Project import
diff --git a/bt/.clang-format b/bt/.clang-format
new file mode 100644
index 0000000..fa9d143
--- /dev/null
+++ b/bt/.clang-format
@@ -0,0 +1,24 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# Below are some minor deviations from the default Google style to
+# accommodate for handling of the large legacy code base.
+#
+
+BasedOnStyle: Google
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
diff --git a/bt/.gn b/bt/.gn
new file mode 100644
index 0000000..947ebac
--- /dev/null
+++ b/bt/.gn
@@ -0,0 +1,22 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT 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 is used by the GN meta build system to find the root of the source
+# tree and to set startup options. For documentation on the values set in this
+# file, run "gn help dotfile" at the command line.
+
+buildconfig = "//build/config/BUILDCONFIG.gn"
+secondary_source = "//build/secondary/"
diff --git a/bt/Android.mk b/bt/Android.mk
new file mode 100644
index 0000000..29760e4
--- /dev/null
+++ b/bt/Android.mk
@@ -0,0 +1,53 @@
+LOCAL_PATH := $(call my-dir)
+
+# Setup Bluetooth local make variables for handling configuration
+ifneq ($(BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR),)
+  bluetooth_C_INCLUDES := $(BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR)
+  bluetooth_CFLAGS += -DHAS_BDROID_BUILDCFG
+else
+  bluetooth_C_INCLUDES :=
+  bluetooth_CFLAGS += -DHAS_NO_BDROID_BUILDCFG
+endif
+
+ifneq ($(BOARD_BLUETOOTH_BDROID_HCILP_INCLUDED),)
+  bluetooth_CFLAGS += -DHCILP_INCLUDED=$(BOARD_BLUETOOTH_BDROID_HCILP_INCLUDED)
+endif
+
+ifneq ($(TARGET_BUILD_VARIANT),user)
+bluetooth_CFLAGS += -DBLUEDROID_DEBUG
+endif
+
+bluetooth_CFLAGS += -DEXPORT_SYMBOL="__attribute__((visibility(\"default\")))"
+
+#
+# Common C/C++ compiler flags.
+#
+# -Wno-gnu-variable-sized-type-not-at-end is needed, because struct BT_HDR
+#  is defined as a variable-size header in a struct.
+# -Wno-typedef-redefinition is needed because of the way the struct typedef
+#  is done in osi/include header files. This issue can be obsoleted by
+#  switching to C11 or C++.
+# -Wno-unused-parameter is needed, because there are too many unused
+#  parameters in all the code.
+#
+bluetooth_CFLAGS += \
+  -fvisibility=hidden \
+  -Wall \
+  -Wextra \
+  -Werror \
+  -Wno-gnu-variable-sized-type-not-at-end \
+  -Wno-typedef-redefinition \
+  -Wno-unused-parameter \
+  -UNDEBUG \
+  -DLOG_NDEBUG=1
+
+bluetooth_CONLYFLAGS += -std=c99
+bluetooth_CPPFLAGS :=
+
+include $(call all-subdir-makefiles)
+
+# Cleanup our locals
+bluetooth_C_INCLUDES :=
+bluetooth_CFLAGS :=
+bluetooth_CONLYFLAGS :=
+bluetooth_CPPFLAGS :=
diff --git a/bt/BUILD.gn b/bt/BUILD.gn
new file mode 100644
index 0000000..ffbe4ef
--- /dev/null
+++ b/bt/BUILD.gn
@@ -0,0 +1,42 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT 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 is the root build file for GN. GN will start processing by loading this
+# file, and recursively load all dependencies until all dependencies are either
+# resolved or known not to exist (which will cause the build to fail). So if
+# you add a new build file, there must be some path of dependencies from this
+# file to your new one or GN won't know about it.
+
+# This pulls in main/BUILD.gn and all of its dependencies.
+group("bluetooth") {
+  deps = [
+    "//main:bluetooth.default",
+    "//service:bluetoothtbd",
+    "//vendor_libs:vendor-libs",
+  ]
+}
+
+group("bluetooth_tests") {
+  testonly = true
+
+  deps = [
+    "//test/suite:net_test_bluetooth",
+    "//btcore:net_test_btcore",
+    "//hci:net_test_hci",
+    "//osi:net_test_osi",
+    "//device:net_test_device",
+  ]
+}
diff --git a/bt/CleanSpec.mk b/bt/CleanSpec.mk
new file mode 100644
index 0000000..518119b
--- /dev/null
+++ b/bt/CleanSpec.mk
@@ -0,0 +1,53 @@
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# Start of Clean Step list:
+$(call add-clean-step, find $(OUT_DIR) -type f -iname "*blue*" -print0 | xargs -0 rm -f)
+$(call add-clean-step, find $(OUT_DIR) -type f -iname "*bdroid*" -print0 | xargs -0 rm -f)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/bt/EventLogTags.logtags b/bt/EventLogTags.logtags
new file mode 100644
index 0000000..dc1d239
--- /dev/null
+++ b/bt/EventLogTags.logtags
@@ -0,0 +1,38 @@
+# The entries in this file map a sparse set of log tag numbers to tag names.
+# This is installed on the device, in /system/etc, and parsed by logcat.
+#
+# Tag numbers are decimal integers, from 0 to 2^31.  (Let's leave the
+# negative values alone for now.)
+#
+# Tag names are one or more ASCII letters and numbers or underscores, i.e.
+# "[A-Z][a-z][0-9]_".  Do not include spaces or punctuation (the former
+# impacts log readability, the latter makes regex searches more annoying).
+#
+# Tag numbers and names are separated by whitespace.  Blank lines and lines
+# starting with '#' are ignored.
+#
+# Optionally, after the tag names can be put a description for the value(s)
+# of the tag. Description are in the format
+#    (<name>|data type[|data unit])
+# Multiple values are separated by commas.
+#
+# The data type is a number from the following values:
+# 1: int
+# 2: long
+# 3: string
+# 4: list
+#
+# The data unit is a number taken from the following list:
+# 1: Number of objects
+# 2: Number of bytes
+# 3: Number of milliseconds
+# 4: Number of allocations
+# 5: Id
+# 6: Percent
+# Default value for data of type int/long is 2 (bytes).
+#
+# TODO: generate ".java" and ".h" files with integer constants from this file.
+
+1010000 bt_hci_timeout (opcode|1)
+1010001 bt_config_source (opcode|1)
+1010002 bt_hci_unknown_type (hci_type|1)
diff --git a/bt/MODULE_LICENSE_APACHE2 b/bt/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/bt/MODULE_LICENSE_APACHE2
diff --git a/bt/NOTICE b/bt/NOTICE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/bt/NOTICE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/bt/OWNERS b/bt/OWNERS
new file mode 100644
index 0000000..19aa7af
--- /dev/null
+++ b/bt/OWNERS
@@ -0,0 +1,13 @@
+set noparent
+
+# Project owners
+eisenbach
+apanicke
+jamuraa
+jpawlowski
+mylesgw
+pavlin
+
+# Android Team (rollbacks, global changes etc.)
+bsears
+ijpedowitz
diff --git a/bt/README.md b/bt/README.md
new file mode 100644
index 0000000..fa247d0
--- /dev/null
+++ b/bt/README.md
@@ -0,0 +1,100 @@
+# Fluoride Bluetooth stack
+
+## Building and running on AOSP
+Just build AOSP - Fluoride is there by default.
+
+## Building and running on Linux
+
+Instructions for Ubuntu, tested on 15.10 with GCC 5.2.1.
+
+### Install required libraries
+
+```sh
+sudo apt-get install libevent-dev
+```
+
+### Install build tools
+
+  - Install [ninja](https://ninja-build.org/) build system
+
+```sh
+sudo apt-get install ninja-build
+```
+
+or download binary from https://github.com/ninja-build/ninja/releases
+
+  - Install [gn](https://chromium.googlesource.com/chromium/src/tools/gn/) -  meta-build system that generates NinjaBuild files.
+
+Get sha1 of current version from [here](
+https://chromium.googlesource.com/chromium/buildtools/+/master/linux64/gn.sha1) and then download corresponding executable:
+
+```sh
+wget -O gn http://storage.googleapis.com/chromium-gn/<gn.sha1>
+```
+
+i.e. if sha1 is "3491f6687bd9f19946035700eb84ce3eed18c5fa" (value from 24 Feb 2016) do
+
+```sh
+wget -O gn http://storage.googleapis.com/chromium-gn/3491f6687bd9f19946035700eb84ce3eed18c5fa
+```
+
+Then make binary executable and put it on your PATH, i.e.:
+
+```sh
+chmod a+x ./gn
+sudo mv ./gn /usr/bin
+```
+
+### Download source
+
+```sh
+mkdir ~/fluoride
+cd ~/fluoride
+git clone https://android.googlesource.com/platform/system/bt
+```
+
+Then fetch third party dependencies:
+
+```sh
+cd ~/fluoride/bt
+mkdir third_party
+cd third_party
+git clone https://github.com/google/googletest.git
+git clone https://android.googlesource.com/platform/external/libchrome
+git clone https://android.googlesource.com/platform/external/modp_b64
+git clone https://android.googlesource.com/platform/external/tinyxml2
+git clone https://android.googlesource.com/platform/hardware/libhardware
+```
+
+And third party dependencies of third party dependencies:
+
+```sh
+cd fluoride/bt/third_party/libchrome/base/third_party
+mkdir valgrind
+cd valgrind
+curl https://chromium.googlesource.com/chromium/src/base/+/master/third_party/valgrind/valgrind.h?format=TEXT | base64 -d > valgrind.h
+curl https://chromium.googlesource.com/chromium/src/base/+/master/third_party/valgrind/memcheck.h?format=TEXT | base64 -d > memcheck.h
+```
+
+### Generate your build files
+
+```sh
+cd ~/fluoride/bt
+gn gen out/Default
+```
+
+### Build
+
+```sh
+cd ~/fluoride/bt
+ninja -C out/Default all
+```
+
+This will build all targets (the shared library, executables, tests, etc) and put them in out/Default. To build an individual target, replace "all" with the target of your choice, e.g. ```ninja -C out/Default net_test_osi```.
+
+### Run
+
+```sh
+cd ~/fluoride/bt/out/Default
+LD_LIBRARY_PATH=./ ./bluetoothtbd -create-ipc-socket=fluoride
+```
diff --git a/bt/audio_a2dp_hw/Android.mk b/bt/audio_a2dp_hw/Android.mk
new file mode 100644
index 0000000..ecad094
--- /dev/null
+++ b/bt/audio_a2dp_hw/Android.mk
@@ -0,0 +1,29 @@
+LOCAL_PATH := $(call my-dir)
+
+# Audio A2DP shared library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+
+LOCAL_SRC_FILES := \
+	audio_a2dp_hw.cc \
+	audio_a2dp_hw_utils.cc
+
+LOCAL_C_INCLUDES := \
+	. \
+	$(LOCAL_PATH)/../ \
+	$(LOCAL_PATH)/../utils/include
+
+LOCAL_MODULE := audio.a2dp.default
+LOCAL_MODULE_RELATIVE_PATH := hw
+
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_STATIC_LIBRARIES := libosi
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/bt/audio_a2dp_hw/audio_a2dp_hw.cc b/bt/audio_a2dp_hw/audio_a2dp_hw.cc
new file mode 100644
index 0000000..b00a021
--- /dev/null
+++ b/bt/audio_a2dp_hw/audio_a2dp_hw.cc
@@ -0,0 +1,1383 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ *  Filename:      audio_a2dp_hw.c
+ *
+ *  Description:   Implements hal for bluedroid a2dp audio device
+ *
+ *****************************************************************************/
+
+#define LOG_TAG "bt_a2dp_hw"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <hardware/audio.h>
+#include <hardware/hardware.h>
+#include <system/audio.h>
+
+#include "audio_a2dp_hw.h"
+#include "bt_utils.h"
+#include "osi/include/hash_map_utils.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/socket_utils/sockets.h"
+
+/*****************************************************************************
+**  Constants & Macros
+******************************************************************************/
+
+#define CTRL_CHAN_RETRY_COUNT 3
+#define USEC_PER_SEC 1000000L
+#define SOCK_SEND_TIMEOUT_MS 2000  /* Timeout for sending */
+#define SOCK_RECV_TIMEOUT_MS 5000  /* Timeout for receiving */
+
+// set WRITE_POLL_MS to 0 for blocking sockets, nonzero for polled non-blocking sockets
+#define WRITE_POLL_MS 20
+
+#define FNLOG()             LOG_VERBOSE(LOG_TAG, "%s", __func__);
+#define DEBUG(fmt, ...)     LOG_VERBOSE(LOG_TAG, "%s: " fmt,__func__, ## __VA_ARGS__)
+#define INFO(fmt, ...)      LOG_INFO(LOG_TAG, "%s: " fmt,__func__, ## __VA_ARGS__)
+#define WARN(fmt, ...)      LOG_WARN(LOG_TAG, "%s: " fmt,__func__, ## __VA_ARGS__)
+#define ERROR(fmt, ...)     LOG_ERROR(LOG_TAG, "%s: " fmt,__func__, ## __VA_ARGS__)
+
+#define ASSERTC(cond, msg, val) if (!(cond)) {ERROR("### ASSERT : %s line %d %s (%d) ###", __FILE__, __LINE__, msg, val);}
+
+/*****************************************************************************
+**  Local type definitions
+******************************************************************************/
+
+typedef enum {
+    AUDIO_A2DP_STATE_STARTING,
+    AUDIO_A2DP_STATE_STARTED,
+    AUDIO_A2DP_STATE_STOPPING,
+    AUDIO_A2DP_STATE_STOPPED,
+    AUDIO_A2DP_STATE_SUSPENDED, /* need explicit set param call to resume (suspend=false) */
+    AUDIO_A2DP_STATE_STANDBY    /* allows write to autoresume */
+} a2dp_state_t;
+
+struct a2dp_stream_in;
+struct a2dp_stream_out;
+
+struct a2dp_audio_device {
+    struct audio_hw_device device;
+    struct a2dp_stream_in  *input;
+    struct a2dp_stream_out *output;
+};
+
+struct a2dp_config {
+    uint32_t                rate;
+    uint32_t                channel_flags;
+    int                     format;
+};
+
+/* move ctrl_fd outside output stream and keep open until HAL unloaded ? */
+
+struct a2dp_stream_common {
+    pthread_mutex_t         lock;
+    int                     ctrl_fd;
+    int                     audio_fd;
+    size_t                  buffer_sz;
+    struct a2dp_config      cfg;
+    a2dp_state_t            state;
+};
+
+struct a2dp_stream_out {
+    struct audio_stream_out stream;
+    struct a2dp_stream_common common;
+    uint64_t frames_presented; // frames written, never reset
+    uint64_t frames_rendered;  // frames written, reset on standby
+};
+
+struct a2dp_stream_in {
+    struct audio_stream_in  stream;
+    struct a2dp_stream_common common;
+};
+
+/*****************************************************************************
+**  Static variables
+******************************************************************************/
+
+/*****************************************************************************
+**  Static functions
+******************************************************************************/
+
+static size_t out_get_buffer_size(const struct audio_stream *stream);
+
+/*****************************************************************************
+**  Externs
+******************************************************************************/
+
+/*****************************************************************************
+**  Functions
+******************************************************************************/
+static void a2dp_open_ctrl_path(struct a2dp_stream_common *common);
+
+/*****************************************************************************
+**   Miscellaneous helper functions
+******************************************************************************/
+
+/* logs timestamp with microsec precision
+   pprev is optional in case a dedicated diff is required */
+static void ts_log(UNUSED_ATTR const char *tag, UNUSED_ATTR int val, struct timespec *pprev_opt)
+{
+    struct timespec now;
+    static struct timespec prev = {0,0};
+    unsigned long long now_us;
+    unsigned long long diff_us;
+
+    clock_gettime(CLOCK_MONOTONIC, &now);
+
+    now_us = now.tv_sec*USEC_PER_SEC + now.tv_nsec/1000;
+
+    if (pprev_opt)
+    {
+        diff_us = (now.tv_sec - prev.tv_sec) * USEC_PER_SEC + (now.tv_nsec - prev.tv_nsec)/1000;
+        *pprev_opt = now;
+        DEBUG("[%s] ts %08lld, *diff %08lld, val %d", tag, now_us, diff_us, val);
+    }
+    else
+    {
+        diff_us = (now.tv_sec - prev.tv_sec) * USEC_PER_SEC + (now.tv_nsec - prev.tv_nsec)/1000;
+        prev = now;
+        DEBUG("[%s] ts %08lld, diff %08lld, val %d", tag, now_us, diff_us, val);
+    }
+}
+
+static int calc_audiotime(struct a2dp_config cfg, int bytes)
+{
+    int chan_count = popcount(cfg.channel_flags);
+
+    ASSERTC(cfg.format == AUDIO_FORMAT_PCM_16_BIT,
+            "unsupported sample sz", cfg.format);
+
+    return (int)(((int64_t)bytes * (1000000 / (chan_count * 2))) / cfg.rate);
+}
+
+/*****************************************************************************
+**
+**   bluedroid stack adaptation
+**
+*****************************************************************************/
+
+static int skt_connect(const char *path, size_t buffer_sz)
+{
+    int ret;
+    int skt_fd;
+    int len;
+
+    INFO("connect to %s (sz %zu)", path, buffer_sz);
+
+    skt_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+
+    if(osi_socket_local_client_connect(skt_fd, path,
+            ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM) < 0)
+    {
+        ERROR("failed to connect (%s)", strerror(errno));
+        close(skt_fd);
+        return -1;
+    }
+
+    len = buffer_sz;
+    ret = setsockopt(skt_fd, SOL_SOCKET, SO_SNDBUF, (char*)&len, (int)sizeof(len));
+    if (ret < 0)
+        ERROR("setsockopt failed (%s)", strerror(errno));
+
+    ret = setsockopt(skt_fd, SOL_SOCKET, SO_RCVBUF, (char*)&len, (int)sizeof(len));
+    if (ret < 0)
+        ERROR("setsockopt failed (%s)", strerror(errno));
+
+    /* Socket send/receive timeout value */
+    struct timeval tv;
+    tv.tv_sec = SOCK_SEND_TIMEOUT_MS / 1000;
+    tv.tv_usec = (SOCK_SEND_TIMEOUT_MS % 1000) * 1000;
+
+    ret = setsockopt(skt_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+    if (ret < 0)
+        ERROR("setsockopt failed (%s)", strerror(errno));
+
+    tv.tv_sec = SOCK_RECV_TIMEOUT_MS / 1000;
+    tv.tv_usec = (SOCK_RECV_TIMEOUT_MS % 1000) * 1000;
+
+    ret = setsockopt(skt_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+    if (ret < 0)
+        ERROR("setsockopt failed (%s)", strerror(errno));
+
+    INFO("connected to stack fd = %d", skt_fd);
+
+    return skt_fd;
+}
+
+static int skt_read(int fd, void *p, size_t len)
+{
+    ssize_t read;
+
+    FNLOG();
+
+    ts_log("skt_read recv", len, NULL);
+
+    OSI_NO_INTR(read = recv(fd, p, len, MSG_NOSIGNAL));
+    if (read == -1)
+        ERROR("read failed with errno=%d\n", errno);
+
+    return (int)read;
+}
+
+static int skt_write(int fd, const void *p, size_t len)
+{
+    ssize_t sent;
+    FNLOG();
+
+    ts_log("skt_write", len, NULL);
+
+    if (WRITE_POLL_MS == 0) {
+        // do not poll, use blocking send
+        OSI_NO_INTR(sent = send(fd, p, len, MSG_NOSIGNAL));
+        if (sent == -1)
+            ERROR("write failed with error(%s)", strerror(errno));
+
+        return (int)sent;
+    }
+
+    // use non-blocking send, poll
+    int ms_timeout = SOCK_SEND_TIMEOUT_MS;
+    size_t count = 0;
+    while (count < len) {
+        OSI_NO_INTR(sent = send(fd, p, len - count, MSG_NOSIGNAL | MSG_DONTWAIT));
+        if (sent == -1) {
+            if (errno != EAGAIN && errno != EWOULDBLOCK) {
+                ERROR("write failed with error(%s)", strerror(errno));
+                return -1;
+            }
+            if (ms_timeout >= WRITE_POLL_MS) {
+                usleep(WRITE_POLL_MS * 1000);
+                ms_timeout -= WRITE_POLL_MS;
+                continue;
+            }
+            WARN("write timeout exceeded, sent %zu bytes", count);
+            return -1;
+        }
+        count += sent;
+        p = (const uint8_t *)p + sent;
+    }
+    return (int)count;
+}
+
+static int skt_disconnect(int fd)
+{
+    INFO("fd %d", fd);
+
+    if (fd != AUDIO_SKT_DISCONNECTED)
+    {
+        shutdown(fd, SHUT_RDWR);
+        close(fd);
+    }
+    return 0;
+}
+
+
+
+/*****************************************************************************
+**
+**  AUDIO CONTROL PATH
+**
+*****************************************************************************/
+
+static int a2dp_ctrl_receive(struct a2dp_stream_common *common, void* buffer, int length)
+{
+    ssize_t ret;
+    int i;
+
+    for (i = 0;; i++) {
+        OSI_NO_INTR(ret = recv(common->ctrl_fd, buffer, length, MSG_NOSIGNAL));
+        if (ret > 0) {
+            break;
+        }
+        if (ret == 0) {
+            ERROR("ack failed: peer closed");
+            break;
+        }
+        if (errno != EWOULDBLOCK && errno != EAGAIN) {
+            ERROR("ack failed: error(%s)", strerror(errno));
+            break;
+        }
+        if (i == (CTRL_CHAN_RETRY_COUNT - 1)) {
+            ERROR("ack failed: max retry count");
+            break;
+        }
+        INFO("ack failed (%s), retrying", strerror(errno));
+    }
+    if (ret <= 0) {
+        skt_disconnect(common->ctrl_fd);
+        common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
+    }
+    return ret;
+}
+
+static int a2dp_command(struct a2dp_stream_common *common, tA2DP_CTRL_CMD cmd)
+{
+    char ack;
+
+    DEBUG("A2DP COMMAND %s", audio_a2dp_hw_dump_ctrl_event(cmd));
+
+    if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) {
+        INFO("recovering from previous error");
+        a2dp_open_ctrl_path(common);
+        if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) {
+            ERROR("failure to open ctrl path");
+            return -1;
+        }
+    }
+
+    /* send command */
+    ssize_t sent;
+    OSI_NO_INTR(sent = send(common->ctrl_fd, &cmd, 1, MSG_NOSIGNAL));
+    if (sent == -1)
+    {
+        ERROR("cmd failed (%s)", strerror(errno));
+        skt_disconnect(common->ctrl_fd);
+        common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
+        return -1;
+    }
+
+    /* wait for ack byte */
+    if (a2dp_ctrl_receive(common, &ack, 1) < 0) {
+        ERROR("A2DP COMMAND %s: no ACK", audio_a2dp_hw_dump_ctrl_event(cmd));
+        return -1;
+    }
+
+    DEBUG("A2DP COMMAND %s DONE STATUS %d", audio_a2dp_hw_dump_ctrl_event(cmd),
+          ack);
+
+    if (ack == A2DP_CTRL_ACK_INCALL_FAILURE)
+        return ack;
+    if (ack != A2DP_CTRL_ACK_SUCCESS) {
+        ERROR("A2DP COMMAND %s error %d", audio_a2dp_hw_dump_ctrl_event(cmd),
+              ack);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int check_a2dp_ready(struct a2dp_stream_common *common)
+{
+    if (a2dp_command(common, A2DP_CTRL_CMD_CHECK_READY) < 0)
+    {
+        ERROR("check a2dp ready failed");
+        return -1;
+    }
+    return 0;
+}
+
+static int a2dp_read_audio_config(struct a2dp_stream_common *common)
+{
+    uint32_t sample_rate;
+    uint8_t channel_count;
+
+    if (a2dp_command(common, A2DP_CTRL_GET_AUDIO_CONFIG) < 0)
+    {
+        ERROR("check a2dp ready failed");
+        return -1;
+    }
+
+    if (a2dp_ctrl_receive(common, &sample_rate, 4) < 0)
+        return -1;
+    if (a2dp_ctrl_receive(common, &channel_count, 1) < 0)
+        return -1;
+
+    common->cfg.channel_flags = (channel_count == 1 ? AUDIO_CHANNEL_IN_MONO : AUDIO_CHANNEL_IN_STEREO);
+    common->cfg.format = AUDIO_STREAM_DEFAULT_FORMAT;
+    common->cfg.rate = sample_rate;
+
+    INFO("got config %d %d", common->cfg.format, common->cfg.rate);
+
+    return 0;
+}
+
+static void a2dp_open_ctrl_path(struct a2dp_stream_common *common)
+{
+    int i;
+
+    /* retry logic to catch any timing variations on control channel */
+    for (i = 0; i < CTRL_CHAN_RETRY_COUNT; i++)
+    {
+        /* connect control channel if not already connected */
+        if ((common->ctrl_fd = skt_connect(A2DP_CTRL_PATH, common->buffer_sz)) > 0)
+        {
+            /* success, now check if stack is ready */
+            if (check_a2dp_ready(common) == 0)
+                break;
+
+            ERROR("error : a2dp not ready, wait 250 ms and retry");
+            usleep(250000);
+            skt_disconnect(common->ctrl_fd);
+            common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
+        }
+
+        /* ctrl channel not ready, wait a bit */
+        usleep(250000);
+    }
+}
+
+/*****************************************************************************
+**
+** AUDIO DATA PATH
+**
+*****************************************************************************/
+
+static void a2dp_stream_common_init(struct a2dp_stream_common *common)
+{
+    pthread_mutexattr_t lock_attr;
+
+    FNLOG();
+
+    pthread_mutexattr_init(&lock_attr);
+    pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
+    pthread_mutex_init(&common->lock, &lock_attr);
+
+    common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
+    common->audio_fd = AUDIO_SKT_DISCONNECTED;
+    common->state = AUDIO_A2DP_STATE_STOPPED;
+
+    /* manages max capacity of socket pipe */
+    common->buffer_sz = AUDIO_STREAM_OUTPUT_BUFFER_SZ;
+}
+
+static int start_audio_datapath(struct a2dp_stream_common *common)
+{
+    INFO("state %d", common->state);
+
+    int oldstate = common->state;
+    common->state = AUDIO_A2DP_STATE_STARTING;
+
+    int a2dp_status = a2dp_command(common, A2DP_CTRL_CMD_START);
+    if (a2dp_status < 0)
+    {
+        ERROR("Audiopath start failed (status %d)", a2dp_status);
+        goto error;
+    }
+    else if (a2dp_status == A2DP_CTRL_ACK_INCALL_FAILURE)
+    {
+        ERROR("Audiopath start failed - in call, move to suspended");
+        goto error;
+    }
+
+    /* connect socket if not yet connected */
+    if (common->audio_fd == AUDIO_SKT_DISCONNECTED)
+    {
+        common->audio_fd = skt_connect(A2DP_DATA_PATH, common->buffer_sz);
+        if (common->audio_fd < 0)
+        {
+            ERROR("Audiopath start failed - error opening data socket");
+            goto error;
+        }
+    }
+    common->state = (a2dp_state_t)AUDIO_A2DP_STATE_STARTED;
+    return 0;
+
+error:
+    common->state = (a2dp_state_t)oldstate;
+    return -1;
+}
+
+static int stop_audio_datapath(struct a2dp_stream_common *common)
+{
+    int oldstate = common->state;
+
+    INFO("state %d", common->state);
+
+    /* prevent any stray output writes from autostarting the stream
+       while stopping audiopath */
+    common->state = AUDIO_A2DP_STATE_STOPPING;
+
+    if (a2dp_command(common, A2DP_CTRL_CMD_STOP) < 0)
+    {
+        ERROR("audiopath stop failed");
+        common->state = (a2dp_state_t)oldstate;
+        return -1;
+    }
+
+    common->state = (a2dp_state_t)AUDIO_A2DP_STATE_STOPPED;
+
+    /* disconnect audio path */
+    skt_disconnect(common->audio_fd);
+    common->audio_fd = AUDIO_SKT_DISCONNECTED;
+
+    return 0;
+}
+
+static int suspend_audio_datapath(struct a2dp_stream_common *common, bool standby)
+{
+    INFO("state %d", common->state);
+
+    if (common->state == AUDIO_A2DP_STATE_STOPPING)
+        return -1;
+
+    if (a2dp_command(common, A2DP_CTRL_CMD_SUSPEND) < 0)
+        return -1;
+
+    if (standby)
+        common->state = AUDIO_A2DP_STATE_STANDBY;
+    else
+        common->state = AUDIO_A2DP_STATE_SUSPENDED;
+
+    /* disconnect audio path */
+    skt_disconnect(common->audio_fd);
+
+    common->audio_fd = AUDIO_SKT_DISCONNECTED;
+
+    return 0;
+}
+
+
+/*****************************************************************************
+**
+**  audio output callbacks
+**
+*****************************************************************************/
+
+static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
+                         size_t bytes)
+{
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+    int sent = -1;
+
+    DEBUG("write %zu bytes (fd %d)", bytes, out->common.audio_fd);
+
+    pthread_mutex_lock(&out->common.lock);
+    if (out->common.state == AUDIO_A2DP_STATE_SUSPENDED ||
+            out->common.state == AUDIO_A2DP_STATE_STOPPING) {
+        DEBUG("stream suspended or closing");
+        goto finish;
+    }
+
+    /* only allow autostarting if we are in stopped or standby */
+    if ((out->common.state == AUDIO_A2DP_STATE_STOPPED) ||
+        (out->common.state == AUDIO_A2DP_STATE_STANDBY))
+    {
+        if (start_audio_datapath(&out->common) < 0)
+        {
+            goto finish;
+        }
+    }
+    else if (out->common.state != AUDIO_A2DP_STATE_STARTED)
+    {
+        ERROR("stream not in stopped or standby");
+        goto finish;
+    }
+
+    pthread_mutex_unlock(&out->common.lock);
+    sent = skt_write(out->common.audio_fd, buffer,  bytes);
+    pthread_mutex_lock(&out->common.lock);
+
+    if (sent == -1) {
+        skt_disconnect(out->common.audio_fd);
+        out->common.audio_fd = AUDIO_SKT_DISCONNECTED;
+        if ((out->common.state != AUDIO_A2DP_STATE_SUSPENDED) &&
+                (out->common.state != AUDIO_A2DP_STATE_STOPPING)) {
+            out->common.state = AUDIO_A2DP_STATE_STOPPED;
+        } else {
+            ERROR("write failed : stream suspended, avoid resetting state");
+        }
+        goto finish;
+    }
+
+finish: ;
+    const size_t frames = bytes / audio_stream_out_frame_size(stream);
+    out->frames_rendered += frames;
+    out->frames_presented += frames;
+    pthread_mutex_unlock(&out->common.lock);
+
+    // If send didn't work out, sleep to emulate write delay.
+    if (sent == -1) {
+        const int us_delay = calc_audiotime(out->common.cfg, bytes);
+        DEBUG("emulate a2dp write delay (%d us)", us_delay);
+        usleep(us_delay);
+    }
+    return bytes;
+}
+
+static uint32_t out_get_sample_rate(const struct audio_stream *stream)
+{
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+
+    DEBUG("rate %" PRIu32,out->common.cfg.rate);
+
+    return out->common.cfg.rate;
+}
+
+static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+
+    DEBUG("out_set_sample_rate : %" PRIu32, rate);
+
+    if (rate != AUDIO_STREAM_DEFAULT_RATE)
+    {
+        ERROR("only rate %d supported", AUDIO_STREAM_DEFAULT_RATE);
+        return -1;
+    }
+
+    out->common.cfg.rate = rate;
+
+    return 0;
+}
+
+static size_t out_get_buffer_size(const struct audio_stream *stream)
+{
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+    // period_size is the AudioFlinger mixer buffer size.
+    const size_t period_size = out->common.buffer_sz / AUDIO_STREAM_OUTPUT_BUFFER_PERIODS;
+    const size_t mixer_unit_size = 16 /* frames */ * 4 /* framesize */;
+
+    DEBUG("socket buffer size: %zu  period size: %zu", out->common.buffer_sz, period_size);
+    if (period_size % mixer_unit_size != 0) {
+        ERROR("period size %zu not a multiple of %zu", period_size, mixer_unit_size);
+    }
+
+    return period_size;
+}
+
+static uint32_t out_get_channels(const struct audio_stream *stream)
+{
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+
+    DEBUG("channels 0x%" PRIx32, out->common.cfg.channel_flags);
+
+    return out->common.cfg.channel_flags;
+}
+
+static audio_format_t out_get_format(const struct audio_stream *stream)
+{
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+    DEBUG("format 0x%x", out->common.cfg.format);
+    return (audio_format_t)out->common.cfg.format;
+}
+
+static int out_set_format(UNUSED_ATTR struct audio_stream *stream,
+                          UNUSED_ATTR audio_format_t format)
+{
+    DEBUG("setting format not yet supported (0x%x)", format);
+    return -ENOSYS;
+}
+
+static int out_standby(struct audio_stream *stream)
+{
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+    int retVal = 0;
+
+    FNLOG();
+
+    pthread_mutex_lock(&out->common.lock);
+    // Do nothing in SUSPENDED state.
+    if (out->common.state != AUDIO_A2DP_STATE_SUSPENDED)
+        retVal = suspend_audio_datapath(&out->common, true);
+    out->frames_rendered = 0; // rendered is reset, presented is not
+    pthread_mutex_unlock (&out->common.lock);
+
+    return retVal;
+}
+
+static int out_dump(UNUSED_ATTR const struct audio_stream *stream,
+                    UNUSED_ATTR int fd)
+{
+    FNLOG();
+    return 0;
+}
+
+static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+
+    INFO("state %d", out->common.state);
+
+    std::unordered_map<std::string, std::string> params =
+            hash_map_utils_new_from_string_params(kvpairs);
+    int status = 0;
+
+    if (params.empty())
+      return status;
+
+    pthread_mutex_lock(&out->common.lock);
+
+    /* dump params */
+    hash_map_utils_dump_string_keys_string_values(params);
+
+    if (params["closing"].compare("true") == 0)
+    {
+        DEBUG("stream closing, disallow any writes");
+        out->common.state = AUDIO_A2DP_STATE_STOPPING;
+    }
+
+    if (params["A2dpSuspended"].compare("true") == 0)
+    {
+        if (out->common.state == AUDIO_A2DP_STATE_STARTED)
+            status = suspend_audio_datapath(&out->common, false);
+    }
+    else
+    {
+        /* Do not start the streaming automatically. If the phone was streaming
+         * prior to being suspended, the next out_write shall trigger the
+         * AVDTP start procedure */
+        if (out->common.state == AUDIO_A2DP_STATE_SUSPENDED)
+            out->common.state = AUDIO_A2DP_STATE_STANDBY;
+        /* Irrespective of the state, return 0 */
+    }
+
+    pthread_mutex_unlock(&out->common.lock);
+
+    return status;
+}
+
+static char * out_get_parameters(UNUSED_ATTR const struct audio_stream *stream,
+                                 UNUSED_ATTR const char *keys)
+{
+    FNLOG();
+
+    /* add populating param here */
+
+    return strdup("");
+}
+
+static uint32_t out_get_latency(const struct audio_stream_out *stream)
+{
+    int latency_us;
+
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+
+    FNLOG();
+
+    latency_us = ((out->common.buffer_sz * 1000 ) /
+                    audio_stream_out_frame_size(&out->stream) /
+                    out->common.cfg.rate) * 1000;
+
+
+    return (latency_us / 1000) + 200;
+}
+
+static int out_set_volume(UNUSED_ATTR struct audio_stream_out *stream, UNUSED_ATTR float left,
+                          UNUSED_ATTR float right)
+{
+
+    FNLOG();
+
+    /* volume controlled in audioflinger mixer (digital) */
+
+    return -ENOSYS;
+}
+
+static int out_get_presentation_position(const struct audio_stream_out *stream,
+                                         uint64_t *frames, struct timespec *timestamp)
+{
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+
+    FNLOG();
+    if (stream == NULL || frames == NULL || timestamp == NULL)
+        return -EINVAL;
+
+    int ret = -EWOULDBLOCK;
+    pthread_mutex_lock(&out->common.lock);
+    uint64_t latency_frames = (uint64_t)out_get_latency(stream) * out->common.cfg.rate / 1000;
+    if (out->frames_presented >= latency_frames) {
+        *frames = out->frames_presented - latency_frames;
+        clock_gettime(CLOCK_MONOTONIC, timestamp); // could also be associated with out_write().
+        ret = 0;
+    }
+    pthread_mutex_unlock(&out->common.lock);
+    return ret;
+}
+
+static int out_get_render_position(const struct audio_stream_out *stream,
+                                   uint32_t *dsp_frames)
+{
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+
+    FNLOG();
+    if (stream == NULL || dsp_frames == NULL)
+        return -EINVAL;
+
+    pthread_mutex_lock(&out->common.lock);
+    uint64_t latency_frames = (uint64_t)out_get_latency(stream) * out->common.cfg.rate / 1000;
+    if (out->frames_rendered >= latency_frames) {
+        *dsp_frames = (uint32_t)(out->frames_rendered - latency_frames);
+    } else {
+        *dsp_frames = 0;
+    }
+    pthread_mutex_unlock(&out->common.lock);
+    return 0;
+}
+
+static int out_add_audio_effect(UNUSED_ATTR const struct audio_stream *stream,
+                                UNUSED_ATTR effect_handle_t effect)
+{
+    FNLOG();
+    return 0;
+}
+
+static int out_remove_audio_effect(UNUSED_ATTR const struct audio_stream *stream,
+                                   UNUSED_ATTR effect_handle_t effect)
+{
+    FNLOG();
+    return 0;
+}
+
+/*
+ * AUDIO INPUT STREAM
+ */
+
+static uint32_t in_get_sample_rate(const struct audio_stream *stream)
+{
+    struct a2dp_stream_in *in = (struct a2dp_stream_in *)stream;
+
+    FNLOG();
+    return in->common.cfg.rate;
+}
+
+static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+    struct a2dp_stream_in *in = (struct a2dp_stream_in *)stream;
+
+    FNLOG();
+
+    if (in->common.cfg.rate > 0 && in->common.cfg.rate == rate)
+        return 0;
+    else
+        return -1;
+}
+
+static size_t in_get_buffer_size(UNUSED_ATTR const struct audio_stream *stream)
+{
+
+    FNLOG();
+    return 320;
+}
+
+static uint32_t in_get_channels(const struct audio_stream *stream)
+{
+    struct a2dp_stream_in *in = (struct a2dp_stream_in *)stream;
+
+    FNLOG();
+    return in->common.cfg.channel_flags;
+}
+
+static audio_format_t in_get_format(UNUSED_ATTR const struct audio_stream *stream)
+{
+
+    FNLOG();
+    return AUDIO_FORMAT_PCM_16_BIT;
+}
+
+static int in_set_format(UNUSED_ATTR struct audio_stream *stream,
+                         UNUSED_ATTR audio_format_t format)
+{
+
+    FNLOG();
+    if (format == AUDIO_FORMAT_PCM_16_BIT)
+        return 0;
+    else
+        return -1;
+}
+
+static int in_standby(UNUSED_ATTR struct audio_stream *stream)
+{
+
+    FNLOG();
+    return 0;
+}
+
+static int in_dump(UNUSED_ATTR const struct audio_stream *stream,
+                   UNUSED_ATTR int fd)
+{
+    FNLOG();
+    return 0;
+}
+
+static int in_set_parameters(UNUSED_ATTR struct audio_stream *stream,
+                             UNUSED_ATTR const char *kvpairs)
+{
+
+    FNLOG();
+    return 0;
+}
+
+static char * in_get_parameters(UNUSED_ATTR const struct audio_stream *stream,
+                                UNUSED_ATTR const char *keys)
+{
+    FNLOG();
+    return strdup("");
+}
+
+static int in_set_gain(UNUSED_ATTR struct audio_stream_in *stream,
+                       UNUSED_ATTR float gain)
+{
+
+    FNLOG();
+    return 0;
+}
+
+static ssize_t in_read(struct audio_stream_in *stream, void* buffer,
+                       size_t bytes)
+{
+    struct a2dp_stream_in *in = (struct a2dp_stream_in *)stream;
+    int read;
+    int us_delay;
+
+    DEBUG("read %zu bytes, state: %d", bytes, in->common.state);
+
+    pthread_mutex_lock(&in->common.lock);
+    if (in->common.state == AUDIO_A2DP_STATE_SUSPENDED ||
+            in->common.state == AUDIO_A2DP_STATE_STOPPING)
+    {
+        DEBUG("stream suspended");
+        goto error;
+    }
+
+    /* only allow autostarting if we are in stopped or standby */
+    if ((in->common.state == AUDIO_A2DP_STATE_STOPPED) ||
+        (in->common.state == AUDIO_A2DP_STATE_STANDBY))
+    {
+        if (start_audio_datapath(&in->common) < 0)
+        {
+            goto error;
+        }
+    }
+    else if (in->common.state != AUDIO_A2DP_STATE_STARTED)
+    {
+        ERROR("stream not in stopped or standby");
+        goto error;
+    }
+
+    pthread_mutex_unlock(&in->common.lock);
+    read = skt_read(in->common.audio_fd, buffer, bytes);
+    pthread_mutex_lock(&in->common.lock);
+    if (read == -1)
+    {
+        skt_disconnect(in->common.audio_fd);
+        in->common.audio_fd = AUDIO_SKT_DISCONNECTED;
+        if ((in->common.state != AUDIO_A2DP_STATE_SUSPENDED) &&
+                (in->common.state != AUDIO_A2DP_STATE_STOPPING)) {
+            in->common.state = AUDIO_A2DP_STATE_STOPPED;
+        } else {
+            ERROR("read failed : stream suspended, avoid resetting state");
+        }
+        goto error;
+    } else if (read == 0) {
+        DEBUG("read time out - return zeros");
+        memset(buffer, 0, bytes);
+        read = bytes;
+    }
+    pthread_mutex_unlock(&in->common.lock);
+
+    DEBUG("read %d bytes out of %zu bytes", read, bytes);
+    return read;
+
+error:
+    pthread_mutex_unlock(&in->common.lock);
+    memset(buffer, 0, bytes);
+    us_delay = calc_audiotime(in->common.cfg, bytes);
+    DEBUG("emulate a2dp read delay (%d us)", us_delay);
+
+    usleep(us_delay);
+    return bytes;
+}
+
+static uint32_t in_get_input_frames_lost(UNUSED_ATTR struct audio_stream_in *stream)
+{
+
+    FNLOG();
+    return 0;
+}
+
+static int in_add_audio_effect(UNUSED_ATTR const struct audio_stream *stream,
+                               UNUSED_ATTR effect_handle_t effect)
+{
+    FNLOG();
+    return 0;
+}
+
+static int in_remove_audio_effect(UNUSED_ATTR const struct audio_stream *stream,
+                                  UNUSED_ATTR effect_handle_t effect)
+{
+    FNLOG();
+
+    return 0;
+}
+
+static int adev_open_output_stream(struct audio_hw_device *dev,
+                                   UNUSED_ATTR audio_io_handle_t handle,
+                                   UNUSED_ATTR audio_devices_t devices,
+                                   UNUSED_ATTR audio_output_flags_t flags,
+                                   struct audio_config *config,
+                                   struct audio_stream_out **stream_out,
+                                   UNUSED_ATTR const char *address)
+
+{
+    struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev;
+    struct a2dp_stream_out *out;
+    int ret = 0;
+
+    INFO("opening output");
+
+    out = (struct a2dp_stream_out *)calloc(1, sizeof(struct a2dp_stream_out));
+
+    if (!out)
+        return -ENOMEM;
+
+    out->stream.common.get_sample_rate = out_get_sample_rate;
+    out->stream.common.set_sample_rate = out_set_sample_rate;
+    out->stream.common.get_buffer_size = out_get_buffer_size;
+    out->stream.common.get_channels = out_get_channels;
+    out->stream.common.get_format = out_get_format;
+    out->stream.common.set_format = out_set_format;
+    out->stream.common.standby = out_standby;
+    out->stream.common.dump = out_dump;
+    out->stream.common.set_parameters = out_set_parameters;
+    out->stream.common.get_parameters = out_get_parameters;
+    out->stream.common.add_audio_effect = out_add_audio_effect;
+    out->stream.common.remove_audio_effect = out_remove_audio_effect;
+    out->stream.get_latency = out_get_latency;
+    out->stream.set_volume = out_set_volume;
+    out->stream.write = out_write;
+    out->stream.get_render_position = out_get_render_position;
+    out->stream.get_presentation_position = out_get_presentation_position;
+
+
+    /* initialize a2dp specifics */
+    a2dp_stream_common_init(&out->common);
+
+    out->common.cfg.channel_flags = AUDIO_STREAM_DEFAULT_CHANNEL_FLAG;
+    out->common.cfg.format = AUDIO_STREAM_DEFAULT_FORMAT;
+    out->common.cfg.rate = AUDIO_STREAM_DEFAULT_RATE;
+
+   /* set output config values */
+   if (config)
+   {
+      config->format = out_get_format((const struct audio_stream *)&out->stream);
+      config->sample_rate = out_get_sample_rate((const struct audio_stream *)&out->stream);
+      config->channel_mask = out_get_channels((const struct audio_stream *)&out->stream);
+   }
+    *stream_out = &out->stream;
+    a2dp_dev->output = out;
+
+    a2dp_open_ctrl_path(&out->common);
+    if (out->common.ctrl_fd == AUDIO_SKT_DISCONNECTED)
+    {
+        ERROR("ctrl socket failed to connect (%s)", strerror(errno));
+        ret = -1;
+        goto err_open;
+    }
+
+    DEBUG("success");
+    /* Delay to ensure Headset is in proper state when START is initiated
+       from DUT immediately after the connection due to ongoing music playback. */
+    usleep(250000);
+    return 0;
+
+err_open:
+    free(out);
+    *stream_out = NULL;
+    a2dp_dev->output = NULL;
+    ERROR("failed");
+    return ret;
+}
+
+static void adev_close_output_stream(struct audio_hw_device *dev,
+                                     struct audio_stream_out *stream)
+{
+    struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev;
+    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
+
+    INFO("closing output (state %d)", out->common.state);
+
+    pthread_mutex_lock(&out->common.lock);
+    if ((out->common.state == AUDIO_A2DP_STATE_STARTED) ||
+            (out->common.state == AUDIO_A2DP_STATE_STOPPING)) {
+        stop_audio_datapath(&out->common);
+    }
+
+    skt_disconnect(out->common.ctrl_fd);
+    out->common.ctrl_fd = AUDIO_SKT_DISCONNECTED;
+    free(stream);
+    a2dp_dev->output = NULL;
+    pthread_mutex_unlock(&out->common.lock);
+
+    DEBUG("done");
+}
+
+static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
+{
+    struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev;
+    struct a2dp_stream_out *out = a2dp_dev->output;
+    int retval = 0;
+
+    if (out == NULL)
+        return retval;
+
+    INFO("state %d", out->common.state);
+
+    retval = out->stream.common.set_parameters((struct audio_stream *)out, kvpairs);
+
+    return retval;
+}
+
+static char * adev_get_parameters(UNUSED_ATTR const struct audio_hw_device *dev,
+                                  const char *keys)
+{
+    FNLOG();
+
+    std::unordered_map<std::string, std::string> params =
+            hash_map_utils_new_from_string_params(keys);
+    hash_map_utils_dump_string_keys_string_values(params);
+
+    return strdup("");
+}
+
+static int adev_init_check(UNUSED_ATTR const struct audio_hw_device *dev)
+{
+    
+    FNLOG();
+
+    return 0;
+}
+
+static int adev_set_voice_volume(UNUSED_ATTR struct audio_hw_device *dev,
+                                 UNUSED_ATTR float volume)
+{
+    FNLOG();
+
+    return -ENOSYS;
+}
+
+static int adev_set_master_volume(UNUSED_ATTR struct audio_hw_device *dev,
+                                  UNUSED_ATTR float volume)
+{
+    FNLOG();
+
+    return -ENOSYS;
+}
+
+static int adev_set_mode(UNUSED_ATTR struct audio_hw_device *dev,
+                         UNUSED_ATTR audio_mode_t mode)
+{
+    FNLOG();
+
+    return 0;
+}
+
+static int adev_set_mic_mute(UNUSED_ATTR struct audio_hw_device *dev,
+                             UNUSED_ATTR bool state)
+{
+    FNLOG();
+
+    return -ENOSYS;
+}
+
+static int adev_get_mic_mute(UNUSED_ATTR const struct audio_hw_device *dev,
+                             UNUSED_ATTR bool *state)
+{
+    FNLOG();
+
+    return -ENOSYS;
+}
+
+static size_t adev_get_input_buffer_size(UNUSED_ATTR const struct audio_hw_device *dev,
+                                         UNUSED_ATTR const struct audio_config *config)
+{
+    FNLOG();
+
+    return 320;
+}
+
+static int adev_open_input_stream(struct audio_hw_device *dev,
+                                  UNUSED_ATTR audio_io_handle_t handle,
+                                  UNUSED_ATTR audio_devices_t devices,
+                                  UNUSED_ATTR struct audio_config *config,
+                                  struct audio_stream_in **stream_in,
+                                  UNUSED_ATTR audio_input_flags_t flags,
+                                  UNUSED_ATTR const char *address,
+                                  UNUSED_ATTR audio_source_t source)
+{
+    struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev;
+    struct a2dp_stream_in *in;
+    int ret;
+
+    FNLOG();
+
+    in = (struct a2dp_stream_in *)calloc(1, sizeof(struct a2dp_stream_in));
+
+    if (!in)
+        return -ENOMEM;
+
+    in->stream.common.get_sample_rate = in_get_sample_rate;
+    in->stream.common.set_sample_rate = in_set_sample_rate;
+    in->stream.common.get_buffer_size = in_get_buffer_size;
+    in->stream.common.get_channels = in_get_channels;
+    in->stream.common.get_format = in_get_format;
+    in->stream.common.set_format = in_set_format;
+    in->stream.common.standby = in_standby;
+    in->stream.common.dump = in_dump;
+    in->stream.common.set_parameters = in_set_parameters;
+    in->stream.common.get_parameters = in_get_parameters;
+    in->stream.common.add_audio_effect = in_add_audio_effect;
+    in->stream.common.remove_audio_effect = in_remove_audio_effect;
+    in->stream.set_gain = in_set_gain;
+    in->stream.read = in_read;
+    in->stream.get_input_frames_lost = in_get_input_frames_lost;
+
+    /* initialize a2dp specifics */
+    a2dp_stream_common_init(&in->common);
+
+    *stream_in = &in->stream;
+    a2dp_dev->input = in;
+
+    a2dp_open_ctrl_path(&in->common);
+    if (in->common.ctrl_fd == AUDIO_SKT_DISCONNECTED)
+    {
+        ERROR("ctrl socket failed to connect (%s)", strerror(errno));
+        ret = -1;
+        goto err_open;
+    }
+
+    if (a2dp_read_audio_config(&in->common) < 0) {
+        ERROR("a2dp_read_audio_config failed (%s)", strerror(errno));
+        ret = -1;
+        goto err_open;
+    }
+
+    DEBUG("success");
+    return 0;
+
+err_open:
+    free(in);
+    *stream_in = NULL;
+    a2dp_dev->input = NULL;
+    ERROR("failed");
+    return ret;
+}
+
+static void adev_close_input_stream(struct audio_hw_device *dev,
+                                   struct audio_stream_in *stream)
+{
+    struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev;
+    struct a2dp_stream_in* in = (struct a2dp_stream_in *)stream;
+    a2dp_state_t state = in->common.state;
+
+    INFO("closing input (state %d)", state);
+
+    if ((state == AUDIO_A2DP_STATE_STARTED) || (state == AUDIO_A2DP_STATE_STOPPING))
+        stop_audio_datapath(&in->common);
+
+    skt_disconnect(in->common.ctrl_fd);
+    in->common.ctrl_fd = AUDIO_SKT_DISCONNECTED;
+    free(stream);
+    a2dp_dev->input = NULL;
+
+    DEBUG("done");
+}
+
+static int adev_dump(UNUSED_ATTR const audio_hw_device_t *device,
+                     UNUSED_ATTR int fd)
+{
+    FNLOG();
+
+    return 0;
+}
+
+static int adev_close(hw_device_t *device)
+{
+    FNLOG();
+
+    free(device);
+    return 0;
+}
+
+static int adev_open(const hw_module_t* module, const char* name,
+                     hw_device_t** device)
+{
+    struct a2dp_audio_device *adev;
+
+    INFO(" adev_open in A2dp_hw module");
+    FNLOG();
+
+    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
+    {
+        ERROR("interface %s not matching [%s]", name, AUDIO_HARDWARE_INTERFACE);
+        return -EINVAL;
+    }
+
+    adev = (struct a2dp_audio_device *)calloc(1, sizeof(struct a2dp_audio_device));
+
+    if (!adev)
+        return -ENOMEM;
+
+    adev->device.common.tag = HARDWARE_DEVICE_TAG;
+    adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
+    adev->device.common.module = (struct hw_module_t *) module;
+    adev->device.common.close = adev_close;
+
+    adev->device.init_check = adev_init_check;
+    adev->device.set_voice_volume = adev_set_voice_volume;
+    adev->device.set_master_volume = adev_set_master_volume;
+    adev->device.set_mode = adev_set_mode;
+    adev->device.set_mic_mute = adev_set_mic_mute;
+    adev->device.get_mic_mute = adev_get_mic_mute;
+    adev->device.set_parameters = adev_set_parameters;
+    adev->device.get_parameters = adev_get_parameters;
+    adev->device.get_input_buffer_size = adev_get_input_buffer_size;
+    adev->device.open_output_stream = adev_open_output_stream;
+    adev->device.close_output_stream = adev_close_output_stream;
+    adev->device.open_input_stream = adev_open_input_stream;
+    adev->device.close_input_stream = adev_close_input_stream;
+    adev->device.dump = adev_dump;
+
+    adev->output = NULL;
+
+
+    *device = &adev->device.common;
+
+    return 0;
+}
+
+static struct hw_module_methods_t hal_module_methods = {
+    .open = adev_open,
+};
+
+__attribute__ ((visibility ("default")))
+struct audio_module HAL_MODULE_INFO_SYM = {
+    .common = {
+        .tag = HARDWARE_MODULE_TAG,
+        .version_major = 1,
+        .version_minor = 0,
+        .id = AUDIO_HARDWARE_MODULE_ID,
+        .name = "A2DP Audio HW HAL",
+        .author = "The Android Open Source Project",
+        .methods = &hal_module_methods,
+    },
+};
diff --git a/bt/audio_a2dp_hw/audio_a2dp_hw.h b/bt/audio_a2dp_hw/audio_a2dp_hw.h
new file mode 100644
index 0000000..af3f219
--- /dev/null
+++ b/bt/audio_a2dp_hw/audio_a2dp_hw.h
@@ -0,0 +1,125 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ *  Filename:      audio_a2dp_hw.h
+ *
+ *  Description:
+ *
+ *****************************************************************************/
+
+#ifndef AUDIO_A2DP_HW_H
+#define AUDIO_A2DP_HW_H
+
+/*****************************************************************************
+**  Constants & Macros
+******************************************************************************/
+
+#define A2DP_AUDIO_HARDWARE_INTERFACE "audio.a2dp"
+#define A2DP_CTRL_PATH "/data/misc/bluedroid/.a2dp_ctrl"
+#define A2DP_DATA_PATH "/data/misc/bluedroid/.a2dp_data"
+
+#define AUDIO_STREAM_DEFAULT_RATE          44100
+#define AUDIO_STREAM_DEFAULT_FORMAT        AUDIO_FORMAT_PCM_16_BIT
+#define AUDIO_STREAM_DEFAULT_CHANNEL_FLAG  AUDIO_CHANNEL_OUT_STEREO
+
+// AUDIO_STREAM_OUTPUT_BUFFER_SZ controls the size of the audio socket buffer.
+// If one assumes the write buffer is always full during normal BT playback,
+// then increasing this value increases our playback latency.
+//
+// FIXME: AUDIO_STREAM_OUTPUT_BUFFER_SZ should be controlled by the actual audio
+// sample rate rather than being constant.
+//
+// FIXME: The BT HAL should consume data at a constant rate.
+// AudioFlinger assumes that the HAL draws data at a constant rate, which is true
+// for most audio devices; however, the BT engine reads data at a variable rate
+// (over the short term), which confuses both AudioFlinger as well as applications
+// which deliver data at a (generally) fixed rate.
+//
+// 20 * 512 is not sufficient size to smooth the variability for some BT devices,
+// resulting in mixer sleep and throttling. We increase this to 28 * 512 to help
+// reduce the effect of variable data consumption.
+#define AUDIO_STREAM_OUTPUT_BUFFER_SZ      (28*512)
+
+// AUDIO_STREAM_OUTPUT_BUFFER_PERIODS controls how the socket buffer is divided
+// for AudioFlinger data delivery. The AudioFlinger mixer delivers data in chunks
+// of AUDIO_STREAM_OUTPUT_BUFFER_SZ / AUDIO_STREAM_OUTPUT_BUFFER_PERIODS. If
+// the number of periods is 2, the socket buffer represents "double buffering"
+// of the AudioFlinger mixer buffer.
+//
+// In general, AUDIO_STREAM_OUTPUT_BUFFER_PERIODS * 16 * 4 should be a divisor of
+// AUDIO_STREAM_OUTPUT_BUFFER_SZ.
+//
+// These values should be chosen such that
+//
+// AUDIO_STREAM_BUFFER_SIZE * 1000 / (AUDIO_STREAM_OUTPUT_BUFFER_PERIODS
+//         * AUDIO_STREAM_DEFAULT_RATE * 4) > 20 (ms)
+//
+// to avoid introducing the FastMixer in AudioFlinger. Using the FastMixer results in
+// unnecessary latency and CPU overhead for Bluetooth.
+#define AUDIO_STREAM_OUTPUT_BUFFER_PERIODS 4
+
+#define AUDIO_SKT_DISCONNECTED             (-1)
+
+typedef enum {
+    A2DP_CTRL_CMD_NONE,
+    A2DP_CTRL_CMD_CHECK_READY,
+    A2DP_CTRL_CMD_START,
+    A2DP_CTRL_CMD_STOP,
+    A2DP_CTRL_CMD_SUSPEND,
+    A2DP_CTRL_GET_AUDIO_CONFIG,
+    A2DP_CTRL_CMD_OFFLOAD_START,
+} tA2DP_CTRL_CMD;
+
+typedef enum {
+    A2DP_CTRL_ACK_SUCCESS,
+    A2DP_CTRL_ACK_FAILURE,
+    A2DP_CTRL_ACK_INCALL_FAILURE, /* Failure when in Call*/
+    A2DP_CTRL_ACK_UNSUPPORTED
+} tA2DP_CTRL_ACK;
+
+
+/*****************************************************************************
+**  Type definitions for callback functions
+******************************************************************************/
+
+/*****************************************************************************
+**  Type definitions and return values
+******************************************************************************/
+
+/*****************************************************************************
+**  Extern variables and functions
+******************************************************************************/
+
+/*****************************************************************************
+**  Functions
+******************************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Returns a string representation of |event|.
+extern const char* audio_a2dp_hw_dump_ctrl_event(tA2DP_CTRL_CMD event);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* A2DP_AUDIO_HW_H */
diff --git a/bt/audio_a2dp_hw/audio_a2dp_hw_utils.cc b/bt/audio_a2dp_hw/audio_a2dp_hw_utils.cc
new file mode 100644
index 0000000..40d3ade
--- /dev/null
+++ b/bt/audio_a2dp_hw/audio_a2dp_hw_utils.cc
@@ -0,0 +1,38 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#include "audio_a2dp_hw.h"
+
+#define CASE_RETURN_STR(const) case const: return #const;
+
+const char* audio_a2dp_hw_dump_ctrl_event(tA2DP_CTRL_CMD event)
+{
+    switch (event) {
+        CASE_RETURN_STR(A2DP_CTRL_CMD_NONE)
+        CASE_RETURN_STR(A2DP_CTRL_CMD_CHECK_READY)
+        CASE_RETURN_STR(A2DP_CTRL_CMD_START)
+        CASE_RETURN_STR(A2DP_CTRL_CMD_STOP)
+        CASE_RETURN_STR(A2DP_CTRL_CMD_SUSPEND)
+        CASE_RETURN_STR(A2DP_CTRL_GET_AUDIO_CONFIG)
+        CASE_RETURN_STR(A2DP_CTRL_CMD_OFFLOAD_START)
+    default:
+        break;
+    }
+
+    return "UNKNOWN A2DP_CTRL_CMD";
+}
diff --git a/bt/bta/Android.mk b/bt/bta/Android.mk
new file mode 100644
index 0000000..88b9a57
--- /dev/null
+++ b/bt/bta/Android.mk
@@ -0,0 +1,135 @@
+LOCAL_PATH:= $(call my-dir)
+
+# Tests
+btaTestSrc := \
+  test/bta_closure_test.cc
+
+btaCommonIncludes := \
+                   $(LOCAL_PATH)/../ \
+                   $(LOCAL_PATH)/include \
+                   $(LOCAL_PATH)/sys \
+                   $(LOCAL_PATH)/dm \
+                   $(LOCAL_PATH)/hh \
+                   $(LOCAL_PATH)/closure \
+                   $(LOCAL_PATH)/../btcore/include \
+                   $(LOCAL_PATH)/../hci/include \
+                   $(LOCAL_PATH)/../include \
+                   $(LOCAL_PATH)/../stack/include \
+                   $(LOCAL_PATH)/../stack/btm \
+                   $(LOCAL_PATH)/../udrv/include \
+                   $(LOCAL_PATH)/../vnd/include \
+                   $(LOCAL_PATH)/../utils/include \
+                   $(bluetooth_C_INCLUDES)
+
+# BTA static library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+
+LOCAL_SRC_FILES:= \
+    ./ag/bta_ag_act.cc \
+    ./ag/bta_ag_api.cc \
+    ./ag/bta_ag_at.cc \
+    ./ag/bta_ag_cfg.cc \
+    ./ag/bta_ag_ci.cc \
+    ./ag/bta_ag_cmd.cc \
+    ./ag/bta_ag_main.cc \
+    ./ag/bta_ag_rfc.cc \
+    ./ag/bta_ag_sco.cc \
+    ./ag/bta_ag_sdp.cc \
+    ./ar/bta_ar.cc \
+    ./av/bta_av_aact.cc \
+    ./av/bta_av_act.cc \
+    ./av/bta_av_api.cc \
+    ./av/bta_av_cfg.cc \
+    ./av/bta_av_ci.cc \
+    ./av/bta_av_main.cc \
+    ./av/bta_av_ssm.cc \
+    ./closure/bta_closure.cc \
+    ./dm/bta_dm_act.cc \
+    ./dm/bta_dm_api.cc \
+    ./dm/bta_dm_cfg.cc \
+    ./dm/bta_dm_ci.cc \
+    ./dm/bta_dm_main.cc \
+    ./dm/bta_dm_pm.cc \
+    ./dm/bta_dm_sco.cc \
+    ./gatt/bta_gattc_act.cc \
+    ./gatt/bta_gattc_api.cc \
+    ./gatt/bta_gattc_cache.cc \
+    ./gatt/bta_gattc_main.cc \
+    ./gatt/bta_gattc_utils.cc \
+    ./gatt/bta_gatts_act.cc \
+    ./gatt/bta_gatts_api.cc \
+    ./gatt/bta_gatts_main.cc \
+    ./gatt/bta_gatts_utils.cc \
+    ./hf_client/bta_hf_client_act.cc \
+    ./hf_client/bta_hf_client_api.cc \
+    ./hf_client/bta_hf_client_at.cc \
+    ./hf_client/bta_hf_client_cmd.cc \
+    ./hf_client/bta_hf_client_main.cc \
+    ./hf_client/bta_hf_client_rfc.cc \
+    ./hf_client/bta_hf_client_sco.cc \
+    ./hf_client/bta_hf_client_sdp.cc \
+    ./hh/bta_hh_act.cc \
+    ./hh/bta_hh_api.cc \
+    ./hh/bta_hh_cfg.cc \
+    ./hh/bta_hh_le.cc \
+    ./hh/bta_hh_main.cc \
+    ./hh/bta_hh_utils.cc \
+    ./hl/bta_hl_act.cc \
+    ./hl/bta_hl_api.cc \
+    ./hl/bta_hl_ci.cc \
+    ./hl/bta_hl_main.cc \
+    ./hl/bta_hl_sdp.cc \
+    ./hl/bta_hl_utils.cc \
+    ./jv/bta_jv_act.cc \
+    ./jv/bta_jv_api.cc \
+    ./jv/bta_jv_cfg.cc \
+    ./jv/bta_jv_main.cc \
+    ./mce/bta_mce_act.cc \
+    ./mce/bta_mce_api.cc \
+    ./mce/bta_mce_cfg.cc \
+    ./mce/bta_mce_main.cc \
+    ./pan/bta_pan_act.cc \
+    ./pan/bta_pan_api.cc \
+    ./pan/bta_pan_ci.cc \
+    ./pan/bta_pan_main.cc \
+    ./sdp/bta_sdp.cc \
+    ./sdp/bta_sdp_act.cc \
+    ./sdp/bta_sdp_api.cc \
+    ./sdp/bta_sdp_cfg.cc \
+    ./sys/bta_sys_conn.cc \
+    ./sys/bta_sys_main.cc \
+    ./sys/utl.cc
+
+LOCAL_MODULE := libbt-bta
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES := libcutils libc libchrome
+
+LOCAL_C_INCLUDES := $(btaCommonIncludes)
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS) -DBUILDCFG
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_STATIC_LIBRARY)
+
+# bta unit tests for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_CPP_EXTENSION := .cc
+
+LOCAL_C_INCLUDES := $(btaCommonIncludes)
+LOCAL_SRC_FILES := $(btaTestSrc)
+LOCAL_SHARED_LIBRARIES := libcutils libc libchrome libhardware liblog
+LOCAL_STATIC_LIBRARIES := libbtcore libbt-bta libosi
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := net_test_bta
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS) -DBUILDCFG
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_NATIVE_TEST)
diff --git a/bt/bta/BUILD.gn b/bt/bta/BUILD.gn
new file mode 100644
index 0000000..8ce9a9b
--- /dev/null
+++ b/bt/bta/BUILD.gn
@@ -0,0 +1,116 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+static_library("bta") {
+  sources = [
+    "ag/bta_ag_act.cc",
+    "ag/bta_ag_api.cc",
+    "ag/bta_ag_at.cc",
+    "ag/bta_ag_cfg.cc",
+    "ag/bta_ag_ci.cc",
+    "ag/bta_ag_cmd.cc",
+    "ag/bta_ag_main.cc",
+    "ag/bta_ag_rfc.cc",
+    "ag/bta_ag_sco.cc",
+    "ag/bta_ag_sdp.cc",
+    "ar/bta_ar.cc",
+    "av/bta_av_aact.cc",
+    "av/bta_av_act.cc",
+    "av/bta_av_api.cc",
+    "av/bta_av_cfg.cc",
+    "av/bta_av_ci.cc",
+    "av/bta_av_main.cc",
+    "av/bta_av_ssm.cc",
+    "closure/bta_closure.cc",
+    "dm/bta_dm_act.cc",
+    "dm/bta_dm_api.cc",
+    "dm/bta_dm_cfg.cc",
+    "dm/bta_dm_ci.cc",
+    "dm/bta_dm_main.cc",
+    "dm/bta_dm_pm.cc",
+    "dm/bta_dm_sco.cc",
+    "gatt/bta_gattc_act.cc",
+    "gatt/bta_gattc_api.cc",
+    "gatt/bta_gattc_cache.cc",
+    "gatt/bta_gattc_main.cc",
+    "gatt/bta_gattc_utils.cc",
+    "gatt/bta_gatts_act.cc",
+    "gatt/bta_gatts_api.cc",
+    "gatt/bta_gatts_main.cc",
+    "gatt/bta_gatts_utils.cc",
+    "hf_client/bta_hf_client_act.cc",
+    "hf_client/bta_hf_client_api.cc",
+    "hf_client/bta_hf_client_at.cc",
+    "hf_client/bta_hf_client_cmd.cc",
+    "hf_client/bta_hf_client_main.cc",
+    "hf_client/bta_hf_client_rfc.cc",
+    "hf_client/bta_hf_client_sdp.cc",
+    "hf_client/bta_hf_client_sco.cc",
+    "hh/bta_hh_act.cc",
+    "hh/bta_hh_api.cc",
+    "hh/bta_hh_cfg.cc",
+    "hh/bta_hh_le.cc",
+    "hh/bta_hh_main.cc",
+    "hh/bta_hh_utils.cc",
+    "hl/bta_hl_act.cc",
+    "hl/bta_hl_api.cc",
+    "hl/bta_hl_ci.cc",
+    "hl/bta_hl_main.cc",
+    "hl/bta_hl_sdp.cc",
+    "hl/bta_hl_utils.cc",
+    "jv/bta_jv_act.cc",
+    "jv/bta_jv_api.cc",
+    "jv/bta_jv_cfg.cc",
+    "jv/bta_jv_main.cc",
+    "mce/bta_mce_act.cc",
+    "mce/bta_mce_api.cc",
+    "mce/bta_mce_cfg.cc",
+    "mce/bta_mce_main.cc",
+    "pan/bta_pan_act.cc",
+    "pan/bta_pan_api.cc",
+    "pan/bta_pan_ci.cc",
+    "pan/bta_pan_main.cc",
+    "sdp/bta_sdp.cc",
+    "sdp/bta_sdp_act.cc",
+    "sdp/bta_sdp_api.cc",
+    "sdp/bta_sdp_cfg.cc",
+    "sys/bta_sys_conn.cc",
+    "sys/bta_sys_main.cc",
+    "sys/utl.cc",
+  ]
+
+  include_dirs = [
+    "closure",
+    "dm",
+    "hh",
+    "include",
+    "sys",
+    "//",
+    "//btcore/include",
+    "//hci/include",
+    "//include",
+    "//stack/include",
+    "//stack/btm",
+    "//udrv/include",
+    "//utils/include",
+    "//vnd/include",
+  ]
+
+  deps = [
+    "//third_party/libchrome:base"
+  ]
+
+}
diff --git a/bt/bta/ag/bta_ag_act.cc b/bt/bta/ag/bta_ag_act.cc
new file mode 100644
index 0000000..8cd2616
--- /dev/null
+++ b/bt/bta/ag/bta_ag_act.cc
@@ -0,0 +1,868 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 action functions for the audio gateway.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bta_ag_api.h"
+#include "bta_ag_co.h"
+#include "bta_ag_int.h"
+#include "bta_api.h"
+#include "bta_dm_api.h"
+#include "bta_sys.h"
+#include "l2c_api.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+#include "utl.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+/* maximum length of data to read from RFCOMM */
+#define BTA_AG_RFC_READ_MAX 512
+
+/* maximum AT command length */
+#define BTA_AG_CMD_MAX 512
+
+const uint16_t bta_ag_uuid[BTA_AG_NUM_IDX] = {
+    UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY, UUID_SERVCLASS_AG_HANDSFREE};
+
+const uint8_t bta_ag_sec_id[BTA_AG_NUM_IDX] = {BTM_SEC_SERVICE_HEADSET_AG,
+                                               BTM_SEC_SERVICE_AG_HANDSFREE};
+
+const tBTA_SERVICE_ID bta_ag_svc_id[BTA_AG_NUM_IDX] = {BTA_HSP_SERVICE_ID,
+                                                       BTA_HFP_SERVICE_ID};
+
+const tBTA_SERVICE_MASK bta_ag_svc_mask[BTA_AG_NUM_IDX] = {
+    BTA_HSP_SERVICE_MASK, BTA_HFP_SERVICE_MASK};
+
+typedef void (*tBTA_AG_ATCMD_CBACK)(tBTA_AG_SCB* p_scb, uint16_t cmd,
+                                    uint8_t arg_type, char* p_arg,
+                                    int16_t int_arg);
+
+const tBTA_AG_ATCMD_CBACK bta_ag_at_cback_tbl[BTA_AG_NUM_IDX] = {
+    bta_ag_at_hsp_cback, bta_ag_at_hfp_cback};
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_cback_open
+ *
+ * Description      Send open callback event to application.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ag_cback_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data,
+                              tBTA_AG_STATUS status) {
+  tBTA_AG_OPEN open;
+
+  /* call app callback with open event */
+  open.hdr.handle = bta_ag_scb_to_idx(p_scb);
+  open.hdr.app_id = p_scb->app_id;
+  open.status = status;
+  open.service_id = bta_ag_svc_id[p_scb->conn_service];
+  if (p_data) {
+    /* if p_data is provided then we need to pick the bd address from the open
+     * api structure */
+    bdcpy(open.bd_addr, p_data->api_open.bd_addr);
+  } else {
+    bdcpy(open.bd_addr, p_scb->peer_addr);
+  }
+
+  (*bta_ag_cb.p_cback)(BTA_AG_OPEN_EVT, (tBTA_AG*)&open);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_register
+ *
+ * Description      This function initializes values of the AG cb and sets up
+ *                  the SDP record for the services.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_register(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+  tBTA_AG_REGISTER reg;
+
+  /* initialize control block */
+  p_scb->reg_services = p_data->api_register.services;
+  p_scb->serv_sec_mask = p_data->api_register.sec_mask;
+  p_scb->features = p_data->api_register.features;
+  p_scb->app_id = p_data->api_register.app_id;
+
+  /* create SDP records */
+  bta_ag_create_records(p_scb, p_data);
+
+  /* start RFCOMM servers */
+  bta_ag_start_servers(p_scb, p_scb->reg_services);
+
+  /* call app callback with register event */
+  reg.hdr.handle = bta_ag_scb_to_idx(p_scb);
+  reg.hdr.app_id = p_scb->app_id;
+  reg.status = BTA_AG_SUCCESS;
+  (*bta_ag_cb.p_cback)(BTA_AG_REGISTER_EVT, (tBTA_AG*)&reg);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_deregister
+ *
+ * Description      This function removes the sdp records, closes the RFCOMM
+ *                  servers, and deallocates the service control block.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_deregister(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+  /* set dealloc */
+  p_scb->dealloc = true;
+
+  /* remove sdp records */
+  bta_ag_del_records(p_scb, p_data);
+
+  /* remove rfcomm servers */
+  bta_ag_close_servers(p_scb, p_scb->reg_services);
+
+  /* dealloc */
+  bta_ag_scb_dealloc(p_scb);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_start_dereg
+ *
+ * Description      Start a deregister event.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_start_dereg(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+  /* set dealloc */
+  p_scb->dealloc = true;
+
+  /* remove sdp records */
+  bta_ag_del_records(p_scb, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_start_open
+ *
+ * Description      This starts an AG open.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_start_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+  BD_ADDR pending_bd_addr;
+
+  /* store parameters */
+  if (p_data) {
+    bdcpy(p_scb->peer_addr, p_data->api_open.bd_addr);
+    p_scb->open_services = p_data->api_open.services;
+    p_scb->cli_sec_mask = p_data->api_open.sec_mask;
+  }
+
+  /* Check if RFCOMM has any incoming connection to avoid collision. */
+  if (PORT_IsOpening(pending_bd_addr)) {
+    /* Let the incoming connection goes through.                        */
+    /* Issue collision for this scb for now.                            */
+    /* We will decide what to do when we find incoming connetion later. */
+    bta_ag_collision_cback(0, BTA_ID_AG, 0, p_scb->peer_addr);
+    return;
+  }
+
+  /* close servers */
+  bta_ag_close_servers(p_scb, p_scb->reg_services);
+
+  /* set role */
+  p_scb->role = BTA_AG_INT;
+
+  /* do service search */
+  bta_ag_do_disc(p_scb, p_scb->open_services);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_disc_int_res
+ *
+ * Description      This function handles a discovery result when initiator.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_disc_int_res(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+  uint16_t event = BTA_AG_DISC_FAIL_EVT;
+
+  APPL_TRACE_DEBUG("bta_ag_disc_int_res: Status: %d",
+                   p_data->disc_result.status);
+
+  /* if found service */
+  if (p_data->disc_result.status == SDP_SUCCESS ||
+      p_data->disc_result.status == SDP_DB_FULL) {
+    /* get attributes */
+    if (bta_ag_sdp_find_attr(p_scb, p_scb->open_services)) {
+      /* set connected service */
+      p_scb->conn_service = bta_ag_service_to_idx(p_scb->open_services);
+
+      /* send ourselves sdp ok event */
+      event = BTA_AG_DISC_OK_EVT;
+    }
+  }
+
+  /* free discovery db */
+  bta_ag_free_db(p_scb, p_data);
+
+  /* if service not found check if we should search for other service */
+  if ((event == BTA_AG_DISC_FAIL_EVT) &&
+      (p_data->disc_result.status == SDP_SUCCESS ||
+       p_data->disc_result.status == SDP_DB_FULL ||
+       p_data->disc_result.status == SDP_NO_RECS_MATCH)) {
+    if ((p_scb->open_services & BTA_HFP_SERVICE_MASK) &&
+        (p_scb->open_services & BTA_HSP_SERVICE_MASK)) {
+      /* search for HSP */
+      p_scb->open_services &= ~BTA_HFP_SERVICE_MASK;
+      bta_ag_do_disc(p_scb, p_scb->open_services);
+    } else if ((p_scb->open_services & BTA_HSP_SERVICE_MASK) &&
+               (p_scb->hsp_version == HSP_VERSION_1_2)) {
+      /* search for UUID_SERVCLASS_HEADSET for HSP 1.0 device */
+      p_scb->hsp_version = HSP_VERSION_1_0;
+      bta_ag_do_disc(p_scb, p_scb->open_services);
+    } else {
+      /* send ourselves sdp ok/fail event */
+      bta_ag_sm_execute(p_scb, event, p_data);
+    }
+  } else {
+    /* send ourselves sdp ok/fail event */
+    bta_ag_sm_execute(p_scb, event, p_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_disc_acp_res
+ *
+ * Description      This function handles a discovery result when acceptor.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_disc_acp_res(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+  /* if found service */
+  if (p_data->disc_result.status == SDP_SUCCESS ||
+      p_data->disc_result.status == SDP_DB_FULL) {
+    /* get attributes */
+    bta_ag_sdp_find_attr(p_scb, bta_ag_svc_mask[p_scb->conn_service]);
+  }
+
+  /* free discovery db */
+  bta_ag_free_db(p_scb, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_disc_fail
+ *
+ * Description      This function handles a discovery failure.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_disc_fail(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+  /* reopen registered servers */
+  bta_ag_start_servers(p_scb, p_scb->reg_services);
+
+  /* reinitialize stuff */
+
+  /* clear the remote BD address */
+  bdcpy(p_scb->peer_addr, bd_addr_null);
+
+  /* call open cback w. failure */
+  bta_ag_cback_open(p_scb, NULL, BTA_AG_FAIL_SDP);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_open_fail
+ *
+ * Description      open connection failed.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_open_fail(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+  /* call open cback w. failure */
+  bta_ag_cback_open(p_scb, p_data, BTA_AG_FAIL_RESOURCES);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_rfc_fail
+ *
+ * Description      RFCOMM connection failed.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_rfc_fail(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+  /* reinitialize stuff */
+  p_scb->conn_handle = 0;
+  p_scb->conn_service = 0;
+  p_scb->peer_features = 0;
+#if (BTM_WBS_INCLUDED == TRUE)
+  p_scb->peer_codecs = BTA_AG_CODEC_CVSD;
+  p_scb->sco_codec = BTA_AG_CODEC_CVSD;
+#endif
+  p_scb->role = 0;
+  p_scb->svc_conn = false;
+  p_scb->hsp_version = HSP_VERSION_1_2;
+  /*Clear the BD address*/
+  bdcpy(p_scb->peer_addr, bd_addr_null);
+
+  /* reopen registered servers */
+  bta_ag_start_servers(p_scb, p_scb->reg_services);
+
+  /* call open cback w. failure */
+  bta_ag_cback_open(p_scb, NULL, BTA_AG_FAIL_RFCOMM);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_rfc_close
+ *
+ * Description      RFCOMM connection closed.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_rfc_close(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+  tBTA_AG_CLOSE close;
+  tBTA_SERVICE_MASK services;
+  int i, num_active_conn = 0;
+
+  /* reinitialize stuff */
+  p_scb->conn_service = 0;
+  p_scb->peer_features = 0;
+#if (BTM_WBS_INCLUDED == TRUE)
+  p_scb->peer_codecs = BTA_AG_CODEC_CVSD;
+  p_scb->sco_codec = BTA_AG_CODEC_CVSD;
+  /* Clear these flags upon SLC teardown */
+  p_scb->codec_updated = false;
+  p_scb->codec_fallback = false;
+  p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2;
+#endif
+  p_scb->role = 0;
+  p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+  p_scb->svc_conn = false;
+  p_scb->hsp_version = HSP_VERSION_1_2;
+  bta_ag_at_reinit(&p_scb->at_cb);
+
+  memset(&(p_scb->peer_hf_indicators), 0, sizeof(p_scb->peer_hf_indicators));
+  memset(&(p_scb->local_hf_indicators), 0, sizeof(p_scb->local_hf_indicators));
+
+  /* stop timers */
+  alarm_cancel(p_scb->ring_timer);
+#if (BTM_WBS_INCLUDED == TRUE)
+  alarm_cancel(p_scb->codec_negotiation_timer);
+#endif
+
+  close.hdr.handle = bta_ag_scb_to_idx(p_scb);
+  close.hdr.app_id = p_scb->app_id;
+  bdcpy(close.bd_addr, p_scb->peer_addr);
+
+  bta_sys_conn_close(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+  /* call close call-out */
+  bta_ag_co_data_close(close.hdr.handle);
+
+  /* call close cback */
+  (*bta_ag_cb.p_cback)(BTA_AG_CLOSE_EVT, (tBTA_AG*)&close);
+
+  /* if not deregistering (deallocating) reopen registered servers */
+  if (p_scb->dealloc == false) {
+    /* Clear peer bd_addr so instance can be reused */
+    bdcpy(p_scb->peer_addr, bd_addr_null);
+
+    /* start only unopened server */
+    services = p_scb->reg_services;
+    for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++) {
+      if (p_scb->serv_handle[i])
+        services &= ~((tBTA_SERVICE_MASK)1 << (BTA_HSP_SERVICE_ID + i));
+    }
+    bta_ag_start_servers(p_scb, services);
+
+    p_scb->conn_handle = 0;
+
+    /* Make sure SCO state is BTA_AG_SCO_SHUTDOWN_ST */
+    bta_ag_sco_shutdown(p_scb, NULL);
+
+    /* Check if all the SLCs are down */
+    for (i = 0; i < BTA_AG_NUM_SCB; i++) {
+      if (bta_ag_cb.scb[i].in_use && bta_ag_cb.scb[i].svc_conn)
+        num_active_conn++;
+    }
+
+    if (!num_active_conn) {
+      bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+    }
+
+  }
+  /* else close port and deallocate scb */
+  else {
+    RFCOMM_RemoveServer(p_scb->conn_handle);
+    bta_ag_scb_dealloc(p_scb);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_rfc_open
+ *
+ * Description      Handle RFCOMM channel open.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_rfc_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+  /* initialize AT feature variables */
+  p_scb->clip_enabled = false;
+  p_scb->ccwa_enabled = false;
+  p_scb->cmer_enabled = false;
+  p_scb->cmee_enabled = false;
+  p_scb->inband_enabled =
+      ((p_scb->features & BTA_AG_FEAT_INBAND) == BTA_AG_FEAT_INBAND);
+
+  /* set up AT command interpreter */
+  p_scb->at_cb.p_at_tbl = (tBTA_AG_AT_CMD*)bta_ag_at_tbl[p_scb->conn_service];
+  p_scb->at_cb.p_cmd_cback =
+      (tBTA_AG_AT_CMD_CBACK*)bta_ag_at_cback_tbl[p_scb->conn_service];
+  p_scb->at_cb.p_err_cback = (tBTA_AG_AT_ERR_CBACK*)bta_ag_at_err_cback;
+  p_scb->at_cb.p_user = p_scb;
+  p_scb->at_cb.cmd_max_len = BTA_AG_CMD_MAX;
+  bta_ag_at_init(&p_scb->at_cb);
+
+  /* call app open call-out */
+  bta_ag_co_data_open(bta_ag_scb_to_idx(p_scb),
+                      bta_ag_svc_id[p_scb->conn_service]);
+
+  bta_sys_conn_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+  bta_ag_cback_open(p_scb, NULL, BTA_AG_SUCCESS);
+
+  if (p_scb->conn_service == BTA_AG_HFP) {
+    /* if hfp start timer for service level conn */
+    bta_sys_start_timer(p_scb->ring_timer, p_bta_ag_cfg->conn_tout,
+                        BTA_AG_SVC_TIMEOUT_EVT, bta_ag_scb_to_idx(p_scb));
+  } else {
+    /* else service level conn is open */
+    bta_ag_svc_conn_open(p_scb, p_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_rfc_acp_open
+ *
+ * Description      Handle RFCOMM channel open when accepting connection.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_rfc_acp_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+  uint16_t lcid;
+  int i;
+  tBTA_AG_SCB *ag_scb, *other_scb;
+  BD_ADDR dev_addr;
+  int status;
+
+  /* set role */
+  p_scb->role = BTA_AG_ACP;
+
+  APPL_TRACE_DEBUG("bta_ag_rfc_acp_open: serv_handle0 = %d serv_handle1 = %d",
+                   p_scb->serv_handle[0], p_scb->serv_handle[1]);
+
+  /* get bd addr of peer */
+  if (PORT_SUCCESS != (status = PORT_CheckConnection(p_data->rfc.port_handle,
+                                                     dev_addr, &lcid))) {
+    APPL_TRACE_DEBUG(
+        "bta_ag_rfc_acp_open error PORT_CheckConnection returned status %d",
+        status);
+  }
+
+  /* Collision Handling */
+  for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, ag_scb++) {
+    if (ag_scb->in_use && alarm_is_scheduled(ag_scb->collision_timer)) {
+      alarm_cancel(ag_scb->collision_timer);
+
+      if (bdcmp(dev_addr, ag_scb->peer_addr) == 0) {
+        /* If incoming and outgoing device are same, nothing more to do. */
+        /* Outgoing conn will be aborted because we have successful incoming
+         * conn.  */
+      } else {
+        /* Resume outgoing connection. */
+        other_scb = bta_ag_get_other_idle_scb(p_scb);
+        if (other_scb) {
+          bdcpy(other_scb->peer_addr, ag_scb->peer_addr);
+          other_scb->open_services = ag_scb->open_services;
+          other_scb->cli_sec_mask = ag_scb->cli_sec_mask;
+
+          bta_ag_resume_open(other_scb);
+        }
+      }
+
+      break;
+    }
+  }
+
+  bdcpy(p_scb->peer_addr, dev_addr);
+
+  /* determine connected service from port handle */
+  for (i = 0; i < BTA_AG_NUM_IDX; i++) {
+    APPL_TRACE_DEBUG(
+        "bta_ag_rfc_acp_open: i = %d serv_handle = %d port_handle = %d", i,
+        p_scb->serv_handle[i], p_data->rfc.port_handle);
+
+    if (p_scb->serv_handle[i] == p_data->rfc.port_handle) {
+      p_scb->conn_service = i;
+      p_scb->conn_handle = p_data->rfc.port_handle;
+      break;
+    }
+  }
+
+  APPL_TRACE_DEBUG("bta_ag_rfc_acp_open: conn_service = %d conn_handle = %d",
+                   p_scb->conn_service, p_scb->conn_handle);
+
+  /* close any unopened server */
+  bta_ag_close_servers(
+      p_scb, (p_scb->reg_services & ~bta_ag_svc_mask[p_scb->conn_service]));
+
+  /* do service discovery to get features */
+  bta_ag_do_disc(p_scb, bta_ag_svc_mask[p_scb->conn_service]);
+
+  /* continue with common open processing */
+  bta_ag_rfc_open(p_scb, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_rfc_data
+ *
+ * Description      Read and process data from RFCOMM.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_rfc_data(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+  uint16_t len;
+  char buf[BTA_AG_RFC_READ_MAX];
+
+  memset(buf, 0, BTA_AG_RFC_READ_MAX);
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  /* do the following */
+  for (;;) {
+    /* read data from rfcomm; if bad status, we're done */
+    if (PORT_ReadData(p_scb->conn_handle, buf, BTA_AG_RFC_READ_MAX, &len) !=
+        PORT_SUCCESS) {
+      break;
+    }
+
+    /* if no data, we're done */
+    if (len == 0) {
+      break;
+    }
+
+    /* run AT command interpreter on data */
+    bta_sys_busy(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+    bta_ag_at_parse(&p_scb->at_cb, buf, len);
+    if ((p_scb->sco_idx != BTM_INVALID_SCO_INDEX) &&
+        bta_ag_sco_is_open(p_scb)) {
+      APPL_TRACE_DEBUG("%s change link policy for SCO", __func__);
+      bta_sys_sco_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+    } else {
+      bta_sys_idle(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+    }
+
+    /* no more data to read, we're done */
+    if (len < BTA_AG_RFC_READ_MAX) {
+      break;
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_start_close
+ *
+ * Description      Start the process of closing SCO and RFCOMM connection.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_start_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+  /* Take the link out of sniff and set L2C idle time to 0 */
+  bta_dm_pm_active(p_scb->peer_addr);
+  L2CA_SetIdleTimeoutByBdAddr(p_scb->peer_addr, 0, BT_TRANSPORT_BR_EDR);
+
+  /* if SCO is open close SCO and wait on RFCOMM close */
+  if (bta_ag_sco_is_open(p_scb)) {
+    p_scb->post_sco = BTA_AG_POST_SCO_CLOSE_RFC;
+  } else {
+    p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+    bta_ag_rfc_do_close(p_scb, p_data);
+  }
+
+  /* always do SCO shutdown to handle all SCO corner cases */
+  bta_ag_sco_shutdown(p_scb, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_post_sco_open
+ *
+ * Description      Perform post-SCO open action, if any
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_post_sco_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+  switch (p_scb->post_sco) {
+    case BTA_AG_POST_SCO_RING:
+      bta_ag_send_ring(p_scb, p_data);
+      p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+      break;
+
+    case BTA_AG_POST_SCO_CALL_CONN:
+      bta_ag_send_call_inds(p_scb, BTA_AG_IN_CALL_CONN_RES);
+      p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+      break;
+
+    default:
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_post_sco_close
+ *
+ * Description      Perform post-SCO close action, if any
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_post_sco_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+  switch (p_scb->post_sco) {
+    case BTA_AG_POST_SCO_CLOSE_RFC:
+      bta_ag_rfc_do_close(p_scb, p_data);
+      p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+      break;
+
+    case BTA_AG_POST_SCO_CALL_CONN:
+      bta_ag_send_call_inds(p_scb, BTA_AG_IN_CALL_CONN_RES);
+      p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+      break;
+
+    case BTA_AG_POST_SCO_CALL_ORIG:
+      bta_ag_send_call_inds(p_scb, BTA_AG_OUT_CALL_ORIG_RES);
+      p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+      break;
+
+    case BTA_AG_POST_SCO_CALL_END:
+      bta_ag_send_call_inds(p_scb, BTA_AG_END_CALL_RES);
+      p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+      break;
+
+    case BTA_AG_POST_SCO_CALL_END_INCALL:
+      bta_ag_send_call_inds(p_scb, BTA_AG_END_CALL_RES);
+
+      /* Sending callsetup IND and Ring were defered to after SCO close. */
+      bta_ag_send_call_inds(p_scb, BTA_AG_IN_CALL_RES);
+
+      if (bta_ag_inband_enabled(p_scb) &&
+          !(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+        p_scb->post_sco = BTA_AG_POST_SCO_RING;
+        bta_ag_sco_open(p_scb, p_data);
+      } else {
+        p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+        bta_ag_send_ring(p_scb, p_data);
+      }
+      break;
+
+    default:
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_svc_conn_open
+ *
+ * Description      Service level connection opened
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_svc_conn_open(tBTA_AG_SCB* p_scb,
+                          UNUSED_ATTR tBTA_AG_DATA* p_data) {
+  tBTA_AG_CONN evt;
+
+  if (!p_scb->svc_conn) {
+    /* set state variable */
+    p_scb->svc_conn = true;
+
+    /* Clear AT+BIA mask from previous SLC if any. */
+    p_scb->bia_masked_out = 0;
+
+    alarm_cancel(p_scb->ring_timer);
+
+    /* call callback */
+    evt.hdr.handle = bta_ag_scb_to_idx(p_scb);
+    evt.hdr.app_id = p_scb->app_id;
+    evt.peer_feat = p_scb->peer_features;
+    bdcpy(evt.bd_addr, p_scb->peer_addr);
+#if (BTM_WBS_INCLUDED == TRUE)
+    evt.peer_codec = p_scb->peer_codecs;
+#endif
+
+    if ((p_scb->call_ind != BTA_AG_CALL_INACTIVE) ||
+        (p_scb->callsetup_ind != BTA_AG_CALLSETUP_NONE)) {
+      bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+    }
+
+    (*bta_ag_cb.p_cback)(BTA_AG_CONN_EVT, (tBTA_AG*)&evt);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_ci_rx_data
+ *
+ * Description      Send result code
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_ci_rx_data(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+  uint16_t len;
+  tBTA_AG_CI_RX_WRITE* p_rx_write_msg = (tBTA_AG_CI_RX_WRITE*)p_data;
+  char* p_data_area =
+      (char*)(p_rx_write_msg + 1); /* Point to data area after header */
+
+  APPL_TRACE_DEBUG("bta_ag_ci_rx_data:");
+  /* send to RFCOMM */
+  bta_sys_busy(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+  PORT_WriteData(p_scb->conn_handle, p_data_area, strlen(p_data_area), &len);
+  if ((p_scb->sco_idx != BTM_INVALID_SCO_INDEX) && bta_ag_sco_is_open(p_scb)) {
+    APPL_TRACE_DEBUG("bta_ag_rfc_data, change link policy for SCO");
+    bta_sys_sco_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+  } else {
+    bta_sys_idle(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_rcvd_slc_ready
+ *
+ * Description      Handles SLC ready call-in in case of pass-through mode.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_rcvd_slc_ready(tBTA_AG_SCB* p_scb,
+                           UNUSED_ATTR tBTA_AG_DATA* p_data) {
+  APPL_TRACE_DEBUG("bta_ag_rcvd_slc_ready: handle = %d",
+                   bta_ag_scb_to_idx(p_scb));
+
+  if (bta_ag_cb.parse_mode == BTA_AG_PASS_THROUGH) {
+    /* In pass-through mode, BTA knows that SLC is ready only through call-in.
+     */
+    bta_ag_svc_conn_open(p_scb, NULL);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_setcodec
+ *
+ * Description      Handle API SetCodec
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_setcodec(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+#if (BTM_WBS_INCLUDED == TRUE)
+  tBTA_AG_PEER_CODEC codec_type = p_data->api_setcodec.codec;
+  tBTA_AG_VAL val;
+
+  /* Check if the requested codec type is valid */
+  if ((codec_type != BTA_AG_CODEC_NONE) && (codec_type != BTA_AG_CODEC_CVSD) &&
+      (codec_type != BTA_AG_CODEC_MSBC)) {
+    val.num = codec_type;
+    val.hdr.status = BTA_AG_FAIL_RESOURCES;
+    APPL_TRACE_ERROR("bta_ag_setcodec error: unsupported codec type %d",
+                     codec_type);
+    (*bta_ag_cb.p_cback)(BTA_AG_WBS_EVT, (tBTA_AG*)&val);
+    return;
+  }
+
+  if ((p_scb->peer_codecs & codec_type) || (codec_type == BTA_AG_CODEC_NONE) ||
+      (codec_type == BTA_AG_CODEC_CVSD)) {
+    p_scb->sco_codec = codec_type;
+    p_scb->codec_updated = true;
+    val.num = codec_type;
+    val.hdr.status = BTA_AG_SUCCESS;
+    APPL_TRACE_DEBUG("bta_ag_setcodec: Updated codec type %d", codec_type);
+  } else {
+    val.num = codec_type;
+    val.hdr.status = BTA_AG_FAIL_RESOURCES;
+    APPL_TRACE_ERROR("bta_ag_setcodec error: unsupported codec type %d",
+                     codec_type);
+  }
+
+  (*bta_ag_cb.p_cback)(BTA_AG_WBS_EVT, (tBTA_AG*)&val);
+#endif
+}
diff --git a/bt/bta/ag/bta_ag_api.cc b/bt/bta/ag/bta_ag_api.cc
new file mode 100644
index 0000000..6df3a1e
--- /dev/null
+++ b/bt/bta/ag/bta_ag_api.cc
@@ -0,0 +1,278 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 is the implementation of the API for the audio gateway (AG)
+ *  subsystem of BTA, Broadcom's Bluetooth application layer for mobile
+ *  phones.
+ *
+ ******************************************************************************/
+
+#include "bta_ag_api.h"
+#include <string.h>
+#include "bt_common.h"
+#include "bta_ag_int.h"
+#include "bta_api.h"
+#include "bta_sys.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_ag_reg = {bta_ag_hdl_event, BTA_AgDisable};
+
+/*******************************************************************************
+ *
+ * Function         BTA_AgEnable
+ *
+ * Description      Enable the audio gateway service. When the enable
+ *                  operation is complete the callback function will be
+ *                  called with a BTA_AG_ENABLE_EVT. This function must
+ *                  be called before other function in the AG API are
+ *                  called.
+ *
+ * Returns          BTA_SUCCESS if OK, BTA_FAILURE otherwise.
+ *
+ ******************************************************************************/
+tBTA_STATUS BTA_AgEnable(tBTA_AG_PARSE_MODE parse_mode,
+                         tBTA_AG_CBACK* p_cback) {
+  /* Error if AG is already enabled, or AG is in the middle of disabling. */
+  for (int idx = 0; idx < BTA_AG_NUM_SCB; idx++) {
+    if (bta_ag_cb.scb[idx].in_use) {
+      APPL_TRACE_ERROR("BTA_AgEnable: FAILED, AG already enabled.");
+      return BTA_FAILURE;
+    }
+  }
+
+  /* register with BTA system manager */
+  bta_sys_register(BTA_ID_AG, &bta_ag_reg);
+
+  tBTA_AG_API_ENABLE* p_buf =
+      (tBTA_AG_API_ENABLE*)osi_malloc(sizeof(tBTA_AG_API_ENABLE));
+  p_buf->hdr.event = BTA_AG_API_ENABLE_EVT;
+  p_buf->parse_mode = parse_mode;
+  p_buf->p_cback = p_cback;
+
+  bta_sys_sendmsg(p_buf);
+
+  return BTA_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AgDisable
+ *
+ * Description      Disable the audio gateway service
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AgDisable(void) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = BTA_AG_API_DISABLE_EVT;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AgRegister
+ *
+ * Description      Register an Audio Gateway service.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AgRegister(tBTA_SERVICE_MASK services, tBTA_SEC sec_mask,
+                    tBTA_AG_FEAT features, const char* p_service_names[],
+                    uint8_t app_id) {
+  tBTA_AG_API_REGISTER* p_buf =
+      (tBTA_AG_API_REGISTER*)osi_malloc(sizeof(tBTA_AG_API_REGISTER));
+
+  p_buf->hdr.event = BTA_AG_API_REGISTER_EVT;
+  p_buf->features = features;
+  p_buf->sec_mask = sec_mask;
+  p_buf->services = services;
+  p_buf->app_id = app_id;
+  for (int i = 0; i < BTA_AG_NUM_IDX; i++) {
+    if (p_service_names[i])
+      strlcpy(p_buf->p_name[i], p_service_names[i], BTA_SERVICE_NAME_LEN);
+    else
+      p_buf->p_name[i][0] = 0;
+  }
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AgDeregister
+ *
+ * Description      Deregister an audio gateway service.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AgDeregister(uint16_t handle) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = BTA_AG_API_DEREGISTER_EVT;
+  p_buf->layer_specific = handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AgOpen
+ *
+ * Description      Opens a connection to a headset or hands-free device.
+ *                  When connection is open callback function is called
+ *                  with a BTA_AG_OPEN_EVT. Only the data connection is
+ *                  opened. The audio connection is not opened.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AgOpen(uint16_t handle, BD_ADDR bd_addr, tBTA_SEC sec_mask,
+                tBTA_SERVICE_MASK services) {
+  tBTA_AG_API_OPEN* p_buf =
+      (tBTA_AG_API_OPEN*)osi_malloc(sizeof(tBTA_AG_API_OPEN));
+
+  p_buf->hdr.event = BTA_AG_API_OPEN_EVT;
+  p_buf->hdr.layer_specific = handle;
+  bdcpy(p_buf->bd_addr, bd_addr);
+  p_buf->services = services;
+  p_buf->sec_mask = sec_mask;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AgClose
+ *
+ * Description      Close the current connection to a headset or a handsfree
+ *                  Any current audio connection will also be closed.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AgClose(uint16_t handle) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = BTA_AG_API_CLOSE_EVT;
+  p_buf->layer_specific = handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AgAudioOpen
+ *
+ * Description      Opens an audio connection to the currently connected
+ *                  headset or hnadsfree.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AgAudioOpen(uint16_t handle) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = BTA_AG_API_AUDIO_OPEN_EVT;
+  p_buf->layer_specific = handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AgAudioClose
+ *
+ * Description      Close the currently active audio connection to a headset
+ *                  or hnadsfree. The data connection remains open
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AgAudioClose(uint16_t handle) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = BTA_AG_API_AUDIO_CLOSE_EVT;
+  p_buf->layer_specific = handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AgResult
+ *
+ * Description      Send an AT result code to a headset or hands-free device.
+ *                  This function is only used when the AG parse mode is set
+ *                  to BTA_AG_PARSE.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AgResult(uint16_t handle, tBTA_AG_RES result,
+                  tBTA_AG_RES_DATA* p_data) {
+  tBTA_AG_API_RESULT* p_buf =
+      (tBTA_AG_API_RESULT*)osi_malloc(sizeof(tBTA_AG_API_RESULT));
+
+  p_buf->hdr.event = BTA_AG_API_RESULT_EVT;
+  p_buf->hdr.layer_specific = handle;
+  p_buf->result = result;
+  if (p_data) memcpy(&p_buf->data, p_data, sizeof(p_buf->data));
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AgSetCodec
+ *
+ * Description      Specify the codec type to be used for the subsequent
+ *                  audio connection.
+ *
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AgSetCodec(uint16_t handle, tBTA_AG_PEER_CODEC codec) {
+  tBTA_AG_API_SETCODEC* p_buf =
+      (tBTA_AG_API_SETCODEC*)osi_malloc(sizeof(tBTA_AG_API_SETCODEC));
+
+  p_buf->hdr.event = BTA_AG_API_SETCODEC_EVT;
+  p_buf->hdr.layer_specific = handle;
+  p_buf->codec = codec;
+
+  bta_sys_sendmsg(p_buf);
+}
diff --git a/bt/bta/ag/bta_ag_at.cc b/bt/bta/ag/bta_ag_at.cc
new file mode 100644
index 0000000..3e4868b
--- /dev/null
+++ b/bt/bta/ag/bta_ag_at.cc
@@ -0,0 +1,209 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  BTA AG AT command interpreter.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_ag_at.h"
+#include "utl.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ * Function         bta_ag_at_init
+ *
+ * Description      Initialize the AT command parser control block.
+ *
+ *
+ * Returns          void
+ *
+ *****************************************************************************/
+void bta_ag_at_init(tBTA_AG_AT_CB* p_cb) {
+  p_cb->p_cmd_buf = NULL;
+  p_cb->cmd_pos = 0;
+}
+
+/******************************************************************************
+ *
+ * Function         bta_ag_at_reinit
+ *
+ * Description      Re-initialize the AT command parser control block.  This
+ *                  function resets the AT command parser state and frees
+ *                  any GKI buffer.
+ *
+ *
+ * Returns          void
+ *
+ *****************************************************************************/
+void bta_ag_at_reinit(tBTA_AG_AT_CB* p_cb) {
+  osi_free_and_reset((void**)&p_cb->p_cmd_buf);
+  p_cb->cmd_pos = 0;
+}
+
+/******************************************************************************
+ *
+ * Function         bta_ag_process_at
+ *
+ * Description      Parse AT commands.  This function will take the input
+ *                  character string and parse it for AT commands according to
+ *                  the AT command table passed in the control block.
+ *
+ *
+ * Returns          void
+ *
+ *****************************************************************************/
+void bta_ag_process_at(tBTA_AG_AT_CB* p_cb) {
+  uint16_t idx;
+  uint8_t arg_type;
+  char* p_arg;
+  int16_t int_arg = 0;
+  /* loop through at command table looking for match */
+  for (idx = 0; p_cb->p_at_tbl[idx].p_cmd[0] != 0; idx++) {
+    if (!utl_strucmp(p_cb->p_at_tbl[idx].p_cmd, p_cb->p_cmd_buf)) {
+      break;
+    }
+  }
+
+  /* if there is a match; verify argument type */
+  if (p_cb->p_at_tbl[idx].p_cmd[0] != 0) {
+    /* start of argument is p + strlen matching command */
+    p_arg = p_cb->p_cmd_buf + strlen(p_cb->p_at_tbl[idx].p_cmd);
+
+    /* if no argument */
+    if (p_arg[0] == 0) {
+      arg_type = BTA_AG_AT_NONE;
+    }
+    /* else if arg is '?' and it is last character */
+    else if (p_arg[0] == '?' && p_arg[1] == 0) {
+      /* we have a read */
+      arg_type = BTA_AG_AT_READ;
+    }
+    /* else if arg is '=' */
+    else if (p_arg[0] == '=' && p_arg[1] != 0) {
+      if (p_arg[1] == '?' && p_arg[2] == 0) {
+        /* we have a test */
+        arg_type = BTA_AG_AT_TEST;
+      } else {
+        /* we have a set */
+        arg_type = BTA_AG_AT_SET;
+
+        /* skip past '=' */
+        p_arg++;
+      }
+    } else
+    /* else it is freeform argument */
+    {
+      arg_type = BTA_AG_AT_FREE;
+    }
+
+    /* if arguments match command capabilities */
+    if ((arg_type & p_cb->p_at_tbl[idx].arg_type) != 0) {
+      /* if it's a set integer check max, min range */
+      if (arg_type == BTA_AG_AT_SET &&
+          p_cb->p_at_tbl[idx].fmt == BTA_AG_AT_INT) {
+        int_arg = utl_str2int(p_arg);
+        if (int_arg < (int16_t)p_cb->p_at_tbl[idx].min ||
+            int_arg > (int16_t)p_cb->p_at_tbl[idx].max) {
+          /* arg out of range; error */
+          (*p_cb->p_err_cback)(p_cb->p_user, false, NULL);
+        } else {
+          (*p_cb->p_cmd_cback)(p_cb->p_user, p_cb->p_at_tbl[idx].command_id,
+                               arg_type, p_arg, int_arg);
+        }
+      } else {
+        (*p_cb->p_cmd_cback)(p_cb->p_user, p_cb->p_at_tbl[idx].command_id,
+                             arg_type, p_arg, int_arg);
+      }
+    }
+    /* else error */
+    else {
+      (*p_cb->p_err_cback)(p_cb->p_user, false, NULL);
+    }
+  }
+  /* else no match call error callback */
+  else {
+    (*p_cb->p_err_cback)(p_cb->p_user, true, p_cb->p_cmd_buf);
+  }
+}
+
+/******************************************************************************
+ *
+ * Function         bta_ag_at_parse
+ *
+ * Description      Parse AT commands.  This function will take the input
+ *                  character string and parse it for AT commands according to
+ *                  the AT command table passed in the control block.
+ *
+ *
+ * Returns          void
+ *
+ *****************************************************************************/
+void bta_ag_at_parse(tBTA_AG_AT_CB* p_cb, char* p_buf, uint16_t len) {
+  int i = 0;
+  char* p_save;
+
+  if (p_cb->p_cmd_buf == NULL) {
+    p_cb->p_cmd_buf = (char*)osi_malloc(p_cb->cmd_max_len);
+    p_cb->cmd_pos = 0;
+  }
+
+  for (i = 0; i < len;) {
+    while (p_cb->cmd_pos < p_cb->cmd_max_len - 1 && i < len) {
+      /* Skip null characters between AT commands. */
+      if ((p_cb->cmd_pos == 0) && (p_buf[i] == 0)) {
+        i++;
+        continue;
+      }
+
+      p_cb->p_cmd_buf[p_cb->cmd_pos] = p_buf[i++];
+      if (p_cb->p_cmd_buf[p_cb->cmd_pos] == '\r' ||
+          p_cb->p_cmd_buf[p_cb->cmd_pos] == '\n') {
+        p_cb->p_cmd_buf[p_cb->cmd_pos] = 0;
+        if ((p_cb->cmd_pos > 2) &&
+            (p_cb->p_cmd_buf[0] == 'A' || p_cb->p_cmd_buf[0] == 'a') &&
+            (p_cb->p_cmd_buf[1] == 'T' || p_cb->p_cmd_buf[1] == 't')) {
+          p_save = p_cb->p_cmd_buf;
+          p_cb->p_cmd_buf += 2;
+          bta_ag_process_at(p_cb);
+          p_cb->p_cmd_buf = p_save;
+        }
+
+        p_cb->cmd_pos = 0;
+
+      } else if (p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1A ||
+                 p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1B) {
+        p_cb->p_cmd_buf[++p_cb->cmd_pos] = 0;
+        (*p_cb->p_err_cback)(p_cb->p_user, true, p_cb->p_cmd_buf);
+        p_cb->cmd_pos = 0;
+      } else {
+        ++p_cb->cmd_pos;
+      }
+    }
+
+    if (i < len) p_cb->cmd_pos = 0;
+  }
+}
diff --git a/bt/bta/ag/bta_ag_at.h b/bt/bta/ag/bta_ag_at.h
new file mode 100644
index 0000000..f5636e0
--- /dev/null
+++ b/bt/bta/ag/bta_ag_at.h
@@ -0,0 +1,128 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Interface file for BTA AG AT command interpreter.
+ *
+ ******************************************************************************/
+#ifndef BTA_AG_AT_H
+#define BTA_AG_AT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+/* AT command argument capabilities */
+#define BTA_AG_AT_NONE 0x01 /* no argument */
+#define BTA_AG_AT_SET 0x02  /* set value */
+#define BTA_AG_AT_READ 0x04 /* read value */
+#define BTA_AG_AT_TEST 0x08 /* test value range */
+#define BTA_AG_AT_FREE 0x10 /* freeform argument */
+
+/* AT command argument format */
+#define BTA_AG_AT_STR 0 /* string */
+#define BTA_AG_AT_INT 1 /* integer */
+
+/*****************************************************************************
+ *  Data types
+ ****************************************************************************/
+
+/* AT command table element */
+typedef struct {
+  const char* p_cmd; /* AT command string */
+  size_t command_id; /* passed to the callback on p_cmd match */
+  uint8_t arg_type;  /* allowable argument type syntax */
+  uint8_t fmt;       /* whether arg is int or string */
+  uint8_t min;       /* minimum value for int arg */
+  int16_t max;       /* maximum value for int arg */
+} tBTA_AG_AT_CMD;
+
+/* callback function executed when command is parsed */
+typedef void(tBTA_AG_AT_CMD_CBACK)(void* p_user, uint16_t command_id,
+                                   uint8_t arg_type, char* p_arg,
+                                   int16_t int_arg);
+
+/* callback function executed to send "ERROR" result code */
+typedef void(tBTA_AG_AT_ERR_CBACK)(void* p_user, bool unknown, char* p_arg);
+
+/* AT command parsing control block */
+typedef struct {
+  tBTA_AG_AT_CMD* p_at_tbl;          /* AT command table */
+  tBTA_AG_AT_CMD_CBACK* p_cmd_cback; /* command callback */
+  tBTA_AG_AT_ERR_CBACK* p_err_cback; /* error callback */
+  void* p_user;                      /* user-defined data */
+  char* p_cmd_buf;                   /* temp parsing buffer */
+  uint16_t cmd_pos;                  /* position in temp buffer */
+  uint16_t cmd_max_len;              /* length of temp buffer to allocate */
+  uint8_t state;                     /* parsing state */
+} tBTA_AG_AT_CB;
+
+/*****************************************************************************
+ *  Function prototypes
+ ****************************************************************************/
+
+/*****************************************************************************
+ *
+ * Function         bta_ag_at_init
+ *
+ * Description      Initialize the AT command parser control block.
+ *
+ *
+ * Returns          void
+ *
+ ****************************************************************************/
+extern void bta_ag_at_init(tBTA_AG_AT_CB* p_cb);
+
+/*****************************************************************************
+ *
+ * Function         bta_ag_at_reinit
+ *
+ * Description      Re-initialize the AT command parser control block.  This
+ *                  function resets the AT command parser state and frees
+ *                  any GKI buffer.
+ *
+ *
+ * Returns          void
+ *
+ ****************************************************************************/
+extern void bta_ag_at_reinit(tBTA_AG_AT_CB* p_cb);
+
+/*****************************************************************************
+ *
+ * Function         bta_ag_at_parse
+ *
+ * Description      Parse AT commands.  This function will take the input
+ *                  character string and parse it for AT commands according to
+ *                  the AT command table passed in the control block.
+ *
+ *
+ * Returns          void
+ *
+ ****************************************************************************/
+extern void bta_ag_at_parse(tBTA_AG_AT_CB* p_cb, char* p_buf, uint16_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_AG_AT_H */
diff --git a/bt/bta/ag/bta_ag_cfg.cc b/bt/bta/ag/bta_ag_cfg.cc
new file mode 100644
index 0000000..9a1c879
--- /dev/null
+++ b/bt/bta/ag/bta_ag_cfg.cc
@@ -0,0 +1,78 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 compile-time configurable constants for the audio
+ *  gateway.
+ *
+ ******************************************************************************/
+
+#include "bt_common.h"
+#include "bta_ag_api.h"
+#include "bta_ag_int.h"
+#include "bta_api.h"
+
+#ifndef BTA_AG_CIND_INFO
+#define BTA_AG_CIND_INFO                                                       \
+  "(\"call\",(0,1)),(\"callsetup\",(0-3)),(\"service\",(0-3)),(\"signal\",(0-" \
+  "6)),(\"roam\",(0,1)),(\"battchg\",(0-5)),(\"callheld\",(0-2)),(\"bearer\"," \
+  "(0-7))"
+#endif
+
+#ifndef BTA_AG_CHLD_VAL_ECC
+#define BTA_AG_CHLD_VAL_ECC "(0,1,1x,2,2x,3,4)"
+#endif
+
+#ifndef BTA_AG_CHLD_VAL
+#define BTA_AG_CHLD_VAL "(0,1,2,3,4)"
+#endif
+
+#ifndef BTA_AG_CONN_TIMEOUT
+#define BTA_AG_CONN_TIMEOUT 5000
+#endif
+
+#ifndef BTA_AG_SCO_PKT_TYPES
+/* S1 packet type setting from HFP 1.5 spec */
+#define BTA_AG_SCO_PKT_TYPES /* BTM_SCO_LINK_ALL_PKT_MASK */           \
+  (BTM_SCO_LINK_ONLY_MASK | BTM_SCO_PKT_TYPES_MASK_EV3 |               \
+   BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | \
+   BTM_SCO_PKT_TYPES_MASK_NO_3_EV5)
+#endif
+
+#ifndef BTA_AG_BIND_INFO
+#define BTA_AG_BIND_INFO "(1)"
+#endif
+
+const tBTA_AG_HF_IND bta_ag_local_hf_ind_cfg[] = {
+    /* The first row contains the number of indicators. Need to be updated
+       accordingly */
+    {BTA_AG_NUM_LOCAL_HF_IND, 0, 0, 0, 0},
+
+    {1, 1, 1, 0,
+     1}, /* Enhanced Driver Status, supported, enabled, range 0 ~ 1 */
+    {2, 1, 1, 0,
+     100} /* Battery Level Status, supported, enabled, range 0 ~ 100 */
+};
+
+const tBTA_AG_CFG bta_ag_cfg = {BTA_AG_CIND_INFO,        BTA_AG_BIND_INFO,
+                                BTA_AG_NUM_LOCAL_HF_IND, BTA_AG_CONN_TIMEOUT,
+                                BTA_AG_SCO_PKT_TYPES,    BTA_AG_CHLD_VAL_ECC,
+                                BTA_AG_CHLD_VAL};
+
+tBTA_AG_CFG* p_bta_ag_cfg = (tBTA_AG_CFG*)&bta_ag_cfg;
diff --git a/bt/bta/ag/bta_ag_ci.cc b/bt/bta/ag/bta_ag_ci.cc
new file mode 100644
index 0000000..1fde9d8
--- /dev/null
+++ b/bt/bta/ag/bta_ag_ci.cc
@@ -0,0 +1,88 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 is the implementation file for audio gateway call-in functions.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_ag_api.h"
+#include "bta_ag_ci.h"
+#include "bta_ag_int.h"
+#include "bta_api.h"
+
+/******************************************************************************
+ *
+ * Function         bta_ag_ci_rx_write
+ *
+ * Description      This function is called to send data to the AG when the AG
+ *                  is configured for AT command pass-through.  The function
+ *                  copies data to an event buffer and sends it.
+ *
+ * Returns          void
+ *
+ *****************************************************************************/
+void bta_ag_ci_rx_write(uint16_t handle, char* p_data, uint16_t len) {
+  uint16_t len_remaining = len;
+  char* p_data_area;
+
+  if (len > (RFCOMM_DATA_BUF_SIZE - sizeof(tBTA_AG_CI_RX_WRITE) - 1))
+    len = RFCOMM_DATA_BUF_SIZE - sizeof(tBTA_AG_CI_RX_WRITE) - 1;
+
+  while (len_remaining) {
+    if (len_remaining < len) len = len_remaining;
+
+    tBTA_AG_CI_RX_WRITE* p_buf =
+        (tBTA_AG_CI_RX_WRITE*)osi_malloc(sizeof(tBTA_AG_CI_RX_WRITE) + len + 1);
+    p_buf->hdr.event = BTA_AG_CI_RX_WRITE_EVT;
+    p_buf->hdr.layer_specific = handle;
+
+    p_data_area = (char*)(p_buf + 1); /* Point to data area after header */
+    strncpy(p_data_area, p_data, len);
+    p_data_area[len] = 0;
+
+    bta_sys_sendmsg(p_buf);
+
+    len_remaining -= len;
+    p_data += len;
+  }
+}
+
+/******************************************************************************
+ *
+ * Function         bta_ag_ci_slc_ready
+ *
+ * Description      This function is called to notify AG that SLC is up at
+ *                  the application. This funcion is only used when the app
+ *                  is running in pass-through mode.
+ *
+ * Returns          void
+ *
+ *****************************************************************************/
+void bta_ag_ci_slc_ready(uint16_t handle) {
+  tBTA_AG_DATA* p_buf = (tBTA_AG_DATA*)osi_malloc(sizeof(tBTA_AG_DATA));
+
+  p_buf->hdr.event = BTA_AG_CI_SLC_READY_EVT;
+  p_buf->hdr.layer_specific = handle;
+
+  bta_sys_sendmsg(p_buf);
+}
diff --git a/bt/bta/ag/bta_ag_cmd.cc b/bt/bta/ag/bta_ag_cmd.cc
new file mode 100644
index 0000000..dbbd460
--- /dev/null
+++ b/bt/bta/ag/bta_ag_cmd.cc
@@ -0,0 +1,1748 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bta_ag_cmd"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bta_ag_api.h"
+#include "bta_ag_at.h"
+#include "bta_ag_int.h"
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+#include "utl.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+/* Ring timeout */
+#define BTA_AG_RING_TIMEOUT_MS (5 * 1000) /* 5 seconds */
+
+#define BTA_AG_CMD_MAX_VAL 32767 /* Maximum value is signed 16-bit value */
+
+/* Invalid Chld command */
+#define BTA_AG_INVALID_CHLD 255
+
+/* clip type constants */
+#define BTA_AG_CLIP_TYPE_MIN 128
+#define BTA_AG_CLIP_TYPE_MAX 175
+#define BTA_AG_CLIP_TYPE_DEFAULT 129
+#define BTA_AG_CLIP_TYPE_VOIP 255
+
+#define COLON_IDX_4_VGSVGM 4
+
+/* Local events which will not trigger a higher layer callback */
+enum {
+  BTA_AG_LOCAL_EVT_FIRST = 0x100,
+  BTA_AG_LOCAL_EVT_CCWA,
+  BTA_AG_LOCAL_EVT_CLIP,
+  BTA_AG_LOCAL_EVT_CMER,
+  BTA_AG_LOCAL_EVT_BRSF,
+  BTA_AG_LOCAL_EVT_CMEE,
+  BTA_AG_LOCAL_EVT_BIA,
+  BTA_AG_LOCAL_EVT_BCC,
+};
+
+/* AT command interpreter table for HSP */
+const tBTA_AG_AT_CMD bta_ag_hsp_cmd[] = {
+    {"+CKPD", BTA_AG_AT_CKPD_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 200, 200},
+    {"+VGS", BTA_AG_SPK_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
+    {"+VGM", BTA_AG_MIC_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
+    /* End-of-table marker used to stop lookup iteration */
+    {"", 0, 0, 0, 0, 0}};
+
+/* AT command interpreter table for HFP */
+const tBTA_AG_AT_CMD bta_ag_hfp_cmd[] = {
+    {"A", BTA_AG_AT_A_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+    {"D", BTA_AG_AT_D_EVT, BTA_AG_AT_NONE | BTA_AG_AT_FREE, BTA_AG_AT_STR, 0,
+     0},
+    {"+VGS", BTA_AG_SPK_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
+    {"+VGM", BTA_AG_MIC_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
+    {"+CCWA", BTA_AG_LOCAL_EVT_CCWA, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
+    /* Consider CHLD as str to take care of indexes for ECC */
+    {"+CHLD", BTA_AG_AT_CHLD_EVT, BTA_AG_AT_SET | BTA_AG_AT_TEST, BTA_AG_AT_STR,
+     0, 4},
+    {"+CHUP", BTA_AG_AT_CHUP_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+    {"+CIND", BTA_AG_AT_CIND_EVT, BTA_AG_AT_READ | BTA_AG_AT_TEST,
+     BTA_AG_AT_STR, 0, 0},
+    {"+CLIP", BTA_AG_LOCAL_EVT_CLIP, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
+    {"+CMER", BTA_AG_LOCAL_EVT_CMER, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
+    {"+VTS", BTA_AG_AT_VTS_EVT, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
+    {"+BINP", BTA_AG_AT_BINP_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 1, 1},
+    {"+BLDN", BTA_AG_AT_BLDN_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+    {"+BVRA", BTA_AG_AT_BVRA_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
+    {"+BRSF", BTA_AG_LOCAL_EVT_BRSF, BTA_AG_AT_SET, BTA_AG_AT_INT, 0,
+     BTA_AG_CMD_MAX_VAL},
+    {"+NREC", BTA_AG_AT_NREC_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 0},
+    {"+CNUM", BTA_AG_AT_CNUM_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+    {"+BTRH", BTA_AG_AT_BTRH_EVT, BTA_AG_AT_READ | BTA_AG_AT_SET, BTA_AG_AT_INT,
+     0, 2},
+    {"+CLCC", BTA_AG_AT_CLCC_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+    {"+COPS", BTA_AG_AT_COPS_EVT, BTA_AG_AT_READ | BTA_AG_AT_SET, BTA_AG_AT_STR,
+     0, 0},
+    {"+CMEE", BTA_AG_LOCAL_EVT_CMEE, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
+    {"+BIA", BTA_AG_LOCAL_EVT_BIA, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 20},
+    {"+CBC", BTA_AG_AT_CBC_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 100},
+    {"+BCC", BTA_AG_LOCAL_EVT_BCC, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+    {"+BCS", BTA_AG_AT_BCS_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0,
+     BTA_AG_CMD_MAX_VAL},
+    {"+BIND", BTA_AG_AT_BIND_EVT,
+     BTA_AG_AT_SET | BTA_AG_AT_READ | BTA_AG_AT_TEST, BTA_AG_AT_STR, 0, 0},
+    {"+BIEV", BTA_AG_AT_BIEV_EVT, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
+    {"+BAC", BTA_AG_AT_BAC_EVT, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
+    /* End-of-table marker used to stop lookup iteration */
+    {"", 0, 0, 0, 0, 0}};
+
+/* AT result code table element */
+typedef struct {
+  const char* result_string; /* AT result string */
+  size_t result_id;          /* Local or BTA result id */
+  uint8_t arg_type;          /* whether argument is int or string */
+} tBTA_AG_RESULT;
+
+/* AT result code argument types */
+enum {
+  BTA_AG_RES_FMT_NONE, /* no argument */
+  BTA_AG_RES_FMT_INT,  /* integer argument */
+  BTA_AG_RES_FMT_STR   /* string argument */
+};
+
+/* Local AT command result codes not defined in bta_ag_api.h */
+enum {
+  BTA_AG_LOCAL_RES_FIRST = 0x0100,
+  BTA_AG_LOCAL_RES_OK,
+  BTA_AG_LOCAL_RES_ERROR,
+  BTA_AG_LOCAL_RES_RING,
+  BTA_AG_LOCAL_RES_CLIP,
+  BTA_AG_LOCAL_RES_BRSF,
+  BTA_AG_LOCAL_RES_CMEE,
+  BTA_AG_LOCAL_RES_BCS
+};
+
+/* AT result code constant table */
+const tBTA_AG_RESULT bta_ag_result_tbl[] = {
+    {"OK", BTA_AG_LOCAL_RES_OK, BTA_AG_RES_FMT_NONE},
+    {"ERROR", BTA_AG_LOCAL_RES_ERROR, BTA_AG_RES_FMT_NONE},
+    {"RING", BTA_AG_LOCAL_RES_RING, BTA_AG_RES_FMT_NONE},
+    {"+VGS: ", BTA_AG_SPK_RES, BTA_AG_RES_FMT_INT},
+    {"+VGM: ", BTA_AG_MIC_RES, BTA_AG_RES_FMT_INT},
+    {"+CCWA: ", BTA_AG_CALL_WAIT_RES, BTA_AG_RES_FMT_STR},
+    {"+CHLD: ", BTA_AG_IN_CALL_HELD_RES, BTA_AG_RES_FMT_STR},
+    {"+CIND: ", BTA_AG_CIND_RES, BTA_AG_RES_FMT_STR},
+    {"+CLIP: ", BTA_AG_LOCAL_RES_CLIP, BTA_AG_RES_FMT_STR},
+    {"+CIEV: ", BTA_AG_IND_RES, BTA_AG_RES_FMT_STR},
+    {"+BINP: ", BTA_AG_BINP_RES, BTA_AG_RES_FMT_STR},
+    {"+BVRA: ", BTA_AG_BVRA_RES, BTA_AG_RES_FMT_INT},
+    {"+BRSF: ", BTA_AG_LOCAL_RES_BRSF, BTA_AG_RES_FMT_INT},
+    {"+BSIR: ", BTA_AG_INBAND_RING_RES, BTA_AG_RES_FMT_INT},
+    {"+CNUM: ", BTA_AG_CNUM_RES, BTA_AG_RES_FMT_STR},
+    {"+BTRH: ", BTA_AG_BTRH_RES, BTA_AG_RES_FMT_INT},
+    {"+CLCC: ", BTA_AG_CLCC_RES, BTA_AG_RES_FMT_STR},
+    {"+COPS: ", BTA_AG_COPS_RES, BTA_AG_RES_FMT_STR},
+    {"+CME ERROR: ", BTA_AG_LOCAL_RES_CMEE, BTA_AG_RES_FMT_INT},
+    {"+BCS: ", BTA_AG_LOCAL_RES_BCS, BTA_AG_RES_FMT_INT},
+    {"+BIND: ", BTA_AG_BIND_RES, BTA_AG_RES_FMT_STR},
+    {"", BTA_AG_UNAT_RES, BTA_AG_RES_FMT_STR}};
+
+static const tBTA_AG_RESULT* bta_ag_result_by_code(size_t code) {
+  for (size_t i = 0;
+       i != sizeof(bta_ag_result_tbl) / sizeof(bta_ag_result_tbl[0]); ++i) {
+    if (code == bta_ag_result_tbl[i].result_id) return &bta_ag_result_tbl[i];
+  }
+  return 0;
+}
+
+const tBTA_AG_AT_CMD* bta_ag_at_tbl[BTA_AG_NUM_IDX] = {bta_ag_hsp_cmd,
+                                                       bta_ag_hfp_cmd};
+
+typedef struct {
+  size_t result_code;
+  size_t indicator;
+} tBTA_AG_INDICATOR_MAP;
+
+/* callsetup indicator value lookup table */
+const tBTA_AG_INDICATOR_MAP callsetup_indicator_map[] = {
+    {BTA_AG_IN_CALL_RES, BTA_AG_CALLSETUP_INCOMING},
+    {BTA_AG_CALL_WAIT_RES, BTA_AG_CALLSETUP_INCOMING},
+    {BTA_AG_OUT_CALL_ORIG_RES, BTA_AG_CALLSETUP_OUTGOING},
+    {BTA_AG_OUT_CALL_ALERT_RES, BTA_AG_CALLSETUP_ALERTING}};
+
+static size_t bta_ag_indicator_by_result_code(size_t code) {
+  for (size_t i = 0;
+       i !=
+       sizeof(callsetup_indicator_map) / sizeof(callsetup_indicator_map[0]);
+       ++i) {
+    if (code == callsetup_indicator_map[i].result_code)
+      return callsetup_indicator_map[i].indicator;
+  }
+  return BTA_AG_CALLSETUP_NONE;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_send_result
+ *
+ * Description      Send an AT result code.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ag_send_result(tBTA_AG_SCB* p_scb, size_t code,
+                               const char* p_arg, int16_t int_arg) {
+  const tBTA_AG_RESULT* result = bta_ag_result_by_code(code);
+  if (result == 0) {
+    LOG_ERROR(LOG_TAG, "%s Unable to lookup result for code %zu", __func__,
+              code);
+    return;
+  }
+
+  char buf[BTA_AG_AT_MAX_LEN + 16];
+  char* p = buf;
+  memset(buf, 0, sizeof(buf));
+
+  /* init with \r\n */
+  *p++ = '\r';
+  *p++ = '\n';
+
+  /* copy result code string */
+  strlcpy(p, result->result_string, sizeof(buf) - 2);
+
+  if (p_scb->conn_service == BTA_AG_HSP) {
+    /* If HSP then ":"symbol should be changed as "=" for HSP compatibility */
+    switch (code) {
+      case BTA_AG_SPK_RES:
+      case BTA_AG_MIC_RES:
+        if (*(p + COLON_IDX_4_VGSVGM) == ':') {
+          *(p + COLON_IDX_4_VGSVGM) = '=';
+        }
+        break;
+    }
+  }
+
+  p += strlen(result->result_string);
+
+  /* copy argument if any */
+  if (result->arg_type == BTA_AG_RES_FMT_INT) {
+    p += utl_itoa((uint16_t)int_arg, p);
+  } else if (result->arg_type == BTA_AG_RES_FMT_STR) {
+    strcpy(p, p_arg);
+    p += strlen(p_arg);
+  }
+
+  /* finish with \r\n */
+  *p++ = '\r';
+  *p++ = '\n';
+
+  /* send to RFCOMM */
+  uint16_t len = 0;
+  PORT_WriteData(p_scb->conn_handle, buf, (uint16_t)(p - buf), &len);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_send_ok
+ *
+ * Description      Send an OK result code.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ag_send_ok(tBTA_AG_SCB* p_scb) {
+  bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_OK, NULL, 0);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_send_error
+ *
+ * Description      Send an ERROR result code.
+ *                      errcode - used to send verbose errocode
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ag_send_error(tBTA_AG_SCB* p_scb, int16_t errcode) {
+  /* If HFP and extended audio gateway error codes are enabled */
+  if (p_scb->conn_service == BTA_AG_HFP && p_scb->cmee_enabled)
+    bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_CMEE, NULL, errcode);
+  else
+    bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_ERROR, NULL, 0);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_send_ind
+ *
+ * Description      Send an indicator CIEV result code.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ag_send_ind(tBTA_AG_SCB* p_scb, uint16_t id, uint16_t value,
+                            bool on_demand) {
+  char str[12];
+  char* p = str;
+
+  /* If the indicator is masked out, just return */
+  /* Mandatory indicators can not be masked out. */
+  if ((p_scb->bia_masked_out & ((uint32_t)1 << id)) &&
+      ((id != BTA_AG_IND_CALL) && (id != BTA_AG_IND_CALLSETUP) &&
+       (id != BTA_AG_IND_CALLHELD)))
+    return;
+
+  /* Ensure we do not send duplicate indicators if not requested by app */
+  /* If it was requested by app, transmit CIEV even if it is duplicate. */
+  if (id == BTA_AG_IND_CALL) {
+    if ((value == p_scb->call_ind) && (on_demand == false)) return;
+
+    p_scb->call_ind = (uint8_t)value;
+  }
+
+  if ((id == BTA_AG_IND_CALLSETUP) && (on_demand == false)) {
+    if (value == p_scb->callsetup_ind) return;
+
+    p_scb->callsetup_ind = (uint8_t)value;
+  }
+
+  if ((id == BTA_AG_IND_SERVICE) && (on_demand == false)) {
+    if (value == p_scb->service_ind) return;
+
+    p_scb->service_ind = (uint8_t)value;
+  }
+  if ((id == BTA_AG_IND_SIGNAL) && (on_demand == false)) {
+    if (value == p_scb->signal_ind) return;
+
+    p_scb->signal_ind = (uint8_t)value;
+  }
+  if ((id == BTA_AG_IND_ROAM) && (on_demand == false)) {
+    if (value == p_scb->roam_ind) return;
+
+    p_scb->roam_ind = (uint8_t)value;
+  }
+  if ((id == BTA_AG_IND_BATTCHG) && (on_demand == false)) {
+    if (value == p_scb->battchg_ind) return;
+
+    p_scb->battchg_ind = (uint8_t)value;
+  }
+
+  if ((id == BTA_AG_IND_CALLHELD) && (on_demand == false)) {
+    /* call swap could result in sending callheld=1 multiple times */
+    if ((value != 1) && (value == p_scb->callheld_ind)) return;
+
+    p_scb->callheld_ind = (uint8_t)value;
+  }
+
+  if (p_scb->cmer_enabled) {
+    p += utl_itoa(id, p);
+    *p++ = ',';
+    utl_itoa(value, p);
+    bta_ag_send_result(p_scb, BTA_AG_IND_RES, str, 0);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_parse_cmer
+ *
+ * Description      Parse AT+CMER parameter string.
+ *
+ *
+ * Returns          true if parsed ok, false otherwise.
+ *
+ ******************************************************************************/
+static bool bta_ag_parse_cmer(char* p_s, bool* p_enabled) {
+  int16_t n[4] = {-1, -1, -1, -1};
+  int i;
+  char* p;
+
+  for (i = 0; i < 4; i++) {
+    /* skip to comma delimiter */
+    for (p = p_s; *p != ',' && *p != 0; p++)
+      ;
+
+    /* get integer value */
+    *p = 0;
+    n[i] = utl_str2int(p_s);
+    p_s = p + 1;
+    if (p_s == 0) {
+      break;
+    }
+  }
+
+  /* process values */
+  if (n[0] < 0 || n[3] < 0) {
+    return false;
+  }
+
+  if ((n[0] == 3) && ((n[3] == 1) || (n[3] == 0))) {
+    *p_enabled = (bool)n[3];
+  }
+
+  return true;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_parse_chld
+ *
+ * Description      Parse AT+CHLD parameter string.
+ *
+ *
+ * Returns          Returns idx (1-7), 0 if ECC not enabled or
+ BTA_AG_INVALID_CHLD
+                    if idx doesn't exist/1st character of argument is not a
+ digit
+ *
+ ******************************************************************************/
+static uint8_t bta_ag_parse_chld(UNUSED_ATTR tBTA_AG_SCB* p_scb, char* p_s) {
+  uint8_t retval = 0;
+  int16_t idx = -1;
+
+  if (!isdigit(p_s[0])) {
+    return BTA_AG_INVALID_CHLD;
+  }
+
+  if (p_s[1] != 0) {
+    /* p_idxstr++;  point to beginning of call number */
+    idx = utl_str2int(&p_s[1]);
+    if (idx != -1 && idx < 255) {
+      retval = (uint8_t)idx;
+    } else {
+      retval = BTA_AG_INVALID_CHLD;
+    }
+  }
+
+  return (retval);
+}
+
+#if (BTM_WBS_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_ag_parse_bac
+ *
+ * Description      Parse AT+BAC parameter string.
+ *
+ * Returns          Returns bitmap of supported codecs.
+ *
+ ******************************************************************************/
+static tBTA_AG_PEER_CODEC bta_ag_parse_bac(tBTA_AG_SCB* p_scb, char* p_s) {
+  tBTA_AG_PEER_CODEC retval = BTA_AG_CODEC_NONE;
+  uint16_t uuid_codec;
+  bool cont = false; /* Continue processing */
+  char* p;
+
+  while (p_s) {
+    /* skip to comma delimiter */
+    for (p = p_s; *p != ',' && *p != 0; p++)
+      ;
+
+    /* get integre value */
+    if (*p != 0) {
+      *p = 0;
+      cont = true;
+    } else
+      cont = false;
+
+    uuid_codec = utl_str2int(p_s);
+    switch (uuid_codec) {
+      case UUID_CODEC_CVSD:
+        retval |= BTA_AG_CODEC_CVSD;
+        break;
+      case UUID_CODEC_MSBC:
+        retval |= BTA_AG_CODEC_MSBC;
+        break;
+      default:
+        APPL_TRACE_ERROR("Unknown Codec UUID(%d) received", uuid_codec);
+        break;
+    }
+
+    if (cont)
+      p_s = p + 1;
+    else
+      break;
+  }
+
+  return (retval);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_process_unat_res
+ *
+ * Description      Process the unat response data and remove extra carriage
+ *                  return and line feed
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+
+static void bta_ag_process_unat_res(char* unat_result) {
+  uint8_t str_leng;
+  uint8_t i = 0;
+  uint8_t j = 0;
+  uint8_t pairs_of_nl_cr;
+  char trim_data[BTA_AG_AT_MAX_LEN];
+
+  str_leng = strlen(unat_result);
+
+  /* If no extra CR and LF, just return */
+  if (str_leng < 4) return;
+
+  /* Remove the carriage return and left feed */
+  while (unat_result[0] == '\r' && unat_result[1] == '\n' &&
+         unat_result[str_leng - 2] == '\r' &&
+         unat_result[str_leng - 1] == '\n') {
+    pairs_of_nl_cr = 1;
+    for (i = 0; i < (str_leng - 4 * pairs_of_nl_cr); i++) {
+      trim_data[j++] = unat_result[i + pairs_of_nl_cr * 2];
+    }
+    /* Add EOF */
+    trim_data[j] = '\0';
+    str_leng = str_leng - 4;
+    strlcpy(unat_result, trim_data, str_leng + 1);
+    i = 0;
+    j = 0;
+
+    if (str_leng < 4) return;
+  }
+  return;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_inband_enabled
+ *
+ * Description      Determine whether in-band ring can be used.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+bool bta_ag_inband_enabled(tBTA_AG_SCB* p_scb) {
+  /* if feature is enabled and no other scbs connected */
+  if (p_scb->inband_enabled && !bta_ag_other_scb_open(p_scb)) {
+    return true;
+  } else {
+    return false;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_send_call_inds
+ *
+ * Description      Send call and callsetup indicators.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_send_call_inds(tBTA_AG_SCB* p_scb, tBTA_AG_RES result) {
+  uint8_t call = p_scb->call_ind;
+
+  /* set new call and callsetup values based on BTA_AgResult */
+  size_t callsetup = bta_ag_indicator_by_result_code(result);
+
+  if (result == BTA_AG_END_CALL_RES) {
+    call = BTA_AG_CALL_INACTIVE;
+  } else if (result == BTA_AG_IN_CALL_CONN_RES ||
+             result == BTA_AG_OUT_CALL_CONN_RES ||
+             result == BTA_AG_IN_CALL_HELD_RES) {
+    call = BTA_AG_CALL_ACTIVE;
+  } else {
+    call = p_scb->call_ind;
+  }
+
+  /* Send indicator function tracks if the values have actually changed */
+  bta_ag_send_ind(p_scb, BTA_AG_IND_CALL, call, false);
+  bta_ag_send_ind(p_scb, BTA_AG_IND_CALLSETUP, callsetup, false);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_at_hsp_cback
+ *
+ * Description      AT command processing callback for HSP.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_at_hsp_cback(tBTA_AG_SCB* p_scb, uint16_t command_id,
+                         uint8_t arg_type, char* p_arg, int16_t int_arg) {
+  APPL_TRACE_DEBUG("AT cmd:%d arg_type:%d arg:%d arg:%s", command_id, arg_type,
+                   int_arg, p_arg);
+
+  bta_ag_send_ok(p_scb);
+
+  tBTA_AG_VAL val;
+  val.hdr.handle = bta_ag_scb_to_idx(p_scb);
+  val.hdr.app_id = p_scb->app_id;
+  val.num = (uint16_t)int_arg;
+  strlcpy(val.str, p_arg, sizeof(val.str));
+
+  /* call callback with event */
+  (*bta_ag_cb.p_cback)(command_id, (tBTA_AG*)&val);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_find_empty_hf_ind)
+ *
+ * Description      This function returns the index of an empty HF indicator
+ *                  structure.
+ *
+ * Returns          int : index of the empty HF indicator structure or
+ *                            -1 if no empty indicator
+ *                            is available.
+ *
+ ******************************************************************************/
+static int bta_ag_find_empty_hf_ind(tBTA_AG_SCB* p_scb) {
+  for (int index = 0; index < BTA_AG_MAX_NUM_PEER_HF_IND; index++) {
+    if (p_scb->peer_hf_indicators[index].ind_id == 0) return index;
+  }
+
+  return -1;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_find_hf_ind_by_id
+ *
+ * Description      This function returns the index of the HF indicator
+ *                  structure by the indicator id
+ *
+ * Returns          int : index of the HF indicator structure
+ *                            -1 if the indicator
+ *                            was not found.
+ *
+ ******************************************************************************/
+static int bta_ag_find_hf_ind_by_id(tBTA_AG_HF_IND* p_hf_ind, int size,
+                                    uint32_t ind_id) {
+  for (int index = 0; index < size; index++) {
+    if (p_hf_ind[index].ind_id == ind_id) return index;
+  }
+
+  return -1;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_parse_bind_set
+ *
+ * Description      Parse AT+BIND set command and save the indicators
+ *
+ * Returns          true if successful
+ *
+ ******************************************************************************/
+static bool bta_ag_parse_bind_set(tBTA_AG_SCB* p_scb, tBTA_AG_VAL val) {
+  char* p_token = strtok(val.str, ",");
+  if (p_token == NULL) return false;
+
+  while (p_token != NULL) {
+    uint16_t rcv_ind_id = atoi(p_token);
+    int index = bta_ag_find_empty_hf_ind(p_scb);
+    if (index == -1) {
+      APPL_TRACE_WARNING("%s Can't save more indicators", __func__);
+      return false;
+    }
+
+    p_scb->peer_hf_indicators[index].ind_id = rcv_ind_id;
+    APPL_TRACE_DEBUG("%s peer_hf_ind[%d] = %d", __func__, index, rcv_ind_id);
+
+    p_token = strtok(NULL, ",");
+  }
+
+  return true;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_bind_response
+ *
+ * Description      Send response for the AT+BIND command (HFP 1.7) received
+ *                  from the headset based on the argument types.
+ *
+ * Returns          Void
+ *
+ ******************************************************************************/
+static void bta_ag_bind_response(tBTA_AG_SCB* p_scb, uint8_t arg_type) {
+  char buffer[BTA_AG_AT_MAX_LEN];
+  memset(buffer, 0, BTA_AG_AT_MAX_LEN);
+
+  if (arg_type == BTA_AG_AT_TEST) {
+    int index = 0;
+    buffer[index++] = '(';
+
+    for (uint32_t i = 0; i < bta_ag_local_hf_ind_cfg[0].ind_id; i++) {
+      if (bta_ag_local_hf_ind_cfg[i + 1].is_supported) {
+        /* Add ',' from second indicator */
+        if (index > 1) buffer[index++] = ',';
+        snprintf(&buffer[index++], 1, "%d",
+                 bta_ag_local_hf_ind_cfg[i + 1].ind_id);
+      }
+    }
+
+    buffer[index++] = ')';
+
+    bta_ag_send_result(p_scb, BTA_AG_BIND_RES, buffer, 0);
+    bta_ag_send_ok(p_scb);
+  } else if (arg_type == BTA_AG_AT_READ) {
+    char* p = buffer;
+
+    /* bta_ag_local_hf_ind_cfg[0].ind_id is used as BTA_AG_NUM_LOCAL_HF_IND */
+    for (uint32_t i = 0; i < bta_ag_local_hf_ind_cfg[0].ind_id; i++) {
+      if (i == BTA_AG_MAX_NUM_LOCAL_HF_IND) {
+        APPL_TRACE_WARNING("%s No space for more HF indicators", __func__);
+        break;
+      }
+
+      p_scb->local_hf_indicators[i].ind_id =
+          bta_ag_local_hf_ind_cfg[i + 1].ind_id;
+      p_scb->local_hf_indicators[i].is_supported =
+          bta_ag_local_hf_ind_cfg[i + 1].is_supported;
+      p_scb->local_hf_indicators[i].is_enable =
+          bta_ag_local_hf_ind_cfg[i + 1].is_enable;
+
+      int peer_index = bta_ag_find_hf_ind_by_id(
+          p_scb->peer_hf_indicators, BTA_AG_MAX_NUM_PEER_HF_IND,
+          p_scb->local_hf_indicators[i].ind_id);
+
+      /* Check whether local and peer sides support this indicator */
+      if (p_scb->local_hf_indicators[i].is_supported == true &&
+          peer_index != -1) {
+        /* In the format of ind, state */
+        p += utl_itoa((uint16_t)p_scb->local_hf_indicators[i].ind_id, p);
+        *p++ = ',';
+        p += utl_itoa((uint16_t)p_scb->local_hf_indicators[i].is_enable, p);
+
+        bta_ag_send_result(p_scb, BTA_AG_BIND_RES, buffer, 0);
+
+        memset(buffer, 0, sizeof(buffer));
+        p = buffer;
+      } else {
+        /* If indicator is not supported, also set it to disable */
+        p_scb->local_hf_indicators[i].is_enable = false;
+      }
+    }
+
+    bta_ag_send_ok(p_scb);
+
+    /* If the service level connection wan't already open, now it's open */
+    if (!p_scb->svc_conn) bta_ag_svc_conn_open(p_scb, NULL);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_parse_biev_response
+ *
+ * Description      Send response for AT+BIEV command (HFP 1.7) received from
+ *                  the headset based on the argument types.
+ *
+ * Returns          true if the response was parsed successfully
+ *
+ ******************************************************************************/
+static bool bta_ag_parse_biev_response(tBTA_AG_SCB* p_scb, tBTA_AG_VAL* val) {
+  char* p_token = strtok(val->str, ",");
+  uint16_t rcv_ind_id = atoi(p_token);
+
+  p_token = strtok(NULL, ",");
+  uint16_t rcv_ind_val = atoi(p_token);
+
+  APPL_TRACE_DEBUG("%s BIEV indicator id %d, value %d", __func__, rcv_ind_id,
+                   rcv_ind_val);
+
+  /* Check whether indicator ID is valid or not */
+  if (rcv_ind_id > BTA_AG_NUM_LOCAL_HF_IND) {
+    APPL_TRACE_WARNING("%s received invalid indicator id %d", __func__,
+                       rcv_ind_id);
+    return false;
+  }
+
+  /* Check this indicator is support or not and enabled or not */
+  int local_index = bta_ag_find_hf_ind_by_id(
+      p_scb->local_hf_indicators, BTA_AG_MAX_NUM_LOCAL_HF_IND, rcv_ind_id);
+  if (local_index == -1 ||
+      p_scb->local_hf_indicators[local_index].is_supported != true ||
+      p_scb->local_hf_indicators[local_index].is_enable != true) {
+    APPL_TRACE_WARNING("%s indicator id %d not supported or disabled", __func__,
+                       rcv_ind_id);
+    return false;
+  }
+
+  /* For each indicator ID, check whether the indicator value is in range */
+  if (rcv_ind_val < bta_ag_local_hf_ind_cfg[rcv_ind_id].ind_min_val ||
+      rcv_ind_val > bta_ag_local_hf_ind_cfg[rcv_ind_id].ind_max_val) {
+    APPL_TRACE_WARNING("%s invalid ind_val %d", __func__, rcv_ind_val);
+    return false;
+  }
+
+  val->lidx = rcv_ind_id;
+  val->num = rcv_ind_val;
+
+  return true;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_at_hfp_cback
+ *
+ * Description      AT command processing callback for HFP.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_at_hfp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd, uint8_t arg_type,
+                         char* p_arg, int16_t int_arg) {
+  tBTA_AG_VAL val;
+  tBTA_AG_SCB* ag_scb;
+  uint32_t i, ind_id;
+  uint32_t bia_masked_out;
+#if (BTM_WBS_INCLUDED == TRUE)
+  tBTA_AG_PEER_CODEC codec_type, codec_sent;
+#endif
+  if (p_arg == NULL) {
+    APPL_TRACE_ERROR("%s: p_arg is null, send error and return", __func__);
+    bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+    return;
+  }
+
+  APPL_TRACE_DEBUG("HFP AT cmd:%d arg_type:%d arg:%d arg:%s", cmd, arg_type,
+                   int_arg, p_arg);
+
+  memset(&val, 0, sizeof(tBTA_AG_VAL));
+  val.hdr.handle = bta_ag_scb_to_idx(p_scb);
+  val.hdr.app_id = p_scb->app_id;
+  val.hdr.status = BTA_AG_SUCCESS;
+  val.num = int_arg;
+  bdcpy(val.bd_addr, p_scb->peer_addr);
+  strlcpy(val.str, p_arg, sizeof(val.str));
+
+  /**
+   * Unless this this is a local event, by default we'll forward
+   * the event code to the application.
+   * If |event| is 0 at the end of this function, the application
+   * callback is NOT invoked.
+   */
+  tBTA_AG_EVT event = 0;
+  if (cmd < BTA_AG_LOCAL_EVT_FIRST) event = cmd;
+
+  switch (cmd) {
+    case BTA_AG_AT_A_EVT:
+    case BTA_AG_SPK_EVT:
+    case BTA_AG_MIC_EVT:
+    case BTA_AG_AT_CHUP_EVT:
+    case BTA_AG_AT_CBC_EVT:
+      /* send OK */
+      bta_ag_send_ok(p_scb);
+      break;
+
+    case BTA_AG_AT_BLDN_EVT:
+      /* Do not send OK, App will send error or OK depending on
+      ** last dial number enabled or not */
+      break;
+
+    case BTA_AG_AT_D_EVT:
+      /* Do not send OK for Dial cmds
+      ** Let application decide whether to send OK or ERROR*/
+
+      /* if mem dial cmd, make sure string contains only digits */
+      if (p_arg[0] == '>') {
+        if (!utl_isintstr(p_arg + 1)) {
+          event = 0;
+          bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_DSTR);
+        }
+      } else if (p_arg[0] == 'V') /* ATDV : Dial VoIP Call */
+      {
+        /* We do not check string. Code will be added later if needed. */
+        if (!((p_scb->peer_features & BTA_AG_PEER_FEAT_VOIP) &&
+              (p_scb->features & BTA_AG_FEAT_VOIP))) {
+          event = 0;
+          bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+        }
+      }
+      /* If dial cmd, make sure string contains only dial digits
+      ** Dial digits are 0-9, A-C, *, #, + */
+      else {
+        if (!utl_isdialstr(p_arg)) {
+          event = 0;
+          bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_DSTR);
+        }
+      }
+      break;
+
+    case BTA_AG_LOCAL_EVT_CCWA:
+      /* store setting */
+      p_scb->ccwa_enabled = (bool)int_arg;
+
+      /* send OK */
+      bta_ag_send_ok(p_scb);
+      break;
+
+    case BTA_AG_AT_CHLD_EVT:
+      if (arg_type == BTA_AG_AT_TEST) {
+        /* don't call callback */
+        event = 0;
+
+        /* send CHLD string */
+        /* Form string based on supported 1.5 feature */
+        if ((p_scb->peer_version >= HFP_VERSION_1_5) &&
+            (p_scb->features & BTA_AG_FEAT_ECC) &&
+            (p_scb->peer_features & BTA_AG_PEER_FEAT_ECC))
+          bta_ag_send_result(p_scb, BTA_AG_IN_CALL_HELD_RES,
+                             p_bta_ag_cfg->chld_val_ecc, 0);
+        else
+          bta_ag_send_result(p_scb, BTA_AG_IN_CALL_HELD_RES,
+                             p_bta_ag_cfg->chld_val, 0);
+
+        /* send OK */
+        bta_ag_send_ok(p_scb);
+
+        /* if service level conn. not already open, now it's open */
+        bta_ag_svc_conn_open(p_scb, NULL);
+      } else {
+        val.idx = bta_ag_parse_chld(p_scb, val.str);
+
+        if (val.idx == BTA_AG_INVALID_CHLD) {
+          event = 0;
+          bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+          break;
+        }
+        if (val.idx &&
+            !((p_scb->features & BTA_AG_FEAT_ECC) &&
+              (p_scb->peer_features & BTA_AG_PEER_FEAT_ECC))) {
+          /* we do not support ECC, but HF is sending us a CHLD with call
+           * index*/
+          event = 0;
+          bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+
+        } else {
+          /* If it is swap between calls, set call held indicator to 3(out of
+          *valid 0-2)
+          ** Application will set it back to 1
+          ** callheld indicator will be sent across to the peer. */
+          if (val.str[0] == '2') {
+            for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB;
+                 i++, ag_scb++) {
+              if (ag_scb->in_use) {
+                if ((ag_scb->call_ind == BTA_AG_CALL_ACTIVE) &&
+                    (ag_scb->callsetup_ind == BTA_AG_CALLSETUP_NONE))
+                  ag_scb->callheld_ind = BTA_AG_CALLHELD_NOACTIVE + 1;
+              }
+            }
+          }
+        }
+
+        /* Do not send OK. Let app decide after parsing the val str */
+        /* bta_ag_send_ok(p_scb); */
+      }
+      break;
+
+    case BTA_AG_AT_BIND_EVT:
+      APPL_TRACE_DEBUG("%s BTA_AG_AT_BIND_EVT arg_type: %d", __func__,
+                       arg_type);
+      if (arg_type == BTA_AG_AT_SET) {
+        if (bta_ag_parse_bind_set(p_scb, val)) {
+          bta_ag_send_ok(p_scb);
+        } else {
+          event = 0; /* don't call callback */
+          bta_ag_send_error(p_scb, BTA_AG_ERR_INVALID_INDEX);
+        }
+      } else {
+        bta_ag_bind_response(p_scb, arg_type);
+
+        /* Need not pass this command beyond BTIF.*/
+        /* Stack handles it internally */
+        event = 0; /* don't call callback */
+      }
+      break;
+
+    case BTA_AG_AT_BIEV_EVT:
+      if (bta_ag_parse_biev_response(p_scb, &val)) {
+        bta_ag_send_ok(p_scb);
+      } else {
+        bta_ag_send_error(p_scb, BTA_AG_ERR_INVALID_INDEX);
+        /* don't call callback receiving invalid indicator */
+        event = 0;
+      }
+      break;
+
+    case BTA_AG_AT_CIND_EVT:
+      if (arg_type == BTA_AG_AT_TEST) {
+        /* don't call callback */
+        event = 0;
+
+        /* send CIND string, send OK */
+        bta_ag_send_result(p_scb, BTA_AG_CIND_RES, p_bta_ag_cfg->cind_info, 0);
+        bta_ag_send_ok(p_scb);
+      }
+      break;
+
+    case BTA_AG_LOCAL_EVT_CLIP:
+      /* store setting, send OK */
+      p_scb->clip_enabled = (bool)int_arg;
+      bta_ag_send_ok(p_scb);
+      break;
+
+    case BTA_AG_LOCAL_EVT_CMER:
+      /* if parsed ok store setting, send OK */
+      if (bta_ag_parse_cmer(p_arg, &p_scb->cmer_enabled)) {
+        bta_ag_send_ok(p_scb);
+
+        /* if service level conn. not already open and our features and
+        ** peer features do not have 3-way, service level conn. now open
+        */
+        if (!p_scb->svc_conn &&
+            !((p_scb->features & BTA_AG_FEAT_3WAY) &&
+              (p_scb->peer_features & BTA_AG_PEER_FEAT_3WAY))) {
+          bta_ag_svc_conn_open(p_scb, NULL);
+        }
+      } else {
+        bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+      }
+      break;
+
+    case BTA_AG_AT_VTS_EVT:
+      /* check argument */
+      if (strlen(p_arg) == 1) {
+        bta_ag_send_ok(p_scb);
+      } else {
+        event = 0;
+        bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+      }
+      break;
+
+    case BTA_AG_AT_BINP_EVT:
+      /* if feature not set don't call callback, send ERROR */
+      if (!(p_scb->features & BTA_AG_FEAT_VTAG)) {
+        event = 0;
+        bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+      }
+      break;
+
+    case BTA_AG_AT_BVRA_EVT:
+      /* if feature not supported don't call callback, send ERROR. App will send
+       * OK */
+      if (!(p_scb->features & BTA_AG_FEAT_VREC)) {
+        event = 0;
+        bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+      }
+      break;
+
+    case BTA_AG_LOCAL_EVT_BRSF: {
+      /* store peer features */
+      p_scb->peer_features = (uint16_t)int_arg;
+
+      tBTA_AG_FEAT features = p_scb->features;
+      if (p_scb->peer_version < HFP_VERSION_1_7) {
+        features &= HFP_1_6_FEAT_MASK;
+      }
+
+      APPL_TRACE_DEBUG("%s BRSF HF: 0x%x, phone: 0x%x", __func__,
+                       p_scb->peer_features, features);
+
+      /* send BRSF, send OK */
+      bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_BRSF, NULL, (int16_t)features);
+      bta_ag_send_ok(p_scb);
+      break;
+    }
+
+    case BTA_AG_AT_NREC_EVT:
+      /* if feature send OK, else don't call callback, send ERROR */
+      if (p_scb->features & BTA_AG_FEAT_ECNR) {
+        bta_ag_send_ok(p_scb);
+      } else {
+        event = 0;
+        bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+      }
+      break;
+
+    case BTA_AG_AT_BTRH_EVT:
+      /* if feature send BTRH, send OK:, else don't call callback, send ERROR */
+      if (p_scb->features & BTA_AG_FEAT_BTRH) {
+        /* If set command; send response and notify app */
+        if (arg_type == BTA_AG_AT_SET) {
+          for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB;
+               i++, ag_scb++) {
+            if (ag_scb->in_use) {
+              bta_ag_send_result(ag_scb, BTA_AG_BTRH_RES, NULL, int_arg);
+            }
+          }
+          bta_ag_send_ok(p_scb);
+        } else /* Read Command */
+        {
+          val.num = BTA_AG_BTRH_READ;
+        }
+      } else {
+        event = 0;
+        bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+      }
+      break;
+
+    case BTA_AG_AT_COPS_EVT:
+      if (arg_type == BTA_AG_AT_SET) {
+        /* don't call callback */
+        event = 0;
+
+        /* send OK */
+        bta_ag_send_ok(p_scb);
+      }
+      break;
+
+    case BTA_AG_LOCAL_EVT_CMEE:
+      if (p_scb->features & BTA_AG_FEAT_EXTERR) {
+        /* store setting */
+        p_scb->cmee_enabled = (bool)int_arg;
+
+        /* send OK */
+        bta_ag_send_ok(p_scb);
+      } else {
+        bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+      }
+      /* don't call callback */
+      event = 0;
+      break;
+
+    case BTA_AG_LOCAL_EVT_BIA:
+      /* don't call callback */
+      event = 0;
+
+      bia_masked_out = p_scb->bia_masked_out;
+
+      /* Parse the indicator mask */
+      for (i = 0, ind_id = 1; (val.str[i] != 0) && (ind_id <= 20);
+           i++, ind_id++) {
+        if (val.str[i] == ',') continue;
+
+        if (val.str[i] == '0')
+          bia_masked_out |= ((uint32_t)1 << ind_id);
+        else if (val.str[i] == '1')
+          bia_masked_out &= ~((uint32_t)1 << ind_id);
+        else
+          break;
+
+        i++;
+        if ((val.str[i] == 0) || (val.str[i] != ',')) break;
+      }
+      if (val.str[i] == 0) {
+        p_scb->bia_masked_out = bia_masked_out;
+        bta_ag_send_ok(p_scb);
+      } else
+        bta_ag_send_error(p_scb, BTA_AG_ERR_INVALID_INDEX);
+      break;
+
+    case BTA_AG_AT_CNUM_EVT:
+      break;
+
+    case BTA_AG_AT_CLCC_EVT:
+      if (!(p_scb->features & BTA_AG_FEAT_ECS)) {
+        event = 0;
+        bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+      }
+      break;
+
+#if (BTM_WBS_INCLUDED == TRUE)
+    case BTA_AG_AT_BAC_EVT:
+      bta_ag_send_ok(p_scb);
+
+      /* store available codecs from the peer */
+      if ((p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC) &&
+          (p_scb->features & BTA_AG_FEAT_CODEC)) {
+        p_scb->peer_codecs = bta_ag_parse_bac(p_scb, p_arg);
+        p_scb->codec_updated = true;
+
+        if (p_scb->peer_codecs & BTA_AG_CODEC_MSBC) {
+          p_scb->sco_codec = UUID_CODEC_MSBC;
+          APPL_TRACE_DEBUG("Received AT+BAC, updating sco codec to MSBC");
+        } else {
+          p_scb->sco_codec = UUID_CODEC_CVSD;
+          APPL_TRACE_DEBUG("Received AT+BAC, updating sco codec to CVSD");
+        }
+        /* The above logic sets the stack preferred codec based on local and
+        peer codec
+        capabilities. This can be overridden by the application depending on its
+        preference
+        using the bta_ag_setcodec API. We send the peer_codecs to the
+        application. */
+        val.num = p_scb->peer_codecs;
+        /* Received BAC while in codec negotiation. */
+        if ((bta_ag_cb.sco.state == BTA_AG_SCO_CODEC_ST) &&
+            (bta_ag_cb.sco.p_curr_scb == p_scb)) {
+          bta_ag_codec_negotiate(p_scb);
+        }
+      } else {
+        p_scb->peer_codecs = BTA_AG_CODEC_CVSD;
+        APPL_TRACE_ERROR(
+            "Unexpected CMD:AT+BAC, Codec Negotiation is not supported");
+      }
+      break;
+
+    case BTA_AG_AT_BCS_EVT:
+      bta_ag_send_ok(p_scb);
+      alarm_cancel(p_scb->codec_negotiation_timer);
+
+      switch (int_arg) {
+        case UUID_CODEC_CVSD:
+          codec_type = BTA_AG_CODEC_CVSD;
+          break;
+        case UUID_CODEC_MSBC:
+          codec_type = BTA_AG_CODEC_MSBC;
+          break;
+        default:
+          APPL_TRACE_ERROR("Unknown codec_uuid %d", int_arg);
+          codec_type = 0xFFFF;
+          break;
+      }
+
+      if (p_scb->codec_fallback)
+        codec_sent = BTA_AG_CODEC_CVSD;
+      else
+        codec_sent = p_scb->sco_codec;
+
+      if (codec_type == codec_sent)
+        bta_ag_sco_codec_nego(p_scb, true);
+      else
+        bta_ag_sco_codec_nego(p_scb, false);
+
+      /* send final codec info to callback */
+      val.num = codec_sent;
+      break;
+
+    case BTA_AG_LOCAL_EVT_BCC:
+      bta_ag_send_ok(p_scb);
+      bta_ag_sco_open(p_scb, NULL);
+      break;
+#endif
+
+    default:
+      bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+      break;
+  }
+
+  /* call callback */
+  if (event != 0) {
+    (*bta_ag_cb.p_cback)(event, (tBTA_AG*)&val);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_at_err_cback
+ *
+ * Description      AT command parser error callback.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_at_err_cback(tBTA_AG_SCB* p_scb, bool unknown, char* p_arg) {
+  tBTA_AG_VAL val;
+
+  if (unknown && (!strlen(p_arg))) {
+    APPL_TRACE_DEBUG("Empty AT cmd string received");
+    bta_ag_send_ok(p_scb);
+    return;
+  }
+
+  /* if unknown AT command and configured to pass these to app */
+  if (unknown && (p_scb->features & BTA_AG_FEAT_UNAT)) {
+    val.hdr.handle = bta_ag_scb_to_idx(p_scb);
+    val.hdr.app_id = p_scb->app_id;
+    val.hdr.status = BTA_AG_SUCCESS;
+    val.num = 0;
+    strlcpy(val.str, p_arg, sizeof(val.str));
+    (*bta_ag_cb.p_cback)(BTA_AG_AT_UNAT_EVT, (tBTA_AG*)&val);
+  } else {
+    bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_hsp_result
+ *
+ * Description      Handle API result for HSP connections.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_hsp_result(tBTA_AG_SCB* p_scb, tBTA_AG_API_RESULT* p_result) {
+  APPL_TRACE_DEBUG("bta_ag_hsp_result : res = %d", p_result->result);
+
+  switch (p_result->result) {
+    case BTA_AG_SPK_RES:
+    case BTA_AG_MIC_RES:
+      bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.num);
+      break;
+
+    case BTA_AG_IN_CALL_RES:
+      /* tell sys to stop av if any */
+      bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+      /* if sco already opened or no inband ring send ring now */
+      if (bta_ag_sco_is_open(p_scb) || !bta_ag_inband_enabled(p_scb) ||
+          (p_scb->features & BTA_AG_FEAT_NOSCO)) {
+        bta_ag_send_ring(p_scb, (tBTA_AG_DATA*)p_result);
+      }
+      /* else open sco, send ring after sco opened */
+      else {
+        /* HSPv1.2: AG shall not send RING if using in-band ring tone. */
+        if (p_scb->hsp_version >= HSP_VERSION_1_2)
+          p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+        else
+          p_scb->post_sco = BTA_AG_POST_SCO_RING;
+
+        bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
+      }
+      break;
+
+    case BTA_AG_IN_CALL_CONN_RES:
+    case BTA_AG_OUT_CALL_ORIG_RES:
+      /* if incoming call connected stop ring timer */
+      if (p_result->result == BTA_AG_IN_CALL_CONN_RES) {
+        alarm_cancel(p_scb->ring_timer);
+      }
+
+      if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+        /* if audio connected to this scb open sco */
+        if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb)) {
+          bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
+        }
+        /* else if no audio at call close sco */
+        else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE) {
+          bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result);
+        }
+      }
+      break;
+
+    case BTA_AG_END_CALL_RES:
+      alarm_cancel(p_scb->ring_timer);
+
+      /* close sco */
+      if ((bta_ag_sco_is_open(p_scb) || bta_ag_sco_is_opening(p_scb)) &&
+          !(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+        bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result);
+      } else {
+        /* if av got suspended by this call, let it resume. */
+        bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+      }
+      break;
+
+    case BTA_AG_INBAND_RING_RES:
+      p_scb->inband_enabled = p_result->data.state;
+      APPL_TRACE_DEBUG("inband_enabled set to %d", p_scb->inband_enabled);
+      break;
+
+    case BTA_AG_UNAT_RES:
+      if (p_result->data.ok_flag != BTA_AG_OK_ERROR) {
+        if (p_result->data.str[0] != 0) {
+          bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0);
+        }
+
+        if (p_result->data.ok_flag == BTA_AG_OK_DONE) bta_ag_send_ok(p_scb);
+      } else {
+        bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+      }
+      break;
+
+    default:
+      /* ignore all others */
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_hfp_result
+ *
+ * Description      Handle API result for HFP connections.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_hfp_result(tBTA_AG_SCB* p_scb, tBTA_AG_API_RESULT* p_result) {
+  APPL_TRACE_DEBUG("bta_ag_hfp_result : res = %d", p_result->result);
+
+  switch (p_result->result) {
+    case BTA_AG_SPK_RES:
+    case BTA_AG_MIC_RES:
+      bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.num);
+      break;
+
+    case BTA_AG_IN_CALL_RES:
+      /* tell sys to stop av if any */
+      bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+      /* store caller id string.
+       * append type info at the end.
+       * make sure a valid type info is passed.
+       * otherwise add 129 as default type */
+      if ((p_result->data.num < BTA_AG_CLIP_TYPE_MIN) ||
+          (p_result->data.num > BTA_AG_CLIP_TYPE_MAX)) {
+        if (p_result->data.num != BTA_AG_CLIP_TYPE_VOIP)
+          p_result->data.num = BTA_AG_CLIP_TYPE_DEFAULT;
+      }
+
+      APPL_TRACE_DEBUG("CLIP type :%d", p_result->data.num);
+      p_scb->clip[0] = 0;
+      if (p_result->data.str[0] != 0)
+        snprintf(p_scb->clip, sizeof(p_scb->clip), "%s,%d", p_result->data.str,
+                 p_result->data.num);
+
+      /* send callsetup indicator */
+      if (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END) {
+        /* Need to sent 2 callsetup IND's(Call End and Incoming call) after SCO
+         * close. */
+        p_scb->post_sco = BTA_AG_POST_SCO_CALL_END_INCALL;
+      } else {
+        bta_ag_send_call_inds(p_scb, p_result->result);
+
+        /* if sco already opened or no inband ring send ring now */
+        if (bta_ag_sco_is_open(p_scb) || !bta_ag_inband_enabled(p_scb) ||
+            (p_scb->features & BTA_AG_FEAT_NOSCO)) {
+          bta_ag_send_ring(p_scb, (tBTA_AG_DATA*)p_result);
+        }
+        /* else open sco, send ring after sco opened */
+        else {
+          p_scb->post_sco = BTA_AG_POST_SCO_RING;
+          bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
+        }
+      }
+      break;
+
+    case BTA_AG_IN_CALL_CONN_RES:
+      alarm_cancel(p_scb->ring_timer);
+
+      /* if sco not opened and we need to open it, send indicators first
+      ** then  open sco.
+      */
+      bta_ag_send_call_inds(p_scb, p_result->result);
+
+      if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+        if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb)) {
+          bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
+        } else if ((p_result->data.audio_handle == BTA_AG_HANDLE_NONE) &&
+                   bta_ag_sco_is_open(p_scb)) {
+          bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result);
+        }
+      }
+      break;
+
+    case BTA_AG_IN_CALL_HELD_RES:
+      alarm_cancel(p_scb->ring_timer);
+
+      bta_ag_send_call_inds(p_scb, p_result->result);
+
+      break;
+
+    case BTA_AG_OUT_CALL_ORIG_RES:
+      bta_ag_send_call_inds(p_scb, p_result->result);
+      if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
+          !(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+        bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
+      }
+      break;
+
+    case BTA_AG_OUT_CALL_ALERT_RES:
+      /* send indicators */
+      bta_ag_send_call_inds(p_scb, p_result->result);
+      if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
+          !(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+        bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
+      }
+      break;
+
+    case BTA_AG_MULTI_CALL_RES:
+      /* open SCO at SLC for this three way call */
+      APPL_TRACE_DEBUG("Headset Connected in three way call");
+      if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+        if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb))
+          bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
+        else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE)
+          bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result);
+      }
+      break;
+
+    case BTA_AG_OUT_CALL_CONN_RES:
+      /* send indicators */
+      bta_ag_send_call_inds(p_scb, p_result->result);
+
+      /* open or close sco */
+      if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+        if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb)) {
+          bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
+        } else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE) {
+          bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result);
+        }
+      }
+      break;
+
+    case BTA_AG_CALL_CANCEL_RES:
+      /* send indicators */
+      bta_ag_send_call_inds(p_scb, p_result->result);
+      break;
+
+    case BTA_AG_END_CALL_RES:
+      alarm_cancel(p_scb->ring_timer);
+
+      /* if sco open, close sco then send indicator values */
+      if ((bta_ag_sco_is_open(p_scb) || bta_ag_sco_is_opening(p_scb)) &&
+          !(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+        p_scb->post_sco = BTA_AG_POST_SCO_CALL_END;
+        bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result);
+      } else if (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END_INCALL) {
+        /* sco closing for outgoing call because of incoming call */
+        /* Send only callsetup end indicator after sco close */
+        p_scb->post_sco = BTA_AG_POST_SCO_CALL_END;
+      } else {
+        bta_ag_send_call_inds(p_scb, p_result->result);
+
+        /* if av got suspended by this call, let it resume. */
+        bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+      }
+      break;
+
+    case BTA_AG_INBAND_RING_RES:
+      p_scb->inband_enabled = p_result->data.state;
+      APPL_TRACE_DEBUG("inband_enabled set to %d", p_scb->inband_enabled);
+      bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.state);
+      break;
+
+    case BTA_AG_CIND_RES:
+      /* store local values */
+      p_scb->call_ind = p_result->data.str[0] - '0';
+      p_scb->callsetup_ind = p_result->data.str[2] - '0';
+      p_scb->service_ind = p_result->data.str[4] - '0';
+      p_scb->signal_ind = p_result->data.str[6] - '0';
+      p_scb->roam_ind = p_result->data.str[8] - '0';
+      p_scb->battchg_ind = p_result->data.str[10] - '0';
+      p_scb->callheld_ind = p_result->data.str[12] - '0';
+      APPL_TRACE_DEBUG("cind call:%d callsetup:%d", p_scb->call_ind,
+                       p_scb->callsetup_ind);
+
+      bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0);
+      bta_ag_send_ok(p_scb);
+      break;
+
+    case BTA_AG_BINP_RES:
+    case BTA_AG_CNUM_RES:
+    case BTA_AG_CLCC_RES:
+    case BTA_AG_COPS_RES:
+      if (p_result->data.ok_flag != BTA_AG_OK_ERROR) {
+        if (p_result->data.str[0] != 0) {
+          bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0);
+        }
+
+        if (p_result->data.ok_flag == BTA_AG_OK_DONE) bta_ag_send_ok(p_scb);
+      } else {
+        bta_ag_send_error(p_scb, p_result->data.errcode);
+      }
+      break;
+
+    case BTA_AG_UNAT_RES:
+      if (p_result->data.ok_flag != BTA_AG_OK_ERROR) {
+        if (p_result->data.str[0] != 0) {
+          bta_ag_process_unat_res(p_result->data.str);
+          APPL_TRACE_DEBUG("BTA_AG_RES :%s", p_result->data.str);
+          bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0);
+        }
+
+        if (p_result->data.ok_flag == BTA_AG_OK_DONE) bta_ag_send_ok(p_scb);
+      } else {
+        bta_ag_send_error(p_scb, p_result->data.errcode);
+      }
+      break;
+
+    case BTA_AG_CALL_WAIT_RES:
+      if (p_scb->ccwa_enabled) {
+        bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0);
+      }
+      bta_ag_send_call_inds(p_scb, p_result->result);
+      break;
+
+    case BTA_AG_IND_RES:
+      bta_ag_send_ind(p_scb, p_result->data.ind.id, p_result->data.ind.value,
+                      false);
+      break;
+
+    case BTA_AG_BVRA_RES:
+      bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.state);
+      break;
+
+    case BTA_AG_BTRH_RES:
+      if (p_result->data.ok_flag != BTA_AG_OK_ERROR) {
+        /* Don't respond to read if not in response & hold state */
+        if (p_result->data.num != BTA_AG_BTRH_NO_RESP) {
+          bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.num);
+        }
+
+        /* In case of a response to a read request we need to send OK */
+        if (p_result->data.ok_flag == BTA_AG_OK_DONE) bta_ag_send_ok(p_scb);
+      } else {
+        bta_ag_send_error(p_scb, p_result->data.errcode);
+      }
+      break;
+
+    case BTA_AG_BIND_RES: {
+      /* Find whether ind_id is supported by local device or not */
+      int local_index = bta_ag_find_hf_ind_by_id(p_scb->local_hf_indicators,
+                                                 BTA_AG_MAX_NUM_LOCAL_HF_IND,
+                                                 p_result->data.ind.id);
+      if (local_index == -1) {
+        APPL_TRACE_WARNING("%s Invalid HF Indicator ID %d", __func__,
+                           p_result->data.ind.id);
+        return;
+      }
+
+      /* Find whether ind_id is supported by peer device or not */
+      int peer_index = bta_ag_find_hf_ind_by_id(p_scb->peer_hf_indicators,
+                                                BTA_AG_MAX_NUM_PEER_HF_IND,
+                                                p_result->data.ind.id);
+      if (peer_index == -1) {
+        APPL_TRACE_WARNING("%s Invalid HF Indicator ID %d", __func__,
+                           p_result->data.ind.id);
+        return;
+      } else {
+        /* If the current state is different from the one upper layer request
+           change current state and send out the result */
+        if (p_scb->local_hf_indicators[local_index].is_enable !=
+            p_result->data.ind.on_demand) {
+          char buffer[BTA_AG_AT_MAX_LEN] = {0};
+          char* p = buffer;
+
+          p_scb->local_hf_indicators[local_index].is_enable =
+              p_result->data.ind.on_demand;
+          p += utl_itoa(p_result->data.ind.id, p);
+          *p++ = ',';
+          p += utl_itoa(p_scb->local_hf_indicators[local_index].is_enable, p);
+
+          bta_ag_send_result(p_scb, p_result->result, buffer, 0);
+        } else {
+          APPL_TRACE_DEBUG(
+              "%s HF Indicator %d already %s", p_result->data.ind.id,
+              (p_result->data.ind.on_demand == true) ? "Enabled" : "Disabled");
+        }
+      }
+      break;
+    }
+
+    default:
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_result
+ *
+ * Description      Handle API result.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_result(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+  if (p_scb->conn_service == BTA_AG_HSP) {
+    bta_ag_hsp_result(p_scb, &p_data->api_result);
+  } else {
+    bta_ag_hfp_result(p_scb, &p_data->api_result);
+  }
+}
+
+#if (BTM_WBS_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_ag_send_bcs
+ *
+ * Description      Send +BCS AT command to peer.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_send_bcs(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+  uint16_t codec_uuid;
+
+  if (p_scb->codec_fallback) {
+    codec_uuid = UUID_CODEC_CVSD;
+  } else {
+    switch (p_scb->sco_codec) {
+      case BTA_AG_CODEC_NONE:
+        codec_uuid = UUID_CODEC_CVSD;
+        break;
+      case BTA_AG_CODEC_CVSD:
+        codec_uuid = UUID_CODEC_CVSD;
+        break;
+      case BTA_AG_CODEC_MSBC:
+        codec_uuid = UUID_CODEC_MSBC;
+        break;
+      default:
+        APPL_TRACE_ERROR("bta_ag_send_bcs: unknown codec %d, use CVSD",
+                         p_scb->sco_codec);
+        codec_uuid = UUID_CODEC_CVSD;
+        break;
+    }
+  }
+
+  /* send +BCS */
+  APPL_TRACE_DEBUG("send +BCS codec is %d", codec_uuid);
+  bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_BCS, NULL, codec_uuid);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_send_ring
+ *
+ * Description      Send RING result code to peer.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_send_ring(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+  /* send RING */
+  bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_RING, NULL, 0);
+
+  /* if HFP and clip enabled and clip data send CLIP */
+  if (p_scb->conn_service == BTA_AG_HFP && p_scb->clip_enabled &&
+      p_scb->clip[0] != 0) {
+    bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_CLIP, p_scb->clip, 0);
+  }
+
+  bta_sys_start_timer(p_scb->ring_timer, BTA_AG_RING_TIMEOUT_MS,
+                      BTA_AG_RING_TIMEOUT_EVT, bta_ag_scb_to_idx(p_scb));
+}
diff --git a/bt/bta/ag/bta_ag_int.h b/bt/bta/ag/bta_ag_int.h
new file mode 100644
index 0000000..c52f364
--- /dev/null
+++ b/bt/bta/ag/bta_ag_int.h
@@ -0,0 +1,421 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 is the private interface file for the BTA audio gateway.
+ *
+ ******************************************************************************/
+#ifndef BTA_AG_INT_H
+#define BTA_AG_INT_H
+
+#include "bta_ag_api.h"
+#include "bta_ag_at.h"
+#include "bta_api.h"
+#include "bta_sys.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+/* Number of SCBs (AG service instances that can be registered) */
+#ifndef BTA_AG_NUM_SCB
+#define BTA_AG_NUM_SCB 2
+#endif
+
+/* Time to wait for retry in case of collision */
+#ifndef BTA_AG_COLLISION_TIMEOUT_MS
+#define BTA_AG_COLLISION_TIMEOUT_MS (2 * 1000) /* 2 seconds */
+#endif
+
+/* RFCOMM MTU SIZE */
+#define BTA_AG_MTU 256
+
+/* Max number of peer and local HF indicators */
+#define BTA_AG_MAX_NUM_PEER_HF_IND 20
+#define BTA_AG_MAX_NUM_LOCAL_HF_IND 4
+
+/* Internal profile indexes */
+#define BTA_AG_HSP 0     /* index for HSP */
+#define BTA_AG_HFP 1     /* index for HFP */
+#define BTA_AG_NUM_IDX 2 /* number of profile indexes */
+
+/* profile role for connection */
+#define BTA_AG_ACP 0 /* accepted connection */
+#define BTA_AG_INT 1 /* initiating connection */
+
+/* feature mask that matches spec */
+#define BTA_AG_BSRF_FEAT_SPEC                                   \
+  (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR | BTA_AG_FEAT_VREC |     \
+   BTA_AG_FEAT_INBAND | BTA_AG_FEAT_VTAG | BTA_AG_FEAT_REJECT | \
+   BTA_AG_FEAT_ECS | BTA_AG_FEAT_ECC | BTA_AG_FEAT_EXTERR |     \
+   BTA_AG_FEAT_CODEC | BTA_AG_FEAT_HF_IND | BTA_AG_FEAT_ESCO |  \
+   BTA_AG_FEAT_VOIP)
+
+#define BTA_AG_SDP_FEAT_SPEC                                \
+  (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR | BTA_AG_FEAT_VREC | \
+   BTA_AG_FEAT_INBAND | BTA_AG_FEAT_VTAG)
+
+enum {
+  /* these events are handled by the state machine */
+  BTA_AG_API_REGISTER_EVT = BTA_SYS_EVT_START(BTA_ID_AG),
+  BTA_AG_API_DEREGISTER_EVT,
+  BTA_AG_API_OPEN_EVT,
+  BTA_AG_API_CLOSE_EVT,
+  BTA_AG_API_AUDIO_OPEN_EVT,
+  BTA_AG_API_AUDIO_CLOSE_EVT,
+  BTA_AG_API_RESULT_EVT,
+  BTA_AG_API_SETCODEC_EVT,
+  BTA_AG_RFC_OPEN_EVT,
+  BTA_AG_RFC_CLOSE_EVT,
+  BTA_AG_RFC_SRV_CLOSE_EVT,
+  BTA_AG_RFC_DATA_EVT,
+  BTA_AG_SCO_OPEN_EVT,
+  BTA_AG_SCO_CLOSE_EVT,
+  BTA_AG_DISC_ACP_RES_EVT,
+  BTA_AG_DISC_INT_RES_EVT,
+  BTA_AG_DISC_OK_EVT,
+  BTA_AG_DISC_FAIL_EVT,
+  BTA_AG_CI_RX_WRITE_EVT,
+  BTA_AG_RING_TIMEOUT_EVT,
+  BTA_AG_SVC_TIMEOUT_EVT,
+  BTA_AG_CI_SCO_DATA_EVT,
+  BTA_AG_CI_SLC_READY_EVT,
+  BTA_AG_MAX_EVT,
+
+  /* these events are handled outside of the state machine */
+  BTA_AG_API_ENABLE_EVT,
+  BTA_AG_API_DISABLE_EVT
+};
+
+/* Actions to perform after a SCO event */
+enum {
+  BTA_AG_POST_SCO_NONE,      /* no action */
+  BTA_AG_POST_SCO_CLOSE_RFC, /* close RFCOMM channel after SCO closes */
+  BTA_AG_POST_SCO_RING,      /* send RING result code after SCO opens */
+  BTA_AG_POST_SCO_CALL_CONN, /* send call indicators after SCO opens/closes */
+  BTA_AG_POST_SCO_CALL_ORIG, /* send call indicators after SCO closes */
+  BTA_AG_POST_SCO_CALL_END,  /* send call indicators after SCO closes */
+  BTA_AG_POST_SCO_CALL_END_INCALL /* send call indicators for end call &
+                                     incoming call after SCO closes */
+};
+
+/* sco states */
+enum {
+  BTA_AG_SCO_SHUTDOWN_ST, /* no sco listening, all sco connections closed */
+  BTA_AG_SCO_LISTEN_ST,   /* sco listening */
+#if (BTM_WBS_INCLUDED == TRUE)
+  BTA_AG_SCO_CODEC_ST, /* sco codec negotiation */
+#endif
+  BTA_AG_SCO_OPENING_ST,    /* sco connection opening */
+  BTA_AG_SCO_OPEN_CL_ST,    /* opening sco connection being closed */
+  BTA_AG_SCO_OPEN_XFER_ST,  /* opening sco connection being transferred */
+  BTA_AG_SCO_OPEN_ST,       /* sco open */
+  BTA_AG_SCO_CLOSING_ST,    /* sco closing */
+  BTA_AG_SCO_CLOSE_OP_ST,   /* closing sco being opened */
+  BTA_AG_SCO_CLOSE_XFER_ST, /* closing sco being transferred */
+  BTA_AG_SCO_SHUTTING_ST    /* sco shutting down */
+};
+
+/*****************************************************************************
+ *  Data types
+ ****************************************************************************/
+
+/* data type for BTA_AG_API_ENABLE_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_AG_PARSE_MODE parse_mode;
+  tBTA_AG_CBACK* p_cback;
+} tBTA_AG_API_ENABLE;
+
+/* data type for BTA_AG_API_REGISTER_EVT */
+typedef struct {
+  BT_HDR hdr;
+  char p_name[2][BTA_SERVICE_NAME_LEN + 1];
+  tBTA_SERVICE_MASK services;
+  tBTA_SEC sec_mask;
+  tBTA_AG_FEAT features;
+  uint8_t app_id;
+} tBTA_AG_API_REGISTER;
+
+/* data type for BTA_AG_API_OPEN_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  tBTA_SERVICE_MASK services;
+  tBTA_SEC sec_mask;
+} tBTA_AG_API_OPEN;
+
+/* data type for BTA_AG_API_RESULT_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_AG_RES result;
+  tBTA_AG_RES_DATA data;
+} tBTA_AG_API_RESULT;
+
+/* data type for BTA_AG_API_SETCODEC_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_AG_PEER_CODEC codec;
+} tBTA_AG_API_SETCODEC;
+
+/* data type for BTA_AG_DISC_RESULT_EVT */
+typedef struct {
+  BT_HDR hdr;
+  uint16_t status;
+} tBTA_AG_DISC_RESULT;
+
+/* data type for RFCOMM events */
+typedef struct {
+  BT_HDR hdr;
+  uint16_t port_handle;
+} tBTA_AG_RFC;
+
+/* data type for BTA_AG_CI_RX_WRITE_EVT */
+typedef struct {
+  BT_HDR hdr;
+  //    char            p_data[BTA_AG_MTU+1];
+} tBTA_AG_CI_RX_WRITE;
+
+/* union of all event datatypes */
+typedef union {
+  BT_HDR hdr;
+  tBTA_AG_API_ENABLE api_enable;
+  tBTA_AG_API_REGISTER api_register;
+  tBTA_AG_API_OPEN api_open;
+  tBTA_AG_API_RESULT api_result;
+#if (BTM_WBS_INCLUDED == TRUE)
+  tBTA_AG_API_SETCODEC api_setcodec;
+#endif
+  tBTA_AG_DISC_RESULT disc_result;
+  tBTA_AG_RFC rfc;
+  tBTA_AG_CI_RX_WRITE ci_rx_write;
+} tBTA_AG_DATA;
+
+/* type for each profile */
+typedef struct {
+  uint32_t sdp_handle;
+  uint8_t scn;
+} tBTA_AG_PROFILE;
+
+#if (BTM_WBS_INCLUDED == TRUE)
+typedef enum {
+  BTA_AG_SCO_MSBC_SETTINGS_T2 = 0, /* preferred/default when codec is mSBC */
+  BTA_AG_SCO_MSBC_SETTINGS_T1,
+} tBTA_AG_SCO_MSBC_SETTINGS;
+#endif
+
+/* type for each service control block */
+typedef struct {
+  char clip[BTA_AG_AT_MAX_LEN + 1];     /* number string used for CLIP */
+  uint16_t serv_handle[BTA_AG_NUM_IDX]; /* RFCOMM server handles */
+  tBTA_AG_AT_CB at_cb;                  /* AT command interpreter */
+  BD_ADDR peer_addr;                    /* peer bd address */
+  tSDP_DISCOVERY_DB* p_disc_db;         /* pointer to discovery database */
+  tBTA_SERVICE_MASK reg_services;       /* services specified in register API */
+  tBTA_SERVICE_MASK open_services;      /* services specified in open API */
+  uint16_t conn_handle;                 /* RFCOMM handle of connected service */
+  tBTA_SEC serv_sec_mask;               /* server security mask */
+  tBTA_SEC cli_sec_mask;                /* client security mask */
+  tBTA_AG_FEAT features;                /* features registered by application */
+  tBTA_AG_PEER_FEAT peer_features;      /* peer device features */
+  uint16_t peer_version;                /* profile version of peer device */
+  uint16_t hsp_version;                 /* HSP profile version */
+  uint16_t sco_idx;                     /* SCO handle */
+  bool in_use;                          /* scb in use */
+  bool dealloc;                         /* true if service shutting down */
+  bool clip_enabled;        /* set to true if HF enables CLIP reporting */
+  bool ccwa_enabled;        /* set to true if HF enables CCWA reporting */
+  bool cmer_enabled;        /* set to true if HF enables CMER reporting */
+  bool cmee_enabled;        /* set to true if HF enables CME ERROR reporting */
+  bool inband_enabled;      /* set to true if inband ring enabled */
+  bool svc_conn;            /* set to true when service level connection up */
+  uint8_t state;            /* state machine state */
+  uint8_t conn_service;     /* connected service */
+  uint8_t peer_scn;         /* peer scn */
+  uint8_t app_id;           /* application id */
+  uint8_t role;             /* initiator/acceptor role */
+  uint8_t post_sco;         /* action to perform after sco event */
+  uint8_t call_ind;         /* CIEV call indicator value */
+  uint8_t callsetup_ind;    /* CIEV callsetup indicator value */
+  uint8_t service_ind;      /* CIEV service indicator value */
+  uint8_t signal_ind;       /* CIEV signal indicator value */
+  uint8_t roam_ind;         /* CIEV roam indicator value */
+  uint8_t battchg_ind;      /* CIEV battery charge indicator value */
+  uint8_t callheld_ind;     /* CIEV call held indicator value */
+  bool retry_with_sco_only; /* indicator to try with SCO only when eSCO fails */
+  uint32_t bia_masked_out;  /* indicators HF does not want us to send */
+  alarm_t* collision_timer;
+  alarm_t* ring_timer;
+#if (BTM_WBS_INCLUDED == TRUE)
+  alarm_t* codec_negotiation_timer;
+  tBTA_AG_PEER_CODEC peer_codecs; /* codecs for eSCO supported by the peer */
+  tBTA_AG_PEER_CODEC sco_codec;   /* codec to be used for eSCO connection */
+  tBTA_AG_PEER_CODEC
+      inuse_codec;     /* codec being used for the current SCO connection */
+  bool codec_updated;  /* set to true whenever the app updates codec type */
+  bool codec_fallback; /* If sco nego fails for mSBC, fallback to CVSD */
+  tBTA_AG_SCO_MSBC_SETTINGS
+      codec_msbc_settings; /* settings to be used for the impending eSCO */
+#endif
+
+  tBTA_AG_HF_IND
+      peer_hf_indicators[BTA_AG_MAX_NUM_PEER_HF_IND]; /* Peer supported
+                                                  HF indicators */
+  tBTA_AG_HF_IND
+      local_hf_indicators[BTA_AG_MAX_NUM_LOCAL_HF_IND]; /* Local supported
+                                                    HF indicators */
+} tBTA_AG_SCB;
+
+/* type for sco data */
+typedef struct {
+  tBTM_ESCO_CONN_REQ_EVT_DATA conn_data; /* SCO data for pending conn request */
+  tBTA_AG_SCB* p_curr_scb; /* SCB associated with SCO connection */
+  tBTA_AG_SCB* p_xfer_scb; /* SCB associated with SCO transfer */
+  uint16_t cur_idx;        /* SCO handle */
+  uint8_t state;           /* SCO state variable */
+  bool param_updated;      /* if params were updated to non-default */
+  tBTM_ESCO_PARAMS params; /* ESCO parameters */
+} tBTA_AG_SCO_CB;
+
+/* type for AG control block */
+typedef struct {
+  tBTA_AG_SCB scb[BTA_AG_NUM_SCB];         /* service control blocks */
+  tBTA_AG_PROFILE profile[BTA_AG_NUM_IDX]; /* profile-specific data */
+  tBTA_AG_SCO_CB sco;                      /* SCO data */
+  tBTA_AG_CBACK* p_cback;                  /* application callback */
+  tBTA_AG_PARSE_MODE parse_mode;           /* parse/pass-through mode */
+} tBTA_AG_CB;
+
+/*****************************************************************************
+ *  Global data
+ ****************************************************************************/
+
+/* constant lookup tables */
+extern const uint16_t bta_ag_uuid[BTA_AG_NUM_IDX];
+extern const uint8_t bta_ag_sec_id[BTA_AG_NUM_IDX];
+extern const tBTA_AG_AT_CMD* bta_ag_at_tbl[BTA_AG_NUM_IDX];
+
+/* control block declaration */
+extern tBTA_AG_CB bta_ag_cb;
+
+/* config struct */
+extern tBTA_AG_CFG* p_bta_ag_cfg;
+extern const tBTA_AG_HF_IND bta_ag_local_hf_ind_cfg[];
+
+/*****************************************************************************
+ *  Function prototypes
+ ****************************************************************************/
+
+/* main functions */
+extern void bta_ag_scb_dealloc(tBTA_AG_SCB* p_scb);
+extern uint16_t bta_ag_scb_to_idx(tBTA_AG_SCB* p_scb);
+extern tBTA_AG_SCB* bta_ag_scb_by_idx(uint16_t idx);
+extern uint8_t bta_ag_service_to_idx(tBTA_SERVICE_MASK services);
+extern uint16_t bta_ag_idx_by_bdaddr(BD_ADDR peer_addr);
+extern bool bta_ag_other_scb_open(tBTA_AG_SCB* p_curr_scb);
+extern bool bta_ag_scb_open(tBTA_AG_SCB* p_curr_scb);
+extern tBTA_AG_SCB* bta_ag_get_other_idle_scb(tBTA_AG_SCB* p_curr_scb);
+extern void bta_ag_sm_execute(tBTA_AG_SCB* p_scb, uint16_t event,
+                              tBTA_AG_DATA* p_data);
+extern bool bta_ag_hdl_event(BT_HDR* p_msg);
+extern void bta_ag_collision_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
+                                   uint8_t app_id, BD_ADDR peer_addr);
+extern void bta_ag_resume_open(tBTA_AG_SCB* p_scb);
+
+/* SDP functions */
+extern bool bta_ag_add_record(uint16_t service_uuid, char* p_service_name,
+                              uint8_t scn, tBTA_AG_FEAT features,
+                              uint32_t sdp_handle);
+extern void bta_ag_create_records(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_del_records(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern bool bta_ag_sdp_find_attr(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK service);
+extern void bta_ag_do_disc(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK service);
+extern void bta_ag_free_db(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+
+/* RFCOMM functions */
+extern void bta_ag_start_servers(tBTA_AG_SCB* p_scb,
+                                 tBTA_SERVICE_MASK services);
+extern void bta_ag_close_servers(tBTA_AG_SCB* p_scb,
+                                 tBTA_SERVICE_MASK services);
+extern bool bta_ag_is_server_closed(tBTA_AG_SCB* p_scb);
+extern void bta_ag_rfc_do_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_rfc_do_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+
+/* SCO functions */
+extern bool bta_ag_sco_is_open(tBTA_AG_SCB* p_scb);
+extern bool bta_ag_sco_is_opening(tBTA_AG_SCB* p_scb);
+extern void bta_ag_sco_conn_rsp(tBTA_AG_SCB* p_scb,
+                                tBTM_ESCO_CONN_REQ_EVT_DATA* p_data);
+
+/* AT command functions */
+extern void bta_ag_at_hsp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd,
+                                uint8_t arg_type, char* p_arg, int16_t int_arg);
+extern void bta_ag_at_hfp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd,
+                                uint8_t arg_type, char* p_arg, int16_t int_arg);
+extern void bta_ag_at_err_cback(tBTA_AG_SCB* p_scb, bool unknown, char* p_arg);
+extern bool bta_ag_inband_enabled(tBTA_AG_SCB* p_scb);
+extern void bta_ag_send_call_inds(tBTA_AG_SCB* p_scb, tBTA_AG_RES result);
+
+/* Action functions */
+extern void bta_ag_register(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_deregister(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_start_dereg(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_start_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_start_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_disc_int_res(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_disc_acp_res(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_disc_fail(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_open_fail(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_rfc_fail(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_rfc_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_rfc_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_rfc_acp_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_rfc_data(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_sco_listen(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_sco_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_sco_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+#if (BTM_WBS_INCLUDED == TRUE)
+extern void bta_ag_sco_codec_nego(tBTA_AG_SCB* p_scb, bool result);
+extern void bta_ag_codec_negotiate(tBTA_AG_SCB* p_scb);
+#endif
+extern void bta_ag_sco_shutdown(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_sco_conn_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_sco_conn_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_post_sco_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_post_sco_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_svc_conn_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_result(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_setcodec(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+#if (BTM_WBS_INCLUDED == TRUE)
+extern void bta_ag_send_bcs(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+#endif
+extern void bta_ag_send_ring(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_ci_sco_data(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_set_esco_param(bool set_reset, tBTM_ESCO_PARAMS* param);
+extern void bta_ag_ci_rx_data(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_rcvd_slc_ready(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_AG_INT_H */
diff --git a/bt/bta/ag/bta_ag_main.cc b/bt/bta/ag/bta_ag_main.cc
new file mode 100644
index 0000000..44965ea
--- /dev/null
+++ b/bt/bta/ag/bta_ag_main.cc
@@ -0,0 +1,933 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 is the main implementation file for the BTA audio gateway.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bta_ag_co.h"
+#include "bta_ag_int.h"
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "osi/include/osi.h"
+#include "utl.h"
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+#ifndef BTA_AG_DEBUG
+#define BTA_AG_DEBUG FALSE
+#endif
+
+extern fixed_queue_t* btu_bta_alarm_queue;
+
+#if (BTA_AG_DEBUG == TRUE)
+static char* bta_ag_evt_str(uint16_t event, tBTA_AG_RES result);
+static char* bta_ag_state_str(uint8_t state);
+#endif
+
+/* state machine states */
+enum { BTA_AG_INIT_ST, BTA_AG_OPENING_ST, BTA_AG_OPEN_ST, BTA_AG_CLOSING_ST };
+
+/* state machine action enumeration list */
+enum {
+  BTA_AG_REGISTER,
+  BTA_AG_DEREGISTER,
+  BTA_AG_START_OPEN,
+  BTA_AG_RFC_DO_OPEN,
+  BTA_AG_RFC_DO_CLOSE,
+  BTA_AG_START_DEREG,
+  BTA_AG_START_CLOSE,
+  BTA_AG_RFC_OPEN,
+  BTA_AG_OPEN_FAIL,
+  BTA_AG_RFC_ACP_OPEN,
+  BTA_AG_RFC_CLOSE,
+  BTA_AG_RFC_FAIL,
+  BTA_AG_RFC_DATA,
+  BTA_AG_DISC_INT_RES,
+  BTA_AG_DISC_FAIL,
+  BTA_AG_DISC_ACP_RES,
+  BTA_AG_FREE_DB,
+  BTA_AG_SCO_CONN_OPEN,
+  BTA_AG_SCO_CONN_CLOSE,
+  BTA_AG_SCO_LISTEN,
+  BTA_AG_SCO_OPEN,
+  BTA_AG_SCO_CLOSE,
+  BTA_AG_SCO_SHUTDOWN,
+  BTA_AG_POST_SCO_OPEN,
+  BTA_AG_POST_SCO_CLOSE,
+  BTA_AG_SVC_CONN_OPEN,
+  BTA_AG_RESULT,
+  BTA_AG_SETCODEC,
+  BTA_AG_SEND_RING,
+  BTA_AG_CI_SCO_DATA,
+  BTA_AG_CI_RX_DATA,
+  BTA_AG_RCVD_SLC_READY,
+  BTA_AG_NUM_ACTIONS
+};
+
+#define BTA_AG_IGNORE BTA_AG_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tBTA_AG_ACTION)(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+
+/* action functions */
+const tBTA_AG_ACTION bta_ag_action[] = {
+    bta_ag_register,       bta_ag_deregister,    bta_ag_start_open,
+    bta_ag_rfc_do_open,    bta_ag_rfc_do_close,  bta_ag_start_dereg,
+    bta_ag_start_close,    bta_ag_rfc_open,      bta_ag_open_fail,
+    bta_ag_rfc_acp_open,   bta_ag_rfc_close,     bta_ag_rfc_fail,
+    bta_ag_rfc_data,       bta_ag_disc_int_res,  bta_ag_disc_fail,
+    bta_ag_disc_acp_res,   bta_ag_free_db,       bta_ag_sco_conn_open,
+    bta_ag_sco_conn_close, bta_ag_sco_listen,    bta_ag_sco_open,
+    bta_ag_sco_close,      bta_ag_sco_shutdown,  bta_ag_post_sco_open,
+    bta_ag_post_sco_close, bta_ag_svc_conn_open, bta_ag_result,
+    bta_ag_setcodec,       bta_ag_send_ring,     bta_ag_ci_sco_data,
+    bta_ag_ci_rx_data,     bta_ag_rcvd_slc_ready};
+
+/* state table information */
+#define BTA_AG_ACTIONS 2    /* number of actions */
+#define BTA_AG_NEXT_STATE 2 /* position of next state */
+#define BTA_AG_NUM_COLS 3   /* number of columns in state tables */
+
+/* state table for init state */
+const uint8_t bta_ag_st_init[][BTA_AG_NUM_COLS] = {
+    /* Event                    Action 1                Action 2 Next state */
+    /* API_REGISTER_EVT */ {BTA_AG_REGISTER, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* API_DEREGISTER_EVT */ {BTA_AG_DEREGISTER, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* API_OPEN_EVT */ {BTA_AG_START_OPEN, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+    /* API_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* API_AUDIO_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* API_AUDIO_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* API_RESULT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* API_SETCODEC_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* RFC_OPEN_EVT */ {BTA_AG_RFC_ACP_OPEN, BTA_AG_SCO_LISTEN, BTA_AG_OPEN_ST},
+    /* RFC_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* RFC_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* DISC_ACP_RES_EVT */ {BTA_AG_FREE_DB, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* DISC_INT_RES_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* CI_RX_WRITE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* CI_SCO_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* CI_SLC_READY_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}};
+
+/* state table for opening state */
+const uint8_t bta_ag_st_opening[][BTA_AG_NUM_COLS] = {
+    /* Event                    Action 1                Action 2 Next state */
+    /* API_REGISTER_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+    /* API_DEREGISTER_EVT */ {BTA_AG_RFC_DO_CLOSE, BTA_AG_START_DEREG,
+                              BTA_AG_CLOSING_ST},
+    /* API_OPEN_EVT */ {BTA_AG_OPEN_FAIL, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+    /* API_CLOSE_EVT */ {BTA_AG_RFC_DO_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* API_AUDIO_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+    /* API_AUDIO_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+    /* API_RESULT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+    /* API_SETCODEC_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+    /* RFC_OPEN_EVT */ {BTA_AG_RFC_OPEN, BTA_AG_SCO_LISTEN, BTA_AG_OPEN_ST},
+    /* RFC_CLOSE_EVT */ {BTA_AG_RFC_FAIL, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+    /* RFC_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+    /* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+    /* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_IGNORE,
+                         BTA_AG_OPENING_ST},
+    /* DISC_ACP_RES_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+    /* DISC_INT_RES_EVT */ {BTA_AG_DISC_INT_RES, BTA_AG_IGNORE,
+                            BTA_AG_OPENING_ST},
+    /* DISC_OK_EVT */ {BTA_AG_RFC_DO_OPEN, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+    /* DISC_FAIL_EVT */ {BTA_AG_DISC_FAIL, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* CI_RX_WRITE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+    /* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+    /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+    /* CI_SCO_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+    /* CI_SLC_READY_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}};
+
+/* state table for open state */
+const uint8_t bta_ag_st_open[][BTA_AG_NUM_COLS] = {
+    /* Event                    Action 1                Action 2 Next state */
+    /* API_REGISTER_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+    /* API_DEREGISTER_EVT */ {BTA_AG_START_CLOSE, BTA_AG_START_DEREG,
+                              BTA_AG_CLOSING_ST},
+    /* API_OPEN_EVT */ {BTA_AG_OPEN_FAIL, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+    /* API_CLOSE_EVT */ {BTA_AG_START_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* API_AUDIO_OPEN_EVT */ {BTA_AG_SCO_OPEN, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+    /* API_AUDIO_CLOSE_EVT */ {BTA_AG_SCO_CLOSE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+    /* API_RESULT_EVT */ {BTA_AG_RESULT, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+    /* API_SETCODEC_EVT */ {BTA_AG_SETCODEC, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+    /* RFC_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+    /* RFC_CLOSE_EVT */ {BTA_AG_RFC_CLOSE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+    /* RFC_DATA_EVT */ {BTA_AG_RFC_DATA, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+    /* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_POST_SCO_OPEN,
+                        BTA_AG_OPEN_ST},
+    /* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_POST_SCO_CLOSE,
+                         BTA_AG_OPEN_ST},
+    /* DISC_ACP_RES_EVT */ {BTA_AG_DISC_ACP_RES, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+    /* DISC_INT_RES_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+    /* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+    /* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+    /* CI_RX_WRITE_EVT */ {BTA_AG_CI_RX_DATA, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+    /* RING_TOUT_EVT */ {BTA_AG_SEND_RING, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+    /* SVC_TOUT_EVT */ {BTA_AG_START_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* CI_SCO_DATA_EVT */ {BTA_AG_CI_SCO_DATA, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+    /* CI_SLC_READY_EVT */ {BTA_AG_RCVD_SLC_READY, BTA_AG_IGNORE,
+                            BTA_AG_OPEN_ST}};
+
+/* state table for closing state */
+const uint8_t bta_ag_st_closing[][BTA_AG_NUM_COLS] = {
+    /* Event                    Action 1                Action 2 Next state */
+    /* API_REGISTER_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* API_DEREGISTER_EVT */ {BTA_AG_START_DEREG, BTA_AG_IGNORE,
+                              BTA_AG_CLOSING_ST},
+    /* API_OPEN_EVT */ {BTA_AG_OPEN_FAIL, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* API_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* API_AUDIO_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* API_AUDIO_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* API_RESULT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* API_SETCODEC_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* RFC_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* RFC_CLOSE_EVT */ {BTA_AG_RFC_CLOSE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* RFC_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_POST_SCO_CLOSE,
+                         BTA_AG_CLOSING_ST},
+    /* DISC_ACP_RES_EVT */ {BTA_AG_FREE_DB, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* DISC_INT_RES_EVT */ {BTA_AG_FREE_DB, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+    /* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* CI_RX_WRITE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* CI_SCO_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+    /* CI_SLC_READY_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}};
+
+/* type for state table */
+typedef const uint8_t (*tBTA_AG_ST_TBL)[BTA_AG_NUM_COLS];
+
+/* state table */
+const tBTA_AG_ST_TBL bta_ag_st_tbl[] = {bta_ag_st_init, bta_ag_st_opening,
+                                        bta_ag_st_open, bta_ag_st_closing};
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+
+/* AG control block */
+tBTA_AG_CB bta_ag_cb;
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_scb_alloc
+ *
+ * Description      Allocate an AG service control block.
+ *
+ *
+ * Returns          pointer to the scb, or NULL if none could be allocated.
+ *
+ ******************************************************************************/
+static tBTA_AG_SCB* bta_ag_scb_alloc(void) {
+  tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
+  int i;
+
+  for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) {
+    if (!p_scb->in_use) {
+      /* initialize variables */
+      p_scb->in_use = true;
+      p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+#if (BTM_WBS_INCLUDED == TRUE)
+      p_scb->codec_updated = false;
+      p_scb->peer_codecs = BTA_AG_CODEC_CVSD;
+      p_scb->sco_codec = BTA_AG_CODEC_CVSD;
+#endif
+      /* set up timers */
+      p_scb->ring_timer = alarm_new("bta_ag.scb_ring_timer");
+      p_scb->collision_timer = alarm_new("bta_ag.scb_collision_timer");
+#if (BTM_WBS_INCLUDED == TRUE)
+      p_scb->codec_negotiation_timer =
+          alarm_new("bta_ag.scb_codec_negotiation_timer");
+      /* set eSCO mSBC setting to T2 as the preferred */
+      p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2;
+#endif
+      APPL_TRACE_DEBUG("bta_ag_scb_alloc %d", bta_ag_scb_to_idx(p_scb));
+      break;
+    }
+  }
+
+  if (i == BTA_AG_NUM_SCB) {
+    /* out of scbs */
+    p_scb = NULL;
+    APPL_TRACE_WARNING("Out of ag scbs");
+  }
+  return p_scb;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_scb_dealloc
+ *
+ * Description      Deallocate a service control block.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_scb_dealloc(tBTA_AG_SCB* p_scb) {
+  uint8_t idx;
+  bool allocated = false;
+
+  APPL_TRACE_DEBUG("bta_ag_scb_dealloc %d", bta_ag_scb_to_idx(p_scb));
+
+  /* stop and free timers */
+  alarm_free(p_scb->ring_timer);
+#if (BTM_WBS_INCLUDED == TRUE)
+  alarm_free(p_scb->codec_negotiation_timer);
+#endif
+  alarm_free(p_scb->collision_timer);
+
+  /* initialize control block */
+  memset(p_scb, 0, sizeof(tBTA_AG_SCB));
+  p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+
+  /* If all scbs are deallocated, callback with disable event */
+  if (!bta_sys_is_register(BTA_ID_AG)) {
+    for (idx = 0; idx < BTA_AG_NUM_SCB; idx++) {
+      if (bta_ag_cb.scb[idx].in_use) {
+        allocated = true;
+        break;
+      }
+    }
+
+    if (!allocated) {
+      (*bta_ag_cb.p_cback)(BTA_AG_DISABLE_EVT, NULL);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_scb_to_idx
+ *
+ * Description      Given a pointer to an scb, return its index.
+ *
+ *
+ * Returns          Index of scb.
+ *
+ ******************************************************************************/
+uint16_t bta_ag_scb_to_idx(tBTA_AG_SCB* p_scb) {
+  /* use array arithmetic to determine index */
+  return ((uint16_t)(p_scb - bta_ag_cb.scb)) + 1;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_scb_by_idx
+ *
+ * Description      Given an scb index return pointer to scb.
+ *
+ *
+ * Returns          Pointer to scb or NULL if not allocated.
+ *
+ ******************************************************************************/
+tBTA_AG_SCB* bta_ag_scb_by_idx(uint16_t idx) {
+  tBTA_AG_SCB* p_scb;
+
+  /* verify index */
+  if (idx > 0 && idx <= BTA_AG_NUM_SCB) {
+    p_scb = &bta_ag_cb.scb[idx - 1];
+    if (!p_scb->in_use) {
+      p_scb = NULL;
+      APPL_TRACE_WARNING("ag scb idx %d not allocated", idx);
+    }
+  } else {
+    p_scb = NULL;
+    APPL_TRACE_DEBUG("ag scb idx %d out of range", idx);
+  }
+  return p_scb;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_service_to_idx
+ *
+ * Description      Given a BTA service mask convert to profile index.
+ *
+ *
+ * Returns          Profile ndex of scb.
+ *
+ ******************************************************************************/
+uint8_t bta_ag_service_to_idx(tBTA_SERVICE_MASK services) {
+  if (services & BTA_HFP_SERVICE_MASK) {
+    return BTA_AG_HFP;
+  } else {
+    return BTA_AG_HSP;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_idx_by_bdaddr
+ *
+ * Description      Find SCB associated with peer BD address.
+ *
+ *
+ * Returns          Index of SCB or zero if none found.
+ *
+ ******************************************************************************/
+uint16_t bta_ag_idx_by_bdaddr(BD_ADDR peer_addr) {
+  tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
+  uint16_t i;
+
+  if (peer_addr != NULL) {
+    for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) {
+      if (p_scb->in_use && !bdcmp(peer_addr, p_scb->peer_addr)) {
+        return (i + 1);
+      }
+    }
+  }
+
+  /* no scb found */
+  APPL_TRACE_WARNING("No ag scb for peer addr");
+  return 0;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_other_scb_open
+ *
+ * Description      Check whether any other scb is in open state.
+ *
+ *
+ * Returns          true if another scb is in open state, false otherwise.
+ *
+ ******************************************************************************/
+bool bta_ag_other_scb_open(tBTA_AG_SCB* p_curr_scb) {
+  tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
+  int i;
+
+  for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) {
+    if (p_scb->in_use && p_scb != p_curr_scb &&
+        p_scb->state == BTA_AG_OPEN_ST) {
+      return true;
+    }
+  }
+
+  /* no other scb found */
+  APPL_TRACE_DEBUG("No other ag scb open");
+  return false;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_scb_open
+ *
+ * Description      Check whether given scb is in open state.
+ *
+ *
+ * Returns          true if scb is in open state, false otherwise.
+ *
+ ******************************************************************************/
+bool bta_ag_scb_open(tBTA_AG_SCB* p_curr_scb) {
+  if (p_curr_scb && p_curr_scb->in_use && p_curr_scb->state == BTA_AG_OPEN_ST) {
+    return true;
+  }
+
+  return false;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_get_other_idle_scb
+ *
+ * Description      Return other scb if it is in INIT st.
+ *
+ *
+ * Returns          Pointer to other scb if INIT st, NULL otherwise.
+ *
+ ******************************************************************************/
+tBTA_AG_SCB* bta_ag_get_other_idle_scb(tBTA_AG_SCB* p_curr_scb) {
+  tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
+  uint8_t xx;
+
+  for (xx = 0; xx < BTA_AG_NUM_SCB; xx++, p_scb++) {
+    if (p_scb->in_use && (p_scb != p_curr_scb) &&
+        (p_scb->state == BTA_AG_INIT_ST)) {
+      return p_scb;
+    }
+  }
+
+  /* no other scb found */
+  APPL_TRACE_DEBUG("bta_ag_get_other_idle_scb: No idle AG scb");
+  return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_collision_timer_cback
+ *
+ * Description      AG connection collision timer callback
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ag_collision_timer_cback(void* data) {
+  tBTA_AG_SCB* p_scb = (tBTA_AG_SCB*)data;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  /* If the peer haven't opened AG connection     */
+  /* we will restart opening process.             */
+  bta_ag_resume_open(p_scb);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_collision_cback
+ *
+ * Description      Get notified about collision.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_collision_cback(UNUSED_ATTR tBTA_SYS_CONN_STATUS status, uint8_t id,
+                            UNUSED_ATTR uint8_t app_id, BD_ADDR peer_addr) {
+  uint16_t handle;
+  tBTA_AG_SCB* p_scb;
+
+  /* Check if we have opening scb for the peer device. */
+  handle = bta_ag_idx_by_bdaddr(peer_addr);
+  p_scb = bta_ag_scb_by_idx(handle);
+
+  if (p_scb && (p_scb->state == BTA_AG_OPENING_ST)) {
+    if (id == BTA_ID_SYS) /* ACL collision */
+    {
+      APPL_TRACE_WARNING("AG found collision (ACL) ...");
+    } else if (id == BTA_ID_AG) /* RFCOMM collision */
+    {
+      APPL_TRACE_WARNING("AG found collision (RFCOMM) ...");
+    } else {
+      APPL_TRACE_WARNING("AG found collision (\?\?\?) ...");
+    }
+
+    p_scb->state = BTA_AG_INIT_ST;
+
+    /* Cancel SDP if it had been started. */
+    if (p_scb->p_disc_db) {
+      (void)SDP_CancelServiceSearch(p_scb->p_disc_db);
+      bta_ag_free_db(p_scb, NULL);
+    }
+
+    /* reopen registered servers */
+    /* Collision may be detected before or after we close servers. */
+    if (bta_ag_is_server_closed(p_scb))
+      bta_ag_start_servers(p_scb, p_scb->reg_services);
+
+    /* Start timer to han */
+    alarm_set_on_queue(p_scb->collision_timer, BTA_AG_COLLISION_TIMEOUT_MS,
+                       bta_ag_collision_timer_cback, p_scb,
+                       btu_bta_alarm_queue);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_resume_open
+ *
+ * Description      Resume opening process.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_resume_open(tBTA_AG_SCB* p_scb) {
+  if (p_scb) {
+    APPL_TRACE_DEBUG("bta_ag_resume_open, Handle(%d)",
+                     bta_ag_scb_to_idx(p_scb));
+
+    /* resume opening process.  */
+    if (p_scb->state == BTA_AG_INIT_ST) {
+      p_scb->state = BTA_AG_OPENING_ST;
+      bta_ag_start_open(p_scb, NULL);
+    }
+  } else {
+    APPL_TRACE_ERROR("bta_ag_resume_open, Null p_scb");
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_api_enable
+ *
+ * Description      Handle an API enable event.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ag_api_enable(tBTA_AG_DATA* p_data) {
+  /* initialize control block */
+  for (size_t i = 0; i < BTA_AG_NUM_SCB; i++) {
+    alarm_free(bta_ag_cb.scb[i].ring_timer);
+#if (BTM_WBS_INCLUDED == TRUE)
+    alarm_free(bta_ag_cb.scb[i].codec_negotiation_timer);
+#endif
+    alarm_free(bta_ag_cb.scb[i].collision_timer);
+  }
+  memset(&bta_ag_cb, 0, sizeof(tBTA_AG_CB));
+
+  /* store callback function */
+  bta_ag_cb.p_cback = p_data->api_enable.p_cback;
+  bta_ag_cb.parse_mode = p_data->api_enable.parse_mode;
+
+  /* call init call-out */
+  bta_ag_co_init();
+
+  bta_sys_collision_register(BTA_ID_AG, bta_ag_collision_cback);
+
+  /* call callback with enable event */
+  (*bta_ag_cb.p_cback)(BTA_AG_ENABLE_EVT, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_api_disable
+ *
+ * Description      Handle an API disable event.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ag_api_disable(tBTA_AG_DATA* p_data) {
+  /* deregister all scbs in use */
+  tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
+  bool do_dereg = false;
+  int i;
+
+  if (!bta_sys_is_register(BTA_ID_AG)) {
+    APPL_TRACE_ERROR("BTA AG is already disabled, ignoring ...");
+    return;
+  }
+
+  /* De-register with BTA system manager */
+  bta_sys_deregister(BTA_ID_AG);
+
+  for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) {
+    if (p_scb->in_use) {
+      bta_ag_sm_execute(p_scb, BTA_AG_API_DEREGISTER_EVT, p_data);
+      do_dereg = true;
+    }
+  }
+
+  if (!do_dereg) {
+    /* Done, send callback evt to app */
+    (*bta_ag_cb.p_cback)(BTA_AG_DISABLE_EVT, NULL);
+  }
+
+  bta_sys_collision_register(BTA_ID_AG, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_api_register
+ *
+ * Description      Handle an API event registers a new service.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ag_api_register(tBTA_AG_DATA* p_data) {
+  tBTA_AG_SCB* p_scb;
+  tBTA_AG_REGISTER reg;
+
+  /* allocate an scb */
+  if ((p_scb = bta_ag_scb_alloc()) != NULL) {
+    APPL_TRACE_DEBUG("bta_ag_api_register: p_scb 0x%08x ", p_scb);
+    bta_ag_sm_execute(p_scb, p_data->hdr.event, p_data);
+  } else {
+    reg.status = BTA_AG_FAIL_RESOURCES;
+    (*bta_ag_cb.p_cback)(BTA_AG_REGISTER_EVT, (tBTA_AG*)&reg);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_api_result
+ *
+ * Description      Handle an API result event.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ag_api_result(tBTA_AG_DATA* p_data) {
+  tBTA_AG_SCB* p_scb;
+  int i;
+
+  if (p_data->hdr.layer_specific != BTA_AG_HANDLE_ALL) {
+    if ((p_scb = bta_ag_scb_by_idx(p_data->hdr.layer_specific)) != NULL) {
+      APPL_TRACE_DEBUG("bta_ag_api_result: p_scb 0x%08x ", p_scb);
+      bta_ag_sm_execute(p_scb, BTA_AG_API_RESULT_EVT, p_data);
+    }
+  } else {
+    for (i = 0, p_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, p_scb++) {
+      if (p_scb->in_use && p_scb->svc_conn) {
+        APPL_TRACE_DEBUG("bta_ag_api_result p_scb 0x%08x ", p_scb);
+        bta_ag_sm_execute(p_scb, BTA_AG_API_RESULT_EVT, p_data);
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_sm_execute
+ *
+ * Description      State machine event handling function for AG
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_sm_execute(tBTA_AG_SCB* p_scb, uint16_t event,
+                       tBTA_AG_DATA* p_data) {
+  tBTA_AG_ST_TBL state_table;
+  uint8_t action;
+  int i;
+
+#if (BTA_AG_DEBUG == TRUE)
+  uint16_t in_event = event;
+  uint8_t in_state = p_scb->state;
+
+  /* Ignore displaying of AT results when not connected (Ignored in state
+   * machine) */
+  if (in_event != BTA_AG_API_RESULT_EVT || p_scb->state == BTA_AG_OPEN_ST) {
+    APPL_TRACE_EVENT("AG evt (hdl 0x%04x): State %d (%s), Event 0x%04x (%s)",
+                     bta_ag_scb_to_idx(p_scb), p_scb->state,
+                     bta_ag_state_str(p_scb->state), event,
+                     bta_ag_evt_str(event, p_data->api_result.result));
+  }
+#else
+  APPL_TRACE_EVENT("AG evt (hdl 0x%04x): State %d, Event 0x%04x",
+                   bta_ag_scb_to_idx(p_scb), p_scb->state, event);
+#endif
+
+  event &= 0x00FF;
+  if (event >= (BTA_AG_MAX_EVT & 0x00FF)) {
+    APPL_TRACE_ERROR("AG evt out of range, ignoring...");
+    return;
+  }
+
+  /* look up the state table for the current state */
+  state_table = bta_ag_st_tbl[p_scb->state];
+
+  /* set next state */
+  p_scb->state = state_table[event][BTA_AG_NEXT_STATE];
+
+  /* execute action functions */
+  for (i = 0; i < BTA_AG_ACTIONS; i++) {
+    if ((action = state_table[event][i]) != BTA_AG_IGNORE) {
+      (*bta_ag_action[action])(p_scb, p_data);
+    } else {
+      break;
+    }
+  }
+#if (BTA_AG_DEBUG == TRUE)
+  if (p_scb->state != in_state) {
+    APPL_TRACE_EVENT("BTA AG State Change: [%s] -> [%s] after Event [%s]",
+                     bta_ag_state_str(in_state), bta_ag_state_str(p_scb->state),
+                     bta_ag_evt_str(in_event, p_data->api_result.result));
+  }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_hdl_event
+ *
+ * Description      Data gateway main event handling function.
+ *
+ *
+ * Returns          bool
+ *
+ ******************************************************************************/
+bool bta_ag_hdl_event(BT_HDR* p_msg) {
+  tBTA_AG_SCB* p_scb;
+
+  APPL_TRACE_DEBUG("bta_ag_hdl_event: Event 0x%04x ", p_msg->event);
+  switch (p_msg->event) {
+    /* handle enable event */
+    case BTA_AG_API_ENABLE_EVT:
+      bta_ag_api_enable((tBTA_AG_DATA*)p_msg);
+      break;
+
+    /* handle disable event */
+    case BTA_AG_API_DISABLE_EVT:
+      bta_ag_api_disable((tBTA_AG_DATA*)p_msg);
+      break;
+
+    /* handle register event */
+    case BTA_AG_API_REGISTER_EVT:
+      bta_ag_api_register((tBTA_AG_DATA*)p_msg);
+      break;
+
+    /* handle result event */
+    case BTA_AG_API_RESULT_EVT:
+      bta_ag_api_result((tBTA_AG_DATA*)p_msg);
+      break;
+
+    /* all others reference scb by handle */
+    default:
+      if ((p_scb = bta_ag_scb_by_idx(p_msg->layer_specific)) != NULL) {
+        APPL_TRACE_DEBUG("bta_ag_hdl_event: p_scb 0x%08x ", p_scb);
+        bta_ag_sm_execute(p_scb, p_msg->event, (tBTA_AG_DATA*)p_msg);
+      }
+      break;
+  }
+  return true;
+}
+
+#if (BTA_AG_DEBUG == TRUE)
+static char* bta_ag_evt_str(uint16_t event, tBTA_AG_RES result) {
+  switch (event) {
+    case BTA_AG_API_REGISTER_EVT:
+      return "Register Request";
+    case BTA_AG_API_DEREGISTER_EVT:
+      return "Deregister Request";
+    case BTA_AG_API_OPEN_EVT:
+      return "Open SLC Request";
+    case BTA_AG_API_CLOSE_EVT:
+      return "Close SLC Request";
+    case BTA_AG_API_AUDIO_OPEN_EVT:
+      return "Open Audio Request";
+    case BTA_AG_API_AUDIO_CLOSE_EVT:
+      return "Close Audio Request";
+    case BTA_AG_API_RESULT_EVT:
+      switch (result) {
+        case BTA_AG_SPK_RES:
+          return ("AT Result  BTA_AG_SPK_RES");
+        case BTA_AG_MIC_RES:
+          return ("AT Result  BTA_AG_MIC_RES");
+        case BTA_AG_INBAND_RING_RES:
+          return ("AT Result  BTA_AG_INBAND_RING_RES");
+        case BTA_AG_CIND_RES:
+          return ("AT Result  BTA_AG_CIND_RES");
+        case BTA_AG_BINP_RES:
+          return ("AT Result  BTA_AG_BINP_RES");
+        case BTA_AG_IND_RES:
+          return ("AT Result  BTA_AG_IND_RES");
+        case BTA_AG_BVRA_RES:
+          return ("AT Result  BTA_AG_BVRA_RES");
+        case BTA_AG_CNUM_RES:
+          return ("AT Result  BTA_AG_CNUM_RES");
+        case BTA_AG_BTRH_RES:
+          return ("AT Result  BTA_AG_BTRH_RES");
+        case BTA_AG_CLCC_RES:
+          return ("AT Result  BTA_AG_CLCC_RES");
+        case BTA_AG_COPS_RES:
+          return ("AT Result  BTA_AG_COPS_RES");
+        case BTA_AG_IN_CALL_RES:
+          return ("AT Result  BTA_AG_IN_CALL_RES");
+        case BTA_AG_IN_CALL_CONN_RES:
+          return ("AT Result  BTA_AG_IN_CALL_CONN_RES");
+        case BTA_AG_CALL_WAIT_RES:
+          return ("AT Result  BTA_AG_CALL_WAIT_RES");
+        case BTA_AG_OUT_CALL_ORIG_RES:
+          return ("AT Result  BTA_AG_OUT_CALL_ORIG_RES");
+        case BTA_AG_OUT_CALL_ALERT_RES:
+          return ("AT Result  BTA_AG_OUT_CALL_ALERT_RES");
+        case BTA_AG_OUT_CALL_CONN_RES:
+          return ("AT Result  BTA_AG_OUT_CALL_CONN_RES");
+        case BTA_AG_CALL_CANCEL_RES:
+          return ("AT Result  BTA_AG_CALL_CANCEL_RES");
+        case BTA_AG_END_CALL_RES:
+          return ("AT Result  BTA_AG_END_CALL_RES");
+        case BTA_AG_UNAT_RES:
+          return ("AT Result  BTA_AG_UNAT_RES");
+        default:
+          return ("Unknown AG Result");
+      }
+    case BTA_AG_API_SETCODEC_EVT:
+      return "Set Codec Request";
+    case BTA_AG_RFC_OPEN_EVT:
+      return "RFC Opened";
+    case BTA_AG_RFC_CLOSE_EVT:
+      return "RFC Closed";
+    case BTA_AG_RFC_SRV_CLOSE_EVT:
+      return "RFC SRV Closed";
+    case BTA_AG_RFC_DATA_EVT:
+      return "RFC Data";
+    case BTA_AG_SCO_OPEN_EVT:
+      return "Audio Opened";
+    case BTA_AG_SCO_CLOSE_EVT:
+      return "Audio Closed";
+    case BTA_AG_DISC_ACP_RES_EVT:
+      return "Discovery ACP Result";
+    case BTA_AG_DISC_INT_RES_EVT:
+      return "Discovery INT Result";
+    case BTA_AG_DISC_OK_EVT:
+      return "Discovery OK";
+    case BTA_AG_DISC_FAIL_EVT:
+      return "Discovery Failed";
+    case BTA_AG_CI_RX_WRITE_EVT:
+      return "CI RX Write";
+    case BTA_AG_RING_TIMEOUT_EVT:
+      return "Ring Timeout";
+    case BTA_AG_SVC_TIMEOUT_EVT:
+      return "Service Timeout";
+    case BTA_AG_API_ENABLE_EVT:
+      return "Enable AG";
+    case BTA_AG_API_DISABLE_EVT:
+      return "Disable AG";
+    case BTA_AG_CI_SCO_DATA_EVT:
+      return "SCO data Callin";
+    case BTA_AG_CI_SLC_READY_EVT:
+      return "SLC Ready Callin";
+    default:
+      return "Unknown AG Event";
+  }
+}
+
+static char* bta_ag_state_str(uint8_t state) {
+  switch (state) {
+    case BTA_AG_INIT_ST:
+      return "Initial";
+    case BTA_AG_OPENING_ST:
+      return "Opening";
+    case BTA_AG_OPEN_ST:
+      return "Open";
+    case BTA_AG_CLOSING_ST:
+      return "Closing";
+    default:
+      return "Unknown AG State";
+  }
+}
+
+#endif
diff --git a/bt/bta/ag/bta_ag_rfc.cc b/bt/bta/ag/bta_ag_rfc.cc
new file mode 100644
index 0000000..22be803
--- /dev/null
+++ b/bt/bta/ag/bta_ag_rfc.cc
@@ -0,0 +1,394 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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 audio gateway functions controlling the RFCOMM
+ *  connections.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_ag_api.h"
+#include "bta_ag_co.h"
+#include "bta_ag_int.h"
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+#include "rfcdefs.h"
+#include "utl.h"
+
+/* Event mask for RfCOMM port callback */
+#define BTA_AG_PORT_EV_MASK PORT_EV_RXCHAR
+
+/* each scb has its own rfcomm callbacks */
+void bta_ag_port_cback_1(uint32_t code, uint16_t port_handle);
+void bta_ag_port_cback_2(uint32_t code, uint16_t port_handle);
+void bta_ag_port_cback_3(uint32_t code, uint16_t port_handle);
+
+void bta_ag_mgmt_cback_1(uint32_t code, uint16_t port_handle);
+void bta_ag_mgmt_cback_2(uint32_t code, uint16_t port_handle);
+void bta_ag_mgmt_cback_3(uint32_t code, uint16_t port_handle);
+
+int bta_ag_data_cback_1(uint16_t port_handle, void* p_data, uint16_t len);
+int bta_ag_data_cback_2(uint16_t port_handle, void* p_data, uint16_t len);
+int bta_ag_data_cback_3(uint16_t port_handle, void* p_data, uint16_t len);
+
+/* rfcomm callback function tables */
+typedef tPORT_CALLBACK* tBTA_AG_PORT_CBACK;
+const tBTA_AG_PORT_CBACK bta_ag_port_cback_tbl[] = {
+    bta_ag_port_cback_1, bta_ag_port_cback_2, bta_ag_port_cback_3};
+
+const tBTA_AG_PORT_CBACK bta_ag_mgmt_cback_tbl[] = {
+    bta_ag_mgmt_cback_1, bta_ag_mgmt_cback_2, bta_ag_mgmt_cback_3};
+
+typedef tPORT_DATA_CALLBACK* tBTA_AG_DATA_CBACK;
+const tBTA_AG_DATA_CBACK bta_ag_data_cback_tbl[] = {
+    bta_ag_data_cback_1, bta_ag_data_cback_2, bta_ag_data_cback_3};
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_port_cback
+ *
+ * Description      RFCOMM Port callback
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ag_port_cback(UNUSED_ATTR uint32_t code, uint16_t port_handle,
+                              uint16_t handle) {
+  tBTA_AG_SCB* p_scb;
+
+  if ((p_scb = bta_ag_scb_by_idx(handle)) != NULL) {
+    /* ignore port events for port handles other than connected handle */
+    if (port_handle != p_scb->conn_handle) {
+      APPL_TRACE_DEBUG(
+          "ag_port_cback ignoring handle:%d conn_handle = %d other handle = %d",
+          port_handle, p_scb->conn_handle, handle);
+      return;
+    }
+
+    BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+    p_buf->event = BTA_AG_RFC_DATA_EVT;
+    p_buf->layer_specific = handle;
+    bta_sys_sendmsg(p_buf);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_mgmt_cback
+ *
+ * Description      RFCOMM management callback
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ag_mgmt_cback(uint32_t code, uint16_t port_handle,
+                              uint16_t handle) {
+  tBTA_AG_SCB* p_scb;
+  uint16_t event;
+  uint8_t i;
+  bool found_handle = false;
+
+  APPL_TRACE_DEBUG("ag_mgmt_cback : code = %d, port_handle = %d, handle = %d",
+                   code, port_handle, handle);
+
+  if ((p_scb = bta_ag_scb_by_idx(handle)) != NULL) {
+    /* ignore close event for port handles other than connected handle */
+    if ((code != PORT_SUCCESS) && (port_handle != p_scb->conn_handle)) {
+      APPL_TRACE_DEBUG("ag_mgmt_cback ignoring handle:%d", port_handle);
+      return;
+    }
+
+    if (code == PORT_SUCCESS) {
+      if (p_scb->conn_handle) /* Outgoing connection */
+      {
+        if (port_handle == p_scb->conn_handle) found_handle = true;
+      } else /* Incoming connection */
+      {
+        for (i = 0; i < BTA_AG_NUM_IDX; i++) {
+          if (port_handle == p_scb->serv_handle[i]) found_handle = true;
+        }
+      }
+
+      if (!found_handle) {
+        APPL_TRACE_ERROR(
+            "bta_ag_mgmt_cback: PORT_SUCCESS, ignoring handle = %d",
+            port_handle);
+        return;
+      }
+
+      event = BTA_AG_RFC_OPEN_EVT;
+    }
+    /* distinguish server close events */
+    else if (port_handle == p_scb->conn_handle) {
+      event = BTA_AG_RFC_CLOSE_EVT;
+    } else {
+      event = BTA_AG_RFC_SRV_CLOSE_EVT;
+    }
+
+    tBTA_AG_RFC* p_buf = (tBTA_AG_RFC*)osi_malloc(sizeof(tBTA_AG_RFC));
+    p_buf->hdr.event = event;
+    p_buf->hdr.layer_specific = handle;
+    p_buf->port_handle = port_handle;
+    bta_sys_sendmsg(p_buf);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_data_cback
+ *
+ * Description      RFCOMM data callback
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static int bta_ag_data_cback(UNUSED_ATTR uint16_t port_handle, void* p_data,
+                             uint16_t len, uint16_t handle) {
+  /* call data call-out directly */
+  bta_ag_co_tx_write(handle, (uint8_t*)p_data, len);
+  return 0;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_port_cback_1 to 3
+ *                  bta_ag_mgmt_cback_1 to 3
+ *
+ * Description      RFCOMM callback functions.  This is an easy way to
+ *                  distinguish scb from the callback.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_mgmt_cback_1(uint32_t code, uint16_t handle) {
+  bta_ag_mgmt_cback(code, handle, 1);
+}
+void bta_ag_mgmt_cback_2(uint32_t code, uint16_t handle) {
+  bta_ag_mgmt_cback(code, handle, 2);
+}
+void bta_ag_mgmt_cback_3(uint32_t code, uint16_t handle) {
+  bta_ag_mgmt_cback(code, handle, 3);
+}
+void bta_ag_port_cback_1(uint32_t code, uint16_t handle) {
+  bta_ag_port_cback(code, handle, 1);
+}
+void bta_ag_port_cback_2(uint32_t code, uint16_t handle) {
+  bta_ag_port_cback(code, handle, 2);
+}
+void bta_ag_port_cback_3(uint32_t code, uint16_t handle) {
+  bta_ag_port_cback(code, handle, 3);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_data_cback_1 to 3
+ *
+ * Description      RFCOMM data callback functions.  This is an easy way to
+ *                  distinguish scb from the callback.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+int bta_ag_data_cback_1(uint16_t port_handle, void* p_data, uint16_t len) {
+  return bta_ag_data_cback(port_handle, p_data, len, 1);
+}
+int bta_ag_data_cback_2(uint16_t port_handle, void* p_data, uint16_t len) {
+  return bta_ag_data_cback(port_handle, p_data, len, 2);
+}
+int bta_ag_data_cback_3(uint16_t port_handle, void* p_data, uint16_t len) {
+  return bta_ag_data_cback(port_handle, p_data, len, 3);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_setup_port
+ *
+ * Description      Setup RFCOMM port for use by AG.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_setup_port(tBTA_AG_SCB* p_scb, uint16_t handle) {
+  uint16_t i = bta_ag_scb_to_idx(p_scb) - 1;
+
+  /* set up data callback if using pass through mode */
+  if (bta_ag_cb.parse_mode == BTA_AG_PASS_THROUGH) {
+    PORT_SetDataCallback(handle, bta_ag_data_cback_tbl[i]);
+  }
+
+  PORT_SetEventMask(handle, BTA_AG_PORT_EV_MASK);
+  PORT_SetEventCallback(handle, bta_ag_port_cback_tbl[i]);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_start_servers
+ *
+ * Description      Setup RFCOMM servers for use by AG.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_start_servers(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK services) {
+  int i;
+  int bta_ag_port_status;
+
+  services >>= BTA_HSP_SERVICE_ID;
+  for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) {
+    /* if service is set in mask */
+    if (services & 1) {
+      BTM_SetSecurityLevel(false, "", bta_ag_sec_id[i], p_scb->serv_sec_mask,
+                           BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM,
+                           bta_ag_cb.profile[i].scn);
+
+      bta_ag_port_status = RFCOMM_CreateConnection(
+          bta_ag_uuid[i], bta_ag_cb.profile[i].scn, true, BTA_AG_MTU,
+          (uint8_t*)bd_addr_any, &(p_scb->serv_handle[i]),
+          bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]);
+
+      if (bta_ag_port_status == PORT_SUCCESS) {
+        bta_ag_setup_port(p_scb, p_scb->serv_handle[i]);
+      } else {
+        /* TODO: CR#137125 to handle to error properly */
+        APPL_TRACE_DEBUG(
+            "bta_ag_start_servers: RFCOMM_CreateConnection returned error:%d",
+            bta_ag_port_status);
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_close_servers
+ *
+ * Description      Close RFCOMM servers port for use by AG.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_close_servers(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK services) {
+  int i;
+
+  services >>= BTA_HSP_SERVICE_ID;
+  for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) {
+    /* if service is set in mask */
+    if (services & 1) {
+      RFCOMM_RemoveServer(p_scb->serv_handle[i]);
+      p_scb->serv_handle[i] = 0;
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_is_server_closed
+ *
+ * Description      Returns true if all servers are closed.
+ *
+ *
+ * Returns          true if all servers are closed, false otherwise
+ *
+ ******************************************************************************/
+bool bta_ag_is_server_closed(tBTA_AG_SCB* p_scb) {
+  uint8_t xx;
+  bool is_closed = true;
+
+  for (xx = 0; xx < BTA_AG_NUM_IDX; xx++) {
+    if (p_scb->serv_handle[xx] != 0) is_closed = false;
+  }
+
+  return is_closed;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_rfc_do_open
+ *
+ * Description      Open an RFCOMM connection to the peer device.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_rfc_do_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+  BTM_SetSecurityLevel(true, "", bta_ag_sec_id[p_scb->conn_service],
+                       p_scb->cli_sec_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM,
+                       p_scb->peer_scn);
+
+  if (RFCOMM_CreateConnection(
+          bta_ag_uuid[p_scb->conn_service], p_scb->peer_scn, false, BTA_AG_MTU,
+          p_scb->peer_addr, &(p_scb->conn_handle),
+          bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]) ==
+      PORT_SUCCESS) {
+    bta_ag_setup_port(p_scb, p_scb->conn_handle);
+    APPL_TRACE_DEBUG("bta_ag_rfc_do_open : conn_handle = %d",
+                     p_scb->conn_handle);
+  }
+  /* RFCOMM create connection failed; send ourselves RFCOMM close event */
+  else {
+    bta_ag_sm_execute(p_scb, BTA_AG_RFC_CLOSE_EVT, p_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_rfc_do_close
+ *
+ * Description      Close RFCOMM connection.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_rfc_do_close(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+  if (p_scb->conn_handle) {
+    RFCOMM_RemoveConnection(p_scb->conn_handle);
+  } else {
+    /* Close API was called while AG is in Opening state.               */
+    /* Need to trigger the state machine to send callback to the app    */
+    /* and move back to INIT state.                                     */
+    tBTA_AG_RFC* p_buf = (tBTA_AG_RFC*)osi_malloc(sizeof(tBTA_AG_RFC));
+    p_buf->hdr.event = BTA_AG_RFC_CLOSE_EVT;
+    p_buf->hdr.layer_specific = bta_ag_scb_to_idx(p_scb);
+    bta_sys_sendmsg(p_buf);
+
+    /* Cancel SDP if it had been started. */
+    /*
+    if(p_scb->p_disc_db)
+    {
+        (void)SDP_CancelServiceSearch (p_scb->p_disc_db);
+    }
+    */
+  }
+}
diff --git a/bt/bta/ag/bta_ag_sco.cc b/bt/bta/ag/bta_ag_sco.cc
new file mode 100644
index 0000000..5ff5900
--- /dev/null
+++ b/bt/bta/ag/bta_ag_sco.cc
@@ -0,0 +1,1631 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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 functions for managing the SCO connection used in AG.
+ *
+ ******************************************************************************/
+
+#include <stddef.h>
+
+#include "bta_ag_api.h"
+#include "bta_ag_co.h"
+#include "bta_api.h"
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+#include "bta_dm_co.h"
+#endif
+#include "bt_common.h"
+#include "bta_ag_int.h"
+#include "btm_api.h"
+#include "osi/include/osi.h"
+#include "utl.h"
+
+#ifndef BTA_AG_SCO_DEBUG
+#define BTA_AG_SCO_DEBUG FALSE
+#endif
+
+/* Codec negotiation timeout */
+#ifndef BTA_AG_CODEC_NEGOTIATION_TIMEOUT_MS
+#define BTA_AG_CODEC_NEGOTIATION_TIMEOUT_MS (3 * 1000) /* 3 seconds */
+#endif
+
+extern fixed_queue_t* btu_bta_alarm_queue;
+
+#if (BTA_AG_SCO_DEBUG == TRUE)
+static char* bta_ag_sco_evt_str(uint8_t event);
+static char* bta_ag_sco_state_str(uint8_t state);
+#endif
+
+#define BTA_AG_NO_EDR_ESCO                                             \
+  (BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 | BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | \
+   BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | BTM_SCO_PKT_TYPES_MASK_NO_3_EV5)
+
+/* sco events */
+enum {
+  BTA_AG_SCO_LISTEN_E, /* listen request */
+  BTA_AG_SCO_OPEN_E,   /* open request */
+  BTA_AG_SCO_XFER_E,   /* transfer request */
+#if (BTM_WBS_INCLUDED == TRUE)
+  BTA_AG_SCO_CN_DONE_E, /* codec negotiation done */
+  BTA_AG_SCO_REOPEN_E,  /* Retry with other codec when failed */
+#endif
+  BTA_AG_SCO_CLOSE_E,      /* close request */
+  BTA_AG_SCO_SHUTDOWN_E,   /* shutdown request */
+  BTA_AG_SCO_CONN_OPEN_E,  /* sco open */
+  BTA_AG_SCO_CONN_CLOSE_E, /* sco closed */
+  BTA_AG_SCO_CI_DATA_E     /* SCO data ready */
+};
+
+#if (BTM_WBS_INCLUDED == TRUE)
+#define BTA_AG_NUM_CODECS 3
+#define BTA_AG_ESCO_SETTING_IDX_CVSD 0 /* eSCO setting for CVSD */
+#define BTA_AG_ESCO_SETTING_IDX_T1 1   /* eSCO setting for mSBC T1 */
+#define BTA_AG_ESCO_SETTING_IDX_T2 2   /* eSCO setting for mSBC T2 */
+
+static const tBTM_ESCO_PARAMS bta_ag_esco_params[BTA_AG_NUM_CODECS] = {
+    /* CVSD */
+    {
+        BTM_64KBITS_RATE,       /* TX Bandwidth (64 kbits/sec)              */
+        BTM_64KBITS_RATE,       /* RX Bandwidth (64 kbits/sec)              */
+        0x000c,                 /* 12 ms (HS/HF can use EV3, 2-EV3, 3-EV3)  */
+        BTM_VOICE_SETTING_CVSD, /* Inp Linear, Air CVSD, 2s Comp, 16bit     */
+        (BTM_SCO_PKT_TYPES_MASK_HV1 + /* Packet Types */
+         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_PKT_TYPES_MASK_NO_2_EV5 +
+         BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+        BTM_ESCO_RETRANS_QUALITY /* Retransmission effort                    */
+    },
+    /* mSBC  T1 */
+    {
+        BTM_64KBITS_RATE,        /* TX Bandwidth (64 kbits/sec), 8000        */
+        BTM_64KBITS_RATE,        /* RX Bandwidth (64 kbits/sec), 8000        */
+        8,                       /* 8 ms                                     */
+        BTM_VOICE_SETTING_TRANS, /* Inp Linear, Transparent, 2s Comp, 16bit  */
+        (BTM_SCO_PKT_TYPES_MASK_EV3 | /* Packet Types : EV3 + NO_2_EV3 */
+         BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+         BTM_SCO_PKT_TYPES_MASK_NO_3_EV5 | BTM_SCO_PKT_TYPES_MASK_NO_2_EV3),
+        BTM_ESCO_RETRANS_QUALITY /* Retransmission effort */
+    },
+    /* mSBC T2*/
+    {
+        BTM_64KBITS_RATE,        /* TX Bandwidth (64 kbits/sec), 8000        */
+        BTM_64KBITS_RATE,        /* RX Bandwidth (64 kbits/sec), 8000        */
+        13,                      /* 13 ms                                    */
+        BTM_VOICE_SETTING_TRANS, /* Inp Linear, Transparent, 2s Comp, 16bit  */
+        (BTM_SCO_PKT_TYPES_MASK_EV3 | /* Packet Types : EV3 + 2-EV3 */
+         BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+         BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+        BTM_ESCO_RETRANS_QUALITY /* Retransmission effort */
+    }};
+#else
+/* WBS not included, CVSD by default */
+static const tBTM_ESCO_PARAMS bta_ag_esco_params = {
+    BTM_64KBITS_RATE,             /* TX Bandwidth (64 kbits/sec)              */
+    BTM_64KBITS_RATE,             /* RX Bandwidth (64 kbits/sec)              */
+    0x000a,                       /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3)  */
+    0x0060,                       /* Inp Linear, Air CVSD, 2s Comp, 16bit     */
+    (BTM_SCO_PKT_TYPES_MASK_HV1 + /* Packet Types                             */
+     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_PKT_TYPES_MASK_NO_2_EV5 +
+     BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+    BTM_ESCO_RETRANS_POWER /* Retransmission effort                      */
+};
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_sco_conn_cback
+ *
+ * Description      BTM SCO connection callback.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ag_sco_conn_cback(uint16_t sco_idx) {
+  uint16_t handle;
+  tBTA_AG_SCB* p_scb;
+
+  /* match callback to scb; first check current sco scb */
+  if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb->in_use) {
+    handle = bta_ag_scb_to_idx(bta_ag_cb.sco.p_curr_scb);
+  }
+  /* then check for scb connected to this peer */
+  else {
+    /* Check if SLC is up */
+    handle = bta_ag_idx_by_bdaddr(BTM_ReadScoBdAddr(sco_idx));
+    p_scb = bta_ag_scb_by_idx(handle);
+    if (p_scb && !p_scb->svc_conn) handle = 0;
+  }
+
+  if (handle != 0) {
+    BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+    p_buf->event = BTA_AG_SCO_OPEN_EVT;
+    p_buf->layer_specific = handle;
+    bta_sys_sendmsg(p_buf);
+  } else {
+    /* no match found; disconnect sco, init sco variables */
+    bta_ag_cb.sco.p_curr_scb = NULL;
+    bta_ag_cb.sco.state = BTA_AG_SCO_SHUTDOWN_ST;
+    BTM_RemoveSco(sco_idx);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_sco_disc_cback
+ *
+ * Description      BTM SCO disconnection callback.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ag_sco_disc_cback(uint16_t sco_idx) {
+  uint16_t handle = 0;
+
+  APPL_TRACE_DEBUG(
+      "bta_ag_sco_disc_cback(): sco_idx: 0x%x  p_cur_scb: 0x%08x  sco.state: "
+      "%d",
+      sco_idx, bta_ag_cb.sco.p_curr_scb, bta_ag_cb.sco.state);
+
+  APPL_TRACE_DEBUG(
+      "bta_ag_sco_disc_cback(): scb[0] addr: 0x%08x  in_use: %u  sco_idx: 0x%x "
+      " sco state: %u",
+      &bta_ag_cb.scb[0], bta_ag_cb.scb[0].in_use, bta_ag_cb.scb[0].sco_idx,
+      bta_ag_cb.scb[0].state);
+  APPL_TRACE_DEBUG(
+      "bta_ag_sco_disc_cback(): scb[1] addr: 0x%08x  in_use: %u  sco_idx: 0x%x "
+      " sco state: %u",
+      &bta_ag_cb.scb[1], bta_ag_cb.scb[1].in_use, bta_ag_cb.scb[1].sco_idx,
+      bta_ag_cb.scb[1].state);
+
+  /* match callback to scb */
+  if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb->in_use) {
+    /* We only care about callbacks for the active SCO */
+    if (bta_ag_cb.sco.p_curr_scb->sco_idx != sco_idx) {
+      if (bta_ag_cb.sco.p_curr_scb->sco_idx != 0xFFFF) return;
+    }
+    handle = bta_ag_scb_to_idx(bta_ag_cb.sco.p_curr_scb);
+  }
+
+  if (handle != 0) {
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+    tBTM_STATUS status = BTM_ConfigScoPath(BTM_SCO_ROUTE_PCM, NULL, NULL, true);
+    APPL_TRACE_DEBUG("bta_ag_sco_disc_cback sco close config status = %d",
+                     status);
+    /* SCO clean up here */
+    bta_dm_sco_co_close();
+#endif
+
+#if (BTM_WBS_INCLUDED == TRUE)
+    /* Restore settings */
+    if (bta_ag_cb.sco.p_curr_scb->inuse_codec == BTA_AG_CODEC_MSBC) {
+      /* set_sco_codec(BTM_SCO_CODEC_NONE); we should get a close */
+      BTM_WriteVoiceSettings(BTM_VOICE_SETTING_CVSD);
+
+      /* If SCO open was initiated by AG and failed for mSBC, then attempt
+      mSBC with T1 settings i.e. 'Safe Settings'. If this fails, then switch to
+      CVSD */
+      if (bta_ag_sco_is_opening(bta_ag_cb.sco.p_curr_scb)) {
+        if (bta_ag_cb.sco.p_curr_scb->codec_msbc_settings ==
+            BTA_AG_SCO_MSBC_SETTINGS_T2) {
+          APPL_TRACE_DEBUG("Fallback to mSBC T1 settings");
+          bta_ag_cb.sco.p_curr_scb->codec_msbc_settings =
+              BTA_AG_SCO_MSBC_SETTINGS_T1;
+        } else {
+          APPL_TRACE_DEBUG("Fallback to CVSD settings");
+          bta_ag_cb.sco.p_curr_scb->codec_fallback = true;
+        }
+      }
+    }
+
+    bta_ag_cb.sco.p_curr_scb->inuse_codec = BTA_AG_CODEC_NONE;
+#endif
+
+    BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+    p_buf->event = BTA_AG_SCO_CLOSE_EVT;
+    p_buf->layer_specific = handle;
+    bta_sys_sendmsg(p_buf);
+  } else {
+    /* no match found */
+    APPL_TRACE_DEBUG("no scb for ag_sco_disc_cback");
+
+    /* sco could be closed after scb dealloc'ed */
+    if (bta_ag_cb.sco.p_curr_scb != NULL) {
+      bta_ag_cb.sco.p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+      bta_ag_cb.sco.p_curr_scb = NULL;
+      bta_ag_cb.sco.state = BTA_AG_SCO_SHUTDOWN_ST;
+    }
+  }
+}
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_ag_sco_read_cback
+ *
+ * Description      Callback function is the callback function for incoming
+ *                  SCO data over HCI.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ag_sco_read_cback(uint16_t sco_inx, BT_HDR* p_data,
+                                  tBTM_SCO_DATA_FLAG status) {
+  if (status != BTM_SCO_DATA_CORRECT) {
+    APPL_TRACE_DEBUG("bta_ag_sco_read_cback: status(%d)", status);
+  }
+
+  /* Callout function must free the data. */
+  bta_dm_sco_co_in_data(p_data, status);
+}
+#endif
+/*******************************************************************************
+ *
+ * Function         bta_ag_remove_sco
+ *
+ * Description      Removes the specified SCO from the system.
+ *                  If only_active is true, then SCO is only removed if
+ *                  connected
+ *
+ * Returns          bool   - true if Sco removal was started
+ *
+ ******************************************************************************/
+static bool bta_ag_remove_sco(tBTA_AG_SCB* p_scb, bool only_active) {
+  bool removed_started = false;
+  tBTM_STATUS status;
+
+  if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX) {
+    if (!only_active || p_scb->sco_idx == bta_ag_cb.sco.cur_idx) {
+      status = BTM_RemoveSco(p_scb->sco_idx);
+
+      APPL_TRACE_DEBUG("ag remove sco: inx 0x%04x, status:0x%x", p_scb->sco_idx,
+                       status);
+
+      if (status == BTM_CMD_STARTED) {
+        /* Sco is connected; set current control block */
+        bta_ag_cb.sco.p_curr_scb = p_scb;
+
+        removed_started = true;
+      }
+      /* If no connection reset the sco handle */
+      else if ((status == BTM_SUCCESS) || (status == BTM_UNKNOWN_ADDR)) {
+        p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+      }
+    }
+  }
+  return removed_started;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_esco_connreq_cback
+ *
+ * Description      BTM eSCO connection requests and eSCO change requests
+ *                  Only the connection requests are processed by BTA.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ag_esco_connreq_cback(tBTM_ESCO_EVT event,
+                                      tBTM_ESCO_EVT_DATA* p_data) {
+  tBTA_AG_SCB* p_scb;
+  uint16_t handle;
+  uint16_t sco_inx = p_data->conn_evt.sco_inx;
+
+  /* Only process connection requests */
+  if (event == BTM_ESCO_CONN_REQ_EVT) {
+    if ((handle = bta_ag_idx_by_bdaddr(BTM_ReadScoBdAddr(sco_inx))) != 0 &&
+        ((p_scb = bta_ag_scb_by_idx(handle)) != NULL) && p_scb->svc_conn) {
+      p_scb->sco_idx = sco_inx;
+
+      /* If no other SCO active, allow this one */
+      if (!bta_ag_cb.sco.p_curr_scb) {
+        APPL_TRACE_EVENT(
+            "bta_ag_esco_connreq_cback: Accept Conn Request (sco_inx 0x%04x)",
+            sco_inx);
+        bta_ag_sco_conn_rsp(p_scb, &p_data->conn_evt);
+
+        bta_ag_cb.sco.state = BTA_AG_SCO_OPENING_ST;
+        bta_ag_cb.sco.p_curr_scb = p_scb;
+        bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
+      } else /* Begin a transfer: Close current SCO before responding */
+      {
+        APPL_TRACE_DEBUG("bta_ag_esco_connreq_cback: Begin XFER");
+        bta_ag_cb.sco.p_xfer_scb = p_scb;
+        bta_ag_cb.sco.conn_data = p_data->conn_evt;
+        bta_ag_cb.sco.state = BTA_AG_SCO_OPEN_XFER_ST;
+
+        if (!bta_ag_remove_sco(bta_ag_cb.sco.p_curr_scb, true)) {
+          APPL_TRACE_ERROR(
+              "bta_ag_esco_connreq_cback: Nothing to remove so accept Conn "
+              "Request (sco_inx 0x%04x)",
+              sco_inx);
+          bta_ag_cb.sco.p_xfer_scb = NULL;
+          bta_ag_cb.sco.state = BTA_AG_SCO_LISTEN_ST;
+
+          bta_ag_sco_conn_rsp(p_scb, &p_data->conn_evt);
+        }
+      }
+    }
+    /* If error occurred send reject response immediately */
+    else {
+      APPL_TRACE_WARNING(
+          "no scb for bta_ag_esco_connreq_cback or no resources");
+      BTM_EScoConnRsp(p_data->conn_evt.sco_inx, HCI_ERR_HOST_REJECT_RESOURCES,
+                      NULL);
+    }
+  }
+  /* Received a change in the esco link */
+  else if (event == BTM_ESCO_CHG_EVT) {
+    APPL_TRACE_EVENT(
+        "eSCO change event (inx %d): rtrans %d, rxlen %d, txlen %d, txint %d",
+        p_data->chg_evt.sco_inx, p_data->chg_evt.retrans_window,
+        p_data->chg_evt.rx_pkt_len, p_data->chg_evt.tx_pkt_len,
+        p_data->chg_evt.tx_interval);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_cback_sco
+ *
+ * Description      Call application callback function with SCO event.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ag_cback_sco(tBTA_AG_SCB* p_scb, uint8_t event) {
+  tBTA_AG_HDR sco;
+
+  sco.handle = bta_ag_scb_to_idx(p_scb);
+  sco.app_id = p_scb->app_id;
+
+  /* call close cback */
+  (*bta_ag_cb.p_cback)(event, (tBTA_AG*)&sco);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_create_sco
+ *
+ * Description
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ag_create_sco(tBTA_AG_SCB* p_scb, bool is_orig) {
+  tBTM_STATUS status;
+  uint8_t* p_bd_addr = NULL;
+  tBTM_ESCO_PARAMS params;
+#if (BTM_WBS_INCLUDED == TRUE)
+  tBTA_AG_PEER_CODEC esco_codec = BTM_SCO_CODEC_CVSD;
+  int codec_index = 0;
+#endif
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+  tBTM_SCO_ROUTE_TYPE sco_route;
+  tBTA_CODEC_INFO codec_info = {BTA_SCO_CODEC_PCM};
+  uint32_t pcm_sample_rate;
+#endif
+
+  /* Make sure this sco handle is not already in use */
+  if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX) {
+    APPL_TRACE_WARNING("bta_ag_create_sco: Index 0x%04x Already In Use!",
+                       p_scb->sco_idx);
+    return;
+  }
+
+#if (BTM_WBS_INCLUDED == TRUE)
+  if ((p_scb->sco_codec == BTM_SCO_CODEC_MSBC) && !p_scb->codec_fallback &&
+      !p_scb->retry_with_sco_only)
+    esco_codec = BTM_SCO_CODEC_MSBC;
+
+  if (p_scb->codec_fallback) {
+    p_scb->codec_fallback = false;
+
+    /* Force AG to send +BCS for the next audio connection. */
+    p_scb->codec_updated = true;
+  }
+
+  /* If WBS included, use CVSD by default, index is 0 for CVSD by initialization
+   */
+  /* If eSCO codec is mSBC, index is T2 or T1 */
+  if (esco_codec == BTM_SCO_CODEC_MSBC) {
+    if (p_scb->codec_msbc_settings == BTA_AG_SCO_MSBC_SETTINGS_T2) {
+      codec_index = BTA_AG_ESCO_SETTING_IDX_T2;
+    } else {
+      codec_index = BTA_AG_ESCO_SETTING_IDX_T1;
+    }
+  }
+
+  params = bta_ag_esco_params[codec_index];
+#else
+  /* When WBS is not included, use CVSD by default */
+  params = bta_ag_esco_params;
+#endif
+
+  if (bta_ag_cb.sco.param_updated) /* If we do not use the default parameters */
+    params = bta_ag_cb.sco.params;
+
+  if (!bta_ag_cb.sco.param_updated) {
+#if (BTM_WBS_INCLUDED == TRUE)
+    if (esco_codec == BTM_SCO_CODEC_CVSD) /* For CVSD */
+#endif
+    {
+      /* Use the application packet types (5 slot EV packets not allowed) */
+      params.packet_types = p_bta_ag_cfg->sco_pkt_types |
+                            BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+                            BTM_SCO_PKT_TYPES_MASK_NO_3_EV5;
+    }
+  }
+
+  /* if initiating set current scb and peer bd addr */
+  if (is_orig) {
+    /* Attempt to use eSCO if remote host supports HFP >= 1.5 */
+    /* Need to find out from SIG if HSP can use eSCO; for now use SCO */
+    if (p_scb->conn_service == BTA_AG_HFP &&
+        p_scb->peer_version >= HFP_VERSION_1_5 && !p_scb->retry_with_sco_only) {
+      BTM_SetEScoMode(BTM_LINK_TYPE_ESCO, &params);
+      /* If ESCO or EDR ESCO, retry with SCO only in case of failure */
+      if ((params.packet_types & BTM_ESCO_LINK_ONLY_MASK) ||
+          !((params.packet_types &
+             ~(BTM_ESCO_LINK_ONLY_MASK | BTM_SCO_LINK_ONLY_MASK)) ^
+            BTA_AG_NO_EDR_ESCO)) {
+#if (BTM_WBS_INCLUDED == TRUE)
+        if (esco_codec != BTA_AG_CODEC_MSBC) {
+          p_scb->retry_with_sco_only = true;
+          APPL_TRACE_API("Setting retry_with_sco_only to true");
+        } else /* Do not use SCO when using mSBC */
+        {
+          p_scb->retry_with_sco_only = false;
+          APPL_TRACE_API("Setting retry_with_sco_only to false");
+        }
+#else
+        p_scb->retry_with_sco_only = true;
+        APPL_TRACE_API("Setting retry_with_sco_only to true");
+#endif
+      }
+    } else {
+      if (p_scb->retry_with_sco_only) APPL_TRACE_API("retrying with SCO only");
+      p_scb->retry_with_sco_only = false;
+
+      BTM_SetEScoMode(BTM_LINK_TYPE_SCO, &params);
+    }
+
+    bta_ag_cb.sco.p_curr_scb = p_scb;
+
+    /* tell sys to stop av if any */
+    bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+#if (BTM_WBS_INCLUDED == TRUE)
+    /* Allow any platform specific pre-SCO set up to take place */
+    bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id,
+                          SCO_STATE_SETUP, esco_codec);
+
+    /* This setting may not be necessary */
+    /* To be verified with stable 2049 boards */
+    if (esco_codec == BTA_AG_CODEC_MSBC)
+      BTM_WriteVoiceSettings(BTM_VOICE_SETTING_TRANS);
+    else
+      BTM_WriteVoiceSettings(BTM_VOICE_SETTING_CVSD);
+    /* save the current codec because sco_codec can be updated while SCO is
+     * open. */
+    p_scb->inuse_codec = esco_codec;
+#else
+    /* Allow any platform specific pre-SCO set up to take place */
+    bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id,
+                          SCO_STATE_SETUP);
+#endif
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+#if (BTM_WBS_INCLUDED == TRUE)
+    if (esco_codec == BTA_AG_CODEC_MSBC)
+      pcm_sample_rate = BTA_DM_SCO_SAMP_RATE_16K;
+    else
+#endif
+      pcm_sample_rate = BTA_DM_SCO_SAMP_RATE_8K;
+
+    sco_route = bta_dm_sco_co_init(pcm_sample_rate, pcm_sample_rate,
+                                   &codec_info, p_scb->app_id);
+#endif
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+    /* initialize SCO setup, no voice setting for AG, data rate <==> sample rate
+     */
+    BTM_ConfigScoPath(sco_route, bta_ag_sco_read_cback, NULL, true);
+#endif
+    bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
+  } else
+    p_scb->retry_with_sco_only = false;
+
+  p_bd_addr = p_scb->peer_addr;
+
+  status =
+      BTM_CreateSco(p_bd_addr, is_orig, params.packet_types, &p_scb->sco_idx,
+                    bta_ag_sco_conn_cback, bta_ag_sco_disc_cback);
+  if (status == BTM_CMD_STARTED) {
+    if (!is_orig) {
+      BTM_RegForEScoEvts(p_scb->sco_idx, bta_ag_esco_connreq_cback);
+    } else /* Initiating the connection, set the current sco handle */
+    {
+      bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
+    }
+  }
+
+  APPL_TRACE_API(
+      "ag create sco: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x",
+      is_orig, p_scb->sco_idx, status, params.packet_types);
+}
+
+#if (BTM_WBS_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_ag_attempt_msbc_safe_settings
+ *
+ * Description    Checks if ESCO connection needs to be attempted using mSBC
+ *                T1(safe) settings
+ *
+ *
+ * Returns          true if T1 settings has to be used, false otherwise
+ *
+ ******************************************************************************/
+bool bta_ag_attempt_msbc_safe_settings(tBTA_AG_SCB* p_scb) {
+  if (p_scb->svc_conn && p_scb->sco_codec == BTM_SCO_CODEC_MSBC &&
+      p_scb->codec_msbc_settings == BTA_AG_SCO_MSBC_SETTINGS_T1)
+    return true;
+  else
+    return false;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_codec_negotiation_timer_cback
+ *
+ * Description
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ag_codec_negotiation_timer_cback(void* data) {
+  tBTA_AG_SCB* p_scb = (tBTA_AG_SCB*)data;
+
+  /* Announce that codec negotiation failed. */
+  bta_ag_sco_codec_nego(p_scb, false);
+
+  /* call app callback */
+  bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_CLOSE_EVT);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_codec_negotiate
+ *
+ * Description      Initiate codec negotiation by sending AT command.
+ *                  If not necessary, skip negotiation.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_codec_negotiate(tBTA_AG_SCB* p_scb) {
+  bta_ag_cb.sco.p_curr_scb = p_scb;
+
+  if ((p_scb->codec_updated || p_scb->codec_fallback ||
+       bta_ag_attempt_msbc_safe_settings(p_scb)) &&
+      (p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC)) {
+    /* Change the power mode to Active until sco open is completed. */
+    bta_sys_busy(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+    /* Send +BCS to the peer */
+    bta_ag_send_bcs(p_scb, NULL);
+
+    /* Start timer to handle timeout */
+    alarm_set_on_queue(
+        p_scb->codec_negotiation_timer, BTA_AG_CODEC_NEGOTIATION_TIMEOUT_MS,
+        bta_ag_codec_negotiation_timer_cback, p_scb, btu_bta_alarm_queue);
+  } else {
+    /* use same codec type as previous SCO connection, skip codec negotiation */
+    APPL_TRACE_DEBUG(
+        "use same codec type as previous SCO connection,skip codec "
+        "negotiation");
+    bta_ag_sco_codec_nego(p_scb, true);
+  }
+}
+#endif /* (BTM_WBS_INCLUDED == TRUE) */
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_sco_event
+ *
+ * Description
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ag_sco_event(tBTA_AG_SCB* p_scb, uint8_t event) {
+  tBTA_AG_SCO_CB* p_sco = &bta_ag_cb.sco;
+#if (BTM_WBS_INCLUDED == TRUE)
+  tBTA_AG_SCB* p_cn_scb = NULL; /* For codec negotiation */
+#endif
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+  BT_HDR* p_buf;
+#endif
+#if (BTA_AG_SCO_DEBUG == TRUE)
+  uint8_t in_state = p_sco->state;
+
+  APPL_TRACE_EVENT("BTA ag sco evt (hdl 0x%04x): State %d (%s), Event %d (%s)",
+                   p_scb->sco_idx, p_sco->state,
+                   bta_ag_sco_state_str(p_sco->state), event,
+                   bta_ag_sco_evt_str(event));
+#else
+  APPL_TRACE_EVENT("BTA ag sco evt (hdl 0x%04x): State %d, Event %d",
+                   p_scb->sco_idx, p_sco->state, event);
+#endif
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+  if (event == BTA_AG_SCO_CI_DATA_E) {
+    while (true) {
+      bta_dm_sco_co_out_data(&p_buf);
+      if (p_buf) {
+        if (p_sco->state == BTA_AG_SCO_OPEN_ST)
+          BTM_WriteScoData(p_sco->p_curr_scb->sco_idx, p_buf);
+        else
+          osi_free(p_buf);
+      } else
+        break;
+    }
+
+    return;
+  }
+#endif
+
+  switch (p_sco->state) {
+    case BTA_AG_SCO_SHUTDOWN_ST:
+      switch (event) {
+        case BTA_AG_SCO_LISTEN_E:
+          /* create sco listen connection */
+          bta_ag_create_sco(p_scb, false);
+          p_sco->state = BTA_AG_SCO_LISTEN_ST;
+          break;
+
+        default:
+          APPL_TRACE_WARNING("BTA_AG_SCO_SHUTDOWN_ST: Ignoring event %d",
+                             event);
+          break;
+      }
+      break;
+
+    case BTA_AG_SCO_LISTEN_ST:
+      switch (event) {
+        case BTA_AG_SCO_LISTEN_E:
+          /* create sco listen connection (Additional channel) */
+          bta_ag_create_sco(p_scb, false);
+          break;
+
+        case BTA_AG_SCO_OPEN_E:
+          /* remove listening connection */
+          bta_ag_remove_sco(p_scb, false);
+
+#if (BTM_WBS_INCLUDED == TRUE)
+          /* start codec negotiation */
+          p_sco->state = BTA_AG_SCO_CODEC_ST;
+          p_cn_scb = p_scb;
+#else
+          /* create sco connection to peer */
+          bta_ag_create_sco(p_scb, true);
+          p_sco->state = BTA_AG_SCO_OPENING_ST;
+#endif
+          break;
+
+        case BTA_AG_SCO_SHUTDOWN_E:
+          /* remove listening connection */
+          bta_ag_remove_sco(p_scb, false);
+
+          if (p_scb == p_sco->p_curr_scb) p_sco->p_curr_scb = NULL;
+
+          /* If last SCO instance then finish shutting down */
+          if (!bta_ag_other_scb_open(p_scb)) {
+            p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+          }
+          break;
+
+        case BTA_AG_SCO_CLOSE_E:
+          /* remove listening connection */
+          /* Ignore the event. We need to keep listening SCO for the active SLC
+           */
+          APPL_TRACE_WARNING("BTA_AG_SCO_LISTEN_ST: Ignoring event %d", event);
+          break;
+
+        case BTA_AG_SCO_CONN_CLOSE_E:
+          /* sco failed; create sco listen connection */
+          bta_ag_create_sco(p_scb, false);
+          p_sco->state = BTA_AG_SCO_LISTEN_ST;
+          break;
+
+        default:
+          APPL_TRACE_WARNING("BTA_AG_SCO_LISTEN_ST: Ignoring event %d", event);
+          break;
+      }
+      break;
+
+#if (BTM_WBS_INCLUDED == TRUE)
+    case BTA_AG_SCO_CODEC_ST:
+      switch (event) {
+        case BTA_AG_SCO_LISTEN_E:
+          /* create sco listen connection (Additional channel) */
+          bta_ag_create_sco(p_scb, false);
+          break;
+
+        case BTA_AG_SCO_CN_DONE_E:
+          /* create sco connection to peer */
+          bta_ag_create_sco(p_scb, true);
+          p_sco->state = BTA_AG_SCO_OPENING_ST;
+          break;
+
+        case BTA_AG_SCO_XFER_E:
+          /* save xfer scb */
+          p_sco->p_xfer_scb = p_scb;
+          p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+          break;
+
+        case BTA_AG_SCO_SHUTDOWN_E:
+          /* remove listening connection */
+          bta_ag_remove_sco(p_scb, false);
+
+          if (p_scb == p_sco->p_curr_scb) p_sco->p_curr_scb = NULL;
+
+          /* If last SCO instance then finish shutting down */
+          if (!bta_ag_other_scb_open(p_scb)) {
+            p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+          }
+          break;
+
+        case BTA_AG_SCO_CLOSE_E:
+          /* sco open is not started yet. just go back to listening */
+          p_sco->state = BTA_AG_SCO_LISTEN_ST;
+          break;
+
+        case BTA_AG_SCO_CONN_CLOSE_E:
+          /* sco failed; create sco listen connection */
+          bta_ag_create_sco(p_scb, false);
+          p_sco->state = BTA_AG_SCO_LISTEN_ST;
+          break;
+
+        default:
+          APPL_TRACE_WARNING("BTA_AG_SCO_CODEC_ST: Ignoring event %d", event);
+          break;
+      }
+      break;
+#endif
+
+    case BTA_AG_SCO_OPENING_ST:
+      switch (event) {
+        case BTA_AG_SCO_LISTEN_E:
+          /* second headset has now joined */
+          /* create sco listen connection (Additional channel) */
+          if (p_scb != p_sco->p_curr_scb) {
+            bta_ag_create_sco(p_scb, false);
+          }
+          break;
+
+#if (BTM_WBS_INCLUDED == TRUE)
+        case BTA_AG_SCO_REOPEN_E:
+          /* start codec negotiation */
+          p_sco->state = BTA_AG_SCO_CODEC_ST;
+          p_cn_scb = p_scb;
+          break;
+#endif
+
+        case BTA_AG_SCO_XFER_E:
+          /* save xfer scb */
+          p_sco->p_xfer_scb = p_scb;
+          p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+          break;
+
+        case BTA_AG_SCO_CLOSE_E:
+          p_sco->state = BTA_AG_SCO_OPEN_CL_ST;
+          break;
+
+        case BTA_AG_SCO_SHUTDOWN_E:
+          /* If not opening scb, just close it */
+          if (p_scb != p_sco->p_curr_scb) {
+            /* remove listening connection */
+            bta_ag_remove_sco(p_scb, false);
+          } else
+            p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+
+          break;
+
+        case BTA_AG_SCO_CONN_OPEN_E:
+          p_sco->state = BTA_AG_SCO_OPEN_ST;
+          break;
+
+        case BTA_AG_SCO_CONN_CLOSE_E:
+          /* sco failed; create sco listen connection */
+          bta_ag_create_sco(p_scb, false);
+          p_sco->state = BTA_AG_SCO_LISTEN_ST;
+          break;
+
+        default:
+          APPL_TRACE_WARNING("BTA_AG_SCO_OPENING_ST: Ignoring event %d", event);
+          break;
+      }
+      break;
+
+    case BTA_AG_SCO_OPEN_CL_ST:
+      switch (event) {
+        case BTA_AG_SCO_XFER_E:
+          /* save xfer scb */
+          p_sco->p_xfer_scb = p_scb;
+
+          p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+          break;
+
+        case BTA_AG_SCO_OPEN_E:
+          p_sco->state = BTA_AG_SCO_OPENING_ST;
+          break;
+
+        case BTA_AG_SCO_SHUTDOWN_E:
+          /* If not opening scb, just close it */
+          if (p_scb != p_sco->p_curr_scb) {
+            /* remove listening connection */
+            bta_ag_remove_sco(p_scb, false);
+          } else
+            p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+
+          break;
+
+        case BTA_AG_SCO_CONN_OPEN_E:
+          /* close sco connection */
+          bta_ag_remove_sco(p_scb, true);
+
+          p_sco->state = BTA_AG_SCO_CLOSING_ST;
+          break;
+
+        case BTA_AG_SCO_CONN_CLOSE_E:
+          /* sco failed; create sco listen connection */
+
+          p_sco->state = BTA_AG_SCO_LISTEN_ST;
+          break;
+
+        default:
+          APPL_TRACE_WARNING("BTA_AG_SCO_OPEN_CL_ST: Ignoring event %d", event);
+          break;
+      }
+      break;
+
+    case BTA_AG_SCO_OPEN_XFER_ST:
+      switch (event) {
+        case BTA_AG_SCO_CLOSE_E:
+          /* close sco connection */
+          bta_ag_remove_sco(p_scb, true);
+
+          p_sco->state = BTA_AG_SCO_CLOSING_ST;
+          break;
+
+        case BTA_AG_SCO_SHUTDOWN_E:
+          /* remove all connection */
+          bta_ag_remove_sco(p_scb, false);
+          p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+
+          break;
+
+        case BTA_AG_SCO_CONN_CLOSE_E:
+          /* closed sco; place in listen mode and
+             accept the transferred connection */
+          bta_ag_create_sco(p_scb, false); /* Back into listen mode */
+
+          /* Accept sco connection with xfer scb */
+          bta_ag_sco_conn_rsp(p_sco->p_xfer_scb, &p_sco->conn_data);
+          p_sco->state = BTA_AG_SCO_OPENING_ST;
+          p_sco->p_curr_scb = p_sco->p_xfer_scb;
+          p_sco->cur_idx = p_sco->p_xfer_scb->sco_idx;
+          p_sco->p_xfer_scb = NULL;
+          break;
+
+        default:
+          APPL_TRACE_WARNING("BTA_AG_SCO_OPEN_XFER_ST: Ignoring event %d",
+                             event);
+          break;
+      }
+      break;
+
+    case BTA_AG_SCO_OPEN_ST:
+      switch (event) {
+        case BTA_AG_SCO_LISTEN_E:
+          /* second headset has now joined */
+          /* create sco listen connection (Additional channel) */
+          if (p_scb != p_sco->p_curr_scb) {
+            bta_ag_create_sco(p_scb, false);
+          }
+          break;
+
+        case BTA_AG_SCO_XFER_E:
+          /* close current sco connection */
+          bta_ag_remove_sco(p_sco->p_curr_scb, true);
+
+          /* save xfer scb */
+          p_sco->p_xfer_scb = p_scb;
+
+          p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+          break;
+
+        case BTA_AG_SCO_CLOSE_E:
+          /* close sco connection if active */
+          if (bta_ag_remove_sco(p_scb, true)) {
+            p_sco->state = BTA_AG_SCO_CLOSING_ST;
+          }
+          break;
+
+        case BTA_AG_SCO_SHUTDOWN_E:
+          /* remove all listening connections */
+          bta_ag_remove_sco(p_scb, false);
+
+          /* If SCO was active on this scb, close it */
+          if (p_scb == p_sco->p_curr_scb) {
+            p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+          }
+          break;
+
+        case BTA_AG_SCO_CONN_CLOSE_E:
+          /* peer closed sco; create sco listen connection */
+          bta_ag_create_sco(p_scb, false);
+          p_sco->state = BTA_AG_SCO_LISTEN_ST;
+          break;
+
+        default:
+          APPL_TRACE_WARNING("BTA_AG_SCO_OPEN_ST: Ignoring event %d", event);
+          break;
+      }
+      break;
+
+    case BTA_AG_SCO_CLOSING_ST:
+      switch (event) {
+        case BTA_AG_SCO_LISTEN_E:
+          /* create sco listen connection (Additional channel) */
+          if (p_scb != p_sco->p_curr_scb) {
+            bta_ag_create_sco(p_scb, false);
+          }
+          break;
+
+        case BTA_AG_SCO_OPEN_E:
+          p_sco->state = BTA_AG_SCO_CLOSE_OP_ST;
+          break;
+
+        case BTA_AG_SCO_XFER_E:
+          /* save xfer scb */
+          p_sco->p_xfer_scb = p_scb;
+
+          p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+          break;
+
+        case BTA_AG_SCO_SHUTDOWN_E:
+          /* If not closing scb, just close it */
+          if (p_scb != p_sco->p_curr_scb) {
+            /* remove listening connection */
+            bta_ag_remove_sco(p_scb, false);
+          } else
+            p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+
+          break;
+
+        case BTA_AG_SCO_CONN_CLOSE_E:
+          /* peer closed sco; create sco listen connection */
+          bta_ag_create_sco(p_scb, false);
+
+          p_sco->state = BTA_AG_SCO_LISTEN_ST;
+          break;
+
+        default:
+          APPL_TRACE_WARNING("BTA_AG_SCO_CLOSING_ST: Ignoring event %d", event);
+          break;
+      }
+      break;
+
+    case BTA_AG_SCO_CLOSE_OP_ST:
+      switch (event) {
+        case BTA_AG_SCO_CLOSE_E:
+          p_sco->state = BTA_AG_SCO_CLOSING_ST;
+          break;
+
+        case BTA_AG_SCO_SHUTDOWN_E:
+          p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+          break;
+
+        case BTA_AG_SCO_CONN_CLOSE_E:
+#if (BTM_WBS_INCLUDED == TRUE)
+          /* start codec negotiation */
+          p_sco->state = BTA_AG_SCO_CODEC_ST;
+          p_cn_scb = p_scb;
+#else
+          /* open sco connection */
+          bta_ag_create_sco(p_scb, true);
+          p_sco->state = BTA_AG_SCO_OPENING_ST;
+#endif
+          break;
+
+        case BTA_AG_SCO_LISTEN_E:
+          /* create sco listen connection (Additional channel) */
+          if (p_scb != p_sco->p_curr_scb) {
+            bta_ag_create_sco(p_scb, false);
+          }
+          break;
+
+        default:
+          APPL_TRACE_WARNING("BTA_AG_SCO_CLOSE_OP_ST: Ignoring event %d",
+                             event);
+          break;
+      }
+      break;
+
+    case BTA_AG_SCO_CLOSE_XFER_ST:
+      switch (event) {
+        case BTA_AG_SCO_CONN_OPEN_E:
+          /* close sco connection so headset can be transferred
+             Probably entered this state from "opening state" */
+          bta_ag_remove_sco(p_scb, true);
+          break;
+
+        case BTA_AG_SCO_CLOSE_E:
+          /* clear xfer scb */
+          p_sco->p_xfer_scb = NULL;
+
+          p_sco->state = BTA_AG_SCO_CLOSING_ST;
+          break;
+
+        case BTA_AG_SCO_SHUTDOWN_E:
+          /* clear xfer scb */
+          p_sco->p_xfer_scb = NULL;
+
+          p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+          break;
+
+        case BTA_AG_SCO_CONN_CLOSE_E:
+          /* closed sco; place old sco in listen mode,
+             take current sco out of listen, and
+             create originating sco for current */
+          bta_ag_create_sco(p_scb, false);
+          bta_ag_remove_sco(p_sco->p_xfer_scb, false);
+
+#if (BTM_WBS_INCLUDED == TRUE)
+          /* start codec negotiation */
+          p_sco->state = BTA_AG_SCO_CODEC_ST;
+          p_cn_scb = p_sco->p_xfer_scb;
+          p_sco->p_xfer_scb = NULL;
+#else
+          /* create sco connection to peer */
+          bta_ag_create_sco(p_sco->p_xfer_scb, true);
+          p_sco->p_xfer_scb = NULL;
+          p_sco->state = BTA_AG_SCO_OPENING_ST;
+#endif
+          break;
+
+        default:
+          APPL_TRACE_WARNING("BTA_AG_SCO_CLOSE_XFER_ST: Ignoring event %d",
+                             event);
+          break;
+      }
+      break;
+
+    case BTA_AG_SCO_SHUTTING_ST:
+      switch (event) {
+        case BTA_AG_SCO_CONN_OPEN_E:
+          /* close sco connection; wait for conn close event */
+          bta_ag_remove_sco(p_scb, true);
+          break;
+
+        case BTA_AG_SCO_CONN_CLOSE_E:
+          /* If last SCO instance then finish shutting down */
+          if (!bta_ag_other_scb_open(p_scb)) {
+            p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+          } else /* Other instance is still listening */
+          {
+            p_sco->state = BTA_AG_SCO_LISTEN_ST;
+          }
+
+          /* If SCO closed for other HS which is not being disconnected,
+             then create listen sco connection for it as scb still open */
+          if (bta_ag_scb_open(p_scb)) {
+            bta_ag_create_sco(p_scb, false);
+            p_sco->state = BTA_AG_SCO_LISTEN_ST;
+          }
+
+          if (p_scb == p_sco->p_curr_scb) {
+            p_sco->p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+            p_sco->p_curr_scb = NULL;
+          }
+          break;
+
+        case BTA_AG_SCO_LISTEN_E:
+          /* create sco listen connection (Additional channel) */
+          if (p_scb != p_sco->p_curr_scb) {
+            bta_ag_create_sco(p_scb, false);
+          }
+          break;
+
+        case BTA_AG_SCO_SHUTDOWN_E:
+          if (!bta_ag_other_scb_open(p_scb)) {
+            p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+          } else /* Other instance is still listening */
+          {
+            p_sco->state = BTA_AG_SCO_LISTEN_ST;
+          }
+
+          if (p_scb == p_sco->p_curr_scb) {
+            p_sco->p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+            p_sco->p_curr_scb = NULL;
+          }
+          break;
+
+        default:
+          APPL_TRACE_WARNING("BTA_AG_SCO_SHUTTING_ST: Ignoring event %d",
+                             event);
+          break;
+      }
+      break;
+
+    default:
+      break;
+  }
+#if (BTA_AG_SCO_DEBUG == TRUE)
+  if (p_sco->state != in_state) {
+    APPL_TRACE_EVENT("BTA AG SCO State Change: [%s] -> [%s] after Event [%s]",
+                     bta_ag_sco_state_str(in_state),
+                     bta_ag_sco_state_str(p_sco->state),
+                     bta_ag_sco_evt_str(event));
+  }
+#endif
+
+#if (BTM_WBS_INCLUDED == TRUE)
+  if (p_cn_scb) {
+    bta_ag_codec_negotiate(p_cn_scb);
+  }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_sco_is_open
+ *
+ * Description      Check if sco is open for this scb.
+ *
+ *
+ * Returns          true if sco open for this scb, false otherwise.
+ *
+ ******************************************************************************/
+bool bta_ag_sco_is_open(tBTA_AG_SCB* p_scb) {
+  return ((bta_ag_cb.sco.state == BTA_AG_SCO_OPEN_ST) &&
+          (bta_ag_cb.sco.p_curr_scb == p_scb));
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_sco_is_opening
+ *
+ * Description      Check if sco is in Opening state.
+ *
+ *
+ * Returns          true if sco is in Opening state for this scb, false
+ *                  otherwise.
+ *
+ ******************************************************************************/
+bool bta_ag_sco_is_opening(tBTA_AG_SCB* p_scb) {
+  return ((bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST) &&
+          (bta_ag_cb.sco.p_curr_scb == p_scb));
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_sco_listen
+ *
+ * Description
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_sco_listen(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+  bta_ag_sco_event(p_scb, BTA_AG_SCO_LISTEN_E);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_sco_open
+ *
+ * Description
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_sco_open(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+  uint8_t event;
+
+  /* if another scb using sco, this is a transfer */
+  if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb != p_scb) {
+    event = BTA_AG_SCO_XFER_E;
+  }
+  /* else it is an open */
+  else {
+    event = BTA_AG_SCO_OPEN_E;
+  }
+
+  bta_ag_sco_event(p_scb, event);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_sco_close
+ *
+ * Description
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_sco_close(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+/* if scb is in use */
+#if (BTM_WBS_INCLUDED == TRUE)
+  /* sco_idx is not allocated in SCO_CODEC_ST, we still need to move to
+   * listening state. */
+  if ((p_scb->sco_idx != BTM_INVALID_SCO_INDEX) ||
+      (bta_ag_cb.sco.state == BTA_AG_SCO_CODEC_ST))
+#else
+  if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX)
+#endif
+  {
+    APPL_TRACE_DEBUG("bta_ag_sco_close: sco_inx = %d", p_scb->sco_idx);
+    bta_ag_sco_event(p_scb, BTA_AG_SCO_CLOSE_E);
+  }
+}
+
+#if (BTM_WBS_INCLUDED == TRUE)
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_sco_codec_nego
+ *
+ * Description
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_sco_codec_nego(tBTA_AG_SCB* p_scb, bool result) {
+  if (result == true) {
+    /* Subsequent sco connection will skip codec negotiation */
+    p_scb->codec_updated = false;
+
+    bta_ag_sco_event(p_scb, BTA_AG_SCO_CN_DONE_E);
+  } else /* codec negotiation failed */
+    bta_ag_sco_event(p_scb, BTA_AG_SCO_CLOSE_E);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_sco_shutdown
+ *
+ * Description
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_sco_shutdown(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+  bta_ag_sco_event(p_scb, BTA_AG_SCO_SHUTDOWN_E);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_sco_conn_open
+ *
+ * Description
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_sco_conn_open(tBTA_AG_SCB* p_scb,
+                          UNUSED_ATTR tBTA_AG_DATA* p_data) {
+  bta_ag_sco_event(p_scb, BTA_AG_SCO_CONN_OPEN_E);
+
+  bta_sys_sco_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+#if (BTM_WBS_INCLUDED == TRUE)
+  bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, SCO_STATE_ON,
+                        p_scb->inuse_codec);
+#else
+  bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, SCO_STATE_ON);
+#endif
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+  /* open SCO codec if SCO is routed through transport */
+  bta_dm_sco_co_open(bta_ag_scb_to_idx(p_scb), BTA_SCO_OUT_PKT_SIZE,
+                     BTA_AG_CI_SCO_DATA_EVT);
+#endif
+
+  /* call app callback */
+  bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_OPEN_EVT);
+
+  p_scb->retry_with_sco_only = false;
+#if (BTM_WBS_INCLUDED == TRUE)
+  /* reset to mSBC T2 settings as the preferred */
+  p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2;
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_sco_conn_close
+ *
+ * Description
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_sco_conn_close(tBTA_AG_SCB* p_scb,
+                           UNUSED_ATTR tBTA_AG_DATA* p_data) {
+  uint16_t handle = bta_ag_scb_to_idx(p_scb);
+
+  /* clear current scb */
+  bta_ag_cb.sco.p_curr_scb = NULL;
+  p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+
+#if (BTM_WBS_INCLUDED == TRUE)
+  /* codec_fallback is set when AG is initiator and connection failed for mSBC.
+   */
+  /* OR if codec is msbc and T2 settings failed, then retry Safe T1 settings */
+  if ((p_scb->codec_fallback && p_scb->svc_conn) ||
+      bta_ag_attempt_msbc_safe_settings(p_scb)) {
+    bta_ag_sco_event(p_scb, BTA_AG_SCO_REOPEN_E);
+  } else if (p_scb->retry_with_sco_only && p_scb->svc_conn) {
+    /* retry_with_sco_only is set when AG is initiator and connection failed for
+     * eSCO */
+    bta_ag_create_sco(p_scb, true);
+  }
+#else
+  /* retry_with_sco_only, will be set only when AG is initiator
+  ** and AG is first trying to establish an eSCO connection */
+  if (p_scb->retry_with_sco_only && p_scb->svc_conn) {
+    bta_ag_create_sco(p_scb, true);
+  }
+#endif
+  else {
+    sco_state_t sco_state =
+        bta_ag_cb.sco.p_xfer_scb ? SCO_STATE_OFF_TRANSFER : SCO_STATE_OFF;
+#if (BTM_WBS_INCLUDED == TRUE)
+    /* Indicate if the closing of audio is because of transfer */
+    bta_ag_co_audio_state(handle, p_scb->app_id, sco_state, p_scb->inuse_codec);
+#else
+    /* Indicate if the closing of audio is because of transfer */
+    bta_ag_co_audio_state(handle, p_scb->app_id, sco_state);
+#endif
+    bta_ag_sco_event(p_scb, BTA_AG_SCO_CONN_CLOSE_E);
+
+    bta_sys_sco_close(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+    /* if av got suspended by this call, let it resume. */
+    /* In case call stays alive regardless of sco, av should not be affected. */
+    if (((p_scb->call_ind == BTA_AG_CALL_INACTIVE) &&
+         (p_scb->callsetup_ind == BTA_AG_CALLSETUP_NONE)) ||
+        (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END)) {
+      bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+    }
+
+    /* call app callback */
+    bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_CLOSE_EVT);
+#if (BTM_WBS_INCLUDED == TRUE)
+    p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2;
+#endif
+  }
+  p_scb->retry_with_sco_only = false;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_sco_conn_rsp
+ *
+ * Description      Process the SCO connection request
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_sco_conn_rsp(tBTA_AG_SCB* p_scb,
+                         tBTM_ESCO_CONN_REQ_EVT_DATA* p_data) {
+  tBTM_ESCO_PARAMS resp;
+  uint8_t hci_status = HCI_SUCCESS;
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+  tBTA_CODEC_INFO codec_info = {BTA_SCO_CODEC_PCM};
+  uint32_t pcm_sample_rate;
+#endif
+
+  if (bta_ag_cb.sco.state == BTA_AG_SCO_LISTEN_ST ||
+      bta_ag_cb.sco.state == BTA_AG_SCO_CLOSE_XFER_ST ||
+      bta_ag_cb.sco.state == BTA_AG_SCO_OPEN_XFER_ST) {
+    /* If script overrided sco parameter by BTA_CMD_SET_ESCO_PARAM */
+    if (bta_ag_cb.sco.param_updated) {
+      resp = bta_ag_cb.sco.params;
+    } else {
+      resp.rx_bw = BTM_64KBITS_RATE;
+      resp.tx_bw = BTM_64KBITS_RATE;
+      resp.max_latency = 12;
+      resp.voice_contfmt = 0x60;
+      resp.retrans_effort = BTM_ESCO_RETRANS_QUALITY;
+
+      if (p_data->link_type == BTM_LINK_TYPE_SCO) {
+        resp.packet_types =
+            (BTM_SCO_LINK_ONLY_MASK | BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 |
+             BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+             BTM_SCO_PKT_TYPES_MASK_NO_3_EV5);
+      } else /* Allow controller to use all types available except 5-slot EDR */
+      {
+        resp.packet_types =
+            (BTM_SCO_LINK_ALL_PKT_MASK | BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+             BTM_SCO_PKT_TYPES_MASK_NO_3_EV5);
+      }
+    }
+
+    /* tell sys to stop av if any */
+    bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+#if (BTM_WBS_INCLUDED == FALSE)
+    /* Allow any platform specific pre-SCO set up to take place */
+    bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id,
+                          SCO_STATE_SETUP);
+#else
+    /* When HS initiated SCO, it cannot be WBS. */
+    /* Allow any platform specific pre-SCO set up to take place */
+    bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id,
+                          SCO_STATE_SETUP, BTA_AG_CODEC_CVSD);
+#endif
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+    pcm_sample_rate = BTA_DM_SCO_SAMP_RATE_8K;
+
+    /* initialize SCO setup, no voice setting for AG, data rate <==> sample rate
+     */
+    BTM_ConfigScoPath(bta_dm_sco_co_init(pcm_sample_rate, pcm_sample_rate,
+                                         &codec_info, p_scb->app_id),
+                      bta_ag_sco_read_cback, NULL, true);
+#endif
+  } else
+    hci_status = HCI_ERR_HOST_REJECT_DEVICE;
+
+#if (BTM_WBS_INCLUDED == TRUE)
+  /* If SCO open was initiated from HS, it must be CVSD */
+  p_scb->inuse_codec = BTA_AG_CODEC_NONE;
+#endif
+
+  BTM_EScoConnRsp(p_data->sco_inx, hci_status, &resp);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_ci_sco_data
+ *
+ * Description      Process the SCO data ready callin event
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_ci_sco_data(UNUSED_ATTR tBTA_AG_SCB* p_scb,
+                        UNUSED_ATTR tBTA_AG_DATA* p_data) {
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+  bta_ag_sco_event(p_scb, BTA_AG_SCO_CI_DATA_E);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_set_esco_param
+ *
+ * Description      Update esco parameters from script wrapper.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_set_esco_param(bool set_reset, tBTM_ESCO_PARAMS* param) {
+  if (set_reset == false) /* reset the parameters to default */
+  {
+    bta_ag_cb.sco.param_updated = false;
+    APPL_TRACE_DEBUG(
+        "bta_ag_set_esco_param : Resetting ESCO parameters to default");
+  } else {
+    bta_ag_cb.sco.param_updated = true;
+    bta_ag_cb.sco.params = *param;
+    APPL_TRACE_DEBUG("bta_ag_set_esco_param : Setting ESCO parameters");
+  }
+}
+
+/*******************************************************************************
+ *  Debugging functions
+ ******************************************************************************/
+
+#if (BTA_AG_SCO_DEBUG == TRUE)
+static char* bta_ag_sco_evt_str(uint8_t event) {
+  switch (event) {
+    case BTA_AG_SCO_LISTEN_E:
+      return "Listen Request";
+    case BTA_AG_SCO_OPEN_E:
+      return "Open Request";
+    case BTA_AG_SCO_XFER_E:
+      return "Transfer Request";
+#if (BTM_WBS_INCLUDED == TRUE)
+    case BTA_AG_SCO_CN_DONE_E:
+      return "Codec Negotiation Done";
+    case BTA_AG_SCO_REOPEN_E:
+      return "Reopen Request";
+#endif
+    case BTA_AG_SCO_CLOSE_E:
+      return "Close Request";
+    case BTA_AG_SCO_SHUTDOWN_E:
+      return "Shutdown Request";
+    case BTA_AG_SCO_CONN_OPEN_E:
+      return "Opened";
+    case BTA_AG_SCO_CONN_CLOSE_E:
+      return "Closed";
+    case BTA_AG_SCO_CI_DATA_E:
+      return "Sco Data";
+    default:
+      return "Unknown SCO Event";
+  }
+}
+
+static char* bta_ag_sco_state_str(uint8_t state) {
+  switch (state) {
+    case BTA_AG_SCO_SHUTDOWN_ST:
+      return "Shutdown";
+    case BTA_AG_SCO_LISTEN_ST:
+      return "Listening";
+#if (BTM_WBS_INCLUDED == TRUE)
+    case BTA_AG_SCO_CODEC_ST:
+      return "Codec Negotiation";
+#endif
+    case BTA_AG_SCO_OPENING_ST:
+      return "Opening";
+    case BTA_AG_SCO_OPEN_CL_ST:
+      return "Open while closing";
+    case BTA_AG_SCO_OPEN_XFER_ST:
+      return "Opening while Transferring";
+    case BTA_AG_SCO_OPEN_ST:
+      return "Open";
+    case BTA_AG_SCO_CLOSING_ST:
+      return "Closing";
+    case BTA_AG_SCO_CLOSE_OP_ST:
+      return "Close while Opening";
+    case BTA_AG_SCO_CLOSE_XFER_ST:
+      return "Close while Transferring";
+    case BTA_AG_SCO_SHUTTING_ST:
+      return "Shutting Down";
+    default:
+      return "Unknown SCO State";
+  }
+}
+
+#endif
diff --git a/bt/bta/ag/bta_ag_sdp.cc b/bt/bta/ag/bta_ag_sdp.cc
new file mode 100644
index 0000000..957bf8b
--- /dev/null
+++ b/bt/bta/ag/bta_ag_sdp.cc
@@ -0,0 +1,447 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 audio gateway functions performing SDP
+ *  operations.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_ag_api.h"
+#include "bta_ag_int.h"
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+#include "osi/include/osi.h"
+#include "sdp_api.h"
+#include "utl.h"
+
+/* Number of protocol elements in protocol element list. */
+#define BTA_AG_NUM_PROTO_ELEMS 2
+
+/* Number of elements in service class id list. */
+#define BTA_AG_NUM_SVC_ELEMS 2
+
+/* size of database for service discovery */
+#ifndef BTA_AG_DISC_BUF_SIZE
+#define BTA_AG_DISC_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* declare sdp callback functions */
+void bta_ag_sdp_cback_1(uint16_t status);
+void bta_ag_sdp_cback_2(uint16_t status);
+void bta_ag_sdp_cback_3(uint16_t status);
+
+/* SDP callback function table */
+typedef tSDP_DISC_CMPL_CB* tBTA_AG_SDP_CBACK;
+const tBTA_AG_SDP_CBACK bta_ag_sdp_cback_tbl[] = {
+    bta_ag_sdp_cback_1, bta_ag_sdp_cback_2, bta_ag_sdp_cback_3};
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_sdp_cback
+ *
+ * Description      SDP callback function.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ag_sdp_cback(uint16_t status, uint8_t idx) {
+  uint16_t event;
+  tBTA_AG_SCB* p_scb;
+
+  APPL_TRACE_DEBUG("%s status:0x%x", __func__, status);
+
+  if ((p_scb = bta_ag_scb_by_idx(idx)) != NULL) {
+    /* set event according to int/acp */
+    if (p_scb->role == BTA_AG_ACP) {
+      event = BTA_AG_DISC_ACP_RES_EVT;
+    } else {
+      event = BTA_AG_DISC_INT_RES_EVT;
+    }
+
+    tBTA_AG_DISC_RESULT* p_buf =
+        (tBTA_AG_DISC_RESULT*)osi_malloc(sizeof(tBTA_AG_DISC_RESULT));
+    p_buf->hdr.event = event;
+    p_buf->hdr.layer_specific = idx;
+    p_buf->status = status;
+    bta_sys_sendmsg(p_buf);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_sdp_cback_1 to 3
+ *
+ * Description      SDP callback functions.  Since there is no way to
+ *                  distinguish scb from the callback we need separate
+ *                  callbacks for each scb.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_sdp_cback_1(uint16_t status) { bta_ag_sdp_cback(status, 1); }
+void bta_ag_sdp_cback_2(uint16_t status) { bta_ag_sdp_cback(status, 2); }
+void bta_ag_sdp_cback_3(uint16_t status) { bta_ag_sdp_cback(status, 3); }
+
+/******************************************************************************
+ *
+ * Function         bta_ag_add_record
+ *
+ * Description      This function is called by a server application to add
+ *                  HSP or HFP information to an SDP record.  Prior to
+ *                  calling this function the application must call
+ *                  SDP_CreateRecord() to create an SDP record.
+ *
+ * Returns          true if function execution succeeded,
+ *                  false if function execution failed.
+ *
+ *****************************************************************************/
+bool bta_ag_add_record(uint16_t service_uuid, char* p_service_name, uint8_t scn,
+                       tBTA_AG_FEAT features, uint32_t sdp_handle) {
+  tSDP_PROTOCOL_ELEM proto_elem_list[BTA_AG_NUM_PROTO_ELEMS];
+  uint16_t svc_class_id_list[BTA_AG_NUM_SVC_ELEMS];
+  uint16_t browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
+  uint16_t version;
+  uint16_t profile_uuid;
+  uint8_t network;
+  bool result = true;
+  bool codec_supported = false;
+  uint8_t buf[2];
+
+  APPL_TRACE_DEBUG("%s uuid: %x", __func__, service_uuid);
+
+  memset(proto_elem_list, 0,
+         BTA_AG_NUM_PROTO_ELEMS * sizeof(tSDP_PROTOCOL_ELEM));
+
+  /* add the protocol element sequence */
+  proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+  proto_elem_list[0].num_params = 0;
+  proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+  proto_elem_list[1].num_params = 1;
+  proto_elem_list[1].params[0] = scn;
+  result &=
+      SDP_AddProtocolList(sdp_handle, BTA_AG_NUM_PROTO_ELEMS, proto_elem_list);
+
+  /* add service class id list */
+  svc_class_id_list[0] = service_uuid;
+  svc_class_id_list[1] = UUID_SERVCLASS_GENERIC_AUDIO;
+  result &= SDP_AddServiceClassIdList(sdp_handle, BTA_AG_NUM_SVC_ELEMS,
+                                      svc_class_id_list);
+
+  /* add profile descriptor list */
+  if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE) {
+    profile_uuid = UUID_SERVCLASS_HF_HANDSFREE;
+    version = BTA_HFP_VERSION;
+  } else {
+    profile_uuid = UUID_SERVCLASS_HEADSET;
+    version = HSP_VERSION_1_2;
+  }
+  result &= SDP_AddProfileDescriptorList(sdp_handle, profile_uuid, version);
+
+  /* add service name */
+  if (p_service_name != NULL && p_service_name[0] != 0) {
+    result &= SDP_AddAttribute(
+        sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+        (uint32_t)(strlen(p_service_name) + 1), (uint8_t*)p_service_name);
+  }
+
+  /* add features and network */
+  if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE) {
+    network = (features & BTA_AG_FEAT_REJECT) ? 1 : 0;
+    result &= SDP_AddAttribute(sdp_handle, ATTR_ID_DATA_STORES_OR_NETWORK,
+                               UINT_DESC_TYPE, 1, &network);
+
+    if (features & BTA_AG_FEAT_CODEC) codec_supported = true;
+
+    features &= BTA_AG_SDP_FEAT_SPEC;
+
+    /* Codec bit position is different in SDP and in BRSF */
+    if (codec_supported) features |= 0x0020;
+
+    UINT16_TO_BE_FIELD(buf, features);
+    result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES,
+                               UINT_DESC_TYPE, 2, buf);
+  }
+
+  /* add browse group list */
+  result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1,
+                                browse_list);
+
+  return result;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_create_records
+ *
+ * Description      Create SDP records for registered services.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_create_records(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+  int i;
+  tBTA_SERVICE_MASK services;
+
+  services = p_scb->reg_services >> BTA_HSP_SERVICE_ID;
+  for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) {
+    /* if service is set in mask */
+    if (services & 1) {
+      /* add sdp record if not already registered */
+      if (bta_ag_cb.profile[i].sdp_handle == 0) {
+        bta_ag_cb.profile[i].sdp_handle = SDP_CreateRecord();
+        bta_ag_cb.profile[i].scn = BTM_AllocateSCN();
+        bta_ag_add_record(bta_ag_uuid[i], p_data->api_register.p_name[i],
+                          bta_ag_cb.profile[i].scn,
+                          p_data->api_register.features,
+                          bta_ag_cb.profile[i].sdp_handle);
+        bta_sys_add_uuid(bta_ag_uuid[i]);
+      }
+    }
+  }
+
+  p_scb->hsp_version = HSP_VERSION_1_2;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_del_records
+ *
+ * Description      Delete SDP records for any registered services.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_del_records(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+  tBTA_AG_SCB* p = &bta_ag_cb.scb[0];
+  tBTA_SERVICE_MASK services;
+  tBTA_SERVICE_MASK others = 0;
+  int i;
+
+  /* get services of all other registered servers */
+  for (i = 0; i < BTA_AG_NUM_IDX; i++, p++) {
+    if (p_scb == p) {
+      continue;
+    }
+
+    if (p->in_use && p->dealloc == false) {
+      others |= p->reg_services;
+    }
+  }
+
+  others >>= BTA_HSP_SERVICE_ID;
+  services = p_scb->reg_services >> BTA_HSP_SERVICE_ID;
+  for (i = 0; i < BTA_AG_NUM_IDX && services != 0;
+       i++, services >>= 1, others >>= 1) {
+    /* if service registered for this scb and not registered for any other scb
+     */
+    if (((services & 1) == 1) && ((others & 1) == 0)) {
+      APPL_TRACE_DEBUG("bta_ag_del_records %d", i);
+      if (bta_ag_cb.profile[i].sdp_handle != 0) {
+        SDP_DeleteRecord(bta_ag_cb.profile[i].sdp_handle);
+        bta_ag_cb.profile[i].sdp_handle = 0;
+      }
+      BTM_FreeSCN(bta_ag_cb.profile[i].scn);
+      BTM_SecClrService(bta_ag_sec_id[i]);
+      bta_sys_remove_uuid(bta_ag_uuid[i]);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_sdp_find_attr
+ *
+ * Description      Process SDP discovery results to find requested attributes
+ *                  for requested service.
+ *
+ *
+ * Returns          true if results found, false otherwise.
+ *
+ ******************************************************************************/
+bool bta_ag_sdp_find_attr(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK service) {
+  tSDP_DISC_REC* p_rec = NULL;
+  tSDP_DISC_ATTR* p_attr;
+  tSDP_PROTOCOL_ELEM pe;
+  uint16_t uuid;
+  bool result = false;
+
+  if (service & BTA_HFP_SERVICE_MASK) {
+    uuid = UUID_SERVCLASS_HF_HANDSFREE;
+    p_scb->peer_version = HFP_VERSION_1_1; /* Default version */
+  } else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT) {
+    uuid = UUID_SERVCLASS_HEADSET_HS;
+    p_scb->peer_version = 0x0100; /* Default version */
+  } else {
+    return result;
+  }
+
+  /* loop through all records we found */
+  while (true) {
+    /* get next record; if none found, we're done */
+    if ((p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec)) == NULL) {
+      if (uuid == UUID_SERVCLASS_HEADSET_HS) {
+        /* Search again in case the peer device is HSP v1.0 */
+        uuid = UUID_SERVCLASS_HEADSET;
+        if ((p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec)) ==
+            NULL) {
+          break;
+        }
+      } else
+        break;
+    }
+
+    /* get scn from proto desc list if initiator */
+    if (p_scb->role == BTA_AG_INT) {
+      if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+        p_scb->peer_scn = (uint8_t)pe.params[0];
+      } else {
+        continue;
+      }
+    }
+
+    /* get profile version (if failure, version parameter is not updated) */
+    SDP_FindProfileVersionInRec(p_rec, uuid, &p_scb->peer_version);
+
+    /* get features if HFP */
+    if (service & BTA_HFP_SERVICE_MASK) {
+      if ((p_attr = SDP_FindAttributeInRec(
+               p_rec, ATTR_ID_SUPPORTED_FEATURES)) != NULL) {
+        /* Found attribute. Get value. */
+        /* There might be race condition between SDP and BRSF.  */
+        /* Do not update if we already received BRSF.           */
+        if (p_scb->peer_features == 0)
+          p_scb->peer_features = p_attr->attr_value.v.u16;
+      }
+    } else /* HSP */
+    {
+      if ((p_attr = SDP_FindAttributeInRec(
+               p_rec, ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL)) != NULL) {
+        /* Remote volume control of HSP */
+        if (p_attr->attr_value.v.u8)
+          p_scb->peer_features |= BTA_AG_PEER_FEAT_VOL;
+        else
+          p_scb->peer_features &= ~BTA_AG_PEER_FEAT_VOL;
+      }
+    }
+
+    /* found what we needed */
+    result = true;
+    break;
+  }
+  return result;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_do_disc
+ *
+ * Description      Do service discovery.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_do_disc(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK service) {
+  tSDP_UUID uuid_list[2];
+  uint16_t num_uuid = 1;
+  uint16_t attr_list[4];
+  uint8_t num_attr;
+  bool db_inited = false;
+
+  /* HFP initiator; get proto list and features */
+  if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_INT) {
+    attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+    attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+    attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
+    attr_list[3] = ATTR_ID_SUPPORTED_FEATURES;
+    num_attr = 4;
+    uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE;
+  }
+  /* HFP acceptor; get features */
+  else if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_ACP) {
+    attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+    attr_list[1] = ATTR_ID_BT_PROFILE_DESC_LIST;
+    attr_list[2] = ATTR_ID_SUPPORTED_FEATURES;
+    num_attr = 3;
+    uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE;
+  }
+  /* HSP initiator; get proto list */
+  else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT) {
+    attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+    attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+    attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
+    attr_list[3] = ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL;
+    num_attr = 4;
+
+    uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HEADSET; /* Legacy from HSP v1.0 */
+    if (p_scb->hsp_version >= HSP_VERSION_1_2) {
+      uuid_list[1].uu.uuid16 = UUID_SERVCLASS_HEADSET_HS;
+      num_uuid = 2;
+    }
+  }
+  /* HSP acceptor; no discovery */
+  else {
+    return;
+  }
+
+  /* allocate buffer for sdp database */
+  p_scb->p_disc_db = (tSDP_DISCOVERY_DB*)osi_malloc(BTA_AG_DISC_BUF_SIZE);
+  /* set up service discovery database; attr happens to be attr_list len */
+  uuid_list[0].len = LEN_UUID_16;
+  uuid_list[1].len = LEN_UUID_16;
+  db_inited = SDP_InitDiscoveryDb(p_scb->p_disc_db, BTA_AG_DISC_BUF_SIZE,
+                                  num_uuid, uuid_list, num_attr, attr_list);
+
+  if (db_inited) {
+    /*Service discovery not initiated */
+    db_inited = SDP_ServiceSearchAttributeRequest(
+        p_scb->peer_addr, p_scb->p_disc_db,
+        bta_ag_sdp_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]);
+  }
+
+  if (!db_inited) {
+    /*free discover db */
+    bta_ag_free_db(p_scb, NULL);
+    /* sent failed event */
+    bta_ag_sm_execute(p_scb, BTA_AG_DISC_FAIL_EVT, NULL);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_free_db
+ *
+ * Description      Free discovery database.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_free_db(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+  osi_free_and_reset((void**)&p_scb->p_disc_db);
+}
diff --git a/bt/bta/ar/bta_ar.cc b/bt/bta/ar/bta_ar.cc
new file mode 100644
index 0000000..f5aeeca
--- /dev/null
+++ b/bt/bta/ar/bta_ar.cc
@@ -0,0 +1,301 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 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 is the implementation for the audio/video registration module.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bta_ar_api.h"
+#include "bta_ar_int.h"
+
+/* AV control block */
+tBTA_AR_CB bta_ar_cb;
+
+/*******************************************************************************
+ *
+ * Function         bta_ar_id
+ *
+ * Description      This function maps sys_id to ar id mask.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static uint8_t bta_ar_id(tBTA_SYS_ID sys_id) {
+  uint8_t mask = 0;
+  if (sys_id == BTA_ID_AV) {
+    mask = BTA_AR_AV_MASK;
+  } else if (sys_id == BTA_ID_AVK) {
+    mask = BTA_AR_AVK_MASK;
+  }
+
+  return mask;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ar_init
+ *
+ * Description      This function is called to register to AVDTP.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ar_init(void) {
+  /* initialize control block */
+  memset(&bta_ar_cb, 0, sizeof(tBTA_AR_CB));
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ar_reg_avdt
+ *
+ * Description      This function is called to register to AVDTP.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_ar_avdt_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+                              tAVDT_CTRL* p_data) {
+  /* route the AVDT registration callback to av or avk */
+  if (bta_ar_cb.p_av_conn_cback)
+    (*bta_ar_cb.p_av_conn_cback)(handle, bd_addr, event, p_data);
+  if (bta_ar_cb.p_avk_conn_cback)
+    (*bta_ar_cb.p_avk_conn_cback)(handle, bd_addr, event, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ar_reg_avdt
+ *
+ * Description      AR module registration to AVDT.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ar_reg_avdt(tAVDT_REG* p_reg, tAVDT_CTRL_CBACK* p_cback,
+                     tBTA_SYS_ID sys_id) {
+  uint8_t mask = 0;
+
+  if (sys_id == BTA_ID_AV) {
+    bta_ar_cb.p_av_conn_cback = p_cback;
+    mask = BTA_AR_AV_MASK;
+  } else if (sys_id == BTA_ID_AVK) {
+    bta_ar_cb.p_avk_conn_cback = p_cback;
+    mask = BTA_AR_AVK_MASK;
+  }
+#if (BTA_AR_DEBUG == TRUE)
+  else {
+    APPL_TRACE_ERROR(
+        "bta_ar_reg_avdt: the registration is from wrong sys_id:%d", sys_id);
+  }
+#endif
+
+  if (mask) {
+    if (bta_ar_cb.avdt_registered == 0) {
+      AVDT_Register(p_reg, bta_ar_avdt_cback);
+    }
+    bta_ar_cb.avdt_registered |= mask;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ar_dereg_avdt
+ *
+ * Description      This function is called to de-register from AVDTP.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ar_dereg_avdt(tBTA_SYS_ID sys_id) {
+  uint8_t mask = 0;
+
+  if (sys_id == BTA_ID_AV) {
+    bta_ar_cb.p_av_conn_cback = NULL;
+    mask = BTA_AR_AV_MASK;
+  } else if (sys_id == BTA_ID_AVK) {
+    bta_ar_cb.p_avk_conn_cback = NULL;
+    mask = BTA_AR_AVK_MASK;
+  }
+  bta_ar_cb.avdt_registered &= ~mask;
+
+  if (bta_ar_cb.avdt_registered == 0) AVDT_Deregister();
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ar_avdt_conn
+ *
+ * Description      This function is called to let ar know that some AVDTP
+ *                  profile is connected for this sys_id.
+ *                  If the other sys modules started a timer for PENDING_EVT,
+ *                  the timer can be stopped now.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ar_avdt_conn(tBTA_SYS_ID sys_id, BD_ADDR bd_addr) {
+  uint8_t event = BTA_AR_AVDT_CONN_EVT;
+  tAVDT_CTRL data;
+
+  if (sys_id == BTA_ID_AV) {
+    if (bta_ar_cb.p_avk_conn_cback) {
+      (*bta_ar_cb.p_avk_conn_cback)(0, bd_addr, event, &data);
+    }
+  } else if (sys_id == BTA_ID_AVK) {
+    if (bta_ar_cb.p_av_conn_cback) {
+      (*bta_ar_cb.p_av_conn_cback)(0, bd_addr, event, &data);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ar_reg_avct
+ *
+ * Description      This function is called to register to AVCTP.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ar_reg_avct(uint16_t mtu, uint16_t mtu_br, uint8_t sec_mask,
+                     tBTA_SYS_ID sys_id) {
+  uint8_t mask = bta_ar_id(sys_id);
+
+  if (mask) {
+    if (bta_ar_cb.avct_registered == 0) {
+      AVCT_Register(mtu, mtu_br, sec_mask);
+    }
+    bta_ar_cb.avct_registered |= mask;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ar_dereg_avct
+ *
+ * Description      This function is called to deregister from AVCTP.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ar_dereg_avct(tBTA_SYS_ID sys_id) {
+  uint8_t mask = bta_ar_id(sys_id);
+
+  bta_ar_cb.avct_registered &= ~mask;
+
+  if (bta_ar_cb.avct_registered == 0) AVCT_Deregister();
+}
+
+/******************************************************************************
+ *
+ * Function         bta_ar_reg_avrc
+ *
+ * Description      This function is called to register an SDP record for AVRCP.
+ *
+ * Returns          void
+ *
+ *****************************************************************************/
+void bta_ar_reg_avrc(uint16_t service_uuid, const char* service_name,
+                     const char* provider_name, uint16_t categories,
+                     tBTA_SYS_ID sys_id, bool browse_supported,
+                     uint16_t profile_version) {
+  uint8_t mask = bta_ar_id(sys_id);
+  uint8_t temp[8], *p;
+
+  if (!mask || !categories) return;
+
+  if (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET) {
+    if (bta_ar_cb.sdp_tg_handle == 0) {
+      bta_ar_cb.tg_registered = mask;
+      bta_ar_cb.sdp_tg_handle = SDP_CreateRecord();
+      AVRC_AddRecord(service_uuid, service_name, provider_name, categories,
+                     bta_ar_cb.sdp_tg_handle, browse_supported,
+                     profile_version);
+      bta_sys_add_uuid(service_uuid);
+    }
+    /* only one TG is allowed (first-come, first-served).
+     * If sdp_tg_handle is non-0, ignore this request */
+  } else if ((service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL) ||
+             (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_CONTROL)) {
+    bta_ar_cb.ct_categories[mask - 1] = categories;
+    categories = bta_ar_cb.ct_categories[0] | bta_ar_cb.ct_categories[1];
+    if (bta_ar_cb.sdp_ct_handle == 0) {
+      bta_ar_cb.sdp_ct_handle = SDP_CreateRecord();
+      AVRC_AddRecord(service_uuid, service_name, provider_name, categories,
+                     bta_ar_cb.sdp_ct_handle, browse_supported,
+                     profile_version);
+      bta_sys_add_uuid(service_uuid);
+    } else {
+      /* multiple CTs are allowed.
+       * Change supported categories on the second one */
+      p = temp;
+      UINT16_TO_BE_STREAM(p, categories);
+      SDP_AddAttribute(bta_ar_cb.sdp_ct_handle, ATTR_ID_SUPPORTED_FEATURES,
+                       UINT_DESC_TYPE, (uint32_t)2, (uint8_t*)temp);
+    }
+  }
+}
+
+/******************************************************************************
+ *
+ * Function         bta_ar_dereg_avrc
+ *
+ * Description      This function is called to de-register/delete an SDP record
+ *                  for AVRCP.
+ *
+ * Returns          void
+ *
+ *****************************************************************************/
+void bta_ar_dereg_avrc(uint16_t service_uuid, tBTA_SYS_ID sys_id) {
+  uint8_t mask = bta_ar_id(sys_id);
+  uint16_t categories = 0;
+  uint8_t temp[8], *p;
+
+  if (!mask) return;
+
+  if (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET) {
+    if (bta_ar_cb.sdp_tg_handle && mask == bta_ar_cb.tg_registered) {
+      bta_ar_cb.tg_registered = 0;
+      SDP_DeleteRecord(bta_ar_cb.sdp_tg_handle);
+      bta_ar_cb.sdp_tg_handle = 0;
+      bta_sys_remove_uuid(service_uuid);
+    }
+  } else if (service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL) {
+    if (bta_ar_cb.sdp_ct_handle) {
+      bta_ar_cb.ct_categories[mask - 1] = 0;
+      categories = bta_ar_cb.ct_categories[0] | bta_ar_cb.ct_categories[1];
+      if (!categories) {
+        /* no CT is still registered - cleaup */
+        SDP_DeleteRecord(bta_ar_cb.sdp_ct_handle);
+        bta_ar_cb.sdp_ct_handle = 0;
+        bta_sys_remove_uuid(service_uuid);
+      } else {
+        /* change supported categories to the remaning one */
+        p = temp;
+        UINT16_TO_BE_STREAM(p, categories);
+        SDP_AddAttribute(bta_ar_cb.sdp_ct_handle, ATTR_ID_SUPPORTED_FEATURES,
+                         UINT_DESC_TYPE, (uint32_t)2, (uint8_t*)temp);
+      }
+    }
+  }
+}
diff --git a/bt/bta/ar/bta_ar_int.h b/bt/bta/ar/bta_ar_int.h
new file mode 100644
index 0000000..679cd03
--- /dev/null
+++ b/bt/bta/ar/bta_ar_int.h
@@ -0,0 +1,66 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 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 is the private interface file for the BTA audio/video registration
+ *  module.
+ *
+ ******************************************************************************/
+#ifndef BTA_AR_INT_H
+#define BTA_AR_INT_H
+
+#include "bta_av_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef BTA_AR_DEBUG
+#define BTA_AR_DEBUG TRUE
+#endif
+
+#define BTA_AR_AV_MASK 0x01
+#define BTA_AR_AVK_MASK 0x02
+
+/* data associated with BTA_AR */
+typedef struct {
+  tAVDT_CTRL_CBACK* p_av_conn_cback;  /* av connection callback function */
+  tAVDT_CTRL_CBACK* p_avk_conn_cback; /* avk connection callback function */
+  uint8_t avdt_registered;
+  uint8_t avct_registered;
+  uint32_t sdp_tg_handle;
+  uint32_t sdp_ct_handle;
+  uint16_t ct_categories[2];
+  uint8_t tg_registered;
+  tBTA_AV_HNDL hndl; /* Handle associated with the stream that rejected the
+                        connection. */
+} tBTA_AR_CB;
+
+/*****************************************************************************
+ *  Global data
+ ****************************************************************************/
+
+/* control block declaration */
+extern tBTA_AR_CB bta_ar_cb;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_AR_INT_H */
diff --git a/bt/bta/av/bta_av_aact.cc b/bt/bta/av/bta_av_aact.cc
new file mode 100644
index 0000000..2b96534
--- /dev/null
+++ b/bt/bta/av/bta_av_aact.cc
@@ -0,0 +1,2954 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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 action functions for advanced audio/video stream
+ *  state machine. these functions are shared by both audio and video
+ *  streams.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include "avdt_api.h"
+#include "bt_utils.h"
+#include "bta_av_int.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+#include "utl.h"
+#include "vendor.h"
+
+#if (BTA_AR_INCLUDED == TRUE)
+#include "bta_ar_api.h"
+#endif
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+/* the delay time in milliseconds to start service discovery on AVRCP */
+#ifndef BTA_AV_RC_DISC_TIME_VAL
+#define BTA_AV_RC_DISC_TIME_VAL 3500
+#endif
+
+/* the timer in milliseconds to guard against link busy and AVDT_CloseReq failed
+ * to be sent */
+#ifndef BTA_AV_CLOSE_REQ_TIME_VAL
+#define BTA_AV_CLOSE_REQ_TIME_VAL 4000
+#endif
+
+/* number to retry on reconfigure failure - some headsets requirs this number to
+ * be more than 1 */
+#ifndef BTA_AV_RECONFIG_RETRY
+#define BTA_AV_RECONFIG_RETRY 6
+#endif
+
+/* ACL quota we are letting FW use for A2DP Offload Tx. */
+#define BTA_AV_A2DP_OFFLOAD_XMIT_QUOTA 4
+
+static void bta_av_st_rc_timer(tBTA_AV_SCB* p_scb,
+                               UNUSED_ATTR tBTA_AV_DATA* p_data);
+
+/* state machine states */
+enum {
+  BTA_AV_INIT_SST,
+  BTA_AV_INCOMING_SST,
+  BTA_AV_OPENING_SST,
+  BTA_AV_OPEN_SST,
+  BTA_AV_RCFG_SST,
+  BTA_AV_CLOSING_SST
+};
+
+/* the call out functions for audio stream */
+const tBTA_AV_CO_FUNCTS bta_av_a2dp_cos = {
+    bta_av_co_audio_init,          bta_av_co_audio_disc_res,
+    bta_av_co_audio_getconfig,     bta_av_co_audio_setconfig,
+    bta_av_co_audio_open,          bta_av_co_audio_close,
+    bta_av_co_audio_start,         bta_av_co_audio_stop,
+    bta_av_co_audio_src_data_path, bta_av_co_audio_delay};
+
+/* ssm action functions for audio stream */
+const tBTA_AV_SACT bta_av_a2dp_action[] = {
+    bta_av_do_disc_a2dp,    /* BTA_AV_DO_DISC  */
+    bta_av_cleanup,         /* BTA_AV_CLEANUP */
+    bta_av_free_sdb,        /* BTA_AV_FREE_SDB */
+    bta_av_config_ind,      /* BTA_AV_CONFIG_IND */
+    bta_av_disconnect_req,  /* BTA_AV_DISCONNECT_REQ */
+    bta_av_security_req,    /* BTA_AV_SECURITY_REQ */
+    bta_av_security_rsp,    /* BTA_AV_SECURITY_RSP */
+    bta_av_setconfig_rsp,   /* BTA_AV_SETCONFIG_RSP */
+    bta_av_st_rc_timer,     /* BTA_AV_ST_RC_TIMER */
+    bta_av_str_opened,      /* BTA_AV_STR_OPENED */
+    bta_av_security_ind,    /* BTA_AV_SECURITY_IND */
+    bta_av_security_cfm,    /* BTA_AV_SECURITY_CFM */
+    bta_av_do_close,        /* BTA_AV_DO_CLOSE */
+    bta_av_connect_req,     /* BTA_AV_CONNECT_REQ */
+    bta_av_sdp_failed,      /* BTA_AV_SDP_FAILED */
+    bta_av_disc_results,    /* BTA_AV_DISC_RESULTS */
+    bta_av_disc_res_as_acp, /* BTA_AV_DISC_RES_AS_ACP */
+    bta_av_open_failed,     /* BTA_AV_OPEN_FAILED */
+    bta_av_getcap_results,  /* BTA_AV_GETCAP_RESULTS */
+    bta_av_setconfig_rej,   /* BTA_AV_SETCONFIG_REJ */
+    bta_av_discover_req,    /* BTA_AV_DISCOVER_REQ */
+    bta_av_conn_failed,     /* BTA_AV_CONN_FAILED */
+    bta_av_do_start,        /* BTA_AV_DO_START */
+    bta_av_str_stopped,     /* BTA_AV_STR_STOPPED */
+    bta_av_reconfig,        /* BTA_AV_RECONFIG */
+    bta_av_data_path,       /* BTA_AV_DATA_PATH */
+    bta_av_start_ok,        /* BTA_AV_START_OK */
+    bta_av_start_failed,    /* BTA_AV_START_FAILED */
+    bta_av_str_closed,      /* BTA_AV_STR_CLOSED */
+    bta_av_clr_cong,        /* BTA_AV_CLR_CONG */
+    bta_av_suspend_cfm,     /* BTA_AV_SUSPEND_CFM */
+    bta_av_rcfg_str_ok,     /* BTA_AV_RCFG_STR_OK */
+    bta_av_rcfg_failed,     /* BTA_AV_RCFG_FAILED */
+    bta_av_rcfg_connect,    /* BTA_AV_RCFG_CONNECT */
+    bta_av_rcfg_discntd,    /* BTA_AV_RCFG_DISCNTD */
+    bta_av_suspend_cont,    /* BTA_AV_SUSPEND_CONT */
+    bta_av_rcfg_cfm,        /* BTA_AV_RCFG_CFM */
+    bta_av_rcfg_open,       /* BTA_AV_RCFG_OPEN */
+    bta_av_security_rej,    /* BTA_AV_SECURITY_REJ */
+    bta_av_open_rc,         /* BTA_AV_OPEN_RC */
+    bta_av_chk_2nd_start,   /* BTA_AV_CHK_2ND_START */
+    bta_av_save_caps,       /* BTA_AV_SAVE_CAPS */
+    bta_av_set_use_rc,      /* BTA_AV_SET_USE_RC */
+    bta_av_cco_close,       /* BTA_AV_CCO_CLOSE */
+    bta_av_switch_role,     /* BTA_AV_SWITCH_ROLE */
+    bta_av_role_res,        /* BTA_AV_ROLE_RES */
+    bta_av_delay_co,        /* BTA_AV_DELAY_CO */
+    bta_av_open_at_inc,     /* BTA_AV_OPEN_AT_INC */
+    bta_av_offload_req,     /* BTA_AV_OFFLOAD_REQ */
+    bta_av_offload_rsp,     /* BTA_AV_OFFLOAD_RSP */
+    NULL};
+
+/* these tables translate AVDT events to SSM events */
+static const uint16_t bta_av_stream_evt_ok[] = {
+    BTA_AV_STR_DISC_OK_EVT,      /* AVDT_DISCOVER_CFM_EVT */
+    BTA_AV_STR_GETCAP_OK_EVT,    /* AVDT_GETCAP_CFM_EVT */
+    BTA_AV_STR_OPEN_OK_EVT,      /* AVDT_OPEN_CFM_EVT */
+    BTA_AV_STR_OPEN_OK_EVT,      /* AVDT_OPEN_IND_EVT */
+    BTA_AV_STR_CONFIG_IND_EVT,   /* AVDT_CONFIG_IND_EVT */
+    BTA_AV_STR_START_OK_EVT,     /* AVDT_START_CFM_EVT */
+    BTA_AV_STR_START_OK_EVT,     /* AVDT_START_IND_EVT */
+    BTA_AV_STR_SUSPEND_CFM_EVT,  /* AVDT_SUSPEND_CFM_EVT */
+    BTA_AV_STR_SUSPEND_CFM_EVT,  /* AVDT_SUSPEND_IND_EVT */
+    BTA_AV_STR_CLOSE_EVT,        /* AVDT_CLOSE_CFM_EVT */
+    BTA_AV_STR_CLOSE_EVT,        /* AVDT_CLOSE_IND_EVT */
+    BTA_AV_STR_RECONFIG_CFM_EVT, /* AVDT_RECONFIG_CFM_EVT */
+    0,                           /* AVDT_RECONFIG_IND_EVT */
+    BTA_AV_STR_SECURITY_CFM_EVT, /* AVDT_SECURITY_CFM_EVT */
+    BTA_AV_STR_SECURITY_IND_EVT, /* AVDT_SECURITY_IND_EVT */
+    BTA_AV_STR_WRITE_CFM_EVT,    /* AVDT_WRITE_CFM_EVT */
+    BTA_AV_AVDT_CONNECT_EVT,     /* AVDT_CONNECT_IND_EVT */
+    BTA_AV_AVDT_DISCONNECT_EVT,  /* AVDT_DISCONNECT_IND_EVT */
+#if (AVDT_REPORTING == TRUE)
+    BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_CONN_EVT */
+    BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_DISCONN_EVT */
+#endif
+    BTA_AV_AVDT_DELAY_RPT_EVT, /* AVDT_DELAY_REPORT_EVT */
+    0                          /* AVDT_DELAY_REPORT_CFM_EVT */
+};
+
+static const uint16_t bta_av_stream_evt_fail[] = {
+    BTA_AV_STR_DISC_FAIL_EVT,    /* AVDT_DISCOVER_CFM_EVT */
+    BTA_AV_STR_GETCAP_FAIL_EVT,  /* AVDT_GETCAP_CFM_EVT */
+    BTA_AV_STR_OPEN_FAIL_EVT,    /* AVDT_OPEN_CFM_EVT */
+    BTA_AV_STR_OPEN_OK_EVT,      /* AVDT_OPEN_IND_EVT */
+    BTA_AV_STR_CONFIG_IND_EVT,   /* AVDT_CONFIG_IND_EVT */
+    BTA_AV_STR_START_FAIL_EVT,   /* AVDT_START_CFM_EVT */
+    BTA_AV_STR_START_OK_EVT,     /* AVDT_START_IND_EVT */
+    BTA_AV_STR_SUSPEND_CFM_EVT,  /* AVDT_SUSPEND_CFM_EVT */
+    BTA_AV_STR_SUSPEND_CFM_EVT,  /* AVDT_SUSPEND_IND_EVT */
+    BTA_AV_STR_CLOSE_EVT,        /* AVDT_CLOSE_CFM_EVT */
+    BTA_AV_STR_CLOSE_EVT,        /* AVDT_CLOSE_IND_EVT */
+    BTA_AV_STR_RECONFIG_CFM_EVT, /* AVDT_RECONFIG_CFM_EVT */
+    0,                           /* AVDT_RECONFIG_IND_EVT */
+    BTA_AV_STR_SECURITY_CFM_EVT, /* AVDT_SECURITY_CFM_EVT */
+    BTA_AV_STR_SECURITY_IND_EVT, /* AVDT_SECURITY_IND_EVT */
+    BTA_AV_STR_WRITE_CFM_EVT,    /* AVDT_WRITE_CFM_EVT */
+    BTA_AV_AVDT_CONNECT_EVT,     /* AVDT_CONNECT_IND_EVT */
+    BTA_AV_AVDT_DISCONNECT_EVT,  /* AVDT_DISCONNECT_IND_EVT */
+#if (AVDT_REPORTING == TRUE)
+    BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_CONN_EVT */
+    BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_DISCONN_EVT */
+#endif
+    BTA_AV_AVDT_DELAY_RPT_EVT, /* AVDT_DELAY_REPORT_EVT */
+    0                          /* AVDT_DELAY_REPORT_CFM_EVT */
+};
+
+static void bta_av_stream0_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+                                 tAVDT_CTRL* p_data);
+static void bta_av_stream1_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+                                 tAVDT_CTRL* p_data);
+#if BTA_AV_NUM_STRS > 2
+static void bta_av_stream2_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+                                 tAVDT_CTRL* p_data);
+#endif
+#if BTA_AV_NUM_STRS > 3
+static void bta_av_stream3_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+                                 tAVDT_CTRL* p_data);
+#endif
+#if BTA_AV_NUM_STRS > 4
+static void bta_av_stream4_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+                                 tAVDT_CTRL* p_data);
+#endif
+#if BTA_AV_NUM_STRS > 5
+static void bta_av_stream5_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+                                 tAVDT_CTRL* p_data);
+#endif
+/* the array of callback functions to receive events from AVDT control channel
+ */
+tAVDT_CTRL_CBACK* const bta_av_dt_cback[] = {bta_av_stream0_cback,
+                                             bta_av_stream1_cback
+#if BTA_AV_NUM_STRS > 2
+                                             ,
+                                             bta_av_stream2_cback
+#endif
+#if BTA_AV_NUM_STRS > 3
+                                             ,
+                                             bta_av_stream3_cback
+#endif
+#if BTA_AV_NUM_STRS > 4
+                                             ,
+                                             bta_av_stream4_cback
+#endif
+#if BTA_AV_NUM_STRS > 5
+                                             ,
+                                             bta_av_stream5_cback
+#endif
+};
+/***********************************************
+ *
+ * Function         bta_get_scb_handle
+ *
+ * Description      gives the registered AVDT handle.by checking with sep_type.
+ *
+ *
+ * Returns          void
+ **********************************************/
+static uint8_t bta_av_get_scb_handle(tBTA_AV_SCB* p_scb, uint8_t local_sep) {
+  for (int i = 0; i < A2DP_CODEC_SEP_INDEX_MAX; i++) {
+    if ((p_scb->seps[i].tsep == local_sep) &&
+        A2DP_CodecTypeEquals(p_scb->seps[i].codec_info,
+                             p_scb->cfg.codec_info)) {
+      return (p_scb->seps[i].av_handle);
+    }
+  }
+  APPL_TRACE_DEBUG("%s: local sep_type %d not found", __func__, local_sep)
+  return 0; /* return invalid handle */
+}
+
+/***********************************************
+ *
+ * Function         bta_av_get_scb_sep_type
+ *
+ * Description      gives the sep type by cross-checking with AVDT handle
+ *
+ *
+ * Returns          void
+ **********************************************/
+static uint8_t bta_av_get_scb_sep_type(tBTA_AV_SCB* p_scb,
+                                       uint8_t tavdt_handle) {
+  for (int i = 0; i < A2DP_CODEC_SEP_INDEX_MAX; i++) {
+    if (p_scb->seps[i].av_handle == tavdt_handle) return (p_scb->seps[i].tsep);
+  }
+  APPL_TRACE_DEBUG("%s: handle %d not found", __func__, tavdt_handle)
+  return AVDT_TSEP_INVALID;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_save_addr
+ *
+ * Description      copy the bd_addr and maybe reset the supported flags
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_av_save_addr(tBTA_AV_SCB* p_scb, const BD_ADDR b) {
+  APPL_TRACE_DEBUG("%s: r:%d, s:%d", __func__, p_scb->recfg_sup,
+                   p_scb->suspend_sup);
+  if (bdcmp(p_scb->peer_addr, b) != 0) {
+    APPL_TRACE_ERROR("%s: reset flags", __func__);
+    /* a new addr, reset the supported flags */
+    p_scb->recfg_sup = true;
+    p_scb->suspend_sup = true;
+  }
+
+  /* do this copy anyway, just in case the first addr matches
+   * the control block one by accident */
+  bdcpy(p_scb->peer_addr, b);
+}
+
+/*******************************************************************************
+ *
+ * Function         notify_start_failed
+ *
+ * Description      notify up-layer AV start failed
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void notify_start_failed(tBTA_AV_SCB* p_scb) {
+  tBTA_AV_START start;
+  /* if start failed, clear role */
+  p_scb->role &= ~BTA_AV_ROLE_START_INT;
+  start.chnl = p_scb->chnl;
+  start.status = BTA_AV_FAIL;
+  start.initiator = true;
+  start.hndl = p_scb->hndl;
+  (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV*)&start);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_st_rc_timer
+ *
+ * Description      start the AVRC timer if no RC connection & CT is supported &
+ *                  RC is used or
+ *                  as ACP (we do not really know if we want AVRC)
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_av_st_rc_timer(tBTA_AV_SCB* p_scb,
+                               UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  APPL_TRACE_DEBUG("%s: rc_handle:%d, use_rc: %d", __func__, p_scb->rc_handle,
+                   p_scb->use_rc);
+  /* for outgoing RC connection as INT/CT */
+  if ((p_scb->rc_handle == BTA_AV_RC_HANDLE_NONE) &&
+      /* (bta_av_cb.features & BTA_AV_FEAT_RCCT) && */
+      (p_scb->use_rc == true || (p_scb->role & BTA_AV_ROLE_AD_ACP))) {
+    if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) == 0) {
+      bta_sys_start_timer(p_scb->avrc_ct_timer, BTA_AV_RC_DISC_TIME_VAL,
+                          BTA_AV_AVRC_TIMER_EVT, p_scb->hndl);
+    } else {
+      p_scb->wait |= BTA_AV_WAIT_CHECK_RC;
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_next_getcap
+ *
+ * Description      The function gets the capabilities of the next available
+ *                  stream found in the discovery results.
+ *
+ * Returns          true if we sent request to AVDT, false otherwise.
+ *
+ ******************************************************************************/
+static bool bta_av_next_getcap(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  int i;
+  tAVDT_GETCAP_REQ* p_req;
+  bool sent_cmd = false;
+  uint16_t uuid_int = p_scb->uuid_int;
+  uint8_t sep_requested = 0;
+
+  if (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE)
+    sep_requested = AVDT_TSEP_SNK;
+  else if (uuid_int == UUID_SERVCLASS_AUDIO_SINK)
+    sep_requested = AVDT_TSEP_SRC;
+
+  for (i = p_scb->sep_info_idx; i < p_scb->num_seps; i++) {
+    /* steam not in use, is a sink, and is the right media type (audio/video) */
+    if ((p_scb->sep_info[i].in_use == false) &&
+        (p_scb->sep_info[i].tsep == sep_requested) &&
+        (p_scb->sep_info[i].media_type == p_scb->media_type)) {
+      p_scb->sep_info_idx = i;
+
+      /* we got a stream; get its capabilities */
+      if (p_scb->p_cap == NULL)
+        p_scb->p_cap = (tAVDT_CFG*)osi_malloc(sizeof(tAVDT_CFG));
+      if (p_scb->avdt_version >= AVDT_VERSION_SYNC) {
+        p_req = AVDT_GetAllCapReq;
+      } else {
+        p_req = AVDT_GetCapReq;
+      }
+      (*p_req)(p_scb->peer_addr, p_scb->sep_info[i].seid, p_scb->p_cap,
+               bta_av_dt_cback[p_scb->hdi]);
+      sent_cmd = true;
+      break;
+    }
+  }
+
+  /* if no streams available then stream open fails */
+  if (!sent_cmd) {
+    bta_av_ssm_execute(p_scb, BTA_AV_STR_GETCAP_FAIL_EVT, p_data);
+  }
+
+  return sent_cmd;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_proc_stream_evt
+ *
+ * Description      Utility function to compose stream events.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_av_proc_stream_evt(uint8_t handle, BD_ADDR bd_addr,
+                                   uint8_t event, tAVDT_CTRL* p_data,
+                                   int index) {
+  uint16_t sec_len = 0;
+  tBTA_AV_SCB* p_scb = bta_av_cb.p_scb[index];
+
+  if (p_data) {
+    if (event == AVDT_SECURITY_IND_EVT) {
+      sec_len = (p_data->security_ind.len < BTA_AV_SECURITY_MAX_LEN)
+                    ? p_data->security_ind.len
+                    : BTA_AV_SECURITY_MAX_LEN;
+    } else if (event == AVDT_SECURITY_CFM_EVT && p_data->hdr.err_code == 0) {
+      sec_len = (p_data->security_cfm.len < BTA_AV_SECURITY_MAX_LEN)
+                    ? p_data->security_cfm.len
+                    : BTA_AV_SECURITY_MAX_LEN;
+    }
+  }
+
+  if (p_scb) {
+    tBTA_AV_STR_MSG* p_msg =
+        (tBTA_AV_STR_MSG*)osi_malloc(sizeof(tBTA_AV_STR_MSG) + sec_len);
+
+    /* copy event data, bd addr, and handle to event message buffer */
+    p_msg->hdr.offset = 0;
+
+    if (bd_addr != NULL) {
+      bdcpy(p_msg->bd_addr, bd_addr);
+      APPL_TRACE_DEBUG("%s: bd_addr:%02x-%02x-%02x-%02x-%02x-%02x", __func__,
+                       bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3],
+                       bd_addr[4], bd_addr[5]);
+    }
+
+    if (p_data != NULL) {
+      memcpy(&p_msg->msg, p_data, sizeof(tAVDT_CTRL));
+      /* copy config params to event message buffer */
+      switch (event) {
+        case AVDT_RECONFIG_CFM_EVT:
+          APPL_TRACE_DEBUG(
+              "%s: reconfig cfm event codec info = 0x%06x-%06x-%06x-%02x",
+              __func__,
+              (p_msg->msg.reconfig_cfm.p_cfg->codec_info[0] << 16) +
+                  (p_msg->msg.reconfig_cfm.p_cfg->codec_info[1] << 8) +
+                  p_msg->msg.reconfig_cfm.p_cfg->codec_info[2],
+              (p_msg->msg.reconfig_cfm.p_cfg->codec_info[3] << 16) +
+                  (p_msg->msg.reconfig_cfm.p_cfg->codec_info[4] << 8) +
+                  p_msg->msg.reconfig_cfm.p_cfg->codec_info[5],
+              (p_msg->msg.reconfig_cfm.p_cfg->codec_info[6] << 16) +
+                  (p_msg->msg.reconfig_cfm.p_cfg->codec_info[7] << 8) +
+                  p_msg->msg.reconfig_cfm.p_cfg->codec_info[8],
+              p_msg->msg.reconfig_cfm.p_cfg->codec_info[9]);
+          break;
+
+        case AVDT_CONFIG_IND_EVT:
+          /* We might have 2 SEP signallings(A2DP + VDP) with one peer device on
+           * one L2CAP.
+           * If we already have a signalling connection with the bd_addr and the
+           * streaming
+           * SST is at INIT state, change it to INCOMING state to handle the
+           * signalling
+           * from the 2nd SEP. */
+          if ((bta_av_find_lcb(bd_addr, BTA_AV_LCB_FIND) != NULL) &&
+              (bta_av_is_scb_init(p_scb))) {
+            bta_av_set_scb_sst_incoming(p_scb);
+
+            /* When ACP_CONNECT_EVT was received, we put first available scb to
+             * incoming state.
+             * Later when we receive AVDT_CONFIG_IND_EVT, we use a new p_scb and
+             * set its state to
+             * incoming which we do it above.
+             * We also have to set the old p_scb state to init to be used later
+             */
+            for (int i = 0; i < BTA_AV_NUM_STRS; i++) {
+              if ((bta_av_cb.p_scb[i]) && (i != index)) {
+                if (bta_av_cb.p_scb[i]->state == BTA_AV_INCOMING_SST) {
+                  bta_av_cb.p_scb[i]->state = BTA_AV_INIT_SST;
+                  bta_av_cb.p_scb[i]->coll_mask = 0;
+                  break;
+                }
+              }
+            }
+          }
+
+          memcpy(&p_msg->cfg, p_data->config_ind.p_cfg, sizeof(tAVDT_CFG));
+          break;
+
+        case AVDT_SECURITY_IND_EVT:
+          p_msg->msg.security_ind.p_data = (uint8_t*)(p_msg + 1);
+          memcpy(p_msg->msg.security_ind.p_data, p_data->security_ind.p_data,
+                 sec_len);
+          break;
+
+        case AVDT_SECURITY_CFM_EVT:
+          p_msg->msg.security_cfm.p_data = (uint8_t*)(p_msg + 1);
+          if (p_data->hdr.err_code == 0) {
+            memcpy(p_msg->msg.security_cfm.p_data, p_data->security_cfm.p_data,
+                   sec_len);
+          }
+          break;
+
+        case AVDT_SUSPEND_IND_EVT:
+          p_msg->msg.hdr.err_code = 0;
+          break;
+
+        case AVDT_CONNECT_IND_EVT:
+          p_scb->recfg_sup = true;
+          p_scb->suspend_sup = true;
+          break;
+
+        default:
+          break;
+      }
+    } else
+      p_msg->msg.hdr.err_code = 0;
+
+    /* look up application event */
+    if ((p_data == NULL) || (p_data->hdr.err_code == 0)) {
+      p_msg->hdr.event = bta_av_stream_evt_ok[event];
+    } else {
+      p_msg->hdr.event = bta_av_stream_evt_fail[event];
+    }
+
+    p_msg->initiator = false;
+    if (event == AVDT_SUSPEND_CFM_EVT) p_msg->initiator = true;
+
+    APPL_TRACE_VERBOSE("%s: hndl:x%x", __func__, p_scb->hndl);
+    p_msg->hdr.layer_specific = p_scb->hndl;
+    p_msg->handle = handle;
+    p_msg->avdt_event = event;
+    bta_sys_sendmsg(p_msg);
+  }
+
+  /* coverity[var_deref_model] */
+  /* false-positive: bta_av_conn_cback only processes AVDT_CONNECT_IND_EVT and
+   * AVDT_DISCONNECT_IND_EVT event
+   *                 these 2 events always have associated p_data */
+  if (p_data) {
+    bta_av_conn_cback(handle, bd_addr, event, p_data);
+  } else {
+    APPL_TRACE_ERROR("%s: p_data is null", __func__);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_sink_data_cback
+ *
+ * Description      This is the AVDTP callback function for sink stream events.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_sink_data_cback(uint8_t handle, BT_HDR* p_pkt, uint32_t time_stamp,
+                            uint8_t m_pt) {
+  int index = 0;
+  tBTA_AV_SCB* p_scb;
+  APPL_TRACE_DEBUG(
+      "%s: avdt_handle: %d pkt_len=0x%x  offset = 0x%x "
+      "number of frames 0x%x sequence number 0x%x",
+      __func__, handle, p_pkt->len, p_pkt->offset,
+      *((uint8_t*)(p_pkt + 1) + p_pkt->offset), p_pkt->layer_specific);
+  /* Get SCB and correct sep type */
+  for (index = 0; index < BTA_AV_NUM_STRS; index++) {
+    p_scb = bta_av_cb.p_scb[index];
+    if ((p_scb->avdt_handle == handle) &&
+        (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK)) {
+      break;
+    }
+  }
+  if (index == BTA_AV_NUM_STRS) {
+    /* cannot find correct handler */
+    osi_free(p_pkt);
+    return;
+  }
+  p_pkt->event = BTA_AV_SINK_MEDIA_DATA_EVT;
+  p_scb->seps[p_scb->sep_idx].p_app_sink_data_cback(BTA_AV_SINK_MEDIA_DATA_EVT,
+                                                    (tBTA_AV_MEDIA*)p_pkt);
+  /* Free the buffer: a copy of the packet has been delivered */
+  osi_free(p_pkt);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_stream0_cback
+ *
+ * Description      This is the AVDTP callback function for stream events.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_av_stream0_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+                                 tAVDT_CTRL* p_data) {
+  APPL_TRACE_VERBOSE("%s: avdt_handle: %d event=0x%x", __func__, handle, event);
+  bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 0);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_stream1_cback
+ *
+ * Description      This is the AVDTP callback function for stream events.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_av_stream1_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+                                 tAVDT_CTRL* p_data) {
+  APPL_TRACE_EVENT("%s: avdt_handle: %d event=0x%x", __func__, handle, event);
+  bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 1);
+}
+
+#if BTA_AV_NUM_STRS > 2
+/*******************************************************************************
+ *
+ * Function         bta_av_stream2_cback
+ *
+ * Description      This is the AVDTP callback function for stream events.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_av_stream2_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+                                 tAVDT_CTRL* p_data) {
+  APPL_TRACE_EVENT("%s: avdt_handle: %d event=0x%x", __func__, handle, event);
+  bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 2);
+}
+#endif
+
+#if BTA_AV_NUM_STRS > 3
+/*******************************************************************************
+ *
+ * Function         bta_av_stream3_cback
+ *
+ * Description      This is the AVDTP callback function for stream events.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_av_stream3_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+                                 tAVDT_CTRL* p_data) {
+  APPL_TRACE_EVENT("%s: avdt_handle: %d event=0x%x", __func__, handle, event);
+  bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 3);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_av_stream4_cback
+ *
+ * Description      This is the AVDTP callback function for stream events.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+#if BTA_AV_NUM_STRS > 4
+static void bta_av_stream4_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+                                 tAVDT_CTRL* p_data) {
+  APPL_TRACE_EVENT("%s: avdt_handle: %d event=0x%x", __func__, handle, event);
+  bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 4);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_av_stream5_cback
+ *
+ * Description      This is the AVDTP callback function for stream events.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+#if BTA_AV_NUM_STRS > 5
+static void bta_av_stream5_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+                                 tAVDT_CTRL* p_data) {
+  APPL_TRACE_EVENT("%s: avdt_handle: %d event=0x%x", __func__, handle, event);
+  bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 5);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_av_a2dp_sdp_cback
+ *
+ * Description      A2DP service discovery callback.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_av_a2dp_sdp_cback(bool found, tA2DP_Service* p_service) {
+  tBTA_AV_SCB* p_scb = bta_av_hndl_to_scb(bta_av_cb.handle);
+
+  if (p_scb == NULL) {
+    APPL_TRACE_ERROR("%s: no scb found for handle(0x%x)", __func__,
+                     bta_av_cb.handle);
+    return;
+  }
+
+  tBTA_AV_SDP_RES* p_msg =
+      (tBTA_AV_SDP_RES*)osi_malloc(sizeof(tBTA_AV_SDP_RES));
+  p_msg->hdr.event =
+      (found) ? BTA_AV_SDP_DISC_OK_EVT : BTA_AV_SDP_DISC_FAIL_EVT;
+  if (found && (p_service != NULL))
+    p_scb->avdt_version = p_service->avdt_version;
+  else
+    p_scb->avdt_version = 0x00;
+  p_msg->hdr.layer_specific = bta_av_cb.handle;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_adjust_seps_idx
+ *
+ * Description      adjust the sep_idx
+ *
+ * Returns
+ *
+ ******************************************************************************/
+static void bta_av_adjust_seps_idx(tBTA_AV_SCB* p_scb, uint8_t avdt_handle) {
+  APPL_TRACE_DEBUG("%s: codec: %s", __func__,
+                   A2DP_CodecName(p_scb->cfg.codec_info));
+  for (int i = 0; i < A2DP_CODEC_SEP_INDEX_MAX; i++) {
+    APPL_TRACE_DEBUG("%s: av_handle: %d codec: %s", __func__,
+                     p_scb->seps[i].av_handle,
+                     A2DP_CodecName(p_scb->seps[i].codec_info));
+    if (p_scb->seps[i].av_handle && (p_scb->seps[i].av_handle == avdt_handle) &&
+        A2DP_CodecTypeEquals(p_scb->seps[i].codec_info,
+                             p_scb->cfg.codec_info)) {
+      p_scb->sep_idx = i;
+      p_scb->avdt_handle = p_scb->seps[i].av_handle;
+      break;
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_switch_role
+ *
+ * Description      Switch role was not started and a timer was started.
+ *                  another attempt to switch role now - still opening.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_switch_role(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  tBTA_AV_RS_RES switch_res = BTA_AV_RS_NONE;
+  tBTA_AV_API_OPEN* p_buf = &p_scb->q_info.open;
+
+  APPL_TRACE_DEBUG("%s: wait:x%x", __func__, p_scb->wait);
+  if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_START)
+    p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RETRY;
+
+  /* clear the masks set when the timer is started */
+  p_scb->wait &=
+      ~(BTA_AV_WAIT_ROLE_SW_RES_OPEN | BTA_AV_WAIT_ROLE_SW_RES_START);
+
+  if (p_scb->q_tag == BTA_AV_Q_TAG_OPEN) {
+    if (bta_av_switch_if_needed(p_scb) ||
+        !bta_av_link_role_ok(p_scb, A2DP_SET_MULTL_BIT)) {
+      p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_OPEN;
+    } else {
+      /* this should not happen in theory. Just in case...
+       * continue to do_disc_a2dp */
+      switch_res = BTA_AV_RS_DONE;
+    }
+  } else {
+    /* report failure on OPEN */
+    switch_res = BTA_AV_RS_FAIL;
+  }
+
+  if (switch_res != BTA_AV_RS_NONE) {
+    if (bta_av_cb.rs_idx == (p_scb->hdi + 1)) {
+      bta_av_cb.rs_idx = 0;
+    }
+    p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_RETRY;
+    p_scb->q_tag = 0;
+    p_buf->switch_res = switch_res;
+    bta_av_do_disc_a2dp(p_scb, (tBTA_AV_DATA*)p_buf);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_role_res
+ *
+ * Description      Handle the role changed event
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_role_res(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  bool initiator = false;
+  tBTA_AV_START start;
+  tBTA_AV_OPEN av_open;
+
+  APPL_TRACE_DEBUG("%s: q_tag:%d, wait:x%x, role:x%x", __func__, p_scb->q_tag,
+                   p_scb->wait, p_scb->role);
+  if (p_scb->role & BTA_AV_ROLE_START_INT) initiator = true;
+
+  if (p_scb->q_tag == BTA_AV_Q_TAG_START) {
+    if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_STARTED) {
+      p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+      if (p_data->role_res.hci_status != HCI_SUCCESS) {
+        p_scb->role &= ~BTA_AV_ROLE_START_INT;
+        bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+        /* start failed because of role switch. */
+        start.chnl = p_scb->chnl;
+        start.status = BTA_AV_FAIL_ROLE;
+        start.hndl = p_scb->hndl;
+        start.initiator = initiator;
+        (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV*)&start);
+      } else {
+        bta_av_start_ok(p_scb, p_data);
+      }
+    } else if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_START)
+      p_scb->wait |= BTA_AV_WAIT_ROLE_SW_FAILED;
+  } else if (p_scb->q_tag == BTA_AV_Q_TAG_OPEN) {
+    if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_OPEN) {
+      p_scb->role &= ~BTA_AV_ROLE_START_INT;
+      p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+
+      if (p_data->role_res.hci_status != HCI_SUCCESS) {
+        /* Open failed because of role switch. */
+        bdcpy(av_open.bd_addr, p_scb->peer_addr);
+        av_open.chnl = p_scb->chnl;
+        av_open.hndl = p_scb->hndl;
+        start.status = BTA_AV_FAIL_ROLE;
+        if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC)
+          av_open.sep = AVDT_TSEP_SNK;
+        else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK)
+          av_open.sep = AVDT_TSEP_SRC;
+        (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV*)&av_open);
+      } else {
+        /* Continue av open process */
+        p_scb->q_info.open.switch_res = BTA_AV_RS_DONE;
+        bta_av_do_disc_a2dp(p_scb, (tBTA_AV_DATA*)&(p_scb->q_info.open));
+      }
+    } else {
+      APPL_TRACE_WARNING(
+          "%s: unexpected role switch event: q_tag = %d wait = %d", __func__,
+          p_scb->q_tag, p_scb->wait);
+    }
+  }
+
+  APPL_TRACE_DEBUG("%s: wait:x%x, role:x%x", __func__, p_scb->wait,
+                   p_scb->role);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_delay_co
+ *
+ * Description      Call the delay call-out function to report the delay report
+ *                  from SNK
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_delay_co(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  p_scb->p_cos->delay(p_scb->hndl, p_data->str_msg.msg.delay_rpt_cmd.delay);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_do_disc_a2dp
+ *
+ * Description      Do service discovery for A2DP.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_do_disc_a2dp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  bool ok_continue = false;
+  tA2DP_SDP_DB_PARAMS db_params;
+  uint16_t attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST,
+                          ATTR_ID_PROTOCOL_DESC_LIST,
+                          ATTR_ID_BT_PROFILE_DESC_LIST};
+  uint16_t sdp_uuid = 0; /* UUID for which SDP has to be done */
+
+  APPL_TRACE_DEBUG("%s: use_rc: %d rs:%d, oc:%d", __func__,
+                   p_data->api_open.use_rc, p_data->api_open.switch_res,
+                   bta_av_cb.audio_open_cnt);
+
+  memcpy(&(p_scb->open_api), &(p_data->api_open), sizeof(tBTA_AV_API_OPEN));
+
+  switch (p_data->api_open.switch_res) {
+    case BTA_AV_RS_NONE:
+      if (bta_av_switch_if_needed(p_scb) ||
+          !bta_av_link_role_ok(p_scb, A2DP_SET_MULTL_BIT)) {
+        /* waiting for role switch result. save the api to control block */
+        memcpy(&p_scb->q_info.open, &p_data->api_open,
+               sizeof(tBTA_AV_API_OPEN));
+        p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_OPEN;
+        p_scb->q_tag = BTA_AV_Q_TAG_OPEN;
+      } else {
+        ok_continue = true;
+      }
+      break;
+
+    case BTA_AV_RS_FAIL:
+      /* report a new failure event  */
+      p_scb->open_status = BTA_AV_FAIL_ROLE;
+      bta_av_ssm_execute(p_scb, BTA_AV_SDP_DISC_FAIL_EVT, NULL);
+      break;
+
+    case BTA_AV_RS_OK:
+      p_data = (tBTA_AV_DATA*)&p_scb->q_info.open;
+      /* continue to open if link role is ok */
+      if (bta_av_link_role_ok(p_scb, A2DP_SET_MULTL_BIT)) {
+        ok_continue = true;
+      } else {
+        p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_OPEN;
+      }
+      break;
+
+    case BTA_AV_RS_DONE:
+      ok_continue = true;
+      break;
+  }
+
+  APPL_TRACE_DEBUG("%s: ok_continue: %d wait:x%x, q_tag: %d", __func__,
+                   ok_continue, p_scb->wait, p_scb->q_tag);
+  if (!ok_continue) return;
+
+  /* clear the role switch bits */
+  p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+
+  if (p_scb->wait & BTA_AV_WAIT_CHECK_RC) {
+    p_scb->wait &= ~BTA_AV_WAIT_CHECK_RC;
+    bta_sys_start_timer(p_scb->avrc_ct_timer, BTA_AV_RC_DISC_TIME_VAL,
+                        BTA_AV_AVRC_TIMER_EVT, p_scb->hndl);
+  }
+
+  if (bta_av_cb.features & BTA_AV_FEAT_MASTER) {
+    L2CA_SetDesireRole(L2CAP_ROLE_DISALLOW_SWITCH);
+
+    if (bta_av_cb.audio_open_cnt == 1) {
+      /* there's already an A2DP connection. do not allow switch */
+      bta_sys_clear_default_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH);
+    }
+  }
+  /* store peer addr other parameters */
+  bta_av_save_addr(p_scb, p_data->api_open.bd_addr);
+  p_scb->sec_mask = p_data->api_open.sec_mask;
+  p_scb->use_rc = p_data->api_open.use_rc;
+
+  bta_sys_app_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+
+  if (p_scb->skip_sdp == true) {
+    tA2DP_Service a2dp_ser;
+    a2dp_ser.avdt_version = AVDT_VERSION;
+    p_scb->skip_sdp = false;
+    p_scb->uuid_int = p_data->api_open.uuid;
+    /* only one A2DP find service is active at a time */
+    bta_av_cb.handle = p_scb->hndl;
+    APPL_TRACE_WARNING("%s: Skip Sdp for incoming A2dp connection", __func__);
+    bta_av_a2dp_sdp_cback(true, &a2dp_ser);
+    return;
+  }
+
+  /* only one A2DP find service is active at a time */
+  bta_av_cb.handle = p_scb->hndl;
+
+  /* set up parameters */
+  db_params.db_len = BTA_AV_DISC_BUF_SIZE;
+  db_params.num_attr = 3;
+  db_params.p_attrs = attr_list;
+  p_scb->uuid_int = p_data->api_open.uuid;
+  p_scb->sdp_discovery_started = true;
+  if (p_scb->uuid_int == UUID_SERVCLASS_AUDIO_SINK)
+    sdp_uuid = UUID_SERVCLASS_AUDIO_SOURCE;
+  else if (p_scb->uuid_int == UUID_SERVCLASS_AUDIO_SOURCE)
+    sdp_uuid = UUID_SERVCLASS_AUDIO_SINK;
+
+  APPL_TRACE_DEBUG("%s: uuid_int 0x%x, Doing SDP For 0x%x", __func__,
+                   p_scb->uuid_int, sdp_uuid);
+  if (A2DP_FindService(sdp_uuid, p_scb->peer_addr, &db_params,
+                       bta_av_a2dp_sdp_cback) == A2DP_SUCCESS)
+    return;
+
+  /* when the code reaches here, either the DB is NULL
+   * or A2DP_FindService is not successful */
+  bta_av_a2dp_sdp_cback(false, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_cleanup
+ *
+ * Description      cleanup AV stream control block.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_cleanup(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  tBTA_AV_CONN_CHG msg;
+  uint8_t role = BTA_AV_ROLE_AD_INT;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  /* free any buffers */
+  osi_free_and_reset((void**)&p_scb->p_cap);
+  p_scb->sdp_discovery_started = false;
+  p_scb->avdt_version = 0;
+
+  /* initialize some control block variables */
+  p_scb->open_status = BTA_AV_SUCCESS;
+
+  /* if de-registering shut everything down */
+  msg.hdr.layer_specific = p_scb->hndl;
+  p_scb->started = false;
+  p_scb->cong = false;
+  p_scb->role = role;
+  p_scb->cur_psc_mask = 0;
+  p_scb->wait = 0;
+  p_scb->num_disc_snks = 0;
+  alarm_cancel(p_scb->avrc_ct_timer);
+
+  vendor_get_interface()->send_command(
+      (vendor_opcode_t)BT_VND_OP_A2DP_OFFLOAD_STOP, (void*)&p_scb->l2c_cid);
+  if (p_scb->offload_start_pending) {
+    tBTA_AV_STATUS status = BTA_AV_FAIL_STREAM;
+    (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, (tBTA_AV*)&status);
+  }
+  p_scb->offload_start_pending = false;
+
+  p_scb->skip_sdp = false;
+  if (p_scb->deregistring) {
+    /* remove stream */
+    for (int i = 0; i < A2DP_CODEC_SEP_INDEX_MAX; i++) {
+      if (p_scb->seps[i].av_handle) AVDT_RemoveStream(p_scb->seps[i].av_handle);
+      p_scb->seps[i].av_handle = 0;
+    }
+
+    bta_av_dereg_comp((tBTA_AV_DATA*)&msg);
+  } else {
+    /* report stream closed to main SM */
+    msg.is_up = false;
+    bdcpy(msg.peer_addr, p_scb->peer_addr);
+    bta_av_conn_chg((tBTA_AV_DATA*)&msg);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_free_sdb
+ *
+ * Description      Free service discovery db buffer.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_free_sdb(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  p_scb->sdp_discovery_started = false;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_config_ind
+ *
+ * Description      Handle a stream configuration indication from the peer.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_config_ind(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  tBTA_AV_CI_SETCONFIG setconfig;
+  tAVDT_SEP_INFO* p_info;
+  tAVDT_CFG* p_evt_cfg = &p_data->str_msg.cfg;
+  uint8_t psc_mask = (p_evt_cfg->psc_mask | p_scb->cfg.psc_mask);
+  uint8_t
+      local_sep; /* sep type of local handle on which connection was received */
+  tBTA_AV_STR_MSG* p_msg = (tBTA_AV_STR_MSG*)p_data;
+
+  local_sep = bta_av_get_scb_sep_type(p_scb, p_msg->handle);
+  p_scb->avdt_label = p_data->str_msg.msg.hdr.label;
+  memcpy(p_scb->cfg.codec_info, p_evt_cfg->codec_info, AVDT_CODEC_SIZE);
+  bta_av_save_addr(p_scb, p_data->str_msg.bd_addr);
+
+  /* Clear collision mask */
+  p_scb->coll_mask = 0;
+  alarm_cancel(bta_av_cb.accept_signalling_timer);
+
+  /* if no codec parameters in configuration, fail */
+  if ((p_evt_cfg->num_codec == 0) ||
+      /* or the peer requests for a service we do not support */
+      ((psc_mask != p_scb->cfg.psc_mask) &&
+       (psc_mask != (p_scb->cfg.psc_mask & ~AVDT_PSC_DELAY_RPT)))) {
+    setconfig.hndl = p_scb->hndl; /* we may not need this */
+    setconfig.err_code = AVDT_ERR_UNSUP_CFG;
+    bta_av_ssm_execute(p_scb, BTA_AV_CI_SETCONFIG_FAIL_EVT,
+                       (tBTA_AV_DATA*)&setconfig);
+  } else {
+    p_info = &p_scb->sep_info[0];
+    p_info->in_use = 0;
+    p_info->media_type = p_scb->media_type;
+    p_info->seid = p_data->str_msg.msg.config_ind.int_seid;
+
+    /* Sep type of Peer will be oppsite role to our local sep */
+    if (local_sep == AVDT_TSEP_SRC)
+      p_info->tsep = AVDT_TSEP_SNK;
+    else if (local_sep == AVDT_TSEP_SNK)
+      p_info->tsep = AVDT_TSEP_SRC;
+
+    p_scb->role |= BTA_AV_ROLE_AD_ACP;
+    p_scb->cur_psc_mask = p_evt_cfg->psc_mask;
+    if (bta_av_cb.features & BTA_AV_FEAT_RCTG)
+      p_scb->use_rc = true;
+    else
+      p_scb->use_rc = false;
+
+    p_scb->num_seps = 1;
+    p_scb->sep_info_idx = 0;
+    APPL_TRACE_DEBUG("%s: SEID: %d use_rc: %d cur_psc_mask:0x%x", __func__,
+                     p_info->seid, p_scb->use_rc, p_scb->cur_psc_mask);
+    /*  in case of A2DP SINK this is the first time peer data is being sent to
+     * co functions */
+    if (local_sep == AVDT_TSEP_SNK) {
+      p_scb->p_cos->setcfg(p_scb->hndl, p_evt_cfg->codec_info, p_info->seid,
+                           p_scb->peer_addr, p_evt_cfg->num_protect,
+                           p_evt_cfg->protect_info, AVDT_TSEP_SNK,
+                           p_msg->handle);
+    } else {
+      p_scb->p_cos->setcfg(p_scb->hndl, p_evt_cfg->codec_info, p_info->seid,
+                           p_scb->peer_addr, p_evt_cfg->num_protect,
+                           p_evt_cfg->protect_info, AVDT_TSEP_SRC,
+                           p_msg->handle);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_disconnect_req
+ *
+ * Description      Disconnect AVDTP connection.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_disconnect_req(tBTA_AV_SCB* p_scb,
+                           UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  tBTA_AV_RCB* p_rcb;
+
+  APPL_TRACE_DEBUG("%s: conn_lcb: 0x%x", __func__, bta_av_cb.conn_lcb);
+
+  alarm_cancel(bta_av_cb.link_signalling_timer);
+  alarm_cancel(p_scb->avrc_ct_timer);
+
+  if (bta_av_cb.conn_lcb) {
+    p_rcb = bta_av_get_rcb_by_shdl((uint8_t)(p_scb->hdi + 1));
+    if (p_rcb) bta_av_del_rc(p_rcb);
+    AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]);
+  } else {
+    bta_av_ssm_execute(p_scb, BTA_AV_AVDT_DISCONNECT_EVT, NULL);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_security_req
+ *
+ * Description      Send an AVDTP security request.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_security_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  if (bta_av_cb.features & BTA_AV_FEAT_PROTECT) {
+    AVDT_SecurityReq(p_scb->avdt_handle, p_data->api_protect_req.p_data,
+                     p_data->api_protect_req.len);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_security_rsp
+ *
+ * Description      Send an AVDTP security response.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_security_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  if (bta_av_cb.features & BTA_AV_FEAT_PROTECT) {
+    AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label,
+                     p_data->api_protect_rsp.error_code,
+                     p_data->api_protect_rsp.p_data,
+                     p_data->api_protect_rsp.len);
+  } else {
+    AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_NSC, NULL,
+                     0);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_setconfig_rsp
+ *
+ * Description      setconfig is OK
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_setconfig_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  uint8_t num = p_data->ci_setconfig.num_seid + 1;
+  uint8_t avdt_handle = p_data->ci_setconfig.avdt_handle;
+  uint8_t* p_seid = p_data->ci_setconfig.p_seid;
+  int i;
+  uint8_t local_sep;
+
+  /* we like this codec_type. find the sep_idx */
+  local_sep = bta_av_get_scb_sep_type(p_scb, avdt_handle);
+  bta_av_adjust_seps_idx(p_scb, avdt_handle);
+  APPL_TRACE_DEBUG("%s: sep_idx: %d cur_psc_mask:0x%x", __func__,
+                   p_scb->sep_idx, p_scb->cur_psc_mask);
+
+  if ((AVDT_TSEP_SNK == local_sep) &&
+      (p_data->ci_setconfig.err_code == AVDT_SUCCESS) &&
+      (p_scb->seps[p_scb->sep_idx].p_app_sink_data_cback != NULL)) {
+    tBTA_AV_MEDIA av_sink_codec_info;
+    memcpy(av_sink_codec_info.avk_config.bd_addr, p_scb->peer_addr,
+           sizeof(BD_ADDR));
+    av_sink_codec_info.avk_config.codec_info = p_scb->cfg.codec_info;
+    p_scb->seps[p_scb->sep_idx].p_app_sink_data_cback(BTA_AV_SINK_MEDIA_CFG_EVT,
+                                                      &av_sink_codec_info);
+  }
+
+  AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label,
+                 p_data->ci_setconfig.err_code, p_data->ci_setconfig.category);
+
+  alarm_cancel(bta_av_cb.link_signalling_timer);
+
+  if (p_data->ci_setconfig.err_code == AVDT_SUCCESS) {
+    p_scb->wait = BTA_AV_WAIT_ACP_CAPS_ON;
+    if (p_data->ci_setconfig.recfg_needed)
+      p_scb->role |= BTA_AV_ROLE_SUSPEND_OPT;
+    APPL_TRACE_DEBUG("%s: recfg_needed:%d role:x%x num:%d", __func__,
+                     p_data->ci_setconfig.recfg_needed, p_scb->role, num);
+    /* callout module tells BTA the number of "good" SEPs and their SEIDs.
+     * getcap on these SEID */
+    p_scb->num_seps = num;
+
+    if (p_scb->cur_psc_mask & AVDT_PSC_DELAY_RPT)
+      p_scb->avdt_version = AVDT_VERSION_SYNC;
+
+    if (A2DP_GetCodecType(p_scb->cfg.codec_info) == A2DP_MEDIA_CT_SBC ||
+        num > 1) {
+      /* if SBC is used by the SNK as INT, discover req is not sent in
+       * bta_av_config_ind.
+                 * call disc_res now */
+      /* this is called in A2DP SRC path only, In case of SINK we don't need it
+       */
+      if (local_sep == AVDT_TSEP_SRC)
+        p_scb->p_cos->disc_res(p_scb->hndl, num, num, 0, p_scb->peer_addr,
+                               UUID_SERVCLASS_AUDIO_SOURCE);
+    } else {
+      /* we do not know the peer device and it is using non-SBC codec
+       * we need to know all the SEPs on SNK */
+      bta_av_discover_req(p_scb, NULL);
+      return;
+    }
+
+    for (i = 1; i < num; i++) {
+      APPL_TRACE_DEBUG("%s: sep_info[%d] SEID: %d", __func__, i, p_seid[i - 1]);
+      /* initialize the sep_info[] to get capabilities */
+      p_scb->sep_info[i].in_use = false;
+      p_scb->sep_info[i].tsep = AVDT_TSEP_SNK;
+      p_scb->sep_info[i].media_type = p_scb->media_type;
+      p_scb->sep_info[i].seid = p_seid[i - 1];
+    }
+
+    /* only in case of local sep as SRC we need to look for other SEPs, In case
+     * of SINK we don't */
+    if (local_sep == AVDT_TSEP_SRC) {
+      /* Make sure UUID has been initialized... */
+      if (p_scb->uuid_int == 0) p_scb->uuid_int = p_scb->open_api.uuid;
+      bta_av_next_getcap(p_scb, p_data);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_str_opened
+ *
+ * Description      Stream opened OK (incoming/outgoing).
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_str_opened(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  tBTA_AV_CONN_CHG msg;
+  tBTA_AV_OPEN open;
+  uint8_t* p;
+  uint16_t mtu;
+
+  msg.hdr.layer_specific = p_scb->hndl;
+  msg.is_up = true;
+  bdcpy(msg.peer_addr, p_scb->peer_addr);
+  p_scb->l2c_cid = AVDT_GetL2CapChannel(p_scb->avdt_handle);
+  bta_av_conn_chg((tBTA_AV_DATA*)&msg);
+  /* set the congestion flag, so AV would not send media packets by accident */
+  p_scb->cong = true;
+  p_scb->offload_start_pending = false;
+
+  p_scb->stream_mtu =
+      p_data->str_msg.msg.open_ind.peer_mtu - AVDT_MEDIA_HDR_SIZE;
+  mtu = bta_av_chk_mtu(p_scb, p_scb->stream_mtu);
+  APPL_TRACE_DEBUG("%s: l2c_cid: 0x%x stream_mtu: %d mtu: %d", __func__,
+                   p_scb->l2c_cid, p_scb->stream_mtu, mtu);
+  if (mtu == 0 || mtu > p_scb->stream_mtu) mtu = p_scb->stream_mtu;
+
+  /* Set the media channel as medium priority */
+  L2CA_SetTxPriority(p_scb->l2c_cid, L2CAP_CHNL_PRIORITY_MEDIUM);
+  L2CA_SetChnlFlushability(p_scb->l2c_cid, true);
+
+  bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+  memset(&p_scb->q_info, 0, sizeof(tBTA_AV_Q_INFO));
+
+  p_scb->l2c_bufs = 0;
+  p_scb->p_cos->open(p_scb->hndl, p_scb->cfg.codec_info, mtu);
+
+  {
+    /* TODO check if other audio channel is open.
+     * If yes, check if reconfig is needed
+     * Rigt now we do not do this kind of checking.
+     * BTA-AV is INT for 2nd audio connection.
+     * The application needs to make sure the current codec_info is proper.
+     * If one audio connection is open and another SNK attempts to connect to
+     * AV,
+     * the connection will be rejected.
+     */
+    /* check if other audio channel is started. If yes, start */
+    bdcpy(open.bd_addr, p_scb->peer_addr);
+    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;
+    if (NULL != (p = BTM_ReadRemoteFeatures(p_scb->peer_addr))) {
+      if (HCI_EDR_ACL_2MPS_SUPPORTED(p)) open.edr |= BTA_AV_EDR_2MBPS;
+      if (HCI_EDR_ACL_3MPS_SUPPORTED(p)) open.edr |= BTA_AV_EDR_3MBPS;
+    }
+#if (BTA_AR_INCLUDED == TRUE)
+    bta_ar_avdt_conn(BTA_ID_AV, open.bd_addr);
+#endif
+    if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC)
+      open.sep = AVDT_TSEP_SNK;
+    else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK)
+      open.sep = AVDT_TSEP_SRC;
+
+    (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV*)&open);
+    if (open.starting) {
+      bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL);
+    }
+  }
+
+  // This code is used to pass PTS TC for AVDTP ABORT
+  char value[PROPERTY_VALUE_MAX] = {0};
+  if ((osi_property_get("bluetooth.pts.force_a2dp_abort", value, "false")) &&
+      (!strcmp(value, "true"))) {
+    APPL_TRACE_ERROR("%s: Calling AVDT_AbortReq", __func__);
+    AVDT_AbortReq(p_scb->avdt_handle);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_security_ind
+ *
+ * Description      Handle an AVDTP security indication.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_security_ind(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  tBTA_AV_PROTECT_REQ protect_req;
+
+  p_scb->avdt_label = p_data->str_msg.msg.hdr.label;
+
+  if (bta_av_cb.features & BTA_AV_FEAT_PROTECT) {
+    protect_req.chnl = p_scb->chnl;
+    protect_req.hndl = p_scb->hndl;
+    protect_req.p_data = p_data->str_msg.msg.security_ind.p_data;
+    protect_req.len = p_data->str_msg.msg.security_ind.len;
+
+    (*bta_av_cb.p_cback)(BTA_AV_PROTECT_REQ_EVT, (tBTA_AV*)&protect_req);
+  }
+  /* app doesn't support security indication; respond with failure */
+  else {
+    AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_NSC, NULL,
+                     0);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_security_cfm
+ *
+ * Description      Handle an AVDTP security confirm.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_security_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  tBTA_AV_PROTECT_RSP protect_rsp;
+
+  if (bta_av_cb.features & BTA_AV_FEAT_PROTECT) {
+    protect_rsp.chnl = p_scb->chnl;
+    protect_rsp.hndl = p_scb->hndl;
+    protect_rsp.p_data = p_data->str_msg.msg.security_cfm.p_data;
+    protect_rsp.len = p_data->str_msg.msg.security_cfm.len;
+    protect_rsp.err_code = p_data->str_msg.msg.hdr.err_code;
+
+    (*bta_av_cb.p_cback)(BTA_AV_PROTECT_RSP_EVT, (tBTA_AV*)&protect_rsp);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_do_close
+ *
+ * Description      Close stream.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_do_close(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  /* stop stream if started */
+  if (p_scb->co_started) {
+    bta_av_str_stopped(p_scb, NULL);
+  }
+  alarm_cancel(bta_av_cb.link_signalling_timer);
+
+  /* close stream */
+  p_scb->started = false;
+
+  /* drop the buffers queued in L2CAP */
+  L2CA_FlushChannel(p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
+
+  AVDT_CloseReq(p_scb->avdt_handle);
+  /* just in case that the link is congested, link is flow controled by peer or
+   * for whatever reason the the close request can not be sent in time.
+   * when this timer expires, AVDT_DisconnectReq will be called to disconnect
+   * the link
+   */
+  bta_sys_start_timer(p_scb->avrc_ct_timer, BTA_AV_CLOSE_REQ_TIME_VAL,
+                      BTA_AV_API_CLOSE_EVT, p_scb->hndl);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_connect_req
+ *
+ * Description      Connect AVDTP connection.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_connect_req(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  p_scb->sdp_discovery_started = false;
+  if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR) {
+    /* SNK initiated L2C connection while SRC was doing SDP.    */
+    /* Wait until timeout to check if SNK starts signalling.    */
+    APPL_TRACE_EVENT("%s: coll_mask = 0x%2X", __func__, p_scb->coll_mask);
+    p_scb->coll_mask |= BTA_AV_COLL_API_CALLED;
+    APPL_TRACE_EVENT("%s: updated coll_mask = 0x%2X", __func__,
+                     p_scb->coll_mask);
+    return;
+  }
+
+  AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask,
+                  bta_av_dt_cback[p_scb->hdi]);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_sdp_failed
+ *
+ * Description      Service discovery failed.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_sdp_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  if (!p_scb->open_status) p_scb->open_status = BTA_AV_FAIL_SDP;
+
+  p_scb->sdp_discovery_started = false;
+  bta_av_str_closed(p_scb, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_disc_results
+ *
+ * Description      Handle the AVDTP discover results.  Search through the
+ *                  results and find the first available stream, and get
+ *                  its capabilities.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_disc_results(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  uint8_t num_snks = 0, num_srcs = 0, i;
+  /* our uuid in case we initiate connection */
+  uint16_t uuid_int = p_scb->uuid_int;
+
+  APPL_TRACE_DEBUG("%s: initiator UUID 0x%x", __func__, uuid_int);
+  /* store number of stream endpoints returned */
+  p_scb->num_seps = p_data->str_msg.msg.discover_cfm.num_seps;
+
+  for (i = 0; i < p_scb->num_seps; i++) {
+    /* steam not in use, is a sink, and is audio */
+    if ((p_scb->sep_info[i].in_use == false) &&
+        (p_scb->sep_info[i].media_type == p_scb->media_type)) {
+      if ((p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) &&
+          (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE))
+        num_snks++;
+
+      if ((p_scb->sep_info[i].tsep == AVDT_TSEP_SRC) &&
+          (uuid_int == UUID_SERVCLASS_AUDIO_SINK))
+        num_srcs++;
+    }
+  }
+
+  p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, num_srcs,
+                         p_scb->peer_addr, uuid_int);
+  p_scb->num_disc_snks = num_snks;
+  p_scb->num_disc_srcs = num_srcs;
+
+  /* if we got any */
+  if (p_scb->num_seps > 0) {
+    /* initialize index into discovery results */
+    p_scb->sep_info_idx = 0;
+
+    /* get the capabilities of the first available stream */
+    bta_av_next_getcap(p_scb, p_data);
+  }
+  /* else we got discover response but with no streams; we're done */
+  else {
+    bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, p_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_disc_res_as_acp
+ *
+ * Description      Handle the AVDTP discover results.  Search through the
+ *                  results and find the first available stream, and get
+ *                  its capabilities.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_disc_res_as_acp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  uint8_t num_snks = 0, i;
+
+  /* store number of stream endpoints returned */
+  p_scb->num_seps = p_data->str_msg.msg.discover_cfm.num_seps;
+
+  for (i = 0; i < p_scb->num_seps; i++) {
+    /* steam is a sink, and is audio */
+    if ((p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) &&
+        (p_scb->sep_info[i].media_type == p_scb->media_type)) {
+      p_scb->sep_info[i].in_use = false;
+      num_snks++;
+    }
+  }
+  p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, 0,
+                         p_scb->peer_addr, UUID_SERVCLASS_AUDIO_SOURCE);
+  p_scb->num_disc_snks = num_snks;
+  p_scb->num_disc_srcs = 0;
+
+  /* if we got any */
+  if (p_scb->num_seps > 0) {
+    /* initialize index into discovery results */
+    p_scb->sep_info_idx = 0;
+
+    /* get the capabilities of the first available stream */
+    bta_av_next_getcap(p_scb, p_data);
+  }
+  /* else we got discover response but with no streams; we're done */
+  else {
+    bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, p_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_save_caps
+ *
+ * Description      report the SNK SEP capabilities to application
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_save_caps(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  tAVDT_CFG cfg;
+  tAVDT_SEP_INFO* p_info = &p_scb->sep_info[p_scb->sep_info_idx];
+  uint8_t old_wait = p_scb->wait;
+  bool getcap_done = false;
+
+  APPL_TRACE_DEBUG("%s: num_seps:%d sep_info_idx:%d wait:x%x", __func__,
+                   p_scb->num_seps, p_scb->sep_info_idx, p_scb->wait);
+  memcpy(&cfg, p_scb->p_cap, sizeof(tAVDT_CFG));
+  /* let application know the capability of the SNK */
+  p_scb->p_cos->getcfg(p_scb->hndl, cfg.codec_info, &p_scb->sep_info_idx,
+                       p_info->seid, &cfg.num_protect, cfg.protect_info);
+
+  p_scb->sep_info_idx++;
+  if (p_scb->num_seps > p_scb->sep_info_idx) {
+    /* Some devices have seps at the end of the discover list, which is not */
+    /* matching media type(video not audio).                                */
+    /* In this case, we are done with getcap without sending another        */
+    /* request to AVDT.                                                     */
+    if (!bta_av_next_getcap(p_scb, p_data)) getcap_done = true;
+  } else
+    getcap_done = true;
+
+  if (getcap_done) {
+    /* we are done getting capabilities. restore the p_cb->sep_info_idx */
+    p_scb->sep_info_idx = 0;
+    p_scb->wait &= ~(BTA_AV_WAIT_ACP_CAPS_ON | BTA_AV_WAIT_ACP_CAPS_STARTED);
+    if (old_wait & BTA_AV_WAIT_ACP_CAPS_STARTED) {
+      bta_av_start_ok(p_scb, NULL);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_set_use_rc
+ *
+ * Description      set to use AVRC for this stream control block.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_set_use_rc(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  p_scb->use_rc = true;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_cco_close
+ *
+ * Description      call close call-out function.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_cco_close(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  uint16_t mtu;
+
+  mtu = bta_av_chk_mtu(p_scb, BTA_AV_MAX_A2DP_MTU);
+
+  p_scb->p_cos->close(p_scb->hndl, mtu);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_open_failed
+ *
+ * Description      Failed to open an AVDT stream
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_open_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  bool is_av_opened = false;
+  tBTA_AV_SCB* p_opened_scb = NULL;
+  uint8_t idx;
+  tBTA_AV_OPEN open;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+  p_scb->open_status = BTA_AV_FAIL_STREAM;
+  bta_av_cco_close(p_scb, p_data);
+
+  /* check whether there is already an opened audio or video connection with the
+   * same device */
+  for (idx = 0; (idx < BTA_AV_NUM_STRS) && (is_av_opened == false); idx++) {
+    p_opened_scb = bta_av_cb.p_scb[idx];
+    if (p_opened_scb && (p_opened_scb->state == BTA_AV_OPEN_SST) &&
+        (!bdcmp(p_opened_scb->peer_addr, p_scb->peer_addr)))
+      is_av_opened = true;
+  }
+
+  /* if there is already an active AV connnection with the same bd_addr,
+     don't send disconnect req, just report the open event with
+     BTA_AV_FAIL_GET_CAP status */
+  if (is_av_opened == true) {
+    bdcpy(open.bd_addr, p_scb->peer_addr);
+    open.chnl = p_scb->chnl;
+    open.hndl = p_scb->hndl;
+    open.status = BTA_AV_FAIL_GET_CAP;
+    open.starting = bta_av_chk_start(p_scb);
+    open.edr = 0;
+    /* set the state back to initial state */
+    bta_av_set_scb_sst_init(p_scb);
+
+    if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC)
+      open.sep = AVDT_TSEP_SNK;
+    else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK)
+      open.sep = AVDT_TSEP_SRC;
+
+    (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV*)&open);
+
+  } else {
+    AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_getcap_results
+ *
+ * Description      Handle the AVDTP get capabilities results.  Check the codec
+ *                  type and see if it matches ours.  If it does not, get the
+ *                  capabilities of the next stream, if any.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_getcap_results(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  tAVDT_CFG cfg;
+  uint8_t media_type;
+  tAVDT_SEP_INFO* p_info = &p_scb->sep_info[p_scb->sep_info_idx];
+  uint16_t uuid_int; /* UUID for which connection was initiatied */
+
+  memcpy(&cfg, &p_scb->cfg, sizeof(tAVDT_CFG));
+  cfg.num_codec = 1;
+  cfg.num_protect = p_scb->p_cap->num_protect;
+  memcpy(cfg.codec_info, p_scb->p_cap->codec_info, AVDT_CODEC_SIZE);
+  memcpy(cfg.protect_info, p_scb->p_cap->protect_info, AVDT_PROTECT_SIZE);
+  media_type = A2DP_GetMediaType(p_scb->p_cap->codec_info);
+
+  APPL_TRACE_DEBUG("%s: num_codec %d", __func__, p_scb->p_cap->num_codec);
+  APPL_TRACE_DEBUG("%s: media type x%x, x%x", __func__, media_type,
+                   p_scb->media_type);
+
+  /* if codec present and we get a codec configuration */
+  if ((p_scb->p_cap->num_codec != 0) && (media_type == p_scb->media_type) &&
+      (p_scb->p_cos->getcfg(p_scb->hndl, cfg.codec_info, &p_scb->sep_info_idx,
+                            p_info->seid, &cfg.num_protect,
+                            cfg.protect_info) == A2DP_SUCCESS)) {
+    /* save copy of codec configuration */
+    memcpy(&p_scb->cfg, &cfg, sizeof(tAVDT_CFG));
+
+    uuid_int = p_scb->uuid_int;
+    APPL_TRACE_DEBUG("%s: initiator UUID = 0x%x", __func__, uuid_int);
+    if (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE)
+      bta_av_adjust_seps_idx(p_scb,
+                             bta_av_get_scb_handle(p_scb, AVDT_TSEP_SRC));
+    else if (uuid_int == UUID_SERVCLASS_AUDIO_SINK)
+      bta_av_adjust_seps_idx(p_scb,
+                             bta_av_get_scb_handle(p_scb, AVDT_TSEP_SNK));
+
+    /* use only the services peer supports */
+    cfg.psc_mask &= p_scb->p_cap->psc_mask;
+    p_scb->cur_psc_mask = cfg.psc_mask;
+
+    if ((uuid_int == UUID_SERVCLASS_AUDIO_SINK) &&
+        (p_scb->seps[p_scb->sep_idx].p_app_sink_data_cback != NULL)) {
+      APPL_TRACE_DEBUG("%s: configure decoder for Sink connection", __func__);
+      tBTA_AV_MEDIA av_sink_codec_info;
+      memcpy(av_sink_codec_info.avk_config.bd_addr, p_scb->peer_addr,
+             sizeof(BD_ADDR));
+      av_sink_codec_info.avk_config.codec_info = p_scb->cfg.codec_info;
+      p_scb->seps[p_scb->sep_idx].p_app_sink_data_cback(
+          BTA_AV_SINK_MEDIA_CFG_EVT, &av_sink_codec_info);
+    }
+
+    if (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE) {
+      A2DP_AdjustCodec(cfg.codec_info);
+    }
+
+    /* open the stream */
+    AVDT_OpenReq(p_scb->seps[p_scb->sep_idx].av_handle, p_scb->peer_addr,
+                 p_scb->sep_info[p_scb->sep_info_idx].seid, &cfg);
+
+    if (!bta_av_is_rcfg_sst(p_scb)) {
+      /* free capabilities buffer */
+      osi_free_and_reset((void**)&p_scb->p_cap);
+    }
+  } else {
+    /* try the next stream, if any */
+    p_scb->sep_info_idx++;
+    bta_av_next_getcap(p_scb, p_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_setconfig_rej
+ *
+ * Description      Send AVDTP set config reject.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_setconfig_rej(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  tBTA_AV_REJECT reject;
+  uint8_t avdt_handle = p_data->ci_setconfig.avdt_handle;
+
+  bta_av_adjust_seps_idx(p_scb, avdt_handle);
+  APPL_TRACE_DEBUG("%s: sep_idx: %d", __func__, p_scb->sep_idx);
+  AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_UNSUP_CFG, 0);
+
+  bdcpy(reject.bd_addr, p_data->str_msg.bd_addr);
+  reject.hndl = p_scb->hndl;
+  (*bta_av_cb.p_cback)(BTA_AV_REJECT_EVT, (tBTA_AV*)&reject);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_discover_req
+ *
+ * Description      Send an AVDTP discover request to the peer.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_discover_req(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  /* send avdtp discover request */
+
+  AVDT_DiscoverReq(p_scb->peer_addr, p_scb->sep_info, BTA_AV_NUM_SEPS,
+                   bta_av_dt_cback[p_scb->hdi]);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_conn_failed
+ *
+ * Description      AVDTP connection failed.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_conn_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  p_scb->open_status = BTA_AV_FAIL_STREAM;
+  bta_av_str_closed(p_scb, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_do_start
+ *
+ * Description      Start stream.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_do_start(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  uint8_t policy = HCI_ENABLE_SNIFF_MODE;
+  uint8_t cur_role;
+
+  APPL_TRACE_DEBUG("%s: sco_occupied:%d, role:x%x, started:%d", __func__,
+                   bta_av_cb.sco_occupied, p_scb->role, p_scb->started);
+  if (bta_av_cb.sco_occupied) {
+    bta_av_start_failed(p_scb, p_data);
+    return;
+  }
+
+  /* disallow role switch during streaming, only if we are the master role
+   * i.e. allow role switch, if we are slave.
+   * It would not hurt us, if the peer device wants us to be master */
+  if ((BTM_GetRole(p_scb->peer_addr, &cur_role) == BTM_SUCCESS) &&
+      (cur_role == BTM_ROLE_MASTER)) {
+    policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+  }
+
+  bta_sys_clear_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+
+  if ((p_scb->started == false) &&
+      ((p_scb->role & BTA_AV_ROLE_START_INT) == 0)) {
+    p_scb->role |= BTA_AV_ROLE_START_INT;
+    bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+
+    AVDT_StartReq(&p_scb->avdt_handle, 1);
+  } else if (p_scb->started) {
+    p_scb->role |= BTA_AV_ROLE_START_INT;
+    if (p_scb->wait == 0) {
+      if (p_scb->role & BTA_AV_ROLE_SUSPEND) {
+        notify_start_failed(p_scb);
+      } else {
+        bta_av_start_ok(p_scb, NULL);
+      }
+    }
+  }
+  APPL_TRACE_DEBUG("%s: started %d role:x%x", __func__, p_scb->started,
+                   p_scb->role);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_str_stopped
+ *
+ * Description      Stream stopped.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_str_stopped(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  tBTA_AV_SUSPEND suspend_rsp;
+  uint8_t start = p_scb->started;
+  bool sus_evt = true;
+  BT_HDR* p_buf;
+  uint8_t policy = HCI_ENABLE_SNIFF_MODE;
+
+  APPL_TRACE_ERROR("%s: audio_open_cnt=%d, p_data %x", __func__,
+                   bta_av_cb.audio_open_cnt, p_data);
+
+  bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+  if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 ||
+      bta_av_cb.audio_open_cnt == 1)
+    policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+  bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+
+  if (p_scb->co_started) {
+    vendor_get_interface()->send_command(
+        (vendor_opcode_t)BT_VND_OP_A2DP_OFFLOAD_STOP, (void*)&p_scb->l2c_cid);
+    if (p_scb->offload_start_pending) {
+      tBTA_AV_STATUS status = BTA_AV_FAIL_STREAM;
+      (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, (tBTA_AV*)&status);
+    }
+    p_scb->offload_start_pending = false;
+
+    bta_av_stream_chg(p_scb, false);
+    p_scb->co_started = false;
+
+    p_scb->p_cos->stop(p_scb->hndl);
+    L2CA_SetFlushTimeout(p_scb->peer_addr, L2CAP_DEFAULT_FLUSH_TO);
+  }
+
+  /* if q_info.a2dp_list is not empty, drop it now */
+  if (BTA_AV_CHNL_AUDIO == p_scb->chnl) {
+    while (!list_is_empty(p_scb->a2dp_list)) {
+      p_buf = (BT_HDR*)list_front(p_scb->a2dp_list);
+      list_remove(p_scb->a2dp_list, p_buf);
+      osi_free(p_buf);
+    }
+
+    /* drop the audio buffers queued in L2CAP */
+    if (p_data && p_data->api_stop.flush)
+      L2CA_FlushChannel(p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
+  }
+
+  suspend_rsp.chnl = p_scb->chnl;
+  suspend_rsp.hndl = p_scb->hndl;
+
+  if (p_data && p_data->api_stop.suspend) {
+    APPL_TRACE_DEBUG("%s: suspending: %d, sup:%d", __func__, start,
+                     p_scb->suspend_sup);
+    if ((start) && (p_scb->suspend_sup)) {
+      sus_evt = false;
+      p_scb->l2c_bufs = 0;
+      AVDT_SuspendReq(&p_scb->avdt_handle, 1);
+    }
+
+    /* send SUSPEND_EVT event only if not in reconfiguring state and sus_evt is
+     * true*/
+    if ((sus_evt) && (p_scb->state != BTA_AV_RCFG_SST)) {
+      suspend_rsp.status = BTA_AV_SUCCESS;
+      suspend_rsp.initiator = true;
+      (*bta_av_cb.p_cback)(BTA_AV_SUSPEND_EVT, (tBTA_AV*)&suspend_rsp);
+    }
+  } else {
+    suspend_rsp.status = BTA_AV_SUCCESS;
+    suspend_rsp.initiator = true;
+    APPL_TRACE_EVENT("%s: status %d", __func__, suspend_rsp.status);
+
+    /* send STOP_EVT event only if not in reconfiguring state */
+    if (p_scb->state != BTA_AV_RCFG_SST) {
+      (*bta_av_cb.p_cback)(BTA_AV_STOP_EVT, (tBTA_AV*)&suspend_rsp);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_reconfig
+ *
+ * Description      process the reconfigure request.
+ *                  save the parameter in control block and
+ *                  suspend, reconfigure or close the stream
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_reconfig(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  tAVDT_CFG* p_cfg;
+  tBTA_AV_API_STOP stop;
+  tBTA_AV_API_RCFG* p_rcfg = &p_data->api_reconfig;
+
+  APPL_TRACE_DEBUG("%s: r:%d, s:%d idx: %d (o:%d)", __func__, p_scb->recfg_sup,
+                   p_scb->suspend_sup, p_scb->rcfg_idx, p_scb->sep_info_idx);
+
+  p_scb->num_recfg = 0;
+  /* store the new configuration in control block */
+  if (p_scb->p_cap == NULL)
+    p_scb->p_cap = (tAVDT_CFG*)osi_malloc(sizeof(tAVDT_CFG));
+  p_cfg = p_scb->p_cap;
+
+  alarm_cancel(p_scb->avrc_ct_timer);
+
+  memcpy(p_cfg, &p_scb->cfg, sizeof(tAVDT_CFG));
+  p_cfg->num_protect = p_rcfg->num_protect;
+  memcpy(p_cfg->codec_info, p_rcfg->codec_info, AVDT_CODEC_SIZE);
+  memcpy(p_cfg->protect_info, p_rcfg->p_protect_info, p_rcfg->num_protect);
+  p_scb->rcfg_idx = p_rcfg->sep_info_idx;
+  p_scb->p_cap->psc_mask = p_scb->cur_psc_mask;
+
+  /* if the requested index differs from the current one, we can only close/open
+   */
+  if ((p_scb->rcfg_idx == p_scb->sep_info_idx) && (p_rcfg->suspend) &&
+      (p_scb->recfg_sup) && (p_scb->suspend_sup)) {
+    if (p_scb->started) {
+      stop.flush = false;
+      stop.suspend = true;
+      bta_av_str_stopped(p_scb, (tBTA_AV_DATA*)&stop);
+    } else {
+      APPL_TRACE_DEBUG("%s: reconfig", __func__);
+      AVDT_ReconfigReq(p_scb->avdt_handle, p_scb->p_cap);
+      p_scb->p_cap->psc_mask = p_scb->cur_psc_mask;
+    }
+  } else {
+    /* close the stream */
+    APPL_TRACE_DEBUG("%s: close/open num_protect: %d", __func__,
+                     p_cfg->num_protect);
+    if (p_scb->started) {
+      bta_av_str_stopped(p_scb, NULL);
+      p_scb->started = false;
+
+      /* drop the buffers queued in L2CAP */
+      L2CA_FlushChannel(p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
+
+      AVDT_CloseReq(p_scb->avdt_handle);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_data_path
+ *
+ * Description      Handle stream data path.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_data_path(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  BT_HDR* p_buf = NULL;
+  uint32_t timestamp;
+  bool new_buf = false;
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_scb->cfg.codec_info);
+  uint8_t m_pt = 0x60 | codec_type;
+  tAVDT_DATA_OPT_MASK opt;
+
+  if (p_scb->cong) return;
+
+  // Always get the current number of bufs que'd up
+  p_scb->l2c_bufs =
+      (uint8_t)L2CA_FlushChannel(p_scb->l2c_cid, L2CAP_FLUSH_CHANS_GET);
+
+  if (!list_is_empty(p_scb->a2dp_list)) {
+    p_buf = (BT_HDR*)list_front(p_scb->a2dp_list);
+    list_remove(p_scb->a2dp_list, p_buf);
+    /* use q_info.a2dp data, read the timestamp */
+    timestamp = *(uint32_t*)(p_buf + 1);
+  } else {
+    new_buf = true;
+    /* A2DP_list empty, call co_data, dup data to other channels */
+    p_buf = (BT_HDR*)p_scb->p_cos->data(p_scb->cfg.codec_info, &timestamp);
+
+    if (p_buf) {
+      /* use the offset area for the time stamp */
+      *(uint32_t*)(p_buf + 1) = timestamp;
+
+      /* dup the data to other channels */
+      bta_av_dup_audio_buf(p_scb, p_buf);
+    }
+  }
+
+  if (p_buf) {
+    if (p_scb->l2c_bufs < (BTA_AV_QUEUE_DATA_CHK_NUM)) {
+      /* There's a buffer, just queue it to L2CAP.
+       * There's no need to increment it here, it is always read from
+       * L2CAP (see above).
+       */
+
+      /* opt is a bit mask, it could have several options set */
+      opt = AVDT_DATA_OPT_NONE;
+      if (p_scb->no_rtp_hdr) {
+        opt |= AVDT_DATA_OPT_NO_RTP;
+      }
+
+      AVDT_WriteReqOpt(p_scb->avdt_handle, p_buf, timestamp, m_pt, opt);
+      p_scb->cong = true;
+    } else {
+      /* there's a buffer, but L2CAP does not seem to be moving data */
+      if (new_buf) {
+        /* just got this buffer from co_data,
+         * put it in queue */
+        list_append(p_scb->a2dp_list, p_buf);
+      } else {
+        /* just dequeue it from the a2dp_list */
+        if (list_length(p_scb->a2dp_list) < 3) {
+          /* put it back to the queue */
+          list_prepend(p_scb->a2dp_list, p_buf);
+        } else {
+          /* too many buffers in a2dp_list, drop it. */
+          bta_av_co_audio_drop(p_scb->hndl);
+          osi_free(p_buf);
+        }
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_start_ok
+ *
+ * Description      Stream started.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_start_ok(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  tBTA_AV_START start;
+  tBTA_AV_API_STOP stop;
+  bool initiator = false;
+  bool suspend = false;
+  uint16_t flush_to;
+  uint8_t new_role = p_scb->role;
+  BT_HDR hdr;
+  uint8_t policy = HCI_ENABLE_SNIFF_MODE;
+  uint8_t cur_role;
+
+  APPL_TRACE_DEBUG("%s: wait:x%x, role:x%x", __func__, p_scb->wait,
+                   p_scb->role);
+
+  p_scb->started = true;
+  if (p_scb->sco_suspend) {
+    p_scb->sco_suspend = false;
+  }
+
+  if (new_role & BTA_AV_ROLE_START_INT) initiator = true;
+
+  /* for A2DP SINK we do not send get_caps */
+  if ((p_scb->avdt_handle == p_scb->seps[p_scb->sep_idx].av_handle) &&
+      (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK)) {
+    p_scb->wait &= ~(BTA_AV_WAIT_ACP_CAPS_ON);
+    APPL_TRACE_DEBUG("%s: local SEP type is SNK new wait is 0x%x", __func__,
+                     p_scb->wait);
+  }
+  if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_FAILED) {
+    /* role switch has failed */
+    p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_FAILED;
+    p_data = (tBTA_AV_DATA*)&hdr;
+    hdr.offset = BTA_AV_RS_FAIL;
+  }
+  APPL_TRACE_DEBUG("%s: wait:x%x", __func__, p_scb->wait);
+
+  if (p_data && (p_data->hdr.offset != BTA_AV_RS_NONE)) {
+    p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+    if (p_data->hdr.offset == BTA_AV_RS_FAIL) {
+      bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+      start.chnl = p_scb->chnl;
+      start.status = BTA_AV_FAIL_ROLE;
+      start.hndl = p_scb->hndl;
+      start.initiator = initiator;
+      (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV*)&start);
+      return;
+    }
+  }
+
+  if (!bta_av_link_role_ok(p_scb, A2DP_SET_ONE_BIT))
+    p_scb->q_tag = BTA_AV_Q_TAG_START;
+  else {
+    /* The wait flag may be set here while we are already master on the link */
+    /* this could happen if a role switch complete event occurred during
+     * reconfig */
+    /* if we are now master on the link, there is no need to wait for the role
+     * switch, */
+    /* complete anymore so we can clear the wait for role switch flag */
+    p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+  }
+
+  if (p_scb->wait &
+      (BTA_AV_WAIT_ROLE_SW_RES_OPEN | BTA_AV_WAIT_ROLE_SW_RES_START)) {
+    p_scb->wait |= BTA_AV_WAIT_ROLE_SW_STARTED;
+    p_scb->q_tag = BTA_AV_Q_TAG_START;
+  }
+
+  if (p_scb->wait) {
+    APPL_TRACE_ERROR("%s: wait:x%x q_tag:%d- not started", __func__,
+                     p_scb->wait, p_scb->q_tag);
+    /* Clear first bit of p_scb->wait and not to return from this point else
+     * HAL layer gets blocked. And if there is delay in Get Capability response
+     * as
+     * first bit of p_scb->wait is cleared hence it ensures bt_av_start_ok is
+     * not called
+     * again from bta_av_save_caps.
+    */
+    p_scb->wait &= ~BTA_AV_WAIT_ACP_CAPS_ON;
+  }
+
+  /* tell role manager to check M/S role */
+  bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+
+  bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+
+  if (p_scb->media_type == AVDT_MEDIA_TYPE_AUDIO) {
+    /* in normal logic, conns should be bta_av_cb.audio_count - 1,
+     * However, bta_av_stream_chg is not called to increase
+     * bta_av_cb.audio_count yet.
+     * If the code were to be re-arranged for some reasons, this number may need
+     * to be changed
+     */
+    p_scb->co_started = bta_av_cb.audio_open_cnt;
+    flush_to = p_bta_av_cfg->p_audio_flush_to[p_scb->co_started - 1];
+  } else {
+    flush_to = p_bta_av_cfg->video_flush_to;
+  }
+  L2CA_SetFlushTimeout(p_scb->peer_addr, flush_to);
+
+  /* clear the congestion flag */
+  p_scb->cong = false;
+
+  if (new_role & BTA_AV_ROLE_START_INT) {
+    new_role &= ~BTA_AV_ROLE_START_INT;
+  } else if ((new_role & BTA_AV_ROLE_AD_ACP) &&
+             (new_role & BTA_AV_ROLE_SUSPEND_OPT)) {
+    suspend = true;
+  }
+
+  if (!suspend) {
+    p_scb->q_tag = BTA_AV_Q_TAG_STREAM;
+    bta_av_stream_chg(p_scb, true);
+  }
+
+  {
+    /* If sink starts stream, disable sniff mode here */
+    if (!initiator) {
+      /* If souce is the master role, disable role switch during streaming.
+      * Otherwise allow role switch, if source is slave.
+      * Because it would not hurt source, if the peer device wants source to be
+      * master */
+      if ((BTM_GetRole(p_scb->peer_addr, &cur_role) == BTM_SUCCESS) &&
+          (cur_role == BTM_ROLE_MASTER)) {
+        policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+      }
+
+      bta_sys_clear_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+    }
+
+    p_scb->role = new_role;
+    p_scb->role &= ~BTA_AV_ROLE_AD_ACP;
+    p_scb->role &= ~BTA_AV_ROLE_SUSPEND_OPT;
+
+    p_scb->no_rtp_hdr = false;
+    p_scb->p_cos->start(p_scb->hndl, p_scb->cfg.codec_info, &p_scb->no_rtp_hdr);
+    p_scb->co_started = true;
+
+    APPL_TRACE_DEBUG("%s: suspending: %d, role:x%x, init %d", __func__, suspend,
+                     p_scb->role, initiator);
+
+    start.suspending = suspend;
+    start.initiator = initiator;
+    start.chnl = p_scb->chnl;
+    start.status = BTA_AV_SUCCESS;
+    start.hndl = p_scb->hndl;
+    (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV*)&start);
+
+    if (suspend) {
+      p_scb->role |= BTA_AV_ROLE_SUSPEND;
+      p_scb->cong = true; /* do not allow the media data to go through */
+      /* do not duplicate the media packets to this channel */
+      p_scb->p_cos->stop(p_scb->hndl);
+      p_scb->co_started = false;
+      stop.flush = false;
+      stop.suspend = true;
+      bta_av_ssm_execute(p_scb, BTA_AV_AP_STOP_EVT, (tBTA_AV_DATA*)&stop);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_start_failed
+ *
+ * Description      Stream start failed.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_start_failed(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  if (p_scb->started == false && p_scb->co_started == false) {
+    bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+    notify_start_failed(p_scb);
+  }
+
+  bta_sys_set_policy(BTA_ID_AV,
+                     (HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_MASTER_SLAVE_SWITCH),
+                     p_scb->peer_addr);
+  p_scb->sco_suspend = false;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_str_closed
+ *
+ * Description      Stream closed.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_str_closed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  tBTA_AV data;
+  tBTA_AV_EVT event;
+  uint16_t mtu;
+  uint8_t policy = HCI_ENABLE_SNIFF_MODE;
+
+  if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 ||
+      bta_av_cb.audio_open_cnt == 1)
+    policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+  bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+  if (bta_av_cb.audio_open_cnt <= 1) {
+    /* last connection - restore the allow switch flag */
+    L2CA_SetDesireRole(L2CAP_ROLE_ALLOW_SWITCH);
+  }
+
+  if (p_scb->open_status) {
+    /* must be failure when opening the stream */
+    bdcpy(data.open.bd_addr, p_scb->peer_addr);
+    data.open.status = p_scb->open_status;
+    data.open.chnl = p_scb->chnl;
+    data.open.hndl = p_scb->hndl;
+
+    if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC)
+      data.open.sep = AVDT_TSEP_SNK;
+    else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK)
+      data.open.sep = AVDT_TSEP_SRC;
+
+    event = BTA_AV_OPEN_EVT;
+    p_scb->open_status = BTA_AV_SUCCESS;
+
+    bta_sys_conn_close(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+    bta_av_cleanup(p_scb, p_data);
+    (*bta_av_cb.p_cback)(event, &data);
+  } else {
+    /* do stop if we were started */
+    if (p_scb->co_started) {
+      bta_av_str_stopped(p_scb, NULL);
+    }
+
+    /* Update common mtu shared by remaining connectons */
+    mtu = bta_av_chk_mtu(p_scb, BTA_AV_MAX_A2DP_MTU);
+
+    {
+      p_scb->p_cos->close(p_scb->hndl, mtu);
+      data.close.chnl = p_scb->chnl;
+      data.close.hndl = p_scb->hndl;
+      event = BTA_AV_CLOSE_EVT;
+
+      bta_sys_conn_close(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+      bta_av_cleanup(p_scb, p_data);
+      (*bta_av_cb.p_cback)(event, &data);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_clr_cong
+ *
+ * Description      Clear stream congestion flag.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_clr_cong(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  if (p_scb->co_started) p_scb->cong = false;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_suspend_cfm
+ *
+ * Description      process the suspend response
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_suspend_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  tBTA_AV_SUSPEND suspend_rsp;
+  uint8_t err_code = p_data->str_msg.msg.hdr.err_code;
+  uint8_t policy = HCI_ENABLE_SNIFF_MODE;
+
+  APPL_TRACE_DEBUG("%s: audio_open_cnt = %d, err_code = %d", __func__,
+                   bta_av_cb.audio_open_cnt, err_code);
+
+  if (p_scb->started == false) {
+    /* handle the condition where there is a collision of SUSPEND req from
+    *either side
+    ** Second SUSPEND req could be rejected. Do not treat this as a failure
+    */
+    APPL_TRACE_WARNING("%s: already suspended, ignore, err_code %d", __func__,
+                       err_code);
+    return;
+  }
+
+  suspend_rsp.status = BTA_AV_SUCCESS;
+  if (err_code && (err_code != AVDT_ERR_BAD_STATE)) {
+    /* Disable suspend feature only with explicit rejection(not with timeout) */
+    if (err_code != AVDT_ERR_TIMEOUT) {
+      p_scb->suspend_sup = false;
+    }
+    suspend_rsp.status = BTA_AV_FAIL;
+
+    APPL_TRACE_ERROR("%s: suspend failed, closing connection", __func__);
+
+    /* SUSPEND failed. Close connection. */
+    bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, NULL);
+  } else {
+    /* only set started to false when suspend is successful */
+    p_scb->started = false;
+  }
+
+  if (p_scb->role & BTA_AV_ROLE_SUSPEND) {
+    p_scb->role &= ~BTA_AV_ROLE_SUSPEND;
+    p_scb->cong = false;
+  }
+
+  bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+  if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 ||
+      bta_av_cb.audio_open_cnt == 1)
+    policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+  bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+
+  /* in case that we received suspend_ind, we may need to call co_stop here */
+  if (p_scb->co_started) {
+    vendor_get_interface()->send_command(
+        (vendor_opcode_t)BT_VND_OP_A2DP_OFFLOAD_STOP, (void*)&p_scb->l2c_cid);
+    if (p_scb->offload_start_pending) {
+      tBTA_AV_STATUS status = BTA_AV_FAIL_STREAM;
+      (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, (tBTA_AV*)&status);
+    }
+    p_scb->offload_start_pending = false;
+
+    bta_av_stream_chg(p_scb, false);
+
+    {
+      p_scb->co_started = false;
+      p_scb->p_cos->stop(p_scb->hndl);
+    }
+    L2CA_SetFlushTimeout(p_scb->peer_addr, L2CAP_DEFAULT_FLUSH_TO);
+  }
+
+  {
+    suspend_rsp.chnl = p_scb->chnl;
+    suspend_rsp.hndl = p_scb->hndl;
+    suspend_rsp.initiator = p_data->str_msg.initiator;
+    (*bta_av_cb.p_cback)(BTA_AV_SUSPEND_EVT, (tBTA_AV*)&suspend_rsp);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rcfg_str_ok
+ *
+ * Description      report reconfigure successful
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_rcfg_str_ok(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  tBTA_AV_RECONFIG evt;
+
+  p_scb->l2c_cid = AVDT_GetL2CapChannel(p_scb->avdt_handle);
+  APPL_TRACE_DEBUG("%s: l2c_cid: %d", __func__, p_scb->l2c_cid);
+
+  /* rc listen */
+  bta_av_st_rc_timer(p_scb, NULL);
+  osi_free_and_reset((void**)&p_scb->p_cap);
+
+  /* No need to keep the role bits once reconfig is done. */
+  p_scb->role &= ~BTA_AV_ROLE_AD_ACP;
+  p_scb->role &= ~BTA_AV_ROLE_SUSPEND_OPT;
+  p_scb->role &= ~BTA_AV_ROLE_START_INT;
+
+  {
+    /* reconfigure success  */
+    evt.status = BTA_AV_SUCCESS;
+    evt.chnl = p_scb->chnl;
+    evt.hndl = p_scb->hndl;
+    (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV*)&evt);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rcfg_failed
+ *
+ * Description      process reconfigure failed
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_rcfg_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  tBTA_AV_RECONFIG evt;
+
+  APPL_TRACE_DEBUG("%s: num_recfg: %d, conn_lcb:0x%x", __func__,
+                   p_scb->num_recfg, bta_av_cb.conn_lcb);
+  if (p_scb->num_recfg > BTA_AV_RECONFIG_RETRY) {
+    bta_av_cco_close(p_scb, p_data);
+    /* report failure */
+    evt.status = BTA_AV_FAIL_STREAM;
+    evt.chnl = p_scb->chnl;
+    evt.hndl = p_scb->hndl;
+    (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV*)&evt);
+    /* go to closing state */
+    bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, NULL);
+  } else {
+    /* open failed. try again */
+    p_scb->num_recfg++;
+    if (bta_av_cb.conn_lcb) {
+      AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]);
+    } else {
+      bta_av_connect_req(p_scb, NULL);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rcfg_connect
+ *
+ * Description      stream closed. reconnect the stream
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_rcfg_connect(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  p_scb->cong = false;
+  p_scb->num_recfg++;
+  APPL_TRACE_DEBUG("%s: num_recfg: %d", __func__, p_scb->num_recfg);
+  if (p_scb->num_recfg > BTA_AV_RECONFIG_RETRY) {
+    /* let bta_av_rcfg_failed report fail */
+    bta_av_rcfg_failed(p_scb, NULL);
+  } else
+    AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask,
+                    bta_av_dt_cback[p_scb->hdi]);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rcfg_discntd
+ *
+ * Description      AVDT disconnected. reconnect the stream
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_rcfg_discntd(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  tBTA_AV_RECONFIG evt;
+
+  APPL_TRACE_DEBUG("%s: num_recfg: %d", __func__, p_scb->num_recfg);
+  p_scb->num_recfg++;
+  if (p_scb->num_recfg > BTA_AV_RECONFIG_RETRY) {
+    /* report failure */
+    evt.status = BTA_AV_FAIL_STREAM;
+    evt.chnl = p_scb->chnl;
+    evt.hndl = p_scb->hndl;
+    (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV*)&evt);
+    /* report close event & go to init state */
+    bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, NULL);
+  } else
+    AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask,
+                    bta_av_dt_cback[p_scb->hdi]);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_suspend_cont
+ *
+ * Description      received the suspend response.
+ *                  continue to reconfigure the stream
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_suspend_cont(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  uint8_t err_code = p_data->str_msg.msg.hdr.err_code;
+  tBTA_AV_RECONFIG evt;
+
+  p_scb->started = false;
+  p_scb->cong = false;
+  if (err_code) {
+    if (AVDT_ERR_CONNECT == err_code) {
+      /* report failure */
+      evt.status = BTA_AV_FAIL;
+      (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV*)&evt);
+      bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, NULL);
+    } else {
+      APPL_TRACE_ERROR("%s: suspend rejected, try close", __func__);
+      /* Disable suspend feature only with explicit rejection(not with timeout)
+       */
+      if (err_code != AVDT_ERR_TIMEOUT) {
+        p_scb->suspend_sup = false;
+      }
+      /* drop the buffers queued in L2CAP */
+      L2CA_FlushChannel(p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
+
+      AVDT_CloseReq(p_scb->avdt_handle);
+    }
+  } else {
+    APPL_TRACE_DEBUG("%s: calling AVDT_ReconfigReq", __func__);
+    /* reconfig the stream */
+
+    AVDT_ReconfigReq(p_scb->avdt_handle, p_scb->p_cap);
+    p_scb->p_cap->psc_mask = p_scb->cur_psc_mask;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rcfg_cfm
+ *
+ * Description      if reconfigure is successful, report the event
+ *                  otherwise, close the stream.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_rcfg_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  uint8_t err_code = p_data->str_msg.msg.hdr.err_code;
+
+  APPL_TRACE_DEBUG("%s: err_code = %d", __func__, err_code);
+  if (err_code) {
+    APPL_TRACE_ERROR("%s: reconfig rejected, try close", __func__);
+    /* Disable reconfiguration feature only with explicit rejection(not with
+     * timeout) */
+    if (err_code != AVDT_ERR_TIMEOUT) {
+      p_scb->recfg_sup = false;
+    }
+    /* started flag is false when reconfigure command is sent */
+    /* drop the buffers queued in L2CAP */
+    L2CA_FlushChannel(p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
+    AVDT_CloseReq(p_scb->avdt_handle);
+  } else {
+    /* update the codec info after rcfg cfm */
+    APPL_TRACE_DEBUG(
+        "%s: updating from codec %s to codec %s", __func__,
+        A2DP_CodecName(p_scb->cfg.codec_info),
+        A2DP_CodecName(p_data->str_msg.msg.reconfig_cfm.p_cfg->codec_info));
+    memcpy(p_scb->cfg.codec_info,
+           p_data->str_msg.msg.reconfig_cfm.p_cfg->codec_info, AVDT_CODEC_SIZE);
+    /* take the SSM back to OPEN state */
+    bta_av_ssm_execute(p_scb, BTA_AV_STR_OPEN_OK_EVT, NULL);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rcfg_open
+ *
+ * Description      AVDT is connected. open the stream with the new
+ *                  configuration
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_rcfg_open(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  APPL_TRACE_DEBUG("%s: num_disc_snks = %d", __func__, p_scb->num_disc_snks);
+
+  if (p_scb->num_disc_snks == 0) {
+    /* Need to update call-out module so that it will be ready for discover */
+    p_scb->p_cos->stop(p_scb->hndl);
+
+    /* send avdtp discover request */
+    AVDT_DiscoverReq(p_scb->peer_addr, p_scb->sep_info, BTA_AV_NUM_SEPS,
+                     bta_av_dt_cback[p_scb->hdi]);
+  } else {
+    memcpy(p_scb->cfg.codec_info, p_scb->p_cap->codec_info, AVDT_CODEC_SIZE);
+    /* we may choose to use a different SEP at reconfig.
+     * adjust the sep_idx now */
+    bta_av_adjust_seps_idx(p_scb, bta_av_get_scb_handle(p_scb, AVDT_TSEP_SRC));
+
+    /* open the stream with the new config */
+    p_scb->sep_info_idx = p_scb->rcfg_idx;
+    AVDT_OpenReq(p_scb->avdt_handle, p_scb->peer_addr,
+                 p_scb->sep_info[p_scb->sep_info_idx].seid, p_scb->p_cap);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_security_rej
+ *
+ * Description      Send an AVDTP security reject.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_security_rej(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_BAD_STATE,
+                   NULL, 0);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_chk_2nd_start
+ *
+ * Description      check if this is 2nd stream and if it needs to be started.
+ *                  This function needs to be kept very similar to
+ *                  bta_av_chk_start
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_chk_2nd_start(tBTA_AV_SCB* p_scb,
+                          UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  tBTA_AV_SCB* p_scbi;
+  int i;
+  bool new_started = false;
+
+  if ((p_scb->chnl == BTA_AV_CHNL_AUDIO) && (bta_av_cb.audio_open_cnt >= 2)) {
+    /* more than one audio channel is connected */
+    if (!(p_scb->role & BTA_AV_ROLE_SUSPEND_OPT)) {
+      /* this channel does not need to be reconfigured.
+       * if there is other channel streaming, start the stream now */
+      for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+        p_scbi = bta_av_cb.p_scb[i];
+        if (p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started) {
+          if (!new_started) {
+            /* start the new stream */
+            new_started = true;
+            bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL);
+          }
+          /* may need to update the flush timeout of this already started stream
+           */
+          if (p_scbi->co_started != bta_av_cb.audio_open_cnt) {
+            p_scbi->co_started = bta_av_cb.audio_open_cnt;
+            L2CA_SetFlushTimeout(
+                p_scbi->peer_addr,
+                p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1]);
+          }
+        }
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_open_rc
+ *
+ * Description      Send a message to main SM to open RC channel.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_open_rc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  tBTA_AV_START start;
+
+  APPL_TRACE_DEBUG("%s: use_rc: %d, wait: x%x role:x%x", __func__,
+                   p_scb->use_rc, p_scb->wait, p_scb->role);
+  if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) &&
+      (p_scb->q_tag == BTA_AV_Q_TAG_START)) {
+    /* waiting for role switch for some reason & the timer expires */
+    if (!bta_av_link_role_ok(p_scb, A2DP_SET_ONE_BIT)) {
+      APPL_TRACE_ERROR(
+          "%s: failed to start streaming for role management reasons!!",
+          __func__);
+      alarm_cancel(p_scb->avrc_ct_timer);
+      start.chnl = p_scb->chnl;
+      start.status = BTA_AV_FAIL_ROLE;
+      start.initiator = true;
+      start.hndl = p_scb->hndl;
+      p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+      bta_av_cb.rs_idx = 0;
+      (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV*)&start);
+    } else {
+      /* role switch is done. continue to start streaming */
+      bta_av_cb.rs_idx = 0;
+      p_data->hdr.offset = BTA_AV_RS_OK;
+      bta_av_start_ok(p_scb, p_data);
+    }
+    return;
+  }
+
+  if (p_scb->use_rc == true || (p_scb->role & BTA_AV_ROLE_AD_ACP)) {
+    if (bta_av_cb.disc) {
+      /* AVRC discover db is in use */
+      if (p_scb->rc_handle == BTA_AV_RC_HANDLE_NONE) {
+        /* AVRC channel is not connected. delay a little bit */
+        if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) == 0) {
+          bta_sys_start_timer(p_scb->avrc_ct_timer, BTA_AV_RC_DISC_TIME_VAL,
+                              BTA_AV_AVRC_TIMER_EVT, p_scb->hndl);
+        } else {
+          p_scb->wait |= BTA_AV_WAIT_CHECK_RC;
+        }
+      }
+    } else {
+      /* use main SM for AVRC SDP activities */
+      bta_av_rc_disc((uint8_t)(p_scb->hdi + 1));
+    }
+  } else {
+    if (BTA_AV_RC_HANDLE_NONE != p_scb->rc_handle) {
+      /* the open API said that this handle does not want a RC connection.
+       * disconnect it now */
+      AVRC_Close(p_scb->rc_handle);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_open_at_inc
+ *
+ * Description      This function is called if API open is called by application
+ *                  while state-machine is at incoming state.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_open_at_inc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  memcpy(&(p_scb->open_api), &(p_data->api_open), sizeof(tBTA_AV_API_OPEN));
+
+  if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR) {
+    p_scb->coll_mask |= BTA_AV_COLL_API_CALLED;
+
+    /* API open will be handled at timeout if SNK did not start signalling. */
+    /* API open will be ignored if SNK starts signalling.                   */
+  } else {
+    /* SNK did not start signalling, API was called N seconds timeout. */
+    /* We need to switch to INIT state and start opening connection. */
+    p_scb->coll_mask = 0;
+    bta_av_set_scb_sst_init(p_scb);
+
+    tBTA_AV_API_OPEN* p_buf =
+        (tBTA_AV_API_OPEN*)osi_malloc(sizeof(tBTA_AV_API_OPEN));
+    memcpy(p_buf, &(p_scb->open_api), sizeof(tBTA_AV_API_OPEN));
+    p_scb->skip_sdp = true;
+    bta_sys_sendmsg(p_buf);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_offload_req
+ *
+ * Description      This function is called if application requests offload of
+ *                  a2dp audio.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_offload_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  tBTA_AV_STATUS status = BTA_AV_FAIL_RESOURCES;
+  uint16_t mtu = bta_av_chk_mtu(p_scb, p_scb->stream_mtu);
+
+  APPL_TRACE_DEBUG("%s: stream %s, audio channels open %d", __func__,
+                   p_scb->started ? "STARTED" : "STOPPED",
+                   bta_av_cb.audio_open_cnt);
+
+  /* Check if stream has already been started. */
+  /* Support offload if only one audio source stream is open. */
+  if (p_scb->started != true) {
+    status = BTA_AV_FAIL_STREAM;
+
+  } else if (bta_av_cb.audio_open_cnt == 1 &&
+             p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC &&
+             p_scb->chnl == BTA_AV_CHNL_AUDIO) {
+    bt_vendor_op_a2dp_offload_t a2dp_offload_start;
+
+    if (L2CA_GetConnectionConfig(
+            p_scb->l2c_cid, &a2dp_offload_start.acl_data_size,
+            &a2dp_offload_start.remote_cid, &a2dp_offload_start.lm_handle)) {
+      APPL_TRACE_DEBUG("%s: l2cmtu %d lcid 0x%02X rcid 0x%02X lm_handle 0x%02X",
+                       __func__, a2dp_offload_start.acl_data_size,
+                       p_scb->l2c_cid, a2dp_offload_start.remote_cid,
+                       a2dp_offload_start.lm_handle);
+
+      a2dp_offload_start.bta_av_handle = p_scb->hndl;
+      a2dp_offload_start.xmit_quota = BTA_AV_A2DP_OFFLOAD_XMIT_QUOTA;
+      a2dp_offload_start.stream_mtu =
+          (mtu < p_scb->stream_mtu) ? mtu : p_scb->stream_mtu;
+      a2dp_offload_start.local_cid = p_scb->l2c_cid;
+      a2dp_offload_start.is_flushable = true;
+      a2dp_offload_start.stream_source =
+          ((uint32_t)(p_scb->cfg.codec_info[1] | p_scb->cfg.codec_info[2]));
+
+      memcpy(a2dp_offload_start.codec_info, p_scb->cfg.codec_info,
+             sizeof(a2dp_offload_start.codec_info));
+
+      if (!vendor_get_interface()->send_command(
+              (vendor_opcode_t)BT_VND_OP_A2DP_OFFLOAD_START,
+              &a2dp_offload_start)) {
+        status = BTA_AV_SUCCESS;
+        p_scb->offload_start_pending = true;
+      }
+    }
+  }
+
+  if (status != BTA_AV_SUCCESS)
+    (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, (tBTA_AV*)&status);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_offload_rsp
+ *
+ * Description      This function is called when the vendor lib responds to
+ *                  BT_VND_OP_A2DP_OFFLOAD_START.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_offload_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+  tBTA_AV_STATUS status = p_data->api_status_rsp.status;
+
+  APPL_TRACE_DEBUG("%s: stream %s status %s", __func__,
+                   p_scb->started ? "STARTED" : "STOPPED",
+                   status ? "FAIL" : "SUCCESS");
+
+  /* Check if stream has already been started. */
+  if (status == BTA_AV_SUCCESS && p_scb->started != true) {
+    status = BTA_AV_FAIL_STREAM;
+  }
+
+  p_scb->offload_start_pending = false;
+  (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, (tBTA_AV*)&status);
+}
diff --git a/bt/bta/av/bta_av_act.cc b/bt/bta/av/bta_av_act.cc
new file mode 100644
index 0000000..535eab4
--- /dev/null
+++ b/bt/bta/av/bta_av_act.cc
@@ -0,0 +1,2150 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-2016 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 action functions for advanced audio/video main state
+ *  machine.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bta_av"
+
+#include "bt_target.h"
+
+#include <string.h>
+
+#include "avdt_api.h"
+#include "bta_av_api.h"
+#include "bta_av_int.h"
+#include "l2c_api.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+#include "utl.h"
+
+#if (BTA_AR_INCLUDED == TRUE)
+#include "bta_ar_api.h"
+#endif
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+/* the timeout to wait for open req after setconfig for incoming connections */
+#ifndef BTA_AV_SIGNALLING_TIMEOUT_MS
+#define BTA_AV_SIGNALLING_TIMEOUT_MS (8 * 1000) /* 8 seconds */
+#endif
+
+/* Time to wait for signalling from SNK when it is initiated from SNK. */
+/* If not, we will start signalling from SRC. */
+#ifndef BTA_AV_ACCEPT_SIGNALLING_TIMEOUT_MS
+#define BTA_AV_ACCEPT_SIGNALLING_TIMEOUT_MS (2 * 1000) /* 2 seconds */
+#endif
+
+extern fixed_queue_t* btu_bta_alarm_queue;
+
+static void bta_av_accept_signalling_timer_cback(void* data);
+
+#ifndef AVRC_MIN_META_CMD_LEN
+#define AVRC_MIN_META_CMD_LEN 20
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_av_get_rcb_by_shdl
+ *
+ * Description      find the RCB associated with the given SCB handle.
+ *
+ * Returns          tBTA_AV_RCB
+ *
+ ******************************************************************************/
+tBTA_AV_RCB* bta_av_get_rcb_by_shdl(uint8_t shdl) {
+  tBTA_AV_RCB* p_rcb = NULL;
+  int i;
+
+  for (i = 0; i < BTA_AV_NUM_RCB; i++) {
+    if (bta_av_cb.rcb[i].shdl == shdl &&
+        bta_av_cb.rcb[i].handle != BTA_AV_RC_HANDLE_NONE) {
+      p_rcb = &bta_av_cb.rcb[i];
+      break;
+    }
+  }
+  return p_rcb;
+}
+#define BTA_AV_STS_NO_RSP 0xFF /* a number not used by tAVRC_STS */
+
+/*******************************************************************************
+ *
+ * Function         bta_av_del_rc
+ *
+ * Description      delete the given AVRC handle.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_del_rc(tBTA_AV_RCB* p_rcb) {
+  tBTA_AV_SCB* p_scb;
+  uint8_t rc_handle; /* connected AVRCP handle */
+
+  p_scb = NULL;
+  if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE) {
+    if (p_rcb->shdl) {
+      /* Validate array index*/
+      if ((p_rcb->shdl - 1) < BTA_AV_NUM_STRS) {
+        p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1];
+      }
+      if (p_scb) {
+        APPL_TRACE_DEBUG("bta_av_del_rc shdl:%d, srch:%d rc_handle:%d",
+                         p_rcb->shdl, p_scb->rc_handle, p_rcb->handle);
+        if (p_scb->rc_handle == p_rcb->handle)
+          p_scb->rc_handle = BTA_AV_RC_HANDLE_NONE;
+        /* just in case the RC timer is active
+        if (bta_av_cb.features & BTA_AV_FEAT_RCCT && p_scb->chnl ==
+        BTA_AV_CHNL_AUDIO) */
+        alarm_cancel(p_scb->avrc_ct_timer);
+      }
+    }
+
+    APPL_TRACE_EVENT(
+        "bta_av_del_rc  handle: %d status=0x%x, rc_acp_handle:%d, idx:%d",
+        p_rcb->handle, p_rcb->status, bta_av_cb.rc_acp_handle,
+        bta_av_cb.rc_acp_idx);
+    rc_handle = p_rcb->handle;
+    if (!(p_rcb->status & BTA_AV_RC_CONN_MASK) ||
+        ((p_rcb->status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT)) {
+      p_rcb->status = 0;
+      p_rcb->handle = BTA_AV_RC_HANDLE_NONE;
+      p_rcb->shdl = 0;
+      p_rcb->lidx = 0;
+    }
+    /* else ACP && connected. do not clear the handle yet */
+    AVRC_Close(rc_handle);
+    if (rc_handle == bta_av_cb.rc_acp_handle)
+      bta_av_cb.rc_acp_handle = BTA_AV_RC_HANDLE_NONE;
+    APPL_TRACE_EVENT(
+        "end del_rc handle: %d status=0x%x, rc_acp_handle:%d, lidx:%d",
+        p_rcb->handle, p_rcb->status, bta_av_cb.rc_acp_handle, p_rcb->lidx);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_close_all_rc
+ *
+ * Description      close the all AVRC handle.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_av_close_all_rc(tBTA_AV_CB* p_cb) {
+  int i;
+
+  for (i = 0; i < BTA_AV_NUM_RCB; i++) {
+    if ((p_cb->disabling == true) || (bta_av_cb.rcb[i].shdl != 0))
+      bta_av_del_rc(&bta_av_cb.rcb[i]);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_del_sdp_rec
+ *
+ * Description      delete the given SDP record handle.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_av_del_sdp_rec(uint32_t* p_sdp_handle) {
+  if (*p_sdp_handle != 0) {
+    SDP_DeleteRecord(*p_sdp_handle);
+    *p_sdp_handle = 0;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_avrc_sdp_cback
+ *
+ * Description      AVRCP service discovery callback.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_av_avrc_sdp_cback(UNUSED_ATTR uint16_t status) {
+  BT_HDR* p_msg = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_msg->event = BTA_AV_SDP_AVRC_DISC_EVT;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rc_ctrl_cback
+ *
+ * Description      AVRCP control callback.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_av_rc_ctrl_cback(uint8_t handle, uint8_t event,
+                                 UNUSED_ATTR uint16_t result,
+                                 BD_ADDR peer_addr) {
+  uint16_t msg_event = 0;
+
+  APPL_TRACE_EVENT("%s handle: %d event=0x%x", __func__, handle, event);
+  if (event == AVRC_OPEN_IND_EVT) {
+    /* save handle of opened connection
+    bta_av_cb.rc_handle = handle;*/
+
+    msg_event = BTA_AV_AVRC_OPEN_EVT;
+  } else if (event == AVRC_CLOSE_IND_EVT) {
+    msg_event = BTA_AV_AVRC_CLOSE_EVT;
+  } else if (event == AVRC_BROWSE_OPEN_IND_EVT) {
+    msg_event = BTA_AV_AVRC_BROWSE_OPEN_EVT;
+  } else if (event == AVRC_BROWSE_CLOSE_IND_EVT) {
+    msg_event = BTA_AV_AVRC_BROWSE_CLOSE_EVT;
+  }
+
+  if (msg_event) {
+    tBTA_AV_RC_CONN_CHG* p_msg =
+        (tBTA_AV_RC_CONN_CHG*)osi_malloc(sizeof(tBTA_AV_RC_CONN_CHG));
+    p_msg->hdr.event = msg_event;
+    p_msg->handle = handle;
+    if (peer_addr) bdcpy(p_msg->peer_addr, peer_addr);
+    bta_sys_sendmsg(p_msg);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rc_msg_cback
+ *
+ * Description      AVRCP message callback.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_av_rc_msg_cback(uint8_t handle, uint8_t label, uint8_t opcode,
+                                tAVRC_MSG* p_msg) {
+  uint8_t* p_data_src = NULL;
+  uint16_t data_len = 0;
+
+  APPL_TRACE_DEBUG("%s handle: %u opcode=0x%x", __func__, handle, opcode);
+
+  /* Copy avrc packet into BTA message buffer (for sending to BTA state machine)
+   */
+
+  /* Get size of payload data  (for vendor and passthrough messages only; for
+   * browsing
+   * messages, use zero-copy) */
+  if (opcode == AVRC_OP_VENDOR && p_msg->vendor.p_vendor_data != NULL) {
+    p_data_src = p_msg->vendor.p_vendor_data;
+    data_len = (uint16_t)p_msg->vendor.vendor_len;
+  } else if (opcode == AVRC_OP_PASS_THRU && p_msg->pass.p_pass_data != NULL) {
+    p_data_src = p_msg->pass.p_pass_data;
+    data_len = (uint16_t)p_msg->pass.pass_len;
+  }
+
+  /* Create a copy of the message */
+  tBTA_AV_RC_MSG* p_buf =
+      (tBTA_AV_RC_MSG*)osi_malloc(sizeof(tBTA_AV_RC_MSG) + data_len);
+
+  p_buf->hdr.event = BTA_AV_AVRC_MSG_EVT;
+  p_buf->handle = handle;
+  p_buf->label = label;
+  p_buf->opcode = opcode;
+  memcpy(&p_buf->msg, p_msg, sizeof(tAVRC_MSG));
+  /* Copy the data payload, and set the pointer to it */
+  if (p_data_src != NULL) {
+    uint8_t* p_data_dst = (uint8_t*)(p_buf + 1);
+    memcpy(p_data_dst, p_data_src, data_len);
+
+    /* Update bta message buffer to point to payload data */
+    /* (Note AVRC_OP_BROWSING uses zero-copy: p_buf->msg.browse.p_browse_data
+     * already points to original avrc buffer) */
+    if (opcode == AVRC_OP_VENDOR)
+      p_buf->msg.vendor.p_vendor_data = p_data_dst;
+    else if (opcode == AVRC_OP_PASS_THRU)
+      p_buf->msg.pass.p_pass_data = p_data_dst;
+  }
+
+  if (opcode == AVRC_OP_BROWSE) {
+    /* set p_pkt to NULL, so avrc would not free the buffer */
+    p_msg->browse.p_browse_pkt = NULL;
+  }
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rc_create
+ *
+ * Description      alloc RCB and call AVRC_Open
+ *
+ * Returns          the created rc handle
+ *
+ ******************************************************************************/
+uint8_t bta_av_rc_create(tBTA_AV_CB* p_cb, uint8_t role, uint8_t shdl,
+                         uint8_t lidx) {
+  tAVRC_CONN_CB ccb;
+  BD_ADDR_PTR bda = (BD_ADDR_PTR)bd_addr_any;
+  uint8_t status = BTA_AV_RC_ROLE_ACP;
+  tBTA_AV_SCB* p_scb = p_cb->p_scb[shdl - 1];
+  int i;
+  uint8_t rc_handle;
+  tBTA_AV_RCB* p_rcb;
+
+  if (role == AVCT_INT) {
+    bda = p_scb->peer_addr;
+    status = BTA_AV_RC_ROLE_INT;
+  } else {
+    if ((p_rcb = bta_av_get_rcb_by_shdl(shdl)) != NULL) {
+      APPL_TRACE_ERROR("bta_av_rc_create ACP handle exist for shdl:%d", shdl);
+      return p_rcb->handle;
+    }
+  }
+
+  ccb.p_ctrl_cback = bta_av_rc_ctrl_cback;
+  ccb.p_msg_cback = bta_av_rc_msg_cback;
+  ccb.company_id = p_bta_av_cfg->company_id;
+  ccb.conn = role;
+  /* note: BTA_AV_FEAT_RCTG = AVRC_CT_TARGET, BTA_AV_FEAT_RCCT = AVRC_CT_CONTROL
+   */
+  ccb.control = p_cb->features & (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_RCCT |
+                                  BTA_AV_FEAT_METADATA | AVRC_CT_PASSIVE);
+
+  if (AVRC_Open(&rc_handle, &ccb, bda) != AVRC_SUCCESS)
+    return BTA_AV_RC_HANDLE_NONE;
+
+  i = rc_handle;
+  p_rcb = &p_cb->rcb[i];
+
+  if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE) {
+    APPL_TRACE_ERROR("bta_av_rc_create found duplicated handle:%d", rc_handle);
+  }
+
+  p_rcb->handle = rc_handle;
+  p_rcb->status = status;
+  p_rcb->shdl = shdl;
+  p_rcb->lidx = lidx;
+  p_rcb->peer_features = 0;
+  if (lidx == (BTA_AV_NUM_LINKS + 1)) {
+    /* this LIDX is reserved for the AVRCP ACP connection */
+    p_cb->rc_acp_handle = p_rcb->handle;
+    p_cb->rc_acp_idx = (i + 1);
+    APPL_TRACE_DEBUG("rc_acp_handle:%d idx:%d", p_cb->rc_acp_handle,
+                     p_cb->rc_acp_idx);
+  }
+  APPL_TRACE_DEBUG(
+      "create %d, role: %d, shdl:%d, rc_handle:%d, lidx:%d, status:0x%x", i,
+      role, shdl, p_rcb->handle, lidx, p_rcb->status);
+
+  return rc_handle;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_valid_group_navi_msg
+ *
+ * Description      Check if it is Group Navigation Msg for Metadata
+ *
+ * Returns          BTA_AV_RSP_ACCEPT or BTA_AV_RSP_NOT_IMPL.
+ *
+ ******************************************************************************/
+static tBTA_AV_CODE bta_av_group_navi_supported(uint8_t len, uint8_t* p_data,
+                                                bool is_inquiry) {
+  tBTA_AV_CODE ret = BTA_AV_RSP_NOT_IMPL;
+  uint8_t* p_ptr = p_data;
+  uint16_t u16;
+  uint32_t u32;
+
+  if (p_bta_av_cfg->avrc_group && len == BTA_GROUP_NAVI_MSG_OP_DATA_LEN) {
+    BTA_AV_BE_STREAM_TO_CO_ID(u32, p_ptr);
+    BE_STREAM_TO_UINT16(u16, p_ptr);
+
+    if (u32 == AVRC_CO_METADATA) {
+      if (is_inquiry) {
+        if (u16 <= AVRC_PDU_PREV_GROUP) ret = BTA_AV_RSP_IMPL_STBL;
+      } else {
+        if (u16 <= AVRC_PDU_PREV_GROUP)
+          ret = BTA_AV_RSP_ACCEPT;
+        else
+          ret = BTA_AV_RSP_REJ;
+      }
+    }
+  }
+
+  return ret;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_op_supported
+ *
+ * Description      Check if remote control operation is supported.
+ *
+ * Returns          BTA_AV_RSP_ACCEPT of supported, BTA_AV_RSP_NOT_IMPL if not.
+ *
+ ******************************************************************************/
+static tBTA_AV_CODE bta_av_op_supported(tBTA_AV_RC rc_id, bool is_inquiry) {
+  tBTA_AV_CODE ret_code = BTA_AV_RSP_NOT_IMPL;
+
+  if (p_bta_av_rc_id) {
+    if (is_inquiry) {
+      if (p_bta_av_rc_id[rc_id >> 4] & (1 << (rc_id & 0x0F))) {
+        ret_code = BTA_AV_RSP_IMPL_STBL;
+      }
+    } else {
+      if (p_bta_av_rc_id[rc_id >> 4] & (1 << (rc_id & 0x0F))) {
+        ret_code = BTA_AV_RSP_ACCEPT;
+      } else if ((p_bta_av_cfg->rc_pass_rsp == BTA_AV_RSP_INTERIM) &&
+                 p_bta_av_rc_id_ac) {
+        if (p_bta_av_rc_id_ac[rc_id >> 4] & (1 << (rc_id & 0x0F))) {
+          ret_code = BTA_AV_RSP_INTERIM;
+        }
+      }
+    }
+  }
+  return ret_code;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_find_lcb
+ *
+ * Description      Given BD_addr, find the associated LCB.
+ *
+ * Returns          NULL, if not found.
+ *
+ ******************************************************************************/
+tBTA_AV_LCB* bta_av_find_lcb(BD_ADDR addr, uint8_t op) {
+  tBTA_AV_CB* p_cb = &bta_av_cb;
+  int xx;
+  uint8_t mask;
+  tBTA_AV_LCB* p_lcb = NULL;
+
+  for (xx = 0; xx < BTA_AV_NUM_LINKS; xx++) {
+    mask = 1 << xx; /* the used mask for this lcb */
+    if ((mask & p_cb->conn_lcb) && 0 == (bdcmp(p_cb->lcb[xx].addr, addr))) {
+      p_lcb = &p_cb->lcb[xx];
+      if (op == BTA_AV_LCB_FREE) {
+        p_cb->conn_lcb &= ~mask; /* clear the connect mask */
+        APPL_TRACE_DEBUG("conn_lcb: 0x%x", p_cb->conn_lcb);
+      }
+      break;
+    }
+  }
+  return p_lcb;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rc_opened
+ *
+ * Description      Set AVRCP state to opened.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_rc_opened(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) {
+  tBTA_AV_RC_OPEN rc_open;
+  tBTA_AV_SCB* p_scb;
+  int i;
+  uint8_t shdl = 0;
+  tBTA_AV_LCB* p_lcb;
+  tBTA_AV_RCB* p_rcb;
+  uint8_t tmp;
+  uint8_t disc = 0;
+
+  /* find the SCB & stop the timer */
+  for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+    p_scb = p_cb->p_scb[i];
+    if (p_scb && bdcmp(p_scb->peer_addr, p_data->rc_conn_chg.peer_addr) == 0) {
+      p_scb->rc_handle = p_data->rc_conn_chg.handle;
+      APPL_TRACE_DEBUG("bta_av_rc_opened shdl:%d, srch %d", i + 1,
+                       p_scb->rc_handle);
+      shdl = i + 1;
+      LOG_INFO(LOG_TAG, "%s allow incoming AVRCP connections:%d", __func__,
+               p_scb->use_rc);
+      alarm_cancel(p_scb->avrc_ct_timer);
+      disc = p_scb->hndl;
+      break;
+    }
+  }
+
+  i = p_data->rc_conn_chg.handle;
+  if (p_cb->rcb[i].handle == BTA_AV_RC_HANDLE_NONE) {
+    APPL_TRACE_ERROR("not a valid handle:%d any more", i);
+    return;
+  }
+
+  APPL_TRACE_DEBUG("%s local features %d peer features %d", __func__,
+                   p_cb->features, p_cb->rcb[i].peer_features);
+
+  /* listen to browsing channel when the connection is open,
+   * if peer initiated AVRCP connection and local device supports browsing
+   * channel */
+  AVRC_OpenBrowse(p_data->rc_conn_chg.handle, AVCT_ACP);
+
+  if (p_cb->rcb[i].lidx == (BTA_AV_NUM_LINKS + 1) && shdl != 0) {
+    /* rc is opened on the RC only ACP channel, but is for a specific
+     * SCB -> need to switch RCBs */
+    p_rcb = bta_av_get_rcb_by_shdl(shdl);
+    if (p_rcb) {
+      p_rcb->shdl = p_cb->rcb[i].shdl;
+      tmp = p_rcb->lidx;
+      p_rcb->lidx = p_cb->rcb[i].lidx;
+      p_cb->rcb[i].lidx = tmp;
+      p_cb->rc_acp_handle = p_rcb->handle;
+      p_cb->rc_acp_idx = (p_rcb - p_cb->rcb) + 1;
+      APPL_TRACE_DEBUG("switching RCB rc_acp_handle:%d idx:%d",
+                       p_cb->rc_acp_handle, p_cb->rc_acp_idx);
+    }
+  }
+
+  p_cb->rcb[i].shdl = shdl;
+  rc_open.rc_handle = i;
+  APPL_TRACE_ERROR("bta_av_rc_opened rcb[%d] shdl:%d lidx:%d/%d", i, shdl,
+                   p_cb->rcb[i].lidx, p_cb->lcb[BTA_AV_NUM_LINKS].lidx);
+  p_cb->rcb[i].status |= BTA_AV_RC_CONN_MASK;
+
+  if (!shdl && 0 == p_cb->lcb[BTA_AV_NUM_LINKS].lidx) {
+    /* no associated SCB -> connected to an RC only device
+     * update the index to the extra LCB */
+    p_lcb = &p_cb->lcb[BTA_AV_NUM_LINKS];
+    bdcpy(p_lcb->addr, p_data->rc_conn_chg.peer_addr);
+    APPL_TRACE_DEBUG("rc_only bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+                     p_lcb->addr[0], p_lcb->addr[1], p_lcb->addr[2],
+                     p_lcb->addr[3], p_lcb->addr[4], p_lcb->addr[5]);
+    p_lcb->lidx = BTA_AV_NUM_LINKS + 1;
+    p_cb->rcb[i].lidx = p_lcb->lidx;
+    p_lcb->conn_msk = 1;
+    APPL_TRACE_ERROR("rcb[%d].lidx=%d, lcb.conn_msk=x%x", i, p_cb->rcb[i].lidx,
+                     p_lcb->conn_msk);
+    disc = p_data->rc_conn_chg.handle | BTA_AV_CHNL_MSK;
+  }
+
+  bdcpy(rc_open.peer_addr, p_data->rc_conn_chg.peer_addr);
+  rc_open.peer_features = p_cb->rcb[i].peer_features;
+  rc_open.status = BTA_AV_SUCCESS;
+  APPL_TRACE_DEBUG("%s local features:x%x peer_features:x%x", __func__,
+                   p_cb->features, rc_open.peer_features);
+  if (rc_open.peer_features == 0) {
+    /* we have not done SDP on peer RC capabilities.
+     * peer must have initiated the RC connection */
+    if (p_cb->features & BTA_AV_FEAT_RCCT)
+      rc_open.peer_features |= BTA_AV_FEAT_RCTG;
+    if (p_cb->features & BTA_AV_FEAT_RCTG)
+      rc_open.peer_features |= BTA_AV_FEAT_RCCT;
+
+    bta_av_rc_disc(disc);
+  }
+  (*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, (tBTA_AV*)&rc_open);
+
+  /* if local initiated AVRCP connection and both peer and locals device support
+   * browsing channel, open the browsing channel now
+   * TODO (sanketa): Some TG would not broadcast browse feature hence check
+   * inter-op. */
+  if ((p_cb->features & BTA_AV_FEAT_BROWSE) &&
+      (rc_open.peer_features & BTA_AV_FEAT_BROWSE) &&
+      ((p_cb->rcb[i].status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT)) {
+    APPL_TRACE_DEBUG("%s opening AVRC Browse channel", __func__);
+    AVRC_OpenBrowse(p_data->rc_conn_chg.handle, AVCT_INT);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rc_remote_cmd
+ *
+ * Description      Send an AVRCP remote control command.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_rc_remote_cmd(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) {
+  tBTA_AV_RCB* p_rcb;
+  if (p_cb->features & BTA_AV_FEAT_RCCT) {
+    if (p_data->hdr.layer_specific < BTA_AV_NUM_RCB) {
+      p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
+      if (p_rcb->status & BTA_AV_RC_CONN_MASK) {
+        AVRC_PassCmd(p_rcb->handle, p_data->api_remote_cmd.label,
+                     &p_data->api_remote_cmd.msg);
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rc_vendor_cmd
+ *
+ * Description      Send an AVRCP vendor specific command.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_rc_vendor_cmd(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) {
+  tBTA_AV_RCB* p_rcb;
+  if ((p_cb->features & (BTA_AV_FEAT_RCCT | BTA_AV_FEAT_VENDOR)) ==
+      (BTA_AV_FEAT_RCCT | BTA_AV_FEAT_VENDOR)) {
+    if (p_data->hdr.layer_specific < BTA_AV_NUM_RCB) {
+      p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
+      AVRC_VendorCmd(p_rcb->handle, p_data->api_vendor.label,
+                     &p_data->api_vendor.msg);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rc_vendor_rsp
+ *
+ * Description      Send an AVRCP vendor specific response.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_rc_vendor_rsp(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) {
+  tBTA_AV_RCB* p_rcb;
+  if ((p_cb->features & (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_VENDOR)) ==
+      (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_VENDOR)) {
+    if (p_data->hdr.layer_specific < BTA_AV_NUM_RCB) {
+      p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
+      AVRC_VendorRsp(p_rcb->handle, p_data->api_vendor.label,
+                     &p_data->api_vendor.msg);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rc_meta_rsp
+ *
+ * Description      Send an AVRCP metadata/advanced control command/response.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_rc_meta_rsp(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) {
+  tBTA_AV_RCB* p_rcb;
+  bool do_free = true;
+
+  if ((p_cb->features & BTA_AV_FEAT_METADATA) &&
+      (p_data->hdr.layer_specific < BTA_AV_NUM_RCB)) {
+    if ((p_data->api_meta_rsp.is_rsp && (p_cb->features & BTA_AV_FEAT_RCTG)) ||
+        (!p_data->api_meta_rsp.is_rsp && (p_cb->features & BTA_AV_FEAT_RCCT))) {
+      p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
+      if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE) {
+        AVRC_MsgReq(p_rcb->handle, p_data->api_meta_rsp.label,
+                    p_data->api_meta_rsp.rsp_code, p_data->api_meta_rsp.p_pkt);
+        do_free = false;
+      }
+    }
+  }
+
+  if (do_free) osi_free_and_reset((void**)&p_data->api_meta_rsp.p_pkt);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rc_free_rsp
+ *
+ * Description      free an AVRCP metadata command buffer.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_rc_free_rsp(UNUSED_ATTR tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) {
+  osi_free_and_reset((void**)&p_data->api_meta_rsp.p_pkt);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rc_free_browse_msg
+ *
+ * Description      free an AVRCP browse message buffer.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_rc_free_browse_msg(UNUSED_ATTR tBTA_AV_CB* p_cb,
+                               tBTA_AV_DATA* p_data) {
+  if (p_data->rc_msg.opcode == AVRC_OP_BROWSE) {
+    osi_free_and_reset((void**)&p_data->rc_msg.msg.browse.p_browse_pkt);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_chk_notif_evt_id
+ *
+ * Description      make sure the requested player id is valid.
+ *
+ * Returns          BTA_AV_STS_NO_RSP, if no error
+ *
+ ******************************************************************************/
+static tAVRC_STS bta_av_chk_notif_evt_id(tAVRC_MSG_VENDOR* p_vendor) {
+  tAVRC_STS status = BTA_AV_STS_NO_RSP;
+  uint8_t xx;
+  uint16_t u16;
+  uint8_t* p = p_vendor->p_vendor_data + 2;
+
+  BE_STREAM_TO_UINT16(u16, p);
+  /* double check the fixed length */
+  if ((u16 != 5) || (p_vendor->vendor_len != 9)) {
+    status = AVRC_STS_INTERNAL_ERR;
+  } else {
+    /* make sure the player_id is valid */
+    for (xx = 0; xx < p_bta_av_cfg->num_evt_ids; xx++) {
+      if (*p == p_bta_av_cfg->p_meta_evt_ids[xx]) {
+        break;
+      }
+    }
+    if (xx == p_bta_av_cfg->num_evt_ids) {
+      status = AVRC_STS_BAD_PARAM;
+    }
+  }
+
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_proc_meta_cmd
+ *
+ * Description      Process an AVRCP metadata command from the peer.
+ *
+ * Returns          true to respond immediately
+ *
+ ******************************************************************************/
+tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE* p_rc_rsp,
+                                 tBTA_AV_RC_MSG* p_msg, uint8_t* p_ctype) {
+  tBTA_AV_EVT evt = BTA_AV_META_MSG_EVT;
+  uint8_t u8, pdu, *p;
+  uint16_t u16;
+  tAVRC_MSG_VENDOR* p_vendor = &p_msg->msg.vendor;
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+  pdu = *(p_vendor->p_vendor_data);
+  p_rc_rsp->pdu = pdu;
+  *p_ctype = AVRC_RSP_REJ;
+
+  /* Check to ansure a  valid minimum meta data length */
+  if ((AVRC_MIN_META_CMD_LEN + p_vendor->vendor_len) > AVRC_META_CMD_BUF_SIZE) {
+    /* reject it */
+    p_rc_rsp->rsp.status = AVRC_STS_BAD_PARAM;
+    APPL_TRACE_ERROR("%s Invalid meta-command length: %d", __func__,
+                     p_vendor->vendor_len);
+    return 0;
+  }
+
+  /* Metadata messages only use PANEL sub-unit type */
+  if (p_vendor->hdr.subunit_type != AVRC_SUB_PANEL) {
+    APPL_TRACE_DEBUG("SUBUNIT must be PANEL");
+    /* reject it */
+    evt = 0;
+    p_vendor->hdr.ctype = BTA_AV_RSP_NOT_IMPL;
+    p_vendor->vendor_len = 0;
+    p_rc_rsp->rsp.status = AVRC_STS_BAD_PARAM;
+  } else if (!AVRC_IsValidAvcType(pdu, p_vendor->hdr.ctype)) {
+    APPL_TRACE_DEBUG("Invalid pdu/ctype: 0x%x, %d", pdu, p_vendor->hdr.ctype);
+    /* reject invalid message without reporting to app */
+    evt = 0;
+    p_rc_rsp->rsp.status = AVRC_STS_BAD_CMD;
+  } else {
+    switch (pdu) {
+      case AVRC_PDU_GET_CAPABILITIES:
+        /* process GetCapabilities command without reporting the event to app */
+        evt = 0;
+        u8 = *(p_vendor->p_vendor_data + 4);
+        p = p_vendor->p_vendor_data + 2;
+        p_rc_rsp->get_caps.capability_id = u8;
+        BE_STREAM_TO_UINT16(u16, p);
+        if ((u16 != 1) || (p_vendor->vendor_len != 5)) {
+          p_rc_rsp->get_caps.status = AVRC_STS_INTERNAL_ERR;
+        } else {
+          p_rc_rsp->get_caps.status = AVRC_STS_NO_ERROR;
+          if (u8 == AVRC_CAP_COMPANY_ID) {
+            *p_ctype = AVRC_RSP_IMPL_STBL;
+            p_rc_rsp->get_caps.count = p_bta_av_cfg->num_co_ids;
+            memcpy(p_rc_rsp->get_caps.param.company_id,
+                   p_bta_av_cfg->p_meta_co_ids,
+                   (p_bta_av_cfg->num_co_ids << 2));
+          } else if (u8 == AVRC_CAP_EVENTS_SUPPORTED) {
+            *p_ctype = AVRC_RSP_IMPL_STBL;
+            p_rc_rsp->get_caps.count = p_bta_av_cfg->num_evt_ids;
+            memcpy(p_rc_rsp->get_caps.param.event_id,
+                   p_bta_av_cfg->p_meta_evt_ids, p_bta_av_cfg->num_evt_ids);
+          } else {
+            APPL_TRACE_DEBUG("Invalid capability ID: 0x%x", u8);
+            /* reject - unknown capability ID */
+            p_rc_rsp->get_caps.status = AVRC_STS_BAD_PARAM;
+          }
+        }
+        break;
+
+      case AVRC_PDU_REGISTER_NOTIFICATION:
+        /* make sure the event_id is implemented */
+        p_rc_rsp->rsp.status = bta_av_chk_notif_evt_id(p_vendor);
+        if (p_rc_rsp->rsp.status != BTA_AV_STS_NO_RSP) evt = 0;
+        break;
+    }
+  }
+#else
+  APPL_TRACE_DEBUG("AVRCP 1.3 Metadata not supporteed. Reject command.");
+  /* reject invalid message without reporting to app */
+  evt = 0;
+  p_rc_rsp->rsp.status = AVRC_STS_BAD_CMD;
+#endif
+
+  return evt;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rc_msg
+ *
+ * Description      Process an AVRCP message from the peer.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_rc_msg(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) {
+  tBTA_AV_EVT evt = 0;
+  tBTA_AV av;
+  BT_HDR* p_pkt = NULL;
+  tAVRC_MSG_VENDOR* p_vendor = &p_data->rc_msg.msg.vendor;
+  bool is_inquiry = ((p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_SPEC_INQ) ||
+                     p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_GEN_INQ);
+#if (AVRC_METADATA_INCLUDED == TRUE)
+  uint8_t ctype = 0;
+  tAVRC_RESPONSE rc_rsp;
+
+  rc_rsp.rsp.status = BTA_AV_STS_NO_RSP;
+#endif
+
+  if (NULL == p_data) {
+    APPL_TRACE_ERROR("Message from peer with no data in %s", __func__);
+    return;
+  }
+
+  APPL_TRACE_DEBUG("%s: opcode=%x, ctype=%x", __func__, p_data->rc_msg.opcode,
+                   p_data->rc_msg.msg.hdr.ctype);
+
+  if (p_data->rc_msg.opcode == AVRC_OP_PASS_THRU) {
+    /* if this is a pass thru command */
+    if ((p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_CTRL) ||
+        (p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_SPEC_INQ) ||
+        (p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_GEN_INQ)) {
+      /* check if operation is supported */
+      char avrcp_ct_support[PROPERTY_VALUE_MAX];
+      osi_property_get("bluetooth.pts.avrcp_ct.support", avrcp_ct_support,
+                       "false");
+      if (p_data->rc_msg.msg.pass.op_id == AVRC_ID_VENDOR) {
+        p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_NOT_IMPL;
+#if (AVRC_METADATA_INCLUDED == TRUE)
+        if (p_cb->features & BTA_AV_FEAT_METADATA)
+          p_data->rc_msg.msg.hdr.ctype = bta_av_group_navi_supported(
+              p_data->rc_msg.msg.pass.pass_len,
+              p_data->rc_msg.msg.pass.p_pass_data, is_inquiry);
+#endif
+      }
+#if (AVRC_CTRL_INCLUDED == TRUE)
+      else if (((p_data->rc_msg.msg.pass.op_id == AVRC_ID_VOL_UP) ||
+                (p_data->rc_msg.msg.pass.op_id == AVRC_ID_VOL_DOWN)) &&
+               !strcmp(avrcp_ct_support, "true")) {
+        p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_ACCEPT;
+      }
+#endif
+      else {
+        p_data->rc_msg.msg.hdr.ctype =
+            bta_av_op_supported(p_data->rc_msg.msg.pass.op_id, is_inquiry);
+      }
+
+      APPL_TRACE_DEBUG("ctype %d", p_data->rc_msg.msg.hdr.ctype)
+
+      /* send response */
+      if (p_data->rc_msg.msg.hdr.ctype != BTA_AV_RSP_INTERIM)
+        AVRC_PassRsp(p_data->rc_msg.handle, p_data->rc_msg.label,
+                     &p_data->rc_msg.msg.pass);
+
+      /* set up for callback if supported */
+      if (p_data->rc_msg.msg.hdr.ctype == BTA_AV_RSP_ACCEPT ||
+          p_data->rc_msg.msg.hdr.ctype == BTA_AV_RSP_INTERIM) {
+        evt = BTA_AV_REMOTE_CMD_EVT;
+        av.remote_cmd.rc_id = p_data->rc_msg.msg.pass.op_id;
+        av.remote_cmd.key_state = p_data->rc_msg.msg.pass.state;
+        av.remote_cmd.p_data = p_data->rc_msg.msg.pass.p_pass_data;
+        av.remote_cmd.len = p_data->rc_msg.msg.pass.pass_len;
+        memcpy(&av.remote_cmd.hdr, &p_data->rc_msg.msg.hdr, sizeof(tAVRC_HDR));
+        av.remote_cmd.label = p_data->rc_msg.label;
+      }
+    }
+    /* else if this is a pass thru response */
+    /* id response type is not impl, we have to release label */
+    else if (p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_NOT_IMPL) {
+      /* set up for callback */
+      evt = BTA_AV_REMOTE_RSP_EVT;
+      av.remote_rsp.rc_id = p_data->rc_msg.msg.pass.op_id;
+      av.remote_rsp.key_state = p_data->rc_msg.msg.pass.state;
+      av.remote_rsp.rsp_code = p_data->rc_msg.msg.hdr.ctype;
+      av.remote_rsp.label = p_data->rc_msg.label;
+
+      /* If this response is for vendor unique command  */
+      if ((p_data->rc_msg.msg.pass.op_id == AVRC_ID_VENDOR) &&
+          (p_data->rc_msg.msg.pass.pass_len > 0)) {
+        av.remote_rsp.p_data =
+            (uint8_t*)osi_malloc(p_data->rc_msg.msg.pass.pass_len);
+        APPL_TRACE_DEBUG("Vendor Unique data len = %d",
+                         p_data->rc_msg.msg.pass.pass_len);
+        memcpy(av.remote_rsp.p_data, p_data->rc_msg.msg.pass.p_pass_data,
+               p_data->rc_msg.msg.pass.pass_len);
+      }
+    }
+    /* must be a bad ctype -> reject*/
+    else {
+      p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_REJ;
+      AVRC_PassRsp(p_data->rc_msg.handle, p_data->rc_msg.label,
+                   &p_data->rc_msg.msg.pass);
+    }
+  }
+  /* else if this is a vendor specific command or response */
+  else if (p_data->rc_msg.opcode == AVRC_OP_VENDOR) {
+    /* set up for callback */
+    av.vendor_cmd.code = p_data->rc_msg.msg.hdr.ctype;
+    av.vendor_cmd.company_id = p_vendor->company_id;
+    av.vendor_cmd.label = p_data->rc_msg.label;
+    av.vendor_cmd.p_data = p_vendor->p_vendor_data;
+    av.vendor_cmd.len = p_vendor->vendor_len;
+
+    /* if configured to support vendor specific and it's a command */
+    if ((p_cb->features & BTA_AV_FEAT_VENDOR) &&
+        p_data->rc_msg.msg.hdr.ctype <= AVRC_CMD_GEN_INQ) {
+#if (AVRC_METADATA_INCLUDED == TRUE)
+      if ((p_cb->features & BTA_AV_FEAT_METADATA) &&
+          (p_vendor->company_id == AVRC_CO_METADATA)) {
+        av.meta_msg.p_msg = &p_data->rc_msg.msg;
+        rc_rsp.rsp.status = BTA_AV_STS_NO_RSP;
+        evt = bta_av_proc_meta_cmd(&rc_rsp, &p_data->rc_msg, &ctype);
+      } else
+#endif
+        evt = BTA_AV_VENDOR_CMD_EVT;
+    }
+    /* else if configured to support vendor specific and it's a response */
+    else if ((p_cb->features & BTA_AV_FEAT_VENDOR) &&
+             p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_NOT_IMPL) {
+#if (AVRC_METADATA_INCLUDED == TRUE)
+      if ((p_cb->features & BTA_AV_FEAT_METADATA) &&
+          (p_vendor->company_id == AVRC_CO_METADATA)) {
+        av.meta_msg.p_msg = &p_data->rc_msg.msg;
+        evt = BTA_AV_META_MSG_EVT;
+      } else
+#endif
+        evt = BTA_AV_VENDOR_RSP_EVT;
+
+    }
+    /* else if not configured to support vendor specific and it's a command */
+    else if (!(p_cb->features & BTA_AV_FEAT_VENDOR) &&
+             p_data->rc_msg.msg.hdr.ctype <= AVRC_CMD_GEN_INQ) {
+      if (p_data->rc_msg.msg.vendor.p_vendor_data[0] == AVRC_PDU_INVALID) {
+        /* reject it */
+        p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_REJ;
+        p_data->rc_msg.msg.vendor.p_vendor_data[4] = AVRC_STS_BAD_CMD;
+      } else
+        p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_NOT_IMPL;
+      AVRC_VendorRsp(p_data->rc_msg.handle, p_data->rc_msg.label,
+                     &p_data->rc_msg.msg.vendor);
+    }
+  } else if (p_data->rc_msg.opcode == AVRC_OP_BROWSE) {
+    /* set up for callback */
+    av.meta_msg.rc_handle = p_data->rc_msg.handle;
+    av.meta_msg.company_id = p_vendor->company_id;
+    av.meta_msg.code = p_data->rc_msg.msg.hdr.ctype;
+    av.meta_msg.label = p_data->rc_msg.label;
+    av.meta_msg.p_msg = &p_data->rc_msg.msg;
+    av.meta_msg.p_data = p_data->rc_msg.msg.browse.p_browse_data;
+    av.meta_msg.len = p_data->rc_msg.msg.browse.browse_len;
+    evt = BTA_AV_META_MSG_EVT;
+  }
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+  if (evt == 0 && rc_rsp.rsp.status != BTA_AV_STS_NO_RSP) {
+    if (!p_pkt) {
+      rc_rsp.rsp.opcode = p_data->rc_msg.opcode;
+      AVRC_BldResponse(0, &rc_rsp, &p_pkt);
+    }
+    if (p_pkt)
+      AVRC_MsgReq(p_data->rc_msg.handle, p_data->rc_msg.label, ctype, p_pkt);
+  }
+#endif
+
+  /* call callback */
+  if (evt != 0) {
+    av.remote_cmd.rc_handle = p_data->rc_msg.handle;
+    (*p_cb->p_cback)(evt, &av);
+    /* If browsing message, then free the browse message buffer */
+    bta_av_rc_free_browse_msg(p_cb, p_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rc_close
+ *
+ * Description      close the specified AVRC handle.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_rc_close(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) {
+  uint16_t handle = p_data->hdr.layer_specific;
+  tBTA_AV_SCB* p_scb;
+  tBTA_AV_RCB* p_rcb;
+
+  if (handle < BTA_AV_NUM_RCB) {
+    p_rcb = &p_cb->rcb[handle];
+
+    APPL_TRACE_DEBUG("%s handle: %d, status=0x%x", __func__, p_rcb->handle,
+                     p_rcb->status);
+    if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE) {
+      if (p_rcb->shdl) {
+        p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1];
+        if (p_scb) {
+          /* just in case the RC timer is active
+          if (bta_av_cb.features & BTA_AV_FEAT_RCCT &&
+             p_scb->chnl == BTA_AV_CHNL_AUDIO) */
+          alarm_cancel(p_scb->avrc_ct_timer);
+        }
+      }
+
+      AVRC_Close(p_rcb->handle);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rc_browse_close
+ *
+ * Description      Empty placeholder.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_rc_browse_close(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) {
+  APPL_TRACE_WARNING("%s empty placeholder does nothing!", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_get_shdl
+ *
+ * Returns          The index to p_scb[]
+ *
+ ******************************************************************************/
+static uint8_t bta_av_get_shdl(tBTA_AV_SCB* p_scb) {
+  int i;
+  uint8_t shdl = 0;
+  /* find the SCB & stop the timer */
+  for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+    if (p_scb == bta_av_cb.p_scb[i]) {
+      shdl = i + 1;
+      break;
+    }
+  }
+  return shdl;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_stream_chg
+ *
+ * Description      audio streaming status changed.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_stream_chg(tBTA_AV_SCB* p_scb, bool started) {
+  uint8_t started_msk;
+  int i;
+  uint8_t* p_streams;
+  bool no_streams = false;
+  tBTA_AV_SCB* p_scbi;
+
+  started_msk = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
+  APPL_TRACE_DEBUG("bta_av_stream_chg started:%d started_msk:x%x chnl:x%x",
+                   started, started_msk, p_scb->chnl);
+  if (BTA_AV_CHNL_AUDIO == p_scb->chnl)
+    p_streams = &bta_av_cb.audio_streams;
+  else
+    p_streams = &bta_av_cb.video_streams;
+
+  if (started) {
+    /* Let L2CAP know this channel is processed with high priority */
+    L2CA_SetAclPriority(p_scb->peer_addr, L2CAP_PRIORITY_HIGH);
+    (*p_streams) |= started_msk;
+  } else {
+    (*p_streams) &= ~started_msk;
+  }
+
+  if (!started) {
+    i = 0;
+    if (BTA_AV_CHNL_AUDIO == p_scb->chnl) {
+      if (bta_av_cb.video_streams == 0) no_streams = true;
+    } else {
+      no_streams = true;
+      if (bta_av_cb.audio_streams) {
+        for (; i < BTA_AV_NUM_STRS; i++) {
+          p_scbi = bta_av_cb.p_scb[i];
+          /* scb is used and started */
+          if (p_scbi && (bta_av_cb.audio_streams & BTA_AV_HNDL_TO_MSK(i)) &&
+              bdcmp(p_scbi->peer_addr, p_scb->peer_addr) == 0) {
+            no_streams = false;
+            break;
+          }
+        }
+      }
+    }
+
+    APPL_TRACE_DEBUG("no_streams:%d i:%d, audio_streams:x%x, video_streams:x%x",
+                     no_streams, i, bta_av_cb.audio_streams,
+                     bta_av_cb.video_streams);
+    if (no_streams) {
+      /* Let L2CAP know this channel is processed with low priority */
+      L2CA_SetAclPriority(p_scb->peer_addr, L2CAP_PRIORITY_NORMAL);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_conn_chg
+ *
+ * Description      connetion status changed.
+ *                  Open an AVRCP acceptor channel, if new conn.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_conn_chg(tBTA_AV_DATA* p_data) {
+  tBTA_AV_CB* p_cb = &bta_av_cb;
+  tBTA_AV_SCB* p_scb = NULL;
+  tBTA_AV_SCB* p_scbi;
+  uint8_t mask;
+  uint8_t conn_msk;
+  uint8_t old_msk;
+  int i;
+  int index = (p_data->hdr.layer_specific & BTA_AV_HNDL_MSK) - 1;
+  tBTA_AV_LCB* p_lcb;
+  tBTA_AV_LCB* p_lcb_rc;
+  tBTA_AV_RCB *p_rcb, *p_rcb2;
+  bool chk_restore = false;
+
+  /* Validate array index*/
+  if (index < BTA_AV_NUM_STRS) {
+    p_scb = p_cb->p_scb[index];
+  }
+  mask = BTA_AV_HNDL_TO_MSK(index);
+  p_lcb = bta_av_find_lcb(p_data->conn_chg.peer_addr, BTA_AV_LCB_FIND);
+  conn_msk = 1 << (index + 1);
+  if (p_data->conn_chg.is_up) {
+    /* set the conned mask for this channel */
+    if (p_scb) {
+      if (p_lcb) {
+        p_lcb->conn_msk |= conn_msk;
+        for (i = 0; i < BTA_AV_NUM_RCB; i++) {
+          if (bta_av_cb.rcb[i].lidx == p_lcb->lidx) {
+            bta_av_cb.rcb[i].shdl = index + 1;
+            APPL_TRACE_DEBUG(
+                "conn_chg up[%d]: %d, status=0x%x, shdl:%d, lidx:%d", i,
+                bta_av_cb.rcb[i].handle, bta_av_cb.rcb[i].status,
+                bta_av_cb.rcb[i].shdl, bta_av_cb.rcb[i].lidx);
+            break;
+          }
+        }
+      }
+      if (p_scb->chnl == BTA_AV_CHNL_AUDIO) {
+        old_msk = p_cb->conn_audio;
+        p_cb->conn_audio |= mask;
+      } else {
+        old_msk = p_cb->conn_video;
+        p_cb->conn_video |= mask;
+      }
+
+      if ((old_msk & mask) == 0) {
+        /* increase the audio open count, if not set yet */
+        bta_av_cb.audio_open_cnt++;
+      }
+
+      APPL_TRACE_DEBUG("rc_acp_handle:%d rc_acp_idx:%d", p_cb->rc_acp_handle,
+                       p_cb->rc_acp_idx);
+      /* check if the AVRCP ACP channel is already connected */
+      if (p_lcb && p_cb->rc_acp_handle != BTA_AV_RC_HANDLE_NONE &&
+          p_cb->rc_acp_idx) {
+        p_lcb_rc = &p_cb->lcb[BTA_AV_NUM_LINKS];
+        APPL_TRACE_DEBUG(
+            "rc_acp is connected && conn_chg on same addr "
+            "p_lcb_rc->conn_msk:x%x",
+            p_lcb_rc->conn_msk);
+        /* check if the RC is connected to the scb addr */
+        APPL_TRACE_DEBUG("p_lcb_rc->addr: %02x:%02x:%02x:%02x:%02x:%02x",
+                         p_lcb_rc->addr[0], p_lcb_rc->addr[1],
+                         p_lcb_rc->addr[2], p_lcb_rc->addr[3],
+                         p_lcb_rc->addr[4], p_lcb_rc->addr[5]);
+        APPL_TRACE_DEBUG(
+            "conn_chg.peer_addr: %02x:%02x:%02x:%02x:%02x:%02x",
+            p_data->conn_chg.peer_addr[0], p_data->conn_chg.peer_addr[1],
+            p_data->conn_chg.peer_addr[2], p_data->conn_chg.peer_addr[3],
+            p_data->conn_chg.peer_addr[4], p_data->conn_chg.peer_addr[5]);
+        if (p_lcb_rc->conn_msk &&
+            bdcmp(p_lcb_rc->addr, p_data->conn_chg.peer_addr) == 0) {
+          /* AVRCP is already connected.
+           * need to update the association betwen SCB and RCB */
+          p_lcb_rc->conn_msk = 0; /* indicate RC ONLY is not connected */
+          p_lcb_rc->lidx = 0;
+          p_scb->rc_handle = p_cb->rc_acp_handle;
+          p_rcb = &p_cb->rcb[p_cb->rc_acp_idx - 1];
+          p_rcb->shdl = bta_av_get_shdl(p_scb);
+          APPL_TRACE_DEBUG("update rc_acp shdl:%d/%d srch:%d", index + 1,
+                           p_rcb->shdl, p_scb->rc_handle);
+
+          p_rcb2 = bta_av_get_rcb_by_shdl(p_rcb->shdl);
+          if (p_rcb2) {
+            /* found the RCB that was created to associated with this SCB */
+            p_cb->rc_acp_handle = p_rcb2->handle;
+            p_cb->rc_acp_idx = (p_rcb2 - p_cb->rcb) + 1;
+            APPL_TRACE_DEBUG("new rc_acp_handle:%d, idx:%d",
+                             p_cb->rc_acp_handle, p_cb->rc_acp_idx);
+            p_rcb2->lidx = (BTA_AV_NUM_LINKS + 1);
+            APPL_TRACE_DEBUG("rc2 handle:%d lidx:%d/%d", p_rcb2->handle,
+                             p_rcb2->lidx, p_cb->lcb[p_rcb2->lidx - 1].lidx);
+          }
+          p_rcb->lidx = p_lcb->lidx;
+          APPL_TRACE_DEBUG("rc handle:%d lidx:%d/%d", p_rcb->handle,
+                           p_rcb->lidx, p_cb->lcb[p_rcb->lidx - 1].lidx);
+        }
+      }
+    }
+  } else {
+    if ((p_cb->conn_audio & mask) && bta_av_cb.audio_open_cnt) {
+      /* this channel is still marked as open. decrease the count */
+      bta_av_cb.audio_open_cnt--;
+    }
+
+    /* clear the conned mask for this channel */
+    p_cb->conn_audio &= ~mask;
+    p_cb->conn_video &= ~mask;
+    if (p_scb) {
+      /* the stream is closed.
+       * clear the peer address, so it would not mess up the AVRCP for the next
+       * round of operation */
+      bdcpy(p_scb->peer_addr, bd_addr_null);
+      if (p_scb->chnl == BTA_AV_CHNL_AUDIO) {
+        if (p_lcb) {
+          p_lcb->conn_msk &= ~conn_msk;
+        }
+        /* audio channel is down. make sure the INT channel is down */
+        /* just in case the RC timer is active
+        if (p_cb->features & BTA_AV_FEAT_RCCT) */
+        { alarm_cancel(p_scb->avrc_ct_timer); }
+        /* one audio channel goes down. check if we need to restore high
+         * priority */
+        chk_restore = true;
+      }
+    }
+
+    APPL_TRACE_DEBUG("bta_av_conn_chg shdl:%d", index + 1);
+    for (i = 0; i < BTA_AV_NUM_RCB; i++) {
+      APPL_TRACE_DEBUG("conn_chg dn[%d]: %d, status=0x%x, shdl:%d, lidx:%d", i,
+                       bta_av_cb.rcb[i].handle, bta_av_cb.rcb[i].status,
+                       bta_av_cb.rcb[i].shdl, bta_av_cb.rcb[i].lidx);
+      if (bta_av_cb.rcb[i].shdl == index + 1) {
+        bta_av_del_rc(&bta_av_cb.rcb[i]);
+        /* since the connection is already down and info was removed, clean
+         * reference */
+        bta_av_cb.rcb[i].shdl = 0;
+        break;
+      }
+    }
+
+    if (p_cb->conn_audio == 0 && p_cb->conn_video == 0) {
+      /* if both channels are not connected,
+       * close all RC channels */
+      bta_av_close_all_rc(p_cb);
+    }
+
+    /* if the AVRCP is no longer listening, create the listening channel */
+    if (bta_av_cb.rc_acp_handle == BTA_AV_RC_HANDLE_NONE &&
+        bta_av_cb.features & BTA_AV_FEAT_RCTG)
+      bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
+  }
+
+  APPL_TRACE_DEBUG(
+      "bta_av_conn_chg audio:%x video:%x up:%d conn_msk:0x%x chk_restore:%d "
+      "audio_open_cnt:%d",
+      p_cb->conn_audio, p_cb->conn_video, p_data->conn_chg.is_up, conn_msk,
+      chk_restore, p_cb->audio_open_cnt);
+
+  if (chk_restore) {
+    if (p_cb->audio_open_cnt == 1) {
+      /* one audio channel goes down and there's one audio channel remains open.
+       * restore the switch role in default link policy */
+      bta_sys_set_default_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH);
+      /* allow role switch, if this is the last connection */
+      bta_av_restore_switch();
+    }
+    if (p_cb->audio_open_cnt) {
+      /* adjust flush timeout settings to longer period */
+      for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+        p_scbi = bta_av_cb.p_scb[i];
+        if (p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started) {
+          /* may need to update the flush timeout of this already started stream
+           */
+          if (p_scbi->co_started != bta_av_cb.audio_open_cnt) {
+            p_scbi->co_started = bta_av_cb.audio_open_cnt;
+            L2CA_SetFlushTimeout(
+                p_scbi->peer_addr,
+                p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1]);
+          }
+        }
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_disable
+ *
+ * Description      disable AV.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_disable(tBTA_AV_CB* p_cb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  BT_HDR hdr;
+  uint16_t xx;
+
+  p_cb->disabling = true;
+
+  bta_av_close_all_rc(p_cb);
+
+  osi_free_and_reset((void**)&p_cb->p_disc_db);
+
+  /* disable audio/video - de-register all channels,
+   * expect BTA_AV_DEREG_COMP_EVT when deregister is complete */
+  for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) {
+    if (p_cb->p_scb[xx] != NULL) {
+      hdr.layer_specific = xx + 1;
+      bta_av_api_deregister((tBTA_AV_DATA*)&hdr);
+    }
+  }
+
+  alarm_free(p_cb->link_signalling_timer);
+  p_cb->link_signalling_timer = NULL;
+  alarm_free(p_cb->accept_signalling_timer);
+  p_cb->accept_signalling_timer = NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_api_disconnect
+ *
+ * Description      .
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_api_disconnect(tBTA_AV_DATA* p_data) {
+  AVDT_DisconnectReq(p_data->api_discnt.bd_addr, bta_av_conn_cback);
+  alarm_cancel(bta_av_cb.link_signalling_timer);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_sig_chg
+ *
+ * Description      process AVDT signal channel up/down.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_sig_chg(tBTA_AV_DATA* p_data) {
+  uint16_t event = p_data->str_msg.hdr.layer_specific;
+  tBTA_AV_CB* p_cb = &bta_av_cb;
+  uint32_t xx;
+  uint8_t mask;
+  tBTA_AV_LCB* p_lcb = NULL;
+
+  APPL_TRACE_DEBUG("bta_av_sig_chg event: %d", event);
+  if (event == AVDT_CONNECT_IND_EVT) {
+    p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FIND);
+    if (!p_lcb) {
+      /* if the address does not have an LCB yet, alloc one */
+      for (xx = 0; xx < BTA_AV_NUM_LINKS; xx++) {
+        mask = 1 << xx;
+        APPL_TRACE_DEBUG("conn_lcb: 0x%x", p_cb->conn_lcb);
+        tBTA_AV_SCB* p_scb = p_cb->p_scb[xx];
+        if (p_scb != NULL) {
+          uint8_t avdt_tsep_type = p_scb->sep_info[p_scb->sep_info_idx].tsep;
+          /* If the device is a A2DP source, disconnect the AVDT connection */
+          if ((avdt_tsep_type == AVDT_TSEP_SRC) &&
+              (p_data->hdr.offset == AVDT_ACP)) {
+            LOG_INFO(LOG_TAG,
+                     "%s disconnecting invalid A2DP source to A2DP source "
+                     "connection.",
+                     __func__);
+            AVDT_DisconnectReq(p_data->str_msg.bd_addr, NULL);
+            return;
+          }
+        }
+        /* look for a p_lcb with its p_scb registered */
+        if ((!(mask & p_cb->conn_lcb)) && (p_cb->p_scb[xx] != NULL)) {
+          p_lcb = &p_cb->lcb[xx];
+          p_lcb->lidx = xx + 1;
+          bdcpy(p_lcb->addr, p_data->str_msg.bd_addr);
+          p_lcb->conn_msk = 0; /* clear the connect mask */
+          /* start listening when the signal channel is open */
+          if (p_cb->features & BTA_AV_FEAT_RCTG) {
+            bta_av_rc_create(p_cb, AVCT_ACP, 0, p_lcb->lidx);
+          }
+          /* this entry is not used yet. */
+          p_cb->conn_lcb |= mask; /* mark it as used */
+          APPL_TRACE_DEBUG("start sig timer %d", p_data->hdr.offset);
+          if (p_data->hdr.offset == AVDT_ACP) {
+            APPL_TRACE_DEBUG("Incoming L2CAP acquired, set state as incoming",
+                             NULL);
+            bdcpy(p_cb->p_scb[xx]->peer_addr, p_data->str_msg.bd_addr);
+            p_cb->p_scb[xx]->use_rc =
+                true; /* allowing RC for incoming connection */
+            bta_av_ssm_execute(p_cb->p_scb[xx], BTA_AV_ACP_CONNECT_EVT, p_data);
+
+            /* The Pending Event should be sent as soon as the L2CAP signalling
+             * channel
+             * is set up, which is NOW. Earlier this was done only after
+             * BTA_AV_SIGNALLING_TIMEOUT_MS.
+             * The following function shall send the event and start the
+             * recurring timer
+             */
+            bta_av_signalling_timer(NULL);
+
+            APPL_TRACE_DEBUG("%s: Re-start timer for AVDTP service", __func__);
+            bta_sys_conn_open(BTA_ID_AV, p_cb->p_scb[xx]->app_id,
+                              p_cb->p_scb[xx]->peer_addr);
+            /* Possible collision : need to avoid outgoing processing while the
+             * timer is running */
+            p_cb->p_scb[xx]->coll_mask = BTA_AV_COLL_INC_TMR;
+            alarm_set_on_queue(p_cb->accept_signalling_timer,
+                               BTA_AV_ACCEPT_SIGNALLING_TIMEOUT_MS,
+                               bta_av_accept_signalling_timer_cback,
+                               UINT_TO_PTR(xx), btu_bta_alarm_queue);
+          }
+          break;
+        }
+      }
+
+      /* check if we found something */
+      if (xx == BTA_AV_NUM_LINKS) {
+        /* We do not have scb for this avdt connection.     */
+        /* Silently close the connection.                   */
+        APPL_TRACE_ERROR("av scb not available for avdt connection");
+        AVDT_DisconnectReq(p_data->str_msg.bd_addr, NULL);
+        return;
+      }
+    }
+  }
+#if (BTA_AR_INCLUDED == TRUE)
+  else if (event == BTA_AR_AVDT_CONN_EVT) {
+    alarm_cancel(bta_av_cb.link_signalling_timer);
+  }
+#endif
+  else {
+    /* disconnected. */
+    APPL_TRACE_DEBUG("%s: bta_av_cb.conn_lcb is %d", __func__,
+                     bta_av_cb.conn_lcb);
+
+    p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FREE);
+    if (p_lcb && (p_lcb->conn_msk || bta_av_cb.conn_lcb)) {
+      APPL_TRACE_DEBUG("conn_msk: 0x%x", p_lcb->conn_msk);
+      /* clean up ssm  */
+      for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) {
+        if ((p_cb->p_scb[xx]) &&
+            (bdcmp(p_cb->p_scb[xx]->peer_addr, p_data->str_msg.bd_addr) == 0)) {
+          APPL_TRACE_DEBUG("%s: Closing timer for AVDTP service", __func__);
+          bta_sys_conn_close(BTA_ID_AV, p_cb->p_scb[xx]->app_id,
+                             p_cb->p_scb[xx]->peer_addr);
+        }
+        mask = 1 << (xx + 1);
+        if (((mask & p_lcb->conn_msk) || bta_av_cb.conn_lcb) &&
+            (p_cb->p_scb[xx]) &&
+            (bdcmp(p_cb->p_scb[xx]->peer_addr, p_data->str_msg.bd_addr) == 0)) {
+          APPL_TRACE_DEBUG("%s: Sending AVDT_DISCONNECT_EVT", __func__);
+          bta_av_ssm_execute(p_cb->p_scb[xx], BTA_AV_AVDT_DISCONNECT_EVT, NULL);
+        }
+      }
+    }
+  }
+  APPL_TRACE_DEBUG("%s: sig_chg conn_lcb: 0x%x", __func__, p_cb->conn_lcb);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_signalling_timer
+ *
+ * Description      process the signal channel timer. This timer is started
+ *                  when the AVDTP signal channel is connected. If no profile
+ *                  is connected, the timer goes off every
+ *                  BTA_AV_SIGNALLING_TIMEOUT_MS.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_signalling_timer(UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  tBTA_AV_CB* p_cb = &bta_av_cb;
+  int xx;
+  uint8_t mask;
+  tBTA_AV_LCB* p_lcb = NULL;
+  tBTA_AV_PEND pend;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+  for (xx = 0; xx < BTA_AV_NUM_LINKS; xx++) {
+    mask = 1 << xx;
+    if (mask & p_cb->conn_lcb) {
+      /* this entry is used. check if it is connected */
+      p_lcb = &p_cb->lcb[xx];
+      if (!p_lcb->conn_msk) {
+        bta_sys_start_timer(p_cb->link_signalling_timer,
+                            BTA_AV_SIGNALLING_TIMEOUT_MS,
+                            BTA_AV_SIGNALLING_TIMER_EVT, 0);
+        bdcpy(pend.bd_addr, p_lcb->addr);
+        (*p_cb->p_cback)(BTA_AV_PENDING_EVT, (tBTA_AV*)&pend);
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_accept_signalling_timer_cback
+ *
+ * Description      Process the timeout when SRC is accepting connection
+ *                  and SNK did not start signalling.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_av_accept_signalling_timer_cback(void* data) {
+  uint32_t inx = PTR_TO_UINT(data);
+  tBTA_AV_CB* p_cb = &bta_av_cb;
+  tBTA_AV_SCB* p_scb = NULL;
+  if (inx < BTA_AV_NUM_STRS) {
+    p_scb = p_cb->p_scb[inx];
+  }
+  if (p_scb) {
+    APPL_TRACE_DEBUG("%s coll_mask = 0x%02X", __func__, p_scb->coll_mask);
+
+    if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR) {
+      p_scb->coll_mask &= ~BTA_AV_COLL_INC_TMR;
+
+      if (bta_av_is_scb_opening(p_scb)) {
+        APPL_TRACE_DEBUG("%s: stream state opening: SDP started = %d", __func__,
+                         p_scb->sdp_discovery_started);
+        if (p_scb->sdp_discovery_started) {
+          /* We are still doing SDP. Run the timer again. */
+          p_scb->coll_mask |= BTA_AV_COLL_INC_TMR;
+
+          alarm_set_on_queue(p_cb->accept_signalling_timer,
+                             BTA_AV_ACCEPT_SIGNALLING_TIMEOUT_MS,
+                             bta_av_accept_signalling_timer_cback,
+                             UINT_TO_PTR(inx), btu_bta_alarm_queue);
+        } else {
+          /* SNK did not start signalling, resume signalling process. */
+          bta_av_discover_req(p_scb, NULL);
+        }
+      } else if (bta_av_is_scb_incoming(p_scb)) {
+        /* Stay in incoming state if SNK does not start signalling */
+
+        APPL_TRACE_DEBUG("%s: stream state incoming", __func__);
+        /* API open was called right after SNK opened L2C connection. */
+        if (p_scb->coll_mask & BTA_AV_COLL_API_CALLED) {
+          p_scb->coll_mask &= ~BTA_AV_COLL_API_CALLED;
+
+          /* BTA_AV_API_OPEN_EVT */
+          tBTA_AV_API_OPEN* p_buf =
+              (tBTA_AV_API_OPEN*)osi_malloc(sizeof(tBTA_AV_API_OPEN));
+          memcpy(p_buf, &(p_scb->open_api), sizeof(tBTA_AV_API_OPEN));
+          bta_sys_sendmsg(p_buf);
+        }
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_check_peer_features
+ *
+ * Description      check supported features on the peer device from the SDP
+ *                  record and return the feature mask
+ *
+ * Returns          tBTA_AV_FEAT peer device feature mask
+ *
+ ******************************************************************************/
+tBTA_AV_FEAT bta_av_check_peer_features(uint16_t service_uuid) {
+  tBTA_AV_FEAT peer_features = 0;
+  tBTA_AV_CB* p_cb = &bta_av_cb;
+  tSDP_DISC_REC* p_rec = NULL;
+  tSDP_DISC_ATTR* p_attr;
+  uint16_t peer_rc_version = 0;
+  uint16_t categories = 0;
+
+  APPL_TRACE_DEBUG("bta_av_check_peer_features service_uuid:x%x", service_uuid);
+  /* loop through all records we found */
+  while (true) {
+    /* get next record; if none found, we're done */
+    if ((p_rec = SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, p_rec)) ==
+        NULL) {
+      break;
+    }
+
+    if ((SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_CLASS_ID_LIST)) !=
+        NULL) {
+      /* find peer features */
+      if (SDP_FindServiceInDb(p_cb->p_disc_db, UUID_SERVCLASS_AV_REMOTE_CONTROL,
+                              NULL)) {
+        peer_features |= BTA_AV_FEAT_RCCT;
+      }
+      if (SDP_FindServiceInDb(p_cb->p_disc_db,
+                              UUID_SERVCLASS_AV_REM_CTRL_TARGET, NULL)) {
+        peer_features |= BTA_AV_FEAT_RCTG;
+      }
+    }
+
+    if ((SDP_FindAttributeInRec(p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL) {
+      /* get profile version (if failure, version parameter is not updated) */
+      SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL,
+                                  &peer_rc_version);
+      APPL_TRACE_DEBUG("peer_rc_version 0x%x", peer_rc_version);
+
+      if (peer_rc_version >= AVRC_REV_1_3)
+        peer_features |= (BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_METADATA);
+
+      if (peer_rc_version >= AVRC_REV_1_4) {
+        peer_features |= (BTA_AV_FEAT_ADV_CTRL);
+        /* get supported categories */
+        if ((p_attr = SDP_FindAttributeInRec(
+                 p_rec, ATTR_ID_SUPPORTED_FEATURES)) != NULL) {
+          categories = p_attr->attr_value.v.u16;
+          if (categories & AVRC_SUPF_CT_BROWSE)
+            peer_features |= (BTA_AV_FEAT_BROWSE);
+        }
+      }
+    }
+  }
+  APPL_TRACE_DEBUG("peer_features:x%x", peer_features);
+  return peer_features;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_avk_check_peer_features
+ *
+ * Description      check supported features on the peer device from the SDP
+ *                  record and return the feature mask
+ *
+ * Returns          tBTA_AV_FEAT peer device feature mask
+ *
+ ******************************************************************************/
+tBTA_AV_FEAT bta_avk_check_peer_features(uint16_t service_uuid) {
+  tBTA_AV_FEAT peer_features = 0;
+  tBTA_AV_CB* p_cb = &bta_av_cb;
+
+  APPL_TRACE_DEBUG("%s service_uuid:x%x", __func__, service_uuid);
+
+  /* loop through all records we found */
+  tSDP_DISC_REC* p_rec =
+      SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, NULL);
+  while (p_rec) {
+    APPL_TRACE_DEBUG("%s found Service record for x%x", __func__, service_uuid);
+
+    if ((SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_CLASS_ID_LIST)) !=
+        NULL) {
+      /* find peer features */
+      if (SDP_FindServiceInDb(p_cb->p_disc_db, UUID_SERVCLASS_AV_REMOTE_CONTROL,
+                              NULL)) {
+        peer_features |= BTA_AV_FEAT_RCCT;
+      }
+      if (SDP_FindServiceInDb(p_cb->p_disc_db,
+                              UUID_SERVCLASS_AV_REM_CTRL_TARGET, NULL)) {
+        peer_features |= BTA_AV_FEAT_RCTG;
+      }
+    }
+
+    if ((SDP_FindAttributeInRec(p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL) {
+      /* get profile version (if failure, version parameter is not updated) */
+      uint16_t peer_rc_version = 0;
+      bool val = SDP_FindProfileVersionInRec(
+          p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_rc_version);
+      APPL_TRACE_DEBUG("%s peer_rc_version for TG 0x%x, profile_found %d",
+                       __func__, peer_rc_version, val);
+
+      if (peer_rc_version >= AVRC_REV_1_3)
+        peer_features |= (BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_METADATA);
+
+      /*
+       * Though Absolute Volume came after in 1.4 and above, but there are few
+       * devices
+       * in market which supports absolute Volume and they are still 1.3
+       * TO avoid IOT issuses with those devices, we check for 1.3 as minimum
+       * version
+       */
+      if (peer_rc_version >= AVRC_REV_1_3) {
+        /* get supported features */
+        tSDP_DISC_ATTR* p_attr =
+            SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES);
+        if (p_attr != NULL) {
+          uint16_t categories = p_attr->attr_value.v.u16;
+          if (categories & AVRC_SUPF_CT_CAT2)
+            peer_features |= (BTA_AV_FEAT_ADV_CTRL);
+          if (categories & AVRC_SUPF_CT_APP_SETTINGS)
+            peer_features |= (BTA_AV_FEAT_APP_SETTING);
+          if (categories & AVRC_SUPF_CT_BROWSE)
+            peer_features |= (BTA_AV_FEAT_BROWSE);
+        }
+      }
+    }
+    /* get next record; if none found, we're done */
+    p_rec = SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, p_rec);
+  }
+  APPL_TRACE_DEBUG("%s peer_features:x%x", __func__, peer_features);
+  return peer_features;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rc_disc_done
+ *
+ * Description      Handle AVRCP service discovery results.  If matching
+ *                  service found, open AVRCP connection.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_rc_disc_done(UNUSED_ATTR tBTA_AV_DATA* p_data) {
+  tBTA_AV_CB* p_cb = &bta_av_cb;
+  tBTA_AV_SCB* p_scb = NULL;
+  tBTA_AV_LCB* p_lcb;
+  tBTA_AV_RC_OPEN rc_open;
+  tBTA_AV_RC_FEAT rc_feat;
+  uint8_t rc_handle;
+  tBTA_AV_FEAT peer_features = 0; /* peer features mask */
+
+  APPL_TRACE_DEBUG("%s bta_av_rc_disc_done disc:x%x", __func__, p_cb->disc);
+  if (!p_cb->disc) {
+    return;
+  }
+
+  if ((p_cb->disc & BTA_AV_CHNL_MSK) == BTA_AV_CHNL_MSK) {
+    /* this is the rc handle/index to tBTA_AV_RCB */
+    rc_handle = p_cb->disc & (~BTA_AV_CHNL_MSK);
+  } else {
+    /* Validate array index*/
+    if (((p_cb->disc & BTA_AV_HNDL_MSK) - 1) < BTA_AV_NUM_STRS) {
+      p_scb = p_cb->p_scb[(p_cb->disc & BTA_AV_HNDL_MSK) - 1];
+    }
+    if (p_scb) {
+      rc_handle = p_scb->rc_handle;
+    } else {
+      p_cb->disc = 0;
+      return;
+    }
+  }
+
+  APPL_TRACE_DEBUG("%s rc_handle %d", __func__, rc_handle);
+#if (BTA_AV_SINK_INCLUDED == TRUE)
+  if (p_cb->sdp_a2dp_snk_handle) {
+    /* This is Sink + CT + TG(Abs Vol) */
+    peer_features =
+        bta_avk_check_peer_features(UUID_SERVCLASS_AV_REM_CTRL_TARGET);
+    APPL_TRACE_DEBUG("%s populating rem ctrl target features %d", __func__,
+                     peer_features);
+    if (BTA_AV_FEAT_ADV_CTRL &
+        bta_avk_check_peer_features(UUID_SERVCLASS_AV_REMOTE_CONTROL))
+      peer_features |= (BTA_AV_FEAT_ADV_CTRL | BTA_AV_FEAT_RCCT);
+  } else
+#endif
+      if (p_cb->sdp_a2dp_handle) {
+    /* check peer version and whether support CT and TG role */
+    peer_features =
+        bta_av_check_peer_features(UUID_SERVCLASS_AV_REMOTE_CONTROL);
+    if ((p_cb->features & BTA_AV_FEAT_ADV_CTRL) &&
+        ((peer_features & BTA_AV_FEAT_ADV_CTRL) == 0)) {
+      /* if we support advance control and peer does not, check their support on
+       * TG role
+       * some implementation uses 1.3 on CT ans 1.4 on TG */
+      peer_features |=
+          bta_av_check_peer_features(UUID_SERVCLASS_AV_REM_CTRL_TARGET);
+    }
+  }
+
+  p_cb->disc = 0;
+  osi_free_and_reset((void**)&p_cb->p_disc_db);
+
+  APPL_TRACE_DEBUG("peer_features 0x%x, features 0x%x", peer_features,
+                   p_cb->features);
+
+  /* if we have no rc connection */
+  if (rc_handle == BTA_AV_RC_HANDLE_NONE) {
+    if (p_scb) {
+      /* if peer remote control service matches ours and USE_RC is true */
+      if ((((p_cb->features & BTA_AV_FEAT_RCCT) &&
+            (peer_features & BTA_AV_FEAT_RCTG)) ||
+           ((p_cb->features & BTA_AV_FEAT_RCTG) &&
+            (peer_features & BTA_AV_FEAT_RCCT)))) {
+        p_lcb = bta_av_find_lcb(p_scb->peer_addr, BTA_AV_LCB_FIND);
+        if (p_lcb) {
+          rc_handle = bta_av_rc_create(p_cb, AVCT_INT,
+                                       (uint8_t)(p_scb->hdi + 1), p_lcb->lidx);
+          p_cb->rcb[rc_handle].peer_features = peer_features;
+        } else {
+          APPL_TRACE_ERROR("can not find LCB!!");
+        }
+      } else if (p_scb->use_rc) {
+        /* can not find AVRC on peer device. report failure */
+        p_scb->use_rc = false;
+        bdcpy(rc_open.peer_addr, p_scb->peer_addr);
+        rc_open.peer_features = 0;
+        rc_open.status = BTA_AV_FAIL_SDP;
+        (*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, (tBTA_AV*)&rc_open);
+      }
+    }
+  } else {
+    p_cb->rcb[rc_handle].peer_features = peer_features;
+    rc_feat.rc_handle = rc_handle;
+    rc_feat.peer_features = peer_features;
+    if (p_scb == NULL) {
+      /*
+       * In case scb is not created by the time we are done with SDP
+       * we still need to send RC feature event. So we need to get BD
+       * from Message
+       */
+      bdcpy(rc_feat.peer_addr, p_cb->lcb[p_cb->rcb[rc_handle].lidx].addr);
+    } else
+      bdcpy(rc_feat.peer_addr, p_scb->peer_addr);
+    (*p_cb->p_cback)(BTA_AV_RC_FEAT_EVT, (tBTA_AV*)&rc_feat);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rc_closed
+ *
+ * Description      Set AVRCP state to closed.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_rc_closed(tBTA_AV_DATA* p_data) {
+  tBTA_AV_CB* p_cb = &bta_av_cb;
+  tBTA_AV_RC_CLOSE rc_close;
+  tBTA_AV_RC_CONN_CHG* p_msg = (tBTA_AV_RC_CONN_CHG*)p_data;
+  tBTA_AV_RCB* p_rcb;
+  tBTA_AV_SCB* p_scb;
+  int i;
+  bool conn = false;
+  tBTA_AV_LCB* p_lcb;
+
+  rc_close.rc_handle = BTA_AV_RC_HANDLE_NONE;
+  p_scb = NULL;
+  APPL_TRACE_DEBUG("bta_av_rc_closed rc_handle:%d", p_msg->handle);
+  for (i = 0; i < BTA_AV_NUM_RCB; i++) {
+    p_rcb = &p_cb->rcb[i];
+    APPL_TRACE_DEBUG("bta_av_rc_closed rcb[%d] rc_handle:%d, status=0x%x", i,
+                     p_rcb->handle, p_rcb->status);
+    if (p_rcb->handle == p_msg->handle) {
+      rc_close.rc_handle = i;
+      p_rcb->status &= ~BTA_AV_RC_CONN_MASK;
+      p_rcb->peer_features = 0;
+      APPL_TRACE_DEBUG("       shdl:%d, lidx:%d", p_rcb->shdl, p_rcb->lidx);
+      if (p_rcb->shdl) {
+        if ((p_rcb->shdl - 1) < BTA_AV_NUM_STRS) {
+          p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1];
+        }
+        if (p_scb) {
+          bdcpy(rc_close.peer_addr, p_scb->peer_addr);
+          if (p_scb->rc_handle == p_rcb->handle)
+            p_scb->rc_handle = BTA_AV_RC_HANDLE_NONE;
+          APPL_TRACE_DEBUG("shdl:%d, srch:%d", p_rcb->shdl, p_scb->rc_handle);
+        }
+        p_rcb->shdl = 0;
+      } else if (p_rcb->lidx == (BTA_AV_NUM_LINKS + 1)) {
+        /* if the RCB uses the extra LCB, use the addr for event and clean it */
+        p_lcb = &p_cb->lcb[BTA_AV_NUM_LINKS];
+        bdcpy(rc_close.peer_addr, p_msg->peer_addr);
+        APPL_TRACE_DEBUG("rc_only closed bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+                         p_msg->peer_addr[0], p_msg->peer_addr[1],
+                         p_msg->peer_addr[2], p_msg->peer_addr[3],
+                         p_msg->peer_addr[4], p_msg->peer_addr[5]);
+        p_lcb->conn_msk = 0;
+        p_lcb->lidx = 0;
+      }
+      p_rcb->lidx = 0;
+
+      if ((p_rcb->status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT) {
+        /* AVCT CCB is deallocated */
+        p_rcb->handle = BTA_AV_RC_HANDLE_NONE;
+        p_rcb->status = 0;
+      } else {
+        /* AVCT CCB is still there. dealloc */
+        bta_av_del_rc(p_rcb);
+
+        /* if the AVRCP is no longer listening, create the listening channel */
+        if (bta_av_cb.rc_acp_handle == BTA_AV_RC_HANDLE_NONE &&
+            bta_av_cb.features & BTA_AV_FEAT_RCTG)
+          bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
+      }
+    } else if ((p_rcb->handle != BTA_AV_RC_HANDLE_NONE) &&
+               (p_rcb->status & BTA_AV_RC_CONN_MASK)) {
+      /* at least one channel is still connected */
+      conn = true;
+    }
+  }
+
+  if (!conn) {
+    /* no AVRC channels are connected, go back to INIT state */
+    bta_av_sm_execute(p_cb, BTA_AV_AVRC_NONE_EVT, NULL);
+  }
+
+  if (rc_close.rc_handle == BTA_AV_RC_HANDLE_NONE) {
+    rc_close.rc_handle = p_msg->handle;
+    bdcpy(rc_close.peer_addr, p_msg->peer_addr);
+  }
+  (*p_cb->p_cback)(BTA_AV_RC_CLOSE_EVT, (tBTA_AV*)&rc_close);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rc_browse_opened
+ *
+ * Description      AVRC browsing channel is opened
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_rc_browse_opened(tBTA_AV_DATA* p_data) {
+  tBTA_AV_CB* p_cb = &bta_av_cb;
+  tBTA_AV_RC_CONN_CHG* p_msg = (tBTA_AV_RC_CONN_CHG*)p_data;
+  tBTA_AV_RC_BROWSE_OPEN rc_browse_open;
+
+  APPL_TRACE_DEBUG(
+      "bta_av_rc_browse_opened bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+      p_msg->peer_addr[0], p_msg->peer_addr[1], p_msg->peer_addr[2],
+      p_msg->peer_addr[3], p_msg->peer_addr[4], p_msg->peer_addr[5]);
+  APPL_TRACE_DEBUG("bta_av_rc_browse_opened rc_handle:%d", p_msg->handle);
+
+  rc_browse_open.status = BTA_AV_SUCCESS;
+  rc_browse_open.rc_handle = p_msg->handle;
+  bdcpy(rc_browse_open.peer_addr, p_msg->peer_addr);
+
+  (*p_cb->p_cback)(BTA_AV_RC_BROWSE_OPEN_EVT, (tBTA_AV*)&rc_browse_open);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rc_browse_closed
+ *
+ * Description      AVRC browsing channel is closed
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_rc_browse_closed(tBTA_AV_DATA* p_data) {
+  tBTA_AV_CB* p_cb = &bta_av_cb;
+  tBTA_AV_RC_CONN_CHG* p_msg = (tBTA_AV_RC_CONN_CHG*)p_data;
+  tBTA_AV_RC_BROWSE_CLOSE rc_browse_close;
+
+  APPL_TRACE_DEBUG(
+      "bta_av_rc_browse_closed bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+      p_msg->peer_addr[0], p_msg->peer_addr[1], p_msg->peer_addr[2],
+      p_msg->peer_addr[3], p_msg->peer_addr[4], p_msg->peer_addr[5]);
+  APPL_TRACE_DEBUG("bta_av_rc_browse_closed rc_handle:%d", p_msg->handle);
+
+  rc_browse_close.rc_handle = p_msg->handle;
+  bdcpy(rc_browse_close.peer_addr, p_msg->peer_addr);
+
+  (*p_cb->p_cback)(BTA_AV_RC_BROWSE_CLOSE_EVT, (tBTA_AV*)&rc_browse_close);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rc_disc
+ *
+ * Description      start AVRC SDP discovery.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_rc_disc(uint8_t disc) {
+  tBTA_AV_CB* p_cb = &bta_av_cb;
+  tAVRC_SDP_DB_PARAMS db_params;
+  uint16_t attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST,
+                          ATTR_ID_BT_PROFILE_DESC_LIST,
+                          ATTR_ID_SUPPORTED_FEATURES};
+  uint8_t hdi;
+  tBTA_AV_SCB* p_scb;
+  uint8_t* p_addr = NULL;
+  uint8_t rc_handle;
+
+  APPL_TRACE_DEBUG("bta_av_rc_disc 0x%x, %d", disc, bta_av_cb.disc);
+  if ((bta_av_cb.disc != 0) || (disc == 0)) return;
+
+  if ((disc & BTA_AV_CHNL_MSK) == BTA_AV_CHNL_MSK) {
+    /* this is the rc handle/index to tBTA_AV_RCB */
+    rc_handle = disc & (~BTA_AV_CHNL_MSK);
+    if (p_cb->rcb[rc_handle].lidx) {
+      p_addr = p_cb->lcb[p_cb->rcb[rc_handle].lidx - 1].addr;
+    }
+  } else {
+    hdi = (disc & BTA_AV_HNDL_MSK) - 1;
+    p_scb = p_cb->p_scb[hdi];
+
+    if (p_scb) {
+      APPL_TRACE_DEBUG("rc_handle %d", p_scb->rc_handle);
+      p_addr = p_scb->peer_addr;
+    }
+  }
+
+  if (p_addr) {
+    /* allocate discovery database */
+    if (p_cb->p_disc_db == NULL)
+      p_cb->p_disc_db = (tSDP_DISCOVERY_DB*)osi_malloc(BTA_AV_DISC_BUF_SIZE);
+
+    /* set up parameters */
+    db_params.db_len = BTA_AV_DISC_BUF_SIZE;
+    db_params.num_attr = 3;
+    db_params.p_db = p_cb->p_disc_db;
+    db_params.p_attrs = attr_list;
+
+    /* searching for UUID_SERVCLASS_AV_REMOTE_CONTROL gets both TG and CT */
+    if (AVRC_FindService(UUID_SERVCLASS_AV_REMOTE_CONTROL, p_addr, &db_params,
+                         bta_av_avrc_sdp_cback) == AVRC_SUCCESS) {
+      p_cb->disc = disc;
+      APPL_TRACE_DEBUG("disc %d", p_cb->disc);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_dereg_comp
+ *
+ * Description      deregister complete. free the stream control block.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_dereg_comp(tBTA_AV_DATA* p_data) {
+  tBTA_AV_CB* p_cb = &bta_av_cb;
+  tBTA_AV_SCB* p_scb;
+  tBTA_UTL_COD cod;
+  uint8_t mask;
+  BT_HDR* p_buf;
+
+  /* find the stream control block */
+  p_scb = bta_av_hndl_to_scb(p_data->hdr.layer_specific);
+
+  if (p_scb) {
+    APPL_TRACE_DEBUG("deregistered %d(h%d)", p_scb->chnl, p_scb->hndl);
+    mask = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
+    if (p_scb->chnl == BTA_AV_CHNL_AUDIO) {
+      p_cb->reg_audio &= ~mask;
+      if ((p_cb->conn_audio & mask) && bta_av_cb.audio_open_cnt) {
+        /* this channel is still marked as open. decrease the count */
+        bta_av_cb.audio_open_cnt--;
+      }
+      p_cb->conn_audio &= ~mask;
+
+      if (p_scb->q_tag == BTA_AV_Q_TAG_STREAM && p_scb->a2dp_list) {
+        /* make sure no buffers are in a2dp_list */
+        while (!list_is_empty(p_scb->a2dp_list)) {
+          p_buf = (BT_HDR*)list_front(p_scb->a2dp_list);
+          list_remove(p_scb->a2dp_list, p_buf);
+          osi_free(p_buf);
+        }
+      }
+
+      /* remove the A2DP SDP record, if no more audio stream is left */
+      if (!p_cb->reg_audio) {
+#if (BTA_AR_INCLUDED == TRUE)
+        bta_ar_dereg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, BTA_ID_AV);
+#endif
+        if (p_cb->sdp_a2dp_handle) {
+          bta_av_del_sdp_rec(&p_cb->sdp_a2dp_handle);
+          p_cb->sdp_a2dp_handle = 0;
+          bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SOURCE);
+        }
+
+#if (BTA_AV_SINK_INCLUDED == TRUE)
+        if (p_cb->sdp_a2dp_snk_handle) {
+          bta_av_del_sdp_rec(&p_cb->sdp_a2dp_snk_handle);
+          p_cb->sdp_a2dp_snk_handle = 0;
+          bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SINK);
+        }
+#endif
+      }
+    } else {
+      p_cb->reg_video &= ~mask;
+      /* make sure that this channel is not connected */
+      p_cb->conn_video &= ~mask;
+      /* remove the VDP SDP record, (only one video stream at most) */
+      bta_av_del_sdp_rec(&p_cb->sdp_vdp_handle);
+      bta_sys_remove_uuid(UUID_SERVCLASS_VIDEO_SOURCE);
+    }
+
+    /* make sure that the timer is not active */
+    alarm_cancel(p_scb->avrc_ct_timer);
+    osi_free_and_reset((void**)&p_cb->p_scb[p_scb->hdi]);
+  }
+
+  APPL_TRACE_DEBUG("audio 0x%x, video: 0x%x, disable:%d", p_cb->reg_audio,
+                   p_cb->reg_video, p_cb->disabling);
+  /* if no stream control block is active */
+  if ((p_cb->reg_audio + p_cb->reg_video) == 0) {
+#if (BTA_AR_INCLUDED == TRUE)
+    /* deregister from AVDT */
+    bta_ar_dereg_avdt(BTA_ID_AV);
+
+    /* deregister from AVCT */
+    bta_ar_dereg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, BTA_ID_AV);
+    bta_ar_dereg_avct(BTA_ID_AV);
+#endif
+
+    if (p_cb->disabling) {
+      p_cb->disabling = false;
+      bta_av_cb.features = 0;
+    }
+
+    /* Clear the Capturing service class bit */
+    cod.service = BTM_COD_SERVICE_CAPTURING;
+    utl_set_device_class(&cod, BTA_UTL_CLR_COD_SERVICE_CLASS);
+  }
+}
diff --git a/bt/bta/av/bta_av_api.cc b/bt/bta/av/bta_av_api.cc
new file mode 100644
index 0000000..90a2dec
--- /dev/null
+++ b/bt/bta/av/bta_av_api.cc
@@ -0,0 +1,600 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2011-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 is the implementation of the API for the advanced audio/video (AV)
+ *  subsystem of BTA, Broadcom's Bluetooth application layer for mobile
+ *  phones.
+ *
+ ******************************************************************************/
+
+#include <assert.h>
+
+#include "bt_target.h"
+
+#include <string.h>
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_av_api.h"
+#include "bta_av_int.h"
+#include "bta_sys.h"
+
+#include "osi/include/allocator.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_av_reg = {bta_av_hdl_event, BTA_AvDisable};
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvEnable
+ *
+ * Description      Enable the advanced audio/video service. When the enable
+ *                  operation is complete the callback function will be
+ *                  called with a BTA_AV_ENABLE_EVT. This function must
+ *                  be called before other function in the AV API are
+ *                  called.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvEnable(tBTA_SEC sec_mask, tBTA_AV_FEAT features,
+                  tBTA_AV_CBACK* p_cback) {
+  tBTA_AV_API_ENABLE* p_buf =
+      (tBTA_AV_API_ENABLE*)osi_malloc(sizeof(tBTA_AV_API_ENABLE));
+
+  /* register with BTA system manager */
+  bta_sys_register(BTA_ID_AV, &bta_av_reg);
+
+  p_buf->hdr.event = BTA_AV_API_ENABLE_EVT;
+  p_buf->p_cback = p_cback;
+  p_buf->features = features;
+  p_buf->sec_mask = sec_mask;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvDisable
+ *
+ * Description      Disable the advanced audio/video service.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvDisable(void) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  bta_sys_deregister(BTA_ID_AV);
+  p_buf->event = BTA_AV_API_DISABLE_EVT;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvRegister
+ *
+ * Description      Register the audio or video service to stack. When the
+ *                  operation is complete the callback function will be
+ *                  called with a BTA_AV_REGISTER_EVT. This function must
+ *                  be called before AVDT stream is open.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvRegister(tBTA_AV_CHNL chnl, const char* p_service_name,
+                    uint8_t app_id, tBTA_AV_SINK_DATA_CBACK* p_sink_data_cback,
+                    uint16_t service_uuid) {
+  tBTA_AV_API_REG* p_buf =
+      (tBTA_AV_API_REG*)osi_malloc(sizeof(tBTA_AV_API_REG));
+
+  p_buf->hdr.layer_specific = chnl;
+  p_buf->hdr.event = BTA_AV_API_REGISTER_EVT;
+  if (p_service_name)
+    strlcpy(p_buf->p_service_name, p_service_name, BTA_SERVICE_NAME_LEN);
+  else
+    p_buf->p_service_name[0] = 0;
+  p_buf->app_id = app_id;
+  p_buf->p_app_sink_data_cback = p_sink_data_cback;
+  p_buf->service_uuid = service_uuid;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvDeregister
+ *
+ * Description      Deregister the audio or video service
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvDeregister(tBTA_AV_HNDL hndl) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->layer_specific = hndl;
+  p_buf->event = BTA_AV_API_DEREGISTER_EVT;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvOpen
+ *
+ * Description      Opens an advanced audio/video connection to a peer device.
+ *                  When connection is open callback function is called
+ *                  with a BTA_AV_OPEN_EVT.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvOpen(BD_ADDR bd_addr, tBTA_AV_HNDL handle, bool use_rc,
+                tBTA_SEC sec_mask, uint16_t uuid) {
+  tBTA_AV_API_OPEN* p_buf =
+      (tBTA_AV_API_OPEN*)osi_malloc(sizeof(tBTA_AV_API_OPEN));
+
+  p_buf->hdr.event = BTA_AV_API_OPEN_EVT;
+  p_buf->hdr.layer_specific = handle;
+  bdcpy(p_buf->bd_addr, bd_addr);
+  p_buf->use_rc = use_rc;
+  p_buf->sec_mask = sec_mask;
+  p_buf->switch_res = BTA_AV_RS_NONE;
+  p_buf->uuid = uuid;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvClose
+ *
+ * Description      Close the current streams.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvClose(tBTA_AV_HNDL handle) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = BTA_AV_API_CLOSE_EVT;
+  p_buf->layer_specific = handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvDisconnect
+ *
+ * Description      Close the connection to the address.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvDisconnect(BD_ADDR bd_addr) {
+  tBTA_AV_API_DISCNT* p_buf =
+      (tBTA_AV_API_DISCNT*)osi_malloc(sizeof(tBTA_AV_API_DISCNT));
+
+  p_buf->hdr.event = BTA_AV_API_DISCONNECT_EVT;
+  bdcpy(p_buf->bd_addr, bd_addr);
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvStart
+ *
+ * Description      Start audio/video stream data transfer.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvStart(void) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = BTA_AV_API_START_EVT;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvOffloadStart
+ *
+ * Description      Start a2dp audio offloading.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvOffloadStart(tBTA_AV_HNDL hndl) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = BTA_AV_API_OFFLOAD_START_EVT;
+  p_buf->layer_specific = hndl;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvOffloadStartRsp
+ *
+ * Description      Response from vendor lib for A2DP Offload Start request.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvOffloadStartRsp(tBTA_AV_HNDL hndl, tBTA_AV_STATUS status) {
+  tBTA_AV_API_STATUS_RSP* p_buf =
+      (tBTA_AV_API_STATUS_RSP*)osi_malloc(sizeof(tBTA_AV_API_STATUS_RSP));
+
+  p_buf->hdr.event = BTA_AV_API_OFFLOAD_START_RSP_EVT;
+  p_buf->hdr.layer_specific = hndl;
+  p_buf->status = status;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvStop
+ *
+ * Description      Stop audio/video stream data transfer.
+ *                  If suspend is true, this function sends AVDT suspend signal
+ *                  to the connected peer(s).
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvStop(bool suspend) {
+  tBTA_AV_API_STOP* p_buf =
+      (tBTA_AV_API_STOP*)osi_malloc(sizeof(tBTA_AV_API_STOP));
+
+  p_buf->hdr.event = BTA_AV_API_STOP_EVT;
+  p_buf->flush = true;
+  p_buf->suspend = suspend;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvReconfig
+ *
+ * Description      Reconfigure the audio/video stream.
+ *                  If suspend is true, this function tries the
+ *                  suspend/reconfigure procedure first.
+ *                  If suspend is false or when suspend/reconfigure fails,
+ *                  this function closes and re-opens the AVDT connection.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvReconfig(tBTA_AV_HNDL hndl, bool suspend, uint8_t sep_info_idx,
+                    uint8_t* p_codec_info, uint8_t num_protect,
+                    const uint8_t* p_protect_info) {
+  tBTA_AV_API_RCFG* p_buf =
+      (tBTA_AV_API_RCFG*)osi_malloc(sizeof(tBTA_AV_API_RCFG) + num_protect);
+
+  p_buf->hdr.layer_specific = hndl;
+  p_buf->hdr.event = BTA_AV_API_RECONFIG_EVT;
+  p_buf->num_protect = num_protect;
+  p_buf->suspend = suspend;
+  p_buf->sep_info_idx = sep_info_idx;
+  p_buf->p_protect_info = (uint8_t*)(p_buf + 1);
+  memcpy(p_buf->codec_info, p_codec_info, AVDT_CODEC_SIZE);
+  memcpy(p_buf->p_protect_info, p_protect_info, num_protect);
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvProtectReq
+ *
+ * Description      Send a content protection request.  This function can only
+ *                  be used if AV is enabled with feature BTA_AV_FEAT_PROTECT.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvProtectReq(tBTA_AV_HNDL hndl, uint8_t* p_data, uint16_t len) {
+  tBTA_AV_API_PROTECT_REQ* p_buf = (tBTA_AV_API_PROTECT_REQ*)osi_malloc(
+      sizeof(tBTA_AV_API_PROTECT_REQ) + len);
+
+  p_buf->hdr.layer_specific = hndl;
+  p_buf->hdr.event = BTA_AV_API_PROTECT_REQ_EVT;
+  p_buf->len = len;
+  if (p_data == NULL) {
+    p_buf->p_data = NULL;
+  } else {
+    p_buf->p_data = (uint8_t*)(p_buf + 1);
+    memcpy(p_buf->p_data, p_data, len);
+  }
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvProtectRsp
+ *
+ * Description      Send a content protection response.  This function must
+ *                  be called if a BTA_AV_PROTECT_REQ_EVT is received.
+ *                  This function can only be used if AV is enabled with
+ *                  feature BTA_AV_FEAT_PROTECT.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvProtectRsp(tBTA_AV_HNDL hndl, uint8_t error_code, uint8_t* p_data,
+                      uint16_t len) {
+  tBTA_AV_API_PROTECT_RSP* p_buf = (tBTA_AV_API_PROTECT_RSP*)osi_malloc(
+      sizeof(tBTA_AV_API_PROTECT_RSP) + len);
+
+  p_buf->hdr.layer_specific = hndl;
+  p_buf->hdr.event = BTA_AV_API_PROTECT_RSP_EVT;
+  p_buf->len = len;
+  p_buf->error_code = error_code;
+  if (p_data == NULL) {
+    p_buf->p_data = NULL;
+  } else {
+    p_buf->p_data = (uint8_t*)(p_buf + 1);
+    memcpy(p_buf->p_data, p_data, len);
+  }
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvRemoteCmd
+ *
+ * Description      Send a remote control command.  This function can only
+ *                  be used if AV is enabled with feature BTA_AV_FEAT_RCCT.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvRemoteCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_RC rc_id,
+                     tBTA_AV_STATE key_state) {
+  tBTA_AV_API_REMOTE_CMD* p_buf =
+      (tBTA_AV_API_REMOTE_CMD*)osi_malloc(sizeof(tBTA_AV_API_REMOTE_CMD));
+
+  p_buf->hdr.event = BTA_AV_API_REMOTE_CMD_EVT;
+  p_buf->hdr.layer_specific = rc_handle;
+  p_buf->msg.op_id = rc_id;
+  p_buf->msg.state = key_state;
+  p_buf->msg.p_pass_data = NULL;
+  p_buf->msg.pass_len = 0;
+  p_buf->label = label;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvRemoteVendorUniqueCmd
+ *
+ * Description      Send a remote control command with Vendor Unique rc_id.
+ *                  This function can only be used if AV is enabled with
+ *                  feature BTA_AV_FEAT_RCCT.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvRemoteVendorUniqueCmd(uint8_t rc_handle, uint8_t label,
+                                 tBTA_AV_STATE key_state, uint8_t* p_msg,
+                                 uint8_t buf_len) {
+  tBTA_AV_API_REMOTE_CMD* p_buf = (tBTA_AV_API_REMOTE_CMD*)osi_malloc(
+      sizeof(tBTA_AV_API_REMOTE_CMD) + buf_len);
+
+  p_buf->label = label;
+  p_buf->hdr.event = BTA_AV_API_REMOTE_CMD_EVT;
+  p_buf->hdr.layer_specific = rc_handle;
+  p_buf->msg.op_id = AVRC_ID_VENDOR;
+  p_buf->msg.state = key_state;
+  p_buf->msg.pass_len = buf_len;
+  if (p_msg == NULL) {
+    p_buf->msg.p_pass_data = NULL;
+  } else {
+    p_buf->msg.p_pass_data = (uint8_t*)(p_buf + 1);
+    memcpy(p_buf->msg.p_pass_data, p_msg, buf_len);
+  }
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvVendorCmd
+ *
+ * Description      Send a vendor dependent remote control command.  This
+ *                  function can only be used if AV is enabled with feature
+ *                  BTA_AV_FEAT_VENDOR.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvVendorCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE cmd_code,
+                     uint8_t* p_data, uint16_t len) {
+  tBTA_AV_API_VENDOR* p_buf =
+      (tBTA_AV_API_VENDOR*)osi_malloc(sizeof(tBTA_AV_API_VENDOR) + len);
+
+  p_buf->hdr.event = BTA_AV_API_VENDOR_CMD_EVT;
+  p_buf->hdr.layer_specific = rc_handle;
+  p_buf->msg.hdr.ctype = cmd_code;
+  p_buf->msg.hdr.subunit_type = AVRC_SUB_PANEL;
+  p_buf->msg.hdr.subunit_id = 0;
+  p_buf->msg.company_id = p_bta_av_cfg->company_id;
+  p_buf->label = label;
+  p_buf->msg.vendor_len = len;
+  if (p_data == NULL) {
+    p_buf->msg.p_vendor_data = NULL;
+  } else {
+    p_buf->msg.p_vendor_data = (uint8_t*)(p_buf + 1);
+    memcpy(p_buf->msg.p_vendor_data, p_data, len);
+  }
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvVendorRsp
+ *
+ * Description      Send a vendor dependent remote control response.
+ *                  This function must be called if a BTA_AV_VENDOR_CMD_EVT
+ *                  is received. This function can only be used if AV is
+ *                  enabled with feature BTA_AV_FEAT_VENDOR.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvVendorRsp(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code,
+                     uint8_t* p_data, uint16_t len, uint32_t company_id) {
+  tBTA_AV_API_VENDOR* p_buf =
+      (tBTA_AV_API_VENDOR*)osi_malloc(sizeof(tBTA_AV_API_VENDOR) + len);
+
+  p_buf->hdr.event = BTA_AV_API_VENDOR_RSP_EVT;
+  p_buf->hdr.layer_specific = rc_handle;
+  p_buf->msg.hdr.ctype = rsp_code;
+  p_buf->msg.hdr.subunit_type = AVRC_SUB_PANEL;
+  p_buf->msg.hdr.subunit_id = 0;
+  if (company_id)
+    p_buf->msg.company_id = company_id;
+  else
+    p_buf->msg.company_id = p_bta_av_cfg->company_id;
+  p_buf->label = label;
+  p_buf->msg.vendor_len = len;
+  if (p_data == NULL) {
+    p_buf->msg.p_vendor_data = NULL;
+  } else {
+    p_buf->msg.p_vendor_data = (uint8_t*)(p_buf + 1);
+    memcpy(p_buf->msg.p_vendor_data, p_data, len);
+  }
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvOpenRc
+ *
+ * Description      Open an AVRCP connection toward the device with the
+ *                  specified handle
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvOpenRc(tBTA_AV_HNDL handle) {
+  tBTA_AV_API_OPEN_RC* p_buf =
+      (tBTA_AV_API_OPEN_RC*)osi_malloc(sizeof(tBTA_AV_API_OPEN_RC));
+
+  p_buf->hdr.event = BTA_AV_API_RC_OPEN_EVT;
+  p_buf->hdr.layer_specific = handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvCloseRc
+ *
+ * Description      Close an AVRCP connection
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvCloseRc(uint8_t rc_handle) {
+  tBTA_AV_API_CLOSE_RC* p_buf =
+      (tBTA_AV_API_CLOSE_RC*)osi_malloc(sizeof(tBTA_AV_API_CLOSE_RC));
+
+  p_buf->hdr.event = BTA_AV_API_RC_CLOSE_EVT;
+  p_buf->hdr.layer_specific = rc_handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvMetaRsp
+ *
+ * Description      Send a Metadata/Advanced Control response. The message
+ *                  contained in p_pkt can be composed with AVRC utility
+ *                  functions.
+ *                  This function can only be used if AV is enabled with feature
+ *                  BTA_AV_FEAT_METADATA.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvMetaRsp(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code,
+                   BT_HDR* p_pkt) {
+  tBTA_AV_API_META_RSP* p_buf =
+      (tBTA_AV_API_META_RSP*)osi_malloc(sizeof(tBTA_AV_API_META_RSP));
+
+  p_buf->hdr.event = BTA_AV_API_META_RSP_EVT;
+  p_buf->hdr.layer_specific = rc_handle;
+  p_buf->rsp_code = rsp_code;
+  p_buf->p_pkt = p_pkt;
+  p_buf->is_rsp = true;
+  p_buf->label = label;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvMetaCmd
+ *
+ * Description      Send a Metadata/Advanced Control command. The message
+*contained
+ *                  in p_pkt can be composed with AVRC utility functions.
+ *                  This function can only be used if AV is enabled with feature
+ *                  BTA_AV_FEAT_METADATA.
+ *                  This message is sent only when the peer supports the TG
+*role.
+*8                  The only command makes sense right now is the absolute
+*volume command.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvMetaCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_CMD cmd_code,
+                   BT_HDR* p_pkt) {
+  tBTA_AV_API_META_RSP* p_buf =
+      (tBTA_AV_API_META_RSP*)osi_malloc(sizeof(tBTA_AV_API_META_RSP));
+
+  p_buf->hdr.event = BTA_AV_API_META_RSP_EVT;
+  p_buf->hdr.layer_specific = rc_handle;
+  p_buf->p_pkt = p_pkt;
+  p_buf->rsp_code = cmd_code;
+  p_buf->is_rsp = false;
+  p_buf->label = label;
+
+  bta_sys_sendmsg(p_buf);
+}
diff --git a/bt/bta/av/bta_av_cfg.cc b/bt/bta/av/bta_av_cfg.cc
new file mode 100644
index 0000000..5a3aabe
--- /dev/null
+++ b/bt/bta/av/bta_av_cfg.cc
@@ -0,0 +1,283 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2005-2016 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 compile-time configurable constants for advanced
+ *  audio/video
+ *
+ ******************************************************************************/
+
+#include <stddef.h>
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bta_api.h"
+#include "bta_av_int.h"
+
+#ifndef BTA_AV_RC_COMP_ID
+#define BTA_AV_RC_COMP_ID AVRC_CO_GOOGLE
+#endif
+
+#ifndef BTA_AV_RC_PASS_RSP_CODE
+#define BTA_AV_RC_PASS_RSP_CODE BTA_AV_RSP_NOT_IMPL
+#endif
+
+const uint32_t bta_av_meta_caps_co_ids[] = {AVRC_CO_METADATA, AVRC_CO_BROADCOM};
+
+/* AVRCP supported categories */
+#if (AVRC_CTRL_INCLUDED == TRUE)
+#define BTA_AV_RC_SUPF_CT (AVRC_SUPF_CT_CAT2)
+#define BTA_AVK_RC_SUPF_CT (AVRC_SUPF_CT_CAT1 | AVRC_SUPF_CT_BROWSE)
+#define BTA_AVK_RC_SUPF_TG (AVRC_SUPF_TG_CAT2)
+#endif
+
+/* AVRCP Controller and Targer default name */
+#ifndef BTA_AV_RC_CT_NAME
+#define BTA_AV_RC_CT_NAME "AVRC Controller"
+#endif
+
+#ifndef BTA_AV_RC_TG_NAME
+#define BTA_AV_RC_TG_NAME "AVRC Target"
+#endif
+
+/* Added to modify
+ *	1. flush timeout
+ *	2. Remove Group navigation support in SupportedFeatures
+ *	3. GetCapabilities supported event_ids list
+ *	4. GetCapabilities supported event_ids count
+*/
+/* Flushing partial avdtp packets can cause some headsets to disconnect the link
+   if receiving partial a2dp frames */
+const uint16_t bta_av_audio_flush_to[] = {
+    0, /* 1 stream */
+    0, /* 2 streams */
+    0, /* 3 streams */
+    0, /* 4 streams */
+    0  /* 5 streams */
+};     /* AVDTP audio transport channel flush timeout */
+
+/* Note: Android doesnt support AVRC_SUPF_TG_GROUP_NAVI  */
+/* Note: if AVRC_SUPF_TG_GROUP_NAVI is set, bta_av_cfg.avrc_group should be true
+ */
+#ifndef BTA_AV_RC_SUPF_TG
+#if (AVRC_METADATA_INCLUDED == TRUE)
+#define BTA_AV_RC_SUPF_TG                          \
+  (AVRC_SUPF_TG_CAT1 | AVRC_SUPF_TG_MULTI_PLAYER | \
+   AVRC_SUPF_TG_BROWSE) /* TODO: | AVRC_SUPF_TG_APP_SETTINGS) */
+#else
+#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1)
+#endif
+#endif
+
+/*
+ * If the number of event IDs is changed in this array, BTA_AV_ NUM_RC_EVT_IDS
+ * also needs to be changed.
+ */
+const uint8_t bta_av_meta_caps_evt_ids[] = {
+    AVRC_EVT_PLAY_STATUS_CHANGE, AVRC_EVT_TRACK_CHANGE,
+    AVRC_EVT_PLAY_POS_CHANGED,   AVRC_EVT_AVAL_PLAYERS_CHANGE,
+    AVRC_EVT_ADDR_PLAYER_CHANGE, AVRC_EVT_UIDS_CHANGE,
+    AVRC_EVT_NOW_PLAYING_CHANGE,
+    /* TODO: Add support for these events
+    AVRC_EVT_APP_SETTING_CHANGE,
+    */
+};
+#ifndef BTA_AV_NUM_RC_EVT_IDS
+#define BTA_AV_NUM_RC_EVT_IDS \
+  (sizeof(bta_av_meta_caps_evt_ids) / sizeof(bta_av_meta_caps_evt_ids[0]))
+#endif /* BTA_AV_NUM_RC_EVT_IDS */
+
+const uint8_t bta_avk_meta_caps_evt_ids[] = {
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+    AVRC_EVT_VOLUME_CHANGE,
+#endif
+};
+#ifndef BTA_AVK_NUM_RC_EVT_IDS
+#define BTA_AVK_NUM_RC_EVT_IDS \
+  (sizeof(bta_avk_meta_caps_evt_ids) / sizeof(bta_avk_meta_caps_evt_ids[0]))
+#endif /* BTA_AVK_NUM_RC_EVT_IDS */
+
+/* the MTU for the AVRCP browsing channel */
+#ifndef BTA_AV_MAX_RC_BR_MTU
+#define BTA_AV_MAX_RC_BR_MTU 1008
+#endif
+
+/* This configuration to be used when we are Src + TG + CT( only for abs vol) */
+const tBTA_AV_CFG bta_av_cfg = {
+    BTA_AV_RC_COMP_ID, /* AVRCP Company ID */
+#if (AVRC_METADATA_INCLUDED == TRUE)
+    512,                  /* AVRCP MTU at L2CAP for control channel */
+    BTA_AV_MAX_RC_BR_MTU, /* AVRCP MTU at L2CAP for browsing channel */
+#else
+    48,                   /* AVRCP MTU at L2CAP for control channel */
+    BTA_AV_MAX_RC_BR_MTU, /* AVRCP MTU at L2CAP for browsing channel */
+#endif
+    BTA_AV_RC_SUPF_CT,     /* AVRCP controller categories */
+    BTA_AV_RC_SUPF_TG,     /* AVRCP target categories */
+    672,                   /* AVDTP signaling channel MTU at L2CAP */
+    BTA_AV_MAX_A2DP_MTU,   /* AVDTP audio transport channel MTU at L2CAP
+                              */
+    bta_av_audio_flush_to, /* AVDTP audio transport channel flush
+                              timeout */
+    6,                     /* AVDTP audio channel max data queue size */
+    BTA_AV_MAX_VDP_MTU,    /* AVDTP video transport channel MTU at L2CAP */
+    600,                   /* AVDTP video transport channel flush timeout */
+    false, /* true, to accept AVRC 1.3 group nevigation command */
+    2,     /* company id count in p_meta_co_ids */
+    BTA_AV_NUM_RC_EVT_IDS,    /* event id count in p_meta_evt_ids */
+    BTA_AV_RC_PASS_RSP_CODE,  /* the default response code for pass
+                                 through commands */
+    bta_av_meta_caps_co_ids,  /* the metadata Get Capabilities response
+                                 for company id */
+    bta_av_meta_caps_evt_ids, /* the the metadata Get Capabilities
+                                 response for event id */
+    NULL,                     /* the action function table for VDP stream */
+    NULL,                     /* action function to register VDP */
+    BTA_AV_RC_CT_NAME,        /* Default AVRCP controller name */
+    BTA_AV_RC_TG_NAME         /* Default AVRCP target name */
+};
+
+/* This configuration to be used when we are Sink + CT + TG( only for abs vol)
+ */
+const tBTA_AV_CFG bta_avk_cfg = {
+    AVRC_CO_METADATA, /* AVRCP Company ID */
+#if (AVRC_METADATA_INCLUDED == TRUE)
+    512, /* AVRCP MTU at L2CAP for control channel */
+#else
+    48,                   /* AVRCP MTU at L2CAP for control channel */
+#endif
+    BTA_AV_MAX_RC_BR_MTU,  /* AVRCP MTU at L2CAP for browsing channel */
+    BTA_AVK_RC_SUPF_CT,    /* AVRCP controller categories */
+    BTA_AVK_RC_SUPF_TG,    /* AVRCP target categories */
+    672,                   /* AVDTP signaling channel MTU at L2CAP */
+    BTA_AV_MAX_A2DP_MTU,   /* AVDTP audio transport channel MTU at L2CAP
+                              */
+    bta_av_audio_flush_to, /* AVDTP audio transport channel flush
+                              timeout */
+    6,                     /* AVDTP audio channel max data queue size */
+    BTA_AV_MAX_VDP_MTU,    /* AVDTP video transport channel MTU at L2CAP */
+    600,                   /* AVDTP video transport channel flush timeout */
+    false, /* true, to accept AVRC 1.3 group nevigation command */
+    2,     /* company id count in p_meta_co_ids */
+    BTA_AVK_NUM_RC_EVT_IDS,    /* event id count in p_meta_evt_ids */
+    BTA_AV_RC_PASS_RSP_CODE,   /* the default response code for pass
+                                  through commands */
+    bta_av_meta_caps_co_ids,   /* the metadata Get Capabilities response
+                                  for company id */
+    bta_avk_meta_caps_evt_ids, /* the the metadata Get Capabilities
+                                  response for event id */
+    NULL,                      /* the action function table for VDP stream */
+    NULL,                      /* action function to register VDP */
+    {0},                       /* Default AVRCP controller name */
+    {0},                       /* Default AVRCP target name */
+};
+
+tBTA_AV_CFG* p_bta_av_cfg = NULL;
+
+const uint16_t bta_av_rc_id[] = {
+    0x0000, /* bit mask: 0=SELECT, 1=UP, 2=DOWN, 3=LEFT,
+                         4=RIGHT, 5=RIGHT_UP, 6=RIGHT_DOWN, 7=LEFT_UP,
+                         8=LEFT_DOWN, 9=ROOT_MENU, 10=SETUP_MENU, 11=CONT_MENU,
+                         12=FAV_MENU, 13=EXIT */
+
+    0, /* not used */
+
+    0x0000, /* bit mask: 0=0, 1=1, 2=2, 3=3,
+                         4=4, 5=5, 6=6, 7=7,
+                         8=8, 9=9, 10=DOT, 11=ENTER,
+                         12=CLEAR */
+
+    0x0000, /* bit mask: 0=CHAN_UP, 1=CHAN_DOWN, 2=PREV_CHAN, 3=SOUND_SEL,
+                         4=INPUT_SEL, 5=DISP_INFO, 6=HELP, 7=PAGE_UP,
+                         8=PAGE_DOWN */
+
+/* btui_app provides an example of how to leave the decision of rejecting a
+ command or not
+ * based on which media player is currently addressed (this is only applicable
+ for AVRCP 1.4 or later)
+ * If the decision is per player for a particular rc_id, the related bit is
+ clear (not set)
+ * bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE, 4=PLAY, 5=STOP,
+             6=PAUSE, 7=RECORD, 8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD,
+             12=BACKWARD */
+#if (BTA_AV_RC_PASS_RSP_CODE == BTA_AV_RSP_INTERIM)
+    0x0070, /* PLAY | STOP | PAUSE */
+#else       /* BTA_AV_RC_PASS_RSP_CODE != BTA_AV_RSP_INTERIM */
+#if (BTA_AVRCP_FF_RW_SUPPORT == TRUE)
+    0x1b7E, /* PLAY | STOP | PAUSE | FF | RW | VOL_UP | VOL_DOWN | MUTE | FW |
+               BACK */
+#else  /* BTA_AVRCP_FF_RW_SUPPORT == FALSE */
+    0x187E, /* PLAY | STOP | PAUSE | VOL_UP | VOL_DOWN | MUTE | FW | BACK */
+#endif /* BTA_AVRCP_FF_RW_SUPPORT */
+#endif /* BTA_AV_RC_PASS_RSP_CODE */
+
+    0x0000, /* bit mask: 0=ANGLE, 1=SUBPICT */
+
+    0, /* not used */
+
+    0x0000 /* bit mask: 0=not used, 1=F1, 2=F2, 3=F3,
+                        4=F4, 5=F5 */
+};
+
+#if (BTA_AV_RC_PASS_RSP_CODE == BTA_AV_RSP_INTERIM)
+const uint16_t bta_av_rc_id_ac[] = {
+    0x0000, /* bit mask: 0=SELECT, 1=UP, 2=DOWN, 3=LEFT,
+                         4=RIGHT, 5=RIGHT_UP, 6=RIGHT_DOWN,
+               7=LEFT_UP,
+                         8=LEFT_DOWN, 9=ROOT_MENU, 10=SETUP_MENU,
+               11=CONT_MENU,
+                         12=FAV_MENU, 13=EXIT */
+
+    0, /* not used */
+
+    0x0000, /* bit mask: 0=0, 1=1, 2=2, 3=3,
+                         4=4, 5=5, 6=6, 7=7,
+                         8=8, 9=9, 10=DOT, 11=ENTER,
+                         12=CLEAR */
+
+    0x0000, /* bit mask: 0=CHAN_UP, 1=CHAN_DOWN, 2=PREV_CHAN,
+               3=SOUND_SEL,
+                         4=INPUT_SEL, 5=DISP_INFO, 6=HELP,
+               7=PAGE_UP,
+                         8=PAGE_DOWN */
+
+    /* btui_app provides an example of how to leave the decision of
+     * rejecting a command or not
+     * based on which media player is currently addressed (this is
+     * only applicable for AVRCP 1.4 or later)
+     * If the decision is per player for a particular rc_id, the
+     * related bit is set */
+    0x1800, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE,
+                         4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD,
+                         8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD,
+                         12=BACKWARD */
+
+    0x0000, /* bit mask: 0=ANGLE, 1=SUBPICT */
+
+    0, /* not used */
+
+    0x0000 /* bit mask: 0=not used, 1=F1, 2=F2, 3=F3,
+                        4=F4, 5=F5 */
+};
+uint16_t* p_bta_av_rc_id_ac = (uint16_t*)bta_av_rc_id_ac;
+#else
+uint16_t* p_bta_av_rc_id_ac = NULL;
+#endif
+
+uint16_t* p_bta_av_rc_id = (uint16_t*)bta_av_rc_id;
diff --git a/bt/bta/av/bta_av_ci.cc b/bt/bta/av/bta_av_ci.cc
new file mode 100644
index 0000000..a215046
--- /dev/null
+++ b/bt/bta/av/bta_av_ci.cc
@@ -0,0 +1,89 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2005-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 is the implementation file for advanced audio/video call-in
+ *  functions.
+ *
+ ******************************************************************************/
+
+#include "bta_av_ci.h"
+#include "bta_api.h"
+#include "bta_av_int.h"
+#include "bta_sys.h"
+
+#include <string.h>
+
+/*******************************************************************************
+ *
+ * Function         bta_av_ci_src_data_ready
+ *
+ * Description      This function sends an event to the AV indicating that
+ *                  the phone has audio stream data ready to send and AV
+ *                  should call bta_av_co_audio_src_data_path().
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_ci_src_data_ready(tBTA_AV_CHNL chnl) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->layer_specific = chnl;
+  p_buf->event = BTA_AV_CI_SRC_DATA_READY_EVT;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_ci_setconfig
+ *
+ * Description      This function must be called in response to function
+ *                  bta_av_co_audio_setconfig().
+ *                  Parameter err_code is set to an AVDTP status value;
+ *                  AVDT_SUCCESS if the codec configuration is ok,
+ *                  otherwise error.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_ci_setconfig(tBTA_AV_HNDL hndl, uint8_t err_code, uint8_t category,
+                         uint8_t num_seid, uint8_t* p_seid, bool recfg_needed,
+                         uint8_t avdt_handle) {
+  tBTA_AV_CI_SETCONFIG* p_buf =
+      (tBTA_AV_CI_SETCONFIG*)osi_malloc(sizeof(tBTA_AV_CI_SETCONFIG));
+
+  p_buf->hdr.layer_specific = hndl;
+  p_buf->hdr.event = (err_code == A2DP_SUCCESS) ? BTA_AV_CI_SETCONFIG_OK_EVT
+                                                : BTA_AV_CI_SETCONFIG_FAIL_EVT;
+  p_buf->err_code = err_code;
+  p_buf->category = category;
+  p_buf->recfg_needed = recfg_needed;
+  p_buf->num_seid = num_seid;
+  p_buf->avdt_handle = avdt_handle;
+  if (p_seid && num_seid) {
+    p_buf->p_seid = (uint8_t*)(p_buf + 1);
+    memcpy(p_buf->p_seid, p_seid, num_seid);
+  } else {
+    p_buf->p_seid = NULL;
+    p_buf->num_seid = 0;
+  }
+
+  bta_sys_sendmsg(p_buf);
+}
diff --git a/bt/bta/av/bta_av_int.h b/bt/bta/av/bta_av_int.h
new file mode 100644
index 0000000..4d4a592
--- /dev/null
+++ b/bt/bta/av/bta_av_int.h
@@ -0,0 +1,703 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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 is the private interface file for the BTA advanced audio/video.
+ *
+ ******************************************************************************/
+#ifndef BTA_AV_INT_H
+#define BTA_AV_INT_H
+
+#include "avdt_api.h"
+#include "bta_api.h"
+#include "bta_av_api.h"
+#include "bta_av_co.h"
+#include "bta_sys.h"
+#include "osi/include/list.h"
+#include "stack/include/a2dp_api.h"
+
+#define BTA_AV_DEBUG TRUE
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+enum {
+  /* these events are handled by the AV main state machine */
+  BTA_AV_API_DISABLE_EVT = BTA_SYS_EVT_START(BTA_ID_AV),
+  BTA_AV_API_REMOTE_CMD_EVT,
+  BTA_AV_API_VENDOR_CMD_EVT,
+  BTA_AV_API_VENDOR_RSP_EVT,
+  BTA_AV_API_META_RSP_EVT,
+  BTA_AV_API_RC_CLOSE_EVT,
+  BTA_AV_AVRC_OPEN_EVT,
+  BTA_AV_AVRC_MSG_EVT,
+  BTA_AV_AVRC_NONE_EVT,
+
+  /* these events are handled by the AV stream state machine */
+  BTA_AV_API_OPEN_EVT,
+  BTA_AV_API_CLOSE_EVT,
+  BTA_AV_AP_START_EVT, /* the following 2 events must be in the same order as
+                          the *API_*EVT */
+  BTA_AV_AP_STOP_EVT,
+  BTA_AV_API_RECONFIG_EVT,
+  BTA_AV_API_PROTECT_REQ_EVT,
+  BTA_AV_API_PROTECT_RSP_EVT,
+  BTA_AV_API_RC_OPEN_EVT,
+  BTA_AV_SRC_DATA_READY_EVT,
+  BTA_AV_CI_SETCONFIG_OK_EVT,
+  BTA_AV_CI_SETCONFIG_FAIL_EVT,
+  BTA_AV_SDP_DISC_OK_EVT,
+  BTA_AV_SDP_DISC_FAIL_EVT,
+  BTA_AV_STR_DISC_OK_EVT,
+  BTA_AV_STR_DISC_FAIL_EVT,
+  BTA_AV_STR_GETCAP_OK_EVT,
+  BTA_AV_STR_GETCAP_FAIL_EVT,
+  BTA_AV_STR_OPEN_OK_EVT,
+  BTA_AV_STR_OPEN_FAIL_EVT,
+  BTA_AV_STR_START_OK_EVT,
+  BTA_AV_STR_START_FAIL_EVT,
+  BTA_AV_STR_CLOSE_EVT,
+  BTA_AV_STR_CONFIG_IND_EVT,
+  BTA_AV_STR_SECURITY_IND_EVT,
+  BTA_AV_STR_SECURITY_CFM_EVT,
+  BTA_AV_STR_WRITE_CFM_EVT,
+  BTA_AV_STR_SUSPEND_CFM_EVT,
+  BTA_AV_STR_RECONFIG_CFM_EVT,
+  BTA_AV_AVRC_TIMER_EVT,
+  BTA_AV_AVDT_CONNECT_EVT,
+  BTA_AV_AVDT_DISCONNECT_EVT,
+  BTA_AV_ROLE_CHANGE_EVT,
+  BTA_AV_AVDT_DELAY_RPT_EVT,
+  BTA_AV_ACP_CONNECT_EVT,
+  BTA_AV_API_OFFLOAD_START_EVT,
+  BTA_AV_API_OFFLOAD_START_RSP_EVT,
+
+  /* these events are handled outside of the state machine */
+  BTA_AV_API_ENABLE_EVT,
+  BTA_AV_API_REGISTER_EVT,
+  BTA_AV_API_DEREGISTER_EVT,
+  BTA_AV_API_DISCONNECT_EVT,
+  BTA_AV_CI_SRC_DATA_READY_EVT,
+  BTA_AV_SIG_CHG_EVT,
+  BTA_AV_SIGNALLING_TIMER_EVT,
+  BTA_AV_SDP_AVRC_DISC_EVT,
+  BTA_AV_AVRC_CLOSE_EVT,
+  BTA_AV_AVRC_BROWSE_OPEN_EVT,
+  BTA_AV_AVRC_BROWSE_CLOSE_EVT,
+  BTA_AV_CONN_CHG_EVT,
+  BTA_AV_DEREG_COMP_EVT,
+#if (AVDT_REPORTING == TRUE)
+  BTA_AV_AVDT_RPT_CONN_EVT,
+#endif
+  BTA_AV_API_START_EVT, /* the following 2 events must be in the same order as
+                           the *AP_*EVT */
+  BTA_AV_API_STOP_EVT
+};
+
+/* events for AV control block state machine */
+#define BTA_AV_FIRST_SM_EVT BTA_AV_API_DISABLE_EVT
+#define BTA_AV_LAST_SM_EVT BTA_AV_AVRC_NONE_EVT
+
+/* events for AV stream control block state machine */
+#define BTA_AV_FIRST_SSM_EVT BTA_AV_API_OPEN_EVT
+
+/* events that do not go through state machine */
+#define BTA_AV_FIRST_NSM_EVT BTA_AV_API_ENABLE_EVT
+#define BTA_AV_LAST_NSM_EVT BTA_AV_API_STOP_EVT
+
+/* API events passed to both SSMs (by bta_av_api_to_ssm) */
+#define BTA_AV_FIRST_A2S_API_EVT BTA_AV_API_START_EVT
+#define BTA_AV_FIRST_A2S_SSM_EVT BTA_AV_AP_START_EVT
+
+#define BTA_AV_LAST_EVT BTA_AV_API_STOP_EVT
+
+/* maximum number of SEPS in stream discovery results */
+#define BTA_AV_NUM_SEPS 32
+
+/* initialization value for AVRC handle */
+#define BTA_AV_RC_HANDLE_NONE 0xFF
+
+/* size of database for service discovery */
+#define BTA_AV_DISC_BUF_SIZE 1000
+
+/* maximum length of AVDTP security data */
+#define BTA_AV_SECURITY_MAX_LEN 400
+
+/* check number of buffers queued at L2CAP when this amount of buffers are
+ * queued to L2CAP */
+#define BTA_AV_QUEUE_DATA_CHK_NUM L2CAP_HIGH_PRI_MIN_XMIT_QUOTA
+
+/* the number of ACL links with AVDT */
+#define BTA_AV_NUM_LINKS AVDT_NUM_LINKS
+
+#define BTA_AV_BE_STREAM_TO_CO_ID(u32, p)                                 \
+  {                                                                       \
+    (u32) = (((uint32_t)(*((p) + 2))) + (((uint32_t)(*((p) + 1))) << 8) + \
+             (((uint32_t)(*(p))) << 16));                                 \
+    (p) += 3;                                                             \
+  }
+
+/*****************************************************************************
+ *  Data types
+ ****************************************************************************/
+
+/* function types for call-out functions */
+typedef bool (*tBTA_AV_CO_INIT)(tA2DP_CODEC_SEP_INDEX codec_sep_index,
+                                tAVDT_CFG* p_cfg);
+typedef void (*tBTA_AV_CO_DISC_RES)(tBTA_AV_HNDL hndl, uint8_t num_seps,
+                                    uint8_t num_snk, uint8_t num_src,
+                                    BD_ADDR addr, uint16_t uuid_local);
+typedef tA2DP_STATUS (*tBTA_AV_CO_GETCFG)(tBTA_AV_HNDL hndl,
+                                          uint8_t* p_codec_info,
+                                          uint8_t* p_sep_info_idx, uint8_t seid,
+                                          uint8_t* p_num_protect,
+                                          uint8_t* p_protect_info);
+typedef void (*tBTA_AV_CO_SETCFG)(tBTA_AV_HNDL hndl,
+                                  const uint8_t* p_codec_info, uint8_t seid,
+                                  BD_ADDR addr, uint8_t num_protect,
+                                  uint8_t* p_protect_info, uint8_t t_local_sep,
+                                  uint8_t avdt_handle);
+typedef void (*tBTA_AV_CO_OPEN)(tBTA_AV_HNDL hndl, uint8_t* p_codec_info,
+                                uint16_t mtu);
+typedef void (*tBTA_AV_CO_CLOSE)(tBTA_AV_HNDL hndl, uint16_t mtu);
+typedef void (*tBTA_AV_CO_START)(tBTA_AV_HNDL hndl, uint8_t* p_codec_info,
+                                 bool* p_no_rtp_hdr);
+typedef void (*tBTA_AV_CO_STOP)(tBTA_AV_HNDL hndl);
+typedef void* (*tBTA_AV_CO_DATAPATH)(const uint8_t* p_codec_info,
+                                     uint32_t* p_timestamp);
+typedef void (*tBTA_AV_CO_DELAY)(tBTA_AV_HNDL hndl, uint16_t delay);
+
+/* the call-out functions for one stream */
+typedef struct {
+  tBTA_AV_CO_INIT init;
+  tBTA_AV_CO_DISC_RES disc_res;
+  tBTA_AV_CO_GETCFG getcfg;
+  tBTA_AV_CO_SETCFG setcfg;
+  tBTA_AV_CO_OPEN open;
+  tBTA_AV_CO_CLOSE close;
+  tBTA_AV_CO_START start;
+  tBTA_AV_CO_STOP stop;
+  tBTA_AV_CO_DATAPATH data;
+  tBTA_AV_CO_DELAY delay;
+} tBTA_AV_CO_FUNCTS;
+
+/* data type for BTA_AV_API_ENABLE_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_AV_CBACK* p_cback;
+  tBTA_AV_FEAT features;
+  tBTA_SEC sec_mask;
+} tBTA_AV_API_ENABLE;
+
+/* data type for BTA_AV_API_REGISTER_EVT */
+typedef struct {
+  BT_HDR hdr;
+  char p_service_name[BTA_SERVICE_NAME_LEN + 1];
+  uint8_t app_id;
+  tBTA_AV_SINK_DATA_CBACK* p_app_sink_data_cback;
+  uint16_t service_uuid;
+} tBTA_AV_API_REG;
+
+enum {
+  BTA_AV_RS_NONE, /* straight API call */
+  BTA_AV_RS_OK,   /* the role switch result - successful */
+  BTA_AV_RS_FAIL, /* the role switch result - failed */
+  BTA_AV_RS_DONE  /* the role switch is done - continue */
+};
+typedef uint8_t tBTA_AV_RS_RES;
+/* data type for BTA_AV_API_OPEN_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  bool use_rc;
+  tBTA_SEC sec_mask;
+  tBTA_AV_RS_RES switch_res;
+  uint16_t uuid; /* uuid of initiator */
+} tBTA_AV_API_OPEN;
+
+/* data type for BTA_AV_API_STOP_EVT */
+typedef struct {
+  BT_HDR hdr;
+  bool suspend;
+  bool flush;
+} tBTA_AV_API_STOP;
+
+/* data type for BTA_AV_API_DISCONNECT_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+} tBTA_AV_API_DISCNT;
+
+/* data type for BTA_AV_API_PROTECT_REQ_EVT */
+typedef struct {
+  BT_HDR hdr;
+  uint8_t* p_data;
+  uint16_t len;
+} tBTA_AV_API_PROTECT_REQ;
+
+/* data type for BTA_AV_API_PROTECT_RSP_EVT */
+typedef struct {
+  BT_HDR hdr;
+  uint8_t* p_data;
+  uint16_t len;
+  uint8_t error_code;
+} tBTA_AV_API_PROTECT_RSP;
+
+/* data type for BTA_AV_API_REMOTE_CMD_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tAVRC_MSG_PASS msg;
+  uint8_t label;
+} tBTA_AV_API_REMOTE_CMD;
+
+/* data type for BTA_AV_API_VENDOR_CMD_EVT and RSP */
+typedef struct {
+  BT_HDR hdr;
+  tAVRC_MSG_VENDOR msg;
+  uint8_t label;
+} tBTA_AV_API_VENDOR;
+
+/* data type for BTA_AV_API_RC_OPEN_EVT */
+typedef struct { BT_HDR hdr; } tBTA_AV_API_OPEN_RC;
+
+/* data type for BTA_AV_API_RC_CLOSE_EVT */
+typedef struct { BT_HDR hdr; } tBTA_AV_API_CLOSE_RC;
+
+/* data type for BTA_AV_API_META_RSP_EVT */
+typedef struct {
+  BT_HDR hdr;
+  bool is_rsp;
+  uint8_t label;
+  tBTA_AV_CODE rsp_code;
+  BT_HDR* p_pkt;
+} tBTA_AV_API_META_RSP;
+
+/* data type for BTA_AV_API_RECONFIG_EVT */
+typedef struct {
+  BT_HDR hdr;
+  uint8_t codec_info[AVDT_CODEC_SIZE]; /* codec configuration */
+  uint8_t* p_protect_info;
+  uint8_t num_protect;
+  bool suspend;
+  uint8_t sep_info_idx;
+} tBTA_AV_API_RCFG;
+
+/* data type for BTA_AV_CI_SETCONFIG_OK_EVT and BTA_AV_CI_SETCONFIG_FAIL_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_AV_HNDL hndl;
+  uint8_t err_code;
+  uint8_t category;
+  uint8_t num_seid;
+  uint8_t* p_seid;
+  bool recfg_needed;
+  uint8_t avdt_handle; /* local sep type for which this stream will be set up */
+} tBTA_AV_CI_SETCONFIG;
+
+/* data type for all stream events from AVDTP */
+typedef struct {
+  BT_HDR hdr;
+  tAVDT_CFG cfg;   /* configuration/capabilities parameters */
+  tAVDT_CTRL msg;  /* AVDTP callback message parameters */
+  BD_ADDR bd_addr; /* bd address */
+  uint8_t handle;
+  uint8_t avdt_event;
+  bool initiator; /* true, if local device initiates the SUSPEND */
+} tBTA_AV_STR_MSG;
+
+/* data type for BTA_AV_AVRC_MSG_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tAVRC_MSG msg;
+  uint8_t handle;
+  uint8_t label;
+  uint8_t opcode;
+} tBTA_AV_RC_MSG;
+
+/* data type for BTA_AV_AVRC_OPEN_EVT, BTA_AV_AVRC_CLOSE_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR peer_addr;
+  uint8_t handle;
+} tBTA_AV_RC_CONN_CHG;
+
+/* data type for BTA_AV_CONN_CHG_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR peer_addr;
+  bool is_up;
+} tBTA_AV_CONN_CHG;
+
+/* data type for BTA_AV_ROLE_CHANGE_EVT */
+typedef struct {
+  BT_HDR hdr;
+  uint8_t new_role;
+  uint8_t hci_status;
+} tBTA_AV_ROLE_RES;
+
+/* data type for BTA_AV_SDP_DISC_OK_EVT */
+typedef struct {
+  BT_HDR hdr;
+  uint16_t avdt_version; /* AVDTP protocol version */
+} tBTA_AV_SDP_RES;
+
+/* data type for BTA_AV_API_OFFLOAD_RSP_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_AV_STATUS status;
+} tBTA_AV_API_STATUS_RSP;
+
+/* type for SEP control block */
+typedef struct {
+  uint8_t av_handle;                   /* AVDTP handle */
+  uint8_t tsep;                        /* SEP type of local SEP */
+  uint8_t codec_info[AVDT_CODEC_SIZE]; /* Codec info */
+  tBTA_AV_SINK_DATA_CBACK*
+      p_app_sink_data_cback; /* Sink application callback for media packets */
+} tBTA_AV_SEP;
+
+/* initiator/acceptor role for adaption */
+#define BTA_AV_ROLE_AD_INT 0x00 /* initiator */
+#define BTA_AV_ROLE_AD_ACP 0x01 /* acceptor */
+
+/* initiator/acceptor signaling roles */
+#define BTA_AV_ROLE_START_ACP 0x00
+#define BTA_AV_ROLE_START_INT 0x10 /* do not change this value */
+
+#define BTA_AV_ROLE_SUSPEND 0x20     /* suspending on start */
+#define BTA_AV_ROLE_SUSPEND_OPT 0x40 /* Suspend on Start option is set */
+
+/* union of all event datatypes */
+typedef union {
+  BT_HDR hdr;
+  tBTA_AV_API_ENABLE api_enable;
+  tBTA_AV_API_REG api_reg;
+  tBTA_AV_API_OPEN api_open;
+  tBTA_AV_API_STOP api_stop;
+  tBTA_AV_API_DISCNT api_discnt;
+  tBTA_AV_API_PROTECT_REQ api_protect_req;
+  tBTA_AV_API_PROTECT_RSP api_protect_rsp;
+  tBTA_AV_API_REMOTE_CMD api_remote_cmd;
+  tBTA_AV_API_VENDOR api_vendor;
+  tBTA_AV_API_RCFG api_reconfig;
+  tBTA_AV_CI_SETCONFIG ci_setconfig;
+  tBTA_AV_STR_MSG str_msg;
+  tBTA_AV_RC_MSG rc_msg;
+  tBTA_AV_RC_CONN_CHG rc_conn_chg;
+  tBTA_AV_CONN_CHG conn_chg;
+  tBTA_AV_ROLE_RES role_res;
+  tBTA_AV_SDP_RES sdp_res;
+  tBTA_AV_API_META_RSP api_meta_rsp;
+  tBTA_AV_API_STATUS_RSP api_status_rsp;
+} tBTA_AV_DATA;
+
+typedef union {
+  tBTA_AV_API_OPEN open; /* used only before open and role switch
+                            is needed on another AV channel */
+} tBTA_AV_Q_INFO;
+
+#define BTA_AV_Q_TAG_OPEN 0x01   /* after API_OPEN, before STR_OPENED */
+#define BTA_AV_Q_TAG_START 0x02  /* before start sending media packets */
+#define BTA_AV_Q_TAG_STREAM 0x03 /* during streaming */
+
+#define BTA_AV_WAIT_ACP_CAPS_ON 0x01 /* retriving the peer capabilities */
+#define BTA_AV_WAIT_ACP_CAPS_STARTED \
+  0x02 /* started while retriving peer capabilities */
+#define BTA_AV_WAIT_ROLE_SW_RES_OPEN \
+  0x04 /* waiting for role switch result after API_OPEN, before STR_OPENED */
+#define BTA_AV_WAIT_ROLE_SW_RES_START \
+  0x08 /* waiting for role switch result before streaming */
+#define BTA_AV_WAIT_ROLE_SW_STARTED \
+  0x10 /* started while waiting for role switch result */
+#define BTA_AV_WAIT_ROLE_SW_RETRY 0x20 /* set when retry on timeout */
+#define BTA_AV_WAIT_CHECK_RC \
+  0x40 /* set when the timer is used by role switch */
+#define BTA_AV_WAIT_ROLE_SW_FAILED 0x80 /* role switch failed */
+
+#define BTA_AV_WAIT_ROLE_SW_BITS                                  \
+  (BTA_AV_WAIT_ROLE_SW_RES_OPEN | BTA_AV_WAIT_ROLE_SW_RES_START | \
+   BTA_AV_WAIT_ROLE_SW_STARTED | BTA_AV_WAIT_ROLE_SW_RETRY)
+
+/* Bitmap for collision, coll_mask */
+#define BTA_AV_COLL_INC_TMR \
+  0x01 /* Timer is running for incoming L2C connection */
+#define BTA_AV_COLL_API_CALLED \
+  0x02 /* API open was called while incoming timer is running */
+
+/* type for AV stream control block */
+typedef struct {
+  const tBTA_AV_ACT* p_act_tbl; /* the action table for stream state machine */
+  const tBTA_AV_CO_FUNCTS* p_cos; /* the associated callout functions */
+  bool sdp_discovery_started; /* variable to determine whether SDP is started */
+  tBTA_AV_SEP seps[A2DP_CODEC_SEP_INDEX_MAX];
+  tAVDT_CFG* p_cap;  /* buffer used for get capabilities */
+  list_t* a2dp_list; /* used for audio channels only */
+  tBTA_AV_Q_INFO q_info;
+  tAVDT_SEP_INFO sep_info[BTA_AV_NUM_SEPS]; /* stream discovery results */
+  tAVDT_CFG cfg;                            /* local SEP configuration */
+  alarm_t* avrc_ct_timer;                   /* delay timer for AVRC CT */
+  BD_ADDR peer_addr;                        /* peer BD address */
+  uint16_t l2c_cid;                         /* L2CAP channel ID */
+  uint16_t stream_mtu;                      /* MTU of stream */
+  uint16_t avdt_version;      /* the avdt version of peer device */
+  tBTA_SEC sec_mask;          /* security mask */
+  uint8_t media_type;         /* Media type: AVDT_MEDIA_TYPE_* */
+  bool cong;                  /* true if AVDTP congested */
+  tBTA_AV_STATUS open_status; /* open failure status */
+  tBTA_AV_CHNL chnl;          /* the channel: audio/video */
+  tBTA_AV_HNDL hndl;          /* the handle: ((hdi + 1)|chnl) */
+  uint16_t cur_psc_mask;      /* Protocol service capabilities mask for current
+                                 connection */
+  uint8_t avdt_handle;        /* AVDTP handle */
+  uint8_t hdi;                /* the index to SCB[] */
+  uint8_t num_seps;           /* number of seps returned by stream discovery */
+  uint8_t num_disc_snks;      /* number of discovered snks */
+  uint8_t num_disc_srcs;      /* number of discovered srcs */
+  uint8_t sep_info_idx;       /* current index into sep_info */
+  uint8_t sep_idx;            /* current index into local seps[] */
+  uint8_t rcfg_idx;           /* reconfig requested index into sep_info */
+  uint8_t state;              /* state machine state */
+  uint8_t avdt_label;         /* AVDTP label */
+  uint8_t app_id;             /* application id */
+  uint8_t num_recfg;          /* number of reconfigure sent */
+  uint8_t role;
+  uint8_t l2c_bufs;  /* the number of buffers queued to L2CAP */
+  uint8_t rc_handle; /* connected AVRCP handle */
+  bool use_rc;       /* true if AVRCP is allowed */
+  bool started;      /* true if stream started */
+  uint8_t
+      co_started;    /* non-zero, if stream started from call-out perspective */
+  bool recfg_sup;    /* true if the first attempt to reconfigure the stream was
+                        successfull, else False if command fails */
+  bool suspend_sup;  /* true if Suspend stream is supported, else false if
+                        suspend command fails */
+  bool deregistring; /* true if deregistering */
+  bool sco_suspend;  /* true if SUSPEND is issued automatically for SCO */
+  uint8_t coll_mask; /* Mask to check incoming and outgoing collision */
+  tBTA_AV_API_OPEN open_api; /* Saved OPEN api message */
+  uint8_t wait;  /* set 0x1, when getting Caps as ACP, set 0x2, when started */
+  uint8_t q_tag; /* identify the associated q_info union member */
+  bool no_rtp_hdr;   /* true if add no RTP header*/
+  uint16_t uuid_int; /*intended UUID of Initiator to connect to */
+  bool offload_start_pending;
+  bool skip_sdp; /* Decides if sdp to be done prior to profile connection */
+} tBTA_AV_SCB;
+
+#define BTA_AV_RC_ROLE_MASK 0x10
+#define BTA_AV_RC_ROLE_INT 0x00
+#define BTA_AV_RC_ROLE_ACP 0x10
+
+#define BTA_AV_RC_CONN_MASK 0x20
+
+/* type for AV RCP control block */
+/* index to this control block is the rc handle */
+typedef struct {
+  uint8_t status;
+  uint8_t handle;
+  uint8_t shdl;               /* stream handle (hdi + 1) */
+  uint8_t lidx;               /* (index+1) to LCB */
+  tBTA_AV_FEAT peer_features; /* peer features mask */
+} tBTA_AV_RCB;
+#define BTA_AV_NUM_RCB (BTA_AV_NUM_STRS + 2)
+
+enum { BTA_AV_LCB_FREE, BTA_AV_LCB_FIND };
+
+/* type for AV ACL Link control block */
+typedef struct {
+  BD_ADDR addr;     /* peer BD address */
+  uint8_t conn_msk; /* handle mask of connected stream handle */
+  uint8_t lidx;     /* index + 1 */
+} tBTA_AV_LCB;
+
+/* type for stream state machine action functions */
+typedef void (*tBTA_AV_SACT)(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+
+/* type for AV control block */
+typedef struct {
+  tBTA_AV_SCB* p_scb[BTA_AV_NUM_STRS];   /* stream control block */
+  tSDP_DISCOVERY_DB* p_disc_db;          /* pointer to discovery database */
+  tBTA_AV_CBACK* p_cback;                /* application callback function */
+  tBTA_AV_RCB rcb[BTA_AV_NUM_RCB];       /* RCB control block */
+  tBTA_AV_LCB lcb[BTA_AV_NUM_LINKS + 1]; /* link control block */
+  alarm_t* link_signalling_timer;
+  alarm_t*
+      accept_signalling_timer;  /* timer to monitor signalling when accepting */
+  uint32_t sdp_a2dp_handle;     /* SDP record handle for audio src */
+  uint32_t sdp_a2dp_snk_handle; /* SDP record handle for audio snk */
+  uint32_t sdp_vdp_handle;      /* SDP record handle for video src */
+  tBTA_AV_FEAT features;        /* features mask */
+  tBTA_SEC sec_mask;            /* security mask */
+  tBTA_AV_HNDL handle;          /* the handle for SDP activity */
+  bool disabling;               /* true if api disabled called */
+  uint8_t
+      disc; /* (hdi+1) or (rc_handle|BTA_AV_CHNL_MSK) if p_disc_db is in use */
+  uint8_t state;          /* state machine state */
+  uint8_t conn_rc;        /* handle mask of connected RCP channels */
+  uint8_t conn_audio;     /* handle mask of connected audio channels */
+  uint8_t conn_video;     /* handle mask of connected video channels */
+  uint8_t conn_lcb;       /* index mask of used LCBs */
+  uint8_t audio_open_cnt; /* number of connected audio channels */
+  uint8_t reg_audio;      /* handle mask of registered audio channels */
+  uint8_t reg_video;      /* handle mask of registered video channels */
+  uint8_t rc_acp_handle;
+  uint8_t rc_acp_idx; /* (index + 1) to RCB */
+  uint8_t rs_idx;    /* (index + 1) to SCB for the one waiting for RS on open */
+  bool sco_occupied; /* true if SCO is being used or call is in progress */
+  uint8_t audio_streams; /* handle mask of streaming audio channels */
+  uint8_t video_streams; /* handle mask of streaming video channels */
+} tBTA_AV_CB;
+
+/*****************************************************************************
+ *  Global data
+ ****************************************************************************/
+
+/* control block declaration */
+extern tBTA_AV_CB bta_av_cb;
+
+/* config struct */
+extern tBTA_AV_CFG* p_bta_av_cfg;
+extern const tBTA_AV_CFG bta_avk_cfg;
+extern const tBTA_AV_CFG bta_av_cfg;
+
+/* rc id config struct */
+extern uint16_t* p_bta_av_rc_id;
+extern uint16_t* p_bta_av_rc_id_ac;
+
+extern const tBTA_AV_SACT bta_av_a2dp_action[];
+extern const tBTA_AV_CO_FUNCTS bta_av_a2dp_cos;
+extern tAVDT_CTRL_CBACK* const bta_av_dt_cback[];
+extern void bta_av_sink_data_cback(uint8_t handle, BT_HDR* p_pkt,
+                                   uint32_t time_stamp, uint8_t m_pt);
+
+/*****************************************************************************
+ *  Function prototypes
+ ****************************************************************************/
+/* utility functions */
+extern tBTA_AV_SCB* bta_av_hndl_to_scb(uint16_t handle);
+extern bool bta_av_chk_start(tBTA_AV_SCB* p_scb);
+extern void bta_av_restore_switch(void);
+extern uint16_t bta_av_chk_mtu(tBTA_AV_SCB* p_scb, uint16_t mtu);
+extern void bta_av_conn_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+                              tAVDT_CTRL* p_data);
+extern uint8_t bta_av_rc_create(tBTA_AV_CB* p_cb, uint8_t role, uint8_t shdl,
+                                uint8_t lidx);
+extern void bta_av_stream_chg(tBTA_AV_SCB* p_scb, bool started);
+extern bool bta_av_is_scb_opening(tBTA_AV_SCB* p_scb);
+extern bool bta_av_is_scb_incoming(tBTA_AV_SCB* p_scb);
+extern void bta_av_set_scb_sst_init(tBTA_AV_SCB* p_scb);
+extern bool bta_av_is_scb_init(tBTA_AV_SCB* p_scb);
+extern void bta_av_set_scb_sst_incoming(tBTA_AV_SCB* p_scb);
+extern tBTA_AV_LCB* bta_av_find_lcb(BD_ADDR addr, uint8_t op);
+
+/* main functions */
+extern void bta_av_api_deregister(tBTA_AV_DATA* p_data);
+extern void bta_av_dup_audio_buf(tBTA_AV_SCB* p_scb, BT_HDR* p_buf);
+extern void bta_av_sm_execute(tBTA_AV_CB* p_cb, uint16_t event,
+                              tBTA_AV_DATA* p_data);
+extern void bta_av_ssm_execute(tBTA_AV_SCB* p_scb, uint16_t event,
+                               tBTA_AV_DATA* p_data);
+extern bool bta_av_hdl_event(BT_HDR* p_msg);
+#if (BTA_AV_DEBUG == TRUE)
+extern const char* bta_av_evt_code(uint16_t evt_code);
+#endif
+extern bool bta_av_switch_if_needed(tBTA_AV_SCB* p_scb);
+extern bool bta_av_link_role_ok(tBTA_AV_SCB* p_scb, uint8_t bits);
+extern bool bta_av_is_rcfg_sst(tBTA_AV_SCB* p_scb);
+
+/* nsm action functions */
+extern void bta_av_api_disconnect(tBTA_AV_DATA* p_data);
+extern void bta_av_sig_chg(tBTA_AV_DATA* p_data);
+extern void bta_av_signalling_timer(tBTA_AV_DATA* p_data);
+extern void bta_av_rc_disc_done(tBTA_AV_DATA* p_data);
+extern void bta_av_rc_closed(tBTA_AV_DATA* p_data);
+extern void bta_av_rc_browse_opened(tBTA_AV_DATA* p_data);
+extern void bta_av_rc_browse_closed(tBTA_AV_DATA* p_data);
+extern void bta_av_rc_disc(uint8_t disc);
+extern void bta_av_conn_chg(tBTA_AV_DATA* p_data);
+extern void bta_av_dereg_comp(tBTA_AV_DATA* p_data);
+
+/* sm action functions */
+extern void bta_av_disable(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+extern void bta_av_rc_opened(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+extern void bta_av_rc_remote_cmd(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+extern void bta_av_rc_vendor_cmd(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+extern void bta_av_rc_vendor_rsp(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+extern void bta_av_rc_msg(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+extern void bta_av_rc_close(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+extern void bta_av_rc_meta_rsp(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+extern void bta_av_rc_free_rsp(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+extern void bta_av_rc_free_browse_msg(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+
+extern tBTA_AV_RCB* bta_av_get_rcb_by_shdl(uint8_t shdl);
+extern void bta_av_del_rc(tBTA_AV_RCB* p_rcb);
+
+/* ssm action functions */
+extern void bta_av_do_disc_a2dp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_cleanup(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_free_sdb(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_config_ind(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_disconnect_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_security_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_security_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_setconfig_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_str_opened(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_security_ind(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_security_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_do_close(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_connect_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_sdp_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_disc_results(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_disc_res_as_acp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_open_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_getcap_results(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_setconfig_rej(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_discover_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_conn_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_do_start(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_str_stopped(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_reconfig(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_data_path(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_start_ok(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_start_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_str_closed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_clr_cong(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_suspend_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_rcfg_str_ok(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_rcfg_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_rcfg_connect(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_rcfg_discntd(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_suspend_cont(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_rcfg_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_rcfg_open(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_security_rej(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_open_rc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_chk_2nd_start(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_save_caps(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_rej_conn(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_rej_conn(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_set_use_rc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_cco_close(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_switch_role(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_role_res(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_delay_co(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_open_at_inc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_offload_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_offload_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+
+#endif /* BTA_AV_INT_H */
diff --git a/bt/bta/av/bta_av_main.cc b/bt/bta/av/bta_av_main.cc
new file mode 100644
index 0000000..702e759
--- /dev/null
+++ b/bt/bta/av/bta_av_main.cc
@@ -0,0 +1,1332 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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 is the main implementation file for the BTA advanced audio/video.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bta_av"
+
+#include <assert.h>
+#include <string.h>
+
+#include "bt_target.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#include "bta_av_co.h"
+#include "bta_av_int.h"
+#include "btif/include/btif_av_co.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "utl.h"
+
+#if (BTA_AR_INCLUDED == TRUE)
+#include "bta_ar_api.h"
+#endif
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+
+#ifndef BTA_AV_RET_TOUT
+#define BTA_AV_RET_TOUT 4
+#endif
+
+#ifndef BTA_AV_SIG_TOUT
+#define BTA_AV_SIG_TOUT 4
+#endif
+
+#ifndef BTA_AV_IDLE_TOUT
+#define BTA_AV_IDLE_TOUT 10
+#endif
+
+/* the delay time in milliseconds to retry role switch */
+#ifndef BTA_AV_RS_TIME_VAL
+#define BTA_AV_RS_TIME_VAL 1000
+#endif
+
+/* state machine states */
+enum { BTA_AV_INIT_ST, BTA_AV_OPEN_ST };
+
+/* state machine action enumeration list */
+enum {
+  BTA_AV_DISABLE,
+  BTA_AV_RC_OPENED,
+  BTA_AV_RC_REMOTE_CMD,
+  BTA_AV_RC_VENDOR_CMD,
+  BTA_AV_RC_VENDOR_RSP,
+  BTA_AV_RC_FREE_RSP,
+  BTA_AV_RC_FREE_BROWSE_MSG,
+  BTA_AV_RC_META_RSP,
+  BTA_AV_RC_MSG,
+  BTA_AV_RC_CLOSE,
+  BTA_AV_RC_BROWSE_CLOSE,
+  BTA_AV_NUM_ACTIONS
+};
+
+#define BTA_AV_IGNORE BTA_AV_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tBTA_AV_ACTION)(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+
+/* action functions */
+const tBTA_AV_ACTION bta_av_action[] = {
+    bta_av_disable,
+    bta_av_rc_opened,
+    bta_av_rc_remote_cmd,
+    bta_av_rc_vendor_cmd,
+    bta_av_rc_vendor_rsp,
+    bta_av_rc_free_rsp,
+    bta_av_rc_free_browse_msg,
+    bta_av_rc_meta_rsp,
+    bta_av_rc_msg,
+    bta_av_rc_close,
+};
+
+/* state table information */
+#define BTA_AV_ACTION_COL 0 /* position of actions */
+#define BTA_AV_NEXT_STATE 1 /* position of next state */
+#define BTA_AV_NUM_COLS 2   /* number of columns in state tables */
+
+/* state table for init state */
+static const uint8_t bta_av_st_init[][BTA_AV_NUM_COLS] = {
+    /* Event                     Action 1                   Next state */
+    /* API_DISABLE_EVT */ {BTA_AV_DISABLE, BTA_AV_INIT_ST},
+    /* API_REMOTE_CMD_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST},
+    /* API_VENDOR_CMD_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST},
+    /* API_VENDOR_RSP_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST},
+    /* API_META_RSP_EVT */ {BTA_AV_RC_FREE_RSP, BTA_AV_INIT_ST},
+    /* API_RC_CLOSE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST},
+    /* AVRC_OPEN_EVT */ {BTA_AV_RC_OPENED, BTA_AV_OPEN_ST},
+    /* AVRC_MSG_EVT */ {BTA_AV_RC_FREE_BROWSE_MSG, BTA_AV_INIT_ST},
+    /* AVRC_NONE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST},
+};
+
+/* state table for open state */
+static const uint8_t bta_av_st_open[][BTA_AV_NUM_COLS] = {
+    /* Event                     Action 1                   Next state */
+    /* API_DISABLE_EVT */ {BTA_AV_DISABLE, BTA_AV_INIT_ST},
+    /* API_REMOTE_CMD_EVT */ {BTA_AV_RC_REMOTE_CMD, BTA_AV_OPEN_ST},
+    /* API_VENDOR_CMD_EVT */ {BTA_AV_RC_VENDOR_CMD, BTA_AV_OPEN_ST},
+    /* API_VENDOR_RSP_EVT */ {BTA_AV_RC_VENDOR_RSP, BTA_AV_OPEN_ST},
+    /* API_META_RSP_EVT */ {BTA_AV_RC_META_RSP, BTA_AV_OPEN_ST},
+    /* API_RC_CLOSE_EVT */ {BTA_AV_RC_CLOSE, BTA_AV_OPEN_ST},
+    /* AVRC_OPEN_EVT */ {BTA_AV_RC_OPENED, BTA_AV_OPEN_ST},
+    /* AVRC_MSG_EVT */ {BTA_AV_RC_MSG, BTA_AV_OPEN_ST},
+    /* AVRC_NONE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST},
+};
+
+/* type for state table */
+typedef const uint8_t (*tBTA_AV_ST_TBL)[BTA_AV_NUM_COLS];
+
+/* state table */
+static const tBTA_AV_ST_TBL bta_av_st_tbl[] = {bta_av_st_init, bta_av_st_open};
+
+typedef void (*tBTA_AV_NSM_ACT)(tBTA_AV_DATA* p_data);
+static void bta_av_api_enable(tBTA_AV_DATA* p_data);
+static void bta_av_api_register(tBTA_AV_DATA* p_data);
+static void bta_av_ci_data(tBTA_AV_DATA* p_data);
+#if (AVDT_REPORTING == TRUE)
+static void bta_av_rpc_conn(tBTA_AV_DATA* p_data);
+#endif
+static void bta_av_api_to_ssm(tBTA_AV_DATA* p_data);
+
+static void bta_av_sco_chg_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
+                                 uint8_t app_id, BD_ADDR peer_addr);
+static void bta_av_sys_rs_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
+                                uint8_t app_id, BD_ADDR peer_addr);
+
+/* action functions */
+const tBTA_AV_NSM_ACT bta_av_nsm_act[] = {
+    bta_av_api_enable,       /* BTA_AV_API_ENABLE_EVT */
+    bta_av_api_register,     /* BTA_AV_API_REGISTER_EVT */
+    bta_av_api_deregister,   /* BTA_AV_API_DEREGISTER_EVT */
+    bta_av_api_disconnect,   /* BTA_AV_API_DISCONNECT_EVT */
+    bta_av_ci_data,          /* BTA_AV_CI_SRC_DATA_READY_EVT */
+    bta_av_sig_chg,          /* BTA_AV_SIG_CHG_EVT */
+    bta_av_signalling_timer, /* BTA_AV_SIGNALLING_TIMER_EVT */
+    bta_av_rc_disc_done,     /* BTA_AV_SDP_AVRC_DISC_EVT */
+    bta_av_rc_closed,        /* BTA_AV_AVRC_CLOSE_EVT */
+    bta_av_rc_browse_opened, /* BTA_AV_AVRC_BROWSE_OPEN_EVT */
+    bta_av_rc_browse_closed, /* BTA_AV_AVRC_BROWSE_CLOSE_EVT */
+    bta_av_conn_chg,         /* BTA_AV_CONN_CHG_EVT */
+    bta_av_dereg_comp,       /* BTA_AV_DEREG_COMP_EVT */
+#if (AVDT_REPORTING == TRUE)
+    bta_av_rpc_conn, /* BTA_AV_AVDT_RPT_CONN_EVT */
+#endif
+    bta_av_api_to_ssm, /* BTA_AV_API_START_EVT */
+    bta_av_api_to_ssm, /* BTA_AV_API_STOP_EVT */
+};
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+
+/* AV control block */
+tBTA_AV_CB bta_av_cb;
+
+#if (BTA_AV_DEBUG == TRUE)
+static const char* bta_av_st_code(uint8_t state);
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_av_api_enable
+ *
+ * Description      Handle an API enable event.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_av_api_enable(tBTA_AV_DATA* p_data) {
+  /* initialize control block */
+  memset(&bta_av_cb, 0, sizeof(tBTA_AV_CB));
+
+  for (int i = 0; i < BTA_AV_NUM_RCB; i++)
+    bta_av_cb.rcb[i].handle = BTA_AV_RC_HANDLE_NONE;
+
+  bta_av_cb.rc_acp_handle = BTA_AV_RC_HANDLE_NONE;
+
+  /*
+   * TODO: The "disable" event handling is missing - there we need
+   * to alarm_free() the alarms below.
+   */
+  bta_av_cb.link_signalling_timer = alarm_new("bta_av.link_signalling_timer");
+  bta_av_cb.accept_signalling_timer =
+      alarm_new("bta_av.accept_signalling_timer");
+
+  /* store parameters */
+  bta_av_cb.p_cback = p_data->api_enable.p_cback;
+  bta_av_cb.features = p_data->api_enable.features;
+  bta_av_cb.sec_mask = p_data->api_enable.sec_mask;
+
+  tBTA_AV_ENABLE enable;
+  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);
+  }
+
+  /* call callback with enable event */
+  (*bta_av_cb.p_cback)(BTA_AV_ENABLE_EVT, (tBTA_AV*)&enable);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_addr_to_scb
+ *
+ * Description      find the stream control block by the peer addr
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static tBTA_AV_SCB* bta_av_addr_to_scb(BD_ADDR bd_addr) {
+  tBTA_AV_SCB* p_scb = NULL;
+  int xx;
+
+  for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) {
+    if (bta_av_cb.p_scb[xx]) {
+      if (!bdcmp(bd_addr, bta_av_cb.p_scb[xx]->peer_addr)) {
+        p_scb = bta_av_cb.p_scb[xx];
+        break;
+      }
+    }
+  }
+  return p_scb;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_hndl_to_scb
+ *
+ * Description      find the stream control block by the handle
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+tBTA_AV_SCB* bta_av_hndl_to_scb(uint16_t handle) {
+  tBTA_AV_HNDL hndl = (tBTA_AV_HNDL)handle;
+  tBTA_AV_SCB* p_scb = NULL;
+  uint8_t idx = (hndl & BTA_AV_HNDL_MSK);
+
+  if (idx && (idx <= BTA_AV_NUM_STRS)) {
+    p_scb = bta_av_cb.p_scb[idx - 1];
+  }
+  return p_scb;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_alloc_scb
+ *
+ * Description      allocate stream control block,
+ *                  register the service to stack
+ *                  create SDP record
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static tBTA_AV_SCB* bta_av_alloc_scb(tBTA_AV_CHNL chnl) {
+  tBTA_AV_SCB* p_ret = NULL;
+  int xx;
+  tBTA_AV_STATUS sts = BTA_AV_SUCCESS;
+
+  if (chnl == BTA_AV_CHNL_VIDEO) {
+    if (p_bta_av_cfg->p_act_tbl == NULL || p_bta_av_cfg->p_reg == NULL) {
+      APPL_TRACE_ERROR("Video streaming not supported");
+      sts = BTA_AV_FAIL;
+    } else {
+      /* allow only one Video channel */
+      if (bta_av_cb.reg_video) {
+        APPL_TRACE_ERROR("Already registered");
+        sts = BTA_AV_FAIL;
+      }
+    }
+  } else if (chnl != BTA_AV_CHNL_AUDIO) {
+    APPL_TRACE_ERROR("bad channel: %d", chnl);
+    sts = BTA_AV_FAIL;
+  }
+
+  if (sts == BTA_AV_SUCCESS) {
+    for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) {
+      if (bta_av_cb.p_scb[xx] == NULL) {
+        /* found an empty spot */
+        p_ret = (tBTA_AV_SCB*)osi_calloc(sizeof(tBTA_AV_SCB));
+        p_ret->rc_handle = BTA_AV_RC_HANDLE_NONE;
+        p_ret->chnl = chnl;
+        p_ret->hndl = (tBTA_AV_HNDL)((xx + 1) | chnl);
+        p_ret->hdi = xx;
+        p_ret->a2dp_list = list_new(NULL);
+        p_ret->avrc_ct_timer = alarm_new("bta_av.avrc_ct_timer");
+        bta_av_cb.p_scb[xx] = p_ret;
+        break;
+      }
+    }
+  }
+  return p_ret;
+}
+
+/*******************************************************************************
+ ******************************************************************************/
+void bta_av_conn_cback(UNUSED_ATTR uint8_t handle, BD_ADDR bd_addr,
+                       uint8_t event, tAVDT_CTRL* p_data) {
+  uint16_t evt = 0;
+  tBTA_AV_SCB* p_scb = NULL;
+
+#if (BTA_AR_INCLUDED == TRUE)
+  if (event == BTA_AR_AVDT_CONN_EVT || event == AVDT_CONNECT_IND_EVT ||
+      event == AVDT_DISCONNECT_IND_EVT)
+#else
+  if (event == AVDT_CONNECT_IND_EVT || event == AVDT_DISCONNECT_IND_EVT)
+#endif
+  {
+    evt = BTA_AV_SIG_CHG_EVT;
+    if (AVDT_DISCONNECT_IND_EVT == event) p_scb = bta_av_addr_to_scb(bd_addr);
+#if (BTA_AV_DEBUG == TRUE)
+    else if (AVDT_CONNECT_IND_EVT == event) {
+      APPL_TRACE_DEBUG("CONN_IND is ACP:%d", p_data->hdr.err_param);
+    }
+#endif
+
+    tBTA_AV_STR_MSG* p_msg =
+        (tBTA_AV_STR_MSG*)osi_malloc(sizeof(tBTA_AV_STR_MSG));
+    p_msg->hdr.event = evt;
+    p_msg->hdr.layer_specific = event;
+    p_msg->hdr.offset = p_data->hdr.err_param;
+    bdcpy(p_msg->bd_addr, bd_addr);
+#if (BTA_AV_DEBUG == TRUE)
+    if (p_scb) {
+      APPL_TRACE_DEBUG("scb hndl x%x, role x%x", p_scb->hndl, p_scb->role);
+    }
+#endif
+    APPL_TRACE_DEBUG("conn_cback bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+                     bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4],
+                     bd_addr[5]);
+    bta_sys_sendmsg(p_msg);
+  }
+}
+
+#if (AVDT_REPORTING == TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_av_a2dp_report_cback
+ *
+ * Description      A2DP report callback.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_av_a2dp_report_cback(UNUSED_ATTR uint8_t handle,
+                                     UNUSED_ATTR AVDT_REPORT_TYPE type,
+                                     UNUSED_ATTR tAVDT_REPORT_DATA* p_data) {
+  /* Do not need to handle report data for now.
+   * This empty function is here for conformance reasons. */
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_av_api_register
+ *
+ * Description      allocate stream control block,
+ *                  register the service to stack
+ *                  create SDP record
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_av_api_register(tBTA_AV_DATA* p_data) {
+  tBTA_AV_REGISTER registr;
+  tBTA_AV_SCB* p_scb; /* stream control block */
+  tAVDT_REG reg;
+  tAVDT_CS cs;
+  char* p_service_name;
+  tBTA_UTL_COD cod;
+
+  memset(&cs, 0, sizeof(tAVDT_CS));
+
+  registr.status = BTA_AV_FAIL_RESOURCES;
+  registr.app_id = p_data->api_reg.app_id;
+  registr.chnl = (tBTA_AV_CHNL)p_data->hdr.layer_specific;
+
+  uint16_t profile_initialized = p_data->api_reg.service_uuid;
+  if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) {
+    p_bta_av_cfg = (tBTA_AV_CFG*)&bta_avk_cfg;
+  } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) {
+    p_bta_av_cfg = (tBTA_AV_CFG*)&bta_av_cfg;
+  }
+
+  APPL_TRACE_DEBUG("%s: profile: 0x%x", __func__, profile_initialized);
+  if (p_bta_av_cfg == NULL) {
+    APPL_TRACE_ERROR("AV configuration is null!");
+    return;
+  }
+
+  do {
+    p_scb = bta_av_alloc_scb(registr.chnl);
+    if (p_scb == NULL) {
+      APPL_TRACE_ERROR("failed to alloc SCB");
+      break;
+    }
+
+    registr.hndl = p_scb->hndl;
+    p_scb->app_id = registr.app_id;
+
+    /* initialize the stream control block */
+    registr.status = BTA_AV_SUCCESS;
+
+    if ((bta_av_cb.reg_audio + bta_av_cb.reg_video) == 0) {
+      /* the first channel registered. register to AVDTP */
+      reg.ctrl_mtu = p_bta_av_cfg->sig_mtu;
+      reg.ret_tout = BTA_AV_RET_TOUT;
+      reg.sig_tout = BTA_AV_SIG_TOUT;
+      reg.idle_tout = BTA_AV_IDLE_TOUT;
+      reg.sec_mask = bta_av_cb.sec_mask;
+#if (BTA_AR_INCLUDED == TRUE)
+      bta_ar_reg_avdt(&reg, bta_av_conn_cback, BTA_ID_AV);
+#endif
+      bta_sys_role_chg_register(&bta_av_sys_rs_cback);
+
+      /* create remote control TG service if required */
+      if (bta_av_cb.features & (BTA_AV_FEAT_RCTG)) {
+/* register with no authorization; let AVDTP use authorization instead */
+#if (BTA_AR_INCLUDED == TRUE)
+#if (BTA_AV_WITH_AVCTP_AUTHORIZATION == TRUE)
+        bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
+                        bta_av_cb.sec_mask, BTA_ID_AV);
+#else
+        bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
+                        (uint8_t)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)),
+                        BTA_ID_AV);
+#endif
+
+        /* Both Audio Source and Audio Sink support AVRCP 1.6 for the
+         * major roles (i.e. Audio Source -> TG 1.6 and vice versa). For
+         * Audio Sink role we support additional TG 1.3 to support
+         * absolute volume. Here we only do TG registration.
+         */
+        uint16_t profile_version = AVRC_REV_1_0;
+        if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) {
+          profile_version = AVRC_REV_1_6;
+        } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) {
+          // Initialize AVRCP1.4 to provide Absolute Volume control.
+          profile_version = AVRC_REV_1_4;
+        }
+        bta_ar_reg_avrc(
+            UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target", NULL,
+            p_bta_av_cfg->avrc_tg_cat, BTA_ID_AV,
+            (bta_av_cb.features & BTA_AV_FEAT_BROWSE), profile_version);
+#endif
+      }
+
+      /* Set the Capturing service class bit */
+      if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE)
+        cod.service = BTM_COD_SERVICE_CAPTURING;
+      else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK)
+        cod.service = BTM_COD_SERVICE_RENDERING;
+      utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
+    } /* if 1st channel */
+
+    /* get stream configuration and create stream */
+    cs.cfg.num_codec = 1;
+    cs.nsc_mask =
+        AVDT_NSC_RECONFIG |
+        ((bta_av_cb.features & BTA_AV_FEAT_PROTECT) ? 0 : AVDT_NSC_SECURITY);
+    APPL_TRACE_DEBUG("nsc_mask: 0x%x", cs.nsc_mask);
+
+    if (p_data->api_reg.p_service_name[0] == 0) {
+      p_service_name = NULL;
+    } else {
+      p_service_name = p_data->api_reg.p_service_name;
+    }
+
+    p_scb->suspend_sup = true;
+    p_scb->recfg_sup = true;
+    p_scb->skip_sdp = false;
+
+    cs.p_ctrl_cback = bta_av_dt_cback[p_scb->hdi];
+    if (registr.chnl == BTA_AV_CHNL_AUDIO) {
+      /* set up the audio stream control block */
+      p_scb->p_act_tbl = (const tBTA_AV_ACT*)bta_av_a2dp_action;
+      p_scb->p_cos = &bta_av_a2dp_cos;
+      p_scb->media_type = AVDT_MEDIA_TYPE_AUDIO;
+      cs.cfg.psc_mask = AVDT_PSC_TRANS;
+      cs.media_type = AVDT_MEDIA_TYPE_AUDIO;
+      cs.mtu = p_bta_av_cfg->audio_mtu;
+      cs.flush_to = L2CAP_DEFAULT_FLUSH_TO;
+      tA2DP_CODEC_SEP_INDEX codec_sep_index_min =
+          A2DP_CODEC_SEP_INDEX_SOURCE_MIN;
+      tA2DP_CODEC_SEP_INDEX codec_sep_index_max =
+          A2DP_CODEC_SEP_INDEX_SOURCE_MAX;
+
+#if (AVDT_REPORTING == TRUE)
+      if (bta_av_cb.features & BTA_AV_FEAT_REPORT) {
+        cs.cfg.psc_mask |= AVDT_PSC_REPORT;
+        cs.p_report_cback = bta_av_a2dp_report_cback;
+      }
+#endif
+      if (bta_av_cb.features & BTA_AV_FEAT_DELAY_RPT)
+        cs.cfg.psc_mask |= AVDT_PSC_DELAY_RPT;
+
+      if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) {
+        cs.tsep = AVDT_TSEP_SRC;
+        codec_sep_index_min = A2DP_CODEC_SEP_INDEX_SOURCE_MIN;
+        codec_sep_index_max = A2DP_CODEC_SEP_INDEX_SOURCE_MAX;
+      } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) {
+        cs.tsep = AVDT_TSEP_SNK;
+        cs.p_sink_data_cback = bta_av_sink_data_cback;
+        codec_sep_index_min = A2DP_CODEC_SEP_INDEX_SINK_MIN;
+        codec_sep_index_max = A2DP_CODEC_SEP_INDEX_SINK_MAX;
+      }
+
+      /* Initialize handles to zero */
+      for (int xx = 0; xx < A2DP_CODEC_SEP_INDEX_MAX; xx++) {
+        p_scb->seps[xx].av_handle = 0;
+      }
+
+      /* keep the configuration in the stream control block */
+      memcpy(&p_scb->cfg, &cs.cfg, sizeof(tAVDT_CFG));
+      for (int i = 0; i < A2DP_CODEC_SEP_INDEX_MAX; i++) {
+        tA2DP_CODEC_SEP_INDEX codec_sep_index =
+            static_cast<tA2DP_CODEC_SEP_INDEX>(i);
+        if (!(*bta_av_a2dp_cos.init)(codec_sep_index, &cs.cfg)) {
+          continue;
+        }
+        if (AVDT_CreateStream(&p_scb->seps[codec_sep_index].av_handle, &cs) !=
+            AVDT_SUCCESS) {
+          continue;
+        }
+        /* Save a copy of the codec */
+        memcpy(p_scb->seps[codec_sep_index].codec_info, cs.cfg.codec_info,
+               AVDT_CODEC_SIZE);
+        p_scb->seps[codec_sep_index].tsep = cs.tsep;
+        if (cs.tsep == AVDT_TSEP_SNK) {
+          p_scb->seps[codec_sep_index].p_app_sink_data_cback =
+              p_data->api_reg.p_app_sink_data_cback;
+        } else {
+          /* In case of A2DP SOURCE we don't need a callback to
+           * handle media packets.
+           */
+          p_scb->seps[codec_sep_index].p_app_sink_data_cback = NULL;
+        }
+      }
+
+      if (!bta_av_cb.reg_audio) {
+        bta_av_cb.sdp_a2dp_handle = 0;
+        bta_av_cb.sdp_a2dp_snk_handle = 0;
+        if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) {
+          /* create the SDP records on the 1st audio channel */
+          bta_av_cb.sdp_a2dp_handle = SDP_CreateRecord();
+          A2DP_AddRecord(UUID_SERVCLASS_AUDIO_SOURCE, p_service_name, NULL,
+                         A2DP_SUPF_PLAYER, bta_av_cb.sdp_a2dp_handle);
+          bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SOURCE);
+        } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) {
+#if (BTA_AV_SINK_INCLUDED == TRUE)
+          bta_av_cb.sdp_a2dp_snk_handle = SDP_CreateRecord();
+          A2DP_AddRecord(UUID_SERVCLASS_AUDIO_SINK, p_service_name, NULL,
+                         A2DP_SUPF_PLAYER, bta_av_cb.sdp_a2dp_snk_handle);
+          bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SINK);
+#endif
+        }
+        /* start listening when A2DP is registered */
+        if (bta_av_cb.features & BTA_AV_FEAT_RCTG)
+          bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
+
+        /* if the AV and AVK are both supported, it cannot support the CT role
+         */
+        if (bta_av_cb.features & (BTA_AV_FEAT_RCCT)) {
+          /* if TG is not supported, we need to register to AVCT now */
+          if ((bta_av_cb.features & (BTA_AV_FEAT_RCTG)) == 0) {
+#if (BTA_AR_INCLUDED == TRUE)
+#if (BTA_AV_WITH_AVCTP_AUTHORIZATION == TRUE)
+            bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
+                            bta_av_cb.sec_mask, BTA_ID_AV);
+#else
+            bta_ar_reg_avct(
+                p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
+                (uint8_t)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)),
+                BTA_ID_AV);
+#endif
+#endif
+            bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
+          }
+#if (BTA_AR_INCLUDED == TRUE)
+          /* create an SDP record as AVRC CT. We create 1.3 for SOURCE
+           * because we rely on feature bits being scanned by external
+           * devices more than the profile version itself.
+           *
+           * We create 1.4 for SINK since we support browsing.
+           */
+          if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) {
+            bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,
+                            p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV,
+                            (bta_av_cb.features & BTA_AV_FEAT_BROWSE),
+                            AVRC_REV_1_3);
+          } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) {
+            bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,
+                            p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV,
+                            (bta_av_cb.features & BTA_AV_FEAT_BROWSE),
+                            AVRC_REV_1_6);
+          }
+#endif
+        }
+      }
+      bta_av_cb.reg_audio |= BTA_AV_HNDL_TO_MSK(p_scb->hdi);
+      APPL_TRACE_DEBUG("reg_audio: 0x%x", bta_av_cb.reg_audio);
+    } else {
+      bta_av_cb.reg_video = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
+      bta_av_cb.sdp_vdp_handle = SDP_CreateRecord();
+      /* register the video channel */
+      /* no need to verify the function pointer here. it's verified prior */
+      (*p_bta_av_cfg->p_reg)(&cs, p_service_name, p_scb);
+    }
+  } while (0);
+
+  /* call callback with register event */
+  (*bta_av_cb.p_cback)(BTA_AV_REGISTER_EVT, (tBTA_AV*)&registr);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_api_deregister
+ *
+ * Description      de-register a channel
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_api_deregister(tBTA_AV_DATA* p_data) {
+  tBTA_AV_SCB* p_scb = bta_av_hndl_to_scb(p_data->hdr.layer_specific);
+
+  if (p_scb) {
+    p_scb->deregistring = true;
+    bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, p_data);
+  } else {
+    bta_av_dereg_comp(p_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_ci_data
+ *
+ * Description      Forward the BTA_AV_CI_SRC_DATA_READY_EVT to stream state
+ *                  machine.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_av_ci_data(tBTA_AV_DATA* p_data) {
+  tBTA_AV_SCB* p_scb;
+  int i;
+  uint8_t chnl = (uint8_t)p_data->hdr.layer_specific;
+
+  for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+    p_scb = bta_av_cb.p_scb[i];
+
+    if (p_scb && p_scb->chnl == chnl) {
+      bta_av_ssm_execute(p_scb, BTA_AV_SRC_DATA_READY_EVT, p_data);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_rpc_conn
+ *
+ * Description      report report channel open
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+#if (AVDT_REPORTING == TRUE)
+static void bta_av_rpc_conn(UNUSED_ATTR tBTA_AV_DATA* p_data) {}
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_av_api_to_ssm
+ *
+ * Description      forward the API request to stream state machine
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_av_api_to_ssm(tBTA_AV_DATA* p_data) {
+  int xx;
+  uint16_t event =
+      p_data->hdr.event - BTA_AV_FIRST_A2S_API_EVT + BTA_AV_FIRST_A2S_SSM_EVT;
+
+  for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) {
+    bta_av_ssm_execute(bta_av_cb.p_scb[xx], event, p_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_chk_start
+ *
+ * Description      if this is audio channel, check if more than one audio
+ *                  channel is connected & already started.
+ *
+ * Returns          true, if need api_start
+ *
+ ******************************************************************************/
+bool bta_av_chk_start(tBTA_AV_SCB* p_scb) {
+  bool start = false;
+  tBTA_AV_SCB* p_scbi;
+  int i;
+
+  if (p_scb->chnl == BTA_AV_CHNL_AUDIO) {
+    if ((bta_av_cb.audio_open_cnt >= 2) &&
+        ((0 ==
+          (p_scb->role & BTA_AV_ROLE_AD_ACP)) || /* Outgoing connection or   */
+         (bta_av_cb.features &
+          BTA_AV_FEAT_ACP_START))) /* auto-starting option     */
+    {
+      /* more than one audio channel is connected */
+      /* if this is the 2nd stream as ACP, give INT a chance to issue the START
+       * command */
+      for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+        p_scbi = bta_av_cb.p_scb[i];
+        if (p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started) {
+          start = true;
+          /* may need to update the flush timeout of this already started stream
+           */
+          if (p_scbi->co_started != bta_av_cb.audio_open_cnt) {
+            p_scbi->co_started = bta_av_cb.audio_open_cnt;
+            L2CA_SetFlushTimeout(
+                p_scbi->peer_addr,
+                p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1]);
+          }
+        }
+      }
+    }
+  }
+  return start;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_restore_switch
+ *
+ * Description      assume that the caller of this function already makes
+ *                  sure that there's only one ACL connection left
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_restore_switch(void) {
+  tBTA_AV_CB* p_cb = &bta_av_cb;
+  int i;
+  uint8_t mask;
+
+  APPL_TRACE_DEBUG("reg_audio: 0x%x", bta_av_cb.reg_audio);
+  for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+    mask = BTA_AV_HNDL_TO_MSK(i);
+    if (p_cb->conn_audio == mask) {
+      if (p_cb->p_scb[i]) {
+        bta_sys_set_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH,
+                           p_cb->p_scb[i]->peer_addr);
+      }
+      break;
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_sys_rs_cback
+ *
+ * Description      Receives the role change event from dm
+ *
+ * Returns          (BTA_SYS_ROLE_CHANGE, new_role, hci_status, p_bda)
+ *
+ ******************************************************************************/
+static void bta_av_sys_rs_cback(UNUSED_ATTR tBTA_SYS_CONN_STATUS status,
+                                uint8_t id, uint8_t app_id, BD_ADDR peer_addr) {
+  int i;
+  tBTA_AV_SCB* p_scb = NULL;
+  uint8_t cur_role;
+  uint8_t peer_idx = 0;
+
+  APPL_TRACE_DEBUG("bta_av_sys_rs_cback: %d", bta_av_cb.rs_idx);
+  for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+    /* loop through all the SCBs to find matching peer addresses and report the
+     * role change event */
+    /* note that more than one SCB (a2dp & vdp) maybe waiting for this event */
+    p_scb = bta_av_cb.p_scb[i];
+    if (p_scb && (bdcmp(peer_addr, p_scb->peer_addr) == 0)) {
+      tBTA_AV_ROLE_RES* p_buf =
+          (tBTA_AV_ROLE_RES*)osi_malloc(sizeof(tBTA_AV_ROLE_RES));
+      APPL_TRACE_DEBUG("new_role:%d, hci_status:x%x hndl: x%x", id, app_id,
+                       p_scb->hndl);
+      /*
+      if ((id != BTM_ROLE_MASTER) && (app_id != HCI_SUCCESS))
+      {
+          bta_sys_set_policy(BTA_ID_AV,
+      (HCI_ENABLE_MASTER_SLAVE_SWITCH|HCI_ENABLE_SNIFF_MODE), p_scb->peer_addr);
+      }
+      */
+      p_buf->hdr.event = BTA_AV_ROLE_CHANGE_EVT;
+      p_buf->hdr.layer_specific = p_scb->hndl;
+      p_buf->new_role = id;
+      p_buf->hci_status = app_id;
+      bta_sys_sendmsg(p_buf);
+
+      peer_idx = p_scb->hdi + 1; /* Handle index for the peer_addr */
+    }
+  }
+
+  /* restore role switch policy, if role switch failed */
+  if ((HCI_SUCCESS != app_id) &&
+      (BTM_GetRole(peer_addr, &cur_role) == BTM_SUCCESS) &&
+      (cur_role == BTM_ROLE_SLAVE)) {
+    bta_sys_set_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH, peer_addr);
+  }
+
+  /* if BTA_AvOpen() was called for other device, which caused the role switch
+   * of the peer_addr,  */
+  /* we need to continue opening process for the BTA_AvOpen(). */
+  if ((bta_av_cb.rs_idx != 0) && (bta_av_cb.rs_idx != peer_idx)) {
+    if ((bta_av_cb.rs_idx - 1) < BTA_AV_NUM_STRS) {
+      p_scb = bta_av_cb.p_scb[bta_av_cb.rs_idx - 1];
+    }
+    if (p_scb && p_scb->q_tag == BTA_AV_Q_TAG_OPEN) {
+      APPL_TRACE_DEBUG("bta_av_sys_rs_cback: rs_idx(%d), hndl:x%x q_tag: %d",
+                       bta_av_cb.rs_idx, p_scb->hndl, p_scb->q_tag);
+
+      if (HCI_SUCCESS == app_id || HCI_ERR_NO_CONNECTION == app_id)
+        p_scb->q_info.open.switch_res = BTA_AV_RS_OK;
+      else
+        p_scb->q_info.open.switch_res = BTA_AV_RS_FAIL;
+
+      /* Continue av open process */
+      bta_av_do_disc_a2dp(p_scb, (tBTA_AV_DATA*)&(p_scb->q_info.open));
+    }
+
+    bta_av_cb.rs_idx = 0;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_sco_chg_cback
+ *
+ * Description      receive & process the SCO connection up/down event from sys.
+ *                  call setup also triggers this callback, to suspend av before
+ *                  SCO activity happens, or to resume av once call ends.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_av_sco_chg_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
+                                 UNUSED_ATTR uint8_t app_id,
+                                 UNUSED_ATTR BD_ADDR peer_addr) {
+  tBTA_AV_SCB* p_scb;
+  int i;
+  tBTA_AV_API_STOP stop;
+
+  APPL_TRACE_DEBUG("bta_av_sco_chg_cback:%d status:%d", id, status);
+  if (id) {
+    bta_av_cb.sco_occupied = true;
+
+    /* 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 == false)) {
+        APPL_TRACE_DEBUG("suspending scb:%d", i);
+        /* scb is used and started, not suspended automatically */
+        p_scb->sco_suspend = true;
+        stop.flush = false;
+        stop.suspend = true;
+        bta_av_ssm_execute(p_scb, BTA_AV_AP_STOP_EVT, (tBTA_AV_DATA*)&stop);
+      }
+    }
+  } else {
+    bta_av_cb.sco_occupied = false;
+
+    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("starting scb:%d", i);
+        bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL);
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_switch_if_needed
+ *
+ * Description      This function checks if there is another existing AV
+ *                  channel that is local as slave role.
+ *                  If so, role switch and remove it from link policy.
+ *
+ * Returns          true, if role switch is done
+ *
+ ******************************************************************************/
+bool bta_av_switch_if_needed(tBTA_AV_SCB* p_scb) {
+  uint8_t role;
+  bool needed = false;
+  tBTA_AV_SCB* p_scbi;
+  int i;
+  uint8_t mask;
+
+  for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+    mask = BTA_AV_HNDL_TO_MSK(i);
+    p_scbi = bta_av_cb.p_scb[i];
+    if (p_scbi && (p_scb->hdi != i) &&    /* not the original channel */
+        ((bta_av_cb.conn_audio & mask) || /* connected audio */
+         (bta_av_cb.conn_video & mask)))  /* connected video */
+    {
+      BTM_GetRole(p_scbi->peer_addr, &role);
+      /* this channel is open - clear the role switch link policy for this link
+       */
+      if (BTM_ROLE_MASTER != role) {
+        if (bta_av_cb.features & BTA_AV_FEAT_MASTER)
+          bta_sys_clear_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH,
+                               p_scbi->peer_addr);
+        if (BTM_CMD_STARTED !=
+            BTM_SwitchRole(p_scbi->peer_addr, BTM_ROLE_MASTER, NULL)) {
+          /* can not switch role on SCBI
+           * start the timer on SCB - because this function is ONLY called when
+           * SCB gets API_OPEN */
+          bta_sys_start_timer(p_scb->avrc_ct_timer, BTA_AV_RS_TIME_VAL,
+                              BTA_AV_AVRC_TIMER_EVT, p_scb->hndl);
+        }
+        needed = true;
+        /* mark the original channel as waiting for RS result */
+        bta_av_cb.rs_idx = p_scb->hdi + 1;
+        break;
+      }
+    }
+  }
+  return needed;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_link_role_ok
+ *
+ * Description      This function checks if the SCB has existing ACL connection
+ *                  If so, check if the link role fits the requirements.
+ *
+ * Returns          true, if role is ok
+ *
+ ******************************************************************************/
+bool bta_av_link_role_ok(tBTA_AV_SCB* p_scb, uint8_t bits) {
+  uint8_t role;
+  bool is_ok = true;
+
+  if (BTM_GetRole(p_scb->peer_addr, &role) == BTM_SUCCESS) {
+    LOG_INFO(LOG_TAG, "%s hndl:x%x role:%d conn_audio:x%x bits:%d features:x%x",
+             __func__, p_scb->hndl, role, bta_av_cb.conn_audio, bits,
+             bta_av_cb.features);
+    if (BTM_ROLE_MASTER != role &&
+        (A2DP_BitsSet(bta_av_cb.conn_audio) > bits ||
+         (bta_av_cb.features & BTA_AV_FEAT_MASTER))) {
+      if (bta_av_cb.features & BTA_AV_FEAT_MASTER)
+        bta_sys_clear_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH,
+                             p_scb->peer_addr);
+
+      if (BTM_CMD_STARTED !=
+          BTM_SwitchRole(p_scb->peer_addr, BTM_ROLE_MASTER, NULL)) {
+        /* can not switch role on SCB - start the timer on SCB */
+      }
+      is_ok = false;
+      p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_START;
+    }
+  }
+
+  return is_ok;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_chk_mtu
+ *
+ * Description      if this is audio channel, check if more than one audio
+ *                  channel is connected.
+ *
+ * Returns          The smallest mtu of the connected audio channels
+ *
+ ******************************************************************************/
+uint16_t bta_av_chk_mtu(tBTA_AV_SCB* p_scb, UNUSED_ATTR uint16_t mtu) {
+  uint16_t ret_mtu = BTA_AV_MAX_A2DP_MTU;
+  tBTA_AV_SCB* p_scbi;
+  int i;
+  uint8_t mask;
+
+  /* TODO_MV mess with the mtu according to the number of EDR/non-EDR headsets
+   */
+  if (p_scb->chnl == BTA_AV_CHNL_AUDIO) {
+    if (bta_av_cb.audio_open_cnt >= 2) {
+      /* more than one audio channel is connected */
+      for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+        p_scbi = bta_av_cb.p_scb[i];
+        if ((p_scb != p_scbi) && p_scbi &&
+            (p_scbi->chnl == BTA_AV_CHNL_AUDIO)) {
+          mask = BTA_AV_HNDL_TO_MSK(i);
+          APPL_TRACE_DEBUG("[%d] mtu: %d, mask:0x%x", i, p_scbi->stream_mtu,
+                           mask);
+          if (bta_av_cb.conn_audio & mask) {
+            if (ret_mtu > p_scbi->stream_mtu) ret_mtu = p_scbi->stream_mtu;
+          }
+        }
+      }
+    }
+    APPL_TRACE_DEBUG("bta_av_chk_mtu audio count:%d, conn_audio:0x%x, ret:%d",
+                     bta_av_cb.audio_open_cnt, bta_av_cb.conn_audio, ret_mtu);
+  }
+  return ret_mtu;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_dup_audio_buf
+ *
+ * Description      dup the audio data to the q_info.a2dp of other audio
+ *                  channels
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_dup_audio_buf(tBTA_AV_SCB* p_scb, BT_HDR* p_buf) {
+  /* Test whether there is more than one audio channel connected */
+  if ((p_buf == NULL) || (bta_av_cb.audio_open_cnt < 2)) return;
+
+  uint16_t copy_size = BT_HDR_SIZE + p_buf->len + p_buf->offset;
+  for (int i = 0; i < BTA_AV_NUM_STRS; i++) {
+    tBTA_AV_SCB* p_scbi = bta_av_cb.p_scb[i];
+
+    if (i == p_scb->hdi) continue; /* Ignore the original channel */
+    if ((p_scbi == NULL) || !p_scbi->co_started)
+      continue; /* Ignore if SCB is not used or started */
+    if (!(bta_av_cb.conn_audio & BTA_AV_HNDL_TO_MSK(i)))
+      continue; /* Audio is not connected */
+
+    /* Enqueue the data */
+    BT_HDR* p_new = (BT_HDR*)osi_malloc(copy_size);
+    memcpy(p_new, p_buf, copy_size);
+    list_append(p_scbi->a2dp_list, p_new);
+
+    if (list_length(p_scbi->a2dp_list) > p_bta_av_cfg->audio_mqs) {
+      // Drop the oldest packet
+      bta_av_co_audio_drop(p_scbi->hndl);
+      BT_HDR* p_buf_drop = static_cast<BT_HDR*>(list_front(p_scbi->a2dp_list));
+      list_remove(p_scbi->a2dp_list, p_buf_drop);
+      osi_free(p_buf_drop);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_sm_execute
+ *
+ * Description      State machine event handling function for AV
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_sm_execute(tBTA_AV_CB* p_cb, uint16_t event, tBTA_AV_DATA* p_data) {
+  tBTA_AV_ST_TBL state_table;
+  uint8_t action;
+
+#if (BTA_AV_DEBUG == TRUE)
+  APPL_TRACE_EVENT("AV event=0x%x(%s) state=%d(%s)", event,
+                   bta_av_evt_code(event), p_cb->state,
+                   bta_av_st_code(p_cb->state));
+#else
+  APPL_TRACE_EVENT("AV event=0x%x state=%d", event, p_cb->state);
+#endif
+
+  /* look up the state table for the current state */
+  state_table = bta_av_st_tbl[p_cb->state];
+
+  event &= 0x00FF;
+
+  /* set next state */
+  p_cb->state = state_table[event][BTA_AV_NEXT_STATE];
+  APPL_TRACE_EVENT("next state=%d event offset:%d", p_cb->state, event);
+
+  /* execute action functions */
+  if ((action = state_table[event][BTA_AV_ACTION_COL]) != BTA_AV_IGNORE) {
+    APPL_TRACE_EVENT("%s action executed %d", __func__, action);
+    (*bta_av_action[action])(p_cb, p_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_hdl_event
+ *
+ * Description      Advanced audio/video main event handling function.
+ *
+ *
+ * Returns          bool
+ *
+ ******************************************************************************/
+bool bta_av_hdl_event(BT_HDR* p_msg) {
+  uint16_t event = p_msg->event;
+  uint16_t first_event = BTA_AV_FIRST_NSM_EVT;
+
+  if (event > BTA_AV_LAST_EVT) {
+    return true; /* to free p_msg */
+  }
+
+  if (event >= first_event) {
+#if (BTA_AV_DEBUG == TRUE)
+    APPL_TRACE_VERBOSE("AV nsm event=0x%x(%s)", event, bta_av_evt_code(event));
+#else
+    APPL_TRACE_VERBOSE("AV nsm event=0x%x", event);
+#endif
+    /* non state machine events */
+    (*bta_av_nsm_act[event - BTA_AV_FIRST_NSM_EVT])((tBTA_AV_DATA*)p_msg);
+  } else if (event >= BTA_AV_FIRST_SM_EVT && event <= BTA_AV_LAST_SM_EVT) {
+#if (BTA_AV_DEBUG == TRUE)
+    APPL_TRACE_VERBOSE("AV sm event=0x%x(%s)", event, bta_av_evt_code(event));
+#else
+    APPL_TRACE_VERBOSE("AV sm event=0x%x", event);
+#endif
+    /* state machine events */
+    bta_av_sm_execute(&bta_av_cb, p_msg->event, (tBTA_AV_DATA*)p_msg);
+  } else {
+    APPL_TRACE_VERBOSE("handle=0x%x", p_msg->layer_specific);
+    /* stream state machine events */
+    bta_av_ssm_execute(bta_av_hndl_to_scb(p_msg->layer_specific), p_msg->event,
+                       (tBTA_AV_DATA*)p_msg);
+  }
+  return true;
+}
+
+/*****************************************************************************
+ *  Debug Functions
+ ****************************************************************************/
+#if (BTA_AV_DEBUG == TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_av_st_code
+ *
+ * Description
+ *
+ * Returns          char *
+ *
+ ******************************************************************************/
+static const char* bta_av_st_code(uint8_t state) {
+  switch (state) {
+    case BTA_AV_INIT_ST:
+      return "INIT";
+    case BTA_AV_OPEN_ST:
+      return "OPEN";
+    default:
+      return "unknown";
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_av_evt_code
+ *
+ * Description
+ *
+ * Returns          char *
+ *
+ ******************************************************************************/
+const char* bta_av_evt_code(uint16_t evt_code) {
+  switch (evt_code) {
+    case BTA_AV_API_DISABLE_EVT:
+      return "API_DISABLE";
+    case BTA_AV_API_REMOTE_CMD_EVT:
+      return "API_REMOTE_CMD";
+    case BTA_AV_API_VENDOR_CMD_EVT:
+      return "API_VENDOR_CMD";
+    case BTA_AV_API_VENDOR_RSP_EVT:
+      return "API_VENDOR_RSP";
+    case BTA_AV_API_META_RSP_EVT:
+      return "API_META_RSP_EVT";
+    case BTA_AV_API_RC_CLOSE_EVT:
+      return "API_RC_CLOSE";
+    case BTA_AV_AVRC_OPEN_EVT:
+      return "AVRC_OPEN";
+    case BTA_AV_AVRC_MSG_EVT:
+      return "AVRC_MSG";
+    case BTA_AV_AVRC_NONE_EVT:
+      return "AVRC_NONE";
+
+    case BTA_AV_API_OPEN_EVT:
+      return "API_OPEN";
+    case BTA_AV_API_CLOSE_EVT:
+      return "API_CLOSE";
+    case BTA_AV_AP_START_EVT:
+      return "AP_START";
+    case BTA_AV_AP_STOP_EVT:
+      return "AP_STOP";
+    case BTA_AV_API_RECONFIG_EVT:
+      return "API_RECONFIG";
+    case BTA_AV_API_PROTECT_REQ_EVT:
+      return "API_PROTECT_REQ";
+    case BTA_AV_API_PROTECT_RSP_EVT:
+      return "API_PROTECT_RSP";
+    case BTA_AV_API_RC_OPEN_EVT:
+      return "API_RC_OPEN";
+    case BTA_AV_SRC_DATA_READY_EVT:
+      return "SRC_DATA_READY";
+    case BTA_AV_CI_SETCONFIG_OK_EVT:
+      return "CI_SETCONFIG_OK";
+    case BTA_AV_CI_SETCONFIG_FAIL_EVT:
+      return "CI_SETCONFIG_FAIL";
+    case BTA_AV_SDP_DISC_OK_EVT:
+      return "SDP_DISC_OK";
+    case BTA_AV_SDP_DISC_FAIL_EVT:
+      return "SDP_DISC_FAIL";
+    case BTA_AV_STR_DISC_OK_EVT:
+      return "STR_DISC_OK";
+    case BTA_AV_STR_DISC_FAIL_EVT:
+      return "STR_DISC_FAIL";
+    case BTA_AV_STR_GETCAP_OK_EVT:
+      return "STR_GETCAP_OK";
+    case BTA_AV_STR_GETCAP_FAIL_EVT:
+      return "STR_GETCAP_FAIL";
+    case BTA_AV_STR_OPEN_OK_EVT:
+      return "STR_OPEN_OK";
+    case BTA_AV_STR_OPEN_FAIL_EVT:
+      return "STR_OPEN_FAIL";
+    case BTA_AV_STR_START_OK_EVT:
+      return "STR_START_OK";
+    case BTA_AV_STR_START_FAIL_EVT:
+      return "STR_START_FAIL";
+    case BTA_AV_STR_CLOSE_EVT:
+      return "STR_CLOSE";
+    case BTA_AV_STR_CONFIG_IND_EVT:
+      return "STR_CONFIG_IND";
+    case BTA_AV_STR_SECURITY_IND_EVT:
+      return "STR_SECURITY_IND";
+    case BTA_AV_STR_SECURITY_CFM_EVT:
+      return "STR_SECURITY_CFM";
+    case BTA_AV_STR_WRITE_CFM_EVT:
+      return "STR_WRITE_CFM";
+    case BTA_AV_STR_SUSPEND_CFM_EVT:
+      return "STR_SUSPEND_CFM";
+    case BTA_AV_STR_RECONFIG_CFM_EVT:
+      return "STR_RECONFIG_CFM";
+    case BTA_AV_AVRC_TIMER_EVT:
+      return "AVRC_TIMER";
+    case BTA_AV_AVDT_CONNECT_EVT:
+      return "AVDT_CONNECT";
+    case BTA_AV_AVDT_DISCONNECT_EVT:
+      return "AVDT_DISCONNECT";
+    case BTA_AV_ROLE_CHANGE_EVT:
+      return "ROLE_CHANGE";
+    case BTA_AV_AVDT_DELAY_RPT_EVT:
+      return "AVDT_DELAY_RPT";
+    case BTA_AV_ACP_CONNECT_EVT:
+      return "ACP_CONNECT";
+
+    case BTA_AV_API_ENABLE_EVT:
+      return "API_ENABLE";
+    case BTA_AV_API_REGISTER_EVT:
+      return "API_REG";
+    case BTA_AV_API_DEREGISTER_EVT:
+      return "API_DEREG";
+    case BTA_AV_API_DISCONNECT_EVT:
+      return "API_DISCNT";
+    case BTA_AV_CI_SRC_DATA_READY_EVT:
+      return "CI_DATA_READY";
+    case BTA_AV_SIG_CHG_EVT:
+      return "SIG_CHG";
+    case BTA_AV_SIGNALLING_TIMER_EVT:
+      return "SIGNALLING_TIMER";
+    case BTA_AV_SDP_AVRC_DISC_EVT:
+      return "SDP_AVRC_DISC";
+    case BTA_AV_AVRC_CLOSE_EVT:
+      return "AVRC_CLOSE";
+    case BTA_AV_AVRC_BROWSE_OPEN_EVT:
+      return "AVRC_BROWSE_OPEN";
+    case BTA_AV_AVRC_BROWSE_CLOSE_EVT:
+      return "AVRC_BROWSE_CLOSE";
+    case BTA_AV_CONN_CHG_EVT:
+      return "CONN_CHG";
+    case BTA_AV_DEREG_COMP_EVT:
+      return "DEREG_COMP";
+#if (AVDT_REPORTING == TRUE)
+    case BTA_AV_AVDT_RPT_CONN_EVT:
+      return "RPT_CONN";
+#endif
+    case BTA_AV_API_START_EVT:
+      return "API_START";
+    case BTA_AV_API_STOP_EVT:
+      return "API_STOP";
+    default:
+      return "unknown";
+  }
+}
+#endif /* BTA_AV_DEBUG */
diff --git a/bt/bta/av/bta_av_ssm.cc b/bt/bta/av/bta_av_ssm.cc
new file mode 100644
index 0000000..1578c22
--- /dev/null
+++ b/bt/bta/av/bta_av_ssm.cc
@@ -0,0 +1,682 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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 is the stream state machine for the BTA advanced audio/video.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#include "bta_av_co.h"
+#include "bta_av_int.h"
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+
+/* state machine states */
+enum {
+  BTA_AV_INIT_SST,
+  BTA_AV_INCOMING_SST,
+  BTA_AV_OPENING_SST,
+  BTA_AV_OPEN_SST,
+  BTA_AV_RCFG_SST,
+  BTA_AV_CLOSING_SST
+};
+
+/* state machine action enumeration list */
+enum {
+  BTA_AV_DO_DISC,
+  BTA_AV_CLEANUP,
+  BTA_AV_FREE_SDB,
+  BTA_AV_CONFIG_IND,
+  BTA_AV_DISCONNECT_REQ,
+  BTA_AV_SECURITY_REQ,
+  BTA_AV_SECURITY_RSP,
+  BTA_AV_SETCONFIG_RSP,
+  BTA_AV_ST_RC_TIMER,
+  BTA_AV_STR_OPENED,
+  BTA_AV_SECURITY_IND,
+  BTA_AV_SECURITY_CFM,
+  BTA_AV_DO_CLOSE,
+  BTA_AV_CONNECT_REQ,
+  BTA_AV_SDP_FAILED,
+  BTA_AV_DISC_RESULTS,
+  BTA_AV_DISC_RES_AS_ACP,
+  BTA_AV_OPEN_FAILED,
+  BTA_AV_GETCAP_RESULTS,
+  BTA_AV_SETCONFIG_REJ,
+  BTA_AV_DISCOVER_REQ,
+  BTA_AV_CONN_FAILED,
+  BTA_AV_DO_START,
+  BTA_AV_STR_STOPPED,
+  BTA_AV_RECONFIG,
+  BTA_AV_DATA_PATH,
+  BTA_AV_START_OK,
+  BTA_AV_START_FAILED,
+  BTA_AV_STR_CLOSED,
+  BTA_AV_CLR_CONG,
+  BTA_AV_SUSPEND_CFM,
+  BTA_AV_RCFG_STR_OK,
+  BTA_AV_RCFG_FAILED,
+  BTA_AV_RCFG_CONNECT,
+  BTA_AV_RCFG_DISCNTD,
+  BTA_AV_SUSPEND_CONT,
+  BTA_AV_RCFG_CFM,
+  BTA_AV_RCFG_OPEN,
+  BTA_AV_SECURITY_REJ,
+  BTA_AV_OPEN_RC,
+  BTA_AV_CHK_2ND_START,
+  BTA_AV_SAVE_CAPS,
+  BTA_AV_SET_USE_RC,
+  BTA_AV_CCO_CLOSE,
+  BTA_AV_SWITCH_ROLE,
+  BTA_AV_ROLE_RES,
+  BTA_AV_DELAY_CO,
+  BTA_AV_OPEN_AT_INC,
+  BTA_AV_OFFLOAD_REQ,
+  BTA_AV_OFFLOAD_RSP,
+  BTA_AV_NUM_SACTIONS
+};
+
+#define BTA_AV_SIGNORE BTA_AV_NUM_SACTIONS
+
+/* state table information */
+/* #define BTA_AV_SACTION_COL           0       position of actions */
+#define BTA_AV_SACTIONS 2    /* number of actions */
+#define BTA_AV_SNEXT_STATE 2 /* position of next state */
+#define BTA_AV_NUM_COLS 3    /* number of columns in state tables */
+
+/* state table for init state */
+static const uint8_t bta_av_sst_init[][BTA_AV_NUM_COLS] = {
+    /* Event                     Action 1               Action 2 Next state */
+    /* AP_OPEN_EVT */ {BTA_AV_DO_DISC, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* AP_CLOSE_EVT */ {BTA_AV_CLEANUP, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* API_PROTECT_REQ_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* API_PROTECT_RSP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* API_RC_OPEN_EVT  */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                                 BTA_AV_INIT_SST},
+    /* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* STR_DISC_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* STR_GETCAP_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* STR_OPEN_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* STR_OPEN_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* STR_CLOSE_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE,
+                              BTA_AV_INIT_SST},
+    /* STR_SECURITY_IND_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                                BTA_AV_INIT_SST},
+    /* STR_SECURITY_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                                BTA_AV_INIT_SST},
+    /* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                                BTA_AV_INIT_SST},
+    /* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* AVDT_DISCONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* AVDT_DELAY_RPT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* API_OFFLOAD_START_EVT */ {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE,
+                                 BTA_AV_INIT_SST},
+    /* API_OFFLOAD_START_RSP_EVT */ {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE,
+                                     BTA_AV_INIT_SST}};
+
+/* state table for incoming state */
+static const uint8_t bta_av_sst_incoming[][BTA_AV_NUM_COLS] = {
+    /* Event                     Action 1               Action 2 Next state */
+    /* AP_OPEN_EVT */ {BTA_AV_OPEN_AT_INC, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* AP_CLOSE_EVT */ {BTA_AV_CCO_CLOSE, BTA_AV_DISCONNECT_REQ,
+                        BTA_AV_CLOSING_SST},
+    /* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                            BTA_AV_INCOMING_SST},
+    /* API_PROTECT_REQ_EVT */ {BTA_AV_SECURITY_REQ, BTA_AV_SIGNORE,
+                               BTA_AV_INCOMING_SST},
+    /* API_PROTECT_RSP_EVT */ {BTA_AV_SECURITY_RSP, BTA_AV_SIGNORE,
+                               BTA_AV_INCOMING_SST},
+    /* API_RC_OPEN_EVT  */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                            BTA_AV_INCOMING_SST},
+    /* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                              BTA_AV_INCOMING_SST},
+    /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SETCONFIG_RSP, BTA_AV_ST_RC_TIMER,
+                               BTA_AV_INCOMING_SST},
+    /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_CLEANUP,
+                                 BTA_AV_INIT_SST},
+    /* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE,
+                           BTA_AV_INCOMING_SST},
+    /* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE,
+                             BTA_AV_INCOMING_SST},
+    /* STR_DISC_OK_EVT */ {BTA_AV_DISC_RES_AS_ACP, BTA_AV_SIGNORE,
+                           BTA_AV_INCOMING_SST},
+    /* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                             BTA_AV_INCOMING_SST},
+    /* STR_GETCAP_OK_EVT */ {BTA_AV_SAVE_CAPS, BTA_AV_SIGNORE,
+                             BTA_AV_INCOMING_SST},
+    /* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                               BTA_AV_INCOMING_SST},
+    /* STR_OPEN_OK_EVT */ {BTA_AV_STR_OPENED, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* STR_OPEN_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                             BTA_AV_INCOMING_SST},
+    /* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                            BTA_AV_INCOMING_SST},
+    /* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                              BTA_AV_INCOMING_SST},
+    /* STR_CLOSE_EVT */ {BTA_AV_CCO_CLOSE, BTA_AV_CLEANUP, BTA_AV_INIT_SST},
+    /* STR_CONFIG_IND_EVT */ {BTA_AV_CONFIG_IND, BTA_AV_SIGNORE,
+                              BTA_AV_INCOMING_SST},
+    /* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_IND, BTA_AV_SIGNORE,
+                                BTA_AV_INCOMING_SST},
+    /* STR_SECURITY_CFM_EVT */ {BTA_AV_SECURITY_CFM, BTA_AV_SIGNORE,
+                                BTA_AV_INCOMING_SST},
+    /* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                             BTA_AV_INCOMING_SST},
+    /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                               BTA_AV_INCOMING_SST},
+    /* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                                BTA_AV_INCOMING_SST},
+    /* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                            BTA_AV_INCOMING_SST},
+    /* AVDT_DISCONNECT_EVT */ {BTA_AV_CCO_CLOSE, BTA_AV_DISCONNECT_REQ,
+                               BTA_AV_CLOSING_SST},
+    /* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE,
+                              BTA_AV_INCOMING_SST},
+    /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+    /* API_OFFLOAD_START_EVT */ {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE,
+                                 BTA_AV_INCOMING_SST},
+    /* API_OFFLOAD_START_RSP_EVT */ {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE,
+                                     BTA_AV_INCOMING_SST}};
+
+/* state table for opening state */
+static const uint8_t bta_av_sst_opening[][BTA_AV_NUM_COLS] = {
+    /* Event                     Action 1               Action 2 Next state */
+    /* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* AP_CLOSE_EVT */ {BTA_AV_DO_CLOSE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* API_PROTECT_REQ_EVT */ {BTA_AV_SECURITY_REQ, BTA_AV_SIGNORE,
+                               BTA_AV_OPENING_SST},
+    /* API_PROTECT_RSP_EVT */ {BTA_AV_SECURITY_RSP, BTA_AV_SIGNORE,
+                               BTA_AV_OPENING_SST},
+    /* API_RC_OPEN_EVT  */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                              BTA_AV_OPENING_SST},
+    /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                               BTA_AV_OPENING_SST},
+    /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                                 BTA_AV_OPENING_SST},
+    /* SDP_DISC_OK_EVT */ {BTA_AV_CONNECT_REQ, BTA_AV_SIGNORE,
+                           BTA_AV_OPENING_SST},
+    /* SDP_DISC_FAIL_EVT */ {BTA_AV_CONNECT_REQ, BTA_AV_SIGNORE,
+                             BTA_AV_OPENING_SST},
+    /* STR_DISC_OK_EVT */ {BTA_AV_DISC_RESULTS, BTA_AV_SIGNORE,
+                           BTA_AV_OPENING_SST},
+    /* STR_DISC_FAIL_EVT */ {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE,
+                             BTA_AV_CLOSING_SST},
+    /* STR_GETCAP_OK_EVT */ {BTA_AV_GETCAP_RESULTS, BTA_AV_SIGNORE,
+                             BTA_AV_OPENING_SST},
+    /* STR_GETCAP_FAIL_EVT */ {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE,
+                               BTA_AV_CLOSING_SST},
+    /* STR_OPEN_OK_EVT */ {BTA_AV_ST_RC_TIMER, BTA_AV_STR_OPENED,
+                           BTA_AV_OPEN_SST},
+    /* STR_OPEN_FAIL_EVT */ {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE,
+                             BTA_AV_CLOSING_SST},
+    /* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                              BTA_AV_OPENING_SST},
+    /* STR_CLOSE_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* STR_CONFIG_IND_EVT */ {BTA_AV_CONFIG_IND, BTA_AV_SIGNORE,
+                              BTA_AV_INCOMING_SST},
+    /* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_IND, BTA_AV_SIGNORE,
+                                BTA_AV_OPENING_SST},
+    /* STR_SECURITY_CFM_EVT */ {BTA_AV_SECURITY_CFM, BTA_AV_SIGNORE,
+                                BTA_AV_OPENING_SST},
+    /* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                             BTA_AV_OPENING_SST},
+    /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                               BTA_AV_OPENING_SST},
+    /* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                                BTA_AV_OPENING_SST},
+    /* AVRC_TIMER_EVT */ {BTA_AV_SWITCH_ROLE, BTA_AV_SIGNORE,
+                          BTA_AV_OPENING_SST},
+    /* AVDT_CONNECT_EVT */ {BTA_AV_DISCOVER_REQ, BTA_AV_SIGNORE,
+                            BTA_AV_OPENING_SST},
+    /* AVDT_DISCONNECT_EVT */ {BTA_AV_CONN_FAILED, BTA_AV_SIGNORE,
+                               BTA_AV_INIT_SST},
+    /* ROLE_CHANGE_EVT*/ {BTA_AV_ROLE_RES, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE,
+                              BTA_AV_OPENING_SST},
+    /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+    /* API_OFFLOAD_START_EVT */ {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE,
+                                 BTA_AV_OPENING_SST},
+    /* API_OFFLOAD_START_RSP_EVT */ {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE,
+                                     BTA_AV_OPENING_SST}};
+
+/* state table for open state */
+static const uint8_t bta_av_sst_open[][BTA_AV_NUM_COLS] = {
+    /* Event                     Action 1               Action 2 Next state */
+    /* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* AP_CLOSE_EVT */ {BTA_AV_DO_CLOSE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* AP_START_EVT */ {BTA_AV_DO_START, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* AP_STOP_EVT */ {BTA_AV_STR_STOPPED, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* API_RECONFIG_EVT */ {BTA_AV_RECONFIG, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* API_PROTECT_REQ_EVT */ {BTA_AV_SECURITY_REQ, BTA_AV_SIGNORE,
+                               BTA_AV_OPEN_SST},
+    /* API_PROTECT_RSP_EVT */ {BTA_AV_SECURITY_RSP, BTA_AV_SIGNORE,
+                               BTA_AV_OPEN_SST},
+    /* API_RC_OPEN_EVT  */ {BTA_AV_SET_USE_RC, BTA_AV_OPEN_RC, BTA_AV_OPEN_SST},
+    /* SRC_DATA_READY_EVT */ {BTA_AV_DATA_PATH, BTA_AV_SIGNORE,
+                              BTA_AV_OPEN_SST},
+    /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                                 BTA_AV_OPEN_SST},
+    /* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* STR_DISC_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* STR_GETCAP_OK_EVT */ {BTA_AV_SAVE_CAPS, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* STR_OPEN_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* STR_OPEN_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* STR_START_OK_EVT */ {BTA_AV_START_OK, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* STR_START_FAIL_EVT */ {BTA_AV_START_FAILED, BTA_AV_SIGNORE,
+                              BTA_AV_OPEN_SST},
+    /* STR_CLOSE_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE,
+                              BTA_AV_OPEN_SST},
+    /* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_IND, BTA_AV_SIGNORE,
+                                BTA_AV_OPEN_SST},
+    /* STR_SECURITY_CFM_EVT */ {BTA_AV_SECURITY_CFM, BTA_AV_SIGNORE,
+                                BTA_AV_OPEN_SST},
+    /* STR_WRITE_CFM_EVT */ {BTA_AV_CLR_CONG, BTA_AV_DATA_PATH,
+                             BTA_AV_OPEN_SST},
+    /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SUSPEND_CFM, BTA_AV_SIGNORE,
+                               BTA_AV_OPEN_SST},
+    /* 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},
+    /* 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},
+    /* ROLE_CHANGE_EVT*/ {BTA_AV_ROLE_RES, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* API_OFFLOAD_START_EVT */ {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE,
+                                 BTA_AV_OPEN_SST},
+    /* API_OFFLOAD_START_RSP_EVT */ {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE,
+                                     BTA_AV_OPEN_SST}};
+
+/* state table for reconfig state */
+static const uint8_t bta_av_sst_rcfg[][BTA_AV_NUM_COLS] = {
+    /* Event                     Action 1               Action 2 Next state */
+    /* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* AP_CLOSE_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE,
+                        BTA_AV_CLOSING_SST},
+    /* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* API_PROTECT_REQ_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* API_PROTECT_RSP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* API_RC_OPEN_EVT  */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                                 BTA_AV_RCFG_SST},
+    /* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* STR_DISC_OK_EVT */ {BTA_AV_DISC_RESULTS, BTA_AV_SIGNORE,
+                           BTA_AV_RCFG_SST},
+    /* STR_DISC_FAIL_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE,
+                             BTA_AV_INIT_SST},
+    /* STR_GETCAP_OK_EVT */ {BTA_AV_GETCAP_RESULTS, BTA_AV_SIGNORE,
+                             BTA_AV_RCFG_SST},
+    /* STR_GETCAP_FAIL_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE,
+                               BTA_AV_INIT_SST},
+    /* STR_OPEN_OK_EVT */ {BTA_AV_RCFG_STR_OK, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+    /* STR_OPEN_FAIL_EVT */ {BTA_AV_RCFG_FAILED, BTA_AV_SIGNORE,
+                             BTA_AV_RCFG_SST},
+    /* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* STR_CLOSE_EVT */ {BTA_AV_RCFG_CONNECT, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE,
+                              BTA_AV_RCFG_SST},
+    /* STR_SECURITY_IND_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                                BTA_AV_RCFG_SST},
+    /* STR_SECURITY_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                                BTA_AV_RCFG_SST},
+    /* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SUSPEND_CFM, BTA_AV_SUSPEND_CONT,
+                               BTA_AV_RCFG_SST},
+    /* STR_RECONFIG_CFM_EVT */ {BTA_AV_RCFG_CFM, BTA_AV_SIGNORE,
+                                BTA_AV_RCFG_SST},
+    /* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* AVDT_CONNECT_EVT */ {BTA_AV_RCFG_OPEN, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* AVDT_DISCONNECT_EVT */ {BTA_AV_RCFG_DISCNTD, BTA_AV_SIGNORE,
+                               BTA_AV_RCFG_SST},
+    /* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+    /* API_OFFLOAD_START_EVT */ {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE,
+                                 BTA_AV_RCFG_SST},
+    /* API_OFFLOAD_START_RSP_EVT */ {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE,
+                                     BTA_AV_RCFG_SST}};
+
+/* state table for closing state */
+static const uint8_t bta_av_sst_closing[][BTA_AV_NUM_COLS] = {
+    /* Event                     Action 1               Action 2 Next state */
+    /* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* AP_CLOSE_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE,
+                        BTA_AV_CLOSING_SST},
+    /* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* API_PROTECT_REQ_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                               BTA_AV_CLOSING_SST},
+    /* API_PROTECT_RSP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                               BTA_AV_CLOSING_SST},
+    /* API_RC_OPEN_EVT  */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                              BTA_AV_CLOSING_SST},
+    /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                               BTA_AV_CLOSING_SST},
+    /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                                 BTA_AV_CLOSING_SST},
+    /* SDP_DISC_OK_EVT */ {BTA_AV_SDP_FAILED, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+    /* SDP_DISC_FAIL_EVT */ {BTA_AV_SDP_FAILED, BTA_AV_SIGNORE,
+                             BTA_AV_INIT_SST},
+    /* STR_DISC_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                             BTA_AV_CLOSING_SST},
+    /* STR_GETCAP_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                             BTA_AV_CLOSING_SST},
+    /* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                               BTA_AV_CLOSING_SST},
+    /* STR_OPEN_OK_EVT */ {BTA_AV_DO_CLOSE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* STR_OPEN_FAIL_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE,
+                             BTA_AV_CLOSING_SST},
+    /* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                              BTA_AV_CLOSING_SST},
+    /* STR_CLOSE_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE,
+                         BTA_AV_CLOSING_SST},
+    /* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE,
+                              BTA_AV_CLOSING_SST},
+    /* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_REJ, BTA_AV_SIGNORE,
+                                BTA_AV_CLOSING_SST},
+    /* STR_SECURITY_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                                BTA_AV_CLOSING_SST},
+    /* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                             BTA_AV_CLOSING_SST},
+    /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                               BTA_AV_CLOSING_SST},
+    /* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                                BTA_AV_CLOSING_SST},
+    /* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* AVDT_DISCONNECT_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE,
+                               BTA_AV_INIT_SST},
+    /* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* AVDT_DELAY_RPT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+                              BTA_AV_CLOSING_SST},
+    /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+    /* API_OFFLOAD_START_EVT */ {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE,
+                                 BTA_AV_CLOSING_SST},
+    /* API_OFFLOAD_START_RSP_EVT */ {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE,
+                                     BTA_AV_CLOSING_SST}};
+
+/* type for state table */
+typedef const uint8_t (*tBTA_AV_SST_TBL)[BTA_AV_NUM_COLS];
+
+/* state table */
+static const tBTA_AV_SST_TBL bta_av_sst_tbl[] = {
+    bta_av_sst_init, bta_av_sst_incoming, bta_av_sst_opening,
+    bta_av_sst_open, bta_av_sst_rcfg,     bta_av_sst_closing};
+
+#if (BTA_AV_DEBUG == TRUE)
+static const char* bta_av_sst_code(uint8_t state);
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_av_is_rcfg_sst
+ *
+ * Description      Check if stream state machine is in reconfig state.
+ *
+ *
+ * Returns          true if stream state machine is in reconfig state.
+ *
+ ******************************************************************************/
+bool bta_av_is_rcfg_sst(tBTA_AV_SCB* p_scb) {
+  bool is_rcfg_sst = false;
+
+  if (p_scb != NULL) {
+    if (p_scb->state == BTA_AV_RCFG_SST) is_rcfg_sst = true;
+  }
+
+  return is_rcfg_sst;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_ssm_execute
+ *
+ * Description      Stream state machine event handling function for AV
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_ssm_execute(tBTA_AV_SCB* p_scb, uint16_t event,
+                        tBTA_AV_DATA* p_data) {
+  tBTA_AV_SST_TBL state_table;
+  uint8_t action;
+  int i, xx;
+
+  if (p_scb == NULL) {
+    /* this stream is not registered */
+    APPL_TRACE_EVENT("AV channel not registered");
+    return;
+  }
+
+  /* In case incoming connection is for VDP, we need to swap scb.        */
+  /* When ACP_CONNECT_EVT was received, we put first available scb to    */
+  /* to Incoming state. Later, when STR_CONFIG_IND_EVT is coming, we     */
+  /* know if it is A2DP or VDP.                                          */
+  if ((p_scb->state == BTA_AV_INIT_SST) &&
+      (event == BTA_AV_STR_CONFIG_IND_EVT)) {
+    for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) {
+      if (bta_av_cb.p_scb[xx]) {
+        if (bta_av_cb.p_scb[xx]->state == BTA_AV_INCOMING_SST) {
+          bta_av_cb.p_scb[xx]->state = BTA_AV_INIT_SST;
+          bta_av_cb.p_scb[xx]->coll_mask = 0;
+          p_scb->state = BTA_AV_INCOMING_SST;
+          break;
+        }
+      }
+    }
+  }
+
+#if (BTA_AV_DEBUG == TRUE)
+  APPL_TRACE_VERBOSE("AV Sevent(0x%x)=0x%x(%s) state=%d(%s)", p_scb->hndl,
+                     event, bta_av_evt_code(event), p_scb->state,
+                     bta_av_sst_code(p_scb->state));
+#else
+  APPL_TRACE_VERBOSE("AV Sevent=0x%x state=%d", event, p_scb->state);
+#endif
+
+  /* look up the state table for the current state */
+  state_table = bta_av_sst_tbl[p_scb->state];
+
+  event -= BTA_AV_FIRST_SSM_EVT;
+
+  /* set next state */
+  p_scb->state = state_table[event][BTA_AV_SNEXT_STATE];
+
+  /* execute action functions */
+  for (i = 0; i < BTA_AV_SACTIONS; i++) {
+    if ((action = state_table[event][i]) != BTA_AV_SIGNORE) {
+      (*p_scb->p_act_tbl[action])(p_scb, p_data);
+    } else
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_is_scb_opening
+ *
+ * Description      Returns true is scb is in opening state.
+ *
+ *
+ * Returns          true if scb is in opening state.
+ *
+ ******************************************************************************/
+bool bta_av_is_scb_opening(tBTA_AV_SCB* p_scb) {
+  bool is_opening = false;
+
+  if (p_scb) {
+    if (p_scb->state == BTA_AV_OPENING_SST) is_opening = true;
+  }
+
+  return is_opening;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_is_scb_incoming
+ *
+ * Description      Returns true is scb is in incoming state.
+ *
+ *
+ * Returns          true if scb is in incoming state.
+ *
+ ******************************************************************************/
+bool bta_av_is_scb_incoming(tBTA_AV_SCB* p_scb) {
+  bool is_incoming = false;
+
+  if (p_scb) {
+    if (p_scb->state == BTA_AV_INCOMING_SST) is_incoming = true;
+  }
+
+  return is_incoming;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_set_scb_sst_init
+ *
+ * Description      Set SST state to INIT.
+ *                  Use this function to change SST outside of state machine.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void bta_av_set_scb_sst_init(tBTA_AV_SCB* p_scb) {
+  if (p_scb) {
+    p_scb->state = BTA_AV_INIT_SST;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_is_scb_init
+ *
+ * Description      Returns true is scb is in init state.
+ *
+ *
+ * Returns          true if scb is in incoming state.
+ *
+ ******************************************************************************/
+bool bta_av_is_scb_init(tBTA_AV_SCB* p_scb) {
+  bool is_init = false;
+
+  if (p_scb) {
+    if (p_scb->state == BTA_AV_INIT_SST) is_init = true;
+  }
+
+  return is_init;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_av_set_scb_sst_incoming
+ *
+ * Description      Set SST state to incoming.
+ *                  Use this function to change SST outside of state machine.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void bta_av_set_scb_sst_incoming(tBTA_AV_SCB* p_scb) {
+  if (p_scb) {
+    p_scb->state = BTA_AV_INCOMING_SST;
+  }
+}
+
+/*****************************************************************************
+ *  Debug Functions
+ ****************************************************************************/
+#if (BTA_AV_DEBUG == TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_av_sst_code
+ *
+ * Description
+ *
+ * Returns          char *
+ *
+ ******************************************************************************/
+static const char* bta_av_sst_code(uint8_t state) {
+  switch (state) {
+    case BTA_AV_INIT_SST:
+      return "INIT";
+    case BTA_AV_INCOMING_SST:
+      return "INCOMING";
+    case BTA_AV_OPENING_SST:
+      return "OPENING";
+    case BTA_AV_OPEN_SST:
+      return "OPEN";
+    case BTA_AV_RCFG_SST:
+      return "RCFG";
+    case BTA_AV_CLOSING_SST:
+      return "CLOSING";
+    default:
+      return "unknown";
+  }
+}
+
+#endif
diff --git a/bt/bta/closure/bta_closure.cc b/bt/bta/closure/bta_closure.cc
new file mode 100644
index 0000000..19c0c3e
--- /dev/null
+++ b/bt/bta/closure/bta_closure.cc
@@ -0,0 +1,100 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "base/pending_task.h"
+#include "base/time/time.h"
+#include "bta_closure_int.h"
+#include "bta_sys.h"
+
+using base::PendingTask;
+using base::TaskQueue;
+using base::TimeTicks;
+
+namespace {
+
+enum {
+  /* these events are handled by the state machine */
+  BTA_CLOSURE_EXECUTE_EVT = BTA_SYS_EVT_START(BTA_ID_CLOSURE),
+};
+
+struct tBTA_CLOSURE_EXECUTE {
+  BT_HDR hdr;
+};
+
+static const tBTA_SYS_REG bta_closure_hw_reg = {bta_closure_execute, NULL};
+
+// The incoming queue receiving all posted tasks.
+TaskQueue task_queue;
+
+tBTA_SYS_SENDMSG bta_closure_sys_sendmsg = NULL;
+
+}  // namespace
+
+/* Accept bta_sys_register, and bta_sys_sendmsg. Those parameters can be used to
+ * override system methods for tests.
+ */
+void bta_closure_init(tBTA_SYS_REGISTER registerer, tBTA_SYS_SENDMSG sender) {
+  /* register closure message handler */
+  registerer(BTA_ID_CLOSURE, &bta_closure_hw_reg);
+  bta_closure_sys_sendmsg = sender;
+}
+
+bool bta_closure_execute(BT_HDR* p_msg) {
+  if (p_msg->event != BTA_CLOSURE_EXECUTE_EVT) {
+    APPL_TRACE_ERROR("%s: don't know how to execute event type %d", __func__,
+                     p_msg->event);
+    return false;
+  }
+
+  if (task_queue.empty()) {
+    APPL_TRACE_ERROR("%s: trying to execute event, but queue is empty.",
+                     __func__);
+    return false;
+  }
+
+  PendingTask pending_task = std::move(task_queue.front());
+  task_queue.pop();
+
+  APPL_TRACE_VERBOSE("%s: executing closure %s", __func__,
+                     pending_task.posted_from.ToString().c_str());
+
+  pending_task.task.Run();
+  return true;
+}
+
+/*
+ * This function posts a closure for execution on the btu_bta_msg_queue. Please
+ * see documentation at
+ * https://www.chromium.org/developers/coding-style/important-abstractions-and-data-structures
+ * for how to handle dynamic memory ownership/smart pointers with base::Owned(),
+ * base::Passed(), base::ConstRef() and others.
+ */
+void do_in_bta_thread(const tracked_objects::Location& from_here,
+                      const base::Closure& task) {
+  PendingTask pending_task(from_here, task, TimeTicks(), true);
+
+  task_queue.push(std::move(pending_task));
+
+  tBTA_CLOSURE_EXECUTE* p_msg =
+      (tBTA_CLOSURE_EXECUTE*)osi_malloc(sizeof(tBTA_CLOSURE_EXECUTE));
+
+  APPL_TRACE_API("%s", __func__);
+
+  p_msg->hdr.event = BTA_CLOSURE_EXECUTE_EVT;
+  bta_closure_sys_sendmsg(p_msg);
+}
diff --git a/bt/bta/closure/bta_closure_int.h b/bt/bta/closure/bta_closure_int.h
new file mode 100644
index 0000000..39aaab3
--- /dev/null
+++ b/bt/bta/closure/bta_closure_int.h
@@ -0,0 +1,42 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTA_CLOSURE_INT_H
+#define BTA_CLOSURE_INT_H
+
+#include <stdbool.h>
+
+#include "bta/sys/bta_sys.h"
+#include "bta_api.h"
+#include "include/bt_trace.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Accept bta_sys_register, and bta_sys_sendmsg. Those parameters can be used to
+ * override system methods for tests.
+ */
+void bta_closure_init(tBTA_SYS_REGISTER registerer, tBTA_SYS_SENDMSG sender);
+bool bta_closure_execute(BT_HDR* p_msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_CLOSURE_INT_H */
diff --git a/bt/bta/dm/bta_dm_act.cc b/bt/bta/dm/bta_dm_act.cc
new file mode 100644
index 0000000..b8357c8
--- /dev/null
+++ b/bt/bta/dm/bta_dm_act.cc
@@ -0,0 +1,5202 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2014 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 action functions for device manager state
+ *  machine.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bta_dm"
+
+#include <assert.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bta_api.h"
+#include "bta_dm_api.h"
+#include "bta_dm_co.h"
+#include "bta_dm_int.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "gap_api.h" /* For GAP_BleReadPeerPrefConnParams */
+#include "l2c_api.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "sdp_api.h"
+#include "utl.h"
+
+#if (GAP_INCLUDED == TRUE)
+#include "gap_api.h"
+#endif
+
+static void bta_dm_inq_results_cb(tBTM_INQ_RESULTS* p_inq, uint8_t* p_eir);
+static void bta_dm_inq_cmpl_cb(void* p_result);
+static void bta_dm_service_search_remname_cback(BD_ADDR bd_addr, DEV_CLASS dc,
+                                                BD_NAME bd_name);
+static void bta_dm_remname_cback(tBTM_REMOTE_DEV_NAME* p_remote_name);
+static void bta_dm_find_services(BD_ADDR bd_addr);
+static void bta_dm_discover_next_device(void);
+static void bta_dm_sdp_callback(uint16_t sdp_status);
+static uint8_t bta_dm_authorize_cback(BD_ADDR bd_addr, DEV_CLASS dev_class,
+                                      BD_NAME bd_name, uint8_t* service_name,
+                                      uint8_t service_id, bool is_originator);
+static uint8_t bta_dm_pin_cback(BD_ADDR bd_addr, DEV_CLASS dev_class,
+                                BD_NAME bd_name, bool min_16_digit);
+static uint8_t bta_dm_new_link_key_cback(BD_ADDR bd_addr, DEV_CLASS dev_class,
+                                         BD_NAME bd_name, LINK_KEY key,
+                                         uint8_t key_type);
+static uint8_t bta_dm_authentication_complete_cback(BD_ADDR bd_addr,
+                                                    DEV_CLASS dev_class,
+                                                    BD_NAME bd_name,
+                                                    int result);
+static void bta_dm_local_name_cback(BD_ADDR bd_addr);
+static bool bta_dm_check_av(uint16_t event);
+static void bta_dm_bl_change_cback(tBTM_BL_EVENT_DATA* p_data);
+
+static void bta_dm_policy_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
+                                uint8_t app_id, BD_ADDR peer_addr);
+
+/* Extended Inquiry Response */
+static uint8_t bta_dm_sp_cback(tBTM_SP_EVT event, tBTM_SP_EVT_DATA* p_data);
+
+static void bta_dm_set_eir(char* local_name);
+
+static void bta_dm_eir_search_services(tBTM_INQ_RESULTS* p_result,
+                                       tBTA_SERVICE_MASK* p_services_to_search,
+                                       tBTA_SERVICE_MASK* p_services_found);
+
+static void bta_dm_search_timer_cback(void* data);
+static void bta_dm_disable_conn_down_timer_cback(void* data);
+static void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
+                            uint8_t app_id, BD_ADDR peer_addr);
+static void bta_dm_adjust_roles(bool delay_role_switch);
+static char* bta_dm_get_remname(void);
+static void bta_dm_bond_cancel_complete_cback(tBTM_STATUS result);
+
+static bool bta_dm_read_remote_device_name(BD_ADDR bd_addr,
+                                           tBT_TRANSPORT transport);
+static void bta_dm_discover_device(BD_ADDR remote_bd_addr);
+
+static void bta_dm_sys_hw_cback(tBTA_SYS_HW_EVT status);
+static void bta_dm_disable_search_and_disc(void);
+
+#if (BLE_INCLUDED == TRUE)
+#if (SMP_INCLUDED == TRUE)
+static uint8_t bta_dm_ble_smp_cback(tBTM_LE_EVT event, BD_ADDR bda,
+                                    tBTM_LE_EVT_DATA* p_data);
+#endif
+static void bta_dm_ble_id_key_cback(uint8_t key_type,
+                                    tBTM_BLE_LOCAL_KEYS* p_key);
+#if (BTA_GATT_INCLUDED == TRUE)
+static void bta_dm_gattc_register(void);
+static void btm_dm_start_gatt_discovery(BD_ADDR bd_addr);
+static void bta_dm_cancel_gatt_discovery(BD_ADDR bd_addr);
+static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data);
+extern tBTA_DM_CONTRL_STATE bta_dm_pm_obtain_controller_state(void);
+#endif
+
+#if (BLE_VND_INCLUDED == TRUE)
+static void bta_dm_ctrl_features_rd_cmpl_cback(tBTM_STATUS result);
+#endif
+
+#ifndef BTA_DM_BLE_ADV_CHNL_MAP
+#define BTA_DM_BLE_ADV_CHNL_MAP \
+  (BTM_BLE_ADV_CHNL_37 | BTM_BLE_ADV_CHNL_38 | BTM_BLE_ADV_CHNL_39)
+#endif
+#endif
+
+/* Disable timer interval (in milliseconds) */
+#ifndef BTA_DM_DISABLE_TIMER_MS
+#define BTA_DM_DISABLE_TIMER_MS 5000
+#endif
+
+/* Disable timer retrial interval (in milliseconds) */
+#ifndef BTA_DM_DISABLE_TIMER_RETRIAL_MS
+#define BTA_DM_DISABLE_TIMER_RETRIAL_MS 1500
+#endif
+
+/* Disable connection down timer (in milliseconds) */
+#ifndef BTA_DM_DISABLE_CONN_DOWN_TIMER_MS
+#define BTA_DM_DISABLE_CONN_DOWN_TIMER_MS 1000
+#endif
+
+/* Switch delay timer (in milliseconds) */
+#ifndef BTA_DM_SWITCH_DELAY_TIMER_MS
+#define BTA_DM_SWITCH_DELAY_TIMER_MS 500
+#endif
+
+static void bta_dm_reset_sec_dev_pending(BD_ADDR remote_bd_addr);
+static void bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr);
+static void bta_dm_observe_results_cb(tBTM_INQ_RESULTS* p_inq, uint8_t* p_eir);
+static void bta_dm_observe_cmpl_cb(void* p_result);
+static void bta_dm_delay_role_switch_cback(void* data);
+static void bta_dm_disable_timer_cback(void* data);
+
+const uint16_t bta_service_id_to_uuid_lkup_tbl[BTA_MAX_SERVICE_ID] = {
+    UUID_SERVCLASS_PNP_INFORMATION,       /* Reserved */
+    UUID_SERVCLASS_SERIAL_PORT,           /* BTA_SPP_SERVICE_ID */
+    UUID_SERVCLASS_DIALUP_NETWORKING,     /* BTA_DUN_SERVICE_ID */
+    UUID_SERVCLASS_AUDIO_SOURCE,          /* BTA_A2DP_SOURCE_SERVICE_ID */
+    UUID_SERVCLASS_LAN_ACCESS_USING_PPP,  /* BTA_LAP_SERVICE_ID */
+    UUID_SERVCLASS_HEADSET,               /* BTA_HSP_HS_SERVICE_ID */
+    UUID_SERVCLASS_HF_HANDSFREE,          /* BTA_HFP_HS_SERVICE_ID */
+    UUID_SERVCLASS_OBEX_OBJECT_PUSH,      /* BTA_OPP_SERVICE_ID */
+    UUID_SERVCLASS_OBEX_FILE_TRANSFER,    /* BTA_FTP_SERVICE_ID */
+    UUID_SERVCLASS_CORDLESS_TELEPHONY,    /* BTA_CTP_SERVICE_ID */
+    UUID_SERVCLASS_INTERCOM,              /* BTA_ICP_SERVICE_ID */
+    UUID_SERVCLASS_IRMC_SYNC,             /* BTA_SYNC_SERVICE_ID */
+    UUID_SERVCLASS_DIRECT_PRINTING,       /* BTA_BPP_SERVICE_ID */
+    UUID_SERVCLASS_IMAGING_RESPONDER,     /* BTA_BIP_SERVICE_ID */
+    UUID_SERVCLASS_PANU,                  /* BTA_PANU_SERVICE_ID */
+    UUID_SERVCLASS_NAP,                   /* BTA_NAP_SERVICE_ID */
+    UUID_SERVCLASS_GN,                    /* BTA_GN_SERVICE_ID */
+    UUID_SERVCLASS_SAP,                   /* BTA_SAP_SERVICE_ID */
+    UUID_SERVCLASS_AUDIO_SINK,            /* BTA_A2DP_SERVICE_ID */
+    UUID_SERVCLASS_AV_REMOTE_CONTROL,     /* BTA_AVRCP_SERVICE_ID */
+    UUID_SERVCLASS_HUMAN_INTERFACE,       /* BTA_HID_SERVICE_ID */
+    UUID_SERVCLASS_VIDEO_SINK,            /* BTA_VDP_SERVICE_ID */
+    UUID_SERVCLASS_PBAP_PSE,              /* BTA_PBAP_SERVICE_ID */
+    UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY, /* BTA_HSP_SERVICE_ID */
+    UUID_SERVCLASS_AG_HANDSFREE,          /* BTA_HFP_SERVICE_ID */
+    UUID_SERVCLASS_MESSAGE_ACCESS,        /* BTA_MAP_SERVICE_ID */
+    UUID_SERVCLASS_MESSAGE_NOTIFICATION,  /* BTA_MN_SERVICE_ID */
+    UUID_SERVCLASS_HDP_PROFILE,           /* BTA_HDP_SERVICE_ID */
+    UUID_SERVCLASS_PBAP_PCE               /* BTA_PCE_SERVICE_ID */
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+    ,
+    UUID_PROTOCOL_ATT /* BTA_GATT_SERVICE_ID */
+#endif
+};
+
+/*
+ * NOTE : The number of element in bta_service_id_to_btm_srv_id_lkup_tbl should
+ * be matching with
+ *        the value BTA_MAX_SERVICE_ID in bta_api.h
+ *
+ *        i.e., If you add new Service ID for BTA, the correct security ID of
+ * the new service
+ *              from Security service definitions (btm_api.h) should be added to
+ * this lookup table.
+ */
+const uint32_t bta_service_id_to_btm_srv_id_lkup_tbl[BTA_MAX_SERVICE_ID] = {
+    0,                             /* Reserved */
+    BTM_SEC_SERVICE_SERIAL_PORT,   /* BTA_SPP_SERVICE_ID */
+    BTM_SEC_SERVICE_DUN,           /* BTA_DUN_SERVICE_ID */
+    BTM_SEC_SERVICE_AVDTP,         /* BTA_AUDIO_SOURCE_SERVICE_ID */
+    BTM_SEC_SERVICE_LAN_ACCESS,    /* BTA_LAP_SERVICE_ID */
+    BTM_SEC_SERVICE_HEADSET_AG,    /* BTA_HSP_SERVICE_ID */
+    BTM_SEC_SERVICE_AG_HANDSFREE,  /* BTA_HFP_SERVICE_ID */
+    BTM_SEC_SERVICE_OBEX,          /* BTA_OPP_SERVICE_ID */
+    BTM_SEC_SERVICE_OBEX_FTP,      /* BTA_FTP_SERVICE_ID */
+    BTM_SEC_SERVICE_CORDLESS,      /* BTA_CTP_SERVICE_ID */
+    BTM_SEC_SERVICE_INTERCOM,      /* BTA_ICP_SERVICE_ID */
+    BTM_SEC_SERVICE_IRMC_SYNC,     /* BTA_SYNC_SERVICE_ID */
+    BTM_SEC_SERVICE_BPP_JOB,       /* BTA_BPP_SERVICE_ID */
+    BTM_SEC_SERVICE_BIP,           /* BTA_BIP_SERVICE_ID */
+    BTM_SEC_SERVICE_BNEP_PANU,     /* BTA_PANU_SERVICE_ID */
+    BTM_SEC_SERVICE_BNEP_NAP,      /* BTA_NAP_SERVICE_ID */
+    BTM_SEC_SERVICE_BNEP_GN,       /* BTA_GN_SERVICE_ID */
+    BTM_SEC_SERVICE_SAP,           /* BTA_SAP_SERVICE_ID */
+    BTM_SEC_SERVICE_AVDTP,         /* BTA_A2DP_SERVICE_ID */
+    BTM_SEC_SERVICE_AVCTP,         /* BTA_AVRCP_SERVICE_ID */
+    BTM_SEC_SERVICE_HIDH_SEC_CTRL, /* BTA_HID_SERVICE_ID */
+    BTM_SEC_SERVICE_AVDTP,         /* BTA_VDP_SERVICE_ID */
+    BTM_SEC_SERVICE_PBAP,          /* BTA_PBAP_SERVICE_ID */
+    BTM_SEC_SERVICE_HEADSET,       /* BTA_HSP_HS_SERVICE_ID */
+    BTM_SEC_SERVICE_HF_HANDSFREE,  /* BTA_HFP_HS_SERVICE_ID */
+    BTM_SEC_SERVICE_MAP,           /* BTA_MAP_SERVICE_ID */
+    BTM_SEC_SERVICE_MAP,           /* BTA_MN_SERVICE_ID */
+    BTM_SEC_SERVICE_HDP_SNK,       /* BTA_HDP_SERVICE_ID */
+    BTM_SEC_SERVICE_PBAP           /* BTA_PCE_SERVICE_ID */
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+    ,
+    BTM_SEC_SERVICE_ATT /* BTA_GATT_SERVICE_ID */
+#endif
+
+};
+
+/* bta security callback */
+const tBTM_APPL_INFO bta_security = {
+    &bta_dm_authorize_cback, &bta_dm_pin_cback, &bta_dm_new_link_key_cback,
+    &bta_dm_authentication_complete_cback, &bta_dm_bond_cancel_complete_cback,
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+    &bta_dm_sp_cback
+#else
+    NULL
+#endif
+#if (BLE_INCLUDED == TRUE)
+#if (SMP_INCLUDED == TRUE)
+    ,
+    &bta_dm_ble_smp_cback
+#endif
+    ,
+    &bta_dm_ble_id_key_cback
+#endif
+
+};
+
+#define MAX_DISC_RAW_DATA_BUF (4096)
+uint8_t g_disc_raw_data_buf[MAX_DISC_RAW_DATA_BUF];
+
+extern DEV_CLASS local_device_default_class;
+extern fixed_queue_t* btu_bta_alarm_queue;
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_enable
+ *
+ * Description      Initialises the BT device manager
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_enable(tBTA_DM_MSG* p_data) {
+  tBTA_DM_ENABLE enable_event;
+
+  /* if already in use, return an error */
+  if (bta_dm_cb.is_bta_dm_active == true) {
+    APPL_TRACE_WARNING("%s Device already started by another application",
+                       __func__);
+    memset(&enable_event, 0, sizeof(tBTA_DM_ENABLE));
+    enable_event.status = BTA_FAILURE;
+    if (p_data->enable.p_sec_cback != NULL)
+      p_data->enable.p_sec_cback(BTA_DM_ENABLE_EVT,
+                                 (tBTA_DM_SEC*)&enable_event);
+    return;
+  }
+
+  /* first, register our callback to SYS HW manager */
+  bta_sys_hw_register(BTA_SYS_HW_BLUETOOTH, bta_dm_sys_hw_cback);
+
+  /* make sure security callback is saved - if no callback, do not erase the
+  previous one,
+  it could be an error recovery mechanism */
+  if (p_data->enable.p_sec_cback != NULL)
+    bta_dm_cb.p_sec_cback = p_data->enable.p_sec_cback;
+  /* notify BTA DM is now active */
+  bta_dm_cb.is_bta_dm_active = true;
+
+  /* send a message to BTA SYS */
+  tBTA_SYS_HW_MSG* sys_enable_event =
+      (tBTA_SYS_HW_MSG*)osi_malloc(sizeof(tBTA_SYS_HW_MSG));
+  sys_enable_event->hdr.event = BTA_SYS_API_ENABLE_EVT;
+  sys_enable_event->hw_module = BTA_SYS_HW_BLUETOOTH;
+
+  bta_sys_sendmsg(sys_enable_event);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_init_cb
+ *
+ * Description      Initializes the bta_dm_cb control block
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_init_cb(void) {
+  memset(&bta_dm_cb, 0, sizeof(bta_dm_cb));
+  bta_dm_cb.disable_timer = alarm_new("bta_dm.disable_timer");
+  bta_dm_cb.switch_delay_timer = alarm_new("bta_dm.switch_delay_timer");
+  for (size_t i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
+    for (size_t j = 0; j < BTA_DM_PM_MODE_TIMER_MAX; j++) {
+      bta_dm_cb.pm_timer[i].timer[j] = alarm_new("bta_dm.pm_timer");
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_deinit_cb
+ *
+ * Description      De-initializes the bta_dm_cb control block
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_deinit_cb(void) {
+  /*
+   * TODO: Should alarm_free() the bta_dm_cb timers during graceful
+   * shutdown.
+   */
+  alarm_free(bta_dm_cb.disable_timer);
+  alarm_free(bta_dm_cb.switch_delay_timer);
+  for (size_t i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
+    for (size_t j = 0; j < BTA_DM_PM_MODE_TIMER_MAX; j++) {
+      alarm_free(bta_dm_cb.pm_timer[i].timer[j]);
+    }
+  }
+  memset(&bta_dm_cb, 0, sizeof(bta_dm_cb));
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_sys_hw_cback
+ *
+ * Description     callback register to SYS to get HW status updates
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_sys_hw_cback(tBTA_SYS_HW_EVT status) {
+  DEV_CLASS dev_class;
+  tBTA_DM_SEC_CBACK* temp_cback;
+#if (BLE_INCLUDED == TRUE)
+  uint8_t key_mask = 0;
+  BT_OCTET16 er;
+  tBTA_BLE_LOCAL_ID_KEYS id_key;
+#endif
+
+  APPL_TRACE_DEBUG("%s with event: %i", __func__, status);
+
+  /* On H/W error evt, report to the registered DM application callback */
+  if (status == BTA_SYS_HW_ERROR_EVT) {
+    if (bta_dm_cb.p_sec_cback != NULL)
+      bta_dm_cb.p_sec_cback(BTA_DM_HW_ERROR_EVT, NULL);
+    return;
+  }
+
+  if (status == BTA_SYS_HW_OFF_EVT) {
+    if (bta_dm_cb.p_sec_cback != NULL)
+      bta_dm_cb.p_sec_cback(BTA_DM_DISABLE_EVT, NULL);
+
+    /* reinitialize the control block */
+    bta_dm_deinit_cb();
+
+    /* hw is ready, go on with BTA DM initialization */
+    alarm_free(bta_dm_search_cb.search_timer);
+    alarm_free(bta_dm_search_cb.gatt_close_timer);
+    memset(&bta_dm_search_cb, 0, sizeof(bta_dm_search_cb));
+
+    /* unregister from SYS */
+    bta_sys_hw_unregister(BTA_SYS_HW_BLUETOOTH);
+    /* notify BTA DM is now unactive */
+    bta_dm_cb.is_bta_dm_active = false;
+  } else if (status == BTA_SYS_HW_ON_EVT) {
+    /* FIXME: We should not unregister as the SYS shall invoke this callback on
+    * a H/W error.
+    * We need to revisit when this platform has more than one BLuetooth H/W chip
+    */
+    // bta_sys_hw_unregister( BTA_SYS_HW_BLUETOOTH);
+
+    /* save security callback */
+    temp_cback = bta_dm_cb.p_sec_cback;
+    /* make sure the control block is properly initialized */
+    bta_dm_init_cb();
+    /* and retrieve the callback */
+    bta_dm_cb.p_sec_cback = temp_cback;
+    bta_dm_cb.is_bta_dm_active = true;
+
+    /* hw is ready, go on with BTA DM initialization */
+    alarm_free(bta_dm_search_cb.search_timer);
+    alarm_free(bta_dm_search_cb.gatt_close_timer);
+    memset(&bta_dm_search_cb, 0, sizeof(bta_dm_search_cb));
+    /*
+     * TODO: Should alarm_free() the bta_dm_search_cb timers during
+     * graceful shutdown.
+     */
+    bta_dm_search_cb.search_timer = alarm_new("bta_dm_search.search_timer");
+    bta_dm_search_cb.gatt_close_timer =
+        alarm_new("bta_dm_search.gatt_close_timer");
+
+    memset(&bta_dm_conn_srvcs, 0, sizeof(bta_dm_conn_srvcs));
+    memset(&bta_dm_di_cb, 0, sizeof(tBTA_DM_DI_CB));
+
+    memcpy(dev_class, p_bta_dm_cfg->dev_class, sizeof(dev_class));
+    BTM_SetDeviceClass(dev_class);
+
+#if (BLE_INCLUDED == TRUE)
+    /* load BLE local information: ID keys, ER if available */
+    bta_dm_co_ble_load_local_keys(&key_mask, er, &id_key);
+
+    if (key_mask & BTA_BLE_LOCAL_KEY_TYPE_ER) {
+      BTM_BleLoadLocalKeys(BTA_BLE_LOCAL_KEY_TYPE_ER,
+                           (tBTM_BLE_LOCAL_KEYS*)&er);
+    }
+    if (key_mask & BTA_BLE_LOCAL_KEY_TYPE_ID) {
+      BTM_BleLoadLocalKeys(BTA_BLE_LOCAL_KEY_TYPE_ID,
+                           (tBTM_BLE_LOCAL_KEYS*)&id_key);
+    }
+#if (BTA_GATT_INCLUDED == TRUE)
+    bta_dm_search_cb.conn_id = BTA_GATT_INVALID_CONN_ID;
+#endif  // (defined(BTA_GATT_INCLUDED) && BTA_GATT_INCLUDED)
+#endif  // (defined(BLE_INCLUDED) && (BLE_INCLUDED == true))
+
+    BTM_SecRegister((tBTM_APPL_INFO*)&bta_security);
+    BTM_SetDefaultLinkSuperTout(p_bta_dm_cfg->link_timeout);
+    BTM_WritePageTimeout(p_bta_dm_cfg->page_timeout);
+    bta_dm_cb.cur_policy = p_bta_dm_cfg->policy_settings;
+    BTM_SetDefaultLinkPolicy(bta_dm_cb.cur_policy);
+    BTM_RegBusyLevelNotif(bta_dm_bl_change_cback, NULL,
+                          BTM_BL_UPDATE_MASK | BTM_BL_ROLE_CHG_MASK);
+
+#if (BLE_VND_INCLUDED == TRUE)
+    BTM_BleReadControllerFeatures(bta_dm_ctrl_features_rd_cmpl_cback);
+#endif
+
+    /* Earlier, we used to invoke BTM_ReadLocalAddr which was just copying the
+       bd_addr
+       from the control block and invoking the callback which was sending the
+       DM_ENABLE_EVT.
+       But then we have a few HCI commands being invoked above which were still
+       in progress
+       when the ENABLE_EVT was sent. So modified this to fetch the local name
+       which forces
+       the DM_ENABLE_EVT to be sent only after all the init steps are complete
+       */
+    BTM_ReadLocalDeviceNameFromController(
+        (tBTM_CMPL_CB*)bta_dm_local_name_cback);
+
+    bta_sys_rm_register((tBTA_SYS_CONN_CBACK*)bta_dm_rm_cback);
+
+    /* initialize bluetooth low power manager */
+    bta_dm_init_pm();
+
+    bta_sys_policy_register((tBTA_SYS_CONN_CBACK*)bta_dm_policy_cback);
+
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+    bta_dm_gattc_register();
+#endif
+
+  } else
+    APPL_TRACE_DEBUG(" --- ignored event");
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_disable
+ *
+ * Description      Disables the BT device manager
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_disable(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+  /* Set l2cap idle timeout to 0 (so BTE immediately disconnects ACL link after
+   * last channel is closed) */
+  L2CA_SetIdleTimeoutByBdAddr((uint8_t*)BT_BD_ANY, 0, BT_TRANSPORT_BR_EDR);
+  L2CA_SetIdleTimeoutByBdAddr((uint8_t*)BT_BD_ANY, 0, BT_TRANSPORT_LE);
+
+  /* disable all active subsystems */
+  bta_sys_disable(BTA_SYS_HW_BLUETOOTH);
+
+  BTM_SetDiscoverability(BTM_NON_DISCOVERABLE, 0, 0);
+  BTM_SetConnectability(BTM_NON_CONNECTABLE, 0, 0);
+
+  bta_dm_disable_pm();
+  bta_dm_disable_search_and_disc();
+  bta_dm_cb.disabling = true;
+
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+  BTM_BleClearBgConnDev();
+#endif
+
+  if (BTM_GetNumAclLinks() == 0) {
+#if (BTA_DISABLE_DELAY > 0)
+    /* If BTA_DISABLE_DELAY is defined and greater than zero, then delay the
+     * shutdown by
+     * BTA_DISABLE_DELAY milliseconds
+     */
+    APPL_TRACE_WARNING("%s BTA_DISABLE_DELAY set to %d ms", __func__,
+                       BTA_DISABLE_DELAY);
+    alarm_set_on_queue(bta_dm_cb.disable_timer, BTA_DISABLE_DELAY,
+                       bta_dm_disable_conn_down_timer_cback, NULL,
+                       btu_bta_alarm_queue);
+#else
+    bta_dm_disable_conn_down_timer_cback(NULL);
+#endif
+  } else {
+    alarm_set_on_queue(bta_dm_cb.disable_timer, BTA_DM_DISABLE_TIMER_MS,
+                       bta_dm_disable_timer_cback, UINT_TO_PTR(0),
+                       btu_bta_alarm_queue);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_disable_timer_cback
+ *
+ * Description      Called if the disable timer expires
+ *                  Used to close ACL connections which are still active
+ *
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_disable_timer_cback(void* data) {
+  uint8_t i;
+  tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+  bool trigger_disc = false;
+  uint32_t param = PTR_TO_UINT(data);
+
+  APPL_TRACE_EVENT("%s trial %u", __func__, param);
+
+  if (BTM_GetNumAclLinks() && (param == 0)) {
+    for (i = 0; i < bta_dm_cb.device_list.count; i++) {
+#if (BLE_INCLUDED == TRUE)
+      transport = bta_dm_cb.device_list.peer_device[i].transport;
+#endif
+      btm_remove_acl(bta_dm_cb.device_list.peer_device[i].peer_bdaddr,
+                     transport);
+      trigger_disc = true;
+    }
+
+    /* Retrigger disable timer in case ACL disconnect failed, DISABLE_EVT still
+       need
+        to be sent out to avoid jave layer disable timeout */
+    if (trigger_disc) {
+      alarm_set_on_queue(
+          bta_dm_cb.disable_timer, BTA_DM_DISABLE_TIMER_RETRIAL_MS,
+          bta_dm_disable_timer_cback, UINT_TO_PTR(1), btu_bta_alarm_queue);
+    }
+  } else {
+    bta_dm_cb.disabling = false;
+
+    bta_sys_remove_uuid(UUID_SERVCLASS_PNP_INFORMATION);
+    bta_dm_cb.p_sec_cback(BTA_DM_DISABLE_EVT, NULL);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_set_dev_name
+ *
+ * Description      Sets local device name
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_set_dev_name(tBTA_DM_MSG* p_data) {
+  BTM_SetLocalDeviceName((char*)p_data->set_name.name);
+  bta_dm_set_eir((char*)p_data->set_name.name);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_set_visibility
+ *
+ * Description      Sets discoverability, connectability and pairability
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_set_visibility(tBTA_DM_MSG* p_data) {
+  uint16_t window, interval;
+#if (BTA_GATT_INCLUDED == TRUE)
+  uint16_t le_disc_mode = BTM_BleReadDiscoverability();
+  uint16_t le_conn_mode = BTM_BleReadConnectability();
+#endif  // BTA_GATT_INCLUDED
+  uint16_t disc_mode = BTM_ReadDiscoverability(&window, &interval);
+  uint16_t conn_mode = BTM_ReadConnectability(&window, &interval);
+
+  /* set modes for Discoverability and connectability if not ignore */
+  if (p_data->set_visibility.disc_mode != (BTA_DM_IGNORE | BTA_DM_LE_IGNORE)) {
+#if (BTA_GATT_INCLUDED == TRUE)
+    if ((p_data->set_visibility.disc_mode & BTA_DM_LE_IGNORE) ==
+        BTA_DM_LE_IGNORE)
+      p_data->set_visibility.disc_mode =
+          ((p_data->set_visibility.disc_mode & ~BTA_DM_LE_IGNORE) |
+           le_disc_mode);
+#endif  // BTA_GATT_INCLUDED
+    if ((p_data->set_visibility.disc_mode & BTA_DM_IGNORE) == BTA_DM_IGNORE)
+      p_data->set_visibility.disc_mode =
+          ((p_data->set_visibility.disc_mode & ~BTA_DM_IGNORE) | disc_mode);
+
+    BTM_SetDiscoverability(p_data->set_visibility.disc_mode,
+                           bta_dm_cb.inquiry_scan_window,
+                           bta_dm_cb.inquiry_scan_interval);
+  }
+
+  if (p_data->set_visibility.conn_mode != (BTA_DM_IGNORE | BTA_DM_LE_IGNORE)) {
+#if (BTA_GATT_INCLUDED == TRUE)
+    if ((p_data->set_visibility.conn_mode & BTA_DM_LE_IGNORE) ==
+        BTA_DM_LE_IGNORE)
+      p_data->set_visibility.conn_mode =
+          ((p_data->set_visibility.conn_mode & ~BTA_DM_LE_IGNORE) |
+           le_conn_mode);
+#endif  // BTA_GATT_INCLUDED
+    if ((p_data->set_visibility.conn_mode & BTA_DM_IGNORE) == BTA_DM_IGNORE)
+      p_data->set_visibility.conn_mode =
+          ((p_data->set_visibility.conn_mode & ~BTA_DM_IGNORE) | conn_mode);
+
+    BTM_SetConnectability(p_data->set_visibility.conn_mode,
+                          bta_dm_cb.page_scan_window,
+                          bta_dm_cb.page_scan_interval);
+  }
+
+  /* Send False or True if not ignore */
+  if (p_data->set_visibility.pair_mode != BTA_DM_IGNORE) {
+    if (p_data->set_visibility.pair_mode == BTA_DM_NON_PAIRABLE)
+      bta_dm_cb.disable_pair_mode = true;
+    else
+      bta_dm_cb.disable_pair_mode = false;
+  }
+
+  /* Send False or True if not ignore */
+  if (p_data->set_visibility.conn_paired_only != BTA_DM_IGNORE) {
+    if (p_data->set_visibility.conn_paired_only == BTA_DM_CONN_ALL)
+      bta_dm_cb.conn_paired_only = false;
+    else
+      bta_dm_cb.conn_paired_only = true;
+  }
+
+  /* Change mode if either mode is not ignore */
+  if (p_data->set_visibility.pair_mode != BTA_DM_IGNORE ||
+      p_data->set_visibility.conn_paired_only != BTA_DM_IGNORE)
+    BTM_SetPairableMode((bool)(!(bta_dm_cb.disable_pair_mode)),
+                        bta_dm_cb.conn_paired_only);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_process_remove_device
+ *
+ * Description      Removes device, Disconnects ACL link if required.
+ ***
+ ******************************************************************************/
+void bta_dm_process_remove_device(BD_ADDR bd_addr) {
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+  /* need to remove all pending background connection before unpair */
+  BTA_GATTC_CancelOpen(0, bd_addr, false);
+#endif
+
+  BTM_SecDeleteDevice(bd_addr);
+
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+  /* remove all cached GATT information */
+  BTA_GATTC_Refresh(bd_addr);
+#endif
+
+  if (bta_dm_cb.p_sec_cback) {
+    tBTA_DM_SEC sec_event;
+    bdcpy(sec_event.link_down.bd_addr, bd_addr);
+    /* No connection, set status to success (acl disc code not valid) */
+    sec_event.link_down.status = HCI_SUCCESS;
+    bta_dm_cb.p_sec_cback(BTA_DM_DEV_UNPAIRED_EVT, &sec_event);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_remove_device
+ *
+ * Description      Removes device, disconnects ACL link if required.
+ ***
+ ******************************************************************************/
+void bta_dm_remove_device(tBTA_DM_MSG* p_data) {
+  tBTA_DM_API_REMOVE_DEVICE* p_dev = &p_data->remove_dev;
+  bool continue_delete_other_dev = false;
+  if (p_dev == NULL) return;
+
+  BD_ADDR other_address;
+  bdcpy(other_address, p_dev->bd_addr);
+
+  /* If ACL exists for the device in the remove_bond message*/
+  bool continue_delete_dev = false;
+  uint8_t other_transport = BT_TRANSPORT_INVALID;
+
+  if (BTM_IsAclConnectionUp(p_dev->bd_addr, BT_TRANSPORT_LE) ||
+      BTM_IsAclConnectionUp(p_dev->bd_addr, BT_TRANSPORT_BR_EDR)) {
+    APPL_TRACE_DEBUG("%s: ACL Up count  %d", __func__,
+                     bta_dm_cb.device_list.count);
+    continue_delete_dev = false;
+
+    /* Take the link down first, and mark the device for removal when
+     * disconnected */
+    for (int i = 0; i < bta_dm_cb.device_list.count; i++) {
+      if (!bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr,
+                 p_dev->bd_addr)) {
+        uint8_t transport = BT_TRANSPORT_BR_EDR;
+
+#if (BTA_GATT_INCLUDED == TRUE)
+        transport = bta_dm_cb.device_list.peer_device[i].transport;
+#endif  // BTA_GATT_INCLUDED
+        bta_dm_cb.device_list.peer_device[i].conn_state = BTA_DM_UNPAIRING;
+        btm_remove_acl(p_dev->bd_addr, transport);
+#if (BTA_GATT_INCLUDED == TRUE)
+        APPL_TRACE_DEBUG("%s:transport = %d", __func__,
+                         bta_dm_cb.device_list.peer_device[i].transport);
+
+        /* save the other transport to check if device is connected on
+         * other_transport */
+        if (bta_dm_cb.device_list.peer_device[i].transport == BT_TRANSPORT_LE)
+          other_transport = BT_TRANSPORT_BR_EDR;
+        else
+          other_transport = BT_TRANSPORT_LE;
+#endif  // BTA_GATT_INCLUDED
+
+        break;
+      }
+    }
+  } else {
+    continue_delete_dev = true;
+  }
+#if (BTA_GATT_INCLUDED == TRUE)
+  // If it is DUMO device and device is paired as different address, unpair that
+  // device
+  // if different address
+  if ((other_transport &&
+       (BTM_ReadConnectedTransportAddress(other_address, other_transport))) ||
+      (!other_transport &&
+       (BTM_ReadConnectedTransportAddress(other_address, BT_TRANSPORT_BR_EDR) ||
+        BTM_ReadConnectedTransportAddress(other_address, BT_TRANSPORT_LE)))) {
+    continue_delete_other_dev = false;
+    /* Take the link down first, and mark the device for removal when
+     * disconnected */
+    for (int i = 0; i < bta_dm_cb.device_list.count; i++) {
+      if (!bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr,
+                 other_address)) {
+        bta_dm_cb.device_list.peer_device[i].conn_state = BTA_DM_UNPAIRING;
+        btm_remove_acl(other_address,
+                       bta_dm_cb.device_list.peer_device[i].transport);
+        break;
+      }
+    }
+  } else {
+    APPL_TRACE_DEBUG("%s: continue to delete the other dev ", __func__);
+    continue_delete_other_dev = true;
+  }
+#endif  // BTA_GATT_INCLUDED
+  /* Delete the device mentioned in the msg */
+  if (continue_delete_dev) bta_dm_process_remove_device(p_dev->bd_addr);
+
+  /* Delete the other paired device too */
+  BD_ADDR dummy_bda = {0};
+  if (continue_delete_other_dev && (bdcmp(other_address, dummy_bda) != 0))
+    bta_dm_process_remove_device(other_address);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_add_device
+ *
+ * Description      This function adds a Link Key to an security database entry.
+ *                  It is normally called during host startup to restore all
+ *                  required information stored in the NVRAM.
+ ***
+ ******************************************************************************/
+void bta_dm_add_device(tBTA_DM_MSG* p_data) {
+  tBTA_DM_API_ADD_DEVICE* p_dev = &p_data->add_dev;
+  uint8_t* p_dc = NULL;
+  uint8_t* p_lc = NULL;
+  uint32_t trusted_services_mask[BTM_SEC_SERVICE_ARRAY_SIZE];
+  uint8_t index = 0;
+  uint8_t btm_mask_index = 0;
+
+  memset(trusted_services_mask, 0, sizeof(trusted_services_mask));
+
+  /* If not all zeros, the device class has been specified */
+  if (p_dev->dc_known) p_dc = (uint8_t*)p_dev->dc;
+
+  if (p_dev->link_key_known) p_lc = (uint8_t*)p_dev->link_key;
+
+  if (p_dev->is_trusted) {
+    /* covert BTA service mask to BTM mask */
+    while (p_dev->tm && (index < BTA_MAX_SERVICE_ID)) {
+      if (p_dev->tm & (uint32_t)(1 << index)) {
+        btm_mask_index =
+            bta_service_id_to_btm_srv_id_lkup_tbl[index] / BTM_SEC_ARRAY_BITS;
+        trusted_services_mask[btm_mask_index] |=
+            (uint32_t)(1 << (bta_service_id_to_btm_srv_id_lkup_tbl[index] -
+                             (uint32_t)(btm_mask_index * 32)));
+
+        p_dev->tm &= (uint32_t)(~(1 << index));
+      }
+      index++;
+    }
+  }
+
+  if (!BTM_SecAddDevice(p_dev->bd_addr, p_dc, p_dev->bd_name, p_dev->features,
+                        trusted_services_mask, p_lc, p_dev->key_type,
+                        p_dev->io_cap, p_dev->pin_length)) {
+    APPL_TRACE_ERROR("BTA_DM: Error adding device %08x%04x",
+                     (p_dev->bd_addr[0] << 24) + (p_dev->bd_addr[1] << 16) +
+                         (p_dev->bd_addr[2] << 8) + p_dev->bd_addr[3],
+                     (p_dev->bd_addr[4] << 8) + p_dev->bd_addr[5]);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_close_acl
+ *
+ * Description      This function forces to close the connection to a remote
+ *                  device and optionaly remove the device from security
+ *                  database if required.
+ ***
+ ******************************************************************************/
+void bta_dm_close_acl(tBTA_DM_MSG* p_data) {
+  tBTA_DM_API_REMOVE_ACL* p_remove_acl = &p_data->remove_acl;
+  uint8_t index;
+
+  APPL_TRACE_DEBUG("bta_dm_close_acl");
+
+  if (BTM_IsAclConnectionUp(p_remove_acl->bd_addr, p_remove_acl->transport)) {
+    for (index = 0; index < bta_dm_cb.device_list.count; index++) {
+      if (!bdcmp(bta_dm_cb.device_list.peer_device[index].peer_bdaddr,
+                 p_remove_acl->bd_addr))
+        break;
+    }
+    if (index != bta_dm_cb.device_list.count) {
+      if (p_remove_acl->remove_dev)
+        bta_dm_cb.device_list.peer_device[index].remove_dev_pending = true;
+    } else {
+      APPL_TRACE_ERROR("unknown device, remove ACL failed");
+    }
+    /* Disconnect the ACL link */
+    btm_remove_acl(p_remove_acl->bd_addr, p_remove_acl->transport);
+  }
+  /* if to remove the device from security database ? do it now */
+  else if (p_remove_acl->remove_dev) {
+    if (!BTM_SecDeleteDevice(p_remove_acl->bd_addr)) {
+      APPL_TRACE_ERROR("delete device from security database failed.");
+    }
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+    /* need to remove all pending background connection if any */
+    BTA_GATTC_CancelOpen(0, p_remove_acl->bd_addr, false);
+    /* remove all cached GATT information */
+    BTA_GATTC_Refresh(p_remove_acl->bd_addr);
+#endif
+  }
+  /* otherwise, no action needed */
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_remove_all_acl
+ *
+ * Description      This function forces to close all the ACL links specified by
+ *                  link type
+ ***
+ ******************************************************************************/
+void bta_dm_remove_all_acl(tBTA_DM_MSG* p_data) {
+  const tBTA_DM_LINK_TYPE link_type = p_data->remove_all_acl.link_type;
+  tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+
+  APPL_TRACE_DEBUG("%s link type = %d", __func__, link_type);
+
+  for (uint8_t i = 0; i < bta_dm_cb.device_list.count; i++) {
+    BD_ADDR addr = {0};
+    bdcpy(addr, bta_dm_cb.device_list.peer_device[i].peer_bdaddr);
+#if (BLE_INCLUDED == TRUE)
+    transport = bta_dm_cb.device_list.peer_device[i].transport;
+#endif
+    if ((link_type == BTA_DM_LINK_TYPE_ALL) ||
+        ((link_type == BTA_DM_LINK_TYPE_LE) &&
+         (transport == BT_TRANSPORT_LE)) ||
+        ((link_type == BTA_DM_LINK_TYPE_BR_EDR) &&
+         (transport == BT_TRANSPORT_BR_EDR))) {
+      /* Disconnect the ACL link */
+      btm_remove_acl(addr, transport);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_bond
+ *
+ * Description      Bonds with peer device
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_bond(tBTA_DM_MSG* p_data) {
+  tBTM_STATUS status;
+  tBTA_DM_SEC sec_event;
+  char* p_name;
+
+  if (p_data->bond.transport == BTA_TRANSPORT_UNKNOWN)
+    status = BTM_SecBond(p_data->bond.bd_addr, 0, NULL, 0);
+  else
+    status = BTM_SecBondByTransport(p_data->bond.bd_addr,
+                                    p_data->bond.transport, 0, NULL, 0);
+
+  if (bta_dm_cb.p_sec_cback && (status != BTM_CMD_STARTED)) {
+    memset(&sec_event, 0, sizeof(tBTA_DM_SEC));
+    bdcpy(sec_event.auth_cmpl.bd_addr, p_data->bond.bd_addr);
+    p_name = BTM_SecReadDevName(p_data->bond.bd_addr);
+    if (p_name != NULL) {
+      memcpy(sec_event.auth_cmpl.bd_name, p_name, (BD_NAME_LEN - 1));
+      sec_event.auth_cmpl.bd_name[BD_NAME_LEN - 1] = 0;
+    }
+
+    /*      taken care of by memset [above]
+            sec_event.auth_cmpl.key_present = false;
+            sec_event.auth_cmpl.success = false;
+    */
+    sec_event.auth_cmpl.fail_reason = HCI_ERR_ILLEGAL_COMMAND;
+    if (status == BTM_SUCCESS) {
+      sec_event.auth_cmpl.success = true;
+    } else {
+      /* delete this device entry from Sec Dev DB */
+      bta_dm_remove_sec_dev_entry(p_data->bond.bd_addr);
+    }
+    bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_bond_cancel
+ *
+ * Description      Cancels bonding with a peer device
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_bond_cancel(tBTA_DM_MSG* p_data) {
+  tBTM_STATUS status;
+  tBTA_DM_SEC sec_event;
+
+  APPL_TRACE_EVENT(" bta_dm_bond_cancel ");
+  status = BTM_SecBondCancel(p_data->bond_cancel.bd_addr);
+
+  if (bta_dm_cb.p_sec_cback &&
+      (status != BTM_CMD_STARTED && status != BTM_SUCCESS)) {
+    sec_event.bond_cancel_cmpl.result = BTA_FAILURE;
+
+    bta_dm_cb.p_sec_cback(BTA_DM_BOND_CANCEL_CMPL_EVT, &sec_event);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_pin_reply
+ *
+ * Description      Send the pin_reply to a request from BTM
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_pin_reply(tBTA_DM_MSG* p_data) {
+  uint32_t trusted_mask[BTM_SEC_SERVICE_ARRAY_SIZE];
+  uint32_t* current_trusted_mask;
+
+  current_trusted_mask = BTM_ReadTrustedMask(p_data->pin_reply.bd_addr);
+
+  if (current_trusted_mask) {
+    memcpy(trusted_mask, current_trusted_mask, sizeof(trusted_mask));
+  } else {
+    memset(trusted_mask, 0, sizeof(trusted_mask));
+  }
+
+  if (p_data->pin_reply.accept) {
+    BTM_PINCodeReply(p_data->pin_reply.bd_addr, BTM_SUCCESS,
+                     p_data->pin_reply.pin_len, p_data->pin_reply.p_pin,
+                     trusted_mask);
+  } else {
+    BTM_PINCodeReply(p_data->pin_reply.bd_addr, BTM_NOT_AUTHORIZED, 0, NULL,
+                     trusted_mask);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_policy_cback
+ *
+ * Description      process the link policy changes
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_policy_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
+                                uint8_t app_id, BD_ADDR peer_addr) {
+  tBTA_DM_PEER_DEVICE* p_dev = NULL;
+  uint16_t policy = app_id;
+  uint32_t mask = (uint32_t)(1 << id);
+
+  if (peer_addr) p_dev = bta_dm_find_peer_device(peer_addr);
+
+  APPL_TRACE_DEBUG(" bta_dm_policy_cback cmd:%d, policy:0x%x", status, policy);
+  switch (status) {
+    case BTA_SYS_PLCY_SET:
+      if (!p_dev) return;
+      /* restore the default link policy */
+      p_dev->link_policy |= policy;
+      BTM_SetLinkPolicy(p_dev->peer_bdaddr, &(p_dev->link_policy));
+      break;
+
+    case BTA_SYS_PLCY_CLR:
+      if (!p_dev) return;
+      /* clear the policy from the default link policy */
+      p_dev->link_policy &= (~policy);
+      BTM_SetLinkPolicy(p_dev->peer_bdaddr, &(p_dev->link_policy));
+
+      if (policy & (HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_PARK_MODE)) {
+        /* if clearing sniff/park, wake the link */
+        bta_dm_pm_active(p_dev->peer_bdaddr);
+      }
+      break;
+
+    case BTA_SYS_PLCY_DEF_SET:
+      /* want to restore/set the role switch policy */
+      bta_dm_cb.role_policy_mask &= ~mask;
+      if (0 == bta_dm_cb.role_policy_mask) {
+        /* if nobody wants to insist on the role */
+        bta_dm_cb.cur_policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+        BTM_SetDefaultLinkPolicy(bta_dm_cb.cur_policy);
+      }
+      break;
+
+    case BTA_SYS_PLCY_DEF_CLR:
+      /* want to remove the role switch policy */
+      bta_dm_cb.role_policy_mask |= mask;
+      bta_dm_cb.cur_policy &= ~HCI_ENABLE_MASTER_SLAVE_SWITCH;
+      BTM_SetDefaultLinkPolicy(bta_dm_cb.cur_policy);
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_confirm
+ *
+ * Description      Send the user confirm request reply in response to a
+ *                  request from BTM
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_confirm(tBTA_DM_MSG* p_data) {
+  tBTM_STATUS res = BTM_NOT_AUTHORIZED;
+
+  if (p_data->confirm.accept == true) res = BTM_SUCCESS;
+  BTM_ConfirmReqReply(res, p_data->confirm.bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_loc_oob
+ *
+ * Description      Retrieve the OOB data from the local LM
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_loc_oob(UNUSED_ATTR tBTA_DM_MSG* p_data) { BTM_ReadLocalOobData(); }
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_ci_io_req_act
+ *
+ * Description      respond to the IO capabilities request from BTM
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_ci_io_req_act(tBTA_DM_MSG* p_data) {
+  tBTM_AUTH_REQ auth_req = BTM_AUTH_AP_NO;
+  if (p_data->ci_io_req.auth_req) auth_req = BTM_AUTH_AP_YES;
+  BTM_IoCapRsp(p_data->ci_io_req.bd_addr, p_data->ci_io_req.io_cap,
+               p_data->ci_io_req.oob_data, auth_req);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_ci_rmt_oob_act
+ *
+ * Description      respond to the OOB data request for the remote device from
+ *                  BTM
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_ci_rmt_oob_act(tBTA_DM_MSG* p_data) {
+  tBTM_STATUS res = BTM_NOT_AUTHORIZED;
+
+  if (p_data->ci_rmt_oob.accept == true) res = BTM_SUCCESS;
+  BTM_RemoteOobDataReply(res, p_data->ci_rmt_oob.bd_addr, p_data->ci_rmt_oob.c,
+                         p_data->ci_rmt_oob.r);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_search_start
+ *
+ * Description      Starts an inquiry
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_search_start(tBTA_DM_MSG* p_data) {
+  tBTM_INQUIRY_CMPL result;
+
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+  size_t len = sizeof(tBT_UUID) * p_data->search.num_uuid;
+  bta_dm_gattc_register();
+#endif
+
+  APPL_TRACE_DEBUG("%s avoid_scatter=%d", __func__,
+                   p_bta_dm_cfg->avoid_scatter);
+
+  if (p_bta_dm_cfg->avoid_scatter &&
+      (p_data->search.rs_res == BTA_DM_RS_NONE) &&
+      bta_dm_check_av(BTA_DM_API_SEARCH_EVT)) {
+    memcpy(&bta_dm_cb.search_msg, &p_data->search, sizeof(tBTA_DM_API_SEARCH));
+    return;
+  }
+
+  BTM_ClearInqDb(NULL);
+  /* save search params */
+  bta_dm_search_cb.p_search_cback = p_data->search.p_cback;
+  bta_dm_search_cb.services = p_data->search.services;
+
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+  osi_free_and_reset((void**)&bta_dm_search_cb.p_srvc_uuid);
+
+  if ((bta_dm_search_cb.num_uuid = p_data->search.num_uuid) != 0 &&
+      p_data->search.p_uuid != NULL) {
+    bta_dm_search_cb.p_srvc_uuid = (tBT_UUID*)osi_malloc(len);
+    memcpy(bta_dm_search_cb.p_srvc_uuid, p_data->search.p_uuid, len);
+  }
+#endif
+  result.status = BTM_StartInquiry((tBTM_INQ_PARMS*)&p_data->search.inq_params,
+                                   bta_dm_inq_results_cb,
+                                   (tBTM_CMPL_CB*)bta_dm_inq_cmpl_cb);
+
+  APPL_TRACE_EVENT("%s status=%d", __func__, result.status);
+  if (result.status != BTM_CMD_STARTED) {
+    result.num_resp = 0;
+    bta_dm_inq_cmpl_cb((void*)&result);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_search_cancel
+ *
+ * Description      Cancels an ongoing search for devices
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_search_cancel(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+  tBTA_DM_MSG* p_msg;
+
+  if (BTM_IsInquiryActive()) {
+    if (BTM_CancelInquiry() == BTM_SUCCESS) {
+      bta_dm_search_cancel_notify(NULL);
+      p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+      p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+      p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
+      bta_sys_sendmsg(p_msg);
+    } else {
+      /* flag a search cancel is pending */
+      bta_dm_search_cb.cancel_pending = true;
+    }
+  }
+  /* If no Service Search going on then issue cancel remote name in case it is
+     active */
+  else if (!bta_dm_search_cb.name_discover_done) {
+    BTM_CancelRemoteDeviceName();
+
+    p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+    p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+    p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
+    bta_sys_sendmsg(p_msg);
+  } else {
+    p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+    p_msg->hdr.event = BTA_DM_INQUIRY_CMPL_EVT;
+    p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
+    bta_sys_sendmsg(p_msg);
+  }
+
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+  if (bta_dm_search_cb.gatt_disc_active) {
+    bta_dm_cancel_gatt_discovery(bta_dm_search_cb.peer_bdaddr);
+  }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_discover
+ *
+ * Description      Discovers services on a remote device
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_discover(tBTA_DM_MSG* p_data) {
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+  size_t len = sizeof(tBT_UUID) * p_data->discover.num_uuid;
+#endif
+  APPL_TRACE_EVENT("%s services_to_search=0x%04X, sdp_search=%d", __func__,
+                   p_data->discover.services, p_data->discover.sdp_search);
+
+  /* save the search condition */
+  bta_dm_search_cb.services = p_data->discover.services;
+
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+  bta_dm_gattc_register();
+  osi_free_and_reset((void**)&bta_dm_search_cb.p_srvc_uuid);
+  if ((bta_dm_search_cb.num_uuid = p_data->discover.num_uuid) != 0 &&
+      p_data->discover.p_uuid != NULL) {
+    bta_dm_search_cb.p_srvc_uuid = (tBT_UUID*)osi_malloc(len);
+    memcpy(bta_dm_search_cb.p_srvc_uuid, p_data->discover.p_uuid, len);
+  }
+  bta_dm_search_cb.uuid_to_search = bta_dm_search_cb.num_uuid;
+#endif
+
+  bta_dm_search_cb.p_search_cback = p_data->discover.p_cback;
+  bta_dm_search_cb.sdp_search = p_data->discover.sdp_search;
+  bta_dm_search_cb.services_to_search = bta_dm_search_cb.services;
+  bta_dm_search_cb.service_index = 0;
+  bta_dm_search_cb.services_found = 0;
+  bta_dm_search_cb.peer_name[0] = 0;
+  bta_dm_search_cb.sdp_search = p_data->discover.sdp_search;
+  bta_dm_search_cb.p_btm_inq_info = BTM_InqDbRead(p_data->discover.bd_addr);
+  bta_dm_search_cb.transport = p_data->discover.transport;
+
+  bta_dm_search_cb.name_discover_done = false;
+  memcpy(&bta_dm_search_cb.uuid, &p_data->discover.uuid, sizeof(tSDP_UUID));
+  bta_dm_discover_device(p_data->discover.bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_di_disc_cmpl
+ *
+ * Description      Sends event to application when DI discovery complete
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_di_disc_cmpl(tBTA_DM_MSG* p_data) {
+  tBTA_DM_DI_DISC_CMPL di_disc;
+
+  memset(&di_disc, 0, sizeof(tBTA_DM_DI_DISC_CMPL));
+  bdcpy(di_disc.bd_addr, bta_dm_search_cb.peer_bdaddr);
+
+  if ((p_data->hdr.offset == SDP_SUCCESS) ||
+      (p_data->hdr.offset == SDP_DB_FULL)) {
+    di_disc.num_record = SDP_GetNumDiRecords(bta_dm_di_cb.p_di_db);
+  } else
+    di_disc.result = BTA_FAILURE;
+
+  bta_dm_di_cb.p_di_db = NULL;
+  bta_dm_search_cb.p_search_cback(BTA_DM_DI_DISC_CMPL_EVT,
+                                  (tBTA_DM_SEARCH*)&di_disc);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_di_disc_callback
+ *
+ * Description      This function queries a remote device for DI information.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_di_disc_callback(uint16_t result) {
+  tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+
+  p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+  p_msg->hdr.layer_specific = BTA_DM_API_DI_DISCOVER_EVT;
+  p_msg->hdr.offset = result;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_disable_search_and_disc
+ *
+ * Description      Cancels an ongoing search or discovery for devices in case
+ *                  of a Bluetooth disable
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_disable_search_and_disc(void) {
+  tBTA_DM_DI_DISC_CMPL di_disc;
+
+  if (bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE) bta_dm_search_cancel(NULL);
+
+  if (bta_dm_di_cb.p_di_db != NULL) {
+    memset(&di_disc, 0, sizeof(tBTA_DM_DI_DISC_CMPL));
+    bdcpy(di_disc.bd_addr, bta_dm_search_cb.peer_bdaddr);
+    di_disc.result = BTA_FAILURE;
+
+    bta_dm_di_cb.p_di_db = NULL;
+    bta_dm_search_cb.p_search_cback(BTA_DM_DI_DISC_CMPL_EVT, NULL);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_di_disc
+ *
+ * Description      This function queries a remote device for DI information.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_di_disc(tBTA_DM_MSG* p_data) {
+  uint16_t result = BTA_FAILURE;
+
+  bta_dm_search_cb.p_search_cback = p_data->di_disc.p_cback;
+  bdcpy(bta_dm_search_cb.peer_bdaddr, p_data->di_disc.bd_addr);
+  bta_dm_di_cb.p_di_db = p_data->di_disc.p_sdp_db;
+
+  bta_dm_search_cb.p_sdp_db =
+      (tSDP_DISCOVERY_DB*)osi_malloc(BTA_DM_SDP_DB_SIZE);
+  if (SDP_DiDiscover(bta_dm_search_cb.peer_bdaddr, p_data->di_disc.p_sdp_db,
+                     p_data->di_disc.len,
+                     bta_dm_di_disc_callback) == SDP_SUCCESS) {
+    result = BTA_SUCCESS;
+  }
+
+  if (result == BTA_FAILURE) {
+    tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+
+    p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+    p_msg->hdr.layer_specific = BTA_DM_API_DI_DISCOVER_EVT;
+    p_data->hdr.offset = result;
+    bta_sys_sendmsg(p_msg);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_read_remote_device_name
+ *
+ * Description      Initiate to get remote device name
+ *
+ * Returns          true if started to get remote name
+ *
+ ******************************************************************************/
+static bool bta_dm_read_remote_device_name(BD_ADDR bd_addr,
+                                           tBT_TRANSPORT transport) {
+  tBTM_STATUS btm_status;
+
+  APPL_TRACE_DEBUG("bta_dm_read_remote_device_name");
+
+  bdcpy(bta_dm_search_cb.peer_bdaddr, bd_addr);
+  bta_dm_search_cb.peer_name[0] = 0;
+
+  btm_status =
+      BTM_ReadRemoteDeviceName(bta_dm_search_cb.peer_bdaddr,
+                               (tBTM_CMPL_CB*)bta_dm_remname_cback, transport);
+
+  if (btm_status == BTM_CMD_STARTED) {
+    APPL_TRACE_DEBUG(
+        "bta_dm_read_remote_device_name: BTM_ReadRemoteDeviceName is started");
+
+    return (true);
+  } else if (btm_status == BTM_BUSY) {
+    APPL_TRACE_DEBUG(
+        "bta_dm_read_remote_device_name: BTM_ReadRemoteDeviceName is busy");
+
+    /* Remote name discovery is on going now so BTM cannot notify through
+     * "bta_dm_remname_cback" */
+    /* adding callback to get notified that current reading remore name done */
+    BTM_SecAddRmtNameNotifyCallback(&bta_dm_service_search_remname_cback);
+
+    return (true);
+  } else {
+    APPL_TRACE_WARNING(
+        "bta_dm_read_remote_device_name: BTM_ReadRemoteDeviceName returns "
+        "0x%02X",
+        btm_status);
+
+    return (false);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_inq_cmpl
+ *
+ * Description      Process the inquiry complete event from BTM
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_inq_cmpl(tBTA_DM_MSG* p_data) {
+  tBTA_DM_SEARCH data;
+
+  APPL_TRACE_DEBUG("bta_dm_inq_cmpl");
+
+  data.inq_cmpl.num_resps = p_data->inq_cmpl.num;
+  bta_dm_search_cb.p_search_cback(BTA_DM_INQ_CMPL_EVT, &data);
+
+  if ((bta_dm_search_cb.p_btm_inq_info = BTM_InqDbFirst()) != NULL) {
+    /* start name and service discovery from the first device on inquiry result
+     */
+    bta_dm_search_cb.name_discover_done = false;
+    bta_dm_search_cb.peer_name[0] = 0;
+    bta_dm_discover_device(
+        bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr);
+  } else {
+    tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+
+    /* no devices, search complete */
+    bta_dm_search_cb.services = 0;
+
+    p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+    p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
+    bta_sys_sendmsg(p_msg);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_rmt_name
+ *
+ * Description      Process the remote name result from BTM
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_rmt_name(tBTA_DM_MSG* p_data) {
+  APPL_TRACE_DEBUG("bta_dm_rmt_name");
+
+  if (p_data->rem_name.result.disc_res.bd_name[0] &&
+      bta_dm_search_cb.p_btm_inq_info) {
+    bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name = true;
+  }
+
+  bta_dm_discover_device(bta_dm_search_cb.peer_bdaddr);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_disc_rmt_name
+ *
+ * Description      Process the remote name result from BTM when application
+ *                  wants to find the name for a bdaddr
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_disc_rmt_name(tBTA_DM_MSG* p_data) {
+  tBTM_INQ_INFO* p_btm_inq_info;
+
+  APPL_TRACE_DEBUG("bta_dm_disc_rmt_name");
+
+  p_btm_inq_info = BTM_InqDbRead(p_data->rem_name.result.disc_res.bd_addr);
+  if (p_btm_inq_info) {
+    if (p_data->rem_name.result.disc_res.bd_name[0]) {
+      p_btm_inq_info->appl_knows_rem_name = true;
+    }
+  }
+
+  bta_dm_discover_device(p_data->rem_name.result.disc_res.bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_sdp_result
+ *
+ * Description      Process the discovery result from sdp
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_sdp_result(tBTA_DM_MSG* p_data) {
+  tSDP_DISC_REC* p_sdp_rec = NULL;
+  tBTA_DM_MSG* p_msg;
+  bool scn_found = false;
+  uint16_t service = 0xFFFF;
+  tSDP_PROTOCOL_ELEM pe;
+
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+  tBT_UUID* p_uuid = bta_dm_search_cb.p_srvc_uuid;
+  tBTA_DM_SEARCH result;
+  tBT_UUID service_uuid;
+#endif
+
+  uint32_t num_uuids = 0;
+  uint8_t uuid_list[32][MAX_UUID_SIZE];  // assuming a max of 32 services
+
+  if ((p_data->sdp_event.sdp_result == SDP_SUCCESS) ||
+      (p_data->sdp_event.sdp_result == SDP_NO_RECS_MATCH) ||
+      (p_data->sdp_event.sdp_result == SDP_DB_FULL)) {
+    APPL_TRACE_DEBUG("sdp_result::0x%x", p_data->sdp_event.sdp_result);
+    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 (p_sdp_rec && SDP_FindProtocolListElemInRec(
+                             p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+          bta_dm_search_cb.peer_scn = (uint8_t)pe.params[0];
+          scn_found = true;
+        }
+      } else {
+        service =
+            bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index - 1];
+        p_sdp_rec =
+            SDP_FindServiceInDb(bta_dm_search_cb.p_sdp_db, service, p_sdp_rec);
+      }
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+      /* finished with BR/EDR services, now we check the result for GATT based
+       * service UUID */
+      if (bta_dm_search_cb.service_index == BTA_MAX_SERVICE_ID) {
+        if (bta_dm_search_cb.uuid_to_search != 0 && p_uuid != NULL) {
+          p_uuid +=
+              (bta_dm_search_cb.num_uuid - bta_dm_search_cb.uuid_to_search);
+          /* only support 16 bits UUID for now */
+          service = p_uuid->uu.uuid16;
+        }
+        /* all GATT based services */
+        do {
+          /* find a service record, report it */
+          p_sdp_rec =
+              SDP_FindServiceInDb(bta_dm_search_cb.p_sdp_db, 0, p_sdp_rec);
+          if (p_sdp_rec) {
+            if (SDP_FindServiceUUIDInRec(p_sdp_rec, &service_uuid)) {
+              /* send result back to app now, one by one */
+              bdcpy(result.disc_ble_res.bd_addr, bta_dm_search_cb.peer_bdaddr);
+              strlcpy((char*)result.disc_ble_res.bd_name, bta_dm_get_remname(),
+                      BD_NAME_LEN);
+              result.disc_ble_res.service.len = service_uuid.len;
+              result.disc_ble_res.service.uu.uuid16 = service_uuid.uu.uuid16;
+
+              bta_dm_search_cb.p_search_cback(BTA_DM_DISC_BLE_RES_EVT, &result);
+            }
+          }
+
+          if (bta_dm_search_cb.uuid_to_search > 0) break;
+
+        } while (p_sdp_rec);
+      } else
+#endif
+      {
+        /* SDP_DB_FULL means some records with the
+           required attributes were received */
+        if (((p_data->sdp_event.sdp_result == SDP_DB_FULL) &&
+             bta_dm_search_cb.services != BTA_ALL_SERVICE_MASK) ||
+            (p_sdp_rec != NULL)) {
+          if (service != UUID_SERVCLASS_PNP_INFORMATION) {
+            uint16_t tmp_svc = 0xFFFF;
+            bta_dm_search_cb.services_found |=
+                (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(
+                    bta_dm_search_cb.service_index - 1));
+            tmp_svc =
+                bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index -
+                                                1];
+            /* Add to the list of UUIDs */
+            sdpu_uuid16_to_uuid128(tmp_svc, uuid_list[num_uuids]);
+            num_uuids++;
+          }
+        }
+      }
+
+      if (bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK &&
+          bta_dm_search_cb.services_to_search == 0) {
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+        if (bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID &&
+            bta_dm_search_cb.uuid_to_search > 0)
+          bta_dm_search_cb.uuid_to_search--;
+
+        if (bta_dm_search_cb.uuid_to_search == 0 ||
+            bta_dm_search_cb.service_index != BTA_BLE_SERVICE_ID)
+#endif
+          bta_dm_search_cb.service_index++;
+      } else /* regular one service per search or PNP search */
+        break;
+
+    } while (bta_dm_search_cb.service_index <= BTA_MAX_SERVICE_ID);
+
+    APPL_TRACE_DEBUG("%s services_found = %04x", __func__,
+                     bta_dm_search_cb.services_found);
+
+    /* Collect the 128-bit services here and put them into the list */
+    if (bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK) {
+      p_sdp_rec = NULL;
+      do {
+        tBT_UUID temp_uuid;
+        /* find a service record, report it */
+        p_sdp_rec =
+            SDP_FindServiceInDb_128bit(bta_dm_search_cb.p_sdp_db, p_sdp_rec);
+        if (p_sdp_rec) {
+          if (SDP_FindServiceUUIDInRec_128bit(p_sdp_rec, &temp_uuid)) {
+            memcpy(uuid_list[num_uuids], temp_uuid.uu.uuid128, MAX_UUID_SIZE);
+            num_uuids++;
+          }
+        }
+      } while (p_sdp_rec);
+    }
+    /* if there are more services to search for */
+    if (bta_dm_search_cb.services_to_search) {
+      /* Free up the p_sdp_db before checking the next one */
+      bta_dm_free_sdp_db(NULL);
+      bta_dm_find_services(bta_dm_search_cb.peer_bdaddr);
+    } else {
+      /* callbacks */
+      /* start next bd_addr if necessary */
+
+      BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback);
+
+      p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+      p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
+      p_msg->disc_result.result.disc_res.result = BTA_SUCCESS;
+      p_msg->disc_result.result.disc_res.p_raw_data = NULL;
+      p_msg->disc_result.result.disc_res.raw_data_size = 0;
+      p_msg->disc_result.result.disc_res.num_uuids = num_uuids;
+      p_msg->disc_result.result.disc_res.p_uuid_list = NULL;
+      if (num_uuids > 0) {
+        p_msg->disc_result.result.disc_res.p_uuid_list =
+            (uint8_t*)osi_malloc(num_uuids * MAX_UUID_SIZE);
+        memcpy(p_msg->disc_result.result.disc_res.p_uuid_list, uuid_list,
+               num_uuids * MAX_UUID_SIZE);
+      }
+      // Copy the raw_data to the discovery result structure
+      if (bta_dm_search_cb.p_sdp_db != NULL &&
+          bta_dm_search_cb.p_sdp_db->raw_used != 0 &&
+          bta_dm_search_cb.p_sdp_db->raw_data != NULL) {
+        APPL_TRACE_DEBUG("%s raw_data used = 0x%x raw_data_ptr = 0x%x",
+                         __func__, bta_dm_search_cb.p_sdp_db->raw_used,
+                         bta_dm_search_cb.p_sdp_db->raw_data);
+
+        p_msg->disc_result.result.disc_res.p_raw_data =
+            (uint8_t*)osi_malloc(bta_dm_search_cb.p_sdp_db->raw_used);
+        memcpy(p_msg->disc_result.result.disc_res.p_raw_data,
+               bta_dm_search_cb.p_sdp_db->raw_data,
+               bta_dm_search_cb.p_sdp_db->raw_used);
+
+        p_msg->disc_result.result.disc_res.raw_data_size =
+            bta_dm_search_cb.p_sdp_db->raw_used;
+
+        bta_dm_search_cb.p_sdp_db->raw_data =
+            NULL;  // no need to free this - it is a global assigned.
+        bta_dm_search_cb.p_sdp_db->raw_used = 0;
+        bta_dm_search_cb.p_sdp_db->raw_size = 0;
+      } else {
+        APPL_TRACE_DEBUG("%s raw data size is 0 or raw_data is null!!",
+                         __func__);
+      }
+      /* Done with p_sdp_db. Free it */
+      bta_dm_free_sdp_db(NULL);
+      p_msg->disc_result.result.disc_res.services =
+          bta_dm_search_cb.services_found;
+
+      // Piggy back the SCN over result field
+      if (scn_found) {
+        p_msg->disc_result.result.disc_res.result =
+            (3 + bta_dm_search_cb.peer_scn);
+        p_msg->disc_result.result.disc_res.services |= BTA_USER_SERVICE_MASK;
+
+        APPL_TRACE_EVENT(" Piggy back the SCN over result field  SCN=%d",
+                         bta_dm_search_cb.peer_scn);
+      }
+      bdcpy(p_msg->disc_result.result.disc_res.bd_addr,
+            bta_dm_search_cb.peer_bdaddr);
+      strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name,
+              bta_dm_get_remname(), BD_NAME_LEN);
+
+      bta_sys_sendmsg(p_msg);
+    }
+  } else {
+    /* conn failed. No need for timer */
+    if (p_data->sdp_event.sdp_result == SDP_CONN_FAILED ||
+        p_data->sdp_event.sdp_result == SDP_CONN_REJECTED ||
+        p_data->sdp_event.sdp_result == SDP_SECURITY_ERR)
+      bta_dm_search_cb.wait_disc = false;
+
+    /* not able to connect go to next device */
+    if (bta_dm_search_cb.p_sdp_db)
+      osi_free_and_reset((void**)&bta_dm_search_cb.p_sdp_db);
+
+    BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback);
+
+    p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+    p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
+    p_msg->disc_result.result.disc_res.result = BTA_FAILURE;
+    p_msg->disc_result.result.disc_res.services =
+        bta_dm_search_cb.services_found;
+    bdcpy(p_msg->disc_result.result.disc_res.bd_addr,
+          bta_dm_search_cb.peer_bdaddr);
+    strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name,
+            bta_dm_get_remname(), BD_NAME_LEN);
+
+    bta_sys_sendmsg(p_msg);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_search_cmpl
+ *
+ * Description      Sends event to application
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_search_cmpl(tBTA_DM_MSG* p_data) {
+  APPL_TRACE_EVENT("%s", __func__);
+
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+  osi_free_and_reset((void**)&bta_dm_search_cb.p_srvc_uuid);
+#endif
+
+  if (p_data->hdr.layer_specific == BTA_DM_API_DI_DISCOVER_EVT)
+    bta_dm_di_disc_cmpl(p_data);
+  else
+    bta_dm_search_cb.p_search_cback(BTA_DM_DISC_CMPL_EVT, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_disc_result
+ *
+ * Description      Service discovery result when discovering services on a
+ *                  device
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_disc_result(tBTA_DM_MSG* p_data) {
+  APPL_TRACE_EVENT("%s", __func__);
+
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+  /* if any BR/EDR service discovery has been done, report the event */
+  if ((bta_dm_search_cb.services &
+       ((BTA_ALL_SERVICE_MASK | BTA_USER_SERVICE_MASK) &
+        ~BTA_BLE_SERVICE_MASK)))
+#endif
+    bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT,
+                                    &p_data->disc_result.result);
+
+  tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+
+  /* send a message to change state */
+  p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+  p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_search_result
+ *
+ * Description      Service discovery result while searching for devices
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_search_result(tBTA_DM_MSG* p_data) {
+  APPL_TRACE_DEBUG("%s searching:0x%04x, result:0x%04x", __func__,
+                   bta_dm_search_cb.services,
+                   p_data->disc_result.result.disc_res.services);
+
+  /* call back if application wants name discovery or found services that
+   * application is searching */
+  if ((!bta_dm_search_cb.services) ||
+      ((bta_dm_search_cb.services) &&
+       (p_data->disc_result.result.disc_res.services))) {
+    bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT,
+                                    &p_data->disc_result.result);
+  }
+
+  /* if searching did not initiate to create link */
+  if (!bta_dm_search_cb.wait_disc) {
+    /* if service searching is done with EIR, don't search next device */
+    if (bta_dm_search_cb.p_btm_inq_info) bta_dm_discover_next_device();
+  } else {
+    /* wait until link is disconnected or timeout */
+    bta_dm_search_cb.sdp_results = true;
+    alarm_set_on_queue(bta_dm_search_cb.search_timer,
+                       1000 * (L2CAP_LINK_INACTIVITY_TOUT + 1),
+                       bta_dm_search_timer_cback, NULL, btu_bta_alarm_queue);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_search_timer_cback
+ *
+ * Description      Called when ACL disconnect time is over
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_search_timer_cback(UNUSED_ATTR void* data) {
+  APPL_TRACE_EVENT("%s", __func__);
+  bta_dm_search_cb.wait_disc = false;
+
+  /* proceed with next device */
+  bta_dm_discover_next_device();
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_free_sdp_db
+ *
+ * Description      Frees SDP data base
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_free_sdp_db(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+  osi_free_and_reset((void**)&bta_dm_search_cb.p_sdp_db);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_queue_search
+ *
+ * Description      Queues search command while search is being cancelled
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_queue_search(tBTA_DM_MSG* p_data) {
+  osi_free(bta_dm_search_cb.p_search_queue);
+  bta_dm_search_cb.p_search_queue =
+      (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_API_SEARCH));
+  memcpy(bta_dm_search_cb.p_search_queue, p_data, sizeof(tBTA_DM_API_SEARCH));
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_queue_disc
+ *
+ * Description      Queues discovery command while search is being cancelled
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_queue_disc(tBTA_DM_MSG* p_data) {
+  osi_free(bta_dm_search_cb.p_search_queue);
+  bta_dm_search_cb.p_search_queue =
+      (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_API_DISCOVER));
+  memcpy(bta_dm_search_cb.p_search_queue, p_data, sizeof(tBTA_DM_API_DISCOVER));
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_search_clear_queue
+ *
+ * Description      Clears the queue if API search cancel is called
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_search_clear_queue(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+  osi_free_and_reset((void**)&bta_dm_search_cb.p_search_queue);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_search_cancel_cmpl
+ *
+ * Description      Search cancel is complete
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_search_cancel_cmpl(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+  if (bta_dm_search_cb.p_search_queue) {
+    bta_sys_sendmsg(bta_dm_search_cb.p_search_queue);
+    bta_dm_search_cb.p_search_queue = NULL;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_search_cancel_transac_cmpl
+ *
+ * Description      Current Service Discovery or remote name procedure is
+ *                  completed after search cancellation
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_search_cancel_transac_cmpl(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+  osi_free_and_reset((void**)&bta_dm_search_cb.p_sdp_db);
+  bta_dm_search_cancel_notify(NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_search_cancel_notify
+ *
+ * Description      Notify application that search has been cancelled
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_search_cancel_notify(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+  if (bta_dm_search_cb.p_search_cback) {
+    bta_dm_search_cb.p_search_cback(BTA_DM_SEARCH_CANCEL_CMPL_EVT, NULL);
+  }
+  if (!bta_dm_search_cb.name_discover_done) {
+    BTM_CancelRemoteDeviceName();
+  }
+#if (BLE_INCLUDED == TRUE) && (BTA_GATT_INCLUDED == TRUE)
+  if (bta_dm_search_cb.gatt_disc_active) {
+    bta_dm_cancel_gatt_discovery(bta_dm_search_cb.peer_bdaddr);
+  }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_find_services
+ *
+ * Description      Starts discovery on a device
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_find_services(BD_ADDR bd_addr) {
+  tSDP_UUID uuid;
+
+  memset(&uuid, 0, sizeof(tSDP_UUID));
+
+  while (bta_dm_search_cb.service_index < BTA_MAX_SERVICE_ID) {
+    if (bta_dm_search_cb.services_to_search &
+        (tBTA_SERVICE_MASK)(
+            BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index))) {
+      bta_dm_search_cb.p_sdp_db =
+          (tSDP_DISCOVERY_DB*)osi_malloc(BTA_DM_SDP_DB_SIZE);
+      APPL_TRACE_DEBUG("bta_dm_search_cb.services = %04x***********",
+                       bta_dm_search_cb.services);
+      /* try to search all services by search based on L2CAP UUID */
+      if (bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK) {
+        LOG_INFO(LOG_TAG, "%s services_to_search=%08x", __func__,
+                 bta_dm_search_cb.services_to_search);
+        if (bta_dm_search_cb.services_to_search & BTA_RES_SERVICE_MASK) {
+          uuid.uu.uuid16 = bta_service_id_to_uuid_lkup_tbl[0];
+          bta_dm_search_cb.services_to_search &= ~BTA_RES_SERVICE_MASK;
+        } else {
+          uuid.uu.uuid16 = UUID_PROTOCOL_L2CAP;
+          bta_dm_search_cb.services_to_search = 0;
+        }
+      } else {
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+        /* for LE only profile */
+        if (bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID) {
+          if (bta_dm_search_cb.uuid_to_search > 0 &&
+              bta_dm_search_cb.p_srvc_uuid) {
+            memcpy(&uuid, (const void*)(bta_dm_search_cb.p_srvc_uuid +
+                                        bta_dm_search_cb.num_uuid -
+                                        bta_dm_search_cb.uuid_to_search),
+                   sizeof(tBT_UUID));
+
+            bta_dm_search_cb.uuid_to_search--;
+          } else {
+            uuid.uu.uuid16 =
+                bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index];
+          }
+
+          /* last one? clear the BLE service bit if all discovery has been done
+           */
+          if (bta_dm_search_cb.uuid_to_search == 0)
+            bta_dm_search_cb.services_to_search &=
+                (tBTA_SERVICE_MASK)(~(BTA_SERVICE_ID_TO_SERVICE_MASK(
+                    bta_dm_search_cb.service_index)));
+
+        } else
+#endif
+        {
+          /* remove the service from services to be searched  */
+          bta_dm_search_cb.services_to_search &= (tBTA_SERVICE_MASK)(~(
+              BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index)));
+          uuid.uu.uuid16 =
+              bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index];
+        }
+      }
+
+      if (uuid.len == 0) uuid.len = LEN_UUID_16;
+
+      if (bta_dm_search_cb.service_index == BTA_USER_SERVICE_ID) {
+        memcpy(&uuid, &bta_dm_search_cb.uuid, sizeof(tSDP_UUID));
+      }
+
+      LOG_INFO(LOG_TAG, "%s search UUID = %04x", __func__, uuid.uu.uuid16);
+      SDP_InitDiscoveryDb(bta_dm_search_cb.p_sdp_db, BTA_DM_SDP_DB_SIZE, 1,
+                          &uuid, 0, NULL);
+
+      memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf));
+      bta_dm_search_cb.p_sdp_db->raw_data = g_disc_raw_data_buf;
+
+      bta_dm_search_cb.p_sdp_db->raw_size = MAX_DISC_RAW_DATA_BUF;
+
+      if (!SDP_ServiceSearchAttributeRequest(bd_addr, bta_dm_search_cb.p_sdp_db,
+                                             &bta_dm_sdp_callback)) {
+        /*
+         * If discovery is not successful with this device, then
+         * proceed with the next one.
+         */
+        osi_free_and_reset((void**)&bta_dm_search_cb.p_sdp_db);
+        bta_dm_search_cb.service_index = BTA_MAX_SERVICE_ID;
+
+      } else {
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+        if ((bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID &&
+             bta_dm_search_cb.uuid_to_search == 0) ||
+            bta_dm_search_cb.service_index != BTA_BLE_SERVICE_ID)
+#endif
+          bta_dm_search_cb.service_index++;
+        return;
+      }
+    }
+
+    bta_dm_search_cb.service_index++;
+  }
+
+  /* no more services to be discovered */
+  if (bta_dm_search_cb.service_index >= BTA_MAX_SERVICE_ID) {
+    tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+    p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
+    p_msg->disc_result.result.disc_res.services =
+        bta_dm_search_cb.services_found;
+    bdcpy(p_msg->disc_result.result.disc_res.bd_addr,
+          bta_dm_search_cb.peer_bdaddr);
+    strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name,
+            bta_dm_get_remname(), BD_NAME_LEN);
+
+    bta_sys_sendmsg(p_msg);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_discover_next_device
+ *
+ * Description      Starts discovery on the next device in Inquiry data base
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_discover_next_device(void) {
+  APPL_TRACE_DEBUG("bta_dm_discover_next_device");
+
+  /* searching next device on inquiry result */
+  if ((bta_dm_search_cb.p_btm_inq_info =
+           BTM_InqDbNext(bta_dm_search_cb.p_btm_inq_info)) != NULL) {
+    bta_dm_search_cb.name_discover_done = false;
+    bta_dm_search_cb.peer_name[0] = 0;
+    bta_dm_discover_device(
+        bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr);
+  } else {
+    tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+
+    /* no devices, search complete */
+    bta_dm_search_cb.services = 0;
+
+    p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+    p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
+
+    bta_sys_sendmsg(p_msg);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_discover_device
+ *
+ * Description      Starts name and service discovery on the device
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_discover_device(BD_ADDR remote_bd_addr) {
+  tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+#if (BLE_INCLUDED == TRUE)
+  if (bta_dm_search_cb.transport == BTA_TRANSPORT_UNKNOWN) {
+    tBT_DEVICE_TYPE dev_type;
+    tBLE_ADDR_TYPE addr_type;
+
+    BTM_ReadDevInfo(remote_bd_addr, &dev_type, &addr_type);
+    if (dev_type == BT_DEVICE_TYPE_BLE || addr_type == BLE_ADDR_RANDOM)
+      transport = BT_TRANSPORT_LE;
+  } else {
+    transport = bta_dm_search_cb.transport;
+  }
+#endif
+
+  /* Reset transport state for next discovery */
+  bta_dm_search_cb.transport = BTA_TRANSPORT_UNKNOWN;
+
+  APPL_TRACE_DEBUG("%s BDA:0x%02X%02X%02X%02X%02X%02X", __func__,
+                   remote_bd_addr[0], remote_bd_addr[1], remote_bd_addr[2],
+                   remote_bd_addr[3], remote_bd_addr[4], remote_bd_addr[5]);
+
+  bdcpy(bta_dm_search_cb.peer_bdaddr, remote_bd_addr);
+
+  APPL_TRACE_DEBUG(
+      "%s name_discover_done = %d p_btm_inq_info 0x%x state = %d, transport=%d",
+      __func__, bta_dm_search_cb.name_discover_done,
+      bta_dm_search_cb.p_btm_inq_info, bta_dm_search_cb.state, transport);
+
+  if (bta_dm_search_cb.p_btm_inq_info) {
+    APPL_TRACE_DEBUG("%s appl_knows_rem_name %d", __func__,
+                     bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name);
+  }
+#if (BLE_INCLUDED == TRUE)
+  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)) {
+    /* Do not perform RNR for LE devices at inquiry complete*/
+    bta_dm_search_cb.name_discover_done = true;
+  }
+#endif
+  /* if name discovery is not done and application needs remote name */
+  if ((!bta_dm_search_cb.name_discover_done) &&
+      ((bta_dm_search_cb.p_btm_inq_info == NULL) ||
+       (bta_dm_search_cb.p_btm_inq_info &&
+        (!bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name)))) {
+    if (bta_dm_read_remote_device_name(bta_dm_search_cb.peer_bdaddr,
+                                       transport) == true)
+      return;
+
+    /* starting name discovery failed */
+    bta_dm_search_cb.name_discover_done = true;
+  }
+
+  /* if application wants to discover service */
+  if (bta_dm_search_cb.services) {
+    /* initialize variables */
+    bta_dm_search_cb.service_index = 0;
+    bta_dm_search_cb.services_found = 0;
+    bta_dm_search_cb.services_to_search = bta_dm_search_cb.services;
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+    bta_dm_search_cb.uuid_to_search = bta_dm_search_cb.num_uuid;
+#endif
+    if ((bta_dm_search_cb.p_btm_inq_info != NULL) &&
+        bta_dm_search_cb.services != BTA_USER_SERVICE_MASK &&
+        (bta_dm_search_cb.sdp_search == false)) {
+      /* check if EIR provides the information of supported services */
+      bta_dm_eir_search_services(&bta_dm_search_cb.p_btm_inq_info->results,
+                                 &bta_dm_search_cb.services_to_search,
+                                 &bta_dm_search_cb.services_found);
+    }
+
+    /* if seaching with EIR is not completed */
+    if (bta_dm_search_cb.services_to_search) {
+      /* check whether connection already exists to the device
+         if connection exists, we don't have to wait for ACL
+         link to go down to start search on next device */
+      if (BTM_IsAclConnectionUp(bta_dm_search_cb.peer_bdaddr,
+                                BT_TRANSPORT_BR_EDR))
+        bta_dm_search_cb.wait_disc = false;
+      else
+        bta_dm_search_cb.wait_disc = true;
+
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+      if (bta_dm_search_cb.p_btm_inq_info) {
+        APPL_TRACE_DEBUG(
+            "%s p_btm_inq_info 0x%x results.device_type 0x%x "
+            "services_to_search 0x%x",
+            __func__, bta_dm_search_cb.p_btm_inq_info,
+            bta_dm_search_cb.p_btm_inq_info->results.device_type,
+            bta_dm_search_cb.services_to_search);
+      }
+
+      if (transport == BT_TRANSPORT_LE) {
+        if (bta_dm_search_cb.services_to_search & BTA_BLE_SERVICE_MASK) {
+          // set the raw data buffer here
+          memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf));
+          bta_dm_search_cb.p_ble_rawdata = g_disc_raw_data_buf;
+
+          bta_dm_search_cb.ble_raw_size = MAX_DISC_RAW_DATA_BUF;
+          bta_dm_search_cb.ble_raw_used = 0;
+
+          /* start GATT for service discovery */
+          btm_dm_start_gatt_discovery(bta_dm_search_cb.peer_bdaddr);
+          return;
+        }
+      } else
+#endif
+      {
+        bta_dm_search_cb.sdp_results = false;
+        bta_dm_find_services(bta_dm_search_cb.peer_bdaddr);
+        return;
+      }
+    }
+  }
+
+  /* name discovery and service discovery are done for this device */
+  tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+  p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
+  /* initialize the data structure - includes p_raw_data and raw_data_size */
+  memset(&(p_msg->disc_result.result), 0, sizeof(tBTA_DM_DISC_RES));
+  p_msg->disc_result.result.disc_res.result = BTA_SUCCESS;
+  p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found;
+  bdcpy(p_msg->disc_result.result.disc_res.bd_addr,
+        bta_dm_search_cb.peer_bdaddr);
+  strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name,
+          (char*)bta_dm_search_cb.peer_name, BD_NAME_LEN);
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_sdp_callback
+ *
+ * Description      Callback from sdp with discovery status
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_sdp_callback(uint16_t sdp_status) {
+  tBTA_DM_SDP_RESULT* p_msg =
+      (tBTA_DM_SDP_RESULT*)osi_malloc(sizeof(tBTA_DM_SDP_RESULT));
+
+  p_msg->hdr.event = BTA_DM_SDP_RESULT_EVT;
+  p_msg->sdp_result = sdp_status;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_inq_results_cb
+ *
+ * Description      Inquiry results callback from BTM
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_inq_results_cb(tBTM_INQ_RESULTS* p_inq, uint8_t* p_eir) {
+  tBTA_DM_SEARCH result;
+  tBTM_INQ_INFO* p_inq_info;
+  uint16_t service_class;
+
+  bdcpy(result.inq_res.bd_addr, p_inq->remote_bd_addr);
+  memcpy(result.inq_res.dev_class, p_inq->dev_class, DEV_CLASS_LEN);
+  BTM_COD_SERVICE_CLASS(service_class, p_inq->dev_class);
+  result.inq_res.is_limited =
+      (service_class & BTM_COD_SERVICE_LMTD_DISCOVER) ? true : false;
+  result.inq_res.rssi = p_inq->rssi;
+
+#if (BLE_INCLUDED == TRUE)
+  result.inq_res.ble_addr_type = p_inq->ble_addr_type;
+  result.inq_res.inq_result_type = p_inq->inq_result_type;
+  result.inq_res.device_type = p_inq->device_type;
+  result.inq_res.flag = p_inq->flag;
+#endif
+
+  /* application will parse EIR to find out remote device name */
+  result.inq_res.p_eir = p_eir;
+
+  if ((p_inq_info = BTM_InqDbRead(p_inq->remote_bd_addr)) != NULL) {
+    /* initialize remt_name_not_required to false so that we get the name by
+     * default */
+    result.inq_res.remt_name_not_required = false;
+  }
+
+  if (bta_dm_search_cb.p_search_cback)
+    bta_dm_search_cb.p_search_cback(BTA_DM_INQ_RES_EVT, &result);
+
+  if (p_inq_info) {
+    /* application indicates if it knows the remote name, inside the callback
+     copy that to the inquiry data base*/
+    if (result.inq_res.remt_name_not_required)
+      p_inq_info->appl_knows_rem_name = true;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_inq_cmpl_cb
+ *
+ * Description      Inquiry complete callback from BTM
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_inq_cmpl_cb(void* p_result) {
+  tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  if (bta_dm_search_cb.cancel_pending == false) {
+    p_msg->inq_cmpl.hdr.event = BTA_DM_INQUIRY_CMPL_EVT;
+    p_msg->inq_cmpl.num = ((tBTM_INQUIRY_CMPL*)p_result)->num_resp;
+  } else {
+    bta_dm_search_cb.cancel_pending = false;
+    bta_dm_search_cancel_notify(NULL);
+    p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+    p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
+  }
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_service_search_remname_cback
+ *
+ * Description      Remote name call back from BTM during service discovery
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_service_search_remname_cback(BD_ADDR bd_addr,
+                                                UNUSED_ATTR DEV_CLASS dc,
+                                                BD_NAME bd_name) {
+  tBTM_REMOTE_DEV_NAME rem_name;
+  tBTM_STATUS btm_status;
+
+  APPL_TRACE_DEBUG("bta_dm_service_search_remname_cback name=<%s>", bd_name);
+
+  /* if this is what we are looking for */
+  if (!bdcmp(bta_dm_search_cb.peer_bdaddr, bd_addr)) {
+    rem_name.length = strlen((char*)bd_name);
+    if (rem_name.length > (BD_NAME_LEN - 1)) {
+      rem_name.length = (BD_NAME_LEN - 1);
+      rem_name.remote_bd_name[(BD_NAME_LEN - 1)] = 0;
+    }
+    strlcpy((char*)rem_name.remote_bd_name, (char*)bd_name, BD_NAME_LEN);
+    rem_name.status = BTM_SUCCESS;
+
+    bta_dm_remname_cback(&rem_name);
+  } else {
+    /* get name of device */
+    btm_status = BTM_ReadRemoteDeviceName(bta_dm_search_cb.peer_bdaddr,
+                                          (tBTM_CMPL_CB*)bta_dm_remname_cback,
+                                          BT_TRANSPORT_BR_EDR);
+    if (btm_status == BTM_BUSY) {
+      /* wait for next chance(notification of remote name discovery done) */
+      APPL_TRACE_DEBUG(
+          "bta_dm_service_search_remname_cback: BTM_ReadRemoteDeviceName is "
+          "busy");
+    } else if (btm_status != BTM_CMD_STARTED) {
+      /* if failed to start getting remote name then continue */
+      APPL_TRACE_WARNING(
+          "bta_dm_service_search_remname_cback: BTM_ReadRemoteDeviceName "
+          "returns 0x%02X",
+          btm_status);
+
+      rem_name.length = 0;
+      rem_name.remote_bd_name[0] = 0;
+      rem_name.status = btm_status;
+      bta_dm_remname_cback(&rem_name);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_remname_cback
+ *
+ * Description      Remote name complete call back from BTM
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_remname_cback(tBTM_REMOTE_DEV_NAME* p_remote_name) {
+  APPL_TRACE_DEBUG("bta_dm_remname_cback len = %d name=<%s>",
+                   p_remote_name->length, p_remote_name->remote_bd_name);
+
+  /* remote name discovery is done but it could be failed */
+  bta_dm_search_cb.name_discover_done = true;
+  strlcpy((char*)bta_dm_search_cb.peer_name,
+          (char*)p_remote_name->remote_bd_name, BD_NAME_LEN);
+
+  BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback);
+
+#if (BLE_INCLUDED == TRUE)
+  if (bta_dm_search_cb.transport == BT_TRANSPORT_LE) {
+    GAP_BleReadPeerPrefConnParams(bta_dm_search_cb.peer_bdaddr);
+  }
+#endif
+
+  tBTA_DM_REM_NAME* p_msg =
+      (tBTA_DM_REM_NAME*)osi_malloc(sizeof(tBTA_DM_REM_NAME));
+  bdcpy(p_msg->result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr);
+  strlcpy((char*)p_msg->result.disc_res.bd_name,
+          (char*)p_remote_name->remote_bd_name, BD_NAME_LEN);
+  p_msg->hdr.event = BTA_DM_REMT_NAME_EVT;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_authorize_cback
+ *
+ * Description      cback requesting authorization
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static uint8_t bta_dm_authorize_cback(BD_ADDR bd_addr, DEV_CLASS dev_class,
+                                      BD_NAME bd_name,
+                                      UNUSED_ATTR uint8_t* service_name,
+                                      uint8_t service_id,
+                                      UNUSED_ATTR bool is_originator) {
+  tBTA_DM_SEC sec_event;
+  uint8_t index = 1;
+
+  bdcpy(sec_event.authorize.bd_addr, bd_addr);
+  memcpy(sec_event.authorize.dev_class, dev_class, DEV_CLASS_LEN);
+  strlcpy((char*)sec_event.authorize.bd_name, (char*)bd_name, BD_NAME_LEN);
+
+#if (BTA_JV_INCLUDED == TRUE)
+  sec_event.authorize.service = service_id;
+#endif
+
+  while (index < BTA_MAX_SERVICE_ID) {
+    /* get the BTA service id corresponding to BTM id */
+    if (bta_service_id_to_btm_srv_id_lkup_tbl[index] == service_id) {
+      sec_event.authorize.service = index;
+      break;
+    }
+    index++;
+  }
+
+  /* if supported service callback otherwise not authorized */
+  if (bta_dm_cb.p_sec_cback && (index < BTA_MAX_SERVICE_ID
+#if (BTA_JV_INCLUDED == TRUE)
+                                /* pass through JV service ID */
+                                || (service_id >= BTA_FIRST_JV_SERVICE_ID &&
+                                    service_id <= BTA_LAST_JV_SERVICE_ID)
+#endif
+                                    )) {
+    bta_dm_cb.p_sec_cback(BTA_DM_AUTHORIZE_EVT, &sec_event);
+    return BTM_CMD_STARTED;
+  } else {
+    return BTM_NOT_AUTHORIZED;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_pinname_cback
+ *
+ * Description      Callback requesting pin_key
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_pinname_cback(void* p_data) {
+  tBTM_REMOTE_DEV_NAME* p_result = (tBTM_REMOTE_DEV_NAME*)p_data;
+  tBTA_DM_SEC sec_event;
+  uint32_t bytes_to_copy;
+  tBTA_DM_SEC_EVT event = bta_dm_cb.pin_evt;
+
+  if (BTA_DM_SP_CFM_REQ_EVT == event) {
+    /* Retrieved saved device class and bd_addr */
+    bdcpy(sec_event.cfm_req.bd_addr, bta_dm_cb.pin_bd_addr);
+    BTA_COPY_DEVICE_CLASS(sec_event.cfm_req.dev_class, bta_dm_cb.pin_dev_class);
+
+    if (p_result && p_result->status == BTM_SUCCESS) {
+      bytes_to_copy = (p_result->length < (BD_NAME_LEN - 1))
+                          ? p_result->length
+                          : (BD_NAME_LEN - 1);
+      memcpy(sec_event.cfm_req.bd_name, p_result->remote_bd_name,
+             bytes_to_copy);
+      sec_event.pin_req.bd_name[BD_NAME_LEN - 1] = 0;
+    } else /* No name found */
+      sec_event.cfm_req.bd_name[0] = 0;
+
+    sec_event.key_notif.passkey =
+        bta_dm_cb.num_val; /* get PIN code numeric number */
+
+    /* 1 additional event data fields for this event */
+    sec_event.cfm_req.just_works = bta_dm_cb.just_works;
+  } else {
+    /* Retrieved saved device class and bd_addr */
+    bdcpy(sec_event.pin_req.bd_addr, bta_dm_cb.pin_bd_addr);
+    BTA_COPY_DEVICE_CLASS(sec_event.pin_req.dev_class, bta_dm_cb.pin_dev_class);
+
+    if (p_result && p_result->status == BTM_SUCCESS) {
+      bytes_to_copy = (p_result->length < (BD_NAME_LEN - 1))
+                          ? p_result->length
+                          : (BD_NAME_LEN - 1);
+      memcpy(sec_event.pin_req.bd_name, p_result->remote_bd_name,
+             bytes_to_copy);
+      sec_event.pin_req.bd_name[BD_NAME_LEN - 1] = 0;
+    } else /* No name found */
+      sec_event.pin_req.bd_name[0] = 0;
+
+    event = bta_dm_cb.pin_evt;
+    sec_event.key_notif.passkey =
+        bta_dm_cb.num_val; /* get PIN code numeric number */
+  }
+
+  if (bta_dm_cb.p_sec_cback) bta_dm_cb.p_sec_cback(event, &sec_event);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_pin_cback
+ *
+ * Description      Callback requesting pin_key
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static uint8_t bta_dm_pin_cback(BD_ADDR bd_addr, DEV_CLASS dev_class,
+                                BD_NAME bd_name, bool min_16_digit) {
+  tBTA_DM_SEC sec_event;
+
+  if (!bta_dm_cb.p_sec_cback) return BTM_NOT_AUTHORIZED;
+
+  /* If the device name is not known, save bdaddr and devclass and initiate a
+   * name request */
+  if (bd_name[0] == 0) {
+    bta_dm_cb.pin_evt = BTA_DM_PIN_REQ_EVT;
+    bdcpy(bta_dm_cb.pin_bd_addr, bd_addr);
+    BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class, dev_class);
+    if ((BTM_ReadRemoteDeviceName(bd_addr, bta_dm_pinname_cback,
+                                  BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED)
+      return BTM_CMD_STARTED;
+
+    APPL_TRACE_WARNING(
+        " bta_dm_pin_cback() -> Failed to start Remote Name Request  ");
+  }
+
+  bdcpy(sec_event.pin_req.bd_addr, bd_addr);
+  BTA_COPY_DEVICE_CLASS(sec_event.pin_req.dev_class, dev_class);
+  strlcpy((char*)sec_event.pin_req.bd_name, (char*)bd_name, BD_NAME_LEN);
+  sec_event.pin_req.min_16_digit = min_16_digit;
+
+  bta_dm_cb.p_sec_cback(BTA_DM_PIN_REQ_EVT, &sec_event);
+  return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_new_link_key_cback
+ *
+ * Description      Callback from BTM to notify new link key
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static uint8_t bta_dm_new_link_key_cback(BD_ADDR bd_addr,
+                                         UNUSED_ATTR DEV_CLASS dev_class,
+                                         BD_NAME bd_name, LINK_KEY key,
+                                         uint8_t key_type) {
+  tBTA_DM_SEC sec_event;
+  tBTA_DM_AUTH_CMPL* p_auth_cmpl;
+  uint8_t event;
+
+  memset(&sec_event, 0, sizeof(tBTA_DM_SEC));
+
+  /* Not AMP Key type */
+  if (key_type != HCI_LKEY_TYPE_AMP_WIFI && key_type != HCI_LKEY_TYPE_AMP_UWB) {
+    event = BTA_DM_AUTH_CMPL_EVT;
+    p_auth_cmpl = &sec_event.auth_cmpl;
+
+    bdcpy(p_auth_cmpl->bd_addr, bd_addr);
+
+    memcpy(p_auth_cmpl->bd_name, bd_name, (BD_NAME_LEN - 1));
+    p_auth_cmpl->bd_name[BD_NAME_LEN - 1] = 0;
+
+    p_auth_cmpl->key_present = true;
+    p_auth_cmpl->key_type = key_type;
+    p_auth_cmpl->success = true;
+
+    memcpy(p_auth_cmpl->key, key, LINK_KEY_LEN);
+    sec_event.auth_cmpl.fail_reason = HCI_SUCCESS;
+
+#if (BLE_INCLUDED == TRUE)
+    // Report the BR link key based on the BR/EDR address and type
+    BTM_ReadDevInfo(bd_addr, &sec_event.auth_cmpl.dev_type,
+                    &sec_event.auth_cmpl.addr_type);
+#endif
+    if (bta_dm_cb.p_sec_cback) bta_dm_cb.p_sec_cback(event, &sec_event);
+
+    // Setting remove_dev_pending flag to false, where it will avoid deleting
+    // the
+    // security device record when the ACL connection link goes down in case of
+    // reconnection.
+    if (bta_dm_cb.device_list.count)
+      bta_dm_reset_sec_dev_pending(p_auth_cmpl->bd_addr);
+  } else {
+    APPL_TRACE_WARNING("%s() Received AMP Key", __func__);
+  }
+
+  return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_authentication_complete_cback
+ *
+ * Description      Authentication complete callback from BTM
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static uint8_t bta_dm_authentication_complete_cback(
+    BD_ADDR bd_addr, UNUSED_ATTR DEV_CLASS dev_class, BD_NAME bd_name,
+    int result) {
+  tBTA_DM_SEC sec_event;
+
+  if (result != BTM_SUCCESS) {
+    memset(&sec_event, 0, sizeof(tBTA_DM_SEC));
+    bdcpy(sec_event.auth_cmpl.bd_addr, bd_addr);
+
+    memcpy(sec_event.auth_cmpl.bd_name, bd_name, (BD_NAME_LEN - 1));
+    sec_event.auth_cmpl.bd_name[BD_NAME_LEN - 1] = 0;
+
+#if (BLE_INCLUDED == TRUE)
+    // Report the BR link key based on the BR/EDR address and type
+    BTM_ReadDevInfo(bd_addr, &sec_event.auth_cmpl.dev_type,
+                    &sec_event.auth_cmpl.addr_type);
+#endif
+    sec_event.auth_cmpl.fail_reason = (uint8_t)result;
+
+    if (bta_dm_cb.p_sec_cback)
+      bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);
+
+    bta_dm_remove_sec_dev_entry(bd_addr);
+  }
+
+  return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_sp_cback
+ *
+ * Description      simple pairing callback from BTM
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static uint8_t bta_dm_sp_cback(tBTM_SP_EVT event, tBTM_SP_EVT_DATA* p_data) {
+  tBTM_STATUS status = BTM_CMD_STARTED;
+  tBTA_DM_SEC sec_event;
+  tBTA_DM_SEC_EVT pin_evt = BTA_DM_SP_KEY_NOTIF_EVT;
+
+  APPL_TRACE_EVENT("bta_dm_sp_cback: %d", event);
+  if (!bta_dm_cb.p_sec_cback) return BTM_NOT_AUTHORIZED;
+
+  /* TODO_SP */
+  switch (event) {
+    case BTM_SP_IO_REQ_EVT:
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+      /* translate auth_req */
+      bta_dm_co_io_req(p_data->io_req.bd_addr, &p_data->io_req.io_cap,
+                       &p_data->io_req.oob_data, &p_data->io_req.auth_req,
+                       p_data->io_req.is_orig);
+#endif
+      APPL_TRACE_EVENT("io mitm: %d oob_data:%d", p_data->io_req.auth_req,
+                       p_data->io_req.oob_data);
+      break;
+    case BTM_SP_IO_RSP_EVT:
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+      bta_dm_co_io_rsp(p_data->io_rsp.bd_addr, p_data->io_rsp.io_cap,
+                       p_data->io_rsp.oob_data, p_data->io_rsp.auth_req);
+#endif
+      break;
+
+    case BTM_SP_CFM_REQ_EVT:
+      pin_evt = BTA_DM_SP_CFM_REQ_EVT;
+      bta_dm_cb.just_works = sec_event.cfm_req.just_works =
+          p_data->cfm_req.just_works;
+      sec_event.cfm_req.loc_auth_req = p_data->cfm_req.loc_auth_req;
+      sec_event.cfm_req.rmt_auth_req = p_data->cfm_req.rmt_auth_req;
+      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 */
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+    /* 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: */
+    case BTM_SP_KEY_NOTIF_EVT:
+#endif
+      bta_dm_cb.num_val = sec_event.key_notif.passkey =
+          p_data->key_notif.passkey;
+
+      if (BTM_SP_CFM_REQ_EVT == event) {
+        /* Due to the switch case falling through below to BTM_SP_KEY_NOTIF_EVT,
+           call remote name request using values from cfm_req */
+        if (p_data->cfm_req.bd_name[0] == 0) {
+          bta_dm_cb.pin_evt = pin_evt;
+          bdcpy(bta_dm_cb.pin_bd_addr, p_data->cfm_req.bd_addr);
+          BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class,
+                                p_data->cfm_req.dev_class);
+          if ((BTM_ReadRemoteDeviceName(
+                  p_data->cfm_req.bd_addr, bta_dm_pinname_cback,
+                  BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED)
+            return BTM_CMD_STARTED;
+          APPL_TRACE_WARNING(
+              " bta_dm_sp_cback() -> Failed to start Remote Name Request  ");
+        } else {
+          /* Due to the switch case falling through below to
+             BTM_SP_KEY_NOTIF_EVT,
+             copy these values into key_notif from cfm_req */
+          bdcpy(sec_event.key_notif.bd_addr, p_data->cfm_req.bd_addr);
+          BTA_COPY_DEVICE_CLASS(sec_event.key_notif.dev_class,
+                                p_data->cfm_req.dev_class);
+          strlcpy((char*)sec_event.key_notif.bd_name,
+                  (char*)p_data->cfm_req.bd_name, BD_NAME_LEN);
+        }
+      }
+
+      if (BTM_SP_KEY_NOTIF_EVT == event) {
+        /* If the device name is not known, save bdaddr and devclass
+           and initiate a name request with values from key_notif */
+        if (p_data->key_notif.bd_name[0] == 0) {
+          bta_dm_cb.pin_evt = pin_evt;
+          bdcpy(bta_dm_cb.pin_bd_addr, p_data->key_notif.bd_addr);
+          BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class,
+                                p_data->key_notif.dev_class);
+          if ((BTM_ReadRemoteDeviceName(
+                  p_data->key_notif.bd_addr, bta_dm_pinname_cback,
+                  BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED)
+            return BTM_CMD_STARTED;
+          APPL_TRACE_WARNING(
+              " bta_dm_sp_cback() -> Failed to start Remote Name Request  ");
+        } else {
+          bdcpy(sec_event.key_notif.bd_addr, p_data->key_notif.bd_addr);
+          BTA_COPY_DEVICE_CLASS(sec_event.key_notif.dev_class,
+                                p_data->key_notif.dev_class);
+          strlcpy((char*)sec_event.key_notif.bd_name,
+                  (char*)p_data->key_notif.bd_name, BD_NAME_LEN);
+          sec_event.key_notif.bd_name[BD_NAME_LEN - 1] = 0;
+        }
+      }
+
+      bta_dm_cb.p_sec_cback(pin_evt, &sec_event);
+
+      break;
+
+    case BTM_SP_LOC_OOB_EVT:
+      bta_dm_co_loc_oob((bool)(p_data->loc_oob.status == BTM_SUCCESS),
+                        p_data->loc_oob.c, p_data->loc_oob.r);
+      break;
+
+    case BTM_SP_RMT_OOB_EVT:
+      /* If the device name is not known, save bdaddr and devclass and initiate
+       * a name request */
+      if (p_data->rmt_oob.bd_name[0] == 0) {
+        bta_dm_cb.pin_evt = BTA_DM_SP_RMT_OOB_EVT;
+        bdcpy(bta_dm_cb.pin_bd_addr, p_data->rmt_oob.bd_addr);
+        BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class,
+                              p_data->rmt_oob.dev_class);
+        if ((BTM_ReadRemoteDeviceName(p_data->rmt_oob.bd_addr,
+                                      bta_dm_pinname_cback,
+                                      BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED)
+          return BTM_CMD_STARTED;
+        APPL_TRACE_WARNING(
+            " bta_dm_sp_cback() -> Failed to start Remote Name Request  ");
+      }
+
+      bdcpy(sec_event.rmt_oob.bd_addr, p_data->rmt_oob.bd_addr);
+      BTA_COPY_DEVICE_CLASS(sec_event.rmt_oob.dev_class,
+                            p_data->rmt_oob.dev_class);
+      strlcpy((char*)sec_event.rmt_oob.bd_name, (char*)p_data->rmt_oob.bd_name,
+              BD_NAME_LEN);
+
+      bta_dm_cb.p_sec_cback(BTA_DM_SP_RMT_OOB_EVT, &sec_event);
+
+      bta_dm_co_rmt_oob(p_data->rmt_oob.bd_addr);
+      break;
+
+    case BTM_SP_COMPLT_EVT:
+      /* do not report this event - handled by link_key_callback or
+       * auth_complete_callback */
+      break;
+
+    case BTM_SP_KEYPRESS_EVT:
+      memcpy(&sec_event.key_press, &p_data->key_press,
+             sizeof(tBTM_SP_KEYPRESS));
+      bta_dm_cb.p_sec_cback(BTA_DM_SP_KEYPRESS_EVT, &sec_event);
+      break;
+
+    case BTM_SP_UPGRADE_EVT:
+      bta_dm_co_lk_upgrade(p_data->upgrade.bd_addr, &p_data->upgrade.upgrade);
+      break;
+
+    default:
+      status = BTM_NOT_AUTHORIZED;
+      break;
+  }
+  APPL_TRACE_EVENT("dm status: %d", status);
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_local_name_cback
+ *
+ * Description      Callback from btm after local name is read
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_local_name_cback(UNUSED_ATTR uint8_t* p_name) {
+  tBTA_DM_SEC sec_event;
+
+  sec_event.enable.status = BTA_SUCCESS;
+
+  if (bta_dm_cb.p_sec_cback)
+    bta_dm_cb.p_sec_cback(BTA_DM_ENABLE_EVT, &sec_event);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_bl_change_cback
+ *
+ * Description      Callback from btm when acl connection goes up or down
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_bl_change_cback(tBTM_BL_EVENT_DATA* p_data) {
+  tBTA_DM_ACL_CHANGE* p_msg =
+      (tBTA_DM_ACL_CHANGE*)osi_malloc(sizeof(tBTA_DM_ACL_CHANGE));
+
+  p_msg->event = p_data->event;
+  p_msg->is_new = false;
+
+  switch (p_msg->event) {
+    case BTM_BL_CONN_EVT:
+      p_msg->is_new = true;
+      bdcpy(p_msg->bd_addr, p_data->conn.p_bda);
+#if (BLE_INCLUDED == TRUE)
+      p_msg->transport = p_data->conn.transport;
+      p_msg->handle = p_data->conn.handle;
+#endif
+      break;
+    case BTM_BL_DISCN_EVT:
+      bdcpy(p_msg->bd_addr, p_data->discn.p_bda);
+#if (BLE_INCLUDED == TRUE)
+      p_msg->transport = p_data->discn.transport;
+      p_msg->handle = p_data->discn.handle;
+#endif
+      break;
+    case BTM_BL_UPDATE_EVT:
+      p_msg->busy_level = p_data->update.busy_level;
+      p_msg->busy_level_flags = p_data->update.busy_level_flags;
+      break;
+    case BTM_BL_ROLE_CHG_EVT:
+      p_msg->new_role = p_data->role_chg.new_role;
+      p_msg->hci_status = p_data->role_chg.hci_status;
+      bdcpy(p_msg->bd_addr, p_data->role_chg.p_bda);
+      break;
+    case BTM_BL_COLLISION_EVT:
+      bdcpy(p_msg->bd_addr, p_data->conn.p_bda);
+      break;
+  }
+
+  p_msg->hdr.event = BTA_DM_ACL_CHANGE_EVT;
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_rs_cback
+ *
+ * Description      Receives the role switch complete event
+ *
+ * Returns
+ *
+ ******************************************************************************/
+static void bta_dm_rs_cback(UNUSED_ATTR tBTM_ROLE_SWITCH_CMPL* p1) {
+  APPL_TRACE_WARNING("bta_dm_rs_cback:%d", bta_dm_cb.rs_event);
+  if (bta_dm_cb.rs_event == BTA_DM_API_SEARCH_EVT) {
+    bta_dm_cb.search_msg.rs_res =
+        BTA_DM_RS_OK; /* do not care about the result for now */
+    bta_dm_cb.rs_event = 0;
+    bta_dm_search_start((tBTA_DM_MSG*)&bta_dm_cb.search_msg);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_check_av
+ *
+ * Description      This function checks if AV is active
+ *                  if yes, make sure the AV link is master
+ *
+ * Returns          bool - true, if switch is in progress
+ *
+ ******************************************************************************/
+static bool bta_dm_check_av(uint16_t event) {
+  bool avoid_roleswitch = false;
+  bool switching = false;
+  uint8_t i;
+  tBTA_DM_PEER_DEVICE* p_dev;
+
+#if (BTA_DM_AVOID_A2DP_ROLESWITCH_ON_INQUIRY == TRUE)
+
+  /* avoid role switch upon inquiry if a2dp is actively streaming as it
+     introduces an audioglitch due to FW scheduling delays (unavoidable) */
+  if (event == BTA_DM_API_SEARCH_EVT) {
+    avoid_roleswitch = true;
+  }
+#endif
+
+  APPL_TRACE_WARNING("bta_dm_check_av:%d", bta_dm_cb.cur_av_count);
+  if (bta_dm_cb.cur_av_count) {
+    for (i = 0; i < bta_dm_cb.device_list.count; i++) {
+      p_dev = &bta_dm_cb.device_list.peer_device[i];
+      APPL_TRACE_WARNING("[%d]: state:%d, info:x%x, avoid_rs %d", i,
+                         p_dev->conn_state, p_dev->info, avoid_roleswitch);
+      if ((p_dev->conn_state == BTA_DM_CONNECTED) &&
+          (p_dev->info & BTA_DM_DI_AV_ACTIVE) && (avoid_roleswitch == false)) {
+        /* make master and take away the role switch policy */
+        if (BTM_CMD_STARTED == BTM_SwitchRole(p_dev->peer_bdaddr,
+                                              HCI_ROLE_MASTER,
+                                              (tBTM_CMPL_CB*)bta_dm_rs_cback)) {
+          /* the role switch command is actually sent */
+          bta_dm_cb.rs_event = event;
+          switching = true;
+        }
+        /* else either already master or can not switch for some reasons */
+        bta_dm_policy_cback(BTA_SYS_PLCY_CLR, 0, HCI_ENABLE_MASTER_SLAVE_SWITCH,
+                            p_dev->peer_bdaddr);
+        break;
+      }
+    }
+  }
+  return switching;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_acl_change
+ *
+ * Description      Process BTA_DM_ACL_CHANGE_EVT
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_acl_change(tBTA_DM_MSG* p_data) {
+  uint8_t i;
+  uint8_t* p;
+  tBTA_DM_SEC conn;
+  bool is_new = p_data->acl_change.is_new;
+  BD_ADDR_PTR p_bda = p_data->acl_change.bd_addr;
+  bool need_policy_change = false;
+  bool issue_unpair_cb = false;
+
+  tBTA_DM_PEER_DEVICE* p_dev;
+  memset(&conn, 0, sizeof(tBTA_DM_SEC));
+
+  switch (p_data->acl_change.event) {
+    case BTM_BL_UPDATE_EVT: /* busy level update */
+      if (bta_dm_cb.p_sec_cback) {
+        conn.busy_level.level = p_data->acl_change.busy_level;
+        conn.busy_level.level_flags = p_data->acl_change.busy_level_flags;
+        bta_dm_cb.p_sec_cback(BTA_DM_BUSY_LEVEL_EVT, &conn);
+      }
+      return;
+
+    case BTM_BL_ROLE_CHG_EVT: /* role change event */
+      p_dev = bta_dm_find_peer_device(p_bda);
+      if (p_dev) {
+        APPL_TRACE_DEBUG(
+            "bta_dm_acl_change role chg info:x%x new_role:%d dev count:%d",
+            p_dev->info, p_data->acl_change.new_role,
+            bta_dm_cb.device_list.count);
+        if (p_dev->info & BTA_DM_DI_AV_ACTIVE) {
+          /* there's AV activity on this link */
+          if (p_data->acl_change.new_role == HCI_ROLE_SLAVE &&
+              bta_dm_cb.device_list.count > 1 &&
+              p_data->acl_change.hci_status == HCI_SUCCESS) {
+            /* more than one connections and the AV connection is role switched
+             * to slave
+             * switch it back to master and remove the switch policy */
+            BTM_SwitchRole(p_bda, BTM_ROLE_MASTER, NULL);
+            need_policy_change = true;
+          } else if (p_bta_dm_cfg->avoid_scatter &&
+                     (p_data->acl_change.new_role == HCI_ROLE_MASTER)) {
+            /* if the link updated to be master include AV activities, remove
+             * the switch policy */
+            need_policy_change = true;
+          }
+
+          if (need_policy_change) {
+            bta_dm_policy_cback(BTA_SYS_PLCY_CLR, 0,
+                                HCI_ENABLE_MASTER_SLAVE_SWITCH,
+                                p_dev->peer_bdaddr);
+          }
+        } else {
+          /* there's AV no activity on this link and role switch happened
+           * check if AV is active
+           * if so, make sure the AV link is master */
+          bta_dm_check_av(0);
+        }
+        bta_sys_notify_role_chg(p_data->acl_change.bd_addr,
+                                p_data->acl_change.new_role,
+                                p_data->acl_change.hci_status);
+        bdcpy(conn.role_chg.bd_addr, p_bda);
+        conn.role_chg.new_role = (uint8_t)p_data->acl_change.new_role;
+        if (bta_dm_cb.p_sec_cback)
+          bta_dm_cb.p_sec_cback(BTA_DM_ROLE_CHG_EVT, (tBTA_DM_SEC*)&conn);
+      }
+      return;
+  }
+
+  /* Collision report from Stack: Notify profiles */
+  if (p_data->acl_change.event == BTM_BL_COLLISION_EVT) {
+    bta_sys_notify_collision(p_bda);
+    return;
+  }
+
+  if (is_new) {
+    for (i = 0; i < bta_dm_cb.device_list.count; i++) {
+      if (!bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr, p_bda)
+#if (BLE_INCLUDED == TRUE)
+          &&
+          bta_dm_cb.device_list.peer_device[i].conn_handle ==
+              p_data->acl_change.handle
+#endif
+          )
+        break;
+    }
+
+    if (i == bta_dm_cb.device_list.count) {
+      if (bta_dm_cb.device_list.count < BTA_DM_NUM_PEER_DEVICE) {
+        bdcpy(bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count]
+                  .peer_bdaddr,
+              p_bda);
+        bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count]
+            .link_policy = bta_dm_cb.cur_policy;
+        bta_dm_cb.device_list.count++;
+#if (BLE_INCLUDED == TRUE)
+        bta_dm_cb.device_list.peer_device[i].conn_handle =
+            p_data->acl_change.handle;
+        if (p_data->acl_change.transport == BT_TRANSPORT_LE)
+          bta_dm_cb.device_list.le_count++;
+#endif
+      } else {
+        APPL_TRACE_ERROR("%s max active connection reached, no resources",
+                         __func__);
+        return;
+      }
+    }
+
+    bta_dm_cb.device_list.peer_device[i].conn_state = BTA_DM_CONNECTED;
+    bta_dm_cb.device_list.peer_device[i].pref_role = BTA_ANY_ROLE;
+    bdcpy(conn.link_up.bd_addr, p_bda);
+    bta_dm_cb.device_list.peer_device[i].info = BTA_DM_DI_NONE;
+#if (BLE_INCLUDED == TRUE)
+    conn.link_up.link_type = p_data->acl_change.transport;
+    bta_dm_cb.device_list.peer_device[i].transport =
+        p_data->acl_change.transport;
+#endif
+
+    if (((NULL != (p = BTM_ReadLocalFeatures())) &&
+         HCI_SNIFF_SUB_RATE_SUPPORTED(p)) &&
+        ((NULL != (p = BTM_ReadRemoteFeatures(p_bda))) &&
+         HCI_SNIFF_SUB_RATE_SUPPORTED(p))) {
+      /* both local and remote devices support SSR */
+      bta_dm_cb.device_list.peer_device[i].info = BTA_DM_DI_USE_SSR;
+    }
+    APPL_TRACE_WARNING("%s info: 0x%x", __func__,
+                       bta_dm_cb.device_list.peer_device[i].info);
+
+    if (bta_dm_cb.p_sec_cback)
+      bta_dm_cb.p_sec_cback(BTA_DM_LINK_UP_EVT, (tBTA_DM_SEC*)&conn);
+  } else {
+    for (i = 0; i < bta_dm_cb.device_list.count; i++) {
+      if (bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr, p_bda)
+#if (BLE_INCLUDED == TRUE)
+          ||
+          bta_dm_cb.device_list.peer_device[i].transport !=
+              p_data->acl_change.transport
+#endif
+          )
+        continue;
+
+      if (bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_UNPAIRING) {
+        if (BTM_SecDeleteDevice(
+                bta_dm_cb.device_list.peer_device[i].peer_bdaddr))
+          issue_unpair_cb = true;
+
+        APPL_TRACE_DEBUG("%s: Unpairing: issue unpair CB = %d ", __func__,
+                         issue_unpair_cb);
+      }
+
+      conn.link_down.is_removed =
+          bta_dm_cb.device_list.peer_device[i].remove_dev_pending;
+
+      for (; i < bta_dm_cb.device_list.count; i++) {
+        memcpy(&bta_dm_cb.device_list.peer_device[i],
+               &bta_dm_cb.device_list.peer_device[i + 1],
+               sizeof(bta_dm_cb.device_list.peer_device[i]));
+      }
+      break;
+    }
+    if (bta_dm_cb.device_list.count) bta_dm_cb.device_list.count--;
+#if (BLE_INCLUDED == TRUE)
+    if ((p_data->acl_change.transport == BT_TRANSPORT_LE) &&
+        (bta_dm_cb.device_list.le_count))
+      bta_dm_cb.device_list.le_count--;
+    conn.link_down.link_type = p_data->acl_change.transport;
+#endif
+
+    if (bta_dm_search_cb.wait_disc &&
+        !bdcmp(bta_dm_search_cb.peer_bdaddr, p_bda)) {
+      bta_dm_search_cb.wait_disc = false;
+
+      if (bta_dm_search_cb.sdp_results) {
+        APPL_TRACE_EVENT(" timer stopped  ");
+        alarm_cancel(bta_dm_search_cb.search_timer);
+        bta_dm_discover_next_device();
+      }
+    }
+
+    if (bta_dm_cb.disabling) {
+      if (!BTM_GetNumAclLinks()) {
+        /*
+         * Start a timer to make sure that the profiles
+         * get the disconnect event.
+         */
+        alarm_set_on_queue(
+            bta_dm_cb.disable_timer, BTA_DM_DISABLE_CONN_DOWN_TIMER_MS,
+            bta_dm_disable_conn_down_timer_cback, NULL, btu_bta_alarm_queue);
+      }
+    }
+    if (conn.link_down.is_removed) {
+      BTM_SecDeleteDevice(p_bda);
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+      /* need to remove all pending background connection */
+      BTA_GATTC_CancelOpen(0, p_bda, false);
+      /* remove all cached GATT information */
+      BTA_GATTC_Refresh(p_bda);
+#endif
+    }
+
+    bdcpy(conn.link_down.bd_addr, p_bda);
+    conn.link_down.status = (uint8_t)btm_get_acl_disc_reason_code();
+    if (bta_dm_cb.p_sec_cback) {
+      bta_dm_cb.p_sec_cback(BTA_DM_LINK_DOWN_EVT, &conn);
+      if (issue_unpair_cb)
+        bta_dm_cb.p_sec_cback(BTA_DM_DEV_UNPAIRED_EVT, &conn);
+    }
+  }
+
+  bta_dm_adjust_roles(true);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_disable_conn_down_timer_cback
+ *
+ * Description      Sends disable event to application
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_disable_conn_down_timer_cback(UNUSED_ATTR void* data) {
+  tBTA_SYS_HW_MSG* sys_enable_event =
+      (tBTA_SYS_HW_MSG*)osi_malloc(sizeof(tBTA_SYS_HW_MSG));
+
+  /* disable the power managment module */
+  bta_dm_disable_pm();
+
+  /* register our callback to SYS HW manager */
+  bta_sys_hw_register(BTA_SYS_HW_BLUETOOTH, bta_dm_sys_hw_cback);
+
+  /* send a message to BTA SYS */
+  sys_enable_event->hdr.event = BTA_SYS_API_DISABLE_EVT;
+  sys_enable_event->hw_module = BTA_SYS_HW_BLUETOOTH;
+  bta_sys_sendmsg(sys_enable_event);
+
+  bta_dm_cb.disabling = false;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_rm_cback
+ *
+ * Description      Role management callback from sys
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
+                            uint8_t app_id, BD_ADDR peer_addr) {
+  uint8_t j;
+  tBTA_PREF_ROLES role;
+  tBTA_DM_PEER_DEVICE* p_dev;
+
+  p_dev = bta_dm_find_peer_device(peer_addr);
+  if (status == BTA_SYS_CONN_OPEN) {
+    if (p_dev) {
+      /* Do not set to connected if we are in the middle of unpairing. When AV
+       * stream is
+       * started it fakes out a SYS_CONN_OPEN to potentially trigger a role
+       * switch command.
+       * But this should not be done if we are in the middle of unpairing.
+       */
+      if (p_dev->conn_state != BTA_DM_UNPAIRING)
+        p_dev->conn_state = BTA_DM_CONNECTED;
+
+      for (j = 1; j <= p_bta_dm_rm_cfg[0].app_id; j++) {
+        if (((p_bta_dm_rm_cfg[j].app_id == app_id) ||
+             (p_bta_dm_rm_cfg[j].app_id == BTA_ALL_APP_ID)) &&
+            (p_bta_dm_rm_cfg[j].id == id)) {
+          role = p_bta_dm_rm_cfg[j].cfg;
+
+          if (role > p_dev->pref_role) p_dev->pref_role = role;
+          break;
+        }
+      }
+    }
+  }
+
+  if ((BTA_ID_AV == id) || (BTA_ID_AVK == id)) {
+    if (status == BTA_SYS_CONN_BUSY) {
+      if (p_dev) p_dev->info |= BTA_DM_DI_AV_ACTIVE;
+      /* AV calls bta_sys_conn_open with the A2DP stream count as app_id */
+      if (BTA_ID_AV == id) bta_dm_cb.cur_av_count = bta_dm_get_av_count();
+    } else if (status == BTA_SYS_CONN_IDLE) {
+      if (p_dev) p_dev->info &= ~BTA_DM_DI_AV_ACTIVE;
+
+      /* get cur_av_count from connected services */
+      if (BTA_ID_AV == id) bta_dm_cb.cur_av_count = bta_dm_get_av_count();
+    }
+    APPL_TRACE_WARNING("bta_dm_rm_cback:%d, status:%d", bta_dm_cb.cur_av_count,
+                       status);
+  }
+
+  /* Don't adjust roles for each busy/idle state transition to avoid
+     excessive switch requests when individual profile busy/idle status
+     changes */
+  if ((status != BTA_SYS_CONN_BUSY) && (status != BTA_SYS_CONN_IDLE))
+    bta_dm_adjust_roles(false);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_delay_role_switch_cback
+ *
+ * Description      Callback from btm to delay a role switch
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_delay_role_switch_cback(UNUSED_ATTR void* data) {
+  APPL_TRACE_EVENT("%s: initiating Delayed RS", __func__);
+  bta_dm_adjust_roles(false);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_reset_sec_dev_pending
+ *
+ * Description      Setting the remove device pending status to false from
+ *                  security device DB, when the link key notification
+ *                  event comes.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_reset_sec_dev_pending(BD_ADDR remote_bd_addr) {
+  for (size_t i = 0; i < bta_dm_cb.device_list.count; i++) {
+    if (bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr,
+              remote_bd_addr) == 0) {
+      bta_dm_cb.device_list.peer_device[i].remove_dev_pending = false;
+      return;
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_remove_sec_dev_entry
+ *
+ * Description      Removes device entry from Security device DB if ACL
+ connection with
+ *                  remtoe device does not exist, else schedule for dev entry
+ removal upon
+                     ACL close
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr) {
+  if (BTM_IsAclConnectionUp(remote_bd_addr, BT_TRANSPORT_LE) ||
+      BTM_IsAclConnectionUp(remote_bd_addr, BT_TRANSPORT_BR_EDR)) {
+    APPL_TRACE_DEBUG(
+        "%s ACL is not down. Schedule for  Dev Removal when ACL closes",
+        __func__);
+    BTM_SecClearSecurityFlags(remote_bd_addr);
+    for (int i = 0; i < bta_dm_cb.device_list.count; i++) {
+      if (!bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr,
+                 remote_bd_addr)) {
+        bta_dm_cb.device_list.peer_device[i].remove_dev_pending = TRUE;
+        break;
+      }
+    }
+  } else {
+    BTM_SecDeleteDevice(remote_bd_addr);
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+    /* need to remove all pending background connection */
+    BTA_GATTC_CancelOpen(0, remote_bd_addr, false);
+    /* remove all cached GATT information */
+    BTA_GATTC_Refresh(remote_bd_addr);
+#endif
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_adjust_roles
+ *
+ * Description      Adjust roles
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_adjust_roles(bool delay_role_switch) {
+  uint8_t i;
+  bool set_master_role = false;
+#if (BLE_INCLUDED == TRUE)
+  uint8_t br_count =
+      bta_dm_cb.device_list.count - bta_dm_cb.device_list.le_count;
+#else
+  uint8_t br_count = bta_dm_cb.device_list.count;
+#endif
+  if (br_count) {
+    /* the configuration is no scatternet
+     * or AV connection exists and there are more than one ACL link */
+    if ((p_bta_dm_rm_cfg[0].cfg == BTA_DM_NO_SCATTERNET) ||
+        (bta_dm_cb.cur_av_count && br_count > 1)) {
+      L2CA_SetDesireRole(HCI_ROLE_MASTER);
+      set_master_role = true;
+    }
+
+    for (i = 0; i < bta_dm_cb.device_list.count; i++) {
+      if (bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_CONNECTED
+#if (BLE_INCLUDED == TRUE)
+          &&
+          bta_dm_cb.device_list.peer_device[i].transport == BT_TRANSPORT_BR_EDR
+#endif
+          ) {
+        if (!set_master_role &&
+            (bta_dm_cb.device_list.peer_device[i].pref_role != BTA_ANY_ROLE) &&
+            (p_bta_dm_rm_cfg[0].cfg == BTA_DM_PARTIAL_SCATTERNET)) {
+          L2CA_SetDesireRole(HCI_ROLE_MASTER);
+          set_master_role = true;
+        }
+
+        if ((bta_dm_cb.device_list.peer_device[i].pref_role ==
+             BTA_MASTER_ROLE_ONLY) ||
+            (br_count > 1)) {
+          /* Initiating immediate role switch with certain remote devices
+            has caused issues due to role  switch colliding with link encryption
+            setup and
+            causing encryption (and in turn the link) to fail .  These device .
+            Firmware
+            versions are stored in a blacklist and role switch with these
+            devices are
+            delayed to avoid the collision with link encryption setup */
+
+          if (bta_dm_cb.device_list.peer_device[i].pref_role !=
+                  BTA_SLAVE_ROLE_ONLY &&
+              delay_role_switch == false) {
+            BTM_SwitchRole(bta_dm_cb.device_list.peer_device[i].peer_bdaddr,
+                           HCI_ROLE_MASTER, NULL);
+          } else {
+            alarm_set_on_queue(
+                bta_dm_cb.switch_delay_timer, BTA_DM_SWITCH_DELAY_TIMER_MS,
+                bta_dm_delay_role_switch_cback, NULL, btu_bta_alarm_queue);
+          }
+        }
+      }
+    }
+
+    if (!set_master_role) {
+      L2CA_SetDesireRole(L2CAP_DESIRED_LINK_ROLE);
+    }
+
+  } else {
+    L2CA_SetDesireRole(L2CAP_DESIRED_LINK_ROLE);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_get_remname
+ *
+ * Description      Returns a pointer to the remote name stored in the DM
+ *                  control block if it exists, or from the BTM memory.
+ *
+ * Returns          char * - Pointer to the remote device name
+ ******************************************************************************/
+static char* bta_dm_get_remname(void) {
+  char* p_name = (char*)bta_dm_search_cb.peer_name;
+  char* p_temp;
+
+  /* If the name isn't already stored, try retrieving from BTM */
+  if (*p_name == '\0')
+    if ((p_temp = BTM_SecReadDevName(bta_dm_search_cb.peer_bdaddr)) != NULL)
+      p_name = p_temp;
+
+  return p_name;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_bond_cancel_complete_cback
+ *
+ * Description      Authentication complete callback from BTM
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_bond_cancel_complete_cback(tBTM_STATUS result) {
+  tBTA_DM_SEC sec_event;
+
+  if (result == BTM_SUCCESS)
+    sec_event.bond_cancel_cmpl.result = BTA_SUCCESS;
+  else
+    sec_event.bond_cancel_cmpl.result = BTA_FAILURE;
+
+  if (bta_dm_cb.p_sec_cback) {
+    bta_dm_cb.p_sec_cback(BTA_DM_BOND_CANCEL_CMPL_EVT, &sec_event);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         find_utf8_char_boundary
+ *
+ * Description      This function checks a UTF8 string |utf8str| starting at
+ *                  |offset|, moving backwards and returns the offset of the
+ *                  next valid UTF8 character boundary found.
+ *
+ * Returns          Offset of UTF8 character boundary
+ *
+ ******************************************************************************/
+static size_t find_utf8_char_boundary(const char* utf8str, size_t offset) {
+  assert(utf8str);
+  assert(offset > 0);
+
+  while (--offset) {
+    uint8_t ch = (uint8_t)utf8str[offset];
+    if ((ch & 0x80) == 0x00)  // ASCII
+      return offset + 1;
+    if ((ch & 0xC0) == 0xC0)  // Multi-byte sequence start
+      return offset;
+  }
+
+  return 0;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_set_eir
+ *
+ * Description      This function creates EIR tagged data and writes it to
+ *                  controller.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+static void bta_dm_set_eir(char* local_name) {
+  uint8_t* p;
+  uint8_t* p_length;
+#if (BTA_EIR_CANNED_UUID_LIST != TRUE)
+  uint8_t* p_type;
+  uint8_t max_num_uuid;
+#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0)
+  uint8_t custom_uuid_idx;
+#endif  // BTA_EIR_SERVER_NUM_CUSTOM_UUID
+#endif  // BTA_EIR_CANNED_UUID_LIST
+#if (BTM_EIR_DEFAULT_FEC_REQUIRED == FALSE)
+  uint8_t free_eir_length = HCI_EXT_INQ_RESPONSE_LEN;
+#else  // BTM_EIR_DEFAULT_FEC_REQUIRED
+  uint8_t free_eir_length = HCI_DM5_PACKET_SIZE;
+#endif  // BTM_EIR_DEFAULT_FEC_REQUIRED
+  uint8_t num_uuid;
+  uint8_t data_type;
+  uint8_t local_name_len;
+
+  /* wait until complete to disable */
+  if (alarm_is_scheduled(bta_dm_cb.disable_timer)) return;
+
+#if (BTA_EIR_CANNED_UUID_LIST != TRUE)
+  /* if local name is not provided, get it from controller */
+  if (local_name == NULL) {
+    if (BTM_ReadLocalDeviceName(&local_name) != BTM_SUCCESS) {
+      APPL_TRACE_ERROR("Fail to read local device name for EIR");
+    }
+  }
+#endif  // BTA_EIR_CANNED_UUID_LIST
+
+  /* Allocate a buffer to hold HCI command */
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(BTM_CMD_BUF_SIZE);
+  p = (uint8_t*)p_buf + BTM_HCI_EIR_OFFSET;
+
+  memset(p, 0x00, HCI_EXT_INQ_RESPONSE_LEN);
+
+  APPL_TRACE_DEBUG("BTA is generating EIR");
+
+  if (local_name)
+    local_name_len = strlen(local_name);
+  else
+    local_name_len = 0;
+
+  data_type = BTM_EIR_COMPLETE_LOCAL_NAME_TYPE;
+  /* if local name is longer than minimum length of shortened name */
+  /* check whether it needs to be shortened or not */
+  if (local_name_len > p_bta_dm_eir_cfg->bta_dm_eir_min_name_len) {
+/* get number of UUID 16-bit list */
+#if (BTA_EIR_CANNED_UUID_LIST == TRUE)
+    num_uuid = p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len / LEN_UUID_16;
+#else   // BTA_EIR_CANNED_UUID_LIST
+    max_num_uuid = (free_eir_length - 2) / LEN_UUID_16;
+    data_type = BTM_GetEirSupportedServices(bta_dm_cb.eir_uuid, &p,
+                                            max_num_uuid, &num_uuid);
+    p = (uint8_t*)p_buf + BTM_HCI_EIR_OFFSET; /* reset p */
+#endif  // BTA_EIR_CANNED_UUID_LIST
+
+    /* if UUID doesn't fit remaing space, shorten local name */
+    if (local_name_len > (free_eir_length - 4 - num_uuid * LEN_UUID_16)) {
+      local_name_len = find_utf8_char_boundary(
+          local_name, p_bta_dm_eir_cfg->bta_dm_eir_min_name_len);
+      APPL_TRACE_WARNING("%s local name is shortened (%d)", __func__,
+                         local_name_len);
+      data_type = BTM_EIR_SHORTENED_LOCAL_NAME_TYPE;
+    } else {
+      data_type = BTM_EIR_COMPLETE_LOCAL_NAME_TYPE;
+    }
+  }
+
+  UINT8_TO_STREAM(p, local_name_len + 1);
+  UINT8_TO_STREAM(p, data_type);
+
+  if (local_name != NULL) {
+    memcpy(p, local_name, local_name_len);
+    p += local_name_len;
+  }
+  free_eir_length -= local_name_len + 2;
+
+#if (BTA_EIR_CANNED_UUID_LIST == TRUE)
+  /* if UUID list is provided as static data in configuration */
+  if ((p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len > 0) &&
+      (p_bta_dm_eir_cfg->bta_dm_eir_uuid16)) {
+    if (free_eir_length > LEN_UUID_16 + 2) {
+      free_eir_length -= 2;
+
+      if (free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len) {
+        num_uuid = p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len / LEN_UUID_16;
+        data_type = BTM_EIR_COMPLETE_16BITS_UUID_TYPE;
+      } else /* not enough room for all UUIDs */
+      {
+        APPL_TRACE_WARNING("BTA EIR: UUID 16-bit list is truncated");
+        num_uuid = free_eir_length / LEN_UUID_16;
+        data_type = BTM_EIR_MORE_16BITS_UUID_TYPE;
+      }
+      UINT8_TO_STREAM(p, num_uuid * LEN_UUID_16 + 1);
+      UINT8_TO_STREAM(p, data_type);
+      memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_uuid16, num_uuid * LEN_UUID_16);
+      p += num_uuid * LEN_UUID_16;
+      free_eir_length -= num_uuid * LEN_UUID_16;
+    }
+  }
+#else /* (BTA_EIR_CANNED_UUID_LIST == TRUE) */
+  /* if UUID list is dynamic */
+  if (free_eir_length >= 2) {
+    p_length = p++;
+    p_type = p++;
+    num_uuid = 0;
+
+    max_num_uuid = (free_eir_length - 2) / LEN_UUID_16;
+    data_type = BTM_GetEirSupportedServices(bta_dm_cb.eir_uuid, &p,
+                                            max_num_uuid, &num_uuid);
+
+    if (data_type == BTM_EIR_MORE_16BITS_UUID_TYPE) {
+      APPL_TRACE_WARNING("BTA EIR: UUID 16-bit list is truncated");
+    }
+#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0)
+    else {
+      for (custom_uuid_idx = 0;
+           custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID;
+           custom_uuid_idx++) {
+        if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_16) {
+          if (num_uuid < max_num_uuid) {
+            UINT16_TO_STREAM(p,
+                             bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid16);
+            num_uuid++;
+          } else {
+            data_type = BTM_EIR_MORE_16BITS_UUID_TYPE;
+            APPL_TRACE_WARNING("BTA EIR: UUID 16-bit list is truncated");
+            break;
+          }
+        }
+      }
+    }
+#endif /* (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) */
+
+    UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_16 + 1);
+    UINT8_TO_STREAM(p_type, data_type);
+    free_eir_length -= num_uuid * LEN_UUID_16 + 2;
+  }
+#endif /* (BTA_EIR_CANNED_UUID_LIST == TRUE) */
+
+#if (BTA_EIR_CANNED_UUID_LIST != TRUE && BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0)
+  /* Adding 32-bit UUID list */
+  if (free_eir_length >= 2) {
+    p_length = p++;
+    p_type = p++;
+    num_uuid = 0;
+    data_type = BTM_EIR_COMPLETE_32BITS_UUID_TYPE;
+
+    max_num_uuid = (free_eir_length - 2) / LEN_UUID_32;
+
+    for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID;
+         custom_uuid_idx++) {
+      if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_32) {
+        if (num_uuid < max_num_uuid) {
+          UINT32_TO_STREAM(p, bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid32);
+          num_uuid++;
+        } else {
+          data_type = BTM_EIR_MORE_32BITS_UUID_TYPE;
+          APPL_TRACE_WARNING("BTA EIR: UUID 32-bit list is truncated");
+          break;
+        }
+      }
+    }
+
+    UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_32 + 1);
+    UINT8_TO_STREAM(p_type, data_type);
+    free_eir_length -= num_uuid * LEN_UUID_32 + 2;
+  }
+
+  /* Adding 128-bit UUID list */
+  if (free_eir_length >= 2) {
+    p_length = p++;
+    p_type = p++;
+    num_uuid = 0;
+    data_type = BTM_EIR_COMPLETE_128BITS_UUID_TYPE;
+
+    max_num_uuid = (free_eir_length - 2) / LEN_UUID_128;
+
+    for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID;
+         custom_uuid_idx++) {
+      if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_128) {
+        if (num_uuid < max_num_uuid) {
+          ARRAY16_TO_STREAM(p,
+                            bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid128);
+          num_uuid++;
+        } else {
+          data_type = BTM_EIR_MORE_128BITS_UUID_TYPE;
+          APPL_TRACE_WARNING("BTA EIR: UUID 128-bit list is truncated");
+          break;
+        }
+      }
+    }
+
+    UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_128 + 1);
+    UINT8_TO_STREAM(p_type, data_type);
+    free_eir_length -= num_uuid * LEN_UUID_128 + 2;
+  }
+#endif /* ( BTA_EIR_CANNED_UUID_LIST != TRUE \
+          )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) */
+
+  /* if Flags are provided in configuration */
+  if ((p_bta_dm_eir_cfg->bta_dm_eir_flag_len > 0) &&
+      (p_bta_dm_eir_cfg->bta_dm_eir_flags) &&
+      (free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 2)) {
+    UINT8_TO_STREAM(p, p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 1);
+    UINT8_TO_STREAM(p, BTM_EIR_FLAGS_TYPE);
+    memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_flags,
+           p_bta_dm_eir_cfg->bta_dm_eir_flag_len);
+    p += p_bta_dm_eir_cfg->bta_dm_eir_flag_len;
+    free_eir_length -= p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 2;
+  }
+
+  /* if Manufacturer Specific are provided in configuration */
+  if ((p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len > 0) &&
+      (p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec) &&
+      (free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 2)) {
+    p_length = p;
+
+    UINT8_TO_STREAM(p, p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 1);
+    UINT8_TO_STREAM(p, BTM_EIR_MANUFACTURER_SPECIFIC_TYPE);
+    memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec,
+           p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len);
+    p += p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len;
+    free_eir_length -= p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 2;
+
+  } else {
+    p_length = NULL;
+  }
+
+  /* if Inquiry Tx Resp Power compiled */
+  if ((p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power) && (free_eir_length >= 3)) {
+    UINT8_TO_STREAM(p, 2); /* Length field */
+    UINT8_TO_STREAM(p, BTM_EIR_TX_POWER_LEVEL_TYPE);
+    UINT8_TO_STREAM(p, *(p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power));
+    free_eir_length -= 3;
+  }
+
+  if (free_eir_length)
+    UINT8_TO_STREAM(p, 0); /* terminator of significant part */
+
+  BTM_WriteEIR(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_eir_search_services
+ *
+ * Description      This function searches services in received EIR
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+static void bta_dm_eir_search_services(tBTM_INQ_RESULTS* p_result,
+                                       tBTA_SERVICE_MASK* p_services_to_search,
+                                       tBTA_SERVICE_MASK* p_services_found) {
+  tBTA_SERVICE_MASK service_index = 0;
+  tBTM_EIR_SEARCH_RESULT result;
+
+  APPL_TRACE_DEBUG(
+      "BTA searching services in EIR of BDA:0x%02X%02X%02X%02X%02X%02X",
+      p_result->remote_bd_addr[0], p_result->remote_bd_addr[1],
+      p_result->remote_bd_addr[2], p_result->remote_bd_addr[3],
+      p_result->remote_bd_addr[4], p_result->remote_bd_addr[5]);
+
+  APPL_TRACE_DEBUG("    with services_to_search=0x%08X", *p_services_to_search);
+
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+  /* always do GATT based service discovery by SDP instead of from EIR    */
+  /* if GATT based service is also to be put in EIR, need to modify this  */
+  while (service_index < (BTA_MAX_SERVICE_ID - 1))
+#else
+  while (service_index < BTA_MAX_SERVICE_ID)
+#endif
+  {
+    if (*p_services_to_search &
+        (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(service_index))) {
+      result = BTM_HasInquiryEirService(
+          p_result, bta_service_id_to_uuid_lkup_tbl[service_index]);
+
+      /* Searching for HSP v1.2 only device */
+      if ((result != BTM_EIR_FOUND) &&
+          (bta_service_id_to_uuid_lkup_tbl[service_index] ==
+           UUID_SERVCLASS_HEADSET)) {
+        result = BTM_HasInquiryEirService(p_result, UUID_SERVCLASS_HEADSET_HS);
+      }
+
+      if (result == BTM_EIR_FOUND) {
+        /* If Plug and Play service record, need to check to see if Broadcom
+         * stack */
+        /* However, EIR data doesn't have EXT_BRCM_VERSION so just skip it */
+        if (bta_service_id_to_uuid_lkup_tbl[service_index] !=
+            UUID_SERVCLASS_PNP_INFORMATION) {
+          *p_services_found |= (tBTA_SERVICE_MASK)(
+              BTA_SERVICE_ID_TO_SERVICE_MASK(service_index));
+          /* remove the service from services to be searched  */
+          *p_services_to_search &= (tBTA_SERVICE_MASK)(
+              ~(BTA_SERVICE_ID_TO_SERVICE_MASK(service_index)));
+        }
+      } else if (result == BTM_EIR_NOT_FOUND) {
+        /* remove the service from services to be searched  */
+        *p_services_to_search &= (tBTA_SERVICE_MASK)(
+            ~(BTA_SERVICE_ID_TO_SERVICE_MASK(service_index)));
+      }
+    }
+
+    service_index++;
+  }
+
+  APPL_TRACE_ERROR(
+      "BTA EIR search result, services_to_search=0x%08X, services_found=0x%08X",
+      *p_services_to_search, *p_services_found);
+}
+
+#if (BTA_EIR_CANNED_UUID_LIST != TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_dm_eir_update_uuid
+ *
+ * Description      This function adds or removes service UUID in EIR database.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void bta_dm_eir_update_uuid(uint16_t uuid16, bool adding) {
+  /* if this UUID is not advertised in EIR */
+  if (!BTM_HasEirService(p_bta_dm_eir_cfg->uuid_mask, uuid16)) return;
+
+  if (adding) {
+    APPL_TRACE_EVENT("Adding UUID=0x%04X into EIR", uuid16);
+
+    BTM_AddEirService(bta_dm_cb.eir_uuid, uuid16);
+  } else {
+    APPL_TRACE_EVENT("Removing UUID=0x%04X from EIR", uuid16);
+
+    BTM_RemoveEirService(bta_dm_cb.eir_uuid, uuid16);
+  }
+
+  bta_dm_set_eir(NULL);
+
+  APPL_TRACE_EVENT("bta_dm_eir_update_uuid UUID bit mask=0x%08X %08X",
+                   bta_dm_cb.eir_uuid[1], bta_dm_cb.eir_uuid[0]);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_enable_test_mode
+ *
+ * Description      enable test mode
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_enable_test_mode(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+  BTM_EnableTestMode();
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_disable_test_mode
+ *
+ * Description      disable test mode
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_disable_test_mode(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+  BTM_DeviceReset(NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_execute_callback
+ *
+ * Description      Just execute a generic call back in the context of the
+ *                  BTU/BTA tack
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_execute_callback(tBTA_DM_MSG* p_data) {
+  /* sanity check */
+  if (p_data->exec_cback.p_exec_cback == NULL) {
+    return;
+  }
+
+  p_data->exec_cback.p_exec_cback(p_data->exec_cback.p_param);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_encrypt_cback
+ *
+ * Description      link encryption complete callback.
+ *
+ * Returns         None
+ *
+ ******************************************************************************/
+void bta_dm_encrypt_cback(BD_ADDR bd_addr, tBT_TRANSPORT transport,
+                          UNUSED_ATTR void* p_ref_data, tBTM_STATUS result) {
+  tBTA_STATUS bta_status = BTA_SUCCESS;
+  tBTA_DM_ENCRYPT_CBACK* p_callback = NULL;
+  uint8_t i;
+
+  for (i = 0; i < bta_dm_cb.device_list.count; i++) {
+    if (bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr, bd_addr) == 0 &&
+        bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_CONNECTED)
+      break;
+  }
+
+  if (i < bta_dm_cb.device_list.count) {
+    p_callback = bta_dm_cb.device_list.peer_device[i].p_encrypt_cback;
+    bta_dm_cb.device_list.peer_device[i].p_encrypt_cback = NULL;
+  }
+
+  switch (result) {
+    case BTM_SUCCESS:
+      break;
+    case BTM_WRONG_MODE:
+      bta_status = BTA_WRONG_MODE;
+      break;
+    case BTM_NO_RESOURCES:
+      bta_status = BTA_NO_RESOURCES;
+      break;
+    case BTM_BUSY:
+      bta_status = BTA_BUSY;
+      break;
+    default:
+      bta_status = BTA_FAILURE;
+      break;
+  }
+
+  APPL_TRACE_DEBUG("bta_dm_encrypt_cback status =%d p_callback=0x%x",
+                   bta_status, p_callback);
+
+  if (p_callback) {
+    (*p_callback)(bd_addr, transport, bta_status);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_set_encryption
+ *
+ * Description      This function to encrypt the link
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void bta_dm_set_encryption(tBTA_DM_MSG* p_data) {
+  uint8_t i;
+
+  APPL_TRACE_DEBUG("bta_dm_set_encryption");  // todo
+  if (!p_data->set_encryption.p_callback) {
+    APPL_TRACE_ERROR("bta_dm_set_encryption callback is not provided");
+    return;
+  }
+  for (i = 0; i < bta_dm_cb.device_list.count; i++) {
+    if (bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr,
+              p_data->set_encryption.bd_addr) == 0 &&
+        bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_CONNECTED)
+      break;
+  }
+  if (i < bta_dm_cb.device_list.count) {
+    if (bta_dm_cb.device_list.peer_device[i].p_encrypt_cback) {
+      APPL_TRACE_ERROR("earlier enc was not done for same device");
+      (*p_data->set_encryption.p_callback)(p_data->set_encryption.bd_addr,
+                                           p_data->set_encryption.transport,
+                                           BTA_BUSY);
+      return;
+    }
+
+    if (BTM_SetEncryption(p_data->set_encryption.bd_addr,
+                          p_data->set_encryption.transport,
+                          bta_dm_encrypt_cback, NULL,
+                          p_data->set_encryption.sec_act) == BTM_CMD_STARTED) {
+      bta_dm_cb.device_list.peer_device[i].p_encrypt_cback =
+          p_data->set_encryption.p_callback;
+    }
+  }
+}
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_dm_observe_results_cb
+ *
+ * Description      Callback for BLE Observe result
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_observe_results_cb(tBTM_INQ_RESULTS* p_inq, uint8_t* p_eir) {
+  ;
+  tBTA_DM_SEARCH result;
+  tBTM_INQ_INFO* p_inq_info;
+  APPL_TRACE_DEBUG("bta_dm_observe_results_cb")
+
+  bdcpy(result.inq_res.bd_addr, p_inq->remote_bd_addr);
+  result.inq_res.rssi = p_inq->rssi;
+  result.inq_res.ble_addr_type = p_inq->ble_addr_type;
+  result.inq_res.inq_result_type = p_inq->inq_result_type;
+  result.inq_res.device_type = p_inq->device_type;
+  result.inq_res.flag = p_inq->flag;
+
+  /* application will parse EIR to find out remote device name */
+  result.inq_res.p_eir = p_eir;
+
+  if ((p_inq_info = BTM_InqDbRead(p_inq->remote_bd_addr)) != NULL) {
+    /* initialize remt_name_not_required to false so that we get the name by
+     * default */
+    result.inq_res.remt_name_not_required = false;
+  }
+
+  if (bta_dm_search_cb.p_scan_cback)
+    bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_RES_EVT, &result);
+
+  if (p_inq_info) {
+    /* application indicates if it knows the remote name, inside the callback
+     copy that to the inquiry data base*/
+    if (result.inq_res.remt_name_not_required)
+      p_inq_info->appl_knows_rem_name = true;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_observe_cmpl_cb
+ *
+ * Description      Callback for BLE Observe complete
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_observe_cmpl_cb(void* p_result) {
+  tBTA_DM_SEARCH data;
+
+  APPL_TRACE_DEBUG("bta_dm_observe_cmpl_cb");
+
+  data.inq_cmpl.num_resps = ((tBTM_INQUIRY_CMPL*)p_result)->num_resp;
+  if (bta_dm_search_cb.p_scan_cback) {
+    bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_CMPL_EVT, &data);
+  }
+}
+
+#if (SMP_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_dm_ble_smp_cback
+ *
+ * Description      Callback for BLE SMP
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static uint8_t bta_dm_ble_smp_cback(tBTM_LE_EVT event, BD_ADDR bda,
+                                    tBTM_LE_EVT_DATA* p_data) {
+  tBTM_STATUS status = BTM_SUCCESS;
+  tBTA_DM_SEC sec_event;
+  char* p_name = NULL;
+
+  if (!bta_dm_cb.p_sec_cback) return BTM_NOT_AUTHORIZED;
+
+  memset(&sec_event, 0, sizeof(tBTA_DM_SEC));
+  switch (event) {
+    case BTM_LE_IO_REQ_EVT:
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+
+      bta_dm_co_ble_io_req(
+          bda, &p_data->io_req.io_cap, &p_data->io_req.oob_data,
+          &p_data->io_req.auth_req, &p_data->io_req.max_key_size,
+          &p_data->io_req.init_keys, &p_data->io_req.resp_keys);
+#endif
+      APPL_TRACE_EVENT("io mitm: %d oob_data:%d", p_data->io_req.auth_req,
+                       p_data->io_req.oob_data);
+
+      break;
+
+    case BTM_LE_SEC_REQUEST_EVT:
+      bdcpy(sec_event.ble_req.bd_addr, bda);
+      p_name = BTM_SecReadDevName(bda);
+      if (p_name != NULL)
+        strlcpy((char*)sec_event.ble_req.bd_name, p_name, BD_NAME_LEN);
+      else
+        sec_event.ble_req.bd_name[0] = 0;
+      bta_dm_cb.p_sec_cback(BTA_DM_BLE_SEC_REQ_EVT, &sec_event);
+      break;
+
+    case BTM_LE_KEY_NOTIF_EVT:
+      bdcpy(sec_event.key_notif.bd_addr, bda);
+      p_name = BTM_SecReadDevName(bda);
+      if (p_name != NULL)
+        strlcpy((char*)sec_event.key_notif.bd_name, p_name, BD_NAME_LEN);
+      else
+        sec_event.key_notif.bd_name[0] = 0;
+      sec_event.key_notif.passkey = p_data->key_notif;
+      bta_dm_cb.p_sec_cback(BTA_DM_BLE_PASSKEY_NOTIF_EVT, &sec_event);
+      break;
+
+    case BTM_LE_KEY_REQ_EVT:
+      bdcpy(sec_event.ble_req.bd_addr, bda);
+      bta_dm_cb.p_sec_cback(BTA_DM_BLE_PASSKEY_REQ_EVT, &sec_event);
+      break;
+
+    case BTM_LE_OOB_REQ_EVT:
+      bdcpy(sec_event.ble_req.bd_addr, bda);
+      bta_dm_cb.p_sec_cback(BTA_DM_BLE_OOB_REQ_EVT, &sec_event);
+      break;
+
+    case BTM_LE_NC_REQ_EVT:
+      bdcpy(sec_event.key_notif.bd_addr, bda);
+      strlcpy((char*)sec_event.key_notif.bd_name, bta_dm_get_remname(),
+              (BD_NAME_LEN));
+      sec_event.key_notif.passkey = p_data->key_notif;
+      bta_dm_cb.p_sec_cback(BTA_DM_BLE_NC_REQ_EVT, &sec_event);
+      break;
+
+    case BTM_LE_SC_OOB_REQ_EVT:
+      bdcpy(sec_event.ble_req.bd_addr, bda);
+      bta_dm_cb.p_sec_cback(BTA_DM_BLE_SC_OOB_REQ_EVT, &sec_event);
+      break;
+
+    case BTM_LE_KEY_EVT:
+      bdcpy(sec_event.ble_key.bd_addr, bda);
+      sec_event.ble_key.key_type = p_data->key.key_type;
+      sec_event.ble_key.p_key_value = p_data->key.p_key_value;
+      bta_dm_cb.p_sec_cback(BTA_DM_BLE_KEY_EVT, &sec_event);
+      break;
+
+    case BTM_LE_COMPLT_EVT:
+      bdcpy(sec_event.auth_cmpl.bd_addr, bda);
+#if (BLE_INCLUDED == TRUE)
+      BTM_ReadDevInfo(bda, &sec_event.auth_cmpl.dev_type,
+                      &sec_event.auth_cmpl.addr_type);
+#endif
+      p_name = BTM_SecReadDevName(bda);
+      if (p_name != NULL)
+        strlcpy((char*)sec_event.auth_cmpl.bd_name, p_name, (BD_NAME_LEN));
+      else
+        sec_event.auth_cmpl.bd_name[0] = 0;
+
+      if (p_data->complt.reason != 0) {
+        sec_event.auth_cmpl.fail_reason =
+            BTA_DM_AUTH_CONVERT_SMP_CODE(((uint8_t)p_data->complt.reason));
+        /* delete this device entry from Sec Dev DB */
+        bta_dm_remove_sec_dev_entry(bda);
+      } else {
+        sec_event.auth_cmpl.success = true;
+      }
+
+      if (bta_dm_cb.p_sec_cback) {
+        // bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);
+        bta_dm_cb.p_sec_cback(BTA_DM_BLE_AUTH_CMPL_EVT, &sec_event);
+      }
+      break;
+
+    default:
+      status = BTM_NOT_AUTHORIZED;
+      break;
+  }
+  return status;
+}
+#endif /* SMP_INCLUDED == TRUE */
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_ble_id_key_cback
+ *
+ * Description      Callback for BLE local ID keys
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_ble_id_key_cback(uint8_t key_type,
+                                    tBTM_BLE_LOCAL_KEYS* p_key) {
+  uint8_t evt;
+  tBTA_DM_SEC dm_key;
+
+  switch (key_type) {
+    case BTM_BLE_KEY_TYPE_ID:
+    case BTM_BLE_KEY_TYPE_ER:
+      if (bta_dm_cb.p_sec_cback) {
+        memcpy(&dm_key.ble_id_keys, p_key, sizeof(tBTM_BLE_LOCAL_KEYS));
+
+        evt = (key_type == BTM_BLE_KEY_TYPE_ID) ? BTA_DM_BLE_LOCAL_IR_EVT
+                                                : BTA_DM_BLE_LOCAL_ER_EVT;
+        bta_dm_cb.p_sec_cback(evt, &dm_key);
+      }
+      break;
+
+    default:
+      APPL_TRACE_DEBUG("Unknown key type %d", key_type);
+      break;
+  }
+  return;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_add_blekey
+ *
+ * Description      This function adds an BLE Key to an security database entry.
+ *                  This function shall only be called AFTER BTA_DmAddBleDevice
+ *                  has been called.
+ *                  It is normally called during host startup to restore all
+ *                  required information stored in the NVRAM.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_add_blekey(tBTA_DM_MSG* p_data) {
+  if (!BTM_SecAddBleKey(p_data->add_ble_key.bd_addr,
+                        (tBTM_LE_KEY_VALUE*)&p_data->add_ble_key.blekey,
+                        p_data->add_ble_key.key_type)) {
+    APPL_TRACE_ERROR(
+        "BTA_DM: Error adding BLE Key for device %08x%04x",
+        (p_data->add_ble_key.bd_addr[0] << 24) +
+            (p_data->add_ble_key.bd_addr[1] << 16) +
+            (p_data->add_ble_key.bd_addr[2] << 8) +
+            p_data->add_ble_key.bd_addr[3],
+        (p_data->add_ble_key.bd_addr[4] << 8) + p_data->add_ble_key.bd_addr[5]);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_add_ble_device
+ *
+ * Description      This function adds an BLE device to an security database
+ *                  entry.
+ *                  It is normally called during host startup to restore all
+ *                  required information stored in the NVRAM.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_add_ble_device(tBTA_DM_MSG* p_data) {
+  if (!BTM_SecAddBleDevice(p_data->add_ble_device.bd_addr, NULL,
+                           p_data->add_ble_device.dev_type,
+                           p_data->add_ble_device.addr_type)) {
+    APPL_TRACE_ERROR("BTA_DM: Error adding BLE Device for device %08x%04x",
+                     (p_data->add_ble_device.bd_addr[0] << 24) +
+                         (p_data->add_ble_device.bd_addr[1] << 16) +
+                         (p_data->add_ble_device.bd_addr[2] << 8) +
+                         p_data->add_ble_device.bd_addr[3],
+                     (p_data->add_ble_device.bd_addr[4] << 8) +
+                         p_data->add_ble_device.bd_addr[5]);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_add_ble_device
+ *
+ * Description      This function adds an BLE device to an security database
+ *                  entry.
+ *                  It is normally called during host startup to restore all
+ *                  required information stored in the NVRAM.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_passkey_reply(tBTA_DM_MSG* p_data) {
+  if (p_data->pin_reply.accept) {
+    BTM_BlePasskeyReply(p_data->ble_passkey_reply.bd_addr, BTM_SUCCESS,
+                        p_data->ble_passkey_reply.passkey);
+  } else {
+    BTM_BlePasskeyReply(p_data->ble_passkey_reply.bd_addr, BTM_NOT_AUTHORIZED,
+                        p_data->ble_passkey_reply.passkey);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_ble_confirm_reply
+ *
+ * Description      This is response to SM numeric comparison request submitted
+ *                  to application.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_confirm_reply(tBTA_DM_MSG* p_data) {
+  if (p_data->confirm.accept) {
+    BTM_BleConfirmReply(p_data->confirm.bd_addr, BTM_SUCCESS);
+  } else {
+    BTM_BleConfirmReply(p_data->ble_passkey_reply.bd_addr, BTM_NOT_AUTHORIZED);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_security_grant
+ *
+ * Description      This function grant SMP security request access.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_security_grant(tBTA_DM_MSG* p_data) {
+  BTM_SecurityGrant(p_data->ble_sec_grant.bd_addr, p_data->ble_sec_grant.res);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_ble_set_bg_conn_type
+ *
+ * Description      This function set the BLE background connection type
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_set_bg_conn_type(tBTA_DM_MSG* p_data) {
+  BTM_BleSetBgConnType(p_data->ble_set_bd_conn_type.bg_conn_type,
+                       p_data->ble_set_bd_conn_type.p_select_cback);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_ble_set_conn_params
+ *
+ * Description      This function set the preferred connection parameters.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_set_conn_params(tBTA_DM_MSG* p_data) {
+  BTM_BleSetPrefConnParams(p_data->ble_set_conn_params.peer_bda,
+                           p_data->ble_set_conn_params.conn_int_min,
+                           p_data->ble_set_conn_params.conn_int_max,
+                           p_data->ble_set_conn_params.slave_latency,
+                           p_data->ble_set_conn_params.supervision_tout);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_ble_set_conn_scan_params
+ *
+ * Description      This function sets BLE scan parameters.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_set_scan_params(tBTA_DM_MSG* p_data) {
+  BTM_BleSetScanParams(p_data->ble_set_scan_params.client_if,
+                       p_data->ble_set_scan_params.scan_int,
+                       p_data->ble_set_scan_params.scan_window,
+                       p_data->ble_set_scan_params.scan_mode,
+                       p_data->ble_set_scan_params.scan_param_setup_cback);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_ble_set_conn_scan_params
+ *
+ * Description      This function set the preferred connection scan parameters.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_set_conn_scan_params(tBTA_DM_MSG* p_data) {
+  BTM_BleSetConnScanParams(p_data->ble_set_conn_scan_params.scan_int,
+                           p_data->ble_set_conn_scan_params.scan_window);
+}
+/*******************************************************************************
+ *
+ * Function         bta_dm_ble_update_conn_params
+ *
+ * Description      This function update LE connection parameters.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_update_conn_params(tBTA_DM_MSG* p_data) {
+  if (!L2CA_UpdateBleConnParams(p_data->ble_update_conn_params.bd_addr,
+                                p_data->ble_update_conn_params.min_int,
+                                p_data->ble_update_conn_params.max_int,
+                                p_data->ble_update_conn_params.latency,
+                                p_data->ble_update_conn_params.timeout)) {
+    APPL_TRACE_ERROR("Update connection parameters failed!");
+  }
+}
+
+#if (BLE_PRIVACY_SPT == TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_dm_ble_config_local_privacy
+ *
+ * Description      This function set the local device LE privacy settings.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_config_local_privacy(tBTA_DM_MSG* p_data) {
+  BTM_BleConfigPrivacy(p_data->ble_local_privacy.privacy_enable);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_ble_observe
+ *
+ * Description      This function set the preferred connection scan parameters.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_observe(tBTA_DM_MSG* p_data) {
+  tBTM_STATUS status;
+  if (p_data->ble_observe.start) {
+    /*Save the  callback to be called when a scan results are available */
+    bta_dm_search_cb.p_scan_cback = p_data->ble_observe.p_cback;
+    if ((status = BTM_BleObserve(true, p_data->ble_observe.duration,
+                                 bta_dm_observe_results_cb,
+                                 bta_dm_observe_cmpl_cb)) != BTM_CMD_STARTED) {
+      tBTA_DM_SEARCH data;
+      APPL_TRACE_WARNING(" %s BTM_BleObserve  failed. status %d", __func__,
+                         status);
+      data.inq_cmpl.num_resps = 0;
+      if (bta_dm_search_cb.p_scan_cback) {
+        bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_CMPL_EVT, &data);
+      }
+    }
+  } else {
+    bta_dm_search_cb.p_scan_cback = NULL;
+    BTM_BleObserve(false, 0, NULL, NULL);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_dm_ble_set_adv_params
+ *
+ * Description      This function set the adv parameters.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_set_adv_params(uint16_t adv_int_min, uint16_t adv_int_max,
+                               tBLE_BD_ADDR* p_dir_bda) {
+  BTM_BleSetAdvParams(adv_int_min, adv_int_max, p_dir_bda,
+                      BTA_DM_BLE_ADV_CHNL_MAP);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_ble_set_data_length
+ *
+ * Description      This function set the maximum transmission packet size
+ *
+ * Parameters
+ *
+ ******************************************************************************/
+void bta_dm_ble_set_data_length(tBTA_DM_MSG* p_data) {
+  if (BTM_SetBleDataLength(p_data->ble_set_data_length.remote_bda,
+                           p_data->ble_set_data_length.tx_data_length) !=
+      BTM_SUCCESS) {
+    APPL_TRACE_ERROR("%s failed", __func__);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_ble_setup_storage
+ *
+ * Description      This function configures up the storage parameters for ADV
+ *                  batch scanning
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_setup_storage(tBTA_DM_MSG* p_data) {
+  tBTM_STATUS btm_status = 0;
+  tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+
+  BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+  if (0 != cmn_ble_vsc_cb.tot_scan_results_strg) {
+    btm_status = BTM_BleSetStorageConfig(
+        p_data->ble_set_storage.batch_scan_full_max,
+        p_data->ble_set_storage.batch_scan_trunc_max,
+        p_data->ble_set_storage.batch_scan_notify_threshold,
+        p_data->ble_set_storage.p_setup_cback,
+        p_data->ble_set_storage.p_thres_cback,
+        p_data->ble_set_storage.p_read_rep_cback,
+        p_data->ble_set_storage.ref_value);
+  }
+
+  if (BTM_CMD_STARTED != btm_status)
+    bta_ble_scan_setup_cb(BTM_BLE_BATCH_SCAN_CFG_STRG_EVT,
+                          p_data->ble_set_storage.ref_value, btm_status);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_ble_enable_batch_scan
+ *
+ * Description      This function sets up the parameters and enables batch scan
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_enable_batch_scan(tBTA_DM_MSG* p_data) {
+  tBTM_STATUS btm_status = 0;
+  tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+
+  BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+  if (0 != cmn_ble_vsc_cb.tot_scan_results_strg) {
+    btm_status = BTM_BleEnableBatchScan(
+        p_data->ble_enable_scan.scan_mode, p_data->ble_enable_scan.scan_int,
+        p_data->ble_enable_scan.scan_window,
+        p_data->ble_enable_scan.discard_rule, p_data->ble_enable_scan.addr_type,
+        p_data->ble_enable_scan.ref_value);
+  }
+
+  if (BTM_CMD_STARTED != btm_status)
+    bta_ble_scan_setup_cb(BTM_BLE_BATCH_SCAN_ENABLE_EVT,
+                          p_data->ble_enable_scan.ref_value, btm_status);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_ble_disable_batch_scan
+ *
+ * Description      This function disables the batch scan
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_disable_batch_scan(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+  tBTM_STATUS btm_status = 0;
+  tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+
+  BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+  if (0 != cmn_ble_vsc_cb.tot_scan_results_strg) {
+    btm_status = BTM_BleDisableBatchScan(p_data->ble_disable_scan.ref_value);
+  }
+
+  if (BTM_CMD_STARTED != btm_status)
+    bta_ble_scan_setup_cb(BTM_BLE_BATCH_SCAN_DISABLE_EVT,
+                          p_data->ble_enable_scan.ref_value, btm_status);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_ble_read_scan_reports
+ *
+ * Description      This function reads the batch scan reports
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_read_scan_reports(tBTA_DM_MSG* p_data) {
+  tBTM_STATUS btm_status = 0;
+  tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+
+  BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+  if (0 != cmn_ble_vsc_cb.tot_scan_results_strg) {
+    btm_status = BTM_BleReadScanReports(p_data->ble_read_reports.scan_type,
+                                        p_data->ble_read_reports.ref_value);
+  }
+
+  if (BTM_CMD_STARTED != btm_status)
+    bta_ble_scan_setup_cb(BTM_BLE_BATCH_SCAN_READ_REPTS_EVT,
+                          p_data->ble_enable_scan.ref_value, btm_status);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_ble_track_advertiser
+ *
+ * Description      This function tracks the specific advertiser
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_track_advertiser(tBTA_DM_MSG* p_data) {
+  tBTM_STATUS btm_status = 0;
+  BD_ADDR bda;
+  memset(&bda, 0, sizeof(BD_ADDR));
+  tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+  tBTA_DM_BLE_TRACK_ADV_DATA track_adv_data;
+
+  BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+  if (0 != cmn_ble_vsc_cb.tot_scan_results_strg) {
+    btm_status = BTM_BleTrackAdvertiser(
+        (tBTM_BLE_TRACK_ADV_CBACK*)p_data->ble_track_advert.p_track_adv_cback,
+        p_data->ble_track_advert.ref_value);
+  }
+
+  if (BTM_CMD_STARTED != btm_status) {
+    memset(&track_adv_data, 0, sizeof(tBTA_DM_BLE_TRACK_ADV_DATA));
+    track_adv_data.advertiser_info_present =
+        NO_ADV_INFO_PRESENT; /* Indicates failure */
+    track_adv_data.client_if = (uint8_t)p_data->ble_track_advert.ref_value;
+    p_data->ble_track_advert.p_track_adv_cback(&track_adv_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ble_scan_setup_cb
+ *
+ * Description      Handle the setup callback from BTM layer and forward it to
+ *                  app layer
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_ble_scan_setup_cb(tBTM_BLE_BATCH_SCAN_EVT evt,
+                           tBTM_BLE_REF_VALUE ref_value, tBTM_STATUS status) {
+  tBTA_BLE_BATCH_SCAN_EVT bta_evt = 0;
+
+  APPL_TRACE_DEBUG("bta_ble_scan_setup_cb : evt: %d, ref_value: %d, status:%d",
+                   evt, ref_value, status);
+
+  switch (evt) {
+    case BTM_BLE_BATCH_SCAN_ENABLE_EVT:
+      bta_evt = BTA_BLE_BATCH_SCAN_ENB_EVT;
+      break;
+    case BTM_BLE_BATCH_SCAN_CFG_STRG_EVT:
+      bta_evt = BTA_BLE_BATCH_SCAN_CFG_STRG_EVT;
+      break;
+    case BTM_BLE_BATCH_SCAN_DISABLE_EVT:
+      bta_evt = BTA_BLE_BATCH_SCAN_DIS_EVT;
+      break;
+    case BTM_BLE_BATCH_SCAN_PARAM_EVT:
+      bta_evt = BTA_BLE_BATCH_SCAN_PARAM_EVT;
+      break;
+    default:
+      break;
+  }
+
+  if (NULL != bta_dm_cb.p_setup_cback)
+    bta_dm_cb.p_setup_cback(bta_evt, ref_value, status);
+}
+
+#if (BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_ble_scan_pf_cmpl
+ *
+ * Description      ADV payload filtering operation complete callback
+ *
+ *
+ * Returns         true if handled, otherwise false.
+ *
+ ******************************************************************************/
+static void bta_ble_scan_cfg_cmpl(tBTM_BLE_PF_ACTION action,
+                                  tBTM_BLE_SCAN_COND_OP cfg_op,
+                                  tBTM_BLE_PF_AVBL_SPACE avbl_space,
+                                  tBTM_STATUS status,
+                                  tBTM_BLE_REF_VALUE ref_value) {
+  tBTA_STATUS st = (status == BTM_SUCCESS) ? BTA_SUCCESS : BTA_FAILURE;
+
+  APPL_TRACE_DEBUG("bta_ble_scan_cfg_cmpl: %d, %d, %d, %d", action, cfg_op,
+                   avbl_space, status);
+
+  if (bta_dm_cb.p_scan_filt_cfg_cback)
+    bta_dm_cb.p_scan_filt_cfg_cback(action, cfg_op, avbl_space, st, ref_value);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_cfg_filter_cond
+ *
+ * Description      This function configure adv payload filtering condition
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_cfg_filter_cond(tBTA_DM_MSG* p_data) {
+  tBTM_STATUS st = BTM_MODE_UNSUPPORTED;
+  tBTA_STATUS status = BTA_FAILURE;
+
+  tBTM_BLE_VSC_CB cmn_vsc_cb;
+
+  APPL_TRACE_DEBUG("bta_dm_cfg_filter_cond");
+  BTM_BleGetVendorCapabilities(&cmn_vsc_cb);
+  if (0 != cmn_vsc_cb.filter_support) {
+    if ((st = BTM_BleCfgFilterCondition(
+             p_data->ble_cfg_filter_cond.action,
+             p_data->ble_cfg_filter_cond.cond_type,
+             (tBTM_BLE_PF_FILT_INDEX)p_data->ble_cfg_filter_cond.filt_index,
+             (tBTM_BLE_PF_COND_PARAM*)p_data->ble_cfg_filter_cond.p_cond_param,
+             bta_ble_scan_cfg_cmpl, p_data->ble_cfg_filter_cond.ref_value)) ==
+        BTM_CMD_STARTED) {
+      bta_dm_cb.p_scan_filt_cfg_cback =
+          p_data->ble_cfg_filter_cond.p_filt_cfg_cback;
+      return;
+    }
+  }
+
+  if (p_data->ble_cfg_filter_cond.p_filt_cfg_cback)
+    p_data->ble_cfg_filter_cond.p_filt_cfg_cback(
+        BTA_DM_BLE_PF_CONFIG_EVT, p_data->ble_cfg_filter_cond.cond_type, 0,
+        status, p_data->ble_cfg_filter_cond.ref_value);
+  return;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_enable_scan_filter
+ *
+ * Description      This function enable/disable adv payload filtering condition
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_enable_scan_filter(tBTA_DM_MSG* p_data) {
+  tBTM_STATUS st = BTM_MODE_UNSUPPORTED;
+  tBTA_STATUS status = BTA_FAILURE;
+
+  tBTM_BLE_VSC_CB cmn_vsc_cb;
+  APPL_TRACE_DEBUG("bta_dm_enable_scan_filter");
+  BTM_BleGetVendorCapabilities(&cmn_vsc_cb);
+
+  if (0 != cmn_vsc_cb.filter_support) {
+    if ((st = BTM_BleEnableDisableFilterFeature(
+             p_data->ble_enable_scan_filt.action,
+             p_data->ble_enable_scan_filt.p_filt_status_cback,
+             (tBTM_BLE_REF_VALUE)p_data->ble_enable_scan_filt.ref_value)) ==
+        BTM_CMD_STARTED)
+      bta_dm_cb.p_scan_filt_status_cback =
+          p_data->ble_enable_scan_filt.p_filt_status_cback;
+    return;
+  }
+
+  if (p_data->ble_enable_scan_filt.p_filt_status_cback)
+    p_data->ble_enable_scan_filt.p_filt_status_cback(
+        BTA_DM_BLE_PF_ENABLE_EVT, p_data->ble_enable_scan_filt.ref_value,
+        status);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_scan_filter_param_setup
+ *
+ * Description      This function sets up scan filter params
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_scan_filter_param_setup(tBTA_DM_MSG* p_data) {
+  tBTM_STATUS st = BTM_MODE_UNSUPPORTED;
+  tBTA_STATUS status = BTA_FAILURE;
+
+  tBTM_BLE_VSC_CB cmn_vsc_cb;
+
+  APPL_TRACE_DEBUG("bta_dm_scan_filter_param_setup");
+  BTM_BleGetVendorCapabilities(&cmn_vsc_cb);
+  if (0 != cmn_vsc_cb.filter_support) {
+    if ((st = BTM_BleAdvFilterParamSetup(
+             p_data->ble_scan_filt_param_setup.action,
+             p_data->ble_scan_filt_param_setup.filt_index,
+             (tBTM_BLE_PF_FILT_PARAMS*)&p_data->ble_scan_filt_param_setup
+                 .filt_params,
+             p_data->ble_scan_filt_param_setup.p_target,
+             p_data->ble_scan_filt_param_setup.p_filt_param_cback,
+             p_data->ble_scan_filt_param_setup.ref_value)) == BTM_CMD_STARTED) {
+      bta_dm_cb.p_scan_filt_param_cback =
+          p_data->ble_scan_filt_param_setup.p_filt_param_cback;
+      return;
+    }
+  }
+
+  if (p_data->ble_scan_filt_param_setup.p_filt_param_cback)
+    p_data->ble_scan_filt_param_setup.p_filt_param_cback(
+        BTA_DM_BLE_PF_ENABLE_EVT, 0,
+        p_data->ble_scan_filt_param_setup.ref_value, status);
+
+  return;
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_ble_enable_scan_cmpl
+ *
+ * Description      ADV payload filtering enable / disable complete callback
+ *
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+static void bta_ble_energy_info_cmpl(tBTM_BLE_TX_TIME_MS tx_time,
+                                     tBTM_BLE_RX_TIME_MS rx_time,
+                                     tBTM_BLE_IDLE_TIME_MS idle_time,
+                                     tBTM_BLE_ENERGY_USED energy_used,
+                                     tBTM_STATUS status) {
+  tBTA_STATUS st = (status == BTM_SUCCESS) ? BTA_SUCCESS : BTA_FAILURE;
+  tBTA_DM_CONTRL_STATE ctrl_state = 0;
+
+  if (BTA_SUCCESS == st) ctrl_state = bta_dm_pm_obtain_controller_state();
+
+  if (bta_dm_cb.p_energy_info_cback)
+    bta_dm_cb.p_energy_info_cback(tx_time, rx_time, idle_time, energy_used,
+                                  ctrl_state, st);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_ble_get_energy_info
+ *
+ * Description      This function obtains the energy info
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_get_energy_info(tBTA_DM_MSG* p_data) {
+  tBTM_STATUS btm_status = 0;
+
+  bta_dm_cb.p_energy_info_cback = p_data->ble_energy_info.p_energy_info_cback;
+  btm_status = BTM_BleGetEnergyInfo(bta_ble_energy_info_cmpl);
+  if (BTM_CMD_STARTED != btm_status)
+    bta_ble_energy_info_cmpl(0, 0, 0, 0, btm_status);
+}
+
+#if (BTA_GATT_INCLUDED == TRUE)
+#ifndef BTA_DM_GATT_CLOSE_DELAY_TOUT
+#define BTA_DM_GATT_CLOSE_DELAY_TOUT 1000
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_gattc_register
+ *
+ * Description      Register with GATTC in DM if BLE is needed.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_gattc_register(void) {
+  tBT_UUID app_uuid = {LEN_UUID_128, {0}};
+
+  if (bta_dm_search_cb.client_if == BTA_GATTS_INVALID_IF) {
+    memset(&app_uuid.uu.uuid128, 0x87, LEN_UUID_128);
+    BTA_GATTC_AppRegister(&app_uuid, bta_dm_gattc_callback);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btm_dm_start_disc_gatt_services
+ *
+ * Description      This function starts a GATT service search request.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+static void btm_dm_start_disc_gatt_services(uint16_t conn_id) {
+  tBT_UUID* p_uuid = bta_dm_search_cb.p_srvc_uuid + bta_dm_search_cb.num_uuid -
+                     bta_dm_search_cb.uuid_to_search;
+
+  p_uuid = bta_dm_search_cb.p_srvc_uuid + bta_dm_search_cb.num_uuid -
+           bta_dm_search_cb.uuid_to_search;
+
+  /* always search for all services */
+  BTA_GATTC_ServiceSearchRequest(conn_id, p_uuid);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_gatt_disc_result
+ *
+ * Description      This function process the GATT service search result.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+static void bta_dm_gatt_disc_result(tBTA_GATT_ID service_id) {
+  tBTA_DM_SEARCH result;
+
+  /*
+      * This logic will not work for gatt case.  We are checking against the
+   * bluetooth profiles here
+      * just copy the GATTID in raw data field and send it across.
+      */
+
+  if (bta_dm_search_cb.ble_raw_used + sizeof(tBTA_GATT_ID) <
+      bta_dm_search_cb.ble_raw_size) {
+    APPL_TRACE_DEBUG(
+        "ADDING BLE SERVICE uuid=0x%x, ble_ptr = 0x%x, ble_raw_used = 0x%x",
+        service_id.uuid.uu.uuid16, bta_dm_search_cb.p_ble_rawdata,
+        bta_dm_search_cb.ble_raw_used);
+
+    if (bta_dm_search_cb.p_ble_rawdata) {
+      memcpy((bta_dm_search_cb.p_ble_rawdata + bta_dm_search_cb.ble_raw_used),
+             &service_id, sizeof(service_id));
+
+      bta_dm_search_cb.ble_raw_used += sizeof(service_id);
+    } else {
+      APPL_TRACE_ERROR("p_ble_rawdata is NULL");
+    }
+
+  } else {
+    APPL_TRACE_ERROR(
+        "%s out of room to accomodate more service ids ble_raw_size = %d "
+        "ble_raw_used = %d",
+        __func__, bta_dm_search_cb.ble_raw_size, bta_dm_search_cb.ble_raw_used);
+  }
+
+  LOG_INFO(LOG_TAG, "%s service_id_uuid_len=%d ", __func__,
+           service_id.uuid.len);
+  if (bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE) {
+    /* send result back to app now, one by one */
+    bdcpy(result.disc_ble_res.bd_addr, bta_dm_search_cb.peer_bdaddr);
+    strlcpy((char*)result.disc_ble_res.bd_name, bta_dm_get_remname(),
+            BD_NAME_LEN);
+    memcpy(&result.disc_ble_res.service, &service_id.uuid, sizeof(tBT_UUID));
+
+    bta_dm_search_cb.p_search_cback(BTA_DM_DISC_BLE_RES_EVT, &result);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_gatt_disc_complete
+ *
+ * Description      This function process the GATT service search complete.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+static void bta_dm_gatt_disc_complete(uint16_t conn_id,
+                                      tBTA_GATT_STATUS status) {
+  APPL_TRACE_DEBUG("%s conn_id = %d", __func__, conn_id);
+
+  if (bta_dm_search_cb.uuid_to_search > 0) bta_dm_search_cb.uuid_to_search--;
+
+  if (status == BTA_GATT_OK && bta_dm_search_cb.uuid_to_search > 0) {
+    btm_dm_start_disc_gatt_services(conn_id);
+  } else {
+    tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+
+    bta_dm_search_cb.uuid_to_search = 0;
+
+    /* no more services to be discovered */
+    p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
+    p_msg->disc_result.result.disc_res.result =
+        (status == BTA_GATT_OK) ? BTA_SUCCESS : BTA_FAILURE;
+    APPL_TRACE_DEBUG("%s service found: 0x%08x", __func__,
+                     bta_dm_search_cb.services_found);
+    p_msg->disc_result.result.disc_res.services =
+        bta_dm_search_cb.services_found;
+    p_msg->disc_result.result.disc_res.num_uuids = 0;
+    p_msg->disc_result.result.disc_res.p_uuid_list = NULL;
+    bdcpy(p_msg->disc_result.result.disc_res.bd_addr,
+          bta_dm_search_cb.peer_bdaddr);
+    strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name,
+            bta_dm_get_remname(), BD_NAME_LEN);
+
+    p_msg->disc_result.result.disc_res.device_type |= BT_DEVICE_TYPE_BLE;
+    if (bta_dm_search_cb.ble_raw_used > 0) {
+      p_msg->disc_result.result.disc_res.p_raw_data =
+          (uint8_t*)osi_malloc(bta_dm_search_cb.ble_raw_used);
+
+      memcpy(p_msg->disc_result.result.disc_res.p_raw_data,
+             bta_dm_search_cb.p_ble_rawdata, bta_dm_search_cb.ble_raw_used);
+
+      p_msg->disc_result.result.disc_res.raw_data_size =
+          bta_dm_search_cb.ble_raw_used;
+    } else {
+      p_msg->disc_result.result.disc_res.p_raw_data = NULL;
+      bta_dm_search_cb.p_ble_rawdata = 0;
+    }
+
+    bta_sys_sendmsg(p_msg);
+
+    if (conn_id != BTA_GATT_INVALID_CONN_ID) {
+      /* start a GATT channel close delay timer */
+      bta_sys_start_timer(bta_dm_search_cb.gatt_close_timer,
+                          BTA_DM_GATT_CLOSE_DELAY_TOUT,
+                          BTA_DM_DISC_CLOSE_TOUT_EVT, 0);
+      bdcpy(bta_dm_search_cb.pending_close_bda, bta_dm_search_cb.peer_bdaddr);
+    }
+    bta_dm_search_cb.gatt_disc_active = false;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_close_gatt_conn
+ *
+ * Description      This function close the GATT connection after delay timeout.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_close_gatt_conn(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+  if (bta_dm_search_cb.conn_id != BTA_GATT_INVALID_CONN_ID)
+    BTA_GATTC_Close(bta_dm_search_cb.conn_id);
+
+  memset(bta_dm_search_cb.pending_close_bda, 0, BD_ADDR_LEN);
+  bta_dm_search_cb.conn_id = BTA_GATT_INVALID_CONN_ID;
+}
+/*******************************************************************************
+ *
+ * Function         btm_dm_start_gatt_discovery
+ *
+ * Description      This is GATT initiate the service search by open a GATT
+ *                  connection first.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void btm_dm_start_gatt_discovery(BD_ADDR bd_addr) {
+  bta_dm_search_cb.gatt_disc_active = true;
+
+  /* connection is already open */
+  if (bdcmp(bta_dm_search_cb.pending_close_bda, bd_addr) == 0 &&
+      bta_dm_search_cb.conn_id != BTA_GATT_INVALID_CONN_ID) {
+    memset(bta_dm_search_cb.pending_close_bda, 0, BD_ADDR_LEN);
+    alarm_cancel(bta_dm_search_cb.gatt_close_timer);
+    btm_dm_start_disc_gatt_services(bta_dm_search_cb.conn_id);
+  } else
+    BTA_GATTC_Open(bta_dm_search_cb.client_if, bd_addr, true,
+                   BTA_GATT_TRANSPORT_LE);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_cancel_gatt_discovery
+ *
+ * Description      This is GATT cancel the GATT service search.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+static void bta_dm_cancel_gatt_discovery(BD_ADDR bd_addr) {
+  if (bta_dm_search_cb.conn_id == BTA_GATT_INVALID_CONN_ID) {
+    BTA_GATTC_CancelOpen(bta_dm_search_cb.client_if, bd_addr, true);
+  }
+
+  bta_dm_gatt_disc_complete(bta_dm_search_cb.conn_id,
+                            (tBTA_GATT_STATUS)BTA_GATT_ERROR);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_proc_open_evt
+ *
+ * Description      process BTA_GATTC_OPEN_EVT in DM.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_proc_open_evt(tBTA_GATTC_OPEN* p_data) {
+  uint8_t* p1;
+  uint8_t* p2;
+
+  p1 = bta_dm_search_cb.peer_bdaddr;
+  p2 = p_data->remote_bda;
+
+  APPL_TRACE_DEBUG(
+      "DM Search state= %d search_cb.peer_dbaddr: [%08x%04x] connected_bda= "
+      "[%08x%04x] ",
+      bta_dm_search_cb.state,
+      ((p1[0]) << 24) + ((p1[1]) << 16) + ((p1[2]) << 8) + (p1[3]),
+      ((p1[4]) << 8) + p1[5],
+      ((p2[0]) << 24) + ((p2[1]) << 16) + ((p2[2]) << 8) + (p2[3]),
+      ((p2[4]) << 8) + p2[5]);
+
+  APPL_TRACE_DEBUG("BTA_GATTC_OPEN_EVT conn_id = %d client_if=%d status = %d",
+                   p_data->conn_id, p_data->client_if, p_data->status);
+
+  bta_dm_search_cb.conn_id = p_data->conn_id;
+
+  if (p_data->status == BTA_GATT_OK) {
+    btm_dm_start_disc_gatt_services(p_data->conn_id);
+  } else {
+    bta_dm_gatt_disc_complete(BTA_GATT_INVALID_CONN_ID, p_data->status);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_gattc_callback
+ *
+ * Description      This is GATT client callback function used in DM.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
+  APPL_TRACE_DEBUG("bta_dm_gattc_callback event = %d", event);
+
+  switch (event) {
+    case BTA_GATTC_REG_EVT:
+      APPL_TRACE_DEBUG("BTA_GATTC_REG_EVT client_if = %d",
+                       p_data->reg_oper.client_if);
+      if (p_data->reg_oper.status == BTA_GATT_OK)
+        bta_dm_search_cb.client_if = p_data->reg_oper.client_if;
+      else
+        bta_dm_search_cb.client_if = BTA_GATTS_INVALID_IF;
+      break;
+
+    case BTA_GATTC_OPEN_EVT:
+      bta_dm_proc_open_evt(&p_data->open);
+      break;
+
+    case BTA_GATTC_SEARCH_RES_EVT:
+      bta_dm_gatt_disc_result(p_data->srvc_res.service_uuid);
+      break;
+
+    case BTA_GATTC_SEARCH_CMPL_EVT:
+      if (bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE)
+        bta_dm_gatt_disc_complete(p_data->search_cmpl.conn_id,
+                                  p_data->search_cmpl.status);
+      break;
+
+    case BTA_GATTC_CLOSE_EVT:
+      APPL_TRACE_DEBUG("BTA_GATTC_CLOSE_EVT reason = %d", p_data->close.reason);
+      /* in case of disconnect before search is completed */
+      if ((bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE) &&
+          (bta_dm_search_cb.state != BTA_DM_SEARCH_ACTIVE) &&
+          !memcmp(p_data->close.remote_bda, bta_dm_search_cb.peer_bdaddr,
+                  BD_ADDR_LEN)) {
+        bta_dm_gatt_disc_complete((uint16_t)BTA_GATT_INVALID_CONN_ID,
+                                  (tBTA_GATT_STATUS)BTA_GATT_ERROR);
+      }
+      break;
+
+    default:
+      break;
+  }
+}
+
+#endif /* BTA_GATT_INCLUDED */
+
+#if (BLE_VND_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_dm_ctrl_features_rd_cmpl_cback
+ *
+ * Description      callback to handle controller feature read complete
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+static void bta_dm_ctrl_features_rd_cmpl_cback(tBTM_STATUS result) {
+  APPL_TRACE_DEBUG("%s  status = %d ", __func__, result);
+  if (result == BTM_SUCCESS) {
+    if (bta_dm_cb.p_sec_cback)
+      bta_dm_cb.p_sec_cback(BTA_DM_LE_FEATURES_READ, NULL);
+  } else {
+    APPL_TRACE_ERROR("%s Ctrl BLE feature read failed: status :%d", __func__,
+                     result);
+  }
+}
+#endif /* BLE_VND_INCLUDED */
+
+#endif /* BLE_INCLUDED */
diff --git a/bt/bta/dm/bta_dm_api.cc b/bt/bta/dm/bta_dm_api.cc
new file mode 100644
index 0000000..6eada78
--- /dev/null
+++ b/bt/bta/dm/bta_dm_api.cc
@@ -0,0 +1,1705 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2014 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 is the API implementation file for the BTA device manager.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_closure_api.h"
+#include "bta_dm_int.h"
+#include "bta_sys.h"
+#include "bta_sys_int.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "osi/include/osi.h"
+#include "utl.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_dm_reg = {bta_dm_sm_execute, bta_dm_sm_disable};
+
+static const tBTA_SYS_REG bta_dm_search_reg = {bta_dm_search_sm_execute,
+                                               bta_dm_search_sm_disable};
+
+/*******************************************************************************
+ *
+ * Function         BTA_EnableBluetooth
+ *
+ * Description      Enables bluetooth service.  This function must be
+ *                  called before any other functions in the BTA API are called.
+ *
+ *
+ * Returns          tBTA_STATUS
+ *
+ ******************************************************************************/
+tBTA_STATUS BTA_EnableBluetooth(tBTA_DM_SEC_CBACK* p_cback) {
+  /* Bluetooth disabling is in progress */
+  if (bta_dm_cb.disabling) return BTA_FAILURE;
+
+  bta_sys_register(BTA_ID_DM, &bta_dm_reg);
+  bta_sys_register(BTA_ID_DM_SEARCH, &bta_dm_search_reg);
+
+  /* if UUID list is not provided as static data */
+  bta_sys_eir_register(bta_dm_eir_update_uuid);
+
+  tBTA_DM_API_ENABLE* p_msg =
+      (tBTA_DM_API_ENABLE*)osi_malloc(sizeof(tBTA_DM_API_ENABLE));
+  p_msg->hdr.event = BTA_DM_API_ENABLE_EVT;
+  p_msg->p_sec_cback = p_cback;
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DisableBluetooth
+ *
+ * Description      Disables bluetooth service.  This function is called when
+ *                  the application no longer needs bluetooth service
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+tBTA_STATUS BTA_DisableBluetooth(void) {
+  BT_HDR* p_msg = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_msg->event = BTA_DM_API_DISABLE_EVT;
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_EnableTestMode
+ *
+ * Description      Enables bluetooth device under test mode
+ *
+ *
+ * Returns          tBTA_STATUS
+ *
+ ******************************************************************************/
+tBTA_STATUS BTA_EnableTestMode(void) {
+  BT_HDR* p_msg = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  APPL_TRACE_API("%s", __func__);
+
+  p_msg->event = BTA_DM_API_ENABLE_TEST_MODE_EVT;
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DisableTestMode
+ *
+ * Description      Disable bluetooth device under test mode
+ *
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_DisableTestMode(void) {
+  BT_HDR* p_msg = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  APPL_TRACE_API("%s", __func__);
+
+  p_msg->event = BTA_DM_API_DISABLE_TEST_MODE_EVT;
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmSetDeviceName
+ *
+ * Description      This function sets the Bluetooth name of local device
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmSetDeviceName(char* p_name) {
+  tBTA_DM_API_SET_NAME* p_msg =
+      (tBTA_DM_API_SET_NAME*)osi_malloc(sizeof(tBTA_DM_API_SET_NAME));
+
+  p_msg->hdr.event = BTA_DM_API_SET_NAME_EVT;
+  strlcpy((char*)p_msg->name, p_name, BD_NAME_LEN);
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmSetVisibility
+ *
+ * Description      This function sets the Bluetooth connectable,
+ *                  discoverable, pairable and conn paired only modes of local
+ *                  device
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmSetVisibility(tBTA_DM_DISC disc_mode, tBTA_DM_CONN conn_mode,
+                         uint8_t pairable_mode, uint8_t conn_filter) {
+  tBTA_DM_API_SET_VISIBILITY* p_msg =
+      (tBTA_DM_API_SET_VISIBILITY*)osi_malloc(sizeof(tBTA_DM_MSG));
+
+  p_msg->hdr.event = BTA_DM_API_SET_VISIBILITY_EVT;
+  p_msg->disc_mode = disc_mode;
+  p_msg->conn_mode = conn_mode;
+  p_msg->pair_mode = pairable_mode;
+  p_msg->conn_paired_only = conn_filter;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmSearch
+ *
+ * Description      This function searches for peer Bluetooth devices. It
+ *                  performs an inquiry and gets the remote name for devices.
+ *                  Service discovery is done if services is non zero
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmSearch(tBTA_DM_INQ* p_dm_inq, tBTA_SERVICE_MASK services,
+                  tBTA_DM_SEARCH_CBACK* p_cback) {
+  tBTA_DM_API_SEARCH* p_msg =
+      (tBTA_DM_API_SEARCH*)osi_calloc(sizeof(tBTA_DM_API_SEARCH));
+
+  p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
+  memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ));
+  p_msg->services = services;
+  p_msg->p_cback = p_cback;
+  p_msg->rs_res = BTA_DM_RS_NONE;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmSearchCancel
+ *
+ * Description      This function  cancels a search initiated by BTA_DmSearch
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmSearchCancel(void) {
+  BT_HDR* p_msg = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_msg->event = BTA_DM_API_SEARCH_CANCEL_EVT;
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmDiscover
+ *
+ * Description      This function does service discovery for services of a
+ *                  peer device
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmDiscover(BD_ADDR bd_addr, tBTA_SERVICE_MASK services,
+                    tBTA_DM_SEARCH_CBACK* p_cback, bool sdp_search) {
+  tBTA_DM_API_DISCOVER* p_msg =
+      (tBTA_DM_API_DISCOVER*)osi_calloc(sizeof(tBTA_DM_API_DISCOVER));
+
+  p_msg->hdr.event = BTA_DM_API_DISCOVER_EVT;
+  bdcpy(p_msg->bd_addr, bd_addr);
+  p_msg->services = services;
+  p_msg->p_cback = p_cback;
+  p_msg->sdp_search = sdp_search;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmDiscoverUUID
+ *
+ * Description      This function does service discovery for services of a
+ *                  peer device
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmDiscoverUUID(BD_ADDR bd_addr, tSDP_UUID* uuid,
+                        tBTA_DM_SEARCH_CBACK* p_cback, bool sdp_search) {
+  tBTA_DM_API_DISCOVER* p_msg =
+      (tBTA_DM_API_DISCOVER*)osi_malloc(sizeof(tBTA_DM_API_DISCOVER));
+
+  p_msg->hdr.event = BTA_DM_API_DISCOVER_EVT;
+  bdcpy(p_msg->bd_addr, bd_addr);
+  p_msg->services = BTA_USER_SERVICE_MASK;  // Not exposed at API level
+  p_msg->p_cback = p_cback;
+  p_msg->sdp_search = sdp_search;
+
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+  p_msg->num_uuid = 0;
+  p_msg->p_uuid = NULL;
+#endif
+  memcpy(&p_msg->uuid, uuid, sizeof(tSDP_UUID));
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBond
+ *
+ * Description      This function initiates a bonding procedure with a peer
+ *                  device
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmBond(BD_ADDR bd_addr) {
+  tBTA_DM_API_BOND* p_msg =
+      (tBTA_DM_API_BOND*)osi_malloc(sizeof(tBTA_DM_API_BOND));
+
+  p_msg->hdr.event = BTA_DM_API_BOND_EVT;
+  bdcpy(p_msg->bd_addr, bd_addr);
+  p_msg->transport = BTA_TRANSPORT_UNKNOWN;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBondByTransports
+ *
+ * Description      This function initiates a bonding procedure with a peer
+ *                  device
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmBondByTransport(BD_ADDR bd_addr, tBTA_TRANSPORT transport) {
+  tBTA_DM_API_BOND* p_msg =
+      (tBTA_DM_API_BOND*)osi_malloc(sizeof(tBTA_DM_API_BOND));
+
+  p_msg->hdr.event = BTA_DM_API_BOND_EVT;
+  bdcpy(p_msg->bd_addr, bd_addr);
+  p_msg->transport = transport;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBondCancel
+ *
+ * Description      This function cancels the bonding procedure with a peer
+ *                  device
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmBondCancel(BD_ADDR bd_addr) {
+  tBTA_DM_API_BOND_CANCEL* p_msg =
+      (tBTA_DM_API_BOND_CANCEL*)osi_malloc(sizeof(tBTA_DM_API_BOND_CANCEL));
+
+  p_msg->hdr.event = BTA_DM_API_BOND_CANCEL_EVT;
+  bdcpy(p_msg->bd_addr, bd_addr);
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmPinReply
+ *
+ * Description      This function provides a pincode for a remote device when
+ *                  one is requested by DM through BTA_DM_PIN_REQ_EVT
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmPinReply(BD_ADDR bd_addr, bool accept, uint8_t pin_len,
+                    uint8_t* p_pin)
+
+{
+  tBTA_DM_API_PIN_REPLY* p_msg =
+      (tBTA_DM_API_PIN_REPLY*)osi_malloc(sizeof(tBTA_DM_API_PIN_REPLY));
+
+  p_msg->hdr.event = BTA_DM_API_PIN_REPLY_EVT;
+  bdcpy(p_msg->bd_addr, bd_addr);
+  p_msg->accept = accept;
+  if (accept) {
+    p_msg->pin_len = pin_len;
+    memcpy(p_msg->p_pin, p_pin, pin_len);
+  }
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmLocalOob
+ *
+ * Description      This function retrieves the OOB data from local controller.
+ *                  The result is reported by:
+ *                  - bta_dm_co_loc_oob_ext() if device supports secure
+ *                    connections (SC)
+ *                  - bta_dm_co_loc_oob() if device doesn't support SC
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmLocalOob(void) {
+  tBTA_DM_API_LOC_OOB* p_msg =
+      (tBTA_DM_API_LOC_OOB*)osi_malloc(sizeof(tBTA_DM_API_LOC_OOB));
+
+  p_msg->hdr.event = BTA_DM_API_LOC_OOB_EVT;
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmConfirm
+ *
+ * Description      This function accepts or rejects the numerical value of the
+ *                  Simple Pairing process on BTA_DM_SP_CFM_REQ_EVT
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmConfirm(BD_ADDR bd_addr, bool accept) {
+  tBTA_DM_API_CONFIRM* p_msg =
+      (tBTA_DM_API_CONFIRM*)osi_malloc(sizeof(tBTA_DM_API_CONFIRM));
+
+  p_msg->hdr.event = BTA_DM_API_CONFIRM_EVT;
+  bdcpy(p_msg->bd_addr, bd_addr);
+  p_msg->accept = accept;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmAddDevice
+ *
+ * Description      This function adds a device to the security database list of
+ *                  peer device
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmAddDevice(BD_ADDR bd_addr, DEV_CLASS dev_class, LINK_KEY link_key,
+                     tBTA_SERVICE_MASK trusted_mask, bool is_trusted,
+                     uint8_t key_type, tBTA_IO_CAP io_cap, uint8_t pin_length) {
+  tBTA_DM_API_ADD_DEVICE* p_msg =
+      (tBTA_DM_API_ADD_DEVICE*)osi_calloc(sizeof(tBTA_DM_API_ADD_DEVICE));
+
+  p_msg->hdr.event = BTA_DM_API_ADD_DEVICE_EVT;
+  bdcpy(p_msg->bd_addr, bd_addr);
+  p_msg->tm = trusted_mask;
+  p_msg->is_trusted = is_trusted;
+  p_msg->io_cap = io_cap;
+
+  if (link_key) {
+    p_msg->link_key_known = true;
+    p_msg->key_type = key_type;
+    memcpy(p_msg->link_key, link_key, LINK_KEY_LEN);
+  }
+
+  /* Load device class if specified */
+  if (dev_class) {
+    p_msg->dc_known = true;
+    memcpy(p_msg->dc, dev_class, DEV_CLASS_LEN);
+  }
+
+  memset(p_msg->bd_name, 0, BD_NAME_LEN + 1);
+  memset(p_msg->features, 0, sizeof(p_msg->features));
+  p_msg->pin_length = pin_length;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmRemoveDevice
+ *
+ * Description      This function removes a device fromthe security database
+ *                  list of peer device. It manages unpairing even while
+ *                  connected.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+tBTA_STATUS BTA_DmRemoveDevice(BD_ADDR bd_addr) {
+  tBTA_DM_API_REMOVE_DEVICE* p_msg =
+      (tBTA_DM_API_REMOVE_DEVICE*)osi_calloc(sizeof(tBTA_DM_API_REMOVE_DEVICE));
+
+  p_msg->hdr.event = BTA_DM_API_REMOVE_DEVICE_EVT;
+  bdcpy(p_msg->bd_addr, bd_addr);
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GetEirService
+ *
+ * Description      This function is called to get BTA service mask from EIR.
+ *
+ * Parameters       p_eir - pointer of EIR significant part
+ *                  p_services - return the BTA service mask
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern const uint16_t bta_service_id_to_uuid_lkup_tbl[];
+void BTA_GetEirService(uint8_t* p_eir, tBTA_SERVICE_MASK* p_services) {
+  uint8_t xx, yy;
+  uint8_t num_uuid, max_num_uuid = 32;
+  uint8_t uuid_list[32 * LEN_UUID_16];
+  uint16_t* p_uuid16 = (uint16_t*)uuid_list;
+  tBTA_SERVICE_MASK mask;
+
+  BTM_GetEirUuidList(p_eir, LEN_UUID_16, &num_uuid, uuid_list, max_num_uuid);
+  for (xx = 0; xx < num_uuid; xx++) {
+    mask = 1;
+    for (yy = 0; yy < BTA_MAX_SERVICE_ID; yy++) {
+      if (*(p_uuid16 + xx) == bta_service_id_to_uuid_lkup_tbl[yy]) {
+        *p_services |= mask;
+        break;
+      }
+      mask <<= 1;
+    }
+
+    /* for HSP v1.2 only device */
+    if (*(p_uuid16 + xx) == UUID_SERVCLASS_HEADSET_HS)
+      *p_services |= BTA_HSP_SERVICE_MASK;
+
+    if (*(p_uuid16 + xx) == UUID_SERVCLASS_HDP_SOURCE)
+      *p_services |= BTA_HL_SERVICE_MASK;
+
+    if (*(p_uuid16 + xx) == UUID_SERVCLASS_HDP_SINK)
+      *p_services |= BTA_HL_SERVICE_MASK;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmGetConnectionState
+ *
+ * Description      Returns whether the remote device is currently connected.
+ *
+ * Returns          0 if the device is NOT connected.
+ *
+ ******************************************************************************/
+uint16_t BTA_DmGetConnectionState(const BD_ADDR bd_addr) {
+  tBTA_DM_PEER_DEVICE* p_dev = bta_dm_find_peer_device(bd_addr);
+  return (p_dev && p_dev->conn_state == BTA_DM_CONNECTED);
+}
+
+/*******************************************************************************
+ *                   Device Identification (DI) Server Functions
+ ******************************************************************************/
+/*******************************************************************************
+ *
+ * Function         BTA_DmSetLocalDiRecord
+ *
+ * Description      This function adds a DI record to the local SDP database.
+ *
+ * Returns          BTA_SUCCESS if record set sucessfully, otherwise error code.
+ *
+ ******************************************************************************/
+tBTA_STATUS BTA_DmSetLocalDiRecord(tBTA_DI_RECORD* p_device_info,
+                                   uint32_t* p_handle) {
+  tBTA_STATUS status = BTA_FAILURE;
+
+  if (bta_dm_di_cb.di_num < BTA_DI_NUM_MAX) {
+    if (SDP_SetLocalDiRecord((tSDP_DI_RECORD*)p_device_info, p_handle) ==
+        SDP_SUCCESS) {
+      if (!p_device_info->primary_record) {
+        bta_dm_di_cb.di_handle[bta_dm_di_cb.di_num] = *p_handle;
+        bta_dm_di_cb.di_num++;
+      }
+
+      bta_sys_add_uuid(UUID_SERVCLASS_PNP_INFORMATION);
+      status = BTA_SUCCESS;
+    }
+  }
+
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dmexecutecallback
+ *
+ * Description      This function will request BTA to execute a call back in the
+ *                  context of BTU task.
+ *                  This API was named in lower case because it is only intended
+ *                  for the internal customers(like BTIF).
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dmexecutecallback(tBTA_DM_EXEC_CBACK* p_callback, void* p_param) {
+  tBTA_DM_API_EXECUTE_CBACK* p_msg =
+      (tBTA_DM_API_EXECUTE_CBACK*)osi_malloc(sizeof(tBTA_DM_MSG));
+
+  p_msg->hdr.event = BTA_DM_API_EXECUTE_CBACK_EVT;
+  p_msg->p_param = p_param;
+  p_msg->p_exec_cback = p_callback;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmAddBleKey
+ *
+ * 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          BTA_SUCCESS if successful
+ *                  BTA_FAIL if operation failed.
+ *
+ ******************************************************************************/
+void BTA_DmAddBleKey(BD_ADDR bd_addr, tBTA_LE_KEY_VALUE* p_le_key,
+                     tBTA_LE_KEY_TYPE key_type) {
+#if (BLE_INCLUDED == TRUE)
+
+  tBTA_DM_API_ADD_BLEKEY* p_msg =
+      (tBTA_DM_API_ADD_BLEKEY*)osi_calloc(sizeof(tBTA_DM_API_ADD_BLEKEY));
+
+  p_msg->hdr.event = BTA_DM_API_ADD_BLEKEY_EVT;
+  p_msg->key_type = key_type;
+  bdcpy(p_msg->bd_addr, bd_addr);
+  memcpy(&p_msg->blekey, p_le_key, sizeof(tBTA_LE_KEY_VALUE));
+
+  bta_sys_sendmsg(p_msg);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmAddBleDevice
+ *
+ * Description      Add a BLE 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
+ *                  dev_type         - Remote device's device type.
+ *                  addr_type        - LE device address type.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmAddBleDevice(BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type,
+                        tBT_DEVICE_TYPE dev_type) {
+#if (BLE_INCLUDED == TRUE)
+  tBTA_DM_API_ADD_BLE_DEVICE* p_msg = (tBTA_DM_API_ADD_BLE_DEVICE*)osi_calloc(
+      sizeof(tBTA_DM_API_ADD_BLE_DEVICE));
+
+  p_msg->hdr.event = BTA_DM_API_ADD_BLEDEVICE_EVT;
+  bdcpy(p_msg->bd_addr, bd_addr);
+  p_msg->addr_type = addr_type;
+  p_msg->dev_type = dev_type;
+
+  bta_sys_sendmsg(p_msg);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBlePasskeyReply
+ *
+ * Description      Send BLE SMP passkey reply.
+ *
+ * Parameters:      bd_addr          - BD address of the peer
+ *                  accept           - passkey entry sucessful or declined.
+ *                  passkey          - passkey value, must be a 6 digit number,
+ *                                     can be lead by 0.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmBlePasskeyReply(BD_ADDR bd_addr, bool accept, uint32_t passkey) {
+#if (BLE_INCLUDED == TRUE)
+  tBTA_DM_API_PASSKEY_REPLY* p_msg =
+      (tBTA_DM_API_PASSKEY_REPLY*)osi_calloc(sizeof(tBTA_DM_API_PASSKEY_REPLY));
+
+  p_msg->hdr.event = BTA_DM_API_BLE_PASSKEY_REPLY_EVT;
+  bdcpy(p_msg->bd_addr, bd_addr);
+  p_msg->accept = accept;
+
+  if (accept) p_msg->passkey = passkey;
+
+  bta_sys_sendmsg(p_msg);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleConfirmReply
+ *
+ * Description      Send BLE SMP SC user confirmation reply.
+ *
+ * Parameters:      bd_addr          - BD address of the peer
+ *                  accept           - numbers to compare are the same or
+ *                                     different.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmBleConfirmReply(BD_ADDR bd_addr, bool accept) {
+#if (BLE_INCLUDED == TRUE)
+  tBTA_DM_API_CONFIRM* p_msg =
+      (tBTA_DM_API_CONFIRM*)osi_calloc(sizeof(tBTA_DM_API_CONFIRM));
+
+  p_msg->hdr.event = BTA_DM_API_BLE_CONFIRM_REPLY_EVT;
+  bdcpy(p_msg->bd_addr, bd_addr);
+  p_msg->accept = accept;
+
+  bta_sys_sendmsg(p_msg);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleSecurityGrant
+ *
+ * Description      Grant security request access.
+ *
+ * Parameters:      bd_addr          - BD address of the peer
+ *                  res              - security grant status.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmBleSecurityGrant(BD_ADDR bd_addr, tBTA_DM_BLE_SEC_GRANT res) {
+#if (BLE_INCLUDED == TRUE)
+  tBTA_DM_API_BLE_SEC_GRANT* p_msg =
+      (tBTA_DM_API_BLE_SEC_GRANT*)osi_calloc(sizeof(tBTA_DM_API_BLE_SEC_GRANT));
+
+  p_msg->hdr.event = BTA_DM_API_BLE_SEC_GRANT_EVT;
+  bdcpy(p_msg->bd_addr, bd_addr);
+  p_msg->res = res;
+
+  bta_sys_sendmsg(p_msg);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmSetBlePrefConnParams
+ *
+ * Description      This function is called to set the preferred connection
+ *                  parameters when default connection parameter is not desired.
+ *
+ * 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 BTA_DmSetBlePrefConnParams(const BD_ADDR bd_addr, uint16_t min_conn_int,
+                                uint16_t max_conn_int, uint16_t slave_latency,
+                                uint16_t supervision_tout) {
+#if (BLE_INCLUDED == TRUE)
+  tBTA_DM_API_BLE_CONN_PARAMS* p_msg = (tBTA_DM_API_BLE_CONN_PARAMS*)osi_calloc(
+      sizeof(tBTA_DM_API_BLE_CONN_PARAMS));
+
+  p_msg->hdr.event = BTA_DM_API_BLE_CONN_PARAM_EVT;
+  memcpy(p_msg->peer_bda, bd_addr, BD_ADDR_LEN);
+  p_msg->conn_int_max = max_conn_int;
+  p_msg->conn_int_min = min_conn_int;
+  p_msg->slave_latency = slave_latency;
+  p_msg->supervision_tout = supervision_tout;
+
+  bta_sys_sendmsg(p_msg);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmSetBleConnScanParams
+ *
+ * Description      This function is called to set scan parameters used in
+ *                  BLE connection request
+ *
+ * Parameters:      scan_interval    - scan interval
+ *                  scan_window      - scan window
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmSetBleConnScanParams(uint32_t scan_interval, uint32_t scan_window) {
+#if (BLE_INCLUDED == TRUE)
+  tBTA_DM_API_BLE_SCAN_PARAMS* p_msg = (tBTA_DM_API_BLE_SCAN_PARAMS*)osi_calloc(
+      sizeof(tBTA_DM_API_BLE_SCAN_PARAMS));
+
+  p_msg->hdr.event = BTA_DM_API_BLE_CONN_SCAN_PARAM_EVT;
+  p_msg->scan_int = scan_interval;
+  p_msg->scan_window = scan_window;
+
+  bta_sys_sendmsg(p_msg);
+#endif  // BLE_INCLUDED == true
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmSetBleScanParams
+ *
+ * Description      This function is called to set scan parameters
+ *
+ * Parameters:      client_if - Client IF
+ *                  scan_interval - scan interval
+ *                  scan_window - scan window
+ *                  scan_mode - scan mode
+ *                  scan_param_setup_status_cback - Set scan param status
+ *                                                  callback
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+
+#if (BLE_INCLUDED == TRUE)
+void BTA_DmSetBleScanParams(
+    tGATT_IF client_if, uint32_t scan_interval, uint32_t scan_window,
+    tBLE_SCAN_MODE scan_mode,
+    tBLE_SCAN_PARAM_SETUP_CBACK scan_param_setup_cback) {
+  tBTA_DM_API_BLE_SCAN_PARAMS* p_msg = (tBTA_DM_API_BLE_SCAN_PARAMS*)osi_calloc(
+      sizeof(tBTA_DM_API_BLE_SCAN_PARAMS));
+
+  p_msg->hdr.event = BTA_DM_API_BLE_SCAN_PARAM_EVT;
+  p_msg->client_if = client_if;
+  p_msg->scan_int = scan_interval;
+  p_msg->scan_window = scan_window;
+  p_msg->scan_mode = scan_mode;
+  p_msg->scan_param_setup_cback = scan_param_setup_cback;
+
+  bta_sys_sendmsg(p_msg);
+}
+#endif  // BLE_INCLUDED == true
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmSetBleAdvParams
+ *
+ * Description      This function sets the advertising parameters BLE
+ *                  functionality.
+ *                  It is to be called when device act in peripheral or
+ *                  broadcaster role.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmSetBleAdvParams(uint16_t adv_int_min, uint16_t adv_int_max,
+                           tBLE_BD_ADDR* p_dir_bda) {
+#if (BLE_INCLUDED == TRUE)
+  if (p_dir_bda != NULL) {
+    tBLE_BD_ADDR* bda = new tBLE_BD_ADDR;
+    memcpy(bda, p_dir_bda, sizeof(tBLE_BD_ADDR));
+    do_in_bta_thread(FROM_HERE,
+                     base::Bind(&bta_dm_ble_set_adv_params, adv_int_min,
+                                adv_int_max, base::Owned(bda)));
+  }
+
+  do_in_bta_thread(FROM_HERE, base::Bind(&bta_dm_ble_set_adv_params,
+                                         adv_int_min, adv_int_max, nullptr));
+
+#endif
+}
+
+/*******************************************************************************
+ *                      BLE ADV data management API
+ *******************************************************************************/
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleSetStorageParams
+ *
+ * Description      This function is called to override the BTA scan response.
+ *
+ * Parameters       batch_scan_full_max -Max storage space (in %) allocated to
+ *                                       full scanning
+ *                  batch_scan_trunc_max -Max storage space (in %) allocated to
+ *                                        truncated scanning
+ *                  batch_scan_notify_threshold -Setup notification level based
+ *                                               on total space
+ *                  p_setup_cback - Setup callback pointer
+ *                  p_thres_cback - Threshold callback pointer
+ *                  p_rep_cback - Reports callback pointer
+ *                  ref_value - Ref value
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_DmBleSetStorageParams(
+    uint8_t batch_scan_full_max, uint8_t batch_scan_trunc_max,
+    uint8_t batch_scan_notify_threshold,
+    tBTA_BLE_SCAN_SETUP_CBACK* p_setup_cback,
+    tBTA_BLE_SCAN_THRESHOLD_CBACK* p_thres_cback,
+    tBTA_BLE_SCAN_REP_CBACK* p_rep_cback, tBTA_DM_BLE_REF_VALUE ref_value) {
+  tBTA_DM_API_SET_STORAGE_CONFIG* p_msg =
+      (tBTA_DM_API_SET_STORAGE_CONFIG*)osi_malloc(
+          sizeof(tBTA_DM_API_SET_STORAGE_CONFIG));
+
+  bta_dm_cb.p_setup_cback = p_setup_cback;
+
+  p_msg->hdr.event = BTA_DM_API_BLE_SETUP_STORAGE_EVT;
+  p_msg->p_setup_cback = bta_ble_scan_setup_cb;
+  p_msg->p_thres_cback = p_thres_cback;
+  p_msg->p_read_rep_cback = p_rep_cback;
+  p_msg->ref_value = ref_value;
+  p_msg->batch_scan_full_max = batch_scan_full_max;
+  p_msg->batch_scan_trunc_max = batch_scan_trunc_max;
+  p_msg->batch_scan_notify_threshold = batch_scan_notify_threshold;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleEnableBatchScan
+ *
+ * Description      This function is called to enable the batch scan
+ *
+ * Parameters       scan_mode -Batch scan mode
+ *                  scan_interval - Scan interval
+ *                  scan_window - Scan window
+ *                  discard_rule -Discard rules
+ *                  addr_type - Address type
+ *                  ref_value - Reference value
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_DmBleEnableBatchScan(tBTA_BLE_BATCH_SCAN_MODE scan_mode,
+                                     uint32_t scan_interval,
+                                     uint32_t scan_window,
+                                     tBTA_BLE_DISCARD_RULE discard_rule,
+                                     tBLE_ADDR_TYPE addr_type,
+                                     tBTA_DM_BLE_REF_VALUE ref_value) {
+  tBTA_DM_API_ENABLE_SCAN* p_msg =
+      (tBTA_DM_API_ENABLE_SCAN*)osi_malloc(sizeof(tBTA_DM_API_ENABLE_SCAN));
+
+  p_msg->hdr.event = BTA_DM_API_BLE_ENABLE_BATCH_SCAN_EVT;
+  p_msg->scan_mode = scan_mode;
+  p_msg->scan_int = scan_interval;
+  p_msg->scan_window = scan_window;
+  p_msg->discard_rule = discard_rule;
+  p_msg->addr_type = addr_type;
+  p_msg->ref_value = ref_value;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleDisableBatchScan
+ *
+ * Description      This function is called to disable the batch scan
+ *
+ * Parameters       ref_value - Reference value
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_DmBleDisableBatchScan(tBTA_DM_BLE_REF_VALUE ref_value) {
+  tBTA_DM_API_DISABLE_SCAN* p_msg =
+      (tBTA_DM_API_DISABLE_SCAN*)osi_malloc(sizeof(tBTA_DM_API_DISABLE_SCAN));
+
+  p_msg->hdr.event = BTA_DM_API_BLE_DISABLE_BATCH_SCAN_EVT;
+  p_msg->ref_value = ref_value;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleReadScanReports
+ *
+ * Description      This function is called to read scan reports
+ *
+ * Parameters       scan_type -Batch scan mode
+ *                  ref_value - Reference value
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_DmBleReadScanReports(tBTA_BLE_BATCH_SCAN_MODE scan_type,
+                                     tBTA_DM_BLE_REF_VALUE ref_value) {
+  tBTA_DM_API_READ_SCAN_REPORTS* p_msg =
+      (tBTA_DM_API_READ_SCAN_REPORTS*)osi_malloc(
+          sizeof(tBTA_DM_API_READ_SCAN_REPORTS));
+
+  p_msg->hdr.event = BTA_DM_API_BLE_READ_SCAN_REPORTS_EVT;
+  p_msg->scan_type = scan_type;
+  p_msg->ref_value = ref_value;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleTrackAdvertiser
+ *
+ * Description      This function is called to track advertiser
+ *
+ * Parameters       ref_value - Reference value
+ *                  p_track_adv_cback - Track ADV callback
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_DmBleTrackAdvertiser(
+    tBTA_DM_BLE_REF_VALUE ref_value,
+    tBTA_BLE_TRACK_ADV_CBACK* p_track_adv_cback) {
+  tBTA_DM_API_TRACK_ADVERTISER* p_msg =
+      (tBTA_DM_API_TRACK_ADVERTISER*)osi_malloc(
+          sizeof(tBTA_DM_API_TRACK_ADVERTISER));
+
+  p_msg->hdr.event = BTA_DM_API_BLE_TRACK_ADVERTISER_EVT;
+  p_msg->p_track_adv_cback = p_track_adv_cback;
+  p_msg->ref_value = ref_value;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+#endif
+
+/*******************************************************************************
+ *                      BLE ADV data management API
+ *******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleSetBgConnType
+ *
+ * Description      This function is called to set BLE connectable mode for a
+ *                  peripheral device.
+ *
+ * Parameters       bg_conn_type: it can be auto connection, or selective
+ *                                connection.
+ *                  p_select_cback: callback function when selective connection
+ *                                  procedure is being used.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmBleSetBgConnType(tBTA_DM_BLE_CONN_TYPE bg_conn_type,
+                            tBTA_DM_BLE_SEL_CBACK* p_select_cback) {
+#if (BLE_INCLUDED == TRUE)
+  tBTA_DM_API_BLE_SET_BG_CONN_TYPE* p_msg =
+      (tBTA_DM_API_BLE_SET_BG_CONN_TYPE*)osi_calloc(
+          sizeof(tBTA_DM_API_BLE_SET_BG_CONN_TYPE));
+
+  p_msg->hdr.event = BTA_DM_API_BLE_SET_BG_CONN_TYPE;
+  p_msg->bg_conn_type = bg_conn_type;
+  p_msg->p_select_cback = p_select_cback;
+
+  bta_sys_sendmsg(p_msg);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_discover_send_msg
+ *
+ * Description      This function send discover message to BTA task.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+static void bta_dm_discover_send_msg(BD_ADDR bd_addr,
+                                     tBTA_SERVICE_MASK_EXT* p_services,
+                                     tBTA_DM_SEARCH_CBACK* p_cback,
+                                     bool sdp_search,
+                                     tBTA_TRANSPORT transport) {
+  const size_t len = p_services ? (sizeof(tBTA_DM_API_DISCOVER) +
+                                   sizeof(tBT_UUID) * p_services->num_uuid)
+                                : sizeof(tBTA_DM_API_DISCOVER);
+  tBTA_DM_API_DISCOVER* p_msg = (tBTA_DM_API_DISCOVER*)osi_calloc(len);
+
+  p_msg->hdr.event = BTA_DM_API_DISCOVER_EVT;
+  bdcpy(p_msg->bd_addr, bd_addr);
+  p_msg->p_cback = p_cback;
+  p_msg->sdp_search = sdp_search;
+  p_msg->transport = transport;
+
+  if (p_services != NULL) {
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+    p_msg->services = p_services->srvc_mask;
+    p_msg->num_uuid = p_services->num_uuid;
+    if (p_services->num_uuid != 0) {
+      p_msg->p_uuid = (tBT_UUID*)(p_msg + 1);
+      memcpy(p_msg->p_uuid, p_services->p_uuid,
+             sizeof(tBT_UUID) * p_services->num_uuid);
+    }
+#endif
+  }
+
+  bta_sys_sendmsg(p_msg);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmDiscoverByTransport
+ *
+ * Description      This function does service discovery on particular transport
+ *                  for services of a
+ *                  peer device. When services.num_uuid is 0, it indicates all
+ *                  GATT based services are to be searched; otherwise a list of
+ *                  UUID of interested services should be provided through
+ *                  p_services->p_uuid.
+ *
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmDiscoverByTransport(BD_ADDR bd_addr,
+                               tBTA_SERVICE_MASK_EXT* p_services,
+                               tBTA_DM_SEARCH_CBACK* p_cback, bool sdp_search,
+                               tBTA_TRANSPORT transport) {
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+  bta_dm_discover_send_msg(bd_addr, p_services, p_cback, sdp_search, transport);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmDiscoverExt
+ *
+ * Description      This function does service discovery for services of a
+ *                  peer device. When services.num_uuid is 0, it indicates all
+ *                  GATT based services are to be searched; other wise a list of
+ *                  UUID of interested services should be provided through
+ *                  p_services->p_uuid.
+ *
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmDiscoverExt(BD_ADDR bd_addr, tBTA_SERVICE_MASK_EXT* p_services,
+                       tBTA_DM_SEARCH_CBACK* p_cback, bool sdp_search) {
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+  bta_dm_discover_send_msg(bd_addr, p_services, p_cback, sdp_search,
+                           BTA_TRANSPORT_UNKNOWN);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmSearchExt
+ *
+ * Description      This function searches for peer Bluetooth devices. It
+ *                  performs an inquiry and gets the remote name for devices.
+ *                  Service discovery is done if services is non zero
+ *
+ * Parameters       p_dm_inq: inquiry conditions
+ *                  p_services: if service is not empty, service discovery will
+ *                              be done. For all GATT based service conditions,
+ *                              put num_uuid, and p_uuid is the pointer to the
+ *                              list of UUID values.
+ *                  p_cback: callback function when search is completed.
+ *
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+void BTA_DmSearchExt(tBTA_DM_INQ* p_dm_inq, tBTA_SERVICE_MASK_EXT* p_services,
+                     tBTA_DM_SEARCH_CBACK* p_cback) {
+  const size_t len = p_services ? (sizeof(tBTA_DM_API_SEARCH) +
+                                   sizeof(tBT_UUID) * p_services->num_uuid)
+                                : sizeof(tBTA_DM_API_SEARCH);
+  tBTA_DM_API_SEARCH* p_msg = (tBTA_DM_API_SEARCH*)osi_calloc(len);
+
+  p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
+  memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ));
+  p_msg->p_cback = p_cback;
+  p_msg->rs_res = BTA_DM_RS_NONE;
+
+  if (p_services != NULL) {
+    p_msg->services = p_services->srvc_mask;
+    p_msg->num_uuid = p_services->num_uuid;
+
+    if (p_services->num_uuid != 0) {
+      p_msg->p_uuid = (tBT_UUID*)(p_msg + 1);
+      memcpy(p_msg->p_uuid, p_services->p_uuid,
+             sizeof(tBT_UUID) * p_services->num_uuid);
+    } else {
+      p_msg->p_uuid = NULL;
+    }
+  }
+
+  bta_sys_sendmsg(p_msg);
+}
+#else
+void BTA_DmSearchExt(UNUSED_ATTR tBTA_DM_INQ* p_dm_inq,
+                     UNUSED_ATTR tBTA_SERVICE_MASK_EXT* p_services,
+                     UNUSED_ATTR tBTA_DM_SEARCH_CBACK* p_cback) {}
+#endif
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleUpdateConnectionParam
+ *
+ * Description      Update connection parameters, can only be used when
+ *                  connection is up.
+ *
+ * Parameters:      bd_addr          - BD address of the peer
+ *                  min_int   -     minimum connection interval,
+ *                                  [0x0004 ~ 0x4000]
+ *                  max_int   -     maximum connection interval,
+ *                                  [0x0004 ~ 0x4000]
+ *                  latency   -     slave latency [0 ~ 500]
+ *                  timeout   -     supervision timeout [0x000a ~ 0xc80]
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmBleUpdateConnectionParam(BD_ADDR bd_addr, uint16_t min_int,
+                                    uint16_t max_int, uint16_t latency,
+                                    uint16_t timeout) {
+#if (BLE_INCLUDED == TRUE)
+  tBTA_DM_API_UPDATE_CONN_PARAM* p_msg =
+      (tBTA_DM_API_UPDATE_CONN_PARAM*)osi_calloc(
+          sizeof(tBTA_DM_API_UPDATE_CONN_PARAM));
+
+  p_msg->hdr.event = BTA_DM_API_UPDATE_CONN_PARAM_EVT;
+  bdcpy(p_msg->bd_addr, bd_addr);
+  p_msg->min_int = min_int;
+  p_msg->max_int = max_int;
+  p_msg->latency = latency;
+  p_msg->timeout = timeout;
+
+  bta_sys_sendmsg(p_msg);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleConfigLocalPrivacy
+ *
+ * Description      Enable/disable privacy on the local device
+ *
+ * Parameters:      privacy_enable   - enable/disabe privacy on remote device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmBleConfigLocalPrivacy(bool privacy_enable) {
+#if (BLE_INCLUDED == TRUE && BLE_PRIVACY_SPT == TRUE)
+  tBTA_DM_API_LOCAL_PRIVACY* p_msg = (tBTA_DM_API_LOCAL_PRIVACY*)osi_calloc(
+      sizeof(tBTA_DM_API_ENABLE_PRIVACY));
+
+  p_msg->hdr.event = BTA_DM_API_LOCAL_PRIVACY_EVT;
+  p_msg->privacy_enable = privacy_enable;
+
+  bta_sys_sendmsg(p_msg);
+#else
+  UNUSED(privacy_enable);
+#endif
+}
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleCfgFilterCondition
+ *
+ * Description      This function is called to configure the adv data payload
+ *                  filter condition.
+ *
+ * Parameters       action: to read/write/clear
+ *                  cond_type: filter condition type
+ *                  filt_index - Filter index
+ *                  p_cond: filter condition parameter
+ *                  p_cmpl_back - Command completed callback
+ *                  ref_value - Reference value
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+#if (BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE)
+void BTA_DmBleCfgFilterCondition(tBTA_DM_BLE_SCAN_COND_OP action,
+                                 tBTA_DM_BLE_PF_COND_TYPE cond_type,
+                                 tBTA_DM_BLE_PF_FILT_INDEX filt_index,
+                                 tBTA_DM_BLE_PF_COND_PARAM* p_cond,
+                                 tBTA_DM_BLE_PF_CFG_CBACK* p_cmpl_cback,
+                                 tBTA_DM_BLE_REF_VALUE ref_value) {
+  tBTA_DM_API_CFG_FILTER_COND* p_msg;
+  APPL_TRACE_API("BTA_DmBleCfgFilterCondition: %d, %d", action, cond_type);
+
+  uint16_t len =
+      sizeof(tBTA_DM_API_CFG_FILTER_COND) + sizeof(tBTA_DM_BLE_PF_COND_PARAM);
+  uint8_t* p;
+
+  if (NULL != p_cond) {
+    switch (cond_type) {
+      case BTA_DM_BLE_PF_SRVC_DATA_PATTERN:
+      case BTA_DM_BLE_PF_MANU_DATA:
+        /* Length of pattern and pattern mask and other elements in */
+        /* tBTA_DM_BLE_PF_MANU_COND */
+        len += ((p_cond->manu_data.data_len) * 2) + sizeof(uint16_t) +
+               sizeof(uint16_t) + sizeof(uint8_t);
+        break;
+
+      case BTA_DM_BLE_PF_LOCAL_NAME:
+        len += ((p_cond->local_name.data_len) + sizeof(uint8_t));
+        break;
+
+      case BTM_BLE_PF_SRVC_UUID:
+      case BTM_BLE_PF_SRVC_SOL_UUID:
+        len += sizeof(tBLE_BD_ADDR) + sizeof(tBTA_DM_BLE_PF_COND_MASK);
+        break;
+
+      default:
+        break;
+    }
+  }
+
+  p_msg = (tBTA_DM_API_CFG_FILTER_COND*)osi_calloc(len);
+  p_msg->hdr.event = BTA_DM_API_CFG_FILTER_COND_EVT;
+  p_msg->action = action;
+  p_msg->cond_type = cond_type;
+  p_msg->filt_index = filt_index;
+  p_msg->p_filt_cfg_cback = p_cmpl_cback;
+  p_msg->ref_value = ref_value;
+  if (p_cond) {
+    p_msg->p_cond_param = (tBTA_DM_BLE_PF_COND_PARAM*)(p_msg + 1);
+    memcpy(p_msg->p_cond_param, p_cond, sizeof(tBTA_DM_BLE_PF_COND_PARAM));
+
+    p = (uint8_t*)(p_msg->p_cond_param + 1);
+
+    if (cond_type == BTA_DM_BLE_PF_SRVC_DATA_PATTERN ||
+        cond_type == BTA_DM_BLE_PF_MANU_DATA) {
+      p_msg->p_cond_param->manu_data.p_pattern = p;
+      p_msg->p_cond_param->manu_data.data_len = p_cond->manu_data.data_len;
+      memcpy(p_msg->p_cond_param->manu_data.p_pattern,
+             p_cond->manu_data.p_pattern, p_cond->manu_data.data_len);
+      p += p_cond->manu_data.data_len;
+
+      if (cond_type == BTA_DM_BLE_PF_MANU_DATA) {
+        p_msg->p_cond_param->manu_data.company_id_mask =
+            p_cond->manu_data.company_id_mask;
+        if (p_cond->manu_data.p_pattern_mask != NULL) {
+          p_msg->p_cond_param->manu_data.p_pattern_mask = p;
+          memcpy(p_msg->p_cond_param->manu_data.p_pattern_mask,
+                 p_cond->manu_data.p_pattern_mask, p_cond->manu_data.data_len);
+        }
+      }
+    } else if (cond_type == BTA_DM_BLE_PF_LOCAL_NAME) {
+      p_msg->p_cond_param->local_name.p_data = p;
+      p_msg->p_cond_param->local_name.data_len = p_cond->local_name.data_len;
+      memcpy(p_msg->p_cond_param->local_name.p_data, p_cond->local_name.p_data,
+             p_cond->local_name.data_len);
+    } else if (cond_type == BTM_BLE_PF_SRVC_UUID ||
+               cond_type == BTM_BLE_PF_SRVC_SOL_UUID) {
+      if (p_cond->srvc_uuid.p_target_addr != NULL) {
+        p_msg->p_cond_param->srvc_uuid.p_target_addr = (tBLE_BD_ADDR*)(p);
+        p_msg->p_cond_param->srvc_uuid.p_target_addr->type =
+            p_cond->srvc_uuid.p_target_addr->type;
+        memcpy(p_msg->p_cond_param->srvc_uuid.p_target_addr->bda,
+               p_cond->srvc_uuid.p_target_addr->bda, BD_ADDR_LEN);
+        p = (uint8_t*)(p_msg->p_cond_param->srvc_uuid.p_target_addr + 1);
+      }
+      if (p_cond->srvc_uuid.p_uuid_mask) {
+        p_msg->p_cond_param->srvc_uuid.p_uuid_mask =
+            (tBTA_DM_BLE_PF_COND_MASK*)p;
+        memcpy(p_msg->p_cond_param->srvc_uuid.p_uuid_mask,
+               p_cond->srvc_uuid.p_uuid_mask, sizeof(tBTA_DM_BLE_PF_COND_MASK));
+      }
+    }
+  }
+
+  bta_sys_sendmsg(p_msg);
+}
+#else
+void BTA_DmBleCfgFilterCondition(
+    UNUSED_ATTR tBTA_DM_BLE_SCAN_COND_OP action,
+    UNUSED_ATTR tBTA_DM_BLE_PF_COND_TYPE cond_type,
+    UNUSED_ATTR tBTA_DM_BLE_PF_FILT_INDEX filt_index,
+    UNUSED_ATTR tBTA_DM_BLE_PF_COND_PARAM* p_cond,
+    UNUSED_ATTR tBTA_DM_BLE_PF_CFG_CBACK* p_cmpl_cback,
+    UNUSED_ATTR tBTA_DM_BLE_REF_VALUE ref_value) {}
+#endif
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleScanFilterSetup
+ *
+ * Description      This function is called to setup the adv data payload filter
+ *                  param
+ *
+ * Parameters       p_target: enable the filter condition on a target device; if
+ *                            NULL
+ *                  filt_index - Filter index
+ *                  p_filt_params -Filter parameters
+ *                  ref_value - Reference value
+ *                  action - Add, delete or clear
+ *                  p_cmpl_back - Command completed callback
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+#if (BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE)
+void BTA_DmBleScanFilterSetup(uint8_t action,
+                              tBTA_DM_BLE_PF_FILT_INDEX filt_index,
+                              tBTA_DM_BLE_PF_FILT_PARAMS* p_filt_params,
+                              tBLE_BD_ADDR* p_target,
+                              tBTA_DM_BLE_PF_PARAM_CBACK* p_cmpl_cback,
+                              tBTA_DM_BLE_REF_VALUE ref_value) {
+  const size_t len =
+      sizeof(tBTA_DM_API_SCAN_FILTER_PARAM_SETUP) + sizeof(tBLE_BD_ADDR);
+  tBTA_DM_API_SCAN_FILTER_PARAM_SETUP* p_msg =
+      (tBTA_DM_API_SCAN_FILTER_PARAM_SETUP*)osi_calloc(len);
+
+  APPL_TRACE_API("%s: %d", __func__, action);
+
+  p_msg->hdr.event = BTA_DM_API_SCAN_FILTER_SETUP_EVT;
+  p_msg->action = action;
+  p_msg->filt_index = filt_index;
+  if (p_filt_params) {
+    memcpy(&p_msg->filt_params, p_filt_params,
+           sizeof(tBTA_DM_BLE_PF_FILT_PARAMS));
+  }
+  p_msg->p_filt_param_cback = p_cmpl_cback;
+  p_msg->ref_value = ref_value;
+
+  if (p_target) {
+    p_msg->p_target = (tBLE_BD_ADDR*)(p_msg + 1);
+    memcpy(p_msg->p_target, p_target, sizeof(tBLE_BD_ADDR));
+  }
+
+  bta_sys_sendmsg(p_msg);
+}
+#else
+void BTA_DmBleScanFilterSetup(
+    UNUSED_ATTR uint8_t action,
+    UNUSED_ATTR tBTA_DM_BLE_PF_FILT_INDEX filt_index,
+    UNUSED_ATTR tBTA_DM_BLE_PF_FILT_PARAMS* p_filt_params,
+    UNUSED_ATTR tBLE_BD_ADDR* p_target,
+    UNUSED_ATTR tBTA_DM_BLE_PF_PARAM_CBACK* p_cmpl_cback,
+    UNUSED_ATTR tBTA_DM_BLE_REF_VALUE ref_value)
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleGetEnergyInfo
+ *
+ * Description      This function is called to obtain the energy info
+ *
+ * Parameters       p_cmpl_cback - Command complete callback
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmBleGetEnergyInfo(tBTA_BLE_ENERGY_INFO_CBACK* p_cmpl_cback) {
+  const size_t len = sizeof(tBTA_DM_API_ENERGY_INFO) + sizeof(tBLE_BD_ADDR);
+  tBTA_DM_API_ENERGY_INFO* p_msg = (tBTA_DM_API_ENERGY_INFO*)osi_calloc(len);
+
+  APPL_TRACE_API("%s", __func__);
+
+  p_msg->hdr.event = BTA_DM_API_BLE_ENERGY_INFO_EVT;
+  p_msg->p_energy_info_cback = p_cmpl_cback;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmEnableScanFilter
+ *
+ * Description      This function is called to enable the adv data payload
+ *                  filter
+ *
+ * Parameters       action - enable or disable the APCF feature
+ *                  p_cmpl_cback - Command completed callback
+ *                  ref_value - Reference value
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+#if (BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE)
+void BTA_DmEnableScanFilter(uint8_t action,
+                            tBTA_DM_BLE_PF_STATUS_CBACK* p_cmpl_cback,
+                            tBTA_DM_BLE_REF_VALUE ref_value) {
+  const size_t len =
+      sizeof(tBTA_DM_API_ENABLE_SCAN_FILTER) + sizeof(tBLE_BD_ADDR);
+  tBTA_DM_API_ENABLE_SCAN_FILTER* p_msg =
+      (tBTA_DM_API_ENABLE_SCAN_FILTER*)osi_calloc(len);
+
+  APPL_TRACE_API("%s: %d", __func__, action);
+
+  p_msg->hdr.event = BTA_DM_API_SCAN_FILTER_ENABLE_EVT;
+  p_msg->action = action;
+  p_msg->ref_value = ref_value;
+  p_msg->p_filt_status_cback = p_cmpl_cback;
+
+  bta_sys_sendmsg(p_msg);
+}
+#else
+void BTA_DmEnableScanFilter(
+    UNUSED_ATTR uint8_t action,
+    UNUSED_ATTR tBTA_DM_BLE_PF_STATUS_CBACK* p_cmpl_cback,
+    UNUSED_ATTR tBTA_DM_BLE_REF_VALUE ref_value) {}
+#endif
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleUpdateConnectionParams
+ *
+ * Description      Update connection parameters, can only be used when
+ *                  connection is up.
+ *
+ * Parameters:      bd_addr   - BD address of the peer
+ *                  min_int   -     minimum connection interval,
+ *                                  [0x0004 ~ 0x4000]
+ *                  max_int   -     maximum connection interval,
+ *                                  [0x0004 ~ 0x4000]
+ *                  latency   -     slave latency [0 ~ 500]
+ *                  timeout   -     supervision timeout [0x000a ~ 0xc80]
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmBleUpdateConnectionParams(const BD_ADDR bd_addr, uint16_t min_int,
+                                     uint16_t max_int, uint16_t latency,
+                                     uint16_t timeout) {
+  tBTA_DM_API_UPDATE_CONN_PARAM* p_msg =
+      (tBTA_DM_API_UPDATE_CONN_PARAM*)osi_calloc(
+          sizeof(tBTA_DM_API_UPDATE_CONN_PARAM));
+
+  p_msg->hdr.event = BTA_DM_API_UPDATE_CONN_PARAM_EVT;
+  bdcpy(p_msg->bd_addr, bd_addr);
+  p_msg->min_int = min_int;
+  p_msg->max_int = max_int;
+  p_msg->latency = latency;
+  p_msg->timeout = timeout;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleSetDataLength
+ *
+ * Description      This function is to set maximum LE data packet size
+ *
+ * Returns          void
+ *
+ *
+ ******************************************************************************/
+void BTA_DmBleSetDataLength(BD_ADDR remote_device, uint16_t tx_data_length) {
+  tBTA_DM_API_BLE_SET_DATA_LENGTH* p_msg =
+      (tBTA_DM_API_BLE_SET_DATA_LENGTH*)osi_malloc(
+          sizeof(tBTA_DM_API_BLE_SET_DATA_LENGTH));
+
+  bdcpy(p_msg->remote_bda, remote_device);
+  p_msg->hdr.event = BTA_DM_API_SET_DATA_LENGTH_EVT;
+  p_msg->tx_data_length = tx_data_length;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+#endif
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmSetEncryption
+ *
+ * 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     - transport of the link to be encruypted
+ *                  p_callback    - Pointer to callback function to indicat the
+ *                                  link encryption status
+ *                  sec_act       - This is the security action to indicate
+ *                                  what kind of BLE security level is required
+ *                                  for the BLE link if BLE is supported.
+ *                                  Note: This parameter is ignored for the
+ *                                        BR/EDR or if BLE is not supported.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmSetEncryption(BD_ADDR bd_addr, tBTA_TRANSPORT transport,
+                         tBTA_DM_ENCRYPT_CBACK* p_callback,
+                         tBTA_DM_BLE_SEC_ACT sec_act) {
+  tBTA_DM_API_SET_ENCRYPTION* p_msg = (tBTA_DM_API_SET_ENCRYPTION*)osi_calloc(
+      sizeof(tBTA_DM_API_SET_ENCRYPTION));
+
+  APPL_TRACE_API("%s", __func__);
+
+  p_msg->hdr.event = BTA_DM_API_SET_ENCRYPTION_EVT;
+  memcpy(p_msg->bd_addr, bd_addr, BD_ADDR_LEN);
+  p_msg->transport = transport;
+  p_msg->p_callback = p_callback;
+  p_msg->sec_act = sec_act;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmCloseACL
+ *
+ * Description      This function force to close an ACL connection and remove
+ *                  the device from the security database list of known devices.
+ *
+ * Parameters:      bd_addr       - Address of the peer device
+ *                  remove_dev    - remove device or not after link down
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_DmCloseACL(BD_ADDR bd_addr, bool remove_dev,
+                    tBTA_TRANSPORT transport) {
+  tBTA_DM_API_REMOVE_ACL* p_msg =
+      (tBTA_DM_API_REMOVE_ACL*)osi_calloc(sizeof(tBTA_DM_API_REMOVE_ACL));
+
+  APPL_TRACE_API("%s", __func__);
+
+  p_msg->hdr.event = BTA_DM_API_REMOVE_ACL_EVT;
+  memcpy(p_msg->bd_addr, bd_addr, BD_ADDR_LEN);
+  p_msg->remove_dev = remove_dev;
+  p_msg->transport = transport;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleObserve
+ *
+ * Description      This procedure keep the device listening for advertising
+ *                  events from a broadcast device.
+ *
+ * Parameters       start: start or stop observe.
+ *
+ * Returns          void
+
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+extern void BTA_DmBleObserve(bool start, uint8_t duration,
+                             tBTA_DM_SEARCH_CBACK* p_results_cb) {
+  tBTA_DM_API_BLE_OBSERVE* p_msg =
+      (tBTA_DM_API_BLE_OBSERVE*)osi_calloc(sizeof(tBTA_DM_API_BLE_OBSERVE));
+
+  APPL_TRACE_API("%s:start = %d ", __func__, start);
+
+  p_msg->hdr.event = BTA_DM_API_BLE_OBSERVE_EVT;
+  p_msg->start = start;
+  p_msg->duration = duration;
+  p_msg->p_cback = p_results_cb;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_VendorInit
+ *
+ * Description      This function initializes vendor specific
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_VendorInit(void) { APPL_TRACE_API("BTA_VendorInit"); }
+
+/*******************************************************************************
+ *
+ * Function         BTA_VendorCleanup
+ *
+ * Description      This function frees up Broadcom specific VS specific dynamic
+ *                  memory
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_VendorCleanup(void) {
+  tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+  BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+#if (BLE_INCLUDED == TRUE && BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE)
+  if (cmn_ble_vsc_cb.max_filter > 0) {
+    btm_ble_adv_filter_cleanup();
+#if (BLE_PRIVACY_SPT == TRUE)
+    btm_ble_resolving_list_cleanup();
+#endif
+  }
+
+  if (cmn_ble_vsc_cb.tot_scan_results_strg > 0) btm_ble_batchscan_cleanup();
+#endif
+
+  if (cmn_ble_vsc_cb.adv_inst_max > 0) btm_ble_multi_adv_cleanup();
+}
+
+#endif
diff --git a/bt/bta/dm/bta_dm_cfg.cc b/bt/bta/dm/bta_dm_cfg.cc
new file mode 100644
index 0000000..37d9383
--- /dev/null
+++ b/bt/bta/dm/bta_dm_cfg.cc
@@ -0,0 +1,642 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 compile-time configurable constants for the device
+ *  manager.
+ *
+ ******************************************************************************/
+
+#include <stddef.h>
+
+#include "bt_target.h"
+#include "bta_api.h"
+#include "bta_dm_int.h"
+#include "bta_jv_api.h"
+#include "bta_sys.h"
+
+#ifndef BTA_DM_LINK_POLICY_SETTINGS
+#define BTA_DM_LINK_POLICY_SETTINGS                        \
+  (HCI_ENABLE_MASTER_SLAVE_SWITCH | HCI_ENABLE_HOLD_MODE | \
+   HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_PARK_MODE)
+#endif
+
+/* page timeout in 625uS */
+#ifndef BTA_DM_PAGE_TIMEOUT
+#define BTA_DM_PAGE_TIMEOUT 8192
+#endif
+
+/* link supervision timeout in 625uS (5 secs) */
+#ifndef BTA_DM_LINK_TIMEOUT
+#define BTA_DM_LINK_TIMEOUT 8000
+#endif
+
+/* TRUE to avoid scatternet when av is streaming (be the master) */
+#ifndef BTA_DM_AVOID_SCATTER_A2DP
+#define BTA_DM_AVOID_SCATTER_A2DP TRUE
+#endif
+
+/* For Insight, PM cfg lookup tables are runtime configurable (to allow tweaking
+ * of params for power consumption measurements) */
+#ifndef BTE_SIM_APP
+#define tBTA_DM_PM_TYPE_QUALIFIER const
+#else
+#define tBTA_DM_PM_TYPE_QUALIFIER
+#endif
+
+const tBTA_DM_CFG bta_dm_cfg = {
+    /* mobile phone COD */
+    BTA_DM_COD,
+    /* link policy settings */
+    BTA_DM_LINK_POLICY_SETTINGS,
+    /* page timeout in 625uS */
+    BTA_DM_PAGE_TIMEOUT,
+    /* link supervision timeout in 625uS*/
+    BTA_DM_LINK_TIMEOUT,
+    /* true to avoid scatternet when av is streaming (be the master) */
+    BTA_DM_AVOID_SCATTER_A2DP};
+
+#ifndef BTA_DM_SCATTERNET
+/* By default, allow partial scatternet */
+#define BTA_DM_SCATTERNET BTA_DM_PARTIAL_SCATTERNET
+#endif
+
+#ifndef BTA_HH_ROLE
+/* By default, do not specify HH role (backward compatibility) */
+#define BTA_HH_ROLE BTA_ANY_ROLE
+#endif
+
+#ifndef BTA_AV_ROLE
+/* By default, AV role (backward BTA_MASTER_ROLE_PREF) */
+#define BTA_AV_ROLE BTA_MASTER_ROLE_PREF
+#endif
+
+#ifndef BTA_PANU_ROLE
+/* By default, AV role (backward BTA_MASTER_ROLE_PREF) */
+#define BTA_PANU_ROLE BTA_SLAVE_ROLE_ONLY
+#endif
+#define BTA_DM_NUM_RM_ENTRY 6
+
+/* appids for PAN used by insight sample application
+   these have to be same as defined in btui_int.h */
+#define BTUI_PAN_ID_PANU 0
+#define BTUI_PAN_ID_NAP 1
+#define BTUI_PAN_ID_GN 2
+
+/* First element is always for SYS:
+   app_id = # of entries table, cfg is
+   device scatternet support */
+const tBTA_DM_RM bta_dm_rm_cfg[] = {
+    {BTA_ID_SYS, BTA_DM_NUM_RM_ENTRY, BTA_DM_SCATTERNET},
+    {BTA_ID_PAN, BTUI_PAN_ID_NAP, BTA_ANY_ROLE},
+    {BTA_ID_PAN, BTUI_PAN_ID_GN, BTA_ANY_ROLE},
+    {BTA_ID_PAN, BTA_APP_ID_PAN_MULTI, BTA_MASTER_ROLE_ONLY},
+    {BTA_ID_PAN, BTUI_PAN_ID_PANU, BTA_PANU_ROLE},
+    {BTA_ID_HH, BTA_ALL_APP_ID, BTA_HH_ROLE},
+    {BTA_ID_AV, BTA_ALL_APP_ID, BTA_AV_ROLE}};
+
+tBTA_DM_CFG* p_bta_dm_cfg = (tBTA_DM_CFG*)&bta_dm_cfg;
+
+tBTA_DM_RM* p_bta_dm_rm_cfg = (tBTA_DM_RM*)&bta_dm_rm_cfg;
+
+#if (BLE_INCLUDED == TRUE)
+#define BTA_DM_NUM_PM_ENTRY \
+  23 /* number of entries in bta_dm_pm_cfg except the first */
+#define BTA_DM_NUM_PM_SPEC 15 /* number of entries in bta_dm_pm_spec */
+#else
+#define BTA_DM_NUM_PM_ENTRY \
+  21 /* number of entries in bta_dm_pm_cfg except the first */
+#define BTA_DM_NUM_PM_SPEC 13 /* number of entries in bta_dm_pm_spec */
+#endif
+
+tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_CFG
+    bta_dm_pm_cfg[BTA_DM_NUM_PM_ENTRY + 1] = {
+        {BTA_ID_SYS, BTA_DM_NUM_PM_ENTRY,
+         0}, /* reserved: specifies length of this table. */
+        {BTA_ID_AG, BTA_ALL_APP_ID,
+         0},               /* ag uses first spec table for app id 0 */
+        {BTA_ID_CT, 1, 1}, /* ct (BTA_ID_CT,APP ID=1) spec table */
+        {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_HD, BTA_ALL_APP_ID, 3},   /* hd spec table */
+        {BTA_ID_HH, BTA_ALL_APP_ID, 5},   /* 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_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 */
+#if (BLE_INCLUDED == TRUE)
+        ,
+        {BTA_ID_GATTC, BTA_ALL_APP_ID, 13} /* gattc spec table */
+        ,
+        {BTA_ID_GATTS, BTA_ALL_APP_ID, 14} /* gatts spec table */
+#endif
+};
+
+tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = {
+    /* AG : 0 */
+    {(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+     (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+     {
+         {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff  */
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}},   /* conn close  */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+         {{BTA_DM_PM_SNIFF_SCO_OPEN_IDX, 7000},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */
+         {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff  */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+         {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}},    /* busy */
+         {{BTA_DM_PM_RETRY, 7000},
+          {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+     }},
+
+    /* CT, CG : 1 */
+    {(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+     (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+     {
+         {{BTA_DM_PM_PARK, 5000},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* conn open  park */
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}},   /* conn close  */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+         {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* sco open sniff */
+         {{BTA_DM_PM_PARK, 5000},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* sco close  park */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+         {{BTA_DM_PM_RETRY, 5000},
+          {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+     }},
+
+    /* DG, PBC : 2 */
+    {(BTA_DM_PM_ACTIVE), /* no power saving mode allowed */
+#if (BTM_SSR_INCLUDED == TRUE)
+     (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+     {
+         {{BTA_DM_PM_SNIFF, 5000},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}},   /* conn close  */
+         {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}},    /* app open */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open  */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close   */
+         {{BTA_DM_PM_SNIFF, 1000}, {BTA_DM_PM_NO_ACTION, 0}},  /* idle */
+         {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}},    /* busy */
+         {{BTA_DM_PM_NO_ACTION, 0},
+          {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+     }},
+
+    /* HD : 3 */
+    {(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+     (BTA_DM_PM_SSR3), /* the SSR entry */
+#endif
+     {
+         {{BTA_DM_PM_SNIFF_HD_ACTIVE_IDX, 5000},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}},   /* conn close */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open  */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
+         {{BTA_DM_PM_SNIFF_HD_IDLE_IDX, 5000},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+         {{BTA_DM_PM_SNIFF_HD_ACTIVE_IDX, 0},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+         {{BTA_DM_PM_NO_ACTION, 0},
+          {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+     }},
+
+    /* AV : 4 */
+    {(BTA_DM_PM_SNIFF), /* allow sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+     (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+     {
+         {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* conn open  sniff */
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}},   /* conn close  */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open  */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close   */
+         {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000},
+          {BTA_DM_PM_NO_ACTION, 0}},                        /* idle */
+         {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+         {{BTA_DM_PM_NO_ACTION, 0},
+          {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+     }},
+
+    /* HH : 5 */
+    {(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+     (BTA_DM_PM_SSR1), /* the SSR entry */
+#endif
+     {
+         {{BTA_DM_PM_SNIFF_HH_OPEN_IDX, BTA_DM_PM_HH_OPEN_DELAY},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* conn open  sniff */
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}},   /* conn close  */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open  */
+         {{BTA_DM_PM_NO_ACTION, 0},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* sco close, used for HH suspend   */
+         {{BTA_DM_PM_SNIFF_HH_IDLE_IDX, BTA_DM_PM_HH_IDLE_DELAY},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+         {{BTA_DM_PM_SNIFF_HH_ACTIVE_IDX, BTA_DM_PM_HH_ACTIVE_DELAY},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+         {{BTA_DM_PM_NO_ACTION, 0},
+          {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+     }},
+
+    /* FTC, OPC, JV : 6 */
+    {(BTA_DM_PM_SNIFF), /* allow sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+     (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+     {
+         {{BTA_DM_PM_ACTIVE, 0},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* conn open  active */
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}},   /* conn close  */
+         {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}},    /* app open */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open  */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close   */
+         {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000},
+          {BTA_DM_PM_NO_ACTION, 0}},                        /* idle */
+         {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+         {{BTA_DM_PM_NO_ACTION, 0},
+          {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+     }},
+
+    /* FTS, PBS, OPS, MSE, BTA_JV_PM_ID_1 : 7 */
+    {(BTA_DM_PM_SNIFF), /* allow sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+     (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+     {
+         {{BTA_DM_PM_ACTIVE, 0},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* conn open  active */
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}},   /* conn close  */
+         {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}},    /* app open */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open  */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close   */
+         {{BTA_DM_PM_SNIFF_A2DP_IDX, BTA_FTS_OPS_IDLE_TO_SNIFF_DELAY_MS},
+          {BTA_DM_PM_NO_ACTION, 0}},                        /* idle */
+         {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+         {{BTA_DM_PM_NO_ACTION, 0},
+          {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+     }},
+
+    /* HL : 8 */
+    {(BTA_DM_PM_SNIFF), /* allow sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+     (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+     {
+         {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff  */
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}},   /* conn close  */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+         {{BTA_DM_PM_NO_ACTION, 0},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */
+         {{BTA_DM_PM_NO_ACTION, 0},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff  */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+         {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}},    /* busy */
+         {{BTA_DM_PM_NO_ACTION, 0},
+          {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+     }},
+
+    /* PANU : 9 */
+    {(BTA_DM_PM_SNIFF), /* allow sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+     (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+     {
+         {{BTA_DM_PM_ACTIVE, 0},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* conn open  active */
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}},   /* conn close  */
+         {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}},    /* app open */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open  */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close   */
+         {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000},
+          {BTA_DM_PM_NO_ACTION, 0}},                        /* idle */
+         {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+         {{BTA_DM_PM_NO_ACTION, 0},
+          {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+     }},
+
+    /* NAP : 10 */
+    {(BTA_DM_PM_SNIFF), /* allow sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+     (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+     {
+         {{BTA_DM_PM_ACTIVE, 0},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* conn open  active */
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}},   /* conn close  */
+         {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}},    /* app open */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open  */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close   */
+         {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000},
+          {BTA_DM_PM_NO_ACTION, 0}},                        /* idle */
+         {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+
+         {{BTA_DM_PM_NO_ACTION, 0},
+          {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+     }},
+
+    /* HS : 11 */
+    {(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+     (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+     {
+         {{BTA_DM_PM_SNIFF, 7000},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff  */
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}},   /* conn close  */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+         {{BTA_DM_PM_SNIFF3, 7000},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */
+         {{BTA_DM_PM_SNIFF, 7000},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff  */
+         {{BTA_DM_PM_SNIFF, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+         {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}},   /* busy */
+         {{BTA_DM_PM_RETRY, 7000},
+          {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+     }},
+
+    /* AVK : 12 */
+    {(BTA_DM_PM_SNIFF), /* allow sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+     (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+     {
+         {{BTA_DM_PM_SNIFF, 3000},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* conn open  sniff */
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}},   /* conn close  */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open  */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close   */
+         {{BTA_DM_PM_SNIFF4, 3000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+         {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}},    /* busy */
+         {{BTA_DM_PM_NO_ACTION, 0},
+          {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+     }}
+
+#if (BLE_INCLUDED == TRUE)
+    /* GATTC : 13 */
+    ,
+    {(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+     (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+     {
+         {{BTA_DM_PM_SNIFF_A2DP_IDX, 10000},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* conn open  active */
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}},   /* conn close  */
+         {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}},    /* app open */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open  */
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close   */
+         {{BTA_DM_PM_SNIFF_A2DP_IDX, 10000},
+          {BTA_DM_PM_NO_ACTION, 0}},                        /* idle */
+         {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+#if (AMP_INCLUDED == TRUE)
+         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* amp */
+#endif
+         {{BTA_DM_PM_RETRY, 5000},
+          {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+     }}
+    /* GATTS : 14 */
+    ,
+    {(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+     (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+     {
+         {{BTA_DM_PM_NO_PREF, 0},
+          {BTA_DM_PM_NO_ACTION, 0}}, /* conn open  active */
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close  */
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open  */
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+#if (AMP_INCLUDED == TRUE)
+         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* amp */
+#endif
+         {{BTA_DM_PM_RETRY, 5000},
+          {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+     }}
+
+#endif
+
+#ifdef BTE_SIM_APP /* For Insight builds only */
+    /* Entries at the end of the pm_spec table are user-defined (runtime
+       configurable),
+       for power consumption experiments.
+       Insight finds the first user-defined entry by looking for the first
+       BTA_DM_PM_NO_PREF.
+       The number of user_defined specs is defined by
+       BTA_SWRAP_UD_PM_SPEC_COUNT */
+    ,
+    {BTA_DM_PM_NO_PREF}, /* pm_spec USER_DEFINED_0 */
+    {BTA_DM_PM_NO_PREF}  /* pm_spec USER_DEFINED_1 */
+#endif                   /* BTE_SIM_APP */
+};
+
+/* Please refer to the SNIFF table definitions in bta_api.h.
+ *
+ * Adding to or Modifying the Table
+ * Additional sniff parameter entries can be added for BTA_DM_PM_SNIFF5 -
+ * BTA_DM_PM_SNIFF7.
+ * Overrides of additional table entries can be specified in bdroid_buildcfg.h.
+ * If additional
+ * sniff parameter entries are added or an override of an existing entry is
+ * specified in
+ * bdroid_buildcfg.h then the BTA_DM_PM_*_IDX defines in bta_api.h will need to
+ * be match the new
+ * ordering.
+ *
+ * Table Ordering
+ * Sniff Table entries must be ordered from highest latency (biggest interval)
+ * to lowest latency.
+ * If there is a conflict among the connected services the setting with the
+ * lowest latency will
+ * be selected.
+ */
+tBTA_DM_PM_TYPE_QUALIFIER tBTM_PM_PWR_MD bta_dm_pm_md[] = {
+    /*
+     * More sniff parameter entries can be added for
+     * BTA_DM_PM_SNIFF3 - BTA_DM_PM_SNIFF7, if needed. When entries are added or
+     * removed, BTA_DM_PM_PARK_IDX needs to be updated to reflect the actual
+     * index
+     * BTA_DM_PM_PARK_IDX is defined in bta_api.h and can be override by the
+     * bdroid_buildcfg.h settings.
+     * The SNIFF table entries must be in the order from highest latency
+     * (biggest
+     * interval) to lowest latency. If there's a conflict among the connected
+     * services, the setting with lowest latency wins.
+     */
+    /* sniff modes: max interval, min interval, attempt, timeout */
+    {BTA_DM_PM_SNIFF_MAX, BTA_DM_PM_SNIFF_MIN, BTA_DM_PM_SNIFF_ATTEMPT,
+     BTA_DM_PM_SNIFF_TIMEOUT, BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF - A2DP */
+    {BTA_DM_PM_SNIFF1_MAX, BTA_DM_PM_SNIFF1_MIN, BTA_DM_PM_SNIFF1_ATTEMPT,
+     BTA_DM_PM_SNIFF1_TIMEOUT, BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF1 */
+    {BTA_DM_PM_SNIFF2_MAX, BTA_DM_PM_SNIFF2_MIN, BTA_DM_PM_SNIFF2_ATTEMPT,
+     BTA_DM_PM_SNIFF2_TIMEOUT,
+     BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF2- HD idle */
+    {BTA_DM_PM_SNIFF3_MAX, BTA_DM_PM_SNIFF3_MIN, BTA_DM_PM_SNIFF3_ATTEMPT,
+     BTA_DM_PM_SNIFF3_TIMEOUT,
+     BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF3- SCO open */
+    {BTA_DM_PM_SNIFF4_MAX, BTA_DM_PM_SNIFF4_MIN, BTA_DM_PM_SNIFF4_ATTEMPT,
+     BTA_DM_PM_SNIFF4_TIMEOUT,
+     BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF4- HD active */
+    {BTA_DM_PM_SNIFF5_MAX, BTA_DM_PM_SNIFF5_MIN, BTA_DM_PM_SNIFF5_ATTEMPT,
+     BTA_DM_PM_SNIFF5_TIMEOUT,
+     BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF5- HD active */
+    {BTA_DM_PM_PARK_MAX, BTA_DM_PM_PARK_MIN, BTA_DM_PM_PARK_ATTEMPT,
+     BTA_DM_PM_PARK_TIMEOUT, BTM_PM_MD_PARK}
+
+#ifdef BTE_SIM_APP /* For Insight builds only */
+    /* Entries at the end of the bta_dm_pm_md table are user-defined (runtime
+       configurable),
+       for power consumption experiments.
+       Insight finds the first user-defined entry by looking for the first
+       'max=0'.
+       The number of user_defined specs is defined by BTA_SWRAP_UD_PM_DM_COUNT
+       */
+    ,
+    {0}, /* CONN_OPEN/SCO_CLOSE power mode settings for pm_spec USER_DEFINED_0
+            */
+    {0}, /* SCO_OPEN power mode settings for pm_spec USER_DEFINED_0 */
+
+    {0}, /* CONN_OPEN/SCO_CLOSE power mode settings for pm_spec USER_DEFINED_1
+            */
+    {0}  /* SCO_OPEN power mode settings for pm_spec USER_DEFINED_1 */
+#endif   /* BTE_SIM_APP */
+};
+
+/* 0=max_lat -> no SSR */
+/* the smaller of the SSR max latency wins.
+ * the entries in this table must be from highest latency (biggest interval) to
+ * lowest latency */
+#if (BTM_SSR_INCLUDED == TRUE)
+tBTA_DM_SSR_SPEC bta_dm_ssr_spec[] = {
+    /*max_lat, min_rmt_to, min_loc_to*/
+    {0, 0, 0}, /* BTA_DM_PM_SSR0 - do not use SSR */
+    {0, 0,
+     2}, /* BTA_DM_PM_SSR1 - HH, can NOT share entry with any other profile,
+            seting default max latency and min remote timeout as 0,
+            and always read individual device preference from HH module */
+    {1200, 2, 2}, /* BTA_DM_PM_SSR2 - others (as long as sniff is allowed)*/
+    {360, 160, 2} /* BTA_DM_PM_SSR3 - HD */
+};
+
+tBTA_DM_SSR_SPEC* p_bta_dm_ssr_spec = (tBTA_DM_SSR_SPEC*)&bta_dm_ssr_spec;
+#endif
+
+tBTA_DM_PM_CFG* p_bta_dm_pm_cfg = (tBTA_DM_PM_CFG*)&bta_dm_pm_cfg;
+tBTA_DM_PM_SPEC* p_bta_dm_pm_spec = (tBTA_DM_PM_SPEC*)&bta_dm_pm_spec;
+tBTM_PM_PWR_MD* p_bta_dm_pm_md = (tBTM_PM_PWR_MD*)&bta_dm_pm_md;
+
+/* The performance impact of EIR packet size
+ *
+ * When BTM_EIR_DEFAULT_FEC_REQUIRED is true,
+ * 1 to 17 bytes,    DM1 is used and most robust.
+ * 18 to 121 bytes,  DM3 is used but impacts inquiry scan time with large number
+ *                    of devices.(almost double with 150 users)
+ * 122 to 224 bytes, DM5 is used but cause quite big performance loss even with
+ *                    small number of users. so it is not recommended.
+ * 225 to 240 bytes, DH5 is used without FEC but it not recommended.
+ *                    (same reason of DM5)
+ *
+ * When BTM_EIR_DEFAULT_FEC_REQUIRED is false,
+ * 1 to 27 bytes,    DH1 is used but only robust at short range.
+ * 28 to 183 bytes,  DH3 is used but only robust at short range and impacts
+ * inquiry
+ *                    scan time with large number of devices.
+ * 184 to 240 bytes, DH5 is used but it not recommended.
+*/
+
+#if (BTA_EIR_CANNED_UUID_LIST == TRUE)
+/* for example */
+const uint8_t bta_dm_eir_uuid16_list[] = {
+    0x08, 0x11, /* Headset */
+    0x1E, 0x11, /* Handsfree */
+    0x0E, 0x11, /* AV Remote Control */
+    0x0B, 0x11, /* Audio Sink */
+};
+#endif  // BTA_EIR_CANNED_UUID_LIST
+
+/* Extended Inquiry Response */
+const tBTA_DM_EIR_CONF bta_dm_eir_cfg = {
+    50, /* minimum length of local name when it is shortened */
+        /* if length of local name is longer than this and EIR has not enough */
+        /* room for all UUID list then local name is shortened to this length */
+#if (BTA_EIR_CANNED_UUID_LIST == TRUE)
+    8,    (uint8_t*)bta_dm_eir_uuid16_list,
+#else     // BTA_EIR_CANNED_UUID_LIST
+    {
+        /* mask of UUID list in EIR */
+        0xFFFFFFFF, /* LSB is the first UUID of the first 32 UUIDs in
+                       BTM_EIR_UUID_LKUP_TBL */
+        0xFFFFFFFF  /* LSB is the first UUID of the next 32 UUIDs in
+                       BTM_EIR_UUID_LKUP_TBL */
+        /* BTM_EIR_UUID_LKUP_TBL can be overrided */
+    },
+#endif    // BTA_EIR_CANNED_UUID_LIST
+    NULL, /* Inquiry TX power         */
+    0,    /* length of flags in bytes */
+    NULL, /* flags for EIR */
+    0,    /* length of manufacturer specific in bytes */
+    NULL, /* manufacturer specific */
+    0,    /* length of additional data in bytes */
+    NULL  /* additional data */
+};
+tBTA_DM_EIR_CONF* p_bta_dm_eir_cfg = (tBTA_DM_EIR_CONF*)&bta_dm_eir_cfg;
diff --git a/bt/bta/dm/bta_dm_ci.cc b/bt/bta/dm/bta_dm_ci.cc
new file mode 100644
index 0000000..d3616d4
--- /dev/null
+++ b/bt/bta/dm/bta_dm_ci.cc
@@ -0,0 +1,108 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 is the API implementation file for the BTA device manager.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_dm_ci.h"
+#include "bta_dm_int.h"
+#include "bta_sys.h"
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_ci_io_req
+ *
+ * Description      This function must be called in response to function
+ *                  bta_dm_co_io_req(), if *p_oob_data to BTA_OOB_UNKNOWN
+ *                  by bta_dm_co_io_req().
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_ci_io_req(BD_ADDR bd_addr, tBTA_IO_CAP io_cap,
+                      tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req)
+
+{
+  tBTA_DM_CI_IO_REQ* p_msg =
+      (tBTA_DM_CI_IO_REQ*)osi_malloc(sizeof(tBTA_DM_CI_IO_REQ));
+
+  p_msg->hdr.event = BTA_DM_CI_IO_REQ_EVT;
+  bdcpy(p_msg->bd_addr, bd_addr);
+  p_msg->io_cap = io_cap;
+  p_msg->oob_data = oob_data;
+  p_msg->auth_req = auth_req;
+
+  bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_ci_rmt_oob
+ *
+ * Description      This function must be called in response to function
+ *                  bta_dm_co_rmt_oob() to provide the OOB data associated
+ *                  with the remote device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_ci_rmt_oob(bool accept, BD_ADDR bd_addr, BT_OCTET16 c,
+                       BT_OCTET16 r) {
+  tBTA_DM_CI_RMT_OOB* p_msg =
+      (tBTA_DM_CI_RMT_OOB*)osi_malloc(sizeof(tBTA_DM_CI_RMT_OOB));
+
+  p_msg->hdr.event = BTA_DM_CI_RMT_OOB_EVT;
+  bdcpy(p_msg->bd_addr, bd_addr);
+  p_msg->accept = accept;
+  memcpy(p_msg->c, c, BT_OCTET16_LEN);
+  memcpy(p_msg->r, r, BT_OCTET16_LEN);
+
+  bta_sys_sendmsg(p_msg);
+}
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_dm_sco_ci_data_ready
+ *
+ * Description      This function sends an event to indicating that the phone
+ *                  has SCO data ready.
+ *
+ * Parameters       event: is obtained from bta_dm_sco_co_open() function, which
+ *                          is the BTA event we want to send back to BTA module
+ *                          when there is encoded data ready.
+ *                  sco_handle: is the BTA sco handle which indicate a specific
+ *                           SCO connection.
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_sco_ci_data_ready(uint16_t event, uint16_t sco_handle) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = event;
+  p_buf->layer_specific = sco_handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+#endif
diff --git a/bt/bta/dm/bta_dm_int.h b/bt/bta/dm/bta_dm_int.h
new file mode 100644
index 0000000..3d8b85d
--- /dev/null
+++ b/bt/bta/dm/bta_dm_int.h
@@ -0,0 +1,1014 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 is the private interface file for the BTA device manager.
+ *
+ ******************************************************************************/
+#ifndef BTA_DM_INT_H
+#define BTA_DM_INT_H
+
+#include "bt_target.h"
+#include "bta_sys.h"
+
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+#include "bta_gatt_api.h"
+#endif
+
+/*****************************************************************************
+ *  Constants and data types
+ ****************************************************************************/
+
+#define BTA_COPY_DEVICE_CLASS(coddst, codsrc)          \
+  {                                                    \
+    ((uint8_t*)(coddst))[0] = ((uint8_t*)(codsrc))[0]; \
+    ((uint8_t*)(coddst))[1] = ((uint8_t*)(codsrc))[1]; \
+    ((uint8_t*)(coddst))[2] = ((uint8_t*)(codsrc))[2]; \
+  }
+
+#define BTA_DM_MSG_LEN 50
+
+#define BTA_SERVICE_ID_TO_SERVICE_MASK(id) (1 << (id))
+
+/* DM events */
+enum {
+  /* device manager local device API events */
+  BTA_DM_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_DM),
+  BTA_DM_API_DISABLE_EVT,
+  BTA_DM_API_SET_NAME_EVT,
+  BTA_DM_API_SET_VISIBILITY_EVT,
+
+  BTA_DM_ACL_CHANGE_EVT,
+  BTA_DM_API_ADD_DEVICE_EVT,
+  BTA_DM_API_REMOVE_ACL_EVT,
+
+  /* security API events */
+  BTA_DM_API_BOND_EVT,
+  BTA_DM_API_BOND_CANCEL_EVT,
+  BTA_DM_API_PIN_REPLY_EVT,
+
+  /* power manger events */
+  BTA_DM_PM_BTM_STATUS_EVT,
+  BTA_DM_PM_TIMER_EVT,
+
+  /* simple pairing events */
+  BTA_DM_API_CONFIRM_EVT,
+
+  BTA_DM_API_SET_ENCRYPTION_EVT,
+
+  BTA_DM_API_LOC_OOB_EVT,
+  BTA_DM_CI_IO_REQ_EVT,
+  BTA_DM_CI_RMT_OOB_EVT,
+
+#if (BLE_INCLUDED == TRUE)
+  BTA_DM_API_ADD_BLEKEY_EVT,
+  BTA_DM_API_ADD_BLEDEVICE_EVT,
+  BTA_DM_API_BLE_PASSKEY_REPLY_EVT,
+  BTA_DM_API_BLE_CONFIRM_REPLY_EVT,
+  BTA_DM_API_BLE_SEC_GRANT_EVT,
+  BTA_DM_API_BLE_SET_BG_CONN_TYPE,
+  BTA_DM_API_BLE_CONN_PARAM_EVT,
+  BTA_DM_API_BLE_CONN_SCAN_PARAM_EVT,
+  BTA_DM_API_BLE_SCAN_PARAM_EVT,
+  BTA_DM_API_BLE_OBSERVE_EVT,
+  BTA_DM_API_UPDATE_CONN_PARAM_EVT,
+#if (BLE_PRIVACY_SPT == TRUE)
+  BTA_DM_API_LOCAL_PRIVACY_EVT,
+#endif
+  BTA_DM_API_SET_DATA_LENGTH_EVT,
+
+#if (BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE)
+  BTA_DM_API_CFG_FILTER_COND_EVT,
+  BTA_DM_API_SCAN_FILTER_SETUP_EVT,
+  BTA_DM_API_SCAN_FILTER_ENABLE_EVT,
+#endif
+  BTA_DM_API_BLE_SETUP_STORAGE_EVT,
+  BTA_DM_API_BLE_ENABLE_BATCH_SCAN_EVT,
+  BTA_DM_API_BLE_DISABLE_BATCH_SCAN_EVT,
+  BTA_DM_API_BLE_READ_SCAN_REPORTS_EVT,
+  BTA_DM_API_BLE_TRACK_ADVERTISER_EVT,
+  BTA_DM_API_BLE_ENERGY_INFO_EVT,
+
+#endif
+
+  BTA_DM_API_ENABLE_TEST_MODE_EVT,
+  BTA_DM_API_DISABLE_TEST_MODE_EVT,
+  BTA_DM_API_EXECUTE_CBACK_EVT,
+  BTA_DM_API_REMOVE_ALL_ACL_EVT,
+  BTA_DM_API_REMOVE_DEVICE_EVT,
+  BTA_DM_MAX_EVT
+};
+
+/* DM search events */
+enum {
+  /* DM search API events */
+  BTA_DM_API_SEARCH_EVT = BTA_SYS_EVT_START(BTA_ID_DM_SEARCH),
+  BTA_DM_API_SEARCH_CANCEL_EVT,
+  BTA_DM_API_DISCOVER_EVT,
+  BTA_DM_INQUIRY_CMPL_EVT,
+  BTA_DM_REMT_NAME_EVT,
+  BTA_DM_SDP_RESULT_EVT,
+  BTA_DM_SEARCH_CMPL_EVT,
+  BTA_DM_DISCOVERY_RESULT_EVT,
+  BTA_DM_API_DI_DISCOVER_EVT,
+  BTA_DM_DISC_CLOSE_TOUT_EVT
+
+};
+
+/* data type for BTA_DM_API_ENABLE_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_DM_SEC_CBACK* p_sec_cback;
+} tBTA_DM_API_ENABLE;
+
+/* data type for BTA_DM_API_SET_NAME_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_NAME name; /* max 248 bytes name, plus must be Null terminated */
+} tBTA_DM_API_SET_NAME;
+
+/* data type for BTA_DM_API_SET_VISIBILITY_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_DM_DISC disc_mode;
+  tBTA_DM_CONN conn_mode;
+  uint8_t pair_mode;
+  uint8_t conn_paired_only;
+} tBTA_DM_API_SET_VISIBILITY;
+
+enum {
+  BTA_DM_RS_NONE, /* straight API call */
+  BTA_DM_RS_OK,   /* the role switch result - successful */
+  BTA_DM_RS_FAIL  /* the role switch result - failed */
+};
+typedef uint8_t tBTA_DM_RS_RES;
+
+/* data type for BTA_DM_API_SEARCH_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_DM_INQ inq_params;
+  tBTA_SERVICE_MASK services;
+  tBTA_DM_SEARCH_CBACK* p_cback;
+  tBTA_DM_RS_RES rs_res;
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+  uint8_t num_uuid;
+  tBT_UUID* p_uuid;
+#endif
+} tBTA_DM_API_SEARCH;
+
+/* data type for BTA_DM_API_DISCOVER_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  tBTA_SERVICE_MASK services;
+  tBTA_DM_SEARCH_CBACK* p_cback;
+  bool sdp_search;
+  tBTA_TRANSPORT transport;
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+  uint8_t num_uuid;
+  tBT_UUID* p_uuid;
+#endif
+  tSDP_UUID uuid;
+} tBTA_DM_API_DISCOVER;
+
+/* data type for BTA_DM_API_DI_DISC_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  tBTA_DISCOVERY_DB* p_sdp_db;
+  uint32_t len;
+  tBTA_DM_SEARCH_CBACK* p_cback;
+} tBTA_DM_API_DI_DISC;
+
+/* data type for BTA_DM_API_BOND_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  tBTA_TRANSPORT transport;
+} tBTA_DM_API_BOND;
+
+/* data type for BTA_DM_API_BOND_CANCEL_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  tBTA_TRANSPORT transport;
+} tBTA_DM_API_BOND_CANCEL;
+
+/* data type for BTA_DM_API_PIN_REPLY_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  bool accept;
+  uint8_t pin_len;
+  uint8_t p_pin[PIN_CODE_LEN];
+} tBTA_DM_API_PIN_REPLY;
+
+/* data type for BTA_DM_API_LOC_OOB_EVT */
+typedef struct { BT_HDR hdr; } tBTA_DM_API_LOC_OOB;
+
+/* data type for BTA_DM_API_CONFIRM_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  bool accept;
+} tBTA_DM_API_CONFIRM;
+
+/* data type for BTA_DM_CI_IO_REQ_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  tBTA_IO_CAP io_cap;
+  tBTA_OOB_DATA oob_data;
+  tBTA_AUTH_REQ auth_req;
+} tBTA_DM_CI_IO_REQ;
+
+/* data type for BTA_DM_CI_RMT_OOB_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  BT_OCTET16 c;
+  BT_OCTET16 r;
+  bool accept;
+} tBTA_DM_CI_RMT_OOB;
+
+/* data type for BTA_DM_REMT_NAME_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_DM_SEARCH result;
+} tBTA_DM_REM_NAME;
+
+/* data type for tBTA_DM_DISC_RESULT */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_DM_SEARCH result;
+} tBTA_DM_DISC_RESULT;
+
+/* data type for BTA_DM_INQUIRY_CMPL_EVT */
+typedef struct {
+  BT_HDR hdr;
+  uint8_t num;
+} tBTA_DM_INQUIRY_CMPL;
+
+/* data type for BTA_DM_SDP_RESULT_EVT */
+typedef struct {
+  BT_HDR hdr;
+  uint16_t sdp_result;
+} tBTA_DM_SDP_RESULT;
+
+/* data type for BTA_DM_ACL_CHANGE_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tBTM_BL_EVENT event;
+  uint8_t busy_level;
+  uint8_t busy_level_flags;
+  bool is_new;
+  uint8_t new_role;
+  BD_ADDR bd_addr;
+  uint8_t hci_status;
+#if (BLE_INCLUDED == TRUE)
+  uint16_t handle;
+  tBT_TRANSPORT transport;
+#endif
+} tBTA_DM_ACL_CHANGE;
+
+/* data type for BTA_DM_PM_BTM_STATUS_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  tBTM_PM_STATUS status;
+  uint16_t value;
+  uint8_t hci_status;
+
+} tBTA_DM_PM_BTM_STATUS;
+
+/* data type for BTA_DM_PM_TIMER_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  tBTA_DM_PM_ACTION pm_request;
+} tBTA_DM_PM_TIMER;
+
+/* data type for BTA_DM_API_ADD_DEVICE_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  DEV_CLASS dc;
+  LINK_KEY link_key;
+  tBTA_SERVICE_MASK tm;
+  bool is_trusted;
+  uint8_t key_type;
+  tBTA_IO_CAP io_cap;
+  bool link_key_known;
+  bool dc_known;
+  BD_NAME bd_name;
+  uint8_t
+      features[BTA_FEATURE_BYTES_PER_PAGE * (BTA_EXT_FEATURES_PAGE_MAX + 1)];
+  uint8_t pin_length;
+} tBTA_DM_API_ADD_DEVICE;
+
+/* data type for BTA_DM_API_REMOVE_ACL_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+} tBTA_DM_API_REMOVE_DEVICE;
+
+/* data type for BTA_DM_API_EXECUTE_CBACK_EVT */
+typedef struct {
+  BT_HDR hdr;
+  void* p_param;
+  tBTA_DM_EXEC_CBACK* p_exec_cback;
+} tBTA_DM_API_EXECUTE_CBACK;
+
+/* data type for tBTA_DM_API_SET_ENCRYPTION */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_TRANSPORT transport;
+  tBTA_DM_ENCRYPT_CBACK* p_callback;
+  tBTA_DM_BLE_SEC_ACT sec_act;
+  BD_ADDR bd_addr;
+} tBTA_DM_API_SET_ENCRYPTION;
+
+#if (BLE_INCLUDED == TRUE)
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  tBTA_LE_KEY_VALUE blekey;
+  tBTA_LE_KEY_TYPE key_type;
+
+} tBTA_DM_API_ADD_BLEKEY;
+
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  tBT_DEVICE_TYPE dev_type;
+  tBLE_ADDR_TYPE addr_type;
+
+} tBTA_DM_API_ADD_BLE_DEVICE;
+
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  bool accept;
+  uint32_t passkey;
+} tBTA_DM_API_PASSKEY_REPLY;
+
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  tBTA_DM_BLE_SEC_GRANT res;
+} tBTA_DM_API_BLE_SEC_GRANT;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_DM_BLE_CONN_TYPE bg_conn_type;
+  tBTA_DM_BLE_SEL_CBACK* p_select_cback;
+} tBTA_DM_API_BLE_SET_BG_CONN_TYPE;
+
+/* set prefered BLE connection parameters for a device */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR peer_bda;
+  uint16_t conn_int_min;
+  uint16_t conn_int_max;
+  uint16_t supervision_tout;
+  uint16_t slave_latency;
+
+} tBTA_DM_API_BLE_CONN_PARAMS;
+
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR peer_bda;
+  bool privacy_enable;
+
+} tBTA_DM_API_ENABLE_PRIVACY;
+
+typedef struct {
+  BT_HDR hdr;
+  bool privacy_enable;
+} tBTA_DM_API_LOCAL_PRIVACY;
+
+/* set scan parameter for BLE connections */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_GATTC_IF client_if;
+  uint32_t scan_int;
+  uint32_t scan_window;
+  tBLE_SCAN_MODE scan_mode;
+  tBLE_SCAN_PARAM_SETUP_CBACK scan_param_setup_cback;
+} tBTA_DM_API_BLE_SCAN_PARAMS;
+
+/* set scan parameter for BLE connections */
+typedef struct {
+  BT_HDR hdr;
+  uint16_t scan_int;
+  uint16_t scan_window;
+} tBTA_DM_API_BLE_CONN_SCAN_PARAMS;
+
+/* Data type for start/stop observe */
+typedef struct {
+  BT_HDR hdr;
+  bool start;
+  uint16_t duration;
+  tBTA_DM_SEARCH_CBACK* p_cback;
+} tBTA_DM_API_BLE_OBSERVE;
+
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR remote_bda;
+  uint16_t tx_data_length;
+} tBTA_DM_API_BLE_SET_DATA_LENGTH;
+
+/* set adv parameter for BLE advertising */
+
+typedef struct {
+  BT_HDR hdr;
+  bool enable;
+
+} tBTA_DM_API_BLE_FEATURE;
+
+/* adv data structure */
+typedef struct {
+  BT_HDR hdr;
+  uint8_t batch_scan_full_max;
+  uint8_t batch_scan_trunc_max;
+  uint8_t batch_scan_notify_threshold;
+  tBTA_BLE_SCAN_SETUP_CBACK* p_setup_cback;
+  tBTA_BLE_SCAN_THRESHOLD_CBACK* p_thres_cback;
+  tBTA_BLE_SCAN_REP_CBACK* p_read_rep_cback;
+  tBTA_DM_BLE_REF_VALUE ref_value;
+} tBTA_DM_API_SET_STORAGE_CONFIG;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_BLE_BATCH_SCAN_MODE scan_mode;
+  uint32_t scan_int;
+  uint32_t scan_window;
+  tBTA_BLE_DISCARD_RULE discard_rule;
+  tBLE_ADDR_TYPE addr_type;
+  tBTA_DM_BLE_REF_VALUE ref_value;
+} tBTA_DM_API_ENABLE_SCAN;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_DM_BLE_REF_VALUE ref_value;
+} tBTA_DM_API_DISABLE_SCAN;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_BLE_BATCH_SCAN_MODE scan_type;
+  tBTA_DM_BLE_REF_VALUE ref_value;
+} tBTA_DM_API_READ_SCAN_REPORTS;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_DM_BLE_REF_VALUE ref_value;
+  tBTA_BLE_TRACK_ADV_CBACK* p_track_adv_cback;
+} tBTA_DM_API_TRACK_ADVERTISER;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_BLE_ENERGY_INFO_CBACK* p_energy_info_cback;
+} tBTA_DM_API_ENERGY_INFO;
+
+#endif /* BLE_INCLUDED */
+
+/* data type for BTA_DM_API_REMOVE_ACL_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  bool remove_dev;
+  tBTA_TRANSPORT transport;
+
+} tBTA_DM_API_REMOVE_ACL;
+
+/* data type for BTA_DM_API_REMOVE_ALL_ACL_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_DM_LINK_TYPE link_type;
+
+} tBTA_DM_API_REMOVE_ALL_ACL;
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  uint16_t min_int;
+  uint16_t max_int;
+  uint16_t latency;
+  uint16_t timeout;
+} tBTA_DM_API_UPDATE_CONN_PARAM;
+
+#if (BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE)
+typedef struct {
+  BT_HDR hdr;
+  tBTA_DM_BLE_SCAN_COND_OP action;
+  tBTA_DM_BLE_PF_COND_TYPE cond_type;
+  tBTA_DM_BLE_PF_FILT_INDEX filt_index;
+  tBTA_DM_BLE_PF_COND_PARAM* p_cond_param;
+  tBTA_DM_BLE_PF_CFG_CBACK* p_filt_cfg_cback;
+  tBTA_DM_BLE_REF_VALUE ref_value;
+} tBTA_DM_API_CFG_FILTER_COND;
+
+typedef struct {
+  BT_HDR hdr;
+  uint8_t action;
+  tBTA_DM_BLE_PF_STATUS_CBACK* p_filt_status_cback;
+  tBTA_DM_BLE_REF_VALUE ref_value;
+} tBTA_DM_API_ENABLE_SCAN_FILTER;
+
+typedef struct {
+  BT_HDR hdr;
+  uint8_t action;
+  tBTA_DM_BLE_PF_FILT_INDEX filt_index;
+  tBTA_DM_BLE_PF_FILT_PARAMS filt_params;
+  tBLE_BD_ADDR* p_target;
+  tBTA_DM_BLE_PF_PARAM_CBACK* p_filt_param_cback;
+  tBTA_DM_BLE_REF_VALUE ref_value;
+} tBTA_DM_API_SCAN_FILTER_PARAM_SETUP;
+#endif
+
+/* union of all data types */
+typedef union {
+  /* GKI event buffer header */
+  BT_HDR hdr;
+  tBTA_DM_API_ENABLE enable;
+
+  tBTA_DM_API_SET_NAME set_name;
+
+  tBTA_DM_API_SET_VISIBILITY set_visibility;
+
+  tBTA_DM_API_ADD_DEVICE add_dev;
+
+  tBTA_DM_API_REMOVE_DEVICE remove_dev;
+
+  tBTA_DM_API_SEARCH search;
+
+  tBTA_DM_API_DISCOVER discover;
+
+  tBTA_DM_API_BOND bond;
+
+  tBTA_DM_API_BOND_CANCEL bond_cancel;
+
+  tBTA_DM_API_PIN_REPLY pin_reply;
+
+  tBTA_DM_API_LOC_OOB loc_oob;
+  tBTA_DM_API_CONFIRM confirm;
+  tBTA_DM_CI_IO_REQ ci_io_req;
+  tBTA_DM_CI_RMT_OOB ci_rmt_oob;
+
+  tBTA_DM_REM_NAME rem_name;
+
+  tBTA_DM_DISC_RESULT disc_result;
+
+  tBTA_DM_INQUIRY_CMPL inq_cmpl;
+
+  tBTA_DM_SDP_RESULT sdp_event;
+
+  tBTA_DM_ACL_CHANGE acl_change;
+
+  tBTA_DM_PM_BTM_STATUS pm_status;
+
+  tBTA_DM_PM_TIMER pm_timer;
+
+  tBTA_DM_API_DI_DISC di_disc;
+
+  tBTA_DM_API_EXECUTE_CBACK exec_cback;
+
+  tBTA_DM_API_SET_ENCRYPTION set_encryption;
+
+#if (BLE_INCLUDED == TRUE)
+  tBTA_DM_API_ADD_BLEKEY add_ble_key;
+  tBTA_DM_API_ADD_BLE_DEVICE add_ble_device;
+  tBTA_DM_API_PASSKEY_REPLY ble_passkey_reply;
+  tBTA_DM_API_BLE_SEC_GRANT ble_sec_grant;
+  tBTA_DM_API_BLE_SET_BG_CONN_TYPE ble_set_bd_conn_type;
+  tBTA_DM_API_BLE_CONN_PARAMS ble_set_conn_params;
+  tBTA_DM_API_BLE_CONN_SCAN_PARAMS ble_set_conn_scan_params;
+  tBTA_DM_API_BLE_SCAN_PARAMS ble_set_scan_params;
+  tBTA_DM_API_BLE_OBSERVE ble_observe;
+  tBTA_DM_API_ENABLE_PRIVACY ble_remote_privacy;
+  tBTA_DM_API_LOCAL_PRIVACY ble_local_privacy;
+#if (BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE)
+  tBTA_DM_API_SCAN_FILTER_PARAM_SETUP ble_scan_filt_param_setup;
+  tBTA_DM_API_CFG_FILTER_COND ble_cfg_filter_cond;
+  tBTA_DM_API_ENABLE_SCAN_FILTER ble_enable_scan_filt;
+#endif
+  tBTA_DM_API_UPDATE_CONN_PARAM ble_update_conn_params;
+  tBTA_DM_API_BLE_SET_DATA_LENGTH ble_set_data_length;
+
+  tBTA_DM_API_SET_STORAGE_CONFIG ble_set_storage;
+  tBTA_DM_API_ENABLE_SCAN ble_enable_scan;
+  tBTA_DM_API_READ_SCAN_REPORTS ble_read_reports;
+  tBTA_DM_API_DISABLE_SCAN ble_disable_scan;
+  tBTA_DM_API_TRACK_ADVERTISER ble_track_advert;
+  tBTA_DM_API_ENERGY_INFO ble_energy_info;
+#endif
+
+  tBTA_DM_API_REMOVE_ACL remove_acl;
+  tBTA_DM_API_REMOVE_ALL_ACL remove_all_acl;
+
+} tBTA_DM_MSG;
+
+#define BTA_DM_NUM_PEER_DEVICE 7
+
+#define BTA_DM_NOT_CONNECTED 0
+#define BTA_DM_CONNECTED 1
+#define BTA_DM_UNPAIRING 2
+typedef uint8_t tBTA_DM_CONN_STATE;
+
+#define BTA_DM_DI_NONE 0x00 /* nothing special */
+#define BTA_DM_DI_USE_SSR \
+  0x10 /* set this bit if ssr is supported for this link */
+#define BTA_DM_DI_AV_ACTIVE \
+  0x20 /* set this bit if AV is active for this link */
+#define BTA_DM_DI_SET_SNIFF \
+  0x01 /* set this bit if call BTM_SetPowerMode(sniff) */
+#define BTA_DM_DI_INT_SNIFF \
+  0x02 /* set this bit if call BTM_SetPowerMode(sniff) & enter sniff mode */
+#define BTA_DM_DI_ACP_SNIFF 0x04 /* set this bit if peer init sniff */
+typedef uint8_t tBTA_DM_DEV_INFO;
+
+/* set power mode request type */
+#define BTA_DM_PM_RESTART 1
+#define BTA_DM_PM_NEW_REQ 2
+#define BTA_DM_PM_EXECUTE 3
+typedef uint8_t tBTA_DM_PM_REQ;
+
+typedef struct {
+  BD_ADDR peer_bdaddr;
+  uint16_t link_policy;
+  tBTA_DM_CONN_STATE conn_state;
+  tBTA_PREF_ROLES pref_role;
+  bool in_use;
+  tBTA_DM_DEV_INFO info;
+  tBTA_DM_ENCRYPT_CBACK* p_encrypt_cback;
+#if (BTM_SSR_INCLUDED == TRUE)
+  tBTM_PM_STATUS prev_low; /* previous low power mode used */
+#endif
+  tBTA_DM_PM_ACTION pm_mode_attempted;
+  tBTA_DM_PM_ACTION pm_mode_failed;
+  bool remove_dev_pending;
+#if (BLE_INCLUDED == TRUE)
+  uint16_t conn_handle;
+  tBT_TRANSPORT transport;
+#endif
+} tBTA_DM_PEER_DEVICE;
+
+/* structure to store list of
+  active connections */
+typedef struct {
+  tBTA_DM_PEER_DEVICE peer_device[BTA_DM_NUM_PEER_DEVICE];
+  uint8_t count;
+#if (BLE_INCLUDED == TRUE)
+  uint8_t le_count;
+#endif
+} tBTA_DM_ACTIVE_LINK;
+
+typedef struct {
+  BD_ADDR peer_bdaddr;
+  tBTA_SYS_ID id;
+  uint8_t app_id;
+  tBTA_SYS_CONN_STATUS state;
+  bool new_request;
+
+} tBTA_DM_SRVCS;
+
+#ifndef BTA_DM_NUM_CONN_SRVS
+#define BTA_DM_NUM_CONN_SRVS 10
+#endif
+
+typedef struct {
+  uint8_t count;
+  tBTA_DM_SRVCS conn_srvc[BTA_DM_NUM_CONN_SRVS];
+
+} tBTA_DM_CONNECTED_SRVCS;
+
+typedef struct {
+#define BTA_DM_PM_SNIFF_TIMER_IDX 0
+#define BTA_DM_PM_PARK_TIMER_IDX 1
+#define BTA_DM_PM_SUSPEND_TIMER_IDX 2
+#define BTA_DM_PM_MODE_TIMER_MAX 3
+  /*
+   * Keep three different timers for PARK, SNIFF and SUSPEND if TBFC is
+   * supported.
+   */
+  alarm_t* timer[BTA_DM_PM_MODE_TIMER_MAX];
+
+  uint8_t srvc_id[BTA_DM_PM_MODE_TIMER_MAX];
+  uint8_t pm_action[BTA_DM_PM_MODE_TIMER_MAX];
+  uint8_t active; /* number of active timer */
+
+  BD_ADDR peer_bdaddr;
+  bool in_use;
+} tBTA_PM_TIMER;
+
+extern tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs;
+
+#define BTA_DM_NUM_PM_TIMER 7
+
+/* DM control block */
+typedef struct {
+  bool is_bta_dm_active;
+  tBTA_DM_ACTIVE_LINK device_list;
+  tBTA_DM_SEC_CBACK* p_sec_cback;
+#if (BLE_INCLUDED == TRUE)
+  tBTA_BLE_SCAN_SETUP_CBACK* p_setup_cback;
+  tBTA_DM_BLE_PF_CFG_CBACK* p_scan_filt_cfg_cback;
+  tBTA_DM_BLE_PF_STATUS_CBACK* p_scan_filt_status_cback;
+  tBTA_DM_BLE_PF_PARAM_CBACK* p_scan_filt_param_cback;
+  tBTA_BLE_ENERGY_INFO_CBACK* p_energy_info_cback;
+#endif
+  uint16_t state;
+  bool disabling;
+  alarm_t* disable_timer;
+  uint32_t wbt_sdp_handle; /* WIDCOMM Extensions SDP record handle */
+  uint8_t wbt_scn;         /* WIDCOMM Extensions SCN */
+  uint8_t num_master_only;
+  uint8_t pm_id;
+  tBTA_PM_TIMER pm_timer[BTA_DM_NUM_PM_TIMER];
+  uint32_t
+      role_policy_mask;   /* the bits set indicates the modules that wants to
+                             remove role switch from the default link policy */
+  uint16_t cur_policy;    /* current default link policy */
+  uint16_t rs_event;      /* the event waiting for role switch */
+  uint8_t cur_av_count;   /* current AV connecions */
+  bool disable_pair_mode; /* disable pair mode or not */
+  bool conn_paired_only;  /* allow connectable to paired device only or not */
+  tBTA_DM_API_SEARCH search_msg;
+  uint16_t page_scan_interval;
+  uint16_t page_scan_window;
+  uint16_t inquiry_scan_interval;
+  uint16_t inquiry_scan_window;
+
+  /* Storage for pin code request parameters */
+  BD_ADDR pin_bd_addr;
+  DEV_CLASS pin_dev_class;
+  tBTA_DM_SEC_EVT pin_evt;
+  uint32_t num_val; /* the numeric value for comparison. If just_works, do not
+                       show this number to UI */
+  bool just_works;  /* true, if "Just Works" association model */
+#if (BTA_EIR_CANNED_UUID_LIST != TRUE)
+  /* store UUID list for EIR */
+  uint32_t eir_uuid[BTM_EIR_SERVICE_ARRAY_SIZE];
+#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0)
+  tBT_UUID custom_uuid[BTA_EIR_SERVER_NUM_CUSTOM_UUID];
+#endif
+
+#endif
+
+  tBTA_DM_ENCRYPT_CBACK* p_encrypt_cback;
+  alarm_t* switch_delay_timer;
+
+} tBTA_DM_CB;
+
+/* DM search control block */
+typedef struct {
+  tBTA_DM_SEARCH_CBACK* p_search_cback;
+  tBTM_INQ_INFO* p_btm_inq_info;
+  tBTA_SERVICE_MASK services;
+  tBTA_SERVICE_MASK services_to_search;
+  tBTA_SERVICE_MASK services_found;
+  tSDP_DISCOVERY_DB* p_sdp_db;
+  uint16_t state;
+  BD_ADDR peer_bdaddr;
+  bool name_discover_done;
+  BD_NAME peer_name;
+  alarm_t* search_timer;
+  uint8_t service_index;
+  tBTA_DM_MSG* p_search_queue; /* search or discover commands during search
+                                  cancel stored here */
+  bool wait_disc;
+  bool sdp_results;
+  tSDP_UUID uuid;
+  uint8_t peer_scn;
+  bool sdp_search;
+  bool cancel_pending; /* inquiry cancel is pending */
+  tBTA_TRANSPORT transport;
+#if (BLE_INCLUDED == TRUE)
+  tBTA_DM_SEARCH_CBACK* p_scan_cback;
+#if (BTA_GATT_INCLUDED == TRUE)
+  tBTA_GATTC_IF client_if;
+  uint8_t num_uuid;
+  tBT_UUID* p_srvc_uuid;
+  uint8_t uuid_to_search;
+  bool gatt_disc_active;
+  uint16_t conn_id;
+  uint8_t* p_ble_rawdata;
+  uint32_t ble_raw_size;
+  uint32_t ble_raw_used;
+  alarm_t* gatt_close_timer; /* GATT channel close delay timer */
+  BD_ADDR pending_close_bda; /* pending GATT channel remote device address */
+#endif
+#endif
+
+} tBTA_DM_SEARCH_CB;
+
+/* DI control block */
+typedef struct {
+  tSDP_DISCOVERY_DB* p_di_db;         /* pointer to the DI discovery database */
+  uint8_t di_num;                     /* total local DI record number */
+  uint32_t di_handle[BTA_DI_NUM_MAX]; /* local DI record handle, the first one
+                                         is primary record */
+} tBTA_DM_DI_CB;
+
+/* DM search state */
+enum {
+
+  BTA_DM_SEARCH_IDLE,
+  BTA_DM_SEARCH_ACTIVE,
+  BTA_DM_SEARCH_CANCELLING,
+  BTA_DM_DISCOVER_ACTIVE
+
+};
+
+typedef struct {
+  DEV_CLASS dev_class; /* local device class */
+  uint16_t
+      policy_settings;   /* link policy setting hold, sniff, park, MS switch */
+  uint16_t page_timeout; /* timeout for page in slots */
+  uint16_t link_timeout; /* link supervision timeout in slots */
+  bool avoid_scatter; /* true to avoid scatternet when av is streaming (be the
+                         master) */
+
+} tBTA_DM_CFG;
+
+extern const uint32_t bta_service_id_to_btm_srv_id_lkup_tbl[];
+
+typedef struct {
+  uint8_t id;
+  uint8_t app_id;
+  uint8_t cfg;
+
+} tBTA_DM_RM;
+
+extern tBTA_DM_CFG* p_bta_dm_cfg;
+extern tBTA_DM_RM* p_bta_dm_rm_cfg;
+
+typedef struct {
+  uint8_t id;
+  uint8_t app_id;
+  uint8_t spec_idx; /* index of spec table to use */
+
+} tBTA_DM_PM_CFG;
+
+typedef struct {
+  tBTA_DM_PM_ACTION power_mode;
+  uint16_t timeout;
+
+} tBTA_DM_PM_ACTN;
+
+typedef struct {
+  uint8_t allow_mask; /* mask of sniff/hold/park modes to allow */
+#if (BTM_SSR_INCLUDED == TRUE)
+  uint8_t ssr; /* set SSR on conn open/unpark */
+#endif
+  tBTA_DM_PM_ACTN actn_tbl[BTA_DM_PM_NUM_EVTS][2];
+
+} tBTA_DM_PM_SPEC;
+
+typedef struct {
+  uint16_t max_lat;
+  uint16_t min_rmt_to;
+  uint16_t min_loc_to;
+} tBTA_DM_SSR_SPEC;
+
+typedef struct {
+  uint16_t manufacturer;
+  uint16_t lmp_sub_version;
+  uint8_t lmp_version;
+} tBTA_DM_LMP_VER_INFO;
+
+extern const uint16_t bta_service_id_to_uuid_lkup_tbl[];
+
+extern tBTA_DM_PM_CFG* p_bta_dm_pm_cfg;
+extern tBTA_DM_PM_SPEC* p_bta_dm_pm_spec;
+extern tBTM_PM_PWR_MD* p_bta_dm_pm_md;
+#if (BTM_SSR_INCLUDED == TRUE)
+extern tBTA_DM_SSR_SPEC* p_bta_dm_ssr_spec;
+#endif
+
+/* update dynamic BRCM Aware EIR data */
+extern const tBTA_DM_EIR_CONF bta_dm_eir_cfg;
+extern tBTA_DM_EIR_CONF* p_bta_dm_eir_cfg;
+
+/* DM control block */
+extern tBTA_DM_CB bta_dm_cb;
+
+/* DM search control block */
+extern tBTA_DM_SEARCH_CB bta_dm_search_cb;
+
+/* DI control block */
+extern tBTA_DM_DI_CB bta_dm_di_cb;
+
+extern bool bta_dm_sm_execute(BT_HDR* p_msg);
+extern void bta_dm_sm_disable(void);
+extern bool bta_dm_search_sm_execute(BT_HDR* p_msg);
+extern void bta_dm_search_sm_disable(void);
+
+extern void bta_dm_enable(tBTA_DM_MSG* p_data);
+extern void bta_dm_disable(tBTA_DM_MSG* p_data);
+extern void bta_dm_init_cb(void);
+extern void bta_dm_set_dev_name(tBTA_DM_MSG* p_data);
+extern void bta_dm_set_visibility(tBTA_DM_MSG* p_data);
+
+extern void bta_dm_set_scan_config(tBTA_DM_MSG* p_data);
+extern void bta_dm_vendor_spec_command(tBTA_DM_MSG* p_data);
+extern void bta_dm_bond(tBTA_DM_MSG* p_data);
+extern void bta_dm_bond_cancel(tBTA_DM_MSG* p_data);
+extern void bta_dm_pin_reply(tBTA_DM_MSG* p_data);
+extern void bta_dm_acl_change(tBTA_DM_MSG* p_data);
+extern void bta_dm_add_device(tBTA_DM_MSG* p_data);
+extern void bta_dm_remove_device(tBTA_DM_MSG* p_data);
+extern void bta_dm_close_acl(tBTA_DM_MSG* p_data);
+
+extern void bta_dm_pm_btm_status(tBTA_DM_MSG* p_data);
+extern void bta_dm_pm_timer(tBTA_DM_MSG* p_data);
+extern void bta_dm_add_ampkey(tBTA_DM_MSG* p_data);
+
+#if (BLE_INCLUDED == TRUE)
+extern void bta_dm_add_blekey(tBTA_DM_MSG* p_data);
+extern void bta_dm_add_ble_device(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_passkey_reply(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_confirm_reply(tBTA_DM_MSG* p_data);
+extern void bta_dm_security_grant(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_set_bg_conn_type(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_set_conn_params(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_set_scan_params(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_set_conn_scan_params(tBTA_DM_MSG* p_data);
+extern void bta_dm_close_gatt_conn(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_observe(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_update_conn_params(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_config_local_privacy(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_set_adv_params(uint16_t adv_int_min,
+                                      uint16_t adv_int_max,
+                                      tBLE_BD_ADDR* p_dir_bda);
+
+extern void bta_dm_ble_set_data_length(tBTA_DM_MSG* p_data);
+
+#if (BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE)
+extern void bta_dm_cfg_filter_cond(tBTA_DM_MSG* p_data);
+extern void bta_dm_scan_filter_param_setup(tBTA_DM_MSG* p_data);
+extern void bta_dm_enable_scan_filter(tBTA_DM_MSG* p_data);
+#endif
+
+extern void bta_dm_ble_setup_storage(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_enable_batch_scan(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_disable_batch_scan(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_read_scan_reports(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_track_advertiser(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_get_energy_info(tBTA_DM_MSG* p_data);
+
+#endif
+extern void bta_dm_set_encryption(tBTA_DM_MSG* p_data);
+extern void bta_dm_confirm(tBTA_DM_MSG* p_data);
+extern void bta_dm_loc_oob(tBTA_DM_MSG* p_data);
+extern void bta_dm_ci_io_req_act(tBTA_DM_MSG* p_data);
+extern void bta_dm_ci_rmt_oob_act(tBTA_DM_MSG* p_data);
+
+extern void bta_dm_init_pm(void);
+extern void bta_dm_disable_pm(void);
+
+extern uint8_t bta_dm_get_av_count(void);
+extern void bta_dm_search_start(tBTA_DM_MSG* p_data);
+extern void bta_dm_search_cancel(tBTA_DM_MSG* p_data);
+extern void bta_dm_discover(tBTA_DM_MSG* p_data);
+extern void bta_dm_di_disc(tBTA_DM_MSG* p_data);
+extern void bta_dm_inq_cmpl(tBTA_DM_MSG* p_data);
+extern void bta_dm_rmt_name(tBTA_DM_MSG* p_data);
+extern void bta_dm_sdp_result(tBTA_DM_MSG* p_data);
+extern void bta_dm_search_cmpl(tBTA_DM_MSG* p_data);
+extern void bta_dm_free_sdp_db(tBTA_DM_MSG* p_data);
+extern void bta_dm_disc_result(tBTA_DM_MSG* p_data);
+extern void bta_dm_search_result(tBTA_DM_MSG* p_data);
+extern void bta_dm_discovery_cmpl(tBTA_DM_MSG* p_data);
+extern void bta_dm_queue_search(tBTA_DM_MSG* p_data);
+extern void bta_dm_queue_disc(tBTA_DM_MSG* p_data);
+extern void bta_dm_search_clear_queue(tBTA_DM_MSG* p_data);
+extern void bta_dm_search_cancel_cmpl(tBTA_DM_MSG* p_data);
+extern void bta_dm_search_cancel_notify(tBTA_DM_MSG* p_data);
+extern void bta_dm_search_cancel_transac_cmpl(tBTA_DM_MSG* p_data);
+extern void bta_dm_disc_rmt_name(tBTA_DM_MSG* p_data);
+extern tBTA_DM_PEER_DEVICE* bta_dm_find_peer_device(const BD_ADDR peer_addr);
+
+void bta_dm_eir_update_uuid(uint16_t uuid16, bool adding);
+
+extern void bta_dm_enable_test_mode(tBTA_DM_MSG* p_data);
+extern void bta_dm_disable_test_mode(tBTA_DM_MSG* p_data);
+extern void bta_dm_execute_callback(tBTA_DM_MSG* p_data);
+
+extern void bta_dm_remove_all_acl(tBTA_DM_MSG* p_data);
+#endif /* BTA_DM_INT_H */
diff --git a/bt/bta/dm/bta_dm_main.cc b/bt/bta/dm/bta_dm_main.cc
new file mode 100644
index 0000000..ecbff69
--- /dev/null
+++ b/bt/bta/dm/bta_dm_main.cc
@@ -0,0 +1,375 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 is the main implementation file for the BTA device manager.
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+#include "bta_dm_int.h"
+#include "bta_sys.h"
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+
+tBTA_DM_CB bta_dm_cb;
+tBTA_DM_SEARCH_CB bta_dm_search_cb;
+tBTA_DM_DI_CB bta_dm_di_cb;
+
+#define BTA_DM_NUM_ACTIONS (BTA_DM_MAX_EVT & 0x00ff)
+
+/* type for action functions */
+typedef void (*tBTA_DM_ACTION)(tBTA_DM_MSG* p_data);
+
+/* action function list */
+const tBTA_DM_ACTION bta_dm_action[] = {
+
+    /* device manager local device API events */
+    bta_dm_enable,         /* 0  BTA_DM_API_ENABLE_EVT */
+    bta_dm_disable,        /* 1  BTA_DM_API_DISABLE_EVT */
+    bta_dm_set_dev_name,   /* 2  BTA_DM_API_SET_NAME_EVT */
+    bta_dm_set_visibility, /* 3  BTA_DM_API_SET_VISIBILITY_EVT */
+    bta_dm_acl_change,     /* 8  BTA_DM_ACL_CHANGE_EVT */
+    bta_dm_add_device,     /* 9  BTA_DM_API_ADD_DEVICE_EVT */
+    bta_dm_close_acl,      /* 10  BTA_DM_API_ADD_DEVICE_EVT */
+
+    /* security API events */
+    bta_dm_bond,        /* 11  BTA_DM_API_BOND_EVT */
+    bta_dm_bond_cancel, /* 12  BTA_DM_API_BOND_CANCEL_EVT */
+    bta_dm_pin_reply,   /* 13 BTA_DM_API_PIN_REPLY_EVT */
+
+    /* power manger events */
+    bta_dm_pm_btm_status, /* 16 BTA_DM_PM_BTM_STATUS_EVT */
+    bta_dm_pm_timer,      /* 17 BTA_DM_PM_TIMER_EVT*/
+
+    /* simple pairing events */
+    bta_dm_confirm, /* 18 BTA_DM_API_CONFIRM_EVT */
+
+    bta_dm_set_encryption, /* BTA_DM_API_SET_ENCRYPTION_EVT */
+
+    /* out of band pairing events */
+    bta_dm_loc_oob,        /* 20 BTA_DM_API_LOC_OOB_EVT */
+    bta_dm_ci_io_req_act,  /* 21 BTA_DM_CI_IO_REQ_EVT */
+    bta_dm_ci_rmt_oob_act, /* 22 BTA_DM_CI_RMT_OOB_EVT */
+
+#if (BLE_INCLUDED == TRUE)
+    bta_dm_add_blekey,        /*  BTA_DM_API_ADD_BLEKEY_EVT           */
+    bta_dm_add_ble_device,    /*  BTA_DM_API_ADD_BLEDEVICE_EVT        */
+    bta_dm_ble_passkey_reply, /*  BTA_DM_API_BLE_PASSKEY_REPLY_EVT    */
+    bta_dm_ble_confirm_reply, /*  BTA_DM_API_BLE_CONFIRM_REPLY_EVT    */
+    bta_dm_security_grant, bta_dm_ble_set_bg_conn_type,
+    bta_dm_ble_set_conn_params,      /* BTA_DM_API_BLE_CONN_PARAM_EVT */
+    bta_dm_ble_set_conn_scan_params, /* BTA_DM_API_BLE_CONN_SCAN_PARAM_EVT */
+    bta_dm_ble_set_scan_params,      /* BTA_DM_API_BLE_SCAN_PARAM_EVT */
+    bta_dm_ble_observe,
+    bta_dm_ble_update_conn_params, /* BTA_DM_API_UPDATE_CONN_PARAM_EVT */
+#if (BLE_PRIVACY_SPT == TRUE)
+    bta_dm_ble_config_local_privacy, /* BTA_DM_API_LOCAL_PRIVACY_EVT */
+#endif
+    bta_dm_ble_set_data_length, /* BTA_DM_API_SET_DATA_LENGTH_EVT */
+#if (BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE)
+    bta_dm_cfg_filter_cond,         /* BTA_DM_API_CFG_FILTER_COND_EVT */
+    bta_dm_scan_filter_param_setup, /* BTA_DM_API_SCAN_FILTER_SETUP_EVT */
+    bta_dm_enable_scan_filter,      /* BTA_DM_API_SCAN_FILTER_ENABLE_EVT */
+#endif
+    bta_dm_ble_setup_storage,      /* BTA_DM_API_BLE_SETUP_STORAGE_EVT */
+    bta_dm_ble_enable_batch_scan,  /* BTA_DM_API_BLE_ENABLE_BATCH_SCAN_EVT */
+    bta_dm_ble_disable_batch_scan, /* BTA_DM_API_BLE_DISABLE_BATCH_SCAN_EVT */
+    bta_dm_ble_read_scan_reports,  /* BTA_DM_API_BLE_READ_SCAN_REPORTS_EVT */
+    bta_dm_ble_track_advertiser,   /* BTA_DM_API_BLE_TRACK_ADVERTISER_EVT */
+    bta_dm_ble_get_energy_info,    /* BTA_DM_API_BLE_ENERGY_INFO_EVT */
+#endif
+
+    bta_dm_enable_test_mode,  /*  BTA_DM_API_ENABLE_TEST_MODE_EVT     */
+    bta_dm_disable_test_mode, /*  BTA_DM_API_DISABLE_TEST_MODE_EVT    */
+    bta_dm_execute_callback,  /*  BTA_DM_API_EXECUTE_CBACK_EVT        */
+
+    bta_dm_remove_all_acl, /* BTA_DM_API_REMOVE_ALL_ACL_EVT */
+    bta_dm_remove_device,  /* BTA_DM_API_REMOVE_DEVICE_EVT */
+};
+
+/* state machine action enumeration list */
+enum {
+  BTA_DM_API_SEARCH,                 /* 0 bta_dm_search_start */
+  BTA_DM_API_SEARCH_CANCEL,          /* 1 bta_dm_search_cancel */
+  BTA_DM_API_DISCOVER,               /* 2 bta_dm_discover */
+  BTA_DM_INQUIRY_CMPL,               /* 3 bta_dm_inq_cmpl */
+  BTA_DM_REMT_NAME,                  /* 4 bta_dm_rmt_name */
+  BTA_DM_SDP_RESULT,                 /* 5 bta_dm_sdp_result */
+  BTA_DM_SEARCH_CMPL,                /* 6 bta_dm_search_cmpl*/
+  BTA_DM_FREE_SDP_DB,                /* 7 bta_dm_free_sdp_db */
+  BTA_DM_DISC_RESULT,                /* 8 bta_dm_disc_result */
+  BTA_DM_SEARCH_RESULT,              /* 9 bta_dm_search_result */
+  BTA_DM_QUEUE_SEARCH,               /* 10 bta_dm_queue_search */
+  BTA_DM_QUEUE_DISC,                 /* 11 bta_dm_queue_disc */
+  BTA_DM_SEARCH_CLEAR_QUEUE,         /* 12 bta_dm_search_clear_queue */
+  BTA_DM_SEARCH_CANCEL_CMPL,         /* 13 bta_dm_search_cancel_cmpl */
+  BTA_DM_SEARCH_CANCEL_NOTIFY,       /* 14 bta_dm_search_cancel_notify */
+  BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL, /* 15 bta_dm_search_cancel_transac_cmpl */
+  BTA_DM_DISC_RMT_NAME,              /* 16 bta_dm_disc_rmt_name */
+  BTA_DM_API_DI_DISCOVER,            /* 17 bta_dm_di_disc */
+#if (BLE_INCLUDED == TRUE)
+  BTA_DM_CLOSE_GATT_CONN, /* 18 bta_dm_close_gatt_conn */
+#endif
+  BTA_DM_SEARCH_NUM_ACTIONS /* 19 */
+};
+
+/* action function list */
+const tBTA_DM_ACTION bta_dm_search_action[] = {
+
+    bta_dm_search_start,               /* 0 BTA_DM_API_SEARCH */
+    bta_dm_search_cancel,              /* 1 BTA_DM_API_SEARCH_CANCEL */
+    bta_dm_discover,                   /* 2 BTA_DM_API_DISCOVER */
+    bta_dm_inq_cmpl,                   /* 3 BTA_DM_INQUIRY_CMPL */
+    bta_dm_rmt_name,                   /* 4 BTA_DM_REMT_NAME */
+    bta_dm_sdp_result,                 /* 5 BTA_DM_SDP_RESULT */
+    bta_dm_search_cmpl,                /* 6 BTA_DM_SEARCH_CMPL */
+    bta_dm_free_sdp_db,                /* 7 BTA_DM_FREE_SDP_DB */
+    bta_dm_disc_result,                /* 8 BTA_DM_DISC_RESULT */
+    bta_dm_search_result,              /* 9 BTA_DM_SEARCH_RESULT */
+    bta_dm_queue_search,               /* 10 BTA_DM_QUEUE_SEARCH */
+    bta_dm_queue_disc,                 /* 11 BTA_DM_QUEUE_DISC */
+    bta_dm_search_clear_queue,         /* 12 BTA_DM_SEARCH_CLEAR_QUEUE */
+    bta_dm_search_cancel_cmpl,         /* 13 BTA_DM_SEARCH_CANCEL_CMPL */
+    bta_dm_search_cancel_notify,       /* 14 BTA_DM_SEARCH_CANCEL_NOTIFY */
+    bta_dm_search_cancel_transac_cmpl, /* 15 BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL
+                                          */
+    bta_dm_disc_rmt_name,              /* 16 BTA_DM_DISC_RMT_NAME */
+    bta_dm_di_disc                     /* 17 BTA_DM_API_DI_DISCOVER */
+#if (BLE_INCLUDED == TRUE)
+    ,
+    bta_dm_close_gatt_conn
+#endif
+};
+
+#define BTA_DM_SEARCH_IGNORE BTA_DM_SEARCH_NUM_ACTIONS
+/* state table information */
+#define BTA_DM_SEARCH_ACTIONS 2    /* number of actions */
+#define BTA_DM_SEARCH_NEXT_STATE 2 /* position of next state */
+#define BTA_DM_SEARCH_NUM_COLS 3   /* number of columns in state tables */
+
+/* state table for listen state */
+const uint8_t bta_dm_search_idle_st_table[][BTA_DM_SEARCH_NUM_COLS] = {
+
+    /* Event                        Action 1
+       Action 2                    Next State */
+    /* API_SEARCH */ {BTA_DM_API_SEARCH, BTA_DM_SEARCH_IGNORE,
+                      BTA_DM_SEARCH_ACTIVE},
+    /* API_SEARCH_CANCEL */ {BTA_DM_SEARCH_CANCEL_NOTIFY, BTA_DM_SEARCH_IGNORE,
+                             BTA_DM_SEARCH_IDLE},
+    /* API_SEARCH_DISC */ {BTA_DM_API_DISCOVER, BTA_DM_SEARCH_IGNORE,
+                           BTA_DM_DISCOVER_ACTIVE},
+    /* INQUIRY_CMPL */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+                        BTA_DM_SEARCH_IDLE},
+    /* REMT_NAME_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+                         BTA_DM_SEARCH_IDLE},
+    /* SDP_RESULT_EVT */ {BTA_DM_FREE_SDP_DB, BTA_DM_SEARCH_IGNORE,
+                          BTA_DM_SEARCH_IDLE},
+    /* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+                           BTA_DM_SEARCH_IDLE},
+    /* DISCV_RES_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+                         BTA_DM_SEARCH_IDLE},
+    /* API_DI_DISCOVER_EVT */ {BTA_DM_API_DI_DISCOVER, BTA_DM_SEARCH_IGNORE,
+                               BTA_DM_SEARCH_ACTIVE}
+#if (BLE_INCLUDED == TRUE)
+    /* DISC_CLOSE_TOUT_EVT */,
+    {BTA_DM_CLOSE_GATT_CONN, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}
+#endif
+};
+const uint8_t bta_dm_search_search_active_st_table[][BTA_DM_SEARCH_NUM_COLS] = {
+
+    /* Event                        Action 1
+       Action 2                    Next State */
+    /* API_SEARCH */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+                      BTA_DM_SEARCH_ACTIVE},
+    /* API_SEARCH_CANCEL */ {BTA_DM_API_SEARCH_CANCEL, BTA_DM_SEARCH_IGNORE,
+                             BTA_DM_SEARCH_CANCELLING},
+    /* API_SEARCH_DISC */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+                           BTA_DM_SEARCH_ACTIVE},
+    /* INQUIRY_CMPL */ {BTA_DM_INQUIRY_CMPL, BTA_DM_SEARCH_IGNORE,
+                        BTA_DM_SEARCH_ACTIVE},
+    /* REMT_NAME_EVT */ {BTA_DM_REMT_NAME, BTA_DM_SEARCH_IGNORE,
+                         BTA_DM_SEARCH_ACTIVE},
+    /* SDP_RESULT_EVT */ {BTA_DM_SDP_RESULT, BTA_DM_SEARCH_IGNORE,
+                          BTA_DM_SEARCH_ACTIVE},
+    /* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_CMPL, BTA_DM_SEARCH_IGNORE,
+                           BTA_DM_SEARCH_IDLE},
+    /* DISCV_RES_EVT */ {BTA_DM_SEARCH_RESULT, BTA_DM_SEARCH_IGNORE,
+                         BTA_DM_SEARCH_ACTIVE},
+    /* API_DI_DISCOVER_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+                               BTA_DM_SEARCH_ACTIVE}
+#if (BLE_INCLUDED == TRUE)
+    /* DISC_CLOSE_TOUT_EVT */,
+    {BTA_DM_CLOSE_GATT_CONN, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE}
+#endif
+
+};
+
+const uint8_t
+    bta_dm_search_search_cancelling_st_table[][BTA_DM_SEARCH_NUM_COLS] = {
+
+        /* Event                        Action 1
+           Action 2                    Next State */
+        /* API_SEARCH */ {BTA_DM_QUEUE_SEARCH, BTA_DM_SEARCH_IGNORE,
+                          BTA_DM_SEARCH_CANCELLING},
+        /* API_SEARCH_CANCEL */ {BTA_DM_SEARCH_CLEAR_QUEUE,
+                                 BTA_DM_SEARCH_CANCEL_NOTIFY,
+                                 BTA_DM_SEARCH_CANCELLING},
+        /* API_SEARCH_DISC */ {BTA_DM_QUEUE_DISC, BTA_DM_SEARCH_IGNORE,
+                               BTA_DM_SEARCH_CANCELLING},
+        /* INQUIRY_CMPL */ {BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IGNORE,
+                            BTA_DM_SEARCH_IDLE},
+        /* REMT_NAME_EVT */ {BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL,
+                             BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IDLE},
+        /* SDP_RESULT_EVT */ {BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL,
+                              BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IDLE},
+        /* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL,
+                               BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IDLE},
+        /* DISCV_RES_EVT */ {BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL,
+                             BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IDLE},
+        /* API_DI_DISCOVER_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+                                   BTA_DM_SEARCH_CANCELLING}
+#if (BLE_INCLUDED == TRUE)
+        /* DISC_CLOSE_TOUT_EVT */,
+        {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_CANCELLING}
+#endif
+
+};
+
+const uint8_t bta_dm_search_disc_active_st_table[][BTA_DM_SEARCH_NUM_COLS] = {
+
+    /* Event                        Action 1
+       Action 2                    Next State */
+    /* API_SEARCH */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+                      BTA_DM_DISCOVER_ACTIVE},
+    /* API_SEARCH_CANCEL */ {BTA_DM_SEARCH_CANCEL_NOTIFY, BTA_DM_SEARCH_IGNORE,
+                             BTA_DM_SEARCH_CANCELLING},
+    /* API_SEARCH_DISC */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+                           BTA_DM_DISCOVER_ACTIVE},
+    /* INQUIRY_CMPL */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+                        BTA_DM_DISCOVER_ACTIVE},
+    /* REMT_NAME_EVT */ {BTA_DM_DISC_RMT_NAME, BTA_DM_SEARCH_IGNORE,
+                         BTA_DM_DISCOVER_ACTIVE},
+    /* SDP_RESULT_EVT */ {BTA_DM_SDP_RESULT, BTA_DM_SEARCH_IGNORE,
+                          BTA_DM_DISCOVER_ACTIVE},
+    /* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_CMPL, BTA_DM_SEARCH_IGNORE,
+                           BTA_DM_SEARCH_IDLE},
+    /* DISCV_RES_EVT */ {BTA_DM_DISC_RESULT, BTA_DM_SEARCH_IGNORE,
+                         BTA_DM_DISCOVER_ACTIVE},
+    /* API_DI_DISCOVER_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+                               BTA_DM_DISCOVER_ACTIVE}
+
+#if (BLE_INCLUDED == TRUE)
+    /* DISC_CLOSE_TOUT_EVT */,
+    {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE}
+#endif
+};
+
+typedef const uint8_t (*tBTA_DM_ST_TBL)[BTA_DM_SEARCH_NUM_COLS];
+
+/* state table */
+const tBTA_DM_ST_TBL bta_dm_search_st_tbl[] = {
+    bta_dm_search_idle_st_table, bta_dm_search_search_active_st_table,
+    bta_dm_search_search_cancelling_st_table,
+    bta_dm_search_disc_active_st_table};
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_sm_disable
+ *
+ * Description     unregister BTA DM
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_sm_disable() { bta_sys_deregister(BTA_ID_DM); }
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_sm_execute
+ *
+ * Description      State machine event handling function for DM
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+bool bta_dm_sm_execute(BT_HDR* p_msg) {
+  uint16_t event = p_msg->event & 0x00ff;
+
+  APPL_TRACE_EVENT("bta_dm_sm_execute event:0x%x", event);
+
+  /* execute action functions */
+  if (event < BTA_DM_NUM_ACTIONS) {
+    (*bta_dm_action[event])((tBTA_DM_MSG*)p_msg);
+  }
+
+  return true;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_sm_search_disable
+ *
+ * Description     unregister BTA SEARCH DM
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_search_sm_disable() { bta_sys_deregister(BTA_ID_DM_SEARCH); }
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_search_sm_execute
+ *
+ * Description      State machine event handling function for DM
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+bool bta_dm_search_sm_execute(BT_HDR* p_msg) {
+  tBTA_DM_ST_TBL state_table;
+  uint8_t action;
+  int i;
+
+  APPL_TRACE_EVENT("bta_dm_search_sm_execute state:%d, event:0x%x",
+                   bta_dm_search_cb.state, p_msg->event);
+
+  /* look up the state table for the current state */
+  state_table = bta_dm_search_st_tbl[bta_dm_search_cb.state];
+
+  bta_dm_search_cb.state =
+      state_table[p_msg->event & 0x00ff][BTA_DM_SEARCH_NEXT_STATE];
+
+  /* execute action functions */
+  for (i = 0; i < BTA_DM_SEARCH_ACTIONS; i++) {
+    if ((action = state_table[p_msg->event & 0x00ff][i]) !=
+        BTA_DM_SEARCH_IGNORE) {
+      (*bta_dm_search_action[action])((tBTA_DM_MSG*)p_msg);
+    } else {
+      break;
+    }
+  }
+  return true;
+}
diff --git a/bt/bta/dm/bta_dm_pm.cc b/bt/bta/dm/bta_dm_pm.cc
new file mode 100644
index 0000000..6f64bc2
--- /dev/null
+++ b/bt/bta/dm/bta_dm_pm.cc
@@ -0,0 +1,1172 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 action functions for device manager state
+ *  machine.
+ *
+ ******************************************************************************/
+
+#include <assert.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_dm_api.h"
+#include "bta_dm_int.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+
+extern fixed_queue_t* btu_bta_alarm_queue;
+
+static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
+                            uint8_t app_id, BD_ADDR peer_addr);
+static void bta_dm_pm_set_mode(BD_ADDR peer_addr, tBTA_DM_PM_ACTION pm_mode,
+                               tBTA_DM_PM_REQ pm_req);
+static void bta_dm_pm_timer_cback(void* data);
+static void bta_dm_pm_btm_cback(BD_ADDR bd_addr, tBTM_PM_STATUS status,
+                                uint16_t value, uint8_t hci_status);
+static bool bta_dm_pm_park(BD_ADDR peer_addr);
+static bool bta_dm_pm_sniff(tBTA_DM_PEER_DEVICE* p_peer_dev, uint8_t index);
+static bool bta_dm_pm_is_sco_active();
+static int bta_dm_get_sco_index();
+static void bta_dm_pm_hid_check(bool bScoActive);
+static void bta_dm_pm_set_sniff_policy(tBTA_DM_PEER_DEVICE* p_dev,
+                                       bool bDisable);
+static void bta_dm_pm_stop_timer_by_index(tBTA_PM_TIMER* p_timer,
+                                          uint8_t timer_idx);
+
+#if (BTM_SSR_INCLUDED == TRUE)
+#if (BTA_HH_INCLUDED == TRUE)
+#include "../hh/bta_hh_int.h"
+/* BTA_DM_PM_SSR1 will be dedicated for HH SSR setting entry, no other profile
+ * can use it */
+#define BTA_DM_PM_SSR_HH BTA_DM_PM_SSR1
+#endif
+static void bta_dm_pm_ssr(BD_ADDR peer_addr);
+#endif
+
+tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs;
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_init_pm
+ *
+ * Description      Initializes the BT low power manager
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_init_pm(void) {
+  memset(&bta_dm_conn_srvcs, 0x00, sizeof(bta_dm_conn_srvcs));
+
+  /* if there are no power manger entries, so not register */
+  if (p_bta_dm_pm_cfg[0].app_id != 0) {
+    bta_sys_pm_register((tBTA_SYS_CONN_CBACK*)bta_dm_pm_cback);
+
+    BTM_PmRegister((BTM_PM_REG_SET | BTM_PM_REG_NOTIF), &bta_dm_cb.pm_id,
+                   bta_dm_pm_btm_cback);
+  }
+
+  /* Need to initialize all PM timer service IDs */
+  for (int i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
+    for (int j = 0; j < BTA_DM_PM_MODE_TIMER_MAX; j++)
+      bta_dm_cb.pm_timer[i].srvc_id[j] = BTA_ID_MAX;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_disable_pm
+ *
+ * Description      Disable PM
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_disable_pm(void) {
+  BTM_PmRegister(BTM_PM_DEREG, &bta_dm_cb.pm_id, NULL);
+
+  /*
+   * Deregister the PM callback from the system handling to prevent
+   * re-enabling the PM timers after this call if the callback is invoked.
+   */
+  bta_sys_pm_register((tBTA_SYS_CONN_CBACK*)NULL);
+
+  /* Need to stop all active timers. */
+  for (int i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
+    for (int j = 0; j < BTA_DM_PM_MODE_TIMER_MAX; j++) {
+      bta_dm_pm_stop_timer_by_index(&bta_dm_cb.pm_timer[i], j);
+      bta_dm_cb.pm_timer[i].pm_action[j] = BTA_DM_PM_NO_ACTION;
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_get_av_count
+ *
+ * Description      Get the number of connected AV
+ *
+ *
+ * Returns          number of av connections
+ *
+ ******************************************************************************/
+uint8_t bta_dm_get_av_count(void) {
+  uint8_t count = 0;
+  for (int i = 0; i < bta_dm_conn_srvcs.count; i++) {
+    if (bta_dm_conn_srvcs.conn_srvc[i].id == BTA_ID_AV) ++count;
+  }
+  return count;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_pm_stop_timer
+ *
+ * Description      stop a PM timer
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_pm_stop_timer(BD_ADDR peer_addr) {
+  APPL_TRACE_DEBUG("%s: ", __func__);
+
+  for (int i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
+    if (bta_dm_cb.pm_timer[i].in_use &&
+        !bdcmp(bta_dm_cb.pm_timer[i].peer_bdaddr, peer_addr)) {
+      for (int j = 0; j < BTA_DM_PM_MODE_TIMER_MAX; j++) {
+        bta_dm_pm_stop_timer_by_index(&bta_dm_cb.pm_timer[i], j);
+        /*
+         * TODO: For now, stopping the timer does not reset
+         * pm_action[j].
+         * The reason is because some of the internal logic that
+         * (re)assigns the pm_action[] values is taking into account
+         * the older value; e.g., see the pm_action[] assignment in
+         * function bta_dm_pm_start_timer().
+         * Such subtlety in the execution logic is error prone, and
+         * should be eliminiated in the future.
+         */
+      }
+      break;
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pm_action_to_timer_idx
+ *
+ * Description      convert power mode into timer index for each connected
+ *                  device
+ *
+ *
+ * Returns          index of the power mode delay timer
+ *
+ ******************************************************************************/
+static uint8_t bta_pm_action_to_timer_idx(uint8_t pm_action) {
+  if (pm_action == BTA_DM_PM_SUSPEND)
+    return BTA_DM_PM_SUSPEND_TIMER_IDX;
+  else if (pm_action == BTA_DM_PM_PARK)
+    return BTA_DM_PM_PARK_TIMER_IDX;
+  else if ((pm_action & BTA_DM_PM_SNIFF) == BTA_DM_PM_SNIFF)
+    return BTA_DM_PM_SNIFF_TIMER_IDX;
+
+  /* Active, no preference, no action and retry */
+  return BTA_DM_PM_MODE_TIMER_MAX;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_pm_stop_timer_by_mode
+ *
+ * Description      stop a PM timer
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_pm_stop_timer_by_mode(BD_ADDR peer_addr,
+                                         uint8_t power_mode) {
+  const uint8_t timer_idx = bta_pm_action_to_timer_idx(power_mode);
+  if (timer_idx == BTA_DM_PM_MODE_TIMER_MAX) return;
+
+  for (int i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
+    if (bta_dm_cb.pm_timer[i].in_use &&
+        !bdcmp(bta_dm_cb.pm_timer[i].peer_bdaddr, peer_addr)) {
+      if (bta_dm_cb.pm_timer[i].srvc_id[timer_idx] != BTA_ID_MAX) {
+        bta_dm_pm_stop_timer_by_index(&bta_dm_cb.pm_timer[i], timer_idx);
+        /*
+         * TODO: Intentionally setting pm_action[timer_idx].
+         * This assignment should be eliminated in the future - see the
+         * pm_action[] related comment inside function
+         * bta_dm_pm_stop_timer().
+         */
+        bta_dm_cb.pm_timer[i].pm_action[timer_idx] = power_mode;
+      }
+      break;
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_pm_stop_timer_by_srvc_id
+ *
+ * Description      stop all timer started by the service ID.
+ *
+ *
+ * Returns          index of the power mode delay timer
+ *
+ ******************************************************************************/
+static void bta_dm_pm_stop_timer_by_srvc_id(BD_ADDR peer_addr,
+                                            uint8_t srvc_id) {
+  for (int i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
+    if (bta_dm_cb.pm_timer[i].in_use &&
+        !bdcmp(bta_dm_cb.pm_timer[i].peer_bdaddr, peer_addr)) {
+      for (int j = 0; j < BTA_DM_PM_MODE_TIMER_MAX; j++) {
+        if (bta_dm_cb.pm_timer[i].srvc_id[j] == srvc_id) {
+          bta_dm_pm_stop_timer_by_index(&bta_dm_cb.pm_timer[i], j);
+          bta_dm_cb.pm_timer[i].pm_action[j] = BTA_DM_PM_NO_ACTION;
+          break;
+        }
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_pm_start_timer
+ *
+ * Description      start a PM timer
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_pm_start_timer(tBTA_PM_TIMER* p_timer, uint8_t timer_idx,
+                                  period_ms_t timeout_ms, uint8_t srvc_id,
+                                  uint8_t pm_action) {
+  p_timer->in_use = true;
+
+  if (p_timer->srvc_id[timer_idx] == BTA_ID_MAX) p_timer->active++;
+
+  if (p_timer->pm_action[timer_idx] < pm_action)
+    p_timer->pm_action[timer_idx] = pm_action;
+
+  p_timer->srvc_id[timer_idx] = srvc_id;
+
+  alarm_set_on_queue(p_timer->timer[timer_idx], timeout_ms,
+                     bta_dm_pm_timer_cback, p_timer->timer[timer_idx],
+                     btu_bta_alarm_queue);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_pm_stop_timer_by_index
+ *
+ * Description      stop a PM timer
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_pm_stop_timer_by_index(tBTA_PM_TIMER* p_timer,
+                                          uint8_t timer_idx) {
+  if ((p_timer == NULL) || (timer_idx >= BTA_DM_PM_MODE_TIMER_MAX)) return;
+
+  if (p_timer->srvc_id[timer_idx] == BTA_ID_MAX)
+    return; /* The timer was not scheduled */
+
+  assert(p_timer->in_use && (p_timer->active > 0));
+
+  alarm_cancel(p_timer->timer[timer_idx]);
+  p_timer->srvc_id[timer_idx] = BTA_ID_MAX;
+  /* NOTE: pm_action[timer_idx] intentionally not reset */
+
+  p_timer->active--;
+  if (p_timer->active == 0) p_timer->in_use = false;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_pm_cback
+ *
+ * Description      Conn change callback from sys for low power management
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
+                            uint8_t app_id, BD_ADDR peer_addr) {
+  uint8_t i, j;
+  uint8_t* p = NULL;
+  tBTA_DM_PEER_DEVICE* p_dev;
+  tBTA_DM_PM_REQ pm_req = BTA_DM_PM_NEW_REQ;
+
+#if (BTM_SSR_INCLUDED == TRUE)
+  int index = BTA_DM_PM_SSR0;
+#endif
+
+  APPL_TRACE_DEBUG("bta_dm_pm_cback: st(%d), id(%d), app(%d)", status, id,
+                   app_id);
+
+  p_dev = bta_dm_find_peer_device(peer_addr);
+
+  /* find if there is an power mode entry for the service */
+  for (i = 1; i <= p_bta_dm_pm_cfg[0].app_id; i++) {
+    if ((p_bta_dm_pm_cfg[i].id == id) &&
+        ((p_bta_dm_pm_cfg[i].app_id == BTA_ALL_APP_ID) ||
+         (p_bta_dm_pm_cfg[i].app_id == app_id)))
+      break;
+  }
+
+  /* if no entries are there for the app_id and subsystem in p_bta_dm_pm_spec*/
+  if (i > p_bta_dm_pm_cfg[0].app_id) return;
+
+  bta_dm_pm_stop_timer_by_srvc_id(peer_addr, id);
+/*p_dev = bta_dm_find_peer_device(peer_addr);*/
+
+#if (BTM_SSR_INCLUDED == TRUE)
+  /* set SSR parameters on SYS CONN OPEN */
+  if ((BTA_SYS_CONN_OPEN == status) && p_dev &&
+      (p_dev->info & BTA_DM_DI_USE_SSR)) {
+    index = p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].ssr;
+  }
+#endif
+
+  /* if no action for the event */
+  if (p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx]
+          .actn_tbl[status][0]
+          .power_mode == BTA_DM_PM_NO_ACTION) {
+#if (BTM_SSR_INCLUDED == TRUE)
+    if (BTA_DM_PM_SSR0 == index) /* and do not need to set SSR, return. */
+#endif
+      return;
+  }
+
+  for (j = 0; j < bta_dm_conn_srvcs.count; j++) {
+    /* check if an entry already present */
+    if ((bta_dm_conn_srvcs.conn_srvc[j].id == id) &&
+        (bta_dm_conn_srvcs.conn_srvc[j].app_id == app_id) &&
+        !bdcmp(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, peer_addr)) {
+      bta_dm_conn_srvcs.conn_srvc[j].new_request = true;
+      break;
+    }
+  }
+
+  /* if subsystem has no more preference on the power mode remove
+ the cb */
+  if (p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx]
+          .actn_tbl[status][0]
+          .power_mode == BTA_DM_PM_NO_PREF) {
+    if (j != bta_dm_conn_srvcs.count) {
+      bta_dm_conn_srvcs.count--;
+
+      for (; j < bta_dm_conn_srvcs.count; j++) {
+        memcpy(&bta_dm_conn_srvcs.conn_srvc[j],
+               &bta_dm_conn_srvcs.conn_srvc[j + 1],
+               sizeof(bta_dm_conn_srvcs.conn_srvc[j]));
+      }
+    } else {
+      APPL_TRACE_WARNING("bta_dm_act no entry for connected service cbs");
+      return;
+    }
+  } else if (j == bta_dm_conn_srvcs.count) {
+    /* check if we have more connected service that cbs */
+    if (bta_dm_conn_srvcs.count == BTA_DM_NUM_CONN_SRVS) {
+      APPL_TRACE_WARNING("bta_dm_act no more connected service cbs");
+      return;
+    }
+
+    /* fill in a new cb */
+    bta_dm_conn_srvcs.conn_srvc[j].id = id;
+    bta_dm_conn_srvcs.conn_srvc[j].app_id = app_id;
+    bta_dm_conn_srvcs.conn_srvc[j].new_request = true;
+    bdcpy(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, peer_addr);
+
+    APPL_TRACE_WARNING("new conn_srvc id:%d, app_id:%d", id, app_id);
+
+    bta_dm_conn_srvcs.count++;
+    bta_dm_conn_srvcs.conn_srvc[j].state = status;
+  } else {
+    /* no service is added or removed. only updating status. */
+    bta_dm_conn_srvcs.conn_srvc[j].state = status;
+  }
+
+  /* stop timer */
+  bta_dm_pm_stop_timer(peer_addr);
+  if (bta_dm_conn_srvcs.count > 0) {
+    pm_req = BTA_DM_PM_RESTART;
+    APPL_TRACE_DEBUG(
+        "%s bta_dm_pm_stop_timer for current service, restart other "
+        "service timers: count = %d",
+        __func__, bta_dm_conn_srvcs.count);
+  }
+
+  if (p_dev) {
+    p_dev->pm_mode_attempted = 0;
+    p_dev->pm_mode_failed = 0;
+  }
+
+#if (BTM_SSR_INCLUDED == TRUE)
+  if (p_bta_dm_ssr_spec[index].max_lat
+#if (BTA_HH_INCLUDED == TRUE)
+      || index == BTA_DM_PM_SSR_HH
+#endif
+      ) {
+    bta_dm_pm_ssr(peer_addr);
+  } else {
+    if (((NULL != (p = BTM_ReadLocalFeatures())) &&
+         HCI_SNIFF_SUB_RATE_SUPPORTED(p)) &&
+        ((NULL != (p = BTM_ReadRemoteFeatures(peer_addr))) &&
+         HCI_SNIFF_SUB_RATE_SUPPORTED(p)) &&
+        (index == BTA_DM_PM_SSR0)) {
+      if (status == BTA_SYS_SCO_OPEN) {
+        APPL_TRACE_DEBUG("%s: SCO inactive, reset SSR to zero", __func__);
+        BTM_SetSsrParams(peer_addr, 0, 0, 0);
+      } else if (status == BTA_SYS_SCO_CLOSE) {
+        APPL_TRACE_DEBUG("%s: SCO active, back to old SSR", __func__);
+        bta_dm_pm_ssr(peer_addr);
+      }
+    }
+  }
+#endif
+
+  bta_dm_pm_set_mode(peer_addr, BTA_DM_PM_NO_ACTION, pm_req);
+
+  /* perform the HID link workaround if needed
+  ** 1. If SCO up/down event is received OR
+  ** 2. If HID connection open is received and SCO is already active.
+  **     This will handle the case where HID connects when SCO already active
+  */
+  if (BTM_IsDeviceUp() &&
+      (((status == BTA_SYS_SCO_OPEN) || (status == BTA_SYS_SCO_CLOSE)) ||
+       ((status == BTA_SYS_CONN_OPEN) && (id == BTA_ID_HH) &&
+        bta_dm_pm_is_sco_active()))) {
+    bool bScoActive;
+    if (status == BTA_SYS_CONN_OPEN)
+      bScoActive = true;
+    else
+      bScoActive = (status == BTA_SYS_SCO_OPEN);
+
+    bta_dm_pm_hid_check(bScoActive);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_pm_set_mode
+ *
+ * Description      Set the power mode for the device
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+
+static void bta_dm_pm_set_mode(BD_ADDR peer_addr, tBTA_DM_PM_ACTION pm_request,
+                               tBTA_DM_PM_REQ pm_req) {
+  tBTA_DM_PM_ACTION pm_action = BTA_DM_PM_NO_ACTION;
+  period_ms_t timeout_ms = 0;
+  uint8_t i, j;
+  tBTA_DM_PM_ACTION failed_pm = 0;
+  tBTA_DM_PEER_DEVICE* p_peer_device = NULL;
+  tBTA_DM_PM_ACTION allowed_modes = 0;
+  tBTA_DM_PM_ACTION pref_modes = 0;
+  tBTA_DM_PM_CFG* p_pm_cfg;
+  tBTA_DM_PM_SPEC* p_pm_spec;
+  tBTA_DM_PM_ACTN *p_act0, *p_act1;
+  tBTA_DM_SRVCS* p_srvcs = NULL;
+  bool timer_started = false;
+  uint8_t timer_idx, available_timer = BTA_DM_PM_MODE_TIMER_MAX;
+  period_ms_t remaining_ms = 0;
+
+  if (!bta_dm_cb.device_list.count) return;
+
+  /* see if any attempt to put device in low power mode failed */
+  p_peer_device = bta_dm_find_peer_device(peer_addr);
+  /* if no peer device found return */
+  if (p_peer_device == NULL) return;
+
+  failed_pm = p_peer_device->pm_mode_failed;
+
+  for (i = 0; i < bta_dm_conn_srvcs.count; i++) {
+    p_srvcs = &bta_dm_conn_srvcs.conn_srvc[i];
+    if (!bdcmp(p_srvcs->peer_bdaddr, peer_addr)) {
+      /* p_bta_dm_pm_cfg[0].app_id is the number of entries */
+      for (j = 1; j <= p_bta_dm_pm_cfg[0].app_id; j++) {
+        if ((p_bta_dm_pm_cfg[j].id == p_srvcs->id) &&
+            ((p_bta_dm_pm_cfg[j].app_id == BTA_ALL_APP_ID) ||
+             (p_bta_dm_pm_cfg[j].app_id == p_srvcs->app_id)))
+          break;
+      }
+
+      p_pm_cfg = &p_bta_dm_pm_cfg[j];
+      p_pm_spec = &p_bta_dm_pm_spec[p_pm_cfg->spec_idx];
+      p_act0 = &p_pm_spec->actn_tbl[p_srvcs->state][0];
+      p_act1 = &p_pm_spec->actn_tbl[p_srvcs->state][1];
+
+      APPL_TRACE_DEBUG("bta_dm_pm_set_mode: srvcsid: %d, state: %d, j: %d",
+                       p_srvcs->id, p_srvcs->state, j);
+      allowed_modes |= p_pm_spec->allow_mask;
+
+      /* PM actions are in the order of strictness */
+
+      /* first check if the first preference is ok */
+      if (!(failed_pm & p_act0->power_mode)) {
+        pref_modes |= p_act0->power_mode;
+
+        if (p_act0->power_mode >= pm_action) {
+          pm_action = p_act0->power_mode;
+
+          if (pm_req != BTA_DM_PM_NEW_REQ || p_srvcs->new_request) {
+            p_srvcs->new_request = false;
+            timeout_ms = p_act0->timeout;
+          }
+        }
+      }
+      /* if first preference has already failed, try second preference */
+      else if (!(failed_pm & p_act1->power_mode)) {
+        pref_modes |= p_act1->power_mode;
+
+        if (p_act1->power_mode > pm_action) {
+          pm_action = p_act1->power_mode;
+          timeout_ms = p_act1->timeout;
+        }
+      }
+    }
+  }
+
+  if (pm_action & (BTA_DM_PM_PARK | BTA_DM_PM_SNIFF)) {
+    /* some service don't like the mode */
+    if (!(allowed_modes & pm_action)) {
+      /* select the other mode if its allowed and preferred, otherwise 0 which
+       * is BTA_DM_PM_NO_ACTION */
+      pm_action =
+          (allowed_modes & (BTA_DM_PM_PARK | BTA_DM_PM_SNIFF) & pref_modes);
+
+      /* no timeout needed if no action is required */
+      if (pm_action == BTA_DM_PM_NO_ACTION) {
+        timeout_ms = 0;
+      }
+    }
+  }
+  /* if need to start a timer */
+  if ((pm_req != BTA_DM_PM_EXECUTE) && (timeout_ms > 0)) {
+    for (i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
+      if (bta_dm_cb.pm_timer[i].in_use &&
+          bdcmp(bta_dm_cb.pm_timer[i].peer_bdaddr, peer_addr) == 0) {
+        if ((timer_idx = bta_pm_action_to_timer_idx(pm_action)) !=
+            BTA_DM_PM_MODE_TIMER_MAX) {
+          remaining_ms =
+              alarm_get_remaining_ms(bta_dm_cb.pm_timer[i].timer[timer_idx]);
+          if (remaining_ms < timeout_ms) {
+            /* Cancel and restart the timer */
+            /*
+             * TODO: The value of pm_action[timer_idx] is
+             * conditionally updated between the two function
+             * calls below when the timer is restarted.
+             * This logic is error-prone and should be eliminated
+             * in the future.
+             */
+            bta_dm_pm_stop_timer_by_index(&bta_dm_cb.pm_timer[i], timer_idx);
+            bta_dm_pm_start_timer(&bta_dm_cb.pm_timer[i], timer_idx, timeout_ms,
+                                  p_srvcs->id, pm_action);
+          }
+          timer_started = true;
+        }
+        break;
+      } else if (!bta_dm_cb.pm_timer[i].in_use) {
+        APPL_TRACE_DEBUG("%s dm_pm_timer:%d, %d ms", __func__, i, timeout_ms);
+        if (available_timer == BTA_DM_PM_MODE_TIMER_MAX) available_timer = i;
+      }
+    }
+    /* new power mode for a new active connection */
+    if (!timer_started) {
+      if (available_timer != BTA_DM_PM_MODE_TIMER_MAX) {
+        bdcpy(bta_dm_cb.pm_timer[available_timer].peer_bdaddr, peer_addr);
+        if ((timer_idx = bta_pm_action_to_timer_idx(pm_action)) !=
+            BTA_DM_PM_MODE_TIMER_MAX) {
+          bta_dm_pm_start_timer(&bta_dm_cb.pm_timer[available_timer], timer_idx,
+                                timeout_ms, p_srvcs->id, pm_action);
+          timer_started = true;
+        }
+      }
+      /* no more timers */
+      else {
+        APPL_TRACE_WARNING("bta_dm_act dm_pm_timer no more");
+      }
+    }
+    return;
+  }
+  /* if pending power mode timer expires, and currecnt link is in a
+     lower power mode than current profile requirement, igonre it */
+  if (pm_req == BTA_DM_PM_EXECUTE && pm_request < pm_action) {
+    APPL_TRACE_ERROR("Ignore the power mode request: %d", pm_request)
+    return;
+  }
+  if (pm_action == BTA_DM_PM_PARK) {
+    p_peer_device->pm_mode_attempted = BTA_DM_PM_PARK;
+    bta_dm_pm_park(peer_addr);
+  } else if (pm_action & BTA_DM_PM_SNIFF) {
+    /* dont initiate SNIFF, if link_policy has it disabled */
+    if (p_peer_device->link_policy & HCI_ENABLE_SNIFF_MODE) {
+      p_peer_device->pm_mode_attempted = BTA_DM_PM_SNIFF;
+      bta_dm_pm_sniff(p_peer_device, (uint8_t)(pm_action & 0x0F));
+    } else {
+      APPL_TRACE_DEBUG(
+          "bta_dm_pm_set_mode: Link policy disallows SNIFF, ignore request");
+    }
+  } else if (pm_action == BTA_DM_PM_ACTIVE) {
+    bta_dm_pm_active(peer_addr);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_ag_pm_park
+ *
+ * Description      Switch to park mode.
+ *
+ *
+ * Returns          true if park attempted, false otherwise.
+ *
+ ******************************************************************************/
+static bool bta_dm_pm_park(BD_ADDR peer_addr) {
+  tBTM_PM_MODE mode = BTM_PM_STS_ACTIVE;
+
+  /* if not in park mode, switch to park */
+  BTM_ReadPowerMode(peer_addr, &mode);
+
+  if (mode != BTM_PM_MD_PARK) {
+    BTM_SetPowerMode(bta_dm_cb.pm_id, peer_addr,
+                     &p_bta_dm_pm_md[BTA_DM_PM_PARK_IDX]);
+  }
+  return true;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_pm_sniff
+ *
+ * Description      Switch to sniff mode.
+ *
+ *
+ * Returns          true if sniff attempted, false otherwise.
+ *
+ ******************************************************************************/
+static bool bta_dm_pm_sniff(tBTA_DM_PEER_DEVICE* p_peer_dev, uint8_t index) {
+  tBTM_PM_MODE mode = BTM_PM_STS_ACTIVE;
+  tBTM_PM_PWR_MD pwr_md;
+  tBTM_STATUS status;
+#if (BTM_SSR_INCLUDED == TRUE)
+  uint8_t* p_rem_feat = NULL;
+#endif
+
+  BTM_ReadPowerMode(p_peer_dev->peer_bdaddr, &mode);
+  p_rem_feat = BTM_ReadRemoteFeatures(p_peer_dev->peer_bdaddr);
+#if (BTM_SSR_INCLUDED == TRUE)
+  APPL_TRACE_DEBUG("bta_dm_pm_sniff cur:%d, idx:%d, info:x%x", mode, index,
+                   p_peer_dev->info);
+  if (mode != BTM_PM_MD_SNIFF ||
+      (HCI_SNIFF_SUB_RATE_SUPPORTED(BTM_ReadLocalFeatures()) && p_rem_feat &&
+       HCI_SNIFF_SUB_RATE_SUPPORTED(p_rem_feat) &&
+       !(p_peer_dev->info & BTA_DM_DI_USE_SSR)))
+#else
+  APPL_TRACE_DEBUG("bta_dm_pm_sniff cur:%d, idx:%d", mode, index);
+  if (mode != BTM_PM_MD_SNIFF)
+#endif
+  {
+#if (BTM_SSR_INCLUDED == TRUE)
+    /* Dont initiate Sniff if controller has alreay accepted
+     * remote sniff params. This avoid sniff loop issue with
+     * some agrresive headsets who use sniff latencies more than
+     * DUT supported range of Sniff intervals.*/
+    if ((mode == BTM_PM_MD_SNIFF) && (p_peer_dev->info & BTA_DM_DI_ACP_SNIFF)) {
+      APPL_TRACE_DEBUG("%s: already in remote initiate sniff", __func__);
+      return true;
+    }
+#endif
+    /* if the current mode is not sniff, issue the sniff command.
+     * If sniff, but SSR is not used in this link, still issue the command */
+    memcpy(&pwr_md, &p_bta_dm_pm_md[index], sizeof(tBTM_PM_PWR_MD));
+    if (p_peer_dev->info & BTA_DM_DI_INT_SNIFF) {
+      pwr_md.mode |= BTM_PM_MD_FORCE;
+    }
+    status =
+        BTM_SetPowerMode(bta_dm_cb.pm_id, p_peer_dev->peer_bdaddr, &pwr_md);
+    if (status == BTM_CMD_STORED || status == BTM_CMD_STARTED) {
+      p_peer_dev->info &= ~(BTA_DM_DI_INT_SNIFF | BTA_DM_DI_ACP_SNIFF);
+      p_peer_dev->info |= BTA_DM_DI_SET_SNIFF;
+    } else if (status == BTM_SUCCESS) {
+      APPL_TRACE_DEBUG(
+          "bta_dm_pm_sniff BTM_SetPowerMode() returns BTM_SUCCESS");
+      p_peer_dev->info &=
+          ~(BTA_DM_DI_INT_SNIFF | BTA_DM_DI_ACP_SNIFF | BTA_DM_DI_SET_SNIFF);
+    } else /* error */
+    {
+      APPL_TRACE_ERROR(
+          "bta_dm_pm_sniff BTM_SetPowerMode() returns ERROR status=%d", status);
+      p_peer_dev->info &=
+          ~(BTA_DM_DI_INT_SNIFF | BTA_DM_DI_ACP_SNIFF | BTA_DM_DI_SET_SNIFF);
+    }
+  }
+  return true;
+}
+/*******************************************************************************
+ *
+ * Function         bta_dm_pm_ssr
+ *
+ * Description      checks and sends SSR parameters
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+#if (BTM_SSR_INCLUDED == TRUE)
+static void bta_dm_pm_ssr(BD_ADDR peer_addr) {
+  tBTA_DM_SSR_SPEC *p_spec, *p_spec_cur;
+  uint8_t i, j;
+  int ssr = BTA_DM_PM_SSR0;
+
+  /* go through the connected services */
+  for (i = 0; i < bta_dm_conn_srvcs.count; i++) {
+    if (!bdcmp(bta_dm_conn_srvcs.conn_srvc[i].peer_bdaddr, peer_addr)) {
+      /* p_bta_dm_pm_cfg[0].app_id is the number of entries */
+      for (j = 1; j <= p_bta_dm_pm_cfg[0].app_id; j++) {
+        /* find the associated p_bta_dm_pm_cfg */
+        if ((p_bta_dm_pm_cfg[j].id == bta_dm_conn_srvcs.conn_srvc[i].id) &&
+            ((p_bta_dm_pm_cfg[j].app_id == BTA_ALL_APP_ID) ||
+             (p_bta_dm_pm_cfg[j].app_id ==
+              bta_dm_conn_srvcs.conn_srvc[i].app_id))) {
+          APPL_TRACE_WARNING("bta_dm_pm_ssr conn_srvc id:%d, app_id:%d",
+                             bta_dm_conn_srvcs.conn_srvc[i].id,
+                             bta_dm_conn_srvcs.conn_srvc[i].app_id);
+          break;
+        }
+      }
+
+      /* find the ssr index with the smallest max latency. */
+      p_spec_cur =
+          &p_bta_dm_ssr_spec[p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr];
+      p_spec = &p_bta_dm_ssr_spec[ssr];
+
+#if (BTA_HH_INCLUDED == TRUE)
+      /* HH has the per connection SSR preference, already read the SSR params
+       * from BTA HH */
+      if (p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr ==
+          BTA_DM_PM_SSR_HH) {
+        if (bta_hh_read_ssr_param(peer_addr, &p_spec_cur->max_lat,
+                                  &p_spec_cur->min_rmt_to) == BTA_HH_ERR)
+          continue;
+      }
+#endif
+      if (p_spec_cur->max_lat < p_spec->max_lat ||
+          (ssr == BTA_DM_PM_SSR0 &&
+           p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr !=
+               BTA_DM_PM_SSR0)) {
+        ssr = p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr;
+      }
+    }
+  }
+
+  p_spec = &p_bta_dm_ssr_spec[ssr];
+  APPL_TRACE_WARNING("%s ssr:%d, lat:%d", __func__, ssr, p_spec->max_lat);
+
+  if (p_spec->max_lat) {
+    /* Avoid SSR reset on device which has SCO connected */
+    if (bta_dm_pm_is_sco_active()) {
+      int idx = bta_dm_get_sco_index();
+      if (idx != -1) {
+        if (bdcmp(bta_dm_conn_srvcs.conn_srvc[idx].peer_bdaddr, peer_addr) ==
+            0) {
+          APPL_TRACE_WARNING("%s SCO is active on device, ignore SSR",
+                             __func__);
+          return;
+        }
+      }
+    }
+
+    /* set the SSR parameters. */
+    BTM_SetSsrParams(peer_addr, p_spec->max_lat, p_spec->min_rmt_to,
+                     p_spec->min_loc_to);
+  }
+}
+#endif
+/*******************************************************************************
+ *
+ * Function         bta_dm_pm_active
+ *
+ * Description      Brings connection to active mode
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_pm_active(BD_ADDR peer_addr) {
+  tBTM_PM_PWR_MD pm;
+
+  memset((void*)&pm, 0, sizeof(pm));
+
+  /* switch to active mode */
+  pm.mode = BTM_PM_MD_ACTIVE;
+  BTM_SetPowerMode(bta_dm_cb.pm_id, peer_addr, &pm);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_pm_btm_cback
+ *
+ * Description      BTM power manager callback.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_pm_btm_cback(BD_ADDR bd_addr, tBTM_PM_STATUS status,
+                                uint16_t value, uint8_t hci_status) {
+  tBTA_DM_PM_BTM_STATUS* p_buf =
+      (tBTA_DM_PM_BTM_STATUS*)osi_malloc(sizeof(tBTA_DM_PM_BTM_STATUS));
+
+  p_buf->hdr.event = BTA_DM_PM_BTM_STATUS_EVT;
+  p_buf->status = status;
+  p_buf->value = value;
+  p_buf->hci_status = hci_status;
+  bdcpy(p_buf->bd_addr, bd_addr);
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_pm_timer_cback
+ *
+ * Description      Power management timer callback.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_dm_pm_timer_cback(void* data) {
+  uint8_t i, j;
+  alarm_t* alarm = (alarm_t*)data;
+
+  for (i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
+    APPL_TRACE_DEBUG("dm_pm_timer[%d] in use? %d", i,
+                     bta_dm_cb.pm_timer[i].in_use);
+    if (bta_dm_cb.pm_timer[i].in_use) {
+      for (j = 0; j < BTA_DM_PM_MODE_TIMER_MAX; j++) {
+        if (bta_dm_cb.pm_timer[i].timer[j] == alarm) {
+          bta_dm_cb.pm_timer[i].active--;
+          bta_dm_cb.pm_timer[i].srvc_id[j] = BTA_ID_MAX;
+          APPL_TRACE_DEBUG("dm_pm_timer[%d] expires, timer_idx=%d", i, j);
+          break;
+        }
+      }
+      if (bta_dm_cb.pm_timer[i].active == 0)
+        bta_dm_cb.pm_timer[i].in_use = false;
+      if (j < BTA_DM_PM_MODE_TIMER_MAX) break;
+    }
+  }
+
+  /* no more timers */
+  if (i == BTA_DM_NUM_PM_TIMER) return;
+
+  tBTA_DM_PM_TIMER* p_buf =
+      (tBTA_DM_PM_TIMER*)osi_malloc(sizeof(tBTA_DM_PM_TIMER));
+  p_buf->hdr.event = BTA_DM_PM_TIMER_EVT;
+  p_buf->pm_request = bta_dm_cb.pm_timer[i].pm_action[j];
+  bdcpy(p_buf->bd_addr, bta_dm_cb.pm_timer[i].peer_bdaddr);
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_pm_btm_status
+ *
+ * Description      Process pm status event from btm
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_pm_btm_status(tBTA_DM_MSG* p_data) {
+  APPL_TRACE_DEBUG("%s status: %d", __func__, p_data->pm_status.status);
+
+  tBTA_DM_PEER_DEVICE* p_dev =
+      bta_dm_find_peer_device(p_data->pm_status.bd_addr);
+  if (NULL == p_dev) return;
+
+  tBTA_DM_DEV_INFO info = p_dev->info;
+  /* check new mode */
+  switch (p_data->pm_status.status) {
+    case BTM_PM_STS_ACTIVE:
+      /* if our sniff or park attempt failed
+      we should not try it again*/
+      if (p_data->pm_status.hci_status != 0) {
+        APPL_TRACE_ERROR("%s hci_status=%d", __func__,
+                         p_data->pm_status.hci_status);
+        p_dev->info &=
+            ~(BTA_DM_DI_INT_SNIFF | BTA_DM_DI_ACP_SNIFF | BTA_DM_DI_SET_SNIFF);
+
+        if (p_dev->pm_mode_attempted & (BTA_DM_PM_PARK | BTA_DM_PM_SNIFF)) {
+          p_dev->pm_mode_failed |=
+              ((BTA_DM_PM_PARK | BTA_DM_PM_SNIFF) & p_dev->pm_mode_attempted);
+          bta_dm_pm_stop_timer_by_mode(p_data->pm_status.bd_addr,
+                                       p_dev->pm_mode_attempted);
+          bta_dm_pm_set_mode(p_data->pm_status.bd_addr, BTA_DM_PM_NO_ACTION,
+                             BTA_DM_PM_RESTART);
+        }
+      } else {
+#if (BTM_SSR_INCLUDED == TRUE)
+        if (p_dev->prev_low) {
+          /* need to send the SSR paramaters to controller again */
+          bta_dm_pm_ssr(p_dev->peer_bdaddr);
+        }
+        p_dev->prev_low = BTM_PM_STS_ACTIVE;
+#endif
+        /* link to active mode, need to restart the timer for next low power
+         * mode if needed */
+        bta_dm_pm_stop_timer(p_data->pm_status.bd_addr);
+        bta_dm_pm_set_mode(p_data->pm_status.bd_addr, BTA_DM_PM_NO_ACTION,
+                           BTA_DM_PM_RESTART);
+      }
+      break;
+
+#if (BTM_SSR_INCLUDED == TRUE)
+    case BTM_PM_STS_PARK:
+    case BTM_PM_STS_HOLD:
+      /* save the previous low power mode - for SSR.
+       * SSR parameters are sent to controller on "conn open".
+       * the numbers stay good until park/hold/detach */
+      if (p_dev->info & BTA_DM_DI_USE_SSR)
+        p_dev->prev_low = p_data->pm_status.status;
+      break;
+
+    case BTM_PM_STS_SSR:
+      if (p_data->pm_status.value)
+        p_dev->info |= BTA_DM_DI_USE_SSR;
+      else
+        p_dev->info &= ~BTA_DM_DI_USE_SSR;
+      break;
+#endif
+    case BTM_PM_STS_SNIFF:
+      if (p_data->pm_status.hci_status == 0) {
+        /* Stop PM timer now if already active for
+         * particular device since link is already
+         * put in sniff mode by remote device, and
+         * PM timer sole purpose is to put the link
+         * in sniff mode from host side.
+         */
+        bta_dm_pm_stop_timer(p_data->pm_status.bd_addr);
+      } else {
+        p_dev->info &=
+            ~(BTA_DM_DI_SET_SNIFF | BTA_DM_DI_INT_SNIFF | BTA_DM_DI_ACP_SNIFF);
+        if (info & BTA_DM_DI_SET_SNIFF)
+          p_dev->info |= BTA_DM_DI_INT_SNIFF;
+        else
+          p_dev->info |= BTA_DM_DI_ACP_SNIFF;
+      }
+      break;
+
+    case BTM_PM_STS_ERROR:
+      p_dev->info &= ~BTA_DM_DI_SET_SNIFF;
+      break;
+
+    default:
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_pm_timer
+ *
+ * Description      Process pm timer event from btm
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_pm_timer(tBTA_DM_MSG* p_data) {
+  APPL_TRACE_EVENT("%s", __func__);
+  bta_dm_pm_set_mode(p_data->pm_timer.bd_addr, p_data->pm_timer.pm_request,
+                     BTA_DM_PM_EXECUTE);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_find_peer_device
+ *
+ * Description      Given an address, find the associated control block.
+ *
+ * Returns          tBTA_DM_PEER_DEVICE
+ *
+ ******************************************************************************/
+tBTA_DM_PEER_DEVICE* bta_dm_find_peer_device(const BD_ADDR peer_addr) {
+  tBTA_DM_PEER_DEVICE* p_dev = NULL;
+
+  for (int i = 0; i < bta_dm_cb.device_list.count; i++) {
+    if (!bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr, peer_addr)) {
+      p_dev = &bta_dm_cb.device_list.peer_device[i];
+      break;
+    }
+  }
+  return p_dev;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_is_sco_active
+ *
+ * Description      Loop through connected services for HFP+State=SCO
+ *
+ * Returns          bool. true if SCO active, else false
+ *
+ ******************************************************************************/
+static bool bta_dm_pm_is_sco_active() {
+  int j;
+  bool bScoActive = false;
+
+  for (j = 0; j < bta_dm_conn_srvcs.count; j++) {
+    /* check if an entry already present */
+    if ((bta_dm_conn_srvcs.conn_srvc[j].id == BTA_ID_AG) &&
+        (bta_dm_conn_srvcs.conn_srvc[j].state == BTA_SYS_SCO_OPEN)) {
+      bScoActive = true;
+      break;
+    }
+  }
+
+  APPL_TRACE_DEBUG("bta_dm_is_sco_active: SCO active: %d", bScoActive);
+  return bScoActive;
+}
+
+/*******************************************************************************
+ *
+ * Function        bta_dm_get_sco_index
+ *
+ * Description     Loop through connected services for HFP+State=SCO
+ *
+ * Returns         index at which SCO is connected, in absence of SCO return -1
+ *
+ ******************************************************************************/
+static int bta_dm_get_sco_index() {
+  for (int j = 0; j < bta_dm_conn_srvcs.count; j++) {
+    /* check for SCO connected index */
+    if ((bta_dm_conn_srvcs.conn_srvc[j].id == BTA_ID_AG) &&
+        (bta_dm_conn_srvcs.conn_srvc[j].state == BTA_SYS_SCO_OPEN)) {
+      return j;
+    }
+  }
+  return -1;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_pm_hid_check
+ *
+ * Description      Disables/Enables sniff in link policy based on SCO Up/Down
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+static void bta_dm_pm_hid_check(bool bScoActive) {
+  int j;
+
+  /* if HID is active, disable the link policy */
+  for (j = 0; j < bta_dm_conn_srvcs.count; j++) {
+    /* check if an entry already present */
+    if (bta_dm_conn_srvcs.conn_srvc[j].id == BTA_ID_HH) {
+      APPL_TRACE_DEBUG(
+          "SCO status change(Active: %d), modify HID link policy. state: %d",
+          bScoActive, bta_dm_conn_srvcs.conn_srvc[j].state);
+      bta_dm_pm_set_sniff_policy(
+          bta_dm_find_peer_device(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr),
+          bScoActive);
+
+      /* if we had disabled link policy, seems like the hid device stop retrying
+       * SNIFF after a few tries. force sniff if needed */
+      if (!bScoActive)
+        bta_dm_pm_set_mode(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr,
+                           BTA_DM_PM_NO_ACTION, BTA_DM_PM_RESTART);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_pm_set_sniff_policy
+ *
+ * Description      Disables/Enables sniff in link policy for the give device
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+static void bta_dm_pm_set_sniff_policy(tBTA_DM_PEER_DEVICE* p_dev,
+                                       bool bDisable) {
+  uint16_t policy_setting;
+
+  if (!p_dev) return;
+
+  if (bDisable) {
+    policy_setting =
+        bta_dm_cb.cur_policy & (HCI_ENABLE_MASTER_SLAVE_SWITCH |
+                                HCI_ENABLE_HOLD_MODE | HCI_ENABLE_PARK_MODE);
+
+  } else {
+    /*  allow sniff after sco is closed */
+    policy_setting = bta_dm_cb.cur_policy;
+  }
+
+  /* if disabling SNIFF, make sure link is Active */
+  if (bDisable) bta_dm_pm_active(p_dev->peer_bdaddr);
+
+  /* update device record and set link policy */
+  p_dev->link_policy = policy_setting;
+  BTM_SetLinkPolicy(p_dev->peer_bdaddr, &policy_setting);
+}
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_dm_pm_obtain_controller_state
+ *
+ * Description      This function obtains the consolidated controller power
+ *                  state
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+tBTA_DM_CONTRL_STATE bta_dm_pm_obtain_controller_state(void) {
+  /*   Did not use counts as it is not sure, how accurate the count values are
+   *in
+   **  bta_dm_cb.device_list.count > 0 || bta_dm_cb.device_list.le_count > 0 */
+
+  tBTA_DM_CONTRL_STATE cur_state = BTA_DM_CONTRL_UNKNOWN;
+  cur_state = BTM_PM_ReadControllerState();
+
+  APPL_TRACE_DEBUG("bta_dm_pm_obtain_controller_state: %d", cur_state);
+  return cur_state;
+}
+#endif
diff --git a/bt/bta/dm/bta_dm_sco.cc b/bt/bta/dm/bta_dm_sco.cc
new file mode 100644
index 0000000..094906f
--- /dev/null
+++ b/bt/bta/dm/bta_dm_sco.cc
@@ -0,0 +1,667 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 down sampling utility to convert PCM samples in
+ *  16k/32k/48k/44.1k/22050/11025 sampling rate into 8K/16bits samples
+ *  required for SCO channel format. One API function isprovided and only
+ *  possible to be used when transmitting SCO data is sent via HCI
+ *  interface.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bta_api.h"
+#include "bta_sys.h"
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+
+#ifndef BTA_DM_SCO_DEBUG
+#define BTA_DM_SCO_DEBUG false
+#endif
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+#define BTA_DM_PCM_OVERLAP_SIZE 48
+
+#define BTA_DM_PCM_SMPL_RATE_44100 44100
+#define BTA_DM_PCM_SMPL_RATE_22050 22050
+#define BTA_DM_PCM_SMPL_RATE_11025 11025
+
+/*****************************************************************************
+ *  Data types for PCM Resampling utility
+ ****************************************************************************/
+
+typedef int32_t (*PCONVERT_TO_BT_FILTERED)(uint8_t* pSrc, void* pDst,
+                                           uint32_t dwSrcSamples,
+                                           uint32_t dwSrcSps,
+                                           int32_t* pLastCurPos,
+                                           uint8_t* pOverlapArea);
+typedef int32_t (*PCONVERT_TO_BT_NOFILTER)(void* pSrc, void* pDst,
+                                           uint32_t dwSrcSamples,
+                                           uint32_t dwSrcSps);
+typedef struct {
+  uint8_t overlap_area[BTA_DM_PCM_OVERLAP_SIZE * 4];
+  uint32_t cur_pos;                 /* current position */
+  uint32_t src_sps;                 /* samples per second (source audio data) */
+  PCONVERT_TO_BT_FILTERED filter;   /* the action function to do the
+                             conversion 44100, 22050, 11025*/
+  PCONVERT_TO_BT_NOFILTER nofilter; /* the action function to do
+                               the conversion 48000, 32000, 16000*/
+  uint32_t bits;                    /* number of bits per pcm sample */
+  uint32_t n_channels; /* number of channels (i.e. mono(1), stereo(2)...) */
+  uint32_t sample_size;
+  uint32_t can_be_filtered;
+  uint32_t divisor;
+} tBTA_DM_PCM_RESAMPLE_CB;
+
+tBTA_DM_PCM_RESAMPLE_CB bta_dm_pcm_cb;
+
+/*****************************************************************************
+ *  Macro Definition
+ ****************************************************************************/
+
+#define CHECK_SATURATION16(x) \
+  do {                        \
+    if ((x) > 32767)          \
+      (x) = 32767;            \
+    else if ((x) < -32768)    \
+      (x) = -32768;           \
+  } while (0)
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+#define CONVERT_44100_TO_BLUETOOTH(pStart, pEnd)          \
+  do {                                                    \
+    int32_t out1, out2, out3, out4, out5;                 \
+    SRC_TYPE* pS = (SRC_TYPE*)(pStart);                   \
+    SRC_TYPE* pSEnd = (SRC_TYPE*)(pEnd);                  \
+                                                          \
+    while (pS < pSEnd) {                                  \
+      CurrentPos -= 8000;                                 \
+                                                          \
+      if (CurrentPos >= 0) {                              \
+        pS += SRC_CHANNELS;                               \
+        continue;                                         \
+      }                                                   \
+      CurrentPos += dwSrcSps;                             \
+                                                          \
+      out1 = (SRC_SAMPLE(0) * 1587) +                     \
+             ((SRC_SAMPLE(1) + SRC_SAMPLE(-1)) * 1522) +  \
+             ((SRC_SAMPLE(2) + SRC_SAMPLE(-2)) * 1337) +  \
+             ((SRC_SAMPLE(3) + SRC_SAMPLE(-3)) * 1058);   \
+                                                          \
+      out1 = out1 / 30000;                                \
+                                                          \
+      out2 = ((SRC_SAMPLE(4) + SRC_SAMPLE(-4)) * 725) +   \
+             ((SRC_SAMPLE(5) + SRC_SAMPLE(-5)) * 384) +   \
+             ((SRC_SAMPLE(6) + SRC_SAMPLE(-6)) * 79);     \
+                                                          \
+      out2 = out2 / 30000;                                \
+                                                          \
+      out3 = ((SRC_SAMPLE(7) + SRC_SAMPLE(-7)) * 156) +   \
+             ((SRC_SAMPLE(8) + SRC_SAMPLE(-8)) * 298) +   \
+             ((SRC_SAMPLE(9) + SRC_SAMPLE(-9)) * 345);    \
+                                                          \
+      out3 = out3 / 30000;                                \
+                                                          \
+      out4 = ((SRC_SAMPLE(10) + SRC_SAMPLE(-10)) * 306) + \
+             ((SRC_SAMPLE(11) + SRC_SAMPLE(-11)) * 207) + \
+             ((SRC_SAMPLE(12) + SRC_SAMPLE(-12)) * 78);   \
+                                                          \
+      out4 = out4 / 30000;                                \
+                                                          \
+      out5 = out1 + out2 - out3 - out4;                   \
+                                                          \
+      CHECK_SATURATION16(out5);                           \
+      *psBtOut++ = (int16_t)out5;                         \
+                                                          \
+      pS += SRC_CHANNELS;                                 \
+    }                                                     \
+  } while (0)
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+#define CONVERT_22050_TO_BLUETOOTH(pStart, pEnd)         \
+  do {                                                   \
+    int32_t out1, out2, out3, out4, out5;                \
+    SRC_TYPE* pS = (SRC_TYPE*)(pStart);                  \
+    SRC_TYPE* pSEnd = (SRC_TYPE*)(pEnd);                 \
+                                                         \
+    while (pS < pSEnd) {                                 \
+      CurrentPos -= 8000;                                \
+                                                         \
+      if (CurrentPos >= 0) {                             \
+        pS += SRC_CHANNELS;                              \
+        continue;                                        \
+      }                                                  \
+      CurrentPos += dwSrcSps;                            \
+                                                         \
+      out1 = (SRC_SAMPLE(0) * 2993) +                    \
+             ((SRC_SAMPLE(1) + SRC_SAMPLE(-1)) * 2568) + \
+             ((SRC_SAMPLE(2) + SRC_SAMPLE(-2)) * 1509) + \
+             ((SRC_SAMPLE(3) + SRC_SAMPLE(-3)) * 331);   \
+                                                         \
+      out1 = out1 / 30000;                               \
+                                                         \
+      out2 = ((SRC_SAMPLE(4) + SRC_SAMPLE(-4)) * 454) +  \
+             ((SRC_SAMPLE(5) + SRC_SAMPLE(-5)) * 620) +  \
+             ((SRC_SAMPLE(6) + SRC_SAMPLE(-6)) * 305);   \
+                                                         \
+      out2 = out2 / 30000;                               \
+                                                         \
+      out3 = ((SRC_SAMPLE(7) + SRC_SAMPLE(-7)) * 127) +  \
+             ((SRC_SAMPLE(8) + SRC_SAMPLE(-8)) * 350) +  \
+             ((SRC_SAMPLE(9) + SRC_SAMPLE(-9)) * 265) +  \
+             ((SRC_SAMPLE(10) + SRC_SAMPLE(-10)) * 6);   \
+                                                         \
+      out3 = out3 / 30000;                               \
+                                                         \
+      out4 = ((SRC_SAMPLE(11) + SRC_SAMPLE(-11)) * 201); \
+                                                         \
+      out4 = out4 / 30000;                               \
+                                                         \
+      out5 = out1 - out2 + out3 - out4;                  \
+                                                         \
+      CHECK_SATURATION16(out5);                          \
+      *psBtOut++ = (int16_t)out5;                        \
+                                                         \
+      pS += SRC_CHANNELS;                                \
+    }                                                    \
+  } while (0)
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+#define CONVERT_11025_TO_BLUETOOTH(pStart, pEnd)         \
+  do {                                                   \
+    int32_t out1;                                        \
+    SRC_TYPE* pS = (SRC_TYPE*)(pStart);                  \
+    SRC_TYPE* pSEnd = (SRC_TYPE*)(pEnd);                 \
+                                                         \
+    while (pS < pSEnd) {                                 \
+      CurrentPos -= 8000;                                \
+                                                         \
+      if (CurrentPos >= 0) {                             \
+        pS += SRC_CHANNELS;                              \
+        continue;                                        \
+      }                                                  \
+      CurrentPos += dwSrcSps;                            \
+                                                         \
+      out1 = (SRC_SAMPLE(0) * 6349) +                    \
+             ((SRC_SAMPLE(1) + SRC_SAMPLE(-1)) * 2874) - \
+             ((SRC_SAMPLE(2) + SRC_SAMPLE(-2)) * 1148) - \
+             ((SRC_SAMPLE(3) + SRC_SAMPLE(-3)) * 287) +  \
+             ((SRC_SAMPLE(4) + SRC_SAMPLE(-4)) * 675) -  \
+             ((SRC_SAMPLE(5) + SRC_SAMPLE(-5)) * 258) -  \
+             ((SRC_SAMPLE(6) + SRC_SAMPLE(-6)) * 206) +  \
+             ((SRC_SAMPLE(7) + SRC_SAMPLE(-7)) * 266);   \
+                                                         \
+      out1 = out1 / 30000;                               \
+                                                         \
+      CHECK_SATURATION16(out1);                          \
+      *psBtOut++ = (int16_t)out1;                        \
+                                                         \
+      pS += SRC_CHANNELS;                                \
+    }                                                    \
+  } while (0)
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+#undef SRC_CHANNELS
+#undef SRC_SAMPLE
+#undef SRC_TYPE
+
+#define SRC_TYPE uint8_t
+#define SRC_CHANNELS 1
+#define SRC_SAMPLE(x) ((pS[x] - 0x80) << 8)
+
+/*****************************************************************************
+ *  Local Function
+ ****************************************************************************/
+int32_t Convert_8M_ToBT_Filtered(uint8_t* pSrc, void* pDst,
+                                 uint32_t dwSrcSamples, uint32_t dwSrcSps,
+                                 int32_t* pLastCurPos, uint8_t* pOverlapArea) {
+  int32_t CurrentPos = *pLastCurPos;
+  SRC_TYPE *pIn, *pInEnd;
+  SRC_TYPE *pOv, *pOvEnd;
+  int16_t* psBtOut = (int16_t*)pDst;
+#if (BTA_DM_SCO_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("Convert_8M_ToBT_Filtered,  CurrentPos %d\n", CurrentPos);
+#endif
+  memcpy(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc,
+         BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+  pOv = (SRC_TYPE*)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE);
+  pOvEnd = (SRC_TYPE*)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3));
+
+  pIn = (SRC_TYPE*)(pSrc + BTA_DM_PCM_OVERLAP_SIZE);
+  pInEnd = (SRC_TYPE*)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
+                       BTA_DM_PCM_OVERLAP_SIZE);
+
+  if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100) {
+    CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd);
+    CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd);
+  } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050) {
+    CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd);
+    CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd);
+  } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025) {
+    CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd);
+    CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd);
+  }
+
+  memcpy(pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
+                           (BTA_DM_PCM_OVERLAP_SIZE * 2),
+         BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+  *pLastCurPos = CurrentPos;
+
+  return (psBtOut - (int16_t*)pDst);
+}
+
+int32_t Convert_8M_ToBT_NoFilter(void* pSrc, void* pDst, uint32_t dwSrcSamples,
+                                 uint32_t dwSrcSps) {
+  int32_t CurrentPos;
+  uint8_t* pbSrc = (uint8_t*)pSrc;
+  int16_t* psDst = (int16_t*)pDst;
+  int16_t sWorker;
+
+  //      start at dwSpsSrc / 2, decrement by 8000
+  //
+  CurrentPos = (dwSrcSps >> 1);
+
+  while (dwSrcSamples--) {
+    CurrentPos -= 8000;
+
+    if (CurrentPos >= 0)
+      pbSrc++;
+    else {
+      sWorker = *pbSrc++;
+      sWorker -= 0x80;
+      sWorker <<= 8;
+
+      *psDst++ = sWorker;
+
+      CurrentPos += dwSrcSps;
+    }
+  }
+
+  return (psDst - (int16_t*)pDst);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+#undef SRC_CHANNELS
+#undef SRC_SAMPLE
+#undef SRC_TYPE
+
+#define SRC_TYPE int16_t
+#define SRC_CHANNELS 1
+#define SRC_SAMPLE(x) pS[x]
+
+int32_t Convert_16M_ToBT_Filtered(uint8_t* pSrc, void* pDst,
+                                  uint32_t dwSrcSamples, uint32_t dwSrcSps,
+                                  int32_t* pLastCurPos, uint8_t* pOverlapArea) {
+  int32_t CurrentPos = *pLastCurPos;
+  SRC_TYPE *pIn, *pInEnd;
+  SRC_TYPE *pOv, *pOvEnd;
+  int16_t* psBtOut = (int16_t*)pDst;
+
+  memcpy(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc,
+         BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+  pOv = (SRC_TYPE*)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE);
+  pOvEnd = (SRC_TYPE*)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3));
+
+  pIn = (SRC_TYPE*)(pSrc + BTA_DM_PCM_OVERLAP_SIZE);
+  pInEnd = (SRC_TYPE*)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
+                       BTA_DM_PCM_OVERLAP_SIZE);
+
+  if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100) {
+    CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd);
+    CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd);
+  } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050) {
+    CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd);
+    CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd);
+  } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025) {
+    CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd);
+    CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd);
+  }
+
+  memcpy(pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
+                           (BTA_DM_PCM_OVERLAP_SIZE * 2),
+         BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+  *pLastCurPos = CurrentPos;
+
+  return (psBtOut - (int16_t*)pDst);
+}
+
+int32_t Convert_16M_ToBT_NoFilter(void* pSrc, void* pDst, uint32_t dwSrcSamples,
+                                  uint32_t dwSrcSps) {
+  int32_t CurrentPos;
+  int16_t* psSrc = (int16_t*)pSrc;
+  int16_t* psDst = (int16_t*)pDst;
+
+  //      start at dwSpsSrc / 2, decrement by 8000
+  //
+  CurrentPos = (dwSrcSps >> 1);
+
+  while (dwSrcSamples--) {
+    CurrentPos -= 8000;
+
+    if (CurrentPos >= 0)
+      psSrc++;
+    else {
+      *psDst++ = *psSrc++;
+
+      CurrentPos += dwSrcSps;
+    }
+  }
+
+  return (psDst - (int16_t*)pDst);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+#undef SRC_CHANNELS
+#undef SRC_SAMPLE
+#undef SRC_TYPE
+
+#define SRC_TYPE uint8_t
+#define SRC_CHANNELS 2
+#define SRC_SAMPLE(x) \
+  ((((pS[x * 2] - 0x80) << 8) + ((pS[(x * 2) + 1] - 0x80) << 8)) >> 1)
+
+int32_t Convert_8S_ToBT_Filtered(uint8_t* pSrc, void* pDst,
+                                 uint32_t dwSrcSamples, uint32_t dwSrcSps,
+                                 int32_t* pLastCurPos, uint8_t* pOverlapArea) {
+  int32_t CurrentPos = *pLastCurPos;
+  SRC_TYPE *pIn, *pInEnd;
+  SRC_TYPE *pOv, *pOvEnd;
+  int16_t* psBtOut = (int16_t*)pDst;
+
+#if (BTA_DM_SCO_DEBUG == TRUE)
+  APPL_TRACE_DEBUG(
+      "Convert_8S_ToBT_Filtered CurrentPos %d, SRC_TYPE %d, SRC_CHANNELS %d, \
+        dwSrcSamples %d,  dwSrcSps %d",
+      CurrentPos, sizeof(SRC_TYPE), SRC_CHANNELS, dwSrcSamples, dwSrcSps);
+#endif
+  memcpy(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc,
+         BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+  pOv = (SRC_TYPE*)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE);
+  pOvEnd = (SRC_TYPE*)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3));
+
+  pIn = (SRC_TYPE*)(pSrc + BTA_DM_PCM_OVERLAP_SIZE);
+  pInEnd = (SRC_TYPE*)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
+                       BTA_DM_PCM_OVERLAP_SIZE);
+
+  if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100) {
+    CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd);
+    CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd);
+  } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050) {
+    CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd);
+    CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd);
+  } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025) {
+    CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd);
+    CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd);
+  }
+
+  memcpy(pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
+                           (BTA_DM_PCM_OVERLAP_SIZE * 2),
+         BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+  *pLastCurPos = CurrentPos;
+
+  return (psBtOut - (int16_t*)pDst);
+}
+
+int32_t Convert_8S_ToBT_NoFilter(void* pSrc, void* pDst, uint32_t dwSrcSamples,
+                                 uint32_t dwSrcSps) {
+  int32_t CurrentPos;
+  uint8_t* pbSrc = (uint8_t*)pSrc;
+  int16_t* psDst = (int16_t*)pDst;
+  int16_t sWorker, sWorker2;
+
+  //      start at dwSpsSrc / 2, decrement by 8000
+  //
+  CurrentPos = (dwSrcSps >> 1);
+
+  while (dwSrcSamples--) {
+    CurrentPos -= 8000;
+
+    if (CurrentPos >= 0)
+      pbSrc += 2;
+    else {
+      sWorker = *(unsigned char*)pbSrc;
+      sWorker -= 0x80;
+      sWorker <<= 8;
+      pbSrc++;
+
+      sWorker2 = *(unsigned char*)pbSrc;
+      sWorker2 -= 0x80;
+      sWorker2 <<= 8;
+      pbSrc++;
+
+      sWorker += sWorker2;
+      sWorker >>= 1;
+
+      *psDst++ = sWorker;
+
+      CurrentPos += dwSrcSps;
+    }
+  }
+
+  return (psDst - (int16_t*)pDst);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+#undef SRC_CHANNELS
+#undef SRC_SAMPLE
+#undef SRC_TYPE
+
+#define SRC_TYPE int16_t
+#define SRC_CHANNELS 2
+#define SRC_SAMPLE(x) ((pS[x * 2] + pS[(x * 2) + 1]) >> 1)
+
+int32_t Convert_16S_ToBT_Filtered(uint8_t* pSrc, void* pDst,
+                                  uint32_t dwSrcSamples, uint32_t dwSrcSps,
+                                  int32_t* pLastCurPos, uint8_t* pOverlapArea) {
+  int32_t CurrentPos = *pLastCurPos;
+  SRC_TYPE *pIn, *pInEnd;
+  SRC_TYPE *pOv, *pOvEnd;
+  int16_t* psBtOut = (int16_t*)pDst;
+
+  memcpy(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc,
+         BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+  pOv = (SRC_TYPE*)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE);
+  pOvEnd = (SRC_TYPE*)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3));
+
+  pIn = (SRC_TYPE*)(pSrc + BTA_DM_PCM_OVERLAP_SIZE);
+  pInEnd = (SRC_TYPE*)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
+                       BTA_DM_PCM_OVERLAP_SIZE);
+
+  if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100) {
+    CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd);
+    CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd);
+  } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050) {
+    CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd);
+    CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd);
+  } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025) {
+    CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd);
+    CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd);
+  }
+
+  memcpy(pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
+                           (BTA_DM_PCM_OVERLAP_SIZE * 2),
+         BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+  *pLastCurPos = CurrentPos;
+
+  return (psBtOut - (int16_t*)pDst);
+}
+
+int32_t Convert_16S_ToBT_NoFilter(void* pSrc, void* pDst, uint32_t dwSrcSamples,
+                                  uint32_t dwSrcSps) {
+  int32_t CurrentPos;
+  int16_t* psSrc = (int16_t*)pSrc;
+  int16_t* psDst = (int16_t*)pDst;
+  int16_t sWorker;
+
+  //      start at dwSpsSrc / 2, decrement by 8000
+  //
+  CurrentPos = (dwSrcSps >> 1);
+
+  while (dwSrcSamples--) {
+    CurrentPos -= 8000;
+
+    if (CurrentPos >= 0)
+      psSrc += 2;
+    else {
+      /* CR 82894, to avoid overflow, divide before add */
+      sWorker = ((*psSrc) >> 1);
+      psSrc++;
+      sWorker += ((*psSrc) >> 1);
+      psSrc++;
+
+      *psDst++ = sWorker;
+
+      CurrentPos += dwSrcSps;
+    }
+  }
+
+  return (psDst - (int16_t*)pDst);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmPcmInitSamples
+ *
+ * Description      initialize the down sample converter.
+ *
+ *                  src_sps: original samples per second (source audio data)
+ *                            (ex. 44100, 48000)
+ *                  bits: number of bits per pcm sample (16)
+ *                  n_channels: number of channels (i.e. mono(1), stereo(2)...)
+ *
+ * Returns          none
+ *
+ ******************************************************************************/
+void BTA_DmPcmInitSamples(uint32_t src_sps, uint32_t bits,
+                          uint32_t n_channels) {
+  tBTA_DM_PCM_RESAMPLE_CB* p_cb = &bta_dm_pcm_cb;
+
+  p_cb->cur_pos = src_sps / 2;
+  p_cb->src_sps = src_sps;
+  p_cb->bits = bits;
+  p_cb->n_channels = n_channels;
+  p_cb->sample_size = 2;
+  p_cb->divisor = 2;
+
+  memset(p_cb->overlap_area, 0, sizeof(p_cb->overlap_area));
+
+  if ((src_sps == BTA_DM_PCM_SMPL_RATE_44100) ||
+      (src_sps == BTA_DM_PCM_SMPL_RATE_22050) ||
+      (src_sps == BTA_DM_PCM_SMPL_RATE_11025))
+    p_cb->can_be_filtered = 1;
+  else
+    p_cb->can_be_filtered = 0;
+
+#if (BTA_DM_SCO_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_dm_pcm_init_samples: n_channels = %d bits = %d",
+                   n_channels, bits);
+#endif
+  if (n_channels == 1) {
+    /* mono */
+    if (bits == 8) {
+      p_cb->filter = (PCONVERT_TO_BT_FILTERED)Convert_8M_ToBT_Filtered;
+      p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER)Convert_8M_ToBT_NoFilter;
+      p_cb->divisor = 1;
+    } else {
+      p_cb->filter = (PCONVERT_TO_BT_FILTERED)Convert_16M_ToBT_Filtered;
+      p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER)Convert_16M_ToBT_NoFilter;
+    }
+  } else {
+    /* stereo */
+    if (bits == 8) {
+      p_cb->filter = (PCONVERT_TO_BT_FILTERED)Convert_8S_ToBT_Filtered;
+      p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER)Convert_8S_ToBT_NoFilter;
+    } else {
+      p_cb->filter = (PCONVERT_TO_BT_FILTERED)Convert_16S_ToBT_Filtered;
+      p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER)Convert_16S_ToBT_NoFilter;
+      p_cb->divisor = 4;
+    }
+  }
+
+#if (BTA_DM_SCO_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_pcm_init_dwn_sample: cur_pos %d, src_sps %d",
+                   p_cb->cur_pos, p_cb->src_sps);
+  APPL_TRACE_DEBUG(
+      "bta_pcm_init_dwn_sample: bits %d, n_channels %d, sample_size %d, ",
+      p_cb->bits, p_cb->n_channels, p_cb->sample_size);
+  APPL_TRACE_DEBUG(
+      "bta_pcm_init_dwn_sample: can_be_filtered %d, n_channels: %d, \
+        divisor %d",
+      p_cb->can_be_filtered, p_cb->n_channels, p_cb->divisor);
+#endif
+}
+
+/**************************************************************************************
+ * Function         BTA_DmPcmResample
+ *
+ * Description      Down sampling utility to convert higher sampling rate into
+ *                  8K/16bits PCM samples.
+ *
+ * Parameters       p_src: pointer to the buffer where the original sampling PCM
+ *                              are stored.
+ *                  in_bytes:  Length of the input PCM sample buffer in byte.
+ *                  p_dst:      pointer to the buffer which is to be used to
+ *                              store the converted PCM samples.
+ *
+ *
+ * Returns          int32_t: number of samples converted.
+ *
+ *************************************************************************************/
+int32_t BTA_DmPcmResample(void* p_src, uint32_t in_bytes, void* p_dst) {
+  uint32_t out_sample;
+
+#if (BTA_DM_SCO_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_pcm_resample : insamples  %d",
+                   (in_bytes / bta_dm_pcm_cb.divisor));
+#endif
+  if (bta_dm_pcm_cb.can_be_filtered) {
+    out_sample = (*bta_dm_pcm_cb.filter)(
+        p_src, p_dst, (in_bytes / bta_dm_pcm_cb.divisor), bta_dm_pcm_cb.src_sps,
+        (int32_t*)&bta_dm_pcm_cb.cur_pos, bta_dm_pcm_cb.overlap_area);
+  } else {
+    out_sample = (*bta_dm_pcm_cb.nofilter)(p_src, p_dst,
+                                           (in_bytes / bta_dm_pcm_cb.divisor),
+                                           bta_dm_pcm_cb.src_sps);
+  }
+
+#if (BTA_DM_SCO_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_pcm_resample : outsamples  %d", out_sample);
+#endif
+
+  return (out_sample * bta_dm_pcm_cb.sample_size);
+}
+#endif
diff --git a/bt/bta/gatt/bta_gattc_act.cc b/bt/bta/gatt/bta_gattc_act.cc
new file mode 100644
index 0000000..7895cf2
--- /dev/null
+++ b/bt/bta/gatt/bta_gattc_act.cc
@@ -0,0 +1,1719 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 GATT client action functions for the state
+ *  machine.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bta_gattc"
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bta_gattc_int.h"
+#include "bta_sys.h"
+#include "btif/include/btif_debug_conn.h"
+#include "l2c_api.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "stack/l2cap/l2c_int.h"
+#include "utl.h"
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+#include "bta_hh_int.h"
+#endif
+
+#if (BTA_GATT_INCLUDED == TRUE && BLE_INCLUDED == TRUE)
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+static void bta_gattc_conn_cback(tGATT_IF gattc_if, BD_ADDR bda,
+                                 uint16_t conn_id, bool connected,
+                                 tGATT_DISCONN_REASON reason,
+                                 tBT_TRANSPORT transport);
+
+static void bta_gattc_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op,
+                                 tGATT_STATUS status,
+                                 tGATT_CL_COMPLETE* p_data);
+static void bta_gattc_cmpl_sendmsg(uint16_t conn_id, tGATTC_OPTYPE op,
+                                   tBTA_GATT_STATUS status,
+                                   tGATT_CL_COMPLETE* p_data);
+
+static void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB* p_clreg);
+static void bta_gattc_enc_cmpl_cback(tGATT_IF gattc_if, BD_ADDR bda);
+static void bta_gattc_cong_cback(uint16_t conn_id, bool congested);
+
+static tGATT_CBACK bta_gattc_cl_cback = {bta_gattc_conn_cback,
+                                         bta_gattc_cmpl_cback,
+                                         bta_gattc_disc_res_cback,
+                                         bta_gattc_disc_cmpl_cback,
+                                         NULL,
+                                         bta_gattc_enc_cmpl_cback,
+                                         bta_gattc_cong_cback};
+
+/* opcode(tGATTC_OPTYPE) order has to be comply with internal event order */
+static uint16_t bta_gattc_opcode_to_int_evt[] = {
+    BTA_GATTC_API_READ_EVT, BTA_GATTC_API_WRITE_EVT, BTA_GATTC_API_EXEC_EVT,
+    BTA_GATTC_API_CFG_MTU_EVT};
+
+#if (BT_TRACE_VERBOSE == TRUE)
+static const char* bta_gattc_op_code_name[] = {
+    "Unknown", "Discovery", "Read",         "Write",
+    "Exec",    "Config",    "Notification", "Indication"};
+#endif  // BT_TRACE_VERBOSE
+/*****************************************************************************
+ *  Action Functions
+ ****************************************************************************/
+
+void bta_gattc_reset_discover_st(tBTA_GATTC_SERV* p_srcb,
+                                 tBTA_GATT_STATUS status);
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_enable
+ *
+ * Description      Enables GATTC module
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_gattc_enable() {
+  APPL_TRACE_DEBUG("bta_gattc_enable");
+
+  if (bta_gattc_cb.state == BTA_GATTC_STATE_DISABLED) {
+    /* initialize control block */
+    memset(&bta_gattc_cb, 0, sizeof(tBTA_GATTC_CB));
+    bta_gattc_cb.state = BTA_GATTC_STATE_ENABLED;
+  } else {
+    APPL_TRACE_DEBUG("GATTC is arelady enabled");
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_disable
+ *
+ * Description      Disable GATTC module by cleaning up all active connections
+ *                  and deregister all application.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_gattc_disable() {
+  uint8_t i;
+
+  APPL_TRACE_DEBUG("bta_gattc_disable");
+
+  if (bta_gattc_cb.state != BTA_GATTC_STATE_ENABLED) {
+    APPL_TRACE_ERROR("not enabled or disable in pogress");
+    return;
+  }
+
+  for (i = 0; i < BTA_GATTC_CL_MAX; i++) {
+    if (bta_gattc_cb.cl_rcb[i].in_use) {
+      bta_gattc_cb.state = BTA_GATTC_STATE_DISABLING;
+/* don't deregister HH GATT IF */
+/* HH GATT IF will be deregistered by bta_hh_le_deregister when disable HH */
+#if (BTA_HH_LE_INCLUDED == TRUE)
+      if (!bta_hh_le_is_hh_gatt_if(bta_gattc_cb.cl_rcb[i].client_if)) {
+#endif
+        bta_gattc_deregister(&bta_gattc_cb.cl_rcb[i]);
+#if (BTA_HH_LE_INCLUDED == TRUE)
+      }
+#endif
+    }
+  }
+
+  /* no registered apps, indicate disable completed */
+  if (bta_gattc_cb.state != BTA_GATTC_STATE_DISABLING) {
+    memset(&bta_gattc_cb, 0, sizeof(tBTA_GATTC_CB));
+    bta_gattc_cb.state = BTA_GATTC_STATE_DISABLED;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_register
+ *
+ * Description      Register a GATT client application with BTA.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_gattc_register(tBTA_GATTC_DATA* p_data) {
+  tBTA_GATTC cb_data;
+  uint8_t i;
+  tBT_UUID* p_app_uuid = &p_data->api_reg.app_uuid;
+  tBTA_GATT_STATUS status = BTA_GATT_NO_RESOURCES;
+
+  APPL_TRACE_DEBUG("bta_gattc_register state %d", bta_gattc_cb.state);
+  memset(&cb_data, 0, sizeof(cb_data));
+  cb_data.reg_oper.status = BTA_GATT_NO_RESOURCES;
+
+  /* check if  GATTC module is already enabled . Else enable */
+  if (bta_gattc_cb.state == BTA_GATTC_STATE_DISABLED) {
+    bta_gattc_enable();
+  }
+  /* todo need to check duplicate uuid */
+  for (i = 0; i < BTA_GATTC_CL_MAX; i++) {
+    if (!bta_gattc_cb.cl_rcb[i].in_use) {
+      if ((p_app_uuid == NULL) ||
+          (bta_gattc_cb.cl_rcb[i].client_if =
+               GATT_Register(p_app_uuid, &bta_gattc_cl_cback)) == 0) {
+        APPL_TRACE_ERROR("Register with GATT stack failed.");
+        status = BTA_GATT_ERROR;
+      } else {
+        bta_gattc_cb.cl_rcb[i].in_use = true;
+        bta_gattc_cb.cl_rcb[i].p_cback = p_data->api_reg.p_cback;
+        memcpy(&bta_gattc_cb.cl_rcb[i].app_uuid, p_app_uuid, sizeof(tBT_UUID));
+
+        /* BTA use the same client interface as BTE GATT statck */
+        cb_data.reg_oper.client_if = bta_gattc_cb.cl_rcb[i].client_if;
+
+        tBTA_GATTC_INT_START_IF* p_buf = (tBTA_GATTC_INT_START_IF*)osi_malloc(
+            sizeof(tBTA_GATTC_INT_START_IF));
+        p_buf->hdr.event = BTA_GATTC_INT_START_IF_EVT;
+        p_buf->client_if = bta_gattc_cb.cl_rcb[i].client_if;
+
+        bta_sys_sendmsg(p_buf);
+        status = BTA_GATT_OK;
+        break;
+      }
+    }
+  }
+
+  /* callback with register event */
+  if (p_data->api_reg.p_cback) {
+    if (p_app_uuid != NULL)
+      memcpy(&(cb_data.reg_oper.app_uuid), p_app_uuid, sizeof(tBT_UUID));
+
+    cb_data.reg_oper.status = status;
+    (*p_data->api_reg.p_cback)(BTA_GATTC_REG_EVT, (tBTA_GATTC*)&cb_data);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_start_if
+ *
+ * Description      start an application interface.
+ *
+ * Returns          none.
+ *
+ ******************************************************************************/
+void bta_gattc_start_if(tBTA_GATTC_DATA* p_msg) {
+  if (bta_gattc_cl_get_regcb(p_msg->int_start_if.client_if) != NULL) {
+    GATT_StartIf(p_msg->int_start_if.client_if);
+  } else {
+    APPL_TRACE_ERROR("Unable to start app.: Unknown interface =%d",
+                     p_msg->int_start_if.client_if);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_deregister
+ *
+ * Description      De-Register a GATT client application with BTA.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_gattc_deregister(tBTA_GATTC_RCB* p_clreg) {
+  uint8_t i;
+  BT_HDR buf;
+
+  if (p_clreg != NULL) {
+    /* remove bg connection associated with this rcb */
+    for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i++) {
+      if (bta_gattc_cb.bg_track[i].in_use) {
+        if (bta_gattc_cb.bg_track[i].cif_mask &
+            (1 << (p_clreg->client_if - 1))) {
+          bta_gattc_mark_bg_conn(p_clreg->client_if,
+                                 bta_gattc_cb.bg_track[i].remote_bda, false);
+          GATT_CancelConnect(p_clreg->client_if,
+                             bta_gattc_cb.bg_track[i].remote_bda, false);
+        }
+      }
+    }
+
+    if (p_clreg->num_clcb > 0) {
+      /* close all CLCB related to this app */
+      for (i = 0; i < BTA_GATTC_CLCB_MAX; i++) {
+        if (bta_gattc_cb.clcb[i].in_use &&
+            (bta_gattc_cb.clcb[i].p_rcb == p_clreg)) {
+          p_clreg->dereg_pending = true;
+
+          buf.event = BTA_GATTC_API_CLOSE_EVT;
+          buf.layer_specific = bta_gattc_cb.clcb[i].bta_conn_id;
+          bta_gattc_close(&bta_gattc_cb.clcb[i], (tBTA_GATTC_DATA*)&buf);
+        }
+      }
+    } else
+      bta_gattc_deregister_cmpl(p_clreg);
+  } else {
+    APPL_TRACE_ERROR(
+        "bta_gattc_deregister Deregister Failedm unknown client cif");
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_process_api_open
+ *
+ * Description      process connect API request.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_gattc_process_api_open(tBTA_GATTC_DATA* p_msg) {
+  uint16_t event = ((BT_HDR*)p_msg)->event;
+  tBTA_GATTC_CLCB* p_clcb = NULL;
+  tBTA_GATTC_RCB* p_clreg = bta_gattc_cl_get_regcb(p_msg->api_conn.client_if);
+
+  if (p_clreg != NULL) {
+    if (p_msg->api_conn.is_direct) {
+      if ((p_clcb = bta_gattc_find_alloc_clcb(
+               p_msg->api_conn.client_if, p_msg->api_conn.remote_bda,
+               p_msg->api_conn.transport)) != NULL) {
+        bta_gattc_sm_execute(p_clcb, event, p_msg);
+      } else {
+        APPL_TRACE_ERROR("No resources to open a new connection.");
+
+        bta_gattc_send_open_cback(
+            p_clreg, BTA_GATT_NO_RESOURCES, p_msg->api_conn.remote_bda,
+            BTA_GATT_INVALID_CONN_ID, p_msg->api_conn.transport, 0);
+      }
+    } else {
+      bta_gattc_init_bk_conn(&p_msg->api_conn, p_clreg);
+    }
+  } else {
+    APPL_TRACE_ERROR("bta_gattc_process_api_open Failed, unknown client_if: %d",
+                     p_msg->api_conn.client_if);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_process_api_open_cancel
+ *
+ * Description      process connect API request.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_gattc_process_api_open_cancel(tBTA_GATTC_DATA* p_msg) {
+  uint16_t event = ((BT_HDR*)p_msg)->event;
+  tBTA_GATTC_CLCB* p_clcb = NULL;
+  tBTA_GATTC_RCB* p_clreg;
+  tBTA_GATTC cb_data;
+
+  if (p_msg->api_cancel_conn.is_direct) {
+    if ((p_clcb = bta_gattc_find_clcb_by_cif(p_msg->api_cancel_conn.client_if,
+                                             p_msg->api_cancel_conn.remote_bda,
+                                             BTA_GATT_TRANSPORT_LE)) != NULL) {
+      bta_gattc_sm_execute(p_clcb, event, p_msg);
+    } else {
+      APPL_TRACE_ERROR("No such connection need to be cancelled");
+
+      p_clreg = bta_gattc_cl_get_regcb(p_msg->api_cancel_conn.client_if);
+
+      if (p_clreg && p_clreg->p_cback) {
+        cb_data.status = BTA_GATT_ERROR;
+        (*p_clreg->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data);
+      }
+    }
+  } else {
+    bta_gattc_cancel_bk_conn(&p_msg->api_cancel_conn);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_process_enc_cmpl
+ *
+ * Description      process encryption complete message.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_gattc_process_enc_cmpl(tBTA_GATTC_DATA* p_msg) {
+  tBTA_GATTC_RCB* p_clreg;
+  tBTA_GATTC cb_data;
+
+  p_clreg = bta_gattc_cl_get_regcb(p_msg->enc_cmpl.client_if);
+
+  if (p_clreg && p_clreg->p_cback) {
+    memset(&cb_data, 0, sizeof(tBTA_GATTC));
+
+    cb_data.enc_cmpl.client_if = p_msg->enc_cmpl.client_if;
+    bdcpy(cb_data.enc_cmpl.remote_bda, p_msg->enc_cmpl.remote_bda);
+
+    (*p_clreg->p_cback)(BTA_GATTC_ENC_CMPL_CB_EVT, &cb_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_cancel_open_error
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_gattc_cancel_open_error(tBTA_GATTC_CLCB* p_clcb,
+                                 UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+  tBTA_GATTC cb_data;
+
+  cb_data.status = BTA_GATT_ERROR;
+
+  if (p_clcb && p_clcb->p_rcb && p_clcb->p_rcb->p_cback)
+    (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_open_error
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_gattc_open_error(tBTA_GATTC_CLCB* p_clcb,
+                          UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+  APPL_TRACE_ERROR("Connection already opened. wrong state");
+
+  bta_gattc_send_open_cback(p_clcb->p_rcb, BTA_GATT_OK, p_clcb->bda,
+                            p_clcb->bta_conn_id, p_clcb->transport, 0);
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_open_fail
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_gattc_open_fail(tBTA_GATTC_CLCB* p_clcb,
+                         UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+  bta_gattc_send_open_cback(p_clcb->p_rcb, BTA_GATT_ERROR, p_clcb->bda,
+                            p_clcb->bta_conn_id, p_clcb->transport, 0);
+  /* open failure, remove clcb */
+  bta_gattc_clcb_dealloc(p_clcb);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_open
+ *
+ * Description      Process API connection function.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_gattc_open(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+  tBTA_GATTC_DATA gattc_data;
+
+  /* open/hold a connection */
+  if (!GATT_Connect(p_clcb->p_rcb->client_if, p_data->api_conn.remote_bda, true,
+                    p_data->api_conn.transport, false)) {
+    APPL_TRACE_ERROR("Connection open failure");
+
+    bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_OPEN_FAIL_EVT, p_data);
+  } else {
+    /* a connected remote device */
+    if (GATT_GetConnIdIfConnected(
+            p_clcb->p_rcb->client_if, p_data->api_conn.remote_bda,
+            &p_clcb->bta_conn_id, p_data->api_conn.transport)) {
+      gattc_data.int_conn.hdr.layer_specific = p_clcb->bta_conn_id;
+
+      bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, &gattc_data);
+    }
+    /* else wait for the callback event */
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_init_bk_conn
+ *
+ * Description      Process API Open for a background connection
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN* p_data,
+                            tBTA_GATTC_RCB* p_clreg) {
+  tBTA_GATT_STATUS status = BTA_GATT_NO_RESOURCES;
+  uint16_t conn_id;
+  tBTA_GATTC_CLCB* p_clcb;
+  tBTA_GATTC_DATA gattc_data;
+
+  if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, true)) {
+    /* always call open to hold a connection */
+    if (!GATT_Connect(p_data->client_if, p_data->remote_bda, false,
+                      p_data->transport, false)) {
+      uint8_t* bda = (uint8_t*)p_data->remote_bda;
+      status = BTA_GATT_ERROR;
+      APPL_TRACE_ERROR(
+          "%s unable to connect to remote "
+          "bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
+          __func__, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+
+    } else {
+      status = BTA_GATT_OK;
+
+      /* if is a connected remote device */
+      if (GATT_GetConnIdIfConnected(p_data->client_if, p_data->remote_bda,
+                                    &conn_id, p_data->transport)) {
+        if ((p_clcb = bta_gattc_find_alloc_clcb(
+                 p_data->client_if, p_data->remote_bda,
+                 BTA_GATT_TRANSPORT_LE)) != NULL) {
+          gattc_data.hdr.layer_specific = p_clcb->bta_conn_id = conn_id;
+
+          /* open connection */
+          bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, &gattc_data);
+          status = BTA_GATT_OK;
+        }
+      }
+    }
+  }
+
+  /* open failure, report OPEN_EVT */
+  if (status != BTA_GATT_OK) {
+    bta_gattc_send_open_cback(p_clreg, status, p_data->remote_bda,
+                              BTA_GATT_INVALID_CONN_ID, BTA_GATT_TRANSPORT_LE,
+                              0);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_cancel_bk_conn
+ *
+ * Description      Process API Cancel Open for a background connection
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN* p_data) {
+  tBTA_GATTC_RCB* p_clreg;
+  tBTA_GATTC cb_data;
+  cb_data.status = BTA_GATT_ERROR;
+
+  /* remove the device from the bg connection mask */
+  if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, false)) {
+    if (GATT_CancelConnect(p_data->client_if, p_data->remote_bda, false)) {
+      cb_data.status = BTA_GATT_OK;
+    } else {
+      APPL_TRACE_ERROR("bta_gattc_cancel_bk_conn failed");
+    }
+  }
+  p_clreg = bta_gattc_cl_get_regcb(p_data->client_if);
+
+  if (p_clreg && p_clreg->p_cback) {
+    (*p_clreg->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_int_cancel_open_ok
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_gattc_cancel_open_ok(tBTA_GATTC_CLCB* p_clcb,
+                              UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+  tBTA_GATTC cb_data;
+
+  if (p_clcb->p_rcb->p_cback) {
+    cb_data.status = BTA_GATT_OK;
+    (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data);
+  }
+
+  bta_gattc_clcb_dealloc(p_clcb);
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_cancel_open
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_gattc_cancel_open(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+  tBTA_GATTC cb_data;
+
+  if (GATT_CancelConnect(p_clcb->p_rcb->client_if,
+                         p_data->api_cancel_conn.remote_bda, true)) {
+    bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CANCEL_OPEN_OK_EVT, p_data);
+  } else {
+    if (p_clcb->p_rcb->p_cback) {
+      cb_data.status = BTA_GATT_ERROR;
+      (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data);
+    }
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_conn
+ *
+ * Description      receive connection callback from stack
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_gattc_conn(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+  tBTA_GATTC_IF gatt_if;
+  APPL_TRACE_DEBUG("bta_gattc_conn server cache state=%d",
+                   p_clcb->p_srcb->state);
+
+  if (p_data != NULL) {
+    APPL_TRACE_DEBUG("bta_gattc_conn conn_id=%d", p_data->hdr.layer_specific);
+    p_clcb->bta_conn_id = p_data->int_conn.hdr.layer_specific;
+
+    GATT_GetConnectionInfor(p_data->hdr.layer_specific, &gatt_if, p_clcb->bda,
+                            &p_clcb->transport);
+  }
+
+  p_clcb->p_srcb->connected = true;
+
+  if (p_clcb->p_srcb->mtu == 0) p_clcb->p_srcb->mtu = GATT_DEF_BLE_MTU_SIZE;
+
+  /* start database cache if needed */
+  if (p_clcb->p_srcb->p_srvc_cache == NULL ||
+      p_clcb->p_srcb->state != BTA_GATTC_SERV_IDLE) {
+    if (p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE) {
+      p_clcb->p_srcb->state = BTA_GATTC_SERV_LOAD;
+      if (bta_gattc_cache_load(p_clcb)) {
+        p_clcb->p_srcb->state = BTA_GATTC_SERV_IDLE;
+        bta_gattc_reset_discover_st(p_clcb->p_srcb, BTA_GATT_OK);
+      } else {
+        p_clcb->p_srcb->state = BTA_GATTC_SERV_DISC;
+        /* cache load failure, start discovery */
+        bta_gattc_start_discover(p_clcb, NULL);
+      }
+    } else /* cache is building */
+      p_clcb->state = BTA_GATTC_DISCOVER_ST;
+  }
+
+  else {
+    /* a pending service handle change indication */
+    if (p_clcb->p_srcb->srvc_hdl_chg) {
+      p_clcb->p_srcb->srvc_hdl_chg = false;
+      /* start discovery */
+      bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL);
+    }
+  }
+
+  if (p_clcb->p_rcb) {
+    /* there is no RM for GATT */
+    if (p_clcb->transport == BTA_TRANSPORT_BR_EDR)
+      bta_sys_conn_open(BTA_ID_GATTC, BTA_ALL_APP_ID, p_clcb->bda);
+
+    bta_gattc_send_open_cback(p_clcb->p_rcb, BTA_GATT_OK, p_clcb->bda,
+                              p_clcb->bta_conn_id, p_clcb->transport,
+                              p_clcb->p_srcb->mtu);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_close_fail
+ *
+ * Description      close a  connection.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_gattc_close_fail(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+  tBTA_GATTC cb_data;
+
+  if (p_clcb->p_rcb->p_cback) {
+    memset(&cb_data, 0, sizeof(tBTA_GATTC));
+    cb_data.close.client_if = p_clcb->p_rcb->client_if;
+    cb_data.close.conn_id = p_data->hdr.layer_specific;
+    bdcpy(cb_data.close.remote_bda, p_clcb->bda);
+    cb_data.close.status = BTA_GATT_ERROR;
+    cb_data.close.reason = BTA_GATT_CONN_NONE;
+
+    (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CLOSE_EVT, &cb_data);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_api_close
+ *
+ * Description      close a GATTC connection.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_gattc_close(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+  tBTA_GATTC_CBACK* p_cback = p_clcb->p_rcb->p_cback;
+  tBTA_GATTC_RCB* p_clreg = p_clcb->p_rcb;
+  tBTA_GATTC cb_data;
+
+  APPL_TRACE_DEBUG("bta_gattc_close conn_id=%d", p_clcb->bta_conn_id);
+
+  cb_data.close.client_if = p_clcb->p_rcb->client_if;
+  cb_data.close.conn_id = p_clcb->bta_conn_id;
+  cb_data.close.reason = p_clcb->reason;
+  cb_data.close.status = p_clcb->status;
+  bdcpy(cb_data.close.remote_bda, p_clcb->bda);
+
+  if (p_clcb->transport == BTA_TRANSPORT_BR_EDR)
+    bta_sys_conn_close(BTA_ID_GATTC, BTA_ALL_APP_ID, p_clcb->bda);
+
+  bta_gattc_clcb_dealloc(p_clcb);
+
+  if (p_data->hdr.event == BTA_GATTC_API_CLOSE_EVT) {
+    cb_data.close.status = GATT_Disconnect(p_data->hdr.layer_specific);
+  } else if (p_data->hdr.event == BTA_GATTC_INT_DISCONN_EVT) {
+    cb_data.close.status = p_data->int_conn.reason;
+    cb_data.close.reason = p_data->int_conn.reason;
+  }
+
+  if (p_cback) (*p_cback)(BTA_GATTC_CLOSE_EVT, (tBTA_GATTC*)&cb_data);
+
+  if (p_clreg->num_clcb == 0 && p_clreg->dereg_pending) {
+    bta_gattc_deregister_cmpl(p_clreg);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_reset_discover_st
+ *
+ * Description      when a SRCB finished discovery, tell all related clcb.
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_reset_discover_st(tBTA_GATTC_SERV* p_srcb,
+                                 tBTA_GATT_STATUS status) {
+  uint8_t i;
+
+  for (i = 0; i < BTA_GATTC_CLCB_MAX; i++) {
+    if (bta_gattc_cb.clcb[i].p_srcb == p_srcb) {
+      bta_gattc_cb.clcb[i].status = status;
+      bta_gattc_sm_execute(&bta_gattc_cb.clcb[i], BTA_GATTC_DISCOVER_CMPL_EVT,
+                           NULL);
+    }
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_disc_close
+ *
+ * Description      close a GATTC connection while in discovery state.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_gattc_disc_close(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+  APPL_TRACE_DEBUG("%s: Discovery cancel conn_id=%d", __func__,
+                   p_clcb->bta_conn_id);
+
+  if (p_clcb->disc_active)
+    bta_gattc_reset_discover_st(p_clcb->p_srcb, BTA_GATT_ERROR);
+  else
+    p_clcb->state = BTA_GATTC_CONN_ST;
+
+  // This function only gets called as the result of a BTA_GATTC_API_CLOSE_EVT
+  // while in the BTA_GATTC_DISCOVER_ST state. Once the state changes, the
+  // connection itself still needs to be closed to resolve the original event.
+  if (p_clcb->state == BTA_GATTC_CONN_ST) {
+    APPL_TRACE_DEBUG(
+        "State is back to BTA_GATTC_CONN_ST. "
+        "Trigger connection close");
+    bta_gattc_close(p_clcb, p_data);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_set_discover_st
+ *
+ * Description      when a SRCB start discovery, tell all related clcb and set
+ *                  the state.
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_set_discover_st(tBTA_GATTC_SERV* p_srcb) {
+  uint8_t i;
+
+#if (BLE_INCLUDED == TRUE)
+  L2CA_EnableUpdateBleConnParams(p_srcb->server_bda, false);
+#endif
+  for (i = 0; i < BTA_GATTC_CLCB_MAX; i++) {
+    if (bta_gattc_cb.clcb[i].p_srcb == p_srcb) {
+      bta_gattc_cb.clcb[i].status = BTA_GATT_OK;
+      bta_gattc_cb.clcb[i].state = BTA_GATTC_DISCOVER_ST;
+    }
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_restart_discover
+ *
+ * Description      process service change in discovery state, mark up the auto
+ *                  update flag and set status to be discovery cancel for
+ *                  current discovery.
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_restart_discover(tBTA_GATTC_CLCB* p_clcb,
+                                UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+  p_clcb->status = BTA_GATT_CANCEL;
+  p_clcb->auto_update = BTA_GATTC_DISC_WAITING;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_cfg_mtu
+ *
+ * Description      Configure MTU size on the GATT connection.
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_cfg_mtu(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+  tBTA_GATT_STATUS status;
+
+  if (bta_gattc_enqueue(p_clcb, p_data)) {
+    status = GATTC_ConfigureMTU(p_clcb->bta_conn_id, p_data->api_mtu.mtu);
+
+    /* if failed, return callback here */
+    if (status != GATT_SUCCESS && status != GATT_CMD_STARTED) {
+      /* Dequeue the data, if it was enqueued */
+      if (p_clcb->p_q_cmd == p_data) p_clcb->p_q_cmd = NULL;
+
+      bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_CONFIG, status,
+                             NULL);
+    }
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_start_discover
+ *
+ * Description      Start a discovery on server.
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_start_discover(tBTA_GATTC_CLCB* p_clcb,
+                              UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+  APPL_TRACE_DEBUG(
+      "bta_gattc_start_discover conn_id=%d p_clcb->p_srcb->state = %d ",
+      p_clcb->bta_conn_id, p_clcb->p_srcb->state);
+
+  if (((p_clcb->p_q_cmd == NULL ||
+        p_clcb->auto_update == BTA_GATTC_REQ_WAITING) &&
+       p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE) ||
+      p_clcb->p_srcb->state == BTA_GATTC_SERV_DISC)
+  /* no pending operation, start discovery right away */
+  {
+    p_clcb->auto_update = BTA_GATTC_NO_SCHEDULE;
+
+    if (p_clcb->p_srcb != NULL) {
+      /* clear the service change mask */
+      p_clcb->p_srcb->srvc_hdl_chg = false;
+      p_clcb->p_srcb->update_count = 0;
+      p_clcb->p_srcb->state = BTA_GATTC_SERV_DISC_ACT;
+
+      if (p_clcb->transport == BTA_TRANSPORT_LE)
+        L2CA_EnableUpdateBleConnParams(p_clcb->p_srcb->server_bda, false);
+
+      /* set all srcb related clcb into discovery ST */
+      bta_gattc_set_discover_st(p_clcb->p_srcb);
+
+      if ((p_clcb->status = bta_gattc_init_cache(p_clcb->p_srcb)) ==
+          BTA_GATT_OK) {
+        p_clcb->status = bta_gattc_discover_pri_service(
+            p_clcb->bta_conn_id, p_clcb->p_srcb, GATT_DISC_SRVC_ALL);
+      }
+      if (p_clcb->status != BTA_GATT_OK) {
+        APPL_TRACE_ERROR("discovery on server failed");
+        bta_gattc_reset_discover_st(p_clcb->p_srcb, p_clcb->status);
+      } else
+        p_clcb->disc_active = true;
+    } else {
+      APPL_TRACE_ERROR("unknown device, can not start discovery");
+    }
+  }
+  /* pending operation, wait until it finishes */
+  else {
+    p_clcb->auto_update = BTA_GATTC_DISC_WAITING;
+
+    if (p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE)
+      p_clcb->state = BTA_GATTC_CONN_ST; /* set clcb state */
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_disc_cmpl
+ *
+ * Description      discovery on server is finished
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB* p_clcb,
+                         UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+  tBTA_GATTC_DATA* p_q_cmd = p_clcb->p_q_cmd;
+
+  APPL_TRACE_DEBUG("bta_gattc_disc_cmpl conn_id=%d", p_clcb->bta_conn_id);
+
+#if (BLE_INCLUDED == TRUE)
+  if (p_clcb->transport == BTA_TRANSPORT_LE)
+    L2CA_EnableUpdateBleConnParams(p_clcb->p_srcb->server_bda, true);
+#endif
+  p_clcb->p_srcb->state = BTA_GATTC_SERV_IDLE;
+  p_clcb->disc_active = false;
+
+  if (p_clcb->status != GATT_SUCCESS) {
+    /* clean up cache */
+    if (p_clcb->p_srcb && p_clcb->p_srcb->p_srvc_cache) {
+      list_free(p_clcb->p_srcb->p_srvc_cache);
+      p_clcb->p_srcb->p_srvc_cache = NULL;
+    }
+
+    /* used to reset cache in application */
+    bta_gattc_cache_reset(p_clcb->p_srcb->server_bda);
+  }
+  if (p_clcb->p_srcb && p_clcb->p_srcb->p_srvc_list) {
+    /* release pending attribute list buffer */
+    osi_free_and_reset((void**)&p_clcb->p_srcb->p_srvc_list);
+  }
+
+  if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING) {
+    /* start discovery again */
+    p_clcb->auto_update = BTA_GATTC_REQ_WAITING;
+    bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL);
+  }
+  /* get any queued command to proceed */
+  else if (p_q_cmd != NULL) {
+    p_clcb->p_q_cmd = NULL;
+    /* execute pending operation of link block still present */
+    if (l2cu_find_lcb_by_bd_addr(p_clcb->p_srcb->server_bda, BT_TRANSPORT_LE) !=
+        NULL) {
+      bta_gattc_sm_execute(p_clcb, p_q_cmd->hdr.event, p_q_cmd);
+    }
+    /* if the command executed requeued the cmd, we don't
+     * want to free the underlying buffer that's being
+     * referenced by p_clcb->p_q_cmd
+     */
+    if (p_q_cmd != p_clcb->p_q_cmd) osi_free_and_reset((void**)&p_q_cmd);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_read
+ *
+ * Description      Read an attribute
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_read(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+  if (!bta_gattc_enqueue(p_clcb, p_data)) return;
+
+  tGATT_READ_PARAM read_param;
+  memset(&read_param, 0, sizeof(tGATT_READ_PARAM));
+  read_param.by_handle.handle = p_data->api_read.handle;
+  read_param.by_handle.auth_req = p_data->api_read.auth_req;
+
+  tBTA_GATT_STATUS status =
+      GATTC_Read(p_clcb->bta_conn_id, GATT_READ_BY_HANDLE, &read_param);
+
+  /* read fail */
+  if (status != BTA_GATT_OK) {
+    /* Dequeue the data, if it was enqueued */
+    if (p_clcb->p_q_cmd == p_data) p_clcb->p_q_cmd = NULL;
+
+    bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_READ, status,
+                           NULL);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_read_multi
+ *
+ * Description      read multiple
+ *
+ * Returns          None.
+ ********************************************************************************/
+void bta_gattc_read_multi(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+  tBTA_GATT_STATUS status = BTA_GATT_OK;
+  tGATT_READ_PARAM read_param;
+
+  if (bta_gattc_enqueue(p_clcb, p_data)) {
+    memset(&read_param, 0, sizeof(tGATT_READ_PARAM));
+
+    if (status == BTA_GATT_OK) {
+      read_param.read_multiple.num_handles = p_data->api_read_multi.num_attr;
+      read_param.read_multiple.auth_req = p_data->api_read_multi.auth_req;
+      memcpy(&read_param.read_multiple.handles, p_data->api_read_multi.handles,
+             sizeof(uint16_t) * p_data->api_read_multi.num_attr);
+
+      status = GATTC_Read(p_clcb->bta_conn_id, GATT_READ_MULTIPLE, &read_param);
+    }
+
+    /* read fail */
+    if (status != BTA_GATT_OK) {
+      /* Dequeue the data, if it was enqueued */
+      if (p_clcb->p_q_cmd == p_data) p_clcb->p_q_cmd = NULL;
+
+      bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_READ, status,
+                             NULL);
+    }
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_write
+ *
+ * Description      Write an attribute
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_write(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+  if (!bta_gattc_enqueue(p_clcb, p_data)) return;
+
+  tBTA_GATT_STATUS status = BTA_GATT_OK;
+  tGATT_VALUE attr;
+
+  attr.conn_id = p_clcb->bta_conn_id;
+  attr.handle = p_data->api_write.handle;
+  attr.offset = p_data->api_write.offset;
+  attr.len = p_data->api_write.len;
+  attr.auth_req = p_data->api_write.auth_req;
+
+  if (p_data->api_write.p_value)
+    memcpy(attr.value, p_data->api_write.p_value, p_data->api_write.len);
+
+  status =
+      GATTC_Write(p_clcb->bta_conn_id, p_data->api_write.write_type, &attr);
+
+  /* write fail */
+  if (status != BTA_GATT_OK) {
+    /* Dequeue the data, if it was enqueued */
+    if (p_clcb->p_q_cmd == p_data) p_clcb->p_q_cmd = NULL;
+
+    bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_WRITE, status,
+                           NULL);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_execute
+ *
+ * Description      send execute write
+ *
+ * Returns          None.
+ ********************************************************************************/
+void bta_gattc_execute(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+  tBTA_GATT_STATUS status;
+
+  if (bta_gattc_enqueue(p_clcb, p_data)) {
+    status =
+        GATTC_ExecuteWrite(p_clcb->bta_conn_id, p_data->api_exec.is_execute);
+
+    if (status != BTA_GATT_OK) {
+      /* Dequeue the data, if it was enqueued */
+      if (p_clcb->p_q_cmd == p_data) p_clcb->p_q_cmd = NULL;
+
+      bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_EXE_WRITE,
+                             status, NULL);
+    }
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_confirm
+ *
+ * Description      send handle value confirmation
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_confirm(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+  uint16_t handle = p_data->api_confirm.handle;
+
+  if (GATTC_SendHandleValueConfirm(p_data->api_confirm.hdr.layer_specific,
+                                   handle) != GATT_SUCCESS) {
+    APPL_TRACE_ERROR("bta_gattc_confirm to handle [0x%04x] failed", handle);
+  } else {
+    /* if over BR_EDR, inform PM for mode change */
+    if (p_clcb->transport == BTA_TRANSPORT_BR_EDR) {
+      bta_sys_busy(BTA_ID_GATTC, BTA_ALL_APP_ID, p_clcb->bda);
+      bta_sys_idle(BTA_ID_GATTC, BTA_ALL_APP_ID, p_clcb->bda);
+    }
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_read_cmpl
+ *
+ * Description      read complete
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_read_cmpl(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_OP_CMPL* p_data) {
+  GATT_READ_OP_CB cb = p_clcb->p_q_cmd->api_read.read_cb;
+  void* my_cb_data = p_clcb->p_q_cmd->api_read.read_cb_data;
+
+  uint16_t handle = p_clcb->p_q_cmd->api_read.handle;
+  osi_free_and_reset((void**)&p_clcb->p_q_cmd);
+
+  if (cb) {
+    cb(p_clcb->bta_conn_id, p_data->status, handle,
+       p_data->p_cmpl->att_value.len, p_data->p_cmpl->att_value.value,
+       my_cb_data);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_write_cmpl
+ *
+ * Description      write complete
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_write_cmpl(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_OP_CMPL* p_data) {
+  GATT_WRITE_OP_CB cb = p_clcb->p_q_cmd->api_write.write_cb;
+  void* my_cb_data = p_clcb->p_q_cmd->api_write.write_cb_data;
+
+  osi_free_and_reset((void**)&p_clcb->p_q_cmd);
+
+  if (cb) {
+    cb(p_clcb->bta_conn_id, p_data->status, p_data->p_cmpl->att_value.handle,
+       my_cb_data);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_exec_cmpl
+ *
+ * Description      execute write complete
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_exec_cmpl(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_OP_CMPL* p_data) {
+  tBTA_GATTC cb_data;
+
+  osi_free_and_reset((void**)&p_clcb->p_q_cmd);
+  p_clcb->status = BTA_GATT_OK;
+
+  /* execute complete, callback */
+  cb_data.exec_cmpl.conn_id = p_clcb->bta_conn_id;
+  cb_data.exec_cmpl.status = p_data->status;
+
+  (*p_clcb->p_rcb->p_cback)(BTA_GATTC_EXEC_EVT, &cb_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_cfg_mtu_cmpl
+ *
+ * Description      configure MTU operation complete
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_cfg_mtu_cmpl(tBTA_GATTC_CLCB* p_clcb,
+                            tBTA_GATTC_OP_CMPL* p_data) {
+  tBTA_GATTC cb_data;
+
+  osi_free_and_reset((void**)&p_clcb->p_q_cmd);
+
+  if (p_data->p_cmpl && p_data->status == BTA_GATT_OK)
+    p_clcb->p_srcb->mtu = p_data->p_cmpl->mtu;
+
+  /* configure MTU complete, callback */
+  p_clcb->status = p_data->status;
+  cb_data.cfg_mtu.conn_id = p_clcb->bta_conn_id;
+  cb_data.cfg_mtu.status = p_data->status;
+  cb_data.cfg_mtu.mtu = p_clcb->p_srcb->mtu;
+
+  (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CFG_MTU_EVT, &cb_data);
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_op_cmpl
+ *
+ * Description      operation completed.
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_op_cmpl(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+  uint8_t op = (uint8_t)p_data->op_cmpl.op_code;
+  uint8_t mapped_op = 0;
+
+  APPL_TRACE_DEBUG("bta_gattc_op_cmpl op = %d", op);
+
+  if (op == GATTC_OPTYPE_INDICATION || op == GATTC_OPTYPE_NOTIFICATION) {
+    APPL_TRACE_ERROR("unexpected operation, ignored");
+  } else if (op >= GATTC_OPTYPE_READ) {
+    if (p_clcb->p_q_cmd == NULL) {
+      APPL_TRACE_ERROR("No pending command");
+      return;
+    }
+    if (p_clcb->p_q_cmd->hdr.event !=
+        bta_gattc_opcode_to_int_evt[op - GATTC_OPTYPE_READ]) {
+      mapped_op = p_clcb->p_q_cmd->hdr.event - BTA_GATTC_API_READ_EVT +
+                  GATTC_OPTYPE_READ;
+      if (mapped_op > GATTC_OPTYPE_INDICATION) mapped_op = 0;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+      APPL_TRACE_ERROR(
+          "expect op:(%s :0x%04x), receive unexpected operation (%s).",
+          bta_gattc_op_code_name[mapped_op], p_clcb->p_q_cmd->hdr.event,
+          bta_gattc_op_code_name[op]);
+#else
+      APPL_TRACE_ERROR(
+          "expect op:(%u :0x%04x), receive unexpected operation (%u).",
+          mapped_op, p_clcb->p_q_cmd->hdr.event, op);
+#endif
+      return;
+    }
+
+    /* discard responses if service change indication is received before
+     * operation completed */
+    if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING &&
+        p_clcb->p_srcb->srvc_hdl_chg) {
+      APPL_TRACE_DEBUG(
+          "Discard all responses when service change indication is received.");
+      p_data->op_cmpl.status = GATT_ERROR;
+    }
+
+    /* service handle change void the response, discard it */
+    if (op == GATTC_OPTYPE_READ)
+      bta_gattc_read_cmpl(p_clcb, &p_data->op_cmpl);
+
+    else if (op == GATTC_OPTYPE_WRITE)
+      bta_gattc_write_cmpl(p_clcb, &p_data->op_cmpl);
+
+    else if (op == GATTC_OPTYPE_EXE_WRITE)
+      bta_gattc_exec_cmpl(p_clcb, &p_data->op_cmpl);
+
+    else if (op == GATTC_OPTYPE_CONFIG)
+      bta_gattc_cfg_mtu_cmpl(p_clcb, &p_data->op_cmpl);
+
+    if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING) {
+      p_clcb->auto_update = BTA_GATTC_REQ_WAITING;
+      bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL);
+    }
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_op_cmpl
+ *
+ * Description      operation completed.
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_ignore_op_cmpl(UNUSED_ATTR tBTA_GATTC_CLCB* p_clcb,
+                              tBTA_GATTC_DATA* p_data) {
+  /* receive op complete when discovery is started, ignore the response,
+      and wait for discovery finish and resent */
+  APPL_TRACE_DEBUG("bta_gattc_ignore_op_cmpl op = %d",
+                   p_data->hdr.layer_specific);
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_search
+ *
+ * Description      start a search in the local server cache
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_search(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+  tBTA_GATT_STATUS status = GATT_INTERNAL_ERROR;
+  tBTA_GATTC cb_data;
+  APPL_TRACE_DEBUG("bta_gattc_search conn_id=%d", p_clcb->bta_conn_id);
+  if (p_clcb->p_srcb && p_clcb->p_srcb->p_srvc_cache) {
+    status = BTA_GATT_OK;
+    /* search the local cache of a server device */
+    bta_gattc_search_service(p_clcb, p_data->api_search.p_srvc_uuid);
+  }
+  cb_data.search_cmpl.status = status;
+  cb_data.search_cmpl.conn_id = p_clcb->bta_conn_id;
+
+  /* end of search or no server cache available */
+  (*p_clcb->p_rcb->p_cback)(BTA_GATTC_SEARCH_CMPL_EVT, &cb_data);
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_q_cmd
+ *
+ * Description      enqueue a command into control block, usually because
+ *                  discovery operation is busy.
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_q_cmd(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+  bta_gattc_enqueue(p_clcb, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_fail
+ *
+ * Description      report API call failure back to apps
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_fail(tBTA_GATTC_CLCB* p_clcb,
+                    UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+  if (p_clcb->status == BTA_GATT_OK) {
+    APPL_TRACE_ERROR("operation not supported at current state [%d]",
+                     p_clcb->state);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_deregister_cmpl
+ *
+ * Description      De-Register a GATT client application with BTA completed.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB* p_clreg) {
+  tBTA_GATTC_IF client_if = p_clreg->client_if;
+  tBTA_GATTC cb_data;
+  tBTA_GATTC_CBACK* p_cback = p_clreg->p_cback;
+
+  memset(&cb_data, 0, sizeof(tBTA_GATTC));
+
+  GATT_Deregister(p_clreg->client_if);
+  memset(p_clreg, 0, sizeof(tBTA_GATTC_RCB));
+
+  cb_data.reg_oper.client_if = client_if;
+  cb_data.reg_oper.status = BTA_GATT_OK;
+
+  if (p_cback) /* callback with de-register event */
+    (*p_cback)(BTA_GATTC_DEREG_EVT, (tBTA_GATTC*)&cb_data);
+
+  if (bta_gattc_num_reg_app() == 0 &&
+      bta_gattc_cb.state == BTA_GATTC_STATE_DISABLING) {
+    bta_gattc_cb.state = BTA_GATTC_STATE_DISABLED;
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_conn_cback
+ *
+ * Description      callback functions to GATT client stack.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_gattc_conn_cback(tGATT_IF gattc_if, BD_ADDR bda,
+                                 uint16_t conn_id, bool connected,
+                                 tGATT_DISCONN_REASON reason,
+                                 tBT_TRANSPORT transport) {
+  if (reason != 0) {
+    APPL_TRACE_WARNING("%s() - cif=%d connected=%d conn_id=%d reason=0x%04x",
+                       __func__, gattc_if, connected, conn_id, reason);
+  }
+
+  bt_bdaddr_t bdaddr;
+  bdcpy(bdaddr.address, bda);
+  if (connected)
+    btif_debug_conn_state(bdaddr, BTIF_DEBUG_CONNECTED, GATT_CONN_UNKNOWN);
+  else
+    btif_debug_conn_state(bdaddr, BTIF_DEBUG_DISCONNECTED, reason);
+
+  tBTA_GATTC_DATA* p_buf =
+      (tBTA_GATTC_DATA*)osi_calloc(sizeof(tBTA_GATTC_DATA));
+  p_buf->int_conn.hdr.event =
+      connected ? BTA_GATTC_INT_CONN_EVT : BTA_GATTC_INT_DISCONN_EVT;
+  p_buf->int_conn.hdr.layer_specific = conn_id;
+  p_buf->int_conn.client_if = gattc_if;
+  p_buf->int_conn.role = L2CA_GetBleConnRole(bda);
+  p_buf->int_conn.reason = reason;
+  p_buf->int_conn.transport = transport;
+  bdcpy(p_buf->int_conn.remote_bda, bda);
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_enc_cmpl_cback
+ *
+ * Description      encryption complete callback function to GATT client stack.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_gattc_enc_cmpl_cback(tGATT_IF gattc_if, BD_ADDR bda) {
+  tBTA_GATTC_CLCB* p_clcb =
+      bta_gattc_find_clcb_by_cif(gattc_if, bda, BTA_GATT_TRANSPORT_LE);
+
+  if (p_clcb == NULL) return;
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+  /* filter this event just for BTA HH LE GATT client,
+     In the future, if we want to enable encryption complete event
+     for all GATT clients, we can remove this code */
+  if (!bta_hh_le_is_hh_gatt_if(gattc_if)) {
+    return;
+  }
+#endif
+
+  APPL_TRACE_DEBUG("%s: cif = %d", __func__, gattc_if);
+
+  tBTA_GATTC_DATA* p_buf =
+      (tBTA_GATTC_DATA*)osi_calloc(sizeof(tBTA_GATTC_DATA));
+  p_buf->enc_cmpl.hdr.event = BTA_GATTC_ENC_CMPL_EVT;
+  p_buf->enc_cmpl.hdr.layer_specific = p_clcb->bta_conn_id;
+  p_buf->enc_cmpl.client_if = gattc_if;
+  bdcpy(p_buf->enc_cmpl.remote_bda, bda);
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_process_api_refresh
+ *
+ * Description      process refresh API to delete cache and start a new
+ *                  discovery if currently connected.
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_process_api_refresh(tBTA_GATTC_DATA* p_msg) {
+  tBTA_GATTC_SERV* p_srvc_cb =
+      bta_gattc_find_srvr_cache(p_msg->api_conn.remote_bda);
+  tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[0];
+  bool found = false;
+  uint8_t i;
+
+  if (p_srvc_cb != NULL) {
+    /* try to find a CLCB */
+    if (p_srvc_cb->connected && p_srvc_cb->num_clcb != 0) {
+      for (i = 0; i < BTA_GATTC_CLCB_MAX; i++, p_clcb++) {
+        if (p_clcb->in_use && p_clcb->p_srcb == p_srvc_cb) {
+          found = true;
+          break;
+        }
+      }
+      if (found) {
+        bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL);
+        return;
+      }
+    }
+    /* in all other cases, mark it and delete the cache */
+    if (p_srvc_cb->p_srvc_cache != NULL) {
+      list_free(p_srvc_cb->p_srvc_cache);
+      p_srvc_cb->p_srvc_cache = NULL;
+    }
+  }
+  /* used to reset cache in application */
+  bta_gattc_cache_reset(p_msg->api_conn.remote_bda);
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_process_srvc_chg_ind
+ *
+ * Description      process service change indication.
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+bool bta_gattc_process_srvc_chg_ind(uint16_t conn_id, tBTA_GATTC_RCB* p_clrcb,
+                                    tBTA_GATTC_SERV* p_srcb,
+                                    tBTA_GATTC_CLCB* p_clcb,
+                                    tBTA_GATTC_NOTIFY* p_notify,
+                                    tGATT_VALUE* att_value) {
+  tBT_UUID gattp_uuid, srvc_chg_uuid;
+  bool processed = false;
+  uint8_t i;
+
+  gattp_uuid.len = 2;
+  gattp_uuid.uu.uuid16 = UUID_SERVCLASS_GATT_SERVER;
+
+  srvc_chg_uuid.len = 2;
+  srvc_chg_uuid.uu.uuid16 = GATT_UUID_GATT_SRV_CHGD;
+
+  const tBTA_GATTC_CHARACTERISTIC* p_char =
+      bta_gattc_get_characteristic_srcb(p_srcb, p_notify->handle);
+  if (p_char &&
+      bta_gattc_uuid_compare(&p_char->service->uuid, &gattp_uuid, true) &&
+      bta_gattc_uuid_compare(&p_char->uuid, &srvc_chg_uuid, true)) {
+    if (att_value->len != BTA_GATTC_SERVICE_CHANGED_LEN) {
+      APPL_TRACE_ERROR(
+          "%s: received malformed service changed indication, skipping",
+          __func__);
+      return false;
+    }
+
+    uint8_t* p = att_value->value;
+    uint16_t s_handle = ((uint16_t)(*(p)) + (((uint16_t)(*(p + 1))) << 8));
+    uint16_t e_handle = ((uint16_t)(*(p + 2)) + (((uint16_t)(*(p + 3))) << 8));
+
+    APPL_TRACE_ERROR("%s: service changed s_handle:0x%04x e_handle:0x%04x",
+                     __func__, s_handle, e_handle);
+
+    processed = true;
+    /* mark service handle change pending */
+    p_srcb->srvc_hdl_chg = true;
+    /* clear up all notification/indication registration */
+    bta_gattc_clear_notif_registration(p_srcb, conn_id, s_handle, e_handle);
+    /* service change indication all received, do discovery update */
+    if (++p_srcb->update_count == bta_gattc_num_reg_app()) {
+      /* not an opened connection; or connection busy */
+      /* search for first available clcb and start discovery */
+      if (p_clcb == NULL || (p_clcb && p_clcb->p_q_cmd != NULL)) {
+        for (i = 0; i < BTA_GATTC_CLCB_MAX; i++) {
+          if (bta_gattc_cb.clcb[i].in_use &&
+              bta_gattc_cb.clcb[i].p_srcb == p_srcb &&
+              bta_gattc_cb.clcb[i].p_q_cmd == NULL) {
+            p_clcb = &bta_gattc_cb.clcb[i];
+            break;
+          }
+        }
+      }
+      /* send confirmation here if this is an indication, it should always be */
+      GATTC_SendHandleValueConfirm(conn_id, att_value->handle);
+
+      /* if connection available, refresh cache by doing discovery now */
+      if (p_clcb != NULL)
+        bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL);
+    }
+    /* notify applicationf or service change */
+    if (p_clrcb->p_cback != NULL) {
+      (*p_clrcb->p_cback)(BTA_GATTC_SRVC_CHG_EVT,
+                          (tBTA_GATTC*)p_srcb->server_bda);
+    }
+  }
+
+  return processed;
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_proc_other_indication
+ *
+ * Description      process all non-service change indication/notification.
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_proc_other_indication(tBTA_GATTC_CLCB* p_clcb, uint8_t op,
+                                     tGATT_CL_COMPLETE* p_data,
+                                     tBTA_GATTC_NOTIFY* p_notify) {
+  APPL_TRACE_DEBUG(
+      "bta_gattc_proc_other_indication check \
+                       p_data->att_value.handle=%d p_data->handle=%d",
+      p_data->att_value.handle, p_data->handle);
+  APPL_TRACE_DEBUG("is_notify", p_notify->is_notify);
+
+  p_notify->is_notify = (op == GATTC_OPTYPE_INDICATION) ? false : true;
+  p_notify->len = p_data->att_value.len;
+  bdcpy(p_notify->bda, p_clcb->bda);
+  memcpy(p_notify->value, p_data->att_value.value, p_data->att_value.len);
+  p_notify->conn_id = p_clcb->bta_conn_id;
+
+  if (p_clcb->p_rcb->p_cback)
+    (*p_clcb->p_rcb->p_cback)(BTA_GATTC_NOTIF_EVT, (tBTA_GATTC*)p_notify);
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_process_indicate
+ *
+ * Description      process indication/notification.
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_process_indicate(uint16_t conn_id, tGATTC_OPTYPE op,
+                                tGATT_CL_COMPLETE* p_data) {
+  uint16_t handle = p_data->att_value.handle;
+  tBTA_GATTC_CLCB* p_clcb;
+  tBTA_GATTC_RCB* p_clrcb = NULL;
+  tBTA_GATTC_SERV* p_srcb = NULL;
+  tBTA_GATTC_NOTIFY notify;
+  BD_ADDR remote_bda;
+  tBTA_GATTC_IF gatt_if;
+  tBTA_TRANSPORT transport;
+
+  if (!GATT_GetConnectionInfor(conn_id, &gatt_if, remote_bda, &transport)) {
+    APPL_TRACE_ERROR("%s indication/notif for unknown app", __func__);
+    if (op == GATTC_OPTYPE_INDICATION)
+      GATTC_SendHandleValueConfirm(conn_id, handle);
+    return;
+  }
+
+  if ((p_clrcb = bta_gattc_cl_get_regcb(gatt_if)) == NULL) {
+    APPL_TRACE_ERROR("%s indication/notif for unregistered app", __func__);
+    if (op == GATTC_OPTYPE_INDICATION)
+      GATTC_SendHandleValueConfirm(conn_id, handle);
+    return;
+  }
+
+  if ((p_srcb = bta_gattc_find_srcb(remote_bda)) == NULL) {
+    APPL_TRACE_ERROR("%s indication/notif for unknown device, ignore",
+                     __func__);
+    if (op == GATTC_OPTYPE_INDICATION)
+      GATTC_SendHandleValueConfirm(conn_id, handle);
+    return;
+  }
+
+  p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+
+  notify.handle = handle;
+  /* if non-service change indication/notification, forward to application */
+  if (!bta_gattc_process_srvc_chg_ind(conn_id, p_clrcb, p_srcb, p_clcb, &notify,
+                                      &p_data->att_value)) {
+    /* if app registered for the notification */
+    if (bta_gattc_check_notif_registry(p_clrcb, p_srcb, &notify)) {
+      /* connection not open yet */
+      if (p_clcb == NULL) {
+        p_clcb = bta_gattc_clcb_alloc(gatt_if, remote_bda, transport);
+
+        if (p_clcb == NULL) {
+          APPL_TRACE_ERROR("No resources");
+          return;
+        }
+
+        p_clcb->bta_conn_id = conn_id;
+        p_clcb->transport = transport;
+
+        bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, NULL);
+      }
+
+      if (p_clcb != NULL)
+        bta_gattc_proc_other_indication(p_clcb, op, p_data, &notify);
+    }
+    /* no one intersted and need ack? */
+    else if (op == GATTC_OPTYPE_INDICATION) {
+      APPL_TRACE_DEBUG("%s no one interested, ack now", __func__);
+      GATTC_SendHandleValueConfirm(conn_id, handle);
+    }
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_cmpl_cback
+ *
+ * Description      client operation complete callback register with BTE GATT.
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+static void bta_gattc_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op,
+                                 tGATT_STATUS status,
+                                 tGATT_CL_COMPLETE* p_data) {
+  tBTA_GATTC_CLCB* p_clcb;
+  APPL_TRACE_DEBUG("bta_gattc_cmpl_cback: conn_id = %d op = %d status = %d",
+                   conn_id, op, status);
+
+  /* notification and indication processed right away */
+  if (op == GATTC_OPTYPE_NOTIFICATION || op == GATTC_OPTYPE_INDICATION) {
+    bta_gattc_process_indicate(conn_id, op, p_data);
+    return;
+  }
+  /* for all other operation, not expected if w/o connection */
+  else if ((p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id)) == NULL) {
+    APPL_TRACE_ERROR("bta_gattc_cmpl_cback unknown conn_id =  %d, ignore data",
+                     conn_id);
+    return;
+  }
+
+  /* if over BR_EDR, inform PM for mode change */
+  if (p_clcb->transport == BTA_TRANSPORT_BR_EDR) {
+    bta_sys_busy(BTA_ID_GATTC, BTA_ALL_APP_ID, p_clcb->bda);
+    bta_sys_idle(BTA_ID_GATTC, BTA_ALL_APP_ID, p_clcb->bda);
+  }
+
+  bta_gattc_cmpl_sendmsg(conn_id, op, status, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_cmpl_sendmsg
+ *
+ * Description      client operation complete send message
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+static void bta_gattc_cmpl_sendmsg(uint16_t conn_id, tGATTC_OPTYPE op,
+                                   tBTA_GATT_STATUS status,
+                                   tGATT_CL_COMPLETE* p_data) {
+  const size_t len = sizeof(tBTA_GATTC_OP_CMPL) + sizeof(tGATT_CL_COMPLETE);
+  tBTA_GATTC_OP_CMPL* p_buf = (tBTA_GATTC_OP_CMPL*)osi_calloc(len);
+
+  p_buf->hdr.event = BTA_GATTC_OP_CMPL_EVT;
+  p_buf->hdr.layer_specific = conn_id;
+  p_buf->status = status;
+  p_buf->op_code = op;
+
+  if (p_data != NULL) {
+    p_buf->p_cmpl = (tGATT_CL_COMPLETE*)(p_buf + 1);
+    memcpy(p_buf->p_cmpl, p_data, sizeof(tGATT_CL_COMPLETE));
+  }
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_cong_cback
+ *
+ * Description      congestion callback for BTA GATT client.
+ *
+ * Returns          void
+ *
+ *******************************************************************************/
+static void bta_gattc_cong_cback(uint16_t conn_id, bool congested) {
+  tBTA_GATTC_CLCB* p_clcb;
+  tBTA_GATTC cb_data;
+
+  if ((p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id)) != NULL) {
+    if (p_clcb->p_rcb->p_cback) {
+      cb_data.congest.conn_id = conn_id;
+      cb_data.congest.congested = congested;
+
+      (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CONGEST_EVT, &cb_data);
+    }
+  }
+}
+#endif  // BTA_GATT_INCLUDED == TRUE && BLE_INCLUDED == TRUE
diff --git a/bt/bta/gatt/bta_gattc_api.cc b/bt/bta/gatt/bta_gattc_api.cc
new file mode 100644
index 0000000..0f1d8c6
--- /dev/null
+++ b/bt/bta/gatt/bta_gattc_api.cc
@@ -0,0 +1,707 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2010-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 is the implementation of the API for GATT module of BTA.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if (BTA_GATT_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include <base/callback.h>
+#include "bt_common.h"
+#include "bta_gatt_api.h"
+#include "bta_gattc_int.h"
+#include "bta_sys.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_gattc_reg = {bta_gattc_hdl_event,
+                                           BTA_GATTC_Disable};
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_Disable
+ *
+ * Description      This function is called to disable GATTC module
+ *
+ * Parameters       None.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_GATTC_Disable(void) {
+  if (bta_sys_is_register(BTA_ID_GATTC) == false) {
+    APPL_TRACE_WARNING("GATTC Module not enabled/already disabled");
+    return;
+  }
+
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+  p_buf->event = BTA_GATTC_API_DISABLE_EVT;
+
+  bta_sys_sendmsg(p_buf);
+  bta_sys_deregister(BTA_ID_GATTC);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_AppRegister
+ *
+ * Description      This function is called to register application callbacks
+ *                    with BTA GATTC module.
+ *
+ * Parameters       p_app_uuid - applicaiton UUID
+ *                  p_client_cb - pointer to the application callback function.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_GATTC_AppRegister(tBT_UUID* p_app_uuid,
+                           tBTA_GATTC_CBACK* p_client_cb) {
+  tBTA_GATTC_API_REG* p_buf =
+      (tBTA_GATTC_API_REG*)osi_malloc(sizeof(tBTA_GATTC_API_REG));
+
+  if (bta_sys_is_register(BTA_ID_GATTC) == false)
+    bta_sys_register(BTA_ID_GATTC, &bta_gattc_reg);
+
+  p_buf->hdr.event = BTA_GATTC_API_REG_EVT;
+  if (p_app_uuid != NULL)
+    memcpy(&p_buf->app_uuid, p_app_uuid, sizeof(tBT_UUID));
+  p_buf->p_cback = p_client_cb;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_AppDeregister
+ *
+ * Description      This function is called to deregister an application
+ *                  from BTA GATTC module.
+ *
+ * Parameters       client_if - client interface identifier.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_GATTC_AppDeregister(tBTA_GATTC_IF client_if) {
+  tBTA_GATTC_API_DEREG* p_buf =
+      (tBTA_GATTC_API_DEREG*)osi_malloc(sizeof(tBTA_GATTC_API_DEREG));
+
+  p_buf->hdr.event = BTA_GATTC_API_DEREG_EVT;
+  p_buf->client_if = client_if;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_Open
+ *
+ * Description      Open a direct connection or add a background auto connection
+ *                  bd address
+ *
+ * Parameters       client_if: server interface.
+ *                  remote_bda: remote device BD address.
+ *                  is_direct: direct connection or background auto connection
+ *                  transport: Transport to be used for GATT connection
+ *                             (BREDR/LE)
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_GATTC_Open(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, bool is_direct,
+                    tBTA_GATT_TRANSPORT transport) {
+  tBTA_GATTC_API_OPEN* p_buf =
+      (tBTA_GATTC_API_OPEN*)osi_malloc(sizeof(tBTA_GATTC_API_OPEN));
+
+  p_buf->hdr.event = BTA_GATTC_API_OPEN_EVT;
+  p_buf->client_if = client_if;
+  p_buf->is_direct = is_direct;
+  p_buf->transport = transport;
+  memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN);
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_CancelOpen
+ *
+ * Description      Cancel a direct open connection or remove a background auto
+ *                  connection
+ *                  bd address
+ *
+ * Parameters       client_if: server interface.
+ *                  remote_bda: remote device BD address.
+ *                  is_direct: direct connection or background auto connection
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_GATTC_CancelOpen(tBTA_GATTC_IF client_if, BD_ADDR remote_bda,
+                          bool is_direct) {
+  tBTA_GATTC_API_CANCEL_OPEN* p_buf = (tBTA_GATTC_API_CANCEL_OPEN*)osi_malloc(
+      sizeof(tBTA_GATTC_API_CANCEL_OPEN));
+
+  p_buf->hdr.event = BTA_GATTC_API_CANCEL_OPEN_EVT;
+  p_buf->client_if = client_if;
+  p_buf->is_direct = is_direct;
+  memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN);
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_Close
+ *
+ * Description      Close a connection to a GATT server.
+ *
+ * Parameters       conn_id: connectino ID to be closed.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_GATTC_Close(uint16_t conn_id) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = BTA_GATTC_API_CLOSE_EVT;
+  p_buf->layer_specific = conn_id;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_ConfigureMTU
+ *
+ * Description      Configure the MTU size in the GATT channel. This can be done
+ *                  only once per connection.
+ *
+ * Parameters       conn_id: connection ID.
+ *                  mtu: desired MTU size to use.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_GATTC_ConfigureMTU(uint16_t conn_id, uint16_t mtu) {
+  tBTA_GATTC_API_CFG_MTU* p_buf =
+      (tBTA_GATTC_API_CFG_MTU*)osi_malloc(sizeof(tBTA_GATTC_API_CFG_MTU));
+
+  p_buf->hdr.event = BTA_GATTC_API_CFG_MTU_EVT;
+  p_buf->hdr.layer_specific = conn_id;
+  p_buf->mtu = mtu;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_ServiceSearchRequest
+ *
+ * Description      This function is called to request a GATT service discovery
+ *                  on a GATT server. This function report service search
+ *                  result by a callback event, and followed by a service search
+ *                  complete event.
+ *
+ * Parameters       conn_id: connection ID.
+ *                  p_srvc_uuid: a UUID of the service application is interested
+ *                               in.
+ *                              If Null, discover for all services.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_GATTC_ServiceSearchRequest(uint16_t conn_id, tBT_UUID* p_srvc_uuid) {
+  const size_t len = sizeof(tBTA_GATTC_API_SEARCH) + sizeof(tBT_UUID);
+  tBTA_GATTC_API_SEARCH* p_buf = (tBTA_GATTC_API_SEARCH*)osi_calloc(len);
+
+  p_buf->hdr.event = BTA_GATTC_API_SEARCH_EVT;
+  p_buf->hdr.layer_specific = conn_id;
+  if (p_srvc_uuid) {
+    p_buf->p_srvc_uuid = (tBT_UUID*)(p_buf + 1);
+    memcpy(p_buf->p_srvc_uuid, p_srvc_uuid, sizeof(tBT_UUID));
+  } else {
+    p_buf->p_srvc_uuid = NULL;
+  }
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_GetServices
+ *
+ * Description      This function is called to find the services on the given
+ *                  server.
+ *
+ * Parameters       conn_id: connection ID which identify the server.
+ *
+ * Returns          returns list_t of tBTA_GATTC_SERVICE or NULL.
+ *
+ ******************************************************************************/
+const list_t* BTA_GATTC_GetServices(uint16_t conn_id) {
+  return bta_gattc_get_services(conn_id);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_GetCharacteristic
+ *
+ * Description      This function is called to find the characteristic on the
+ *                  given server.
+ *
+ * Parameters       conn_id - connection ID which identify the server.
+ *                  handle - characteristic handle
+ *
+ * Returns          returns pointer to tBTA_GATTC_CHARACTERISTIC or NULL.
+ *
+ ******************************************************************************/
+const tBTA_GATTC_CHARACTERISTIC* BTA_GATTC_GetCharacteristic(uint16_t conn_id,
+                                                             uint16_t handle) {
+  return bta_gattc_get_characteristic(conn_id, handle);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_GetDescriptor
+ *
+ * Description      This function is called to find the characteristic on the
+ *                  given server.
+ *
+ * Parameters       conn_id - connection ID which identify the server.
+ *                  handle - descriptor handle
+ *
+ * Returns          returns pointer to tBTA_GATTC_DESCRIPTOR or NULL.
+ *
+ ******************************************************************************/
+const tBTA_GATTC_DESCRIPTOR* BTA_GATTC_GetDescriptor(uint16_t conn_id,
+                                                     uint16_t handle) {
+  return bta_gattc_get_descriptor(conn_id, handle);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_GetGattDb
+ *
+ * Description      This function is called to get the GATT database.
+ *
+ * Parameters       conn_id: connection ID which identify the server.
+ *                  db: output parameter which will contain the GATT database
+ *                      copy. Caller is responsible for freeing it.
+ *                  count: number of elements in database.
+ *
+ ******************************************************************************/
+void BTA_GATTC_GetGattDb(uint16_t conn_id, uint16_t start_handle,
+                         uint16_t end_handle, btgatt_db_element_t** db,
+                         int* count) {
+  bta_gattc_get_gatt_db(conn_id, start_handle, end_handle, db, count);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_ReadCharacteristic
+ *
+ * Description      This function is called to read a characteristics value
+ *
+ * Parameters       conn_id - connection ID.
+ *                  handle - characteritic handle to read.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_GATTC_ReadCharacteristic(uint16_t conn_id, uint16_t handle,
+                                  tBTA_GATT_AUTH_REQ auth_req,
+                                  GATT_READ_OP_CB callback, void* cb_data) {
+  tBTA_GATTC_API_READ* p_buf =
+      (tBTA_GATTC_API_READ*)osi_calloc(sizeof(tBTA_GATTC_API_READ));
+
+  p_buf->hdr.event = BTA_GATTC_API_READ_EVT;
+  p_buf->hdr.layer_specific = conn_id;
+  p_buf->auth_req = auth_req;
+  p_buf->handle = handle;
+  p_buf->read_cb = callback;
+  p_buf->read_cb_data = cb_data;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_ReadCharDescr
+ *
+ * Description      This function is called to read a descriptor value.
+ *
+ * Parameters       conn_id - connection ID.
+ *                  handle - descriptor handle to read.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_GATTC_ReadCharDescr(uint16_t conn_id, uint16_t handle,
+                             tBTA_GATT_AUTH_REQ auth_req,
+                             GATT_READ_OP_CB callback, void* cb_data) {
+  tBTA_GATTC_API_READ* p_buf =
+      (tBTA_GATTC_API_READ*)osi_calloc(sizeof(tBTA_GATTC_API_READ));
+
+  p_buf->hdr.event = BTA_GATTC_API_READ_EVT;
+  p_buf->hdr.layer_specific = conn_id;
+  p_buf->auth_req = auth_req;
+  p_buf->handle = handle;
+  p_buf->read_cb = callback;
+  p_buf->read_cb_data = cb_data;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_ReadMultiple
+ *
+ * Description      This function is called to read multiple characteristic or
+ *                  characteristic descriptors.
+ *
+ * Parameters       conn_id - connectino ID.
+ *                    p_read_multi - pointer to the read multiple parameter.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_GATTC_ReadMultiple(uint16_t conn_id, tBTA_GATTC_MULTI* p_read_multi,
+                            tBTA_GATT_AUTH_REQ auth_req) {
+  tBTA_GATTC_API_READ_MULTI* p_buf =
+      (tBTA_GATTC_API_READ_MULTI*)osi_calloc(sizeof(tBTA_GATTC_API_READ_MULTI));
+
+  p_buf->hdr.event = BTA_GATTC_API_READ_MULTI_EVT;
+  p_buf->hdr.layer_specific = conn_id;
+  p_buf->auth_req = auth_req;
+  p_buf->num_attr = p_read_multi->num_attr;
+
+  if (p_buf->num_attr > 0)
+    memcpy(p_buf->handles, p_read_multi->handles,
+           sizeof(uint16_t) * p_read_multi->num_attr);
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_WriteCharValue
+ *
+ * Description      This function is called to write characteristic value.
+ *
+ * Parameters       conn_id - connection ID.
+ *                  handle - characteristic handle to write.
+ *                  write_type - type of write.
+ *                  value - the value to be written.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_GATTC_WriteCharValue(uint16_t conn_id, uint16_t handle,
+                              tBTA_GATTC_WRITE_TYPE write_type,
+                              std::vector<uint8_t> value,
+                              tBTA_GATT_AUTH_REQ auth_req,
+                              GATT_WRITE_OP_CB callback, void* cb_data) {
+  tBTA_GATTC_API_WRITE* p_buf = (tBTA_GATTC_API_WRITE*)osi_calloc(
+      sizeof(tBTA_GATTC_API_WRITE) + value.size());
+
+  p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT;
+  p_buf->hdr.layer_specific = conn_id;
+  p_buf->auth_req = auth_req;
+  p_buf->handle = handle;
+  p_buf->write_type = write_type;
+  p_buf->len = value.size();
+  p_buf->write_cb = callback;
+  p_buf->write_cb_data = cb_data;
+
+  if (value.size() > 0) {
+    p_buf->p_value = (uint8_t*)(p_buf + 1);
+    memcpy(p_buf->p_value, value.data(), value.size());
+  }
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_WriteCharDescr
+ *
+ * Description      This function is called to write descriptor value.
+ *
+ * Parameters       conn_id - connection ID
+ *                  handle - descriptor hadle to write.
+ *                  value - the value to be written.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_GATTC_WriteCharDescr(uint16_t conn_id, uint16_t handle,
+                              std::vector<uint8_t> value,
+                              tBTA_GATT_AUTH_REQ auth_req,
+                              GATT_WRITE_OP_CB callback, void* cb_data) {
+  tBTA_GATTC_API_WRITE* p_buf = (tBTA_GATTC_API_WRITE*)osi_calloc(
+      sizeof(tBTA_GATTC_API_WRITE) + value.size());
+
+  p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT;
+  p_buf->hdr.layer_specific = conn_id;
+  p_buf->auth_req = auth_req;
+  p_buf->handle = handle;
+  p_buf->write_type = BTA_GATTC_TYPE_WRITE;
+  p_buf->write_cb = callback;
+  p_buf->write_cb_data = cb_data;
+
+  if (value.size() != 0) {
+    p_buf->p_value = (uint8_t*)(p_buf + 1);
+    p_buf->len = value.size();
+    memcpy(p_buf->p_value, value.data(), value.size());
+  }
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_PrepareWrite
+ *
+ * Description      This function is called to prepare write a characteristic
+ *                  value.
+ *
+ * Parameters       conn_id - connection ID.
+ *                  p_char_id - GATT characteritic ID of the service.
+ *                  offset - offset of the write value.
+ *                  value - the value to be written.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_GATTC_PrepareWrite(uint16_t conn_id, uint16_t handle, uint16_t offset,
+                            std::vector<uint8_t> value,
+                            tBTA_GATT_AUTH_REQ auth_req,
+                            GATT_WRITE_OP_CB callback, void* cb_data) {
+  tBTA_GATTC_API_WRITE* p_buf = (tBTA_GATTC_API_WRITE*)osi_calloc(
+      sizeof(tBTA_GATTC_API_WRITE) + value.size());
+
+  p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT;
+  p_buf->hdr.layer_specific = conn_id;
+  p_buf->auth_req = auth_req;
+  p_buf->handle = handle;
+  p_buf->write_cb = callback;
+  p_buf->write_cb_data = cb_data;
+
+  p_buf->write_type = BTA_GATTC_WRITE_PREPARE;
+  p_buf->offset = offset;
+  p_buf->len = value.size();
+
+  if (value.size() > 0) {
+    p_buf->p_value = (uint8_t*)(p_buf + 1);
+    memcpy(p_buf->p_value, value.data(), value.size());
+  }
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_ExecuteWrite
+ *
+ * Description      This function is called to execute write a prepare write
+ *                  sequence.
+ *
+ * Parameters       conn_id - connection ID.
+ *                    is_execute - execute or cancel.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_GATTC_ExecuteWrite(uint16_t conn_id, bool is_execute) {
+  tBTA_GATTC_API_EXEC* p_buf =
+      (tBTA_GATTC_API_EXEC*)osi_calloc(sizeof(tBTA_GATTC_API_EXEC));
+
+  p_buf->hdr.event = BTA_GATTC_API_EXEC_EVT;
+  p_buf->hdr.layer_specific = conn_id;
+  p_buf->is_execute = is_execute;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_SendIndConfirm
+ *
+ * Description      This function is called to send handle value confirmation.
+ *
+ * Parameters       conn_id - connection ID.
+ *                    p_char_id - characteristic ID to confirm.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_GATTC_SendIndConfirm(uint16_t conn_id, uint16_t handle) {
+  tBTA_GATTC_API_CONFIRM* p_buf =
+      (tBTA_GATTC_API_CONFIRM*)osi_calloc(sizeof(tBTA_GATTC_API_CONFIRM));
+
+  APPL_TRACE_API("%s conn_id=%d handle=0x%04x", __func__, conn_id, handle);
+
+  p_buf->hdr.event = BTA_GATTC_API_CONFIRM_EVT;
+  p_buf->hdr.layer_specific = conn_id;
+  p_buf->handle = handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_RegisterForNotifications
+ *
+ * Description      This function is called to register for notification of a
+ *                  service.
+ *
+ * Parameters       client_if - client interface.
+ *                  bda - target GATT server.
+ *                  handle - GATT characteristic handle.
+ *
+ * Returns          OK if registration succeed, otherwise failed.
+ *
+ ******************************************************************************/
+tBTA_GATT_STATUS BTA_GATTC_RegisterForNotifications(tBTA_GATTC_IF client_if,
+                                                    const BD_ADDR bda,
+                                                    uint16_t handle) {
+  tBTA_GATTC_RCB* p_clreg;
+  tBTA_GATT_STATUS status = BTA_GATT_ILLEGAL_PARAMETER;
+  uint8_t i;
+
+  if (!handle) {
+    APPL_TRACE_ERROR("deregistration failed, handle is 0");
+    return status;
+  }
+
+  if ((p_clreg = bta_gattc_cl_get_regcb(client_if)) != NULL) {
+    for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i++) {
+      if (p_clreg->notif_reg[i].in_use &&
+          !memcmp(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN) &&
+          p_clreg->notif_reg[i].handle == handle) {
+        APPL_TRACE_WARNING("notification already registered");
+        status = BTA_GATT_OK;
+        break;
+      }
+    }
+    if (status != BTA_GATT_OK) {
+      for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i++) {
+        if (!p_clreg->notif_reg[i].in_use) {
+          memset((void*)&p_clreg->notif_reg[i], 0,
+                 sizeof(tBTA_GATTC_NOTIF_REG));
+
+          p_clreg->notif_reg[i].in_use = true;
+          memcpy(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN);
+
+          p_clreg->notif_reg[i].handle = handle;
+          status = BTA_GATT_OK;
+          break;
+        }
+      }
+      if (i == BTA_GATTC_NOTIF_REG_MAX) {
+        status = BTA_GATT_NO_RESOURCES;
+        APPL_TRACE_ERROR("Max Notification Reached, registration failed.");
+      }
+    }
+  } else {
+    APPL_TRACE_ERROR("Client_if: %d Not Registered", client_if);
+  }
+
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_DeregisterForNotifications
+ *
+ * Description      This function is called to de-register for notification of a
+ *                  service.
+ *
+ * Parameters       client_if - client interface.
+ *                  remote_bda - target GATT server.
+ *                  handle - GATT characteristic handle.
+ *
+ * Returns          OK if deregistration succeed, otherwise failed.
+ *
+ ******************************************************************************/
+tBTA_GATT_STATUS BTA_GATTC_DeregisterForNotifications(tBTA_GATTC_IF client_if,
+                                                      const BD_ADDR bda,
+                                                      uint16_t handle) {
+  if (!handle) {
+    APPL_TRACE_ERROR("%s: deregistration failed, handle is 0", __func__);
+    return BTA_GATT_ILLEGAL_PARAMETER;
+  }
+
+  tBTA_GATTC_RCB* p_clreg = bta_gattc_cl_get_regcb(client_if);
+  if (p_clreg == NULL) {
+    APPL_TRACE_ERROR(
+        "%s client_if: %d not registered bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
+        __func__, client_if, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+    return BTA_GATT_ILLEGAL_PARAMETER;
+  }
+
+  for (int i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i++) {
+    if (p_clreg->notif_reg[i].in_use &&
+        !memcmp(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN) &&
+        p_clreg->notif_reg[i].handle == handle) {
+      APPL_TRACE_DEBUG("%s deregistered bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
+                       __func__, bda[0], bda[1], bda[2], bda[3], bda[4],
+                       bda[5]);
+      memset(&p_clreg->notif_reg[i], 0, sizeof(tBTA_GATTC_NOTIF_REG));
+      return BTA_GATT_OK;
+    }
+  }
+
+  APPL_TRACE_ERROR(
+      "%s registration not found bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
+      __func__, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+  return BTA_GATT_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_Refresh
+ *
+ * Description      Refresh the server cache of the remote device
+ *
+ * Parameters       remote_bda: remote device BD address.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_GATTC_Refresh(const BD_ADDR remote_bda) {
+  tBTA_GATTC_API_OPEN* p_buf =
+      (tBTA_GATTC_API_OPEN*)osi_malloc(sizeof(tBTA_GATTC_API_OPEN));
+
+  p_buf->hdr.event = BTA_GATTC_API_REFRESH_EVT;
+  memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN);
+
+  bta_sys_sendmsg(p_buf);
+}
+
+#endif /* BTA_GATT_INCLUDED */
diff --git a/bt/bta/gatt/bta_gattc_cache.cc b/bt/bta/gatt/bta_gattc_cache.cc
new file mode 100644
index 0000000..76d0200
--- /dev/null
+++ b/bt/bta/gatt/bta_gattc_cache.cc
@@ -0,0 +1,1546 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 GATT client discovery procedures and cache
+ *  related functions.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bta_gattc"
+
+#include "bt_target.h"
+
+#if (BTA_GATT_INCLUDED == TRUE)
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "bt_common.h"
+#include "bta_gattc_int.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+#include "btm_ble_api.h"
+#include "btm_int.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "sdp_api.h"
+#include "sdpdefs.h"
+#include "utl.h"
+
+static void bta_gattc_cache_write(BD_ADDR server_bda, uint16_t num_attr,
+                                  tBTA_GATTC_NV_ATTR* attr);
+static void bta_gattc_char_dscpt_disc_cmpl(uint16_t conn_id,
+                                           tBTA_GATTC_SERV* p_srvc_cb);
+static tBTA_GATT_STATUS bta_gattc_sdp_service_disc(
+    uint16_t conn_id, tBTA_GATTC_SERV* p_server_cb);
+extern void bta_to_btif_uuid(bt_uuid_t* p_dest, tBT_UUID* p_src);
+tBTA_GATTC_SERVICE* bta_gattc_find_matching_service(const list_t* services,
+                                                    uint16_t handle);
+tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor_srcb(tBTA_GATTC_SERV* p_srcb,
+                                                     uint16_t handle);
+tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic_srcb(
+    tBTA_GATTC_SERV* p_srcb, uint16_t handle);
+
+#define BTA_GATT_SDP_DB_SIZE 4096
+
+#define GATT_CACHE_PREFIX "/data/misc/bluetooth/gatt_cache_"
+#define GATT_CACHE_VERSION 2
+
+static void bta_gattc_generate_cache_file_name(char* buffer, size_t buffer_len,
+                                               BD_ADDR bda) {
+  snprintf(buffer, buffer_len, "%s%02x%02x%02x%02x%02x%02x", GATT_CACHE_PREFIX,
+           bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+}
+
+/*****************************************************************************
+ *  Constants and data types
+ ****************************************************************************/
+
+typedef struct {
+  tSDP_DISCOVERY_DB* p_sdp_db;
+  uint16_t sdp_conn_id;
+} tBTA_GATTC_CB_DATA;
+
+#if (BTA_GATT_DEBUG == TRUE)
+static char* bta_gattc_attr_type[] = {
+    "I", /* Included Service */
+    "C", /* Characteristic */
+    "D"  /* Characteristic Descriptor */
+};
+/* utility functions */
+
+bool display_cache_attribute(void* data, void* context) {
+  tBTA_GATTC_CACHE_ATTR* p_attr = data;
+  APPL_TRACE_ERROR("\t Attr handle[%d] uuid[0x%04x] type[%s] prop[0x%1x]",
+                   p_attr->handle, p_attr->uuid.uu.uuid16,
+                   bta_gattc_attr_type[p_attr->attr_type], p_attr->property);
+  return true;
+}
+
+bool display_cache_service(void* data, void* context) {
+  tBTA_GATTC_SERVICE* p_cur_srvc = data;
+  APPL_TRACE_ERROR("Service: handle[%d ~ %d] %s[0x%04x] inst[%d]",
+                   p_cur_srvc->s_handle, p_cur_srvc->e_handle,
+                   ((p_cur_srvc->uuid.len == 2) ? "uuid16" : "uuid128"),
+                   p_cur_srvc->uuid.uu.uuid16, p_cur_srvc->handle);
+
+  if (p_cur_srvc->characteristics != NULL) {
+    list_foreach(p_cur_srvc->characteristics, display_cache_attribute, NULL);
+  }
+
+  return true;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_display_cache_server
+ *
+ * Description      debug function to display the server cache.
+ *
+ * Returns          none.
+ *
+ ******************************************************************************/
+static void bta_gattc_display_cache_server(list_t* p_cache) {
+  APPL_TRACE_ERROR("<================Start Server Cache =============>");
+  list_foreach(p_cache, display_cache_service, NULL);
+  APPL_TRACE_ERROR("<================End Server Cache =============>");
+  APPL_TRACE_ERROR(" ");
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_display_explore_record
+ *
+ * Description      debug function to display the exploration list
+ *
+ * Returns          none.
+ *
+ ******************************************************************************/
+static void bta_gattc_display_explore_record(tBTA_GATTC_ATTR_REC* p_rec,
+                                             uint8_t num_rec) {
+  uint8_t i;
+  tBTA_GATTC_ATTR_REC* pp = p_rec;
+
+  APPL_TRACE_ERROR("<================Start Explore Queue =============>");
+  for (i = 0; i < num_rec; i++, pp++) {
+    APPL_TRACE_ERROR(
+        "\t rec[%d] uuid[0x%04x] s_handle[%d] e_handle[%d] is_primary[%d]",
+        i + 1, pp->uuid.uu.uuid16, pp->s_handle, pp->e_handle, pp->is_primary);
+  }
+  APPL_TRACE_ERROR("<================ End Explore Queue =============>");
+  APPL_TRACE_ERROR(" ");
+}
+#endif /* BTA_GATT_DEBUG == TRUE */
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_init_cache
+ *
+ * Description      Initialize the database cache and discovery related
+ *                  resources.
+ *
+ * Returns          status
+ *
+ ******************************************************************************/
+tBTA_GATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV* p_srvc_cb) {
+  if (p_srvc_cb->p_srvc_cache != NULL) {
+    list_free(p_srvc_cb->p_srvc_cache);
+    p_srvc_cb->p_srvc_cache = NULL;
+  }
+
+  osi_free(p_srvc_cb->p_srvc_list);
+  p_srvc_cb->p_srvc_list =
+      (tBTA_GATTC_ATTR_REC*)osi_malloc(BTA_GATTC_ATTR_LIST_SIZE);
+  p_srvc_cb->total_srvc = 0;
+  p_srvc_cb->cur_srvc_idx = 0;
+  p_srvc_cb->cur_char_idx = 0;
+  p_srvc_cb->next_avail_idx = 0;
+
+  return BTA_GATT_OK;
+}
+
+static void characteristic_free(void* ptr) {
+  tBTA_GATTC_CHARACTERISTIC* p_char = (tBTA_GATTC_CHARACTERISTIC*)ptr;
+  list_free(p_char->descriptors);
+  osi_free(p_char);
+}
+
+static void service_free(void* ptr) {
+  tBTA_GATTC_SERVICE* srvc = (tBTA_GATTC_SERVICE*)ptr;
+  list_free(srvc->characteristics);
+  list_free(srvc->included_svc);
+  osi_free(srvc);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_add_srvc_to_cache
+ *
+ * Description      Add a service into database cache.
+ *
+ * Returns          status
+ *
+ ******************************************************************************/
+static tBTA_GATT_STATUS bta_gattc_add_srvc_to_cache(tBTA_GATTC_SERV* p_srvc_cb,
+                                                    uint16_t s_handle,
+                                                    uint16_t e_handle,
+                                                    tBT_UUID* p_uuid,
+                                                    bool is_primary) {
+#if (BTA_GATT_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("Add a service into Service");
+#endif
+
+  tBTA_GATTC_SERVICE* p_new_srvc =
+      (tBTA_GATTC_SERVICE*)osi_malloc(sizeof(tBTA_GATTC_SERVICE));
+
+  /* update service information */
+  p_new_srvc->s_handle = s_handle;
+  p_new_srvc->e_handle = e_handle;
+  p_new_srvc->is_primary = is_primary;
+  memcpy(&p_new_srvc->uuid, p_uuid, sizeof(tBT_UUID));
+  p_new_srvc->handle = s_handle;
+  p_new_srvc->characteristics = list_new(characteristic_free);
+  p_new_srvc->included_svc = list_new(osi_free);
+
+  if (p_srvc_cb->p_srvc_cache == NULL) {
+    p_srvc_cb->p_srvc_cache = list_new(service_free);
+  }
+
+  list_append(p_srvc_cb->p_srvc_cache, p_new_srvc);
+  return BTA_GATT_OK;
+}
+
+static tBTA_GATT_STATUS bta_gattc_add_char_to_cache(tBTA_GATTC_SERV* p_srvc_cb,
+                                                    uint16_t attr_handle,
+                                                    uint16_t value_handle,
+                                                    tBT_UUID* p_uuid,
+                                                    uint8_t property) {
+#if (BTA_GATT_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("%s: Add a characteristic into Service", __func__);
+  APPL_TRACE_DEBUG("handle=%d uuid16=0x%x property=0x%x", value_handle,
+                   p_uuid->uu.uuid16, property);
+#endif
+
+  tBTA_GATTC_SERVICE* service =
+      bta_gattc_find_matching_service(p_srvc_cb->p_srvc_cache, attr_handle);
+  if (!service) {
+    APPL_TRACE_ERROR(
+        "Illegal action to add char/descr/incl srvc for non-existing service!");
+    return GATT_WRONG_STATE;
+  }
+
+  /* TODO(jpawlowski): We should use attribute handle, not value handle to refer
+     to characteristic.
+     This is just a temporary workaround.
+  */
+  if (service->e_handle < value_handle) service->e_handle = value_handle;
+
+  tBTA_GATTC_CHARACTERISTIC* characteristic =
+      (tBTA_GATTC_CHARACTERISTIC*)osi_malloc(sizeof(tBTA_GATTC_CHARACTERISTIC));
+
+  characteristic->handle = value_handle;
+  characteristic->properties = property;
+  characteristic->descriptors = list_new(osi_free);
+  memcpy(&characteristic->uuid, p_uuid, sizeof(tBT_UUID));
+
+  characteristic->service = service;
+  list_append(service->characteristics, characteristic);
+
+  return BTA_GATT_OK;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_add_attr_to_cache
+ *
+ * Description      Add an attribute into database cache buffer.
+ *
+ * Returns          status
+ *
+ ******************************************************************************/
+static tBTA_GATT_STATUS bta_gattc_add_attr_to_cache(
+    tBTA_GATTC_SERV* p_srvc_cb, uint16_t handle, tBT_UUID* p_uuid,
+    uint8_t property, uint16_t incl_srvc_s_handle, tBTA_GATTC_ATTR_TYPE type) {
+#if (BTA_GATT_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("%s: Add a [%s] into Service", __func__,
+                   bta_gattc_attr_type[type]);
+  APPL_TRACE_DEBUG("handle=%d uuid16=0x%x property=0x%x type=%d", handle,
+                   p_uuid->uu.uuid16, property, type);
+#endif
+
+  tBTA_GATTC_SERVICE* service =
+      bta_gattc_find_matching_service(p_srvc_cb->p_srvc_cache, handle);
+  if (!service) {
+    APPL_TRACE_ERROR(
+        "Illegal action to add char/descr/incl srvc for non-existing service!");
+    return GATT_WRONG_STATE;
+  }
+
+  if (type == BTA_GATTC_ATTR_TYPE_INCL_SRVC) {
+    tBTA_GATTC_INCLUDED_SVC* isvc =
+        (tBTA_GATTC_INCLUDED_SVC*)osi_malloc(sizeof(tBTA_GATTC_INCLUDED_SVC));
+
+    isvc->handle = handle;
+    memcpy(&isvc->uuid, p_uuid, sizeof(tBT_UUID));
+
+    isvc->owning_service = service;
+    isvc->included_service = bta_gattc_find_matching_service(
+        p_srvc_cb->p_srvc_cache, incl_srvc_s_handle);
+    if (!isvc->included_service) {
+      APPL_TRACE_ERROR(
+          "%s: Illegal action to add non-existing included service!", __func__);
+      osi_free(isvc);
+      return GATT_WRONG_STATE;
+    }
+
+    list_append(service->included_svc, isvc);
+  } else if (type == BTA_GATTC_ATTR_TYPE_CHAR_DESCR) {
+    tBTA_GATTC_DESCRIPTOR* descriptor =
+        (tBTA_GATTC_DESCRIPTOR*)osi_malloc(sizeof(tBTA_GATTC_DESCRIPTOR));
+
+    descriptor->handle = handle;
+    memcpy(&descriptor->uuid, p_uuid, sizeof(tBT_UUID));
+
+    if (service->characteristics == NULL) {
+      APPL_TRACE_ERROR(
+          "%s: Illegal action to add descriptor before adding a "
+          "characteristic!",
+          __func__);
+      osi_free(descriptor);
+      return GATT_WRONG_STATE;
+    }
+
+    tBTA_GATTC_CHARACTERISTIC* char_node =
+        (tBTA_GATTC_CHARACTERISTIC*)list_back(service->characteristics);
+
+    descriptor->characteristic = char_node;
+    list_append(char_node->descriptors, descriptor);
+  }
+  return BTA_GATT_OK;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_get_disc_range
+ *
+ * Description      get discovery stating and ending handle range.
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_get_disc_range(tBTA_GATTC_SERV* p_srvc_cb, uint16_t* p_s_hdl,
+                              uint16_t* p_e_hdl, bool is_srvc) {
+  tBTA_GATTC_ATTR_REC* p_rec = NULL;
+
+  if (is_srvc) {
+    p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx;
+    *p_s_hdl = p_rec->s_handle;
+  } else {
+    p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_char_idx;
+    *p_s_hdl = p_rec->s_handle + 1;
+  }
+
+  *p_e_hdl = p_rec->e_handle;
+#if (BTA_GATT_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("discover range [%d ~ %d]", p_rec->s_handle,
+                   p_rec->e_handle);
+#endif
+  return;
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_discover_pri_service
+ *
+ * Description      Start primary service discovery
+ *
+ * Returns          status of the operation.
+ *
+ ******************************************************************************/
+tBTA_GATT_STATUS bta_gattc_discover_pri_service(uint16_t conn_id,
+                                                tBTA_GATTC_SERV* p_server_cb,
+                                                uint8_t disc_type) {
+  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+  tBTA_GATT_STATUS status = BTA_GATT_ERROR;
+
+  if (p_clcb) {
+    if (p_clcb->transport == BTA_TRANSPORT_LE)
+      status = bta_gattc_discover_procedure(conn_id, p_server_cb, disc_type);
+    else
+      status = bta_gattc_sdp_service_disc(conn_id, p_server_cb);
+  }
+
+  return status;
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_discover_procedure
+ *
+ * Description      Start a particular type of discovery procedure on server.
+ *
+ * Returns          status of the operation.
+ *
+ ******************************************************************************/
+tBTA_GATT_STATUS bta_gattc_discover_procedure(uint16_t conn_id,
+                                              tBTA_GATTC_SERV* p_server_cb,
+                                              uint8_t disc_type) {
+  tGATT_DISC_PARAM param;
+  bool is_service = true;
+
+  memset(&param, 0, sizeof(tGATT_DISC_PARAM));
+
+  if (disc_type == GATT_DISC_SRVC_ALL || disc_type == GATT_DISC_SRVC_BY_UUID) {
+    param.s_handle = 1;
+    param.e_handle = 0xFFFF;
+  } else {
+    if (disc_type == GATT_DISC_CHAR_DSCPT) is_service = false;
+
+    bta_gattc_get_disc_range(p_server_cb, &param.s_handle, &param.e_handle,
+                             is_service);
+
+    if (param.s_handle > param.e_handle) {
+      return GATT_ERROR;
+    }
+  }
+  return GATTC_Discover(conn_id, disc_type, &param);
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_start_disc_include_srvc
+ *
+ * Description      Start discovery for included service
+ *
+ * Returns          status of the operation.
+ *
+ ******************************************************************************/
+tBTA_GATT_STATUS bta_gattc_start_disc_include_srvc(uint16_t conn_id,
+                                                   tBTA_GATTC_SERV* p_srvc_cb) {
+  return bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_INC_SRVC);
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_start_disc_char
+ *
+ * Description      Start discovery for characteristic
+ *
+ * Returns          status of the operation.
+ *
+ ******************************************************************************/
+tBTA_GATT_STATUS bta_gattc_start_disc_char(uint16_t conn_id,
+                                           tBTA_GATTC_SERV* p_srvc_cb) {
+  p_srvc_cb->total_char = 0;
+
+  return bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_CHAR);
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_start_disc_char_dscp
+ *
+ * Description      Start discovery for characteristic descriptor
+ *
+ * Returns          none.
+ *
+ ******************************************************************************/
+void bta_gattc_start_disc_char_dscp(uint16_t conn_id,
+                                    tBTA_GATTC_SERV* p_srvc_cb) {
+  APPL_TRACE_DEBUG("starting discover characteristics descriptor");
+
+  if (bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_CHAR_DSCPT) !=
+      0)
+    bta_gattc_char_dscpt_disc_cmpl(conn_id, p_srvc_cb);
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_explore_srvc
+ *
+ * Description      process the service discovery complete event
+ *
+ * Returns          status
+ *
+ ******************************************************************************/
+static void bta_gattc_explore_srvc(uint16_t conn_id,
+                                   tBTA_GATTC_SERV* p_srvc_cb) {
+  tBTA_GATTC_ATTR_REC* p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx;
+  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+
+  APPL_TRACE_DEBUG("Start service discovery: srvc_idx = %d",
+                   p_srvc_cb->cur_srvc_idx);
+
+  p_srvc_cb->cur_char_idx = p_srvc_cb->next_avail_idx = p_srvc_cb->total_srvc;
+
+  if (p_clcb == NULL) {
+    APPL_TRACE_ERROR("unknown connection ID");
+    return;
+  }
+  /* start expore a service if there is service not been explored */
+  if (p_srvc_cb->cur_srvc_idx < p_srvc_cb->total_srvc) {
+    /* add the first service into cache */
+    if (bta_gattc_add_srvc_to_cache(p_srvc_cb, p_rec->s_handle, p_rec->e_handle,
+                                    &p_rec->uuid, p_rec->is_primary) == 0) {
+      /* start discovering included services */
+      bta_gattc_start_disc_include_srvc(conn_id, p_srvc_cb);
+      return;
+    }
+  }
+  /* no service found at all, the end of server discovery*/
+  LOG_WARN(LOG_TAG, "%s no more services found", __func__);
+
+#if (BTA_GATT_DEBUG == TRUE)
+  bta_gattc_display_cache_server(p_srvc_cb->p_srvc_cache);
+#endif
+  /* save cache to NV */
+  p_clcb->p_srcb->state = BTA_GATTC_SERV_SAVE;
+
+  if (btm_sec_is_a_bonded_dev(p_srvc_cb->server_bda)) {
+    bta_gattc_cache_save(p_clcb->p_srcb, p_clcb->bta_conn_id);
+  }
+
+  bta_gattc_reset_discover_st(p_clcb->p_srcb, BTA_GATT_OK);
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_incl_srvc_disc_cmpl
+ *
+ * Description      process the relationship discovery complete event
+ *
+ * Returns          status
+ *
+ ******************************************************************************/
+static void bta_gattc_incl_srvc_disc_cmpl(uint16_t conn_id,
+                                          tBTA_GATTC_SERV* p_srvc_cb) {
+  p_srvc_cb->cur_char_idx = p_srvc_cb->total_srvc;
+
+  /* start discoverying characteristic */
+  bta_gattc_start_disc_char(conn_id, p_srvc_cb);
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_char_disc_cmpl
+ *
+ * Description      process the characteristic discovery complete event
+ *
+ * Returns          status
+ *
+ ******************************************************************************/
+static void bta_gattc_char_disc_cmpl(uint16_t conn_id,
+                                     tBTA_GATTC_SERV* p_srvc_cb) {
+  tBTA_GATTC_ATTR_REC* p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_char_idx;
+
+  /* if there are characteristic needs to be explored */
+  if (p_srvc_cb->total_char > 0) {
+    /* add the first characteristic into cache */
+    bta_gattc_add_char_to_cache(p_srvc_cb, p_rec->char_decl_handle,
+                                p_rec->s_handle, &p_rec->uuid, p_rec->property);
+
+    /* start discoverying characteristic descriptor , if failed, disc for next
+     * char*/
+    bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
+  } else /* otherwise start with next service */
+  {
+    p_srvc_cb->cur_srvc_idx++;
+
+    bta_gattc_explore_srvc(conn_id, p_srvc_cb);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_char_dscpt_disc_cmpl
+ *
+ * Description      process the char descriptor discovery complete event
+ *
+ * Returns          status
+ *
+ ******************************************************************************/
+static void bta_gattc_char_dscpt_disc_cmpl(uint16_t conn_id,
+                                           tBTA_GATTC_SERV* p_srvc_cb) {
+  tBTA_GATTC_ATTR_REC* p_rec = NULL;
+
+  if (--p_srvc_cb->total_char > 0) {
+    p_rec = p_srvc_cb->p_srvc_list + (++p_srvc_cb->cur_char_idx);
+    /* add the next characteristic into cache */
+    bta_gattc_add_char_to_cache(p_srvc_cb, p_rec->char_decl_handle,
+                                p_rec->s_handle, &p_rec->uuid, p_rec->property);
+
+    /* start discoverying next characteristic for char descriptor */
+    bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
+  } else
+  /* all characteristic has been explored, start with next service if any */
+  {
+#if (BTA_GATT_DEBUG == TRUE)
+    APPL_TRACE_ERROR("all char has been explored");
+#endif
+    p_srvc_cb->cur_srvc_idx++;
+    bta_gattc_explore_srvc(conn_id, p_srvc_cb);
+  }
+}
+static bool bta_gattc_srvc_in_list(tBTA_GATTC_SERV* p_srvc_cb,
+                                   uint16_t s_handle, uint16_t e_handle,
+                                   UNUSED_ATTR tBT_UUID uuid) {
+  tBTA_GATTC_ATTR_REC* p_rec = NULL;
+  uint8_t i;
+  bool exist_srvc = false;
+
+  if (!GATT_HANDLE_IS_VALID(s_handle) || !GATT_HANDLE_IS_VALID(e_handle)) {
+    APPL_TRACE_ERROR("invalid included service handle: [0x%04x ~ 0x%04x]",
+                     s_handle, e_handle);
+    exist_srvc = true;
+  } else {
+    for (i = 0; i < p_srvc_cb->next_avail_idx; i++) {
+      p_rec = p_srvc_cb->p_srvc_list + i;
+
+      /* a new service should not have any overlap with other service handle
+       * range */
+      if (p_rec->s_handle == s_handle || p_rec->e_handle == e_handle) {
+        exist_srvc = true;
+        break;
+      }
+    }
+  }
+  return exist_srvc;
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_add_srvc_to_list
+ *
+ * Description      Add a service into explore pending list
+ *
+ * Returns          status
+ *
+ ******************************************************************************/
+static tBTA_GATT_STATUS bta_gattc_add_srvc_to_list(tBTA_GATTC_SERV* p_srvc_cb,
+                                                   uint16_t s_handle,
+                                                   uint16_t e_handle,
+                                                   tBT_UUID uuid,
+                                                   bool is_primary) {
+  tBTA_GATTC_ATTR_REC* p_rec = NULL;
+  tBTA_GATT_STATUS status = BTA_GATT_OK;
+
+  if (p_srvc_cb->p_srvc_list &&
+      p_srvc_cb->next_avail_idx < BTA_GATTC_MAX_CACHE_CHAR) {
+    p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->next_avail_idx;
+
+    APPL_TRACE_DEBUG("%s handle=%d, service type=0x%04x", __func__, s_handle,
+                     uuid.uu.uuid16);
+
+    p_rec->s_handle = s_handle;
+    p_rec->e_handle = e_handle;
+    p_rec->is_primary = is_primary;
+    memcpy(&p_rec->uuid, &uuid, sizeof(tBT_UUID));
+
+    p_srvc_cb->total_srvc++;
+    p_srvc_cb->next_avail_idx++;
+  } else { /* allocate bigger buffer ?? */
+    status = GATT_DB_FULL;
+
+    APPL_TRACE_ERROR("service not added, no resources or wrong state");
+  }
+  return status;
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_add_char_to_list
+ *
+ * Description      Add a characteristic into explore pending list
+ *
+ * Returns          status
+ *
+ ******************************************************************************/
+static tBTA_GATT_STATUS bta_gattc_add_char_to_list(tBTA_GATTC_SERV* p_srvc_cb,
+                                                   uint16_t decl_handle,
+                                                   uint16_t value_handle,
+                                                   tBT_UUID uuid,
+                                                   uint8_t property) {
+  tBTA_GATTC_ATTR_REC* p_rec = NULL;
+  tBTA_GATT_STATUS status = BTA_GATT_OK;
+
+  if (p_srvc_cb->p_srvc_list == NULL) {
+    APPL_TRACE_ERROR("No service available, unexpected char discovery result");
+    status = BTA_GATT_INTERNAL_ERROR;
+  } else if (p_srvc_cb->next_avail_idx < BTA_GATTC_MAX_CACHE_CHAR) {
+    p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->next_avail_idx;
+
+    p_srvc_cb->total_char++;
+
+    p_rec->s_handle = value_handle;
+    p_rec->char_decl_handle = decl_handle;
+    p_rec->property = property;
+    p_rec->e_handle =
+        (p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx)->e_handle;
+    memcpy(&p_rec->uuid, &uuid, sizeof(tBT_UUID));
+
+    /* update the endind handle of pervious characteristic if available */
+    if (p_srvc_cb->total_char > 1) {
+      p_rec -= 1;
+      p_rec->e_handle = decl_handle - 1;
+    }
+    p_srvc_cb->next_avail_idx++;
+  } else {
+    APPL_TRACE_ERROR("char not added, no resources");
+    /* allocate bigger buffer ?? */
+    status = BTA_GATT_DB_FULL;
+  }
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_sdp_callback
+ *
+ * Description      Process the discovery result from sdp
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_gattc_sdp_callback(uint16_t sdp_status, void* user_data) {
+  tSDP_DISC_REC* p_sdp_rec = NULL;
+  tBT_UUID service_uuid;
+  tSDP_PROTOCOL_ELEM pe;
+  uint16_t start_handle = 0, end_handle = 0;
+  tBTA_GATTC_CB_DATA* cb_data = (tBTA_GATTC_CB_DATA*)user_data;
+  tBTA_GATTC_SERV* p_srvc_cb = bta_gattc_find_scb_by_cid(cb_data->sdp_conn_id);
+
+  if (((sdp_status == SDP_SUCCESS) || (sdp_status == SDP_DB_FULL)) &&
+      p_srvc_cb != NULL) {
+    do {
+      /* find a service record, report it */
+      p_sdp_rec = SDP_FindServiceInDb(cb_data->p_sdp_db, 0, p_sdp_rec);
+      if (p_sdp_rec) {
+        if (SDP_FindServiceUUIDInRec(p_sdp_rec, &service_uuid)) {
+          if (SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_ATT,
+                                            &pe)) {
+            start_handle = (uint16_t)pe.params[0];
+            end_handle = (uint16_t)pe.params[1];
+
+#if (BTA_GATT_DEBUG == TRUE)
+            APPL_TRACE_EVENT(
+                "Found ATT service [0x%04x] handle[0x%04x ~ 0x%04x]",
+                service_uuid.uu.uuid16, start_handle, end_handle);
+#endif
+
+            if (GATT_HANDLE_IS_VALID(start_handle) &&
+                GATT_HANDLE_IS_VALID(end_handle) && p_srvc_cb != NULL) {
+              /* discover services result, add services into a service list */
+              bta_gattc_add_srvc_to_list(p_srvc_cb, start_handle, end_handle,
+                                         service_uuid, true);
+            } else {
+              APPL_TRACE_ERROR("invalid start_handle = %d end_handle = %d",
+                               start_handle, end_handle);
+            }
+          }
+        }
+      }
+    } while (p_sdp_rec);
+  }
+
+  if (p_srvc_cb != NULL) {
+    /* start discover primary service */
+    bta_gattc_explore_srvc(cb_data->sdp_conn_id, p_srvc_cb);
+  } else {
+    APPL_TRACE_ERROR("GATT service discovery is done on unknown connection");
+  }
+
+  /* both were allocated in bta_gattc_sdp_service_disc */
+  osi_free(cb_data->p_sdp_db);
+  osi_free(cb_data);
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_sdp_service_disc
+ *
+ * Description      Start DSP Service Discovert
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static tBTA_GATT_STATUS bta_gattc_sdp_service_disc(
+    uint16_t conn_id, tBTA_GATTC_SERV* p_server_cb) {
+  tSDP_UUID uuid;
+  uint16_t num_attrs = 2;
+  uint16_t attr_list[2];
+
+  memset(&uuid, 0, sizeof(tSDP_UUID));
+
+  uuid.len = LEN_UUID_16;
+  uuid.uu.uuid16 = UUID_PROTOCOL_ATT;
+
+  /*
+   * On success, cb_data will be freed inside bta_gattc_sdp_callback,
+   * otherwise it will be freed within this function.
+   */
+  tBTA_GATTC_CB_DATA* cb_data =
+      (tBTA_GATTC_CB_DATA*)osi_malloc(sizeof(tBTA_GATTC_CB_DATA));
+
+  cb_data->p_sdp_db = (tSDP_DISCOVERY_DB*)osi_malloc(BTA_GATT_SDP_DB_SIZE);
+  attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+  attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+
+  SDP_InitDiscoveryDb(cb_data->p_sdp_db, BTA_GATT_SDP_DB_SIZE, 1, &uuid,
+                      num_attrs, attr_list);
+
+  if (!SDP_ServiceSearchAttributeRequest2(p_server_cb->server_bda,
+                                          cb_data->p_sdp_db,
+                                          &bta_gattc_sdp_callback, cb_data)) {
+    osi_free(cb_data->p_sdp_db);
+    osi_free(cb_data);
+    return BTA_GATT_ERROR;
+  }
+
+  cb_data->sdp_conn_id = conn_id;
+  return BTA_GATT_OK;
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_disc_res_cback
+ *                  bta_gattc_disc_cmpl_cback
+ *
+ * Description      callback functions to GATT client stack.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_gattc_disc_res_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+                              tGATT_DISC_RES* p_data) {
+  tBTA_GATTC_SERV* p_srvc_cb = NULL;
+  bool pri_srvc;
+  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+
+  p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id);
+
+  if (p_srvc_cb != NULL && p_clcb != NULL &&
+      p_clcb->state == BTA_GATTC_DISCOVER_ST) {
+    switch (disc_type) {
+      case GATT_DISC_SRVC_ALL:
+        /* discover services result, add services into a service list */
+        bta_gattc_add_srvc_to_list(
+            p_srvc_cb, p_data->handle, p_data->value.group_value.e_handle,
+            p_data->value.group_value.service_type, true);
+
+        break;
+      case GATT_DISC_SRVC_BY_UUID:
+        bta_gattc_add_srvc_to_list(
+            p_srvc_cb, p_data->handle, p_data->value.group_value.e_handle,
+            p_data->value.group_value.service_type, true);
+        break;
+
+      case GATT_DISC_INC_SRVC:
+        /* add included service into service list if it's secondary or it never
+           showed up
+           in the primary service search */
+        pri_srvc = bta_gattc_srvc_in_list(
+            p_srvc_cb, p_data->value.incl_service.s_handle,
+            p_data->value.incl_service.e_handle,
+            p_data->value.incl_service.service_type);
+
+        if (!pri_srvc)
+          bta_gattc_add_srvc_to_list(
+              p_srvc_cb, p_data->value.incl_service.s_handle,
+              p_data->value.incl_service.e_handle,
+              p_data->value.incl_service.service_type, false);
+        /* add into database */
+        bta_gattc_add_attr_to_cache(
+            p_srvc_cb, p_data->handle, &p_data->value.incl_service.service_type,
+            pri_srvc, p_data->value.incl_service.s_handle,
+            BTA_GATTC_ATTR_TYPE_INCL_SRVC);
+        break;
+
+      case GATT_DISC_CHAR:
+        /* add char value into database */
+        bta_gattc_add_char_to_list(p_srvc_cb, p_data->handle,
+                                   p_data->value.dclr_value.val_handle,
+                                   p_data->value.dclr_value.char_uuid,
+                                   p_data->value.dclr_value.char_prop);
+        break;
+
+      case GATT_DISC_CHAR_DSCPT:
+        bta_gattc_add_attr_to_cache(p_srvc_cb, p_data->handle, &p_data->type, 0,
+                                    0 /* incl_srvc_handle */,
+                                    BTA_GATTC_ATTR_TYPE_CHAR_DESCR);
+        break;
+    }
+  }
+}
+void bta_gattc_disc_cmpl_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+                               tGATT_STATUS status) {
+  tBTA_GATTC_SERV* p_srvc_cb;
+  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+
+  if (p_clcb && (status != GATT_SUCCESS || p_clcb->status != GATT_SUCCESS)) {
+    if (status == GATT_SUCCESS) p_clcb->status = status;
+    bta_gattc_sm_execute(p_clcb, BTA_GATTC_DISCOVER_CMPL_EVT, NULL);
+    return;
+  }
+  p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id);
+
+  if (p_srvc_cb != NULL) {
+    switch (disc_type) {
+      case GATT_DISC_SRVC_ALL:
+      case GATT_DISC_SRVC_BY_UUID:
+#if (BTA_GATT_DEBUG == TRUE)
+        bta_gattc_display_explore_record(p_srvc_cb->p_srvc_list,
+                                         p_srvc_cb->next_avail_idx);
+#endif
+        bta_gattc_explore_srvc(conn_id, p_srvc_cb);
+        break;
+
+      case GATT_DISC_INC_SRVC:
+        bta_gattc_incl_srvc_disc_cmpl(conn_id, p_srvc_cb);
+
+        break;
+
+      case GATT_DISC_CHAR:
+#if (BTA_GATT_DEBUG == TRUE)
+        bta_gattc_display_explore_record(p_srvc_cb->p_srvc_list,
+                                         p_srvc_cb->next_avail_idx);
+#endif
+        bta_gattc_char_disc_cmpl(conn_id, p_srvc_cb);
+        break;
+
+      case GATT_DISC_CHAR_DSCPT:
+        bta_gattc_char_dscpt_disc_cmpl(conn_id, p_srvc_cb);
+        break;
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_search_service
+ *
+ * Description      search local cache for matching service record.
+ *
+ * Returns          false if map can not be found.
+ *
+ ******************************************************************************/
+void bta_gattc_search_service(tBTA_GATTC_CLCB* p_clcb, tBT_UUID* p_uuid) {
+  tBTA_GATTC cb_data;
+
+  if (!p_clcb->p_srcb->p_srvc_cache ||
+      list_is_empty(p_clcb->p_srcb->p_srvc_cache))
+    return;
+
+  for (list_node_t* sn = list_begin(p_clcb->p_srcb->p_srvc_cache);
+       sn != list_end(p_clcb->p_srcb->p_srvc_cache); sn = list_next(sn)) {
+    tBTA_GATTC_SERVICE* p_cache = (tBTA_GATTC_SERVICE*)list_node(sn);
+
+    if (!bta_gattc_uuid_compare(p_uuid, &p_cache->uuid, false)) continue;
+
+#if (BTA_GATT_DEBUG == TRUE)
+    APPL_TRACE_DEBUG("found service [0x%04x], inst[%d] handle [%d]",
+                     p_cache->uuid.uu.uuid16, p_cache->handle,
+                     p_cache->s_handle);
+#endif
+    if (!p_clcb->p_rcb->p_cback) continue;
+
+    memset(&cb_data, 0, sizeof(tBTA_GATTC));
+
+    cb_data.srvc_res.conn_id = p_clcb->bta_conn_id;
+    cb_data.srvc_res.service_uuid.inst_id = p_cache->handle;
+    memcpy(&cb_data.srvc_res.service_uuid.uuid, &p_cache->uuid,
+           sizeof(tBTA_GATT_ID));
+
+    (*p_clcb->p_rcb->p_cback)(BTA_GATTC_SEARCH_RES_EVT, &cb_data);
+  }
+}
+
+list_t* bta_gattc_get_services_srcb(tBTA_GATTC_SERV* p_srcb) {
+  if (!p_srcb || !p_srcb->p_srvc_cache || list_is_empty(p_srcb->p_srvc_cache))
+    return NULL;
+
+  return p_srcb->p_srvc_cache;
+}
+
+const list_t* bta_gattc_get_services(uint16_t conn_id) {
+  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+
+  if (p_clcb == NULL) return NULL;
+
+  tBTA_GATTC_SERV* p_srcb = p_clcb->p_srcb;
+
+  return bta_gattc_get_services_srcb(p_srcb);
+}
+
+tBTA_GATTC_SERVICE* bta_gattc_find_matching_service(const list_t* services,
+                                                    uint16_t handle) {
+  if (!services || list_is_empty(services)) return NULL;
+
+  for (list_node_t* sn = list_begin(services); sn != list_end(services);
+       sn = list_next(sn)) {
+    tBTA_GATTC_SERVICE* service = (tBTA_GATTC_SERVICE*)list_node(sn);
+
+    if (handle >= service->s_handle && handle <= service->e_handle)
+      return service;
+  }
+
+  return NULL;
+}
+
+const tBTA_GATTC_SERVICE* bta_gattc_get_service_for_handle_srcb(
+    tBTA_GATTC_SERV* p_srcb, uint16_t handle) {
+  const list_t* services = bta_gattc_get_services_srcb(p_srcb);
+
+  return bta_gattc_find_matching_service(services, handle);
+}
+
+const tBTA_GATTC_SERVICE* bta_gattc_get_service_for_handle(uint16_t conn_id,
+                                                           uint16_t handle) {
+  const list_t* services = bta_gattc_get_services(conn_id);
+
+  return bta_gattc_find_matching_service(services, handle);
+}
+
+tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic_srcb(
+    tBTA_GATTC_SERV* p_srcb, uint16_t handle) {
+  const tBTA_GATTC_SERVICE* service =
+      bta_gattc_get_service_for_handle_srcb(p_srcb, handle);
+
+  if (!service) return NULL;
+
+  for (list_node_t* cn = list_begin(service->characteristics);
+       cn != list_end(service->characteristics); cn = list_next(cn)) {
+    tBTA_GATTC_CHARACTERISTIC* p_char =
+        (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
+    if (handle == p_char->handle) return p_char;
+  }
+
+  return NULL;
+}
+
+tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic(uint16_t conn_id,
+                                                        uint16_t handle) {
+  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+
+  if (p_clcb == NULL) return NULL;
+
+  tBTA_GATTC_SERV* p_srcb = p_clcb->p_srcb;
+  return bta_gattc_get_characteristic_srcb(p_srcb, handle);
+}
+
+tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor_srcb(tBTA_GATTC_SERV* p_srcb,
+                                                     uint16_t handle) {
+  const tBTA_GATTC_SERVICE* service =
+      bta_gattc_get_service_for_handle_srcb(p_srcb, handle);
+
+  if (!service) {
+    return NULL;
+  }
+
+  for (list_node_t* cn = list_begin(service->characteristics);
+       cn != list_end(service->characteristics); cn = list_next(cn)) {
+    tBTA_GATTC_CHARACTERISTIC* p_char =
+        (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
+    for (list_node_t* dn = list_begin(p_char->descriptors);
+         dn != list_end(p_char->descriptors); dn = list_next(dn)) {
+      tBTA_GATTC_DESCRIPTOR* p_desc = (tBTA_GATTC_DESCRIPTOR*)list_node(dn);
+      if (handle == p_desc->handle) return p_desc;
+    }
+  }
+
+  return NULL;
+}
+
+tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor(uint16_t conn_id,
+                                                uint16_t handle) {
+  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+
+  if (p_clcb == NULL) return NULL;
+
+  tBTA_GATTC_SERV* p_srcb = p_clcb->p_srcb;
+  return bta_gattc_get_descriptor_srcb(p_srcb, handle);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_fill_gatt_db_el
+ *
+ * Description      fill a btgatt_db_element_t value
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_fill_gatt_db_el(btgatt_db_element_t* p_attr,
+                               bt_gatt_db_attribute_type_t type,
+                               uint16_t att_handle, uint16_t s_handle,
+                               uint16_t e_handle, uint16_t id, tBT_UUID uuid,
+                               uint8_t prop) {
+  p_attr->type = type;
+  p_attr->attribute_handle = att_handle;
+  p_attr->start_handle = s_handle;
+  p_attr->end_handle = e_handle;
+  p_attr->id = id;
+  p_attr->properties = prop;
+  bta_to_btif_uuid(&p_attr->uuid, &uuid);
+}
+
+/*******************************************************************************
+ * Returns          number of elements inside db from start_handle to end_handle
+ ******************************************************************************/
+static size_t bta_gattc_get_db_size(list_t* services, uint16_t start_handle,
+                                    uint16_t end_handle) {
+  if (!services || list_is_empty(services)) return 0;
+
+  size_t db_size = 0;
+
+  for (list_node_t* sn = list_begin(services); sn != list_end(services);
+       sn = list_next(sn)) {
+    tBTA_GATTC_SERVICE* p_cur_srvc = (tBTA_GATTC_SERVICE*)list_node(sn);
+
+    if (p_cur_srvc->s_handle < start_handle) continue;
+
+    if (p_cur_srvc->e_handle > end_handle) break;
+
+    db_size++;
+    if (!p_cur_srvc->characteristics ||
+        list_is_empty(p_cur_srvc->characteristics))
+      continue;
+
+    for (list_node_t* cn = list_begin(p_cur_srvc->characteristics);
+         cn != list_end(p_cur_srvc->characteristics); cn = list_next(cn)) {
+      tBTA_GATTC_CHARACTERISTIC* p_char =
+          (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
+      db_size++;
+
+      if (p_char->descriptors) db_size += list_length(p_char->descriptors);
+    }
+
+    if (p_cur_srvc->included_svc) {
+      db_size += list_length(p_cur_srvc->included_svc);
+    }
+  }
+
+  return db_size;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_get_gatt_db_impl
+ *
+ * Description      copy the server GATT database into db parameter.
+ *
+ * Parameters       p_srvc_cb: server.
+ *                  db: output parameter which will contain GATT database copy.
+ *                      Caller is responsible for freeing it.
+ *                  count: output parameter which will contain number of
+ *                  elements in database.
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+static void bta_gattc_get_gatt_db_impl(tBTA_GATTC_SERV* p_srvc_cb,
+                                       uint16_t start_handle,
+                                       uint16_t end_handle,
+                                       btgatt_db_element_t** db, int* count) {
+  APPL_TRACE_DEBUG("%s: start_handle 0x%04x, end_handle 0x%04x", __func__,
+                   start_handle, end_handle);
+
+  if (!p_srvc_cb->p_srvc_cache || list_is_empty(p_srvc_cb->p_srvc_cache)) {
+    *count = 0;
+    *db = NULL;
+    return;
+  }
+
+  size_t db_size =
+      bta_gattc_get_db_size(p_srvc_cb->p_srvc_cache, start_handle, end_handle);
+
+  void* buffer = osi_malloc(db_size * sizeof(btgatt_db_element_t));
+  btgatt_db_element_t* curr_db_attr = (btgatt_db_element_t*)buffer;
+
+  for (list_node_t* sn = list_begin(p_srvc_cb->p_srvc_cache);
+       sn != list_end(p_srvc_cb->p_srvc_cache); sn = list_next(sn)) {
+    tBTA_GATTC_SERVICE* p_cur_srvc = (tBTA_GATTC_SERVICE*)list_node(sn);
+
+    if (p_cur_srvc->s_handle < start_handle) continue;
+
+    if (p_cur_srvc->e_handle > end_handle) break;
+
+    bta_gattc_fill_gatt_db_el(
+        curr_db_attr, p_cur_srvc->is_primary ? BTGATT_DB_PRIMARY_SERVICE
+                                             : BTGATT_DB_SECONDARY_SERVICE,
+        0 /* att_handle */, p_cur_srvc->s_handle, p_cur_srvc->e_handle,
+        p_cur_srvc->s_handle, p_cur_srvc->uuid, 0 /* prop */);
+    curr_db_attr++;
+
+    if (!p_cur_srvc->characteristics ||
+        list_is_empty(p_cur_srvc->characteristics))
+      continue;
+
+    for (list_node_t* cn = list_begin(p_cur_srvc->characteristics);
+         cn != list_end(p_cur_srvc->characteristics); cn = list_next(cn)) {
+      tBTA_GATTC_CHARACTERISTIC* p_char =
+          (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
+
+      bta_gattc_fill_gatt_db_el(curr_db_attr, BTGATT_DB_CHARACTERISTIC,
+                                p_char->handle, 0 /* s_handle */,
+                                0 /* e_handle */, p_char->handle, p_char->uuid,
+                                p_char->properties);
+      curr_db_attr++;
+
+      if (!p_char->descriptors || list_is_empty(p_char->descriptors)) continue;
+
+      for (list_node_t* dn = list_begin(p_char->descriptors);
+           dn != list_end(p_char->descriptors); dn = list_next(dn)) {
+        tBTA_GATTC_DESCRIPTOR* p_desc = (tBTA_GATTC_DESCRIPTOR*)list_node(dn);
+
+        bta_gattc_fill_gatt_db_el(curr_db_attr, BTGATT_DB_DESCRIPTOR,
+                                  p_desc->handle, 0 /* s_handle */,
+                                  0 /* e_handle */, p_desc->handle,
+                                  p_desc->uuid, 0 /* property */);
+        curr_db_attr++;
+      }
+    }
+
+    if (!p_cur_srvc->included_svc || list_is_empty(p_cur_srvc->included_svc))
+      continue;
+
+    for (list_node_t* isn = list_begin(p_cur_srvc->included_svc);
+         isn != list_end(p_cur_srvc->included_svc); isn = list_next(isn)) {
+      tBTA_GATTC_INCLUDED_SVC* p_isvc =
+          (tBTA_GATTC_INCLUDED_SVC*)list_node(isn);
+
+      bta_gattc_fill_gatt_db_el(curr_db_attr, BTGATT_DB_INCLUDED_SERVICE,
+                                p_isvc->handle, 0 /* s_handle */,
+                                0 /* e_handle */, p_isvc->handle, p_isvc->uuid,
+                                0 /* property */);
+      curr_db_attr++;
+    }
+  }
+
+  *db = (btgatt_db_element_t*)buffer;
+  *count = db_size;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_get_gatt_db
+ *
+ * Description      copy the server GATT database into db parameter.
+ *
+ * Parameters       conn_id: connection ID which identify the server.
+ *                  db: output parameter which will contain GATT database copy.
+ *                      Caller is responsible for freeing it.
+ *                  count: number of elements in database.
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_get_gatt_db(uint16_t conn_id, uint16_t start_handle,
+                           uint16_t end_handle, btgatt_db_element_t** db,
+                           int* count) {
+  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+
+  LOG_DEBUG(LOG_TAG, "%s", __func__);
+  if (p_clcb == NULL) {
+    APPL_TRACE_ERROR("Unknown conn ID: %d", conn_id);
+    return;
+  }
+
+  if (p_clcb->state != BTA_GATTC_CONN_ST) {
+    APPL_TRACE_ERROR("server cache not available, CLCB state = %d",
+                     p_clcb->state);
+    return;
+  }
+
+  if (!p_clcb->p_srcb ||
+      p_clcb->p_srcb->p_srvc_list || /* no active discovery */
+      !p_clcb->p_srcb->p_srvc_cache) {
+    APPL_TRACE_ERROR("No server cache available");
+    return;
+  }
+
+  bta_gattc_get_gatt_db_impl(p_clcb->p_srcb, start_handle, end_handle, db,
+                             count);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_rebuild_cache
+ *
+ * Description      rebuild server cache from NV cache.
+ *
+ * Parameters
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_rebuild_cache(tBTA_GATTC_SERV* p_srvc_cb, uint16_t num_attr,
+                             tBTA_GATTC_NV_ATTR* p_attr) {
+  /* first attribute loading, initialize buffer */
+  APPL_TRACE_ERROR("%s: bta_gattc_rebuild_cache", __func__);
+
+  list_free(p_srvc_cb->p_srvc_cache);
+  p_srvc_cb->p_srvc_cache = NULL;
+
+  while (num_attr > 0 && p_attr != NULL) {
+    switch (p_attr->attr_type) {
+      case BTA_GATTC_ATTR_TYPE_SRVC:
+        bta_gattc_add_srvc_to_cache(p_srvc_cb, p_attr->s_handle,
+                                    p_attr->e_handle, &p_attr->uuid,
+                                    p_attr->is_primary);
+        break;
+
+      case BTA_GATTC_ATTR_TYPE_CHAR:
+        // TODO(jpawlowski): store decl_handle properly.
+        bta_gattc_add_char_to_cache(p_srvc_cb, p_attr->s_handle,
+                                    p_attr->s_handle, &p_attr->uuid,
+                                    p_attr->prop);
+        break;
+
+      case BTA_GATTC_ATTR_TYPE_CHAR_DESCR:
+      case BTA_GATTC_ATTR_TYPE_INCL_SRVC:
+        bta_gattc_add_attr_to_cache(p_srvc_cb, p_attr->s_handle, &p_attr->uuid,
+                                    p_attr->prop, p_attr->incl_srvc_handle,
+                                    p_attr->attr_type);
+        break;
+    }
+    p_attr++;
+    num_attr--;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_fill_nv_attr
+ *
+ * Description      fill a NV attribute entry value
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_fill_nv_attr(tBTA_GATTC_NV_ATTR* p_attr, uint8_t type,
+                            uint16_t s_handle, uint16_t e_handle, tBT_UUID uuid,
+                            uint8_t prop, uint16_t incl_srvc_handle,
+                            bool is_primary) {
+  p_attr->s_handle = s_handle;
+  p_attr->e_handle = e_handle;
+  p_attr->attr_type = type;
+  p_attr->is_primary = is_primary;
+  p_attr->id = 0;
+  p_attr->prop = prop;
+  p_attr->incl_srvc_handle = incl_srvc_handle;
+
+  memcpy(&p_attr->uuid, &uuid, sizeof(tBT_UUID));
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_cache_save
+ *
+ * Description      save the server cache into NV
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_cache_save(tBTA_GATTC_SERV* p_srvc_cb, uint16_t conn_id) {
+  if (!p_srvc_cb->p_srvc_cache || list_is_empty(p_srvc_cb->p_srvc_cache))
+    return;
+
+  int i = 0;
+  size_t db_size =
+      bta_gattc_get_db_size(p_srvc_cb->p_srvc_cache, 0x0000, 0xFFFF);
+  tBTA_GATTC_NV_ATTR* nv_attr =
+      (tBTA_GATTC_NV_ATTR*)osi_malloc(db_size * sizeof(tBTA_GATTC_NV_ATTR));
+
+  for (list_node_t* sn = list_begin(p_srvc_cb->p_srvc_cache);
+       sn != list_end(p_srvc_cb->p_srvc_cache); sn = list_next(sn)) {
+    tBTA_GATTC_SERVICE* p_cur_srvc = (tBTA_GATTC_SERVICE*)list_node(sn);
+
+    bta_gattc_fill_nv_attr(&nv_attr[i++], BTA_GATTC_ATTR_TYPE_SRVC,
+                           p_cur_srvc->s_handle, p_cur_srvc->e_handle,
+                           p_cur_srvc->uuid, 0 /* properties */,
+                           0 /* incl_srvc_handle */, p_cur_srvc->is_primary);
+  }
+
+  for (list_node_t* sn = list_begin(p_srvc_cb->p_srvc_cache);
+       sn != list_end(p_srvc_cb->p_srvc_cache); sn = list_next(sn)) {
+    tBTA_GATTC_SERVICE* p_cur_srvc = (tBTA_GATTC_SERVICE*)list_node(sn);
+
+    if (!p_cur_srvc->characteristics ||
+        list_is_empty(p_cur_srvc->characteristics))
+      continue;
+
+    for (list_node_t* cn = list_begin(p_cur_srvc->characteristics);
+         cn != list_end(p_cur_srvc->characteristics); cn = list_next(cn)) {
+      tBTA_GATTC_CHARACTERISTIC* p_char =
+          (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
+
+      bta_gattc_fill_nv_attr(
+          &nv_attr[i++], BTA_GATTC_ATTR_TYPE_CHAR, p_char->handle, 0,
+          p_char->uuid, p_char->properties, 0 /* incl_srvc_handle */, false);
+
+      if (!p_char->descriptors || list_is_empty(p_char->descriptors)) continue;
+
+      for (list_node_t* dn = list_begin(p_char->descriptors);
+           dn != list_end(p_char->descriptors); dn = list_next(dn)) {
+        tBTA_GATTC_DESCRIPTOR* p_desc = (tBTA_GATTC_DESCRIPTOR*)list_node(dn);
+
+        bta_gattc_fill_nv_attr(
+            &nv_attr[i++], BTA_GATTC_ATTR_TYPE_CHAR_DESCR, p_desc->handle, 0,
+            p_desc->uuid, 0 /* properties */, 0 /* incl_srvc_handle */, false);
+      }
+    }
+
+    if (!p_cur_srvc->included_svc || list_is_empty(p_cur_srvc->included_svc))
+      continue;
+
+    for (list_node_t* an = list_begin(p_cur_srvc->included_svc);
+         an != list_end(p_cur_srvc->included_svc); an = list_next(an)) {
+      tBTA_GATTC_INCLUDED_SVC* p_isvc = (tBTA_GATTC_INCLUDED_SVC*)list_node(an);
+
+      bta_gattc_fill_nv_attr(&nv_attr[i++], BTA_GATTC_ATTR_TYPE_INCL_SRVC,
+                             p_isvc->handle, 0, p_isvc->uuid,
+                             0 /* properties */,
+                             p_isvc->included_service->s_handle, false);
+    }
+  }
+
+  bta_gattc_cache_write(p_srvc_cb->server_bda, db_size, nv_attr);
+  osi_free(nv_attr);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_cache_load
+ *
+ * Description      Load GATT cache from storage for server.
+ *
+ * Parameter        p_clcb: pointer to server clcb, that will
+ *                          be filled from storage
+ * Returns          true on success, false otherwise
+ *
+ ******************************************************************************/
+bool bta_gattc_cache_load(tBTA_GATTC_CLCB* p_clcb) {
+  char fname[255] = {0};
+  bta_gattc_generate_cache_file_name(fname, sizeof(fname),
+                                     p_clcb->p_srcb->server_bda);
+
+  FILE* fd = fopen(fname, "rb");
+  if (!fd) {
+    APPL_TRACE_ERROR("%s: can't open GATT cache file %s for reading, error: %s",
+                     __func__, fname, strerror(errno));
+    return false;
+  }
+
+  uint16_t cache_ver = 0;
+  tBTA_GATTC_NV_ATTR* attr = NULL;
+  bool success = false;
+  uint16_t num_attr = 0;
+
+  if (fread(&cache_ver, sizeof(uint16_t), 1, fd) != 1) {
+    APPL_TRACE_ERROR("%s: can't read GATT cache version from: %s", __func__,
+                     fname);
+    goto done;
+  }
+
+  if (cache_ver != GATT_CACHE_VERSION) {
+    APPL_TRACE_ERROR("%s: wrong GATT cache version: %s", __func__, fname);
+    goto done;
+  }
+
+  if (fread(&num_attr, sizeof(uint16_t), 1, fd) != 1) {
+    APPL_TRACE_ERROR("%s: can't read number of GATT attributes: %s", __func__,
+                     fname);
+    goto done;
+  }
+
+  attr = (tBTA_GATTC_NV_ATTR*)osi_malloc(sizeof(tBTA_GATTC_NV_ATTR) * num_attr);
+
+  if (fread(attr, sizeof(tBTA_GATTC_NV_ATTR), 0xFF, fd) != num_attr) {
+    APPL_TRACE_ERROR("%s: can't read GATT attributes: %s", __func__, fname);
+    goto done;
+  }
+
+  bta_gattc_rebuild_cache(p_clcb->p_srcb, num_attr, attr);
+
+  success = true;
+
+done:
+  osi_free(attr);
+  fclose(fd);
+  return success;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_cache_write
+ *
+ * Description      This callout function is executed by GATT when a server
+ *                  cache is available to save.
+ *
+ * Parameter        server_bda: server bd address of this cache belongs to
+ *                  num_attr: number of attribute to be save.
+ *                  attr: pointer to the list of attributes to save.
+ * Returns
+ *
+ ******************************************************************************/
+static void bta_gattc_cache_write(BD_ADDR server_bda, uint16_t num_attr,
+                                  tBTA_GATTC_NV_ATTR* attr) {
+  char fname[255] = {0};
+  bta_gattc_generate_cache_file_name(fname, sizeof(fname), server_bda);
+
+  FILE* fd = fopen(fname, "wb");
+  if (!fd) {
+    APPL_TRACE_ERROR("%s: can't open GATT cache file for writing: %s", __func__,
+                     fname);
+    return;
+  }
+
+  uint16_t cache_ver = GATT_CACHE_VERSION;
+  if (fwrite(&cache_ver, sizeof(uint16_t), 1, fd) != 1) {
+    APPL_TRACE_ERROR("%s: can't write GATT cache version: %s", __func__, fname);
+    fclose(fd);
+    return;
+  }
+
+  if (fwrite(&num_attr, sizeof(uint16_t), 1, fd) != 1) {
+    APPL_TRACE_ERROR("%s: can't write GATT cache attribute count: %s", __func__,
+                     fname);
+    fclose(fd);
+    return;
+  }
+
+  if (fwrite(attr, sizeof(tBTA_GATTC_NV_ATTR), num_attr, fd) != num_attr) {
+    APPL_TRACE_ERROR("%s: can't write GATT cache attributes: %s", __func__,
+                     fname);
+    fclose(fd);
+    return;
+  }
+
+  fclose(fd);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_cache_reset
+ *
+ * Description      This callout function is executed by GATTC to reset cache in
+ *                  application
+ *
+ * Parameter        server_bda: server bd address of this cache belongs to
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+void bta_gattc_cache_reset(BD_ADDR server_bda) {
+  BTIF_TRACE_DEBUG("%s", __func__);
+  char fname[255] = {0};
+  bta_gattc_generate_cache_file_name(fname, sizeof(fname), server_bda);
+  unlink(fname);
+}
+#endif /* BTA_GATT_INCLUDED */
diff --git a/bt/bta/gatt/bta_gattc_int.h b/bt/bta/gatt/bta_gattc_int.h
new file mode 100644
index 0000000..53c5670
--- /dev/null
+++ b/bt/bta/gatt/bta_gattc_int.h
@@ -0,0 +1,504 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 is the private file for the file transfer client (FTC).
+ *
+ ******************************************************************************/
+#ifndef BTA_GATTC_INT_H
+#define BTA_GATTC_INT_H
+
+#include "bt_target.h"
+
+#include "bta_gatt_api.h"
+#include "bta_sys.h"
+#include "osi/include/fixed_queue.h"
+
+#include "bt_common.h"
+
+/*****************************************************************************
+ *  Constants and data types
+ ****************************************************************************/
+enum {
+  BTA_GATTC_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_GATTC),
+  BTA_GATTC_INT_OPEN_FAIL_EVT,
+  BTA_GATTC_API_CANCEL_OPEN_EVT,
+  BTA_GATTC_INT_CANCEL_OPEN_OK_EVT,
+
+  BTA_GATTC_API_READ_EVT,
+  BTA_GATTC_API_WRITE_EVT,
+  BTA_GATTC_API_EXEC_EVT,
+  BTA_GATTC_API_CFG_MTU_EVT,
+
+  BTA_GATTC_API_CLOSE_EVT,
+
+  BTA_GATTC_API_SEARCH_EVT,
+  BTA_GATTC_API_CONFIRM_EVT,
+  BTA_GATTC_API_READ_MULTI_EVT,
+  BTA_GATTC_API_REFRESH_EVT,
+
+  BTA_GATTC_INT_CONN_EVT,
+  BTA_GATTC_INT_DISCOVER_EVT,
+  BTA_GATTC_DISCOVER_CMPL_EVT,
+  BTA_GATTC_OP_CMPL_EVT,
+  BTA_GATTC_INT_DISCONN_EVT,
+
+  BTA_GATTC_INT_START_IF_EVT,
+  BTA_GATTC_API_REG_EVT,
+  BTA_GATTC_API_DEREG_EVT,
+  BTA_GATTC_API_DISABLE_EVT,
+  BTA_GATTC_ENC_CMPL_EVT
+};
+typedef uint16_t tBTA_GATTC_INT_EVT;
+
+#define BTA_GATTC_SERVICE_CHANGED_LEN 4
+
+/* max client application GATTC can support */
+#ifndef BTA_GATTC_CL_MAX
+#define BTA_GATTC_CL_MAX 32
+#endif
+
+/* max known devices GATTC can support */
+#ifndef BTA_GATTC_KNOWN_SR_MAX
+#define BTA_GATTC_KNOWN_SR_MAX 10
+#endif
+
+#define BTA_GATTC_CONN_MAX GATT_MAX_PHY_CHANNEL
+
+#ifndef BTA_GATTC_CLCB_MAX
+#define BTA_GATTC_CLCB_MAX GATT_CL_MAX_LCB
+#endif
+
+#define BTA_GATTC_WRITE_PREPARE GATT_WRITE_PREPARE
+
+/* internal strucutre for GATTC register API  */
+typedef struct {
+  BT_HDR hdr;
+  tBT_UUID app_uuid;
+  tBTA_GATTC_CBACK* p_cback;
+} tBTA_GATTC_API_REG;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_GATTC_IF client_if;
+} tBTA_GATTC_INT_START_IF;
+
+typedef tBTA_GATTC_INT_START_IF tBTA_GATTC_API_DEREG;
+typedef tBTA_GATTC_INT_START_IF tBTA_GATTC_INT_DEREG;
+
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR remote_bda;
+  tBTA_GATTC_IF client_if;
+  bool is_direct;
+  tBTA_TRANSPORT transport;
+} tBTA_GATTC_API_OPEN;
+
+typedef tBTA_GATTC_API_OPEN tBTA_GATTC_API_CANCEL_OPEN;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_GATT_AUTH_REQ auth_req;
+  uint16_t handle;
+  tBTA_GATTC_EVT cmpl_evt;
+  GATT_READ_OP_CB read_cb;
+  void* read_cb_data;
+} tBTA_GATTC_API_READ;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_GATT_AUTH_REQ auth_req;
+  uint16_t handle;
+  tBTA_GATTC_WRITE_TYPE write_type;
+  uint16_t offset;
+  uint16_t len;
+  uint8_t* p_value;
+  GATT_WRITE_OP_CB write_cb;
+  void* write_cb_data;
+} tBTA_GATTC_API_WRITE;
+
+typedef struct {
+  BT_HDR hdr;
+  bool is_execute;
+} tBTA_GATTC_API_EXEC;
+
+typedef struct {
+  BT_HDR hdr;
+  uint16_t handle;
+} tBTA_GATTC_API_CONFIRM;
+
+typedef tGATT_CL_COMPLETE tBTA_GATTC_CMPL;
+
+typedef struct {
+  BT_HDR hdr;
+  uint8_t op_code;
+  tGATT_STATUS status;
+  tBTA_GATTC_CMPL* p_cmpl;
+} tBTA_GATTC_OP_CMPL;
+
+typedef struct {
+  BT_HDR hdr;
+  tBT_UUID* p_srvc_uuid;
+} tBTA_GATTC_API_SEARCH;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_GATT_AUTH_REQ auth_req;
+  uint8_t num_attr;
+  uint16_t handles[GATT_MAX_READ_MULTI_HANDLES];
+} tBTA_GATTC_API_READ_MULTI;
+
+typedef struct {
+  BT_HDR hdr;
+  uint16_t mtu;
+} tBTA_GATTC_API_CFG_MTU;
+
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR remote_bda;
+  tBTA_GATTC_IF client_if;
+  uint8_t role;
+  tBT_TRANSPORT transport;
+  tGATT_DISCONN_REASON reason;
+} tBTA_GATTC_INT_CONN;
+
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR remote_bda;
+  tBTA_GATTC_IF client_if;
+} tBTA_GATTC_ENC_CMPL;
+
+typedef union {
+  BT_HDR hdr;
+  tBTA_GATTC_API_REG api_reg;
+  tBTA_GATTC_API_DEREG api_dereg;
+  tBTA_GATTC_API_OPEN api_conn;
+  tBTA_GATTC_API_CANCEL_OPEN api_cancel_conn;
+  tBTA_GATTC_API_READ api_read;
+  tBTA_GATTC_API_SEARCH api_search;
+  tBTA_GATTC_API_WRITE api_write;
+  tBTA_GATTC_API_CONFIRM api_confirm;
+  tBTA_GATTC_API_EXEC api_exec;
+  tBTA_GATTC_API_READ_MULTI api_read_multi;
+  tBTA_GATTC_API_CFG_MTU api_mtu;
+  tBTA_GATTC_OP_CMPL op_cmpl;
+  tBTA_GATTC_INT_CONN int_conn;
+  tBTA_GATTC_ENC_CMPL enc_cmpl;
+
+  tBTA_GATTC_INT_START_IF int_start_if;
+  tBTA_GATTC_INT_DEREG int_dereg;
+
+} tBTA_GATTC_DATA;
+
+/* GATT server cache on the client */
+
+typedef struct {
+  tBT_UUID uuid;
+  uint16_t s_handle;
+  uint16_t e_handle;
+  // this field is set only for characteristic
+  uint16_t char_decl_handle;
+  bool is_primary;
+  tBTA_GATT_CHAR_PROP property;
+} tBTA_GATTC_ATTR_REC;
+
+#define BTA_GATTC_MAX_CACHE_CHAR 40
+#define BTA_GATTC_ATTR_LIST_SIZE \
+  (BTA_GATTC_MAX_CACHE_CHAR * sizeof(tBTA_GATTC_ATTR_REC))
+
+#ifndef BTA_GATTC_CACHE_SRVR_SIZE
+#define BTA_GATTC_CACHE_SRVR_SIZE 600
+#endif
+
+enum {
+  BTA_GATTC_IDLE_ST = 0, /* Idle  */
+  BTA_GATTC_W4_CONN_ST,  /* Wait for connection -  (optional) */
+  BTA_GATTC_CONN_ST,     /* connected state */
+  BTA_GATTC_DISCOVER_ST  /* discover is in progress */
+};
+typedef uint8_t tBTA_GATTC_STATE;
+
+typedef struct {
+  bool in_use;
+  BD_ADDR server_bda;
+  bool connected;
+
+#define BTA_GATTC_SERV_IDLE 0
+#define BTA_GATTC_SERV_LOAD 1
+#define BTA_GATTC_SERV_SAVE 2
+#define BTA_GATTC_SERV_DISC 3
+#define BTA_GATTC_SERV_DISC_ACT 4
+
+  uint8_t state;
+
+  list_t* p_srvc_cache; /* list of tBTA_GATTC_SERVICE */
+  uint8_t update_count; /* indication received */
+  uint8_t num_clcb;     /* number of associated CLCB */
+
+  tBTA_GATTC_ATTR_REC* p_srvc_list;
+  uint8_t cur_srvc_idx;
+  uint8_t cur_char_idx;
+  uint8_t next_avail_idx;
+  uint8_t total_srvc;
+  uint8_t total_char;
+
+  uint8_t srvc_hdl_chg; /* service handle change indication pending */
+  uint16_t attr_index;  /* cahce NV saving/loading attribute index */
+
+  uint16_t mtu;
+} tBTA_GATTC_SERV;
+
+#ifndef BTA_GATTC_NOTIF_REG_MAX
+#define BTA_GATTC_NOTIF_REG_MAX 15
+#endif
+
+typedef struct {
+  bool in_use;
+  BD_ADDR remote_bda;
+  uint16_t handle;
+} tBTA_GATTC_NOTIF_REG;
+
+typedef struct {
+  tBTA_GATTC_CBACK* p_cback;
+  bool in_use;
+  tBTA_GATTC_IF
+      client_if;    /* client interface with BTE stack for this application */
+  uint8_t num_clcb; /* number of associated CLCB */
+  bool dereg_pending;
+  tBT_UUID app_uuid;
+  tBTA_GATTC_NOTIF_REG notif_reg[BTA_GATTC_NOTIF_REG_MAX];
+} tBTA_GATTC_RCB;
+
+/* client channel is a mapping between a BTA client(cl_id) and a remote BD
+ * address */
+typedef struct {
+  uint16_t bta_conn_id; /* client channel ID, unique for clcb */
+  BD_ADDR bda;
+  tBTA_TRANSPORT transport; /* channel transport */
+  tBTA_GATTC_RCB* p_rcb;    /* pointer to the registration CB */
+  tBTA_GATTC_SERV* p_srcb;  /* server cache CB */
+  tBTA_GATTC_DATA* p_q_cmd; /* command in queue waiting for execution */
+
+#define BTA_GATTC_NO_SCHEDULE 0
+#define BTA_GATTC_DISC_WAITING 0x01
+#define BTA_GATTC_REQ_WAITING 0x10
+
+  uint8_t auto_update; /* auto update is waiting */
+  bool disc_active;
+  bool in_use;
+  tBTA_GATTC_STATE state;
+  tBTA_GATT_STATUS status;
+  uint16_t reason;
+} tBTA_GATTC_CLCB;
+
+/* back ground connection tracking information */
+#if GATT_MAX_APPS <= 8
+typedef uint8_t tBTA_GATTC_CIF_MASK;
+#elif GATT_MAX_APPS <= 16
+typedef uint16_t tBTA_GATTC_CIF_MASK;
+#elif GATT_MAX_APPS <= 32
+typedef uint32_t tBTA_GATTC_CIF_MASK;
+#endif
+
+typedef struct {
+  bool in_use;
+  BD_ADDR remote_bda;
+  tBTA_GATTC_CIF_MASK cif_mask;
+
+} tBTA_GATTC_BG_TCK;
+
+typedef struct {
+  bool in_use;
+  BD_ADDR remote_bda;
+} tBTA_GATTC_CONN;
+
+enum {
+  BTA_GATTC_STATE_DISABLED,
+  BTA_GATTC_STATE_ENABLING,
+  BTA_GATTC_STATE_ENABLED,
+  BTA_GATTC_STATE_DISABLING
+};
+
+typedef struct {
+  uint8_t state;
+
+  tBTA_GATTC_CONN conn_track[BTA_GATTC_CONN_MAX];
+  tBTA_GATTC_BG_TCK bg_track[BTA_GATTC_KNOWN_SR_MAX];
+  tBTA_GATTC_RCB cl_rcb[BTA_GATTC_CL_MAX];
+
+  tBTA_GATTC_CLCB clcb[BTA_GATTC_CLCB_MAX];
+  tBTA_GATTC_SERV known_server[BTA_GATTC_KNOWN_SR_MAX];
+} tBTA_GATTC_CB;
+
+/*****************************************************************************
+ *  Global data
+ ****************************************************************************/
+
+/* GATTC control block */
+extern tBTA_GATTC_CB bta_gattc_cb;
+
+/*****************************************************************************
+ *  Function prototypes
+ ****************************************************************************/
+extern bool bta_gattc_hdl_event(BT_HDR* p_msg);
+extern bool bta_gattc_sm_execute(tBTA_GATTC_CLCB* p_clcb, uint16_t event,
+                                 tBTA_GATTC_DATA* p_data);
+
+/* function processed outside SM */
+extern void bta_gattc_disable();
+extern void bta_gattc_register(tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_start_if(tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_process_api_open(tBTA_GATTC_DATA* p_msg);
+extern void bta_gattc_process_api_open_cancel(tBTA_GATTC_DATA* p_msg);
+extern void bta_gattc_deregister(tBTA_GATTC_RCB* p_clreg);
+extern void bta_gattc_process_enc_cmpl(tBTA_GATTC_DATA* p_msg);
+
+/* function within state machine */
+extern void bta_gattc_open(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_open_fail(tBTA_GATTC_CLCB* p_clcb,
+                                tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_open_error(tBTA_GATTC_CLCB* p_clcb,
+                                 tBTA_GATTC_DATA* p_data);
+
+extern void bta_gattc_cancel_open(tBTA_GATTC_CLCB* p_clcb,
+                                  tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_cancel_open_ok(tBTA_GATTC_CLCB* p_clcb,
+                                     tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_cancel_open_error(tBTA_GATTC_CLCB* p_clcb,
+                                        tBTA_GATTC_DATA* p_data);
+
+extern void bta_gattc_conn(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+
+extern void bta_gattc_close(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_close_fail(tBTA_GATTC_CLCB* p_clcb,
+                                 tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_disc_close(tBTA_GATTC_CLCB* p_clcb,
+                                 tBTA_GATTC_DATA* p_data);
+
+extern void bta_gattc_start_discover(tBTA_GATTC_CLCB* p_clcb,
+                                     tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB* p_clcb,
+                                tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_read(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_write(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_op_cmpl(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_q_cmd(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_search(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_fail(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_confirm(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_execute(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_read_multi(tBTA_GATTC_CLCB* p_clcb,
+                                 tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_ci_open(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_ci_close(tBTA_GATTC_CLCB* p_clcb,
+                               tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_ignore_op_cmpl(tBTA_GATTC_CLCB* p_clcb,
+                                     tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_restart_discover(tBTA_GATTC_CLCB* p_clcb,
+                                       tBTA_GATTC_DATA* p_msg);
+extern void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN* p_data,
+                                   tBTA_GATTC_RCB* p_clreg);
+extern void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN* p_data);
+extern void bta_gattc_send_open_cback(tBTA_GATTC_RCB* p_clreg,
+                                      tBTA_GATT_STATUS status,
+                                      BD_ADDR remote_bda, uint16_t conn_id,
+                                      tBTA_TRANSPORT transport, uint16_t mtu);
+extern void bta_gattc_process_api_refresh(tBTA_GATTC_DATA* p_msg);
+extern void bta_gattc_cfg_mtu(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+#if (BLE_INCLUDED == TRUE)
+extern void bta_gattc_listen(tBTA_GATTC_DATA* p_msg);
+extern void bta_gattc_broadcast(tBTA_GATTC_DATA* p_msg);
+#endif
+/* utility functions */
+extern tBTA_GATTC_CLCB* bta_gattc_find_clcb_by_cif(uint8_t client_if,
+                                                   BD_ADDR remote_bda,
+                                                   tBTA_TRANSPORT transport);
+extern tBTA_GATTC_CLCB* bta_gattc_find_clcb_by_conn_id(uint16_t conn_id);
+extern tBTA_GATTC_CLCB* bta_gattc_clcb_alloc(tBTA_GATTC_IF client_if,
+                                             BD_ADDR remote_bda,
+                                             tBTA_TRANSPORT transport);
+extern void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB* p_clcb);
+extern tBTA_GATTC_CLCB* bta_gattc_find_alloc_clcb(tBTA_GATTC_IF client_if,
+                                                  BD_ADDR remote_bda,
+                                                  tBTA_TRANSPORT transport);
+extern tBTA_GATTC_RCB* bta_gattc_cl_get_regcb(uint8_t client_if);
+extern tBTA_GATTC_SERV* bta_gattc_find_srcb(BD_ADDR bda);
+extern tBTA_GATTC_SERV* bta_gattc_srcb_alloc(BD_ADDR bda);
+extern tBTA_GATTC_SERV* bta_gattc_find_scb_by_cid(uint16_t conn_id);
+extern tBTA_GATTC_CLCB* bta_gattc_find_int_conn_clcb(tBTA_GATTC_DATA* p_msg);
+extern tBTA_GATTC_CLCB* bta_gattc_find_int_disconn_clcb(tBTA_GATTC_DATA* p_msg);
+
+extern bool bta_gattc_enqueue(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+
+extern bool bta_gattc_uuid_compare(const tBT_UUID* p_src, const tBT_UUID* p_tar,
+                                   bool is_precise);
+extern bool bta_gattc_check_notif_registry(tBTA_GATTC_RCB* p_clreg,
+                                           tBTA_GATTC_SERV* p_srcb,
+                                           tBTA_GATTC_NOTIFY* p_notify);
+extern bool bta_gattc_mark_bg_conn(tBTA_GATTC_IF client_if,
+                                   BD_ADDR_PTR remote_bda, bool add);
+extern bool bta_gattc_check_bg_conn(tBTA_GATTC_IF client_if, BD_ADDR remote_bda,
+                                    uint8_t role);
+extern uint8_t bta_gattc_num_reg_app(void);
+extern void bta_gattc_clear_notif_registration(tBTA_GATTC_SERV* p_srcb,
+                                               uint16_t conn_id,
+                                               uint16_t start_handle,
+                                               uint16_t end_handle);
+extern tBTA_GATTC_SERV* bta_gattc_find_srvr_cache(BD_ADDR bda);
+
+/* discovery functions */
+extern void bta_gattc_disc_res_cback(uint16_t conn_id,
+                                     tGATT_DISC_TYPE disc_type,
+                                     tGATT_DISC_RES* p_data);
+extern void bta_gattc_disc_cmpl_cback(uint16_t conn_id,
+                                      tGATT_DISC_TYPE disc_type,
+                                      tGATT_STATUS status);
+extern tBTA_GATT_STATUS bta_gattc_discover_procedure(
+    uint16_t conn_id, tBTA_GATTC_SERV* p_server_cb, uint8_t disc_type);
+extern tBTA_GATT_STATUS bta_gattc_discover_pri_service(
+    uint16_t conn_id, tBTA_GATTC_SERV* p_server_cb, uint8_t disc_type);
+extern void bta_gattc_search_service(tBTA_GATTC_CLCB* p_clcb, tBT_UUID* p_uuid);
+extern const list_t* bta_gattc_get_services(uint16_t conn_id);
+extern const tBTA_GATTC_SERVICE* bta_gattc_get_service_for_handle(
+    uint16_t conn_id, uint16_t handle);
+tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic_srcb(
+    tBTA_GATTC_SERV* p_srcb, uint16_t handle);
+extern tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic(uint16_t conn_id,
+                                                               uint16_t handle);
+extern tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor(uint16_t conn_id,
+                                                       uint16_t handle);
+extern void bta_gattc_get_gatt_db(uint16_t conn_id, uint16_t start_handle,
+                                  uint16_t end_handle, btgatt_db_element_t** db,
+                                  int* count);
+extern tBTA_GATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV* p_srvc_cb);
+extern void bta_gattc_rebuild_cache(tBTA_GATTC_SERV* p_srcv, uint16_t num_attr,
+                                    tBTA_GATTC_NV_ATTR* attr);
+extern void bta_gattc_cache_save(tBTA_GATTC_SERV* p_srvc_cb, uint16_t conn_id);
+extern void bta_gattc_reset_discover_st(tBTA_GATTC_SERV* p_srcb,
+                                        tBTA_GATT_STATUS status);
+
+extern tBTA_GATTC_CONN* bta_gattc_conn_alloc(BD_ADDR remote_bda);
+extern tBTA_GATTC_CONN* bta_gattc_conn_find(BD_ADDR remote_bda);
+extern tBTA_GATTC_CONN* bta_gattc_conn_find_alloc(BD_ADDR remote_bda);
+extern bool bta_gattc_conn_dealloc(BD_ADDR remote_bda);
+
+extern bool bta_gattc_cache_load(tBTA_GATTC_CLCB* p_clcb);
+extern void bta_gattc_cache_reset(BD_ADDR server_bda);
+
+#endif /* BTA_GATTC_INT_H */
diff --git a/bt/bta/gatt/bta_gattc_main.cc b/bt/bta/gatt/bta_gattc_main.cc
new file mode 100644
index 0000000..b175a2d
--- /dev/null
+++ b/bt/bta/gatt/bta_gattc_main.cc
@@ -0,0 +1,517 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 GATT client main functions and state machine.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if (BTA_GATT_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_gattc_int.h"
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+
+/* state machine action enumeration list */
+enum {
+  BTA_GATTC_OPEN,
+  BTA_GATTC_OPEN_FAIL,
+  BTA_GATTC_OPEN_ERROR,
+  BTA_GATTC_CANCEL_OPEN,
+  BTA_GATTC_CANCEL_OPEN_OK,
+  BTA_GATTC_CANCEL_OPEN_ERROR,
+  BTA_GATTC_CONN,
+  BTA_GATTC_START_DISCOVER,
+  BTA_GATTC_DISC_CMPL,
+
+  BTA_GATTC_Q_CMD,
+  BTA_GATTC_CLOSE,
+  BTA_GATTC_CLOSE_FAIL,
+  BTA_GATTC_READ,
+  BTA_GATTC_WRITE,
+
+  BTA_GATTC_OP_CMPL,
+  BTA_GATTC_SEARCH,
+  BTA_GATTC_FAIL,
+  BTA_GATTC_CONFIRM,
+  BTA_GATTC_EXEC,
+  BTA_GATTC_READ_MULTI,
+  BTA_GATTC_IGNORE_OP_CMPL,
+  BTA_GATTC_DISC_CLOSE,
+  BTA_GATTC_RESTART_DISCOVER,
+  BTA_GATTC_CFG_MTU,
+
+  BTA_GATTC_IGNORE
+};
+/* type for action functions */
+typedef void (*tBTA_GATTC_ACTION)(tBTA_GATTC_CLCB* p_clcb,
+                                  tBTA_GATTC_DATA* p_data);
+
+/* action function list */
+const tBTA_GATTC_ACTION bta_gattc_action[] = {bta_gattc_open,
+                                              bta_gattc_open_fail,
+                                              bta_gattc_open_error,
+                                              bta_gattc_cancel_open,
+                                              bta_gattc_cancel_open_ok,
+                                              bta_gattc_cancel_open_error,
+                                              bta_gattc_conn,
+                                              bta_gattc_start_discover,
+                                              bta_gattc_disc_cmpl,
+
+                                              bta_gattc_q_cmd,
+                                              bta_gattc_close,
+                                              bta_gattc_close_fail,
+                                              bta_gattc_read,
+                                              bta_gattc_write,
+
+                                              bta_gattc_op_cmpl,
+                                              bta_gattc_search,
+                                              bta_gattc_fail,
+                                              bta_gattc_confirm,
+                                              bta_gattc_execute,
+                                              bta_gattc_read_multi,
+                                              bta_gattc_ignore_op_cmpl,
+                                              bta_gattc_disc_close,
+                                              bta_gattc_restart_discover,
+                                              bta_gattc_cfg_mtu};
+
+/* state table information */
+#define BTA_GATTC_ACTIONS 1    /* number of actions */
+#define BTA_GATTC_NEXT_STATE 1 /* position of next state */
+#define BTA_GATTC_NUM_COLS 2   /* number of columns in state tables */
+
+/* state table for idle state */
+static const uint8_t bta_gattc_st_idle[][BTA_GATTC_NUM_COLS] = {
+    /* Event                            Action 1                  Next state */
+    /* BTA_GATTC_API_OPEN_EVT           */ {BTA_GATTC_OPEN,
+                                            BTA_GATTC_W4_CONN_ST},
+    /* BTA_GATTC_INT_OPEN_FAIL_EVT      */ {BTA_GATTC_IGNORE,
+                                            BTA_GATTC_IDLE_ST},
+    /* BTA_GATTC_API_CANCEL_OPEN_EVT    */ {BTA_GATTC_IGNORE,
+                                            BTA_GATTC_IDLE_ST},
+    /* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_IGNORE,
+                                            BTA_GATTC_IDLE_ST},
+
+    /* BTA_GATTC_API_READ_EVT           */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST},
+    /* BTA_GATTC_API_WRITE_EVT          */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST},
+    /* BTA_GATTC_API_EXEC_EVT           */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST},
+    /* BTA_GATTC_API_CFG_MTU_EVT        */ {BTA_GATTC_IGNORE,
+                                            BTA_GATTC_IDLE_ST},
+
+    /* BTA_GATTC_API_CLOSE_EVT          */ {BTA_GATTC_CLOSE_FAIL,
+                                            BTA_GATTC_IDLE_ST},
+
+    /* BTA_GATTC_API_SEARCH_EVT         */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST},
+    /* BTA_GATTC_API_CONFIRM_EVT        */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST},
+    /* BTA_GATTC_API_READ_MULTI_EVT     */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST},
+    /* BTA_GATTC_API_REFRESH_EVT        */ {BTA_GATTC_IGNORE,
+                                            BTA_GATTC_IDLE_ST},
+
+    /* BTA_GATTC_INT_CONN_EVT           */ {BTA_GATTC_CONN, BTA_GATTC_CONN_ST},
+    /* BTA_GATTC_INT_DISCOVER_EVT       */ {BTA_GATTC_IGNORE,
+                                            BTA_GATTC_IDLE_ST},
+    /* BTA_GATTC_DISCOVER_CMPL_EVT      */ {BTA_GATTC_IGNORE,
+                                            BTA_GATTC_IDLE_ST},
+    /* BTA_GATTC_OP_CMPL_EVT            */ {BTA_GATTC_IGNORE,
+                                            BTA_GATTC_IDLE_ST},
+    /* BTA_GATTC_INT_DISCONN_EVT       */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST},
+
+};
+
+/* state table for wait for open state */
+static const uint8_t bta_gattc_st_w4_conn[][BTA_GATTC_NUM_COLS] = {
+    /* Event                            Action 1 Next state */
+    /* BTA_GATTC_API_OPEN_EVT           */ {BTA_GATTC_OPEN,
+                                            BTA_GATTC_W4_CONN_ST},
+    /* BTA_GATTC_INT_OPEN_FAIL_EVT      */ {BTA_GATTC_OPEN_FAIL,
+                                            BTA_GATTC_IDLE_ST},
+    /* BTA_GATTC_API_CANCEL_OPEN_EVT    */ {BTA_GATTC_CANCEL_OPEN,
+                                            BTA_GATTC_W4_CONN_ST},
+    /* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_CANCEL_OPEN_OK,
+                                            BTA_GATTC_IDLE_ST},
+
+    /* BTA_GATTC_API_READ_EVT           */ {BTA_GATTC_FAIL,
+                                            BTA_GATTC_W4_CONN_ST},
+    /* BTA_GATTC_API_WRITE_EVT          */ {BTA_GATTC_FAIL,
+                                            BTA_GATTC_W4_CONN_ST},
+    /* BTA_GATTC_API_EXEC_EVT           */ {BTA_GATTC_FAIL,
+                                            BTA_GATTC_W4_CONN_ST},
+    /* BTA_GATTC_API_CFG_MTU_EVT        */ {BTA_GATTC_IGNORE,
+                                            BTA_GATTC_W4_CONN_ST},
+
+    /* BTA_GATTC_API_CLOSE_EVT          */ {BTA_GATTC_CANCEL_OPEN,
+                                            BTA_GATTC_W4_CONN_ST},
+
+    /* BTA_GATTC_API_SEARCH_EVT         */ {BTA_GATTC_FAIL,
+                                            BTA_GATTC_W4_CONN_ST},
+    /* BTA_GATTC_API_CONFIRM_EVT        */ {BTA_GATTC_FAIL,
+                                            BTA_GATTC_W4_CONN_ST},
+    /* BTA_GATTC_API_READ_MULTI_EVT     */ {BTA_GATTC_FAIL,
+                                            BTA_GATTC_W4_CONN_ST},
+    /* BTA_GATTC_API_REFRESH_EVT        */ {BTA_GATTC_IGNORE,
+                                            BTA_GATTC_W4_CONN_ST},
+
+    /* BTA_GATTC_INT_CONN_EVT           */ {BTA_GATTC_CONN, BTA_GATTC_CONN_ST},
+    /* BTA_GATTC_INT_DISCOVER_EVT       */ {BTA_GATTC_IGNORE,
+                                            BTA_GATTC_W4_CONN_ST},
+    /* BTA_GATTC_DISCOVER_CMPL_EVT       */ {BTA_GATTC_IGNORE,
+                                             BTA_GATTC_W4_CONN_ST},
+    /* BTA_GATTC_OP_CMPL_EVT            */ {BTA_GATTC_IGNORE,
+                                            BTA_GATTC_W4_CONN_ST},
+    /* BTA_GATTC_INT_DISCONN_EVT      */ {BTA_GATTC_OPEN_FAIL,
+                                          BTA_GATTC_IDLE_ST},
+
+};
+
+/* state table for open state */
+static const uint8_t bta_gattc_st_connected[][BTA_GATTC_NUM_COLS] = {
+    /* Event                            Action 1 Next state */
+    /* BTA_GATTC_API_OPEN_EVT           */ {BTA_GATTC_OPEN, BTA_GATTC_CONN_ST},
+    /* BTA_GATTC_INT_OPEN_FAIL_EVT      */ {BTA_GATTC_IGNORE,
+                                            BTA_GATTC_CONN_ST},
+    /* BTA_GATTC_API_CANCEL_OPEN_EVT    */ {BTA_GATTC_CANCEL_OPEN_ERROR,
+                                            BTA_GATTC_CONN_ST},
+    /* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_IGNORE,
+                                            BTA_GATTC_CONN_ST},
+
+    /* BTA_GATTC_API_READ_EVT           */ {BTA_GATTC_READ, BTA_GATTC_CONN_ST},
+    /* BTA_GATTC_API_WRITE_EVT          */ {BTA_GATTC_WRITE, BTA_GATTC_CONN_ST},
+    /* BTA_GATTC_API_EXEC_EVT           */ {BTA_GATTC_EXEC, BTA_GATTC_CONN_ST},
+    /* BTA_GATTC_API_CFG_MTU_EVT        */ {BTA_GATTC_CFG_MTU,
+                                            BTA_GATTC_CONN_ST},
+
+    /* BTA_GATTC_API_CLOSE_EVT          */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST},
+
+    /* BTA_GATTC_API_SEARCH_EVT         */ {BTA_GATTC_SEARCH,
+                                            BTA_GATTC_CONN_ST},
+    /* BTA_GATTC_API_CONFIRM_EVT        */ {BTA_GATTC_CONFIRM,
+                                            BTA_GATTC_CONN_ST},
+    /* BTA_GATTC_API_READ_MULTI_EVT     */ {BTA_GATTC_READ_MULTI,
+                                            BTA_GATTC_CONN_ST},
+    /* BTA_GATTC_API_REFRESH_EVT        */ {BTA_GATTC_IGNORE,
+                                            BTA_GATTC_CONN_ST},
+
+    /* BTA_GATTC_INT_CONN_EVT           */ {BTA_GATTC_IGNORE,
+                                            BTA_GATTC_CONN_ST},
+    /* BTA_GATTC_INT_DISCOVER_EVT       */ {BTA_GATTC_START_DISCOVER,
+                                            BTA_GATTC_DISCOVER_ST},
+    /* BTA_GATTC_DISCOVER_CMPL_EVT       */ {BTA_GATTC_IGNORE,
+                                             BTA_GATTC_CONN_ST},
+    /* BTA_GATTC_OP_CMPL_EVT            */ {BTA_GATTC_OP_CMPL,
+                                            BTA_GATTC_CONN_ST},
+
+    /* BTA_GATTC_INT_DISCONN_EVT        */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST},
+
+};
+
+/* state table for discover state */
+static const uint8_t bta_gattc_st_discover[][BTA_GATTC_NUM_COLS] = {
+    /* Event                            Action 1 Next state */
+    /* BTA_GATTC_API_OPEN_EVT           */ {BTA_GATTC_OPEN,
+                                            BTA_GATTC_DISCOVER_ST},
+    /* BTA_GATTC_INT_OPEN_FAIL_EVT      */ {BTA_GATTC_IGNORE,
+                                            BTA_GATTC_DISCOVER_ST},
+    /* BTA_GATTC_API_CANCEL_OPEN_EVT    */ {BTA_GATTC_CANCEL_OPEN_ERROR,
+                                            BTA_GATTC_DISCOVER_ST},
+    /* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_FAIL,
+                                            BTA_GATTC_DISCOVER_ST},
+
+    /* BTA_GATTC_API_READ_EVT           */ {BTA_GATTC_Q_CMD,
+                                            BTA_GATTC_DISCOVER_ST},
+    /* BTA_GATTC_API_WRITE_EVT          */ {BTA_GATTC_Q_CMD,
+                                            BTA_GATTC_DISCOVER_ST},
+    /* BTA_GATTC_API_EXEC_EVT           */ {BTA_GATTC_Q_CMD,
+                                            BTA_GATTC_DISCOVER_ST},
+    /* BTA_GATTC_API_CFG_MTU_EVT        */ {BTA_GATTC_Q_CMD,
+                                            BTA_GATTC_DISCOVER_ST},
+
+    /* BTA_GATTC_API_CLOSE_EVT          */ {BTA_GATTC_DISC_CLOSE,
+                                            BTA_GATTC_DISCOVER_ST},
+
+    /* BTA_GATTC_API_SEARCH_EVT         */ {BTA_GATTC_Q_CMD,
+                                            BTA_GATTC_DISCOVER_ST},
+    /* BTA_GATTC_API_CONFIRM_EVT        */ {BTA_GATTC_CONFIRM,
+                                            BTA_GATTC_DISCOVER_ST},
+    /* BTA_GATTC_API_READ_MULTI_EVT     */ {BTA_GATTC_Q_CMD,
+                                            BTA_GATTC_DISCOVER_ST},
+    /* BTA_GATTC_API_REFRESH_EVT        */ {BTA_GATTC_IGNORE,
+                                            BTA_GATTC_DISCOVER_ST},
+
+    /* BTA_GATTC_INT_CONN_EVT           */ {BTA_GATTC_CONN,
+                                            BTA_GATTC_DISCOVER_ST},
+    /* BTA_GATTC_INT_DISCOVER_EVT       */ {BTA_GATTC_RESTART_DISCOVER,
+                                            BTA_GATTC_DISCOVER_ST},
+    /* BTA_GATTC_DISCOVER_CMPL_EVT      */ {BTA_GATTC_DISC_CMPL,
+                                            BTA_GATTC_CONN_ST},
+    /* BTA_GATTC_OP_CMPL_EVT            */ {BTA_GATTC_IGNORE_OP_CMPL,
+                                            BTA_GATTC_DISCOVER_ST},
+    /* BTA_GATTC_INT_DISCONN_EVT        */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST},
+
+};
+
+/* type for state table */
+typedef const uint8_t (*tBTA_GATTC_ST_TBL)[BTA_GATTC_NUM_COLS];
+
+/* state table */
+const tBTA_GATTC_ST_TBL bta_gattc_st_tbl[] = {
+    bta_gattc_st_idle, bta_gattc_st_w4_conn, bta_gattc_st_connected,
+    bta_gattc_st_discover};
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+
+/* GATTC control block */
+tBTA_GATTC_CB bta_gattc_cb;
+
+#if (BTA_GATT_DEBUG == TRUE)
+static char* gattc_evt_code(tBTA_GATTC_INT_EVT evt_code);
+static char* gattc_state_code(tBTA_GATTC_STATE state_code);
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_sm_execute
+ *
+ * Description      State machine event handling function for GATTC
+ *
+ *
+ * Returns          bool  : true if queued client request buffer can be
+ *                          immediately released, else false
+ *
+ ******************************************************************************/
+bool bta_gattc_sm_execute(tBTA_GATTC_CLCB* p_clcb, uint16_t event,
+                          tBTA_GATTC_DATA* p_data) {
+  tBTA_GATTC_ST_TBL state_table;
+  uint8_t action;
+  int i;
+  bool rt = true;
+#if (BTA_GATT_DEBUG == TRUE)
+  tBTA_GATTC_STATE in_state = p_clcb->state;
+  uint16_t in_event = event;
+  APPL_TRACE_DEBUG("bta_gattc_sm_execute: State 0x%02x [%s], Event 0x%x[%s]",
+                   in_state, gattc_state_code(in_state), in_event,
+                   gattc_evt_code(in_event));
+#endif
+
+  /* look up the state table for the current state */
+  state_table = bta_gattc_st_tbl[p_clcb->state];
+
+  event &= 0x00FF;
+
+  /* set next state */
+  p_clcb->state = state_table[event][BTA_GATTC_NEXT_STATE];
+
+  /* execute action functions */
+  for (i = 0; i < BTA_GATTC_ACTIONS; i++) {
+    if ((action = state_table[event][i]) != BTA_GATTC_IGNORE) {
+      (*bta_gattc_action[action])(p_clcb, p_data);
+      if (p_clcb->p_q_cmd == p_data) {
+        /* buffer is queued, don't free in the bta dispatcher.
+         * we free it ourselves when a completion event is received.
+         */
+        rt = false;
+      }
+    } else {
+      break;
+    }
+  }
+
+#if (BTA_GATT_DEBUG == TRUE)
+  if (in_state != p_clcb->state) {
+    APPL_TRACE_DEBUG("GATTC State Change: [%s] -> [%s] after Event [%s]",
+                     gattc_state_code(in_state),
+                     gattc_state_code(p_clcb->state), gattc_evt_code(in_event));
+  }
+#endif
+  return rt;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_hdl_event
+ *
+ * Description      GATT client main event handling function.
+ *
+ *
+ * Returns          bool
+ *
+ ******************************************************************************/
+bool bta_gattc_hdl_event(BT_HDR* p_msg) {
+  tBTA_GATTC_CLCB* p_clcb = NULL;
+  tBTA_GATTC_RCB* p_clreg;
+  bool rt = true;
+#if (BTA_GATT_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_gattc_hdl_event: Event [%s]",
+                   gattc_evt_code(p_msg->event));
+#endif
+  switch (p_msg->event) {
+    case BTA_GATTC_API_DISABLE_EVT:
+      bta_gattc_disable();
+      break;
+
+    case BTA_GATTC_API_REG_EVT:
+      bta_gattc_register((tBTA_GATTC_DATA*)p_msg);
+      break;
+
+    case BTA_GATTC_INT_START_IF_EVT:
+      bta_gattc_start_if((tBTA_GATTC_DATA*)p_msg);
+      break;
+
+    case BTA_GATTC_API_DEREG_EVT:
+      p_clreg = bta_gattc_cl_get_regcb(
+          ((tBTA_GATTC_DATA*)p_msg)->api_dereg.client_if);
+      bta_gattc_deregister(p_clreg);
+      break;
+
+    case BTA_GATTC_API_OPEN_EVT:
+      bta_gattc_process_api_open((tBTA_GATTC_DATA*)p_msg);
+      break;
+
+    case BTA_GATTC_API_CANCEL_OPEN_EVT:
+      bta_gattc_process_api_open_cancel((tBTA_GATTC_DATA*)p_msg);
+      break;
+
+    case BTA_GATTC_API_REFRESH_EVT:
+      bta_gattc_process_api_refresh((tBTA_GATTC_DATA*)p_msg);
+      break;
+
+    case BTA_GATTC_ENC_CMPL_EVT:
+      bta_gattc_process_enc_cmpl((tBTA_GATTC_DATA*)p_msg);
+      break;
+
+    default:
+      if (p_msg->event == BTA_GATTC_INT_CONN_EVT)
+        p_clcb = bta_gattc_find_int_conn_clcb((tBTA_GATTC_DATA*)p_msg);
+      else if (p_msg->event == BTA_GATTC_INT_DISCONN_EVT)
+        p_clcb = bta_gattc_find_int_disconn_clcb((tBTA_GATTC_DATA*)p_msg);
+      else
+        p_clcb = bta_gattc_find_clcb_by_conn_id(p_msg->layer_specific);
+
+      if (p_clcb != NULL) {
+        rt =
+            bta_gattc_sm_execute(p_clcb, p_msg->event, (tBTA_GATTC_DATA*)p_msg);
+      } else {
+        APPL_TRACE_DEBUG("Ignore unknown conn ID: %d", p_msg->layer_specific);
+      }
+
+      break;
+  }
+
+  return rt;
+}
+
+/*****************************************************************************
+ *  Debug Functions
+ ****************************************************************************/
+#if (BTA_GATT_DEBUG == TRUE)
+
+/*******************************************************************************
+ *
+ * Function         gattc_evt_code
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static char* gattc_evt_code(tBTA_GATTC_INT_EVT evt_code) {
+  switch (evt_code) {
+    case BTA_GATTC_API_OPEN_EVT:
+      return "BTA_GATTC_API_OPEN_EVT";
+    case BTA_GATTC_INT_OPEN_FAIL_EVT:
+      return "BTA_GATTC_INT_OPEN_FAIL_EVT";
+    case BTA_GATTC_API_CANCEL_OPEN_EVT:
+      return "BTA_GATTC_API_CANCEL_OPEN_EVT";
+    case BTA_GATTC_INT_CANCEL_OPEN_OK_EVT:
+      return "BTA_GATTC_INT_CANCEL_OPEN_OK_EVT";
+    case BTA_GATTC_API_READ_EVT:
+      return "BTA_GATTC_API_READ_EVT";
+    case BTA_GATTC_API_WRITE_EVT:
+      return "BTA_GATTC_API_WRITE_EVT";
+    case BTA_GATTC_API_EXEC_EVT:
+      return "BTA_GATTC_API_EXEC_EVT";
+    case BTA_GATTC_API_CLOSE_EVT:
+      return "BTA_GATTC_API_CLOSE_EVT";
+    case BTA_GATTC_API_SEARCH_EVT:
+      return "BTA_GATTC_API_SEARCH_EVT";
+    case BTA_GATTC_API_CONFIRM_EVT:
+      return "BTA_GATTC_API_CONFIRM_EVT";
+    case BTA_GATTC_API_READ_MULTI_EVT:
+      return "BTA_GATTC_API_READ_MULTI_EVT";
+    case BTA_GATTC_INT_CONN_EVT:
+      return "BTA_GATTC_INT_CONN_EVT";
+    case BTA_GATTC_INT_DISCOVER_EVT:
+      return "BTA_GATTC_INT_DISCOVER_EVT";
+    case BTA_GATTC_DISCOVER_CMPL_EVT:
+      return "BTA_GATTC_DISCOVER_CMPL_EVT";
+    case BTA_GATTC_OP_CMPL_EVT:
+      return "BTA_GATTC_OP_CMPL_EVT";
+    case BTA_GATTC_INT_DISCONN_EVT:
+      return "BTA_GATTC_INT_DISCONN_EVT";
+    case BTA_GATTC_INT_START_IF_EVT:
+      return "BTA_GATTC_INT_START_IF_EVT";
+    case BTA_GATTC_API_REG_EVT:
+      return "BTA_GATTC_API_REG_EVT";
+    case BTA_GATTC_API_DEREG_EVT:
+      return "BTA_GATTC_API_DEREG_EVT";
+    case BTA_GATTC_API_REFRESH_EVT:
+      return "BTA_GATTC_API_REFRESH_EVT";
+    case BTA_GATTC_API_DISABLE_EVT:
+      return "BTA_GATTC_API_DISABLE_EVT";
+    case BTA_GATTC_API_CFG_MTU_EVT:
+      return "BTA_GATTC_API_CFG_MTU_EVT";
+    default:
+      return "unknown GATTC event code";
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         gattc_state_code
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static char* gattc_state_code(tBTA_GATTC_STATE state_code) {
+  switch (state_code) {
+    case BTA_GATTC_IDLE_ST:
+      return "GATTC_IDLE_ST";
+    case BTA_GATTC_W4_CONN_ST:
+      return "GATTC_W4_CONN_ST";
+    case BTA_GATTC_CONN_ST:
+      return "GATTC_CONN_ST";
+    case BTA_GATTC_DISCOVER_ST:
+      return "GATTC_DISCOVER_ST";
+    default:
+      return "unknown GATTC state code";
+  }
+}
+
+#endif /* Debug Functions */
+#endif /* BTA_GATT_INCLUDED */
diff --git a/bt/bta/gatt/bta_gattc_utils.cc b/bt/bta/gatt/bta_gattc_utils.cc
new file mode 100644
index 0000000..1762a98
--- /dev/null
+++ b/bt/bta/gatt/bta_gattc_utils.cc
@@ -0,0 +1,741 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 GATT client utility function.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bta_gattc"
+
+#include "bt_target.h"
+
+#if (BTA_GATT_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_gattc_int.h"
+#include "bta_sys.h"
+#include "btcore/include/bdaddr.h"
+#include "l2c_api.h"
+#include "utl.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+static const uint8_t base_uuid[LEN_UUID_128] = {
+    0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
+    0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const BD_ADDR dummy_bda = {0, 0, 0, 0, 0, 0};
+
+/*******************************************************************************
+ *
+ * Function         bta_gatt_convert_uuid16_to_uuid128
+ *
+ * Description      Convert a 16 bits UUID to be an standard 128 bits one.
+ *
+ * Returns          true if two uuid match; false otherwise.
+ *
+ ******************************************************************************/
+void bta_gatt_convert_uuid16_to_uuid128(uint8_t uuid_128[LEN_UUID_128],
+                                        uint16_t uuid_16) {
+  uint8_t* p = &uuid_128[LEN_UUID_128 - 4];
+
+  memcpy(uuid_128, base_uuid, LEN_UUID_128);
+
+  UINT16_TO_STREAM(p, uuid_16);
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_uuid_compare
+ *
+ * Description      Compare two UUID to see if they are the same.
+ *
+ * Returns          true if two uuid match; false otherwise.
+ *
+ ******************************************************************************/
+bool bta_gattc_uuid_compare(const tBT_UUID* p_src, const tBT_UUID* p_tar,
+                            bool is_precise) {
+  uint8_t su[LEN_UUID_128], tu[LEN_UUID_128];
+  const uint8_t *ps, *pt;
+
+  /* any of the UUID is unspecified */
+  if (p_src == 0 || p_tar == 0) {
+    if (is_precise)
+      return false;
+    else
+      return true;
+  }
+
+  /* If both are 16-bit, we can do a simple compare */
+  if (p_src->len == 2 && p_tar->len == 2) {
+    return p_src->uu.uuid16 == p_tar->uu.uuid16;
+  }
+
+  /* One or both of the UUIDs is 128-bit */
+  if (p_src->len == LEN_UUID_16) {
+    /* convert a 16 bits UUID to 128 bits value */
+    bta_gatt_convert_uuid16_to_uuid128(su, p_src->uu.uuid16);
+    ps = su;
+  } else
+    ps = p_src->uu.uuid128;
+
+  if (p_tar->len == LEN_UUID_16) {
+    /* convert a 16 bits UUID to 128 bits value */
+    bta_gatt_convert_uuid16_to_uuid128(tu, p_tar->uu.uuid16);
+    pt = tu;
+  } else
+    pt = p_tar->uu.uuid128;
+
+  return (memcmp(ps, pt, LEN_UUID_128) == 0);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_cl_get_regcb
+ *
+ * Description      get registration control block by client interface.
+ *
+ * Returns          pointer to the regcb
+ *
+ ******************************************************************************/
+tBTA_GATTC_RCB* bta_gattc_cl_get_regcb(uint8_t client_if) {
+  uint8_t i = 0;
+  tBTA_GATTC_RCB* p_clrcb = &bta_gattc_cb.cl_rcb[0];
+
+  for (i = 0; i < BTA_GATTC_CL_MAX; i++, p_clrcb++) {
+    if (p_clrcb->in_use && p_clrcb->client_if == client_if) return p_clrcb;
+  }
+  return NULL;
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_num_reg_app
+ *
+ * Description      find the number of registered application.
+ *
+ * Returns          pointer to the regcb
+ *
+ ******************************************************************************/
+uint8_t bta_gattc_num_reg_app(void) {
+  uint8_t i = 0, j = 0;
+
+  for (i = 0; i < BTA_GATTC_CL_MAX; i++) {
+    if (bta_gattc_cb.cl_rcb[i].in_use) j++;
+  }
+  return j;
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_find_clcb_by_cif
+ *
+ * Description      get clcb by client interface and remote bd adddress
+ *
+ * Returns          pointer to the clcb
+ *
+ ******************************************************************************/
+tBTA_GATTC_CLCB* bta_gattc_find_clcb_by_cif(uint8_t client_if,
+                                            BD_ADDR remote_bda,
+                                            tBTA_TRANSPORT transport) {
+  tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[0];
+  uint8_t i;
+
+  for (i = 0; i < BTA_GATTC_CLCB_MAX; i++, p_clcb++) {
+    if (p_clcb->in_use && p_clcb->p_rcb->client_if == client_if &&
+        p_clcb->transport == transport && bdcmp(p_clcb->bda, remote_bda) == 0)
+      return p_clcb;
+  }
+  return NULL;
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_find_clcb_by_conn_id
+ *
+ * Description      get clcb by connection ID
+ *
+ * Returns          pointer to the clcb
+ *
+ ******************************************************************************/
+tBTA_GATTC_CLCB* bta_gattc_find_clcb_by_conn_id(uint16_t conn_id) {
+  tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[0];
+  uint8_t i;
+
+  for (i = 0; i < BTA_GATTC_CLCB_MAX; i++, p_clcb++) {
+    if (p_clcb->in_use && p_clcb->bta_conn_id == conn_id) return p_clcb;
+  }
+  return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_clcb_alloc
+ *
+ * Description      allocate CLCB
+ *
+ * Returns          pointer to the clcb
+ *
+ ******************************************************************************/
+tBTA_GATTC_CLCB* bta_gattc_clcb_alloc(tBTA_GATTC_IF client_if,
+                                      BD_ADDR remote_bda,
+                                      tBTA_TRANSPORT transport) {
+  uint8_t i_clcb = 0;
+  tBTA_GATTC_CLCB* p_clcb = NULL;
+
+  for (i_clcb = 0; i_clcb < BTA_GATTC_CLCB_MAX; i_clcb++) {
+    if (!bta_gattc_cb.clcb[i_clcb].in_use) {
+#if (BTA_GATT_DEBUG == TRUE)
+      APPL_TRACE_DEBUG("bta_gattc_clcb_alloc: found clcb[%d] available",
+                       i_clcb);
+#endif
+      p_clcb = &bta_gattc_cb.clcb[i_clcb];
+      p_clcb->in_use = true;
+      p_clcb->status = BTA_GATT_OK;
+      p_clcb->transport = transport;
+      bdcpy(p_clcb->bda, remote_bda);
+
+      p_clcb->p_rcb = bta_gattc_cl_get_regcb(client_if);
+
+      if ((p_clcb->p_srcb = bta_gattc_find_srcb(remote_bda)) == NULL)
+        p_clcb->p_srcb = bta_gattc_srcb_alloc(remote_bda);
+
+      if (p_clcb->p_rcb != NULL && p_clcb->p_srcb != NULL) {
+        p_clcb->p_srcb->num_clcb++;
+        p_clcb->p_rcb->num_clcb++;
+      } else {
+        /* release this clcb if clcb or srcb allocation failed */
+        p_clcb->in_use = false;
+        p_clcb = NULL;
+      }
+      break;
+    }
+  }
+  return p_clcb;
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_find_alloc_clcb
+ *
+ * Description      find or allocate CLCB if not found.
+ *
+ * Returns          pointer to the clcb
+ *
+ ******************************************************************************/
+tBTA_GATTC_CLCB* bta_gattc_find_alloc_clcb(tBTA_GATTC_IF client_if,
+                                           BD_ADDR remote_bda,
+                                           tBTA_TRANSPORT transport) {
+  tBTA_GATTC_CLCB* p_clcb;
+
+  if ((p_clcb = bta_gattc_find_clcb_by_cif(client_if, remote_bda, transport)) ==
+      NULL) {
+    p_clcb = bta_gattc_clcb_alloc(client_if, remote_bda, transport);
+  }
+  return p_clcb;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_clcb_dealloc
+ *
+ * Description      Deallocte a clcb
+ *
+ * Returns          pointer to the clcb
+ *
+ ******************************************************************************/
+void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB* p_clcb) {
+  tBTA_GATTC_SERV* p_srcb = NULL;
+
+  if (p_clcb) {
+    p_srcb = p_clcb->p_srcb;
+    if (p_srcb->num_clcb) p_srcb->num_clcb--;
+
+    if (p_clcb->p_rcb->num_clcb) p_clcb->p_rcb->num_clcb--;
+
+    /* if the srcb is no longer needed, reset the state */
+    if (p_srcb->num_clcb == 0) {
+      p_srcb->connected = false;
+      p_srcb->state = BTA_GATTC_SERV_IDLE;
+      p_srcb->mtu = 0;
+    }
+
+    osi_free_and_reset((void**)&p_clcb->p_q_cmd);
+    memset(p_clcb, 0, sizeof(tBTA_GATTC_CLCB));
+  } else {
+    APPL_TRACE_ERROR("bta_gattc_clcb_dealloc p_clcb=NULL");
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_find_srcb
+ *
+ * Description      find server cache by remote bd address currently in use
+ *
+ * Returns          pointer to the server cache.
+ *
+ ******************************************************************************/
+tBTA_GATTC_SERV* bta_gattc_find_srcb(BD_ADDR bda) {
+  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++) {
+    if (p_srcb->in_use && bdcmp(p_srcb->server_bda, bda) == 0) return p_srcb;
+  }
+  return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_find_srvr_cache
+ *
+ * Description      find server cache by remote bd address
+ *
+ * Returns          pointer to the server cache.
+ *
+ ******************************************************************************/
+tBTA_GATTC_SERV* bta_gattc_find_srvr_cache(BD_ADDR bda) {
+  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++) {
+    if (bdcmp(p_srcb->server_bda, bda) == 0) return p_srcb;
+  }
+  return NULL;
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_find_scb_by_cid
+ *
+ * Description      find server control block by connection ID
+ *
+ * Returns          pointer to the server cache.
+ *
+ ******************************************************************************/
+tBTA_GATTC_SERV* bta_gattc_find_scb_by_cid(uint16_t conn_id) {
+  tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+
+  if (p_clcb)
+    return p_clcb->p_srcb;
+  else
+    return NULL;
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_srcb_alloc
+ *
+ * Description      allocate server cache control block
+ *
+ * Returns          pointer to the server cache.
+ *
+ ******************************************************************************/
+tBTA_GATTC_SERV* bta_gattc_srcb_alloc(BD_ADDR bda) {
+  tBTA_GATTC_SERV *p_tcb = &bta_gattc_cb.known_server[0], *p_recycle = NULL;
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i++, p_tcb++) {
+    if (!p_tcb->in_use) {
+      found = true;
+      break;
+    } else if (!p_tcb->connected) {
+      p_recycle = p_tcb;
+    }
+  }
+
+  /* if not found, try to recycle one known device */
+  if (!found && !p_recycle)
+    p_tcb = NULL;
+  else if (!found && p_recycle)
+    p_tcb = p_recycle;
+
+  if (p_tcb != NULL) {
+    if (p_tcb->p_srvc_cache != NULL) list_free(p_tcb->p_srvc_cache);
+
+    osi_free_and_reset((void**)&p_tcb->p_srvc_list);
+    memset(p_tcb, 0, sizeof(tBTA_GATTC_SERV));
+
+    p_tcb->in_use = true;
+    bdcpy(p_tcb->server_bda, bda);
+  }
+  return p_tcb;
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_enqueue
+ *
+ * Description      enqueue a client request in clcb.
+ *
+ * Returns          success or failure.
+ *
+ ******************************************************************************/
+bool bta_gattc_enqueue(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+  if (p_clcb->p_q_cmd == NULL) {
+    p_clcb->p_q_cmd = p_data;
+    return true;
+  }
+
+  APPL_TRACE_ERROR("%s: already has a pending command!!", __func__);
+  /* skip the callback now. ----- need to send callback ? */
+  return false;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_check_notif_registry
+ *
+ * Description      check if the service notificaition has been registered.
+ *
+ * Returns
+ *
+ ******************************************************************************/
+bool bta_gattc_check_notif_registry(tBTA_GATTC_RCB* p_clreg,
+                                    tBTA_GATTC_SERV* p_srcb,
+                                    tBTA_GATTC_NOTIFY* p_notify) {
+  uint8_t i;
+
+  for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i++) {
+    if (p_clreg->notif_reg[i].in_use &&
+        bdcmp(p_clreg->notif_reg[i].remote_bda, p_srcb->server_bda) == 0 &&
+        p_clreg->notif_reg[i].handle == p_notify->handle) {
+      APPL_TRACE_DEBUG("Notification registered!");
+      return true;
+    }
+  }
+  return false;
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_clear_notif_registration
+ *
+ * Description      Clear up the notification registration information by
+ *                  BD_ADDR.
+ *                  Where handle is between start_handle and end_handle, and
+ *                  start_handle and end_handle are boundaries of service
+ *                  containing characteristic.
+ *
+ * Returns          None.
+ *
+ ******************************************************************************/
+void bta_gattc_clear_notif_registration(tBTA_GATTC_SERV* p_srcb,
+                                        uint16_t conn_id, uint16_t start_handle,
+                                        uint16_t end_handle) {
+  BD_ADDR remote_bda;
+  tBTA_GATTC_IF gatt_if;
+  tBTA_GATTC_RCB* p_clrcb;
+  uint8_t i;
+  tGATT_TRANSPORT transport;
+  uint16_t handle;
+
+  if (GATT_GetConnectionInfor(conn_id, &gatt_if, remote_bda, &transport)) {
+    if ((p_clrcb = bta_gattc_cl_get_regcb(gatt_if)) != NULL) {
+      for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i++) {
+        if (p_clrcb->notif_reg[i].in_use &&
+            !bdcmp(p_clrcb->notif_reg[i].remote_bda, remote_bda)) {
+          /* It's enough to get service or characteristic handle, as
+           * clear boundaries are always around service.
+           */
+          handle = p_clrcb->notif_reg[i].handle;
+          if (handle >= start_handle && handle <= end_handle)
+            memset(&p_clrcb->notif_reg[i], 0, sizeof(tBTA_GATTC_NOTIF_REG));
+        }
+      }
+    }
+  } else {
+    APPL_TRACE_ERROR(
+        "can not clear indication/notif registration for unknown app");
+  }
+  return;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_mark_bg_conn
+ *
+ * Description      mark background connection status when a bg connection is
+ *                  initiated or terminated.
+ *
+ * Returns          true if success; false otherwise.
+ *
+ ******************************************************************************/
+bool bta_gattc_mark_bg_conn(tBTA_GATTC_IF client_if, BD_ADDR_PTR remote_bda_ptr,
+                            bool add) {
+  tBTA_GATTC_BG_TCK* p_bg_tck = &bta_gattc_cb.bg_track[0];
+  uint8_t i = 0;
+  tBTA_GATTC_CIF_MASK* p_cif_mask;
+
+  for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i++, p_bg_tck++) {
+    if (p_bg_tck->in_use &&
+        ((remote_bda_ptr != NULL &&
+          bdcmp(p_bg_tck->remote_bda, remote_bda_ptr) == 0) ||
+         (remote_bda_ptr == NULL &&
+          bdcmp(p_bg_tck->remote_bda, dummy_bda) == 0))) {
+      p_cif_mask = &p_bg_tck->cif_mask;
+
+      if (add) /* mask on the cif bit */
+        *p_cif_mask |= (1 << (client_if - 1));
+      else {
+        if (client_if != 0)
+          *p_cif_mask &= (~(1 << (client_if - 1)));
+        else
+          *p_cif_mask = 0;
+      }
+      /* no BG connection for this device, make it available */
+      if (p_bg_tck->cif_mask == 0) {
+        memset(p_bg_tck, 0, sizeof(tBTA_GATTC_BG_TCK));
+      }
+      return true;
+    }
+  }
+  if (!add) {
+    if (remote_bda_ptr) {
+      bdstr_t bdstr = {0};
+      APPL_TRACE_ERROR(
+          "%s unable to find the bg connection mask for: %s", __func__,
+          bdaddr_to_string((bt_bdaddr_t*)remote_bda_ptr, bdstr, sizeof(bdstr)));
+    }
+    return false;
+  } 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++) {
+      if (!p_bg_tck->in_use) {
+        p_bg_tck->in_use = true;
+        if (remote_bda_ptr)
+          bdcpy(p_bg_tck->remote_bda, remote_bda_ptr);
+        else
+          bdcpy(p_bg_tck->remote_bda, dummy_bda);
+
+        p_cif_mask = &p_bg_tck->cif_mask;
+
+        *p_cif_mask = (1 << (client_if - 1));
+        return true;
+      }
+    }
+    APPL_TRACE_ERROR("no available space to mark the bg connection status");
+    return false;
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_check_bg_conn
+ *
+ * Description      check if this is a background connection background
+ *                  connection.
+ *
+ * Returns          true if success; false otherwise.
+ *
+ ******************************************************************************/
+bool bta_gattc_check_bg_conn(tBTA_GATTC_IF client_if, BD_ADDR remote_bda,
+                             uint8_t role) {
+  tBTA_GATTC_BG_TCK* p_bg_tck = &bta_gattc_cb.bg_track[0];
+  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++) {
+    if (p_bg_tck->in_use && (bdcmp(p_bg_tck->remote_bda, remote_bda) == 0 ||
+                             bdcmp(p_bg_tck->remote_bda, dummy_bda) == 0)) {
+      if (((p_bg_tck->cif_mask & (1 << (client_if - 1))) != 0) &&
+          role == HCI_ROLE_MASTER)
+        is_bg_conn = true;
+    }
+  }
+  return is_bg_conn;
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_send_open_cback
+ *
+ * Description      send open callback
+ *
+ * Returns
+ *
+ ******************************************************************************/
+void bta_gattc_send_open_cback(tBTA_GATTC_RCB* p_clreg, tBTA_GATT_STATUS status,
+                               BD_ADDR remote_bda, uint16_t conn_id,
+                               tBTA_TRANSPORT transport, uint16_t mtu) {
+  tBTA_GATTC cb_data;
+
+  if (p_clreg->p_cback) {
+    memset(&cb_data, 0, sizeof(tBTA_GATTC));
+
+    cb_data.open.status = status;
+    cb_data.open.client_if = p_clreg->client_if;
+    cb_data.open.conn_id = conn_id;
+    cb_data.open.mtu = mtu;
+    cb_data.open.transport = transport;
+    bdcpy(cb_data.open.remote_bda, remote_bda);
+
+    (*p_clreg->p_cback)(BTA_GATTC_OPEN_EVT, &cb_data);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gattc_conn_alloc
+ *
+ * Description      allocate connection tracking spot
+ *
+ * Returns          pointer to the clcb
+ *
+ ******************************************************************************/
+tBTA_GATTC_CONN* bta_gattc_conn_alloc(BD_ADDR remote_bda) {
+  uint8_t i_conn = 0;
+  tBTA_GATTC_CONN* p_conn = &bta_gattc_cb.conn_track[0];
+
+  for (i_conn = 0; i_conn < BTA_GATTC_CONN_MAX; i_conn++, p_conn++) {
+    if (!p_conn->in_use) {
+#if (BTA_GATT_DEBUG == TRUE)
+      APPL_TRACE_DEBUG("bta_gattc_conn_alloc: found conn_track[%d] available",
+                       i_conn);
+#endif
+      p_conn->in_use = true;
+      bdcpy(p_conn->remote_bda, remote_bda);
+      return p_conn;
+    }
+  }
+  return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_conn_find
+ *
+ * Description      allocate connection tracking spot
+ *
+ * Returns          pointer to the clcb
+ *
+ ******************************************************************************/
+tBTA_GATTC_CONN* bta_gattc_conn_find(BD_ADDR remote_bda) {
+  uint8_t i_conn = 0;
+  tBTA_GATTC_CONN* p_conn = &bta_gattc_cb.conn_track[0];
+
+  for (i_conn = 0; i_conn < BTA_GATTC_CONN_MAX; i_conn++, p_conn++) {
+    if (p_conn->in_use && bdcmp(remote_bda, p_conn->remote_bda) == 0) {
+#if (BTA_GATT_DEBUG == TRUE)
+      APPL_TRACE_DEBUG("bta_gattc_conn_find: found conn_track[%d] matched",
+                       i_conn);
+#endif
+      return p_conn;
+    }
+  }
+  return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_conn_find_alloc
+ *
+ * Description      find or allocate connection tracking spot
+ *
+ * Returns          pointer to the clcb
+ *
+ ******************************************************************************/
+tBTA_GATTC_CONN* bta_gattc_conn_find_alloc(BD_ADDR remote_bda) {
+  tBTA_GATTC_CONN* p_conn = bta_gattc_conn_find(remote_bda);
+
+  if (p_conn == NULL) {
+    p_conn = bta_gattc_conn_alloc(remote_bda);
+  }
+  return p_conn;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_conn_dealloc
+ *
+ * Description      de-allocate connection tracking spot
+ *
+ * Returns          pointer to the clcb
+ *
+ ******************************************************************************/
+bool bta_gattc_conn_dealloc(BD_ADDR remote_bda) {
+  tBTA_GATTC_CONN* p_conn = bta_gattc_conn_find(remote_bda);
+
+  if (p_conn != NULL) {
+    p_conn->in_use = false;
+    memset(p_conn->remote_bda, 0, BD_ADDR_LEN);
+    return true;
+  }
+  return false;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_find_int_conn_clcb
+ *
+ * Description      try to locate a clcb when an internal connecion event
+ *                  arrives.
+ *
+ * Returns          pointer to the clcb
+ *
+ ******************************************************************************/
+tBTA_GATTC_CLCB* bta_gattc_find_int_conn_clcb(tBTA_GATTC_DATA* p_msg) {
+  tBTA_GATTC_CLCB* p_clcb = NULL;
+
+  if (p_msg->int_conn.role == HCI_ROLE_SLAVE)
+    bta_gattc_conn_find_alloc(p_msg->int_conn.remote_bda);
+
+  /* try to locate a logic channel */
+  if ((p_clcb = bta_gattc_find_clcb_by_cif(
+           p_msg->int_conn.client_if, p_msg->int_conn.remote_bda,
+           p_msg->int_conn.transport)) == NULL) {
+    /* for a background connection or listening connection */
+    if (/*p_msg->int_conn.role == HCI_ROLE_SLAVE ||  */
+        bta_gattc_check_bg_conn(p_msg->int_conn.client_if,
+                                p_msg->int_conn.remote_bda,
+                                p_msg->int_conn.role)) {
+      /* allocate a new channel */
+      p_clcb = bta_gattc_clcb_alloc(p_msg->int_conn.client_if,
+                                    p_msg->int_conn.remote_bda,
+                                    p_msg->int_conn.transport);
+    }
+  }
+  return p_clcb;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gattc_find_int_disconn_clcb
+ *
+ * Description      try to locate a clcb when an internal disconnect callback
+ *                  arrives.
+ *
+ * Returns          pointer to the clcb
+ *
+ ******************************************************************************/
+tBTA_GATTC_CLCB* bta_gattc_find_int_disconn_clcb(tBTA_GATTC_DATA* p_msg) {
+  tBTA_GATTC_CLCB* p_clcb = NULL;
+
+  bta_gattc_conn_dealloc(p_msg->int_conn.remote_bda);
+  if ((p_clcb = bta_gattc_find_clcb_by_conn_id(
+           p_msg->int_conn.hdr.layer_specific)) == NULL) {
+    /* connection attempt failed, send connection callback event */
+    p_clcb = bta_gattc_find_clcb_by_cif(p_msg->int_conn.client_if,
+                                        p_msg->int_conn.remote_bda,
+                                        p_msg->int_conn.transport);
+  }
+  if (p_clcb == NULL) {
+    APPL_TRACE_DEBUG(" disconnection ID: [%d] not used by BTA",
+                     p_msg->int_conn.hdr.layer_specific);
+  }
+  return p_clcb;
+}
+
+#endif /* BTA_GATT_INCLUDED */
diff --git a/bt/bta/gatt/bta_gatts_act.cc b/bt/bta/gatt/bta_gatts_act.cc
new file mode 100644
index 0000000..8b04955
--- /dev/null
+++ b/bt/bta/gatt/bta_gatts_act.cc
@@ -0,0 +1,637 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 GATT Server action functions for the state
+ *  machine.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if (BTA_GATT_INCLUDED == TRUE)
+
+#include <string.h>
+#include "bt_common.h"
+#include "bta_gatts_co.h"
+#include "bta_gatts_int.h"
+#include "bta_sys.h"
+#include "btif/include/btif_debug_conn.h"
+#include "btm_ble_api.h"
+#include "osi/include/osi.h"
+#include "utl.h"
+
+static void bta_gatts_nv_save_cback(bool is_saved,
+                                    tGATTS_HNDL_RANGE* p_hndl_range);
+static bool bta_gatts_nv_srv_chg_cback(tGATTS_SRV_CHG_CMD cmd,
+                                       tGATTS_SRV_CHG_REQ* p_req,
+                                       tGATTS_SRV_CHG_RSP* p_rsp);
+
+static void bta_gatts_conn_cback(tGATT_IF gatt_if, BD_ADDR bda,
+                                 uint16_t conn_id, bool connected,
+                                 tGATT_DISCONN_REASON reason,
+                                 tGATT_TRANSPORT transport);
+static void bta_gatts_send_request_cback(uint16_t conn_id, uint32_t trans_id,
+                                         tGATTS_REQ_TYPE req_type,
+                                         tGATTS_DATA* p_data);
+static void bta_gatts_cong_cback(uint16_t conn_id, bool congested);
+
+static tGATT_CBACK bta_gatts_cback = {
+    bta_gatts_conn_cback, NULL, NULL, NULL, bta_gatts_send_request_cback, NULL,
+    bta_gatts_cong_cback};
+
+tGATT_APPL_INFO bta_gatts_nv_cback = {bta_gatts_nv_save_cback,
+                                      bta_gatts_nv_srv_chg_cback};
+
+/*******************************************************************************
+ *
+ * Function         bta_gatts_nv_save_cback
+ *
+ * Description      NV save callback function.
+ *
+ * Parameter        is_add: true is to add a handle range; otherwise is to
+ *                          delete.
+ * Returns          none.
+ *
+ ******************************************************************************/
+static void bta_gatts_nv_save_cback(bool is_add,
+                                    tGATTS_HNDL_RANGE* p_hndl_range) {
+  bta_gatts_co_update_handle_range(is_add,
+                                   (tBTA_GATTS_HNDL_RANGE*)p_hndl_range);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gatts_nv_srv_chg_cback
+ *
+ * Description      NV save callback function.
+ *
+ * Parameter        is_add: true is to add a handle range; otherwise is to
+ *                          delete.
+ * Returns          none.
+ *
+ ******************************************************************************/
+static bool bta_gatts_nv_srv_chg_cback(tGATTS_SRV_CHG_CMD cmd,
+                                       tGATTS_SRV_CHG_REQ* p_req,
+                                       tGATTS_SRV_CHG_RSP* p_rsp) {
+  return bta_gatts_co_srv_chg((tBTA_GATTS_SRV_CHG_CMD)cmd,
+                              (tBTA_GATTS_SRV_CHG_REQ*)p_req,
+                              (tBTA_GATTS_SRV_CHG_RSP*)p_rsp);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gatts_enable
+ *
+ * Description      enable BTA GATTS module.
+ *
+ * Returns          none.
+ *
+ ******************************************************************************/
+void bta_gatts_enable(tBTA_GATTS_CB* p_cb) {
+  uint8_t index = 0;
+  tBTA_GATTS_HNDL_RANGE handle_range;
+
+  if (p_cb->enabled) {
+    APPL_TRACE_DEBUG("GATTS already enabled.");
+  } else {
+    memset(p_cb, 0, sizeof(tBTA_GATTS_CB));
+
+    p_cb->enabled = true;
+
+    while (bta_gatts_co_load_handle_range(index, &handle_range)) {
+      GATTS_AddHandleRange((tGATTS_HNDL_RANGE*)&handle_range);
+      memset(&handle_range, 0, sizeof(tGATTS_HNDL_RANGE));
+      index++;
+    }
+
+    APPL_TRACE_DEBUG("bta_gatts_enable: num of handle range added=%d", index);
+
+    if (!GATTS_NVRegister(&bta_gatts_nv_cback)) {
+      APPL_TRACE_ERROR("BTA GATTS NV register failed.");
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gatts_api_disable
+ *
+ * Description      disable BTA GATTS module.
+ *
+ * Returns          none.
+ *
+ ******************************************************************************/
+void bta_gatts_api_disable(tBTA_GATTS_CB* p_cb) {
+  uint8_t i;
+
+  if (p_cb->enabled) {
+    for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i++) {
+      if (p_cb->rcb[i].in_use) {
+        GATT_Deregister(p_cb->rcb[i].gatt_if);
+      }
+    }
+    memset(p_cb, 0, sizeof(tBTA_GATTS_CB));
+  } else {
+    APPL_TRACE_ERROR("GATTS not enabled");
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gatts_register
+ *
+ * Description      register an application.
+ *
+ * Returns          none.
+ *
+ ******************************************************************************/
+void bta_gatts_register(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg) {
+  tBTA_GATTS cb_data;
+  tBTA_GATT_STATUS status = BTA_GATT_OK;
+  uint8_t i, first_unuse = 0xff;
+
+  if (p_cb->enabled == false) {
+    bta_gatts_enable(p_cb);
+  }
+
+  for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i++) {
+    if (p_cb->rcb[i].in_use) {
+      if (bta_gatts_uuid_compare(p_cb->rcb[i].app_uuid,
+                                 p_msg->api_reg.app_uuid)) {
+        APPL_TRACE_ERROR("application already registered.");
+        status = BTA_GATT_DUP_REG;
+        break;
+      }
+    }
+  }
+
+  if (status == BTA_GATT_OK) {
+    for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i++) {
+      if (first_unuse == 0xff && !p_cb->rcb[i].in_use) {
+        first_unuse = i;
+        break;
+      }
+    }
+
+    cb_data.reg_oper.server_if = BTA_GATTS_INVALID_IF;
+    memcpy(&cb_data.reg_oper.uuid, &p_msg->api_reg.app_uuid, sizeof(tBT_UUID));
+    if (first_unuse != 0xff) {
+      APPL_TRACE_ERROR("register application first_unuse rcb_idx = %d",
+                       first_unuse);
+
+      p_cb->rcb[first_unuse].in_use = true;
+      p_cb->rcb[first_unuse].p_cback = p_msg->api_reg.p_cback;
+      memcpy(&p_cb->rcb[first_unuse].app_uuid, &p_msg->api_reg.app_uuid,
+             sizeof(tBT_UUID));
+      cb_data.reg_oper.server_if = p_cb->rcb[first_unuse].gatt_if =
+          GATT_Register(&p_msg->api_reg.app_uuid, &bta_gatts_cback);
+      if (!p_cb->rcb[first_unuse].gatt_if) {
+        status = BTA_GATT_NO_RESOURCES;
+      } else {
+        tBTA_GATTS_INT_START_IF* p_buf = (tBTA_GATTS_INT_START_IF*)osi_malloc(
+            sizeof(tBTA_GATTS_INT_START_IF));
+        p_buf->hdr.event = BTA_GATTS_INT_START_IF_EVT;
+        p_buf->server_if = p_cb->rcb[first_unuse].gatt_if;
+
+        bta_sys_sendmsg(p_buf);
+      }
+    } else {
+      status = BTA_GATT_NO_RESOURCES;
+    }
+  }
+  cb_data.reg_oper.status = status;
+  if (p_msg->api_reg.p_cback)
+    (*p_msg->api_reg.p_cback)(BTA_GATTS_REG_EVT, &cb_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gatts_start_if
+ *
+ * Description      start an application interface.
+ *
+ * Returns          none.
+ *
+ ******************************************************************************/
+void bta_gatts_start_if(UNUSED_ATTR tBTA_GATTS_CB* p_cb,
+                        tBTA_GATTS_DATA* p_msg) {
+  if (bta_gatts_find_app_rcb_by_app_if(p_msg->int_start_if.server_if)) {
+    GATT_StartIf(p_msg->int_start_if.server_if);
+  } else {
+    APPL_TRACE_ERROR("Unable to start app.: Unknown interface =%d",
+                     p_msg->int_start_if.server_if);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gatts_deregister
+ *
+ * Description      deregister an application.
+ *
+ * Returns          none.
+ *
+ ******************************************************************************/
+void bta_gatts_deregister(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg) {
+  tBTA_GATT_STATUS status = BTA_GATT_ERROR;
+  tBTA_GATTS_CBACK* p_cback = NULL;
+  uint8_t i;
+  tBTA_GATTS cb_data;
+
+  cb_data.reg_oper.server_if = p_msg->api_dereg.server_if;
+  cb_data.reg_oper.status = status;
+
+  for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i++) {
+    if (p_cb->rcb[i].in_use &&
+        p_cb->rcb[i].gatt_if == p_msg->api_dereg.server_if) {
+      p_cback = p_cb->rcb[i].p_cback;
+      status = BTA_GATT_OK;
+
+      /* deregister the app */
+      GATT_Deregister(p_cb->rcb[i].gatt_if);
+
+      /* reset cb */
+      memset(&p_cb->rcb[i], 0, sizeof(tBTA_GATTS_RCB));
+      cb_data.reg_oper.status = status;
+      break;
+    }
+  }
+
+  if (p_cback) {
+    (*p_cback)(BTA_GATTS_DEREG_EVT, &cb_data);
+  } else {
+    APPL_TRACE_ERROR("application not registered.");
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gatts_delete_service
+ *
+ * Description      action function to delete a service.
+ *
+ * Returns          none.
+ *
+ ******************************************************************************/
+void bta_gatts_delete_service(tBTA_GATTS_SRVC_CB* p_srvc_cb,
+                              tBTA_GATTS_DATA* p_msg) {
+  tBTA_GATTS_RCB* p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx];
+  tBTA_GATTS cb_data;
+
+  cb_data.srvc_oper.server_if = p_rcb->gatt_if;
+  // cb_data.srvc_oper.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific;
+
+  if (GATTS_DeleteService(p_rcb->gatt_if, &p_srvc_cb->service_uuid,
+                          p_srvc_cb->service_id)) {
+    cb_data.srvc_oper.status = BTA_GATT_OK;
+    memset(p_srvc_cb, 0, sizeof(tBTA_GATTS_SRVC_CB));
+  } else {
+    cb_data.srvc_oper.status = BTA_GATT_ERROR;
+  }
+
+  if (p_rcb->p_cback) (*p_rcb->p_cback)(BTA_GATTS_DELELTE_EVT, &cb_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gatts_stop_service
+ *
+ * Description      action function to stop a service.
+ *
+ * Returns          none.
+ *
+ ******************************************************************************/
+void bta_gatts_stop_service(tBTA_GATTS_SRVC_CB* p_srvc_cb,
+                            UNUSED_ATTR tBTA_GATTS_DATA* p_msg) {
+  tBTA_GATTS_RCB* p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx];
+  tBTA_GATTS cb_data;
+
+  GATTS_StopService(p_srvc_cb->service_id);
+  cb_data.srvc_oper.server_if = p_rcb->gatt_if;
+  cb_data.srvc_oper.service_id = p_srvc_cb->service_id;
+  cb_data.srvc_oper.status = BTA_GATT_OK;
+  APPL_TRACE_ERROR("bta_gatts_stop_service service_id= %d",
+                   p_srvc_cb->service_id);
+
+  if (p_rcb->p_cback) (*p_rcb->p_cback)(BTA_GATTS_STOP_EVT, &cb_data);
+}
+/*******************************************************************************
+ *
+ * Function         bta_gatts_send_rsp
+ *
+ * Description      GATTS send response.
+ *
+ * Returns          none.
+ *
+ ******************************************************************************/
+void bta_gatts_send_rsp(UNUSED_ATTR tBTA_GATTS_CB* p_cb,
+                        tBTA_GATTS_DATA* p_msg) {
+  if (GATTS_SendRsp(p_msg->api_rsp.hdr.layer_specific, p_msg->api_rsp.trans_id,
+                    p_msg->api_rsp.status,
+                    (tGATTS_RSP*)p_msg->api_rsp.p_rsp) != GATT_SUCCESS) {
+    APPL_TRACE_ERROR("Sending response failed");
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_gatts_indicate_handle
+ *
+ * Description      GATTS send handle value indication or notification.
+ *
+ * Returns          none.
+ *
+ ******************************************************************************/
+void bta_gatts_indicate_handle(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg) {
+  tBTA_GATTS_SRVC_CB* p_srvc_cb;
+  tBTA_GATTS_RCB* p_rcb = NULL;
+  tBTA_GATT_STATUS status = BTA_GATT_ILLEGAL_PARAMETER;
+  tGATT_IF gatt_if;
+  BD_ADDR remote_bda;
+  tBTA_TRANSPORT transport;
+  tBTA_GATTS cb_data;
+
+  p_srvc_cb =
+      bta_gatts_find_srvc_cb_by_attr_id(p_cb, p_msg->api_indicate.attr_id);
+
+  if (p_srvc_cb) {
+    if (GATT_GetConnectionInfor(p_msg->api_indicate.hdr.layer_specific,
+                                &gatt_if, remote_bda, &transport)) {
+      p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if);
+
+      if (p_msg->api_indicate.need_confirm)
+
+        status = GATTS_HandleValueIndication(
+            p_msg->api_indicate.hdr.layer_specific, p_msg->api_indicate.attr_id,
+            p_msg->api_indicate.len, p_msg->api_indicate.value);
+      else
+        status = GATTS_HandleValueNotification(
+            p_msg->api_indicate.hdr.layer_specific, p_msg->api_indicate.attr_id,
+            p_msg->api_indicate.len, p_msg->api_indicate.value);
+
+      /* if over BR_EDR, inform PM for mode change */
+      if (transport == BTA_TRANSPORT_BR_EDR) {
+        bta_sys_busy(BTA_ID_GATTS, BTA_ALL_APP_ID, remote_bda);
+        bta_sys_idle(BTA_ID_GATTS, BTA_ALL_APP_ID, remote_bda);
+      }
+    } else {
+      APPL_TRACE_ERROR("Unknown connection ID: %d fail sending notification",
+                       p_msg->api_indicate.hdr.layer_specific);
+    }
+
+    if ((status != GATT_SUCCESS || !p_msg->api_indicate.need_confirm) &&
+        p_rcb && p_cb->rcb[p_srvc_cb->rcb_idx].p_cback) {
+      cb_data.req_data.status = status;
+      cb_data.req_data.conn_id = p_msg->api_indicate.hdr.layer_specific;
+
+      (*p_rcb->p_cback)(BTA_GATTS_CONF_EVT, &cb_data);
+    }
+  } else {
+    APPL_TRACE_ERROR("Not an registered servce attribute ID: 0x%04x",
+                     p_msg->api_indicate.attr_id);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gatts_open
+ *
+ * Description
+ *
+ * Returns          none.
+ *
+ ******************************************************************************/
+void bta_gatts_open(UNUSED_ATTR tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg) {
+  tBTA_GATTS_RCB* p_rcb = NULL;
+  tBTA_GATT_STATUS status = BTA_GATT_ERROR;
+  uint16_t conn_id;
+
+  if ((p_rcb = bta_gatts_find_app_rcb_by_app_if(p_msg->api_open.server_if)) !=
+      NULL) {
+    /* should always get the connection ID */
+    if (GATT_Connect(p_rcb->gatt_if, p_msg->api_open.remote_bda,
+                     p_msg->api_open.is_direct, p_msg->api_open.transport,
+                     false)) {
+      status = BTA_GATT_OK;
+
+      if (GATT_GetConnIdIfConnected(p_rcb->gatt_if, p_msg->api_open.remote_bda,
+                                    &conn_id, p_msg->api_open.transport)) {
+        status = BTA_GATT_ALREADY_OPEN;
+      }
+    }
+  } else {
+    APPL_TRACE_ERROR("Inavlide server_if=%d", p_msg->api_open.server_if);
+  }
+
+  if (p_rcb && p_rcb->p_cback)
+    (*p_rcb->p_cback)(BTA_GATTS_OPEN_EVT, (tBTA_GATTS*)&status);
+}
+/*******************************************************************************
+ *
+ * Function         bta_gatts_cancel_open
+ *
+ * Description
+ *
+ * Returns          none.
+ *
+ ******************************************************************************/
+void bta_gatts_cancel_open(UNUSED_ATTR tBTA_GATTS_CB* p_cb,
+                           tBTA_GATTS_DATA* p_msg) {
+  tBTA_GATTS_RCB* p_rcb;
+  tBTA_GATT_STATUS status = BTA_GATT_ERROR;
+
+  if ((p_rcb = bta_gatts_find_app_rcb_by_app_if(
+           p_msg->api_cancel_open.server_if)) != NULL) {
+    if (!GATT_CancelConnect(p_rcb->gatt_if, p_msg->api_cancel_open.remote_bda,
+                            p_msg->api_cancel_open.is_direct)) {
+      APPL_TRACE_ERROR("bta_gatts_cancel_open failed for open request");
+    } else {
+      status = BTA_GATT_OK;
+    }
+  } else {
+    APPL_TRACE_ERROR("Inavlide server_if=%d", p_msg->api_cancel_open.server_if);
+  }
+
+  if (p_rcb && p_rcb->p_cback)
+    (*p_rcb->p_cback)(BTA_GATTS_CANCEL_OPEN_EVT, (tBTA_GATTS*)&status);
+}
+/*******************************************************************************
+ *
+ * Function         bta_gatts_close
+ *
+ * Description
+ *
+ * Returns          none.
+ *
+ ******************************************************************************/
+void bta_gatts_close(UNUSED_ATTR tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg) {
+  tBTA_GATTS_RCB* p_rcb;
+  tBTA_GATT_STATUS status = BTA_GATT_ERROR;
+  tGATT_IF gatt_if;
+  BD_ADDR remote_bda;
+  tBTA_GATT_TRANSPORT transport;
+
+  if (GATT_GetConnectionInfor(p_msg->hdr.layer_specific, &gatt_if, remote_bda,
+                              &transport)) {
+    if (GATT_Disconnect(p_msg->hdr.layer_specific) != GATT_SUCCESS) {
+      APPL_TRACE_ERROR("bta_gatts_close fail conn_id=%d",
+                       p_msg->hdr.layer_specific);
+    } else {
+      status = BTA_GATT_OK;
+    }
+
+    p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if);
+
+    if (p_rcb && p_rcb->p_cback) {
+      if (transport == BTA_TRANSPORT_BR_EDR)
+        bta_sys_conn_close(BTA_ID_GATTS, BTA_ALL_APP_ID, remote_bda);
+
+      (*p_rcb->p_cback)(BTA_GATTS_CLOSE_EVT, (tBTA_GATTS*)&status);
+    }
+  } else {
+    APPL_TRACE_ERROR("Unknown connection ID: %d", p_msg->hdr.layer_specific);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gatts_request_cback
+ *
+ * Description      GATTS attribute request callback.
+ *
+ * Returns          none.
+ *
+ ******************************************************************************/
+static void bta_gatts_send_request_cback(uint16_t conn_id, uint32_t trans_id,
+                                         tGATTS_REQ_TYPE req_type,
+                                         tGATTS_DATA* p_data) {
+  tBTA_GATTS cb_data;
+  tBTA_GATTS_RCB* p_rcb;
+  tGATT_IF gatt_if;
+  tBTA_GATT_TRANSPORT transport;
+
+  memset(&cb_data, 0, sizeof(tBTA_GATTS));
+
+  if (GATT_GetConnectionInfor(conn_id, &gatt_if, cb_data.req_data.remote_bda,
+                              &transport)) {
+    p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if);
+
+    APPL_TRACE_DEBUG("%s: conn_id=%d trans_id=%d req_type=%d", __func__,
+                     conn_id, trans_id, req_type);
+
+    if (p_rcb && p_rcb->p_cback) {
+      /* if over BR_EDR, inform PM for mode change */
+      if (transport == BTA_TRANSPORT_BR_EDR) {
+        bta_sys_busy(BTA_ID_GATTS, BTA_ALL_APP_ID, cb_data.req_data.remote_bda);
+        bta_sys_idle(BTA_ID_GATTS, BTA_ALL_APP_ID, cb_data.req_data.remote_bda);
+      }
+
+      cb_data.req_data.conn_id = conn_id;
+      cb_data.req_data.trans_id = trans_id;
+      cb_data.req_data.p_data = (tBTA_GATTS_REQ_DATA*)p_data;
+
+      (*p_rcb->p_cback)(req_type, &cb_data);
+    } else {
+      APPL_TRACE_ERROR("connection request on gatt_if[%d] is not interested",
+                       gatt_if);
+    }
+  } else {
+    APPL_TRACE_ERROR("request received on unknown connectino ID: %d", conn_id);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gatts_conn_cback
+ *
+ * Description      connection callback.
+ *
+ * Returns          none.
+ *
+ ******************************************************************************/
+static void bta_gatts_conn_cback(tGATT_IF gatt_if, BD_ADDR bda,
+                                 uint16_t conn_id, bool connected,
+                                 tGATT_DISCONN_REASON reason,
+                                 tGATT_TRANSPORT transport) {
+  tBTA_GATTS cb_data;
+  uint8_t evt = connected ? BTA_GATTS_CONNECT_EVT : BTA_GATTS_DISCONNECT_EVT;
+  tBTA_GATTS_RCB* p_reg;
+
+  APPL_TRACE_DEBUG(
+      "bta_gatts_conn_cback gatt_if=%d conn_id=%d connected=%d reason = 0x%04d",
+      gatt_if, conn_id, connected, reason);
+  APPL_TRACE_DEBUG("bta_gatts_conn_cback  bda :%02x-%02x-%02x-%02x-%02x-%02x ",
+                   bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+
+  bt_bdaddr_t bdaddr;
+  bdcpy(bdaddr.address, bda);
+  if (connected)
+    btif_debug_conn_state(bdaddr, BTIF_DEBUG_CONNECTED, GATT_CONN_UNKNOWN);
+  else
+    btif_debug_conn_state(bdaddr, BTIF_DEBUG_DISCONNECTED, reason);
+
+  p_reg = bta_gatts_find_app_rcb_by_app_if(gatt_if);
+
+  if (p_reg && p_reg->p_cback) {
+    /* there is no RM for GATT */
+    if (transport == BTA_TRANSPORT_BR_EDR) {
+      if (connected)
+        bta_sys_conn_open(BTA_ID_GATTS, BTA_ALL_APP_ID, bda);
+      else
+        bta_sys_conn_close(BTA_ID_GATTS, BTA_ALL_APP_ID, bda);
+    }
+
+    cb_data.conn.conn_id = conn_id;
+    cb_data.conn.server_if = gatt_if;
+    cb_data.conn.reason = reason;
+    cb_data.conn.transport = transport;
+    memcpy(cb_data.conn.remote_bda, bda, BD_ADDR_LEN);
+    (*p_reg->p_cback)(evt, &cb_data);
+  } else {
+    APPL_TRACE_ERROR("bta_gatts_conn_cback server_if=%d not found", gatt_if);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gatts_cong_cback
+ *
+ * Description      congestion callback.
+ *
+ * Returns          none.
+ *
+ ******************************************************************************/
+static void bta_gatts_cong_cback(uint16_t conn_id, bool congested) {
+  tBTA_GATTS_RCB* p_rcb;
+  tGATT_IF gatt_if;
+  tBTA_GATT_TRANSPORT transport;
+  tBTA_GATTS cb_data;
+
+  if (GATT_GetConnectionInfor(conn_id, &gatt_if, cb_data.req_data.remote_bda,
+                              &transport)) {
+    p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if);
+
+    if (p_rcb && p_rcb->p_cback) {
+      cb_data.congest.conn_id = conn_id;
+      cb_data.congest.congested = congested;
+
+      (*p_rcb->p_cback)(BTA_GATTS_CONGEST_EVT, &cb_data);
+    }
+  }
+}
+#endif /* BTA_GATT_INCLUDED */
diff --git a/bt/bta/gatt/bta_gatts_api.cc b/bt/bta/gatt/bta_gatts_api.cc
new file mode 100644
index 0000000..a56ec4e
--- /dev/null
+++ b/bt/bta/gatt/bta_gatts_api.cc
@@ -0,0 +1,347 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2010-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 is the implementation of the API for GATT server of BTA.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if (BTA_GATT_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_gatt_api.h"
+#include "bta_gatts_int.h"
+#include "bta_sys.h"
+
+void btif_to_bta_uuid(tBT_UUID* p_dest, const bt_uuid_t* p_src);
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_gatts_reg = {bta_gatts_hdl_event,
+                                           BTA_GATTS_Disable};
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_Disable
+ *
+ * Description      This function is called to disable GATTS module
+ *
+ * Parameters       None.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_GATTS_Disable(void) {
+  if (bta_sys_is_register(BTA_ID_GATTS) == false) {
+    APPL_TRACE_WARNING("GATTS Module not enabled/already disabled");
+    return;
+  }
+
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+  p_buf->event = BTA_GATTS_API_DISABLE_EVT;
+  bta_sys_sendmsg(p_buf);
+  bta_sys_deregister(BTA_ID_GATTS);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_AppRegister
+ *
+ * Description      This function is called to register application callbacks
+ *                    with BTA GATTS module.
+ *
+ * Parameters       p_app_uuid - applicaiton UUID
+ *                  p_cback - pointer to the application callback function.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_GATTS_AppRegister(tBT_UUID* p_app_uuid, tBTA_GATTS_CBACK* p_cback) {
+  tBTA_GATTS_API_REG* p_buf =
+      (tBTA_GATTS_API_REG*)osi_malloc(sizeof(tBTA_GATTS_API_REG));
+
+  /* register with BTA system manager */
+  if (bta_sys_is_register(BTA_ID_GATTS) == false)
+    bta_sys_register(BTA_ID_GATTS, &bta_gatts_reg);
+
+  p_buf->hdr.event = BTA_GATTS_API_REG_EVT;
+  if (p_app_uuid != NULL)
+    memcpy(&p_buf->app_uuid, p_app_uuid, sizeof(tBT_UUID));
+  p_buf->p_cback = p_cback;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_AppDeregister
+ *
+ * Description      De-register with GATT Server.
+ *
+ * Parameters       app_id: applicatino ID.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_GATTS_AppDeregister(tBTA_GATTS_IF server_if) {
+  tBTA_GATTS_API_DEREG* p_buf =
+      (tBTA_GATTS_API_DEREG*)osi_malloc(sizeof(tBTA_GATTS_API_DEREG));
+
+  p_buf->hdr.event = BTA_GATTS_API_DEREG_EVT;
+  p_buf->server_if = server_if;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_AddService
+ *
+ * Description      Add the given |service| and all included elements to the
+ *                  GATT database. a |BTA_GATTS_ADD_SRVC_EVT| is triggered to
+ *                  report the status and attribute handles.
+ *
+ * Parameters       server_if: server interface.
+ *                  service: pointer vector describing service.
+ *
+ * Returns          Returns |BTA_GATT_OK| on success or |BTA_GATT_ERROR| if the
+ *                  service cannot be added.
+ *
+ ******************************************************************************/
+extern uint16_t BTA_GATTS_AddService(tBTA_GATTS_IF server_if,
+                                     vector<btgatt_db_element_t>& service) {
+  uint8_t rcb_idx =
+      bta_gatts_find_app_rcb_idx_by_app_if(&bta_gatts_cb, server_if);
+
+  APPL_TRACE_ERROR("%s: rcb_idx = %d", __func__, rcb_idx);
+
+  if (rcb_idx == BTA_GATTS_INVALID_APP) return BTA_GATT_ERROR;
+
+  uint8_t srvc_idx = bta_gatts_alloc_srvc_cb(&bta_gatts_cb, rcb_idx);
+  if (srvc_idx == BTA_GATTS_INVALID_APP) return BTA_GATT_ERROR;
+
+  uint16_t status = GATTS_AddService(server_if, service.data(), service.size());
+
+  if (status == GATT_SERVICE_STARTED) {
+    btif_to_bta_uuid(&bta_gatts_cb.srvc_cb[srvc_idx].service_uuid,
+                     &service[0].uuid);
+
+    // service_id is equal to service start handle
+    bta_gatts_cb.srvc_cb[srvc_idx].service_id = service[0].attribute_handle;
+    bta_gatts_cb.srvc_cb[srvc_idx].idx = srvc_idx;
+
+    return BTA_GATT_OK;
+  } else {
+    memset(&bta_gatts_cb.srvc_cb[srvc_idx], 0, sizeof(tBTA_GATTS_SRVC_CB));
+    APPL_TRACE_ERROR("%s: service creation failed.", __func__);
+    return BTA_GATT_ERROR;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_DeleteService
+ *
+ * Description      This function is called to delete a service. When this is
+ *                  done, a callback event BTA_GATTS_DELETE_EVT is report with
+ *                  the status.
+ *
+ * Parameters       service_id: service_id to be deleted.
+ *
+ * Returns          returns none.
+ *
+ ******************************************************************************/
+void BTA_GATTS_DeleteService(uint16_t service_id) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = BTA_GATTS_API_DEL_SRVC_EVT;
+  p_buf->layer_specific = service_id;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_StopService
+ *
+ * Description      This function is called to stop a service.
+ *
+ * Parameters       service_id - service to be topped.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_GATTS_StopService(uint16_t service_id) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = BTA_GATTS_API_STOP_SRVC_EVT;
+  p_buf->layer_specific = service_id;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_HandleValueIndication
+ *
+ * Description      This function is called to read a characteristics
+ *                  descriptor.
+ *
+ * Parameters       bda - remote device bd address to indicate.
+ *                  attr_id - attribute ID to indicate.
+ *                  value - data to indicate.
+ *                  need_confirm - if this indication expects a confirmation or
+ *                                 not.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_GATTS_HandleValueIndication(uint16_t conn_id, uint16_t attr_id,
+                                     std::vector<uint8_t> value,
+                                     bool need_confirm) {
+  tBTA_GATTS_API_INDICATION* p_buf =
+      (tBTA_GATTS_API_INDICATION*)osi_calloc(sizeof(tBTA_GATTS_API_INDICATION));
+
+  p_buf->hdr.event = BTA_GATTS_API_INDICATION_EVT;
+  p_buf->hdr.layer_specific = conn_id;
+  p_buf->attr_id = attr_id;
+  p_buf->need_confirm = need_confirm;
+  if (value.size() > 0) {
+    p_buf->len = value.size();
+    memcpy(p_buf->value, value.data(), value.size());
+  }
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_SendRsp
+ *
+ * Description      This function is called to send a response to a request.
+ *
+ * Parameters       conn_id - connection identifier.
+ *                  trans_id - transaction ID.
+ *                  status - response status
+ *                  p_msg - response data.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_GATTS_SendRsp(uint16_t conn_id, uint32_t trans_id,
+                       tBTA_GATT_STATUS status, tBTA_GATTS_RSP* p_msg) {
+  const size_t len = sizeof(tBTA_GATTS_API_RSP) + sizeof(tBTA_GATTS_RSP);
+  tBTA_GATTS_API_RSP* p_buf = (tBTA_GATTS_API_RSP*)osi_calloc(len);
+
+  p_buf->hdr.event = BTA_GATTS_API_RSP_EVT;
+  p_buf->hdr.layer_specific = conn_id;
+  p_buf->trans_id = trans_id;
+  p_buf->status = status;
+  if (p_msg != NULL) {
+    p_buf->p_rsp = (tBTA_GATTS_RSP*)(p_buf + 1);
+    memcpy(p_buf->p_rsp, p_msg, sizeof(tBTA_GATTS_RSP));
+  }
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_Open
+ *
+ * Description      Open a direct open connection or add a background auto
+ *                  connection bd address
+ *
+ * Parameters       server_if: server interface.
+ *                  remote_bda: remote device BD address.
+ *                  is_direct: direct connection or background auto connection
+ *                  transport : Transport on which GATT connection to be opened
+ *                              (BR/EDR or LE)
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_GATTS_Open(tBTA_GATTS_IF server_if, BD_ADDR remote_bda, bool is_direct,
+                    tBTA_GATT_TRANSPORT transport) {
+  tBTA_GATTS_API_OPEN* p_buf =
+      (tBTA_GATTS_API_OPEN*)osi_malloc(sizeof(tBTA_GATTS_API_OPEN));
+
+  p_buf->hdr.event = BTA_GATTS_API_OPEN_EVT;
+  p_buf->server_if = server_if;
+  p_buf->is_direct = is_direct;
+  p_buf->transport = transport;
+  memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN);
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_CancelOpen
+ *
+ * Description      Cancel a direct open connection or remove a background auto
+ *                  connection bd address
+ *
+ * Parameters       server_if: server interface.
+ *                  remote_bda: remote device BD address.
+ *                  is_direct: direct connection or background auto connection
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_GATTS_CancelOpen(tBTA_GATTS_IF server_if, BD_ADDR remote_bda,
+                          bool is_direct) {
+  tBTA_GATTS_API_CANCEL_OPEN* p_buf = (tBTA_GATTS_API_CANCEL_OPEN*)osi_malloc(
+      sizeof(tBTA_GATTS_API_CANCEL_OPEN));
+
+  p_buf->hdr.event = BTA_GATTS_API_CANCEL_OPEN_EVT;
+  p_buf->server_if = server_if;
+  p_buf->is_direct = is_direct;
+  memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN);
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_Close
+ *
+ * Description      Close a connection  a remote device.
+ *
+ * Parameters       conn_id: connectino ID to be closed.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_GATTS_Close(uint16_t conn_id) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = BTA_GATTS_API_CLOSE_EVT;
+  p_buf->layer_specific = conn_id;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+#endif /* BTA_GATT_INCLUDED */
diff --git a/bt/bta/gatt/bta_gatts_int.h b/bt/bta/gatt/bta_gatts_int.h
new file mode 100644
index 0000000..91bd9fe
--- /dev/null
+++ b/bt/bta/gatt/bta_gatts_int.h
@@ -0,0 +1,189 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 is the private file for the BTA GATT server.
+ *
+ ******************************************************************************/
+#ifndef BTA_GATTS_INT_H
+#define BTA_GATTS_INT_H
+
+#include "bt_target.h"
+#include "bta_gatt_api.h"
+#include "bta_sys.h"
+#include "gatt_api.h"
+
+#include "bt_common.h"
+
+/*****************************************************************************
+ *  Constants and data types
+ ****************************************************************************/
+enum {
+  BTA_GATTS_API_REG_EVT = BTA_SYS_EVT_START(BTA_ID_GATTS),
+  BTA_GATTS_INT_START_IF_EVT,
+  BTA_GATTS_API_DEREG_EVT,
+  BTA_GATTS_API_INDICATION_EVT,
+
+  BTA_GATTS_API_DEL_SRVC_EVT,
+  BTA_GATTS_API_STOP_SRVC_EVT,
+  BTA_GATTS_API_RSP_EVT,
+  BTA_GATTS_API_OPEN_EVT,
+  BTA_GATTS_API_CANCEL_OPEN_EVT,
+  BTA_GATTS_API_CLOSE_EVT,
+  BTA_GATTS_API_DISABLE_EVT
+};
+typedef uint16_t tBTA_GATTS_INT_EVT;
+
+/* max number of application allowed on device */
+#define BTA_GATTS_MAX_APP_NUM GATT_MAX_SR_PROFILES
+
+/* max number of services allowed in the device */
+#define BTA_GATTS_MAX_SRVC_NUM GATT_MAX_SR_PROFILES
+
+/* internal strucutre for GATTC register API  */
+typedef struct {
+  BT_HDR hdr;
+  tBT_UUID app_uuid;
+  tBTA_GATTS_CBACK* p_cback;
+} tBTA_GATTS_API_REG;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_GATTS_IF server_if;
+} tBTA_GATTS_INT_START_IF;
+
+typedef tBTA_GATTS_INT_START_IF tBTA_GATTS_API_DEREG;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_GATTS_IF server_if;
+  btgatt_db_element_t* service;
+  uint16_t count;
+} tBTA_GATTS_API_ADD_SERVICE;
+
+typedef struct {
+  BT_HDR hdr;
+  uint16_t attr_id;
+  uint16_t len;
+  bool need_confirm;
+  uint8_t value[BTA_GATT_MAX_ATTR_LEN];
+} tBTA_GATTS_API_INDICATION;
+
+typedef struct {
+  BT_HDR hdr;
+  uint32_t trans_id;
+  tBTA_GATT_STATUS status;
+  tBTA_GATTS_RSP* p_rsp;
+} tBTA_GATTS_API_RSP;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_GATT_TRANSPORT transport;
+} tBTA_GATTS_API_START;
+
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR remote_bda;
+  tBTA_GATTS_IF server_if;
+  bool is_direct;
+  tBTA_GATT_TRANSPORT transport;
+
+} tBTA_GATTS_API_OPEN;
+
+typedef tBTA_GATTS_API_OPEN tBTA_GATTS_API_CANCEL_OPEN;
+
+typedef union {
+  BT_HDR hdr;
+  tBTA_GATTS_API_REG api_reg;
+  tBTA_GATTS_API_DEREG api_dereg;
+  tBTA_GATTS_API_ADD_SERVICE api_add_service;
+  tBTA_GATTS_API_INDICATION api_indicate;
+  tBTA_GATTS_API_RSP api_rsp;
+  tBTA_GATTS_API_OPEN api_open;
+  tBTA_GATTS_API_CANCEL_OPEN api_cancel_open;
+
+  tBTA_GATTS_INT_START_IF int_start_if;
+} tBTA_GATTS_DATA;
+
+/* application registration control block */
+typedef struct {
+  bool in_use;
+  tBT_UUID app_uuid;
+  tBTA_GATTS_CBACK* p_cback;
+  tBTA_GATTS_IF gatt_if;
+} tBTA_GATTS_RCB;
+
+/* service registration control block */
+typedef struct {
+  tBT_UUID service_uuid; /* service UUID */
+  uint16_t service_id;   /* service start handle */
+  uint8_t rcb_idx;
+  uint8_t idx; /* self index of serviec CB */
+  bool in_use;
+} tBTA_GATTS_SRVC_CB;
+
+/* GATT server control block */
+typedef struct {
+  bool enabled;
+  tBTA_GATTS_RCB rcb[BTA_GATTS_MAX_APP_NUM];
+  tBTA_GATTS_SRVC_CB srvc_cb[BTA_GATTS_MAX_SRVC_NUM];
+} tBTA_GATTS_CB;
+
+/*****************************************************************************
+ *  Global data
+ ****************************************************************************/
+
+/* GATTC control block */
+extern tBTA_GATTS_CB bta_gatts_cb;
+
+/*****************************************************************************
+ *  Function prototypes
+ ****************************************************************************/
+extern bool bta_gatts_hdl_event(BT_HDR* p_msg);
+
+extern void bta_gatts_api_disable(tBTA_GATTS_CB* p_cb);
+extern void bta_gatts_api_enable(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_data);
+extern void bta_gatts_register(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg);
+extern void bta_gatts_start_if(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg);
+extern void bta_gatts_deregister(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg);
+extern void bta_gatts_delete_service(tBTA_GATTS_SRVC_CB* p_srvc_cb,
+                                     tBTA_GATTS_DATA* p_msg);
+extern void bta_gatts_stop_service(tBTA_GATTS_SRVC_CB* p_srvc_cb,
+                                   tBTA_GATTS_DATA* p_msg);
+
+extern void bta_gatts_send_rsp(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg);
+extern void bta_gatts_indicate_handle(tBTA_GATTS_CB* p_cb,
+                                      tBTA_GATTS_DATA* p_msg);
+
+extern void bta_gatts_open(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg);
+extern void bta_gatts_cancel_open(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg);
+extern void bta_gatts_close(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg);
+
+extern bool bta_gatts_uuid_compare(tBT_UUID tar, tBT_UUID src);
+extern tBTA_GATTS_RCB* bta_gatts_find_app_rcb_by_app_if(
+    tBTA_GATTS_IF server_if);
+extern uint8_t bta_gatts_find_app_rcb_idx_by_app_if(tBTA_GATTS_CB* p_cb,
+                                                    tBTA_GATTS_IF server_if);
+extern uint8_t bta_gatts_alloc_srvc_cb(tBTA_GATTS_CB* p_cb, uint8_t rcb_idx);
+extern tBTA_GATTS_SRVC_CB* bta_gatts_find_srvc_cb_by_srvc_id(
+    tBTA_GATTS_CB* p_cb, uint16_t service_id);
+extern tBTA_GATTS_SRVC_CB* bta_gatts_find_srvc_cb_by_attr_id(
+    tBTA_GATTS_CB* p_cb, uint16_t attr_id);
+
+#endif /* BTA_GATTS_INT_H */
diff --git a/bt/bta/gatt/bta_gatts_main.cc b/bt/bta/gatt/bta_gatts_main.cc
new file mode 100644
index 0000000..8c97314
--- /dev/null
+++ b/bt/bta/gatt/bta_gatts_main.cc
@@ -0,0 +1,119 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 GATT server main functions and state machine.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if (BTA_GATT_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_gatts_int.h"
+
+/* GATTS control block */
+tBTA_GATTS_CB bta_gatts_cb;
+
+/*******************************************************************************
+ *
+ * Function         bta_gatts_hdl_event
+ *
+ * Description      BTA GATT server main event handling function.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+bool bta_gatts_hdl_event(BT_HDR* p_msg) {
+  tBTA_GATTS_CB* p_cb = &bta_gatts_cb;
+
+  switch (p_msg->event) {
+    case BTA_GATTS_API_DISABLE_EVT:
+      bta_gatts_api_disable(p_cb);
+      break;
+
+    case BTA_GATTS_API_REG_EVT:
+      bta_gatts_register(p_cb, (tBTA_GATTS_DATA*)p_msg);
+      break;
+
+    case BTA_GATTS_INT_START_IF_EVT:
+      bta_gatts_start_if(p_cb, (tBTA_GATTS_DATA*)p_msg);
+      break;
+
+    case BTA_GATTS_API_DEREG_EVT:
+      bta_gatts_deregister(p_cb, (tBTA_GATTS_DATA*)p_msg);
+      break;
+
+    case BTA_GATTS_API_INDICATION_EVT:
+      bta_gatts_indicate_handle(p_cb, (tBTA_GATTS_DATA*)p_msg);
+      break;
+
+    case BTA_GATTS_API_OPEN_EVT:
+      bta_gatts_open(p_cb, (tBTA_GATTS_DATA*)p_msg);
+      break;
+
+    case BTA_GATTS_API_CANCEL_OPEN_EVT:
+      bta_gatts_cancel_open(p_cb, (tBTA_GATTS_DATA*)p_msg);
+      break;
+
+    case BTA_GATTS_API_CLOSE_EVT:
+      bta_gatts_close(p_cb, (tBTA_GATTS_DATA*)p_msg);
+      break;
+
+    case BTA_GATTS_API_RSP_EVT:
+      bta_gatts_send_rsp(p_cb, (tBTA_GATTS_DATA*)p_msg);
+      break;
+
+    case BTA_GATTS_API_DEL_SRVC_EVT: {
+      tBTA_GATTS_SRVC_CB* p_srvc_cb = bta_gatts_find_srvc_cb_by_srvc_id(
+          p_cb, ((tBTA_GATTS_DATA*)p_msg)->api_add_service.hdr.layer_specific);
+
+      if (p_srvc_cb != NULL)
+        bta_gatts_delete_service(p_srvc_cb, (tBTA_GATTS_DATA*)p_msg);
+      else
+        APPL_TRACE_ERROR("%s: can't delete service - no srvc_cb found",
+                         __func__);
+
+      break;
+    }
+
+    case BTA_GATTS_API_STOP_SRVC_EVT: {
+      tBTA_GATTS_SRVC_CB* p_srvc_cb = bta_gatts_find_srvc_cb_by_srvc_id(
+          p_cb, ((tBTA_GATTS_DATA*)p_msg)->api_add_service.hdr.layer_specific);
+
+      if (p_srvc_cb != NULL)
+        bta_gatts_stop_service(p_srvc_cb, (tBTA_GATTS_DATA*)p_msg);
+      else
+        APPL_TRACE_ERROR("%s: can't stop service - no srvc_cb found", __func__);
+
+      break;
+    }
+
+    default:
+      break;
+  }
+
+  return (true);
+}
+
+#endif /* BTA_GATT_INCLUDED */
diff --git a/bt/bta/gatt/bta_gatts_utils.cc b/bt/bta/gatt/bta_gatts_utils.cc
new file mode 100644
index 0000000..2196a2c
--- /dev/null
+++ b/bt/bta/gatt/bta_gatts_utils.cc
@@ -0,0 +1,214 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 GATT client utility function.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if (BTA_GATT_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_gatts_int.h"
+#include "bta_sys.h"
+#include "utl.h"
+
+static const uint8_t base_uuid[LEN_UUID_128] = {
+    0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
+    0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/*******************************************************************************
+ *
+ * Function         bta_gatt_convert_uuid16_to_uuid128
+ *
+ * Description      Convert a 16 bits UUID to be an standard 128 bits one.
+ *
+ * Returns          true if two uuid match; false otherwise.
+ *
+ ******************************************************************************/
+static void bta_gatt_convert_uuid16_to_uuid128(uint8_t uuid_128[LEN_UUID_128],
+                                               uint16_t uuid_16) {
+  uint8_t* p = &uuid_128[LEN_UUID_128 - 4];
+
+  memcpy(uuid_128, base_uuid, LEN_UUID_128);
+
+  UINT16_TO_STREAM(p, uuid_16);
+}
+/*******************************************************************************
+ *
+ * Function         bta_gatts_alloc_srvc_cb
+ *
+ * Description      allocate a service control block.
+ *
+ * Returns          pointer to the control block, or otherwise NULL when failed.
+ *
+ ******************************************************************************/
+uint8_t bta_gatts_alloc_srvc_cb(tBTA_GATTS_CB* p_cb, uint8_t rcb_idx) {
+  uint8_t i;
+
+  for (i = 0; i < BTA_GATTS_MAX_SRVC_NUM; i++) {
+    if (!p_cb->srvc_cb[i].in_use) {
+      p_cb->srvc_cb[i].in_use = true;
+      p_cb->srvc_cb[i].rcb_idx = rcb_idx;
+      return i;
+    }
+  }
+  return BTA_GATTS_INVALID_APP;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gatts_find_app_rcb_by_app_if
+ *
+ * Description      find the index of the application control block by app ID.
+ *
+ * Returns          pointer to the control block if success, otherwise NULL
+ *
+ ******************************************************************************/
+tBTA_GATTS_RCB* bta_gatts_find_app_rcb_by_app_if(tBTA_GATTS_IF server_if) {
+  uint8_t i;
+  tBTA_GATTS_RCB* p_reg;
+
+  for (i = 0, p_reg = bta_gatts_cb.rcb; i < BTA_GATTS_MAX_APP_NUM;
+       i++, p_reg++) {
+    if (p_reg->in_use && p_reg->gatt_if == server_if) return p_reg;
+  }
+  return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gatts_find_app_rcb_idx_by_app_if
+ *
+ * Description      find the index of the application control block by app ID.
+ *
+ * Returns          index of the control block, or BTA_GATTS_INVALID_APP if
+ *                  failed.
+ *
+ ******************************************************************************/
+
+uint8_t bta_gatts_find_app_rcb_idx_by_app_if(tBTA_GATTS_CB* p_cb,
+                                             tBTA_GATTS_IF server_if) {
+  uint8_t i;
+
+  for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i++) {
+    if (p_cb->rcb[i].in_use && p_cb->rcb[i].gatt_if == server_if) return i;
+  }
+  return BTA_GATTS_INVALID_APP;
+}
+/*******************************************************************************
+ *
+ * Function         bta_gatts_find_srvc_cb_by_srvc_id
+ *
+ * Description      find the service control block by service ID.
+ *
+ * Returns          pointer to the rcb.
+ *
+ ******************************************************************************/
+tBTA_GATTS_SRVC_CB* bta_gatts_find_srvc_cb_by_srvc_id(tBTA_GATTS_CB* p_cb,
+                                                      uint16_t service_id) {
+  uint8_t i;
+  APPL_TRACE_DEBUG("bta_gatts_find_srvc_cb_by_srvc_id  service_id=%d",
+                   service_id);
+  for (i = 0; i < BTA_GATTS_MAX_SRVC_NUM; i++) {
+    if (p_cb->srvc_cb[i].in_use && p_cb->srvc_cb[i].service_id == service_id) {
+      APPL_TRACE_DEBUG(
+          "bta_gatts_find_srvc_cb_by_srvc_id  found service cb index =%d", i);
+      return &p_cb->srvc_cb[i];
+    }
+  }
+  return NULL;
+}
+/*******************************************************************************
+ *
+ * Function         bta_gatts_find_srvc_cb_by_attr_id
+ *
+ * Description      find the service control block by attribute ID.
+ *
+ * Returns          pointer to the rcb.
+ *
+ ******************************************************************************/
+tBTA_GATTS_SRVC_CB* bta_gatts_find_srvc_cb_by_attr_id(tBTA_GATTS_CB* p_cb,
+                                                      uint16_t attr_id) {
+  uint8_t i;
+
+  for (i = 0; i < (BTA_GATTS_MAX_SRVC_NUM); i++) {
+    if (/* middle service */
+        (i < (BTA_GATTS_MAX_SRVC_NUM - 1) && p_cb->srvc_cb[i].in_use &&
+         p_cb->srvc_cb[i + 1].in_use &&
+         attr_id >= p_cb->srvc_cb[i].service_id &&
+         attr_id < p_cb->srvc_cb[i + 1].service_id) ||
+        /* last active service */
+        (i < (BTA_GATTS_MAX_SRVC_NUM - 1) && p_cb->srvc_cb[i].in_use &&
+         !p_cb->srvc_cb[i + 1].in_use &&
+         attr_id >= p_cb->srvc_cb[i].service_id) ||
+        /* last service incb */
+        (i == (BTA_GATTS_MAX_SRVC_NUM - 1) &&
+         attr_id >= p_cb->srvc_cb[i].service_id)) {
+      return &p_cb->srvc_cb[i];
+    }
+  }
+  return NULL;
+}
+/*******************************************************************************
+ *
+ * Function         bta_gatts_uuid_compare
+ *
+ * Description      Compare two UUID to see if they are the same.
+ *
+ * Returns          true if two uuid match; false otherwise.
+ *
+ ******************************************************************************/
+bool bta_gatts_uuid_compare(tBT_UUID tar, tBT_UUID src) {
+  uint8_t su[LEN_UUID_128], tu[LEN_UUID_128];
+  uint8_t *ps, *pt;
+
+  /* any of the UUID is unspecified */
+  if (src.len == 0 || tar.len == 0) {
+    return true;
+  }
+
+  /* If both are 16-bit, we can do a simple compare */
+  if (src.len == 2 && tar.len == 2) {
+    return src.uu.uuid16 == tar.uu.uuid16;
+  }
+
+  /* One or both of the UUIDs is 128-bit */
+  if (src.len == LEN_UUID_16) {
+    /* convert a 16 bits UUID to 128 bits value */
+    bta_gatt_convert_uuid16_to_uuid128(su, src.uu.uuid16);
+    ps = su;
+  } else
+    ps = src.uu.uuid128;
+
+  if (tar.len == LEN_UUID_16) {
+    /* convert a 16 bits UUID to 128 bits value */
+    bta_gatt_convert_uuid16_to_uuid128(tu, tar.uu.uuid16);
+    pt = tu;
+  } else
+    pt = tar.uu.uuid128;
+
+  return (memcmp(ps, pt, LEN_UUID_128) == 0);
+}
+
+#endif
diff --git a/bt/bta/hf_client/bta_hf_client_act.cc b/bt/bta/hf_client/bta_hf_client_act.cc
new file mode 100644
index 0000000..9724d26
--- /dev/null
+++ b/bt/bta/hf_client/bta_hf_client_act.cc
@@ -0,0 +1,719 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-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 action functions for the handsfree client.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_utils.h"
+#include "bta_api.h"
+#include "bta_dm_api.h"
+#include "bta_hf_client_api.h"
+#include "bta_hf_client_int.h"
+#include "bta_sys.h"
+#include "l2c_api.h"
+#include "osi/include/compat.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+#include "utl.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+/* maximum length of data to read from RFCOMM */
+#define BTA_HF_CLIENT_RFC_READ_MAX 512
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_register
+ *
+ * Description      This function initializes values of the scb and sets up
+ *                  the SDP record for the services.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_register(tBTA_HF_CLIENT_DATA* p_data) {
+  tBTA_HF_CLIENT evt;
+  tBTA_UTL_COD cod;
+
+  memset(&evt, 0, sizeof(evt));
+
+  /* initialize control block */
+  bta_hf_client_scb_init();
+
+  bta_hf_client_cb.scb.serv_sec_mask = p_data->api_register.sec_mask;
+  bta_hf_client_cb.scb.features = p_data->api_register.features;
+
+  /* initialize AT control block */
+  bta_hf_client_at_init();
+
+  /* create SDP records */
+  bta_hf_client_create_record(p_data);
+
+  /* Set the Audio service class bit */
+  cod.service = BTM_COD_SERVICE_AUDIO;
+  utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
+
+  /* start RFCOMM server */
+  bta_hf_client_start_server();
+
+  /* call app callback with register event */
+  evt.reg.status = BTA_HF_CLIENT_SUCCESS;
+  (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_REGISTER_EVT, &evt);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_deregister
+ *
+ * Description      This function removes the sdp records, closes the RFCOMM
+ *                  servers, and deallocates the service control block.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_deregister(tBTA_HF_CLIENT_DATA* p_data) {
+  bta_hf_client_cb.scb.deregister = true;
+
+  /* remove sdp record */
+  bta_hf_client_del_record(p_data);
+
+  /* remove rfcomm server */
+  bta_hf_client_close_server();
+
+  /* disable */
+  bta_hf_client_scb_disable();
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_start_dereg
+ *
+ * Description      Start a deregister event.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_start_dereg(tBTA_HF_CLIENT_DATA* p_data) {
+  bta_hf_client_cb.scb.deregister = true;
+
+  /* remove sdp record */
+  bta_hf_client_del_record(p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_start_close
+ *
+ * Description      Start the process of closing SCO and RFCOMM connection.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_start_close(tBTA_HF_CLIENT_DATA* p_data) {
+  /* Take the link out of sniff and set L2C idle time to 0 */
+  bta_dm_pm_active(bta_hf_client_cb.scb.peer_addr);
+  L2CA_SetIdleTimeoutByBdAddr(bta_hf_client_cb.scb.peer_addr, 0,
+                              BT_TRANSPORT_BR_EDR);
+
+  /* if SCO is open close SCO and wait on RFCOMM close */
+  if (bta_hf_client_cb.scb.sco_state == BTA_HF_CLIENT_SCO_OPEN_ST) {
+    bta_hf_client_cb.scb.sco_close_rfc = true;
+  } else {
+    bta_hf_client_rfc_do_close(p_data);
+  }
+
+  /* always do SCO shutdown to handle all SCO corner cases */
+  bta_hf_client_sco_shutdown(NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_start_open
+ *
+ * Description      This starts an HF Client open.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_start_open(tBTA_HF_CLIENT_DATA* p_data) {
+  BD_ADDR pending_bd_addr;
+
+  /* store parameters */
+  if (p_data) {
+    bdcpy(bta_hf_client_cb.scb.peer_addr, p_data->api_open.bd_addr);
+    bta_hf_client_cb.scb.cli_sec_mask = p_data->api_open.sec_mask;
+  }
+
+  /* Check if RFCOMM has any incoming connection to avoid collision. */
+  if (PORT_IsOpening(pending_bd_addr)) {
+    /* Let the incoming connection goes through.                        */
+    /* Issue collision for now.                                         */
+    /* We will decide what to do when we find incoming connection later.*/
+    bta_hf_client_collision_cback(0, BTA_ID_HS, 0,
+                                  bta_hf_client_cb.scb.peer_addr);
+    return;
+  }
+
+  /* close server */
+  bta_hf_client_close_server();
+
+  /* set role */
+  bta_hf_client_cb.scb.role = BTA_HF_CLIENT_INT;
+
+  /* do service search */
+  bta_hf_client_do_disc();
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_cback_open
+ *
+ * Description      Send open callback event to application.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hf_client_cback_open(tBTA_HF_CLIENT_DATA* p_data,
+                                     tBTA_HF_CLIENT_STATUS status) {
+  tBTA_HF_CLIENT evt;
+
+  memset(&evt, 0, sizeof(evt));
+
+  /* call app callback with open event */
+  evt.open.status = status;
+  if (p_data) {
+    /* if p_data is provided then we need to pick the bd address from the open
+     * api structure */
+    bdcpy(evt.open.bd_addr, p_data->api_open.bd_addr);
+  } else {
+    bdcpy(evt.open.bd_addr, bta_hf_client_cb.scb.peer_addr);
+  }
+
+  (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_OPEN_EVT, &evt);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_rfc_open
+ *
+ * Description      Handle RFCOMM channel open.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_rfc_open(UNUSED_ATTR tBTA_HF_CLIENT_DATA* p_data) {
+  bta_sys_conn_open(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+
+  bta_hf_client_cback_open(NULL, BTA_HF_CLIENT_SUCCESS);
+
+  /* start SLC procedure */
+  bta_hf_client_slc_seq(false);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_rfc_acp_open
+ *
+ * Description      Handle RFCOMM channel open when accepting connection.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_rfc_acp_open(tBTA_HF_CLIENT_DATA* p_data) {
+  uint16_t lcid;
+  BD_ADDR dev_addr;
+  int status;
+
+  /* set role */
+  bta_hf_client_cb.scb.role = BTA_HF_CLIENT_ACP;
+
+  APPL_TRACE_DEBUG(
+      "bta_hf_client_rfc_acp_open: serv_handle = %d rfc.port_handle = %d",
+      bta_hf_client_cb.scb.serv_handle, p_data->rfc.port_handle);
+
+  /* get bd addr of peer */
+  if (PORT_SUCCESS != (status = PORT_CheckConnection(p_data->rfc.port_handle,
+                                                     dev_addr, &lcid))) {
+    APPL_TRACE_DEBUG(
+        "bta_hf_client_rfc_acp_open error PORT_CheckConnection returned status "
+        "%d",
+        status);
+  }
+
+  /* Collision Handling */
+  if (alarm_is_scheduled(bta_hf_client_cb.scb.collision_timer)) {
+    alarm_cancel(bta_hf_client_cb.scb.collision_timer);
+
+    if (bdcmp(dev_addr, bta_hf_client_cb.scb.peer_addr) == 0) {
+      /* If incoming and outgoing device are same, nothing more to do. */
+      /* Outgoing conn will be aborted because we have successful incoming conn.
+       */
+    } else {
+      /* Resume outgoing connection. */
+      bta_hf_client_resume_open();
+    }
+  }
+
+  bdcpy(bta_hf_client_cb.scb.peer_addr, dev_addr);
+  bta_hf_client_cb.scb.conn_handle = p_data->rfc.port_handle;
+
+  /* do service discovery to get features */
+  bta_hf_client_do_disc();
+
+  /* continue with open processing */
+  bta_hf_client_rfc_open(p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_rfc_fail
+ *
+ * Description      RFCOMM connection failed.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_rfc_fail(UNUSED_ATTR tBTA_HF_CLIENT_DATA* p_data) {
+  /* reinitialize stuff */
+  bta_hf_client_cb.scb.conn_handle = 0;
+  bta_hf_client_cb.scb.peer_features = 0;
+  bta_hf_client_cb.scb.chld_features = 0;
+  bta_hf_client_cb.scb.role = BTA_HF_CLIENT_ACP;
+  bta_hf_client_cb.scb.svc_conn = false;
+  bta_hf_client_cb.scb.send_at_reply = false;
+  bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD;
+
+  bta_hf_client_at_reset();
+
+  /* reopen server */
+  bta_hf_client_start_server();
+
+  /* call open cback w. failure */
+  bta_hf_client_cback_open(NULL, BTA_HF_CLIENT_FAIL_RFCOMM);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_disc_fail
+ *
+ * Description      This function handles a discovery failure.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_disc_fail(UNUSED_ATTR tBTA_HF_CLIENT_DATA* p_data) {
+  /* reopen server */
+  bta_hf_client_start_server();
+
+  /* reinitialize stuff */
+
+  /* call open cback w. failure */
+  bta_hf_client_cback_open(NULL, BTA_HF_CLIENT_FAIL_SDP);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_open_fail
+ *
+ * Description      open connection failed.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_open_fail(tBTA_HF_CLIENT_DATA* p_data) {
+  /* call open cback w. failure */
+  bta_hf_client_cback_open(p_data, BTA_HF_CLIENT_FAIL_RESOURCES);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_rfc_close
+ *
+ * Description      RFCOMM connection closed.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_rfc_close(UNUSED_ATTR tBTA_HF_CLIENT_DATA* p_data) {
+  /* reinitialize stuff */
+  bta_hf_client_cb.scb.peer_features = 0;
+  bta_hf_client_cb.scb.chld_features = 0;
+  bta_hf_client_cb.scb.role = BTA_HF_CLIENT_ACP;
+  bta_hf_client_cb.scb.svc_conn = false;
+  bta_hf_client_cb.scb.send_at_reply = false;
+  bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD;
+
+  bta_hf_client_at_reset();
+
+  bta_sys_conn_close(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+
+  /* call close cback */
+  (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CLOSE_EVT, NULL);
+
+  /* if not deregistering reopen server */
+  if (bta_hf_client_cb.scb.deregister == false) {
+    /* Clear peer bd_addr so instance can be reused */
+    bdcpy(bta_hf_client_cb.scb.peer_addr, bd_addr_null);
+
+    /* start server as it might got closed on open*/
+    bta_hf_client_start_server();
+
+    bta_hf_client_cb.scb.conn_handle = 0;
+
+    /* Make sure SCO is shutdown */
+    bta_hf_client_sco_shutdown(NULL);
+
+    bta_sys_sco_unuse(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+  }
+  /* else close port and deallocate scb */
+  else {
+    bta_hf_client_close_server();
+    bta_hf_client_scb_disable();
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_disc_int_res
+ *
+ * Description      This function handles a discovery result when initiator.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_disc_int_res(tBTA_HF_CLIENT_DATA* p_data) {
+  uint16_t event = BTA_HF_CLIENT_DISC_FAIL_EVT;
+
+  APPL_TRACE_DEBUG("bta_hf_client_disc_int_res: Status: %d",
+                   p_data->disc_result.status);
+
+  /* if found service */
+  if (p_data->disc_result.status == SDP_SUCCESS ||
+      p_data->disc_result.status == SDP_DB_FULL) {
+    /* get attributes */
+    if (bta_hf_client_sdp_find_attr()) {
+      event = BTA_HF_CLIENT_DISC_OK_EVT;
+    }
+  }
+
+  /* free discovery db */
+  bta_hf_client_free_db(p_data);
+
+  /* send ourselves sdp ok/fail event */
+  bta_hf_client_sm_execute(event, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_disc_acp_res
+ *
+ * Description      This function handles a discovery result when acceptor.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_disc_acp_res(tBTA_HF_CLIENT_DATA* p_data) {
+  /* if found service */
+  if (p_data->disc_result.status == SDP_SUCCESS ||
+      p_data->disc_result.status == SDP_DB_FULL) {
+    /* get attributes */
+    bta_hf_client_sdp_find_attr();
+  }
+
+  /* free discovery db */
+  bta_hf_client_free_db(p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_rfc_data
+ *
+ * Description      Read and process data from RFCOMM.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_rfc_data(UNUSED_ATTR tBTA_HF_CLIENT_DATA* p_data) {
+  uint16_t len;
+  char buf[BTA_HF_CLIENT_RFC_READ_MAX];
+
+  memset(buf, 0, sizeof(buf));
+
+  /* read data from rfcomm; if bad status, we're done */
+  while (PORT_ReadData(bta_hf_client_cb.scb.conn_handle, buf,
+                       BTA_HF_CLIENT_RFC_READ_MAX, &len) == PORT_SUCCESS) {
+    /* if no data, we're done */
+    if (len == 0) {
+      break;
+    }
+
+    bta_hf_client_at_parse(buf, len);
+
+    /* no more data to read, we're done */
+    if (len < BTA_HF_CLIENT_RFC_READ_MAX) {
+      break;
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_svc_conn_open
+ *
+ * Description      Service level connection opened
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_svc_conn_open(UNUSED_ATTR tBTA_HF_CLIENT_DATA* p_data) {
+  tBTA_HF_CLIENT evt;
+
+  memset(&evt, 0, sizeof(evt));
+
+  if (!bta_hf_client_cb.scb.svc_conn) {
+    /* set state variable */
+    bta_hf_client_cb.scb.svc_conn = true;
+
+    /* call callback */
+    evt.conn.peer_feat = bta_hf_client_cb.scb.peer_features;
+    evt.conn.chld_feat = bta_hf_client_cb.scb.chld_features;
+
+    (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CONN_EVT, &evt);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_cback_ind
+ *
+ * Description      Send indicator callback event to application.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_ind(tBTA_HF_CLIENT_IND_TYPE type, uint16_t value) {
+  tBTA_HF_CLIENT evt;
+
+  memset(&evt, 0, sizeof(evt));
+
+  evt.ind.type = type;
+  evt.ind.value = value;
+
+  (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_IND_EVT, &evt);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_evt_val
+ *
+ * Description      Send event to application.
+ *                  This is a generic helper for events with common data.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_evt_val(tBTA_HF_CLIENT_EVT type, uint16_t value) {
+  tBTA_HF_CLIENT evt;
+
+  memset(&evt, 0, sizeof(evt));
+
+  evt.val.value = value;
+
+  (*bta_hf_client_cb.p_cback)(type, &evt);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_operator_name
+ *
+ * Description      Send operator name event to application.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_operator_name(char* name) {
+  tBTA_HF_CLIENT evt;
+
+  memset(&evt, 0, sizeof(evt));
+
+  strlcpy(evt.operator_name.name, name, BTA_HF_CLIENT_OPERATOR_NAME_LEN + 1);
+  evt.operator_name.name[BTA_HF_CLIENT_OPERATOR_NAME_LEN] = '\0';
+
+  (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_OPERATOR_NAME_EVT, &evt);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_clip
+ *
+ * Description      Send CLIP event to application.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_clip(char* number) {
+  tBTA_HF_CLIENT evt;
+
+  memset(&evt, 0, sizeof(evt));
+
+  strlcpy(evt.number.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+  evt.number.number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+
+  (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CLIP_EVT, &evt);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_ccwa
+ *
+ * Description      Send CLIP event to application.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_ccwa(char* number) {
+  tBTA_HF_CLIENT evt;
+
+  memset(&evt, 0, sizeof(evt));
+
+  strlcpy(evt.number.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+  evt.number.number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+
+  (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CCWA_EVT, &evt);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_at_result
+ *
+ * Description      Send AT result event to application.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_at_result(tBTA_HF_CLIENT_AT_RESULT_TYPE type, uint16_t cme) {
+  tBTA_HF_CLIENT evt;
+
+  memset(&evt, 0, sizeof(evt));
+
+  evt.result.type = type;
+  evt.result.cme = cme;
+
+  (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_AT_RESULT_EVT, &evt);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_clcc
+ *
+ * Description      Send clcc event to application.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_clcc(uint32_t idx, bool incoming, uint8_t status, bool mpty,
+                        char* number) {
+  tBTA_HF_CLIENT evt;
+
+  memset(&evt, 0, sizeof(evt));
+
+  evt.clcc.idx = idx;
+  evt.clcc.inc = incoming;
+  evt.clcc.status = status;
+  evt.clcc.mpty = mpty;
+
+  if (number) {
+    evt.clcc.number_present = true;
+    strlcpy(evt.clcc.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+    evt.clcc.number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+  }
+
+  (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CLCC_EVT, &evt);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_cnum
+ *
+ * Description      Send cnum event to application.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_cnum(char* number, uint16_t service) {
+  tBTA_HF_CLIENT evt;
+
+  memset(&evt, 0, sizeof(evt));
+
+  evt.cnum.service = service;
+  strlcpy(evt.cnum.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+  evt.cnum.number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+
+  (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_CNUM_EVT, &evt);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_binp
+ *
+ * Description      Send BINP event to application.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_binp(char* number) {
+  tBTA_HF_CLIENT evt;
+
+  memset(&evt, 0, sizeof(evt));
+
+  strlcpy(evt.number.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+  evt.number.number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+
+  (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_BINP_EVT, &evt);
+}
diff --git a/bt/bta/hf_client/bta_hf_client_api.cc b/bt/bta/hf_client/bta_hf_client_api.cc
new file mode 100644
index 0000000..e932661
--- /dev/null
+++ b/bt/bta/hf_client/bta_hf_client_api.cc
@@ -0,0 +1,253 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-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 is the implementation of the API for the handsfree (HF role)
+ *  subsystem of BTA
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bta_hf_client_api.h"
+#include "bta_hf_client_int.h"
+#include "osi/include/compat.h"
+
+/*****************************************************************************
+ *  Constants and data types
+ ****************************************************************************/
+static const tBTA_SYS_REG bta_hf_client_reg = {bta_hf_client_hdl_event,
+                                               BTA_HfClientDisable};
+
+/*****************************************************************************
+ *  External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         BTA_HfClientEnable
+ *
+ * Description      Enable the HF CLient service. When the enable
+ *                  operation is complete the callback function will be
+ *                  called with a BTA_HF_CLIENT_ENABLE_EVT. This function must
+ *                  be called before other function in the HF CLient API are
+ *                  called.
+ *
+ * Returns          BTA_SUCCESS if OK, BTA_FAILURE otherwise.
+ *
+ ******************************************************************************/
+tBTA_STATUS BTA_HfClientEnable(tBTA_HF_CLIENT_CBACK* p_cback) {
+  if (bta_sys_is_register(BTA_ID_HS)) {
+    APPL_TRACE_ERROR("BTA HF Client is already enabled, ignoring ...");
+    return BTA_FAILURE;
+  }
+
+  /* register with BTA system manager */
+  bta_sys_register(BTA_ID_HS, &bta_hf_client_reg);
+
+  tBTA_HF_CLIENT_API_ENABLE* p_buf =
+      (tBTA_HF_CLIENT_API_ENABLE*)osi_malloc(sizeof(tBTA_HF_CLIENT_API_ENABLE));
+  p_buf->hdr.event = BTA_HF_CLIENT_API_ENABLE_EVT;
+  p_buf->p_cback = p_cback;
+
+  bta_sys_sendmsg(p_buf);
+
+  return BTA_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HfClientDisable
+ *
+ * Description      Disable the HF Client service
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HfClientDisable(void) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = BTA_HF_CLIENT_API_DISABLE_EVT;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HfClientRegister
+ *
+ * Description      Register an HF Client service.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HfClientRegister(tBTA_SEC sec_mask, tBTA_HF_CLIENT_FEAT features,
+                          const char* p_service_name) {
+  tBTA_HF_CLIENT_API_REGISTER* p_buf = (tBTA_HF_CLIENT_API_REGISTER*)osi_malloc(
+      sizeof(tBTA_HF_CLIENT_API_REGISTER));
+
+  p_buf->hdr.event = BTA_HF_CLIENT_API_REGISTER_EVT;
+  p_buf->features = features;
+  p_buf->sec_mask = sec_mask;
+  if (p_service_name)
+    strlcpy(p_buf->name, p_service_name, BTA_SERVICE_NAME_LEN);
+  else
+    p_buf->name[0] = 0;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HfClientDeregister
+ *
+ * Description      Deregister an HF Client service.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HfClientDeregister(uint16_t handle) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = BTA_HF_CLIENT_API_DEREGISTER_EVT;
+  p_buf->layer_specific = handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HfClientOpen
+ *
+ * Description      Opens a connection to an audio gateway.
+ *                  When connection is open callback function is called
+ *                  with a BTA_AG_OPEN_EVT. Only the data connection is
+ *                  opened. The audio connection is not opened.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HfClientOpen(uint16_t handle, BD_ADDR bd_addr, tBTA_SEC sec_mask) {
+  tBTA_HF_CLIENT_API_OPEN* p_buf =
+      (tBTA_HF_CLIENT_API_OPEN*)osi_malloc(sizeof(tBTA_HF_CLIENT_API_OPEN));
+
+  p_buf->hdr.event = BTA_HF_CLIENT_API_OPEN_EVT;
+  p_buf->hdr.layer_specific = handle;
+  bdcpy(p_buf->bd_addr, bd_addr);
+  p_buf->sec_mask = sec_mask;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HfClientClose
+ *
+ * Description      Close the current connection to an audio gateway.
+ *                  Any current audio connection will also be closed
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HfClientClose(uint16_t handle) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = BTA_HF_CLIENT_API_CLOSE_EVT;
+  p_buf->layer_specific = handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HfCllientAudioOpen
+ *
+ * Description      Opens an audio connection to the currently connected
+ *                 audio gateway
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HfClientAudioOpen(uint16_t handle) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = BTA_HF_CLIENT_API_AUDIO_OPEN_EVT;
+  p_buf->layer_specific = handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HfClientAudioClose
+ *
+ * Description      Close the currently active audio connection to an audio
+ *                  gateway. The data connection remains open
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HfClientAudioClose(uint16_t handle) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = BTA_HF_CLIENT_API_AUDIO_CLOSE_EVT;
+  p_buf->layer_specific = handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HfClientSendAT
+ *
+ * Description      send AT command
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HfClientSendAT(uint16_t handle, tBTA_HF_CLIENT_AT_CMD_TYPE at,
+                        uint32_t val1, uint32_t val2, const char* str) {
+  tBTA_HF_CLIENT_DATA_VAL* p_buf =
+      (tBTA_HF_CLIENT_DATA_VAL*)osi_malloc(sizeof(tBTA_HF_CLIENT_DATA_VAL));
+
+  p_buf->hdr.event = BTA_HF_CLIENT_SEND_AT_CMD_EVT;
+  p_buf->uint8_val = at;
+  p_buf->uint32_val1 = val1;
+  p_buf->uint32_val2 = val2;
+
+  if (str) {
+    strlcpy(p_buf->str, str, BTA_HF_CLIENT_NUMBER_LEN + 1);
+    p_buf->str[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+  } else {
+    p_buf->str[0] = '\0';
+  }
+
+  p_buf->hdr.layer_specific = handle;
+
+  bta_sys_sendmsg(p_buf);
+}
diff --git a/bt/bta/hf_client/bta_hf_client_at.cc b/bt/bta/hf_client/bta_hf_client_at.cc
new file mode 100644
index 0000000..f607528
--- /dev/null
+++ b/bt/bta/hf_client/bta_hf_client_at.cc
@@ -0,0 +1,1755 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-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.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_hf_client"
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bta_hf_client_api.h"
+#include "bta_hf_client_int.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+
+/* Uncomment to enable AT traffic dumping */
+/* #define BTA_HF_CLIENT_AT_DUMP 1 */
+
+/* minimum length of AT event */
+#define BTA_HF_CLIENT_AT_EVENT_MIN_LEN 3
+
+/* timeout (in milliseconds) for AT response */
+#define BTA_HF_CLIENT_AT_TIMEOUT 29989
+
+/* timeout (in milliseconds) for AT hold timer */
+#define BTA_HF_CLIENT_AT_HOLD_TIMEOUT 41
+
+/******************************************************************************
+ *
+ *          DATA TYPES AND CONTAINERS
+ *
+ ******************************************************************************/
+/* BRSF: store received values here */
+extern tBTA_HF_CLIENT_CB bta_hf_client_cb;
+
+extern fixed_queue_t* btu_bta_alarm_queue;
+
+/******************************************************************************
+ *       SUPPORTED EVENT MESSAGES
+ ******************************************************************************/
+
+/* CIND: supported indicator names */
+#define BTA_HF_CLIENT_INDICATOR_BATTERYCHG "battchg"
+#define BTA_HF_CLIENT_INDICATOR_SIGNAL "signal"
+#define BTA_HF_CLIENT_INDICATOR_SERVICE "service"
+#define BTA_HF_CLIENT_INDICATOR_CALL "call"
+#define BTA_HF_CLIENT_INDICATOR_ROAM "roam"
+#define BTA_HF_CLIENT_INDICATOR_CALLSETUP "callsetup"
+#define BTA_HF_CLIENT_INDICATOR_CALLHELD "callheld"
+
+#define MIN(a, b)           \
+  ({                        \
+    __typeof__(a) _a = (a); \
+    __typeof__(b) _b = (b); \
+    (_a < _b) ? _a : _b;    \
+  })
+
+/* CIND: represents each indicators boundaries */
+typedef struct {
+  const char* name;
+  uint8_t min;
+  uint8_t max;
+  uint8_t namelen;
+} tBTA_HF_CLIENT_INDICATOR;
+
+#define BTA_HF_CLIENT_AT_SUPPORTED_INDICATOR_COUNT 7
+
+/* CIND: storage room for indicators value range and their statuses */
+static const tBTA_HF_CLIENT_INDICATOR
+    bta_hf_client_indicators[BTA_HF_CLIENT_AT_SUPPORTED_INDICATOR_COUNT] = {
+        /* name                                | min | max | name length -
+           used by parser */
+        {BTA_HF_CLIENT_INDICATOR_BATTERYCHG, 0, 5,
+         sizeof(BTA_HF_CLIENT_INDICATOR_BATTERYCHG)},
+        {BTA_HF_CLIENT_INDICATOR_SIGNAL, 0, 5,
+         sizeof(BTA_HF_CLIENT_INDICATOR_SIGNAL)},
+        {BTA_HF_CLIENT_INDICATOR_SERVICE, 0, 1,
+         sizeof(BTA_HF_CLIENT_INDICATOR_SERVICE)},
+        {BTA_HF_CLIENT_INDICATOR_CALL, 0, 1,
+         sizeof(BTA_HF_CLIENT_INDICATOR_CALL)},
+        {BTA_HF_CLIENT_INDICATOR_ROAM, 0, 1,
+         sizeof(BTA_HF_CLIENT_INDICATOR_ROAM)},
+        {BTA_HF_CLIENT_INDICATOR_CALLSETUP, 0, 3,
+         sizeof(BTA_HF_CLIENT_INDICATOR_CALLSETUP)},
+        {BTA_HF_CLIENT_INDICATOR_CALLHELD, 0, 2,
+         sizeof(BTA_HF_CLIENT_INDICATOR_CALLHELD)}};
+
+/* +VGM/+VGS - gain min/max values  */
+#define BTA_HF_CLIENT_VGS_MIN 0
+#define BTA_HF_CLIENT_VGS_MAX 15
+#define BTA_HF_CLIENT_VGM_MIN 0
+#define BTA_HF_CLIENT_VGM_MAX 15
+
+uint32_t service_index = 0;
+bool service_availability = true;
+/* helper functions for handling AT commands queueing */
+
+static void bta_hf_client_handle_ok();
+
+static void bta_hf_client_clear_queued_at(void) {
+  tBTA_HF_CLIENT_AT_QCMD* cur = bta_hf_client_cb.scb.at_cb.queued_cmd;
+  tBTA_HF_CLIENT_AT_QCMD* next;
+
+  while (cur != NULL) {
+    next = cur->next;
+    osi_free(cur);
+    cur = next;
+  }
+
+  bta_hf_client_cb.scb.at_cb.queued_cmd = NULL;
+}
+
+static void bta_hf_client_queue_at(tBTA_HF_CLIENT_AT_CMD cmd, const char* buf,
+                                   uint16_t buf_len) {
+  tBTA_HF_CLIENT_AT_QCMD* new_cmd =
+      (tBTA_HF_CLIENT_AT_QCMD*)osi_malloc(sizeof(tBTA_HF_CLIENT_AT_QCMD));
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  new_cmd->cmd = cmd;
+  new_cmd->buf_len = buf_len;
+  new_cmd->next = NULL;
+  memcpy(new_cmd->buf, buf, buf_len);
+
+  if (bta_hf_client_cb.scb.at_cb.queued_cmd != NULL) {
+    tBTA_HF_CLIENT_AT_QCMD* qcmd = bta_hf_client_cb.scb.at_cb.queued_cmd;
+
+    while (qcmd->next != NULL) qcmd = qcmd->next;
+
+    qcmd->next = new_cmd;
+  } else {
+    bta_hf_client_cb.scb.at_cb.queued_cmd = new_cmd;
+  }
+}
+
+static void bta_hf_client_at_resp_timer_cback(UNUSED_ATTR void* data) {
+  if (bta_hf_client_cb.scb.at_cb.current_cmd == BTA_HF_CLIENT_AT_CNUM) {
+    LOG_INFO(LOG_TAG, "%s timed out waiting for AT+CNUM response; spoofing OK.",
+             __func__);
+    bta_hf_client_handle_ok();
+  } else {
+    APPL_TRACE_ERROR("HFPClient: AT response timeout, disconnecting");
+    bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL);
+  }
+}
+
+static void bta_hf_client_start_at_resp_timer(void) {
+  alarm_set_on_queue(
+      bta_hf_client_cb.scb.at_cb.resp_timer, BTA_HF_CLIENT_AT_TIMEOUT,
+      bta_hf_client_at_resp_timer_cback, NULL, btu_bta_alarm_queue);
+}
+
+static void bta_hf_client_stop_at_resp_timer(void) {
+  alarm_cancel(bta_hf_client_cb.scb.at_cb.resp_timer);
+}
+
+static void bta_hf_client_send_at(tBTA_HF_CLIENT_AT_CMD cmd, const char* buf,
+                                  uint16_t buf_len) {
+  if ((bta_hf_client_cb.scb.at_cb.current_cmd == BTA_HF_CLIENT_AT_NONE ||
+       bta_hf_client_cb.scb.svc_conn == false) &&
+      !alarm_is_scheduled(bta_hf_client_cb.scb.at_cb.hold_timer)) {
+    uint16_t len;
+
+#ifdef BTA_HF_CLIENT_AT_DUMP
+    APPL_TRACE_DEBUG("%s %.*s", __func__, buf_len - 1, buf);
+#endif
+
+    bta_hf_client_cb.scb.at_cb.current_cmd = cmd;
+    /* Generate fake responses for these because they won't reliably work */
+    if (!service_availability &&
+        (cmd == BTA_HF_CLIENT_AT_CNUM || cmd == BTA_HF_CLIENT_AT_COPS)) {
+      APPL_TRACE_WARNING("%s: No service, skipping %d command", __func__, cmd);
+      bta_hf_client_handle_ok();
+      return;
+    }
+
+    PORT_WriteData(bta_hf_client_cb.scb.conn_handle, buf, buf_len, &len);
+
+    bta_hf_client_start_at_resp_timer();
+
+    return;
+  }
+
+  bta_hf_client_queue_at(cmd, buf, buf_len);
+}
+
+static void bta_hf_client_send_queued_at(void) {
+  tBTA_HF_CLIENT_AT_QCMD* cur = bta_hf_client_cb.scb.at_cb.queued_cmd;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  if (cur != NULL) {
+    bta_hf_client_cb.scb.at_cb.queued_cmd = cur->next;
+
+    bta_hf_client_send_at(cur->cmd, cur->buf, cur->buf_len);
+
+    osi_free(cur);
+  }
+}
+
+static void bta_hf_client_at_hold_timer_cback(UNUSED_ATTR void* data) {
+  APPL_TRACE_DEBUG("%s", __func__);
+  bta_hf_client_send_queued_at();
+}
+
+static void bta_hf_client_stop_at_hold_timer(void) {
+  APPL_TRACE_DEBUG("%s", __func__);
+  alarm_cancel(bta_hf_client_cb.scb.at_cb.hold_timer);
+}
+
+static void bta_hf_client_start_at_hold_timer(void) {
+  APPL_TRACE_DEBUG("%s", __func__);
+  alarm_set_on_queue(
+      bta_hf_client_cb.scb.at_cb.hold_timer, BTA_HF_CLIENT_AT_HOLD_TIMEOUT,
+      bta_hf_client_at_hold_timer_cback, NULL, btu_bta_alarm_queue);
+}
+
+/******************************************************************************
+ *
+ *          COMMON AT EVENT HANDLING funcS
+ *
+ *   Receives data (strings, ints, etc.) from the parser and processes this
+ *   data. No buffer parsing is being done here.
+ ******************************************************************************/
+
+static void bta_hf_client_handle_ok() {
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  bta_hf_client_stop_at_resp_timer();
+
+  if (!bta_hf_client_cb.scb.svc_conn) {
+    bta_hf_client_slc_seq(false);
+    return;
+  }
+
+  switch (bta_hf_client_cb.scb.at_cb.current_cmd) {
+    case BTA_HF_CLIENT_AT_BIA:
+    case BTA_HF_CLIENT_AT_BCC:
+      break;
+    case BTA_HF_CLIENT_AT_BCS:
+      bta_hf_client_start_at_hold_timer();
+      bta_hf_client_cb.scb.at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
+      return;
+    case BTA_HF_CLIENT_AT_CLIP:  // last cmd is post slc seq
+      if (bta_hf_client_cb.scb.send_at_reply == false) {
+        bta_hf_client_cb.scb.send_at_reply = true;
+      }
+      break;
+    case BTA_HF_CLIENT_AT_NONE:
+      bta_hf_client_stop_at_hold_timer();
+      break;
+    default:
+      if (bta_hf_client_cb.scb.send_at_reply) {
+        bta_hf_client_at_result(BTA_HF_CLIENT_AT_RESULT_OK, 0);
+      }
+      break;
+  }
+
+  bta_hf_client_cb.scb.at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
+
+  bta_hf_client_send_queued_at();
+}
+
+static void bta_hf_client_handle_error(tBTA_HF_CLIENT_AT_RESULT_TYPE type,
+                                       uint16_t cme) {
+  APPL_TRACE_DEBUG("%s %u %u", __func__, type, cme);
+
+  bta_hf_client_stop_at_resp_timer();
+
+  if (!bta_hf_client_cb.scb.svc_conn) {
+    bta_hf_client_slc_seq(true);
+    return;
+  }
+
+  switch (bta_hf_client_cb.scb.at_cb.current_cmd) {
+    case BTA_HF_CLIENT_AT_BIA:
+      break;
+    case BTA_HF_CLIENT_AT_BCC:
+    case BTA_HF_CLIENT_AT_BCS:
+      bta_hf_client_cback_sco(BTA_HF_CLIENT_AUDIO_CLOSE_EVT);
+      break;
+    case BTA_HF_CLIENT_AT_CLIP:  // last cmd is post slc seq
+      if (bta_hf_client_cb.scb.send_at_reply == false) {
+        bta_hf_client_cb.scb.send_at_reply = true;
+      }
+      break;
+    default:
+      if (bta_hf_client_cb.scb.send_at_reply) {
+        bta_hf_client_at_result(type, cme);
+      }
+      break;
+  }
+
+  bta_hf_client_cb.scb.at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
+
+  bta_hf_client_send_queued_at();
+}
+
+static void bta_hf_client_handle_ring() {
+  APPL_TRACE_DEBUG("%s", __func__);
+  bta_hf_client_evt_val(BTA_HF_CLIENT_RING_INDICATION, 0);
+}
+
+static void bta_hf_client_handle_brsf(uint32_t value) {
+  APPL_TRACE_DEBUG("%s 0x%x", __func__, value);
+  bta_hf_client_cb.scb.peer_features = value;
+}
+
+/* handles a single indicator descriptor - registers it for value changing
+ * events */
+static void bta_hf_client_handle_cind_list_item(char* name, uint32_t min,
+                                                uint32_t max, uint32_t index) {
+  uint8_t i = 0;
+
+  APPL_TRACE_DEBUG("%s %lu.%s <%lu:%lu>", __func__, index, name, min, max);
+
+  /* look for a matching indicator on list of supported ones */
+  for (i = 0; i < BTA_HF_CLIENT_AT_SUPPORTED_INDICATOR_COUNT; i++) {
+    if (strcmp(name, BTA_HF_CLIENT_INDICATOR_SERVICE) == 0) {
+      service_index = index;
+    }
+    /* look for a match - search one sign further than indicators name to check
+     * for string end */
+    /* It will distinguish 'callheld' which could be matched by strncmp as
+     * 'call'.               */
+    if (strncmp(name, bta_hf_client_indicators[i].name,
+                bta_hf_client_indicators[i].namelen) != 0)
+      continue;
+
+    /* index - enumerates value position in the incoming sequence */
+    /* if name matches one of the known indicators, add its incoming position */
+    /* to lookup table for easy value->indicator matching later, when only
+     * values come  */
+    bta_hf_client_cb.scb.at_cb.indicator_lookup[index] = i;
+
+    return;
+  }
+}
+
+static void bta_hf_client_handle_cind_value(uint32_t index, uint32_t value) {
+  APPL_TRACE_DEBUG("%s index: %u value: %u", __func__, index, value);
+
+  if (index >= BTA_HF_CLIENT_AT_INDICATOR_COUNT) {
+    return;
+  }
+
+  if (service_index == index) {
+    if (value == 0) {
+      service_availability = false;
+    } else {
+      service_availability = true;
+    }
+  }
+  if (bta_hf_client_cb.scb.at_cb.indicator_lookup[index] == -1) {
+    return;
+  }
+
+  /* get the real array index from lookup table */
+  index = bta_hf_client_cb.scb.at_cb.indicator_lookup[index];
+
+  /* Ignore out of range values */
+  if (value > bta_hf_client_indicators[index].max ||
+      value < bta_hf_client_indicators[index].min) {
+    return;
+  }
+
+  /* tBTA_HF_CLIENT_IND_TYPE match index in bta_hf_client_indicators */
+  bta_hf_client_ind(index, value);
+}
+
+static void bta_hf_client_handle_chld(uint32_t mask) {
+  APPL_TRACE_DEBUG("%s 0x%x", __func__, mask);
+
+  bta_hf_client_cb.scb.chld_features |= mask;
+}
+
+static void bta_hf_client_handle_ciev(uint32_t index, uint32_t value) {
+  int8_t realind = -1;
+
+  APPL_TRACE_DEBUG("%s index: %u value: %u", __func__, index, value);
+
+  if (index == 0 || index > BTA_HF_CLIENT_AT_INDICATOR_COUNT) {
+    return;
+  }
+
+  if (service_index == index - 1) {
+    service_availability = value == 0 ? false : true;
+  }
+
+  realind = bta_hf_client_cb.scb.at_cb.indicator_lookup[index - 1];
+
+  if (realind >= 0 && realind < BTA_HF_CLIENT_AT_SUPPORTED_INDICATOR_COUNT) {
+    /* get the real in-array index from lookup table by index it comes at */
+    /* if there is no bug it should automatically be correctly calculated    */
+    if (value > bta_hf_client_indicators[realind].max ||
+        value < bta_hf_client_indicators[realind].min) {
+      return;
+    }
+
+    /* update service availability on +ciev from AG. */
+    if (service_index == (index - 1)) {
+      if (value == 1) {
+        service_availability = true;
+      } else {
+        service_availability = false;
+      }
+    }
+
+    /* tBTA_HF_CLIENT_IND_TYPE match index in bta_hf_client_indicators */
+    bta_hf_client_ind(realind, value);
+  }
+}
+
+static void bta_hf_client_handle_bcs(uint32_t codec) {
+  APPL_TRACE_DEBUG("%s %u", __func__, codec);
+
+  if (codec == BTM_SCO_CODEC_CVSD ||
+      (codec == BTM_SCO_CODEC_MSBC && bta_hf_client_cb.msbc_enabled == true)) {
+    bta_hf_client_cb.scb.negotiated_codec = codec;
+    bta_hf_client_send_at_bcs(codec);
+  } else {
+    bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD;
+    bta_hf_client_send_at_bac();
+  }
+}
+
+static void bta_hf_client_handle_bsir(uint32_t provided) {
+  APPL_TRACE_DEBUG("%s %u", __func__, provided);
+
+  bta_hf_client_evt_val(BTA_HF_CLIENT_BSIR_EVT, provided);
+}
+
+static void bta_hf_client_handle_cmeerror(uint32_t code) {
+  bta_hf_client_handle_error(BTA_HF_CLIENT_AT_RESULT_CME, code);
+}
+
+static void bta_hf_client_handle_vgm(uint32_t value) {
+  APPL_TRACE_DEBUG("%s %lu", __func__, value);
+
+  if (value <= BTA_HF_CLIENT_VGM_MAX) {
+    bta_hf_client_evt_val(BTA_HF_CLIENT_MIC_EVT, value);
+  }
+}
+
+static void bta_hf_client_handle_vgs(uint32_t value) {
+  APPL_TRACE_DEBUG("%s %lu", __func__, value);
+
+  if (value <= BTA_HF_CLIENT_VGS_MAX) {
+    bta_hf_client_evt_val(BTA_HF_CLIENT_SPK_EVT, value);
+  }
+}
+
+static void bta_hf_client_handle_bvra(uint32_t value) {
+  APPL_TRACE_DEBUG("%s %lu", __func__, value);
+
+  if (value > 1) {
+    return;
+  }
+
+  bta_hf_client_evt_val(BTA_HF_CLIENT_VOICE_REC_EVT, value);
+}
+
+static void bta_hf_client_handle_clip(char* numstr, uint32_t type) {
+  APPL_TRACE_DEBUG("%s %u %s", __func__, type, numstr);
+
+  bta_hf_client_clip(numstr);
+}
+
+static void bta_hf_client_handle_ccwa(char* numstr, uint32_t type) {
+  APPL_TRACE_DEBUG("%s %u %s", __func__, type, numstr);
+
+  bta_hf_client_ccwa(numstr);
+}
+
+static void bta_hf_client_handle_cops(char* opstr, uint32_t mode) {
+  APPL_TRACE_DEBUG("%s %u %s", __func__, mode, opstr);
+
+  bta_hf_client_operator_name(opstr);
+}
+
+static void bta_hf_client_handle_binp(char* numstr) {
+  APPL_TRACE_DEBUG("%s %s", __func__, numstr);
+
+  bta_hf_client_binp(numstr);
+}
+
+static void bta_hf_client_handle_clcc(uint16_t idx, uint16_t dir,
+                                      uint16_t status, uint16_t mode,
+                                      uint16_t mpty, char* numstr,
+                                      uint16_t type) {
+  APPL_TRACE_DEBUG("%s idx: %u dir: %u status: %u mode: %u mpty: %u", __func__,
+                   idx, dir, status, mode, mpty);
+
+  if (numstr) {
+    APPL_TRACE_DEBUG("%s number: %s  type: %u", __func__, numstr, type);
+  }
+
+  bta_hf_client_clcc(idx, dir, status, mpty, numstr);
+}
+
+static void bta_hf_client_handle_cnum(char* numstr, uint16_t type,
+                                      uint16_t service) {
+  APPL_TRACE_DEBUG("%s number: %s type: %u service: %u", __func__, numstr, type,
+                   service);
+
+  /* TODO: should number be modified according to type? */
+  bta_hf_client_cnum(numstr, service);
+}
+
+static void bta_hf_client_handle_btrh(uint16_t code) {
+  APPL_TRACE_DEBUG("%s %lu", __func__, code);
+
+  bta_hf_client_evt_val(BTA_HF_CLIENT_BTRH_EVT, code);
+}
+
+/******************************************************************************
+ *
+ *          COMMON AT EVENTS PARSING FUNCTIONS
+ *
+ ******************************************************************************/
+
+/* Check if prefix match and skip spaces if any */
+#define AT_CHECK_EVENT(buf, event)                                             \
+  do {                                                                         \
+    if (strncmp("\r\n" event, buf, sizeof("\r\n" event) - 1) != 0) return buf; \
+    (buf) += sizeof("\r\n" event) - 1;                                         \
+    while (*(buf) == ' ') (buf)++;                                             \
+  } while (0)
+
+/* check for <cr><lf> and forward buffer if match */
+#define AT_CHECK_RN(buf)                                     \
+  do {                                                       \
+    if (strncmp("\r\n", buf, sizeof("\r\n") - 1) != 0) {     \
+      APPL_TRACE_DEBUG("%s missing end <cr><lf>", __func__); \
+      return NULL;                                           \
+    }                                                        \
+    (buf) += sizeof("\r\n") - 1;                             \
+  } while (0)
+
+/* skip rest of AT string up to <cr> */
+#define AT_SKIP_REST(buf)           \
+  do {                              \
+    while (*(buf) != '\r') (buf)++; \
+  } while (0)
+
+static char* bta_hf_client_parse_ok(char* buffer) {
+  AT_CHECK_EVENT(buffer, "OK");
+  AT_CHECK_RN(buffer);
+
+  bta_hf_client_handle_ok();
+
+  return buffer;
+}
+
+static char* bta_hf_client_parse_error(char* buffer) {
+  AT_CHECK_EVENT(buffer, "ERROR");
+  AT_CHECK_RN(buffer);
+
+  bta_hf_client_handle_error(BTA_HF_CLIENT_AT_RESULT_ERROR, 0);
+
+  return buffer;
+}
+
+static char* bta_hf_client_parse_ring(char* buffer) {
+  AT_CHECK_EVENT(buffer, "RING");
+  AT_CHECK_RN(buffer);
+
+  bta_hf_client_handle_ring();
+
+  return buffer;
+}
+
+/* generic uint32 parser */
+static char* bta_hf_client_parse_uint32(char* buffer,
+                                        void (*handler_callback)(uint32_t)) {
+  uint32_t value;
+  int res;
+  int offset;
+
+  res = sscanf(buffer, "%u%n", &value, &offset);
+  if (res < 1) {
+    return NULL;
+  }
+
+  buffer += offset;
+
+  AT_CHECK_RN(buffer);
+
+  handler_callback(value);
+  return buffer;
+}
+
+static char* bta_hf_client_parse_brsf(char* buffer) {
+  AT_CHECK_EVENT(buffer, "+BRSF:");
+
+  return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_brsf);
+}
+
+static char* bta_hf_client_parse_cind_values(char* buffer) {
+  /* value and its position */
+  uint16_t index = 0;
+  uint32_t value = 0;
+
+  int offset;
+  int res;
+
+  while ((res = sscanf(buffer, "%u%n", &value, &offset)) > 0) {
+    /* decides if its valid index and value, if yes stores it */
+    bta_hf_client_handle_cind_value(index, value);
+
+    buffer += offset;
+
+    /* check if more values are present */
+    if (*buffer != ',') {
+      break;
+    }
+
+    index++;
+    buffer++;
+  }
+
+  if (res > 0) {
+    AT_CHECK_RN(buffer);
+    return buffer;
+  }
+
+  return NULL;
+}
+
+static char* bta_hf_client_parse_cind_list(char* buffer) {
+  int offset = 0;
+  char name[129];
+  uint32_t min, max;
+  uint32_t index = 0;
+  int res;
+
+  while ((res = sscanf(buffer, "(\"%128[^\"]\",(%u%*[-,]%u))%n", name, &min,
+                       &max, &offset)) > 2) {
+    bta_hf_client_handle_cind_list_item(name, min, max, index);
+    if (offset == 0) {
+      APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer);
+      return NULL;
+    }
+
+    buffer += offset;
+    index++;
+
+    if (*buffer != ',') {
+      break;
+    }
+
+    buffer++;
+  }
+
+  if (res > 2) {
+    AT_CHECK_RN(buffer);
+    return buffer;
+  }
+
+  return NULL;
+}
+
+static char* bta_hf_client_parse_cind(char* buffer) {
+  AT_CHECK_EVENT(buffer, "+CIND:");
+
+  if (*buffer == '(') return bta_hf_client_parse_cind_list(buffer);
+
+  return bta_hf_client_parse_cind_values(buffer);
+}
+
+static char* bta_hf_client_parse_chld(char* buffer) {
+  AT_CHECK_EVENT(buffer, "+CHLD:");
+
+  if (*buffer != '(') {
+    return NULL;
+  }
+
+  buffer++;
+
+  while (*buffer != '\0') {
+    if (strncmp("0", buffer, 1) == 0) {
+      bta_hf_client_handle_chld(BTA_HF_CLIENT_CHLD_REL);
+      buffer++;
+    } else if (strncmp("1x", buffer, 2) == 0) {
+      bta_hf_client_handle_chld(BTA_HF_CLIENT_CHLD_REL_X);
+      buffer += 2;
+    } else if (strncmp("1", buffer, 1) == 0) {
+      bta_hf_client_handle_chld(BTA_HF_CLIENT_CHLD_REL_ACC);
+      buffer++;
+    } else if (strncmp("2x", buffer, 2) == 0) {
+      bta_hf_client_handle_chld(BTA_HF_CLIENT_CHLD_PRIV_X);
+      buffer += 2;
+    } else if (strncmp("2", buffer, 1) == 0) {
+      bta_hf_client_handle_chld(BTA_HF_CLIENT_CHLD_HOLD_ACC);
+      buffer++;
+    } else if (strncmp("3", buffer, 1) == 0) {
+      bta_hf_client_handle_chld(BTA_HF_CLIENT_CHLD_MERGE);
+      buffer++;
+    } else if (strncmp("4", buffer, 1) == 0) {
+      bta_hf_client_handle_chld(BTA_HF_CLIENT_CHLD_MERGE_DETACH);
+      buffer++;
+    } else {
+      return NULL;
+    }
+
+    if (*buffer == ',') {
+      buffer++;
+      continue;
+    }
+
+    if (*buffer == ')') {
+      buffer++;
+      break;
+    }
+
+    return NULL;
+  }
+
+  AT_CHECK_RN(buffer);
+
+  return buffer;
+}
+
+static char* bta_hf_client_parse_ciev(char* buffer) {
+  uint32_t index, value;
+  int res;
+  int offset = 0;
+
+  AT_CHECK_EVENT(buffer, "+CIEV:");
+
+  res = sscanf(buffer, "%u,%u%n", &index, &value, &offset);
+  if (res < 2) {
+    return NULL;
+  }
+
+  if (offset == 0) {
+    APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer);
+    return NULL;
+  }
+
+  buffer += offset;
+
+  AT_CHECK_RN(buffer);
+
+  bta_hf_client_handle_ciev(index, value);
+  return buffer;
+}
+
+static char* bta_hf_client_parse_bcs(char* buffer) {
+  AT_CHECK_EVENT(buffer, "+BCS:");
+
+  return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_bcs);
+}
+
+static char* bta_hf_client_parse_bsir(char* buffer) {
+  AT_CHECK_EVENT(buffer, "+BSIR:");
+
+  return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_bsir);
+}
+
+static char* bta_hf_client_parse_cmeerror(char* buffer) {
+  AT_CHECK_EVENT(buffer, "+CME ERROR:");
+
+  return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_cmeerror);
+}
+
+static char* bta_hf_client_parse_vgm(char* buffer) {
+  AT_CHECK_EVENT(buffer, "+VGM:");
+
+  return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_vgm);
+}
+
+static char* bta_hf_client_parse_vgme(char* buffer) {
+  AT_CHECK_EVENT(buffer, "+VGM=");
+
+  return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_vgm);
+}
+
+static char* bta_hf_client_parse_vgs(char* buffer) {
+  AT_CHECK_EVENT(buffer, "+VGS:");
+
+  return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_vgs);
+}
+
+static char* bta_hf_client_parse_vgse(char* buffer) {
+  AT_CHECK_EVENT(buffer, "+VGS=");
+
+  return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_vgs);
+}
+
+static char* bta_hf_client_parse_bvra(char* buffer) {
+  AT_CHECK_EVENT(buffer, "+BVRA:");
+
+  return bta_hf_client_parse_uint32(buffer, bta_hf_client_handle_bvra);
+}
+
+static char* bta_hf_client_parse_clip(char* buffer) {
+  /* spec forces 32 chars, plus \0 here */
+  char number[33];
+  uint32_t type = 0;
+  int res;
+  int offset = 0;
+
+  AT_CHECK_EVENT(buffer, "+CLIP:");
+
+  /* there might be something more after %lu but HFP doesn't care */
+  res = sscanf(buffer, "\"%32[^\"]\",%u%n", number, &type, &offset);
+  if (res < 2) {
+    return NULL;
+  }
+
+  if (offset == 0) {
+    APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer);
+    return NULL;
+  }
+
+  buffer += offset;
+
+  AT_SKIP_REST(buffer);
+
+  AT_CHECK_RN(buffer);
+
+  bta_hf_client_handle_clip(number, type);
+  return buffer;
+}
+
+/* in HFP context there is no difference between ccwa and clip */
+static char* bta_hf_client_parse_ccwa(char* buffer) {
+  /* ac to spec 32 chars max, plus \0 here */
+  char number[33];
+  uint32_t type = 0;
+  int res;
+  int offset = 0;
+
+  AT_CHECK_EVENT(buffer, "+CCWA:");
+
+  /* there might be something more after %lu but HFP doesn't care */
+  res = sscanf(buffer, "\"%32[^\"]\",%u%n", number, &type, &offset);
+  if (res < 2) {
+    return NULL;
+  }
+
+  if (offset == 0) {
+    APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer);
+    return NULL;
+  }
+
+  buffer += offset;
+
+  AT_SKIP_REST(buffer);
+
+  AT_CHECK_RN(buffer);
+
+  bta_hf_client_handle_ccwa(number, type);
+  return buffer;
+}
+
+static char* bta_hf_client_parse_cops(char* buffer) {
+  uint8_t mode;
+  /* spec forces 16 chars max, plus \0 here */
+  char opstr[17];
+  int res;
+  int offset = 0;
+
+  AT_CHECK_EVENT(buffer, "+COPS:");
+
+  /* TODO: Not sure if operator string actually can contain escaped " char
+   * inside */
+  res = sscanf(buffer, "%hhi,0,\"%16[^\"]\"%n", &mode, opstr, &offset);
+  if (res < 2) {
+    return NULL;
+  }
+  /* Abort in case offset not set because of format error */
+  if (offset == 0) {
+    APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer);
+    return NULL;
+  }
+
+  buffer += offset;
+
+  AT_SKIP_REST(buffer);
+
+  AT_CHECK_RN(buffer);
+
+  bta_hf_client_handle_cops(opstr, mode);
+  // check for OK Response in end
+  AT_CHECK_EVENT(buffer, "OK");
+  AT_CHECK_RN(buffer);
+
+  bta_hf_client_handle_ok();
+
+  return buffer;
+}
+
+static char* bta_hf_client_parse_binp(char* buffer) {
+  /* HFP only supports phone number as BINP data */
+  /* phone number is 32 chars plus one for \0*/
+  char numstr[33];
+  int res;
+  int offset = 0;
+
+  AT_CHECK_EVENT(buffer, "+BINP:");
+
+  res = sscanf(buffer, "\"%32[^\"]\"\r\n%n", numstr, &offset);
+  if (res < 1) {
+    return NULL;
+  }
+
+  /* Abort in case offset not set because of format error */
+  if (offset == 0) {
+    APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer);
+    return NULL;
+  }
+
+  buffer += offset;
+
+  /* some phones might sent type as well, just skip it */
+  AT_SKIP_REST(buffer);
+
+  AT_CHECK_RN(buffer);
+
+  bta_hf_client_handle_binp(numstr);
+
+  // check for OK response in end
+  AT_CHECK_EVENT(buffer, "OK");
+  AT_CHECK_RN(buffer);
+
+  bta_hf_client_handle_ok();
+
+  return buffer;
+}
+
+static char* bta_hf_client_parse_clcc(char* buffer) {
+  uint16_t idx, dir, status, mode, mpty;
+  char numstr[33]; /* spec forces 32 chars, plus one for \0*/
+  uint16_t type;
+  int res;
+  int offset = 0;
+
+  AT_CHECK_EVENT(buffer, "+CLCC:");
+
+  res = sscanf(buffer, "%hu,%hu,%hu,%hu,%hu%n", &idx, &dir, &status, &mode,
+               &mpty, &offset);
+  if (res < 5) {
+    return NULL;
+  }
+
+  /* Abort in case offset not set because of format error */
+  if (offset == 0) {
+    APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer);
+    return NULL;
+  }
+
+  buffer += offset;
+  offset = 0;
+
+  /* check optional part */
+  if (*buffer == ',') {
+    int res2 = sscanf(buffer, ",\"%32[^\"]\",%hu%n", numstr, &type, &offset);
+    if (res2 < 0) return NULL;
+
+    if (res2 == 0) {
+      res2 = sscanf(buffer, ",\"\",%hu%n", &type, &offset);
+      if (res < 0) return NULL;
+
+      /* numstr is not matched in second attempt, correct this */
+      res2++;
+      numstr[0] = '\0';
+    }
+
+    if (res2 >= 2) {
+      res += res2;
+      /* Abort in case offset not set because of format error */
+      if (offset == 0) {
+        APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer);
+        return NULL;
+      }
+
+      buffer += offset;
+    }
+  }
+
+  /* Skip any remaing param,as they are not defined by BT HFP spec */
+  AT_SKIP_REST(buffer);
+  AT_CHECK_RN(buffer);
+
+  if (res > 6) {
+    /* we also have last two optional parameters */
+    bta_hf_client_handle_clcc(idx, dir, status, mode, mpty, numstr, type);
+  } else {
+    /* we didn't get the last two parameters */
+    bta_hf_client_handle_clcc(idx, dir, status, mode, mpty, NULL, 0);
+  }
+
+  // check for OK response in end
+  AT_CHECK_EVENT(buffer, "OK");
+  AT_CHECK_RN(buffer);
+
+  bta_hf_client_handle_ok();
+  return buffer;
+}
+
+static char* bta_hf_client_parse_cnum(char* buffer) {
+  char numstr[33]; /* spec forces 32 chars, plus one for \0*/
+  uint16_t type;
+  uint16_t service =
+      0; /* 0 in case this optional parameter is not being sent */
+  int res;
+  int offset = 0;
+
+  AT_CHECK_EVENT(buffer, "+CNUM:");
+
+  res = sscanf(buffer, ",\"%32[^\"]\",%hu,,%hu%n", numstr, &type, &service,
+               &offset);
+  if (res < 0) {
+    return NULL;
+  }
+
+  if (res == 0) {
+    res = sscanf(buffer, ",\"\",%hu,,%hu%n", &type, &service, &offset);
+    if (res < 0) {
+      return NULL;
+    }
+
+    /* numstr is not matched in second attempt, correct this */
+    res++;
+    numstr[0] = '\0';
+  }
+
+  if (res < 3) {
+    return NULL;
+  }
+
+  /* Abort in case offset not set because of format error */
+  if (offset == 0) {
+    APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer);
+    return NULL;
+  }
+
+  buffer += offset;
+
+  AT_CHECK_RN(buffer);
+
+  /* service is optional */
+  if (res == 2) {
+    bta_hf_client_handle_cnum(numstr, type, service);
+    return buffer;
+  }
+
+  if (service != 4 && service != 5) {
+    return NULL;
+  }
+
+  bta_hf_client_handle_cnum(numstr, type, service);
+
+  // check for OK response in end
+  AT_CHECK_EVENT(buffer, "OK");
+  AT_CHECK_RN(buffer);
+
+  bta_hf_client_handle_ok();
+  return buffer;
+}
+
+static char* bta_hf_client_parse_btrh(char* buffer) {
+  uint16_t code = 0;
+  int res;
+  int offset;
+
+  AT_CHECK_EVENT(buffer, "+BTRH:");
+
+  res = sscanf(buffer, "%hu%n", &code, &offset);
+  if (res < 1) {
+    return NULL;
+  }
+
+  buffer += offset;
+
+  AT_CHECK_RN(buffer);
+
+  bta_hf_client_handle_btrh(code);
+  return buffer;
+}
+
+static char* bta_hf_client_parse_busy(char* buffer) {
+  AT_CHECK_EVENT(buffer, "BUSY");
+  AT_CHECK_RN(buffer);
+
+  bta_hf_client_handle_error(BTA_HF_CLIENT_AT_RESULT_BUSY, 0);
+
+  return buffer;
+}
+
+static char* bta_hf_client_parse_delayed(char* buffer) {
+  AT_CHECK_EVENT(buffer, "DELAYED");
+  AT_CHECK_RN(buffer);
+
+  bta_hf_client_handle_error(BTA_HF_CLIENT_AT_RESULT_DELAY, 0);
+
+  return buffer;
+}
+
+static char* bta_hf_client_parse_no_carrier(char* buffer) {
+  AT_CHECK_EVENT(buffer, "NO CARRIER");
+  AT_CHECK_RN(buffer);
+
+  bta_hf_client_handle_error(BTA_HF_CLIENT_AT_RESULT_NO_CARRIER, 0);
+
+  return buffer;
+}
+
+static char* bta_hf_client_parse_no_answer(char* buffer) {
+  AT_CHECK_EVENT(buffer, "NO ANSWER");
+  AT_CHECK_RN(buffer);
+
+  bta_hf_client_handle_error(BTA_HF_CLIENT_AT_RESULT_NO_ANSWER, 0);
+
+  return buffer;
+}
+
+static char* bta_hf_client_parse_blacklisted(char* buffer) {
+  AT_CHECK_EVENT(buffer, "BLACKLISTED");
+  AT_CHECK_RN(buffer);
+
+  bta_hf_client_handle_error(BTA_HF_CLIENT_AT_RESULT_BLACKLISTED, 0);
+
+  return buffer;
+}
+
+static char* bta_hf_client_skip_unknown(char* buffer) {
+  char* start;
+  char* tmp;
+
+  tmp = strstr(buffer, "\r\n");
+  if (tmp == NULL) {
+    return NULL;
+  }
+
+  buffer += 2;
+  start = buffer;
+
+  tmp = strstr(buffer, "\r\n");
+  if (tmp == NULL) {
+    return NULL;
+  }
+
+  buffer = tmp + 2;
+
+  APPL_TRACE_DEBUG("%s %.*s", __func__, buffer - start - 2, start);
+
+  return buffer;
+}
+
+/******************************************************************************
+ *       SUPPORTED EVENT MESSAGES
+ ******************************************************************************/
+
+/* returned values are as follow:
+ * != NULL && != buf  : match and parsed ok
+ * == NULL            : match but parse failed
+ * != NULL && == buf  : no match
+ */
+typedef char* (*tBTA_HF_CLIENT_PARSER_CALLBACK)(char*);
+
+static const tBTA_HF_CLIENT_PARSER_CALLBACK bta_hf_client_parser_cb[] = {
+    bta_hf_client_parse_ok,          bta_hf_client_parse_error,
+    bta_hf_client_parse_ring,        bta_hf_client_parse_brsf,
+    bta_hf_client_parse_cind,        bta_hf_client_parse_ciev,
+    bta_hf_client_parse_chld,        bta_hf_client_parse_bcs,
+    bta_hf_client_parse_bsir,        bta_hf_client_parse_cmeerror,
+    bta_hf_client_parse_vgm,         bta_hf_client_parse_vgme,
+    bta_hf_client_parse_vgs,         bta_hf_client_parse_vgse,
+    bta_hf_client_parse_bvra,        bta_hf_client_parse_clip,
+    bta_hf_client_parse_ccwa,        bta_hf_client_parse_cops,
+    bta_hf_client_parse_binp,        bta_hf_client_parse_clcc,
+    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};
+
+/* calculate supported event list length */
+static const uint16_t bta_hf_client_psraser_cb_count =
+    sizeof(bta_hf_client_parser_cb) / sizeof(bta_hf_client_parser_cb[0]);
+
+#ifdef BTA_HF_CLIENT_AT_DUMP
+static void bta_hf_client_dump_at(void) {
+  char dump[(4 * BTA_HF_CLIENT_AT_PARSER_MAX_LEN) + 1];
+  char *p1, *p2;
+
+  p1 = bta_hf_client_cb.scb.at_cb.buf;
+  p2 = dump;
+
+  while (*p1 != '\0') {
+    if (*p1 == '\r') {
+      strlcpy(p2, "<cr>", 4);
+      p2 += 4;
+    } else if (*p1 == '\n') {
+      strlcpy(p2, "<lf>", 4);
+      p2 += 4;
+    } else {
+      *p2 = *p1;
+      p2++;
+    }
+    p1++;
+  }
+
+  *p2 = '\0';
+
+  APPL_TRACE_DEBUG("%s %s", __func__, dump);
+}
+#endif
+
+static void bta_hf_client_at_parse_start(void) {
+  char* buf = bta_hf_client_cb.scb.at_cb.buf;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+#ifdef BTA_HF_CLIENT_AT_DUMP
+  bta_hf_client_dump_at();
+#endif
+
+  while (*buf != '\0') {
+    int i;
+    char* tmp = NULL;
+
+    for (i = 0; i < bta_hf_client_psraser_cb_count; i++) {
+      tmp = bta_hf_client_parser_cb[i](buf);
+      if (tmp == NULL) {
+        APPL_TRACE_ERROR("HFPCient: AT event/reply parsing failed, skipping");
+        tmp = bta_hf_client_skip_unknown(buf);
+        break;
+      }
+
+      /* matched or unknown skipped, if unknown failed tmp is NULL so
+         this is also handled */
+      if (tmp != buf) {
+        buf = tmp;
+        break;
+      }
+    }
+
+    /* could not skip unknown (received garbage?)... disconnect */
+    if (tmp == NULL) {
+      APPL_TRACE_ERROR(
+          "HFPCient: could not skip unknown AT event, disconnecting");
+      bta_hf_client_at_reset();
+      bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL);
+      return;
+    }
+
+    buf = tmp;
+  }
+}
+
+static bool bta_hf_client_check_at_complete(void) {
+  bool ret = false;
+  tBTA_HF_CLIENT_AT_CB* at_cb = &bta_hf_client_cb.scb.at_cb;
+
+  if (at_cb->offset >= BTA_HF_CLIENT_AT_EVENT_MIN_LEN) {
+    if (at_cb->buf[at_cb->offset - 2] == '\r' &&
+        at_cb->buf[at_cb->offset - 1] == '\n') {
+      ret = true;
+    }
+  }
+
+  APPL_TRACE_DEBUG("%s %d", __func__, ret);
+
+  return ret;
+}
+
+static void bta_hf_client_at_clear_buf(void) {
+  memset(bta_hf_client_cb.scb.at_cb.buf, 0,
+         sizeof(bta_hf_client_cb.scb.at_cb.buf));
+  bta_hf_client_cb.scb.at_cb.offset = 0;
+}
+
+/******************************************************************************
+ *
+ *          MAIN PARSING FUNCTION
+ *
+ *
+ ******************************************************************************/
+void bta_hf_client_at_parse(char* buf, unsigned int len) {
+  APPL_TRACE_DEBUG("%s offset: %u len: %u", __func__,
+                   bta_hf_client_cb.scb.at_cb.offset, len);
+
+  if (len + bta_hf_client_cb.scb.at_cb.offset >
+      BTA_HF_CLIENT_AT_PARSER_MAX_LEN) {
+    char tmp_buff[BTA_HF_CLIENT_AT_PARSER_MAX_LEN];
+    unsigned int tmp = bta_hf_client_cb.scb.at_cb.offset;
+    unsigned int space_left =
+        BTA_HF_CLIENT_AT_PARSER_MAX_LEN - bta_hf_client_cb.scb.at_cb.offset;
+
+    APPL_TRACE_DEBUG("%s overrun, trying to recover", __func__);
+
+    /* fill up parser buffer */
+    memcpy(bta_hf_client_cb.scb.at_cb.buf + bta_hf_client_cb.scb.at_cb.offset,
+           buf, space_left);
+    len -= space_left;
+    buf += space_left;
+    bta_hf_client_cb.scb.at_cb.offset += space_left;
+
+    /* find end of last complete command before proceeding */
+    while (bta_hf_client_check_at_complete() == false) {
+      if (bta_hf_client_cb.scb.at_cb.offset == 0) {
+        APPL_TRACE_ERROR("HFPClient: AT parser buffer overrun, disconnecting");
+
+        bta_hf_client_at_reset();
+        bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL);
+        return;
+      }
+
+      bta_hf_client_cb.scb.at_cb.offset--;
+    }
+
+    /* cut buffer to complete AT event and keep cut data */
+    tmp += space_left - bta_hf_client_cb.scb.at_cb.offset;
+    memcpy(tmp_buff,
+           bta_hf_client_cb.scb.at_cb.buf + bta_hf_client_cb.scb.at_cb.offset,
+           tmp);
+    bta_hf_client_cb.scb.at_cb.buf[bta_hf_client_cb.scb.at_cb.offset] = '\0';
+
+    /* parse */
+    bta_hf_client_at_parse_start();
+    bta_hf_client_at_clear_buf();
+
+    /* recover cut data */
+    memcpy(bta_hf_client_cb.scb.at_cb.buf, tmp_buff, tmp);
+    bta_hf_client_cb.scb.at_cb.offset += tmp;
+  }
+
+  memcpy(bta_hf_client_cb.scb.at_cb.buf + bta_hf_client_cb.scb.at_cb.offset,
+         buf, len);
+  bta_hf_client_cb.scb.at_cb.offset += len;
+
+  /* If last event is complete, parsing can be started */
+  if (bta_hf_client_check_at_complete() == true) {
+    bta_hf_client_at_parse_start();
+    bta_hf_client_at_clear_buf();
+  }
+}
+
+void bta_hf_client_send_at_brsf(void) {
+  char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+  int at_len;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  at_len =
+      snprintf(buf, sizeof(buf), "AT+BRSF=%u\r", bta_hf_client_cb.scb.features);
+  if (at_len < 0) {
+    APPL_TRACE_ERROR("%s: AT command Framing error", __func__);
+    return;
+  }
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_BRSF, buf, at_len);
+}
+
+void bta_hf_client_send_at_bac(void) {
+  const char* buf;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  if (bta_hf_client_cb.msbc_enabled) {
+    buf = "AT+BAC=1,2\r";
+  } else {
+    buf = "AT+BAC=1\r";
+  }
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_BAC, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_bcs(uint32_t codec) {
+  char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+  int at_len;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  at_len = snprintf(buf, sizeof(buf), "AT+BCS=%u\r", codec);
+  if (at_len < 0) {
+    APPL_TRACE_ERROR("%s: AT command Framing error", __func__);
+    return;
+  }
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_BCS, buf, at_len);
+}
+
+void bta_hf_client_send_at_cind(bool status) {
+  const char* buf;
+  tBTA_HF_CLIENT_AT_CMD cmd;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  if (status) {
+    buf = "AT+CIND?\r";
+    cmd = BTA_HF_CLIENT_AT_CIND_STATUS;
+  } else {
+    buf = "AT+CIND=?\r";
+    cmd = BTA_HF_CLIENT_AT_CIND;
+  }
+
+  bta_hf_client_send_at(cmd, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_cmer(bool activate) {
+  const char* buf;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  if (activate)
+    buf = "AT+CMER=3,0,0,1\r";
+  else
+    buf = "AT+CMER=3,0,0,0\r";
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_CMER, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_chld(char cmd, uint32_t idx) {
+  char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+  int at_len;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  if (idx > 0)
+    at_len = snprintf(buf, sizeof(buf), "AT+CHLD=%c%u\r", cmd, idx);
+  else
+    at_len = snprintf(buf, sizeof(buf), "AT+CHLD=%c\r", cmd);
+
+  if (at_len < 0) {
+    APPL_TRACE_ERROR("%s: AT command Framing error", __func__);
+    return;
+  }
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_CHLD, buf, at_len);
+}
+
+void bta_hf_client_send_at_clip(bool activate) {
+  const char* buf;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  if (activate)
+    buf = "AT+CLIP=1\r";
+  else
+    buf = "AT+CLIP=0\r";
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_CLIP, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_ccwa(bool activate) {
+  const char* buf;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  if (activate)
+    buf = "AT+CCWA=1\r";
+  else
+    buf = "AT+CCWA=0\r";
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_CCWA, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_cmee(bool activate) {
+  const char* buf;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  if (activate)
+    buf = "AT+CMEE=1\r";
+  else
+    buf = "AT+CMEE=0\r";
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_CMEE, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_cops(bool query) {
+  const char* buf;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  if (query)
+    buf = "AT+COPS?\r";
+  else
+    buf = "AT+COPS=3,0\r";
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_COPS, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_clcc(void) {
+  const char* buf;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  buf = "AT+CLCC\r";
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_CLCC, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_bvra(bool enable) {
+  const char* buf;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  if (enable)
+    buf = "AT+BVRA=1\r";
+  else
+    buf = "AT+BVRA=0\r";
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_BVRA, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_vgs(uint32_t volume) {
+  char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+  int at_len;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  at_len = snprintf(buf, sizeof(buf), "AT+VGS=%u\r", volume);
+  if (at_len < 0) {
+    APPL_TRACE_ERROR("%s: AT command Framing error", __func__);
+    return;
+  }
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_VGS, buf, at_len);
+}
+
+void bta_hf_client_send_at_vgm(uint32_t volume) {
+  char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+  int at_len;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  at_len = snprintf(buf, sizeof(buf), "AT+VGM=%u\r", volume);
+  if (at_len < 0) {
+    APPL_TRACE_ERROR("%s: AT command Framing error", __func__);
+    return;
+  }
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_VGM, buf, at_len);
+}
+
+void bta_hf_client_send_at_atd(char* number, uint32_t memory) {
+  char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+  int at_len;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  if (number[0] != '\0') {
+    at_len = snprintf(buf, sizeof(buf), "ATD%s;\r", number);
+  } else {
+    at_len = snprintf(buf, sizeof(buf), "ATD>%u;\r", memory);
+  }
+
+  if (at_len < 0) {
+    APPL_TRACE_ERROR("%s: error preparing ATD command", __func__);
+    return;
+  }
+
+  at_len = MIN((size_t)at_len, sizeof(buf));
+
+  if (at_len < 0) {
+    APPL_TRACE_ERROR("%s: AT command Framing error", __func__);
+    return;
+  }
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_ATD, buf, at_len);
+}
+
+void bta_hf_client_send_at_bldn(void) {
+  const char* buf;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  buf = "AT+BLDN\r";
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_BLDN, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_ata(void) {
+  const char* buf;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  buf = "ATA\r";
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_ATA, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_chup(void) {
+  const char* buf;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  buf = "AT+CHUP\r";
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_CHUP, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_btrh(bool query, uint32_t val) {
+  char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+  int at_len;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  if (query == true) {
+    at_len = snprintf(buf, sizeof(buf), "AT+BTRH?\r");
+  } else {
+    at_len = snprintf(buf, sizeof(buf), "AT+BTRH=%u\r", val);
+  }
+
+  if (at_len < 0) {
+    APPL_TRACE_ERROR("%s: AT command Framing error", __func__);
+    return;
+  }
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_BTRH, buf, at_len);
+}
+
+void bta_hf_client_send_at_vts(char code) {
+  char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+  int at_len;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  at_len = snprintf(buf, sizeof(buf), "AT+VTS=%c\r", code);
+
+  if (at_len < 0) {
+    APPL_TRACE_ERROR("%s: AT command Framing error", __func__);
+    return;
+  }
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_VTS, buf, at_len);
+}
+
+void bta_hf_client_send_at_bcc(void) {
+  const char* buf;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  buf = "AT+BCC\r";
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_BCC, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_cnum(void) {
+  const char* buf;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  buf = "AT+CNUM\r";
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_CNUM, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_nrec(void) {
+  const char* buf;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  if (!(bta_hf_client_cb.scb.peer_features & BTA_HF_CLIENT_PEER_FEAT_ECNR)) {
+    APPL_TRACE_ERROR("%s: Remote does not support NREC.", __func__);
+    return;
+  }
+
+  buf = "AT+NREC=0\r";
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_NREC, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_binp(uint32_t action) {
+  char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+  int at_len;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  at_len = snprintf(buf, sizeof(buf), "AT+BINP=%u\r", action);
+
+  if (at_len < 0) {
+    APPL_TRACE_ERROR("%s: AT command Framing error", __func__);
+    return;
+  }
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_BINP, buf, at_len);
+}
+
+void bta_hf_client_send_at_bia(void) {
+  char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+  int at_len;
+  int i;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+  if (bta_hf_client_cb.scb.peer_version < HFP_VERSION_1_6) {
+    APPL_TRACE_DEBUG("Remote does not Support AT+BIA");
+    return;
+  }
+
+  at_len = snprintf(buf, sizeof(buf), "AT+BIA=");
+
+  for (i = 0; i < BTA_HF_CLIENT_AT_INDICATOR_COUNT; i++) {
+    int sup = bta_hf_client_cb.scb.at_cb.indicator_lookup[i] == -1 ? 0 : 1;
+
+    at_len += snprintf(buf + at_len, sizeof(buf) - at_len, "%u,", sup);
+  }
+
+  buf[at_len - 1] = '\r';
+
+  if (at_len < 0) {
+    APPL_TRACE_ERROR("%s: AT command Framing error", __func__);
+    return;
+  }
+
+  bta_hf_client_send_at(BTA_HF_CLIENT_AT_BIA, buf, at_len);
+}
+
+void bta_hf_client_at_init(void) {
+  alarm_free(bta_hf_client_cb.scb.at_cb.resp_timer);
+  alarm_free(bta_hf_client_cb.scb.at_cb.hold_timer);
+  memset(&bta_hf_client_cb.scb.at_cb, 0, sizeof(tBTA_HF_CLIENT_AT_CB));
+  bta_hf_client_cb.scb.at_cb.resp_timer =
+      alarm_new("bta_hf_client.scb_at_resp_timer");
+  bta_hf_client_cb.scb.at_cb.hold_timer =
+      alarm_new("bta_hf_client.scb_at_hold_timer");
+  bta_hf_client_at_reset();
+}
+
+void bta_hf_client_at_reset(void) {
+  int i;
+
+  bta_hf_client_stop_at_resp_timer();
+  bta_hf_client_stop_at_hold_timer();
+
+  bta_hf_client_clear_queued_at();
+
+  bta_hf_client_at_clear_buf();
+
+  for (i = 0; i < BTA_HF_CLIENT_AT_INDICATOR_COUNT; i++) {
+    bta_hf_client_cb.scb.at_cb.indicator_lookup[i] = -1;
+  }
+
+  bta_hf_client_cb.scb.at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
+}
diff --git a/bt/bta/hf_client/bta_hf_client_at.h b/bt/bta/hf_client/bta_hf_client_at.h
new file mode 100644
index 0000000..9072195
--- /dev/null
+++ b/bt/bta/hf_client/bta_hf_client_at.h
@@ -0,0 +1,113 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *  Data types
+ ****************************************************************************/
+
+/* ASCII character string of arguments to the AT command */
+#define BTA_HF_CLIENT_AT_MAX_LEN 512
+
+/* AT command table element */
+typedef struct {
+  const char* p_cmd; /* AT command string */
+  uint8_t arg_type;  /* allowable argument type syntax */
+  uint8_t fmt;       /* whether arg is int or string */
+  uint8_t min;       /* minimum value for int arg */
+  int16_t max;       /* maximum value for int arg */
+} tBTA_AG_AT_CMD;
+
+/* callback function executed when command is parsed */
+typedef void(tBTA_AG_AT_CMD_CBACK)(void* p_user, uint16_t cmd, uint8_t arg_type,
+                                   char* p_arg, int16_t int_arg);
+
+/* callback function executed to send "ERROR" result code */
+typedef void(tBTA_AG_AT_ERR_CBACK)(void* p_user, bool unknown, char* p_arg);
+
+enum {
+  BTA_HF_CLIENT_AT_NONE,
+  BTA_HF_CLIENT_AT_BRSF,
+  BTA_HF_CLIENT_AT_BAC,
+  BTA_HF_CLIENT_AT_CIND,
+  BTA_HF_CLIENT_AT_CIND_STATUS,
+  BTA_HF_CLIENT_AT_CMER,
+  BTA_HF_CLIENT_AT_CHLD,
+  BTA_HF_CLIENT_AT_CMEE,
+  BTA_HF_CLIENT_AT_BIA,
+  BTA_HF_CLIENT_AT_CLIP,
+  BTA_HF_CLIENT_AT_CCWA,
+  BTA_HF_CLIENT_AT_COPS,
+  BTA_HF_CLIENT_AT_CLCC,
+  BTA_HF_CLIENT_AT_BVRA,
+  BTA_HF_CLIENT_AT_VGS,
+  BTA_HF_CLIENT_AT_VGM,
+  BTA_HF_CLIENT_AT_ATD,
+  BTA_HF_CLIENT_AT_BLDN,
+  BTA_HF_CLIENT_AT_ATA,
+  BTA_HF_CLIENT_AT_CHUP,
+  BTA_HF_CLIENT_AT_BTRH,
+  BTA_HF_CLIENT_AT_VTS,
+  BTA_HF_CLIENT_AT_BCC,
+  BTA_HF_CLIENT_AT_BCS,
+  BTA_HF_CLIENT_AT_CNUM,
+  BTA_HF_CLIENT_AT_NREC,
+  BTA_HF_CLIENT_AT_BINP,
+};
+
+typedef uint8_t tBTA_HF_CLIENT_AT_CMD;
+
+/* Maximum combined buffer for received AT events string */
+#define BTA_HF_CLIENT_AT_PARSER_MAX_LEN 4096
+
+/* This structure holds prepared AT command queued for sending */
+struct queued_at_cmd {
+  tBTA_HF_CLIENT_AT_CMD cmd;
+  char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+  uint16_t buf_len;
+  struct queued_at_cmd* next;
+};
+typedef struct queued_at_cmd tBTA_HF_CLIENT_AT_QCMD;
+
+/* Maximum number of indicators */
+#define BTA_HF_CLIENT_AT_INDICATOR_COUNT 20
+
+/* AT command parsing control block */
+typedef struct {
+  char buf[BTA_HF_CLIENT_AT_PARSER_MAX_LEN +
+           1]; /* extra byte to always have \0 at the end */
+  unsigned int offset;
+  tBTA_HF_CLIENT_AT_CMD current_cmd;
+  tBTA_HF_CLIENT_AT_QCMD* queued_cmd;
+  alarm_t* resp_timer; /* AT response timer */
+  alarm_t* hold_timer; /* AT hold timer */
+
+  /* CIND: lookup table to store the sequence of incoming indicators and their
+     values
+     so when their values come later, we know which value in sequence match
+     certain indicator */
+  int indicator_lookup[BTA_HF_CLIENT_AT_INDICATOR_COUNT];
+
+} tBTA_HF_CLIENT_AT_CB;
+
+/*****************************************************************************
+ *  Functions
+ ****************************************************************************/
+
+void bta_hf_client_at_init(void);
+void bta_hf_client_at_reset(void);
diff --git a/bt/bta/hf_client/bta_hf_client_cmd.cc b/bt/bta/hf_client/bta_hf_client_cmd.cc
new file mode 100644
index 0000000..b7109cb
--- /dev/null
+++ b/bt/bta/hf_client/bta_hf_client_cmd.cc
@@ -0,0 +1,85 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-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.
+ *
+ ******************************************************************************/
+
+#include "bta_hf_client_int.h"
+#include "stdio.h"
+
+void bta_hf_client_send_at_cmd(tBTA_HF_CLIENT_DATA* p_data) {
+  tBTA_HF_CLIENT_DATA_VAL* p_val = (tBTA_HF_CLIENT_DATA_VAL*)p_data;
+  char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+
+  switch (p_val->uint8_val) {
+    case BTA_HF_CLIENT_AT_CMD_VTS:
+      bta_hf_client_send_at_vts((char)p_val->uint32_val1);
+      break;
+    case BTA_HF_CLIENT_AT_CMD_BTRH:
+      bta_hf_client_send_at_btrh(false, p_val->uint32_val1);
+      break;
+    case BTA_HF_CLIENT_AT_CMD_CHUP:
+      bta_hf_client_send_at_chup();
+      break;
+    case BTA_HF_CLIENT_AT_CMD_CHLD:
+      /* expects ascii code for command */
+      bta_hf_client_send_at_chld('0' + p_val->uint32_val1, p_val->uint32_val2);
+      break;
+    case BTA_HF_CLIENT_AT_CMD_BCC:
+      bta_hf_client_send_at_bcc();
+      break;
+    case BTA_HF_CLIENT_AT_CMD_CNUM:
+      bta_hf_client_send_at_cnum();
+      break;
+    case BTA_HF_CLIENT_AT_CMD_ATA:
+      bta_hf_client_send_at_ata();
+      break;
+    case BTA_HF_CLIENT_AT_CMD_COPS:
+      bta_hf_client_send_at_cops(true);
+      break;
+    case BTA_HF_CLIENT_AT_CMD_ATD:
+      bta_hf_client_send_at_atd(p_val->str, p_val->uint32_val1);
+      break;
+    case BTA_HF_CLIENT_AT_CMD_VGM:
+      bta_hf_client_send_at_vgm(p_val->uint32_val1);
+      break;
+    case BTA_HF_CLIENT_AT_CMD_VGS:
+      bta_hf_client_send_at_vgs(p_val->uint32_val1);
+      break;
+    case BTA_HF_CLIENT_AT_CMD_BVRA:
+      bta_hf_client_send_at_bvra(p_val->uint32_val1 == 0 ? false : true);
+      break;
+    case BTA_HF_CLIENT_AT_CMD_CLCC:
+      bta_hf_client_send_at_clcc();
+      break;
+    case BTA_HF_CLIENT_AT_CMD_BINP:
+      bta_hf_client_send_at_binp(p_val->uint32_val1);
+      break;
+    case BTA_HF_CLIENT_AT_CMD_BLDN:
+      bta_hf_client_send_at_bldn();
+      break;
+    case BTA_HF_CLIENT_AT_CMD_NREC:
+      bta_hf_client_send_at_nrec();
+      break;
+    default:
+      APPL_TRACE_ERROR("Default case");
+      snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN,
+               "Cmd %d 1st arg %u 2nd arg %u string arg %s", p_val->uint8_val,
+               p_val->uint32_val1, p_val->uint32_val2, p_val->str);
+      APPL_TRACE_ERROR("%s ", buf);
+      break;
+  }
+}
diff --git a/bt/bta/hf_client/bta_hf_client_int.h b/bt/bta/hf_client/bta_hf_client_int.h
new file mode 100644
index 0000000..9b3faad
--- /dev/null
+++ b/bt/bta/hf_client/bta_hf_client_int.h
@@ -0,0 +1,285 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-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.
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+#include "bta_hf_client_api.h"
+#include "bta_hf_client_at.h"
+#include "bta_sys.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+#define HFP_VERSION_1_1 0x0101
+#define HFP_VERSION_1_5 0x0105
+#define HFP_VERSION_1_6 0x0106
+
+/* RFCOMM MTU SIZE */
+#define BTA_HF_CLIENT_MTU 256
+
+/* profile role for connection */
+#define BTA_HF_CLIENT_ACP 0 /* accepted connection */
+#define BTA_HF_CLIENT_INT 1 /* initiating connection */
+
+/* Time (in milliseconds) to wait for retry in case of collision */
+#ifndef BTA_HF_CLIENT_COLLISION_TIMER_MS
+#define BTA_HF_CLIENT_COLLISION_TIMER_MS 2411
+#endif
+
+enum {
+  /* these events are handled by the state machine */
+  BTA_HF_CLIENT_API_REGISTER_EVT = BTA_SYS_EVT_START(BTA_ID_HS),
+  BTA_HF_CLIENT_API_DEREGISTER_EVT,
+  BTA_HF_CLIENT_API_OPEN_EVT,
+  BTA_HF_CLIENT_API_CLOSE_EVT,
+  BTA_HF_CLIENT_API_AUDIO_OPEN_EVT,
+  BTA_HF_CLIENT_API_AUDIO_CLOSE_EVT,
+  BTA_HF_CLIENT_RFC_OPEN_EVT,
+  BTA_HF_CLIENT_RFC_CLOSE_EVT,
+  BTA_HF_CLIENT_RFC_SRV_CLOSE_EVT,
+  BTA_HF_CLIENT_RFC_DATA_EVT,
+  BTA_HF_CLIENT_DISC_ACP_RES_EVT,
+  BTA_HF_CLIENT_DISC_INT_RES_EVT,
+  BTA_HF_CLIENT_DISC_OK_EVT,
+  BTA_HF_CLIENT_DISC_FAIL_EVT,
+  BTA_HF_CLIENT_SCO_OPEN_EVT,
+  BTA_HF_CLIENT_SCO_CLOSE_EVT,
+  BTA_HF_CLIENT_SEND_AT_CMD_EVT,
+  BTA_HF_CLIENT_MAX_EVT,
+
+  /* these events are handled outside of the state machine */
+  BTA_HF_CLIENT_API_ENABLE_EVT,
+  BTA_HF_CLIENT_API_DISABLE_EVT
+};
+
+/*****************************************************************************
+ *  Data types
+ ****************************************************************************/
+
+/* data type for BTA_HF_CLIENT_API_ENABLE_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_HF_CLIENT_CBACK* p_cback;
+} tBTA_HF_CLIENT_API_ENABLE;
+
+/* data type for BTA_HF_CLIENT_API_REGISTER_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_HF_CLIENT_CBACK* p_cback;
+  tBTA_SEC sec_mask;
+  tBTA_HF_CLIENT_FEAT features;
+  char name[BTA_SERVICE_NAME_LEN + 1];
+} tBTA_HF_CLIENT_API_REGISTER;
+
+/* data type for BTA_HF_CLIENT_API_OPEN_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  tBTA_SEC sec_mask;
+} tBTA_HF_CLIENT_API_OPEN;
+
+/* data type for BTA_HF_CLIENT_DISC_RESULT_EVT */
+typedef struct {
+  BT_HDR hdr;
+  uint16_t status;
+} tBTA_HF_CLIENT_DISC_RESULT;
+
+/* data type for RFCOMM events */
+typedef struct {
+  BT_HDR hdr;
+  uint16_t port_handle;
+} tBTA_HF_CLIENT_RFC;
+
+/* generic purpose data type for other events */
+typedef struct {
+  BT_HDR hdr;
+  bool bool_val;
+  uint8_t uint8_val;
+  uint32_t uint32_val1;
+  uint32_t uint32_val2;
+  char str[BTA_HF_CLIENT_NUMBER_LEN + 1];
+} tBTA_HF_CLIENT_DATA_VAL;
+
+/* union of all event datatypes */
+typedef union {
+  BT_HDR hdr;
+  tBTA_HF_CLIENT_API_ENABLE api_enable;
+  tBTA_HF_CLIENT_API_REGISTER api_register;
+  tBTA_HF_CLIENT_API_OPEN api_open;
+  tBTA_HF_CLIENT_DISC_RESULT disc_result;
+  tBTA_HF_CLIENT_RFC rfc;
+  tBTA_HF_CLIENT_DATA_VAL val;
+
+} tBTA_HF_CLIENT_DATA;
+
+/* type for each service control block */
+typedef struct {
+  uint16_t serv_handle;         /* RFCOMM server handle */
+  BD_ADDR peer_addr;            /* peer bd address */
+  tSDP_DISCOVERY_DB* p_disc_db; /* pointer to discovery database */
+  uint16_t conn_handle;         /* RFCOMM handle of connected service */
+  tBTA_SEC serv_sec_mask;       /* server security mask */
+  tBTA_SEC cli_sec_mask;        /* client security mask */
+  tBTA_HF_CLIENT_FEAT features; /* features registered by application */
+  tBTA_HF_CLIENT_PEER_FEAT peer_features; /* peer device features */
+  tBTA_HF_CLIENT_CHLD_FEAT chld_features; /* call handling features */
+  uint16_t peer_version;                  /* profile version of peer device */
+  uint8_t peer_scn;                       /* peer scn */
+  uint8_t role;                           /* initiator/acceptor role */
+  uint16_t sco_idx;                       /* SCO handle */
+  uint8_t sco_state;                      /* SCO state variable */
+  bool sco_close_rfc; /* true if also close RFCOMM after SCO */
+  bool retry_with_sco_only;
+  bool deregister;    /* true if service shutting down */
+  bool svc_conn;      /* set to true when service level connection is up */
+  bool send_at_reply; /* set to true to notify framework about AT results */
+  tBTA_HF_CLIENT_AT_CB at_cb;           /* AT Parser control block */
+  uint8_t state;                        /* state machine state */
+  tBTM_SCO_CODEC_TYPE negotiated_codec; /* negotiated codec */
+  alarm_t* collision_timer;             /* Collision timer */
+} tBTA_HF_CLIENT_SCB;
+
+/* sco states */
+enum {
+  BTA_HF_CLIENT_SCO_SHUTDOWN_ST, /* no listening, no connection */
+  BTA_HF_CLIENT_SCO_LISTEN_ST,   /* listening */
+  BTA_HF_CLIENT_SCO_OPENING_ST,  /* connection opening */
+  BTA_HF_CLIENT_SCO_OPEN_CL_ST,  /* opening connection being closed */
+  BTA_HF_CLIENT_SCO_OPEN_ST,     /* open */
+  BTA_HF_CLIENT_SCO_CLOSING_ST,  /* closing */
+  BTA_HF_CLIENT_SCO_CLOSE_OP_ST, /* closing sco being opened */
+  BTA_HF_CLIENT_SCO_SHUTTING_ST  /* sco shutting down */
+};
+
+/* type for AG control block */
+typedef struct {
+  tBTA_HF_CLIENT_SCB scb; /* service control block */
+  uint32_t sdp_handle;
+  uint8_t scn;
+  tBTA_HF_CLIENT_CBACK* p_cback; /* application callback */
+  bool msbc_enabled;
+} tBTA_HF_CLIENT_CB;
+
+/*****************************************************************************
+ *  Global data
+ ****************************************************************************/
+
+/* control block declaration */
+extern tBTA_HF_CLIENT_CB bta_hf_client_cb;
+
+/*****************************************************************************
+ *  Function prototypes
+ ****************************************************************************/
+
+/* main functions */
+extern void bta_hf_client_scb_init(void);
+extern void bta_hf_client_scb_disable(void);
+extern bool bta_hf_client_hdl_event(BT_HDR* p_msg);
+extern void bta_hf_client_sm_execute(uint16_t event,
+                                     tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_slc_seq(bool error);
+extern void bta_hf_client_collision_cback(tBTA_SYS_CONN_STATUS status,
+                                          uint8_t id, uint8_t app_id,
+                                          BD_ADDR peer_addr);
+extern void bta_hf_client_resume_open();
+
+/* SDP functions */
+extern bool bta_hf_client_add_record(char* p_service_name, uint8_t scn,
+                                     tBTA_HF_CLIENT_FEAT features,
+                                     uint32_t sdp_handle);
+extern void bta_hf_client_create_record(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_del_record(tBTA_HF_CLIENT_DATA* p_data);
+extern bool bta_hf_client_sdp_find_attr(void);
+extern void bta_hf_client_do_disc(void);
+extern void bta_hf_client_free_db(tBTA_HF_CLIENT_DATA* p_data);
+
+/* RFCOMM functions */
+extern void bta_hf_client_setup_port(uint16_t handle);
+extern void bta_hf_client_start_server(void);
+extern void bta_hf_client_close_server(void);
+extern void bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_rfc_do_close(tBTA_HF_CLIENT_DATA* p_data);
+
+/* SCO functions */
+extern void bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_cback_sco(uint8_t event);
+
+/* AT command functions */
+extern void bta_hf_client_at_parse(char* buf, unsigned int len);
+extern void bta_hf_client_send_at_brsf(void);
+extern void bta_hf_client_send_at_bac(void);
+extern void bta_hf_client_send_at_cind(bool status);
+extern void bta_hf_client_send_at_cmer(bool activate);
+extern void bta_hf_client_send_at_chld(char cmd, uint32_t idx);
+extern void bta_hf_client_send_at_clip(bool activate);
+extern void bta_hf_client_send_at_ccwa(bool activate);
+extern void bta_hf_client_send_at_cmee(bool activate);
+extern void bta_hf_client_send_at_cops(bool query);
+extern void bta_hf_client_send_at_clcc(void);
+extern void bta_hf_client_send_at_bvra(bool enable);
+extern void bta_hf_client_send_at_vgs(uint32_t volume);
+extern void bta_hf_client_send_at_vgm(uint32_t volume);
+extern void bta_hf_client_send_at_atd(char* number, uint32_t memory);
+extern void bta_hf_client_send_at_bldn(void);
+extern void bta_hf_client_send_at_ata(void);
+extern void bta_hf_client_send_at_chup(void);
+extern void bta_hf_client_send_at_btrh(bool query, uint32_t val);
+extern void bta_hf_client_send_at_vts(char code);
+extern void bta_hf_client_send_at_bcc(void);
+extern void bta_hf_client_send_at_bcs(uint32_t codec);
+extern void bta_hf_client_send_at_cnum(void);
+extern void bta_hf_client_send_at_nrec(void);
+extern void bta_hf_client_send_at_binp(uint32_t action);
+extern void bta_hf_client_send_at_bia(void);
+
+/* Action functions */
+extern void bta_hf_client_register(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_deregister(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_start_dereg(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_start_close(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_start_open(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_rfc_acp_open(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_rfc_open(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_rfc_fail(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_disc_fail(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_open_fail(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_rfc_close(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_disc_acp_res(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_rfc_data(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_disc_int_res(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_svc_conn_open(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_ind(tBTA_HF_CLIENT_IND_TYPE type, uint16_t value);
+extern void bta_hf_client_evt_val(tBTA_HF_CLIENT_EVT type, uint16_t value);
+extern void bta_hf_client_operator_name(char* name);
+extern void bta_hf_client_clip(char* number);
+extern void bta_hf_client_ccwa(char* number);
+extern void bta_hf_client_at_result(tBTA_HF_CLIENT_AT_RESULT_TYPE type,
+                                    uint16_t cme);
+extern void bta_hf_client_clcc(uint32_t idx, bool incoming, uint8_t status,
+                               bool mpty, char* number);
+extern void bta_hf_client_cnum(char* number, uint16_t service);
+extern void bta_hf_client_binp(char* number);
+
+/* Commands handling functions */
+extern void bta_hf_client_dial(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_send_at_cmd(tBTA_HF_CLIENT_DATA* p_data);
diff --git a/bt/bta/hf_client/bta_hf_client_main.cc b/bt/bta/hf_client/bta_hf_client_main.cc
new file mode 100644
index 0000000..85e24c6
--- /dev/null
+++ b/bt/bta/hf_client/bta_hf_client_main.cc
@@ -0,0 +1,706 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-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.
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_utils.h"
+#include "bta_api.h"
+#include "bta_hf_client_api.h"
+#include "bta_hf_client_int.h"
+#include "bta_sys.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+
+/* uncomment to enable extra debug */
+/* #define BTA_HF_CLIENT_DEBUG TRUE */
+
+#ifndef BTA_HF_CLIENT_DEBUG
+#define BTA_HF_CLIENT_DEBUG FALSE
+#endif
+
+extern fixed_queue_t* btu_bta_alarm_queue;
+
+#if (BTA_HF_CLIENT_DEBUG == TRUE)
+static char* bta_hf_client_evt_str(uint16_t event);
+static char* bta_hf_client_state_str(uint8_t state);
+#endif
+
+/* state machine states */
+enum {
+  BTA_HF_CLIENT_INIT_ST,
+  BTA_HF_CLIENT_OPENING_ST,
+  BTA_HF_CLIENT_OPEN_ST,
+  BTA_HF_CLIENT_CLOSING_ST
+};
+
+/* state machine action enumeration list */
+enum {
+  BTA_HF_CLIENT_REGISTER,
+  BTA_HF_CLIENT_DEREGISTER,
+  BTA_HF_CLIENT_START_DEREG,
+  BTA_HF_CLIENT_RFC_DO_CLOSE,
+  BTA_HF_CLIENT_START_CLOSE,
+  BTA_HF_CLIENT_START_OPEN,
+  BTA_HF_CLIENT_RFC_ACP_OPEN,
+  BTA_HF_CLIENT_SCO_LISTEN,
+  BTA_HF_CLIENT_SCO_CONN_OPEN,
+  BTA_HF_CLIENT_SCO_CONN_CLOSE,
+  BTA_HF_CLIENT_SCO_OPEN,
+  BTA_HF_CLIENT_SCO_CLOSE,
+  BTA_HF_CLIENT_SCO_SHUTDOWN,
+  BTA_HF_CLIENT_FREE_DB,
+  BTA_HF_CLIENT_OPEN_FAIL,
+  BTA_HF_CLIENT_RFC_OPEN,
+  BTA_HF_CLIENT_RFC_FAIL,
+  BTA_HF_CLIENT_DISC_INT_RES,
+  BTA_HF_CLIENT_RFC_DO_OPEN,
+  BTA_HF_CLIENT_DISC_FAIL,
+  BTA_HF_CLIENT_RFC_CLOSE,
+  BTA_HF_CLIENT_RFC_DATA,
+  BTA_HF_CLIENT_DISC_ACP_RES,
+  BTA_HF_CLIENT_SVC_CONN_OPEN,
+  BTA_HF_CLIENT_SEND_AT_CMD,
+  BTA_HF_CLIENT_NUM_ACTIONS,
+};
+
+#define BTA_HF_CLIENT_IGNORE BTA_HF_CLIENT_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tBTA_HF_CLIENT_ACTION)(tBTA_HF_CLIENT_DATA* p_data);
+
+/* action functions table, indexed with action enum */
+const tBTA_HF_CLIENT_ACTION bta_hf_client_action[] = {
+    /* BTA_HF_CLIENT_REGISTER */ bta_hf_client_register,
+    /* BTA_HF_CLIENT_DEREGISTER */ bta_hf_client_deregister,
+    /* BTA_HF_CLIENT_START_DEREG */ bta_hf_client_start_dereg,
+    /* BTA_HF_CLIENT_RFC_DO_CLOSE */ bta_hf_client_rfc_do_close,
+    /* BTA_HF_CLIENT_START_CLOSE */ bta_hf_client_start_close,
+    /* BTA_HF_CLIENT_START_OPEN */ bta_hf_client_start_open,
+    /* BTA_HF_CLIENT_RFC_ACP_OPEN */ bta_hf_client_rfc_acp_open,
+    /* BTA_HF_CLIENT_SCO_LISTEN */ bta_hf_client_sco_listen,
+    /* BTA_HF_CLIENT_SCO_CONN_OPEN */ bta_hf_client_sco_conn_open,
+    /* BTA_HF_CLIENT_SCO_CONN_CLOSE*/ bta_hf_client_sco_conn_close,
+    /* BTA_HF_CLIENT_SCO_OPEN */ bta_hf_client_sco_open,
+    /* BTA_HF_CLIENT_SCO_CLOSE */ bta_hf_client_sco_close,
+    /* BTA_HF_CLIENT_SCO_SHUTDOWN */ bta_hf_client_sco_shutdown,
+    /* BTA_HF_CLIENT_FREE_DB */ bta_hf_client_free_db,
+    /* BTA_HF_CLIENT_OPEN_FAIL */ bta_hf_client_open_fail,
+    /* BTA_HF_CLIENT_RFC_OPEN */ bta_hf_client_rfc_open,
+    /* BTA_HF_CLIENT_RFC_FAIL */ bta_hf_client_rfc_fail,
+    /* BTA_HF_CLIENT_DISC_INT_RES */ bta_hf_client_disc_int_res,
+    /* BTA_HF_CLIENT_RFC_DO_OPEN */ bta_hf_client_rfc_do_open,
+    /* BTA_HF_CLIENT_DISC_FAIL */ bta_hf_client_disc_fail,
+    /* BTA_HF_CLIENT_RFC_CLOSE */ bta_hf_client_rfc_close,
+    /* BTA_HF_CLIENT_RFC_DATA */ bta_hf_client_rfc_data,
+    /* BTA_HF_CLIENT_DISC_ACP_RES */ bta_hf_client_disc_acp_res,
+    /* BTA_HF_CLIENT_SVC_CONN_OPEN */ bta_hf_client_svc_conn_open,
+    /* BTA_HF_CLIENT_SEND_AT_CMD */ bta_hf_client_send_at_cmd,
+};
+
+/* state table information */
+#define BTA_HF_CLIENT_ACTIONS 2    /* number of actions */
+#define BTA_HF_CLIENT_NEXT_STATE 2 /* position of next state */
+#define BTA_HF_CLIENT_NUM_COLS 3   /* number of columns in state tables */
+
+/* state table for init state */
+const uint8_t bta_hf_client_st_init[][BTA_HF_CLIENT_NUM_COLS] = {
+    /* Event                    Action 1                       Action 2
+       Next state */
+    /* API_REGISTER_EVT */ {BTA_HF_CLIENT_REGISTER, BTA_HF_CLIENT_IGNORE,
+                            BTA_HF_CLIENT_INIT_ST},
+    /* API_DEREGISTER_EVT */ {BTA_HF_CLIENT_DEREGISTER, BTA_HF_CLIENT_IGNORE,
+                              BTA_HF_CLIENT_INIT_ST},
+    /* API_OPEN_EVT */ {BTA_HF_CLIENT_START_OPEN, BTA_HF_CLIENT_IGNORE,
+                        BTA_HF_CLIENT_OPENING_ST},
+    /* API_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                         BTA_HF_CLIENT_INIT_ST},
+    /* API_AUDIO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                              BTA_HF_CLIENT_INIT_ST},
+    /* API_AUDIO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                               BTA_HF_CLIENT_INIT_ST},
+    /* RFC_OPEN_EVT */ {BTA_HF_CLIENT_RFC_ACP_OPEN, BTA_HF_CLIENT_SCO_LISTEN,
+                        BTA_HF_CLIENT_OPEN_ST},
+    /* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                         BTA_HF_CLIENT_INIT_ST},
+    /* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                             BTA_HF_CLIENT_INIT_ST},
+    /* RFC_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                        BTA_HF_CLIENT_INIT_ST},
+    /* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_FREE_DB, BTA_HF_CLIENT_IGNORE,
+                            BTA_HF_CLIENT_INIT_ST},
+    /* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                            BTA_HF_CLIENT_INIT_ST},
+    /* DISC_OK_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                       BTA_HF_CLIENT_INIT_ST},
+    /* DISC_FAIL_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                         BTA_HF_CLIENT_INIT_ST},
+    /* SCO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                        BTA_HF_CLIENT_INIT_ST},
+    /* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                         BTA_HF_CLIENT_INIT_ST},
+    /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                           BTA_HF_CLIENT_INIT_ST},
+};
+
+/* state table for opening state */
+const uint8_t bta_hf_client_st_opening[][BTA_HF_CLIENT_NUM_COLS] = {
+    /* Event                    Action 1                       Action 2
+       Next state */
+    /* API_REGISTER_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                            BTA_HF_CLIENT_OPENING_ST},
+    /* API_DEREGISTER_EVT */ {BTA_HF_CLIENT_RFC_DO_CLOSE,
+                              BTA_HF_CLIENT_START_DEREG,
+                              BTA_HF_CLIENT_CLOSING_ST},
+    /* API_OPEN_EVT */ {BTA_HF_CLIENT_OPEN_FAIL, BTA_HF_CLIENT_IGNORE,
+                        BTA_HF_CLIENT_OPENING_ST},
+    /* API_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_DO_CLOSE, BTA_HF_CLIENT_IGNORE,
+                         BTA_HF_CLIENT_CLOSING_ST},
+    /* API_AUDIO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                              BTA_HF_CLIENT_OPENING_ST},
+    /* API_AUDIO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                               BTA_HF_CLIENT_OPENING_ST},
+    /* RFC_OPEN_EVT */ {BTA_HF_CLIENT_RFC_OPEN, BTA_HF_CLIENT_SCO_LISTEN,
+                        BTA_HF_CLIENT_OPEN_ST},
+    /* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_FAIL, BTA_HF_CLIENT_IGNORE,
+                         BTA_HF_CLIENT_INIT_ST},
+    /* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                             BTA_HF_CLIENT_OPENING_ST},
+    /* RFC_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                        BTA_HF_CLIENT_OPENING_ST},
+    /* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                            BTA_HF_CLIENT_OPENING_ST},
+    /* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_DISC_INT_RES, BTA_HF_CLIENT_IGNORE,
+                            BTA_HF_CLIENT_OPENING_ST},
+    /* DISC_OK_EVT */ {BTA_HF_CLIENT_RFC_DO_OPEN, BTA_HF_CLIENT_IGNORE,
+                       BTA_HF_CLIENT_OPENING_ST},
+    /* DISC_FAIL_EVT */ {BTA_HF_CLIENT_DISC_FAIL, BTA_HF_CLIENT_IGNORE,
+                         BTA_HF_CLIENT_INIT_ST},
+    /* SCO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                        BTA_HF_CLIENT_OPENING_ST},
+    /* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                         BTA_HF_CLIENT_OPENING_ST},
+    /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                           BTA_HF_CLIENT_OPENING_ST},
+};
+
+/* state table for open state */
+const uint8_t bta_hf_client_st_open[][BTA_HF_CLIENT_NUM_COLS] = {
+    /* Event                    Action 1                       Action 2
+       Next state */
+    /* API_REGISTER_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                            BTA_HF_CLIENT_OPEN_ST},
+    /* API_DEREGISTER_EVT */ {BTA_HF_CLIENT_START_CLOSE,
+                              BTA_HF_CLIENT_START_DEREG,
+                              BTA_HF_CLIENT_CLOSING_ST},
+    /* API_OPEN_EVT */ {BTA_HF_CLIENT_OPEN_FAIL, BTA_HF_CLIENT_IGNORE,
+                        BTA_HF_CLIENT_OPEN_ST},
+    /* API_CLOSE_EVT */ {BTA_HF_CLIENT_START_CLOSE, BTA_HF_CLIENT_IGNORE,
+                         BTA_HF_CLIENT_CLOSING_ST},
+    /* API_AUDIO_OPEN_EVT */ {BTA_HF_CLIENT_SCO_OPEN, BTA_HF_CLIENT_IGNORE,
+                              BTA_HF_CLIENT_OPEN_ST},
+    /* API_AUDIO_CLOSE_EVT */ {BTA_HF_CLIENT_SCO_CLOSE, BTA_HF_CLIENT_IGNORE,
+                               BTA_HF_CLIENT_OPEN_ST},
+    /* RFC_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                        BTA_HF_CLIENT_OPEN_ST},
+    /* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_CLOSE, BTA_HF_CLIENT_IGNORE,
+                         BTA_HF_CLIENT_INIT_ST},
+    /* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                             BTA_HF_CLIENT_OPEN_ST},
+    /* RFC_DATA_EVT */ {BTA_HF_CLIENT_RFC_DATA, BTA_HF_CLIENT_IGNORE,
+                        BTA_HF_CLIENT_OPEN_ST},
+    /* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_DISC_ACP_RES, BTA_HF_CLIENT_IGNORE,
+                            BTA_HF_CLIENT_OPEN_ST},
+    /* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                            BTA_HF_CLIENT_OPEN_ST},
+    /* DISC_OK_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                       BTA_HF_CLIENT_OPEN_ST},
+    /* DISC_FAIL_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                         BTA_HF_CLIENT_OPEN_ST},
+    /* SCO_OPEN_EVT */ {BTA_HF_CLIENT_SCO_CONN_OPEN, BTA_HF_CLIENT_IGNORE,
+                        BTA_HF_CLIENT_OPEN_ST},
+    /* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_SCO_CONN_CLOSE, BTA_HF_CLIENT_IGNORE,
+                         BTA_HF_CLIENT_OPEN_ST},
+    /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_SEND_AT_CMD, BTA_HF_CLIENT_IGNORE,
+                           BTA_HF_CLIENT_OPEN_ST},
+};
+
+/* state table for closing state */
+const uint8_t bta_hf_client_st_closing[][BTA_HF_CLIENT_NUM_COLS] = {
+    /* Event                    Action 1                       Action 2
+       Next state */
+    /* API_REGISTER_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                            BTA_HF_CLIENT_CLOSING_ST},
+    /* API_DEREGISTER_EVT */ {BTA_HF_CLIENT_START_DEREG, BTA_HF_CLIENT_IGNORE,
+                              BTA_HF_CLIENT_CLOSING_ST},
+    /* API_OPEN_EVT */ {BTA_HF_CLIENT_OPEN_FAIL, BTA_HF_CLIENT_IGNORE,
+                        BTA_HF_CLIENT_CLOSING_ST},
+    /* API_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                         BTA_HF_CLIENT_CLOSING_ST},
+    /* API_AUDIO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                              BTA_HF_CLIENT_CLOSING_ST},
+    /* API_AUDIO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                               BTA_HF_CLIENT_CLOSING_ST},
+    /* RFC_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                        BTA_HF_CLIENT_CLOSING_ST},
+    /* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_CLOSE, BTA_HF_CLIENT_IGNORE,
+                         BTA_HF_CLIENT_INIT_ST},
+    /* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                             BTA_HF_CLIENT_CLOSING_ST},
+    /* RFC_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                        BTA_HF_CLIENT_CLOSING_ST},
+    /* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_FREE_DB, BTA_HF_CLIENT_IGNORE,
+                            BTA_HF_CLIENT_CLOSING_ST},
+    /* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_FREE_DB, BTA_HF_CLIENT_IGNORE,
+                            BTA_HF_CLIENT_INIT_ST},
+    /* DISC_OK_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                       BTA_HF_CLIENT_CLOSING_ST},
+    /* DISC_FAIL_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                         BTA_HF_CLIENT_CLOSING_ST},
+    /* SCO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                        BTA_HF_CLIENT_CLOSING_ST},
+    /* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                         BTA_HF_CLIENT_CLOSING_ST},
+    /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+                           BTA_HF_CLIENT_CLOSING_ST},
+};
+
+/* type for state table */
+typedef const uint8_t (*tBTA_HF_CLIENT_ST_TBL)[BTA_HF_CLIENT_NUM_COLS];
+
+/* state table */
+const tBTA_HF_CLIENT_ST_TBL bta_hf_client_st_tbl[] = {
+    bta_hf_client_st_init, bta_hf_client_st_opening, bta_hf_client_st_open,
+    bta_hf_client_st_closing};
+
+/* HF Client control block */
+tBTA_HF_CLIENT_CB bta_hf_client_cb;
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_scb_init
+ *
+ * Description      Initialize an HF_Client service control block.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_scb_init(void) {
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  alarm_free(bta_hf_client_cb.scb.collision_timer);
+  alarm_free(bta_hf_client_cb.scb.at_cb.resp_timer);
+  alarm_free(bta_hf_client_cb.scb.at_cb.hold_timer);
+  memset(&bta_hf_client_cb.scb, 0, sizeof(tBTA_HF_CLIENT_SCB));
+  bta_hf_client_cb.scb.collision_timer =
+      alarm_new("bta_hf_client.scb_collision_timer");
+  bta_hf_client_cb.scb.sco_idx = BTM_INVALID_SCO_INDEX;
+  bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_scb_disable
+ *
+ * Description      Disable a service control block.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_scb_disable(void) {
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  bta_hf_client_scb_init();
+
+  (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_DISABLE_EVT, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_resume_open
+ *
+ * Description      Resume opening process.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_resume_open(void) {
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  /* resume opening process.  */
+  if (bta_hf_client_cb.scb.state == BTA_HF_CLIENT_INIT_ST) {
+    bta_hf_client_cb.scb.state = BTA_HF_CLIENT_OPENING_ST;
+    bta_hf_client_start_open(NULL);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_collision_timer_cback
+ *
+ * Description      HF Client connection collision timer callback
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hf_client_collision_timer_cback(UNUSED_ATTR void* data) {
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  /* If the peer haven't opened connection, restart opening process */
+  bta_hf_client_resume_open();
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_collision_cback
+ *
+ * Description      Get notified about collision.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_collision_cback(UNUSED_ATTR tBTA_SYS_CONN_STATUS status,
+                                   uint8_t id, UNUSED_ATTR uint8_t app_id,
+                                   UNUSED_ATTR BD_ADDR peer_addr) {
+  if (bta_hf_client_cb.scb.state == BTA_HF_CLIENT_OPENING_ST) {
+    if (id == BTA_ID_SYS) /* ACL collision */
+    {
+      APPL_TRACE_WARNING("HF Client found collision (ACL) ...");
+    } else if (id == BTA_ID_HS) /* RFCOMM collision */
+    {
+      APPL_TRACE_WARNING("HF Client found collision (RFCOMM) ...");
+    } else {
+      APPL_TRACE_WARNING("HF Client found collision (\?\?\?) ...");
+    }
+
+    bta_hf_client_cb.scb.state = BTA_HF_CLIENT_INIT_ST;
+
+    /* Cancel SDP if it had been started. */
+    if (bta_hf_client_cb.scb.p_disc_db) {
+      (void)SDP_CancelServiceSearch(bta_hf_client_cb.scb.p_disc_db);
+      bta_hf_client_free_db(NULL);
+    }
+
+    /* reopen registered server */
+    /* Collision may be detected before or after we close servers. */
+    bta_hf_client_start_server();
+
+    /* Start timer to handle connection opening restart */
+    alarm_set_on_queue(
+        bta_hf_client_cb.scb.collision_timer, BTA_HF_CLIENT_COLLISION_TIMER_MS,
+        bta_hf_client_collision_timer_cback, NULL, btu_bta_alarm_queue);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_api_enable
+ *
+ * Description      Handle an API enable event.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hf_client_api_enable(tBTA_HF_CLIENT_DATA* p_data) {
+  char value[PROPERTY_VALUE_MAX];
+
+  /* initialize control block */
+  memset(&bta_hf_client_cb, 0, sizeof(tBTA_HF_CLIENT_CB));
+
+  /* store callback function */
+  bta_hf_client_cb.p_cback = p_data->api_enable.p_cback;
+
+  /* check if mSBC support enabled */
+  osi_property_get("ro.bluetooth.hfp.ver", value, "0");
+  if (strcmp(value, "1.6") == 0) {
+    bta_hf_client_cb.msbc_enabled = true;
+  }
+
+  bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD;
+
+  /* set same setting as AG does */
+  BTM_WriteVoiceSettings(AG_VOICE_SETTINGS);
+
+  bta_sys_collision_register(BTA_ID_HS, bta_hf_client_collision_cback);
+
+  /* call callback with enable event */
+  (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_ENABLE_EVT, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_api_disable
+ *
+ * Description      Handle an API disable event.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hf_client_api_disable(tBTA_HF_CLIENT_DATA* p_data) {
+  if (!bta_sys_is_register(BTA_ID_HS)) {
+    APPL_TRACE_ERROR("BTA HF Client is already disabled, ignoring ...");
+    return;
+  }
+
+  /* De-register with BTA system manager */
+  bta_sys_deregister(BTA_ID_HS);
+
+  bta_hf_client_sm_execute(BTA_HF_CLIENT_API_DEREGISTER_EVT, p_data);
+
+  bta_sys_collision_register(BTA_ID_HS, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_hdl_event
+ *
+ * Description      Data HF Client main event handling function.
+ *
+ *
+ * Returns          bool
+ *
+ ******************************************************************************/
+bool bta_hf_client_hdl_event(BT_HDR* p_msg) {
+#if (BTA_HF_CLIENT_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hf_client_hdl_event %s (0x%x)",
+                   bta_hf_client_evt_str(p_msg->event), p_msg->event);
+#endif
+
+  switch (p_msg->event) {
+    /* handle enable event */
+    case BTA_HF_CLIENT_API_ENABLE_EVT:
+      bta_hf_client_api_enable((tBTA_HF_CLIENT_DATA*)p_msg);
+      break;
+
+    /* handle disable event */
+    case BTA_HF_CLIENT_API_DISABLE_EVT:
+      bta_hf_client_api_disable((tBTA_HF_CLIENT_DATA*)p_msg);
+      break;
+
+    default:
+      bta_hf_client_sm_execute(p_msg->event, (tBTA_HF_CLIENT_DATA*)p_msg);
+      break;
+  }
+  return true;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_sm_execute
+ *
+ * Description      State machine event handling function for HF Client
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_sm_execute(uint16_t event, tBTA_HF_CLIENT_DATA* p_data) {
+  tBTA_HF_CLIENT_ST_TBL state_table;
+  uint8_t action;
+  int i;
+
+#if (BTA_HF_CLIENT_DEBUG == TRUE)
+  uint16_t in_event = event;
+  uint8_t in_state = bta_hf_client_cb.scb.state;
+
+  /* Ignore displaying of AT results when not connected (Ignored in state
+   * machine) */
+  if (bta_hf_client_cb.scb.state == BTA_HF_CLIENT_OPEN_ST) {
+    APPL_TRACE_EVENT("HF Client evt : State %d (%s), Event 0x%04x (%s)",
+                     bta_hf_client_cb.scb.state,
+                     bta_hf_client_state_str(bta_hf_client_cb.scb.state), event,
+                     bta_hf_client_evt_str(event));
+  }
+#endif
+
+  event &= 0x00FF;
+  if (event >= (BTA_HF_CLIENT_MAX_EVT & 0x00FF)) {
+    APPL_TRACE_ERROR("HF Client evt out of range, ignoring...");
+    return;
+  }
+
+  /* look up the state table for the current state */
+  state_table = bta_hf_client_st_tbl[bta_hf_client_cb.scb.state];
+
+  /* set next state */
+  bta_hf_client_cb.scb.state = state_table[event][BTA_HF_CLIENT_NEXT_STATE];
+
+  /* execute action functions */
+  for (i = 0; i < BTA_HF_CLIENT_ACTIONS; i++) {
+    if ((action = state_table[event][i]) != BTA_HF_CLIENT_IGNORE) {
+      (*bta_hf_client_action[action])(p_data);
+    } else {
+      break;
+    }
+  }
+
+#if (BTA_HF_CLIENT_DEBUG == TRUE)
+  if (bta_hf_client_cb.scb.state != in_state) {
+    APPL_TRACE_EVENT(
+        "BTA HF Client State Change: [%s] -> [%s] after Event [%s]",
+        bta_hf_client_state_str(in_state),
+        bta_hf_client_state_str(bta_hf_client_cb.scb.state),
+        bta_hf_client_evt_str(in_event));
+  }
+#endif
+}
+
+static void send_post_slc_cmd(void) {
+  bta_hf_client_cb.scb.at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
+
+  bta_hf_client_send_at_bia();
+  bta_hf_client_send_at_ccwa(true);
+  bta_hf_client_send_at_cmee(true);
+  bta_hf_client_send_at_cops(false);
+  bta_hf_client_send_at_btrh(true, 0);
+  bta_hf_client_send_at_clip(true);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_slc_seq
+ *
+ * Description      Handles AT commands sequence required for SLC creation
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_slc_seq(bool error) {
+  APPL_TRACE_DEBUG("bta_hf_client_slc_seq cmd: %u",
+                   bta_hf_client_cb.scb.at_cb.current_cmd);
+
+  if (error) {
+    /* SLC establishment error, sent close rfcomm event */
+    APPL_TRACE_ERROR(
+        "HFPClient: Failed to create SLC due to AT error, disconnecting (%u)",
+        bta_hf_client_cb.scb.at_cb.current_cmd);
+
+    bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL);
+    return;
+  }
+
+  if (bta_hf_client_cb.scb.svc_conn) return;
+
+  switch (bta_hf_client_cb.scb.at_cb.current_cmd) {
+    case BTA_HF_CLIENT_AT_NONE:
+      bta_hf_client_send_at_brsf();
+      break;
+
+    case BTA_HF_CLIENT_AT_BRSF:
+      if ((bta_hf_client_cb.scb.features & BTA_HF_CLIENT_FEAT_CODEC) &&
+          (bta_hf_client_cb.scb.peer_features & BTA_HF_CLIENT_PEER_CODEC)) {
+        bta_hf_client_send_at_bac();
+        break;
+      }
+
+      bta_hf_client_send_at_cind(false);
+      break;
+
+    case BTA_HF_CLIENT_AT_BAC:
+      bta_hf_client_send_at_cind(false);
+      break;
+
+    case BTA_HF_CLIENT_AT_CIND:
+      bta_hf_client_send_at_cind(true);
+      break;
+
+    case BTA_HF_CLIENT_AT_CIND_STATUS:
+      bta_hf_client_send_at_cmer(true);
+      break;
+
+    case BTA_HF_CLIENT_AT_CMER:
+      if (bta_hf_client_cb.scb.peer_features & BTA_HF_CLIENT_PEER_FEAT_3WAY &&
+          bta_hf_client_cb.scb.features & BTA_HF_CLIENT_FEAT_3WAY) {
+        bta_hf_client_send_at_chld('?', 0);
+      } else {
+        bta_hf_client_svc_conn_open(NULL);
+        send_post_slc_cmd();
+      }
+      break;
+
+    case BTA_HF_CLIENT_AT_CHLD:
+      bta_hf_client_svc_conn_open(NULL);
+      send_post_slc_cmd();
+      break;
+
+    default:
+      /* If happen there is a bug in SLC creation procedure... */
+      APPL_TRACE_ERROR(
+          "HFPClient: Failed to create SLCdue to unexpected AT command, "
+          "disconnecting (%u)",
+          bta_hf_client_cb.scb.at_cb.current_cmd);
+
+      bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, NULL);
+      break;
+  }
+}
+
+#if (BTA_HF_CLIENT_DEBUG == TRUE)
+
+#ifndef CASE_RETURN_STR
+#define CASE_RETURN_STR(const) \
+  case const:                  \
+    return #const;
+#endif
+
+static char* bta_hf_client_evt_str(uint16_t event) {
+  switch (event) {
+    CASE_RETURN_STR(BTA_HF_CLIENT_API_REGISTER_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_API_DEREGISTER_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_API_OPEN_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_API_CLOSE_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_API_AUDIO_OPEN_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_API_AUDIO_CLOSE_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_RFC_OPEN_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_RFC_CLOSE_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_RFC_SRV_CLOSE_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_RFC_DATA_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_DISC_ACP_RES_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_DISC_INT_RES_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_DISC_OK_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_DISC_FAIL_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_API_ENABLE_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_API_DISABLE_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_SCO_OPEN_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_SCO_CLOSE_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_SEND_AT_CMD_EVT)
+    default:
+      return "Unknown HF Client Event";
+  }
+}
+
+static char* bta_hf_client_state_str(uint8_t state) {
+  switch (state) {
+    CASE_RETURN_STR(BTA_HF_CLIENT_INIT_ST)
+    CASE_RETURN_STR(BTA_HF_CLIENT_OPENING_ST)
+    CASE_RETURN_STR(BTA_HF_CLIENT_OPEN_ST)
+    CASE_RETURN_STR(BTA_HF_CLIENT_CLOSING_ST)
+    default:
+      return "Unknown HF Client State";
+  }
+}
+#endif
diff --git a/bt/bta/hf_client/bta_hf_client_rfc.cc b/bt/bta/hf_client/bta_hf_client_rfc.cc
new file mode 100644
index 0000000..4961dd8
--- /dev/null
+++ b/bt/bta/hf_client/bta_hf_client_rfc.cc
@@ -0,0 +1,254 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2004-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 audio gateway functions controlling the RFCOMM
+ *  connections.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_utils.h"
+#include "bta_api.h"
+#include "bta_hf_client_int.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_port_cback
+ *
+ * Description      RFCOMM Port callback
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hf_client_port_cback(UNUSED_ATTR uint32_t code,
+                                     uint16_t port_handle) {
+  /* ignore port events for port handles other than connected handle */
+  if (port_handle != bta_hf_client_cb.scb.conn_handle) {
+    APPL_TRACE_DEBUG(
+        "bta_hf_client_port_cback ignoring handle:%d conn_handle = %d",
+        port_handle, bta_hf_client_cb.scb.conn_handle);
+    return;
+  }
+
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+  p_buf->event = BTA_HF_CLIENT_RFC_DATA_EVT;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_mgmt_cback
+ *
+ * Description      RFCOMM management callback
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hf_client_mgmt_cback(uint32_t code, uint16_t port_handle) {
+  uint16_t event;
+
+  APPL_TRACE_DEBUG(
+      "bta_hf_client_mgmt_cback : code = %d, port_handle = %d, conn_handle = "
+      "%d, serv_handle = %d",
+      code, port_handle, bta_hf_client_cb.scb.conn_handle,
+      bta_hf_client_cb.scb.serv_handle);
+
+  /* ignore close event for port handles other than connected handle */
+  if ((code != PORT_SUCCESS) &&
+      (port_handle != bta_hf_client_cb.scb.conn_handle)) {
+    APPL_TRACE_DEBUG("bta_hf_client_mgmt_cback ignoring handle:%d",
+                     port_handle);
+    return;
+  }
+
+  if (code == PORT_SUCCESS) {
+    if ((bta_hf_client_cb.scb.conn_handle &&
+         (port_handle ==
+          bta_hf_client_cb.scb.conn_handle)) || /* outgoing connection */
+        (port_handle ==
+         bta_hf_client_cb.scb.serv_handle)) /* incoming connection */
+    {
+      event = BTA_HF_CLIENT_RFC_OPEN_EVT;
+    } else {
+      APPL_TRACE_ERROR(
+          "bta_hf_client_mgmt_cback: PORT_SUCCESS, ignoring handle = %d",
+          port_handle);
+      return;
+    }
+  }
+  /* distinguish server close events */
+  else if (port_handle == bta_hf_client_cb.scb.conn_handle) {
+    event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
+  } else {
+    event = BTA_HF_CLIENT_RFC_SRV_CLOSE_EVT;
+  }
+
+  tBTA_HF_CLIENT_RFC* p_buf =
+      (tBTA_HF_CLIENT_RFC*)osi_malloc(sizeof(tBTA_HF_CLIENT_RFC));
+  p_buf->hdr.event = event;
+  p_buf->port_handle = port_handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_setup_port
+ *
+ * Description      Setup RFCOMM port for use by HF Client.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_setup_port(uint16_t handle) {
+  PORT_SetEventMask(handle, PORT_EV_RXCHAR);
+  PORT_SetEventCallback(handle, bta_hf_client_port_cback);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_start_server
+ *
+ * Description      Setup RFCOMM server for use by HF Client.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_start_server(void) {
+  int port_status;
+
+  if (bta_hf_client_cb.scb.serv_handle > 0) {
+    APPL_TRACE_DEBUG("%s already started, handle: %d", __func__,
+                     bta_hf_client_cb.scb.serv_handle);
+    return;
+  }
+
+  BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_HF_HANDSFREE,
+                       bta_hf_client_cb.scb.serv_sec_mask, BT_PSM_RFCOMM,
+                       BTM_SEC_PROTO_RFCOMM, bta_hf_client_cb.scn);
+
+  port_status = RFCOMM_CreateConnection(
+      UUID_SERVCLASS_HF_HANDSFREE, bta_hf_client_cb.scn, true,
+      BTA_HF_CLIENT_MTU, (uint8_t*)bd_addr_any,
+      &(bta_hf_client_cb.scb.serv_handle), bta_hf_client_mgmt_cback);
+
+  if (port_status == PORT_SUCCESS) {
+    bta_hf_client_setup_port(bta_hf_client_cb.scb.serv_handle);
+  } else {
+    /* TODO: can we handle this better? */
+    APPL_TRACE_DEBUG(
+        "bta_hf_client_start_server: RFCOMM_CreateConnection returned error:%d",
+        port_status);
+  }
+
+  APPL_TRACE_DEBUG("bta_hf_client_start_server handle: %d",
+                   bta_hf_client_cb.scb.serv_handle);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_close_server
+ *
+ * Description      Close RFCOMM server port for use by HF Client.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_close_server(void) {
+  APPL_TRACE_DEBUG("%s %d", __func__, bta_hf_client_cb.scb.serv_handle);
+
+  if (bta_hf_client_cb.scb.serv_handle == 0) {
+    APPL_TRACE_DEBUG("%s already stopped", __func__);
+    return;
+  }
+
+  RFCOMM_RemoveServer(bta_hf_client_cb.scb.serv_handle);
+  bta_hf_client_cb.scb.serv_handle = 0;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_rfc_do_open
+ *
+ * Description      Open an RFCOMM connection to the peer device.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA* p_data) {
+  BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_HF_HANDSFREE,
+                       bta_hf_client_cb.scb.cli_sec_mask, BT_PSM_RFCOMM,
+                       BTM_SEC_PROTO_RFCOMM, bta_hf_client_cb.scb.peer_scn);
+
+  if (RFCOMM_CreateConnection(UUID_SERVCLASS_HF_HANDSFREE,
+                              bta_hf_client_cb.scb.peer_scn, false,
+                              BTA_HF_CLIENT_MTU, bta_hf_client_cb.scb.peer_addr,
+                              &(bta_hf_client_cb.scb.conn_handle),
+                              bta_hf_client_mgmt_cback) == PORT_SUCCESS) {
+    bta_hf_client_setup_port(bta_hf_client_cb.scb.conn_handle);
+    APPL_TRACE_DEBUG("bta_hf_client_rfc_do_open : conn_handle = %d",
+                     bta_hf_client_cb.scb.conn_handle);
+  }
+  /* RFCOMM create connection failed; send ourselves RFCOMM close event */
+  else {
+    bta_hf_client_sm_execute(BTA_HF_CLIENT_RFC_CLOSE_EVT, p_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_rfc_do_close
+ *
+ * Description      Close RFCOMM connection.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_rfc_do_close(UNUSED_ATTR tBTA_HF_CLIENT_DATA* p_data) {
+  if (bta_hf_client_cb.scb.conn_handle) {
+    RFCOMM_RemoveConnection(bta_hf_client_cb.scb.conn_handle);
+  } else {
+    /* Close API was called while HF Client is in Opening state.        */
+    /* Need to trigger the state machine to send callback to the app    */
+    /* and move back to INIT state.                                     */
+    tBTA_HF_CLIENT_RFC* p_buf =
+        (tBTA_HF_CLIENT_RFC*)osi_malloc(sizeof(tBTA_HF_CLIENT_RFC));
+    p_buf->hdr.event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
+    bta_sys_sendmsg(p_buf);
+
+    /* Cancel SDP if it had been started. */
+    if (bta_hf_client_cb.scb.p_disc_db) {
+      (void)SDP_CancelServiceSearch(bta_hf_client_cb.scb.p_disc_db);
+      bta_hf_client_free_db(NULL);
+    }
+  }
+}
diff --git a/bt/bta/hf_client/bta_hf_client_sco.cc b/bt/bta/hf_client/bta_hf_client_sco.cc
new file mode 100644
index 0000000..64918dc
--- /dev/null
+++ b/bt/bta/hf_client/bta_hf_client_sco.cc
@@ -0,0 +1,677 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2004-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.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_trace.h"
+#include "bt_utils.h"
+#include "bta_hf_client_int.h"
+#include "osi/include/osi.h"
+
+#define BTA_HF_CLIENT_NO_EDR_ESCO                                      \
+  (BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 | BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | \
+   BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | BTM_SCO_PKT_TYPES_MASK_NO_3_EV5)
+
+static const tBTM_ESCO_PARAMS bta_hf_client_esco_params[] = {
+    /* SCO CVSD */
+    {
+        .rx_bw = BTM_64KBITS_RATE,
+        .tx_bw = BTM_64KBITS_RATE,
+        .max_latency = 10,
+        .voice_contfmt = BTM_VOICE_SETTING_CVSD,
+        .packet_types =
+            (BTM_SCO_LINK_ONLY_MASK | BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 |
+             BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+             BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+        .retrans_effort = BTM_ESCO_RETRANS_POWER,
+    },
+    /* ESCO CVSD */
+    {
+        .rx_bw = BTM_64KBITS_RATE,
+        .tx_bw = BTM_64KBITS_RATE,
+        .max_latency = 10,
+        .voice_contfmt = BTM_VOICE_SETTING_CVSD,
+        /* Allow controller to use all types available except 5-slot EDR */
+        .packet_types =
+            (BTM_SCO_LINK_ALL_PKT_MASK | BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+             BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+        .retrans_effort = BTM_ESCO_RETRANS_POWER,
+    },
+    /* ESCO mSBC */
+    {
+        .rx_bw = BTM_64KBITS_RATE,
+        .tx_bw = BTM_64KBITS_RATE,
+        .max_latency = 13,
+        .voice_contfmt = BTM_VOICE_SETTING_TRANS,
+        /* Packet Types : EV3 + 2-EV3               */
+        .packet_types =
+            (BTM_SCO_PKT_TYPES_MASK_EV3 | BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 |
+             BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+        .retrans_effort = BTM_ESCO_RETRANS_QUALITY,
+    }};
+
+enum {
+  BTA_HF_CLIENT_SCO_LISTEN_E,
+  BTA_HF_CLIENT_SCO_OPEN_E,       /* open request */
+  BTA_HF_CLIENT_SCO_CLOSE_E,      /* close request */
+  BTA_HF_CLIENT_SCO_SHUTDOWN_E,   /* shutdown request */
+  BTA_HF_CLIENT_SCO_CONN_OPEN_E,  /* sco opened */
+  BTA_HF_CLIENT_SCO_CONN_CLOSE_E, /* sco closed */
+};
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_remove_sco
+ *
+ * Description      Removes the specified SCO from the system.
+ *                  If only_active is true, then SCO is only removed if
+ *                  connected.
+ *
+ * Returns          bool   - true if SCO removal was started
+ *
+ ******************************************************************************/
+static bool bta_hf_client_sco_remove(bool only_active) {
+  bool removed_started = false;
+  tBTM_STATUS status;
+
+  APPL_TRACE_DEBUG("%s %d", __func__, only_active);
+
+  if (bta_hf_client_cb.scb.sco_idx != BTM_INVALID_SCO_INDEX) {
+    status = BTM_RemoveSco(bta_hf_client_cb.scb.sco_idx);
+
+    APPL_TRACE_DEBUG("%s idx 0x%04x, status:0x%x", __func__,
+                     bta_hf_client_cb.scb.sco_idx, status);
+
+    if (status == BTM_CMD_STARTED) {
+      removed_started = true;
+    }
+    /* If no connection reset the sco handle */
+    else if ((status == BTM_SUCCESS) || (status == BTM_UNKNOWN_ADDR)) {
+      bta_hf_client_cb.scb.sco_idx = BTM_INVALID_SCO_INDEX;
+    }
+  }
+  return removed_started;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_cback_sco
+ *
+ * Description      Call application callback function with SCO event.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_cback_sco(uint8_t event) {
+  tBTA_HF_CLIENT evt;
+
+  memset(&evt, 0, sizeof(evt));
+
+  /* call app cback */
+  (*bta_hf_client_cb.p_cback)(event, (tBTA_HF_CLIENT*)&evt);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_sco_conn_rsp
+ *
+ * Description      Process the SCO connection request
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hf_client_sco_conn_rsp(tBTM_ESCO_CONN_REQ_EVT_DATA* p_data) {
+  tBTM_ESCO_PARAMS resp;
+  uint8_t hci_status = HCI_SUCCESS;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  if (bta_hf_client_cb.scb.sco_state == BTA_HF_CLIENT_SCO_LISTEN_ST) {
+    if (p_data->link_type == BTM_LINK_TYPE_SCO) {
+      resp = bta_hf_client_esco_params[0];
+    } else {
+      resp = bta_hf_client_esco_params[bta_hf_client_cb.scb.negotiated_codec];
+    }
+
+    /* tell sys to stop av if any */
+    bta_sys_sco_use(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+  } else {
+    hci_status = HCI_ERR_HOST_REJECT_DEVICE;
+  }
+
+  BTM_EScoConnRsp(p_data->sco_inx, hci_status, &resp);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_sco_connreq_cback
+ *
+ * Description      BTM eSCO connection requests and eSCO change requests
+ *                  Only the connection requests are processed by BTA.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hf_client_esco_connreq_cback(tBTM_ESCO_EVT event,
+                                             tBTM_ESCO_EVT_DATA* p_data) {
+  APPL_TRACE_DEBUG("%s %d", __func__, event);
+
+  if (event != BTM_ESCO_CONN_REQ_EVT) {
+    return;
+  }
+
+  /* TODO check remote bdaddr, should allow connect only from device with
+   * active SLC  */
+
+  bta_hf_client_cb.scb.sco_idx = p_data->conn_evt.sco_inx;
+
+  bta_hf_client_sco_conn_rsp(&p_data->conn_evt);
+
+  bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_sco_conn_cback
+ *
+ * Description      BTM SCO connection callback.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hf_client_sco_conn_cback(uint16_t sco_idx) {
+  uint8_t* rem_bd;
+
+  APPL_TRACE_DEBUG("%s %d", __func__, sco_idx);
+
+  rem_bd = BTM_ReadScoBdAddr(sco_idx);
+
+  if (rem_bd && bdcmp(bta_hf_client_cb.scb.peer_addr, rem_bd) == 0 &&
+      bta_hf_client_cb.scb.svc_conn &&
+      bta_hf_client_cb.scb.sco_idx == sco_idx) {
+    BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+    p_buf->event = BTA_HF_CLIENT_SCO_OPEN_EVT;
+    p_buf->layer_specific = bta_hf_client_cb.scb.conn_handle;
+    bta_sys_sendmsg(p_buf);
+  }
+  /* no match found; disconnect sco, init sco variables */
+  else {
+    /* should not force the sco state to shutdown state here */
+    BTM_RemoveSco(sco_idx);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_sco_disc_cback
+ *
+ * Description      BTM SCO disconnection callback.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hf_client_sco_disc_cback(uint16_t sco_idx) {
+  APPL_TRACE_DEBUG("%s %d", __func__, sco_idx);
+
+  if (bta_hf_client_cb.scb.sco_idx == sco_idx) {
+    BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+    p_buf->event = BTA_HF_CLIENT_SCO_CLOSE_EVT;
+    p_buf->layer_specific = bta_hf_client_cb.scb.conn_handle;
+    ;
+    bta_sys_sendmsg(p_buf);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_create_sco
+ *
+ * Description
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hf_client_sco_create(bool is_orig) {
+  tBTM_STATUS status;
+  uint8_t* p_bd_addr = NULL;
+  tBTM_ESCO_PARAMS params;
+
+  APPL_TRACE_DEBUG("%s %d", __func__, is_orig);
+
+  /* Make sure this sco handle is not already in use */
+  if (bta_hf_client_cb.scb.sco_idx != BTM_INVALID_SCO_INDEX) {
+    APPL_TRACE_WARNING("%s: Index 0x%04x already in use", __func__,
+                       bta_hf_client_cb.scb.sco_idx);
+    return;
+  }
+
+  params = bta_hf_client_esco_params[1];
+
+  /* if initiating set current scb and peer bd addr */
+  if (is_orig) {
+    /* Attempt to use eSCO if remote host supports HFP >= 1.5 */
+    if (bta_hf_client_cb.scb.peer_version >= HFP_VERSION_1_5 &&
+        !bta_hf_client_cb.scb.retry_with_sco_only) {
+      BTM_SetEScoMode(BTM_LINK_TYPE_ESCO, &params);
+      /* If ESCO or EDR ESCO, retry with SCO only in case of failure */
+      if ((params.packet_types & BTM_ESCO_LINK_ONLY_MASK) ||
+          !((params.packet_types &
+             ~(BTM_ESCO_LINK_ONLY_MASK | BTM_SCO_LINK_ONLY_MASK)) ^
+            BTA_HF_CLIENT_NO_EDR_ESCO)) {
+        bta_hf_client_cb.scb.retry_with_sco_only = true;
+        APPL_TRACE_API("Setting retry_with_sco_only to true");
+      }
+    } else {
+      if (bta_hf_client_cb.scb.retry_with_sco_only)
+        APPL_TRACE_API("retrying with SCO only");
+      bta_hf_client_cb.scb.retry_with_sco_only = false;
+
+      BTM_SetEScoMode(BTM_LINK_TYPE_SCO, &params);
+    }
+
+    /* tell sys to stop av if any */
+    bta_sys_sco_use(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+  } else {
+    bta_hf_client_cb.scb.retry_with_sco_only = false;
+  }
+
+  p_bd_addr = bta_hf_client_cb.scb.peer_addr;
+
+  status = BTM_CreateSco(
+      p_bd_addr, is_orig, params.packet_types, &bta_hf_client_cb.scb.sco_idx,
+      bta_hf_client_sco_conn_cback, bta_hf_client_sco_disc_cback);
+  if (status == BTM_CMD_STARTED && !is_orig) {
+    if (!BTM_RegForEScoEvts(bta_hf_client_cb.scb.sco_idx,
+                            bta_hf_client_esco_connreq_cback))
+      APPL_TRACE_DEBUG("%s SCO registration success", __func__);
+  }
+
+  APPL_TRACE_API("%s: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x",
+                 __func__, is_orig, bta_hf_client_cb.scb.sco_idx, status,
+                 params.packet_types);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_sco_event
+ *
+ * Description      Handle SCO events
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hf_client_sco_event(uint8_t event) {
+  APPL_TRACE_DEBUG("%s state: %d event: %d", __func__,
+                   bta_hf_client_cb.scb.sco_state, event);
+
+  switch (bta_hf_client_cb.scb.sco_state) {
+    case BTA_HF_CLIENT_SCO_SHUTDOWN_ST:
+      switch (event) {
+        case BTA_HF_CLIENT_SCO_LISTEN_E:
+          /* create sco listen connection */
+          bta_hf_client_sco_create(false);
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
+          break;
+
+        default:
+          APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_SHUTDOWN_ST: Ignoring event %d",
+                             event);
+          break;
+      }
+      break;
+
+    case BTA_HF_CLIENT_SCO_LISTEN_ST:
+      switch (event) {
+        case BTA_HF_CLIENT_SCO_LISTEN_E:
+          /* create sco listen connection (Additional channel) */
+          bta_hf_client_sco_create(false);
+          break;
+
+        case BTA_HF_CLIENT_SCO_OPEN_E:
+          /* remove listening connection */
+          bta_hf_client_sco_remove(false);
+
+          /* create sco connection to peer */
+          bta_hf_client_sco_create(true);
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
+          break;
+
+        case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+          /* remove listening connection */
+          bta_hf_client_sco_remove(false);
+
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
+          break;
+
+        case BTA_HF_CLIENT_SCO_CLOSE_E:
+          /* remove listening connection */
+          /* Ignore the event. We need to keep listening SCO for the active SLC
+           */
+          APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event %d",
+                             event);
+          break;
+
+        case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+          /* sco failed; create sco listen connection */
+          bta_hf_client_sco_create(false);
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
+          break;
+
+        default:
+          APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event %d",
+                             event);
+          break;
+      }
+      break;
+
+    case BTA_HF_CLIENT_SCO_OPENING_ST:
+      switch (event) {
+        case BTA_HF_CLIENT_SCO_CLOSE_E:
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPEN_CL_ST;
+          break;
+
+        case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
+          break;
+
+        case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPEN_ST;
+          break;
+
+        case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+          /* sco failed; create sco listen connection */
+          bta_hf_client_sco_create(false);
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
+          break;
+
+        default:
+          APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPENING_ST: Ignoring event %d",
+                             event);
+          break;
+      }
+      break;
+
+    case BTA_HF_CLIENT_SCO_OPEN_CL_ST:
+      switch (event) {
+        case BTA_HF_CLIENT_SCO_OPEN_E:
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
+          break;
+
+        case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
+          break;
+
+        case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
+          /* close sco connection */
+          bta_hf_client_sco_remove(true);
+
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
+          break;
+
+        case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+          /* sco failed; create sco listen connection */
+
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
+          break;
+
+        default:
+          APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_CL_ST: Ignoring event %d",
+                             event);
+          break;
+      }
+      break;
+
+    case BTA_HF_CLIENT_SCO_OPEN_ST:
+      switch (event) {
+        case BTA_HF_CLIENT_SCO_CLOSE_E:
+          /* close sco connection if active */
+          if (bta_hf_client_sco_remove(true)) {
+            bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
+          }
+          break;
+
+        case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+          /* remove all listening connections */
+          bta_hf_client_sco_remove(false);
+
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
+          break;
+
+        case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+          /* peer closed sco; create sco listen connection */
+          bta_hf_client_sco_create(false);
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
+          break;
+
+        default:
+          APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_ST: Ignoring event %d",
+                             event);
+          break;
+      }
+      break;
+
+    case BTA_HF_CLIENT_SCO_CLOSING_ST:
+      switch (event) {
+        case BTA_HF_CLIENT_SCO_OPEN_E:
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSE_OP_ST;
+          break;
+
+        case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
+          break;
+
+        case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+          /* peer closed sco; create sco listen connection */
+          bta_hf_client_sco_create(false);
+
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
+          break;
+
+        default:
+          APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSING_ST: Ignoring event %d",
+                             event);
+          break;
+      }
+      break;
+
+    case BTA_HF_CLIENT_SCO_CLOSE_OP_ST:
+      switch (event) {
+        case BTA_HF_CLIENT_SCO_CLOSE_E:
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
+          break;
+
+        case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
+          break;
+
+        case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+          /* open sco connection */
+          bta_hf_client_sco_create(true);
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
+          break;
+
+        default:
+          APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSE_OP_ST: Ignoring event %d",
+                             event);
+          break;
+      }
+      break;
+
+    case BTA_HF_CLIENT_SCO_SHUTTING_ST:
+      switch (event) {
+        case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
+          /* close sco connection; wait for conn close event */
+          bta_hf_client_sco_remove(true);
+          break;
+
+        case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
+          break;
+
+        case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+          bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
+          break;
+
+        default:
+          APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_SHUTTING_ST: Ignoring event %d",
+                             event);
+          break;
+      }
+      break;
+
+    default:
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_sco_listen
+ *
+ * Description      Initialize SCO listener
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_sco_listen(UNUSED_ATTR tBTA_HF_CLIENT_DATA* p_data) {
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_LISTEN_E);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_sco_shutdown
+ *
+ * Description
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_sco_shutdown(UNUSED_ATTR tBTA_HF_CLIENT_DATA* p_data) {
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_SHUTDOWN_E);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_sco_conn_open
+ *
+ * Description
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_sco_conn_open(UNUSED_ATTR tBTA_HF_CLIENT_DATA* p_data) {
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_CONN_OPEN_E);
+
+  bta_sys_sco_open(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+
+  if (bta_hf_client_cb.scb.negotiated_codec == BTM_SCO_CODEC_MSBC) {
+    bta_hf_client_cback_sco(BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT);
+  } else {
+    bta_hf_client_cback_sco(BTA_HF_CLIENT_AUDIO_OPEN_EVT);
+  }
+
+  bta_hf_client_cb.scb.retry_with_sco_only = false;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_sco_conn_close
+ *
+ * Description
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA* p_data) {
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  /* clear current scb */
+  bta_hf_client_cb.scb.sco_idx = BTM_INVALID_SCO_INDEX;
+
+  /* retry_with_sco_only, will be set only when initiator
+  ** and HFClient is first trying to establish an eSCO connection */
+  if (bta_hf_client_cb.scb.retry_with_sco_only &&
+      bta_hf_client_cb.scb.svc_conn) {
+    bta_hf_client_sco_create(true);
+  } else {
+    bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_CONN_CLOSE_E);
+
+    bta_sys_sco_close(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+
+    bta_sys_sco_unuse(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
+
+    /* call app callback */
+    bta_hf_client_cback_sco(BTA_HF_CLIENT_AUDIO_CLOSE_EVT);
+
+    if (bta_hf_client_cb.scb.sco_close_rfc == true) {
+      bta_hf_client_cb.scb.sco_close_rfc = false;
+      bta_hf_client_rfc_do_close(p_data);
+    }
+  }
+  bta_hf_client_cb.scb.retry_with_sco_only = false;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_sco_open
+ *
+ * Description
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_sco_open(UNUSED_ATTR tBTA_HF_CLIENT_DATA* p_data) {
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_OPEN_E);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_sco_close
+ *
+ * Description
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_sco_close(UNUSED_ATTR tBTA_HF_CLIENT_DATA* p_data) {
+  APPL_TRACE_DEBUG("%s  0x%x", __func__, bta_hf_client_cb.scb.sco_idx);
+
+  if (bta_hf_client_cb.scb.sco_idx != BTM_INVALID_SCO_INDEX) {
+    bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_CLOSE_E);
+  }
+}
diff --git a/bt/bta/hf_client/bta_hf_client_sdp.cc b/bt/bta/hf_client/bta_hf_client_sdp.cc
new file mode 100644
index 0000000..b4e063c
--- /dev/null
+++ b/bt/bta/hf_client/bta_hf_client_sdp.cc
@@ -0,0 +1,351 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-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 audio gateway functions performing SDP
+ *  operations.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_utils.h"
+#include "bta_api.h"
+#include "bta_hf_client_api.h"
+#include "bta_hf_client_int.h"
+#include "bta_sys.h"
+#include "osi/include/osi.h"
+
+/* Number of protocol elements in protocol element list. */
+#define BTA_HF_CLIENT_NUM_PROTO_ELEMS 2
+
+/* Number of elements in service class id list. */
+#define BTA_HF_CLIENT_NUM_SVC_ELEMS 2
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_sdp_cback
+ *
+ * Description      SDP callback function.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hf_client_sdp_cback(uint16_t status) {
+  uint16_t event;
+  tBTA_HF_CLIENT_DISC_RESULT* p_buf = (tBTA_HF_CLIENT_DISC_RESULT*)osi_malloc(
+      sizeof(tBTA_HF_CLIENT_DISC_RESULT));
+
+  APPL_TRACE_DEBUG("bta_hf_client_sdp_cback status:0x%x", status);
+
+  /* set event according to int/acp */
+  if (bta_hf_client_cb.scb.role == BTA_HF_CLIENT_ACP)
+    event = BTA_HF_CLIENT_DISC_ACP_RES_EVT;
+  else
+    event = BTA_HF_CLIENT_DISC_INT_RES_EVT;
+
+  p_buf->hdr.event = event;
+  p_buf->status = status;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/******************************************************************************
+ *
+ * Function         bta_hf_client_add_record
+ *
+ * Description      This function is called by a server application to add
+ *                  HFP Client information to an SDP record.  Prior to
+ *                  calling this function the application must call
+ *                  SDP_CreateRecord() to create an SDP record.
+ *
+ * Returns          true if function execution succeeded,
+ *                  false if function execution failed.
+ *
+ *****************************************************************************/
+bool bta_hf_client_add_record(char* p_service_name, uint8_t scn,
+                              tBTA_HF_CLIENT_FEAT features,
+                              uint32_t sdp_handle) {
+  tSDP_PROTOCOL_ELEM proto_elem_list[BTA_HF_CLIENT_NUM_PROTO_ELEMS];
+  uint16_t svc_class_id_list[BTA_HF_CLIENT_NUM_SVC_ELEMS];
+  uint16_t browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
+  uint16_t version;
+  uint16_t profile_uuid;
+  bool result = true;
+  uint8_t buf[2];
+  uint16_t sdp_features = 0;
+
+  APPL_TRACE_DEBUG("bta_hf_client_add_record");
+
+  memset(proto_elem_list, 0,
+         BTA_HF_CLIENT_NUM_PROTO_ELEMS * sizeof(tSDP_PROTOCOL_ELEM));
+
+  /* add the protocol element sequence */
+  proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+  proto_elem_list[0].num_params = 0;
+  proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+  proto_elem_list[1].num_params = 1;
+  proto_elem_list[1].params[0] = scn;
+  result &= SDP_AddProtocolList(sdp_handle, BTA_HF_CLIENT_NUM_PROTO_ELEMS,
+                                proto_elem_list);
+
+  /* add service class id list */
+  svc_class_id_list[0] = UUID_SERVCLASS_HF_HANDSFREE;
+  svc_class_id_list[1] = UUID_SERVCLASS_GENERIC_AUDIO;
+  result &= SDP_AddServiceClassIdList(sdp_handle, BTA_HF_CLIENT_NUM_SVC_ELEMS,
+                                      svc_class_id_list);
+
+  /* add profile descriptor list */
+  profile_uuid = UUID_SERVCLASS_HF_HANDSFREE;
+  version = HFP_VERSION_1_6;
+
+  result &= SDP_AddProfileDescriptorList(sdp_handle, profile_uuid, version);
+
+  /* add service name */
+  if (p_service_name != NULL && p_service_name[0] != 0) {
+    result &= SDP_AddAttribute(
+        sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+        (uint32_t)(strlen(p_service_name) + 1), (uint8_t*)p_service_name);
+  }
+
+  /* add features */
+  if (features & BTA_HF_CLIENT_FEAT_ECNR)
+    sdp_features |= BTA_HF_CLIENT_FEAT_ECNR;
+
+  if (features & BTA_HF_CLIENT_FEAT_3WAY)
+    sdp_features |= BTA_HF_CLIENT_FEAT_3WAY;
+
+  if (features & BTA_HF_CLIENT_FEAT_CLI) sdp_features |= BTA_HF_CLIENT_FEAT_CLI;
+
+  if (features & BTA_HF_CLIENT_FEAT_VREC)
+    sdp_features |= BTA_HF_CLIENT_FEAT_VREC;
+
+  if (features & BTA_HF_CLIENT_FEAT_VOL) sdp_features |= BTA_HF_CLIENT_FEAT_VOL;
+
+  /* Codec bit position is different in SDP (bit 5) and in BRSF (bit 7) */
+  if (features & BTA_HF_CLIENT_FEAT_CODEC) sdp_features |= 0x0020;
+
+  UINT16_TO_BE_FIELD(buf, sdp_features);
+  result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES,
+                             UINT_DESC_TYPE, 2, buf);
+
+  /* add browse group list */
+  result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1,
+                                browse_list);
+
+  return result;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_create_record
+ *
+ * Description      Create SDP record for registered service.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_create_record(tBTA_HF_CLIENT_DATA* p_data) {
+  /* add sdp record if not already registered */
+  if (bta_hf_client_cb.sdp_handle == 0) {
+    bta_hf_client_cb.sdp_handle = SDP_CreateRecord();
+    bta_hf_client_cb.scn = BTM_AllocateSCN();
+    bta_hf_client_add_record(p_data->api_register.name, bta_hf_client_cb.scn,
+                             p_data->api_register.features,
+                             bta_hf_client_cb.sdp_handle);
+
+    bta_sys_add_uuid(UUID_SERVCLASS_HF_HANDSFREE);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_del_record
+ *
+ * Description      Delete SDP record for registered service.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_del_record(UNUSED_ATTR tBTA_HF_CLIENT_DATA* p_data) {
+  APPL_TRACE_DEBUG("bta_hf_client_del_record");
+
+  if (bta_hf_client_cb.sdp_handle != 0) {
+    SDP_DeleteRecord(bta_hf_client_cb.sdp_handle);
+    bta_hf_client_cb.sdp_handle = 0;
+    BTM_FreeSCN(bta_hf_client_cb.scn);
+    BTM_SecClrService(BTM_SEC_SERVICE_HF_HANDSFREE);
+    bta_sys_remove_uuid(UUID_SERVCLASS_HF_HANDSFREE);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_sdp_find_attr
+ *
+ * Description      Process SDP discovery results to find requested attribute
+ *
+ *
+ * Returns          true if results found, false otherwise.
+ *
+ ******************************************************************************/
+bool bta_hf_client_sdp_find_attr(void) {
+  tSDP_DISC_REC* p_rec = NULL;
+  tSDP_DISC_ATTR* p_attr;
+  tSDP_PROTOCOL_ELEM pe;
+  bool result = false;
+
+  bta_hf_client_cb.scb.peer_version = HFP_VERSION_1_1; /* Default version */
+
+  /* loop through all records we found */
+  while (true) {
+    /* get next record; if none found, we're done */
+    if ((p_rec = SDP_FindServiceInDb(bta_hf_client_cb.scb.p_disc_db,
+                                     UUID_SERVCLASS_AG_HANDSFREE, p_rec)) ==
+        NULL) {
+      break;
+    }
+
+    /* get scn from proto desc list if initiator */
+    if (bta_hf_client_cb.scb.role == BTA_HF_CLIENT_INT) {
+      if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+        bta_hf_client_cb.scb.peer_scn = (uint8_t)pe.params[0];
+      } else {
+        continue;
+      }
+    }
+
+    /* get profile version (if failure, version parameter is not updated) */
+    SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_HF_HANDSFREE,
+                                &bta_hf_client_cb.scb.peer_version);
+
+    /* get features */
+    if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES)) !=
+        NULL) {
+      /* Found attribute. Get value. */
+      /* There might be race condition between SDP and BRSF.  */
+      /* Do not update if we already received BRSF.           */
+      if (bta_hf_client_cb.scb.peer_features == 0) {
+        bta_hf_client_cb.scb.peer_features = p_attr->attr_value.v.u16;
+
+        /* SDP and BRSF WBS bit are different, correct it if set */
+        if (bta_hf_client_cb.scb.peer_features & 0x0020) {
+          bta_hf_client_cb.scb.peer_features &= ~0x0020;
+          bta_hf_client_cb.scb.peer_features |= BTA_HF_CLIENT_PEER_CODEC;
+        }
+
+        /* get network for ability to reject calls */
+        if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_NETWORK)) != NULL) {
+          if (p_attr->attr_value.v.u16 == 0x01) {
+            bta_hf_client_cb.scb.peer_features |= BTA_HF_CLIENT_PEER_REJECT;
+          }
+        }
+      }
+    }
+
+    /* found what we needed */
+    result = true;
+    break;
+  }
+
+  APPL_TRACE_DEBUG("%s peer_version=0x%x peer_features=0x%x", __func__,
+                   bta_hf_client_cb.scb.peer_version,
+                   bta_hf_client_cb.scb.peer_features);
+
+  return result;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_do_disc
+ *
+ * Description      Do service discovery.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_do_disc(void) {
+  tSDP_UUID uuid_list[2];
+  uint16_t num_uuid = 1;
+  uint16_t attr_list[4];
+  uint8_t num_attr;
+  bool db_inited = false;
+
+  /* initiator; get proto list and features */
+  if (bta_hf_client_cb.scb.role == BTA_HF_CLIENT_INT) {
+    attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+    attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+    attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
+    attr_list[3] = ATTR_ID_SUPPORTED_FEATURES;
+    num_attr = 4;
+    uuid_list[0].uu.uuid16 = UUID_SERVCLASS_AG_HANDSFREE;
+  }
+  /* acceptor; get features */
+  else {
+    attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+    attr_list[1] = ATTR_ID_BT_PROFILE_DESC_LIST;
+    attr_list[2] = ATTR_ID_SUPPORTED_FEATURES;
+    num_attr = 3;
+    uuid_list[0].uu.uuid16 = UUID_SERVCLASS_AG_HANDSFREE;
+  }
+
+  /* allocate buffer for sdp database */
+  bta_hf_client_cb.scb.p_disc_db =
+      (tSDP_DISCOVERY_DB*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+
+  /* set up service discovery database; attr happens to be attr_list len */
+  uuid_list[0].len = LEN_UUID_16;
+  uuid_list[1].len = LEN_UUID_16;
+  db_inited = SDP_InitDiscoveryDb(bta_hf_client_cb.scb.p_disc_db,
+                                  BT_DEFAULT_BUFFER_SIZE, num_uuid, uuid_list,
+                                  num_attr, attr_list);
+
+  if (db_inited) {
+    /*Service discovery not initiated */
+    db_inited = SDP_ServiceSearchAttributeRequest(
+        bta_hf_client_cb.scb.peer_addr, bta_hf_client_cb.scb.p_disc_db,
+        bta_hf_client_sdp_cback);
+  }
+
+  if (!db_inited) {
+    /*free discover db */
+    bta_hf_client_free_db(NULL);
+    /* sent failed event */
+    bta_hf_client_sm_execute(BTA_HF_CLIENT_DISC_FAIL_EVT, NULL);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hf_client_free_db
+ *
+ * Description      Free discovery database.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hf_client_free_db(UNUSED_ATTR tBTA_HF_CLIENT_DATA* p_data) {
+  osi_free_and_reset((void**)&bta_hf_client_cb.scb.p_disc_db);
+}
diff --git a/bt/bta/hh/bta_hh_act.cc b/bt/bta/hh/bta_hh_act.cc
new file mode 100644
index 0000000..6240211
--- /dev/null
+++ b/bt/bta/hh/bta_hh_act.cc
@@ -0,0 +1,1228 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2005-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 HID host action functions.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if (BTA_HH_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bta_hh_co.h"
+#include "bta_hh_int.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+#include "l2c_api.h"
+#include "osi/include/osi.h"
+#include "utl.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+/*****************************************************************************
+ *  Local Function prototypes
+ ****************************************************************************/
+static void bta_hh_cback(uint8_t dev_handle, BD_ADDR addr, uint8_t event,
+                         uint32_t data, BT_HDR* pdata);
+static tBTA_HH_STATUS bta_hh_get_trans_status(uint32_t result);
+
+#if (BTA_HH_DEBUG == TRUE)
+static const char* bta_hh_get_w4_event(uint16_t event);
+static const char* bta_hh_hid_event_name(uint16_t event);
+#endif
+
+/*****************************************************************************
+ *  Action Functions
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function         bta_hh_api_enable
+ *
+ * Description      Perform necessary operations to enable HID host.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_api_enable(tBTA_HH_DATA* p_data) {
+  tBTA_HH_STATUS status = BTA_HH_ERR;
+  uint8_t xx;
+
+  /* initialize BTE HID */
+  HID_HostInit();
+
+  memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB));
+
+  HID_HostSetSecurityLevel("", p_data->api_enable.sec_mask);
+
+  /* Register with L2CAP */
+  if (HID_HostRegister(bta_hh_cback) == HID_SUCCESS) {
+    /* store parameters */
+    bta_hh_cb.p_cback = p_data->api_enable.p_cback;
+
+    status = BTA_HH_OK;
+    /* initialize device CB */
+    for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) {
+      bta_hh_cb.kdev[xx].state = BTA_HH_IDLE_ST;
+      bta_hh_cb.kdev[xx].hid_handle = BTA_HH_INVALID_HANDLE;
+      bta_hh_cb.kdev[xx].index = xx;
+    }
+
+    /* initialize control block map */
+    for (xx = 0; xx < BTA_HH_MAX_KNOWN; xx++)
+      bta_hh_cb.cb_index[xx] = BTA_HH_IDX_INVALID;
+  }
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+  if (status == BTA_HH_OK) {
+    bta_hh_le_enable();
+  } else
+#endif
+    /* signal BTA call back event */
+    (*bta_hh_cb.p_cback)(BTA_HH_ENABLE_EVT, (tBTA_HH*)&status);
+}
+/*******************************************************************************
+ *
+ * Function         bta_hh_api_disable
+ *
+ * Description      Perform necessary operations to disable HID host.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_api_disable(void) {
+  uint8_t xx;
+
+  /* service is not enabled */
+  if (bta_hh_cb.p_cback == NULL) return;
+
+  /* no live connection, signal DISC_CMPL_EVT directly */
+  if (!bta_hh_cb.cnt_num) {
+    bta_hh_disc_cmpl();
+  } else /* otherwise, disconnect all live connections */
+  {
+    bta_hh_cb.w4_disable = true;
+
+    for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) {
+      /* send API_CLOSE event to every connected device */
+      if (bta_hh_cb.kdev[xx].state == BTA_HH_CONN_ST) {
+        /* disconnect all connected devices */
+        bta_hh_sm_execute(&bta_hh_cb.kdev[xx], BTA_HH_API_CLOSE_EVT, NULL);
+      }
+    }
+  }
+
+  return;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_disc_cmpl
+ *
+ * Description      All connections have been closed, disable service.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_disc_cmpl(void) {
+#if (BTA_HH_LE_INCLUDED == TRUE)
+  HID_HostDeregister();
+  bta_hh_le_deregister();
+#else
+  tBTA_HH_STATUS status = BTA_HH_OK;
+
+  /* Deregister with lower layer */
+  if (HID_HostDeregister() != HID_SUCCESS) status = BTA_HH_ERR;
+
+  bta_hh_cleanup_disable(status);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_sdp_cback
+ *
+ * Description      SDP callback function.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hh_sdp_cback(uint16_t result, uint16_t attr_mask,
+                             tHID_DEV_SDP_INFO* sdp_rec) {
+  tBTA_HH_DEV_CB* p_cb = bta_hh_cb.p_cur;
+  uint8_t hdl = 0;
+  tBTA_HH_STATUS status = BTA_HH_ERR_SDP;
+
+  /* make sure sdp succeeded and hh has not been disabled */
+  if ((result == SDP_SUCCESS) && (p_cb != NULL)) {
+    /* security is required for the connection, add attr_mask bit*/
+    if (p_cb->sec_mask) attr_mask |= HID_SEC_REQUIRED;
+
+#if (BTA_HH_DEBUG == TRUE)
+    APPL_TRACE_EVENT(
+        "bta_hh_sdp_cback: p_cb: %d result 0x%02x, \
+                            attr_mask 0x%02x, handle %x",
+        p_cb, result, attr_mask, p_cb->hid_handle);
+#endif
+
+    /* check to see type of device is supported , and should not been added
+     * before */
+    if (bta_hh_tod_spt(p_cb, sdp_rec->sub_class)) {
+      /* if not added before */
+      if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) {
+        /*  add device/update attr_mask information */
+        if (HID_HostAddDev(p_cb->addr, attr_mask, &hdl) == HID_SUCCESS) {
+          status = BTA_HH_OK;
+          /* update cb_index[] map */
+          bta_hh_cb.cb_index[hdl] = p_cb->index;
+        } else {
+          p_cb->app_id = 0;
+        }
+      } else {
+        hdl = p_cb->hid_handle;
+      }
+      /* else : incoming connection after SDP should update the SDP information
+       * as well */
+
+      if (p_cb->app_id != 0) {
+        /* update cb information with attr_mask, dscp_info etc. */
+        bta_hh_add_device_to_list(p_cb, hdl, attr_mask, &sdp_rec->dscp_info,
+                                  sdp_rec->sub_class, sdp_rec->ssr_max_latency,
+                                  sdp_rec->ssr_min_tout, p_cb->app_id);
+
+        p_cb->dscp_info.ctry_code = sdp_rec->ctry_code;
+
+        status = BTA_HH_OK;
+      }
+
+    } else /* type of device is not supported */
+      status = BTA_HH_ERR_TOD_UNSPT;
+  }
+
+  /* free disc_db when SDP is completed */
+  osi_free_and_reset((void**)&bta_hh_cb.p_disc_db);
+
+  /* send SDP_CMPL_EVT into state machine */
+  bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA*)&status);
+
+  return;
+}
+/*******************************************************************************
+ *
+ * Function         bta_hh_di_sdp_cback
+ *
+ * Description      SDP DI callback function.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hh_di_sdp_cback(uint16_t result) {
+  tBTA_HH_DEV_CB* p_cb = bta_hh_cb.p_cur;
+  tBTA_HH_STATUS status = BTA_HH_ERR_SDP;
+  tSDP_DI_GET_RECORD di_rec;
+  tHID_STATUS ret;
+#if (BTA_HH_DEBUG == TRUE)
+  APPL_TRACE_EVENT("bta_hh_di_sdp_cback: p_cb: %d result 0x%02x", p_cb, result);
+#endif
+
+  /* if DI record does not exist on remote device, vendor_id in
+   * tBTA_HH_DEV_DSCP_INFO will be
+       * set to 0xffff and we will allow the connection to go through. Spec
+   * mandates that DI
+       * record be set, but many HID devices do not set this. So for IOP
+   * purposes, we allow the
+       * connection to go through and update the DI record to invalid DI
+   * entry.*/
+  if (((result == SDP_SUCCESS) || (result == SDP_NO_RECS_MATCH)) &&
+      (p_cb != NULL)) {
+    if (result == SDP_SUCCESS &&
+        SDP_GetNumDiRecords(bta_hh_cb.p_disc_db) != 0) {
+      /* always update information with primary DI record */
+      if (SDP_GetDiRecord(1, &di_rec, bta_hh_cb.p_disc_db) == SDP_SUCCESS) {
+        bta_hh_update_di_info(p_cb, di_rec.rec.vendor, di_rec.rec.product,
+                              di_rec.rec.version, 0);
+      }
+
+    } else /* no DI recrod available */
+    {
+      bta_hh_update_di_info(p_cb, BTA_HH_VENDOR_ID_INVALID, 0, 0, 0);
+    }
+
+    if ((ret = HID_HostGetSDPRecord(p_cb->addr, bta_hh_cb.p_disc_db,
+                                    p_bta_hh_cfg->sdp_db_size,
+                                    bta_hh_sdp_cback)) == HID_SUCCESS) {
+      status = BTA_HH_OK;
+    } else {
+#if (BTA_HH_DEBUG == TRUE)
+      APPL_TRACE_DEBUG(
+          "bta_hh_di_sdp_cback:  HID_HostGetSDPRecord failed: Status 0x%2x",
+          ret);
+#endif
+    }
+  }
+
+  if (status != BTA_HH_OK) {
+    osi_free_and_reset((void**)&bta_hh_cb.p_disc_db);
+    /* send SDP_CMPL_EVT into state machine */
+    bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA*)&status);
+  }
+  return;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_start_sdp
+ *
+ * Description      Start SDP service search, and obtain necessary SDP records.
+ *                  Only one SDP service search request is allowed at the same
+ *                  time. For every BTA_HhOpen API call, do SDP first unless SDP
+ *                  has been done previously.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_start_sdp(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+  tBTA_HH_STATUS status = BTA_HH_ERR_SDP;
+  uint8_t hdl;
+
+  p_cb->sec_mask = p_data->api_conn.sec_mask;
+  p_cb->mode = p_data->api_conn.mode;
+  bta_hh_cb.p_cur = p_cb;
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+  if (bta_hh_is_le_device(p_cb, p_data->api_conn.bd_addr)) {
+    bta_hh_le_open_conn(p_cb, p_data->api_conn.bd_addr);
+    return;
+  }
+#endif
+
+  /* if previously virtually cabled device, skip SDP */
+  if (p_cb->app_id) {
+    status = BTA_HH_OK;
+#if (BTA_HH_DEBUG == TRUE)
+    APPL_TRACE_DEBUG("bta_hh_start_sdp:: skip SDP for known devices");
+#endif
+    if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) {
+      if (HID_HostAddDev(p_cb->addr, p_cb->attr_mask, &hdl) == HID_SUCCESS) {
+        /* update device CB with newly register device handle */
+        bta_hh_add_device_to_list(p_cb, hdl, p_cb->attr_mask, NULL,
+                                  p_cb->sub_class,
+                                  p_cb->dscp_info.ssr_max_latency,
+                                  p_cb->dscp_info.ssr_min_tout, p_cb->app_id);
+        /* update cb_index[] map */
+        bta_hh_cb.cb_index[hdl] = p_cb->index;
+      } else
+        status = BTA_HH_ERR_NO_RES;
+    }
+    bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA*)&status);
+
+    return;
+  }
+  /* GetSDPRecord. at one time only one SDP precedure can be active */
+  else if (!bta_hh_cb.p_disc_db) {
+    bta_hh_cb.p_disc_db =
+        (tSDP_DISCOVERY_DB*)osi_malloc(p_bta_hh_cfg->sdp_db_size);
+    bta_hh_cb.p_cur = p_cb;
+    /* do DI discovery first */
+    if (SDP_DiDiscover(p_data->api_conn.bd_addr, bta_hh_cb.p_disc_db,
+                       p_bta_hh_cfg->sdp_db_size,
+                       bta_hh_di_sdp_cback) != SDP_SUCCESS) {
+#if (BTA_HH_DEBUG == TRUE)
+      APPL_TRACE_DEBUG(
+          "bta_hh_start_sdp:  SDP_DiDiscover failed: \
+                    Status 0x%2X",
+          status);
+#endif
+      status = BTA_HH_ERR_SDP;
+      osi_free_and_reset((void**)&bta_hh_cb.p_disc_db);
+    } else {
+      status = BTA_HH_OK;
+    }
+  } else if (bta_hh_cb.p_disc_db) {
+    /* It is possible that there is incoming/outgoing collision case. DUT
+     * initiated
+     * HID connection at same time remote has connected L2CAP for HID control,
+     * so SDP would be in progress, when this flow reaches here. Just do nothing
+     * when the code reaches here, and ongoing SDP completion or failure will
+     * handle this case.
+     */
+    APPL_TRACE_DEBUG("%s: ignoring as SDP already in progress", __func__);
+    return;
+  }
+
+  if (status != BTA_HH_OK)
+    bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA*)&status);
+
+  return;
+}
+/*******************************************************************************
+ *
+ * Function         bta_hh_sdp_cmpl
+ *
+ * Description      When SDP completes, initiate a connection or report an error
+ *                  depending on the SDP result.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+  tBTA_HH_CONN conn_dat;
+  tBTA_HH_STATUS status = p_data->status;
+
+#if (BTA_HH_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hh_sdp_cmpl:  status 0x%2X", p_data->status);
+#endif
+
+  /* initialize call back data */
+  memset((void*)&conn_dat, 0, sizeof(tBTA_HH_CONN));
+  conn_dat.handle = p_cb->hid_handle;
+  bdcpy(conn_dat.bda, p_cb->addr);
+
+  /* if SDP compl success */
+  if (status == BTA_HH_OK) {
+    /* not incoming connection doing SDP, initiate a HID connection */
+    if (!p_cb->incoming_conn) {
+      tHID_STATUS ret;
+      /* set security level */
+      HID_HostSetSecurityLevel("", p_cb->sec_mask);
+
+      /* open HID connection */
+      ret = HID_HostOpenDev(p_cb->hid_handle);
+      APPL_TRACE_DEBUG("%s: HID_HostOpenDev returned=%d", __func__, ret);
+      if (ret == HID_SUCCESS || ret == HID_ERR_ALREADY_CONN) {
+        status = BTA_HH_OK;
+      } else if (ret == HID_ERR_CONN_IN_PROCESS) {
+        /* Connection already in progress, return from here, SDP
+         * will be performed after connection is completed.
+         */
+        APPL_TRACE_DEBUG("%s: connection already in progress", __func__);
+        return;
+      } else {
+#if (BTA_HH_DEBUG == TRUE)
+        APPL_TRACE_DEBUG("%s: HID_HostOpenDev failed: Status 0x%2X", __func__,
+                         ret);
+#endif
+        /* open fail, remove device from management device list */
+        HID_HostRemoveDev(p_cb->hid_handle);
+        status = BTA_HH_ERR;
+      }
+    } else /* incoming connection SDP finish */
+    {
+      bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, NULL);
+    }
+  }
+
+  if (status != BTA_HH_OK) {
+    /* Check if this was incoming connection request  from an unknown device
+       **and connection failed due to missing HID Device SDP UUID
+       **In above condition, disconnect the link as well as remove the
+       **device from list of HID devices*/
+    if ((status == BTA_HH_ERR_SDP) && (p_cb->incoming_conn) &&
+        (p_cb->app_id == 0)) {
+      APPL_TRACE_DEBUG("bta_hh_sdp_cmpl:SDP failed for  incoming conn :hndl %d",
+                       p_cb->incoming_hid_handle);
+      HID_HostRemoveDev(p_cb->incoming_hid_handle);
+    }
+    conn_dat.status = status;
+    (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH*)&conn_dat);
+
+    /* move state machine W4_CONN ->IDLE */
+    bta_hh_sm_execute(p_cb, BTA_HH_API_CLOSE_EVT, NULL);
+
+    /* if this is an outgoing connection to an unknown device, clean up cb */
+    if (p_cb->app_id == 0 && !p_cb->incoming_conn) {
+      /* clean up device control block */
+      bta_hh_clean_up_kdev(p_cb);
+    }
+#if (BTA_HH_DEBUG == TRUE)
+    bta_hh_trace_dev_db();
+#endif
+  }
+  return;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_api_disc_act
+ *
+ * Description      HID Host initiate a disconnection.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_api_disc_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+  tBTA_HH_CBDATA disc_dat;
+  tHID_STATUS status;
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+  if (p_cb->is_le_device)
+    bta_hh_le_api_disc_act(p_cb);
+  else
+#endif
+  {
+    /* found an active connection */
+    disc_dat.handle =
+        p_data ? (uint8_t)p_data->hdr.layer_specific : p_cb->hid_handle;
+    disc_dat.status = BTA_HH_ERR;
+
+    status = HID_HostCloseDev(disc_dat.handle);
+
+    if (status) (*bta_hh_cb.p_cback)(BTA_HH_CLOSE_EVT, (tBTA_HH*)&disc_dat);
+  }
+
+  return;
+}
+/*******************************************************************************
+ *
+ * Function         bta_hh_open_cmpl_act
+ *
+ * Description      HID host connection completed
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+  tBTA_HH_CONN conn;
+  uint8_t dev_handle =
+      p_data ? (uint8_t)p_data->hid_cback.hdr.layer_specific : p_cb->hid_handle;
+
+  memset((void*)&conn, 0, sizeof(tBTA_HH_CONN));
+  conn.handle = dev_handle;
+  bdcpy(conn.bda, p_cb->addr);
+
+  /* increase connection number */
+  bta_hh_cb.cnt_num++;
+
+  /* initialize device driver */
+  bta_hh_co_open(p_cb->hid_handle, p_cb->sub_class, p_cb->attr_mask,
+                 p_cb->app_id);
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+  conn.status = p_cb->status;
+  conn.le_hid = p_cb->is_le_device;
+  conn.scps_supported = p_cb->scps_supported;
+
+  if (!p_cb->is_le_device)
+#endif
+  {
+    /* inform role manager */
+    bta_sys_conn_open(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+  }
+  /* set protocol mode when not default report mode */
+  if (p_cb->mode != BTA_HH_PROTO_RPT_MODE
+#if (BTA_HH_LE_INCLUDED == TRUE)
+      && !p_cb->is_le_device
+#endif
+      ) {
+    if ((HID_HostWriteDev(dev_handle, HID_TRANS_SET_PROTOCOL,
+                          HID_PAR_PROTOCOL_BOOT_MODE, 0, 0, NULL)) !=
+        HID_SUCCESS) {
+      /* HID connection is up, while SET_PROTO fail */
+      conn.status = BTA_HH_ERR_PROTO;
+      (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH*)&conn);
+    } else {
+      conn.status = BTA_HH_OK;
+      p_cb->w4_evt = BTA_HH_OPEN_EVT;
+    }
+  } else
+    (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH*)&conn);
+
+  p_cb->incoming_conn = false;
+  p_cb->incoming_hid_handle = BTA_HH_INVALID_HANDLE;
+}
+/*******************************************************************************
+ *
+ * Function         bta_hh_open_act
+ *
+ * Description      HID host receive HID_OPEN_EVT .
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_open_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+  tBTA_HH_API_CONN conn_data;
+
+  uint8_t dev_handle =
+      p_data ? (uint8_t)p_data->hid_cback.hdr.layer_specific : p_cb->hid_handle;
+
+#if (BTA_HH_DEBUG == TRUE)
+  APPL_TRACE_EVENT("bta_hh_open_act:  Device[%d] connected", dev_handle);
+#endif
+
+  /* SDP has been done */
+  if (p_cb->app_id != 0) {
+    bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, p_data);
+  } else
+  /*  app_id == 0 indicates an incoming conenction request arrives without SDP
+      performed, do it first */
+  {
+    p_cb->incoming_conn = true;
+    /* store the handle here in case sdp fails - need to disconnect */
+    p_cb->incoming_hid_handle = dev_handle;
+
+    memset(&conn_data, 0, sizeof(tBTA_HH_API_CONN));
+    bdcpy(conn_data.bd_addr, p_cb->addr);
+    bta_hh_start_sdp(p_cb, (tBTA_HH_DATA*)&conn_data);
+  }
+
+  return;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_data_act
+ *
+ * Description      HID Host process a data report
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_data_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+  BT_HDR* pdata = p_data->hid_cback.p_data;
+  uint8_t* p_rpt = (uint8_t*)(pdata + 1) + pdata->offset;
+
+  bta_hh_co_data((uint8_t)p_data->hid_cback.hdr.layer_specific, p_rpt,
+                 pdata->len, p_cb->mode, p_cb->sub_class,
+                 p_cb->dscp_info.ctry_code, p_cb->addr, p_cb->app_id);
+
+  osi_free_and_reset((void**)&pdata);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_handsk_act
+ *
+ * Description      HID Host process a handshake acknoledgement.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_handsk_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+  tBTA_HH_CBDATA cback_data;
+  tBTA_HH_HSDATA hs_data;
+  tBTA_HH_CONN conn;
+
+#if (BTA_HH_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("HANDSHAKE received for: event = %s data= %d",
+                   bta_hh_get_w4_event(p_cb->w4_evt), p_data->hid_cback.data);
+#endif
+
+  memset(&hs_data, 0, sizeof(tBTA_HH_HSDATA));
+  memset(&cback_data, 0, sizeof(tBTA_HH_CBDATA));
+
+  switch (p_cb->w4_evt) {
+    /* GET_ transsaction, handshake indicate unsupported request */
+    case BTA_HH_GET_PROTO_EVT:
+      hs_data.rsp_data.proto_mode = BTA_HH_PROTO_UNKNOWN;
+    /* fall through */
+    case BTA_HH_GET_RPT_EVT:
+    case BTA_HH_GET_IDLE_EVT:
+      hs_data.handle = p_cb->hid_handle;
+      /* if handshake gives an OK code for these transaction, fill in UNSUPT */
+      if ((hs_data.status = bta_hh_get_trans_status(p_data->hid_cback.data)) ==
+          BTA_HH_OK)
+        hs_data.status = BTA_HH_HS_TRANS_NOT_SPT;
+
+      (*bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH*)&hs_data);
+      p_cb->w4_evt = 0;
+      break;
+
+    /* acknoledgement from HID device for SET_ transaction */
+    case BTA_HH_SET_RPT_EVT:
+    case BTA_HH_SET_PROTO_EVT:
+    case BTA_HH_SET_IDLE_EVT:
+      cback_data.handle = p_cb->hid_handle;
+      cback_data.status = bta_hh_get_trans_status(p_data->hid_cback.data);
+      (*bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH*)&cback_data);
+      p_cb->w4_evt = 0;
+      break;
+
+    /* SET_PROTOCOL when open connection */
+    case BTA_HH_OPEN_EVT:
+      conn.status = p_data->hid_cback.data ? BTA_HH_ERR_PROTO : BTA_HH_OK;
+      conn.handle = p_cb->hid_handle;
+      bdcpy(conn.bda, p_cb->addr);
+      (*bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH*)&conn);
+#if (BTA_HH_DEBUG == TRUE)
+      bta_hh_trace_dev_db();
+#endif
+      p_cb->w4_evt = 0;
+      break;
+
+    default:
+      /* unknow transaction handshake response */
+      APPL_TRACE_DEBUG("unknown transaction type");
+      break;
+  }
+
+  /* transaction achknoledgement received, inform PM for mode change */
+  bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+  return;
+}
+/*******************************************************************************
+ *
+ * Function         bta_hh_ctrl_dat_act
+ *
+ * Description      HID Host process a data report from control channel.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+  BT_HDR* pdata = p_data->hid_cback.p_data;
+  uint8_t* data = (uint8_t*)(pdata + 1) + pdata->offset;
+  tBTA_HH_HSDATA hs_data;
+
+#if (BTA_HH_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("Ctrl DATA received w4: event[%s]",
+                   bta_hh_get_w4_event(p_cb->w4_evt));
+#endif
+  hs_data.status = BTA_HH_OK;
+  hs_data.handle = p_cb->hid_handle;
+
+  switch (p_cb->w4_evt) {
+    case BTA_HH_GET_IDLE_EVT:
+      hs_data.rsp_data.idle_rate = *data;
+      break;
+    case BTA_HH_GET_RPT_EVT:
+      hs_data.rsp_data.p_rpt_data = pdata;
+      break;
+    case BTA_HH_GET_PROTO_EVT:
+      /* match up BTE/BTA report/boot mode def*/
+      hs_data.rsp_data.proto_mode = ((*data) == HID_PAR_PROTOCOL_REPORT)
+                                        ? BTA_HH_PROTO_RPT_MODE
+                                        : BTA_HH_PROTO_BOOT_MODE;
+#if (BTA_HH_DEBUG == TRUE)
+      APPL_TRACE_DEBUG("GET_PROTOCOL Mode = [%s]",
+                       (hs_data.rsp_data.proto_mode == BTA_HH_PROTO_RPT_MODE)
+                           ? "Report"
+                           : "Boot");
+#endif
+      break;
+    /* should not expect control DATA for SET_ transaction */
+    case BTA_HH_SET_PROTO_EVT:
+    /* fall through */
+    case BTA_HH_SET_RPT_EVT:
+    /* fall through */
+    case BTA_HH_SET_IDLE_EVT:
+    /* fall through */
+    default:
+#if (BTA_HH_DEBUG == TRUE)
+      APPL_TRACE_DEBUG("invalid  transaction type for DATA payload: 4_evt[%s]",
+                       bta_hh_get_w4_event(p_cb->w4_evt));
+#endif
+      break;
+  }
+
+  /* inform PM for mode change */
+  bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+  bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+
+  (*bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH*)&hs_data);
+
+  p_cb->w4_evt = 0;
+  osi_free_and_reset((void**)&pdata);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_open_failure
+ *
+ * Description      report HID open failure when at wait for connection state
+ *                  and receive device close event.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_open_failure(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+  tBTA_HH_CONN conn_dat;
+  uint32_t reason = p_data->hid_cback.data; /* Reason for closing (32-bit) */
+
+  memset(&conn_dat, 0, sizeof(tBTA_HH_CONN));
+  conn_dat.handle = p_cb->hid_handle;
+  conn_dat.status =
+      (reason == HID_ERR_AUTH_FAILED) ? BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR;
+  bdcpy(conn_dat.bda, p_cb->addr);
+  HID_HostCloseDev(p_cb->hid_handle);
+
+  /* Report OPEN fail event */
+  (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH*)&conn_dat);
+
+#if (BTA_HH_DEBUG == TRUE)
+  bta_hh_trace_dev_db();
+#endif
+  /* clean up control block, but retain SDP info and device handle */
+  p_cb->vp = false;
+  p_cb->w4_evt = 0;
+
+  /* if no connection is active and HH disable is signaled, disable service */
+  if (bta_hh_cb.cnt_num == 0 && bta_hh_cb.w4_disable) {
+    bta_hh_disc_cmpl();
+  }
+
+  /* Error in opening hid connection, reset flags */
+  p_cb->incoming_conn = false;
+  p_cb->incoming_hid_handle = BTA_HH_INVALID_HANDLE;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_close_act
+ *
+ * Description      HID Host process a close event
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_close_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+  tBTA_HH_CONN conn_dat;
+  tBTA_HH_CBDATA disc_dat = {BTA_HH_OK, 0};
+  uint32_t reason = p_data->hid_cback.data; /* Reason for closing (32-bit) */
+
+  /* if HID_HDEV_EVT_VC_UNPLUG was received, report BTA_HH_VC_UNPLUG_EVT */
+  uint16_t event = p_cb->vp ? BTA_HH_VC_UNPLUG_EVT : BTA_HH_CLOSE_EVT;
+
+  disc_dat.handle = p_cb->hid_handle;
+  disc_dat.status = p_data->hid_cback.data;
+
+  /* Check reason for closing */
+  if ((reason & (HID_L2CAP_CONN_FAIL |
+                 HID_L2CAP_REQ_FAIL)) || /* Failure to initialize connection
+                                            (page timeout or l2cap error) */
+      (reason ==
+       HID_ERR_AUTH_FAILED) || /* Authenication error (while initiating) */
+      (reason == HID_ERR_L2CAP_FAILED)) /* Failure creating l2cap connection */
+  {
+    /* Failure in opening connection */
+    conn_dat.handle = p_cb->hid_handle;
+    conn_dat.status =
+        (reason == HID_ERR_AUTH_FAILED) ? BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR;
+    bdcpy(conn_dat.bda, p_cb->addr);
+    HID_HostCloseDev(p_cb->hid_handle);
+
+    /* Report OPEN fail event */
+    (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH*)&conn_dat);
+
+#if (BTA_HH_DEBUG == TRUE)
+    bta_hh_trace_dev_db();
+#endif
+    return;
+  }
+  /* otherwise report CLOSE/VC_UNPLUG event */
+  else {
+    /* finaliza device driver */
+    bta_hh_co_close(p_cb->hid_handle, p_cb->app_id);
+    /* inform role manager */
+    bta_sys_conn_close(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+    /* update total conn number */
+    bta_hh_cb.cnt_num--;
+
+    if (disc_dat.status) disc_dat.status = BTA_HH_ERR;
+
+    (*bta_hh_cb.p_cback)(event, (tBTA_HH*)&disc_dat);
+
+    /* if virtually unplug, remove device */
+    if (p_cb->vp) {
+      HID_HostRemoveDev(p_cb->hid_handle);
+      bta_hh_clean_up_kdev(p_cb);
+    }
+
+#if (BTA_HH_DEBUG == TRUE)
+    bta_hh_trace_dev_db();
+#endif
+  }
+
+  /* clean up control block, but retain SDP info and device handle */
+  p_cb->vp = false;
+  p_cb->w4_evt = 0;
+
+  /* if no connection is active and HH disable is signaled, disable service */
+  if (bta_hh_cb.cnt_num == 0 && bta_hh_cb.w4_disable) {
+    bta_hh_disc_cmpl();
+  }
+
+  return;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_get_dscp_act
+ *
+ * Description      Get device report descriptor
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_get_dscp_act(tBTA_HH_DEV_CB* p_cb,
+                         UNUSED_ATTR tBTA_HH_DATA* p_data) {
+#if (BTA_HH_LE_INCLUDED == TRUE)
+  if (p_cb->is_le_device) {
+    bta_hh_le_get_dscp_act(p_cb);
+  } else
+#endif
+    (*bta_hh_cb.p_cback)(BTA_HH_GET_DSCP_EVT, (tBTA_HH*)&p_cb->dscp_info);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_maint_dev_act
+ *
+ * Description      HID Host maintain device list.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_maint_dev_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+  tBTA_HH_MAINT_DEV* p_dev_info = &p_data->api_maintdev;
+  tBTA_HH_DEV_INFO dev_info;
+  uint8_t dev_handle;
+
+  dev_info.status = BTA_HH_ERR;
+  dev_info.handle = BTA_HH_INVALID_HANDLE;
+
+  switch (p_dev_info->sub_event) {
+    case BTA_HH_ADD_DEV_EVT: /* add a device */
+      bdcpy(dev_info.bda, p_dev_info->bda);
+      /* initialize callback data */
+      if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) {
+#if (BTA_HH_LE_INCLUDED == TRUE)
+        if (bta_hh_is_le_device(p_cb, p_data->api_conn.bd_addr)) {
+          dev_info.handle = bta_hh_le_add_device(p_cb, p_dev_info);
+          dev_info.status = BTA_HH_OK;
+        } else
+#endif
+
+            if (HID_HostAddDev(p_dev_info->bda, p_dev_info->attr_mask,
+                               &dev_handle) == HID_SUCCESS) {
+          dev_info.handle = dev_handle;
+          dev_info.status = BTA_HH_OK;
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+          /* update DI information */
+          bta_hh_update_di_info(p_cb, p_dev_info->dscp_info.vendor_id,
+                                p_dev_info->dscp_info.product_id,
+                                p_dev_info->dscp_info.version,
+                                p_dev_info->dscp_info.flag);
+#else
+          bta_hh_update_di_info(p_cb, p_dev_info->dscp_info.vendor_id,
+                                p_dev_info->dscp_info.product_id,
+                                p_dev_info->dscp_info.version, 0);
+
+#endif
+          /* add to BTA device list */
+          bta_hh_add_device_to_list(
+              p_cb, dev_handle, p_dev_info->attr_mask,
+              &p_dev_info->dscp_info.descriptor, p_dev_info->sub_class,
+              p_dev_info->dscp_info.ssr_max_latency,
+              p_dev_info->dscp_info.ssr_min_tout, p_dev_info->app_id);
+          /* update cb_index[] map */
+          bta_hh_cb.cb_index[dev_handle] = p_cb->index;
+        }
+      } else /* device already been added */
+      {
+        dev_info.handle = p_cb->hid_handle;
+        dev_info.status = BTA_HH_OK;
+      }
+#if (BTA_HH_DEBUG == TRUE)
+      bta_hh_trace_dev_db();
+#endif
+
+      break;
+    case BTA_HH_RMV_DEV_EVT: /* remove device */
+      dev_info.handle = (uint8_t)p_dev_info->hdr.layer_specific;
+      bdcpy(dev_info.bda, p_cb->addr);
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+      if (p_cb->is_le_device) {
+        bta_hh_le_remove_dev_bg_conn(p_cb);
+        bta_hh_sm_execute(p_cb, BTA_HH_API_CLOSE_EVT, NULL);
+        bta_hh_clean_up_kdev(p_cb);
+      } else
+#endif
+      {
+        if (HID_HostRemoveDev(dev_info.handle) == HID_SUCCESS) {
+          dev_info.status = BTA_HH_OK;
+
+          /* remove from known device list in BTA */
+          bta_hh_clean_up_kdev(p_cb);
+        }
+      }
+      break;
+
+    default:
+      APPL_TRACE_DEBUG("invalid command");
+      break;
+  }
+
+  (*bta_hh_cb.p_cback)(p_dev_info->sub_event, (tBTA_HH*)&dev_info);
+}
+/*******************************************************************************
+ *
+ * Function         bta_hh_write_dev_act
+ *
+ * Description      Write device action. can be SET/GET/DATA transaction.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_write_dev_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+  tBTA_HH_CBDATA cbdata = {BTA_HH_OK, 0};
+  uint16_t event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
+                   BTA_HH_FST_TRANS_CB_EVT;
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+  if (p_cb->is_le_device)
+    bta_hh_le_write_dev_act(p_cb, p_data);
+  else
+#endif
+  {
+
+    cbdata.handle = p_cb->hid_handle;
+
+    /* match up BTE/BTA report/boot mode def */
+    if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL) {
+      p_data->api_sndcmd.param =
+          (p_data->api_sndcmd.param == BTA_HH_PROTO_RPT_MODE)
+              ? HID_PAR_PROTOCOL_REPORT
+              : HID_PAR_PROTOCOL_BOOT_MODE;
+    }
+
+    if (HID_HostWriteDev(p_cb->hid_handle, p_data->api_sndcmd.t_type,
+                         p_data->api_sndcmd.param, p_data->api_sndcmd.data,
+                         p_data->api_sndcmd.rpt_id,
+                         p_data->api_sndcmd.p_data) != HID_SUCCESS) {
+      APPL_TRACE_ERROR("HID_HostWriteDev Error ");
+      cbdata.status = BTA_HH_ERR;
+
+      if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL &&
+          p_data->api_sndcmd.t_type != HID_TRANS_DATA)
+        (*bta_hh_cb.p_cback)(event, (tBTA_HH*)&cbdata);
+      else if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
+        (*bta_hh_cb.p_cback)(BTA_HH_VC_UNPLUG_EVT, (tBTA_HH*)&cbdata);
+    } else {
+      switch (p_data->api_sndcmd.t_type) {
+        case HID_TRANS_SET_PROTOCOL:
+        /* fall through */
+        case HID_TRANS_GET_REPORT:
+        /* fall through */
+        case HID_TRANS_SET_REPORT:
+        /* fall through */
+        case HID_TRANS_GET_PROTOCOL:
+        /* fall through */
+        case HID_TRANS_GET_IDLE:
+        /* fall through */
+        case HID_TRANS_SET_IDLE: /* set w4_handsk event name for callback
+                                    function use */
+          p_cb->w4_evt = event;
+          break;
+        case HID_TRANS_DATA: /* output report */
+                             /* fall through */
+        case HID_TRANS_CONTROL:
+          /* no handshake event will be generated */
+          /* if VC_UNPLUG is issued, set flag */
+          if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
+            p_cb->vp = true;
+
+          break;
+        /* currently not expected */
+        case HID_TRANS_DATAC:
+        default:
+          APPL_TRACE_DEBUG("bta_hh_write_dev_act:: cmd type = %d",
+                           p_data->api_sndcmd.t_type);
+          break;
+      }
+
+      /* if not control type transaction, notify PM for energy control */
+      if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL) {
+        /* inform PM for mode change */
+        bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+        bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+      } else if (p_data->api_sndcmd.param == BTA_HH_CTRL_SUSPEND) {
+        bta_sys_sco_close(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+      } else if (p_data->api_sndcmd.param == BTA_HH_CTRL_EXIT_SUSPEND) {
+        bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+      }
+    }
+  }
+  return;
+}
+
+/*****************************************************************************
+ *  Static Function
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function         bta_hh_cback
+ *
+ * Description      BTA HH callback function.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hh_cback(uint8_t dev_handle, BD_ADDR addr, uint8_t event,
+                         uint32_t data, BT_HDR* pdata) {
+  uint16_t sm_event = BTA_HH_INVALID_EVT;
+  uint8_t xx = 0;
+
+#if (BTA_HH_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hh_cback::HID_event [%s]",
+                   bta_hh_hid_event_name(event));
+#endif
+
+  switch (event) {
+    case HID_HDEV_EVT_OPEN:
+      sm_event = BTA_HH_INT_OPEN_EVT;
+      break;
+    case HID_HDEV_EVT_CLOSE:
+      sm_event = BTA_HH_INT_CLOSE_EVT;
+      break;
+    case HID_HDEV_EVT_INTR_DATA:
+      sm_event = BTA_HH_INT_DATA_EVT;
+      break;
+    case HID_HDEV_EVT_HANDSHAKE:
+      sm_event = BTA_HH_INT_HANDSK_EVT;
+      break;
+    case HID_HDEV_EVT_CTRL_DATA:
+      sm_event = BTA_HH_INT_CTRL_DATA;
+      break;
+    case HID_HDEV_EVT_RETRYING:
+      break;
+    case HID_HDEV_EVT_INTR_DATC:
+    case HID_HDEV_EVT_CTRL_DATC:
+      /* Unhandled events: Free buffer for DATAC */
+      osi_free_and_reset((void**)&pdata);
+      break;
+    case HID_HDEV_EVT_VC_UNPLUG:
+      for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) {
+        if (bta_hh_cb.kdev[xx].hid_handle == dev_handle) {
+          bta_hh_cb.kdev[xx].vp = true;
+          break;
+        }
+      }
+      break;
+  }
+
+  if (sm_event != BTA_HH_INVALID_EVT) {
+    tBTA_HH_CBACK_DATA* p_buf = (tBTA_HH_CBACK_DATA*)osi_malloc(
+        sizeof(tBTA_HH_CBACK_DATA) + sizeof(BT_HDR));
+    p_buf->hdr.event = sm_event;
+    p_buf->hdr.layer_specific = (uint16_t)dev_handle;
+    p_buf->data = data;
+    bdcpy(p_buf->addr, addr);
+    p_buf->p_data = pdata;
+
+    bta_sys_sendmsg(p_buf);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_get_trans_status
+ *
+ * Description      translate a handshake result code into BTA HH
+ *                  status code
+ *
+ ******************************************************************************/
+static tBTA_HH_STATUS bta_hh_get_trans_status(uint32_t result) {
+  switch (result) {
+    case HID_PAR_HANDSHAKE_RSP_SUCCESS: /*   (0) */
+      return BTA_HH_OK;
+    case HID_PAR_HANDSHAKE_RSP_NOT_READY:           /*   (1) */
+    case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID:  /*   (2) */
+    case HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ: /*   (3) */
+    case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM:   /*   (4) */
+      return (tBTA_HH_STATUS)result;
+    case HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN: /*   (14) */
+    case HID_PAR_HANDSHAKE_RSP_ERR_FATAL:   /*   (15) */
+    default:
+      return BTA_HH_HS_ERROR;
+      break;
+  }
+}
+/*****************************************************************************
+ *  Debug Functions
+ ****************************************************************************/
+
+#if (BTA_HH_DEBUG == TRUE)
+static const char* bta_hh_get_w4_event(uint16_t event) {
+  switch (event) {
+    case BTA_HH_GET_RPT_EVT:
+      return "BTA_HH_GET_RPT_EVT";
+    case BTA_HH_SET_RPT_EVT:
+      return "BTA_HH_SET_RPT_EVT";
+    case BTA_HH_GET_PROTO_EVT:
+      return "BTA_HH_GET_PROTO_EVT";
+    case BTA_HH_SET_PROTO_EVT:
+      return "BTA_HH_SET_PROTO_EVT";
+    case BTA_HH_GET_IDLE_EVT:
+      return "BTA_HH_GET_IDLE_EVT";
+    case BTA_HH_SET_IDLE_EVT:
+      return "BTA_HH_SET_IDLE_EVT";
+    case BTA_HH_OPEN_EVT:
+      return "BTA_HH_OPEN_EVT";
+    default:
+      return "Unknown event";
+  }
+}
+
+static const char* bta_hh_hid_event_name(uint16_t event) {
+  switch (event) {
+    case HID_HDEV_EVT_OPEN:
+      return "HID_HDEV_EVT_OPEN";
+    case HID_HDEV_EVT_CLOSE:
+      return "HID_HDEV_EVT_CLOSE";
+    case HID_HDEV_EVT_RETRYING:
+      return "HID_HDEV_EVT_RETRYING";
+    case HID_HDEV_EVT_INTR_DATA:
+      return "HID_HDEV_EVT_INTR_DATA";
+    case HID_HDEV_EVT_INTR_DATC:
+      return "HID_HDEV_EVT_INTR_DATC";
+    case HID_HDEV_EVT_CTRL_DATA:
+      return "HID_HDEV_EVT_CTRL_DATA";
+    case HID_HDEV_EVT_CTRL_DATC:
+      return "HID_HDEV_EVT_CTRL_DATC";
+    case HID_HDEV_EVT_HANDSHAKE:
+      return "HID_HDEV_EVT_HANDSHAKE";
+    case HID_HDEV_EVT_VC_UNPLUG:
+      return "HID_HDEV_EVT_VC_UNPLUG";
+    default:
+      return "Unknown HID event";
+  }
+}
+#endif
+#endif /* BTA_HH_INCLUDED */
diff --git a/bt/bta/hh/bta_hh_api.cc b/bt/bta/hh/bta_hh_api.cc
new file mode 100644
index 0000000..26c9051
--- /dev/null
+++ b/bt/bta/hh/bta_hh_api.cc
@@ -0,0 +1,411 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2005-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 HID HOST API in the subsystem of BTA.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bta_hh"
+
+#include "bta_hh_api.h"
+
+#include "bt_target.h"
+
+#if (BTA_HH_INCLUDED == TRUE)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bta_hh_int.h"
+#include "l2c_api.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "utl.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_hh_reg = {bta_hh_hdl_event, BTA_HhDisable};
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhEnable
+ *
+ * Description      Enable the HID host.  This function must be called before
+ *                  any other functions in the HID host API are called. When the
+ *                  enable operation is complete the callback function will be
+ *                  called with BTA_HH_ENABLE_EVT.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HhEnable(tBTA_SEC sec_mask, tBTA_HH_CBACK* p_cback) {
+  tBTA_HH_API_ENABLE* p_buf =
+      (tBTA_HH_API_ENABLE*)osi_calloc(sizeof(tBTA_HH_API_ENABLE));
+
+  LOG_INFO(LOG_TAG, "%s sec_mask:0x%x p_cback:%p", __func__, sec_mask, p_cback);
+
+  /* register with BTA system manager */
+  bta_sys_register(BTA_ID_HH, &bta_hh_reg);
+
+  p_buf->hdr.event = BTA_HH_API_ENABLE_EVT;
+  p_buf->p_cback = p_cback;
+  p_buf->sec_mask = sec_mask;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhDisable
+ *
+ * Description      Disable the HID host. If the server is currently
+ *                  connected, the connection will be closed.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HhDisable(void) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  bta_sys_deregister(BTA_ID_HH);
+  p_buf->event = BTA_HH_API_DISABLE_EVT;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhClose
+ *
+ * Description      Disconnect a connection.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HhClose(uint8_t dev_handle) {
+  BT_HDR* p_buf = (BT_HDR*)osi_calloc(sizeof(BT_HDR));
+
+  p_buf->event = BTA_HH_API_CLOSE_EVT;
+  p_buf->layer_specific = (uint16_t)dev_handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhOpen
+ *
+ * Description      Connect to a device of specified BD address in specified
+ *                  protocol mode and security level.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HhOpen(BD_ADDR dev_bda, tBTA_HH_PROTO_MODE mode, tBTA_SEC sec_mask) {
+  tBTA_HH_API_CONN* p_buf =
+      (tBTA_HH_API_CONN*)osi_calloc(sizeof(tBTA_HH_API_CONN));
+
+  p_buf->hdr.event = BTA_HH_API_OPEN_EVT;
+  p_buf->hdr.layer_specific = BTA_HH_INVALID_HANDLE;
+  p_buf->sec_mask = sec_mask;
+  p_buf->mode = mode;
+  bdcpy(p_buf->bd_addr, dev_bda);
+
+  bta_sys_sendmsg((void*)p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function  bta_hh_snd_write_dev
+ *
+ ******************************************************************************/
+static void bta_hh_snd_write_dev(uint8_t dev_handle, uint8_t t_type,
+                                 uint8_t param, uint16_t data, uint8_t rpt_id,
+                                 BT_HDR* p_data) {
+  tBTA_HH_CMD_DATA* p_buf =
+      (tBTA_HH_CMD_DATA*)osi_calloc(sizeof(tBTA_HH_CMD_DATA));
+
+  p_buf->hdr.event = BTA_HH_API_WRITE_DEV_EVT;
+  p_buf->hdr.layer_specific = (uint16_t)dev_handle;
+  p_buf->t_type = t_type;
+  p_buf->data = data;
+  p_buf->param = param;
+  p_buf->p_data = p_data;
+  p_buf->rpt_id = rpt_id;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhSetReport
+ *
+ * Description      send SET_REPORT to device.
+ *
+ * Parameter        dev_handle: device handle
+ *                  r_type:     report type, could be BTA_HH_RPTT_OUTPUT or
+ *                              BTA_HH_RPTT_FEATURE.
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HhSetReport(uint8_t dev_handle, tBTA_HH_RPT_TYPE r_type,
+                     BT_HDR* p_data) {
+  bta_hh_snd_write_dev(dev_handle, HID_TRANS_SET_REPORT, r_type, 0, 0, p_data);
+}
+/*******************************************************************************
+ *
+ * Function         BTA_HhGetReport
+ *
+ * Description      Send a GET_REPORT to HID device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HhGetReport(uint8_t dev_handle, tBTA_HH_RPT_TYPE r_type,
+                     uint8_t rpt_id, uint16_t buf_size) {
+  uint8_t param = (buf_size) ? (r_type | 0x08) : r_type;
+
+  bta_hh_snd_write_dev(dev_handle, HID_TRANS_GET_REPORT, param, buf_size,
+                       rpt_id, NULL);
+}
+/*******************************************************************************
+ *
+ * Function         BTA_HhSetProtoMode
+ *
+ * Description      This function set the protocol mode at specified HID handle
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HhSetProtoMode(uint8_t dev_handle, tBTA_HH_PROTO_MODE p_type) {
+  bta_hh_snd_write_dev(dev_handle, HID_TRANS_SET_PROTOCOL, (uint8_t)p_type, 0,
+                       0, NULL);
+}
+/*******************************************************************************
+ *
+ * Function         BTA_HhGetProtoMode
+ *
+ * Description      This function get protocol mode information.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HhGetProtoMode(uint8_t dev_handle) {
+  bta_hh_snd_write_dev(dev_handle, HID_TRANS_GET_PROTOCOL, 0, 0, 0, NULL);
+}
+/*******************************************************************************
+ *
+ * Function         BTA_HhSetIdle
+ *
+ * Description      send SET_IDLE to device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HhSetIdle(uint8_t dev_handle, uint16_t idle_rate) {
+  bta_hh_snd_write_dev(dev_handle, HID_TRANS_SET_IDLE, 0, idle_rate, 0, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhGetIdle
+ *
+ * Description      Send a GET_IDLE from HID device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HhGetIdle(uint8_t dev_handle) {
+  bta_hh_snd_write_dev(dev_handle, HID_TRANS_GET_IDLE, 0, 0, 0, NULL);
+}
+/*******************************************************************************
+ *
+ * Function         BTA_HhSendCtrl
+ *
+ * Description      Send a control command to HID device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HhSendCtrl(uint8_t dev_handle, tBTA_HH_TRANS_CTRL_TYPE c_type) {
+  bta_hh_snd_write_dev(dev_handle, HID_TRANS_CONTROL, (uint8_t)c_type, 0, 0,
+                       NULL);
+}
+/*******************************************************************************
+ *
+ * Function         BTA_HhSendData
+ *
+ * Description      This function send DATA transaction to HID device.
+ *
+ * Parameter        dev_handle: device handle
+ *                  dev_bda: remote device address
+ *                  p_data: data to be sent in the DATA transaction; or
+ *                          the data to be write into the Output Report of a LE
+ *                          HID device. The report is identified the report ID
+ *                          which is the value of the byte
+ *                          (uint8_t *)(p_buf + 1) + *p_buf->offset.
+ *                          p_data->layer_specific needs to be set to the report
+ *                          type. It can be OUTPUT report, or FEATURE report.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HhSendData(uint8_t dev_handle, UNUSED_ATTR BD_ADDR dev_bda,
+                    BT_HDR* p_data) {
+#if (BTA_HH_LE_INCLUDED == TRUE)
+  if (p_data->layer_specific != BTA_HH_RPTT_OUTPUT) {
+    APPL_TRACE_ERROR(
+        "ERROR! Wrong report type! Write Command only valid for output "
+        "report!");
+    return;
+  }
+#endif
+  bta_hh_snd_write_dev(dev_handle, HID_TRANS_DATA,
+                       (uint8_t)p_data->layer_specific, 0, 0, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhGetDscpInfo
+ *
+ * Description      Get HID device report descriptor
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HhGetDscpInfo(uint8_t dev_handle) {
+  BT_HDR* p_buf = (BT_HDR*)osi_calloc(sizeof(BT_HDR));
+
+  p_buf->event = BTA_HH_API_GET_DSCP_EVT;
+  p_buf->layer_specific = (uint16_t)dev_handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhAddDev
+ *
+ * Description      Add a virtually cabled device into HID-Host device list
+ *                  to manage and assign a device handle for future API call,
+ *                  host applciation call this API at start-up to initialize its
+ *                  virtually cabled devices.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HhAddDev(BD_ADDR bda, tBTA_HH_ATTR_MASK attr_mask, uint8_t sub_class,
+                  uint8_t app_id, tBTA_HH_DEV_DSCP_INFO dscp_info) {
+  size_t len = sizeof(tBTA_HH_MAINT_DEV) + dscp_info.descriptor.dl_len;
+  tBTA_HH_MAINT_DEV* p_buf = (tBTA_HH_MAINT_DEV*)osi_calloc(len);
+
+  p_buf->hdr.event = BTA_HH_API_MAINT_DEV_EVT;
+  p_buf->sub_event = BTA_HH_ADD_DEV_EVT;
+  p_buf->hdr.layer_specific = BTA_HH_INVALID_HANDLE;
+
+  p_buf->attr_mask = (uint16_t)attr_mask;
+  p_buf->sub_class = sub_class;
+  p_buf->app_id = app_id;
+  bdcpy(p_buf->bda, bda);
+
+  memcpy(&p_buf->dscp_info, &dscp_info, sizeof(tBTA_HH_DEV_DSCP_INFO));
+  if (dscp_info.descriptor.dl_len != 0 && dscp_info.descriptor.dsc_list) {
+    p_buf->dscp_info.descriptor.dl_len = dscp_info.descriptor.dl_len;
+    p_buf->dscp_info.descriptor.dsc_list = (uint8_t*)(p_buf + 1);
+    memcpy(p_buf->dscp_info.descriptor.dsc_list, dscp_info.descriptor.dsc_list,
+           dscp_info.descriptor.dl_len);
+  } else {
+    p_buf->dscp_info.descriptor.dsc_list = NULL;
+    p_buf->dscp_info.descriptor.dl_len = 0;
+  }
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhRemoveDev
+ *
+ * Description      Remove a device from the HID host devices list.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HhRemoveDev(uint8_t dev_handle) {
+  tBTA_HH_MAINT_DEV* p_buf =
+      (tBTA_HH_MAINT_DEV*)osi_calloc(sizeof(tBTA_HH_MAINT_DEV));
+
+  p_buf->hdr.event = BTA_HH_API_MAINT_DEV_EVT;
+  p_buf->sub_event = BTA_HH_RMV_DEV_EVT;
+  p_buf->hdr.layer_specific = (uint16_t)dev_handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************/
+/*                          Utility Function */
+/*******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhParseBootRpt
+ *
+ * Description      This utility function parse a boot mode report.
+ *                  For keyboard report, report data will carry the keycode max
+ *                  up to 6 key press in one report. Application need to convert
+ *                  the keycode into keypress character according to keyboard
+ *                  language.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HhParseBootRpt(tBTA_HH_BOOT_RPT* p_data, uint8_t* p_report,
+                        uint16_t report_len) {
+  p_data->dev_type = BTA_HH_DEVT_UNKNOWN;
+
+  if (p_report) {
+    /* first byte is report ID */
+    switch (p_report[0]) {
+      case BTA_HH_KEYBD_RPT_ID: /* key board report ID */
+        p_data->dev_type = p_report[0];
+        bta_hh_parse_keybd_rpt(p_data, p_report + 1,
+                               (uint16_t)(report_len - 1));
+        break;
+
+      case BTA_HH_MOUSE_RPT_ID: /* mouse report ID */
+        p_data->dev_type = p_report[0];
+        bta_hh_parse_mice_rpt(p_data, p_report + 1, (uint16_t)(report_len - 1));
+        break;
+
+      default:
+        APPL_TRACE_DEBUG("Unknown boot report: %d", p_report[0]);
+        ;
+        break;
+    }
+  }
+
+  return;
+}
+
+#endif /* BTA_HH_INCLUDED */
diff --git a/bt/bta/hh/bta_hh_cfg.cc b/bt/bta/hh/bta_hh_cfg.cc
new file mode 100644
index 0000000..9479e8b
--- /dev/null
+++ b/bt/bta/hh/bta_hh_cfg.cc
@@ -0,0 +1,55 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2005-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 compile-time configurable constants for the BTA Hid
+ *  Host.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+#include "bta_hh_api.h"
+
+/* max number of device types supported by BTA */
+#define BTA_HH_MAX_DEVT_SPT 9
+
+/* size of database for service discovery */
+#ifndef BTA_HH_DISC_BUF_SIZE
+#define BTA_HH_DISC_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* The type of devices supported by BTA HH and corresponding application ID */
+tBTA_HH_SPT_TOD p_devt_list[BTA_HH_MAX_DEVT_SPT] = {
+    {BTA_HH_DEVT_MIC, BTA_HH_APP_ID_MI},
+    {BTA_HH_DEVT_KBD, BTA_HH_APP_ID_KB},
+    {BTA_HH_DEVT_KBD | BTA_HH_DEVT_MIC, BTA_HH_APP_ID_KB},
+    {BTA_HH_DEVT_RMC, BTA_HH_APP_ID_RMC},
+    {BTA_HH_DEVT_RMC | BTA_HH_DEVT_KBD, BTA_HH_APP_ID_RMC},
+    {BTA_HH_DEVT_MIC | BTA_HH_DEVT_DGT, BTA_HH_APP_ID_MI},
+    {BTA_HH_DEVT_JOS, BTA_HH_APP_ID_JOY},
+    {BTA_HH_DEVT_GPD, BTA_HH_APP_ID_GPAD},
+    {BTA_HH_DEVT_UNKNOWN, BTA_HH_APP_ID_3DSG}};
+
+const tBTA_HH_CFG bta_hh_cfg = {
+    BTA_HH_MAX_DEVT_SPT, /* number of supported type of devices */
+    p_devt_list,         /* ToD & AppID list */
+    BTA_HH_DISC_BUF_SIZE /* HH SDP discovery database size */
+};
+
+tBTA_HH_CFG* p_bta_hh_cfg = (tBTA_HH_CFG*)&bta_hh_cfg;
diff --git a/bt/bta/hh/bta_hh_int.h b/bt/bta/hh/bta_hh_int.h
new file mode 100644
index 0000000..0edbf60
--- /dev/null
+++ b/bt/bta/hh/bta_hh_int.h
@@ -0,0 +1,388 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2005-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 BTA HID Host internal definitions
+ *
+ ******************************************************************************/
+
+#ifndef BTA_HH_INT_H
+#define BTA_HH_INT_H
+
+#include "bta_hh_api.h"
+#include "bta_sys.h"
+#include "utl.h"
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+#include "bta_gatt_api.h"
+#endif
+
+/* can be moved to bta_api.h */
+#define BTA_HH_MAX_RPT_CHARS 8
+
+#if (BTA_GATT_INCLUDED == FALSE || BLE_INCLUDED == FALSE)
+#undef BTA_HH_LE_INCLUDED
+#define BTA_HH_LE_INCLUDED false
+#endif
+
+/* state machine events, these events are handled by the state machine */
+enum {
+  BTA_HH_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_HH),
+  BTA_HH_API_CLOSE_EVT,
+  BTA_HH_INT_OPEN_EVT,
+  BTA_HH_INT_CLOSE_EVT,
+  BTA_HH_INT_DATA_EVT,
+  BTA_HH_INT_CTRL_DATA,
+  BTA_HH_INT_HANDSK_EVT,
+  BTA_HH_SDP_CMPL_EVT,
+  BTA_HH_API_WRITE_DEV_EVT,
+  BTA_HH_API_GET_DSCP_EVT,
+  BTA_HH_API_MAINT_DEV_EVT,
+  BTA_HH_OPEN_CMPL_EVT,
+#if (BTA_HH_LE_INCLUDED == TRUE)
+  BTA_HH_GATT_CLOSE_EVT,
+  BTA_HH_GATT_OPEN_EVT,
+  BTA_HH_START_ENC_EVT,
+  BTA_HH_ENC_CMPL_EVT,
+  BTA_HH_GATT_ENC_CMPL_EVT,
+#endif
+
+  /* not handled by execute state machine */
+  BTA_HH_API_ENABLE_EVT,
+  BTA_HH_API_DISABLE_EVT,
+  BTA_HH_DISC_CMPL_EVT
+};
+typedef uint16_t tBTA_HH_INT_EVT; /* HID host internal events */
+
+#define BTA_HH_INVALID_EVT (BTA_HH_DISC_CMPL_EVT + 1)
+
+/* event used to map between BTE event and BTA event */
+#define BTA_HH_FST_TRANS_CB_EVT BTA_HH_GET_RPT_EVT
+#define BTA_HH_FST_BTE_TRANS_EVT HID_TRANS_GET_REPORT
+
+/* sub event code used for device maintainence API call */
+#define BTA_HH_ADD_DEV 0
+#define BTA_HH_REMOVE_DEV 1
+
+/* state machine states */
+enum {
+  BTA_HH_NULL_ST,
+  BTA_HH_IDLE_ST,
+  BTA_HH_W4_CONN_ST,
+  BTA_HH_CONN_ST
+#if (BTA_HH_LE_INCLUDED == TRUE)
+  ,
+  BTA_HH_W4_SEC
+#endif
+  ,
+  BTA_HH_INVALID_ST /* Used to check invalid states before executing SM function
+                       */
+
+};
+typedef uint8_t tBTA_HH_STATE;
+
+/* data structure used to send a command/data to HID device */
+typedef struct {
+  BT_HDR hdr;
+  uint8_t t_type;
+  uint8_t param;
+  uint8_t rpt_id;
+#if (BTA_HH_LE_INCLUDED == TRUE)
+  uint8_t srvc_id;
+#endif
+  uint16_t data;
+  BT_HDR* p_data;
+} tBTA_HH_CMD_DATA;
+
+/* data type for BTA_HH_API_ENABLE_EVT */
+typedef struct {
+  BT_HDR hdr;
+  uint8_t sec_mask;
+  uint8_t service_name[BTA_SERVICE_NAME_LEN + 1];
+  tBTA_HH_CBACK* p_cback;
+} tBTA_HH_API_ENABLE;
+
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  uint8_t sec_mask;
+  tBTA_HH_PROTO_MODE mode;
+} tBTA_HH_API_CONN;
+
+/* internal event data from BTE HID callback */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR addr;
+  uint32_t data;
+  BT_HDR* p_data;
+} tBTA_HH_CBACK_DATA;
+
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bda;
+  uint16_t attr_mask;
+  uint16_t sub_event;
+  uint8_t sub_class;
+  uint8_t app_id;
+  tBTA_HH_DEV_DSCP_INFO dscp_info;
+} tBTA_HH_MAINT_DEV;
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+typedef struct {
+  BT_HDR hdr;
+  uint16_t conn_id;
+  tBTA_GATT_REASON reason; /* disconnect reason code, not useful when connect
+                              event is reported */
+
+} tBTA_HH_LE_CLOSE;
+
+typedef struct {
+  BT_HDR hdr;
+  uint16_t scan_int;
+  uint16_t scan_win;
+} tBTA_HH_SCPP_UPDATE;
+#endif
+/* union of all event data types */
+typedef union {
+  BT_HDR hdr;
+  tBTA_HH_API_ENABLE api_enable;
+  tBTA_HH_API_CONN api_conn;
+  tBTA_HH_CMD_DATA api_sndcmd;
+  tBTA_HH_CBACK_DATA hid_cback;
+  tBTA_HH_STATUS status;
+  tBTA_HH_MAINT_DEV api_maintdev;
+#if (BTA_HH_LE_INCLUDED == TRUE)
+  tBTA_HH_LE_CLOSE le_close;
+  tBTA_GATTC_OPEN le_open;
+  tBTA_HH_SCPP_UPDATE le_scpp_update;
+  tBTA_GATTC_ENC_CMPL_CB le_enc_cmpl;
+#endif
+} tBTA_HH_DATA;
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+typedef struct {
+  uint8_t index;
+  bool in_use;
+  uint8_t srvc_inst_id;
+  uint8_t char_inst_id;
+  tBTA_HH_RPT_TYPE rpt_type;
+  uint16_t uuid;
+  uint8_t rpt_id;
+  bool client_cfg_exist;
+  uint16_t client_cfg_value;
+} tBTA_HH_LE_RPT;
+
+#ifndef BTA_HH_LE_RPT_MAX
+#define BTA_HH_LE_RPT_MAX 20
+#endif
+
+typedef struct {
+  bool in_use;
+  uint8_t srvc_inst_id;
+  tBTA_HH_LE_RPT report[BTA_HH_LE_RPT_MAX];
+
+  uint16_t proto_mode_handle;
+  uint8_t control_point_handle;
+
+  uint8_t
+      incl_srvc_inst; /* assuming only one included service : battery service */
+  uint8_t cur_expl_char_idx; /* currently discovering service index */
+  uint8_t* rpt_map;
+  uint16_t ext_rpt_ref;
+  tBTA_HH_DEV_DESCR descriptor;
+
+} tBTA_HH_LE_HID_SRVC;
+
+/* convert a HID handle to the LE CB index */
+#define BTA_HH_GET_LE_CB_IDX(x) (((x) >> 4) - 1)
+/* convert a GATT connection ID to HID device handle, it is the hi 4 bits of a
+ * uint8_t */
+#define BTA_HH_GET_LE_DEV_HDL(x) (uint8_t)(((x) + 1) << 4)
+/* check to see if th edevice handle is a LE device handle */
+#define BTA_HH_IS_LE_DEV_HDL(x) ((x)&0xf0)
+#define BTA_HH_IS_LE_DEV_HDL_VALID(x) (((x) >> 4) <= BTA_HH_LE_MAX_KNOWN)
+#endif
+
+/* device control block */
+typedef struct {
+  tBTA_HH_DEV_DSCP_INFO dscp_info; /* report descriptor and DI information */
+  BD_ADDR addr;                    /* BD-Addr of the HID device */
+  uint16_t attr_mask;              /* attribute mask */
+  uint16_t w4_evt;                 /* W4_handshake event name */
+  uint8_t index;                   /* index number referenced to handle index */
+  uint8_t sub_class;               /* Cod sub class */
+  uint8_t sec_mask;                /* security mask */
+  uint8_t app_id;                  /* application ID for this connection */
+  uint8_t hid_handle;          /* device handle : low 4 bits for regular HID:
+                                  HID_HOST_MAX_DEVICES can not exceed 15;
+                                                 high 4 bits for LE HID:
+                                  GATT_MAX_PHY_CHANNEL can not exceed 15 */
+  bool vp;                     /* virtually unplug flag */
+  bool in_use;                 /* control block currently in use */
+  bool incoming_conn;          /* is incoming connection? */
+  uint8_t incoming_hid_handle; /* temporary handle for incoming connection? */
+  bool opened; /* true if device successfully opened HID connection */
+  tBTA_HH_PROTO_MODE mode; /* protocol mode */
+  tBTA_HH_STATE state;     /* CB state */
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+#define BTA_HH_LE_DISC_NONE 0x00
+#define BTA_HH_LE_DISC_HIDS 0x01
+#define BTA_HH_LE_DISC_DIS 0x02
+#define BTA_HH_LE_DISC_SCPS 0x04
+
+  uint8_t disc_active;
+  tBTA_HH_STATUS status;
+  tBTA_GATT_REASON reason;
+  bool is_le_device;
+  tBTA_HH_LE_HID_SRVC hid_srvc;
+  uint16_t conn_id;
+  bool in_bg_conn;
+  uint8_t clt_cfg_idx;
+  uint16_t scan_refresh_char_handle;
+  bool scps_supported;
+
+#define BTA_HH_LE_SCPS_NOTIFY_NONE 0
+#define BTA_HH_LE_SCPS_NOTIFY_SPT 0x01
+#define BTA_HH_LE_SCPS_NOTIFY_ENB 0x02
+  uint8_t scps_notify; /* scan refresh supported/notification enabled */
+#endif
+
+  bool security_pending;
+} tBTA_HH_DEV_CB;
+
+/* key board parsing control block */
+typedef struct {
+  bool mod_key[4]; /* ctrl, shift(upper), Alt, GUI */
+  bool num_lock;
+  bool caps_lock;
+  uint8_t last_report[BTA_HH_MAX_RPT_CHARS];
+} tBTA_HH_KB_CB;
+
+/******************************************************************************
+ * Main Control Block
+ ******************************************************************************/
+typedef struct {
+  tBTA_HH_KB_CB kb_cb;                    /* key board control block,
+                                             suppose BTA will connect
+                                             to only one keyboard at
+                                              the same time */
+  tBTA_HH_DEV_CB kdev[BTA_HH_MAX_DEVICE]; /* device control block */
+  tBTA_HH_DEV_CB* p_cur;                  /* current device control
+                                                 block idx, used in sdp */
+  uint8_t cb_index[BTA_HH_MAX_KNOWN];     /* maintain a CB index
+                                        map to dev handle */
+#if (BTA_HH_LE_INCLUDED == TRUE)
+  uint8_t le_cb_index[BTA_HH_MAX_DEVICE]; /* maintain a CB index map to LE dev
+                                             handle */
+  tBTA_GATTC_IF gatt_if;
+#endif
+  tBTA_HH_CBACK* p_cback; /* Application callbacks */
+  tSDP_DISCOVERY_DB* p_disc_db;
+  uint8_t trace_level; /* tracing level */
+  uint8_t cnt_num;     /* connected device number */
+  bool w4_disable;     /* w4 disable flag */
+} tBTA_HH_CB;
+
+extern tBTA_HH_CB bta_hh_cb;
+
+/* from bta_hh_cfg.c */
+extern tBTA_HH_CFG* p_bta_hh_cfg;
+
+/*****************************************************************************
+ *  Function prototypes
+ ****************************************************************************/
+extern bool bta_hh_hdl_event(BT_HDR* p_msg);
+extern void bta_hh_sm_execute(tBTA_HH_DEV_CB* p_cb, uint16_t event,
+                              tBTA_HH_DATA* p_data);
+
+/* action functions */
+extern void bta_hh_api_disc_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_open_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_close_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_data_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_start_sdp(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_write_dev_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_get_dscp_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_handsk_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_maint_dev_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_open_failure(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+
+/* utility functions */
+extern uint8_t bta_hh_find_cb(BD_ADDR bda);
+extern void bta_hh_parse_keybd_rpt(tBTA_HH_BOOT_RPT* p_kb_data,
+                                   uint8_t* p_report, uint16_t report_len);
+extern void bta_hh_parse_mice_rpt(tBTA_HH_BOOT_RPT* p_kb_data,
+                                  uint8_t* p_report, uint16_t report_len);
+extern bool bta_hh_tod_spt(tBTA_HH_DEV_CB* p_cb, uint8_t sub_class);
+extern void bta_hh_clean_up_kdev(tBTA_HH_DEV_CB* p_cb);
+
+extern void bta_hh_add_device_to_list(tBTA_HH_DEV_CB* p_cb, uint8_t handle,
+                                      uint16_t attr_mask,
+                                      tHID_DEV_DSCP_INFO* p_dscp_info,
+                                      uint8_t sub_class, uint16_t max_latency,
+                                      uint16_t min_tout, uint8_t app_id);
+extern void bta_hh_update_di_info(tBTA_HH_DEV_CB* p_cb, uint16_t vendor_id,
+                                  uint16_t product_id, uint16_t version,
+                                  uint8_t flag);
+extern void bta_hh_cleanup_disable(tBTA_HH_STATUS status);
+
+extern uint8_t bta_hh_dev_handle_to_cb_idx(uint8_t dev_handle);
+
+/* action functions used outside state machine */
+extern void bta_hh_api_enable(tBTA_HH_DATA* p_data);
+extern void bta_hh_api_disable(void);
+extern void bta_hh_disc_cmpl(void);
+
+extern tBTA_HH_STATUS bta_hh_read_ssr_param(BD_ADDR bd_addr,
+                                            uint16_t* p_max_ssr_lat,
+                                            uint16_t* p_min_ssr_tout);
+
+/* functions for LE HID */
+extern void bta_hh_le_enable(void);
+extern bool bta_hh_le_is_hh_gatt_if(tBTA_GATTC_IF client_if);
+extern void bta_hh_le_deregister(void);
+extern bool bta_hh_is_le_device(tBTA_HH_DEV_CB* p_cb, BD_ADDR remote_bda);
+extern void bta_hh_le_open_conn(tBTA_HH_DEV_CB* p_cb, BD_ADDR remote_bda);
+extern void bta_hh_le_api_disc_act(tBTA_HH_DEV_CB* p_cb);
+extern void bta_hh_le_get_dscp_act(tBTA_HH_DEV_CB* p_cb);
+extern void bta_hh_le_write_dev_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern uint8_t bta_hh_le_add_device(tBTA_HH_DEV_CB* p_cb,
+                                    tBTA_HH_MAINT_DEV* p_dev_info);
+extern void bta_hh_le_remove_dev_bg_conn(tBTA_HH_DEV_CB* p_cb);
+extern void bta_hh_le_open_fail(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_gatt_open(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_gatt_close(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_start_security(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_buf);
+extern void bta_hh_start_srvc_discovery(tBTA_HH_DEV_CB* p_cb,
+                                        tBTA_HH_DATA* p_buf);
+extern void bta_hh_start_security(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_buf);
+extern void bta_hh_security_cmpl(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_buf);
+extern void bta_hh_le_notify_enc_cmpl(tBTA_HH_DEV_CB* p_cb,
+                                      tBTA_HH_DATA* p_data);
+extern void bta_hh_ci_load_rpt(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_buf);
+
+#if (BTA_HH_DEBUG == TRUE)
+extern void bta_hh_trace_dev_db(void);
+#endif
+
+#endif
diff --git a/bt/bta/hh/bta_hh_le.cc b/bt/bta/hh/bta_hh_le.cc
new file mode 100644
index 0000000..d33084c
--- /dev/null
+++ b/bt/bta/hh/bta_hh_le.cc
@@ -0,0 +1,2351 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bta_hh"
+
+#include "bta_api.h"
+#include "bta_hh_int.h"
+#include "osi/include/osi.h"
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include <list>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "bta_api.h"
+#include "bta_gatt_api.h"
+#include "bta_hh_co.h"
+#include "btm_api.h"
+#include "btm_ble_api.h"
+#include "btm_int.h"
+#include "osi/include/log.h"
+#include "srvc_api.h"
+#include "stack/include/l2c_api.h"
+#include "utl.h"
+
+using std::vector;
+
+#ifndef BTA_HH_LE_RECONN
+#define BTA_HH_LE_RECONN true
+#endif
+
+#define BTA_HH_APP_ID_LE 0xff
+
+#define BTA_HH_LE_RPT_TYPE_VALID(x) \
+  ((x) <= BTA_LE_HID_RPT_FEATURE && (x) >= BTA_LE_HID_RPT_INPUT)
+
+#define BTA_HH_LE_PROTO_BOOT_MODE 0x00
+#define BTA_HH_LE_PROTO_REPORT_MODE 0x01
+
+#define BTA_LE_HID_RTP_UUID_MAX 5
+static const uint16_t bta_hh_uuid_to_rtp_type[BTA_LE_HID_RTP_UUID_MAX][2] = {
+    {GATT_UUID_HID_REPORT, BTA_HH_RPTT_INPUT},
+    {GATT_UUID_HID_BT_KB_INPUT, BTA_HH_RPTT_INPUT},
+    {GATT_UUID_HID_BT_KB_OUTPUT, BTA_HH_RPTT_OUTPUT},
+    {GATT_UUID_HID_BT_MOUSE_INPUT, BTA_HH_RPTT_INPUT},
+    {GATT_UUID_BATTERY_LEVEL, BTA_HH_RPTT_INPUT}};
+
+static void bta_hh_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data);
+static void bta_hh_le_add_dev_bg_conn(tBTA_HH_DEV_CB* p_cb, bool check_bond);
+// TODO(jpawlowski): uncomment when fixed
+// static void bta_hh_process_cache_rpt (tBTA_HH_DEV_CB *p_cb,
+//                                       tBTA_HH_RPT_CACHE_ENTRY *p_rpt_cache,
+//                                       uint8_t num_rpt);
+
+#define GATT_READ_CHAR 0
+#define GATT_READ_DESC 1
+#define GATT_WRITE_CHAR 2
+#define GATT_WRITE_DESC 3
+
+/* Holds pending GATT operations */
+struct gatt_operation {
+  uint8_t type;
+  uint16_t handle;
+  GATT_READ_OP_CB read_cb;
+  void* read_cb_data;
+  GATT_WRITE_OP_CB write_cb;
+  void* write_cb_data;
+
+  /* write-specific fields */
+  tBTA_GATTC_WRITE_TYPE write_type;
+  vector<uint8_t> value;
+};
+
+// maps connection id to operations waiting for execution
+static std::unordered_map<uint16_t, std::list<gatt_operation>> gatt_op_queue;
+// contain connection ids that currently execute operations
+static std::unordered_set<uint16_t> gatt_op_queue_executing;
+
+static void mark_as_not_executing(uint16_t conn_id) {
+  gatt_op_queue_executing.erase(conn_id);
+}
+
+static void gatt_op_queue_clean(uint16_t conn_id) {
+  gatt_op_queue.erase(conn_id);
+  gatt_op_queue_executing.erase(conn_id);
+}
+
+static void gatt_execute_next_op(uint16_t conn_id);
+GATT_READ_OP_CB act_read_cb = NULL;
+void* act_read_cb_data = NULL;
+static void gatt_read_op_finished(uint16_t conn_id, tGATT_STATUS status,
+                                  uint16_t handle, uint16_t len, uint8_t* value,
+                                  void* data) {
+  GATT_READ_OP_CB tmp_cb = act_read_cb;
+  void* tmp_cb_data = act_read_cb_data;
+
+  act_read_cb = NULL;
+  act_read_cb_data = NULL;
+
+  mark_as_not_executing(conn_id);
+  gatt_execute_next_op(conn_id);
+
+  if (tmp_cb) {
+    tmp_cb(conn_id, status, handle, len, value, tmp_cb_data);
+    return;
+  }
+}
+
+GATT_WRITE_OP_CB act_write_cb = NULL;
+void* act_write_cb_data = NULL;
+static void gatt_write_op_finished(uint16_t conn_id, tGATT_STATUS status,
+                                   uint16_t handle, void* data) {
+  GATT_WRITE_OP_CB tmp_cb = act_write_cb;
+  void* tmp_cb_data = act_write_cb_data;
+  act_write_cb = NULL;
+  act_write_cb_data = NULL;
+
+  mark_as_not_executing(conn_id);
+  gatt_execute_next_op(conn_id);
+
+  if (tmp_cb) {
+    tmp_cb(conn_id, status, handle, tmp_cb_data);
+    return;
+  }
+}
+
+static void gatt_execute_next_op(uint16_t conn_id) {
+  APPL_TRACE_DEBUG("%s:", __func__, conn_id);
+  if (gatt_op_queue.empty()) {
+    APPL_TRACE_DEBUG("%s: op queue is empty", __func__);
+    return;
+  }
+
+  auto map_ptr = gatt_op_queue.find(conn_id);
+  if (map_ptr == gatt_op_queue.end() || map_ptr->second.empty()) {
+    APPL_TRACE_DEBUG("%s: no more operations queued for conn_id %d", __func__,
+                     conn_id);
+    return;
+  }
+
+  if (gatt_op_queue_executing.count(conn_id)) {
+    APPL_TRACE_DEBUG("%s: can't enqueue next op, already executing", __func__);
+    return;
+  }
+
+  gatt_op_queue_executing.insert(conn_id);
+
+  std::list<gatt_operation>& gatt_ops = map_ptr->second;
+
+  gatt_operation& op = gatt_ops.front();
+
+  if (op.type == GATT_READ_CHAR) {
+    act_read_cb = op.read_cb;
+    act_read_cb_data = op.read_cb_data;
+    BTA_GATTC_ReadCharacteristic(conn_id, op.handle, BTA_GATT_AUTH_REQ_NONE,
+                                 gatt_read_op_finished, NULL);
+
+  } else if (op.type == GATT_READ_DESC) {
+    act_read_cb = op.read_cb;
+    act_read_cb_data = op.read_cb_data;
+    BTA_GATTC_ReadCharDescr(conn_id, op.handle, BTA_GATT_AUTH_REQ_NONE,
+                            gatt_read_op_finished, NULL);
+
+  } else if (op.type == GATT_WRITE_CHAR) {
+    act_write_cb = op.write_cb;
+    act_write_cb_data = op.write_cb_data;
+    BTA_GATTC_WriteCharValue(conn_id, op.handle, op.write_type,
+                             std::move(op.value), BTA_GATT_AUTH_REQ_NONE,
+                             gatt_write_op_finished, NULL);
+
+  } else if (op.type == GATT_WRITE_DESC) {
+    act_write_cb = op.write_cb;
+    act_write_cb_data = op.write_cb_data;
+    BTA_GATTC_WriteCharDescr(conn_id, op.handle, std::move(op.value),
+                             BTA_GATT_AUTH_REQ_NONE, gatt_write_op_finished,
+                             NULL);
+  }
+
+  gatt_ops.pop_front();
+}
+
+static void gatt_queue_read_op(uint8_t op_type, uint16_t conn_id,
+                               uint16_t handle, GATT_READ_OP_CB cb,
+                               void* cb_data) {
+  gatt_operation op;
+  op.type = op_type;
+  op.handle = handle;
+  op.read_cb = cb;
+  op.read_cb_data = cb_data;
+  gatt_op_queue[conn_id].push_back(op);
+  gatt_execute_next_op(conn_id);
+}
+
+static void gatt_queue_write_op(uint8_t op_type, uint16_t conn_id,
+                                uint16_t handle, vector<uint8_t> value,
+                                tBTA_GATTC_WRITE_TYPE write_type,
+                                GATT_WRITE_OP_CB cb, void* cb_data) {
+  gatt_operation op;
+  op.type = op_type;
+  op.handle = handle;
+  op.write_type = write_type;
+  op.write_cb = cb;
+  op.write_cb_data = cb_data;
+  op.value = std::move(value);
+
+  gatt_op_queue[conn_id].push_back(op);
+  gatt_execute_next_op(conn_id);
+}
+
+#if (BTA_HH_DEBUG == TRUE)
+static const char* bta_hh_le_rpt_name[4] = {"UNKNOWN", "INPUT", "OUTPUT",
+                                            "FEATURE"};
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_hid_report_dbg
+ *
+ * Description      debug function to print out all HID report available on
+ *                  remote device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hh_le_hid_report_dbg(tBTA_HH_DEV_CB* p_cb) {
+  APPL_TRACE_DEBUG("%s: HID Report DB", __func__);
+
+  if (!p_cb->hid_srvc.in_use) return;
+
+  tBTA_HH_LE_RPT* p_rpt = &p_cb->hid_srvc.report[0];
+
+  for (int j = 0; j < BTA_HH_LE_RPT_MAX; j++, p_rpt++) {
+    const char* rpt_name = "Unknown";
+
+    if (!p_rpt->in_use) break;
+
+    if (p_rpt->uuid == GATT_UUID_HID_REPORT) rpt_name = "Report";
+    if (p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT) rpt_name = "Boot KB Input";
+    if (p_rpt->uuid == GATT_UUID_HID_BT_KB_OUTPUT) rpt_name = "Boot KB Output";
+    if (p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT) rpt_name = "Boot MI Input";
+
+    APPL_TRACE_DEBUG(
+        "\t\t [%s- 0x%04x] [Type: %s], [ReportID: %d] [srvc_inst_id: %d] "
+        "[char_inst_id: %d] [Clt_cfg: %d]",
+        rpt_name, p_rpt->uuid,
+        ((p_rpt->rpt_type < 4) ? bta_hh_le_rpt_name[p_rpt->rpt_type]
+                               : "UNKNOWN"),
+        p_rpt->rpt_id, p_rpt->srvc_inst_id, p_rpt->char_inst_id,
+        p_rpt->client_cfg_value);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_uuid_to_str
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static const char* bta_hh_uuid_to_str(uint16_t uuid) {
+  switch (uuid) {
+    case GATT_UUID_HID_INFORMATION:
+      return "GATT_UUID_HID_INFORMATION";
+    case GATT_UUID_HID_REPORT_MAP:
+      return "GATT_UUID_HID_REPORT_MAP";
+    case GATT_UUID_HID_CONTROL_POINT:
+      return "GATT_UUID_HID_CONTROL_POINT";
+    case GATT_UUID_HID_REPORT:
+      return "GATT_UUID_HID_REPORT";
+    case GATT_UUID_HID_PROTO_MODE:
+      return "GATT_UUID_HID_PROTO_MODE";
+    case GATT_UUID_HID_BT_KB_INPUT:
+      return "GATT_UUID_HID_BT_KB_INPUT";
+    case GATT_UUID_HID_BT_KB_OUTPUT:
+      return "GATT_UUID_HID_BT_KB_OUTPUT";
+    case GATT_UUID_HID_BT_MOUSE_INPUT:
+      return "GATT_UUID_HID_BT_MOUSE_INPUT";
+    case GATT_UUID_CHAR_CLIENT_CONFIG:
+      return "GATT_UUID_CHAR_CLIENT_CONFIG";
+    case GATT_UUID_EXT_RPT_REF_DESCR:
+      return "GATT_UUID_EXT_RPT_REF_DESCR";
+    case GATT_UUID_RPT_REF_DESCR:
+      return "GATT_UUID_RPT_REF_DESCR";
+    default:
+      return "Unknown UUID";
+  }
+}
+
+#endif
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_enable
+ *
+ * Description      initialize LE HID related functionality
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_le_enable(void) {
+  char app_name[LEN_UUID_128 + 1];
+  tBT_UUID app_uuid = {LEN_UUID_128, {0}};
+  uint8_t xx;
+
+  bta_hh_cb.gatt_if = BTA_GATTS_INVALID_IF;
+
+  for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++)
+    bta_hh_cb.le_cb_index[xx] = BTA_HH_IDX_INVALID;
+
+  memset(app_name, 0, LEN_UUID_128 + 1);
+  strncpy(app_name, "BTA HH OVER LE", LEN_UUID_128);
+
+  memcpy((void*)app_uuid.uu.uuid128, (void*)app_name, LEN_UUID_128);
+
+  BTA_GATTC_AppRegister(&app_uuid, bta_hh_gattc_callback);
+
+  return;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_register_cmpl
+ *
+ * Description      BTA HH register with BTA GATTC completed
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_le_register_cmpl(tBTA_GATTC_REG* p_reg) {
+  tBTA_HH_STATUS status = BTA_HH_ERR;
+
+  if (p_reg->status == BTA_GATT_OK) {
+    bta_hh_cb.gatt_if = p_reg->client_if;
+    status = BTA_HH_OK;
+  } else
+    bta_hh_cb.gatt_if = BTA_GATTS_INVALID_IF;
+
+  /* signal BTA call back event */
+  (*bta_hh_cb.p_cback)(BTA_HH_ENABLE_EVT, (tBTA_HH*)&status);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_is_hh_gatt_if
+ *
+ * Description      Check to see if client_if is BTA HH LE GATT interface
+ *
+ *
+ * Returns          whether it is HH GATT IF
+ *
+ ******************************************************************************/
+bool bta_hh_le_is_hh_gatt_if(tBTA_GATTC_IF client_if) {
+  return (bta_hh_cb.gatt_if == client_if);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_deregister
+ *
+ * Description      De-register BTA HH from BTA GATTC
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_le_deregister(void) { BTA_GATTC_AppDeregister(bta_hh_cb.gatt_if); }
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_is_le_device
+ *
+ * Description      Check to see if the remote device is a LE only device
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+bool bta_hh_is_le_device(tBTA_HH_DEV_CB* p_cb, BD_ADDR remote_bda) {
+  p_cb->is_le_device = BTM_UseLeLink(remote_bda);
+
+  return p_cb->is_le_device;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_open_conn
+ *
+ * Description      open a GATT connection first.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_le_open_conn(tBTA_HH_DEV_CB* p_cb, BD_ADDR remote_bda) {
+  /* update cb_index[] map */
+  p_cb->hid_handle = BTA_HH_GET_LE_DEV_HDL(p_cb->index);
+  memcpy(p_cb->addr, remote_bda, BD_ADDR_LEN);
+  bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = p_cb->index;
+  p_cb->in_use = true;
+
+  BTA_GATTC_Open(bta_hh_cb.gatt_if, remote_bda, true, BTA_GATT_TRANSPORT_LE);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_find_dev_cb_by_conn_id
+ *
+ * Description      Utility function find a device control block by connection
+ *                  ID.
+ *
+ ******************************************************************************/
+tBTA_HH_DEV_CB* bta_hh_le_find_dev_cb_by_conn_id(uint16_t conn_id) {
+  uint8_t i;
+  tBTA_HH_DEV_CB* p_dev_cb = &bta_hh_cb.kdev[0];
+
+  for (i = 0; i < BTA_HH_MAX_DEVICE; i++, p_dev_cb++) {
+    if (p_dev_cb->in_use && p_dev_cb->conn_id == conn_id) return p_dev_cb;
+  }
+  return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_find_dev_cb_by_bda
+ *
+ * Description      Utility function find a device control block by BD address.
+ *
+ ******************************************************************************/
+tBTA_HH_DEV_CB* bta_hh_le_find_dev_cb_by_bda(BD_ADDR bda) {
+  uint8_t i;
+  tBTA_HH_DEV_CB* p_dev_cb = &bta_hh_cb.kdev[0];
+
+  for (i = 0; i < BTA_HH_MAX_DEVICE; i++, p_dev_cb++) {
+    if (p_dev_cb->in_use && memcmp(p_dev_cb->addr, bda, BD_ADDR_LEN) == 0)
+      return p_dev_cb;
+  }
+  return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_find_service_inst_by_battery_inst_id
+ *
+ * Description      find HID service instance ID by battery service instance ID
+ *
+ ******************************************************************************/
+uint8_t bta_hh_le_find_service_inst_by_battery_inst_id(tBTA_HH_DEV_CB* p_cb,
+                                                       uint8_t ba_inst_id) {
+  if (p_cb->hid_srvc.in_use && p_cb->hid_srvc.incl_srvc_inst == ba_inst_id) {
+    return p_cb->hid_srvc.srvc_inst_id;
+  }
+  return BTA_HH_IDX_INVALID;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_find_report_entry
+ *
+ * Description      find the report entry by service instance and report UUID
+ *                  and instance ID
+ *
+ ******************************************************************************/
+tBTA_HH_LE_RPT* bta_hh_le_find_report_entry(
+    tBTA_HH_DEV_CB* p_cb, uint8_t srvc_inst_id, /* service instance ID */
+    uint16_t rpt_uuid, uint8_t char_inst_id) {
+  uint8_t i;
+  uint8_t hid_inst_id = srvc_inst_id;
+  tBTA_HH_LE_RPT* p_rpt;
+
+  if (rpt_uuid == GATT_UUID_BATTERY_LEVEL) {
+    hid_inst_id =
+        bta_hh_le_find_service_inst_by_battery_inst_id(p_cb, srvc_inst_id);
+
+    if (hid_inst_id == BTA_HH_IDX_INVALID) return NULL;
+  }
+
+  p_rpt = &p_cb->hid_srvc.report[0];
+
+  for (i = 0; i < BTA_HH_LE_RPT_MAX; i++, p_rpt++) {
+    if (p_rpt->uuid == rpt_uuid && p_rpt->srvc_inst_id == srvc_inst_id &&
+        p_rpt->char_inst_id == char_inst_id) {
+      return p_rpt;
+    }
+  }
+  return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_find_rpt_by_idtype
+ *
+ * Description      find a report entry by report ID and protocol mode
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+tBTA_HH_LE_RPT* bta_hh_le_find_rpt_by_idtype(tBTA_HH_LE_RPT* p_head,
+                                             uint8_t mode,
+                                             tBTA_HH_RPT_TYPE r_type,
+                                             uint8_t rpt_id) {
+  tBTA_HH_LE_RPT* p_rpt = p_head;
+  uint8_t i;
+
+#if (BTA_HH_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hh_le_find_rpt_by_idtype: r_type: %d rpt_id: %d",
+                   r_type, rpt_id);
+#endif
+
+  for (i = 0; i < BTA_HH_LE_RPT_MAX; i++, p_rpt++) {
+    if (p_rpt->in_use && p_rpt->rpt_id == rpt_id && r_type == p_rpt->rpt_type) {
+      /* return battery report w/o condition */
+      if (p_rpt->uuid == GATT_UUID_BATTERY_LEVEL) return p_rpt;
+
+      if (mode == BTA_HH_PROTO_RPT_MODE && p_rpt->uuid == GATT_UUID_HID_REPORT)
+        return p_rpt;
+
+      if (mode == BTA_HH_PROTO_BOOT_MODE &&
+          (p_rpt->uuid >= GATT_UUID_HID_BT_KB_INPUT &&
+           p_rpt->uuid <= GATT_UUID_HID_BT_MOUSE_INPUT))
+        return p_rpt;
+    }
+  }
+  return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_find_alloc_report_entry
+ *
+ * Description      find or allocate a report entry in the HID service report
+ *                  list.
+ *
+ ******************************************************************************/
+tBTA_HH_LE_RPT* bta_hh_le_find_alloc_report_entry(tBTA_HH_DEV_CB* p_cb,
+                                                  uint8_t srvc_inst_id,
+                                                  uint16_t rpt_uuid,
+                                                  uint8_t inst_id) {
+  uint8_t i, hid_inst_id = srvc_inst_id;
+  tBTA_HH_LE_RPT* p_rpt;
+
+  if (rpt_uuid == GATT_UUID_BATTERY_LEVEL) {
+    hid_inst_id =
+        bta_hh_le_find_service_inst_by_battery_inst_id(p_cb, srvc_inst_id);
+
+    if (hid_inst_id == BTA_HH_IDX_INVALID) return NULL;
+  }
+  p_rpt = &p_cb->hid_srvc.report[0];
+
+  for (i = 0; i < BTA_HH_LE_RPT_MAX; i++, p_rpt++) {
+    if (!p_rpt->in_use ||
+        (p_rpt->uuid == rpt_uuid && p_rpt->srvc_inst_id == srvc_inst_id &&
+         p_rpt->char_inst_id == inst_id)) {
+      if (!p_rpt->in_use) {
+        p_rpt->in_use = true;
+        p_rpt->index = i;
+        p_rpt->srvc_inst_id = srvc_inst_id;
+        p_rpt->char_inst_id = inst_id;
+        p_rpt->uuid = rpt_uuid;
+
+        /* assign report type */
+        for (i = 0; i < BTA_LE_HID_RTP_UUID_MAX; i++) {
+          if (bta_hh_uuid_to_rtp_type[i][0] == rpt_uuid) {
+            p_rpt->rpt_type = (tBTA_HH_RPT_TYPE)bta_hh_uuid_to_rtp_type[i][1];
+
+            if (rpt_uuid == GATT_UUID_HID_BT_KB_INPUT ||
+                rpt_uuid == GATT_UUID_HID_BT_KB_OUTPUT)
+              p_rpt->rpt_id = BTA_HH_KEYBD_RPT_ID;
+
+            if (rpt_uuid == GATT_UUID_HID_BT_MOUSE_INPUT)
+              p_rpt->rpt_id = BTA_HH_MOUSE_RPT_ID;
+
+            break;
+          }
+        }
+      }
+      return p_rpt;
+    }
+  }
+  return NULL;
+}
+
+static tBTA_GATTC_DESCRIPTOR* find_descriptor_by_short_uuid(
+    uint16_t conn_id, uint16_t char_handle, uint16_t short_uuid) {
+  const tBTA_GATTC_CHARACTERISTIC* p_char =
+      BTA_GATTC_GetCharacteristic(conn_id, char_handle);
+
+  if (!p_char) {
+    LOG_WARN(LOG_TAG, "%s No such characteristic: %d", __func__, char_handle);
+    return NULL;
+  }
+
+  if (!p_char->descriptors || list_is_empty(p_char->descriptors)) return NULL;
+
+  for (list_node_t* dn = list_begin(p_char->descriptors);
+       dn != list_end(p_char->descriptors); dn = list_next(dn)) {
+    tBTA_GATTC_DESCRIPTOR* p_desc = (tBTA_GATTC_DESCRIPTOR*)list_node(dn);
+
+    if (p_char->uuid.len == LEN_UUID_16 && p_desc->uuid.uu.uuid16 == short_uuid)
+      return p_desc;
+  }
+
+  return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_read_char_descriptor
+ *
+ * Description      read characteristic descriptor
+ *
+ ******************************************************************************/
+static tBTA_HH_STATUS bta_hh_le_read_char_descriptor(tBTA_HH_DEV_CB* p_cb,
+                                                     uint16_t char_handle,
+                                                     uint16_t short_uuid,
+                                                     GATT_READ_OP_CB cb,
+                                                     void* cb_data) {
+  const tBTA_GATTC_DESCRIPTOR* p_desc =
+      find_descriptor_by_short_uuid(p_cb->conn_id, char_handle, short_uuid);
+  if (!p_desc) return BTA_HH_ERR;
+
+  gatt_queue_read_op(GATT_READ_DESC, p_cb->conn_id, p_desc->handle, cb,
+                     cb_data);
+  return BTA_HH_OK;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_save_report_ref
+ *
+ * Description      save report reference information and move to next one.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_le_save_report_ref(tBTA_HH_DEV_CB* p_dev_cb, tBTA_HH_LE_RPT* p_rpt,
+                               tGATT_STATUS status, uint8_t* value,
+                               uint16_t len) {
+  if (status == BTA_GATT_INSUF_AUTHENTICATION) {
+    /* close connection right away */
+    p_dev_cb->status = BTA_HH_ERR_AUTH_FAILED;
+    /* close the connection and report service discovery complete with error */
+    bta_hh_le_api_disc_act(p_dev_cb);
+    return;
+  }
+
+  /* if the length of the descriptor value is right, parse it */
+  if (status == BTA_GATT_OK && len == 2) {
+    uint8_t* pp = value;
+
+    STREAM_TO_UINT8(p_rpt->rpt_id, pp);
+    STREAM_TO_UINT8(p_rpt->rpt_type, pp);
+
+    if (p_rpt->rpt_type > BTA_HH_RPTT_FEATURE) /* invalid report type */
+      p_rpt->rpt_type = BTA_HH_RPTT_RESRV;
+
+#if (BTA_HH_DEBUG == TRUE)
+    APPL_TRACE_DEBUG("%s: report ID: %d", __func__, p_rpt->rpt_id);
+#endif
+    tBTA_HH_RPT_CACHE_ENTRY rpt_entry;
+    rpt_entry.rpt_id = p_rpt->rpt_id;
+    rpt_entry.rpt_type = p_rpt->rpt_type;
+    rpt_entry.rpt_uuid = p_rpt->uuid;
+    rpt_entry.srvc_inst_id = p_rpt->srvc_inst_id;
+    rpt_entry.char_inst_id = p_rpt->char_inst_id;
+
+    bta_hh_le_co_rpt_info(p_dev_cb->addr, &rpt_entry, p_dev_cb->app_id);
+  }
+
+  if (p_rpt->index < BTA_HH_LE_RPT_MAX - 1)
+    p_rpt++;
+  else
+    p_rpt = NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_register_input_notif
+ *
+ * Description      Register for all notifications for the report applicable
+ *                  for the protocol mode.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_le_register_input_notif(tBTA_HH_DEV_CB* p_dev_cb,
+                                    uint8_t proto_mode, bool register_ba) {
+  tBTA_HH_LE_RPT* p_rpt = &p_dev_cb->hid_srvc.report[0];
+
+#if (BTA_HH_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("%s: bta_hh_le_register_input_notif mode: %d", __func__,
+                   proto_mode);
+#endif
+
+  for (int i = 0; i < BTA_HH_LE_RPT_MAX; i++, p_rpt++) {
+    if (p_rpt->rpt_type == BTA_HH_RPTT_INPUT) {
+      if (register_ba && p_rpt->uuid == GATT_UUID_BATTERY_LEVEL) {
+        BTA_GATTC_RegisterForNotifications(bta_hh_cb.gatt_if, p_dev_cb->addr,
+                                           p_rpt->char_inst_id);
+      }
+      /* boot mode, deregister report input notification */
+      else if (proto_mode == BTA_HH_PROTO_BOOT_MODE) {
+        if (p_rpt->uuid == GATT_UUID_HID_REPORT &&
+            p_rpt->client_cfg_value == BTA_GATT_CLT_CONFIG_NOTIFICATION) {
+          APPL_TRACE_DEBUG("%s ---> Deregister Report ID: %d", __func__,
+                           p_rpt->rpt_id);
+          BTA_GATTC_DeregisterForNotifications(
+              bta_hh_cb.gatt_if, p_dev_cb->addr, p_rpt->char_inst_id);
+        }
+        /* register boot reports notification */
+        else if (p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT ||
+                 p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT) {
+          APPL_TRACE_DEBUG("%s <--- Register Boot Report ID: %d", __func__,
+                           p_rpt->rpt_id);
+          BTA_GATTC_RegisterForNotifications(bta_hh_cb.gatt_if, p_dev_cb->addr,
+                                             p_rpt->char_inst_id);
+        }
+      } else if (proto_mode == BTA_HH_PROTO_RPT_MODE) {
+        if ((p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT ||
+             p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT) &&
+            p_rpt->client_cfg_value == BTA_GATT_CLT_CONFIG_NOTIFICATION) {
+          APPL_TRACE_DEBUG("%s ---> Deregister Boot Report ID: %d", __func__,
+                           p_rpt->rpt_id);
+          BTA_GATTC_DeregisterForNotifications(
+              bta_hh_cb.gatt_if, p_dev_cb->addr, p_rpt->char_inst_id);
+        } else if (p_rpt->uuid == GATT_UUID_HID_REPORT &&
+                   p_rpt->client_cfg_value ==
+                       BTA_GATT_CLT_CONFIG_NOTIFICATION) {
+          APPL_TRACE_DEBUG("%s <--- Register Report ID: %d", __func__,
+                           p_rpt->rpt_id);
+          BTA_GATTC_RegisterForNotifications(bta_hh_cb.gatt_if, p_dev_cb->addr,
+                                             p_rpt->char_inst_id);
+        }
+      }
+      /*
+      else unknow protocol mode */
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_deregister_input_notif
+ *
+ * Description      Deregister all notifications
+ *
+ ******************************************************************************/
+void bta_hh_le_deregister_input_notif(tBTA_HH_DEV_CB* p_dev_cb) {
+  tBTA_HH_LE_RPT* p_rpt = &p_dev_cb->hid_srvc.report[0];
+
+  for (uint8_t i = 0; i < BTA_HH_LE_RPT_MAX; i++, p_rpt++) {
+    if (p_rpt->rpt_type == BTA_HH_RPTT_INPUT) {
+      if (p_rpt->uuid == GATT_UUID_HID_REPORT &&
+          p_rpt->client_cfg_value == BTA_GATT_CLT_CONFIG_NOTIFICATION) {
+        APPL_TRACE_DEBUG("%s ---> Deregister Report ID: %d", __func__,
+                         p_rpt->rpt_id);
+        BTA_GATTC_DeregisterForNotifications(bta_hh_cb.gatt_if, p_dev_cb->addr,
+                                             p_rpt->char_inst_id);
+      } else if ((p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT ||
+                  p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT) &&
+                 p_rpt->client_cfg_value == BTA_GATT_CLT_CONFIG_NOTIFICATION) {
+        APPL_TRACE_DEBUG("%s ---> Deregister Boot Report ID: %d", __func__,
+                         p_rpt->rpt_id);
+        BTA_GATTC_DeregisterForNotifications(bta_hh_cb.gatt_if, p_dev_cb->addr,
+                                             p_rpt->char_inst_id);
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_open_cmpl
+ *
+ * Description      HID over GATT connection sucessfully opened
+ *
+ ******************************************************************************/
+void bta_hh_le_open_cmpl(tBTA_HH_DEV_CB* p_cb) {
+  if (p_cb->disc_active == BTA_HH_LE_DISC_NONE) {
+#if (BTA_HH_DEBUG == TRUE)
+    bta_hh_le_hid_report_dbg(p_cb);
+#endif
+    bta_hh_le_register_input_notif(p_cb, p_cb->mode, true);
+    bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, NULL);
+
+#if (BTA_HH_LE_RECONN == TRUE)
+    if (p_cb->status == BTA_HH_OK) {
+      bta_hh_le_add_dev_bg_conn(p_cb, true);
+    }
+#endif
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_write_ccc
+ *
+ * Description      Utility function to find and write client configuration of
+ *                  a characteristic
+ *
+ ******************************************************************************/
+bool bta_hh_le_write_ccc(tBTA_HH_DEV_CB* p_cb, uint8_t char_handle,
+                         uint16_t clt_cfg_value, GATT_WRITE_OP_CB cb,
+                         void* cb_data) {
+  tBTA_GATTC_DESCRIPTOR* p_desc = find_descriptor_by_short_uuid(
+      p_cb->conn_id, char_handle, GATT_UUID_CHAR_CLIENT_CONFIG);
+  if (!p_desc) return false;
+
+  vector<uint8_t> value(2);
+  uint8_t* ptr = value.data();
+  UINT16_TO_STREAM(ptr, clt_cfg_value);
+
+  gatt_queue_write_op(GATT_WRITE_DESC, p_cb->conn_id, p_desc->handle,
+                      std::move(value), BTA_GATTC_TYPE_WRITE, cb, cb_data);
+  return true;
+}
+
+bool bta_hh_le_write_rpt_clt_cfg(tBTA_HH_DEV_CB* p_cb);
+
+static void write_rpt_ctl_cfg_cb(uint16_t conn_id, tGATT_STATUS status,
+                                 uint16_t handle, void* data) {
+  uint8_t srvc_inst_id, hid_inst_id;
+
+  tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
+  const tBTA_GATTC_DESCRIPTOR* p_desc =
+      BTA_GATTC_GetDescriptor(conn_id, handle);
+
+  uint16_t char_uuid = p_desc->characteristic->uuid.uu.uuid16;
+
+  srvc_inst_id = p_desc->characteristic->service->handle;
+  hid_inst_id = srvc_inst_id;
+  switch (char_uuid) {
+    case GATT_UUID_BATTERY_LEVEL: /* battery level clt cfg registered */
+      hid_inst_id = bta_hh_le_find_service_inst_by_battery_inst_id(
+          p_dev_cb, srvc_inst_id);
+    /* FALLTHROUGH */
+    case GATT_UUID_HID_BT_KB_INPUT:
+    case GATT_UUID_HID_BT_MOUSE_INPUT:
+    case GATT_UUID_HID_REPORT:
+      if (status == BTA_GATT_OK)
+        p_dev_cb->hid_srvc.report[p_dev_cb->clt_cfg_idx].client_cfg_value =
+            BTA_GATT_CLT_CONFIG_NOTIFICATION;
+      p_dev_cb->clt_cfg_idx++;
+      bta_hh_le_write_rpt_clt_cfg(p_dev_cb);
+      break;
+
+    default:
+      APPL_TRACE_ERROR("Unknown char ID clt cfg: 0x%04x", char_uuid);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_write_rpt_clt_cfg
+ *
+ * Description      write client configuration. This is only for input report
+ *                  enable all input notification upon connection open.
+ *
+ ******************************************************************************/
+bool bta_hh_le_write_rpt_clt_cfg(tBTA_HH_DEV_CB* p_cb) {
+  uint8_t i;
+  tBTA_HH_LE_RPT* p_rpt = &p_cb->hid_srvc.report[p_cb->clt_cfg_idx];
+
+  for (i = p_cb->clt_cfg_idx; i < BTA_HH_LE_RPT_MAX && p_rpt->in_use;
+       i++, p_rpt++) {
+    /* enable notification for all input report, regardless mode */
+    if (p_rpt->rpt_type == BTA_HH_RPTT_INPUT) {
+      if (bta_hh_le_write_ccc(p_cb, p_rpt->char_inst_id,
+                              BTA_GATT_CLT_CONFIG_NOTIFICATION,
+                              write_rpt_ctl_cfg_cb, p_cb)) {
+        p_cb->clt_cfg_idx = i;
+        return true;
+      }
+    }
+  }
+  p_cb->clt_cfg_idx = 0;
+
+  /* client configuration is completed, send open callback */
+  if (p_cb->state == BTA_HH_W4_CONN_ST) {
+    p_cb->disc_active &= ~BTA_HH_LE_DISC_HIDS;
+
+    bta_hh_le_open_cmpl(p_cb);
+  }
+  return false;
+}
+
+static void write_proto_mode_cb(uint16_t conn_id, tGATT_STATUS status,
+                                uint16_t handle, void* data) {
+  tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
+
+  if (p_dev_cb->state == BTA_HH_CONN_ST) {
+    /* Set protocol finished in CONN state*/
+
+    uint16_t cb_evt = p_dev_cb->w4_evt;
+    if (cb_evt == 0) return;
+
+    tBTA_HH_CBDATA cback_data;
+
+    cback_data.handle = p_dev_cb->hid_handle;
+    cback_data.status = (status == BTA_GATT_OK) ? BTA_HH_OK : BTA_HH_ERR;
+
+    if (status == BTA_GATT_OK)
+      bta_hh_le_register_input_notif(p_dev_cb, p_dev_cb->mode, false);
+
+    p_dev_cb->w4_evt = 0;
+    (*bta_hh_cb.p_cback)(cb_evt, (tBTA_HH*)&cback_data);
+  } else if (p_dev_cb->state == BTA_HH_W4_CONN_ST) {
+    p_dev_cb->status = (status == BTA_GATT_OK) ? BTA_HH_OK : BTA_HH_ERR_PROTO;
+
+    if ((p_dev_cb->disc_active & BTA_HH_LE_DISC_HIDS) == 0)
+      bta_hh_le_open_cmpl(p_dev_cb);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_set_protocol_mode
+ *
+ * Description      Set remote device protocol mode.
+ *
+ ******************************************************************************/
+bool bta_hh_le_set_protocol_mode(tBTA_HH_DEV_CB* p_cb,
+                                 tBTA_HH_PROTO_MODE mode) {
+  tBTA_HH_CBDATA cback_data;
+
+  APPL_TRACE_DEBUG("%s attempt mode: %s", __func__,
+                   (mode == BTA_HH_PROTO_RPT_MODE) ? "Report" : "Boot");
+
+  cback_data.handle = p_cb->hid_handle;
+  /* boot mode is not supported in the remote device */
+  if (p_cb->hid_srvc.proto_mode_handle == 0) {
+    p_cb->mode = BTA_HH_PROTO_RPT_MODE;
+
+    if (mode == BTA_HH_PROTO_BOOT_MODE) {
+      APPL_TRACE_ERROR("Set Boot Mode failed!! No PROTO_MODE Char!");
+      cback_data.status = BTA_HH_ERR;
+    } else {
+      /* if set to report mode, need to de-register all input report
+       * notification */
+      bta_hh_le_register_input_notif(p_cb, p_cb->mode, false);
+      cback_data.status = BTA_HH_OK;
+    }
+    if (p_cb->state == BTA_HH_W4_CONN_ST) {
+      p_cb->status =
+          (cback_data.status == BTA_HH_OK) ? BTA_HH_OK : BTA_HH_ERR_PROTO;
+    } else
+      (*bta_hh_cb.p_cback)(BTA_HH_SET_PROTO_EVT, (tBTA_HH*)&cback_data);
+  } else if (p_cb->mode != mode) {
+    p_cb->mode = mode;
+    mode = (mode == BTA_HH_PROTO_BOOT_MODE) ? BTA_HH_LE_PROTO_BOOT_MODE
+                                            : BTA_HH_LE_PROTO_REPORT_MODE;
+
+    gatt_queue_write_op(GATT_WRITE_CHAR, p_cb->conn_id,
+                        p_cb->hid_srvc.proto_mode_handle, {mode},
+                        BTA_GATTC_TYPE_WRITE_NO_RSP, write_proto_mode_cb, p_cb);
+    return true;
+  }
+
+  return false;
+}
+
+/*******************************************************************************
+ * Function         get_protocol_mode_cb
+ *
+ * Description      Process the Read protocol mode, send GET_PROTO_EVT to
+ *                  application with the protocol mode.
+ *
+ ******************************************************************************/
+static void get_protocol_mode_cb(uint16_t conn_id, tGATT_STATUS status,
+                                 uint16_t handle, uint16_t len, uint8_t* value,
+                                 void* data) {
+  tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
+  tBTA_HH_HSDATA hs_data;
+
+  hs_data.status = BTA_HH_ERR;
+  hs_data.handle = p_dev_cb->hid_handle;
+  hs_data.rsp_data.proto_mode = p_dev_cb->mode;
+
+  if (status == BTA_GATT_OK && len) {
+    hs_data.status = BTA_HH_OK;
+    /* match up BTE/BTA report/boot mode def*/
+    hs_data.rsp_data.proto_mode = *(value);
+    /* LE repot mode is the opposite value of BR/EDR report mode, flip it here
+     */
+    if (hs_data.rsp_data.proto_mode == 0)
+      hs_data.rsp_data.proto_mode = BTA_HH_PROTO_BOOT_MODE;
+    else
+      hs_data.rsp_data.proto_mode = BTA_HH_PROTO_RPT_MODE;
+
+    p_dev_cb->mode = hs_data.rsp_data.proto_mode;
+  }
+
+#if (BTA_HH_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("LE GET_PROTOCOL Mode = [%s]",
+                   (hs_data.rsp_data.proto_mode == BTA_HH_PROTO_RPT_MODE)
+                       ? "Report"
+                       : "Boot");
+#endif
+
+  p_dev_cb->w4_evt = 0;
+  (*bta_hh_cb.p_cback)(BTA_HH_GET_PROTO_EVT, (tBTA_HH*)&hs_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_get_protocol_mode
+ *
+ * Description      Get remote device protocol mode.
+ *
+ ******************************************************************************/
+void bta_hh_le_get_protocol_mode(tBTA_HH_DEV_CB* p_cb) {
+  tBTA_HH_HSDATA hs_data;
+  p_cb->w4_evt = BTA_HH_GET_PROTO_EVT;
+
+  if (p_cb->hid_srvc.in_use && p_cb->hid_srvc.proto_mode_handle != 0) {
+    gatt_queue_read_op(GATT_READ_CHAR, p_cb->conn_id,
+                       p_cb->hid_srvc.proto_mode_handle, get_protocol_mode_cb,
+                       p_cb);
+    return;
+  }
+
+  /* no service support protocol_mode, by default report mode */
+  hs_data.status = BTA_HH_OK;
+  hs_data.handle = p_cb->hid_handle;
+  hs_data.rsp_data.proto_mode = BTA_HH_PROTO_RPT_MODE;
+  p_cb->w4_evt = 0;
+  (*bta_hh_cb.p_cback)(BTA_HH_GET_PROTO_EVT, (tBTA_HH*)&hs_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_dis_cback
+ *
+ * Description      DIS read complete callback
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_le_dis_cback(BD_ADDR addr, tDIS_VALUE* p_dis_value) {
+  tBTA_HH_DEV_CB* p_cb = bta_hh_le_find_dev_cb_by_bda(addr);
+
+  if (p_cb == NULL || p_dis_value == NULL) {
+    APPL_TRACE_ERROR("received unexpected/error DIS callback");
+    return;
+  }
+
+  p_cb->disc_active &= ~BTA_HH_LE_DISC_DIS;
+  /* plug in the PnP info for this device */
+  if (p_dis_value->attr_mask & DIS_ATTR_PNP_ID_BIT) {
+#if (BTA_HH_DEBUG == TRUE)
+    APPL_TRACE_DEBUG(
+        "Plug in PnP info: product_id = %02x, vendor_id = %04x, version = %04x",
+        p_dis_value->pnp_id.product_id, p_dis_value->pnp_id.vendor_id,
+        p_dis_value->pnp_id.product_version);
+#endif
+    p_cb->dscp_info.product_id = p_dis_value->pnp_id.product_id;
+    p_cb->dscp_info.vendor_id = p_dis_value->pnp_id.vendor_id;
+    p_cb->dscp_info.version = p_dis_value->pnp_id.product_version;
+  }
+  bta_hh_le_open_cmpl(p_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_pri_service_discovery
+ *
+ * Description      Initialize GATT discovery on the remote LE HID device by
+ *                  opening a GATT connection first.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_le_pri_service_discovery(tBTA_HH_DEV_CB* p_cb) {
+  tBT_UUID pri_srvc;
+
+  bta_hh_le_co_reset_rpt_cache(p_cb->addr, p_cb->app_id);
+
+  p_cb->disc_active |= (BTA_HH_LE_DISC_HIDS | BTA_HH_LE_DISC_DIS);
+
+  /* read DIS info */
+  if (!DIS_ReadDISInfo(p_cb->addr, bta_hh_le_dis_cback, DIS_ATTR_PNP_ID_BIT)) {
+    APPL_TRACE_ERROR("read DIS failed");
+    p_cb->disc_active &= ~BTA_HH_LE_DISC_DIS;
+  }
+
+  /* in parallel */
+  /* start primary service discovery for HID service */
+  pri_srvc.len = LEN_UUID_16;
+  pri_srvc.uu.uuid16 = UUID_SERVCLASS_LE_HID;
+  BTA_GATTC_ServiceSearchRequest(p_cb->conn_id, &pri_srvc);
+  return;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_encrypt_cback
+ *
+ * Description      link encryption complete callback for bond verification.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void bta_hh_le_encrypt_cback(BD_ADDR bd_addr,
+                             UNUSED_ATTR tBTA_GATT_TRANSPORT transport,
+                             UNUSED_ATTR void* p_ref_data, tBTM_STATUS result) {
+  uint8_t idx = bta_hh_find_cb(bd_addr);
+  tBTA_HH_DEV_CB* p_dev_cb;
+
+  if (idx != BTA_HH_IDX_INVALID)
+    p_dev_cb = &bta_hh_cb.kdev[idx];
+  else {
+    APPL_TRACE_ERROR("unexpected encryption callback, ignore");
+    return;
+  }
+  p_dev_cb->status = (result == BTM_SUCCESS) ? BTA_HH_OK : BTA_HH_ERR_SEC;
+  p_dev_cb->reason = result;
+
+  bta_hh_sm_execute(p_dev_cb, BTA_HH_ENC_CMPL_EVT, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_security_cmpl
+ *
+ * Description      Security check completed, start the service discovery
+ *                  if no cache available, otherwise report connection open
+ *                  completed
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_security_cmpl(tBTA_HH_DEV_CB* p_cb,
+                          UNUSED_ATTR tBTA_HH_DATA* p_buf) {
+  APPL_TRACE_DEBUG("%s", __func__);
+  if (p_cb->status == BTA_HH_OK) {
+    if (!p_cb->hid_srvc.in_use) {
+      APPL_TRACE_DEBUG("bta_hh_security_cmpl no reports loaded, try to load");
+
+      /* start loading the cache if not in stack */
+      // TODO(jpawlowski): cache storage is broken, fix it
+      // tBTA_HH_RPT_CACHE_ENTRY     *p_rpt_cache;
+      // uint8_t                       num_rpt = 0;
+      // if ((p_rpt_cache = bta_hh_le_co_cache_load(p_cb->addr, &num_rpt,
+      // p_cb->app_id)) != NULL)
+      // {
+      //     bta_hh_process_cache_rpt(p_cb, p_rpt_cache, num_rpt);
+      // }
+    }
+    /*  discovery has been done for HID service */
+    if (p_cb->app_id != 0 && p_cb->hid_srvc.in_use) {
+      APPL_TRACE_DEBUG("%s: discovery has been done for HID service", __func__);
+      /* configure protocol mode */
+      if (bta_hh_le_set_protocol_mode(p_cb, p_cb->mode) == false) {
+        bta_hh_le_open_cmpl(p_cb);
+      }
+    }
+    /* start primary service discovery for HID service */
+    else {
+      APPL_TRACE_DEBUG("%s: Starting service discovery", __func__);
+      bta_hh_le_pri_service_discovery(p_cb);
+    }
+  } else {
+    APPL_TRACE_ERROR("%s() - encryption failed; status=0x%04x, reason=0x%04x",
+                     __func__, p_cb->status, p_cb->reason);
+    if (!(p_cb->status == BTA_HH_ERR_SEC && p_cb->reason == BTM_ERR_PROCESSING))
+      bta_hh_le_api_disc_act(p_cb);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_notify_enc_cmpl
+ *
+ * Description      process GATT encryption complete event
+ *
+ * Returns
+ *
+ ******************************************************************************/
+void bta_hh_le_notify_enc_cmpl(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_buf) {
+  if (p_cb == NULL || p_cb->security_pending == false || p_buf == NULL ||
+      p_buf->le_enc_cmpl.client_if != bta_hh_cb.gatt_if) {
+    return;
+  }
+
+  p_cb->security_pending = false;
+  bta_hh_start_security(p_cb, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_clear_service_cache
+ *
+ * Description      clear the service cache
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_clear_service_cache(tBTA_HH_DEV_CB* p_cb) {
+  tBTA_HH_LE_HID_SRVC* p_hid_srvc = &p_cb->hid_srvc;
+
+  p_cb->app_id = 0;
+  p_cb->dscp_info.descriptor.dsc_list = NULL;
+
+  osi_free_and_reset((void**)&p_hid_srvc->rpt_map);
+  memset(p_hid_srvc, 0, sizeof(tBTA_HH_LE_HID_SRVC));
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_start_security
+ *
+ * Description      start the security check of the established connection
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_start_security(tBTA_HH_DEV_CB* p_cb,
+                           UNUSED_ATTR tBTA_HH_DATA* p_buf) {
+  uint8_t sec_flag = 0;
+  tBTM_SEC_DEV_REC* p_dev_rec;
+
+  p_dev_rec = btm_find_dev(p_cb->addr);
+  if (p_dev_rec) {
+    if (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING ||
+        p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) {
+      /* if security collision happened, wait for encryption done */
+      p_cb->security_pending = true;
+      return;
+    }
+  }
+
+  /* verify bond */
+  BTM_GetSecurityFlagsByTransport(p_cb->addr, &sec_flag, BT_TRANSPORT_LE);
+
+  /* if link has been encrypted */
+  if (sec_flag & BTM_SEC_FLAG_ENCRYPTED) {
+    bta_hh_sm_execute(p_cb, BTA_HH_ENC_CMPL_EVT, NULL);
+  }
+  /* if bonded and link not encrypted */
+  else if (sec_flag & BTM_SEC_FLAG_LKEY_KNOWN) {
+    sec_flag = BTM_BLE_SEC_ENCRYPT;
+    p_cb->status = BTA_HH_ERR_AUTH_FAILED;
+    BTM_SetEncryption(p_cb->addr, BTA_TRANSPORT_LE, bta_hh_le_encrypt_cback,
+                      NULL, sec_flag);
+  }
+  /* unbonded device, report security error here */
+  else if (p_cb->sec_mask != BTA_SEC_NONE) {
+    sec_flag = BTM_BLE_SEC_ENCRYPT_NO_MITM;
+    p_cb->status = BTA_HH_ERR_AUTH_FAILED;
+    bta_hh_clear_service_cache(p_cb);
+    BTM_SetEncryption(p_cb->addr, BTA_TRANSPORT_LE, bta_hh_le_encrypt_cback,
+                      NULL, sec_flag);
+  }
+  /* otherwise let it go through */
+  else {
+    bta_hh_sm_execute(p_cb, BTA_HH_ENC_CMPL_EVT, NULL);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_gatt_open
+ *
+ * Description      process GATT open event.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_gatt_open(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_buf) {
+  tBTA_GATTC_OPEN* p_data = &p_buf->le_open;
+  uint8_t* p2;
+  tHID_STATUS status = BTA_HH_ERR;
+
+  /* if received invalid callback data , ignore it */
+  if (p_cb == NULL || p_data == NULL) return;
+
+  p2 = p_data->remote_bda;
+
+  APPL_TRACE_DEBUG(
+      "bta_hh_gatt_open BTA_GATTC_OPEN_EVT bda= [%08x%04x] status =%d",
+      ((p2[0]) << 24) + ((p2[1]) << 16) + ((p2[2]) << 8) + (p2[3]),
+      ((p2[4]) << 8) + p2[5], p_data->status);
+
+  if (p_data->status == BTA_GATT_OK) {
+    p_cb->is_le_device = true;
+    p_cb->in_use = true;
+    p_cb->conn_id = p_data->conn_id;
+    p_cb->hid_handle = BTA_HH_GET_LE_DEV_HDL(p_cb->index);
+
+    bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = p_cb->index;
+
+    gatt_op_queue_clean(p_cb->conn_id);
+
+#if (BTA_HH_DEBUG == TRUE)
+    APPL_TRACE_DEBUG("hid_handle = %2x conn_id = %04x cb_index = %d",
+                     p_cb->hid_handle, p_cb->conn_id, p_cb->index);
+#endif
+
+    bta_hh_sm_execute(p_cb, BTA_HH_START_ENC_EVT, NULL);
+
+  } else /* open failure */
+  {
+    bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA*)&status);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_close
+ *
+ * Description      This function process the GATT close event and post it as a
+ *                  BTA HH internal event
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_le_close(tBTA_GATTC_CLOSE* p_data) {
+  tBTA_HH_DEV_CB* p_dev_cb = bta_hh_le_find_dev_cb_by_bda(p_data->remote_bda);
+  uint16_t sm_event = BTA_HH_GATT_CLOSE_EVT;
+
+  if (p_dev_cb != NULL) {
+    tBTA_HH_LE_CLOSE* p_buf =
+        (tBTA_HH_LE_CLOSE*)osi_malloc(sizeof(tBTA_HH_LE_CLOSE));
+    p_buf->hdr.event = sm_event;
+    p_buf->hdr.layer_specific = (uint16_t)p_dev_cb->hid_handle;
+    p_buf->conn_id = p_data->conn_id;
+    p_buf->reason = p_data->reason;
+
+    p_dev_cb->conn_id = BTA_GATT_INVALID_CONN_ID;
+    p_dev_cb->security_pending = false;
+    bta_sys_sendmsg(p_buf);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_gatt_disc_cmpl
+ *
+ * Description      Check to see if the remote device is a LE only device
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_le_gatt_disc_cmpl(tBTA_HH_DEV_CB* p_cb, tBTA_HH_STATUS status) {
+  APPL_TRACE_DEBUG("bta_hh_le_gatt_disc_cmpl ");
+
+  /* if open sucessful or protocol mode not desired, keep the connection open
+   * but inform app */
+  if (status == BTA_HH_OK || status == BTA_HH_ERR_PROTO) {
+    /* assign a special APP ID temp, since device type unknown */
+    p_cb->app_id = BTA_HH_APP_ID_LE;
+
+    /* set report notification configuration */
+    p_cb->clt_cfg_idx = 0;
+    bta_hh_le_write_rpt_clt_cfg(p_cb);
+  } else /* error, close the GATT connection */
+  {
+    /* close GATT connection if it's on */
+    bta_hh_le_api_disc_act(p_cb);
+  }
+}
+
+static void read_hid_info_cb(uint16_t conn_id, tGATT_STATUS status,
+                             uint16_t handle, uint16_t len, uint8_t* value,
+                             void* data) {
+  if (status != BTA_GATT_OK) {
+    APPL_TRACE_ERROR("%s: error: %d", __func__, status);
+    return;
+  }
+
+  if (len != 4) {
+    APPL_TRACE_ERROR("%s: wrong length: %d", __func__, len);
+    return;
+  }
+
+  tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
+  uint8_t* pp = value;
+  /* save device information */
+  STREAM_TO_UINT16(p_dev_cb->dscp_info.version, pp);
+  STREAM_TO_UINT8(p_dev_cb->dscp_info.ctry_code, pp);
+  STREAM_TO_UINT8(p_dev_cb->dscp_info.flag, pp);
+}
+
+static void read_hid_report_map_cb(uint16_t conn_id, tGATT_STATUS status,
+                                   uint16_t handle, uint16_t len,
+                                   uint8_t* value, void* data) {
+  if (status != BTA_GATT_OK) {
+    APPL_TRACE_ERROR("%s: error reading characteristic: %d", __func__, status);
+    return;
+  }
+
+  tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
+  tBTA_HH_LE_HID_SRVC* p_srvc = &p_dev_cb->hid_srvc;
+
+  osi_free_and_reset((void**)&p_srvc->rpt_map);
+
+  if (len > 0) {
+    p_srvc->rpt_map = (uint8_t*)osi_malloc(len);
+
+    uint8_t* pp = value;
+    STREAM_TO_ARRAY(p_srvc->rpt_map, pp, len);
+    p_srvc->descriptor.dl_len = len;
+    p_srvc->descriptor.dsc_list = p_dev_cb->hid_srvc.rpt_map;
+  }
+}
+
+static void read_ext_rpt_ref_desc_cb(uint16_t conn_id, tGATT_STATUS status,
+                                     uint16_t handle, uint16_t len,
+                                     uint8_t* value, void* data) {
+  if (status != BTA_GATT_OK) {
+    APPL_TRACE_ERROR("%s: error: %d", __func__, status);
+    return;
+  }
+
+  /* if the length of the descriptor value is right, parse it assume it's a 16
+   * bits UUID */
+  if (len != LEN_UUID_16) {
+    APPL_TRACE_ERROR("%s: we support only 16bit UUID: %d", __func__, len);
+    return;
+  }
+
+  tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
+  uint8_t* pp = value;
+
+  STREAM_TO_UINT16(p_dev_cb->hid_srvc.ext_rpt_ref, pp);
+
+#if (BTA_HH_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("%s: External Report Reference UUID 0x%04x", __func__,
+                   p_dev_cb->hid_srvc.ext_rpt_ref);
+#endif
+}
+
+static void read_report_ref_desc_cb(uint16_t conn_id, tGATT_STATUS status,
+                                    uint16_t handle, uint16_t len,
+                                    uint8_t* value, void* data) {
+  if (status != BTA_GATT_OK) {
+    APPL_TRACE_ERROR("%s: error: %d", __func__, status);
+    return;
+  }
+
+  tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
+  const tBTA_GATTC_DESCRIPTOR* p_desc =
+      BTA_GATTC_GetDescriptor(conn_id, handle);
+
+  tBTA_HH_LE_RPT* p_rpt;
+  if ((p_rpt = bta_hh_le_find_report_entry(
+           p_dev_cb, p_desc->characteristic->service->handle,
+           GATT_UUID_HID_REPORT, p_desc->characteristic->handle)))
+    bta_hh_le_save_report_ref(p_dev_cb, p_rpt, status, value, len);
+}
+
+void read_pref_conn_params_cb(uint16_t conn_id, tGATT_STATUS status,
+                              uint16_t handle, uint16_t len, uint8_t* value,
+                              void* data) {
+  if (status != BTA_GATT_OK) {
+    APPL_TRACE_ERROR("%s: error: %d", __func__, status);
+    return;
+  }
+
+  if (len != 8) {
+    APPL_TRACE_ERROR("%s: we support only 16bit UUID: %d", __func__, len);
+    return;
+  }
+
+  // TODO(jpawlowski): this should be done by GAP profile, remove when GAP is
+  // fixed.
+  uint8_t* pp = value;
+  uint16_t min, max, latency, tout;
+  STREAM_TO_UINT16(min, pp);
+  STREAM_TO_UINT16(max, pp);
+  STREAM_TO_UINT16(latency, pp);
+  STREAM_TO_UINT16(tout, pp);
+
+  // Make sure both min, and max are bigger than 11.25ms, lower values can
+  // introduce
+  // audio issues if A2DP is also active.
+  if (min < BTM_BLE_CONN_INT_MIN_LIMIT) min = BTM_BLE_CONN_INT_MIN_LIMIT;
+  if (max < BTM_BLE_CONN_INT_MIN_LIMIT) max = BTM_BLE_CONN_INT_MIN_LIMIT;
+
+  // If the device has no preferred connection timeout, use the default.
+  if (tout == BTM_BLE_CONN_PARAM_UNDEF) tout = BTM_BLE_CONN_TIMEOUT_DEF;
+
+  tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
+  BTM_BleSetPrefConnParams(p_dev_cb->addr, min, max, latency, tout);
+  L2CA_UpdateBleConnParams(p_dev_cb->addr, min, max, latency, tout);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_search_hid_chars
+ *
+ * Description      This function discover all characteristics a service and
+ *                  all descriptors available.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+static void bta_hh_le_search_hid_chars(tBTA_HH_DEV_CB* p_dev_cb,
+                                       tBTA_GATTC_SERVICE* service) {
+  tBTA_HH_LE_RPT* p_rpt;
+
+  for (list_node_t* cn = list_begin(service->characteristics);
+       cn != list_end(service->characteristics); cn = list_next(cn)) {
+    tBTA_GATTC_CHARACTERISTIC* p_char =
+        (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
+
+    if (p_char->uuid.len != LEN_UUID_16) continue;
+
+    LOG_DEBUG(LOG_TAG, "%s: %s 0x%04d", __func__,
+              bta_hh_uuid_to_str(p_char->uuid.uu.uuid16),
+              p_char->uuid.uu.uuid16);
+
+    switch (p_char->uuid.uu.uuid16) {
+      case GATT_UUID_HID_CONTROL_POINT:
+        p_dev_cb->hid_srvc.control_point_handle = p_char->handle;
+        break;
+      case GATT_UUID_HID_INFORMATION:
+        /* only one instance per HID service */
+        gatt_queue_read_op(GATT_READ_CHAR, p_dev_cb->conn_id, p_char->handle,
+                           read_hid_info_cb, p_dev_cb);
+        break;
+      case GATT_UUID_HID_REPORT_MAP:
+        /* only one instance per HID service */
+        gatt_queue_read_op(GATT_READ_CHAR, p_dev_cb->conn_id, p_char->handle,
+                           read_hid_report_map_cb, p_dev_cb);
+        /* descriptor is optional */
+        bta_hh_le_read_char_descriptor(p_dev_cb, p_char->handle,
+                                       GATT_UUID_EXT_RPT_REF_DESCR,
+                                       read_ext_rpt_ref_desc_cb, p_dev_cb);
+        break;
+
+      case GATT_UUID_HID_REPORT:
+        p_rpt = bta_hh_le_find_alloc_report_entry(
+            p_dev_cb, p_dev_cb->hid_srvc.srvc_inst_id, GATT_UUID_HID_REPORT,
+            p_char->handle);
+        if (p_rpt == NULL) {
+          APPL_TRACE_ERROR("%s: Add report entry failed !!!", __func__);
+          break;
+        }
+
+        if (p_rpt->rpt_type != BTA_HH_RPTT_INPUT) break;
+
+        bta_hh_le_read_char_descriptor(p_dev_cb, p_char->handle,
+                                       GATT_UUID_RPT_REF_DESCR,
+                                       read_report_ref_desc_cb, p_dev_cb);
+        break;
+
+      /* found boot mode report types */
+      case GATT_UUID_HID_BT_KB_OUTPUT:
+      case GATT_UUID_HID_BT_MOUSE_INPUT:
+      case GATT_UUID_HID_BT_KB_INPUT:
+        if (bta_hh_le_find_alloc_report_entry(p_dev_cb, service->handle,
+                                              p_char->uuid.uu.uuid16,
+                                              p_char->handle) == NULL)
+          APPL_TRACE_ERROR("%s: Add report entry failed !!!", __func__);
+
+        break;
+
+      default:
+        APPL_TRACE_DEBUG("%s: not processing %s 0x%04d", __func__,
+                         bta_hh_uuid_to_str(p_char->uuid.uu.uuid16),
+                         p_char->uuid.uu.uuid16);
+    }
+  }
+
+  /* Make sure PROTO_MODE is processed as last */
+  for (list_node_t* cn = list_begin(service->characteristics);
+       cn != list_end(service->characteristics); cn = list_next(cn)) {
+    tBTA_GATTC_CHARACTERISTIC* p_char =
+        (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
+
+    if (p_char->uuid.len != LEN_UUID_16 &&
+        p_char->uuid.uu.uuid16 == GATT_UUID_HID_PROTO_MODE) {
+      p_dev_cb->hid_srvc.proto_mode_handle = p_char->handle;
+      bta_hh_le_set_protocol_mode(p_dev_cb, p_dev_cb->mode);
+      break;
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_srvc_search_cmpl
+ *
+ * Description      This function process the GATT service search complete.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_le_srvc_search_cmpl(tBTA_GATTC_SEARCH_CMPL* p_data) {
+  tBTA_HH_DEV_CB* p_dev_cb = bta_hh_le_find_dev_cb_by_conn_id(p_data->conn_id);
+
+  /* service search exception or no HID service is supported on remote */
+  if (p_dev_cb == NULL) return;
+
+  if (p_data->status != BTA_GATT_OK) {
+    p_dev_cb->status = BTA_HH_ERR_SDP;
+    /* close the connection and report service discovery complete with error */
+    bta_hh_le_api_disc_act(p_dev_cb);
+    return;
+  }
+
+  const list_t* services = BTA_GATTC_GetServices(p_data->conn_id);
+
+  bool have_hid = false;
+  for (list_node_t* sn = list_begin(services); sn != list_end(services);
+       sn = list_next(sn)) {
+    tBTA_GATTC_SERVICE* service = (tBTA_GATTC_SERVICE*)list_node(sn);
+
+    if (service->uuid.uu.uuid16 == UUID_SERVCLASS_LE_HID &&
+        service->is_primary && !have_hid) {
+      have_hid = true;
+
+      /* found HID primamry service */
+      p_dev_cb->hid_srvc.in_use = true;
+      p_dev_cb->hid_srvc.srvc_inst_id = service->handle;
+      p_dev_cb->hid_srvc.proto_mode_handle = 0;
+      p_dev_cb->hid_srvc.control_point_handle = 0;
+
+      bta_hh_le_search_hid_chars(p_dev_cb, service);
+
+      APPL_TRACE_DEBUG("%s: have HID service inst_id= %d", __func__,
+                       p_dev_cb->hid_srvc.srvc_inst_id);
+    } else if (service->uuid.uu.uuid16 == UUID_SERVCLASS_SCAN_PARAM) {
+      p_dev_cb->scan_refresh_char_handle = 0;
+
+      for (list_node_t* cn = list_begin(service->characteristics);
+           cn != list_end(service->characteristics); cn = list_next(cn)) {
+        tBTA_GATTC_CHARACTERISTIC* p_char =
+            (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
+        if (p_char->uuid.len == LEN_UUID_16 &&
+            p_char->uuid.uu.uuid16 == GATT_UUID_SCAN_REFRESH) {
+          p_dev_cb->scan_refresh_char_handle = p_char->handle;
+
+          if (p_char->properties & BTA_GATT_CHAR_PROP_BIT_NOTIFY)
+            p_dev_cb->scps_notify |= BTA_HH_LE_SCPS_NOTIFY_SPT;
+          else
+            p_dev_cb->scps_notify = BTA_HH_LE_SCPS_NOTIFY_NONE;
+
+          break;
+        }
+      }
+    } else if (service->uuid.uu.uuid16 == UUID_SERVCLASS_GAP_SERVER) {
+      // TODO(jpawlowski): this should be done by GAP profile, remove when GAP
+      // is fixed.
+      for (list_node_t* cn = list_begin(service->characteristics);
+           cn != list_end(service->characteristics); cn = list_next(cn)) {
+        tBTA_GATTC_CHARACTERISTIC* p_char =
+            (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
+        if (p_char->uuid.len == LEN_UUID_16 &&
+            p_char->uuid.uu.uuid16 == GATT_UUID_GAP_PREF_CONN_PARAM) {
+          /* read the char value */
+          gatt_queue_read_op(GATT_READ_CHAR, p_dev_cb->conn_id, p_char->handle,
+                             read_pref_conn_params_cb, p_dev_cb);
+
+          break;
+        }
+      }
+    }
+  }
+
+  bta_hh_le_gatt_disc_cmpl(p_dev_cb, p_dev_cb->status);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_input_rpt_notify
+ *
+ * Description      process the notificaton event, most likely for input report.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_le_input_rpt_notify(tBTA_GATTC_NOTIFY* p_data) {
+  tBTA_HH_DEV_CB* p_dev_cb = bta_hh_le_find_dev_cb_by_conn_id(p_data->conn_id);
+  uint8_t app_id;
+  uint8_t* p_buf;
+  tBTA_HH_LE_RPT* p_rpt;
+
+  if (p_dev_cb == NULL) {
+    APPL_TRACE_ERROR(
+        "%s: notification received from Unknown device, conn_id: 0x%04x",
+        __func__, p_data->conn_id);
+    return;
+  }
+
+  const tBTA_GATTC_CHARACTERISTIC* p_char =
+      BTA_GATTC_GetCharacteristic(p_dev_cb->conn_id, p_data->handle);
+  if (p_char == NULL) {
+    APPL_TRACE_ERROR(
+        "%s: notification received for Unknown Characteristic, conn_id: "
+        "0x%04x, handle: 0x%04x",
+        __func__, p_dev_cb->conn_id, p_data->handle);
+    return;
+  }
+
+  app_id = p_dev_cb->app_id;
+
+  p_rpt = bta_hh_le_find_report_entry(p_dev_cb, p_dev_cb->hid_srvc.srvc_inst_id,
+                                      p_char->uuid.uu.uuid16, p_char->handle);
+  if (p_rpt == NULL) {
+    APPL_TRACE_ERROR(
+        "%s: notification received for Unknown Report, uuid: 0x%04x, handle: "
+        "0x%04x",
+        __func__, p_char->uuid.uu.uuid16, p_char->handle);
+    return;
+  }
+
+  if (p_char->uuid.uu.uuid16 == GATT_UUID_HID_BT_MOUSE_INPUT)
+    app_id = BTA_HH_APP_ID_MI;
+  else if (p_char->uuid.uu.uuid16 == GATT_UUID_HID_BT_KB_INPUT)
+    app_id = BTA_HH_APP_ID_KB;
+
+  APPL_TRACE_DEBUG("Notification received on report ID: %d", p_rpt->rpt_id);
+
+  /* need to append report ID to the head of data */
+  if (p_rpt->rpt_id != 0) {
+    p_buf = (uint8_t*)osi_malloc(p_data->len + 1);
+
+    p_buf[0] = p_rpt->rpt_id;
+    memcpy(&p_buf[1], p_data->value, p_data->len);
+    ++p_data->len;
+  } else {
+    p_buf = p_data->value;
+  }
+
+  bta_hh_co_data((uint8_t)p_dev_cb->hid_handle, p_buf, p_data->len,
+                 p_dev_cb->mode, 0, /* no sub class*/
+                 p_dev_cb->dscp_info.ctry_code, p_dev_cb->addr, app_id);
+
+  if (p_buf != p_data->value) osi_free(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_gatt_open_fail
+ *
+ * Description      action function to process the open fail
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_le_open_fail(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+  tBTA_HH_CONN conn_dat;
+
+  /* open failure in the middle of service discovery, clear all services */
+  if (p_cb->disc_active & BTA_HH_LE_DISC_HIDS) {
+    bta_hh_clear_service_cache(p_cb);
+  }
+
+  p_cb->disc_active = BTA_HH_LE_DISC_NONE;
+  /* Failure in opening connection or GATT discovery failure */
+  conn_dat.handle = p_cb->hid_handle;
+  memcpy(conn_dat.bda, p_cb->addr, BD_ADDR_LEN);
+  conn_dat.le_hid = true;
+  conn_dat.scps_supported = p_cb->scps_supported;
+
+  if (p_cb->status == BTA_HH_OK)
+    conn_dat.status = (p_data->le_close.reason == BTA_GATT_CONN_UNKNOWN)
+                          ? p_cb->status
+                          : BTA_HH_ERR;
+  else
+    conn_dat.status = p_cb->status;
+
+  /* Report OPEN fail event */
+  (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH*)&conn_dat);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_gatt_close
+ *
+ * Description      action function to process the GATT close int he state
+ *                  machine.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_gatt_close(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+  tBTA_HH_CBDATA disc_dat = {BTA_HH_OK, 0};
+
+  /* deregister all notification */
+  bta_hh_le_deregister_input_notif(p_cb);
+  /* finaliza device driver */
+  bta_hh_co_close(p_cb->hid_handle, p_cb->app_id);
+  /* update total conn number */
+  bta_hh_cb.cnt_num--;
+
+  disc_dat.handle = p_cb->hid_handle;
+  disc_dat.status = p_cb->status;
+
+  (*bta_hh_cb.p_cback)(BTA_HH_CLOSE_EVT, (tBTA_HH*)&disc_dat);
+
+  /* if no connection is active and HH disable is signaled, disable service */
+  if (bta_hh_cb.cnt_num == 0 && bta_hh_cb.w4_disable) {
+    bta_hh_disc_cmpl();
+  } else {
+#if (BTA_HH_LE_RECONN == TRUE)
+    if (p_data->le_close.reason == BTA_GATT_CONN_TIMEOUT) {
+      bta_hh_le_add_dev_bg_conn(p_cb, false);
+    }
+#endif
+  }
+
+  return;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_api_disc_act
+ *
+ * Description      initaite a Close API to a remote HID device
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_le_api_disc_act(tBTA_HH_DEV_CB* p_cb) {
+  if (p_cb->conn_id != BTA_GATT_INVALID_CONN_ID) {
+    gatt_op_queue_clean(p_cb->conn_id);
+    BTA_GATTC_Close(p_cb->conn_id);
+    /* remove device from background connection if intended to disconnect,
+       do not allow reconnection */
+    bta_hh_le_remove_dev_bg_conn(p_cb);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         read_report_cb
+ *
+ * Description      Process the Read report complete, send GET_REPORT_EVT to
+ *                  application with the report data.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+static void read_report_cb(uint16_t conn_id, tGATT_STATUS status,
+                           uint16_t handle, uint16_t len, uint8_t* value,
+                           void* data) {
+  const tBTA_GATTC_CHARACTERISTIC* p_char =
+      BTA_GATTC_GetCharacteristic(conn_id, handle);
+
+  if (p_char == NULL) return;
+
+  uint16_t char_uuid = p_char->uuid.uu.uuid16;
+
+  if (char_uuid != GATT_UUID_HID_REPORT &&
+      char_uuid != GATT_UUID_HID_BT_KB_INPUT &&
+      char_uuid != GATT_UUID_HID_BT_KB_OUTPUT &&
+      char_uuid != GATT_UUID_HID_BT_MOUSE_INPUT &&
+      char_uuid != GATT_UUID_BATTERY_LEVEL) {
+    APPL_TRACE_ERROR("%s: Unexpected Read UUID: 0x%04x", __func__, char_uuid);
+    return;
+  }
+
+  tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
+  if (p_dev_cb->w4_evt != BTA_HH_GET_RPT_EVT) {
+    APPL_TRACE_ERROR("Unexpected READ cmpl, w4_evt = %d", p_dev_cb->w4_evt);
+    return;
+  }
+
+  /* GET_REPORT */
+  BT_HDR* p_buf = NULL;
+  tBTA_HH_LE_RPT* p_rpt;
+  tBTA_HH_HSDATA hs_data;
+  uint8_t* pp;
+
+  memset(&hs_data, 0, sizeof(hs_data));
+  hs_data.status = BTA_HH_ERR;
+  hs_data.handle = p_dev_cb->hid_handle;
+
+  if (status == BTA_GATT_OK) {
+    p_rpt = bta_hh_le_find_report_entry(p_dev_cb, p_char->service->handle,
+                                        p_char->uuid.uu.uuid16, p_char->handle);
+
+    if (p_rpt != NULL && len) {
+      p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + len + 1);
+      /* pack data send to app */
+      hs_data.status = BTA_HH_OK;
+      p_buf->len = len + 1;
+      p_buf->layer_specific = 0;
+      p_buf->offset = 0;
+
+      /* attach report ID as the first byte of the report before sending it to
+       * USB HID driver */
+      pp = (uint8_t*)(p_buf + 1);
+      UINT8_TO_STREAM(pp, p_rpt->rpt_id);
+      memcpy(pp, value, len);
+
+      hs_data.rsp_data.p_rpt_data = p_buf;
+    }
+  }
+
+  p_dev_cb->w4_evt = 0;
+  (*bta_hh_cb.p_cback)(BTA_HH_GET_RPT_EVT, (tBTA_HH*)&hs_data);
+
+  osi_free_and_reset((void**)&p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_get_rpt
+ *
+ * Description      GET_REPORT on a LE HID Report
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_le_get_rpt(tBTA_HH_DEV_CB* p_cb, tBTA_HH_RPT_TYPE r_type,
+                       uint8_t rpt_id) {
+  tBTA_HH_LE_RPT* p_rpt = bta_hh_le_find_rpt_by_idtype(
+      p_cb->hid_srvc.report, p_cb->mode, r_type, rpt_id);
+
+  if (p_rpt == NULL) {
+    APPL_TRACE_ERROR("%s: no matching report", __func__);
+    return;
+  }
+
+  p_cb->w4_evt = BTA_HH_GET_RPT_EVT;
+  gatt_queue_read_op(GATT_READ_CHAR, p_cb->conn_id, p_rpt->char_inst_id,
+                     read_report_cb, p_cb);
+}
+
+static void write_report_cb(uint16_t conn_id, tGATT_STATUS status,
+                            uint16_t handle, void* data) {
+  tBTA_HH_CBDATA cback_data;
+  tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
+  uint16_t cb_evt = p_dev_cb->w4_evt;
+
+  if (cb_evt == 0) return;
+
+#if (BTA_HH_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hh_le_write_cmpl w4_evt: %d", p_dev_cb->w4_evt);
+#endif
+
+  const tBTA_GATTC_CHARACTERISTIC* p_char =
+      BTA_GATTC_GetCharacteristic(conn_id, handle);
+  uint16_t uuid = p_char->uuid.uu.uuid16;
+  if (uuid != GATT_UUID_HID_REPORT && uuid != GATT_UUID_HID_BT_KB_INPUT &&
+      uuid != GATT_UUID_HID_BT_MOUSE_INPUT &&
+      uuid != GATT_UUID_HID_BT_KB_OUTPUT) {
+    return;
+  }
+
+  /* Set Report finished */
+  cback_data.handle = p_dev_cb->hid_handle;
+  cback_data.status = (status == BTA_GATT_OK) ? BTA_HH_OK : BTA_HH_ERR;
+  p_dev_cb->w4_evt = 0;
+  (*bta_hh_cb.p_cback)(cb_evt, (tBTA_HH*)&cback_data);
+}
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_write_rpt
+ *
+ * Description      SET_REPORT/or DATA output on a LE HID Report
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_le_write_rpt(tBTA_HH_DEV_CB* p_cb, tBTA_HH_RPT_TYPE r_type,
+                         BT_HDR* p_buf, uint16_t w4_evt) {
+  tBTA_HH_LE_RPT* p_rpt;
+  uint8_t rpt_id;
+
+  if (p_buf == NULL || p_buf->len == 0) {
+    APPL_TRACE_ERROR("%s: Illegal data", __func__);
+    return;
+  }
+
+  /* strip report ID from the data */
+  uint8_t* vec_start = (uint8_t*)(p_buf + 1) + p_buf->offset;
+  STREAM_TO_UINT8(rpt_id, vec_start);
+  vector<uint8_t> value(vec_start, vec_start + p_buf->len - 1);
+
+  p_rpt = bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc.report, p_cb->mode,
+                                       r_type, rpt_id);
+  if (p_rpt == NULL) {
+    APPL_TRACE_ERROR("%s: no matching report", __func__);
+    osi_free(p_buf);
+    return;
+  }
+
+  p_cb->w4_evt = w4_evt;
+
+  const tBTA_GATTC_CHARACTERISTIC* p_char =
+      BTA_GATTC_GetCharacteristic(p_cb->conn_id, p_rpt->char_inst_id);
+
+  tBTA_GATTC_WRITE_TYPE write_type = BTA_GATTC_TYPE_WRITE;
+  if (p_char && (p_char->properties & BTA_GATT_CHAR_PROP_BIT_WRITE_NR))
+    write_type = BTA_GATTC_TYPE_WRITE_NO_RSP;
+
+  gatt_queue_write_op(GATT_WRITE_CHAR, p_cb->conn_id, p_rpt->char_inst_id,
+                      std::move(value), write_type, write_report_cb, p_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_suspend
+ *
+ * Description      send LE suspend or exit suspend mode to remote device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_le_suspend(tBTA_HH_DEV_CB* p_cb,
+                       tBTA_HH_TRANS_CTRL_TYPE ctrl_type) {
+  ctrl_type -= BTA_HH_CTRL_SUSPEND;
+
+  // We don't care about response
+  gatt_queue_write_op(GATT_WRITE_CHAR, p_cb->conn_id,
+                      p_cb->hid_srvc.control_point_handle, {(uint8_t)ctrl_type},
+                      BTA_GATTC_TYPE_WRITE_NO_RSP, NULL, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_write_dev_act
+ *
+ * Description      Write LE device action. can be SET/GET/DATA transaction.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_le_write_dev_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+  switch (p_data->api_sndcmd.t_type) {
+    case HID_TRANS_SET_PROTOCOL:
+      p_cb->w4_evt = BTA_HH_SET_PROTO_EVT;
+      bta_hh_le_set_protocol_mode(p_cb, p_data->api_sndcmd.param);
+      break;
+
+    case HID_TRANS_GET_PROTOCOL:
+      bta_hh_le_get_protocol_mode(p_cb);
+      break;
+
+    case HID_TRANS_GET_REPORT:
+      bta_hh_le_get_rpt(p_cb, p_data->api_sndcmd.param,
+                        p_data->api_sndcmd.rpt_id);
+      break;
+
+    case HID_TRANS_SET_REPORT:
+      bta_hh_le_write_rpt(p_cb, p_data->api_sndcmd.param,
+                          p_data->api_sndcmd.p_data, BTA_HH_SET_RPT_EVT);
+      break;
+
+    case HID_TRANS_DATA: /* output report */
+
+      bta_hh_le_write_rpt(p_cb, p_data->api_sndcmd.param,
+                          p_data->api_sndcmd.p_data, BTA_HH_DATA_EVT);
+      break;
+
+    case HID_TRANS_CONTROL:
+      /* no handshake event will be generated */
+      /* if VC_UNPLUG is issued, set flag */
+      if (p_data->api_sndcmd.param == BTA_HH_CTRL_SUSPEND ||
+          p_data->api_sndcmd.param == BTA_HH_CTRL_EXIT_SUSPEND) {
+        bta_hh_le_suspend(p_cb, p_data->api_sndcmd.param);
+      }
+      break;
+
+    default:
+      APPL_TRACE_ERROR("%s unsupported transaction for BLE HID device: %d",
+                       __func__, p_data->api_sndcmd.t_type);
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_get_dscp_act
+ *
+ * Description      Send ReportDescriptor to application for all HID services.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_le_get_dscp_act(tBTA_HH_DEV_CB* p_cb) {
+  if (p_cb->hid_srvc.in_use) {
+    p_cb->dscp_info.descriptor.dl_len = p_cb->hid_srvc.descriptor.dl_len;
+    p_cb->dscp_info.descriptor.dsc_list = p_cb->hid_srvc.descriptor.dsc_list;
+
+    (*bta_hh_cb.p_cback)(BTA_HH_GET_DSCP_EVT, (tBTA_HH*)&p_cb->dscp_info);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_add_dev_bg_conn
+ *
+ * Description      Remove a LE HID device from back ground connection
+ *                  procedure.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hh_le_add_dev_bg_conn(tBTA_HH_DEV_CB* p_cb, bool check_bond) {
+  uint8_t sec_flag = 0;
+  bool to_add = true;
+
+  if (check_bond) {
+    /* start reconnection if remote is a bonded device */
+    /* verify bond */
+    BTM_GetSecurityFlagsByTransport(p_cb->addr, &sec_flag, BT_TRANSPORT_LE);
+
+    if ((sec_flag & BTM_SEC_FLAG_LKEY_KNOWN) == 0) to_add = false;
+  }
+
+  if (/*p_cb->dscp_info.flag & BTA_HH_LE_NORMAL_CONN &&*/
+      !p_cb->in_bg_conn && to_add) {
+    /* add device into BG connection to accept remote initiated connection */
+    BTA_GATTC_Open(bta_hh_cb.gatt_if, p_cb->addr, false, BTA_GATT_TRANSPORT_LE);
+    p_cb->in_bg_conn = true;
+
+    BTA_DmBleSetBgConnType(BTA_DM_BLE_CONN_AUTO, NULL);
+  }
+  return;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_add_device
+ *
+ * Description      Add a LE HID device as a known device, and also add the
+ *                  address
+ *                  into back ground connection WL for incoming connection.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+uint8_t bta_hh_le_add_device(tBTA_HH_DEV_CB* p_cb,
+                             tBTA_HH_MAINT_DEV* p_dev_info) {
+  p_cb->hid_handle = BTA_HH_GET_LE_DEV_HDL(p_cb->index);
+  bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = p_cb->index;
+
+  /* update DI information */
+  bta_hh_update_di_info(
+      p_cb, p_dev_info->dscp_info.vendor_id, p_dev_info->dscp_info.product_id,
+      p_dev_info->dscp_info.version, p_dev_info->dscp_info.flag);
+
+  /* add to BTA device list */
+  bta_hh_add_device_to_list(
+      p_cb, p_cb->hid_handle, p_dev_info->attr_mask,
+      &p_dev_info->dscp_info.descriptor, p_dev_info->sub_class,
+      p_dev_info->dscp_info.ssr_max_latency, p_dev_info->dscp_info.ssr_min_tout,
+      p_dev_info->app_id);
+
+  bta_hh_le_add_dev_bg_conn(p_cb, false);
+
+  return p_cb->hid_handle;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_remove_dev_bg_conn
+ *
+ * Description      Remove a LE HID device from back ground connection
+ *                  procedure.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_le_remove_dev_bg_conn(tBTA_HH_DEV_CB* p_dev_cb) {
+  if (p_dev_cb->in_bg_conn) {
+    p_dev_cb->in_bg_conn = false;
+
+    BTA_GATTC_CancelOpen(bta_hh_cb.gatt_if, p_dev_cb->addr, false);
+  }
+
+  /* deregister all notifications */
+  bta_hh_le_deregister_input_notif(p_dev_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_gattc_callback
+ *
+ * Description      This is GATT client callback function used in BTA HH.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+static void bta_hh_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
+  tBTA_HH_DEV_CB* p_dev_cb;
+#if (BTA_HH_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hh_gattc_callback event = %d", event);
+#endif
+  if (p_data == NULL) return;
+
+  switch (event) {
+    case BTA_GATTC_REG_EVT: /* 0 */
+      bta_hh_le_register_cmpl(&p_data->reg_oper);
+      break;
+
+    case BTA_GATTC_DEREG_EVT: /* 1 */
+      bta_hh_cleanup_disable(p_data->reg_oper.status);
+      break;
+
+    case BTA_GATTC_OPEN_EVT: /* 2 */
+      p_dev_cb = bta_hh_le_find_dev_cb_by_bda(p_data->open.remote_bda);
+      if (p_dev_cb) {
+        bta_hh_sm_execute(p_dev_cb, BTA_HH_GATT_OPEN_EVT,
+                          (tBTA_HH_DATA*)&p_data->open);
+      }
+      break;
+
+    case BTA_GATTC_CLOSE_EVT: /* 5 */
+      bta_hh_le_close(&p_data->close);
+      break;
+
+    case BTA_GATTC_SEARCH_CMPL_EVT: /* 6 */
+      bta_hh_le_srvc_search_cmpl(&p_data->search_cmpl);
+      break;
+
+    case BTA_GATTC_NOTIF_EVT: /* 10 */
+      bta_hh_le_input_rpt_notify(&p_data->notify);
+      break;
+
+    case BTA_GATTC_ENC_CMPL_CB_EVT: /* 17 */
+      p_dev_cb = bta_hh_le_find_dev_cb_by_bda(p_data->enc_cmpl.remote_bda);
+      if (p_dev_cb) {
+        bta_hh_sm_execute(p_dev_cb, BTA_HH_GATT_ENC_CMPL_EVT,
+                          (tBTA_HH_DATA*)&p_data->enc_cmpl);
+      }
+      break;
+
+    default:
+      break;
+  }
+}
+
+static void read_report_descriptor_ccc_cb(uint16_t conn_id, tGATT_STATUS status,
+                                          uint16_t handle, uint16_t len,
+                                          uint8_t* value, void* data) {
+  tBTA_HH_LE_RPT* p_rpt = (tBTA_HH_LE_RPT*)data;
+  uint8_t* pp = value;
+  STREAM_TO_UINT16(p_rpt->client_cfg_value, pp);
+
+  APPL_TRACE_DEBUG("Read Client Configuration: 0x%04x",
+                   p_rpt->client_cfg_value);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_hid_read_rpt_clt_cfg
+ *
+ * Description      a test command to read report descriptor client
+ *                  configuration
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_le_hid_read_rpt_clt_cfg(BD_ADDR bd_addr, uint8_t rpt_id) {
+  tBTA_HH_DEV_CB* p_cb = NULL;
+  tBTA_HH_LE_RPT* p_rpt;
+  uint8_t index = BTA_HH_IDX_INVALID;
+
+  index = bta_hh_find_cb(bd_addr);
+  if ((index = bta_hh_find_cb(bd_addr)) == BTA_HH_IDX_INVALID) {
+    APPL_TRACE_ERROR("%s: unknown device", __func__);
+    return;
+  }
+
+  p_cb = &bta_hh_cb.kdev[index];
+
+  p_rpt = bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc.report, p_cb->mode,
+                                       BTA_HH_RPTT_INPUT, rpt_id);
+
+  if (p_rpt == NULL) {
+    APPL_TRACE_ERROR("%s: no matching report", __func__);
+    return;
+  }
+
+  bta_hh_le_read_char_descriptor(p_cb, p_rpt->char_inst_id,
+                                 GATT_UUID_CHAR_CLIENT_CONFIG,
+                                 read_report_descriptor_ccc_cb, p_rpt);
+  return;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_process_cache_rpt
+ *
+ * Description      Process the cached reports
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+// TODO(jpawlowski): uncomment when fixed
+// static void bta_hh_process_cache_rpt (tBTA_HH_DEV_CB *p_cb,
+//                                       tBTA_HH_RPT_CACHE_ENTRY *p_rpt_cache,
+//                                       uint8_t num_rpt)
+// {
+//     uint8_t                       i = 0;
+//     tBTA_HH_LE_RPT              *p_rpt;
+
+//     if (num_rpt != 0)  /* no cache is found */
+//     {
+//         p_cb->hid_srvc.in_use = true;
+
+//         /* set the descriptor info */
+//         p_cb->hid_srvc.descriptor.dl_len =
+//                 p_cb->dscp_info.descriptor.dl_len;
+//         p_cb->hid_srvc.descriptor.dsc_list =
+//                     p_cb->dscp_info.descriptor.dsc_list;
+
+//         for (; i <num_rpt; i ++, p_rpt_cache ++)
+//         {
+//             if ((p_rpt = bta_hh_le_find_alloc_report_entry (p_cb,
+//                                                p_rpt_cache->srvc_inst_id,
+//                                                p_rpt_cache->rpt_uuid,
+//                                                p_rpt_cache->char_inst_id,
+//                                                p_rpt_cache->prop))  == NULL)
+//             {
+//                 APPL_TRACE_ERROR("bta_hh_process_cache_rpt: allocation report
+//                 entry failure");
+//                 break;
+//             }
+//             else
+//             {
+//                 p_rpt->rpt_type =  p_rpt_cache->rpt_type;
+//                 p_rpt->rpt_id   =  p_rpt_cache->rpt_id;
+
+//                 if (p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT ||
+//                     p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT ||
+//                     (p_rpt->uuid == GATT_UUID_HID_REPORT && p_rpt->rpt_type
+//                     == BTA_HH_RPTT_INPUT))
+//                 {
+//                     p_rpt->client_cfg_value =
+//                     BTA_GATT_CLT_CONFIG_NOTIFICATION;
+//                 }
+//             }
+//         }
+//     }
+// }
+
+#endif
diff --git a/bt/bta/hh/bta_hh_main.cc b/bt/bta/hh/bta_hh_main.cc
new file mode 100644
index 0000000..ca7601a
--- /dev/null
+++ b/bt/bta/hh/bta_hh_main.cc
@@ -0,0 +1,512 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2005-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 HID host main functions and state machine.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if (BTA_HH_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_hh_api.h"
+#include "bta_hh_int.h"
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+
+/* state machine action enumeration list */
+enum {
+  BTA_HH_API_DISC_ACT, /* HID host process API close action    */
+  BTA_HH_OPEN_ACT,     /* HID host process BTA_HH_EVT_OPEN     */
+  BTA_HH_CLOSE_ACT,    /* HID host process BTA_HH_EVT_CLOSE    */
+  BTA_HH_DATA_ACT,     /* HID host receive data report         */
+  BTA_HH_CTRL_DAT_ACT,
+  BTA_HH_HANDSK_ACT,
+  BTA_HH_START_SDP, /* HID host inquery                     */
+  BTA_HH_SDP_CMPL,
+  BTA_HH_WRITE_DEV_ACT,
+  BTA_HH_GET_DSCP_ACT,
+  BTA_HH_MAINT_DEV_ACT,
+  BTA_HH_OPEN_CMPL_ACT,
+  BTA_HH_OPEN_FAILURE,
+#if (BTA_HH_LE_INCLUDED == TRUE)
+  BTA_HH_GATT_CLOSE,
+  BTA_HH_LE_OPEN_FAIL,
+  BTA_HH_GATT_OPEN,
+  BTA_HH_START_SEC,
+  BTA_HH_SEC_CMPL,
+  BTA_HH_GATT_ENC_CMPL,
+#endif
+  BTA_HH_NUM_ACTIONS
+};
+
+#define BTA_HH_IGNORE BTA_HH_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tBTA_HH_ACTION)(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+
+/* action functions */
+const tBTA_HH_ACTION bta_hh_action[] = {
+    bta_hh_api_disc_act, bta_hh_open_act, bta_hh_close_act, bta_hh_data_act,
+    bta_hh_ctrl_dat_act, bta_hh_handsk_act, bta_hh_start_sdp, bta_hh_sdp_cmpl,
+    bta_hh_write_dev_act, bta_hh_get_dscp_act, bta_hh_maint_dev_act,
+    bta_hh_open_cmpl_act, bta_hh_open_failure
+#if (BTA_HH_LE_INCLUDED == TRUE)
+    ,
+    bta_hh_gatt_close, bta_hh_le_open_fail, bta_hh_gatt_open,
+    bta_hh_start_security, bta_hh_security_cmpl, bta_hh_le_notify_enc_cmpl
+#endif
+};
+
+/* state table information */
+#define BTA_HH_ACTION 0     /* position of action */
+#define BTA_HH_NEXT_STATE 1 /* position of next state */
+#define BTA_HH_NUM_COLS 2   /* number of columns */
+
+/* state table for idle state */
+const uint8_t bta_hh_st_idle[][BTA_HH_NUM_COLS] = {
+    /* Event                          Action                    Next state */
+    /* BTA_HH_API_OPEN_EVT      */ {BTA_HH_START_SDP, BTA_HH_W4_CONN_ST},
+    /* BTA_HH_API_CLOSE_EVT     */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST},
+    /* BTA_HH_INT_OPEN_EVT      */ {BTA_HH_OPEN_ACT, BTA_HH_W4_CONN_ST},
+    /* BTA_HH_INT_CLOSE_EVT     */ {BTA_HH_CLOSE_ACT, BTA_HH_IDLE_ST},
+    /* BTA_HH_INT_DATA_EVT      */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST},
+    /* BTA_HH_INT_CTRL_DATA     */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST},
+    /* BTA_HH_INT_HANDSK_EVT    */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST},
+    /* BTA_HH_SDP_CMPL_EVT      */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST},
+    /* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST},
+    /* BTA_HH_API_GET_DSCP_EVT  */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST},
+    /* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_IDLE_ST},
+    /* BTA_HH_OPEN_CMPL_EVT        */ {BTA_HH_OPEN_CMPL_ACT, BTA_HH_CONN_ST}
+#if (BTA_HH_LE_INCLUDED == TRUE)
+    /* BTA_HH_GATT_CLOSE_EVT    */,
+    {BTA_HH_IGNORE, BTA_HH_IDLE_ST}
+    /* BTA_HH_GATT_OPEN_EVT    */,
+    {BTA_HH_GATT_OPEN, BTA_HH_W4_CONN_ST}
+    /* BTA_HH_START_ENC_EVT    */,
+    {BTA_HH_IGNORE, BTA_HH_IDLE_ST}
+    /* BTA_HH_ENC_CMPL_EVT     */,
+    {BTA_HH_IGNORE, BTA_HH_IDLE_ST}
+    /* BTA_HH_GATT_ENC_CMPL_EVT */,
+    {BTA_HH_IGNORE, BTA_HH_IDLE_ST}
+#endif
+
+};
+
+const uint8_t bta_hh_st_w4_conn[][BTA_HH_NUM_COLS] = {
+    /* Event                          Action                 Next state */
+    /* BTA_HH_API_OPEN_EVT      */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST},
+    /* BTA_HH_API_CLOSE_EVT     */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST},
+    /* BTA_HH_INT_OPEN_EVT      */ {BTA_HH_OPEN_ACT, BTA_HH_W4_CONN_ST},
+    /* BTA_HH_INT_CLOSE_EVT     */ {BTA_HH_OPEN_FAILURE, BTA_HH_IDLE_ST},
+    /* BTA_HH_INT_DATA_EVT      */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST},
+    /* BTA_HH_INT_CTRL_DATA     */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST},
+    /* BTA_HH_INT_HANDSK_EVT    */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST},
+    /* BTA_HH_SDP_CMPL_EVT      */ {BTA_HH_SDP_CMPL, BTA_HH_W4_CONN_ST},
+    /* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_WRITE_DEV_ACT, BTA_HH_W4_CONN_ST},
+    /* BTA_HH_API_GET_DSCP_EVT  */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST},
+    /* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_IDLE_ST},
+    /* BTA_HH_OPEN_CMPL_EVT     */ {BTA_HH_OPEN_CMPL_ACT, BTA_HH_CONN_ST}
+#if (BTA_HH_LE_INCLUDED == TRUE)
+    /* BTA_HH_GATT_CLOSE_EVT    */,
+    {BTA_HH_LE_OPEN_FAIL, BTA_HH_IDLE_ST}
+    /* BTA_HH_GATT_OPEN_EVT    */,
+    {BTA_HH_GATT_OPEN, BTA_HH_W4_CONN_ST}
+    /* BTA_HH_START_ENC_EVT    */,
+    {BTA_HH_START_SEC, BTA_HH_W4_SEC}
+    /* BTA_HH_ENC_CMPL_EVT     */,
+    {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST}
+    /* BTA_HH_GATT_ENC_CMPL_EVT */,
+    {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST}
+#endif
+};
+
+const uint8_t bta_hh_st_connected[][BTA_HH_NUM_COLS] = {
+    /* Event                          Action                 Next state */
+    /* BTA_HH_API_OPEN_EVT      */ {BTA_HH_IGNORE, BTA_HH_CONN_ST},
+    /* BTA_HH_API_CLOSE_EVT     */ {BTA_HH_API_DISC_ACT, BTA_HH_CONN_ST},
+    /* BTA_HH_INT_OPEN_EVT      */ {BTA_HH_OPEN_ACT, BTA_HH_CONN_ST},
+    /* BTA_HH_INT_CLOSE_EVT     */ {BTA_HH_CLOSE_ACT, BTA_HH_IDLE_ST},
+    /* BTA_HH_INT_DATA_EVT      */ {BTA_HH_DATA_ACT, BTA_HH_CONN_ST},
+    /* BTA_HH_INT_CTRL_DATA     */ {BTA_HH_CTRL_DAT_ACT, BTA_HH_CONN_ST},
+    /* BTA_HH_INT_HANDSK_EVT    */ {BTA_HH_HANDSK_ACT, BTA_HH_CONN_ST},
+    /* BTA_HH_SDP_CMPL_EVT      */ {BTA_HH_IGNORE, BTA_HH_CONN_ST},
+    /* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_WRITE_DEV_ACT, BTA_HH_CONN_ST},
+    /* BTA_HH_API_GET_DSCP_EVT  */ {BTA_HH_GET_DSCP_ACT, BTA_HH_CONN_ST},
+    /* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_CONN_ST},
+    /* BTA_HH_OPEN_CMPL_EVT        */ {BTA_HH_IGNORE, BTA_HH_CONN_ST}
+#if (BTA_HH_LE_INCLUDED == TRUE)
+    /* BTA_HH_GATT_CLOSE_EVT    */,
+    {BTA_HH_GATT_CLOSE, BTA_HH_IDLE_ST}
+    /* BTA_HH_GATT_OPEN_EVT    */,
+    {BTA_HH_IGNORE, BTA_HH_CONN_ST}
+    /* BTA_HH_START_ENC_EVT    */,
+    {BTA_HH_IGNORE, BTA_HH_CONN_ST}
+    /* BTA_HH_ENC_CMPL_EVT     */,
+    {BTA_HH_IGNORE, BTA_HH_CONN_ST}
+    /* BTA_HH_GATT_ENC_CMPL_EVT */,
+    {BTA_HH_IGNORE, BTA_HH_CONN_ST}
+#endif
+};
+#if (BTA_HH_LE_INCLUDED == TRUE)
+const uint8_t bta_hh_st_w4_sec[][BTA_HH_NUM_COLS] = {
+    /* Event                          Action                 Next state */
+    /* BTA_HH_API_OPEN_EVT      */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+    /* BTA_HH_API_CLOSE_EVT     */ {BTA_HH_API_DISC_ACT, BTA_HH_W4_SEC},
+    /* BTA_HH_INT_OPEN_EVT      */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+    /* BTA_HH_INT_CLOSE_EVT     */ {BTA_HH_OPEN_FAILURE, BTA_HH_IDLE_ST},
+    /* BTA_HH_INT_DATA_EVT      */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+    /* BTA_HH_INT_CTRL_DATA     */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+    /* BTA_HH_INT_HANDSK_EVT    */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+    /* BTA_HH_SDP_CMPL_EVT      */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+    /* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+    /* BTA_HH_API_GET_DSCP_EVT  */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+    /* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_W4_SEC},
+    /* BTA_HH_OPEN_CMPL_EVT     */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+    /* BTA_HH_GATT_CLOSE_EVT    */ {BTA_HH_LE_OPEN_FAIL, BTA_HH_IDLE_ST},
+    /* BTA_HH_GATT_OPEN_EVT    */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+    /* BTA_HH_START_ENC_EVT    */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+    /* BTA_HH_ENC_CMPL_EVT     */ {BTA_HH_SEC_CMPL, BTA_HH_W4_CONN_ST},
+    /* BTA_HH_GATT_ENC_CMPL_EVT */ {BTA_HH_GATT_ENC_CMPL, BTA_HH_W4_SEC}};
+#endif
+
+/* type for state table */
+typedef const uint8_t (*tBTA_HH_ST_TBL)[BTA_HH_NUM_COLS];
+
+/* state table */
+const tBTA_HH_ST_TBL bta_hh_st_tbl[] = {bta_hh_st_idle, bta_hh_st_w4_conn,
+                                        bta_hh_st_connected
+#if (BTA_HH_LE_INCLUDED == TRUE)
+                                        ,
+                                        bta_hh_st_w4_sec
+#endif
+};
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+tBTA_HH_CB bta_hh_cb;
+
+/*****************************************************************************
+ * Static functions
+ ****************************************************************************/
+#if (BTA_HH_DEBUG == TRUE)
+static const char* bta_hh_evt_code(tBTA_HH_INT_EVT evt_code);
+static const char* bta_hh_state_code(tBTA_HH_STATE state_code);
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_sm_execute
+ *
+ * Description      State machine event handling function for HID Host
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_sm_execute(tBTA_HH_DEV_CB* p_cb, uint16_t event,
+                       tBTA_HH_DATA* p_data) {
+  tBTA_HH_ST_TBL state_table;
+  uint8_t action;
+  tBTA_HH cback_data;
+  tBTA_HH_EVT cback_event = 0;
+#if (BTA_HH_DEBUG == TRUE)
+  tBTA_HH_STATE in_state;
+  uint16_t debug_event = event;
+#endif
+
+  memset(&cback_data, 0, sizeof(tBTA_HH));
+
+  /* handle exception, no valid control block was found */
+  if (!p_cb) {
+    /* BTA HH enabled already? otherwise ignore the event although it's bad*/
+    if (bta_hh_cb.p_cback != NULL) {
+      switch (event) {
+        /* no control block available for new connection */
+        case BTA_HH_API_OPEN_EVT:
+          cback_event = BTA_HH_OPEN_EVT;
+          /* build cback data */
+          bdcpy(cback_data.conn.bda, ((tBTA_HH_API_CONN*)p_data)->bd_addr);
+          cback_data.conn.status = BTA_HH_ERR_DB_FULL;
+          cback_data.conn.handle = BTA_HH_INVALID_HANDLE;
+          break;
+        /* DB full, BTA_HhAddDev */
+        case BTA_HH_API_MAINT_DEV_EVT:
+          cback_event = p_data->api_maintdev.sub_event;
+
+          if (p_data->api_maintdev.sub_event == BTA_HH_ADD_DEV_EVT) {
+            bdcpy(cback_data.dev_info.bda, p_data->api_maintdev.bda);
+            cback_data.dev_info.status = BTA_HH_ERR_DB_FULL;
+            cback_data.dev_info.handle = BTA_HH_INVALID_HANDLE;
+          } else {
+            cback_data.dev_info.status = BTA_HH_ERR_HDL;
+            cback_data.dev_info.handle =
+                (uint8_t)p_data->api_maintdev.hdr.layer_specific;
+          }
+          break;
+        case BTA_HH_API_WRITE_DEV_EVT:
+          cback_event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
+                        BTA_HH_FST_TRANS_CB_EVT;
+          osi_free_and_reset((void**)&p_data->api_sndcmd.p_data);
+          if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL ||
+              p_data->api_sndcmd.t_type == HID_TRANS_SET_REPORT ||
+              p_data->api_sndcmd.t_type == HID_TRANS_SET_IDLE) {
+            cback_data.dev_status.status = BTA_HH_ERR_HDL;
+            cback_data.dev_status.handle =
+                (uint8_t)p_data->api_sndcmd.hdr.layer_specific;
+          } else if (p_data->api_sndcmd.t_type != HID_TRANS_DATA &&
+                     p_data->api_sndcmd.t_type != HID_TRANS_CONTROL) {
+            cback_data.hs_data.handle =
+                (uint8_t)p_data->api_sndcmd.hdr.layer_specific;
+            cback_data.hs_data.status = BTA_HH_ERR_HDL;
+            /* hs_data.rsp_data will be all zero, which is not valid value */
+          } else if (p_data->api_sndcmd.t_type == HID_TRANS_CONTROL &&
+                     p_data->api_sndcmd.param ==
+                         BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG) {
+            cback_data.status = BTA_HH_ERR_HDL;
+            cback_event = BTA_HH_VC_UNPLUG_EVT;
+          } else
+            cback_event = 0;
+          break;
+
+        case BTA_HH_API_CLOSE_EVT:
+          cback_event = BTA_HH_CLOSE_EVT;
+
+          cback_data.dev_status.status = BTA_HH_ERR_HDL;
+          cback_data.dev_status.handle =
+              (uint8_t)p_data->api_sndcmd.hdr.layer_specific;
+          break;
+
+        default:
+          /* invalid handle, call bad API event */
+          APPL_TRACE_ERROR("wrong device handle: [%d]",
+                           p_data->hdr.layer_specific);
+          /* Free the callback buffer now */
+          if (p_data != NULL)
+            osi_free_and_reset((void**)&p_data->hid_cback.p_data);
+          break;
+      }
+      if (cback_event) (*bta_hh_cb.p_cback)(cback_event, &cback_data);
+    }
+  }
+  /* corresponding CB is found, go to state machine */
+  else {
+#if (BTA_HH_DEBUG == TRUE)
+    in_state = p_cb->state;
+    APPL_TRACE_EVENT("bta_hh_sm_execute: State 0x%02x [%s], Event [%s]",
+                     in_state, bta_hh_state_code(in_state),
+                     bta_hh_evt_code(debug_event));
+#endif
+
+    if ((p_cb->state == BTA_HH_NULL_ST) || (p_cb->state >= BTA_HH_INVALID_ST)) {
+      APPL_TRACE_ERROR(
+          "bta_hh_sm_execute: Invalid state State = 0x%x, Event = %d",
+          p_cb->state, event);
+      return;
+    }
+    state_table = bta_hh_st_tbl[p_cb->state - 1];
+
+    event &= 0xff;
+
+    p_cb->state = state_table[event][BTA_HH_NEXT_STATE];
+
+    if ((action = state_table[event][BTA_HH_ACTION]) != BTA_HH_IGNORE) {
+      (*bta_hh_action[action])(p_cb, p_data);
+    }
+
+#if (BTA_HH_DEBUG == TRUE)
+    if (in_state != p_cb->state) {
+      APPL_TRACE_DEBUG("HH State Change: [%s] -> [%s] after Event [%s]",
+                       bta_hh_state_code(in_state),
+                       bta_hh_state_code(p_cb->state),
+                       bta_hh_evt_code(debug_event));
+    }
+#endif
+  }
+
+  return;
+}
+/*******************************************************************************
+ *
+ * Function         bta_hh_hdl_event
+ *
+ * Description      HID host main event handling function.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+bool bta_hh_hdl_event(BT_HDR* p_msg) {
+  uint8_t index = BTA_HH_IDX_INVALID;
+  tBTA_HH_DEV_CB* p_cb = NULL;
+
+  switch (p_msg->event) {
+    case BTA_HH_API_ENABLE_EVT:
+      bta_hh_api_enable((tBTA_HH_DATA*)p_msg);
+      break;
+
+    case BTA_HH_API_DISABLE_EVT:
+      bta_hh_api_disable();
+      break;
+
+    case BTA_HH_DISC_CMPL_EVT: /* disable complete */
+      bta_hh_disc_cmpl();
+      break;
+
+    default:
+      /* all events processed in state machine need to find corresponding
+          CB before proceed */
+      if (p_msg->event == BTA_HH_API_OPEN_EVT) {
+        index = bta_hh_find_cb(((tBTA_HH_API_CONN*)p_msg)->bd_addr);
+      } else if (p_msg->event == BTA_HH_API_MAINT_DEV_EVT) {
+        /* if add device */
+        if (((tBTA_HH_MAINT_DEV*)p_msg)->sub_event == BTA_HH_ADD_DEV_EVT) {
+          index = bta_hh_find_cb(((tBTA_HH_MAINT_DEV*)p_msg)->bda);
+        } else /* else remove device by handle */
+        {
+          index = bta_hh_dev_handle_to_cb_idx((uint8_t)p_msg->layer_specific);
+          /* If BT disable is done while the HID device is connected and
+           * Link_Key uses unauthenticated combination
+            * then we can get into a situation where remove_bonding is called
+           * with the index set to 0 (without getting
+            * cleaned up). Only when VIRTUAL_UNPLUG is called do we cleanup the
+           * index and make it MAX_KNOWN.
+            * So if REMOVE_DEVICE is called and in_use is false then we should
+           * treat this as a NULL p_cb. Hence we
+            * force the index to be IDX_INVALID
+            */
+          if ((index != BTA_HH_IDX_INVALID) &&
+              (bta_hh_cb.kdev[index].in_use == false)) {
+            index = BTA_HH_IDX_INVALID;
+          }
+        }
+      } else if (p_msg->event == BTA_HH_INT_OPEN_EVT) {
+        index = bta_hh_find_cb(((tBTA_HH_CBACK_DATA*)p_msg)->addr);
+      } else
+        index = bta_hh_dev_handle_to_cb_idx((uint8_t)p_msg->layer_specific);
+
+      if (index != BTA_HH_IDX_INVALID) p_cb = &bta_hh_cb.kdev[index];
+
+#if (BTA_HH_DEBUG == TRUE)
+      APPL_TRACE_DEBUG("bta_hh_hdl_event:: handle = %d dev_cb[%d] ",
+                       p_msg->layer_specific, index);
+#endif
+      bta_hh_sm_execute(p_cb, p_msg->event, (tBTA_HH_DATA*)p_msg);
+  }
+  return (true);
+}
+
+/*****************************************************************************
+ *  Debug Functions
+ ****************************************************************************/
+#if (BTA_HH_DEBUG == TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_hh_evt_code
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static const char* bta_hh_evt_code(tBTA_HH_INT_EVT evt_code) {
+  switch (evt_code) {
+    case BTA_HH_API_DISABLE_EVT:
+      return "BTA_HH_API_DISABLE_EVT";
+    case BTA_HH_API_ENABLE_EVT:
+      return "BTA_HH_API_ENABLE_EVT";
+    case BTA_HH_API_OPEN_EVT:
+      return "BTA_HH_API_OPEN_EVT";
+    case BTA_HH_API_CLOSE_EVT:
+      return "BTA_HH_API_CLOSE_EVT";
+    case BTA_HH_INT_OPEN_EVT:
+      return "BTA_HH_INT_OPEN_EVT";
+    case BTA_HH_INT_CLOSE_EVT:
+      return "BTA_HH_INT_CLOSE_EVT";
+    case BTA_HH_INT_HANDSK_EVT:
+      return "BTA_HH_INT_HANDSK_EVT";
+    case BTA_HH_INT_DATA_EVT:
+      return "BTA_HH_INT_DATA_EVT";
+    case BTA_HH_INT_CTRL_DATA:
+      return "BTA_HH_INT_CTRL_DATA";
+    case BTA_HH_API_WRITE_DEV_EVT:
+      return "BTA_HH_API_WRITE_DEV_EVT";
+    case BTA_HH_SDP_CMPL_EVT:
+      return "BTA_HH_SDP_CMPL_EVT";
+    case BTA_HH_DISC_CMPL_EVT:
+      return "BTA_HH_DISC_CMPL_EVT";
+    case BTA_HH_API_MAINT_DEV_EVT:
+      return "BTA_HH_API_MAINT_DEV_EVT";
+    case BTA_HH_API_GET_DSCP_EVT:
+      return "BTA_HH_API_GET_DSCP_EVT";
+    case BTA_HH_OPEN_CMPL_EVT:
+      return "BTA_HH_OPEN_CMPL_EVT";
+#if (BTA_HH_LE_INCLUDED == TRUE)
+    case BTA_HH_GATT_CLOSE_EVT:
+      return "BTA_HH_GATT_CLOSE_EVT";
+    case BTA_HH_GATT_OPEN_EVT:
+      return "BTA_HH_GATT_OPEN_EVT";
+    case BTA_HH_START_ENC_EVT:
+      return "BTA_HH_START_ENC_EVT";
+    case BTA_HH_ENC_CMPL_EVT:
+      return "BTA_HH_ENC_CMPL_EVT";
+#endif
+    default:
+      return "unknown HID Host event code";
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_state_code
+ *
+ * Description      get string representation of HID host state code.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static const char* bta_hh_state_code(tBTA_HH_STATE state_code) {
+  switch (state_code) {
+    case BTA_HH_NULL_ST:
+      return "BTA_HH_NULL_ST";
+    case BTA_HH_IDLE_ST:
+      return "BTA_HH_IDLE_ST";
+    case BTA_HH_W4_CONN_ST:
+      return "BTA_HH_W4_CONN_ST";
+    case BTA_HH_CONN_ST:
+      return "BTA_HH_CONN_ST";
+#if (BTA_HH_LE_INCLUDED == TRUE)
+    case BTA_HH_W4_SEC:
+      return "BTA_HH_W4_SEC";
+#endif
+    default:
+      return "unknown HID Host state";
+  }
+}
+
+#endif /* Debug Functions */
+
+#endif /* BTA_HH_INCLUDED */
diff --git a/bt/bta/hh/bta_hh_utils.cc b/bt/bta/hh/bta_hh_utils.cc
new file mode 100644
index 0000000..8274c95
--- /dev/null
+++ b/bt/bta/hh/bta_hh_utils.cc
@@ -0,0 +1,495 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2005-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.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#if (BTA_HH_INCLUDED == TRUE)
+
+#include "bta_hh_int.h"
+#include "osi/include/osi.h"
+
+/* if SSR max latency is not defined by remote device, set the default value
+   as half of the link supervision timeout */
+#define BTA_HH_GET_DEF_SSR_MAX_LAT(x) ((x) >> 1)
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+#define BTA_HH_KB_CTRL_MASK 0x11
+#define BTA_HH_KB_SHIFT_MASK 0x22
+#define BTA_HH_KB_ALT_MASK 0x44
+#define BTA_HH_KB_GUI_MASK 0x88
+
+#define BTA_HH_KB_CAPS_LOCK 0x39 /* caps lock */
+#define BTA_HH_KB_NUM_LOCK 0x53  /* num lock */
+
+#define BTA_HH_MAX_RPT_CHARS 8
+
+static const uint8_t bta_hh_mod_key_mask[BTA_HH_MOD_MAX_KEY] = {
+    BTA_HH_KB_CTRL_MASK, BTA_HH_KB_SHIFT_MASK, BTA_HH_KB_ALT_MASK,
+    BTA_HH_KB_GUI_MASK};
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_find_cb
+ *
+ * Description      Find best available control block according to BD address.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+uint8_t bta_hh_find_cb(BD_ADDR bda) {
+  uint8_t xx;
+
+  /* See how many active devices there are. */
+  for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) {
+    /* check if any active/known devices is a match */
+    if ((!bdcmp(bda, bta_hh_cb.kdev[xx].addr) &&
+         bdcmp(bda, bd_addr_null) != 0)) {
+#if (BTA_HH_DEBUG == TRUE)
+      APPL_TRACE_DEBUG("found kdev_cb[%d] hid_handle = %d ", xx,
+                       bta_hh_cb.kdev[xx].hid_handle)
+#endif
+      return xx;
+    }
+#if (BTA_HH_DEBUG == TRUE)
+    else
+      APPL_TRACE_DEBUG("in_use ? [%d] kdev[%d].hid_handle = %d state = [%d]",
+                       bta_hh_cb.kdev[xx].in_use, xx,
+                       bta_hh_cb.kdev[xx].hid_handle, bta_hh_cb.kdev[xx].state);
+#endif
+  }
+
+  /* if no active device match, find a spot for it */
+  for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) {
+    if (!bta_hh_cb.kdev[xx].in_use) {
+      bdcpy(bta_hh_cb.kdev[xx].addr, bda);
+      break;
+    }
+  }
+/* If device list full, report BTA_HH_IDX_INVALID */
+#if (BTA_HH_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hh_find_cb:: index = %d while max = %d", xx,
+                   BTA_HH_MAX_DEVICE);
+#endif
+
+  if (xx == BTA_HH_MAX_DEVICE) xx = BTA_HH_IDX_INVALID;
+
+  return xx;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_clean_up_kdev
+ *
+ * Description      Clean up device control block when device is removed from
+ *                  manitainace list, and update control block index map.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_clean_up_kdev(tBTA_HH_DEV_CB* p_cb) {
+  uint8_t index;
+
+  if (p_cb->hid_handle != BTA_HH_INVALID_HANDLE) {
+#if (BTA_HH_LE_INCLUDED == TRUE)
+    if (p_cb->is_le_device)
+      bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] =
+          BTA_HH_IDX_INVALID;
+    else
+#endif
+      bta_hh_cb.cb_index[p_cb->hid_handle] = BTA_HH_IDX_INVALID;
+  }
+
+  /* reset device control block */
+  index = p_cb->index; /* Preserve index for this control block */
+
+  /* Free buffer for report descriptor info */
+  osi_free_and_reset((void**)&p_cb->dscp_info.descriptor.dsc_list);
+
+  memset(p_cb, 0, sizeof(tBTA_HH_DEV_CB)); /* Reset control block */
+
+  p_cb->index = index; /* Restore index for this control block */
+  p_cb->state = BTA_HH_IDLE_ST;
+  p_cb->hid_handle = BTA_HH_INVALID_HANDLE;
+}
+/*******************************************************************************
+ *
+ * Function         bta_hh_update_di_info
+ *
+ * Description      Maintain a known device list for BTA HH.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_update_di_info(tBTA_HH_DEV_CB* p_cb, uint16_t vendor_id,
+                           uint16_t product_id, uint16_t version,
+#if (BTA_HH_LE_INCLUDED == TRUE)
+                           uint8_t flag)
+#else
+                           UNUSED_ATTR uint8_t flag)
+#endif
+{
+#if (BTA_HH_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("vendor_id = 0x%2x product_id = 0x%2x version = 0x%2x",
+                   vendor_id, product_id, version);
+#endif
+  p_cb->dscp_info.vendor_id = vendor_id;
+  p_cb->dscp_info.product_id = product_id;
+  p_cb->dscp_info.version = version;
+#if (BTA_HH_LE_INCLUDED == TRUE)
+  p_cb->dscp_info.flag = flag;
+#endif
+}
+/*******************************************************************************
+ *
+ * Function         bta_hh_add_device_to_list
+ *
+ * Description      Maintain a known device list for BTA HH.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_add_device_to_list(tBTA_HH_DEV_CB* p_cb, uint8_t handle,
+                               uint16_t attr_mask,
+                               tHID_DEV_DSCP_INFO* p_dscp_info,
+                               uint8_t sub_class, uint16_t ssr_max_latency,
+                               uint16_t ssr_min_tout, uint8_t app_id) {
+#if (BTA_HH_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("subclass = 0x%2x", sub_class);
+#endif
+
+  p_cb->hid_handle = handle;
+  p_cb->in_use = true;
+  p_cb->attr_mask = attr_mask;
+
+  p_cb->sub_class = sub_class;
+  p_cb->app_id = app_id;
+
+  p_cb->dscp_info.ssr_max_latency = ssr_max_latency;
+  p_cb->dscp_info.ssr_min_tout = ssr_min_tout;
+
+  /* store report descriptor info */
+  if (p_dscp_info) {
+    osi_free_and_reset((void**)&p_cb->dscp_info.descriptor.dsc_list);
+
+    if (p_dscp_info->dl_len) {
+      p_cb->dscp_info.descriptor.dsc_list =
+          (uint8_t*)osi_malloc(p_dscp_info->dl_len);
+      p_cb->dscp_info.descriptor.dl_len = p_dscp_info->dl_len;
+      memcpy(p_cb->dscp_info.descriptor.dsc_list, p_dscp_info->dsc_list,
+             p_dscp_info->dl_len);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_tod_spt
+ *
+ * Description      Check to see if this type of device is supported
+ *
+ * Returns
+ *
+ ******************************************************************************/
+bool bta_hh_tod_spt(tBTA_HH_DEV_CB* p_cb, uint8_t sub_class) {
+  uint8_t xx;
+  uint8_t cod = (sub_class >> 2); /* lower two bits are reserved */
+
+  for (xx = 0; xx < p_bta_hh_cfg->max_devt_spt; xx++) {
+    if (cod == (uint8_t)p_bta_hh_cfg->p_devt_list[xx].tod) {
+      p_cb->app_id = p_bta_hh_cfg->p_devt_list[xx].app_id;
+#if (BTA_HH_DEBUG == TRUE)
+      APPL_TRACE_EVENT("bta_hh_tod_spt sub_class:0x%x supported", sub_class);
+#endif
+      return true;
+    }
+  }
+#if (BTA_HH_DEBUG == TRUE)
+  APPL_TRACE_EVENT("bta_hh_tod_spt sub_class:0x%x NOT supported", sub_class);
+#endif
+  return false;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_parse_keybd_rpt
+ *
+ * Description      This utility function parse a boot mode keyboard report.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_parse_keybd_rpt(tBTA_HH_BOOT_RPT* p_kb_data, uint8_t* p_report,
+                            uint16_t report_len) {
+  tBTA_HH_KB_CB* p_kb = &bta_hh_cb.kb_cb;
+  tBTA_HH_KEYBD_RPT* p_data = &p_kb_data->data_rpt.keybd_rpt;
+
+  uint8_t this_char, ctl_shift;
+  uint16_t xx, yy, key_idx = 0;
+  uint8_t this_report[BTA_HH_MAX_RPT_CHARS];
+
+#if (BTA_HH_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hh_parse_keybd_rpt:  (report=%p, report_len=%d) called",
+                   p_report, report_len);
+#endif
+
+  if (report_len < 2) return;
+
+  ctl_shift = *p_report++;
+  report_len--;
+
+  if (report_len > BTA_HH_MAX_RPT_CHARS) report_len = BTA_HH_MAX_RPT_CHARS;
+
+  memset(this_report, 0, BTA_HH_MAX_RPT_CHARS);
+  memset(p_data, 0, sizeof(tBTA_HH_KEYBD_RPT));
+  memcpy(this_report, p_report, report_len);
+
+  /* Take care of shift, control, GUI and alt, modifier keys  */
+  for (xx = 0; xx < BTA_HH_MOD_MAX_KEY; xx++) {
+    if (ctl_shift & bta_hh_mod_key_mask[xx]) {
+      APPL_TRACE_DEBUG("Mod Key[%02x] pressed", bta_hh_mod_key_mask[xx]);
+      p_kb->mod_key[xx] = true;
+    } else if (p_kb->mod_key[xx]) {
+      p_kb->mod_key[xx] = false;
+    }
+    /* control key flag is set */
+    p_data->mod_key[xx] = p_kb->mod_key[xx];
+  }
+
+  /***************************************************************************/
+  /*  First step is to remove all characters we saw in the last report       */
+  /***************************************************************************/
+  for (xx = 0; xx < report_len; xx++) {
+    for (yy = 0; yy < BTA_HH_MAX_RPT_CHARS; yy++) {
+      if (this_report[xx] == p_kb->last_report[yy]) {
+        this_report[xx] = 0;
+      }
+    }
+  }
+  /***************************************************************************/
+  /*  Now, process all the characters in the report, up to 6 keycodes        */
+  /***************************************************************************/
+  for (xx = 0; xx < report_len; xx++) {
+#if (BTA_HH_DEBUG == TRUE)
+    APPL_TRACE_DEBUG("this_char = %02x", this_report[xx]);
+#endif
+    if ((this_char = this_report[xx]) == 0) continue;
+    /* take the key code as the report data */
+    if (this_report[xx] == BTA_HH_KB_CAPS_LOCK)
+      p_kb->caps_lock = p_kb->caps_lock ? false : true;
+    else if (this_report[xx] == BTA_HH_KB_NUM_LOCK)
+      p_kb->num_lock = p_kb->num_lock ? false : true;
+    else
+      p_data->this_char[key_idx++] = this_char;
+
+#if (BTA_HH_DEBUG == TRUE)
+    APPL_TRACE_DEBUG("found keycode %02x ", this_report[xx]);
+#endif
+    p_data->caps_lock = p_kb->caps_lock;
+    p_data->num_lock = p_kb->num_lock;
+  }
+
+  memset(p_kb->last_report, 0, BTA_HH_MAX_RPT_CHARS);
+  memcpy(p_kb->last_report, p_report, report_len);
+
+  return;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_parse_mice_rpt
+ *
+ * Description      This utility function parse a boot mode mouse report.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_parse_mice_rpt(tBTA_HH_BOOT_RPT* p_mice_data, uint8_t* p_report,
+                           uint16_t report_len) {
+  tBTA_HH_MICE_RPT* p_data = &p_mice_data->data_rpt.mice_rpt;
+#if (BTA_HH_DEBUG == TRUE)
+  uint8_t xx;
+
+  APPL_TRACE_DEBUG(
+      "bta_hh_parse_mice_rpt:  bta_keybd_rpt_rcvd(report=%p, \
+                report_len=%d) called",
+      p_report, report_len);
+#endif
+
+  if (report_len < 3) return;
+
+  if (report_len > BTA_HH_MAX_RPT_CHARS) report_len = BTA_HH_MAX_RPT_CHARS;
+
+#if (BTA_HH_DEBUG == TRUE)
+  for (xx = 0; xx < report_len; xx++) {
+    APPL_TRACE_DEBUG("this_char = %02x", p_report[xx]);
+  }
+#endif
+
+  /* only first bytes lower 3 bits valid */
+  p_data->mouse_button = (p_report[0] & 0x07);
+
+  /* x displacement */
+  p_data->delta_x = p_report[1];
+
+  /* y displacement */
+  p_data->delta_y = p_report[2];
+
+#if (BTA_HH_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("mice button: 0x%2x", p_data->mouse_button);
+  APPL_TRACE_DEBUG("mice move: x = %d y = %d", p_data->delta_x,
+                   p_data->delta_y);
+#endif
+
+  return;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_read_ssr_param
+ *
+ * Description      Read the SSR Parameter for the remote device
+ *
+ * Returns          tBTA_HH_STATUS  operation status
+ *
+ ******************************************************************************/
+tBTA_HH_STATUS bta_hh_read_ssr_param(BD_ADDR bd_addr, uint16_t* p_max_ssr_lat,
+                                     uint16_t* p_min_ssr_tout) {
+  tBTA_HH_STATUS status = BTA_HH_ERR;
+  tBTA_HH_CB* p_cb = &bta_hh_cb;
+  uint8_t i;
+  uint16_t ssr_max_latency;
+  for (i = 0; i < BTA_HH_MAX_KNOWN; i++) {
+    if (memcmp(p_cb->kdev[i].addr, bd_addr, BD_ADDR_LEN) == 0) {
+      /* if remote device does not have HIDSSRHostMaxLatency attribute in SDP,
+      set SSR max latency default value here.  */
+      if (p_cb->kdev[i].dscp_info.ssr_max_latency == HID_SSR_PARAM_INVALID) {
+        /* The default is calculated as half of link supervision timeout.*/
+
+        BTM_GetLinkSuperTout(p_cb->kdev[i].addr, &ssr_max_latency);
+        ssr_max_latency = BTA_HH_GET_DEF_SSR_MAX_LAT(ssr_max_latency);
+
+        /* per 1.1 spec, if the newly calculated max latency is greater than
+        BTA_HH_SSR_MAX_LATENCY_DEF which is 500ms, use
+        BTA_HH_SSR_MAX_LATENCY_DEF */
+        if (ssr_max_latency > BTA_HH_SSR_MAX_LATENCY_DEF)
+          ssr_max_latency = BTA_HH_SSR_MAX_LATENCY_DEF;
+
+        *p_max_ssr_lat = ssr_max_latency;
+      } else
+        *p_max_ssr_lat = p_cb->kdev[i].dscp_info.ssr_max_latency;
+
+      if (p_cb->kdev[i].dscp_info.ssr_min_tout == HID_SSR_PARAM_INVALID)
+        *p_min_ssr_tout = BTA_HH_SSR_MIN_TOUT_DEF;
+      else
+        *p_min_ssr_tout = p_cb->kdev[i].dscp_info.ssr_min_tout;
+
+      status = BTA_HH_OK;
+
+      break;
+    }
+  }
+
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_cleanup_disable
+ *
+ * Description      when disable finished, cleanup control block and send
+ *                  callback
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hh_cleanup_disable(tBTA_HH_STATUS status) {
+  uint8_t xx;
+  /* free buffer in CB holding report descriptors */
+  for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) {
+    osi_free_and_reset(
+        (void**)&bta_hh_cb.kdev[xx].dscp_info.descriptor.dsc_list);
+  }
+  osi_free_and_reset((void**)&bta_hh_cb.p_disc_db);
+
+  (*bta_hh_cb.p_cback)(BTA_HH_DISABLE_EVT, (tBTA_HH*)&status);
+  /* all connections are down, no waiting for diconnect */
+  memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB));
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_dev_handle_to_cb_idx
+ *
+ * Description      convert a HID device handle to the device control block
+ *                  index.
+ *
+ *
+ * Returns          uint8_t: index of the device control block.
+ *
+ ******************************************************************************/
+uint8_t bta_hh_dev_handle_to_cb_idx(uint8_t dev_handle) {
+  uint8_t index = BTA_HH_IDX_INVALID;
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+  if (BTA_HH_IS_LE_DEV_HDL(dev_handle)) {
+    if (BTA_HH_IS_LE_DEV_HDL_VALID(dev_handle))
+      index = bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(dev_handle)];
+#if (BTA_HH_DEBUG == TRUE)
+    APPL_TRACE_DEBUG("bta_hh_dev_handle_to_cb_idx dev_handle = %d index = %d",
+                     dev_handle, index);
+#endif
+  } else
+#endif
+      /* regular HID device checking */
+      if (dev_handle < BTA_HH_MAX_KNOWN)
+    index = bta_hh_cb.cb_index[dev_handle];
+
+  return index;
+}
+#if (BTA_HH_DEBUG == TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_hh_trace_dev_db
+ *
+ * Description      Check to see if this type of device is supported
+ *
+ * Returns
+ *
+ ******************************************************************************/
+void bta_hh_trace_dev_db(void) {
+  uint8_t xx;
+
+  APPL_TRACE_DEBUG("bta_hh_trace_dev_db:: Device DB list********************");
+
+  for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) {
+    APPL_TRACE_DEBUG("kdev[%d] in_use[%d]  handle[%d] ", xx,
+                     bta_hh_cb.kdev[xx].in_use, bta_hh_cb.kdev[xx].hid_handle);
+
+    APPL_TRACE_DEBUG(
+        "\t\t\t attr_mask[%04x] state [%d] sub_class[%02x] index = %d",
+        bta_hh_cb.kdev[xx].attr_mask, bta_hh_cb.kdev[xx].state,
+        bta_hh_cb.kdev[xx].sub_class, bta_hh_cb.kdev[xx].index);
+  }
+  APPL_TRACE_DEBUG("*********************************************************");
+}
+#endif
+#endif /* HL_INCLUDED */
diff --git a/bt/bta/hl/bta_hl_act.cc b/bt/bta/hl/bta_hl_act.cc
new file mode 100644
index 0000000..5db5707
--- /dev/null
+++ b/bt/bta/hl/bta_hl_act.cc
@@ -0,0 +1,2443 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 HeaLth device profile (HL) action functions for
+ *  the state machine.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_target.h"
+#if (HL_INCLUDED == TRUE)
+
+#include "bt_common.h"
+#include "bta_hl_api.h"
+#include "bta_hl_int.h"
+#include "bta_sys.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+#include "sdp_api.h"
+#include "utl.h"
+
+/*****************************************************************************
+ *  Local Function prototypes
+ ****************************************************************************/
+#if (BTA_HL_DEBUG == TRUE && BT_TRACE_VERBOSE == TRUE)
+static char* bta_hl_mcap_evt_code(uint8_t evt_code);
+static char* bta_hl_dch_oper_code(tBTA_HL_DCH_OPER oper_code);
+static char* bta_hl_cback_evt_code(uint8_t evt_code);
+#endif
+static void bta_hl_sdp_cback(uint8_t sdp_op, uint8_t app_idx, uint8_t mcl_idx,
+                             uint8_t mdl_idx, uint16_t status);
+static void bta_hl_sdp_cback0(uint16_t status);
+static void bta_hl_sdp_cback1(uint16_t status);
+static void bta_hl_sdp_cback2(uint16_t status);
+static void bta_hl_sdp_cback3(uint16_t status);
+static void bta_hl_sdp_cback4(uint16_t status);
+static void bta_hl_sdp_cback5(uint16_t status);
+static void bta_hl_sdp_cback6(uint16_t status);
+
+static tSDP_DISC_CMPL_CB* const bta_hl_sdp_cback_arr[] = {
+    bta_hl_sdp_cback0, bta_hl_sdp_cback1, bta_hl_sdp_cback2, bta_hl_sdp_cback3,
+    bta_hl_sdp_cback4, bta_hl_sdp_cback5, bta_hl_sdp_cback6};
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_mca_cong_change
+ *
+ * Description      Action routine for processing congestion change notification
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_cong_change(uint8_t app_idx, uint8_t mcl_idx,
+                                uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  tMCA_CONG_CHG* p_cong_chg = &p_data->mca_evt.mca_data.cong_chg;
+  tBTA_HL evt_data;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_mca_cong_change mdl_id=%d cong=%d",
+                   p_cong_chg->mdl_id, p_cong_chg->cong);
+#endif
+  evt_data.dch_cong_ind.cong = p_dcb->cong = p_cong_chg->cong;
+  evt_data.dch_cong_ind.mdl_handle = p_dcb->mdl_handle;
+  evt_data.dch_cong_ind.mcl_handle = p_mcb->mcl_handle;
+  evt_data.dch_cong_ind.app_handle = p_acb->app_handle;
+
+  p_acb->p_cback(BTA_HL_CONG_CHG_IND_EVT, (tBTA_HL*)&evt_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_echo_test
+ *
+ * Description      Action routine for processing echo test request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_echo_test(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+                          UNUSED_ATTR tBTA_HL_DATA* p_data) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_echo_test");
+#endif
+
+  p_dcb->echo_oper = BTA_HL_ECHO_OP_CI_GET_ECHO_DATA;
+  p_dcb->cout_oper |= BTA_HL_CO_GET_ECHO_DATA_MASK;
+
+  bta_hl_co_get_echo_data(
+      p_acb->app_id, p_mcb->mcl_handle, p_dcb->p_echo_tx_pkt->len,
+      BTA_HL_GET_BUF_PTR(p_dcb->p_echo_tx_pkt), BTA_HL_CI_GET_ECHO_DATA_EVT);
+}
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_sdp_init
+ *
+ * Description      Action routine for processing DCH SDP initiation
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_sdp_init(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+                         tBTA_HL_DATA* p_data) {
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_sdp_init");
+#endif
+  if (p_mcb->sdp_oper == BTA_HL_SDP_OP_NONE) {
+    p_mcb->sdp_mdl_idx = mdl_idx;
+    if (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_OPEN) {
+      p_mcb->sdp_oper = BTA_HL_SDP_OP_DCH_OPEN_INIT;
+
+    } else {
+      p_mcb->sdp_oper = BTA_HL_SDP_OP_DCH_RECONNECT_INIT;
+    }
+
+    if (bta_hl_init_sdp(p_mcb->sdp_oper, app_idx, mcl_idx, mdl_idx) !=
+        BTA_HL_STATUS_OK) {
+      APPL_TRACE_ERROR("SDP INIT failed");
+      p_mcb->sdp_oper = BTA_HL_SDP_OP_NONE;
+      bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_SDP_FAIL_EVT,
+                            p_data);
+    }
+  } else {
+    APPL_TRACE_ERROR("SDP in use");
+    bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_SDP_FAIL_EVT,
+                          p_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_close_echo_test
+ *
+ * Description      Action routine for processing the closing of echo test
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_close_echo_test(uint8_t app_idx, uint8_t mcl_idx,
+                                uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_close_echo_test");
+#endif
+
+  switch (p_dcb->echo_oper) {
+    case BTA_HL_ECHO_OP_DCH_CLOSE_CFM:
+    case BTA_HL_ECHO_OP_OPEN_IND:
+    case BTA_HL_ECHO_OP_ECHO_PKT:
+      p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST;
+      break;
+    case BTA_HL_ECHO_OP_MDL_CREATE_CFM:
+    case BTA_HL_ECHO_OP_DCH_OPEN_CFM:
+    case BTA_HL_ECHO_OP_LOOP_BACK:
+    default:
+      break;
+  }
+
+  if (MCA_CloseReq((tMCA_DL)p_dcb->mdl_handle) != MCA_SUCCESS) {
+    bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
+                          p_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_mca_rcv_data
+ *
+ * Description      Action routine for processing the received data
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_rcv_data(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+                             tBTA_HL_DATA* p_data) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_mca_rcv_data");
+#endif
+
+  if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
+    switch (p_dcb->echo_oper) {
+      case BTA_HL_ECHO_OP_ECHO_PKT:
+
+        if (MCA_WriteReq((tMCA_DL)p_dcb->mdl_handle,
+                         p_data->mca_rcv_data_evt.p_pkt) != MCA_SUCCESS) {
+          osi_free_and_reset((void**)&p_data->mca_rcv_data_evt.p_pkt);
+          bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+                                BTA_HL_DCH_CLOSE_ECHO_TEST_EVT, p_data);
+        }
+        break;
+      case BTA_HL_ECHO_OP_LOOP_BACK:
+
+        p_dcb->p_echo_rx_pkt = p_data->mca_rcv_data_evt.p_pkt;
+        p_dcb->echo_oper = BTA_HL_ECHO_OP_CI_PUT_ECHO_DATA;
+        p_dcb->cout_oper |= BTA_HL_CO_PUT_ECHO_DATA_MASK;
+        p_dcb->ci_put_echo_data_status = BTA_HL_STATUS_FAIL;
+
+        bta_hl_co_put_echo_data(p_acb->app_id, p_mcb->mcl_handle,
+                                p_dcb->p_echo_rx_pkt->len,
+                                BTA_HL_GET_BUF_PTR(p_dcb->p_echo_rx_pkt),
+                                BTA_HL_CI_PUT_ECHO_DATA_EVT);
+        break;
+      default:
+        APPL_TRACE_ERROR("Unknonw echo_oper=%d", p_dcb->echo_oper);
+        break;
+    }
+
+  } else {
+    p_dcb->cout_oper |= BTA_HL_CO_PUT_RX_DATA_MASK;
+    p_dcb->p_rx_pkt = p_data->mca_rcv_data_evt.p_pkt;
+
+    bta_hl_co_put_rx_data(
+        p_acb->app_id, p_dcb->mdl_handle, p_dcb->p_rx_pkt->len,
+        BTA_HL_GET_BUF_PTR(p_dcb->p_rx_pkt), BTA_HL_CI_PUT_RX_DATA_EVT);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_ci_put_echo_data
+ *
+ * Description      Action routine for processing the call-in of the
+ *                  put echo data event
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_ci_put_echo_data(uint8_t app_idx, uint8_t mcl_idx,
+                                 uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_ci_put_echo_data");
+#endif
+
+  p_dcb->cout_oper &= ~BTA_HL_CO_PUT_ECHO_DATA_MASK;
+  osi_free_and_reset((void**)&p_dcb->p_echo_rx_pkt);
+  p_dcb->ci_put_echo_data_status = p_data->ci_get_put_echo_data.status;
+
+  p_dcb->echo_oper = BTA_HL_ECHO_OP_DCH_CLOSE_CFM;
+  bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+                        BTA_HL_DCH_CLOSE_ECHO_TEST_EVT, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_ci_get_echo_data
+ *
+ * Description      Action routine for processing the call-in of the
+ *                  get echo data event
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_ci_get_echo_data(uint8_t app_idx, uint8_t mcl_idx,
+                                 uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  tBTA_HL_STATUS status;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_ci_get_echo_data");
+#endif
+
+  p_dcb->cout_oper &= ~BTA_HL_CO_GET_ECHO_DATA_MASK;
+
+  if (!p_dcb->abort_oper) {
+    status = p_data->ci_get_put_echo_data.status;
+    if (status == BTA_HL_STATUS_OK) {
+      p_dcb->echo_oper = BTA_HL_ECHO_OP_MDL_CREATE_CFM;
+      bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_OPEN_EVT,
+                            p_data);
+    } else {
+      bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+                            BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+    }
+  } else {
+    bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
+                          p_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_ci_put_rx_data
+ *
+ * Description      Action routine for processing the call-in of the
+ *                  put rx data event
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_ci_put_rx_data(uint8_t app_idx, uint8_t mcl_idx,
+                               uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  tBTA_HL evt_data;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_ci_put_rx_data");
+#endif
+
+  p_dcb->cout_oper &= ~BTA_HL_CO_PUT_RX_DATA_MASK;
+  osi_free_and_reset((void**)&p_dcb->p_rx_pkt);
+  bta_hl_build_rcv_data_ind(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
+                            p_dcb->mdl_handle);
+  p_acb->p_cback(BTA_HL_DCH_RCV_DATA_IND_EVT, (tBTA_HL*)&evt_data);
+  if (p_dcb->close_pending) {
+    if (!p_dcb->cout_oper) {
+      bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_EVT,
+                            p_data);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_ci_get_tx_data
+ *
+ * Description      Action routine for processing the call-in of the
+ *                  get tx data event
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_ci_get_tx_data(uint8_t app_idx, uint8_t mcl_idx,
+                               uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  tMCA_RESULT result;
+  tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+  bool free_buf = false;
+  bool close_dch = false;
+  tBTA_HL evt_data;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_ci_get_tx_data");
+#endif
+
+  p_dcb->cout_oper &= ~BTA_HL_CO_GET_TX_DATA_MASK;
+
+  if (p_dcb->close_pending) {
+    status = BTA_HL_STATUS_FAIL;
+    free_buf = true;
+
+    if (!p_dcb->cout_oper) {
+      close_dch = true;
+    }
+  } else {
+    if ((result = MCA_WriteReq((tMCA_DL)p_dcb->mdl_handle, p_dcb->p_tx_pkt)) !=
+        MCA_SUCCESS) {
+      if (result == MCA_BUSY) {
+        status = BTA_HL_STATUS_DCH_BUSY;
+      } else {
+        status = BTA_HL_STATUS_FAIL;
+      }
+      free_buf = true;
+    } else {
+      p_dcb->p_tx_pkt = NULL;
+    }
+  }
+
+  if (free_buf) osi_free_and_reset((void**)&p_dcb->p_tx_pkt);
+
+  bta_hl_build_send_data_cfm(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
+                             p_dcb->mdl_handle, status);
+  p_acb->p_cback(BTA_HL_DCH_SEND_DATA_CFM_EVT, (tBTA_HL*)&evt_data);
+
+  if (close_dch) {
+    bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_EVT,
+                          p_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_send_data
+ *
+ * Description      Action routine for processing api send data request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_send_data(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+                          tBTA_HL_DATA* p_data) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  tBTA_HL evt_data;
+  bool success = true;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_send_data");
+#endif
+
+  if (!(p_dcb->cout_oper & BTA_HL_CO_GET_TX_DATA_MASK)) {
+    // p_dcb->chnl_cfg.fcs may be BTA_HL_MCA_USE_FCS (0x11) or BTA_HL_MCA_NO_FCS
+    // (0x10) or BTA_HL_DEFAULT_SOURCE_FCS (1)
+    bool fcs_use = (bool)(p_dcb->chnl_cfg.fcs & BTA_HL_MCA_FCS_USE_MASK);
+    if ((p_dcb->p_tx_pkt =
+             bta_hl_get_buf(p_data->api_send_data.pkt_size, fcs_use)) != NULL) {
+      bta_hl_co_get_tx_data(
+          p_acb->app_id, p_dcb->mdl_handle, p_data->api_send_data.pkt_size,
+          BTA_HL_GET_BUF_PTR(p_dcb->p_tx_pkt), BTA_HL_CI_GET_TX_DATA_EVT);
+      p_dcb->cout_oper |= BTA_HL_CO_GET_TX_DATA_MASK;
+    } else {
+      success = false;
+    }
+  } else {
+    success = false;
+  }
+
+  if (!success) {
+    bta_hl_build_send_data_cfm(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
+                               p_dcb->mdl_handle, BTA_HL_STATUS_FAIL);
+    p_acb->p_cback(BTA_HL_DCH_SEND_DATA_CFM_EVT, (tBTA_HL*)&evt_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_close_cmpl
+ *
+ * Description      Action routine for processing the close complete event
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_close_cmpl(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+                           tBTA_HL_DATA* p_data) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  tBTA_HL evt_data;
+  tBTA_HL_EVT event = 0;
+  bool send_evt = true;
+  tBTA_HL_STATUS status;
+
+#if (BTA_HL_DEBUG == TRUE)
+#if (BT_TRACE_VERBOSE == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_close_cmpl dch oper=%s",
+                   bta_hl_dch_oper_code(p_dcb->dch_oper));
+#else
+  APPL_TRACE_DEBUG("bta_hl_dch_close_cmpl dch oper=%d", p_dcb->dch_oper);
+#endif
+#endif
+
+  switch (p_dcb->dch_oper) {
+    case BTA_HL_DCH_OP_LOCAL_OPEN:
+    case BTA_HL_DCH_OP_LOCAL_RECONNECT:
+
+      if (p_dcb->abort_oper & BTA_HL_ABORT_LOCAL_MASK) {
+        bta_hl_build_abort_cfm(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
+                               BTA_HL_STATUS_OK);
+        event = BTA_HL_DCH_ABORT_CFM_EVT;
+      } else if (p_dcb->abort_oper & BTA_HL_ABORT_REMOTE_MASK) {
+        bta_hl_build_abort_ind(&evt_data, p_acb->app_handle, p_mcb->mcl_handle);
+        event = BTA_HL_DCH_ABORT_IND_EVT;
+      } else {
+        bta_hl_build_dch_open_cfm(&evt_data, p_acb->app_handle,
+                                  p_mcb->mcl_handle, BTA_HL_INVALID_MDL_HANDLE,
+                                  0, 0, 0, 0, 0, BTA_HL_STATUS_FAIL);
+        event = BTA_HL_DCH_OPEN_CFM_EVT;
+        if (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_RECONNECT) {
+          event = BTA_HL_DCH_RECONNECT_CFM_EVT;
+        }
+      }
+      break;
+
+    case BTA_HL_DCH_OP_LOCAL_CLOSE:
+    case BTA_HL_DCH_OP_REMOTE_DELETE:
+    case BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT:
+    case BTA_HL_DCH_OP_NONE:
+
+      bta_hl_build_dch_close_cfm(&evt_data, p_acb->app_handle,
+                                 p_mcb->mcl_handle, p_dcb->mdl_handle,
+                                 BTA_HL_STATUS_OK);
+      event = BTA_HL_DCH_CLOSE_CFM_EVT;
+      break;
+
+    case BTA_HL_DCH_OP_REMOTE_CLOSE:
+      bta_hl_build_dch_close_ind(&evt_data, p_acb->app_handle,
+                                 p_mcb->mcl_handle, p_dcb->mdl_handle,
+                                 p_dcb->intentional_close);
+      event = BTA_HL_DCH_CLOSE_IND_EVT;
+      break;
+
+    case BTA_HL_DCH_OP_REMOTE_OPEN:
+
+      if (p_dcb->abort_oper & BTA_HL_ABORT_LOCAL_MASK) {
+        bta_hl_build_abort_cfm(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
+                               BTA_HL_STATUS_OK);
+        event = BTA_HL_DCH_ABORT_CFM_EVT;
+      } else if (p_dcb->abort_oper & BTA_HL_ABORT_REMOTE_MASK) {
+        bta_hl_build_abort_ind(&evt_data, p_acb->app_handle, p_mcb->mcl_handle);
+        event = BTA_HL_DCH_ABORT_IND_EVT;
+      } else {
+        bta_hl_build_dch_close_ind(&evt_data, p_acb->app_handle,
+                                   p_mcb->mcl_handle, p_dcb->mdl_handle,
+                                   p_dcb->intentional_close);
+        event = BTA_HL_DCH_CLOSE_IND_EVT;
+      }
+      break;
+
+    case BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST:
+    /* this is normal echo test close */
+    case BTA_HL_DCH_OP_REMOTE_CREATE:
+    case BTA_HL_DCH_OP_REMOTE_RECONNECT:
+      send_evt = false;
+      break;
+
+    default:
+#if (BTA_HL_DEBUG == TRUE)
+#if (BT_TRACE_VERBOSE == TRUE)
+      APPL_TRACE_ERROR("DCH operation not found oper=%s",
+                       bta_hl_dch_oper_code(p_dcb->dch_oper));
+#else
+      APPL_TRACE_ERROR("DCH operation not found oper=%d", p_dcb->dch_oper);
+#endif
+#endif
+      send_evt = false;
+      break;
+  }
+
+  if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
+    p_mcb->echo_test = false;
+    send_evt = false;
+
+    if (p_dcb->dch_oper != BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST) {
+      switch (p_dcb->echo_oper) {
+        case BTA_HL_ECHO_OP_CI_GET_ECHO_DATA:
+        case BTA_HL_ECHO_OP_SDP_INIT:
+        case BTA_HL_ECHO_OP_MDL_CREATE_CFM:
+        case BTA_HL_ECHO_OP_DCH_OPEN_CFM:
+        case BTA_HL_ECHO_OP_LOOP_BACK:
+
+          status = BTA_HL_STATUS_FAIL;
+          send_evt = true;
+          break;
+        case BTA_HL_ECHO_OP_OPEN_IND:
+        case BTA_HL_ECHO_OP_ECHO_PKT:
+          break;
+        default:
+          APPL_TRACE_ERROR("Invalid echo_oper=%d", p_dcb->echo_oper);
+          break;
+      }
+    } else {
+      status = p_dcb->ci_put_echo_data_status;
+      send_evt = true;
+    }
+
+    if (send_evt) {
+      bta_hl_build_echo_test_cfm(&evt_data, p_acb->app_handle,
+                                 p_mcb->mcl_handle, status);
+      event = BTA_HL_DCH_ECHO_TEST_CFM_EVT;
+    }
+  }
+
+  bta_hl_clean_mdl_cb(app_idx, mcl_idx, mdl_idx);
+
+  if (send_evt) {
+    if (p_acb->p_cback) {
+#if (BTA_HL_DEBUG == TRUE)
+#if (BT_TRACE_VERBOSE == TRUE)
+      APPL_TRACE_DEBUG("Send Event: %s", bta_hl_cback_evt_code(event));
+#else
+      APPL_TRACE_DEBUG("Send Event: 0x%02x", event);
+#endif
+#endif
+      p_acb->p_cback(event, (tBTA_HL*)&evt_data);
+    }
+  }
+  /* check cch close is in progress or not */
+  bta_hl_check_cch_close(app_idx, mcl_idx, p_data, false);
+}
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_mca_close_ind
+ *
+ * Description      Action routine for processing the close indication
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_close_ind(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+                              tBTA_HL_DATA* p_data) {
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+#if (BT_TRACE_VERBOSE == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_mca_close_ind dch oper=%s",
+                   bta_hl_dch_oper_code(p_dcb->dch_oper));
+#else
+  APPL_TRACE_DEBUG("bta_hl_dch_mca_close_ind dch oper=%d", p_dcb->dch_oper);
+#endif
+#endif
+
+  p_dcb->intentional_close = false;
+  if (p_data->mca_evt.mca_data.close_ind.reason == L2CAP_DISC_OK) {
+    p_dcb->intentional_close = true;
+  }
+
+  if (!p_dcb->cout_oper) {
+    if ((p_dcb->dch_oper != BTA_HL_DCH_OP_REMOTE_OPEN) &&
+        (p_dcb->dch_oper != BTA_HL_DCH_OP_REMOTE_RECONNECT)) {
+      p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_CLOSE;
+    }
+    bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
+                          p_data);
+  } else {
+    p_dcb->close_pending = true;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_mca_close_cfm
+ *
+ * Description      Action routine for processing the close confirmation
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_close_cfm(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+                              tBTA_HL_DATA* p_data) {
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+#if (BT_TRACE_VERBOSE == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_mca_close_cfm dch_oper=%s",
+                   bta_hl_dch_oper_code(p_dcb->dch_oper));
+#else
+  APPL_TRACE_DEBUG("bta_hl_dch_mca_close_cfm dch_oper=%d", p_dcb->dch_oper);
+#endif
+#endif
+
+  switch (p_dcb->dch_oper) {
+    case BTA_HL_DCH_OP_LOCAL_CLOSE:
+    case BTA_HL_DCH_OP_LOCAL_OPEN:
+    case BTA_HL_DCH_OP_LOCAL_RECONNECT:
+    case BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST:
+    case BTA_HL_DCH_OP_REMOTE_DELETE:
+    case BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT:
+    case BTA_HL_DCH_OP_NONE:
+      bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+                            BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+      break;
+    default:
+#if (BTA_HL_DEBUG == TRUE)
+#if (BT_TRACE_VERBOSE == TRUE)
+      APPL_TRACE_ERROR("Invalid dch_oper=%s for close cfm",
+                       bta_hl_dch_oper_code(p_dcb->dch_oper));
+#else
+      APPL_TRACE_ERROR("Invalid dch_oper=%d for close cfm", p_dcb->dch_oper);
+#endif
+#endif
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_mca_close
+ *
+ * Description      Action routine for processing the DCH close request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_close(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+                          tBTA_HL_DATA* p_data) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+  tBTA_HL evt_data;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_mca_close");
+#endif
+  if (!p_dcb->cout_oper) {
+    p_dcb->close_pending = false;
+    if (MCA_CloseReq((tMCA_DL)p_dcb->mdl_handle) == MCA_SUCCESS) {
+      p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_CLOSE;
+    } else {
+      status = BTA_HL_STATUS_FAIL;
+    }
+
+    if ((status != BTA_HL_STATUS_OK) &&
+        (p_mcb->cch_close_dch_oper != BTA_HL_CCH_CLOSE_OP_DCH_CLOSE)) {
+      bta_hl_build_dch_close_cfm(&evt_data, p_acb->app_handle,
+                                 p_mcb->mcl_handle,
+                                 p_data->api_dch_close.mdl_handle, status);
+      p_acb->p_cback(BTA_HL_DCH_CLOSE_CFM_EVT, (tBTA_HL*)&evt_data);
+    }
+  } else {
+    p_dcb->close_pending = true;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_mca_open_ind
+ *
+ * Description      Action routine for processing the open indication
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_open_ind(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+                             tBTA_HL_DATA* p_data) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  tMCA_DL_OPEN* p_open_ind = &p_data->mca_evt.mca_data.open_ind;
+  tBTA_HL evt_data;
+  tBTA_HL_EVT event;
+  uint8_t old_dch_oper = BTA_HL_DCH_OP_NONE;
+  bool send_event = false;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_mca_open_ind");
+#endif
+  if ((p_dcb->dch_oper == BTA_HL_DCH_OP_REMOTE_OPEN) ||
+      (p_dcb->dch_oper == BTA_HL_DCH_OP_REMOTE_RECONNECT)) {
+    p_dcb->mdl_handle = (tBTA_HL_MDL_HANDLE)p_open_ind->mdl;
+    p_dcb->mtu = p_open_ind->mtu;
+
+    evt_data.dch_open_ind.mdl_handle = p_dcb->mdl_handle;
+    evt_data.dch_open_ind.mcl_handle = p_mcb->mcl_handle;
+    evt_data.dch_open_ind.app_handle = p_acb->app_handle;
+
+    evt_data.dch_open_ind.local_mdep_id = p_dcb->local_mdep_id;
+    evt_data.dch_open_ind.mdl_id = p_dcb->mdl_id;
+    evt_data.dch_open_ind.mtu = p_dcb->mtu;
+
+    if (p_dcb->chnl_cfg.fcr_opt.mode == L2CAP_FCR_ERTM_MODE) {
+      evt_data.dch_open_ind.dch_mode = BTA_HL_DCH_MODE_RELIABLE;
+      if (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx)) {
+        p_dcb->is_the_first_reliable = true;
+      }
+    } else {
+      evt_data.dch_open_ind.dch_mode = BTA_HL_DCH_MODE_STREAMING;
+    }
+    evt_data.dch_open_ind.first_reliable = p_dcb->is_the_first_reliable;
+
+    old_dch_oper = p_dcb->dch_oper;
+    p_dcb->dch_oper = BTA_HL_DCH_OP_NONE;
+  }
+
+  switch (old_dch_oper) {
+    case BTA_HL_DCH_OP_REMOTE_OPEN:
+
+      p_dcb->dch_mode = evt_data.dch_open_ind.dch_mode;
+      if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) {
+        bta_hl_save_mdl_cfg(app_idx, mcl_idx, mdl_idx);
+        event = BTA_HL_DCH_OPEN_IND_EVT;
+        send_event = true;
+      } else {
+        p_dcb->echo_oper = BTA_HL_ECHO_OP_ECHO_PKT;
+      }
+
+      break;
+
+    case BTA_HL_DCH_OP_REMOTE_RECONNECT:
+
+      if (bta_hl_validate_chan_cfg(app_idx, mcl_idx, mdl_idx)) {
+        bta_hl_save_mdl_cfg(app_idx, mcl_idx, mdl_idx);
+        event = BTA_HL_DCH_RECONNECT_IND_EVT;
+        send_event = true;
+      } else {
+        if (MCA_CloseReq((tMCA_DL)p_dcb->mdl_handle) == MCA_SUCCESS) {
+          p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT;
+        } else {
+          APPL_TRACE_ERROR("Unabel to close DCH for reconnect cfg mismatch");
+        }
+      }
+      break;
+    default:
+      break;
+  }
+
+  if (send_event) {
+    p_acb->p_cback(event, (tBTA_HL*)&evt_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_mca_open_cfm
+ *
+ * Description      Action routine for processing the open confirmation
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_open_cfm(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+                             tBTA_HL_DATA* p_data) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  tMCA_DL_OPEN* p_open_cfm = &p_data->mca_evt.mca_data.open_cfm;
+  tBTA_HL evt_data;
+  tBTA_HL_EVT event;
+  uint8_t old_dch_oper = BTA_HL_DCH_OP_NONE;
+  tBTA_HL_DCH_MODE dch_mode = BTA_HL_DCH_MODE_STREAMING;
+  bool send_event = false;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_mca_open_cfm");
+#endif
+  if ((p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_OPEN) ||
+      (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_RECONNECT)) {
+    p_dcb->mdl_handle = (tBTA_HL_MDL_HANDLE)p_open_cfm->mdl;
+    p_dcb->mtu = p_open_cfm->mtu;
+
+    /*todo verify dch_mode, mtu and fcs for reconnect */
+    if (p_dcb->chnl_cfg.fcr_opt.mode == L2CAP_FCR_ERTM_MODE) {
+      dch_mode = BTA_HL_DCH_MODE_RELIABLE;
+    }
+
+    if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) {
+      if (dch_mode == BTA_HL_DCH_MODE_RELIABLE) {
+        if (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx)) {
+          p_dcb->is_the_first_reliable = true;
+        }
+      }
+    }
+
+    bta_hl_build_dch_open_cfm(
+        &evt_data, p_acb->app_handle, p_mcb->mcl_handle, p_dcb->mdl_handle,
+        p_dcb->local_mdep_id, p_dcb->mdl_id, dch_mode,
+        p_dcb->is_the_first_reliable, p_dcb->mtu, BTA_HL_STATUS_OK);
+
+    old_dch_oper = p_dcb->dch_oper;
+    p_dcb->dch_oper = BTA_HL_DCH_OP_NONE;
+  } else {
+    APPL_TRACE_ERROR("Error dch oper =%d", p_dcb->dch_oper);
+    return;
+  }
+
+  switch (old_dch_oper) {
+    case BTA_HL_DCH_OP_LOCAL_OPEN:
+
+      p_dcb->dch_mode = dch_mode;
+      if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) {
+        bta_hl_save_mdl_cfg(app_idx, mcl_idx, mdl_idx);
+        event = BTA_HL_DCH_OPEN_CFM_EVT;
+        send_event = true;
+      } else {
+        p_dcb->echo_oper = BTA_HL_ECHO_OP_LOOP_BACK;
+        if (MCA_WriteReq((tMCA_DL)p_dcb->mdl_handle, p_dcb->p_echo_tx_pkt) !=
+            MCA_SUCCESS) {
+          bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+                                BTA_HL_DCH_CLOSE_ECHO_TEST_EVT, p_data);
+        } else {
+          p_dcb->p_echo_tx_pkt = NULL;
+        }
+      }
+      break;
+
+    case BTA_HL_DCH_OP_LOCAL_RECONNECT:
+
+      if (bta_hl_validate_chan_cfg(app_idx, mcl_idx, mdl_idx)) {
+        bta_hl_save_mdl_cfg(app_idx, mcl_idx, mdl_idx);
+        event = BTA_HL_DCH_RECONNECT_CFM_EVT;
+        send_event = true;
+      } else {
+        if (MCA_CloseReq((tMCA_DL)p_dcb->mdl_handle) == MCA_SUCCESS) {
+          p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT;
+        } else {
+          APPL_TRACE_ERROR("Unabel to close DCH for reconnect cfg mismatch");
+        }
+      }
+      break;
+    default:
+      break;
+  }
+
+  if (send_event) p_acb->p_cback(event, (tBTA_HL*)&evt_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_mca_abort_ind
+ *
+ * Description      Action routine for processing the abort indication
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_abort_ind(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+                              tBTA_HL_DATA* p_data) {
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_mca_abort_ind");
+#endif
+
+  p_dcb->abort_oper |= BTA_HL_ABORT_REMOTE_MASK;
+  bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
+                        p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_mca_abort_cfm
+ *
+ * Description      Action routine for processing the abort confirmation
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_abort_cfm(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+                              tBTA_HL_DATA* p_data) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  tBTA_HL evt_data;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_mca_abort_cfm");
+#endif
+
+  if (p_dcb->abort_oper) {
+    if (p_data->mca_evt.mca_data.abort_cfm.rsp_code != MCA_RSP_SUCCESS) {
+      if (p_dcb->abort_oper & BTA_HL_ABORT_LOCAL_MASK) {
+        bta_hl_build_abort_cfm(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
+                               BTA_HL_STATUS_FAIL);
+        p_acb->p_cback(BTA_HL_DCH_ABORT_CFM_EVT, (tBTA_HL*)&evt_data);
+      }
+    } else {
+      bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+                            BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+    }
+  } else {
+    APPL_TRACE_ERROR("Not expecting Abort CFM ");
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_mca_abort
+ *
+ * Description      Action routine for processing the abort request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_abort(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+                          tBTA_HL_DATA* p_data) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  tMCA_RESULT mca_result;
+  tBTA_HL evt_data;
+
+  if (((p_mcb->sdp_oper == BTA_HL_SDP_OP_DCH_OPEN_INIT) ||
+       (p_mcb->sdp_oper == BTA_HL_SDP_OP_DCH_RECONNECT_INIT)) &&
+      (p_mcb->sdp_mdl_idx == mdl_idx)) {
+    p_dcb->abort_oper |= BTA_HL_ABORT_PENDING_MASK;
+    return;
+  } else if (p_dcb->echo_oper == BTA_HL_ECHO_OP_CI_GET_ECHO_DATA) {
+    p_dcb->abort_oper |= BTA_HL_ABORT_PENDING_MASK;
+    return;
+  }
+
+  p_dcb->abort_oper &= ~BTA_HL_ABORT_PENDING_MASK;
+
+  if ((mca_result = MCA_Abort((tMCA_CL)p_mcb->mcl_handle)) != MCA_SUCCESS) {
+    if (mca_result == MCA_NO_RESOURCES) {
+      p_dcb->abort_oper |= BTA_HL_ABORT_PENDING_MASK;
+    } else {
+      if (p_dcb->abort_oper & BTA_HL_ABORT_LOCAL_MASK) {
+        bta_hl_build_abort_cfm(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
+                               BTA_HL_STATUS_FAIL);
+        p_acb->p_cback(BTA_HL_DCH_ABORT_CFM_EVT, (tBTA_HL*)&evt_data);
+      }
+      bta_hl_check_cch_close(app_idx, mcl_idx, p_data, false);
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_mca_abort abort_oper=0x%x", p_dcb->abort_oper);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_mca_reconnect_ind
+ *
+ * Description      Action routine for processing the reconnect indication
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_reconnect_ind(uint8_t app_idx, uint8_t mcl_idx,
+                                  uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  tBTA_HL_MDL_CFG* p_mdl_cfg;
+  tMCA_EVT_HDR* p_reconnect_ind = &p_data->mca_evt.mca_data.reconnect_ind;
+  uint8_t mdl_cfg_idx, in_use_mdl_idx, mdep_cfg_idx;
+  uint8_t rsp_code = MCA_RSP_SUCCESS;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_mca_reconnect_ind mdl_id=%d",
+                   p_reconnect_ind->mdl_id);
+#endif
+
+  if (bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, p_reconnect_ind->mdl_id,
+                              &mdl_cfg_idx)) {
+    if (!bta_hl_find_mdl_idx(app_idx, mcl_idx, p_reconnect_ind->mdl_id,
+                             &in_use_mdl_idx)) {
+      p_mdl_cfg = BTA_HL_GET_MDL_CFG_PTR(app_idx, mdl_cfg_idx);
+
+      if (bta_hl_find_mdep_cfg_idx(app_idx, p_mdl_cfg->local_mdep_id,
+                                   &mdep_cfg_idx)) {
+        p_dcb->in_use = true;
+        p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_RECONNECT;
+        p_dcb->sec_mask = (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+        p_dcb->peer_mdep_id = 0xFF;
+        p_dcb->local_mdep_id = p_mdl_cfg->local_mdep_id;
+        p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+        p_dcb->local_cfg = BTA_HL_DCH_CFG_UNKNOWN;
+        p_dcb->mdl_id = p_reconnect_ind->mdl_id;
+        p_dcb->mdl_cfg_idx_included = true;
+        p_dcb->mdl_cfg_idx = mdl_cfg_idx;
+        p_dcb->dch_mode = p_mdl_cfg->dch_mode;
+        bta_hl_find_rxtx_apdu_size(app_idx, mdep_cfg_idx,
+                                   &p_dcb->max_rx_apdu_size,
+                                   &p_dcb->max_tx_apdu_size);
+        bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data);
+      } else {
+        rsp_code = MCA_RSP_BAD_MDL;
+      }
+    } else {
+      rsp_code = MCA_RSP_BAD_MDL;
+    }
+  } else {
+    rsp_code = MCA_RSP_BAD_MDL;
+  }
+
+  if (MCA_ReconnectMdlRsp((tMCA_CL)p_mcb->mcl_handle, p_dcb->local_mdep_id,
+                          p_dcb->mdl_id, rsp_code,
+                          &p_dcb->chnl_cfg) != MCA_SUCCESS) {
+    MCA_Abort((tMCA_CL)p_mcb->mcl_handle);
+    bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
+                          p_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_mca_reconnect_cfm
+ *
+ * Description      Action routine for processing the reconenct confirmation
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_reconnect_cfm(uint8_t app_idx, uint8_t mcl_idx,
+                                  uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  tMCA_RSP_EVT* p_reconnect_cfm = &p_data->mca_evt.mca_data.reconnect_cfm;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_mca_reconnect_cfm");
+#endif
+  if (p_dcb->abort_oper & BTA_HL_ABORT_PENDING_MASK) {
+    p_dcb->abort_oper &= ~BTA_HL_ABORT_PENDING_MASK;
+    bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ABORT_EVT,
+                          p_data);
+    return;
+  }
+
+  if (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_RECONNECT) {
+    if (p_reconnect_cfm->rsp_code == MCA_RSP_SUCCESS) {
+      bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data);
+
+      if (MCA_DataChnlCfg((tMCA_CL)p_mcb->mcl_handle, &p_dcb->chnl_cfg) !=
+          MCA_SUCCESS) {
+        /* should be able to abort so no checking of the return code */
+        MCA_Abort((tMCA_CL)p_mcb->mcl_handle);
+        bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+                              BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+      }
+    } else {
+      bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+                            BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_mca_reconnect
+ *
+ * Description      Action routine for processing the reconnect request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_reconnect(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+                              tBTA_HL_DATA* p_data) {
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  tMCA_CHNL_CFG* p_chnl_cfg = NULL;
+  uint8_t sdp_idx;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_mca_reconnect");
+#endif
+  if (bta_hl_find_sdp_idx_using_ctrl_psm(&p_mcb->sdp, p_mcb->ctrl_psm,
+                                         &sdp_idx)) {
+    p_mcb->data_psm = p_mcb->sdp.sdp_rec[sdp_idx].data_psm;
+    if (MCA_ReconnectMdl((tMCA_CL)p_mcb->mcl_handle, p_dcb->local_mdep_id,
+                         p_mcb->data_psm, p_dcb->mdl_id,
+                         p_chnl_cfg) != MCA_SUCCESS) {
+      bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+                            BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+    }
+  } else {
+    bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
+                          p_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_create_rsp
+ *
+ * Description      Action routine for processing BTA_HL_API_DCH_CREATE_RSP_EVT
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_create_rsp(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+                           tBTA_HL_DATA* p_data) {
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  tBTA_HL_API_DCH_CREATE_RSP* p_create_rsp = &p_data->api_dch_create_rsp;
+  uint8_t mca_rsp_code = MCA_RSP_SUCCESS;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_create_rsp");
+#endif
+  if (p_create_rsp->rsp_code == BTA_HL_DCH_CREATE_RSP_SUCCESS) {
+    p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_OPEN;
+    p_dcb->local_cfg = p_create_rsp->cfg_rsp;
+
+    bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data);
+  } else {
+    mca_rsp_code = MCA_RSP_CFG_REJ;
+  }
+
+  if (MCA_CreateMdlRsp((tMCA_CL)p_mcb->mcl_handle, p_dcb->local_mdep_id,
+                       p_dcb->mdl_id, p_dcb->local_cfg, mca_rsp_code,
+                       &p_dcb->chnl_cfg) != MCA_SUCCESS) {
+    bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
+                          p_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_mca_create_ind
+ *
+ * Description      Action routine for processing
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_create_ind(uint8_t app_idx, uint8_t mcl_idx,
+                               uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  tMCA_CREATE_IND* p_create_ind = &p_data->mca_evt.mca_data.create_ind;
+  uint8_t mdep_cfg_idx;
+  uint8_t cfg_rsp;
+  uint8_t rsp_code = MCA_RSP_SUCCESS;
+  bool send_create_ind_evt = false;
+  tBTA_HL evt_data;
+  tBTA_HL_ECHO_CFG* p_echo_cfg;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_mca_create_ind");
+#endif
+
+  if (bta_hl_find_mdep_cfg_idx(app_idx, p_create_ind->dep_id, &mdep_cfg_idx)) {
+    if (p_create_ind->dep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
+      if (bta_hl_find_echo_cfg_rsp(app_idx, mcl_idx, mdep_cfg_idx,
+                                   p_create_ind->cfg, &cfg_rsp)) {
+        p_dcb->in_use = true;
+        p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_OPEN;
+        p_dcb->local_mdep_id = p_create_ind->dep_id;
+        p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+        p_dcb->local_cfg = cfg_rsp;
+        p_dcb->remote_cfg = p_create_ind->cfg;
+        p_dcb->mdl_id = p_create_ind->mdl_id;
+        p_dcb->mdl_cfg_idx_included = false;
+        p_echo_cfg = BTA_HL_GET_ECHO_CFG_PTR(app_idx);
+        p_dcb->max_rx_apdu_size = p_echo_cfg->max_rx_apdu_size;
+        p_dcb->max_tx_apdu_size = p_echo_cfg->max_tx_apdu_size;
+
+        bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data);
+      } else {
+        rsp_code = MCA_RSP_CFG_REJ;
+      }
+    } else
+
+    {
+      p_dcb->in_use = true;
+      p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_CREATE;
+      p_dcb->local_mdep_id = p_create_ind->dep_id;
+      p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+      p_dcb->local_cfg = BTA_HL_DCH_CFG_UNKNOWN;
+      p_dcb->remote_cfg = p_create_ind->cfg;
+      p_dcb->mdl_id = p_create_ind->mdl_id;
+      p_dcb->mdl_cfg_idx_included = false;
+      bta_hl_find_rxtx_apdu_size(app_idx, mdep_cfg_idx,
+                                 &p_dcb->max_rx_apdu_size,
+                                 &p_dcb->max_tx_apdu_size);
+      send_create_ind_evt = true;
+    }
+  } else {
+    rsp_code = MCA_RSP_BAD_MDEP;
+  }
+
+  if (send_create_ind_evt) {
+    evt_data.dch_create_ind.mcl_handle = p_mcb->mcl_handle;
+    evt_data.dch_create_ind.app_handle = p_acb->app_handle;
+    evt_data.dch_create_ind.local_mdep_id = p_dcb->local_mdep_id;
+    evt_data.dch_create_ind.mdl_id = p_dcb->mdl_id;
+    evt_data.dch_create_ind.cfg = p_dcb->remote_cfg;
+    bdcpy(evt_data.dch_create_ind.bd_addr, p_mcb->bd_addr);
+    p_acb->p_cback(BTA_HL_DCH_CREATE_IND_EVT, (tBTA_HL*)&evt_data);
+  } else {
+    if (MCA_CreateMdlRsp((tMCA_CL)p_mcb->mcl_handle, p_dcb->local_mdep_id,
+                         p_dcb->mdl_id, p_dcb->local_cfg, rsp_code,
+                         &p_dcb->chnl_cfg) != MCA_SUCCESS) {
+      bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+                            BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+    } else {
+      if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
+        p_mcb->echo_test = true;
+        p_dcb->echo_oper = BTA_HL_ECHO_OP_OPEN_IND;
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_mca_create_cfm
+ *
+ * Description      Action routine for processing
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_create_cfm(uint8_t app_idx, uint8_t mcl_idx,
+                               uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  tMCA_CREATE_CFM* p_create_cfm = &p_data->mca_evt.mca_data.create_cfm;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_mca_create_cfm");
+#endif
+
+  if (p_dcb->abort_oper & BTA_HL_ABORT_PENDING_MASK) {
+    p_dcb->abort_oper &= ~BTA_HL_ABORT_PENDING_MASK;
+    bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ABORT_EVT,
+                          p_data);
+    return;
+  }
+
+  if (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_OPEN) {
+    if (p_create_cfm->rsp_code == MCA_RSP_SUCCESS) {
+      if (bta_hl_validate_cfg(app_idx, mcl_idx, mdl_idx, p_create_cfm->cfg)) {
+        bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data);
+
+        if (MCA_DataChnlCfg((tMCA_CL)p_mcb->mcl_handle, &p_dcb->chnl_cfg) !=
+            MCA_SUCCESS) {
+          /* this should not happen */
+          APPL_TRACE_ERROR("Unable to create data channel");
+          MCA_Abort((tMCA_CL)p_mcb->mcl_handle);
+          bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+                                BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+        } else {
+          if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
+            p_dcb->echo_oper = BTA_HL_ECHO_OP_DCH_OPEN_CFM;
+          }
+        }
+      } else {
+        MCA_Abort((tMCA_CL)p_mcb->mcl_handle);
+        bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+                              BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+      }
+    } else {
+      APPL_TRACE_ERROR("MCA Create- failed");
+      bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+                            BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_mca_create
+ *
+ * Description      Action routine for processing the MDL create request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_create(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+                           tBTA_HL_DATA* p_data) {
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  tMCA_RESULT result;
+  uint8_t sdp_idx;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_mca_create");
+#endif
+
+  if (bta_hl_find_sdp_idx_using_ctrl_psm(&p_mcb->sdp, p_mcb->ctrl_psm,
+                                         &sdp_idx) &&
+      bta_hl_validate_peer_cfg(app_idx, mcl_idx, mdl_idx, p_dcb->peer_mdep_id,
+                               p_dcb->peer_mdep_role, sdp_idx)) {
+    p_mcb->data_psm = p_mcb->sdp.sdp_rec[sdp_idx].data_psm;
+    if ((result =
+             MCA_CreateMdl((tMCA_CL)p_mcb->mcl_handle, p_dcb->local_mdep_id,
+                           p_mcb->data_psm, p_dcb->mdl_id, p_dcb->peer_mdep_id,
+                           p_dcb->local_cfg, NULL)) != MCA_SUCCESS) {
+      APPL_TRACE_ERROR("MCA_CreateMdl FAIL mca_result=%d", result);
+      bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+                            BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+    }
+  } else {
+    APPL_TRACE_ERROR("MCA Create- SDP idx or peer MDEP cfg not found");
+    bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
+                          p_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_sdp_fail
+ *
+ * Description      Action routine for processing the SDP failed event
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_sdp_fail(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+                         tBTA_HL_DATA* p_data) {
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_dch_sdp_fail");
+#endif
+  bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
+                        p_data);
+}
+
+/******************************************************************************
+ *
+ * Function         bta_hl_sdp_cback
+ *
+ * Description      This is the SDP callback function used by HL.
+ *                  This function will be executed by SDP when the service
+ *                  search is completed.  If the search is successful, it
+ *                  finds the first record in the database that matches the
+ *                  UUID of the search.  Then retrieves the scn from the
+ *                  record.
+ *
+ * Returns          void.
+ *
+ *****************************************************************************/
+static void bta_hl_sdp_cback(uint8_t sdp_oper, uint8_t app_idx, uint8_t mcl_idx,
+                             uint8_t mdl_idx, uint16_t status) {
+  tBTA_HL_MCL_CB* p_cb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_SDP_REC* p_hdp_rec;
+  tBTA_HL_CCH_SDP* p_cch_buf;
+  tBTA_HL_DCH_SDP* p_dch_buf;
+  tSDP_DISC_REC* p_rec = NULL;
+  tSDP_PROTOCOL_ELEM pe;
+  tSDP_DISC_ATTR* p_attr;
+  uint8_t i, rec_cnt;
+  tBTA_HL_SUP_FEATURE_LIST_ELEM sup_feature;
+  bool sdp_parsing_ok = false, result = false;
+  uint16_t event;
+  tBTA_HL_MDL_CB* p_dcb;
+  uint16_t service_uuid;
+  uint16_t name_len;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG(
+      "bta_hl_sdp_cback status:%d sdp_oper=%d app_idx=%d, mcl_idx=%d,   "
+      "mdl_idx=%d",
+      status, sdp_oper, app_idx, mcl_idx, mdl_idx);
+#endif
+
+  rec_cnt = 0;
+  service_uuid = bta_hl_get_service_uuids(sdp_oper, app_idx, mcl_idx, mdl_idx);
+
+  if (status == SDP_SUCCESS || status == SDP_DB_FULL) {
+    memset(&p_cb->sdp, 0, sizeof(tBTA_HL_SDP));
+    do {
+      if (bta_hl_find_service_in_db(app_idx, mcl_idx, service_uuid, &p_rec)) {
+        p_hdp_rec = &p_cb->sdp.sdp_rec[rec_cnt];
+        p_cb->sdp.num_recs = rec_cnt + 1;
+      } else {
+        break;
+      }
+
+      if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_L2CAP, &pe)) {
+        p_hdp_rec->ctrl_psm = (uint16_t)pe.params[0];
+      } else {
+        APPL_TRACE_WARNING("Control PSM not found");
+        break;
+      }
+      if (SDP_FindAddProtoListsElemInRec(p_rec, UUID_PROTOCOL_L2CAP, &pe)) {
+        p_hdp_rec->data_psm = (uint16_t)pe.params[0];
+      } else {
+        APPL_TRACE_WARNING("Data PSM not found");
+        break;
+      }
+
+      p_hdp_rec->srv_name[0] = '\0';
+      if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) !=
+          NULL) {
+        if (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) < BT_MAX_SERVICE_NAME_LEN)
+          name_len = (uint16_t)SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+        else
+          name_len = BT_MAX_SERVICE_NAME_LEN;
+        memcpy(p_hdp_rec->srv_name, p_attr->attr_value.v.array, name_len);
+      }
+
+      p_hdp_rec->srv_desp[0] = '\0';
+      if ((p_attr = SDP_FindAttributeInRec(
+               p_rec, ATTR_ID_SERVICE_DESCRIPTION)) != NULL) {
+        if (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) < BT_MAX_SERVICE_NAME_LEN)
+          name_len = (uint16_t)SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+        else
+          name_len = BT_MAX_SERVICE_NAME_LEN;
+        memcpy(p_hdp_rec->srv_desp, p_attr->attr_value.v.array, name_len);
+      }
+
+      p_hdp_rec->provider_name[0] = '\0';
+      if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_PROVIDER_NAME)) !=
+          NULL) {
+        if (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) < BT_MAX_SERVICE_NAME_LEN)
+          name_len = (uint16_t)SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+        else
+          name_len = BT_MAX_SERVICE_NAME_LEN;
+        memcpy(p_hdp_rec->provider_name, p_attr->attr_value.v.array, name_len);
+      }
+
+      if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HDP_MCAP_SUP_PROC)) !=
+          NULL) {
+        p_hdp_rec->mcap_sup_proc = p_attr->attr_value.v.u8;
+      } else {
+        APPL_TRACE_WARNING("MCAP SUP PROC not found");
+        break;
+      }
+
+      if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HDP_SUP_FEAT_LIST)) !=
+          NULL) {
+        if (bta_hl_fill_sup_feature_list(p_attr, &sup_feature)) {
+          p_hdp_rec->num_mdeps = (uint8_t)sup_feature.num_elems;
+          APPL_TRACE_WARNING("bta_hl_sdp_cback num_mdeps %d",
+                             sup_feature.num_elems);
+          for (i = 0; i < sup_feature.num_elems; i++) {
+            p_hdp_rec->mdep_cfg[i].data_type =
+                sup_feature.list_elem[i].data_type;
+            p_hdp_rec->mdep_cfg[i].mdep_id = sup_feature.list_elem[i].mdep_id;
+            p_hdp_rec->mdep_cfg[i].mdep_role =
+                sup_feature.list_elem[i].mdep_role;
+            /* Check MDEP Description pointer to prevent crash due to null
+             * pointer */
+            if (sup_feature.list_elem[i].p_mdep_desp != NULL) {
+              strlcpy(p_hdp_rec->mdep_cfg[i].mdep_desp,
+                      sup_feature.list_elem[i].p_mdep_desp,
+                      BTA_HL_MDEP_DESP_LEN);
+            } else {
+              APPL_TRACE_ERROR(
+                  "bta_hl_sdp_cback Incorrect Mdep[%d] Description (Null ptr)",
+                  i);
+            }
+          }
+
+          sdp_parsing_ok = true;
+        } else {
+          APPL_TRACE_WARNING("HDP supported feature list fill failed");
+          break;
+        }
+      } else {
+        APPL_TRACE_WARNING("HDP supported feature list not found");
+        break;
+      }
+#if (BTA_HL_DEBUG == TRUE)
+      APPL_TRACE_DEBUG("record=%d ctrl_psm=%0x data_psm=%x", rec_cnt + 1,
+                       p_hdp_rec->ctrl_psm, p_hdp_rec->data_psm);
+      APPL_TRACE_DEBUG("srv_name=[%s]", (p_hdp_rec->srv_name[0] != '\0')
+                                            ? p_hdp_rec->srv_name
+                                            : "NULL");
+      APPL_TRACE_DEBUG("srv_desp=[%s]", (p_hdp_rec->srv_desp[0] != '\0')
+                                            ? p_hdp_rec->srv_desp
+                                            : "NULL");
+      for (i = 0; i < sup_feature.num_elems; i++) {
+        APPL_TRACE_DEBUG(
+            "index=0x%02x mdep_id=0x%04x data type=0x%04x mdep role=%s(0x%02x)",
+            (i + 1), p_hdp_rec->mdep_cfg[i].mdep_id,
+            p_hdp_rec->mdep_cfg[i].data_type,
+            (p_hdp_rec->mdep_cfg[i].mdep_role == BTA_HL_MDEP_ROLE_SOURCE)
+                ? "Src"
+                : "Snk",
+            p_hdp_rec->mdep_cfg[i].mdep_role);
+      }
+      APPL_TRACE_DEBUG("provider_name=[%s]",
+                       (p_hdp_rec->provider_name[0] != '\0')
+                           ? p_hdp_rec->provider_name
+                           : "NULL");
+      APPL_TRACE_DEBUG("found MCAP sup procedure=%d",
+                       p_cb->sdp.sdp_rec[rec_cnt].mcap_sup_proc);
+#endif
+      rec_cnt++;
+      if (rec_cnt >= BTA_HL_NUM_SDP_RECS) {
+        APPL_TRACE_WARNING("No more spaces for SDP recs max_rec_cnt=%d",
+                           BTA_HL_NUM_SDP_RECS);
+        break;
+      }
+
+    } while (true);
+  }
+
+  osi_free_and_reset((void**)&p_cb->p_db);
+
+  if ((status == SDP_SUCCESS || status == SDP_DB_FULL) && p_cb->sdp.num_recs &&
+      sdp_parsing_ok) {
+    result = true;
+  } else {
+    APPL_TRACE_WARNING(
+        "SDP Failed sdp_status=%d num_recs=%d sdp_parsing_ok=%d ", status,
+        p_cb->sdp.num_recs, sdp_parsing_ok);
+  }
+
+  p_cb->sdp_oper = BTA_HL_SDP_OP_NONE;
+
+  switch (sdp_oper) {
+    case BTA_HL_SDP_OP_CCH_INIT:
+    case BTA_HL_SDP_OP_SDP_QUERY_NEW:
+    case BTA_HL_SDP_OP_SDP_QUERY_CURRENT:
+
+      /* send result in event back to BTA */
+      p_cch_buf = (tBTA_HL_CCH_SDP*)osi_malloc(sizeof(tBTA_HL_CCH_SDP));
+      if (result) {
+        if (sdp_oper == BTA_HL_SDP_OP_CCH_INIT) {
+          event = BTA_HL_CCH_SDP_OK_EVT;
+          if (p_cb->close_pending) event = BTA_HL_CCH_SDP_FAIL_EVT;
+        } else {
+          event = BTA_HL_SDP_QUERY_OK_EVT;
+        }
+      } else {
+        if (sdp_oper == BTA_HL_SDP_OP_CCH_INIT)
+          event = BTA_HL_CCH_SDP_FAIL_EVT;
+        else
+          event = BTA_HL_SDP_QUERY_FAIL_EVT;
+      }
+      p_cch_buf->hdr.event = event;
+
+      p_cch_buf->app_idx = app_idx;
+      p_cch_buf->mcl_idx = mcl_idx;
+      p_cch_buf->release_mcl_cb = false;
+      if (sdp_oper == BTA_HL_SDP_OP_SDP_QUERY_NEW)
+        p_cch_buf->release_mcl_cb = true;
+
+      bta_sys_sendmsg(p_cch_buf);
+      break;
+    case BTA_HL_SDP_OP_DCH_OPEN_INIT:
+    case BTA_HL_SDP_OP_DCH_RECONNECT_INIT:
+      p_dch_buf = (tBTA_HL_DCH_SDP*)osi_malloc(sizeof(tBTA_HL_DCH_SDP));
+      p_dch_buf->hdr.event = BTA_HL_DCH_SDP_FAIL_EVT;
+      p_dch_buf->app_idx = app_idx;
+      p_dch_buf->mcl_idx = mcl_idx;
+      p_dch_buf->mdl_idx = mdl_idx;
+      p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+      if (p_dcb->abort_oper & BTA_HL_ABORT_PENDING_MASK) {
+        p_dcb->abort_oper &= ~BTA_HL_ABORT_PENDING_MASK;
+        result = false;
+      }
+      if (result) {
+        if (sdp_oper == BTA_HL_SDP_OP_DCH_OPEN_INIT) {
+          if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
+            p_dch_buf->hdr.event = BTA_HL_DCH_ECHO_TEST_EVT;
+          } else {
+            p_dch_buf->hdr.event = BTA_HL_DCH_OPEN_EVT;
+          }
+        } else {
+          p_dch_buf->hdr.event = BTA_HL_DCH_RECONNECT_EVT;
+        }
+      }
+      bta_sys_sendmsg(p_dch_buf);
+      break;
+    default:
+      break;
+  }
+}
+
+/******************************************************************************
+ *
+ * Function         bta_hl_sdp_cback0
+ *
+ * Description      This is the SDP callback function used by index = 0
+ *
+ * Returns          void.
+ *
+ *****************************************************************************/
+static void bta_hl_sdp_cback0(uint16_t status) {
+  bta_hl_sdp_cback(bta_hl_cb.scb[0].sdp_oper, bta_hl_cb.scb[0].app_idx,
+                   bta_hl_cb.scb[0].mcl_idx, bta_hl_cb.scb[0].mdl_idx, status);
+  bta_hl_deallocate_spd_cback(0);
+}
+
+/******************************************************************************
+ *
+ * Function         bta_hl_sdp_cback1
+ *
+ * Description      This is the SDP callback function used by index = 1
+ *
+ * Parameters       status  - status of the SDP callabck
+ *
+ * Returns          void.
+ *
+ *****************************************************************************/
+static void bta_hl_sdp_cback1(uint16_t status) {
+  bta_hl_sdp_cback(bta_hl_cb.scb[1].sdp_oper, bta_hl_cb.scb[1].app_idx,
+                   bta_hl_cb.scb[1].mcl_idx, bta_hl_cb.scb[1].mdl_idx, status);
+  bta_hl_deallocate_spd_cback(1);
+}
+
+/******************************************************************************
+ *
+ * Function         bta_hl_sdp_cback2
+ *
+ * Description      This is the SDP callback function used by index = 2
+ *
+ * Returns          void.
+ *
+ *****************************************************************************/
+static void bta_hl_sdp_cback2(uint16_t status) {
+  bta_hl_sdp_cback(bta_hl_cb.scb[2].sdp_oper, bta_hl_cb.scb[2].app_idx,
+                   bta_hl_cb.scb[2].mcl_idx, bta_hl_cb.scb[2].mdl_idx, status);
+  bta_hl_deallocate_spd_cback(2);
+}
+
+/******************************************************************************
+ *
+ * Function         bta_hl_sdp_cback3
+ *
+ * Description      This is the SDP callback function used by index = 3
+ *
+ * Returns          void.
+ *
+ *****************************************************************************/
+static void bta_hl_sdp_cback3(uint16_t status) {
+  bta_hl_sdp_cback(bta_hl_cb.scb[3].sdp_oper, bta_hl_cb.scb[3].app_idx,
+                   bta_hl_cb.scb[3].mcl_idx, bta_hl_cb.scb[3].mdl_idx, status);
+  bta_hl_deallocate_spd_cback(3);
+}
+
+/******************************************************************************
+ *
+ * Function         bta_hl_sdp_cback4
+ *
+ * Description      This is the SDP callback function used by index = 4
+ *
+ * Parameters       status  - status of the SDP callabck
+ *
+ * Returns          void.
+ *
+ *****************************************************************************/
+static void bta_hl_sdp_cback4(uint16_t status) {
+  bta_hl_sdp_cback(bta_hl_cb.scb[4].sdp_oper, bta_hl_cb.scb[4].app_idx,
+                   bta_hl_cb.scb[4].mcl_idx, bta_hl_cb.scb[4].mdl_idx, status);
+  bta_hl_deallocate_spd_cback(4);
+}
+
+/******************************************************************************
+ *
+ * Function         bta_hl_sdp_cback5
+ *
+ * Description      This is the SDP callback function used by index = 5
+ *
+ * Parameters       status  - status of the SDP callabck
+ *
+ * Returns          void.
+ *
+ *****************************************************************************/
+static void bta_hl_sdp_cback5(uint16_t status) {
+  bta_hl_sdp_cback(bta_hl_cb.scb[5].sdp_oper, bta_hl_cb.scb[5].app_idx,
+                   bta_hl_cb.scb[5].mcl_idx, bta_hl_cb.scb[5].mdl_idx, status);
+  bta_hl_deallocate_spd_cback(5);
+}
+
+/******************************************************************************
+ *
+ * Function         bta_hl_sdp_cback6
+ *
+ * Description      This is the SDP callback function used by index = 6
+ *
+ * Returns          void.
+ *
+ *****************************************************************************/
+static void bta_hl_sdp_cback6(uint16_t status) {
+  bta_hl_sdp_cback(bta_hl_cb.scb[6].sdp_oper, bta_hl_cb.scb[6].app_idx,
+                   bta_hl_cb.scb[6].mcl_idx, bta_hl_cb.scb[6].mdl_idx, status);
+  bta_hl_deallocate_spd_cback(6);
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_deallocate_spd_cback
+ *
+ * Description   Deallocate a SDP control block
+ *
+ * Returns      bool - true found
+ *                        false not found
+ *
+ ******************************************************************************/
+void bta_hl_deallocate_spd_cback(uint8_t sdp_cback_idx) {
+  tBTA_HL_SDP_CB* p_spd_cb = &bta_hl_cb.scb[sdp_cback_idx];
+
+  memset(p_spd_cb, 0, sizeof(tBTA_HL_SDP_CB));
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_deallocate_spd_cback index=%d", sdp_cback_idx);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_allocate_spd_cback
+ *
+ * Description   Finds a not in used SDP control block index
+ *
+ *
+ * Returns      bool - true found
+ *                        false not found
+ *
+ ******************************************************************************/
+tSDP_DISC_CMPL_CB* bta_hl_allocate_spd_cback(tBTA_HL_SDP_OPER sdp_oper,
+                                             uint8_t app_idx, uint8_t mcl_idx,
+                                             uint8_t mdl_idx,
+                                             uint8_t* p_sdp_cback_idx) {
+  uint8_t i;
+  tSDP_DISC_CMPL_CB* p_cbcak = NULL;
+
+  for (i = 0; i < BTA_HL_NUM_SDP_CBACKS; i++) {
+    if (!bta_hl_cb.scb[i].in_use) {
+      p_cbcak = bta_hl_sdp_cback_arr[i];
+      bta_hl_cb.scb[i].in_use = true;
+      bta_hl_cb.scb[i].sdp_oper = sdp_oper;
+      bta_hl_cb.scb[i].app_idx = app_idx;
+      bta_hl_cb.scb[i].mcl_idx = mcl_idx;
+      bta_hl_cb.scb[i].mdl_idx = mdl_idx;
+      *p_sdp_cback_idx = i;
+      break;
+    }
+  }
+
+  if (i == BTA_HL_NUM_SDP_CBACKS) {
+    APPL_TRACE_WARNING("No scb is available to allocate")
+  } else {
+#if (BTA_HL_DEBUG == TRUE)
+    APPL_TRACE_DEBUG("bta_hl_allocate_spd_cback cback_idx=%d ", i);
+    APPL_TRACE_DEBUG("sdp_oper=%d, app_idx=%d, mcl_idx=%d,  mdl_idx=%d",
+                     bta_hl_cb.scb[i].sdp_oper, bta_hl_cb.scb[i].app_idx,
+                     bta_hl_cb.scb[i].mcl_idx, bta_hl_cb.scb[i].mdl_idx);
+#endif
+  }
+  return p_cbcak;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_init_sdp
+ *
+ * Description      Action routine for processing the SDP initiattion request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+tBTA_HL_STATUS bta_hl_init_sdp(tBTA_HL_SDP_OPER sdp_oper, uint8_t app_idx,
+                               uint8_t mcl_idx, uint8_t mdl_idx) {
+  tBTA_HL_MCL_CB* p_cb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tSDP_UUID uuid_list;
+  uint16_t attr_list[BTA_HL_NUM_SRCH_ATTR];
+  uint16_t num_attrs = BTA_HL_NUM_SRCH_ATTR;
+  tBTA_HL_STATUS status;
+  uint8_t sdp_cback_idx;
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG(
+      "bta_hl_init_sdp sdp_oper=%d app_idx=%d mcl_idx=%d, mdl_idx=%d", sdp_oper,
+      app_idx, mcl_idx, mdl_idx);
+#endif
+  if ((p_cb->sdp_cback = bta_hl_allocate_spd_cback(
+           sdp_oper, app_idx, mcl_idx, mdl_idx, &sdp_cback_idx)) != NULL) {
+    if (p_cb->p_db == NULL)
+      (p_cb->p_db = (tSDP_DISCOVERY_DB*)osi_malloc(BTA_HL_DISC_SIZE));
+    attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+    attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+    attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
+    attr_list[3] = ATTR_ID_ADDITION_PROTO_DESC_LISTS;
+    attr_list[4] = ATTR_ID_SERVICE_NAME;
+    attr_list[5] = ATTR_ID_SERVICE_DESCRIPTION;
+    attr_list[6] = ATTR_ID_PROVIDER_NAME;
+    attr_list[7] = ATTR_ID_HDP_SUP_FEAT_LIST;
+    attr_list[8] = ATTR_ID_HDP_DATA_EXCH_SPEC;
+    attr_list[9] = ATTR_ID_HDP_MCAP_SUP_PROC;
+
+    uuid_list.len = LEN_UUID_16;
+    uuid_list.uu.uuid16 = UUID_SERVCLASS_HDP_PROFILE;
+    SDP_InitDiscoveryDb(p_cb->p_db, BTA_HL_DISC_SIZE, 1, &uuid_list, num_attrs,
+                        attr_list);
+
+    if (!SDP_ServiceSearchAttributeRequest(p_cb->bd_addr, p_cb->p_db,
+                                           p_cb->sdp_cback)) {
+      status = BTA_HL_STATUS_FAIL;
+    } else {
+      status = BTA_HL_STATUS_OK;
+    }
+  } else {
+    status = BTA_HL_STATUS_SDP_NO_RESOURCE;
+  }
+
+  if (status != BTA_HL_STATUS_OK) {
+    osi_free_and_reset((void**)&p_cb->p_db);
+    if (status != BTA_HL_STATUS_SDP_NO_RESOURCE)
+      bta_hl_deallocate_spd_cback(sdp_cback_idx);
+  }
+
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_cch_sdp_init
+ *
+ * Description      Action routine for processing the CCH SDP init event
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_cch_sdp_init(uint8_t app_idx, uint8_t mcl_idx,
+                         tBTA_HL_DATA* p_data) {
+  tBTA_HL_MCL_CB* p_cb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_cch_init_sdp");
+#endif
+  if (p_cb->sdp_oper == BTA_HL_SDP_OP_NONE) {
+    p_cb->app_id = p_data->api_cch_open.app_id;
+    p_cb->sdp_oper = BTA_HL_SDP_OP_CCH_INIT;
+
+    if (bta_hl_init_sdp(p_cb->sdp_oper, app_idx, mcl_idx, 0xFF) !=
+        BTA_HL_STATUS_OK) {
+      p_cb->sdp_oper = BTA_HL_SDP_OP_NONE;
+      bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_SDP_FAIL_EVT, p_data);
+    }
+  } else {
+    APPL_TRACE_ERROR("SDP in use");
+    bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_SDP_FAIL_EVT, p_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_cch_mca_open
+ *
+ * Description      Action routine for processing the CCH open request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_cch_mca_open(uint8_t app_idx, uint8_t mcl_idx,
+                         tBTA_HL_DATA* p_data) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  uint8_t sdp_idx;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_cch_mca_open");
+#endif
+
+  if (bta_hl_find_sdp_idx_using_ctrl_psm(&p_mcb->sdp, p_mcb->req_ctrl_psm,
+                                         &sdp_idx)) {
+    p_mcb->ctrl_psm = p_mcb->sdp.sdp_rec[sdp_idx].ctrl_psm;
+    p_mcb->data_psm = p_mcb->sdp.sdp_rec[sdp_idx].data_psm;
+    if (MCA_ConnectReq((tMCA_HANDLE)p_acb->app_handle, p_mcb->bd_addr,
+                       p_mcb->ctrl_psm, p_mcb->sec_mask) != MCA_SUCCESS) {
+      bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT,
+                            p_data);
+    }
+  } else {
+    bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT, p_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_cch_mca_close
+ *
+ * Description      Action routine for processing the CCH close request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_cch_mca_close(uint8_t app_idx, uint8_t mcl_idx,
+                          tBTA_HL_DATA* p_data) {
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_cch_mca_close mcl_handle=%d", p_mcb->mcl_handle);
+#endif
+  if (p_mcb->sdp_oper != BTA_HL_SDP_OP_CCH_INIT) {
+    if (p_mcb->mcl_handle) {
+      if (MCA_DisconnectReq((tMCA_HANDLE)p_mcb->mcl_handle) != MCA_SUCCESS) {
+        bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT,
+                              p_data);
+      }
+    } else {
+      p_mcb->close_pending = true;
+      APPL_TRACE_DEBUG(
+          "No valid mcl_handle to stop the CCH setup now so wait until CCH is "
+          "up then close it");
+    }
+  } else {
+    p_mcb->close_pending = true;
+    APPL_TRACE_DEBUG(
+        "can not stop the CCH setup becasue SDP is in progress so wait until "
+        "it is done");
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_cch_close_cmpl
+ *
+ * Description      Action routine for processing the CCH close complete event
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_cch_close_cmpl(uint8_t app_idx, uint8_t mcl_idx,
+                           tBTA_HL_DATA* p_data) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+  tBTA_HL evt_data;
+  tBTA_HL_EVT event;
+  bool send_evt = true;
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_cch_close_cmpl");
+#endif
+  bta_sys_conn_close(BTA_ID_HL, p_acb->app_id, p_mcb->bd_addr);
+
+  if (p_mcb->cch_oper == BTA_HL_CCH_OP_LOCAL_CLOSE &&
+      p_mcb->force_close_local_cch_opening) {
+    p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_OPEN;
+    APPL_TRACE_DEBUG(
+        "change cch_oper from BTA_HL_CCH_OP_LOCAL_CLOSE to "
+        "BTA_HL_CCH_OP_LOCAL_OPEN");
+  }
+
+  switch (p_mcb->cch_oper) {
+    case BTA_HL_CCH_OP_LOCAL_OPEN:
+      bta_hl_build_cch_open_cfm(&evt_data, p_mcb->app_id, p_acb->app_handle,
+                                p_mcb->mcl_handle, p_mcb->bd_addr,
+                                BTA_HL_STATUS_FAIL);
+      event = BTA_HL_CCH_OPEN_CFM_EVT;
+      break;
+    case BTA_HL_CCH_OP_LOCAL_CLOSE:
+      bta_hl_build_cch_close_cfm(&evt_data, p_acb->app_handle,
+                                 p_mcb->mcl_handle, BTA_HL_STATUS_OK);
+      event = BTA_HL_CCH_CLOSE_CFM_EVT;
+      break;
+    case BTA_HL_CCH_OP_REMOTE_CLOSE:
+      bta_hl_build_cch_close_ind(&evt_data, p_acb->app_handle,
+                                 p_mcb->mcl_handle, p_mcb->intentional_close);
+      event = BTA_HL_CCH_CLOSE_IND_EVT;
+      break;
+    default:
+      send_evt = false;
+      break;
+  }
+
+  memset(p_mcb, 0, sizeof(tBTA_HL_MCL_CB));
+
+  if (send_evt) p_acb->p_cback(event, (tBTA_HL*)&evt_data);
+
+  bta_hl_check_deregistration(app_idx, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_cch_mca_disconnect
+ *
+ * Description      Action routine for processing the CCH disconnect indication
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_cch_mca_disconnect(uint8_t app_idx, uint8_t mcl_idx,
+                               tBTA_HL_DATA* p_data) {
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb;
+  uint8_t i;
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_cch_mca_disconnect");
+#endif
+
+  p_mcb->intentional_close = false;
+  if (p_data->mca_evt.mca_data.disconnect_ind.reason == L2CAP_DISC_OK) {
+    p_mcb->intentional_close = true;
+  }
+
+  for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+    p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, i);
+    if (p_dcb->in_use && (p_dcb->dch_state != BTA_HL_DCH_IDLE_ST)) {
+      if (p_mcb->cch_oper == BTA_HL_CCH_OP_LOCAL_CLOSE) {
+        bta_hl_dch_sm_execute(app_idx, mcl_idx, i, BTA_HL_DCH_CLOSE_CMPL_EVT,
+                              p_data);
+      } else {
+        bta_hl_dch_sm_execute(app_idx, mcl_idx, i, BTA_HL_MCA_CLOSE_IND_EVT,
+                              p_data);
+      }
+    }
+  }
+  bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_cch_mca_disc_open
+ *
+ * Description      Action routine for disconnect the just opened Control
+ *                  channel
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_cch_mca_disc_open(uint8_t app_idx, uint8_t mcl_idx,
+                              tBTA_HL_DATA* p_data) {
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_cch_mca_disc_open mcl_handle=0x%x close_pending=%d",
+                   p_data->mca_evt.mcl_handle, p_mcb->close_pending);
+#endif
+
+  p_mcb->close_pending = false;
+  p_mcb->mcl_handle = p_data->mca_evt.mcl_handle;
+  bta_hl_cch_mca_close(app_idx, mcl_idx, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_cch_mca_rsp_tout
+ *
+ * Description      Action routine for processing the MCAP response timeout
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_cch_mca_rsp_tout(uint8_t app_idx, uint8_t mcl_idx,
+                             tBTA_HL_DATA* p_data) {
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_cch_mca_rsp_tout");
+#endif
+
+  p_mcb->rsp_tout = true;
+
+  bta_hl_check_cch_close(app_idx, mcl_idx, p_data, true);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_cch_mca_connect
+ *
+ * Description      Action routine for processing the CCH connect indication
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_cch_mca_connect(uint8_t app_idx, uint8_t mcl_idx,
+                            tBTA_HL_DATA* p_data) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL evt_data;
+  tBTA_HL_EVT event;
+  bool send_event = true;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_cch_mca_connect mcl_handle=%d ",
+                   p_data->mca_evt.mcl_handle);
+#endif
+
+  p_mcb->mcl_handle = p_data->mca_evt.mcl_handle;
+  bdcpy(p_mcb->bd_addr, p_data->mca_evt.mca_data.connect_ind.bd_addr);
+  p_mcb->cch_mtu = p_data->mca_evt.mca_data.connect_ind.mtu;
+
+  bta_sys_conn_open(BTA_ID_HL, p_acb->app_id, p_mcb->bd_addr);
+  switch (p_mcb->cch_oper) {
+    case BTA_HL_CCH_OP_LOCAL_OPEN:
+      bta_hl_build_cch_open_cfm(&evt_data, p_mcb->app_id, p_acb->app_handle,
+                                p_mcb->mcl_handle, p_mcb->bd_addr,
+                                BTA_HL_STATUS_OK);
+      event = BTA_HL_CCH_OPEN_CFM_EVT;
+      break;
+    case BTA_HL_CCH_OP_REMOTE_OPEN:
+      bta_hl_build_cch_open_ind(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
+                                p_mcb->bd_addr);
+      event = BTA_HL_CCH_OPEN_IND_EVT;
+      break;
+    default:
+      send_event = false;
+      break;
+  }
+
+  p_mcb->cch_oper = BTA_HL_CCH_OP_NONE;
+  if (send_event) p_acb->p_cback(event, (tBTA_HL*)&evt_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_mcap_ctrl_cback
+ *
+ * Description      MCAP control callback function for HL.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_mcap_ctrl_cback(tMCA_HANDLE handle, tMCA_CL mcl, uint8_t event,
+                            tMCA_CTRL* p_data) {
+  bool send_event = true;
+  uint16_t mca_event;
+
+#if (BTA_HL_DEBUG == TRUE)
+#if (BT_TRACE_VERBOSE == TRUE)
+  APPL_TRACE_EVENT("bta_hl_mcap_ctrl_cback event[%s]",
+                   bta_hl_mcap_evt_code(event));
+#else
+  APPL_TRACE_EVENT("bta_hl_mcap_ctrl_cback event[0x%02x]", event);
+#endif
+#endif
+
+  switch (event) {
+    case MCA_CREATE_IND_EVT:
+      mca_event = (uint16_t)BTA_HL_MCA_CREATE_IND_EVT;
+      break;
+    case MCA_CREATE_CFM_EVT:
+      mca_event = (uint16_t)BTA_HL_MCA_CREATE_CFM_EVT;
+      break;
+    case MCA_RECONNECT_IND_EVT:
+      mca_event = (uint16_t)BTA_HL_MCA_RECONNECT_IND_EVT;
+      break;
+    case MCA_RECONNECT_CFM_EVT:
+      mca_event = (uint16_t)BTA_HL_MCA_RECONNECT_CFM_EVT;
+      break;
+    case MCA_ABORT_IND_EVT:
+      mca_event = (uint16_t)BTA_HL_MCA_ABORT_IND_EVT;
+      break;
+    case MCA_ABORT_CFM_EVT:
+      mca_event = (uint16_t)BTA_HL_MCA_ABORT_CFM_EVT;
+      break;
+    case MCA_DELETE_IND_EVT:
+      mca_event = (uint16_t)BTA_HL_MCA_DELETE_IND_EVT;
+      break;
+    case MCA_DELETE_CFM_EVT:
+      mca_event = (uint16_t)BTA_HL_MCA_DELETE_CFM_EVT;
+      break;
+    case MCA_CONNECT_IND_EVT:
+      mca_event = (uint16_t)BTA_HL_MCA_CONNECT_IND_EVT;
+      break;
+    case MCA_DISCONNECT_IND_EVT:
+      mca_event = (uint16_t)BTA_HL_MCA_DISCONNECT_IND_EVT;
+      break;
+    case MCA_OPEN_IND_EVT:
+      mca_event = (uint16_t)BTA_HL_MCA_OPEN_IND_EVT;
+      break;
+    case MCA_OPEN_CFM_EVT:
+      mca_event = (uint16_t)BTA_HL_MCA_OPEN_CFM_EVT;
+      break;
+    case MCA_CLOSE_IND_EVT:
+      mca_event = (uint16_t)BTA_HL_MCA_CLOSE_IND_EVT;
+      break;
+    case MCA_CLOSE_CFM_EVT:
+      mca_event = (uint16_t)BTA_HL_MCA_CLOSE_CFM_EVT;
+      break;
+    case MCA_CONG_CHG_EVT:
+      mca_event = (uint16_t)BTA_HL_MCA_CONG_CHG_EVT;
+      break;
+    case MCA_RSP_TOUT_IND_EVT:
+      mca_event = (uint16_t)BTA_HL_MCA_RSP_TOUT_IND_EVT;
+      break;
+    case MCA_ERROR_RSP_EVT:
+
+    default:
+      send_event = false;
+      break;
+  }
+
+  if (send_event) {
+    tBTA_HL_MCA_EVT* p_msg =
+        (tBTA_HL_MCA_EVT*)osi_malloc(sizeof(tBTA_HL_MCA_EVT));
+    p_msg->hdr.event = mca_event;
+    p_msg->app_handle = (tBTA_HL_APP_HANDLE)handle;
+    p_msg->mcl_handle = (tBTA_HL_MCL_HANDLE)mcl;
+    memcpy(&p_msg->mca_data, p_data, sizeof(tMCA_CTRL));
+    bta_sys_sendmsg(p_msg);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_mcap_data_cback
+ *
+ * Description      MCAP data callback function for HL.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_mcap_data_cback(tMCA_DL mdl, BT_HDR* p_pkt) {
+  uint8_t app_idx, mcl_idx, mdl_idx;
+  if (bta_hl_find_mdl_idx_using_handle((tBTA_HL_MDL_HANDLE)mdl, &app_idx,
+                                       &mcl_idx, &mdl_idx)) {
+    tBTA_HL_MCA_RCV_DATA_EVT* p_msg =
+        (tBTA_HL_MCA_RCV_DATA_EVT*)osi_malloc(sizeof(tBTA_HL_MCA_RCV_DATA_EVT));
+    p_msg->hdr.event = BTA_HL_MCA_RCV_DATA_EVT;
+    p_msg->app_idx = app_idx;
+    p_msg->mcl_idx = mcl_idx;
+    p_msg->mdl_idx = mdl_idx;
+    p_msg->p_pkt = p_pkt;
+    bta_sys_sendmsg(p_msg);
+  }
+}
+
+/*****************************************************************************
+ *  Debug Functions
+ ****************************************************************************/
+#if (BTA_HL_DEBUG == TRUE && BT_TRACE_VERBOSE == TRUE)
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_mcap_evt_code
+ *
+ * Description      get the MCAP event string pointer
+ *
+ * Returns          char * - event string pointer
+ *
+ ******************************************************************************/
+static char* bta_hl_mcap_evt_code(uint8_t evt_code) {
+  switch (evt_code) {
+    case MCA_ERROR_RSP_EVT:
+      return "MCA_ERROR_RSP_EVT";
+    case MCA_CREATE_IND_EVT:
+      return "MCA_CREATE_IND_EVT";
+    case MCA_CREATE_CFM_EVT:
+      return "MCA_CREATE_CFM_EVT";
+    case MCA_RECONNECT_IND_EVT:
+      return "MCA_RECONNECT_IND_EVT";
+    case MCA_RECONNECT_CFM_EVT:
+      return "MCA_RECONNECT_CFM_EVT";
+    case MCA_ABORT_IND_EVT:
+      return "MCA_ABORT_IND_EVT";
+    case MCA_ABORT_CFM_EVT:
+      return "MCA_ABORT_CFM_EVT";
+    case MCA_DELETE_IND_EVT:
+      return "MCA_DELETE_IND_EVT";
+    case MCA_DELETE_CFM_EVT:
+      return "MCA_DELETE_CFM_EVT";
+
+    case MCA_CONNECT_IND_EVT:
+      return "MCA_CONNECT_IND_EVT";
+    case MCA_DISCONNECT_IND_EVT:
+      return "MCA_DISCONNECT_IND_EVT";
+    case MCA_OPEN_IND_EVT:
+      return "MCA_OPEN_IND_EVT";
+    case MCA_OPEN_CFM_EVT:
+      return "MCA_OPEN_CFM_EVT";
+    case MCA_CLOSE_IND_EVT:
+      return "MCA_CLOSE_IND_EVT";
+    case MCA_CLOSE_CFM_EVT:
+      return "MCA_CLOSE_CFM_EVT";
+    case MCA_CONG_CHG_EVT:
+      return "MCA_CONG_CHG_EVT";
+    case MCA_RSP_TOUT_IND_EVT:
+      return "MCA_RSP_TOUT_IND_EVT";
+    default:
+      return "Unknown MCAP event code";
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_cback_evt_code
+ *
+ * Description      get the HDP event string pointer
+ *
+ * Returns          char * - event string pointer
+ *
+ ******************************************************************************/
+static char* bta_hl_cback_evt_code(uint8_t evt_code) {
+  switch (evt_code) {
+    case BTA_HL_CCH_OPEN_IND_EVT:
+      return "BTA_HL_CCH_OPEN_IND_EVT";
+    case BTA_HL_CCH_OPEN_CFM_EVT:
+      return "BTA_HL_CCH_OPEN_CFM_EVT";
+    case BTA_HL_CCH_CLOSE_IND_EVT:
+      return "BTA_HL_CCH_CLOSE_IND_EVT";
+    case BTA_HL_CCH_CLOSE_CFM_EVT:
+      return "BTA_HL_CCH_CLOSE_CFM_EVT";
+    case BTA_HL_DCH_OPEN_IND_EVT:
+      return "BTA_HL_DCH_OPEN_IND_EVT";
+    case BTA_HL_DCH_OPEN_CFM_EVT:
+      return "BTA_HL_DCH_OPEN_CFM_EVT";
+    case BTA_HL_DCH_CLOSE_IND_EVT:
+      return "BTA_HL_DCH_CLOSE_IND_EVT";
+    case BTA_HL_DCH_CLOSE_CFM_EVT:
+      return "BTA_HL_DCH_CLOSE_CFM_EVT";
+    case BTA_HL_DCH_RCV_DATA_IND_EVT:
+      return "BTA_HL_DCH_RCV_DATA_IND_EVT";
+    case BTA_HL_REGISTER_CFM_EVT:
+      return "BTA_HL_REGISTER_CFM_EVT";
+    case BTA_HL_DEREGISTER_CFM_EVT:
+      return "BTA_HL_DEREGISTER_CFM_EVT";
+    case BTA_HL_DCH_RECONNECT_CFM_EVT:
+      return "BTA_HL_DCH_RECONNECT_CFM_EVT";
+    case BTA_HL_DCH_RECONNECT_IND_EVT:
+      return "BTA_HL_DCH_RECONNECT_IND_EVT";
+    case BTA_HL_DCH_ECHO_TEST_CFM_EVT:
+      return "BTA_HL_DCH_ECHO_TEST_CFM_EVT";
+    case BTA_HL_SDP_QUERY_CFM_EVT:
+      return "BTA_HL_SDP_QUERY_CFM_EVT";
+    case BTA_HL_CONG_CHG_IND_EVT:
+      return "BTA_HL_CONG_CHG_IND_EVT";
+    case BTA_HL_DCH_CREATE_IND_EVT:
+      return "BTA_HL_DCH_CREATE_IND_EVT";
+    case BTA_HL_DELETE_MDL_IND_EVT:
+      return "BTA_HL_DELETE_MDL_IND_EVT";
+    case BTA_HL_DELETE_MDL_CFM_EVT:
+      return "BTA_HL_DELETE_MDL_CFM_EVT";
+    case BTA_HL_DCH_ABORT_IND_EVT:
+      return "BTA_HL_DCH_ABORT_IND_EVT";
+    case BTA_HL_DCH_ABORT_CFM_EVT:
+      return "BTA_HL_DCH_ABORT_CFM_EVT";
+    default:
+      return "Unknown HDP event code";
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_oper_code
+ *
+ * Description      Get the DCH operation string
+ *
+ * Returns          char * - DCH operation string pointer
+ *
+ ******************************************************************************/
+static char* bta_hl_dch_oper_code(tBTA_HL_DCH_OPER oper_code) {
+  switch (oper_code) {
+    case BTA_HL_DCH_OP_NONE:
+      return "BTA_HL_DCH_OP_NONE";
+    case BTA_HL_DCH_OP_REMOTE_CREATE:
+      return "BTA_HL_DCH_OP_REMOTE_CREATE";
+    case BTA_HL_DCH_OP_LOCAL_OPEN:
+      return "BTA_HL_DCH_OP_LOCAL_OPEN";
+    case BTA_HL_DCH_OP_REMOTE_OPEN:
+      return "BTA_HL_DCH_OP_REMOTE_OPEN";
+    case BTA_HL_DCH_OP_LOCAL_CLOSE:
+      return "BTA_HL_DCH_OP_LOCAL_CLOSE";
+    case BTA_HL_DCH_OP_REMOTE_CLOSE:
+      return "BTA_HL_DCH_OP_REMOTE_CLOSE";
+    case BTA_HL_DCH_OP_LOCAL_DELETE:
+      return "BTA_HL_DCH_OP_LOCAL_DELETE";
+    case BTA_HL_DCH_OP_REMOTE_DELETE:
+      return "BTA_HL_DCH_OP_REMOTE_DELETE";
+    case BTA_HL_DCH_OP_LOCAL_RECONNECT:
+      return "BTA_HL_DCH_OP_LOCAL_RECONNECT";
+    case BTA_HL_DCH_OP_REMOTE_RECONNECT:
+      return "BTA_HL_DCH_OP_REMOTE_RECONNECT";
+    case BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST:
+      return "BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST";
+    case BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT:
+      return "BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT";
+    default:
+      return "Unknown DCH oper code";
+  }
+}
+
+#endif /* Debug Functions */
+#endif /* HL_INCLUDED */
diff --git a/bt/bta/hl/bta_hl_api.cc b/bt/bta/hl/bta_hl_api.cc
new file mode 100644
index 0000000..cc0ae06
--- /dev/null
+++ b/bt/bta/hl/bta_hl_api.cc
@@ -0,0 +1,489 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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 is the implementation of the API for the HeaLth device profile (HL)
+ *  subsystem of BTA, Broadcom Corp's Bluetooth application layer for mobile
+ *  phones.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_target.h"
+#if (HL_INCLUDED == TRUE)
+
+#include "bt_common.h"
+#include "bta_hl_api.h"
+#include "bta_hl_int.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_hl_reg = {bta_hl_hdl_event, BTA_HlDisable};
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlEnable
+ *
+ * Description      Enable the HL subsystems.  This function must be
+ *                  called before any other functions in the HL API are called.
+ *                  When the enable operation is completed the callback function
+ *                  will be called with an BTA_HL_CTRL_ENABLE_CFM_EVT event.
+ *
+ * Parameters       p_cback - HL event call back function
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HlEnable(tBTA_HL_CTRL_CBACK* p_ctrl_cback) {
+  tBTA_HL_API_ENABLE* p_buf =
+      (tBTA_HL_API_ENABLE*)osi_malloc(sizeof(tBTA_HL_API_ENABLE));
+
+  /* register with BTA system manager */
+  bta_sys_register(BTA_ID_HL, &bta_hl_reg);
+
+  p_buf->hdr.event = BTA_HL_API_ENABLE_EVT;
+  p_buf->p_cback = p_ctrl_cback;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlDisable
+ *
+ * Description     Disable the HL subsystem.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HlDisable(void) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  bta_sys_deregister(BTA_ID_HL);
+  p_buf->event = BTA_HL_API_DISABLE_EVT;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlUpdate
+ *
+ * Description      Register an HDP application
+ *
+ * Parameters       app_id        - Application ID
+ *                  p_reg_param   - non-platform related parameters for the
+ *                                  HDP application
+ *                  p_cback       - HL event callback fucntion
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HlUpdate(uint8_t app_id, tBTA_HL_REG_PARAM* p_reg_param,
+                  bool is_register, tBTA_HL_CBACK* p_cback) {
+  tBTA_HL_API_UPDATE* p_buf =
+      (tBTA_HL_API_UPDATE*)osi_malloc(sizeof(tBTA_HL_API_UPDATE));
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  p_buf->hdr.event = BTA_HL_API_UPDATE_EVT;
+  p_buf->app_id = app_id;
+  p_buf->is_register = is_register;
+
+  if (is_register) {
+    p_buf->sec_mask =
+        (p_reg_param->sec_mask | BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+    p_buf->p_cback = p_cback;
+    if (p_reg_param->p_srv_name)
+      strlcpy(p_buf->srv_name, p_reg_param->p_srv_name, BTA_SERVICE_NAME_LEN);
+    else
+      p_buf->srv_name[0] = 0;
+
+    if (p_reg_param->p_srv_desp)
+      strlcpy(p_buf->srv_desp, p_reg_param->p_srv_desp, BTA_SERVICE_DESP_LEN);
+    else
+      p_buf->srv_desp[0] = 0;
+
+    if (p_reg_param->p_provider_name)
+      strlcpy(p_buf->provider_name, p_reg_param->p_provider_name,
+              BTA_PROVIDER_NAME_LEN);
+    else
+      p_buf->provider_name[0] = 0;
+  }
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlRegister
+ *
+ * Description      Register an HDP application
+ *
+ * Parameters       app_id        - Application ID
+ *                  p_reg_param   - non-platform related parameters for the
+ *                                  HDP application
+ *                  p_cback       - HL event callback fucntion
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HlRegister(uint8_t app_id, tBTA_HL_REG_PARAM* p_reg_param,
+                    tBTA_HL_CBACK* p_cback) {
+  tBTA_HL_API_REGISTER* p_buf =
+      (tBTA_HL_API_REGISTER*)osi_malloc(sizeof(tBTA_HL_API_REGISTER));
+
+  p_buf->hdr.event = BTA_HL_API_REGISTER_EVT;
+  p_buf->app_id = app_id;
+  p_buf->sec_mask =
+      (p_reg_param->sec_mask | BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+  p_buf->p_cback = p_cback;
+
+  if (p_reg_param->p_srv_name)
+    strlcpy(p_buf->srv_name, p_reg_param->p_srv_name, BTA_SERVICE_NAME_LEN);
+  else
+    p_buf->srv_name[0] = 0;
+
+  if (p_reg_param->p_srv_desp)
+    strlcpy(p_buf->srv_desp, p_reg_param->p_srv_desp, BTA_SERVICE_DESP_LEN);
+  else
+    p_buf->srv_desp[0] = 0;
+
+  if (p_reg_param->p_provider_name)
+    strlcpy(p_buf->provider_name, p_reg_param->p_provider_name,
+            BTA_PROVIDER_NAME_LEN);
+  else
+    p_buf->provider_name[0] = 0;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlDeregister
+ *
+ * Description      Deregister an HDP application
+ *
+ * Parameters       app_handle - Application handle
+ *
+ * Returns           void
+ *
+ ******************************************************************************/
+void BTA_HlDeregister(uint8_t app_id, tBTA_HL_APP_HANDLE app_handle) {
+  tBTA_HL_API_DEREGISTER* p_buf =
+      (tBTA_HL_API_DEREGISTER*)osi_malloc(sizeof(tBTA_HL_API_DEREGISTER));
+
+  p_buf->hdr.event = BTA_HL_API_DEREGISTER_EVT;
+  p_buf->app_id = app_id;
+  p_buf->app_handle = app_handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlCchOpen
+ *
+ * Description      Open a Control channel connection with the specified BD
+ *                  address
+ *
+ * Parameters       app_handle - Application Handle
+ *                  p_open_param - parameters for opening a control channel
+ *
+ * Returns          void
+ *
+ *                  Note: The control PSM value is used to select which
+ *                  HDP insatnce should be used in case the peer device support
+ *                  multiple HDP instances. Also, if the control PSM value is
+ *                  zero then the first HDP instance is used for the control
+ *                  channel setup
+ ******************************************************************************/
+void BTA_HlCchOpen(uint8_t app_id, tBTA_HL_APP_HANDLE app_handle,
+                   tBTA_HL_CCH_OPEN_PARAM* p_open_param) {
+  tBTA_HL_API_CCH_OPEN* p_buf =
+      (tBTA_HL_API_CCH_OPEN*)osi_malloc(sizeof(tBTA_HL_API_CCH_OPEN));
+
+  p_buf->hdr.event = BTA_HL_API_CCH_OPEN_EVT;
+  p_buf->app_id = app_id;
+  p_buf->app_handle = app_handle;
+  p_buf->sec_mask =
+      (p_open_param->sec_mask | BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+  bdcpy(p_buf->bd_addr, p_open_param->bd_addr);
+  p_buf->ctrl_psm = p_open_param->ctrl_psm;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlCchClose
+ *
+ * Description      Close a Control channel connection with the specified MCL
+ *                  handle
+ *
+ * Parameters       mcl_handle - MCL handle
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HlCchClose(tBTA_HL_MCL_HANDLE mcl_handle) {
+  tBTA_HL_API_CCH_CLOSE* p_buf =
+      (tBTA_HL_API_CCH_CLOSE*)osi_malloc(sizeof(tBTA_HL_API_CCH_CLOSE));
+
+  p_buf->hdr.event = BTA_HL_API_CCH_CLOSE_EVT;
+  p_buf->mcl_handle = mcl_handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlDchOpen
+ *
+ * Description      Open a data channel connection with the specified DCH
+ *                  parameters
+ *
+ * Parameters       mcl_handle - MCL handle
+ *                  p_open_param - parameters for opening a data channel
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HlDchOpen(tBTA_HL_MCL_HANDLE mcl_handle,
+                   tBTA_HL_DCH_OPEN_PARAM* p_open_param) {
+  tBTA_HL_API_DCH_OPEN* p_buf =
+      (tBTA_HL_API_DCH_OPEN*)osi_malloc(sizeof(tBTA_HL_API_DCH_OPEN));
+
+  p_buf->hdr.event = BTA_HL_API_DCH_OPEN_EVT;
+  p_buf->mcl_handle = mcl_handle;
+  p_buf->ctrl_psm = p_open_param->ctrl_psm;
+  p_buf->local_mdep_id = p_open_param->local_mdep_id;
+  p_buf->peer_mdep_id = p_open_param->peer_mdep_id;
+  p_buf->local_cfg = p_open_param->local_cfg;
+  p_buf->sec_mask =
+      (p_open_param->sec_mask | BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlDchReconnect
+ *
+ * Description      Reconnect a data channel with the specified MDL_ID
+ *
+ * Parameters       mcl_handle      - MCL handle
+*8                  p_recon_param   - parameters for reconnecting a data channel
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HlDchReconnect(tBTA_HL_MCL_HANDLE mcl_handle,
+                        tBTA_HL_DCH_RECONNECT_PARAM* p_recon_param) {
+  tBTA_HL_API_DCH_RECONNECT* p_buf =
+      (tBTA_HL_API_DCH_RECONNECT*)osi_malloc(sizeof(tBTA_HL_API_DCH_RECONNECT));
+
+  p_buf->hdr.event = BTA_HL_API_DCH_RECONNECT_EVT;
+  p_buf->mcl_handle = mcl_handle;
+  p_buf->ctrl_psm = p_recon_param->ctrl_psm;
+  p_buf->mdl_id = p_recon_param->mdl_id;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlDchClose
+ *
+ * Description      Close a data channel with the specified MDL handle
+ *
+ * Parameters       mdl_handle  - MDL handle
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HlDchClose(tBTA_HL_MDL_HANDLE mdl_handle) {
+  tBTA_HL_API_DCH_CLOSE* p_buf =
+      (tBTA_HL_API_DCH_CLOSE*)osi_malloc(sizeof(tBTA_HL_API_DCH_CLOSE));
+
+  p_buf->hdr.event = BTA_HL_API_DCH_CLOSE_EVT;
+  p_buf->mdl_handle = mdl_handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlDchAbort
+ *
+ * Description      Abort the current data channel setup with the specified MCL
+ *                  handle
+ *
+ * Parameters       mcl_handle  - MCL handle
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HlDchAbort(tBTA_HL_MCL_HANDLE mcl_handle) {
+  tBTA_HL_API_DCH_ABORT* p_buf =
+      (tBTA_HL_API_DCH_ABORT*)osi_malloc(sizeof(tBTA_HL_API_DCH_ABORT));
+
+  p_buf->hdr.event = BTA_HL_API_DCH_ABORT_EVT;
+  p_buf->mcl_handle = mcl_handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlSendData
+ *
+ * Description      Send an APDU to the peer device
+ *
+ * Parameters       mdl_handle  - MDL handle
+ *                  pkt_size    - size of the data packet to be sent
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HlSendData(tBTA_HL_MDL_HANDLE mdl_handle, uint16_t pkt_size) {
+  tBTA_HL_API_SEND_DATA* p_buf =
+      (tBTA_HL_API_SEND_DATA*)osi_malloc(sizeof(tBTA_HL_API_SEND_DATA));
+
+  p_buf->hdr.event = BTA_HL_API_SEND_DATA_EVT;
+  p_buf->mdl_handle = mdl_handle;
+  p_buf->pkt_size = pkt_size;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlDeleteMdl
+ *
+ * Description      Delete the specified MDL_ID within the specified MCL handle
+ *
+ * Parameters       mcl_handle  - MCL handle
+ *                  mdl_id      - MDL ID
+ *
+ * Returns          void
+ *
+ *                  note: If mdl_id = 0xFFFF then this means to delete all MDLs
+ *                        and this value can only be used with DeleteMdl request
+ *                        only not other requests
+ *
+ ******************************************************************************/
+void BTA_HlDeleteMdl(tBTA_HL_MCL_HANDLE mcl_handle, tBTA_HL_MDL_ID mdl_id) {
+  tBTA_HL_API_DELETE_MDL* p_buf =
+      (tBTA_HL_API_DELETE_MDL*)osi_malloc(sizeof(tBTA_HL_API_DELETE_MDL));
+
+  p_buf->hdr.event = BTA_HL_API_DELETE_MDL_EVT;
+  p_buf->mcl_handle = mcl_handle;
+  p_buf->mdl_id = mdl_id;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlDchEchoTest
+ *
+ * Description      Initiate an echo test with the specified MCL handle
+ *
+ * Parameters       mcl_handle           - MCL handle
+*8                  p_echo_test_param   -  parameters for echo testing
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HlDchEchoTest(tBTA_HL_MCL_HANDLE mcl_handle,
+                       tBTA_HL_DCH_ECHO_TEST_PARAM* p_echo_test_param) {
+  tBTA_HL_API_DCH_ECHO_TEST* p_buf =
+      (tBTA_HL_API_DCH_ECHO_TEST*)osi_malloc(sizeof(tBTA_HL_API_DCH_ECHO_TEST));
+
+  p_buf->hdr.event = BTA_HL_API_DCH_ECHO_TEST_EVT;
+  p_buf->mcl_handle = mcl_handle;
+  p_buf->ctrl_psm = p_echo_test_param->ctrl_psm;
+  p_buf->local_cfg = p_echo_test_param->local_cfg;
+  p_buf->pkt_size = p_echo_test_param->pkt_size;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlSdpQuery
+ *
+ * Description      SDP query request for the specified BD address
+ *
+ * Parameters       app_handle      - application handle
+ *                  bd_addr         - BD address
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HlSdpQuery(uint8_t app_id, tBTA_HL_APP_HANDLE app_handle,
+                    BD_ADDR bd_addr) {
+  tBTA_HL_API_SDP_QUERY* p_buf =
+      (tBTA_HL_API_SDP_QUERY*)osi_malloc(sizeof(tBTA_HL_API_SDP_QUERY));
+
+  p_buf->hdr.event = BTA_HL_API_SDP_QUERY_EVT;
+  p_buf->app_id = app_id;
+  p_buf->app_handle = app_handle;
+  bdcpy(p_buf->bd_addr, bd_addr);
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlDchCreateMdlRsp
+ *
+ * Description      Set the Response and configuration values for the Create MDL
+ *                  request
+ *
+ * Parameters       mcl_handle  - MCL handle
+ *                  p_rsp_param - parameters specified whether the request
+ *                                should be accepted or not and if it should be
+ *                                accepted, then it also specified the
+ *                                configuration response value
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HlDchCreateRsp(tBTA_HL_MCL_HANDLE mcl_handle,
+                        tBTA_HL_DCH_CREATE_RSP_PARAM* p_rsp_param) {
+  tBTA_HL_API_DCH_CREATE_RSP* p_buf = (tBTA_HL_API_DCH_CREATE_RSP*)osi_malloc(
+      sizeof(tBTA_HL_API_DCH_CREATE_RSP));
+
+  p_buf->hdr.event = BTA_HL_API_DCH_CREATE_RSP_EVT;
+  p_buf->mcl_handle = mcl_handle;
+  p_buf->mdl_id = p_rsp_param->mdl_id;
+  p_buf->local_mdep_id = p_rsp_param->local_mdep_id;
+  p_buf->rsp_code = p_rsp_param->rsp_code;
+  p_buf->cfg_rsp = p_rsp_param->cfg_rsp;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+#endif /* HL_INCLUDED */
diff --git a/bt/bta/hl/bta_hl_ci.cc b/bt/bta/hl/bta_hl_ci.cc
new file mode 100644
index 0000000..b7bc2fd
--- /dev/null
+++ b/bt/bta/hl/bta_hl_ci.cc
@@ -0,0 +1,162 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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 is the implementation file for the HeaLth device profile (HL)
+ *  subsystem call-in functions.
+ *
+ ******************************************************************************/
+
+#include <stddef.h>
+
+#include "bta_api.h"
+#include "bta_hl_api.h"
+#include "bta_hl_ci.h"
+#include "bta_hl_co.h"
+#include "bta_hl_int.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_ci_get_tx_data
+ *
+ * Description      This function is called in response to the
+ *                  bta_hl_co_get_tx_data call-out function.
+ *
+ * Parameters       mdl_handle -MDL handle
+ *                  status - BTA_MA_STATUS_OK if operation is successful
+ *                           BTA_MA_STATUS_FAIL if any errors have occurred.
+ *                  evt    - evt from the call-out function
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_ci_get_tx_data(tBTA_HL_MDL_HANDLE mdl_handle, tBTA_HL_STATUS status,
+                           uint16_t evt) {
+  tBTA_HL_CI_GET_PUT_DATA* p_evt =
+      (tBTA_HL_CI_GET_PUT_DATA*)osi_malloc(sizeof(tBTA_HL_CI_GET_PUT_DATA));
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("%s mdl_handle=%d status=%d evt=%d\n", __func__, mdl_handle,
+                   status, evt);
+#endif
+
+  p_evt->hdr.event = evt;
+  p_evt->mdl_handle = mdl_handle;
+  p_evt->status = status;
+
+  bta_sys_sendmsg(p_evt);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_ci_put_rx_data
+ *
+ * Description      This function is called in response to the
+ *                  bta_hl_co_put_rx_data call-out function.
+ *
+ * Parameters       mdl_handle -MDL handle
+ *                  status - BTA_MA_STATUS_OK if operation is successful
+ *                           BTA_MA_STATUS_FAIL if any errors have occurred.
+ *                  evt    - evt from the call-out function
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hl_ci_put_rx_data(tBTA_HL_MDL_HANDLE mdl_handle,
+                                  tBTA_HL_STATUS status, uint16_t evt) {
+  tBTA_HL_CI_GET_PUT_DATA* p_evt =
+      (tBTA_HL_CI_GET_PUT_DATA*)osi_malloc(sizeof(tBTA_HL_CI_GET_PUT_DATA));
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("%s mdl_handle=%d status=%d evt=%d\n", __func__, mdl_handle,
+                   status, evt);
+#endif
+
+  p_evt->hdr.event = evt;
+  p_evt->mdl_handle = mdl_handle;
+  p_evt->status = status;
+
+  bta_sys_sendmsg(p_evt);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_ci_get_echo_data
+ *
+ * Description      This function is called in response to the
+ *                  bta_hl_co_get_echo_data call-out function.
+ *
+ * Parameters       mcl_handle -MCL handle
+ *                  status - BTA_MA_STATUS_OK if operation is successful
+ *                           BTA_MA_STATUS_FAIL if any errors have occurred.
+ *                  evt    - evt from the call-out function
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hl_ci_get_echo_data(tBTA_HL_MCL_HANDLE mcl_handle,
+                                    tBTA_HL_STATUS status, uint16_t evt) {
+  tBTA_HL_CI_ECHO_DATA* p_evt =
+      (tBTA_HL_CI_ECHO_DATA*)osi_malloc(sizeof(tBTA_HL_CI_ECHO_DATA));
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("%s mcl_handle=%d status=%d evt=%d\n", __func__, mcl_handle,
+                   status, evt);
+#endif
+
+  p_evt->hdr.event = evt;
+  p_evt->mcl_handle = mcl_handle;
+  p_evt->status = status;
+
+  bta_sys_sendmsg(p_evt);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_ci_put_echo_data
+ *
+ * Description      This function is called in response to the
+ *                  bta_hl_co_put_echo_data call-out function.
+ *
+ * Parameters       mcl_handle -MCL handle
+ *                  status - BTA_MA_STATUS_OK if operation is successful
+ *                           BTA_MA_STATUS_FAIL if any errors have occurred.
+ *                  evt    - evt from the call-out function
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hl_ci_put_echo_data(tBTA_HL_MCL_HANDLE mcl_handle,
+                                    tBTA_HL_STATUS status, uint16_t evt) {
+  tBTA_HL_CI_ECHO_DATA* p_evt =
+      (tBTA_HL_CI_ECHO_DATA*)osi_malloc(sizeof(tBTA_HL_CI_ECHO_DATA));
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("%s mcl_handle=%d status=%d evt=%d\n", __func__, mcl_handle,
+                   status, evt);
+#endif
+
+  p_evt->hdr.event = evt;
+  p_evt->mcl_handle = mcl_handle;
+  p_evt->status = status;
+
+  bta_sys_sendmsg(p_evt);
+}
diff --git a/bt/bta/hl/bta_hl_int.h b/bt/bta/hl/bta_hl_int.h
new file mode 100644
index 0000000..e5acb52
--- /dev/null
+++ b/bt/bta/hl/bta_hl_int.h
@@ -0,0 +1,859 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1998-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 is the private file for the message access equipment (MSE)
+ *  subsystem.
+ *
+ ******************************************************************************/
+#ifndef BTA_HL_INT_H
+#define BTA_HL_INT_H
+
+#include "bt_target.h"
+#include "bta_hl_api.h"
+#include "bta_hl_co.h"
+#include "bta_sys.h"
+#include "l2cdefs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef uint16_t(tBTA_HL_ALLOCATE_PSM)(void);
+
+/*****************************************************************************
+ *  Constants and data types
+ ****************************************************************************/
+
+#ifndef BTA_HL_DISC_SIZE
+#define BTA_HL_DISC_SIZE 1600
+#endif
+#define BTA_HL_NUM_SRCH_ATTR 10
+#define BTA_HL_MIN_SDP_MDEP_LEN 7
+
+/* L2CAP defualt parameters */
+#define BTA_HL_L2C_TX_WIN_SIZE 10
+#define BTA_HL_L2C_MAX_TRANSMIT 32
+#define BTA_HL_L2C_RTRANS_TOUT 2000
+#define BTA_HL_L2C_MON_TOUT 12000
+#define BTA_HL_L2C_MPS 1017
+
+/* L2CAP FCS setting*/
+#define BTA_HL_MCA_USE_FCS MCA_FCS_USE
+#define BTA_HL_MCA_NO_FCS MCA_FCS_BYPASS
+#define BTA_HL_L2C_USE_FCS 1
+#define BTA_HL_L2C_NO_FCS 0
+#define BTA_HL_DEFAULT_SOURCE_FCS BTA_HL_L2C_USE_FCS
+#define BTA_HL_MCA_FCS_USE_MASK MCA_FCS_USE_MASK
+
+/* SDP Operations */
+#define BTA_HL_SDP_OP_NONE 0
+#define BTA_HL_SDP_OP_CCH_INIT 1
+#define BTA_HL_SDP_OP_DCH_OPEN_INIT 2
+#define BTA_HL_SDP_OP_DCH_RECONNECT_INIT 3
+#define BTA_HL_SDP_OP_SDP_QUERY_NEW 4
+#define BTA_HL_SDP_OP_SDP_QUERY_CURRENT 5
+
+typedef uint8_t tBTA_HL_SDP_OPER;
+
+/* CCH Operations */
+#define BTA_HL_CCH_OP_NONE 0
+#define BTA_HL_CCH_OP_LOCAL_OPEN 1
+#define BTA_HL_CCH_OP_REMOTE_OPEN 2
+#define BTA_HL_CCH_OP_LOCAL_CLOSE 3
+#define BTA_HL_CCH_OP_REMOTE_CLOSE 4
+
+typedef uint8_t tBTA_HL_CCH_OPER;
+
+/* Pending DCH close operations when closing a CCH */
+#define BTA_HL_CCH_CLOSE_OP_DCH_NONE 0
+#define BTA_HL_CCH_CLOSE_OP_DCH_ABORT 1
+#define BTA_HL_CCH_CLOSE_OP_DCH_CLOSE 2
+typedef uint8_t tBTA_HL_CCH_CLOSE_DCH_OPER;
+
+/* DCH Operations */
+#define BTA_HL_DCH_OP_NONE 0
+#define BTA_HL_DCH_OP_REMOTE_CREATE 1
+#define BTA_HL_DCH_OP_LOCAL_OPEN 2
+#define BTA_HL_DCH_OP_REMOTE_OPEN 3
+#define BTA_HL_DCH_OP_LOCAL_CLOSE 4
+#define BTA_HL_DCH_OP_REMOTE_CLOSE 5
+#define BTA_HL_DCH_OP_LOCAL_DELETE 6
+#define BTA_HL_DCH_OP_REMOTE_DELETE 7
+#define BTA_HL_DCH_OP_LOCAL_RECONNECT 8
+#define BTA_HL_DCH_OP_REMOTE_RECONNECT 9
+#define BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST 10
+#define BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT 11
+
+typedef uint8_t tBTA_HL_DCH_OPER;
+
+/* Echo test Operations */
+#define BTA_HL_ECHO_OP_NONE 0
+#define BTA_HL_ECHO_OP_CI_GET_ECHO_DATA 1
+#define BTA_HL_ECHO_OP_SDP_INIT 2
+#define BTA_HL_ECHO_OP_MDL_CREATE_CFM 3
+#define BTA_HL_ECHO_OP_DCH_OPEN_CFM 4
+#define BTA_HL_ECHO_OP_LOOP_BACK 5
+#define BTA_HL_ECHO_OP_CI_PUT_ECHO_DATA 6
+#define BTA_HL_ECHO_OP_DCH_CLOSE_CFM 7
+#define BTA_HL_ECHO_OP_OPEN_IND 8
+#define BTA_HL_ECHO_OP_ECHO_PKT 9
+
+typedef uint8_t tBTA_HL_ECHO_OPER;
+
+/* abort status mask for abort_oper */
+
+#define BTA_HL_ABORT_NONE_MASK 0x00
+#define BTA_HL_ABORT_PENDING_MASK 0x01
+#define BTA_HL_ABORT_LOCAL_MASK 0x10
+#define BTA_HL_ABORT_REMOTE_MASK 0x20
+#define BTA_HL_ABORT_CCH_CLOSE_MASK 0x40
+
+/* call out mask for cout_oper */
+#define BTA_HL_CO_NONE_MASK 0x00
+#define BTA_HL_CO_GET_TX_DATA_MASK 0x01
+#define BTA_HL_CO_PUT_RX_DATA_MASK 0x02
+#define BTA_HL_CO_GET_ECHO_DATA_MASK 0x04
+#define BTA_HL_CO_PUT_ECHO_DATA_MASK 0x08
+
+typedef struct {
+  uint16_t mtu;
+  uint8_t fcs; /* '0' No FCS, otherwise '1' */
+} tBTA_HL_L2CAP_CFG_INFO;
+
+/* State Machine Events */
+enum {
+  /* these events are handled by the state machine */
+  BTA_HL_CCH_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_HL),
+  BTA_HL_CCH_SDP_OK_EVT,
+  BTA_HL_CCH_SDP_FAIL_EVT,
+  BTA_HL_MCA_CONNECT_IND_EVT,
+  BTA_HL_MCA_DISCONNECT_IND_EVT,
+  BTA_HL_CCH_CLOSE_EVT,
+  BTA_HL_CCH_CLOSE_CMPL_EVT,
+  BTA_HL_MCA_RSP_TOUT_IND_EVT,
+  /* DCH EVENT */
+  BTA_HL_DCH_SDP_INIT_EVT,
+  BTA_HL_DCH_OPEN_EVT,
+  BTA_HL_MCA_CREATE_IND_EVT,
+  BTA_HL_MCA_CREATE_CFM_EVT,
+  BTA_HL_MCA_OPEN_IND_EVT,
+
+  BTA_HL_MCA_OPEN_CFM_EVT,
+  BTA_HL_DCH_CLOSE_EVT,
+  BTA_HL_MCA_CLOSE_IND_EVT,
+  BTA_HL_MCA_CLOSE_CFM_EVT,
+  BTA_HL_API_SEND_DATA_EVT,
+
+  BTA_HL_MCA_RCV_DATA_EVT,
+  BTA_HL_DCH_CLOSE_CMPL_EVT,
+  BTA_HL_DCH_RECONNECT_EVT,
+  BTA_HL_DCH_SDP_FAIL_EVT,
+  BTA_HL_MCA_RECONNECT_IND_EVT,
+
+  BTA_HL_MCA_RECONNECT_CFM_EVT,
+  BTA_HL_DCH_CLOSE_ECHO_TEST_EVT,
+  BTA_HL_API_DCH_CREATE_RSP_EVT,
+  BTA_HL_DCH_ABORT_EVT,
+  BTA_HL_MCA_ABORT_IND_EVT,
+
+  BTA_HL_MCA_ABORT_CFM_EVT,
+  BTA_HL_MCA_CONG_CHG_EVT,
+  BTA_HL_CI_GET_TX_DATA_EVT,
+  BTA_HL_CI_PUT_RX_DATA_EVT,
+  BTA_HL_CI_GET_ECHO_DATA_EVT,
+  BTA_HL_DCH_ECHO_TEST_EVT,
+  BTA_HL_CI_PUT_ECHO_DATA_EVT,
+
+  /* these events are handled outside the state machine */
+  BTA_HL_API_ENABLE_EVT,
+  BTA_HL_API_DISABLE_EVT,
+  BTA_HL_API_UPDATE_EVT,
+  BTA_HL_API_REGISTER_EVT,
+  BTA_HL_API_DEREGISTER_EVT,
+  BTA_HL_API_CCH_OPEN_EVT,
+  BTA_HL_API_CCH_CLOSE_EVT,
+  BTA_HL_API_DCH_OPEN_EVT,
+  BTA_HL_API_DCH_RECONNECT_EVT,
+  BTA_HL_API_DCH_CLOSE_EVT,
+  BTA_HL_API_DELETE_MDL_EVT,
+  BTA_HL_API_DCH_ABORT_EVT,
+
+  BTA_HL_API_DCH_ECHO_TEST_EVT,
+  BTA_HL_API_SDP_QUERY_EVT,
+  BTA_HL_SDP_QUERY_OK_EVT,
+  BTA_HL_SDP_QUERY_FAIL_EVT,
+  BTA_HL_MCA_DELETE_IND_EVT,
+  BTA_HL_MCA_DELETE_CFM_EVT
+};
+typedef uint16_t tBTA_HL_INT_EVT;
+
+#define BTA_HL_DCH_EVT_MIN BTA_HL_DCH_SDP_INIT_EVT
+#define BTA_HL_DCH_EVT_MAX 0xFFFF
+
+/* state machine states */
+enum {
+  BTA_HL_CCH_IDLE_ST = 0, /* Idle  */
+  BTA_HL_CCH_OPENING_ST,  /* Opening a connection*/
+  BTA_HL_CCH_OPEN_ST,     /* Connection is open */
+  BTA_HL_CCH_CLOSING_ST   /* Closing is in progress */
+};
+typedef uint8_t tBTA_HL_CCH_STATE;
+
+enum {
+  BTA_HL_DCH_IDLE_ST = 0, /* Idle  */
+  BTA_HL_DCH_OPENING_ST,  /* Opening a connection*/
+  BTA_HL_DCH_OPEN_ST,     /* Connection is open */
+  BTA_HL_DCH_CLOSING_ST   /* Closing is in progress */
+};
+typedef uint8_t tBTA_HL_DCH_STATE;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_HL_CTRL_CBACK* p_cback; /* pointer to control callback function */
+} tBTA_HL_API_ENABLE;
+
+typedef struct {
+  BT_HDR hdr;
+  uint8_t app_id;
+  bool is_register; /* Update HL application due to register or deregister */
+  tBTA_HL_CBACK* p_cback;       /* pointer to application callback function */
+  tBTA_HL_DEVICE_TYPE dev_type; /* sink, source or dual roles */
+  tBTA_SEC sec_mask;            /* security mask for accepting conenction*/
+  char srv_name[BTA_SERVICE_NAME_LEN +
+                1]; /* service name to be used in the SDP; null terminated*/
+  char srv_desp[BTA_SERVICE_DESP_LEN + 1]; /* service description to be used in
+                                              the SDP; null terminated */
+  char provider_name[BTA_PROVIDER_NAME_LEN + 1]; /* provide name to be used in
+                                                    the SDP; null terminated */
+
+} tBTA_HL_API_UPDATE;
+
+typedef struct {
+  BT_HDR hdr;
+  uint8_t app_id;
+  tBTA_HL_CBACK* p_cback;       /* pointer to application callback function */
+  tBTA_HL_DEVICE_TYPE dev_type; /* sink, source or dual roles */
+  tBTA_SEC sec_mask;            /* security mask for accepting conenction*/
+  char srv_name[BTA_SERVICE_NAME_LEN +
+                1]; /* service name to be used in the SDP; null terminated*/
+  char srv_desp[BTA_SERVICE_DESP_LEN + 1]; /* service description to be used in
+                                              the SDP; null terminated */
+  char provider_name[BTA_PROVIDER_NAME_LEN + 1]; /* provide name to be used in
+                                                    the SDP; null terminated */
+} tBTA_HL_API_REGISTER;
+
+typedef struct {
+  BT_HDR hdr;
+  uint8_t app_id;
+  tBTA_HL_CBACK* p_cback; /* pointer to application callback function */
+  tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_API_DEREGISTER;
+
+typedef struct {
+  BT_HDR hdr;
+  uint8_t app_id;
+  tBTA_HL_APP_HANDLE app_handle;
+  uint16_t ctrl_psm;
+  BD_ADDR bd_addr;   /* Address of peer device */
+  tBTA_SEC sec_mask; /* security mask for initiating connection*/
+} tBTA_HL_API_CCH_OPEN;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_HL_MCL_HANDLE mcl_handle;
+} tBTA_HL_API_CCH_CLOSE;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  uint16_t ctrl_psm;
+  tBTA_HL_MDEP_ID local_mdep_id; /* local MDEP ID */
+  tBTA_HL_MDEP_ID peer_mdep_id;  /* peer mdep id */
+  tBTA_HL_DCH_CFG local_cfg;
+  tBTA_SEC sec_mask; /* security mask for initiating connection*/
+} tBTA_HL_API_DCH_OPEN;
+
+typedef struct {
+  BT_HDR hdr;
+
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  uint16_t ctrl_psm;
+  tBTA_HL_MDL_ID mdl_id;
+} tBTA_HL_API_DCH_RECONNECT;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_HL_MDL_HANDLE mdl_handle;
+} tBTA_HL_API_DCH_CLOSE;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  tBTA_HL_MDL_ID mdl_id;
+} tBTA_HL_API_DELETE_MDL;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_HL_MCL_HANDLE mcl_handle;
+} tBTA_HL_API_DCH_ABORT;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_HL_MDL_HANDLE mdl_handle;
+  uint16_t pkt_size;
+} tBTA_HL_API_SEND_DATA;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  uint16_t ctrl_psm;
+  uint16_t pkt_size;
+  tBTA_HL_DCH_CFG local_cfg;
+} tBTA_HL_API_DCH_ECHO_TEST;
+
+typedef struct {
+  BT_HDR hdr;
+  uint8_t app_idx;
+  uint8_t mcl_idx;
+  bool release_mcl_cb;
+} tBTA_HL_CCH_SDP;
+
+/* MCA callback event parameters. */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_HL_APP_HANDLE app_handle;
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  tMCA_CTRL mca_data;
+} tBTA_HL_MCA_EVT;
+
+/* MCA callback event parameters. */
+typedef struct {
+  BT_HDR hdr;
+  uint8_t app_idx;
+  uint8_t mcl_idx;
+  uint8_t mdl_idx;
+  BT_HDR* p_pkt;
+} tBTA_HL_MCA_RCV_DATA_EVT;
+
+typedef struct {
+  BT_HDR hdr;
+  uint8_t app_idx;
+  uint8_t mcl_idx;
+  uint8_t mdl_idx;
+} tBTA_HL_DCH_SDP;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_HL_APP_HANDLE app_handle;
+  uint8_t app_id;
+  BD_ADDR bd_addr; /* Address of peer device */
+} tBTA_HL_API_SDP_QUERY;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  tBTA_HL_MDL_ID mdl_id;
+  tBTA_HL_MDEP_ID local_mdep_id;
+  tBTA_HL_DCH_CREATE_RSP rsp_code;
+  tBTA_HL_DCH_CFG cfg_rsp;
+} tBTA_HL_API_DCH_CREATE_RSP;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_HL_MDL_HANDLE mdl_handle;
+  tBTA_HL_STATUS status;
+} tBTA_HL_CI_GET_PUT_DATA;
+
+typedef struct {
+  BT_HDR hdr;
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  tBTA_HL_STATUS status;
+} tBTA_HL_CI_ECHO_DATA;
+
+/* union of all state machine event data types */
+typedef union {
+  BT_HDR hdr;
+  tBTA_HL_API_ENABLE api_enable; /* data for BTA_MSE_API_ENABLE_EVT */
+  tBTA_HL_API_UPDATE api_update;
+  tBTA_HL_API_REGISTER api_reg;
+  tBTA_HL_API_DEREGISTER api_dereg;
+  tBTA_HL_API_CCH_OPEN api_cch_open;
+  tBTA_HL_API_CCH_CLOSE api_cch_close;
+  tBTA_HL_API_DCH_CREATE_RSP api_dch_create_rsp;
+  tBTA_HL_API_DCH_OPEN api_dch_open;
+  tBTA_HL_API_DCH_RECONNECT api_dch_reconnect;
+  tBTA_HL_API_DCH_CLOSE api_dch_close;
+  tBTA_HL_API_DELETE_MDL api_delete_mdl;
+  tBTA_HL_API_DCH_ABORT api_dch_abort;
+  tBTA_HL_API_SEND_DATA api_send_data;
+  tBTA_HL_API_DCH_ECHO_TEST api_dch_echo_test;
+  tBTA_HL_API_SDP_QUERY api_sdp_query;
+
+  tBTA_HL_CCH_SDP cch_sdp;
+  tBTA_HL_MCA_EVT mca_evt;
+  tBTA_HL_MCA_RCV_DATA_EVT mca_rcv_data_evt;
+  tBTA_HL_DCH_SDP dch_sdp; /* for DCH_OPEN_EVT and DCH_RECONNECT_EVT */
+  tBTA_HL_CI_GET_PUT_DATA ci_get_put_data;
+  tBTA_HL_CI_ECHO_DATA ci_get_put_echo_data;
+} tBTA_HL_DATA;
+
+typedef struct {
+  bool in_use;
+  uint16_t mdl_id;
+  tBTA_HL_MDL_HANDLE mdl_handle;
+  tBTA_HL_DCH_OPER dch_oper;
+  bool intentional_close;
+  tBTA_HL_DCH_STATE dch_state;
+  uint8_t abort_oper;
+  uint16_t req_data_psm;
+  uint16_t max_rx_apdu_size;
+  uint16_t max_tx_apdu_size;
+  BT_HDR* p_tx_pkt;
+  BT_HDR* p_rx_pkt;
+  tBTA_HL_MDEP_ID local_mdep_id;
+  uint8_t local_mdep_cfg_idx;
+  tBTA_HL_DCH_CFG local_cfg;
+  tBTA_HL_DCH_CFG remote_cfg;
+  tBTA_HL_MDEP_ID peer_mdep_id;
+  uint16_t peer_data_type;
+  tBTA_HL_MDEP_ROLE peer_mdep_role;
+  tBTA_HL_DCH_MODE dch_mode;
+  tBTA_SEC sec_mask;
+  bool is_the_first_reliable;
+  bool delete_mdl;
+  uint16_t mtu;
+  tMCA_CHNL_CFG chnl_cfg;
+  bool mdl_cfg_idx_included;
+  uint8_t mdl_cfg_idx;
+  uint8_t echo_oper;
+  bool cong;
+  bool close_pending;
+  uint8_t cout_oper;
+  BT_HDR* p_echo_tx_pkt;
+  BT_HDR* p_echo_rx_pkt;
+  tBTA_HL_STATUS ci_put_echo_data_status;
+} tBTA_HL_MDL_CB;
+
+typedef struct {
+  tBTA_HL_MDL_CB mdl[BTA_HL_NUM_MDLS_PER_MCL];
+  tBTA_HL_DELETE_MDL delete_mdl;
+  bool in_use;
+  tBTA_HL_CCH_STATE cch_state;
+  uint16_t req_ctrl_psm;
+  uint16_t ctrl_psm;
+  uint16_t data_psm;
+  BD_ADDR bd_addr;
+  uint16_t cch_mtu;
+  uint16_t sec_mask;
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  tSDP_DISCOVERY_DB* p_db; /* pointer to discovery database */
+  tSDP_DISC_CMPL_CB* sdp_cback;
+  tBTA_HL_SDP_OPER sdp_oper;
+  bool close_pending;
+  uint8_t sdp_mdl_idx;
+  tBTA_HL_SDP sdp;
+  uint8_t cch_oper;
+  uint8_t force_close_local_cch_opening;
+  bool intentional_close;
+  bool rsp_tout;
+  uint8_t timer_oper;
+  bool echo_test;
+  uint8_t echo_mdl_idx;
+  uint8_t cch_close_dch_oper;
+  uint8_t app_id;
+} tBTA_HL_MCL_CB;
+
+typedef struct {
+  tBTA_HL_MCL_CB mcb[BTA_HL_NUM_MCLS]; /* application Control Blocks */
+  tBTA_HL_CBACK* p_cback; /* pointer to control callback function */
+  bool in_use;            /* this CB is in use*/
+  bool deregistering;
+  uint8_t app_id;
+  uint32_t sdp_handle; /* SDP record handle */
+  tBTA_HL_SUP_FEATURE sup_feature;
+  tBTA_HL_MDL_CFG mdl_cfg[BTA_HL_NUM_MDL_CFGS];
+  tBTA_HL_DEVICE_TYPE dev_type;
+  tBTA_HL_APP_HANDLE app_handle;
+  uint16_t ctrl_psm; /* L2CAP PSM for the MCAP control channel */
+  uint16_t data_psm; /* L2CAP PSM for the MCAP data channel */
+  uint16_t sec_mask; /* Security mask for BTM_SetSecurityLevel() */
+
+  char srv_name[BTA_SERVICE_NAME_LEN +
+                1]; /* service name to be used in the SDP; null terminated*/
+  char srv_desp[BTA_SERVICE_DESP_LEN + 1]; /* service description to be used in
+                                              the SDP; null terminated */
+  char provider_name[BTA_PROVIDER_NAME_LEN + 1]; /* provide name to be used in
+                                                    the SDP; null terminated */
+
+  tMCA_CTRL_CBACK* p_mcap_cback; /* pointer to MCAP callback function */
+  tMCA_DATA_CBACK* p_data_cback;
+} tBTA_HL_APP_CB;
+
+typedef struct {
+  bool in_use;
+  tBTA_HL_SDP_OPER sdp_oper;
+  uint8_t app_idx;
+  uint8_t mcl_idx;
+  uint8_t mdl_idx;
+} tBTA_HL_SDP_CB;
+
+typedef struct {
+  bool in_use;
+  uint8_t app_idx;
+  uint8_t mcl_idx;
+} tBTA_HL_TIMER_CB;
+
+typedef struct {
+  tBTA_HL_APP_CB acb[BTA_HL_NUM_APPS]; /* HL Control Blocks */
+  tBTA_HL_CTRL_CBACK* p_ctrl_cback; /* pointer to control callback function */
+  bool enable;
+  bool disabling;
+
+  tBTA_HL_SDP_CB scb[BTA_HL_NUM_SDP_CBACKS];
+  tBTA_HL_TIMER_CB tcb[BTA_HL_NUM_TIMERS];
+  bool enable_random_psm;
+  tBTA_HL_ALLOCATE_PSM* p_alloc_psm;
+} tBTA_HL_CB;
+
+/******************************************************************************
+ *  Configuration Definitions
+ ******************************************************************************/
+/* Configuration structure */
+
+/*****************************************************************************
+ *  Global data
+ ****************************************************************************/
+
+/* HL control block */
+extern tBTA_HL_CB bta_hl_cb;
+
+#define BTA_HL_GET_CB_PTR() &(bta_hl_cb)
+#define BTA_HL_GET_APP_CB_PTR(app_idx) &(bta_hl_cb.acb[(app_idx)])
+#define BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx) \
+  &(bta_hl_cb.acb[(app_idx)].mcb[(mcl_idx)])
+#define BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx) \
+  &(bta_hl_cb.acb[(app_idx)].mcb[(mcl_idx)].mdl[(mdl_idx)])
+#define BTA_HL_GET_MDL_CFG_PTR(app_idx, item_idx) \
+  &(bta_hl_cb.acb[(app_idx)].mdl_cfg[(item_idx)])
+#define BTA_HL_GET_ECHO_CFG_PTR(app_idx) \
+  &(bta_hl_cb.acb[(app_idx)].sup_feature.echo_cfg)
+#define BTA_HL_GET_MDEP_CFG_PTR(app_idx, mdep_cfg_idx) \
+  &(bta_hl_cb.acb[(app_idx)].sup_feature.mdep[(mdep_cfg_idx)].mdep_cfg)
+#define BTA_HL_GET_DATA_CFG_PTR(app_idx, mdep_cfg_idx, data_cfg_idx) \
+  &(bta_hl_cb.acb[(app_idx)]                                         \
+        .sup_feature.mdep[(mdep_cfg_idx)]                            \
+        .mdep_cfg.data_cfg[(data_cfg_idx)])
+#define BTA_HL_GET_BUF_PTR(p_pkt) \
+  ((uint8_t*)((uint8_t*)((p_pkt) + 1) + (p_pkt)->offset))
+
+/*****************************************************************************
+ *  Function prototypes
+ ****************************************************************************/
+/* main */
+extern bool bta_hl_hdl_event(BT_HDR* p_msg);
+/* sdp */
+extern bool bta_hl_fill_sup_feature_list(const tSDP_DISC_ATTR* p_attr,
+                                         tBTA_HL_SUP_FEATURE_LIST_ELEM* p_list);
+extern tBTA_HL_STATUS bta_hl_sdp_update(uint8_t app_id);
+extern tBTA_HL_STATUS bta_hl_sdp_register(uint8_t app_idx);
+extern tSDP_DISC_REC* bta_hl_find_sink_or_src_srv_class_in_db(
+    const tSDP_DISCOVERY_DB* p_db, const tSDP_DISC_REC* p_start_rec);
+
+/* action routines */
+extern void bta_hl_dch_ci_get_tx_data(uint8_t app_idx, uint8_t mcl_idx,
+                                      uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_ci_put_rx_data(uint8_t app_idx, uint8_t mcl_idx,
+                                      uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_ci_get_echo_data(uint8_t app_idx, uint8_t mcl_idx,
+                                        uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+
+extern void bta_hl_dch_echo_test(uint8_t app_idx, uint8_t mcl_idx,
+                                 uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_ci_put_echo_data(uint8_t app_idx, uint8_t mcl_idx,
+                                        uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_send_data(uint8_t app_idx, uint8_t mcl_idx,
+                                 uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_sdp_fail(uint8_t app_idx, uint8_t mcl_idx,
+                                uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_cong_change(uint8_t app_idx, uint8_t mcl_idx,
+                                       uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_reconnect_ind(uint8_t app_idx, uint8_t mcl_idx,
+                                         uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_reconnect_cfm(uint8_t app_idx, uint8_t mcl_idx,
+                                         uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_reconnect(uint8_t app_idx, uint8_t mcl_idx,
+                                     uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_sdp_init(uint8_t app_idx, uint8_t mcl_idx,
+                                uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_close_echo_test(uint8_t app_idx, uint8_t mcl_idx,
+                                       uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_create_rsp(uint8_t app_idx, uint8_t mcl_idx,
+                                  uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_rcv_data(uint8_t app_idx, uint8_t mcl_idx,
+                                    uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_close_cmpl(uint8_t app_idx, uint8_t mcl_idx,
+                                  uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_close_cfm(uint8_t app_idx, uint8_t mcl_idx,
+                                     uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_close_ind(uint8_t app_idx, uint8_t mcl_idx,
+                                     uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_close(uint8_t app_idx, uint8_t mcl_idx,
+                                 uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_delete_ind(uint8_t app_idx, uint8_t mcl_idx,
+                                      uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+
+extern void bta_hl_dch_mca_delete_cfm(uint8_t app_idx, uint8_t mcl_idx,
+                                      uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_delete(uint8_t app_idx, uint8_t mcl_idx,
+                                  uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_abort_ind(uint8_t app_idx, uint8_t mcl_idx,
+                                     uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_abort_cfm(uint8_t app_idx, uint8_t mcl_idx,
+                                     uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_abort(uint8_t app_idx, uint8_t mcl_idx,
+                                 uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_open_ind(uint8_t app_idx, uint8_t mcl_idx,
+                                    uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_open_cfm(uint8_t app_idx, uint8_t mcl_idx,
+                                    uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_create_ind(uint8_t app_idx, uint8_t mcl_idx,
+                                      uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_create_cfm(uint8_t app_idx, uint8_t mcl_idx,
+                                      uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_create(uint8_t app_idx, uint8_t mcl_idx,
+                                  uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_deallocate_spd_cback(uint8_t sdp_cback_idx);
+extern tSDP_DISC_CMPL_CB* bta_hl_allocate_spd_cback(tBTA_HL_SDP_OPER sdp_oper,
+                                                    uint8_t app_idx,
+                                                    uint8_t mcl_idx,
+                                                    uint8_t mdl_idx,
+                                                    uint8_t* p_sdp_cback_idx);
+extern tBTA_HL_STATUS bta_hl_init_sdp(tBTA_HL_SDP_OPER sdp_oper,
+                                      uint8_t app_idx, uint8_t mcl_idx,
+                                      uint8_t mdl_idx);
+extern void bta_hl_cch_sdp_init(uint8_t app_idx, uint8_t mcl_idx,
+                                tBTA_HL_DATA* p_data);
+extern void bta_hl_cch_mca_open(uint8_t app_idx, uint8_t mcl_idx,
+                                tBTA_HL_DATA* p_data);
+extern void bta_hl_cch_mca_close(uint8_t app_idx, uint8_t mcl_idx,
+                                 tBTA_HL_DATA* p_data);
+extern void bta_hl_cch_close_cmpl(uint8_t app_idx, uint8_t mcl_idx,
+                                  tBTA_HL_DATA* p_data);
+extern void bta_hl_cch_mca_disconnect(uint8_t app_idx, uint8_t mcl_idx,
+                                      tBTA_HL_DATA* p_data);
+extern void bta_hl_cch_mca_disc_open(uint8_t app_idx, uint8_t mcl_idx,
+                                     tBTA_HL_DATA* p_data);
+extern void bta_hl_cch_mca_rsp_tout(uint8_t app_idx, uint8_t mcl_idx,
+                                    tBTA_HL_DATA* p_data);
+extern void bta_hl_cch_mca_connect(uint8_t app_idx, uint8_t mcl_idx,
+                                   tBTA_HL_DATA* p_data);
+
+/* State machine drivers  */
+extern void bta_hl_cch_sm_execute(uint8_t inst_idx, uint8_t mcl_idx,
+                                  uint16_t event, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_sm_execute(uint8_t inst_idx, uint8_t mcl_idx,
+                                  uint8_t mdl_idx, uint16_t event,
+                                  tBTA_HL_DATA* p_data);
+/* MCAP callback functions  */
+extern void bta_hl_mcap_ctrl_cback(tMCA_HANDLE handle, tMCA_CL mcl,
+                                   uint8_t event, tMCA_CTRL* p_data);
+
+extern void bta_hl_mcap_data_cback(tMCA_DL mdl, BT_HDR* p_pkt);
+
+/* utility functions  */
+extern bool bta_hl_set_ctrl_psm_for_dch(uint8_t app_idx, uint8_t mcl_idx,
+                                        uint8_t mdl_idx, uint16_t ctrl_psm);
+extern bool bta_hl_find_sdp_idx_using_ctrl_psm(tBTA_HL_SDP* p_sdp,
+                                               uint16_t ctrl_psm,
+                                               uint8_t* p_sdp_idx);
+extern uint16_t bta_hl_set_user_tx_buf_size(uint16_t max_tx_size);
+extern uint16_t bta_hl_set_user_rx_buf_size(uint16_t mtu);
+extern uint8_t bta_hl_set_tx_win_size(uint16_t mtu, uint16_t mps);
+extern uint16_t bta_hl_set_mps(uint16_t mtu);
+extern void bta_hl_clean_mdl_cb(uint8_t app_idx, uint8_t mcl_idx,
+                                uint8_t mdl_idx);
+extern BT_HDR* bta_hl_get_buf(uint16_t data_size, bool fcs_use);
+extern bool bta_hl_find_service_in_db(uint8_t app_idx, uint8_t mcl_idx,
+                                      uint16_t service_uuid,
+                                      tSDP_DISC_REC** pp_rec);
+extern uint16_t bta_hl_get_service_uuids(uint8_t sdp_oper, uint8_t app_idx,
+                                         uint8_t mcl_idx, uint8_t mdl_idx);
+extern bool bta_hl_find_echo_cfg_rsp(uint8_t app_idx, uint8_t mcl_idx,
+                                     uint8_t mdep_idx, uint8_t cfg,
+                                     uint8_t* p_cfg_rsp);
+extern bool bta_hl_validate_cfg(uint8_t app_idx, uint8_t mcl_idx,
+                                uint8_t mdl_idx, uint8_t cfg);
+extern bool bta_hl_find_cch_cb_indexes(tBTA_HL_DATA* p_msg, uint8_t* p_app_idx,
+                                       uint8_t* p_mcl_idx);
+extern bool bta_hl_find_dch_cb_indexes(tBTA_HL_DATA* p_msg, uint8_t* p_app_idx,
+                                       uint8_t* p_mcl_idx, uint8_t* p_mdl_idx);
+extern uint16_t bta_hl_allocate_mdl_id(uint8_t app_idx, uint8_t mcl_idx,
+                                       uint8_t mdl_idx);
+extern bool bta_hl_find_mdl_idx_using_handle(tBTA_HL_MDL_HANDLE mdl_handle,
+                                             uint8_t* p_app_idx,
+                                             uint8_t* p_mcl_idx,
+                                             uint8_t* p_mdl_idx);
+extern bool bta_hl_find_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
+                                uint16_t mdl_id, uint8_t* p_mdl_idx);
+extern bool bta_hl_find_an_active_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
+                                          uint8_t* p_mdl_idx);
+extern bool bta_hl_find_dch_setup_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
+                                          uint8_t* p_mdl_idx);
+extern bool bta_hl_find_an_in_use_mcl_idx(uint8_t app_idx, uint8_t* p_mcl_idx);
+extern bool bta_hl_find_an_in_use_app_idx(uint8_t* p_app_idx);
+extern bool bta_hl_find_app_idx(uint8_t app_id, uint8_t* p_app_idx);
+extern bool bta_hl_find_app_idx_using_handle(tBTA_HL_APP_HANDLE app_handle,
+                                             uint8_t* p_app_idx);
+extern bool bta_hl_find_mcl_idx_using_handle(tBTA_HL_MCL_HANDLE mcl_handle,
+                                             uint8_t* p_app_idx,
+                                             uint8_t* p_mcl_idx);
+extern bool bta_hl_find_mcl_idx(uint8_t app_idx, BD_ADDR p_bd_addr,
+                                uint8_t* p_mcl_idx);
+extern bool bta_hl_is_the_first_reliable_existed(uint8_t app_idx,
+                                                 uint8_t mcl_idx);
+extern bool bta_hl_find_non_active_mdl_cfg(uint8_t app_idx,
+                                           uint8_t start_mdl_cfg_idx,
+                                           uint8_t* p_mdl_cfg_idx);
+extern bool bta_hl_find_avail_mdl_cfg_idx(uint8_t app_idx, uint8_t mcl_idx,
+                                          uint8_t* p_mdl_cfg_idx);
+extern bool bta_hl_find_mdl_cfg_idx(uint8_t app_idx, uint8_t mcl_idx,
+                                    tBTA_HL_MDL_ID mdl_id,
+                                    uint8_t* p_mdl_cfg_idx);
+extern bool bta_hl_get_cur_time(uint8_t app_idx, uint8_t* p_cur_time);
+extern void bta_hl_sort_cfg_time_idx(uint8_t app_idx, uint8_t* a, uint8_t n);
+extern void bta_hl_compact_mdl_cfg_time(uint8_t app_idx, uint8_t mdep_id);
+extern bool bta_hl_is_mdl_exsit_in_mcl(uint8_t app_idx, BD_ADDR bd_addr,
+                                       tBTA_HL_MDL_ID mdl_id);
+extern bool bta_hl_delete_mdl_cfg(uint8_t app_idx, BD_ADDR bd_addr,
+                                  tBTA_HL_MDL_ID mdl_id);
+extern bool bta_hl_is_mdl_value_valid(tBTA_HL_MDL_ID mdl_id);
+extern bool bta_hl_find_mdep_cfg_idx(uint8_t app_idx,
+                                     tBTA_HL_MDEP_ID local_mdep_id,
+                                     uint8_t* p_mdep_cfg_idx);
+extern void bta_hl_find_rxtx_apdu_size(uint8_t app_idx, uint8_t mdep_cfg_idx,
+                                       uint16_t* p_rx_apu_size,
+                                       uint16_t* p_tx_apu_size);
+extern bool bta_hl_validate_peer_cfg(uint8_t app_idx, uint8_t mcl_idx,
+                                     uint8_t mdl_idx,
+                                     tBTA_HL_MDEP_ID peer_mdep_id,
+                                     tBTA_HL_MDEP_ROLE peer_mdep_role,
+                                     uint8_t sdp_idx);
+extern tBTA_HL_STATUS bta_hl_chk_local_cfg(uint8_t app_idx, uint8_t mcl_idx,
+                                           uint8_t mdep_cfg_idx,
+                                           tBTA_HL_DCH_CFG local_cfg);
+
+extern bool bta_hl_validate_reconnect_params(
+    uint8_t app_idx, uint8_t mcl_idx, tBTA_HL_API_DCH_RECONNECT* p_reconnect,
+    uint8_t* p_mdep_cfg_idx, uint8_t* p_mdl_cfg_idx);
+extern bool bta_hl_find_avail_mcl_idx(uint8_t app_idx, uint8_t* p_mcl_idx);
+extern bool bta_hl_find_avail_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
+                                      uint8_t* p_mdl_idx);
+extern bool bta_hl_is_a_duplicate_id(uint8_t app_id);
+extern bool bta_hl_find_avail_app_idx(uint8_t* p_idx);
+extern tBTA_HL_STATUS bta_hl_app_update(uint8_t app_id, bool is_register);
+extern tBTA_HL_STATUS bta_hl_app_registration(uint8_t app_idx);
+extern void bta_hl_discard_data(uint16_t event, tBTA_HL_DATA* p_data);
+extern void bta_hl_save_mdl_cfg(uint8_t app_idx, uint8_t mcl_idx,
+                                uint8_t mdl_idx);
+extern void bta_hl_set_dch_chan_cfg(uint8_t app_idx, uint8_t mcl_idx,
+                                    uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern bool bta_hl_get_l2cap_cfg(tBTA_HL_MDL_HANDLE mdl_hnd,
+                                 tBTA_HL_L2CAP_CFG_INFO* p_cfg);
+extern bool bta_hl_validate_chan_cfg(uint8_t app_idx, uint8_t mcl_idx,
+                                     uint8_t mdl_idx);
+extern bool bta_hl_is_cong_on(uint8_t app_id, BD_ADDR bd_addr,
+                              tBTA_HL_MDL_ID mdl_id);
+extern void bta_hl_check_cch_close(uint8_t app_idx, uint8_t mcl_idx,
+                                   tBTA_HL_DATA* p_data, bool check_dch_setup);
+extern void bta_hl_clean_app(uint8_t app_idx);
+extern void bta_hl_check_deregistration(uint8_t app_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_check_disable(tBTA_HL_DATA* p_data);
+extern void bta_hl_build_abort_ind(tBTA_HL* p_evt_data,
+                                   tBTA_HL_APP_HANDLE app_handle,
+                                   tBTA_HL_MCL_HANDLE mcl_handle);
+extern void bta_hl_build_abort_cfm(tBTA_HL* p_evt_data,
+                                   tBTA_HL_APP_HANDLE app_handle,
+                                   tBTA_HL_MCL_HANDLE mcl_handle,
+                                   tBTA_HL_STATUS status);
+extern void bta_hl_build_dch_close_cfm(tBTA_HL* p_evt_data,
+                                       tBTA_HL_APP_HANDLE app_handle,
+                                       tBTA_HL_MCL_HANDLE mcl_handle,
+                                       tBTA_HL_MDL_HANDLE mdl_handle,
+                                       tBTA_HL_STATUS status);
+extern void bta_hl_build_dch_close_ind(tBTA_HL* p_evt_data,
+                                       tBTA_HL_APP_HANDLE app_handle,
+                                       tBTA_HL_MCL_HANDLE mcl_handle,
+                                       tBTA_HL_MDL_HANDLE mdl_handle,
+                                       bool intentional);
+extern void bta_hl_build_send_data_cfm(tBTA_HL* p_evt_data,
+                                       tBTA_HL_APP_HANDLE app_handle,
+                                       tBTA_HL_MCL_HANDLE mcl_handle,
+                                       tBTA_HL_MDL_HANDLE mdl_handle,
+                                       tBTA_HL_STATUS status);
+extern void bta_hl_build_rcv_data_ind(tBTA_HL* p_evt_data,
+                                      tBTA_HL_APP_HANDLE app_handle,
+                                      tBTA_HL_MCL_HANDLE mcl_handle,
+                                      tBTA_HL_MDL_HANDLE mdl_handle);
+extern void bta_hl_build_cch_open_cfm(tBTA_HL* p_evt_data, uint8_t app_id,
+                                      tBTA_HL_APP_HANDLE app_handle,
+                                      tBTA_HL_MCL_HANDLE mcl_handle,
+                                      BD_ADDR bd_addr, tBTA_HL_STATUS status);
+extern void bta_hl_build_cch_open_ind(tBTA_HL* p_evt_data,
+                                      tBTA_HL_APP_HANDLE app_handle,
+                                      tBTA_HL_MCL_HANDLE mcl_handle,
+                                      BD_ADDR bd_addr);
+extern void bta_hl_build_cch_close_cfm(tBTA_HL* p_evt_data,
+                                       tBTA_HL_APP_HANDLE app_handle,
+                                       tBTA_HL_MCL_HANDLE mcl_handle,
+                                       tBTA_HL_STATUS status);
+extern void bta_hl_build_cch_close_ind(tBTA_HL* p_evt_data,
+                                       tBTA_HL_APP_HANDLE app_handle,
+                                       tBTA_HL_MCL_HANDLE mcl_handle,
+                                       bool intentional);
+
+extern void bta_hl_build_dch_open_cfm(
+    tBTA_HL* p_evt_data, tBTA_HL_APP_HANDLE app_handle,
+    tBTA_HL_MCL_HANDLE mcl_handle, tBTA_HL_MDL_HANDLE mdl_handle,
+    tBTA_HL_MDEP_ID local_mdep_id, tBTA_HL_MDL_ID mdl_id,
+    tBTA_HL_DCH_MODE dch_mode, bool first_reliable, uint16_t mtu,
+    tBTA_HL_STATUS status);
+
+extern void bta_hl_build_delete_mdl_cfm(tBTA_HL* p_evt_data,
+                                        tBTA_HL_APP_HANDLE app_handle,
+                                        tBTA_HL_MCL_HANDLE mcl_handle,
+                                        tBTA_HL_MDL_ID mdl_id,
+                                        tBTA_HL_STATUS status);
+extern void bta_hl_build_echo_test_cfm(tBTA_HL* p_evt_data,
+                                       tBTA_HL_APP_HANDLE app_handle,
+                                       tBTA_HL_MCL_HANDLE mcl_handle,
+                                       tBTA_HL_STATUS status);
+extern void bta_hl_build_sdp_query_cfm(tBTA_HL* p_evt_data, uint8_t app_id,
+                                       tBTA_HL_APP_HANDLE app_handle,
+                                       BD_ADDR bd_addr, tBTA_HL_SDP* p_sdp,
+                                       tBTA_HL_STATUS status);
+
+#if (BTA_HL_DEBUG == TRUE)
+extern const char* bta_hl_status_code(tBTA_HL_STATUS status);
+extern const char* bta_hl_evt_code(tBTA_HL_INT_EVT evt_code);
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif /* BTA_MSE_INT_H */
diff --git a/bt/bta/hl/bta_hl_main.cc b/bt/bta/hl/bta_hl_main.cc
new file mode 100644
index 0000000..6f15338
--- /dev/null
+++ b/bt/bta/hl/bta_hl_main.cc
@@ -0,0 +1,1869 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1998-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 HeaLth device profile main functions and state
+ *  machine.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#if (HL_INCLUDED == TRUE)
+
+#include "bt_common.h"
+#include "bta_hl_api.h"
+#include "bta_hl_int.h"
+#include "l2c_api.h"
+#include "mca_defs.h"
+#include "osi/include/osi.h"
+#include "utl.h"
+
+#if (BTA_HL_DEBUG == TRUE)
+static const char* bta_hl_cch_state_code(tBTA_HL_CCH_STATE state_code);
+static const char* bta_hl_dch_state_code(tBTA_HL_DCH_STATE state_code);
+#endif
+
+extern uint16_t L2CA_AllocateRandomPsm(void);
+extern uint16_t L2CA_AllocatePsm(void);
+/*****************************************************************************
+ * DCH State Table
+ ****************************************************************************/
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+/* state machine action enumeration list for DCH */
+/* The order of this enumeration must be the same as bta_hl_dch_act_tbl[] */
+enum {
+  BTA_HL_DCH_MCA_CREATE,
+  BTA_HL_DCH_MCA_CREATE_CFM,
+  BTA_HL_DCH_MCA_CREATE_IND,
+  BTA_HL_DCH_MCA_OPEN_CFM,
+  BTA_HL_DCH_MCA_OPEN_IND,
+  BTA_HL_DCH_MCA_CLOSE,
+  BTA_HL_DCH_MCA_CLOSE_CFM,
+  BTA_HL_DCH_MCA_CLOSE_IND,
+  BTA_HL_DCH_CLOSE_CMPL,
+  BTA_HL_DCH_MCA_RCV_DATA,
+
+  BTA_HL_DCH_SDP_INIT,
+  BTA_HL_DCH_MCA_RECONNECT,
+  BTA_HL_DCH_MCA_RECONNECT_IND,
+  BTA_HL_DCH_MCA_RECONNECT_CFM,
+  BTA_HL_DCH_CLOSE_ECHO_TEST,
+  BTA_HL_DCH_CREATE_RSP,
+  BTA_HL_DCH_MCA_ABORT,
+  BTA_HL_DCH_MCA_ABORT_IND,
+  BTA_HL_DCH_MCA_ABORT_CFM,
+  BTA_HL_DCH_MCA_CONG_CHANGE,
+
+  BTA_HL_DCH_SDP_FAIL,
+  BTA_HL_DCH_SEND_DATA,
+  BTA_HL_DCH_CI_GET_TX_DATA,
+  BTA_HL_DCH_CI_PUT_RX_DATA,
+  BTA_HL_DCH_CI_GET_ECHO_DATA,
+  BTA_HL_DCH_ECHO_TEST,
+  BTA_HL_DCH_CI_PUT_ECHO_DATA,
+  BTA_HL_DCH_IGNORE
+};
+
+typedef void (*tBTA_HL_DCH_ACTION)(uint8_t app_idx, uint8_t mcl_idx,
+                                   uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+
+static const tBTA_HL_DCH_ACTION bta_hl_dch_action[] = {
+    bta_hl_dch_mca_create,        bta_hl_dch_mca_create_cfm,
+    bta_hl_dch_mca_create_ind,    bta_hl_dch_mca_open_cfm,
+    bta_hl_dch_mca_open_ind,      bta_hl_dch_mca_close,
+    bta_hl_dch_mca_close_cfm,     bta_hl_dch_mca_close_ind,
+    bta_hl_dch_close_cmpl,        bta_hl_dch_mca_rcv_data,
+
+    bta_hl_dch_sdp_init,          bta_hl_dch_mca_reconnect,
+    bta_hl_dch_mca_reconnect_ind, bta_hl_dch_mca_reconnect_cfm,
+    bta_hl_dch_close_echo_test,   bta_hl_dch_create_rsp,
+    bta_hl_dch_mca_abort,         bta_hl_dch_mca_abort_ind,
+    bta_hl_dch_mca_abort_cfm,     bta_hl_dch_mca_cong_change,
+
+    bta_hl_dch_sdp_fail,          bta_hl_dch_send_data,
+    bta_hl_dch_ci_get_tx_data,    bta_hl_dch_ci_put_rx_data,
+    bta_hl_dch_ci_get_echo_data,  bta_hl_dch_echo_test,
+    bta_hl_dch_ci_put_echo_data,
+};
+
+/* state table information */
+#define BTA_HL_DCH_ACTIONS 1    /* number of actions */
+#define BTA_HL_DCH_ACTION_COL 0 /* position of action */
+#define BTA_HL_DCH_NEXT_STATE 1 /* position of next state */
+#define BTA_HL_DCH_NUM_COLS 2   /* number of columns in state tables */
+
+/* state table for idle state */
+static const uint8_t bta_hl_dch_st_idle[][BTA_HL_DCH_NUM_COLS] = {
+    /* Event                                Action 1                    Next
+       state */
+    /* BTA_HL_DCH_SDP_INIT_EVT   */ {BTA_HL_DCH_SDP_INIT,
+                                     BTA_HL_DCH_OPENING_ST},
+    /* BTA_HL_DCH_OPEN_EVT       */ {BTA_HL_DCH_MCA_CREATE,
+                                     BTA_HL_DCH_OPENING_ST},
+    /* BTA_HL_MCA_CREATE_IND_EVT */ {BTA_HL_DCH_MCA_CREATE_IND,
+                                     BTA_HL_DCH_OPENING_ST},
+    /* BTA_HL_MCA_CREATE_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+    /* BTA_HL_MCA_OPEN_IND_EVT   */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+
+    /* BTA_HL_MCA_OPEN_CFM_EVT   */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+    /* BTA_HL_DCH_CLOSE_EVT      */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+    /* BTA_HL_MCA_CLOSE_IND_EVT  */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+    /* BTA_HL_MCA_CLOSE_CFM_EVT  */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+    /* BTA_HL_API_SEND_DATA_EVT  */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+
+    /* BTA_HL_MCA_RCV_DATA_EVT   */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+    /* BTA_HL_DCH_CLOSE_CMPL_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+    /* BTA_HL_DCH_RECONNECT_EVT  */ {BTA_HL_DCH_MCA_RECONNECT,
+                                     BTA_HL_DCH_OPENING_ST},
+    /* BTA_HL_DCH_SDP_FAIL_EVT   */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+    /* BTA_HL_MCA_RECONNECT_IND_EVT*/ {BTA_HL_DCH_MCA_RECONNECT_IND,
+                                       BTA_HL_DCH_OPENING_ST},
+
+    /* BTA_HL_MCA_RECONNECT_CFM_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+    /* BTA_HL_DCH_CLOSE_ECHO_TEST_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+    /* BTA_HL_API_DCH_CREATE_RSP_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+    /* BTA_HL_DCH_ABORT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+    /* BTA_HL_MCA_ABORT_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+
+    /* BTA_HL_MCA_ABORT_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+    /* BTA_HL_MCA_CONG_CHG_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+    /* BTA_HL_CI_GET_TX_DATA_EVT  */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+    /* BTA_HL_CI_PUT_RX_DATA_EVT  */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+    /* BTA_HL_CI_GET_ECHO_DATA_EVT  */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+    /* BTA_HL_DCH_ECHO_TEST_EVT  */ {BTA_HL_DCH_ECHO_TEST,
+                                     BTA_HL_DCH_OPENING_ST},
+    /* BTA_HL_CI_PUT_ECHO_DATA_EVT  */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}};
+
+/* state table for opening state */
+static const uint8_t bta_hl_dch_st_opening[][BTA_HL_DCH_NUM_COLS] = {
+    /* Event                                Action 1                    Next
+       state */
+    /* BTA_HL_DCH_SDP_INIT_EVT   */ {BTA_HL_DCH_SDP_INIT,
+                                     BTA_HL_DCH_OPENING_ST},
+    /* BTA_HL_DCH_OPEN_EVT       */ {BTA_HL_DCH_MCA_CREATE,
+                                     BTA_HL_DCH_OPENING_ST},
+    /* BTA_HL_MCA_CREATE_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST},
+    /* BTA_HL_MCA_CREATE_CFM_EVT */ {BTA_HL_DCH_MCA_CREATE_CFM,
+                                     BTA_HL_DCH_OPENING_ST},
+    /* BTA_HL_MCA_OPEN_IND_EVT   */ {BTA_HL_DCH_MCA_OPEN_IND,
+                                     BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_MCA_OPEN_CFM_EVT   */ {BTA_HL_DCH_MCA_OPEN_CFM,
+                                     BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_DCH_CLOSE_EVT      */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST},
+    /* BTA_HL_MCA_CLOSE_IND_EVT  */ {BTA_HL_DCH_MCA_CLOSE_IND,
+                                     BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_MCA_CLOSE_CFM_EVT  */ {BTA_HL_DCH_MCA_CLOSE_CFM,
+                                     BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_API_SEND_DATA_EVT  */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+
+    /* BTA_HL_MCA_RCV_DATA_EVT   */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_DCH_CLOSE_CMPL_EVT */ {BTA_HL_DCH_CLOSE_CMPL, BTA_HL_DCH_IDLE_ST},
+    /* BTA_HL_DCH_RECONNECT_EVT  */ {BTA_HL_DCH_MCA_RECONNECT,
+                                     BTA_HL_DCH_OPENING_ST},
+    /* BTA_HL_DCH_SDP_FAIL_EVT   */ {BTA_HL_DCH_SDP_FAIL,
+                                     BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_MCA_RECONNECT_IND_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+    /* BTA_HL_MCA_RECONNECT_CFM_EVT*/ {BTA_HL_DCH_MCA_RECONNECT_CFM,
+                                       BTA_HL_DCH_OPENING_ST},
+    /* BTA_HL_DCH_CLOSE_ECHO_TEST_EVT*/ {BTA_HL_DCH_IGNORE,
+                                         BTA_HL_DCH_OPENING_ST},
+    /* BTA_HL_API_DCH_CREATE_RSP_EVT */ {BTA_HL_DCH_CREATE_RSP,
+                                         BTA_HL_DCH_OPENING_ST},
+    /* BTA_HL_DCH_ABORT_EVT */ {BTA_HL_DCH_MCA_ABORT, BTA_HL_DCH_OPENING_ST},
+    /* BTA_HL_MCA_ABORT_IND_EVT */ {BTA_HL_DCH_MCA_ABORT_IND,
+                                    BTA_HL_DCH_OPENING_ST},
+
+    /* BTA_HL_MCA_ABORT_CFM_EVT */ {BTA_HL_DCH_MCA_ABORT_CFM,
+                                    BTA_HL_DCH_OPENING_ST},
+    /* BTA_HL_MCA_CONG_CHG_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST},
+    /* BTA_HL_CI_GET_TX_DATA_EVT  */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST},
+    /* BTA_HL_CI_PUT_RX_DATA_EVT  */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST},
+    /* BTA_HL_CI_GET_ECHO_DATA_EVT  */ {BTA_HL_DCH_CI_GET_ECHO_DATA,
+                                        BTA_HL_DCH_OPENING_ST},
+    /* BTA_HL_DCH_ECHO_TEST_EVT  */ {BTA_HL_DCH_ECHO_TEST,
+                                     BTA_HL_DCH_OPENING_ST},
+    /* BTA_HL_CI_PUT_ECHO_DATA_EVT  */ {BTA_HL_DCH_IGNORE,
+                                        BTA_HL_DCH_OPENING_ST}};
+
+/* state table for open state */
+static const uint8_t bta_hl_dch_st_open[][BTA_HL_DCH_NUM_COLS] = {
+    /* Event                                Action 1                  Next
+       state */
+    /* BTA_HL_DCH_SDP_INIT_EVT   */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_DCH_OPEN_EVT       */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_MCA_CREATE_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_MCA_CREATE_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_MCA_OPEN_IND_EVT   */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_MCA_OPEN_CFM_EVT   */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_DCH_CLOSE_EVT      */ {BTA_HL_DCH_MCA_CLOSE,
+                                     BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_MCA_CLOSE_IND_EVT  */ {BTA_HL_DCH_MCA_CLOSE_IND,
+                                     BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_MCA_CLOSE_CFM_EVT  */ {BTA_HL_DCH_MCA_CLOSE_CFM,
+                                     BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_API_SEND_DATA_EVT  */ {BTA_HL_DCH_SEND_DATA, BTA_HL_DCH_OPEN_ST},
+
+    /* BTA_HL_MCA_RCV_DATA_EVT   */ {BTA_HL_DCH_MCA_RCV_DATA,
+                                     BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_DCH_CLOSE_CMPL_EVT */ {BTA_HL_DCH_CLOSE_CMPL, BTA_HL_DCH_IDLE_ST},
+    /* BTA_HL_DCH_RECONNECT_EVT  */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_DCH_SDP_FAIL_EVT   */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_MCA_RECONNECT_IND_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_MCA_RECONNECT_CFM_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_DCH_CLOSE_ECHO_TEST_EVT*/ {BTA_HL_DCH_CLOSE_ECHO_TEST,
+                                         BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_API_DCH_CREATE_RSP_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_DCH_ABORT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_MCA_ABORT_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+
+    /* BTA_HL_DCH_ABORT_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_MCA_CONG_CHG_EVT */ {BTA_HL_DCH_MCA_CONG_CHANGE,
+                                   BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_CI_GET_TX_DATA_EVT  */ {BTA_HL_DCH_CI_GET_TX_DATA,
+                                      BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_CI_PUT_RX_DATA_EVT  */ {BTA_HL_DCH_CI_PUT_RX_DATA,
+                                      BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_CI_GET_ECHO_DATA_EVT  */ {BTA_HL_DCH_CI_GET_ECHO_DATA,
+                                        BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_DCH_ECHO_TEST_EVT  */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+    /* BTA_HL_CI_PUT_ECHO_DATA_EVT  */ {BTA_HL_DCH_CI_PUT_ECHO_DATA,
+                                        BTA_HL_DCH_OPEN_ST}};
+
+/* state table for closing state */
+static const uint8_t bta_hl_dch_st_closing[][BTA_HL_DCH_NUM_COLS] = {
+    /* Event                                Action 1 Next state */
+    /* BTA_HL_DCH_SDP_INIT_EVT   */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_DCH_OPEN_EVT       */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_MCA_CREATE_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_MCA_CREATE_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_MCA_OPEN_IND_EVT   */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_MCA_OPEN_CFM_EVT   */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_DCH_CLOSE_EVT      */ {BTA_HL_DCH_MCA_CLOSE,
+                                     BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_MCA_CLOSE_IND_EVT  */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_MCA_CLOSE_CFM_EVT  */ {BTA_HL_DCH_MCA_CLOSE_CFM,
+                                     BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_API_SEND_DATA_EVT  */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+
+    /* BTA_HL_MCA_RCV_DATA_EVT   */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_DCH_CLOSE_CMPL_EVT */ {BTA_HL_DCH_CLOSE_CMPL, BTA_HL_DCH_IDLE_ST},
+    /* BTA_HL_DCH_RECONNECT_EVT  */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_DCH_SDP_FAIL_EVT   */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_MCA_RECONNECT_IND_EVT*/ {BTA_HL_DCH_IGNORE,
+                                       BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_MCA_RECONNECT_CFM_EVT*/ {BTA_HL_DCH_IGNORE,
+                                       BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_DCH_CLOSE_ECHO_TEST_EVT*/ {BTA_HL_DCH_IGNORE,
+                                         BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_API_DCH_CREATE_RSP_EVT */ {BTA_HL_DCH_IGNORE,
+                                         BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_DCH_ABORT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_MCA_ABORT_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+
+    /* BTA_HL_DCH_ABORT_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_MCA_CONG_CHG_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_CI_GET_TX_DATA_EVT  */ {BTA_HL_DCH_CI_GET_TX_DATA,
+                                      BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_CI_PUT_RX_DATA_EVT  */ {BTA_HL_DCH_CI_PUT_RX_DATA,
+                                      BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_CI_GET_ECHO_DATA_EVT  */ {BTA_HL_DCH_CI_GET_ECHO_DATA,
+                                        BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_DCH_ECHO_TEST_EVT  */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+    /* BTA_HL_CI_PUT_ECHO_DATA_EVT  */ {BTA_HL_DCH_CI_PUT_ECHO_DATA,
+                                        BTA_HL_DCH_CLOSING_ST}};
+
+/* type for state table */
+typedef const uint8_t (*tBTA_HL_DCH_ST_TBL)[BTA_HL_DCH_NUM_COLS];
+
+/* state table */
+const tBTA_HL_DCH_ST_TBL bta_hl_dch_st_tbl[] = {
+    bta_hl_dch_st_idle, bta_hl_dch_st_opening, bta_hl_dch_st_open,
+    bta_hl_dch_st_closing};
+
+/*****************************************************************************
+ * CCH State Table
+ ****************************************************************************/
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+/* state machine action enumeration list for CCH */
+enum {
+  BTA_HL_CCH_SDP_INIT,
+  BTA_HL_CCH_MCA_OPEN,
+  BTA_HL_CCH_MCA_CLOSE,
+  BTA_HL_CCH_CLOSE_CMPL,
+  BTA_HL_CCH_MCA_CONNECT,
+  BTA_HL_CCH_MCA_DISCONNECT,
+  BTA_HL_CCH_MCA_RSP_TOUT,
+  BTA_HL_CCH_MCA_DISC_OPEN,
+  BTA_HL_CCH_IGNORE
+};
+
+/* type for action functions */
+typedef void (*tBTA_HL_CCH_ACTION)(uint8_t app_idx, uint8_t mcl_idx,
+                                   tBTA_HL_DATA* p_data);
+
+/* action function list for MAS */
+const tBTA_HL_CCH_ACTION bta_hl_cch_action[] = {
+    bta_hl_cch_sdp_init,     bta_hl_cch_mca_open,     bta_hl_cch_mca_close,
+    bta_hl_cch_close_cmpl,   bta_hl_cch_mca_connect,  bta_hl_cch_mca_disconnect,
+    bta_hl_cch_mca_rsp_tout, bta_hl_cch_mca_disc_open};
+
+/* state table information */
+#define BTA_HL_CCH_ACTIONS 1    /* number of actions */
+#define BTA_HL_CCH_NEXT_STATE 1 /* position of next state */
+#define BTA_HL_CCH_NUM_COLS 2   /* number of columns in state tables */
+
+/* state table for MAS idle state */
+static const uint8_t bta_hl_cch_st_idle[][BTA_HL_CCH_NUM_COLS] = {
+    /* Event                          Action 1                  Next state */
+    /* BTA_HL_CCH_OPEN_EVT           */ {BTA_HL_CCH_SDP_INIT,
+                                         BTA_HL_CCH_OPENING_ST},
+    /* BTA_HL_CCH_SDP_OK_EVT         */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST},
+    /* BTA_HL_CCH_SDP_FAIL_EVT       */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST},
+    /* BTA_HL_MCA_CONNECT_IND_EVT    */ {BTA_HL_CCH_MCA_CONNECT,
+                                         BTA_HL_CCH_OPEN_ST},
+    /* BTA_HL_MCA_DISCONNECT_IND_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST},
+    /* BTA_HL_CCH_CLOSE_EVT          */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST},
+    /* BTA_HL_CCH_CLOSE_CMPL_EVT     */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST},
+    /* BTA_HL_CCH_CLOSE_CMPL_EVT     */ {BTA_HL_CCH_IGNORE,
+                                         BTA_HL_CCH_IDLE_ST}};
+
+/* state table for obex/rfcomm connection state */
+static const uint8_t bta_hl_cch_st_opening[][BTA_HL_CCH_NUM_COLS] = {
+    /* Event                          Action 1               Next state */
+    /* BTA_HL_CCH_OPEN_EVT           */ {BTA_HL_CCH_IGNORE,
+                                         BTA_HL_CCH_OPENING_ST},
+    /* BTA_HL_CCH_SDP_OK_EVT         */ {BTA_HL_CCH_MCA_OPEN,
+                                         BTA_HL_CCH_OPENING_ST},
+    /* BTA_HL_CCH_SDP_FAIL_EVT       */ {BTA_HL_CCH_CLOSE_CMPL,
+                                         BTA_HL_CCH_IDLE_ST},
+    /* BTA_HL_MCA_CONNECT_IND_EVT    */ {BTA_HL_CCH_MCA_CONNECT,
+                                         BTA_HL_CCH_OPEN_ST},
+    /* BTA_HL_MCA_DISCONNECT_IND_EVT */ {BTA_HL_CCH_MCA_DISCONNECT,
+                                         BTA_HL_CCH_CLOSING_ST},
+    /* BTA_HL_CCH_CLOSE_EVT          */ {BTA_HL_CCH_MCA_CLOSE,
+                                         BTA_HL_CCH_CLOSING_ST},
+    /* BTA_HL_CCH_CLOSE_CMPL_EVT     */ {BTA_HL_CCH_CLOSE_CMPL,
+                                         BTA_HL_CCH_IDLE_ST},
+    /* BTA_HL_MCA_RSP_TOUT_IND_EVT   */ {BTA_HL_CCH_MCA_RSP_TOUT,
+                                         BTA_HL_CCH_CLOSING_ST}};
+
+/* state table for open state */
+static const uint8_t bta_hl_cch_st_open[][BTA_HL_CCH_NUM_COLS] = {
+    /* Event                          Action 1                  Next state */
+    /* BTA_HL_CCH_OPEN_EVT           */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPEN_ST},
+    /* BTA_HL_CCH_SDP_OK_EVT         */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPEN_ST},
+    /* BTA_HL_CCH_SDP_FAIL_EVT       */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPEN_ST},
+    /* BTA_HL_MCA_CONNECT_IND_EVT    */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPEN_ST},
+    /* BTA_HL_MCA_DISCONNECT_IND_EVT */ {BTA_HL_CCH_MCA_DISCONNECT,
+                                         BTA_HL_CCH_CLOSING_ST},
+    /* BTA_HL_CCH_CLOSE_EVT          */ {BTA_HL_CCH_MCA_CLOSE,
+                                         BTA_HL_CCH_CLOSING_ST},
+    /* BTA_HL_CCH_CLOSE_CMPL_EVT     */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPEN_ST},
+    /* BTA_HL_MCA_RSP_TOUT_IND_EVT   */ {BTA_HL_CCH_MCA_RSP_TOUT,
+                                         BTA_HL_CCH_CLOSING_ST}};
+
+/* state table for closing state */
+static const uint8_t bta_hl_cch_st_closing[][BTA_HL_CCH_NUM_COLS] = {
+    /* Event                          Action 1                  Next state */
+    /* BTA_HL_CCH_OPEN_EVT           */ {BTA_HL_CCH_IGNORE,
+                                         BTA_HL_CCH_CLOSING_ST},
+    /* BTA_HL_CCH_SDP_OK_EVT         */ {BTA_HL_CCH_CLOSE_CMPL,
+                                         BTA_HL_CCH_IDLE_ST},
+    /* BTA_HL_CCH_SDP_FAIL_EVT       */ {BTA_HL_CCH_CLOSE_CMPL,
+                                         BTA_HL_CCH_IDLE_ST},
+    /* BTA_HL_MCA_CONNECT_IND_EVT    */ {BTA_HL_CCH_MCA_DISC_OPEN,
+                                         BTA_HL_CCH_CLOSING_ST},
+    /* BTA_HL_MCA_DISCONNECT_IND_EVT */ {BTA_HL_CCH_MCA_DISCONNECT,
+                                         BTA_HL_CCH_CLOSING_ST},
+    /* BTA_HL_CCH_CLOSE_EVT          */ {BTA_HL_CCH_MCA_CLOSE,
+                                         BTA_HL_CCH_CLOSING_ST},
+    /* BTA_HL_CCH_CLOSE_CMPL_EVT     */ {BTA_HL_CCH_CLOSE_CMPL,
+                                         BTA_HL_CCH_IDLE_ST},
+    /* BTA_HL_MCA_RSP_TOUT_IND_EVT   */ {BTA_HL_CCH_IGNORE,
+                                         BTA_HL_CCH_CLOSING_ST}};
+
+/* type for state table CCH */
+typedef const uint8_t (*tBTA_HL_CCH_ST_TBL)[BTA_HL_CCH_NUM_COLS];
+
+/* MAS state table */
+const tBTA_HL_CCH_ST_TBL bta_hl_cch_st_tbl[] = {
+    bta_hl_cch_st_idle, bta_hl_cch_st_opening, bta_hl_cch_st_open,
+    bta_hl_cch_st_closing};
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+
+/* HL control block */
+tBTA_HL_CB bta_hl_cb;
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_cch_sm_execute
+ *
+ * Description      State machine event handling function for CCH
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_cch_sm_execute(uint8_t app_idx, uint8_t mcl_idx, uint16_t event,
+                           tBTA_HL_DATA* p_data) {
+  tBTA_HL_CCH_ST_TBL state_table;
+  uint8_t action;
+  int i;
+  tBTA_HL_MCL_CB* p_cb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+  tBTA_HL_CCH_STATE in_state = p_cb->cch_state;
+  uint16_t cur_evt = event;
+  APPL_TRACE_DEBUG("HDP CCH Event Handler: State 0x%02x [%s], Event [%s]",
+                   in_state, bta_hl_cch_state_code(in_state),
+                   bta_hl_evt_code(cur_evt));
+#endif
+
+  /* look up the state table for the current state */
+  state_table = bta_hl_cch_st_tbl[p_cb->cch_state];
+
+  event &= 0x00FF;
+
+  /* set next state */
+  p_cb->cch_state = state_table[event][BTA_HL_CCH_NEXT_STATE];
+
+  for (i = 0; i < BTA_HL_CCH_ACTIONS; i++) {
+    if ((action = state_table[event][i]) != BTA_HL_CCH_IGNORE) {
+      (*bta_hl_cch_action[action])(app_idx, mcl_idx, p_data);
+    } else {
+      /* discard HDP data */
+      bta_hl_discard_data(p_data->hdr.event, p_data);
+      break;
+    }
+  }
+#if (BTA_HL_DEBUG == TRUE)
+  if (in_state != p_cb->cch_state) {
+    APPL_TRACE_DEBUG("HL CCH State Change: [%s] -> [%s] after [%s]",
+                     bta_hl_cch_state_code(in_state),
+                     bta_hl_cch_state_code(p_cb->cch_state),
+                     bta_hl_evt_code(cur_evt));
+  }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_sm_execute
+ *
+ * Description      State machine event handling function for DCH
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_dch_sm_execute(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+                           uint16_t event, tBTA_HL_DATA* p_data) {
+  tBTA_HL_DCH_ST_TBL state_table;
+  uint8_t action;
+  int i;
+  tBTA_HL_MDL_CB* p_cb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+  tBTA_HL_DCH_STATE in_state = p_cb->dch_state;
+  uint16_t cur_evt = event;
+  APPL_TRACE_DEBUG("HDP DCH Event Handler: State 0x%02x [%s], Event [%s]",
+                   in_state, bta_hl_dch_state_code(in_state),
+                   bta_hl_evt_code(cur_evt));
+#endif
+
+  /* look up the state table for the current state */
+  state_table = bta_hl_dch_st_tbl[p_cb->dch_state];
+  event -= BTA_HL_DCH_EVT_MIN;
+
+  /* set next state */
+  p_cb->dch_state = state_table[event][BTA_HL_DCH_NEXT_STATE];
+
+  for (i = 0; i < BTA_HL_DCH_ACTIONS; i++) {
+    if ((action = state_table[event][i]) != BTA_HL_DCH_IGNORE) {
+      (*bta_hl_dch_action[action])(app_idx, mcl_idx, mdl_idx, p_data);
+    } else {
+      /* discard mas data */
+      bta_hl_discard_data(p_data->hdr.event, p_data);
+      break;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (in_state != p_cb->dch_state) {
+    APPL_TRACE_DEBUG("HL DCH State Change: [%s] -> [%s] after [%s]",
+                     bta_hl_dch_state_code(in_state),
+                     bta_hl_dch_state_code(p_cb->dch_state),
+                     bta_hl_evt_code(cur_evt));
+  }
+#endif
+}
+/*******************************************************************************
+ *
+ * Function         bta_hl_api_enable
+ *
+ * Description      Process the API enable request to enable the HL subsystem
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hl_api_enable(tBTA_HL_CB* p_cb, tBTA_HL_DATA* p_data) {
+  tBTA_HL_CTRL evt_data;
+
+  /* If already enabled then reject this request */
+  if (p_cb->enable) {
+    APPL_TRACE_ERROR("HL is already enabled");
+    evt_data.enable_cfm.status = BTA_HL_STATUS_FAIL;
+    if (p_data->api_enable.p_cback)
+      p_data->api_enable.p_cback(BTA_HL_CTRL_ENABLE_CFM_EVT,
+                                 (tBTA_HL_CTRL*)&evt_data);
+    return;
+  }
+
+  /* Done with checking. now perform the enable oepration*/
+  /* initialize control block */
+  memset(p_cb, 0, sizeof(tBTA_HL_CB));
+  p_cb->enable = true;
+  p_cb->p_ctrl_cback = p_data->api_enable.p_cback;
+  evt_data.enable_cfm.status = BTA_HL_STATUS_OK;
+  if (p_data->api_enable.p_cback)
+    p_data->api_enable.p_cback(BTA_HL_CTRL_ENABLE_CFM_EVT,
+                               (tBTA_HL_CTRL*)&evt_data);
+}
+/*******************************************************************************
+ *
+ * Function         bta_hl_api_disable
+ *
+ * Description      Process the API disable request to disable the HL subsystem
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hl_api_disable(tBTA_HL_CB* p_cb, tBTA_HL_DATA* p_data) {
+  tBTA_HL_CTRL evt_data;
+  tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+
+  if (p_cb->enable) {
+    p_cb->disabling = true;
+    bta_hl_check_disable(p_data);
+  } else {
+    status = BTA_HL_STATUS_FAIL;
+    evt_data.disable_cfm.status = status;
+    if (p_cb->p_ctrl_cback)
+      p_cb->p_ctrl_cback(BTA_HL_CTRL_DISABLE_CFM_EVT, (tBTA_HL_CTRL*)&evt_data);
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (status != BTA_HL_STATUS_OK) {
+    APPL_TRACE_DEBUG("bta_hl_api_disable status =%s",
+                     bta_hl_status_code(status));
+  }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_api_update
+ *
+ * Description      Process the API registration request to register an HDP
+ *                  application
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hl_api_update(tBTA_HL_CB* p_cb, tBTA_HL_DATA* p_data) {
+  tBTA_HL evt_data;
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(0);
+  tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL;
+
+  APPL_TRACE_DEBUG("bta_hl_api_update");
+  if (p_cb->enable) {
+    status = bta_hl_app_update(p_data->api_update.app_id,
+                               p_data->api_update.is_register);
+    if (!p_data->api_update.is_register) {
+      APPL_TRACE_DEBUG("Deregister");
+      memset(&evt_data, 0, sizeof(tBTA_HL));
+      evt_data.dereg_cfm.status = status;
+      evt_data.dereg_cfm.app_id = p_data->api_update.app_id;
+      if (status == BTA_HL_STATUS_OK)
+        evt_data.dereg_cfm.app_handle = p_acb->app_handle;
+      if (p_acb->p_cback) {
+        p_acb->p_cback(BTA_HL_DEREGISTER_CFM_EVT, (tBTA_HL*)&evt_data);
+      }
+      return;
+    }
+  }
+
+  if (status != BTA_HL_STATUS_OK) {
+    if ((status != BTA_HL_STATUS_DUPLICATE_APP_ID) &&
+        (status != BTA_HL_STATUS_NO_RESOURCE)) {
+      if (p_acb) memset(p_acb, 0, sizeof(tBTA_HL_APP_CB));
+    }
+  }
+#if (BTA_HL_DEBUG == TRUE)
+  if (status != BTA_HL_STATUS_OK) {
+    APPL_TRACE_DEBUG("bta_hl_api_register status =%s",
+                     bta_hl_status_code(status));
+  }
+#endif
+
+  memset(&evt_data, 0, sizeof(tBTA_HL));
+  evt_data.reg_cfm.status = status;
+  evt_data.reg_cfm.app_id = p_data->api_update.app_id;
+  if (status == BTA_HL_STATUS_OK)
+    evt_data.reg_cfm.app_handle = p_acb->app_handle;
+  if (p_data->api_reg.p_cback) {
+    p_data->api_reg.p_cback(BTA_HL_REGISTER_CFM_EVT, (tBTA_HL*)&evt_data);
+  }
+
+  if (status == BTA_HL_STATUS_OK) {
+    evt_data.sdp_info_ind.app_handle = p_acb->app_handle;
+    evt_data.sdp_info_ind.ctrl_psm = p_acb->ctrl_psm;
+    evt_data.sdp_info_ind.data_psm = p_acb->data_psm;
+    evt_data.sdp_info_ind.data_x_spec = BTA_HL_SDP_IEEE_11073_20601;
+    evt_data.sdp_info_ind.mcap_sup_procs = BTA_HL_MCAP_SUP_PROC_MASK;
+
+    if (p_data->api_reg.p_cback) {
+      p_data->api_reg.p_cback(BTA_HL_SDP_INFO_IND_EVT, (tBTA_HL*)&evt_data);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_api_register
+ *
+ * Description      Process the API registration request to register an HDP
+ *                  application
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hl_api_register(tBTA_HL_CB* p_cb, tBTA_HL_DATA* p_data) {
+  tBTA_HL evt_data;
+  uint8_t app_idx;
+  tBTA_HL_APP_CB* p_acb = NULL;
+  tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL;
+
+  if (p_cb->enable) {
+    if (!bta_hl_is_a_duplicate_id(p_data->api_reg.app_id)) {
+      if (bta_hl_find_avail_app_idx(&app_idx)) {
+        p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+        p_acb->in_use = true;
+        p_acb->app_id = p_data->api_reg.app_id;
+        p_acb->p_cback = p_data->api_reg.p_cback;
+        p_acb->sec_mask = p_data->api_reg.sec_mask;
+        p_acb->dev_type = p_data->api_reg.dev_type;
+        strlcpy(p_acb->srv_name, p_data->api_reg.srv_name,
+                BTA_SERVICE_NAME_LEN);
+        strlcpy(p_acb->srv_desp, p_data->api_reg.srv_desp,
+                BTA_SERVICE_DESP_LEN);
+        strlcpy(p_acb->provider_name, p_data->api_reg.provider_name,
+                BTA_PROVIDER_NAME_LEN);
+        bta_hl_cb.p_alloc_psm = L2CA_AllocatePSM;
+        p_acb->ctrl_psm = bta_hl_cb.p_alloc_psm();
+        p_acb->data_psm = bta_hl_cb.p_alloc_psm();
+        p_acb->p_mcap_cback = bta_hl_mcap_ctrl_cback;
+        status = bta_hl_app_registration(app_idx);
+      } else {
+        status = BTA_HL_STATUS_NO_RESOURCE;
+      }
+    } else {
+      status = BTA_HL_STATUS_DUPLICATE_APP_ID;
+    }
+  }
+
+  if (status != BTA_HL_STATUS_OK) {
+    if ((status != BTA_HL_STATUS_DUPLICATE_APP_ID) &&
+        (status != BTA_HL_STATUS_NO_RESOURCE)) {
+      if (p_acb) memset(p_acb, 0, sizeof(tBTA_HL_APP_CB));
+    }
+  }
+#if (BTA_HL_DEBUG == TRUE)
+  if (status != BTA_HL_STATUS_OK) {
+    APPL_TRACE_DEBUG("bta_hl_api_register status =%s",
+                     bta_hl_status_code(status));
+  }
+#endif
+
+  memset(&evt_data, 0, sizeof(tBTA_HL));
+  evt_data.reg_cfm.status = status;
+  evt_data.reg_cfm.app_id = p_data->api_reg.app_id;
+  if (status == BTA_HL_STATUS_OK)
+    evt_data.reg_cfm.app_handle = p_acb->app_handle;
+  if (p_data->api_reg.p_cback) {
+    p_data->api_reg.p_cback(BTA_HL_REGISTER_CFM_EVT, (tBTA_HL*)&evt_data);
+  }
+
+  if (status == BTA_HL_STATUS_OK) {
+    evt_data.sdp_info_ind.app_handle = p_acb->app_handle;
+    evt_data.sdp_info_ind.ctrl_psm = p_acb->ctrl_psm;
+    evt_data.sdp_info_ind.data_psm = p_acb->data_psm;
+    evt_data.sdp_info_ind.data_x_spec = BTA_HL_SDP_IEEE_11073_20601;
+    evt_data.sdp_info_ind.mcap_sup_procs = BTA_HL_MCAP_SUP_PROC_MASK;
+
+    if (p_data->api_reg.p_cback) {
+      p_data->api_reg.p_cback(BTA_HL_SDP_INFO_IND_EVT, (tBTA_HL*)&evt_data);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_api_deregister
+ *
+ * Description      Process the API de-registration request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hl_api_deregister(UNUSED_ATTR tBTA_HL_CB* p_cb,
+                                  tBTA_HL_DATA* p_data) {
+  uint8_t app_idx;
+  tBTA_HL_APP_CB* p_acb;
+
+  if (bta_hl_find_app_idx_using_handle(p_data->api_dereg.app_handle,
+                                       &app_idx)) {
+    p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+    p_acb->deregistering = true;
+    bta_hl_check_deregistration(app_idx, p_data);
+  } else {
+    APPL_TRACE_ERROR("Invalid app_handle=%d", p_data->api_dereg.app_handle);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_api_cch_open
+ *
+ * Description      Process the API CCH open request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hl_api_cch_open(UNUSED_ATTR tBTA_HL_CB* p_cb,
+                                tBTA_HL_DATA* p_data) {
+  tBTA_HL evt_data;
+  tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+  uint8_t app_idx, mcl_idx;
+  tBTA_HL_APP_CB* p_acb;
+  tBTA_HL_MCL_CB* p_mcb;
+
+  if (bta_hl_find_app_idx_using_handle(p_data->api_cch_open.app_handle,
+                                       &app_idx)) {
+    if (!bta_hl_find_mcl_idx(app_idx, p_data->api_cch_open.bd_addr, &mcl_idx)) {
+      if (bta_hl_find_avail_mcl_idx(app_idx, &mcl_idx)) {
+        p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+        p_mcb->in_use = true;
+        p_mcb->req_ctrl_psm = p_data->api_cch_open.ctrl_psm;
+        p_mcb->sec_mask = p_data->api_cch_open.sec_mask;
+        bdcpy(p_mcb->bd_addr, p_data->api_cch_open.bd_addr);
+        p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_OPEN;
+      } else {
+        status = BTA_HL_STATUS_NO_RESOURCE;
+      }
+    } else {
+      /* Only one MCL per BD_ADDR */
+      status = BTA_HL_STATUS_DUPLICATE_CCH_OPEN;
+      APPL_TRACE_DEBUG("bta_hl_api_cch_open: CCH already open: status =%d",
+                       status)
+      p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+      p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+      if (p_acb->p_cback) {
+        bta_hl_build_cch_open_cfm(&evt_data, p_data->api_cch_open.app_id,
+                                  p_data->api_cch_open.app_handle,
+                                  p_mcb->mcl_handle,
+                                  p_data->api_cch_open.bd_addr, status);
+        p_acb->p_cback(BTA_HL_CCH_OPEN_CFM_EVT, (tBTA_HL*)&evt_data);
+      } else {
+        APPL_TRACE_ERROR("bta_hl_api_cch_open Null Callback");
+      }
+      return;
+    }
+  } else {
+    status = BTA_HL_STATUS_INVALID_APP_HANDLE;
+  }
+#if (BTA_HL_DEBUG == TRUE)
+  if (status != BTA_HL_STATUS_OK) {
+    APPL_TRACE_DEBUG("bta_hl_api_cch_open status =%s",
+                     bta_hl_status_code(status));
+  }
+#endif
+  switch (status) {
+    case BTA_HL_STATUS_OK:
+      bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_OPEN_EVT, p_data);
+      break;
+    case BTA_HL_STATUS_NO_RESOURCE:
+    case BTA_HL_STATUS_FAIL:
+
+      p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+      if (p_acb->p_cback) {
+        bta_hl_build_cch_open_cfm(&evt_data, p_data->api_cch_open.app_id,
+                                  p_data->api_cch_open.app_handle, 0,
+                                  p_data->api_cch_open.bd_addr, status);
+        p_acb->p_cback(BTA_HL_CCH_OPEN_CFM_EVT, (tBTA_HL*)&evt_data);
+      } else {
+        APPL_TRACE_ERROR("bta_hl_api_cch_open Null Callback");
+      }
+      break;
+    default:
+      APPL_TRACE_ERROR("status code=%d", status);
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_api_cch_close
+ *
+ * Description      Process the API CCH close request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hl_api_cch_close(UNUSED_ATTR tBTA_HL_CB* p_cb,
+                                 tBTA_HL_DATA* p_data) {
+  tBTA_HL evt_data;
+  tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+  uint8_t app_idx, mcl_idx;
+  tBTA_HL_APP_CB* p_acb;
+  tBTA_HL_MCL_CB* p_mcb;
+
+  if (bta_hl_find_mcl_idx_using_handle(p_data->api_cch_close.mcl_handle,
+                                       &app_idx, &mcl_idx)) {
+    p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+    p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_CLOSE;
+  } else {
+    status = BTA_HL_STATUS_INVALID_MCL_HANDLE;
+  }
+#if (BTA_HL_DEBUG == TRUE)
+  if (status != BTA_HL_STATUS_OK) {
+    APPL_TRACE_DEBUG("bta_hl_api_cch_close status =%s",
+                     bta_hl_status_code(status));
+  }
+#endif
+  switch (status) {
+    case BTA_HL_STATUS_OK:
+      bta_hl_check_cch_close(app_idx, mcl_idx, p_data, true);
+      break;
+
+    case BTA_HL_STATUS_INVALID_MCL_HANDLE:
+      p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+      if (p_acb->p_cback) {
+        bta_hl_build_cch_close_cfm(&evt_data, p_acb->app_handle,
+                                   p_data->api_cch_close.mcl_handle, status);
+        p_acb->p_cback(BTA_HL_CCH_CLOSE_CFM_EVT, (tBTA_HL*)&evt_data);
+      } else {
+        APPL_TRACE_ERROR("bta_hl_api_cch_close Null Callback");
+      }
+      break;
+    default:
+      APPL_TRACE_ERROR("status code=%d", status);
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_api_dch_open
+ *
+ * Description      Process the API DCH open request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hl_api_dch_open(UNUSED_ATTR tBTA_HL_CB* p_cb,
+                                tBTA_HL_DATA* p_data) {
+  tBTA_HL evt_data;
+  tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+  uint8_t app_idx, mcl_idx, mdl_idx;
+  tBTA_HL_APP_CB* p_acb;
+  tBTA_HL_MCL_CB* p_mcb = NULL;
+  tBTA_HL_MDL_CB* p_dcb;
+  tBTA_HL_MDEP_CFG* p_mdep_cfg;
+  uint8_t mdep_cfg_idx;
+
+  if (bta_hl_find_mcl_idx_using_handle(p_data->api_dch_open.mcl_handle,
+                                       &app_idx, &mcl_idx)) {
+    p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+    p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+    APPL_TRACE_DEBUG(
+        "bta_hl_api_dch_open: app_ix=%d, mcl_idx=%d, cch_state=%d, "
+        "mcl_handle=%d",
+        app_idx, mcl_idx, p_mcb->cch_state, p_data->api_dch_open.mcl_handle);
+    if (p_mcb->cch_state == BTA_HL_CCH_OPEN_ST) {
+      if (bta_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
+        p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+        if (bta_hl_find_mdep_cfg_idx(
+                app_idx, p_data->api_dch_open.local_mdep_id, &mdep_cfg_idx)) {
+          if (mdep_cfg_idx &&
+              (p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg.mdep_role ==
+               BTA_HL_MDEP_ROLE_SINK)) {
+            p_data->api_dch_open.local_cfg = BTA_HL_DCH_CFG_NO_PREF;
+          }
+
+          if ((status = bta_hl_chk_local_cfg(app_idx, mcl_idx, mdep_cfg_idx,
+                                             p_data->api_dch_open.local_cfg)) ==
+              BTA_HL_STATUS_OK) {
+            if (p_data->api_dch_open.local_mdep_id !=
+                BTA_HL_ECHO_TEST_MDEP_ID) {
+              if (bta_hl_set_ctrl_psm_for_dch(app_idx, mcl_idx, mdl_idx,
+                                              p_data->api_dch_open.ctrl_psm)) {
+                p_mdep_cfg = BTA_HL_GET_MDEP_CFG_PTR(app_idx, mdep_cfg_idx);
+                p_dcb->in_use = true;
+                p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_OPEN;
+                p_dcb->sec_mask = p_data->api_dch_open.sec_mask;
+                p_dcb->local_mdep_id = p_data->api_dch_open.local_mdep_id;
+                p_dcb->peer_mdep_id = p_data->api_dch_open.peer_mdep_id;
+
+                if (p_mdep_cfg->mdep_role == BTA_HL_MDEP_ROLE_SINK) {
+                  p_dcb->peer_mdep_role = BTA_HL_MDEP_ROLE_SOURCE;
+                } else {
+                  p_dcb->peer_mdep_role = BTA_HL_MDEP_ROLE_SINK;
+                }
+
+                p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+                p_dcb->local_cfg = p_data->api_dch_open.local_cfg;
+
+                bta_hl_find_rxtx_apdu_size(app_idx, mdep_cfg_idx,
+                                           &p_dcb->max_rx_apdu_size,
+                                           &p_dcb->max_tx_apdu_size);
+                p_dcb->mdl_id =
+                    bta_hl_allocate_mdl_id(app_idx, mcl_idx, mdl_idx);
+                p_dcb->mdl_cfg_idx_included = false;
+              } else {
+                status = BTA_HL_STATUS_INVALID_CTRL_PSM;
+              }
+
+            } else {
+              status = BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID;
+            }
+          }
+        } else {
+          status = BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID;
+        }
+      } else {
+        status = BTA_HL_STATUS_NO_RESOURCE;
+      }
+    } else {
+      status = BTA_HL_STATUS_NO_CCH;
+    }
+  } else {
+    status = BTA_HL_STATUS_INVALID_MCL_HANDLE;
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (status != BTA_HL_STATUS_OK) {
+    APPL_TRACE_DEBUG("bta_hl_api_dch_open status =%s",
+                     bta_hl_status_code(status));
+  }
+#endif
+  switch (status) {
+    case BTA_HL_STATUS_OK:
+      if (p_mcb->sdp.num_recs) {
+        bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_OPEN_EVT,
+                              p_data);
+      } else {
+        bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+                              BTA_HL_DCH_SDP_INIT_EVT, p_data);
+      }
+      break;
+    case BTA_HL_STATUS_INVALID_DCH_CFG:
+    case BTA_HL_STATUS_NO_FIRST_RELIABLE:
+    case BTA_HL_STATUS_NO_CCH:
+    case BTA_HL_STATUS_NO_RESOURCE:
+    case BTA_HL_STATUS_FAIL:
+    case BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID:
+    case BTA_HL_STATUS_INVALID_CTRL_PSM:
+      p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+      if (p_acb->p_cback) {
+        bta_hl_build_dch_open_cfm(
+            &evt_data, p_acb->app_handle, p_data->api_dch_open.mcl_handle,
+            BTA_HL_INVALID_MDL_HANDLE, 0, 0, 0, 0, 0, status);
+        p_acb->p_cback(BTA_HL_DCH_OPEN_CFM_EVT, (tBTA_HL*)&evt_data);
+      } else {
+        APPL_TRACE_ERROR("bta_hl_api_dch_open Null Callback");
+      }
+
+      break;
+    default:
+      APPL_TRACE_ERROR("Status code=%d", status);
+      break;
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_hl_api_dch_close
+ *
+ * Description      Process the API DCH close request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hl_api_dch_close(UNUSED_ATTR tBTA_HL_CB* p_cb,
+                                 tBTA_HL_DATA* p_data) {
+  tBTA_HL evt_data;
+  tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+  uint8_t app_idx, mcl_idx, mdl_idx;
+  tBTA_HL_APP_CB* p_acb;
+  tBTA_HL_MCL_CB* p_mcb;
+  tBTA_HL_MDL_CB* p_dcb;
+
+  if (bta_hl_find_mdl_idx_using_handle(p_data->api_dch_close.mdl_handle,
+                                       &app_idx, &mcl_idx, &mdl_idx)) {
+    p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+    if (p_dcb->dch_state != BTA_HL_DCH_OPEN_ST) {
+      status = BTA_HL_STATUS_FAIL;
+    }
+  } else {
+    status = BTA_HL_STATUS_INVALID_MDL_HANDLE;
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (status != BTA_HL_STATUS_OK) {
+    APPL_TRACE_DEBUG("bta_hl_api_dch_close status =%s",
+                     bta_hl_status_code(status));
+  }
+#endif
+
+  switch (status) {
+    case BTA_HL_STATUS_OK:
+      bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_EVT,
+                            p_data);
+      break;
+    case BTA_HL_STATUS_FAIL:
+      p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+      if (p_acb->p_cback) {
+        p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+        bta_hl_build_dch_close_cfm(&evt_data, p_acb->app_handle,
+                                   p_mcb->mcl_handle,
+                                   p_data->api_dch_close.mdl_handle, status);
+
+        p_acb->p_cback(BTA_HL_DCH_CLOSE_CFM_EVT, (tBTA_HL*)&evt_data);
+      } else {
+        APPL_TRACE_ERROR("bta_hl_api_dch_close Null Callback");
+      }
+      break;
+    default:
+      APPL_TRACE_ERROR("Status code=%d", status);
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_api_dch_reconnect
+ *
+ * Description      Process the API DCH reconnect request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hl_api_dch_reconnect(UNUSED_ATTR tBTA_HL_CB* p_cb,
+                                     tBTA_HL_DATA* p_data) {
+  tBTA_HL evt_data;
+  tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+  uint8_t app_idx, mcl_idx, mdl_idx;
+  tBTA_HL_APP_CB* p_acb;
+  tBTA_HL_MCL_CB* p_mcb = NULL;
+  tBTA_HL_MDL_CB* p_dcb;
+  uint8_t mdep_cfg_idx;
+  uint8_t mdl_cfg_idx;
+  tBTA_HL_MDEP_CFG* p_mdep_cfg;
+
+  if (bta_hl_find_mcl_idx_using_handle(p_data->api_dch_reconnect.mcl_handle,
+                                       &app_idx, &mcl_idx)) {
+    p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+    p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+    if (p_mcb->cch_state == BTA_HL_CCH_OPEN_ST) {
+      if (bta_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
+        p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+        if (bta_hl_validate_reconnect_params(app_idx, mcl_idx,
+                                             &(p_data->api_dch_reconnect),
+                                             &mdep_cfg_idx, &mdl_cfg_idx)) {
+          if (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx) &&
+              (p_acb->mdl_cfg[mdl_cfg_idx].dch_mode !=
+               BTA_HL_DCH_MODE_RELIABLE)) {
+            status = BTA_HL_STATUS_NO_FIRST_RELIABLE;
+          } else {
+            if (bta_hl_set_ctrl_psm_for_dch(app_idx, mcl_idx, mdl_idx,
+                                            p_data->api_dch_open.ctrl_psm)) {
+              p_dcb->in_use = true;
+              p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_RECONNECT;
+              p_dcb->sec_mask = (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+              p_dcb->local_mdep_id = p_acb->mdl_cfg[mdl_cfg_idx].local_mdep_id;
+              p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+              p_dcb->local_cfg = BTA_HL_DCH_CFG_UNKNOWN;
+              p_dcb->mdl_id = p_data->api_dch_reconnect.mdl_id;
+              p_dcb->mdl_cfg_idx_included = true;
+              p_dcb->mdl_cfg_idx = mdl_cfg_idx;
+              p_dcb->dch_mode = p_acb->mdl_cfg[mdl_cfg_idx].dch_mode;
+
+              p_mdep_cfg = BTA_HL_GET_MDEP_CFG_PTR(app_idx, mdep_cfg_idx);
+
+              if (p_mdep_cfg->mdep_role == BTA_HL_MDEP_ROLE_SINK) {
+                p_dcb->peer_mdep_role = BTA_HL_MDEP_ROLE_SOURCE;
+                APPL_TRACE_DEBUG("peer mdep role = SOURCE ");
+              } else {
+                p_dcb->peer_mdep_role = BTA_HL_MDEP_ROLE_SINK;
+                APPL_TRACE_DEBUG("peer mdep role = SINK ");
+              }
+
+              bta_hl_find_rxtx_apdu_size(app_idx, mdep_cfg_idx,
+                                         &p_dcb->max_rx_apdu_size,
+                                         &p_dcb->max_tx_apdu_size);
+            } else {
+              status = BTA_HL_STATUS_INVALID_CTRL_PSM;
+            }
+          }
+        } else {
+          status = BTA_HL_STATUS_INVALID_RECONNECT_CFG;
+        }
+      } else {
+        status = BTA_HL_STATUS_NO_RESOURCE;
+      }
+    } else {
+      status = BTA_HL_STATUS_NO_CCH;
+    }
+  } else {
+    status = BTA_HL_STATUS_INVALID_MCL_HANDLE;
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (status != BTA_HL_STATUS_OK) {
+    APPL_TRACE_DEBUG("bta_hl_api_dch_reconnect status=%s",
+                     bta_hl_status_code(status));
+  }
+#endif
+
+  switch (status) {
+    case BTA_HL_STATUS_OK:
+      if (p_mcb->sdp.num_recs) {
+        bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+                              BTA_HL_DCH_RECONNECT_EVT, p_data);
+      } else {
+        bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+                              BTA_HL_DCH_SDP_INIT_EVT, p_data);
+      }
+      break;
+    case BTA_HL_STATUS_INVALID_RECONNECT_CFG:
+    case BTA_HL_STATUS_NO_FIRST_RELIABLE:
+    case BTA_HL_STATUS_NO_CCH:
+    case BTA_HL_STATUS_NO_RESOURCE:
+      p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+      if (p_acb->p_cback) {
+        bta_hl_build_dch_open_cfm(
+            &evt_data, p_acb->app_handle, p_data->api_dch_reconnect.mcl_handle,
+            BTA_HL_INVALID_MDL_HANDLE, 0, p_data->api_dch_reconnect.mdl_id, 0,
+            0, 0, status);
+        p_acb->p_cback(BTA_HL_DCH_RECONNECT_CFM_EVT, (tBTA_HL*)&evt_data);
+      } else {
+        APPL_TRACE_ERROR("bta_hl_api_dch_reconnect Null Callback");
+      }
+      break;
+    default:
+      APPL_TRACE_ERROR("Status code=%d", status);
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_api_dch_echo_test
+ *
+ * Description      Process the API Echo test request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hl_api_dch_echo_test(UNUSED_ATTR tBTA_HL_CB* p_cb,
+                                     tBTA_HL_DATA* p_data) {
+  tBTA_HL evt_data;
+  tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+  uint8_t app_idx, mcl_idx, mdl_idx;
+  tBTA_HL_APP_CB* p_acb;
+  tBTA_HL_MCL_CB* p_mcb = NULL;
+  tBTA_HL_MDL_CB* p_dcb;
+  tBTA_HL_ECHO_CFG* p_echo_cfg;
+
+  if (bta_hl_find_mcl_idx_using_handle(p_data->api_dch_echo_test.mcl_handle,
+                                       &app_idx, &mcl_idx)) {
+    p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+    p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+    if (p_mcb->cch_state == BTA_HL_CCH_OPEN_ST) {
+      if (!p_mcb->echo_test) {
+        if (bta_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
+          p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+          if ((p_data->api_dch_echo_test.local_cfg ==
+               BTA_HL_DCH_CFG_RELIABLE) ||
+              (p_data->api_dch_echo_test.local_cfg ==
+               BTA_HL_DCH_CFG_STREAMING)) {
+            bool fcs_use =
+                (bool)(p_dcb->chnl_cfg.fcs & BTA_HL_MCA_FCS_USE_MASK);
+            if ((p_dcb->p_echo_tx_pkt = bta_hl_get_buf(
+                     p_data->api_dch_echo_test.pkt_size, fcs_use)) != NULL) {
+              if (bta_hl_set_ctrl_psm_for_dch(app_idx, mcl_idx, mdl_idx,
+                                              p_data->api_dch_open.ctrl_psm)) {
+                p_dcb->in_use = true;
+                p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_OPEN;
+                p_dcb->sec_mask = (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+                p_dcb->local_mdep_cfg_idx = BTA_HL_ECHO_TEST_MDEP_CFG_IDX;
+                p_dcb->local_cfg = p_data->api_dch_echo_test.local_cfg;
+                p_dcb->local_mdep_id = BTA_HL_ECHO_TEST_MDEP_ID;
+                p_dcb->peer_mdep_id = BTA_HL_ECHO_TEST_MDEP_ID;
+                p_dcb->mdl_id =
+                    bta_hl_allocate_mdl_id(app_idx, mcl_idx, mdl_idx);
+                p_dcb->mdl_cfg_idx_included = false;
+                p_echo_cfg = BTA_HL_GET_ECHO_CFG_PTR(app_idx);
+                p_dcb->max_rx_apdu_size = p_echo_cfg->max_rx_apdu_size;
+                p_dcb->max_tx_apdu_size = p_echo_cfg->max_tx_apdu_size;
+                p_mcb->echo_test = true;
+                p_mcb->echo_mdl_idx = mdl_idx;
+              } else {
+                status = BTA_HL_STATUS_INVALID_CTRL_PSM;
+              }
+            } else {
+              status = BTA_HL_STATUS_NO_RESOURCE;
+            }
+          } else {
+            status = BTA_HL_STATUS_INVALID_DCH_CFG;
+          }
+        } else {
+          status = BTA_HL_STATUS_NO_RESOURCE;
+        }
+      } else {
+        status = BTA_HL_STATUS_ECHO_TEST_BUSY;
+      }
+    } else {
+      status = BTA_HL_STATUS_NO_CCH;
+    }
+  } else {
+    status = BTA_HL_STATUS_NO_MCL;
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (status != BTA_HL_STATUS_OK) {
+    APPL_TRACE_DEBUG("bta_hl_api_dch_echo_test status=%s",
+                     bta_hl_status_code(status));
+  }
+#endif
+
+  switch (status) {
+    case BTA_HL_STATUS_OK:
+      if (p_mcb->sdp.num_recs) {
+        bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+                              BTA_HL_DCH_ECHO_TEST_EVT, p_data);
+      } else {
+        bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+                              BTA_HL_DCH_SDP_INIT_EVT, p_data);
+      }
+      break;
+    case BTA_HL_STATUS_ECHO_TEST_BUSY:
+    case BTA_HL_STATUS_NO_RESOURCE:
+    case BTA_HL_STATUS_INVALID_DCH_CFG:
+      p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+      if (p_acb->p_cback) {
+        bta_hl_build_echo_test_cfm(&evt_data, p_acb->app_handle,
+                                   p_mcb->mcl_handle, status);
+        p_acb->p_cback(BTA_HL_DCH_ECHO_TEST_CFM_EVT, (tBTA_HL*)&evt_data);
+      } else {
+        APPL_TRACE_ERROR("bta_hl_api_dch_echo_test Null Callback");
+      }
+      break;
+
+    default:
+      APPL_TRACE_ERROR("Status code=%s", status);
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_api_sdp_query
+ *
+ * Description      Process the API SDP query request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hl_api_sdp_query(UNUSED_ATTR tBTA_HL_CB* p_cb,
+                                 tBTA_HL_DATA* p_data) {
+  tBTA_HL evt_data;
+  tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+  uint8_t app_idx, mcl_idx;
+  tBTA_HL_APP_CB* p_acb;
+  tBTA_HL_MCL_CB* p_mcb;
+
+  if (bta_hl_find_app_idx_using_handle(p_data->api_sdp_query.app_handle,
+                                       &app_idx)) {
+    if (!bta_hl_find_mcl_idx(app_idx, p_data->api_sdp_query.bd_addr,
+                             &mcl_idx)) {
+      if (bta_hl_find_avail_mcl_idx(app_idx, &mcl_idx)) {
+        p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+        p_mcb->in_use = true;
+        bdcpy(p_mcb->bd_addr, p_data->api_sdp_query.bd_addr);
+        APPL_TRACE_DEBUG(
+            "bta_hl_api_sdp_query p_mcb->app_id %d app_idx %d mcl_idx %d",
+            p_mcb->app_id, app_idx, mcl_idx);
+        p_mcb->app_id = p_data->api_sdp_query.app_id;
+        p_mcb->sdp_oper = BTA_HL_SDP_OP_SDP_QUERY_NEW;
+      } else {
+        status = BTA_HL_STATUS_NO_RESOURCE;
+      }
+    } else {
+      p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+      p_mcb->app_id = p_data->api_sdp_query.app_id;
+      if (p_mcb->sdp_oper != BTA_HL_SDP_OP_NONE) {
+        status = BTA_HL_STATUS_SDP_NO_RESOURCE;
+      } else {
+        p_mcb->sdp_oper = BTA_HL_SDP_OP_SDP_QUERY_CURRENT;
+      }
+    }
+  } else {
+    status = BTA_HL_STATUS_INVALID_APP_HANDLE;
+  }
+
+  if (status == BTA_HL_STATUS_OK) {
+    status = bta_hl_init_sdp(p_mcb->sdp_oper, app_idx, mcl_idx, 0xFF);
+    if ((status != BTA_HL_STATUS_OK) &&
+        (p_mcb->sdp_oper == BTA_HL_SDP_OP_SDP_QUERY_NEW)) {
+      memset(p_mcb, 0, sizeof(tBTA_HL_MCL_CB));
+    }
+  }
+#if (BTA_HL_DEBUG == TRUE)
+  if (status != BTA_HL_STATUS_OK) {
+    APPL_TRACE_DEBUG("bta_hl_api_sdp_query status=%s",
+                     bta_hl_status_code(status));
+  }
+#endif
+  switch (status) {
+    case BTA_HL_STATUS_NO_RESOURCE:
+    case BTA_HL_STATUS_FAIL:
+    case BTA_HL_STATUS_SDP_NO_RESOURCE:
+      p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+      if (p_acb->p_cback) {
+        bta_hl_build_sdp_query_cfm(&evt_data, p_data->api_sdp_query.app_id,
+                                   p_data->api_sdp_query.app_handle,
+                                   p_data->api_sdp_query.bd_addr, NULL, status);
+        p_acb->p_cback(BTA_HL_SDP_QUERY_CFM_EVT, (tBTA_HL*)&evt_data);
+      } else {
+        APPL_TRACE_ERROR("bta_hl_api_sdp_query Null Callback");
+      }
+      break;
+    case BTA_HL_STATUS_OK:
+      break;
+    default:
+      APPL_TRACE_ERROR("Status code=%d", status);
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_sdp_query_results
+ *
+ * Description      Process the SDP query results
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hl_sdp_query_results(UNUSED_ATTR tBTA_HL_CB* p_cb,
+                                     tBTA_HL_DATA* p_data) {
+  tBTA_HL evt_data;
+  tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+  uint8_t app_idx = p_data->cch_sdp.app_idx;
+  uint8_t mcl_idx = p_data->cch_sdp.mcl_idx;
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_SDP* p_sdp = NULL;
+  uint16_t event;
+  bool release_sdp_buf = false;
+
+  event = p_data->hdr.event;
+
+  if (event == BTA_HL_SDP_QUERY_OK_EVT) {
+    p_sdp = (tBTA_HL_SDP*)osi_malloc(sizeof(tBTA_HL_SDP));
+    memcpy(p_sdp, &p_mcb->sdp, sizeof(tBTA_HL_SDP));
+    release_sdp_buf = true;
+  } else {
+    status = BTA_HL_STATUS_SDP_FAIL;
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (status != BTA_HL_STATUS_OK) {
+    APPL_TRACE_DEBUG("bta_hl_sdp_query_results status=%s",
+                     bta_hl_status_code(status));
+  }
+#endif
+
+  APPL_TRACE_DEBUG(
+      "bta_hl_sdp_query_results p_mcb->app_id %d app_idx %d mcl_idx %d",
+      p_mcb->app_id, app_idx, mcl_idx);
+  bta_hl_build_sdp_query_cfm(&evt_data, p_mcb->app_id, p_acb->app_handle,
+                             p_mcb->bd_addr, p_sdp, status);
+  p_acb->p_cback(BTA_HL_SDP_QUERY_CFM_EVT, (tBTA_HL*)&evt_data);
+
+  if (release_sdp_buf) osi_free_and_reset((void**)&p_sdp);
+
+  if (p_data->cch_sdp.release_mcl_cb) {
+    memset(p_mcb, 0, sizeof(tBTA_HL_MCL_CB));
+  } else {
+    if (p_mcb->close_pending)
+      bta_hl_check_cch_close(app_idx, mcl_idx, p_data, true);
+
+    if (!p_mcb->ctrl_psm) {
+      /* Control channel acceptor: do not store the SDP records */
+      memset(&p_mcb->sdp, 0, sizeof(tBTA_HL_SDP));
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_api_delete_mdl
+ *
+ * Description      Process the API DELETE MDL request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hl_api_delete_mdl(UNUSED_ATTR tBTA_HL_CB* p_cb,
+                                  tBTA_HL_DATA* p_data) {
+  tBTA_HL evt_data;
+  tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+  uint8_t app_idx, mcl_idx;
+  tBTA_HL_APP_CB* p_acb;
+  tBTA_HL_MCL_CB* p_mcb;
+
+  if (bta_hl_find_mcl_idx_using_handle(p_data->api_delete_mdl.mcl_handle,
+                                       &app_idx, &mcl_idx)) {
+    if (bta_hl_is_mdl_value_valid(p_data->api_delete_mdl.mdl_id)) {
+      p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+      if (bta_hl_is_mdl_exsit_in_mcl(app_idx, p_mcb->bd_addr,
+                                     p_data->api_delete_mdl.mdl_id)) {
+        p_mcb->delete_mdl.mcl_handle = p_data->api_delete_mdl.mcl_handle;
+        p_mcb->delete_mdl.mdl_id = p_data->api_delete_mdl.mdl_id;
+        p_mcb->delete_mdl.delete_req_pending = true;
+
+        if (MCA_Delete((tMCA_CL)p_mcb->mcl_handle,
+                       p_data->api_delete_mdl.mdl_id) != MCA_SUCCESS) {
+          status = BTA_HL_STATUS_FAIL;
+          memset(&p_mcb->delete_mdl, 0, sizeof(tBTA_HL_DELETE_MDL));
+        }
+      } else {
+        status = BTA_HL_STATUS_NO_MDL_ID_FOUND;
+      }
+    } else {
+      status = BTA_HL_STATUS_INVALID_MDL_ID;
+    }
+  } else {
+    status = BTA_HL_STATUS_INVALID_MCL_HANDLE;
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (status != BTA_HL_STATUS_OK) {
+    APPL_TRACE_DEBUG("bta_hl_api_delete_mdl status=%s",
+                     bta_hl_status_code(status));
+  }
+#endif
+  switch (status) {
+    case BTA_HL_STATUS_OK:
+      break;
+    case BTA_HL_STATUS_FAIL:
+    case BTA_HL_STATUS_NO_MDL_ID_FOUND:
+    case BTA_HL_STATUS_INVALID_MDL_ID:
+      p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+      if (p_acb->p_cback) {
+        bta_hl_build_delete_mdl_cfm(&evt_data, p_acb->app_handle,
+                                    p_data->api_delete_mdl.mcl_handle,
+                                    p_data->api_delete_mdl.mdl_id, status);
+        p_acb->p_cback(BTA_HL_DELETE_MDL_CFM_EVT, (tBTA_HL*)&evt_data);
+      } else {
+        APPL_TRACE_ERROR("bta_hl_api_delete_mdl Null Callback");
+      }
+      break;
+    default:
+      APPL_TRACE_ERROR("status code =%d", status);
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_mca_delete_mdl_cfm
+ *
+ * Description      Process the DELETE MDL confirmation event
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hl_mca_delete_mdl_cfm(UNUSED_ATTR tBTA_HL_CB* p_cb,
+                                      tBTA_HL_DATA* p_data) {
+  tBTA_HL evt_data;
+  tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+  uint8_t app_idx, mcl_idx;
+  tMCA_RSP_EVT* p_delete_cfm = &p_data->mca_evt.mca_data.delete_cfm;
+  tBTA_HL_MCL_CB* p_mcb;
+  bool send_cfm_evt = true;
+  tBTA_HL_APP_CB* p_acb;
+
+  if (bta_hl_find_mcl_idx_using_handle(p_data->mca_evt.mcl_handle, &app_idx,
+                                       &mcl_idx)) {
+    p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+    if (p_mcb->delete_mdl.delete_req_pending) {
+      if (p_delete_cfm->rsp_code == MCA_RSP_SUCCESS) {
+        if (!bta_hl_delete_mdl_cfg(app_idx, p_mcb->bd_addr,
+                                   p_delete_cfm->mdl_id)) {
+          status = BTA_HL_STATUS_FAIL;
+        }
+      } else {
+        status = BTA_HL_STATUS_FAIL;
+      }
+
+      memset(&p_mcb->delete_mdl, 0, sizeof(tBTA_HL_DELETE_MDL));
+    } else {
+      send_cfm_evt = false;
+    }
+  } else {
+    send_cfm_evt = false;
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (status != BTA_HL_STATUS_OK) {
+    APPL_TRACE_DEBUG("bta_hl_api_delete_mdl status=%s",
+                     bta_hl_status_code(status));
+  }
+#endif
+
+  if (send_cfm_evt) {
+    p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+    if (p_acb->p_cback) {
+      bta_hl_build_delete_mdl_cfm(&evt_data, p_acb->app_handle,
+                                  p_mcb->mcl_handle, p_delete_cfm->mdl_id,
+                                  status);
+
+      p_acb->p_cback(BTA_HL_DELETE_MDL_CFM_EVT, (tBTA_HL*)&evt_data);
+    } else {
+      APPL_TRACE_ERROR("bta_hl_mca_delete_mdl_cfm Null Callback");
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_mca_delete_mdl_ind
+ *
+ * Description      Process the DELETE MDL indication event
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hl_mca_delete_mdl_ind(UNUSED_ATTR tBTA_HL_CB* p_cb,
+                                      tBTA_HL_DATA* p_data) {
+  tBTA_HL evt_data;
+  uint8_t app_idx, mcl_idx, mdl_idx;
+  tMCA_EVT_HDR* p_delete_ind = &p_data->mca_evt.mca_data.delete_ind;
+  tBTA_HL_MCL_CB* p_mcb;
+  tBTA_HL_MDL_CB* p_dcb;
+  bool send_ind_evt = false;
+  tBTA_HL_APP_CB* p_acb;
+
+  if (bta_hl_find_mcl_idx_using_handle(p_data->mca_evt.mcl_handle, &app_idx,
+                                       &mcl_idx)) {
+    p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+    if (bta_hl_find_mdl_idx(app_idx, mcl_idx, p_delete_ind->mdl_id, &mdl_idx)) {
+      p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+      p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_DELETE;
+    }
+    if (bta_hl_delete_mdl_cfg(app_idx, p_mcb->bd_addr, p_delete_ind->mdl_id)) {
+      send_ind_evt = true;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!send_ind_evt) {
+    APPL_TRACE_DEBUG("bta_hl_mca_delete_mdl_ind is_send_ind_evt =%d",
+                     send_ind_evt);
+  }
+#endif
+
+  if (send_ind_evt) {
+    p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+    if (p_acb->p_cback) {
+      evt_data.delete_mdl_ind.mcl_handle = p_mcb->mcl_handle;
+      evt_data.delete_mdl_ind.app_handle = p_acb->app_handle;
+      evt_data.delete_mdl_ind.mdl_id = p_delete_ind->mdl_id;
+      p_acb->p_cback(BTA_HL_DELETE_MDL_IND_EVT, (tBTA_HL*)&evt_data);
+    } else {
+      APPL_TRACE_ERROR("bta_hl_mca_delete_mdl_ind Null Callback");
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_api_dch_abort
+ *
+ * Description      Process the API DCH abort request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_hl_api_dch_abort(UNUSED_ATTR tBTA_HL_CB* p_cb,
+                                 tBTA_HL_DATA* p_data) {
+  tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+  uint8_t app_idx, mcl_idx, mdl_idx;
+  tBTA_HL_APP_CB* p_acb;
+  tBTA_HL_MCL_CB* p_mcb;
+  tBTA_HL_MDL_CB* p_dcb;
+  tBTA_HL evt_data;
+
+  if (bta_hl_find_mcl_idx_using_handle(p_data->api_dch_abort.mcl_handle,
+                                       &app_idx, &mcl_idx)) {
+    if (!bta_hl_find_dch_setup_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
+      status = BTA_HL_STATUS_NO_MDL_ID_FOUND;
+    } else {
+      p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+      if (p_dcb->abort_oper) {
+        /* abort already in progress*/
+        status = BTA_HL_STATUS_FAIL;
+      } else {
+        p_dcb->abort_oper = BTA_HL_ABORT_LOCAL_MASK;
+      }
+    }
+  } else {
+    status = BTA_HL_STATUS_INVALID_MCL_HANDLE;
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (status != BTA_HL_STATUS_OK) {
+    APPL_TRACE_DEBUG("bta_hl_api_dch_abort status=%s",
+                     bta_hl_status_code(status));
+  }
+#endif
+  switch (status) {
+    case BTA_HL_STATUS_OK:
+
+      bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ABORT_EVT,
+                            p_data);
+      break;
+    case BTA_HL_STATUS_NO_MDL_ID_FOUND:
+    case BTA_HL_STATUS_FAIL:
+
+      p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+      if (p_acb->p_cback) {
+        p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+        bta_hl_build_abort_cfm(&evt_data,
+
+                               p_acb->app_handle, p_mcb->mcl_handle,
+                               BTA_HL_STATUS_FAIL);
+        p_acb->p_cback(BTA_HL_DCH_ABORT_CFM_EVT, (tBTA_HL*)&evt_data);
+      } else {
+        APPL_TRACE_ERROR("bta_hl_api_dch_abort Null Callback");
+      }
+      break;
+    default:
+      APPL_TRACE_ERROR("Status code=%d", status);
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_hdl_event
+ *
+ * Description      HL main event handling function.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+bool bta_hl_hdl_event(BT_HDR* p_msg) {
+  uint8_t app_idx, mcl_idx, mdl_idx;
+  bool success = true;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("BTA HL Event Handler: Event [%s]",
+                   bta_hl_evt_code(p_msg->event));
+#endif
+
+  switch (p_msg->event) {
+    case BTA_HL_API_ENABLE_EVT:
+      bta_hl_api_enable(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+      break;
+    case BTA_HL_API_DISABLE_EVT:
+      bta_hl_api_disable(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+      break;
+    case BTA_HL_API_UPDATE_EVT:
+      bta_hl_api_update(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+      break;
+    case BTA_HL_API_REGISTER_EVT:
+      bta_hl_api_register(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+      break;
+    case BTA_HL_API_DEREGISTER_EVT:
+      bta_hl_api_deregister(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+      break;
+    case BTA_HL_API_CCH_OPEN_EVT:
+      bta_hl_api_cch_open(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+      break;
+    case BTA_HL_API_CCH_CLOSE_EVT:
+      bta_hl_api_cch_close(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+      break;
+    case BTA_HL_API_DCH_OPEN_EVT:
+      bta_hl_api_dch_open(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+      break;
+    case BTA_HL_API_DCH_CLOSE_EVT:
+      bta_hl_api_dch_close(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+      break;
+    case BTA_HL_API_DELETE_MDL_EVT:
+      bta_hl_api_delete_mdl(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+      break;
+    case BTA_HL_API_DCH_RECONNECT_EVT:
+      bta_hl_api_dch_reconnect(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+      break;
+
+    case BTA_HL_API_DCH_ECHO_TEST_EVT:
+      bta_hl_api_dch_echo_test(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+      break;
+
+    case BTA_HL_API_SDP_QUERY_EVT:
+      bta_hl_api_sdp_query(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+      break;
+
+    case BTA_HL_MCA_DELETE_CFM_EVT:
+      bta_hl_mca_delete_mdl_cfm(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+      break;
+
+    case BTA_HL_MCA_DELETE_IND_EVT:
+      bta_hl_mca_delete_mdl_ind(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+      break;
+
+    case BTA_HL_SDP_QUERY_OK_EVT:
+    case BTA_HL_SDP_QUERY_FAIL_EVT:
+      bta_hl_sdp_query_results(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+      break;
+    case BTA_HL_API_DCH_ABORT_EVT:
+      bta_hl_api_dch_abort(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+      break;
+
+    default:
+      if (p_msg->event < BTA_HL_DCH_EVT_MIN) {
+        if (bta_hl_find_cch_cb_indexes((tBTA_HL_DATA*)p_msg, &app_idx,
+                                       &mcl_idx)) {
+          bta_hl_cch_sm_execute(app_idx, mcl_idx, p_msg->event,
+                                (tBTA_HL_DATA*)p_msg);
+        } else {
+#if (BTA_HL_DEBUG == TRUE)
+          APPL_TRACE_ERROR(
+              "unable to find control block indexes for CCH: [event=%s]",
+              bta_hl_evt_code(p_msg->event));
+#else
+          APPL_TRACE_ERROR(
+              "unable to find control block indexes for CCH: [event=%d]",
+              p_msg->event);
+#endif
+          success = false;
+        }
+      } else {
+        if (bta_hl_find_dch_cb_indexes((tBTA_HL_DATA*)p_msg, &app_idx, &mcl_idx,
+                                       &mdl_idx)) {
+          bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, p_msg->event,
+                                (tBTA_HL_DATA*)p_msg);
+        } else {
+#if (BTA_HL_DEBUG == TRUE)
+          APPL_TRACE_ERROR(
+              "unable to find control block indexes for DCH : [event=%s]",
+              bta_hl_evt_code(p_msg->event));
+#else
+          APPL_TRACE_ERROR(
+              "unable to find control block indexes for DCH: [event=%d]",
+              p_msg->event);
+#endif
+          success = false;
+        }
+      }
+
+      break;
+  }
+
+  return (success);
+}
+
+/*****************************************************************************
+ *  Debug Functions
+ ****************************************************************************/
+#if (BTA_HL_DEBUG == TRUE)
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_cch_state_code
+ *
+ * Description      Map CCH state code to the corresponding state string
+ *
+ * Returns          string pointer for the associated state name
+ *
+ ******************************************************************************/
+static const char* bta_hl_cch_state_code(tBTA_HL_CCH_STATE state_code) {
+  switch (state_code) {
+    case BTA_HL_CCH_IDLE_ST:
+      return "BTA_HL_CCH_IDLE_ST";
+    case BTA_HL_CCH_OPENING_ST:
+      return "BTA_HL_CCH_OPENING_ST";
+    case BTA_HL_CCH_OPEN_ST:
+      return "BTA_HL_CCH_OPEN_ST";
+    case BTA_HL_CCH_CLOSING_ST:
+      return "BTA_HL_CCH_CLOSING_ST";
+    default:
+      return "Unknown CCH state code";
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_dch_state_code
+ *
+ * Description      Map DCH state code to the corresponding state string
+ *
+ * Returns          string pointer for the associated state name
+ *
+ ******************************************************************************/
+static const char* bta_hl_dch_state_code(tBTA_HL_DCH_STATE state_code) {
+  switch (state_code) {
+    case BTA_HL_DCH_IDLE_ST:
+      return "BTA_HL_DCH_IDLE_ST";
+    case BTA_HL_DCH_OPENING_ST:
+      return "BTA_HL_DCH_OPENING_ST";
+    case BTA_HL_DCH_OPEN_ST:
+      return "BTA_HL_DCH_OPEN_ST";
+    case BTA_HL_DCH_CLOSING_ST:
+      return "BTA_HL_DCH_CLOSING_ST";
+    default:
+      return "Unknown DCH state code";
+  }
+}
+#endif /* Debug Functions */
+#endif /* HL_INCLUDED */
diff --git a/bt/bta/hl/bta_hl_sdp.cc b/bt/bta/hl/bta_hl_sdp.cc
new file mode 100644
index 0000000..69b6f68
--- /dev/null
+++ b/bt/bta/hl/bta_hl_sdp.cc
@@ -0,0 +1,575 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1998-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.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_target.h"
+#if (HL_INCLUDED == TRUE)
+
+#include "bta_hl_int.h"
+#include "osi/include/osi.h"
+#include "sdp_api.h"
+#include "utl.h"
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_fill_sup_feature_list
+ *
+ * Description      Fill the supported features from teh SDP record
+ *
+ * Returns          true if found, false if not
+ *                  If found, the passed protocol list element is filled in.
+ *
+ ******************************************************************************/
+bool bta_hl_fill_sup_feature_list(const tSDP_DISC_ATTR* p_attr,
+                                  tBTA_HL_SUP_FEATURE_LIST_ELEM* p_list) {
+  tSDP_DISC_ATTR* p_sattr;
+  uint8_t item_cnt;
+  uint8_t list_cnt = 0;
+  bool status = true;
+
+  for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr;
+       p_attr = p_attr->p_next_attr) {
+    /* mdep sequence */
+    if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) {
+      return (false);
+    }
+
+    item_cnt = 0;
+
+    for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr && (item_cnt < 4);
+         p_sattr = p_sattr->p_next_attr) {
+      /* for each mdep list */
+
+      p_list->list_elem[list_cnt].p_mdep_desp = NULL;
+      switch (item_cnt) {
+        case 0:
+          p_list->list_elem[list_cnt].mdep_id = p_sattr->attr_value.v.u8;
+          break;
+        case 1:
+          p_list->list_elem[list_cnt].data_type = p_sattr->attr_value.v.u16;
+          break;
+        case 2:
+          p_list->list_elem[list_cnt].mdep_role =
+              (tBTA_HL_MDEP_ROLE)p_sattr->attr_value.v.u8;
+          break;
+        case 3:
+          p_list->list_elem[list_cnt].p_mdep_desp =
+              (char*)p_sattr->attr_value.v.array;
+          break;
+      }
+
+      item_cnt++;
+    }
+    list_cnt++;
+  }
+  p_list->num_elems = list_cnt;
+  return (status);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_compose_supported_feature_list
+ *
+ * Description      This function is called to compose a data sequence from
+ *                  the supported  feature element list struct pointer
+ *
+ * Returns          the length of the data sequence
+ *
+ ******************************************************************************/
+int bta_hl_compose_supported_feature_list(
+    uint8_t* p, uint16_t num_elem,
+    const tBTA_HL_SUP_FEATURE_ELEM* p_elem_list) {
+  uint16_t xx, str_len, seq_len;
+  uint8_t* p_head = p;
+
+  for (xx = 0; xx < num_elem; xx++, p_elem_list++) {
+    UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+    seq_len = 7;
+    str_len = 0;
+    if (p_elem_list->p_mdep_desp) {
+      str_len = strlen(p_elem_list->p_mdep_desp) + 1;
+      seq_len += str_len + 2; /* todo add a # symbol for 2 */
+    }
+
+    *p++ = (uint8_t)seq_len;
+
+    UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
+    UINT8_TO_BE_STREAM(p, p_elem_list->mdep_id);
+    UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+    UINT16_TO_BE_STREAM(p, p_elem_list->data_type);
+    UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
+    UINT8_TO_BE_STREAM(p, p_elem_list->mdep_role);
+
+    if (str_len) {
+      UINT8_TO_BE_STREAM(p, (TEXT_STR_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+      UINT8_TO_BE_STREAM(p, str_len);
+      ARRAY_TO_BE_STREAM(p, p_elem_list->p_mdep_desp, str_len);
+    }
+  }
+
+  return (p - p_head);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_add_sup_feature_list
+ *
+ * Description      This function is called to add a protocol descriptor list to
+ *                  a record. This would be through the SDP database maintenance
+ *                  API. If the protocol list already exists in the record, it
+ *                  is replaced with the new list.
+ *
+ * Returns          true if added OK, else false
+ *
+ ******************************************************************************/
+bool bta_hl_add_sup_feature_list(uint32_t handle, uint16_t num_elem,
+                                 const tBTA_HL_SUP_FEATURE_ELEM* p_elem_list) {
+  int offset;
+  bool result;
+  uint8_t* p_buf = (uint8_t*)osi_malloc(BTA_HL_SUP_FEATURE_SDP_BUF_SIZE);
+
+  offset = bta_hl_compose_supported_feature_list(p_buf, num_elem, p_elem_list);
+  result = SDP_AddAttribute(handle, ATTR_ID_HDP_SUP_FEAT_LIST,
+                            DATA_ELE_SEQ_DESC_TYPE, (uint32_t)offset, p_buf);
+  osi_free(p_buf);
+
+  return result;
+}
+
+/*****************************************************************************
+ *
+ *  Function:    bta_hl_sdp_update
+ *
+ *  Purpose:     Register an HDP application with SDP
+ *
+ *  Parameters:
+ *
+ *  Returns:     void
+ *
+ ****************************************************************************/
+tBTA_HL_STATUS bta_hl_sdp_update(UNUSED_ATTR uint8_t app_id) {
+  uint16_t svc_class_id_list[BTA_HL_NUM_SVC_ELEMS];
+  tSDP_PROTOCOL_ELEM proto_elem_list[BTA_HL_NUM_PROTO_ELEMS];
+  tSDP_PROTO_LIST_ELEM add_proto_list;
+  tBTA_HL_SUP_FEATURE_LIST_ELEM sup_feature_list;
+  uint16_t browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
+  uint8_t i, j, cnt, mdep_id, mdep_role;
+  uint8_t data_exchange_spec = BTA_HL_SDP_IEEE_11073_20601;
+  uint8_t mcap_sup_proc = BTA_HL_MCAP_SUP_PROC_MASK;
+  uint16_t profile_uuid = UUID_SERVCLASS_HDP_PROFILE;
+  uint16_t version = BTA_HL_VERSION;
+  uint8_t num_services = 1;
+  tBTA_HL_APP_CB* p_cb = BTA_HL_GET_APP_CB_PTR(0);
+  bool result = true;
+  tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+
+  if ((p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SOURCE) &&
+      (!p_cb->sup_feature.advertize_source_sdp)) {
+    return BTA_HL_STATUS_OK;
+  }
+
+  num_services = 1;
+  svc_class_id_list[0] = UUID_SERVCLASS_HDP_SOURCE;
+  if (p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SINK) {
+    svc_class_id_list[0] = UUID_SERVCLASS_HDP_SINK;
+  } else {
+    if (p_cb->sup_feature.app_role_mask != BTA_HL_MDEP_ROLE_MASK_SOURCE) {
+      /* dual role */
+      num_services = 2;
+      svc_class_id_list[1] = UUID_SERVCLASS_HDP_SINK;
+    }
+  }
+  result &= SDP_AddServiceClassIdList(p_cb->sdp_handle, num_services,
+                                      svc_class_id_list);
+
+  if (result) {
+    /* add the protocol element sequence */
+    proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+    proto_elem_list[0].num_params = 1;
+    proto_elem_list[0].params[0] = p_cb->ctrl_psm;
+    proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_MCAP_CTRL;
+    proto_elem_list[1].num_params = 1;
+    proto_elem_list[1].params[0] = version;
+    result &= SDP_AddProtocolList(p_cb->sdp_handle, BTA_HL_NUM_PROTO_ELEMS,
+                                  proto_elem_list);
+
+    result &=
+        SDP_AddProfileDescriptorList(p_cb->sdp_handle, profile_uuid, version);
+  }
+
+  if (result) {
+    add_proto_list.num_elems = BTA_HL_NUM_ADD_PROTO_ELEMS;
+    add_proto_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+    add_proto_list.list_elem[0].num_params = 1;
+    add_proto_list.list_elem[0].params[0] = p_cb->data_psm;
+    add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_MCAP_DATA;
+    add_proto_list.list_elem[1].num_params = 0;
+    result &=
+        SDP_AddAdditionProtoLists(p_cb->sdp_handle, BTA_HL_NUM_ADD_PROTO_LISTS,
+                                  (tSDP_PROTO_LIST_ELEM*)&add_proto_list);
+  }
+
+  if (result) {
+    if (p_cb->srv_name[0]) {
+      result &= SDP_AddAttribute(
+          p_cb->sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
+          (uint8_t)TEXT_STR_DESC_TYPE, (uint32_t)(strlen(p_cb->srv_name) + 1),
+          (uint8_t*)p_cb->srv_name);
+    } /* end of setting optional service name */
+  }
+
+  if (result) {
+    if (p_cb->srv_desp[0]) {
+      result &= SDP_AddAttribute(
+          p_cb->sdp_handle, (uint16_t)ATTR_ID_SERVICE_DESCRIPTION,
+          (uint8_t)TEXT_STR_DESC_TYPE, (uint32_t)(strlen(p_cb->srv_desp) + 1),
+          (uint8_t*)p_cb->srv_desp);
+
+    } /* end of setting optional service description */
+  }
+
+  if (result) {
+    if (p_cb->provider_name[0]) {
+      result &=
+          SDP_AddAttribute(p_cb->sdp_handle, (uint16_t)ATTR_ID_PROVIDER_NAME,
+                           (uint8_t)TEXT_STR_DESC_TYPE,
+                           (uint32_t)(strlen(p_cb->provider_name) + 1),
+                           (uint8_t*)p_cb->provider_name);
+    } /* end of setting optional provider name */
+  }
+
+  /* add supported feture list */
+
+  if (result) {
+    cnt = 0;
+    for (i = 1; i < BTA_HL_NUM_MDEPS; i++) {
+      if (p_cb->sup_feature.mdep[i].mdep_id) {
+        mdep_id = (uint8_t)p_cb->sup_feature.mdep[i].mdep_id;
+        mdep_role = (uint8_t)p_cb->sup_feature.mdep[i].mdep_cfg.mdep_role;
+
+        APPL_TRACE_DEBUG(
+            "num_of_mdep_data_types %d ",
+            p_cb->sup_feature.mdep[i].mdep_cfg.num_of_mdep_data_types);
+        for (j = 0;
+             j < p_cb->sup_feature.mdep[i].mdep_cfg.num_of_mdep_data_types;
+             j++) {
+          sup_feature_list.list_elem[cnt].mdep_id = mdep_id;
+          sup_feature_list.list_elem[cnt].mdep_role = mdep_role;
+          sup_feature_list.list_elem[cnt].data_type =
+              p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].data_type;
+          if (p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp[0] != '\0') {
+            sup_feature_list.list_elem[cnt].p_mdep_desp =
+                p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp;
+          } else {
+            sup_feature_list.list_elem[cnt].p_mdep_desp = NULL;
+          }
+
+          cnt++;
+          if (cnt == BTA_HL_NUM_SUP_FEATURE_ELEMS) {
+            result = false;
+            break;
+          }
+        }
+      }
+    }
+    sup_feature_list.num_elems = cnt;
+    result &= bta_hl_add_sup_feature_list(p_cb->sdp_handle,
+                                          sup_feature_list.num_elems,
+                                          sup_feature_list.list_elem);
+  }
+  if (result) {
+    result &= SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_DATA_EXCH_SPEC,
+                               UINT_DESC_TYPE, (uint32_t)1,
+                               (uint8_t*)&data_exchange_spec);
+  }
+
+  if (result) {
+    result &=
+        SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_MCAP_SUP_PROC,
+                         UINT_DESC_TYPE, (uint32_t)1, (uint8_t*)&mcap_sup_proc);
+  }
+
+  if (result) {
+    result &= SDP_AddUuidSequence(p_cb->sdp_handle, ATTR_ID_BROWSE_GROUP_LIST,
+                                  1, browse_list);
+  }
+
+  if (result) {
+    for (i = 0; i < num_services; i++) {
+      bta_sys_add_uuid(svc_class_id_list[i]);
+      APPL_TRACE_DEBUG("dbg bta_sys_add_uuid i=%d uuid=0x%x", i,
+                       svc_class_id_list[i]);  // todo
+    }
+  } else {
+    if (p_cb->sdp_handle) {
+      SDP_DeleteRecord(p_cb->sdp_handle);
+      p_cb->sdp_handle = 0;
+    }
+    status = BTA_HL_STATUS_SDP_FAIL;
+  }
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_sdp_update status=%s", bta_hl_status_code(status));
+#endif
+  return status;
+}
+
+/*****************************************************************************
+ *
+ *  Function:    bta_hl_sdp_register
+ *
+ *  Purpose:     Register an HDP application with SDP
+ *
+ *  Parameters:  p_cb           - Pointer to MA instance control block
+ *               p_service_name - MA server name
+ *               inst_id        - MAS instance ID
+ *               msg_type       - Supported message type(s)
+ *
+ *
+ *  Returns:     void
+ *
+ ****************************************************************************/
+tBTA_HL_STATUS bta_hl_sdp_register(uint8_t app_idx) {
+  uint16_t svc_class_id_list[BTA_HL_NUM_SVC_ELEMS];
+  tSDP_PROTOCOL_ELEM proto_elem_list[BTA_HL_NUM_PROTO_ELEMS];
+  tSDP_PROTO_LIST_ELEM add_proto_list;
+  tBTA_HL_SUP_FEATURE_LIST_ELEM sup_feature_list;
+  uint16_t browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
+  uint8_t i, j, cnt, mdep_id, mdep_role;
+  uint8_t data_exchange_spec = BTA_HL_SDP_IEEE_11073_20601;
+  uint8_t mcap_sup_proc = BTA_HL_MCAP_SUP_PROC_MASK;
+  uint16_t profile_uuid = UUID_SERVCLASS_HDP_PROFILE;
+  uint16_t version = BTA_HL_VERSION;
+  uint8_t num_services = 1;
+  tBTA_HL_APP_CB* p_cb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  bool result = true;
+  tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_sdp_register app_idx=%d", app_idx);
+#endif
+
+  if ((p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SOURCE) &&
+      (!p_cb->sup_feature.advertize_source_sdp)) {
+    return BTA_HL_STATUS_OK;
+  }
+
+  if ((p_cb->sdp_handle = SDP_CreateRecord()) == 0) {
+    return BTA_HL_STATUS_SDP_NO_RESOURCE;
+  }
+
+  num_services = 1;
+  svc_class_id_list[0] = UUID_SERVCLASS_HDP_SOURCE;
+  if (p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SINK) {
+    svc_class_id_list[0] = UUID_SERVCLASS_HDP_SINK;
+  } else {
+    if (p_cb->sup_feature.app_role_mask != BTA_HL_MDEP_ROLE_MASK_SOURCE) {
+      /* dual role */
+      num_services = 2;
+      svc_class_id_list[1] = UUID_SERVCLASS_HDP_SINK;
+    }
+  }
+  result &= SDP_AddServiceClassIdList(p_cb->sdp_handle, num_services,
+                                      svc_class_id_list);
+
+  if (result) {
+    /* add the protocol element sequence */
+    proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+    proto_elem_list[0].num_params = 1;
+    proto_elem_list[0].params[0] = p_cb->ctrl_psm;
+    proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_MCAP_CTRL;
+    proto_elem_list[1].num_params = 1;
+    proto_elem_list[1].params[0] = version;
+    result &= SDP_AddProtocolList(p_cb->sdp_handle, BTA_HL_NUM_PROTO_ELEMS,
+                                  proto_elem_list);
+
+    result &=
+        SDP_AddProfileDescriptorList(p_cb->sdp_handle, profile_uuid, version);
+  }
+
+  if (result) {
+    add_proto_list.num_elems = BTA_HL_NUM_ADD_PROTO_ELEMS;
+    add_proto_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+    add_proto_list.list_elem[0].num_params = 1;
+    add_proto_list.list_elem[0].params[0] = p_cb->data_psm;
+    add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_MCAP_DATA;
+    add_proto_list.list_elem[1].num_params = 0;
+    result &=
+        SDP_AddAdditionProtoLists(p_cb->sdp_handle, BTA_HL_NUM_ADD_PROTO_LISTS,
+                                  (tSDP_PROTO_LIST_ELEM*)&add_proto_list);
+  }
+
+  if (result) {
+    if (p_cb->srv_name[0]) {
+      result &= SDP_AddAttribute(
+          p_cb->sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
+          (uint8_t)TEXT_STR_DESC_TYPE, (uint32_t)(strlen(p_cb->srv_name) + 1),
+          (uint8_t*)p_cb->srv_name);
+    } /* end of setting optional service name */
+  }
+
+  if (result) {
+    if (p_cb->srv_desp[0]) {
+      result &= SDP_AddAttribute(
+          p_cb->sdp_handle, (uint16_t)ATTR_ID_SERVICE_DESCRIPTION,
+          (uint8_t)TEXT_STR_DESC_TYPE, (uint32_t)(strlen(p_cb->srv_desp) + 1),
+          (uint8_t*)p_cb->srv_desp);
+
+    } /* end of setting optional service description */
+  }
+
+  if (result) {
+    if (p_cb->provider_name[0]) {
+      result &=
+          SDP_AddAttribute(p_cb->sdp_handle, (uint16_t)ATTR_ID_PROVIDER_NAME,
+                           (uint8_t)TEXT_STR_DESC_TYPE,
+                           (uint32_t)(strlen(p_cb->provider_name) + 1),
+                           (uint8_t*)p_cb->provider_name);
+    } /* end of setting optional provider name */
+  }
+
+  /* add supported feture list */
+
+  if (result) {
+    cnt = 0;
+    for (i = 1; i <= p_cb->sup_feature.num_of_mdeps; i++) {
+      mdep_id = (uint8_t)p_cb->sup_feature.mdep[i].mdep_id;
+      mdep_role = (uint8_t)p_cb->sup_feature.mdep[i].mdep_cfg.mdep_role;
+
+      for (j = 0; j < p_cb->sup_feature.mdep[i].mdep_cfg.num_of_mdep_data_types;
+           j++) {
+        sup_feature_list.list_elem[cnt].mdep_id = mdep_id;
+        sup_feature_list.list_elem[cnt].mdep_role = mdep_role;
+        sup_feature_list.list_elem[cnt].data_type =
+            p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].data_type;
+        if (p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp[0] != '\0') {
+          sup_feature_list.list_elem[cnt].p_mdep_desp =
+              p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp;
+        } else {
+          sup_feature_list.list_elem[cnt].p_mdep_desp = NULL;
+        }
+
+        cnt++;
+        if (cnt == BTA_HL_NUM_SUP_FEATURE_ELEMS) {
+          result = false;
+          break;
+        }
+      }
+    }
+    sup_feature_list.num_elems = cnt;
+    result &= bta_hl_add_sup_feature_list(p_cb->sdp_handle,
+                                          sup_feature_list.num_elems,
+                                          sup_feature_list.list_elem);
+  }
+  if (result) {
+    result &= SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_DATA_EXCH_SPEC,
+                               UINT_DESC_TYPE, (uint32_t)1,
+                               (uint8_t*)&data_exchange_spec);
+  }
+
+  if (result) {
+    result &=
+        SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_MCAP_SUP_PROC,
+                         UINT_DESC_TYPE, (uint32_t)1, (uint8_t*)&mcap_sup_proc);
+  }
+
+  if (result) {
+    result &= SDP_AddUuidSequence(p_cb->sdp_handle, ATTR_ID_BROWSE_GROUP_LIST,
+                                  1, browse_list);
+  }
+
+  if (result) {
+    for (i = 0; i < num_services; i++) {
+      bta_sys_add_uuid(svc_class_id_list[i]);
+      APPL_TRACE_DEBUG("dbg bta_sys_add_uuid i=%d uuid=0x%x", i,
+                       svc_class_id_list[i]);  // todo
+    }
+  } else {
+    if (p_cb->sdp_handle) {
+      SDP_DeleteRecord(p_cb->sdp_handle);
+      p_cb->sdp_handle = 0;
+    }
+    status = BTA_HL_STATUS_SDP_FAIL;
+  }
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_sdp_register status=%s", bta_hl_status_code(status));
+#endif
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_find_sink_or_src_srv_class_in_db
+ *
+ * Description      This function queries an SDP database for either a HDP Sink
+ *                  or Source service class ID.
+ *                  If the p_start_rec pointer is NULL, it looks from the
+ *                  beginning of the database, else it continues from the next
+ *                  record after p_start_rec.
+ *
+ * Returns          Pointer to record containing service class, or NULL
+ *
+ ******************************************************************************/
+tSDP_DISC_REC* bta_hl_find_sink_or_src_srv_class_in_db(
+    const tSDP_DISCOVERY_DB* p_db, const tSDP_DISC_REC* p_start_rec) {
+#if (SDP_CLIENT_ENABLED == TRUE)
+  tSDP_DISC_REC* p_rec;
+  tSDP_DISC_ATTR *p_attr, *p_sattr;
+
+  /* Must have a valid database */
+  if (p_db == NULL) return (NULL);
+
+  if (!p_start_rec) {
+    p_rec = p_db->p_first_rec;
+  } else {
+    p_rec = p_start_rec->p_next_rec;
+  }
+
+  while (p_rec) {
+    p_attr = p_rec->p_first_attr;
+    while (p_attr) {
+      if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) &&
+          (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) ==
+           DATA_ELE_SEQ_DESC_TYPE)) {
+        for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr;
+             p_sattr = p_sattr->p_next_attr) {
+          if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) &&
+              (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) &&
+              ((p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SINK) ||
+               (p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SOURCE))) {
+            return (p_rec);
+          }
+        }
+        break;
+      }
+
+      p_attr = p_attr->p_next_attr;
+    }
+
+    p_rec = p_rec->p_next_rec;
+  }
+#endif
+/* If here, no matching UUID found */
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_find_sink_or_src_srv_class_in_db failed");
+#endif
+
+  return (NULL);
+}
+#endif /* HL_INCLUDED */
diff --git a/bt/bta/hl/bta_hl_utils.cc b/bt/bta/hl/bta_hl_utils.cc
new file mode 100644
index 0000000..1dea0a2
--- /dev/null
+++ b/bt/bta/hl/bta_hl_utils.cc
@@ -0,0 +1,3081 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 implements utility functions for the HeaLth device profile
+ *  (HL).
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "bt_target.h"
+#if (HL_INCLUDED == TRUE)
+
+#include "bt_common.h"
+#include "bta_hl_co.h"
+#include "bta_hl_int.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "osi/include/osi.h"
+#include "utl.h"
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_set_ctrl_psm_for_dch
+ *
+ * Description    This function set the control PSM for the DCH setup
+ *
+ * Returns     bool - true - control PSM setting is successful
+ ******************************************************************************/
+bool bta_hl_set_ctrl_psm_for_dch(uint8_t app_idx, uint8_t mcl_idx,
+                                 UNUSED_ATTR uint8_t mdl_idx,
+                                 uint16_t ctrl_psm) {
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  bool success = true, update_ctrl_psm = false;
+
+  if (p_mcb->sdp.num_recs) {
+    if (p_mcb->ctrl_psm != ctrl_psm) {
+      /* can not use a different ctrl PSM than the current one*/
+      success = false;
+    }
+  } else {
+    /* No SDP info control i.e. channel was opened by the peer */
+    update_ctrl_psm = true;
+  }
+
+  if (success && update_ctrl_psm) {
+    p_mcb->ctrl_psm = ctrl_psm;
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!success) {
+    APPL_TRACE_DEBUG(
+        "bta_hl_set_ctrl_psm_for_dch num_recs=%d success=%d update_ctrl_psm=%d "
+        "ctrl_psm=0x%x ",
+        p_mcb->sdp.num_recs, success, update_ctrl_psm, ctrl_psm);
+  }
+#endif
+
+  return success;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_find_sdp_idx_using_ctrl_psm
+ *
+ * Description
+ *
+ * Returns      true if found
+ *
+ ******************************************************************************/
+bool bta_hl_find_sdp_idx_using_ctrl_psm(tBTA_HL_SDP* p_sdp, uint16_t ctrl_psm,
+                                        uint8_t* p_sdp_idx) {
+  bool found = false;
+  tBTA_HL_SDP_REC* p_rec;
+  uint8_t i;
+
+  if (ctrl_psm != 0) {
+    for (i = 0; i < p_sdp->num_recs; i++) {
+      p_rec = &p_sdp->sdp_rec[i];
+      if (p_rec->ctrl_psm == ctrl_psm) {
+        *p_sdp_idx = i;
+        found = true;
+        break;
+      }
+    }
+  } else {
+    *p_sdp_idx = 0;
+    found = true;
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!found) {
+    APPL_TRACE_DEBUG(
+        "bta_hl_find_sdp_idx_using_ctrl_psm found=%d sdp_idx=%d ctrl_psm=0x%x ",
+        found, *p_sdp_idx, ctrl_psm);
+  }
+#endif
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_set_user_tx_buf_size
+ *
+ * Description  This function sets the user tx buffer size
+ *
+ * Returns      uint16_t buf_size
+ *
+ ******************************************************************************/
+
+uint16_t bta_hl_set_user_tx_buf_size(uint16_t max_tx_size) {
+  if (max_tx_size > BT_DEFAULT_BUFFER_SIZE) return BTA_HL_LRG_DATA_BUF_SIZE;
+  return L2CAP_INVALID_ERM_BUF_SIZE;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_set_user_rx_buf_size
+ *
+ * Description  This function sets the user rx buffer size
+ *
+ * Returns      uint16_t buf_size
+ *
+ ******************************************************************************/
+
+uint16_t bta_hl_set_user_rx_buf_size(uint16_t mtu) {
+  if (mtu > BT_DEFAULT_BUFFER_SIZE) return BTA_HL_LRG_DATA_BUF_SIZE;
+  return L2CAP_INVALID_ERM_BUF_SIZE;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_set_tx_win_size
+ *
+ * Description  This function sets the tx window size
+ *
+ * Returns      uint8_t tx_win_size
+ *
+ ******************************************************************************/
+uint8_t bta_hl_set_tx_win_size(uint16_t mtu, uint16_t mps) {
+  uint8_t tx_win_size;
+
+  if (mtu <= mps) {
+    tx_win_size = 1;
+  } else {
+    if (mps > 0) {
+      tx_win_size = (mtu / mps) + 1;
+    } else {
+      APPL_TRACE_ERROR("The MPS is zero");
+      tx_win_size = 10;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_set_tx_win_size win_size=%d mtu=%d mps=%d",
+                   tx_win_size, mtu, mps);
+#endif
+  return tx_win_size;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_set_mps
+ *
+ * Description  This function sets the MPS
+ *
+ * Returns      uint16_t MPS
+ *
+ ******************************************************************************/
+uint16_t bta_hl_set_mps(uint16_t mtu) {
+  uint16_t mps;
+  if (mtu > BTA_HL_L2C_MPS) {
+    mps = BTA_HL_L2C_MPS;
+  } else {
+    mps = mtu;
+  }
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_set_mps mps=%d mtu=%d", mps, mtu);
+#endif
+  return mps;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_clean_mdl_cb
+ *
+ * Description  This function clean up the specified MDL control block
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_hl_clean_mdl_cb(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx) {
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_clean_mdl_cb app_idx=%d mcl_idx=%d mdl_idx=%d",
+                   app_idx, mcl_idx, mdl_idx);
+#endif
+  osi_free_and_reset((void**)&p_dcb->p_tx_pkt);
+  osi_free_and_reset((void**)&p_dcb->p_rx_pkt);
+  osi_free_and_reset((void**)&p_dcb->p_echo_tx_pkt);
+  osi_free_and_reset((void**)&p_dcb->p_echo_rx_pkt);
+
+  memset((void*)p_dcb, 0, sizeof(tBTA_HL_MDL_CB));
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_get_buf
+ *
+ * Description  This function allocate a buffer based on the specified data size
+ *
+ * Returns      BT_HDR *.
+ *
+ ******************************************************************************/
+BT_HDR* bta_hl_get_buf(uint16_t data_size, bool fcs_use) {
+  size_t size = data_size + L2CAP_MIN_OFFSET + BT_HDR_SIZE + L2CAP_FCS_LEN +
+                L2CAP_EXT_CONTROL_OVERHEAD;
+
+  if (fcs_use) size += L2CAP_FCS_LEN;
+
+  BT_HDR* p_new = (BT_HDR*)osi_malloc(size);
+  p_new->len = data_size;
+  p_new->offset = L2CAP_MIN_OFFSET;
+
+  return p_new;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_find_service_in_db
+ *
+ * Description  This function check the specified service class(es) can be find
+ *              in the received SDP database
+ *
+ * Returns      bool true - found
+ *                      false - not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_service_in_db(uint8_t app_idx, uint8_t mcl_idx,
+                               uint16_t service_uuid, tSDP_DISC_REC** pp_rec) {
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  bool found = true;
+
+  switch (service_uuid) {
+    case UUID_SERVCLASS_HDP_SINK:
+    case UUID_SERVCLASS_HDP_SOURCE:
+      if ((*pp_rec = SDP_FindServiceInDb(p_mcb->p_db, service_uuid, *pp_rec)) ==
+          NULL) {
+        found = false;
+      }
+      break;
+    default:
+      if ((*pp_rec = bta_hl_find_sink_or_src_srv_class_in_db(
+               p_mcb->p_db, *pp_rec)) == NULL) {
+        found = false;
+      }
+      break;
+  }
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_get_service_uuids
+ *
+ *
+ * Description  This function finds the service class(es) for both CCH and DCH
+ *              operations
+ *
+ * Returns      uint16_t - service_id
+ *                       if service_uuid = 0xFFFF then it means service uuid
+ *                       can be either Sink or Source
+ *
+ ******************************************************************************/
+uint16_t bta_hl_get_service_uuids(uint8_t sdp_oper, uint8_t app_idx,
+                                  uint8_t mcl_idx, uint8_t mdl_idx) {
+  tBTA_HL_MDL_CB* p_dcb;
+  uint16_t service_uuid = 0xFFFF; /* both Sink and Source */
+
+  switch (sdp_oper) {
+    case BTA_HL_SDP_OP_DCH_OPEN_INIT:
+    case BTA_HL_SDP_OP_DCH_RECONNECT_INIT:
+      p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+      if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) {
+        if (p_dcb->peer_mdep_role == BTA_HL_MDEP_ROLE_SINK) {
+          service_uuid = UUID_SERVCLASS_HDP_SINK;
+        } else {
+          service_uuid = UUID_SERVCLASS_HDP_SOURCE;
+        }
+      }
+      break;
+    case BTA_HL_SDP_OP_CCH_INIT:
+    default:
+      /* use default that is both Sink and Source */
+      break;
+  }
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_get_service_uuids service_uuid=0x%x", service_uuid);
+#endif
+  return service_uuid;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_find_echo_cfg_rsp
+ *
+ *
+ * Description  This function finds the configuration response for the echo test
+ *
+ * Returns      bool - true found
+ *                        false not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_echo_cfg_rsp(uint8_t app_idx, uint8_t mcl_idx,
+                              uint8_t mdep_idx, uint8_t cfg,
+                              uint8_t* p_cfg_rsp) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MDEP* p_mdep = &p_acb->sup_feature.mdep[mdep_idx];
+  bool status = true;
+
+  if (p_mdep->mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
+    if ((cfg == BTA_HL_DCH_CFG_RELIABLE) || (cfg == BTA_HL_DCH_CFG_STREAMING)) {
+      *p_cfg_rsp = cfg;
+    } else if (cfg == BTA_HL_DCH_CFG_NO_PREF) {
+      *p_cfg_rsp = BTA_HL_DEFAULT_ECHO_TEST_SRC_DCH_CFG;
+    } else {
+      status = false;
+      APPL_TRACE_ERROR("Inavlid echo cfg value");
+    }
+    return status;
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!status) {
+    APPL_TRACE_DEBUG(
+        "bta_hl_find_echo_cfg_rsp status=failed app_idx=%d mcl_idx=%d "
+        "mdep_idx=%d cfg=%d",
+        app_idx, mcl_idx, mdep_idx, cfg);
+  }
+#endif
+
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_validate_dch_cfg
+ *
+ * Description  This function validate the DCH configuration
+ *
+ * Returns      bool - true cfg is valid
+ *                        false not valid
+ *
+ ******************************************************************************/
+bool bta_hl_validate_cfg(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+                         uint8_t cfg) {
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  bool is_valid = false;
+
+  if (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx) &&
+      (cfg != BTA_HL_DCH_CFG_RELIABLE)) {
+    APPL_TRACE_ERROR("the first DCH should be a reliable channel");
+    return is_valid;
+  }
+
+  switch (p_dcb->local_cfg) {
+    case BTA_HL_DCH_CFG_NO_PREF:
+
+      if ((cfg == BTA_HL_DCH_CFG_RELIABLE) ||
+          (cfg == BTA_HL_DCH_CFG_STREAMING)) {
+        is_valid = true;
+      }
+      break;
+    case BTA_HL_DCH_CFG_RELIABLE:
+    case BTA_HL_DCH_CFG_STREAMING:
+      if (p_dcb->local_cfg == cfg) {
+        is_valid = true;
+      }
+      break;
+    default:
+      break;
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!is_valid) {
+    APPL_TRACE_DEBUG("bta_hl_validate_dch_open_cfg is_valid=%d, cfg=%d",
+                     is_valid, cfg);
+  }
+#endif
+  return is_valid;
+}
+
+/*******************************************************************************
+ *
+ * Function       bta_hl_find_cch_cb_indexes
+ *
+ * Description  This function finds the indexes needed for the CCH state machine
+ *
+ * Returns      bool - true found
+ *                        false not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_cch_cb_indexes(tBTA_HL_DATA* p_msg, uint8_t* p_app_idx,
+                                uint8_t* p_mcl_idx) {
+  bool found = false;
+  tBTA_HL_MCL_CB* p_mcb;
+  uint8_t app_idx = 0, mcl_idx = 0;
+
+  switch (p_msg->hdr.event) {
+    case BTA_HL_CCH_SDP_OK_EVT:
+    case BTA_HL_CCH_SDP_FAIL_EVT:
+      app_idx = p_msg->cch_sdp.app_idx;
+      mcl_idx = p_msg->cch_sdp.mcl_idx;
+      found = true;
+      break;
+
+    case BTA_HL_MCA_CONNECT_IND_EVT:
+
+      if (bta_hl_find_app_idx_using_handle(p_msg->mca_evt.app_handle,
+                                           &app_idx)) {
+        if (bta_hl_find_mcl_idx(app_idx,
+                                p_msg->mca_evt.mca_data.connect_ind.bd_addr,
+                                &mcl_idx)) {
+          /* local initiated */
+          found = true;
+        } else if (!bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle,
+                                                     &app_idx, &mcl_idx) &&
+                   bta_hl_find_avail_mcl_idx(app_idx, &mcl_idx)) {
+          /* remote initiated */
+          p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+          p_mcb->in_use = true;
+          p_mcb->cch_oper = BTA_HL_CCH_OP_REMOTE_OPEN;
+          found = true;
+        }
+      }
+      break;
+
+    case BTA_HL_MCA_DISCONNECT_IND_EVT:
+
+      if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
+                                           &mcl_idx)) {
+        found = true;
+      } else if (bta_hl_find_app_idx_using_handle(p_msg->mca_evt.app_handle,
+                                                  &app_idx) &&
+                 bta_hl_find_mcl_idx(
+                     app_idx, p_msg->mca_evt.mca_data.disconnect_ind.bd_addr,
+                     &mcl_idx)) {
+        found = true;
+      }
+
+      if (found) {
+        p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+        if ((p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_CLOSE) &&
+            (p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_OPEN)) {
+          p_mcb->cch_oper = BTA_HL_CCH_OP_REMOTE_CLOSE;
+        }
+      }
+      break;
+
+    case BTA_HL_MCA_RSP_TOUT_IND_EVT:
+
+      if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
+                                           &mcl_idx)) {
+        found = true;
+      }
+
+      if (found) {
+        p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+        if ((p_mcb->cch_oper != BTA_HL_CCH_OP_REMOTE_CLOSE) &&
+            (p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_OPEN)) {
+          p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_CLOSE;
+        }
+      }
+      break;
+    default:
+      break;
+  }
+
+  if (found) {
+    *p_app_idx = app_idx;
+    *p_mcl_idx = mcl_idx;
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!found) {
+    APPL_TRACE_DEBUG(
+        "bta_hl_find_cch_cb_indexes event=%s found=%d app_idx=%d mcl_idx=%d",
+        bta_hl_evt_code(p_msg->hdr.event), found, app_idx, mcl_idx);
+  }
+#endif
+
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function       bta_hl_find_dch_cb_indexes
+ *
+ * Description  This function finds the indexes needed for the DCH state machine
+ *
+ * Returns      bool - true found
+ *                        false not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_dch_cb_indexes(tBTA_HL_DATA* p_msg, uint8_t* p_app_idx,
+                                uint8_t* p_mcl_idx, uint8_t* p_mdl_idx) {
+  bool found = false;
+  tBTA_HL_MCL_CB* p_mcb;
+  uint8_t app_idx = 0, mcl_idx = 0, mdl_idx = 0;
+
+  switch (p_msg->hdr.event) {
+    case BTA_HL_MCA_CREATE_CFM_EVT:
+      if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
+                                           &mcl_idx) &&
+          bta_hl_find_mdl_idx(app_idx, mcl_idx,
+                              p_msg->mca_evt.mca_data.create_cfm.mdl_id,
+                              &mdl_idx)) {
+        found = true;
+      }
+      break;
+
+    case BTA_HL_MCA_CREATE_IND_EVT:
+    case BTA_HL_MCA_RECONNECT_IND_EVT:
+      if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
+                                           &mcl_idx) &&
+          bta_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
+        found = true;
+      }
+      break;
+
+    case BTA_HL_MCA_OPEN_CFM_EVT:
+      if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
+                                           &mcl_idx) &&
+          bta_hl_find_mdl_idx(app_idx, mcl_idx,
+                              p_msg->mca_evt.mca_data.open_cfm.mdl_id,
+                              &mdl_idx)) {
+        found = true;
+      }
+      break;
+
+    case BTA_HL_MCA_OPEN_IND_EVT:
+      if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
+                                           &mcl_idx) &&
+          bta_hl_find_mdl_idx(app_idx, mcl_idx,
+                              p_msg->mca_evt.mca_data.open_ind.mdl_id,
+                              &mdl_idx)) {
+        found = true;
+      }
+      break;
+
+    case BTA_HL_MCA_CLOSE_CFM_EVT:
+
+      if (bta_hl_find_mdl_idx_using_handle(
+              (tBTA_HL_MDL_HANDLE)p_msg->mca_evt.mca_data.close_cfm.mdl,
+              &app_idx, &mcl_idx, &mdl_idx)) {
+        found = true;
+      }
+      break;
+    case BTA_HL_MCA_CLOSE_IND_EVT:
+
+      if (bta_hl_find_mdl_idx_using_handle(
+              (tBTA_HL_MDL_HANDLE)p_msg->mca_evt.mca_data.close_ind.mdl,
+              &app_idx, &mcl_idx, &mdl_idx)) {
+        found = true;
+      }
+      break;
+    case BTA_HL_API_SEND_DATA_EVT:
+
+      if (bta_hl_find_mdl_idx_using_handle(p_msg->api_send_data.mdl_handle,
+                                           &app_idx, &mcl_idx, &mdl_idx)) {
+        found = true;
+      }
+
+      break;
+
+    case BTA_HL_MCA_CONG_CHG_EVT:
+
+      if (bta_hl_find_mdl_idx_using_handle(
+              (tBTA_HL_MDL_HANDLE)p_msg->mca_evt.mca_data.cong_chg.mdl,
+              &app_idx, &mcl_idx, &mdl_idx)) {
+        found = true;
+      }
+
+      break;
+
+    case BTA_HL_MCA_RCV_DATA_EVT:
+      app_idx = p_msg->mca_rcv_data_evt.app_idx;
+      mcl_idx = p_msg->mca_rcv_data_evt.mcl_idx;
+      mdl_idx = p_msg->mca_rcv_data_evt.mdl_idx;
+      found = true;
+      break;
+    case BTA_HL_DCH_RECONNECT_EVT:
+    case BTA_HL_DCH_OPEN_EVT:
+    case BTA_HL_DCH_ECHO_TEST_EVT:
+    case BTA_HL_DCH_SDP_FAIL_EVT:
+      app_idx = p_msg->dch_sdp.app_idx;
+      mcl_idx = p_msg->dch_sdp.mcl_idx;
+      mdl_idx = p_msg->dch_sdp.mdl_idx;
+      found = true;
+      break;
+    case BTA_HL_MCA_RECONNECT_CFM_EVT:
+      if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
+                                           &mcl_idx) &&
+          bta_hl_find_mdl_idx(app_idx, mcl_idx,
+                              p_msg->mca_evt.mca_data.reconnect_cfm.mdl_id,
+                              &mdl_idx)) {
+        found = true;
+      }
+      break;
+
+    case BTA_HL_API_DCH_CREATE_RSP_EVT:
+      if (bta_hl_find_mcl_idx_using_handle(p_msg->api_dch_create_rsp.mcl_handle,
+                                           &app_idx, &mcl_idx) &&
+          bta_hl_find_mdl_idx(app_idx, mcl_idx,
+                              p_msg->api_dch_create_rsp.mdl_id, &mdl_idx)) {
+        found = true;
+      }
+      break;
+    case BTA_HL_MCA_ABORT_IND_EVT:
+      if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
+                                           &mcl_idx) &&
+          bta_hl_find_mdl_idx(app_idx, mcl_idx,
+                              p_msg->mca_evt.mca_data.abort_ind.mdl_id,
+                              &mdl_idx)) {
+        found = true;
+      }
+      break;
+    case BTA_HL_MCA_ABORT_CFM_EVT:
+      if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
+                                           &mcl_idx) &&
+          bta_hl_find_mdl_idx(app_idx, mcl_idx,
+                              p_msg->mca_evt.mca_data.abort_cfm.mdl_id,
+                              &mdl_idx)) {
+        found = true;
+      }
+      break;
+    case BTA_HL_CI_GET_TX_DATA_EVT:
+    case BTA_HL_CI_PUT_RX_DATA_EVT:
+      if (bta_hl_find_mdl_idx_using_handle(p_msg->ci_get_put_data.mdl_handle,
+                                           &app_idx, &mcl_idx, &mdl_idx)) {
+        found = true;
+      }
+      break;
+    case BTA_HL_CI_GET_ECHO_DATA_EVT:
+    case BTA_HL_CI_PUT_ECHO_DATA_EVT:
+      if (bta_hl_find_mcl_idx_using_handle(
+              p_msg->ci_get_put_echo_data.mcl_handle, &app_idx, &mcl_idx)) {
+        p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+        mdl_idx = p_mcb->echo_mdl_idx;
+        found = true;
+      }
+      break;
+
+    default:
+      break;
+  }
+
+  if (found) {
+    *p_app_idx = app_idx;
+    *p_mcl_idx = mcl_idx;
+    *p_mdl_idx = mdl_idx;
+  }
+#if (BTA_HL_DEBUG == TRUE)
+  if (!found) {
+    APPL_TRACE_DEBUG(
+        "bta_hl_find_dch_cb_indexes event=%s found=%d app_idx=%d mcl_idx=%d "
+        "mdl_idx=%d",
+        bta_hl_evt_code(p_msg->hdr.event), found, *p_app_idx, *p_mcl_idx,
+        *p_mdl_idx);
+  }
+#endif
+
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_allocate_mdl_id
+ *
+ * Description  This function allocates a MDL ID
+ *
+ * Returns      uint16_t - MDL ID
+ *
+ ******************************************************************************/
+uint16_t bta_hl_allocate_mdl_id(uint8_t app_idx, uint8_t mcl_idx,
+                                uint8_t mdl_idx) {
+  uint16_t mdl_id = 0;
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  bool duplicate_id;
+  uint8_t i, mdl_cfg_idx;
+
+  do {
+    duplicate_id = false;
+    mdl_id = ((mdl_id + 1) & 0xFEFF);
+    /* check mdl_ids that are used for the current conenctions */
+    for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+      if (p_mcb->mdl[i].in_use && (i != mdl_idx) &&
+          (p_mcb->mdl[i].mdl_id == mdl_id)) {
+        duplicate_id = true;
+        break;
+      }
+    }
+
+    if (duplicate_id) {
+      /* start from the beginning to get another MDL value*/
+      continue;
+    } else {
+      /* check mdl_ids that are stored in the persistent memory */
+      if (bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, mdl_id, &mdl_cfg_idx)) {
+        duplicate_id = true;
+      } else {
+        /* found a new MDL value */
+        break;
+      }
+    }
+
+  } while (true);
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_allocate_mdl OK mdl_id=%d", mdl_id);
+#endif
+  return mdl_id;
+}
+/*******************************************************************************
+ *
+ * Function      bta_hl_find_mdl_idx
+ *
+ * Description  This function finds the MDL index based on mdl_id
+ *
+ * Returns      bool true-found
+ *
+ ******************************************************************************/
+bool bta_hl_find_mdl_idx(uint8_t app_idx, uint8_t mcl_idx, uint16_t mdl_id,
+                         uint8_t* p_mdl_idx) {
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+    if (p_mcb->mdl[i].in_use && (mdl_id != 0) &&
+        (p_mcb->mdl[i].mdl_id == mdl_id)) {
+      found = true;
+      *p_mdl_idx = i;
+      break;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!found) {
+    APPL_TRACE_DEBUG("bta_hl_find_mdl_idx found=%d mdl_id=%d mdl_idx=%d ",
+                     found, mdl_id, i);
+  }
+#endif
+
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_find_an_active_mdl_idx
+ *
+ * Description  This function finds an active MDL
+ *
+ * Returns      bool true-found
+ *
+ ******************************************************************************/
+bool bta_hl_find_an_active_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
+                                   uint8_t* p_mdl_idx) {
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+    if (p_mcb->mdl[i].in_use &&
+        (p_mcb->mdl[i].dch_state == BTA_HL_DCH_OPEN_ST)) {
+      found = true;
+      *p_mdl_idx = i;
+      break;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (found) {
+    APPL_TRACE_DEBUG(
+        "bta_hl_find_an_opened_mdl_idx found=%d app_idx=%d mcl_idx=%d "
+        "mdl_idx=%d",
+        found, app_idx, mcl_idx, i);
+  }
+#endif
+
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_find_dch_setup_mdl_idx
+ *
+ * Description  This function finds a MDL which in the DCH setup state
+ *
+ * Returns      bool true-found
+ *
+ ******************************************************************************/
+bool bta_hl_find_dch_setup_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
+                                   uint8_t* p_mdl_idx) {
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+    if (p_mcb->mdl[i].in_use &&
+        (p_mcb->mdl[i].dch_state == BTA_HL_DCH_OPENING_ST)) {
+      found = true;
+      *p_mdl_idx = i;
+      break;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (found) {
+    APPL_TRACE_DEBUG(
+        "bta_hl_find_dch_setup_mdl_idx found=%d app_idx=%d mcl_idx=%d "
+        "mdl_idx=%d",
+        found, app_idx, mcl_idx, i);
+  }
+#endif
+
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_find_an_in_use_mcl_idx
+ *
+ * Description  This function finds an in-use MCL control block index
+ *
+ * Returns      bool true-found
+ *
+ ******************************************************************************/
+bool bta_hl_find_an_in_use_mcl_idx(uint8_t app_idx, uint8_t* p_mcl_idx) {
+  tBTA_HL_MCL_CB* p_mcb;
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_MCLS; i++) {
+    p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, i);
+    if (p_mcb->in_use && (p_mcb->cch_state != BTA_HL_CCH_IDLE_ST)) {
+      found = true;
+      *p_mcl_idx = i;
+      break;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (found) {
+    APPL_TRACE_DEBUG(
+        "bta_hl_find_an_in_use_mcl_idx found=%d app_idx=%d mcl_idx=%d ", found,
+        app_idx, i);
+  }
+#endif
+
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_find_an_in_use_app_idx
+ *
+ * Description  This function finds an in-use application control block index
+ *
+ * Returns      bool true-found
+ *
+ ******************************************************************************/
+bool bta_hl_find_an_in_use_app_idx(uint8_t* p_app_idx) {
+  tBTA_HL_APP_CB* p_acb;
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    p_acb = BTA_HL_GET_APP_CB_PTR(i);
+    if (p_acb->in_use) {
+      found = true;
+      *p_app_idx = i;
+      break;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (found) {
+    APPL_TRACE_DEBUG("bta_hl_find_an_in_use_app_idx found=%d app_idx=%d ",
+                     found, i);
+  }
+#endif
+
+  return found;
+}
+/*******************************************************************************
+ *
+ * Function      bta_hl_find_app_idx
+ *
+ * Description  This function finds the application control block index based on
+ *              the application ID
+ *
+ * Returns      bool true-found
+ *
+ ******************************************************************************/
+bool bta_hl_find_app_idx(uint8_t app_id, uint8_t* p_app_idx) {
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    if (bta_hl_cb.acb[i].in_use && (bta_hl_cb.acb[i].app_id == app_id)) {
+      found = true;
+      *p_app_idx = i;
+      break;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_find_app_idx found=%d app_id=%d idx=%d ", found,
+                   app_id, i);
+#endif
+
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_find_app_idx_using_handle
+ *
+ * Description  This function finds the application control block index based on
+ *              the application handle
+ *
+ * Returns      bool true-found
+ *
+ ******************************************************************************/
+bool bta_hl_find_app_idx_using_handle(tBTA_HL_APP_HANDLE app_handle,
+                                      uint8_t* p_app_idx) {
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    if (bta_hl_cb.acb[i].in_use &&
+        (bta_hl_cb.acb[i].app_handle == app_handle)) {
+      found = true;
+      *p_app_idx = i;
+      break;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!found) {
+    APPL_TRACE_DEBUG(
+        "bta_hl_find_app_idx_using_mca_handle status=%d handle=%d app_idx=%d ",
+        found, app_handle, i);
+  }
+#endif
+
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_find_mcl_idx_using_handle
+ *
+ * Description  This function finds the MCL control block index based on
+ *              the MCL handle
+ *
+ * Returns      bool true-found
+ *
+ ******************************************************************************/
+bool bta_hl_find_mcl_idx_using_handle(tBTA_HL_MCL_HANDLE mcl_handle,
+                                      uint8_t* p_app_idx, uint8_t* p_mcl_idx) {
+  tBTA_HL_APP_CB* p_acb;
+  bool found = false;
+  uint8_t i = 0, j = 0;
+
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    p_acb = BTA_HL_GET_APP_CB_PTR(i);
+    if (p_acb->in_use) {
+      for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+        if (p_acb->mcb[j].mcl_handle == mcl_handle) {
+          found = true;
+          *p_app_idx = i;
+          *p_mcl_idx = j;
+          break;
+        }
+      }
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!found) {
+    APPL_TRACE_DEBUG(
+        "bta_hl_find_mcl_idx_using_handle found=%d app_idx=%d mcl_idx=%d",
+        found, i, j);
+  }
+#endif
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_find_mcl_idx
+ *
+ * Description  This function finds the MCL control block index based on
+ *              the peer BD address
+ *
+ * Returns      bool true-found
+ *
+ ******************************************************************************/
+bool bta_hl_find_mcl_idx(uint8_t app_idx, BD_ADDR p_bd_addr,
+                         uint8_t* p_mcl_idx) {
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_MCLS; i++) {
+    if (bta_hl_cb.acb[app_idx].mcb[i].in_use &&
+        (!memcmp(bta_hl_cb.acb[app_idx].mcb[i].bd_addr, p_bd_addr,
+                 BD_ADDR_LEN))) {
+      found = true;
+      *p_mcl_idx = i;
+      break;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!found) {
+    APPL_TRACE_DEBUG("bta_hl_find_mcl_idx found=%d idx=%d", found, i);
+  }
+#endif
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_find_mdl_idx_using_handle
+ *
+ * Description  This function finds the MDL control block index based on
+ *              the MDL handle
+ *
+ * Returns      bool true-found
+ *
+ ******************************************************************************/
+bool bta_hl_find_mdl_idx_using_handle(tBTA_HL_MDL_HANDLE mdl_handle,
+                                      uint8_t* p_app_idx, uint8_t* p_mcl_idx,
+                                      uint8_t* p_mdl_idx) {
+  tBTA_HL_APP_CB* p_acb;
+  tBTA_HL_MCL_CB* p_mcb;
+  tBTA_HL_MDL_CB* p_dcb;
+  bool found = false;
+  uint8_t i, j, k;
+
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    p_acb = BTA_HL_GET_APP_CB_PTR(i);
+    if (p_acb->in_use) {
+      for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+        p_mcb = BTA_HL_GET_MCL_CB_PTR(i, j);
+        if (p_mcb->in_use) {
+          for (k = 0; k < BTA_HL_NUM_MDLS_PER_MCL; k++) {
+            p_dcb = BTA_HL_GET_MDL_CB_PTR(i, j, k);
+            if (p_dcb->in_use) {
+              if (p_dcb->mdl_handle == mdl_handle) {
+                found = true;
+                *p_app_idx = i;
+                *p_mcl_idx = j;
+                *p_mdl_idx = k;
+                break;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!found) {
+    APPL_TRACE_DEBUG(
+        "bta_hl_find_mdl_idx_using_handle found=%d mdl_handle=%d  ", found,
+        mdl_handle);
+  }
+#endif
+  return found;
+}
+/*******************************************************************************
+ *
+ * Function      bta_hl_is_the_first_reliable_existed
+ *
+ * Description  This function checks whether the first reliable DCH channel
+ *              has been setup on the MCL or not
+ *
+ * Returns      bool - true exist
+ *                        false does not exist
+ *
+ ******************************************************************************/
+bool bta_hl_is_the_first_reliable_existed(uint8_t app_idx, uint8_t mcl_idx) {
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  bool is_existed = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+    if (p_mcb->mdl[i].in_use && p_mcb->mdl[i].is_the_first_reliable) {
+      is_existed = true;
+      break;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_is_the_first_reliable_existed is_existed=%d  ",
+                   is_existed);
+#endif
+  return is_existed;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_find_non_active_mdl_cfg
+ *
+ * Description  This function finds a valid MDL configiration index and this
+ *              MDL ID is not active
+ *
+ * Returns      bool - true found
+ *                        false not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_non_active_mdl_cfg(uint8_t app_idx, uint8_t start_mdl_cfg_idx,
+                                    uint8_t* p_mdl_cfg_idx) {
+  tBTA_HL_MCL_CB* p_mcb;
+  tBTA_HL_MDL_CB* p_dcb;
+  tBTA_HL_MDL_CFG* p_mdl;
+  bool mdl_in_use;
+  bool found = false;
+  uint8_t i, j, k;
+
+  for (i = start_mdl_cfg_idx; i < BTA_HL_NUM_MDL_CFGS; i++) {
+    mdl_in_use = false;
+    p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
+    for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+      p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, j);
+      if (p_mcb->in_use &&
+          !memcmp(p_mdl->peer_bd_addr, p_mcb->bd_addr, BD_ADDR_LEN)) {
+        for (k = 0; k < BTA_HL_NUM_MDLS_PER_MCL; k++) {
+          p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, j, k);
+
+          if (p_dcb->in_use && p_mdl->mdl_id == p_dcb->mdl_id) {
+            mdl_in_use = true;
+            break;
+          }
+        }
+      }
+
+      if (mdl_in_use) {
+        break;
+      }
+    }
+
+    if (!mdl_in_use) {
+      *p_mdl_cfg_idx = i;
+      found = true;
+      break;
+    }
+  }
+
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_find_mdl_cfg_idx
+ *
+ * Description  This function finds an available MDL configuration index
+ *
+ * Returns      bool - true found
+ *                        false not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_avail_mdl_cfg_idx(uint8_t app_idx, UNUSED_ATTR uint8_t mcl_idx,
+                                   uint8_t* p_mdl_cfg_idx) {
+  tBTA_HL_MDL_CFG *p_mdl, *p_mdl1, *p_mdl2;
+  uint8_t i;
+  bool found = false;
+  uint8_t first_mdl_cfg_idx, second_mdl_cfg_idx, older_mdl_cfg_idx;
+  bool done;
+
+  for (i = 0; i < BTA_HL_NUM_MDL_CFGS; i++) {
+    p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
+    if (!p_mdl->active) {
+      /* found an unused space to store mdl cfg*/
+      found = true;
+      *p_mdl_cfg_idx = i;
+      break;
+    }
+  }
+
+  if (!found) {
+    /* all available mdl cfg spaces are in use so we need to find the mdl cfg
+    which is
+    not currently in use and has the the oldest time stamp to remove*/
+
+    found = true;
+    if (bta_hl_find_non_active_mdl_cfg(app_idx, 0, &first_mdl_cfg_idx)) {
+      if (bta_hl_find_non_active_mdl_cfg(
+              app_idx, (uint8_t)(first_mdl_cfg_idx + 1), &second_mdl_cfg_idx)) {
+        done = false;
+        while (!done) {
+          p_mdl1 = BTA_HL_GET_MDL_CFG_PTR(app_idx, first_mdl_cfg_idx);
+          p_mdl2 = BTA_HL_GET_MDL_CFG_PTR(app_idx, second_mdl_cfg_idx);
+
+          if (p_mdl1->time < p_mdl2->time) {
+            older_mdl_cfg_idx = first_mdl_cfg_idx;
+          } else {
+            older_mdl_cfg_idx = second_mdl_cfg_idx;
+          }
+
+          if (bta_hl_find_non_active_mdl_cfg(app_idx,
+                                             (uint8_t)(second_mdl_cfg_idx + 1),
+                                             &second_mdl_cfg_idx)) {
+            first_mdl_cfg_idx = older_mdl_cfg_idx;
+          } else {
+            done = true;
+          }
+        }
+
+        *p_mdl_cfg_idx = older_mdl_cfg_idx;
+
+      } else {
+        *p_mdl_cfg_idx = first_mdl_cfg_idx;
+      }
+
+    } else {
+      found = false;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!found) {
+    APPL_TRACE_DEBUG("bta_hl_find_avail_mdl_cfg_idx found=%d mdl_cfg_idx=%d ",
+                     found, *p_mdl_cfg_idx);
+  }
+#endif
+
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_find_mdl_cfg_idx
+ *
+ * Description  This function finds the MDL configuration index based on
+ *              the MDL ID
+ *
+ * Returns      bool - true found
+ *                        false not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_mdl_cfg_idx(uint8_t app_idx, uint8_t mcl_idx,
+                             tBTA_HL_MDL_ID mdl_id, uint8_t* p_mdl_cfg_idx) {
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CFG* p_mdl;
+  uint8_t i;
+  bool found = false;
+
+  *p_mdl_cfg_idx = 0;
+  for (i = 0; i < BTA_HL_NUM_MDL_CFGS; i++) {
+    p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
+    if (p_mdl->active)
+      APPL_TRACE_DEBUG("bta_hl_find_mdl_cfg_idx: mdl_id =%d, p_mdl->mdl_id=%d",
+                       mdl_id, p_mdl->mdl_id);
+    if (p_mdl->active &&
+        (!memcmp(p_mcb->bd_addr, p_mdl->peer_bd_addr, BD_ADDR_LEN)) &&
+        (p_mdl->mdl_id == mdl_id)) {
+      found = true;
+      *p_mdl_cfg_idx = i;
+      break;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!found) {
+    APPL_TRACE_DEBUG("bta_hl_find_mdl_cfg_idx found=%d mdl_cfg_idx=%d ", found,
+                     i);
+  }
+#endif
+
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_get_cur_time
+ *
+ * Description  This function get the cuurent time value
+ *
+ * Returns      bool - true found
+ *                        false not found
+ *
+ ******************************************************************************/
+bool bta_hl_get_cur_time(uint8_t app_idx, uint8_t* p_cur_time) {
+  tBTA_HL_MDL_CFG* p_mdl;
+  uint8_t i, j, time_latest, time;
+  bool found = false, result = true;
+
+  for (i = 0; i < BTA_HL_NUM_MDL_CFGS; i++) {
+    p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
+    if (p_mdl->active) {
+      found = true;
+      time_latest = p_mdl->time;
+      for (j = (i + 1); j < BTA_HL_NUM_MDL_CFGS; j++) {
+        p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, j);
+        if (p_mdl->active) {
+          time = p_mdl->time;
+          if (time > time_latest) {
+            time_latest = time;
+          }
+        }
+      }
+      break;
+    }
+  }
+
+  if (found) {
+    if (time_latest < BTA_HL_MAX_TIME) {
+      *p_cur_time = time_latest + 1;
+    } else {
+      /* need to wrap around */
+      result = false;
+    }
+  } else {
+    *p_cur_time = BTA_HL_MIN_TIME;
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!result) {
+    APPL_TRACE_DEBUG("bta_hl_get_cur_time result=%s cur_time=%d",
+                     (result ? "OK" : "FAIL"), *p_cur_time);
+  }
+#endif
+
+  return result;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_sort_cfg_time_idx
+ *
+ * Description  This function sort the mdl configuration idx stored in array a
+ *              based on decending time value
+ *
+ * Returns      bool - true found
+ *                        false not found
+ *
+ ******************************************************************************/
+void bta_hl_sort_cfg_time_idx(uint8_t app_idx, uint8_t* a, uint8_t n) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  uint8_t temp_time, temp_idx;
+  int16_t i, j;
+  for (i = 1; i < n; ++i) {
+    temp_idx = a[i];
+    temp_time = p_acb->mdl_cfg[temp_idx].time;
+    j = i - 1;
+    while ((j >= 0) && (temp_time < p_acb->mdl_cfg[a[j]].time)) {
+      a[j + 1] = a[j];
+      --j;
+    }
+    a[j + 1] = temp_idx;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_compact_mdl_cfg_time
+ *
+ * Description  This function finds the MDL configuration index based on
+ *              the MDL ID
+ *
+ * Returns      bool - true found
+ *                        false not found
+ *
+ ******************************************************************************/
+void bta_hl_compact_mdl_cfg_time(uint8_t app_idx, uint8_t mdep_id) {
+  tBTA_HL_MDL_CFG* p_mdl;
+  uint8_t i, time_min, cnt = 0;
+  uint8_t s_arr[BTA_HL_NUM_MDL_CFGS];
+
+  for (i = 0; i < BTA_HL_NUM_MDL_CFGS; i++) {
+    p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
+    if (p_mdl->active) {
+      s_arr[cnt] = i;
+      cnt++;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_compact_mdl_cfg_time cnt=%d ", cnt);
+#endif
+
+  if (cnt) {
+    bta_hl_sort_cfg_time_idx(app_idx, s_arr, cnt);
+    time_min = BTA_HL_MIN_TIME;
+    for (i = 0; i < cnt; i++) {
+      p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, s_arr[i]);
+      p_mdl->time = time_min + i;
+      bta_hl_co_save_mdl(mdep_id, s_arr[i], p_mdl);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_is_mdl_exsit_in_mcl
+ *
+ * Description  This function checks whether the MDL ID
+ *              has already existed in teh MCL or not
+ *
+ * Returns      bool - true exist
+ *                        false does not exist
+ *
+ ******************************************************************************/
+bool bta_hl_is_mdl_exsit_in_mcl(uint8_t app_idx, BD_ADDR bd_addr,
+                                tBTA_HL_MDL_ID mdl_id) {
+  tBTA_HL_MDL_CFG* p_mdl;
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_MDL_CFGS; i++) {
+    p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
+    if (p_mdl->active && !memcmp(p_mdl->peer_bd_addr, bd_addr, BD_ADDR_LEN)) {
+      if (mdl_id != BTA_HL_DELETE_ALL_MDL_IDS) {
+        if (p_mdl->mdl_id == mdl_id) {
+          found = true;
+          break;
+        }
+      } else {
+        found = true;
+        break;
+      }
+    }
+  }
+
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_delete_mdl_cfg
+ *
+ * Description  This function delete the specified MDL ID
+ *
+ * Returns      bool - true Success
+ *                        false Failed
+ *
+ ******************************************************************************/
+bool bta_hl_delete_mdl_cfg(uint8_t app_idx, BD_ADDR bd_addr,
+                           tBTA_HL_MDL_ID mdl_id) {
+  tBTA_HL_MDL_CFG* p_mdl;
+  bool success = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_MDL_CFGS; i++) {
+    p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
+    if (p_mdl->active && !memcmp(p_mdl->peer_bd_addr, bd_addr, BD_ADDR_LEN)) {
+      if (mdl_id != BTA_HL_DELETE_ALL_MDL_IDS) {
+        if (p_mdl->mdl_id == mdl_id) {
+          bta_hl_co_delete_mdl(p_mdl->local_mdep_id, i);
+          memset(p_mdl, 0, sizeof(tBTA_HL_MDL_CFG));
+          success = true;
+          break;
+        }
+      } else {
+        bta_hl_co_delete_mdl(p_mdl->local_mdep_id, i);
+        memset(p_mdl, 0, sizeof(tBTA_HL_MDL_CFG));
+        success = true;
+      }
+    }
+  }
+
+  return success;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_is_mdl_value_valid
+ *
+ *
+ * Description  This function checks the specified MDL ID is in valid range.
+ *
+ * Returns      bool - true Success
+ *                        false Failed
+ *
+ * note:   mdl_id range   0x0000 reserved,
+ *                        0x0001-oxFEFF dynamic range,
+ *                        0xFF00-0xFFFE reserved,
+ *                        0xFFFF indicates all MDLs (for delete operation only)
+ *
+ ******************************************************************************/
+bool bta_hl_is_mdl_value_valid(tBTA_HL_MDL_ID mdl_id) {
+  bool status = true;
+
+  if (mdl_id != BTA_HL_DELETE_ALL_MDL_IDS) {
+    if (mdl_id != 0) {
+      if (mdl_id > BTA_HL_MAX_MDL_VAL) {
+        status = false;
+      }
+    } else {
+      status = false;
+    }
+  }
+
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_find_mdep_cfg_idx
+ *
+ * Description  This function finds the MDEP configuration index based
+ *                on the local MDEP ID
+ *
+ * Returns      bool - true found
+ *                        false not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_mdep_cfg_idx(uint8_t app_idx, tBTA_HL_MDEP_ID local_mdep_id,
+                              uint8_t* p_mdep_cfg_idx) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_SUP_FEATURE* p_sup_feature = &p_acb->sup_feature;
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < p_sup_feature->num_of_mdeps; i++) {
+    if (p_sup_feature->mdep[i].mdep_id == local_mdep_id) {
+      found = true;
+      *p_mdep_cfg_idx = i;
+      break;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!found) {
+    APPL_TRACE_DEBUG(
+        "bta_hl_find_mdep_cfg_idx found=%d mdep_idx=%d local_mdep_id=%d ",
+        found, i, local_mdep_id);
+  }
+#endif
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_find_rxtx_apdu_size
+ *
+ * Description  This function finds the maximum APDU rx and tx sizes based on
+ *              the MDEP configuration data
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_hl_find_rxtx_apdu_size(uint8_t app_idx, uint8_t mdep_cfg_idx,
+                                uint16_t* p_rx_apu_size,
+                                uint16_t* p_tx_apu_size) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MDEP_CFG* p_mdep_cfg;
+  uint8_t i;
+  uint16_t max_rx_apdu_size = 0, max_tx_apdu_size = 0;
+
+  p_mdep_cfg = &p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg;
+
+  for (i = 0; i < p_mdep_cfg->num_of_mdep_data_types; i++) {
+    if (max_rx_apdu_size < p_mdep_cfg->data_cfg[i].max_rx_apdu_size) {
+      max_rx_apdu_size = p_mdep_cfg->data_cfg[i].max_rx_apdu_size;
+    }
+
+    if (max_tx_apdu_size < p_mdep_cfg->data_cfg[i].max_tx_apdu_size) {
+      max_tx_apdu_size = p_mdep_cfg->data_cfg[i].max_tx_apdu_size;
+    }
+  }
+
+  *p_rx_apu_size = max_rx_apdu_size;
+  *p_tx_apu_size = max_tx_apdu_size;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG(
+      "bta_hl_find_rxtx_apdu_size max_rx_apdu_size=%d max_tx_apdu_size=%d ",
+      max_rx_apdu_size, max_tx_apdu_size);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_validate_peer_cfg
+ *
+ * Description  This function validates the peer DCH configuration
+ *
+ * Returns      bool - true validation is successful
+ *                        false validation failed
+ *
+ ******************************************************************************/
+bool bta_hl_validate_peer_cfg(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+                              tBTA_HL_MDEP_ID peer_mdep_id,
+                              tBTA_HL_MDEP_ROLE peer_mdep_role,
+                              uint8_t sdp_idx) {
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  tBTA_HL_SDP_REC* p_rec;
+  bool peer_found = false;
+  uint8_t i;
+
+  APPL_TRACE_DEBUG("bta_hl_validate_peer_cfg sdp_idx=%d app_idx %d", sdp_idx,
+                   app_idx);
+
+  if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
+    return true;
+  }
+
+  p_rec = &p_mcb->sdp.sdp_rec[sdp_idx];
+  for (i = 0; i < p_rec->num_mdeps; i++) {
+    APPL_TRACE_DEBUG("mdep_id %d peer_mdep_id %d", p_rec->mdep_cfg[i].mdep_id,
+                     peer_mdep_id);
+    APPL_TRACE_DEBUG("mdep_role %d peer_mdep_role %d",
+                     p_rec->mdep_cfg[i].mdep_role, peer_mdep_role)
+    if ((p_rec->mdep_cfg[i].mdep_id == peer_mdep_id) &&
+        (p_rec->mdep_cfg[i].mdep_role == peer_mdep_role)) {
+      peer_found = true;
+
+      break;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!peer_found) {
+    APPL_TRACE_DEBUG("bta_hl_validate_peer_cfg failed num_mdeps=%d",
+                     p_rec->num_mdeps);
+  }
+#endif
+  return peer_found;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_chk_local_cfg
+ *
+ * Description  This function check whether the local DCH configuration is OK.
+ *
+ * Returns      tBTA_HL_STATUS - OK - local DCH configuration is OK
+ *                               NO_FIRST_RELIABLE - the streaming DCH
+ *                                                   configuration is not OK and
+ *                                                   it needs to use reliable
+ *                                                   DCH configuration
+ *
+ ******************************************************************************/
+tBTA_HL_STATUS bta_hl_chk_local_cfg(uint8_t app_idx, uint8_t mcl_idx,
+                                    uint8_t mdep_cfg_idx,
+                                    tBTA_HL_DCH_CFG local_cfg) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+
+  if (mdep_cfg_idx &&
+      (p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg.mdep_role ==
+       BTA_HL_MDEP_ROLE_SOURCE) &&
+      (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx)) &&
+      (local_cfg != BTA_HL_DCH_CFG_RELIABLE)) {
+    status = BTA_HL_STATUS_NO_FIRST_RELIABLE;
+    APPL_TRACE_ERROR("BTA_HL_STATUS_INVALID_DCH_CFG");
+  }
+
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_validate_reconnect_params
+ *
+ * Description  This function validates the reconnect parameters
+ *
+ * Returns      bool - true validation is successful
+ *                        false validation failed
+ ******************************************************************************/
+bool bta_hl_validate_reconnect_params(uint8_t app_idx, uint8_t mcl_idx,
+                                      tBTA_HL_API_DCH_RECONNECT* p_reconnect,
+                                      uint8_t* p_mdep_cfg_idx,
+                                      uint8_t* p_mdl_cfg_idx) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_SUP_FEATURE* p_sup_feature = &p_acb->sup_feature;
+  uint8_t num_mdeps;
+  uint8_t mdl_cfg_idx;
+  bool local_mdep_id_found = false;
+  bool mdl_cfg_found = false;
+  bool status = false;
+  uint8_t i, in_use_mdl_idx = 0;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_validate_reconnect_params  mdl_id=%d app_idx=%d",
+                   p_reconnect->mdl_id, app_idx);
+#endif
+  if (bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, p_reconnect->mdl_id,
+                              &mdl_cfg_idx)) {
+    mdl_cfg_found = true;
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!mdl_cfg_found) {
+    APPL_TRACE_DEBUG("mdl_cfg_found not found");
+  }
+#endif
+
+  if (mdl_cfg_found) {
+    num_mdeps = p_sup_feature->num_of_mdeps;
+    for (i = 0; i < num_mdeps; i++) {
+      if (p_sup_feature->mdep[i].mdep_id ==
+          p_acb->mdl_cfg[mdl_cfg_idx].local_mdep_id) {
+        local_mdep_id_found = true;
+        *p_mdep_cfg_idx = i;
+        *p_mdl_cfg_idx = mdl_cfg_idx;
+        break;
+      }
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!local_mdep_id_found) {
+    APPL_TRACE_DEBUG("local_mdep_id not found");
+  }
+#endif
+
+  if (local_mdep_id_found) {
+    if (!bta_hl_find_mdl_idx(app_idx, mcl_idx, p_reconnect->mdl_id,
+                             &in_use_mdl_idx)) {
+      status = true;
+    } else {
+      APPL_TRACE_ERROR("mdl_id=%d is curreltly in use", p_reconnect->mdl_id);
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!status) {
+    APPL_TRACE_DEBUG(
+        "Reconnect validation failed local_mdep_id found=%d mdl_cfg_idx "
+        "found=%d in_use_mdl_idx=%d ",
+        local_mdep_id_found, mdl_cfg_found, in_use_mdl_idx);
+  }
+#endif
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_find_avail_mcl_idx
+ *
+ * Returns      bool - true found
+ *                        false not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_avail_mcl_idx(uint8_t app_idx, uint8_t* p_mcl_idx) {
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_MCLS; i++) {
+    if (!bta_hl_cb.acb[app_idx].mcb[i].in_use) {
+      found = true;
+      *p_mcl_idx = i;
+      break;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!found) {
+    APPL_TRACE_DEBUG("bta_hl_find_avail_mcl_idx found=%d idx=%d", found, i);
+  }
+#endif
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_find_avail_mdl_idx
+ *
+ * Description  This function finds an available MDL control block index
+ *
+ * Returns      bool - true found
+ *                        false not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_avail_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
+                               uint8_t* p_mdl_idx) {
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+    if (!p_mcb->mdl[i].in_use) {
+      memset((void*)&p_mcb->mdl[i], 0, sizeof(tBTA_HL_MDL_CB));
+      found = true;
+      *p_mdl_idx = i;
+      break;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!found) {
+    APPL_TRACE_DEBUG("bta_hl_find_avail_mdl_idx found=%d idx=%d", found, i);
+  }
+#endif
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_is_a_duplicate_id
+ *
+ * Description  This function finds the application has been used or not
+ *
+ * Returns      bool - true the app_id is a duplicate ID
+ *                        false not a duplicate ID
+ ******************************************************************************/
+bool bta_hl_is_a_duplicate_id(uint8_t app_id) {
+  bool is_duplicate = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    if (bta_hl_cb.acb[i].in_use && (bta_hl_cb.acb[i].app_id == app_id)) {
+      is_duplicate = true;
+
+      break;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (is_duplicate) {
+    APPL_TRACE_DEBUG("bta_hl_is_a_duplicate_id app_id=%d is_duplicate=%d",
+                     app_id, is_duplicate);
+  }
+#endif
+
+  return is_duplicate;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_find_avail_app_idx
+ *
+ * Description  This function finds an available application control block index
+ *
+ * Returns      bool - true found
+ *                        false not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_avail_app_idx(uint8_t* p_idx) {
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    if (!bta_hl_cb.acb[i].in_use) {
+      found = true;
+      *p_idx = i;
+      break;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!found) {
+    APPL_TRACE_DEBUG("bta_hl_find_avail_app_idx found=%d app_idx=%d", found, i);
+  }
+#endif
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_app_update
+ *
+ * Description  This function registers an HDP application MCAP and DP
+ *
+ * Returns      tBTA_HL_STATUS -registration status
+ *
+ ******************************************************************************/
+tBTA_HL_STATUS bta_hl_app_update(uint8_t app_id, bool is_register) {
+  tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(0);
+  tMCA_CS mca_cs;
+  uint8_t i, mdep_idx, num_of_mdeps;
+  uint8_t mdep_counter = 0;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_app_update app_id=%d", app_id);
+#endif
+
+  if (is_register) {
+    if ((status == BTA_HL_STATUS_OK) &&
+        bta_hl_co_get_num_of_mdep(app_id, &num_of_mdeps)) {
+      for (i = 0; i < num_of_mdeps; i++) {
+        mca_cs.type = MCA_TDEP_DATA;
+        mca_cs.max_mdl = BTA_HL_NUM_MDLS_PER_MDEP;
+        mca_cs.p_data_cback = bta_hl_mcap_data_cback;
+        /* Find the first available mdep index, and create a MDL Endpoint */
+        // make a function later if needed
+        for (mdep_idx = 1; mdep_idx < BTA_HL_NUM_MDEPS; mdep_idx++) {
+          if (p_acb->sup_feature.mdep[mdep_idx].mdep_id == 0) {
+            break; /* We found an available index */
+          } else {
+            mdep_counter++;
+          }
+        }
+        /* If no available MDEPs, return error */
+        if (mdep_idx == BTA_HL_NUM_MDEPS) {
+          APPL_TRACE_ERROR("bta_hl_app_update: Out of MDEP IDs");
+          status = BTA_HL_STATUS_MCAP_REG_FAIL;
+          break;
+        }
+        if (MCA_CreateDep((tMCA_HANDLE)p_acb->app_handle,
+                          &(p_acb->sup_feature.mdep[mdep_idx].mdep_id),
+                          &mca_cs) == MCA_SUCCESS) {
+          if (bta_hl_co_get_mdep_config(
+                  app_id, mdep_idx, mdep_counter,
+                  p_acb->sup_feature.mdep[mdep_idx].mdep_id,
+                  &p_acb->sup_feature.mdep[mdep_idx].mdep_cfg)) {
+            p_acb->sup_feature.mdep[mdep_idx].ori_app_id = app_id;
+            APPL_TRACE_DEBUG("mdep idx %d id %d ori_app_id %d num data type %d",
+                             mdep_idx,
+                             p_acb->sup_feature.mdep[mdep_idx].mdep_id,
+                             p_acb->sup_feature.mdep[mdep_idx].ori_app_id,
+                             p_acb->sup_feature.mdep[mdep_idx]
+                                 .mdep_cfg.num_of_mdep_data_types);
+            if (p_acb->sup_feature.mdep[mdep_idx].mdep_cfg.mdep_role ==
+                BTA_HL_MDEP_ROLE_SOURCE) {
+              p_acb->sup_feature.app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SOURCE;
+            } else if (p_acb->sup_feature.mdep[mdep_idx].mdep_cfg.mdep_role ==
+                       BTA_HL_MDEP_ROLE_SINK) {
+              p_acb->sup_feature.app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SINK;
+            } else {
+              APPL_TRACE_ERROR(
+                  "bta_hl_app_registration: Invalid Role %d",
+                  p_acb->sup_feature.mdep[mdep_idx].mdep_cfg.mdep_role);
+              status = BTA_HL_STATUS_MDEP_CO_FAIL;
+              break;
+            }
+          } else {
+            APPL_TRACE_ERROR("bta_hl_app_registration: Cfg callout failed");
+            status = BTA_HL_STATUS_MDEP_CO_FAIL;
+            break;
+          }
+        } else {
+          APPL_TRACE_ERROR("bta_hl_app_registration: MCA_CreateDep failed");
+          status = BTA_HL_STATUS_MCAP_REG_FAIL;
+          break;
+        }
+      }
+      p_acb->sup_feature.num_of_mdeps += num_of_mdeps;
+      APPL_TRACE_DEBUG("num_of_mdeps %d", p_acb->sup_feature.num_of_mdeps);
+
+      if ((status == BTA_HL_STATUS_OK) &&
+          (p_acb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SOURCE)) {
+        p_acb->sup_feature.advertize_source_sdp =
+            bta_hl_co_advrtise_source_sdp(app_id);
+      }
+
+      if ((status == BTA_HL_STATUS_OK) &&
+          (!bta_hl_co_get_echo_config(app_id, &p_acb->sup_feature.echo_cfg))) {
+        status = BTA_HL_STATUS_ECHO_CO_FAIL;
+      }
+
+      if ((status == BTA_HL_STATUS_OK) &&
+          (!bta_hl_co_load_mdl_config(app_id, BTA_HL_NUM_MDL_CFGS,
+                                      &p_acb->mdl_cfg[0]))) {
+        status = BTA_HL_STATUS_MDL_CFG_CO_FAIL;
+      }
+    } else {
+      status = BTA_HL_STATUS_MDEP_CO_FAIL;
+    }
+  } else {
+    for (i = 1; i < BTA_HL_NUM_MDEPS; i++) {
+      if (p_acb->sup_feature.mdep[i].ori_app_id == app_id) {
+        APPL_TRACE_DEBUG("Found index %", i);
+
+        if (MCA_DeleteDep((tMCA_HANDLE)p_acb->app_handle,
+                          (p_acb->sup_feature.mdep[i].mdep_id)) !=
+            MCA_SUCCESS) {
+          APPL_TRACE_ERROR("Error deregistering");
+          status = BTA_HL_STATUS_MCAP_REG_FAIL;
+          return status;
+        }
+        memset(&p_acb->sup_feature.mdep[i], 0, sizeof(tBTA_HL_MDEP));
+      }
+    }
+  }
+
+  if (status == BTA_HL_STATUS_OK) {
+    /* Register/Update MDEP(s) in SDP Record */
+    status = bta_hl_sdp_update(app_id);
+  }
+  /* else do cleanup */
+
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_app_registration
+ *
+ * Description  This function registers an HDP application MCAP and DP
+ *
+ * Returns      tBTA_HL_STATUS -registration status
+ *
+ ******************************************************************************/
+tBTA_HL_STATUS bta_hl_app_registration(uint8_t app_idx) {
+  tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tMCA_REG reg;
+  tMCA_CS mca_cs;
+  uint8_t i, num_of_mdeps;
+  uint8_t mdep_counter = 0;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_app_registration app_idx=%d", app_idx);
+#endif
+
+  reg.ctrl_psm = p_acb->ctrl_psm;
+  reg.data_psm = p_acb->data_psm;
+  reg.sec_mask = p_acb->sec_mask;
+  reg.rsp_tout = BTA_HL_MCAP_RSP_TOUT;
+
+  if ((p_acb->app_handle = (tBTA_HL_APP_HANDLE)MCA_Register(
+           &reg, bta_hl_mcap_ctrl_cback)) != 0) {
+    mca_cs.type = MCA_TDEP_ECHO;
+    mca_cs.max_mdl = BTA_HL_NUM_MDLS_PER_MDEP;
+    mca_cs.p_data_cback = bta_hl_mcap_data_cback;
+
+    if (MCA_CreateDep((tMCA_HANDLE)p_acb->app_handle,
+                      &(p_acb->sup_feature.mdep[0].mdep_id),
+                      &mca_cs) == MCA_SUCCESS) {
+      if (p_acb->sup_feature.mdep[0].mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) {
+        status = BTA_HL_STATUS_MCAP_REG_FAIL;
+        APPL_TRACE_ERROR("BAD MDEP ID for echo test mdep_id=%d",
+                         p_acb->sup_feature.mdep[0].mdep_id);
+      }
+    } else {
+      status = BTA_HL_STATUS_MCAP_REG_FAIL;
+      APPL_TRACE_ERROR("MCA_CreateDep for echo test(mdep_id=0) failed");
+    }
+
+    if ((status == BTA_HL_STATUS_OK) &&
+        bta_hl_co_get_num_of_mdep(p_acb->app_id, &num_of_mdeps)) {
+      p_acb->sup_feature.num_of_mdeps = num_of_mdeps + 1;
+
+      for (i = 1; i < p_acb->sup_feature.num_of_mdeps; i++) {
+        mca_cs.type = MCA_TDEP_DATA;
+        mca_cs.max_mdl = BTA_HL_NUM_MDLS_PER_MDEP;
+        mca_cs.p_data_cback = bta_hl_mcap_data_cback;
+
+        if (MCA_CreateDep((tMCA_HANDLE)p_acb->app_handle,
+                          &(p_acb->sup_feature.mdep[i].mdep_id),
+                          &mca_cs) == MCA_SUCCESS) {
+          if (bta_hl_co_get_mdep_config(p_acb->app_id, i, mdep_counter,
+                                        p_acb->sup_feature.mdep[i].mdep_id,
+                                        &p_acb->sup_feature.mdep[i].mdep_cfg)) {
+            if (p_acb->sup_feature.mdep[i].mdep_cfg.mdep_role ==
+                BTA_HL_MDEP_ROLE_SOURCE) {
+              p_acb->sup_feature.app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SOURCE;
+            } else if (p_acb->sup_feature.mdep[i].mdep_cfg.mdep_role ==
+                       BTA_HL_MDEP_ROLE_SINK) {
+              p_acb->sup_feature.app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SINK;
+            } else {
+              status = BTA_HL_STATUS_MDEP_CO_FAIL;
+              break;
+            }
+            p_acb->sup_feature.mdep[i].ori_app_id = p_acb->app_id;
+            APPL_TRACE_DEBUG("index %d ori_app_id %d", i,
+                             p_acb->sup_feature.mdep[i].ori_app_id);
+          } else {
+            status = BTA_HL_STATUS_MDEP_CO_FAIL;
+            break;
+          }
+        } else {
+          status = BTA_HL_STATUS_MCAP_REG_FAIL;
+          break;
+        }
+      }
+
+      if ((status == BTA_HL_STATUS_OK) &&
+          (p_acb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SOURCE)) {
+        /* this is a source only applciation */
+        p_acb->sup_feature.advertize_source_sdp =
+            bta_hl_co_advrtise_source_sdp(p_acb->app_id);
+      }
+
+      if ((status == BTA_HL_STATUS_OK) &&
+          (!bta_hl_co_get_echo_config(p_acb->app_id,
+                                      &p_acb->sup_feature.echo_cfg))) {
+        status = BTA_HL_STATUS_ECHO_CO_FAIL;
+      }
+
+      if ((status == BTA_HL_STATUS_OK) &&
+          (!bta_hl_co_load_mdl_config(p_acb->app_id, BTA_HL_NUM_MDL_CFGS,
+                                      &p_acb->mdl_cfg[0]))) {
+        status = BTA_HL_STATUS_MDL_CFG_CO_FAIL;
+      }
+    } else {
+      status = BTA_HL_STATUS_MDEP_CO_FAIL;
+    }
+  } else {
+    status = BTA_HL_STATUS_MCAP_REG_FAIL;
+  }
+
+  if (status == BTA_HL_STATUS_OK) {
+    status = bta_hl_sdp_register(app_idx);
+  }
+
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_discard_data
+ *
+ * Description  This function discard an HDP event
+ *
+ * Returns     void
+ *
+ ******************************************************************************/
+void bta_hl_discard_data(uint16_t event, tBTA_HL_DATA* p_data) {
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_ERROR("BTA HL Discard event=%s", bta_hl_evt_code(event));
+
+#endif
+
+  switch (event) {
+    case BTA_HL_API_SEND_DATA_EVT:
+      break;
+
+    case BTA_HL_MCA_RCV_DATA_EVT:
+      osi_free_and_reset((void**)&p_data->mca_rcv_data_evt.p_pkt);
+      break;
+
+    default:
+      /*Nothing to free*/
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_save_mdl_cfg
+ *
+ * Description    This function saves the MDL configuration
+ *
+ * Returns     void
+ *
+ ******************************************************************************/
+void bta_hl_save_mdl_cfg(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  uint8_t mdl_cfg_idx;
+  tBTA_HL_MDL_ID mdl_id;
+  bool found = true;
+  tBTA_HL_MDL_CFG mdl_cfg;
+  tBTA_HL_MDEP* p_mdep_cfg;
+  tBTA_HL_L2CAP_CFG_INFO l2cap_cfg;
+  uint8_t time_val = 0;
+  mdl_id = p_dcb->mdl_id;
+  if (!bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, mdl_id, &mdl_cfg_idx)) {
+    if (!bta_hl_find_avail_mdl_cfg_idx(app_idx, mcl_idx, &mdl_cfg_idx)) {
+      APPL_TRACE_ERROR("No space to save the MDL config");
+      found = false; /*no space available*/
+    }
+  }
+
+  if (found) {
+    bta_hl_get_l2cap_cfg(p_dcb->mdl_handle, &l2cap_cfg);
+    if (!bta_hl_get_cur_time(app_idx, &time_val)) {
+      bta_hl_compact_mdl_cfg_time(app_idx, p_dcb->local_mdep_id);
+      bta_hl_get_cur_time(app_idx, &time_val);
+    }
+    mdl_cfg.active = true;
+    mdl_cfg.time = time_val;
+    mdl_cfg.mdl_id = p_dcb->mdl_id;
+    mdl_cfg.dch_mode = p_dcb->dch_mode;
+    mdl_cfg.mtu = l2cap_cfg.mtu;
+    mdl_cfg.fcs = l2cap_cfg.fcs;
+
+    bdcpy(mdl_cfg.peer_bd_addr, p_mcb->bd_addr);
+    mdl_cfg.local_mdep_id = p_dcb->local_mdep_id;
+    p_mdep_cfg = &p_acb->sup_feature.mdep[p_dcb->local_mdep_cfg_idx];
+    mdl_cfg.local_mdep_role = p_mdep_cfg->mdep_cfg.mdep_role;
+    memcpy(&p_acb->mdl_cfg[mdl_cfg_idx], &mdl_cfg, sizeof(tBTA_HL_MDL_CFG));
+    bta_hl_co_save_mdl(mdl_cfg.local_mdep_id, mdl_cfg_idx, &mdl_cfg);
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (found) {
+    if (p_dcb->mtu != l2cap_cfg.mtu) {
+      APPL_TRACE_WARNING(
+          "MCAP and L2CAP peer mtu size out of sync from MCAP mtu=%d from "
+          "l2cap mtu=%d",
+          p_dcb->mtu, l2cap_cfg.mtu);
+    }
+    APPL_TRACE_DEBUG("bta_hl_save_mdl_cfg saved=%d", found);
+    APPL_TRACE_DEBUG("Saved. L2cap cfg mdl_id=%d mtu=%d fcs=%d dch_mode=%d",
+                     mdl_cfg.mdl_id, mdl_cfg.mtu, mdl_cfg.fcs,
+                     mdl_cfg.dch_mode);
+  }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_set_dch_chan_cfg
+ *
+ * Description    This function setups the L2CAP DCH channel configuration
+ *
+ * Returns     void
+ ******************************************************************************/
+void bta_hl_set_dch_chan_cfg(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+                             tBTA_HL_DATA* p_data) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  uint8_t l2cap_mode = L2CAP_FCR_ERTM_MODE;
+  tBTA_HL_SUP_FEATURE* p_sup_feature = &p_acb->sup_feature;
+  uint8_t local_mdep_cfg_idx = p_dcb->local_mdep_cfg_idx;
+
+  switch (p_dcb->dch_oper) {
+    case BTA_HL_DCH_OP_LOCAL_RECONNECT:
+    case BTA_HL_DCH_OP_REMOTE_RECONNECT:
+      if (p_dcb->dch_mode == BTA_HL_DCH_MODE_STREAMING)
+        l2cap_mode = L2CAP_FCR_STREAM_MODE;
+      break;
+    case BTA_HL_DCH_OP_LOCAL_OPEN:
+      if (p_data->mca_evt.mca_data.create_cfm.cfg == BTA_HL_DCH_CFG_STREAMING)
+        l2cap_mode = L2CAP_FCR_STREAM_MODE;
+      break;
+    case BTA_HL_DCH_OP_REMOTE_OPEN:
+      if (p_dcb->local_cfg == BTA_HL_DCH_CFG_STREAMING)
+        l2cap_mode = L2CAP_FCR_STREAM_MODE;
+      break;
+    default:
+      APPL_TRACE_ERROR("Invalid dch oper=%d for set dch chan cfg",
+                       p_dcb->dch_oper);
+      break;
+  }
+  p_dcb->chnl_cfg.fcr_opt.mode = l2cap_mode;
+  p_dcb->chnl_cfg.fcr_opt.mps = bta_hl_set_mps(p_dcb->max_rx_apdu_size);
+  p_dcb->chnl_cfg.fcr_opt.tx_win_sz = bta_hl_set_tx_win_size(
+      p_dcb->max_rx_apdu_size, p_dcb->chnl_cfg.fcr_opt.mps);
+  p_dcb->chnl_cfg.fcr_opt.max_transmit = BTA_HL_L2C_MAX_TRANSMIT;
+  p_dcb->chnl_cfg.fcr_opt.rtrans_tout = BTA_HL_L2C_RTRANS_TOUT;
+  p_dcb->chnl_cfg.fcr_opt.mon_tout = BTA_HL_L2C_MON_TOUT;
+
+  p_dcb->chnl_cfg.user_rx_buf_size =
+      bta_hl_set_user_rx_buf_size(p_dcb->max_rx_apdu_size);
+  p_dcb->chnl_cfg.user_tx_buf_size =
+      bta_hl_set_user_tx_buf_size(p_dcb->max_tx_apdu_size);
+  p_dcb->chnl_cfg.fcr_rx_buf_size = L2CAP_INVALID_ERM_BUF_SIZE;
+  p_dcb->chnl_cfg.fcr_tx_buf_size = L2CAP_INVALID_ERM_BUF_SIZE;
+  p_dcb->chnl_cfg.data_mtu = p_dcb->max_rx_apdu_size;
+
+  p_dcb->chnl_cfg.fcs = BTA_HL_MCA_NO_FCS;
+  if (local_mdep_cfg_idx != BTA_HL_ECHO_TEST_MDEP_CFG_IDX) {
+    if (p_sup_feature->mdep[local_mdep_cfg_idx].mdep_cfg.mdep_role ==
+        BTA_HL_MDEP_ROLE_SOURCE) {
+      p_dcb->chnl_cfg.fcs = BTA_HL_DEFAULT_SOURCE_FCS;
+    }
+  } else {
+    p_dcb->chnl_cfg.fcs = BTA_HL_MCA_USE_FCS;
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("L2CAP Params l2cap_mode[3-ERTM 4-STREAM]=%d", l2cap_mode);
+  APPL_TRACE_DEBUG("Use FCS =%s mtu=%d",
+                   ((p_dcb->chnl_cfg.fcs & 1) ? "YES" : "NO"),
+                   p_dcb->chnl_cfg.data_mtu);
+  APPL_TRACE_DEBUG(
+      "tx_win_sz=%d, max_transmit=%d, rtrans_tout=%d, mon_tout=%d, mps=%d",
+      p_dcb->chnl_cfg.fcr_opt.tx_win_sz, p_dcb->chnl_cfg.fcr_opt.max_transmit,
+      p_dcb->chnl_cfg.fcr_opt.rtrans_tout, p_dcb->chnl_cfg.fcr_opt.mon_tout,
+      p_dcb->chnl_cfg.fcr_opt.mps);
+
+  APPL_TRACE_DEBUG(
+      "USER rx_buf_size=%d, tx_buf_size=%d, FCR rx_buf_size=%d, tx_buf_size=%d",
+      p_dcb->chnl_cfg.user_rx_buf_size, p_dcb->chnl_cfg.user_tx_buf_size,
+      p_dcb->chnl_cfg.fcr_rx_buf_size, p_dcb->chnl_cfg.fcr_tx_buf_size);
+
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_get_l2cap_cfg
+ *
+ * Description    This function get the current L2CAP channel configuration
+ *
+ * Returns     bool - true - operation is successful
+ ******************************************************************************/
+bool bta_hl_get_l2cap_cfg(tBTA_HL_MDL_HANDLE mdl_hnd,
+                          tBTA_HL_L2CAP_CFG_INFO* p_cfg) {
+  bool success = false;
+  uint16_t lcid;
+  tL2CAP_CFG_INFO* p_our_cfg;
+  tL2CAP_CH_CFG_BITS our_cfg_bits;
+  tL2CAP_CFG_INFO* p_peer_cfg;
+  tL2CAP_CH_CFG_BITS peer_cfg_bits;
+
+  lcid = MCA_GetL2CapChannel((tMCA_DL)mdl_hnd);
+  if (lcid && L2CA_GetCurrentConfig(lcid, &p_our_cfg, &our_cfg_bits,
+                                    &p_peer_cfg, &peer_cfg_bits)) {
+    p_cfg->fcs = BTA_HL_MCA_NO_FCS;
+    if (our_cfg_bits & L2CAP_CH_CFG_MASK_FCS) {
+      p_cfg->fcs |= p_our_cfg->fcs;
+    } else {
+      p_cfg->fcs = BTA_HL_MCA_USE_FCS;
+    }
+
+    if (p_cfg->fcs != BTA_HL_MCA_USE_FCS) {
+      if (peer_cfg_bits & L2CAP_CH_CFG_MASK_FCS) {
+        p_cfg->fcs |= p_peer_cfg->fcs;
+      } else {
+        p_cfg->fcs = BTA_HL_MCA_USE_FCS;
+      }
+    }
+
+    p_cfg->mtu = 0;
+    if (peer_cfg_bits & L2CAP_CH_CFG_MASK_MTU) {
+      p_cfg->mtu = p_peer_cfg->mtu;
+    } else {
+      p_cfg->mtu = L2CAP_DEFAULT_MTU;
+    }
+    success = true;
+  } else {
+    p_cfg->mtu = L2CAP_DEFAULT_MTU;
+    p_cfg->fcs = BTA_HL_L2C_NO_FCS;
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+  if (!success) {
+    APPL_TRACE_DEBUG("bta_hl_get_l2cap_cfg success=%d mdl=%d lcid=%d", success,
+                     mdl_hnd, lcid);
+    APPL_TRACE_DEBUG("l2cap mtu=%d fcs=%d", p_cfg->mtu, p_cfg->fcs);
+  }
+#endif
+
+  return success;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_validate_chan_cfg
+ *
+ * Description    This function validates the L2CAP channel configuration
+ *
+ * Returns     bool - true - validation is successful
+ ******************************************************************************/
+bool bta_hl_validate_chan_cfg(uint8_t app_idx, uint8_t mcl_idx,
+                              uint8_t mdl_idx) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  bool success = false;
+  uint8_t mdl_cfg_idx = 0;
+  tBTA_HL_L2CAP_CFG_INFO l2cap_cfg;
+  bool get_l2cap_result, get_mdl_result;
+
+  get_l2cap_result = bta_hl_get_l2cap_cfg(p_dcb->mdl_handle, &l2cap_cfg);
+  get_mdl_result =
+      bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, p_dcb->mdl_id, &mdl_cfg_idx);
+
+  if (get_l2cap_result && get_mdl_result) {
+    if ((p_acb->mdl_cfg[mdl_cfg_idx].mtu <= l2cap_cfg.mtu) &&
+        (p_acb->mdl_cfg[mdl_cfg_idx].fcs == l2cap_cfg.fcs) &&
+        (p_acb->mdl_cfg[mdl_cfg_idx].dch_mode == p_dcb->dch_mode)) {
+      success = true;
+    }
+  }
+
+#if (BTA_HL_DEBUG == TRUE)
+
+  if (p_dcb->mtu != l2cap_cfg.mtu) {
+    APPL_TRACE_WARNING(
+        "MCAP and L2CAP peer mtu size out of sync from MCAP mtu=%d from l2cap "
+        "mtu=%d",
+        p_dcb->mtu, l2cap_cfg.mtu);
+  }
+
+  if (!success) {
+    APPL_TRACE_DEBUG(
+        "bta_hl_validate_chan_cfg success=%d app_idx=%d mcl_idx=%d mdl_idx=%d",
+        success, app_idx, mcl_idx, mdl_idx);
+    APPL_TRACE_DEBUG("Cur. L2cap cfg mtu=%d fcs=%d dch_mode=%d", l2cap_cfg.mtu,
+                     l2cap_cfg.fcs, p_dcb->dch_mode);
+    APPL_TRACE_DEBUG("From saved: L2cap cfg mtu=%d fcs=%d dch_mode=%d",
+                     p_acb->mdl_cfg[mdl_cfg_idx].mtu,
+                     p_acb->mdl_cfg[mdl_cfg_idx].fcs,
+                     p_acb->mdl_cfg[mdl_cfg_idx].dch_mode);
+  }
+#endif
+
+  return success;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_is_cong_on
+ *
+ * Description    This function checks whether the congestion condition is on.
+ *
+ * Returns      bool - true DCH is congested
+ *                        false not congested
+ *
+ ******************************************************************************/
+bool bta_hl_is_cong_on(uint8_t app_id, BD_ADDR bd_addr, tBTA_HL_MDL_ID mdl_id)
+
+{
+  tBTA_HL_MDL_CB* p_dcb;
+  uint8_t app_idx = 0, mcl_idx, mdl_idx;
+  bool cong_status = true;
+
+  if (bta_hl_find_app_idx(app_id, &app_idx)) {
+    if (bta_hl_find_mcl_idx(app_idx, bd_addr, &mcl_idx)) {
+      if (bta_hl_find_mdl_idx(app_idx, mcl_idx, mdl_id, &mdl_idx)) {
+        p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+        cong_status = p_dcb->cong;
+      }
+    }
+  }
+
+  return cong_status;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_check_cch_close
+ *
+ * Description   This function checks whether there is a pending CCH close
+ *               request or not
+ *
+ * Returns      void
+ ******************************************************************************/
+void bta_hl_check_cch_close(uint8_t app_idx, uint8_t mcl_idx,
+                            tBTA_HL_DATA* p_data, bool check_dch_setup) {
+  tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_MDL_CB* p_dcb;
+  uint8_t mdl_idx;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_check_cch_close cch_close_dch_oper=%d",
+                   p_mcb->cch_close_dch_oper);
+#endif
+
+  if (p_mcb->cch_oper == BTA_HL_CCH_OP_LOCAL_CLOSE) {
+    if (check_dch_setup &&
+        bta_hl_find_dch_setup_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
+      p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+      if (!p_mcb->rsp_tout) {
+        p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_ABORT;
+
+        if (!p_dcb->abort_oper) {
+          p_dcb->abort_oper |= BTA_HL_ABORT_CCH_CLOSE_MASK;
+          bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ABORT_EVT,
+                                p_data);
+        }
+      } else {
+        p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_CLOSE;
+        bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+                              BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+      }
+    } else if (bta_hl_find_an_active_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
+      p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_CLOSE;
+      bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_EVT,
+                            p_data);
+    } else {
+      p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_NONE;
+      bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_EVT, p_data);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_clean_app
+ *
+ * Description      Cleans up the HDP application resources and control block
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_clean_app(uint8_t app_idx) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  int i, num_act_apps = 0;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_clean_app");
+#endif
+  MCA_Deregister((tMCA_HANDLE)p_acb->app_handle);
+
+  if (p_acb->sdp_handle) SDP_DeleteRecord(p_acb->sdp_handle);
+
+  memset((void*)p_acb, 0, sizeof(tBTA_HL_APP_CB));
+
+  /* check any application is still active */
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    p_acb = BTA_HL_GET_APP_CB_PTR(i);
+    if (p_acb->in_use) num_act_apps++;
+  }
+
+  if (!num_act_apps) {
+    bta_sys_remove_uuid(UUID_SERVCLASS_HDP_PROFILE);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_check_deregistration
+ *
+ * Description   This function checks whether there is a pending deregistration
+ *               request or not
+ *
+ * Returns      void
+ ******************************************************************************/
+void bta_hl_check_deregistration(uint8_t app_idx, tBTA_HL_DATA* p_data) {
+  tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_MCL_CB* p_mcb;
+  uint8_t mcl_idx;
+  tBTA_HL evt_data;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_check_deregistration");
+#endif
+
+  if (p_acb->deregistering) {
+    if (bta_hl_find_an_in_use_mcl_idx(app_idx, &mcl_idx)) {
+      p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+      if (p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_CLOSE) {
+        if (p_mcb->cch_state == BTA_HL_CCH_OPENING_ST)
+          p_mcb->force_close_local_cch_opening = true;
+        p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_CLOSE;
+        APPL_TRACE_DEBUG("p_mcb->force_close_local_cch_opening=%d",
+                         p_mcb->force_close_local_cch_opening);
+        bta_hl_check_cch_close(app_idx, mcl_idx, p_data, true);
+      }
+    } else {
+      /* all cchs are closed */
+      evt_data.dereg_cfm.app_handle = p_acb->app_handle;
+      evt_data.dereg_cfm.app_id = p_data->api_dereg.app_id;
+      evt_data.dereg_cfm.status = BTA_HL_STATUS_OK;
+      p_acb->p_cback(BTA_HL_DEREGISTER_CFM_EVT, (tBTA_HL*)&evt_data);
+      bta_hl_clean_app(app_idx);
+      bta_hl_check_disable(p_data);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_check_disable
+ *
+ * Description   This function checks whether there is a pending disable
+ *               request or not
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_hl_check_disable(tBTA_HL_DATA* p_data) {
+  tBTA_HL_CB* p_cb = &bta_hl_cb;
+  tBTA_HL_APP_CB* p_acb;
+  uint8_t app_idx;
+  tBTA_HL_CTRL evt_data;
+
+#if (BTA_HL_DEBUG == TRUE)
+  APPL_TRACE_DEBUG("bta_hl_check_disable");
+#endif
+
+  if (bta_hl_cb.disabling) {
+    if (bta_hl_find_an_in_use_app_idx(&app_idx)) {
+      p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+      if (!p_acb->deregistering) {
+        p_acb->deregistering = true;
+        bta_hl_check_deregistration(app_idx, p_data);
+      }
+    } else {
+      /* all apps are deregistered */
+      bta_sys_deregister(BTA_ID_HL);
+      evt_data.disable_cfm.status = BTA_HL_STATUS_OK;
+      if (p_cb->p_ctrl_cback)
+        p_cb->p_ctrl_cback(BTA_HL_CTRL_DISABLE_CFM_EVT,
+                           (tBTA_HL_CTRL*)&evt_data);
+      memset((void*)p_cb, 0, sizeof(tBTA_HL_CB));
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_build_abort_cfm
+ *
+ * Description   This function builds the abort confirmation event data
+ *
+ * Returns      None
+ *
+ ******************************************************************************/
+void bta_hl_build_abort_cfm(tBTA_HL* p_evt_data, tBTA_HL_APP_HANDLE app_handle,
+                            tBTA_HL_MCL_HANDLE mcl_handle,
+                            tBTA_HL_STATUS status) {
+  p_evt_data->dch_abort_cfm.status = status;
+  p_evt_data->dch_abort_cfm.mcl_handle = mcl_handle;
+  p_evt_data->dch_abort_cfm.app_handle = app_handle;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_build_abort_ind
+ *
+ * Description   This function builds the abort indication event data
+ *
+ * Returns      None
+ *
+ ******************************************************************************/
+void bta_hl_build_abort_ind(tBTA_HL* p_evt_data, tBTA_HL_APP_HANDLE app_handle,
+                            tBTA_HL_MCL_HANDLE mcl_handle) {
+  p_evt_data->dch_abort_ind.mcl_handle = mcl_handle;
+  p_evt_data->dch_abort_ind.app_handle = app_handle;
+}
+/*******************************************************************************
+ *
+ * Function      bta_hl_build_close_cfm
+ *
+ * Description   This function builds the close confirmation event data
+ *
+ * Returns      None
+ *
+ ******************************************************************************/
+void bta_hl_build_dch_close_cfm(tBTA_HL* p_evt_data,
+                                tBTA_HL_APP_HANDLE app_handle,
+                                tBTA_HL_MCL_HANDLE mcl_handle,
+                                tBTA_HL_MDL_HANDLE mdl_handle,
+                                tBTA_HL_STATUS status) {
+  p_evt_data->dch_close_cfm.status = status;
+  p_evt_data->dch_close_cfm.mdl_handle = mdl_handle;
+  p_evt_data->dch_close_cfm.mcl_handle = mcl_handle;
+  p_evt_data->dch_close_cfm.app_handle = app_handle;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_build_dch_close_ind
+ *
+ * Description   This function builds the close indication event data
+ *
+ * Returns      None
+ *
+ ******************************************************************************/
+void bta_hl_build_dch_close_ind(tBTA_HL* p_evt_data,
+                                tBTA_HL_APP_HANDLE app_handle,
+                                tBTA_HL_MCL_HANDLE mcl_handle,
+                                tBTA_HL_MDL_HANDLE mdl_handle,
+                                bool intentional) {
+  p_evt_data->dch_close_ind.mdl_handle = mdl_handle;
+  p_evt_data->dch_close_ind.mcl_handle = mcl_handle;
+  p_evt_data->dch_close_ind.app_handle = app_handle;
+  p_evt_data->dch_close_ind.intentional = intentional;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_build_send_data_cfm
+ *
+ * Description   This function builds the send data confirmation event data
+ *
+ * Returns      None
+ *
+ ******************************************************************************/
+void bta_hl_build_send_data_cfm(tBTA_HL* p_evt_data,
+                                tBTA_HL_APP_HANDLE app_handle,
+                                tBTA_HL_MCL_HANDLE mcl_handle,
+                                tBTA_HL_MDL_HANDLE mdl_handle,
+                                tBTA_HL_STATUS status) {
+  p_evt_data->dch_send_data_cfm.mdl_handle = mdl_handle;
+  p_evt_data->dch_send_data_cfm.mcl_handle = mcl_handle;
+  p_evt_data->dch_send_data_cfm.app_handle = app_handle;
+  p_evt_data->dch_send_data_cfm.status = status;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_build_rcv_data_ind
+ *
+ * Description   This function builds the received data indication event data
+ *
+ * Returns      None
+ *
+ ******************************************************************************/
+void bta_hl_build_rcv_data_ind(tBTA_HL* p_evt_data,
+                               tBTA_HL_APP_HANDLE app_handle,
+                               tBTA_HL_MCL_HANDLE mcl_handle,
+                               tBTA_HL_MDL_HANDLE mdl_handle) {
+  p_evt_data->dch_rcv_data_ind.mdl_handle = mdl_handle;
+  p_evt_data->dch_rcv_data_ind.mcl_handle = mcl_handle;
+  p_evt_data->dch_rcv_data_ind.app_handle = app_handle;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_build_cch_open_cfm
+ *
+ * Description   This function builds the CCH open confirmation event data
+ *
+ * Returns      None
+ *
+ ******************************************************************************/
+void bta_hl_build_cch_open_cfm(tBTA_HL* p_evt_data, uint8_t app_id,
+                               tBTA_HL_APP_HANDLE app_handle,
+                               tBTA_HL_MCL_HANDLE mcl_handle, BD_ADDR bd_addr,
+                               tBTA_HL_STATUS status) {
+  p_evt_data->cch_open_cfm.app_id = app_id;
+  p_evt_data->cch_open_cfm.app_handle = app_handle;
+  p_evt_data->cch_open_cfm.mcl_handle = mcl_handle;
+  bdcpy(p_evt_data->cch_open_cfm.bd_addr, bd_addr);
+  p_evt_data->cch_open_cfm.status = status;
+  APPL_TRACE_DEBUG("bta_hl_build_cch_open_cfm: status=%d", status);
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_build_cch_open_ind
+ *
+ * Description   This function builds the CCH open indication event data
+ *
+ * Returns      None
+ *
+ ******************************************************************************/
+void bta_hl_build_cch_open_ind(tBTA_HL* p_evt_data,
+                               tBTA_HL_APP_HANDLE app_handle,
+                               tBTA_HL_MCL_HANDLE mcl_handle, BD_ADDR bd_addr) {
+  p_evt_data->cch_open_ind.app_handle = app_handle;
+  p_evt_data->cch_open_ind.mcl_handle = mcl_handle;
+  bdcpy(p_evt_data->cch_open_ind.bd_addr, bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_build_cch_close_cfm
+ *
+ * Description   This function builds the CCH close confirmation event data
+ *
+ * Returns      None
+ *
+ ******************************************************************************/
+void bta_hl_build_cch_close_cfm(tBTA_HL* p_evt_data,
+                                tBTA_HL_APP_HANDLE app_handle,
+                                tBTA_HL_MCL_HANDLE mcl_handle,
+                                tBTA_HL_STATUS status) {
+  p_evt_data->cch_close_cfm.mcl_handle = mcl_handle;
+  p_evt_data->cch_close_cfm.app_handle = app_handle;
+  p_evt_data->cch_close_cfm.status = status;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_build_cch_close_ind
+ *
+ * Description   This function builds the CCH colse indication event data
+ *
+ * Returns      None
+ *
+ ******************************************************************************/
+void bta_hl_build_cch_close_ind(tBTA_HL* p_evt_data,
+                                tBTA_HL_APP_HANDLE app_handle,
+                                tBTA_HL_MCL_HANDLE mcl_handle,
+                                bool intentional) {
+  p_evt_data->cch_close_ind.mcl_handle = mcl_handle;
+  p_evt_data->cch_close_ind.app_handle = app_handle;
+  p_evt_data->cch_close_ind.intentional = intentional;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_build_dch_open_cfm
+ *
+ * Description   This function builds the DCH open confirmation event data
+ *
+ * Returns      None
+ *
+ ******************************************************************************/
+void bta_hl_build_dch_open_cfm(tBTA_HL* p_evt_data,
+                               tBTA_HL_APP_HANDLE app_handle,
+                               tBTA_HL_MCL_HANDLE mcl_handle,
+                               tBTA_HL_MDL_HANDLE mdl_handle,
+                               tBTA_HL_MDEP_ID local_mdep_id,
+                               tBTA_HL_MDL_ID mdl_id, tBTA_HL_DCH_MODE dch_mode,
+                               bool first_reliable, uint16_t mtu,
+                               tBTA_HL_STATUS status)
+
+{
+  p_evt_data->dch_open_cfm.mdl_handle = mdl_handle;
+  p_evt_data->dch_open_cfm.mcl_handle = mcl_handle;
+  p_evt_data->dch_open_cfm.app_handle = app_handle;
+  p_evt_data->dch_open_cfm.local_mdep_id = local_mdep_id;
+  p_evt_data->dch_open_cfm.mdl_id = mdl_id;
+  p_evt_data->dch_open_cfm.dch_mode = dch_mode;
+  p_evt_data->dch_open_cfm.first_reliable = first_reliable;
+  p_evt_data->dch_open_cfm.mtu = mtu;
+  p_evt_data->dch_open_cfm.status = status;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_build_sdp_query_cfm
+ *
+ * Description   This function builds the SDP query indication event data
+ *
+ * Returns      None
+ *
+ ******************************************************************************/
+void bta_hl_build_sdp_query_cfm(tBTA_HL* p_evt_data, uint8_t app_id,
+                                tBTA_HL_APP_HANDLE app_handle, BD_ADDR bd_addr,
+                                tBTA_HL_SDP* p_sdp, tBTA_HL_STATUS status)
+
+{
+  APPL_TRACE_DEBUG("bta_hl_build_sdp_query_cfm: app_id = %d, app_handle=%d",
+                   app_id, app_handle);
+  p_evt_data->sdp_query_cfm.app_id = app_id;
+  p_evt_data->sdp_query_cfm.app_handle = app_handle;
+  bdcpy(p_evt_data->sdp_query_cfm.bd_addr, bd_addr);
+  p_evt_data->sdp_query_cfm.p_sdp = p_sdp;
+  p_evt_data->sdp_query_cfm.status = status;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_build_delete_mdl_cfm
+ *
+ * Description   This function builds the delete MDL confirmation event data
+ *
+ * Returns      None
+ *
+ ******************************************************************************/
+void bta_hl_build_delete_mdl_cfm(tBTA_HL* p_evt_data,
+                                 tBTA_HL_APP_HANDLE app_handle,
+                                 tBTA_HL_MCL_HANDLE mcl_handle,
+                                 tBTA_HL_MDL_ID mdl_id, tBTA_HL_STATUS status)
+
+{
+  p_evt_data->delete_mdl_cfm.mcl_handle = mcl_handle;
+  p_evt_data->delete_mdl_cfm.app_handle = app_handle;
+  p_evt_data->delete_mdl_cfm.mdl_id = mdl_id;
+  p_evt_data->delete_mdl_cfm.status = status;
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hl_build_echo_test_cfm
+ *
+ * Description   This function builds the echo test confirmation event data
+ *
+ * Returns      None
+ *
+ ******************************************************************************/
+void bta_hl_build_echo_test_cfm(tBTA_HL* p_evt_data,
+                                tBTA_HL_APP_HANDLE app_handle,
+                                tBTA_HL_MCL_HANDLE mcl_handle,
+                                tBTA_HL_STATUS status) {
+  p_evt_data->echo_test_cfm.mcl_handle = mcl_handle;
+  p_evt_data->echo_test_cfm.app_handle = app_handle;
+  p_evt_data->echo_test_cfm.status = status;
+}
+
+/*****************************************************************************
+ *  Debug Functions
+ ****************************************************************************/
+#if (BTA_HL_DEBUG == TRUE)
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_status_code
+ *
+ * Description      get the status string pointer
+ *
+ * Returns          char * - status string pointer
+ *
+ ******************************************************************************/
+const char* bta_hl_status_code(tBTA_HL_STATUS status) {
+  switch (status) {
+    case BTA_HL_STATUS_OK:
+      return "BTA_HL_STATUS_OK";
+    case BTA_HL_STATUS_FAIL:
+      return "BTA_HL_STATUS_FAIL";
+    case BTA_HL_STATUS_ABORTED:
+      return "BTA_HL_STATUS_ABORTED";
+    case BTA_HL_STATUS_NO_RESOURCE:
+      return "BTA_HL_STATUS_NO_RESOURCE";
+    case BTA_HL_STATUS_LAST_ITEM:
+      return "BTA_HL_STATUS_LAST_ITEM";
+    case BTA_HL_STATUS_DUPLICATE_APP_ID:
+      return "BTA_HL_STATUS_DUPLICATE_APP_ID";
+    case BTA_HL_STATUS_INVALID_APP_HANDLE:
+      return "BTA_HL_STATUS_INVALID_APP_HANDLE";
+    case BTA_HL_STATUS_INVALID_MCL_HANDLE:
+      return "BTA_HL_STATUS_INVALID_MCL_HANDLE";
+    case BTA_HL_STATUS_MCAP_REG_FAIL:
+      return "BTA_HL_STATUS_MCAP_REG_FAIL";
+    case BTA_HL_STATUS_MDEP_CO_FAIL:
+      return "BTA_HL_STATUS_MDEP_CO_FAIL";
+    case BTA_HL_STATUS_ECHO_CO_FAIL:
+      return "BTA_HL_STATUS_ECHO_CO_FAIL";
+    case BTA_HL_STATUS_MDL_CFG_CO_FAIL:
+      return "BTA_HL_STATUS_MDL_CFG_CO_FAIL";
+    case BTA_HL_STATUS_SDP_NO_RESOURCE:
+      return "BTA_HL_STATUS_SDP_NO_RESOURCE";
+    case BTA_HL_STATUS_SDP_FAIL:
+      return "BTA_HL_STATUS_SDP_FAIL";
+    case BTA_HL_STATUS_NO_CCH:
+      return "BTA_HL_STATUS_NO_CCH";
+    case BTA_HL_STATUS_NO_MCL:
+      return "BTA_HL_STATUS_NO_MCL";
+
+    case BTA_HL_STATUS_NO_FIRST_RELIABLE:
+      return "BTA_HL_STATUS_NO_FIRST_RELIABLE";
+    case BTA_HL_STATUS_INVALID_DCH_CFG:
+      return "BTA_HL_STATUS_INVALID_DCH_CFG";
+    case BTA_HL_STATUS_INVALID_BD_ADDR:
+      return "BTA_HL_STATUS_INVALID_BD_ADDR";
+    case BTA_HL_STATUS_INVALID_RECONNECT_CFG:
+      return "BTA_HL_STATUS_INVALID_RECONNECT_CFG";
+    case BTA_HL_STATUS_ECHO_TEST_BUSY:
+      return "BTA_HL_STATUS_ECHO_TEST_BUSY";
+    case BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID:
+      return "BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID";
+    case BTA_HL_STATUS_INVALID_MDL_ID:
+      return "BTA_HL_STATUS_INVALID_MDL_ID";
+    case BTA_HL_STATUS_NO_MDL_ID_FOUND:
+      return "BTA_HL_STATUS_NO_MDL_ID_FOUND";
+    case BTA_HL_STATUS_DCH_BUSY:
+      return "BTA_HL_STATUS_DCH_BUSY";
+    default:
+      return "Unknown status code";
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_hl_evt_code
+ *
+ * Description      Maps HL event code to the corresponding event string
+ *
+ * Returns          string pointer for the associated event name
+ *
+ ******************************************************************************/
+const char* bta_hl_evt_code(tBTA_HL_INT_EVT evt_code) {
+  switch (evt_code) {
+    case BTA_HL_CCH_OPEN_EVT:
+      return "BTA_HL_CCH_OPEN_EVT";
+    case BTA_HL_CCH_SDP_OK_EVT:
+      return "BTA_HL_CCH_SDP_OK_EVT";
+    case BTA_HL_CCH_SDP_FAIL_EVT:
+      return "BTA_HL_CCH_SDP_FAIL_EVT";
+    case BTA_HL_MCA_CONNECT_IND_EVT:
+      return "BTA_HL_MCA_CONNECT_IND_EVT";
+    case BTA_HL_MCA_DISCONNECT_IND_EVT:
+      return "BTA_HL_MCA_DISCONNECT_IND_EVT";
+
+    case BTA_HL_CCH_CLOSE_EVT:
+      return "BTA_HL_CCH_CLOSE_EVT";
+    case BTA_HL_CCH_CLOSE_CMPL_EVT:
+      return "BTA_HL_CCH_CLOSE_CMPL_EVT";
+    case BTA_HL_DCH_OPEN_EVT:
+      return "BTA_HL_DCH_OPEN_EVT";
+    case BTA_HL_MCA_CREATE_IND_EVT:
+      return "BTA_HL_MCA_CREATE_IND_EVT";
+    case BTA_HL_MCA_CREATE_CFM_EVT:
+      return "BTA_HL_MCA_CREATE_CFM_EVT";
+    case BTA_HL_MCA_OPEN_IND_EVT:
+      return "BTA_HL_MCA_OPEN_IND_EVT";
+    case BTA_HL_MCA_OPEN_CFM_EVT:
+      return "BTA_HL_MCA_OPEN_CFM_EVT";
+    case BTA_HL_DCH_CLOSE_EVT:
+      return "BTA_HL_DCH_CLOSE_EVT";
+    case BTA_HL_MCA_CLOSE_IND_EVT:
+      return "BTA_HL_MCA_CLOSE_IND_EVT";
+    case BTA_HL_MCA_CLOSE_CFM_EVT:
+      return "BTA_HL_MCA_CLOSE_CFM_EVT";
+    case BTA_HL_API_SEND_DATA_EVT:
+      return "BTA_HL_API_SEND_DATA_EVT";
+    case BTA_HL_MCA_RCV_DATA_EVT:
+      return "BTA_HL_MCA_RCV_DATA_EVT";
+    case BTA_HL_DCH_CLOSE_CMPL_EVT:
+      return "BTA_HL_DCH_CLOSE_CMPL_EVT";
+
+    case BTA_HL_API_ENABLE_EVT:
+      return "BTA_HL_API_ENABLE_EVT";
+    case BTA_HL_API_DISABLE_EVT:
+      return "BTA_HL_API_DISABLE_EVT";
+    case BTA_HL_API_UPDATE_EVT:
+      return "BTA_HL_API_UPDATE_EVT";
+    case BTA_HL_API_REGISTER_EVT:
+      return "BTA_HL_API_REGISTER_EVT";
+    case BTA_HL_API_DEREGISTER_EVT:
+      return "BTA_HL_API_DEREGISTER_EVT";
+
+    case BTA_HL_API_CCH_OPEN_EVT:
+      return "BTA_HL_API_CCH_OPEN_EVT";
+
+    case BTA_HL_API_CCH_CLOSE_EVT:
+      return "BTA_HL_API_CCH_CLOSE_EVT";
+    case BTA_HL_API_DCH_OPEN_EVT:
+      return "BTA_HL_API_DCH_OPEN_EVT";
+
+    case BTA_HL_API_DCH_RECONNECT_EVT:
+      return "BTA_HL_API_DCH_RECONNECT_EVT";
+    case BTA_HL_API_DCH_CLOSE_EVT:
+      return "BTA_HL_API_DCH_CLOSE_EVT";
+    case BTA_HL_API_DELETE_MDL_EVT:
+      return "BTA_HL_API_DELETE_MDL_EVT";
+    case BTA_HL_API_DCH_ABORT_EVT:
+      return "BTA_HL_API_DCH_ABORT_EVT";
+
+    case BTA_HL_DCH_RECONNECT_EVT:
+      return "BTA_HL_DCH_RECONNECT_EVT";
+    case BTA_HL_DCH_SDP_INIT_EVT:
+      return "BTA_HL_DCH_SDP_INIT_EVT";
+    case BTA_HL_DCH_SDP_FAIL_EVT:
+      return "BTA_HL_DCH_SDP_FAIL_EVT";
+    case BTA_HL_API_DCH_ECHO_TEST_EVT:
+      return "BTA_HL_API_DCH_ECHO_TEST_EVT";
+    case BTA_HL_DCH_CLOSE_ECHO_TEST_EVT:
+      return "BTA_HL_DCH_CLOSE_ECHO_TEST_EVT";
+    case BTA_HL_MCA_RECONNECT_IND_EVT:
+      return "BTA_HL_MCA_RECONNECT_IND_EVT";
+    case BTA_HL_MCA_RECONNECT_CFM_EVT:
+      return "BTA_HL_MCA_RECONNECT_CFM_EVT";
+    case BTA_HL_API_DCH_CREATE_RSP_EVT:
+      return "BTA_HL_API_DCH_CREATE_RSP_EVT";
+    case BTA_HL_DCH_ABORT_EVT:
+      return "BTA_HL_DCH_ABORT_EVT";
+    case BTA_HL_MCA_ABORT_IND_EVT:
+      return "BTA_HL_MCA_ABORT_IND_EVT";
+    case BTA_HL_MCA_ABORT_CFM_EVT:
+      return "BTA_HL_MCA_ABORT_CFM_EVT";
+    case BTA_HL_MCA_DELETE_IND_EVT:
+      return "BTA_HL_MCA_DELETE_IND_EVT";
+    case BTA_HL_MCA_DELETE_CFM_EVT:
+      return "BTA_HL_MCA_DELETE_CFM_EVT";
+    case BTA_HL_MCA_CONG_CHG_EVT:
+      return "BTA_HL_MCA_CONG_CHG_EVT";
+    case BTA_HL_CI_GET_TX_DATA_EVT:
+      return "BTA_HL_CI_GET_TX_DATA_EVT";
+    case BTA_HL_CI_PUT_RX_DATA_EVT:
+      return "BTA_HL_CI_PUT_RX_DATA_EVT";
+    case BTA_HL_CI_GET_ECHO_DATA_EVT:
+      return "BTA_HL_CI_GET_ECHO_DATA_EVT";
+    case BTA_HL_DCH_ECHO_TEST_EVT:
+      return "BTA_HL_DCH_ECHO_TEST_EVT";
+    case BTA_HL_CI_PUT_ECHO_DATA_EVT:
+      return "BTA_HL_CI_PUT_ECHO_DATA_EVT";
+    case BTA_HL_API_SDP_QUERY_EVT:
+      return "BTA_HL_API_SDP_QUERY_EVT";
+    case BTA_HL_SDP_QUERY_OK_EVT:
+      return "BTA_HL_SDP_QUERY_OK_EVT";
+    case BTA_HL_SDP_QUERY_FAIL_EVT:
+      return "BTA_HL_SDP_QUERY_FAIL_EVT";
+    case BTA_HL_MCA_RSP_TOUT_IND_EVT:
+      return "BTA_HL_MCA_RSP_TOUT_IND_EVT";
+
+    default:
+      return "Unknown HL event code";
+  }
+}
+
+#endif  /* Debug Functions */
+#endif  // HL_INCLUDED
diff --git a/bt/bta/include/bta_ag_api.h b/bt/bta/include/bta_ag_api.h
new file mode 100644
index 0000000..7088536
--- /dev/null
+++ b/bt/bta/include/bta_ag_api.h
@@ -0,0 +1,598 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 is the public interface file for the audio gateway (AG) subsystem
+ *  of BTA, Broadcom's Bluetooth application layer for mobile phones.
+ *
+ ******************************************************************************/
+#ifndef BTA_AG_API_H
+#define BTA_AG_API_H
+
+#include "bta_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+ *  Constants and data types
+ ****************************************************************************/
+#define HFP_VERSION_1_1 0x0101
+#define HFP_VERSION_1_5 0x0105
+#define HFP_VERSION_1_6 0x0106
+#define HFP_VERSION_1_7 0x0107
+
+#define HSP_VERSION_1_0 0x0100
+#define HSP_VERSION_1_2 0x0102
+
+/* Note, if you change the default version here, please also change the one in
+ * bta_hs_api.h, they are meant to be the same.
+ */
+#ifndef BTA_HFP_VERSION
+#define BTA_HFP_VERSION HFP_VERSION_1_7
+#endif
+
+/* AG feature masks */
+#define BTA_AG_FEAT_3WAY 0x00000001 /* Three-way calling */
+#define BTA_AG_FEAT_ECNR \
+  0x00000002 /* Echo cancellation and/or noise reduction */
+#define BTA_AG_FEAT_VREC 0x00000004   /* Voice recognition */
+#define BTA_AG_FEAT_INBAND 0x00000008 /* In-band ring tone */
+#define BTA_AG_FEAT_VTAG 0x00000010   /* Attach a phone number to a voice tag */
+#define BTA_AG_FEAT_REJECT 0x00000020 /* Ability to reject incoming call */
+#define BTA_AG_FEAT_ECS 0x00000040    /* Enhanced Call Status */
+#define BTA_AG_FEAT_ECC 0x00000080    /* Enhanced Call Control */
+#define BTA_AG_FEAT_EXTERR 0x00000100 /* Extended error codes */
+#define BTA_AG_FEAT_CODEC 0x00000200  /* Codec Negotiation */
+
+#define HFP_1_6_FEAT_MASK \
+  0x000003FF /* Valid feature bit mask for HFP 1.6 (and below) */
+
+/* HFP 1.7+ */
+#define BTA_AG_FEAT_HF_IND 0x00000400 /* HF Indicators */
+#define BTA_AG_FEAT_ESCO 0x00000800   /* eSCO S4 (and T2) setting supported */
+
+/* Proprietary features: using 31 ~ 16 bits */
+#define BTA_AG_FEAT_BTRH 0x00010000 /* CCAP incoming call hold */
+#define BTA_AG_FEAT_UNAT \
+  0x00020000 /* Pass unknown AT commands to application */
+#define BTA_AG_FEAT_NOSCO 0x00040000   /* No SCO control performed by BTA AG */
+#define BTA_AG_FEAT_NO_ESCO 0x00080000 /* Do not allow or use eSCO */
+#define BTA_AG_FEAT_VOIP 0x00100000    /* VoIP call */
+
+typedef uint32_t tBTA_AG_FEAT;
+
+/* AG parse mode */
+#define BTA_AG_PARSE 0 /* Perform AT command parsing in AG */
+#define BTA_AG_PASS_THROUGH \
+  1 /* Pass data directly to phone's AT command interpreter */
+
+typedef uint8_t tBTA_AG_PARSE_MODE;
+
+/* AG open status */
+#define BTA_AG_SUCCESS 0        /* Connection successfully opened */
+#define BTA_AG_FAIL_SDP 1       /* Open failed due to SDP */
+#define BTA_AG_FAIL_RFCOMM 2    /* Open failed due to RFCOMM */
+#define BTA_AG_FAIL_RESOURCES 3 /* out of resources failure  */
+
+/* Status to disallow passing AT Events after BTIF */
+#define BTA_AG_DISALLOW_AT 5
+
+typedef uint8_t tBTA_AG_STATUS;
+
+/* handle values used with BTA_AgResult */
+#define BTA_AG_HANDLE_NONE 0
+#define BTA_AG_HANDLE_ALL 0xFFFF
+/* It is safe to use the same value as BTA_AG_HANDLE_ALL
+ * HANDLE_ALL is used for delivering indication
+ * SCO_NO_CHANGE is used for changing sco behavior
+ * They donot interfere with each other
+ */
+
+/* Number of supported HF indicators, there is one HF indicator so far i.e.
+                                                   enhanced driver status. */
+/* Number of supported HF indicators,
+   1 for Enhanced Safety Status
+   2 for Battery Level Status */
+#ifndef BTA_AG_NUM_LOCAL_HF_IND
+#define BTA_AG_NUM_LOCAL_HF_IND 2
+#endif
+
+#define BTA_AG_HANDLE_SCO_NO_CHANGE 0xFFFF
+
+/* AG result codes used with BTA_AgResult */
+#define BTA_AG_SPK_RES 0         /* Update speaker volume */
+#define BTA_AG_MIC_RES 1         /* Update microphone volume */
+#define BTA_AG_INBAND_RING_RES 2 /* Update inband ring state */
+#define BTA_AG_CIND_RES 3        /* Send indicator response for AT+CIND */
+#define BTA_AG_BINP_RES 4     /* Send phone number for voice tag for AT+BINP */
+#define BTA_AG_IND_RES 5      /* Update an indicator value */
+#define BTA_AG_BVRA_RES 6     /* Update voice recognition state */
+#define BTA_AG_CNUM_RES 7     /* Send subscriber number response for AT+CNUM */
+#define BTA_AG_BTRH_RES 8     /* Send CCAP incoming call hold */
+#define BTA_AG_CLCC_RES 9     /* Query list of calls */
+#define BTA_AG_COPS_RES 10    /* Read network operator */
+#define BTA_AG_IN_CALL_RES 11 /* Indicate incoming phone call */
+#define BTA_AG_IN_CALL_CONN_RES 12  /* Incoming phone call connected */
+#define BTA_AG_CALL_WAIT_RES 13     /* Call waiting notification */
+#define BTA_AG_OUT_CALL_ORIG_RES 14 /* Outgoing phone call origination */
+#define BTA_AG_OUT_CALL_ALERT_RES \
+  15 /* Outgoing phone call alerting remote party */
+#define BTA_AG_OUT_CALL_CONN_RES 16 /* Outgoing phone call connected */
+#define BTA_AG_CALL_CANCEL_RES \
+  17 /* Incoming/outgoing 3-way canceled before connected */
+#define BTA_AG_END_CALL_RES 18     /* End call */
+#define BTA_AG_IN_CALL_HELD_RES 19 /* Incoming call held */
+#define BTA_AG_UNAT_RES 20         /* Response to unknown AT command event */
+#define BTA_AG_MULTI_CALL_RES 21   /* SLC at three way call */
+#define BTA_AG_BIND_RES 22         /* Activate/Deactivate HF indicator */
+
+typedef uint8_t tBTA_AG_RES;
+
+/* HFP peer features */
+#define BTA_AG_PEER_FEAT_ECNR \
+  0x0001 /* Echo cancellation and/or noise reduction */
+#define BTA_AG_PEER_FEAT_3WAY 0x0002   /* Call waiting and three-way calling */
+#define BTA_AG_PEER_FEAT_CLI 0x0004    /* Caller ID presentation capability */
+#define BTA_AG_PEER_FEAT_VREC 0x0008   /* Voice recognition activation */
+#define BTA_AG_PEER_FEAT_VOL 0x0010    /* Remote volume control */
+#define BTA_AG_PEER_FEAT_ECS 0x0020    /* Enhanced Call Status */
+#define BTA_AG_PEER_FEAT_ECC 0x0040    /* Enhanced Call Control */
+#define BTA_AG_PEER_FEAT_CODEC 0x0080  /* Codec Negotiation */
+#define BTA_AG_PEER_FEAT_HF_IND 0x0100 /* HF Indicators */
+#define BTA_AG_PEER_FEAT_ESCO 0x0200   /* eSCO S4 (and T2) setting supported */
+
+/* Proprietary features: using bits after 12 */
+#define BTA_AG_PEER_FEAT_UNAT \
+  0x1000 /* Pass unknown AT command responses to application */
+#define BTA_AG_PEER_FEAT_VOIP 0x2000 /* VoIP call */
+
+typedef uint16_t tBTA_AG_PEER_FEAT;
+
+/* HFP peer supported codec masks */
+// TODO(google) This should use common definitions
+// in hci/include/hci_audio.h
+#define BTA_AG_CODEC_NONE BTM_SCO_CODEC_NONE
+#define BTA_AG_CODEC_CVSD BTM_SCO_CODEC_CVSD /* CVSD */
+#define BTA_AG_CODEC_MSBC BTM_SCO_CODEC_MSBC /* mSBC */
+typedef uint16_t tBTA_AG_PEER_CODEC;
+
+/* HFP errcode - Set when BTA_AG_OK_ERROR is returned in 'ok_flag' */
+#define BTA_AG_ERR_PHONE_FAILURE 0     /* Phone Failure */
+#define BTA_AG_ERR_NO_CONN_PHONE 1     /* No connection to phone */
+#define BTA_AG_ERR_OP_NOT_ALLOWED 3    /* Operation not allowed */
+#define BTA_AG_ERR_OP_NOT_SUPPORTED 4  /* Operation not supported */
+#define BTA_AG_ERR_PHSIM_PIN_REQ 5     /* PH-SIM PIN required */
+#define BTA_AG_ERR_SIM_NOT_INSERTED 10 /* SIM not inserted */
+#define BTA_AG_ERR_SIM_PIN_REQ 11      /* SIM PIN required */
+#define BTA_AG_ERR_SIM_PUK_REQ 12      /* SIM PUK required */
+#define BTA_AG_ERR_SIM_FAILURE 13      /* SIM failure */
+#define BTA_AG_ERR_SIM_BUSY 14         /* SIM busy */
+#define BTA_AG_ERR_INCORRECT_PWD 16    /* Incorrect password */
+#define BTA_AG_ERR_SIM_PIN2_REQ 17     /* SIM PIN2 required */
+#define BTA_AG_ERR_SIM_PUK2_REQ 18     /* SIM PUK2 required */
+#define BTA_AG_ERR_MEMORY_FULL 20      /* Memory full */
+#define BTA_AG_ERR_INVALID_INDEX 21    /* Invalid index */
+#define BTA_AG_ERR_MEMORY_FAILURE 23   /* Memory failure */
+#define BTA_AG_ERR_TEXT_TOO_LONG 24    /* Text string too long */
+#define BTA_AG_ERR_INV_CHAR_IN_TSTR 25 /* Invalid characters in text string */
+#define BTA_AG_ERR_DSTR_TOO_LONG 26    /* Dial string too long */
+#define BTA_AG_ERR_INV_CHAR_IN_DSTR 27 /* Invalid characters in dial string */
+#define BTA_AG_ERR_NO_NETWORK_SERV 30  /* No network service */
+#define BTA_AG_ERR_NETWORK_TIME_OUT 31 /* Network timeout */
+#define BTA_AG_ERR_NO_NET_EMG_ONLY \
+  32 /* Network not allowed - emergency service only */
+#define BTA_AG_ERR_VOIP_CS_CALLS \
+  33 /* AG cannot create simultaneous VoIP and CS calls */
+#define BTA_AG_ERR_NOT_FOR_VOIP 34  /* Not supported on this call type(VoIP) */
+#define BTA_AG_ERR_SIP_RESP_CODE 35 /* SIP 3 digit response code */
+
+#if 0 /* Not Used in Bluetooth HFP 1.5 Specification */
+#define BTA_AG_ERR_PHADAP_LNK_RES 2   /* Phone-adapter link reserved */
+#define BTA_AG_ERR_PHFSIM_PIN_REQ 6   /* PH-FSIM PIN required */
+#define BTA_AG_ERR_PHFSIM_PUK_REQ 7   /* PH-FSIM PUK required */
+#define BTA_AG_ERR_SIM_WRONG 15       /* SIM wrong */
+#define BTA_AG_ERR_NOT_FOUND 22       /* Not found */
+#define BTA_AG_ERR_NETWORK_TIMEOUT 31 /* Network timeout */
+#define BTA_AG_ERR_NET_PIN_REQ 40     /* Network personalization PIN required */
+#define BTA_AG_ERR_NET_PUK_REQ 41     /* Network personalization PUK required */
+#define BTA_AG_ERR_SUBSET_PIN_REQ \
+  42 /* Network subset personalization PIN required */
+#define BTA_AG_ERR_SUBSET_PUK_REQ \
+  43 /* Network subset personalization PUK required */
+#define BTA_AG_ERR_SERVPRO_PIN_REQ \
+  44 /* Service provider personalization PIN required */
+#define BTA_AG_ERR_SERVPRO_PUK_REQ \
+  45 /* Service provider personalization PUK required */
+#define BTA_AG_ERR_CORP_PIN_REQ                \
+  46 /* Corporate personalization PIN required \
+        */
+#define BTA_AG_ERR_CORP_PUK_REQ                                          \
+  47                           /* Corporate personalization PUK required \
+                                  */
+#define BTA_AG_ERR_UNKNOWN 100 /* Unknown error */
+/* GPRS-related errors */
+#define BTA_AG_ERR_ILL_MS 103  /* Illegal MS (#3) */
+#define BTA_AG_ERR_ILL_ME 106  /* Illegal ME (#6) */
+#define BTA_AG_ERR_GPRS_NOT_ALLOWED 107 /* GPRS services not allowed (#7) */
+#define BTA_AG_ERR_PLMN_NOT_ALLOWED 111 /* PLMN services not allowed (#11) */
+#define BTA_AG_ERR_LOC_NOT_ALLOWED 112  /* Location area not allowed (#12) */
+#define BTA_AG_ERR_ROAM_NOT_ALLOWED \
+  113                               /* Roaming not allowed in this location area (#13) */
+/* Errors related to a failure to Activate a Context */
+#define BTA_AG_ERR_OPT_NOT_SUPP 132 /* Service option not supported (#32) */
+#define BTA_AG_ERR_OPT_NOT_SUBSCR \
+  133 /* Requested service option not subscribed (#33) */
+#define BTA_AG_ERR_OPT_OUT_OF_ORDER \
+  134 /* Service option temporarily out of order (#34) */
+#define BTA_AG_ERR_PDP_AUTH_FAILURE 149 /* PDP authentication failure */
+/* Other GPRS errors */
+#define BTA_AG_ERR_INV_MOBILE_CLASS 150 /* Invalid mobile class */
+#define BTA_AG_ERR_UNSPEC_GPRS_ERR 148  /* Unspecified GPRS error */
+#endif                                  /* Unused error codes */
+
+/* HFP result data 'ok_flag' */
+#define BTA_AG_OK_CONTINUE 0 /* Send out response (more responses coming) */
+#define BTA_AG_OK_DONE 1     /* Send out response followed by OK (finished) */
+#define BTA_AG_OK_ERROR 2    /* Error response */
+
+/* BTRH values */
+#define BTA_AG_BTRH_SET_HOLD 0 /* Put incoming call on hold */
+#define BTA_AG_BTRH_SET_ACC 1  /* Accept incoming call on hold */
+#define BTA_AG_BTRH_SET_REJ 2  /* Reject incoming call on hold */
+#define BTA_AG_BTRH_READ 3     /* Read the current value */
+#define BTA_AG_BTRH_NO_RESP 4  /* Not in RH States (reply to read) */
+
+/* ASCII character string of arguments to the AT command or result */
+#ifndef BTA_AG_AT_MAX_LEN
+#define BTA_AG_AT_MAX_LEN 256
+#endif
+
+/* data associated with BTA_AG_IND_RES */
+typedef struct {
+  uint16_t id;
+  uint16_t value;
+  bool on_demand;
+} tBTA_AG_IND;
+
+/* data type for BTA_AgResult() */
+typedef struct {
+  char str[BTA_AG_AT_MAX_LEN + 1];
+  tBTA_AG_IND ind;
+  uint16_t num;
+  uint16_t audio_handle;
+  uint16_t errcode; /* Valid only if 'ok_flag' is set to BTA_AG_OK_ERROR */
+  uint8_t
+      ok_flag; /* Indicates if response is finished, and if error occurred */
+  bool state;
+} tBTA_AG_RES_DATA;
+
+/* AG callback events */
+#define BTA_AG_ENABLE_EVT 0      /* AG enabled */
+#define BTA_AG_REGISTER_EVT 1    /* AG registered */
+#define BTA_AG_OPEN_EVT 2        /* AG connection open */
+#define BTA_AG_CLOSE_EVT 3       /* AG connection closed */
+#define BTA_AG_CONN_EVT 4        /* Service level connection opened */
+#define BTA_AG_AUDIO_OPEN_EVT 5  /* Audio connection open */
+#define BTA_AG_AUDIO_CLOSE_EVT 6 /* Audio connection closed */
+#define BTA_AG_SPK_EVT 7         /* Speaker volume changed */
+#define BTA_AG_MIC_EVT 8         /* Microphone volume changed */
+#define BTA_AG_AT_CKPD_EVT 9     /* CKPD from the HS */
+#define BTA_AG_DISABLE_EVT 30    /* AG disabled       */
+#if (BTM_WBS_INCLUDED == TRUE)
+#define BTA_AG_WBS_EVT 31 /* SCO codec info */
+#endif
+/* Values below are for HFP only */
+#define BTA_AG_AT_A_EVT 10    /* Answer a call */
+#define BTA_AG_AT_D_EVT 11    /* Place a call using number or memory dial */
+#define BTA_AG_AT_CHLD_EVT 12 /* Call hold */
+#define BTA_AG_AT_CHUP_EVT 13 /* Hang up a call */
+#define BTA_AG_AT_CIND_EVT 14 /* Read indicator settings */
+#define BTA_AG_AT_VTS_EVT 15  /* Transmit DTMF tone */
+#define BTA_AG_AT_BINP_EVT 16 /* Retrieve number from voice tag */
+#define BTA_AG_AT_BLDN_EVT 17 /* Place call to last dialed number */
+#define BTA_AG_AT_BVRA_EVT 18 /* Enable/disable voice recognition */
+#define BTA_AG_AT_NREC_EVT 19 /* Disable echo canceling */
+#define BTA_AG_AT_CNUM_EVT 20 /* Retrieve subscriber number */
+#define BTA_AG_AT_BTRH_EVT 21 /* CCAP-style incoming call hold */
+#define BTA_AG_AT_CLCC_EVT 22 /* Query list of current calls */
+#define BTA_AG_AT_COPS_EVT 23 /* Query list of current calls */
+#define BTA_AG_AT_UNAT_EVT 24 /* Unknown AT command */
+#define BTA_AG_AT_CBC_EVT 25  /* Battery Level report from HF */
+#define BTA_AG_AT_BAC_EVT 26  /* avablable codec */
+#define BTA_AG_AT_BCS_EVT 27  /* Codec select */
+#define BTA_AG_AT_BIND_EVT 28 /* HF indicator */
+#define BTA_AG_AT_BIEV_EVT 29 /* HF indicator updates from peer */
+
+typedef uint8_t tBTA_AG_EVT;
+
+/* data associated with most non-AT events */
+typedef struct {
+  uint16_t handle;
+  uint8_t app_id;
+  tBTA_AG_STATUS status;
+} tBTA_AG_HDR;
+
+/* data associated with BTA_AG_REGISTER_EVT */
+typedef struct {
+  tBTA_AG_HDR hdr;
+  tBTA_AG_STATUS status;
+} tBTA_AG_REGISTER;
+
+/* data associated with BTA_AG_OPEN_EVT */
+typedef struct {
+  tBTA_AG_HDR hdr;
+  BD_ADDR bd_addr;
+  tBTA_SERVICE_ID service_id;
+  tBTA_AG_STATUS status;
+} tBTA_AG_OPEN;
+
+/* data associated with BTA_AG_CLOSE_EVT */
+typedef struct {
+  tBTA_AG_HDR hdr;
+  BD_ADDR bd_addr;
+} tBTA_AG_CLOSE;
+
+/* data associated with BTA_AG_CONN_EVT */
+typedef struct {
+  tBTA_AG_HDR hdr;
+  tBTA_AG_PEER_FEAT peer_feat;
+  BD_ADDR bd_addr;
+  tBTA_AG_PEER_CODEC peer_codec;
+} tBTA_AG_CONN;
+
+/* data associated with AT command event */
+typedef struct {
+  tBTA_AG_HDR hdr;
+  BD_ADDR bd_addr;
+  char str[BTA_AG_AT_MAX_LEN + 1];
+  uint16_t num;
+  uint8_t idx;   /* call number used by CLCC and CHLD */
+  uint16_t lidx; /* long index, ex, HF indicator */
+} tBTA_AG_VAL;
+
+/* union of data associated with AG callback */
+typedef union {
+  tBTA_AG_HDR hdr;
+  tBTA_AG_REGISTER reg;
+  tBTA_AG_OPEN open;
+  tBTA_AG_CLOSE close;
+  tBTA_AG_CONN conn;
+  tBTA_AG_VAL val;
+} tBTA_AG;
+
+/* AG callback */
+typedef void(tBTA_AG_CBACK)(tBTA_AG_EVT event, tBTA_AG* p_data);
+
+/* indicator constants HFP 1.1 and later */
+#define BTA_AG_IND_CALL 1      /* position of call indicator */
+#define BTA_AG_IND_CALLSETUP 2 /* position of callsetup indicator */
+#define BTA_AG_IND_SERVICE 3   /* position of service indicator */
+
+/* indicator constants HFP 1.5 and later */
+#define BTA_AG_IND_SIGNAL 4   /* position of signal strength indicator */
+#define BTA_AG_IND_ROAM 5     /* position of roaming indicator */
+#define BTA_AG_IND_BATTCHG 6  /* position of battery charge indicator */
+#define BTA_AG_IND_CALLHELD 7 /* position of callheld indicator */
+#define BTA_AG_IND_BEARER 8   /* position of bearer indicator */
+
+/* call indicator values */
+#define BTA_AG_CALL_INACTIVE 0 /* Phone call inactive */
+#define BTA_AG_CALL_ACTIVE 1   /* Phone call active */
+
+/* callsetup indicator values */
+#define BTA_AG_CALLSETUP_NONE 0     /* Not currently in call set up */
+#define BTA_AG_CALLSETUP_INCOMING 1 /* Incoming call process ongoing */
+#define BTA_AG_CALLSETUP_OUTGOING 2 /* Outgoing call set up is ongoing */
+#define BTA_AG_CALLSETUP_ALERTING \
+  3 /* Remote party being alerted in an outgoing call */
+
+/* service indicator values */
+#define BTA_AG_SERVICE_NONE 0 /* Neither CS nor VoIP service is available */
+#define BTA_AG_SERVICE_CS 1   /* Only CS service is available                 */
+#define BTA_AG_SERVICE_VOIP 2 /* Only VoIP service is available */
+#define BTA_AG_SERVICE_CS_VOIP \
+  3 /* Both CS and VoIP services available          */
+
+/* callheld indicator values */
+#define BTA_AG_CALLHELD_INACTIVE 0 /* No held calls */
+#define BTA_AG_CALLHELD_ACTIVE 1   /* Call held and call active */
+#define BTA_AG_CALLHELD_NOACTIVE 2 /* Call held and no call active */
+
+/* signal strength indicator values */
+#define BTA_AG_ROAMING_INACTIVE 0 /* Phone call inactive */
+#define BTA_AG_ROAMING_ACTIVE 1   /* Phone call active */
+
+/* bearer indicator values */
+#define BTA_AG_BEARER_WLAN 0      /* WLAN         */
+#define BTA_AG_BEARER_BLUETOOTH 1 /* Bluetooth    */
+#define BTA_AG_BEARER_WIRED 2     /* Wired        */
+#define BTA_AG_BEARER_2G3G 3      /* 2G 3G        */
+#define BTA_AG_BEARER_WIMAX 4     /* WIMAX        */
+#define BTA_AG_BEARER_RES1 5      /* Reserved     */
+#define BTA_AG_BEARER_RES2 6      /* Reserved     */
+#define BTA_AG_BEARER_RES3 7      /* Reserved     */
+
+/* type for HF indicator */
+typedef struct {
+  uint16_t ind_id;
+  bool is_supported;
+  bool is_enable;
+  uint32_t ind_min_val;
+  uint32_t ind_max_val;
+} tBTA_AG_HF_IND;
+
+/* AG configuration structure */
+typedef struct {
+  const char* cind_info;
+  const char* bind_info;
+  uint8_t num_local_hf_ind;
+  int32_t conn_tout;
+  uint16_t sco_pkt_types;
+  const char* chld_val_ecc;
+  const char* chld_val;
+} tBTA_AG_CFG;
+
+/*****************************************************************************
+ *  External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         BTA_AgEnable
+ *
+ * Description      Enable the audio gateway service. When the enable
+ *                  operation is complete the callback function will be
+ *                  called with a BTA_AG_ENABLE_EVT. This function must
+ *                  be called before other function in the AG API are
+ *                  called.
+ *
+ * Returns          BTA_SUCCESS if OK, BTA_FAILURE otherwise.
+ *
+ ******************************************************************************/
+tBTA_STATUS BTA_AgEnable(tBTA_AG_PARSE_MODE parse_mode, tBTA_AG_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AgDisable
+ *
+ * Description      Disable the audio gateway service
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AgDisable(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AgRegister
+ *
+ * Description      Register an Audio Gateway service.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AgRegister(tBTA_SERVICE_MASK services, tBTA_SEC sec_mask,
+                    tBTA_AG_FEAT features, const char* p_service_names[],
+                    uint8_t app_id);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AgDeregister
+ *
+ * Description      Deregister an audio gateway service.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AgDeregister(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AgOpen
+ *
+ * Description      Opens a connection to a headset or hands-free device.
+ *                  When connection is open callback function is called
+ *                  with a BTA_AG_OPEN_EVT. Only the data connection is
+ *                  opened. The audio connection is not opened.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AgOpen(uint16_t handle, BD_ADDR bd_addr, tBTA_SEC sec_mask,
+                tBTA_SERVICE_MASK services);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AgClose
+ *
+ * Description      Close the current connection to a headset or a handsfree
+ *                  Any current audio connection will also be closed
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AgClose(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AgAudioOpen
+ *
+ * Description      Opens an audio connection to the currently connected
+ *                  headset or hnadsfree
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AgAudioOpen(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AgAudioClose
+ *
+ * Description      Close the currently active audio connection to a headset
+ *                  or hnadsfree. The data connection remains open
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AgAudioClose(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AgResult
+ *
+ * Description      Send an AT result code to a headset or hands-free device.
+ *                  This function is only used when the AG parse mode is set
+ *                  to BTA_AG_PARSE.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AgResult(uint16_t handle, tBTA_AG_RES result,
+                  tBTA_AG_RES_DATA* p_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AgSetCodec
+ *
+ * Description      Specify the codec type to be used for the subsequent
+ *                  audio connection.
+ *
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AgSetCodec(uint16_t handle, tBTA_AG_PEER_CODEC codec);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_AG_API_H */
diff --git a/bt/bta/include/bta_ag_ci.h b/bt/bta/include/bta_ag_ci.h
new file mode 100644
index 0000000..984625a
--- /dev/null
+++ b/bt/bta/include/bta_ag_ci.h
@@ -0,0 +1,78 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 is the interface file for audio gateway call-in functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_AG_CI_H
+#define BTA_AG_CI_H
+
+#include "bta_ag_api.h"
+
+/*****************************************************************************
+ *  Function Declarations
+ ****************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_ci_rx_write
+ *
+ * Description      This function is called to send data to the AG when the AG
+ *                  is configured for AT command pass-through.  The function
+ *                  copies data to an event buffer and sends it.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_ag_ci_rx_write(uint16_t handle, char* p_data, uint16_t len);
+
+/******************************************************************************
+ *
+ * Function         bta_ag_ci_slc_ready
+ *
+ * Description      This function is called to notify AG that SLC is up at
+ *                  the application. This funcion is only used when the app
+ *                  is running in pass-through mode.
+ *
+ * Returns          void
+ *
+ *****************************************************************************/
+extern void bta_ag_ci_slc_ready(uint16_t handle);
+
+/******************************************************************************
+ *
+ * Function         bta_ag_ci_wbs_command
+ *
+ * Description      This function is called to notify AG that a WBS command is
+ *                  received
+ *
+ * Returns          void
+ *
+ *****************************************************************************/
+extern void bta_ag_ci_wbs_command(uint16_t handle, char* p_data, uint16_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_AG_CI_H */
diff --git a/bt/bta/include/bta_ag_co.h b/bt/bta/include/bta_ag_co.h
new file mode 100644
index 0000000..f03322f
--- /dev/null
+++ b/bt/bta/include/bta_ag_co.h
@@ -0,0 +1,124 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 is the interface file for audio gateway call-out functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_AG_CO_H
+#define BTA_AG_CO_H
+
+#include "bta_ag_api.h"
+#include "hci/include/hci_audio.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_co_init
+ *
+ * Description      This callout function is executed by AG when it is
+ *                  started by calling BTA_AgEnable().  This function can be
+ *                  used by the phone to initialize audio paths or for other
+ *                  initialization purposes.
+ *
+ *
+ * Returns          Void.
+ *
+ ******************************************************************************/
+extern void bta_ag_co_init(void);
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_co_audio_state
+ *
+ * Description      This function is called by the AG before the audio
+ *                  connection
+ *                  is brought up, after it comes up, and after it goes down.
+ *
+ * Parameters       handle - handle of the AG instance
+ *                  state - Audio state
+ *                  codec - if WBS support is compiled in, codec to going to be
+ *                          used is provided and when in SCO_STATE_SETUP,
+ *                          BTM_I2SPCMConfig() must be called with the correct
+ *                          platform parameters. In the other states, codec type
+ *                          should not be ignored
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+#if (BTM_WBS_INCLUDED == TRUE)
+extern void bta_ag_co_audio_state(uint16_t handle, uint8_t app_id,
+                                  uint8_t state, tBTA_AG_PEER_CODEC codec);
+
+#else
+extern void bta_ag_co_audio_state(uint16_t handle, uint8_t app_id,
+                                  uint8_t state);
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_co_data_open
+ *
+ * Description      This function is executed by AG when a service level
+ *                  connection
+ *                  is opened.  The phone can use this function to set
+ *                  up data paths or perform any required initialization or
+ *                  set up particular to the connected service.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_ag_co_data_open(uint16_t handle, tBTA_SERVICE_ID service);
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_co_data_close
+ *
+ * Description      This function is called by AG when a service level
+ *                  connection is closed
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_ag_co_data_close(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_co_tx_write
+ *
+ * Description      This function is called by the AG to send data to the
+ *                  phone when the AG is configured for AT command pass-through.
+ *                  The implementation of this function must copy the data to
+ *                  the phone's memory.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_ag_co_tx_write(uint16_t handle, uint8_t* p_data, uint16_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_AG_CO_H */
diff --git a/bt/bta/include/bta_api.h b/bt/bta/include/bta_api.h
new file mode 100644
index 0000000..f9d137f
--- /dev/null
+++ b/bt/bta/include/bta_api.h
@@ -0,0 +1,2191 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2014 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 is the public interface file for BTA, Broadcom's Bluetooth
+ *  application layer for mobile phones.
+ *
+ ******************************************************************************/
+#ifndef BTA_API_H
+#define BTA_API_H
+
+#include "bt_target.h"
+#include "bt_types.h"
+#include "btm_api.h"
+
+#if (BLE_INCLUDED == TRUE)
+#include "btm_ble_api.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+ *  Constants and data types
+ ****************************************************************************/
+
+/* Status Return Value */
+#define BTA_SUCCESS 0 /* Successful operation. */
+#define BTA_FAILURE 1 /* Generic failure. */
+#define BTA_PENDING 2 /* API cannot be completed right now */
+#define BTA_BUSY 3
+#define BTA_NO_RESOURCES 4
+#define BTA_WRONG_MODE 5
+
+typedef uint8_t tBTA_STATUS;
+
+/*
+ * Service ID
+ *
+ * NOTES: When you add a new Service ID for BTA AND require to change the value
+ * of BTA_MAX_SERVICE_ID,
+ *        make sure that the correct security ID of the new service from
+ * Security service definitions (btm_api.h)
+ *        should be added to bta_service_id_to_btm_srv_id_lkup_tbl table in
+ * bta_dm_act.c.
+ */
+
+#define BTA_RES_SERVICE_ID 0         /* Reserved */
+#define BTA_SPP_SERVICE_ID 1         /* Serial port profile. */
+#define BTA_DUN_SERVICE_ID 2         /* Dial-up networking profile. */
+#define BTA_A2DP_SOURCE_SERVICE_ID 3 /* A2DP Source profile. */
+#define BTA_LAP_SERVICE_ID 4         /* LAN access profile. */
+#define BTA_HSP_SERVICE_ID 5         /* Headset profile. */
+#define BTA_HFP_SERVICE_ID 6         /* Hands-free profile. */
+#define BTA_OPP_SERVICE_ID 7         /* Object push  */
+#define BTA_FTP_SERVICE_ID 8         /* File transfer */
+#define BTA_CTP_SERVICE_ID 9         /* Cordless Terminal */
+#define BTA_ICP_SERVICE_ID 10        /* Intercom Terminal */
+#define BTA_SYNC_SERVICE_ID 11       /* Synchronization */
+#define BTA_BPP_SERVICE_ID 12        /* Basic printing profile */
+#define BTA_BIP_SERVICE_ID 13        /* Basic Imaging profile */
+#define BTA_PANU_SERVICE_ID 14       /* PAN User */
+#define BTA_NAP_SERVICE_ID 15        /* PAN Network access point */
+#define BTA_GN_SERVICE_ID 16         /* PAN Group Ad-hoc networks */
+#define BTA_SAP_SERVICE_ID 17        /* SIM Access profile */
+#define BTA_A2DP_SINK_SERVICE_ID 18  /* A2DP Sink */
+#define BTA_AVRCP_SERVICE_ID 19      /* A/V remote control */
+#define BTA_HID_SERVICE_ID 20        /* HID */
+#define BTA_VDP_SERVICE_ID 21        /* Video distribution */
+#define BTA_PBAP_SERVICE_ID 22       /* PhoneBook Access Server*/
+#define BTA_HSP_HS_SERVICE_ID 23     /* HFP HS role */
+#define BTA_HFP_HS_SERVICE_ID 24     /* HSP HS role */
+#define BTA_MAP_SERVICE_ID 25        /* Message Access Profile */
+#define BTA_MN_SERVICE_ID 26         /* Message Notification Service */
+#define BTA_HDP_SERVICE_ID 27        /* Health Device Profile */
+#define BTA_PCE_SERVICE_ID 28        /* PhoneBook Access Client*/
+#define BTA_SDP_SERVICE_ID 29        /* SDP Search*/
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+/* BLE profile service ID */
+#define BTA_BLE_SERVICE_ID 30 /* GATT profile */
+
+#define BTA_USER_SERVICE_ID 31 /* User requested UUID */
+
+#define BTA_MAX_SERVICE_ID 32
+#else
+#define BTA_USER_SERVICE_ID 30 /* User requested UUID */
+#define BTA_MAX_SERVICE_ID 31
+#endif
+/* service IDs (BTM_SEC_SERVICE_FIRST_EMPTY + 1) to (BTM_SEC_MAX_SERVICES - 1)
+ * are used by BTA JV */
+#define BTA_FIRST_JV_SERVICE_ID (BTM_SEC_SERVICE_FIRST_EMPTY + 1)
+#define BTA_LAST_JV_SERVICE_ID (BTM_SEC_MAX_SERVICES - 1)
+
+typedef uint8_t tBTA_SERVICE_ID;
+
+/* Service ID Mask */
+#define BTA_RES_SERVICE_MASK 0x00000001    /* Reserved */
+#define BTA_SPP_SERVICE_MASK 0x00000002    /* Serial port profile. */
+#define BTA_DUN_SERVICE_MASK 0x00000004    /* Dial-up networking profile. */
+#define BTA_FAX_SERVICE_MASK 0x00000008    /* Fax profile. */
+#define BTA_LAP_SERVICE_MASK 0x00000010    /* LAN access profile. */
+#define BTA_HSP_SERVICE_MASK 0x00000020    /* HSP AG role. */
+#define BTA_HFP_SERVICE_MASK 0x00000040    /* HFP AG role */
+#define BTA_OPP_SERVICE_MASK 0x00000080    /* Object push  */
+#define BTA_FTP_SERVICE_MASK 0x00000100    /* File transfer */
+#define BTA_CTP_SERVICE_MASK 0x00000200    /* Cordless Terminal */
+#define BTA_ICP_SERVICE_MASK 0x00000400    /* Intercom Terminal */
+#define BTA_SYNC_SERVICE_MASK 0x00000800   /* Synchronization */
+#define BTA_BPP_SERVICE_MASK 0x00001000    /* Print server */
+#define BTA_BIP_SERVICE_MASK 0x00002000    /* Basic Imaging */
+#define BTA_PANU_SERVICE_MASK 0x00004000   /* PAN User */
+#define BTA_NAP_SERVICE_MASK 0x00008000    /* PAN Network access point */
+#define BTA_GN_SERVICE_MASK 0x00010000     /* PAN Group Ad-hoc networks */
+#define BTA_SAP_SERVICE_MASK 0x00020000    /* PAN Group Ad-hoc networks */
+#define BTA_A2DP_SERVICE_MASK 0x00040000   /* Advanced audio distribution */
+#define BTA_AVRCP_SERVICE_MASK 0x00080000  /* A/V remote control */
+#define BTA_HID_SERVICE_MASK 0x00100000    /* HID */
+#define BTA_VDP_SERVICE_MASK 0x00200000    /* Video distribution */
+#define BTA_PBAP_SERVICE_MASK 0x00400000   /* Phone Book Server */
+#define BTA_HSP_HS_SERVICE_MASK 0x00800000 /* HFP HS role */
+#define BTA_HFP_HS_SERVICE_MASK 0x01000000 /* HSP HS role */
+#define BTA_MAS_SERVICE_MASK 0x02000000    /* Message Access Profile */
+#define BTA_MN_SERVICE_MASK 0x04000000     /* Message Notification Profile */
+#define BTA_HL_SERVICE_MASK 0x08000000     /* Health Device Profile */
+#define BTA_PCE_SERVICE_MASK 0x10000000    /* Phone Book Client */
+
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+#define BTA_BLE_SERVICE_MASK 0x20000000  /* GATT based service */
+#define BTA_USER_SERVICE_MASK 0x40000000 /* Message Notification Profile */
+#else
+#define BTA_USER_SERVICE_MASK 0x20000000 /* Message Notification Profile */
+#endif
+
+#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE)
+#define BTA_ALL_SERVICE_MASK 0x3FFFFFFF /* All services supported by BTA. */
+#else
+#define BTA_ALL_SERVICE_MASK 0x1FFFFFFF /* All services supported by BTA. */
+#endif
+
+typedef uint32_t tBTA_SERVICE_MASK;
+
+/* extended service mask, including mask with one or more GATT UUID */
+typedef struct {
+  tBTA_SERVICE_MASK srvc_mask;
+  uint8_t num_uuid;
+  tBT_UUID* p_uuid;
+} tBTA_SERVICE_MASK_EXT;
+
+/* Security Setting Mask */
+#define BTA_SEC_NONE BTM_SEC_NONE /* No security. */
+#define BTA_SEC_AUTHORIZE                                               \
+  (BTM_SEC_IN_AUTHORIZE) /* Authorization required (only needed for out \
+                            going connection )*/
+#define BTA_SEC_AUTHENTICATE \
+  (BTM_SEC_IN_AUTHENTICATE | \
+   BTM_SEC_OUT_AUTHENTICATE) /* Authentication required. */
+#define BTA_SEC_ENCRYPT \
+  (BTM_SEC_IN_ENCRYPT | BTM_SEC_OUT_ENCRYPT) /* Encryption required. */
+#define BTA_SEC_MODE4_LEVEL4                                               \
+  (BTM_SEC_MODE4_LEVEL4) /* Mode 4 level 4 service, i.e. incoming/outgoing \
+                            MITM and P-256 encryption */
+#define BTA_SEC_MITM \
+  (BTM_SEC_IN_MITM | BTM_SEC_OUT_MITM) /* Man-In-The_Middle protection */
+#define BTA_SEC_IN_16_DIGITS \
+  (BTM_SEC_IN_MIN_16_DIGIT_PIN) /* Min 16 digit for pin code */
+
+typedef uint16_t tBTA_SEC;
+
+/* Ignore for Discoverable, Connectable, Pairable and Connectable Paired only
+ * device modes */
+#define BTA_DM_IGNORE 0x00FF
+
+/* Ignore for Discoverable, Connectable only for LE modes */
+#define BTA_DM_LE_IGNORE 0xFF00
+
+#define BTA_APP_ID_PAN_MULTI 0xFE /* app id for pan multiple connection */
+#define BTA_ALL_APP_ID 0xFF
+
+/* Discoverable Modes */
+#define BTA_DM_NON_DISC BTM_NON_DISCOVERABLE /* Device is not discoverable. */
+#define BTA_DM_GENERAL_DISC                         \
+  BTM_GENERAL_DISCOVERABLE /* General discoverable. \
+                              */
+#if (BLE_INCLUDED == TRUE)
+#define BTA_DM_BLE_NON_DISCOVERABLE \
+  BTM_BLE_NON_DISCOVERABLE /* Device is not LE discoverable */
+#define BTA_DM_BLE_GENERAL_DISCOVERABLE \
+  BTM_BLE_GENERAL_DISCOVERABLE /* Device is LE General discoverable */
+#define BTA_DM_BLE_LIMITED_DISCOVERABLE \
+  BTM_BLE_LIMITED_DISCOVERABLE /* Device is LE Limited discoverable */
+#endif
+typedef uint16_t
+    tBTA_DM_DISC; /* this discoverability mode is a bit mask among BR mode and
+                     LE mode */
+
+/* Connectable Modes */
+#define BTA_DM_NON_CONN BTM_NON_CONNECTABLE /* Device is not connectable. */
+#define BTA_DM_CONN BTM_CONNECTABLE         /* Device is connectable. */
+#if (BLE_INCLUDED == TRUE)
+#define BTA_DM_BLE_NON_CONNECTABLE \
+  BTM_BLE_NON_CONNECTABLE /* Device is LE non-connectable. */
+#define BTA_DM_BLE_CONNECTABLE \
+  BTM_BLE_CONNECTABLE /* Device is LE connectable. */
+#endif
+
+typedef uint16_t tBTA_DM_CONN;
+
+#define BTA_TRANSPORT_UNKNOWN 0
+#define BTA_TRANSPORT_BR_EDR BT_TRANSPORT_BR_EDR
+#define BTA_TRANSPORT_LE BT_TRANSPORT_LE
+typedef tBT_TRANSPORT tBTA_TRANSPORT;
+
+/* Pairable Modes */
+#define BTA_DM_PAIRABLE 1
+#define BTA_DM_NON_PAIRABLE 0
+
+/* Connectable Paired Only Mode */
+#define BTA_DM_CONN_ALL 0
+#define BTA_DM_CONN_PAIRED 1
+
+/* Inquiry Modes */
+#define BTA_DM_INQUIRY_NONE BTM_INQUIRY_NONE /*No BR inquiry. */
+#define BTA_DM_GENERAL_INQUIRY \
+  BTM_GENERAL_INQUIRY /* Perform general inquiry. */
+#define BTA_DM_LIMITED_INQUIRY \
+  BTM_LIMITED_INQUIRY /* Perform limited inquiry. */
+
+#if (BLE_INCLUDED == TRUE)
+#define BTA_BLE_INQUIRY_NONE BTM_BLE_INQUIRY_NONE
+#define BTA_BLE_GENERAL_INQUIRY \
+  BTM_BLE_GENERAL_INQUIRY /* Perform LE general inquiry. */
+#define BTA_BLE_LIMITED_INQUIRY \
+  BTM_BLE_LIMITED_INQUIRY /* Perform LE limited inquiry. */
+#endif
+typedef uint8_t tBTA_DM_INQ_MODE;
+
+/* Inquiry Filter Type */
+#define BTA_DM_INQ_CLR BTM_CLR_INQUIRY_FILTER /* Clear inquiry filter. */
+#define BTA_DM_INQ_DEV_CLASS \
+  BTM_FILTER_COND_DEVICE_CLASS /* Filter on device class. */
+#define BTA_DM_INQ_BD_ADDR \
+  BTM_FILTER_COND_BD_ADDR /* Filter on a specific  BD address. */
+
+typedef uint8_t tBTA_DM_INQ_FILT;
+
+/* Authorize Response */
+#define BTA_DM_AUTH_PERM \
+  0 /* Authorized for future connections to the service */
+#define BTA_DM_AUTH_TEMP 1 /* Authorized for current connection only */
+#define BTA_DM_NOT_AUTH 2  /* Not authorized for the service */
+
+typedef uint8_t tBTA_AUTH_RESP;
+
+/* M/S preferred roles */
+#define BTA_ANY_ROLE 0x00
+#define BTA_MASTER_ROLE_PREF 0x01
+#define BTA_MASTER_ROLE_ONLY 0x02
+#define BTA_SLAVE_ROLE_ONLY \
+  0x03 /* Used for PANU only, skip role switch to master */
+
+typedef uint8_t tBTA_PREF_ROLES;
+
+enum {
+
+  BTA_DM_NO_SCATTERNET,      /* Device doesn't support scatternet, it might
+                                support "role switch during connection" for
+                                an incoming connection, when it already has
+                                another connection in master role */
+  BTA_DM_PARTIAL_SCATTERNET, /* Device supports partial scatternet. It can have
+                                simulateous connection in Master and Slave roles
+                                for short period of time */
+  BTA_DM_FULL_SCATTERNET /* Device can have simultaneous connection in master
+                            and slave roles */
+
+};
+
+/* Inquiry filter device class condition */
+typedef struct {
+  DEV_CLASS dev_class;      /* device class of interest */
+  DEV_CLASS dev_class_mask; /* mask to determine the bits of device class of
+                               interest */
+} tBTA_DM_COD_COND;
+
+/* Inquiry Filter Condition */
+typedef union {
+  BD_ADDR bd_addr;                 /* BD address of  device to filter. */
+  tBTA_DM_COD_COND dev_class_cond; /* Device class filter condition */
+} tBTA_DM_INQ_COND;
+
+/* Inquiry Parameters */
+typedef struct {
+  tBTA_DM_INQ_MODE mode; /* Inquiry mode, limited or general. */
+  uint8_t duration;      /* Inquiry duration in 1.28 sec units. */
+  uint8_t max_resps; /* Maximum inquiry responses.  Set to zero for unlimited
+                        responses. */
+  bool report_dup; /* report duplicated inquiry response with higher RSSI value
+                      */
+  tBTA_DM_INQ_FILT filter_type; /* Filter condition type. */
+  tBTA_DM_INQ_COND filter_cond; /* Filter condition data. */
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+  uint8_t intl_duration
+      [4]; /*duration array storing the interleave scan's time portions*/
+#endif
+} tBTA_DM_INQ;
+
+typedef struct {
+  uint8_t bta_dm_eir_min_name_len; /* minimum length of local name when it is
+                                      shortened */
+#if (BTA_EIR_CANNED_UUID_LIST == TRUE)
+  uint8_t bta_dm_eir_uuid16_len; /* length of 16-bit UUIDs */
+  uint8_t* bta_dm_eir_uuid16;    /* 16-bit UUIDs */
+#else
+  uint32_t uuid_mask[BTM_EIR_SERVICE_ARRAY_SIZE]; /* mask of UUID list in EIR */
+#endif
+  int8_t* bta_dm_eir_inq_tx_power;     /* Inquiry TX power         */
+  uint8_t bta_dm_eir_flag_len;         /* length of flags in bytes */
+  uint8_t* bta_dm_eir_flags;           /* flags for EIR */
+  uint8_t bta_dm_eir_manufac_spec_len; /* length of manufacturer specific in
+                                          bytes */
+  uint8_t* bta_dm_eir_manufac_spec;    /* manufacturer specific */
+  uint8_t bta_dm_eir_additional_len;   /* length of additional data in bytes */
+  uint8_t* bta_dm_eir_additional;      /* additional data */
+} tBTA_DM_EIR_CONF;
+
+#if (BLE_INCLUDED == TRUE)
+
+/* advertising filter policy */
+typedef tBTM_BLE_AFP tBTA_BLE_AFP;
+
+enum {
+  BTA_BLE_BATCH_SCAN_MODE_PASS = 1,
+  BTA_BLE_BATCH_SCAN_MODE_ACTI = 2,
+  BTA_BLE_BATCH_SCAN_MODE_PASS_ACTI = 3
+};
+typedef uint8_t tBTA_BLE_BATCH_SCAN_MODE;
+
+enum { BTA_BLE_DISCARD_OLD_ITEMS = 0, BTA_BLE_DISCARD_LOWER_RSSI_ITEMS = 1 };
+typedef uint8_t tBTA_BLE_DISCARD_RULE;
+
+enum { BTA_BLE_ADV_SEEN_FIRST_TIME = 0, BTA_BLE_ADV_TRACKING_TIMEOUT = 1 };
+typedef uint8_t tBTA_BLE_ADV_CHANGE_REASON;
+
+enum {
+  BTA_BLE_BATCH_SCAN_ENB_EVT = 1,
+  BTA_BLE_BATCH_SCAN_CFG_STRG_EVT = 2,
+  BTA_BLE_BATCH_SCAN_DATA_EVT = 3,
+  BTA_BLE_BATCH_SCAN_THRES_EVT = 4,
+  BTA_BLE_BATCH_SCAN_PARAM_EVT = 5,
+  BTA_BLE_BATCH_SCAN_DIS_EVT = 6
+};
+typedef tBTM_BLE_BATCH_SCAN_EVT tBTA_BLE_BATCH_SCAN_EVT;
+
+typedef tBTM_BLE_TRACK_ADV_ACTION tBTA_BLE_TRACK_ADV_ACTION;
+#endif
+
+/* BLE customer specific feature function type definitions */
+/* data type used on customer specific feature for RSSI monitoring */
+#define BTA_BLE_RSSI_ALERT_HI 0
+#define BTA_BLE_RSSI_ALERT_RANGE 1
+#define BTA_BLE_RSSI_ALERT_LO 2
+typedef uint8_t tBTA_DM_BLE_RSSI_ALERT_TYPE;
+
+#define BTA_BLE_RSSI_ALERT_NONE BTM_BLE_RSSI_ALERT_NONE     /*    (0) */
+#define BTA_BLE_RSSI_ALERT_HI_BIT BTM_BLE_RSSI_ALERT_HI_BIT /*    (1) */
+#define BTA_BLE_RSSI_ALERT_RANGE_BIT \
+  BTM_BLE_RSSI_ALERT_RANGE_BIT                              /*    (1 << 1) */
+#define BTA_BLE_RSSI_ALERT_LO_BIT BTM_BLE_RSSI_ALERT_LO_BIT /*    (1 << 2) */
+typedef uint8_t tBTA_DM_BLE_RSSI_ALERT_MASK;
+
+typedef void(tBTA_DM_BLE_RSSI_CBACK)(BD_ADDR bd_addr,
+                                     tBTA_DM_BLE_RSSI_ALERT_TYPE alert_type,
+                                     int8_t rssi);
+
+/* max number of filter spot for different filter type */
+#define BTA_DM_BLE_MAX_UUID_FILTER BTM_BLE_MAX_UUID_FILTER /* 8 */
+#define BTA_DM_BLE_MAX_ADDR_FILTER BTM_BLE_MAX_ADDR_FILTER /* 8 */
+#define BTA_DM_BLE_PF_STR_COND_MAX \
+  BTM_BLE_PF_STR_COND_MAX /* 4    apply to manu data , or local name */
+#define BTA_DM_BLE_PF_STR_LEN_MAX \
+  BTM_BLE_PF_STR_LEN_MAX /* match for first 20 bytes */
+
+#define BTA_DM_BLE_PF_LOGIC_OR 0
+#define BTA_DM_BLE_PF_LOGIC_AND 1
+typedef uint8_t tBTA_DM_BLE_PF_LOGIC_TYPE;
+
+enum {
+  BTA_DM_BLE_SCAN_COND_ADD,
+  BTA_DM_BLE_SCAN_COND_DELETE,
+  BTA_DM_BLE_SCAN_COND_CLEAR = 2
+};
+typedef uint8_t tBTA_DM_BLE_SCAN_COND_OP;
+
+/* ADV payload filtering vendor specific call event */
+enum { BTA_BLE_SCAN_PF_ENABLE_EVT = 7, BTA_BLE_SCAN_PF_COND_EVT };
+
+/* filter selection bit index  */
+#define BTA_DM_BLE_PF_ADDR_FILTER BTM_BLE_PF_ADDR_FILTER
+#define BTA_DM_BLE_PF_SRVC_DATA BTM_BLE_PF_SRVC_DATA
+#define BTA_DM_BLE_PF_SRVC_UUID BTM_BLE_PF_SRVC_UUID
+#define BTA_DM_BLE_PF_SRVC_SOL_UUID BTM_BLE_PF_SRVC_SOL_UUID
+#define BTA_DM_BLE_PF_LOCAL_NAME BTM_BLE_PF_LOCAL_NAME
+#define BTA_DM_BLE_PF_MANU_DATA BTM_BLE_PF_MANU_DATA
+#define BTA_DM_BLE_PF_SRVC_DATA_PATTERN BTM_BLE_PF_SRVC_DATA_PATTERN
+#define BTA_DM_BLE_PF_TYPE_ALL BTM_BLE_PF_TYPE_ALL
+#define BTA_DM_BLE_PF_TYPE_MAX BTM_BLE_PF_TYPE_MAX
+typedef uint8_t tBTA_DM_BLE_PF_COND_TYPE;
+
+typedef union {
+  uint16_t uuid16_mask;
+  uint32_t uuid32_mask;
+  uint8_t uuid128_mask[LEN_UUID_128];
+} tBTA_DM_BLE_PF_COND_MASK;
+
+typedef struct {
+  tBLE_BD_ADDR*
+      p_target_addr; /* target address, if NULL, generic UUID filter */
+  tBT_UUID uuid;     /* UUID condition */
+  tBTA_DM_BLE_PF_LOGIC_TYPE cond_logic; /* AND/OR */
+  tBTA_DM_BLE_PF_COND_MASK*
+      p_uuid_mask; /* UUID condition mask, if NULL, match exact as UUID
+                      condition */
+} tBTA_DM_BLE_PF_UUID_COND;
+
+typedef struct {
+  uint8_t data_len; /* <= 20 bytes */
+  uint8_t* p_data;
+} tBTA_DM_BLE_PF_LOCAL_NAME_COND;
+
+typedef struct {
+  uint16_t company_id; /* company ID */
+  uint8_t data_len;    /* <= 20 bytes */
+  uint8_t* p_pattern;
+  uint16_t company_id_mask; /* UUID value mask */
+  uint8_t*
+      p_pattern_mask; /* Manufacturer data matching mask, same length
+                       as data pattern, set to all 0xff, match exact data */
+} tBTA_DM_BLE_PF_MANU_COND;
+
+typedef struct {
+  uint16_t uuid;    /* service ID */
+  uint8_t data_len; /* <= 20 bytes */
+  uint8_t* p_pattern;
+  uint8_t*
+      p_pattern_mask; /* Service data matching mask, same length
+                       as data pattern, set to all 0xff, match exact data */
+} tBTA_DM_BLE_PF_SRVC_PATTERN_COND;
+
+typedef union {
+  tBLE_BD_ADDR target_addr;
+  tBTA_DM_BLE_PF_LOCAL_NAME_COND local_name; /* lcoal name filtering */
+  tBTA_DM_BLE_PF_MANU_COND manu_data;        /* manufactuer data filtering */
+  tBTA_DM_BLE_PF_UUID_COND srvc_uuid;        /* service UUID filtering */
+  tBTA_DM_BLE_PF_UUID_COND
+      solicitate_uuid; /* solicitated service UUID filtering */
+  tBTA_DM_BLE_PF_SRVC_PATTERN_COND srvc_data; /* service data pattern */
+} tBTA_DM_BLE_PF_COND_PARAM;
+
+typedef uint8_t tBTA_DM_BLE_PF_FILT_INDEX;
+typedef uint8_t tBTA_DM_BLE_PF_AVBL_SPACE;
+
+typedef int8_t tBTA_DM_RSSI_VALUE;
+typedef uint8_t tBTA_DM_LINK_QUALITY_VALUE;
+
+typedef uint8_t tBTA_SIG_STRENGTH_MASK;
+
+/* Security Callback Events */
+#define BTA_DM_ENABLE_EVT 0    /* Enable Event */
+#define BTA_DM_DISABLE_EVT 1   /* Disable Event */
+#define BTA_DM_PIN_REQ_EVT 2   /* PIN request. */
+#define BTA_DM_AUTH_CMPL_EVT 3 /* Authentication complete indication. */
+#define BTA_DM_AUTHORIZE_EVT 4 /* Authorization request. */
+#define BTA_DM_LINK_UP_EVT 5   /* Connection UP event */
+#define BTA_DM_LINK_DOWN_EVT 6 /* Connection DOWN event */
+#define BTA_DM_SIG_STRENGTH_EVT                                             \
+  7                             /* Signal strength for bluetooth connection \
+                                   */
+#define BTA_DM_BUSY_LEVEL_EVT 8 /* System busy level */
+#define BTA_DM_BOND_CANCEL_CMPL_EVT 9 /* Bond cancel complete indication */
+#define BTA_DM_SP_CFM_REQ_EVT                     \
+  10 /* Simple Pairing User Confirmation request. \
+        */
+#define BTA_DM_SP_KEY_NOTIF_EVT 11 /* Simple Pairing Passkey Notification */
+#define BTA_DM_SP_RMT_OOB_EVT 12   /* Simple Pairing Remote OOB Data request. */
+#define BTA_DM_SP_KEYPRESS_EVT 13  /* Key press notification event. */
+#define BTA_DM_ROLE_CHG_EVT 14     /* Role Change event. */
+#define BTA_DM_BLE_KEY_EVT 15      /* BLE SMP key event for peer device keys */
+#define BTA_DM_BLE_SEC_REQ_EVT 16  /* BLE SMP security request */
+#define BTA_DM_BLE_PASSKEY_NOTIF_EVT 17 /* SMP passkey notification event */
+#define BTA_DM_BLE_PASSKEY_REQ_EVT 18   /* SMP passkey request event */
+#define BTA_DM_BLE_OOB_REQ_EVT 19       /* SMP OOB request event */
+#define BTA_DM_BLE_LOCAL_IR_EVT 20      /* BLE local IR event */
+#define BTA_DM_BLE_LOCAL_ER_EVT 21      /* BLE local ER event */
+#define BTA_DM_BLE_NC_REQ_EVT 22 /* SMP Numeric Comparison request event */
+#define BTA_DM_SP_RMT_OOB_EXT_EVT \
+  23 /* Simple Pairing Remote OOB Extended Data request. */
+#define BTA_DM_BLE_AUTH_CMPL_EVT 24 /* BLE Auth complete */
+#define BTA_DM_DEV_UNPAIRED_EVT 25
+#define BTA_DM_HW_ERROR_EVT 26 /* BT Chip H/W error */
+#define BTA_DM_LE_FEATURES_READ                                             \
+  27                             /* Cotroller specific LE features are read \
+                                    */
+#define BTA_DM_ENER_INFO_READ 28 /* Energy info read */
+#define BTA_DM_BLE_SC_OOB_REQ_EVT 29 /* SMP SC OOB request event */
+typedef uint8_t tBTA_DM_SEC_EVT;
+
+/* Structure associated with BTA_DM_ENABLE_EVT */
+typedef struct { tBTA_STATUS status; } tBTA_DM_ENABLE;
+
+/* Structure associated with BTA_DM_PIN_REQ_EVT */
+typedef struct {
+  /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in
+   * order */
+  BD_ADDR bd_addr;     /* BD address peer device. */
+  DEV_CLASS dev_class; /* Class of Device */
+  BD_NAME bd_name;     /* Name of peer device. */
+  bool min_16_digit;   /* true if the pin returned must be at least 16 digits */
+} tBTA_DM_PIN_REQ;
+
+/* BLE related definition */
+
+#define BTA_DM_AUTH_FAIL_BASE (HCI_ERR_MAX_ERR + 10)
+
+/* Converts SMP error codes defined in smp_api.h to SMP auth fail reasons below.
+ */
+#define BTA_DM_AUTH_CONVERT_SMP_CODE(x) (BTA_DM_AUTH_FAIL_BASE + (x))
+
+#define BTA_DM_AUTH_SMP_PASSKEY_FAIL \
+  (BTA_DM_AUTH_FAIL_BASE + SMP_PASSKEY_ENTRY_FAIL)
+#define BTA_DM_AUTH_SMP_OOB_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_OOB_FAIL)
+#define BTA_DM_AUTH_SMP_PAIR_AUTH_FAIL \
+  (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_AUTH_FAIL)
+#define BTA_DM_AUTH_SMP_CONFIRM_VALUE_FAIL \
+  (BTA_DM_AUTH_FAIL_BASE + SMP_CONFIRM_VALUE_ERR)
+#define BTA_DM_AUTH_SMP_PAIR_NOT_SUPPORT \
+  (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_NOT_SUPPORT)
+#define BTA_DM_AUTH_SMP_ENC_KEY_SIZE (BTA_DM_AUTH_FAIL_BASE + SMP_ENC_KEY_SIZE)
+#define BTA_DM_AUTH_SMP_INVALID_CMD (BTA_DM_AUTH_FAIL_BASE + SMP_INVALID_CMD)
+#define BTA_DM_AUTH_SMP_UNKNOWN_ERR \
+  (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_FAIL_UNKNOWN)
+#define BTA_DM_AUTH_SMP_REPEATED_ATTEMPT \
+  (BTA_DM_AUTH_FAIL_BASE + SMP_REPEATED_ATTEMPTS)
+#define BTA_DM_AUTH_SMP_INVALID_PARAMETERS \
+  (BTA_DM_AUTH_FAIL_BASE + SMP_INVALID_PARAMETERS)
+#define BTA_DM_AUTH_SMP_INTERNAL_ERR \
+  (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_INTERNAL_ERR)
+#define BTA_DM_AUTH_SMP_UNKNOWN_IO (BTA_DM_AUTH_FAIL_BASE + SMP_UNKNOWN_IO_CAP)
+#define BTA_DM_AUTH_SMP_INIT_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_INIT_FAIL)
+#define BTA_DM_AUTH_SMP_CONFIRM_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_CONFIRM_FAIL)
+#define BTA_DM_AUTH_SMP_BUSY (BTA_DM_AUTH_FAIL_BASE + SMP_BUSY)
+#define BTA_DM_AUTH_SMP_ENC_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_ENC_FAIL)
+#define BTA_DM_AUTH_SMP_RSP_TIMEOUT (BTA_DM_AUTH_FAIL_BASE + SMP_RSP_TIMEOUT)
+#define BTA_DM_AUTH_SMP_CONN_TOUT (BTA_DM_AUTH_FAIL_BASE + SMP_CONN_TOUT)
+
+/* connection parameter boundary value and dummy value */
+#define BTA_DM_BLE_SCAN_INT_MIN BTM_BLE_SCAN_INT_MIN
+#define BTA_DM_BLE_SCAN_INT_MAX BTM_BLE_SCAN_INT_MAX
+#define BTA_DM_BLE_SCAN_WIN_MIN BTM_BLE_SCAN_WIN_MIN
+#define BTA_DM_BLE_SCAN_WIN_MAX BTM_BLE_SCAN_WIN_MAX
+#define BTA_DM_BLE_CONN_INT_MIN BTM_BLE_CONN_INT_MIN
+#define BTA_DM_BLE_CONN_INT_MAX BTM_BLE_CONN_INT_MAX
+#define BTA_DM_BLE_CONN_LATENCY_MAX BTM_BLE_CONN_LATENCY_MAX
+#define BTA_DM_BLE_CONN_SUP_TOUT_MIN BTM_BLE_CONN_SUP_TOUT_MIN
+#define BTA_DM_BLE_CONN_SUP_TOUT_MAX BTM_BLE_CONN_SUP_TOUT_MAX
+#define BTA_DM_BLE_CONN_PARAM_UNDEF                                          \
+  BTM_BLE_CONN_PARAM_UNDEF /* use this value when a specific value not to be \
+                              overwritten */
+
+#define BTA_LE_KEY_PENC \
+  BTM_LE_KEY_PENC /* encryption information of peer device */
+#define BTA_LE_KEY_PID BTM_LE_KEY_PID     /* identity key of the peer device */
+#define BTA_LE_KEY_PCSRK BTM_LE_KEY_PCSRK /* peer SRK */
+#define BTA_LE_KEY_LENC \
+  BTM_LE_KEY_LENC                     /* master role security information:div */
+#define BTA_LE_KEY_LID BTM_LE_KEY_LID /* master device ID key */
+#define BTA_LE_KEY_LCSRK \
+  BTM_LE_KEY_LCSRK                /* local CSRK has been deliver to peer */
+typedef uint8_t tBTA_LE_KEY_TYPE; /* can be used as a bit mask */
+
+typedef tBTM_LE_PENC_KEYS tBTA_LE_PENC_KEYS;
+typedef tBTM_LE_PCSRK_KEYS tBTA_LE_PCSRK_KEYS;
+typedef tBTM_LE_LENC_KEYS tBTA_LE_LENC_KEYS;
+typedef tBTM_LE_LCSRK_KEYS tBTA_LE_LCSRK_KEYS;
+typedef tBTM_LE_PID_KEYS tBTA_LE_PID_KEYS;
+
+typedef union {
+  tBTA_LE_PENC_KEYS penc_key;  /* received peer encryption key */
+  tBTA_LE_PCSRK_KEYS psrk_key; /* received peer device SRK */
+  tBTA_LE_PID_KEYS pid_key;    /* peer device ID key */
+  tBTA_LE_LENC_KEYS
+      lenc_key; /* local encryption reproduction keys LTK = = d1(ER,DIV,0)*/
+  tBTA_LE_LCSRK_KEYS lcsrk_key; /* local device CSRK = d1(ER,DIV,1)*/
+  tBTA_LE_PID_KEYS lid_key; /* local device ID key for the particular remote */
+} tBTA_LE_KEY_VALUE;
+
+#define BTA_BLE_LOCAL_KEY_TYPE_ID 1
+#define BTA_BLE_LOCAL_KEY_TYPE_ER 2
+typedef uint8_t tBTA_DM_BLE_LOCAL_KEY_MASK;
+
+typedef struct {
+  BT_OCTET16 ir;
+  BT_OCTET16 irk;
+  BT_OCTET16 dhk;
+} tBTA_BLE_LOCAL_ID_KEYS;
+
+#define BTA_DM_SEC_GRANTED BTA_SUCCESS
+#define BTA_DM_SEC_PAIR_NOT_SPT BTA_DM_AUTH_SMP_PAIR_NOT_SUPPORT
+#define BTA_DM_SEC_REP_ATTEMPTS BTA_DM_AUTH_SMP_REPEATED_ATTEMPT
+typedef uint8_t tBTA_DM_BLE_SEC_GRANT;
+
+#define BTA_DM_BLE_ONN_NONE BTM_BLE_CONN_NONE
+#define BTA_DM_BLE_CONN_AUTO BTM_BLE_CONN_AUTO
+#define BTA_DM_BLE_CONN_SELECTIVE BTM_BLE_CONN_SELECTIVE
+typedef uint8_t tBTA_DM_BLE_CONN_TYPE;
+
+typedef bool(tBTA_DM_BLE_SEL_CBACK)(BD_ADDR random_bda, uint8_t* p_remote_name);
+
+/* Structure associated with BTA_DM_BLE_SEC_REQ_EVT */
+typedef struct {
+  BD_ADDR bd_addr; /* peer address */
+  BD_NAME bd_name; /* peer device name */
+} tBTA_DM_BLE_SEC_REQ;
+
+typedef struct {
+  BD_ADDR bd_addr; /* peer address */
+  tBTM_LE_KEY_TYPE key_type;
+  tBTM_LE_KEY_VALUE* p_key_value;
+} tBTA_DM_BLE_KEY;
+
+/* Structure associated with BTA_DM_AUTH_CMPL_EVT */
+typedef struct {
+  BD_ADDR bd_addr;     /* BD address peer device. */
+  BD_NAME bd_name;     /* Name of peer device. */
+  bool key_present;    /* Valid link key value in key element */
+  LINK_KEY key;        /* Link key associated with peer device. */
+  uint8_t key_type;    /* The type of Link Key */
+  bool success;        /* true of authentication succeeded, false if failed. */
+  uint8_t fail_reason; /* The HCI reason/error code for when success=false */
+  tBLE_ADDR_TYPE addr_type; /* Peer device address type */
+  tBT_DEVICE_TYPE dev_type;
+} tBTA_DM_AUTH_CMPL;
+
+/* Structure associated with BTA_DM_AUTHORIZE_EVT */
+typedef struct {
+  BD_ADDR bd_addr;         /* BD address peer device. */
+  BD_NAME bd_name;         /* Name of peer device. */
+  tBTA_SERVICE_ID service; /* Service ID to authorize. */
+  DEV_CLASS dev_class;
+} tBTA_DM_AUTHORIZE;
+
+/* Structure associated with BTA_DM_LINK_UP_EVT */
+typedef struct {
+  BD_ADDR bd_addr; /* BD address peer device. */
+#if (BLE_INCLUDED == TRUE)
+  tBTA_TRANSPORT link_type;
+#endif
+} tBTA_DM_LINK_UP;
+
+/* Structure associated with BTA_DM_LINK_DOWN_EVT */
+typedef struct {
+  BD_ADDR bd_addr; /* BD address peer device. */
+  uint8_t status;  /* connection open/closed */
+  bool is_removed; /* true if device is removed when link is down */
+#if (BLE_INCLUDED == TRUE)
+  tBTA_TRANSPORT link_type;
+#endif
+} tBTA_DM_LINK_DOWN;
+
+/* Structure associated with BTA_DM_ROLE_CHG_EVT */
+typedef struct {
+  BD_ADDR bd_addr;  /* BD address peer device. */
+  uint8_t new_role; /* the new connection role */
+} tBTA_DM_ROLE_CHG;
+
+/* Structure associated with BTA_DM_BUSY_LEVEL_EVT */
+typedef struct {
+  uint8_t level;       /* when paging or inquiring, level is 10.
+                          Otherwise, the number of ACL links */
+  uint8_t level_flags; /* indicates individual flags */
+} tBTA_DM_BUSY_LEVEL;
+
+#define BTA_IO_CAP_OUT BTM_IO_CAP_OUT   /* 0 DisplayOnly */
+#define BTA_IO_CAP_IO BTM_IO_CAP_IO     /* 1 DisplayYesNo */
+#define BTA_IO_CAP_IN BTM_IO_CAP_IN     /* 2 KeyboardOnly */
+#define BTA_IO_CAP_NONE BTM_IO_CAP_NONE /* 3 NoInputNoOutput */
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+#define BTA_IO_CAP_KBDISP BTM_IO_CAP_KBDISP /* 4 Keyboard display */
+#endif
+typedef tBTM_IO_CAP tBTA_IO_CAP;
+
+#define BTA_AUTH_SP_NO                                      \
+  BTM_AUTH_SP_NO /* 0 MITM Protection Not Required - Single \
+                   Profile/non-bonding                      \
+                   Numeric comparison with automatic accept allowed */
+#define BTA_AUTH_SP_YES                                                       \
+  BTM_AUTH_SP_YES /* 1 MITM Protection Required - Single Profile/non-bonding  \
+                    Use IO Capabilities to determine authentication procedure \
+                    */
+#define BTA_AUTH_AP_NO                                                      \
+  BTM_AUTH_AP_NO /* 2 MITM Protection Not Required - All Profiles/dedicated \
+                   bonding                                                  \
+                   Numeric comparison with automatic accept allowed */
+#define BTA_AUTH_AP_YES                                                       \
+  BTM_AUTH_AP_YES /* 3 MITM Protection Required - All Profiles/dedicated      \
+                    bonding                                                   \
+                    Use IO Capabilities to determine authentication procedure \
+                    */
+#define BTA_AUTH_SPGB_NO                                                       \
+  BTM_AUTH_SPGB_NO /* 4 MITM Protection Not Required - Single Profiles/general \
+                     bonding                                                   \
+                     Numeric comparison with automatic accept allowed */
+#define BTA_AUTH_SPGB_YES                                                   \
+  BTM_AUTH_SPGB_YES /* 5 MITM Protection Required - Single Profiles/general \
+                      bonding                                               \
+                      Use IO Capabilities to determine authentication       \
+                      procedure */
+typedef tBTM_AUTH_REQ tBTA_AUTH_REQ;
+
+#define BTA_AUTH_DD_BOND \
+  BTM_AUTH_DD_BOND /* 2 this bit is set for dedicated bonding */
+#define BTA_AUTH_GEN_BOND \
+  BTM_AUTH_SPGB_NO /* 4 this bit is set for general bonding */
+#define BTA_AUTH_BONDS \
+  BTM_AUTH_BONDS /* 6 the general/dedicated bonding bits  */
+
+#define BTA_LE_AUTH_NO_BOND BTM_LE_AUTH_REQ_NO_BOND /* 0*/
+#define BTA_LE_AUTH_BOND BTM_LE_AUTH_REQ_BOND       /* 1 << 0 */
+#define BTA_LE_AUTH_REQ_MITM BTM_LE_AUTH_REQ_MITM   /* 1 << 2 */
+
+#define BTA_LE_AUTH_REQ_SC_ONLY BTM_LE_AUTH_REQ_SC_ONLY           /* 1 << 3 */
+#define BTA_LE_AUTH_REQ_SC_BOND BTM_LE_AUTH_REQ_SC_BOND           /* 1001 */
+#define BTA_LE_AUTH_REQ_SC_MITM BTM_LE_AUTH_REQ_SC_MITM           /* 1100 */
+#define BTA_LE_AUTH_REQ_SC_MITM_BOND BTM_LE_AUTH_REQ_SC_MITM_BOND /* 1101 */
+typedef tBTM_LE_AUTH_REQ
+    tBTA_LE_AUTH_REQ; /* combination of the above bit pattern */
+
+#define BTA_OOB_NONE BTM_OOB_NONE
+#define BTA_OOB_PRESENT BTM_OOB_PRESENT
+#define BTA_OOB_UNKNOWN BTM_OOB_UNKNOWN
+
+typedef tBTM_OOB_DATA tBTA_OOB_DATA;
+
+/* Structure associated with BTA_DM_SP_CFM_REQ_EVT */
+typedef struct {
+  /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in
+   * order */
+  BD_ADDR bd_addr;     /* peer address */
+  DEV_CLASS dev_class; /* peer CoD */
+  BD_NAME bd_name;     /* peer device name */
+  uint32_t num_val; /* the numeric value for comparison. If just_works, do not
+                       show this number to UI */
+  bool just_works;  /* true, if "Just Works" association model */
+  tBTA_AUTH_REQ loc_auth_req; /* Authentication required for local device */
+  tBTA_AUTH_REQ rmt_auth_req; /* Authentication required for peer device */
+  tBTA_IO_CAP loc_io_caps;    /* IO Capabilities of local device */
+  tBTA_AUTH_REQ rmt_io_caps;  /* IO Capabilities of remote device */
+} tBTA_DM_SP_CFM_REQ;
+
+enum {
+  BTA_SP_KEY_STARTED, /* passkey entry started */
+  BTA_SP_KEY_ENTERED, /* passkey digit entered */
+  BTA_SP_KEY_ERASED,  /* passkey digit erased */
+  BTA_SP_KEY_CLEARED, /* passkey cleared */
+  BTA_SP_KEY_COMPLT   /* passkey entry completed */
+};
+typedef uint8_t tBTA_SP_KEY_TYPE;
+
+/* Structure associated with BTA_DM_SP_KEYPRESS_EVT */
+typedef struct {
+  BD_ADDR bd_addr; /* peer address */
+  tBTA_SP_KEY_TYPE notif_type;
+} tBTA_DM_SP_KEY_PRESS;
+
+/* Structure associated with BTA_DM_SP_KEY_NOTIF_EVT */
+typedef struct {
+  /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in
+   * order */
+  BD_ADDR bd_addr;     /* peer address */
+  DEV_CLASS dev_class; /* peer CoD */
+  BD_NAME bd_name;     /* peer device name */
+  uint32_t passkey; /* the numeric value for comparison. If just_works, do not
+                       show this number to UI */
+} tBTA_DM_SP_KEY_NOTIF;
+
+/* Structure associated with BTA_DM_SP_RMT_OOB_EVT */
+typedef struct {
+  /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in
+   * order */
+  BD_ADDR bd_addr;     /* peer address */
+  DEV_CLASS dev_class; /* peer CoD */
+  BD_NAME bd_name;     /* peer device name */
+} tBTA_DM_SP_RMT_OOB;
+
+/* Structure associated with BTA_DM_BOND_CANCEL_CMPL_EVT */
+typedef struct {
+  tBTA_STATUS result; /* true of bond cancel succeeded, false if failed. */
+} tBTA_DM_BOND_CANCEL_CMPL;
+
+/* Union of all security callback structures */
+typedef union {
+  tBTA_DM_ENABLE enable;          /* BTA enabled */
+  tBTA_DM_PIN_REQ pin_req;        /* PIN request. */
+  tBTA_DM_AUTH_CMPL auth_cmpl;    /* Authentication complete indication. */
+  tBTA_DM_AUTHORIZE authorize;    /* Authorization request. */
+  tBTA_DM_LINK_UP link_up;        /* ACL connection down event */
+  tBTA_DM_LINK_DOWN link_down;    /* ACL connection down event */
+  tBTA_DM_BUSY_LEVEL busy_level;  /* System busy level */
+  tBTA_DM_SP_CFM_REQ cfm_req;     /* user confirm request */
+  tBTA_DM_SP_KEY_NOTIF key_notif; /* passkey notification */
+  tBTA_DM_SP_RMT_OOB rmt_oob;     /* remote oob */
+  tBTA_DM_BOND_CANCEL_CMPL
+      bond_cancel_cmpl;               /* Bond Cancel Complete indication */
+  tBTA_DM_SP_KEY_PRESS key_press;     /* key press notification event */
+  tBTA_DM_ROLE_CHG role_chg;          /* role change event */
+  tBTA_DM_BLE_SEC_REQ ble_req;        /* BLE SMP related request */
+  tBTA_DM_BLE_KEY ble_key;            /* BLE SMP keys used when pairing */
+  tBTA_BLE_LOCAL_ID_KEYS ble_id_keys; /* IR event */
+  BT_OCTET16 ble_er;                  /* ER event data */
+} tBTA_DM_SEC;
+
+/* Security callback */
+typedef void(tBTA_DM_SEC_CBACK)(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data);
+
+typedef uint32_t tBTA_DM_BLE_REF_VALUE;
+
+#define BTA_DM_BLE_PF_ENABLE_EVT BTM_BLE_PF_ENABLE
+#define BTA_DM_BLE_PF_CONFIG_EVT BTM_BLE_PF_CONFIG
+typedef uint8_t tBTA_DM_BLE_PF_EVT;
+
+#define BTA_DM_BLE_PF_ENABLE 1
+#define BTA_DM_BLE_PF_CONFIG 2
+typedef uint8_t tBTA_DM_BLE_PF_ACTION;
+
+/* Config callback */
+typedef void(tBTA_DM_BLE_PF_CFG_CBACK)(tBTA_DM_BLE_PF_ACTION action,
+                                       tBTA_DM_BLE_PF_COND_TYPE cfg_cond,
+                                       tBTA_DM_BLE_PF_AVBL_SPACE avbl_space,
+                                       tBTA_STATUS status,
+                                       tBTA_DM_BLE_REF_VALUE ref_value);
+/* Param callback */
+typedef void(tBTA_DM_BLE_PF_PARAM_CBACK)(uint8_t action_type,
+                                         tBTA_DM_BLE_PF_AVBL_SPACE avbl_space,
+                                         tBTA_DM_BLE_REF_VALUE ref_value,
+                                         tBTA_STATUS status);
+
+/* Status callback */
+typedef void(tBTA_DM_BLE_PF_STATUS_CBACK)(uint8_t action, tBTA_STATUS status,
+                                          tBTA_DM_BLE_REF_VALUE ref_value);
+
+#define BTA_DM_BLE_PF_BRDCAST_ADDR_FILT 1
+#define BTA_DM_BLE_PF_SERV_DATA_CHG_FILT 2
+#define BTA_DM_BLE_PF_SERV_UUID 4
+#define BTA_DM_BLE_PF_SERV_SOLC_UUID 8
+#define BTA_DM_BLE_PF_LOC_NAME_CHECK 16
+#define BTA_DM_BLE_PF_MANUF_NAME_CHECK 32
+#define BTA_DM_BLE_PF_SERV_DATA_CHECK 64
+typedef uint16_t tBTA_DM_BLE_PF_FEAT_SEL;
+
+#define BTA_DM_BLE_PF_LIST_LOGIC_OR 1
+#define BTA_DM_BLE_PF_LIST_LOGIC_AND 2
+typedef uint16_t tBTA_DM_BLE_PF_LIST_LOGIC_TYPE;
+
+#define BTA_DM_BLE_PF_FILT_LOGIC_OR 0
+#define BTA_DM_BLE_PF_FILT_LOGIC_AND 1
+typedef uint16_t tBTA_DM_BLE_PF_FILT_LOGIC_TYPE;
+
+typedef uint8_t tBTA_DM_BLE_PF_RSSI_THRESHOLD;
+typedef uint8_t tBTA_DM_BLE_PF_DELIVERY_MODE;
+typedef uint16_t tBTA_DM_BLE_PF_TIMEOUT;
+typedef uint8_t tBTA_DM_BLE_PF_TIMEOUT_CNT;
+typedef uint16_t tBTA_DM_BLE_PF_ADV_TRACK_ENTRIES;
+
+typedef struct {
+  tBTA_DM_BLE_PF_FEAT_SEL feat_seln;
+  tBTA_DM_BLE_PF_LIST_LOGIC_TYPE list_logic_type;
+  tBTA_DM_BLE_PF_FILT_LOGIC_TYPE filt_logic_type;
+  tBTA_DM_BLE_PF_RSSI_THRESHOLD rssi_high_thres;
+  tBTA_DM_BLE_PF_RSSI_THRESHOLD rssi_low_thres;
+  tBTA_DM_BLE_PF_DELIVERY_MODE dely_mode;
+  tBTA_DM_BLE_PF_TIMEOUT found_timeout;
+  tBTA_DM_BLE_PF_TIMEOUT lost_timeout;
+  tBTA_DM_BLE_PF_TIMEOUT_CNT found_timeout_cnt;
+  tBTA_DM_BLE_PF_ADV_TRACK_ENTRIES num_of_tracking_entries;
+} tBTA_DM_BLE_PF_FILT_PARAMS;
+
+/* Search callback events */
+#define BTA_DM_INQ_RES_EVT 0  /* Inquiry result for a peer device. */
+#define BTA_DM_INQ_CMPL_EVT 1 /* Inquiry complete. */
+#define BTA_DM_DISC_RES_EVT 2 /* Discovery result for a peer device. */
+#define BTA_DM_DISC_BLE_RES_EVT \
+  3 /* Discovery result for BLE GATT based servoce on a peer device. */
+#define BTA_DM_DISC_CMPL_EVT 4          /* Discovery complete. */
+#define BTA_DM_DI_DISC_CMPL_EVT 5       /* Discovery complete. */
+#define BTA_DM_SEARCH_CANCEL_CMPL_EVT 6 /* Search cancelled */
+
+typedef uint8_t tBTA_DM_SEARCH_EVT;
+
+#define BTA_DM_INQ_RES_IGNORE_RSSI \
+  BTM_INQ_RES_IGNORE_RSSI /* 0x7f RSSI value not supplied (ignore it) */
+
+/* Structure associated with BTA_DM_INQ_RES_EVT */
+typedef struct {
+  BD_ADDR bd_addr;             /* BD address peer device. */
+  DEV_CLASS dev_class;         /* Device class of peer device. */
+  bool remt_name_not_required; /* Application sets this flag if it already knows
+                                  the name of the device */
+  /* If the device name is known to application BTA skips the remote name
+   * request */
+  bool is_limited; /* true, if the limited inquiry bit is set in the CoD */
+  int8_t rssi;     /* The rssi value */
+  uint8_t* p_eir;  /* received EIR */
+#if (BLE_INCLUDED == TRUE)
+  uint8_t inq_result_type;
+  uint8_t ble_addr_type;
+  tBTM_BLE_EVT_TYPE ble_evt_type;
+  tBT_DEVICE_TYPE device_type;
+  uint8_t flag;
+#endif
+
+} tBTA_DM_INQ_RES;
+
+/* Structure associated with BTA_DM_INQ_CMPL_EVT */
+typedef struct {
+  uint8_t num_resps; /* Number of inquiry responses. */
+} tBTA_DM_INQ_CMPL;
+
+/* Structure associated with BTA_DM_DI_DISC_CMPL_EVT */
+typedef struct {
+  BD_ADDR bd_addr;    /* BD address peer device. */
+  uint8_t num_record; /* Number of DI record */
+  tBTA_STATUS result;
+} tBTA_DM_DI_DISC_CMPL;
+
+/* Structure associated with BTA_DM_DISC_RES_EVT */
+typedef struct {
+  BD_ADDR bd_addr;             /* BD address peer device. */
+  BD_NAME bd_name;             /* Name of peer device. */
+  tBTA_SERVICE_MASK services;  /* Services found on peer device. */
+  uint8_t* p_raw_data;         /* Raw data for discovery DB */
+  uint32_t raw_data_size;      /* size of raw data */
+  tBT_DEVICE_TYPE device_type; /* device type in case it is BLE device */
+  uint32_t num_uuids;
+  uint8_t* p_uuid_list;
+  tBTA_STATUS result;
+} tBTA_DM_DISC_RES;
+
+/* Structure associated with tBTA_DM_DISC_BLE_RES */
+typedef struct {
+  BD_ADDR bd_addr;  /* BD address peer device. */
+  BD_NAME bd_name;  /* Name of peer device. */
+  tBT_UUID service; /* GATT based Services UUID found on peer device. */
+} tBTA_DM_DISC_BLE_RES;
+
+/* Union of all search callback structures */
+typedef union {
+  tBTA_DM_INQ_RES inq_res;   /* Inquiry result for a peer device. */
+  tBTA_DM_INQ_CMPL inq_cmpl; /* Inquiry complete. */
+  tBTA_DM_DISC_RES disc_res; /* Discovery result for a peer device. */
+  tBTA_DM_DISC_BLE_RES
+      disc_ble_res;             /* discovery result for GATT based service */
+  tBTA_DM_DI_DISC_CMPL di_disc; /* DI discovery result for a peer device */
+
+} tBTA_DM_SEARCH;
+
+/* Search callback */
+typedef void(tBTA_DM_SEARCH_CBACK)(tBTA_DM_SEARCH_EVT event,
+                                   tBTA_DM_SEARCH* p_data);
+
+/* Execute call back */
+typedef void(tBTA_DM_EXEC_CBACK)(void* p_param);
+
+/* Encryption callback*/
+typedef void(tBTA_DM_ENCRYPT_CBACK)(BD_ADDR bd_addr, tBTA_TRANSPORT transport,
+                                    tBTA_STATUS result);
+
+#define BTA_DM_BLE_SEC_NONE BTM_BLE_SEC_NONE
+#define BTA_DM_BLE_SEC_ENCRYPT BTM_BLE_SEC_ENCRYPT
+#define BTA_DM_BLE_SEC_NO_MITM BTM_BLE_SEC_ENCRYPT_NO_MITM
+#define BTA_DM_BLE_SEC_MITM BTM_BLE_SEC_ENCRYPT_MITM
+typedef tBTM_BLE_SEC_ACT tBTA_DM_BLE_SEC_ACT;
+
+#if (BLE_INCLUDED == TRUE)
+typedef tBTM_BLE_TX_TIME_MS tBTA_DM_BLE_TX_TIME_MS;
+typedef tBTM_BLE_RX_TIME_MS tBTA_DM_BLE_RX_TIME_MS;
+typedef tBTM_BLE_IDLE_TIME_MS tBTA_DM_BLE_IDLE_TIME_MS;
+typedef tBTM_BLE_ENERGY_USED tBTA_DM_BLE_ENERGY_USED;
+
+#define BTA_DM_CONTRL_UNKNOWN 0 /* Unknown state */
+#define BTA_DM_CONTRL_ACTIVE 1  /* ACL link on, SCO link ongoing, sniff mode */
+#define BTA_DM_CONTRL_SCAN                   \
+  2 /* Scan state - paging/inquiry/trying to \
+       connect*/
+#define BTA_DM_CONTRL_IDLE                           \
+  3 /* Idle state - page scan, LE advt, inquiry scan \
+       */
+
+typedef uint8_t tBTA_DM_CONTRL_STATE;
+
+typedef uint8_t tBTA_DM_BLE_ADV_STATE;
+typedef uint8_t tBTA_DM_BLE_ADV_INFO_PRESENT;
+typedef uint8_t tBTA_DM_BLE_RSSI_VALUE;
+typedef uint16_t tBTA_DM_BLE_ADV_INFO_TIMESTAMP;
+
+typedef tBTM_BLE_TRACK_ADV_DATA tBTA_DM_BLE_TRACK_ADV_DATA;
+
+typedef void(tBTA_BLE_SCAN_THRESHOLD_CBACK)(tBTA_DM_BLE_REF_VALUE ref_value);
+
+typedef void(tBTA_BLE_SCAN_REP_CBACK)(tBTA_DM_BLE_REF_VALUE ref_value,
+                                      uint8_t report_format,
+                                      uint8_t num_records, uint16_t data_len,
+                                      uint8_t* p_rep_data, tBTA_STATUS status);
+
+typedef void(tBTA_BLE_SCAN_SETUP_CBACK)(tBTA_BLE_BATCH_SCAN_EVT evt,
+                                        tBTA_DM_BLE_REF_VALUE ref_value,
+                                        tBTA_STATUS status);
+
+typedef void(tBTA_BLE_TRACK_ADV_CMPL_CBACK)(
+    int action, tBTA_STATUS status, tBTA_DM_BLE_PF_AVBL_SPACE avbl_space,
+    tBTA_DM_BLE_REF_VALUE ref_value);
+
+typedef void(tBTA_BLE_TRACK_ADV_CBACK)(tBTA_DM_BLE_TRACK_ADV_DATA* p_adv_data);
+
+typedef void(tBTA_BLE_ENERGY_INFO_CBACK)(tBTA_DM_BLE_TX_TIME_MS tx_time,
+                                         tBTA_DM_BLE_RX_TIME_MS rx_time,
+                                         tBTA_DM_BLE_IDLE_TIME_MS idle_time,
+                                         tBTA_DM_BLE_ENERGY_USED energy_used,
+                                         tBTA_DM_CONTRL_STATE ctrl_state,
+                                         tBTA_STATUS status);
+
+#else
+typedef uint8_t tBTA_DM_BLE_SEC_ACT;
+#endif
+
+/* Maximum service name length */
+#define BTA_SERVICE_NAME_LEN 35
+#define BTA_SERVICE_DESP_LEN BTA_SERVICE_NAME_LEN
+#define BTA_PROVIDER_NAME_LEN BTA_SERVICE_NAME_LEN
+
+/* link policy masks  */
+#define BTA_DM_LP_SWITCH HCI_ENABLE_MASTER_SLAVE_SWITCH
+#define BTA_DM_LP_HOLD HCI_ENABLE_HOLD_MODE
+#define BTA_DM_LP_SNIFF HCI_ENABLE_SNIFF_MODE
+#define BTA_DM_LP_PARK HCI_ENABLE_PARK_MODE
+typedef uint16_t tBTA_DM_LP_MASK;
+
+/* power mode actions  */
+#define BTA_DM_PM_NO_ACTION 0x00 /* no change to the current pm setting */
+#define BTA_DM_PM_PARK 0x10      /* prefers park mode */
+#define BTA_DM_PM_SNIFF 0x20     /* prefers sniff mode */
+#define BTA_DM_PM_SNIFF1 0x21    /* prefers sniff1 mode */
+#define BTA_DM_PM_SNIFF2 0x22    /* prefers sniff2 mode */
+#define BTA_DM_PM_SNIFF3 0x23    /* prefers sniff3 mode */
+#define BTA_DM_PM_SNIFF4 0x24    /* prefers sniff4 mode */
+#define BTA_DM_PM_SNIFF5 0x25    /* prefers sniff5 mode */
+#define BTA_DM_PM_SNIFF6 0x26    /* prefers sniff6 mode */
+#define BTA_DM_PM_SNIFF7 0x27    /* prefers sniff7 mode */
+#define BTA_DM_PM_SNIFF_USER0 \
+  0x28 /* prefers user-defined sniff0 mode (testtool only) */
+#define BTA_DM_PM_SNIFF_USER1 \
+  0x29 /* prefers user-defined sniff1 mode (testtool only) */
+#define BTA_DM_PM_ACTIVE 0x40  /* prefers active mode */
+#define BTA_DM_PM_RETRY 0x80   /* retry power mode based on current settings */
+#define BTA_DM_PM_SUSPEND 0x04 /* prefers suspend mode */
+#define BTA_DM_PM_NO_PREF                                                   \
+  0x01 /* service has no prefernce on power mode setting. eg. connection to \
+          service got closed */
+
+typedef uint8_t tBTA_DM_PM_ACTION;
+
+/* index to bta_dm_ssr_spec */
+#define BTA_DM_PM_SSR0 0
+#define BTA_DM_PM_SSR1                      \
+  1 /* BTA_DM_PM_SSR1 will be dedicated for \
+    HH SSR setting entry, no other profile can use it */
+#define BTA_DM_PM_SSR2 2
+#define BTA_DM_PM_SSR3 3
+#define BTA_DM_PM_SSR4 4
+#define BTA_DM_PM_SSR5 5
+#define BTA_DM_PM_SSR6 6
+
+#define BTA_DM_PM_NUM_EVTS 9
+
+#ifndef BTA_DM_PM_PARK_IDX
+#define BTA_DM_PM_PARK_IDX \
+  5 /* the actual index to bta_dm_pm_md[] for PARK mode */
+#endif
+
+#ifndef BTA_DM_PM_SNIFF_A2DP_IDX
+#define BTA_DM_PM_SNIFF_A2DP_IDX BTA_DM_PM_SNIFF
+#endif
+
+#ifndef BTA_DM_PM_SNIFF_HD_IDLE_IDX
+#define BTA_DM_PM_SNIFF_HD_IDLE_IDX BTA_DM_PM_SNIFF2
+#endif
+
+#ifndef BTA_DM_PM_SNIFF_SCO_OPEN_IDX
+#define BTA_DM_PM_SNIFF_SCO_OPEN_IDX BTA_DM_PM_SNIFF3
+#endif
+
+#ifndef BTA_DM_PM_SNIFF_HD_ACTIVE_IDX
+#define BTA_DM_PM_SNIFF_HD_ACTIVE_IDX BTA_DM_PM_SNIFF4
+#endif
+
+#ifndef BTA_DM_PM_SNIFF_HH_OPEN_IDX
+#define BTA_DM_PM_SNIFF_HH_OPEN_IDX BTA_DM_PM_SNIFF2
+#endif
+
+#ifndef BTA_DM_PM_SNIFF_HH_ACTIVE_IDX
+#define BTA_DM_PM_SNIFF_HH_ACTIVE_IDX BTA_DM_PM_SNIFF2
+#endif
+
+#ifndef BTA_DM_PM_SNIFF_HH_IDLE_IDX
+#define BTA_DM_PM_SNIFF_HH_IDLE_IDX BTA_DM_PM_SNIFF2
+#endif
+
+#ifndef BTA_DM_PM_HH_OPEN_DELAY
+#define BTA_DM_PM_HH_OPEN_DELAY 30000
+#endif
+
+#ifndef BTA_DM_PM_HH_ACTIVE_DELAY
+#define BTA_DM_PM_HH_ACTIVE_DELAY 30000
+#endif
+
+#ifndef BTA_DM_PM_HH_IDLE_DELAY
+#define BTA_DM_PM_HH_IDLE_DELAY 30000
+#endif
+
+/* The Sniff Parameters defined below must be ordered from highest
+ * latency (biggest interval) to lowest latency.  If there is a conflict
+ * among the connected services the setting with the lowest latency will
+ * be selected.  If a device should override a sniff parameter then it
+ * must insure that order is maintained.
+ */
+#ifndef BTA_DM_PM_SNIFF_MAX
+#define BTA_DM_PM_SNIFF_MAX 800
+#define BTA_DM_PM_SNIFF_MIN 400
+#define BTA_DM_PM_SNIFF_ATTEMPT 4
+#define BTA_DM_PM_SNIFF_TIMEOUT 1
+#endif
+
+#ifndef BTA_DM_PM_SNIFF1_MAX
+#define BTA_DM_PM_SNIFF1_MAX 400
+#define BTA_DM_PM_SNIFF1_MIN 200
+#define BTA_DM_PM_SNIFF1_ATTEMPT 4
+#define BTA_DM_PM_SNIFF1_TIMEOUT 1
+#endif
+
+#ifndef BTA_DM_PM_SNIFF2_MAX
+#define BTA_DM_PM_SNIFF2_MAX 180
+#define BTA_DM_PM_SNIFF2_MIN 150
+#define BTA_DM_PM_SNIFF2_ATTEMPT 4
+#define BTA_DM_PM_SNIFF2_TIMEOUT 1
+#endif
+
+#ifndef BTA_DM_PM_SNIFF3_MAX
+#define BTA_DM_PM_SNIFF3_MAX 150
+#define BTA_DM_PM_SNIFF3_MIN 50
+#define BTA_DM_PM_SNIFF3_ATTEMPT 4
+#define BTA_DM_PM_SNIFF3_TIMEOUT 1
+#endif
+
+#ifndef BTA_DM_PM_SNIFF4_MAX
+#define BTA_DM_PM_SNIFF4_MAX 54
+#define BTA_DM_PM_SNIFF4_MIN 30
+#define BTA_DM_PM_SNIFF4_ATTEMPT 4
+#define BTA_DM_PM_SNIFF4_TIMEOUT 1
+#endif
+
+#ifndef BTA_DM_PM_SNIFF5_MAX
+#define BTA_DM_PM_SNIFF5_MAX 36
+#define BTA_DM_PM_SNIFF5_MIN 30
+#define BTA_DM_PM_SNIFF5_ATTEMPT 2
+#define BTA_DM_PM_SNIFF5_TIMEOUT 0
+#endif
+
+#ifndef BTA_DM_PM_PARK_MAX
+#define BTA_DM_PM_PARK_MAX 800
+#define BTA_DM_PM_PARK_MIN 400
+#define BTA_DM_PM_PARK_ATTEMPT 0
+#define BTA_DM_PM_PARK_TIMEOUT 0
+#endif
+
+/* Switch callback events */
+#define BTA_DM_SWITCH_CMPL_EVT 0 /* Completion of the Switch API */
+
+typedef uint8_t tBTA_DM_SWITCH_EVT;
+typedef void(tBTA_DM_SWITCH_CBACK)(tBTA_DM_SWITCH_EVT event,
+                                   tBTA_STATUS status);
+
+/* Audio routing out configuration */
+#define BTA_DM_ROUTE_NONE 0x00      /* No Audio output */
+#define BTA_DM_ROUTE_DAC 0x01       /* routing over analog output */
+#define BTA_DM_ROUTE_I2S 0x02       /* routing over digital (I2S) output */
+#define BTA_DM_ROUTE_BT_MONO 0x04   /* routing over SCO */
+#define BTA_DM_ROUTE_BT_STEREO 0x08 /* routing over BT Stereo */
+#define BTA_DM_ROUTE_HOST 0x10      /* routing over Host */
+#define BTA_DM_ROUTE_FMTX 0x20      /* routing over FMTX */
+#define BTA_DM_ROUTE_FMRX 0x40      /* routing over FMRX */
+#define BTA_DM_ROUTE_BTSNK 0x80     /* routing over BT SNK */
+
+typedef uint8_t tBTA_DM_ROUTE_PATH;
+
+/* Device Identification (DI) data structure
+*/
+/* Used to set the DI record */
+typedef tSDP_DI_RECORD tBTA_DI_RECORD;
+/* Used to get the DI record */
+typedef tSDP_DI_GET_RECORD tBTA_DI_GET_RECORD;
+/* SDP discovery database */
+typedef tSDP_DISCOVERY_DB tBTA_DISCOVERY_DB;
+
+#ifndef BTA_DI_NUM_MAX
+#define BTA_DI_NUM_MAX 3
+#endif
+
+/* Device features mask definitions */
+#define BTA_FEATURE_BYTES_PER_PAGE BTM_FEATURE_BYTES_PER_PAGE
+#define BTA_EXT_FEATURES_PAGE_MAX BTM_EXT_FEATURES_PAGE_MAX
+/* ACL type
+*/
+#define BTA_DM_LINK_TYPE_BR_EDR 0x01
+#define BTA_DM_LINK_TYPE_LE 0x02
+#define BTA_DM_LINK_TYPE_ALL 0xFF
+typedef uint8_t tBTA_DM_LINK_TYPE;
+
+#define IMMEDIATE_DELY_MODE 0x00
+#define ONFOUND_DELY_MODE 0x01
+#define BATCH_DELY_MODE 0x02
+#define ALLOW_ALL_FILTER 0x00
+#define LOWEST_RSSI_VALUE 129
+
+/*****************************************************************************
+ *  External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         BTA_EnableBluetooth
+ *
+ * Description      This function initializes BTA and prepares BTA and the
+ *                  Bluetooth protocol stack for use.  This function is
+ *                  typically called at startup or when Bluetooth services
+ *                  are required by the phone.  This function must be called
+ *                  before calling any other API function.
+ *
+ *
+ * Returns          BTA_SUCCESS if successful.
+ *                  BTA_FAIL if internal failure.
+ *
+ ******************************************************************************/
+extern tBTA_STATUS BTA_EnableBluetooth(tBTA_DM_SEC_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DisableBluetooth
+ *
+ * Description      This function disables BTA and the Bluetooth protocol
+ *                  stack.  It is called when BTA is no longer being used
+ *                  by any application in the system.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern tBTA_STATUS BTA_DisableBluetooth(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_EnableTestMode
+ *
+ * Description      Enables bluetooth device under test mode
+ *
+ *
+ * Returns          tBTA_STATUS
+ *
+ ******************************************************************************/
+extern tBTA_STATUS BTA_EnableTestMode(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DisableTestMode
+ *
+ * Description      Disable bluetooth device under test mode
+ *
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_DisableTestMode(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmSetDeviceName
+ *
+ * Description      This function sets the Bluetooth name of the local device.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmSetDeviceName(char* p_name);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmSetVisibility
+ *
+ * Description      This function sets the Bluetooth connectable,discoverable,
+ *                  pairable and conn paired only modesmodes of the local
+ *                  device.
+ *                  This controls whether other Bluetooth devices can find and
+ *                  connect to the local device.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmSetVisibility(tBTA_DM_DISC disc_mode, tBTA_DM_CONN conn_mode,
+                                uint8_t pairable_mode, uint8_t conn_filter);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmSearch
+ *
+ * Description      This function searches for peer Bluetooth devices.  It
+ *                  first performs an inquiry; for each device found from the
+ *                  inquiry it gets the remote name of the device.  If
+ *                  parameter services is nonzero, service discovery will be
+ *                  performed on each device for the services specified.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmSearch(tBTA_DM_INQ* p_dm_inq, tBTA_SERVICE_MASK services,
+                         tBTA_DM_SEARCH_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmSearchCancel
+ *
+ * Description      This function cancels a search that has been initiated
+ *                  by calling BTA_DmSearch().
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmSearchCancel(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmDiscover
+ *
+ * Description      This function performs service discovery for the services
+ *                  of a particular peer device.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmDiscover(BD_ADDR bd_addr, tBTA_SERVICE_MASK services,
+                           tBTA_DM_SEARCH_CBACK* p_cback, bool sdp_search);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmDiscoverUUID
+ *
+ * Description      This function performs service discovery for the services
+ *                  of a particular peer device.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmDiscoverUUID(BD_ADDR bd_addr, tSDP_UUID* uuid,
+                               tBTA_DM_SEARCH_CBACK* p_cback, bool sdp_search);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmGetCachedRemoteName
+ *
+ * Description      Retieve cached remote name if available
+ *
+ * Returns          BTA_SUCCESS if cached name was retrieved
+ *                  BTA_FAILURE if cached name is not available
+ *
+ ******************************************************************************/
+tBTA_STATUS BTA_DmGetCachedRemoteName(BD_ADDR remote_device,
+                                      uint8_t** pp_cached_name);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBond
+ *
+ * Description      This function initiates a bonding procedure with a peer
+ *                  device.  The bonding procedure enables authentication
+ *                  and optionally encryption on the Bluetooth link.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmBond(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBondByTransport
+ *
+ * Description      This function initiates a bonding procedure with a peer
+ *                  device by designated transport.  The bonding procedure
+ *                  enables authentication and optionally encryption on the
+ *                  Bluetooth link.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmBondByTransport(BD_ADDR bd_addr, tBTA_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBondCancel
+ *
+ * Description      This function cancels a bonding procedure with a peer
+ *                  device.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmBondCancel(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmPinReply
+ *
+ * Description      This function provides a PIN when one is requested by DM
+ *                  during a bonding procedure.  The application should call
+ *                  this function after the security callback is called with
+ *                  a BTA_DM_PIN_REQ_EVT.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmPinReply(BD_ADDR bd_addr, bool accept, uint8_t pin_len,
+                           uint8_t* p_pin);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmLocalOob
+ *
+ * Description      This function retrieves the OOB data from local controller.
+ *                  The result is reported by bta_dm_co_loc_oob().
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmLocalOob(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmConfirm
+ *
+ * Description      This function accepts or rejects the numerical value of the
+ *                  Simple Pairing process on BTA_DM_SP_CFM_REQ_EVT
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmConfirm(BD_ADDR bd_addr, bool accept);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmAddDevice
+ *
+ * Description      This function adds a device to the security database list
+ *                  of peer devices. This function would typically be called
+ *                  at system startup to initialize the security database with
+ *                  known peer devices.  This is a direct execution function
+ *                  that may lock task scheduling on some platforms.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmAddDevice(BD_ADDR bd_addr, DEV_CLASS dev_class,
+                            LINK_KEY link_key, tBTA_SERVICE_MASK trusted_mask,
+                            bool is_trusted, uint8_t key_type,
+                            tBTA_IO_CAP io_cap, uint8_t pin_length);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmRemoveDevice
+ *
+ * Description      This function removes a device from the security database.
+ *                  This is a direct execution function that may lock task
+ *                  scheduling on some platforms.
+ *
+ *
+ * Returns          BTA_SUCCESS if successful.
+ *                  BTA_FAIL if operation failed.
+ *
+ ******************************************************************************/
+extern tBTA_STATUS BTA_DmRemoveDevice(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GetEirService
+ *
+ * Description      This function is called to get BTA service mask from EIR.
+ *
+ * Parameters       p_eir - pointer of EIR significant part
+ *                  p_services - return the BTA service mask
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_GetEirService(uint8_t* p_eir, tBTA_SERVICE_MASK* p_services);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmGetConnectionState
+ *
+ * Description      Returns whether the remote device is currently connected.
+ *
+ * Returns          0 if the device is NOT connected.
+ *
+ ******************************************************************************/
+extern uint16_t BTA_DmGetConnectionState(const BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmSetLocalDiRecord
+ *
+ * Description      This function adds a DI record to the local SDP database.
+ *
+ * Returns          BTA_SUCCESS if record set sucessfully, otherwise error code.
+ *
+ ******************************************************************************/
+extern tBTA_STATUS BTA_DmSetLocalDiRecord(tBTA_DI_RECORD* p_device_info,
+                                          uint32_t* p_handle);
+
+/*******************************************************************************
+ *
+ *
+ * Function         BTA_DmCloseACL
+ *
+ * Description      This function force to close an ACL connection and remove
+ the
+ *                  device from the security database list of known devices.
+ *
+ * Parameters:      bd_addr       - Address of the peer device
+ *                  remove_dev    - remove device or not after link down
+ *                  transport     - which transport to close
+
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+extern void BTA_DmCloseACL(BD_ADDR bd_addr, bool remove_dev,
+                           tBTA_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function         bta_dmexecutecallback
+ *
+ * Description      This function will request BTA to execute a call back in the
+ *                  context of BTU task.
+ *                  This API was named in lower case because it is only intended
+ *                  for the internal customers(like BTIF).
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_dmexecutecallback(tBTA_DM_EXEC_CBACK* p_callback,
+                                  void* p_param);
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function         BTA_DmPcmInitSamples
+ *
+ * Description      initialize the down sample converter.
+ *
+ *                  src_sps: original samples per second (source audio data)
+ *                            (ex. 44100, 48000)
+ *                  bits: number of bits per pcm sample (16)
+ *                  n_channels: number of channels (i.e. mono(1), stereo(2)...)
+ *
+ * Returns          none
+ *
+ ******************************************************************************/
+extern void BTA_DmPcmInitSamples(uint32_t src_sps, uint32_t bits,
+                                 uint32_t n_channels);
+
+/**************************************************************************************
+ * Function         BTA_DmPcmResample
+ *
+ * Description      Down sampling utility to convert higher sampling rate into
+ *                  8K/16bits
+ *                  PCM samples.
+ *
+ * Parameters       p_src: pointer to the buffer where the original sampling PCM
+ *                              are stored.
+ *                  in_bytes:  Length of the input PCM sample buffer in byte.
+ *                  p_dst: pointer to the buffer which is to be used to store
+ *                         the converted PCM samples.
+ *
+ *
+ * Returns          int32_t: number of samples converted.
+ *
+ *************************************************************************************/
+extern int32_t BTA_DmPcmResample(void* p_src, uint32_t in_bytes, void* p_dst);
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+/* BLE related API functions */
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleSecurityGrant
+ *
+ * Description      Grant security request access.
+ *
+ * Parameters:      bd_addr          - BD address of the peer
+ *                  res              - security grant status.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmBleSecurityGrant(BD_ADDR bd_addr, tBTA_DM_BLE_SEC_GRANT res);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleSetBgConnType
+ *
+ * Description      This function is called to set BLE connectable mode for a
+ *                  peripheral device.
+ *
+ * Parameters       bg_conn_type: it can be auto connection, or selective
+ *                                connection.
+ *                  p_select_cback: callback function when selective connection
+ *                                  procedure is being used.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmBleSetBgConnType(tBTA_DM_BLE_CONN_TYPE bg_conn_type,
+                                   tBTA_DM_BLE_SEL_CBACK* p_select_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBlePasskeyReply
+ *
+ * Description      Send BLE SMP passkey reply.
+ *
+ * Parameters:      bd_addr          - BD address of the peer
+ *                  accept           - passkey entry sucessful or declined.
+ *                  passkey          - passkey value, must be a 6 digit number,
+ *                                     can be lead by 0.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmBlePasskeyReply(BD_ADDR bd_addr, bool accept,
+                                  uint32_t passkey);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleConfirmReply
+ *
+ * Description      Send BLE SMP SC user confirmation reply.
+ *
+ * Parameters:      bd_addr          - BD address of the peer
+ *                  accept           - numbers to compare are the same or
+ *                                     different.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmBleConfirmReply(BD_ADDR bd_addr, bool accept);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmAddBleDevice
+ *
+ * Description      Add a BLE 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
+ *                  dev_type         - Remote device's device type.
+ *                  addr_type        - LE device address type.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmAddBleDevice(BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type,
+                               tBT_DEVICE_TYPE dev_type);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmAddBleKey
+ *
+ * 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          void
+ *
+ ******************************************************************************/
+extern void BTA_DmAddBleKey(BD_ADDR bd_addr, tBTA_LE_KEY_VALUE* p_le_key,
+                            tBTA_LE_KEY_TYPE key_type);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmSetBlePrefConnParams
+ *
+ * Description      This function is called to set the preferred connection
+ *                  parameters when default connection parameter is not desired.
+ *
+ * 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
+ *
+ ******************************************************************************/
+extern void BTA_DmSetBlePrefConnParams(const BD_ADDR bd_addr,
+                                       uint16_t min_conn_int,
+                                       uint16_t max_conn_int,
+                                       uint16_t slave_latency,
+                                       uint16_t supervision_tout);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmSetBleConnScanParams
+ *
+ * Description      This function is called to set scan parameters used in
+ *                  BLE connection request
+ *
+ * Parameters:      scan_interval    - scan interval
+ *                  scan_window      - scan window
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmSetBleConnScanParams(uint32_t scan_interval,
+                                       uint32_t scan_window);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmSetBleScanParams
+ *
+ * Description      This function is called to set scan parameters
+ *
+ * Parameters:      client_if - Client IF
+ *                  scan_interval - scan interval
+ *                  scan_window - scan window
+ *                  scan_mode - scan mode
+ *                  scan_param_setup_status_cback - Set scan param status
+ *                                                  callback
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmSetBleScanParams(
+    tGATT_IF client_if, uint32_t scan_interval, uint32_t scan_window,
+    tBLE_SCAN_MODE scan_mode,
+    tBLE_SCAN_PARAM_SETUP_CBACK scan_param_setup_status_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmSetBleAdvParams
+ *
+ * Description      This function sets the advertising parameters BLE
+ *                  functionality.
+ *                  It is to be called when device act in peripheral or
+ *                  broadcaster role.
+ *
+ * Parameters:      adv_int_min    - adv interval minimum
+ *                  adv_int_max    - adv interval max
+ *                  p_dir_bda      - directed adv initator address
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmSetBleAdvParams(uint16_t adv_int_min, uint16_t adv_int_max,
+                                  tBLE_BD_ADDR* p_dir_bda);
+/*******************************************************************************
+ *
+ * Function         BTA_DmSearchExt
+ *
+ * Description      This function searches for peer Bluetooth devices. It
+ *                  performs an inquiry and gets the remote name for devices.
+ *                  Service discovery is done if services is non zero
+ *
+ * Parameters       p_dm_inq: inquiry conditions
+ *                  services: if service is not empty, service discovery will be
+ *                            done.
+ *                            for all GATT based service condition, put
+ *                            num_uuid, and p_uuid is the pointer to the list of
+ *                            UUID values.
+ *                  p_cback: callback functino when search is completed.
+ *
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmSearchExt(tBTA_DM_INQ* p_dm_inq,
+                            tBTA_SERVICE_MASK_EXT* p_services,
+                            tBTA_DM_SEARCH_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmDiscoverExt
+ *
+ * Description      This function does service discovery for services of a
+ *                  peer device. When services.num_uuid is 0, it indicates all
+ *                  GATT based services are to be searched; other wise a list of
+ *                  UUID of interested services should be provided through
+ *                  services.p_uuid.
+ *
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmDiscoverExt(BD_ADDR bd_addr,
+                              tBTA_SERVICE_MASK_EXT* p_services,
+                              tBTA_DM_SEARCH_CBACK* p_cback, bool sdp_search);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmDiscoverByTransport
+ *
+ * Description      This function does service discovery on particular transport
+ *                  for services of a
+ *                  peer device. When services.num_uuid is 0, it indicates all
+ *                  GATT based services are to be searched; other wise a list of
+ *                  UUID of interested services should be provided through
+ *                  p_services->p_uuid.
+ *
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmDiscoverByTransport(BD_ADDR bd_addr,
+                                      tBTA_SERVICE_MASK_EXT* p_services,
+                                      tBTA_DM_SEARCH_CBACK* p_cback,
+                                      bool sdp_search,
+                                      tBTA_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmSetEncryption
+ *
+ * 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     - transport of the link to be encruypted
+ *                  p_callback    - Pointer to callback function to indicat the
+ *                                  link encryption status
+ *                  sec_act       - This is the security action to indicate
+ *                                  what kind of BLE security level is required
+ *                                  for the BLE link if BLE is supported
+ *                                  Note: This parameter is ignored for
+ *                                        BR/EDR or if BLE is not supported.
+ *
+ * Returns          void
+ *
+ *
+ ******************************************************************************/
+extern void BTA_DmSetEncryption(BD_ADDR bd_addr, tBTA_TRANSPORT transport,
+                                tBTA_DM_ENCRYPT_CBACK* p_callback,
+                                tBTA_DM_BLE_SEC_ACT sec_act);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleObserve
+ *
+ * Description      This procedure keep the device listening for advertising
+ *                  events from a broadcast device.
+ *
+ * Parameters       start: start or stop observe.
+ *                  duration : Duration of the scan. Continuous scan if 0 is
+ *                             passed
+ *                  p_results_cb: Callback to be called with scan results
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmBleObserve(bool start, uint8_t duration,
+                             tBTA_DM_SEARCH_CBACK* p_results_cb);
+
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleConfigLocalPrivacy
+ *
+ * Description      Enable/disable privacy on the local device
+ *
+ * Parameters:      privacy_enable   - enable/disabe privacy on remote device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmBleConfigLocalPrivacy(bool privacy_enable);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleEnableRemotePrivacy
+ *
+ * Description      Enable/disable privacy on a remote device
+ *
+ * Parameters:      bd_addr          - BD address of the peer
+ *                  privacy_enable   - enable/disabe privacy on remote device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmBleEnableRemotePrivacy(BD_ADDR bd_addr, bool privacy_enable);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleUpdateConnectionParams
+ *
+ * Description      Update connection parameters, can only be used when
+ *                  connection is up.
+ *
+ * Parameters:      bd_addr   - BD address of the peer
+ *                  min_int   - minimum connection interval, [0x0004 ~ 0x4000]
+ *                  max_int   - maximum connection interval, [0x0004 ~ 0x4000]
+ *                  latency   - slave latency [0 ~ 500]
+ *                  timeout   - supervision timeout [0x000a ~ 0xc80]
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmBleUpdateConnectionParams(const BD_ADDR bd_addr,
+                                            uint16_t min_int, uint16_t max_int,
+                                            uint16_t latency, uint16_t timeout);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleSetDataLength
+ *
+ * Description      This function is to set maximum LE data packet size
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmBleSetDataLength(BD_ADDR remote_device,
+                                   uint16_t tx_data_length);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleSetStorageParams
+ *
+ * Description      This function is called to set the storage parameters
+ *
+ * Parameters       batch_scan_full_max -Max storage space (in %) allocated to
+ *                                       full scanning
+ *                  batch_scan_trunc_max -Max storage space (in %) allocated to
+ *                                        truncated scanning
+ *                  batch_scan_notify_threshold - Setup notification level based
+ *                                                on total space consumed by
+ *                                                both pools. Setting it to 0
+ *                                                will disable threshold
+ *                                                notification
+ *                  p_setup_cback - Setup callback
+ *                  p_thres_cback - Threshold callback
+ *                  p_rep_cback - Reports callback
+ *                  ref_value - Reference value
+ *
+ * Returns           None
+ *
+ ******************************************************************************/
+extern void BTA_DmBleSetStorageParams(
+    uint8_t batch_scan_full_max, uint8_t batch_scan_trunc_max,
+    uint8_t batch_scan_notify_threshold,
+    tBTA_BLE_SCAN_SETUP_CBACK* p_setup_cback,
+    tBTA_BLE_SCAN_THRESHOLD_CBACK* p_thres_cback,
+    tBTA_BLE_SCAN_REP_CBACK* p_rep_cback, tBTA_DM_BLE_REF_VALUE ref_value);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleEnableBatchScan
+ *
+ * Description      This function is called to enable the batch scan
+ *
+ * Parameters       scan_mode -Batch scan mode
+ *                  scan_interval - Scan interval
+ *                  scan_window - Scan window
+ *                  discard_rule -Discard rules
+ *                  addr_type - Address type
+ *                  ref_value - Reference value
+ *
+ * Returns           None
+ *
+ ******************************************************************************/
+extern void BTA_DmBleEnableBatchScan(tBTA_BLE_BATCH_SCAN_MODE scan_mode,
+                                     uint32_t scan_interval,
+                                     uint32_t scan_window,
+                                     tBTA_BLE_DISCARD_RULE discard_rule,
+                                     tBLE_ADDR_TYPE addr_type,
+                                     tBTA_DM_BLE_REF_VALUE ref_value);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleReadScanReports
+ *
+ * Description      This function is called to read the batch scan reports
+ *
+ * Parameters       scan_mode -Batch scan mode
+ *                  ref_value - Reference value
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_DmBleReadScanReports(tBTA_BLE_BATCH_SCAN_MODE scan_type,
+                                     tBTA_DM_BLE_REF_VALUE ref_value);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleDisableBatchScan
+ *
+ * Description      This function is called to disable the batch scanning
+ *
+ * Parameters       ref_value - Reference value
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_DmBleDisableBatchScan(tBTA_DM_BLE_REF_VALUE ref_value);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmEnableScanFilter
+ *
+ * Description      This function is called to enable the adv data payload
+ *                  filter
+ *
+ * Parameters       action - enable or disable the APCF feature
+ *                  p_cmpl_cback - Command completed callback
+ *                  ref_value - Reference value
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmEnableScanFilter(uint8_t action,
+                                   tBTA_DM_BLE_PF_STATUS_CBACK* p_cmpl_cback,
+                                   tBTA_DM_BLE_REF_VALUE ref_value);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleScanFilterSetup
+ *
+ * Description      This function is called to setup the filter params
+ *
+ * Parameters       p_target: enable the filter condition on a target device; if
+ *                            NULL
+ *                  filt_index - Filter index
+ *                  p_filt_params -Filter parameters
+ *                  ref_value - Reference value
+ *                  action - Add, delete or clear
+ *                  p_cmpl_back - Command completed callback
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmBleScanFilterSetup(uint8_t action,
+                                     tBTA_DM_BLE_PF_FILT_INDEX filt_index,
+                                     tBTA_DM_BLE_PF_FILT_PARAMS* p_filt_params,
+                                     tBLE_BD_ADDR* p_target,
+                                     tBTA_DM_BLE_PF_PARAM_CBACK* p_cmpl_cback,
+                                     tBTA_DM_BLE_REF_VALUE ref_value);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleCfgFilterCondition
+ *
+ * Description      This function is called to configure the adv data payload
+ *                  filter condition.
+ *
+ * Parameters       action: to read/write/clear
+ *                  cond_type: filter condition type
+ *                  filt_index - Filter index
+ *                  p_cond: filter condition parameter
+ *                  p_cmpl_back - Command completed callback
+ *                  ref_value - Reference value
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmBleCfgFilterCondition(tBTA_DM_BLE_SCAN_COND_OP action,
+                                        tBTA_DM_BLE_PF_COND_TYPE cond_type,
+                                        tBTA_DM_BLE_PF_FILT_INDEX filt_index,
+                                        tBTA_DM_BLE_PF_COND_PARAM* p_cond,
+                                        tBTA_DM_BLE_PF_CFG_CBACK* p_cmpl_cback,
+                                        tBTA_DM_BLE_REF_VALUE ref_value);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleTrackAdvertiser
+ *
+ * Description      This function is called to track the advertiser
+ *
+ * Parameters    ref_value - Reference value
+ *               p_track_adv_cback - ADV callback
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_DmBleTrackAdvertiser(
+    tBTA_DM_BLE_REF_VALUE ref_value,
+    tBTA_BLE_TRACK_ADV_CBACK* p_track_adv_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTA_DmBleGetEnergyInfo
+ *
+ * Description      This function is called to obtain the energy info
+ *
+ * Parameters       p_cmpl_cback - Command complete callback
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_DmBleGetEnergyInfo(tBTA_BLE_ENERGY_INFO_CBACK* p_cmpl_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTA_BrcmInit
+ *
+ * Description      This function initializes Broadcom specific VS handler in
+ *                  BTA
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_VendorInit(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_BrcmCleanup
+ *
+ * Description      This function frees up Broadcom specific VS specific dynamic
+ *                  memory
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_VendorCleanup(void);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_API_H */
diff --git a/bt/bta/include/bta_ar_api.h b/bt/bta/include/bta_ar_api.h
new file mode 100644
index 0000000..d6a8147
--- /dev/null
+++ b/bt/bta/include/bta_ar_api.h
@@ -0,0 +1,148 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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 is the public interface file for the simulatenous advanced
+ *  audio/video streaming (AV) source and sink of BTA, Broadcom's Bluetooth
+ *  application layer for mobile phones.
+ *
+ ******************************************************************************/
+#ifndef BTA_AR_API_H
+#define BTA_AR_API_H
+
+#include "avct_api.h"
+#include "avdt_api.h"
+#include "avrc_api.h"
+#include "bta_av_api.h"
+#include "bta_sys.h"
+#include "sdp_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+ *  Constants and data types
+ ****************************************************************************/
+/* This event signal to AR user that other profile is connected */
+#define BTA_AR_AVDT_CONN_EVT (AVDT_MAX_EVT + 1)
+
+/*******************************************************************************
+ *
+ * Function         bta_ar_init
+ *
+ * Description      This function is called from bta_sys_init().
+ *                  to initialize the control block
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_ar_init(void);
+
+/*******************************************************************************
+ *
+ * Function         bta_ar_reg_avdt
+ *
+ * Description      This function is called to register to AVDTP.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_ar_reg_avdt(tAVDT_REG* p_reg, tAVDT_CTRL_CBACK* p_cback,
+                            tBTA_SYS_ID sys_id);
+
+/*******************************************************************************
+ *
+ * Function         bta_ar_dereg_avdt
+ *
+ * Description      This function is called to de-register from AVDTP.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_ar_dereg_avdt(tBTA_SYS_ID sys_id);
+
+/*******************************************************************************
+ *
+ * Function         bta_ar_avdt_conn
+ *
+ * Description      This function is called to let ar know that some AVDTP
+ *                  profile is connected for this sys_id.
+ *                  If the other sys modules started a timer for PENDING_EVT,
+ *                  the timer can be stopped now.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_ar_avdt_conn(tBTA_SYS_ID sys_id, BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         bta_ar_reg_avct
+ *
+ * Description      This function is called to register to AVCTP.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_ar_reg_avct(uint16_t mtu, uint16_t mtu_br, uint8_t sec_mask,
+                            tBTA_SYS_ID sys_id);
+
+/*******************************************************************************
+ *
+ * Function         bta_ar_dereg_avct
+ *
+ * Description      This function is called to deregister from AVCTP.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_ar_dereg_avct(tBTA_SYS_ID sys_id);
+
+/******************************************************************************
+ *
+ * Function         bta_ar_reg_avrc
+ *
+ * Description      This function is called to register an SDP record for AVRCP.
+ *
+ * Returns          void
+ *
+ *****************************************************************************/
+extern void bta_ar_reg_avrc(uint16_t service_uuid, const char* p_service_name,
+                            const char* p_provider_name, uint16_t categories,
+                            tBTA_SYS_ID sys_id, bool browse_supported,
+                            uint16_t profile_version);
+
+/******************************************************************************
+ *
+ * Function         bta_ar_dereg_avrc
+ *
+ * Description      This function is called to de-register/delete an SDP record
+ *                  for AVRCP.
+ *
+ * Returns          void
+ *
+ *****************************************************************************/
+extern void bta_ar_dereg_avrc(uint16_t service_uuid, tBTA_SYS_ID sys_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_AR_API_H */
diff --git a/bt/bta/include/bta_av_api.h b/bt/bta/include/bta_av_api.h
new file mode 100644
index 0000000..edc21de
--- /dev/null
+++ b/bt/bta/include/bta_av_api.h
@@ -0,0 +1,800 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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 is the public interface file for the advanced audio/video streaming
+ *  (AV) subsystem of BTA, Broadcom's Bluetooth application layer for mobile
+ *  phones.
+ *
+ ******************************************************************************/
+#ifndef BTA_AV_API_H
+#define BTA_AV_API_H
+
+#include "a2dp_api.h"
+#include "avdt_api.h"
+#include "avrc_api.h"
+#include "bta_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+ *  Constants and data types
+ ****************************************************************************/
+/* Set to TRUE if seperate authorization prompt desired for AVCTP besides A2DP
+ * authorization */
+/* Typically FALSE when AVRCP is used in conjunction with A2DP */
+#ifndef BTA_AV_WITH_AVCTP_AUTHORIZATION
+#define BTA_AV_WITH_AVCTP_AUTHORIZATION FALSE
+#endif
+
+/* AV status values */
+#define BTA_AV_SUCCESS 0        /* successful operation */
+#define BTA_AV_FAIL 1           /* generic failure */
+#define BTA_AV_FAIL_SDP 2       /* service not found */
+#define BTA_AV_FAIL_STREAM 3    /* stream connection failed */
+#define BTA_AV_FAIL_RESOURCES 4 /* no resources */
+#define BTA_AV_FAIL_ROLE 5 /* failed due to role management related issues */
+#define BTA_AV_FAIL_GET_CAP \
+  6 /* get capability failed due to no SEP availale on the peer  */
+
+typedef uint8_t tBTA_AV_STATUS;
+
+/* AV features masks */
+#define BTA_AV_FEAT_RCTG 0x0001    /* remote control target */
+#define BTA_AV_FEAT_RCCT 0x0002    /* remote control controller */
+#define BTA_AV_FEAT_PROTECT 0x0004 /* streaming media contect protection */
+#define BTA_AV_FEAT_VENDOR                                                    \
+  0x0008                          /* remote control vendor dependent commands \
+                                     */
+#define BTA_AV_FEAT_REPORT 0x0020 /* use reporting service for VDP */
+#define BTA_AV_FEAT_METADATA \
+  0x0040 /* remote control Metadata Transfer command/response */
+#define BTA_AV_FEAT_MULTI_AV \
+  0x0080                          /* use multi-av, if controller supports it */
+#define BTA_AV_FEAT_BROWSE 0x0010 /* use browsing channel */
+#define BTA_AV_FEAT_MASTER 0x0100 /* stream only as master role */
+#define BTA_AV_FEAT_ADV_CTRL \
+  0x0200 /* remote control Advanced Control command/response */
+#define BTA_AV_FEAT_DELAY_RPT 0x0400 /* allow delay reporting */
+#define BTA_AV_FEAT_ACP_START \
+  0x0800 /* start stream when 2nd SNK was accepted   */
+#define BTA_AV_FEAT_APP_SETTING 0x2000 /* Player app setting support */
+
+/* Internal features */
+#define BTA_AV_FEAT_NO_SCO_SSPD \
+  0x8000 /* Do not suspend av streaming as to AG events(SCO or Call) */
+
+typedef uint16_t tBTA_AV_FEAT;
+
+/* AV channel values */
+#define BTA_AV_CHNL_MSK 0xC0
+#define BTA_AV_CHNL_AUDIO 0x40 /* audio channel */
+#define BTA_AV_CHNL_VIDEO 0x80 /* video channel */
+typedef uint8_t tBTA_AV_CHNL;
+
+#define BTA_AV_HNDL_MSK 0x3F
+typedef uint8_t tBTA_AV_HNDL;
+/* handle index to mask */
+#define BTA_AV_HNDL_TO_MSK(h) ((uint8_t)(1 << (h)))
+
+/* maximum number of streams created: 1 for audio, 1 for video */
+#ifndef BTA_AV_NUM_STRS
+#define BTA_AV_NUM_STRS 2
+#endif
+
+#ifndef BTA_AV_MAX_A2DP_MTU
+/*#define BTA_AV_MAX_A2DP_MTU     668 //224 (DM5) * 3 - 4(L2CAP header) */
+#define BTA_AV_MAX_A2DP_MTU 1008
+#endif
+
+#ifndef BTA_AV_MAX_VDP_MTU
+#define BTA_AV_MAX_VDP_MTU 1008
+#endif
+
+/* operation id list for BTA_AvRemoteCmd */
+#define BTA_AV_RC_SELECT AVRC_ID_SELECT         /* select */
+#define BTA_AV_RC_UP AVRC_ID_UP                 /* up */
+#define BTA_AV_RC_DOWN AVRC_ID_DOWN             /* down */
+#define BTA_AV_RC_LEFT AVRC_ID_LEFT             /* left */
+#define BTA_AV_RC_RIGHT AVRC_ID_RIGHT           /* right */
+#define BTA_AV_RC_RIGHT_UP AVRC_ID_RIGHT_UP     /* right-up */
+#define BTA_AV_RC_RIGHT_DOWN AVRC_ID_RIGHT_DOWN /* right-down */
+#define BTA_AV_RC_LEFT_UP AVRC_ID_LEFT_UP       /* left-up */
+#define BTA_AV_RC_LEFT_DOWN AVRC_ID_LEFT_DOWN   /* left-down */
+#define BTA_AV_RC_ROOT_MENU AVRC_ID_ROOT_MENU   /* root menu */
+#define BTA_AV_RC_SETUP_MENU AVRC_ID_SETUP_MENU /* setup menu */
+#define BTA_AV_RC_CONT_MENU AVRC_ID_CONT_MENU   /* contents menu */
+#define BTA_AV_RC_FAV_MENU AVRC_ID_FAV_MENU     /* favorite menu */
+#define BTA_AV_RC_EXIT AVRC_ID_EXIT             /* exit */
+#define BTA_AV_RC_0 AVRC_ID_0                   /* 0 */
+#define BTA_AV_RC_1 AVRC_ID_1                   /* 1 */
+#define BTA_AV_RC_2 AVRC_ID_2                   /* 2 */
+#define BTA_AV_RC_3 AVRC_ID_3                   /* 3 */
+#define BTA_AV_RC_4 AVRC_ID_4                   /* 4 */
+#define BTA_AV_RC_5 AVRC_ID_5                   /* 5 */
+#define BTA_AV_RC_6 AVRC_ID_6                   /* 6 */
+#define BTA_AV_RC_7 AVRC_ID_7                   /* 7 */
+#define BTA_AV_RC_8 AVRC_ID_8                   /* 8 */
+#define BTA_AV_RC_9 AVRC_ID_9                   /* 9 */
+#define BTA_AV_RC_DOT AVRC_ID_DOT               /* dot */
+#define BTA_AV_RC_ENTER AVRC_ID_ENTER           /* enter */
+#define BTA_AV_RC_CLEAR AVRC_ID_CLEAR           /* clear */
+#define BTA_AV_RC_CHAN_UP AVRC_ID_CHAN_UP       /* channel up */
+#define BTA_AV_RC_CHAN_DOWN AVRC_ID_CHAN_DOWN   /* channel down */
+#define BTA_AV_RC_PREV_CHAN AVRC_ID_PREV_CHAN   /* previous channel */
+#define BTA_AV_RC_SOUND_SEL AVRC_ID_SOUND_SEL   /* sound select */
+#define BTA_AV_RC_INPUT_SEL AVRC_ID_INPUT_SEL   /* input select */
+#define BTA_AV_RC_DISP_INFO AVRC_ID_DISP_INFO   /* display information */
+#define BTA_AV_RC_HELP AVRC_ID_HELP             /* help */
+#define BTA_AV_RC_PAGE_UP AVRC_ID_PAGE_UP       /* page up */
+#define BTA_AV_RC_PAGE_DOWN AVRC_ID_PAGE_DOWN   /* page down */
+#define BTA_AV_RC_POWER AVRC_ID_POWER           /* power */
+#define BTA_AV_RC_VOL_UP AVRC_ID_VOL_UP         /* volume up */
+#define BTA_AV_RC_VOL_DOWN AVRC_ID_VOL_DOWN     /* volume down */
+#define BTA_AV_RC_MUTE AVRC_ID_MUTE             /* mute */
+#define BTA_AV_RC_PLAY AVRC_ID_PLAY             /* play */
+#define BTA_AV_RC_STOP AVRC_ID_STOP             /* stop */
+#define BTA_AV_RC_PAUSE AVRC_ID_PAUSE           /* pause */
+#define BTA_AV_RC_RECORD AVRC_ID_RECORD         /* record */
+#define BTA_AV_RC_REWIND AVRC_ID_REWIND         /* rewind */
+#define BTA_AV_RC_FAST_FOR AVRC_ID_FAST_FOR     /* fast forward */
+#define BTA_AV_RC_EJECT AVRC_ID_EJECT           /* eject */
+#define BTA_AV_RC_FORWARD AVRC_ID_FORWARD       /* forward */
+#define BTA_AV_RC_BACKWARD AVRC_ID_BACKWARD     /* backward */
+#define BTA_AV_RC_ANGLE AVRC_ID_ANGLE           /* angle */
+#define BTA_AV_RC_SUBPICT AVRC_ID_SUBPICT       /* subpicture */
+#define BTA_AV_RC_F1 AVRC_ID_F1                 /* F1 */
+#define BTA_AV_RC_F2 AVRC_ID_F2                 /* F2 */
+#define BTA_AV_RC_F3 AVRC_ID_F3                 /* F3 */
+#define BTA_AV_RC_F4 AVRC_ID_F4                 /* F4 */
+#define BTA_AV_RC_F5 AVRC_ID_F5                 /* F5 */
+#define BTA_AV_VENDOR AVRC_ID_VENDOR            /* vendor unique */
+
+typedef uint8_t tBTA_AV_RC;
+
+/* state flag for pass through command */
+#define BTA_AV_STATE_PRESS AVRC_STATE_PRESS     /* key pressed */
+#define BTA_AV_STATE_RELEASE AVRC_STATE_RELEASE /* key released */
+
+typedef uint8_t tBTA_AV_STATE;
+
+/* command codes for BTA_AvVendorCmd */
+#define BTA_AV_CMD_CTRL AVRC_CMD_CTRL
+#define BTA_AV_CMD_STATUS AVRC_CMD_STATUS
+#define BTA_AV_CMD_SPEC_INQ AVRC_CMD_SPEC_INQ
+#define BTA_AV_CMD_NOTIF AVRC_CMD_NOTIF
+#define BTA_AV_CMD_GEN_INQ AVRC_CMD_GEN_INQ
+
+typedef uint8_t tBTA_AV_CMD;
+
+/* response codes for BTA_AvVendorRsp */
+#define BTA_AV_RSP_NOT_IMPL AVRC_RSP_NOT_IMPL
+#define BTA_AV_RSP_ACCEPT AVRC_RSP_ACCEPT
+#define BTA_AV_RSP_REJ AVRC_RSP_REJ
+#define BTA_AV_RSP_IN_TRANS AVRC_RSP_IN_TRANS
+#define BTA_AV_RSP_IMPL_STBL AVRC_RSP_IMPL_STBL
+#define BTA_AV_RSP_CHANGED AVRC_RSP_CHANGED
+#define BTA_AV_RSP_INTERIM AVRC_RSP_INTERIM
+
+typedef uint8_t tBTA_AV_CODE;
+
+/* error codes for BTA_AvProtectRsp */
+#define BTA_AV_ERR_NONE A2DP_SUCCESS /* Success, no error */
+#define BTA_AV_ERR_BAD_STATE \
+  AVDT_ERR_BAD_STATE /* Message cannot be processed in this state */
+#define BTA_AV_ERR_RESOURCE AVDT_ERR_RESOURCE /* Insufficient resources */
+#define BTA_AV_ERR_BAD_CP_TYPE                                               \
+  A2DP_BAD_CP_TYPE /* The requested Content Protection Type is not supported \
+                      */
+#define BTA_AV_ERR_BAD_CP_FORMAT                                             \
+  A2DP_BAD_CP_FORMAT /* The format of Content Protection Data is not correct \
+                        */
+
+typedef uint8_t tBTA_AV_ERR;
+
+/* AV callback events */
+#define BTA_AV_ENABLE_EVT 0      /* AV enabled */
+#define BTA_AV_REGISTER_EVT 1    /* registered to AVDT */
+#define BTA_AV_OPEN_EVT 2        /* connection opened */
+#define BTA_AV_CLOSE_EVT 3       /* connection closed */
+#define BTA_AV_START_EVT 4       /* stream data transfer started */
+#define BTA_AV_STOP_EVT 5        /* stream data transfer stopped */
+#define BTA_AV_PROTECT_REQ_EVT 6 /* content protection request */
+#define BTA_AV_PROTECT_RSP_EVT 7 /* content protection response */
+#define BTA_AV_RC_OPEN_EVT 8     /* remote control channel open */
+#define BTA_AV_RC_CLOSE_EVT 9    /* remote control channel closed */
+#define BTA_AV_REMOTE_CMD_EVT 10 /* remote control command */
+#define BTA_AV_REMOTE_RSP_EVT 11 /* remote control response */
+#define BTA_AV_VENDOR_CMD_EVT 12 /* vendor dependent remote control command */
+#define BTA_AV_VENDOR_RSP_EVT                                              \
+  13                           /* vendor dependent remote control response \
+                                  */
+#define BTA_AV_RECONFIG_EVT 14 /* reconfigure response */
+#define BTA_AV_SUSPEND_EVT 15  /* suspend response */
+#define BTA_AV_PENDING_EVT                                             \
+  16                           /* incoming connection pending:         \
+                                * signal channel is open and stream is \
+                                * not open after                       \
+                                * BTA_AV_SIGNALLING_TIMEOUT_MS */
+#define BTA_AV_META_MSG_EVT 17 /* metadata messages */
+#define BTA_AV_REJECT_EVT 18   /* incoming connection rejected */
+#define BTA_AV_RC_FEAT_EVT \
+  19 /* remote control channel peer supported features update */
+#define BTA_AV_SINK_MEDIA_CFG_EVT 20    /* command to configure codec */
+#define BTA_AV_SINK_MEDIA_DATA_EVT 21   /* sending data to Media Task */
+#define BTA_AV_OFFLOAD_START_RSP_EVT 22 /* a2dp offload start response */
+#define BTA_AV_RC_BROWSE_OPEN_EVT 23    /* remote control channel open */
+#define BTA_AV_RC_BROWSE_CLOSE_EVT 24   /* remote control channel closed */
+/* Max BTA event */
+#define BTA_AV_MAX_EVT 25
+
+typedef uint8_t tBTA_AV_EVT;
+
+/* Event associated with BTA_AV_ENABLE_EVT */
+typedef struct { tBTA_AV_FEAT features; } tBTA_AV_ENABLE;
+
+/* Event associated with BTA_AV_REGISTER_EVT */
+typedef struct {
+  tBTA_AV_CHNL chnl; /* audio/video */
+  tBTA_AV_HNDL hndl; /* Handle associated with the stream. */
+  uint8_t app_id;    /* ID associated with call to BTA_AvRegister() */
+  tBTA_AV_STATUS status;
+} tBTA_AV_REGISTER;
+
+/* data associated with BTA_AV_OPEN_EVT */
+#define BTA_AV_EDR_2MBPS 0x01
+#define BTA_AV_EDR_3MBPS 0x02
+typedef uint8_t tBTA_AV_EDR;
+
+typedef struct {
+  tBTA_AV_CHNL chnl;
+  tBTA_AV_HNDL hndl;
+  BD_ADDR bd_addr;
+  tBTA_AV_STATUS status;
+  bool starting;
+  tBTA_AV_EDR edr; /* 0, if peer device does not support EDR */
+  uint8_t sep;     /*  sep type of peer device */
+} tBTA_AV_OPEN;
+
+/* data associated with BTA_AV_CLOSE_EVT */
+typedef struct {
+  tBTA_AV_CHNL chnl;
+  tBTA_AV_HNDL hndl;
+} tBTA_AV_CLOSE;
+
+/* data associated with BTA_AV_START_EVT */
+typedef struct {
+  tBTA_AV_CHNL chnl;
+  tBTA_AV_HNDL hndl;
+  tBTA_AV_STATUS status;
+  bool initiator; /* true, if local device initiates the START */
+  bool suspending;
+} tBTA_AV_START;
+
+/* data associated with BTA_AV_SUSPEND_EVT */
+typedef struct {
+  tBTA_AV_CHNL chnl;
+  tBTA_AV_HNDL hndl;
+  bool initiator; /* true, if local device initiates the SUSPEND */
+  tBTA_AV_STATUS status;
+} tBTA_AV_SUSPEND;
+
+/* data associated with BTA_AV_RECONFIG_EVT */
+typedef struct {
+  tBTA_AV_CHNL chnl;
+  tBTA_AV_HNDL hndl;
+  tBTA_AV_STATUS status;
+} tBTA_AV_RECONFIG;
+
+/* data associated with BTA_AV_PROTECT_REQ_EVT */
+typedef struct {
+  tBTA_AV_CHNL chnl;
+  tBTA_AV_HNDL hndl;
+  uint8_t* p_data;
+  uint16_t len;
+} tBTA_AV_PROTECT_REQ;
+
+/* data associated with BTA_AV_PROTECT_RSP_EVT */
+typedef struct {
+  tBTA_AV_CHNL chnl;
+  tBTA_AV_HNDL hndl;
+  uint8_t* p_data;
+  uint16_t len;
+  tBTA_AV_ERR err_code;
+} tBTA_AV_PROTECT_RSP;
+
+/* data associated with BTA_AV_RC_OPEN_EVT */
+typedef struct {
+  uint8_t rc_handle;
+  tBTA_AV_FEAT peer_features;
+  BD_ADDR peer_addr;
+  tBTA_AV_STATUS status;
+} tBTA_AV_RC_OPEN;
+
+/* data associated with BTA_AV_RC_CLOSE_EVT */
+typedef struct {
+  uint8_t rc_handle;
+  BD_ADDR peer_addr;
+} tBTA_AV_RC_CLOSE;
+
+/* data associated with BTA_AV_RC_BROWSE_OPEN_EVT */
+typedef struct {
+  uint8_t rc_handle;
+  BD_ADDR peer_addr;
+  tBTA_AV_STATUS status;
+} tBTA_AV_RC_BROWSE_OPEN;
+
+/* data associated with BTA_AV_RC_BROWSE_CLOSE_EVT */
+typedef struct {
+  uint8_t rc_handle;
+  BD_ADDR peer_addr;
+} tBTA_AV_RC_BROWSE_CLOSE;
+
+/* data associated with BTA_AV_RC_FEAT_EVT */
+typedef struct {
+  uint8_t rc_handle;
+  tBTA_AV_FEAT peer_features;
+  BD_ADDR peer_addr;
+} tBTA_AV_RC_FEAT;
+
+/* data associated with BTA_AV_REMOTE_CMD_EVT */
+typedef struct {
+  uint8_t rc_handle;
+  tBTA_AV_RC rc_id;
+  tBTA_AV_STATE key_state;
+  uint8_t len;
+  uint8_t* p_data;
+  tAVRC_HDR hdr; /* Message header. */
+  uint8_t label;
+} tBTA_AV_REMOTE_CMD;
+
+/* data associated with BTA_AV_REMOTE_RSP_EVT */
+typedef struct {
+  uint8_t rc_handle;
+  tBTA_AV_RC rc_id;
+  tBTA_AV_STATE key_state;
+  uint8_t len;
+  uint8_t* p_data;
+  tBTA_AV_CODE rsp_code;
+  uint8_t label;
+} tBTA_AV_REMOTE_RSP;
+
+/* data associated with BTA_AV_VENDOR_CMD_EVT, BTA_AV_VENDOR_RSP_EVT */
+typedef struct {
+  uint8_t rc_handle;
+  uint16_t len; /* Max vendor dependent message is 512 */
+  uint8_t label;
+  tBTA_AV_CODE code;
+  uint32_t company_id;
+  uint8_t* p_data;
+} tBTA_AV_VENDOR;
+
+/* data associated with BTA_AV_META_MSG_EVT */
+typedef struct {
+  uint8_t rc_handle;
+  uint16_t len;
+  uint8_t label;
+  tBTA_AV_CODE code;
+  uint32_t company_id;
+  uint8_t* p_data;
+  tAVRC_MSG* p_msg;
+} tBTA_AV_META_MSG;
+
+/* data associated with BTA_AV_PENDING_EVT */
+typedef struct { BD_ADDR bd_addr; } tBTA_AV_PEND;
+
+/* data associated with BTA_AV_REJECT_EVT */
+typedef struct {
+  BD_ADDR bd_addr;
+  tBTA_AV_HNDL hndl; /* Handle associated with the stream that rejected the
+                        connection. */
+} tBTA_AV_REJECT;
+
+/* union of data associated with AV callback */
+typedef union {
+  tBTA_AV_CHNL chnl;
+  tBTA_AV_ENABLE enable;
+  tBTA_AV_REGISTER registr;
+  tBTA_AV_OPEN open;
+  tBTA_AV_CLOSE close;
+  tBTA_AV_START start;
+  tBTA_AV_PROTECT_REQ protect_req;
+  tBTA_AV_PROTECT_RSP protect_rsp;
+  tBTA_AV_RC_OPEN rc_open;
+  tBTA_AV_RC_CLOSE rc_close;
+  tBTA_AV_RC_BROWSE_OPEN rc_browse_open;
+  tBTA_AV_RC_BROWSE_CLOSE rc_browse_close;
+  tBTA_AV_REMOTE_CMD remote_cmd;
+  tBTA_AV_REMOTE_RSP remote_rsp;
+  tBTA_AV_VENDOR vendor_cmd;
+  tBTA_AV_VENDOR vendor_rsp;
+  tBTA_AV_RECONFIG reconfig;
+  tBTA_AV_SUSPEND suspend;
+  tBTA_AV_PEND pend;
+  tBTA_AV_META_MSG meta_msg;
+  tBTA_AV_REJECT reject;
+  tBTA_AV_RC_FEAT rc_feat;
+  tBTA_AV_STATUS status;
+} tBTA_AV;
+
+typedef struct {
+  uint8_t* codec_info;
+  BD_ADDR bd_addr;
+  ;
+} tBTA_AVK_CONFIG;
+
+/* union of data associated with AV Media callback */
+typedef union {
+  BT_HDR* p_data;
+  tBTA_AVK_CONFIG avk_config;
+} tBTA_AV_MEDIA;
+
+#define BTA_GROUP_NAVI_MSG_OP_DATA_LEN 5
+
+/* AV callback */
+typedef void(tBTA_AV_CBACK)(tBTA_AV_EVT event, tBTA_AV* p_data);
+typedef void(tBTA_AV_SINK_DATA_CBACK)(tBTA_AV_EVT event, tBTA_AV_MEDIA* p_data);
+
+/* type for stream state machine action functions */
+typedef void (*tBTA_AV_ACT)(void* p_cb, void* p_data);
+
+/* type for registering VDP */
+typedef void(tBTA_AV_REG)(tAVDT_CS* p_cs, char* p_service_name, void* p_data);
+
+/* AV configuration structure */
+typedef struct {
+  uint32_t company_id;  /* AVRCP Company ID */
+  uint16_t avrc_mtu;    /* AVRCP MTU at L2CAP for control channel */
+  uint16_t avrc_br_mtu; /* AVRCP MTU at L2CAP for browsing channel */
+  uint16_t avrc_ct_cat; /* AVRCP controller categories */
+  uint16_t avrc_tg_cat; /* AVRCP target categories */
+  uint16_t sig_mtu;     /* AVDTP signaling channel MTU at L2CAP */
+  uint16_t audio_mtu;   /* AVDTP audio transport channel MTU at L2CAP */
+  const uint16_t*
+      p_audio_flush_to;    /* AVDTP audio transport channel flush timeout */
+  uint16_t audio_mqs;      /* AVDTP audio channel max data queue size */
+  uint16_t video_mtu;      /* AVDTP video transport channel MTU at L2CAP */
+  uint16_t video_flush_to; /* AVDTP video transport channel flush timeout */
+  bool avrc_group;     /* true, to accept AVRC 1.3 group nevigation command */
+  uint8_t num_co_ids;  /* company id count in p_meta_co_ids */
+  uint8_t num_evt_ids; /* event id count in p_meta_evt_ids */
+  tBTA_AV_CODE
+      rc_pass_rsp; /* the default response code for pass through commands */
+  const uint32_t*
+      p_meta_co_ids; /* the metadata Get Capabilities response for company id */
+  const uint8_t* p_meta_evt_ids; /* the the metadata Get Capabilities response
+                                    for event id */
+  const tBTA_AV_ACT* p_act_tbl;  /* the action function table for VDP stream */
+  tBTA_AV_REG* p_reg;            /* action function to register VDP */
+  char avrc_controller_name[BTA_SERVICE_NAME_LEN]; /* Default AVRCP controller
+                                                      name */
+  char avrc_target_name[BTA_SERVICE_NAME_LEN]; /* Default AVRCP target name*/
+} tBTA_AV_CFG;
+
+/*****************************************************************************
+ *  External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvEnable
+ *
+ * Description      Enable the advanced audio/video service. When the enable
+ *                  operation is complete the callback function will be
+ *                  called with a BTA_AV_ENABLE_EVT. This function must
+ *                  be called before other function in the AV API are
+ *                  called.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvEnable(tBTA_SEC sec_mask, tBTA_AV_FEAT features,
+                  tBTA_AV_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvDisable
+ *
+ * Description      Disable the advanced audio/video service.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvDisable(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvRegister
+ *
+ * Description      Register the audio or video service to stack. When the
+ *                  operation is complete the callback function will be
+ *                  called with a BTA_AV_REGISTER_EVT. This function must
+ *                  be called before AVDT stream is open.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvRegister(tBTA_AV_CHNL chnl, const char* p_service_name,
+                    uint8_t app_id, tBTA_AV_SINK_DATA_CBACK* p_sink_data_cback,
+                    uint16_t service_uuid);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvDeregister
+ *
+ * Description      Deregister the audio or video service
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvDeregister(tBTA_AV_HNDL hndl);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvOpen
+ *
+ * Description      Opens an advanced audio/video connection to a peer device.
+ *                  When connection is open callback function is called
+ *                  with a BTA_AV_OPEN_EVT.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvOpen(BD_ADDR bd_addr, tBTA_AV_HNDL handle, bool use_rc,
+                tBTA_SEC sec_mask, uint16_t uuid);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvClose
+ *
+ * Description      Close the current streams.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvClose(tBTA_AV_HNDL handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvDisconnect
+ *
+ * Description      Close the connection to the address.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvDisconnect(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvStart
+ *
+ * Description      Start audio/video stream data transfer.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvStart(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvStop
+ *
+ * Description      Stop audio/video stream data transfer.
+ *                  If suspend is true, this function sends AVDT suspend signal
+ *                  to the connected peer(s).
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvStop(bool suspend);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvReconfig
+ *
+ * Description      Reconfigure the audio/video stream.
+ *                  If suspend is true, this function tries the
+ *                  suspend/reconfigure procedure first.
+ *                  If suspend is false or when suspend/reconfigure fails,
+ *                  this function closes and re-opens the AVDT connection.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvReconfig(tBTA_AV_HNDL hndl, bool suspend, uint8_t sep_info_idx,
+                    uint8_t* p_codec_info, uint8_t num_protect,
+                    const uint8_t* p_protect_info);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvProtectReq
+ *
+ * Description      Send a content protection request.  This function can only
+ *                  be used if AV is enabled with feature BTA_AV_FEAT_PROTECT.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvProtectReq(tBTA_AV_HNDL hndl, uint8_t* p_data, uint16_t len);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvProtectRsp
+ *
+ * Description      Send a content protection response.  This function must
+ *                  be called if a BTA_AV_PROTECT_REQ_EVT is received.
+ *                  This function can only be used if AV is enabled with
+ *                  feature BTA_AV_FEAT_PROTECT.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvProtectRsp(tBTA_AV_HNDL hndl, uint8_t error_code, uint8_t* p_data,
+                      uint16_t len);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvRemoteCmd
+ *
+ * Description      Send a remote control command.  This function can only
+ *                  be used if AV is enabled with feature BTA_AV_FEAT_RCCT.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvRemoteCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_RC rc_id,
+                     tBTA_AV_STATE key_state);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvRemoteVendorUniqueCmd
+ *
+ * Description      Send a remote control command with Vendor Unique rc_id.
+ *                  This function can only be used if AV is enabled with
+ *                  feature BTA_AV_FEAT_RCCT.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvRemoteVendorUniqueCmd(uint8_t rc_handle, uint8_t label,
+                                 tBTA_AV_STATE key_state, uint8_t* p_msg,
+                                 uint8_t buf_len);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvVendorCmd
+ *
+ * Description      Send a vendor dependent remote control command.  This
+ *                  function can only be used if AV is enabled with feature
+ *                  BTA_AV_FEAT_VENDOR.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvVendorCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE cmd_code,
+                     uint8_t* p_data, uint16_t len);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvVendorRsp
+ *
+ * Description      Send a vendor dependent remote control response.
+ *                  This function must be called if a BTA_AV_VENDOR_CMD_EVT
+ *                  is received. This function can only be used if AV is
+ *                  enabled with feature BTA_AV_FEAT_VENDOR.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvVendorRsp(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code,
+                     uint8_t* p_data, uint16_t len, uint32_t company_id);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvOpenRc
+ *
+ * Description      Open an AVRCP connection toward the device with the
+ *                  specified handle
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvOpenRc(tBTA_AV_HNDL handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvCloseRc
+ *
+ * Description      Close an AVRCP connection
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvCloseRc(uint8_t rc_handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvMetaRsp
+ *
+ * Description      Send a Metadata command/response. The message contained
+ *                  in p_pkt can be composed with AVRC utility functions.
+ *                  This function can only be used if AV is enabled with feature
+ *                  BTA_AV_FEAT_METADATA.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvMetaRsp(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code,
+                   BT_HDR* p_pkt);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvMetaCmd
+ *
+ * Description      Send a Metadata/Advanced Control command. The message
+*contained
+ *                  in p_pkt can be composed with AVRC utility functions.
+ *                  This function can only be used if AV is enabled with feature
+ *                  BTA_AV_FEAT_METADATA.
+ *                  This message is sent only when the peer supports the TG
+*role.
+*8                  The only command makes sense right now is the absolute
+*volume command.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvMetaCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_CMD cmd_code,
+                   BT_HDR* p_pkt);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvOffloadStart
+ *
+ * Description      Request Starting of A2DP Offload.
+ *                  This function is used to start A2DP offload if vendor lib
+ *                  has the feature enabled.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvOffloadStart(tBTA_AV_HNDL hndl);
+
+/*******************************************************************************
+ *
+ * Function         BTA_AvOffloadStartRsp
+ *
+ * Description      Response from vendor library indicating response for
+ *                  OffloadStart.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_AvOffloadStartRsp(tBTA_AV_HNDL hndl, tBTA_AV_STATUS status);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_AV_API_H */
diff --git a/bt/bta/include/bta_av_ci.h b/bt/bta/include/bta_av_ci.h
new file mode 100644
index 0000000..f4b4a37
--- /dev/null
+++ b/bt/bta/include/bta_av_ci.h
@@ -0,0 +1,71 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2005-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 is the interface file for advanced audio/video call-in functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_AV_CI_H
+#define BTA_AV_CI_H
+
+#include "bta_av_api.h"
+
+/*****************************************************************************
+ *  Function Declarations
+ ****************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_av_ci_src_data_ready
+ *
+ * Description      This function sends an event to the AV indicating that
+ *                  the phone has audio stream data ready to send and AV
+ *                  should call bta_av_co_audio_src_data_path().
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_av_ci_src_data_ready(tBTA_AV_CHNL chnl);
+
+/*******************************************************************************
+ *
+ * Function         bta_av_ci_setconfig
+ *
+ * Description      This function must be called in response to function
+ *                  bta_av_co_audio_setconfig().
+ *                  Parameter err_code is set to an AVDTP status value;
+ *                  AVDT_SUCCESS if the codec configuration is ok,
+ *                  otherwise error.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_av_ci_setconfig(tBTA_AV_HNDL hndl, uint8_t err_code,
+                                uint8_t category, uint8_t num_seid,
+                                uint8_t* p_seid, bool recfg_needed,
+                                uint8_t avdt_handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_AV_CI_H */
diff --git a/bt/bta/include/bta_av_co.h b/bt/bta/include/bta_av_co.h
new file mode 100644
index 0000000..a7cc30e
--- /dev/null
+++ b/bt/bta/include/bta_av_co.h
@@ -0,0 +1,209 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 is the interface file for advanced audio call-out functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_AV_CO_H
+#define BTA_AV_CO_H
+
+#include "bta_av_api.h"
+#include "l2c_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+ *  Constants and data types
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         bta_av_co_audio_init
+ *
+ * Description      This callout function is executed by AV when it is
+ *                  started by calling BTA_AvEnable().  This function can be
+ *                  used by the phone to initialize audio paths or for other
+ *                  initialization purposes.
+ *
+ *
+ * Returns          Stream codec and content protection capabilities info.
+ *
+ ******************************************************************************/
+bool bta_av_co_audio_init(tA2DP_CODEC_SEP_INDEX codec_sep_index,
+                          tAVDT_CFG* p_cfg);
+
+/*******************************************************************************
+ *
+ * Function         bta_av_co_audio_disc_res
+ *
+ * Description      This callout function is executed by AV to report the
+ *                  number of stream end points (SEP) were found during the
+ *                  AVDT stream discovery process.
+ *
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+void bta_av_co_audio_disc_res(tBTA_AV_HNDL hndl, uint8_t num_seps,
+                              uint8_t num_snk, uint8_t num_src, BD_ADDR addr,
+                              uint16_t uuid_local);
+
+/*******************************************************************************
+ *
+ * Function         bta_av_co_audio_getconfig
+ *
+ * Description      This callout function is executed by AV to retrieve the
+ *                  desired codec and content protection configuration for the
+ *                  audio stream.
+ *
+ *
+ * Returns          Stream codec and content protection configuration info.
+ *
+ ******************************************************************************/
+tA2DP_STATUS bta_av_co_audio_getconfig(tBTA_AV_HNDL hndl, uint8_t* p_codec_info,
+                                       uint8_t* p_sep_info_idx, uint8_t seid,
+                                       uint8_t* p_num_protect,
+                                       uint8_t* p_protect_info);
+
+/*******************************************************************************
+ *
+ * Function         bta_av_co_audio_setconfig
+ *
+ * Description      This callout function is executed by AV to set the
+ *                  codec and content protection configuration of the audio
+ *                  stream.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_co_audio_setconfig(tBTA_AV_HNDL hndl, const uint8_t* p_codec_info,
+                               uint8_t seid, BD_ADDR addr, uint8_t num_protect,
+                               uint8_t* p_protect_info, uint8_t t_local_sep,
+                               uint8_t avdt_handle);
+
+/*******************************************************************************
+ *
+ * Function         bta_av_co_audio_open
+ *
+ * Description      This function is called by AV when the audio stream
+ *                  connection is opened.
+ *                  BTA-AV maintains the MTU of A2DP streams.
+ *                  If this is the 2nd audio stream, mtu is the smaller of the 2
+ *                  streams.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_co_audio_open(tBTA_AV_HNDL hndl, uint8_t* p_codec_info,
+                          uint16_t mtu);
+
+/*******************************************************************************
+ *
+ * Function         bta_av_co_audio_close
+ *
+ * Description      This function is called by AV when the audio stream
+ *                  connection is closed.
+ *                  BTA-AV maintains the MTU of A2DP streams.
+ *                  When one stream is closed and no other audio stream is open,
+ *                  mtu is reported as 0.
+ *                  Otherwise, the MTU remains open is reported.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_co_audio_close(tBTA_AV_HNDL hndl, uint16_t mtu);
+
+/*******************************************************************************
+ *
+ * Function         bta_av_co_audio_start
+ *
+ * Description      This function is called by AV when the audio streaming data
+ *                  transfer is started.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_co_audio_start(tBTA_AV_HNDL hndl, uint8_t* p_codec_info,
+                           bool* p_no_rtp_hdr);
+
+/*******************************************************************************
+ *
+ * Function         bta_av_co_audio_stop
+ *
+ * Description      This function is called by AV when the audio streaming data
+ *                  transfer is stopped.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_co_audio_stop(tBTA_AV_HNDL hndl);
+
+/*******************************************************************************
+ *
+ * Function         bta_av_co_audio_src_data_path
+ *
+ * Description      This function is called to get the next data buffer from
+ *                  the audio codec
+ *
+ * Returns          NULL if data is not ready.
+ *                  Otherwise, a buffer (BT_HDR*) containing the audio data.
+ *
+ ******************************************************************************/
+void* bta_av_co_audio_src_data_path(const uint8_t* p_codec_info,
+                                    uint32_t* p_timestamp);
+
+/*******************************************************************************
+ *
+ * Function         bta_av_co_audio_drop
+ *
+ * Description      An Audio packet is dropped. .
+ *                  It's very likely that the connected headset with this handle
+ *                  is moved far away. The implementation may want to reduce
+ *                  the encoder bit rate setting to reduce the packet size.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_co_audio_drop(tBTA_AV_HNDL hndl);
+
+/*******************************************************************************
+ *
+ * Function         bta_av_co_audio_delay
+ *
+ * Description      This function is called by AV when the audio stream
+ *                  connection needs to send the initial delay report to the
+ *                  connected SRC.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_av_co_audio_delay(tBTA_AV_HNDL hndl, uint16_t delay);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_AV_CO_H */
diff --git a/bt/bta/include/bta_closure_api.h b/bt/bta/include/bta_closure_api.h
new file mode 100644
index 0000000..8c4e11a
--- /dev/null
+++ b/bt/bta/include/bta_closure_api.h
@@ -0,0 +1,36 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTA_CLOSURE_API_H
+#define BTA_CLOSURE_API_H
+
+#include <base/bind.h>
+#include <base/callback_forward.h>
+#include <base/location.h>
+
+/*
+ * This method post a closure for execution on bta thread. Please see
+ * documentation at
+ * https://www.chromium.org/developers/coding-style/important-abstractions-and-data-structures
+ * for how to handle dynamic memory ownership/smart pointers with base::Owned(),
+ * base::Passed(), base::ConstRef() and others.
+ */
+void do_in_bta_thread(const tracked_objects::Location& from_here,
+                      const base::Closure& task);
+
+#endif /* BTA_CLOSURE_API_H */
diff --git a/bt/bta/include/bta_dm_api.h b/bt/bta/include/bta_dm_api.h
new file mode 100644
index 0000000..673465f
--- /dev/null
+++ b/bt/bta/include/bta_dm_api.h
@@ -0,0 +1,40 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2006-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 is the interface file for device mananger functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_DM_API_H
+#define BTA_DM_API_H
+
+#include "stack/include/bt_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Brings connection to active mode
+void bta_dm_pm_active(BD_ADDR peer_addr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_DM_API_H */
diff --git a/bt/bta/include/bta_dm_ci.h b/bt/bta/include/bta_dm_ci.h
new file mode 100644
index 0000000..7354476
--- /dev/null
+++ b/bt/bta/include/bta_dm_ci.h
@@ -0,0 +1,79 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2006-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 is the interface file for device mananger call-in functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_DM_CI_H
+#define BTA_DM_CI_H
+
+#include "bta_api.h"
+
+/*****************************************************************************
+ *  Function Declarations
+ ****************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_ci_io_req
+ *
+ * Description      This function must be called in response to function
+ *                  bta_dm_co_io_req(), if *p_oob_data is set to BTA_OOB_UNKNOWN
+ *                  by bta_dm_co_io_req().
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_dm_ci_io_req(BD_ADDR bd_addr, tBTA_IO_CAP io_cap,
+                             tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req);
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_ci_rmt_oob
+ *
+ * Description      This function must be called in response to function
+ *                  bta_dm_co_rmt_oob() to provide the OOB data associated
+ *                  with the remote device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_dm_ci_rmt_oob(bool accept, BD_ADDR bd_addr, BT_OCTET16 c,
+                              BT_OCTET16 r);
+/*******************************************************************************
+ *
+ * Function         bta_dm_sco_ci_data_ready
+ *
+ * Description      This function sends an event to indicating that the phone
+ *                  has SCO data ready..
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_dm_sco_ci_data_ready(uint16_t event, uint16_t sco_handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bt/bta/include/bta_dm_co.h b/bt/bta/include/bta_dm_co.h
new file mode 100644
index 0000000..13f3020
--- /dev/null
+++ b/bt/bta/include/bta_dm_co.h
@@ -0,0 +1,283 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2006-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 is the interface file for device mananger callout functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_DM_CO_H
+#define BTA_DM_CO_H
+
+#include "bta_sys.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef BTA_SCO_OUT_PKT_SIZE
+#define BTA_SCO_OUT_PKT_SIZE BTM_SCO_DATA_SIZE_MAX
+#endif
+
+#define BTA_SCO_CODEC_PCM 0 /* used for regular SCO */
+#define BTA_SCO_CODEC_SBC 1 /* used for WBS */
+typedef uint8_t tBTA_SCO_CODEC_TYPE;
+
+#define BTA_DM_SCO_SAMP_RATE_8K 8000
+#define BTA_DM_SCO_SAMP_RATE_16K 16000
+
+/* SCO codec information */
+typedef struct { tBTA_SCO_CODEC_TYPE codec_type; } tBTA_CODEC_INFO;
+
+#define BTA_DM_SCO_ROUTE_PCM BTM_SCO_ROUTE_PCM
+#define BTA_DM_SCO_ROUTE_HCI BTM_SCO_ROUTE_HCI
+
+typedef tBTM_SCO_ROUTE_TYPE tBTA_DM_SCO_ROUTE_TYPE;
+
+/*****************************************************************************
+ *  Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_co_io_req
+ *
+ * Description      This callout function is executed by DM to get IO
+ *                  capabilities of the local device for the Simple Pairing
+ *                  process
+ *
+ * Parameters       bd_addr  - The peer device
+ *                  *p_io_cap - The local Input/Output capabilities
+ *                  *p_oob_data - true, if OOB data is available for the peer
+ *                                device.
+ *                  *p_auth_req - true, if MITM protection is required.
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+extern void bta_dm_co_io_req(BD_ADDR bd_addr, tBTA_IO_CAP* p_io_cap,
+                             tBTA_OOB_DATA* p_oob_data,
+                             tBTA_AUTH_REQ* p_auth_req, bool is_orig);
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_co_io_rsp
+ *
+ * Description      This callout function is executed by DM to report IO
+ *                  capabilities of the peer device for the Simple Pairing
+ *                  process
+ *
+ * Parameters       bd_addr  - The peer device
+ *                  io_cap - The remote Input/Output capabilities
+ *                  oob_data - true, if OOB data is available for the peer
+ *                             device.
+ *                  auth_req - true, if MITM protection is required.
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+extern void bta_dm_co_io_rsp(BD_ADDR bd_addr, tBTA_IO_CAP io_cap,
+                             tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req);
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_co_lk_upgrade
+ *
+ * Description      This callout function is executed by DM to check if the
+ *                  platform wants allow link key upgrade
+ *
+ * Parameters       bd_addr  - The peer device
+ *                  *p_upgrade - true, if link key upgrade is desired.
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+extern void bta_dm_co_lk_upgrade(BD_ADDR bd_addr, bool* p_upgrade);
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_co_loc_oob
+ *
+ * Description      This callout function is executed by DM to report the OOB
+ *                  data of the local device for the Simple Pairing process
+ *
+ * Parameters       valid - true, if the local OOB data is retrieved from LM
+ *                  c     - Simple Pairing Hash C
+ *                  r     - Simple Pairing Randomnizer R
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+extern void bta_dm_co_loc_oob(bool valid, BT_OCTET16 c, BT_OCTET16 r);
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_co_rmt_oob
+ *
+ * Description      This callout function is executed by DM to request the OOB
+ *                  data for the remote device for the Simple Pairing process
+ *
+ * Parameters       bd_addr  - The peer device
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+extern void bta_dm_co_rmt_oob(BD_ADDR bd_addr);
+
+/*****************************************************************************
+ *  SCO over HCI Function Declarations
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function         bta_dm_sco_co_init
+ *
+ * Description      This function can be used by the phone to initialize audio
+ *                  codec or for other initialization purposes before SCO
+ *                  connection is opened.
+ *
+ *
+ * Returns          Void.
+ *
+ ******************************************************************************/
+extern tBTA_DM_SCO_ROUTE_TYPE bta_dm_sco_co_init(uint32_t rx_bw, uint32_t tx_bw,
+                                                 tBTA_CODEC_INFO* p_codec_info,
+                                                 uint8_t app_id);
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_sco_co_open
+ *
+ * Description      This function is executed when a SCO connection is open.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_dm_sco_co_open(uint16_t handle, uint8_t pkt_size,
+                               uint16_t event);
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_sco_co_close
+ *
+ * Description      This function is called when a SCO connection is closed
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_dm_sco_co_close(void);
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_sco_co_out_data
+ *
+ * Description      This function is called to send SCO data over HCI.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_dm_sco_co_out_data(BT_HDR** p_buf);
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_sco_co_in_data
+ *
+ * Description      This function is called to send incoming SCO data to
+ *                  application.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_dm_sco_co_in_data(BT_HDR* p_buf, tBTM_SCO_DATA_FLAG status);
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_co_ble_io_req
+ *
+ * Description      This callout function is executed by DM to get BLE IO
+ *                  capabilities before SMP pairing gets going.
+ *
+ * Parameters       bd_addr  - The peer device
+ *                  *p_io_cap - The local Input/Output capabilities
+ *                  *p_oob_data - true, if OOB data is available for the peer
+ *                                device.
+ *                  *p_auth_req -  Auth request setting (Bonding and MITM
+ *                                                       required or not)
+ *                  *p_max_key_size - max key size local device supported.
+ *                  *p_init_key - initiator keys.
+ *                  *p_resp_key - responder keys.
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+extern void bta_dm_co_ble_io_req(BD_ADDR bd_addr, tBTA_IO_CAP* p_io_cap,
+                                 tBTA_OOB_DATA* p_oob_data,
+                                 tBTA_LE_AUTH_REQ* p_auth_req,
+                                 uint8_t* p_max_key_size,
+                                 tBTA_LE_KEY_TYPE* p_init_key,
+                                 tBTA_LE_KEY_TYPE* p_resp_key);
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_co_ble_local_key_reload
+ *
+ * Description      This callout function is to load the local BLE keys if
+ *                  available on the device.
+ *
+ * Parameters       none
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+extern void bta_dm_co_ble_load_local_keys(
+    tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask, BT_OCTET16 er,
+    tBTA_BLE_LOCAL_ID_KEYS* p_id_keys);
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_co_ble_io_req
+ *
+ * Description      This callout function is executed by DM to get BLE IO
+ *                  capabilities before SMP pairing gets going.
+ *
+ * Parameters       bd_addr  - The peer device
+ *                  *p_io_cap - The local Input/Output capabilities
+ *                  *p_oob_data - true, if OOB data is available for the peer
+ *                                device.
+ *                  *p_auth_req -  Auth request setting (Bonding and MITM
+ *                                                       required or not)
+ *                  *p_max_key_size - max key size local device supported.
+ *                  *p_init_key - initiator keys.
+ *                  *p_resp_key - responder keys.
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+extern void bta_dm_co_ble_io_req(BD_ADDR bd_addr, tBTA_IO_CAP* p_io_cap,
+                                 tBTA_OOB_DATA* p_oob_data,
+                                 tBTA_LE_AUTH_REQ* p_auth_req,
+                                 uint8_t* p_max_key_size,
+                                 tBTA_LE_KEY_TYPE* p_init_key,
+                                 tBTA_LE_KEY_TYPE* p_resp_key);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_DM_CO_H */
diff --git a/bt/bta/include/bta_gatt_api.h b/bt/bta/include/bta_gatt_api.h
new file mode 100644
index 0000000..6df3f82
--- /dev/null
+++ b/bt/bta/include/bta_gatt_api.h
@@ -0,0 +1,1122 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2013 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 is the public interface file for BTA GATT.
+ *
+ ******************************************************************************/
+
+#ifndef BTA_GATT_API_H
+#define BTA_GATT_API_H
+
+#include "bta_api.h"
+#include "gatt_api.h"
+#include "osi/include/list.h"
+
+#include <base/callback_forward.h>
+#include <vector>
+
+using std::vector;
+
+#ifndef BTA_GATT_INCLUDED
+#warning BTA_GATT_INCLUDED not defined
+#define BTA_GATT_INCLUDED false
+#endif
+
+#if (BLE_INCLUDED == FALSE && BTA_GATT_INCLUDED == TRUE)
+#undef BTA_GATT_INCLUDED
+#define BTA_GATT_INCLUDED false
+#endif
+
+#ifndef BTA_GATT_DEBUG
+#define BTA_GATT_DEBUG false
+#endif
+
+/*****************************************************************************
+ *  Constants and data types
+ ****************************************************************************/
+/**************************
+ *  Common Definitions
+ **************************/
+/* GATT ID */
+typedef struct {
+  tBT_UUID uuid;   /* uuid of the attribute */
+  uint8_t inst_id; /* instance ID */
+} __attribute__((packed)) tBTA_GATT_ID;
+
+/* Success code and error codes */
+#define BTA_GATT_OK GATT_SUCCESS
+#define BTA_GATT_INVALID_HANDLE GATT_INVALID_HANDLE             /* 0x0001 */
+#define BTA_GATT_READ_NOT_PERMIT GATT_READ_NOT_PERMIT           /* 0x0002 */
+#define BTA_GATT_WRITE_NOT_PERMIT GATT_WRITE_NOT_PERMIT         /* 0x0003 */
+#define BTA_GATT_INVALID_PDU GATT_INVALID_PDU                   /* 0x0004 */
+#define BTA_GATT_INSUF_AUTHENTICATION GATT_INSUF_AUTHENTICATION /* 0x0005 */
+#define BTA_GATT_REQ_NOT_SUPPORTED GATT_REQ_NOT_SUPPORTED       /* 0x0006 */
+#define BTA_GATT_INVALID_OFFSET GATT_INVALID_OFFSET             /* 0x0007 */
+#define BTA_GATT_INSUF_AUTHORIZATION GATT_INSUF_AUTHORIZATION   /* 0x0008 */
+#define BTA_GATT_PREPARE_Q_FULL GATT_PREPARE_Q_FULL             /* 0x0009 */
+#define BTA_GATT_NOT_FOUND GATT_NOT_FOUND                       /* 0x000a */
+#define BTA_GATT_NOT_LONG GATT_NOT_LONG                         /* 0x000b */
+#define BTA_GATT_INSUF_KEY_SIZE GATT_INSUF_KEY_SIZE             /* 0x000c */
+#define BTA_GATT_INVALID_ATTR_LEN GATT_INVALID_ATTR_LEN         /* 0x000d */
+#define BTA_GATT_ERR_UNLIKELY GATT_ERR_UNLIKELY                 /* 0x000e */
+#define BTA_GATT_INSUF_ENCRYPTION GATT_INSUF_ENCRYPTION         /* 0x000f */
+#define BTA_GATT_UNSUPPORT_GRP_TYPE GATT_UNSUPPORT_GRP_TYPE     /* 0x0010 */
+#define BTA_GATT_INSUF_RESOURCE GATT_INSUF_RESOURCE             /* 0x0011 */
+
+#define BTA_GATT_NO_RESOURCES GATT_NO_RESOURCES           /* 0x80 */
+#define BTA_GATT_INTERNAL_ERROR GATT_INTERNAL_ERROR       /* 0x81 */
+#define BTA_GATT_WRONG_STATE GATT_WRONG_STATE             /* 0x82 */
+#define BTA_GATT_DB_FULL GATT_DB_FULL                     /* 0x83 */
+#define BTA_GATT_BUSY GATT_BUSY                           /* 0x84 */
+#define BTA_GATT_ERROR GATT_ERROR                         /* 0x85 */
+#define BTA_GATT_CMD_STARTED GATT_CMD_STARTED             /* 0x86 */
+#define BTA_GATT_ILLEGAL_PARAMETER GATT_ILLEGAL_PARAMETER /* 0x87 */
+#define BTA_GATT_PENDING GATT_PENDING                     /* 0x88 */
+#define BTA_GATT_AUTH_FAIL GATT_AUTH_FAIL                 /* 0x89 */
+#define BTA_GATT_MORE GATT_MORE                           /* 0x8a */
+#define BTA_GATT_INVALID_CFG GATT_INVALID_CFG             /* 0x8b */
+#define BTA_GATT_SERVICE_STARTED GATT_SERVICE_STARTED     /* 0x8c */
+#define BTA_GATT_ENCRYPED_MITM GATT_ENCRYPED_MITM         /* GATT_SUCCESS */
+#define BTA_GATT_ENCRYPED_NO_MITM GATT_ENCRYPED_NO_MITM   /* 0x8d */
+#define BTA_GATT_NOT_ENCRYPTED GATT_NOT_ENCRYPTED         /* 0x8e */
+#define BTA_GATT_CONGESTED GATT_CONGESTED                 /* 0x8f */
+
+#define BTA_GATT_DUP_REG 0x90      /* 0x90 */
+#define BTA_GATT_ALREADY_OPEN 0x91 /* 0x91 */
+#define BTA_GATT_CANCEL 0x92       /* 0x92 */
+
+/* 0xE0 ~ 0xFC reserved for future use */
+#define BTA_GATT_CCC_CFG_ERR                                              \
+  GATT_CCC_CFG_ERR /* 0xFD Client Characteristic Configuration Descriptor \
+                      Improperly Configured */
+#define BTA_GATT_PRC_IN_PROGRESS \
+  GATT_PRC_IN_PROGRESS /* 0xFE Procedure Already in progress */
+#define BTA_GATT_OUT_OF_RANGE \
+  GATT_OUT_OF_RANGE /* 0xFFAttribute value out of range */
+
+typedef uint8_t tBTA_GATT_STATUS;
+
+#define BTA_GATT_INVALID_CONN_ID GATT_INVALID_CONN_ID
+
+/* Client callback function events */
+#define BTA_GATTC_REG_EVT 0          /* GATT client is registered. */
+#define BTA_GATTC_DEREG_EVT 1        /* GATT client deregistered event */
+#define BTA_GATTC_OPEN_EVT 2         /* GATTC open request status  event */
+#define BTA_GATTC_CLOSE_EVT 5        /* GATTC  close request status event */
+#define BTA_GATTC_SEARCH_CMPL_EVT 6  /* GATT discovery complete event */
+#define BTA_GATTC_SEARCH_RES_EVT 7   /* GATT discovery result event */
+#define BTA_GATTC_NOTIF_EVT 10       /* GATT attribute notification event */
+#define BTA_GATTC_EXEC_EVT 12        /* execute write complete event */
+#define BTA_GATTC_ACL_EVT 13         /* ACL up event */
+#define BTA_GATTC_CANCEL_OPEN_EVT 14 /* cancel open event */
+#define BTA_GATTC_SRVC_CHG_EVT 15    /* service change event */
+#define BTA_GATTC_ENC_CMPL_CB_EVT 17 /* encryption complete callback event */
+#define BTA_GATTC_CFG_MTU_EVT 18     /* configure MTU complete event */
+#define BTA_GATTC_CONGEST_EVT 24     /* Congestion event */
+
+typedef uint8_t tBTA_GATTC_EVT;
+
+typedef tGATT_IF tBTA_GATTC_IF;
+
+typedef struct {
+  uint16_t unit;  /* as UUIUD defined by SIG */
+  uint16_t descr; /* as UUID as defined by SIG */
+  tGATT_FORMAT format;
+  int8_t exp;
+  uint8_t name_spc; /* The name space of the description */
+} tBTA_GATT_CHAR_PRES;
+
+#define BTA_GATT_CLT_CONFIG_NONE GATT_CLT_CONFIG_NONE /* 0x0000    */
+#define BTA_GATT_CLT_CONFIG_NOTIFICATION \
+  GATT_CLT_CONFIG_NOTIFICATION                                    /* 0x0001 */
+#define BTA_GATT_CLT_CONFIG_INDICATION GATT_CLT_CONFIG_INDICATION /* 0x0002 */
+typedef uint16_t tBTA_GATT_CLT_CHAR_CONFIG;
+
+/* characteristic descriptor: server configuration value
+*/
+#define BTA_GATT_SVR_CONFIG_NONE GATT_SVR_CONFIG_NONE           /* 0x0000 */
+#define BTA_GATT_SVR_CONFIG_BROADCAST GATT_SVR_CONFIG_BROADCAST /*  0x0001 */
+typedef uint16_t tBTA_GATT_SVR_CHAR_CONFIG;
+
+/* Characteristic Aggregate Format attribute value
+*/
+#define BTA_GATT_AGGR_HANDLE_NUM_MAX 10
+typedef struct {
+  uint8_t num_handle;
+  uint16_t handle_list[BTA_GATT_AGGR_HANDLE_NUM_MAX];
+} tBTA_GATT_CHAR_AGGRE;
+typedef tGATT_VALID_RANGE tBTA_GATT_VALID_RANGE;
+
+typedef struct {
+  uint16_t len;
+  uint8_t* p_value;
+} tBTA_GATT_UNFMT;
+
+#define BTA_GATT_MAX_ATTR_LEN GATT_MAX_ATTR_LEN
+
+#define BTA_GATTC_TYPE_WRITE GATT_WRITE
+#define BTA_GATTC_TYPE_WRITE_NO_RSP GATT_WRITE_NO_RSP
+typedef uint8_t tBTA_GATTC_WRITE_TYPE;
+
+#define BTA_GATT_CONN_UNKNOWN 0
+#define BTA_GATT_CONN_L2C_FAILURE \
+  GATT_CONN_L2C_FAILURE /* general l2cap resource failure */
+#define BTA_GATT_CONN_TIMEOUT GATT_CONN_TIMEOUT /* 0x08 connection timeout  */
+#define BTA_GATT_CONN_TERMINATE_PEER_USER \
+  GATT_CONN_TERMINATE_PEER_USER /* 0x13 connection terminate by peer user  */
+#define BTA_GATT_CONN_TERMINATE_LOCAL_HOST \
+  GATT_CONN_TERMINATE_LOCAL_HOST /* 0x16 connectionterminated by local host */
+#define BTA_GATT_CONN_FAIL_ESTABLISH \
+  GATT_CONN_FAIL_ESTABLISH /* 0x03E connection fail to establish  */
+#define BTA_GATT_CONN_LMP_TIMEOUT \
+  GATT_CONN_LMP_TIMEOUT /* 0x22 connection fail for LMP response tout */
+#define BTA_GATT_CONN_CANCEL \
+  GATT_CONN_CANCEL                /* 0x0100 L2CAP connection cancelled  */
+#define BTA_GATT_CONN_NONE 0x0101 /* 0x0101 no connection to cancel  */
+typedef uint16_t tBTA_GATT_REASON;
+
+#define BTA_GATTC_MULTI_MAX GATT_MAX_READ_MULTI_HANDLES
+
+typedef struct {
+  uint8_t num_attr;
+  uint16_t handles[BTA_GATTC_MULTI_MAX];
+} tBTA_GATTC_MULTI;
+
+#define BTA_GATT_AUTH_REQ_NONE GATT_AUTH_REQ_NONE
+#define BTA_GATT_AUTH_REQ_NO_MITM \
+  GATT_AUTH_REQ_NO_MITM /* unauthenticated encryption */
+#define BTA_GATT_AUTH_REQ_MITM                   \
+  GATT_AUTH_REQ_MITM /* authenticated encryption \
+                        */
+#define BTA_GATT_AUTH_REQ_SIGNED_NO_MITM GATT_AUTH_REQ_SIGNED_NO_MITM
+#define BTA_GATT_AUTH_REQ_SIGNED_MITM GATT_AUTH_REQ_SIGNED_MITM
+
+typedef tGATT_AUTH_REQ tBTA_GATT_AUTH_REQ;
+
+enum {
+  BTA_GATTC_ATTR_TYPE_INCL_SRVC,
+  BTA_GATTC_ATTR_TYPE_CHAR,
+  BTA_GATTC_ATTR_TYPE_CHAR_DESCR,
+  BTA_GATTC_ATTR_TYPE_SRVC
+};
+typedef uint8_t tBTA_GATTC_ATTR_TYPE;
+
+typedef struct {
+  tBT_UUID uuid;
+  uint16_t s_handle;
+  uint16_t e_handle; /* used for service only */
+  uint8_t attr_type;
+  uint8_t id;
+  uint8_t prop;              /* used when attribute type is characteristic */
+  bool is_primary;           /* used when attribute type is service */
+  uint16_t incl_srvc_handle; /* used when attribute type is included service */
+} tBTA_GATTC_NV_ATTR;
+
+/* callback data structure */
+typedef struct {
+  tBTA_GATT_STATUS status;
+  tBTA_GATTC_IF client_if;
+  tBT_UUID app_uuid;
+} tBTA_GATTC_REG;
+
+typedef struct {
+  uint16_t conn_id;
+  tBTA_GATT_STATUS status;
+  uint16_t handle;
+  uint16_t len;
+  uint8_t value[BTA_GATT_MAX_ATTR_LEN];
+} tBTA_GATTC_READ;
+
+typedef struct {
+  uint16_t conn_id;
+  tBTA_GATT_STATUS status;
+  uint16_t handle;
+} tBTA_GATTC_WRITE;
+
+typedef struct {
+  uint16_t conn_id;
+  tBTA_GATT_STATUS status;
+} tBTA_GATTC_EXEC_CMPL;
+
+typedef struct {
+  uint16_t conn_id;
+  tBTA_GATT_STATUS status;
+} tBTA_GATTC_SEARCH_CMPL;
+
+typedef struct {
+  uint16_t conn_id;
+  tBTA_GATT_ID service_uuid;
+} tBTA_GATTC_SRVC_RES;
+
+typedef struct {
+  uint16_t conn_id;
+  tBTA_GATT_STATUS status;
+  uint16_t mtu;
+} tBTA_GATTC_CFG_MTU;
+
+typedef struct {
+  tBTA_GATT_STATUS status;
+  uint16_t conn_id;
+  tBTA_GATTC_IF client_if;
+  BD_ADDR remote_bda;
+  tBTA_TRANSPORT transport;
+  uint16_t mtu;
+} tBTA_GATTC_OPEN;
+
+typedef struct {
+  tBTA_GATT_STATUS status;
+  uint16_t conn_id;
+  tBTA_GATTC_IF client_if;
+  BD_ADDR remote_bda;
+  tBTA_GATT_REASON reason; /* disconnect reason code, not useful when connect
+                              event is reported */
+} tBTA_GATTC_CLOSE;
+
+typedef struct {
+  uint16_t conn_id;
+  BD_ADDR bda;
+  uint16_t handle;
+  uint16_t len;
+  uint8_t value[BTA_GATT_MAX_ATTR_LEN];
+  bool is_notify;
+} tBTA_GATTC_NOTIFY;
+
+typedef struct {
+  uint16_t conn_id;
+  bool congested; /* congestion indicator */
+} tBTA_GATTC_CONGEST;
+
+typedef struct {
+  tBTA_GATT_STATUS status;
+  tBTA_GATTC_IF client_if;
+  uint16_t conn_id;
+  BD_ADDR remote_bda;
+} tBTA_GATTC_OPEN_CLOSE;
+
+typedef struct {
+  tBTA_GATTC_IF client_if;
+  BD_ADDR remote_bda;
+} tBTA_GATTC_ENC_CMPL_CB;
+
+typedef union {
+  tBTA_GATT_STATUS status;
+
+  tBTA_GATTC_SEARCH_CMPL search_cmpl; /* discovery complete */
+  tBTA_GATTC_SRVC_RES srvc_res;       /* discovery result */
+  tBTA_GATTC_REG reg_oper;            /* registration data */
+  tBTA_GATTC_OPEN open;
+  tBTA_GATTC_CLOSE close;
+  tBTA_GATTC_READ read;           /* read attribute/descriptor data */
+  tBTA_GATTC_WRITE write;         /* write complete data */
+  tBTA_GATTC_EXEC_CMPL exec_cmpl; /*  execute complete */
+  tBTA_GATTC_NOTIFY notify;       /* notification/indication event data */
+  tBTA_GATTC_ENC_CMPL_CB enc_cmpl;
+  BD_ADDR remote_bda;         /* service change event */
+  tBTA_GATTC_CFG_MTU cfg_mtu; /* configure MTU operation */
+  tBTA_GATTC_CONGEST congest;
+} tBTA_GATTC;
+
+/* GATTC enable callback function */
+typedef void(tBTA_GATTC_ENB_CBACK)(tBTA_GATT_STATUS status);
+
+/* Client callback function */
+typedef void(tBTA_GATTC_CBACK)(tBTA_GATTC_EVT event, tBTA_GATTC* p_data);
+
+/* GATT Server Data Structure */
+/* Server callback function events */
+#define BTA_GATTS_REG_EVT 0
+#define BTA_GATTS_READ_CHARACTERISTIC_EVT \
+  GATTS_REQ_TYPE_READ_CHARACTERISTIC                                 /* 1 */
+#define BTA_GATTS_READ_DESCRIPTOR_EVT GATTS_REQ_TYPE_READ_DESCRIPTOR /* 2 */
+#define BTA_GATTS_WRITE_CHARACTERISTIC_EVT \
+  GATTS_REQ_TYPE_WRITE_CHARACTERISTIC                                  /* 3 */
+#define BTA_GATTS_WRITE_DESCRIPTOR_EVT GATTS_REQ_TYPE_WRITE_DESCRIPTOR /* 4 */
+#define BTA_GATTS_EXEC_WRITE_EVT GATTS_REQ_TYPE_WRITE_EXEC             /* 5 */
+#define BTA_GATTS_MTU_EVT GATTS_REQ_TYPE_MTU                           /* 6 */
+#define BTA_GATTS_CONF_EVT GATTS_REQ_TYPE_CONF                         /* 7 */
+#define BTA_GATTS_DEREG_EVT 8
+#define BTA_GATTS_DELELTE_EVT 11
+#define BTA_GATTS_STOP_EVT 13
+#define BTA_GATTS_CONNECT_EVT 14
+#define BTA_GATTS_DISCONNECT_EVT 15
+#define BTA_GATTS_OPEN_EVT 16
+#define BTA_GATTS_CANCEL_OPEN_EVT 17
+#define BTA_GATTS_CLOSE_EVT 18
+#define BTA_GATTS_CONGEST_EVT 20
+
+typedef uint8_t tBTA_GATTS_EVT;
+typedef tGATT_IF tBTA_GATTS_IF;
+
+/* Attribute permissions
+*/
+#define BTA_GATT_PERM_READ GATT_PERM_READ /* bit 0 -  0x0001 */
+#define BTA_GATT_PERM_READ_ENCRYPTED \
+  GATT_PERM_READ_ENCRYPTED /* bit 1 -  0x0002 */
+#define BTA_GATT_PERM_READ_ENC_MITM \
+  GATT_PERM_READ_ENC_MITM                   /* bit 2 -  0x0004 */
+#define BTA_GATT_PERM_WRITE GATT_PERM_WRITE /* bit 4 -  0x0010 */
+#define BTA_GATT_PERM_WRITE_ENCRYPTED \
+  GATT_PERM_WRITE_ENCRYPTED /* bit 5 -  0x0020 */
+#define BTA_GATT_PERM_WRITE_ENC_MITM \
+  GATT_PERM_WRITE_ENC_MITM /* bit 6 -  0x0040 */
+#define BTA_GATT_PERM_WRITE_SIGNED          \
+  GATT_PERM_WRITE_SIGNED /* bit 7 -  0x0080 \
+                            */
+#define BTA_GATT_PERM_WRITE_SIGNED_MITM \
+  GATT_PERM_WRITE_SIGNED_MITM /* bit 8 -  0x0100 */
+typedef uint16_t tBTA_GATT_PERM;
+
+#define BTA_GATTS_INVALID_APP 0xff
+
+#define BTA_GATTS_INVALID_IF 0
+
+/* definition of characteristic properties */
+#define BTA_GATT_CHAR_PROP_BIT_BROADCAST                                    \
+  GATT_CHAR_PROP_BIT_BROADCAST                                      /* 0x01 \
+                                                                       */
+#define BTA_GATT_CHAR_PROP_BIT_READ GATT_CHAR_PROP_BIT_READ         /* 0x02 */
+#define BTA_GATT_CHAR_PROP_BIT_WRITE_NR GATT_CHAR_PROP_BIT_WRITE_NR /* 0x04 */
+#define BTA_GATT_CHAR_PROP_BIT_WRITE GATT_CHAR_PROP_BIT_WRITE       /* 0x08 */
+#define BTA_GATT_CHAR_PROP_BIT_NOTIFY GATT_CHAR_PROP_BIT_NOTIFY     /* 0x10 */
+#define BTA_GATT_CHAR_PROP_BIT_INDICATE GATT_CHAR_PROP_BIT_INDICATE /* 0x20 */
+#define BTA_GATT_CHAR_PROP_BIT_AUTH GATT_CHAR_PROP_BIT_AUTH         /* 0x40 */
+#define BTA_GATT_CHAR_PROP_BIT_EXT_PROP GATT_CHAR_PROP_BIT_EXT_PROP /* 0x80 */
+typedef uint8_t tBTA_GATT_CHAR_PROP;
+
+#ifndef BTA_GATTC_CHAR_DESCR_MAX
+#define BTA_GATTC_CHAR_DESCR_MAX 7
+#endif
+
+/***********************  NV callback Data Definitions   **********************
+*/
+typedef struct {
+  tBT_UUID app_uuid128;
+  tBT_UUID svc_uuid;
+  uint16_t svc_inst;
+  uint16_t s_handle;
+  uint16_t e_handle;
+  bool is_primary; /* primary service or secondary */
+} tBTA_GATTS_HNDL_RANGE;
+
+#define BTA_GATTS_SRV_CHG_CMD_ADD_CLIENT GATTS_SRV_CHG_CMD_ADD_CLIENT
+#define BTA_GATTS_SRV_CHG_CMD_UPDATE_CLIENT GATTS_SRV_CHG_CMD_UPDATE_CLIENT
+#define BTA_GATTS_SRV_CHG_CMD_REMOVE_CLIENT GATTS_SRV_CHG_CMD_REMOVE_CLIENT
+#define BTA_GATTS_SRV_CHG_CMD_READ_NUM_CLENTS GATTS_SRV_CHG_CMD_READ_NUM_CLENTS
+#define BTA_GATTS_SRV_CHG_CMD_READ_CLENT GATTS_SRV_CHG_CMD_READ_CLENT
+typedef tGATTS_SRV_CHG_CMD tBTA_GATTS_SRV_CHG_CMD;
+
+typedef tGATTS_SRV_CHG tBTA_GATTS_SRV_CHG;
+typedef tGATTS_SRV_CHG_REQ tBTA_GATTS_SRV_CHG_REQ;
+typedef tGATTS_SRV_CHG_RSP tBTA_GATTS_SRV_CHG_RSP;
+
+#define BTA_GATT_TRANSPORT_LE GATT_TRANSPORT_LE
+#define BTA_GATT_TRANSPORT_BR_EDR GATT_TRANSPORT_BR_EDR
+#define BTA_GATT_TRANSPORT_LE_BR_EDR GATT_TRANSPORT_LE_BR_EDR
+typedef uint8_t tBTA_GATT_TRANSPORT;
+
+/* attribute value */
+typedef tGATT_VALUE tBTA_GATT_VALUE;
+
+/* attribute response data */
+typedef tGATTS_RSP tBTA_GATTS_RSP;
+
+/* attribute request data from the client */
+#define BTA_GATT_PREP_WRITE_CANCEL 0x00
+#define BTA_GATT_PREP_WRITE_EXEC 0x01
+typedef tGATT_EXEC_FLAG tBTA_GATT_EXEC_FLAG;
+
+/* read request always based on UUID */
+typedef tGATT_READ_REQ tTA_GBATT_READ_REQ;
+
+/* write request data */
+typedef tGATT_WRITE_REQ tBTA_GATT_WRITE_REQ;
+
+/* callback data for server access request from client */
+typedef tGATTS_DATA tBTA_GATTS_REQ_DATA;
+
+typedef struct {
+  tBTA_GATT_STATUS status;
+  BD_ADDR remote_bda;
+  uint32_t trans_id;
+  uint16_t conn_id;
+  tBTA_GATTS_REQ_DATA* p_data;
+} tBTA_GATTS_REQ;
+
+typedef struct {
+  tBTA_GATTS_IF server_if;
+  tBTA_GATT_STATUS status;
+  tBT_UUID uuid;
+} tBTA_GATTS_REG_OPER;
+
+typedef struct {
+  tBTA_GATTS_IF server_if;
+  uint16_t service_id;
+  uint16_t svc_instance;
+  bool is_primary;
+  tBTA_GATT_STATUS status;
+  tBT_UUID uuid;
+} tBTA_GATTS_CREATE;
+
+typedef struct {
+  tBTA_GATTS_IF server_if;
+  uint16_t service_id;
+  tBTA_GATT_STATUS status;
+} tBTA_GATTS_SRVC_OPER;
+
+typedef struct {
+  tBTA_GATTS_IF server_if;
+  BD_ADDR remote_bda;
+  uint16_t conn_id;
+  tBTA_GATT_REASON reason; /* report disconnect reason */
+  tBTA_GATT_TRANSPORT transport;
+} tBTA_GATTS_CONN;
+
+typedef struct {
+  uint16_t conn_id;
+  bool congested; /* report channel congestion indicator */
+} tBTA_GATTS_CONGEST;
+
+typedef struct {
+  uint16_t conn_id;        /* connection ID */
+  tBTA_GATT_STATUS status; /* notification/indication status */
+} tBTA_GATTS_CONF;
+
+/* GATTS callback data */
+typedef union {
+  tBTA_GATTS_REG_OPER reg_oper;
+  tBTA_GATTS_CREATE create;
+  tBTA_GATTS_SRVC_OPER srvc_oper;
+  tBTA_GATT_STATUS status; /* BTA_GATTS_LISTEN_EVT */
+  tBTA_GATTS_REQ req_data;
+  tBTA_GATTS_CONN conn;       /* BTA_GATTS_CONN_EVT */
+  tBTA_GATTS_CONGEST congest; /* BTA_GATTS_CONGEST_EVT callback data */
+  tBTA_GATTS_CONF confirm;    /* BTA_GATTS_CONF_EVT callback data */
+} tBTA_GATTS;
+
+/* GATTS enable callback function */
+typedef void(tBTA_GATTS_ENB_CBACK)(tBTA_GATT_STATUS status);
+
+/* Server callback function */
+typedef void(tBTA_GATTS_CBACK)(tBTA_GATTS_EVT event, tBTA_GATTS* p_data);
+
+typedef struct {
+  tBT_UUID uuid;
+  bool is_primary;
+  uint16_t handle;
+  uint16_t s_handle;
+  uint16_t e_handle;
+  list_t* characteristics; /* list of tBTA_GATTC_CHARACTERISTIC */
+  list_t* included_svc;    /* list of tBTA_GATTC_INCLUDED_SVC */
+} __attribute__((packed)) tBTA_GATTC_SERVICE;
+
+typedef struct {
+  tBT_UUID uuid;
+  uint16_t handle;
+  tBTA_GATT_CHAR_PROP properties;
+  tBTA_GATTC_SERVICE* service; /* owning service*/
+  list_t* descriptors;         /* list of tBTA_GATTC_DESCRIPTOR */
+} __attribute__((packed)) tBTA_GATTC_CHARACTERISTIC;
+
+typedef struct {
+  tBT_UUID uuid;
+  uint16_t handle;
+  tBTA_GATTC_CHARACTERISTIC* characteristic; /* owning characteristic */
+} __attribute__((packed)) tBTA_GATTC_DESCRIPTOR;
+
+typedef struct {
+  tBT_UUID uuid;
+  uint16_t handle;
+  tBTA_GATTC_SERVICE* owning_service; /* owning service*/
+  tBTA_GATTC_SERVICE* included_service;
+} __attribute__((packed)) tBTA_GATTC_INCLUDED_SVC;
+
+/*****************************************************************************
+ *  External Function Declarations
+ ****************************************************************************/
+
+/**************************
+ *  Client Functions
+ **************************/
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_Disable
+ *
+ * Description      This function is called to disable the GATTC module
+ *
+ * Parameters       None.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_Disable(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_AppRegister
+ *
+ * Description      This function is called to register application callbacks
+ *                    with BTA GATTC module.
+ *
+ * Parameters       p_app_uuid - applicaiton UUID
+ *                  p_client_cb - pointer to the application callback function.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_AppRegister(tBT_UUID* p_app_uuid,
+                                  tBTA_GATTC_CBACK* p_client_cb);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_AppDeregister
+ *
+ * Description      This function is called to deregister an application
+ *                  from BTA GATTC module.
+ *
+ * Parameters       client_if - client interface identifier.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_AppDeregister(tBTA_GATTC_IF client_if);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_Open
+ *
+ * Description      Open a direct connection or add a background auto connection
+ *                  bd address
+ *
+ * Parameters       client_if: server interface.
+ *                  remote_bda: remote device BD address.
+ *                  is_direct: direct connection or background auto connection
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_Open(tBTA_GATTC_IF client_if, BD_ADDR remote_bda,
+                           bool is_direct, tBTA_GATT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_CancelOpen
+ *
+ * Description      Open a direct connection or add a background auto connection
+ *                  bd address
+ *
+ * Parameters       client_if: server interface.
+ *                  remote_bda: remote device BD address.
+ *                  is_direct: direct connection or background auto connection
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_CancelOpen(tBTA_GATTC_IF client_if, BD_ADDR remote_bda,
+                                 bool is_direct);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_Close
+ *
+ * Description      Close a connection to a GATT server.
+ *
+ * Parameters       conn_id: connectino ID to be closed.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_Close(uint16_t conn_id);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_ServiceSearchRequest
+ *
+ * Description      This function is called to request a GATT service discovery
+ *                  on a GATT server. This function report service search result
+ *                  by a callback event, and followed by a service search
+ *                  complete event.
+ *
+ * Parameters       conn_id: connection ID.
+ *                  p_srvc_uuid: a UUID of the service application is interested
+ *                               in. If Null, discover for all services.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_ServiceSearchRequest(uint16_t conn_id,
+                                           tBT_UUID* p_srvc_uuid);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_GetServices
+ *
+ * Description      This function is called to find the services on the given
+ *                  server.
+ *
+ * Parameters       conn_id: connection ID which identify the server.
+ *
+ * Returns          returns list_t of tBTA_GATTC_SERVICE or NULL.
+ *
+ ******************************************************************************/
+extern const list_t* BTA_GATTC_GetServices(uint16_t conn_id);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_GetCharacteristic
+ *
+ * Description      This function is called to find the characteristic on the
+ *                  given server.
+ *
+ * Parameters       conn_id: connection ID which identify the server.
+ *                  handle: characteristic handle
+ *
+ * Returns          returns pointer to tBTA_GATTC_CHARACTERISTIC or NULL.
+ *
+ ******************************************************************************/
+extern const tBTA_GATTC_CHARACTERISTIC* BTA_GATTC_GetCharacteristic(
+    uint16_t conn_id, uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_GetDescriptor
+ *
+ * Description      This function is called to find the characteristic on the
+ *                  given server.
+ *
+ * Parameters       conn_id: connection ID which identify the server.
+ *                  handle: descriptor handle
+ *
+ * Returns          returns pointer to tBTA_GATTC_DESCRIPTOR or NULL.
+ *
+ ******************************************************************************/
+extern const tBTA_GATTC_DESCRIPTOR* BTA_GATTC_GetDescriptor(uint16_t conn_id,
+                                                            uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_GetGattDb
+ *
+ * Description      This function is called to get gatt db.
+ *
+ * Parameters       conn_id: connection ID which identify the server.
+ *                  db: output parameter which will contain gatt db copy.
+ *                      Caller is responsible for freeing it.
+ *                  count: number of elements in db.
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_GetGattDb(uint16_t conn_id, uint16_t start_handle,
+                                uint16_t end_handle, btgatt_db_element_t** db,
+                                int* count);
+
+typedef void (*GATT_READ_OP_CB)(uint16_t conn_id, tGATT_STATUS status,
+                                uint16_t handle, uint16_t len, uint8_t* value,
+                                void* data);
+typedef void (*GATT_WRITE_OP_CB)(uint16_t conn_id, tGATT_STATUS status,
+                                 uint16_t handle, void* data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_ReadCharacteristic
+ *
+ * Description      This function is called to read a characteristics value
+ *
+ * Parameters       conn_id - connectino ID.
+ *                  handle - characteritic handle to read.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_GATTC_ReadCharacteristic(uint16_t conn_id, uint16_t handle,
+                                  tBTA_GATT_AUTH_REQ auth_req,
+                                  GATT_READ_OP_CB callback, void* cb_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_ReadCharDescr
+ *
+ * Description      This function is called to read a descriptor value.
+ *
+ * Parameters       conn_id - connection ID.
+ *                  handle - descriptor handle to read.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_GATTC_ReadCharDescr(uint16_t conn_id, uint16_t handle,
+                             tBTA_GATT_AUTH_REQ auth_req,
+                             GATT_READ_OP_CB callback, void* cb_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_WriteCharValue
+ *
+ * Description      This function is called to write characteristic value.
+ *
+ * Parameters       conn_id - connection ID.
+ *                  handle - characteristic handle to write.
+ *                  write_type - type of write.
+ *                  value - the value to be written.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_GATTC_WriteCharValue(uint16_t conn_id, uint16_t handle,
+                              tBTA_GATTC_WRITE_TYPE write_type,
+                              vector<uint8_t> value,
+                              tBTA_GATT_AUTH_REQ auth_req,
+                              GATT_WRITE_OP_CB callback, void* cb_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_WriteCharDescr
+ *
+ * Description      This function is called to write descriptor value.
+ *
+ * Parameters       conn_id - connection ID
+ *                  handle - descriptor handle to write.
+ *                  value - the value to be written.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTA_GATTC_WriteCharDescr(uint16_t conn_id, uint16_t handle,
+                              vector<uint8_t> value,
+                              tBTA_GATT_AUTH_REQ auth_req,
+                              GATT_WRITE_OP_CB callback, void* cb_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_SendIndConfirm
+ *
+ * Description      This function is called to send handle value confirmation.
+ *
+ * Parameters       conn_id - connection ID.
+ *                  handle - characteristic handle to confirm.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_SendIndConfirm(uint16_t conn_id, uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_RegisterForNotifications
+ *
+ * Description      This function is called to register for notification of a
+ *                  service.
+ *
+ * Parameters       client_if - client interface.
+ *                  remote_bda - target GATT server.
+ *                  handle - GATT characteristic handle.
+ *
+ * Returns          OK if registration succeed, otherwise failed.
+ *
+ ******************************************************************************/
+extern tBTA_GATT_STATUS BTA_GATTC_RegisterForNotifications(
+    tBTA_GATTC_IF client_if, const BD_ADDR remote_bda, uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_DeregisterForNotifications
+ *
+ * Description      This function is called to de-register for notification of a
+ *                  service.
+ *
+ * Parameters       client_if - client interface.
+ *                  remote_bda - target GATT server.
+ *                  handle - GATT characteristic handle.
+ *
+ * Returns          OK if deregistration succeed, otherwise failed.
+ *
+ ******************************************************************************/
+extern tBTA_GATT_STATUS BTA_GATTC_DeregisterForNotifications(
+    tBTA_GATTC_IF client_if, const BD_ADDR remote_bda, uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_PrepareWrite
+ *
+ * Description      This function is called to prepare write a characteristic
+ *                  value.
+ *
+ * Parameters       conn_id - connection ID.
+ *                  handle - GATT characteritic handle.
+ *                  offset - offset of the write value.
+ *                  value - the value to be written.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_PrepareWrite(uint16_t conn_id, uint16_t handle,
+                                   uint16_t offset, vector<uint8_t> value,
+                                   tBTA_GATT_AUTH_REQ auth_req,
+                                   GATT_WRITE_OP_CB callback, void* cb_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_ExecuteWrite
+ *
+ * Description      This function is called to execute write a prepare write
+ *                  sequence.
+ *
+ * Parameters       conn_id - connection ID.
+ *                    is_execute - execute or cancel.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_ExecuteWrite(uint16_t conn_id, bool is_execute);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_ReadMultiple
+ *
+ * Description      This function is called to read multiple characteristic or
+ *                  characteristic descriptors.
+ *
+ * Parameters       conn_id - connectino ID.
+ *                    p_read_multi - read multiple parameters.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_ReadMultiple(uint16_t conn_id,
+                                   tBTA_GATTC_MULTI* p_read_multi,
+                                   tBTA_GATT_AUTH_REQ auth_req);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_Refresh
+ *
+ * Description      Refresh the server cache of the remote device
+ *
+ * Parameters       remote_bda: remote device BD address.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_Refresh(const BD_ADDR remote_bda);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTC_ConfigureMTU
+ *
+ * Description      Configure the MTU size in the GATT channel. This can be done
+ *                  only once per connection.
+ *
+ * Parameters       conn_id: connection ID.
+ *                  mtu: desired MTU size to use.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_ConfigureMTU(uint16_t conn_id, uint16_t mtu);
+
+/*******************************************************************************
+ *  BTA GATT Server API
+ *******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_Init
+ *
+ * Description      This function is called to initalize GATTS module
+ *
+ * Parameters       None
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_Init();
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_Disable
+ *
+ * Description      This function is called to disable GATTS module
+ *
+ * Parameters       None.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_Disable(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_AppRegister
+ *
+ * Description      This function is called to register application callbacks
+ *                    with BTA GATTS module.
+ *
+ * Parameters       p_app_uuid - applicaiton UUID
+ *                  p_cback - pointer to the application callback function.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_AppRegister(tBT_UUID* p_app_uuid,
+                                  tBTA_GATTS_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_AppDeregister
+ *
+ * Description      De-register with BTA GATT Server.
+ *
+ * Parameters       server_if: server interface
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_AppDeregister(tBTA_GATTS_IF server_if);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_AddService
+ *
+ * Description      Add the given |service| and all included elements to the
+ *                  GATT database. a |BTA_GATTS_ADD_SRVC_EVT| is triggered to
+ *                  report the status and attribute handles.
+ *
+ * Parameters       server_if: server interface.
+ *                  service: pointer to vector describing service.
+ *
+ * Returns          Returns |BTA_GATT_OK| on success or |BTA_GATT_ERROR| if the
+ *                  service cannot be added.
+ *
+ ******************************************************************************/
+extern uint16_t BTA_GATTS_AddService(tBTA_GATTS_IF server_if,
+                                     vector<btgatt_db_element_t>& service);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_DeleteService
+ *
+ * Description      This function is called to delete a service. When this is
+ *                  done, a callback event BTA_GATTS_DELETE_EVT is report with
+ *                  the status.
+ *
+ * Parameters       service_id: service_id to be deleted.
+ *
+ * Returns          returns none.
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_DeleteService(uint16_t service_id);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_StopService
+ *
+ * Description      This function is called to stop a service.
+ *
+ * Parameters       service_id - service to be topped.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_StopService(uint16_t service_id);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_HandleValueIndication
+ *
+ * Description      This function is called to read a characteristics
+ *                  descriptor.
+ *
+ * Parameters       conn_id - connection identifier.
+ *                  attr_id - attribute ID to indicate.
+ *                  value - data to indicate.
+ *                  need_confirm - if this indication expects a confirmation or
+ *                                 not.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_HandleValueIndication(uint16_t conn_id, uint16_t attr_id,
+                                            vector<uint8_t> value,
+                                            bool need_confirm);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_SendRsp
+ *
+ * Description      This function is called to send a response to a request.
+ *
+ * Parameters       conn_id - connection identifier.
+ *                  trans_id - transaction ID.
+ *                  status - response status
+ *                  p_msg - response data.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_SendRsp(uint16_t conn_id, uint32_t trans_id,
+                              tBTA_GATT_STATUS status, tBTA_GATTS_RSP* p_msg);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_Open
+ *
+ * Description      Open a direct open connection or add a background auto
+ *                  connection bd address
+ *
+ * Parameters       server_if: server interface.
+ *                  remote_bda: remote device BD address.
+ *                  is_direct: direct connection or background auto connection
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_Open(tBTA_GATTS_IF server_if, BD_ADDR remote_bda,
+                           bool is_direct, tBTA_GATT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_CancelOpen
+ *
+ * Description      Cancel a direct open connection or remove a background auto
+ *                  connection bd address
+ *
+ * Parameters       server_if: server interface.
+ *                  remote_bda: remote device BD address.
+ *                  is_direct: direct connection or background auto connection
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_CancelOpen(tBTA_GATTS_IF server_if, BD_ADDR remote_bda,
+                                 bool is_direct);
+
+/*******************************************************************************
+ *
+ * Function         BTA_GATTS_Close
+ *
+ * Description      Close a connection  a remote device.
+ *
+ * Parameters       conn_id: connectino ID to be closed.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_Close(uint16_t conn_id);
+
+#endif /* BTA_GATT_API_H */
diff --git a/bt/bta/include/bta_gatts_co.h b/bt/bta/include/bta_gatts_co.h
new file mode 100644
index 0000000..ed7f1c8
--- /dev/null
+++ b/bt/bta/include/bta_gatts_co.h
@@ -0,0 +1,90 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2010-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 is the interface file for BTA GATT server call-out functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_GATTS_CO_H
+#define BTA_GATTS_CO_H
+
+#include "bta_gatt_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_gatts_co_update_handle_range
+ *
+ * Description      This callout function is executed by GATTS when a GATT
+ *                  server handle range ios to be added or removed.
+ *
+ * Parameter        is_add: true is to add a handle range; otherwise is to
+ *                          delete.
+ *                  p_hndl_range: handle range.
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+extern void bta_gatts_co_update_handle_range(
+    bool is_add, tBTA_GATTS_HNDL_RANGE* p_hndl_range);
+
+/*******************************************************************************
+ *
+ * Function         bta_gatts_co_srv_chg
+ *
+ * Description      This call-out is to read/write/remove service change related
+ *                  informaiton. The request consists of the cmd and p_req and
+ *                  the response is returned in p_rsp
+ *
+ * Parameter        cmd - request command
+ *                  p_req - request paramters
+ *                  p_rsp - response data for the request
+ *
+ * Returns          true - if the request is processed successfully and
+ *                         the response is returned in p_rsp.
+ *                  false - if the request can not be processed
+ *
+ ******************************************************************************/
+extern bool bta_gatts_co_srv_chg(tBTA_GATTS_SRV_CHG_CMD cmd,
+                                 tBTA_GATTS_SRV_CHG_REQ* p_req,
+                                 tBTA_GATTS_SRV_CHG_RSP* p_rsp);
+
+/*******************************************************************************
+ *
+ * Function         bta_gatts_co_load_handle_range
+ *
+ * Description      This callout function is executed by GATTS when a GATT
+ *                  server handle range is requested to be loaded from NV.
+ *
+ * Parameter
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+extern bool bta_gatts_co_load_handle_range(uint8_t index,
+                                           tBTA_GATTS_HNDL_RANGE* p_handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_GATTS_CO_H */
diff --git a/bt/bta/include/bta_hf_client_api.h b/bt/bta/include/bta_hf_client_api.h
new file mode 100644
index 0000000..bc107e6
--- /dev/null
+++ b/bt/bta/include/bta_hf_client_api.h
@@ -0,0 +1,377 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-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 is the public interface file for the handsfree (HF role) subsystem
+ *
+ ******************************************************************************/
+#ifndef BTA_HF_CLIENT_API_H
+#define BTA_HF_CLIENT_API_H
+
+#include "bta_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+ *  Constants and data types
+ ****************************************************************************/
+
+/* HFP peer (AG) features*/
+#define BTA_HF_CLIENT_PEER_FEAT_3WAY 0x00000001 /* Three-way calling */
+#define BTA_HF_CLIENT_PEER_FEAT_ECNR \
+  0x00000002 /* Echo cancellation and/or noise reduction */
+#define BTA_HF_CLIENT_PEER_FEAT_VREC 0x00000004 /* Voice recognition */
+#define BTA_HF_CLIENT_PEER_INBAND 0x00000008    /* In-band ring tone */
+#define BTA_HF_CLIENT_PEER_VTAG \
+  0x00000010 /* Attach a phone number to a voice tag */
+#define BTA_HF_CLIENT_PEER_REJECT \
+  0x00000020                              /* Ability to reject incoming call */
+#define BTA_HF_CLIENT_PEER_ECS 0x00000040 /* Enhanced Call Status */
+#define BTA_HF_CLIENT_PEER_ECC 0x00000080 /* Enhanced Call Control */
+#define BTA_HF_CLIENT_PEER_EXTERR 0x00000100 /* Extended error codes */
+#define BTA_HF_CLIENT_PEER_CODEC 0x00000200  /* Codec Negotiation */
+
+typedef uint16_t tBTA_HF_CLIENT_PEER_FEAT;
+
+/* HFP HF features */
+#define BTA_HF_CLIENT_FEAT_ECNR \
+  0x00000001 /* Echo cancellation and/or noise reduction */
+#define BTA_HF_CLIENT_FEAT_3WAY \
+  0x00000002 /* Call waiting and three-way calling */
+#define BTA_HF_CLIENT_FEAT_CLI \
+  0x00000004 /* Caller ID presentation capability */
+#define BTA_HF_CLIENT_FEAT_VREC 0x00000008  /* Voice recognition activation */
+#define BTA_HF_CLIENT_FEAT_VOL 0x00000010   /* Remote volume control */
+#define BTA_HF_CLIENT_FEAT_ECS 0x00000020   /* Enhanced Call Status */
+#define BTA_HF_CLIENT_FEAT_ECC 0x00000040   /* Enhanced Call Control */
+#define BTA_HF_CLIENT_FEAT_CODEC 0x00000080 /* Codec Negotiation */
+
+/* HFP HF extended call handling - masks not related to any spec */
+#define BTA_HF_CLIENT_CHLD_REL \
+  0x00000001 /* 0  Release waiting call or held calls */
+#define BTA_HF_CLIENT_CHLD_REL_ACC                                             \
+  0x00000002 /* 1  Release active calls and accept other (waiting or held) cal \
+                */
+#define BTA_HF_CLIENT_CHLD_REL_X 0x00000004 /* 1x Release x call*/
+#define BTA_HF_CLIENT_CHLD_HOLD_ACC \
+  0x00000008 /* 2  Active calls on hold and accept other call */
+#define BTA_HF_CLIENT_CHLD_PRIV_X \
+  0x00000010 /* 2x Active multiparty call on hold except call x */
+#define BTA_HF_CLIENT_CHLD_MERGE               \
+  0x00000020 /* 3  Add held call to multiparty \
+                */
+#define BTA_HF_CLIENT_CHLD_MERGE_DETACH \
+  0x00000040 /* 4  Add held call to multiparty */
+
+typedef uint16_t tBTA_HF_CLIENT_CHLD_FEAT;
+
+/* HFP AG errors ot OK sent to HF Unit */
+#define BTA_HF_CLIENT_AT_RESULT_OK 0
+#define BTA_HF_CLIENT_AT_RESULT_ERROR 1
+#define BTA_HF_CLIENT_AT_RESULT_NO_CARRIER 2
+#define BTA_HF_CLIENT_AT_RESULT_BUSY 3
+#define BTA_HF_CLIENT_AT_RESULT_NO_ANSWER 4
+#define BTA_HF_CLIENT_AT_RESULT_DELAY 5
+#define BTA_HF_CLIENT_AT_RESULT_BLACKLISTED 6
+#define BTA_HF_CLIENT_AT_RESULT_CME 7
+
+typedef uint8_t tBTA_HF_CLIENT_AT_RESULT_TYPE;
+
+/* HF Client callback events */
+#define BTA_HF_CLIENT_ENABLE_EVT 0     /* HF Client enabled */
+#define BTA_HF_CLIENT_REGISTER_EVT 1   /* HF Client registered */
+#define BTA_HF_CLIENT_OPEN_EVT 2       /* HF Client connection open */
+#define BTA_HF_CLIENT_CLOSE_EVT 3      /* HF Client connection closed */
+#define BTA_HF_CLIENT_CONN_EVT 4       /* Service level connection opened */
+#define BTA_HF_CLIENT_AUDIO_OPEN_EVT 5 /* Audio connection open */
+#define BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT \
+  6 /* Audio connection with mSBC codec open */
+#define BTA_HF_CLIENT_AUDIO_CLOSE_EVT 7 /* Audio connection closed */
+#define BTA_HF_CLIENT_SPK_EVT 8         /* Speaker volume changed */
+#define BTA_HF_CLIENT_MIC_EVT 9         /* Microphone volume changed */
+#define BTA_HF_CLIENT_IND_EVT 10        /* Indicator */
+#define BTA_HF_CLIENT_VOICE_REC_EVT \
+  11 /* AG changed voice recognition setting */
+#define BTA_HF_CLIENT_OPERATOR_NAME_EVT 12 /* Operator name acquired */
+#define BTA_HF_CLIENT_CLIP_EVT 13      /* Calling line identification event */
+#define BTA_HF_CLIENT_CCWA_EVT 14      /* Call waiting notification */
+#define BTA_HF_CLIENT_AT_RESULT_EVT 15 /* Call waiting notification */
+#define BTA_HF_CLIENT_CLCC_EVT 16      /* current call event */
+#define BTA_HF_CLIENT_CNUM_EVT 17      /* subscriber information event */
+#define BTA_HF_CLIENT_BTRH_EVT 18      /* bluetooth response and hold event */
+#define BTA_HF_CLIENT_BSIR_EVT                                               \
+  19                              /* in-band ring tone setting changed event \
+                                     */
+#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_DISABLE_EVT 30     /* HF Client disabled */
+
+typedef uint8_t tBTA_HF_CLIENT_EVT;
+
+/* HF Client open status */
+#define BTA_HF_CLIENT_SUCCESS 0        /* Connection successfully opened */
+#define BTA_HF_CLIENT_FAIL_SDP 1       /* Open failed due to SDP */
+#define BTA_HF_CLIENT_FAIL_RFCOMM 2    /* Open failed due to RFCOMM */
+#define BTA_HF_CLIENT_FAIL_RESOURCES 3 /* out of resources failure  */
+
+typedef uint8_t tBTA_HF_CLIENT_STATUS;
+
+/* indicator type */
+#define BTA_HF_CLIENT_IND_BATTCH 0    /* Battery charge indicator */
+#define BTA_HF_CLIENT_IND_SIGNAL 1    /* Signal Strength indicator */
+#define BTA_HF_CLIENT_IND_SERVICE 2   /* Service availability indicator */
+#define BTA_HF_CLIENT_IND_CALL 3      /* Standard call status indicator*/
+#define BTA_HF_CLIENT_IND_ROAM 4      /* Roaming status indicator */
+#define BTA_HF_CLIENT_IND_CALLSETUP 5 /* Call setup status indicator */
+#define BTA_HF_CLIENT_IND_CALLHELD 6  /* Call hold status indicator */
+
+typedef uint8_t tBTA_HF_CLIENT_IND_TYPE;
+
+/* AT commands */
+#define BTA_HF_CLIENT_AT_CMD_VTS 0
+#define BTA_HF_CLIENT_AT_CMD_BTRH 1
+#define BTA_HF_CLIENT_AT_CMD_CHUP 2
+#define BTA_HF_CLIENT_AT_CMD_CHLD 3
+#define BTA_HF_CLIENT_AT_CMD_BCC 4
+#define BTA_HF_CLIENT_AT_CMD_CNUM 5
+#define BTA_HF_CLIENT_AT_CMD_ATA 6
+#define BTA_HF_CLIENT_AT_CMD_COPS 7
+#define BTA_HF_CLIENT_AT_CMD_ATD 8
+#define BTA_HF_CLIENT_AT_CMD_VGM 9
+#define BTA_HF_CLIENT_AT_CMD_VGS 10
+#define BTA_HF_CLIENT_AT_CMD_BVRA 11
+#define BTA_HF_CLIENT_AT_CMD_CLCC 12
+#define BTA_HF_CLIENT_AT_CMD_BINP 13
+#define BTA_HF_CLIENT_AT_CMD_BLDN 14
+#define BTA_HF_CLIENT_AT_CMD_NREC 15
+
+typedef uint8_t tBTA_HF_CLIENT_AT_CMD_TYPE;
+
+/* data associated with BTA_HF_CLIENT_REGISTER_EVT */
+typedef struct {
+  uint16_t handle;
+  tBTA_HF_CLIENT_STATUS status;
+} tBTA_HF_CLIENT_REGISTER;
+
+/* data associated with BTA_HF_CLIENT_OPEN_EVT */
+typedef struct {
+  BD_ADDR bd_addr;
+  tBTA_HF_CLIENT_STATUS status;
+} tBTA_HF_CLIENT_OPEN;
+
+/* data associated with BTA_HF_CLIENT_CONN_EVT */
+typedef struct {
+  tBTA_HF_CLIENT_PEER_FEAT peer_feat;
+  tBTA_HF_CLIENT_CHLD_FEAT chld_feat;
+} tBTA_HF_CLIENT_CONN;
+
+/* data associated with BTA_HF_CLIENT_IND_EVT event */
+typedef struct {
+  tBTA_HF_CLIENT_IND_TYPE type;
+  uint16_t value;
+} tBTA_HF_CLIENT_IND;
+
+/* data associated with BTA_HF_CLIENT_OPERATOR_NAME_EVT */
+#define BTA_HF_CLIENT_OPERATOR_NAME_LEN 16
+typedef struct {
+  char name[BTA_HF_CLIENT_OPERATOR_NAME_LEN + 1];
+} tBTA_HF_CLIENT_OPERATOR_NAME;
+
+/* data associated with BTA_HF_CLIENT_CLIP_EVT  and BTA_HF_CLIENT_CCWA_EVT*/
+#define BTA_HF_CLIENT_NUMBER_LEN 32
+typedef struct {
+  char number[BTA_HF_CLIENT_NUMBER_LEN + 1];
+} tBTA_HF_CLIENT_NUMBER;
+
+/* data associated with BTA_HF_CLIENT_AT_RESULT_EVT event */
+typedef struct {
+  tBTA_HF_CLIENT_AT_RESULT_TYPE type;
+  uint16_t cme;
+} tBTA_HF_CLIENT_AT_RESULT;
+
+/* data associated with BTA_HF_CLIENT_CLCC_EVT event */
+typedef struct {
+  uint32_t idx;
+  bool inc;
+  uint8_t status;
+  bool mpty;
+  bool number_present;
+  char number[BTA_HF_CLIENT_NUMBER_LEN + 1];
+} tBTA_HF_CLIENT_CLCC;
+
+/* data associated with BTA_HF_CLIENT_CNUM_EVT event */
+typedef struct {
+  uint16_t service;
+  char number[BTA_HF_CLIENT_NUMBER_LEN + 1];
+} tBTA_HF_CLIENT_CNUM;
+
+/* data associated with other events */
+typedef struct { uint16_t value; } tBTA_HF_CLIENT_VAL;
+
+/* union of data associated with AG callback */
+typedef union {
+  tBTA_HF_CLIENT_REGISTER reg;
+  tBTA_HF_CLIENT_OPEN open;
+  tBTA_HF_CLIENT_CONN conn;
+  tBTA_HF_CLIENT_IND ind;
+  tBTA_HF_CLIENT_VAL val;
+  tBTA_HF_CLIENT_OPERATOR_NAME operator_name;
+  tBTA_HF_CLIENT_NUMBER number;
+  tBTA_HF_CLIENT_AT_RESULT result;
+  tBTA_HF_CLIENT_CLCC clcc;
+  tBTA_HF_CLIENT_CNUM cnum;
+} tBTA_HF_CLIENT;
+
+typedef uint32_t tBTA_HF_CLIENT_FEAT;
+
+/* HF Client callback */
+typedef void(tBTA_HF_CLIENT_CBACK)(tBTA_HF_CLIENT_EVT event,
+                                   tBTA_HF_CLIENT* p_data);
+
+/*****************************************************************************
+ *  External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         BTA_HfClientEnable
+ *
+ * Description      Enable the HF CLient service. When the enable
+ *                  operation is complete the callback function will be
+ *                  called with a BTA_HF_CLIENT_ENABLE_EVT. This function must
+ *                  be called before other function in the HF CLient API are
+ *                  called.
+ *
+ * Returns          BTA_SUCCESS if OK, BTA_FAILURE otherwise.
+ *
+ ******************************************************************************/
+tBTA_STATUS BTA_HfClientEnable(tBTA_HF_CLIENT_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HfClientDisable
+ *
+ * Description      Disable the HF Client service
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HfClientDisable(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HfClientRegister
+ *
+ * Description      Register an HF Client service.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HfClientRegister(tBTA_SEC sec_mask, tBTA_HF_CLIENT_FEAT features,
+                          const char* p_service_name);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HfClientDeregister
+ *
+ * Description      Deregister an HF Client service.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HfClientDeregister(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HfClientOpen
+ *
+ * Description      Opens a connection to an audio gateway.
+ *                  When connection is open callback function is called
+ *                  with a BTA_HF_CLIENT_OPEN_EVT. Only the data connection is
+ *                  opened. The audio connection is not opened.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HfClientOpen(uint16_t handle, BD_ADDR bd_addr, tBTA_SEC sec_mask);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HfClientClose
+ *
+ * Description      Close the current connection to an audio gateway.
+ *                  Any current audio connection will also be closed
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HfClientClose(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HfCllientAudioOpen
+ *
+ * Description      Opens an audio connection to the currently connected
+ *                 audio gateway
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HfClientAudioOpen(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HfClientAudioClose
+ *
+ * Description      Close the currently active audio connection to an audio
+ *                  gateway. The data connection remains open
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HfClientAudioClose(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HfClientSendAT
+ *
+ * Description      send AT command
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_HfClientSendAT(uint16_t handle, tBTA_HF_CLIENT_AT_CMD_TYPE at,
+                        uint32_t val1, uint32_t val2, const char* str);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_HF_CLIENT_API_H */
diff --git a/bt/bta/include/bta_hh_api.h b/bt/bta/include/bta_hh_api.h
new file mode 100644
index 0000000..9f33722
--- /dev/null
+++ b/bt/bta/include/bta_hh_api.h
@@ -0,0 +1,522 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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.
+ *
+ ******************************************************************************/
+#ifndef BTA_HH_API_H
+#define BTA_HH_API_H
+
+#include "bta_api.h"
+#include "hidh_api.h"
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+#include "gatt_api.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+ *  Constants and Type Definitions
+ ****************************************************************************/
+#ifndef BTA_HH_DEBUG
+#define BTA_HH_DEBUG true
+#endif
+
+#ifndef BTA_HH_SSR_MAX_LATENCY_DEF
+#define BTA_HH_SSR_MAX_LATENCY_DEF 800 /* 500 ms*/
+#endif
+
+#ifndef BTA_HH_SSR_MIN_TOUT_DEF
+#define BTA_HH_SSR_MIN_TOUT_DEF 2
+#endif
+
+/* BTA HID Host callback events */
+#define BTA_HH_ENABLE_EVT 0     /* HH enabled */
+#define BTA_HH_DISABLE_EVT 1    /* HH disabled */
+#define BTA_HH_OPEN_EVT 2       /* connection opened */
+#define BTA_HH_CLOSE_EVT 3      /* connection closed */
+#define BTA_HH_GET_RPT_EVT 4    /* BTA_HhGetReport callback */
+#define BTA_HH_SET_RPT_EVT 5    /* BTA_HhSetReport callback */
+#define BTA_HH_GET_PROTO_EVT 6  /* BTA_GetProtoMode callback */
+#define BTA_HH_SET_PROTO_EVT 7  /* BTA_HhSetProtoMode callback */
+#define BTA_HH_GET_IDLE_EVT 8   /* BTA_HhGetIdle comes callback */
+#define BTA_HH_SET_IDLE_EVT 9   /* BTA_HhSetIdle finish callback */
+#define BTA_HH_GET_DSCP_EVT 10  /* Get report descriptor */
+#define BTA_HH_ADD_DEV_EVT 11   /* Add Device callback */
+#define BTA_HH_RMV_DEV_EVT 12   /* remove device finished */
+#define BTA_HH_VC_UNPLUG_EVT 13 /* virtually unplugged */
+#define BTA_HH_DATA_EVT 15
+#define BTA_HH_API_ERR_EVT 16     /* API error is caught */
+#define BTA_HH_UPDATE_SCPP_EVT 17 /* update scan paramter complete */
+
+typedef uint16_t tBTA_HH_EVT;
+
+/* application ID(none-zero) for each type of device */
+#define BTA_HH_APP_ID_MI 1
+#define BTA_HH_APP_ID_KB 2
+#define BTA_HH_APP_ID_RMC 3
+#define BTA_HH_APP_ID_3DSG 4
+#define BTA_HH_APP_ID_JOY 5
+#define BTA_HH_APP_ID_GPAD 6
+#define BTA_HH_APP_ID_LE 0xff
+
+/* defined the minimum offset */
+#define BTA_HH_MIN_OFFSET (L2CAP_MIN_OFFSET + 1)
+
+/* HID_HOST_MAX_DEVICES can not exceed 15 for th design of BTA HH */
+#define BTA_HH_IDX_INVALID 0xff
+#define BTA_HH_MAX_KNOWN HID_HOST_MAX_DEVICES
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+/* GATT_MAX_PHY_CHANNEL can not exceed 14 for the design of BTA HH */
+#define BTA_HH_LE_MAX_KNOWN GATT_MAX_PHY_CHANNEL
+#define BTA_HH_MAX_DEVICE (HID_HOST_MAX_DEVICES + GATT_MAX_PHY_CHANNEL)
+#else
+#define BTA_HH_MAX_DEVICE HID_HOST_MAX_DEVICES
+#endif
+/* invalid device handle */
+#define BTA_HH_INVALID_HANDLE 0xff
+
+/* type of protocol mode */
+#define BTA_HH_PROTO_RPT_MODE (0x00)
+#define BTA_HH_PROTO_BOOT_MODE (0x01)
+#define BTA_HH_PROTO_UNKNOWN (0xff)
+typedef uint8_t tBTA_HH_PROTO_MODE;
+
+enum { BTA_HH_KEYBD_RPT_ID = 1, BTA_HH_MOUSE_RPT_ID };
+typedef uint8_t tBTA_HH_BOOT_RPT_ID;
+
+/* type of devices, bit mask */
+#define BTA_HH_DEVT_UNKNOWN 0x00
+#define BTA_HH_DEVT_JOS 0x01 /* joy stick */
+#define BTA_HH_DEVT_GPD 0x02 /* game pad */
+#define BTA_HH_DEVT_RMC 0x03 /* remote control */
+#define BTA_HH_DEVT_SED 0x04 /* sensing device */
+#define BTA_HH_DEVT_DGT 0x05 /* Digitizer tablet */
+#define BTA_HH_DEVT_CDR 0x06 /* card reader */
+#define BTA_HH_DEVT_KBD 0x10 /* keyboard */
+#define BTA_HH_DEVT_MIC 0x20 /* pointing device */
+#define BTA_HH_DEVT_COM 0x30 /* Combo keyboard/pointing */
+#define BTA_HH_DEVT_OTHER 0x80
+typedef uint8_t tBTA_HH_DEVT;
+
+enum {
+  BTA_HH_OK,
+  BTA_HH_HS_HID_NOT_READY,  /* handshake error : device not ready */
+  BTA_HH_HS_INVALID_RPT_ID, /* handshake error : invalid report ID */
+  BTA_HH_HS_TRANS_NOT_SPT,  /* handshake error : transaction not spt */
+  BTA_HH_HS_INVALID_PARAM,  /* handshake error : invalid paremter */
+  BTA_HH_HS_ERROR,          /* handshake error : unspecified HS error */
+  BTA_HH_ERR,               /* general BTA HH error */
+  BTA_HH_ERR_SDP,           /* SDP error */
+  BTA_HH_ERR_PROTO,         /* SET_Protocol error,
+                                only used in BTA_HH_OPEN_EVT callback */
+
+  BTA_HH_ERR_DB_FULL,     /* device database full error, used in
+                             BTA_HH_OPEN_EVT/BTA_HH_ADD_DEV_EVT */
+  BTA_HH_ERR_TOD_UNSPT,   /* type of device not supported */
+  BTA_HH_ERR_NO_RES,      /* out of system resources */
+  BTA_HH_ERR_AUTH_FAILED, /* authentication fail */
+  BTA_HH_ERR_HDL,
+  BTA_HH_ERR_SEC
+};
+typedef uint8_t tBTA_HH_STATUS;
+
+#define BTA_HH_VIRTUAL_CABLE HID_VIRTUAL_CABLE
+#define BTA_HH_NORMALLY_CONNECTABLE HID_NORMALLY_CONNECTABLE
+#define BTA_HH_RECONN_INIT HID_RECONN_INIT
+#define BTA_HH_SDP_DISABLE HID_SDP_DISABLE
+#define BTA_HH_BATTERY_POWER HID_BATTERY_POWER
+#define BTA_HH_REMOTE_WAKE HID_REMOTE_WAKE
+#define BTA_HH_SUP_TOUT_AVLBL HID_SUP_TOUT_AVLBL
+#define BTA_HH_SEC_REQUIRED HID_SEC_REQUIRED
+typedef uint16_t tBTA_HH_ATTR_MASK;
+
+/* supported type of device and corresponding application ID */
+typedef struct {
+  tBTA_HH_DEVT tod; /* type of device               */
+  uint8_t app_id;   /* corresponding application ID */
+} tBTA_HH_SPT_TOD;
+
+/* configuration struct */
+typedef struct {
+  uint8_t max_devt_spt;         /* max number of types of devices spt */
+  tBTA_HH_SPT_TOD* p_devt_list; /* supported types of device list     */
+  uint16_t sdp_db_size;
+} tBTA_HH_CFG;
+
+enum {
+  BTA_HH_RPTT_RESRV,  /* reserved         */
+  BTA_HH_RPTT_INPUT,  /* input report     */
+  BTA_HH_RPTT_OUTPUT, /* output report    */
+  BTA_HH_RPTT_FEATURE /* feature report   */
+};
+typedef uint8_t tBTA_HH_RPT_TYPE;
+
+/* HID_CONTROL operation code used in BTA_HhSendCtrl()
+*/
+enum {
+  BTA_HH_CTRL_NOP = 0 + HID_PAR_CONTROL_NOP, /* mapping from BTE */
+  BTA_HH_CTRL_HARD_RESET,                    /* hard reset       */
+  BTA_HH_CTRL_SOFT_RESET,                    /* soft reset       */
+  BTA_HH_CTRL_SUSPEND,                       /* enter suspend    */
+  BTA_HH_CTRL_EXIT_SUSPEND,                  /* exit suspend     */
+  BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG           /* virtual unplug   */
+};
+typedef uint8_t tBTA_HH_TRANS_CTRL_TYPE;
+
+typedef tHID_DEV_DSCP_INFO tBTA_HH_DEV_DESCR;
+
+#define BTA_HH_SSR_PARAM_INVALID HID_SSR_PARAM_INVALID
+
+/* id DI is not existing in remote device, vendor_id in tBTA_HH_DEV_DSCP_INFO
+ * will be set to 0xffff */
+#define BTA_HH_VENDOR_ID_INVALID 0xffff
+
+/* report descriptor information */
+typedef struct {
+  uint16_t vendor_id;       /* vendor ID */
+  uint16_t product_id;      /* product ID */
+  uint16_t version;         /* version */
+  uint16_t ssr_max_latency; /* SSR max latency, BTA_HH_SSR_PARAM_INVALID if
+                               unknown */
+  uint16_t
+      ssr_min_tout;  /* SSR min timeout, BTA_HH_SSR_PARAM_INVALID if unknown */
+  uint8_t ctry_code; /*Country Code.*/
+#if (BTA_HH_LE_INCLUDED == TRUE)
+#define BTA_HH_LE_REMOTE_WAKE 0x01
+#define BTA_HH_LE_NORMAL_CONN 0x02
+
+  uint8_t flag;
+#endif
+  tBTA_HH_DEV_DESCR descriptor;
+} tBTA_HH_DEV_DSCP_INFO;
+
+/* callback event data for BTA_HH_OPEN_EVT */
+typedef struct {
+  BD_ADDR bda;           /* HID device bd address    */
+  tBTA_HH_STATUS status; /* operation status         */
+  uint8_t handle;        /* device handle            */
+#if (BTA_HH_LE_INCLUDED == TRUE)
+  bool le_hid;         /* is LE devices? */
+  bool scps_supported; /* scan parameter service supported */
+#endif
+
+} tBTA_HH_CONN;
+
+typedef tBTA_HH_CONN tBTA_HH_DEV_INFO;
+
+/* callback event data */
+typedef struct {
+  tBTA_HH_STATUS status; /* operation status         */
+  uint8_t handle;        /* device handle            */
+} tBTA_HH_CBDATA;
+
+enum {
+  BTA_HH_MOD_CTRL_KEY,
+  BTA_HH_MOD_SHFT_KEY,
+  BTA_HH_MOD_ALT_KEY,
+  BTA_HH_MOD_GUI_KEY,
+  BTA_HH_MOD_MAX_KEY
+};
+
+/* parsed boot mode keyboard report */
+typedef struct {
+  uint8_t this_char[6]; /* virtual key code     */
+  bool mod_key[BTA_HH_MOD_MAX_KEY];
+  /* ctrl, shift, Alt, GUI */
+  /* modifier key: is Shift key pressed */
+  /* modifier key: is Ctrl key pressed  */
+  /* modifier key: is Alt key pressed   */
+  /* modifier key: GUI up/down */
+  bool caps_lock; /* is caps locked       */
+  bool num_lock;  /* is Num key pressed   */
+} tBTA_HH_KEYBD_RPT;
+
+/* parsed boot mode mouse report */
+typedef struct {
+  uint8_t mouse_button; /* mouse button is clicked   */
+  int8_t delta_x;       /* displacement x            */
+  int8_t delta_y;       /* displacement y            */
+} tBTA_HH_MICE_RPT;
+
+/* parsed Boot report */
+typedef struct {
+  tBTA_HH_BOOT_RPT_ID dev_type; /* type of device report */
+  union {
+    tBTA_HH_KEYBD_RPT keybd_rpt; /* keyboard report      */
+    tBTA_HH_MICE_RPT mice_rpt;   /* mouse report         */
+  } data_rpt;
+} tBTA_HH_BOOT_RPT;
+
+/* handshake data */
+typedef struct {
+  tBTA_HH_STATUS status; /* handshake status */
+  uint8_t handle;        /* device handle    */
+  union {
+    tBTA_HH_PROTO_MODE proto_mode; /* GET_PROTO_EVT :protocol mode */
+    BT_HDR* p_rpt_data;            /* GET_RPT_EVT   : report data  */
+    uint8_t idle_rate;             /* GET_IDLE_EVT  : idle rate    */
+  } rsp_data;
+
+} tBTA_HH_HSDATA;
+
+/* union of data associated with HD callback */
+typedef union {
+  tBTA_HH_DEV_INFO dev_info; /* BTA_HH_ADD_DEV_EVT, BTA_HH_RMV_DEV_EVT   */
+  tBTA_HH_CONN conn;         /* BTA_HH_OPEN_EVT      */
+  tBTA_HH_CBDATA dev_status; /* BTA_HH_CLOSE_EVT,
+                                BTA_HH_SET_PROTO_EVT
+                                BTA_HH_SET_RPT_EVT
+                                BTA_HH_SET_IDLE_EVT
+                                BTA_HH_UPDATE_SCPP_EVT */
+
+  tBTA_HH_STATUS status;           /* BTA_HH_ENABLE_EVT */
+  tBTA_HH_DEV_DSCP_INFO dscp_info; /* BTA_HH_GET_DSCP_EVT */
+  tBTA_HH_HSDATA hs_data;          /* GET_ transaction callback
+                                      BTA_HH_GET_RPT_EVT
+                                      BTA_HH_GET_PROTO_EVT
+                                      BTA_HH_GET_IDLE_EVT */
+} tBTA_HH;
+
+/* BTA HH callback function */
+typedef void(tBTA_HH_CBACK)(tBTA_HH_EVT event, tBTA_HH* p_data);
+
+/*****************************************************************************
+ *  External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhRegister
+ *
+ * Description      This function enable HID host and registers HID-Host with
+ *                  lower layers.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HhEnable(tBTA_SEC sec_mask, tBTA_HH_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhDeregister
+ *
+ * Description      This function is called when the host is about power down.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HhDisable(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhOpen
+ *
+ * Description      This function is called to start an inquiry and read SDP
+ *                  record of responding devices; connect to a device if only
+ *                  one active HID device is found.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HhOpen(BD_ADDR dev_bda, tBTA_HH_PROTO_MODE mode,
+                       tBTA_SEC sec_mask);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhClose
+ *
+ * Description      This function disconnects the device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HhClose(uint8_t dev_handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhSetProtoMode
+ *
+ * Description      This function set the protocol mode at specified HID handle
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HhSetProtoMode(uint8_t handle, tBTA_HH_PROTO_MODE t_type);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhGetProtoMode
+ *
+ * Description      This function get the protocol mode of a specified HID
+ *                  device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HhGetProtoMode(uint8_t dev_handle);
+/*******************************************************************************
+ *
+ * Function         BTA_HhSetReport
+ *
+ * Description      send SET_REPORT to device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HhSetReport(uint8_t dev_handle, tBTA_HH_RPT_TYPE r_type,
+                            BT_HDR* p_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhGetReport
+ *
+ * Description      Send a GET_REPORT to HID device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HhGetReport(uint8_t dev_handle, tBTA_HH_RPT_TYPE r_type,
+                            uint8_t rpt_id, uint16_t buf_size);
+/*******************************************************************************
+ *
+ * Function         BTA_HhSetIdle
+ *
+ * Description      send SET_IDLE to device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HhSetIdle(uint8_t dev_handle, uint16_t idle_rate);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhGetIdle
+ *
+ * Description      Send a GET_IDLE to HID device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HhGetIdle(uint8_t dev_handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhSendCtrl
+ *
+ * Description      Send HID_CONTROL request to a HID device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HhSendCtrl(uint8_t dev_handle, tBTA_HH_TRANS_CTRL_TYPE c_type);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhSetIdle
+ *
+ * Description      send SET_IDLE to device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HhSetIdle(uint8_t dev_handle, uint16_t idle_rate);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhGetIdle
+ *
+ * Description      Send a GET_IDLE from HID device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HhGetIdle(uint8_t dev_handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhSendData
+ *
+ * Description      Send DATA transaction to a HID device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HhSendData(uint8_t dev_handle, BD_ADDR dev_bda, BT_HDR* p_buf);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HhGetDscpInfo
+ *
+ * Description      Get report descriptor of the device
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HhGetDscpInfo(uint8_t dev_handle);
+
+/*******************************************************************************
+ * Function         BTA_HhAddDev
+ *
+ * Description      Add a virtually cabled device into HID-Host device list
+ *                  to manage and assign a device handle for future API call,
+ *                  host applciation call this API at start-up to initialize its
+ *                  virtually cabled devices.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HhAddDev(BD_ADDR bda, tBTA_HH_ATTR_MASK attr_mask,
+                         uint8_t sub_class, uint8_t app_id,
+                         tBTA_HH_DEV_DSCP_INFO dscp_info);
+/*******************************************************************************
+ *
+ * Function         BTA_HhRemoveDev
+ *
+ * Description      Remove a device from the HID host devices list.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HhRemoveDev(uint8_t dev_handle);
+
+/*******************************************************************************
+ *
+ *              Parsing Utility Functions
+ *
+ ******************************************************************************/
+/*******************************************************************************
+ *
+ * Function         BTA_HhParseBootRpt
+ *
+ * Description      This utility function parse a boot mode report.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HhParseBootRpt(tBTA_HH_BOOT_RPT* p_data, uint8_t* p_report,
+                               uint16_t report_len);
+
+/* test commands */
+extern void bta_hh_le_hid_read_rpt_clt_cfg(BD_ADDR bd_addr, uint8_t rpt_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_HH_API_H */
diff --git a/bt/bta/include/bta_hh_co.h b/bt/bta/include/bta_hh_co.h
new file mode 100644
index 0000000..ac52696
--- /dev/null
+++ b/bt/bta/include/bta_hh_co.h
@@ -0,0 +1,144 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2005-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 is the interface file for hid host call-out functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_HH_CO_H
+#define BTA_HH_CO_H
+
+#include "bta_hh_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+  uint16_t rpt_uuid;
+  uint8_t rpt_id;
+  tBTA_HH_RPT_TYPE rpt_type;
+  uint8_t srvc_inst_id;
+  uint8_t char_inst_id;
+} tBTA_HH_RPT_CACHE_ENTRY;
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_co_data
+ *
+ * Description      This callout function is executed by HH when data is
+ *                  received
+ *                  in interupt channel.
+ *
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+extern void bta_hh_co_data(uint8_t dev_handle, uint8_t* p_rpt, uint16_t len,
+                           tBTA_HH_PROTO_MODE mode, uint8_t sub_class,
+                           uint8_t ctry_code, BD_ADDR peer_addr,
+                           uint8_t app_id);
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_co_open
+ *
+ * Description      This callout function is executed by HH when connection is
+ *                  opened, and application may do some device specific
+ *                  initialization.
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+extern void bta_hh_co_open(uint8_t dev_handle, uint8_t sub_class,
+                           uint16_t attr_mask, uint8_t app_id);
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_co_close
+ *
+ * Description      This callout function is executed by HH when connection is
+ *                  closed, and device specific finalizatio nmay be needed.
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+extern void bta_hh_co_close(uint8_t dev_handle, uint8_t app_id);
+
+#if (BLE_INCLUDED == TRUE && BTA_HH_LE_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_co_rpt_info
+ *
+ * Description      This callout function is to convey the report information on
+ *                  a HOGP device to the application. Application can save this
+ *                  information in NV if device is bonded and load it back when
+ *                  stack reboot.
+ *
+ * Parameters       remote_bda  - remote device address
+ *                  p_entry     - report entry pointer
+ *                  app_id      - application id
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+extern void bta_hh_le_co_rpt_info(BD_ADDR remote_bda,
+                                  tBTA_HH_RPT_CACHE_ENTRY* p_entry,
+                                  uint8_t app_id);
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_co_cache_load
+ *
+ * Description      This callout function is to request the application to load
+ *                  the cached HOGP report if there is any. When cache reading
+ *                  is completed, bta_hh_le_ci_cache_load() is called by the
+ *                  application.
+ *
+ * Parameters       remote_bda  - remote device address
+ *                  p_num_rpt: number of cached report
+ *                  app_id      - application id
+ *
+ * Returns          the acched report array
+ *
+ ******************************************************************************/
+extern tBTA_HH_RPT_CACHE_ENTRY* bta_hh_le_co_cache_load(BD_ADDR remote_bda,
+                                                        uint8_t* p_num_rpt,
+                                                        uint8_t app_id);
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_co_reset_rpt_cache
+ *
+ * Description      This callout function is to reset the HOGP device cache.
+ *
+ * Parameters       remote_bda  - remote device address
+ *
+ * Returns          none
+ *
+ ******************************************************************************/
+extern void bta_hh_le_co_reset_rpt_cache(BD_ADDR remote_bda, uint8_t app_id);
+
+#endif /* #if (BLE_INCLUDED == true && BTA_HH_LE_INCLUDED == TRUE) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_HH_CO_H */
diff --git a/bt/bta/include/bta_hl_api.h b/bt/bta/include/bta_hl_api.h
new file mode 100644
index 0000000..39a43f8
--- /dev/null
+++ b/bt/bta/include/bta_hl_api.h
@@ -0,0 +1,832 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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 is the public interface file for the HeaLth device profile (HL)
+ *  subsystem of BTA, Broadcom's Bluetooth application layer for mobile
+ *  phones.
+ *
+ ******************************************************************************/
+#ifndef BTA_HL_API_H
+#define BTA_HL_API_H
+
+#include "bta_api.h"
+#include "btm_api.h"
+#include "mca_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+ *  Constants and data types
+ ****************************************************************************/
+/* Extra Debug Code */
+#ifndef BTA_HL_DEBUG
+#define BTA_HL_DEBUG true
+#endif
+
+#ifndef BTA_HL_NUM_APPS
+#define BTA_HL_NUM_APPS 12
+#endif
+
+#ifndef BTA_HL_NUM_MDEPS
+#define BTA_HL_NUM_MDEPS 13
+#endif
+
+#ifndef BTA_HL_NUM_MCLS
+#define BTA_HL_NUM_MCLS 7
+#endif
+
+#ifndef BTA_HL_NUM_MDLS_PER_MDEP
+#define BTA_HL_NUM_MDLS_PER_MDEP 4
+#endif
+
+#ifndef BTA_HL_NUM_MDLS_PER_MCL
+#define BTA_HL_NUM_MDLS_PER_MCL 10
+#endif
+
+#ifndef BTA_HL_NUM_DATA_TYPES
+#define BTA_HL_NUM_DATA_TYPES                        \
+  5 /* maximum number of data types can be supported \
+       per MDEP ID */
+#endif
+
+#define BTA_HL_MCAP_RSP_TOUT 2 /* 2 seconds */
+
+#ifndef BTA_HL_CCH_NUM_FILTER_ELEMS
+#define BTA_HL_CCH_NUM_FILTER_ELEMS 3
+#endif
+
+#ifndef BTA_HL_NUM_SDP_CBACKS
+#define BTA_HL_NUM_SDP_CBACKS 7
+#endif
+
+#ifndef BTA_HL_NUM_SDP_RECS
+#define BTA_HL_NUM_SDP_RECS 5
+#endif
+
+#ifndef BTA_HL_NUM_SDP_MDEPS
+#define BTA_HL_NUM_SDP_MDEPS 12
+#endif
+
+#ifndef BTA_HL_NUM_SVC_ELEMS
+#define BTA_HL_NUM_SVC_ELEMS 2
+#endif
+
+#ifndef BTA_HL_NUM_PROTO_ELEMS
+#define BTA_HL_NUM_PROTO_ELEMS 2
+#endif
+
+#define BTA_HL_VERSION 0x0101
+#define BTA_HL_NUM_ADD_PROTO_LISTS 1
+#define BTA_HL_NUM_ADD_PROTO_ELEMS 2
+#define BTA_HL_MDEP_SEQ_SIZE 20
+#define BTA_HL_VAL_ARRY_SIZE 320
+
+#ifndef BTA_HL_NUM_MDL_CFGS
+#define BTA_HL_NUM_MDL_CFGS \
+  16 /* numer of MDL cfg saved in the persistent memory*/
+#endif
+
+#define BTA_HL_NUM_TIMERS 7
+
+#define BTA_HL_CCH_RSP_TOUT 2000
+#define BTA_HL_MAX_TIME 255
+#define BTA_HL_MIN_TIME 1
+#define BTA_HL_INVALID_APP_HANDLE 0xFF
+#define BTA_HL_INVALID_MCL_HANDLE 0xFF
+#define BTA_HL_INVALID_MDL_HANDLE 0xFFFF
+
+#define BTA_HL_STATUS_OK 0
+#define BTA_HL_STATUS_FAIL 1 /* Used to pass all other errors */
+#define BTA_HL_STATUS_ABORTED 2
+#define BTA_HL_STATUS_NO_RESOURCE 3
+#define BTA_HL_STATUS_LAST_ITEM 4
+#define BTA_HL_STATUS_DUPLICATE_APP_ID 5
+#define BTA_HL_STATUS_INVALID_APP_HANDLE 6
+#define BTA_HL_STATUS_INVALID_MCL_HANDLE 7
+#define BTA_HL_STATUS_MCAP_REG_FAIL 8
+#define BTA_HL_STATUS_MDEP_CO_FAIL 9
+#define BTA_HL_STATUS_ECHO_CO_FAIL 10
+#define BTA_HL_STATUS_MDL_CFG_CO_FAIL 11
+#define BTA_HL_STATUS_SDP_NO_RESOURCE 12
+#define BTA_HL_STATUS_SDP_FAIL 13
+#define BTA_HL_STATUS_NO_CCH 14
+#define BTA_HL_STATUS_NO_MCL 15
+
+#define BTA_HL_STATUS_NO_FIRST_RELIABLE 17
+#define BTA_HL_STATUS_INVALID_DCH_CFG 18
+#define BTA_HL_STATUS_INVALID_MDL_HANDLE 19
+#define BTA_HL_STATUS_INVALID_BD_ADDR 20
+#define BTA_HL_STATUS_INVALID_RECONNECT_CFG 21
+#define BTA_HL_STATUS_ECHO_TEST_BUSY 22
+#define BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID 23
+#define BTA_HL_STATUS_INVALID_MDL_ID 24
+#define BTA_HL_STATUS_NO_MDL_ID_FOUND 25
+#define BTA_HL_STATUS_DCH_BUSY 26 /* DCH is congested*/
+#define BTA_HL_STATUS_INVALID_CTRL_PSM 27
+#define BTA_HL_STATUS_DUPLICATE_CCH_OPEN 28
+
+typedef uint8_t tBTA_HL_STATUS;
+typedef tMCA_HANDLE tBTA_HL_APP_HANDLE;
+typedef tMCA_CL tBTA_HL_MCL_HANDLE;
+typedef tMCA_DL tBTA_HL_MDL_HANDLE;
+enum {
+  BTA_HL_DEVICE_TYPE_SINK,
+  BTA_HL_DEVICE_TYPE_SOURCE,
+  BTA_HL_DEVICE_TYPE_DUAL
+};
+
+typedef uint8_t tBTA_HL_DEVICE_TYPE;
+
+#define BTA_HL_SDP_IEEE_11073_20601 0x01
+
+#define BTA_HL_MCAP_SUP_RECONNECT_MASK_INIT 2   /* 0x02 */
+#define BTA_HL_MCAP_SUP_RECONNECT_MASK_ACCEPT 4 /* 0x04 */
+#define BTA_HL_MCAP_SUP_CSP_MASK_SYNC_SLAVE 0   /* 0x08 */
+#define BTA_HL_MCAP_SUP_CSP_MASK_SYNC_MASTER 0  /* 0x10 */
+
+#define BTA_HL_MCAP_SUP_PROC_MASK          \
+  (BTA_HL_MCAP_SUP_RECONNECT_MASK_INIT |   \
+   BTA_HL_MCAP_SUP_RECONNECT_MASK_ACCEPT | \
+   BTA_HL_MCAP_SUP_CSP_MASK_SYNC_SLAVE | BTA_HL_MCAP_SUP_CSP_MASK_SYNC_MASTER)
+#define BTA_HL_MDEP_ROLE_SOURCE 0x00
+#define BTA_HL_MDEP_ROLE_SINK 0x01
+
+typedef uint8_t tBTA_HL_MDEP_ROLE;
+
+#define BTA_HL_MDEP_ROLE_MASK_SOURCE 0x01 /* bit mask */
+#define BTA_HL_MDEP_ROLE_MASK_SINK 0x02
+typedef uint8_t tBTA_HL_MDEP_ROLE_MASK;
+
+#define BTA_HL_ECHO_TEST_MDEP_ID 0
+#define BTA_HL_ECHO_TEST_MDEP_CFG_IDX 0
+
+#define BTA_HL_INVALID_MDEP_ID 0xFF
+typedef tMCA_DEP tBTA_HL_MDEP_ID; /* 0 is for echo test,
+                                   0x01-0x7F availave for use,
+                                   0x80-0xFF reserved*/
+
+#define BTA_HL_DELETE_ALL_MDL_IDS 0xFFFF
+#define BTA_HL_MAX_MDL_VAL 0xFEFF
+typedef uint16_t tBTA_HL_MDL_ID; /* 0x0000 reserved,
+                                  0x0001-0xFEFF dynamic range,
+                                  0xFF00-0xFFFE reserved,
+                                  0xFFFF indicates all MDLs*/
+
+#define BTA_HL_MDEP_DESP_LEN 35
+
+#define BTA_HL_DCH_MODE_RELIABLE 0
+#define BTA_HL_DCH_MODE_STREAMING 1
+
+typedef uint8_t tBTA_HL_DCH_MODE;
+
+#define BTA_HL_DCH_CFG_NO_PREF 0
+#define BTA_HL_DCH_CFG_RELIABLE 1
+#define BTA_HL_DCH_CFG_STREAMING 2
+#define BTA_HL_DCH_CFG_UNKNOWN 0xFF
+
+typedef uint8_t tBTA_HL_DCH_CFG;
+
+/* The Default DCH CFG for the echo test when the device is a Source */
+#define BTA_HL_DEFAULT_ECHO_TEST_SRC_DCH_CFG BTA_HL_DCH_CFG_RELIABLE
+
+#define BTA_HL_DCH_CREATE_RSP_SUCCESS 0
+#define BTA_HL_DCH_CREATE_RSP_CFG_REJ 1
+
+typedef uint8_t tBTA_HL_DCH_CREATE_RSP;
+
+#define BTA_HL_MCAP_SUP_PROC_RECONNECT_INIT 0x02
+#define BTA_HL_MCAP_SUP_PROC_RECONNECT_APT 0x04
+#define BTA_HL_MCAP_SUP_PROC_CSP_SLAVE 0x08
+#define BTA_HL_MCAP_SUP_PROC_CSP_MASTER 0x10
+
+typedef uint8_t tBTA_HL_SUP_PROC_MASK;
+
+typedef struct {
+  uint16_t max_rx_apdu_size; /* local rcv MTU */
+  uint16_t max_tx_apdu_size; /* maximum TX APDU size*/
+} tBTA_HL_ECHO_CFG;
+
+typedef struct {
+  uint16_t data_type;
+  uint16_t max_rx_apdu_size; /* local rcv MTU */
+  uint16_t max_tx_apdu_size; /* maximum TX APDU size*/
+  char desp[BTA_HL_MDEP_DESP_LEN + 1];
+} tBTA_HL_MDEP_DATA_TYPE_CFG;
+
+typedef struct {
+  tBTA_HL_MDEP_ROLE mdep_role;
+  uint8_t num_of_mdep_data_types;
+  tBTA_HL_MDEP_DATA_TYPE_CFG data_cfg[BTA_HL_NUM_DATA_TYPES];
+} tBTA_HL_MDEP_CFG;
+
+typedef struct {
+  tBTA_HL_MDEP_ID mdep_id; /* MDEP ID 0x01-0x7F */
+  tBTA_HL_MDEP_CFG mdep_cfg;
+  uint8_t ori_app_id;
+} tBTA_HL_MDEP;
+
+typedef struct {
+  tBTA_HL_MDEP mdep[BTA_HL_NUM_MDEPS];
+  tBTA_HL_ECHO_CFG echo_cfg;
+  tBTA_HL_MDEP_ROLE_MASK app_role_mask;
+  bool advertize_source_sdp;
+  uint8_t num_of_mdeps;
+} tBTA_HL_SUP_FEATURE;
+
+typedef struct {
+  bool delete_req_pending;
+  tBTA_HL_MDL_ID mdl_id;
+  tBTA_HL_MCL_HANDLE mcl_handle;
+} tBTA_HL_DELETE_MDL;
+
+typedef struct {
+  uint8_t time;
+  uint16_t mtu;
+  tBTA_HL_MDL_ID mdl_id;
+  tBTA_HL_MDEP_ID local_mdep_id;
+  tBTA_HL_MDEP_ROLE local_mdep_role;
+  bool active; /* true if this item is in use */
+  tBTA_HL_DCH_MODE dch_mode;
+  uint8_t fcs;
+  BD_ADDR peer_bd_addr;
+} tBTA_HL_MDL_CFG;
+
+/* Maximum number of supported feature list items (list_elem in
+ * tSDP_SUP_FEATURE_ELEM) */
+#define BTA_HL_NUM_SUP_FEATURE_ELEMS 13
+#define BTA_HL_SUP_FEATURE_SDP_BUF_SIZE 512
+/* This structure is used to add supported feature lists and find supported
+ * feature elements */
+typedef struct {
+  uint8_t mdep_id;
+  uint16_t data_type;
+  tBTA_HL_MDEP_ROLE mdep_role;
+  char* p_mdep_desp;
+} tBTA_HL_SUP_FEATURE_ELEM;
+
+typedef struct {
+  uint16_t num_elems;
+  tBTA_HL_SUP_FEATURE_ELEM list_elem[BTA_HL_NUM_SUP_FEATURE_ELEMS];
+} tBTA_HL_SUP_FEATURE_LIST_ELEM;
+
+typedef struct {
+  tBTA_HL_DEVICE_TYPE dev_type; /* sink, source or dual roles */
+  tBTA_SEC sec_mask;            /* security mask for accepting conenction*/
+  const char*
+      p_srv_name; /* service name to be used in the SDP; null terminated*/
+  const char* p_srv_desp; /* service description to be used in the SDP; null
+                             terminated */
+  const char*
+      p_provider_name; /* provide name to be used in the SDP; null terminated */
+} tBTA_HL_REG_PARAM;
+
+typedef struct {
+  uint16_t ctrl_psm;
+  BD_ADDR bd_addr;   /* Address of peer device */
+  tBTA_SEC sec_mask; /* security mask for initiating connection*/
+} tBTA_HL_CCH_OPEN_PARAM;
+
+typedef struct {
+  uint16_t ctrl_psm;
+  tBTA_HL_MDEP_ID local_mdep_id; /* local MDEP ID */
+  tBTA_HL_MDEP_ID peer_mdep_id;  /* peer mdep id */
+  tBTA_HL_DCH_CFG local_cfg;
+  tBTA_SEC sec_mask; /* security mask for initiating connection*/
+} tBTA_HL_DCH_OPEN_PARAM;
+
+typedef struct {
+  uint16_t ctrl_psm;
+  tBTA_HL_MDL_ID mdl_id;
+} tBTA_HL_DCH_RECONNECT_PARAM;
+
+typedef struct {
+  uint16_t ctrl_psm;
+  uint16_t pkt_size;
+  tBTA_HL_DCH_CFG local_cfg;
+} tBTA_HL_DCH_ECHO_TEST_PARAM;
+
+typedef struct {
+  uint16_t buf_size;
+  uint8_t p_buf; /* buffer pointer */
+} tBTA_HL_DCH_BUF_INFO;
+
+typedef struct {
+  tBTA_HL_MDEP_ID local_mdep_id; /* local MDEP ID */
+  tBTA_HL_MDL_ID mdl_id;
+  tBTA_HL_DCH_CREATE_RSP rsp_code;
+  tBTA_HL_DCH_CFG cfg_rsp;
+} tBTA_HL_DCH_CREATE_RSP_PARAM;
+
+typedef struct {
+  uint16_t data_type;
+  uint8_t mdep_id;
+  tBTA_HL_MDEP_ROLE mdep_role;
+  char mdep_desp[BTA_HL_MDEP_DESP_LEN + 1];
+} tBTA_HL_SDP_MDEP_CFG;
+
+typedef struct {
+  uint16_t ctrl_psm;
+  uint16_t data_psm;
+  uint8_t mcap_sup_proc;
+  uint8_t num_mdeps; /* number of mdep elements from SDP*/
+  char srv_name[BTA_SERVICE_NAME_LEN + 1];
+  char srv_desp[BTA_SERVICE_DESP_LEN + 1];
+  char provider_name[BTA_PROVIDER_NAME_LEN + 1];
+  tBTA_HL_SDP_MDEP_CFG mdep_cfg[BTA_HL_NUM_SDP_MDEPS];
+} tBTA_HL_SDP_REC;
+
+typedef struct {
+  uint8_t num_recs;
+  tBTA_HL_SDP_REC sdp_rec[BTA_HL_NUM_SDP_RECS];
+} tBTA_HL_SDP;
+
+/* HL control callback function events */
+enum { BTA_HL_CTRL_ENABLE_CFM_EVT = 0, BTA_HL_CTRL_DISABLE_CFM_EVT };
+typedef uint8_t tBTA_HL_CTRL_EVT;
+/* Structure associated with BTA_HL_ENABLE_EVT
+   BTA_HL_DISABLE_EVT */
+
+typedef struct { tBTA_HL_STATUS status; } tBTA_HL_CTRL_ENABLE_DISABLE;
+
+typedef union {
+  tBTA_HL_CTRL_ENABLE_DISABLE enable_cfm;
+  tBTA_HL_CTRL_ENABLE_DISABLE disable_cfm;
+} tBTA_HL_CTRL;
+
+/* HL instance callback function events */
+enum {
+  BTA_HL_REGISTER_CFM_EVT = 0,
+  BTA_HL_DEREGISTER_CFM_EVT,
+  BTA_HL_CCH_OPEN_IND_EVT,
+  BTA_HL_CCH_OPEN_CFM_EVT,
+  BTA_HL_CCH_CLOSE_IND_EVT,
+  BTA_HL_CCH_CLOSE_CFM_EVT,
+  BTA_HL_DCH_CREATE_IND_EVT,
+  BTA_HL_DCH_OPEN_IND_EVT,
+  BTA_HL_DCH_OPEN_CFM_EVT,
+  BTA_HL_DCH_CLOSE_IND_EVT,
+  BTA_HL_DCH_CLOSE_CFM_EVT,
+  BTA_HL_DCH_RECONNECT_IND_EVT,
+  BTA_HL_DCH_RECONNECT_CFM_EVT,
+
+  BTA_HL_DCH_ABORT_IND_EVT,
+  BTA_HL_DCH_ABORT_CFM_EVT,
+  BTA_HL_DELETE_MDL_IND_EVT,
+  BTA_HL_DELETE_MDL_CFM_EVT,
+  BTA_HL_DCH_SEND_DATA_CFM_EVT,
+  BTA_HL_DCH_RCV_DATA_IND_EVT,
+  BTA_HL_CONG_CHG_IND_EVT,
+  BTA_HL_DCH_ECHO_TEST_CFM_EVT,
+  BTA_HL_SDP_QUERY_CFM_EVT,
+  BTA_HL_SDP_INFO_IND_EVT
+};
+typedef uint8_t tBTA_HL_EVT;
+
+typedef struct {
+  tBTA_HL_STATUS status; /* start status */
+  uint8_t app_id;
+  tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_REGISTER_CFM;
+
+typedef struct {
+  tBTA_HL_STATUS status; /* start status */
+  uint8_t app_id;
+  tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_DEREGISTER_CFM;
+
+typedef struct {
+  bool intentional;
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_CCH_CLOSE_IND;
+
+typedef struct {
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_MCL_IND;
+
+typedef struct {
+  tBTA_HL_STATUS status; /* connection status */
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_MCL_CFM;
+
+typedef struct {
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  tBTA_HL_APP_HANDLE app_handle;
+  BD_ADDR bd_addr; /* address of peer device */
+} tBTA_HL_CCH_OPEN_IND;
+
+typedef struct {
+  tBTA_HL_STATUS status; /* connection status */
+  uint8_t app_id;
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  tBTA_HL_APP_HANDLE app_handle;
+  BD_ADDR bd_addr; /* address of peer device */
+} tBTA_HL_CCH_OPEN_CFM;
+
+typedef struct {
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  tBTA_HL_APP_HANDLE app_handle;
+  tBTA_HL_MDEP_ID local_mdep_id;
+  tBTA_HL_MDL_ID mdl_id; /* MCAP data link ID for this
+                            data channel conenction    */
+  tBTA_HL_DCH_CFG cfg;   /* dch cfg requested by the peer device */
+  BD_ADDR bd_addr;       /* address of peer device */
+
+} tBTA_HL_DCH_CREATE_IND;
+
+typedef struct {
+  tBTA_HL_MDL_HANDLE mdl_handle;
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  tBTA_HL_APP_HANDLE app_handle;
+  tBTA_HL_MDEP_ID local_mdep_id;
+  tBTA_HL_MDL_ID mdl_id;     /* MCAP data link ID for this
+                                data channel conenction    */
+  tBTA_HL_DCH_MODE dch_mode; /* data channel mode - reliable or streaming*/
+
+  bool first_reliable; /* whether this is the first reliable data channel */
+  uint16_t mtu;
+} tBTA_HL_DCH_OPEN_IND;
+
+typedef struct {
+  tBTA_HL_STATUS status; /* connection status */
+  tBTA_HL_MDL_HANDLE mdl_handle;
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  tBTA_HL_APP_HANDLE app_handle;
+  tBTA_HL_MDEP_ID local_mdep_id;
+  tBTA_HL_MDL_ID mdl_id;     /* MCAP data link ID for this
+                                data channel conenction    */
+  tBTA_HL_DCH_MODE dch_mode; /* data channel mode - reliable or streaming*/
+  bool first_reliable; /* whether this is the first reliable data channel */
+  uint16_t mtu;
+} tBTA_HL_DCH_OPEN_CFM;
+
+typedef struct {
+  bool intentional;
+  tBTA_HL_MDL_HANDLE mdl_handle;
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_DCH_CLOSE_IND;
+
+typedef struct {
+  tBTA_HL_MDL_HANDLE mdl_handle;
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_MDL_IND;
+
+typedef struct {
+  tBTA_HL_STATUS status;
+  tBTA_HL_MDL_HANDLE mdl_handle;
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_MDL_CFM;
+
+typedef struct {
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  tBTA_HL_APP_HANDLE app_handle;
+  tBTA_HL_MDL_ID mdl_id;
+} tBTA_HL_DELETE_MDL_IND;
+
+typedef struct {
+  tBTA_HL_STATUS status;
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  tBTA_HL_APP_HANDLE app_handle;
+  tBTA_HL_MDL_ID mdl_id;
+} tBTA_HL_DELETE_MDL_CFM;
+
+typedef struct {
+  tBTA_HL_MDL_HANDLE mdl_handle;
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  tBTA_HL_APP_HANDLE app_handle;
+  bool cong;
+} tBTA_HL_DCH_CONG_IND;
+
+typedef struct {
+  tBTA_HL_APP_HANDLE app_handle;
+  uint16_t ctrl_psm;
+  uint16_t data_psm;
+  uint8_t data_x_spec;
+  uint8_t mcap_sup_procs;
+} tBTA_HL_SDP_INFO_IND;
+
+typedef struct {
+  tBTA_HL_STATUS status;
+  uint8_t app_id;
+  tBTA_HL_APP_HANDLE app_handle;
+  BD_ADDR bd_addr;
+  tBTA_HL_SDP* p_sdp;
+} tBTA_HL_SDP_QUERY_CFM;
+
+typedef union {
+  tBTA_HL_REGISTER_CFM reg_cfm;
+  tBTA_HL_DEREGISTER_CFM dereg_cfm;
+  tBTA_HL_CCH_OPEN_IND cch_open_ind;
+  tBTA_HL_CCH_OPEN_CFM cch_open_cfm;
+  tBTA_HL_CCH_CLOSE_IND cch_close_ind;
+  tBTA_HL_MCL_CFM cch_close_cfm;
+  tBTA_HL_DCH_CREATE_IND dch_create_ind;
+  tBTA_HL_DCH_OPEN_IND dch_open_ind;
+  tBTA_HL_DCH_OPEN_CFM dch_open_cfm;
+  tBTA_HL_DCH_CLOSE_IND dch_close_ind;
+  tBTA_HL_MDL_CFM dch_close_cfm;
+  tBTA_HL_DCH_OPEN_IND dch_reconnect_ind;
+  tBTA_HL_DCH_OPEN_CFM dch_reconnect_cfm;
+  tBTA_HL_MCL_IND dch_abort_ind;
+  tBTA_HL_MCL_CFM dch_abort_cfm;
+  tBTA_HL_DELETE_MDL_IND delete_mdl_ind;
+  tBTA_HL_DELETE_MDL_CFM delete_mdl_cfm;
+  tBTA_HL_MDL_CFM dch_send_data_cfm;
+  tBTA_HL_MDL_IND dch_rcv_data_ind;
+  tBTA_HL_DCH_CONG_IND dch_cong_ind;
+  tBTA_HL_MCL_CFM echo_test_cfm;
+  tBTA_HL_SDP_QUERY_CFM sdp_query_cfm;
+  tBTA_HL_SDP_INFO_IND sdp_info_ind;
+
+} tBTA_HL;
+
+/* HL callback functions */
+typedef void tBTA_HL_CTRL_CBACK(tBTA_HL_CTRL_EVT event, tBTA_HL_CTRL* p_data);
+typedef void tBTA_HL_CBACK(tBTA_HL_EVT event, tBTA_HL* p_data);
+
+/*****************************************************************************
+ *  External Function Declarations
+ ****************************************************************************/
+
+/**************************
+ *  API Functions
+ **************************/
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlEnable
+ *
+ * Description      Enable the HL subsystems.  This function must be
+ *                  called before any other functions in the HL API are called.
+ *                  When the enable operation is completed the callback function
+ *                  will be called with an BTA_HL_CTRL_ENABLE_CFM_EVT event.
+ *
+ * Parameters       p_cback - HL event call back function
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HlEnable(tBTA_HL_CTRL_CBACK* p_ctrl_cback);
+/*******************************************************************************
+ *
+ * Function         BTA_HlDisable
+ *
+ * Description     Disable the HL subsystem.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HlDisable(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlUpdate
+ *
+ * Description      Register an HDP application
+ *
+ * Parameters       app_id        - Application ID
+ *                  p_reg_param   - non-platform related parameters for the
+ *                                  HDP application
+ *                  p_cback       - HL event callback fucntion
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HlUpdate(uint8_t app_id, tBTA_HL_REG_PARAM* p_reg_param,
+                         bool is_register, tBTA_HL_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlRegister
+ *
+ * Description      Register a HDP application
+ *
+ *
+ * Parameters       app_id        - hdp application ID
+ *                  p_reg_param   - non-platform related parameters for the
+ *                                  HDP application
+ *                  p_cback       - HL event callback fucntion
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HlRegister(uint8_t app_id, tBTA_HL_REG_PARAM* p_reg_param,
+                           tBTA_HL_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlDeregister
+ *
+ * Description      Deregister an HDP application
+ *
+ * Parameters       app_handle - Application handle
+ *
+ * Returns         void
+ *
+ ******************************************************************************/
+extern void BTA_HlDeregister(uint8_t app_id, tBTA_HL_APP_HANDLE app_handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlCchOpen
+ *
+ * Description      Open a Control channel connection with the specified BD
+ *                  address and the control PSM value is used to select which
+ *                  HDP insatnce should be used in case the peer device support
+ *                  multiple HDP instances.
+ *
+ *
+ * Parameters       app_handle - Application Handle
+ *                  p_open_param - parameters for opening a control channel
+ *
+ * Returns          void
+ *
+ *                  Note: If the control PSM value is zero then the first HDP
+ *                        instance is used for the control channel setup
+ ******************************************************************************/
+extern void BTA_HlCchOpen(uint8_t app_id, tBTA_HL_APP_HANDLE app_handle,
+                          tBTA_HL_CCH_OPEN_PARAM* p_open_param);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlCchClose
+ *
+ * Description      Close a Control channel connection with the specified MCL
+ *                  handle
+ *
+ * Parameters       mcl_handle - MCL handle
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HlCchClose(tBTA_HL_MCL_HANDLE mcl_handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlDchOpen
+ *
+ * Description      Open a data channel connection with the specified DCH
+ *                  parameters
+ *
+ * Parameters       mcl_handle - MCL handle
+ *                  p_open_param - parameters for opening a data channel
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HlDchOpen(tBTA_HL_MCL_HANDLE mcl_handle,
+                          tBTA_HL_DCH_OPEN_PARAM* p_open_param);
+/*******************************************************************************
+ *
+ * Function         BTA_HlDchReconnect
+ *
+ * Description      Reconnect a data channel with the specified MDL_ID
+ *
+ * Parameters       mcl_handle      - MCL handle
+*8                  p_recon_param   - parameters for reconnecting a data channel
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HlDchReconnect(tBTA_HL_MCL_HANDLE mcl_handle,
+                               tBTA_HL_DCH_RECONNECT_PARAM* p_recon_param);
+/*******************************************************************************
+ *
+ * Function         BTA_HlDchClose
+ *
+ * Description      Close a data channel with the specified MDL handle
+ *
+ * Parameters       mdl_handle  - MDL handle
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HlDchClose(tBTA_HL_MDL_HANDLE mdl_handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlDchAbort
+ *
+ * Description      Abort the current data channel setup with the specified MCL
+ *                  handle
+ *
+ * Parameters       mcl_handle  - MCL handle
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HlDchAbort(tBTA_HL_MCL_HANDLE mcl_handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlSendData
+ *
+ * Description      Send an APDU to the peer device
+ *
+ * Parameters       mdl_handle  - MDL handle
+ *                  pkt_size    - size of the data packet to be sent
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HlSendData(tBTA_HL_MDL_HANDLE mdl_handle, uint16_t pkt_size);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlDeleteMdl
+ *
+ * Description      Delete the specified MDL_ID within the specified MCL handle
+ *
+ * Parameters       mcl_handle  - MCL handle
+ *                  mdl_id      - MDL ID
+ *
+ * Returns          void
+ *
+ *                  note: If mdl_id = 0xFFFF then this means to delete all MDLs
+ *                        and this value can only be used with DeleteMdl request
+ *                        only not other requests
+ *
+ ******************************************************************************/
+extern void BTA_HlDeleteMdl(tBTA_HL_MCL_HANDLE mcl_handle,
+                            tBTA_HL_MDL_ID mdl_id);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlDchEchoTest
+ *
+ * Description      Initiate an echo test with the specified MCL handle
+ *
+ * Parameters       mcl_handle           - MCL handle
+*8                  p_echo_test_param   -  parameters for echo testing
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HlDchEchoTest(tBTA_HL_MCL_HANDLE mcl_handle,
+                              tBTA_HL_DCH_ECHO_TEST_PARAM* p_echo_test_param);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlSdpQuery
+ *
+ * Description      SDP query request for the specified BD address
+ *
+ * Parameters       app_id
+                        app_handle      - application handle
+ *                  bd_addr         - BD address
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HlSdpQuery(uint8_t app_id, tBTA_HL_APP_HANDLE app_handle,
+                           BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         BTA_HlDchCreateMdlRsp
+ *
+ * Description      Set the Response and configuration values for the Create MDL
+ *                  request
+ *
+ * Parameters       mcl_handle  - MCL handle
+ *                  p_rsp_param - parameters specified whether the request
+ *                                should be accepted or not and if it should be
+ *                                accepted then it also specified the
+ *                                configuration response value
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_HlDchCreateRsp(tBTA_HL_MCL_HANDLE mcl_handle,
+                               tBTA_HL_DCH_CREATE_RSP_PARAM* p_rsp_param);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_HL_API_H */
diff --git a/bt/bta/include/bta_hl_ci.h b/bt/bta/include/bta_hl_ci.h
new file mode 100644
index 0000000..f12ed12
--- /dev/null
+++ b/bt/bta/include/bta_hl_ci.h
@@ -0,0 +1,124 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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 is the interface file for the HL (HeaLth device profile) subsystem
+ *  call-in functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_HL_CI_H
+#define BTA_HL_CI_H
+
+#include "bta_api.h"
+#include "bta_hl_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+ *  Constants and Data Types
+ ****************************************************************************/
+/**************************
+ *  Common Definitions
+ **************************/
+/* Read Ready Event */
+/*****************************************************************************
+ *  Function Declarations
+ ****************************************************************************/
+/**************************
+ *  Common Functions
+ **************************/
+/*******************************************************************************
+ *
+ * Function         bta_hl_ci_get_tx_data
+ *
+ * Description      This function is called in response to the
+ *                  bta_hl_co_get_tx_data call-out function.
+ *
+ * Parameters       mdl_handle -MDL handle
+ *                  status - BTA_MA_STATUS_OK if operation is successful
+ *                           BTA_MA_STATUS_FAIL if any errors have occurred.
+ *                  evt    - evt from the call-out function
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hl_ci_get_tx_data(tBTA_HL_MDL_HANDLE mdl_handle,
+                                  tBTA_HL_STATUS status, uint16_t evt);
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_ci_put_rx_data
+ *
+ * Description      This function is called in response to the
+ *                  bta_hl_co_put_rx_data call-out function.
+ *
+ * Parameters       mdl_handle -MDL handle
+ *                  status - BTA_MA_STATUS_OK if operation is successful
+ *                           BTA_MA_STATUS_FAIL if any errors have occurred.
+ *                  evt    - evt from the call-out function
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hl_ci_put_rx_data(tBTA_HL_MDL_HANDLE mdl_handle,
+                                  tBTA_HL_STATUS status, uint16_t evt);
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_ci_get_echo_data
+ *
+ * Description      This function is called in response to the
+ *                  bta_hl_co_get_echo_data call-out function.
+ *
+ * Parameters       mcl_handle -MCL handle
+ *                  status - BTA_MA_STATUS_OK if operation is successful
+ *                           BTA_MA_STATUS_FAIL if any errors have occurred.
+ *                  evt    - evt from the call-out function
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hl_ci_get_echo_data(tBTA_HL_MCL_HANDLE mcl_handle,
+                                    tBTA_HL_STATUS status, uint16_t evt);
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_ci_put_echo_data
+ *
+ * Description      This function is called in response to the
+ *                  bta_hl_co_put_echo_data call-out function.
+ *
+ * Parameters       mcl_handle -MCL handle
+ *                  status - BTA_MA_STATUS_OK if operation is successful
+ *                           BTA_MA_STATUS_FAIL if any errors have occurred.
+ *                  evt    - evt from the call-out function
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hl_ci_put_echo_data(tBTA_HL_MCL_HANDLE mcl_handle,
+                                    tBTA_HL_STATUS status, uint16_t evt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_HL_CI_H */
diff --git a/bt/bta/include/bta_hl_co.h b/bt/bta/include/bta_hl_co.h
new file mode 100644
index 0000000..efdd1d3
--- /dev/null
+++ b/bt/bta/include/bta_hl_co.h
@@ -0,0 +1,248 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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 is the interface file for the HL (HeaLth device profile) subsystem
+ *  call-out functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_HL_CO_H
+#define BTA_HL_CO_H
+
+#include "bta_api.h"
+#include "bta_hl_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+ *  Constants and Data Types
+ ****************************************************************************/
+/**************************
+ *  Common Definitions
+ **************************/
+
+/*******************************************************************************
+ *
+ * Function        bta_hl_co_get_num_of_mdep
+ *
+ * Description     This function is called to get the number of MDEPs for this
+ *                 application ID
+ *
+ * Parameters      app_id - application ID
+ *                 p_num_of_mdep (output) - number of MDEP configurations
+ *                                          supported
+ *                                          by the application
+ *
+ * Returns         Bloolean - true success
+ *
+ ******************************************************************************/
+extern bool bta_hl_co_get_num_of_mdep(uint8_t app_id, uint8_t* p_num_of_mdep);
+/*******************************************************************************
+ *
+ * Function        bta_hl_co_advrtise_source_sdp
+ *
+ * Description     This function is called to find out whether the SOURCE MDEP
+ *                 configuration information should be advertize in the SDP or
+ *                 not
+ *
+ * Parameters      app_id - application ID
+ *
+ * Returns         Bloolean - true advertise the SOURCE MDEP configuration
+ *                            information
+ *
+ ******************************************************************************/
+extern bool bta_hl_co_advrtise_source_sdp(uint8_t app_id);
+/*******************************************************************************
+ *
+ * Function        bta_hl_co_get_mdep_config
+ *
+ * Description     This function is called to get the supported feature
+ *                 configuration for the specified mdep index and it also
+ *                 assigns
+ *                 the MDEP ID for the specified mdep index
+ *
+ * Parameters      app_id - HDP application ID
+ *                 mdep_idx - the mdep index
+ *                  mdep_counter - mdep_counter
+ *                 mdep_id  - the assigned MDEP ID for the specified medp_idx
+ *                 p_mdl_cfg (output) - pointer to the MDEP configuration
+ *
+ *
+ * Returns         Bloolean - true success
+ ******************************************************************************/
+extern bool bta_hl_co_get_mdep_config(uint8_t app_id, uint8_t mdep_idx,
+                                      uint8_t mdep_counter,
+                                      tBTA_HL_MDEP_ID mdep_id,
+                                      tBTA_HL_MDEP_CFG* p_mdep_cfg);
+
+/*******************************************************************************
+ *
+ * Function        bta_hl_co_get_echo_config
+ *
+ * Description     This function is called to get the echo test
+ *                 maximum APDU size configuration
+ *
+ * Parameters      app_id - HDP application ID
+ *                 p_echo_cfg (output) - pointer to the Echo test maximum APDU
+ *                                       size configuration
+ *
+ * Returns         Bloolean - true success
+ ******************************************************************************/
+extern bool bta_hl_co_get_echo_config(uint8_t app_id,
+                                      tBTA_HL_ECHO_CFG* p_echo_cfg);
+
+/*******************************************************************************
+ *
+ * Function        bta_hl_co_save_mdl
+ *
+ * Description     This function is called to save a MDL configuration item in
+ *                 persistent storage
+ *
+ * Parameters      app_id - HDP application ID
+ *                 item_idx - the MDL configuration storage index
+ *                 p_mdl_cfg - pointer to the MDL configuration data
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hl_co_save_mdl(uint8_t app_id, uint8_t item_idx,
+                               tBTA_HL_MDL_CFG* p_mdl_cfg);
+/*******************************************************************************
+ *
+ * Function        bta_hl_co_delete_mdl
+ *
+ * Description     This function is called to delete a MDL configuration item in
+ *                 persistent storage
+ *
+ * Parameters      app_id - HDP application ID
+ *                 item_idx - the MDL configuration storage index
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_hl_co_delete_mdl(uint8_t app_id, uint8_t item_idx);
+/*******************************************************************************
+ *
+ * Function         bta_hl_co_get_mdl_config
+ *
+ * Description     This function is called to get the MDL configuration
+ *                 from teh persistent memory. This function shall only be
+*called
+*8                 once after the device is powered up
+ *
+ * Parameters      app_id - HDP application ID
+ *                 buffer_size - the unit of the buffer size is
+*sizeof(tBTA_HL_MDL_CFG)
+ *                 p_mdl_buf - Point to the starting location of the buffer
+ *
+ * Returns         bool
+ *
+ *
+ ******************************************************************************/
+extern bool bta_hl_co_load_mdl_config(uint8_t app_id, uint8_t buffer_size,
+                                      tBTA_HL_MDL_CFG* p_mdl_buf);
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_co_get_tx_data
+ *
+ * Description     Get the data to be sent
+ *
+ * Parameters      app_id - HDP application ID
+ *                 mdl_handle - MDL handle
+ *                 buf_size - the size of the buffer
+ *                 p_buf - the buffer pointer
+ *                 evt - the evt to be passed back to the HL in the
+ *                       bta_hl_ci_get_tx_data call-in function
+ *
+ * Returns        Void
+ *
+ ******************************************************************************/
+extern void bta_hl_co_get_tx_data(uint8_t app_id, tBTA_HL_MDL_HANDLE mdl_handle,
+                                  uint16_t buf_size, uint8_t* p_buf,
+                                  uint16_t evt);
+
+/*******************************************************************************
+ *
+ * Function        bta_hl_co_put_rx_data
+ *
+ * Description     Put the received data
+ *
+ * Parameters      app_id - HDP application ID
+ *                 mdl_handle - MDL handle
+ *                 data_size - the size of the data
+ *                 p_data - the data pointer
+ *                 evt - the evt to be passed back to the HL in the
+ *                       bta_hl_ci_put_rx_data call-in function
+ *
+ * Returns        Void
+ *
+ ******************************************************************************/
+extern void bta_hl_co_put_rx_data(uint8_t app_id, tBTA_HL_MDL_HANDLE mdl_handle,
+                                  uint16_t data_size, uint8_t* p_data,
+                                  uint16_t evt);
+/*******************************************************************************
+ *
+ * Function         bta_hl_co_get_tx_data
+ *
+ * Description     Get the Echo data to be sent
+ *
+ * Parameters      app_id - HDP application ID
+ *                 mcl_handle - MCL handle
+ *                 buf_size - the size of the buffer
+ *                 p_buf - the buffer pointer
+ *                 evt - the evt to be passed back to the HL in the
+ *                       bta_hl_ci_get_tx_data call-in function
+ *
+ * Returns        Void
+ *
+ ******************************************************************************/
+extern void bta_hl_co_get_echo_data(uint8_t app_id,
+                                    tBTA_HL_MCL_HANDLE mcl_handle,
+                                    uint16_t buf_size, uint8_t* p_buf,
+                                    uint16_t evt);
+
+/*******************************************************************************
+ *
+ * Function        bta_hl_co_put_echo_data
+ *
+ * Description     Put the received loopback echo data
+ *
+ * Parameters      app_id - HDP application ID
+ *                 mcl_handle - MCL handle
+ *                 data_size - the size of the data
+ *                 p_data - the data pointer
+ *                 evt - the evt to be passed back to the HL in the
+ *                       bta_hl_ci_put_echo_data call-in function
+ *
+ * Returns        Void
+ *
+ ******************************************************************************/
+extern void bta_hl_co_put_echo_data(uint8_t app_id,
+                                    tBTA_HL_MCL_HANDLE mcl_handle,
+                                    uint16_t data_size, uint8_t* p_data,
+                                    uint16_t evt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_HL_CO_H */
diff --git a/bt/bta/include/bta_jv_api.h b/bt/bta/include/bta_jv_api.h
new file mode 100644
index 0000000..6d55df3
--- /dev/null
+++ b/bt/bta/include/bta_jv_api.h
@@ -0,0 +1,833 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2006-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 is the public interface file the BTA Java I/F
+ *
+ ******************************************************************************/
+#ifndef BTA_JV_API_H
+#define BTA_JV_API_H
+
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bta_api.h"
+#include "btm_api.h"
+#include "l2c_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+ *  Constants and data types
+ ****************************************************************************/
+/* status values */
+#define BTA_JV_SUCCESS 0     /* Successful operation. */
+#define BTA_JV_FAILURE 1     /* Generic failure. */
+#define BTA_JV_BUSY 2        /* Temporarily can not handle this request. */
+#define BTA_JV_NO_DATA 3     /* no data. */
+#define BTA_JV_NO_RESOURCE 4 /* No more set pm control block */
+
+typedef uint8_t tBTA_JV_STATUS;
+#define BTA_JV_INTERNAL_ERR (-1) /* internal error. */
+
+#define BTA_JV_MAX_UUIDS SDP_MAX_UUID_FILTERS
+#define BTA_JV_MAX_ATTRS SDP_MAX_ATTR_FILTERS
+#define BTA_JV_MAX_SDP_REC SDP_MAX_RECORDS
+#define BTA_JV_MAX_L2C_CONN                                                    \
+  GAP_MAX_CONNECTIONS /* GAP handle is used as index, hence do not change this \
+                         value */
+#define BTA_JV_MAX_SCN \
+  PORT_MAX_RFC_PORTS /* same as BTM_MAX_SCN (in btm_int.h) */
+#define BTA_JV_MAX_RFC_CONN MAX_RFC_PORTS
+
+#ifndef BTA_JV_DEF_RFC_MTU
+#define BTA_JV_DEF_RFC_MTU (3 * 330)
+#endif
+
+#ifndef BTA_JV_MAX_RFC_SR_SESSION
+#define BTA_JV_MAX_RFC_SR_SESSION MAX_BD_CONNECTIONS
+#endif
+
+/* BTA_JV_MAX_RFC_SR_SESSION can not be bigger than MAX_BD_CONNECTIONS */
+#if (BTA_JV_MAX_RFC_SR_SESSION > MAX_BD_CONNECTIONS)
+#undef BTA_JV_MAX_RFC_SR_SESSION
+#define BTA_JV_MAX_RFC_SR_SESSION MAX_BD_CONNECTIONS
+#endif
+
+#define BTA_JV_FIRST_SERVICE_ID BTA_FIRST_JV_SERVICE_ID
+#define BTA_JV_LAST_SERVICE_ID BTA_LAST_JV_SERVICE_ID
+#define BTA_JV_NUM_SERVICE_ID \
+  (BTA_LAST_JV_SERVICE_ID - BTA_FIRST_JV_SERVICE_ID + 1)
+
+/* Discoverable modes */
+enum { BTA_JV_DISC_NONE, BTA_JV_DISC_LIMITED, BTA_JV_DISC_GENERAL };
+typedef uint16_t tBTA_JV_DISC;
+
+#define BTA_JV_ROLE_SLAVE BTM_ROLE_SLAVE
+#define BTA_JV_ROLE_MASTER BTM_ROLE_MASTER
+typedef uint32_t tBTA_JV_ROLE;
+
+#define BTA_JV_SERVICE_LMTD_DISCOVER                                       \
+  BTM_COD_SERVICE_LMTD_DISCOVER                                  /* 0x0020 \
+                                                                    */
+#define BTA_JV_SERVICE_POSITIONING BTM_COD_SERVICE_POSITIONING   /* 0x0100 */
+#define BTA_JV_SERVICE_NETWORKING BTM_COD_SERVICE_NETWORKING     /* 0x0200 */
+#define BTA_JV_SERVICE_RENDERING BTM_COD_SERVICE_RENDERING       /* 0x0400 */
+#define BTA_JV_SERVICE_CAPTURING BTM_COD_SERVICE_CAPTURING       /* 0x0800 */
+#define BTA_JV_SERVICE_OBJ_TRANSFER BTM_COD_SERVICE_OBJ_TRANSFER /* 0x1000 */
+#define BTA_JV_SERVICE_AUDIO BTM_COD_SERVICE_AUDIO               /* 0x2000 */
+#define BTA_JV_SERVICE_TELEPHONY BTM_COD_SERVICE_TELEPHONY       /* 0x4000 */
+#define BTA_JV_SERVICE_INFORMATION BTM_COD_SERVICE_INFORMATION   /* 0x8000 */
+
+/* JV ID type */
+#define BTA_JV_PM_ID_1 1     /* PM example profile 1 */
+#define BTA_JV_PM_ID_2 2     /* PM example profile 2 */
+#define BTA_JV_PM_ID_CLEAR 0 /* Special JV ID used to clear PM profile */
+#define BTA_JV_PM_ALL 0xFF   /* Generic match all id, see bta_dm_cfg.c */
+typedef uint8_t tBTA_JV_PM_ID;
+
+#define BTA_JV_PM_HANDLE_CLEAR \
+  0xFF /* Special JV ID used to clear PM profile  */
+
+/* define maximum number of registered PM entities. should be in sync with bta
+ * pm! */
+#ifndef BTA_JV_PM_MAX_NUM
+#define BTA_JV_PM_MAX_NUM 5
+#endif
+
+/* JV pm connection states */
+enum {
+  BTA_JV_CONN_OPEN = 0, /* Connection opened state */
+  BTA_JV_CONN_CLOSE,    /* Connection closed state */
+  BTA_JV_APP_OPEN,      /* JV Application opened state */
+  BTA_JV_APP_CLOSE,     /* JV Application closed state */
+  BTA_JV_SCO_OPEN,      /* SCO connection opened state */
+  BTA_JV_SCO_CLOSE,     /* SCO connection opened state */
+  BTA_JV_CONN_IDLE,     /* Connection idle state */
+  BTA_JV_CONN_BUSY,     /* Connection busy state */
+  BTA_JV_MAX_CONN_STATE /* Max number of connection state */
+};
+typedef uint8_t tBTA_JV_CONN_STATE;
+
+/* JV Connection types */
+#define BTA_JV_CONN_TYPE_RFCOMM 0
+#define BTA_JV_CONN_TYPE_L2CAP 1
+#define BTA_JV_CONN_TYPE_L2CAP_LE 2
+
+/* Java I/F callback events */
+/* events received by tBTA_JV_DM_CBACK */
+#define BTA_JV_ENABLE_EVT 0         /* JV enabled */
+#define BTA_JV_GET_SCN_EVT 6        /* Reserved an SCN */
+#define BTA_JV_GET_PSM_EVT 7        /* Reserved a PSM */
+#define BTA_JV_DISCOVERY_COMP_EVT 8 /* SDP discovery complete */
+#define BTA_JV_CREATE_RECORD_EVT 11 /* the result for BTA_JvCreateRecord */
+/* events received by tBTA_JV_L2CAP_CBACK */
+#define BTA_JV_L2CAP_OPEN_EVT 16     /* open status of L2CAP connection */
+#define BTA_JV_L2CAP_CLOSE_EVT 17    /* L2CAP connection closed */
+#define BTA_JV_L2CAP_START_EVT 18    /* L2CAP server started */
+#define BTA_JV_L2CAP_CL_INIT_EVT 19  /* L2CAP client initiated a connection */
+#define BTA_JV_L2CAP_DATA_IND_EVT 20 /* L2CAP connection received data */
+#define BTA_JV_L2CAP_CONG_EVT \
+  21 /* L2CAP connection congestion status changed */
+#define BTA_JV_L2CAP_READ_EVT 22  /* the result for BTA_JvL2capRead */
+#define BTA_JV_L2CAP_WRITE_EVT 24 /* the result for BTA_JvL2capWrite*/
+#define BTA_JV_L2CAP_WRITE_FIXED_EVT \
+  25 /* the result for BTA_JvL2capWriteFixed */
+
+/* events received by tBTA_JV_RFCOMM_CBACK */
+#define BTA_JV_RFCOMM_OPEN_EVT                                                \
+  26                               /* open status of RFCOMM Client connection \
+                                      */
+#define BTA_JV_RFCOMM_CLOSE_EVT 27 /* RFCOMM connection closed */
+#define BTA_JV_RFCOMM_START_EVT 28 /* RFCOMM server started */
+#define BTA_JV_RFCOMM_CL_INIT_EVT                                             \
+  29                                  /* RFCOMM client initiated a connection \
+                                         */
+#define BTA_JV_RFCOMM_DATA_IND_EVT 30 /* RFCOMM connection received data */
+#define BTA_JV_RFCOMM_CONG_EVT \
+  31 /* RFCOMM connection congestion status changed */
+#define BTA_JV_RFCOMM_WRITE_EVT 33 /* the result for BTA_JvRfcommWrite*/
+#define BTA_JV_RFCOMM_SRV_OPEN_EVT \
+  34                      /* open status of Server RFCOMM connection */
+#define BTA_JV_MAX_EVT 35 /* max number of JV events */
+
+typedef uint16_t tBTA_JV_EVT;
+
+/* data associated with BTA_JV_SET_DISCOVER_EVT */
+typedef struct {
+  tBTA_JV_STATUS status;  /* Whether the operation succeeded or failed. */
+  tBTA_JV_DISC disc_mode; /* The current discoverable mode */
+} tBTA_JV_SET_DISCOVER;
+
+/* data associated with BTA_JV_DISCOVERY_COMP_EVT_ */
+typedef struct {
+  tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+  int scn;               /* channel # */
+} tBTA_JV_DISCOVERY_COMP;
+
+/* data associated with BTA_JV_CREATE_RECORD_EVT */
+typedef struct {
+  tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+} tBTA_JV_CREATE_RECORD;
+
+/* data associated with BTA_JV_L2CAP_OPEN_EVT */
+typedef struct {
+  tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+  uint32_t handle;       /* The connection handle */
+  BD_ADDR rem_bda;       /* The peer address */
+  int32_t tx_mtu;        /* The transmit MTU */
+} tBTA_JV_L2CAP_OPEN;
+
+/* data associated with BTA_JV_L2CAP_OPEN_EVT for LE sockets */
+typedef struct {
+  tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+  uint32_t handle;       /* The connection handle */
+  BD_ADDR rem_bda;       /* The peer address */
+  int32_t tx_mtu;        /* The transmit MTU */
+  void** p_p_cback;      /* set them for new socket */
+  void** p_user_data;    /* set them for new socket */
+
+} tBTA_JV_L2CAP_LE_OPEN;
+
+/* data associated with BTA_JV_L2CAP_CLOSE_EVT */
+typedef struct {
+  tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+  uint32_t handle;       /* The connection handle */
+  bool async;            /* false, if local initiates disconnect */
+} tBTA_JV_L2CAP_CLOSE;
+
+/* data associated with BTA_JV_L2CAP_START_EVT */
+typedef struct {
+  tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+  uint32_t handle;       /* The connection handle */
+  uint8_t sec_id;        /* security ID used by this server */
+} tBTA_JV_L2CAP_START;
+
+/* data associated with BTA_JV_L2CAP_CL_INIT_EVT */
+typedef struct {
+  tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+  uint32_t handle;       /* The connection handle */
+  uint8_t sec_id;        /* security ID used by this client */
+} tBTA_JV_L2CAP_CL_INIT;
+
+/* data associated with BTA_JV_L2CAP_CONG_EVT */
+typedef struct {
+  tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+  uint32_t handle;       /* The connection handle */
+  bool cong;             /* true, congested. false, uncongested */
+} tBTA_JV_L2CAP_CONG;
+
+/* data associated with BTA_JV_L2CAP_READ_EVT */
+typedef struct {
+  tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+  uint32_t handle;       /* The connection handle */
+  uint32_t req_id;       /* The req_id in the associated BTA_JvL2capRead() */
+  uint8_t* p_data;       /* This points the same location as the p_data
+                        * parameter in BTA_JvL2capRead () */
+  uint16_t len;          /* The length of the data read. */
+} tBTA_JV_L2CAP_READ;
+
+/* data associated with BTA_JV_L2CAP_WRITE_EVT */
+typedef struct {
+  tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+  uint32_t handle;       /* The connection handle */
+  uint32_t req_id;       /* The req_id in the associated BTA_JvL2capWrite() */
+  uint16_t len;          /* The length of the data written. */
+  bool cong;             /* congestion status */
+} tBTA_JV_L2CAP_WRITE;
+
+/* data associated with BTA_JV_L2CAP_WRITE_FIXED_EVT */
+typedef struct {
+  tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+  uint16_t channel;      /* The connection channel */
+  BD_ADDR addr;          /* The peer address */
+  uint32_t req_id;       /* The req_id in the associated BTA_JvL2capWrite() */
+  uint16_t len;          /* The length of the data written. */
+  bool cong;             /* congestion status */
+} tBTA_JV_L2CAP_WRITE_FIXED;
+
+/* data associated with BTA_JV_RFCOMM_OPEN_EVT */
+typedef struct {
+  tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+  uint32_t handle;       /* The connection handle */
+  BD_ADDR rem_bda;       /* The peer address */
+} tBTA_JV_RFCOMM_OPEN;
+/* data associated with BTA_JV_RFCOMM_SRV_OPEN_EVT */
+typedef struct {
+  tBTA_JV_STATUS status;      /* Whether the operation succeeded or failed. */
+  uint32_t handle;            /* The connection handle */
+  uint32_t new_listen_handle; /* The new listen handle */
+  BD_ADDR rem_bda;            /* The peer address */
+} tBTA_JV_RFCOMM_SRV_OPEN;
+
+/* data associated with BTA_JV_RFCOMM_CLOSE_EVT */
+typedef struct {
+  tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+  uint32_t port_status;  /* PORT status */
+  uint32_t handle;       /* The connection handle */
+  bool async;            /* false, if local initiates disconnect */
+} tBTA_JV_RFCOMM_CLOSE;
+
+/* data associated with BTA_JV_RFCOMM_START_EVT */
+typedef struct {
+  tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+  uint32_t handle;       /* The connection handle */
+  uint8_t sec_id;        /* security ID used by this server */
+  bool use_co;           /* true to use co_rfc_data */
+} tBTA_JV_RFCOMM_START;
+
+/* data associated with BTA_JV_RFCOMM_CL_INIT_EVT */
+typedef struct {
+  tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+  uint32_t handle;       /* The connection handle */
+  uint8_t sec_id;        /* security ID used by this client */
+  bool use_co;           /* true to use co_rfc_data */
+} tBTA_JV_RFCOMM_CL_INIT;
+/*data associated with BTA_JV_L2CAP_DATA_IND_EVT & BTA_JV_RFCOMM_DATA_IND_EVT */
+typedef struct {
+  uint32_t handle; /* The connection handle */
+} tBTA_JV_DATA_IND;
+
+/*data associated with BTA_JV_L2CAP_DATA_IND_EVT if used for LE */
+typedef struct {
+  uint32_t handle; /* The connection handle */
+  BT_HDR* p_buf;   /* The incoming data */
+} tBTA_JV_LE_DATA_IND;
+
+/* data associated with BTA_JV_RFCOMM_CONG_EVT */
+typedef struct {
+  tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+  uint32_t handle;       /* The connection handle */
+  bool cong;             /* true, congested. false, uncongested */
+} tBTA_JV_RFCOMM_CONG;
+
+/* data associated with BTA_JV_RFCOMM_WRITE_EVT */
+typedef struct {
+  tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+  uint32_t handle;       /* The connection handle */
+  uint32_t req_id;       /* The req_id in the associated BTA_JvRfcommWrite() */
+  int len;               /* The length of the data written. */
+  bool cong;             /* congestion status */
+} tBTA_JV_RFCOMM_WRITE;
+
+/* data associated with BTA_JV_API_SET_PM_PROFILE_EVT */
+typedef struct {
+  tBTA_JV_STATUS status; /* Status of the operation */
+  uint32_t handle;       /* Connection handle */
+  tBTA_JV_PM_ID app_id;  /* JV app ID */
+} tBTA_JV_SET_PM_PROFILE;
+
+/* data associated with BTA_JV_API_NOTIFY_PM_STATE_CHANGE_EVT */
+typedef struct {
+  uint32_t handle;          /* Connection handle */
+  tBTA_JV_CONN_STATE state; /* JV connection stata */
+} tBTA_JV_NOTIFY_PM_STATE_CHANGE;
+
+/* union of data associated with JV callback */
+typedef union {
+  tBTA_JV_STATUS status;                     /* BTA_JV_ENABLE_EVT */
+  tBTA_JV_DISCOVERY_COMP disc_comp;          /* BTA_JV_DISCOVERY_COMP_EVT */
+  tBTA_JV_SET_DISCOVER set_discover;         /* BTA_JV_SET_DISCOVER_EVT */
+  uint8_t scn;                               /* BTA_JV_GET_SCN_EVT */
+  uint16_t psm;                              /* BTA_JV_GET_PSM_EVT */
+  tBTA_JV_CREATE_RECORD create_rec;          /* BTA_JV_CREATE_RECORD_EVT */
+  tBTA_JV_L2CAP_OPEN l2c_open;               /* BTA_JV_L2CAP_OPEN_EVT */
+  tBTA_JV_L2CAP_CLOSE l2c_close;             /* BTA_JV_L2CAP_CLOSE_EVT */
+  tBTA_JV_L2CAP_START l2c_start;             /* BTA_JV_L2CAP_START_EVT */
+  tBTA_JV_L2CAP_CL_INIT l2c_cl_init;         /* BTA_JV_L2CAP_CL_INIT_EVT */
+  tBTA_JV_L2CAP_CONG l2c_cong;               /* BTA_JV_L2CAP_CONG_EVT */
+  tBTA_JV_L2CAP_READ l2c_read;               /* BTA_JV_L2CAP_READ_EVT */
+  tBTA_JV_L2CAP_WRITE l2c_write;             /* BTA_JV_L2CAP_WRITE_EVT */
+  tBTA_JV_RFCOMM_OPEN rfc_open;              /* BTA_JV_RFCOMM_OPEN_EVT */
+  tBTA_JV_RFCOMM_SRV_OPEN rfc_srv_open;      /* BTA_JV_RFCOMM_SRV_OPEN_EVT */
+  tBTA_JV_RFCOMM_CLOSE rfc_close;            /* BTA_JV_RFCOMM_CLOSE_EVT */
+  tBTA_JV_RFCOMM_START rfc_start;            /* BTA_JV_RFCOMM_START_EVT */
+  tBTA_JV_RFCOMM_CL_INIT rfc_cl_init;        /* BTA_JV_RFCOMM_CL_INIT_EVT */
+  tBTA_JV_RFCOMM_CONG rfc_cong;              /* BTA_JV_RFCOMM_CONG_EVT */
+  tBTA_JV_RFCOMM_WRITE rfc_write;            /* BTA_JV_RFCOMM_WRITE_EVT */
+  tBTA_JV_DATA_IND data_ind;                 /* BTA_JV_L2CAP_DATA_IND_EVT
+                                                BTA_JV_RFCOMM_DATA_IND_EVT */
+  tBTA_JV_LE_DATA_IND le_data_ind;           /* BTA_JV_L2CAP_LE_DATA_IND_EVT */
+  tBTA_JV_L2CAP_LE_OPEN l2c_le_open;         /* BTA_JV_L2CAP_OPEN_EVT */
+  tBTA_JV_L2CAP_WRITE_FIXED l2c_write_fixed; /* BTA_JV_L2CAP_WRITE_FIXED_EVT */
+} tBTA_JV;
+
+/* JAVA DM Interface callback */
+typedef void(tBTA_JV_DM_CBACK)(tBTA_JV_EVT event, tBTA_JV* p_data,
+                               void* user_data);
+
+/* JAVA RFCOMM interface callback */
+typedef void*(tBTA_JV_RFCOMM_CBACK)(tBTA_JV_EVT event, tBTA_JV* p_data,
+                                    void* user_data);
+
+/* JAVA L2CAP interface callback */
+typedef void(tBTA_JV_L2CAP_CBACK)(tBTA_JV_EVT event, tBTA_JV* p_data,
+                                  void* user_Data);
+
+/* JV configuration structure */
+typedef struct {
+  uint16_t sdp_raw_size;       /* The size of p_sdp_raw_data */
+  uint16_t sdp_db_size;        /* The size of p_sdp_db */
+  uint8_t* p_sdp_raw_data;     /* The data buffer to keep raw data */
+  tSDP_DISCOVERY_DB* p_sdp_db; /* The data buffer to keep SDP database */
+} tBTA_JV_CFG;
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvEnable
+ *
+ * Description      Enable the Java I/F service. When the enable
+ *                  operation is complete the callback function will be
+ *                  called with a BTA_JV_ENABLE_EVT. This function must
+ *                  be called before other functions in the JV API are
+ *                  called.
+ *
+ * Returns          BTA_JV_SUCCESS if successful.
+ *                  BTA_JV_FAIL if internal failure.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvEnable(tBTA_JV_DM_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvDisable
+ *
+ * Description      Disable the Java I/F
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_JvDisable(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvIsEncrypted
+ *
+ * Description      This function checks if the link to peer device is encrypted
+ *
+ * Returns          true if encrypted.
+ *                  false if not.
+ *
+ ******************************************************************************/
+bool BTA_JvIsEncrypted(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvGetChannelId
+ *
+ * Description      This function reserves a SCN/PSM for applications running
+ *                  over RFCOMM or L2CAP. It is primarily called by
+ *                  server profiles/applications to register their SCN/PSM into
+ *                  the SDP database. The SCN is reported by the
+ *                  tBTA_JV_DM_CBACK callback with a BTA_JV_GET_SCN_EVT.
+ *                  If the SCN/PSM reported is 0, that means all SCN resources
+ *                  are exhausted.
+ *                  The channel parameter can be used to request a specific
+ *                  channel. If the request on the specific channel fails, the
+ *                  SCN/PSM returned in the EVT will be 0 - no attempt to
+ *                  request a new channel will be made. set channel to <= 0 to
+ *                  automatically assign an channel ID.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvGetChannelId(int conn_type, void* user_data,
+                                  int32_t channel);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvFreeChannel
+ *
+ * Description      This function frees a SCN/PSM that was used
+ *                  by an application running over RFCOMM or L2CAP.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvFreeChannel(uint16_t channel, int conn_type);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvStartDiscovery
+ *
+ * Description      This function performs service discovery for the services
+ *                  provided by the given peer device. When the operation is
+ *                  complete the tBTA_JV_DM_CBACK callback function will be
+ *                  called with a BTA_JV_DISCOVERY_COMP_EVT.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvStartDiscovery(BD_ADDR bd_addr, uint16_t num_uuid,
+                                    tSDP_UUID* p_uuid_list, void* user_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvCreateRecordByUser
+ *
+ * Description      Create a service record in the local SDP database by user in
+ *                  tBTA_JV_DM_CBACK callback with a BTA_JV_CREATE_RECORD_EVT.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvCreateRecordByUser(void* user_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvDeleteRecord
+ *
+ * Description      Delete a service record in the local SDP database.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvDeleteRecord(uint32_t handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capConnectLE
+ *
+ * Description      Initiate a connection as an LE L2CAP client to the given BD
+ *                  Address.
+ *                  When the connection is initiated or failed to initiate,
+ *                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_CL_INIT_EVT
+ *                  When the connection is established or failed,
+ *                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capConnectLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+                                    const tL2CAP_ERTM_INFO* ertm_info,
+                                    uint16_t remote_chan, uint16_t rx_mtu,
+                                    tL2CAP_CFG_INFO* cfg, BD_ADDR peer_bd_addr,
+                                    tBTA_JV_L2CAP_CBACK* p_cback,
+                                    void* user_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capConnect
+ *
+ * Description      Initiate a connection as a L2CAP client to the given BD
+ *                  Address.
+ *                  When the connection is initiated or failed to initiate,
+ *                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_CL_INIT_EVT
+ *                  When the connection is established or failed,
+ *                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capConnect(int conn_type, tBTA_SEC sec_mask,
+                                  tBTA_JV_ROLE role,
+                                  const tL2CAP_ERTM_INFO* ertm_info,
+                                  uint16_t remote_psm, uint16_t rx_mtu,
+                                  tL2CAP_CFG_INFO* cfg, BD_ADDR peer_bd_addr,
+                                  tBTA_JV_L2CAP_CBACK* p_cback,
+                                  void* user_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capClose
+ *
+ * Description      This function closes an L2CAP client connection
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capClose(uint32_t handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capCloseLE
+ *
+ * Description      This function closes an L2CAP client connection for Fixed
+ *                  Channels Function is idempotent and no callbacks are called!
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capCloseLE(uint32_t handle);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capStartServer
+ *
+ * Description      This function starts an L2CAP server and listens for an
+ *                  L2CAP connection from a remote Bluetooth device.  When the
+ *                  server is started successfully, tBTA_JV_L2CAP_CBACK is
+ *                  called with BTA_JV_L2CAP_START_EVT.  When the connection is
+ *                  established, tBTA_JV_L2CAP_CBACK is called with
+ *                  BTA_JV_L2CAP_OPEN_EVT.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStartServer(
+    int conn_type, tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+    const tL2CAP_ERTM_INFO* ertm_info, uint16_t local_psm, uint16_t rx_mtu,
+    tL2CAP_CFG_INFO* cfg, tBTA_JV_L2CAP_CBACK* p_cback, void* user_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capStartServerLE
+ *
+ * Description      This function starts an LE L2CAP server and listens for an
+ *                  L2CAP connection from a remote Bluetooth device on a fixed
+ *                  channel over an LE link.  When the server
+ *                  is started successfully, tBTA_JV_L2CAP_CBACK is called with
+ *                  BTA_JV_L2CAP_START_EVT.  When the connection is established,
+ *                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStartServerLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+                                        const tL2CAP_ERTM_INFO* ertm_info,
+                                        uint16_t local_chan, uint16_t rx_mtu,
+                                        tL2CAP_CFG_INFO* cfg,
+                                        tBTA_JV_L2CAP_CBACK* p_cback,
+                                        void* user_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capStopServerLE
+ *
+ * Description      This function stops the LE L2CAP server. If the server has
+ *                  an active connection, it would be closed.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStopServerLE(uint16_t local_chan, void* user_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capStopServerLE
+ *
+ * Description      This function stops the LE L2CAP server. If the server has
+ *                  an active connection, it would be closed.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStopServer(uint16_t local_psm, void* user_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capRead
+ *
+ * Description      This function reads data from an L2CAP connection
+ *                  When the operation is complete, tBTA_JV_L2CAP_CBACK is
+ *                  called with BTA_JV_L2CAP_READ_EVT.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capRead(uint32_t handle, uint32_t req_id,
+                               uint8_t* p_data, uint16_t len);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capReady
+ *
+ * Description      This function determined if there is data to read from
+ *                  an L2CAP connection
+ *
+ * Returns          BTA_JV_SUCCESS, if data queue size is in *p_data_size.
+ *                  BTA_JV_FAILURE, if error.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capReady(uint32_t handle, uint32_t* p_data_size);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capWrite
+ *
+ * Description      This function writes data to an L2CAP connection
+ *                  When the operation is complete, tBTA_JV_L2CAP_CBACK is
+ *                  called with BTA_JV_L2CAP_WRITE_EVT. Works for
+ *                  PSM-based connections
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capWrite(uint32_t handle, uint32_t req_id,
+                                uint8_t* p_data, uint16_t len, void* user_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capWriteFixed
+ *
+ * Description      This function writes data to an L2CAP connection
+ *                  When the operation is complete, tBTA_JV_L2CAP_CBACK is
+ *                  called with BTA_JV_L2CAP_WRITE_FIXED_EVT. Works for
+ *                  fixed-channel connections
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capWriteFixed(uint16_t channel, BD_ADDR* addr,
+                                     uint32_t req_id,
+                                     tBTA_JV_L2CAP_CBACK* p_cback,
+                                     uint8_t* p_data, uint16_t len,
+                                     void* user_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvRfcommConnect
+ *
+ * Description      This function makes an RFCOMM conection to a remote BD
+ *                  Address.
+ *                  When the connection is initiated or failed to initiate,
+ *                  tBTA_JV_RFCOMM_CBACK is called with
+ *                  BTA_JV_RFCOMM_CL_INIT_EVT
+ *                  When the connection is established or failed,
+ *                  tBTA_JV_RFCOMM_CBACK is called with BTA_JV_RFCOMM_OPEN_EVT
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommConnect(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+                                   uint8_t remote_scn, BD_ADDR peer_bd_addr,
+                                   tBTA_JV_RFCOMM_CBACK* p_cback,
+                                   void* user_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvRfcommClose
+ *
+ * Description      This function closes an RFCOMM connection
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommClose(uint32_t handle, void* user_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvRfcommStartServer
+ *
+ * Description      This function starts listening for an RFCOMM connection
+ *                  request from a remote Bluetooth device.  When the server is
+ *                  started successfully, tBTA_JV_RFCOMM_CBACK is called
+ *                  with BTA_JV_RFCOMM_START_EVT.
+ *                  When the connection is established, tBTA_JV_RFCOMM_CBACK
+ *                  is called with BTA_JV_RFCOMM_OPEN_EVT.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommStartServer(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+                                       uint8_t local_scn, uint8_t max_session,
+                                       tBTA_JV_RFCOMM_CBACK* p_cback,
+                                       void* user_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvRfcommStopServer
+ *
+ * Description      This function stops the RFCOMM server. If the server has an
+ *                  active connection, it would be closed.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommStopServer(uint32_t handle, void* user_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvRfcommWrite
+ *
+ * Description      This function writes data to an RFCOMM connection
+ *                  When the operation is complete, tBTA_JV_RFCOMM_CBACK is
+ *                  called with BTA_JV_RFCOMM_WRITE_EVT.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommWrite(uint32_t handle, uint32_t req_id);
+
+/*******************************************************************************
+ *
+ * Function    BTA_JVSetPmProfile
+ *
+ * Description This function set or free power mode profile for different JV
+ *             application
+ *
+ * Parameters:  handle,  JV handle from RFCOMM or L2CAP
+ *              app_id:  app specific pm ID, can be BTA_JV_PM_ALL, see
+ *                       bta_dm_cfg.c for details
+ *              BTA_JV_PM_ID_CLEAR: removes pm management on the handle. init_st
+ *                                  is ignored and BTA_JV_CONN_CLOSE is called
+ *                                  implicitly
+ *              init_st: state after calling this API. typically it should be
+ *                       BTA_JV_CONN_OPEN
+ *
+ * Returns      BTA_JV_SUCCESS, if the request is being processed.
+ *              BTA_JV_FAILURE, otherwise.
+ *
+ * NOTE:        BTA_JV_PM_ID_CLEAR: In general no need to be called as jv pm
+ *                                  calls automatically
+ *              BTA_JV_CONN_CLOSE to remove in case of connection close!
+ *
+ *******************************************************************************/
+tBTA_JV_STATUS BTA_JvSetPmProfile(uint32_t handle, tBTA_JV_PM_ID app_id,
+                                  tBTA_JV_CONN_STATE init_st);
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvRfcommGetPortHdl
+ *
+ * Description    This function fetches the rfcomm port handle
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+uint16_t BTA_JvRfcommGetPortHdl(uint32_t handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_JV_API_H */
diff --git a/bt/bta/include/bta_jv_co.h b/bt/bta/include/bta_jv_co.h
new file mode 100644
index 0000000..ce9ab1c
--- /dev/null
+++ b/bt/bta/include/bta_jv_co.h
@@ -0,0 +1,62 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2007-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 is the interface file for java interface call-out functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_JV_CO_H
+#define BTA_JV_CO_H
+
+#include "bta_jv_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+ *  Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         bta_jv_co_rfc_data
+ *
+ * Description      This function is called by JV to send data to the java glue
+ *                  code when the RX data path is configured to use a call-out
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+
+extern int bta_co_rfc_data_incoming(void* user_data, BT_HDR* p_buf);
+extern int bta_co_rfc_data_outgoing_size(void* user_data, int* size);
+extern int bta_co_rfc_data_outgoing(void* user_data, uint8_t* buf,
+                                    uint16_t size);
+
+extern int bta_co_l2cap_data_incoming(void* user_data, BT_HDR* p_buf);
+extern int bta_co_l2cap_data_outgoing_size(void* user_data, int* size);
+extern int bta_co_l2cap_data_outgoing(void* user_data, uint8_t* buf,
+                                      uint16_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_DG_CO_H */
diff --git a/bt/bta/include/bta_mce_api.h b/bt/bta/include/bta_mce_api.h
new file mode 100644
index 0000000..ef5525d
--- /dev/null
+++ b/bt/bta/include/bta_mce_api.h
@@ -0,0 +1,129 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright (C) 2006-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 is the public interface file the BTA MCE I/F
+ *
+ ******************************************************************************/
+#ifndef BTA_MCE_API_H
+#define BTA_MCE_API_H
+
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bta_api.h"
+#include "btm_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+ *  Constants and data types
+ ****************************************************************************/
+/* status values */
+#define BTA_MCE_SUCCESS 0 /* Successful operation. */
+#define BTA_MCE_FAILURE 1 /* Generic failure. */
+#define BTA_MCE_BUSY 2    /* Temporarily can not handle this request. */
+
+typedef uint8_t tBTA_MCE_STATUS;
+
+/* MCE I/F callback events */
+/* events received by tBTA_MCE_DM_CBACK */
+#define BTA_MCE_ENABLE_EVT 0             /* MCE enabled */
+#define BTA_MCE_MAS_DISCOVERY_COMP_EVT 1 /* SDP MAS discovery complete */
+#define BTA_MCE_MAX_EVT 2                /* max number of MCE events */
+
+#define BTA_MCE_MAX_MAS_INSTANCES 12
+
+typedef uint16_t tBTA_MCE_EVT;
+
+typedef struct {
+  uint8_t scn;
+  char* p_srv_name;
+  uint16_t srv_name_len;
+  uint8_t instance_id;
+  uint8_t msg_type;
+} tBTA_MCE_MAS_INFO;
+
+/* data associated with BTA_MCE_MAS_DISCOVERY_COMP_EVT */
+typedef struct {
+  tBTA_MCE_STATUS status;
+  BD_ADDR remote_addr;
+  int num_mas;
+  tBTA_MCE_MAS_INFO mas[BTA_MCE_MAX_MAS_INSTANCES];
+} tBTA_MCE_MAS_DISCOVERY_COMP;
+
+/* union of data associated with MCE callback */
+typedef union {
+  tBTA_MCE_STATUS status; /* BTA_MCE_ENABLE_EVT */
+  tBTA_MCE_MAS_DISCOVERY_COMP
+      mas_disc_comp; /* BTA_MCE_MAS_DISCOVERY_COMP_EVT */
+} tBTA_MCE;
+
+/* MCE DM Interface callback */
+typedef void(tBTA_MCE_DM_CBACK)(tBTA_MCE_EVT event, tBTA_MCE* p_data,
+                                void* user_data);
+
+/* MCE configuration structure */
+typedef struct {
+  uint16_t sdp_db_size;        /* The size of p_sdp_db */
+  tSDP_DISCOVERY_DB* p_sdp_db; /* The data buffer to keep SDP database */
+} tBTA_MCE_CFG;
+
+/*****************************************************************************
+ *  External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         BTA_MceEnable
+ *
+ * Description      Enable the MCE I/F service. When the enable
+ *                  operation is complete the callback function will be
+ *                  called with a BTA_MCE_ENABLE_EVT. This function must
+ *                  be called before other functions in the MCE API are
+ *                  called.
+ *
+ * Returns          BTA_MCE_SUCCESS if successful.
+ *                  BTA_MCE_FAIL if internal failure.
+ *
+ ******************************************************************************/
+extern tBTA_MCE_STATUS BTA_MceEnable(tBTA_MCE_DM_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTA_MceGetRemoteMasInstances
+ *
+ * Description      This function performs service discovery for the MAS service
+ *                  by the given peer device. When the operation is completed
+ *                  the tBTA_MCE_DM_CBACK callback function will be  called with
+ *                  a BTA_MCE_MAS_DISCOVERY_COMP_EVT.
+ *
+ * Returns          BTA_MCE_SUCCESS, if the request is being processed.
+ *                  BTA_MCE_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+extern tBTA_MCE_STATUS BTA_MceGetRemoteMasInstances(BD_ADDR bd_addr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_MCE_API_H */
diff --git a/bt/bta/include/bta_op_api.h b/bt/bta/include/bta_op_api.h
new file mode 100644
index 0000000..3918568
--- /dev/null
+++ b/bt/bta/include/bta_op_api.h
@@ -0,0 +1,65 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 is the public interface file for the object push (OP) client and
+ *  server subsystem of BTA, Broadcom's Bluetooth application layer for
+ *  mobile phones.
+ *
+ ******************************************************************************/
+#ifndef BTA_OP_API_H
+#define BTA_OP_API_H
+
+#include "bta_api.h"
+
+/*****************************************************************************
+ *  Constants and data types
+ ****************************************************************************/
+/* Extra Debug Code */
+#ifndef BTA_OPS_DEBUG
+#define BTA_OPS_DEBUG false
+#endif
+
+#ifndef BTA_OPC_DEBUG
+#define BTA_OPC_DEBUG false
+#endif
+
+/* Object format */
+#define BTA_OP_VCARD21_FMT 1  /* vCard 2.1 */
+#define BTA_OP_VCARD30_FMT 2  /* vCard 3.0 */
+#define BTA_OP_VCAL_FMT 3     /* vCal 1.0 */
+#define BTA_OP_ICAL_FMT 4     /* iCal 2.0 */
+#define BTA_OP_VNOTE_FMT 5    /* vNote */
+#define BTA_OP_VMSG_FMT 6     /* vMessage */
+#define BTA_OP_OTHER_FMT 0xFF /* other format */
+
+typedef uint8_t tBTA_OP_FMT;
+
+/* Object format mask */
+#define BTA_OP_VCARD21_MASK 0x01 /* vCard 2.1 */
+#define BTA_OP_VCARD30_MASK 0x02 /* vCard 3.0 */
+#define BTA_OP_VCAL_MASK 0x04    /* vCal 1.0 */
+#define BTA_OP_ICAL_MASK 0x08    /* iCal 2.0 */
+#define BTA_OP_VNOTE_MASK 0x10   /* vNote */
+#define BTA_OP_VMSG_MASK 0x20    /* vMessage */
+#define BTA_OP_ANY_MASK 0x40     /* Any type of object. */
+
+typedef uint8_t tBTA_OP_FMT_MASK;
+
+#endif /* BTA_OP_API_H */
diff --git a/bt/bta/include/bta_pan_api.h b/bt/bta/include/bta_pan_api.h
new file mode 100644
index 0000000..4e91828
--- /dev/null
+++ b/bt/bta/include/bta_pan_api.h
@@ -0,0 +1,187 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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 is the public interface file for the Personal Area Networking (PAN)
+ *  subsystem of BTA, Broadcom's Bluetooth application layer for mobile
+ *  phones.
+ *
+ ******************************************************************************/
+#ifndef BTA_PAN_API_H
+#define BTA_PAN_API_H
+
+#include "bta_api.h"
+#include "pan_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+ *  Constants and data types
+ ****************************************************************************/
+#define BTA_PAN_SUCCESS 0
+#define BTA_PAN_FAIL 1
+
+typedef uint8_t tBTA_PAN_STATUS;
+
+/* PAN Callback events */
+#define BTA_PAN_ENABLE_EVT 0   /* PAN service is enabled. */
+#define BTA_PAN_SET_ROLE_EVT 1 /* PAN roles registered */
+#define BTA_PAN_OPENING_EVT 2  /* Connection is being opened. */
+#define BTA_PAN_OPEN_EVT 3     /* Connection has been opened. */
+#define BTA_PAN_CLOSE_EVT 4    /* Connection has been closed. */
+
+typedef uint8_t tBTA_PAN_EVT;
+
+/* pan roles */
+#define BTA_PAN_ROLE_PANU PAN_ROLE_CLIENT
+#define BTA_PAN_ROLE_GN PAN_ROLE_GN_SERVER
+#define BTA_PAN_ROLE_NAP PAN_ROLE_NAP_SERVER
+
+typedef uint8_t tBTA_PAN_ROLE;
+
+/*  information regarding PAN roles */
+typedef struct {
+  const char* p_srv_name; /* service name for the PAN role */
+  uint8_t app_id;         /* application id */
+  tBTA_SEC sec_mask;      /* security setting for the role */
+
+} tBTA_PAN_ROLE_INFO;
+
+/* Event associated with BTA_PAN_SET_ROLE_EVT */
+typedef struct {
+  tBTA_PAN_STATUS status; /* status of set role event */
+  tBTA_PAN_ROLE role;     /* PAN roles successfully registered */
+} tBTA_PAN_SET_ROLE;
+
+/* Event associated with BTA_PAN_OPENING_EVT */
+typedef struct {
+  BD_ADDR bd_addr; /* BD address of peer device. */
+  uint16_t handle; /* Handle associated with this connection. */
+
+} tBTA_PAN_OPENING;
+
+/* Event associated with BTA_PAN_OPEN_EVT */
+typedef struct {
+  BD_ADDR bd_addr;          /* BD address of peer device. */
+  uint16_t handle;          /* Handle associated with this connection. */
+  tBTA_PAN_STATUS status;   /* status of open event */
+  tBTA_PAN_ROLE local_role; /* Local device PAN role for the connection */
+  tBTA_PAN_ROLE peer_role;  /* Peer device PAN role for the connection */
+
+} tBTA_PAN_OPEN;
+
+/* Event associated with BTA_PAN_CLOSE_EVT */
+typedef struct {
+  uint16_t handle; /* Handle associated with the connection. */
+} tBTA_PAN_CLOSE;
+
+/* Union of all PAN callback structures */
+typedef union {
+  tBTA_PAN_SET_ROLE set_role; /* set_role event */
+  tBTA_PAN_OPEN open;         /* Connection has been opened. */
+  tBTA_PAN_OPENING opening;   /* Connection being opened */
+  tBTA_PAN_CLOSE close;       /* Connection has been closed. */
+} tBTA_PAN;
+
+/* Number of PAN connections */
+#ifndef BTA_PAN_NUM_CONN
+#define BTA_PAN_NUM_CONN 4
+#endif
+
+/* PAN callback */
+typedef void(tBTA_PAN_CBACK)(tBTA_PAN_EVT event, tBTA_PAN* p_data);
+
+/*****************************************************************************
+ *  External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         BTA_PanEnable
+ *
+ * Description      Enable PAN service.  This function must be
+ *                  called before any other functions in the PAN API are called.
+ *                  When the enable operation is complete the callback function
+ *                  will be called with a BTA_PAN_ENABLE_EVT.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_PanEnable(tBTA_PAN_CBACK p_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTA_PanDisable
+ *
+ * Description      Disable PAN service.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_PanDisable(void);
+
+/*******************************************************************************
+ *
+ * Function         BTA_PanSetRole
+ *
+ * Description      Sets PAN roles. When the enable operation is complete
+ *                  the callback function will be called with a
+ *                  BTA_PAN_SET_ROLE_EVT.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_PanSetRole(tBTA_PAN_ROLE role, tBTA_PAN_ROLE_INFO* p_user_info,
+                    tBTA_PAN_ROLE_INFO* p_gn_info,
+                    tBTA_PAN_ROLE_INFO* p_nap_info);
+
+/*******************************************************************************
+ *
+ * Function         BTA_PanOpen
+ *
+ * Description      Opens a connection to a peer device.
+ *                  When connection is open callback function is called
+ *                  with a BTA_PAN_OPEN_EVT.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_PanOpen(BD_ADDR bd_addr, tBTA_PAN_ROLE local_role,
+                 tBTA_PAN_ROLE peer_role);
+
+/*******************************************************************************
+ *
+ * Function         BTA_PanClose
+ *
+ * Description      Close a PAN  connection to a peer device.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void BTA_PanClose(uint16_t handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_PAN_API_H */
diff --git a/bt/bta/include/bta_pan_ci.h b/bt/bta/include/bta_pan_ci.h
new file mode 100644
index 0000000..7c46cce
--- /dev/null
+++ b/bt/bta/include/bta_pan_ci.h
@@ -0,0 +1,150 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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 is the interface file for pan call-in functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_PAN_CI_H
+#define BTA_PAN_CI_H
+
+#include "bta_pan_api.h"
+
+/*****************************************************************************
+ *  Function Declarations
+ ****************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_ci_tx_ready
+ *
+ * Description      This function sends an event to PAN indicating the phone is
+ *                  ready for more data and PAN should call
+ *                  bta_pan_co_tx_path().
+ *                  This function is used when the TX data path is configured
+ *                  to use a pull interface.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_pan_ci_tx_ready(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_ci_rx_ready
+ *
+ * Description      This function sends an event to PAN indicating the phone
+ *                  has data available to send to PAN and PAN should call
+ *                  bta_pan_co_rx_path().  This function is used when the RX
+ *                  data path is configured to use a pull interface.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_pan_ci_rx_ready(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_ci_tx_flow
+ *
+ * Description      This function is called to enable or disable data flow on
+ *                  the TX path.  The phone should call this function to
+ *                  disable data flow when it is congested and cannot handle
+ *                  any more data sent by bta_pan_co_tx_write() or
+ *                  bta_pan_co_tx_writebuf().  This function is used when the
+ *                  TX data path is configured to use a push interface.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_pan_ci_tx_flow(uint16_t handle, bool enable);
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_ci_rx_writebuf
+ *
+ * Description      This function is called to send data to the phone when
+ *                  the RX path is configured to use a push interface with
+ *                  zero copy.  The function sends an event to PAN containing
+ *                  the data buffer. The buffer will be freed by BTA; the
+ *                  phone must not free the buffer.
+ *
+ *
+ * Returns          true if flow enabled
+ *
+ ******************************************************************************/
+extern void bta_pan_ci_rx_writebuf(uint16_t handle, BD_ADDR src, BD_ADDR dst,
+                                   uint16_t protocol, BT_HDR* p_buf, bool ext);
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_ci_readbuf
+ *
+ * Description      This function is called by the phone to read data from PAN
+ *                  when the TX path is configured to use a pull interface.
+ *                  The caller must free the buffer when it is through
+ *                  processing the buffer.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern BT_HDR* bta_pan_ci_readbuf(uint16_t handle, BD_ADDR src, BD_ADDR dst,
+                                  uint16_t* p_protocol, bool* p_ext,
+                                  bool* p_forward);
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_ci_set_pfilters
+ *
+ * Description      This function is called to set protocol filters
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_pan_ci_set_pfilters(uint16_t handle, uint16_t num_filters,
+                                    uint16_t* p_start_array,
+                                    uint16_t* p_end_array);
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_ci_set_mfilters
+ *
+ * Description      This function is called to set multicast filters
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_pan_ci_set_mfilters(uint16_t handle, uint16_t num_mcast_filters,
+                                    uint8_t* p_start_array,
+                                    uint8_t* p_end_array);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_PAN_CI_H */
diff --git a/bt/bta/include/bta_pan_co.h b/bt/bta/include/bta_pan_co.h
new file mode 100644
index 0000000..f3d80f2
--- /dev/null
+++ b/bt/bta/include/bta_pan_co.h
@@ -0,0 +1,207 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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 is the interface file for data gateway call-out functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_PAN_CO_H
+#define BTA_PAN_CO_H
+
+#include "bta_pan_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+/* BT_HDR buffer offset */
+#define BTA_PAN_MIN_OFFSET PAN_MINIMUM_OFFSET
+
+/* Data Flow Mask */
+#define BTA_PAN_RX_PUSH 0x00     /* RX push. */
+#define BTA_PAN_RX_PUSH_BUF 0x01 /* RX push with zero copy. */
+#define BTA_PAN_RX_PULL 0x02     /* RX pull. */
+#define BTA_PAN_TX_PUSH 0x00     /* TX push. */
+#define BTA_PAN_TX_PUSH_BUF 0x10 /* TX push with zero copy. */
+#define BTA_PAN_TX_PULL 0x20     /* TX pull. */
+
+/*****************************************************************************
+ *  Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_co_init
+ *
+ * Description      This callout function is executed by PAN when a server is
+ *                  started by calling BTA_PanEnable().  This function can be
+ *                  used by the phone to initialize data paths or for other
+ *                  initialization purposes.  The function must return the
+ *                  data flow mask as described below.
+ *
+ *
+ * Returns          Data flow mask.
+ *
+ ******************************************************************************/
+extern uint8_t bta_pan_co_init(uint8_t* q_level);
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_co_open
+ *
+ * Description      This function is executed by PAN when a connection
+ *                  is opened.  The phone can use this function to set
+ *                  up data paths or perform any required initialization.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_pan_co_open(uint16_t handle, uint8_t app_id,
+                            tBTA_PAN_ROLE local_role, tBTA_PAN_ROLE peer_role,
+                            BD_ADDR peer_addr);
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_co_close
+ *
+ * Description      This function is called by PAN when a connection to a
+ *                  server is closed.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_pan_co_close(uint16_t handle, uint8_t app_id);
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_co_tx_path
+ *
+ * Description      This function is called by PAN to transfer data on the
+ *                  TX path; that is, data being sent from BTA to the phone.
+ *                  This function is used when the TX data path is configured
+ *                  to use the pull interface.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_pan_co_tx_path(uint16_t handle, uint8_t app_id);
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_co_rx_path
+ *
+ * Description      This function is called by PAN to transfer data on the
+ *                  RX path; that is, data being sent from the phone to BTA.
+ *                  This function is used when the RX data path is configured
+ *                  to use the pull interface.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_pan_co_rx_path(uint16_t handle, uint8_t app_id);
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_co_tx_write
+ *
+ * Description      This function is called by PAN to send data to the phone
+ *                  when the TX path is configured to use a push interface.
+ *                  The implementation of this function must copy the data to
+ *                  the phone's memory.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_pan_co_tx_write(uint16_t handle, uint8_t app_id, BD_ADDR src,
+                                BD_ADDR dst, uint16_t protocol, uint8_t* p_data,
+                                uint16_t len, bool ext, bool forward);
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_co_tx_writebuf
+ *
+ * Description      This function is called by PAN to send data to the phone
+ *                  when the TX path is configured to use a push interface with
+ *                  zero copy.  The phone must free the buffer using function
+ *                  osi_free() when it is through processing the buffer.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_pan_co_tx_writebuf(uint16_t handle, uint8_t app_id, BD_ADDR src,
+                                   BD_ADDR dst, uint16_t protocol,
+                                   BT_HDR* p_buf, bool ext, bool forward);
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_co_rx_flow
+ *
+ * Description      This function is called by PAN to enable or disable
+ *                  data flow on the RX path when it is configured to use
+ *                  a push interface.  If data flow is disabled the phone must
+ *                  not call bta_pan_ci_rx_write() or bta_pan_ci_rx_writebuf()
+ *                  until data flow is enabled again.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_pan_co_rx_flow(uint16_t handle, uint8_t app_id, bool enable);
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_co_filt_ind
+ *
+ * Description      protocol filter indication from peer device
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_pan_co_pfilt_ind(uint16_t handle, bool indication,
+                                 tBTA_PAN_STATUS result, uint16_t len,
+                                 uint8_t* p_filters);
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_co_mfilt_ind
+ *
+ * Description      multicast filter indication from peer device
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+extern void bta_pan_co_mfilt_ind(uint16_t handle, bool indication,
+                                 tBTA_PAN_STATUS result, uint16_t len,
+                                 uint8_t* p_filters);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_PAN_CO_H */
diff --git a/bt/bta/include/bta_sdp_api.h b/bt/bta/include/bta_sdp_api.h
new file mode 100644
index 0000000..37a7774
--- /dev/null
+++ b/bt/bta/include/bta_sdp_api.h
@@ -0,0 +1,144 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 is the public interface file for the BTA SDP I/F
+ *
+ ******************************************************************************/
+#ifndef BTA_SDP_API_H
+#define BTA_SDP_API_H
+
+#include <hardware/bt_sdp.h>
+
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bta_api.h"
+#include "btm_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* status values */
+#define BTA_SDP_SUCCESS 0 /* Successful operation. */
+#define BTA_SDP_FAILURE 1 /* Generic failure. */
+#define BTA_SDP_BUSY 2    /* Temporarily can not handle this request. */
+
+typedef uint8_t tBTA_SDP_STATUS;
+
+/* SDP I/F callback events */
+/* events received by tBTA_SDP_DM_CBACK */
+#define BTA_SDP_ENABLE_EVT 0             /* SDP service i/f enabled*/
+#define BTA_SDP_SEARCH_EVT 1             /* SDP Service started */
+#define BTA_SDP_SEARCH_COMP_EVT 2        /* SDP search complete */
+#define BTA_SDP_CREATE_RECORD_USER_EVT 3 /* SDP search complete */
+#define BTA_SDP_REMOVE_RECORD_USER_EVT 4 /* SDP search complete */
+#define BTA_SDP_MAX_EVT 5                /* max number of SDP events */
+
+#define BTA_SDP_MAX_RECORDS 15
+
+typedef uint16_t tBTA_SDP_EVT;
+
+/* data associated with BTA_SDP_DISCOVERY_COMP_EVT */
+typedef struct {
+  tBTA_SDP_STATUS status;
+  BD_ADDR remote_addr;
+  tBT_UUID uuid;
+  int record_count;
+  bluetooth_sdp_record records[BTA_SDP_MAX_RECORDS];
+} tBTA_SDP_SEARCH_COMP;
+
+typedef union {
+  tBTA_SDP_STATUS status;               /* BTA_SDP_SEARCH_EVT */
+  tBTA_SDP_SEARCH_COMP sdp_search_comp; /* BTA_SDP_SEARCH_COMP_EVT */
+} tBTA_SDP;
+
+/* SDP DM Interface callback */
+typedef void(tBTA_SDP_DM_CBACK)(tBTA_SDP_EVT event, tBTA_SDP* p_data,
+                                void* user_data);
+
+/* MCE configuration structure */
+typedef struct {
+  uint16_t sdp_db_size;        /* The size of p_sdp_db */
+  tSDP_DISCOVERY_DB* p_sdp_db; /* The data buffer to keep SDP database */
+} tBTA_SDP_CFG;
+
+/*******************************************************************************
+ *
+ * Function         BTA_SdpEnable
+ *
+ * Description      Enable the SDP I/F service. When the enable
+ *                  operation is complete the callback function will be
+ *                  called with a BTA_SDP_ENABLE_EVT. This function must
+ *                  be called before other functions in the MCE API are
+ *                  called.
+ *
+ * Returns          BTA_SDP_SUCCESS if successful.
+ *                  BTA_SDP_FAIL if internal failure.
+ *
+ ******************************************************************************/
+extern tBTA_SDP_STATUS BTA_SdpEnable(tBTA_SDP_DM_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTA_SdpSearch
+ *
+ * Description      Start a search for sdp records for a specific BD_ADDR with a
+ *                  specific profile uuid.
+ *                  When the search operation is completed, the callback
+ *                  function will be called with a BTA_SDP_SEARCH_EVT.
+ * Returns          BTA_SDP_SUCCESS if successful.
+ *                  BTA_SDP_FAIL if internal failure.
+ *
+ ******************************************************************************/
+extern tBTA_SDP_STATUS BTA_SdpSearch(BD_ADDR bd_addr, tSDP_UUID* uuid);
+
+/*******************************************************************************
+ *
+ * Function         BTA_SdpCreateRecordByUser
+ *
+ * Description      This function is used to request a callback to create a SDP
+ *                  record. The registered callback will be called with event
+ *                  BTA_SDP_CREATE_RECORD_USER_EVT.
+ *
+ * Returns          BTA_SDP_SUCCESS, if the request is being processed.
+ *                  BTA_SDP_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+extern tBTA_SDP_STATUS BTA_SdpCreateRecordByUser(void* user_data);
+
+/*******************************************************************************
+ *
+ * Function         BTA_SdpRemoveRecordByUser
+ *
+ * Description      This function is used to request a callback to remove a SDP
+ *                  record. The registered callback will be called with event
+ *                  BTA_SDP_REMOVE_RECORD_USER_EVT.
+ *
+ * Returns          BTA_SDP_SUCCESS, if the request is being processed.
+ *                  BTA_SDP_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+extern tBTA_SDP_STATUS BTA_SdpRemoveRecordByUser(void* user_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_SDP_API_H */
diff --git a/bt/bta/include/utl.h b/bt/bta/include/utl.h
new file mode 100644
index 0000000..71b186f
--- /dev/null
+++ b/bt/bta/include/utl.h
@@ -0,0 +1,173 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Basic utility functions.
+ *
+ ******************************************************************************/
+#ifndef UTL_H
+#define UTL_H
+
+#include "bt_types.h"
+#include "bt_utils.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+/*** class of device settings ***/
+#define BTA_UTL_SET_COD_MAJOR_MINOR 0x01
+#define BTA_UTL_SET_COD_SERVICE_CLASS    \
+  0x02 /* only set the bits in the input \
+          */
+#define BTA_UTL_CLR_COD_SERVICE_CLASS 0x04
+#define BTA_UTL_SET_COD_ALL \
+  0x08 /* take service class as the input (may clear some set bits!!) */
+#define BTA_UTL_INIT_COD 0x0a
+
+/*****************************************************************************
+ *  Type Definitions
+ ****************************************************************************/
+
+/** for utl_set_device_class() **/
+typedef struct {
+  uint8_t minor;
+  uint8_t major;
+  uint16_t service;
+} tBTA_UTL_COD;
+
+/*****************************************************************************
+ *  External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         utl_str2int
+ *
+ * Description      This utility function converts a character string to an
+ *                  integer.  Acceptable values in string are 0-9.  If invalid
+ *                  string or string value too large, -1 is returned.
+ *
+ *
+ * Returns          Integer value or -1 on error.
+ *
+ ******************************************************************************/
+extern int16_t utl_str2int(const char* p_s);
+
+/*******************************************************************************
+ *
+ * Function         utl_strucmp
+ *
+ * Description      This utility function compares two strings in uppercase.
+ *                  String p_s must be uppercase.  String p_t is converted to
+ *                  uppercase if lowercase.  If p_s ends first, the substring
+ *                  match is counted as a match.
+ *
+ *
+ * Returns          0 if strings match, nonzero otherwise.
+ *
+ ******************************************************************************/
+extern int utl_strucmp(const char* p_s, const char* p_t);
+
+/*******************************************************************************
+ *
+ * Function         utl_itoa
+ *
+ * Description      This utility function converts a uint16_t to a string.  The
+ *                  string is NULL-terminated.  The length of the string is
+ *                  returned.
+ *
+ *
+ * Returns          Length of string.
+ *
+ ******************************************************************************/
+extern uint8_t utl_itoa(uint16_t i, char* p_s);
+
+/*******************************************************************************
+ *
+ * Function         utl_set_device_class
+ *
+ * Description      This function updates the local Device Class.
+ *
+ * Parameters:
+ *                  p_cod   - Pointer to the device class to set to
+ *
+ *                  cmd     - the fields of the device class to update.
+ *                            BTA_UTL_SET_COD_MAJOR_MINOR, - overwrite major,
+ *                                                           minor class
+ *                            BTA_UTL_SET_COD_SERVICE_CLASS - set the bits in
+ *                                                            the input
+ *                            BTA_UTL_CLR_COD_SERVICE_CLASS - clear the bits in
+ *                                                            the input
+ *                            BTA_UTL_SET_COD_ALL - overwrite major, minor, set
+ *                                                  the bits in service class
+ *                            BTA_UTL_INIT_COD - overwrite major, minor, and
+ *                                               service class
+ *
+ * Returns          true if successful, Otherwise false
+ *
+ ******************************************************************************/
+extern bool utl_set_device_class(tBTA_UTL_COD* p_cod, uint8_t cmd);
+
+/*******************************************************************************
+ *
+ * Function         utl_isintstr
+ *
+ * Description      This utility function checks if the given string is an
+ *                  integer string or not
+ *
+ *
+ * Returns          true if successful, Otherwise false
+ *
+ ******************************************************************************/
+extern bool utl_isintstr(const char* p_s);
+
+/*******************************************************************************
+ *
+ * Function         utl_isdialchar
+ *
+ * Description      This utility function checks if the given character
+ *                  is an acceptable dial digit
+ *
+ * Returns          true if successful, Otherwise false
+ *
+ ******************************************************************************/
+extern bool utl_isdialchar(const char d);
+
+/*******************************************************************************
+ *
+ * Function         utl_isdialstr
+ *
+ * Description      This utility function checks if the given string contains
+ *                  only dial digits or not
+ *
+ *
+ * Returns          true if successful, Otherwise false
+ *
+ ******************************************************************************/
+extern bool utl_isdialstr(const char* p_s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UTL_H */
diff --git a/bt/bta/jv/bta_jv_act.cc b/bt/bta/jv/bta_jv_act.cc
new file mode 100644
index 0000000..44e53af
--- /dev/null
+++ b/bt/bta/jv/bta_jv_act.cc
@@ -0,0 +1,2523 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2006-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 action functions for BTA JV APIs.
+ *
+ ******************************************************************************/
+#include <arpa/inet.h>
+#include <hardware/bluetooth.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avct_api.h"
+#include "avdt_api.h"
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bta_api.h"
+#include "bta_jv_api.h"
+#include "bta_jv_co.h"
+#include "bta_jv_int.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "gap_api.h"
+#include "l2c_api.h"
+#include "osi/include/allocator.h"
+#include "port_api.h"
+#include "rfcdefs.h"
+#include "sdp_api.h"
+#include "utl.h"
+
+#include "osi/include/osi.h"
+
+/* one of these exists for each client */
+struct fc_client {
+  struct fc_client* next_all_list;
+  struct fc_client* next_chan_list;
+  BD_ADDR remote_addr;
+  uint32_t id;
+  tBTA_JV_L2CAP_CBACK* p_cback;
+  void* user_data;
+  uint16_t handle;
+  uint16_t chan;
+  uint8_t sec_id;
+  unsigned server : 1;
+  unsigned init_called : 1;
+};
+
+/* one of these exists for each channel we're dealing with */
+struct fc_channel {
+  struct fc_channel* next;
+  struct fc_client* clients;
+  uint8_t has_server : 1;
+  uint16_t chan;
+};
+
+static struct fc_client* fc_clients;
+static struct fc_channel* fc_channels;
+static uint32_t fc_next_id;
+
+static void fcchan_conn_chng_cbk(uint16_t chan, BD_ADDR bd_addr, bool connected,
+                                 uint16_t reason, tBT_TRANSPORT);
+static void fcchan_data_cbk(uint16_t chan, BD_ADDR bd_addr, BT_HDR* p_buf);
+
+extern void uuid_to_string_legacy(bt_uuid_t* p_uuid, char* str, size_t str_len);
+static inline void logu(const char* title, const uint8_t* p_uuid) {
+  char uuids[128];
+  uuid_to_string_legacy((bt_uuid_t*)p_uuid, uuids, sizeof(uuids));
+  APPL_TRACE_DEBUG("%s: %s", title, uuids);
+}
+
+static tBTA_JV_PCB* bta_jv_add_rfc_port(tBTA_JV_RFC_CB* p_cb,
+                                        tBTA_JV_PCB* p_pcb_open);
+static tBTA_JV_STATUS bta_jv_free_set_pm_profile_cb(uint32_t jv_handle);
+static void bta_jv_pm_conn_busy(tBTA_JV_PM_CB* p_cb);
+static void bta_jv_pm_conn_idle(tBTA_JV_PM_CB* p_cb);
+static void bta_jv_pm_state_change(tBTA_JV_PM_CB* p_cb,
+                                   const tBTA_JV_CONN_STATE state);
+tBTA_JV_STATUS bta_jv_set_pm_conn_state(tBTA_JV_PM_CB* p_cb,
+                                        const tBTA_JV_CONN_STATE new_st);
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_alloc_sec_id
+ *
+ * Description  allocate a security id
+ *
+ * Returns
+ *
+ ******************************************************************************/
+uint8_t bta_jv_alloc_sec_id(void) {
+  uint8_t ret = 0;
+  int i;
+  for (i = 0; i < BTA_JV_NUM_SERVICE_ID; i++) {
+    if (0 == bta_jv_cb.sec_id[i]) {
+      bta_jv_cb.sec_id[i] = BTA_JV_FIRST_SERVICE_ID + i;
+      ret = bta_jv_cb.sec_id[i];
+      break;
+    }
+  }
+  return ret;
+}
+static int get_sec_id_used(void) {
+  int i;
+  int used = 0;
+  for (i = 0; i < BTA_JV_NUM_SERVICE_ID; i++) {
+    if (bta_jv_cb.sec_id[i]) used++;
+  }
+  if (used == BTA_JV_NUM_SERVICE_ID)
+    APPL_TRACE_ERROR("get_sec_id_used, sec id exceeds the limit:%d",
+                     BTA_JV_NUM_SERVICE_ID);
+  return used;
+}
+static int get_rfc_cb_used(void) {
+  int i;
+  int used = 0;
+  for (i = 0; i < BTA_JV_MAX_RFC_CONN; i++) {
+    if (bta_jv_cb.rfc_cb[i].handle) used++;
+  }
+  if (used == BTA_JV_MAX_RFC_CONN)
+    APPL_TRACE_ERROR("get_sec_id_used, rfc ctrl block exceeds the limit:%d",
+                     BTA_JV_MAX_RFC_CONN);
+  return used;
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_free_sec_id
+ *
+ * Description  free the given security id
+ *
+ * Returns
+ *
+ ******************************************************************************/
+static void bta_jv_free_sec_id(uint8_t* p_sec_id) {
+  uint8_t sec_id = *p_sec_id;
+  *p_sec_id = 0;
+  if (sec_id >= BTA_JV_FIRST_SERVICE_ID && sec_id <= BTA_JV_LAST_SERVICE_ID) {
+    BTM_SecClrService(sec_id);
+    bta_jv_cb.sec_id[sec_id - BTA_JV_FIRST_SERVICE_ID] = 0;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_alloc_rfc_cb
+ *
+ * Description  allocate a control block for the given port handle
+ *
+ * Returns
+ *
+ ******************************************************************************/
+tBTA_JV_RFC_CB* bta_jv_alloc_rfc_cb(uint16_t port_handle,
+                                    tBTA_JV_PCB** pp_pcb) {
+  tBTA_JV_RFC_CB* p_cb = NULL;
+  tBTA_JV_PCB* p_pcb;
+  int i, j;
+  for (i = 0; i < BTA_JV_MAX_RFC_CONN; i++) {
+    if (0 == bta_jv_cb.rfc_cb[i].handle) {
+      p_cb = &bta_jv_cb.rfc_cb[i];
+      /* mask handle to distinguish it with L2CAP handle */
+      p_cb->handle = (i + 1) | BTA_JV_RFCOMM_MASK;
+
+      p_cb->max_sess = 1;
+      p_cb->curr_sess = 1;
+      for (j = 0; j < BTA_JV_MAX_RFC_SR_SESSION; j++) p_cb->rfc_hdl[j] = 0;
+      p_cb->rfc_hdl[0] = port_handle;
+      APPL_TRACE_DEBUG("bta_jv_alloc_rfc_cb port_handle:%d handle:0x%2x",
+                       port_handle, p_cb->handle);
+
+      p_pcb = &bta_jv_cb.port_cb[port_handle - 1];
+      p_pcb->handle = p_cb->handle;
+      p_pcb->port_handle = port_handle;
+      p_pcb->p_pm_cb = NULL;
+      *pp_pcb = p_pcb;
+      break;
+    }
+  }
+  if (p_cb == NULL) {
+    APPL_TRACE_ERROR(
+        "bta_jv_alloc_rfc_cb: port_handle:%d, ctrl block exceeds "
+        "limit:%d",
+        port_handle, BTA_JV_MAX_RFC_CONN);
+  }
+  return p_cb;
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_rfc_port_to_pcb
+ *
+ * Description  find the port control block associated with the given port
+ *              handle
+ *
+ * Returns
+ *
+ ******************************************************************************/
+tBTA_JV_PCB* bta_jv_rfc_port_to_pcb(uint16_t port_handle) {
+  tBTA_JV_PCB* p_pcb = NULL;
+
+  if ((port_handle > 0) && (port_handle <= MAX_RFC_PORTS) &&
+      bta_jv_cb.port_cb[port_handle - 1].handle) {
+    p_pcb = &bta_jv_cb.port_cb[port_handle - 1];
+  }
+
+  return p_pcb;
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_rfc_port_to_cb
+ *
+ * Description  find the RFCOMM control block associated with the given port
+ *              handle
+ *
+ * Returns
+ *
+ ******************************************************************************/
+tBTA_JV_RFC_CB* bta_jv_rfc_port_to_cb(uint16_t port_handle) {
+  tBTA_JV_RFC_CB* p_cb = NULL;
+  uint32_t handle;
+
+  if ((port_handle > 0) && (port_handle <= MAX_RFC_PORTS) &&
+      bta_jv_cb.port_cb[port_handle - 1].handle) {
+    handle = bta_jv_cb.port_cb[port_handle - 1].handle;
+    handle &= BTA_JV_RFC_HDL_MASK;
+    handle &= ~BTA_JV_RFCOMM_MASK;
+    if (handle) p_cb = &bta_jv_cb.rfc_cb[handle - 1];
+  } else {
+    APPL_TRACE_WARNING(
+        "bta_jv_rfc_port_to_cb(port_handle:0x%x):jv handle:0x%x not"
+        " FOUND",
+        port_handle, bta_jv_cb.port_cb[port_handle - 1].handle);
+  }
+  return p_cb;
+}
+
+static tBTA_JV_STATUS bta_jv_free_rfc_cb(tBTA_JV_RFC_CB* p_cb,
+                                         tBTA_JV_PCB* p_pcb) {
+  tBTA_JV_STATUS status = BTA_JV_SUCCESS;
+  bool remove_server = false;
+  int close_pending = 0;
+
+  if (!p_cb || !p_pcb) {
+    APPL_TRACE_ERROR("bta_jv_free_sr_rfc_cb, p_cb or p_pcb cannot be null");
+    return BTA_JV_FAILURE;
+  }
+  APPL_TRACE_DEBUG(
+      "bta_jv_free_sr_rfc_cb: max_sess:%d, curr_sess:%d, p_pcb:%p, user:"
+      "%p, state:%d, jv handle: 0x%x",
+      p_cb->max_sess, p_cb->curr_sess, p_pcb, p_pcb->user_data, p_pcb->state,
+      p_pcb->handle);
+
+  if (p_cb->curr_sess <= 0) return BTA_JV_SUCCESS;
+
+  switch (p_pcb->state) {
+    case BTA_JV_ST_CL_CLOSING:
+    case BTA_JV_ST_SR_CLOSING:
+      APPL_TRACE_WARNING(
+          "bta_jv_free_sr_rfc_cb: return on closing, port state:%d, "
+          "scn:%d, p_pcb:%p, user_data:%p",
+          p_pcb->state, p_cb->scn, p_pcb, p_pcb->user_data);
+      status = BTA_JV_FAILURE;
+      return status;
+    case BTA_JV_ST_CL_OPEN:
+    case BTA_JV_ST_CL_OPENING:
+      APPL_TRACE_DEBUG(
+          "bta_jv_free_sr_rfc_cb: state: %d, scn:%d,"
+          " user_data:%p",
+          p_pcb->state, p_cb->scn, p_pcb->user_data);
+      p_pcb->state = BTA_JV_ST_CL_CLOSING;
+      break;
+    case BTA_JV_ST_SR_LISTEN:
+      p_pcb->state = BTA_JV_ST_SR_CLOSING;
+      remove_server = true;
+      APPL_TRACE_DEBUG(
+          "bta_jv_free_sr_rfc_cb: state: BTA_JV_ST_SR_LISTEN, scn:%d,"
+          " user_data:%p",
+          p_cb->scn, p_pcb->user_data);
+      break;
+    case BTA_JV_ST_SR_OPEN:
+      p_pcb->state = BTA_JV_ST_SR_CLOSING;
+      APPL_TRACE_DEBUG(
+          "bta_jv_free_sr_rfc_cb: state: BTA_JV_ST_SR_OPEN, scn:%d,"
+          " user_data:%p",
+          p_cb->scn, p_pcb->user_data);
+      break;
+    default:
+      APPL_TRACE_WARNING(
+          "bta_jv_free_sr_rfc_cb():failed, ignore port state:%d, scn:"
+          "%d, p_pcb:%p, jv handle: 0x%x, port_handle: %d, user_data:%p",
+          p_pcb->state, p_cb->scn, p_pcb, p_pcb->handle, p_pcb->port_handle,
+          p_pcb->user_data);
+      status = BTA_JV_FAILURE;
+      break;
+  }
+  if (BTA_JV_SUCCESS == status) {
+    int port_status;
+
+    if (!remove_server)
+      port_status = RFCOMM_RemoveConnection(p_pcb->port_handle);
+    else
+      port_status = RFCOMM_RemoveServer(p_pcb->port_handle);
+    if (port_status != PORT_SUCCESS) {
+      status = BTA_JV_FAILURE;
+      APPL_TRACE_WARNING(
+          "bta_jv_free_rfc_cb(jv handle: 0x%x, state %d)::"
+          "port_status: %d, port_handle: %d, close_pending: %d:Remove",
+          p_pcb->handle, p_pcb->state, port_status, p_pcb->port_handle,
+          close_pending);
+    }
+  }
+  if (!close_pending) {
+    p_pcb->port_handle = 0;
+    p_pcb->state = BTA_JV_ST_NONE;
+    bta_jv_free_set_pm_profile_cb(p_pcb->handle);
+
+    // Initialize congestion flags
+    p_pcb->cong = false;
+    p_pcb->user_data = 0;
+    int si = BTA_JV_RFC_HDL_TO_SIDX(p_pcb->handle);
+    if (0 <= si && si < BTA_JV_MAX_RFC_SR_SESSION) p_cb->rfc_hdl[si] = 0;
+    p_pcb->handle = 0;
+    p_cb->curr_sess--;
+    if (p_cb->curr_sess == 0) {
+      p_cb->scn = 0;
+      bta_jv_free_sec_id(&p_cb->sec_id);
+      p_cb->p_cback = NULL;
+      p_cb->handle = 0;
+      p_cb->curr_sess = -1;
+    }
+    if (remove_server) {
+      bta_jv_free_sec_id(&p_cb->sec_id);
+    }
+  }
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_free_l2c_cb
+ *
+ * Description  free the given L2CAP control block
+ *
+ * Returns
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS bta_jv_free_l2c_cb(tBTA_JV_L2C_CB* p_cb) {
+  tBTA_JV_STATUS status = BTA_JV_SUCCESS;
+
+  if (BTA_JV_ST_NONE != p_cb->state) {
+    bta_jv_free_set_pm_profile_cb((uint32_t)p_cb->handle);
+    if (GAP_ConnClose(p_cb->handle) != BT_PASS) status = BTA_JV_FAILURE;
+  }
+  p_cb->psm = 0;
+  p_cb->state = BTA_JV_ST_NONE;
+  p_cb->cong = false;
+  bta_jv_free_sec_id(&p_cb->sec_id);
+  p_cb->p_cback = NULL;
+  return status;
+}
+
+/*******************************************************************************
+ *
+ *
+ * Function    bta_jv_clear_pm_cb
+ *
+ * Description clears jv pm control block and optionally calls
+ *             bta_sys_conn_close()
+ *             In general close_conn should be set to true to remove registering
+ *             with dm pm!
+ *
+ * WARNING:    Make sure to clear pointer form port or l2c to this control block
+ *             too!
+ *
+ ******************************************************************************/
+static void bta_jv_clear_pm_cb(tBTA_JV_PM_CB* p_pm_cb, bool close_conn) {
+  /* needs to be called if registered with bta pm, otherwise we may run out of
+   * dm pm slots! */
+  if (close_conn)
+    bta_sys_conn_close(BTA_ID_JV, p_pm_cb->app_id, p_pm_cb->peer_bd_addr);
+  p_pm_cb->state = BTA_JV_PM_FREE_ST;
+  p_pm_cb->app_id = BTA_JV_PM_ALL;
+  p_pm_cb->handle = BTA_JV_PM_HANDLE_CLEAR;
+  bdcpy(p_pm_cb->peer_bd_addr, bd_addr_null);
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_free_set_pm_profile_cb
+ *
+ * Description  free pm profile control block
+ *
+ * Returns     BTA_JV_SUCCESS if cb has been freed correctly,
+ *             BTA_JV_FAILURE in case of no profile has been registered or
+ *             already freed
+ *
+ *******************************************************************************/
+static tBTA_JV_STATUS bta_jv_free_set_pm_profile_cb(uint32_t jv_handle) {
+  tBTA_JV_STATUS status = BTA_JV_FAILURE;
+  tBTA_JV_PM_CB** p_cb;
+  int i, j, bd_counter = 0, appid_counter = 0;
+
+  for (i = 0; i < BTA_JV_PM_MAX_NUM; i++) {
+    p_cb = NULL;
+    if ((bta_jv_cb.pm_cb[i].state != BTA_JV_PM_FREE_ST) &&
+        (jv_handle == bta_jv_cb.pm_cb[i].handle)) {
+      for (j = 0; j < BTA_JV_PM_MAX_NUM; j++) {
+        if (bdcmp(bta_jv_cb.pm_cb[j].peer_bd_addr,
+                  bta_jv_cb.pm_cb[i].peer_bd_addr) == 0)
+          bd_counter++;
+        if (bta_jv_cb.pm_cb[j].app_id == bta_jv_cb.pm_cb[i].app_id)
+          appid_counter++;
+      }
+
+      APPL_TRACE_API(
+          "%s(jv_handle: 0x%2x), idx: %d, "
+          "app_id: 0x%x",
+          __func__, jv_handle, i, bta_jv_cb.pm_cb[i].app_id);
+      APPL_TRACE_API(
+          "%s, bd_counter = %d, "
+          "appid_counter = %d",
+          __func__, bd_counter, appid_counter);
+      if (bd_counter > 1) {
+        bta_jv_pm_conn_idle(&bta_jv_cb.pm_cb[i]);
+      }
+
+      if (bd_counter <= 1 || (appid_counter <= 1)) {
+        bta_jv_clear_pm_cb(&bta_jv_cb.pm_cb[i], true);
+      } else {
+        bta_jv_clear_pm_cb(&bta_jv_cb.pm_cb[i], false);
+      }
+
+      if (BTA_JV_RFCOMM_MASK & jv_handle) {
+        uint32_t hi =
+            ((jv_handle & BTA_JV_RFC_HDL_MASK) & ~BTA_JV_RFCOMM_MASK) - 1;
+        uint32_t si = BTA_JV_RFC_HDL_TO_SIDX(jv_handle);
+        if (hi < BTA_JV_MAX_RFC_CONN && bta_jv_cb.rfc_cb[hi].p_cback &&
+            si < BTA_JV_MAX_RFC_SR_SESSION &&
+            bta_jv_cb.rfc_cb[hi].rfc_hdl[si]) {
+          tBTA_JV_PCB* p_pcb =
+              bta_jv_rfc_port_to_pcb(bta_jv_cb.rfc_cb[hi].rfc_hdl[si]);
+          if (p_pcb) {
+            if (NULL == p_pcb->p_pm_cb)
+              APPL_TRACE_WARNING(
+                  "%s(jv_handle:"
+                  " 0x%x):port_handle: 0x%x, p_pm_cb: %d: no link to "
+                  "pm_cb?",
+                  __func__, jv_handle, p_pcb->port_handle, i);
+            p_cb = &p_pcb->p_pm_cb;
+          }
+        }
+      } else {
+        if (jv_handle < BTA_JV_MAX_L2C_CONN) {
+          tBTA_JV_L2C_CB* p_l2c_cb = &bta_jv_cb.l2c_cb[jv_handle];
+          if (NULL == p_l2c_cb->p_pm_cb)
+            APPL_TRACE_WARNING(
+                "%s(jv_handle: "
+                "0x%x): p_pm_cb: %d: no link to pm_cb?",
+                __func__, jv_handle, i);
+          p_cb = &p_l2c_cb->p_pm_cb;
+        }
+      }
+      if (p_cb) {
+        *p_cb = NULL;
+        status = BTA_JV_SUCCESS;
+      }
+    }
+  }
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function    bta_jv_alloc_set_pm_profile_cb
+ *
+ * Description set PM profile control block
+ *
+ * Returns     pointer to allocated cb or NULL in case of failure
+ *
+ *******************************************************************************/
+static tBTA_JV_PM_CB* bta_jv_alloc_set_pm_profile_cb(uint32_t jv_handle,
+                                                     tBTA_JV_PM_ID app_id) {
+  bool bRfcHandle = (jv_handle & BTA_JV_RFCOMM_MASK) != 0;
+  BD_ADDR peer_bd_addr;
+  int i, j;
+  tBTA_JV_PM_CB** pp_cb;
+
+  for (i = 0; i < BTA_JV_PM_MAX_NUM; i++) {
+    pp_cb = NULL;
+    if (bta_jv_cb.pm_cb[i].state == BTA_JV_PM_FREE_ST) {
+      /* rfc handle bd addr retrieval requires core stack handle */
+      if (bRfcHandle) {
+        for (j = 0; j < BTA_JV_MAX_RFC_CONN; j++) {
+          if (jv_handle == bta_jv_cb.port_cb[j].handle) {
+            pp_cb = &bta_jv_cb.port_cb[j].p_pm_cb;
+            if (PORT_SUCCESS !=
+                PORT_CheckConnection(bta_jv_cb.port_cb[j].port_handle,
+                                     peer_bd_addr, NULL))
+              i = BTA_JV_PM_MAX_NUM;
+            break;
+          }
+        }
+      } else {
+        /* use jv handle for l2cap bd address retrieval */
+        for (j = 0; j < BTA_JV_MAX_L2C_CONN; j++) {
+          if (jv_handle == bta_jv_cb.l2c_cb[j].handle) {
+            pp_cb = &bta_jv_cb.l2c_cb[j].p_pm_cb;
+            uint8_t* p_bd_addr = GAP_ConnGetRemoteAddr((uint16_t)jv_handle);
+            if (NULL != p_bd_addr)
+              bdcpy(peer_bd_addr, p_bd_addr);
+            else
+              i = BTA_JV_PM_MAX_NUM;
+            break;
+          }
+        }
+      }
+      APPL_TRACE_API(
+          "bta_jv_alloc_set_pm_profile_cb(handle 0x%2x, app_id %d): "
+          "idx: %d, (BTA_JV_PM_MAX_NUM: %d), pp_cb: 0x%x",
+          jv_handle, app_id, i, BTA_JV_PM_MAX_NUM, pp_cb);
+      break;
+    }
+  }
+
+  if ((i != BTA_JV_PM_MAX_NUM) && (NULL != pp_cb)) {
+    *pp_cb = &bta_jv_cb.pm_cb[i];
+    bta_jv_cb.pm_cb[i].handle = jv_handle;
+    bta_jv_cb.pm_cb[i].app_id = app_id;
+    bdcpy(bta_jv_cb.pm_cb[i].peer_bd_addr, peer_bd_addr);
+    bta_jv_cb.pm_cb[i].state = BTA_JV_PM_IDLE_ST;
+    return &bta_jv_cb.pm_cb[i];
+  }
+  APPL_TRACE_WARNING(
+      "bta_jv_alloc_set_pm_profile_cb(jv_handle: 0x%x, app_id: %d) "
+      "return NULL",
+      jv_handle, app_id);
+  return (tBTA_JV_PM_CB*)NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_check_psm
+ *
+ * Description  for now use only the legal PSM per JSR82 spec
+ *
+ * Returns      true, if allowed
+ *
+ ******************************************************************************/
+bool bta_jv_check_psm(uint16_t psm) {
+  bool ret = false;
+
+  if (L2C_IS_VALID_PSM(psm)) {
+    if (psm < 0x1001) {
+      /* see if this is defined by spec */
+      switch (psm) {
+        case SDP_PSM:       /* 1 */
+        case BT_PSM_RFCOMM: /* 3 */
+          /* do not allow java app to use these 2 PSMs */
+          break;
+
+        case TCS_PSM_INTERCOM: /* 5 */
+        case TCS_PSM_CORDLESS: /* 7 */
+          if (false == bta_sys_is_register(BTA_ID_CT) &&
+              false == bta_sys_is_register(BTA_ID_CG))
+            ret = true;
+          break;
+
+        case BT_PSM_BNEP: /* F */
+          if (false == bta_sys_is_register(BTA_ID_PAN)) ret = true;
+          break;
+
+        case HID_PSM_CONTROL:   /* 0x11 */
+        case HID_PSM_INTERRUPT: /* 0x13 */
+          // FIX: allow HID Device and HID Host to coexist
+          if (false == bta_sys_is_register(BTA_ID_HD) ||
+              false == bta_sys_is_register(BTA_ID_HH))
+            ret = true;
+          break;
+
+        case AVCT_PSM: /* 0x17 */
+        case AVDT_PSM: /* 0x19 */
+          if ((false == bta_sys_is_register(BTA_ID_AV)) &&
+              (false == bta_sys_is_register(BTA_ID_AVK)))
+            ret = true;
+          break;
+
+        default:
+          ret = true;
+          break;
+      }
+    } else {
+      ret = true;
+    }
+  }
+  return ret;
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_enable
+ *
+ * Description  Initialises the JAVA I/F
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_jv_enable(tBTA_JV_MSG* p_data) {
+  tBTA_JV_STATUS status = BTA_JV_SUCCESS;
+  bta_jv_cb.p_dm_cback = p_data->enable.p_cback;
+  bta_jv_cb.p_dm_cback(BTA_JV_ENABLE_EVT, (tBTA_JV*)&status, 0);
+  memset(bta_jv_cb.free_psm_list, 0, sizeof(bta_jv_cb.free_psm_list));
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_disable
+ *
+ * Description  Disables the BT device manager
+ *              free the resources used by java
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_jv_disable(UNUSED_ATTR tBTA_JV_MSG* p_data) {
+  APPL_TRACE_ERROR("%s", __func__);
+}
+
+/**
+ * We keep a list of PSM's that have been freed from JAVA, for reuse.
+ * This function will return a free PSM, and delete it from the free
+ * list.
+ * If no free PSMs exist, 0 will be returned.
+ */
+static uint16_t bta_jv_get_free_psm() {
+  const int cnt =
+      sizeof(bta_jv_cb.free_psm_list) / sizeof(bta_jv_cb.free_psm_list[0]);
+  for (int i = 0; i < cnt; i++) {
+    uint16_t psm = bta_jv_cb.free_psm_list[i];
+    if (psm != 0) {
+      APPL_TRACE_DEBUG("%s(): Reusing PSM: 0x%04d", __func__, psm)
+      bta_jv_cb.free_psm_list[i] = 0;
+      return psm;
+    }
+  }
+  return 0;
+}
+
+static void bta_jv_set_free_psm(uint16_t psm) {
+  int free_index = -1;
+  const int cnt =
+      sizeof(bta_jv_cb.free_psm_list) / sizeof(bta_jv_cb.free_psm_list[0]);
+  for (int i = 0; i < cnt; i++) {
+    if (bta_jv_cb.free_psm_list[i] == 0) {
+      free_index = i;
+    } else if (psm == bta_jv_cb.free_psm_list[i]) {
+      return;  // PSM already freed?
+    }
+  }
+  if (free_index != -1) {
+    bta_jv_cb.free_psm_list[free_index] = psm;
+    APPL_TRACE_DEBUG("%s(): Recycling PSM: 0x%04d", __func__, psm)
+  } else {
+    APPL_TRACE_ERROR("%s unable to free psm 0x%x no more free slots", __func__,
+                     psm);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_get_channel_id
+ *
+ * Description  Obtain a free SCN (Server Channel Number)
+ *              (RFCOMM channel or L2CAP PSM)
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_jv_get_channel_id(tBTA_JV_MSG* p_data) {
+  uint16_t psm = 0;
+
+  switch (p_data->alloc_channel.type) {
+    case BTA_JV_CONN_TYPE_RFCOMM: {
+      int32_t channel = p_data->alloc_channel.channel;
+      uint8_t scn = 0;
+      if (channel > 0) {
+        if (BTM_TryAllocateSCN(channel) == false) {
+          APPL_TRACE_ERROR("rfc channel:%d already in use or invalid", channel);
+          channel = 0;
+        }
+      } else if ((channel = BTM_AllocateSCN()) == 0) {
+        APPL_TRACE_ERROR("run out of rfc channels");
+        channel = 0;
+      }
+      if (channel != 0) {
+        bta_jv_cb.scn[channel - 1] = true;
+        scn = (uint8_t)channel;
+      }
+      if (bta_jv_cb.p_dm_cback)
+        bta_jv_cb.p_dm_cback(BTA_JV_GET_SCN_EVT, (tBTA_JV*)&scn,
+                             p_data->alloc_channel.user_data);
+      return;
+    }
+    case BTA_JV_CONN_TYPE_L2CAP:
+      psm = bta_jv_get_free_psm();
+      if (psm == 0) {
+        psm = L2CA_AllocatePSM();
+        APPL_TRACE_DEBUG("%s() returned PSM: 0x%04x", __func__, psm);
+      }
+      break;
+    case BTA_JV_CONN_TYPE_L2CAP_LE:
+      break;
+    default:
+      break;
+  }
+
+  if (bta_jv_cb.p_dm_cback)
+    bta_jv_cb.p_dm_cback(BTA_JV_GET_PSM_EVT, (tBTA_JV*)&psm,
+                         p_data->alloc_channel.user_data);
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_free_scn
+ *
+ * Description  free a SCN
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_jv_free_scn(tBTA_JV_MSG* p_data) {
+  uint16_t scn = p_data->free_channel.scn;
+
+  switch (p_data->free_channel.type) {
+    case BTA_JV_CONN_TYPE_RFCOMM: {
+      if (scn > 0 && scn <= BTA_JV_MAX_SCN && bta_jv_cb.scn[scn - 1]) {
+        /* this scn is used by JV */
+        bta_jv_cb.scn[scn - 1] = false;
+        BTM_FreeSCN(scn);
+      }
+      break;
+    }
+    case BTA_JV_CONN_TYPE_L2CAP:
+      bta_jv_set_free_psm(scn);
+      break;
+    case BTA_JV_CONN_TYPE_L2CAP_LE:
+      // TODO: Not yet implemented...
+      break;
+    default:
+      break;
+  }
+}
+static inline tBT_UUID shorten_sdp_uuid(const tBT_UUID* u) {
+  static uint8_t bt_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                   0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+                                   0x5F, 0x9B, 0x34, 0xFB};
+
+  logu("in, uuid:", u->uu.uuid128);
+  APPL_TRACE_DEBUG("uuid len:%d", u->len);
+  if (u->len == 16) {
+    if (memcmp(&u->uu.uuid128[4], &bt_base_uuid[4], 12) == 0) {
+      tBT_UUID su;
+      memset(&su, 0, sizeof(su));
+      if (u->uu.uuid128[0] == 0 && u->uu.uuid128[1] == 0) {
+        su.len = 2;
+        uint16_t u16;
+        memcpy(&u16, &u->uu.uuid128[2], sizeof(u16));
+        su.uu.uuid16 = ntohs(u16);
+        APPL_TRACE_DEBUG("shorten to 16 bits uuid: %x", su.uu.uuid16);
+      } else {
+        su.len = 4;
+        uint32_t u32;
+        memcpy(&u32, &u->uu.uuid128[0], sizeof(u32));
+        su.uu.uuid32 = ntohl(u32);
+        APPL_TRACE_DEBUG("shorten to 32 bits uuid: %x", su.uu.uuid32);
+      }
+      return su;
+    }
+  }
+  APPL_TRACE_DEBUG("cannot shorten none-reserved 128 bits uuid");
+  return *u;
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_start_discovery_cback
+ *
+ * Description  Callback for Start Discovery
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+static void bta_jv_start_discovery_cback(uint16_t result, void* user_data) {
+  tBTA_JV_STATUS status;
+
+  APPL_TRACE_DEBUG("bta_jv_start_discovery_cback res: 0x%x", result);
+
+  bta_jv_cb.sdp_active = BTA_JV_SDP_ACT_NONE;
+  if (bta_jv_cb.p_dm_cback) {
+    tBTA_JV_DISCOVERY_COMP dcomp;
+    dcomp.scn = 0;
+    status = BTA_JV_FAILURE;
+    if (result == SDP_SUCCESS || result == SDP_DB_FULL) {
+      tSDP_DISC_REC* p_sdp_rec = NULL;
+      tSDP_PROTOCOL_ELEM pe;
+      logu("bta_jv_cb.uuid", bta_jv_cb.uuid.uu.uuid128);
+      tBT_UUID su = shorten_sdp_uuid(&bta_jv_cb.uuid);
+      logu("shorten uuid:", su.uu.uuid128);
+      p_sdp_rec =
+          SDP_FindServiceUUIDInDb(p_bta_jv_cfg->p_sdp_db, &su, p_sdp_rec);
+      APPL_TRACE_DEBUG("p_sdp_rec:%p", p_sdp_rec);
+      if (p_sdp_rec &&
+          SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+        dcomp.scn = (uint8_t)pe.params[0];
+        status = BTA_JV_SUCCESS;
+      }
+    }
+
+    dcomp.status = status;
+    bta_jv_cb.p_dm_cback(BTA_JV_DISCOVERY_COMP_EVT, (tBTA_JV*)&dcomp,
+                         user_data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_start_discovery
+ *
+ * Description  Discovers services on a remote device
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_jv_start_discovery(tBTA_JV_MSG* p_data) {
+  tBTA_JV_STATUS status = BTA_JV_FAILURE;
+  APPL_TRACE_DEBUG("bta_jv_start_discovery in, sdp_active:%d",
+                   bta_jv_cb.sdp_active);
+  if (bta_jv_cb.sdp_active != BTA_JV_SDP_ACT_NONE) {
+    /* SDP is still in progress */
+    status = BTA_JV_BUSY;
+    if (bta_jv_cb.p_dm_cback)
+      bta_jv_cb.p_dm_cback(BTA_JV_DISCOVERY_COMP_EVT, (tBTA_JV*)&status,
+                           p_data->start_discovery.user_data);
+    return;
+  }
+
+  /* init the database/set up the filter */
+  APPL_TRACE_DEBUG(
+      "call SDP_InitDiscoveryDb, p_data->start_discovery.num_uuid:%d",
+      p_data->start_discovery.num_uuid);
+  SDP_InitDiscoveryDb(p_bta_jv_cfg->p_sdp_db, p_bta_jv_cfg->sdp_db_size,
+                      p_data->start_discovery.num_uuid,
+                      p_data->start_discovery.uuid_list, 0, NULL);
+
+  /* tell SDP to keep the raw data */
+  p_bta_jv_cfg->p_sdp_db->raw_data = p_bta_jv_cfg->p_sdp_raw_data;
+  p_bta_jv_cfg->p_sdp_db->raw_size = p_bta_jv_cfg->sdp_raw_size;
+
+  bta_jv_cb.p_sel_raw_data = 0;
+  bta_jv_cb.uuid = p_data->start_discovery.uuid_list[0];
+
+  bta_jv_cb.sdp_active = BTA_JV_SDP_ACT_YES;
+  if (!SDP_ServiceSearchAttributeRequest2(
+          p_data->start_discovery.bd_addr, p_bta_jv_cfg->p_sdp_db,
+          bta_jv_start_discovery_cback, p_data->start_discovery.user_data)) {
+    bta_jv_cb.sdp_active = BTA_JV_SDP_ACT_NONE;
+    /* failed to start SDP. report the failure right away */
+    if (bta_jv_cb.p_dm_cback)
+      bta_jv_cb.p_dm_cback(BTA_JV_DISCOVERY_COMP_EVT, (tBTA_JV*)&status,
+                           p_data->start_discovery.user_data);
+  }
+  /*
+  else report the result when the cback is called
+  */
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_create_record
+ *
+ * Description  Create an SDP record with the given attributes
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_jv_create_record(tBTA_JV_MSG* p_data) {
+  tBTA_JV_API_CREATE_RECORD* cr = &(p_data->create_record);
+  tBTA_JV_CREATE_RECORD evt_data;
+  evt_data.status = BTA_JV_SUCCESS;
+  if (bta_jv_cb.p_dm_cback)
+    // callback user immediately to create his own sdp record in stack thread
+    // context
+    bta_jv_cb.p_dm_cback(BTA_JV_CREATE_RECORD_EVT, (tBTA_JV*)&evt_data,
+                         cr->user_data);
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_delete_record
+ *
+ * Description  Delete an SDP record
+ *
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_jv_delete_record(tBTA_JV_MSG* p_data) {
+  tBTA_JV_API_ADD_ATTRIBUTE* dr = &(p_data->add_attr);
+  if (dr->handle) {
+    /* this is a record created by btif layer*/
+    SDP_DeleteRecord(dr->handle);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_l2cap_client_cback
+ *
+ * Description  handles the l2cap client events
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+static void bta_jv_l2cap_client_cback(uint16_t gap_handle, uint16_t event) {
+  tBTA_JV_L2C_CB* p_cb = &bta_jv_cb.l2c_cb[gap_handle];
+  tBTA_JV evt_data;
+
+  if (gap_handle >= BTA_JV_MAX_L2C_CONN && !p_cb->p_cback) return;
+
+  APPL_TRACE_DEBUG("%s: %d evt:x%x", __func__, gap_handle, event);
+  evt_data.l2c_open.status = BTA_JV_SUCCESS;
+  evt_data.l2c_open.handle = gap_handle;
+
+  switch (event) {
+    case GAP_EVT_CONN_OPENED:
+      bdcpy(evt_data.l2c_open.rem_bda, GAP_ConnGetRemoteAddr(gap_handle));
+      evt_data.l2c_open.tx_mtu = GAP_ConnGetRemMtuSize(gap_handle);
+      p_cb->state = BTA_JV_ST_CL_OPEN;
+      p_cb->p_cback(BTA_JV_L2CAP_OPEN_EVT, &evt_data, p_cb->user_data);
+      break;
+
+    case GAP_EVT_CONN_CLOSED:
+      p_cb->state = BTA_JV_ST_NONE;
+      bta_jv_free_sec_id(&p_cb->sec_id);
+      evt_data.l2c_close.async = true;
+      p_cb->p_cback(BTA_JV_L2CAP_CLOSE_EVT, &evt_data, p_cb->user_data);
+      p_cb->p_cback = NULL;
+      break;
+
+    case GAP_EVT_CONN_DATA_AVAIL:
+      evt_data.data_ind.handle = gap_handle;
+      /* Reset idle timer to avoid requesting sniff mode while receiving data */
+      bta_jv_pm_conn_busy(p_cb->p_pm_cb);
+      p_cb->p_cback(BTA_JV_L2CAP_DATA_IND_EVT, &evt_data, p_cb->user_data);
+      bta_jv_pm_conn_idle(p_cb->p_pm_cb);
+      break;
+
+    case GAP_EVT_TX_EMPTY:
+      bta_jv_pm_conn_idle(p_cb->p_pm_cb);
+      break;
+
+    case GAP_EVT_CONN_CONGESTED:
+    case GAP_EVT_CONN_UNCONGESTED:
+      p_cb->cong = (event == GAP_EVT_CONN_CONGESTED) ? true : false;
+      evt_data.l2c_cong.cong = p_cb->cong;
+      p_cb->p_cback(BTA_JV_L2CAP_CONG_EVT, &evt_data, p_cb->user_data);
+      break;
+
+    default:
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_l2cap_connect
+ *
+ * Description  makes an l2cap client connection
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_jv_l2cap_connect(tBTA_JV_MSG* p_data) {
+  tBTA_JV_L2C_CB* p_cb;
+  tBTA_JV_L2CAP_CL_INIT evt_data;
+  uint16_t handle = GAP_INVALID_HANDLE;
+  uint8_t sec_id;
+  tL2CAP_CFG_INFO cfg;
+  tBTA_JV_API_L2CAP_CONNECT* cc = &(p_data->l2cap_connect);
+  uint8_t chan_mode_mask = GAP_FCR_CHAN_OPT_BASIC;
+  tL2CAP_ERTM_INFO* ertm_info = NULL;
+
+  memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+  if (cc->has_cfg == true) {
+    cfg = cc->cfg;
+    if (cfg.fcr_present && cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
+      chan_mode_mask = GAP_FCR_CHAN_OPT_ERTM;
+    }
+  }
+
+  if (cc->has_ertm_info == true) {
+    ertm_info = &(cc->ertm_info);
+  }
+
+  /* We need to use this value for MTU to be able to handle cases where cfg is
+   * not set in req. */
+  cfg.mtu_present = true;
+  cfg.mtu = cc->rx_mtu;
+
+  /* TODO: DM role manager
+  L2CA_SetDesireRole(cc->role);
+  */
+
+  sec_id = bta_jv_alloc_sec_id();
+  evt_data.sec_id = sec_id;
+  evt_data.status = BTA_JV_FAILURE;
+
+  if (sec_id) {
+    /* PSM checking is not required for LE COC */
+    if ((cc->type != BTA_JV_CONN_TYPE_L2CAP) ||
+        (bta_jv_check_psm(cc->remote_psm))) /* allowed */
+    {
+      if ((handle = GAP_ConnOpen("", sec_id, 0, cc->peer_bd_addr,
+                                 cc->remote_psm, &cfg, ertm_info, cc->sec_mask,
+                                 chan_mode_mask, bta_jv_l2cap_client_cback,
+                                 cc->type)) != GAP_INVALID_HANDLE) {
+        evt_data.status = BTA_JV_SUCCESS;
+      }
+    }
+  }
+
+  if (evt_data.status == BTA_JV_SUCCESS) {
+    p_cb = &bta_jv_cb.l2c_cb[handle];
+    p_cb->handle = handle;
+    p_cb->p_cback = cc->p_cback;
+    p_cb->user_data = cc->user_data;
+    p_cb->psm = 0; /* not a server */
+    p_cb->sec_id = sec_id;
+    p_cb->state = BTA_JV_ST_CL_OPENING;
+  } else {
+    bta_jv_free_sec_id(&sec_id);
+  }
+
+  evt_data.handle = handle;
+  if (cc->p_cback)
+    cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, (tBTA_JV*)&evt_data, cc->user_data);
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_l2cap_close
+ *
+ * Description  Close an L2CAP client connection
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_jv_l2cap_close(tBTA_JV_MSG* p_data) {
+  tBTA_JV_L2CAP_CLOSE evt_data;
+  tBTA_JV_API_L2CAP_CLOSE* cc = &(p_data->l2cap_close);
+  tBTA_JV_L2CAP_CBACK* p_cback = cc->p_cb->p_cback;
+  void* user_data = cc->p_cb->user_data;
+
+  evt_data.handle = cc->handle;
+  evt_data.status = bta_jv_free_l2c_cb(cc->p_cb);
+  evt_data.async = false;
+
+  if (p_cback) p_cback(BTA_JV_L2CAP_CLOSE_EVT, (tBTA_JV*)&evt_data, user_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_jv_l2cap_server_cback
+ *
+ * Description      handles the l2cap server callback
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_jv_l2cap_server_cback(uint16_t gap_handle, uint16_t event) {
+  tBTA_JV_L2C_CB* p_cb = &bta_jv_cb.l2c_cb[gap_handle];
+  tBTA_JV evt_data;
+  tBTA_JV_L2CAP_CBACK* p_cback;
+  void* user_data;
+
+  if (gap_handle >= BTA_JV_MAX_L2C_CONN && !p_cb->p_cback) return;
+
+  APPL_TRACE_DEBUG("%s: %d evt:x%x", __func__, gap_handle, event);
+  evt_data.l2c_open.status = BTA_JV_SUCCESS;
+  evt_data.l2c_open.handle = gap_handle;
+
+  switch (event) {
+    case GAP_EVT_CONN_OPENED:
+      bdcpy(evt_data.l2c_open.rem_bda, GAP_ConnGetRemoteAddr(gap_handle));
+      evt_data.l2c_open.tx_mtu = GAP_ConnGetRemMtuSize(gap_handle);
+      p_cb->state = BTA_JV_ST_SR_OPEN;
+      p_cb->p_cback(BTA_JV_L2CAP_OPEN_EVT, &evt_data, p_cb->user_data);
+      break;
+
+    case GAP_EVT_CONN_CLOSED:
+      evt_data.l2c_close.async = true;
+      evt_data.l2c_close.handle = p_cb->handle;
+      p_cback = p_cb->p_cback;
+      user_data = p_cb->user_data;
+      evt_data.l2c_close.status = bta_jv_free_l2c_cb(p_cb);
+      p_cback(BTA_JV_L2CAP_CLOSE_EVT, &evt_data, user_data);
+      break;
+
+    case GAP_EVT_CONN_DATA_AVAIL:
+      evt_data.data_ind.handle = gap_handle;
+      /* Reset idle timer to avoid requesting sniff mode while receiving data */
+      bta_jv_pm_conn_busy(p_cb->p_pm_cb);
+      p_cb->p_cback(BTA_JV_L2CAP_DATA_IND_EVT, &evt_data, p_cb->user_data);
+      bta_jv_pm_conn_idle(p_cb->p_pm_cb);
+      break;
+
+    case GAP_EVT_TX_EMPTY:
+      bta_jv_pm_conn_idle(p_cb->p_pm_cb);
+      break;
+
+    case GAP_EVT_CONN_CONGESTED:
+    case GAP_EVT_CONN_UNCONGESTED:
+      p_cb->cong = (event == GAP_EVT_CONN_CONGESTED) ? true : false;
+      evt_data.l2c_cong.cong = p_cb->cong;
+      p_cb->p_cback(BTA_JV_L2CAP_CONG_EVT, &evt_data, p_cb->user_data);
+      break;
+
+    default:
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_l2cap_start_server
+ *
+ * Description  starts an L2CAP server
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_jv_l2cap_start_server(tBTA_JV_MSG* p_data) {
+  tBTA_JV_L2C_CB* p_cb;
+  uint8_t sec_id;
+  uint16_t handle;
+  tL2CAP_CFG_INFO cfg;
+  tBTA_JV_L2CAP_START evt_data;
+  tBTA_JV_API_L2CAP_SERVER* ls = &(p_data->l2cap_server);
+  uint8_t chan_mode_mask = GAP_FCR_CHAN_OPT_BASIC;
+  tL2CAP_ERTM_INFO* ertm_info = NULL;
+
+  memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+  if (ls->has_cfg == true) {
+    cfg = ls->cfg;
+    if (cfg.fcr_present && cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
+      chan_mode_mask = GAP_FCR_CHAN_OPT_ERTM;
+    }
+  }
+
+  if (ls->has_ertm_info == true) {
+    ertm_info = &(ls->ertm_info);
+  }
+
+  // FIX: MTU=0 means not present
+  if (ls->rx_mtu > 0) {
+    cfg.mtu_present = true;
+    cfg.mtu = ls->rx_mtu;
+  } else {
+    cfg.mtu_present = false;
+    cfg.mtu = 0;
+  }
+
+  /* TODO DM role manager
+  L2CA_SetDesireRole(ls->role);
+  */
+
+  sec_id = bta_jv_alloc_sec_id();
+  /* PSM checking is not required for LE COC */
+  if (0 == sec_id || ((ls->type == BTA_JV_CONN_TYPE_L2CAP) &&
+                      (false == bta_jv_check_psm(ls->local_psm))) ||
+      (handle = GAP_ConnOpen("JV L2CAP", sec_id, 1, 0, ls->local_psm, &cfg,
+                             ertm_info, ls->sec_mask, chan_mode_mask,
+                             bta_jv_l2cap_server_cback, ls->type)) ==
+          GAP_INVALID_HANDLE) {
+    bta_jv_free_sec_id(&sec_id);
+    evt_data.status = BTA_JV_FAILURE;
+  } else {
+    p_cb = &bta_jv_cb.l2c_cb[handle];
+    evt_data.status = BTA_JV_SUCCESS;
+    evt_data.handle = handle;
+    evt_data.sec_id = sec_id;
+    p_cb->p_cback = ls->p_cback;
+    p_cb->user_data = ls->user_data;
+    p_cb->handle = handle;
+    p_cb->sec_id = sec_id;
+    p_cb->state = BTA_JV_ST_SR_LISTEN;
+    p_cb->psm = ls->local_psm;
+  }
+
+  if (ls->p_cback)
+    ls->p_cback(BTA_JV_L2CAP_START_EVT, (tBTA_JV*)&evt_data, ls->user_data);
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_l2cap_stop_server
+ *
+ * Description  stops an L2CAP server
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_jv_l2cap_stop_server(tBTA_JV_MSG* p_data) {
+  tBTA_JV_L2C_CB* p_cb;
+  tBTA_JV_L2CAP_CLOSE evt_data;
+  tBTA_JV_API_L2CAP_SERVER* ls = &(p_data->l2cap_server);
+  tBTA_JV_L2CAP_CBACK* p_cback;
+  void* user_data;
+  for (int i = 0; i < BTA_JV_MAX_L2C_CONN; i++) {
+    if (bta_jv_cb.l2c_cb[i].psm == ls->local_psm) {
+      p_cb = &bta_jv_cb.l2c_cb[i];
+      p_cback = p_cb->p_cback;
+      user_data = p_cb->user_data;
+      evt_data.handle = p_cb->handle;
+      evt_data.status = bta_jv_free_l2c_cb(p_cb);
+      evt_data.async = false;
+      if (p_cback)
+        p_cback(BTA_JV_L2CAP_CLOSE_EVT, (tBTA_JV*)&evt_data, user_data);
+      break;
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_l2cap_read
+ *
+ * Description  Read data from an L2CAP connection
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_jv_l2cap_read(tBTA_JV_MSG* p_data) {
+  tBTA_JV_L2CAP_READ evt_data;
+  tBTA_JV_API_L2CAP_READ* rc = &(p_data->l2cap_read);
+
+  evt_data.status = BTA_JV_FAILURE;
+  evt_data.handle = rc->handle;
+  evt_data.req_id = rc->req_id;
+  evt_data.p_data = rc->p_data;
+  evt_data.len = 0;
+
+  if (BT_PASS ==
+      GAP_ConnReadData(rc->handle, rc->p_data, rc->len, &evt_data.len)) {
+    evt_data.status = BTA_JV_SUCCESS;
+  }
+
+  rc->p_cback(BTA_JV_L2CAP_READ_EVT, (tBTA_JV*)&evt_data, rc->user_data);
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_l2cap_write
+ *
+ * Description  Write data to an L2CAP connection
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_jv_l2cap_write(tBTA_JV_MSG* p_data) {
+  tBTA_JV_L2CAP_WRITE evt_data;
+  tBTA_JV_API_L2CAP_WRITE* ls = &(p_data->l2cap_write);
+
+  /* As we check this callback exists before the tBTA_JV_API_L2CAP_WRITE can be
+   * send through the
+   * API this check should not be needed.
+   * But the API is not designed to be used (safely at least) in a
+   * multi-threaded scheduler, hence
+   * if the peer device disconnects the l2cap link after the API is called, but
+   * before this
+   * message is handled, the ->p_cback will be cleared at this point. At first
+   * glanch this seems
+   * highly unlikely, but for all obex-profiles with two channels connected -
+   * e.g. MAP, this
+   * happens around 1 of 4 disconnects, as a disconnect on the server channel
+   * causes a disconnect
+   * to be send on the client (notification) channel, but at the peer typically
+   * disconnects both
+   * the OBEX disconnect request crosses the incoming l2cap disconnect.
+   * If p_cback is cleared, we simply discard the data.
+   * RISK: The caller must handle any cleanup based on another signal than
+   * BTA_JV_L2CAP_WRITE_EVT,
+   *       which is typically not possible, as the pointer to the allocated
+   * buffer is stored
+   *       in this message, and can therefore not be freed, hence we have a
+   * mem-leak-by-design.*/
+  if (ls->p_cb->p_cback != NULL) {
+    evt_data.status = BTA_JV_FAILURE;
+    evt_data.handle = ls->handle;
+    evt_data.req_id = ls->req_id;
+    evt_data.cong = ls->p_cb->cong;
+    evt_data.len = 0;
+    bta_jv_pm_conn_busy(ls->p_cb->p_pm_cb);
+    if (!evt_data.cong &&
+        BT_PASS ==
+            GAP_ConnWriteData(ls->handle, ls->p_data, ls->len, &evt_data.len)) {
+      evt_data.status = BTA_JV_SUCCESS;
+    }
+    ls->p_cb->p_cback(BTA_JV_L2CAP_WRITE_EVT, (tBTA_JV*)&evt_data,
+                      ls->user_data);
+  } else {
+    /* As this pointer is checked in the API function, this occurs only when the
+     * channel is
+     * disconnected after the API function is called, but before the message is
+     * handled. */
+    APPL_TRACE_ERROR("%s() ls->p_cb->p_cback == NULL", __func__);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_l2cap_write_fixed
+ *
+ * Description  Write data to an L2CAP connection using Fixed channels
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_jv_l2cap_write_fixed(tBTA_JV_MSG* p_data) {
+  tBTA_JV_L2CAP_WRITE_FIXED evt_data;
+  tBTA_JV_API_L2CAP_WRITE_FIXED* ls = &(p_data->l2cap_write_fixed);
+  BT_HDR* msg =
+      (BT_HDR*)osi_malloc(sizeof(BT_HDR) + ls->len + L2CAP_MIN_OFFSET);
+
+  evt_data.status = BTA_JV_FAILURE;
+  evt_data.channel = ls->channel;
+  memcpy(evt_data.addr, ls->addr, sizeof(evt_data.addr));
+  evt_data.req_id = ls->req_id;
+  evt_data.len = 0;
+
+  memcpy(((uint8_t*)(msg + 1)) + L2CAP_MIN_OFFSET, ls->p_data, ls->len);
+  msg->len = ls->len;
+  msg->offset = L2CAP_MIN_OFFSET;
+
+  L2CA_SendFixedChnlData(ls->channel, ls->addr, msg);
+
+  ls->p_cback(BTA_JV_L2CAP_WRITE_FIXED_EVT, (tBTA_JV*)&evt_data, ls->user_data);
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_port_data_co_cback
+ *
+ * Description  port data callback function of rfcomm
+ *              connections
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+static int bta_jv_port_data_co_cback(uint16_t port_handle, uint8_t* buf,
+                                     uint16_t len, int type) {
+  tBTA_JV_RFC_CB* p_cb = bta_jv_rfc_port_to_cb(port_handle);
+  tBTA_JV_PCB* p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
+  APPL_TRACE_DEBUG("%s, p_cb:%p, p_pcb:%p, len:%d, type:%d", __func__, p_cb,
+                   p_pcb, len, type);
+  if (p_pcb != NULL) {
+    switch (type) {
+      case DATA_CO_CALLBACK_TYPE_INCOMING:
+        return bta_co_rfc_data_incoming(p_pcb->user_data, (BT_HDR*)buf);
+      case DATA_CO_CALLBACK_TYPE_OUTGOING_SIZE:
+        return bta_co_rfc_data_outgoing_size(p_pcb->user_data, (int*)buf);
+      case DATA_CO_CALLBACK_TYPE_OUTGOING:
+        return bta_co_rfc_data_outgoing(p_pcb->user_data, buf, len);
+      default:
+        APPL_TRACE_ERROR("unknown callout type:%d", type);
+        break;
+    }
+  }
+  return 0;
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_port_mgmt_cl_cback
+ *
+ * Description  callback for port mamangement function of rfcomm
+ *              client connections
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+static void bta_jv_port_mgmt_cl_cback(uint32_t code, uint16_t port_handle) {
+  tBTA_JV_RFC_CB* p_cb = bta_jv_rfc_port_to_cb(port_handle);
+  tBTA_JV_PCB* p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
+  tBTA_JV evt_data;
+  BD_ADDR rem_bda;
+  uint16_t lcid;
+  tBTA_JV_RFCOMM_CBACK* p_cback; /* the callback function */
+
+  APPL_TRACE_DEBUG("bta_jv_port_mgmt_cl_cback:code:%d, port_handle%d", code,
+                   port_handle);
+  if (NULL == p_cb || NULL == p_cb->p_cback) return;
+
+  APPL_TRACE_DEBUG("bta_jv_port_mgmt_cl_cback code=%d port_handle:%d handle:%d",
+                   code, port_handle, p_cb->handle);
+
+  PORT_CheckConnection(port_handle, rem_bda, &lcid);
+
+  if (code == PORT_SUCCESS) {
+    evt_data.rfc_open.handle = p_cb->handle;
+    evt_data.rfc_open.status = BTA_JV_SUCCESS;
+    bdcpy(evt_data.rfc_open.rem_bda, rem_bda);
+    p_pcb->state = BTA_JV_ST_CL_OPEN;
+    p_cb->p_cback(BTA_JV_RFCOMM_OPEN_EVT, &evt_data, p_pcb->user_data);
+  } else {
+    evt_data.rfc_close.handle = p_cb->handle;
+    evt_data.rfc_close.status = BTA_JV_FAILURE;
+    evt_data.rfc_close.port_status = code;
+    evt_data.rfc_close.async = true;
+    if (p_pcb->state == BTA_JV_ST_CL_CLOSING) {
+      evt_data.rfc_close.async = false;
+    }
+    // p_pcb->state = BTA_JV_ST_NONE;
+    // p_pcb->cong = false;
+    p_cback = p_cb->p_cback;
+    p_cback(BTA_JV_RFCOMM_CLOSE_EVT, &evt_data, p_pcb->user_data);
+    // bta_jv_free_rfc_cb(p_cb, p_pcb);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_port_event_cl_cback
+ *
+ * Description  Callback for RFCOMM client port events
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+static void bta_jv_port_event_cl_cback(uint32_t code, uint16_t port_handle) {
+  tBTA_JV_RFC_CB* p_cb = bta_jv_rfc_port_to_cb(port_handle);
+  tBTA_JV_PCB* p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
+  tBTA_JV evt_data;
+
+  APPL_TRACE_DEBUG("bta_jv_port_event_cl_cback:%d", port_handle);
+  if (NULL == p_cb || NULL == p_cb->p_cback) return;
+
+  APPL_TRACE_DEBUG(
+      "bta_jv_port_event_cl_cback code=x%x port_handle:%d handle:%d", code,
+      port_handle, p_cb->handle);
+  if (code & PORT_EV_RXCHAR) {
+    evt_data.data_ind.handle = p_cb->handle;
+    p_cb->p_cback(BTA_JV_RFCOMM_DATA_IND_EVT, &evt_data, p_pcb->user_data);
+  }
+
+  if (code & PORT_EV_FC) {
+    p_pcb->cong = (code & PORT_EV_FCS) ? false : true;
+    evt_data.rfc_cong.cong = p_pcb->cong;
+    evt_data.rfc_cong.handle = p_cb->handle;
+    evt_data.rfc_cong.status = BTA_JV_SUCCESS;
+    p_cb->p_cback(BTA_JV_RFCOMM_CONG_EVT, &evt_data, p_pcb->user_data);
+  }
+
+  if (code & PORT_EV_TXEMPTY) {
+    bta_jv_pm_conn_idle(p_pcb->p_pm_cb);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_rfcomm_connect
+ *
+ * Description  Client initiates an RFCOMM connection
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_jv_rfcomm_connect(tBTA_JV_MSG* p_data) {
+  uint16_t handle = 0;
+  uint32_t event_mask = BTA_JV_RFC_EV_MASK;
+  tPORT_STATE port_state;
+  uint8_t sec_id = 0;
+  tBTA_JV_RFC_CB* p_cb = NULL;
+  tBTA_JV_PCB* p_pcb;
+  tBTA_JV_API_RFCOMM_CONNECT* cc = &(p_data->rfcomm_connect);
+  tBTA_JV_RFCOMM_CL_INIT evt_data;
+
+  /* TODO DM role manager
+  L2CA_SetDesireRole(cc->role);
+  */
+
+  sec_id = bta_jv_alloc_sec_id();
+  memset(&evt_data, 0, sizeof(evt_data));
+  evt_data.sec_id = sec_id;
+  evt_data.status = BTA_JV_SUCCESS;
+  if (0 == sec_id ||
+      BTM_SetSecurityLevel(true, "", sec_id, cc->sec_mask, BT_PSM_RFCOMM,
+                           BTM_SEC_PROTO_RFCOMM, cc->remote_scn) == false) {
+    evt_data.status = BTA_JV_FAILURE;
+    APPL_TRACE_ERROR(
+        "sec_id:%d is zero or BTM_SetSecurityLevel failed, remote_scn:%d",
+        sec_id, cc->remote_scn);
+  }
+
+  if (evt_data.status == BTA_JV_SUCCESS &&
+      RFCOMM_CreateConnection(UUID_SERVCLASS_SERIAL_PORT, cc->remote_scn, false,
+                              BTA_JV_DEF_RFC_MTU, cc->peer_bd_addr, &handle,
+                              bta_jv_port_mgmt_cl_cback) != PORT_SUCCESS) {
+    APPL_TRACE_ERROR("bta_jv_rfcomm_connect, RFCOMM_CreateConnection failed");
+    evt_data.status = BTA_JV_FAILURE;
+  }
+  if (evt_data.status == BTA_JV_SUCCESS) {
+    p_cb = bta_jv_alloc_rfc_cb(handle, &p_pcb);
+    if (p_cb) {
+      p_cb->p_cback = cc->p_cback;
+      p_cb->sec_id = sec_id;
+      p_cb->scn = 0;
+      p_pcb->state = BTA_JV_ST_CL_OPENING;
+      p_pcb->user_data = cc->user_data;
+      evt_data.use_co = true;
+
+      PORT_SetEventCallback(handle, bta_jv_port_event_cl_cback);
+      PORT_SetEventMask(handle, event_mask);
+      PORT_SetDataCOCallback(handle, bta_jv_port_data_co_cback);
+
+      PORT_GetState(handle, &port_state);
+
+      port_state.fc_type = (PORT_FC_CTS_ON_INPUT | PORT_FC_CTS_ON_OUTPUT);
+
+      /* coverity[uninit_use_in_call]
+         false-POSITIVE: port_state is initialized at PORT_GetState() */
+      PORT_SetState(handle, &port_state);
+
+      evt_data.handle = p_cb->handle;
+    } else {
+      evt_data.status = BTA_JV_FAILURE;
+      APPL_TRACE_ERROR("run out of rfc control block");
+    }
+  }
+  cc->p_cback(BTA_JV_RFCOMM_CL_INIT_EVT, (tBTA_JV*)&evt_data, cc->user_data);
+  if (evt_data.status == BTA_JV_FAILURE) {
+    if (sec_id) bta_jv_free_sec_id(&sec_id);
+    if (handle) RFCOMM_RemoveConnection(handle);
+  }
+}
+
+static int find_rfc_pcb(void* user_data, tBTA_JV_RFC_CB** cb,
+                        tBTA_JV_PCB** pcb) {
+  *cb = NULL;
+  *pcb = NULL;
+  int i;
+  for (i = 0; i < MAX_RFC_PORTS; i++) {
+    uint32_t rfc_handle = bta_jv_cb.port_cb[i].handle & BTA_JV_RFC_HDL_MASK;
+    rfc_handle &= ~BTA_JV_RFCOMM_MASK;
+    if (rfc_handle && bta_jv_cb.port_cb[i].user_data == user_data) {
+      *pcb = &bta_jv_cb.port_cb[i];
+      *cb = &bta_jv_cb.rfc_cb[rfc_handle - 1];
+      APPL_TRACE_DEBUG(
+          "find_rfc_pcb(): FOUND rfc_cb_handle 0x%x, port.jv_handle:"
+          " 0x%x, state: %d, rfc_cb->handle: 0x%x",
+          rfc_handle, (*pcb)->handle, (*pcb)->state, (*cb)->handle);
+      return 1;
+    }
+  }
+  APPL_TRACE_DEBUG("find_rfc_pcb: cannot find rfc_cb from user data: %u",
+                   PTR_TO_UINT(user_data));
+  return 0;
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_rfcomm_close
+ *
+ * Description  Close an RFCOMM connection
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_jv_rfcomm_close(tBTA_JV_MSG* p_data) {
+  tBTA_JV_API_RFCOMM_CLOSE* cc = &(p_data->rfcomm_close);
+  tBTA_JV_RFC_CB* p_cb = NULL;
+  tBTA_JV_PCB* p_pcb = NULL;
+  APPL_TRACE_DEBUG("bta_jv_rfcomm_close, rfc handle:%d", cc->handle);
+  if (!cc->handle) {
+    APPL_TRACE_ERROR("bta_jv_rfcomm_close, rfc handle is null");
+    return;
+  }
+
+  void* user_data = cc->user_data;
+  if (!find_rfc_pcb(user_data, &p_cb, &p_pcb)) return;
+  bta_jv_free_rfc_cb(p_cb, p_pcb);
+  APPL_TRACE_DEBUG("bta_jv_rfcomm_close: sec id in use:%d, rfc_cb in use:%d",
+                   get_sec_id_used(), get_rfc_cb_used());
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_port_mgmt_sr_cback
+ *
+ * Description  callback for port mamangement function of rfcomm
+ *              server connections
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+static void bta_jv_port_mgmt_sr_cback(uint32_t code, uint16_t port_handle) {
+  tBTA_JV_PCB* p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
+  tBTA_JV_RFC_CB* p_cb = bta_jv_rfc_port_to_cb(port_handle);
+  tBTA_JV evt_data;
+  BD_ADDR rem_bda;
+  uint16_t lcid;
+  APPL_TRACE_DEBUG("bta_jv_port_mgmt_sr_cback, code:%d, port_handle:%d", code,
+                   port_handle);
+  if (NULL == p_cb || NULL == p_cb->p_cback) {
+    APPL_TRACE_ERROR("bta_jv_port_mgmt_sr_cback, p_cb:%p, p_cb->p_cback%p",
+                     p_cb, p_cb ? p_cb->p_cback : NULL);
+    return;
+  }
+  void* user_data = p_pcb->user_data;
+  APPL_TRACE_DEBUG(
+      "bta_jv_port_mgmt_sr_cback code=%d port_handle:0x%x handle:0x%x, "
+      "p_pcb:%p, user:%d",
+      code, port_handle, p_cb->handle, p_pcb, p_pcb->user_data);
+
+  PORT_CheckConnection(port_handle, rem_bda, &lcid);
+  int failed = true;
+  if (code == PORT_SUCCESS) {
+    evt_data.rfc_srv_open.handle = p_pcb->handle;
+    evt_data.rfc_srv_open.status = BTA_JV_SUCCESS;
+    bdcpy(evt_data.rfc_srv_open.rem_bda, rem_bda);
+    tBTA_JV_PCB* p_pcb_new_listen = bta_jv_add_rfc_port(p_cb, p_pcb);
+    if (p_pcb_new_listen) {
+      evt_data.rfc_srv_open.new_listen_handle = p_pcb_new_listen->handle;
+      p_pcb_new_listen->user_data =
+          p_cb->p_cback(BTA_JV_RFCOMM_SRV_OPEN_EVT, &evt_data, user_data);
+      APPL_TRACE_DEBUG("PORT_SUCCESS: curr_sess:%d, max_sess:%d",
+                       p_cb->curr_sess, p_cb->max_sess);
+      failed = false;
+    } else
+      APPL_TRACE_ERROR("bta_jv_add_rfc_port failed to create new listen port");
+  }
+  if (failed) {
+    evt_data.rfc_close.handle = p_cb->handle;
+    evt_data.rfc_close.status = BTA_JV_FAILURE;
+    evt_data.rfc_close.async = true;
+    evt_data.rfc_close.port_status = code;
+    p_pcb->cong = false;
+
+    tBTA_JV_RFCOMM_CBACK* p_cback = p_cb->p_cback;
+    APPL_TRACE_DEBUG(
+        "PORT_CLOSED before BTA_JV_RFCOMM_CLOSE_EVT: curr_sess:%d, max_sess:%d",
+        p_cb->curr_sess, p_cb->max_sess);
+    if (BTA_JV_ST_SR_CLOSING == p_pcb->state) {
+      evt_data.rfc_close.async = false;
+      evt_data.rfc_close.status = BTA_JV_SUCCESS;
+    }
+    // p_pcb->state = BTA_JV_ST_NONE;
+    p_cback(BTA_JV_RFCOMM_CLOSE_EVT, &evt_data, user_data);
+    // bta_jv_free_rfc_cb(p_cb, p_pcb);
+
+    APPL_TRACE_DEBUG(
+        "PORT_CLOSED after BTA_JV_RFCOMM_CLOSE_EVT: curr_sess:%d, max_sess:%d",
+        p_cb->curr_sess, p_cb->max_sess);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_port_event_sr_cback
+ *
+ * Description  Callback for RFCOMM server port events
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+static void bta_jv_port_event_sr_cback(uint32_t code, uint16_t port_handle) {
+  tBTA_JV_PCB* p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
+  tBTA_JV_RFC_CB* p_cb = bta_jv_rfc_port_to_cb(port_handle);
+  tBTA_JV evt_data;
+
+  if (NULL == p_cb || NULL == p_cb->p_cback) return;
+
+  APPL_TRACE_DEBUG(
+      "bta_jv_port_event_sr_cback code=x%x port_handle:%d handle:%d", code,
+      port_handle, p_cb->handle);
+
+  void* user_data = p_pcb->user_data;
+  if (code & PORT_EV_RXCHAR) {
+    evt_data.data_ind.handle = p_cb->handle;
+    p_cb->p_cback(BTA_JV_RFCOMM_DATA_IND_EVT, &evt_data, user_data);
+  }
+
+  if (code & PORT_EV_FC) {
+    p_pcb->cong = (code & PORT_EV_FCS) ? false : true;
+    evt_data.rfc_cong.cong = p_pcb->cong;
+    evt_data.rfc_cong.handle = p_cb->handle;
+    evt_data.rfc_cong.status = BTA_JV_SUCCESS;
+    p_cb->p_cback(BTA_JV_RFCOMM_CONG_EVT, &evt_data, user_data);
+  }
+
+  if (code & PORT_EV_TXEMPTY) {
+    bta_jv_pm_conn_idle(p_pcb->p_pm_cb);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_add_rfc_port
+ *
+ * Description  add a port for server when the existing posts is open
+ *
+ * Returns   return a pointer to tBTA_JV_PCB just added
+ *
+ ******************************************************************************/
+static tBTA_JV_PCB* bta_jv_add_rfc_port(tBTA_JV_RFC_CB* p_cb,
+                                        tBTA_JV_PCB* p_pcb_open) {
+  uint8_t used = 0, i, listen = 0;
+  uint32_t si = 0;
+  tPORT_STATE port_state;
+  uint32_t event_mask = BTA_JV_RFC_EV_MASK;
+  tBTA_JV_PCB* p_pcb = NULL;
+  if (p_cb->max_sess > 1) {
+    for (i = 0; i < p_cb->max_sess; i++) {
+      if (p_cb->rfc_hdl[i] != 0) {
+        p_pcb = &bta_jv_cb.port_cb[p_cb->rfc_hdl[i] - 1];
+        if (p_pcb->state == BTA_JV_ST_SR_LISTEN) {
+          listen++;
+          if (p_pcb_open == p_pcb) {
+            APPL_TRACE_DEBUG(
+                "bta_jv_add_rfc_port, port_handle:%d, change the listen port "
+                "to open state",
+                p_pcb->port_handle);
+            p_pcb->state = BTA_JV_ST_SR_OPEN;
+
+          } else {
+            APPL_TRACE_ERROR(
+                "bta_jv_add_rfc_port, open pcb not matching listen one,"
+                "listen count:%d, listen pcb handle:%d, open pcb:%d",
+                listen, p_pcb->port_handle, p_pcb_open->handle);
+            return NULL;
+          }
+        }
+        used++;
+      } else if (si == 0) {
+        si = i + 1;
+      }
+    }
+
+    APPL_TRACE_DEBUG(
+        "bta_jv_add_rfc_port max_sess=%d used:%d curr_sess:%d, listen:%d si:%d",
+        p_cb->max_sess, used, p_cb->curr_sess, listen, si);
+    if (used < p_cb->max_sess && listen == 1 && si) {
+      si--;
+      if (RFCOMM_CreateConnection(p_cb->sec_id, p_cb->scn, true,
+                                  BTA_JV_DEF_RFC_MTU, (uint8_t*)bd_addr_any,
+                                  &(p_cb->rfc_hdl[si]),
+                                  bta_jv_port_mgmt_sr_cback) == PORT_SUCCESS) {
+        p_cb->curr_sess++;
+        p_pcb = &bta_jv_cb.port_cb[p_cb->rfc_hdl[si] - 1];
+        p_pcb->state = BTA_JV_ST_SR_LISTEN;
+        p_pcb->port_handle = p_cb->rfc_hdl[si];
+        p_pcb->user_data = p_pcb_open->user_data;
+
+        PORT_ClearKeepHandleFlag(p_pcb->port_handle);
+        PORT_SetEventCallback(p_pcb->port_handle, bta_jv_port_event_sr_cback);
+        PORT_SetDataCOCallback(p_pcb->port_handle, bta_jv_port_data_co_cback);
+        PORT_SetEventMask(p_pcb->port_handle, event_mask);
+        PORT_GetState(p_pcb->port_handle, &port_state);
+
+        port_state.fc_type = (PORT_FC_CTS_ON_INPUT | PORT_FC_CTS_ON_OUTPUT);
+
+        PORT_SetState(p_pcb->port_handle, &port_state);
+        p_pcb->handle = BTA_JV_RFC_H_S_TO_HDL(p_cb->handle, si);
+        APPL_TRACE_DEBUG(
+            "bta_jv_add_rfc_port: p_pcb->handle:0x%x, curr_sess:%d",
+            p_pcb->handle, p_cb->curr_sess);
+      }
+    } else
+      APPL_TRACE_ERROR(
+          "bta_jv_add_rfc_port, cannot create new rfc listen port");
+  }
+  APPL_TRACE_DEBUG("bta_jv_add_rfc_port: sec id in use:%d, rfc_cb in use:%d",
+                   get_sec_id_used(), get_rfc_cb_used());
+  return p_pcb;
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_rfcomm_start_server
+ *
+ * Description  waits for an RFCOMM client to connect
+ *
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_jv_rfcomm_start_server(tBTA_JV_MSG* p_data) {
+  uint16_t handle = 0;
+  uint32_t event_mask = BTA_JV_RFC_EV_MASK;
+  tPORT_STATE port_state;
+  uint8_t sec_id = 0;
+  tBTA_JV_RFC_CB* p_cb = NULL;
+  tBTA_JV_PCB* p_pcb;
+  tBTA_JV_API_RFCOMM_SERVER* rs = &(p_data->rfcomm_server);
+  tBTA_JV_RFCOMM_START evt_data;
+
+  /* TODO DM role manager
+  L2CA_SetDesireRole(rs->role);
+  */
+  memset(&evt_data, 0, sizeof(evt_data));
+  evt_data.status = BTA_JV_FAILURE;
+  APPL_TRACE_DEBUG(
+      "bta_jv_rfcomm_start_server: sec id in use:%d, rfc_cb in use:%d",
+      get_sec_id_used(), get_rfc_cb_used());
+
+  do {
+    sec_id = bta_jv_alloc_sec_id();
+
+    if (0 == sec_id ||
+        BTM_SetSecurityLevel(false, "JV PORT", sec_id, rs->sec_mask,
+                             BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM,
+                             rs->local_scn) == false) {
+      APPL_TRACE_ERROR("bta_jv_rfcomm_start_server, run out of sec_id");
+      break;
+    }
+
+    if (RFCOMM_CreateConnection(sec_id, rs->local_scn, true, BTA_JV_DEF_RFC_MTU,
+                                (uint8_t*)bd_addr_any, &handle,
+                                bta_jv_port_mgmt_sr_cback) != PORT_SUCCESS) {
+      APPL_TRACE_ERROR(
+          "bta_jv_rfcomm_start_server, RFCOMM_CreateConnection failed");
+      break;
+    }
+
+    p_cb = bta_jv_alloc_rfc_cb(handle, &p_pcb);
+    if (!p_cb) {
+      APPL_TRACE_ERROR(
+          "bta_jv_rfcomm_start_server, run out of rfc control block");
+      break;
+    }
+
+    p_cb->max_sess = rs->max_session;
+    p_cb->p_cback = rs->p_cback;
+    p_cb->sec_id = sec_id;
+    p_cb->scn = rs->local_scn;
+    p_pcb->state = BTA_JV_ST_SR_LISTEN;
+    p_pcb->user_data = rs->user_data;
+    evt_data.status = BTA_JV_SUCCESS;
+    evt_data.handle = p_cb->handle;
+    evt_data.sec_id = sec_id;
+    evt_data.use_co = true;
+
+    PORT_ClearKeepHandleFlag(handle);
+    PORT_SetEventCallback(handle, bta_jv_port_event_sr_cback);
+    PORT_SetEventMask(handle, event_mask);
+    PORT_GetState(handle, &port_state);
+
+    port_state.fc_type = (PORT_FC_CTS_ON_INPUT | PORT_FC_CTS_ON_OUTPUT);
+
+    PORT_SetState(handle, &port_state);
+  } while (0);
+
+  rs->p_cback(BTA_JV_RFCOMM_START_EVT, (tBTA_JV*)&evt_data, rs->user_data);
+  if (evt_data.status == BTA_JV_SUCCESS) {
+    PORT_SetDataCOCallback(handle, bta_jv_port_data_co_cback);
+  } else {
+    if (sec_id) bta_jv_free_sec_id(&sec_id);
+    if (handle) RFCOMM_RemoveConnection(handle);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_rfcomm_stop_server
+ *
+ * Description  stops an RFCOMM server
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+
+void bta_jv_rfcomm_stop_server(tBTA_JV_MSG* p_data) {
+  tBTA_JV_API_RFCOMM_SERVER* ls = &(p_data->rfcomm_server);
+  tBTA_JV_RFC_CB* p_cb = NULL;
+  tBTA_JV_PCB* p_pcb = NULL;
+  APPL_TRACE_DEBUG("bta_jv_rfcomm_stop_server");
+  if (!ls->handle) {
+    APPL_TRACE_ERROR("bta_jv_rfcomm_stop_server, jv handle is null");
+    return;
+  }
+  void* user_data = ls->user_data;
+  if (!find_rfc_pcb(user_data, &p_cb, &p_pcb)) return;
+  APPL_TRACE_DEBUG("bta_jv_rfcomm_stop_server: p_pcb:%p, p_pcb->port_handle:%d",
+                   p_pcb, p_pcb->port_handle);
+  bta_jv_free_rfc_cb(p_cb, p_pcb);
+  APPL_TRACE_DEBUG(
+      "bta_jv_rfcomm_stop_server: sec id in use:%d, rfc_cb in use:%d",
+      get_sec_id_used(), get_rfc_cb_used());
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_rfcomm_write
+ *
+ * Description  write data to an RFCOMM connection
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_jv_rfcomm_write(tBTA_JV_MSG* p_data) {
+  tBTA_JV_API_RFCOMM_WRITE* wc = &(p_data->rfcomm_write);
+  tBTA_JV_RFC_CB* p_cb = wc->p_cb;
+  tBTA_JV_PCB* p_pcb = wc->p_pcb;
+
+  if (p_pcb->state == BTA_JV_ST_NONE) {
+    APPL_TRACE_ERROR("%s in state BTA_JV_ST_NONE - cannot write", __func__);
+    return;
+  }
+
+  tBTA_JV_RFCOMM_WRITE evt_data;
+  evt_data.status = BTA_JV_FAILURE;
+  evt_data.handle = p_cb->handle;
+  evt_data.req_id = wc->req_id;
+  evt_data.cong = p_pcb->cong;
+  evt_data.len = 0;
+
+  bta_jv_pm_conn_busy(p_pcb->p_pm_cb);
+
+  if (!evt_data.cong &&
+      PORT_WriteDataCO(p_pcb->port_handle, &evt_data.len) == PORT_SUCCESS) {
+    evt_data.status = BTA_JV_SUCCESS;
+  }
+
+  // Update congestion flag
+  evt_data.cong = p_pcb->cong;
+
+  if (p_cb->p_cback) {
+    p_cb->p_cback(BTA_JV_RFCOMM_WRITE_EVT, (tBTA_JV*)&evt_data,
+                  p_pcb->user_data);
+  } else {
+    APPL_TRACE_ERROR("%s No JV callback set", __func__);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_set_pm_profile
+ *
+ * Description  Set or free power mode profile for a JV application
+ *
+ * Returns      void
+ *
+ *******************************************************************************/
+void bta_jv_set_pm_profile(tBTA_JV_MSG* p_data) {
+  tBTA_JV_STATUS status;
+  tBTA_JV_PM_CB* p_cb;
+
+  APPL_TRACE_API("bta_jv_set_pm_profile(handle: 0x%x, app_id: %d, init_st: %d)",
+                 p_data->set_pm.handle, p_data->set_pm.app_id,
+                 p_data->set_pm.init_st);
+
+  /* clear PM control block */
+  if (p_data->set_pm.app_id == BTA_JV_PM_ID_CLEAR) {
+    status = bta_jv_free_set_pm_profile_cb(p_data->set_pm.handle);
+
+    if (status != BTA_JV_SUCCESS) {
+      APPL_TRACE_WARNING("bta_jv_set_pm_profile() free pm cb failed: reason %d",
+                         status);
+    }
+  } else /* set PM control block */
+  {
+    p_cb = bta_jv_alloc_set_pm_profile_cb(p_data->set_pm.handle,
+                                          p_data->set_pm.app_id);
+
+    if (NULL != p_cb)
+      bta_jv_pm_state_change(p_cb, p_data->set_pm.init_st);
+    else
+      APPL_TRACE_WARNING("bta_jv_alloc_set_pm_profile_cb() failed");
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_change_pm_state
+ *
+ * Description  change jv pm connect state, used internally
+ *
+ * Returns      void
+ *
+ *******************************************************************************/
+void bta_jv_change_pm_state(tBTA_JV_MSG* p_data) {
+  tBTA_JV_API_PM_STATE_CHANGE* p_msg = (tBTA_JV_API_PM_STATE_CHANGE*)p_data;
+
+  if (p_msg->p_cb) bta_jv_pm_state_change(p_msg->p_cb, p_msg->state);
+}
+
+/*******************************************************************************
+ *
+ * Function    bta_jv_set_pm_conn_state
+ *
+ * Description Send pm event state change to jv state machine to serialize jv pm
+ *             changes in relation to other jv messages. internal API use
+ *             mainly.
+ *
+ * Params:     p_cb: jv pm control block, NULL pointer returns failure
+ *             new_state: new PM connections state, setting is forced by action
+ *                        function
+ *
+ * Returns     BTA_JV_SUCCESS, BTA_JV_FAILURE (buffer allocation, or NULL ptr!)
+ *
+ *******************************************************************************/
+tBTA_JV_STATUS bta_jv_set_pm_conn_state(tBTA_JV_PM_CB* p_cb,
+                                        const tBTA_JV_CONN_STATE new_st) {
+  if (p_cb == NULL) return BTA_JV_FAILURE;
+
+  APPL_TRACE_API("%s: handle:0x%x, state: %d", __func__, p_cb->handle, new_st);
+
+  tBTA_JV_API_PM_STATE_CHANGE* p_msg = (tBTA_JV_API_PM_STATE_CHANGE*)osi_malloc(
+      sizeof(tBTA_JV_API_PM_STATE_CHANGE));
+  p_msg->hdr.event = BTA_JV_API_PM_STATE_CHANGE_EVT;
+  p_msg->p_cb = p_cb;
+  p_msg->state = new_st;
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function    bta_jv_pm_conn_busy
+ *
+ * Description set pm connection busy state (input param safe)
+ *
+ * Params      p_cb: pm control block of jv connection
+ *
+ * Returns     void
+ *
+ *******************************************************************************/
+static void bta_jv_pm_conn_busy(tBTA_JV_PM_CB* p_cb) {
+  if ((NULL != p_cb) && (BTA_JV_PM_IDLE_ST == p_cb->state))
+    bta_jv_pm_state_change(p_cb, BTA_JV_CONN_BUSY);
+}
+
+/*******************************************************************************
+ *
+ * Function    bta_jv_pm_conn_busy
+ *
+ * Description set pm connection busy state (input param safe)
+ *
+ * Params      p_cb: pm control block of jv connection
+ *
+ * Returns     void
+ *
+ *******************************************************************************/
+static void bta_jv_pm_conn_idle(tBTA_JV_PM_CB* p_cb) {
+  if ((NULL != p_cb) && (BTA_JV_PM_IDLE_ST != p_cb->state))
+    bta_jv_pm_state_change(p_cb, BTA_JV_CONN_IDLE);
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_pm_state_change
+ *
+ * Description  Notify power manager there is state change
+ *
+ * Params      p_cb: must be NONE NULL
+ *
+ * Returns      void
+ *
+ *******************************************************************************/
+static void bta_jv_pm_state_change(tBTA_JV_PM_CB* p_cb,
+                                   const tBTA_JV_CONN_STATE state) {
+  APPL_TRACE_API(
+      "bta_jv_pm_state_change(p_cb: 0x%x, handle: 0x%x, busy/idle_state: %d"
+      ", app_id: %d, conn_state: %d)",
+      p_cb, p_cb->handle, p_cb->state, p_cb->app_id, state);
+
+  switch (state) {
+    case BTA_JV_CONN_OPEN:
+      bta_sys_conn_open(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+      break;
+
+    case BTA_JV_CONN_CLOSE:
+      bta_sys_conn_close(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+      break;
+
+    case BTA_JV_APP_OPEN:
+      bta_sys_app_open(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+      break;
+
+    case BTA_JV_APP_CLOSE:
+      bta_sys_app_close(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+      break;
+
+    case BTA_JV_SCO_OPEN:
+      bta_sys_sco_open(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+      break;
+
+    case BTA_JV_SCO_CLOSE:
+      bta_sys_sco_close(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+      break;
+
+    case BTA_JV_CONN_IDLE:
+      p_cb->state = BTA_JV_PM_IDLE_ST;
+      bta_sys_idle(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+      break;
+
+    case BTA_JV_CONN_BUSY:
+      p_cb->state = BTA_JV_PM_BUSY_ST;
+      bta_sys_busy(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+      break;
+
+    default:
+      APPL_TRACE_WARNING("bta_jv_pm_state_change(state: %d): Invalid state",
+                         state);
+      break;
+  }
+}
+/**********************************************************************************************/
+
+static struct fc_channel* fcchan_get(uint16_t chan, char create) {
+  struct fc_channel* t = fc_channels;
+  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,
+              .max_transmit = 0xFF,
+              .rtrans_tout = 2000,
+              .mon_tout = 12000,
+              .mps = 670,
+              .tx_win_sz = 1,
+          },
+  };
+
+  while (t && t->chan != chan) t = t->next;
+
+  if (t)
+    return t;
+  else if (!create)
+    return NULL; /* we cannot alloc a struct if not asked to */
+
+  t = static_cast<struct fc_channel*>(osi_calloc(sizeof(*t)));
+  t->chan = chan;
+
+  if (!L2CA_RegisterFixedChannel(chan, &fcr)) {
+    osi_free(t);
+    return NULL;
+  }
+
+  // link it in
+  t->next = fc_channels;
+  fc_channels = t;
+
+  return t;
+}
+
+/* pass NULL to find servers */
+static struct fc_client* fcclient_find_by_addr(struct fc_client* start,
+                                               BD_ADDR addr) {
+  struct fc_client* t = start;
+
+  while (t) {
+    /* match client if have addr */
+    if (addr && !memcmp(addr, &t->remote_addr, sizeof(t->remote_addr))) break;
+
+    /* match server if do not have addr */
+    if (!addr && t->server) break;
+
+    t = t->next_all_list;
+  }
+
+  return t;
+}
+
+static struct fc_client* fcclient_find_by_id(uint32_t id) {
+  struct fc_client* t = fc_clients;
+
+  while (t && t->id != id) t = t->next_all_list;
+
+  return t;
+}
+
+static struct fc_client* fcclient_alloc(uint16_t chan, char server,
+                                        const uint8_t* sec_id_to_use) {
+  struct fc_channel* fc = fcchan_get(chan, true);
+  struct fc_client* t;
+  uint8_t sec_id;
+
+  if (!fc) return NULL;
+
+  if (fc->has_server && server)
+    return NULL; /* no way to have multiple servers on same channel */
+
+  if (sec_id_to_use)
+    sec_id = *sec_id_to_use;
+  else
+    sec_id = bta_jv_alloc_sec_id();
+
+  t = static_cast<fc_client*>(osi_calloc(sizeof(*t)));
+  // Allocate it a unique ID
+  do {
+    t->id = ++fc_next_id;
+  } while (!t->id || fcclient_find_by_id(t->id));
+
+  // Populate some params
+  t->chan = chan;
+  t->server = server;
+
+  // Get a security id
+  t->sec_id = sec_id;
+
+  // Link it in to global list
+  t->next_all_list = fc_clients;
+  fc_clients = t;
+
+  // Link it in to channel list
+  t->next_chan_list = fc->clients;
+  fc->clients = t;
+
+  // Update channel if needed
+  if (server) fc->has_server = true;
+
+  return t;
+}
+
+static void fcclient_free(struct fc_client* fc) {
+  struct fc_client* t = fc_clients;
+  struct fc_channel* tc = fcchan_get(fc->chan, false);
+
+  // remove from global list
+  while (t && t->next_all_list != fc) t = t->next_all_list;
+
+  if (!t && fc != fc_clients) return; /* prevent double-free */
+
+  if (t)
+    t->next_all_list = fc->next_all_list;
+  else
+    fc_clients = fc->next_all_list;
+
+  // remove from channel list
+  if (tc) {
+    t = tc->clients;
+
+    while (t && t->next_chan_list != fc) t = t->next_chan_list;
+
+    if (t)
+      t->next_chan_list = fc->next_chan_list;
+    else
+      tc->clients = fc->next_chan_list;
+
+    // if was server then channel no longer has a server
+    if (fc->server) tc->has_server = false;
+  }
+
+  // free security id
+  bta_jv_free_sec_id(&fc->sec_id);
+
+  osi_free(fc);
+}
+
+static void fcchan_conn_chng_cbk(uint16_t chan, BD_ADDR bd_addr, bool connected,
+                                 uint16_t reason, tBT_TRANSPORT transport) {
+  tBTA_JV init_evt;
+  tBTA_JV open_evt;
+  struct fc_channel* tc;
+  struct fc_client *t = NULL, *new_conn;
+  tBTA_JV_L2CAP_CBACK* p_cback = NULL;
+  char call_init = false;
+  void* user_data = NULL;
+
+  tc = fcchan_get(chan, false);
+  if (tc) {
+    t = fcclient_find_by_addr(
+        tc->clients, bd_addr);  // try to find an open socked for that addr
+    if (t) {
+      p_cback = t->p_cback;
+      user_data = t->user_data;
+    } else {
+      t = fcclient_find_by_addr(
+          tc->clients,
+          NULL);  // try to find a listening socked for that channel
+      if (t) {
+        // found: create a normal connection socket and assign the connection to
+        // it
+        new_conn = fcclient_alloc(chan, false, &t->sec_id);
+        if (new_conn) {
+          memcpy(&new_conn->remote_addr, bd_addr,
+                 sizeof(new_conn->remote_addr));
+          new_conn->p_cback = NULL;     // for now
+          new_conn->init_called = true; /*nop need to do it again */
+
+          p_cback = t->p_cback;
+          user_data = t->user_data;
+
+          t = new_conn;
+        }
+      } else {
+        // drop it
+        return;
+      }
+    }
+  }
+
+  if (t) {
+    if (!t->init_called) {
+      call_init = true;
+      t->init_called = true;
+
+      init_evt.l2c_cl_init.handle = t->id;
+      init_evt.l2c_cl_init.status = BTA_JV_SUCCESS;
+      init_evt.l2c_cl_init.sec_id = t->sec_id;
+    }
+
+    open_evt.l2c_open.handle = t->id;
+    open_evt.l2c_open.tx_mtu = 23; /* 23, why not ?*/
+    memcpy(&open_evt.l2c_le_open.rem_bda, &t->remote_addr,
+           sizeof(open_evt.l2c_le_open.rem_bda));
+    open_evt.l2c_le_open.p_p_cback = (void**)&t->p_cback;
+    open_evt.l2c_le_open.p_user_data = &t->user_data;
+    open_evt.l2c_le_open.status = BTA_JV_SUCCESS;
+
+    if (connected) {
+      open_evt.l2c_open.status = BTA_JV_SUCCESS;
+    } else {
+      fcclient_free(t);
+      open_evt.l2c_open.status = BTA_JV_FAILURE;
+    }
+  }
+
+  if (call_init) p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &init_evt, user_data);
+
+  // call this with lock taken so socket does not disappear from under us */
+  if (p_cback) {
+    p_cback(BTA_JV_L2CAP_OPEN_EVT, &open_evt, user_data);
+    if (!t->p_cback) /* no callback set, means they do not want this one... */
+      fcclient_free(t);
+  }
+}
+
+static void fcchan_data_cbk(uint16_t chan, BD_ADDR bd_addr, BT_HDR* p_buf) {
+  tBTA_JV evt_data;
+  struct fc_channel* tc;
+  struct fc_client* t = NULL;
+  tBTA_JV_L2CAP_CBACK* sock_cback = NULL;
+  void* sock_user_data;
+
+  tc = fcchan_get(chan, false);
+  if (tc) {
+    t = fcclient_find_by_addr(
+        tc->clients,
+        bd_addr);  // try to find an open socked for that addr and channel
+    if (!t) {
+      // no socket -> drop it
+      return;
+    }
+  }
+
+  sock_cback = t->p_cback;
+  sock_user_data = t->user_data;
+  evt_data.le_data_ind.handle = t->id;
+  evt_data.le_data_ind.p_buf = p_buf;
+
+  if (sock_cback)
+    sock_cback(BTA_JV_L2CAP_DATA_IND_EVT, &evt_data, sock_user_data);
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_l2cap_connect_le
+ *
+ * Description  makes an le l2cap client connection
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_jv_l2cap_connect_le(tBTA_JV_MSG* p_data) {
+  tBTA_JV_API_L2CAP_CONNECT* cc = &(p_data->l2cap_connect);
+  tBTA_JV evt;
+  uint32_t id;
+  char call_init_f = true;
+  struct fc_client* t;
+
+  evt.l2c_cl_init.handle = GAP_INVALID_HANDLE;
+  evt.l2c_cl_init.status = BTA_JV_FAILURE;
+
+  t = fcclient_alloc(cc->remote_chan, false, NULL);
+  if (!t) {
+    cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &evt, cc->user_data);
+    return;
+  }
+
+  t->p_cback = cc->p_cback;
+  t->user_data = cc->user_data;
+  memcpy(&t->remote_addr, &cc->peer_bd_addr, sizeof(t->remote_addr));
+  id = t->id;
+  t->init_called = false;
+
+  if (L2CA_ConnectFixedChnl(t->chan, t->remote_addr)) {
+    evt.l2c_cl_init.status = BTA_JV_SUCCESS;
+    evt.l2c_cl_init.handle = id;
+  }
+
+  // it could have been deleted/moved from under us, so re-find it */
+  t = fcclient_find_by_id(id);
+  if (t) {
+    if (evt.l2c_cl_init.status == BTA_JV_SUCCESS)
+      call_init_f = !t->init_called;
+    else
+      fcclient_free(t);
+  }
+  if (call_init_f) cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &evt, cc->user_data);
+  t->init_called = true;
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_l2cap_stop_server_le
+ *
+ * Description  stops an LE L2CAP server
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_jv_l2cap_stop_server_le(tBTA_JV_MSG* p_data) {
+  tBTA_JV evt;
+  tBTA_JV_API_L2CAP_SERVER* ls = &(p_data->l2cap_server);
+  tBTA_JV_L2CAP_CBACK* p_cback = NULL;
+  struct fc_channel* fcchan;
+  struct fc_client* fcclient;
+  void* user_data;
+
+  evt.l2c_close.status = BTA_JV_FAILURE;
+  evt.l2c_close.async = false;
+  evt.l2c_close.handle = GAP_INVALID_HANDLE;
+
+  fcchan = fcchan_get(ls->local_chan, false);
+  if (fcchan) {
+    while ((fcclient = fcchan->clients)) {
+      p_cback = fcclient->p_cback;
+      user_data = fcclient->user_data;
+
+      evt.l2c_close.handle = fcclient->id;
+      evt.l2c_close.status = BTA_JV_SUCCESS;
+      evt.l2c_close.async = false;
+
+      fcclient_free(fcclient);
+
+      if (p_cback) p_cback(BTA_JV_L2CAP_CLOSE_EVT, &evt, user_data);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_l2cap_start_server_le
+ *
+ * Description  starts an LE L2CAP server
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_jv_l2cap_start_server_le(tBTA_JV_MSG* p_data) {
+  tBTA_JV_API_L2CAP_SERVER* ss = &(p_data->l2cap_server);
+  tBTA_JV_L2CAP_START evt_data;
+  struct fc_client* t;
+
+  evt_data.handle = GAP_INVALID_HANDLE;
+  evt_data.status = BTA_JV_FAILURE;
+
+  t = fcclient_alloc(ss->local_chan, true, NULL);
+  if (!t) goto out;
+
+  t->p_cback = ss->p_cback;
+  t->user_data = ss->user_data;
+
+  // if we got here, we're registered...
+  evt_data.status = BTA_JV_SUCCESS;
+  evt_data.handle = t->id;
+  evt_data.sec_id = t->sec_id;
+
+out:
+  ss->p_cback(BTA_JV_L2CAP_START_EVT, (tBTA_JV*)&evt_data, ss->user_data);
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_jv_l2cap_close_fixed
+ *
+ * Description  close a fixed channel connection. calls no callbacks. idempotent
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+extern void bta_jv_l2cap_close_fixed(tBTA_JV_MSG* p_data) {
+  tBTA_JV_API_L2CAP_CLOSE* cc = &(p_data->l2cap_close);
+  struct fc_client* t;
+
+  t = fcclient_find_by_id(cc->handle);
+  if (t) fcclient_free(t);
+}
diff --git a/bt/bta/jv/bta_jv_api.cc b/bt/bta/jv/bta_jv_api.cc
new file mode 100644
index 0000000..b26df8c
--- /dev/null
+++ b/bt/bta/jv/bta_jv_api.cc
@@ -0,0 +1,975 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2006-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 is the implementation of the JAVA API for Bluetooth Wireless
+ *  Technology (JABWT) as specified by the JSR82 specificiation
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_jv_api.h"
+#include "bta_jv_int.h"
+#include "bta_sys.h"
+#include "gap_api.h"
+#include "port_api.h"
+#include "sdp_api.h"
+#include "utl.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_jv_reg = {bta_jv_sm_execute, NULL};
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvEnable
+ *
+ * Description      Enable the Java I/F service. When the enable
+ *                  operation is complete the callback function will be
+ *                  called with a BTA_JV_ENABLE_EVT. This function must
+ *                  be called before other function in the JV API are
+ *                  called.
+ *
+ * Returns          BTA_JV_SUCCESS if successful.
+ *                  BTA_JV_FAIL if internal failure.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvEnable(tBTA_JV_DM_CBACK* p_cback) {
+  tBTA_JV_STATUS status = BTA_JV_FAILURE;
+  int i;
+
+  APPL_TRACE_API("BTA_JvEnable");
+  if (p_cback && false == bta_sys_is_register(BTA_ID_JV)) {
+    memset(&bta_jv_cb, 0, sizeof(tBTA_JV_CB));
+    /* set handle to invalid value by default */
+    for (i = 0; i < BTA_JV_PM_MAX_NUM; i++) {
+      bta_jv_cb.pm_cb[i].handle = BTA_JV_PM_HANDLE_CLEAR;
+    }
+
+    /* register with BTA system manager */
+    bta_sys_register(BTA_ID_JV, &bta_jv_reg);
+
+    if (p_cback) {
+      tBTA_JV_API_ENABLE* p_buf =
+          (tBTA_JV_API_ENABLE*)osi_malloc(sizeof(tBTA_JV_API_ENABLE));
+      p_buf->hdr.event = BTA_JV_API_ENABLE_EVT;
+      p_buf->p_cback = p_cback;
+      bta_sys_sendmsg(p_buf);
+      status = BTA_JV_SUCCESS;
+    }
+  } else {
+    APPL_TRACE_ERROR("JVenable fails");
+  }
+  return (status);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvDisable
+ *
+ * Description      Disable the Java I/F
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_JvDisable(void) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  APPL_TRACE_API("%s", __func__);
+
+  bta_sys_deregister(BTA_ID_JV);
+  p_buf->event = BTA_JV_API_DISABLE_EVT;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvIsEncrypted
+ *
+ * Description      This function checks if the link to peer device is encrypted
+ *
+ * Returns          true if encrypted.
+ *                  false if not.
+ *
+ ******************************************************************************/
+bool BTA_JvIsEncrypted(BD_ADDR bd_addr) {
+  bool is_encrypted = false;
+  uint8_t sec_flags, le_flags;
+
+  if (BTM_GetSecurityFlags(bd_addr, &sec_flags) &&
+      BTM_GetSecurityFlagsByTransport(bd_addr, &le_flags, BT_TRANSPORT_LE)) {
+    if (sec_flags & BTM_SEC_FLAG_ENCRYPTED || le_flags & BTM_SEC_FLAG_ENCRYPTED)
+      is_encrypted = true;
+  }
+  return is_encrypted;
+}
+/*******************************************************************************
+ *
+ * Function         BTA_JvGetChannelId
+ *
+ * Description      This function reserves a SCN (server channel number) for
+ *                  applications running over RFCOMM, L2CAP of L2CAP_LE.
+ *                  It is primarily called by server profiles/applications to
+ *                  register their SCN into the SDP database. The SCN is
+ *                  reported by the tBTA_JV_DM_CBACK callback with a
+ *                  BTA_JV_GET_SCN_EVT for RFCOMM channels and
+ *                  BTA_JV_GET_PSM_EVT for L2CAP and LE.
+ *                  If the SCN/PSM reported is 0, that means all resources are
+ *                  exhausted.
+ * Parameters
+ *   conn_type      one of BTA_JV_CONN_TYPE_
+ *   user_data      Any uservalue - will be returned in the resulting event.
+ *   channel        Only used for RFCOMM - to try to allocate a specific RFCOMM
+ *                  channel.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvGetChannelId(int conn_type, void* user_data,
+                                  int32_t channel) {
+  tBTA_JV_API_ALLOC_CHANNEL* p_msg =
+      (tBTA_JV_API_ALLOC_CHANNEL*)osi_malloc(sizeof(tBTA_JV_API_ALLOC_CHANNEL));
+
+  APPL_TRACE_API("%s", __func__);
+
+  p_msg->hdr.event = BTA_JV_API_GET_CHANNEL_EVT;
+  p_msg->type = conn_type;
+  p_msg->channel = channel;
+  p_msg->user_data = user_data;
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvFreeChannel
+ *
+ * Description      This function frees a server channel number that was used
+ *                  by an application running over RFCOMM.
+ * Parameters
+ *   channel        The channel to free
+ *   conn_type      one of BTA_JV_CONN_TYPE_
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvFreeChannel(uint16_t channel, int conn_type) {
+  tBTA_JV_API_FREE_CHANNEL* p_msg =
+      (tBTA_JV_API_FREE_CHANNEL*)osi_malloc(sizeof(tBTA_JV_API_FREE_CHANNEL));
+
+  APPL_TRACE_API("%s", __func__);
+
+  p_msg->hdr.event = BTA_JV_API_FREE_SCN_EVT;
+  p_msg->scn = channel;
+  p_msg->type = conn_type;
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvStartDiscovery
+ *
+ * Description      This function performs service discovery for the services
+ *                  provided by the given peer device. When the operation is
+ *                  complete the tBTA_JV_DM_CBACK callback function will be
+ *                  called with a BTA_JV_DISCOVERY_COMP_EVT.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvStartDiscovery(BD_ADDR bd_addr, uint16_t num_uuid,
+                                    tSDP_UUID* p_uuid_list, void* user_data) {
+  tBTA_JV_API_START_DISCOVERY* p_msg = (tBTA_JV_API_START_DISCOVERY*)osi_malloc(
+      sizeof(tBTA_JV_API_START_DISCOVERY));
+
+  APPL_TRACE_API("%s", __func__);
+
+  p_msg->hdr.event = BTA_JV_API_START_DISCOVERY_EVT;
+  bdcpy(p_msg->bd_addr, bd_addr);
+  p_msg->num_uuid = num_uuid;
+  memcpy(p_msg->uuid_list, p_uuid_list, num_uuid * sizeof(tSDP_UUID));
+  p_msg->num_attr = 0;
+  p_msg->user_data = user_data;
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvCreateRecord
+ *
+ * Description      Create a service record in the local SDP database.
+ *                  When the operation is complete the tBTA_JV_DM_CBACK callback
+ *                  function will be called with a BTA_JV_CREATE_RECORD_EVT.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvCreateRecordByUser(void* user_data) {
+  tBTA_JV_API_CREATE_RECORD* p_msg =
+      (tBTA_JV_API_CREATE_RECORD*)osi_malloc(sizeof(tBTA_JV_API_CREATE_RECORD));
+
+  APPL_TRACE_API("%s", __func__);
+
+  p_msg->hdr.event = BTA_JV_API_CREATE_RECORD_EVT;
+  p_msg->user_data = user_data;
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvDeleteRecord
+ *
+ * Description      Delete a service record in the local SDP database.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvDeleteRecord(uint32_t handle) {
+  tBTA_JV_API_ADD_ATTRIBUTE* p_msg =
+      (tBTA_JV_API_ADD_ATTRIBUTE*)osi_malloc(sizeof(tBTA_JV_API_ADD_ATTRIBUTE));
+
+  APPL_TRACE_API("%s", __func__);
+
+  p_msg->hdr.event = BTA_JV_API_DELETE_RECORD_EVT;
+  p_msg->handle = handle;
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capConnectLE
+ *
+ * Description      Initiate an LE connection as a L2CAP client to the given BD
+ *                  Address.
+ *                  When the connection is initiated or failed to initiate,
+ *                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_CL_INIT_EVT
+ *                  When the connection is established or failed,
+ *                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capConnectLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+                                    const tL2CAP_ERTM_INFO* ertm_info,
+                                    uint16_t remote_chan, uint16_t rx_mtu,
+                                    tL2CAP_CFG_INFO* cfg, BD_ADDR peer_bd_addr,
+                                    tBTA_JV_L2CAP_CBACK* p_cback,
+                                    void* user_data) {
+  APPL_TRACE_API("%s", __func__);
+
+  if (p_cback == NULL) return BTA_JV_FAILURE; /* Nothing to do */
+
+  tBTA_JV_API_L2CAP_CONNECT* p_msg =
+      (tBTA_JV_API_L2CAP_CONNECT*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_CONNECT));
+  p_msg->hdr.event = BTA_JV_API_L2CAP_CONNECT_LE_EVT;
+  p_msg->sec_mask = sec_mask;
+  p_msg->role = role;
+  p_msg->remote_chan = remote_chan;
+  p_msg->rx_mtu = rx_mtu;
+  if (cfg != NULL) {
+    p_msg->has_cfg = true;
+    p_msg->cfg = *cfg;
+  } else {
+    p_msg->has_cfg = false;
+  }
+  if (ertm_info != NULL) {
+    p_msg->has_ertm_info = true;
+    p_msg->ertm_info = *ertm_info;
+  } else {
+    p_msg->has_ertm_info = false;
+  }
+  memcpy(p_msg->peer_bd_addr, peer_bd_addr, sizeof(BD_ADDR));
+  p_msg->p_cback = p_cback;
+  p_msg->user_data = user_data;
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capConnect
+ *
+ * Description      Initiate a connection as a L2CAP client to the given BD
+ *                  Address.
+ *                  When the connection is initiated or failed to initiate,
+ *                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_CL_INIT_EVT
+ *                  When the connection is established or failed,
+ *                  tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capConnect(int conn_type, tBTA_SEC sec_mask,
+                                  tBTA_JV_ROLE role,
+                                  const tL2CAP_ERTM_INFO* ertm_info,
+                                  uint16_t remote_psm, uint16_t rx_mtu,
+                                  tL2CAP_CFG_INFO* cfg, BD_ADDR peer_bd_addr,
+                                  tBTA_JV_L2CAP_CBACK* p_cback,
+                                  void* user_data) {
+  APPL_TRACE_API("%s", __func__);
+
+  if (p_cback == NULL) return BTA_JV_FAILURE; /* Nothing to do */
+
+  tBTA_JV_API_L2CAP_CONNECT* p_msg =
+      (tBTA_JV_API_L2CAP_CONNECT*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_CONNECT));
+  p_msg->hdr.event = BTA_JV_API_L2CAP_CONNECT_EVT;
+  p_msg->type = conn_type;
+  p_msg->sec_mask = sec_mask;
+  p_msg->role = role;
+  p_msg->remote_psm = remote_psm;
+  p_msg->rx_mtu = rx_mtu;
+  if (cfg != NULL) {
+    p_msg->has_cfg = true;
+    p_msg->cfg = *cfg;
+  } else {
+    p_msg->has_cfg = false;
+  }
+  if (ertm_info != NULL) {
+    p_msg->has_ertm_info = true;
+    p_msg->ertm_info = *ertm_info;
+  } else {
+    p_msg->has_ertm_info = false;
+  }
+  memcpy(p_msg->peer_bd_addr, peer_bd_addr, sizeof(BD_ADDR));
+  p_msg->p_cback = p_cback;
+  p_msg->user_data = user_data;
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capClose
+ *
+ * Description      This function closes an L2CAP client connection
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capClose(uint32_t handle) {
+  tBTA_JV_STATUS status = BTA_JV_FAILURE;
+
+  APPL_TRACE_API("%s", __func__);
+
+  if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback) {
+    tBTA_JV_API_L2CAP_CLOSE* p_msg =
+        (tBTA_JV_API_L2CAP_CLOSE*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_CLOSE));
+    p_msg->hdr.event = BTA_JV_API_L2CAP_CLOSE_EVT;
+    p_msg->handle = handle;
+    p_msg->p_cb = &bta_jv_cb.l2c_cb[handle];
+
+    bta_sys_sendmsg(p_msg);
+    status = BTA_JV_SUCCESS;
+  }
+
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capCloseLE
+ *
+ * Description      This function closes an L2CAP client connection for Fixed
+ *                  Channels Function is idempotent and no callbacks are called!
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capCloseLE(uint32_t handle) {
+  tBTA_JV_API_L2CAP_CLOSE* p_msg =
+      (tBTA_JV_API_L2CAP_CLOSE*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_CLOSE));
+
+  APPL_TRACE_API("%s", __func__);
+
+  p_msg->hdr.event = BTA_JV_API_L2CAP_CLOSE_FIXED_EVT;
+  p_msg->handle = handle;
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capStartServer
+ *
+ * Description      This function starts an L2CAP server and listens for an
+ *                  L2CAP connection from a remote Bluetooth device.  When the
+ *                  server is started successfully, tBTA_JV_L2CAP_CBACK is
+ *                  called with BTA_JV_L2CAP_START_EVT.  When the connection is
+ *                  established tBTA_JV_L2CAP_CBACK is called with
+ *                  BTA_JV_L2CAP_OPEN_EVT.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStartServer(
+    int conn_type, tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+    const tL2CAP_ERTM_INFO* ertm_info, uint16_t local_psm, uint16_t rx_mtu,
+    tL2CAP_CFG_INFO* cfg, tBTA_JV_L2CAP_CBACK* p_cback, void* user_data) {
+  APPL_TRACE_API("%s", __func__);
+
+  if (p_cback == NULL) return BTA_JV_FAILURE; /* Nothing to do */
+
+  tBTA_JV_API_L2CAP_SERVER* p_msg =
+      (tBTA_JV_API_L2CAP_SERVER*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_SERVER));
+  p_msg->hdr.event = BTA_JV_API_L2CAP_START_SERVER_EVT;
+  p_msg->type = conn_type;
+  p_msg->sec_mask = sec_mask;
+  p_msg->role = role;
+  p_msg->local_psm = local_psm;
+  p_msg->rx_mtu = rx_mtu;
+  if (cfg != NULL) {
+    p_msg->has_cfg = true;
+    p_msg->cfg = *cfg;
+  } else {
+    p_msg->has_cfg = false;
+  }
+  if (ertm_info != NULL) {
+    p_msg->has_ertm_info = true;
+    p_msg->ertm_info = *ertm_info;
+  } else {
+    p_msg->has_ertm_info = false;
+  }
+  p_msg->p_cback = p_cback;
+  p_msg->user_data = user_data;
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capStartServerLE
+ *
+ * Description      This function starts an LE L2CAP server and listens for an
+ *                  L2CAP connection from a remote Bluetooth device.  When the
+ *                  server is started successfully, tBTA_JV_L2CAP_CBACK is
+ *                  called with BTA_JV_L2CAP_START_EVT.  When the connection is
+ *                  established, tBTA_JV_L2CAP_CBACK is called with
+ *                  BTA_JV_L2CAP_OPEN_EVT.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStartServerLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+                                        const tL2CAP_ERTM_INFO* ertm_info,
+                                        uint16_t local_chan, uint16_t rx_mtu,
+                                        tL2CAP_CFG_INFO* cfg,
+                                        tBTA_JV_L2CAP_CBACK* p_cback,
+                                        void* user_data) {
+  APPL_TRACE_API("%s", __func__);
+
+  if (p_cback == NULL) return BTA_JV_FAILURE; /* Nothing to do */
+
+  tBTA_JV_API_L2CAP_SERVER* p_msg =
+      (tBTA_JV_API_L2CAP_SERVER*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_SERVER));
+  p_msg->hdr.event = BTA_JV_API_L2CAP_START_SERVER_LE_EVT;
+  p_msg->sec_mask = sec_mask;
+  p_msg->role = role;
+  p_msg->local_chan = local_chan;
+  p_msg->rx_mtu = rx_mtu;
+  if (cfg != NULL) {
+    p_msg->has_cfg = true;
+    p_msg->cfg = *cfg;
+  } else {
+    p_msg->has_cfg = false;
+  }
+  if (ertm_info != NULL) {
+    p_msg->has_ertm_info = true;
+    p_msg->ertm_info = *ertm_info;
+  } else {
+    p_msg->has_ertm_info = false;
+  }
+  p_msg->p_cback = p_cback;
+  p_msg->user_data = user_data;
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capStopServer
+ *
+ * Description      This function stops the L2CAP server. If the server has an
+ *                  active connection, it would be closed.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStopServer(uint16_t local_psm, void* user_data) {
+  APPL_TRACE_API("%s", __func__);
+
+  tBTA_JV_API_L2CAP_SERVER* p_msg =
+      (tBTA_JV_API_L2CAP_SERVER*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_SERVER));
+  p_msg->hdr.event = BTA_JV_API_L2CAP_STOP_SERVER_EVT;
+  p_msg->local_psm = local_psm;
+  p_msg->user_data = user_data;
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capStopServerLE
+ *
+ * Description      This function stops the LE L2CAP server. If the server has
+ *                  an active connection, it would be closed.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStopServerLE(uint16_t local_chan, void* user_data) {
+  APPL_TRACE_API("%s", __func__);
+
+  tBTA_JV_API_L2CAP_SERVER* p_msg =
+      (tBTA_JV_API_L2CAP_SERVER*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_SERVER));
+  p_msg->hdr.event = BTA_JV_API_L2CAP_STOP_SERVER_LE_EVT;
+  p_msg->local_chan = local_chan;
+  p_msg->user_data = user_data;
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capRead
+ *
+ * Description      This function reads data from an L2CAP connecti;
+    tBTA_JV_RFC_CB  *p_cb = rc->p_cb;
+on
+ *                  When the operation is complete, tBTA_JV_L2CAP_CBACK is
+ *                  called with BTA_JV_L2CAP_READ_EVT.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capRead(uint32_t handle, uint32_t req_id,
+                               uint8_t* p_data, uint16_t len) {
+  tBTA_JV_STATUS status = BTA_JV_FAILURE;
+  tBTA_JV_L2CAP_READ evt_data;
+
+  APPL_TRACE_API("%s", __func__);
+
+  if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback) {
+    status = BTA_JV_SUCCESS;
+    evt_data.status = BTA_JV_FAILURE;
+    evt_data.handle = handle;
+    evt_data.req_id = req_id;
+    evt_data.p_data = p_data;
+    evt_data.len = 0;
+
+    if (BT_PASS ==
+        GAP_ConnReadData((uint16_t)handle, p_data, len, &evt_data.len)) {
+      evt_data.status = BTA_JV_SUCCESS;
+    }
+    bta_jv_cb.l2c_cb[handle].p_cback(BTA_JV_L2CAP_READ_EVT, (tBTA_JV*)&evt_data,
+                                     bta_jv_cb.l2c_cb[handle].user_data);
+  }
+
+  return (status);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capReady
+ *
+ * Description      This function determined if there is data to read from
+ *                    an L2CAP connection
+ *
+ * Returns          BTA_JV_SUCCESS, if data queue size is in *p_data_size.
+ *                  BTA_JV_FAILURE, if error.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capReady(uint32_t handle, uint32_t* p_data_size) {
+  tBTA_JV_STATUS status = BTA_JV_FAILURE;
+
+  APPL_TRACE_API("%s: %d", __func__, handle);
+  if (p_data_size && handle < BTA_JV_MAX_L2C_CONN &&
+      bta_jv_cb.l2c_cb[handle].p_cback) {
+    *p_data_size = 0;
+    if (BT_PASS == GAP_GetRxQueueCnt((uint16_t)handle, p_data_size)) {
+      status = BTA_JV_SUCCESS;
+    }
+  }
+
+  return (status);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capWrite
+ *
+ * Description      This function writes data to an L2CAP connection
+ *                  When the operation is complete, tBTA_JV_L2CAP_CBACK is
+ *                  called with BTA_JV_L2CAP_WRITE_EVT. Works for
+ *                  PSM-based connections
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capWrite(uint32_t handle, uint32_t req_id,
+                                uint8_t* p_data, uint16_t len,
+                                void* user_data) {
+  tBTA_JV_STATUS status = BTA_JV_FAILURE;
+
+  APPL_TRACE_API("%s", __func__);
+
+  if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback) {
+    tBTA_JV_API_L2CAP_WRITE* p_msg =
+        (tBTA_JV_API_L2CAP_WRITE*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_WRITE));
+    p_msg->hdr.event = BTA_JV_API_L2CAP_WRITE_EVT;
+    p_msg->handle = handle;
+    p_msg->req_id = req_id;
+    p_msg->p_data = p_data;
+    p_msg->p_cb = &bta_jv_cb.l2c_cb[handle];
+    p_msg->len = len;
+    p_msg->user_data = user_data;
+
+    bta_sys_sendmsg(p_msg);
+
+    status = BTA_JV_SUCCESS;
+  }
+
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvL2capWriteFixed
+ *
+ * Description      This function writes data to an L2CAP connection
+ *                  When the operation is complete, tBTA_JV_L2CAP_CBACK is
+ *                  called with BTA_JV_L2CAP_WRITE_EVT. Works for
+ *                  fixed-channel connections
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capWriteFixed(uint16_t channel, BD_ADDR* addr,
+                                     uint32_t req_id,
+                                     tBTA_JV_L2CAP_CBACK* p_cback,
+                                     uint8_t* p_data, uint16_t len,
+                                     void* user_data) {
+  tBTA_JV_API_L2CAP_WRITE_FIXED* p_msg =
+      (tBTA_JV_API_L2CAP_WRITE_FIXED*)osi_malloc(
+          sizeof(tBTA_JV_API_L2CAP_WRITE_FIXED));
+
+  APPL_TRACE_API("%s", __func__);
+
+  p_msg->hdr.event = BTA_JV_API_L2CAP_WRITE_FIXED_EVT;
+  p_msg->channel = channel;
+  memcpy(p_msg->addr, addr, sizeof(p_msg->addr));
+  p_msg->req_id = req_id;
+  p_msg->p_data = p_data;
+  p_msg->p_cback = p_cback;
+  p_msg->len = len;
+  p_msg->user_data = user_data;
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvRfcommConnect
+ *
+ * Description      This function makes an RFCOMM conection to a remote BD
+ *                  Address.
+ *                  When the connection is initiated or failed to initiate,
+ *                  tBTA_JV_RFCOMM_CBACK is called with
+ *                  BTA_JV_RFCOMM_CL_INIT_EVT
+ *                  When the connection is established or failed,
+ *                  tBTA_JV_RFCOMM_CBACK is called with BTA_JV_RFCOMM_OPEN_EVT
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommConnect(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+                                   uint8_t remote_scn, BD_ADDR peer_bd_addr,
+                                   tBTA_JV_RFCOMM_CBACK* p_cback,
+                                   void* user_data) {
+  APPL_TRACE_API("%s", __func__);
+
+  if (p_cback == NULL) return BTA_JV_FAILURE; /* Nothing to do */
+
+  tBTA_JV_API_RFCOMM_CONNECT* p_msg = (tBTA_JV_API_RFCOMM_CONNECT*)osi_malloc(
+      sizeof(tBTA_JV_API_RFCOMM_CONNECT));
+  p_msg->hdr.event = BTA_JV_API_RFCOMM_CONNECT_EVT;
+  p_msg->sec_mask = sec_mask;
+  p_msg->role = role;
+  p_msg->remote_scn = remote_scn;
+  memcpy(p_msg->peer_bd_addr, peer_bd_addr, sizeof(BD_ADDR));
+  p_msg->p_cback = p_cback;
+  p_msg->user_data = user_data;
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvRfcommClose
+ *
+ * Description      This function closes an RFCOMM connection
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommClose(uint32_t handle, void* user_data) {
+  tBTA_JV_STATUS status = BTA_JV_FAILURE;
+  uint32_t hi = ((handle & BTA_JV_RFC_HDL_MASK) & ~BTA_JV_RFCOMM_MASK) - 1;
+  uint32_t si = BTA_JV_RFC_HDL_TO_SIDX(handle);
+
+  APPL_TRACE_API("%s", __func__);
+
+  if (hi < BTA_JV_MAX_RFC_CONN && bta_jv_cb.rfc_cb[hi].p_cback &&
+      si < BTA_JV_MAX_RFC_SR_SESSION && bta_jv_cb.rfc_cb[hi].rfc_hdl[si]) {
+    tBTA_JV_API_RFCOMM_CLOSE* p_msg =
+        (tBTA_JV_API_RFCOMM_CLOSE*)osi_malloc(sizeof(tBTA_JV_API_RFCOMM_CLOSE));
+    p_msg->hdr.event = BTA_JV_API_RFCOMM_CLOSE_EVT;
+    p_msg->handle = handle;
+    p_msg->p_cb = &bta_jv_cb.rfc_cb[hi];
+    p_msg->p_pcb = &bta_jv_cb.port_cb[p_msg->p_cb->rfc_hdl[si] - 1];
+    p_msg->user_data = user_data;
+
+    bta_sys_sendmsg(p_msg);
+
+    status = BTA_JV_SUCCESS;
+  }
+
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvRfcommStartServer
+ *
+ * Description      This function starts listening for an RFCOMM connection
+ *                  request from a remote Bluetooth device.  When the server is
+ *                  started successfully, tBTA_JV_RFCOMM_CBACK is called
+ *                  with BTA_JV_RFCOMM_START_EVT.
+ *                  When the connection is established, tBTA_JV_RFCOMM_CBACK
+ *                  is called with BTA_JV_RFCOMM_OPEN_EVT.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommStartServer(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+                                       uint8_t local_scn, uint8_t max_session,
+                                       tBTA_JV_RFCOMM_CBACK* p_cback,
+                                       void* user_data) {
+  APPL_TRACE_API("%s", __func__);
+
+  if (p_cback == NULL) return BTA_JV_FAILURE; /* Nothing to do */
+
+  tBTA_JV_API_RFCOMM_SERVER* p_msg =
+      (tBTA_JV_API_RFCOMM_SERVER*)osi_malloc(sizeof(tBTA_JV_API_RFCOMM_SERVER));
+  if (max_session == 0) max_session = 1;
+  if (max_session > BTA_JV_MAX_RFC_SR_SESSION) {
+    APPL_TRACE_DEBUG("max_session is too big. use max (%d)", max_session,
+                     BTA_JV_MAX_RFC_SR_SESSION);
+    max_session = BTA_JV_MAX_RFC_SR_SESSION;
+  }
+  p_msg->hdr.event = BTA_JV_API_RFCOMM_START_SERVER_EVT;
+  p_msg->sec_mask = sec_mask;
+  p_msg->role = role;
+  p_msg->local_scn = local_scn;
+  p_msg->max_session = max_session;
+  p_msg->p_cback = p_cback;
+  p_msg->user_data = user_data;  // caller's private data
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvRfcommStopServer
+ *
+ * Description      This function stops the RFCOMM server. If the server has an
+ *                  active connection, it would be closed.
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommStopServer(uint32_t handle, void* user_data) {
+  tBTA_JV_API_RFCOMM_SERVER* p_msg =
+      (tBTA_JV_API_RFCOMM_SERVER*)osi_malloc(sizeof(tBTA_JV_API_RFCOMM_SERVER));
+
+  APPL_TRACE_API("%s", __func__);
+
+  p_msg->hdr.event = BTA_JV_API_RFCOMM_STOP_SERVER_EVT;
+  p_msg->handle = handle;
+  p_msg->user_data = user_data;  // caller's private data
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvRfcommGetPortHdl
+ *
+ * Description    This function fetches the rfcomm port handle
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+uint16_t BTA_JvRfcommGetPortHdl(uint32_t handle) {
+  uint32_t hi = ((handle & BTA_JV_RFC_HDL_MASK) & ~BTA_JV_RFCOMM_MASK) - 1;
+  uint32_t si = BTA_JV_RFC_HDL_TO_SIDX(handle);
+
+  if (hi < BTA_JV_MAX_RFC_CONN && si < BTA_JV_MAX_RFC_SR_SESSION &&
+      bta_jv_cb.rfc_cb[hi].rfc_hdl[si])
+    return bta_jv_cb.port_cb[bta_jv_cb.rfc_cb[hi].rfc_hdl[si] - 1].port_handle;
+  else
+    return 0xffff;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_JvRfcommWrite
+ *
+ * Description      This function writes data to an RFCOMM connection
+ *
+ * Returns          BTA_JV_SUCCESS, if the request is being processed.
+ *                  BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommWrite(uint32_t handle, uint32_t req_id) {
+  tBTA_JV_STATUS status = BTA_JV_FAILURE;
+  uint32_t hi = ((handle & BTA_JV_RFC_HDL_MASK) & ~BTA_JV_RFCOMM_MASK) - 1;
+  uint32_t si = BTA_JV_RFC_HDL_TO_SIDX(handle);
+
+  APPL_TRACE_API("%s", __func__);
+
+  APPL_TRACE_DEBUG("handle:0x%x, hi:%d, si:%d", handle, hi, si);
+  if (hi < BTA_JV_MAX_RFC_CONN && bta_jv_cb.rfc_cb[hi].p_cback &&
+      si < BTA_JV_MAX_RFC_SR_SESSION && bta_jv_cb.rfc_cb[hi].rfc_hdl[si]) {
+    tBTA_JV_API_RFCOMM_WRITE* p_msg =
+        (tBTA_JV_API_RFCOMM_WRITE*)osi_malloc(sizeof(tBTA_JV_API_RFCOMM_WRITE));
+    p_msg->hdr.event = BTA_JV_API_RFCOMM_WRITE_EVT;
+    p_msg->handle = handle;
+    p_msg->req_id = req_id;
+    p_msg->p_cb = &bta_jv_cb.rfc_cb[hi];
+    p_msg->p_pcb = &bta_jv_cb.port_cb[p_msg->p_cb->rfc_hdl[si] - 1];
+    APPL_TRACE_API("write ok");
+
+    bta_sys_sendmsg(p_msg);
+    status = BTA_JV_SUCCESS;
+  }
+
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function    BTA_JVSetPmProfile
+ *
+ * Description: This function set or free power mode profile for different JV
+ *              application.
+ *
+ * Parameters:  handle,  JV handle from RFCOMM or L2CAP
+ *              app_id:  app specific pm ID, can be BTA_JV_PM_ALL, see
+ *                       bta_dm_cfg.c for details
+ *              BTA_JV_PM_ID_CLEAR: removes pm management on the handle. init_st
+ *              is ignored and BTA_JV_CONN_CLOSE is called implicitly
+ *              init_st:  state after calling this API. typically it should be
+ *                        BTA_JV_CONN_OPEN
+ *
+ * Returns      BTA_JV_SUCCESS, if the request is being processed.
+ *              BTA_JV_FAILURE, otherwise.
+ *
+ * NOTE:        BTA_JV_PM_ID_CLEAR: In general no need to be called as jv pm
+ *                                  calls automatically
+ *              BTA_JV_CONN_CLOSE to remove in case of connection close!
+ *
+ *******************************************************************************/
+tBTA_JV_STATUS BTA_JvSetPmProfile(uint32_t handle, tBTA_JV_PM_ID app_id,
+                                  tBTA_JV_CONN_STATE init_st) {
+  tBTA_JV_API_SET_PM_PROFILE* p_msg = (tBTA_JV_API_SET_PM_PROFILE*)osi_malloc(
+      sizeof(tBTA_JV_API_SET_PM_PROFILE));
+
+  APPL_TRACE_API("%s handle:0x%x, app_id:%d", __func__, handle, app_id);
+
+  p_msg->hdr.event = BTA_JV_API_SET_PM_PROFILE_EVT;
+  p_msg->handle = handle;
+  p_msg->app_id = app_id;
+  p_msg->init_st = init_st;
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_JV_SUCCESS;
+}
diff --git a/bt/bta/jv/bta_jv_cfg.cc b/bt/bta/jv/bta_jv_cfg.cc
new file mode 100644
index 0000000..b43b035
--- /dev/null
+++ b/bt/bta/jv/bta_jv_cfg.cc
@@ -0,0 +1,58 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright (C) 2004-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 compile-time configurable constants for advanced
+ *  audio
+ *
+ ******************************************************************************/
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_jv_api.h"
+
+#ifndef BTA_JV_SDP_DB_SIZE
+#define BTA_JV_SDP_DB_SIZE 4500
+#endif
+
+#ifndef BTA_JV_SDP_RAW_DATA_SIZE
+#define BTA_JV_SDP_RAW_DATA_SIZE 1800
+#endif
+
+/* The platform may choose to use dynamic memory for these data buffers.
+ * p_bta_jv_cfg->p_sdp_db must be allocated/stay allocated
+ * between BTA_JvEnable and BTA_JvDisable
+ * p_bta_jv_cfg->p_sdp_raw_data can be allocated before calling
+ * BTA_JvStartDiscovery
+ * it can be de-allocated after the last call to access the database */
+static uint8_t bta_jv_sdp_raw_data[BTA_JV_SDP_RAW_DATA_SIZE];
+static uint8_t __attribute__((aligned(4)))
+bta_jv_sdp_db_data[BTA_JV_SDP_DB_SIZE];
+
+/* JV configuration structure */
+const tBTA_JV_CFG bta_jv_cfg = {
+    BTA_JV_SDP_RAW_DATA_SIZE, /* The size of p_sdp_raw_data */
+    BTA_JV_SDP_DB_SIZE,       /* The size of p_sdp_db_data */
+    bta_jv_sdp_raw_data,      /* The data buffer to keep raw data */
+    (tSDP_DISCOVERY_DB*)
+        bta_jv_sdp_db_data /* The data buffer to keep SDP database */
+};
+
+tBTA_JV_CFG* p_bta_jv_cfg = (tBTA_JV_CFG*)&bta_jv_cfg;
diff --git a/bt/bta/jv/bta_jv_int.h b/bt/bta/jv/bta_jv_int.h
new file mode 100644
index 0000000..8c9144c
--- /dev/null
+++ b/bt/bta/jv/bta_jv_int.h
@@ -0,0 +1,408 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2006-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 is the private interface file for the BTA Java I/F
+ *
+ ******************************************************************************/
+#ifndef BTA_JV_INT_H
+#define BTA_JV_INT_H
+
+#include "bta_api.h"
+#include "bta_jv_api.h"
+#include "bta_sys.h"
+#include "port_api.h"
+#include "rfcdefs.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+enum {
+  /* these events are handled by the state machine */
+  BTA_JV_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_JV),
+  BTA_JV_API_DISABLE_EVT,
+  BTA_JV_API_GET_CHANNEL_EVT,
+  BTA_JV_API_FREE_SCN_EVT,
+  BTA_JV_API_START_DISCOVERY_EVT,
+  BTA_JV_API_CREATE_RECORD_EVT,
+  BTA_JV_API_DELETE_RECORD_EVT,
+  BTA_JV_API_L2CAP_CONNECT_EVT,
+  BTA_JV_API_L2CAP_CLOSE_EVT,
+  BTA_JV_API_L2CAP_START_SERVER_EVT,
+  BTA_JV_API_L2CAP_STOP_SERVER_EVT,
+  BTA_JV_API_L2CAP_READ_EVT,
+  BTA_JV_API_L2CAP_WRITE_EVT,
+  BTA_JV_API_RFCOMM_CONNECT_EVT,
+  BTA_JV_API_RFCOMM_CLOSE_EVT,
+  BTA_JV_API_RFCOMM_START_SERVER_EVT,
+  BTA_JV_API_RFCOMM_STOP_SERVER_EVT,
+  BTA_JV_API_RFCOMM_WRITE_EVT,
+  BTA_JV_API_SET_PM_PROFILE_EVT,
+  BTA_JV_API_PM_STATE_CHANGE_EVT,
+  BTA_JV_API_L2CAP_CONNECT_LE_EVT,
+  BTA_JV_API_L2CAP_START_SERVER_LE_EVT,
+  BTA_JV_API_L2CAP_STOP_SERVER_LE_EVT,
+  BTA_JV_API_L2CAP_WRITE_FIXED_EVT,
+  BTA_JV_API_L2CAP_CLOSE_FIXED_EVT,
+  BTA_JV_MAX_INT_EVT
+};
+
+#ifndef BTA_JV_RFC_EV_MASK
+#define BTA_JV_RFC_EV_MASK \
+  (PORT_EV_RXCHAR | PORT_EV_TXEMPTY | PORT_EV_FC | PORT_EV_FCS)
+#endif
+
+/* data type for BTA_JV_API_ENABLE_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_JV_DM_CBACK* p_cback;
+} tBTA_JV_API_ENABLE;
+
+/* data type for BTA_JV_API_START_DISCOVERY_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  uint16_t num_uuid;
+  tSDP_UUID uuid_list[BTA_JV_MAX_UUIDS];
+  uint16_t num_attr;
+  uint16_t attr_list[BTA_JV_MAX_ATTRS];
+  void* user_data; /* piggyback caller's private data*/
+} tBTA_JV_API_START_DISCOVERY;
+
+enum {
+  BTA_JV_PM_FREE_ST = 0, /* empty PM slot */
+  BTA_JV_PM_IDLE_ST,
+  BTA_JV_PM_BUSY_ST
+};
+
+/* BTA JV PM control block */
+typedef struct {
+  uint32_t handle;      /* The connection handle */
+  uint8_t state;        /* state: see above enum */
+  tBTA_JV_PM_ID app_id; /* JV app specific id indicating power table to use */
+  BD_ADDR peer_bd_addr; /* Peer BD address */
+} tBTA_JV_PM_CB;
+
+enum {
+  BTA_JV_ST_NONE = 0,
+  BTA_JV_ST_CL_OPENING,
+  BTA_JV_ST_CL_OPEN,
+  BTA_JV_ST_CL_CLOSING,
+  BTA_JV_ST_SR_LISTEN,
+  BTA_JV_ST_SR_OPEN,
+  BTA_JV_ST_SR_CLOSING
+};
+typedef uint8_t tBTA_JV_STATE;
+#define BTA_JV_ST_CL_MAX BTA_JV_ST_CL_CLOSING
+/* JV L2CAP control block */
+typedef struct {
+  tBTA_JV_L2CAP_CBACK* p_cback; /* the callback function */
+  uint16_t psm;                 /* the psm used for this server connection */
+  tBTA_JV_STATE state;          /* the state of this control block */
+  tBTA_SERVICE_ID sec_id;       /* service id */
+  uint32_t handle; /* the handle reported to java app (same as gap handle) */
+  bool cong;       /* true, if congested */
+  tBTA_JV_PM_CB* p_pm_cb; /* ptr to pm control block, NULL: unused */
+  void* user_data;        /* user data for callback from higher layers */
+} tBTA_JV_L2C_CB;
+
+#define BTA_JV_RFC_HDL_MASK 0xFF
+#define BTA_JV_RFCOMM_MASK 0x80
+#define BTA_JV_ALL_APP_ID 0xFF
+#define BTA_JV_RFC_HDL_TO_SIDX(r) (((r)&0xFF00) >> 8)
+#define BTA_JV_RFC_H_S_TO_HDL(h, s) ((h) | ((s) << 8))
+
+/* port control block */
+typedef struct {
+  uint32_t handle;        /* the rfcomm session handle at jv */
+  uint16_t port_handle;   /* port handle */
+  tBTA_JV_STATE state;    /* the state of this control block */
+  uint8_t max_sess;       /* max sessions */
+  void* user_data;        /* piggyback caller's private data*/
+  bool cong;              /* true, if congested */
+  tBTA_JV_PM_CB* p_pm_cb; /* ptr to pm control block, NULL: unused */
+} tBTA_JV_PCB;
+
+/* JV RFCOMM control block */
+typedef struct {
+  tBTA_JV_RFCOMM_CBACK* p_cback; /* the callback function */
+  uint16_t rfc_hdl[BTA_JV_MAX_RFC_SR_SESSION];
+  tBTA_SERVICE_ID sec_id; /* service id */
+  uint8_t handle;         /* index: the handle reported to java app */
+  uint8_t scn;            /* the scn of the server */
+  uint8_t max_sess;       /* max sessions */
+  int curr_sess;          /* current sessions count*/
+} tBTA_JV_RFC_CB;
+
+/* data type for BTA_JV_API_L2CAP_CONNECT_EVT & BTA_JV_API_L2CAP_CONNECT_LE_EVT
+ */
+typedef struct {
+  BT_HDR hdr;
+  int32_t type; /* One of BTA_JV_CONN_TYPE_ */
+  tBTA_SEC sec_mask;
+  tBTA_JV_ROLE role;
+  union {
+    uint16_t remote_psm;
+    uint16_t remote_chan;
+  };
+  uint16_t rx_mtu;
+  BD_ADDR peer_bd_addr;
+  int32_t has_cfg;
+  tL2CAP_CFG_INFO cfg;
+  int32_t has_ertm_info;
+  tL2CAP_ERTM_INFO ertm_info;
+  tBTA_JV_L2CAP_CBACK* p_cback;
+  void* user_data;
+} tBTA_JV_API_L2CAP_CONNECT;
+
+/* data type for BTA_JV_API_L2CAP_SERVER_EVT */
+typedef struct {
+  BT_HDR hdr;
+  int32_t type; /* One of BTA_JV_CONN_TYPE_ */
+  tBTA_SEC sec_mask;
+  tBTA_JV_ROLE role;
+  union {
+    uint16_t local_psm;
+    uint16_t local_chan;
+  };
+  uint16_t rx_mtu;
+  int32_t has_cfg;
+  tL2CAP_CFG_INFO cfg;
+  int32_t has_ertm_info;
+  tL2CAP_ERTM_INFO ertm_info;
+  tBTA_JV_L2CAP_CBACK* p_cback;
+  void* user_data;
+} tBTA_JV_API_L2CAP_SERVER;
+
+/* data type for BTA_JV_API_L2CAP_CLOSE_EVT */
+typedef struct {
+  BT_HDR hdr;
+  uint32_t handle;
+  tBTA_JV_L2C_CB* p_cb;
+} tBTA_JV_API_L2CAP_CLOSE;
+
+/* data type for BTA_JV_API_L2CAP_READ_EVT */
+typedef struct {
+  BT_HDR hdr;
+  uint32_t handle;
+  uint32_t req_id;
+  tBTA_JV_L2CAP_CBACK* p_cback;
+  uint8_t* p_data;
+  uint16_t len;
+  void* user_data;
+} tBTA_JV_API_L2CAP_READ;
+
+/* data type for BTA_JV_API_L2CAP_WRITE_EVT */
+typedef struct {
+  BT_HDR hdr;
+  uint32_t handle;
+  uint32_t req_id;
+  tBTA_JV_L2C_CB* p_cb;
+  uint8_t* p_data;
+  uint16_t len;
+  void* user_data;
+} tBTA_JV_API_L2CAP_WRITE;
+
+/* data type for BTA_JV_API_L2CAP_WRITE_FIXED_EVT */
+typedef struct {
+  BT_HDR hdr;
+  uint16_t channel;
+  BD_ADDR addr;
+  uint32_t req_id;
+  tBTA_JV_L2CAP_CBACK* p_cback;
+  uint8_t* p_data;
+  uint16_t len;
+  void* user_data;
+} tBTA_JV_API_L2CAP_WRITE_FIXED;
+
+/* data type for BTA_JV_API_RFCOMM_CONNECT_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_SEC sec_mask;
+  tBTA_JV_ROLE role;
+  uint8_t remote_scn;
+  BD_ADDR peer_bd_addr;
+  tBTA_JV_RFCOMM_CBACK* p_cback;
+  void* user_data;
+} tBTA_JV_API_RFCOMM_CONNECT;
+
+/* data type for BTA_JV_API_RFCOMM_SERVER_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_SEC sec_mask;
+  tBTA_JV_ROLE role;
+  uint8_t local_scn;
+  uint8_t max_session;
+  uint32_t handle;
+  tBTA_JV_RFCOMM_CBACK* p_cback;
+  void* user_data;
+} tBTA_JV_API_RFCOMM_SERVER;
+
+/* data type for BTA_JV_API_SET_PM_PROFILE_EVT */
+typedef struct {
+  BT_HDR hdr;
+  uint32_t handle;
+  tBTA_JV_PM_ID app_id;
+  tBTA_JV_CONN_STATE init_st;
+} tBTA_JV_API_SET_PM_PROFILE;
+
+/* data type for BTA_JV_API_PM_STATE_CHANGE_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_JV_PM_CB* p_cb;
+  tBTA_JV_CONN_STATE state;
+} tBTA_JV_API_PM_STATE_CHANGE;
+
+/* data type for BTA_JV_API_RFCOMM_WRITE_EVT */
+typedef struct {
+  BT_HDR hdr;
+  uint32_t handle;
+  uint32_t req_id;
+  uint8_t* p_data;
+  int len;
+  tBTA_JV_RFC_CB* p_cb;
+  tBTA_JV_PCB* p_pcb;
+} tBTA_JV_API_RFCOMM_WRITE;
+
+/* data type for BTA_JV_API_RFCOMM_CLOSE_EVT */
+typedef struct {
+  BT_HDR hdr;
+  uint32_t handle;
+  tBTA_JV_RFC_CB* p_cb;
+  tBTA_JV_PCB* p_pcb;
+  void* user_data;
+} tBTA_JV_API_RFCOMM_CLOSE;
+
+/* data type for BTA_JV_API_CREATE_RECORD_EVT */
+typedef struct {
+  BT_HDR hdr;
+  void* user_data;
+} tBTA_JV_API_CREATE_RECORD;
+
+/* data type for BTA_JV_API_ADD_ATTRIBUTE_EVT */
+typedef struct {
+  BT_HDR hdr;
+  uint32_t handle;
+  uint16_t attr_id;
+  uint8_t* p_value;
+  int32_t value_size;
+} tBTA_JV_API_ADD_ATTRIBUTE;
+
+/* data type for BTA_JV_API_FREE_SCN_EVT */
+typedef struct {
+  BT_HDR hdr;
+  int32_t type; /* One of BTA_JV_CONN_TYPE_ */
+  uint16_t scn;
+} tBTA_JV_API_FREE_CHANNEL;
+
+/* data type for BTA_JV_API_ALLOC_CHANNEL_EVT */
+typedef struct {
+  BT_HDR hdr;
+  int32_t type;    /* One of BTA_JV_CONN_TYPE_ */
+  int32_t channel; /* optionally request a specific channel */
+  void* user_data;
+} tBTA_JV_API_ALLOC_CHANNEL;
+/* union of all data types */
+typedef union {
+  /* GKI event buffer header */
+  BT_HDR hdr;
+  tBTA_JV_API_ENABLE enable;
+  tBTA_JV_API_START_DISCOVERY start_discovery;
+  tBTA_JV_API_ALLOC_CHANNEL alloc_channel;
+  tBTA_JV_API_FREE_CHANNEL free_channel;
+  tBTA_JV_API_CREATE_RECORD create_record;
+  tBTA_JV_API_ADD_ATTRIBUTE add_attr;
+  tBTA_JV_API_L2CAP_CONNECT l2cap_connect;
+  tBTA_JV_API_L2CAP_READ l2cap_read;
+  tBTA_JV_API_L2CAP_WRITE l2cap_write;
+  tBTA_JV_API_L2CAP_CLOSE l2cap_close;
+  tBTA_JV_API_L2CAP_SERVER l2cap_server;
+  tBTA_JV_API_RFCOMM_CONNECT rfcomm_connect;
+  tBTA_JV_API_RFCOMM_WRITE rfcomm_write;
+  tBTA_JV_API_SET_PM_PROFILE set_pm;
+  tBTA_JV_API_PM_STATE_CHANGE change_pm_state;
+  tBTA_JV_API_RFCOMM_CLOSE rfcomm_close;
+  tBTA_JV_API_RFCOMM_SERVER rfcomm_server;
+  tBTA_JV_API_L2CAP_WRITE_FIXED l2cap_write_fixed;
+} tBTA_JV_MSG;
+
+/* JV control block */
+typedef struct {
+  /* the SDP handle reported to JV user is the (index + 1) to sdp_handle[].
+   * if sdp_handle[i]==0, it's not used.
+   * otherwise sdp_handle[i] is the stack SDP handle. */
+  uint32_t sdp_handle[BTA_JV_MAX_SDP_REC]; /* SDP records created */
+  uint8_t* p_sel_raw_data; /* the raw data of last service select */
+  tBTA_JV_DM_CBACK* p_dm_cback;
+  tBTA_JV_L2C_CB l2c_cb[BTA_JV_MAX_L2C_CONN]; /* index is GAP handle (index) */
+  tBTA_JV_RFC_CB rfc_cb[BTA_JV_MAX_RFC_CONN];
+  tBTA_JV_PCB port_cb[MAX_RFC_PORTS];          /* index of this array is
+                                                  the port_handle, */
+  uint8_t sec_id[BTA_JV_NUM_SERVICE_ID];       /* service ID */
+  bool scn[BTA_JV_MAX_SCN];                    /* SCN allocated by java */
+  uint16_t free_psm_list[BTA_JV_MAX_L2C_CONN]; /* PSMs freed by java
+                                                (can be reused) */
+  uint8_t sdp_active;                          /* see BTA_JV_SDP_ACT_* */
+  tSDP_UUID uuid;                         /* current uuid of sdp discovery*/
+  tBTA_JV_PM_CB pm_cb[BTA_JV_PM_MAX_NUM]; /* PM on a per JV handle bases */
+} tBTA_JV_CB;
+
+enum {
+  BTA_JV_SDP_ACT_NONE = 0,
+  BTA_JV_SDP_ACT_YES,   /* waiting for SDP result */
+  BTA_JV_SDP_ACT_CANCEL /* waiting for cancel complete */
+};
+
+/* JV control block */
+extern tBTA_JV_CB bta_jv_cb;
+
+/* config struct */
+extern tBTA_JV_CFG* p_bta_jv_cfg;
+
+extern bool bta_jv_sm_execute(BT_HDR* p_msg);
+
+extern void bta_jv_enable(tBTA_JV_MSG* p_data);
+extern void bta_jv_disable(tBTA_JV_MSG* p_data);
+extern void bta_jv_get_channel_id(tBTA_JV_MSG* p_data);
+extern void bta_jv_free_scn(tBTA_JV_MSG* p_data);
+extern void bta_jv_start_discovery(tBTA_JV_MSG* p_data);
+extern void bta_jv_create_record(tBTA_JV_MSG* p_data);
+extern void bta_jv_delete_record(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_connect(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_close(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_start_server(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_stop_server(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_read(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_write(tBTA_JV_MSG* p_data);
+extern void bta_jv_rfcomm_connect(tBTA_JV_MSG* p_data);
+extern void bta_jv_rfcomm_close(tBTA_JV_MSG* p_data);
+extern void bta_jv_rfcomm_start_server(tBTA_JV_MSG* p_data);
+extern void bta_jv_rfcomm_stop_server(tBTA_JV_MSG* p_data);
+extern void bta_jv_rfcomm_read(tBTA_JV_MSG* p_data);
+extern void bta_jv_rfcomm_write(tBTA_JV_MSG* p_data);
+extern void bta_jv_set_pm_profile(tBTA_JV_MSG* p_data);
+extern void bta_jv_change_pm_state(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_connect_le(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_start_server_le(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_stop_server_le(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_write_fixed(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_close_fixed(tBTA_JV_MSG* p_data);
+
+#endif /* BTA_JV_INT_H */
diff --git a/bt/bta/jv/bta_jv_main.cc b/bt/bta/jv/bta_jv_main.cc
new file mode 100644
index 0000000..fd5ce3a
--- /dev/null
+++ b/bt/bta/jv/bta_jv_main.cc
@@ -0,0 +1,92 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 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 is the main implementation file for the BTA Java I/F
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+#include "bta_jv_api.h"
+#include "bta_jv_int.h"
+#include "bta_sys.h"
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+
+tBTA_JV_CB bta_jv_cb;
+
+/* state machine action enumeration list */
+#define BTA_JV_NUM_ACTIONS (BTA_JV_MAX_INT_EVT & 0x00ff)
+
+/* type for action functions */
+typedef void (*tBTA_JV_ACTION)(tBTA_JV_MSG* p_data);
+
+/* action function list */
+const tBTA_JV_ACTION bta_jv_action[] = {
+    bta_jv_enable,                /* BTA_JV_API_ENABLE_EVT */
+    bta_jv_disable,               /* BTA_JV_API_DISABLE_EVT */
+    bta_jv_get_channel_id,        /* BTA_JV_API_GET_CHANNEL_EVT */
+    bta_jv_free_scn,              /* BTA_JV_API_FREE_SCN_EVT */
+    bta_jv_start_discovery,       /* BTA_JV_API_START_DISCOVERY_EVT */
+    bta_jv_create_record,         /* BTA_JV_API_CREATE_RECORD_EVT */
+    bta_jv_delete_record,         /* BTA_JV_API_DELETE_RECORD_EVT */
+    bta_jv_l2cap_connect,         /* BTA_JV_API_L2CAP_CONNECT_EVT */
+    bta_jv_l2cap_close,           /* BTA_JV_API_L2CAP_CLOSE_EVT */
+    bta_jv_l2cap_start_server,    /* BTA_JV_API_L2CAP_START_SERVER_EVT */
+    bta_jv_l2cap_stop_server,     /* BTA_JV_API_L2CAP_STOP_SERVER_EVT */
+    bta_jv_l2cap_read,            /* BTA_JV_API_L2CAP_READ_EVT */
+    bta_jv_l2cap_write,           /* BTA_JV_API_L2CAP_WRITE_EVT */
+    bta_jv_rfcomm_connect,        /* BTA_JV_API_RFCOMM_CONNECT_EVT */
+    bta_jv_rfcomm_close,          /* BTA_JV_API_RFCOMM_CLOSE_EVT */
+    bta_jv_rfcomm_start_server,   /* BTA_JV_API_RFCOMM_START_SERVER_EVT */
+    bta_jv_rfcomm_stop_server,    /* BTA_JV_API_RFCOMM_STOP_SERVER_EVT */
+    bta_jv_rfcomm_write,          /* BTA_JV_API_RFCOMM_WRITE_EVT */
+    bta_jv_set_pm_profile,        /* BTA_JV_API_SET_PM_PROFILE_EVT */
+    bta_jv_change_pm_state,       /* BTA_JV_API_PM_STATE_CHANGE_EVT */
+    bta_jv_l2cap_connect_le,      /* BTA_JV_API_L2CAP_CONNECT_LE_EVT */
+    bta_jv_l2cap_start_server_le, /* BTA_JV_API_L2CAP_START_SERVER_LE_EVT */
+    bta_jv_l2cap_stop_server_le,  /* BTA_JV_API_L2CAP_STOP_SERVER_LE_EVT */
+    bta_jv_l2cap_write_fixed,     /* BTA_JV_API_L2CAP_WRITE_FIXED_EVT */
+    bta_jv_l2cap_close_fixed,     /*  BTA_JV_API_L2CAP_CLOSE_FIXED_EVT */
+};
+
+/*******************************************************************************
+ *
+ * Function         bta_jv_sm_execute
+ *
+ * Description      State machine event handling function for JV
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+bool bta_jv_sm_execute(BT_HDR* p_msg) {
+  bool ret = false;
+  uint16_t action = (p_msg->event & 0x00ff);
+  /* execute action functions */
+
+  if (action < BTA_JV_NUM_ACTIONS) {
+    (*bta_jv_action[action])((tBTA_JV_MSG*)p_msg);
+    ret = true;
+  }
+
+  return (ret);
+}
diff --git a/bt/bta/mce/bta_mce_act.cc b/bt/bta/mce/bta_mce_act.cc
new file mode 100644
index 0000000..02dc317
--- /dev/null
+++ b/bt/bta/mce/bta_mce_act.cc
@@ -0,0 +1,183 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-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 action functions for MCE.
+ *
+ ******************************************************************************/
+
+#include <arpa/inet.h>
+#include <hardware/bluetooth.h>
+
+#include <string.h>
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bta_api.h"
+#include "bta_mce_api.h"
+#include "bta_mce_int.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "sdp_api.h"
+#include "utl.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+static const tBT_UUID bta_mce_mas_uuid = {
+    .len = 2, .uu.uuid16 = UUID_SERVCLASS_MESSAGE_ACCESS};
+
+/*******************************************************************************
+ *
+ * Function     bta_mce_search_cback
+ *
+ * Description  Callback from btm after search is completed
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+
+static void bta_mce_search_cback(uint16_t result, void* user_data) {
+  tSDP_DISC_REC* p_rec = NULL;
+  tBTA_MCE_MAS_DISCOVERY_COMP evt_data;
+  int found = 0;
+
+  APPL_TRACE_DEBUG("bta_mce_start_discovery_cback res: 0x%x", result);
+
+  bta_mce_cb.sdp_active = BTA_MCE_SDP_ACT_NONE;
+
+  if (bta_mce_cb.p_dm_cback == NULL) return;
+
+  evt_data.status = BTA_MCE_FAILURE;
+  bdcpy(evt_data.remote_addr, bta_mce_cb.remote_addr);
+  evt_data.num_mas = 0;
+
+  if (result == SDP_SUCCESS || result == SDP_DB_FULL) {
+    do {
+      tSDP_DISC_ATTR* p_attr;
+      tSDP_PROTOCOL_ELEM pe;
+
+      p_rec = SDP_FindServiceUUIDInDb(p_bta_mce_cfg->p_sdp_db,
+                                      (tBT_UUID*)&bta_mce_mas_uuid, p_rec);
+
+      APPL_TRACE_DEBUG("p_rec:%p", p_rec);
+
+      if (p_rec == NULL) break;
+
+      if (!SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe))
+        continue;
+
+      evt_data.mas[found].scn = pe.params[0];
+
+      if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) ==
+          NULL)
+        continue;
+
+      evt_data.mas[found].p_srv_name = (char*)p_attr->attr_value.v.array;
+      evt_data.mas[found].srv_name_len =
+          SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+
+      if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_MAS_INSTANCE_ID)) ==
+          NULL)
+        break;
+
+      evt_data.mas[found].instance_id = p_attr->attr_value.v.u8;
+
+      if ((p_attr = SDP_FindAttributeInRec(p_rec,
+                                           ATTR_ID_SUPPORTED_MSG_TYPE)) == NULL)
+        break;
+
+      evt_data.mas[found].msg_type = p_attr->attr_value.v.u8;
+
+      found++;
+    } while (p_rec != NULL && found < BTA_MCE_MAX_MAS_INSTANCES);
+
+    evt_data.num_mas = found;
+    evt_data.status = BTA_MCE_SUCCESS;
+  }
+
+  bta_mce_cb.p_dm_cback(BTA_MCE_MAS_DISCOVERY_COMP_EVT, (tBTA_MCE*)&evt_data,
+                        user_data);
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_mce_enable
+ *
+ * Description  Initializes the MCE I/F
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_mce_enable(tBTA_MCE_MSG* p_data) {
+  tBTA_MCE_STATUS status = BTA_MCE_SUCCESS;
+  bta_mce_cb.p_dm_cback = p_data->enable.p_cback;
+  bta_mce_cb.p_dm_cback(BTA_MCE_ENABLE_EVT, (tBTA_MCE*)&status, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_mce_get_remote_mas_instances
+ *
+ * Description  Discovers MAS instances on remote device
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_mce_get_remote_mas_instances(tBTA_MCE_MSG* p_data) {
+  if (p_data == NULL) {
+    APPL_TRACE_DEBUG("MCE control block handle is null");
+    return;
+  }
+  tBTA_MCE_STATUS status = BTA_MCE_FAILURE;
+
+  APPL_TRACE_DEBUG("%s in, sdp_active:%d", __func__, bta_mce_cb.sdp_active);
+
+  if (bta_mce_cb.sdp_active != BTA_MCE_SDP_ACT_NONE) {
+    /* SDP is still in progress */
+    status = BTA_MCE_BUSY;
+    if (bta_mce_cb.p_dm_cback)
+      bta_mce_cb.p_dm_cback(BTA_MCE_MAS_DISCOVERY_COMP_EVT, (tBTA_MCE*)&status,
+                            NULL);
+
+    return;
+  }
+
+  bta_mce_cb.sdp_active = BTA_MCE_SDP_ACT_YES;
+  bdcpy(bta_mce_cb.remote_addr, p_data->get_rmt_mas.bd_addr);
+
+  SDP_InitDiscoveryDb(p_bta_mce_cfg->p_sdp_db, p_bta_mce_cfg->sdp_db_size, 1,
+                      (tBT_UUID*)&bta_mce_mas_uuid, 0, NULL);
+
+  if (!SDP_ServiceSearchAttributeRequest2(p_data->get_rmt_mas.bd_addr,
+                                          p_bta_mce_cfg->p_sdp_db,
+                                          bta_mce_search_cback, NULL)) {
+    bta_mce_cb.sdp_active = BTA_MCE_SDP_ACT_NONE;
+
+    /* failed to start SDP. report the failure right away */
+    if (bta_mce_cb.p_dm_cback)
+      bta_mce_cb.p_dm_cback(BTA_MCE_MAS_DISCOVERY_COMP_EVT, (tBTA_MCE*)&status,
+                            NULL);
+  }
+  /*
+  else report the result when the cback is called
+  */
+}
diff --git a/bt/bta/mce/bta_mce_api.cc b/bt/bta/mce/bta_mce_api.cc
new file mode 100644
index 0000000..e9233d9
--- /dev/null
+++ b/bt/bta/mce/bta_mce_api.cc
@@ -0,0 +1,107 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-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 is the implementation of the API for MCE subsystem
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bta_api.h"
+#include "bta_mce_api.h"
+#include "bta_mce_int.h"
+#include "bta_sys.h"
+#include "port_api.h"
+#include "sdp_api.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_mce_reg = {bta_mce_sm_execute, NULL};
+
+/*******************************************************************************
+ *
+ * Function         BTA_MceEnable
+ *
+ * Description      Enable the MCE I/F service. When the enable
+ *                  operation is complete the callback function will be
+ *                  called with a BTA_MCE_ENABLE_EVT. This function must
+ *                  be called before other functions in the MCE API are
+ *                  called.
+ *
+ * Returns          BTA_MCE_SUCCESS if successful.
+ *                  BTA_MCE_FAIL if internal failure.
+ *
+ ******************************************************************************/
+tBTA_MCE_STATUS BTA_MceEnable(tBTA_MCE_DM_CBACK* p_cback) {
+  tBTA_MCE_STATUS status = BTA_MCE_FAILURE;
+
+  APPL_TRACE_API("%", __func__);
+
+  if (p_cback && false == bta_sys_is_register(BTA_ID_MCE)) {
+    memset(&bta_mce_cb, 0, sizeof(tBTA_MCE_CB));
+
+    /* register with BTA system manager */
+    bta_sys_register(BTA_ID_MCE, &bta_mce_reg);
+
+    if (p_cback) {
+      tBTA_MCE_API_ENABLE* p_buf =
+          (tBTA_MCE_API_ENABLE*)osi_malloc(sizeof(tBTA_MCE_API_ENABLE));
+      p_buf->hdr.event = BTA_MCE_API_ENABLE_EVT;
+      p_buf->p_cback = p_cback;
+      bta_sys_sendmsg(p_buf);
+      status = BTA_MCE_SUCCESS;
+    }
+  }
+
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_MceGetRemoteMasInstances
+ *
+ * Description      This function performs service discovery for the MAS service
+ *                  by the given peer device. When the operation is completed
+ *                  the tBTA_MCE_DM_CBACK callback function will be  called with
+ *                  a BTA_MCE_MAS_DISCOVERY_COMP_EVT.
+ *
+ * Returns          BTA_MCE_SUCCESS, if the request is being processed.
+ *                  BTA_MCE_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_MCE_STATUS BTA_MceGetRemoteMasInstances(BD_ADDR bd_addr) {
+  tBTA_MCE_API_GET_REMOTE_MAS_INSTANCES* p_msg =
+      (tBTA_MCE_API_GET_REMOTE_MAS_INSTANCES*)osi_malloc(
+          sizeof(tBTA_MCE_API_GET_REMOTE_MAS_INSTANCES));
+
+  APPL_TRACE_API("%s", __func__);
+
+  p_msg->hdr.event = BTA_MCE_API_GET_REMOTE_MAS_INSTANCES_EVT;
+  bdcpy(p_msg->bd_addr, bd_addr);
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_MCE_SUCCESS;
+}
diff --git a/bt/bta/mce/bta_mce_cfg.cc b/bt/bta/mce/bta_mce_cfg.cc
new file mode 100644
index 0000000..3beb265
--- /dev/null
+++ b/bt/bta/mce/bta_mce_cfg.cc
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-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 compile-time configurable constants for MCE
+ *
+ ******************************************************************************/
+
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bta_api.h"
+#include "bta_mce_api.h"
+
+#ifndef BTA_MCE_SDP_DB_SIZE
+#define BTA_MCE_SDP_DB_SIZE 4500
+#endif
+
+static uint8_t __attribute__((aligned(4)))
+bta_mce_sdp_db_data[BTA_MCE_SDP_DB_SIZE];
+
+/* MCE configuration structure */
+const tBTA_MCE_CFG bta_mce_cfg = {
+    BTA_MCE_SDP_DB_SIZE,
+    (tSDP_DISCOVERY_DB*)
+        bta_mce_sdp_db_data /* The data buffer to keep SDP database */
+};
+
+tBTA_MCE_CFG* p_bta_mce_cfg = (tBTA_MCE_CFG*)&bta_mce_cfg;
diff --git a/bt/bta/mce/bta_mce_int.h b/bt/bta/mce/bta_mce_int.h
new file mode 100644
index 0000000..e249d74
--- /dev/null
+++ b/bt/bta/mce/bta_mce_int.h
@@ -0,0 +1,86 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-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 is the private interface file for the BTA MCE I/F
+ *
+ ******************************************************************************/
+#ifndef BTA_MCE_INT_H
+#define BTA_MCE_INT_H
+
+#include "bta_api.h"
+#include "bta_mce_api.h"
+#include "bta_sys.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+enum {
+  /* these events are handled by the state machine */
+  BTA_MCE_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_MCE),
+  BTA_MCE_API_GET_REMOTE_MAS_INSTANCES_EVT,
+  BTA_MCE_MAX_INT_EVT
+};
+
+/* data type for BTA_MCE_API_ENABLE_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_MCE_DM_CBACK* p_cback;
+} tBTA_MCE_API_ENABLE;
+
+/* data type for BTA_MCE_API_GET_REMOTE_MAS_INSTANCES_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+} tBTA_MCE_API_GET_REMOTE_MAS_INSTANCES;
+
+/* union of all data types */
+typedef union {
+  /* GKI event buffer header */
+  BT_HDR hdr;
+  tBTA_MCE_API_ENABLE enable;
+  tBTA_MCE_API_GET_REMOTE_MAS_INSTANCES get_rmt_mas;
+} tBTA_MCE_MSG;
+
+/* MCE control block */
+typedef struct {
+  uint8_t sdp_active; /* see BTA_MCE_SDP_ACT_* */
+  BD_ADDR remote_addr;
+  tBTA_MCE_DM_CBACK* p_dm_cback;
+} tBTA_MCE_CB;
+
+enum {
+  BTA_MCE_SDP_ACT_NONE = 0,
+  BTA_MCE_SDP_ACT_YES /* waiting for SDP result */
+};
+
+/* MCE control block */
+extern tBTA_MCE_CB bta_mce_cb;
+
+/* config struct */
+extern tBTA_MCE_CFG* p_bta_mce_cfg;
+
+extern bool bta_mce_sm_execute(BT_HDR* p_msg);
+
+extern void bta_mce_enable(tBTA_MCE_MSG* p_data);
+extern void bta_mce_get_remote_mas_instances(tBTA_MCE_MSG* p_data);
+
+#endif /* BTA_MCE_INT_H */
diff --git a/bt/bta/mce/bta_mce_main.cc b/bt/bta/mce/bta_mce_main.cc
new file mode 100644
index 0000000..abd3e5c
--- /dev/null
+++ b/bt/bta/mce/bta_mce_main.cc
@@ -0,0 +1,75 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-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 is the main implementation file for the BTA MCE I/F
+ *
+ ******************************************************************************/
+
+#include <stddef.h>
+
+#include "bta_api.h"
+#include "bta_mce_api.h"
+#include "bta_mce_int.h"
+#include "bta_sys.h"
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+
+tBTA_MCE_CB bta_mce_cb;
+
+/* state machine action enumeration list */
+#define BTA_MCE_NUM_ACTIONS (BTA_MCE_MAX_INT_EVT & 0x00ff)
+
+/* type for action functions */
+typedef void (*tBTA_MCE_ACTION)(tBTA_MCE_MSG* p_data);
+
+/* action function list */
+const tBTA_MCE_ACTION bta_mce_action[] = {
+    bta_mce_enable,                   /* BTA_MCE_API_ENABLE_EVT */
+    bta_mce_get_remote_mas_instances, /* BTA_MCE_API_GET_REMOTE_MAS_INSTANCES_EVT
+                                         */
+};
+
+/*******************************************************************************
+ *
+ * Function         bta_mce_sm_execute
+ *
+ * Description      State machine event handling function for MCE
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+bool bta_mce_sm_execute(BT_HDR* p_msg) {
+  if (p_msg == NULL) return false;
+
+  bool ret = false;
+  uint16_t action = (p_msg->event & 0x00ff);
+
+  /* execute action functions */
+  if (action < BTA_MCE_NUM_ACTIONS) {
+    (*bta_mce_action[action])((tBTA_MCE_MSG*)p_msg);
+    ret = true;
+  }
+
+  return (ret);
+}
diff --git a/bt/bta/pan/bta_pan_act.cc b/bt/bta/pan/bta_pan_act.cc
new file mode 100644
index 0000000..0b7eb31
--- /dev/null
+++ b/bt/bta/pan/bta_pan_act.cc
@@ -0,0 +1,702 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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 pan action functions for the state machine.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if (PAN_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include <cutils/log.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_pan_api.h"
+#include "bta_pan_co.h"
+#include "bta_pan_int.h"
+#include "bta_sys.h"
+#include "osi/include/osi.h"
+#include "pan_api.h"
+#include "utl.h"
+
+/* RX and TX data flow mask */
+#define BTA_PAN_RX_MASK 0x0F
+#define BTA_PAN_TX_MASK 0xF0
+
+/*******************************************************************************
+ *
+ * Function    bta_pan_pm_conn_busy
+ *
+ * Description set pan pm connection busy state
+ *
+ * Params      p_scb: state machine control block of pan connection
+ *
+ * Returns     void
+ *
+ *******************************************************************************/
+static void bta_pan_pm_conn_busy(tBTA_PAN_SCB* p_scb) {
+  if ((p_scb != NULL) && (p_scb->state != BTA_PAN_IDLE_ST))
+    bta_sys_busy(BTA_ID_PAN, p_scb->app_id, p_scb->bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function    bta_pan_pm_conn_idle
+ *
+ * Description set pan pm connection idle state
+ *
+ * Params      p_scb: state machine control block of pan connection
+ *
+ * Returns     void
+ *
+ *******************************************************************************/
+static void bta_pan_pm_conn_idle(tBTA_PAN_SCB* p_scb) {
+  if ((p_scb != NULL) && (p_scb->state != BTA_PAN_IDLE_ST))
+    bta_sys_idle(BTA_ID_PAN, p_scb->app_id, p_scb->bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_conn_state_cback
+ *
+ * Description      Connection state callback from Pan profile
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_pan_conn_state_cback(uint16_t handle, BD_ADDR bd_addr,
+                                     tPAN_RESULT state, bool is_role_change,
+                                     uint8_t src_role, uint8_t dst_role) {
+  tBTA_PAN_SCB* p_scb;
+  tBTA_PAN_CONN* p_buf = (tBTA_PAN_CONN*)osi_malloc(sizeof(tBTA_PAN_CONN));
+
+  if ((state == PAN_SUCCESS) && !is_role_change) {
+    p_buf->hdr.event = BTA_PAN_CONN_OPEN_EVT;
+    if ((p_scb = bta_pan_scb_by_handle(handle)) == NULL) {
+      /* allocate an scb */
+      p_scb = bta_pan_scb_alloc();
+    }
+    /* we have exceeded maximum number of connections */
+    if (!p_scb) {
+      PAN_Disconnect(handle);
+      return;
+    }
+
+    p_scb->handle = handle;
+    p_scb->local_role = src_role;
+    p_scb->peer_role = dst_role;
+    p_scb->pan_flow_enable = true;
+    bdcpy(p_scb->bd_addr, bd_addr);
+    p_scb->data_queue = fixed_queue_new(SIZE_MAX);
+
+    if (src_role == PAN_ROLE_CLIENT)
+      p_scb->app_id = bta_pan_cb.app_id[0];
+    else if (src_role == PAN_ROLE_GN_SERVER)
+      p_scb->app_id = bta_pan_cb.app_id[1];
+    else if (src_role == PAN_ROLE_NAP_SERVER)
+      p_scb->app_id = bta_pan_cb.app_id[2];
+  } else if ((state != PAN_SUCCESS) && !is_role_change) {
+    p_buf->hdr.event = BTA_PAN_CONN_CLOSE_EVT;
+  } else {
+    return;
+  }
+
+  p_buf->result = state;
+  p_buf->hdr.layer_specific = handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_data_flow_cb
+ *
+ * Description      Data flow status callback from PAN
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_pan_data_flow_cb(uint16_t handle, tPAN_RESULT result) {
+  tBTA_PAN_SCB* p_scb;
+
+  if ((p_scb = bta_pan_scb_by_handle(handle)) == NULL) return;
+
+  if (result == PAN_TX_FLOW_ON) {
+    BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+    p_buf->layer_specific = handle;
+    p_buf->event = BTA_PAN_BNEP_FLOW_ENABLE_EVT;
+    bta_sys_sendmsg(p_buf);
+    bta_pan_co_rx_flow(handle, p_scb->app_id, true);
+  } else if (result == PAN_TX_FLOW_OFF) {
+    p_scb->pan_flow_enable = false;
+    bta_pan_co_rx_flow(handle, p_scb->app_id, false);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_data_buf_ind_cback
+ *
+ * Description      data indication callback from pan profile
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_pan_data_buf_ind_cback(uint16_t handle, BD_ADDR src,
+                                       BD_ADDR dst, uint16_t protocol,
+                                       BT_HDR* p_buf, bool ext, bool forward) {
+  tBTA_PAN_SCB* p_scb;
+  BT_HDR* p_new_buf;
+
+  if (sizeof(tBTA_PAN_DATA_PARAMS) > p_buf->offset) {
+    /* offset smaller than data structure in front of actual data */
+    if (sizeof(BT_HDR) + sizeof(tBTA_PAN_DATA_PARAMS) + p_buf->len >
+        PAN_BUF_SIZE) {
+      android_errorWriteLog(0x534e4554, "63146237");
+      APPL_TRACE_ERROR("%s: received buffer length too large: %d", __func__,
+                       p_buf->len);
+      osi_free(p_buf);
+      return;
+    }
+    p_new_buf = (BT_HDR*)osi_malloc(PAN_BUF_SIZE);
+    memcpy((uint8_t*)(p_new_buf + 1) + sizeof(tBTA_PAN_DATA_PARAMS),
+           (uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
+    p_new_buf->len = p_buf->len;
+    p_new_buf->offset = sizeof(tBTA_PAN_DATA_PARAMS);
+    osi_free(p_buf);
+  } else {
+    p_new_buf = p_buf;
+  }
+  /* copy params into the space before the data */
+  bdcpy(((tBTA_PAN_DATA_PARAMS*)p_new_buf)->src, src);
+  bdcpy(((tBTA_PAN_DATA_PARAMS*)p_new_buf)->dst, dst);
+  ((tBTA_PAN_DATA_PARAMS*)p_new_buf)->protocol = protocol;
+  ((tBTA_PAN_DATA_PARAMS*)p_new_buf)->ext = ext;
+  ((tBTA_PAN_DATA_PARAMS*)p_new_buf)->forward = forward;
+
+  if ((p_scb = bta_pan_scb_by_handle(handle)) == NULL) {
+    osi_free(p_new_buf);
+    return;
+  }
+
+  fixed_queue_enqueue(p_scb->data_queue, p_new_buf);
+  BT_HDR* p_event = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+  p_event->layer_specific = handle;
+  p_event->event = BTA_PAN_RX_FROM_BNEP_READY_EVT;
+  bta_sys_sendmsg(p_event);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_pfilt_ind_cback
+ *
+ * Description
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_pan_pfilt_ind_cback(uint16_t handle, bool indication,
+                                    tBNEP_RESULT result, uint16_t num_filters,
+                                    uint8_t* p_filters) {
+  bta_pan_co_pfilt_ind(
+      handle, indication,
+      (tBTA_PAN_STATUS)((result == BNEP_SUCCESS) ? BTA_PAN_SUCCESS
+                                                 : BTA_PAN_FAIL),
+      num_filters, p_filters);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_mfilt_ind_cback
+ *
+ * Description
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_pan_mfilt_ind_cback(uint16_t handle, bool indication,
+                                    tBNEP_RESULT result, uint16_t num_mfilters,
+                                    uint8_t* p_mfilters) {
+  bta_pan_co_mfilt_ind(
+      handle, indication,
+      (tBTA_PAN_STATUS)((result == BNEP_SUCCESS) ? BTA_PAN_SUCCESS
+                                                 : BTA_PAN_FAIL),
+      num_mfilters, p_mfilters);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_has_multiple_connections
+ *
+ * Description      Check whether there are multiple GN/NAP connections to
+ *                  different devices
+ *
+ *
+ * Returns          bool
+ *
+ ******************************************************************************/
+static bool bta_pan_has_multiple_connections(uint8_t app_id) {
+  tBTA_PAN_SCB* p_scb = NULL;
+  bool found = false;
+  BD_ADDR bd_addr;
+
+  for (uint8_t index = 0; index < BTA_PAN_NUM_CONN; index++) {
+    p_scb = &bta_pan_cb.scb[index];
+    if (p_scb->in_use == true && app_id == p_scb->app_id) {
+      /* save temp bd_addr */
+      bdcpy(bd_addr, p_scb->bd_addr);
+      found = true;
+      break;
+    }
+  }
+
+  /* If cannot find a match then there is no connection at all */
+  if (found == false) return false;
+
+  /* Find whether there is another connection with different device other than
+     PANU.
+      Could be same service or different service */
+  for (uint8_t index = 0; index < BTA_PAN_NUM_CONN; index++) {
+    p_scb = &bta_pan_cb.scb[index];
+    if (p_scb->in_use == true && p_scb->app_id != bta_pan_cb.app_id[0] &&
+        bdcmp(bd_addr, p_scb->bd_addr)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_enable
+ *
+ * Description
+ *
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_enable(tBTA_PAN_DATA* p_data) {
+  tPAN_REGISTER reg_data;
+  uint16_t initial_discoverability;
+  uint16_t initial_connectability;
+  uint16_t d_window;
+  uint16_t d_interval;
+  uint16_t c_window;
+  uint16_t c_interval;
+
+  bta_pan_cb.p_cback = p_data->api_enable.p_cback;
+
+  reg_data.pan_conn_state_cb = bta_pan_conn_state_cback;
+  reg_data.pan_bridge_req_cb = NULL;
+  reg_data.pan_data_buf_ind_cb = bta_pan_data_buf_ind_cback;
+  reg_data.pan_data_ind_cb = NULL;
+  reg_data.pan_pfilt_ind_cb = bta_pan_pfilt_ind_cback;
+  reg_data.pan_mfilt_ind_cb = bta_pan_mfilt_ind_cback;
+  reg_data.pan_tx_data_flow_cb = bta_pan_data_flow_cb;
+
+  /* read connectability and discoverability settings.
+  Pan profile changes the settings. We have to change it back to
+  be consistent with other bta subsystems */
+  initial_connectability = BTM_ReadConnectability(&c_window, &c_interval);
+  initial_discoverability = BTM_ReadDiscoverability(&d_window, &d_interval);
+
+  PAN_Register(&reg_data);
+
+  /* set it back to original value */
+  BTM_SetDiscoverability(initial_discoverability, d_window, d_interval);
+  BTM_SetConnectability(initial_connectability, c_window, c_interval);
+
+  bta_pan_cb.flow_mask = bta_pan_co_init(&bta_pan_cb.q_level);
+  bta_pan_cb.p_cback(BTA_PAN_ENABLE_EVT, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_set_role
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_set_role(tBTA_PAN_DATA* p_data) {
+  tPAN_RESULT status;
+  tBTA_PAN_SET_ROLE set_role;
+  uint8_t sec[3];
+
+  bta_pan_cb.app_id[0] = p_data->api_set_role.user_app_id;
+  bta_pan_cb.app_id[1] = p_data->api_set_role.gn_app_id;
+  bta_pan_cb.app_id[2] = p_data->api_set_role.nap_app_id;
+
+  sec[0] = p_data->api_set_role.user_sec_mask;
+  sec[1] = p_data->api_set_role.gn_sec_mask;
+  sec[2] = p_data->api_set_role.nap_sec_mask;
+
+  /* set security correctly in api and here */
+  status = PAN_SetRole(
+      p_data->api_set_role.role, sec, p_data->api_set_role.user_name,
+      p_data->api_set_role.gn_name, p_data->api_set_role.nap_name);
+
+  set_role.role = p_data->api_set_role.role;
+  if (status == PAN_SUCCESS) {
+    if (p_data->api_set_role.role & PAN_ROLE_NAP_SERVER)
+      bta_sys_add_uuid(UUID_SERVCLASS_NAP);
+    else
+      bta_sys_remove_uuid(UUID_SERVCLASS_NAP);
+
+    if (p_data->api_set_role.role & PAN_ROLE_GN_SERVER)
+      bta_sys_add_uuid(UUID_SERVCLASS_GN);
+    else
+      bta_sys_remove_uuid(UUID_SERVCLASS_GN);
+
+    if (p_data->api_set_role.role & PAN_ROLE_CLIENT)
+      bta_sys_add_uuid(UUID_SERVCLASS_PANU);
+    else
+      bta_sys_remove_uuid(UUID_SERVCLASS_PANU);
+
+    set_role.status = BTA_PAN_SUCCESS;
+  }
+  /* if status is not success clear everything */
+  else {
+    PAN_SetRole(0, 0, NULL, NULL, NULL);
+    bta_sys_remove_uuid(UUID_SERVCLASS_NAP);
+    bta_sys_remove_uuid(UUID_SERVCLASS_GN);
+    bta_sys_remove_uuid(UUID_SERVCLASS_PANU);
+    set_role.status = BTA_PAN_FAIL;
+  }
+  bta_pan_cb.p_cback(BTA_PAN_SET_ROLE_EVT, (tBTA_PAN*)&set_role);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_disable
+ *
+ * Description
+ *
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_disable(void) {
+  BT_HDR* p_buf;
+  tBTA_PAN_SCB* p_scb = &bta_pan_cb.scb[0];
+  uint8_t i;
+
+  /* close all connections */
+  PAN_SetRole(0, NULL, NULL, NULL, NULL);
+
+#if (BTA_EIR_CANNED_UUID_LIST != TRUE)
+  bta_sys_remove_uuid(UUID_SERVCLASS_NAP);
+  bta_sys_remove_uuid(UUID_SERVCLASS_GN);
+  bta_sys_remove_uuid(UUID_SERVCLASS_PANU);
+#endif  // BTA_EIR_CANNED_UUID_LIST
+  /* free all queued up data buffers */
+  for (i = 0; i < BTA_PAN_NUM_CONN; i++, p_scb++) {
+    if (p_scb->in_use) {
+      while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_scb->data_queue)) !=
+             NULL)
+        osi_free(p_buf);
+
+      bta_pan_co_close(p_scb->handle, p_scb->app_id);
+    }
+  }
+
+  PAN_Deregister();
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_open
+ *
+ * Description
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_open(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data) {
+  tPAN_RESULT status;
+  tBTA_PAN_OPEN data;
+  tBTA_PAN_OPENING opening;
+
+  status = PAN_Connect(p_data->api_open.bd_addr, p_data->api_open.local_role,
+                       p_data->api_open.peer_role, &p_scb->handle);
+  APPL_TRACE_DEBUG("%s pan connect status: %d", __func__, status);
+
+  if (status == PAN_SUCCESS) {
+    bdcpy(p_scb->bd_addr, p_data->api_open.bd_addr);
+    p_scb->local_role = p_data->api_open.local_role;
+    p_scb->peer_role = p_data->api_open.peer_role;
+    bdcpy(opening.bd_addr, p_data->api_open.bd_addr);
+    opening.handle = p_scb->handle;
+    bta_pan_cb.p_cback(BTA_PAN_OPENING_EVT, (tBTA_PAN*)&opening);
+
+  } else {
+    bta_pan_scb_dealloc(p_scb);
+    bdcpy(data.bd_addr, p_data->api_open.bd_addr);
+    data.status = BTA_PAN_FAIL;
+    data.local_role = p_data->api_open.local_role;
+    data.peer_role = p_data->api_open.peer_role;
+    bta_pan_cb.p_cback(BTA_PAN_OPEN_EVT, (tBTA_PAN*)&data);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_close
+ *
+ * Description
+ *
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_api_close(tBTA_PAN_SCB* p_scb, UNUSED_ATTR tBTA_PAN_DATA* p_data) {
+  tBTA_PAN_CONN* p_buf = (tBTA_PAN_CONN*)osi_malloc(sizeof(tBTA_PAN_CONN));
+
+  PAN_Disconnect(p_scb->handle);
+
+  /*
+   * Send an event to BTA so that application will get the connection
+   * close event.
+   */
+  p_buf->hdr.event = BTA_PAN_CONN_CLOSE_EVT;
+  p_buf->hdr.layer_specific = p_scb->handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_conn_open
+ *
+ * Description      process connection open event
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_conn_open(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data) {
+  tBTA_PAN_OPEN data;
+
+  APPL_TRACE_DEBUG("%s pan connection result: %d", __func__,
+                   p_data->conn.result);
+
+  bdcpy(data.bd_addr, p_scb->bd_addr);
+  data.handle = p_scb->handle;
+  data.local_role = p_scb->local_role;
+  data.peer_role = p_scb->peer_role;
+
+  if (p_data->conn.result == PAN_SUCCESS) {
+    data.status = BTA_PAN_SUCCESS;
+    p_scb->pan_flow_enable = true;
+    p_scb->app_flow_enable = true;
+    bta_sys_conn_open(BTA_ID_PAN, p_scb->app_id, p_scb->bd_addr);
+  } else {
+    bta_pan_scb_dealloc(p_scb);
+    data.status = BTA_PAN_FAIL;
+  }
+
+  p_scb->pan_flow_enable = true;
+  p_scb->app_flow_enable = true;
+
+  /* If app_id is NAP/GN, check whether there are multiple connections.
+     If there are, provide a special app_id to dm to enforce master role only.
+     */
+  if ((p_scb->app_id == bta_pan_cb.app_id[1] ||
+       p_scb->app_id == bta_pan_cb.app_id[2]) &&
+      bta_pan_has_multiple_connections(p_scb->app_id)) {
+    p_scb->app_id = BTA_APP_ID_PAN_MULTI;
+  }
+
+  bta_sys_conn_open(BTA_ID_PAN, p_scb->app_id, p_scb->bd_addr);
+  bta_pan_cb.p_cback(BTA_PAN_OPEN_EVT, (tBTA_PAN*)&data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_conn_close
+ *
+ * Description      process connection close event
+ *
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_conn_close(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data) {
+  tBTA_PAN_CLOSE data;
+  BT_HDR* p_buf;
+
+  data.handle = p_data->hdr.layer_specific;
+
+  bta_sys_conn_close(BTA_ID_PAN, p_scb->app_id, p_scb->bd_addr);
+
+  /* free all queued up data buffers */
+  while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_scb->data_queue)) != NULL)
+    osi_free(p_buf);
+
+  bta_pan_scb_dealloc(p_scb);
+
+  bta_pan_cb.p_cback(BTA_PAN_CLOSE_EVT, (tBTA_PAN*)&data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_rx_path
+ *
+ * Description      Handle data on the RX path (data sent from the phone to
+ *                  BTA).
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_rx_path(tBTA_PAN_SCB* p_scb, UNUSED_ATTR tBTA_PAN_DATA* p_data) {
+  /* if data path configured for rx pull */
+  if ((bta_pan_cb.flow_mask & BTA_PAN_RX_MASK) == BTA_PAN_RX_PULL) {
+    /* if we can accept data */
+    if (p_scb->pan_flow_enable == true) {
+      /* call application callout function for rx path */
+      bta_pan_co_rx_path(p_scb->handle, p_scb->app_id);
+    }
+  }
+  /* else data path configured for rx push */
+  else {
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_tx_path
+ *
+ * Description      Handle the TX data path (data sent from BTA to the phone).
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_tx_path(tBTA_PAN_SCB* p_scb, UNUSED_ATTR tBTA_PAN_DATA* p_data) {
+  /* if data path configured for tx pull */
+  if ((bta_pan_cb.flow_mask & BTA_PAN_TX_MASK) == BTA_PAN_TX_PULL) {
+    bta_pan_pm_conn_busy(p_scb);
+    /* call application callout function for tx path */
+    bta_pan_co_tx_path(p_scb->handle, p_scb->app_id);
+
+    /* free data that exceeds queue level */
+    while (fixed_queue_length(p_scb->data_queue) > bta_pan_cb.q_level)
+      osi_free(fixed_queue_try_dequeue(p_scb->data_queue));
+    bta_pan_pm_conn_idle(p_scb);
+  }
+  /* if configured for zero copy push */
+  else if ((bta_pan_cb.flow_mask & BTA_PAN_TX_MASK) == BTA_PAN_TX_PUSH_BUF) {
+    /* if app can accept data */
+    if (p_scb->app_flow_enable == true) {
+      BT_HDR* p_buf;
+
+      /* read data from the queue */
+      if ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_scb->data_queue)) !=
+          NULL) {
+        /* send data to application */
+        bta_pan_co_tx_writebuf(p_scb->handle, p_scb->app_id,
+                               ((tBTA_PAN_DATA_PARAMS*)p_buf)->src,
+                               ((tBTA_PAN_DATA_PARAMS*)p_buf)->dst,
+                               ((tBTA_PAN_DATA_PARAMS*)p_buf)->protocol, p_buf,
+                               ((tBTA_PAN_DATA_PARAMS*)p_buf)->ext,
+                               ((tBTA_PAN_DATA_PARAMS*)p_buf)->forward);
+      }
+      /* free data that exceeds queue level  */
+      while (fixed_queue_length(p_scb->data_queue) > bta_pan_cb.q_level)
+        osi_free(fixed_queue_try_dequeue(p_scb->data_queue));
+
+      /* if there is more data to be passed to
+      upper layer */
+      if (!fixed_queue_is_empty(p_scb->data_queue)) {
+        p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+        p_buf->layer_specific = p_scb->handle;
+        p_buf->event = BTA_PAN_RX_FROM_BNEP_READY_EVT;
+        bta_sys_sendmsg(p_buf);
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_tx_flow
+ *
+ * Description      Set the application flow control state.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_tx_flow(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data) {
+  p_scb->app_flow_enable = p_data->ci_tx_flow.enable;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_write_buf
+ *
+ * Description      Handle a bta_pan_ci_rx_writebuf() and send data to PAN.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_write_buf(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data) {
+  if ((bta_pan_cb.flow_mask & BTA_PAN_RX_MASK) == BTA_PAN_RX_PUSH_BUF) {
+    bta_pan_pm_conn_busy(p_scb);
+
+    PAN_WriteBuf(p_scb->handle, ((tBTA_PAN_DATA_PARAMS*)p_data)->dst,
+                 ((tBTA_PAN_DATA_PARAMS*)p_data)->src,
+                 ((tBTA_PAN_DATA_PARAMS*)p_data)->protocol, (BT_HDR*)p_data,
+                 ((tBTA_PAN_DATA_PARAMS*)p_data)->ext);
+    bta_pan_pm_conn_idle(p_scb);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_free_buf
+ *
+ * Description      Frees the data buffer during closing state
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_free_buf(UNUSED_ATTR tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data) {
+  osi_free(p_data);
+}
+
+#endif /* PAN_INCLUDED */
diff --git a/bt/bta/pan/bta_pan_api.cc b/bt/bta/pan/bta_pan_api.cc
new file mode 100644
index 0000000..cfb0588
--- /dev/null
+++ b/bt/bta/pan/bta_pan_api.cc
@@ -0,0 +1,193 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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 is the implementation of the API for PAN subsystem of BTA,
+ *  Broadcom's Bluetooth application layer for mobile phones.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+
+#include "bt_common.h"
+#include "bt_utils.h"
+#include "bta_api.h"
+#include "bta_pan_api.h"
+#include "bta_pan_int.h"
+#include "bta_sys.h"
+#include "osi/include/osi.h"
+#include "pan_api.h"
+
+#if (BTA_PAN_INCLUDED == TRUE)
+
+static const tBTA_SYS_REG bta_pan_reg = {bta_pan_hdl_event, BTA_PanDisable};
+
+/*******************************************************************************
+ *
+ * Function         BTA_PanEnable
+ *
+ * Description      Enable PAN service.  This function must be
+ *                  called before any other functions in the PAN API are called.
+ *                  When the enable operation is complete the callback function
+ *                  will be called with a BTA_PAN_ENABLE_EVT.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_PanEnable(tBTA_PAN_CBACK p_cback) {
+  tBTA_PAN_API_ENABLE* p_buf =
+      (tBTA_PAN_API_ENABLE*)osi_malloc(sizeof(tBTA_PAN_API_ENABLE));
+
+  /* register with BTA system manager */
+  bta_sys_register(BTA_ID_PAN, &bta_pan_reg);
+
+  p_buf->hdr.event = BTA_PAN_API_ENABLE_EVT;
+  p_buf->p_cback = p_cback;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_PanDisable
+ *
+ * Description      Disables PAN service.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_PanDisable(void) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  bta_sys_deregister(BTA_ID_PAN);
+  p_buf->event = BTA_PAN_API_DISABLE_EVT;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_PanSetRole
+ *
+ * Description      Sets PAN roles. When the enable operation is complete
+ *                  the callback function will be called with a
+ *                  BTA_PAN_SET_ROLE_EVT.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_PanSetRole(tBTA_PAN_ROLE role, tBTA_PAN_ROLE_INFO* p_user_info,
+                    tBTA_PAN_ROLE_INFO* p_gn_info,
+                    tBTA_PAN_ROLE_INFO* p_nap_info) {
+  tBTA_PAN_API_SET_ROLE* p_buf =
+      (tBTA_PAN_API_SET_ROLE*)osi_calloc(sizeof(tBTA_PAN_API_SET_ROLE));
+
+  p_buf->hdr.event = BTA_PAN_API_SET_ROLE_EVT;
+  p_buf->role = role;
+
+  if (p_user_info && (role & BTA_PAN_ROLE_PANU)) {
+    if (p_user_info->p_srv_name)
+      strlcpy(p_buf->user_name, p_user_info->p_srv_name, BTA_SERVICE_NAME_LEN);
+
+    p_buf->user_app_id = p_user_info->app_id;
+    p_buf->user_sec_mask = p_user_info->sec_mask;
+  }
+
+  if (p_gn_info && (role & BTA_PAN_ROLE_GN)) {
+    if (p_gn_info->p_srv_name)
+      strlcpy(p_buf->gn_name, p_gn_info->p_srv_name, BTA_SERVICE_NAME_LEN);
+
+    p_buf->gn_app_id = p_gn_info->app_id;
+    p_buf->gn_sec_mask = p_gn_info->sec_mask;
+  }
+
+  if (p_nap_info && (role & BTA_PAN_ROLE_NAP)) {
+    if (p_nap_info->p_srv_name)
+      strlcpy(p_buf->nap_name, p_nap_info->p_srv_name, BTA_SERVICE_NAME_LEN);
+
+    p_buf->nap_app_id = p_nap_info->app_id;
+    p_buf->nap_sec_mask = p_nap_info->sec_mask;
+  }
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_PanOpen
+ *
+ * Description      Opens a connection to a peer device.
+ *                  When connection is open callback function is called
+ *                  with a BTA_PAN_OPEN_EVT.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_PanOpen(BD_ADDR bd_addr, tBTA_PAN_ROLE local_role,
+                 tBTA_PAN_ROLE peer_role) {
+  tBTA_PAN_API_OPEN* p_buf =
+      (tBTA_PAN_API_OPEN*)osi_malloc(sizeof(tBTA_PAN_API_OPEN));
+
+  p_buf->hdr.event = BTA_PAN_API_OPEN_EVT;
+  p_buf->local_role = local_role;
+  p_buf->peer_role = peer_role;
+  bdcpy(p_buf->bd_addr, bd_addr);
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_PanClose
+ *
+ * Description      Close a PAN  connection to a peer device.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTA_PanClose(uint16_t handle) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = BTA_PAN_API_CLOSE_EVT;
+  p_buf->layer_specific = handle;
+
+  bta_sys_sendmsg(p_buf);
+}
+#else
+
+void BTA_PanEnable(UNUSED_ATTR tBTA_PAN_CBACK p_cback) {}
+
+void BTA_PanDisable(void) {}
+
+void BTA_PanSetRole(UNUSED_ATTR tBTA_PAN_ROLE role,
+                    UNUSED_ATTR tBTA_PAN_ROLE_INFO* p_user_info,
+                    UNUSED_ATTR tBTA_PAN_ROLE_INFO* p_gn_info,
+                    UNUSED_ATTR tBTA_PAN_ROLE_INFO* p_nap_info) {}
+
+void BTA_PanOpen(UNUSED_ATTR BD_ADDR bd_addr,
+                 UNUSED_ATTR tBTA_PAN_ROLE local_role,
+                 UNUSED_ATTR tBTA_PAN_ROLE peer_role) {}
+
+void BTA_PanClose(UNUSED_ATTR uint16_t handle) {}
+
+#endif /* BTA_PAN_INCLUDED */
diff --git a/bt/bta/pan/bta_pan_ci.cc b/bt/bta/pan/bta_pan_ci.cc
new file mode 100644
index 0000000..f44ebee
--- /dev/null
+++ b/bt/bta/pan/bta_pan_ci.cc
@@ -0,0 +1,263 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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 is the implementation file for data gateway call-in functions.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_utils.h"
+#include "bta_api.h"
+#include "bta_pan_api.h"
+#include "bta_pan_ci.h"
+#include "bta_pan_int.h"
+#include "osi/include/osi.h"
+#include "pan_api.h"
+
+#if (BTA_PAN_INCLUDED == TRUE)
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_ci_tx_ready
+ *
+ * Description      This function sends an event to PAN indicating the phone is
+ *                  ready for more data and PAN should call
+ *                  bta_pan_co_tx_path().
+ *                  This function is used when the TX data path is configured
+ *                  to use a pull interface.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_ci_tx_ready(uint16_t handle) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->layer_specific = handle;
+  p_buf->event = BTA_PAN_CI_TX_READY_EVT;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_ci_rx_ready
+ *
+ * Description      This function sends an event to PAN indicating the phone
+ *                  has data available to send to PAN and PAN should call
+ *                  bta_pan_co_rx_path().  This function is used when the RX
+ *                  data path is configured to use a pull interface.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_ci_rx_ready(uint16_t handle) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->layer_specific = handle;
+  p_buf->event = BTA_PAN_CI_RX_READY_EVT;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_ci_tx_flow
+ *
+ * Description      This function is called to enable or disable data flow on
+ *                  the TX path.  The phone should call this function to
+ *                  disable data flow when it is congested and cannot handle
+ *                  any more data sent by bta_pan_co_tx_write() or
+ *                  bta_pan_co_tx_writebuf().  This function is used when the
+ *                  TX data path is configured to use a push interface.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_ci_tx_flow(uint16_t handle, bool enable) {
+  tBTA_PAN_CI_TX_FLOW* p_buf =
+      (tBTA_PAN_CI_TX_FLOW*)osi_malloc(sizeof(tBTA_PAN_CI_TX_FLOW));
+
+  p_buf->hdr.layer_specific = handle;
+  p_buf->hdr.event = BTA_PAN_CI_TX_FLOW_EVT;
+  p_buf->enable = enable;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_ci_rx_write
+ *
+ * Description      This function is called to send data to PAN when the RX path
+ *                  is configured to use a push interface.  The function copies
+ *                  data to an event buffer and sends it to PAN.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_ci_rx_write(uint16_t handle, BD_ADDR dst, BD_ADDR src,
+                         uint16_t protocol, uint8_t* p_data, uint16_t len,
+                         bool ext) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(PAN_BUF_SIZE);
+
+  p_buf->offset = PAN_MINIMUM_OFFSET;
+
+  /* copy all other params before the data */
+  bdcpy(((tBTA_PAN_DATA_PARAMS*)p_buf)->src, src);
+  bdcpy(((tBTA_PAN_DATA_PARAMS*)p_buf)->dst, dst);
+  ((tBTA_PAN_DATA_PARAMS*)p_buf)->protocol = protocol;
+  ((tBTA_PAN_DATA_PARAMS*)p_buf)->ext = ext;
+  p_buf->len = len;
+
+  /* copy data */
+  memcpy((uint8_t*)(p_buf + 1) + p_buf->offset, p_data, len);
+
+  p_buf->layer_specific = handle;
+  p_buf->event = BTA_PAN_CI_RX_WRITEBUF_EVT;
+
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_ci_rx_writebuf
+ *
+ * Description      This function is called to send data to the phone when
+ *                  the RX path is configured to use a push interface with
+ *                  zero copy.  The function sends an event to PAN containing
+ *                  the data buffer. The buffer will be freed by BTA; the
+ *                  phone must not free the buffer.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_ci_rx_writebuf(uint16_t handle, BD_ADDR dst, BD_ADDR src,
+                            uint16_t protocol, BT_HDR* p_buf, bool ext) {
+  /* copy all other params before the data */
+  bdcpy(((tBTA_PAN_DATA_PARAMS*)p_buf)->src, src);
+  bdcpy(((tBTA_PAN_DATA_PARAMS*)p_buf)->dst, dst);
+  ((tBTA_PAN_DATA_PARAMS*)p_buf)->protocol = protocol;
+  ((tBTA_PAN_DATA_PARAMS*)p_buf)->ext = ext;
+
+  p_buf->layer_specific = handle;
+  p_buf->event = BTA_PAN_CI_RX_WRITEBUF_EVT;
+  bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_ci_readbuf
+ *
+ * Description
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+BT_HDR* bta_pan_ci_readbuf(uint16_t handle, BD_ADDR src, BD_ADDR dst,
+                           uint16_t* p_protocol, bool* p_ext, bool* p_forward) {
+  tBTA_PAN_SCB* p_scb;
+  BT_HDR* p_buf;
+
+  p_scb = bta_pan_scb_by_handle(handle);
+
+  p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_scb->data_queue);
+  if (p_buf != NULL) {
+    bdcpy(src, ((tBTA_PAN_DATA_PARAMS*)p_buf)->src);
+    bdcpy(dst, ((tBTA_PAN_DATA_PARAMS*)p_buf)->dst);
+    *p_protocol = ((tBTA_PAN_DATA_PARAMS*)p_buf)->protocol;
+    *p_ext = ((tBTA_PAN_DATA_PARAMS*)p_buf)->ext;
+    *p_forward = ((tBTA_PAN_DATA_PARAMS*)p_buf)->forward;
+  }
+
+  return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_ci_set_mfilters
+ *
+ * Description      This function is called to set multicast filters
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_ci_set_mfilters(uint16_t handle, uint16_t num_mcast_filters,
+                             uint8_t* p_start_array, uint8_t* p_end_array) {
+  PAN_SetMulticastFilters(handle, num_mcast_filters, p_start_array,
+                          p_end_array);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_ci_set_mfilters
+ *
+ * Description      This function is called to set protocol filters
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_ci_set_pfilters(uint16_t handle, uint16_t num_filters,
+                             uint16_t* p_start_array, uint16_t* p_end_array) {
+  PAN_SetProtocolFilters(handle, num_filters, p_start_array, p_end_array);
+}
+#else
+
+void bta_pan_ci_tx_ready(UNUSED_ATTR uint16_t handle) {}
+
+void bta_pan_ci_rx_ready(UNUSED_ATTR uint16_t handle) {}
+
+void bta_pan_ci_tx_flow(UNUSED_ATTR uint16_t handle, UNUSED_ATTR bool enable) {}
+
+void bta_pan_ci_rx_writebuf(UNUSED_ATTR uint16_t handle,
+                            UNUSED_ATTR BD_ADDR src, UNUSED_ATTR BD_ADDR dst,
+                            UNUSED_ATTR uint16_t protocol,
+                            UNUSED_ATTR BT_HDR* p_buf, UNUSED_ATTR bool ext) {}
+
+BT_HDR* bta_pan_ci_readbuf(UNUSED_ATTR uint16_t handle, UNUSED_ATTR BD_ADDR src,
+                           UNUSED_ATTR BD_ADDR dst,
+                           UNUSED_ATTR uint16_t* p_protocol,
+                           UNUSED_ATTR bool* p_ext,
+                           UNUSED_ATTR bool* p_forward) {
+  return NULL;
+}
+
+void bta_pan_ci_set_pfilters(UNUSED_ATTR uint16_t handle,
+                             UNUSED_ATTR uint16_t num_filters,
+                             UNUSED_ATTR uint16_t* p_start_array,
+                             UNUSED_ATTR uint16_t* p_end_array) {}
+
+void bta_pan_ci_set_mfilters(UNUSED_ATTR uint16_t handle,
+                             UNUSED_ATTR uint16_t num_mcast_filters,
+                             UNUSED_ATTR uint8_t* p_start_array,
+                             UNUSED_ATTR uint8_t* p_end_array) {}
+
+#endif /* BTA_PAN_API */
diff --git a/bt/bta/pan/bta_pan_int.h b/bt/bta/pan/bta_pan_int.h
new file mode 100644
index 0000000..71658f2
--- /dev/null
+++ b/bt/bta/pan/bta_pan_int.h
@@ -0,0 +1,186 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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 is the private interface file for the BTA data gateway.
+ *
+ ******************************************************************************/
+#ifndef BTA_PAN_INT_H
+#define BTA_PAN_INT_H
+
+#include "bta_pan_api.h"
+#include "bta_sys.h"
+#include "osi/include/fixed_queue.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+/* PAN events */
+enum {
+  /* these events are handled by the state machine */
+  BTA_PAN_API_CLOSE_EVT = BTA_SYS_EVT_START(BTA_ID_PAN),
+  BTA_PAN_CI_TX_READY_EVT,
+  BTA_PAN_CI_RX_READY_EVT,
+  BTA_PAN_CI_TX_FLOW_EVT,
+  BTA_PAN_CI_RX_WRITE_EVT,
+  BTA_PAN_CI_RX_WRITEBUF_EVT,
+  BTA_PAN_CONN_OPEN_EVT,
+  BTA_PAN_CONN_CLOSE_EVT,
+  BTA_PAN_BNEP_FLOW_ENABLE_EVT,
+  BTA_PAN_RX_FROM_BNEP_READY_EVT,
+
+  /* these events are handled outside of the state machine */
+  BTA_PAN_API_ENABLE_EVT,
+  BTA_PAN_API_DISABLE_EVT,
+  BTA_PAN_API_SET_ROLE_EVT,
+  BTA_PAN_API_OPEN_EVT
+};
+
+/* state machine states */
+enum { BTA_PAN_IDLE_ST, BTA_PAN_OPEN_ST, BTA_PAN_CLOSING_ST };
+
+/*****************************************************************************
+ *  Data types
+ ****************************************************************************/
+
+/* data type for BTA_PAN_API_ENABLE_EVT */
+typedef struct {
+  BT_HDR hdr;              /* Event header */
+  tBTA_PAN_CBACK* p_cback; /* PAN callback function */
+} tBTA_PAN_API_ENABLE;
+
+/* data type for BTA_PAN_API_REG_ROLE_EVT */
+typedef struct {
+  BT_HDR hdr;                               /* Event header */
+  char user_name[BTA_SERVICE_NAME_LEN + 1]; /* Service name */
+  char gn_name[BTA_SERVICE_NAME_LEN + 1];   /* Service name */
+  char nap_name[BTA_SERVICE_NAME_LEN + 1];  /* Service name */
+  tBTA_PAN_ROLE role;
+  uint8_t user_app_id;
+  uint8_t gn_app_id;
+  uint8_t nap_app_id;
+  tBTA_SEC user_sec_mask; /* Security mask */
+  tBTA_SEC gn_sec_mask;   /* Security mask */
+  tBTA_SEC nap_sec_mask;  /* Security mask */
+
+} tBTA_PAN_API_SET_ROLE;
+
+/* data type for BTA_PAN_API_OPEN_EVT */
+typedef struct {
+  BT_HDR hdr;               /* Event header */
+  tBTA_PAN_ROLE local_role; /* local role */
+  tBTA_PAN_ROLE peer_role;  /* peer role */
+  BD_ADDR bd_addr;          /* peer bdaddr */
+} tBTA_PAN_API_OPEN;
+
+/* data type for BTA_PAN_CI_TX_FLOW_EVT */
+typedef struct {
+  BT_HDR hdr;  /* Event header */
+  bool enable; /* Flow control setting */
+} tBTA_PAN_CI_TX_FLOW;
+
+/* data type for BTA_PAN_CONN_OPEN_EVT */
+typedef struct {
+  BT_HDR hdr; /* Event header */
+  tPAN_RESULT result;
+
+} tBTA_PAN_CONN;
+
+/* union of all data types */
+typedef union {
+  BT_HDR hdr;
+  tBTA_PAN_API_ENABLE api_enable;
+  tBTA_PAN_API_SET_ROLE api_set_role;
+  tBTA_PAN_API_OPEN api_open;
+  tBTA_PAN_CI_TX_FLOW ci_tx_flow;
+  tBTA_PAN_CONN conn;
+} tBTA_PAN_DATA;
+
+/* state machine control block */
+typedef struct {
+  BD_ADDR bd_addr; /* peer bdaddr */
+  fixed_queue_t*
+      data_queue;    /* Queue of buffers waiting to be passed to application */
+  uint16_t handle;   /* BTA PAN/BNEP handle */
+  bool in_use;       /* scb in use */
+  tBTA_SEC sec_mask; /* Security mask */
+  bool pan_flow_enable;     /* BNEP flow control state */
+  bool app_flow_enable;     /* Application flow control state */
+  uint8_t state;            /* State machine state */
+  tBTA_PAN_ROLE local_role; /* local role */
+  tBTA_PAN_ROLE peer_role;  /* peer role */
+  uint8_t app_id;           /* application id for the connection */
+
+} tBTA_PAN_SCB;
+
+/* main control block */
+typedef struct {
+  tBTA_PAN_SCB scb[BTA_PAN_NUM_CONN]; /* state machine control blocks */
+  tBTA_PAN_CBACK* p_cback;            /* PAN callback function */
+  uint8_t app_id[3];                  /* application id for PAN roles */
+  uint8_t flow_mask;                  /* Data flow mask */
+  uint8_t q_level; /* queue level set by application for TX data */
+
+} tBTA_PAN_CB;
+
+/* pan data param */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR src;
+  BD_ADDR dst;
+  uint16_t protocol;
+  bool ext;
+  bool forward;
+
+} tBTA_PAN_DATA_PARAMS;
+
+/*****************************************************************************
+ *  Global data
+ ****************************************************************************/
+
+/* PAN control block */
+extern tBTA_PAN_CB bta_pan_cb;
+
+/*****************************************************************************
+ *  Function prototypes
+ ****************************************************************************/
+extern tBTA_PAN_SCB* bta_pan_scb_alloc(void);
+extern void bta_pan_scb_dealloc(tBTA_PAN_SCB* p_scb);
+extern uint8_t bta_pan_scb_to_idx(tBTA_PAN_SCB* p_scb);
+extern tBTA_PAN_SCB* bta_pan_scb_by_handle(uint16_t handle);
+extern bool bta_pan_hdl_event(BT_HDR* p_msg);
+
+/* action functions */
+extern void bta_pan_enable(tBTA_PAN_DATA* p_data);
+extern void bta_pan_disable(void);
+extern void bta_pan_set_role(tBTA_PAN_DATA* p_data);
+extern void bta_pan_open(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+extern void bta_pan_api_close(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+extern void bta_pan_set_shutdown(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+extern void bta_pan_rx_path(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+extern void bta_pan_tx_path(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+extern void bta_pan_tx_flow(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+extern void bta_pan_conn_open(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+extern void bta_pan_conn_close(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+extern void bta_pan_writebuf(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+extern void bta_pan_write_buf(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+extern void bta_pan_free_buf(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+
+#endif /* BTA_PAN_INT_H */
diff --git a/bt/bta/pan/bta_pan_main.cc b/bt/bta/pan/bta_pan_main.cc
new file mode 100644
index 0000000..d003bce
--- /dev/null
+++ b/bt/bta/pan/bta_pan_main.cc
@@ -0,0 +1,358 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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 PAN main functions and state machine.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if (BTA_PAN_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_pan_api.h"
+#include "bta_pan_int.h"
+#include "bta_sys.h"
+#include "osi/include/osi.h"
+#include "pan_api.h"
+#include "utl.h"
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+
+/* state machine action enumeration list */
+enum {
+  BTA_PAN_API_CLOSE,
+  BTA_PAN_TX_PATH,
+  BTA_PAN_RX_PATH,
+  BTA_PAN_TX_FLOW,
+  BTA_PAN_WRITE_BUF,
+  BTA_PAN_CONN_OPEN,
+  BTA_PAN_CONN_CLOSE,
+  BTA_PAN_FREE_BUF,
+  BTA_PAN_IGNORE
+};
+
+/* type for action functions */
+typedef void (*tBTA_PAN_ACTION)(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+
+/* action function list */
+const tBTA_PAN_ACTION bta_pan_action[] = {
+    bta_pan_api_close, bta_pan_tx_path,   bta_pan_rx_path,    bta_pan_tx_flow,
+    bta_pan_write_buf, bta_pan_conn_open, bta_pan_conn_close, bta_pan_free_buf,
+
+};
+
+/* state table information */
+#define BTA_PAN_ACTIONS 1    /* number of actions */
+#define BTA_PAN_NEXT_STATE 1 /* position of next state */
+#define BTA_PAN_NUM_COLS 2   /* number of columns in state tables */
+
+/* state table for listen state */
+const uint8_t bta_pan_st_idle[][BTA_PAN_NUM_COLS] = {
+    /* API_CLOSE */ {BTA_PAN_API_CLOSE, BTA_PAN_IDLE_ST},
+    /* CI_TX_READY */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST},
+    /* CI_RX_READY */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST},
+    /* CI_TX_FLOW */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST},
+    /* CI_RX_WRITE */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST},
+    /* CI_RX_WRITEBUF */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST},
+    /* PAN_CONN_OPEN */ {BTA_PAN_CONN_OPEN, BTA_PAN_OPEN_ST},
+    /* PAN_CONN_CLOSE */ {BTA_PAN_CONN_OPEN, BTA_PAN_IDLE_ST},
+    /* FLOW_ENABLE */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST},
+    /* BNEP_DATA */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST}
+
+};
+
+/* state table for open state */
+const uint8_t bta_pan_st_open[][BTA_PAN_NUM_COLS] = {
+    /* API_CLOSE */ {BTA_PAN_API_CLOSE, BTA_PAN_OPEN_ST},
+    /* CI_TX_READY */ {BTA_PAN_TX_PATH, BTA_PAN_OPEN_ST},
+    /* CI_RX_READY */ {BTA_PAN_RX_PATH, BTA_PAN_OPEN_ST},
+    /* CI_TX_FLOW */ {BTA_PAN_TX_FLOW, BTA_PAN_OPEN_ST},
+    /* CI_RX_WRITE */ {BTA_PAN_IGNORE, BTA_PAN_OPEN_ST},
+    /* CI_RX_WRITEBUF */ {BTA_PAN_WRITE_BUF, BTA_PAN_OPEN_ST},
+    /* PAN_CONN_OPEN */ {BTA_PAN_IGNORE, BTA_PAN_OPEN_ST},
+    /* PAN_CONN_CLOSE */ {BTA_PAN_CONN_CLOSE, BTA_PAN_IDLE_ST},
+    /* FLOW_ENABLE */ {BTA_PAN_RX_PATH, BTA_PAN_OPEN_ST},
+    /* BNEP_DATA */ {BTA_PAN_TX_PATH, BTA_PAN_OPEN_ST}};
+
+/* state table for closing state */
+const uint8_t bta_pan_st_closing[][BTA_PAN_NUM_COLS] = {
+    /* API_CLOSE */ {BTA_PAN_IGNORE, BTA_PAN_CLOSING_ST},
+    /* CI_TX_READY */ {BTA_PAN_TX_PATH, BTA_PAN_CLOSING_ST},
+    /* CI_RX_READY */ {BTA_PAN_RX_PATH, BTA_PAN_CLOSING_ST},
+    /* CI_TX_FLOW */ {BTA_PAN_TX_FLOW, BTA_PAN_CLOSING_ST},
+    /* CI_RX_WRITE */ {BTA_PAN_IGNORE, BTA_PAN_CLOSING_ST},
+    /* CI_RX_WRITEBUF */ {BTA_PAN_FREE_BUF, BTA_PAN_CLOSING_ST},
+    /* PAN_CONN_OPEN */ {BTA_PAN_IGNORE, BTA_PAN_CLOSING_ST},
+    /* PAN_CONN_CLOSE */ {BTA_PAN_CONN_CLOSE, BTA_PAN_IDLE_ST},
+    /* FLOW_ENABLE */ {BTA_PAN_RX_PATH, BTA_PAN_CLOSING_ST},
+    /* BNEP_DATA */ {BTA_PAN_TX_PATH, BTA_PAN_CLOSING_ST}};
+
+/* type for state table */
+typedef const uint8_t (*tBTA_PAN_ST_TBL)[BTA_PAN_NUM_COLS];
+
+/* state table */
+const tBTA_PAN_ST_TBL bta_pan_st_tbl[] = {bta_pan_st_idle, bta_pan_st_open,
+                                          bta_pan_st_closing};
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+
+/* PAN control block */
+tBTA_PAN_CB bta_pan_cb;
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_scb_alloc
+ *
+ * Description      Allocate a PAN server control block.
+ *
+ *
+ * Returns          pointer to the scb, or NULL if none could be allocated.
+ *
+ ******************************************************************************/
+tBTA_PAN_SCB* bta_pan_scb_alloc(void) {
+  tBTA_PAN_SCB* p_scb = &bta_pan_cb.scb[0];
+  int i;
+
+  for (i = 0; i < BTA_PAN_NUM_CONN; i++, p_scb++) {
+    if (!p_scb->in_use) {
+      p_scb->in_use = true;
+      APPL_TRACE_DEBUG("bta_pan_scb_alloc %d", i);
+      break;
+    }
+  }
+
+  if (i == BTA_PAN_NUM_CONN) {
+    /* out of scbs */
+    p_scb = NULL;
+    APPL_TRACE_WARNING("Out of scbs");
+  }
+  return p_scb;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_sm_execute
+ *
+ * Description      State machine event handling function for PAN
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_pan_sm_execute(tBTA_PAN_SCB* p_scb, uint16_t event,
+                               tBTA_PAN_DATA* p_data) {
+  tBTA_PAN_ST_TBL state_table;
+  uint8_t action;
+  int i;
+
+  APPL_TRACE_EVENT("PAN scb=%d event=0x%x state=%d", bta_pan_scb_to_idx(p_scb),
+                   event, p_scb->state);
+
+  /* look up the state table for the current state */
+  state_table = bta_pan_st_tbl[p_scb->state];
+
+  event &= 0x00FF;
+
+  /* set next state */
+  p_scb->state = state_table[event][BTA_PAN_NEXT_STATE];
+
+  /* execute action functions */
+  for (i = 0; i < BTA_PAN_ACTIONS; i++) {
+    if ((action = state_table[event][i]) != BTA_PAN_IGNORE) {
+      (*bta_pan_action[action])(p_scb, p_data);
+    } else {
+      break;
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_api_enable
+ *
+ * Description      Handle an API enable event.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_pan_api_enable(tBTA_PAN_DATA* p_data) {
+  /* initialize control block */
+  memset(&bta_pan_cb, 0, sizeof(bta_pan_cb));
+
+  /* store callback function */
+  bta_pan_cb.p_cback = p_data->api_enable.p_cback;
+  bta_pan_enable(p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_api_disable
+ *
+ * Description      Handle an API disable event.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_pan_api_disable(UNUSED_ATTR tBTA_PAN_DATA* p_data) {
+  bta_pan_disable();
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_api_open
+ *
+ * Description      Handle an API listen event.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_pan_api_open(tBTA_PAN_DATA* p_data) {
+  tBTA_PAN_SCB* p_scb;
+  tBTA_PAN_OPEN data;
+
+  /* allocate an scb */
+  if ((p_scb = bta_pan_scb_alloc()) != NULL) {
+    bta_pan_open(p_scb, p_data);
+  } else {
+    bdcpy(data.bd_addr, p_data->api_open.bd_addr);
+    data.status = BTA_PAN_FAIL;
+    bta_pan_cb.p_cback(BTA_PAN_OPEN_EVT, (tBTA_PAN*)&data);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_pan_scb_dealloc
+ *
+ * Description      Deallocate a link control block.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_scb_dealloc(tBTA_PAN_SCB* p_scb) {
+  APPL_TRACE_DEBUG("bta_pan_scb_dealloc %d", bta_pan_scb_to_idx(p_scb));
+  fixed_queue_free(p_scb->data_queue, NULL);
+  memset(p_scb, 0, sizeof(tBTA_PAN_SCB));
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_scb_to_idx
+ *
+ * Description      Given a pointer to an scb, return its index.
+ *
+ *
+ * Returns          Index of scb.
+ *
+ ******************************************************************************/
+uint8_t bta_pan_scb_to_idx(tBTA_PAN_SCB* p_scb) {
+  return ((uint8_t)(p_scb - bta_pan_cb.scb)) + 1;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_scb_by_handle
+ *
+ * Description      Find scb associated with handle.
+ *
+ *
+ * Returns          Pointer to scb or NULL if not found.
+ *
+ ******************************************************************************/
+tBTA_PAN_SCB* bta_pan_scb_by_handle(uint16_t handle) {
+  tBTA_PAN_SCB* p_scb = &bta_pan_cb.scb[0];
+  uint8_t i;
+
+  for (i = 0; i < BTA_PAN_NUM_CONN; i++, p_scb++) {
+    if (p_scb->handle == handle) {
+      return p_scb;
+      ;
+    }
+  }
+
+  APPL_TRACE_WARNING("No scb for handle %d", handle);
+
+  return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_hdl_event
+ *
+ * Description      Data gateway main event handling function.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+bool bta_pan_hdl_event(BT_HDR* p_msg) {
+  tBTA_PAN_SCB* p_scb;
+  bool freebuf = true;
+
+  switch (p_msg->event) {
+    /* handle enable event */
+    case BTA_PAN_API_ENABLE_EVT:
+      bta_pan_api_enable((tBTA_PAN_DATA*)p_msg);
+      break;
+
+    /* handle disable event */
+    case BTA_PAN_API_DISABLE_EVT:
+      bta_pan_api_disable((tBTA_PAN_DATA*)p_msg);
+      break;
+
+    /* handle set role event */
+    case BTA_PAN_API_SET_ROLE_EVT:
+      bta_pan_set_role((tBTA_PAN_DATA*)p_msg);
+      break;
+
+    /* handle open event */
+    case BTA_PAN_API_OPEN_EVT:
+      bta_pan_api_open((tBTA_PAN_DATA*)p_msg);
+      break;
+
+    /* events that require buffer not be released */
+    case BTA_PAN_CI_RX_WRITEBUF_EVT:
+      freebuf = false;
+      if ((p_scb = bta_pan_scb_by_handle(p_msg->layer_specific)) != NULL) {
+        bta_pan_sm_execute(p_scb, p_msg->event, (tBTA_PAN_DATA*)p_msg);
+      }
+      break;
+
+    /* all other events */
+    default:
+      if ((p_scb = bta_pan_scb_by_handle(p_msg->layer_specific)) != NULL) {
+        bta_pan_sm_execute(p_scb, p_msg->event, (tBTA_PAN_DATA*)p_msg);
+      }
+      break;
+  }
+  return freebuf;
+}
+#endif /* BTA_PAN_INCLUDED */
diff --git a/bt/bta/pb/bta_pbs_int.h b/bt/bta/pb/bta_pbs_int.h
new file mode 100644
index 0000000..ae21ce4
--- /dev/null
+++ b/bt/bta/pb/bta_pbs_int.h
@@ -0,0 +1,60 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 is the private file for the phone book access server (PBS).
+ *
+ ******************************************************************************/
+#ifndef BTA_PBS_INT_H
+#define BTA_PBS_INT_H
+
+#include "bt_target.h"
+#include "bta_sys.h"
+
+/*****************************************************************************
+ *  Constants and data types
+ ****************************************************************************/
+
+/* Profile supported features */
+#define BTA_PBS_SUPF_DOWNLOAD 0x0001
+#define BTA_PBS_SURF_BROWSE 0x0002
+
+/* Profile supported repositories */
+#define BTA_PBS_REPOSIT_LOCAL 0x01 /* Local PhoneBook */
+#define BTA_PBS_REPOSIT_SIM 0x02   /* SIM card PhoneBook */
+
+#define BTA_PBS_TARGET_UUID \
+  "\x79\x61\x35\xf0\xf0\xc5\x11\xd8\x09\x66\x08\x00\x20\x0c\x9a\x66"
+#define BTA_PBS_UUID_LENGTH 16
+#define BTA_PBS_MAX_AUTH_KEY_SIZE \
+  16 /* Must not be greater than OBX_MAX_AUTH_KEY_SIZE */
+
+#define BTA_PBS_DEFAULT_VERSION 0x0101 /* for PBAP PSE version 1.1 */
+
+/* Configuration structure */
+typedef struct {
+  uint8_t realm_charset; /* Server only */
+  bool userid_req; /* true if user id is required during obex authentication
+                      (Server only) */
+  uint8_t supported_features;     /* Server supported features */
+  uint8_t supported_repositories; /* Server supported repositories */
+
+} tBTA_PBS_CFG;
+
+#endif /* BTA_PBS_INT_H */
diff --git a/bt/bta/sdp/bta_sdp.cc b/bt/bta/sdp/bta_sdp.cc
new file mode 100644
index 0000000..735d0b7
--- /dev/null
+++ b/bt/bta/sdp/bta_sdp.cc
@@ -0,0 +1,72 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 is the main implementation file for the BTA MCE I/F
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+
+#include "bta_api.h"
+#include "bta_sdp_api.h"
+#include "bta_sdp_int.h"
+#include "bta_sys.h"
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+
+tBTA_SDP_CB bta_sdp_cb;
+
+/* state machine action enumeration list */
+#define BTA_SDP_NUM_ACTIONS (BTA_SDP_MAX_INT_EVT & 0x00ff)
+
+/* type for action functions */
+typedef void (*tBTA_SDP_ACTION)(tBTA_SDP_MSG* p_data);
+
+/* action function list */
+const tBTA_SDP_ACTION bta_sdp_action[] = {
+    bta_sdp_enable,        /* BTA_SDP_API_ENABLE_EVT */
+    bta_sdp_search,        /* BTA_SDP_API_SEARCH_EVT */
+    bta_sdp_create_record, /* BTA_SDP_API_CREATE_RECORD_USER_EVT */
+    bta_sdp_remove_record, /* BTA_SDP_API_REMOVE_RECORD_USER_EVT */
+};
+
+/*******************************************************************************
+ * Function         bta_sdp_sm_execute
+ *
+ * Description      State machine event handling function for SDP search
+ *
+ * Returns          void
+ ******************************************************************************/
+bool bta_sdp_sm_execute(BT_HDR* p_msg) {
+  if (p_msg == NULL) return false;
+
+  bool ret = false;
+  uint16_t action = (p_msg->event & 0x00ff);
+
+  /* execute action functions */
+  if (action < BTA_SDP_NUM_ACTIONS) {
+    (*bta_sdp_action[action])((tBTA_SDP_MSG*)p_msg);
+    ret = true;
+  }
+
+  return (ret);
+}
diff --git a/bt/bta/sdp/bta_sdp_act.cc b/bt/bta/sdp/bta_sdp_act.cc
new file mode 100644
index 0000000..3787298
--- /dev/null
+++ b/bt/bta/sdp/bta_sdp_act.cc
@@ -0,0 +1,563 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 action functions for SDP search.
+ ******************************************************************************/
+
+#include <arpa/inet.h>
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sdp.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bta_api.h"
+#include "bta_sdp_api.h"
+#include "bta_sdp_int.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "osi/include/allocator.h"
+#include "sdp_api.h"
+#include "utl.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+static const uint8_t UUID_OBEX_OBJECT_PUSH[] = {
+    0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
+    0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_PBAP_PSE[] = {0x00, 0x00, 0x11, 0x2F, 0x00, 0x00,
+                                        0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+                                        0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_MAP_MAS[] = {0x00, 0x00, 0x11, 0x32, 0x00, 0x00,
+                                       0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+                                       0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_MAP_MNS[] = {0x00, 0x00, 0x11, 0x33, 0x00, 0x00,
+                                       0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+                                       0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_SAP[] = {0x00, 0x00, 0x11, 0x2D, 0x00, 0x00,
+                                   0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+                                   0x5F, 0x9B, 0x34, 0xFB};
+// TODO:
+// Both the fact that the UUIDs are declared in multiple places, plus the fact
+// that there is a mess of UUID comparison and shortening methods will have to
+// be fixed.
+// The btcore->uuid module should be used for all instances.
+
+#define UUID_MAX_LENGTH 16
+#define IS_UUID(u1, u2) !memcmp(u1, u2, UUID_MAX_LENGTH)
+
+static inline tBT_UUID shorten_sdp_uuid(const tBT_UUID* u) {
+  static uint8_t bt_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                   0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+                                   0x5F, 0x9B, 0x34, 0xFB};
+
+  APPL_TRACE_DEBUG("%s() - uuid len:%d", __func__, u->len);
+  if (u->len != 16) return *u;
+
+  if (memcmp(&u->uu.uuid128[4], &bt_base_uuid[4], 12) != 0) return *u;
+
+  tBT_UUID su;
+  memset(&su, 0, sizeof(su));
+  if (u->uu.uuid128[0] == 0 && u->uu.uuid128[1] == 0) {
+    su.len = 2;
+    uint16_t u16;
+    memcpy(&u16, &u->uu.uuid128[2], sizeof(u16));
+    su.uu.uuid16 = ntohs(u16);
+  } else {
+    su.len = 4;
+    uint32_t u32;
+    memcpy(&u32, &u->uu.uuid128[0], sizeof(u32));
+    su.uu.uuid32 = ntohl(u32);
+  }
+  return su;
+}
+
+static void bta_create_mns_sdp_record(bluetooth_sdp_record* record,
+                                      tSDP_DISC_REC* p_rec) {
+  tSDP_DISC_ATTR* p_attr;
+  tSDP_PROTOCOL_ELEM pe;
+  uint16_t pversion = 0;
+  record->mns.hdr.type = SDP_TYPE_MAP_MNS;
+  record->mns.hdr.service_name_length = 0;
+  record->mns.hdr.service_name = NULL;
+  record->mns.hdr.rfcomm_channel_number = 0;
+  record->mns.hdr.l2cap_psm = -1;
+  record->mns.hdr.profile_version = 0;
+  record->mns.supported_features = 0x0000001F;  // default value if not found
+
+  if ((p_attr = SDP_FindAttributeInRec(
+           p_rec, ATTR_ID_MAP_SUPPORTED_FEATURES)) != NULL) {
+    record->mns.supported_features = p_attr->attr_value.v.u32;
+  }
+
+  if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) != NULL) {
+    record->mns.hdr.service_name_length =
+        SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+    record->mns.hdr.service_name = (char*)p_attr->attr_value.v.array;
+  }
+
+  if (SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_MAP_PROFILE,
+                                  &pversion)) {
+    record->mns.hdr.profile_version = pversion;
+  }
+
+  if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+    record->mns.hdr.rfcomm_channel_number = pe.params[0];
+  }
+
+  if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_GOEP_L2CAP_PSM)) !=
+      NULL) {
+    record->mns.hdr.l2cap_psm = p_attr->attr_value.v.u16;
+  }
+}
+
+static void bta_create_mas_sdp_record(bluetooth_sdp_record* record,
+                                      tSDP_DISC_REC* p_rec) {
+  tSDP_DISC_ATTR* p_attr;
+  tSDP_PROTOCOL_ELEM pe;
+  uint16_t pversion = -1;
+
+  record->mas.hdr.type = SDP_TYPE_MAP_MAS;
+  record->mas.hdr.service_name_length = 0;
+  record->mas.hdr.service_name = NULL;
+  record->mas.hdr.rfcomm_channel_number = 0;
+  record->mas.hdr.l2cap_psm = -1;
+  record->mas.hdr.profile_version = 0;
+  record->mas.mas_instance_id = 0;
+  record->mas.supported_features = 0x0000001F;
+  record->mas.supported_message_types = 0;
+
+  if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_MAS_INSTANCE_ID)) !=
+      NULL) {
+    record->mas.mas_instance_id = p_attr->attr_value.v.u8;
+  }
+
+  if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_MSG_TYPE)) !=
+      NULL) {
+    record->mas.supported_message_types = p_attr->attr_value.v.u8;
+  }
+
+  if ((p_attr = SDP_FindAttributeInRec(
+           p_rec, ATTR_ID_MAP_SUPPORTED_FEATURES)) != NULL) {
+    record->mas.supported_features = p_attr->attr_value.v.u32;
+  }
+
+  if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) != NULL) {
+    record->mas.hdr.service_name_length =
+        SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+    record->mas.hdr.service_name = (char*)p_attr->attr_value.v.array;
+  }
+
+  if (SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_MAP_PROFILE,
+                                  &pversion)) {
+    record->mas.hdr.profile_version = pversion;
+  }
+
+  if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+    record->mas.hdr.rfcomm_channel_number = pe.params[0];
+  }
+
+  if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_GOEP_L2CAP_PSM)) !=
+      NULL) {
+    record->mas.hdr.l2cap_psm = p_attr->attr_value.v.u16;
+  }
+}
+
+static void bta_create_pse_sdp_record(bluetooth_sdp_record* record,
+                                      tSDP_DISC_REC* p_rec) {
+  tSDP_DISC_ATTR* p_attr;
+  uint16_t pversion;
+  tSDP_PROTOCOL_ELEM pe;
+
+  record->pse.hdr.type = SDP_TYPE_PBAP_PSE;
+  record->pse.hdr.service_name_length = 0;
+  record->pse.hdr.service_name = NULL;
+  record->pse.hdr.rfcomm_channel_number = 0;
+  record->pse.hdr.l2cap_psm = -1;
+  record->pse.hdr.profile_version = 0;
+  record->pse.supported_features = 0x00000003;
+  record->pse.supported_repositories = 0;
+
+  if ((p_attr = SDP_FindAttributeInRec(
+           p_rec, ATTR_ID_SUPPORTED_REPOSITORIES)) != NULL) {
+    record->pse.supported_repositories = p_attr->attr_value.v.u8;
+  }
+  if ((p_attr = SDP_FindAttributeInRec(
+           p_rec, ATTR_ID_PBAP_SUPPORTED_FEATURES)) != NULL) {
+    record->pse.supported_features = p_attr->attr_value.v.u32;
+  }
+
+  if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) != NULL) {
+    record->pse.hdr.service_name_length =
+        SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+    record->pse.hdr.service_name = (char*)p_attr->attr_value.v.array;
+  }
+
+  if (SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_PHONE_ACCESS,
+                                  &pversion)) {
+    record->pse.hdr.profile_version = pversion;
+  }
+
+  if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+    record->pse.hdr.rfcomm_channel_number = pe.params[0];
+  }
+
+  if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_GOEP_L2CAP_PSM)) !=
+      NULL) {
+    record->pse.hdr.l2cap_psm = p_attr->attr_value.v.u16;
+  }
+}
+
+static void bta_create_ops_sdp_record(bluetooth_sdp_record* record,
+                                      tSDP_DISC_REC* p_rec) {
+  tSDP_DISC_ATTR *p_attr, *p_sattr;
+  tSDP_PROTOCOL_ELEM pe;
+  uint16_t pversion = -1;
+
+  record->ops.hdr.type = SDP_TYPE_OPP_SERVER;
+  record->ops.hdr.service_name_length = 0;
+  record->ops.hdr.service_name = NULL;
+  record->ops.hdr.rfcomm_channel_number = 0;
+  record->ops.hdr.l2cap_psm = -1;
+  record->ops.hdr.profile_version = 0;
+  record->ops.supported_formats_list_len = 0;
+
+  if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) != NULL) {
+    record->ops.hdr.service_name_length =
+        SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+    record->ops.hdr.service_name = (char*)p_attr->attr_value.v.array;
+  }
+
+  if (SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_OBEX_OBJECT_PUSH,
+                                  &pversion)) {
+    record->ops.hdr.profile_version = pversion;
+  }
+
+  if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+    record->ops.hdr.rfcomm_channel_number = pe.params[0];
+  }
+
+  if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_GOEP_L2CAP_PSM)) !=
+      NULL) {
+    record->ops.hdr.l2cap_psm = p_attr->attr_value.v.u16;
+  }
+  if ((p_attr = SDP_FindAttributeInRec(
+           p_rec, ATTR_ID_SUPPORTED_FORMATS_LIST)) != NULL) {
+    /* Safety check - each entry should itself be a sequence */
+    if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) {
+      record->ops.supported_formats_list_len = 0;
+      APPL_TRACE_ERROR(
+          "%s() - supported_formats_list - wrong attribute length/type:"
+          " 0x%02x - expected 0x06",
+          __func__, p_attr->attr_len_type);
+    } else {
+      int count = 0;
+      /* 1 byte for type/length 1 byte for value */
+      record->ops.supported_formats_list_len =
+          SDP_DISC_ATTR_LEN(p_attr->attr_len_type) / 2;
+
+      /* Extract each value into */
+      for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr != NULL;
+           p_sattr = p_sattr->p_next_attr) {
+        if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UINT_DESC_TYPE) &&
+            (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 1)) {
+          if (count == sizeof(record->ops.supported_formats_list)) {
+            APPL_TRACE_ERROR(
+                "%s() - supported_formats_list - count overflow - "
+                "too many sub attributes!!",
+                __func__);
+            /* If you hit this, new formats have been added,
+             * update SDP_OPP_SUPPORTED_FORMATS_MAX_LENGTH */
+            break;
+          }
+          record->ops.supported_formats_list[count] = p_sattr->attr_value.v.u8;
+          count++;
+        } else {
+          APPL_TRACE_ERROR(
+              "%s() - supported_formats_list - wrong sub attribute "
+              "length/type: 0x%02x - expected 0x80",
+              __func__, p_sattr->attr_len_type);
+          break;
+        }
+      }
+      if (record->ops.supported_formats_list_len != count) {
+        APPL_TRACE_WARNING(
+            "%s() - supported_formats_list - Length of attribute different "
+            "from the actual number of sub-attributes in the sequence "
+            "att-length: %d - number of elements: %d",
+            __func__, record->ops.supported_formats_list_len, count);
+      }
+      record->ops.supported_formats_list_len = count;
+    }
+  }
+}
+
+static void bta_create_sap_sdp_record(bluetooth_sdp_record* record,
+                                      tSDP_DISC_REC* p_rec) {
+  tSDP_DISC_ATTR* p_attr;
+  tSDP_PROTOCOL_ELEM pe;
+  uint16_t pversion = -1;
+
+  record->sap.hdr.type = SDP_TYPE_MAP_MAS;
+  record->sap.hdr.service_name_length = 0;
+  record->sap.hdr.service_name = NULL;
+  record->sap.hdr.rfcomm_channel_number = 0;
+  record->sap.hdr.l2cap_psm = -1;
+  record->sap.hdr.profile_version = 0;
+
+  if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) != NULL) {
+    record->sap.hdr.service_name_length =
+        SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+    record->sap.hdr.service_name = (char*)p_attr->attr_value.v.array;
+  }
+
+  if (SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_SAP, &pversion)) {
+    record->sap.hdr.profile_version = pversion;
+  }
+
+  if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+    record->sap.hdr.rfcomm_channel_number = pe.params[0];
+  }
+}
+
+static void bta_create_raw_sdp_record(bluetooth_sdp_record* record,
+                                      tSDP_DISC_REC* p_rec) {
+  tSDP_DISC_ATTR* p_attr;
+  tSDP_PROTOCOL_ELEM pe;
+
+  record->hdr.type = SDP_TYPE_RAW;
+  record->hdr.service_name_length = 0;
+  record->hdr.service_name = NULL;
+  record->hdr.rfcomm_channel_number = -1;
+  record->hdr.l2cap_psm = -1;
+  record->hdr.profile_version = -1;
+
+  /* Try to extract a service name */
+  if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) != NULL) {
+    record->pse.hdr.service_name_length =
+        SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+    record->pse.hdr.service_name = (char*)p_attr->attr_value.v.array;
+  }
+
+  /* Try to extract an RFCOMM channel */
+  if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+    record->pse.hdr.rfcomm_channel_number = pe.params[0];
+  }
+  record->hdr.user1_ptr_len = p_bta_sdp_cfg->p_sdp_db->raw_size;
+  record->hdr.user1_ptr = p_bta_sdp_cfg->p_sdp_db->raw_data;
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_sdp_search_cback
+ *
+ * Description  Callback from btm after search is completed
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+static void bta_sdp_search_cback(uint16_t result, void* user_data) {
+  tSDP_DISC_REC* p_rec = NULL;
+  tBTA_SDP_SEARCH_COMP evt_data;
+  tBTA_SDP_STATUS status = BTA_SDP_FAILURE;
+  int count = 0;
+  tBT_UUID su;
+  APPL_TRACE_DEBUG("%s() -  res: 0x%x", __func__, result);
+
+  memset(&evt_data, 0, sizeof(evt_data));
+  bta_sdp_cb.sdp_active = BTA_SDP_ACTIVE_NONE;
+
+  if (bta_sdp_cb.p_dm_cback == NULL) return;
+
+  bdcpy(evt_data.remote_addr, bta_sdp_cb.remote_addr);
+  tBT_UUID* uuid = (tBT_UUID*)user_data;
+  memcpy(&evt_data.uuid, uuid, sizeof(tBT_UUID));
+  su = shorten_sdp_uuid(uuid);
+
+  if (result == SDP_SUCCESS || result == SDP_DB_FULL) {
+    do {
+      p_rec = SDP_FindServiceUUIDInDb(p_bta_sdp_cfg->p_sdp_db, &su, p_rec);
+      /* generate the matching record data pointer */
+      if (p_rec != NULL) {
+        status = BTA_SDP_SUCCESS;
+        if (IS_UUID(UUID_MAP_MAS, uuid->uu.uuid128)) {
+          APPL_TRACE_DEBUG("%s() - found MAP (MAS) uuid", __func__);
+          bta_create_mas_sdp_record(&evt_data.records[count], p_rec);
+        } else if (IS_UUID(UUID_MAP_MNS, uuid->uu.uuid128)) {
+          APPL_TRACE_DEBUG("%s() - found MAP (MNS) uuid", __func__);
+          bta_create_mns_sdp_record(&evt_data.records[count], p_rec);
+        } else if (IS_UUID(UUID_PBAP_PSE, uuid->uu.uuid128)) {
+          APPL_TRACE_DEBUG("%s() - found PBAP (PSE) uuid", __func__);
+          bta_create_pse_sdp_record(&evt_data.records[count], p_rec);
+        } else if (IS_UUID(UUID_OBEX_OBJECT_PUSH, uuid->uu.uuid128)) {
+          APPL_TRACE_DEBUG("%s() - found Object Push Server (OPS) uuid",
+                           __func__);
+          bta_create_ops_sdp_record(&evt_data.records[count], p_rec);
+        } else if (IS_UUID(UUID_SAP, uuid->uu.uuid128)) {
+          APPL_TRACE_DEBUG("%s() - found SAP uuid", __func__);
+          bta_create_sap_sdp_record(&evt_data.records[count], p_rec);
+        } else {
+          /* we do not have specific structure for this */
+          APPL_TRACE_DEBUG("%s() - profile not identified. using raw data",
+                           __func__);
+          bta_create_raw_sdp_record(&evt_data.records[count], p_rec);
+          p_rec = NULL;  // Terminate loop
+          /* For raw, we only extract the first entry, and then return the
+             entire
+             raw data chunk.
+             TODO: Find a way to split the raw data into record chunks, and
+             iterate
+                   to extract generic data for each chunk - e.g. rfcomm channel
+             and
+                   service name. */
+        }
+        count++;
+      } else {
+        APPL_TRACE_DEBUG("%s() - UUID not found", __func__);
+      }
+    } while (p_rec != NULL && count < BTA_SDP_MAX_RECORDS);
+
+    evt_data.record_count = count;
+  }
+  evt_data.status = status;
+
+  bta_sdp_cb.p_dm_cback(BTA_SDP_SEARCH_COMP_EVT, (tBTA_SDP*)&evt_data,
+                        (void*)&uuid->uu.uuid128);
+  osi_free(user_data);  // We no longer need the user data to track the search
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_sdp_enable
+ *
+ * Description  Initializes the SDP I/F
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_sdp_enable(tBTA_SDP_MSG* p_data) {
+  APPL_TRACE_DEBUG("%s in, sdp_active:%d", __func__, bta_sdp_cb.sdp_active);
+  tBTA_SDP_STATUS status = BTA_SDP_SUCCESS;
+  bta_sdp_cb.p_dm_cback = p_data->enable.p_cback;
+  bta_sdp_cb.p_dm_cback(BTA_SDP_ENABLE_EVT, (tBTA_SDP*)&status, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_sdp_search
+ *
+ * Description  Discovers all sdp records for an uuid on remote device
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_sdp_search(tBTA_SDP_MSG* p_data) {
+  if (p_data == NULL) {
+    APPL_TRACE_DEBUG("SDP control block handle is null");
+    return;
+  }
+  tBTA_SDP_STATUS status = BTA_SDP_FAILURE;
+
+  APPL_TRACE_DEBUG("%s in, sdp_active:%d", __func__, bta_sdp_cb.sdp_active);
+
+  if (bta_sdp_cb.sdp_active != BTA_SDP_ACTIVE_NONE) {
+    /* SDP is still in progress */
+    status = BTA_SDP_BUSY;
+    if (bta_sdp_cb.p_dm_cback) {
+      tBTA_SDP_SEARCH_COMP result;
+      memset(&result, 0, sizeof(result));
+      result.uuid = p_data->get_search.uuid;
+      bdcpy(result.remote_addr, p_data->get_search.bd_addr);
+      result.status = status;
+      bta_sdp_cb.p_dm_cback(BTA_SDP_SEARCH_COMP_EVT, (tBTA_SDP*)&result, NULL);
+    }
+    return;
+  }
+
+  bta_sdp_cb.sdp_active = BTA_SDP_ACTIVE_YES;
+  bdcpy(bta_sdp_cb.remote_addr, p_data->get_search.bd_addr);
+  /* set the uuid used in the search */
+  tBT_UUID* bta_sdp_search_uuid =
+      static_cast<tBT_UUID*>(osi_malloc(sizeof(tBT_UUID)));
+  memcpy(bta_sdp_search_uuid, &(p_data->get_search.uuid), sizeof(tBT_UUID));
+
+  /* initialize the search for the uuid */
+  APPL_TRACE_DEBUG("%s init discovery with UUID(len: %d):", __func__,
+                   bta_sdp_search_uuid->len);
+  for (int x = 0; x < bta_sdp_search_uuid->len; x++) {
+    APPL_TRACE_DEBUG("%X", bta_sdp_search_uuid->uu.uuid128[x]);
+  }
+  SDP_InitDiscoveryDb(p_bta_sdp_cfg->p_sdp_db, p_bta_sdp_cfg->sdp_db_size, 1,
+                      bta_sdp_search_uuid, 0, NULL);
+
+  if (!SDP_ServiceSearchAttributeRequest2(
+          p_data->get_search.bd_addr, p_bta_sdp_cfg->p_sdp_db,
+          bta_sdp_search_cback, (void*)bta_sdp_search_uuid)) {
+    bta_sdp_cb.sdp_active = BTA_SDP_ACTIVE_NONE;
+
+    /* failed to start SDP. report the failure right away */
+    if (bta_sdp_cb.p_dm_cback) {
+      tBTA_SDP_SEARCH_COMP result;
+      memset(&result, 0, sizeof(result));
+      result.uuid = p_data->get_search.uuid;
+      bdcpy(result.remote_addr, p_data->get_search.bd_addr);
+      result.status = status;
+      bta_sdp_cb.p_dm_cback(BTA_SDP_SEARCH_COMP_EVT, (tBTA_SDP*)&result, NULL);
+    }
+  }
+  /*
+  else report the result when the cback is called
+  */
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_sdp_record
+ *
+ * Description  Discovers all sdp records for an uuid on remote device
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_sdp_create_record(tBTA_SDP_MSG* p_data) {
+  APPL_TRACE_DEBUG("%s() event: %d", __func__, p_data->record.hdr.event);
+  if (bta_sdp_cb.p_dm_cback)
+    bta_sdp_cb.p_dm_cback(BTA_SDP_CREATE_RECORD_USER_EVT, NULL,
+                          p_data->record.user_data);
+}
+
+/*******************************************************************************
+ *
+ * Function     bta_sdp_create_record
+ *
+ * Description  Discovers all sdp records for an uuid on remote device
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void bta_sdp_remove_record(tBTA_SDP_MSG* p_data) {
+  APPL_TRACE_DEBUG("%s() event: %d", __func__, p_data->record.hdr.event);
+  if (bta_sdp_cb.p_dm_cback)
+    bta_sdp_cb.p_dm_cback(BTA_SDP_REMOVE_RECORD_USER_EVT, NULL,
+                          p_data->record.user_data);
+}
diff --git a/bt/bta/sdp/bta_sdp_api.cc b/bt/bta/sdp/bta_sdp_api.cc
new file mode 100644
index 0000000..7160423
--- /dev/null
+++ b/bt/bta/sdp/bta_sdp_api.cc
@@ -0,0 +1,156 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 is the implementation of the API for SDP search subsystem
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_sdp_api.h"
+#include "bta_sdp_int.h"
+#include "bta_sys.h"
+#include "port_api.h"
+#include "sdp_api.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_sdp_reg = {bta_sdp_sm_execute, NULL};
+
+/*******************************************************************************
+ *
+ * Function         BTA_SdpEnable
+ *
+ * Description      Enable the SDP search I/F service. When the enable
+ *                  operation is complete the callback function will be
+ *                  called with a BTA_SDP_ENABLE_EVT. This function must
+ *                  be called before other functions in the SDP search API are
+ *                  called.
+ *
+ * Returns          BTA_SDP_SUCCESS if successful.
+ *                  BTA_SDP_FAIL if internal failure.
+ *
+ ******************************************************************************/
+tBTA_SDP_STATUS BTA_SdpEnable(tBTA_SDP_DM_CBACK* p_cback) {
+  tBTA_SDP_STATUS status = BTA_SDP_FAILURE;
+
+  APPL_TRACE_API(__func__);
+  if (p_cback && false == bta_sys_is_register(BTA_ID_SDP)) {
+    memset(&bta_sdp_cb, 0, sizeof(tBTA_SDP_CB));
+
+    /* register with BTA system manager */
+    bta_sys_register(BTA_ID_SDP, &bta_sdp_reg);
+
+    if (p_cback) {
+      tBTA_SDP_API_ENABLE* p_buf =
+          (tBTA_SDP_API_ENABLE*)osi_malloc(sizeof(tBTA_SDP_API_ENABLE));
+      p_buf->hdr.event = BTA_SDP_API_ENABLE_EVT;
+      p_buf->p_cback = p_cback;
+      bta_sys_sendmsg(p_buf);
+      status = BTA_SDP_SUCCESS;
+    }
+  }
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_SdpSearch
+ *
+ * Description      This function performs service discovery for a specific
+ *                  service on given peer device. When the operation is
+ *                  completed the tBTA_SDP_DM_CBACK callback function will be
+ *                  called with a BTA_SDP_SEARCH_COMPLETE_EVT.
+ *
+ * Returns          BTA_SDP_SUCCESS, if the request is being processed.
+ *                  BTA_SDP_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_SDP_STATUS BTA_SdpSearch(BD_ADDR bd_addr, tSDP_UUID* uuid) {
+  tBTA_SDP_API_SEARCH* p_msg =
+      (tBTA_SDP_API_SEARCH*)osi_malloc(sizeof(tBTA_SDP_API_SEARCH));
+
+  APPL_TRACE_API("%s", __func__);
+
+  p_msg->hdr.event = BTA_SDP_API_SEARCH_EVT;
+  bdcpy(p_msg->bd_addr, bd_addr);
+  // p_msg->uuid = uuid;
+  memcpy(&(p_msg->uuid), uuid, sizeof(tSDP_UUID));
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_SDP_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_SdpCreateRecordByUser
+ *
+ * Description      This function is used to request a callback to create a SDP
+ *                  record. The registered callback will be called with event
+ *                  BTA_SDP_CREATE_RECORD_USER_EVT.
+ *
+ * Returns          BTA_SDP_SUCCESS, if the request is being processed.
+ *                  BTA_SDP_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_SDP_STATUS BTA_SdpCreateRecordByUser(void* user_data) {
+  tBTA_SDP_API_RECORD_USER* p_msg =
+      (tBTA_SDP_API_RECORD_USER*)osi_malloc(sizeof(tBTA_SDP_API_RECORD_USER));
+
+  APPL_TRACE_API("%s", __func__);
+
+  p_msg->hdr.event = BTA_SDP_API_CREATE_RECORD_USER_EVT;
+  p_msg->user_data = user_data;
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_SDP_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTA_SdpRemoveRecordByUser
+ *
+ * Description      This function is used to request a callback to remove a SDP
+ *                  record. The registered callback will be called with event
+ *                  BTA_SDP_REMOVE_RECORD_USER_EVT.
+ *
+ * Returns          BTA_SDP_SUCCESS, if the request is being processed.
+ *                  BTA_SDP_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_SDP_STATUS BTA_SdpRemoveRecordByUser(void* user_data) {
+  tBTA_SDP_API_RECORD_USER* p_msg =
+      (tBTA_SDP_API_RECORD_USER*)osi_malloc(sizeof(tBTA_SDP_API_RECORD_USER));
+
+  APPL_TRACE_API("%s", __func__);
+
+  p_msg->hdr.event = BTA_SDP_API_REMOVE_RECORD_USER_EVT;
+  p_msg->user_data = user_data;
+
+  bta_sys_sendmsg(p_msg);
+
+  return BTA_SDP_SUCCESS;
+}
diff --git a/bt/bta/sdp/bta_sdp_cfg.cc b/bt/bta/sdp/bta_sdp_cfg.cc
new file mode 100644
index 0000000..5be6755
--- /dev/null
+++ b/bt/bta/sdp/bta_sdp_cfg.cc
@@ -0,0 +1,40 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 compile-time configurable constants for SDP Search
+ ******************************************************************************/
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_sdp_api.h"
+
+#ifndef BTA_SDP_DB_SIZE
+#define BTA_SDP_DB_SIZE 4500
+#endif
+
+static uint8_t __attribute__((aligned(4))) bta_sdp_db_data[BTA_SDP_DB_SIZE];
+
+/* SDP configuration structure */
+const tBTA_SDP_CFG bta_sdp_cfg = {
+    BTA_SDP_DB_SIZE,
+    (tSDP_DISCOVERY_DB*)
+        bta_sdp_db_data /* The data buffer to keep SDP database */
+};
+
+tBTA_SDP_CFG* p_bta_sdp_cfg = (tBTA_SDP_CFG*)&bta_sdp_cfg;
diff --git a/bt/bta/sdp/bta_sdp_int.h b/bt/bta/sdp/bta_sdp_int.h
new file mode 100644
index 0000000..21d814b
--- /dev/null
+++ b/bt/bta/sdp/bta_sdp_int.h
@@ -0,0 +1,100 @@
+
+
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright (C) 2003-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 is the private interface file for the BTA SDP I/F
+ *
+ ******************************************************************************/
+#ifndef BTA_SDP_INT_H
+#define BTA_SDP_INT_H
+
+#include "bta_api.h"
+#include "bta_sdp_api.h"
+#include "bta_sys.h"
+
+/*****************************************************************************
+ *  Constants
+ ****************************************************************************/
+
+enum {
+  /* these events are handled by the state machine */
+  BTA_SDP_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_SDP),
+  BTA_SDP_API_SEARCH_EVT,
+  BTA_SDP_API_CREATE_RECORD_USER_EVT,
+  BTA_SDP_API_REMOVE_RECORD_USER_EVT,
+  BTA_SDP_MAX_INT_EVT
+};
+
+enum {
+  BTA_SDP_ACTIVE_NONE = 0,
+  BTA_SDP_ACTIVE_YES /* waiting for SDP result */
+};
+
+/* data type for BTA_SDP_API_ENABLE_EVT */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_SDP_DM_CBACK* p_cback;
+} tBTA_SDP_API_ENABLE;
+
+/* data type for BTA_SDP_API_SEARCH_EVT */
+typedef struct {
+  BT_HDR hdr;
+  BD_ADDR bd_addr;
+  tSDP_UUID uuid;
+} tBTA_SDP_API_SEARCH;
+
+/* data type for BTA_SDP_API_SEARCH_EVT */
+typedef struct {
+  BT_HDR hdr;
+  void* user_data;
+} tBTA_SDP_API_RECORD_USER;
+
+/* union of all data types */
+typedef union {
+  /* GKI event buffer header */
+  BT_HDR hdr;
+  tBTA_SDP_API_ENABLE enable;
+  tBTA_SDP_API_SEARCH get_search;
+  tBTA_SDP_API_RECORD_USER record;
+} tBTA_SDP_MSG;
+
+/* SDP control block */
+typedef struct {
+  uint8_t sdp_active; /* see BTA_SDP_SDP_ACT_* */
+  BD_ADDR remote_addr;
+  tBTA_SDP_DM_CBACK* p_dm_cback;
+} tBTA_SDP_CB;
+
+/* SDP control block */
+extern tBTA_SDP_CB bta_sdp_cb;
+
+/* config struct */
+extern tBTA_SDP_CFG* p_bta_sdp_cfg;
+
+extern bool bta_sdp_sm_execute(BT_HDR* p_msg);
+
+extern void bta_sdp_enable(tBTA_SDP_MSG* p_data);
+extern void bta_sdp_search(tBTA_SDP_MSG* p_data);
+extern void bta_sdp_create_record(tBTA_SDP_MSG* p_data);
+extern void bta_sdp_remove_record(tBTA_SDP_MSG* p_data);
+
+#endif /* BTA_SDP_INT_H */
diff --git a/bt/bta/sys/bta_sys.h b/bt/bta/sys/bta_sys.h
new file mode 100644
index 0000000..c97d8f1
--- /dev/null
+++ b/bt/bta/sys/bta_sys.h
@@ -0,0 +1,285 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 is the public interface file for the BTA system manager.
+ *
+ ******************************************************************************/
+#ifndef BTA_SYS_H
+#define BTA_SYS_H
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "osi/include/alarm.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+ *  Constants and data types
+ ****************************************************************************/
+
+/* vendor specific event handler function type */
+typedef bool(tBTA_SYS_VS_EVT_HDLR)(uint16_t evt, void* p);
+
+/* event handler function type */
+typedef bool(tBTA_SYS_EVT_HDLR)(BT_HDR* p_msg);
+
+/* disable function type */
+typedef void(tBTA_SYS_DISABLE)(void);
+
+/* HW modules */
+enum {
+  BTA_SYS_HW_BLUETOOTH,
+  BTA_SYS_HW_RT,
+
+  BTA_SYS_MAX_HW_MODULES
+};
+
+typedef uint16_t tBTA_SYS_HW_MODULE;
+
+#ifndef BTA_DM_NUM_JV_ID
+#define BTA_DM_NUM_JV_ID 2
+#endif
+
+/* SW sub-systems */
+#define BTA_ID_SYS 0 /* system manager */
+/* BLUETOOTH PART - from 0 to BTA_ID_BLUETOOTH_MAX */
+#define BTA_ID_DM 1             /* device manager */
+#define BTA_ID_DM_SEARCH 2      /* device manager search */
+#define BTA_ID_DM_SEC 3         /* device manager security */
+#define BTA_ID_DG 4             /* data gateway */
+#define BTA_ID_AG 5             /* audio gateway */
+#define BTA_ID_OPC 6            /* object push client */
+#define BTA_ID_OPS 7            /* object push server */
+#define BTA_ID_FTS 8            /* file transfer server */
+#define BTA_ID_CT 9             /* cordless telephony terminal */
+#define BTA_ID_FTC 10           /* file transfer client */
+#define BTA_ID_SS 11            /* synchronization server */
+#define BTA_ID_PR 12            /* Printer client */
+#define BTA_ID_BIC 13           /* Basic Imaging Client */
+#define BTA_ID_PAN 14           /* Personal Area Networking */
+#define BTA_ID_BIS 15           /* Basic Imaging Server */
+#define BTA_ID_ACC 16           /* Advanced Camera Client */
+#define BTA_ID_SC 17            /* SIM Card Access server */
+#define BTA_ID_AV 18            /* Advanced audio/video */
+#define BTA_ID_AVK 19           /* Audio/video sink */
+#define BTA_ID_HD 20            /* HID Device */
+#define BTA_ID_CG 21            /* Cordless Gateway */
+#define BTA_ID_BP 22            /* Basic Printing Client */
+#define BTA_ID_HH 23            /* Human Interface Device Host */
+#define BTA_ID_PBS 24           /* Phone Book Access Server */
+#define BTA_ID_PBC 25           /* Phone Book Access Client */
+#define BTA_ID_JV 26            /* Java */
+#define BTA_ID_HS 27            /* Headset */
+#define BTA_ID_MSE 28           /* Message Server Equipment */
+#define BTA_ID_MCE 29           /* Message Client Equipment */
+#define BTA_ID_HL 30            /* Health Device Profile*/
+#define BTA_ID_GATTC 31         /* GATT Client */
+#define BTA_ID_GATTS 32         /* GATT Client */
+#define BTA_ID_SDP 33           /* SDP Client */
+#define BTA_ID_BLUETOOTH_MAX 34 /* last BT profile */
+
+/* GENERIC */
+#define BTA_ID_PRM 38
+#define BTA_ID_SYSTEM 39  /* platform-specific */
+#define BTA_ID_SWRAP 40   /* Insight script wrapper */
+#define BTA_ID_MIP 41     /* Multicase Individual Polling */
+#define BTA_ID_RT 42      /* Audio Routing module: This module is always on. */
+#define BTA_ID_CLOSURE 43 /* Generic C++ closure  */
+
+/* JV */
+#define BTA_ID_JV1 44 /* JV1 */
+#define BTA_ID_JV2 45 /* JV2 */
+
+#define BTA_ID_MAX (44 + BTA_DM_NUM_JV_ID)
+
+typedef uint8_t tBTA_SYS_ID;
+
+#define BTA_SYS_CONN_OPEN 0x00
+#define BTA_SYS_CONN_CLOSE 0x01
+#define BTA_SYS_APP_OPEN 0x02
+#define BTA_SYS_APP_CLOSE 0x03
+#define BTA_SYS_SCO_OPEN 0x04
+#define BTA_SYS_SCO_CLOSE 0x05
+#define BTA_SYS_CONN_IDLE 0x06
+#define BTA_SYS_CONN_BUSY 0x07
+
+/* for link policy */
+#define BTA_SYS_PLCY_SET 0x10     /* set the link policy to the given addr */
+#define BTA_SYS_PLCY_CLR 0x11     /* clear the link policy to the given addr */
+#define BTA_SYS_PLCY_DEF_SET 0x12 /* set the default link policy */
+#define BTA_SYS_PLCY_DEF_CLR 0x13 /* clear the default link policy */
+#define BTA_SYS_ROLE_CHANGE 0x14  /* role change */
+
+typedef uint8_t tBTA_SYS_CONN_STATUS;
+
+/* Bitmask of sys features */
+#define BTA_SYS_FEAT_PCM2 0x0001
+#define BTA_SYS_FEAT_PCM2_MASTER 0x0002
+
+/* tBTA_PREF_ROLES */
+typedef uint8_t tBTA_SYS_PREF_ROLES;
+
+/* conn callback for role / low power manager*/
+typedef void(tBTA_SYS_CONN_CBACK)(tBTA_SYS_CONN_STATUS status, uint8_t id,
+                                  uint8_t app_id, BD_ADDR peer_addr);
+
+/* conn callback for role / low power manager*/
+typedef void(tBTA_SYS_SSR_CFG_CBACK)(uint8_t id, uint8_t app_id,
+                                     uint16_t latency, uint16_t tout);
+
+#if (BTA_EIR_CANNED_UUID_LIST != TRUE)
+/* eir callback for adding/removeing UUID */
+typedef void(tBTA_SYS_EIR_CBACK)(uint16_t uuid16, bool adding);
+#endif
+
+/* registration structure */
+typedef struct {
+  tBTA_SYS_EVT_HDLR* evt_hdlr;
+  tBTA_SYS_DISABLE* disable;
+} tBTA_SYS_REG;
+
+/* data type to send events to BTA SYS HW manager */
+typedef struct {
+  BT_HDR hdr;
+  tBTA_SYS_HW_MODULE hw_module;
+} tBTA_SYS_HW_MSG;
+
+typedef void (*tBTA_SYS_REGISTER)(uint8_t id, const tBTA_SYS_REG* p_reg);
+typedef void (*tBTA_SYS_SENDMSG)(void* p_msg);
+
+/*****************************************************************************
+ *  Global data
+ ****************************************************************************/
+
+/* trace level */
+extern uint8_t appl_trace_level;
+
+/*****************************************************************************
+ *  Macros
+ ****************************************************************************/
+
+/* Calculate start of event enumeration; id is top 8 bits of event */
+#define BTA_SYS_EVT_START(id) ((id) << 8)
+
+/*****************************************************************************
+ *  events for BTA SYS HW manager
+ ****************************************************************************/
+
+/* events sent to SYS HW manager - must be kept synchronized with tables in
+ * bta_sys_main.cc */
+enum {
+  /* device manager local device API events */
+  BTA_SYS_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_SYS),
+  BTA_SYS_EVT_ENABLED_EVT,
+  BTA_SYS_EVT_STACK_ENABLED_EVT,
+  BTA_SYS_API_DISABLE_EVT,
+  BTA_SYS_EVT_DISABLED_EVT,
+  BTA_SYS_ERROR_EVT,
+
+  BTA_SYS_MAX_EVT
+};
+
+/* SYS HW status events - returned by SYS HW manager to other modules. */
+enum {
+  BTA_SYS_HW_OFF_EVT,
+  BTA_SYS_HW_ON_EVT,
+  BTA_SYS_HW_STARTING_EVT,
+  BTA_SYS_HW_STOPPING_EVT,
+  BTA_SYS_HW_ERROR_EVT
+
+};
+typedef uint8_t tBTA_SYS_HW_EVT;
+
+/* HW enable callback type */
+typedef void(tBTA_SYS_HW_CBACK)(tBTA_SYS_HW_EVT status);
+
+/*****************************************************************************
+ *  Function declarations
+ ****************************************************************************/
+
+extern void bta_sys_init(void);
+extern void bta_sys_free(void);
+extern void bta_sys_event(BT_HDR* p_msg);
+extern void bta_sys_set_trace_level(uint8_t level);
+extern void bta_sys_register(uint8_t id, const tBTA_SYS_REG* p_reg);
+extern void bta_sys_deregister(uint8_t id);
+extern bool bta_sys_is_register(uint8_t id);
+extern uint16_t bta_sys_get_sys_features(void);
+extern void bta_sys_sendmsg(void* p_msg);
+extern void bta_sys_start_timer(alarm_t* alarm, period_ms_t interval,
+                                uint16_t event, uint16_t layer_specific);
+extern void bta_sys_disable(tBTA_SYS_HW_MODULE module);
+
+extern void bta_sys_hw_register(tBTA_SYS_HW_MODULE module,
+                                tBTA_SYS_HW_CBACK* cback);
+extern void bta_sys_hw_unregister(tBTA_SYS_HW_MODULE module);
+
+extern void bta_sys_rm_register(tBTA_SYS_CONN_CBACK* p_cback);
+extern void bta_sys_pm_register(tBTA_SYS_CONN_CBACK* p_cback);
+
+extern void bta_sys_policy_register(tBTA_SYS_CONN_CBACK* p_cback);
+extern void bta_sys_sco_register(tBTA_SYS_CONN_CBACK* p_cback);
+
+extern void bta_sys_conn_open(uint8_t id, uint8_t app_id, BD_ADDR peer_addr);
+extern void bta_sys_conn_close(uint8_t id, uint8_t app_id, BD_ADDR peer_addr);
+extern void bta_sys_app_open(uint8_t id, uint8_t app_id, BD_ADDR peer_addr);
+extern void bta_sys_app_close(uint8_t id, uint8_t app_id, BD_ADDR peer_addr);
+extern void bta_sys_sco_open(uint8_t id, uint8_t app_id, BD_ADDR peer_addr);
+extern void bta_sys_sco_close(uint8_t id, uint8_t app_id, BD_ADDR peer_addr);
+extern void bta_sys_sco_use(uint8_t id, uint8_t app_id, BD_ADDR peer_addr);
+extern void bta_sys_sco_unuse(uint8_t id, uint8_t app_id, BD_ADDR peer_addr);
+extern void bta_sys_idle(uint8_t id, uint8_t app_id, BD_ADDR peer_addr);
+extern void bta_sys_busy(uint8_t id, uint8_t app_id, BD_ADDR peer_addr);
+
+#if (BTM_SSR_INCLUDED == TRUE)
+extern void bta_sys_ssr_cfg_register(tBTA_SYS_SSR_CFG_CBACK* p_cback);
+extern void bta_sys_chg_ssr_config(uint8_t id, uint8_t app_id,
+                                   uint16_t max_latency, uint16_t min_tout);
+#endif
+
+extern void bta_sys_role_chg_register(tBTA_SYS_CONN_CBACK* p_cback);
+extern void bta_sys_notify_role_chg(BD_ADDR_PTR p_bda, uint8_t new_role,
+                                    uint8_t hci_status);
+extern void bta_sys_collision_register(uint8_t bta_id,
+                                       tBTA_SYS_CONN_CBACK* p_cback);
+extern void bta_sys_notify_collision(BD_ADDR_PTR p_bda);
+
+#if (BTA_EIR_CANNED_UUID_LIST != TRUE)
+extern void bta_sys_eir_register(tBTA_SYS_EIR_CBACK* p_cback);
+extern void bta_sys_add_uuid(uint16_t uuid16);
+extern void bta_sys_remove_uuid(uint16_t uuid16);
+#else
+#define bta_sys_eir_register(ut)
+#define bta_sys_add_uuid(ut)
+#define bta_sys_remove_uuid(ut)
+#endif
+
+extern void bta_sys_set_policy(uint8_t id, uint8_t policy, BD_ADDR peer_addr);
+extern void bta_sys_clear_policy(uint8_t id, uint8_t policy, BD_ADDR peer_addr);
+extern void bta_sys_set_default_policy(uint8_t id, uint8_t policy);
+extern void bta_sys_clear_default_policy(uint8_t id, uint8_t policy);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_SYS_H */
diff --git a/bt/bta/sys/bta_sys_conn.cc b/bt/bta/sys/bta_sys_conn.cc
new file mode 100644
index 0000000..27967cc
--- /dev/null
+++ b/bt/bta/sys/bta_sys_conn.cc
@@ -0,0 +1,505 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Routes connection status callbacks from various sub systems to DM
+ *
+ ******************************************************************************/
+
+#include <stddef.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_sys_int.h"
+#include "osi/include/osi.h"
+#include "utl.h"
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_rm_register
+ *
+ * Description      Called by BTA DM to register role management callbacks
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_rm_register(tBTA_SYS_CONN_CBACK* p_cback) {
+  bta_sys_cb.prm_cb = p_cback;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_policy_register
+ *
+ * Description      Called by BTA DM to register link policy change callbacks
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_policy_register(tBTA_SYS_CONN_CBACK* p_cback) {
+  bta_sys_cb.p_policy_cb = p_cback;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_role_chg_register
+ *
+ * Description      Called by BTA AV to register role change callbacks
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_role_chg_register(tBTA_SYS_CONN_CBACK* p_cback) {
+  bta_sys_cb.p_role_cb = p_cback;
+}
+/*******************************************************************************
+ *
+ * Function         bta_sys_ssr_cfg_register
+ *
+ * Description      Called by BTA DM to register SSR configuration callback
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+#if (BTM_SSR_INCLUDED == TRUE)
+void bta_sys_ssr_cfg_register(tBTA_SYS_SSR_CFG_CBACK* p_cback) {
+  bta_sys_cb.p_ssr_cb = p_cback;
+}
+#endif
+/*******************************************************************************
+ *
+ * Function         bta_sys_role_chg_register
+ *
+ * Description      Called by BTA AV to register role change callbacks
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_notify_role_chg(BD_ADDR_PTR p_bda, uint8_t new_role,
+                             uint8_t hci_status) {
+  if (bta_sys_cb.p_role_cb) {
+    bta_sys_cb.p_role_cb(BTA_SYS_ROLE_CHANGE, new_role, hci_status, p_bda);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_collision_register
+ *
+ * Description      Called by any BTA module to register for collision event.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_collision_register(uint8_t bta_id, tBTA_SYS_CONN_CBACK* p_cback) {
+  uint8_t index;
+
+  for (index = 0; index < MAX_COLLISION_REG; index++) {
+    if ((bta_sys_cb.colli_reg.id[index] == bta_id) ||
+        (bta_sys_cb.colli_reg.id[index] == 0)) {
+      bta_sys_cb.colli_reg.id[index] = bta_id;
+      bta_sys_cb.colli_reg.p_coll_cback[index] = p_cback;
+      return;
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_notify_collision
+ *
+ * Description      Called by BTA DM to notify collision event.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_notify_collision(BD_ADDR_PTR p_bda) {
+  uint8_t index;
+
+  for (index = 0; index < MAX_COLLISION_REG; index++) {
+    if ((bta_sys_cb.colli_reg.id[index] != 0) &&
+        (bta_sys_cb.colli_reg.p_coll_cback[index] != NULL)) {
+      bta_sys_cb.colli_reg.p_coll_cback[index](0, BTA_ID_SYS, 0, p_bda);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_sco_register
+ *
+ * Description      Called by BTA AV to register sco connection change callbacks
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_sco_register(tBTA_SYS_CONN_CBACK* p_cback) {
+  bta_sys_cb.p_sco_cb = p_cback;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_pm_register
+ *
+ * Description      Called by BTA DM to register power management callbacks
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_pm_register(tBTA_SYS_CONN_CBACK* p_cback) {
+  bta_sys_cb.ppm_cb = p_cback;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_conn_open
+ *
+ * Description      Called by BTA subsystems when a connection is made to
+ *                  the service
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_conn_open(uint8_t id, uint8_t app_id, BD_ADDR peer_addr) {
+  if (bta_sys_cb.prm_cb) {
+    bta_sys_cb.prm_cb(BTA_SYS_CONN_OPEN, id, app_id, peer_addr);
+  }
+
+  if (bta_sys_cb.ppm_cb) {
+    bta_sys_cb.ppm_cb(BTA_SYS_CONN_OPEN, id, app_id, peer_addr);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_conn_close
+ *
+ * Description      Called by BTA subsystems when a connection to the service
+ *                  is closed
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_conn_close(uint8_t id, uint8_t app_id, BD_ADDR peer_addr) {
+  if (bta_sys_cb.prm_cb) {
+    bta_sys_cb.prm_cb(BTA_SYS_CONN_CLOSE, id, app_id, peer_addr);
+  }
+
+  if (bta_sys_cb.ppm_cb) {
+    bta_sys_cb.ppm_cb(BTA_SYS_CONN_CLOSE, id, app_id, peer_addr);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_app_open
+ *
+ * Description      Called by BTA subsystems when application initiates
+ *                  connection to a peer device
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_app_open(uint8_t id, uint8_t app_id, BD_ADDR peer_addr) {
+  if (bta_sys_cb.ppm_cb) {
+    bta_sys_cb.ppm_cb(BTA_SYS_APP_OPEN, id, app_id, peer_addr);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_app_close
+ *
+ * Description      Called by BTA subsystems when application initiates close
+ *                  of connection to peer device
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_app_close(uint8_t id, uint8_t app_id, BD_ADDR peer_addr) {
+  if (bta_sys_cb.ppm_cb) {
+    bta_sys_cb.ppm_cb(BTA_SYS_APP_CLOSE, id, app_id, peer_addr);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_sco_open
+ *
+ * Description      Called by BTA subsystems when sco connection for that
+ *                  service is open
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_sco_open(uint8_t id, uint8_t app_id, BD_ADDR peer_addr) {
+  /* AG triggers p_sco_cb by bta_sys_sco_use. */
+  if ((id != BTA_ID_AG) && (bta_sys_cb.p_sco_cb)) {
+    /* without querying BTM_GetNumScoLinks() */
+    bta_sys_cb.p_sco_cb(BTA_SYS_SCO_OPEN, 1, app_id, peer_addr);
+  }
+
+  if (bta_sys_cb.ppm_cb) {
+    bta_sys_cb.ppm_cb(BTA_SYS_SCO_OPEN, id, app_id, peer_addr);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_sco_close
+ *
+ * Description      Called by BTA subsystems when sco connection for that
+ *                  service is closed
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_sco_close(uint8_t id, uint8_t app_id, BD_ADDR peer_addr) {
+  uint8_t num_sco_links;
+
+  if ((id != BTA_ID_AG) && (bta_sys_cb.p_sco_cb)) {
+    num_sco_links = BTM_GetNumScoLinks();
+    bta_sys_cb.p_sco_cb(BTA_SYS_SCO_CLOSE, num_sco_links, app_id, peer_addr);
+  }
+
+  if (bta_sys_cb.ppm_cb) {
+    bta_sys_cb.ppm_cb(BTA_SYS_SCO_CLOSE, id, app_id, peer_addr);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_sco_use
+ *
+ * Description      Called by BTA subsystems when that service needs to use sco.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_sco_use(UNUSED_ATTR uint8_t id, uint8_t app_id,
+                     BD_ADDR peer_addr) {
+  /* AV streaming need to be suspended before SCO is connected. */
+  if (bta_sys_cb.p_sco_cb) {
+    /* without querying BTM_GetNumScoLinks() */
+    bta_sys_cb.p_sco_cb(BTA_SYS_SCO_OPEN, 1, app_id, peer_addr);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_sco_unuse
+ *
+ * Description      Called by BTA subsystems when sco connection for that
+ *                  service is no longer needed.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_sco_unuse(UNUSED_ATTR uint8_t id, uint8_t app_id,
+                       BD_ADDR peer_addr) {
+  uint8_t num_sco_links;
+
+  if ((bta_sys_cb.p_sco_cb)) {
+    num_sco_links = BTM_GetNumScoLinks();
+    bta_sys_cb.p_sco_cb(BTA_SYS_SCO_CLOSE, num_sco_links, app_id, peer_addr);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         bta_sys_chg_ssr_config
+ *
+ * Description      Called by BTA subsystems to indicate that the given app SSR
+ *                  setting needs to be changed.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+#if (BTM_SSR_INCLUDED == TRUE)
+void bta_sys_chg_ssr_config(uint8_t id, uint8_t app_id, uint16_t max_latency,
+                            uint16_t min_tout) {
+  if (bta_sys_cb.p_ssr_cb) {
+    bta_sys_cb.p_ssr_cb(id, app_id, max_latency, min_tout);
+  }
+}
+#endif
+/*******************************************************************************
+ *
+ * Function         bta_sys_set_policy
+ *
+ * Description      Called by BTA subsystems to indicate that the given link
+ *                  policy to peer device should be set
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_set_policy(uint8_t id, uint8_t policy, BD_ADDR peer_addr) {
+  if (bta_sys_cb.p_policy_cb) {
+    bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_SET, id, policy, peer_addr);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_clear_policy
+ *
+ * Description      Called by BTA subsystems to indicate that the given link
+ *                  policy to peer device should be clear
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_clear_policy(uint8_t id, uint8_t policy, BD_ADDR peer_addr) {
+  if (bta_sys_cb.p_policy_cb) {
+    bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_CLR, id, policy, peer_addr);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_set_default_policy
+ *
+ * Description      Called by BTA subsystems to indicate that the given default
+ *                  link policy should be set
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_set_default_policy(uint8_t id, uint8_t policy) {
+  if (bta_sys_cb.p_policy_cb) {
+    bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_DEF_SET, id, policy, NULL);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_clear_default_policy
+ *
+ * Description      Called by BTA subsystems to indicate that the given default
+ *                  link policy should be clear
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_clear_default_policy(uint8_t id, uint8_t policy) {
+  if (bta_sys_cb.p_policy_cb) {
+    bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_DEF_CLR, id, policy, NULL);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_idle
+ *
+ * Description      Called by BTA subsystems to indicate that the connection to
+ *                  peer device is idle
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_idle(uint8_t id, uint8_t app_id, BD_ADDR peer_addr) {
+  if (bta_sys_cb.prm_cb) {
+    bta_sys_cb.prm_cb(BTA_SYS_CONN_IDLE, id, app_id, peer_addr);
+  }
+
+  if (bta_sys_cb.ppm_cb) {
+    bta_sys_cb.ppm_cb(BTA_SYS_CONN_IDLE, id, app_id, peer_addr);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_busy
+ *
+ * Description      Called by BTA subsystems to indicate that the connection to
+ *                  peer device is busy
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_busy(uint8_t id, uint8_t app_id, BD_ADDR peer_addr) {
+  if (bta_sys_cb.prm_cb) {
+    bta_sys_cb.prm_cb(BTA_SYS_CONN_BUSY, id, app_id, peer_addr);
+  }
+
+  if (bta_sys_cb.ppm_cb) {
+    bta_sys_cb.ppm_cb(BTA_SYS_CONN_BUSY, id, app_id, peer_addr);
+  }
+}
+
+#if (BTA_EIR_CANNED_UUID_LIST != TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_sys_eir_register
+ *
+ * Description      Called by BTA DM to register EIR utility function that can
+ *                  be used by the other BTA modules to add/remove UUID.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_eir_register(tBTA_SYS_EIR_CBACK* p_cback) {
+  bta_sys_cb.eir_cb = p_cback;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_add_uuid
+ *
+ * Description      Called by BTA subsystems to indicate to DM that new service
+ *                  class UUID is added.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_add_uuid(uint16_t uuid16) {
+  if (bta_sys_cb.eir_cb) {
+    bta_sys_cb.eir_cb(uuid16, true);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_remove_uuid
+ *
+ * Description      Called by BTA subsystems to indicate to DM that the service
+ *                  class UUID is removed.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_remove_uuid(uint16_t uuid16) {
+  if (bta_sys_cb.eir_cb) {
+    bta_sys_cb.eir_cb(uuid16, false);
+  }
+}
+#endif
diff --git a/bt/bta/sys/bta_sys_int.h b/bt/bta/sys/bta_sys_int.h
new file mode 100644
index 0000000..dc88e45
--- /dev/null
+++ b/bt/bta/sys/bta_sys_int.h
@@ -0,0 +1,101 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 is the private interface file for the BTA system manager.
+ *
+ ******************************************************************************/
+#ifndef BTA_SYS_INT_H
+#define BTA_SYS_INT_H
+
+/*****************************************************************************
+ *  Constants and data types
+ ****************************************************************************/
+
+/*****************************************************************************
+ *  state table
+ ****************************************************************************/
+
+/* SYS HW state */
+enum {
+  BTA_SYS_HW_OFF,
+  BTA_SYS_HW_STARTING,
+  BTA_SYS_HW_ON,
+  BTA_SYS_HW_STOPPING
+};
+typedef uint8_t tBTA_SYS_HW_STATE;
+
+/* Collision callback */
+#define MAX_COLLISION_REG 5
+
+typedef struct {
+  uint8_t id[MAX_COLLISION_REG];
+  tBTA_SYS_CONN_CBACK* p_coll_cback[MAX_COLLISION_REG];
+} tBTA_SYS_COLLISION;
+
+/* system manager control block */
+typedef struct {
+  tBTA_SYS_REG* reg[BTA_ID_MAX]; /* registration structures */
+  bool is_reg[BTA_ID_MAX];       /* registration structures */
+  tBTA_SYS_HW_STATE state;
+  tBTA_SYS_HW_CBACK* sys_hw_cback[BTA_SYS_MAX_HW_MODULES]; /* enable callback
+                                                              for each HW
+                                                              modules */
+  uint32_t sys_hw_module_active; /* bitmask of all active modules */
+  uint16_t sys_features;         /* Bitmask of sys features */
+
+  tBTA_SYS_CONN_CBACK* prm_cb; /* role management callback registered by DM */
+  tBTA_SYS_CONN_CBACK*
+      ppm_cb; /* low power management callback registered by DM */
+  tBTA_SYS_CONN_CBACK*
+      p_policy_cb; /* link policy change callback registered by DM */
+  tBTA_SYS_CONN_CBACK*
+      p_sco_cb; /* SCO connection change callback registered by AV */
+  tBTA_SYS_CONN_CBACK* p_role_cb; /* role change callback registered by AV */
+  tBTA_SYS_COLLISION colli_reg;   /* collision handling module */
+#if (BTA_EIR_CANNED_UUID_LIST != TRUE)
+  tBTA_SYS_EIR_CBACK* eir_cb; /* add/remove UUID into EIR */
+#endif
+#if (BTM_SSR_INCLUDED == TRUE)
+  tBTA_SYS_SSR_CFG_CBACK* p_ssr_cb;
+#endif
+  /* VS event handler */
+  tBTA_SYS_VS_EVT_HDLR* p_vs_evt_hdlr;
+
+} tBTA_SYS_CB;
+
+/*****************************************************************************
+ *  Global variables
+ ****************************************************************************/
+
+/* system manager control block */
+extern tBTA_SYS_CB bta_sys_cb;
+
+/* functions used for BTA SYS HW state machine */
+void bta_sys_hw_btm_cback(tBTM_DEV_STATUS status);
+void bta_sys_hw_error(tBTA_SYS_HW_MSG* p_sys_hw_msg);
+void bta_sys_hw_api_enable(tBTA_SYS_HW_MSG* p_sys_hw_msg);
+void bta_sys_hw_api_disable(tBTA_SYS_HW_MSG* p_sys_hw_msg);
+void bta_sys_hw_evt_enabled(tBTA_SYS_HW_MSG* p_sys_hw_msg);
+void bta_sys_hw_evt_disabled(tBTA_SYS_HW_MSG* p_sys_hw_msg);
+void bta_sys_hw_evt_stack_enabled(tBTA_SYS_HW_MSG* p_sys_hw_msg);
+
+bool bta_sys_sm_execute(BT_HDR* p_msg);
+
+#endif /* BTA_SYS_INT_H */
diff --git a/bt/bta/sys/bta_sys_main.cc b/bt/bta/sys/bta_sys_main.cc
new file mode 100644
index 0000000..39ba6e7
--- /dev/null
+++ b/bt/bta/sys/bta_sys_main.cc
@@ -0,0 +1,618 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 is the main implementation file for the BTA system manager.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bta_sys_main"
+
+#include <assert.h>
+#include <pthread.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_closure_int.h"
+#include "bta_sys.h"
+#include "bta_sys_int.h"
+#include "btm_api.h"
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/thread.h"
+#include "utl.h"
+
+#if (defined BTA_AR_INCLUDED) && (BTA_AR_INCLUDED == true)
+#include "bta_ar_api.h"
+#endif
+
+/* system manager control block definition */
+tBTA_SYS_CB bta_sys_cb;
+
+fixed_queue_t* btu_bta_alarm_queue;
+extern thread_t* bt_workqueue_thread;
+
+/* trace level */
+/* TODO Hard-coded trace levels -  Needs to be configurable */
+uint8_t appl_trace_level = BT_TRACE_LEVEL_WARNING;  // APPL_INITIAL_TRACE_LEVEL;
+uint8_t btif_trace_level = BT_TRACE_LEVEL_WARNING;
+
+// Communication queue between btu_task and bta.
+extern fixed_queue_t* btu_bta_msg_queue;
+
+static const tBTA_SYS_REG bta_sys_hw_reg = {bta_sys_sm_execute, NULL};
+
+/* type for action functions */
+typedef void (*tBTA_SYS_ACTION)(tBTA_SYS_HW_MSG* p_data);
+
+/* action function list */
+const tBTA_SYS_ACTION bta_sys_action[] = {
+    /* device manager local device API events - cf bta_sys.h for events */
+    bta_sys_hw_api_enable,        /* 0  BTA_SYS_HW_API_ENABLE_EVT    */
+    bta_sys_hw_evt_enabled,       /* 1  BTA_SYS_HW_EVT_ENABLED_EVT */
+    bta_sys_hw_evt_stack_enabled, /* 2  BTA_SYS_HW_EVT_STACK_ENABLED_EVT */
+    bta_sys_hw_api_disable,       /* 3  BTA_SYS_HW_API_DISABLE_EVT     */
+    bta_sys_hw_evt_disabled,      /* 4  BTA_SYS_HW_EVT_DISABLED_EVT  */
+    bta_sys_hw_error              /* 5   BTA_SYS_HW_ERROR_EVT  */
+};
+
+/* state machine action enumeration list */
+enum {
+  /* device manager local device API events */
+  BTA_SYS_HW_API_ENABLE,
+  BTA_SYS_HW_EVT_ENABLED,
+  BTA_SYS_HW_EVT_STACK_ENABLED,
+  BTA_SYS_HW_API_DISABLE,
+  BTA_SYS_HW_EVT_DISABLED,
+  BTA_SYS_HW_ERROR
+};
+
+#define BTA_SYS_NUM_ACTIONS (BTA_SYS_MAX_EVT & 0x00ff)
+#define BTA_SYS_IGNORE BTA_SYS_NUM_ACTIONS
+
+/* state table information */
+#define BTA_SYS_ACTIONS 2    /* number of actions */
+#define BTA_SYS_NEXT_STATE 2 /* position of next state */
+#define BTA_SYS_NUM_COLS 3   /* number of columns in state tables */
+
+/* state table for OFF state */
+const uint8_t bta_sys_hw_off[][BTA_SYS_NUM_COLS] = {
+    /* Event                    Action 1               Action 2
+       Next State */
+    /* API_ENABLE    */ {BTA_SYS_HW_API_ENABLE, BTA_SYS_IGNORE,
+                         BTA_SYS_HW_STARTING},
+    /* EVT_ENABLED   */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_STARTING},
+    /* STACK_ENABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
+    /* API_DISABLE   */ {BTA_SYS_HW_EVT_DISABLED, BTA_SYS_IGNORE,
+                         BTA_SYS_HW_OFF},
+    /* EVT_DISABLED  */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_OFF},
+    /* EVT_ERROR     */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_OFF}};
+
+const uint8_t bta_sys_hw_starting[][BTA_SYS_NUM_COLS] = {
+    /* Event                    Action 1                   Action 2
+       Next State */
+    /* API_ENABLE    */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE,
+                         BTA_SYS_HW_STARTING}, /* wait for completion event */
+    /* EVT_ENABLED   */ {BTA_SYS_HW_EVT_ENABLED, BTA_SYS_IGNORE,
+                         BTA_SYS_HW_STARTING},
+    /* STACK_ENABLED */ {BTA_SYS_HW_EVT_STACK_ENABLED, BTA_SYS_IGNORE,
+                         BTA_SYS_HW_ON},
+    /* API_DISABLE   */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE,
+                         BTA_SYS_HW_STOPPING}, /* successive disable/enable:
+                                                  change state wait for
+                                                  completion to disable */
+    /* EVT_DISABLED  */ {BTA_SYS_HW_EVT_DISABLED, BTA_SYS_HW_API_ENABLE,
+                         BTA_SYS_HW_STARTING}, /* successive enable/disable:
+                                                  notify, then restart HW */
+    /* EVT_ERROR */ {BTA_SYS_HW_ERROR, BTA_SYS_IGNORE, BTA_SYS_HW_ON}};
+
+const uint8_t bta_sys_hw_on[][BTA_SYS_NUM_COLS] = {
+    /* Event                    Action 1                   Action 2
+       Next State */
+    /* API_ENABLE    */ {BTA_SYS_HW_API_ENABLE, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
+    /* EVT_ENABLED   */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
+    /* STACK_ENABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
+    /* API_DISABLE   */
+    {BTA_SYS_HW_API_DISABLE, BTA_SYS_IGNORE,
+     BTA_SYS_HW_ON}, /* don't change the state here, as some
+                        other modules might be active */
+    /* EVT_DISABLED */ {BTA_SYS_HW_ERROR, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
+    /* EVT_ERROR */ {BTA_SYS_HW_ERROR, BTA_SYS_IGNORE, BTA_SYS_HW_ON}};
+
+const uint8_t bta_sys_hw_stopping[][BTA_SYS_NUM_COLS] = {
+    /* Event                    Action 1                   Action 2
+       Next State */
+    /* API_ENABLE    */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE,
+                         BTA_SYS_HW_STARTING}, /* change state, and wait for
+                                                  completion event to enable */
+    /* EVT_ENABLED   */ {BTA_SYS_HW_EVT_ENABLED, BTA_SYS_IGNORE,
+                         BTA_SYS_HW_STOPPING}, /* successive enable/disable:
+                                                  finish the enable before
+                                                  disabling */
+    /* STACK_ENABLED */ {BTA_SYS_HW_EVT_STACK_ENABLED, BTA_SYS_HW_API_DISABLE,
+                         BTA_SYS_HW_STOPPING}, /* successive enable/disable:
+                                                  notify, then stop */
+    /* API_DISABLE   */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE,
+                         BTA_SYS_HW_STOPPING}, /* wait for completion event */
+    /* EVT_DISABLED  */ {BTA_SYS_HW_EVT_DISABLED, BTA_SYS_IGNORE,
+                         BTA_SYS_HW_OFF},
+    /* EVT_ERROR     */ {BTA_SYS_HW_API_DISABLE, BTA_SYS_IGNORE,
+                         BTA_SYS_HW_STOPPING}};
+
+typedef const uint8_t (*tBTA_SYS_ST_TBL)[BTA_SYS_NUM_COLS];
+
+/* state table */
+const tBTA_SYS_ST_TBL bta_sys_st_tbl[] = {bta_sys_hw_off, bta_sys_hw_starting,
+                                          bta_sys_hw_on, bta_sys_hw_stopping};
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_init
+ *
+ * Description      BTA initialization; called from task initialization.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_init(void) {
+  memset(&bta_sys_cb, 0, sizeof(tBTA_SYS_CB));
+
+  btu_bta_alarm_queue = fixed_queue_new(SIZE_MAX);
+
+  alarm_register_processing_queue(btu_bta_alarm_queue, bt_workqueue_thread);
+
+  appl_trace_level = APPL_INITIAL_TRACE_LEVEL;
+
+  /* register BTA SYS message handler */
+  bta_sys_register(BTA_ID_SYS, &bta_sys_hw_reg);
+
+  /* register for BTM notifications */
+  BTM_RegisterForDeviceStatusNotif((tBTM_DEV_STATUS_CB*)&bta_sys_hw_btm_cback);
+
+#if (defined BTA_AR_INCLUDED) && (BTA_AR_INCLUDED == true)
+  bta_ar_init();
+#endif
+
+  bta_closure_init(bta_sys_register, bta_sys_sendmsg);
+}
+
+void bta_sys_free(void) {
+  alarm_unregister_processing_queue(btu_bta_alarm_queue);
+  fixed_queue_free(btu_bta_alarm_queue, NULL);
+  btu_bta_alarm_queue = NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_sm_execute
+ *
+ * Description      State machine event handling function for DM
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+bool bta_sys_sm_execute(BT_HDR* p_msg) {
+  bool freebuf = true;
+  tBTA_SYS_ST_TBL state_table;
+  uint8_t action;
+  int i;
+
+  APPL_TRACE_EVENT("bta_sys_sm_execute state:%d, event:0x%x", bta_sys_cb.state,
+                   p_msg->event);
+
+  /* look up the state table for the current state */
+  state_table = bta_sys_st_tbl[bta_sys_cb.state];
+  /* update state */
+  bta_sys_cb.state = state_table[p_msg->event & 0x00ff][BTA_SYS_NEXT_STATE];
+
+  /* execute action functions */
+  for (i = 0; i < BTA_SYS_ACTIONS; i++) {
+    if ((action = state_table[p_msg->event & 0x00ff][i]) != BTA_SYS_IGNORE) {
+      (*bta_sys_action[action])((tBTA_SYS_HW_MSG*)p_msg);
+    } else {
+      break;
+    }
+  }
+  return freebuf;
+}
+
+void bta_sys_hw_register(tBTA_SYS_HW_MODULE module, tBTA_SYS_HW_CBACK* cback) {
+  bta_sys_cb.sys_hw_cback[module] = cback;
+}
+
+void bta_sys_hw_unregister(tBTA_SYS_HW_MODULE module) {
+  bta_sys_cb.sys_hw_cback[module] = NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_hw_btm_cback
+ *
+ * Description     This function is registered by BTA SYS to BTM in order to get
+ *                 status notifications
+ *
+ *
+ * Returns
+ *
+ ******************************************************************************/
+void bta_sys_hw_btm_cback(tBTM_DEV_STATUS status) {
+  tBTA_SYS_HW_MSG* sys_event =
+      (tBTA_SYS_HW_MSG*)osi_malloc(sizeof(tBTA_SYS_HW_MSG));
+
+  APPL_TRACE_DEBUG("%s was called with parameter: %i", __func__, status);
+
+  /* send a message to BTA SYS */
+  if (status == BTM_DEV_STATUS_UP) {
+    sys_event->hdr.event = BTA_SYS_EVT_STACK_ENABLED_EVT;
+  } else if (status == BTM_DEV_STATUS_DOWN) {
+    sys_event->hdr.event = BTA_SYS_ERROR_EVT;
+  } else {
+    /* BTM_DEV_STATUS_CMD_TOUT is ignored for now. */
+    osi_free_and_reset((void**)&sys_event);
+  }
+
+  if (sys_event) bta_sys_sendmsg(sys_event);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_hw_error
+ *
+ * Description     In case the HW device stops answering... Try to turn it off,
+ *                 then re-enable all
+ *                      previously active SW modules.
+ *
+ * Returns          success or failure
+ *
+ ******************************************************************************/
+void bta_sys_hw_error(UNUSED_ATTR tBTA_SYS_HW_MSG* p_sys_hw_msg) {
+  uint8_t module_index;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  for (module_index = 0; module_index < BTA_SYS_MAX_HW_MODULES;
+       module_index++) {
+    if (bta_sys_cb.sys_hw_module_active & ((uint32_t)1 << module_index)) {
+      switch (module_index) {
+        case BTA_SYS_HW_BLUETOOTH:
+          /* Send BTA_SYS_HW_ERROR_EVT to DM */
+          if (bta_sys_cb.sys_hw_cback[module_index] != NULL)
+            bta_sys_cb.sys_hw_cback[module_index](BTA_SYS_HW_ERROR_EVT);
+          break;
+        default:
+          /* not yet supported */
+          break;
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_hw_enable
+ *
+ * Description     this function is called after API enable and HW has been
+ *                 turned on
+ *
+ *
+ * Returns          success or failure
+ *
+ ******************************************************************************/
+
+void bta_sys_hw_api_enable(tBTA_SYS_HW_MSG* p_sys_hw_msg) {
+  if ((!bta_sys_cb.sys_hw_module_active) &&
+      (bta_sys_cb.state != BTA_SYS_HW_ON)) {
+    /* register which HW module was turned on */
+    bta_sys_cb.sys_hw_module_active |= ((uint32_t)1 << p_sys_hw_msg->hw_module);
+
+    tBTA_SYS_HW_MSG* p_msg =
+        (tBTA_SYS_HW_MSG*)osi_malloc(sizeof(tBTA_SYS_HW_MSG));
+    p_msg->hdr.event = BTA_SYS_EVT_ENABLED_EVT;
+    p_msg->hw_module = p_sys_hw_msg->hw_module;
+
+    bta_sys_sendmsg(p_msg);
+  } else {
+    /* register which HW module was turned on */
+    bta_sys_cb.sys_hw_module_active |= ((uint32_t)1 << p_sys_hw_msg->hw_module);
+
+    /* HW already in use, so directly notify the caller */
+    if (bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module] != NULL)
+      bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module](BTA_SYS_HW_ON_EVT);
+  }
+
+  APPL_TRACE_EVENT("bta_sys_hw_api_enable for %d, active modules 0x%04X",
+                   p_sys_hw_msg->hw_module, bta_sys_cb.sys_hw_module_active);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_hw_disable
+ *
+ * Description     if no other module is using the HW, this function will call
+ *                 (if defined) a user-macro to turn off the HW
+ *
+ *
+ * Returns          success or failure
+ *
+ ******************************************************************************/
+void bta_sys_hw_api_disable(tBTA_SYS_HW_MSG* p_sys_hw_msg) {
+  APPL_TRACE_DEBUG("bta_sys_hw_api_disable for %d, active modules: 0x%04X",
+                   p_sys_hw_msg->hw_module, bta_sys_cb.sys_hw_module_active);
+
+  /* make sure the related SW blocks were stopped */
+  bta_sys_disable(p_sys_hw_msg->hw_module);
+
+  /* register which module we turn off */
+  bta_sys_cb.sys_hw_module_active &= ~((uint32_t)1 << p_sys_hw_msg->hw_module);
+
+  /* if there are still some SW modules using the HW, just provide an answer to
+   * the calling */
+  if (bta_sys_cb.sys_hw_module_active != 0) {
+    /*  if there are still some SW modules using the HW,  directly notify the
+     * caller */
+    if (bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module] != NULL)
+      bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module](BTA_SYS_HW_OFF_EVT);
+  } else {
+    /* manually update the state of our system */
+    bta_sys_cb.state = BTA_SYS_HW_STOPPING;
+
+    tBTA_SYS_HW_MSG* p_msg =
+        (tBTA_SYS_HW_MSG*)osi_malloc(sizeof(tBTA_SYS_HW_MSG));
+    p_msg->hdr.event = BTA_SYS_EVT_DISABLED_EVT;
+    p_msg->hw_module = p_sys_hw_msg->hw_module;
+
+    bta_sys_sendmsg(p_msg);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_hw_event_enabled
+ *
+ * Description
+ *
+ *
+ * Returns          success or failure
+ *
+ ******************************************************************************/
+void bta_sys_hw_evt_enabled(tBTA_SYS_HW_MSG* p_sys_hw_msg) {
+  APPL_TRACE_EVENT("bta_sys_hw_evt_enabled for %i", p_sys_hw_msg->hw_module);
+  BTM_DeviceReset(NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_hw_event_disabled
+ *
+ * Description
+ *
+ *
+ * Returns          success or failure
+ *
+ ******************************************************************************/
+void bta_sys_hw_evt_disabled(tBTA_SYS_HW_MSG* p_sys_hw_msg) {
+  uint8_t hw_module_index;
+
+  APPL_TRACE_DEBUG("bta_sys_hw_evt_disabled - module 0x%X",
+                   p_sys_hw_msg->hw_module);
+
+  for (hw_module_index = 0; hw_module_index < BTA_SYS_MAX_HW_MODULES;
+       hw_module_index++) {
+    if (bta_sys_cb.sys_hw_cback[hw_module_index] != NULL)
+      bta_sys_cb.sys_hw_cback[hw_module_index](BTA_SYS_HW_OFF_EVT);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_hw_event_stack_enabled
+ *
+ * Description     we receive this event once the SW side is ready (stack, FW
+ *                 download,... ), i.e. we can really start using the device. So
+ *                 notify the app.
+ *
+ * Returns          success or failure
+ *
+ ******************************************************************************/
+void bta_sys_hw_evt_stack_enabled(UNUSED_ATTR tBTA_SYS_HW_MSG* p_sys_hw_msg) {
+  uint8_t hw_module_index;
+
+  APPL_TRACE_DEBUG(" bta_sys_hw_evt_stack_enabled!notify the callers");
+
+  for (hw_module_index = 0; hw_module_index < BTA_SYS_MAX_HW_MODULES;
+       hw_module_index++) {
+    if (bta_sys_cb.sys_hw_cback[hw_module_index] != NULL)
+      bta_sys_cb.sys_hw_cback[hw_module_index](BTA_SYS_HW_ON_EVT);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_event
+ *
+ * Description      BTA event handler; called from task event handler.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_event(BT_HDR* p_msg) {
+  uint8_t id;
+  bool freebuf = true;
+
+  APPL_TRACE_EVENT("BTA got event 0x%x", p_msg->event);
+
+  /* get subsystem id from event */
+  id = (uint8_t)(p_msg->event >> 8);
+
+  /* verify id and call subsystem event handler */
+  if ((id < BTA_ID_MAX) && (bta_sys_cb.reg[id] != NULL)) {
+    freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg);
+  } else {
+    APPL_TRACE_WARNING("BTA got unregistered event id %d", id);
+  }
+
+  if (freebuf) {
+    osi_free(p_msg);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_register
+ *
+ * Description      Called by other BTA subsystems to register their event
+ *                  handler.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_register(uint8_t id, const tBTA_SYS_REG* p_reg) {
+  bta_sys_cb.reg[id] = (tBTA_SYS_REG*)p_reg;
+  bta_sys_cb.is_reg[id] = true;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_deregister
+ *
+ * Description      Called by other BTA subsystems to de-register
+ *                  handler.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_deregister(uint8_t id) { bta_sys_cb.is_reg[id] = false; }
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_is_register
+ *
+ * Description      Called by other BTA subsystems to get registeration
+ *                  status.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+bool bta_sys_is_register(uint8_t id) { return bta_sys_cb.is_reg[id]; }
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_sendmsg
+ *
+ * Description      Send a GKI message to BTA.  This function is designed to
+ *                  optimize sending of messages to BTA.  It is called by BTA
+ *                  API functions and call-in functions.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_sendmsg(void* p_msg) {
+  // There is a race condition that occurs if the stack is shut down while
+  // there is a procedure in progress that can schedule a task via this
+  // message queue. This causes |btu_bta_msg_queue| to get cleaned up before
+  // it gets used here; hence we check for NULL before using it.
+  if (btu_bta_msg_queue) fixed_queue_enqueue(btu_bta_msg_queue, p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_start_timer
+ *
+ * Description      Start a protocol timer for the specified amount
+ *                  of time in milliseconds.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_start_timer(alarm_t* alarm, period_ms_t interval, uint16_t event,
+                         uint16_t layer_specific) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = event;
+  p_buf->layer_specific = layer_specific;
+  alarm_set_on_queue(alarm, interval, bta_sys_sendmsg, p_buf,
+                     btu_bta_alarm_queue);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_disable
+ *
+ * Description      For each registered subsystem execute its disable function.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_disable(tBTA_SYS_HW_MODULE module) {
+  int bta_id = 0;
+  int bta_id_max = 0;
+
+  APPL_TRACE_DEBUG("bta_sys_disable: module %i", module);
+
+  switch (module) {
+    case BTA_SYS_HW_BLUETOOTH:
+      bta_id = BTA_ID_DM;
+      bta_id_max = BTA_ID_BLUETOOTH_MAX;
+      break;
+    default:
+      APPL_TRACE_WARNING("bta_sys_disable: unkown module");
+      return;
+  }
+
+  for (; bta_id <= bta_id_max; bta_id++) {
+    if (bta_sys_cb.reg[bta_id] != NULL) {
+      if (bta_sys_cb.is_reg[bta_id] == true &&
+          bta_sys_cb.reg[bta_id]->disable != NULL) {
+        (*bta_sys_cb.reg[bta_id]->disable)();
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_set_trace_level
+ *
+ * Description      Set trace level for BTA
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_sys_set_trace_level(uint8_t level) { appl_trace_level = level; }
+
+/*******************************************************************************
+ *
+ * Function         bta_sys_get_sys_features
+ *
+ * Description      Returns sys_features to other BTA modules.
+ *
+ * Returns          sys_features
+ *
+ ******************************************************************************/
+uint16_t bta_sys_get_sys_features(void) { return bta_sys_cb.sys_features; }
diff --git a/bt/bta/sys/utl.cc b/bt/bta/sys/utl.cc
new file mode 100644
index 0000000..7feda33
--- /dev/null
+++ b/bt/bta/sys/utl.cc
@@ -0,0 +1,266 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 utility functions.
+ *
+ ******************************************************************************/
+#include <stddef.h>
+
+#include "bt_common.h"
+#include "btm_api.h"
+#include "utl.h"
+
+/*******************************************************************************
+ *
+ * Function         utl_str2int
+ *
+ * Description      This utility function converts a character string to an
+ *                  integer.  Acceptable values in string are 0-9.  If invalid
+ *                  string or string value too large, -1 is returned.  Leading
+ *                  spaces are skipped.
+ *
+ *
+ * Returns          Integer value or -1 on error.
+ *
+ ******************************************************************************/
+int16_t utl_str2int(const char* p_s) {
+  int32_t val = 0;
+
+  for (; *p_s == ' ' && *p_s != 0; p_s++)
+    ;
+
+  if (*p_s == 0) return -1;
+
+  for (;;) {
+    if ((*p_s < '0') || (*p_s > '9')) return -1;
+
+    val += (int32_t)(*p_s++ - '0');
+
+    if (val > 32767) return -1;
+
+    if (*p_s == 0) {
+      return (int16_t)val;
+    } else {
+      val *= 10;
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         utl_strucmp
+ *
+ * Description      This utility function compares two strings in uppercase.
+ *                  String p_s must be uppercase.  String p_t is converted to
+ *                  uppercase if lowercase.  If p_s ends first, the substring
+ *                  match is counted as a match.
+ *
+ *
+ * Returns          0 if strings match, nonzero otherwise.
+ *
+ ******************************************************************************/
+int utl_strucmp(const char* p_s, const char* p_t) {
+  char c;
+
+  while (*p_s && *p_t) {
+    c = *p_t++;
+    if (c >= 'a' && c <= 'z') {
+      c -= 0x20;
+    }
+    if (*p_s++ != c) {
+      return -1;
+    }
+  }
+  /* if p_t hit null first, no match */
+  if (*p_t == 0 && *p_s != 0) {
+    return 1;
+  }
+  /* else p_s hit null first, count as match */
+  else {
+    return 0;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         utl_itoa
+ *
+ * Description      This utility function converts a uint16_t to a string.  The
+ *                  string is NULL-terminated.  The length of the string is
+ *                  returned;
+ *
+ *
+ * Returns          Length of string.
+ *
+ ******************************************************************************/
+uint8_t utl_itoa(uint16_t i, char* p_s) {
+  uint16_t j, k;
+  char* p = p_s;
+  bool fill = false;
+
+  if (i == 0) {
+    /* take care of zero case */
+    *p++ = '0';
+  } else {
+    for (j = 10000; j > 0; j /= 10) {
+      k = i / j;
+      i %= j;
+      if (k > 0 || fill) {
+        *p++ = k + '0';
+        fill = true;
+      }
+    }
+  }
+  *p = 0;
+  return (uint8_t)(p - p_s);
+}
+
+/*******************************************************************************
+ *
+ * Function         utl_set_device_class
+ *
+ * Description      This function updates the local Device Class.
+ *
+ * Parameters:
+ *                  p_cod   - Pointer to the device class to set to
+ *
+ *                  cmd     - the fields of the device class to update.
+ *                            BTA_UTL_SET_COD_MAJOR_MINOR, - overwrite major,
+ *                                                           minor class
+ *                            BTA_UTL_SET_COD_SERVICE_CLASS - set the bits in
+ *                                                            the input
+ *                            BTA_UTL_CLR_COD_SERVICE_CLASS - clear the bits in
+ *                                                            the input
+ *                            BTA_UTL_SET_COD_ALL - overwrite major, minor, set
+ *                                                  the bits in service class
+ *                            BTA_UTL_INIT_COD - overwrite major, minor, and
+ *                                               service class
+ *
+ * Returns          true if successful, Otherwise false
+ *
+ ******************************************************************************/
+bool utl_set_device_class(tBTA_UTL_COD* p_cod, uint8_t cmd) {
+  uint8_t* dev;
+  uint16_t service;
+  uint8_t minor, major;
+  DEV_CLASS dev_class;
+
+  dev = BTM_ReadDeviceClass();
+  BTM_COD_SERVICE_CLASS(service, dev);
+  BTM_COD_MINOR_CLASS(minor, dev);
+  BTM_COD_MAJOR_CLASS(major, dev);
+
+  switch (cmd) {
+    case BTA_UTL_SET_COD_MAJOR_MINOR:
+      minor = p_cod->minor & BTM_COD_MINOR_CLASS_MASK;
+      major = p_cod->major & BTM_COD_MAJOR_CLASS_MASK;
+      break;
+
+    case BTA_UTL_SET_COD_SERVICE_CLASS:
+      /* clear out the bits that is not SERVICE_CLASS bits */
+      p_cod->service &= BTM_COD_SERVICE_CLASS_MASK;
+      service = service | p_cod->service;
+      break;
+
+    case BTA_UTL_CLR_COD_SERVICE_CLASS:
+      p_cod->service &= BTM_COD_SERVICE_CLASS_MASK;
+      service = service & (~p_cod->service);
+      break;
+
+    case BTA_UTL_SET_COD_ALL:
+      minor = p_cod->minor & BTM_COD_MINOR_CLASS_MASK;
+      major = p_cod->major & BTM_COD_MAJOR_CLASS_MASK;
+      p_cod->service &= BTM_COD_SERVICE_CLASS_MASK;
+      service = service | p_cod->service;
+      break;
+
+    case BTA_UTL_INIT_COD:
+      minor = p_cod->minor & BTM_COD_MINOR_CLASS_MASK;
+      major = p_cod->major & BTM_COD_MAJOR_CLASS_MASK;
+      service = p_cod->service & BTM_COD_SERVICE_CLASS_MASK;
+      break;
+
+    default:
+      return false;
+  }
+
+  /* convert the fields into the device class type */
+  FIELDS_TO_COD(dev_class, minor, major, service);
+
+  if (BTM_SetDeviceClass(dev_class) == BTM_SUCCESS) return true;
+
+  return false;
+}
+
+/*******************************************************************************
+ *
+ * Function         utl_isintstr
+ *
+ * Description      This utility function checks if the given string is an
+ *                  integer string or not
+ *
+ *
+ * Returns          true if successful, Otherwise false
+ *
+ ******************************************************************************/
+bool utl_isintstr(const char* p_s) {
+  uint16_t i = 0;
+
+  for (i = 0; p_s[i] != 0; i++) {
+    if (((p_s[i] < '0') || (p_s[i] > '9')) && (p_s[i] != ';')) return false;
+  }
+
+  return true;
+}
+
+/*******************************************************************************
+ *
+ * Function         utl_isdialchar
+ *
+ * Description      This utility function checks if the given character
+ *                  is an acceptable dial digit
+ *
+ * Returns          true if successful, Otherwise false
+ *
+ ******************************************************************************/
+bool utl_isdialchar(const char d) {
+  return (((d >= '0') && (d <= '9')) || (d == '*') || (d == '+') ||
+          (d == '#') || (d == ';') || ((d >= 'A') && (d <= 'C')) ||
+          ((d == 'p') || (d == 'P') || (d == 'w') || (d == 'W')));
+}
+
+/*******************************************************************************
+ *
+ * Function         utl_isdialstr
+ *
+ * Description      This utility function checks if the given string contains
+ *                  only dial digits or not
+ *
+ *
+ * Returns          true if successful, Otherwise false
+ *
+ ******************************************************************************/
+bool utl_isdialstr(const char* p_s) {
+  for (uint16_t i = 0; p_s[i] != 0; i++) {
+    // include chars not in spec that work sent by some headsets.
+    if (!(utl_isdialchar(p_s[i]) || (p_s[i] == '-'))) return false;
+  }
+  return true;
+}
diff --git a/bt/bta/test/bta_closure_test.cc b/bt/bta/test/bta_closure_test.cc
new file mode 100644
index 0000000..75473c8
--- /dev/null
+++ b/bt/bta/test/bta_closure_test.cc
@@ -0,0 +1,115 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+
+#include "bta/closure/bta_closure_int.h"
+#include "bta/include/bta_closure_api.h"
+#include "include/bt_trace.h"
+
+namespace {
+
+/* There is no test class, because we talk to C code that accepts plain
+ * functions as arguments.
+ */
+
+int test_counter = 0;
+int msg_send_counter = 0;
+tBTA_SYS_EVT_HDLR* closure_handler = NULL;
+void* msg = NULL;
+
+void test_plus_one_task() { test_counter++; }
+
+void test_plus_two_task() { test_counter += 2; }
+
+void fake_bta_sys_sendmsg(void* p_msg) {
+  msg_send_counter++;
+  msg = p_msg;
+}
+
+void fake_bta_sys_register(uint8_t id, const tBTA_SYS_REG* p_reg) {
+  closure_handler = p_reg->evt_hdlr;
+}
+
+bool fake_bta_sys_sendmsg_execute() { return closure_handler((BT_HDR*)msg); }
+
+}  // namespace
+
+// TODO(jpawlowski): there is some weird dependency issue in tests, and the
+// tests here fail to compile without this definition.
+extern "C" void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) {}
+
+TEST(ClosureTest, test_post_task) {
+  msg_send_counter = 0;
+  test_counter = 0;
+
+  bta_closure_init(fake_bta_sys_register, fake_bta_sys_sendmsg);
+
+  msg_send_counter = 0;
+  do_in_bta_thread(FROM_HERE, base::Bind(&test_plus_one_task));
+  EXPECT_EQ(1, msg_send_counter);
+  EXPECT_TRUE(msg != NULL) << "Message should not be NULL";
+
+  EXPECT_TRUE(fake_bta_sys_sendmsg_execute());
+  EXPECT_EQ(1, test_counter);
+
+  // We sent only one task for execution, attempt to execute non-exiting
+  // task should fail, counter shouldn't be updated
+  EXPECT_FALSE(fake_bta_sys_sendmsg_execute());
+  EXPECT_EQ(1, test_counter);
+}
+
+TEST(ClosureTest, test_post_multiple_tasks) {
+  msg_send_counter = 0;
+  test_counter = 0;
+
+  bta_closure_init(fake_bta_sys_register, fake_bta_sys_sendmsg);
+
+  do_in_bta_thread(FROM_HERE, base::Bind(&test_plus_one_task));
+  do_in_bta_thread(FROM_HERE, base::Bind(&test_plus_two_task));
+  do_in_bta_thread(FROM_HERE, base::Bind(&test_plus_one_task));
+  do_in_bta_thread(FROM_HERE, base::Bind(&test_plus_two_task));
+  do_in_bta_thread(FROM_HERE, base::Bind(&test_plus_one_task));
+  do_in_bta_thread(FROM_HERE, base::Bind(&test_plus_two_task));
+
+  EXPECT_EQ(6, msg_send_counter);
+  EXPECT_TRUE(msg != NULL) << "Message should not be NULL";
+
+  EXPECT_TRUE(fake_bta_sys_sendmsg_execute());
+  EXPECT_EQ(1, test_counter);
+
+  EXPECT_TRUE(fake_bta_sys_sendmsg_execute());
+  EXPECT_EQ(3, test_counter);
+
+  EXPECT_TRUE(fake_bta_sys_sendmsg_execute());
+  EXPECT_EQ(4, test_counter);
+
+  EXPECT_TRUE(fake_bta_sys_sendmsg_execute());
+  EXPECT_EQ(6, test_counter);
+
+  EXPECT_TRUE(fake_bta_sys_sendmsg_execute());
+  EXPECT_EQ(7, test_counter);
+
+  EXPECT_TRUE(fake_bta_sys_sendmsg_execute());
+  EXPECT_EQ(9, test_counter);
+
+  // We sent only one task for execution, attempt to execute non-exiting
+  // task should fail, counter shouldn't be updated
+  EXPECT_FALSE(fake_bta_sys_sendmsg_execute());
+  EXPECT_EQ(9, test_counter);
+}
diff --git a/bt/btcore/Android.mk b/bt/btcore/Android.mk
new file mode 100644
index 0000000..e89e54d
--- /dev/null
+++ b/bt/btcore/Android.mk
@@ -0,0 +1,119 @@
+ ##############################################################################
+ #
+ #  Copyright (C) 2014 Google, Inc.
+ #
+ #  Licensed under the Apache License, Version 2.0 (the "License");
+ #  you may not use this file except in compliance with the License.
+ #  You may obtain a copy of the License at:
+ #
+ #  http://www.apache.org/licenses/LICENSE-2.0
+ #
+ #  Unless required by applicable law or agreed to in writing, software
+ #  distributed under the License is distributed on an "AS IS" BASIS,
+ #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ #  See the License for the specific language governing permissions and
+ #  limitations under the License.
+ #
+ ##############################################################################
+
+LOCAL_PATH := $(call my-dir)
+
+# Common variables
+# ========================================================
+btcoreCommonSrc := \
+    src/bdaddr.cc \
+    src/device_class.cc \
+    src/hal_util.cc \
+    src/module.cc \
+    src/osi_module.cc \
+    src/property.cc \
+    src/uuid.cc
+
+btcoreCommonTestSrc := \
+	./test/bdaddr_test.cc \
+    ./test/device_class_test.cc \
+    ./test/property_test.cc \
+    ./test/uuid_test.cc \
+    ../osi/test/AllocationTestHarness.cc
+
+btcoreCommonIncludes := \
+    $(LOCAL_PATH)/include \
+    $(LOCAL_PATH)/..
+
+# libbtcore static library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_C_INCLUDES := $(btcoreCommonIncludes)
+LOCAL_SRC_FILES := $(btcoreCommonSrc)
+LOCAL_MODULE := libbtcore
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES := libc liblog
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_STATIC_LIBRARY)
+
+# libbtcore static library for host
+# ========================================================
+ifeq ($(HOST_OS),linux)
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_C_INCLUDES := $(btcoreCommonIncludes)
+LOCAL_SRC_FILES := $(btcoreCommonSrc)
+LOCAL_MODULE := libbtcore-host
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+# TODO(armansito): Setting _GNU_SOURCE isn't very platform-independent but
+# should be compatible for a Linux host OS. We should figure out what to do for
+# a non-Linux host OS.
+LOCAL_CFLAGS += $(bluetooth_CFLAGS) -D_GNU_SOURCE
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+endif
+
+# Note: It's good to get the tests compiled both for the host and the target so
+# we get to test with both Bionic libc and glibc
+
+# libbtcore unit tests for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_C_INCLUDES := $(btcoreCommonIncludes)
+LOCAL_SRC_FILES := $(btcoreCommonTestSrc)
+LOCAL_MODULE := net_test_btcore
+LOCAL_MODULE_TAGS := tests
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_STATIC_LIBRARIES := libbtcore libosi
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_NATIVE_TEST)
+
+# libbtcore unit tests for host
+# ========================================================
+ifeq ($(HOST_OS),linux)
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_C_INCLUDES := $(btcoreCommonIncludes)
+LOCAL_SRC_FILES := $(btcoreCommonTestSrc)
+LOCAL_MODULE := net_test_btcore
+LOCAL_MODULE_TAGS := tests
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_STATIC_LIBRARIES := libbtcore-host libosi-host
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_HOST_NATIVE_TEST)
+endif
diff --git a/bt/btcore/BUILD.gn b/bt/btcore/BUILD.gn
new file mode 100644
index 0000000..b09f455
--- /dev/null
+++ b/bt/btcore/BUILD.gn
@@ -0,0 +1,59 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+static_library("btcore") {
+  sources = [
+    "src/bdaddr.cc",
+    "src/device_class.cc",
+    "src/hal_util.cc",
+    "src/module.cc",
+    "src/property.cc",
+    "src/uuid.cc",
+    "src/osi_module.cc",
+  ]
+
+  include_dirs = [
+    "include",
+    "//",
+  ]
+}
+
+executable("net_test_btcore") {
+  testonly = true
+  sources = [
+    "test/device_class_test.cc",
+    "test/property_test.cc",
+    "test/uuid_test.cc",
+    "//osi/test/AllocationTestHarness.cc",
+  ]
+
+  include_dirs = [
+    "include",
+    "//",
+  ]
+
+  deps = [
+    "//btcore",
+    "//osi",
+    "//third_party/googletest:gtest_main",
+  ]
+
+  libs = [
+    "-lpthread",
+    "-lrt",
+    "-ldl",
+  ]
+}
diff --git a/bt/btcore/include/bdaddr.h b/bt/btcore/include/bdaddr.h
new file mode 100644
index 0000000..70213e6
--- /dev/null
+++ b/bt/btcore/include/bdaddr.h
@@ -0,0 +1,65 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <hardware/bluetooth.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Note: the string representation of a bdaddr is expected to have the format
+// xx:xx:xx:xx:xx:xx
+// where each 'x' is a hex digit. The API presented in this header will accept
+// both uppercase and lowercase digits but will only ever produce lowercase
+// digits.
+
+typedef char bdstr_t[sizeof("xx:xx:xx:xx:xx:xx")];
+
+// Returns true if |addr| is the empty address (00:00:00:00:00:00).
+// |addr| may not be NULL.
+bool bdaddr_is_empty(const bt_bdaddr_t *addr);
+
+// Returns true if |first| and |second| refer to the same address. Neither
+// may be NULL.
+bool bdaddr_equals(const bt_bdaddr_t *first, const bt_bdaddr_t *second);
+
+// Returns destination bdaddr |dest| after copying |src| to |dest|.
+// |dest| and |src| must not be NULL.
+bt_bdaddr_t *bdaddr_copy(bt_bdaddr_t *dest, const bt_bdaddr_t *src);
+
+// Makes a string representation of |addr| and places it into |string|. |size|
+// refers to the size of |string|'s buffer and must be >= 18. On success, this
+// function returns |string|, otherwise it returns NULL. Neither |addr| nor |string|
+// may be NULL.
+const char *bdaddr_to_string(const bt_bdaddr_t *addr, char *string, size_t size);
+
+// Returns true if |string| represents a Bluetooth address. |string| may not be NULL.
+bool string_is_bdaddr(const char *string);
+
+// Converts |string| to bt_bdaddr_t and places it in |addr|. If |string| does not
+// represent a Bluetooth address, |addr| is not modified and this function returns
+// false. Otherwise, it returns true. Neither |string| nor |addr| may be NULL.
+bool string_to_bdaddr(const char *string, bt_bdaddr_t *addr);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/btcore/include/device_class.h b/bt/btcore/include/device_class.h
new file mode 100644
index 0000000..6887336
--- /dev/null
+++ b/bt/btcore/include/device_class.h
@@ -0,0 +1,100 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+#include <stdint.h>
+
+// Provides Class Of Device primitive as specified in the bluetooth spec.
+// [Class Of Device](https://www.bluetooth.org/en-us/specification/assigned-numbers/baseband)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Device class may be defined in other structures.
+// Only use defined methods to manipulate internals.
+typedef struct bt_device_class_t {
+  uint8_t _[3];  // Do not access directly; use methods below.
+} bt_device_class_t;
+
+// Copies the |data| class of device stream into device class |dc|.  |dc|
+// and |data| must not be NULL.
+void device_class_from_stream(bt_device_class_t *dc, const uint8_t *data);
+
+// Serializes the device class |dc| to pointer argument |data| in big endian
+// format.  |len| must contain the buffer size of |data|.  Returns the actual
+// number of bytes copied into |data|.  |dc| and |data| must not be NULL.
+int device_class_to_stream(const bt_device_class_t *dc, uint8_t *data, size_t len);
+
+// Copies the |data| class of device integer into device class |dc|.  |dc|
+// must not be NULL.
+void device_class_from_int(bt_device_class_t *dc, int data);
+
+// Returns the device class |dc| in integer format.  |dc| must not be NULL.
+int device_class_to_int(const bt_device_class_t *dc);
+
+// Compares and returns |true| if two device classes |p1| and |p2| are equal.
+// False otherwise.
+bool device_class_equals(const bt_device_class_t *p1, const bt_device_class_t *p2);
+
+// Copies and returns |true| if the device class was successfully copied from
+//  |p2| into |p1|.  False otherwise.
+bool device_class_copy(bt_device_class_t *dest, const bt_device_class_t *src);
+
+// Query, getters and setters for the major device class.  |dc| must not be NULL.
+int device_class_get_major_device(const bt_device_class_t *dc);
+void device_class_set_major_device(bt_device_class_t *dc, int val);
+
+// Query, getters and setters for the minor device class. |dc| must not be NULL.
+int device_class_get_minor_device(const bt_device_class_t *dc);
+void device_class_set_minor_device(bt_device_class_t *dc, int val);
+
+// Query, getters and setters for the various major service class features.
+// |dc| must not be NULL.
+bool device_class_get_limited(const bt_device_class_t *dc);
+void device_class_set_limited(bt_device_class_t *dc, bool set);
+
+bool device_class_get_positioning(const bt_device_class_t *dc);
+void device_class_set_positioning(bt_device_class_t *dc, bool set);
+
+bool device_class_get_networking(const bt_device_class_t *dc);
+void device_class_set_networking(bt_device_class_t *dc, bool set);
+
+bool device_class_get_rendering(const bt_device_class_t *dc);
+void device_class_set_rendering(bt_device_class_t *dc, bool set);
+
+bool device_class_get_capturing(const bt_device_class_t *dc);
+void device_class_set_capturing(bt_device_class_t *dc, bool set);
+
+bool device_class_get_object_transfer(const bt_device_class_t *dc);
+void device_class_set_object_transfer(bt_device_class_t *dc, bool set);
+
+bool device_class_get_audio(const bt_device_class_t *dc);
+void device_class_set_audio(bt_device_class_t *dc, bool set);
+
+bool device_class_get_telephony(const bt_device_class_t *dc);
+void device_class_set_telephony(bt_device_class_t *dc, bool set);
+
+bool device_class_get_information(const bt_device_class_t *dc);
+void device_class_set_information(bt_device_class_t *dc, bool set);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/btcore/include/device_features.h b/bt/btcore/include/device_features.h
new file mode 100644
index 0000000..64ef866
--- /dev/null
+++ b/bt/btcore/include/device_features.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Represents a page of device feature enabled/disabled bits returned
+// by the local controller. See the bluetooth spec for bit indexes.
+typedef struct {
+  uint8_t as_array[8];
+} bt_device_features_t;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/btcore/include/event_mask.h b/bt/btcore/include/event_mask.h
new file mode 100644
index 0000000..8dd92a7
--- /dev/null
+++ b/bt/btcore/include/event_mask.h
@@ -0,0 +1,36 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Represents a mask which can be used to tell the controller which
+// HCI events the stack wishes to be informed about. See the bluetooth
+// spec for more information on what each bit means.
+typedef struct {
+  const uint8_t as_array[8];
+} bt_event_mask_t;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/btcore/include/hal_util.h b/bt/btcore/include/hal_util.h
new file mode 100644
index 0000000..c495468
--- /dev/null
+++ b/bt/btcore/include/hal_util.h
@@ -0,0 +1,32 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct hw_module_t;
+
+// Loads the Bluetooth library. If OS_GENERIC is defined, this function looks
+// explicitly for libbluetooth.default.so and loads it. On Android, this calls
+// the hw_get_module routine with the Bluetooth stack module id.
+int hal_util_load_bt_library(const struct hw_module_t **module);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/btcore/include/iac.h b/bt/btcore/include/iac.h
new file mode 100644
index 0000000..c9254d2
--- /dev/null
+++ b/bt/btcore/include/iac.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Inquiry Access Code
+// [Bluetooth Baseband](https://www.bluetooth.org/en-us/specification/assigned-numbers/baseband)
+typedef struct {
+  uint8_t iac[3];
+} __attribute__((packed))bt_inquiry_access_code_t;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/btcore/include/module.h b/bt/btcore/include/module.h
new file mode 100644
index 0000000..8d06b51
--- /dev/null
+++ b/bt/btcore/include/module.h
@@ -0,0 +1,77 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+
+#include "osi/include/future.h"
+#include "osi/include/thread.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef future_t *(*module_lifecycle_fn)(void);
+
+#define BTCORE_MAX_MODULE_DEPENDENCIES 10
+
+typedef struct {
+  const char *name;
+  module_lifecycle_fn init;
+  module_lifecycle_fn start_up;
+  module_lifecycle_fn shut_down;
+  module_lifecycle_fn clean_up;
+  const char *dependencies[BTCORE_MAX_MODULE_DEPENDENCIES];
+} module_t;
+
+// Prepares module management. Must be called before doing anything with modules.
+void module_management_start(void);
+// Cleans up all module management resources.
+void module_management_stop(void);
+
+const module_t *get_module(const char *name);
+
+// Initialize the provided module. |module| may not be NULL
+// and must not be initialized.
+bool module_init(const module_t *module);
+// Start up the provided module. |module| may not be NULL
+// and must be initialized or have no init function.
+bool module_start_up(const module_t *module);
+// Shut down the provided module. |module| may not be NULL.
+// If not started, does nothing.
+void module_shut_down(const module_t *module);
+// Clean up the provided module. |module| may not be NULL.
+// If not initialized, does nothing.
+void module_clean_up(const module_t *module);
+
+// Temporary callbacked wrapper for module start up, so real modules can be
+// spliced into the current janky startup sequence. Runs on a separate thread,
+// which terminates when the module start up has finished. When module startup
+// has finished, |callback| is called within the context of |callback_thread|
+// with |FUTURE_SUCCESS| or |FUTURE_FAIL| depending on whether startup succeeded
+// or not.
+void module_start_up_callbacked_wrapper(
+  const module_t *module,
+  thread_t *callback_thread,
+  thread_fn callback
+);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/btcore/include/osi_module.h b/bt/btcore/include/osi_module.h
new file mode 100644
index 0000000..2411e35
--- /dev/null
+++ b/bt/btcore/include/osi_module.h
@@ -0,0 +1,29 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static const char OSI_MODULE[] = "osi_module";
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/btcore/include/property.h b/bt/btcore/include/property.h
new file mode 100644
index 0000000..038ef90
--- /dev/null
+++ b/bt/btcore/include/property.h
@@ -0,0 +1,85 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <hardware/bluetooth.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "btcore/include/device_class.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Copies an array of consecutive properties of |count| to a newly
+// allocated array. |properties| must not be NULL.
+bt_property_t *property_copy_array(const bt_property_t *properties, size_t count);
+
+// Copies |src| to |dest|. Returns the value of |dest|.
+// |src| and |dest| must not be NULL.
+bt_property_t *property_copy(bt_property_t *dest, const bt_property_t *src);
+
+// Returns true if the value of the two properties |p1| and |p2| are equal.
+// |p1| and |p2| must not be NULL.
+bool property_equals(const bt_property_t *p1, const bt_property_t *p2);
+
+// Property resource allocations. Caller is expected to free |property|
+// using |property_free| or |property_free_array|.
+// Parameter must not be NULL. A copy of the parameter is made and
+// stored in the property.
+bt_property_t *property_new_addr(const bt_bdaddr_t *addr);
+bt_property_t *property_new_device_class(const bt_device_class_t *dc);
+bt_property_t *property_new_device_type(bt_device_type_t device_type);
+bt_property_t *property_new_discovery_timeout(const uint32_t timeout);
+bt_property_t *property_new_name(const char *name);
+bt_property_t *property_new_rssi(const int8_t rssi);
+bt_property_t *property_new_scan_mode(bt_scan_mode_t scan_mode);
+bt_property_t *property_new_uuids(const bt_uuid_t *uuid, size_t count);
+
+// Property resource frees both property and value.
+void property_free(bt_property_t *property);
+void property_free_array(bt_property_t *properties, size_t count);
+
+// Value check convenience methods. The contents of the property are
+// checked for the respective validity and returns true, false otherwise.
+// |property| must not be NULL.
+bool property_is_addr(const bt_property_t *property);
+bool property_is_device_class(const bt_property_t *property);
+bool property_is_device_type(const bt_property_t *property);
+bool property_is_discovery_timeout(const bt_property_t *property);
+bool property_is_name(const bt_property_t *property);
+bool property_is_rssi(const bt_property_t *property);
+bool property_is_scan_mode(const bt_property_t *property);
+bool property_is_uuids(const bt_property_t *property);
+
+// Value conversion convenience methods. The contents of the property are
+// properly typed and returned to the caller. |property| must not be NULL.
+const bt_bdaddr_t *property_as_addr(const bt_property_t *property);
+const bt_device_class_t *property_as_device_class(const bt_property_t *property);
+bt_device_type_t property_as_device_type(const bt_property_t *property);
+uint32_t property_as_discovery_timeout(const bt_property_t *property);
+const bt_bdname_t *property_as_name(const bt_property_t *property);
+int8_t property_as_rssi(const bt_property_t *property);
+bt_scan_mode_t property_as_scan_mode(const bt_property_t *property);
+const bt_uuid_t *property_as_uuids(const bt_property_t *property, size_t *count);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/btcore/include/uuid.h b/bt/btcore/include/uuid.h
new file mode 100644
index 0000000..f0ae266
--- /dev/null
+++ b/bt/btcore/include/uuid.h
@@ -0,0 +1,83 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <hardware/bluetooth.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct uuid_string_t uuid_string_t;
+
+// Creates uuid string structure to hold a well formed UUID
+// string.  Must release resources with |uuid_string_free|.
+// Returns NULL if no memory.
+uuid_string_t *uuid_string_new(void);
+
+// Frees a uuid string structure created from |uuid_string_new|.
+// |uuid_string| may be NULL.
+void uuid_string_free(uuid_string_t *uuid_string);
+
+// Returns a string pointer to the well formed UUID string
+// entry.  |uuid_string| must not be NULL.
+const char *uuid_string_data(const uuid_string_t *uuid_string);
+
+// Creates uuid structure from a well formed UUID string
+// |uuid_string|.  The caller takes ownership of the uuid
+// structure and must release resources with |uuid_free|.
+// |uuid_string| must not be NULL.
+//
+// Returns NULL if |uuid_string| is malformed or no memory.
+//
+// A well formed UUID string is structured like this:
+//   "00112233-4455-6677-8899-aabbccddeeff"
+bt_uuid_t *uuid_new(const char *uuid_string);
+
+// Frees a uuid structure created from |uuid_new| and friends.
+// |uuid| may be NULL.
+void uuid_free(bt_uuid_t *uuid);
+
+// Returns true if the UUID is all zeros, false otherwise.
+// |uuid| may not be NULL.
+bool uuid_is_empty(const bt_uuid_t *uuid);
+
+// Returns true if the two UUIDs are equal, false otherwise.
+// |first| and |second| may not be NULL.
+bool uuid_is_equal(const bt_uuid_t *first, const bt_uuid_t *second);
+
+// Copies uuid |src| into |dest| and returns a pointer to |dest|.
+// |src| and |dest| must not be NULL.
+bt_uuid_t *uuid_copy(bt_uuid_t *dest, const bt_uuid_t *src);
+
+// Converts contents of |uuid| to a well formed UUID string
+// |uuid_string| using numbers and lower case letter.  |uuid|
+// and |uuid_string| must not be NULL.
+void uuid_to_string(const bt_uuid_t *uuid, uuid_string_t *uuid_string);
+
+// Converts contents of |uuid| to a short uuid if possible.  Returns
+// true if conversion is possible, false otherwise.
+// |uuid|, |uuid16| and |uuid32| must not be NULL.
+bool uuid_128_to_16(const bt_uuid_t *uuid, uint16_t *uuid16);
+bool uuid_128_to_32(const bt_uuid_t *uuid, uint32_t *uuid32);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/btcore/include/version.h b/bt/btcore/include/version.h
new file mode 100644
index 0000000..ad0c38b
--- /dev/null
+++ b/bt/btcore/include/version.h
@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+  uint8_t hci_version;
+  uint16_t hci_revision;
+  uint8_t lmp_version;
+  uint16_t manufacturer;
+  uint16_t lmp_subversion;
+} bt_version_t;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/btcore/src/bdaddr.cc b/bt/btcore/src/bdaddr.cc
new file mode 100644
index 0000000..80ad11e
--- /dev/null
+++ b/bt/btcore/src/bdaddr.cc
@@ -0,0 +1,92 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "btcore/include/bdaddr.h"
+
+bool bdaddr_is_empty(const bt_bdaddr_t *addr) {
+  assert(addr != NULL);
+
+  uint8_t zero[sizeof(bt_bdaddr_t)] = { 0 };
+  return memcmp(addr, &zero, sizeof(bt_bdaddr_t)) == 0;
+}
+
+bool bdaddr_equals(const bt_bdaddr_t *first, const bt_bdaddr_t *second) {
+  assert(first != NULL);
+  assert(second != NULL);
+
+  return memcmp(first, second, sizeof(bt_bdaddr_t)) == 0;
+}
+
+bt_bdaddr_t *bdaddr_copy(bt_bdaddr_t *dest, const bt_bdaddr_t *src) {
+  assert(dest != NULL);
+  assert(src != NULL);
+
+  return (bt_bdaddr_t *)memcpy(dest, src, sizeof(bt_bdaddr_t));
+}
+
+const char *bdaddr_to_string(const bt_bdaddr_t *addr, char *string, size_t size) {
+  assert(addr != NULL);
+  assert(string != NULL);
+
+  if (size < 18)
+    return NULL;
+
+  const uint8_t *ptr = addr->address;
+  snprintf(string, size, "%02x:%02x:%02x:%02x:%02x:%02x",
+           ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]);
+  return string;
+}
+
+bool string_is_bdaddr(const char *string) {
+  assert(string != NULL);
+
+  size_t len = strlen(string);
+  if (len != 17)
+    return false;
+
+  for (size_t i = 0; i < len; ++i) {
+    // Every 3rd char must be ':'.
+    if (((i + 1) % 3) == 0 && string[i] != ':')
+      return false;
+
+    // All other chars must be a hex digit.
+    if (((i + 1) % 3) != 0 && !isxdigit(string[i]))
+      return false;
+  }
+  return true;
+}
+
+bool string_to_bdaddr(const char *string, bt_bdaddr_t *addr) {
+  assert(string != NULL);
+  assert(addr != NULL);
+
+  bt_bdaddr_t new_addr;
+  uint8_t *ptr = new_addr.address;
+  bool ret = sscanf(string, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+      &ptr[0], &ptr[1], &ptr[2], &ptr[3], &ptr[4], &ptr[5]) == 6;
+
+  if (ret)
+    memcpy(addr, &new_addr, sizeof(bt_bdaddr_t));
+
+  return ret;
+}
diff --git a/bt/btcore/src/device_class.cc b/bt/btcore/src/device_class.cc
new file mode 100644
index 0000000..f5711af
--- /dev/null
+++ b/bt/btcore/src/device_class.cc
@@ -0,0 +1,158 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <arpa/inet.h>
+#include <assert.h>
+#include <string.h>
+
+#include "btcore/include/device_class.h"
+#include "osi/include/osi.h"
+
+typedef struct _bt_device_class_t {
+  uint32_t unused : 2;          // LSBs
+  uint32_t minor_device : 6;
+  uint32_t major_device : 5;
+  uint32_t major_service : 11;  // MSBs
+} __attribute__ ((__packed__)) _bt_device_class_t;
+
+// Convenience to interpret raw device class bytes.
+#define DC(x) ((_bt_device_class_t *)(x))
+
+// Ensure the internal device class implementation and public one
+// have equal size.
+COMPILE_ASSERT(sizeof(_bt_device_class_t) == sizeof(bt_device_class_t));
+
+// [Major Service Classes](https://www.bluetooth.org/en-us/specification/assigned-numbers/baseband)
+enum {
+  DC_LIMITED_DISCOVERABLE_MODE = 0x0001,
+  DC_RESERVED14 = 0x0002,
+  DC_RESERVED15 = 0x0004,
+  DC_POSITIONING = 0x0008,
+  DC_NETWORKING = 0x0010,
+  DC_RENDERING = 0x0020,
+  DC_CAPTURING = 0x0040,
+  DC_OBJECT_TRANSFER = 0x0080,
+  DC_AUDIO = 0x0100,
+  DC_TELEPHONY = 0x0200,
+  DC_INFORMATION = 0x0400,
+};
+
+static bool device_class_get_major_service_(const bt_device_class_t *dc, int bitmask);
+static void device_class_clr_major_service_(bt_device_class_t *dc, int bitmask);
+static void device_class_set_major_service_(bt_device_class_t *dc, int bitmask);
+
+void device_class_from_stream(bt_device_class_t *dc, const uint8_t *data) {
+  assert(dc != NULL);
+  assert(data != NULL);
+  *dc = *(bt_device_class_t *)data;
+}
+
+int device_class_to_stream(const bt_device_class_t *dc, uint8_t *data, size_t len) {
+  assert(dc != NULL);
+  assert(data != NULL);
+  assert(len >= sizeof(bt_device_class_t));
+  for (size_t i = 0; i < sizeof(bt_device_class_t); ++i) {
+    data[i] = dc->_[i];
+  }
+  return sizeof(bt_device_class_t);
+}
+
+void device_class_from_int(bt_device_class_t *dc, int data) {
+  assert(dc != NULL);
+  assert(data != 0);
+  // Careful with endianess.
+  dc->_[0] = data & 0xff;
+  dc->_[1] = (data >> 8) & 0xff;
+  dc->_[2] = (data >> 16) & 0xff;
+}
+
+int device_class_to_int(const bt_device_class_t *dc) {
+  assert(dc != NULL);
+  // Careful with endianess.
+  return (int)(le32toh(*(int*)dc) & 0xffffff);
+}
+
+bool device_class_equals(const bt_device_class_t *p1, const bt_device_class_t *p2) {
+  assert(p1 != NULL);
+  assert(p2 != NULL);
+  return (memcmp(p1, p2, sizeof(bt_device_class_t)) == 0);
+}
+
+bool device_class_copy(bt_device_class_t *dest, const bt_device_class_t *src) {
+  assert(dest != NULL);
+  assert(src != NULL);
+  return (memcpy(dest, src, sizeof(bt_device_class_t)) == dest);
+}
+
+int device_class_get_major_device(const bt_device_class_t *dc) {
+  assert(dc != NULL);
+  return DC(dc)->major_device;
+}
+
+void device_class_set_major_device(bt_device_class_t *dc, int val) {
+  assert(dc != NULL);
+  DC(dc)->major_device = val;
+}
+
+int device_class_get_minor_device(const bt_device_class_t *dc) {
+  assert(dc != NULL);
+  return DC(dc)->minor_device;
+}
+
+void device_class_set_minor_device(bt_device_class_t *dc, int val) {
+  assert(dc != NULL);
+  DC(dc)->minor_device = val;
+}
+
+bool device_class_get_information(const bt_device_class_t *dc) {
+  assert(dc != NULL);
+  return device_class_get_major_service_(dc, DC_INFORMATION);
+}
+
+void device_class_set_information(bt_device_class_t *dc, bool set) {
+  assert(dc != NULL);
+  if (set)
+    device_class_set_major_service_(dc, DC_INFORMATION);
+  else
+    device_class_clr_major_service_(dc, DC_INFORMATION);
+}
+
+bool device_class_get_limited(const bt_device_class_t *dc) {
+  assert(dc != NULL);
+  return device_class_get_major_service_(dc, DC_LIMITED_DISCOVERABLE_MODE);
+}
+
+void device_class_set_limited(bt_device_class_t *dc, bool set) {
+  assert(dc != NULL);
+  if (set)
+    device_class_set_major_service_(dc, DC_LIMITED_DISCOVERABLE_MODE);
+  else
+    device_class_clr_major_service_(dc, DC_LIMITED_DISCOVERABLE_MODE);
+}
+
+static bool device_class_get_major_service_(const bt_device_class_t *dc, int bitmask) {
+  return (DC(dc)->major_service & bitmask);
+}
+
+static void device_class_clr_major_service_(bt_device_class_t *dc, int bitmask) {
+  DC(dc)->major_service &= ~bitmask;
+}
+
+static void device_class_set_major_service_(bt_device_class_t *dc, int bitmask) {
+  DC(dc)->major_service |= bitmask;
+}
diff --git a/bt/btcore/src/hal_util.cc b/bt/btcore/src/hal_util.cc
new file mode 100644
index 0000000..0480be5
--- /dev/null
+++ b/bt/btcore/src/hal_util.cc
@@ -0,0 +1,93 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "hal_util"
+
+#include <hardware/bluetooth.h>
+#include <hardware/hardware.h>
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <string.h>
+
+#include "btcore/include/hal_util.h"
+#include "osi/include/log.h"
+
+#if defined(OS_GENERIC)
+
+// TODO(armansito): All logging macros should include __func__ by default (see
+// Bug: 22671731)
+#define HULOGERR(fmt, args...) \
+    LOG_ERROR(LOG_TAG, "[%s] failed to load the Bluetooth library: " fmt, \
+              __func__, ## args)
+
+// TODO(armansito): It might be better to pass the library name in a more
+// generic manner as opposed to hard-coding it here.
+static const char kBluetoothLibraryName[] = "libbluetooth.default.so";
+
+static int load_bt_library(const struct hw_module_t **module) {
+  const char *id = BT_STACK_MODULE_ID;
+  const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
+  struct hw_module_t *hmi = nullptr;
+
+  // Always try to load the default Bluetooth stack on GN builds.
+  void *handle = dlopen(kBluetoothLibraryName, RTLD_NOW);
+  if (!handle) {
+    char const *err_str = dlerror();
+    HULOGERR("%s", err_str ? err_str : "error unknown");
+    goto error;
+  }
+
+  // Get the address of the struct hal_module_info.
+  hmi = (struct hw_module_t *)dlsym(handle, sym);
+  if (!hmi) {
+    HULOGERR("%s", sym);
+    goto error;
+  }
+
+  // Check that the id matches.
+  if (strcmp(id, hmi->id) != 0) {
+    HULOGERR("id=%s does not match HAL module ID: %s", id, hmi->id);
+    goto error;
+  }
+
+  hmi->dso = handle;
+
+  // Success.
+  LOG_INFO(
+      LOG_TAG, "[%s] loaded HAL id=%s path=%s hmi=%p handle=%p",
+      __func__, id, kBluetoothLibraryName, hmi, handle);
+
+  *module = hmi;
+  return 0;
+
+error:
+  *module = NULL;
+  if (handle)
+    dlclose(handle);
+
+  return -EINVAL;
+}
+
+#endif  // defined(OS_GENERIC)
+
+int hal_util_load_bt_library(const struct hw_module_t **module) {
+#if defined(OS_GENERIC)
+  return load_bt_library(module);
+#else  // !defined(OS_GENERIC)
+  return hw_get_module(BT_STACK_MODULE_ID, module);
+#endif  // defined(OS_GENERIC)
+}
diff --git a/bt/btcore/src/module.cc b/bt/btcore/src/module.cc
new file mode 100644
index 0000000..6a78a99
--- /dev/null
+++ b/bt/btcore/src/module.cc
@@ -0,0 +1,221 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_core_module"
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <pthread.h>
+#include <string.h>
+#include <unordered_map>
+
+#include "btcore/include/module.h"
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+typedef enum {
+  MODULE_STATE_NONE = 0,
+  MODULE_STATE_INITIALIZED = 1,
+  MODULE_STATE_STARTED = 2
+} module_state_t;
+
+static std::unordered_map<const module_t*, module_state_t> metadata;
+
+// Include this lock for now for correctness, while the startup sequence is being refactored
+static pthread_mutex_t metadata_lock;
+
+static bool call_lifecycle_function(module_lifecycle_fn function);
+static module_state_t get_module_state(const module_t *module);
+static void set_module_state(const module_t *module, module_state_t state);
+
+
+void module_management_start(void) {
+  pthread_mutex_init(&metadata_lock, NULL);
+}
+
+void module_management_stop(void) {
+  metadata.clear();
+
+  pthread_mutex_destroy(&metadata_lock);
+}
+
+const module_t *get_module(const char *name) {
+  module_t* module = (module_t *)dlsym(RTLD_DEFAULT, name);
+  assert(module);
+  return module;
+}
+
+bool module_init(const module_t *module) {
+  assert(module != NULL);
+  assert(get_module_state(module) == MODULE_STATE_NONE);
+
+  LOG_INFO(LOG_TAG, "%s Initializing module \"%s\"", __func__, module->name);
+  if (!call_lifecycle_function(module->init)) {
+    LOG_ERROR(LOG_TAG, "%s Failed to initialize module \"%s\"",
+              __func__, module->name);
+    return false;
+  }
+  LOG_INFO(LOG_TAG, "%s Initialized module \"%s\"", __func__, module->name);
+
+  set_module_state(module, MODULE_STATE_INITIALIZED);
+  return true;
+}
+
+bool module_start_up(const module_t *module) {
+  assert(module != NULL);
+  // TODO(zachoverflow): remove module->init check once automagic order/call is in place.
+  // This hack is here so modules which don't require init don't have to have useless calls
+  // as we're converting the startup sequence.
+  assert(get_module_state(module) == MODULE_STATE_INITIALIZED || module->init == NULL);
+
+  LOG_INFO(LOG_TAG, "%s Starting module \"%s\"", __func__, module->name);
+  if (!call_lifecycle_function(module->start_up)) {
+    LOG_ERROR(LOG_TAG, "%s Failed to start up module \"%s\"",
+              __func__, module->name);
+    return false;
+  }
+  LOG_INFO(LOG_TAG, "%s Started module \"%s\"", __func__, module->name);
+
+  set_module_state(module, MODULE_STATE_STARTED);
+  return true;
+}
+
+void module_shut_down(const module_t *module) {
+  assert(module != NULL);
+  module_state_t state = get_module_state(module);
+  assert(state <= MODULE_STATE_STARTED);
+
+  // Only something to do if the module was actually started
+  if (state < MODULE_STATE_STARTED)
+    return;
+
+  LOG_INFO(LOG_TAG, "%s Shutting down module \"%s\"", __func__, module->name);
+  if (!call_lifecycle_function(module->shut_down)) {
+    LOG_ERROR(LOG_TAG, "%s Failed to shutdown module \"%s\". Continuing anyway.",
+              __func__, module->name);
+  }
+  LOG_INFO(LOG_TAG, "%s Shutdown of module \"%s\" completed",
+           __func__, module->name);
+
+  set_module_state(module, MODULE_STATE_INITIALIZED);
+}
+
+void module_clean_up(const module_t *module) {
+  assert(module != NULL);
+  module_state_t state = get_module_state(module);
+  assert(state <= MODULE_STATE_INITIALIZED);
+
+  // Only something to do if the module was actually initialized
+  if (state < MODULE_STATE_INITIALIZED)
+    return;
+
+  LOG_INFO(LOG_TAG, "%s Cleaning up module \"%s\"", __func__, module->name);
+  if (!call_lifecycle_function(module->clean_up)) {
+    LOG_ERROR(LOG_TAG, "%s Failed to cleanup module \"%s\". Continuing anyway.",
+              __func__, module->name);
+  }
+  LOG_INFO(LOG_TAG, "%s Cleanup of module \"%s\" completed",
+           __func__, module->name);
+
+  set_module_state(module, MODULE_STATE_NONE);
+}
+
+static bool call_lifecycle_function(module_lifecycle_fn function) {
+  // A NULL lifecycle function means it isn't needed, so assume success
+  if (!function)
+    return true;
+
+  future_t *future = function();
+
+  // A NULL future means synchronous success
+  if (!future)
+    return true;
+
+  // Otherwise fall back to the future
+  return future_await(future);
+}
+
+static module_state_t get_module_state(const module_t *module) {
+  pthread_mutex_lock(&metadata_lock);
+  auto map_ptr = metadata.find(module);
+  pthread_mutex_unlock(&metadata_lock);
+
+  return (map_ptr != metadata.end()) ? map_ptr->second : MODULE_STATE_NONE;
+}
+
+static void set_module_state(const module_t *module, module_state_t state) {
+  pthread_mutex_lock(&metadata_lock);
+  metadata[module] = state;
+  pthread_mutex_unlock(&metadata_lock);
+}
+
+// TODO(zachoverflow): remove when everything modulized
+// Temporary callback-wrapper-related code
+
+typedef struct {
+  const module_t *module;
+  thread_t *lifecycle_thread;
+  thread_t *callback_thread; // we don't own this thread
+  thread_fn callback;
+  bool success;
+} callbacked_wrapper_t;
+
+static void run_wrapped_start_up(void *context);
+static void post_result_to_callback(void *context);
+
+void module_start_up_callbacked_wrapper(
+    const module_t *module,
+    thread_t *callback_thread,
+    thread_fn callback) {
+  callbacked_wrapper_t *wrapper = (callbacked_wrapper_t*)osi_calloc(sizeof(callbacked_wrapper_t));
+
+  wrapper->module = module;
+  wrapper->lifecycle_thread = thread_new("module_wrapper");
+  wrapper->callback_thread = callback_thread;
+  wrapper->callback = callback;
+
+  // Run the actual module start up
+  thread_post(wrapper->lifecycle_thread, run_wrapped_start_up, wrapper);
+}
+
+static void run_wrapped_start_up(void *context) {
+  assert(context);
+
+  callbacked_wrapper_t *wrapper = (callbacked_wrapper_t*)context;
+  wrapper->success = module_start_up(wrapper->module);
+
+  // Post the result back to the callback
+  thread_post(wrapper->callback_thread, post_result_to_callback, wrapper);
+}
+
+static void post_result_to_callback(void *context) {
+  assert(context);
+
+  callbacked_wrapper_t *wrapper = (callbacked_wrapper_t*)context;
+
+  // Save the values we need for callback
+  void *result = wrapper->success ? FUTURE_SUCCESS : FUTURE_FAIL;
+  thread_fn callback = wrapper->callback;
+
+  // Clean up the resources we used
+  thread_free(wrapper->lifecycle_thread);
+  osi_free(wrapper);
+
+  callback(result);
+}
diff --git a/bt/btcore/src/osi_module.cc b/bt/btcore/src/osi_module.cc
new file mode 100644
index 0000000..ff71446
--- /dev/null
+++ b/bt/btcore/src/osi_module.cc
@@ -0,0 +1,49 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_osi_module"
+
+#include "btcore/include/module.h"
+#include "btcore/include/osi_module.h"
+#include "osi/include/alarm.h"
+#include "osi/include/future.h"
+#include "osi/include/log.h"
+#include "osi/include/mutex.h"
+#include "osi/include/osi.h"
+#include "osi/include/wakelock.h"
+
+future_t *osi_init(void) {
+  mutex_init();
+  return future_new_immediate(FUTURE_SUCCESS);
+}
+
+future_t *osi_clean_up(void) {
+  alarm_cleanup();
+  wakelock_cleanup();
+  mutex_cleanup();
+  return future_new_immediate(FUTURE_SUCCESS);
+}
+
+EXPORT_SYMBOL extern const module_t osi_module = {
+  .name = OSI_MODULE,
+  .init = osi_init,
+  .start_up = NULL,
+  .shut_down = NULL,
+  .clean_up = osi_clean_up,
+  .dependencies = {NULL}
+};
diff --git a/bt/btcore/src/property.cc b/bt/btcore/src/property.cc
new file mode 100644
index 0000000..9d49daa
--- /dev/null
+++ b/bt/btcore/src/property.cc
@@ -0,0 +1,218 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <assert.h>
+#include <string.h>
+#include "btcore/include/bdaddr.h"
+#include "btcore/include/device_class.h"
+#include "btcore/include/property.h"
+#include "btcore/include/uuid.h"
+#include "osi/include/allocator.h"
+
+static bt_property_t *property_new_(void *val, size_t len, bt_property_type_t type);
+
+bt_property_t *property_copy_array(const bt_property_t *properties, size_t count) {
+  assert(properties != NULL);
+  bt_property_t *clone = static_cast<bt_property_t *>(osi_calloc(sizeof(bt_property_t) * count));
+
+  memcpy(&clone[0], &properties[0], sizeof(bt_property_t) * count);
+  for (size_t i = 0; i < count; ++i) {
+    clone[i].val = osi_calloc(clone[i].len);
+    memcpy(clone[i].val, properties[i].val, clone[i].len);
+  }
+
+  return clone;
+}
+
+bt_property_t *property_copy(bt_property_t *dest, const bt_property_t *src) {
+  assert(dest != NULL);
+  assert(src != NULL);
+  return (bt_property_t *)memcpy(dest, src, sizeof(bt_property_t));
+}
+
+bool property_equals(const bt_property_t *p1, const bt_property_t *p2) {
+  // Two null properties are not the same. May need to revisit that
+  // decision when we have a test case that exercises that condition.
+  if (!p1 || !p2 || p1->type != p2->type) {
+    return false;
+  }
+
+  // Although the Bluetooth name is a 249-byte array, the implementation
+  // treats it like a variable-length array with its size specified in the
+  // property's `len` field. We special-case the equivalence of BDNAME
+  // types here by truncating the larger, zero-padded name to its string
+  // length and comparing against the shorter name.
+  //
+  // Note: it may be the case that both strings are zero-padded but that
+  // hasn't come up yet so this implementation doesn't handle it.
+  if (p1->type == BT_PROPERTY_BDNAME && p1->len != p2->len) {
+    const bt_property_t *shorter = p1, *longer = p2;
+    if (p1->len > p2->len) {
+      shorter = p2;
+      longer = p1;
+    }
+    return strlen((const char *)longer->val) == (size_t)shorter->len && !memcmp(longer->val, shorter->val, shorter->len);
+  }
+
+  return p1->len == p2->len && !memcmp(p1->val, p2->val, p1->len);
+}
+
+bt_property_t *property_new_addr(const bt_bdaddr_t *addr) {
+  assert(addr != NULL);
+  return property_new_((void *)addr, sizeof(bt_bdaddr_t), BT_PROPERTY_BDADDR);
+}
+
+bt_property_t *property_new_device_class(const bt_device_class_t *dc) {
+  assert(dc != NULL);
+  return property_new_((void *)dc, sizeof(bt_device_class_t), BT_PROPERTY_CLASS_OF_DEVICE);
+}
+
+bt_property_t *property_new_device_type(bt_device_type_t type) {
+  return property_new_((void *)&type, sizeof(bt_device_type_t), BT_PROPERTY_TYPE_OF_DEVICE);
+}
+
+bt_property_t *property_new_discovery_timeout(const uint32_t timeout) {
+  return property_new_((void *)&timeout, sizeof(uint32_t), BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT);
+}
+
+bt_property_t *property_new_name(const char *name) {
+  assert(name != NULL);
+  return property_new_((void *)name, sizeof(bt_bdname_t), BT_PROPERTY_BDNAME);
+}
+
+bt_property_t *property_new_rssi(int8_t rssi) {
+  return property_new_((void *)&rssi, sizeof(int8_t), BT_PROPERTY_REMOTE_RSSI);
+}
+
+bt_property_t *property_new_scan_mode(bt_scan_mode_t scan_mode) {
+  return property_new_((void *)&scan_mode, sizeof(bt_scan_mode_t), BT_PROPERTY_ADAPTER_SCAN_MODE);
+}
+
+bt_property_t *property_new_uuids(const bt_uuid_t *uuid, size_t count) {
+  assert(uuid != NULL);
+  return property_new_((void *)uuid, sizeof(bt_uuid_t) * count, BT_PROPERTY_UUIDS);
+}
+
+void property_free(bt_property_t *property) {
+  property_free_array(property, 1);
+}
+
+void property_free_array(bt_property_t *properties, size_t count) {
+  if (properties == NULL)
+    return;
+
+  for (size_t i = 0; i < count; ++i) {
+    osi_free(properties[i].val);
+  }
+
+  osi_free(properties);
+}
+
+bool property_is_addr(const bt_property_t *property) {
+  assert(property != NULL);
+  return property->type == BT_PROPERTY_BDADDR;
+}
+
+bool property_is_device_class(const bt_property_t *property) {
+  assert(property != NULL);
+  return property->type == BT_PROPERTY_CLASS_OF_DEVICE;
+}
+
+bool property_is_device_type(const bt_property_t *property) {
+  assert(property != NULL);
+  return property->type == BT_PROPERTY_TYPE_OF_DEVICE;
+}
+
+bool property_is_discovery_timeout(const bt_property_t *property) {
+  assert(property != NULL);
+  return property->type == BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT;
+}
+
+bool property_is_name(const bt_property_t *property) {
+  assert(property != NULL);
+  return property->type == BT_PROPERTY_BDNAME;
+}
+
+bool property_is_rssi(const bt_property_t *property) {
+  assert(property != NULL);
+  return property->type == BT_PROPERTY_REMOTE_RSSI;
+}
+
+bool property_is_scan_mode(const bt_property_t *property) {
+  assert(property != NULL);
+  return property->type == BT_PROPERTY_ADAPTER_SCAN_MODE;
+}
+
+bool property_is_uuids(const bt_property_t *property) {
+  assert(property != NULL);
+  return property->type == BT_PROPERTY_UUIDS;
+}
+
+// Convenience conversion methods to property values
+const bt_bdaddr_t *property_as_addr(const bt_property_t *property) {
+  assert(property_is_addr(property));
+  return (const bt_bdaddr_t *)property->val;
+}
+
+const bt_device_class_t *property_as_device_class(const bt_property_t *property) {
+  assert(property_is_device_class(property));
+  return (const bt_device_class_t *)property->val;
+}
+
+bt_device_type_t property_as_device_type(const bt_property_t *property) {
+  assert(property_is_device_type(property));
+  return *(const bt_device_type_t *)property->val;
+}
+
+uint32_t property_as_discovery_timeout(const bt_property_t *property) {
+  assert(property_is_discovery_timeout(property));
+  return *(const uint32_t *)property->val;
+}
+
+const bt_bdname_t *property_as_name(const bt_property_t *property) {
+  assert(property_is_name(property));
+  return (const bt_bdname_t *)property->val;
+}
+
+int8_t property_as_rssi(const bt_property_t *property) {
+  assert(property_is_rssi(property));
+  return *(const int8_t *)property->val;
+}
+
+bt_scan_mode_t property_as_scan_mode(const bt_property_t *property) {
+  assert(property_is_scan_mode(property));
+  return *(const bt_scan_mode_t *)property->val;
+}
+
+const bt_uuid_t *property_as_uuids(const bt_property_t *property, size_t *count) {
+  assert(property_is_uuids(property));
+  *count = sizeof(bt_uuid_t) / property->len;
+  return (const bt_uuid_t *)property->val;
+}
+
+static bt_property_t *property_new_(void *val, size_t len, bt_property_type_t type) {
+  bt_property_t *property = static_cast<bt_property_t *>(osi_calloc(sizeof(bt_property_t)));
+
+  property->val = osi_malloc(len);
+  memcpy(property->val, val, len);
+
+  property->type = type;
+  property->len = len;
+
+  return property;
+}
diff --git a/bt/btcore/src/uuid.cc b/bt/btcore/src/uuid.cc
new file mode 100644
index 0000000..78a2904
--- /dev/null
+++ b/bt/btcore/src/uuid.cc
@@ -0,0 +1,170 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "btcore/include/uuid.h"
+#include "osi/include/allocator.h"
+
+static const size_t UUID_WELL_FORMED_STRING_LEN = 36;
+static const size_t UUID_WELL_FORMED_STRING_LEN_WITH_NULL = 36 + 1;
+
+typedef struct uuid_string_t {
+  char string[0];
+} uuid_string_t;
+
+static const bt_uuid_t empty_uuid = {{ 0 }};
+
+// The base UUID is used for calculating 128-bit UUIDs from 16 and
+// 32 bit UUIDs as described in the SDP specification.
+static const bt_uuid_t base_uuid = {
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+    0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb, }};
+
+static bool uuid_is_base(const bt_uuid_t *uuid);
+
+uuid_string_t *uuid_string_new(void) {
+  return static_cast<uuid_string_t *>(osi_calloc(UUID_WELL_FORMED_STRING_LEN_WITH_NULL));
+}
+
+void uuid_string_free(uuid_string_t *uuid_string) {
+  osi_free(uuid_string);
+}
+
+const char *uuid_string_data(const uuid_string_t *uuid_string) {
+  assert(uuid_string != NULL);
+  return (const char *)uuid_string->string;
+}
+
+bt_uuid_t *uuid_new(const char *uuid_string) {
+  assert(uuid_string != NULL);
+
+  if (strlen(uuid_string) < UUID_WELL_FORMED_STRING_LEN)
+    return NULL;
+  if (uuid_string[8] != '-' || uuid_string[13] != '-' || uuid_string[18] != '-' || uuid_string[23] != '-')
+    return NULL;
+
+  bt_uuid_t *uuid = static_cast<bt_uuid_t *>(osi_calloc(sizeof(bt_uuid_t)));
+
+  const char *s = uuid_string;
+  for (size_t i = 0; i < sizeof(bt_uuid_t); ++i, s+=2) {
+    char buf[3] = {0};
+    buf[0] = s[0];
+    buf[1] = s[1];
+    uuid->uu[i] = strtoul(buf, NULL, 16);
+    // Adjust by skipping the dashes
+    switch(i) {
+      case 3:
+      case 5:
+      case 7:
+      case 9:
+        s++;
+        break;
+    }
+  }
+  return uuid;
+}
+
+void uuid_free(bt_uuid_t *uuid) {
+  osi_free(uuid);
+}
+
+bool uuid_is_empty(const bt_uuid_t *uuid) {
+  return !uuid || !memcmp(uuid, &empty_uuid, sizeof(bt_uuid_t));
+}
+
+bool uuid_is_equal(const bt_uuid_t *first, const bt_uuid_t *second) {
+  assert(first != NULL);
+  assert(second != NULL);
+  return !memcmp(first, second, sizeof(bt_uuid_t));
+}
+
+bt_uuid_t *uuid_copy(bt_uuid_t *dest, const bt_uuid_t *src) {
+  assert(dest != NULL);
+  assert(src != NULL);
+  return (bt_uuid_t *)memcpy(dest, src, sizeof(bt_uuid_t));
+}
+
+bool uuid_128_to_16(const bt_uuid_t *uuid, uint16_t *uuid16) {
+  assert(uuid != NULL);
+  assert(uuid16 != NULL);
+
+  if (!uuid_is_base(uuid))
+    return false;
+
+  *uuid16 = (uuid->uu[2] << 8) + uuid->uu[3];
+  return true;
+}
+
+bool uuid_128_to_32(const bt_uuid_t *uuid, uint32_t *uuid32) {
+  assert(uuid != NULL);
+  assert(uuid32 != NULL);
+
+  if (!uuid_is_base(uuid))
+    return false;
+
+  *uuid32 = (uuid->uu[0] << 24) + (uuid->uu[1] << 16) + (uuid->uu[2] << 8) + uuid->uu[3];
+  return true;
+}
+
+void uuid_to_string(const bt_uuid_t *uuid, uuid_string_t *uuid_string) {
+  assert(uuid != NULL);
+  assert(uuid_string != NULL);
+
+  char *string = uuid_string->string;
+  char *end = string + UUID_WELL_FORMED_STRING_LEN_WITH_NULL;
+
+  // XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX
+  for (int i = 0; i < 4; i++) {
+    string += snprintf(string, end - string, "%02x", uuid->uu[i]);
+  }
+  *string = '-';
+  ++string;
+  for (int i = 4; i < 6; i++) {
+    string += snprintf(string, end - string, "%02x", uuid->uu[i]);
+  }
+  *string = '-';
+  ++string;
+  for (int i = 6; i < 8; i++) {
+    string += snprintf(string, end - string, "%02x", uuid->uu[i]);
+  }
+  *string = '-';
+  ++string;
+  for (int i = 8; i < 10; i++) {
+    string += snprintf(string, end - string, "%02x", uuid->uu[i]);
+  }
+  *string = '-';
+  ++string;
+  for (int i = 10; i < 16; i++) {
+    string += snprintf(string, end - string, "%02x", uuid->uu[i]);
+  }
+}
+
+static bool uuid_is_base(const bt_uuid_t *uuid) {
+  if (!uuid)
+    return false;
+
+  for (int i = 4; i < 16; i++) {
+    if (uuid->uu[i] != base_uuid.uu[i])
+      return false;
+  }
+  return true;
+}
diff --git a/bt/btcore/test/bdaddr_test.cc b/bt/btcore/test/bdaddr_test.cc
new file mode 100644
index 0000000..0439c79
--- /dev/null
+++ b/bt/btcore/test/bdaddr_test.cc
@@ -0,0 +1,73 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "btcore/include/bdaddr.h"
+
+static const char* test_addr = "12:34:56:78:9a:bc";
+static const char* test_addr2 = "cb:a9:87:65:43:21";
+
+
+TEST(BdaddrTest, test_empty) {
+  bt_bdaddr_t empty;
+  string_to_bdaddr("00:00:00:00:00:00", &empty);
+  ASSERT_TRUE(bdaddr_is_empty(&empty));
+
+  bt_bdaddr_t not_empty;
+  string_to_bdaddr("00:00:00:00:00:01", &not_empty);
+  ASSERT_FALSE(bdaddr_is_empty(&not_empty));
+}
+
+TEST(BdaddrTest, test_to_from_str) {
+  char ret[19];
+  bt_bdaddr_t bdaddr;
+  string_to_bdaddr(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]);
+
+  bdaddr_to_string(&bdaddr, ret, sizeof(ret));
+
+  ASSERT_STREQ(test_addr, ret);
+}
+
+TEST(BdaddrTest, test_equals) {
+  bt_bdaddr_t bdaddr1;
+  bt_bdaddr_t bdaddr2;
+  bt_bdaddr_t bdaddr3;
+  string_to_bdaddr(test_addr, &bdaddr1);
+  string_to_bdaddr(test_addr, &bdaddr2);
+  EXPECT_TRUE(bdaddr_equals(&bdaddr1, &bdaddr2));
+
+  string_to_bdaddr(test_addr2, &bdaddr3);
+  EXPECT_FALSE(bdaddr_equals(&bdaddr2, &bdaddr3));
+}
+
+TEST(BdaddrTest, test_copy) {
+  bt_bdaddr_t bdaddr1;
+  bt_bdaddr_t bdaddr2;
+  string_to_bdaddr(test_addr, &bdaddr1);
+  bdaddr_copy(&bdaddr2, &bdaddr1);
+
+  EXPECT_TRUE(bdaddr_equals(&bdaddr1, &bdaddr2));
+}
diff --git a/bt/btcore/test/device_class_test.cc b/bt/btcore/test/device_class_test.cc
new file mode 100644
index 0000000..af9ed79
--- /dev/null
+++ b/bt/btcore/test/device_class_test.cc
@@ -0,0 +1,218 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <arpa/inet.h>
+#include <gtest/gtest.h>
+#include "osi/test/AllocationTestHarness.h"
+
+#include "btcore/include/device_class.h"
+
+// Device Class is 3 bytes.
+static const int DC_MASK = 0xffffff;
+
+::testing::AssertionResult check_bitfield(const char *m_expr,
+    const char *n_expr, int m, int n) {
+  if (m == n)
+    return ::testing::AssertionSuccess();
+
+  std::stringstream ss;
+
+  ss.str("");
+  ss << std::showbase << std::hex << std::setw(8) << std::setfill('0') << m;
+  std::string expected_str = ss.str();
+
+  ss.str("");
+  ss << std::showbase << std::hex << std::setw(8) << std::setfill('0') << n;
+  std::string actual_str = ss.str();
+
+  return ::testing::AssertionFailure() << m_expr << " and " << n_expr
+    << " ( " << expected_str << " vs " << actual_str << " )";
+}
+
+class DeviceClassTest : public AllocationTestHarness {};
+
+TEST_F(DeviceClassTest, cod_sizeof) {
+  uint8_t dc_stream[] = { 0x00, 0x00, 0x00, 0x00};
+  bt_device_class_t dc0;
+  device_class_from_stream(&dc0, dc_stream);
+  EXPECT_EQ((size_t)3, sizeof(dc0));
+}
+
+TEST_F(DeviceClassTest, simple) {
+  uint8_t dc_stream[][sizeof(bt_device_class_t)] = {
+    { 0x00, 0x00, 0x00 },
+    { 0xff, 0xff, 0xff },
+    { 0xaa, 0x55, 0xaa },
+    { 0x01, 0x23, 0x45 },
+    { 0x20, 0x07, 0x14 },
+  };
+
+  for (size_t i = 0; i < sizeof(dc_stream)/sizeof(bt_device_class_t); i++) {
+    bt_device_class_t dc;
+    device_class_from_stream(&dc, (uint8_t*)&dc_stream[i]);
+
+    uint8_t *to_stream = (uint8_t *)&dc;
+    EXPECT_PRED_FORMAT2(check_bitfield, (unsigned)dc_stream[i][0], to_stream[0]);
+    EXPECT_PRED_FORMAT2(check_bitfield, (unsigned)dc_stream[i][1], to_stream[1]);
+    EXPECT_PRED_FORMAT2(check_bitfield, (unsigned)dc_stream[i][2], to_stream[2]);
+  }
+}
+
+TEST_F(DeviceClassTest, to_stream) {
+  {
+    bt_device_class_t dc;
+
+    uint8_t dc_stream0[] = { 0x00, 0x00, 0x00, 0xaa };
+    device_class_from_stream(&dc, dc_stream0);
+
+    uint8_t dc_stream1[] = { 0x00, 0x00, 0x00, 0x00 };
+    int rc = device_class_to_stream(&dc, dc_stream1, sizeof(dc_stream1));
+    EXPECT_EQ(3, rc);
+
+    uint32_t *val = (uint32_t *)&dc;
+    EXPECT_PRED_FORMAT2(check_bitfield, 0x00000000, *val & 0xffffff);
+
+    EXPECT_PRED_FORMAT2(check_bitfield, 0x00, dc_stream1[0]);
+    EXPECT_PRED_FORMAT2(check_bitfield, 0x00, dc_stream1[1]);
+    EXPECT_PRED_FORMAT2(check_bitfield, 0x00, dc_stream1[2]);
+  }
+
+  {
+    uint8_t dc_stream0[] = { 0xaa, 0x55, 0xaa, 0x55 };
+    uint8_t dc_stream1[] = { 0x00, 0x00, 0x00, 0x00 };
+
+    bt_device_class_t dc;
+    device_class_from_stream(&dc, dc_stream0);
+
+    int rc = device_class_to_stream(&dc, dc_stream1, sizeof(dc_stream1));
+    EXPECT_EQ(3, rc);
+    uint32_t *val = (uint32_t *)&dc;
+    EXPECT_PRED_FORMAT2(check_bitfield, 0x00aa55aa, *val & 0xffffff);
+
+    EXPECT_PRED_FORMAT2(check_bitfield, 0xaa, dc_stream1[0]);
+    EXPECT_PRED_FORMAT2(check_bitfield, 0x55, dc_stream1[1]);
+    EXPECT_PRED_FORMAT2(check_bitfield, 0xaa, dc_stream1[2]);
+  }
+
+  {
+    uint8_t dc_stream0[] = { 0x01, 0x23, 0x45, 0x67 };
+    uint8_t dc_stream1[] = { 0x00, 0x00, 0x00, 0x00 };
+
+    bt_device_class_t dc;
+    device_class_from_stream(&dc, dc_stream0);
+
+    int rc = device_class_to_stream(&dc, dc_stream1, sizeof(dc_stream1));
+    EXPECT_EQ(3, rc);
+    uint32_t *val = (uint32_t *)&dc;
+    EXPECT_PRED_FORMAT2(check_bitfield, 0x452301, *val & 0xffffff);
+
+    EXPECT_PRED_FORMAT2(check_bitfield, 0x01, dc_stream1[0]);
+    EXPECT_PRED_FORMAT2(check_bitfield, 0x23, dc_stream1[1]);
+    EXPECT_PRED_FORMAT2(check_bitfield, 0x45, dc_stream1[2]);
+  }
+}
+
+TEST_F(DeviceClassTest, limited_discoverable_mode) {
+  uint8_t dc_stream[] = { 0x00, 0x00, 0x00 };
+  bt_device_class_t dc;
+  device_class_from_stream(&dc, dc_stream);
+  uint32_t *test = (uint32_t *)&dc;
+
+  EXPECT_FALSE(device_class_get_limited(&dc));
+  EXPECT_EQ((unsigned)0x00000000, *test & DC_MASK);
+
+  device_class_set_limited(&dc, true);
+  EXPECT_TRUE(device_class_get_limited(&dc));
+  EXPECT_EQ((unsigned)0x00002000, *test & DC_MASK);
+
+  device_class_set_limited(&dc, false);
+  EXPECT_FALSE(device_class_get_limited(&dc));
+  EXPECT_EQ((unsigned)0x00000000, *test & DC_MASK);
+
+  device_class_set_limited(&dc, true);
+  EXPECT_PRED_FORMAT2(check_bitfield, 0x00002000, *test & DC_MASK);
+
+  device_class_set_limited(&dc, false);
+  EXPECT_PRED_FORMAT2(check_bitfield, 0x00000000, *test & DC_MASK);
+}
+
+TEST_F(DeviceClassTest, equals) {
+  uint8_t dc_stream0[] = { 0x00, 0x01, 0x02 };
+  uint8_t dc_stream1[] = { 0x00, 0x02, 0x03 };
+
+  bt_device_class_t dc0;
+  device_class_from_stream(&dc0, dc_stream0);
+  bt_device_class_t dc1;
+  device_class_from_stream(&dc1, dc_stream1);
+  EXPECT_FALSE(device_class_equals(&dc0, &dc1));
+}
+
+TEST_F(DeviceClassTest, copy) {
+  uint8_t dc_stream0[] = { 0xaa, 0x55, 0x33 };
+  bt_device_class_t dc0;
+  device_class_from_stream(&dc0, dc_stream0);
+  bt_device_class_t dc1;
+  EXPECT_TRUE(device_class_copy(&dc1, &dc0));
+  EXPECT_TRUE(device_class_equals(&dc0, &dc1));
+}
+
+TEST_F(DeviceClassTest, from_int) {
+  bt_device_class_t dc1;
+  int cod1 = 0x5a020c;  // 5898764
+  device_class_from_int(&dc1, cod1);
+
+  uint8_t dc_stream[] = { 0x0c, 0x02, 0x5a };
+  bt_device_class_t dc2;
+  device_class_from_stream(&dc2, dc_stream);
+  EXPECT_TRUE(device_class_equals(&dc1, &dc2));
+}
+
+TEST_F(DeviceClassTest, to_int) {
+  bt_device_class_t dc1 = {{ 0x0c, 0x02, 0x5a }};
+  int cod1 = device_class_to_int(&dc1);
+
+  EXPECT_EQ(dc1._[0], 0x0c);
+  EXPECT_EQ(dc1._[1], 0x02);
+  EXPECT_EQ(dc1._[2], 0x5a);
+
+  bt_device_class_t dc2;
+  uint8_t dc_stream[] = { 0x0c, 0x02, 0x5a };
+  device_class_from_stream(&dc2, dc_stream);
+
+  EXPECT_EQ(dc2._[0], 0x0c);
+  EXPECT_EQ(dc2._[1], 0x02);
+  EXPECT_EQ(dc2._[2], 0x5a);
+
+  int cod2 = device_class_to_int(&dc2);
+  EXPECT_EQ(cod1, cod2);
+  EXPECT_EQ(cod1, 0x5a020c);  // 5898764
+}
+
+TEST_F(DeviceClassTest, endian) {
+  bt_device_class_t dc;
+  int cod1 = 0x200714;  // 2098964
+  device_class_from_int(&dc, cod1);
+
+  EXPECT_EQ(dc._[0], 0x14);
+  EXPECT_EQ(dc._[1], 0x07);
+  EXPECT_EQ(dc._[2], 0x20);
+
+  int cod2 = device_class_to_int(&dc);
+  EXPECT_EQ(cod1, cod2);
+  EXPECT_EQ(cod2, 0x200714); // 2098964
+}
diff --git a/bt/btcore/test/property_test.cc b/bt/btcore/test/property_test.cc
new file mode 100644
index 0000000..649be35
--- /dev/null
+++ b/bt/btcore/test/property_test.cc
@@ -0,0 +1,245 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <arpa/inet.h>
+#include <gtest/gtest.h>
+#include "osi/test/AllocationTestHarness.h"
+
+#include "btcore/include/property.h"
+
+class PropertyTest : public AllocationTestHarness {};
+
+TEST_F(PropertyTest, addr) {
+  bt_bdaddr_t addr0 = {{0x1, 0x2, 0x3, 0x4, 0x5, 0x6}};
+  bt_property_t *property = property_new_addr(&addr0);
+
+  EXPECT_EQ(addr0.address[0], ((uint8_t*)property->val)[0]);
+  EXPECT_EQ(addr0.address[1], ((uint8_t*)property->val)[1]);
+  EXPECT_EQ(addr0.address[2], ((uint8_t*)property->val)[2]);
+  EXPECT_EQ(addr0.address[3], ((uint8_t*)property->val)[3]);
+  EXPECT_EQ(addr0.address[4], ((uint8_t*)property->val)[4]);
+  EXPECT_EQ(addr0.address[5], ((uint8_t*)property->val)[5]);
+  EXPECT_EQ(BT_PROPERTY_BDADDR, property->type);
+  EXPECT_EQ((int)sizeof(bt_bdaddr_t), property->len);
+
+  const bt_bdaddr_t *addr1 = property_as_addr(property);
+  EXPECT_EQ(addr0.address[0], addr1->address[0]);
+
+  property_free(property);
+}
+
+TEST_F(PropertyTest, device_class) {
+  bt_device_class_t dc0 = {{ 0x01, 0x23, 0x45 }};
+  bt_property_t *property = property_new_device_class(&dc0);
+
+  EXPECT_EQ(dc0._[0], ((uint8_t*)property->val)[0]);
+  EXPECT_EQ(dc0._[1], ((uint8_t*)property->val)[1]);
+  EXPECT_EQ(dc0._[2], ((uint8_t*)property->val)[2]);
+  EXPECT_EQ(BT_PROPERTY_CLASS_OF_DEVICE, property->type);
+  EXPECT_EQ((int)sizeof(bt_device_class_t), property->len);
+
+  const bt_device_class_t *dc1 = property_as_device_class(property);
+  int dc_int = device_class_to_int(dc1);
+  EXPECT_EQ(0x452301, dc_int);
+
+  property_free(property);
+}
+
+TEST_F(PropertyTest, device_type) {
+  bt_device_type_t dt0 = (bt_device_type_t)1;
+  bt_property_t *property = property_new_device_type(dt0);
+
+  EXPECT_EQ((int)dt0, *(int*)property->val);
+  EXPECT_EQ(BT_PROPERTY_TYPE_OF_DEVICE, property->type);
+  EXPECT_EQ((int)sizeof(bt_device_type_t), property->len);
+
+  bt_device_type_t dt1 = property_as_device_type(property);
+  EXPECT_EQ(1, (int)dt1);
+
+  property_free(property);
+}
+
+TEST_F(PropertyTest, discovery_timeout) {
+  uint32_t timeout0 = 12345;
+  bt_property_t *property = property_new_discovery_timeout(timeout0);
+
+  EXPECT_EQ(timeout0, *(uint32_t *)property->val);
+  EXPECT_EQ(BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT, property->type);
+  EXPECT_EQ((int)sizeof(uint32_t), property->len);
+
+  uint32_t timeout1 = property_as_discovery_timeout(property);
+  EXPECT_EQ(timeout0, timeout1);
+
+  property_free(property);
+}
+
+TEST_F(PropertyTest, name) {
+  const char *name0 = "My btcore name";
+  bt_property_t *property = property_new_name(name0);
+
+  EXPECT_EQ(0, strcmp((char *)name0, (char *)property->val));
+  EXPECT_EQ(BT_PROPERTY_BDNAME, property->type);
+  EXPECT_EQ((int)sizeof(bt_bdname_t), property->len);
+
+  const bt_bdname_t *name1 = property_as_name(property);
+  EXPECT_EQ(0, strcmp((char *)name0, (char *)name1->name));
+
+  property_free(property);
+}
+
+TEST_F(PropertyTest, rssi) {
+  int8_t rssi0 = -56;
+  bt_property_t *property = property_new_rssi(rssi0);
+
+  EXPECT_EQ(*(int8_t *)property->val, rssi0);
+  EXPECT_EQ(BT_PROPERTY_REMOTE_RSSI, property->type);
+  EXPECT_EQ((int)sizeof(int8_t), property->len);
+
+  int8_t rss1 = property_as_rssi(property);
+  EXPECT_EQ(rssi0, rss1);
+
+  property_free(property);
+}
+
+TEST_F(PropertyTest, scan_mode) {
+  bt_scan_mode_t mode0 = (bt_scan_mode_t)3;
+  bt_property_t *property = property_new_scan_mode(mode0);
+
+  EXPECT_EQ(*(int *)property->val, mode0);
+  EXPECT_EQ(BT_PROPERTY_ADAPTER_SCAN_MODE, property->type);
+  EXPECT_EQ((int)sizeof(int), property->len);
+
+  bt_scan_mode_t mode1 = property_as_scan_mode(property);
+  EXPECT_EQ((int)mode0, (int)mode1);
+
+  property_free(property);
+}
+
+TEST_F(PropertyTest, uuids) {
+  bt_uuid_t uuid0 = {
+    {
+      0x00, 0x11, 0x22, 0x33,
+      0x44, 0x55, 0x66, 0x77,
+      0x88, 0x99, 0xaa, 0xbb,
+      0xcc, 0xdd, 0xee, 0xff,
+    }
+  };
+  bt_property_t *property = property_new_uuids(&uuid0, 1);
+
+  EXPECT_EQ(0, strcmp((const char *)uuid0.uu, (char *)property->val));
+  EXPECT_EQ(BT_PROPERTY_UUIDS, property->type);
+  EXPECT_EQ((int)sizeof(bt_uuid_t), property->len);
+
+  size_t uuid_cnt1;
+  const bt_uuid_t *uuid1 = property_as_uuids(property, &uuid_cnt1);
+  EXPECT_EQ(0, memcmp(uuid1->uu, uuid1->uu, sizeof(bt_uuid_t)));
+
+  property_free(property);
+}
+
+TEST_F(PropertyTest, copy) {
+  {
+    bt_uuid_t uuids[] = {
+      {{
+         0x00, 0x11, 0x22, 0x33,
+         0x44, 0x55, 0x66, 0x77,
+         0x88, 0x99, 0xaa, 0xbb,
+         0xcc, 0xdd, 0xee, 0xff,
+       }},
+      {{
+         0xf0, 0xe1, 0xd2, 0xc3,
+         0xf4, 0xe5, 0xd6, 0xc7,
+         0xf8, 0xe9, 0xda, 0xcb,
+         0xfc, 0xed, 0xde, 0xcf,
+       }},
+    };
+
+    bt_property_t *property0 = property_new_uuids(uuids, sizeof(bt_uuid_t)/sizeof(uuids));
+
+    bt_property_t property1;
+    property_copy(&property1, property0);
+    EXPECT_TRUE(property_equals(property0, &property1));
+
+    property_free(property0);
+  }
+}
+
+TEST_F(PropertyTest, equals) {
+  {
+    bt_bdaddr_t addr0 = {{0x1, 0x2, 0x3, 0x4, 0x5, 0x6}};
+    bt_property_t *property0 = property_new_addr(&addr0);
+
+    bt_device_class_t dc0 = {{ 0x01, 0x23, 0x45 }};
+    bt_property_t *property1 = property_new_device_class(&dc0);
+
+    EXPECT_FALSE(property_equals(property0, property1));
+
+    property_free(property0);
+    property_free(property1);
+  }
+
+  {
+    bt_bdaddr_t addr = {{0x1, 0x2, 0x3, 0x4, 0x5, 0x6}};
+    bt_property_t *property0 = property_new_addr(&addr);
+    bt_property_t *property1 = property_new_addr(&addr);
+
+    EXPECT_TRUE(property_equals(property0, property1));
+
+    property_free(property0);
+    property_free(property1);
+  }
+
+  {
+    bt_bdaddr_t addr0 = {{0x1, 0x2, 0x3, 0x4, 0x5, 0x6}};
+    bt_property_t *property0 = property_new_addr(&addr0);
+
+    bt_bdaddr_t addr1 = {{0x1, 0x2, 0x3, 0x4, 0x5, 0xff}};
+    bt_property_t *property1 = property_new_addr(&addr1);
+
+    EXPECT_FALSE(property_equals(property0, property1));
+
+    property_free(property0);
+    property_free(property1);
+  }
+
+  {
+    const char *name0 = "My btcore name";
+    bt_property_t *property0 = property_new_name(name0);
+
+    const char *name1 = "My btcore name";
+    bt_property_t *property1 = property_new_name(name1);
+
+    EXPECT_TRUE(property_equals(property0, property1));
+
+    property_free(property0);
+    property_free(property1);
+  }
+
+  {
+    const char *name0 = "My btcore name";
+    bt_property_t *property0 = property_new_name(name0);
+
+    const char *name1 = "My btcore name     ";
+    bt_property_t *property1 = property_new_name(name1);
+
+    EXPECT_FALSE(property_equals(property0, property1));
+
+    property_free(property0);
+    property_free(property1);
+  }
+}
diff --git a/bt/btcore/test/uuid_test.cc b/bt/btcore/test/uuid_test.cc
new file mode 100644
index 0000000..a20cc1c
--- /dev/null
+++ b/bt/btcore/test/uuid_test.cc
@@ -0,0 +1,164 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "osi/test/AllocationTestHarness.h"
+
+#include "btcore/include/uuid.h"
+
+static const char *UUID_EMPTY = "00000000-0000-0000-0000-000000000000";
+static const char *UUID_ONES = "11111111-1111-1111-1111-111111111111";
+static const char *UUID_SEQUENTIAL = "01234567-89ab-cdef-ABCD-EF0123456789";
+static const char *UUID_BASE = "00000000-0000-1000-8000-00805f9b34fb";
+
+class UuidTest : public AllocationTestHarness {
+  protected:
+    virtual void SetUp() {
+    }
+
+    virtual void TearDown() {
+    }
+};
+
+TEST_F(UuidTest, new_from_string) {
+  bt_uuid_t *uuid;
+
+  uuid = uuid_new("incorrect length");
+  EXPECT_EQ(NULL, uuid);
+
+  uuid = uuid_new("correct length but missing dashes --");
+  EXPECT_EQ(NULL, uuid);
+
+  uuid = uuid_new(UUID_ONES);
+  ASSERT_TRUE(uuid != NULL);
+  for (int i = 0; i < 16; i++) {
+    EXPECT_EQ(0x11, uuid->uu[i]);
+  }
+  uuid_free(uuid);
+
+  uuid = uuid_new(UUID_SEQUENTIAL);
+  EXPECT_EQ(0x01, uuid->uu[0]);
+  EXPECT_EQ(0x23, uuid->uu[1]);
+  EXPECT_EQ(0x45, uuid->uu[2]);
+  EXPECT_EQ(0x67, uuid->uu[3]);
+  EXPECT_EQ(0x89, uuid->uu[4]);
+  EXPECT_EQ(0xAB, uuid->uu[5]);
+  EXPECT_EQ(0xCD, uuid->uu[6]);
+  EXPECT_EQ(0xEF, uuid->uu[7]);
+  EXPECT_EQ(0xab, uuid->uu[8]);
+  EXPECT_EQ(0xcd, uuid->uu[9]);
+  EXPECT_EQ(0xef, uuid->uu[10]);
+  EXPECT_EQ(0x01, uuid->uu[11]);
+  EXPECT_EQ(0x23, uuid->uu[12]);
+  EXPECT_EQ(0x45, uuid->uu[13]);
+  EXPECT_EQ(0x67, uuid->uu[14]);
+  EXPECT_EQ(0x89, uuid->uu[15]);
+  uuid_free(uuid);
+
+  uuid = uuid_new(UUID_BASE);
+  EXPECT_EQ(0x00, uuid->uu[0]);
+  EXPECT_EQ(0x00, uuid->uu[1]);
+  EXPECT_EQ(0x00, uuid->uu[2]);
+  EXPECT_EQ(0x00, uuid->uu[3]);
+  EXPECT_EQ(0x00, uuid->uu[4]);
+  EXPECT_EQ(0x00, uuid->uu[5]);
+  EXPECT_EQ(0x10, uuid->uu[6]);
+  EXPECT_EQ(0x00, uuid->uu[7]);
+  EXPECT_EQ(0x80, uuid->uu[8]);
+  EXPECT_EQ(0x00, uuid->uu[9]);
+  EXPECT_EQ(0x00, uuid->uu[10]);
+  EXPECT_EQ(0x80, uuid->uu[11]);
+  EXPECT_EQ(0x5f, uuid->uu[12]);
+  EXPECT_EQ(0x9b, uuid->uu[13]);
+  EXPECT_EQ(0x34, uuid->uu[14]);
+  EXPECT_EQ(0xfb, uuid->uu[15]);
+  uuid_free(uuid);
+}
+
+TEST_F(UuidTest, uuid_is_empty) {
+  bt_uuid_t *uuid = NULL;
+
+  uuid = uuid_new(UUID_EMPTY);
+  ASSERT_TRUE(uuid != NULL);
+  EXPECT_TRUE(uuid_is_empty(uuid));
+  uuid_free(uuid);
+
+  uuid = uuid_new(UUID_BASE);
+  ASSERT_TRUE(uuid != NULL);
+  EXPECT_FALSE(uuid_is_empty(uuid));
+  uuid_free(uuid);
+}
+
+TEST_F(UuidTest, uuid_128_to_16) {
+  bt_uuid_t *uuid = NULL;
+  uint16_t uuid16 = 0xffff;
+
+  uuid = uuid_new(UUID_ONES);
+  EXPECT_FALSE(uuid_128_to_16(uuid, &uuid16));
+  uuid_free(uuid);
+  EXPECT_EQ((uint16_t)0xffff, uuid16);
+
+  uuid = uuid_new(UUID_BASE);
+  EXPECT_TRUE(uuid_128_to_16(uuid, &uuid16));
+  uuid_free(uuid);
+  EXPECT_NE((uint16_t)0xffff, uuid16);
+  EXPECT_EQ((uint16_t)0, uuid16);
+}
+
+TEST_F(UuidTest, uuid_128_to_32) {
+  bt_uuid_t *uuid = NULL;
+  uint32_t uuid32 = 0xffffffff;
+
+  uuid = uuid_new(UUID_ONES);
+  EXPECT_FALSE(uuid_128_to_32(uuid, &uuid32));
+  uuid_free(uuid);
+  EXPECT_EQ((uint32_t)0xffffffff, uuid32);
+
+  uuid = uuid_new(UUID_BASE);
+  EXPECT_TRUE(uuid_128_to_32(uuid, &uuid32));
+  uuid_free(uuid);
+  EXPECT_NE((uint32_t)0xffffffff, uuid32);
+  EXPECT_EQ((uint32_t)0, uuid32);
+}
+
+TEST_F(UuidTest, uuid_to_string) {
+  bt_uuid_t *uuid = NULL;
+
+  uuid_string_t *uuid_string = uuid_string_new();
+  EXPECT_TRUE(uuid_string != NULL);
+
+  uuid = uuid_new(UUID_BASE);
+  EXPECT_TRUE(uuid != NULL);
+  uuid_to_string(uuid, uuid_string);
+  uuid_free(uuid);
+
+  EXPECT_TRUE(!strcmp(UUID_BASE, uuid_string_data(uuid_string)));
+
+  uuid = uuid_new(UUID_SEQUENTIAL);
+  EXPECT_TRUE(uuid != NULL);
+
+  uuid_to_string(uuid, uuid_string);
+  uuid_free(uuid);
+
+  char lower_case_buf[36+1];
+  for (int i = 0; i < 36+1; i++) {
+    lower_case_buf[i] = tolower(UUID_SEQUENTIAL[i]);
+  }
+  EXPECT_TRUE(!strcmp(lower_case_buf, uuid_string_data(uuid_string)));
+  uuid_string_free(uuid_string);
+}
diff --git a/bt/btif/Android.mk b/bt/btif/Android.mk
new file mode 100644
index 0000000..46696bf
--- /dev/null
+++ b/bt/btif/Android.mk
@@ -0,0 +1,157 @@
+ ##############################################################################
+ #
+ #  Copyright (C) 2014 Google, Inc.
+ #
+ #  Licensed under the Apache License, Version 2.0 (the "License");
+ #  you may not use this file except in compliance with the License.
+ #  You may obtain a copy of the License at:
+ #
+ #  http://www.apache.org/licenses/LICENSE-2.0
+ #
+ #  Unless required by applicable law or agreed to in writing, software
+ #  distributed under the License is distributed on an "AS IS" BASIS,
+ #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ #  See the License for the specific language governing permissions and
+ #  limitations under the License.
+ #
+ ##############################################################################
+
+LOCAL_PATH := $(call my-dir)
+
+# Common variables
+# ========================================================
+
+# HAL layer
+btifCommonSrc += \
+  src/bluetooth.cc \
+  ../EventLogTags.logtags
+
+# BTIF implementation
+btifCommonSrc += \
+  ../audio_a2dp_hw/audio_a2dp_hw_utils.cc \
+  src/btif_a2dp.cc \
+  src/btif_a2dp_control.cc \
+  src/btif_a2dp_sink.cc \
+  src/btif_a2dp_source.cc \
+  src/btif_av.cc \
+  src/btif_avrcp_audio_track.cc \
+  src/btif_ble_advertiser.cc \
+  src/btif_ble_scanner.cc \
+  src/btif_config.cc \
+  src/btif_config_transcode.cc \
+  src/btif_core.cc \
+  src/btif_debug.cc \
+  src/btif_debug_btsnoop.cc \
+  src/btif_debug_conn.cc \
+  src/btif_dm.cc \
+  src/btif_gatt.cc \
+  src/btif_gatt_client.cc \
+  src/btif_gatt_server.cc \
+  src/btif_gatt_test.cc \
+  src/btif_gatt_util.cc \
+  src/btif_hf.cc \
+  src/btif_hf_client.cc \
+  src/btif_hh.cc \
+  src/btif_hl.cc \
+  src/btif_mce.cc \
+  src/btif_pan.cc \
+  src/btif_profile_queue.cc \
+  src/btif_rc.cc \
+  src/btif_sdp.cc \
+  src/btif_sdp_server.cc \
+  src/btif_sm.cc \
+  src/btif_sock.cc \
+  src/btif_sock_rfc.cc \
+  src/btif_sock_l2cap.cc \
+  src/btif_sock_sco.cc \
+  src/btif_sock_sdp.cc \
+  src/btif_sock_thread.cc \
+  src/btif_sock_util.cc \
+  src/btif_storage.cc \
+  src/btif_uid.cc \
+  src/btif_util.cc \
+  src/stack_manager.cc
+
+# Callouts
+btifCommonSrc += \
+  co/bta_ag_co.cc \
+  co/bta_dm_co.cc \
+  co/bta_av_co.cc \
+  co/bta_hh_co.cc \
+  co/bta_hl_co.cc \
+  co/bta_pan_co.cc \
+  co/bta_gatts_co.cc
+
+# Tests
+btifTestSrc := \
+  test/btif_storage_test.cc
+
+# Includes
+btifCommonIncludes := \
+  $(LOCAL_PATH)/../ \
+  $(LOCAL_PATH)/../bta/include \
+  $(LOCAL_PATH)/../bta/sys \
+  $(LOCAL_PATH)/../bta/dm \
+  $(LOCAL_PATH)/../btcore/include \
+  $(LOCAL_PATH)/../include \
+  $(LOCAL_PATH)/../stack/include \
+  $(LOCAL_PATH)/../stack/l2cap \
+  $(LOCAL_PATH)/../stack/a2dp \
+  $(LOCAL_PATH)/../stack/btm \
+  $(LOCAL_PATH)/../stack/avdt \
+  $(LOCAL_PATH)/../hcis \
+  $(LOCAL_PATH)/../hcis/include \
+  $(LOCAL_PATH)/../hcis/patchram \
+  $(LOCAL_PATH)/../udrv/include \
+  $(LOCAL_PATH)/../btif/include \
+  $(LOCAL_PATH)/../btif/co \
+  $(LOCAL_PATH)/../hci/include\
+  $(LOCAL_PATH)/../vnd/include \
+  $(LOCAL_PATH)/../brcm/include \
+  $(LOCAL_PATH)/../embdrv/sbc/encoder/include \
+  $(LOCAL_PATH)/../embdrv/sbc/decoder/include \
+  $(LOCAL_PATH)/../audio_a2dp_hw \
+  $(LOCAL_PATH)/../utils/include \
+  $(bluetooth_C_INCLUDES) \
+  external/tinyxml2 \
+  external/zlib
+
+# libbtif static library for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_CPP_EXTENSION := .cc
+
+LOCAL_C_INCLUDES := $(btifCommonIncludes)
+LOCAL_SRC_FILES := $(btifCommonSrc)
+# Many .h files have redefined typedefs
+LOCAL_SHARED_LIBRARIES := libmedia libcutils liblog libchrome
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := libbtif
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS) -DBUILDCFG
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_STATIC_LIBRARY)
+
+# btif unit tests for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_CPP_EXTENSION := .cc
+
+LOCAL_C_INCLUDES := $(btifCommonIncludes)
+LOCAL_SRC_FILES := $(btifTestSrc)
+LOCAL_SHARED_LIBRARIES := liblog libhardware libhardware_legacy libcutils \
+	libchrome
+LOCAL_STATIC_LIBRARIES := libbtcore libbtif libosi
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := net_test_btif
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS) -DBUILDCFG
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_NATIVE_TEST)
diff --git a/bt/btif/BUILD.gn b/bt/btif/BUILD.gn
new file mode 100644
index 0000000..b3d9504
--- /dev/null
+++ b/bt/btif/BUILD.gn
@@ -0,0 +1,100 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+static_library("btif") {
+  sources = [
+    "//audio_a2dp_hw/audio_a2dp_hw_utils.cc",
+    "src/btif_a2dp.cc",
+    "src/btif_a2dp_control.cc",
+    "src/btif_a2dp_sink.cc",
+    "src/btif_a2dp_source.cc",
+    "src/btif_av.cc",
+
+    #TODO(jpawlowski): heavily depends on Android,
+    #   "src/btif_avrcp_audio_track.cc",
+    "src/btif_ble_advertiser.cc",
+    "src/btif_ble_scanner.cc",
+    "src/btif_config.cc",
+    "src/btif_config_transcode.cc",
+    "src/btif_core.cc",
+    "src/btif_debug.cc",
+    "src/btif_debug_btsnoop.cc",
+    "src/btif_debug_conn.cc",
+    "src/btif_dm.cc",
+    "src/btif_gatt.cc",
+    "src/btif_gatt_client.cc",
+    "src/btif_gatt_server.cc",
+    "src/btif_gatt_test.cc",
+    "src/btif_gatt_util.cc",
+    "src/btif_hf.cc",
+    "src/btif_hf_client.cc",
+    "src/btif_hh.cc",
+    "src/btif_hl.cc",
+    "src/btif_mce.cc",
+    "src/btif_pan.cc",
+    "src/btif_profile_queue.cc",
+    "src/btif_rc.cc",
+    "src/btif_sdp.cc",
+    "src/btif_sdp_server.cc",
+    "src/btif_sm.cc",
+    "src/btif_sock.cc",
+    "src/btif_sock_l2cap.cc",
+    "src/btif_sock_rfc.cc",
+    "src/btif_sock_sco.cc",
+    "src/btif_sock_sdp.cc",
+    "src/btif_sock_thread.cc",
+    "src/btif_sock_util.cc",
+    "src/btif_storage.cc",
+    "src/btif_uid.cc",
+    "src/btif_util.cc",
+    "src/stack_manager.cc",
+  ]
+
+  # BTIF callouts
+  sources += [
+    "co/bta_ag_co.cc",
+    "co/bta_dm_co.cc",
+    "co/bta_av_co.cc",
+    "co/bta_hh_co.cc",
+    "co/bta_hl_co.cc",
+    "co/bta_pan_co.cc",
+    "co/bta_gatts_co.cc",
+  ]
+
+  include_dirs = [
+    "include",
+    "//",
+    "//audio_a2dp_hw",
+    "//bta/include",
+    "//bta/sys",
+    "//btcore/include",
+    "//embdrv/sbc/encoder/include",
+    "//embdrv/sbc/decoder/include",
+    "//hci/include",
+    "//stack/a2dp",
+    "//stack/btm",
+    "//stack/include",
+    "//third_party/tinyxml2",
+    "//include",
+    "//udrv/include",
+    "//utils/include",
+    "//vnd/include",
+  ]
+
+  deps = [
+    "//third_party/libchrome:base"
+  ]
+}
diff --git a/bt/btif/co/bta_ag_co.cc b/bt/btif/co/bta_ag_co.cc
new file mode 100644
index 0000000..32709fd
--- /dev/null
+++ b/bt/btif/co/bta_ag_co.cc
@@ -0,0 +1,151 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_bta_ag"
+
+#include "bta/include/bta_ag_co.h"
+#include "bta/include/bta_ag_api.h"
+#include "hci/include/hci_audio.h"
+#include "osi/include/osi.h"
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_co_init
+ *
+ * Description      This callout function is executed by AG when it is
+ *                  started by calling BTA_AgEnable().  This function can be
+ *                  used by the phone to initialize audio paths or for other
+ *                  initialization purposes.
+ *
+ *
+ * Returns          Void.
+ *
+ ******************************************************************************/
+void bta_ag_co_init(void) { BTM_WriteVoiceSettings(AG_VOICE_SETTINGS); }
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_co_audio_state
+ *
+ * Description      This function is called by the AG before the audio
+ *                  connection is brought up, after it comes up, and
+ *                  after it goes down.
+ *
+ * Parameters       handle - handle of the AG instance
+ *                  state - Audio state
+ *                  codec - if WBS support is compiled in, codec to going to be
+ *                      used is provided and when in SCO_STATE_SETUP,
+ *                      BTM_I2SPCMConfig() must be called with the correct
+ *                      platform parameters.
+ *                      In the other states, codec type should not be ignored.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+#if (BTM_WBS_INCLUDED == TRUE)
+void bta_ag_co_audio_state(uint16_t handle, uint8_t app_id, uint8_t state,
+                           tBTA_AG_PEER_CODEC codec)
+#else
+void bta_ag_co_audio_state(uint16_t handle, uint8_t app_id, uint8_t state)
+#endif
+{
+  BTIF_TRACE_DEBUG("bta_ag_co_audio_state: handle %d, state %d", handle, state);
+  switch (state) {
+    case SCO_STATE_OFF:
+#if (BTM_WBS_INCLUDED == TRUE)
+      BTIF_TRACE_DEBUG(
+          "bta_ag_co_audio_state(handle %d)::Closed (OFF), codec: 0x%x", handle,
+          codec);
+      set_audio_state(handle, (sco_codec_t)codec, (sco_state_t)state);
+#else
+      BTIF_TRACE_DEBUG("bta_ag_co_audio_state(handle %d)::Closed (OFF)",
+                       handle);
+#endif
+      break;
+    case SCO_STATE_OFF_TRANSFER:
+      BTIF_TRACE_DEBUG("bta_ag_co_audio_state(handle %d)::Closed (XFERRING)",
+                       handle);
+      break;
+    case SCO_STATE_SETUP:
+#if (BTM_WBS_INCLUDED == TRUE)
+      set_audio_state(handle, (sco_codec_t)codec, (sco_state_t)state);
+#else
+      set_audio_state(handle, (sco_codec_t)BTA_AG_CODEC_CVSD,
+                      (sco_state_t)state);
+#endif
+      break;
+    default:
+      break;
+  }
+#if (BTM_WBS_INCLUDED == TRUE)
+  APPL_TRACE_DEBUG(
+      "bta_ag_co_audio_state(handle %d, app_id: %d, state %d, codec: 0x%x)",
+      handle, app_id, state, codec);
+#else
+  APPL_TRACE_DEBUG("bta_ag_co_audio_state(handle %d, app_id: %d, state %d)",
+                   handle, app_id, state);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_co_data_open
+ *
+ * Description      This function is executed by AG when a service level
+ *                  connection is opened.  The phone can use this function to
+ *                  set up data paths or perform any required initialization or
+ *                  set up particular to the connected service.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_co_data_open(uint16_t handle, tBTA_SERVICE_ID service) {
+  BTIF_TRACE_DEBUG("bta_ag_co_data_open handle:%d service:%d", handle, service);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_ag_co_data_close
+ *
+ * Description      This function is called by AG when a service level
+ *                  connection is closed
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_ag_co_data_close(uint16_t handle) {
+  BTIF_TRACE_DEBUG("bta_ag_co_data_close handle:%d", handle);
+}
+
+/*******************************************************************************
+ **
+ ** Function         bta_ag_co_tx_write
+ **
+ ** Description      This function is called by the AG to send data to the
+ **                  phone when the AG is configured for AT command
+ **                  pass-through. The implementation of this function must copy
+ **                  the data to the phones memory.
+ **
+ ** Returns          void
+ **
+ *******************************************************************************/
+void bta_ag_co_tx_write(uint16_t handle, UNUSED_ATTR uint8_t* p_data,
+                        uint16_t len) {
+  BTIF_TRACE_DEBUG("bta_ag_co_tx_write: handle: %d, len: %d", handle, len);
+}
diff --git a/bt/btif/co/bta_av_co.cc b/bt/btif/co/bta_av_co.cc
new file mode 100644
index 0000000..b52fcbf
--- /dev/null
+++ b/bt/btif/co/bta_av_co.cc
@@ -0,0 +1,1205 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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 is the advanced audio/video call-out function implementation for
+ *  BTIF.
+ *
+ ******************************************************************************/
+
+#include "bta_av_co.h"
+#include <assert.h>
+#include <string.h>
+#include "a2dp_api.h"
+#include "bt_target.h"
+#include "bta_av_api.h"
+#include "bta_av_ci.h"
+#include "bta_sys.h"
+
+#include "btif_av_co.h"
+#include "btif_util.h"
+#include "osi/include/mutex.h"
+#include "osi/include/osi.h"
+
+/*****************************************************************************
+ **  Constants
+ *****************************************************************************/
+
+/* Macro to retrieve the number of elements in a statically allocated array */
+#define BTA_AV_CO_NUM_ELEMENTS(__a) (sizeof(__a) / sizeof((__a)[0]))
+
+/* MIN and MAX macros */
+#define BTA_AV_CO_MIN(X, Y) ((X) < (Y) ? (X) : (Y))
+#define BTA_AV_CO_MAX(X, Y) ((X) > (Y) ? (X) : (Y))
+
+/* Macro to convert audio handle to index and vice versa */
+#define BTA_AV_CO_AUDIO_HNDL_TO_INDX(hndl) (((hndl) & (~BTA_AV_CHNL_MSK)) - 1)
+#define BTA_AV_CO_AUDIO_INDX_TO_HNDL(indx) (((indx) + 1) | BTA_AV_CHNL_AUDIO)
+
+/* SCMS-T protect info */
+const uint8_t bta_av_co_cp_scmst[AVDT_CP_INFO_LEN] = {0x02, 0x02, 0x00};
+
+/*****************************************************************************
+ *  Local data
+ ****************************************************************************/
+typedef struct {
+  uint8_t sep_info_idx;                /* local SEP index (in BTA tables) */
+  uint8_t seid;                        /* peer SEP index (in peer tables) */
+  uint8_t codec_caps[AVDT_CODEC_SIZE]; /* peer SEP codec capabilities */
+  uint8_t num_protect;                 /* peer SEP number of CP elements */
+  uint8_t protect_info[AVDT_CP_INFO_LEN]; /* peer SEP content protection info */
+} tBTA_AV_CO_SINK;
+
+typedef struct {
+  BD_ADDR addr; /* address of audio/video peer */
+  tBTA_AV_CO_SINK
+      sinks[A2DP_CODEC_SEP_INDEX_MAX];            /* array of supported sinks */
+  tBTA_AV_CO_SINK srcs[A2DP_CODEC_SEP_INDEX_MAX]; /* array of supported srcs */
+  uint8_t num_sinks;     /* total number of sinks at peer */
+  uint8_t num_srcs;      /* total number of srcs at peer */
+  uint8_t num_seps;      /* total number of seids at peer */
+  uint8_t num_rx_sinks;  /* number of received sinks */
+  uint8_t num_rx_srcs;   /* number of received srcs */
+  uint8_t num_sup_sinks; /* number of supported sinks in the sinks array */
+  uint8_t num_sup_srcs;  /* number of supported srcs in the srcs array */
+  const tBTA_AV_CO_SINK* p_sink;      /* currently selected sink */
+  const tBTA_AV_CO_SINK* p_src;       /* currently selected src */
+  uint8_t codec_config[AVDT_CODEC_SIZE]; /* current codec configuration */
+  bool cp_active;                     /* current CP configuration */
+  bool acp;                           /* acceptor */
+  bool reconfig_needed;               /* reconfiguration is needed */
+  bool opened;                        /* opened */
+  uint16_t mtu;                       /* maximum transmit unit size */
+  uint16_t uuid_to_connect;           /* uuid of peer device */
+} tBTA_AV_CO_PEER;
+
+typedef struct {
+  bool active;
+  uint8_t flag;
+} tBTA_AV_CO_CP;
+
+typedef struct {
+  /* Connected peer information */
+  tBTA_AV_CO_PEER peers[BTA_AV_NUM_STRS];
+  /* Current codec configuration - access to this variable must be protected */
+  uint8_t codec_config[AVDT_CODEC_SIZE];
+  uint8_t codec_config_setconfig[AVDT_CODEC_SIZE]; /* remote peer setconfig
+                                                    * preference */
+
+  tBTA_AV_CO_CP cp;
+} tBTA_AV_CO_CB;
+
+/* Control block instance */
+static tBTA_AV_CO_CB bta_av_co_cb;
+
+static bool bta_av_co_cp_is_scmst(const uint8_t* p_protectinfo);
+static bool bta_av_co_audio_sink_has_scmst(const tBTA_AV_CO_SINK* p_sink);
+static const tBTA_AV_CO_SINK* bta_av_co_find_peer_sink_supports_codec(
+    const uint8_t* codec_config, const tBTA_AV_CO_PEER* p_peer);
+static const tBTA_AV_CO_SINK* bta_av_co_find_peer_src_supports_codec(
+    const tBTA_AV_CO_PEER* p_peer);
+static bool bta_av_co_audio_codec_selected(const uint8_t* codec_config);
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_cp_get_flag
+ **
+ ** Description      Get content protection flag
+ **                  AVDT_CP_SCMS_COPY_NEVER
+ **                  AVDT_CP_SCMS_COPY_ONCE
+ **                  AVDT_CP_SCMS_COPY_FREE
+ **
+ ** Returns          The current flag value
+ **
+ *******************************************************************************/
+static uint8_t bta_av_co_cp_get_flag(void) { return bta_av_co_cb.cp.flag; }
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_cp_set_flag
+ **
+ ** Description      Set content protection flag
+ **                  AVDT_CP_SCMS_COPY_NEVER
+ **                  AVDT_CP_SCMS_COPY_ONCE
+ **                  AVDT_CP_SCMS_COPY_FREE
+ **
+ ** Returns          true if setting the SCMS flag is supported else false
+ **
+ *******************************************************************************/
+static bool bta_av_co_cp_set_flag(uint8_t cp_flag) {
+  APPL_TRACE_DEBUG("%s: cp_flag = %d", __func__, cp_flag);
+
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+#else
+  if (cp_flag != AVDT_CP_SCMS_COPY_FREE) {
+    return false;
+  }
+#endif
+  bta_av_co_cb.cp.flag = cp_flag;
+  return true;
+}
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_get_peer
+ **
+ ** Description      find the peer entry for a given handle
+ **
+ ** Returns          the control block
+ **
+ *******************************************************************************/
+static tBTA_AV_CO_PEER* bta_av_co_get_peer(tBTA_AV_HNDL hndl) {
+  uint8_t index;
+
+  index = BTA_AV_CO_AUDIO_HNDL_TO_INDX(hndl);
+
+  APPL_TRACE_DEBUG("%s: handle = %d index = %d", __func__, hndl, index);
+
+  /* Sanity check */
+  if (index >= BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers)) {
+    APPL_TRACE_ERROR("%s: peer index out of bounds: %d", __func__, index);
+    return NULL;
+  }
+
+  return &bta_av_co_cb.peers[index];
+}
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_audio_init
+ **
+ ** Description      This callout function is executed by AV when it is
+ **                  started by calling BTA_AvRegister().  This function can be
+ **                  used by the phone to initialize audio paths or for other
+ **                  initialization purposes.
+ **
+ **
+ ** Returns          Stream codec and content protection capabilities info.
+ **
+ *******************************************************************************/
+bool bta_av_co_audio_init(tA2DP_CODEC_SEP_INDEX codec_sep_index,
+                          tAVDT_CFG* p_cfg) {
+  /* reset remote preference through setconfig */
+  memset(bta_av_co_cb.codec_config_setconfig, 0,
+         sizeof(bta_av_co_cb.codec_config_setconfig));
+
+  return A2DP_InitCodecConfig(codec_sep_index, p_cfg);
+}
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_audio_disc_res
+ **
+ ** Description      This callout function is executed by AV to report the
+ **                  number of stream end points (SEP) were found during the
+ **                  AVDT stream discovery process.
+ **
+ **
+ ** Returns          void.
+ **
+ *******************************************************************************/
+void bta_av_co_audio_disc_res(tBTA_AV_HNDL hndl, uint8_t num_seps,
+                              uint8_t num_sink, uint8_t num_src, BD_ADDR addr,
+                              uint16_t uuid_local) {
+  tBTA_AV_CO_PEER* p_peer;
+
+  APPL_TRACE_DEBUG("%s: h:x%x num_seps:%d num_sink:%d num_src:%d", __func__,
+                   hndl, num_seps, num_sink, num_src);
+
+  /* Find the peer info */
+  p_peer = bta_av_co_get_peer(hndl);
+  if (p_peer == NULL) {
+    APPL_TRACE_ERROR("%s: could not find peer entry", __func__);
+    return;
+  }
+
+  /* Sanity check : this should never happen */
+  if (p_peer->opened) {
+    APPL_TRACE_ERROR("%s: peer already opened", __func__);
+  }
+
+  /* Copy the discovery results */
+  bdcpy(p_peer->addr, addr);
+  p_peer->num_sinks = num_sink;
+  p_peer->num_srcs = num_src;
+  p_peer->num_seps = num_seps;
+  p_peer->num_rx_sinks = 0;
+  p_peer->num_rx_srcs = 0;
+  p_peer->num_sup_sinks = 0;
+  if (uuid_local == UUID_SERVCLASS_AUDIO_SINK)
+    p_peer->uuid_to_connect = UUID_SERVCLASS_AUDIO_SOURCE;
+  else if (uuid_local == UUID_SERVCLASS_AUDIO_SOURCE)
+    p_peer->uuid_to_connect = UUID_SERVCLASS_AUDIO_SINK;
+}
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_audio_sink_getconfig
+ **
+ ** Description      This callout function is executed by AV to retrieve the
+ **                  desired codec and content protection configuration for the
+ **                  A2DP Sink audio stream in Initiator.
+ **
+ **
+ ** Returns          Pass or Fail for current getconfig.
+ **
+ *******************************************************************************/
+static tA2DP_STATUS bta_av_audio_sink_getconfig(
+    tBTA_AV_HNDL hndl, uint8_t* p_codec_info, uint8_t* p_sep_info_idx,
+    uint8_t seid, uint8_t* p_num_protect, uint8_t* p_protect_info) {
+  tA2DP_STATUS result = A2DP_FAIL;
+  tBTA_AV_CO_PEER* p_peer;
+  uint8_t pref_config[AVDT_CODEC_SIZE];
+
+  APPL_TRACE_DEBUG("%s: handle:0x%x codec:%s seid:%d", __func__, hndl,
+                   A2DP_CodecName(p_codec_info), seid);
+  APPL_TRACE_DEBUG("%s: num_protect:0x%02x protect_info:0x%02x%02x%02x",
+                   __func__, *p_num_protect, p_protect_info[0],
+                   p_protect_info[1], p_protect_info[2]);
+
+  /* Retrieve the peer info */
+  p_peer = bta_av_co_get_peer(hndl);
+  if (p_peer == NULL) {
+    APPL_TRACE_ERROR("%s: could not find peer entry", __func__);
+    return A2DP_FAIL;
+  }
+
+  APPL_TRACE_DEBUG("%s: peer(o=%d,n_sinks=%d,n_rx_sinks=%d,n_sup_sinks=%d)",
+                   __func__, p_peer->opened, p_peer->num_srcs,
+                   p_peer->num_rx_srcs, p_peer->num_sup_srcs);
+
+  p_peer->num_rx_srcs++;
+
+  /* Check the peer's SOURCE codec */
+  if (A2DP_IsPeerSourceCodecValid(p_codec_info)) {
+    /* If there is room for a new one */
+    if (p_peer->num_sup_srcs < BTA_AV_CO_NUM_ELEMENTS(p_peer->srcs)) {
+      tBTA_AV_CO_SINK* p_src = &p_peer->srcs[p_peer->num_sup_srcs++];
+
+      APPL_TRACE_DEBUG("%s: saved caps[%x:%x:%x:%x:%x:%x]", __func__,
+                       p_codec_info[1], p_codec_info[2], p_codec_info[3],
+                       p_codec_info[4], p_codec_info[5], p_codec_info[6]);
+
+      memcpy(p_src->codec_caps, p_codec_info, AVDT_CODEC_SIZE);
+      p_src->sep_info_idx = *p_sep_info_idx;
+      p_src->seid = seid;
+      p_src->num_protect = *p_num_protect;
+      memcpy(p_src->protect_info, p_protect_info, AVDT_CP_INFO_LEN);
+    } else {
+      APPL_TRACE_ERROR("%s: no more room for SRC info", __func__);
+    }
+  }
+
+  /* If last SINK get capabilities or all supported codec caps retrieved */
+  if ((p_peer->num_rx_srcs == p_peer->num_srcs) ||
+      (p_peer->num_sup_srcs == BTA_AV_CO_NUM_ELEMENTS(p_peer->srcs))) {
+    APPL_TRACE_DEBUG("%s: last SRC reached", __func__);
+
+    /* Protect access to bta_av_co_cb.codec_config */
+    mutex_global_lock();
+
+    /* Find a src that matches the codec config */
+    const tBTA_AV_CO_SINK* p_src =
+        bta_av_co_find_peer_src_supports_codec(p_peer);
+    if (p_src != NULL) {
+      APPL_TRACE_DEBUG("%s: codec supported", __func__);
+
+      /* Build the codec configuration for this sink */
+      {
+        /* Save the new configuration */
+        p_peer->p_src = p_src;
+        /* get preferred config from src_caps */
+        if (A2DP_BuildSrc2SinkConfig(p_src->codec_caps, pref_config) !=
+            A2DP_SUCCESS) {
+          mutex_global_unlock();
+          return A2DP_FAIL;
+        }
+        memcpy(p_peer->codec_config, pref_config, AVDT_CODEC_SIZE);
+
+        APPL_TRACE_DEBUG("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__,
+                         p_peer->codec_config[1], p_peer->codec_config[2],
+                         p_peer->codec_config[3], p_peer->codec_config[4],
+                         p_peer->codec_config[5], p_peer->codec_config[6]);
+        /* By default, no content protection */
+        *p_num_protect = 0;
+
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+        p_peer->cp_active = false;
+        bta_av_co_cb.cp.active = false;
+#endif
+
+        *p_sep_info_idx = p_src->sep_info_idx;
+        memcpy(p_codec_info, p_peer->codec_config, AVDT_CODEC_SIZE);
+        result = A2DP_SUCCESS;
+      }
+    }
+    /* Protect access to bta_av_co_cb.codec_config */
+    mutex_global_unlock();
+  }
+  return result;
+}
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_audio_getconfig
+ **
+ ** Description      This callout function is executed by AV to retrieve the
+ **                  desired codec and content protection configuration for the
+ **                  audio stream.
+ **
+ **
+ ** Returns          Stream codec and content protection configuration info.
+ **
+ *******************************************************************************/
+tA2DP_STATUS bta_av_co_audio_getconfig(tBTA_AV_HNDL hndl, uint8_t* p_codec_info,
+                                       uint8_t* p_sep_info_idx, uint8_t seid,
+                                       uint8_t* p_num_protect,
+                                       uint8_t* p_protect_info) {
+  tA2DP_STATUS result = A2DP_FAIL;
+  tBTA_AV_CO_PEER* p_peer;
+  uint8_t codec_config[AVDT_CODEC_SIZE];
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  /* Retrieve the peer info */
+  p_peer = bta_av_co_get_peer(hndl);
+  if (p_peer == NULL) {
+    APPL_TRACE_ERROR("%s: could not find peer entry", __func__);
+    return A2DP_FAIL;
+  }
+
+  if (p_peer->uuid_to_connect == UUID_SERVCLASS_AUDIO_SOURCE) {
+    result = bta_av_audio_sink_getconfig(hndl, p_codec_info, p_sep_info_idx,
+                                         seid, p_num_protect, p_protect_info);
+    return result;
+  }
+  APPL_TRACE_DEBUG("%s: handle:0x%x codec:%s seid:%d", __func__, hndl,
+                   A2DP_CodecName(p_codec_info), seid);
+  APPL_TRACE_DEBUG("%s: num_protect:0x%02x protect_info:0x%02x%02x%02x",
+                   __func__, *p_num_protect, p_protect_info[0],
+                   p_protect_info[1], p_protect_info[2]);
+  APPL_TRACE_DEBUG("%s: peer(o=%d, n_sinks=%d, n_rx_sinks=%d, n_sup_sinks=%d)",
+                   __func__, p_peer->opened, p_peer->num_sinks,
+                   p_peer->num_rx_sinks, p_peer->num_sup_sinks);
+
+  p_peer->num_rx_sinks++;
+
+  /* Check the peer's SINK codec */
+  if (A2DP_IsPeerSinkCodecValid(p_codec_info)) {
+    /* If there is room for a new one */
+    if (p_peer->num_sup_sinks < BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks)) {
+      tBTA_AV_CO_SINK* p_sink = &p_peer->sinks[p_peer->num_sup_sinks++];
+
+      APPL_TRACE_DEBUG("%s: saved caps[%x:%x:%x:%x:%x:%x]", __func__,
+                       p_codec_info[1], p_codec_info[2], p_codec_info[3],
+                       p_codec_info[4], p_codec_info[5], p_codec_info[6]);
+
+      memcpy(p_sink->codec_caps, p_codec_info, AVDT_CODEC_SIZE);
+      p_sink->sep_info_idx = *p_sep_info_idx;
+      p_sink->seid = seid;
+      p_sink->num_protect = *p_num_protect;
+      memcpy(p_sink->protect_info, p_protect_info, AVDT_CP_INFO_LEN);
+    } else {
+      APPL_TRACE_ERROR("%s: no more room for SINK info", __func__);
+    }
+  }
+
+  /* If last SINK get capabilities or all supported codec capa retrieved */
+  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_DEBUG("%s: last sink reached", __func__);
+
+    /* Protect access to bta_av_co_cb.codec_config */
+    mutex_global_lock();
+
+    /* Find a sink that matches the codec config */
+    const tBTA_AV_CO_SINK* p_sink = NULL;
+
+    // Initial strawman codec selection mechanism: largest codec SEP index
+    // first.
+    // TODO: Replace this mechanism with a better one, and abstract it
+    // in a separate function.
+    for (int i = A2DP_CODEC_SEP_INDEX_SOURCE_MAX - 1;
+         i >= A2DP_CODEC_SEP_INDEX_SOURCE_MIN; i--) {
+      tA2DP_CODEC_SEP_INDEX source_codec_sep_index =
+        static_cast<tA2DP_CODEC_SEP_INDEX>(i);
+      APPL_TRACE_DEBUG("%s: trying codec %s with sep_index %d", __func__,
+                       A2DP_CodecSepIndexStr(source_codec_sep_index), i);
+      tAVDT_CFG avdt_cfg;
+      if (!A2DP_InitCodecConfig(source_codec_sep_index, &avdt_cfg)) {
+        APPL_TRACE_DEBUG("%s: cannot setup source codec %s", __func__,
+                         A2DP_CodecSepIndexStr(source_codec_sep_index));
+        continue;
+      }
+      p_sink = bta_av_co_find_peer_sink_supports_codec(avdt_cfg.codec_info,
+                                                       p_peer);
+      if (p_sink == NULL)
+        continue;
+      // Found a preferred codec
+      APPL_TRACE_DEBUG("%s: selected codec %s", __func__,
+                       A2DP_CodecName(avdt_cfg.codec_info));
+      memcpy(bta_av_co_cb.codec_config, avdt_cfg.codec_info, AVDT_CODEC_SIZE);
+      break;
+    }
+
+    if (p_sink == NULL) {
+      APPL_TRACE_ERROR("%s: cannot find peer SINK for this codec config",
+                       __func__);
+    } else {
+      /* stop fetching caps once we retrieved a supported codec */
+      if (p_peer->acp) {
+        APPL_TRACE_EVENT("%s: no need to fetch more SEPs", __func__);
+        *p_sep_info_idx = p_peer->num_seps;
+      }
+
+      /* Build the codec configuration for this sink */
+      memset(codec_config, 0, AVDT_CODEC_SIZE);
+      if (A2DP_BuildSinkConfig(bta_av_co_cb.codec_config, p_sink->codec_caps,
+                               codec_config) == A2DP_SUCCESS) {
+        APPL_TRACE_DEBUG("%s: reconfig codec_config[%x:%x:%x:%x:%x:%x]",
+                         __func__, codec_config[1], codec_config[2],
+                         codec_config[3], codec_config[4], codec_config[5],
+                         codec_config[6]);
+        for (int i = 0; i < AVDT_CODEC_SIZE; i++) {
+          APPL_TRACE_DEBUG("%s: p_codec_info[%d]: %x", __func__, i,
+                           p_codec_info[i]);
+        }
+
+        /* Save the new configuration */
+        p_peer->p_sink = p_sink;
+        memcpy(p_peer->codec_config, codec_config, AVDT_CODEC_SIZE);
+
+        /* By default, no content protection */
+        *p_num_protect = 0;
+
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+        /* Check if this sink supports SCMS */
+        p_peer->cp_active = bta_av_co_audio_sink_has_scmst(p_sink);
+        bta_av_co_cb.cp.active = p_peer->cp_active;
+        if (p_peer->cp_active) {
+          *p_num_protect = AVDT_CP_INFO_LEN;
+          memcpy(p_protect_info, bta_av_co_cp_scmst, AVDT_CP_INFO_LEN);
+        }
+#endif
+
+        /* If acceptor -> reconfig otherwise reply for configuration */
+        if (p_peer->acp) {
+          if (p_peer->reconfig_needed) {
+            APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(x%x)", __func__, hndl);
+            BTA_AvReconfig(hndl, true, p_sink->sep_info_idx,
+                           p_peer->codec_config, *p_num_protect,
+                           bta_av_co_cp_scmst);
+          }
+        } else {
+          *p_sep_info_idx = p_sink->sep_info_idx;
+          memcpy(p_codec_info, p_peer->codec_config, AVDT_CODEC_SIZE);
+        }
+        result = A2DP_SUCCESS;
+      }
+    }
+    /* Protect access to bta_av_co_cb.codec_config */
+    mutex_global_unlock();
+  }
+  return result;
+}
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_audio_setconfig
+ **
+ ** Description      This callout function is executed by AV to set the codec
+ **                  and content protection configuration of the audio stream.
+ **
+ **
+ ** Returns          void
+ **
+ *******************************************************************************/
+void bta_av_co_audio_setconfig(tBTA_AV_HNDL hndl, const uint8_t* p_codec_info,
+                               UNUSED_ATTR uint8_t seid,
+                               UNUSED_ATTR BD_ADDR addr, uint8_t num_protect,
+                               uint8_t* p_protect_info, uint8_t t_local_sep,
+                               uint8_t avdt_handle) {
+  tBTA_AV_CO_PEER* p_peer;
+  tA2DP_STATUS status = A2DP_SUCCESS;
+  uint8_t category = A2DP_SUCCESS;
+  bool reconfig_needed = false;
+
+  APPL_TRACE_DEBUG("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__,
+                   p_codec_info[1], p_codec_info[2], p_codec_info[3],
+                   p_codec_info[4], p_codec_info[5], p_codec_info[6]);
+  APPL_TRACE_DEBUG("num_protect:0x%02x protect_info:0x%02x%02x%02x",
+                   num_protect, p_protect_info[0], p_protect_info[1],
+                   p_protect_info[2]);
+
+  /* Retrieve the peer info */
+  p_peer = bta_av_co_get_peer(hndl);
+  if (p_peer == NULL) {
+    APPL_TRACE_ERROR("%s: could not find peer entry", __func__);
+    /* Call call-in rejecting the configuration */
+    bta_av_ci_setconfig(hndl, A2DP_BUSY, AVDT_ASC_CODEC, 0, NULL, false,
+                        avdt_handle);
+    return;
+  }
+
+  APPL_TRACE_DEBUG("%s: peer(o=%d, n_sinks=%d, n_rx_sinks=%d, n_sup_sinks=%d)",
+                   __func__, p_peer->opened, p_peer->num_sinks,
+                   p_peer->num_rx_sinks, p_peer->num_sup_sinks);
+
+  /* Sanity check: should not be opened at this point */
+  if (p_peer->opened) {
+    APPL_TRACE_ERROR("%s: peer already in use", __func__);
+  }
+
+  if (num_protect != 0) {
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+    /* If CP is supported */
+    if ((num_protect != 1) ||
+        (bta_av_co_cp_is_scmst(p_protect_info) == false)) {
+      APPL_TRACE_ERROR("%s: wrong CP configuration", __func__);
+      status = A2DP_BAD_CP_TYPE;
+      category = AVDT_ASC_PROTECT;
+    }
+#else
+    /* Do not support content protection for the time being */
+    APPL_TRACE_ERROR("%s: wrong CP configuration", __func__);
+    status = A2DP_BAD_CP_TYPE;
+    category = AVDT_ASC_PROTECT;
+#endif
+  }
+
+  if (status == A2DP_SUCCESS) {
+    bool codec_config_supported = false;
+    if (t_local_sep == AVDT_TSEP_SNK) {
+      APPL_TRACE_DEBUG("%s: peer is A2DP SRC", __func__);
+      codec_config_supported = A2DP_IsSinkCodecSupported(p_codec_info);
+    }
+    if (t_local_sep == AVDT_TSEP_SRC) {
+      APPL_TRACE_DEBUG("%s: peer is A2DP SINK", __func__);
+      codec_config_supported = A2DP_IsSourceCodecSupported(p_codec_info);
+    }
+
+    /* Check if codec configuration is supported */
+    if (codec_config_supported) {
+      /* Protect access to bta_av_co_cb.codec_config */
+      mutex_global_lock();
+
+      /* Check if the configuration matches the current codec config */
+      if (A2DP_CodecRequiresReconfig(p_codec_info, bta_av_co_cb.codec_config)) {
+        reconfig_needed = true;
+      } else if ((num_protect == 1) && (!bta_av_co_cb.cp.active)) {
+        reconfig_needed = true;
+      }
+      memcpy(bta_av_co_cb.codec_config_setconfig, p_codec_info, AVDT_CODEC_SIZE);
+      if (t_local_sep == AVDT_TSEP_SNK) {
+        /*
+         * If Peer is SRC, and our config subset matches with what is
+         * requested by peer, then just accept what peer wants.
+         */
+        memcpy(bta_av_co_cb.codec_config, p_codec_info, AVDT_CODEC_SIZE);
+        reconfig_needed = false;
+      }
+      /* Protect access to bta_av_co_cb.codec_config */
+      mutex_global_unlock();
+    } else {
+      category = AVDT_ASC_CODEC;
+      status = A2DP_WRONG_CODEC;
+    }
+  }
+
+  if (status != A2DP_SUCCESS) {
+    APPL_TRACE_DEBUG("%s: reject s=%d c=%d", __func__, status, category);
+    /* Call call-in rejecting the configuration */
+    bta_av_ci_setconfig(hndl, status, category, 0, NULL, false, avdt_handle);
+    return;
+  }
+
+  /* Mark that this is an acceptor peer */
+  p_peer->acp = true;
+  p_peer->reconfig_needed = reconfig_needed;
+  APPL_TRACE_DEBUG("%s: accept reconf=%d", __func__, reconfig_needed);
+  /* Call call-in accepting the configuration */
+  bta_av_ci_setconfig(hndl, A2DP_SUCCESS, A2DP_SUCCESS, 0, NULL,
+                      reconfig_needed, avdt_handle);
+}
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_audio_open
+ **
+ ** Description      This function is called by AV when the audio stream
+ **                  connection is opened.
+ **
+ **
+ ** Returns          void
+ **
+ *******************************************************************************/
+void bta_av_co_audio_open(tBTA_AV_HNDL hndl, uint8_t* p_codec_info,
+                          uint16_t mtu) {
+  tBTA_AV_CO_PEER* p_peer;
+
+  APPL_TRACE_DEBUG("%s: mtu:%d codec:%s", __func__, mtu,
+                   A2DP_CodecName(p_codec_info));
+
+  /* Retrieve the peer info */
+  p_peer = bta_av_co_get_peer(hndl);
+  if (p_peer == NULL) {
+    APPL_TRACE_ERROR("%s: could not find peer entry", __func__);
+  } else {
+    p_peer->opened = true;
+    p_peer->mtu = mtu;
+  }
+}
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_audio_close
+ **
+ ** Description      This function is called by AV when the audio stream
+ **                  connection is closed.
+ **
+ **
+ ** Returns          void
+ **
+ *******************************************************************************/
+void bta_av_co_audio_close(tBTA_AV_HNDL hndl, UNUSED_ATTR uint16_t mtu)
+
+{
+  tBTA_AV_CO_PEER* p_peer;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  /* Retrieve the peer info */
+  p_peer = bta_av_co_get_peer(hndl);
+  if (p_peer) {
+    /* Mark the peer closed and clean the peer info */
+    memset(p_peer, 0, sizeof(*p_peer));
+  } else {
+    APPL_TRACE_ERROR("%s: could not find peer entry", __func__);
+  }
+
+  /* reset remote preference through setconfig */
+  memset(bta_av_co_cb.codec_config_setconfig, 0,
+         sizeof(bta_av_co_cb.codec_config_setconfig));
+}
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_audio_start
+ **
+ ** Description      This function is called by AV when the audio streaming data
+ **                  transfer is started.
+ **
+ **
+ ** Returns          void
+ **
+ *******************************************************************************/
+void bta_av_co_audio_start(UNUSED_ATTR tBTA_AV_HNDL hndl,
+                           UNUSED_ATTR uint8_t* p_codec_info,
+                           UNUSED_ATTR bool* p_no_rtp_hdr) {
+  APPL_TRACE_DEBUG("%s", __func__);
+}
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_audio_stop
+ **
+ ** Description      This function is called by AV when the audio streaming data
+ **                  transfer is stopped.
+ **
+ **
+ ** Returns          void
+ **
+ *******************************************************************************/
+void bta_av_co_audio_stop(UNUSED_ATTR tBTA_AV_HNDL hndl) {
+  APPL_TRACE_DEBUG("%s", __func__);
+}
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_audio_src_data_path
+ **
+ ** Description      This function is called to manage data transfer from
+ **                  the audio codec to AVDTP.
+ **
+ ** Returns          Pointer to the GKI buffer to send, NULL if no buffer to
+ **                  send
+ **
+ *******************************************************************************/
+void* bta_av_co_audio_src_data_path(const uint8_t* p_codec_info,
+                                    uint32_t* p_timestamp) {
+  BT_HDR* p_buf;
+
+  APPL_TRACE_DEBUG("%s: codec: %s", __func__, A2DP_CodecName(p_codec_info));
+
+  p_buf = btif_a2dp_source_audio_readbuf();
+  if (p_buf == NULL) return NULL;
+
+  /*
+   * Retrieve the timestamp information from the media packet,
+   * and set up the packet header.
+   *
+   * In media packet, the following information is available:
+   * p_buf->layer_specific : number of audio frames in the packet
+   * p_buf->word[0] : timestamp
+   */
+  if (!A2DP_GetPacketTimestamp(p_codec_info, (const uint8_t*)(p_buf + 1),
+                               p_timestamp) ||
+      !A2DP_BuildCodecHeader(p_codec_info, p_buf, p_buf->layer_specific)) {
+    APPL_TRACE_ERROR("%s: unsupported codec type (%d)", __func__,
+                     A2DP_GetCodecType(p_codec_info));
+  }
+
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+  if (bta_av_co_cb.cp.active) {
+    p_buf->len++;
+    p_buf->offset--;
+    uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+    *p = bta_av_co_cp_get_flag();
+  }
+#endif
+
+  return p_buf;
+}
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_audio_drop
+ **
+ ** Description      An Audio packet is dropped. .
+ **                  It's very likely that the connected headset with this
+ **                  handle is moved far away. The implementation may want to
+ **                  reduce the encoder bit rate setting to reduce the packet
+ **                  size.
+ **
+ ** Returns          void
+ **
+ *******************************************************************************/
+void bta_av_co_audio_drop(tBTA_AV_HNDL hndl) {
+  APPL_TRACE_ERROR("%s: dropped audio packet on handle 0x%x", __func__, hndl);
+}
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_audio_delay
+ **
+ ** Description      This function is called by AV when the audio stream
+ **                  connection needs to send the initial delay report to the
+ **                  connected SRC.
+ **
+ **
+ ** Returns          void
+ **
+ *******************************************************************************/
+void bta_av_co_audio_delay(tBTA_AV_HNDL hndl, uint16_t delay) {
+  APPL_TRACE_ERROR("%s: handle: x%x, delay:0x%x", __func__, hndl, delay);
+}
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_cp_is_scmst
+ **
+ ** Description      Check if a content protection service is SCMS-T
+ **
+ ** Returns          true if this CP is SCMS-T, false otherwise
+ **
+ *******************************************************************************/
+static bool bta_av_co_cp_is_scmst(const uint8_t* p_protectinfo) {
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  if (*p_protectinfo >= AVDT_CP_LOSC) {
+    uint16_t cp_id;
+
+    p_protectinfo++;
+    STREAM_TO_UINT16(cp_id, p_protectinfo);
+    if (cp_id == AVDT_CP_SCMS_T_ID) {
+      APPL_TRACE_DEBUG("%s: SCMS-T found", __func__);
+      return true;
+    }
+  }
+
+  return false;
+}
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_audio_sink_has_scmst
+ **
+ ** Description      Check if a sink supports SCMS-T
+ **
+ ** Returns          true if the sink supports this CP, false otherwise
+ **
+ *******************************************************************************/
+static bool bta_av_co_audio_sink_has_scmst(const tBTA_AV_CO_SINK* p_sink) {
+  uint8_t index;
+  const uint8_t* p;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  /* Check if sink supports SCMS-T */
+  index = p_sink->num_protect;
+  p = &p_sink->protect_info[0];
+
+  while (index) {
+    if (bta_av_co_cp_is_scmst(p)) return true;
+    /* Move to the next SC */
+    p += *p + 1;
+    /* Decrement the SC counter */
+    index--;
+  }
+  APPL_TRACE_DEBUG("%s: SCMS-T not found", __func__);
+  return false;
+}
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_audio_sink_supports_cp
+ **
+ ** Description      Check if a sink supports the current content protection
+ **
+ ** Returns          true if the sink supports this CP, false otherwise
+ **
+ *******************************************************************************/
+static bool bta_av_co_audio_sink_supports_cp(const tBTA_AV_CO_SINK* p_sink) {
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  /* Check if content protection is enabled for this stream */
+  if (bta_av_co_cp_get_flag() != AVDT_CP_SCMS_COPY_FREE)
+    return bta_av_co_audio_sink_has_scmst(p_sink);
+
+  APPL_TRACE_DEBUG("%s: not required", __func__);
+  return true;
+}
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_find_peer_sink_supports_codec
+ **
+ ** Description      Find a peer acting as a sink that suppors codec config
+ **
+ ** Returns          The peer sink that supports the codec, otherwise NULL.
+ **
+ *******************************************************************************/
+static const tBTA_AV_CO_SINK* bta_av_co_find_peer_sink_supports_codec(
+    const uint8_t* codec_config, const tBTA_AV_CO_PEER* p_peer) {
+  APPL_TRACE_DEBUG("%s: peer num_sup_sinks = %d", __func__,
+                   p_peer->num_sup_sinks);
+
+  for (size_t index = 0; index < p_peer->num_sup_sinks; index++) {
+    if (A2DP_CodecConfigMatchesCapabilities(codec_config,
+                                            p_peer->sinks[index].codec_caps)) {
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+      if (!bta_av_co_audio_sink_has_scmst(&p_peer->sinks[index]))
+          continue;
+#endif
+      return &p_peer->sinks[index];
+    }
+  }
+  return NULL;
+}
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_find_peer_src_supports_codec
+ **
+ ** Description      Find a peer acting as src that supports codec config
+ **
+ ** Returns          The peer source that supports the codec, otherwise NULL.
+ **
+ *******************************************************************************/
+static const tBTA_AV_CO_SINK* bta_av_co_find_peer_src_supports_codec(
+    const tBTA_AV_CO_PEER* p_peer) {
+  APPL_TRACE_DEBUG("%s: peer num_sup_srcs = %d", __func__,
+                   p_peer->num_sup_srcs);
+
+  for (size_t index = 0; index < p_peer->num_sup_srcs; index++) {
+    const uint8_t* p_codec_caps = p_peer->srcs[index].codec_caps;
+    if (A2DP_CodecTypeEquals(bta_av_co_cb.codec_config, p_codec_caps) &&
+        A2DP_IsPeerSourceCodecSupported(p_codec_caps)) {
+      return &p_peer->srcs[index];
+    }
+  }
+  return NULL;
+}
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_audio_set_codec
+ **
+ ** Description      Set the current codec configuration from the feeding type.
+ **                  This function is starting to modify the configuration, it
+ **                  should be protected.
+ **
+ ** Returns          true if successful, false otherwise
+ **
+ *******************************************************************************/
+bool bta_av_co_audio_set_codec(const tA2DP_FEEDING_PARAMS* p_feeding_params) {
+  uint8_t new_config[AVDT_CODEC_SIZE];
+
+  /* Protect access to bta_av_co_cb.codec_config */
+  mutex_global_lock();
+
+  // Initial strawman codec selection mechanism: largest codec SEP index first.
+  // TODO: Replace this mechanism with a better one.
+  for (int i = A2DP_CODEC_SEP_INDEX_SOURCE_MAX - 1;
+       i >= A2DP_CODEC_SEP_INDEX_SOURCE_MIN; i--) {
+    tA2DP_CODEC_SEP_INDEX source_codec_sep_index =
+      static_cast<tA2DP_CODEC_SEP_INDEX>(i);
+    APPL_TRACE_DEBUG("%s: trying codec %s with sep_index %d", __func__,
+                     A2DP_CodecSepIndexStr(source_codec_sep_index), i);
+    if (!A2DP_SetSourceCodec(source_codec_sep_index, p_feeding_params,
+                             new_config)) {
+      APPL_TRACE_DEBUG("%s: cannot setup source codec %s", __func__,
+                       A2DP_CodecSepIndexStr(source_codec_sep_index));
+      continue;
+    }
+
+    /* Try to select an open device for the codec */
+    if (bta_av_co_audio_codec_selected(new_config)) {
+      APPL_TRACE_DEBUG("%s: selected codec %s with sep_index %d", __func__,
+                       A2DP_CodecSepIndexStr(source_codec_sep_index), i);
+      mutex_global_unlock();
+      return true;
+    }
+    APPL_TRACE_DEBUG("%s: cannot select source codec %s", __func__,
+                     A2DP_CodecSepIndexStr(source_codec_sep_index));
+  }
+  mutex_global_unlock();
+  return false;
+}
+
+// Select an open device for the given codec info.
+// Return true if an open device was selected, otherwise false.
+static bool bta_av_co_audio_codec_selected(const uint8_t* codec_config) {
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  /* Check AV feeding is supported */
+  for (uint8_t index = 0; index < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers);
+       index++) {
+    uint8_t peer_codec_config[AVDT_CODEC_SIZE];
+
+    tBTA_AV_CO_PEER* p_peer = &bta_av_co_cb.peers[index];
+    if (!p_peer->opened) continue;
+
+    const tBTA_AV_CO_SINK* p_sink =
+      bta_av_co_find_peer_sink_supports_codec(codec_config, p_peer);
+    if (p_sink == NULL) {
+      APPL_TRACE_DEBUG("%s: index %d doesn't support codec", __func__, index);
+      continue;
+    }
+
+    /* Check that this sink is compatible with the CP */
+    if (!bta_av_co_audio_sink_supports_cp(p_sink)) {
+      APPL_TRACE_DEBUG("%s: sink of peer %d doesn't support cp", __func__,
+                       index);
+      continue;
+    }
+
+    /* Build the codec configuration for this sink */
+    memset(peer_codec_config, 0, AVDT_CODEC_SIZE);
+    if (A2DP_BuildSinkConfig(codec_config, p_sink->codec_caps,
+                             peer_codec_config) != A2DP_SUCCESS) {
+      continue;
+    }
+
+    /* The new config was correctly built and selected */
+    memcpy(bta_av_co_cb.codec_config, codec_config,
+           sizeof(bta_av_co_cb.codec_config));
+
+    /* Save the new configuration */
+    uint8_t num_protect = 0;
+    p_peer->p_sink = p_sink;
+    memcpy(p_peer->codec_config, peer_codec_config, AVDT_CODEC_SIZE);
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+    /* Check if this sink supports SCMS */
+    bool cp_active = bta_av_co_audio_sink_has_scmst(p_sink);
+    bta_av_co_cb.cp.active = cp_active;
+    p_peer->cp_active = cp_active;
+    if (p_peer->cp_active) num_protect = AVDT_CP_INFO_LEN;
+#endif
+    APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(0x%x)", __func__,
+                     BTA_AV_CO_AUDIO_INDX_TO_HNDL(index));
+    BTA_AvReconfig(BTA_AV_CO_AUDIO_INDX_TO_HNDL(index), true,
+                   p_sink->sep_info_idx, p_peer->codec_config, num_protect,
+                   bta_av_co_cp_scmst);
+    return true;
+  }
+
+  return false;
+}
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_audio_codec_reset
+ **
+ ** Description      Reset the current codec configuration
+ **
+ ** Returns          void
+ **
+ *******************************************************************************/
+static void bta_av_co_audio_codec_reset(void) {
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  mutex_global_lock();
+
+  /* Reset the current configuration to the default codec */
+  A2DP_InitDefaultCodec(bta_av_co_cb.codec_config);
+
+  mutex_global_unlock();
+}
+
+void bta_av_co_audio_encoder_init(tA2DP_ENCODER_INIT_PARAMS* p_init_params) {
+  uint16_t min_mtu = 0xFFFF;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+  assert(p_init_params != nullptr);
+
+  /* Protect access to bta_av_co_cb.codec_config */
+  mutex_global_lock();
+
+  /* Compute the MTU */
+  for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers); i++) {
+    const tBTA_AV_CO_PEER* p_peer = &bta_av_co_cb.peers[i];
+    if (!p_peer->opened) continue;
+    if (p_peer->mtu < min_mtu) min_mtu = p_peer->mtu;
+  }
+
+  const uint8_t* p_codec_info = bta_av_co_cb.codec_config;
+  p_init_params->NumOfSubBands = A2DP_GetNumberOfSubbands(p_codec_info);
+  p_init_params->NumOfBlocks = A2DP_GetNumberOfBlocks(p_codec_info);
+  p_init_params->AllocationMethod = A2DP_GetAllocationMethodCode(p_codec_info);
+  p_init_params->ChannelMode = A2DP_GetChannelModeCode(p_codec_info);
+  p_init_params->SamplingFreq = A2DP_GetSamplingFrequencyCode(p_codec_info);
+  p_init_params->MtuSize = min_mtu;
+
+  /* Protect access to bta_av_co_cb.codec_config */
+  mutex_global_unlock();
+}
+
+void bta_av_co_audio_encoder_update(
+    tA2DP_ENCODER_UPDATE_PARAMS* p_update_params) {
+  uint16_t min_mtu = 0xFFFF;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+  assert(p_update_params != nullptr);
+
+  /* Protect access to bta_av_co_cb.codec_config */
+  mutex_global_lock();
+
+  const uint8_t* p_codec_info = bta_av_co_cb.codec_config;
+  int min_bitpool = A2DP_GetMinBitpool(p_codec_info);
+  int max_bitpool = A2DP_GetMaxBitpool(p_codec_info);
+
+  if ((min_bitpool < 0) || (max_bitpool < 0)) {
+    APPL_TRACE_ERROR("%s: Invalid min/max bitpool: [%d, %d]", __func__,
+                     min_bitpool, max_bitpool);
+    mutex_global_unlock();
+    return;
+  }
+
+  for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers); i++) {
+    const tBTA_AV_CO_PEER* p_peer = &bta_av_co_cb.peers[i];
+    if (!p_peer->opened) continue;
+
+    if (p_peer->mtu < min_mtu) min_mtu = p_peer->mtu;
+
+    for (int j = 0; j < p_peer->num_sup_sinks; j++) {
+      const tBTA_AV_CO_SINK* p_sink = &p_peer->sinks[j];
+      if (!A2DP_CodecTypeEquals(p_codec_info, p_sink->codec_caps)) continue;
+      /* Update the bitpool boundaries of the current config */
+      int peer_min_bitpool = A2DP_GetMinBitpool(p_sink->codec_caps);
+      int peer_max_bitpool = A2DP_GetMaxBitpool(p_sink->codec_caps);
+      if (peer_min_bitpool >= 0)
+        min_bitpool = BTA_AV_CO_MAX(min_bitpool, peer_min_bitpool);
+      if (peer_max_bitpool >= 0)
+        max_bitpool = BTA_AV_CO_MIN(max_bitpool, peer_max_bitpool);
+      APPL_TRACE_EVENT("%s: sink bitpool min %d, max %d", __func__, min_bitpool,
+                       max_bitpool);
+      break;
+    }
+  }
+
+  /*
+   * Check if the remote Sink has a preferred bitpool range.
+   * Adjust our preferred bitpool with the remote preference if within
+   * our capable range.
+   */
+  if (A2DP_IsSourceCodecValid(bta_av_co_cb.codec_config_setconfig) &&
+      A2DP_CodecTypeEquals(p_codec_info, bta_av_co_cb.codec_config_setconfig)) {
+    int setconfig_min_bitpool =
+        A2DP_GetMinBitpool(bta_av_co_cb.codec_config_setconfig);
+    int setconfig_max_bitpool =
+        A2DP_GetMaxBitpool(bta_av_co_cb.codec_config_setconfig);
+    if (setconfig_min_bitpool >= 0)
+      min_bitpool = BTA_AV_CO_MAX(min_bitpool, setconfig_min_bitpool);
+    if (setconfig_max_bitpool >= 0)
+      max_bitpool = BTA_AV_CO_MIN(max_bitpool, setconfig_max_bitpool);
+    APPL_TRACE_EVENT("%s: sink adjusted bitpool min %d, max %d", __func__,
+                     min_bitpool, max_bitpool);
+  }
+
+  /* Protect access to bta_av_co_cb.codec_config */
+  mutex_global_unlock();
+
+  if (min_bitpool > max_bitpool) {
+    APPL_TRACE_ERROR("%s: Irrational min/max bitpool: [%d, %d]", __func__,
+                     min_bitpool, max_bitpool);
+    return;
+  }
+
+  p_update_params->MinMtuSize = min_mtu;
+  p_update_params->MinBitPool = min_bitpool;
+  p_update_params->MaxBitPool = max_bitpool;
+}
+
+const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface(void) {
+  /* Protect access to bta_av_co_cb.codec_config */
+  mutex_global_lock();
+
+  const tA2DP_ENCODER_INTERFACE* encoder_interface =
+      A2DP_GetEncoderInterface(bta_av_co_cb.codec_config);
+
+  /* Protect access to bta_av_co_cb.codec_config */
+  mutex_global_unlock();
+
+  return encoder_interface;
+}
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_init
+ **
+ ** Description      Initialization
+ **
+ ** Returns          Nothing
+ **
+ *******************************************************************************/
+void bta_av_co_init(void) {
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  /* Reset the control block */
+  memset(&bta_av_co_cb, 0, sizeof(bta_av_co_cb));
+
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+  bta_av_co_cp_set_flag(AVDT_CP_SCMS_COPY_NEVER);
+#else
+  bta_av_co_cp_set_flag(AVDT_CP_SCMS_COPY_FREE);
+#endif
+
+  /* Reset the current config */
+  bta_av_co_audio_codec_reset();
+}
diff --git a/bt/btif/co/bta_dm_co.cc b/bt/btif/co/bta_dm_co.cc
new file mode 100644
index 0000000..81d29f3
--- /dev/null
+++ b/bt/btif/co/bta_dm_co.cc
@@ -0,0 +1,419 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "bt_utils.h"
+#include "bta_api.h"
+#include "bta_dm_ci.h"
+#include "bta_dm_co.h"
+#include "bta_sys.h"
+#include "btif_dm.h"
+#include "osi/include/osi.h"
+#if (BLE_INCLUDED == TRUE)
+#include "bte_appl.h"
+
+tBTE_APPL_CFG bte_appl_cfg = {
+#if (SMP_INCLUDED == TRUE)
+    BTA_LE_AUTH_REQ_SC_MITM_BOND,  // Authentication requirements
+#else
+    BTM_AUTH_SPGB_YES,  // Authentication requirements
+#endif
+    BTM_LOCAL_IO_CAPS_BLE, BTM_BLE_INITIATOR_KEY_SIZE,
+    BTM_BLE_RESPONDER_KEY_SIZE, BTM_BLE_MAX_KEY_SIZE};
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_co_get_compress_memory
+ *
+ * Description      This callout function is executed by DM to get memory for
+ compression
+
+ * Parameters       id  -  BTA SYS ID
+ *                  memory_p - memory return by callout
+ *                  memory_size - memory size
+ *
+ * Returns          true for success, false for fail.
+ *
+ ******************************************************************************/
+bool bta_dm_co_get_compress_memory(UNUSED_ATTR tBTA_SYS_ID id, UNUSED_ATTR uint8_t **memory_p,
+                                   UNUSED_ATTR uint32_t *memory_size) {
+  return true;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_co_io_req
+ *
+ * Description      This callout function is executed by DM to get IO
+ *                  capabilities of the local device for the Simple Pairing
+ *                  process.
+ *
+ * Parameters       bd_addr  - The peer device
+ *                  *p_io_cap - The local Input/Output capabilities
+ *                  *p_oob_data - true, if OOB data is available for the peer
+ *                                device.
+ *                  *p_auth_req - true, if MITM protection is required.
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+void bta_dm_co_io_req(UNUSED_ATTR BD_ADDR bd_addr, tBTA_IO_CAP* p_io_cap,
+                      tBTA_OOB_DATA* p_oob_data, tBTA_AUTH_REQ* p_auth_req,
+                      bool is_orig) {
+  btif_dm_set_oob_for_io_req(p_oob_data);
+  btif_dm_proc_io_req(bd_addr, p_io_cap, p_oob_data, p_auth_req, is_orig);
+  BTIF_TRACE_DEBUG("bta_dm_co_io_req *p_oob_data = %d", *p_oob_data);
+  BTIF_TRACE_DEBUG("bta_dm_co_io_req *p_io_cap = %d", *p_io_cap);
+  BTIF_TRACE_DEBUG("bta_dm_co_io_req *p_auth_req = %d", *p_auth_req);
+  BTIF_TRACE_DEBUG("bta_dm_co_io_req is_orig = %d", is_orig);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_co_io_rsp
+ *
+ * Description      This callout function is executed by DM to report IO
+ *                  capabilities of the peer device for the Simple Pairing
+ *                  process.
+ *
+ * Parameters       bd_addr  - The peer device
+ *                  io_cap - The remote Input/Output capabilities
+ *                  oob_data - true, if OOB data is available for the peer
+ *                             device.
+ *                  auth_req - true, if MITM protection is required.
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+void bta_dm_co_io_rsp(BD_ADDR bd_addr, tBTA_IO_CAP io_cap,
+                      tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req) {
+  btif_dm_proc_io_rsp(bd_addr, io_cap, oob_data, auth_req);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_co_lk_upgrade
+ *
+ * Description      This callout function is executed by DM to check if the
+ *                  platform wants allow link key upgrade
+ *
+ * Parameters       bd_addr  - The peer device
+ *                  *p_upgrade - true, if link key upgrade is desired.
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+void bta_dm_co_lk_upgrade(UNUSED_ATTR BD_ADDR bd_addr,
+                          UNUSED_ATTR bool *p_upgrade) {
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_co_loc_oob
+ *
+ * Description      This callout function is executed by DM to report the OOB
+ *                  data of the local device for the Simple Pairing process
+ *
+ * Parameters       valid - true, if the local OOB data is retrieved from LM
+ *                  c     - Simple Pairing Hash C
+ *                  r     - Simple Pairing Randomnizer R
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+void bta_dm_co_loc_oob(bool valid, BT_OCTET16 c, BT_OCTET16 r) {
+  BTIF_TRACE_DEBUG("bta_dm_co_loc_oob, valid = %d", valid);
+#ifdef BTIF_DM_OOB_TEST
+  btif_dm_proc_loc_oob(valid, c, r);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_co_rmt_oob
+ *
+ * Description      This callout function is executed by DM to request the OOB
+ *                  data for the remote device for the Simple Pairing process
+ *                  Need to call bta_dm_ci_rmt_oob() in response
+ *
+ * Parameters       bd_addr  - The peer device
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+void bta_dm_co_rmt_oob(BD_ADDR bd_addr) {
+  BT_OCTET16 p_c;
+  BT_OCTET16 p_r;
+  bool result = false;
+
+#ifdef BTIF_DM_OOB_TEST
+  result = btif_dm_proc_rmt_oob(bd_addr, p_c, p_r);
+#endif
+
+  BTIF_TRACE_DEBUG("bta_dm_co_rmt_oob: result=%d", result);
+  bta_dm_ci_rmt_oob(result, bd_addr, p_c, p_r);
+}
+
+// REMOVE FOR BLUEDROID ?
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTM_SCO_INCLUDED == TRUE)
+
+/*******************************************************************************
+ *
+ * Function         btui_sco_codec_callback
+ *
+ * Description      Callback for btui codec.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btui_sco_codec_callback(uint16_t event, uint16_t sco_handle) {
+  bta_dm_sco_ci_data_ready(event, sco_handle);
+}
+/*******************************************************************************
+ *
+ * Function         bta_dm_sco_co_init
+ *
+ * Description      This function can be used by the phone to initialize audio
+ *                  codec or for other initialization purposes before SCO
+ *                  connection is opened.
+ *
+ *
+ * Returns          tBTA_DM_SCO_ROUTE_TYPE: SCO routing configuration type.
+ *
+ ******************************************************************************/
+tBTA_DM_SCO_ROUTE_TYPE bta_dm_sco_co_init(uint32_t rx_bw, uint32_t tx_bw,
+                                          tBTA_CODEC_INFO* p_codec_type,
+                                          uint8_t app_id) {
+  tBTM_SCO_ROUTE_TYPE route = BTA_DM_SCO_ROUTE_PCM;
+
+  BTIF_TRACE_DEBUG("bta_dm_sco_co_init");
+
+  /* set up SCO routing configuration if SCO over HCI app ID is used and run
+     time
+      configuration is set to SCO over HCI */
+  /* HS invoke this call-out */
+  if (
+#if (BTA_HS_INCLUDED == TRUE)
+      (app_id == BTUI_DM_SCO_4_HS_APP_ID && btui_cfg.hs_sco_over_hci) ||
+#endif
+      /* AG invoke this call-out */
+      (app_id != BTUI_DM_SCO_4_HS_APP_ID && btui_cfg.ag_sco_over_hci)) {
+    route = btui_cb.sco_hci = BTA_DM_SCO_ROUTE_HCI;
+  }
+  /* no codec is is used for the SCO data */
+  if (p_codec_type->codec_type == BTA_SCO_CODEC_PCM &&
+      route == BTA_DM_SCO_ROUTE_HCI) {
+    /* initialize SCO codec */
+    if (!btui_sco_codec_init(rx_bw, tx_bw)) {
+      BTIF_TRACE_ERROR("codec initialization exception!");
+    }
+  }
+
+  return route;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_sco_co_open
+ *
+ * Description      This function is executed when a SCO connection is open.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_sco_co_open(uint16_t handle, uint8_t pkt_size, uint16_t event) {
+  tBTUI_SCO_CODEC_CFG cfg;
+
+  if (btui_cb.sco_hci) {
+    BTIF_TRACE_DEBUG("bta_dm_sco_co_open handle:%d pkt_size:%d", handle,
+                     pkt_size);
+    cfg.p_cback = btui_sco_codec_callback;
+    cfg.pkt_size = pkt_size;
+    cfg.cb_event = event;
+    /* open and start the codec */
+    btui_sco_codec_open(&cfg);
+    btui_sco_codec_start(handle);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_sco_co_close
+ *
+ * Description      This function is called when a SCO connection is closed
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_sco_co_close(void) {
+  if (btui_cb.sco_hci) {
+    BTIF_TRACE_DEBUG("bta_dm_sco_co_close close codec");
+    /* close sco codec */
+    btui_sco_codec_close();
+
+    btui_cb.sco_hci = false;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_sco_co_in_data
+ *
+ * Description      This function is called to send incoming SCO data to
+ *                  application.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_sco_co_in_data(BT_HDR* p_buf) {
+  if (btui_cfg.sco_use_mic)
+    btui_sco_codec_inqdata(p_buf);
+  else
+    osi_free(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_sco_co_out_data
+ *
+ * Description      This function is called to send SCO data over HCI.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_dm_sco_co_out_data(BT_HDR** p_buf) { btui_sco_codec_readbuf(p_buf); }
+
+#endif /* (BTM_SCO_HCI_INCLUDED == TRUE) && (BTM_SCO_INCLUDED == TRUE)*/
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_dm_co_le_io_key_req
+ *
+ * Description      This callout function is executed by DM to get BLE key
+ *                  information
+ *                  before SMP pairing gets going.
+ *
+ * Parameters       bd_addr  - The peer device
+ *                  *p_max_key_size - max key size local device supported.
+ *                  *p_init_key - initiator keys.
+ *                  *p_resp_key - responder keys.
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+void bta_dm_co_le_io_key_req(UNUSED_ATTR BD_ADDR bd_addr, uint8_t* p_max_key_size,
+                             tBTA_LE_KEY_TYPE* p_init_key,
+                             tBTA_LE_KEY_TYPE* p_resp_key) {
+  BTIF_TRACE_ERROR("##################################");
+  BTIF_TRACE_ERROR("bta_dm_co_le_io_key_req: only setting max size to 16");
+  BTIF_TRACE_ERROR("##################################");
+  *p_max_key_size = 16;
+  *p_init_key = *p_resp_key =
+      (BTA_LE_KEY_PENC | BTA_LE_KEY_PID | BTA_LE_KEY_PCSRK | BTA_LE_KEY_LENC |
+       BTA_LE_KEY_LID | BTA_LE_KEY_LCSRK);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_co_ble_local_key_reload
+ *
+ * Description      This callout function is to load the local BLE keys if
+ *                  available on the device.
+ *
+ * Parameters       none
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+void bta_dm_co_ble_load_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask,
+                                   BT_OCTET16 er,
+                                   tBTA_BLE_LOCAL_ID_KEYS* p_id_keys) {
+  BTIF_TRACE_DEBUG("##################################");
+  BTIF_TRACE_DEBUG(
+      "bta_dm_co_ble_load_local_keys:  Load local keys if any are persisted");
+  BTIF_TRACE_DEBUG("##################################");
+  btif_dm_get_ble_local_keys(p_key_mask, er, p_id_keys);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_dm_co_ble_io_req
+ *
+ * Description      This callout function is executed by DM to get BLE IO
+ *                  capabilities before SMP pairing gets going.
+ *
+ * Parameters       bd_addr  - The peer device
+ *                  *p_io_cap - The local Input/Output capabilities
+ *                  *p_oob_data - true, if OOB data is available for the peer
+ *                                device.
+ *                  *p_auth_req -  Auth request setting (Bonding and MITM
+ *                                 required or not)
+ *                  *p_max_key_size - max key size local device supported.
+ *                  *p_init_key - initiator keys.
+ *                  *p_resp_key - responder keys.
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+void bta_dm_co_ble_io_req(UNUSED_ATTR BD_ADDR bd_addr, tBTA_IO_CAP* p_io_cap,
+                          tBTA_OOB_DATA* p_oob_data,
+                          tBTA_LE_AUTH_REQ* p_auth_req, uint8_t* p_max_key_size,
+                          tBTA_LE_KEY_TYPE* p_init_key,
+                          tBTA_LE_KEY_TYPE* p_resp_key) {
+  /* Retrieve the properties from file system if possible */
+  tBTE_APPL_CFG nv_config;
+  if (btif_dm_get_smp_config(&nv_config)) bte_appl_cfg = nv_config;
+
+  /* *p_auth_req by default is false for devices with NoInputNoOutput; true for
+   * other devices. */
+
+  if (bte_appl_cfg.ble_auth_req)
+    *p_auth_req = bte_appl_cfg.ble_auth_req |
+                  (bte_appl_cfg.ble_auth_req & 0x04) | ((*p_auth_req) & 0x04);
+
+  /* if OOB is not supported, this call-out function does not need to do
+   * anything
+   * otherwise, look for the OOB data associated with the address and set
+   * *p_oob_data accordingly.
+   * If the answer can not be obtained right away,
+   * set *p_oob_data to BTA_OOB_UNKNOWN and call bta_dm_ci_io_req() when the
+   * answer is available.
+   */
+
+  btif_dm_set_oob_for_le_io_req(bd_addr, p_oob_data, p_auth_req);
+
+  if (bte_appl_cfg.ble_io_cap <= 4) *p_io_cap = bte_appl_cfg.ble_io_cap;
+
+  if (bte_appl_cfg.ble_init_key <= BTM_BLE_INITIATOR_KEY_SIZE)
+    *p_init_key = bte_appl_cfg.ble_init_key;
+
+  if (bte_appl_cfg.ble_resp_key <= BTM_BLE_RESPONDER_KEY_SIZE)
+    *p_resp_key = bte_appl_cfg.ble_resp_key;
+
+  if (bte_appl_cfg.ble_max_key_size > 7 && bte_appl_cfg.ble_max_key_size <= 16)
+    *p_max_key_size = bte_appl_cfg.ble_max_key_size;
+}
+
+#endif
diff --git a/bt/btif/co/bta_gatts_co.cc b/bt/btif/co/bta_gatts_co.cc
new file mode 100644
index 0000000..21ec77d
--- /dev/null
+++ b/bt/btif/co/bta_gatts_co.cc
@@ -0,0 +1,150 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+
+#if (BLE_INCLUDED == TRUE) && (BTA_GATT_INCLUDED == TRUE)
+
+#include <stdlib.h>
+#include <string.h>
+#include "bt_common.h"
+#include "bta_gatts_co.h"
+#include "btif_util.h"
+#include "osi/include/osi.h"
+
+/*****************************************************************************
+ *  Local type definitions
+ ****************************************************************************/
+
+#define BTIF_GATTS_MAX_SRV_CHG_CLT_SIZE 50
+
+typedef struct {
+  bool enable;
+  uint8_t num_clients;
+  tBTA_GATTS_SRV_CHG srv_chg[BTIF_GATTS_MAX_SRV_CHG_CLT_SIZE];
+} __attribute__((packed)) btif_gatts_srv_chg_cb_t;
+
+/*****************************************************************************
+ *  Static variables
+ ****************************************************************************/
+
+static btif_gatts_srv_chg_cb_t btif_gatts_srv_chg_cb;
+
+/*****************************************************************************
+ *  Static functions
+ ****************************************************************************/
+
+static void btif_gatts_check_init(void) {
+  btif_gatts_srv_chg_cb_t* p_cb = &btif_gatts_srv_chg_cb;
+
+  if (!p_cb->enable) {
+    memset(p_cb, 0, sizeof(btif_gatts_srv_chg_cb_t));
+    p_cb->enable = true;
+  }
+}
+
+/*****************************************************************************
+ *  Externally called functions
+ ****************************************************************************/
+
+void btif_gatts_add_bonded_dev_from_nv(BD_ADDR bda) {
+  btif_gatts_srv_chg_cb_t* p_cb = &btif_gatts_srv_chg_cb;
+  bool found = false;
+  uint8_t i;
+
+  btif_gatts_check_init();
+
+  for (i = 0; i != p_cb->num_clients; ++i) {
+    if (!memcmp(p_cb->srv_chg[i].bda, bda, sizeof(BD_ADDR))) {
+      found = true;
+      break;
+    }
+  }
+
+  if (!found) {
+    if (p_cb->num_clients < BTIF_GATTS_MAX_SRV_CHG_CLT_SIZE) {
+      bdcpy(p_cb->srv_chg[p_cb->num_clients].bda, bda);
+      p_cb->srv_chg[p_cb->num_clients].srv_changed = false;
+      p_cb->num_clients++;
+    }
+  }
+}
+
+/*****************************************************************************
+ *  Call-out functions
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         bta_gatts_co_update_handle_range
+ *
+ * Description      This callout function is executed by GATTS when a GATT
+ *                  server handle range ios to be added or removed.
+ *
+ * Parameter        is_add: true is to add a handle range; otherwise is to
+ *                          delete.
+ *                  p_hndl_range: handle range.
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+void bta_gatts_co_update_handle_range(UNUSED_ATTR bool is_add,
+                                      UNUSED_ATTR tBTA_GATTS_HNDL_RANGE *p_hndl_range) {
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gatts_co_srv_chg
+ *
+ * Description      This call-out is to read/write/remove service change related
+ *                  informaiton. The request consists of the cmd and p_req and
+ *                  the response is returned in p_rsp
+ *
+ * Parameter        cmd - request command
+ *                  p_req - request paramters
+ *                  p_rsp - response data for the request
+ *
+ * Returns          true - if the request is processed successfully and
+ *                         the response is returned in p_rsp.
+ *                  false - if the request can not be processed
+ *
+ ******************************************************************************/
+bool bta_gatts_co_srv_chg(UNUSED_ATTR tBTA_GATTS_SRV_CHG_CMD cmd,
+                          UNUSED_ATTR tBTA_GATTS_SRV_CHG_REQ *p_req,
+                          UNUSED_ATTR tBTA_GATTS_SRV_CHG_RSP *p_rsp) {
+  return false;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_gatts_co_load_handle_range
+ *
+ * Description      This callout function is executed by GATTS when a GATT
+ *                  server handle range is requested to be loaded from NV.
+ *
+ * Parameter
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+bool bta_gatts_co_load_handle_range(UNUSED_ATTR uint8_t index,
+                                    UNUSED_ATTR tBTA_GATTS_HNDL_RANGE *p_handle_range) {
+  return false;
+}
+
+#endif  // BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE
diff --git a/bt/btif/co/bta_hh_co.cc b/bt/btif/co/bta_hh_co.cc
new file mode 100644
index 0000000..19ccdf6
--- /dev/null
+++ b/bt/btif/co/bta_hh_co.cc
@@ -0,0 +1,609 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/uhid.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/poll.h>
+#include <unistd.h>
+
+#include "bta_api.h"
+#include "bta_hh_api.h"
+#include "bta_hh_co.h"
+#include "btcore/include/bdaddr.h"
+#include "btif_hh.h"
+#include "btif_util.h"
+#include "osi/include/osi.h"
+
+const char* dev_path = "/dev/uhid";
+
+#if (BLE_INCLUDED == TRUE && BTA_HH_LE_INCLUDED == TRUE)
+#include "btif_config.h"
+#define BTA_HH_NV_LOAD_MAX 16
+static tBTA_HH_RPT_CACHE_ENTRY sReportCache[BTA_HH_NV_LOAD_MAX];
+#endif
+
+void uhid_set_non_blocking(int fd) {
+  int opts = fcntl(fd, F_GETFL);
+  if (opts < 0)
+    APPL_TRACE_ERROR("%s() Getting flags failed (%s)", __func__,
+                     strerror(errno));
+
+  opts |= O_NONBLOCK;
+
+  if (fcntl(fd, F_SETFL, opts) < 0)
+    APPL_TRACE_EVENT("%s() Setting non-blocking flag failed (%s)", __func__,
+                     strerror(errno));
+}
+
+/*Internal function to perform UHID write and error checking*/
+static int uhid_write(int fd, const struct uhid_event* ev) {
+  ssize_t ret;
+  OSI_NO_INTR(ret = write(fd, ev, sizeof(*ev)));
+
+  if (ret < 0) {
+    int rtn = -errno;
+    APPL_TRACE_ERROR("%s: Cannot write to uhid:%s", __func__, strerror(errno));
+    return rtn;
+  } else if (ret != (ssize_t)sizeof(*ev)) {
+    APPL_TRACE_ERROR("%s: Wrong size written to uhid: %zd != %zu", __func__,
+                     ret, sizeof(*ev));
+    return -EFAULT;
+  }
+
+  return 0;
+}
+
+/* Internal function to parse the events received from UHID driver*/
+static int uhid_read_event(btif_hh_device_t* p_dev) {
+  assert(p_dev);
+
+  struct uhid_event ev;
+  memset(&ev, 0, sizeof(ev));
+
+  ssize_t ret;
+  OSI_NO_INTR(ret = read(p_dev->fd, &ev, sizeof(ev)));
+
+  if (ret == 0) {
+    APPL_TRACE_ERROR("%s: Read HUP on uhid-cdev %s", __func__, strerror(errno));
+    return -EFAULT;
+  } else if (ret < 0) {
+    APPL_TRACE_ERROR("%s: Cannot read uhid-cdev: %s", __func__,
+                     strerror(errno));
+    return -errno;
+  }
+
+  switch (ev.type) {
+    case UHID_START:
+      APPL_TRACE_DEBUG("UHID_START from uhid-dev\n");
+      p_dev->ready_for_data = true;
+      break;
+    case UHID_STOP:
+      APPL_TRACE_DEBUG("UHID_STOP from uhid-dev\n");
+      p_dev->ready_for_data = false;
+      break;
+    case UHID_OPEN:
+      APPL_TRACE_DEBUG("UHID_OPEN from uhid-dev\n");
+      p_dev->ready_for_data = true;
+      break;
+    case UHID_CLOSE:
+      APPL_TRACE_DEBUG("UHID_CLOSE from uhid-dev\n");
+      p_dev->ready_for_data = false;
+      break;
+    case UHID_OUTPUT:
+      if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.output))) {
+        APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu",
+                         __func__, ret, sizeof(ev.type) + sizeof(ev.u.output));
+        return -EFAULT;
+      }
+
+      APPL_TRACE_DEBUG("UHID_OUTPUT: Report type = %d, report_size = %d",
+                       ev.u.output.rtype, ev.u.output.size);
+      // Send SET_REPORT with feature report if the report type in output event
+      // is FEATURE
+      if (ev.u.output.rtype == UHID_FEATURE_REPORT)
+        btif_hh_setreport(p_dev, BTHH_FEATURE_REPORT, ev.u.output.size,
+                          ev.u.output.data);
+      else if (ev.u.output.rtype == UHID_OUTPUT_REPORT)
+        btif_hh_setreport(p_dev, BTHH_OUTPUT_REPORT, ev.u.output.size,
+                          ev.u.output.data);
+      else
+        btif_hh_setreport(p_dev, BTHH_INPUT_REPORT, ev.u.output.size,
+                          ev.u.output.data);
+      break;
+    case UHID_OUTPUT_EV:
+      if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.output_ev))) {
+        APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu",
+                         __func__, ret,
+                         sizeof(ev.type) + sizeof(ev.u.output_ev));
+        return -EFAULT;
+      }
+      APPL_TRACE_DEBUG("UHID_OUTPUT_EV from uhid-dev\n");
+      break;
+    case UHID_FEATURE:
+      APPL_TRACE_DEBUG("UHID_FEATURE from uhid-dev\n");
+      break;
+    case UHID_FEATURE_ANSWER:
+      APPL_TRACE_DEBUG("UHID_FEATURE_ANSWER from uhid-dev\n");
+      break;
+
+    default:
+      APPL_TRACE_DEBUG("Invalid event from uhid-dev: %u\n", ev.type);
+  }
+
+  return 0;
+}
+
+/*******************************************************************************
+ *
+ * Function create_thread
+ *
+ * Description creat a select loop
+ *
+ * Returns pthread_t
+ *
+ ******************************************************************************/
+static inline pthread_t create_thread(void* (*start_routine)(void*),
+                                      void* arg) {
+  APPL_TRACE_DEBUG("create_thread: entered");
+  pthread_attr_t thread_attr;
+
+  pthread_attr_init(&thread_attr);
+  pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+  pthread_t thread_id = -1;
+  if (pthread_create(&thread_id, &thread_attr, start_routine, arg) != 0) {
+    APPL_TRACE_ERROR("pthread_create : %s", strerror(errno));
+    return -1;
+  }
+  APPL_TRACE_DEBUG("create_thread: thread created successfully");
+  return thread_id;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hh_poll_event_thread
+ *
+ * Description the polling thread which polls for event from UHID driver
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void* btif_hh_poll_event_thread(void* arg) {
+  btif_hh_device_t* p_dev = (btif_hh_device_t*)arg;
+  APPL_TRACE_DEBUG("%s: Thread created fd = %d", __func__, p_dev->fd);
+  struct pollfd pfds[1];
+
+  pfds[0].fd = p_dev->fd;
+  pfds[0].events = POLLIN;
+
+  // Set the uhid fd as non-blocking to ensure we never block the BTU thread
+  uhid_set_non_blocking(p_dev->fd);
+
+  while (p_dev->hh_keep_polling) {
+    int ret;
+    OSI_NO_INTR(ret = poll(pfds, 1, 50));
+    if (ret < 0) {
+      APPL_TRACE_ERROR("%s: Cannot poll for fds: %s\n", __func__,
+                       strerror(errno));
+      break;
+    }
+    if (pfds[0].revents & POLLIN) {
+      APPL_TRACE_DEBUG("%s: POLLIN", __func__);
+      ret = uhid_read_event(p_dev);
+      if (ret != 0) break;
+    }
+  }
+
+  p_dev->hh_poll_thread_id = -1;
+  return 0;
+}
+
+static inline void btif_hh_close_poll_thread(btif_hh_device_t* p_dev) {
+  APPL_TRACE_DEBUG("%s", __func__);
+  p_dev->hh_keep_polling = 0;
+  if (p_dev->hh_poll_thread_id > 0)
+    pthread_join(p_dev->hh_poll_thread_id, NULL);
+
+  return;
+}
+
+void bta_hh_co_destroy(int fd) {
+  struct uhid_event ev;
+  memset(&ev, 0, sizeof(ev));
+  ev.type = UHID_DESTROY;
+  uhid_write(fd, &ev);
+  APPL_TRACE_DEBUG("%s: Closing fd=%d", __func__, fd);
+  close(fd);
+}
+
+int bta_hh_co_write(int fd, uint8_t* rpt, uint16_t len) {
+  APPL_TRACE_DEBUG("%s: UHID write %d", __func__, len);
+
+  struct uhid_event ev;
+  memset(&ev, 0, sizeof(ev));
+  ev.type = UHID_INPUT;
+  ev.u.input.size = len;
+  if (len > sizeof(ev.u.input.data)) {
+    APPL_TRACE_WARNING("%s: Report size greater than allowed size", __func__);
+    return -1;
+  }
+  memcpy(ev.u.input.data, rpt, len);
+
+  return uhid_write(fd, &ev);
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hh_co_open
+ *
+ * Description   When connection is opened, this call-out function is executed
+ *               by HH to do platform specific initialization.
+ *
+ * Returns       void.
+ ******************************************************************************/
+void bta_hh_co_open(uint8_t dev_handle, uint8_t sub_class,
+                    tBTA_HH_ATTR_MASK attr_mask, uint8_t app_id) {
+  uint32_t i;
+  btif_hh_device_t* p_dev = NULL;
+
+  if (dev_handle == BTA_HH_INVALID_HANDLE) {
+    APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __func__,
+                       dev_handle);
+    return;
+  }
+
+  for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+    p_dev = &btif_hh_cb.devices[i];
+    if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN &&
+        p_dev->dev_handle == dev_handle) {
+      // We found a device with the same handle. Must be a device reconnected.
+      APPL_TRACE_WARNING(
+          "%s: Found an existing device with the same handle "
+          "dev_status = %d",
+          __func__, p_dev->dev_status);
+      APPL_TRACE_WARNING("%s:     bd_addr = [%02X:%02X:%02X:%02X:%02X:]",
+                         __func__, p_dev->bd_addr.address[0],
+                         p_dev->bd_addr.address[1], p_dev->bd_addr.address[2],
+                         p_dev->bd_addr.address[3], p_dev->bd_addr.address[4]);
+      APPL_TRACE_WARNING(
+          "%s:     attr_mask = 0x%04x, sub_class = 0x%02x, app_id = %d",
+          __func__, p_dev->attr_mask, p_dev->sub_class, p_dev->app_id);
+
+      if (p_dev->fd < 0) {
+        p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
+        if (p_dev->fd < 0) {
+          APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s", __func__,
+                           strerror(errno));
+          return;
+        } else
+          APPL_TRACE_DEBUG("%s: uhid fd = %d", __func__, p_dev->fd);
+      }
+
+      p_dev->hh_keep_polling = 1;
+      p_dev->hh_poll_thread_id =
+          create_thread(btif_hh_poll_event_thread, p_dev);
+      break;
+    }
+    p_dev = NULL;
+  }
+
+  if (p_dev == NULL) {
+    // Did not find a device reconnection case. Find an empty slot now.
+    for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+      if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_UNKNOWN) {
+        p_dev = &btif_hh_cb.devices[i];
+        p_dev->dev_handle = dev_handle;
+        p_dev->attr_mask = attr_mask;
+        p_dev->sub_class = sub_class;
+        p_dev->app_id = app_id;
+        p_dev->local_vup = false;
+
+        btif_hh_cb.device_num++;
+        // This is a new device,open the uhid driver now.
+        p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
+        if (p_dev->fd < 0) {
+          APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s", __func__,
+                           strerror(errno));
+          return;
+        } else {
+          APPL_TRACE_DEBUG("%s: uhid fd = %d", __func__, p_dev->fd);
+          p_dev->hh_keep_polling = 1;
+          p_dev->hh_poll_thread_id =
+              create_thread(btif_hh_poll_event_thread, p_dev);
+        }
+
+        break;
+      }
+    }
+  }
+
+  if (p_dev == NULL) {
+    APPL_TRACE_ERROR("%s: Error: too many HID devices are connected", __func__);
+    return;
+  }
+
+  p_dev->dev_status = BTHH_CONN_STATE_CONNECTED;
+  APPL_TRACE_DEBUG("%s: Return device status %d", __func__, p_dev->dev_status);
+}
+
+/*******************************************************************************
+ *
+ * Function      bta_hh_co_close
+ *
+ * Description   When connection is closed, this call-out function is executed
+ *               by HH to do platform specific finalization.
+ *
+ * Parameters    dev_handle  - device handle
+ *                  app_id      - application id
+ *
+ * Returns          void.
+ ******************************************************************************/
+void bta_hh_co_close(uint8_t dev_handle, uint8_t app_id) {
+  uint32_t i;
+  btif_hh_device_t* p_dev = NULL;
+
+  APPL_TRACE_WARNING("%s: dev_handle = %d, app_id = %d", __func__, dev_handle,
+                     app_id);
+  if (dev_handle == BTA_HH_INVALID_HANDLE) {
+    APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __func__,
+                       dev_handle);
+    return;
+  }
+
+  for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+    p_dev = &btif_hh_cb.devices[i];
+    if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN &&
+        p_dev->dev_handle == dev_handle) {
+      APPL_TRACE_WARNING(
+          "%s: Found an existing device with the same handle "
+          "dev_status = %d, dev_handle =%d",
+          __func__, p_dev->dev_status, p_dev->dev_handle);
+      btif_hh_close_poll_thread(p_dev);
+      break;
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_co_data
+ *
+ * Description      This function is executed by BTA when HID host receive a
+ *                  data report.
+ *
+ * Parameters       dev_handle  - device handle
+ *                  *p_rpt      - pointer to the report data
+ *                  len         - length of report data
+ *                  mode        - Hid host Protocol Mode
+ *                  sub_clas    - Device Subclass
+ *                  app_id      - application id
+ *
+ * Returns          void
+ ******************************************************************************/
+void bta_hh_co_data(uint8_t dev_handle, uint8_t* p_rpt, uint16_t len,
+                    tBTA_HH_PROTO_MODE mode, uint8_t sub_class,
+                    uint8_t ctry_code,
+                    UNUSED_ATTR BD_ADDR peer_addr, uint8_t app_id) {
+  btif_hh_device_t* p_dev;
+
+  APPL_TRACE_DEBUG(
+      "%s: dev_handle = %d, subclass = 0x%02X, mode = %d, "
+      "ctry_code = %d, app_id = %d",
+      __func__, dev_handle, sub_class, mode, ctry_code, app_id);
+
+  p_dev = btif_hh_find_connected_dev_by_handle(dev_handle);
+  if (p_dev == NULL) {
+    APPL_TRACE_WARNING("%s: Error: unknown HID device handle %d", __func__,
+                       dev_handle);
+    return;
+  }
+
+  // Wait a maximum of MAX_POLLING_ATTEMPTS x POLLING_SLEEP_DURATION in case
+  // device creation is pending.
+  if (p_dev->fd >= 0) {
+    uint32_t polling_attempts = 0;
+    while (!p_dev->ready_for_data &&
+           polling_attempts++ < BTIF_HH_MAX_POLLING_ATTEMPTS) {
+      usleep(BTIF_HH_POLLING_SLEEP_DURATION_US);
+    }
+  }
+
+  // Send the HID data to the kernel.
+  if ((p_dev->fd >= 0) && p_dev->ready_for_data) {
+    bta_hh_co_write(p_dev->fd, p_rpt, len);
+  } else {
+    APPL_TRACE_WARNING("%s: Error: fd = %d, ready %d, len = %d", __func__,
+                       p_dev->fd, p_dev->ready_for_data, len);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_co_send_hid_info
+ *
+ * Description      This function is called in btif_hh.c to process DSCP
+ *                  received.
+ *
+ * Parameters       dev_handle  - device handle
+ *                  dscp_len    - report descriptor length
+ *                  *p_dscp     - report descriptor
+ *
+ * Returns          void
+ ******************************************************************************/
+void bta_hh_co_send_hid_info(btif_hh_device_t* p_dev, const char* dev_name,
+                             uint16_t vendor_id, uint16_t product_id,
+                             uint16_t version, uint8_t ctry_code, int dscp_len,
+                             uint8_t* p_dscp) {
+  int result;
+  struct uhid_event ev;
+
+  if (p_dev->fd < 0) {
+    APPL_TRACE_WARNING("%s: Error: fd = %d, dscp_len = %d", __func__, p_dev->fd,
+                       dscp_len);
+    return;
+  }
+
+  APPL_TRACE_WARNING("%s: fd = %d, name = [%s], dscp_len = %d", __func__,
+                     p_dev->fd, dev_name, dscp_len);
+  APPL_TRACE_WARNING(
+      "%s: vendor_id = 0x%04x, product_id = 0x%04x, version= 0x%04x,"
+      "ctry_code=0x%02x",
+      __func__, vendor_id, product_id, version, ctry_code);
+
+  // Create and send hid descriptor to kernel
+  memset(&ev, 0, sizeof(ev));
+  ev.type = UHID_CREATE;
+  strncpy((char*)ev.u.create.name, dev_name, sizeof(ev.u.create.name) - 1);
+  snprintf((char*)ev.u.create.uniq, sizeof(ev.u.create.uniq),
+           "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", p_dev->bd_addr.address[5],
+           p_dev->bd_addr.address[4], p_dev->bd_addr.address[3],
+           p_dev->bd_addr.address[2], p_dev->bd_addr.address[1],
+           p_dev->bd_addr.address[0]);
+  ev.u.create.rd_size = dscp_len;
+  ev.u.create.rd_data = p_dscp;
+  ev.u.create.bus = BUS_BLUETOOTH;
+  ev.u.create.vendor = vendor_id;
+  ev.u.create.product = product_id;
+  ev.u.create.version = version;
+  ev.u.create.country = ctry_code;
+  result = uhid_write(p_dev->fd, &ev);
+
+  APPL_TRACE_WARNING(
+      "%s: wrote descriptor to fd = %d, dscp_len = %d, result = %d", __func__,
+      p_dev->fd, dscp_len, result);
+
+  if (result) {
+    APPL_TRACE_WARNING("%s: Error: failed to send DSCP, result = %d", __func__,
+                       result);
+
+    /* The HID report descriptor is corrupted. Close the driver. */
+    close(p_dev->fd);
+    p_dev->fd = -1;
+  }
+}
+
+#if (BLE_INCLUDED == TRUE && BTA_HH_LE_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_co_rpt_info
+ *
+ * Description      This callout function is to convey the report information on
+ *                  a HOGP device to the application. Application can save this
+ *                  information in NV if device is bonded and load it back when
+ *                  stack reboot.
+ *
+ * Parameters       remote_bda  - remote device address
+ *                  p_entry     - report entry pointer
+ *                  app_id      - application id
+ *
+ * Returns          void.
+ *
+ ******************************************************************************/
+void bta_hh_le_co_rpt_info(BD_ADDR remote_bda, tBTA_HH_RPT_CACHE_ENTRY* p_entry,
+                           UNUSED_ATTR uint8_t app_id) {
+
+  unsigned idx = 0;
+
+  bdstr_t bdstr;
+  snprintf(bdstr, sizeof(bdstr), "%02x:%02x:%02x:%02x:%02x:%02x", remote_bda[0],
+           remote_bda[1], remote_bda[2], remote_bda[3], remote_bda[4],
+           remote_bda[5]);
+
+  size_t len = btif_config_get_bin_length(bdstr, "HidReport");
+  if (len >= sizeof(tBTA_HH_RPT_CACHE_ENTRY) && len <= sizeof(sReportCache)) {
+    btif_config_get_bin(bdstr, "HidReport", (uint8_t*)sReportCache, &len);
+    idx = len / sizeof(tBTA_HH_RPT_CACHE_ENTRY);
+  }
+
+  if (idx < BTA_HH_NV_LOAD_MAX) {
+    memcpy(&sReportCache[idx++], p_entry, sizeof(tBTA_HH_RPT_CACHE_ENTRY));
+    btif_config_set_bin(bdstr, "HidReport", (const uint8_t*)sReportCache,
+                        idx * sizeof(tBTA_HH_RPT_CACHE_ENTRY));
+    BTIF_TRACE_DEBUG("%s() - Saving report; dev=%s, idx=%d", __func__, bdstr,
+                     idx);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_co_cache_load
+ *
+ * Description      This callout function is to request the application to load
+ *                  the cached HOGP report if there is any. When cache reading
+ *                  is completed, bta_hh_le_ci_cache_load() is called by the
+ *                  application.
+ *
+ * Parameters       remote_bda  - remote device address
+ *                  p_num_rpt: number of cached report
+ *                  app_id      - application id
+ *
+ * Returns          the acched report array
+ *
+ ******************************************************************************/
+tBTA_HH_RPT_CACHE_ENTRY* bta_hh_le_co_cache_load(BD_ADDR remote_bda,
+                                                 uint8_t* p_num_rpt,
+                                                 UNUSED_ATTR uint8_t app_id) {
+
+  bdstr_t bdstr;
+  snprintf(bdstr, sizeof(bdstr), "%02x:%02x:%02x:%02x:%02x:%02x", remote_bda[0],
+           remote_bda[1], remote_bda[2], remote_bda[3], remote_bda[4],
+           remote_bda[5]);
+
+  size_t len = btif_config_get_bin_length(bdstr, "HidReport");
+  if (!p_num_rpt && len < sizeof(tBTA_HH_RPT_CACHE_ENTRY)) return NULL;
+
+  if (len > sizeof(sReportCache)) len = sizeof(sReportCache);
+  btif_config_get_bin(bdstr, "HidReport", (uint8_t*)sReportCache, &len);
+  *p_num_rpt = len / sizeof(tBTA_HH_RPT_CACHE_ENTRY);
+
+  BTIF_TRACE_DEBUG("%s() - Loaded %d reports; dev=%s", __func__, *p_num_rpt,
+                   bdstr);
+
+  return sReportCache;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hh_le_co_reset_rpt_cache
+ *
+ * Description      This callout function is to reset the HOGP device cache.
+ *
+ * Parameters       remote_bda  - remote device address
+ *
+ * Returns          none
+ *
+ ******************************************************************************/
+void bta_hh_le_co_reset_rpt_cache(BD_ADDR remote_bda,
+                                  UNUSED_ATTR uint8_t app_id) {
+
+  bdstr_t bdstr;
+  snprintf(bdstr, sizeof(bdstr), "%02x:%02x:%02x:%02x:%02x:%02x", remote_bda[0],
+           remote_bda[1], remote_bda[2], remote_bda[3], remote_bda[4],
+           remote_bda[5]);
+  btif_config_remove(bdstr, "HidReport");
+
+  BTIF_TRACE_DEBUG("%s() - Reset cache for bda %s", __func__, bdstr);
+}
+
+#endif  // (BLE_INCLUDED == TRUE && BTA_HH_LE_INCLUDED == TRUE)
diff --git a/bt/btif/co/bta_hl_co.cc b/bt/btif/co/bta_hl_co.cc
new file mode 100644
index 0000000..03585ec
--- /dev/null
+++ b/bt/btif/co/bta_hl_co.cc
@@ -0,0 +1,412 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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 is the implementation file for the HeaLth device profile (HL)
+ *  subsystem call-out functions.
+ *
+ ******************************************************************************/
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <time.h>
+
+#include "bta_api.h"
+#include "bta_hl_api.h"
+#include "bta_hl_ci.h"
+#include "bta_hl_co.h"
+#include "bta_sys.h"
+#include "btif_hl.h"
+#include "btif_util.h"
+#include "btm_api.h"
+#include "osi/include/osi.h"
+
+/*****************************************************************************
+ *  Constants and Data Types
+ ****************************************************************************/
+/**************************
+ *  Common Definitions
+ **************************/
+
+/*******************************************************************************
+ *
+ * Function        bta_hl_co_get_num_of_mdep
+ *
+ * Description     This function is called to get the number of MDEPs for this
+ *                 application ID
+ *
+ * Parameters      app_id - application ID
+ *                 p_num_of_mdep (output) - number of MDEP configurations
+ *                                          supported by the application
+ *
+ * Returns         true on success
+ *
+ ******************************************************************************/
+bool bta_hl_co_get_num_of_mdep(uint8_t app_id, uint8_t* p_num_of_mdep) {
+  uint8_t app_idx;
+  bool success = false;
+
+  if (btif_hl_find_app_idx(app_id, &app_idx)) {
+    *p_num_of_mdep = p_btif_hl_cb->acb[app_idx].sup_feature.num_of_mdeps;
+    success = true;
+  }
+
+  BTIF_TRACE_DEBUG("%s success=%d num_mdeps=%d", __func__, success,
+                   *p_num_of_mdep);
+  return success;
+}
+
+/*******************************************************************************
+ *
+ * Function        bta_hl_co_advrtise_source_sdp
+ *
+ * Description     This function is called to find out whether the SOURCE MDEP
+ *                 configuration information should be advertise in the SDP or
+ *                 not.
+ *
+ * Parameters      app_id - application ID
+ *
+ * Returns         true when advertise the SOURCE MDEP configuration
+ *                            information
+ *
+ ******************************************************************************/
+bool bta_hl_co_advrtise_source_sdp(uint8_t app_id) {
+  bool advertize_source_sdp = false;
+  uint8_t app_idx;
+
+  if (btif_hl_find_app_idx(app_id, &app_idx)) {
+    advertize_source_sdp =
+        p_btif_hl_cb->acb[app_idx].sup_feature.advertize_source_sdp;
+  }
+
+  BTIF_TRACE_DEBUG("%s advertize_flag=%d", __func__, advertize_source_sdp);
+
+  return advertize_source_sdp;
+}
+/*******************************************************************************
+ *
+ * Function        bta_hl_co_get_mdep_config
+ *
+ * Description     This function is called to get the supported feature
+ *                 configuration for the specified mdep index and it also
+ *                 assigns the MDEP ID for the specified mdep index
+ *
+ * Parameters      app_id - HDP application ID
+ *                 mdep_idx - the mdep index
+ *                  mdep_counter - number of mdeps
+ *                 mdep_id  - the assigned MDEP ID for the specified medp_idx
+ *                 p_mdl_cfg (output) - pointer to the MDEP configuration
+ *
+ *
+ * Returns         Bloolean - true success
+ ******************************************************************************/
+bool bta_hl_co_get_mdep_config(uint8_t app_id, uint8_t mdep_idx,
+                               uint8_t mdep_counter, tBTA_HL_MDEP_ID mdep_id,
+                               tBTA_HL_MDEP_CFG* p_mdep_cfg) {
+  uint8_t idx;
+  uint8_t app_idx;
+  bool success = false;
+
+  BTIF_TRACE_DEBUG("%s app_id=%d mdep_idx=%d mdep_id=%d mdep_counter=%d",
+                   __func__, app_id, mdep_idx, mdep_id, mdep_counter);
+
+  if (btif_hl_find_app_idx(app_id, &app_idx)) {
+    idx = mdep_idx - mdep_counter - 1;
+    p_btif_hl_cb->acb[app_idx].sup_feature.mdep[idx].mdep_id = mdep_id;
+    memcpy(p_mdep_cfg,
+           &p_btif_hl_cb->acb[app_idx].sup_feature.mdep[idx].mdep_cfg,
+           sizeof(tBTA_HL_MDEP_CFG));
+
+    success = true;
+  }
+
+  BTIF_TRACE_DEBUG("%s success=%d mdep_idx=%d mdep_id=%d", __func__, success,
+                   mdep_idx, mdep_id);
+
+  return success;
+}
+
+/*******************************************************************************
+ *
+ * Function        bta_hl_co_get_echo_config
+ *
+ * Description     This function is called to get the echo test
+ *                 maximum APDU size configurations
+ *
+ * Parameters      app_id - HDP application ID
+ *                 p_echo_cfg (output) - pointer to the Echo test maximum APDU
+ *                                       size configuration
+ *
+ * Returns         Bloolean - true success
+ ******************************************************************************/
+bool bta_hl_co_get_echo_config(uint8_t app_id, tBTA_HL_ECHO_CFG* p_echo_cfg) {
+  uint8_t app_idx;
+  bool success = false;
+  btif_hl_app_cb_t* p_acb;
+  tBTA_HL_SUP_FEATURE* p_sup;
+
+  BTIF_TRACE_DEBUG("%s app_id=%d", __func__, app_id);
+
+  if (btif_hl_find_app_idx(app_id, &app_idx)) {
+    p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+    p_sup = &p_acb->sup_feature;
+    p_echo_cfg->max_rx_apdu_size = p_sup->echo_cfg.max_rx_apdu_size;
+    p_echo_cfg->max_tx_apdu_size = p_sup->echo_cfg.max_tx_apdu_size;
+    success = true;
+  }
+
+  BTIF_TRACE_DEBUG("%s success=%d max tx_size=%d rx_size=%d", __func__, success,
+                   p_echo_cfg->max_tx_apdu_size, p_echo_cfg->max_rx_apdu_size);
+
+  return success;
+}
+
+/*******************************************************************************
+ *
+ * Function        bta_hl_co_save_mdl
+ *
+ * Description     This function is called to save a MDL configuration item in
+ *                 persistent storage
+ *
+ * Parameters      app_id - HDP application ID
+ *                 item_idx - the MDL configuration storage index
+ *                 p_mdl_cfg - pointer to the MDL configuration data
+ *
+ * Returns        void
+ *
+ ******************************************************************************/
+void bta_hl_co_save_mdl(uint8_t mdep_id, uint8_t item_idx,
+                        tBTA_HL_MDL_CFG* p_mdl_cfg) {
+  BTIF_TRACE_DEBUG("%s mdep_id =%d, item_idx=%d active=%d mdl_id=%d time=%d",
+                   __func__, mdep_id, item_idx, p_mdl_cfg->active,
+                   p_mdl_cfg->mdl_id, p_mdl_cfg->time);
+
+  btif_hl_save_mdl_cfg(mdep_id, item_idx, p_mdl_cfg);
+}
+
+/*******************************************************************************
+ *
+ * Function        bta_hl_co_delete_mdl
+ *
+ * Description     This function is called to delete a MDL configuration item in
+ *                 persistent storage
+ *
+ * Parameters      app_id - HDP application ID
+ *                 item_idx - the MDL configuration storage index
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_hl_co_delete_mdl(uint8_t mdep_id, uint8_t item_idx) {
+  BTIF_TRACE_DEBUG("%s mdep_id=%d, item_idx=%d", __func__, mdep_id, item_idx);
+
+  btif_hl_delete_mdl_cfg(mdep_id, item_idx);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_co_get_mdl_config
+ *
+ * Description     This function is called to get the MDL configuration
+ *                 from the persistent memory. This function shall only be
+ *                 called once after the device is powered up
+ *
+ * Parameters      app_id - HDP application ID
+ *                 buffer_size - the unit of the buffer size is
+ *                               sizeof(tBTA_HL_MDL_CFG)
+ *                 p_mdl_buf - Point to the starting location of the buffer
+ *
+ * Returns         bool
+ *
+ *
+ ******************************************************************************/
+bool bta_hl_co_load_mdl_config(uint8_t app_id, uint8_t buffer_size,
+                               tBTA_HL_MDL_CFG* p_mdl_buf) {
+  bool result = true;
+  uint8_t i;
+  tBTA_HL_MDL_CFG* p;
+
+  BTIF_TRACE_DEBUG("%s app_id=%d, num_items=%d", __func__, app_id, buffer_size);
+
+  if (buffer_size > BTA_HL_NUM_MDL_CFGS) {
+    result = false;
+    return result;
+  }
+  result = btif_hl_load_mdl_config(app_id, buffer_size, p_mdl_buf);
+
+  if (result) {
+    for (i = 0, p = p_mdl_buf; i < buffer_size; i++, p++) {
+      if (p->active) {
+        BTIF_TRACE_DEBUG(
+            "i=%d mdl_id=0x%x dch_mode=%d local mdep_role=%d mdep_id=%d mtu=%d",
+            i, p->mdl_id, p->dch_mode, p->local_mdep_role, p->local_mdep_role,
+            p->mtu);
+      }
+    }
+  }
+
+  BTIF_TRACE_DEBUG("%s success=%d num_items=%d", __func__, result, buffer_size);
+
+  return result;
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_co_get_tx_data
+ *
+ * Description     Get the data to be sent
+ *
+ * Parameters      app_id - HDP application ID
+ *                 mdl_handle - MDL handle
+ *                 buf_size - the size of the buffer
+ *                 p_buf - the buffer pointer
+ *                 evt - the evt to be passed back to the HL in the
+ *                       bta_hl_ci_get_tx_data call-in function
+ *
+ * Returns        Void
+ *
+ ******************************************************************************/
+void bta_hl_co_get_tx_data(uint8_t app_id, tBTA_HL_MDL_HANDLE mdl_handle,
+                           uint16_t buf_size, uint8_t* p_buf, uint16_t evt) {
+  uint8_t app_idx, mcl_idx, mdl_idx;
+  btif_hl_mdl_cb_t* p_dcb;
+  tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL;
+
+  BTIF_TRACE_DEBUG("%s app_id=%d mdl_handle=0x%x buf_size=%d", __func__, app_id,
+                   mdl_handle, buf_size);
+
+  if (btif_hl_find_mdl_idx_using_handle(mdl_handle, &app_idx, &mcl_idx,
+                                        &mdl_idx)) {
+    p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+    if (p_dcb->tx_size <= buf_size) {
+      memcpy(p_buf, p_dcb->p_tx_pkt, p_dcb->tx_size);
+      osi_free_and_reset((void**)&p_dcb->p_tx_pkt);
+      p_dcb->tx_size = 0;
+      status = BTA_HL_STATUS_OK;
+    }
+  }
+
+  bta_hl_ci_get_tx_data(mdl_handle, status, evt);
+}
+
+/*******************************************************************************
+ *
+ * Function        bta_hl_co_put_rx_data
+ *
+ * Description     Put the received data
+ *
+ * Parameters      app_id - HDP application ID
+ *                 mdl_handle - MDL handle
+ *                 data_size - the size of the data
+ *                 p_data - the data pointer
+ *                 evt - the evt to be passed back to the HL in the
+ *                       bta_hl_ci_put_rx_data call-in function
+ *
+ * Returns        Void
+ *
+ ******************************************************************************/
+void bta_hl_co_put_rx_data(uint8_t app_id, tBTA_HL_MDL_HANDLE mdl_handle,
+                           uint16_t data_size, uint8_t* p_data, uint16_t evt) {
+  uint8_t app_idx, mcl_idx, mdl_idx;
+  btif_hl_mdl_cb_t* p_dcb;
+  tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL;
+  BTIF_TRACE_DEBUG("%s app_id=%d mdl_handle=0x%x data_size=%d", __func__,
+                   app_id, mdl_handle, data_size);
+
+  if (btif_hl_find_mdl_idx_using_handle(mdl_handle, &app_idx, &mcl_idx,
+                                        &mdl_idx)) {
+    p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+    p_dcb->p_rx_pkt = (uint8_t*)osi_malloc(data_size);
+    memcpy(p_dcb->p_rx_pkt, p_data, data_size);
+    if (p_dcb->p_scb) {
+      BTIF_TRACE_DEBUG("app_idx=%d mcl_idx=0x%x mdl_idx=0x%x data_size=%d",
+                       app_idx, mcl_idx, mdl_idx, data_size);
+      ssize_t r;
+      OSI_NO_INTR(
+          r = send(p_dcb->p_scb->socket_id[1], p_dcb->p_rx_pkt, data_size, 0));
+      if (r == data_size) {
+        BTIF_TRACE_DEBUG("socket send success data_size=%d", data_size);
+        status = BTA_HL_STATUS_OK;
+      } else {
+        BTIF_TRACE_ERROR("socket send failed r=%d data_size=%d", r, data_size);
+      }
+    }
+    osi_free_and_reset((void**)&p_dcb->p_rx_pkt);
+  }
+
+  bta_hl_ci_put_rx_data(mdl_handle, status, evt);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_hl_co_get_tx_data
+ *
+ * Description     Get the Echo data to be sent
+ *
+ * Parameters      app_id - HDP application ID
+ *                 mcl_handle - MCL handle
+ *                 buf_size - the size of the buffer
+ *                 p_buf - the buffer pointer
+ *                 evt - the evt to be passed back to the HL in the
+ *                       bta_hl_ci_get_tx_data call-in function
+ *
+ * Returns        Void
+ *
+ ******************************************************************************/
+void bta_hl_co_get_echo_data(UNUSED_ATTR uint8_t app_id, tBTA_HL_MCL_HANDLE mcl_handle,
+                             UNUSED_ATTR uint16_t buf_size, UNUSED_ATTR uint8_t *p_buf, uint16_t evt) {
+  tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL;
+
+  BTIF_TRACE_ERROR("%s not supported", __func__);
+  bta_hl_ci_get_echo_data(mcl_handle, status, evt);
+}
+
+/*******************************************************************************
+ *
+ * Function        bta_hl_co_put_echo_data
+ *
+ * Description     Put the received loopback echo data
+ *
+ * Parameters      app_id - HDP application ID
+ *                 mcl_handle - MCL handle
+ *                 data_size - the size of the data
+ *                 p_data - the data pointer
+ *                 evt - the evt to be passed back to the HL in the
+ *                       bta_hl_ci_put_echo_data call-in function
+ *
+ * Returns        Void
+ *
+ ******************************************************************************/
+void bta_hl_co_put_echo_data(UNUSED_ATTR uint8_t app_id, tBTA_HL_MCL_HANDLE mcl_handle,
+                             UNUSED_ATTR uint16_t data_size, UNUSED_ATTR uint8_t *p_data,
+                             uint16_t evt) {
+  tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL;
+
+  BTIF_TRACE_ERROR("%s not supported", __func__);
+  bta_hl_ci_put_echo_data(mcl_handle, status, evt);
+}
diff --git a/bt/btif/co/bta_pan_co.cc b/bt/btif/co/bta_pan_co.cc
new file mode 100644
index 0000000..917830f
--- /dev/null
+++ b/bt/btif/co/bta_pan_co.cc
@@ -0,0 +1,309 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Filename:      bta_pan_co.c
+ *
+ *  Description:   PAN stack callout api
+ *
+ *
+ ******************************************************************************/
+#include "bta_pan_co.h"
+#include <hardware/bluetooth.h>
+#include <hardware/bt_pan.h>
+#include <string.h>
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_pan_api.h"
+#include "bta_pan_ci.h"
+#include "btcore/include/bdaddr.h"
+#include "btif_pan_internal.h"
+#include "btif_sock_thread.h"
+#include "btif_util.h"
+#include "osi/include/osi.h"
+#include "pan_api.h"
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_co_init
+ *
+ * Description
+ *
+ *
+ * Returns          Data flow mask.
+ *
+ ******************************************************************************/
+uint8_t bta_pan_co_init(uint8_t* q_level) {
+  BTIF_TRACE_API("bta_pan_co_init");
+
+  /* set the q_level to 30 buffers */
+  *q_level = 30;
+
+  // return (BTA_PAN_RX_PULL | BTA_PAN_TX_PULL);
+  return (BTA_PAN_RX_PUSH_BUF | BTA_PAN_RX_PUSH | BTA_PAN_TX_PULL);
+}
+
+/******************************************************************************
+ *
+ * Function         bta_pan_co_open
+ *
+ * Description
+ *
+ *
+ *
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_co_open(uint16_t handle, uint8_t app_id, tBTA_PAN_ROLE local_role,
+                     tBTA_PAN_ROLE peer_role, BD_ADDR peer_addr) {
+  BTIF_TRACE_API(
+      "bta_pan_co_open:app_id:%d, local_role:%d, peer_role:%d, "
+      "handle:%d",
+      app_id, local_role, peer_role, handle);
+  btpan_conn_t* conn = btpan_find_conn_addr(peer_addr);
+  if (conn == NULL)
+    conn = btpan_new_conn(handle, peer_addr, local_role, peer_role);
+  if (conn) {
+    BTIF_TRACE_DEBUG(
+        "bta_pan_co_open:tap_fd:%d, open_count:%d, "
+        "conn->handle:%d should = handle:%d, local_role:%d, remote_role:%d",
+        btpan_cb.tap_fd, btpan_cb.open_count, conn->handle, handle,
+        conn->local_role, conn->remote_role);
+    // refresh the role & bt address
+
+    btpan_cb.open_count++;
+    conn->handle = handle;
+    // bdcpy(conn->peer, peer_addr);
+    if (btpan_cb.tap_fd < 0) {
+      btpan_cb.tap_fd = btpan_tap_open();
+      if (btpan_cb.tap_fd >= 0) create_tap_read_thread(btpan_cb.tap_fd);
+    }
+    if (btpan_cb.tap_fd >= 0) {
+      btpan_cb.flow = 1;
+      conn->state = PAN_STATE_OPEN;
+      bta_pan_ci_rx_ready(handle);
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_co_close
+ *
+ * Description      This function is called by PAN when a connection to a
+ *                  peer is closed.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_co_close(uint16_t handle, uint8_t app_id) {
+  BTIF_TRACE_API("bta_pan_co_close:app_id:%d, handle:%d", app_id, handle);
+  btpan_conn_t* conn = btpan_find_conn_handle(handle);
+  if (conn && conn->state == PAN_STATE_OPEN) {
+    BTIF_TRACE_DEBUG("bta_pan_co_close");
+
+    // let bta close event reset this handle as it needs
+    // the handle to find the connection upon CLOSE
+    // conn->handle = -1;
+    conn->state = PAN_STATE_CLOSE;
+    btpan_cb.open_count--;
+
+    if (btpan_cb.open_count == 0 && btpan_cb.tap_fd != -1) {
+      btpan_tap_close(btpan_cb.tap_fd);
+      btpan_cb.tap_fd = -1;
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_co_tx_path
+ *
+ * Description      This function is called by PAN to transfer data on the
+ *                  TX path; that is, data being sent from BTA to the phone.
+ *                  This function is used when the TX data path is configured
+ *                  to use the pull interface.  The implementation of this
+ *                  function will typically call Bluetooth stack functions
+ *                  PORT_Read() or PORT_ReadData() to read data from RFCOMM
+ *                  and then a platform-specific function to send data that
+ *                  data to the phone.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_co_tx_path(uint16_t handle, uint8_t app_id) {
+  BT_HDR* p_buf;
+  BD_ADDR src;
+  BD_ADDR dst;
+  uint16_t protocol;
+  bool ext;
+  bool forward;
+
+  BTIF_TRACE_API("%s, handle:%d, app_id:%d", __func__, handle, app_id);
+
+  btpan_conn_t* conn = btpan_find_conn_handle(handle);
+  if (!conn) {
+    BTIF_TRACE_ERROR("%s: cannot find pan connection", __func__);
+    return;
+  } else if (conn->state != PAN_STATE_OPEN) {
+    BTIF_TRACE_ERROR("%s: conn is not opened, conn:%p, conn->state:%d",
+                     __func__, conn, conn->state);
+    return;
+  }
+
+  do {
+    /* read next data buffer from pan */
+    if ((p_buf =
+             bta_pan_ci_readbuf(handle, src, dst, &protocol, &ext, &forward))) {
+      bdstr_t bdstr;
+      BTIF_TRACE_DEBUG(
+          "%s, calling btapp_tap_send, "
+          "p_buf->len:%d, offset:%d",
+          __func__, p_buf->len, p_buf->offset);
+      if (is_empty_eth_addr(conn->eth_addr) && is_valid_bt_eth_addr(src)) {
+        BTIF_TRACE_DEBUG(
+            "%s pan bt peer addr: %s", __func__,
+            bdaddr_to_string((bt_bdaddr_t*)conn->peer, bdstr, sizeof(bdstr)));
+        bdaddr_to_string((bt_bdaddr_t*)src, bdstr, sizeof(bdstr));
+        BTIF_TRACE_DEBUG(
+            "%s:     update its ethernet addr: %s", __func__,
+            bdaddr_to_string((bt_bdaddr_t*)src, bdstr, sizeof(bdstr)));
+        memcpy(conn->eth_addr, src, sizeof(conn->eth_addr));
+      }
+      btpan_tap_send(btpan_cb.tap_fd, src, dst, protocol,
+                     (char*)(p_buf + 1) + p_buf->offset, p_buf->len, ext,
+                     forward);
+      osi_free(p_buf);
+    }
+
+  } while (p_buf != NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_co_rx_path
+ *
+ * Description
+ *
+ *
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_co_rx_path(UNUSED_ATTR uint16_t handle,
+                        UNUSED_ATTR uint8_t app_id) {
+  BTIF_TRACE_API("bta_pan_co_rx_path not used");
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_co_tx_write
+ *
+ * Description      This function is called by PAN to send data to the phone
+ *                  when the TX path is configured to use a push interface.
+ *                  The implementation of this function must copy the data to
+ *                  the phone's memory.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_co_tx_write(UNUSED_ATTR uint16_t handle, UNUSED_ATTR uint8_t app_id, UNUSED_ATTR BD_ADDR src,
+                         UNUSED_ATTR BD_ADDR dst, UNUSED_ATTR uint16_t protocol, UNUSED_ATTR uint8_t *p_data,
+                         UNUSED_ATTR uint16_t len, UNUSED_ATTR bool ext,
+                         UNUSED_ATTR bool forward) {
+  BTIF_TRACE_API("bta_pan_co_tx_write not used");
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_co_tx_writebuf
+ *
+ * Description      This function is called by PAN to send data to the phone
+ *                  when the TX path is configured to use a push interface with
+ *                  zero copy.  The phone must free the buffer using function
+ *                  osi_free() when it is through processing the buffer.
+ *
+ *
+ * Returns          true if flow enabled
+ *
+ ******************************************************************************/
+void bta_pan_co_tx_writebuf(UNUSED_ATTR uint16_t handle, UNUSED_ATTR uint8_t app_id, UNUSED_ATTR BD_ADDR src,
+                            UNUSED_ATTR BD_ADDR dst, UNUSED_ATTR uint16_t protocol, UNUSED_ATTR BT_HDR *p_buf,
+                            UNUSED_ATTR bool ext,
+                            UNUSED_ATTR bool forward) {
+  BTIF_TRACE_API("bta_pan_co_tx_writebuf not used");
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_co_rx_flow
+ *
+ * Description      This function is called by PAN to enable or disable
+ *                  data flow on the RX path when it is configured to use
+ *                  a push interface.  If data flow is disabled the phone must
+ *                  not call bta_pan_ci_rx_write() or bta_pan_ci_rx_writebuf()
+ *                  until data flow is enabled again.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_co_rx_flow(UNUSED_ATTR uint16_t handle, UNUSED_ATTR uint8_t app_id,
+                        UNUSED_ATTR bool enable) {
+  BTIF_TRACE_API("bta_pan_co_rx_flow, enabled:%d, not used", enable);
+  btpan_conn_t* conn = btpan_find_conn_handle(handle);
+  if (!conn || conn->state != PAN_STATE_OPEN) return;
+  btpan_set_flow_control(enable);
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_co_filt_ind
+ *
+ * Description      protocol filter indication from peer device
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_co_pfilt_ind(UNUSED_ATTR uint16_t handle, UNUSED_ATTR bool indication,
+                          UNUSED_ATTR tBTA_PAN_STATUS result, UNUSED_ATTR uint16_t len,
+                          UNUSED_ATTR uint8_t *p_filters) {
+  BTIF_TRACE_API("bta_pan_co_pfilt_ind");
+}
+
+/*******************************************************************************
+ *
+ * Function         bta_pan_co_mfilt_ind
+ *
+ * Description      multicast filter indication from peer device
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bta_pan_co_mfilt_ind(UNUSED_ATTR uint16_t handle, UNUSED_ATTR bool indication,
+                          UNUSED_ATTR tBTA_PAN_STATUS result, UNUSED_ATTR uint16_t len,
+                          UNUSED_ATTR uint8_t *p_filters) {
+  BTIF_TRACE_API("bta_pan_co_mfilt_ind");
+}
diff --git a/bt/btif/include/btif_a2dp.h b/bt/btif/include/btif_a2dp.h
new file mode 100644
index 0000000..a9b56a3
--- /dev/null
+++ b/bt/btif/include/btif_a2dp.h
@@ -0,0 +1,73 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_A2DP_H
+#define BTIF_A2DP_H
+
+#include <stdbool.h>
+
+#include "bta_av_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Process 'idle' request from the BTIF state machine during initialization.
+void btif_a2dp_on_idle(void);
+
+// Process 'start' request from the BTIF state machine to prepare for A2DP
+// streaming.
+// |p_av_start| is the data associated with the request - see |tBTA_AV_START|.
+// |pending_start| should be set to true if the BTIF state machine is in
+// 'pending start' state.
+// Returns true if an ACK for the local command was sent, otherwise false.
+bool btif_a2dp_on_started(tBTA_AV_START* p_av_start, bool pending_start);
+
+// Process 'stop' request from the BTIF state machine to stop A2DP streaming.
+// |p_av_suspend| is the data associated with the request - see
+// |tBTA_AV_SUSPEND|.
+void btif_a2dp_on_stopped(tBTA_AV_SUSPEND* p_av_suspend);
+
+// Process 'suspend' request from the BTIF state machine to suspend A2DP
+// streaming.
+// |p_av_suspend| is the data associated with the request - see
+// |tBTA_AV_SUSPEND|.
+void btif_a2dp_on_suspended(tBTA_AV_SUSPEND* p_av_suspend);
+
+// Process 'offload start' request from the BTIF state machine to start
+// offloading of the A2DP streaming.
+// |status| is the processing status of the request prior to this call.
+// The value can be |BTA_AV_SUCCESS| if the processing has been successful
+// so far, or |BTA_AV_FAIL*| if the request has already failed.
+void btif_a2dp_on_offload_started(tBTA_AV_STATUS status);
+
+// Dump debug-related information for the A2DP module.
+// |fd| is the file descriptor to use for writing the ASCII formatted
+// information.
+void btif_debug_a2dp_dump(int fd);
+
+// Update the A2DP-related metrics.
+// This function should be called before collecting the metrics.
+void btif_update_a2dp_metrics(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTIF_A2DP_H */
diff --git a/bt/btif/include/btif_a2dp_control.h b/bt/btif/include/btif_a2dp_control.h
new file mode 100644
index 0000000..59af29f
--- /dev/null
+++ b/bt/btif/include/btif_a2dp_control.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_A2DP_CONTROL_H
+#define BTIF_A2DP_CONTROL_H
+
+#include "audio_a2dp_hw/audio_a2dp_hw.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Initialize the A2DP control module. It should be called during the
+// startup stage of A2DP streaming.
+void btif_a2dp_control_init(void);
+
+// Cleanup the A2DP control module. It should be called during the shutdown
+// stage of A2DP streaming.
+void btif_a2dp_control_cleanup(void);
+
+// Acknowledge A2DP command to the origin of audio streaming.
+// |status| is the acknowledement status - see |tA2DP_CTRL_ACK|.
+void btif_a2dp_command_ack(tA2DP_CTRL_ACK status);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTIF_A2DP_CONTROL_H */
diff --git a/bt/btif/include/btif_a2dp_sink.h b/bt/btif/include/btif_a2dp_sink.h
new file mode 100644
index 0000000..27b3b26
--- /dev/null
+++ b/bt/btif/include/btif_a2dp_sink.h
@@ -0,0 +1,112 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_A2DP_SINK_H
+#define BTIF_A2DP_SINK_H
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include "bt_types.h"
+#include "bta_av_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//
+// Audio focus state for audio track.
+//
+// NOTE: The values must be same as:
+//  - A2dpSinkStreamingStateMachine.STATE_FOCUS_LOST = 0
+//  - A2dpSinkStreamingStateMachine.STATE_FOCUS_GRANTED = 1
+//
+typedef enum {
+  BTIF_A2DP_SINK_FOCUS_NOT_GRANTED = 0,
+  BTIF_A2DP_SINK_FOCUS_GRANTED = 1
+} btif_a2dp_sink_focus_state_t;
+
+// Initialize and startup the A2DP Sink module.
+// This function should be called by the BTIF state machine prior to using the
+// module.
+bool btif_a2dp_sink_startup(void);
+
+// Shutdown and cleanup the A2DP Sink module.
+// This function should be called by the BTIF state machine during
+// graceful shutdown and cleanup.
+void btif_a2dp_sink_shutdown(void);
+
+// Get the audio sample rate for the A2DP Sink module.
+uint32_t btif_a2dp_sink_get_sample_rate(void);
+
+// Get the audio channel count for the A2DP Sink module.
+uint8_t btif_a2dp_sink_get_channel_count(void);
+
+// Update the decoder for the A2DP Sink module.
+// |p_codec_info| contains the new codec information.
+void btif_a2dp_sink_update_decoder(const uint8_t* p_codec_info);
+
+// Process 'idle' request from the BTIF state machine during initialization.
+void btif_a2dp_sink_on_idle(void);
+
+// Process 'stop' request from the BTIF state machine to stop A2DP streaming.
+// |p_av_suspend| is the data associated with the request - see
+// |tBTA_AV_SUSPEND|.
+void btif_a2dp_sink_on_stopped(tBTA_AV_SUSPEND* p_av_suspend);
+
+// Process 'suspend' request from the BTIF state machine to suspend A2DP
+// streaming.
+// |p_av_suspend| is the data associated with the request - see
+// |tBTA_AV_SUSPEND|.
+void btif_a2dp_sink_on_suspended(tBTA_AV_SUSPEND* p_av_suspend);
+
+// Enable/disable discarding of received A2DP frames.
+// If |enable| is true, the discarding is enabled, otherwise is disabled.
+void btif_a2dp_sink_set_rx_flush(bool enable);
+
+// Enqueue a buffer to the A2DP Sink queue. If the queue has reached its
+// maximum size |MAX_INPUT_A2DP_FRAME_QUEUE_SZ|, the oldest buffer is
+// removed from the queue.
+// |p_buf| is the buffer to enqueue.
+// Returns the number of buffers in the Sink queue after the enqueing.
+uint8_t btif_a2dp_sink_enqueue_buf(BT_HDR* p_buf);
+
+// Dump debug-related information for the A2DP Sink module.
+// |fd| is the file descriptor to use for writing the ASCII formatted
+// information.
+void btif_a2dp_sink_debug_dump(int fd);
+
+// Update the A2DP Sink related metrics.
+// This function should be called before collecting the metrics.
+void btif_a2dp_sink_update_metrics(void);
+
+// Create a request to set the audio focus state for the audio track.
+// |state| is the new state value - see |btif_a2dp_sink_focus_state_t|
+// for valid values.
+void btif_a2dp_sink_set_focus_state_req(btif_a2dp_sink_focus_state_t state);
+
+// Set the audio track gain for the audio track.
+// |gain| is the audio track gain value to use.
+void btif_a2dp_sink_set_audio_track_gain(float gain);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTIF_A2DP_SINK_H */
diff --git a/bt/btif/include/btif_a2dp_source.h b/bt/btif/include/btif_a2dp_source.h
new file mode 100644
index 0000000..baac335
--- /dev/null
+++ b/bt/btif/include/btif_a2dp_source.h
@@ -0,0 +1,100 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_A2DP_SOURCE_H
+#define BTIF_A2DP_SOURCE_H
+
+#include <stdbool.h>
+
+#include "bta_av_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Initialize and startup the A2DP Source module.
+// This function should be called by the BTIF state machine prior to using the
+// module.
+bool btif_a2dp_source_startup(void);
+
+// Shutdown and cleanup the A2DP Source module.
+// This function should be called by the BTIF state machine during
+// graceful shutdown and cleanup.
+void btif_a2dp_source_shutdown(void);
+
+// Check whether the A2DP Source media task is running.
+// Returns true if the A2DP Source media task is running, otherwise false.
+bool btif_a2dp_source_media_task_is_running(void);
+
+// Check whether the A2DP Source media task is shutting down.
+// Returns true if the A2DP Source media task is shutting down.
+bool btif_a2dp_source_media_task_is_shutting_down(void);
+
+// Return true if the A2DP Source module is streaming.
+bool btif_a2dp_source_is_streaming(void);
+
+// Setup the A2DP Source codec, and prepare the encoder.
+// This function should be called prior to starting A2DP streaming.
+void btif_a2dp_source_setup_codec(void);
+
+// Process a request to start the A2DP audio encoding task.
+void btif_a2dp_source_start_audio_req(void);
+
+// Process a request to stop the A2DP audio encoding task.
+void btif_a2dp_source_stop_audio_req(void);
+
+// Process 'idle' request from the BTIF state machine during initialization.
+void btif_a2dp_source_on_idle(void);
+
+// Process 'stop' request from the BTIF state machine to stop A2DP streaming.
+// |p_av_suspend| is the data associated with the request - see
+// |tBTA_AV_SUSPEND|.
+void btif_a2dp_source_on_stopped(tBTA_AV_SUSPEND* p_av_suspend);
+
+// Process 'suspend' request from the BTIF state machine to suspend A2DP
+// streaming.
+// |p_av_suspend| is the data associated with the request - see
+// |tBTA_AV_SUSPEND|.
+void btif_a2dp_source_on_suspended(tBTA_AV_SUSPEND* p_av_suspend);
+
+// Enable/disable discarding of transmitted frames.
+// If |enable| is true, the discarding is enabled, otherwise is disabled.
+void btif_a2dp_source_set_tx_flush(bool enable);
+
+// Update any changed encoder paramenters of the A2DP Source codec.
+void btif_a2dp_source_encoder_update(void);
+
+// Get the next A2DP buffer to send.
+// Returns the next A2DP buffer to send if available, otherwise NULL.
+BT_HDR* btif_a2dp_source_audio_readbuf(void);
+
+// Dump debug-related information for the A2DP Source module.
+// |fd| is the file descriptor to use for writing the ASCII formatted
+// information.
+void btif_a2dp_source_debug_dump(int fd);
+
+// Update the A2DP Source related metrics.
+// This function should be called before collecting the metrics.
+void btif_a2dp_source_update_metrics(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTIF_A2DP_SOURCE_H */
diff --git a/bt/btif/include/btif_api.h b/bt/btif/include/btif_api.h
new file mode 100644
index 0000000..685a354
--- /dev/null
+++ b/bt/btif/include/btif_api.h
@@ -0,0 +1,425 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ *  Filename:      btif_api.h
+ *
+ *  Description:   Main API header file for all BTIF functions accessed
+ *                 from main bluetooth HAL. All HAL extensions will not
+ *                 require headerfiles as they would be accessed through
+ *                 callout/callins.
+ *
+ *******************************************************************************/
+
+#ifndef BTIF_API_H
+#define BTIF_API_H
+
+#include <hardware/bluetooth.h>
+
+#include "btif_common.h"
+#include "btif_dm.h"
+
+/*******************************************************************************
+ *  BTIF CORE API
+ *******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         btif_init_bluetooth
+ *
+ * Description      Creates BTIF task and prepares BT scheduler for startup
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_init_bluetooth(void);
+
+/*******************************************************************************
+ *
+ * Function         btif_enable_bluetooth
+ *
+ * Description      Performs chip power on and kickstarts OS scheduler
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_enable_bluetooth(void);
+
+/*******************************************************************************
+ *
+ * Function         btif_disable_bluetooth
+ *
+ * Description      Inititates shutdown of Bluetooth system.
+ *                  Any active links will be dropped and device entering
+ *                  non connectable/discoverable mode
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+bt_status_t btif_disable_bluetooth(void);
+
+/*******************************************************************************
+ *
+ * Function         btif_cleanup_bluetooth
+ *
+ * Description      Cleanup BTIF state.
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+bt_status_t btif_cleanup_bluetooth(void);
+
+/*******************************************************************************
+ *
+ * Function         is_restricted_mode
+ *
+ * Description      Checks if BT was enabled in restriced mode. In restricted
+ *                  mode, bonds that are created are marked as temporary.
+ *                  These bonds persist until we leave restricted mode, at
+ *                  which point they will be deleted from the config. Also
+ *                  while in restricted mode, the user can access devices
+ *                  that are already paired before entering restricted mode,
+ *                  but they cannot remove any of these devices.
+ *
+ * Returns          bool
+ *
+ ******************************************************************************/
+bool is_restricted_mode(void);
+
+/*******************************************************************************
+ *
+ * Function         btif_get_adapter_properties
+ *
+ * Description      Fetches all local adapter properties
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_get_adapter_properties(void);
+
+/*******************************************************************************
+ *
+ * Function         btif_get_adapter_property
+ *
+ * Description      Fetches property value from local cache
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_get_adapter_property(bt_property_type_t type);
+
+/*******************************************************************************
+ *
+ * Function         btif_set_adapter_property
+ *
+ * Description      Updates core stack with property value and stores it in
+ *                  local cache
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_set_adapter_property(const bt_property_t* property);
+
+/*******************************************************************************
+ *
+ * Function         btif_get_remote_device_property
+ *
+ * Description      Fetches the remote device property from the NVRAM
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_get_remote_device_property(bt_bdaddr_t* remote_addr,
+                                            bt_property_type_t type);
+
+/*******************************************************************************
+ *
+ * Function         btif_get_remote_device_properties
+ *
+ * Description      Fetches all the remote device properties from NVRAM
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_get_remote_device_properties(bt_bdaddr_t* remote_addr);
+
+/*******************************************************************************
+ *
+ * Function         btif_set_remote_device_property
+ *
+ * Description      Writes the remote device property to NVRAM.
+ *                  Currently, BT_PROPERTY_REMOTE_FRIENDLY_NAME is the only
+ *                  remote device property that can be set
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_set_remote_device_property(bt_bdaddr_t* remote_addr,
+                                            const bt_property_t* property);
+
+/*******************************************************************************
+ *
+ * Function         btif_get_remote_service_record
+ *
+ * Description      Looks up the service matching uuid on the remote device
+ *                  and fetches the SCN and service_name if the UUID is found
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_get_remote_service_record(bt_bdaddr_t* remote_addr,
+                                           bt_uuid_t* uuid);
+
+/*******************************************************************************
+ *  BTIF DM API
+ *******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_start_discovery
+ *
+ * Description      Start device discovery/inquiry
+ *
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_start_discovery(void);
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_cancel_discovery
+ *
+ * Description      Cancels search
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_cancel_discovery(void);
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_create_bond
+ *
+ * Description      Initiate bonding with the specified device
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_create_bond(const bt_bdaddr_t* bd_addr, int transport);
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_create_bond_out_of_band
+ *
+ * Description      Initiate bonding with the specified device using OOB data.
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_create_bond_out_of_band(
+    const bt_bdaddr_t* bd_addr, int transport,
+    const bt_out_of_band_data_t* oob_data);
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_cancel_bond
+ *
+ * Description      Initiate bonding with the specified device
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_cancel_bond(const bt_bdaddr_t* bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_remove_bond
+ *
+ * Description      Removes bonding with the specified device
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_remove_bond(const bt_bdaddr_t* bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_get_connection_state
+ *
+ * Description      Returns whether the remote device is currently connected
+ *
+ * Returns          0 if not connected
+ *
+ ******************************************************************************/
+uint16_t btif_dm_get_connection_state(const bt_bdaddr_t* bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_pin_reply
+ *
+ * Description      BT legacy pairing - PIN code reply
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_pin_reply(const bt_bdaddr_t* bd_addr, uint8_t accept,
+                              uint8_t pin_len, bt_pin_code_t* pin_code);
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_passkey_reply
+ *
+ * Description      BT SSP passkey reply
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_passkey_reply(const bt_bdaddr_t* bd_addr, uint8_t accept,
+                                  uint32_t passkey);
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_ssp_reply
+ *
+ * Description      BT SSP Reply - Just Works, Numeric Comparison & Passkey
+ *                  Entry
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_ssp_reply(const bt_bdaddr_t* bd_addr,
+                              bt_ssp_variant_t variant, uint8_t accept,
+                              uint32_t passkey);
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_get_adapter_property
+ *
+ * Description      Queries the BTA for the adapter property
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_get_adapter_property(bt_property_t* prop);
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_get_remote_services
+ *
+ * Description      Start SDP to get remote services
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_get_remote_service_record(bt_bdaddr_t* remote_addr,
+                                              bt_uuid_t* uuid);
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_get_remote_services
+ *
+ * Description      Start SDP to get remote services
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_get_remote_services(bt_bdaddr_t* remote_addr);
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_get_remote_services_by_transport
+ *
+ * Description      Start SDP to get remote services by transport
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_get_remote_services_by_transport(bt_bdaddr_t* remote_addr,
+                                                     int transport);
+
+/*******************************************************************************
+ *
+ * Function         btif_dut_mode_configure
+ *
+ * Description      Configure Test Mode - 'enable' to 1 puts the device in test
+ *                  mode and 0 exits test mode
+ *
+ * Returns          BT_STATUS_SUCCESS on success
+ *
+ ******************************************************************************/
+bt_status_t btif_dut_mode_configure(uint8_t enable);
+
+/*******************************************************************************
+ *
+ * Function         btif_dut_mode_send
+ *
+ * Description     Sends a HCI Vendor specific command to the controller
+ *
+ * Returns          BT_STATUS_SUCCESS on success
+ *
+ ******************************************************************************/
+bt_status_t btif_dut_mode_send(uint16_t opcode, uint8_t* buf, uint8_t len);
+
+/*******************************************************************************
+ *
+ * Function         btif_le_test_mode
+ *
+ * Description     Sends a HCI BLE Test command to the Controller
+ *
+ * Returns          BT_STATUS_SUCCESS on success
+ *
+ ******************************************************************************/
+bt_status_t btif_le_test_mode(uint16_t opcode, uint8_t* buf, uint8_t len);
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_read_energy_info
+ *
+ * Description     Reads the energy info from controller
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btif_dm_read_energy_info();
+
+/*******************************************************************************
+ *
+ * Function         btif_config_hci_snoop_log
+ *
+ * Description     enable or disable HCI snoop log
+ *
+ * Returns          BT_STATUS_SUCCESS on success
+ *
+ ******************************************************************************/
+bt_status_t btif_config_hci_snoop_log(uint8_t enable);
+
+/*******************************************************************************
+ *
+ * Function         btif_debug_bond_event_dump
+ *
+ * Description     Dump bond event information
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btif_debug_bond_event_dump(int fd);
+
+#endif /* BTIF_API_H */
diff --git a/bt/btif/include/btif_av.h b/bt/btif/include/btif_av.h
new file mode 100644
index 0000000..02f8521
--- /dev/null
+++ b/bt/btif/include/btif_av.h
@@ -0,0 +1,190 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ *  Filename:      btif_av.h
+ *
+ *  Description:   Main API header file for all BTIF AV functions accessed
+ *                 from internal stack.
+ *
+ *******************************************************************************/
+
+#ifndef BTIF_AV_H
+#define BTIF_AV_H
+
+#include "bta_av_api.h"
+#include "btif_common.h"
+#include "btif_sm.h"
+
+/*******************************************************************************
+ *  Type definitions for callback functions
+ *******************************************************************************/
+
+typedef enum {
+  /* Reuse BTA_AV_XXX_EVT - No need to redefine them here */
+  BTIF_AV_CONNECT_REQ_EVT = BTA_AV_MAX_EVT,
+  BTIF_AV_DISCONNECT_REQ_EVT,
+  BTIF_AV_START_STREAM_REQ_EVT,
+  BTIF_AV_STOP_STREAM_REQ_EVT,
+  BTIF_AV_SUSPEND_STREAM_REQ_EVT,
+  BTIF_AV_SINK_CONFIG_REQ_EVT,
+  BTIF_AV_OFFLOAD_START_REQ_EVT,
+  BTIF_AV_CLEANUP_REQ_EVT,
+} btif_av_sm_event_t;
+
+/*******************************************************************************
+ *  BTIF AV API
+ *******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         btif_av_get_addr
+ *
+ * Description      Fetches current AV BD address
+ *
+ * Returns          BD address
+ *
+ ******************************************************************************/
+
+bt_bdaddr_t btif_av_get_addr(void);
+
+/*******************************************************************************
+ * Function         btif_av_is_sink_enabled
+ *
+ * Description      Checks if A2DP Sink is enabled or not
+ *
+ * Returns          true if A2DP Sink is enabled, false otherwise
+ *
+ ******************************************************************************/
+
+bool btif_av_is_sink_enabled(void);
+
+/*******************************************************************************
+ *
+ * Function         btif_av_stream_ready
+ *
+ * Description      Checks whether AV is ready for starting a stream
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+
+bool btif_av_stream_ready(void);
+
+/*******************************************************************************
+ *
+ * Function         btif_av_stream_started_ready
+ *
+ * Description      Checks whether AV ready for media start in streaming state
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+
+bool btif_av_stream_started_ready(void);
+
+/*******************************************************************************
+ *
+ * Function         btif_dispatch_sm_event
+ *
+ * Description      Send event to AV statemachine
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+
+/* used to pass events to AV statemachine from other tasks */
+void btif_dispatch_sm_event(btif_av_sm_event_t event, void* p_data, int len);
+
+/*******************************************************************************
+ *
+ * Function         btif_av_init
+ *
+ * Description      Initializes btif AV if not already done
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+
+bt_status_t btif_av_init(int service_id);
+
+/*******************************************************************************
+ *
+ * Function         btif_av_is_connected
+ *
+ * Description      Checks if av has a connected sink
+ *
+ * Returns          bool
+ *
+ ******************************************************************************/
+
+bool btif_av_is_connected(void);
+
+/*******************************************************************************
+ *
+ * Function         btif_av_get_peer_sep
+ *
+ * Description      Get the stream endpoint type.
+ *
+ * Returns          The stream endpoint type: either AVDT_TSEP_SRC or
+ *                  AVDT_TSEP_SNK.
+ *
+ ******************************************************************************/
+
+uint8_t btif_av_get_peer_sep(void);
+
+/*******************************************************************************
+ *
+ * Function         btif_av_is_peer_edr
+ *
+ * Description      Check if the connected a2dp device supports
+ *                  EDR or not. Only when connected this function
+ *                  will accurately provide a true capability of
+ *                  remote peer. If not connected it will always be false.
+ *
+ * Returns          true if remote device is capable of EDR
+ *
+ ******************************************************************************/
+
+bool btif_av_is_peer_edr(void);
+
+/******************************************************************************
+ *
+ * Function         btif_av_clear_remote_suspend_flag
+ *
+ * Description      Clears remote suspended flag
+ *
+ * Returns          Void
+ *******************************************************************************/
+void btif_av_clear_remote_suspend_flag(void);
+
+/*******************************************************************************
+ *
+ * Function         btif_av_peer_supports_3mbps
+ *
+ * Description      Check if the connected A2DP device supports
+ *                  3 Mbps EDR. This function will only work while connected.
+ *                  If not connected it will always return false.
+ *
+ * Returns          true if remote device is EDR and supports 3 Mbps
+ *
+ ******************************************************************************/
+bool btif_av_peer_supports_3mbps(void);
+
+#endif /* BTIF_AV_H */
diff --git a/bt/btif/include/btif_av_co.h b/bt/btif/include/btif_av_co.h
new file mode 100644
index 0000000..f6e3a2d
--- /dev/null
+++ b/bt/btif/include/btif_av_co.h
@@ -0,0 +1,83 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_AV_CO_H
+#define BTIF_AV_CO_H
+
+#include "btif/include/btif_a2dp_source.h"
+#include "stack/include/a2dp_api.h"
+
+/*******************************************************************************
+ *  Constants & Macros
+ *******************************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+ *  Functions
+ *******************************************************************************/
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_audio_set_codec
+ **
+ ** Description      Set the current codec configuration from the feeding
+ **                  information.
+ **                  This function is starting to modify the configuration, it
+ **                  should be protected.
+ **
+ ** Returns          true if successful, false otherwise
+ **
+ *******************************************************************************/
+bool bta_av_co_audio_set_codec(const tA2DP_FEEDING_PARAMS* p_feeding_params);
+
+// Prepares a message to initialize the encoder. The prepared message is
+// stored in |p_init_params|.
+// |p_init_params| cannot be null.
+void bta_av_co_audio_encoder_init(tA2DP_ENCODER_INIT_PARAMS* p_init_params);
+
+// Prepares a message to update the encoder. The prepared message is
+// stored in |p_update_params|.
+// |p_update_params| cannot be null.
+void bta_av_co_audio_encoder_update(
+    tA2DP_ENCODER_UPDATE_PARAMS* p_update_params);
+
+// Gets the current A2DP encoder interface that can be used to encode and
+// prepare A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
+// Returns the A2DP encoder interface if the current codec is setup,
+// otherwise NULL.
+const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface(void);
+
+/*******************************************************************************
+ **
+ ** Function         bta_av_co_init
+ **
+ ** Description      Initialization
+ **
+ ** Returns          Nothing
+ **
+ *******************************************************************************/
+void bta_av_co_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTIF_AV_CO_H */
diff --git a/bt/btif/include/btif_avrcp_audio_track.h b/bt/btif/include/btif_avrcp_audio_track.h
new file mode 100644
index 0000000..6986e43
--- /dev/null
+++ b/bt/btif/include/btif_avrcp_audio_track.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Implements an API to be used by A2DP to do streaming of music over a media
+ * stream. This API provides mechanism to create and control playback of the
+ * media stream depending on the data bits coming from the remote device. The
+ * media stream is played over the default audio media stream type and hence
+ * volume control is handled entirely by the Audio Manager (which is also the
+ * original motivation for this solution.
+ *
+ * TODO: Once the AudioManager provides support for patching audio sources with
+ * volume control we should deprecate this file.
+ */
+
+/**
+ * Creates an audio track object and returns a void handle. Use this handle to
+ * the
+ * following functions.
+ *
+ * The ownership of the handle is maintained by the caller of this API and it
+ * should eventually be
+ * deleted using BtifAvrcpAudioTrackDelete (see below).
+ */
+void* BtifAvrcpAudioTrackCreate(int trackFreq, int channelType);
+
+/**
+ * Starts the audio track.
+ */
+void BtifAvrcpAudioTrackStart(void* handle);
+
+/**
+ * Pauses the audio track.
+ */
+void BtifAvrcpAudioTrackPause(void* handle);
+
+/**
+ * Sets audio track gain.
+ */
+void BtifAvrcpSetAudioTrackGain(void* handle, float gain);
+
+/**
+ * Stop / Delete the audio track.
+ * Delete should usually be called stop.
+ */
+void BtifAvrcpAudioTrackStop(void* handle);
+void BtifAvrcpAudioTrackDelete(void* handle);
+
+/**
+ * Writes the audio track data to file.
+ *
+ * Used only for debugging.
+ */
+int BtifAvrcpAudioTrackWriteData(void* handle, void* audioBuffer,
+                                 int bufferlen);
diff --git a/bt/btif/include/btif_common.h b/bt/btif/include/btif_common.h
new file mode 100644
index 0000000..d7b9047
--- /dev/null
+++ b/bt/btif/include/btif_common.h
@@ -0,0 +1,243 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_COMMON_H
+#define BTIF_COMMON_H
+
+#include <stdlib.h>
+
+#include <hardware/bluetooth.h>
+
+#include "bt_types.h"
+#include "bta_api.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+/*******************************************************************************
+ *  Constants & Macros
+ *******************************************************************************/
+
+#define ASSERTC(cond, msg, val)                                              \
+  do {                                                                       \
+    if (!(cond)) {                                                           \
+      LOG_ERROR(LOG_TAG, "### ASSERT : %s %s line %d %s (%d) ###", __FILE__, \
+                __func__, __LINE__, (msg), (val));                           \
+    }                                                                        \
+  } while (0)
+
+/* Calculate start of event enumeration; id is top 8 bits of event */
+#define BTIF_SIG_START(id) ((id) << 8)
+
+/* For upstream the MSB bit is always SET */
+#define BTIF_SIG_CB_BIT (0x8000)
+#define BTIF_SIG_CB_START(id) (((id) << 8) | BTIF_SIG_CB_BIT)
+
+/*
+ * A memcpy(3) wrapper when copying memory that might not be aligned.
+ *
+ * On certain architectures, if the memcpy(3) arguments appear to be
+ * pointing to aligned memory (e.g., struct pointers), the compiler might
+ * generate optimized memcpy(3) code. However, if the original memory was not
+ * aligned (e.g., because of incorrect "char *" to struct pointer casting),
+ * the result code might trigger SIGBUS crash.
+ *
+ * As a short-term solution, we use the help of the maybe_non_aligned_memcpy()
+ * macro to identify and fix such cases. In the future, we should fix the
+ * problematic "char *" to struct pointer casting, and this macro itself should
+ * be removed.
+ */
+#define maybe_non_aligned_memcpy(_a, _b, _c) memcpy((void*)(_a), (_b), (_c))
+
+/* BTIF sub-systems */
+#define BTIF_CORE 0
+#define BTIF_DM 1
+#define BTIF_HFP 2
+#define BTIF_AV 3
+#define BTIF_PAN 4
+#define BTIF_HF_CLIENT 5
+
+extern bt_callbacks_t* bt_hal_cbacks;
+
+#define HAL_CBACK(P_CB, P_CBACK, ...)                \
+  do {                                               \
+    if ((P_CB) && (P_CB)->P_CBACK) {                 \
+      BTIF_TRACE_API("HAL %s->%s", #P_CB, #P_CBACK); \
+      (P_CB)->P_CBACK(__VA_ARGS__);                  \
+    } else {                                         \
+      ASSERTC(0, "Callback is NULL", 0);             \
+    }                                                \
+  } while (0)
+
+/**
+ * BTIF events for requests that require context switch to btif task
+ * on downstreams path
+ */
+enum {
+  BTIF_CORE_API_START = BTIF_SIG_START(BTIF_CORE),
+  BTIF_CORE_STORAGE_NO_ACTION,
+  BTIF_CORE_STORAGE_ADAPTER_WRITE,
+  BTIF_CORE_STORAGE_ADAPTER_READ,
+  BTIF_CORE_STORAGE_ADAPTER_READ_ALL,
+  BTIF_CORE_STORAGE_REMOTE_WRITE,
+  BTIF_CORE_STORAGE_REMOTE_READ,
+  BTIF_CORE_STORAGE_REMOTE_READ_ALL,
+  BTIF_CORE_STORAGE_READ_ALL,
+  BTIF_CORE_STORAGE_NOTIFY_STATUS,
+  /* add here */
+
+  BTIF_DM_API_START = BTIF_SIG_START(BTIF_DM),
+  BTIF_DM_ENABLE_SERVICE,
+  BTIF_DM_DISABLE_SERVICE,
+  /* add here */
+
+  BTIF_HFP_API_START = BTIF_SIG_START(BTIF_HFP),
+  /* add here */
+
+  BTIF_AV_API_START = BTIF_SIG_START(BTIF_AV),
+  /* add here */
+};
+
+/**
+ * BTIF events for callbacks that require context switch to btif task
+ * on upstream path - Typically these would be non-BTA events
+ * that are generated by the BTIF layer.
+ */
+enum {
+  BTIF_CORE_CB_START = BTIF_SIG_CB_START(BTIF_CORE),
+  /* add here */
+
+  BTIF_DM_CB_START = BTIF_SIG_CB_START(BTIF_DM),
+  BTIF_DM_CB_DISCOVERY_STARTED, /* Discovery has started */
+  BTIF_DM_CB_CREATE_BOND,       /* Create bond */
+  BTIF_DM_CB_REMOVE_BOND,       /*Remove bond */
+  BTIF_DM_CB_HID_REMOTE_NAME,   /* Remote name callback for HID device */
+  BTIF_DM_CB_BOND_STATE_BONDING,
+  BTIF_DM_CB_LE_TX_TEST,  /* BLE Tx Test command complete callback */
+  BTIF_DM_CB_LE_RX_TEST,  /* BLE Rx Test command complete callback */
+  BTIF_DM_CB_LE_TEST_END, /* BLE Test mode end callback */
+
+  BTIF_HFP_CB_START = BTIF_SIG_CB_START(BTIF_HFP),
+  BTIF_HFP_CB_AUDIO_CONNECTING, /* HF AUDIO connect has been sent to BTA
+                                   successfully */
+
+  BTIF_PAN_CB_START = BTIF_SIG_CB_START(BTIF_PAN),
+  BTIF_PAN_CB_DISCONNECTING, /* PAN Disconnect has been sent to BTA successfully
+                                */
+
+  BTIF_HF_CLIENT_CLIENT_CB_START = BTIF_SIG_CB_START(BTIF_HF_CLIENT),
+  BTIF_HF_CLIENT_CB_AUDIO_CONNECTING, /* AUDIO connect has been sent to BTA
+                                         successfully */
+};
+
+/* Macro definitions for BD ADDR persistence */
+
+/**
+ * PROPERTY_BT_BDADDR_PATH
+ * The property key stores the storage location of Bluetooth Device Address
+ */
+#ifndef PROPERTY_BT_BDADDR_PATH
+#define PROPERTY_BT_BDADDR_PATH "ro.bt.bdaddr_path"
+#endif
+
+/**
+ * PERSIST_BDADDR_PROPERTY
+ * If there is no valid bdaddr available from PROPERTY_BT_BDADDR_PATH,
+ * generating a random BDADDR and keeping it in the PERSIST_BDADDR_DROP.
+ */
+#ifndef PERSIST_BDADDR_PROPERTY
+#define PERSIST_BDADDR_PROPERTY "persist.service.bdroid.bdaddr"
+#endif
+
+/**
+ * FACTORY_BT_BDADDR_PROPERTY
+ * If there is no valid bdaddr available from PROPERTY_BT_BDADDR_PATH
+ * and there is no available persistent bdaddr available from
+ * PERSIST_BDADDR_PROPERTY use a factory set address
+ */
+#ifndef FACTORY_BT_ADDR_PROPERTY
+#define FACTORY_BT_ADDR_PROPERTY "ro.boot.btmacaddr"
+#endif
+
+#define FACTORY_BT_BDADDR_STORAGE_LEN 17
+
+/*******************************************************************************
+ *  Type definitions for callback functions
+ *******************************************************************************/
+
+typedef void(tBTIF_CBACK)(uint16_t event, char* p_param);
+typedef void(tBTIF_COPY_CBACK)(uint16_t event, char* p_dest, char* p_src);
+
+/*******************************************************************************
+ *  Type definitions and return values
+ *******************************************************************************/
+
+/* this type handles all btif context switches between BTU and HAL */
+typedef struct {
+  BT_HDR hdr;
+  tBTIF_CBACK* p_cb; /* context switch callback */
+
+  /* parameters passed to callback */
+  uint16_t event;                          /* message event id */
+  char __attribute__((aligned)) p_param[]; /* parameter area needs to be last */
+} tBTIF_CONTEXT_SWITCH_CBACK;
+
+/*******************************************************************************
+ *  Functions
+ *******************************************************************************/
+
+tBTA_SERVICE_MASK btif_get_enabled_services_mask(void);
+bt_status_t btif_enable_service(tBTA_SERVICE_ID service_id);
+bt_status_t btif_disable_service(tBTA_SERVICE_ID service_id);
+int btif_is_enabled(void);
+
+/**
+ * BTIF_Events
+ */
+void btif_enable_bluetooth_evt(tBTA_STATUS status);
+void btif_disable_bluetooth_evt(void);
+void btif_adapter_properties_evt(bt_status_t status, uint32_t num_props,
+                                 bt_property_t* p_props);
+void btif_remote_properties_evt(bt_status_t status, bt_bdaddr_t* remote_addr,
+                                uint32_t num_props, bt_property_t* p_props);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void bte_load_did_conf(const char* p_path);
+void bte_main_boot_entry(void);
+void bte_main_enable(void);
+void bte_main_disable(void);
+void bte_main_cleanup(void);
+#if (HCILP_INCLUDED == TRUE)
+void bte_main_enable_lpm(bool enable);
+#endif
+void bte_main_postload_cfg(void);
+
+bt_status_t btif_transfer_context(tBTIF_CBACK* p_cback, uint16_t event,
+                                  char* p_params, int param_len,
+                                  tBTIF_COPY_CBACK* p_copy_cback);
+
+void btif_init_ok(UNUSED_ATTR uint16_t event, UNUSED_ATTR char* p_param);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTIF_COMMON_H */
diff --git a/bt/btif/include/btif_config.h b/bt/btif/include/btif_config.h
new file mode 100644
index 0000000..5d9ea33
--- /dev/null
+++ b/bt/btif/include/btif_config.h
@@ -0,0 +1,61 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+#include <stddef.h>
+
+#include "bt_types.h"
+
+static const char BTIF_CONFIG_MODULE[] = "btif_config_module";
+
+typedef struct btif_config_section_iter_t btif_config_section_iter_t;
+
+bool btif_config_has_section(const char* section);
+bool btif_config_exist(const char* section, const char* key);
+bool btif_config_get_int(const char* section, const char* key, int* value);
+bool btif_config_set_int(const char* section, const char* key, int value);
+bool btif_config_get_str(const char* section, const char* key, char* value,
+                         int* size_bytes);
+bool btif_config_set_str(const char* section, const char* key,
+                         const char* value);
+bool btif_config_get_bin(const char* section, const char* key, uint8_t* value,
+                         size_t* length);
+bool btif_config_set_bin(const char* section, const char* key,
+                         const uint8_t* value, size_t length);
+bool btif_config_remove(const char* section, const char* key);
+
+size_t btif_config_get_bin_length(const char* section, const char* key);
+
+const btif_config_section_iter_t* btif_config_section_begin(void);
+const btif_config_section_iter_t* btif_config_section_end(void);
+const btif_config_section_iter_t* btif_config_section_next(
+    const btif_config_section_iter_t* section);
+const char* btif_config_section_name(const btif_config_section_iter_t* section);
+
+void btif_config_save(void);
+void btif_config_flush(void);
+bool btif_config_clear(void);
+
+// TODO(zachoverflow): Eww...we need to move these out. These are peer specific,
+// not config general.
+bool btif_get_address_type(const BD_ADDR bd_addr, int* p_addr_type);
+bool btif_get_device_type(const BD_ADDR bd_addr, int* p_device_type);
+
+void btif_debug_config_dump(int fd);
diff --git a/bt/btif/include/btif_config_transcode.h b/bt/btif/include/btif_config_transcode.h
new file mode 100644
index 0000000..66aac8a
--- /dev/null
+++ b/bt/btif/include/btif_config_transcode.h
@@ -0,0 +1,23 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+typedef struct config_t config_t;
+
+config_t* btif_config_transcode(const char* xml_filename);
diff --git a/bt/btif/include/btif_debug.h b/bt/btif/include/btif_debug.h
new file mode 100644
index 0000000..f6a3cc7
--- /dev/null
+++ b/bt/btif/include/btif_debug.h
@@ -0,0 +1,30 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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>
+
+// Debug API
+
+void btif_debug_init(void);
+
+// Debug helpers
+
+// Timestamp in us
+uint64_t btif_debug_ts(void);
diff --git a/bt/btif/include/btif_debug_btsnoop.h b/bt/btif/include/btif_debug_btsnoop.h
new file mode 100644
index 0000000..e82421a
--- /dev/null
+++ b/bt/btif/include/btif_debug_btsnoop.h
@@ -0,0 +1,44 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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>
+
+#define BTSNOOZ_CURRENT_VERSION 0x02
+
+// The preamble is stored un-encrypted as the first part
+// of the file.
+typedef struct btsnooz_preamble_t {
+  uint8_t version;
+  uint64_t last_timestamp_ms;
+} __attribute__((__packed__)) btsnooz_preamble_t;
+
+// One header for each HCI packet
+typedef struct btsnooz_header_t {
+  uint16_t length;
+  uint16_t packet_length;
+  uint32_t delta_time_ms;
+  uint8_t type;
+} __attribute__((__packed__)) btsnooz_header_t;
+
+// Initializes btsnoop memory logging and registers
+void btif_debug_btsnoop_init(void);
+
+// Writes btsnoop data base64 encoded to fd
+void btif_debug_btsnoop_dump(int fd);
diff --git a/bt/btif/include/btif_debug_conn.h b/bt/btif/include/btif_debug_conn.h
new file mode 100644
index 0000000..1823b8a
--- /dev/null
+++ b/bt/btif/include/btif_debug_conn.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <hardware/bluetooth.h>
+
+#include "gatt_api.h"
+
+typedef enum {
+  BTIF_DEBUG_CONNECTED = 1,
+  BTIF_DEBUG_DISCONNECTED
+} btif_debug_conn_state_t;
+
+// Report a connection state change
+void btif_debug_conn_state(const bt_bdaddr_t bda,
+                           const btif_debug_conn_state_t state,
+                           const tGATT_DISCONN_REASON disconnect_reason);
+
+void btif_debug_conn_dump(int fd);
diff --git a/bt/btif/include/btif_dm.h b/bt/btif/include/btif_dm.h
new file mode 100644
index 0000000..b517e86
--- /dev/null
+++ b/bt/btif/include/btif_dm.h
@@ -0,0 +1,111 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_DM_H
+#define BTIF_DM_H
+
+#include "bta_api.h"
+#include "bte_appl.h"
+#include "btif_uid.h"
+
+/************************************************************************************
+ *  Functions
+ *******************************************************************************/
+void btif_dm_init(uid_set_t* set);
+void btif_dm_cleanup(void);
+
+/**
+ * BTIF callback to switch context from bte to btif
+ */
+void bte_dm_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data);
+
+/**
+ * Notify BT disable being initiated. DM may chose to abort
+ * pending commands, like pairing
+ */
+void btif_dm_on_disable(void);
+
+/**
+ * Callout for handling io_capabilities request
+ */
+void btif_dm_proc_io_req(BD_ADDR bd_addr, tBTA_IO_CAP* p_io_cap,
+                         tBTA_OOB_DATA* p_oob_data, tBTA_AUTH_REQ* p_auth_req,
+                         bool is_orig);
+/**
+ * Callout for handling io_capabilities response
+ */
+void btif_dm_proc_io_rsp(BD_ADDR bd_addr, tBTA_IO_CAP io_cap,
+                         tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req);
+
+/**
+ * Out-of-band functions
+ */
+void btif_dm_set_oob_for_io_req(tBTA_OOB_DATA* p_oob_data);
+void btif_dm_set_oob_for_le_io_req(BD_ADDR bd_addr, tBTA_OOB_DATA* p_oob_data,
+                                   tBTA_LE_AUTH_REQ* p_auth_req);
+#ifdef BTIF_DM_OOB_TEST
+void btif_dm_load_local_oob(void);
+void btif_dm_proc_loc_oob(bool valid, BT_OCTET16 c, BT_OCTET16 r);
+bool btif_dm_proc_rmt_oob(BD_ADDR bd_addr, BT_OCTET16 p_c, BT_OCTET16 p_r);
+#endif /* BTIF_DM_OOB_TEST */
+#if (BLE_INCLUDED == TRUE)
+
+/*callout for reading SMP properties from Text file*/
+bool btif_dm_get_smp_config(tBTE_APPL_CFG* p_cfg);
+
+typedef struct {
+  bool is_penc_key_rcvd;
+  tBTM_LE_PENC_KEYS penc_key; /* received peer encryption key */
+  bool is_pcsrk_key_rcvd;
+  tBTM_LE_PCSRK_KEYS pcsrk_key; /* received peer device SRK */
+  bool is_pid_key_rcvd;
+  tBTM_LE_PID_KEYS pid_key; /* peer device ID key */
+  bool is_lenc_key_rcvd;
+  tBTM_LE_LENC_KEYS
+      lenc_key; /* local encryption reproduction keys LTK = = d1(ER,DIV,0)*/
+  bool is_lcsrk_key_rcvd;
+  tBTM_LE_LCSRK_KEYS lcsrk_key; /* local device CSRK = d1(ER,DIV,1)*/
+  bool is_lidk_key_rcvd;        /* local identity key received */
+} btif_dm_ble_cb_t;
+
+#define BTIF_DM_LE_KEY_PENC BTA_LE_KEY_PENC
+#define BTIF_DM_LE_KEY_PID BTA_LE_KEY_PID
+#define BTIF_DM_LE_KEY_PCSRK BTA_LE_KEY_PCSRK
+#define BTIF_DM_LE_KEY_LENC BTA_LE_KEY_LENC
+#define BTIF_DM_LE_KEY_LID BTA_LE_KEY_LID
+#define BTIF_DM_LE_KEY_LCSRK BTA_LE_KEY_LCSRK
+
+#define BTIF_DM_LE_LOCAL_KEY_IR (1 << 0)
+#define BTIF_DM_LE_LOCAL_KEY_IRK (1 << 1)
+#define BTIF_DM_LE_LOCAL_KEY_DHK (1 << 2)
+#define BTIF_DM_LE_LOCAL_KEY_ER (1 << 3)
+
+void btif_dm_load_ble_local_keys(void);
+void btif_dm_get_ble_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask,
+                                BT_OCTET16 er,
+                                tBTA_BLE_LOCAL_ID_KEYS* p_id_keys);
+void btif_dm_save_ble_bonding_keys(void);
+void btif_dm_remove_ble_bonding_keys(void);
+void btif_dm_ble_sec_req_evt(tBTA_DM_BLE_SEC_REQ* p_ble_req);
+
+void btif_dm_update_ble_remote_properties(BD_ADDR bd_addr, BD_NAME bd_name,
+                                          tBT_DEVICE_TYPE dev_type);
+
+#endif /* BLE_INCLUDED */
+
+#endif
diff --git a/bt/btif/include/btif_gatt.h b/bt/btif/include/btif_gatt.h
new file mode 100644
index 0000000..c5d56b0
--- /dev/null
+++ b/bt/btif/include/btif_gatt.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ *  Name:          btif_gatt.h
+ *
+ *  Description:
+ *
+ *****************************************************************************/
+
+#ifndef BTIF_GATT_H
+#define BTIF_GATT_H
+
+extern const btgatt_client_interface_t btgattClientInterface;
+extern const btgatt_server_interface_t btgattServerInterface;
+extern const btgatt_scanner_interface_t btgattScannerInterface;
+
+BleAdvertiserInterface* get_ble_advertiser_instance();
+#endif
diff --git a/bt/btif/include/btif_gatt_util.h b/bt/btif/include/btif_gatt_util.h
new file mode 100644
index 0000000..4a8d412
--- /dev/null
+++ b/bt/btif/include/btif_gatt_util.h
@@ -0,0 +1,42 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_GATT_UTIL_H
+#define BTIF_GATT_UTIL_H
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
+
+#include "bta/include/bta_gatt_api.h"
+
+void btif_to_bta_uuid(tBT_UUID* p_dest, const bt_uuid_t* p_src);
+void btif_to_bta_response(tBTA_GATTS_RSP* p_dest, btgatt_response_t* p_src);
+void btif_to_bta_uuid_mask(tBTA_DM_BLE_PF_COND_MASK* p_mask,
+                           const bt_uuid_t* p_src, const bt_uuid_t* svc_uuid);
+
+void bta_to_btif_uuid(bt_uuid_t* p_dest, tBT_UUID* p_src);
+
+uint16_t set_read_value(btgatt_read_params_t* p_dest, tBTA_GATTC_READ* p_src);
+uint16_t get_uuid16(tBT_UUID* p_uuid);
+
+void btif_gatt_check_encrypted_link(BD_ADDR bd_addr,
+                                    tBTA_GATT_TRANSPORT transport);
+extern void btif_gatt_move_track_adv_data(btgatt_track_adv_info_t* p_dest,
+                                          btgatt_track_adv_info_t* p_src);
+
+#endif
diff --git a/bt/btif/include/btif_hf.h b/bt/btif/include/btif_hf.h
new file mode 100644
index 0000000..4642e2a
--- /dev/null
+++ b/bt/btif/include/btif_hf.h
@@ -0,0 +1,36 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_HF_H
+#define BTIF_HF_H
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Check whether there is a Hands-Free call in progress.
+// Returns true if no call is in progress.
+bool btif_hf_is_call_idle(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTIF_HF_H */
diff --git a/bt/btif/include/btif_hh.h b/bt/btif/include/btif_hh.h
new file mode 100644
index 0000000..39d1a11
--- /dev/null
+++ b/bt/btif/include/btif_hh.h
@@ -0,0 +1,109 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_HH_H
+#define BTIF_HH_H
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hh.h>
+#include <pthread.h>
+#include <stdint.h>
+#include "bta_hh_api.h"
+#include "btu.h"
+
+/*******************************************************************************
+ *  Constants & Macros
+ *******************************************************************************/
+
+#define BTIF_HH_MAX_HID 8
+#define BTIF_HH_MAX_ADDED_DEV 32
+
+#define BTIF_HH_MAX_KEYSTATES 3
+#define BTIF_HH_KEYSTATE_MASK_NUMLOCK 0x01
+#define BTIF_HH_KEYSTATE_MASK_CAPSLOCK 0x02
+#define BTIF_HH_KEYSTATE_MASK_SCROLLLOCK 0x04
+
+#define BTIF_HH_MAX_POLLING_ATTEMPTS 10
+#define BTIF_HH_POLLING_SLEEP_DURATION_US 5000
+
+/*******************************************************************************
+ *  Type definitions and return values
+ *******************************************************************************/
+
+typedef enum {
+  BTIF_HH_DISABLED = 0,
+  BTIF_HH_ENABLED,
+  BTIF_HH_DISABLING,
+  BTIF_HH_DEV_UNKNOWN,
+  BTIF_HH_DEV_CONNECTING,
+  BTIF_HH_DEV_CONNECTED,
+  BTIF_HH_DEV_DISCONNECTED
+} BTIF_HH_STATUS;
+
+typedef struct {
+  bthh_connection_state_t dev_status;
+  uint8_t dev_handle;
+  bt_bdaddr_t bd_addr;
+  tBTA_HH_ATTR_MASK attr_mask;
+  uint8_t sub_class;
+  uint8_t app_id;
+  int fd;
+  bool ready_for_data;
+  pthread_t hh_poll_thread_id;
+  uint8_t hh_keep_polling;
+  alarm_t* vup_timer;
+  bool local_vup;  // Indicated locally initiated VUP
+} btif_hh_device_t;
+
+/* Control block to maintain properties of devices */
+typedef struct {
+  uint8_t dev_handle;
+  bt_bdaddr_t bd_addr;
+  tBTA_HH_ATTR_MASK attr_mask;
+} btif_hh_added_device_t;
+
+/**
+ * BTIF-HH control block to maintain added devices and currently
+ * connected hid devices
+ */
+typedef struct {
+  BTIF_HH_STATUS status;
+  btif_hh_device_t devices[BTIF_HH_MAX_HID];
+  uint32_t device_num;
+  btif_hh_added_device_t added_devices[BTIF_HH_MAX_ADDED_DEV];
+  btif_hh_device_t* p_curr_dev;
+} btif_hh_cb_t;
+
+/*******************************************************************************
+ *  Functions
+ *******************************************************************************/
+
+extern btif_hh_cb_t btif_hh_cb;
+
+extern btif_hh_device_t* btif_hh_find_connected_dev_by_handle(uint8_t handle);
+extern void btif_hh_remove_device(bt_bdaddr_t bd_addr);
+bool btif_hh_add_added_dev(bt_bdaddr_t bda, tBTA_HH_ATTR_MASK attr_mask);
+extern bt_status_t btif_hh_virtual_unplug(bt_bdaddr_t* bd_addr);
+extern void btif_hh_disconnect(bt_bdaddr_t* bd_addr);
+extern void btif_hh_setreport(btif_hh_device_t* p_dev,
+                              bthh_report_type_t r_type, uint16_t size,
+                              uint8_t* report);
+
+bool btif_hh_add_added_dev(bt_bdaddr_t bd_addr, tBTA_HH_ATTR_MASK attr_mask);
+
+#endif
diff --git a/bt/btif/include/btif_hl.h b/bt/btif/include/btif_hl.h
new file mode 100644
index 0000000..94cd108
--- /dev/null
+++ b/bt/btif/include/btif_hl.h
@@ -0,0 +1,315 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_HL_H
+#define BTIF_HL_H
+
+#include <hardware/bluetooth.h>
+
+#include "bt_common.h"
+#include "bta_hl_api.h"
+#include "osi/include/alarm.h"
+
+/*******************************************************************************
+ *  Constants & Macros
+ *******************************************************************************/
+
+#define BTIF_HL_DATA_TYPE_NONE 0x0000
+#define BTIF_HL_DATA_TYPE_PULSE_OXIMETER 0x1004 /* from BT assigned number */
+#define BTIF_HL_DATA_TYPE_BLOOD_PRESSURE_MON 0x1007
+#define BTIF_HL_DATA_TYPE_BODY_THERMOMETER 0x1008
+#define BTIF_HL_DATA_TYPE_BODY_WEIGHT_SCALE 0x100F
+#define BTIF_HL_DATA_TYPE_GLUCOSE_METER 0x1011
+#define BTIF_HL_DATA_TYPE_STEP_COUNTER 0x1068
+#define BTIF_HL_DATA_TYPE_BCA 0x1014
+#define BTIF_HL_DATA_TYPE_PEAK_FLOW 0x1015
+#define BTIF_HL_DATA_TYPE_CARDIO 0x1029
+#define BTIF_HL_DATA_TYPE_ACTIVITY_HUB 0x1047
+#define BTIF_HL_DATA_TYPE_AMM 0x1048
+
+#define BTIF_HL_CCH_NUM_FILTER_ELEMS 3
+#define BTIF_HL_APPLICATION_NAME_LEN 512
+
+/*******************************************************************************
+ *  Type definitions and return values
+ *******************************************************************************/
+
+typedef enum {
+  BTIF_HL_SOC_STATE_IDLE,
+  BTIF_HL_SOC_STATE_W4_ADD,
+  BTIF_HL_SOC_STATE_W4_CONN,
+  BTIF_HL_SOC_STATE_W4_READ,
+  BTIF_HL_SOC_STATE_W4_REL
+} btif_hl_soc_state_t;
+
+typedef enum {
+  BTIF_HL_STATE_DISABLED,
+  BTIF_HL_STATE_DISABLING,
+  BTIF_HL_STATE_ENABLED,
+  BTIF_HL_STATE_ENABLING,
+} btif_hl_state_t;
+
+typedef enum {
+  BTIF_HL_CCH_OP_NONE,
+  BTIF_HL_CCH_OP_MDEP_FILTERING,
+  BTIF_HL_CCH_OP_MATCHED_CTRL_PSM,
+  BTIF_HL_CCH_OP_DCH_OPEN,
+  BTIF_HL_CCH_OP_DCH_RECONNECT,
+  BTIF_HL_CCH_OP_DCH_ECHO_TEST
+} btif_hl_cch_op_t;
+
+typedef enum {
+  BTIF_HL_PEND_DCH_OP_NONE,
+  BTIF_HL_PEND_DCH_OP_DELETE_MDL,
+  BTIF_HL_PEND_DCH_OP_OPEN,
+  BTIF_HL_PEND_DCH_OP_RECONNECT
+} btif_hl_pend_dch_op_t;
+
+typedef enum { BTIF_HL_DCH_OP_NONE, BTIF_HL_DCH_OP_DISC } btif_hl_dch_op_t;
+
+typedef enum {
+  BTIF_HL_CHAN_CB_STATE_NONE,
+  BTIF_HL_CHAN_CB_STATE_CONNECTING_PENDING,
+  BTIF_HL_CHAN_CB_STATE_CONNECTED_PENDING,
+
+  BTIF_HL_CHAN_CB_STATE_DISCONNECTING_PENDING,
+  BTIF_HL_CHAN_CB_STATE_DISCONNECTED_PENDING,
+  BTIF_HL_CHAN_CB_STATE_DESTROYED_PENDING,
+} btif_hl_chan_cb_state_t;
+
+enum {
+  BTIF_HL_SEND_CONNECTED_CB,
+  BTIF_HL_SEND_DISCONNECTED_CB,
+  BTIF_HL_REG_APP,
+  BTIF_HL_UNREG_APP,
+  BTIF_HL_UPDATE_MDL,
+};
+
+typedef struct {
+  uint8_t mdep_cfg_idx;
+  int data_type;
+  tBTA_HL_MDEP_ID peer_mdep_id;
+} btif_hl_extra_mdl_cfg_t;
+
+typedef struct {
+  tBTA_HL_MDL_CFG base;
+  btif_hl_extra_mdl_cfg_t extra;
+} btif_hl_mdl_cfg_t;
+
+typedef struct {
+  bool active;
+  uint8_t app_idx;
+} btif_hl_app_data_t;
+
+typedef struct {
+  int channel_id;
+  BD_ADDR bd_addr;
+  uint8_t mdep_cfg_idx;
+  int max_s;
+  int socket_id[2];
+  uint8_t app_idx;
+  uint8_t mcl_idx;
+  uint8_t mdl_idx;
+  btif_hl_soc_state_t state;
+} btif_hl_soc_cb_t;
+
+typedef struct {
+  uint16_t data_type;
+  uint16_t max_tx_apdu_size;
+  uint16_t max_rx_apdu_size;
+} btif_hl_data_type_cfg_t;
+
+typedef struct {
+  uint16_t data_type;
+  tBTA_HL_MDEP_ROLE peer_mdep_role;
+} btif_hl_filter_elem_t;
+
+typedef struct {
+  uint8_t num_elems;
+  btif_hl_filter_elem_t elem[BTIF_HL_CCH_NUM_FILTER_ELEMS];
+} btif_hl_cch_filter_t;
+
+typedef struct {
+  bool in_use;
+  uint16_t mdl_id;
+  tBTA_HL_MDL_HANDLE mdl_handle;
+  btif_hl_dch_op_t dch_oper;
+  tBTA_HL_MDEP_ID local_mdep_id;
+  uint8_t local_mdep_cfg_idx;
+  tBTA_HL_DCH_CFG local_cfg;
+  tBTA_HL_MDEP_ID peer_mdep_id;
+  uint16_t peer_data_type;
+  tBTA_HL_MDEP_ROLE peer_mdep_role;
+  tBTA_HL_DCH_MODE dch_mode;
+  tBTA_SEC sec_mask;
+  bool is_the_first_reliable;
+  bool delete_mdl;
+  uint16_t mtu;
+  tMCA_CHNL_CFG chnl_cfg;
+  uint16_t tx_size;
+  uint8_t* p_tx_pkt;
+  uint8_t* p_rx_pkt;
+  bool cong;
+  btif_hl_soc_cb_t* p_scb;
+  int channel_id;
+} btif_hl_mdl_cb_t;
+
+typedef struct {
+  int channel_id;
+  int mdep_cfg_idx;
+  bool in_use;
+  btif_hl_chan_cb_state_t cb_state;
+  btif_hl_pend_dch_op_t op;
+  BD_ADDR bd_addr;
+  bool abort_pending;
+} btif_hl_pending_chan_cb_t;
+
+typedef struct {
+  btif_hl_mdl_cb_t mdl[BTA_HL_NUM_MDLS_PER_MCL];
+  bool in_use;
+  bool is_connected;
+  uint16_t req_ctrl_psm;
+  uint16_t ctrl_psm;
+  uint16_t data_psm;
+  BD_ADDR bd_addr;
+  uint16_t cch_mtu;
+  tBTA_SEC sec_mask;
+  tBTA_HL_MCL_HANDLE mcl_handle;
+  btif_hl_pending_chan_cb_t pcb;
+  bool valid_sdp_idx;
+  uint8_t sdp_idx;
+  tBTA_HL_SDP sdp;
+  btif_hl_cch_op_t cch_oper;
+  alarm_t* cch_timer;
+} btif_hl_mcl_cb_t;
+
+typedef struct {
+  bool active;
+  uint16_t mdl_id;
+  uint8_t mdep_cfg_idx;
+  BD_ADDR bd_addr;
+  int channel_id;
+} btif_hl_delete_mdl_t;
+
+typedef struct {
+  btif_hl_mcl_cb_t mcb[BTA_HL_NUM_MCLS]; /* application Control Blocks */
+  bool in_use;                           /* this CB is in use*/
+  bool reg_pending;
+  uint8_t app_id;
+
+  tBTA_HL_SUP_FEATURE sup_feature;
+  tBTA_HL_DCH_CFG channel_type[BTA_HL_NUM_MDEPS];
+  tBTA_HL_SDP_INFO_IND sdp_info_ind;
+  btif_hl_cch_filter_t filter;
+
+  btif_hl_mdl_cfg_t mdl_cfg[BTA_HL_NUM_MDL_CFGS];
+  int mdl_cfg_channel_id[BTA_HL_NUM_MDL_CFGS];
+
+  btif_hl_delete_mdl_t delete_mdl;
+  tBTA_HL_DEVICE_TYPE dev_type;
+  tBTA_HL_APP_HANDLE app_handle;
+  uint16_t sec_mask; /* Security mask for BTM_SetSecurityLevel() */
+  char srv_name[BTA_SERVICE_NAME_LEN +
+                1]; /* service name to be used in the SDP; null terminated*/
+  char srv_desp[BTA_SERVICE_DESP_LEN + 1]; /* service description to be used in
+                                              the SDP; null terminated */
+  char provider_name[BTA_PROVIDER_NAME_LEN + 1]; /* provide name to be used in
+                                                    the SDP; null terminated */
+  char
+      application_name[BTIF_HL_APPLICATION_NAME_LEN + 1]; /* applicaiton name */
+} btif_hl_app_cb_t;
+
+typedef struct {
+  bool in_use;
+  uint8_t app_idx;
+} btif_hl_pending_reg_cb_t;
+
+/* BTIF-HL control block  */
+typedef struct {
+  btif_hl_app_cb_t acb[BTA_HL_NUM_APPS]; /* HL Control Blocks */
+  tBTA_HL_CTRL_CBACK* p_ctrl_cback; /* pointer to control callback function */
+  uint8_t next_app_id;
+  uint16_t next_channel_id;
+  btif_hl_state_t state;
+} btif_hl_cb_t;
+
+typedef uint8_t btif_hl_evt_t;
+
+typedef struct {
+  int app_id;
+  BD_ADDR bd_addr;
+  int mdep_cfg_index;
+  int channel_id;
+  btif_hl_chan_cb_state_t cb_state;
+  int fd;
+} btif_hl_send_chan_state_cb_t;
+
+typedef struct { uint8_t app_idx; } btif_hl_reg_t;
+
+typedef btif_hl_reg_t btif_hl_unreg_t;
+typedef btif_hl_reg_t btif_hl_update_mdl_t;
+
+typedef union {
+  btif_hl_send_chan_state_cb_t chan_cb;
+  btif_hl_reg_t reg;
+  btif_hl_unreg_t unreg;
+  btif_hl_update_mdl_t update_mdl;
+} btif_hl_evt_cb_t;
+
+/*******************************************************************************
+ *  Functions
+ *******************************************************************************/
+
+#define BTIF_HL_GET_CB_PTR() &(btif_hl_cb)
+#define BTIF_HL_GET_APP_CB_PTR(app_idx) &(btif_hl_cb.acb[(app_idx)])
+#define BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx) \
+  &(btif_hl_cb.acb[(app_idx)].mcb[(mcl_idx)])
+#define BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx) \
+  &(btif_hl_cb.acb[(app_idx)].mcb[(mcl_idx)].mdl[mdl_idx])
+#define BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx) \
+  &(btif_hl_cb.acb[app_idx].mcb[mcl_idx].pcb)
+#define BTIF_HL_GET_MDL_CFG_PTR(app_idx, item_idx) \
+  &(btif_hl_cb.acb[(app_idx)].mdl_cfg[(item_idx)])
+#define BTIF_HL_GET_MDL_CFG_CHANNEL_ID_PTR(app_idx, item_idx) \
+  &(btif_hl_cb.acb[(app_idx)].mdl_cfg_channel_id[(item_idx)])
+
+extern btif_hl_cb_t btif_hl_cb;
+extern btif_hl_cb_t* p_btif_hl_cb;
+
+extern bool btif_hl_find_mcl_idx(uint8_t app_idx, BD_ADDR p_bd_addr,
+                                 uint8_t* p_mcl_idx);
+extern bool btif_hl_find_app_idx(uint8_t app_id, uint8_t* p_app_idx);
+extern bool btif_hl_find_avail_mcl_idx(uint8_t app_idx, uint8_t* p_mcl_idx);
+extern bool btif_hl_find_avail_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
+                                       uint8_t* p_mdl_idx);
+extern bool btif_hl_find_mcl_idx_using_handle(tBTA_HL_MCL_HANDLE mcl_handle,
+                                              uint8_t* p_app_idx,
+                                              uint8_t* p_mcl_idx);
+extern bool btif_hl_save_mdl_cfg(uint8_t app_id, uint8_t item_idx,
+                                 tBTA_HL_MDL_CFG* p_mdl_cfg);
+extern bool btif_hl_delete_mdl_cfg(uint8_t app_id, uint8_t item_idx);
+extern bool btif_hl_find_mdl_idx_using_handle(tBTA_HL_MDL_HANDLE mdl_handle,
+                                              uint8_t* p_app_idx,
+                                              uint8_t* p_mcl_idx,
+                                              uint8_t* p_mdl_idx);
+extern void btif_hl_abort_pending_chan_setup(uint8_t app_idx, uint8_t mcl_idx);
+extern bool btif_hl_proc_pending_op(uint8_t app_idx, uint8_t mcl_idx);
+extern bool btif_hl_load_mdl_config(uint8_t app_id, uint8_t buffer_size,
+                                    tBTA_HL_MDL_CFG* p_mdl_buf);
+
+#endif
diff --git a/bt/btif/include/btif_mce.h b/bt/btif/include/btif_mce.h
new file mode 100644
index 0000000..beca0a2
--- /dev/null
+++ b/bt/btif/include/btif_mce.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ *  Filename:      btif_mce.h
+ *
+ *  Description:   Bluetooth MCE Interface
+ *
+ *******************************************************************************/
+
+#ifndef BTIF_MCE_H
+#define BTIF_MCE_H
+
+#include <hardware/bt_mce.h>
+
+btmce_interface_t* btif_mce_get_interface();
+
+#endif
diff --git a/bt/btif/include/btif_pan.h b/bt/btif/include/btif_pan.h
new file mode 100644
index 0000000..ecb480a
--- /dev/null
+++ b/bt/btif/include/btif_pan.h
@@ -0,0 +1,36 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ *  Filename:      btif_pan.h
+ *
+ *  Description:   Bluetooth pan Interface
+ *
+ *******************************************************************************/
+
+#ifndef BTIF_PAN_H
+#define BTIF_PAN_H
+
+#include <hardware/bt_pan.h>
+
+btpan_interface_t* btif_pan_interface();
+void btif_pan_init();
+void btif_pan_cleanup();
+
+#endif
diff --git a/bt/btif/include/btif_pan_internal.h b/bt/btif/include/btif_pan_internal.h
new file mode 100644
index 0000000..462f787
--- /dev/null
+++ b/bt/btif/include/btif_pan_internal.h
@@ -0,0 +1,118 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ *  Filename:      btif_pan_internal.h
+ *
+ *  Description:   Bluetooth pan internal
+ *
+ *******************************************************************************/
+
+#ifndef BTIF_PAN_INTERNAL_H
+#define BTIF_PAN_INTERNAL_H
+
+#include "bt_types.h"
+#include "btif_pan.h"
+
+/*******************************************************************************
+ *  Constants & Macros
+ *******************************************************************************/
+
+#define PAN_NAP_SERVICE_NAME "Android Network Access Point"
+#define PANU_SERVICE_NAME "Android Network User"
+#define TAP_IF_NAME "bt-pan"
+#define ETH_ADDR_LEN 6
+#define TAP_MAX_PKT_WRITE_LEN 2000
+#ifndef PAN_SECURITY
+#define PAN_SECURITY                                                         \
+  (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_IN_ENCRYPT | \
+   BTM_SEC_OUT_ENCRYPT)
+#endif
+
+#define PAN_STATE_UNKNOWN 0
+#define PAN_STATE_OPEN 1
+#define PAN_STATE_CLOSE 2
+#ifndef PAN_ROLE_INACTIVE
+#define PAN_ROLE_INACTIVE 0
+#endif
+
+/*******************************************************************************
+ *  Type definitions and return values
+ *******************************************************************************/
+
+typedef struct eth_hdr {
+  unsigned char h_dest[ETH_ADDR_LEN];
+  unsigned char h_src[ETH_ADDR_LEN];
+  short h_proto;
+} tETH_HDR;
+
+typedef struct {
+  int handle;
+  int state;
+  uint16_t protocol;
+  BD_ADDR peer;
+  int local_role;
+  int remote_role;
+  unsigned char eth_addr[ETH_ADDR_LEN];
+} btpan_conn_t;
+
+typedef struct {
+  int btl_if_handle;
+  int btl_if_handle_panu;
+  int tap_fd;
+  int enabled;
+  int open_count;
+  int flow;  // 1: outbound data flow on; 0: outbound data flow off
+  btpan_conn_t conns[MAX_PAN_CONNS];
+  int congest_packet_size;
+  unsigned char congest_packet[1600];  // max ethernet packet size
+} btpan_cb_t;
+
+/*******************************************************************************
+ *  Functions
+ *******************************************************************************/
+
+extern btpan_cb_t btpan_cb;
+btpan_conn_t* btpan_new_conn(int handle, const BD_ADDR addr, int local_role,
+                             int peer_role);
+btpan_conn_t* btpan_find_conn_addr(const BD_ADDR addr);
+btpan_conn_t* btpan_find_conn_handle(uint16_t handle);
+void btpan_set_flow_control(bool enable);
+int btpan_get_connected_count(void);
+int btpan_tap_open(void);
+void create_tap_read_thread(int tap_fd);
+void destroy_tap_read_thread(void);
+int btpan_tap_close(int tap_fd);
+int btpan_tap_send(int tap_fd, const BD_ADDR src, const BD_ADDR dst,
+                   uint16_t protocol, const char* buff, uint16_t size, bool ext,
+                   bool forward);
+
+static inline int is_empty_eth_addr(const BD_ADDR addr) {
+  int i;
+  for (i = 0; i < BD_ADDR_LEN; i++)
+    if (addr[i] != 0) return 0;
+  return 1;
+}
+
+static inline int is_valid_bt_eth_addr(const BD_ADDR addr) {
+  if (is_empty_eth_addr(addr)) return 0;
+  return addr[0] & 1 ? 0 : 1; /* Cannot be multicasting address */
+}
+
+#endif
diff --git a/bt/btif/include/btif_profile_queue.h b/bt/btif/include/btif_profile_queue.h
new file mode 100644
index 0000000..f6e01a0
--- /dev/null
+++ b/bt/btif/include/btif_profile_queue.h
@@ -0,0 +1,40 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ *  Filename:      btif_profile_queue.h
+ *
+ *  Description:   Bluetooth remote device connection queuing
+ *
+ *******************************************************************************/
+
+#ifndef BTIF_PROFILE_QUEUE_H
+#define BTIF_PROFILE_QUEUE_H
+
+#include <hardware/bluetooth.h>
+
+typedef bt_status_t (*btif_connect_cb_t)(bt_bdaddr_t* bda, uint16_t uuid);
+
+bt_status_t btif_queue_connect(uint16_t uuid, const bt_bdaddr_t* bda,
+                               btif_connect_cb_t connect_cb);
+void btif_queue_advance();
+bt_status_t btif_queue_connect_next(void);
+void btif_queue_release();
+
+#endif
diff --git a/bt/btif/include/btif_sdp.h b/bt/btif/include/btif_sdp.h
new file mode 100644
index 0000000..2fe8b63
--- /dev/null
+++ b/bt/btif/include/btif_sdp.h
@@ -0,0 +1,34 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ *  Filename:      btif_sdp.h
+ *
+ *  Description:   Bluetooth SDP search Interface
+ *
+ *******************************************************************************/
+
+#ifndef BTIF_SDP_H
+#define BTIF_SDP_H
+
+#include <hardware/bt_sdp.h>
+
+btsdp_interface_t* btif_sdp_get_interface();
+
+#endif
diff --git a/bt/btif/include/btif_sm.h b/bt/btif/include/btif_sm.h
new file mode 100644
index 0000000..129e312
--- /dev/null
+++ b/bt/btif/include/btif_sm.h
@@ -0,0 +1,122 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ *  Filename:      btif_sm.h
+ *
+ *  Description:   Generic BTIF state machine API
+ *
+ *****************************************************************************/
+
+#ifndef BTIF_SM_H
+#define BTIF_SM_H
+
+#include <hardware/bluetooth.h>
+
+#include "stack/include/bt_types.h"
+
+/*****************************************************************************
+ *  Constants & Macros
+ *****************************************************************************/
+
+/* Generic Enter/Exit state machine events */
+#define BTIF_SM_ENTER_EVT 0xFFFF
+#define BTIF_SM_EXIT_EVT 0xFFFE
+
+/*****************************************************************************
+ *  Type definitions and return values
+ *****************************************************************************/
+typedef uint32_t btif_sm_state_t;
+typedef uint32_t btif_sm_event_t;
+typedef void* btif_sm_handle_t;
+typedef bool (*btif_sm_handler_t)(btif_sm_event_t event, void* data);
+
+/*****************************************************************************
+ *  Functions
+ *
+ *  NOTE: THESE APIs SHOULD BE INVOKED ONLY IN THE BTIF CONTEXT
+ *
+ *****************************************************************************/
+
+/*****************************************************************************
+ *
+ * Function     btif_sm_init
+ *
+ * Description  Initializes the state machine with the state handlers
+ *              The caller should ensure that the table and the corresponding
+ *              states match. The location that 'p_handlers' points to shall
+ *              be available until the btif_sm_shutdown API is invoked.
+ *
+ * Returns      Returns a pointer to the initialized state machine handle.
+ *
+ *****************************************************************************/
+btif_sm_handle_t btif_sm_init(const btif_sm_handler_t* p_handlers,
+                              btif_sm_state_t initial_state);
+
+/*****************************************************************************
+ *
+ * Function     btif_sm_shutdown
+ *
+ * Description  Tears down the state machine
+ *
+ * Returns      None
+ *
+ *****************************************************************************/
+void btif_sm_shutdown(btif_sm_handle_t handle);
+
+/*****************************************************************************
+ *
+ * Function     btif_sm_get_state
+ *
+ * Description  Fetches the current state of the state machine
+ *
+ * Returns      Current state
+ *
+ *****************************************************************************/
+btif_sm_state_t btif_sm_get_state(btif_sm_handle_t handle);
+
+/*****************************************************************************
+ *
+ * Function     btif_sm_dispatch
+ *
+ * Description  Dispatches the 'event' along with 'data' to the current state
+ *              handler
+ *
+ * Returns      Returns BT_STATUS_OK on success, BT_STATUS_FAIL otherwise
+ *
+ *****************************************************************************/
+bt_status_t btif_sm_dispatch(btif_sm_handle_t handle, btif_sm_event_t event,
+                             void* data);
+
+/*****************************************************************************
+ *
+ * Function     btif_sm_change_state
+ *
+ * Description  Make a transition to the new 'state'. The 'BTIF_SM_EXIT_EVT'
+ *              shall be invoked before exiting the current state. The
+ *              'BTIF_SM_ENTER_EVT' shall be invoked before entering the new
+ *              state
+ *
+ * Returns      Returns BT_STATUS_OK on success, BT_STATUS_FAIL otherwise
+ *
+ *****************************************************************************/
+bt_status_t btif_sm_change_state(btif_sm_handle_t handle,
+                                 btif_sm_state_t state);
+
+#endif /* BTIF_SM_H */
diff --git a/bt/btif/include/btif_sock.h b/bt/btif/include/btif_sock.h
new file mode 100644
index 0000000..e65def6
--- /dev/null
+++ b/bt/btif/include/btif_sock.h
@@ -0,0 +1,28 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 "btif_uid.h"
+
+#include <hardware/bt_sock.h>
+
+btsock_interface_t* btif_sock_get_interface(void);
+
+bt_status_t btif_sock_init(uid_set_t* uid_set);
+void btif_sock_cleanup(void);
diff --git a/bt/btif/include/btif_sock_l2cap.h b/bt/btif/include/btif_sock_l2cap.h
new file mode 100644
index 0000000..480ee6d
--- /dev/null
+++ b/bt/btif/include/btif_sock_l2cap.h
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ *  L2CAP Socket Interface
+ *******************************************************************************/
+
+#ifndef BTIF_SOCK_L2CAP_H
+#define BTIF_SOCK_L2CAP_H
+
+#include "btif_uid.h"
+
+#include <hardware/bluetooth.h>
+
+#define L2CAP_MASK_FIXED_CHANNEL 0x10000
+#define L2CAP_MASK_LE_COC_CHANNEL 0x20000
+
+bt_status_t btsock_l2cap_init(int handle, uid_set_t* set);
+bt_status_t btsock_l2cap_cleanup();
+bt_status_t btsock_l2cap_listen(const char* name, int channel, int* sock_fd,
+                                int flags, int app_uid);
+bt_status_t btsock_l2cap_connect(const bt_bdaddr_t* bd_addr, int channel,
+                                 int* sock_fd, int flags, int app_uid);
+void btsock_l2cap_signaled(int fd, int flags, uint32_t user_id);
+void on_l2cap_psm_assigned(int id, int psm);
+
+#endif
diff --git a/bt/btif/include/btif_sock_rfc.h b/bt/btif/include/btif_sock_rfc.h
new file mode 100644
index 0000000..93129e2
--- /dev/null
+++ b/bt/btif/include/btif_sock_rfc.h
@@ -0,0 +1,42 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ *  Filename:      btif_sock.h
+ *
+ *  Description:   Bluetooth socket Interface
+ *
+ *******************************************************************************/
+
+#ifndef BTIF_SOCK_RFC_H
+#define BTIF_SOCK_RFC_H
+
+#include "btif_uid.h"
+
+bt_status_t btsock_rfc_init(int handle, uid_set_t* set);
+bt_status_t btsock_rfc_cleanup();
+bt_status_t btsock_rfc_listen(const char* name, const uint8_t* uuid,
+                              int channel, int* sock_fd, int flags,
+                              int app_uid);
+bt_status_t btsock_rfc_connect(const bt_bdaddr_t* bd_addr, const uint8_t* uuid,
+                               int channel, int* sock_fd, int flags,
+                               int app_uid);
+void btsock_rfc_signaled(int fd, int flags, uint32_t user_id);
+
+#endif
diff --git a/bt/btif/include/btif_sock_sco.h b/bt/btif/include/btif_sock_sco.h
new file mode 100644
index 0000000..66859d7
--- /dev/null
+++ b/bt/btif/include/btif_sock_sco.h
@@ -0,0 +1,29 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2013 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <hardware/bluetooth.h>
+
+typedef struct thread_t thread_t;
+
+bt_status_t btsock_sco_init(thread_t* thread);
+bt_status_t btsock_sco_cleanup(void);
+bt_status_t btsock_sco_listen(int* sock_fd, int flags);
+bt_status_t btsock_sco_connect(const bt_bdaddr_t* bd_addr, int* sock_fd,
+                               int flags);
diff --git a/bt/btif/include/btif_sock_sdp.h b/bt/btif/include/btif_sock_sdp.h
new file mode 100644
index 0000000..7672c7c
--- /dev/null
+++ b/bt/btif/include/btif_sock_sdp.h
@@ -0,0 +1,52 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_SOCK_SDP_H
+#define BTIF_SOCK_SDP_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+static const uint8_t UUID_OBEX_OBJECT_PUSH[] = {
+    0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
+    0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_PBAP_PSE[] = {0x00, 0x00, 0x11, 0x2F, 0x00, 0x00,
+                                        0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+                                        0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_MAP_MAS[] = {0x00, 0x00, 0x11, 0x32, 0x00, 0x00,
+                                       0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+                                       0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_SAP[] = {0x00, 0x00, 0x11, 0x2D, 0x00, 0x00,
+                                   0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+                                   0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_SPP[] = {0x00, 0x00, 0x11, 0x01, 0x00, 0x00,
+                                   0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+                                   0x5F, 0x9B, 0x34, 0xFB};
+
+static inline bool is_uuid_empty(const uint8_t* uuid) {
+  static uint8_t empty_uuid[16];
+  return uuid == NULL || memcmp(uuid, empty_uuid, sizeof(empty_uuid)) == 0;
+}
+
+int add_rfc_sdp_rec(const char* name, const uint8_t* uuid, int scn);
+void del_rfc_sdp_rec(int handle);
+bool is_reserved_rfc_channel(int channel);
+int get_reserved_rfc_channel(const uint8_t* uuid);
+
+#endif
diff --git a/bt/btif/include/btif_sock_thread.h b/bt/btif/include/btif_sock_thread.h
new file mode 100644
index 0000000..207d5fc
--- /dev/null
+++ b/bt/btif/include/btif_sock_thread.h
@@ -0,0 +1,58 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_SOCK_THREAD_H
+#define BTIF_SOCK_THREAD_H
+
+#include <stdbool.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+
+/*******************************************************************************
+ *  Constants & Macros
+ *******************************************************************************/
+
+#define SOCK_THREAD_FD_RD 1               /* BT socket read signal */
+#define SOCK_THREAD_FD_WR (1 << 1)        /* BT socket write signal */
+#define SOCK_THREAD_FD_EXCEPTION (1 << 2) /* BT socket exception singal */
+
+/* Add BT socket fd in current socket poll thread context immediately */
+#define SOCK_THREAD_ADD_FD_SYNC (1 << 3)
+
+/*******************************************************************************
+ *  Functions
+ *******************************************************************************/
+
+typedef void (*btsock_signaled_cb)(int fd, int type, int flags,
+                                   uint32_t user_id);
+typedef void (*btsock_cmd_cb)(int cmd_fd, int type, int size, uint32_t user_id);
+
+int btsock_thread_init();
+int btsock_thread_add_fd(int handle, int fd, int type, int flags,
+                         uint32_t user_id);
+bool btsock_thread_remove_fd_and_close(int thread_handle, int fd);
+int btsock_thread_wakeup(int handle);
+int btsock_thread_post_cmd(int handle, int cmd_type,
+                           const unsigned char* cmd_data, int data_size,
+                           uint32_t user_id);
+int btsock_thread_create(btsock_signaled_cb callback,
+                         btsock_cmd_cb cmd_callback);
+int btsock_thread_exit(int handle);
+
+#endif
diff --git a/bt/btif/include/btif_sock_util.h b/bt/btif/include/btif_sock_util.h
new file mode 100644
index 0000000..eb915f9
--- /dev/null
+++ b/bt/btif/include/btif_sock_util.h
@@ -0,0 +1,38 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ *  Filename:      btif_sock_util.h
+ *
+ *  Description:   Bluetooth socket Interface Helper functions
+ *
+ *******************************************************************************/
+
+#ifndef BTIF_SOCK_UTIL_H
+#define BTIF_SOCK_UTIL_H
+
+#include <stdint.h>
+
+void dump_bin(const char* title, const char* data, int size);
+
+int sock_send_fd(int sock_fd, const uint8_t* buffer, int len, int send_fd);
+int sock_send_all(int sock_fd, const uint8_t* buf, int len);
+int sock_recv_all(int sock_fd, uint8_t* buf, int len);
+
+#endif
diff --git a/bt/btif/include/btif_storage.h b/bt/btif/include/btif_storage.h
new file mode 100644
index 0000000..78be2c0
--- /dev/null
+++ b/bt/btif/include/btif_storage.h
@@ -0,0 +1,238 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_STORAGE_H
+#define BTIF_STORAGE_H
+
+#include <hardware/bluetooth.h>
+
+#include "bt_target.h"
+#include "bt_types.h"
+
+/*******************************************************************************
+ *  Constants & Macros
+ *******************************************************************************/
+#define BTIF_STORAGE_FILL_PROPERTY(p_prop, t, l, p_v) \
+  do {                                                \
+    (p_prop)->type = (t);                             \
+    (p_prop)->len = (l);                              \
+    (p_prop)->val = (p_v);                            \
+  } while (0)
+
+/*******************************************************************************
+ *  Functions
+ *******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_get_adapter_property
+ *
+ * Description      BTIF storage API - Fetches the adapter property->type
+ *                  from NVRAM and fills property->val.
+ *                  Caller should provide memory for property->val and
+ *                  set the property->val
+ *
+ * Returns          BT_STATUS_SUCCESS if the fetch was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_get_adapter_property(bt_property_t* property);
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_set_adapter_property
+ *
+ * Description      BTIF storage API - Stores the adapter property
+ *                  to NVRAM
+ *
+ * Returns          BT_STATUS_SUCCESS if the store was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_set_adapter_property(bt_property_t* property);
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_get_remote_device_property
+ *
+ * Description      BTIF storage API - Fetches the remote device property->type
+ *                  from NVRAM and fills property->val.
+ *                  Caller should provide memory for property->val and
+ *                  set the property->val
+ *
+ * Returns          BT_STATUS_SUCCESS if the fetch was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_get_remote_device_property(bt_bdaddr_t* remote_bd_addr,
+                                                    bt_property_t* property);
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_set_remote_device_property
+ *
+ * Description      BTIF storage API - Stores the remote device property
+ *                  to NVRAM
+ *
+ * Returns          BT_STATUS_SUCCESS if the store was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_set_remote_device_property(bt_bdaddr_t* remote_bd_addr,
+                                                    bt_property_t* property);
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_add_remote_device
+ *
+ * Description      BTIF storage API - Adds a newly discovered device to
+ *                  track along with the timestamp. Also, stores the various
+ *                  properties - RSSI, BDADDR, NAME (if found in EIR)
+ *
+ * Returns          BT_STATUS_SUCCESS if successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_add_remote_device(bt_bdaddr_t* remote_bd_addr,
+                                           uint32_t num_properties,
+                                           bt_property_t* properties);
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_add_bonded_device
+ *
+ * Description      BTIF storage API - Adds the newly bonded device to NVRAM
+ *                  along with the link-key, Key type and Pin key length
+ *
+ * Returns          BT_STATUS_SUCCESS if the store was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_add_bonded_device(bt_bdaddr_t* remote_bd_addr,
+                                           LINK_KEY link_key, uint8_t key_type,
+                                           uint8_t pin_length);
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_remove_bonded_device
+ *
+ * Description      BTIF storage API - Deletes the bonded device from NVRAM
+ *
+ * Returns          BT_STATUS_SUCCESS if the deletion was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_remove_bonded_device(bt_bdaddr_t* remote_bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_remove_bonded_device
+ *
+ * Description      BTIF storage API - Deletes the bonded device from NVRAM
+ *
+ * Returns          BT_STATUS_SUCCESS if the deletion was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_load_bonded_devices(void);
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_add_hid_device_info
+ *
+ * Description      BTIF storage API - Adds the hid information of bonded hid
+ *                  devices-to NVRAM
+ *
+ * Returns          BT_STATUS_SUCCESS if the store was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+
+bt_status_t btif_storage_add_hid_device_info(
+    bt_bdaddr_t* remote_bd_addr, uint16_t attr_mask, uint8_t sub_class,
+    uint8_t app_id, uint16_t vendor_id, uint16_t product_id, uint16_t version,
+    uint8_t ctry_code, uint16_t ssr_max_latency, uint16_t ssr_min_tout,
+    uint16_t dl_len, uint8_t* dsc_list);
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_load_bonded_hid_info
+ *
+ * Description      BTIF storage API - Loads hid info for all the bonded devices
+ *                  from NVRAM and adds those devices  to the BTA_HH.
+ *
+ * Returns          BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_load_bonded_hid_info(void);
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_remove_hid_info
+ *
+ * Description      BTIF storage API - Deletes the bonded hid device info from
+ *                  NVRAM
+ *
+ * Returns          BT_STATUS_SUCCESS if the deletion was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_remove_hid_info(bt_bdaddr_t* remote_bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_is_retricted_device
+ *
+ * Description      BTIF storage API - checks if this device is a restricted
+ *                  device
+ *
+ * Returns          true  if the device is labled as restricted
+ *                  false otherwise
+ *
+ ******************************************************************************/
+bool btif_storage_is_restricted_device(const bt_bdaddr_t* remote_bd_addr);
+
+#if (BLE_INCLUDED == TRUE)
+bt_status_t btif_storage_add_ble_bonding_key(bt_bdaddr_t* remote_bd_addr,
+                                             char* key, uint8_t key_type,
+                                             uint8_t key_length);
+bt_status_t btif_storage_get_ble_bonding_key(bt_bdaddr_t* remote_bd_addr,
+                                             uint8_t key_type, char* key_value,
+                                             int key_length);
+
+bt_status_t btif_storage_add_ble_local_key(char* key, uint8_t key_type,
+                                           uint8_t key_length);
+bt_status_t btif_storage_remove_ble_bonding_keys(bt_bdaddr_t* remote_bd_addr);
+bt_status_t btif_storage_remove_ble_local_keys(void);
+bt_status_t btif_storage_get_ble_local_key(uint8_t key_type, char* key_value,
+                                           int key_len);
+
+bt_status_t btif_storage_get_remote_addr_type(bt_bdaddr_t* remote_bd_addr,
+                                              int* addr_type);
+
+bt_status_t btif_storage_set_remote_addr_type(bt_bdaddr_t* remote_bd_addr,
+                                              uint8_t addr_type);
+
+#endif
+/******************************************************************************
+ * Exported for unit tests
+ *****************************************************************************/
+size_t btif_split_uuids_string(const char* str, bt_uuid_t* p_uuid,
+                               size_t max_uuids);
+
+#endif /* BTIF_STORAGE_H */
diff --git a/bt/btif/include/btif_uid.h b/bt/btif/include/btif_uid.h
new file mode 100644
index 0000000..35faedb
--- /dev/null
+++ b/bt/btif/include/btif_uid.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "bt_common.h"
+
+#include <hardware/bluetooth.h>
+
+struct uid_set_t;
+typedef struct uid_set_t uid_set_t;
+
+/**
+ * Creates a UID set to keep track of traffic per UID.
+ * Caller is responsible for destroying this object via uid_set_destroy().
+ */
+uid_set_t* uid_set_create();
+
+void uid_set_destroy(uid_set_t* set);
+
+void uid_set_add_tx(uid_set_t* set, int32_t app_uid, uint64_t bytes);
+void uid_set_add_rx(uid_set_t* set, int32_t app_uid, uint64_t bytes);
+
+/**
+ * Returns an array of bt_uid_traffic_t structs, where the end of the array
+ * is signaled by an element with app_uid == -1.
+ *
+ * The caller is responsible for calling osi_free() on the returned array.
+ */
+bt_uid_traffic_t* uid_set_read_and_clear(uid_set_t* set);
diff --git a/bt/btif/include/btif_util.h b/bt/btif/include/btif_util.h
new file mode 100644
index 0000000..58ff18f
--- /dev/null
+++ b/bt/btif/include/btif_util.h
@@ -0,0 +1,80 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_UTIL_H
+#define BTIF_UTIL_H
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hf.h>
+#include <stdbool.h>
+#include <sys/time.h>
+
+#include "bt_types.h"
+#include "bt_utils.h"
+
+/*******************************************************************************
+ *  Constants & Macros
+ *******************************************************************************/
+
+#define CASE_RETURN_STR(const) \
+  case const:                  \
+    return #const;
+
+/*******************************************************************************
+ *  Type definitions for callback functions
+ *******************************************************************************/
+
+/*******************************************************************************
+ *  Functions
+ *******************************************************************************/
+
+const char* dump_bt_status(bt_status_t status);
+const char* dump_dm_search_event(uint16_t event);
+const char* dump_dm_event(uint16_t event);
+const char* dump_hf_event(uint16_t event);
+const char* dump_hf_client_event(uint16_t event);
+const char* dump_hh_event(uint16_t event);
+const char* dump_hf_conn_state(uint16_t event);
+const char* dump_hf_call_state(bthf_call_state_t call_state);
+const char* dump_property_type(bt_property_type_t type);
+const char* dump_hf_audio_state(uint16_t event);
+const char* dump_adapter_scan_mode(bt_scan_mode_t mode);
+const char* dump_thread_evt(bt_cb_thread_evt evt);
+const char* dump_av_conn_state(uint16_t event);
+const char* dump_av_audio_state(uint16_t event);
+const char* dump_rc_event(uint8_t event);
+const char* dump_rc_notification_event_id(uint8_t event_id);
+const char* dump_rc_pdu(uint8_t pdu);
+
+uint32_t devclass2uint(DEV_CLASS dev_class);
+void uint2devclass(uint32_t dev, DEV_CLASS dev_class);
+void uuid16_to_uuid128(uint16_t uuid16, bt_uuid_t* uuid128);
+
+// Takes a |str| containing a 128-bit GUID formatted UUID and stores the
+// result in |p_uuid|. |str| must be formatted in this format:
+//   "12345678-1234-1234-1234-123456789012"
+// |p_uuid| cannot be null. Returns true if parsing was successful, false
+// otherwise. Returns false if |str| is null.
+bool string_to_uuid(const char* str, bt_uuid_t* p_uuid);
+
+int ascii_2_hex(const char* p_ascii, int len, uint8_t* p_hex);
+
+void uuid_to_string_legacy(bt_uuid_t* p_uuid, char* str, size_t str_len);
+
+#endif /* BTIF_UTIL_H */
diff --git a/bt/btif/include/stack_manager.h b/bt/btif/include/stack_manager.h
new file mode 100644
index 0000000..90d81c5
--- /dev/null
+++ b/bt/btif/include/stack_manager.h
@@ -0,0 +1,38 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+
+#include "osi/include/future.h"
+
+typedef struct {
+  void (*init_stack)(void);
+  void (*start_up_stack_async)(void);
+  void (*shut_down_stack_async)(void);
+  void (*clean_up_stack)(void);
+
+  bool (*get_stack_is_running)(void);
+} stack_manager_t;
+
+const stack_manager_t* stack_manager_get_interface();
+
+// TODO(zachoverflow): remove this terrible hack once the startup sequence is
+// more sane
+future_t* stack_manager_get_hack_future();
diff --git a/bt/btif/include/uinput.h b/bt/btif/include/uinput.h
new file mode 100644
index 0000000..99a03ce
--- /dev/null
+++ b/bt/btif/include/uinput.h
@@ -0,0 +1,582 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef __UINPUT_H
+#define __UINPUT_H
+
+#include <stdint.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+
+/*******************************************************************************
+ *  Constants & Macros
+ *******************************************************************************/
+
+/* Events */
+
+#define EV_SYN 0x00
+#define EV_KEY 0x01
+#define EV_REL 0x02
+#define EV_ABS 0x03
+#define EV_MSC 0x04
+#define EV_LED 0x11
+#define EV_SND 0x12
+#define EV_REP 0x14
+#define EV_FF 0x15
+#define EV_PWR 0x16
+#define EV_FF_STATUS 0x17
+#define EV_MAX 0x1f
+
+/* Synchronization events */
+
+#define SYN_REPORT 0
+#define SYN_CONFIG 1
+
+/* Keys and buttons */
+
+#define KEY_RESERVED 0
+#define KEY_ESC 1
+#define KEY_1 2
+#define KEY_2 3
+#define KEY_3 4
+#define KEY_4 5
+#define KEY_5 6
+#define KEY_6 7
+#define KEY_7 8
+#define KEY_8 9
+#define KEY_9 10
+#define KEY_0 11
+#define KEY_MINUS 12
+#define KEY_EQUAL 13
+#define KEY_BACKSPACE 14
+#define KEY_TAB 15
+#define KEY_Q 16
+#define KEY_W 17
+#define KEY_E 18
+#define KEY_R 19
+#define KEY_T 20
+#define KEY_Y 21
+#define KEY_U 22
+#define KEY_I 23
+#define KEY_O 24
+#define KEY_P 25
+#define KEY_LEFTBRACE 26
+#define KEY_RIGHTBRACE 27
+#define KEY_ENTER 28
+#define KEY_LEFTCTRL 29
+#define KEY_A 30
+#define KEY_S 31
+#define KEY_D 32
+#define KEY_F 33
+#define KEY_G 34
+#define KEY_H 35
+#define KEY_J 36
+#define KEY_K 37
+#define KEY_L 38
+#define KEY_SEMICOLON 39
+#define KEY_APOSTROPHE 40
+#define KEY_GRAVE 41
+#define KEY_LEFTSHIFT 42
+#define KEY_BACKSLASH 43
+#define KEY_Z 44
+#define KEY_X 45
+#define KEY_C 46
+#define KEY_V 47
+#define KEY_B 48
+#define KEY_N 49
+#define KEY_M 50
+#define KEY_COMMA 51
+#define KEY_DOT 52
+#define KEY_SLASH 53
+#define KEY_RIGHTSHIFT 54
+#define KEY_KPASTERISK 55
+#define KEY_LEFTALT 56
+#define KEY_SPACE 57
+#define KEY_CAPSLOCK 58
+#define KEY_F1 59
+#define KEY_F2 60
+#define KEY_F3 61
+#define KEY_F4 62
+#define KEY_F5 63
+#define KEY_F6 64
+#define KEY_F7 65
+#define KEY_F8 66
+#define KEY_F9 67
+#define KEY_F10 68
+#define KEY_NUMLOCK 69
+#define KEY_SCROLLLOCK 70
+#define KEY_KP7 71
+#define KEY_KP8 72
+#define KEY_KP9 73
+#define KEY_KPMINUS 74
+#define KEY_KP4 75
+#define KEY_KP5 76
+#define KEY_KP6 77
+#define KEY_KPPLUS 78
+#define KEY_KP1 79
+#define KEY_KP2 80
+#define KEY_KP3 81
+#define KEY_KP0 82
+#define KEY_KPDOT 83
+#define KEY_103RD 84
+#define KEY_F13 85
+#define KEY_102ND 86
+#define KEY_F11 87
+#define KEY_F12 88
+#define KEY_F14 89
+#define KEY_F15 90
+#define KEY_F16 91
+#define KEY_F17 92
+#define KEY_F18 93
+#define KEY_F19 94
+#define KEY_F20 95
+#define KEY_KPENTER 96
+#define KEY_RIGHTCTRL 97
+#define KEY_KPSLASH 98
+#define KEY_SYSRQ 99
+#define KEY_RIGHTALT 100
+#define KEY_LINEFEED 101
+#define KEY_HOME 102
+#define KEY_UP 103
+#define KEY_PAGEUP 104
+#define KEY_LEFT 105
+#define KEY_RIGHT 106
+#define KEY_END 107
+#define KEY_DOWN 108
+#define KEY_PAGEDOWN 109
+#define KEY_INSERT 110
+#define KEY_DELETE 111
+#define KEY_MACRO 112
+#define KEY_MUTE 113
+#define KEY_VOLUMEDOWN 114
+#define KEY_VOLUMEUP 115
+#define KEY_POWER 116
+#define KEY_KPEQUAL 117
+#define KEY_KPPLUSMINUS 118
+#define KEY_PAUSE 119
+#define KEY_F21 120
+#define KEY_F22 121
+#define KEY_F23 122
+#define KEY_F24 123
+#define KEY_KPCOMMA 124
+#define KEY_LEFTMETA 125
+#define KEY_RIGHTMETA 126
+#define KEY_COMPOSE 127
+
+#define KEY_STOP 128
+#define KEY_AGAIN 129
+#define KEY_PROPS 130
+#define KEY_UNDO 131
+#define KEY_FRONT 132
+#define KEY_COPY 133
+#define KEY_OPEN 134
+#define KEY_PASTE 135
+#define KEY_FIND 136
+#define KEY_CUT 137
+#define KEY_HELP 138
+#define KEY_MENU 139
+#define KEY_CALC 140
+#define KEY_SETUP 141
+#define KEY_SLEEP 142
+#define KEY_WAKEUP 143
+#define KEY_FILE 144
+#define KEY_SENDFILE 145
+#define KEY_DELETEFILE 146
+#define KEY_XFER 147
+#define KEY_PROG1 148
+#define KEY_PROG2 149
+#define KEY_WWW 150
+#define KEY_MSDOS 151
+#define KEY_COFFEE 152
+#define KEY_DIRECTION 153
+#define KEY_CYCLEWINDOWS 154
+#define KEY_MAIL 155
+#define KEY_BOOKMARKS 156
+#define KEY_COMPUTER 157
+#define KEY_BACK 158
+#define KEY_FORWARD 159
+#define KEY_CLOSECD 160
+#define KEY_EJECTCD 161
+#define KEY_EJECTCLOSECD 162
+#define KEY_NEXTSONG 163
+#define KEY_PLAYPAUSE 164
+#define KEY_PREVIOUSSONG 165
+#define KEY_STOPCD 166
+#define KEY_RECORD 167
+#define KEY_REWIND 168
+#define KEY_PHONE 169
+#define KEY_ISO 170
+#define KEY_CONFIG 171
+#define KEY_HOMEPAGE 172
+#define KEY_REFRESH 173
+#define KEY_EXIT 174
+#define KEY_MOVE 175
+#define KEY_EDIT 176
+#define KEY_SCROLLUP 177
+#define KEY_SCROLLDOWN 178
+#define KEY_KPLEFTPAREN 179
+#define KEY_KPRIGHTPAREN 180
+
+#define KEY_INTL1 181
+#define KEY_INTL2 182
+#define KEY_INTL3 183
+#define KEY_INTL4 184
+#define KEY_INTL5 185
+#define KEY_INTL6 186
+#define KEY_INTL7 187
+#define KEY_INTL8 188
+#define KEY_INTL9 189
+#define KEY_LANG1 190
+#define KEY_LANG2 191
+#define KEY_LANG3 192
+#define KEY_LANG4 193
+#define KEY_LANG5 194
+#define KEY_LANG6 195
+#define KEY_LANG7 196
+#define KEY_LANG8 197
+#define KEY_LANG9 198
+
+#define KEY_PLAYCD 200
+#define KEY_PAUSECD 201
+#define KEY_PROG3 202
+#define KEY_PROG4 203
+#define KEY_SUSPEND 205
+#define KEY_CLOSE 206
+#define KEY_PLAY 207
+#define KEY_FAST_FORWARD 208
+
+#define KEY_UNKNOWN 220
+
+#define KEY_BRIGHTNESSDOWN 224
+#define KEY_BRIGHTNESSUP 225
+
+#define BTN_MISC 0x100
+#define BTN_0 0x100
+#define BTN_1 0x101
+#define BTN_2 0x102
+#define BTN_3 0x103
+#define BTN_4 0x104
+#define BTN_5 0x105
+#define BTN_6 0x106
+#define BTN_7 0x107
+#define BTN_8 0x108
+#define BTN_9 0x109
+
+#define BTN_MOUSE 0x110
+#define BTN_LEFT 0x110
+#define BTN_RIGHT 0x111
+#define BTN_MIDDLE 0x112
+#define BTN_SIDE 0x113
+#define BTN_EXTRA 0x114
+#define BTN_FORWARD 0x115
+#define BTN_BACK 0x116
+#define BTN_TASK 0x117
+
+#define BTN_JOYSTICK 0x120
+#define BTN_TRIGGER 0x120
+#define BTN_THUMB 0x121
+#define BTN_THUMB2 0x122
+#define BTN_TOP 0x123
+#define BTN_TOP2 0x124
+#define BTN_PINKIE 0x125
+#define BTN_BASE 0x126
+#define BTN_BASE2 0x127
+#define BTN_BASE3 0x128
+#define BTN_BASE4 0x129
+#define BTN_BASE5 0x12a
+#define BTN_BASE6 0x12b
+#define BTN_DEAD 0x12f
+
+#define BTN_GAMEPAD 0x130
+#define BTN_A 0x130
+#define BTN_B 0x131
+#define BTN_C 0x132
+#define BTN_X 0x133
+#define BTN_Y 0x134
+#define BTN_Z 0x135
+#define BTN_TL 0x136
+#define BTN_TR 0x137
+#define BTN_TL2 0x138
+#define BTN_TR2 0x139
+#define BTN_SELECT 0x13a
+#define BTN_START 0x13b
+#define BTN_MODE 0x13c
+#define BTN_THUMBL 0x13d
+#define BTN_THUMBR 0x13e
+
+#define BTN_DIGI 0x140
+#define BTN_TOOL_PEN 0x140
+#define BTN_TOOL_RUBBER 0x141
+#define BTN_TOOL_BRUSH 0x142
+#define BTN_TOOL_PENCIL 0x143
+#define BTN_TOOL_AIRBRUSH 0x144
+#define BTN_TOOL_FINGER 0x145
+#define BTN_TOOL_MOUSE 0x146
+#define BTN_TOOL_LENS 0x147
+#define BTN_TOUCH 0x14a
+#define BTN_STYLUS 0x14b
+#define BTN_STYLUS2 0x14c
+#define BTN_TOOL_DOUBLETAP 0x14d
+#define BTN_TOOL_TRIPLETAP 0x14e
+
+#define BTN_WHEEL 0x150
+#define BTN_GEAR_DOWN 0x150
+#define BTN_GEAR_UP 0x151
+
+#define KEY_OK 0x160
+#define KEY_SELECT 0x161
+#define KEY_GOTO 0x162
+#define KEY_CLEAR 0x163
+#define KEY_POWER2 0x164
+#define KEY_OPTION 0x165
+#define KEY_INFO 0x166
+#define KEY_TIME 0x167
+#define KEY_VENDOR 0x168
+#define KEY_ARCHIVE 0x169
+#define KEY_PROGRAM 0x16a
+#define KEY_CHANNEL 0x16b
+#define KEY_FAVORITES 0x16c
+#define KEY_EPG 0x16d
+#define KEY_PVR 0x16e
+#define KEY_MHP 0x16f
+#define KEY_LANGUAGE 0x170
+#define KEY_TITLE 0x171
+#define KEY_SUBTITLE 0x172
+#define KEY_ANGLE 0x173
+#define KEY_ZOOM 0x174
+#define KEY_MODE 0x175
+#define KEY_KEYBOARD 0x176
+#define KEY_SCREEN 0x177
+#define KEY_PC 0x178
+#define KEY_TV 0x179
+#define KEY_TV2 0x17a
+#define KEY_VCR 0x17b
+#define KEY_VCR2 0x17c
+#define KEY_SAT 0x17d
+#define KEY_SAT2 0x17e
+#define KEY_CD 0x17f
+#define KEY_TAPE 0x180
+#define KEY_RADIO 0x181
+#define KEY_TUNER 0x182
+#define KEY_PLAYER 0x183
+#define KEY_TEXT 0x184
+#define KEY_DVD 0x185
+#define KEY_AUX 0x186
+#define KEY_MP3 0x187
+#define KEY_AUDIO 0x188
+#define KEY_VIDEO 0x189
+#define KEY_DIRECTORY 0x18a
+#define KEY_LIST 0x18b
+#define KEY_MEMO 0x18c
+#define KEY_CALENDAR 0x18d
+#define KEY_RED 0x18e
+#define KEY_GREEN 0x18f
+#define KEY_YELLOW 0x190
+#define KEY_BLUE 0x191
+#define KEY_CHANNELUP 0x192
+#define KEY_CHANNELDOWN 0x193
+#define KEY_FIRST 0x194
+#define KEY_LAST 0x195
+#define KEY_AB 0x196
+#define KEY_NEXT 0x197
+#define KEY_RESTART 0x198
+#define KEY_SLOW 0x199
+#define KEY_SHUFFLE 0x19a
+#define KEY_BREAK 0x19b
+#define KEY_PREVIOUS 0x19c
+#define KEY_DIGITS 0x19d
+#define KEY_TEEN 0x19e
+#define KEY_TWEN 0x19f
+
+#define KEY_FRAMEBACK 0x1b2
+#define KEY_FRAMEFORWARD 0x1b3
+#define KEY_CONTEXT_MENU 0x1fb
+
+#define KEY_MAX 0x1ff
+
+/* Relative axes */
+
+#define REL_X 0x00
+#define REL_Y 0x01
+#define REL_Z 0x02
+#define REL_RX 0x03
+#define REL_RY 0x04
+#define REL_RZ 0x05
+#define REL_HWHEEL 0x06
+#define REL_DIAL 0x07
+#define REL_WHEEL 0x08
+#define REL_MISC 0x09
+#define REL_MAX 0x0f
+
+/* Absolute axes */
+
+#define ABS_X 0x00
+#define ABS_Y 0x01
+#define ABS_Z 0x02
+#define ABS_RX 0x03
+#define ABS_RY 0x04
+#define ABS_RZ 0x05
+#define ABS_THROTTLE 0x06
+#define ABS_RUDDER 0x07
+#define ABS_WHEEL 0x08
+#define ABS_GAS 0x09
+#define ABS_BRAKE 0x0a
+#define ABS_HAT0X 0x10
+#define ABS_HAT0Y 0x11
+#define ABS_HAT1X 0x12
+#define ABS_HAT1Y 0x13
+#define ABS_HAT2X 0x14
+#define ABS_HAT2Y 0x15
+#define ABS_HAT3X 0x16
+#define ABS_HAT3Y 0x17
+#define ABS_PRESSURE 0x18
+#define ABS_DISTANCE 0x19
+#define ABS_TILT_X 0x1a
+#define ABS_TILT_Y 0x1b
+#define ABS_TOOL_WIDTH 0x1c
+#define ABS_VOLUME 0x20
+#define ABS_MISC 0x28
+#define ABS_MAX 0x3f
+
+/* Switch events */
+
+#define SW_0 0x00
+#define SW_1 0x01
+#define SW_2 0x02
+#define SW_3 0x03
+#define SW_4 0x04
+#define SW_5 0x05
+#define SW_6 0x06
+#define SW_7 0x07
+#define SW_MAX 0x0f
+
+/* Misc events */
+
+#define MSC_SERIAL 0x00
+#define MSC_PULSELED 0x01
+#define MSC_GESTURE 0x02
+#define MSC_RAW 0x03
+#define MSC_SCAN 0x04
+#define MSC_MAX 0x07
+
+/* LEDs */
+
+#define LED_NUML 0x00
+#define LED_CAPSL 0x01
+#define LED_SCROLLL 0x02
+#define LED_COMPOSE 0x03
+#define LED_KANA 0x04
+#define LED_SLEEP 0x05
+#define LED_SUSPEND 0x06
+#define LED_MUTE 0x07
+#define LED_MISC 0x08
+#define LED_MAIL 0x09
+#define LED_CHARGING 0x0a
+#define LED_MAX 0x0f
+
+/* Autorepeat values */
+
+#define REP_DELAY 0x00
+#define REP_PERIOD 0x01
+#define REP_MAX 0x01
+
+/* Sounds */
+
+#define SND_CLICK 0x00
+#define SND_BELL 0x01
+#define SND_TONE 0x02
+#define SND_MAX 0x07
+
+/* Identifiers */
+
+#define ID_BUS 0
+#define ID_VENDOR 1
+#define ID_PRODUCT 2
+#define ID_VERSION 3
+
+#define BUS_PCI 0x01
+#define BUS_ISAPNP 0x02
+#define BUS_USB 0x03
+#define BUS_HIL 0x04
+#define BUS_BLUETOOTH 0x05
+
+#define BUS_ISA 0x10
+#define BUS_I8042 0x11
+#define BUS_XTKBD 0x12
+#define BUS_RS232 0x13
+#define BUS_GAMEPORT 0x14
+#define BUS_PARPORT 0x15
+#define BUS_AMIGA 0x16
+#define BUS_ADB 0x17
+#define BUS_I2C 0x18
+#define BUS_HOST 0x19
+#define BUS_GSC 0x1A
+
+/* User input interface */
+
+#define UINPUT_IOCTL_BASE 'U'
+
+#define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1)
+#define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2)
+
+#define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int)
+#define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int)
+#define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int)
+#define UI_SET_ABSBIT _IOW(UINPUT_IOCTL_BASE, 103, int)
+#define UI_SET_MSCBIT _IOW(UINPUT_IOCTL_BASE, 104, int)
+#define UI_SET_LEDBIT _IOW(UINPUT_IOCTL_BASE, 105, int)
+#define UI_SET_SNDBIT _IOW(UINPUT_IOCTL_BASE, 106, int)
+#define UI_SET_FFBIT _IOW(UINPUT_IOCTL_BASE, 107, int)
+#define UI_SET_PHYS _IOW(UINPUT_IOCTL_BASE, 108, char*)
+#define UI_SET_SWBIT _IOW(UINPUT_IOCTL_BASE, 109, int)
+
+#ifndef NBITS
+#define NBITS(x) ((((x)-1) / (sizeof(long) * 8)) + 1)
+#endif
+
+#define UINPUT_MAX_NAME_SIZE 80
+
+/*******************************************************************************
+ *  Type definitions and return values
+ *******************************************************************************/
+
+struct uinput_id {
+  uint16_t bustype;
+  uint16_t vendor;
+  uint16_t product;
+  uint16_t version;
+};
+
+struct uinput_dev {
+  char name[UINPUT_MAX_NAME_SIZE];
+  struct uinput_id id;
+  int ff_effects_max;
+  int absmax[ABS_MAX + 1];
+  int absmin[ABS_MAX + 1];
+  int absfuzz[ABS_MAX + 1];
+  int absflat[ABS_MAX + 1];
+};
+
+struct uinput_event {
+  struct timeval time;
+  uint16_t type;
+  uint16_t code;
+  int32_t value;
+};
+
+#endif /* __UINPUT_H */
diff --git a/bt/btif/src/bluetooth.cc b/bt/btif/src/bluetooth.cc
new file mode 100644
index 0000000..c396ea4
--- /dev/null
+++ b/bt/btif/src/bluetooth.cc
@@ -0,0 +1,488 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ *  Filename:      bluetooth.c
+ *
+ *  Description:   Bluetooth HAL implementation
+ *
+ ***********************************************************************************/
+
+#define LOG_TAG "bt_btif"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_av.h>
+#include <hardware/bt_gatt.h>
+#include <hardware/bt_hf.h>
+#include <hardware/bt_hf_client.h>
+#include <hardware/bt_hh.h>
+#include <hardware/bt_hl.h>
+#include <hardware/bt_mce.h>
+#include <hardware/bt_pan.h>
+#include <hardware/bt_rc.h>
+#include <hardware/bt_sdp.h>
+#include <hardware/bt_sock.h>
+
+#include "bt_utils.h"
+#include "btif/include/btif_debug_btsnoop.h"
+#include "btif/include/btif_debug_conn.h"
+#include "btif_a2dp.h"
+#include "btif_api.h"
+#include "btif_config.h"
+#include "btif_debug.h"
+#include "btif_storage.h"
+#include "btsnoop.h"
+#include "btsnoop_mem.h"
+#include "device/include/interop.h"
+#include "osi/include/alarm.h"
+#include "osi/include/allocation_tracker.h"
+#include "osi/include/log.h"
+#include "osi/include/metrics.h"
+#include "osi/include/osi.h"
+#include "osi/include/wakelock.h"
+#include "stack_manager.h"
+
+/************************************************************************************
+ *  Static variables
+ ***********************************************************************************/
+
+bt_callbacks_t* bt_hal_cbacks = NULL;
+bool restricted_mode = false;
+
+/************************************************************************************
+ *  Externs
+ ***********************************************************************************/
+
+/* list all extended interfaces here */
+
+/* handsfree profile */
+extern bthf_interface_t* btif_hf_get_interface();
+/* handsfree profile - client */
+extern bthf_client_interface_t* btif_hf_client_get_interface();
+/* advanced audio profile */
+extern btav_interface_t* btif_av_get_src_interface();
+extern btav_interface_t* btif_av_get_sink_interface();
+/*rfc l2cap*/
+extern btsock_interface_t* btif_sock_get_interface();
+/* hid host profile */
+extern bthh_interface_t* btif_hh_get_interface();
+/* health device profile */
+extern bthl_interface_t* btif_hl_get_interface();
+/*pan*/
+extern btpan_interface_t* btif_pan_get_interface();
+/*map client*/
+extern btmce_interface_t* btif_mce_get_interface();
+#if (BLE_INCLUDED == TRUE)
+/* gatt */
+extern const btgatt_interface_t* btif_gatt_get_interface();
+#endif
+/* avrc target */
+extern btrc_interface_t* btif_rc_get_interface();
+/* avrc controller */
+extern btrc_interface_t* btif_rc_ctrl_get_interface();
+/*SDP search client*/
+extern btsdp_interface_t* btif_sdp_get_interface();
+
+/************************************************************************************
+ *  Functions
+ ***********************************************************************************/
+
+static bool interface_ready(void) { return bt_hal_cbacks != NULL; }
+
+static bool is_profile(const char* p1, const char* p2) {
+  assert(p1);
+  assert(p2);
+  return strlen(p1) == strlen(p2) && strncmp(p1, p2, strlen(p2)) == 0;
+}
+
+/*****************************************************************************
+ *
+ *   BLUETOOTH HAL INTERFACE FUNCTIONS
+ *
+ ****************************************************************************/
+
+static int init(bt_callbacks_t* callbacks) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+
+  if (interface_ready()) return BT_STATUS_DONE;
+
+#ifdef BLUEDROID_DEBUG
+  allocation_tracker_init();
+#endif
+
+  bt_hal_cbacks = callbacks;
+  stack_manager_get_interface()->init_stack();
+  btif_debug_init();
+  return BT_STATUS_SUCCESS;
+}
+
+static int enable(bool start_restricted) {
+  LOG_INFO(LOG_TAG, "%s: start restricted = %d", __func__, start_restricted);
+
+  restricted_mode = start_restricted;
+
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
+
+  stack_manager_get_interface()->start_up_stack_async();
+  return BT_STATUS_SUCCESS;
+}
+
+static int disable(void) {
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
+
+  stack_manager_get_interface()->shut_down_stack_async();
+  return BT_STATUS_SUCCESS;
+}
+
+static void cleanup(void) { stack_manager_get_interface()->clean_up_stack(); }
+
+bool is_restricted_mode() { return restricted_mode; }
+
+static int get_adapter_properties(void) {
+  /* sanity check */
+  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+  return btif_get_adapter_properties();
+}
+
+static int get_adapter_property(bt_property_type_t type) {
+  /* sanity check */
+  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+  return btif_get_adapter_property(type);
+}
+
+static int set_adapter_property(const bt_property_t* property) {
+  /* sanity check */
+  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+  return btif_set_adapter_property(property);
+}
+
+int get_remote_device_properties(bt_bdaddr_t* remote_addr) {
+  /* sanity check */
+  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+  return btif_get_remote_device_properties(remote_addr);
+}
+
+int get_remote_device_property(bt_bdaddr_t* remote_addr,
+                               bt_property_type_t type) {
+  /* sanity check */
+  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+  return btif_get_remote_device_property(remote_addr, type);
+}
+
+int set_remote_device_property(bt_bdaddr_t* remote_addr,
+                               const bt_property_t* property) {
+  /* sanity check */
+  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+  return btif_set_remote_device_property(remote_addr, property);
+}
+
+int get_remote_service_record(bt_bdaddr_t* remote_addr, bt_uuid_t* uuid) {
+  /* sanity check */
+  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+  return btif_get_remote_service_record(remote_addr, uuid);
+}
+
+int get_remote_services(bt_bdaddr_t* remote_addr) {
+  /* sanity check */
+  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+  return btif_dm_get_remote_services(remote_addr);
+}
+
+static int start_discovery(void) {
+  /* sanity check */
+  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+  return btif_dm_start_discovery();
+}
+
+static int cancel_discovery(void) {
+  /* sanity check */
+  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+  return btif_dm_cancel_discovery();
+}
+
+static int create_bond(const bt_bdaddr_t* bd_addr, int transport) {
+  /* sanity check */
+  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+  return btif_dm_create_bond(bd_addr, transport);
+}
+
+static int create_bond_out_of_band(const bt_bdaddr_t* bd_addr, int transport,
+                                   const bt_out_of_band_data_t* oob_data) {
+  /* sanity check */
+  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+  return btif_dm_create_bond_out_of_band(bd_addr, transport, oob_data);
+}
+
+static int cancel_bond(const bt_bdaddr_t* bd_addr) {
+  /* sanity check */
+  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+  return btif_dm_cancel_bond(bd_addr);
+}
+
+static int remove_bond(const bt_bdaddr_t* bd_addr) {
+  if (is_restricted_mode() && !btif_storage_is_restricted_device(bd_addr))
+    return BT_STATUS_SUCCESS;
+
+  /* sanity check */
+  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+  return btif_dm_remove_bond(bd_addr);
+}
+
+static int get_connection_state(const bt_bdaddr_t* bd_addr) {
+  /* sanity check */
+  if (interface_ready() == false) return 0;
+
+  return btif_dm_get_connection_state(bd_addr);
+}
+
+static int pin_reply(const bt_bdaddr_t* bd_addr, uint8_t accept,
+                     uint8_t pin_len, bt_pin_code_t* pin_code) {
+  /* sanity check */
+  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+  return btif_dm_pin_reply(bd_addr, accept, pin_len, pin_code);
+}
+
+static int ssp_reply(const bt_bdaddr_t* bd_addr, bt_ssp_variant_t variant,
+                     uint8_t accept, uint32_t passkey) {
+  /* sanity check */
+  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+  return btif_dm_ssp_reply(bd_addr, variant, accept, passkey);
+}
+
+static int read_energy_info() {
+  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+  btif_dm_read_energy_info();
+  return BT_STATUS_SUCCESS;
+}
+
+static void dump(int fd, const char** arguments) {
+  if (arguments != NULL && arguments[0] != NULL) {
+    if (strncmp(arguments[0], "--proto-bin", 11) == 0) {
+      btif_update_a2dp_metrics();
+      metrics_write(fd, true);
+      return;
+    }
+  }
+  btif_debug_conn_dump(fd);
+  btif_debug_bond_event_dump(fd);
+  btif_debug_a2dp_dump(fd);
+  btif_debug_config_dump(fd);
+  wakelock_debug_dump(fd);
+  alarm_debug_dump(fd);
+#if (BTSNOOP_MEM == TRUE)
+  btif_debug_btsnoop_dump(fd);
+#endif
+
+  close(fd);
+}
+
+static const void* get_profile_interface(const char* profile_id) {
+  LOG_INFO(LOG_TAG, "get_profile_interface %s", profile_id);
+
+  /* sanity check */
+  if (interface_ready() == false) return NULL;
+
+  /* check for supported profile interfaces */
+  if (is_profile(profile_id, BT_PROFILE_HANDSFREE_ID))
+    return btif_hf_get_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_HANDSFREE_CLIENT_ID))
+    return btif_hf_client_get_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_SOCKETS_ID))
+    return btif_sock_get_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_PAN_ID))
+    return btif_pan_get_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_ADVANCED_AUDIO_ID))
+    return btif_av_get_src_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_ADVANCED_AUDIO_SINK_ID))
+    return btif_av_get_sink_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_HIDHOST_ID))
+    return btif_hh_get_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_HEALTH_ID))
+    return btif_hl_get_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_SDP_CLIENT_ID))
+    return btif_sdp_get_interface();
+
+#if (BTA_GATT_INCLUDED == TRUE && BLE_INCLUDED == TRUE)
+  if (is_profile(profile_id, BT_PROFILE_GATT_ID))
+    return btif_gatt_get_interface();
+#endif
+
+  if (is_profile(profile_id, BT_PROFILE_AV_RC_ID))
+    return btif_rc_get_interface();
+
+  if (is_profile(profile_id, BT_PROFILE_AV_RC_CTRL_ID))
+    return btif_rc_ctrl_get_interface();
+
+  return NULL;
+}
+
+int dut_mode_configure(uint8_t enable) {
+  LOG_INFO(LOG_TAG, "dut_mode_configure");
+
+  /* sanity check */
+  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+  return btif_dut_mode_configure(enable);
+}
+
+int dut_mode_send(uint16_t opcode, uint8_t* buf, uint8_t len) {
+  LOG_INFO(LOG_TAG, "dut_mode_send");
+
+  /* sanity check */
+  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+  return btif_dut_mode_send(opcode, buf, len);
+}
+
+#if (BLE_INCLUDED == TRUE)
+int le_test_mode(uint16_t opcode, uint8_t* buf, uint8_t len) {
+  LOG_INFO(LOG_TAG, "le_test_mode");
+
+  /* sanity check */
+  if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+  return btif_le_test_mode(opcode, buf, len);
+}
+#endif
+
+int config_hci_snoop_log(uint8_t enable) {
+  LOG_INFO(LOG_TAG, "config_hci_snoop_log");
+
+  if (!interface_ready()) return BT_STATUS_NOT_READY;
+
+  btsnoop_get_interface()->set_api_wants_to_log(enable);
+  return BT_STATUS_SUCCESS;
+}
+
+static int set_os_callouts(bt_os_callouts_t* callouts) {
+  wakelock_set_os_callouts(callouts);
+  return BT_STATUS_SUCCESS;
+}
+
+static int config_clear(void) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  return btif_config_clear() ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+static const bt_interface_t bluetoothInterface = {
+    sizeof(bluetoothInterface),
+    init,
+    enable,
+    disable,
+    cleanup,
+    get_adapter_properties,
+    get_adapter_property,
+    set_adapter_property,
+    get_remote_device_properties,
+    get_remote_device_property,
+    set_remote_device_property,
+    get_remote_service_record,
+    get_remote_services,
+    start_discovery,
+    cancel_discovery,
+    create_bond,
+    create_bond_out_of_band,
+    remove_bond,
+    cancel_bond,
+    get_connection_state,
+    pin_reply,
+    ssp_reply,
+    get_profile_interface,
+    dut_mode_configure,
+    dut_mode_send,
+#if (BLE_INCLUDED == TRUE)
+    le_test_mode,
+#else
+    NULL,
+#endif
+    config_hci_snoop_log,
+    set_os_callouts,
+    read_energy_info,
+    dump,
+    config_clear,
+    interop_database_clear,
+    interop_database_add,
+};
+
+const bt_interface_t* bluetooth__get_bluetooth_interface() {
+  /* fixme -- add property to disable bt interface ? */
+
+  return &bluetoothInterface;
+}
+
+static int close_bluetooth_stack(UNUSED_ATTR struct hw_device_t *device) {
+  cleanup();
+  return 0;
+}
+
+static int open_bluetooth_stack(const struct hw_module_t* module,
+                                UNUSED_ATTR char const* name,
+                                struct hw_device_t** abstraction) {
+  static bluetooth_device_t device;
+  device.common.tag = HARDWARE_DEVICE_TAG;
+  device.common.version = 0;
+  device.common.close = close_bluetooth_stack;
+  device.get_bluetooth_interface = bluetooth__get_bluetooth_interface;
+  device.common.module = (struct hw_module_t*)module;
+  *abstraction = (struct hw_device_t*)&device;
+  return 0;
+}
+
+static struct hw_module_methods_t bt_stack_module_methods = {
+    .open = open_bluetooth_stack,
+};
+
+EXPORT_SYMBOL struct hw_module_t HAL_MODULE_INFO_SYM = {
+    .tag = HARDWARE_MODULE_TAG,
+    .version_major = 1,
+    .version_minor = 0,
+    .id = BT_HARDWARE_MODULE_ID,
+    .name = "Bluetooth Stack",
+    .author = "The Android Open Source Project",
+    .methods = &bt_stack_module_methods};
diff --git a/bt/btif/src/btif_a2dp.cc b/bt/btif/src/btif_a2dp.cc
new file mode 100644
index 0000000..7494ba9
--- /dev/null
+++ b/bt/btif/src/btif_a2dp.cc
@@ -0,0 +1,128 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_a2dp"
+
+#include <stdbool.h>
+
+#include "audio_a2dp_hw.h"
+#include "bt_common.h"
+#include "bta_av_api.h"
+#include "btif_a2dp.h"
+#include "btif_a2dp_control.h"
+#include "btif_a2dp_sink.h"
+#include "btif_a2dp_source.h"
+#include "btif_av.h"
+#include "btif_util.h"
+#include "osi/include/log.h"
+
+void btif_a2dp_on_idle(void) {
+  APPL_TRACE_EVENT("## ON A2DP IDLE ## peer_sep = %d", btif_av_get_peer_sep());
+  if (btif_av_get_peer_sep() == AVDT_TSEP_SNK) {
+    btif_a2dp_source_on_idle();
+  } else if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) {
+    btif_a2dp_sink_on_idle();
+  }
+}
+
+bool btif_a2dp_on_started(tBTA_AV_START* p_av_start, bool pending_start) {
+  bool ack = false;
+
+  APPL_TRACE_EVENT("## ON A2DP STARTED ##");
+
+  if (p_av_start == NULL) {
+    /* ack back a local start request */
+    btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+    return true;
+  }
+
+  if (p_av_start->status == BTA_AV_SUCCESS) {
+    if (!p_av_start->suspending) {
+      if (p_av_start->initiator) {
+        if (pending_start) {
+          btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+          ack = true;
+        }
+      } else {
+        /* We were remotely started, make sure codec
+         * is setup before datapath is started.
+         */
+        btif_a2dp_source_setup_codec();
+      }
+
+      /* media task is autostarted upon a2dp audiopath connection */
+    }
+  } else if (pending_start) {
+    APPL_TRACE_WARNING("%s: A2DP start request failed: status = %d", __func__,
+                       p_av_start->status);
+    btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+    ack = true;
+  }
+  return ack;
+}
+
+void btif_a2dp_on_stopped(tBTA_AV_SUSPEND* p_av_suspend) {
+  APPL_TRACE_EVENT("## ON A2DP STOPPED ##");
+
+  if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) {
+    btif_a2dp_sink_on_stopped(p_av_suspend);
+    return;
+  }
+
+  btif_a2dp_source_on_stopped(p_av_suspend);
+}
+
+void btif_a2dp_on_suspended(tBTA_AV_SUSPEND* p_av_suspend) {
+  APPL_TRACE_EVENT("## ON A2DP SUSPENDED ##");
+  if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) {
+    btif_a2dp_sink_on_suspended(p_av_suspend);
+  } else {
+    btif_a2dp_source_on_suspended(p_av_suspend);
+  }
+}
+
+void btif_a2dp_on_offload_started(tBTA_AV_STATUS status) {
+  tA2DP_CTRL_ACK ack;
+  APPL_TRACE_EVENT("%s status %d", __func__, status);
+
+  switch (status) {
+    case BTA_AV_SUCCESS:
+      ack = A2DP_CTRL_ACK_SUCCESS;
+      break;
+    case BTA_AV_FAIL_RESOURCES:
+      APPL_TRACE_ERROR("%s FAILED UNSUPPORTED", __func__);
+      ack = A2DP_CTRL_ACK_UNSUPPORTED;
+      break;
+    default:
+      APPL_TRACE_ERROR("%s FAILED: status = %d", __func__, status);
+      ack = A2DP_CTRL_ACK_FAILURE;
+      break;
+  }
+  btif_a2dp_command_ack(ack);
+}
+
+void btif_debug_a2dp_dump(int fd) {
+  btif_a2dp_source_debug_dump(fd);
+  btif_a2dp_sink_debug_dump(fd);
+}
+
+void btif_update_a2dp_metrics(void) {
+  btif_a2dp_source_update_metrics();
+  btif_a2dp_sink_update_metrics();
+}
diff --git a/bt/btif/src/btif_a2dp_control.cc b/bt/btif/src/btif_a2dp_control.cc
new file mode 100644
index 0000000..2a8f71b
--- /dev/null
+++ b/bt/btif/src/btif_a2dp_control.cc
@@ -0,0 +1,275 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_a2dp_control"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "audio_a2dp_hw.h"
+#include "bt_common.h"
+#include "btif_a2dp.h"
+#include "btif_a2dp_control.h"
+#include "btif_a2dp_sink.h"
+#include "btif_a2dp_source.h"
+#include "btif_av.h"
+#include "btif_hf.h"
+#include "osi/include/osi.h"
+#include "uipc.h"
+
+#define A2DP_DATA_READ_POLL_MS 10
+
+static void btif_a2dp_data_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event);
+static void btif_a2dp_ctrl_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event);
+
+/* We can have max one command pending */
+static tA2DP_CTRL_CMD a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
+
+void btif_a2dp_control_init(void) {
+  UIPC_Init(NULL);
+  UIPC_Open(UIPC_CH_ID_AV_CTRL, btif_a2dp_ctrl_cb);
+}
+
+void btif_a2dp_control_cleanup(void) {
+  /* This calls blocks until UIPC is fully closed */
+  UIPC_Close(UIPC_CH_ID_ALL);
+}
+
+static void btif_a2dp_recv_ctrl_data(void) {
+  tA2DP_CTRL_CMD cmd = A2DP_CTRL_CMD_NONE;
+  int n;
+
+  uint8_t read_cmd = 0; /* The read command size is one octet */
+  n = UIPC_Read(UIPC_CH_ID_AV_CTRL, NULL, &read_cmd, 1);
+  cmd = static_cast<tA2DP_CTRL_CMD>(read_cmd);
+
+  /* detach on ctrl channel means audioflinger process was terminated */
+  if (n == 0) {
+    APPL_TRACE_EVENT("CTRL CH DETACHED");
+    UIPC_Close(UIPC_CH_ID_AV_CTRL);
+    return;
+  }
+
+  APPL_TRACE_DEBUG("a2dp-ctrl-cmd : %s", audio_a2dp_hw_dump_ctrl_event(cmd));
+  a2dp_cmd_pending = cmd;
+
+  switch (cmd) {
+    case A2DP_CTRL_CMD_CHECK_READY:
+      if (btif_a2dp_source_media_task_is_shutting_down()) {
+        APPL_TRACE_WARNING("%s: A2DP command %s while media task shutting down",
+                           __func__, audio_a2dp_hw_dump_ctrl_event(cmd));
+        btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+        return;
+      }
+
+      /* check whether AV is ready to setup A2DP datapath */
+      if (btif_av_stream_ready() || btif_av_stream_started_ready()) {
+        btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+      } else {
+        APPL_TRACE_WARNING("%s: A2DP command %s while AV stream is not ready",
+                           __func__, audio_a2dp_hw_dump_ctrl_event(cmd));
+        btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+      }
+      break;
+
+    case A2DP_CTRL_CMD_START:
+      /*
+       * Don't send START request to stack while we are in a call.
+       * Some headsets such as "Sony MW600", don't allow AVDTP START
+       * while in a call, and respond with BAD_STATE.
+       */
+      if (!btif_hf_is_call_idle()) {
+        btif_a2dp_command_ack(A2DP_CTRL_ACK_INCALL_FAILURE);
+        break;
+      }
+
+      if (btif_a2dp_source_is_streaming()) {
+        APPL_TRACE_WARNING("%s: A2DP command %s while source is streaming",
+                           __func__, audio_a2dp_hw_dump_ctrl_event(cmd));
+        btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+        break;
+      }
+
+      if (btif_av_stream_ready()) {
+        /* Setup audio data channel listener */
+        UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
+
+        /*
+         * Post start event and wait for audio path to open.
+         * If we are the source, the ACK will be sent after the start
+         * procedure is completed, othewise send it now.
+         */
+        btif_dispatch_sm_event(BTIF_AV_START_STREAM_REQ_EVT, NULL, 0);
+        if (btif_av_get_peer_sep() == AVDT_TSEP_SRC)
+          btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+        break;
+      }
+
+      if (btif_av_stream_started_ready()) {
+        /*
+         * Already started, setup audio data channel listener and ACK
+         * back immediately.
+         */
+        UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
+        btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+        break;
+      }
+      APPL_TRACE_WARNING("%s: A2DP command %s while AV stream is not ready",
+                         __func__, audio_a2dp_hw_dump_ctrl_event(cmd));
+      btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+      break;
+
+    case A2DP_CTRL_CMD_STOP:
+      if (btif_av_get_peer_sep() == AVDT_TSEP_SNK &&
+          !btif_a2dp_source_is_streaming()) {
+        /* We are already stopped, just ack back */
+        btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+        break;
+      }
+
+      btif_dispatch_sm_event(BTIF_AV_STOP_STREAM_REQ_EVT, NULL, 0);
+      btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+      break;
+
+    case A2DP_CTRL_CMD_SUSPEND:
+      /* Local suspend */
+      if (btif_av_stream_started_ready()) {
+        btif_dispatch_sm_event(BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0);
+        break;
+      }
+      /* If we are not in started state, just ack back ok and let
+       * audioflinger close the channel. This can happen if we are
+       * remotely suspended, clear REMOTE SUSPEND flag.
+       */
+      btif_av_clear_remote_suspend_flag();
+      btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+      break;
+
+    case A2DP_CTRL_GET_AUDIO_CONFIG: {
+      uint32_t sample_rate = btif_a2dp_sink_get_sample_rate();
+      uint8_t channel_count = btif_a2dp_sink_get_channel_count();
+
+      btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+      UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, reinterpret_cast<uint8_t*>(&sample_rate),
+                sizeof(sample_rate));
+      UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, &channel_count, sizeof(channel_count));
+      break;
+    }
+
+    case A2DP_CTRL_CMD_OFFLOAD_START:
+      btif_dispatch_sm_event(BTIF_AV_OFFLOAD_START_REQ_EVT, NULL, 0);
+      break;
+
+    default:
+      APPL_TRACE_ERROR("UNSUPPORTED CMD (%d)", cmd);
+      btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+      break;
+  }
+  APPL_TRACE_DEBUG("a2dp-ctrl-cmd : %s DONE",
+                   audio_a2dp_hw_dump_ctrl_event(cmd));
+}
+
+static void btif_a2dp_ctrl_cb(UNUSED_ATTR tUIPC_CH_ID ch_id,
+                              tUIPC_EVENT event) {
+  APPL_TRACE_DEBUG("A2DP-CTRL-CHANNEL EVENT %s", dump_uipc_event(event));
+
+  switch (event) {
+    case UIPC_OPEN_EVT:
+      break;
+
+    case UIPC_CLOSE_EVT:
+      /* restart ctrl server unless we are shutting down */
+      if (btif_a2dp_source_media_task_is_running())
+        UIPC_Open(UIPC_CH_ID_AV_CTRL, btif_a2dp_ctrl_cb);
+      break;
+
+    case UIPC_RX_DATA_READY_EVT:
+      btif_a2dp_recv_ctrl_data();
+      break;
+
+    default:
+      APPL_TRACE_ERROR("### A2DP-CTRL-CHANNEL EVENT %d NOT HANDLED ###", event);
+      break;
+  }
+}
+
+static void btif_a2dp_data_cb(UNUSED_ATTR tUIPC_CH_ID ch_id,
+                              tUIPC_EVENT event) {
+  APPL_TRACE_DEBUG("BTIF MEDIA (A2DP-DATA) EVENT %s", dump_uipc_event(event));
+
+  switch (event) {
+    case UIPC_OPEN_EVT:
+      /*
+       * Read directly from media task from here on (keep callback for
+       * connection events.
+       */
+      UIPC_Ioctl(UIPC_CH_ID_AV_AUDIO, UIPC_REG_REMOVE_ACTIVE_READSET, NULL);
+      UIPC_Ioctl(UIPC_CH_ID_AV_AUDIO, UIPC_SET_READ_POLL_TMO,
+                 reinterpret_cast<void*>(A2DP_DATA_READ_POLL_MS));
+
+      if (btif_av_get_peer_sep() == AVDT_TSEP_SNK) {
+        /* Start the media task to encode the audio */
+        btif_a2dp_source_start_audio_req();
+
+        /* Make sure we update any changed encoder params */
+        btif_a2dp_source_encoder_update();
+      }
+
+      /* ACK back when media task is fully started */
+      break;
+
+    case UIPC_CLOSE_EVT:
+      APPL_TRACE_EVENT("## AUDIO PATH DETACHED ##");
+      btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+      /*
+       * Send stop request only if we are actively streaming and haven't
+       * received a stop request. Potentially, the audioflinger detached
+       * abnormally.
+       */
+      if (btif_a2dp_source_is_streaming()) {
+        /* Post stop event and wait for audio path to stop */
+        btif_dispatch_sm_event(BTIF_AV_STOP_STREAM_REQ_EVT, NULL, 0);
+      }
+      break;
+
+    default:
+      APPL_TRACE_ERROR("### A2DP-DATA EVENT %d NOT HANDLED ###", event);
+      break;
+  }
+}
+
+void btif_a2dp_command_ack(tA2DP_CTRL_ACK status) {
+  uint8_t ack = status;
+
+  APPL_TRACE_EVENT("## a2dp ack : %s, status %d ##",
+                   audio_a2dp_hw_dump_ctrl_event(a2dp_cmd_pending), status);
+
+  /* Sanity check */
+  if (a2dp_cmd_pending == A2DP_CTRL_CMD_NONE) {
+    APPL_TRACE_ERROR("warning : no command pending, ignore ack");
+    return;
+  }
+
+  /* Clear pending */
+  a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
+
+  /* Acknowledge start request */
+  UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, &ack, sizeof(ack));
+}
diff --git a/bt/btif/src/btif_a2dp_sink.cc b/bt/btif/src/btif_a2dp_sink.cc
new file mode 100644
index 0000000..5e30c47
--- /dev/null
+++ b/bt/btif/src/btif_a2dp_sink.cc
@@ -0,0 +1,590 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_a2dp_sink"
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "btif_a2dp.h"
+#include "btif_a2dp_sink.h"
+#include "btif_av.h"
+#include "btif_av_co.h"
+#include "btif_avrcp_audio_track.h"
+#include "btif_util.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/thread.h"
+
+#include "oi_codec_sbc.h"
+#include "oi_status.h"
+
+/**
+ * The receiving queue buffer size.
+ */
+#define MAX_INPUT_A2DP_FRAME_QUEUE_SZ (MAX_PCM_FRAME_NUM_PER_TICK * 2)
+
+#define BTIF_SINK_MEDIA_TIME_TICK_MS 20
+
+/* In case of A2DP Sink, we will delay start by 5 AVDTP Packets */
+#define MAX_A2DP_DELAYED_START_FRAME_COUNT 5
+
+enum {
+  BTIF_A2DP_SINK_STATE_OFF,
+  BTIF_A2DP_SINK_STATE_STARTING_UP,
+  BTIF_A2DP_SINK_STATE_RUNNING,
+  BTIF_A2DP_SINK_STATE_SHUTTING_DOWN
+};
+
+/* BTIF Media Sink command event definition */
+enum {
+  BTIF_MEDIA_SINK_DECODER_UPDATE = 1,
+  BTIF_MEDIA_SINK_CLEAR_TRACK,
+  BTIF_MEDIA_SINK_SET_FOCUS_STATE,
+  BTIF_MEDIA_SINK_AUDIO_RX_FLUSH
+};
+
+typedef struct {
+  BT_HDR hdr;
+  uint8_t codec_info[AVDT_CODEC_SIZE];
+} tBTIF_MEDIA_SINK_DECODER_UPDATE;
+
+typedef struct {
+  BT_HDR hdr;
+  btif_a2dp_sink_focus_state_t focus_state;
+} tBTIF_MEDIA_SINK_FOCUS_UPDATE;
+
+typedef struct {
+  uint16_t num_frames_to_be_processed;
+  uint16_t len;
+  uint16_t offset;
+  uint16_t layer_specific;
+} tBT_SBC_HDR;
+
+/* BTIF A2DP Sink control block */
+typedef struct {
+  thread_t* worker_thread;
+  fixed_queue_t* cmd_msg_queue;
+  fixed_queue_t* rx_audio_queue;
+  bool rx_flush; /* discards any incoming data when true */
+  alarm_t* decode_alarm;
+  uint8_t frames_to_process;
+  uint32_t sample_rate;
+  uint8_t channel_count;
+  btif_a2dp_sink_focus_state_t rx_focus_state; /* audio focus state */
+  void* audio_track;
+} tBTIF_A2DP_SINK_CB;
+
+static tBTIF_A2DP_SINK_CB btif_a2dp_sink_cb;
+
+static int btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_OFF;
+
+static OI_CODEC_SBC_DECODER_CONTEXT btif_a2dp_sink_context;
+static uint32_t btif_a2dp_sink_context_data[CODEC_DATA_WORDS(
+    2, SBC_CODEC_FAST_FILTER_BUFFERS)];
+static int16_t
+    btif_a2dp_sink_pcm_data[15 * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX_CHANNELS];
+
+static void btif_a2dp_sink_startup_delayed(void* context);
+static void btif_a2dp_sink_shutdown_delayed(void* context);
+static void btif_a2dp_sink_command_ready(fixed_queue_t* queue, void* context);
+static void btif_a2dp_sink_audio_handle_stop_decoding(void);
+static void btif_decode_alarm_cb(void* context);
+static void btif_a2dp_sink_audio_handle_start_decoding(void);
+static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void* context);
+static void btif_a2dp_sink_audio_rx_flush_req(void);
+/* Handle incoming media packets A2DP SINK streaming */
+static void btif_a2dp_sink_handle_inc_media(tBT_SBC_HDR* p_msg);
+static void btif_a2dp_sink_decoder_update_event(
+    tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf);
+static void btif_a2dp_sink_clear_track_event(void);
+static void btif_a2dp_sink_set_focus_state_event(
+    btif_a2dp_sink_focus_state_t state);
+static void btif_a2dp_sink_audio_rx_flush_event(void);
+static void btif_a2dp_sink_clear_track_event_req(void);
+
+UNUSED_ATTR static const char* dump_media_event(uint16_t event) {
+  switch (event) {
+    CASE_RETURN_STR(BTIF_MEDIA_SINK_DECODER_UPDATE)
+    CASE_RETURN_STR(BTIF_MEDIA_SINK_CLEAR_TRACK)
+    CASE_RETURN_STR(BTIF_MEDIA_SINK_SET_FOCUS_STATE)
+    CASE_RETURN_STR(BTIF_MEDIA_SINK_AUDIO_RX_FLUSH)
+    default:
+      break;
+  }
+  return "UNKNOWN A2DP SINK EVENT";
+}
+
+bool btif_a2dp_sink_startup(void) {
+  if (btif_a2dp_sink_state != BTIF_A2DP_SINK_STATE_OFF) {
+    APPL_TRACE_ERROR("%s: A2DP Sink media task already running", __func__);
+    return false;
+  }
+
+  memset(&btif_a2dp_sink_cb, 0, sizeof(btif_a2dp_sink_cb));
+  btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_STARTING_UP;
+
+  APPL_TRACE_EVENT("## A2DP SINK START MEDIA THREAD ##");
+
+  /* Start A2DP Sink media task */
+  btif_a2dp_sink_cb.worker_thread = thread_new("btif_a2dp_sink_worker_thread");
+  if (btif_a2dp_sink_cb.worker_thread == NULL) {
+    APPL_TRACE_ERROR("%s: unable to start up media thread", __func__);
+    btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_OFF;
+    return false;
+  }
+
+  btif_a2dp_sink_cb.rx_focus_state = BTIF_A2DP_SINK_FOCUS_NOT_GRANTED;
+  btif_a2dp_sink_cb.audio_track = NULL;
+  btif_a2dp_sink_cb.rx_audio_queue = fixed_queue_new(SIZE_MAX);
+
+  btif_a2dp_sink_cb.cmd_msg_queue = fixed_queue_new(SIZE_MAX);
+  fixed_queue_register_dequeue(
+      btif_a2dp_sink_cb.cmd_msg_queue,
+      thread_get_reactor(btif_a2dp_sink_cb.worker_thread),
+      btif_a2dp_sink_command_ready, NULL);
+
+  APPL_TRACE_EVENT("## A2DP SINK MEDIA THREAD STARTED ##");
+
+  /* Schedule the rest of the startup operations */
+  thread_post(btif_a2dp_sink_cb.worker_thread, btif_a2dp_sink_startup_delayed,
+              NULL);
+
+  return true;
+}
+
+static void btif_a2dp_sink_startup_delayed(UNUSED_ATTR void* context) {
+  raise_priority_a2dp(TASK_HIGH_MEDIA);
+  btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_RUNNING;
+}
+
+void btif_a2dp_sink_shutdown(void) {
+  if ((btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) ||
+      (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_SHUTTING_DOWN)) {
+    return;
+  }
+
+  /* Make sure no channels are restarted while shutting down */
+  btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_SHUTTING_DOWN;
+
+  APPL_TRACE_EVENT("## A2DP SINK STOP MEDIA THREAD ##");
+
+  // Stop the timer
+  alarm_free(btif_a2dp_sink_cb.decode_alarm);
+  btif_a2dp_sink_cb.decode_alarm = NULL;
+
+  // Exit the thread
+  fixed_queue_free(btif_a2dp_sink_cb.cmd_msg_queue, NULL);
+  btif_a2dp_sink_cb.cmd_msg_queue = NULL;
+  thread_post(btif_a2dp_sink_cb.worker_thread, btif_a2dp_sink_shutdown_delayed,
+              NULL);
+  thread_free(btif_a2dp_sink_cb.worker_thread);
+  btif_a2dp_sink_cb.worker_thread = NULL;
+}
+
+static void btif_a2dp_sink_shutdown_delayed(UNUSED_ATTR void* context) {
+  fixed_queue_free(btif_a2dp_sink_cb.rx_audio_queue, NULL);
+  btif_a2dp_sink_cb.rx_audio_queue = NULL;
+
+  btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_OFF;
+}
+
+uint32_t btif_a2dp_sink_get_sample_rate(void) {
+  return btif_a2dp_sink_cb.sample_rate;
+}
+
+uint8_t btif_a2dp_sink_get_channel_count(void) {
+  return btif_a2dp_sink_cb.channel_count;
+}
+
+static void btif_a2dp_sink_command_ready(fixed_queue_t* queue,
+                                         UNUSED_ATTR void* context) {
+  BT_HDR* p_msg = (BT_HDR*)fixed_queue_dequeue(queue);
+
+  LOG_VERBOSE(LOG_TAG, "%s: event %d %s", __func__, p_msg->event,
+              dump_media_event(p_msg->event));
+
+  switch (p_msg->event) {
+    case BTIF_MEDIA_SINK_DECODER_UPDATE:
+      btif_a2dp_sink_decoder_update_event(
+          (tBTIF_MEDIA_SINK_DECODER_UPDATE*)p_msg);
+      break;
+    case BTIF_MEDIA_SINK_CLEAR_TRACK:
+      btif_a2dp_sink_clear_track_event();
+      break;
+    case BTIF_MEDIA_SINK_SET_FOCUS_STATE: {
+      btif_a2dp_sink_focus_state_t state =
+          ((tBTIF_MEDIA_SINK_FOCUS_UPDATE*)p_msg)->focus_state;
+      btif_a2dp_sink_set_focus_state_event(state);
+      break;
+    }
+    case BTIF_MEDIA_SINK_AUDIO_RX_FLUSH:
+      btif_a2dp_sink_audio_rx_flush_event();
+      break;
+    default:
+      APPL_TRACE_ERROR("ERROR in %s unknown event %d", __func__, p_msg->event);
+      break;
+  }
+
+  osi_free(p_msg);
+  LOG_VERBOSE(LOG_TAG, "%s: %s DONE", __func__, dump_media_event(p_msg->event));
+}
+
+void btif_a2dp_sink_update_decoder(const uint8_t* p_codec_info) {
+  tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf =
+      reinterpret_cast<tBTIF_MEDIA_SINK_DECODER_UPDATE*>(
+          osi_malloc(sizeof(tBTIF_MEDIA_SINK_DECODER_UPDATE)));
+
+  APPL_TRACE_EVENT("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__,
+                   p_codec_info[1], p_codec_info[2], p_codec_info[3],
+                   p_codec_info[4], p_codec_info[5], p_codec_info[6]);
+
+  memcpy(p_buf->codec_info, p_codec_info, AVDT_CODEC_SIZE);
+  p_buf->hdr.event = BTIF_MEDIA_SINK_DECODER_UPDATE;
+
+  fixed_queue_enqueue(btif_a2dp_sink_cb.cmd_msg_queue, p_buf);
+}
+
+void btif_a2dp_sink_on_idle(void) {
+  if (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) return;
+
+  btif_a2dp_sink_audio_handle_stop_decoding();
+  btif_a2dp_sink_clear_track_event_req();
+  APPL_TRACE_DEBUG("Stopped BT track");
+}
+
+void btif_a2dp_sink_on_stopped(UNUSED_ATTR tBTA_AV_SUSPEND* p_av_suspend) {
+  if (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) return;
+
+  btif_a2dp_sink_audio_handle_stop_decoding();
+}
+
+void btif_a2dp_sink_on_suspended(UNUSED_ATTR tBTA_AV_SUSPEND* p_av_suspend) {
+  if (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) return;
+
+  btif_a2dp_sink_audio_handle_stop_decoding();
+}
+
+static void btif_a2dp_sink_audio_handle_stop_decoding(void) {
+  btif_a2dp_sink_cb.rx_flush = true;
+  btif_a2dp_sink_audio_rx_flush_req();
+
+  alarm_free(btif_a2dp_sink_cb.decode_alarm);
+  btif_a2dp_sink_cb.decode_alarm = NULL;
+#ifndef OS_GENERIC
+  BtifAvrcpAudioTrackPause(btif_a2dp_sink_cb.audio_track);
+#endif
+}
+
+static void btif_decode_alarm_cb(UNUSED_ATTR void* context) {
+  if (btif_a2dp_sink_cb.worker_thread != NULL) {
+    thread_post(btif_a2dp_sink_cb.worker_thread,
+                btif_a2dp_sink_avk_handle_timer, NULL);
+  }
+}
+
+static void btif_a2dp_sink_clear_track_event(void) {
+  APPL_TRACE_DEBUG("%s", __func__);
+
+#ifndef OS_GENERIC
+  BtifAvrcpAudioTrackStop(btif_a2dp_sink_cb.audio_track);
+  BtifAvrcpAudioTrackDelete(btif_a2dp_sink_cb.audio_track);
+#endif
+  btif_a2dp_sink_cb.audio_track = NULL;
+}
+
+static void btif_a2dp_sink_audio_handle_start_decoding(void) {
+  if (btif_a2dp_sink_cb.decode_alarm != NULL)
+    return;  // Already started decoding
+
+#ifndef OS_GENERIC
+  BtifAvrcpAudioTrackStart(btif_a2dp_sink_cb.audio_track);
+#endif
+
+  btif_a2dp_sink_cb.decode_alarm = alarm_new_periodic("btif.a2dp_sink_decode");
+  if (btif_a2dp_sink_cb.decode_alarm == NULL) {
+    LOG_ERROR(LOG_TAG, "%s: unable to allocate decode alarm", __func__);
+    return;
+  }
+  alarm_set(btif_a2dp_sink_cb.decode_alarm, BTIF_SINK_MEDIA_TIME_TICK_MS,
+            btif_decode_alarm_cb, NULL);
+}
+
+static void btif_a2dp_sink_handle_inc_media(tBT_SBC_HDR* p_msg) {
+  uint8_t* sbc_start_frame = ((uint8_t*)(p_msg + 1) + p_msg->offset + 1);
+  int count;
+  uint32_t pcmBytes, availPcmBytes;
+  int16_t* pcmDataPointer =
+      btif_a2dp_sink_pcm_data; /* Will be overwritten on next packet receipt */
+  OI_STATUS status;
+  int num_sbc_frames = p_msg->num_frames_to_be_processed;
+  uint32_t sbc_frame_len = p_msg->len - 1;
+  availPcmBytes = sizeof(btif_a2dp_sink_pcm_data);
+
+  if ((btif_av_get_peer_sep() == AVDT_TSEP_SNK) ||
+      (btif_a2dp_sink_cb.rx_flush)) {
+    APPL_TRACE_DEBUG("State Changed happened in this tick");
+    return;
+  }
+
+  APPL_TRACE_DEBUG("%s Number of SBC frames %d, frame_len %d", __func__,
+                   num_sbc_frames, sbc_frame_len);
+
+  for (count = 0; count < num_sbc_frames && sbc_frame_len != 0; count++) {
+    pcmBytes = availPcmBytes;
+    status = OI_CODEC_SBC_DecodeFrame(
+        &btif_a2dp_sink_context, (const OI_BYTE**)&sbc_start_frame,
+        (uint32_t*)&sbc_frame_len, (int16_t*)pcmDataPointer,
+        (uint32_t*)&pcmBytes);
+    if (!OI_SUCCESS(status)) {
+      APPL_TRACE_ERROR("%s: Decoding failure: %d", __func__, status);
+      break;
+    }
+    availPcmBytes -= pcmBytes;
+    pcmDataPointer += pcmBytes / 2;
+    p_msg->offset += (p_msg->len - 1) - sbc_frame_len;
+    p_msg->len = sbc_frame_len + 1;
+  }
+
+#ifndef OS_GENERIC
+  BtifAvrcpAudioTrackWriteData(
+      btif_a2dp_sink_cb.audio_track, (void*)btif_a2dp_sink_pcm_data,
+      (sizeof(btif_a2dp_sink_pcm_data) - availPcmBytes));
+#endif
+}
+
+static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void* context) {
+  tBT_SBC_HDR* p_msg;
+  int num_sbc_frames;
+  int num_frames_to_process;
+
+  if (fixed_queue_is_empty(btif_a2dp_sink_cb.rx_audio_queue)) {
+    APPL_TRACE_DEBUG("%s: empty queue", __func__);
+    return;
+  }
+
+  /* Don't do anything in case of focus not granted */
+  if (btif_a2dp_sink_cb.rx_focus_state == BTIF_A2DP_SINK_FOCUS_NOT_GRANTED) {
+    APPL_TRACE_DEBUG("%s: skipping frames since focus is not present",
+                     __func__);
+    return;
+  }
+  /* Play only in BTIF_A2DP_SINK_FOCUS_GRANTED case */
+  if (btif_a2dp_sink_cb.rx_flush) {
+    fixed_queue_flush(btif_a2dp_sink_cb.rx_audio_queue, osi_free);
+    return;
+  }
+
+  num_frames_to_process = btif_a2dp_sink_cb.frames_to_process;
+  APPL_TRACE_DEBUG(" Process Frames + ");
+
+  do {
+    p_msg = (tBT_SBC_HDR*)fixed_queue_try_peek_first(
+        btif_a2dp_sink_cb.rx_audio_queue);
+    if (p_msg == NULL) return;
+    /* Number of frames in queue packets */
+    num_sbc_frames = p_msg->num_frames_to_be_processed;
+    APPL_TRACE_DEBUG("Frames left in topmost packet %d", num_sbc_frames);
+    APPL_TRACE_DEBUG("Remaining frames to process in tick %d",
+                     num_frames_to_process);
+    APPL_TRACE_DEBUG("Number of packets in queue %d",
+                     fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue));
+
+    if (num_sbc_frames > num_frames_to_process) {
+      /* Queue packet has more frames */
+      p_msg->num_frames_to_be_processed = num_frames_to_process;
+      btif_a2dp_sink_handle_inc_media(p_msg);
+      p_msg->num_frames_to_be_processed =
+          num_sbc_frames - num_frames_to_process;
+      num_frames_to_process = 0;
+      break;
+    }
+    /* Queue packet has less frames */
+    btif_a2dp_sink_handle_inc_media(p_msg);
+    p_msg =
+        (tBT_SBC_HDR*)fixed_queue_try_dequeue(btif_a2dp_sink_cb.rx_audio_queue);
+    if (p_msg == NULL) {
+      APPL_TRACE_ERROR("Insufficient data in queue");
+      break;
+    }
+    num_frames_to_process =
+        num_frames_to_process - p_msg->num_frames_to_be_processed;
+    osi_free(p_msg);
+  } while (num_frames_to_process > 0);
+
+  APPL_TRACE_DEBUG("Process Frames - ");
+}
+
+/* when true media task discards any rx frames */
+void btif_a2dp_sink_set_rx_flush(bool enable) {
+  APPL_TRACE_EVENT("## DROP RX %d ##", enable);
+  btif_a2dp_sink_cb.rx_flush = enable;
+}
+
+static void btif_a2dp_sink_audio_rx_flush_event(void) {
+  /* Flush all received SBC buffers (encoded) */
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  fixed_queue_flush(btif_a2dp_sink_cb.rx_audio_queue, osi_free);
+}
+
+static void btif_a2dp_sink_decoder_update_event(
+    tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf) {
+  OI_STATUS status;
+
+  APPL_TRACE_DEBUG("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__,
+                   p_buf->codec_info[1], p_buf->codec_info[2],
+                   p_buf->codec_info[3], p_buf->codec_info[4],
+                   p_buf->codec_info[5], p_buf->codec_info[6]);
+
+  int sample_rate = A2DP_GetTrackFrequency(p_buf->codec_info);
+  if (sample_rate == -1) {
+    APPL_TRACE_ERROR("%s: cannot get the track frequency", __func__);
+    return;
+  }
+  int channel_count = A2DP_GetTrackChannelCount(p_buf->codec_info);
+  if (channel_count == -1) {
+    APPL_TRACE_ERROR("%s: cannot get the channel count", __func__);
+    return;
+  }
+  int channel_type = A2DP_GetSinkTrackChannelType(p_buf->codec_info);
+  if (channel_type == -1) {
+    APPL_TRACE_ERROR("%s: cannot get the Sink channel type", __func__);
+    return;
+  }
+  btif_a2dp_sink_cb.sample_rate = sample_rate;
+  btif_a2dp_sink_cb.channel_count = channel_count;
+
+  btif_a2dp_sink_cb.rx_flush = false;
+  APPL_TRACE_DEBUG("Reset to Sink role");
+  status = OI_CODEC_SBC_DecoderReset(
+      &btif_a2dp_sink_context, btif_a2dp_sink_context_data,
+      sizeof(btif_a2dp_sink_context_data), 2, 2, false);
+  if (!OI_SUCCESS(status)) {
+    APPL_TRACE_ERROR("OI_CODEC_SBC_DecoderReset failed with error code %d",
+                     status);
+  }
+
+  APPL_TRACE_DEBUG("%s: A2dpSink: SBC create track", __func__);
+  btif_a2dp_sink_cb.audio_track =
+#ifndef OS_GENERIC
+      BtifAvrcpAudioTrackCreate(sample_rate, channel_type);
+#else
+      NULL;
+#endif
+  if (btif_a2dp_sink_cb.audio_track == NULL) {
+    APPL_TRACE_ERROR("%s: A2dpSink: Track creation failed!!!", __func__);
+    return;
+  }
+
+  btif_a2dp_sink_cb.frames_to_process = A2DP_GetSinkFramesCountToProcess(
+      BTIF_SINK_MEDIA_TIME_TICK_MS, p_buf->codec_info);
+  APPL_TRACE_DEBUG("Frames to be processed in 20 ms %d",
+                   btif_a2dp_sink_cb.frames_to_process);
+  if (btif_a2dp_sink_cb.frames_to_process == 0) {
+    APPL_TRACE_ERROR("Cannot compute the number of frames to process");
+  }
+}
+
+uint8_t btif_a2dp_sink_enqueue_buf(BT_HDR* p_pkt) {
+  if (btif_a2dp_sink_cb.rx_flush) /* Flush enabled, do not enqueue */
+    return fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue);
+
+  if (fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue) ==
+      MAX_INPUT_A2DP_FRAME_QUEUE_SZ) {
+    uint8_t ret = fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue);
+    osi_free(fixed_queue_try_dequeue(btif_a2dp_sink_cb.rx_audio_queue));
+    return ret;
+  }
+
+  BTIF_TRACE_VERBOSE("%s +", __func__);
+  /* Allocate and queue this buffer */
+  tBT_SBC_HDR* p_msg = reinterpret_cast<tBT_SBC_HDR*>(
+      osi_malloc(sizeof(tBT_SBC_HDR) + p_pkt->offset + p_pkt->len));
+  memcpy((uint8_t*)(p_msg + 1), (uint8_t*)(p_pkt + 1) + p_pkt->offset,
+         p_pkt->len);
+  p_msg->num_frames_to_be_processed =
+      (*((uint8_t*)(p_pkt + 1) + p_pkt->offset)) & 0x0f;
+  p_msg->len = p_pkt->len;
+  p_msg->offset = 0;
+  p_msg->layer_specific = p_pkt->layer_specific;
+  BTIF_TRACE_VERBOSE("%s: frames to process %d, len %d", __func__,
+                     p_msg->num_frames_to_be_processed, p_msg->len);
+  fixed_queue_enqueue(btif_a2dp_sink_cb.rx_audio_queue, p_msg);
+  if (fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue) ==
+      MAX_A2DP_DELAYED_START_FRAME_COUNT) {
+    BTIF_TRACE_DEBUG("%s: Initiate decoding", __func__);
+    btif_a2dp_sink_audio_handle_start_decoding();
+  }
+
+  return fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue);
+}
+
+void btif_a2dp_sink_audio_rx_flush_req(void) {
+  if (fixed_queue_is_empty(btif_a2dp_sink_cb.rx_audio_queue)) {
+    /* Queue is already empty */
+    return;
+  }
+
+  BT_HDR* p_buf = reinterpret_cast<BT_HDR*>(osi_malloc(sizeof(BT_HDR)));
+  p_buf->event = BTIF_MEDIA_SINK_AUDIO_RX_FLUSH;
+  fixed_queue_enqueue(btif_a2dp_sink_cb.cmd_msg_queue, p_buf);
+}
+
+void btif_a2dp_sink_debug_dump(UNUSED_ATTR int fd) {
+  // Nothing to do
+}
+
+void btif_a2dp_sink_update_metrics(void) {
+  // Nothing to do
+}
+
+void btif_a2dp_sink_set_focus_state_req(btif_a2dp_sink_focus_state_t state) {
+  tBTIF_MEDIA_SINK_FOCUS_UPDATE* p_buf =
+      reinterpret_cast<tBTIF_MEDIA_SINK_FOCUS_UPDATE*>(
+          osi_malloc(sizeof(tBTIF_MEDIA_SINK_FOCUS_UPDATE)));
+
+  APPL_TRACE_EVENT("%s", __func__);
+
+  p_buf->focus_state = state;
+  p_buf->hdr.event = BTIF_MEDIA_SINK_SET_FOCUS_STATE;
+  fixed_queue_enqueue(btif_a2dp_sink_cb.cmd_msg_queue, p_buf);
+}
+
+static void btif_a2dp_sink_set_focus_state_event(
+    btif_a2dp_sink_focus_state_t state) {
+  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;
+}
+
+void btif_a2dp_sink_set_audio_track_gain(float gain) {
+  APPL_TRACE_DEBUG("%s set gain to %f", __func__, gain);
+#ifndef OS_GENERIC
+  BtifAvrcpSetAudioTrackGain(btif_a2dp_sink_cb.audio_track, gain);
+#endif
+}
+
+static void btif_a2dp_sink_clear_track_event_req(void) {
+  BT_HDR* p_buf = reinterpret_cast<BT_HDR*>(osi_malloc(sizeof(BT_HDR)));
+
+  p_buf->event = BTIF_MEDIA_SINK_CLEAR_TRACK;
+  fixed_queue_enqueue(btif_a2dp_sink_cb.cmd_msg_queue, p_buf);
+}
diff --git a/bt/btif/src/btif_a2dp_source.cc b/bt/btif/src/btif_a2dp_source.cc
new file mode 100644
index 0000000..0d595cc
--- /dev/null
+++ b/bt/btif/src/btif_a2dp_source.cc
@@ -0,0 +1,1036 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_a2dp_source"
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+
+#include "audio_a2dp_hw.h"
+#include "bt_common.h"
+#include "bta_av_ci.h"
+#include "btcore/include/bdaddr.h"
+#include "btif_a2dp.h"
+#include "btif_a2dp_control.h"
+#include "btif_a2dp_source.h"
+#include "btif_av.h"
+#include "btif_av_co.h"
+#include "btif_util.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/log.h"
+#include "osi/include/metrics.h"
+#include "osi/include/mutex.h"
+#include "osi/include/osi.h"
+#include "osi/include/thread.h"
+#include "osi/include/time.h"
+#include "uipc.h"
+
+/**
+ * The typical runlevel of the tx queue size is ~1 buffer
+ * but due to link flow control or thread preemption in lower
+ * layers we might need to temporarily buffer up data.
+ */
+#define MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ (MAX_PCM_FRAME_NUM_PER_TICK * 2)
+
+enum {
+  BTIF_A2DP_SOURCE_STATE_OFF,
+  BTIF_A2DP_SOURCE_STATE_STARTING_UP,
+  BTIF_A2DP_SOURCE_STATE_RUNNING,
+  BTIF_A2DP_SOURCE_STATE_SHUTTING_DOWN
+};
+
+/* BTIF Media Source event definition */
+enum {
+  BTIF_MEDIA_AUDIO_TX_START = 1,
+  BTIF_MEDIA_AUDIO_TX_STOP,
+  BTIF_MEDIA_AUDIO_TX_FLUSH,
+  BTIF_MEDIA_SOURCE_ENCODER_INIT,
+  BTIF_MEDIA_SOURCE_ENCODER_UPDATE,
+  BTIF_MEDIA_AUDIO_FEEDING_INIT
+};
+
+/* tBTIF_A2DP_AUDIO_FEEDING_INIT msg structure */
+typedef struct {
+  BT_HDR hdr;
+  tA2DP_FEEDING_PARAMS feeding_params;
+} tBTIF_A2DP_AUDIO_FEEDING_INIT;
+
+/* tBTIF_A2DP_SOURCE_ENCODER_INIT msg structure */
+typedef struct {
+  BT_HDR hdr;
+  tA2DP_ENCODER_INIT_PARAMS init_params;
+} tBTIF_A2DP_SOURCE_ENCODER_INIT;
+
+/* tBTIF_A2DP_SOURCE_ENCODER_UPDATE msg structure */
+typedef struct {
+  BT_HDR hdr;
+  tA2DP_ENCODER_UPDATE_PARAMS update_params;
+} tBTIF_A2DP_SOURCE_ENCODER_UPDATE;
+
+typedef struct {
+  // Counter for total updates
+  size_t total_updates;
+
+  // Last update timestamp (in us)
+  uint64_t last_update_us;
+
+  // Counter for overdue scheduling
+  size_t overdue_scheduling_count;
+
+  // Accumulated overdue scheduling deviations (in us)
+  uint64_t total_overdue_scheduling_delta_us;
+
+  // Max. overdue scheduling delta time (in us)
+  uint64_t max_overdue_scheduling_delta_us;
+
+  // Counter for premature scheduling
+  size_t premature_scheduling_count;
+
+  // Accumulated premature scheduling deviations (in us)
+  uint64_t total_premature_scheduling_delta_us;
+
+  // Max. premature scheduling delta time (in us)
+  uint64_t max_premature_scheduling_delta_us;
+
+  // Counter for exact scheduling
+  size_t exact_scheduling_count;
+
+  // Accumulated and counted scheduling time (in us)
+  uint64_t total_scheduling_time_us;
+} scheduling_stats_t;
+
+typedef struct {
+  uint64_t session_start_us;
+
+  scheduling_stats_t tx_queue_enqueue_stats;
+  scheduling_stats_t tx_queue_dequeue_stats;
+
+  size_t tx_queue_total_frames;
+  size_t tx_queue_max_frames_per_packet;
+
+  uint64_t tx_queue_total_queueing_time_us;
+  uint64_t tx_queue_max_queueing_time_us;
+
+  size_t tx_queue_total_readbuf_calls;
+  uint64_t tx_queue_last_readbuf_us;
+
+  size_t tx_queue_total_flushed_messages;
+  uint64_t tx_queue_last_flushed_us;
+
+  size_t tx_queue_total_dropped_messages;
+  size_t tx_queue_max_dropped_messages;
+  size_t tx_queue_dropouts;
+  uint64_t tx_queue_last_dropouts_us;
+
+  size_t media_read_total_underflow_bytes;
+  size_t media_read_total_underflow_count;
+  uint64_t media_read_last_underflow_us;
+} btif_media_stats_t;
+
+typedef struct {
+  thread_t* worker_thread;
+  fixed_queue_t* cmd_msg_queue;
+  fixed_queue_t* tx_audio_queue;
+  bool tx_flush; /* Discards any outgoing data when true */
+  bool is_streaming;
+  alarm_t* media_alarm;
+  const tA2DP_ENCODER_INTERFACE* encoder_interface;
+  period_ms_t encoder_interval_ms; /* Local copy of the encoder interval */
+  btif_media_stats_t stats;
+} tBTIF_A2DP_SOURCE_CB;
+
+static tBTIF_A2DP_SOURCE_CB btif_a2dp_source_cb;
+static int btif_a2dp_source_state = BTIF_A2DP_SOURCE_STATE_OFF;
+
+static void btif_a2dp_source_command_ready(fixed_queue_t* queue, void* context);
+static void btif_a2dp_source_startup_delayed(void* context);
+static void btif_a2dp_source_shutdown_delayed(void* context);
+static void btif_a2dp_source_audio_tx_start_event(void);
+static void btif_a2dp_source_audio_tx_stop_event(void);
+static void btif_a2dp_source_audio_tx_flush_event(BT_HDR* p_msg);
+static void btif_a2dp_source_encoder_init_event(BT_HDR* p_msg);
+static void btif_a2dp_source_encoder_update_event(BT_HDR* p_msg);
+static void btif_a2dp_source_audio_feeding_init_event(BT_HDR* p_msg);
+static void btif_a2dp_source_encoder_init(void);
+static void btif_a2dp_source_feeding_init_req(
+    tBTIF_A2DP_AUDIO_FEEDING_INIT* p_msg);
+static void btif_a2dp_source_encoder_init_req(
+    tBTIF_A2DP_SOURCE_ENCODER_INIT* p_msg);
+static void btif_a2dp_source_encoder_update_req(
+    tBTIF_A2DP_SOURCE_ENCODER_UPDATE* p_msg);
+static bool btif_a2dp_source_audio_tx_flush_req(void);
+static void btif_a2dp_source_alarm_cb(void* context);
+static void btif_a2dp_source_audio_handle_timer(void* context);
+static uint32_t btif_a2dp_source_read_callback(uint8_t* p_buf, uint32_t len);
+static bool btif_a2dp_source_enqueue_callback(BT_HDR* p_buf, size_t frames_n);
+static void log_tstamps_us(const char* comment, uint64_t timestamp_us);
+static void update_scheduling_stats(scheduling_stats_t* stats, uint64_t now_us,
+                                    uint64_t expected_delta);
+static void btm_read_rssi_cb(void* data);
+
+UNUSED_ATTR static const char* dump_media_event(uint16_t event) {
+  switch (event) {
+    CASE_RETURN_STR(BTIF_MEDIA_AUDIO_TX_START)
+    CASE_RETURN_STR(BTIF_MEDIA_AUDIO_TX_STOP)
+    CASE_RETURN_STR(BTIF_MEDIA_AUDIO_TX_FLUSH)
+    CASE_RETURN_STR(BTIF_MEDIA_SOURCE_ENCODER_INIT)
+    CASE_RETURN_STR(BTIF_MEDIA_SOURCE_ENCODER_UPDATE)
+    CASE_RETURN_STR(BTIF_MEDIA_AUDIO_FEEDING_INIT)
+    default:
+      break;
+  }
+  return "UNKNOWN A2DP SOURCE EVENT";
+}
+
+bool btif_a2dp_source_startup(void) {
+  if (btif_a2dp_source_state != BTIF_A2DP_SOURCE_STATE_OFF) {
+    APPL_TRACE_ERROR("%s: A2DP Source media task already running", __func__);
+    return false;
+  }
+
+  memset(&btif_a2dp_source_cb, 0, sizeof(btif_a2dp_source_cb));
+  btif_a2dp_source_state = BTIF_A2DP_SOURCE_STATE_STARTING_UP;
+
+  APPL_TRACE_EVENT("## A2DP SOURCE START MEDIA THREAD ##");
+
+  /* Start A2DP Source media task */
+  btif_a2dp_source_cb.worker_thread =
+      thread_new("btif_a2dp_source_worker_thread");
+  if (btif_a2dp_source_cb.worker_thread == NULL) {
+    APPL_TRACE_ERROR("%s: unable to start up media thread", __func__);
+    btif_a2dp_source_state = BTIF_A2DP_SOURCE_STATE_OFF;
+    return false;
+  }
+
+  btif_a2dp_source_cb.stats.session_start_us = time_get_os_boottime_us();
+  btif_a2dp_source_cb.tx_audio_queue = fixed_queue_new(SIZE_MAX);
+
+  btif_a2dp_source_cb.cmd_msg_queue = fixed_queue_new(SIZE_MAX);
+  fixed_queue_register_dequeue(
+      btif_a2dp_source_cb.cmd_msg_queue,
+      thread_get_reactor(btif_a2dp_source_cb.worker_thread),
+      btif_a2dp_source_command_ready, NULL);
+
+  APPL_TRACE_EVENT("## A2DP SOURCE MEDIA THREAD STARTED ##");
+
+  /* Schedule the rest of the startup operations */
+  thread_post(btif_a2dp_source_cb.worker_thread,
+              btif_a2dp_source_startup_delayed, NULL);
+
+  return true;
+}
+
+static void btif_a2dp_source_startup_delayed(UNUSED_ATTR void* context) {
+  raise_priority_a2dp(TASK_HIGH_MEDIA);
+  btif_a2dp_control_init();
+  btif_a2dp_source_state = BTIF_A2DP_SOURCE_STATE_RUNNING;
+}
+
+void btif_a2dp_source_shutdown(void) {
+  if ((btif_a2dp_source_state == BTIF_A2DP_SOURCE_STATE_OFF) ||
+      (btif_a2dp_source_state == BTIF_A2DP_SOURCE_STATE_SHUTTING_DOWN)) {
+    return;
+  }
+
+  /* Make sure no channels are restarted while shutting down */
+  btif_a2dp_source_state = BTIF_A2DP_SOURCE_STATE_SHUTTING_DOWN;
+
+  APPL_TRACE_EVENT("## A2DP SOURCE STOP MEDIA THREAD ##");
+
+  // Stop the timer
+  btif_a2dp_source_cb.is_streaming = FALSE;
+  alarm_free(btif_a2dp_source_cb.media_alarm);
+  btif_a2dp_source_cb.media_alarm = NULL;
+
+  // Exit the thread
+  fixed_queue_free(btif_a2dp_source_cb.cmd_msg_queue, NULL);
+  btif_a2dp_source_cb.cmd_msg_queue = NULL;
+  thread_post(btif_a2dp_source_cb.worker_thread,
+              btif_a2dp_source_shutdown_delayed, NULL);
+  thread_free(btif_a2dp_source_cb.worker_thread);
+  btif_a2dp_source_cb.worker_thread = NULL;
+}
+
+static void btif_a2dp_source_shutdown_delayed(UNUSED_ATTR void* context) {
+  btif_a2dp_control_cleanup();
+  fixed_queue_free(btif_a2dp_source_cb.tx_audio_queue, NULL);
+  btif_a2dp_source_cb.tx_audio_queue = NULL;
+
+  btif_a2dp_source_state = BTIF_A2DP_SOURCE_STATE_OFF;
+}
+
+bool btif_a2dp_source_media_task_is_running(void) {
+  return (btif_a2dp_source_state == BTIF_A2DP_SOURCE_STATE_RUNNING);
+}
+
+bool btif_a2dp_source_media_task_is_shutting_down(void) {
+  return (btif_a2dp_source_state == BTIF_A2DP_SOURCE_STATE_SHUTTING_DOWN);
+}
+
+bool btif_a2dp_source_is_streaming(void) {
+  return btif_a2dp_source_cb.is_streaming;
+}
+
+static void btif_a2dp_source_command_ready(fixed_queue_t* queue,
+                                           UNUSED_ATTR void* context) {
+  BT_HDR* p_msg = (BT_HDR*)fixed_queue_dequeue(queue);
+
+  LOG_VERBOSE(LOG_TAG, "%s: event %d %s", __func__, p_msg->event,
+              dump_media_event(p_msg->event));
+
+  switch (p_msg->event) {
+    case BTIF_MEDIA_AUDIO_TX_START:
+      btif_a2dp_source_audio_tx_start_event();
+      break;
+    case BTIF_MEDIA_AUDIO_TX_STOP:
+      btif_a2dp_source_audio_tx_stop_event();
+      break;
+    case BTIF_MEDIA_AUDIO_TX_FLUSH:
+      btif_a2dp_source_audio_tx_flush_event(p_msg);
+      break;
+    case BTIF_MEDIA_SOURCE_ENCODER_INIT:
+      btif_a2dp_source_encoder_init_event(p_msg);
+      break;
+    case BTIF_MEDIA_SOURCE_ENCODER_UPDATE:
+      btif_a2dp_source_encoder_update_event(p_msg);
+      break;
+    case BTIF_MEDIA_AUDIO_FEEDING_INIT:
+      btif_a2dp_source_audio_feeding_init_event(p_msg);
+      break;
+    default:
+      APPL_TRACE_ERROR("ERROR in %s unknown event %d", __func__, p_msg->event);
+      break;
+  }
+
+  osi_free(p_msg);
+  LOG_VERBOSE(LOG_TAG, "%s: %s DONE", __func__, dump_media_event(p_msg->event));
+}
+
+void btif_a2dp_source_setup_codec(void) {
+  tA2DP_FEEDING_PARAMS feeding_params;
+
+  APPL_TRACE_EVENT("## A2DP SOURCE SETUP CODEC ##");
+
+  mutex_global_lock();
+
+  /* for now hardcode 44.1 khz 16 bit stereo PCM format */
+  feeding_params.sampling_freq = BTIF_A2DP_SRC_SAMPLING_RATE;
+  feeding_params.bit_per_sample = BTIF_A2DP_SRC_BIT_DEPTH;
+  feeding_params.num_channel = BTIF_A2DP_SRC_NUM_CHANNELS;
+
+  if (bta_av_co_audio_set_codec(&feeding_params)) {
+    tBTIF_A2DP_AUDIO_FEEDING_INIT mfeed;
+
+    /* Init the encoding task */
+    btif_a2dp_source_encoder_init();
+
+    /* Build the media task configuration */
+    mfeed.feeding_params = feeding_params;
+    /* Send message to Media task to configure transcoding */
+    btif_a2dp_source_feeding_init_req(&mfeed);
+  }
+
+  mutex_global_unlock();
+}
+
+void btif_a2dp_source_start_audio_req(void) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = BTIF_MEDIA_AUDIO_TX_START;
+  fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf);
+}
+
+void btif_a2dp_source_stop_audio_req(void) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = BTIF_MEDIA_AUDIO_TX_STOP;
+
+  /*
+   * Explicitly check whether btif_a2dp_source_cb.cmd_msg_queue is not NULL
+   * to avoid a race condition during shutdown of the Bluetooth stack.
+   * This race condition is triggered when A2DP audio is streaming on
+   * shutdown:
+   * "btif_a2dp_source_on_stopped() -> btif_a2dp_source_stop_audio_req()"
+   * is called to stop the particular audio stream, and this happens right
+   * after the "BTIF_AV_CLEANUP_REQ_EVT -> btif_a2dp_source_shutdown()"
+   * processing during the shutdown of the Bluetooth stack.
+   */
+  if (btif_a2dp_source_cb.cmd_msg_queue != NULL)
+    fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf);
+}
+
+static void btif_a2dp_source_encoder_init(void) {
+  tBTIF_A2DP_SOURCE_ENCODER_INIT msg;
+
+  // Check to make sure the platform has 8 bits/byte since
+  // we're using that in frame size calculations now.
+  assert(CHAR_BIT == 8);
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  bta_av_co_audio_encoder_init(&msg.init_params);
+  btif_a2dp_source_encoder_init_req(&msg);
+}
+
+void btif_a2dp_source_encoder_update(void) {
+  tBTIF_A2DP_SOURCE_ENCODER_UPDATE msg;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  bta_av_co_audio_encoder_update(&msg.update_params);
+  btif_a2dp_source_encoder_update_req(&msg);
+}
+
+static void btif_a2dp_source_encoder_init_req(
+    tBTIF_A2DP_SOURCE_ENCODER_INIT* p_msg) {
+  tBTIF_A2DP_SOURCE_ENCODER_INIT* p_buf =
+      (tBTIF_A2DP_SOURCE_ENCODER_INIT*)osi_malloc(
+          sizeof(tBTIF_A2DP_SOURCE_ENCODER_INIT));
+
+  memcpy(p_buf, p_msg, sizeof(tBTIF_A2DP_SOURCE_ENCODER_INIT));
+  p_buf->hdr.event = BTIF_MEDIA_SOURCE_ENCODER_INIT;
+  fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf);
+}
+
+static void btif_a2dp_source_encoder_update_req(
+    tBTIF_A2DP_SOURCE_ENCODER_UPDATE* p_msg) {
+  tBTIF_A2DP_SOURCE_ENCODER_UPDATE* p_buf =
+      (tBTIF_A2DP_SOURCE_ENCODER_UPDATE*)osi_malloc(
+          sizeof(tBTIF_A2DP_SOURCE_ENCODER_UPDATE));
+
+  memcpy(p_buf, p_msg, sizeof(tBTIF_A2DP_SOURCE_ENCODER_UPDATE));
+  p_buf->hdr.event = BTIF_MEDIA_SOURCE_ENCODER_UPDATE;
+  fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf);
+}
+
+static void btif_a2dp_source_encoder_init_event(BT_HDR* p_msg) {
+  tBTIF_A2DP_SOURCE_ENCODER_INIT* p_encoder_init =
+      (tBTIF_A2DP_SOURCE_ENCODER_INIT*)p_msg;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  btif_a2dp_source_cb.encoder_interface = bta_av_co_get_encoder_interface();
+  if (btif_a2dp_source_cb.encoder_interface == NULL) {
+    APPL_TRACE_ERROR("%s: Cannot stream audio: no source encoder interface",
+                     __func__);
+    return;
+  }
+
+  btif_a2dp_source_cb.encoder_interface->encoder_init(
+      btif_av_is_peer_edr(), btif_av_peer_supports_3mbps(),
+      &p_encoder_init->init_params, btif_a2dp_source_read_callback,
+      btif_a2dp_source_enqueue_callback);
+
+  // Save a local copy of the encoder_interval_ms
+  btif_a2dp_source_cb.encoder_interval_ms =
+      btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms();
+}
+
+static void btif_a2dp_source_encoder_update_event(BT_HDR* p_msg) {
+  tBTIF_A2DP_SOURCE_ENCODER_UPDATE* p_encoder_update =
+      (tBTIF_A2DP_SOURCE_ENCODER_UPDATE*)p_msg;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+  assert(btif_a2dp_source_cb.encoder_interface != NULL);
+  btif_a2dp_source_cb.encoder_interface->encoder_update(
+      &p_encoder_update->update_params);
+}
+
+static void btif_a2dp_source_feeding_init_req(
+    tBTIF_A2DP_AUDIO_FEEDING_INIT* p_msg) {
+  tBTIF_A2DP_AUDIO_FEEDING_INIT* p_buf =
+      (tBTIF_A2DP_AUDIO_FEEDING_INIT*)osi_malloc(
+          sizeof(tBTIF_A2DP_AUDIO_FEEDING_INIT));
+
+  memcpy(p_buf, p_msg, sizeof(tBTIF_A2DP_AUDIO_FEEDING_INIT));
+  p_buf->hdr.event = BTIF_MEDIA_AUDIO_FEEDING_INIT;
+  fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf);
+}
+
+void btif_a2dp_source_on_idle(void) {
+  if (btif_a2dp_source_state == BTIF_A2DP_SOURCE_STATE_OFF) return;
+
+  /* Make sure media task is stopped */
+  btif_a2dp_source_stop_audio_req();
+}
+
+void btif_a2dp_source_on_stopped(tBTA_AV_SUSPEND* p_av_suspend) {
+  APPL_TRACE_EVENT("## ON A2DP SOURCE STOPPED ##");
+
+  if (btif_a2dp_source_state == BTIF_A2DP_SOURCE_STATE_OFF) return;
+
+  /* allow using this api for other than suspend */
+  if (p_av_suspend != NULL) {
+    if (p_av_suspend->status != BTA_AV_SUCCESS) {
+      APPL_TRACE_EVENT("AV STOP FAILED (%d)", p_av_suspend->status);
+      if (p_av_suspend->initiator) {
+        APPL_TRACE_WARNING("%s: A2DP stop request failed: status = %d",
+                           __func__, p_av_suspend->status);
+        btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+      }
+      return;
+    }
+  }
+
+  /* ensure tx frames are immediately suspended */
+  btif_a2dp_source_cb.tx_flush = true;
+
+  /* request to stop media task */
+  btif_a2dp_source_audio_tx_flush_req();
+  btif_a2dp_source_stop_audio_req();
+
+  /* once stream is fully stopped we will ack back */
+}
+
+void btif_a2dp_source_on_suspended(tBTA_AV_SUSPEND* p_av_suspend) {
+  APPL_TRACE_EVENT("## ON A2DP SOURCE SUSPENDED ##");
+
+  if (btif_a2dp_source_state == BTIF_A2DP_SOURCE_STATE_OFF) return;
+
+  /* check for status failures */
+  if (p_av_suspend->status != BTA_AV_SUCCESS) {
+    if (p_av_suspend->initiator) {
+      APPL_TRACE_WARNING("%s: A2DP suspend request failed: status = %d",
+                         __func__, p_av_suspend->status);
+      btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+    }
+  }
+
+  /* once stream is fully stopped we will ack back */
+
+  /* ensure tx frames are immediately flushed */
+  btif_a2dp_source_cb.tx_flush = true;
+
+  /* stop timer tick */
+  btif_a2dp_source_stop_audio_req();
+}
+
+/* when true media task discards any tx frames */
+void btif_a2dp_source_set_tx_flush(bool enable) {
+  APPL_TRACE_EVENT("## DROP TX %d ##", enable);
+  btif_a2dp_source_cb.tx_flush = enable;
+}
+
+static void btif_a2dp_source_audio_feeding_init_event(BT_HDR* p_msg) {
+  tBTIF_A2DP_AUDIO_FEEDING_INIT* p_feeding =
+      (tBTIF_A2DP_AUDIO_FEEDING_INIT*)p_msg;
+
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  assert(btif_a2dp_source_cb.encoder_interface != NULL);
+  btif_a2dp_source_cb.encoder_interface->feeding_init(
+      &p_feeding->feeding_params);
+}
+
+static void btif_a2dp_source_audio_tx_start_event(void) {
+  APPL_TRACE_DEBUG(
+      "%s media_alarm is %srunning, is_streaming %s", __func__,
+      alarm_is_scheduled(btif_a2dp_source_cb.media_alarm) ? "" : "not ",
+      (btif_a2dp_source_cb.is_streaming) ? "true" : "false");
+
+  /* Reset the media feeding state */
+  assert(btif_a2dp_source_cb.encoder_interface != NULL);
+  btif_a2dp_source_cb.encoder_interface->feeding_reset();
+
+  APPL_TRACE_EVENT(
+      "starting timer %dms",
+      btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms());
+
+  alarm_free(btif_a2dp_source_cb.media_alarm);
+  btif_a2dp_source_cb.media_alarm =
+      alarm_new_periodic("btif.a2dp_source_media_alarm");
+  if (btif_a2dp_source_cb.media_alarm == NULL) {
+    LOG_ERROR(LOG_TAG, "%s unable to allocate media alarm", __func__);
+    return;
+  }
+
+  alarm_set(btif_a2dp_source_cb.media_alarm,
+            btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms(),
+            btif_a2dp_source_alarm_cb, NULL);
+}
+
+static void btif_a2dp_source_audio_tx_stop_event(void) {
+  APPL_TRACE_DEBUG(
+      "%s media_alarm is %srunning, is_streaming %s", __func__,
+      alarm_is_scheduled(btif_a2dp_source_cb.media_alarm) ? "" : "not ",
+      (btif_a2dp_source_cb.is_streaming) ? "true" : "false");
+
+  const bool send_ack = btif_a2dp_source_cb.is_streaming;
+
+  /* Stop the timer first */
+  btif_a2dp_source_cb.is_streaming = false;
+  alarm_free(btif_a2dp_source_cb.media_alarm);
+  btif_a2dp_source_cb.media_alarm = NULL;
+
+  UIPC_Close(UIPC_CH_ID_AV_AUDIO);
+
+  /*
+   * Try to send acknowldegment once the media stream is
+   * stopped. This will make sure that the A2DP HAL layer is
+   * un-blocked on wait for acknowledgment for the sent command.
+   * This resolves a corner cases AVDTP SUSPEND collision
+   * when the DUT and the remote device issue SUSPEND simultaneously
+   * and due to the processing of the SUSPEND request from the remote,
+   * the media path is torn down. If the A2DP HAL happens to wait
+   * for ACK for the initiated SUSPEND, it would never receive it casuing
+   * a block/wait. Due to this acknowledgement, the A2DP HAL is guranteed
+   * to get the ACK for any pending command in such cases.
+   */
+
+  if (send_ack) btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+
+  /* audio engine stopped, reset tx suspended flag */
+  btif_a2dp_source_cb.tx_flush = false;
+
+  /* Reset the media feeding state */
+  if (btif_a2dp_source_cb.encoder_interface != NULL)
+    btif_a2dp_source_cb.encoder_interface->feeding_reset();
+}
+
+static void btif_a2dp_source_alarm_cb(UNUSED_ATTR void* context) {
+  thread_post(btif_a2dp_source_cb.worker_thread,
+              btif_a2dp_source_audio_handle_timer, NULL);
+}
+
+static void btif_a2dp_source_audio_handle_timer(UNUSED_ATTR void* context) {
+  uint64_t timestamp_us = time_get_os_boottime_us();
+  log_tstamps_us("A2DP Source tx timer", timestamp_us);
+
+  if (alarm_is_scheduled(btif_a2dp_source_cb.media_alarm)) {
+    assert(btif_a2dp_source_cb.encoder_interface != NULL);
+    btif_a2dp_source_cb.encoder_interface->send_frames(timestamp_us);
+    bta_av_ci_src_data_ready(BTA_AV_CHNL_AUDIO);
+  } else {
+    APPL_TRACE_ERROR("ERROR Media task Scheduled after Suspend");
+  }
+}
+
+static uint32_t btif_a2dp_source_read_callback(uint8_t* p_buf, uint32_t len) {
+  uint16_t event;
+  uint32_t bytes_read = UIPC_Read(UIPC_CH_ID_AV_AUDIO, &event, p_buf, len);
+
+  if (bytes_read < len) {
+    LOG_WARN(LOG_TAG, "%s: UNDERFLOW: ONLY READ %d BYTES OUT OF %d", __func__,
+             bytes_read, len);
+    btif_a2dp_source_cb.stats.media_read_total_underflow_bytes +=
+        (len - bytes_read);
+    btif_a2dp_source_cb.stats.media_read_total_underflow_count++;
+    btif_a2dp_source_cb.stats.media_read_last_underflow_us =
+        time_get_os_boottime_us();
+  }
+
+  return bytes_read;
+}
+
+static bool btif_a2dp_source_enqueue_callback(BT_HDR* p_buf, size_t frames_n) {
+  uint64_t now_us = time_get_os_boottime_us();
+
+  /* Check if timer was stopped (media task stopped) */
+  if (!alarm_is_scheduled(btif_a2dp_source_cb.media_alarm)) {
+    osi_free(p_buf);
+    return false;
+  }
+
+  /* Check if the transmission queue has been flushed */
+  if (btif_a2dp_source_cb.tx_flush) {
+    LOG_VERBOSE(LOG_TAG, "%s: tx suspended, discarded frame", __func__);
+
+    btif_a2dp_source_cb.stats.tx_queue_total_flushed_messages +=
+        fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue);
+    btif_a2dp_source_cb.stats.tx_queue_last_flushed_us = now_us;
+    fixed_queue_flush(btif_a2dp_source_cb.tx_audio_queue, osi_free);
+
+    osi_free(p_buf);
+    return false;
+  }
+
+  // Check for TX queue overflow
+  // TODO: Using frames_n here is probably wrong: should be "+ 1" instead.
+  if (fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue) + frames_n >
+      MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ) {
+    LOG_WARN(LOG_TAG, "%s: TX queue buffer size now=%u adding=%u max=%d",
+             __func__,
+             (uint32_t)fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue),
+             (uint32_t)frames_n, MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ);
+    // Keep track of drop-outs
+    btif_a2dp_source_cb.stats.tx_queue_dropouts++;
+    btif_a2dp_source_cb.stats.tx_queue_last_dropouts_us = now_us;
+
+    // Flush all queued buffers
+    size_t drop_n = fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue);
+    if (btif_a2dp_source_cb.stats.tx_queue_max_dropped_messages < drop_n)
+      btif_a2dp_source_cb.stats.tx_queue_max_dropped_messages = drop_n;
+    while (fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue)) {
+      btif_a2dp_source_cb.stats.tx_queue_total_dropped_messages++;
+      osi_free(fixed_queue_try_dequeue(btif_a2dp_source_cb.tx_audio_queue));
+    }
+
+    // Request RSSI for log purposes if we had to flush buffers
+    bt_bdaddr_t peer_bda = btif_av_get_addr();
+    BTM_ReadRSSI(peer_bda.address, btm_read_rssi_cb);
+  }
+
+  /* Update the statistics */
+  btif_a2dp_source_cb.stats.tx_queue_total_frames += frames_n;
+  if (frames_n > btif_a2dp_source_cb.stats.tx_queue_max_frames_per_packet)
+    btif_a2dp_source_cb.stats.tx_queue_max_frames_per_packet = frames_n;
+  assert(btif_a2dp_source_cb.encoder_interface != NULL);
+  update_scheduling_stats(&btif_a2dp_source_cb.stats.tx_queue_enqueue_stats,
+                          now_us,
+                          btif_a2dp_source_cb.encoder_interval_ms * 1000);
+
+  fixed_queue_enqueue(btif_a2dp_source_cb.tx_audio_queue, p_buf);
+
+  return true;
+}
+
+static void btif_a2dp_source_audio_tx_flush_event(UNUSED_ATTR BT_HDR* p_msg) {
+  /* Flush all enqueued audio buffers (encoded) */
+  APPL_TRACE_DEBUG("%s", __func__);
+
+  if (btif_a2dp_source_cb.encoder_interface != NULL)
+    btif_a2dp_source_cb.encoder_interface->feeding_flush();
+
+  btif_a2dp_source_cb.stats.tx_queue_total_flushed_messages +=
+      fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue);
+  btif_a2dp_source_cb.stats.tx_queue_last_flushed_us =
+      time_get_os_boottime_us();
+  fixed_queue_flush(btif_a2dp_source_cb.tx_audio_queue, osi_free);
+
+  UIPC_Ioctl(UIPC_CH_ID_AV_AUDIO, UIPC_REQ_RX_FLUSH, NULL);
+}
+
+static bool btif_a2dp_source_audio_tx_flush_req(void) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+  p_buf->event = BTIF_MEDIA_AUDIO_TX_FLUSH;
+
+  /*
+   * Explicitly check whether the btif_a2dp_source_cb.cmd_msg_queue is not
+   * NULL to avoid a race condition during shutdown of the Bluetooth stack.
+   * This race condition is triggered when A2DP audio is streaming on
+   * shutdown:
+   * "btif_a2dp_source_on_stopped() -> btif_a2dp_source_audio_tx_flush_req()"
+   * is called to stop the particular audio stream, and this happens right
+   * after the "BTIF_AV_CLEANUP_REQ_EVT -> btif_a2dp_source_shutdown()"
+   * processing during the shutdown of the Bluetooth stack.
+   */
+  if (btif_a2dp_source_cb.cmd_msg_queue != NULL)
+    fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf);
+
+  return true;
+}
+
+BT_HDR* btif_a2dp_source_audio_readbuf(void) {
+  uint64_t now_us = time_get_os_boottime_us();
+  BT_HDR* p_buf =
+      (BT_HDR*)fixed_queue_try_dequeue(btif_a2dp_source_cb.tx_audio_queue);
+
+  btif_a2dp_source_cb.stats.tx_queue_total_readbuf_calls++;
+  btif_a2dp_source_cb.stats.tx_queue_last_readbuf_us = now_us;
+  if (p_buf != NULL) {
+    // Update the statistics
+    update_scheduling_stats(&btif_a2dp_source_cb.stats.tx_queue_dequeue_stats,
+                            now_us,
+                            btif_a2dp_source_cb.encoder_interval_ms * 1000);
+  }
+
+  return p_buf;
+}
+
+static void log_tstamps_us(const char* comment, uint64_t timestamp_us) {
+  static uint64_t prev_us = 0;
+  APPL_TRACE_DEBUG("[%s] ts %08llu, diff : %08llu, queue sz %d", comment,
+                   timestamp_us, timestamp_us - prev_us,
+                   fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue));
+  prev_us = timestamp_us;
+}
+
+static void update_scheduling_stats(scheduling_stats_t* stats, uint64_t now_us,
+                                    uint64_t expected_delta) {
+  uint64_t last_us = stats->last_update_us;
+
+  stats->total_updates++;
+  stats->last_update_us = now_us;
+
+  if (last_us == 0) return;  // First update: expected delta doesn't apply
+
+  uint64_t deadline_us = last_us + expected_delta;
+  if (deadline_us < now_us) {
+    // Overdue scheduling
+    uint64_t delta_us = now_us - deadline_us;
+    // Ignore extreme outliers
+    if (delta_us < 10 * expected_delta) {
+      if (stats->max_overdue_scheduling_delta_us < delta_us)
+        stats->max_overdue_scheduling_delta_us = delta_us;
+      stats->total_overdue_scheduling_delta_us += delta_us;
+      stats->overdue_scheduling_count++;
+      stats->total_scheduling_time_us += now_us - last_us;
+    }
+  } else if (deadline_us > now_us) {
+    // Premature scheduling
+    uint64_t delta_us = deadline_us - now_us;
+    // Ignore extreme outliers
+    if (delta_us < 10 * expected_delta) {
+      if (stats->max_premature_scheduling_delta_us < delta_us)
+        stats->max_premature_scheduling_delta_us = delta_us;
+      stats->total_premature_scheduling_delta_us += delta_us;
+      stats->premature_scheduling_count++;
+      stats->total_scheduling_time_us += now_us - last_us;
+    }
+  } else {
+    // On-time scheduling
+    stats->exact_scheduling_count++;
+    stats->total_scheduling_time_us += now_us - last_us;
+  }
+}
+
+void btif_a2dp_source_debug_dump(int fd) {
+  uint64_t now_us = time_get_os_boottime_us();
+  btif_media_stats_t* stats = &btif_a2dp_source_cb.stats;
+  scheduling_stats_t* enqueue_stats = &stats->tx_queue_enqueue_stats;
+  scheduling_stats_t* dequeue_stats = &stats->tx_queue_dequeue_stats;
+  size_t ave_size;
+  uint64_t ave_time_us;
+
+  dprintf(fd, "\nA2DP State:\n");
+  dprintf(fd, "  TxQueue:\n");
+
+  dprintf(fd,
+          "  Counts (enqueue/dequeue/readbuf)                        : %zu / "
+          "%zu / %zu\n",
+          enqueue_stats->total_updates, dequeue_stats->total_updates,
+          stats->tx_queue_total_readbuf_calls);
+
+  dprintf(
+      fd,
+      "  Last update time ago in ms (enqueue/dequeue/readbuf)    : %llu / %llu "
+      "/ %llu\n",
+      (enqueue_stats->last_update_us > 0)
+          ? (unsigned long long)(now_us - enqueue_stats->last_update_us) / 1000
+          : 0,
+      (dequeue_stats->last_update_us > 0)
+          ? (unsigned long long)(now_us - dequeue_stats->last_update_us) / 1000
+          : 0,
+      (stats->tx_queue_last_readbuf_us > 0)
+          ? (unsigned long long)(now_us - stats->tx_queue_last_readbuf_us) /
+                1000
+          : 0);
+
+  ave_size = 0;
+  if (enqueue_stats->total_updates != 0)
+    ave_size = stats->tx_queue_total_frames / enqueue_stats->total_updates;
+  dprintf(fd,
+          "  Frames per packet (total/max/ave)                       : %zu / "
+          "%zu / %zu\n",
+          stats->tx_queue_total_frames, stats->tx_queue_max_frames_per_packet,
+          ave_size);
+
+  dprintf(fd,
+          "  Counts (flushed/dropped/dropouts)                       : %zu / "
+          "%zu / %zu\n",
+          stats->tx_queue_total_flushed_messages,
+          stats->tx_queue_total_dropped_messages, stats->tx_queue_dropouts);
+
+  dprintf(fd,
+          "  Counts (max dropped)                                    : %zu\n",
+          stats->tx_queue_max_dropped_messages);
+
+  dprintf(
+      fd,
+      "  Last update time ago in ms (flushed/dropped)            : %llu / "
+      "%llu\n",
+      (stats->tx_queue_last_flushed_us > 0)
+          ? (unsigned long long)(now_us - stats->tx_queue_last_flushed_us) /
+                1000
+          : 0,
+      (stats->tx_queue_last_dropouts_us > 0)
+          ? (unsigned long long)(now_us - stats->tx_queue_last_dropouts_us) /
+                1000
+          : 0);
+
+  dprintf(fd,
+          "  Counts (underflow)                                      : %zu\n",
+          stats->media_read_total_underflow_count);
+
+  dprintf(fd,
+          "  Bytes (underflow)                                       : %zu\n",
+          stats->media_read_total_underflow_bytes);
+
+  dprintf(
+      fd, "  Last update time ago in ms (underflow)                  : %llu\n",
+      (stats->media_read_last_underflow_us > 0)
+          ? (unsigned long long)(now_us - stats->media_read_last_underflow_us) /
+                1000
+          : 0);
+
+  //
+  // TxQueue enqueue stats
+  //
+  dprintf(
+      fd,
+      "  Enqueue deviation counts (overdue/premature)            : %zu / %zu\n",
+      enqueue_stats->overdue_scheduling_count,
+      enqueue_stats->premature_scheduling_count);
+
+  ave_time_us = 0;
+  if (enqueue_stats->overdue_scheduling_count != 0) {
+    ave_time_us = enqueue_stats->total_overdue_scheduling_delta_us /
+                  enqueue_stats->overdue_scheduling_count;
+  }
+  dprintf(
+      fd,
+      "  Enqueue overdue scheduling time in ms (total/max/ave)   : %llu / %llu "
+      "/ %llu\n",
+      (unsigned long long)enqueue_stats->total_overdue_scheduling_delta_us /
+          1000,
+      (unsigned long long)enqueue_stats->max_overdue_scheduling_delta_us / 1000,
+      (unsigned long long)ave_time_us / 1000);
+
+  ave_time_us = 0;
+  if (enqueue_stats->premature_scheduling_count != 0) {
+    ave_time_us = enqueue_stats->total_premature_scheduling_delta_us /
+                  enqueue_stats->premature_scheduling_count;
+  }
+  dprintf(
+      fd,
+      "  Enqueue premature scheduling time in ms (total/max/ave) : %llu / %llu "
+      "/ %llu\n",
+      (unsigned long long)enqueue_stats->total_premature_scheduling_delta_us /
+          1000,
+      (unsigned long long)enqueue_stats->max_premature_scheduling_delta_us /
+          1000,
+      (unsigned long long)ave_time_us / 1000);
+
+  //
+  // TxQueue dequeue stats
+  //
+  dprintf(
+      fd,
+      "  Dequeue deviation counts (overdue/premature)            : %zu / %zu\n",
+      dequeue_stats->overdue_scheduling_count,
+      dequeue_stats->premature_scheduling_count);
+
+  ave_time_us = 0;
+  if (dequeue_stats->overdue_scheduling_count != 0) {
+    ave_time_us = dequeue_stats->total_overdue_scheduling_delta_us /
+                  dequeue_stats->overdue_scheduling_count;
+  }
+  dprintf(
+      fd,
+      "  Dequeue overdue scheduling time in ms (total/max/ave)   : %llu / %llu "
+      "/ %llu\n",
+      (unsigned long long)dequeue_stats->total_overdue_scheduling_delta_us /
+          1000,
+      (unsigned long long)dequeue_stats->max_overdue_scheduling_delta_us / 1000,
+      (unsigned long long)ave_time_us / 1000);
+
+  ave_time_us = 0;
+  if (dequeue_stats->premature_scheduling_count != 0) {
+    ave_time_us = dequeue_stats->total_premature_scheduling_delta_us /
+                  dequeue_stats->premature_scheduling_count;
+  }
+  dprintf(
+      fd,
+      "  Dequeue premature scheduling time in ms (total/max/ave) : %llu / %llu "
+      "/ %llu\n",
+      (unsigned long long)dequeue_stats->total_premature_scheduling_delta_us /
+          1000,
+      (unsigned long long)dequeue_stats->max_premature_scheduling_delta_us /
+          1000,
+      (unsigned long long)ave_time_us / 1000);
+
+  //
+  // Codec-specific stats
+  //
+  if (btif_a2dp_source_cb.encoder_interface != NULL)
+    btif_a2dp_source_cb.encoder_interface->debug_codec_dump(fd);
+}
+
+void btif_a2dp_source_update_metrics(void) {
+  uint64_t now_us = time_get_os_boottime_us();
+  btif_media_stats_t* stats = &btif_a2dp_source_cb.stats;
+  scheduling_stats_t* dequeue_stats = &stats->tx_queue_dequeue_stats;
+  int32_t media_timer_min_ms = 0;
+  int32_t media_timer_max_ms = 0;
+  int32_t media_timer_avg_ms = 0;
+  int32_t buffer_overruns_max_count = 0;
+  int32_t buffer_overruns_total = 0;
+  float buffer_underruns_average = 0.0;
+  int32_t buffer_underruns_count = 0;
+
+  int64_t session_duration_sec =
+      (now_us - stats->session_start_us) / (1000 * 1000);
+
+  /* NOTE: Disconnect reason is unused */
+  const char* disconnect_reason = NULL;
+  uint32_t device_class = BTM_COD_MAJOR_AUDIO;
+
+  if (dequeue_stats->total_updates > 1) {
+    media_timer_min_ms =
+        btif_a2dp_source_cb.encoder_interval_ms -
+        (dequeue_stats->max_premature_scheduling_delta_us / 1000);
+    media_timer_max_ms =
+        btif_a2dp_source_cb.encoder_interval_ms +
+        (dequeue_stats->max_overdue_scheduling_delta_us / 1000);
+
+    uint64_t total_scheduling_count =
+        dequeue_stats->overdue_scheduling_count +
+        dequeue_stats->premature_scheduling_count +
+        dequeue_stats->exact_scheduling_count;
+    if (total_scheduling_count > 0) {
+      media_timer_avg_ms = dequeue_stats->total_scheduling_time_us /
+                           (1000 * total_scheduling_count);
+    }
+
+    buffer_overruns_max_count = stats->tx_queue_max_dropped_messages;
+    buffer_overruns_total = stats->tx_queue_total_dropped_messages;
+    buffer_underruns_count = stats->media_read_total_underflow_count;
+    if (buffer_underruns_count > 0) {
+      buffer_underruns_average =
+          stats->media_read_total_underflow_bytes / buffer_underruns_count;
+    }
+  }
+
+  metrics_a2dp_session(
+      session_duration_sec, disconnect_reason, device_class, media_timer_min_ms,
+      media_timer_max_ms, media_timer_avg_ms, buffer_overruns_max_count,
+      buffer_overruns_total, buffer_underruns_average, buffer_underruns_count);
+}
+
+static void btm_read_rssi_cb(void* data) {
+  if (data == nullptr) {
+    LOG_ERROR(LOG_TAG, "%s RSSI request timed out", __func__);
+    return;
+  }
+
+  tBTM_RSSI_RESULTS* result = (tBTM_RSSI_RESULTS*)data;
+  if (result->status != BTM_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s unable to read remote RSSI (status %d)", __func__,
+              result->status);
+    return;
+  }
+
+  char temp_buffer[20] = {0};
+  LOG_WARN(LOG_TAG, "%s device: %s, rssi: %d", __func__,
+           bdaddr_to_string((bt_bdaddr_t*)result->rem_bda, temp_buffer,
+                            sizeof(temp_buffer)),
+           result->rssi);
+}
diff --git a/bt/btif/src/btif_av.cc b/bt/btif/src/btif_av.cc
new file mode 100644
index 0000000..0541eb9
--- /dev/null
+++ b/bt/btif/src/btif_av.cc
@@ -0,0 +1,1658 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-2016 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.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "btif_av"
+
+#include "btif_av.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_av.h>
+#include <hardware/bt_rc.h>
+
+#include "audio_a2dp_hw.h"
+#include "bt_common.h"
+#include "bt_utils.h"
+#include "bta_api.h"
+#include "btif_a2dp.h"
+#include "btif_a2dp_control.h"
+#include "btif_a2dp_sink.h"
+#include "btif_av_co.h"
+#include "btif_profile_queue.h"
+#include "btif_util.h"
+#include "btu.h"
+#include "osi/include/allocator.h"
+#include "osi/include/osi.h"
+
+/*****************************************************************************
+ *  Constants & Macros
+ *****************************************************************************/
+#define BTIF_AV_SERVICE_NAME "Advanced Audio"
+#define BTIF_AVK_SERVICE_NAME "Advanced Audio Sink"
+
+#define BTIF_TIMEOUT_AV_OPEN_ON_RC_MS (2 * 1000)
+
+typedef enum {
+  BTIF_AV_STATE_IDLE = 0x0,
+  BTIF_AV_STATE_OPENING,
+  BTIF_AV_STATE_OPENED,
+  BTIF_AV_STATE_STARTED,
+  BTIF_AV_STATE_CLOSING
+} btif_av_state_t;
+
+/* Should not need dedicated suspend state as actual actions are no
+   different than open state. Suspend flags are needed however to prevent
+   media task from trying to restart stream during remote suspend or while
+   we are in the process of a local suspend */
+
+#define BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING 0x1
+#define BTIF_AV_FLAG_REMOTE_SUSPEND 0x2
+#define BTIF_AV_FLAG_PENDING_START 0x4
+#define BTIF_AV_FLAG_PENDING_STOP 0x8
+
+/*****************************************************************************
+ *  Local type definitions
+ *****************************************************************************/
+
+typedef struct {
+  tBTA_AV_HNDL bta_handle;
+  bt_bdaddr_t peer_bda;
+  btif_sm_handle_t sm_handle;
+  uint8_t flags;
+  tBTA_AV_EDR edr;
+  uint8_t peer_sep; /* sep type of peer device */
+} btif_av_cb_t;
+
+typedef struct {
+  bt_bdaddr_t* target_bda;
+  uint16_t uuid;
+} btif_av_connect_req_t;
+
+typedef struct {
+  int sample_rate;
+  int channel_count;
+  bt_bdaddr_t peer_bd;
+} btif_av_sink_config_req_t;
+
+/*****************************************************************************
+ *  Static variables
+ *****************************************************************************/
+static btav_callbacks_t* bt_av_src_callbacks = NULL;
+static btav_callbacks_t* bt_av_sink_callbacks = NULL;
+static btif_av_cb_t btif_av_cb = {0, {{0}}, 0, 0, 0, 0};
+static alarm_t* av_open_on_rc_timer = NULL;
+
+/* both interface and media task needs to be ready to alloc incoming request */
+#define CHECK_BTAV_INIT()                                                    \
+  do {                                                                       \
+    if (((bt_av_src_callbacks == NULL) && (bt_av_sink_callbacks == NULL)) || \
+        (btif_av_cb.sm_handle == NULL)) {                                    \
+      BTIF_TRACE_WARNING("%s: BTAV not initialized", __func__);              \
+      return BT_STATUS_NOT_READY;                                            \
+    } else {                                                                 \
+      BTIF_TRACE_EVENT("%s", __func__);                                      \
+    }                                                                        \
+  } while (0)
+
+/* Helper macro to avoid code duplication in the state machine handlers */
+#define CHECK_RC_EVENT(e, d)       \
+  case BTA_AV_RC_OPEN_EVT:         \
+  case BTA_AV_RC_BROWSE_OPEN_EVT:  \
+  case BTA_AV_RC_CLOSE_EVT:        \
+  case BTA_AV_RC_BROWSE_CLOSE_EVT: \
+  case BTA_AV_REMOTE_CMD_EVT:      \
+  case BTA_AV_VENDOR_CMD_EVT:      \
+  case BTA_AV_META_MSG_EVT:        \
+  case BTA_AV_RC_FEAT_EVT:         \
+  case BTA_AV_REMOTE_RSP_EVT: {    \
+    btif_rc_handler(e, d);         \
+  } break;
+
+static bool btif_av_state_idle_handler(btif_sm_event_t event, void* data);
+static bool btif_av_state_opening_handler(btif_sm_event_t event, void* data);
+static bool btif_av_state_opened_handler(btif_sm_event_t event, void* data);
+static bool btif_av_state_started_handler(btif_sm_event_t event, void* data);
+static bool btif_av_state_closing_handler(btif_sm_event_t event, void* data);
+
+static const btif_sm_handler_t btif_av_state_handlers[] = {
+    btif_av_state_idle_handler, btif_av_state_opening_handler,
+    btif_av_state_opened_handler, btif_av_state_started_handler,
+    btif_av_state_closing_handler};
+
+static void btif_av_event_free_data(btif_sm_event_t event, void* p_data);
+
+/*************************************************************************
+ * Extern functions
+ ************************************************************************/
+extern void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV* p_data);
+extern bool btif_rc_get_connected_peer(BD_ADDR peer_addr);
+extern uint8_t btif_rc_get_connected_peer_handle(BD_ADDR peer_addr);
+extern void btif_rc_check_handle_pending_play(BD_ADDR peer_addr,
+                                              bool bSendToApp);
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/*****************************************************************************
+ * Local helper functions
+ *****************************************************************************/
+
+const char* dump_av_sm_state_name(btif_av_state_t state) {
+  switch (state) {
+    CASE_RETURN_STR(BTIF_AV_STATE_IDLE)
+    CASE_RETURN_STR(BTIF_AV_STATE_OPENING)
+    CASE_RETURN_STR(BTIF_AV_STATE_OPENED)
+    CASE_RETURN_STR(BTIF_AV_STATE_STARTED)
+    CASE_RETURN_STR(BTIF_AV_STATE_CLOSING)
+    default:
+      return "UNKNOWN_STATE";
+  }
+}
+
+const char* dump_av_sm_event_name(btif_av_sm_event_t event) {
+  switch ((int)event) {
+    CASE_RETURN_STR(BTA_AV_ENABLE_EVT)
+    CASE_RETURN_STR(BTA_AV_REGISTER_EVT)
+    CASE_RETURN_STR(BTA_AV_OPEN_EVT)
+    CASE_RETURN_STR(BTA_AV_CLOSE_EVT)
+    CASE_RETURN_STR(BTA_AV_START_EVT)
+    CASE_RETURN_STR(BTA_AV_STOP_EVT)
+    CASE_RETURN_STR(BTA_AV_PROTECT_REQ_EVT)
+    CASE_RETURN_STR(BTA_AV_PROTECT_RSP_EVT)
+    CASE_RETURN_STR(BTA_AV_RC_OPEN_EVT)
+    CASE_RETURN_STR(BTA_AV_RC_CLOSE_EVT)
+    CASE_RETURN_STR(BTA_AV_RC_BROWSE_OPEN_EVT)
+    CASE_RETURN_STR(BTA_AV_RC_BROWSE_CLOSE_EVT)
+    CASE_RETURN_STR(BTA_AV_REMOTE_CMD_EVT)
+    CASE_RETURN_STR(BTA_AV_REMOTE_RSP_EVT)
+    CASE_RETURN_STR(BTA_AV_VENDOR_CMD_EVT)
+    CASE_RETURN_STR(BTA_AV_VENDOR_RSP_EVT)
+    CASE_RETURN_STR(BTA_AV_RECONFIG_EVT)
+    CASE_RETURN_STR(BTA_AV_SUSPEND_EVT)
+    CASE_RETURN_STR(BTA_AV_PENDING_EVT)
+    CASE_RETURN_STR(BTA_AV_META_MSG_EVT)
+    CASE_RETURN_STR(BTA_AV_REJECT_EVT)
+    CASE_RETURN_STR(BTA_AV_RC_FEAT_EVT)
+    CASE_RETURN_STR(BTA_AV_OFFLOAD_START_RSP_EVT)
+    CASE_RETURN_STR(BTIF_SM_ENTER_EVT)
+    CASE_RETURN_STR(BTIF_SM_EXIT_EVT)
+    CASE_RETURN_STR(BTIF_AV_CONNECT_REQ_EVT)
+    CASE_RETURN_STR(BTIF_AV_DISCONNECT_REQ_EVT)
+    CASE_RETURN_STR(BTIF_AV_START_STREAM_REQ_EVT)
+    CASE_RETURN_STR(BTIF_AV_STOP_STREAM_REQ_EVT)
+    CASE_RETURN_STR(BTIF_AV_SUSPEND_STREAM_REQ_EVT)
+    CASE_RETURN_STR(BTIF_AV_SINK_CONFIG_REQ_EVT)
+    CASE_RETURN_STR(BTIF_AV_OFFLOAD_START_REQ_EVT)
+    default:
+      return "UNKNOWN_EVENT";
+  }
+}
+
+/****************************************************************************
+ *  Local helper functions
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function         btif_initiate_av_open_timer_timeout
+ *
+ * Description      Timer to trigger AV open if the remote headset establishes
+ *                  RC connection w/o AV connection. The timer is needed to IOP
+ *                  with headsets that do establish AV after RC connection.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_initiate_av_open_timer_timeout(UNUSED_ATTR void* data) {
+  BD_ADDR peer_addr;
+  btif_av_connect_req_t connect_req;
+
+  /* is there at least one RC connection - There should be */
+  if (btif_rc_get_connected_peer(peer_addr)) {
+    BTIF_TRACE_DEBUG("%s Issuing connect to the remote RC peer", __func__);
+    /* In case of AVRCP connection request, we will initiate SRC connection */
+    connect_req.target_bda = (bt_bdaddr_t*)&peer_addr;
+    if (bt_av_sink_callbacks != NULL)
+      connect_req.uuid = UUID_SERVCLASS_AUDIO_SINK;
+    else if (bt_av_src_callbacks != NULL)
+      connect_req.uuid = UUID_SERVCLASS_AUDIO_SOURCE;
+    btif_dispatch_sm_event(BTIF_AV_CONNECT_REQ_EVT, (char*)&connect_req,
+                           sizeof(connect_req));
+  } else {
+    BTIF_TRACE_ERROR("%s No connected RC peers", __func__);
+  }
+}
+
+/*****************************************************************************
+ *  Static functions
+ *****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         btif_report_connection_state
+ *
+ * Description      Updates the components via the callbacks about the
+ *                  connection state of a2dp connection.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+static void btif_report_connection_state(btav_connection_state_t state,
+                                         bt_bdaddr_t* bd_addr) {
+  if (bt_av_sink_callbacks != NULL) {
+    HAL_CBACK(bt_av_sink_callbacks, connection_state_cb, state, bd_addr);
+  } else if (bt_av_src_callbacks != NULL) {
+    HAL_CBACK(bt_av_src_callbacks, connection_state_cb, state, bd_addr);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_report_audio_state
+ *
+ * Description      Updates the components via the callbacks about the audio
+ *                  state of a2dp connection. The state is updated when either
+ *                  the remote ends starts streaming (started state) or whenever
+ *                  it transitions out of started state (to opened or streaming)
+ *                  state.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+static void btif_report_audio_state(btav_audio_state_t state,
+                                    bt_bdaddr_t* bd_addr) {
+  if (bt_av_sink_callbacks != NULL) {
+    HAL_CBACK(bt_av_sink_callbacks, audio_state_cb, state, bd_addr);
+  } else if (bt_av_src_callbacks != NULL) {
+    HAL_CBACK(bt_av_src_callbacks, audio_state_cb, state, bd_addr);
+  }
+}
+
+/*****************************************************************************
+ *
+ * Function     btif_av_state_idle_handler
+ *
+ * Description  State managing disconnected AV link
+ *
+ * Returns      true if event was processed, false otherwise
+ *
+ ******************************************************************************/
+
+static bool btif_av_state_idle_handler(btif_sm_event_t event, void* p_data) {
+  BTIF_TRACE_DEBUG("%s event:%s flags %x", __func__,
+                   dump_av_sm_event_name((btif_av_sm_event_t)event),
+                   btif_av_cb.flags);
+
+  switch (event) {
+    case BTIF_SM_ENTER_EVT:
+      /* clear the peer_bda */
+      memset(&btif_av_cb.peer_bda, 0, sizeof(bt_bdaddr_t));
+      btif_av_cb.flags = 0;
+      btif_av_cb.edr = 0;
+      bta_av_co_init();
+      btif_a2dp_on_idle();
+      break;
+
+    case BTIF_SM_EXIT_EVT:
+      break;
+
+    case BTA_AV_ENABLE_EVT:
+      break;
+
+    case BTA_AV_REGISTER_EVT:
+      btif_av_cb.bta_handle = ((tBTA_AV*)p_data)->registr.hndl;
+      break;
+
+    case BTA_AV_PENDING_EVT:
+    case BTIF_AV_CONNECT_REQ_EVT: {
+      if (event == BTIF_AV_CONNECT_REQ_EVT) {
+        memcpy(&btif_av_cb.peer_bda,
+               ((btif_av_connect_req_t*)p_data)->target_bda,
+               sizeof(bt_bdaddr_t));
+        BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle, true,
+                   BTA_SEC_AUTHENTICATE,
+                   ((btif_av_connect_req_t*)p_data)->uuid);
+      } else if (event == BTA_AV_PENDING_EVT) {
+        bdcpy(btif_av_cb.peer_bda.address, ((tBTA_AV*)p_data)->pend.bd_addr);
+        if (bt_av_src_callbacks != NULL) {
+          BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle, true,
+                     BTA_SEC_AUTHENTICATE, UUID_SERVCLASS_AUDIO_SOURCE);
+        }
+        if (bt_av_sink_callbacks != NULL) {
+          BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle, true,
+                     BTA_SEC_AUTHENTICATE, UUID_SERVCLASS_AUDIO_SINK);
+        }
+      }
+      btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENING);
+    } break;
+
+    case BTA_AV_RC_OPEN_EVT:
+      /* IOP_FIX: Jabra 620 only does RC open without AV open whenever it
+       * connects. So
+       * as per the AV WP, an AVRC connection cannot exist without an AV
+       * connection. Therefore,
+       * we initiate an AV connection if an RC_OPEN_EVT is received when we are
+       * in AV_CLOSED state.
+       * We initiate the AV connection after a small 3s timeout to avoid any
+       * collisions from the
+       * headsets, as some headsets initiate the AVRC connection first and then
+       * immediately initiate the AV connection
+       *
+       * TODO: We may need to do this only on an AVRCP Play. FixMe
+       */
+
+      BTIF_TRACE_DEBUG("BTA_AV_RC_OPEN_EVT received w/o AV");
+      alarm_set_on_queue(av_open_on_rc_timer, BTIF_TIMEOUT_AV_OPEN_ON_RC_MS,
+                         btif_initiate_av_open_timer_timeout, NULL,
+                         btu_general_alarm_queue);
+      btif_rc_handler(event, (tBTA_AV*)p_data);
+      break;
+
+    case BTA_AV_RC_BROWSE_OPEN_EVT:
+      BTIF_TRACE_DEBUG("BTA_AV_RC_BROWSE_OPEN_EVT received");
+      btif_rc_handler(event, (tBTA_AV*)p_data);
+      break;
+
+    /*
+     * In case Signalling channel is not down
+     * and remote started Streaming Procedure
+     * we have to handle config and open event in
+     * idle_state. We hit these scenarios while running
+     * PTS test case for AVRCP Controller
+     */
+    case BTIF_AV_SINK_CONFIG_REQ_EVT: {
+      btif_av_sink_config_req_t req;
+      // copy to avoid alignment problems
+      memcpy(&req, p_data, sizeof(req));
+
+      BTIF_TRACE_WARNING("BTIF_AV_SINK_CONFIG_REQ_EVT %d %d", req.sample_rate,
+                         req.channel_count);
+      if (bt_av_sink_callbacks != NULL) {
+        HAL_CBACK(bt_av_sink_callbacks, audio_config_cb, &(req.peer_bd),
+                  req.sample_rate, req.channel_count);
+      }
+    } break;
+
+    case BTA_AV_OPEN_EVT: {
+      tBTA_AV* p_bta_data = (tBTA_AV*)p_data;
+      btav_connection_state_t state;
+      btif_sm_state_t av_state;
+      BTIF_TRACE_DEBUG("status:%d, edr 0x%x", p_bta_data->open.status,
+                       p_bta_data->open.edr);
+
+      if (p_bta_data->open.status == BTA_AV_SUCCESS) {
+        state = BTAV_CONNECTION_STATE_CONNECTED;
+        av_state = BTIF_AV_STATE_OPENED;
+        btif_av_cb.edr = p_bta_data->open.edr;
+
+        btif_av_cb.peer_sep = p_bta_data->open.sep;
+      } else {
+        BTIF_TRACE_WARNING("BTA_AV_OPEN_EVT::FAILED status: %d",
+                           p_bta_data->open.status);
+        state = BTAV_CONNECTION_STATE_DISCONNECTED;
+        av_state = BTIF_AV_STATE_IDLE;
+      }
+
+      /* inform the application of the event */
+      btif_report_connection_state(state, &(btif_av_cb.peer_bda));
+      /* change state to open/idle based on the status */
+      btif_sm_change_state(btif_av_cb.sm_handle, av_state);
+      if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
+        /* if queued PLAY command,  send it now */
+        btif_rc_check_handle_pending_play(
+            p_bta_data->open.bd_addr,
+            (p_bta_data->open.status == BTA_AV_SUCCESS));
+      } else if ((btif_av_cb.peer_sep == AVDT_TSEP_SRC) &&
+                 (p_bta_data->open.status == BTA_AV_SUCCESS)) {
+        /* Bring up AVRCP connection too */
+        BTA_AvOpenRc(btif_av_cb.bta_handle);
+      }
+      btif_queue_advance();
+    } break;
+
+    case BTA_AV_REMOTE_CMD_EVT:
+    case BTA_AV_VENDOR_CMD_EVT:
+    case BTA_AV_META_MSG_EVT:
+    case BTA_AV_RC_FEAT_EVT:
+    case BTA_AV_REMOTE_RSP_EVT:
+      btif_rc_handler(event, (tBTA_AV*)p_data);
+      break;
+
+    case BTA_AV_RC_CLOSE_EVT:
+      BTIF_TRACE_DEBUG("BTA_AV_RC_CLOSE_EVT: Stopping AV timer.");
+      alarm_cancel(av_open_on_rc_timer);
+      btif_rc_handler(event, (tBTA_AV*)p_data);
+      break;
+
+    case BTIF_AV_OFFLOAD_START_REQ_EVT:
+      BTIF_TRACE_ERROR(
+          "BTIF_AV_OFFLOAD_START_REQ_EVT: Stream not Started IDLE");
+      btif_a2dp_on_offload_started(BTA_AV_FAIL);
+      break;
+
+    default:
+      BTIF_TRACE_WARNING("%s : unhandled event:%s", __func__,
+                         dump_av_sm_event_name((btif_av_sm_event_t)event));
+      return false;
+  }
+
+  return true;
+}
+/*****************************************************************************
+ *
+ * Function        btif_av_state_opening_handler
+ *
+ * Description     Intermediate state managing events during establishment
+ *                 of avdtp channel
+ *
+ * Returns         true if event was processed, false otherwise
+ *
+ ******************************************************************************/
+
+static bool btif_av_state_opening_handler(btif_sm_event_t event, void* p_data) {
+  BTIF_TRACE_DEBUG("%s event:%s flags %x", __func__,
+                   dump_av_sm_event_name((btif_av_sm_event_t)event),
+                   btif_av_cb.flags);
+
+  switch (event) {
+    case BTIF_SM_ENTER_EVT:
+      /* inform the application that we are entering connecting state */
+      btif_report_connection_state(BTAV_CONNECTION_STATE_CONNECTING,
+                                   &(btif_av_cb.peer_bda));
+      break;
+
+    case BTIF_SM_EXIT_EVT:
+      break;
+
+    case BTA_AV_REJECT_EVT:
+      BTIF_TRACE_DEBUG(" Received  BTA_AV_REJECT_EVT ");
+      btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+                                   &(btif_av_cb.peer_bda));
+      btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+      break;
+
+    case BTA_AV_OPEN_EVT: {
+      tBTA_AV* p_bta_data = (tBTA_AV*)p_data;
+      btav_connection_state_t state;
+      btif_sm_state_t av_state;
+      BTIF_TRACE_DEBUG("status:%d, edr 0x%x", p_bta_data->open.status,
+                       p_bta_data->open.edr);
+
+      if (p_bta_data->open.status == BTA_AV_SUCCESS) {
+        state = BTAV_CONNECTION_STATE_CONNECTED;
+        av_state = BTIF_AV_STATE_OPENED;
+        btif_av_cb.edr = p_bta_data->open.edr;
+
+        btif_av_cb.peer_sep = p_bta_data->open.sep;
+      } else {
+        BTIF_TRACE_WARNING("BTA_AV_OPEN_EVT::FAILED status: %d",
+                           p_bta_data->open.status);
+        BD_ADDR peer_addr;
+        uint8_t peer_handle = BTRC_HANDLE_NONE;
+        if ((btif_rc_get_connected_peer(peer_addr)) &&
+            (!bdcmp(btif_av_cb.peer_bda.address, peer_addr))) {
+          /*
+           * Disconnect AVRCP connection, if
+           * A2DP conneciton failed, for any reason
+           */
+          BTIF_TRACE_WARNING(" Disconnecting AVRCP ");
+          peer_handle = btif_rc_get_connected_peer_handle(peer_addr);
+          if (peer_handle != BTRC_HANDLE_NONE) {
+            BTA_AvCloseRc(peer_handle);
+          }
+        }
+        state = BTAV_CONNECTION_STATE_DISCONNECTED;
+        av_state = BTIF_AV_STATE_IDLE;
+      }
+
+      /* inform the application of the event */
+      btif_report_connection_state(state, &(btif_av_cb.peer_bda));
+      /* change state to open/idle based on the status */
+      btif_sm_change_state(btif_av_cb.sm_handle, av_state);
+      if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
+        /* if queued PLAY command,  send it now */
+        btif_rc_check_handle_pending_play(
+            p_bta_data->open.bd_addr,
+            (p_bta_data->open.status == BTA_AV_SUCCESS));
+      } else if ((btif_av_cb.peer_sep == AVDT_TSEP_SRC) &&
+                 (p_bta_data->open.status == BTA_AV_SUCCESS)) {
+        /* Bring up AVRCP connection too */
+        BTA_AvOpenRc(btif_av_cb.bta_handle);
+      }
+      btif_queue_advance();
+    } break;
+
+    case BTIF_AV_SINK_CONFIG_REQ_EVT: {
+      btif_av_sink_config_req_t req;
+      // copy to avoid alignment problems
+      memcpy(&req, p_data, sizeof(req));
+
+      BTIF_TRACE_WARNING("BTIF_AV_SINK_CONFIG_REQ_EVT %d %d", req.sample_rate,
+                         req.channel_count);
+      if (btif_av_cb.peer_sep == AVDT_TSEP_SRC &&
+          bt_av_sink_callbacks != NULL) {
+        HAL_CBACK(bt_av_sink_callbacks, audio_config_cb, &(btif_av_cb.peer_bda),
+                  req.sample_rate, req.channel_count);
+      }
+    } break;
+
+    case BTIF_AV_CONNECT_REQ_EVT:
+      // Check for device, if same device which moved to opening then ignore
+      // callback
+      if (memcmp(((btif_av_connect_req_t *)p_data)->target_bda, &(btif_av_cb.peer_bda),
+                 sizeof(btif_av_cb.peer_bda)) == 0) {
+        BTIF_TRACE_DEBUG(
+            "%s: Same device moved to Opening state,ignore Connect Req",
+            __func__);
+        btif_queue_advance();
+        break;
+      } else {
+        BTIF_TRACE_DEBUG("%s: Moved from idle by Incoming Connection request",
+                         __func__);
+        btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+                                     ((btif_av_connect_req_t *)p_data)->target_bda);
+        btif_queue_advance();
+        break;
+      }
+
+    case BTA_AV_PENDING_EVT:
+      // Check for device, if same device which moved to opening then ignore
+      // callback
+      if (memcmp(((tBTA_AV*)p_data)->pend.bd_addr, &(btif_av_cb.peer_bda),
+                 sizeof(btif_av_cb.peer_bda)) == 0) {
+        BTIF_TRACE_DEBUG(
+            "%s: Same device moved to Opening state,ignore Pending Req",
+            __func__);
+        break;
+      } else {
+        BTIF_TRACE_DEBUG("%s: Moved from idle by outgoing Connection request",
+                         __func__);
+        BTA_AvDisconnect(((tBTA_AV*)p_data)->pend.bd_addr);
+        break;
+      }
+
+    case BTIF_AV_OFFLOAD_START_REQ_EVT:
+      BTIF_TRACE_ERROR(
+          "BTIF_AV_OFFLOAD_START_REQ_EVT: Stream not Started OPENING");
+      btif_a2dp_on_offload_started(BTA_AV_FAIL);
+      break;
+
+    case BTA_AV_CLOSE_EVT:
+      btif_a2dp_on_stopped(NULL);
+      btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+                                   &(btif_av_cb.peer_bda));
+      btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+      break;
+
+      CHECK_RC_EVENT(event, (tBTA_AV*)p_data);
+
+    default:
+      BTIF_TRACE_WARNING("%s : unhandled event:%s", __func__,
+                         dump_av_sm_event_name((btif_av_sm_event_t)event));
+      return false;
+  }
+  return true;
+}
+
+/*****************************************************************************
+ *
+ * Function        btif_av_state_closing_handler
+ *
+ * Description     Intermediate state managing events during closing
+ *                 of avdtp channel
+ *
+ * Returns         true if event was processed, false otherwise
+ *
+ ******************************************************************************/
+
+static bool btif_av_state_closing_handler(btif_sm_event_t event, void* p_data) {
+  BTIF_TRACE_DEBUG("%s event:%s flags %x", __func__,
+                   dump_av_sm_event_name((btif_av_sm_event_t)event),
+                   btif_av_cb.flags);
+
+  switch (event) {
+    case BTIF_SM_ENTER_EVT:
+      if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
+        /* immediately stop transmission of frames */
+        btif_a2dp_source_set_tx_flush(true);
+        /* wait for audioflinger to stop a2dp */
+      }
+      if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
+        btif_a2dp_sink_set_rx_flush(true);
+      }
+      break;
+
+    case BTA_AV_STOP_EVT:
+    case BTIF_AV_STOP_STREAM_REQ_EVT:
+      btif_a2dp_on_stopped(NULL);
+      break;
+
+    case BTIF_SM_EXIT_EVT:
+      break;
+
+    case BTA_AV_CLOSE_EVT:
+
+      /* inform the application that we are disconnecting */
+      btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+                                   &(btif_av_cb.peer_bda));
+
+      btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+      break;
+
+    /* Handle the RC_CLOSE event for the cleanup */
+    case BTA_AV_RC_CLOSE_EVT:
+      btif_rc_handler(event, (tBTA_AV*)p_data);
+      break;
+
+    /* Handle the RC_BROWSE_CLOSE event for tetsing*/
+    case BTA_AV_RC_BROWSE_CLOSE_EVT:
+      btif_rc_handler(event, (tBTA_AV*)p_data);
+      break;
+
+    case BTIF_AV_OFFLOAD_START_REQ_EVT:
+      BTIF_TRACE_ERROR(
+          "BTIF_AV_OFFLOAD_START_REQ_EVT: Stream not Started Closing");
+      btif_a2dp_on_offload_started(BTA_AV_FAIL);
+      break;
+
+    default:
+      BTIF_TRACE_WARNING("%s : unhandled event:%s", __func__,
+                         dump_av_sm_event_name((btif_av_sm_event_t)event));
+      return false;
+  }
+  return true;
+}
+
+/*****************************************************************************
+ *
+ * Function     btif_av_state_opened_handler
+ *
+ * Description  Handles AV events while AVDTP is in OPEN state
+ *
+ * Returns      true if event was processed, false otherwise
+ *
+ ******************************************************************************/
+
+static bool btif_av_state_opened_handler(btif_sm_event_t event, void* p_data) {
+  tBTA_AV* p_av = (tBTA_AV*)p_data;
+
+  BTIF_TRACE_DEBUG("%s event:%s flags %x", __func__,
+                   dump_av_sm_event_name((btif_av_sm_event_t)event),
+                   btif_av_cb.flags);
+
+  if ((event == BTA_AV_REMOTE_CMD_EVT) &&
+      (btif_av_cb.flags & BTIF_AV_FLAG_REMOTE_SUSPEND) &&
+      (p_av->remote_cmd.rc_id == BTA_AV_RC_PLAY)) {
+    BTIF_TRACE_EVENT("%s: Resetting remote suspend flag on RC PLAY", __func__);
+    btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+  }
+
+  switch (event) {
+    case BTIF_SM_ENTER_EVT:
+      btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_STOP;
+      btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
+      break;
+
+    case BTIF_SM_EXIT_EVT:
+      btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
+      break;
+
+    case BTIF_AV_START_STREAM_REQ_EVT:
+      if (btif_av_cb.peer_sep != AVDT_TSEP_SRC) btif_a2dp_source_setup_codec();
+      BTA_AvStart();
+      btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_START;
+      break;
+
+    case BTA_AV_START_EVT: {
+      BTIF_TRACE_EVENT("BTA_AV_START_EVT status %d, suspending %d, init %d",
+                       p_av->start.status, p_av->start.suspending,
+                       p_av->start.initiator);
+
+      if ((p_av->start.status == BTA_SUCCESS) &&
+          (p_av->start.suspending == true))
+        return true;
+
+      /* if remote tries to start a2dp when DUT is a2dp source
+       * then suspend. In case a2dp is sink and call is active
+       * then disconnect the AVDTP channel
+       */
+      if (!(btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START)) {
+        if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
+          BTIF_TRACE_EVENT("%s: trigger suspend as remote initiated!!",
+                           __func__);
+          btif_dispatch_sm_event(BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0);
+        }
+      }
+
+      /*  In case peer is A2DP SRC we do not want to ack commands on UIPC*/
+      if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
+        if (btif_a2dp_on_started(
+                &p_av->start,
+                ((btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) != 0))) {
+          /* only clear pending flag after acknowledgement */
+          btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
+        }
+      }
+
+      /* remain in open state if status failed */
+      if (p_av->start.status != BTA_AV_SUCCESS) return false;
+
+      if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
+        btif_a2dp_sink_set_rx_flush(
+            false); /*  remove flush state, ready for streaming*/
+      }
+
+      /* change state to started, send acknowledgement if start is pending */
+      if (btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) {
+        if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+          btif_a2dp_on_started(NULL, true);
+        /* pending start flag will be cleared when exit current state */
+      }
+      btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_STARTED);
+
+    } break;
+
+    case BTIF_AV_DISCONNECT_REQ_EVT:
+      BTA_AvClose(btif_av_cb.bta_handle);
+      if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
+        BTA_AvCloseRc(btif_av_cb.bta_handle);
+      }
+
+      /* inform the application that we are disconnecting */
+      btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTING,
+                                   &(btif_av_cb.peer_bda));
+      break;
+
+    case BTA_AV_CLOSE_EVT:
+      /* avdtp link is closed */
+      btif_a2dp_on_stopped(NULL);
+
+      /* inform the application that we are disconnected */
+      btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+                                   &(btif_av_cb.peer_bda));
+
+      /* change state to idle, send acknowledgement if start is pending */
+      if (btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) {
+        btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+        /* pending start flag will be cleared when exit current state */
+      }
+      btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+      break;
+
+    case BTA_AV_RECONFIG_EVT:
+      if ((btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) &&
+          (p_av->reconfig.status == BTA_AV_SUCCESS)) {
+        APPL_TRACE_WARNING("reconfig done BTA_AVstart()");
+        BTA_AvStart();
+      } else if (btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) {
+        btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
+        btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+      }
+      break;
+
+    case BTIF_AV_CONNECT_REQ_EVT:
+      if (memcmp((bt_bdaddr_t*)p_data, &(btif_av_cb.peer_bda),
+                 sizeof(btif_av_cb.peer_bda)) == 0) {
+        BTIF_TRACE_DEBUG("%s: Ignore BTIF_AV_CONNECT_REQ_EVT for same device",
+                         __func__);
+      } else {
+        BTIF_TRACE_DEBUG("%s: Moved to opened by Other Incoming Conn req",
+                         __func__);
+        btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+                                     (bt_bdaddr_t*)p_data);
+      }
+      btif_queue_advance();
+      break;
+
+    case BTIF_AV_OFFLOAD_START_REQ_EVT:
+      BTIF_TRACE_ERROR(
+          "BTIF_AV_OFFLOAD_START_REQ_EVT: Stream not Started Opened");
+      btif_a2dp_on_offload_started(BTA_AV_FAIL);
+      break;
+
+      CHECK_RC_EVENT(event, (tBTA_AV*)p_data);
+
+    default:
+      BTIF_TRACE_WARNING("%s : unhandled event:%s", __func__,
+                         dump_av_sm_event_name((btif_av_sm_event_t)event));
+      return false;
+  }
+  return true;
+}
+
+/*****************************************************************************
+ *
+ * Function     btif_av_state_started_handler
+ *
+ * Description  Handles AV events while A2DP stream is started
+ *
+ * Returns      true if event was processed, false otherwise
+ *
+ ******************************************************************************/
+
+static bool btif_av_state_started_handler(btif_sm_event_t event, void* p_data) {
+  tBTA_AV* p_av = (tBTA_AV*)p_data;
+
+  BTIF_TRACE_DEBUG("%s event:%s flags %x", __func__,
+                   dump_av_sm_event_name((btif_av_sm_event_t)event),
+                   btif_av_cb.flags);
+
+  switch (event) {
+    case BTIF_SM_ENTER_EVT:
+
+      /* we are again in started state, clear any remote suspend flags */
+      btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+
+      /**
+       * Report to components above that we have entered the streaming
+       * stage, this should usually be followed by focus grant.
+       * see update_audio_focus_state()
+       */
+      btif_report_audio_state(BTAV_AUDIO_STATE_STARTED, &(btif_av_cb.peer_bda));
+
+      /* increase the a2dp consumer task priority temporarily when start
+      ** audio playing, to avoid overflow the audio packet queue. */
+      adjust_priority_a2dp(true);
+
+      break;
+
+    case BTIF_SM_EXIT_EVT:
+      /* restore the a2dp consumer task priority when stop audio playing. */
+      adjust_priority_a2dp(false);
+
+      break;
+
+    case BTIF_AV_START_STREAM_REQ_EVT:
+      /* we were remotely started, just ack back the local request */
+      if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+        btif_a2dp_on_started(NULL, true);
+      break;
+
+    /* fixme -- use suspend = true always to work around issue with BTA AV */
+    case BTIF_AV_STOP_STREAM_REQ_EVT:
+    case BTIF_AV_SUSPEND_STREAM_REQ_EVT:
+
+      /* set pending flag to ensure btif task is not trying to restart
+         stream while suspend is in progress */
+      btif_av_cb.flags |= BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
+
+      /* if we were remotely suspended but suspend locally, local suspend
+         always overrides */
+      btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+
+      if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
+        /*
+         * Immediately stop transmission of frames while suspend is
+         * pending.
+         */
+        btif_a2dp_source_set_tx_flush(true);
+      }
+
+      if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
+        btif_a2dp_on_stopped(NULL);
+      }
+
+      BTA_AvStop(true);
+      break;
+
+    case BTIF_AV_DISCONNECT_REQ_EVT:
+
+      /* request avdtp to close */
+      BTA_AvClose(btif_av_cb.bta_handle);
+      if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
+        BTA_AvCloseRc(btif_av_cb.bta_handle);
+      }
+
+      /* inform the application that we are disconnecting */
+      btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTING,
+                                   &(btif_av_cb.peer_bda));
+
+      /* wait in closing state until fully closed */
+      btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_CLOSING);
+      break;
+
+    case BTA_AV_SUSPEND_EVT:
+
+      BTIF_TRACE_EVENT("BTA_AV_SUSPEND_EVT status %d, init %d",
+                       p_av->suspend.status, p_av->suspend.initiator);
+
+      /* a2dp suspended, stop media task until resumed */
+      btif_a2dp_on_suspended(&p_av->suspend);
+
+      /* if not successful, remain in current state */
+      if (p_av->suspend.status != BTA_AV_SUCCESS) {
+        btif_av_cb.flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
+
+        if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
+          /* suspend failed, reset back tx flush state */
+          btif_a2dp_source_set_tx_flush(false);
+        }
+        return false;
+      }
+
+      if (p_av->suspend.initiator != true) {
+        /* remote suspend, notify HAL and await audioflinger to
+           suspend/stop stream */
+
+        /* set remote suspend flag to block media task from restarting
+           stream only if we did not already initiate a local suspend */
+        if ((btif_av_cb.flags & BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING) == 0)
+          btif_av_cb.flags |= BTIF_AV_FLAG_REMOTE_SUSPEND;
+
+        btif_report_audio_state(BTAV_AUDIO_STATE_REMOTE_SUSPEND,
+                                &(btif_av_cb.peer_bda));
+      } else {
+        btif_report_audio_state(BTAV_AUDIO_STATE_STOPPED,
+                                &(btif_av_cb.peer_bda));
+      }
+
+      btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENED);
+
+      /* suspend completed and state changed, clear pending status */
+      btif_av_cb.flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
+      break;
+
+    case BTA_AV_STOP_EVT:
+
+      btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_STOP;
+      btif_a2dp_on_stopped(&p_av->suspend);
+
+      btif_report_audio_state(BTAV_AUDIO_STATE_STOPPED, &(btif_av_cb.peer_bda));
+
+      /* if stop was successful, change state to open */
+      if (p_av->suspend.status == BTA_AV_SUCCESS)
+        btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENED);
+
+      break;
+
+    case BTA_AV_CLOSE_EVT:
+
+      btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_STOP;
+
+      /* avdtp link is closed */
+      btif_a2dp_on_stopped(NULL);
+
+      /* inform the application that we are disconnected */
+      btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+                                   &(btif_av_cb.peer_bda));
+
+      btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+      break;
+
+    case BTIF_AV_OFFLOAD_START_REQ_EVT:
+      BTA_AvOffloadStart(btif_av_cb.bta_handle);
+      break;
+
+    case BTA_AV_OFFLOAD_START_RSP_EVT:
+      btif_a2dp_on_offload_started(p_av->status);
+      break;
+
+      CHECK_RC_EVENT(event, (tBTA_AV*)p_data);
+
+    default:
+      BTIF_TRACE_WARNING("%s: unhandled event: %s", __func__,
+                         dump_av_sm_event_name((btif_av_sm_event_t)event));
+      return false;
+  }
+
+  return true;
+}
+
+/*****************************************************************************
+ *  Local event handlers
+ *****************************************************************************/
+
+static void btif_av_handle_event(uint16_t event, char* p_param) {
+  BTIF_TRACE_EVENT("%s event:%s", __func__,
+                   dump_av_sm_event_name((btif_av_sm_event_t)event));
+  switch (event) {
+    case BTIF_AV_CLEANUP_REQ_EVT:
+      btif_a2dp_source_shutdown();
+      btif_a2dp_sink_shutdown();
+      break;
+
+    case BTA_AV_REGISTER_EVT:
+      if (btif_av_cb.sm_handle == NULL) {
+        btif_av_cb.bta_handle = ((tBTA_AV*)p_param)->registr.hndl;
+        BTIF_TRACE_DEBUG("%s: BTA AV Handle updated", __func__);
+      }
+    /* FALLTHROUGH */
+    default:
+      btif_sm_dispatch(btif_av_cb.sm_handle, event, (void*)p_param);
+      btif_av_event_free_data(event, p_param);
+  }
+}
+
+void btif_av_event_deep_copy(uint16_t event, char* p_dest, char* p_src) {
+  BTIF_TRACE_DEBUG("%s", __func__);
+  tBTA_AV* av_src = (tBTA_AV*)p_src;
+  tBTA_AV* av_dest = (tBTA_AV*)p_dest;
+
+  // First copy the structure
+  maybe_non_aligned_memcpy(av_dest, av_src, sizeof(*av_src));
+  switch (event) {
+    case BTA_AV_META_MSG_EVT:
+      if (av_src->meta_msg.p_data && av_src->meta_msg.len) {
+        av_dest->meta_msg.p_data = (uint8_t*)osi_calloc(av_src->meta_msg.len);
+        memcpy(av_dest->meta_msg.p_data, av_src->meta_msg.p_data,
+               av_src->meta_msg.len);
+      }
+
+      if (av_src->meta_msg.p_msg) {
+        av_dest->meta_msg.p_msg = (tAVRC_MSG*)osi_calloc(sizeof(tAVRC_MSG));
+        memcpy(av_dest->meta_msg.p_msg, av_src->meta_msg.p_msg,
+               sizeof(tAVRC_MSG));
+
+        tAVRC_MSG* p_msg_src = av_src->meta_msg.p_msg;
+        tAVRC_MSG* p_msg_dest = av_dest->meta_msg.p_msg;
+
+        if ((p_msg_src->hdr.opcode == AVRC_OP_VENDOR) &&
+            (p_msg_src->vendor.p_vendor_data && p_msg_src->vendor.vendor_len)) {
+          p_msg_dest->vendor.p_vendor_data =
+              (uint8_t*)osi_calloc(p_msg_src->vendor.vendor_len);
+          memcpy(p_msg_dest->vendor.p_vendor_data,
+                 p_msg_src->vendor.p_vendor_data, p_msg_src->vendor.vendor_len);
+        }
+      }
+      break;
+
+    default:
+      break;
+  }
+}
+
+static void btif_av_event_free_data(btif_sm_event_t event, void* p_data) {
+  switch (event) {
+    case BTA_AV_META_MSG_EVT: {
+      tBTA_AV* av = (tBTA_AV*)p_data;
+      osi_free_and_reset((void**)&av->meta_msg.p_data);
+
+      if (av->meta_msg.p_msg) {
+        if (av->meta_msg.p_msg->hdr.opcode == AVRC_OP_VENDOR) {
+          osi_free(av->meta_msg.p_msg->vendor.p_vendor_data);
+        }
+        osi_free_and_reset((void**)&av->meta_msg.p_msg);
+      }
+    } break;
+
+    default:
+      break;
+  }
+}
+
+static void bte_av_callback(tBTA_AV_EVT event, tBTA_AV* p_data) {
+  btif_transfer_context(btif_av_handle_event, event, (char*)p_data,
+                        sizeof(tBTA_AV), btif_av_event_deep_copy);
+}
+
+static void bte_av_sink_media_callback(tBTA_AV_EVT event,
+                                       tBTA_AV_MEDIA* p_data) {
+  switch (event) {
+    case BTA_AV_SINK_MEDIA_DATA_EVT: {
+      btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
+      if ((state == BTIF_AV_STATE_STARTED) || (state == BTIF_AV_STATE_OPENED)) {
+        uint8_t queue_len = btif_a2dp_sink_enqueue_buf((BT_HDR*)p_data);
+        BTIF_TRACE_DEBUG("%s: packets in sink queue %d", __func__, queue_len);
+      }
+      break;
+    }
+    case BTA_AV_SINK_MEDIA_CFG_EVT: {
+      btif_av_sink_config_req_t config_req;
+
+      /* send a command to BT Media Task */
+      btif_a2dp_sink_update_decoder((uint8_t*)(p_data->avk_config.codec_info));
+      /* Switch to BTIF context */
+      config_req.sample_rate =
+          A2DP_GetTrackFrequency(p_data->avk_config.codec_info);
+      if (config_req.sample_rate == -1) {
+        APPL_TRACE_ERROR("%s: cannot get the track frequency", __func__);
+        break;
+      }
+      config_req.channel_count =
+          A2DP_GetTrackChannelCount(p_data->avk_config.codec_info);
+      if (config_req.channel_count == -1) {
+        APPL_TRACE_ERROR("%s: cannot get the channel count", __func__);
+        break;
+      }
+
+      memcpy(&config_req.peer_bd, (uint8_t*)(p_data->avk_config.bd_addr),
+             sizeof(config_req.peer_bd));
+      btif_transfer_context(btif_av_handle_event, BTIF_AV_SINK_CONFIG_REQ_EVT,
+                            (char*)&config_req, sizeof(config_req), NULL);
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_av_init
+ *
+ * Description      Initializes btif AV if not already done
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+
+bt_status_t btif_av_init(int service_id) {
+  if (btif_av_cb.sm_handle == NULL) {
+    alarm_free(av_open_on_rc_timer);
+    av_open_on_rc_timer = alarm_new("btif_av.av_open_on_rc_timer");
+
+    switch (service_id) {
+      case BTA_A2DP_SOURCE_SERVICE_ID:
+        if (!btif_a2dp_source_startup())
+          return BT_STATUS_FAIL;  // Already running
+        break;
+      case BTA_A2DP_SINK_SERVICE_ID:
+        if (!btif_a2dp_sink_startup())
+          return BT_STATUS_FAIL;  // Already running
+        break;
+      default:
+        break;
+    }
+
+    btif_enable_service(service_id);
+
+    /* Also initialize the AV state machine */
+    btif_av_cb.sm_handle = btif_sm_init(
+        (const btif_sm_handler_t*)btif_av_state_handlers, BTIF_AV_STATE_IDLE);
+  }
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         init_src
+ *
+ * Description      Initializes the AV interface for source mode
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+
+static bt_status_t init_src(btav_callbacks_t* callbacks) {
+  BTIF_TRACE_EVENT("%s()", __func__);
+
+  bt_status_t status = btif_av_init(BTA_A2DP_SOURCE_SERVICE_ID);
+  if (status == BT_STATUS_SUCCESS) bt_av_src_callbacks = callbacks;
+
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         init_sink
+ *
+ * Description      Initializes the AV interface for sink mode
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+
+static bt_status_t init_sink(btav_callbacks_t* callbacks) {
+  BTIF_TRACE_EVENT("%s()", __func__);
+
+  bt_status_t status = btif_av_init(BTA_A2DP_SINK_SERVICE_ID);
+  if (status == BT_STATUS_SUCCESS) bt_av_sink_callbacks = callbacks;
+
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         update_audio_focus_state
+ *
+ * Description      Updates the final focus state reported by components calling
+ *                  this module.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+static void update_audio_focus_state(int state) {
+  BTIF_TRACE_DEBUG("%s: state %d", __func__, state);
+  btif_a2dp_sink_set_focus_state_req((btif_a2dp_sink_focus_state_t)state);
+}
+
+/*******************************************************************************
+ *
+ * Function         update_audio_track_gain
+ *
+ * Description      Updates the track gain (used for ducking).
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+static void update_audio_track_gain(float gain) {
+  BTIF_TRACE_DEBUG("%s: gain %f", __func__, gain);
+  btif_a2dp_sink_set_audio_track_gain(gain);
+}
+
+/*******************************************************************************
+ *
+ * Function         connect
+ *
+ * Description      Establishes the AV signalling channel with the remote
+ *                  headset
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+
+static bt_status_t connect_int(bt_bdaddr_t* bd_addr, uint16_t uuid) {
+  btif_av_connect_req_t connect_req;
+  connect_req.target_bda = bd_addr;
+  connect_req.uuid = uuid;
+  BTIF_TRACE_EVENT("%s", __func__);
+
+  btif_sm_dispatch(btif_av_cb.sm_handle, BTIF_AV_CONNECT_REQ_EVT,
+                   (char*)&connect_req);
+
+  return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t src_connect_sink(bt_bdaddr_t* bd_addr) {
+  BTIF_TRACE_EVENT("%s", __func__);
+  CHECK_BTAV_INIT();
+
+  return btif_queue_connect(UUID_SERVCLASS_AUDIO_SOURCE, bd_addr, connect_int);
+}
+
+static bt_status_t sink_connect_src(bt_bdaddr_t* bd_addr) {
+  BTIF_TRACE_EVENT("%s", __func__);
+  CHECK_BTAV_INIT();
+
+  return btif_queue_connect(UUID_SERVCLASS_AUDIO_SINK, bd_addr, connect_int);
+}
+
+/*******************************************************************************
+ *
+ * Function         disconnect
+ *
+ * Description      Tears down the AV signalling channel with the remote headset
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t disconnect(bt_bdaddr_t* bd_addr) {
+  BTIF_TRACE_EVENT("%s", __func__);
+
+  CHECK_BTAV_INIT();
+
+  /* Switch to BTIF context */
+  return btif_transfer_context(btif_av_handle_event, BTIF_AV_DISCONNECT_REQ_EVT,
+                               (char*)bd_addr, sizeof(bt_bdaddr_t), NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         cleanup
+ *
+ * Description      Shuts down the AV interface and does the cleanup
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+static void cleanup(int service_uuid) {
+  BTIF_TRACE_EVENT("%s", __func__);
+
+  btif_transfer_context(btif_av_handle_event, BTIF_AV_CLEANUP_REQ_EVT, NULL, 0,
+                        NULL);
+
+  btif_disable_service(service_uuid);
+
+  alarm_free(av_open_on_rc_timer);
+  av_open_on_rc_timer = NULL;
+
+  /* Also shut down the AV state machine */
+  btif_sm_shutdown(btif_av_cb.sm_handle);
+  btif_av_cb.sm_handle = NULL;
+}
+
+static void cleanup_src(void) {
+  BTIF_TRACE_EVENT("%s", __func__);
+
+  if (bt_av_src_callbacks) {
+    bt_av_src_callbacks = NULL;
+    if (bt_av_sink_callbacks == NULL) cleanup(BTA_A2DP_SOURCE_SERVICE_ID);
+  }
+}
+
+static void cleanup_sink(void) {
+  BTIF_TRACE_EVENT("%s", __func__);
+
+  if (bt_av_sink_callbacks) {
+    bt_av_sink_callbacks = NULL;
+    if (bt_av_src_callbacks == NULL) cleanup(BTA_A2DP_SINK_SERVICE_ID);
+  }
+}
+
+static const btav_interface_t bt_av_src_interface = {
+    sizeof(btav_interface_t),
+    init_src,
+    src_connect_sink,
+    disconnect,
+    cleanup_src,
+    NULL,
+    NULL,
+};
+
+static const btav_interface_t bt_av_sink_interface = {
+    sizeof(btav_interface_t),
+    init_sink,
+    sink_connect_src,
+    disconnect,
+    cleanup_sink,
+    update_audio_focus_state,
+    update_audio_track_gain,
+};
+
+/*******************************************************************************
+ *
+ * Function         btif_av_get_addr
+ *
+ * Description      Fetches current AV BD address
+ *
+ * Returns          BD address
+ *
+ ******************************************************************************/
+
+bt_bdaddr_t btif_av_get_addr(void) { return btif_av_cb.peer_bda; }
+
+/*******************************************************************************
+ * Function         btif_av_is_sink_enabled
+ *
+ * Description      Checks if A2DP Sink is enabled or not
+ *
+ * Returns          true if A2DP Sink is enabled, false otherwise
+ *
+ ******************************************************************************/
+
+bool btif_av_is_sink_enabled(void) {
+  return (bt_av_sink_callbacks != NULL) ? true : false;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_av_stream_ready
+ *
+ * Description      Checks whether AV is ready for starting a stream
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+
+bool btif_av_stream_ready(void) {
+  btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
+
+  BTIF_TRACE_DEBUG("btif_av_stream_ready : sm hdl %d, state %d, flags %x",
+                   btif_av_cb.sm_handle, state, btif_av_cb.flags);
+
+  /* also make sure main adapter is enabled */
+  if (btif_is_enabled() == 0) {
+    BTIF_TRACE_EVENT("main adapter not enabled");
+    return false;
+  }
+
+  /* check if we are remotely suspended or stop is pending */
+  if (btif_av_cb.flags &
+      (BTIF_AV_FLAG_REMOTE_SUSPEND | BTIF_AV_FLAG_PENDING_STOP))
+    return false;
+
+  return (state == BTIF_AV_STATE_OPENED);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_av_stream_started_ready
+ *
+ * Description      Checks whether AV ready for media start in streaming state
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+
+bool btif_av_stream_started_ready(void) {
+  btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
+
+  BTIF_TRACE_DEBUG("btif_av_stream_started : sm hdl %d, state %d, flags %x",
+                   btif_av_cb.sm_handle, state, btif_av_cb.flags);
+
+  /* disallow media task to start if we have pending actions */
+  if (btif_av_cb.flags &
+      (BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING | BTIF_AV_FLAG_REMOTE_SUSPEND |
+       BTIF_AV_FLAG_PENDING_STOP))
+    return false;
+
+  return (state == BTIF_AV_STATE_STARTED);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dispatch_sm_event
+ *
+ * Description      Send event to AV statemachine
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+
+/* used to pass events to AV statemachine from other tasks */
+void btif_dispatch_sm_event(btif_av_sm_event_t event, void* p_data, int len) {
+  /* Switch to BTIF context */
+  btif_transfer_context(btif_av_handle_event, event, (char*)p_data, len, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_av_execute_service
+ *
+ * Description      Initializes/Shuts down the service
+ *
+ * Returns          BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_av_execute_service(bool b_enable) {
+  if (b_enable) {
+/* TODO: Removed BTA_SEC_AUTHORIZE since the Java/App does not
+ * handle this request in order to allow incoming connections to succeed.
+ * We need to put this back once support for this is added */
+
+/* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
+ * auto-suspend av streaming on AG events(SCO or Call). The suspend shall
+ * be initiated by the app/audioflinger layers */
+/* Support for browsing for SDP record should work only if we enable BROWSE
+ * while registering. */
+#if (AVRC_METADATA_INCLUDED == TRUE)
+    BTA_AvEnable(BTA_SEC_AUTHENTICATE,
+                 BTA_AV_FEAT_RCTG | BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR |
+                     BTA_AV_FEAT_NO_SCO_SSPD
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+                     | BTA_AV_FEAT_RCCT | BTA_AV_FEAT_ADV_CTRL |
+                     BTA_AV_FEAT_BROWSE
+#endif
+                 ,
+                 bte_av_callback);
+#else
+    BTA_AvEnable(BTA_SEC_AUTHENTICATE,
+                 (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_NO_SCO_SSPD), bte_av_callback);
+#endif
+    BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0, NULL,
+                   UUID_SERVCLASS_AUDIO_SOURCE);
+  } else {
+    BTA_AvDeregister(btif_av_cb.bta_handle);
+    BTA_AvDisable();
+  }
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_av_sink_execute_service
+ *
+ * Description      Initializes/Shuts down the service
+ *
+ * Returns          BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_av_sink_execute_service(bool b_enable) {
+  if (b_enable) {
+    /* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
+     * auto-suspend av streaming on AG events(SCO or Call). The suspend shall
+     * be initiated by the app/audioflinger layers */
+    BTA_AvEnable(BTA_SEC_AUTHENTICATE,
+                 BTA_AV_FEAT_NO_SCO_SSPD | BTA_AV_FEAT_RCCT |
+                     BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR |
+                     BTA_AV_FEAT_ADV_CTRL | BTA_AV_FEAT_RCTG |
+                     BTA_AV_FEAT_BROWSE,
+                 bte_av_callback);
+    BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AVK_SERVICE_NAME, 0,
+                   bte_av_sink_media_callback, UUID_SERVCLASS_AUDIO_SINK);
+  } else {
+    BTA_AvDeregister(btif_av_cb.bta_handle);
+    BTA_AvDisable();
+  }
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_av_get_src_interface
+ *
+ * Description      Get the AV callback interface for A2DP source profile
+ *
+ * Returns          btav_interface_t
+ *
+ ******************************************************************************/
+const btav_interface_t* btif_av_get_src_interface(void) {
+  BTIF_TRACE_EVENT("%s", __func__);
+  return &bt_av_src_interface;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_av_get_sink_interface
+ *
+ * Description      Get the AV callback interface for A2DP sink profile
+ *
+ * Returns          btav_interface_t
+ *
+ ******************************************************************************/
+const btav_interface_t* btif_av_get_sink_interface(void) {
+  BTIF_TRACE_EVENT("%s", __func__);
+  return &bt_av_sink_interface;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_av_is_connected
+ *
+ * Description      Checks if av has a connected sink
+ *
+ * Returns          bool
+ *
+ ******************************************************************************/
+bool btif_av_is_connected(void) {
+  btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
+  return ((state == BTIF_AV_STATE_OPENED) || (state == BTIF_AV_STATE_STARTED));
+}
+
+uint8_t btif_av_get_peer_sep(void) { return btif_av_cb.peer_sep; }
+
+/*******************************************************************************
+ *
+ * Function         btif_av_is_peer_edr
+ *
+ * Description      Check if the connected a2dp device supports
+ *                  EDR or not. Only when connected this function
+ *                  will accurately provide a true capability of
+ *                  remote peer. If not connected it will always be false.
+ *
+ * Returns          true if remote device is capable of EDR
+ *
+ ******************************************************************************/
+bool btif_av_is_peer_edr(void) {
+  ASSERTC(btif_av_is_connected(), "No active a2dp connection", 0);
+
+  if (btif_av_cb.edr)
+    return true;
+  else
+    return false;
+}
+
+/******************************************************************************
+ *
+ * Function        btif_av_clear_remote_suspend_flag
+ *
+ * Description     Clears btif_av_cd.flags if BTIF_AV_FLAG_REMOTE_SUSPEND is set
+ *
+ * Returns          void
+ *****************************************************************************/
+void btif_av_clear_remote_suspend_flag(void) {
+  BTIF_TRACE_DEBUG("%s: flag :%x", __func__, btif_av_cb.flags);
+  btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_av_peer_supports_3mbps
+ *
+ * Description      Check if the connected A2DP device supports
+ *                  3 Mbps EDR. This function only works if connected.
+ *                  If not connected it will always be false.
+ *
+ * Returns          true if remote device is EDR and supports 3 Mbps
+ *
+ ******************************************************************************/
+bool btif_av_peer_supports_3mbps(void) {
+  bool is3mbps = ((btif_av_cb.edr & BTA_AV_EDR_3MBPS) != 0);
+  BTIF_TRACE_DEBUG("%s: connected %d, edr_3mbps %d", __func__,
+                   btif_av_is_connected(), is3mbps);
+  return (btif_av_is_connected() && is3mbps);
+}
+
+/*******************************************************************************
+**
+** Function         btif_av_move_idle
+**
+** Description      Opening state is intermediate state. It cannot handle
+**                  incoming/outgoing connect/disconnect requests.When ACL
+**                  is disconnected and we are in opening state then move back
+**                  to idle state which is proper to handle connections.
+**
+** Returns          Void
+**
+*******************************************************************************/
+void btif_av_move_idle(bt_bdaddr_t bd_addr)
+{
+    /* inform the application that ACL is disconnected and move to idle state */
+    btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
+    BTIF_TRACE_DEBUG("%s: ACL Disconnected state %d  is same device %d", __func__,
+            state, memcmp (&bd_addr, &(btif_av_cb.peer_bda), sizeof(bd_addr)));
+    if (state == BTIF_AV_STATE_OPENING &&
+            (memcmp (&bd_addr, &(btif_av_cb.peer_bda), sizeof(bd_addr)) == 0))
+    {
+        BTIF_TRACE_DEBUG("%s: Moving State from Opening to Idle due to ACL disconnect", __func__);
+        btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+                &(btif_av_cb.peer_bda));
+        btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+    }
+}
diff --git a/bt/btif/src/btif_avrcp_audio_track.cc b/bt/btif/src/btif_avrcp_audio_track.cc
new file mode 100644
index 0000000..2833dfb
--- /dev/null
+++ b/bt/btif/src/btif_avrcp_audio_track.cc
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_NDEBUG 0
+#define LOG_TAG "bt_btif_avrcp_audio_track"
+
+#include "btif_avrcp_audio_track.h"
+
+#include <media/AudioTrack.h>
+#include <utils/StrongPointer.h>
+
+#include "osi/include/log.h"
+
+using namespace android;
+
+typedef struct { android::sp<android::AudioTrack> track; } BtifAvrcpAudioTrack;
+
+#if (DUMP_PCM_DATA == TRUE)
+FILE* outputPcmSampleFile;
+char outputFilename[50] = "/data/misc/bluedroid/output_sample.pcm";
+#endif
+
+void* BtifAvrcpAudioTrackCreate(int trackFreq, int channelType) {
+  LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btCreateTrack freq %d  channel %d ",
+              __func__, trackFreq, channelType);
+  sp<android::AudioTrack> track = new android::AudioTrack(
+      AUDIO_STREAM_MUSIC, trackFreq, AUDIO_FORMAT_PCM_16_BIT, channelType,
+      (size_t)0 /*frameCount*/, (audio_output_flags_t)AUDIO_OUTPUT_FLAG_FAST,
+      NULL /*callback_t*/, NULL /*void* user*/, 0 /*notificationFrames*/,
+      AUDIO_SESSION_ALLOCATE, android::AudioTrack::TRANSFER_SYNC);
+  assert(track != NULL);
+
+  BtifAvrcpAudioTrack* trackHolder = new BtifAvrcpAudioTrack;
+  assert(trackHolder != NULL);
+  trackHolder->track = track;
+
+  if (trackHolder->track->initCheck() != 0) {
+    return nullptr;
+  }
+
+#if (DUMP_PCM_DATA == TRUE)
+  outputPcmSampleFile = fopen(outputFilename, "ab");
+#endif
+  trackHolder->track->setVolume(1, 1);
+  return (void*)trackHolder;
+}
+
+void BtifAvrcpAudioTrackStart(void* handle) {
+  assert(handle != NULL);
+  BtifAvrcpAudioTrack* trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+  assert(trackHolder != NULL);
+  assert(trackHolder->track != NULL);
+  LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btStartTrack", __func__);
+  trackHolder->track->start();
+}
+
+void BtifAvrcpAudioTrackStop(void* handle) {
+  if (handle == NULL) {
+    LOG_DEBUG(LOG_TAG, "%s handle is null.", __func__);
+    return;
+  }
+  BtifAvrcpAudioTrack* trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+  if (trackHolder != NULL && trackHolder->track != NULL) {
+    LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btStartTrack", __func__);
+    trackHolder->track->stop();
+  }
+}
+
+void BtifAvrcpAudioTrackDelete(void* handle) {
+  if (handle == NULL) {
+    LOG_DEBUG(LOG_TAG, "%s handle is null.", __func__);
+    return;
+  }
+  BtifAvrcpAudioTrack* trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+  if (trackHolder != NULL && trackHolder->track != NULL) {
+    LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btStartTrack", __func__);
+    delete trackHolder;
+  }
+
+#if (DUMP_PCM_DATA == TRUE)
+  if (outputPcmSampleFile) {
+    fclose(outputPcmSampleFile);
+  }
+  outputPcmSampleFile = NULL;
+#endif
+}
+
+void BtifAvrcpAudioTrackPause(void* handle) {
+  if (handle == NULL) {
+    LOG_DEBUG(LOG_TAG, "%s handle is null.", __func__);
+    return;
+  }
+  BtifAvrcpAudioTrack* trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+  if (trackHolder != NULL && trackHolder->track != NULL) {
+    LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btStartTrack", __func__);
+    trackHolder->track->pause();
+    trackHolder->track->flush();
+  }
+}
+
+void BtifAvrcpSetAudioTrackGain(void* handle, float gain) {
+  if (handle == NULL) {
+    LOG_DEBUG(LOG_TAG, "%s handle is null.", __func__);
+    return;
+  }
+  BtifAvrcpAudioTrack* trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+  if (trackHolder != NULL && trackHolder->track != NULL) {
+    LOG_VERBOSE(LOG_TAG, "%s set gain %f", __func__, gain);
+    trackHolder->track->setVolume(gain);
+  }
+}
+
+int BtifAvrcpAudioTrackWriteData(void* handle, void* audioBuffer,
+                                 int bufferlen) {
+  BtifAvrcpAudioTrack* trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+  assert(trackHolder != NULL);
+  assert(trackHolder->track != NULL);
+  int retval = -1;
+#if (DUMP_PCM_DATA == TRUE)
+  if (outputPcmSampleFile) {
+    fwrite((audioBuffer), 1, (size_t)bufferlen, outputPcmSampleFile);
+  }
+#endif
+  retval = trackHolder->track->write(audioBuffer, (size_t)bufferlen);
+  LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btWriteData len = %d ret = %d", __func__,
+              bufferlen, retval);
+  return retval;
+}
diff --git a/bt/btif/src/btif_ble_advertiser.cc b/bt/btif/src/btif_ble_advertiser.cc
new file mode 100644
index 0000000..27111e7
--- /dev/null
+++ b/bt/btif/src/btif_ble_advertiser.cc
@@ -0,0 +1,215 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 Google Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_btif_ble_advertiser"
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
+
+#include <base/bind.h>
+#include <vector>
+
+#include "ble_advertiser.h"
+#include "bta_closure_api.h"
+#include "btif_common.h"
+
+using base::Bind;
+using base::Owned;
+using std::vector;
+
+extern bt_status_t do_in_jni_thread(const base::Closure& task);
+
+namespace {
+
+template <typename T>
+class OwnedArrayWrapper {
+ public:
+  explicit OwnedArrayWrapper(T* o) : ptr_(o) {}
+  ~OwnedArrayWrapper() { delete[] ptr_; }
+  T* get() const { return ptr_; }
+  OwnedArrayWrapper(OwnedArrayWrapper&& other) {
+    ptr_ = other.ptr_;
+    other.ptr_ = NULL;
+  }
+
+ private:
+  mutable T* ptr_;
+};
+
+template <typename T>
+T* Unwrap(const OwnedArrayWrapper<T>& o) {
+  return o.get();
+}
+
+template <typename T>
+static inline OwnedArrayWrapper<T> OwnedArray(T* o) {
+  return OwnedArrayWrapper<T>(o);
+}
+
+/* return the actual power in dBm based on the mapping in config file */
+int8_t ble_tx_power[BTM_BLE_ADV_TX_POWER_MAX + 1] = BTM_BLE_ADV_TX_POWER;
+int8_t ble_map_adv_tx_power(int tx_power_index) {
+  if (0 <= tx_power_index && tx_power_index < BTM_BLE_ADV_TX_POWER_MAX)
+    return (int8_t)ble_tx_power[tx_power_index];
+  return 0;
+}
+
+void bta_adv_set_data_cback(tBTA_STATUS call_status) {}
+
+class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface {
+  ~BleAdvertiserInterfaceImpl(){};
+
+  void RegisterAdvertiserCb(
+      base::Callback<void(uint8_t /* adv_id */, uint8_t /* status */)> cb,
+      uint8_t advertiser_id, uint8_t status) {
+    LOG(INFO) << __func__ << " status: " << +status << " , adveriser_id: " << +advertiser_id;
+    do_in_jni_thread(Bind(cb, advertiser_id, status));
+  }
+
+  void RegisterAdvertiser(
+      base::Callback<void(uint8_t /* advertiser_id */, uint8_t /* status */)>
+          cb) override {
+    do_in_bta_thread(
+        FROM_HERE, Bind(&BleAdvertisingManager::RegisterAdvertiser,
+                        base::Unretained(BleAdvertisingManager::Get()),
+                        Bind(&BleAdvertiserInterfaceImpl::RegisterAdvertiserCb,
+                             base::Unretained(this), cb)));
+  }
+
+  void Unregister(uint8_t advertiser_id) override {
+    do_in_bta_thread(
+        FROM_HERE,
+        Bind(&BleAdvertisingManager::Unregister,
+             base::Unretained(BleAdvertisingManager::Get()), advertiser_id));
+  }
+
+  void SetData(bool set_scan_rsp, vector<uint8_t> data) override {
+    uint8_t* data_ptr = nullptr;
+    if (data.size()) {
+      // base::Owned will free this ptr
+      data_ptr = new uint8_t[data.size()];
+      memcpy(data_ptr, data.data(), data.size());
+    }
+
+    if (!set_scan_rsp) {
+      if (data_ptr) {
+        do_in_bta_thread(FROM_HERE,
+                         Bind(&BTM_BleWriteAdvData, OwnedArray(data_ptr),
+                              data.size(), bta_adv_set_data_cback));
+      } else {
+        do_in_bta_thread(FROM_HERE, Bind(&BTM_BleWriteAdvData, nullptr,
+                                         data.size(), bta_adv_set_data_cback));
+      }
+    } else {
+      if (data_ptr) {
+        do_in_bta_thread(FROM_HERE,
+                         Bind(&BTM_BleWriteScanRsp, OwnedArray(data_ptr),
+                              data.size(), bta_adv_set_data_cback));
+      } else {
+        do_in_bta_thread(FROM_HERE, Bind(&BTM_BleWriteScanRsp, nullptr,
+                                         data.size(), bta_adv_set_data_cback));
+      }
+    }
+  }
+
+  void EnableCb(BleAdvertiserCb cb, uint8_t status) {
+    LOG(INFO) << __func__ << " status: " << +status;
+    do_in_jni_thread(Bind(cb, status));
+  }
+
+  void Enable(bool start, BleAdvertiserCb cb) override {
+    do_in_jni_thread(Bind(&GATT_Listen, start));
+    cb.Run(BT_STATUS_SUCCESS);
+  }
+
+  void MultiAdvSetParametersCb(BleAdvertiserCb cb, uint8_t status) {
+    LOG(INFO) << __func__ << " status: " << +status ;
+    do_in_jni_thread(Bind(cb, status));
+  }
+
+  virtual void MultiAdvSetParameters(int advertiser_id, int min_interval,
+                                     int max_interval, int adv_type,
+                                     int chnl_map, int tx_power,
+                                     BleAdvertiserCb cb) {
+    tBTM_BLE_ADV_PARAMS* params = new tBTM_BLE_ADV_PARAMS;
+    params->adv_int_min = min_interval;
+    params->adv_int_max = max_interval;
+    params->adv_type = adv_type;
+    params->channel_map = chnl_map;
+    params->adv_filter_policy = 0;
+    params->tx_power = ble_map_adv_tx_power(tx_power);
+
+    do_in_bta_thread(
+        FROM_HERE,
+        Bind(&BleAdvertisingManager::SetParameters,
+             base::Unretained(BleAdvertisingManager::Get()), advertiser_id,
+             base::Owned(params),
+             Bind(&BleAdvertiserInterfaceImpl::MultiAdvSetParametersCb,
+                  base::Unretained(this), cb)));
+  }
+
+  void MultiAdvSetInstDataCb(BleAdvertiserCb cb, uint8_t advertiser_id,
+                             uint8_t status) {
+    do_in_jni_thread(Bind(cb, status));
+  }
+
+  void MultiAdvSetInstData(int advertiser_id, bool set_scan_rsp,
+                           vector<uint8_t> data, BleAdvertiserCb cb) override {
+    do_in_bta_thread(
+        FROM_HERE, Bind(&BleAdvertisingManager::SetData,
+                        base::Unretained(BleAdvertisingManager::Get()),
+                        advertiser_id, set_scan_rsp, std::move(data),
+                        Bind(&BleAdvertiserInterfaceImpl::MultiAdvSetInstDataCb,
+                             base::Unretained(this), cb, advertiser_id)));
+  }
+
+  void MultiAdvEnableTimeoutCb(BleAdvertiserCb cb, uint8_t status) {
+    do_in_jni_thread(Bind(cb, status));
+  }
+
+  void MultiAdvEnableCb(BleAdvertiserCb cb, uint8_t status) {
+    do_in_jni_thread(Bind(cb, status));
+  }
+
+  void MultiAdvEnable(uint8_t advertiser_id, bool enable, BleAdvertiserCb cb,
+                      int timeout_s, BleAdvertiserCb timeout_cb) override {
+    VLOG(1) << __func__ << " advertiser_id: " << +advertiser_id
+            << " ,enable: " << enable;
+
+    do_in_bta_thread(
+        FROM_HERE,
+        Bind(&BleAdvertisingManager::Enable,
+             base::Unretained(BleAdvertisingManager::Get()), advertiser_id,
+             enable, Bind(&BleAdvertiserInterfaceImpl::MultiAdvEnableCb,
+                          base::Unretained(this), cb),
+             timeout_s,
+             Bind(&BleAdvertiserInterfaceImpl::MultiAdvEnableTimeoutCb,
+                  base::Unretained(this), timeout_cb)));
+  }
+};
+
+BleAdvertiserInterface* btLeAdvertiserInstance = nullptr;
+
+}  // namespace
+
+BleAdvertiserInterface* get_ble_advertiser_instance() {
+  if (btLeAdvertiserInstance == nullptr)
+    btLeAdvertiserInstance = new BleAdvertiserInterfaceImpl();
+
+  return btLeAdvertiserInstance;
+}
diff --git a/bt/btif/src/btif_ble_scanner.cc b/bt/btif/src/btif_ble_scanner.cc
new file mode 100644
index 0000000..eac3906
--- /dev/null
+++ b/bt/btif/src/btif_ble_scanner.cc
@@ -0,0 +1,668 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_scanner"
+
+#include <base/bind.h>
+#include <base/threading/thread.h>
+#include <errno.h>
+#include <hardware/bluetooth.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unordered_set>
+#include "device/include/controller.h"
+
+#include "btcore/include/bdaddr.h"
+#include "btif_common.h"
+#include "btif_util.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+#include <hardware/bt_gatt.h>
+
+#include "bta_api.h"
+#include "bta_gatt_api.h"
+#include "btif_config.h"
+#include "btif_dm.h"
+#include "btif_gatt.h"
+#include "btif_gatt_util.h"
+#include "btif_storage.h"
+#include "osi/include/log.h"
+#include "vendor_api.h"
+
+using base::Bind;
+using base::Owned;
+using std::vector;
+
+extern bt_status_t do_in_jni_thread(const base::Closure& task);
+extern const btgatt_callbacks_t* bt_gatt_callbacks;
+
+#define  SCAN_CBACK_IN_JNI(P_CBACK, ...)                                       \
+  do {                                                                         \
+    if (bt_gatt_callbacks && bt_gatt_callbacks->scanner->P_CBACK) {            \
+      BTIF_TRACE_API("HAL bt_gatt_callbacks->client->%s", #P_CBACK);           \
+      do_in_jni_thread(Bind(bt_gatt_callbacks->scanner->P_CBACK, __VA_ARGS__)); \
+    } else {                                                                   \
+      ASSERTC(0, "Callback is NULL", 0);                                       \
+    }                                                                          \
+  } while (0)
+
+#define CHECK_BTGATT_INIT()                                      \
+  do {                                                           \
+    if (bt_gatt_callbacks == NULL) {                             \
+      LOG_WARN(LOG_TAG, "%s: BTGATT not initialized", __func__); \
+      return BT_STATUS_NOT_READY;                                \
+    } else {                                                     \
+      LOG_VERBOSE(LOG_TAG, "%s", __func__);                      \
+    }                                                            \
+  } while (0)
+
+namespace std {
+template <>
+struct hash<bt_bdaddr_t> {
+  size_t operator()(const bt_bdaddr_t& f) const {
+    return f.address[0] + f.address[1] + f.address[2] + f.address[3] +
+           f.address[4] + f.address[5];
+  }
+};
+
+template <>
+struct equal_to<bt_bdaddr_t> {
+  size_t operator()(const bt_bdaddr_t& x, const bt_bdaddr_t& y) const {
+    return memcmp(x.address, y.address, BD_ADDR_LEN);
+  }
+};
+}
+
+namespace {
+
+std::unordered_set<bt_bdaddr_t> p_dev_cb;
+
+void btif_gattc_add_remote_bdaddr(BD_ADDR p_bda, uint8_t addr_type) {
+  bt_bdaddr_t bd_addr;
+  memcpy(bd_addr.address, p_bda, BD_ADDR_LEN);
+  p_dev_cb.insert(bd_addr);
+}
+
+bool btif_gattc_find_bdaddr(BD_ADDR p_bda) {
+  bt_bdaddr_t bd_addr;
+  memcpy(bd_addr.address, p_bda, BD_ADDR_LEN);
+  return (p_dev_cb.count(bd_addr) != 0);
+}
+
+void btif_gattc_init_dev_cb(void) { p_dev_cb.clear(); }
+
+btgattc_error_t btif_gattc_translate_btm_status(tBTM_STATUS status) {
+  switch (status) {
+    case BTM_SUCCESS:
+    case BTM_SUCCESS_NO_SECURITY:
+      return BT_GATTC_COMMAND_SUCCESS;
+
+    case BTM_CMD_STARTED:
+      return BT_GATTC_COMMAND_STARTED;
+
+    case BTM_BUSY:
+      return BT_GATTC_COMMAND_BUSY;
+
+    case BTM_CMD_STORED:
+      return BT_GATTC_COMMAND_STORED;
+
+    case BTM_NO_RESOURCES:
+      return BT_GATTC_NO_RESOURCES;
+
+    case BTM_MODE_UNSUPPORTED:
+    case BTM_WRONG_MODE:
+    case BTM_MODE4_LEVEL4_NOT_SUPPORTED:
+      return BT_GATTC_MODE_UNSUPPORTED;
+
+    case BTM_ILLEGAL_VALUE:
+    case BTM_SCO_BAD_LENGTH:
+      return BT_GATTC_ILLEGAL_VALUE;
+
+    case BTM_UNKNOWN_ADDR:
+      return BT_GATTC_UNKNOWN_ADDR;
+
+    case BTM_DEVICE_TIMEOUT:
+      return BT_GATTC_DEVICE_TIMEOUT;
+
+    case BTM_FAILED_ON_SECURITY:
+    case BTM_REPEATED_ATTEMPTS:
+    case BTM_NOT_AUTHORIZED:
+      return BT_GATTC_SECURITY_ERROR;
+
+    case BTM_DEV_RESET:
+    case BTM_ILLEGAL_ACTION:
+      return BT_GATTC_INCORRECT_STATE;
+
+    case BTM_BAD_VALUE_RET:
+      return BT_GATTC_INVALID_CONTROLLER_OUTPUT;
+
+    case BTM_DELAY_CHECK:
+      return BT_GATTC_DELAYED_ENCRYPTION_CHECK;
+
+    case BTM_ERR_PROCESSING:
+    default:
+      return BT_GATTC_ERR_PROCESSING;
+  }
+}
+
+void btif_gatts_upstreams_evt(uint16_t event, char* p_param) {
+  LOG_VERBOSE(LOG_TAG, "%s: Event %d", __func__, event);
+
+  tBTA_GATTC* p_data = (tBTA_GATTC*)p_param;
+  switch (event) {
+    case BTA_GATTC_REG_EVT: {
+      bt_uuid_t app_uuid;
+      bta_to_btif_uuid(&app_uuid, &p_data->reg_oper.app_uuid);
+      HAL_CBACK(bt_gatt_callbacks, scanner->register_scanner_cb,
+                p_data->reg_oper.status, p_data->reg_oper.client_if, &app_uuid);
+      break;
+    }
+
+    case BTA_GATTC_DEREG_EVT:
+      break;
+
+    case BTA_GATTC_SEARCH_CMPL_EVT: {
+      HAL_CBACK(bt_gatt_callbacks, client->search_complete_cb,
+                p_data->search_cmpl.conn_id, p_data->search_cmpl.status);
+      break;
+    }
+
+    default:
+      LOG_ERROR(LOG_TAG, "%s: Unhandled event (%d)!", __func__, event);
+      break;
+  }
+}
+
+void bta_gatts_cback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
+  bt_status_t status =
+      btif_transfer_context(btif_gatts_upstreams_evt, (uint16_t)event,
+                            (char*)p_data, sizeof(tBTA_GATTC), NULL);
+  ASSERTC(status == BT_STATUS_SUCCESS, "Context transfer failed!", status);
+}
+
+void bta_scan_param_setup_cb(tGATT_IF client_if, tBTM_STATUS status) {
+  SCAN_CBACK_IN_JNI(scan_parameter_setup_completed_cb, client_if,
+                   btif_gattc_translate_btm_status(status));
+}
+
+void bta_scan_filt_cfg_cb(tBTA_DM_BLE_PF_ACTION action,
+                          tBTA_DM_BLE_SCAN_COND_OP cfg_op,
+                          tBTA_DM_BLE_PF_AVBL_SPACE avbl_space,
+                          tBTA_STATUS status, tBTA_DM_BLE_REF_VALUE ref_value) {
+  SCAN_CBACK_IN_JNI(scan_filter_cfg_cb, action, ref_value, status, cfg_op,
+                   avbl_space);
+}
+
+void bta_scan_filt_param_setup_cb(uint8_t action_type,
+                                  tBTA_DM_BLE_PF_AVBL_SPACE avbl_space,
+                                  tBTA_DM_BLE_REF_VALUE ref_value,
+                                  tBTA_STATUS status) {
+  SCAN_CBACK_IN_JNI(scan_filter_param_cb, action_type, ref_value, status,
+                   avbl_space);
+}
+
+void bta_scan_filt_status_cb(uint8_t action, tBTA_STATUS status,
+                             tBTA_DM_BLE_REF_VALUE ref_value) {
+  SCAN_CBACK_IN_JNI(scan_filter_status_cb, action, ref_value, status);
+}
+
+void bta_batch_scan_setup_cb(tBTA_BLE_BATCH_SCAN_EVT evt,
+                             tBTA_DM_BLE_REF_VALUE ref_value,
+                             tBTA_STATUS status) {
+  BTIF_TRACE_DEBUG("bta_batch_scan_setup_cb-Status:%x, client_if:%d, evt=%d",
+                   status, ref_value, evt);
+
+  switch (evt) {
+    case BTA_BLE_BATCH_SCAN_ENB_EVT: {
+      SCAN_CBACK_IN_JNI(batchscan_enb_disable_cb, 1, ref_value, status);
+      return;
+    }
+
+    case BTA_BLE_BATCH_SCAN_DIS_EVT: {
+      SCAN_CBACK_IN_JNI(batchscan_enb_disable_cb, 0, ref_value, status);
+      return;
+    }
+
+    case BTA_BLE_BATCH_SCAN_CFG_STRG_EVT: {
+      SCAN_CBACK_IN_JNI(batchscan_cfg_storage_cb, ref_value, status);
+      return;
+    }
+
+    case BTA_BLE_BATCH_SCAN_DATA_EVT: {
+      SCAN_CBACK_IN_JNI(batchscan_reports_cb, ref_value, status, 0, 0,
+                       vector<uint8_t>());
+      return;
+    }
+
+    case BTA_BLE_BATCH_SCAN_THRES_EVT: {
+      SCAN_CBACK_IN_JNI(batchscan_threshold_cb, ref_value);
+      return;
+    }
+
+    default:
+      return;
+  }
+}
+
+void bta_batch_scan_threshold_cb(tBTA_DM_BLE_REF_VALUE ref_value) {
+  SCAN_CBACK_IN_JNI(batchscan_threshold_cb, ref_value);
+}
+
+void bta_batch_scan_reports_cb(tBTA_DM_BLE_REF_VALUE ref_value,
+                               uint8_t report_format, uint8_t num_records,
+                               uint16_t data_len, uint8_t* p_rep_data,
+                               tBTA_STATUS status) {
+  BTIF_TRACE_DEBUG("%s - client_if:%d, %d, %d, %d", __func__, ref_value, status,
+                   num_records, data_len);
+
+  if (data_len > 0) {
+    vector<uint8_t> data(p_rep_data, p_rep_data + data_len);
+    osi_free(p_rep_data);
+
+    SCAN_CBACK_IN_JNI(batchscan_reports_cb, ref_value, status, report_format,
+                     num_records, std::move(data));
+  } else {
+    SCAN_CBACK_IN_JNI(batchscan_reports_cb, ref_value, status, report_format,
+                     num_records, vector<uint8_t>());
+  }
+}
+
+void bta_scan_results_cb_impl(bt_bdaddr_t bd_addr, tBT_DEVICE_TYPE device_type,
+                              int8_t rssi, uint8_t addr_type,
+                              vector<uint8_t> value) {
+  uint8_t remote_name_len;
+  const uint8_t* p_eir_remote_name = NULL;
+  bt_device_type_t dev_type;
+  bt_property_t properties;
+
+  p_eir_remote_name = BTM_CheckEirData(
+      value.data(), BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &remote_name_len);
+
+  if (p_eir_remote_name == NULL) {
+    p_eir_remote_name = BTM_CheckEirData(
+        value.data(), BT_EIR_SHORTENED_LOCAL_NAME_TYPE, &remote_name_len);
+  }
+
+  if ((addr_type != BLE_ADDR_RANDOM) || (p_eir_remote_name)) {
+    if (!btif_gattc_find_bdaddr(bd_addr.address)) {
+      btif_gattc_add_remote_bdaddr(bd_addr.address, addr_type);
+
+      if (p_eir_remote_name) {
+        bt_bdname_t bdname;
+        memcpy(bdname.name, p_eir_remote_name, remote_name_len);
+        bdname.name[remote_name_len] = '\0';
+
+        LOG_VERBOSE(LOG_TAG, "%s BLE device name=%s len=%d dev_type=%d",
+                    __func__, bdname.name, remote_name_len, device_type);
+        btif_dm_update_ble_remote_properties(bd_addr.address, bdname.name,
+                                             device_type);
+      }
+    }
+  }
+
+  dev_type = (bt_device_type_t)device_type;
+  BTIF_STORAGE_FILL_PROPERTY(&properties, BT_PROPERTY_TYPE_OF_DEVICE,
+                             sizeof(dev_type), &dev_type);
+  btif_storage_set_remote_device_property(&(bd_addr), &properties);
+
+  btif_storage_set_remote_addr_type(&bd_addr, addr_type);
+
+  HAL_CBACK(bt_gatt_callbacks, scanner->scan_result_cb, &bd_addr, rssi,
+            std::move(value));
+}
+
+void bta_scan_results_cb(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH* p_data) {
+  uint8_t len;
+
+  if (event == BTA_DM_INQ_CMPL_EVT) {
+    BTIF_TRACE_DEBUG("%s  BLE observe complete. Num Resp %d", __func__,
+                     p_data->inq_cmpl.num_resps);
+    return;
+  }
+
+  if (event != BTA_DM_INQ_RES_EVT) {
+    BTIF_TRACE_WARNING("%s : Unknown event 0x%x", __func__, event);
+    return;
+  }
+
+  vector<uint8_t> value(BTGATT_MAX_ATTR_LEN);
+  if (p_data->inq_res.p_eir) {
+    value.insert(value.begin(), p_data->inq_res.p_eir,
+                 p_data->inq_res.p_eir + 62);
+
+    if (BTM_CheckEirData(p_data->inq_res.p_eir,
+                         BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &len)) {
+      p_data->inq_res.remt_name_not_required = true;
+    }
+  }
+
+  bt_bdaddr_t bdaddr;
+  bdcpy(bdaddr.address, p_data->inq_res.bd_addr);
+  do_in_jni_thread(Bind(bta_scan_results_cb_impl, bdaddr,
+                        p_data->inq_res.device_type, p_data->inq_res.rssi,
+                        p_data->inq_res.ble_addr_type, std::move(value)));
+}
+
+void bta_track_adv_event_cb(tBTA_DM_BLE_TRACK_ADV_DATA* p_track_adv_data) {
+  btgatt_track_adv_info_t* btif_scan_track_cb = new btgatt_track_adv_info_t;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+  btif_gatt_move_track_adv_data(btif_scan_track_cb,
+                                (btgatt_track_adv_info_t*)p_track_adv_data);
+
+  SCAN_CBACK_IN_JNI(track_adv_event_cb, Owned(btif_scan_track_cb));
+}
+
+
+void btif_gattc_register_scanner_impl(tBT_UUID uuid) {
+  BTA_GATTC_AppRegister(&uuid, bta_gatts_cback);
+}
+
+bt_status_t btif_gattc_register_scanner(bt_uuid_t* uuid) {
+  CHECK_BTGATT_INIT();
+
+  tBT_UUID bt_uuid;
+  btif_to_bta_uuid(&bt_uuid, uuid);
+  return do_in_jni_thread(Bind(&btif_gattc_register_scanner_impl, bt_uuid));
+}
+
+void btif_gattc_unregister_scanner_impl(int client_if) {
+  BTA_GATTC_AppDeregister(client_if);
+}
+
+bt_status_t btif_gattc_unregister_scanner(int scanner_id) {
+  CHECK_BTGATT_INIT();
+  return do_in_jni_thread(Bind(&btif_gattc_unregister_scanner_impl, scanner_id));
+}
+
+bt_status_t btif_gattc_scan(bool start) {
+  CHECK_BTGATT_INIT();
+  if (start) {
+    btif_gattc_init_dev_cb();
+    return do_in_jni_thread(Bind(&BTA_DmBleObserve, true, 0,
+                                 (tBTA_DM_SEARCH_CBACK*)bta_scan_results_cb));
+  }
+
+  return do_in_jni_thread(Bind(&BTA_DmBleObserve, false, 0, nullptr));
+}
+
+void btif_gattc_scan_filter_param_setup_impl(
+    int client_if, uint8_t action, int filt_index,
+    tBTA_DM_BLE_PF_FILT_PARAMS* adv_filt_param) {
+  if (1 == adv_filt_param->dely_mode) {
+    BTA_DmBleTrackAdvertiser(client_if, bta_track_adv_event_cb);
+  }
+
+  BTA_DmBleScanFilterSetup(action, filt_index, adv_filt_param, NULL,
+                           bta_scan_filt_param_setup_cb, client_if);
+}
+
+bt_status_t btif_gattc_scan_filter_param_setup(
+    btgatt_filt_param_setup_t filt_param) {
+  CHECK_BTGATT_INIT();
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  tBTA_DM_BLE_PF_FILT_PARAMS* adv_filt_param = new tBTA_DM_BLE_PF_FILT_PARAMS;
+  adv_filt_param->feat_seln = filt_param.feat_seln;
+  adv_filt_param->list_logic_type = filt_param.list_logic_type;
+  adv_filt_param->filt_logic_type = filt_param.filt_logic_type;
+  adv_filt_param->rssi_high_thres = filt_param.rssi_high_thres;
+  adv_filt_param->rssi_low_thres = filt_param.rssi_low_thres;
+  adv_filt_param->dely_mode = filt_param.dely_mode;
+  adv_filt_param->found_timeout = filt_param.found_timeout;
+  adv_filt_param->lost_timeout = filt_param.lost_timeout;
+  adv_filt_param->found_timeout_cnt = filt_param.found_timeout_cnt;
+  adv_filt_param->num_of_tracking_entries = filt_param.num_of_tracking_entries;
+
+  return do_in_jni_thread(
+      Bind(base::IgnoreResult(&btif_gattc_scan_filter_param_setup_impl),
+           filt_param.client_if, filt_param.action, filt_param.filt_index,
+           base::Owned(adv_filt_param)));
+}
+
+void btif_gattc_scan_filter_add_srvc_uuid(tBT_UUID uuid,
+                                          tBTA_DM_BLE_PF_COND_MASK* p_uuid_mask,
+                                          int action, int filt_type,
+                                          int filt_index, int client_if) {
+  tBTA_DM_BLE_PF_COND_PARAM cond;
+  memset(&cond, 0, sizeof(tBTA_DM_BLE_PF_COND_PARAM));
+
+  cond.srvc_uuid.p_target_addr = NULL;
+  cond.srvc_uuid.cond_logic = BTA_DM_BLE_PF_LOGIC_AND;
+  cond.srvc_uuid.uuid = uuid;
+  cond.srvc_uuid.p_uuid_mask = p_uuid_mask;
+
+  BTA_DmBleCfgFilterCondition(action, filt_type, filt_index, &cond,
+                              &bta_scan_filt_cfg_cb, client_if);
+}
+
+void btif_gattc_scan_filter_add_local_name(vector<uint8_t> data, int action,
+                                           int filt_type, int filt_index,
+                                           int client_if) {
+  tBTA_DM_BLE_PF_COND_PARAM cond;
+  memset(&cond, 0, sizeof(tBTA_DM_BLE_PF_COND_PARAM));
+
+  cond.local_name.data_len = data.size();
+  cond.local_name.p_data = const_cast<uint8_t*>(data.data());
+  BTA_DmBleCfgFilterCondition(action, filt_type, filt_index, &cond,
+                              &bta_scan_filt_cfg_cb, client_if);
+}
+
+void btif_gattc_scan_filter_add_manu_data(int company_id, int company_id_mask,
+                                          vector<uint8_t> pattern,
+                                          vector<uint8_t> pattern_mask,
+                                          int action, int filt_type,
+                                          int filt_index, int client_if) {
+  tBTA_DM_BLE_PF_COND_PARAM cond;
+  memset(&cond, 0, sizeof(tBTA_DM_BLE_PF_COND_PARAM));
+
+  cond.manu_data.company_id = company_id;
+  cond.manu_data.company_id_mask = company_id_mask ? company_id_mask : 0xFFFF;
+  cond.manu_data.data_len = pattern.size();
+  cond.manu_data.p_pattern = const_cast<uint8_t*>(pattern.data());
+  cond.manu_data.p_pattern_mask = const_cast<uint8_t*>(pattern_mask.data());
+  BTA_DmBleCfgFilterCondition(action, filt_type, filt_index, &cond,
+                              &bta_scan_filt_cfg_cb, client_if);
+}
+
+void btif_gattc_scan_filter_add_data_pattern(vector<uint8_t> pattern,
+                                             vector<uint8_t> pattern_mask,
+                                             int action, int filt_type,
+                                             int filt_index, int client_if) {
+  tBTA_DM_BLE_PF_COND_PARAM cond;
+  memset(&cond, 0, sizeof(tBTA_DM_BLE_PF_COND_PARAM));
+
+  cond.srvc_data.data_len = pattern.size();
+  cond.srvc_data.p_pattern = const_cast<uint8_t*>(pattern.data());
+  cond.srvc_data.p_pattern_mask = const_cast<uint8_t*>(pattern_mask.data());
+  BTA_DmBleCfgFilterCondition(action, filt_type, filt_index, &cond,
+                              &bta_scan_filt_cfg_cb, client_if);
+}
+
+bt_status_t btif_gattc_scan_filter_add_remove(
+    int client_if, int action, int filt_type, int filt_index, int company_id,
+    int company_id_mask, const bt_uuid_t* p_uuid, const bt_uuid_t* p_uuid_mask,
+    const bt_bdaddr_t* bd_addr, char addr_type, vector<uint8_t> data,
+    vector<uint8_t> mask) {
+  CHECK_BTGATT_INIT();
+  BTIF_TRACE_DEBUG("%s, %d, %d", __func__, action, filt_type);
+
+  /* If data is passed, both mask and data have to be the same length */
+  if (data.size() != mask.size() && data.size() != 0 && mask.size() != 0)
+    return BT_STATUS_PARM_INVALID;
+
+  switch (filt_type) {
+    case BTA_DM_BLE_PF_ADDR_FILTER:
+    {
+      tBTA_DM_BLE_PF_COND_PARAM* cond = new tBTA_DM_BLE_PF_COND_PARAM;
+      memset(cond, 0, sizeof(tBTA_DM_BLE_PF_COND_PARAM));
+
+      bdcpy(cond->target_addr.bda, bd_addr->address);
+      cond->target_addr.type = addr_type;
+      return do_in_jni_thread(Bind(&BTA_DmBleCfgFilterCondition, action,
+                                   filt_type, filt_index, base::Owned(cond),
+                                   &bta_scan_filt_cfg_cb, client_if));
+    }
+
+    case BTA_DM_BLE_PF_SRVC_DATA:
+      return do_in_jni_thread(Bind(&BTA_DmBleCfgFilterCondition, action,
+                                   filt_type, filt_index, nullptr,
+                                   &bta_scan_filt_cfg_cb, client_if));
+
+    case BTA_DM_BLE_PF_SRVC_UUID:
+    {
+      tBT_UUID bt_uuid;
+      btif_to_bta_uuid(&bt_uuid, p_uuid);
+
+      if (p_uuid_mask != NULL) {
+        tBTA_DM_BLE_PF_COND_MASK* uuid_mask = new tBTA_DM_BLE_PF_COND_MASK;
+        btif_to_bta_uuid_mask(uuid_mask, p_uuid_mask, p_uuid);
+        return do_in_jni_thread(Bind(&btif_gattc_scan_filter_add_srvc_uuid,
+                                     bt_uuid, base::Owned(uuid_mask), action,
+                                     filt_type, filt_index, client_if));
+      }
+
+      return do_in_jni_thread(Bind(&btif_gattc_scan_filter_add_srvc_uuid,
+                                   bt_uuid, nullptr, action, filt_type,
+                                   filt_index, client_if));
+    }
+
+    case BTA_DM_BLE_PF_SRVC_SOL_UUID:
+    {
+      tBTA_DM_BLE_PF_COND_PARAM* cond = new tBTA_DM_BLE_PF_COND_PARAM;
+      memset(cond, 0, sizeof(tBTA_DM_BLE_PF_COND_PARAM));
+
+      cond->solicitate_uuid.p_target_addr = NULL;
+      cond->solicitate_uuid.cond_logic = BTA_DM_BLE_PF_LOGIC_AND;
+      btif_to_bta_uuid(&cond->solicitate_uuid.uuid, p_uuid);
+
+      return do_in_jni_thread(Bind(&BTA_DmBleCfgFilterCondition, action,
+                                   filt_type, filt_index, base::Owned(cond),
+                                   &bta_scan_filt_cfg_cb, client_if));
+    }
+
+    case BTA_DM_BLE_PF_LOCAL_NAME:
+    {
+      return do_in_jni_thread(Bind(&btif_gattc_scan_filter_add_local_name,
+                                   std::move(data), action, filt_type,
+                                   filt_index, client_if));
+    }
+
+    case BTA_DM_BLE_PF_MANU_DATA:
+    {
+      return do_in_jni_thread(Bind(&btif_gattc_scan_filter_add_manu_data,
+                                   company_id, company_id_mask, std::move(data),
+                                   std::move(mask), action, filt_type,
+                                   filt_index, client_if));
+    }
+
+    case BTA_DM_BLE_PF_SRVC_DATA_PATTERN:
+    {
+      return do_in_jni_thread(Bind(&btif_gattc_scan_filter_add_data_pattern,
+                                   std::move(data), std::move(mask), action,
+                                   filt_type, filt_index, client_if));
+    }
+
+    default:
+      LOG_ERROR(LOG_TAG, "%s: Unknown filter type (%d)!", __func__, action);
+      return (bt_status_t)BTA_GATT_OK;
+  }
+}
+
+bt_status_t btif_gattc_scan_filter_clear(int client_if, int filter_index) {
+  CHECK_BTGATT_INIT();
+  BTIF_TRACE_DEBUG("%s: filter_index: %d", __func__, filter_index);
+
+  return do_in_jni_thread(Bind(&BTA_DmBleCfgFilterCondition,
+                               BTA_DM_BLE_SCAN_COND_CLEAR,
+                               BTA_DM_BLE_PF_TYPE_ALL, filter_index, nullptr,
+                               &bta_scan_filt_cfg_cb, client_if));
+}
+
+bt_status_t btif_gattc_scan_filter_enable(int client_if, bool enable) {
+  CHECK_BTGATT_INIT();
+  BTIF_TRACE_DEBUG("%s: enable: %d", __func__, enable);
+
+  uint8_t action = enable ? 1 : 0;
+
+  return do_in_jni_thread(Bind(&BTA_DmEnableScanFilter, action,
+                               &bta_scan_filt_status_cb, client_if));
+}
+
+bt_status_t btif_gattc_set_scan_parameters(int client_if, int scan_interval,
+                                           int scan_window) {
+  CHECK_BTGATT_INIT();
+  return do_in_jni_thread(
+      Bind(BTA_DmSetBleScanParams, client_if, scan_interval, scan_window,
+           BTM_BLE_SCAN_MODE_ACTI,
+           (tBLE_SCAN_PARAM_SETUP_CBACK)bta_scan_param_setup_cb));
+}
+
+
+bt_status_t btif_gattc_cfg_storage(int client_if, int batch_scan_full_max,
+                                   int batch_scan_trunc_max,
+                                   int batch_scan_notify_threshold) {
+  CHECK_BTGATT_INIT();
+  return do_in_jni_thread(
+      Bind(BTA_DmBleSetStorageParams, batch_scan_full_max, batch_scan_trunc_max,
+           batch_scan_notify_threshold,
+           (tBTA_BLE_SCAN_SETUP_CBACK*)bta_batch_scan_setup_cb,
+           (tBTA_BLE_SCAN_THRESHOLD_CBACK*)bta_batch_scan_threshold_cb,
+           (tBTA_BLE_SCAN_REP_CBACK*)bta_batch_scan_reports_cb,
+           (tBTA_DM_BLE_REF_VALUE)client_if));
+}
+
+bt_status_t btif_gattc_enb_batch_scan(int client_if, int scan_mode,
+                                      int scan_interval, int scan_window,
+                                      int addr_type, int discard_rule) {
+  CHECK_BTGATT_INIT();
+  return do_in_jni_thread(Bind(BTA_DmBleEnableBatchScan, scan_mode,
+                               scan_interval, scan_window, discard_rule,
+                               addr_type, client_if));
+}
+
+bt_status_t btif_gattc_dis_batch_scan(int client_if) {
+  CHECK_BTGATT_INIT();
+  return do_in_jni_thread(Bind(BTA_DmBleDisableBatchScan, client_if));
+}
+
+bt_status_t btif_gattc_read_batch_scan_reports(int client_if, int scan_mode) {
+  CHECK_BTGATT_INIT();
+  return do_in_jni_thread(Bind(BTA_DmBleReadScanReports, scan_mode, client_if));
+}
+
+} //namespace
+
+const btgatt_scanner_interface_t btgattScannerInterface = {
+    btif_gattc_register_scanner,
+    btif_gattc_unregister_scanner,
+    btif_gattc_scan,
+    btif_gattc_scan_filter_param_setup,
+    btif_gattc_scan_filter_add_remove,
+    btif_gattc_scan_filter_clear,
+    btif_gattc_scan_filter_enable,
+    btif_gattc_set_scan_parameters,
+    btif_gattc_cfg_storage,
+    btif_gattc_enb_batch_scan,
+    btif_gattc_dis_batch_scan,
+    btif_gattc_read_batch_scan_reports,
+};
+
+#endif
diff --git a/bt/btif/src/btif_config.cc b/bt/btif/src/btif_config.cc
new file mode 100644
index 0000000..6b4a2eb
--- /dev/null
+++ b/bt/btif/src/btif_config.cc
@@ -0,0 +1,556 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_btif_config"
+
+#include "btif_config.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <string>
+
+#include <mutex>
+
+#include "bt_types.h"
+#include "btcore/include/bdaddr.h"
+#include "btcore/include/module.h"
+#include "btif_api.h"
+#include "btif_common.h"
+#include "btif_config.h"
+#include "btif_config_transcode.h"
+#include "btif_util.h"
+#include "osi/include/alarm.h"
+#include "osi/include/allocator.h"
+#include "osi/include/compat.h"
+#include "osi/include/config.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+
+#define BT_CONFIG_SOURCE_TAG_NUM 1010001
+
+#define INFO_SECTION "Info"
+#define FILE_TIMESTAMP "TimeCreated"
+#define FILE_SOURCE "FileSource"
+#define TIME_STRING_LENGTH sizeof("YYYY-MM-DD HH:MM:SS")
+static const char* TIME_STRING_FORMAT = "%Y-%m-%d %H:%M:%S";
+
+// TODO(armansito): Find a better way than searching by a hardcoded path.
+#if defined(OS_GENERIC)
+static const char* CONFIG_FILE_PATH = "bt_config.conf";
+static const char* CONFIG_BACKUP_PATH = "bt_config.bak";
+static const char* CONFIG_LEGACY_FILE_PATH = "bt_config.xml";
+#else   // !defined(OS_GENERIC)
+static const char* CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_config.conf";
+static const char* CONFIG_BACKUP_PATH = "/data/misc/bluedroid/bt_config.bak";
+static const char* CONFIG_LEGACY_FILE_PATH =
+    "/data/misc/bluedroid/bt_config.xml";
+#endif  // defined(OS_GENERIC)
+static const period_ms_t CONFIG_SETTLE_PERIOD_MS = 3000;
+
+static void timer_config_save_cb(void* data);
+static void btif_config_write(uint16_t event, char* p_param);
+static bool is_factory_reset(void);
+static void delete_config_files(void);
+static void btif_config_remove_unpaired(config_t* config);
+static void btif_config_remove_restricted(config_t* config);
+static config_t* btif_config_open(const char* filename);
+
+static enum ConfigSource {
+  NOT_LOADED,
+  ORIGINAL,
+  BACKUP,
+  LEGACY,
+  NEW_FILE,
+  RESET
+} btif_config_source = NOT_LOADED;
+
+static int btif_config_devices_loaded = -1;
+static char btif_config_time_created[TIME_STRING_LENGTH];
+
+// TODO(zachoverflow): Move these two functions out, because they are too
+// specific for this file
+// {grumpy-cat/no, monty-python/you-make-me-sad}
+bool btif_get_device_type(const BD_ADDR bd_addr, int* p_device_type) {
+  if (p_device_type == NULL) return false;
+
+  bt_bdaddr_t bda;
+  bdcpy(bda.address, bd_addr);
+
+  bdstr_t bd_addr_str;
+  bdaddr_to_string(&bda, bd_addr_str, sizeof(bd_addr_str));
+
+  if (!btif_config_get_int(bd_addr_str, "DevType", p_device_type)) return false;
+
+  LOG_DEBUG(LOG_TAG, "%s: Device [%s] type %d", __func__, bd_addr_str,
+            *p_device_type);
+  return true;
+}
+
+bool btif_get_address_type(const BD_ADDR bd_addr, int* p_addr_type) {
+  if (p_addr_type == NULL) return false;
+
+  bt_bdaddr_t bda;
+  bdcpy(bda.address, bd_addr);
+
+  bdstr_t bd_addr_str;
+  bdaddr_to_string(&bda, bd_addr_str, sizeof(bd_addr_str));
+
+  if (!btif_config_get_int(bd_addr_str, "AddrType", p_addr_type)) return false;
+
+  LOG_DEBUG(LOG_TAG, "%s: Device [%s] address type %d", __func__, bd_addr_str,
+            *p_addr_type);
+  return true;
+}
+
+static std::mutex config_lock;  // protects operations on |config|.
+static config_t* config;
+static alarm_t* config_timer;
+
+// Module lifecycle functions
+
+static future_t* init(void) {
+  std::unique_lock<std::mutex> lock(config_lock);
+
+  if (is_factory_reset()) delete_config_files();
+
+  std::string file_source;
+
+  config = btif_config_open(CONFIG_FILE_PATH);
+  btif_config_source = ORIGINAL;
+  if (!config) {
+    LOG_WARN(LOG_TAG, "%s unable to load config file: %s; using backup.",
+             __func__, CONFIG_FILE_PATH);
+    config = btif_config_open(CONFIG_BACKUP_PATH);
+    btif_config_source = BACKUP;
+    file_source = "Backup";
+  }
+  if (!config) {
+    LOG_WARN(LOG_TAG,
+             "%s unable to load backup; attempting to transcode legacy file.",
+             __func__);
+    config = btif_config_transcode(CONFIG_LEGACY_FILE_PATH);
+    btif_config_source = LEGACY;
+    file_source = "Legacy";
+  }
+  if (!config) {
+    LOG_ERROR(LOG_TAG,
+              "%s unable to transcode legacy file; creating empty config.",
+              __func__);
+    config = config_new_empty();
+    btif_config_source = NEW_FILE;
+    file_source = "Empty";
+  }
+
+  if (!file_source.empty())
+    config_set_string(config, INFO_SECTION, FILE_SOURCE, file_source.c_str());
+
+  if (!config) {
+    LOG_ERROR(LOG_TAG, "%s unable to allocate a config object.", __func__);
+    goto error;
+  }
+
+  btif_config_remove_unpaired(config);
+
+  // Cleanup temporary pairings if we have left guest mode
+  if (!is_restricted_mode()) btif_config_remove_restricted(config);
+
+  // Read or set config file creation timestamp
+  const char* time_str;
+  time_str = config_get_string(config, INFO_SECTION, FILE_TIMESTAMP, NULL);
+  if (time_str != NULL) {
+    strlcpy(btif_config_time_created, time_str, TIME_STRING_LENGTH);
+  } else {
+    time_t current_time = time(NULL);
+    struct tm* time_created = localtime(&current_time);
+    strftime(btif_config_time_created, TIME_STRING_LENGTH, TIME_STRING_FORMAT,
+             time_created);
+    config_set_string(config, INFO_SECTION, FILE_TIMESTAMP,
+                      btif_config_time_created);
+  }
+
+  // TODO(sharvil): use a non-wake alarm for this once we have
+  // API support for it. There's no need to wake the system to
+  // write back to disk.
+  config_timer = alarm_new("btif.config");
+  if (!config_timer) {
+    LOG_ERROR(LOG_TAG, "%s unable to create alarm.", __func__);
+    goto error;
+  }
+
+  LOG_EVENT_INT(BT_CONFIG_SOURCE_TAG_NUM, btif_config_source);
+
+  return future_new_immediate(FUTURE_SUCCESS);
+
+error:
+  alarm_free(config_timer);
+  config_free(config);
+  config_timer = NULL;
+  config = NULL;
+  btif_config_source = NOT_LOADED;
+  return future_new_immediate(FUTURE_FAIL);
+}
+
+static config_t* btif_config_open(const char* filename) {
+  config_t* config = config_new(filename);
+  if (!config) return NULL;
+
+  if (!config_has_section(config, "Adapter")) {
+    LOG_ERROR(LOG_TAG, "Config is missing adapter section");
+    config_free(config);
+    return NULL;
+  }
+
+  return config;
+}
+
+static future_t* shut_down(void) {
+  btif_config_flush();
+  return future_new_immediate(FUTURE_SUCCESS);
+}
+
+static future_t* clean_up(void) {
+  btif_config_flush();
+
+  alarm_free(config_timer);
+  config_free(config);
+  config_timer = NULL;
+  config = NULL;
+  return future_new_immediate(FUTURE_SUCCESS);
+}
+
+EXPORT_SYMBOL module_t btif_config_module = {.name = BTIF_CONFIG_MODULE,
+                                             .init = init,
+                                             .start_up = NULL,
+                                             .shut_down = shut_down,
+                                             .clean_up = clean_up};
+
+bool btif_config_has_section(const char* section) {
+  assert(config != NULL);
+  assert(section != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  return config_has_section(config, section);
+}
+
+bool btif_config_exist(const char* section, const char* key) {
+  assert(config != NULL);
+  assert(section != NULL);
+  assert(key != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  return config_has_key(config, section, key);
+}
+
+bool btif_config_get_int(const char* section, const char* key, int* value) {
+  assert(config != NULL);
+  assert(section != NULL);
+  assert(key != NULL);
+  assert(value != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  bool ret = config_has_key(config, section, key);
+  if (ret) *value = config_get_int(config, section, key, *value);
+
+  return ret;
+}
+
+bool btif_config_set_int(const char* section, const char* key, int value) {
+  assert(config != NULL);
+  assert(section != NULL);
+  assert(key != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  config_set_int(config, section, key, value);
+
+  return true;
+}
+
+bool btif_config_get_str(const char* section, const char* key, char* value,
+                         int* size_bytes) {
+  assert(config != NULL);
+  assert(section != NULL);
+  assert(key != NULL);
+  assert(value != NULL);
+  assert(size_bytes != NULL);
+
+  {
+    std::unique_lock<std::mutex> lock(config_lock);
+    const char* stored_value = config_get_string(config, section, key, NULL);
+    if (!stored_value) return false;
+    strlcpy(value, stored_value, *size_bytes);
+  }
+
+  *size_bytes = strlen(value) + 1;
+  return true;
+}
+
+bool btif_config_set_str(const char* section, const char* key,
+                         const char* value) {
+  assert(config != NULL);
+  assert(section != NULL);
+  assert(key != NULL);
+  assert(value != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  config_set_string(config, section, key, value);
+  return true;
+}
+
+bool btif_config_get_bin(const char* section, const char* key, uint8_t* value,
+                         size_t* length) {
+  assert(config != NULL);
+  assert(section != NULL);
+  assert(key != NULL);
+  assert(value != NULL);
+  assert(length != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  const char* value_str = config_get_string(config, section, key, NULL);
+
+  if (!value_str) return false;
+
+  size_t value_len = strlen(value_str);
+  if ((value_len % 2) != 0 || *length < (value_len / 2)) return false;
+
+  for (size_t i = 0; i < value_len; ++i)
+    if (!isxdigit(value_str[i])) return false;
+
+  for (*length = 0; *value_str; value_str += 2, *length += 1)
+    sscanf(value_str, "%02hhx", &value[*length]);
+
+  return true;
+}
+
+size_t btif_config_get_bin_length(const char* section, const char* key) {
+  assert(config != NULL);
+  assert(section != NULL);
+  assert(key != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  const char* value_str = config_get_string(config, section, key, NULL);
+  if (!value_str) return 0;
+
+  size_t value_len = strlen(value_str);
+  return ((value_len % 2) != 0) ? 0 : (value_len / 2);
+}
+
+bool btif_config_set_bin(const char* section, const char* key,
+                         const uint8_t* value, size_t length) {
+  const char* lookup = "0123456789abcdef";
+
+  assert(config != NULL);
+  assert(section != NULL);
+  assert(key != NULL);
+
+  if (length > 0) assert(value != NULL);
+
+  char* str = (char*)osi_calloc(length * 2 + 1);
+
+  for (size_t i = 0; i < length; ++i) {
+    str[(i * 2) + 0] = lookup[(value[i] >> 4) & 0x0F];
+    str[(i * 2) + 1] = lookup[value[i] & 0x0F];
+  }
+
+  {
+    std::unique_lock<std::mutex> lock(config_lock);
+    config_set_string(config, section, key, str);
+  }
+
+  osi_free(str);
+  return true;
+}
+
+const btif_config_section_iter_t* btif_config_section_begin(void) {
+  assert(config != NULL);
+  return (const btif_config_section_iter_t*)config_section_begin(config);
+}
+
+const btif_config_section_iter_t* btif_config_section_end(void) {
+  assert(config != NULL);
+  return (const btif_config_section_iter_t*)config_section_end(config);
+}
+
+const btif_config_section_iter_t* btif_config_section_next(
+    const btif_config_section_iter_t* section) {
+  assert(config != NULL);
+  assert(section != NULL);
+  return (const btif_config_section_iter_t*)config_section_next(
+      (const config_section_node_t*)section);
+}
+
+const char* btif_config_section_name(
+    const btif_config_section_iter_t* section) {
+  assert(config != NULL);
+  assert(section != NULL);
+  return config_section_name((const config_section_node_t*)section);
+}
+
+bool btif_config_remove(const char* section, const char* key) {
+  assert(config != NULL);
+  assert(section != NULL);
+  assert(key != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  return config_remove_key(config, section, key);
+}
+
+void btif_config_save(void) {
+  assert(config != NULL);
+  assert(config_timer != NULL);
+
+  alarm_set(config_timer, CONFIG_SETTLE_PERIOD_MS, timer_config_save_cb, NULL);
+}
+
+void btif_config_flush(void) {
+  assert(config != NULL);
+  assert(config_timer != NULL);
+
+  alarm_cancel(config_timer);
+  btif_config_write(0, NULL);
+}
+
+bool btif_config_clear(void) {
+  assert(config != NULL);
+  assert(config_timer != NULL);
+
+  alarm_cancel(config_timer);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  config_free(config);
+
+  config = config_new_empty();
+  if (config == NULL) return false;
+
+  bool ret = config_save(config, CONFIG_FILE_PATH);
+  btif_config_source = RESET;
+  return ret;
+}
+
+static void timer_config_save_cb(UNUSED_ATTR void* data) {
+  // Moving file I/O to btif context instead of timer callback because
+  // it usually takes a lot of time to be completed, introducing
+  // delays during A2DP playback causing blips or choppiness.
+  btif_transfer_context(btif_config_write, 0, NULL, 0, NULL);
+}
+
+static void btif_config_write(UNUSED_ATTR uint16_t event,
+                              UNUSED_ATTR char* p_param) {
+  assert(config != NULL);
+  assert(config_timer != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  rename(CONFIG_FILE_PATH, CONFIG_BACKUP_PATH);
+  config_t* config_paired = config_new_clone(config);
+  btif_config_remove_unpaired(config_paired);
+  config_save(config_paired, CONFIG_FILE_PATH);
+  config_free(config_paired);
+}
+
+static void btif_config_remove_unpaired(config_t* conf) {
+  assert(conf != NULL);
+  int paired_devices = 0;
+
+  // The paired config used to carry information about
+  // discovered devices during regular inquiry scans.
+  // We remove these now and cache them in memory instead.
+  const config_section_node_t* snode = config_section_begin(conf);
+  while (snode != config_section_end(conf)) {
+    const char* section = config_section_name(snode);
+    if (string_is_bdaddr(section)) {
+      if (!config_has_key(conf, section, "LinkKey") &&
+          !config_has_key(conf, section, "LE_KEY_PENC") &&
+          !config_has_key(conf, section, "LE_KEY_PID") &&
+          !config_has_key(conf, section, "LE_KEY_PCSRK") &&
+          !config_has_key(conf, section, "LE_KEY_LENC") &&
+          !config_has_key(conf, section, "LE_KEY_LCSRK")) {
+        snode = config_section_next(snode);
+        config_remove_section(conf, section);
+        continue;
+      }
+      paired_devices++;
+    }
+    snode = config_section_next(snode);
+  }
+
+  // should only happen once, at initial load time
+  if (btif_config_devices_loaded == -1)
+    btif_config_devices_loaded = paired_devices;
+}
+
+void btif_debug_config_dump(int fd) {
+  dprintf(fd, "\nBluetooth Config:\n");
+
+  dprintf(fd, "  Config Source: ");
+  switch (btif_config_source) {
+    case NOT_LOADED:
+      dprintf(fd, "Not loaded\n");
+      break;
+    case ORIGINAL:
+      dprintf(fd, "Original file\n");
+      break;
+    case BACKUP:
+      dprintf(fd, "Backup file\n");
+      break;
+    case LEGACY:
+      dprintf(fd, "Legacy file\n");
+      break;
+    case NEW_FILE:
+      dprintf(fd, "New file\n");
+      break;
+    case RESET:
+      dprintf(fd, "Reset file\n");
+      break;
+  }
+
+  dprintf(fd, "  Devices loaded: %d\n", btif_config_devices_loaded);
+  dprintf(fd, "  File created/tagged: %s\n", btif_config_time_created);
+  dprintf(fd, "  File source: %s\n",
+          config_get_string(config, INFO_SECTION, FILE_SOURCE, "Original"));
+}
+
+static void btif_config_remove_restricted(config_t* config) {
+  assert(config != NULL);
+
+  const config_section_node_t* snode = config_section_begin(config);
+  while (snode != config_section_end(config)) {
+    const char* section = config_section_name(snode);
+    if (string_is_bdaddr(section) &&
+        config_has_key(config, section, "Restricted")) {
+      BTIF_TRACE_DEBUG("%s: Removing restricted device %s", __func__, section);
+      config_remove_section(config, section);
+    }
+    snode = config_section_next(snode);
+  }
+}
+
+static bool is_factory_reset(void) {
+  char factory_reset[PROPERTY_VALUE_MAX] = {0};
+  osi_property_get("persist.bluetooth.factoryreset", factory_reset, "false");
+  return strncmp(factory_reset, "true", 4) == 0;
+}
+
+static void delete_config_files(void) {
+  remove(CONFIG_FILE_PATH);
+  remove(CONFIG_BACKUP_PATH);
+  osi_property_set("persist.bluetooth.factoryreset", "false");
+}
diff --git a/bt/btif/src/btif_config_transcode.cc b/bt/btif/src/btif_config_transcode.cc
new file mode 100644
index 0000000..102a3af
--- /dev/null
+++ b/bt/btif/src/btif_config_transcode.cc
@@ -0,0 +1,66 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_btif_config_transcode"
+
+#include <tinyxml2.h>
+
+#include "osi/include/config.h"
+#include "osi/include/log.h"
+
+using namespace tinyxml2;
+
+config_t* btif_config_transcode(const char* xml_filename) {
+  XMLDocument document;
+  int error = document.LoadFile(xml_filename);
+  if (error != XML_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s unable to load XML file '%s': %d", __func__,
+              xml_filename, error);
+    return NULL;
+  }
+
+  XMLElement* rootElement = document.RootElement();
+  if (!rootElement) {
+    LOG_ERROR(LOG_TAG,
+              "%s unable to find root element; assuming corrupted config file.",
+              __func__);
+    return NULL;
+  }
+
+  config_t* config = config_new_empty();
+  if (!config) {
+    LOG_ERROR(LOG_TAG, "%s unable to allocate config object.", __func__);
+    return NULL;
+  }
+
+  for (XMLElement* i = rootElement->FirstChildElement(); i != NULL;
+       i = i->NextSiblingElement())
+    for (XMLElement* j = i->FirstChildElement(); j != NULL;
+         j = j->NextSiblingElement()) {
+      const char* section = j->Attribute("Tag");
+      for (XMLElement* k = j->FirstChildElement(); k != NULL;
+           k = k->NextSiblingElement()) {
+        const char* key = k->Attribute("Tag");
+        const char* value = k->GetText();
+        if (section && key && value)
+          config_set_string(config, section, key, value);
+      }
+    }
+
+  return config;
+}
diff --git a/bt/btif/src/btif_core.cc b/bt/btif/src/btif_core.cc
new file mode 100644
index 0000000..c98b4cb
--- /dev/null
+++ b/bt/btif/src/btif_core.cc
@@ -0,0 +1,1312 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ *  Filename:      btif_core.c
+ *
+ *  Description:   Contains core functionality related to interfacing between
+ *                 Bluetooth HAL and BTE core stack.
+ *
+ ***********************************************************************************/
+
+#define LOG_TAG "bt_btif_core"
+
+#include <base/at_exit.h>
+#include <base/bind.h>
+#include <base/run_loop.h>
+#include <base/threading/thread.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <hardware/bluetooth.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "bdaddr.h"
+#include "bt_common.h"
+#include "bt_utils.h"
+#include "bta_api.h"
+#include "bte.h"
+#include "btif_api.h"
+#include "btif_av.h"
+#include "btif_config.h"
+#include "btif_pan.h"
+#include "btif_profile_queue.h"
+#include "btif_sock.h"
+#include "btif_storage.h"
+#include "btif_uid.h"
+#include "btif_util.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/future.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+#include "osi/include/thread.h"
+#include "stack_manager.h"
+
+/************************************************************************************
+ *  Constants & Macros
+ ***********************************************************************************/
+
+#ifndef BTE_DID_CONF_FILE
+// TODO(armansito): Find a better way than searching by a hardcoded path.
+#if defined(OS_GENERIC)
+#define BTE_DID_CONF_FILE "bt_did.conf"
+#else  // !defined(OS_GENERIC)
+#define BTE_DID_CONF_FILE "/etc/bluetooth/bt_did.conf"
+#endif  // defined(OS_GENERIC)
+#endif  // BTE_DID_CONF_FILE
+
+/************************************************************************************
+ *  Local type definitions
+ ***********************************************************************************/
+
+/* These type definitions are used when passing data from the HAL to BTIF
+* context
+*  in the downstream path for the adapter and remote_device property APIs */
+
+typedef struct {
+  bt_bdaddr_t bd_addr;
+  bt_property_type_t type;
+} btif_storage_read_t;
+
+typedef struct {
+  bt_bdaddr_t bd_addr;
+  bt_property_t prop;
+} btif_storage_write_t;
+
+typedef union {
+  btif_storage_read_t read_req;
+  btif_storage_write_t write_req;
+} btif_storage_req_t;
+
+typedef enum {
+  BTIF_CORE_STATE_DISABLED = 0,
+  BTIF_CORE_STATE_ENABLING,
+  BTIF_CORE_STATE_ENABLED,
+  BTIF_CORE_STATE_DISABLING
+} btif_core_state_t;
+
+/************************************************************************************
+ *  Static variables
+ ***********************************************************************************/
+
+bt_bdaddr_t btif_local_bd_addr;
+
+static tBTA_SERVICE_MASK btif_enabled_services = 0;
+
+/*
+* This variable should be set to 1, if the Bluedroid+BTIF libraries are to
+* function in DUT mode.
+*
+* To set this, the btif_init_bluetooth needs to be called with argument as 1
+*/
+static uint8_t btif_dut_mode = 0;
+
+static thread_t* bt_jni_workqueue_thread;
+static const char* BT_JNI_WORKQUEUE_NAME = "bt_jni_workqueue";
+static uid_set_t* uid_set = NULL;
+base::MessageLoop* message_loop_ = NULL;
+base::RunLoop* jni_run_loop = NULL;
+
+/************************************************************************************
+ *  Static functions
+ ***********************************************************************************/
+static void btif_jni_associate();
+static void btif_jni_disassociate();
+static bool btif_fetch_property(const char* key, bt_bdaddr_t* addr);
+
+/* sends message to btif task */
+static void btif_sendmsg(void* p_msg);
+
+/************************************************************************************
+ *  Externs
+ ***********************************************************************************/
+extern fixed_queue_t* btu_hci_msg_queue;
+
+void btif_dm_execute_service_request(uint16_t event, char* p_param);
+#ifdef BTIF_DM_OOB_TEST
+void btif_dm_load_local_oob(void);
+#endif
+
+/*******************************************************************************
+ *
+ * Function         btif_context_switched
+ *
+ * Description      Callback used to execute transferred context callback
+ *
+ *                  p_msg : message to be executed in btif context
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+
+static void btif_context_switched(void* p_msg) {
+  BTIF_TRACE_VERBOSE("btif_context_switched");
+
+  tBTIF_CONTEXT_SWITCH_CBACK* p = (tBTIF_CONTEXT_SWITCH_CBACK*)p_msg;
+
+  /* each callback knows how to parse the data */
+  if (p->p_cb) p->p_cb(p->event, p->p_param);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_transfer_context
+ *
+ * Description      This function switches context to btif task
+ *
+ *                  p_cback   : callback used to process message in btif context
+ *                  event     : event id of message
+ *                  p_params  : parameter area passed to callback (copied)
+ *                  param_len : length of parameter area
+ *                  p_copy_cback : If set this function will be invoked for deep
+ *                                 copy
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+
+bt_status_t btif_transfer_context(tBTIF_CBACK* p_cback, uint16_t event,
+                                  char* p_params, int param_len,
+                                  tBTIF_COPY_CBACK* p_copy_cback) {
+  tBTIF_CONTEXT_SWITCH_CBACK* p_msg = (tBTIF_CONTEXT_SWITCH_CBACK*)osi_malloc(
+      sizeof(tBTIF_CONTEXT_SWITCH_CBACK) + param_len);
+
+  BTIF_TRACE_VERBOSE("btif_transfer_context event %d, len %d", event,
+                     param_len);
+
+  /* allocate and send message that will be executed in btif context */
+  p_msg->hdr.event = BT_EVT_CONTEXT_SWITCH_EVT; /* internal event */
+  p_msg->p_cb = p_cback;
+
+  p_msg->event = event; /* callback event */
+
+  /* check if caller has provided a copy callback to do the deep copy */
+  if (p_copy_cback) {
+    p_copy_cback(event, p_msg->p_param, p_params);
+  } else if (p_params) {
+    memcpy(p_msg->p_param, p_params, param_len); /* callback parameter data */
+  }
+
+  btif_sendmsg(p_msg);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         do_in_jni_thread
+ *
+ * Description      This function posts a task into the btif message loop, that
+ *                  executes it in the JNI message loop.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+bt_status_t do_in_jni_thread(const base::Closure& task) {
+  if (!message_loop_ || !message_loop_->task_runner().get()) {
+    BTIF_TRACE_WARNING("%s: Dropped message, message_loop not initialized yet!",
+                       __func__);
+    return BT_STATUS_FAIL;
+  }
+
+  if (message_loop_->task_runner()->PostTask(FROM_HERE, task))
+    return BT_STATUS_SUCCESS;
+
+  BTIF_TRACE_ERROR("%s: Post task to task runner failed!", __func__);
+  return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_is_dut_mode
+ *
+ * Description      checks if BTIF is currently in DUT mode
+ *
+ * Returns          1 if test mode, otherwize 0
+ *
+ ******************************************************************************/
+
+uint8_t btif_is_dut_mode(void) { return (btif_dut_mode == 1); }
+
+/*******************************************************************************
+ *
+ * Function         btif_is_enabled
+ *
+ * Description      checks if main adapter is fully enabled
+ *
+ * Returns          1 if fully enabled, otherwize 0
+ *
+ ******************************************************************************/
+
+int btif_is_enabled(void) {
+  return ((!btif_is_dut_mode()) &&
+          (stack_manager_get_interface()->get_stack_is_running()));
+}
+
+void btif_init_ok(UNUSED_ATTR uint16_t event, UNUSED_ATTR char* p_param) {
+  BTIF_TRACE_DEBUG("btif_task: received trigger stack init event");
+#if (BLE_INCLUDED == TRUE)
+  btif_dm_load_ble_local_keys();
+#endif
+  BTA_EnableBluetooth(bte_dm_evt);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_task
+ *
+ * Description      BTIF task handler managing all messages being passed
+ *                  Bluetooth HAL and BTA.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bt_jni_msg_ready(void* context) {
+  BT_HDR* p_msg = (BT_HDR*)context;
+
+  BTIF_TRACE_VERBOSE("btif task fetched event %x", p_msg->event);
+
+  switch (p_msg->event) {
+    case BT_EVT_CONTEXT_SWITCH_EVT:
+      btif_context_switched(p_msg);
+      break;
+    default:
+      BTIF_TRACE_ERROR("unhandled btif event (%d)", p_msg->event & BT_EVT_MASK);
+      break;
+  }
+  osi_free(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_sendmsg
+ *
+ * Description      Sends msg to BTIF task
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+
+void btif_sendmsg(void* p_msg) {
+  do_in_jni_thread(base::Bind(&bt_jni_msg_ready, p_msg));
+}
+
+void btif_thread_post(thread_fn func, void* context) {
+  do_in_jni_thread(base::Bind(func, context));
+}
+
+static bool btif_fetch_property(const char* key, bt_bdaddr_t* addr) {
+  char val[PROPERTY_VALUE_MAX] = {0};
+
+  if (osi_property_get(key, val, NULL)) {
+    if (string_to_bdaddr(val, addr)) {
+      BTIF_TRACE_DEBUG("%s: Got BDA %s", __func__, val);
+      return true;
+    }
+    BTIF_TRACE_DEBUG("%s: System Property did not contain valid bdaddr",
+                     __func__);
+  }
+  return false;
+}
+
+static void btif_fetch_local_bdaddr(bt_bdaddr_t* local_addr) {
+  char val[PROPERTY_VALUE_MAX] = {0};
+  uint8_t valid_bda = false;
+  int val_size = 0;
+
+  const uint8_t null_bdaddr[BD_ADDR_LEN] = {0, 0, 0, 0, 0, 0};
+
+  /* Get local bdaddr storage path from property */
+  if (osi_property_get(PROPERTY_BT_BDADDR_PATH, val, NULL)) {
+    int addr_fd;
+
+    BTIF_TRACE_DEBUG("%s, local bdaddr is stored in %s", __func__, val);
+
+    if ((addr_fd = open(val, O_RDONLY)) != -1) {
+      memset(val, 0, sizeof(val));
+      read(addr_fd, val, FACTORY_BT_BDADDR_STORAGE_LEN);
+      /* If this is not a reserved/special bda, then use it */
+      if ((string_to_bdaddr(val, local_addr)) &&
+          (memcmp(local_addr->address, null_bdaddr, BD_ADDR_LEN) != 0)) {
+        valid_bda = true;
+        BTIF_TRACE_DEBUG("%s: Got Factory BDA %s", __func__, val);
+      }
+      close(addr_fd);
+    }
+  }
+
+  if (!valid_bda) {
+    val_size = sizeof(val);
+    if (btif_config_get_str("Adapter", "Address", val, &val_size)) {
+      string_to_bdaddr(val, local_addr);
+      BTIF_TRACE_DEBUG("local bdaddr from bt_config.xml is  %s", val);
+      return;
+    }
+  }
+
+  /* No factory BDADDR found. Look for previously generated random BDA */
+  if (!valid_bda) {
+    valid_bda = btif_fetch_property(PERSIST_BDADDR_PROPERTY, local_addr);
+  }
+
+  /* No BDADDR found in file. Look for BDA in factory property */
+  if (!valid_bda) {
+    valid_bda = btif_fetch_property(FACTORY_BT_ADDR_PROPERTY, local_addr);
+  }
+
+  /* Generate new BDA if necessary */
+  if (!valid_bda) {
+    bdstr_t bdstr;
+
+    /* No autogen BDA. Generate one now. */
+    local_addr->address[0] = 0x22;
+    local_addr->address[1] = 0x22;
+    local_addr->address[2] = (uint8_t)osi_rand();
+    local_addr->address[3] = (uint8_t)osi_rand();
+    local_addr->address[4] = (uint8_t)osi_rand();
+    local_addr->address[5] = (uint8_t)osi_rand();
+
+    /* Convert to ascii, and store as a persistent property */
+    bdaddr_to_string(local_addr, bdstr, sizeof(bdstr));
+
+    BTIF_TRACE_DEBUG("No preset BDA. Generating BDA: %s for prop %s",
+                     (char*)bdstr, PERSIST_BDADDR_PROPERTY);
+
+    if (osi_property_set(PERSIST_BDADDR_PROPERTY, (char*)bdstr) < 0)
+      BTIF_TRACE_ERROR("Failed to set random BDA in prop %s",
+                       PERSIST_BDADDR_PROPERTY);
+  }
+
+  // save the bd address to config file
+  bdstr_t bdstr;
+  bdaddr_to_string(local_addr, bdstr, sizeof(bdstr));
+  val_size = sizeof(val);
+  if (btif_config_get_str("Adapter", "Address", val, &val_size)) {
+    if (strcmp(bdstr, val) == 0) {
+      // BDA is already present in the config file.
+      return;
+    }
+  }
+  btif_config_set_str("Adapter", "Address", bdstr);
+}
+
+void run_message_loop(UNUSED_ATTR void* context) {
+  // TODO(jpawlowski): exit_manager should be defined in main(), but there is no
+  // main method.
+  // It is therefore defined in bt_jni_workqueue_thread, and will be deleted
+  // when we free it.
+  base::AtExitManager exit_manager;
+
+  message_loop_ = new base::MessageLoop(base::MessageLoop::Type::TYPE_DEFAULT);
+
+  // Associate this workqueue thread with JNI.
+  message_loop_->task_runner()->PostTask(FROM_HERE,
+                                         base::Bind(&btif_jni_associate));
+
+  jni_run_loop = new base::RunLoop();
+  jni_run_loop->Run();
+
+  delete message_loop_;
+  message_loop_ = NULL;
+
+  delete jni_run_loop;
+  jni_run_loop = NULL;
+}
+/*******************************************************************************
+ *
+ * Function         btif_init_bluetooth
+ *
+ * Description      Creates BTIF task and prepares BT scheduler for startup
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_init_bluetooth() {
+  bte_main_boot_entry();
+
+  /* As part of the init, fetch the local BD ADDR */
+  memset(&btif_local_bd_addr, 0, sizeof(bt_bdaddr_t));
+  btif_fetch_local_bdaddr(&btif_local_bd_addr);
+
+  bt_jni_workqueue_thread = thread_new(BT_JNI_WORKQUEUE_NAME);
+  if (bt_jni_workqueue_thread == NULL) {
+    LOG_ERROR(LOG_TAG, "%s Unable to create thread %s", __func__,
+              BT_JNI_WORKQUEUE_NAME);
+    goto error_exit;
+  }
+
+  thread_post(bt_jni_workqueue_thread, run_message_loop, nullptr);
+
+  return BT_STATUS_SUCCESS;
+
+error_exit:;
+  thread_free(bt_jni_workqueue_thread);
+
+  bt_jni_workqueue_thread = NULL;
+
+  return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_enable_bluetooth_evt
+ *
+ * Description      Event indicating bluetooth enable is completed
+ *                  Notifies HAL user with updated adapter state
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+
+void btif_enable_bluetooth_evt(tBTA_STATUS status) {
+  const controller_t* controller = controller_get_interface();
+  bdstr_t bdstr;
+  bdaddr_to_string(controller->get_address(), bdstr, sizeof(bdstr));
+
+  BTIF_TRACE_DEBUG("%s: status %d, local bd [%s]", __func__, status, bdstr);
+
+  if (bdcmp(btif_local_bd_addr.address, controller->get_address()->address)) {
+    // TODO(zachoverflow): this whole code path seems like a bad time waiting to
+    // happen
+    // We open the vendor library using the old address.
+    bdstr_t old_address;
+    bt_property_t prop;
+
+    bdaddr_to_string(&btif_local_bd_addr, old_address, sizeof(old_address));
+
+    /**
+     * The Controller's BDADDR does not match to the BTIF's initial BDADDR!
+     * This could be because the factory BDADDR was stored separately in
+     * the Controller's non-volatile memory rather than in device's file
+     * system.
+     **/
+    BTIF_TRACE_WARNING("***********************************************");
+    BTIF_TRACE_WARNING("BTIF init BDA was %s", old_address);
+    BTIF_TRACE_WARNING("Controller BDA is %s", bdstr);
+    BTIF_TRACE_WARNING("***********************************************");
+
+    btif_local_bd_addr = *controller->get_address();
+
+    // save the bd address to config file
+    btif_config_set_str("Adapter", "Address", bdstr);
+    btif_config_save();
+
+    // fire HAL callback for property change
+    prop.type = BT_PROPERTY_BDADDR;
+    prop.val = (void*)&btif_local_bd_addr;
+    prop.len = sizeof(bt_bdaddr_t);
+    HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, BT_STATUS_SUCCESS, 1,
+              &prop);
+  }
+
+  bte_main_postload_cfg();
+#if (HCILP_INCLUDED == TRUE)
+  bte_main_enable_lpm(true);
+#endif
+  /* add passing up bd address as well ? */
+
+  /* callback to HAL */
+  if (status == BTA_SUCCESS) {
+    uid_set = uid_set_create();
+
+    btif_dm_init(uid_set);
+
+    /* init rfcomm & l2cap api */
+    btif_sock_init(uid_set);
+
+    /* init pan */
+    btif_pan_init();
+
+    /* load did configuration */
+    bte_load_did_conf(BTE_DID_CONF_FILE);
+
+#ifdef BTIF_DM_OOB_TEST
+    btif_dm_load_local_oob();
+#endif
+
+    future_ready(stack_manager_get_hack_future(), FUTURE_SUCCESS);
+  } else {
+    /* cleanup rfcomm & l2cap api */
+    btif_sock_cleanup();
+
+    btif_pan_cleanup();
+
+    future_ready(stack_manager_get_hack_future(), FUTURE_FAIL);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_disable_bluetooth
+ *
+ * Description      Inititates shutdown of Bluetooth system.
+ *                  Any active links will be dropped and device entering
+ *                  non connectable/discoverable mode
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+bt_status_t btif_disable_bluetooth(void) {
+  BTIF_TRACE_DEBUG("BTIF DISABLE BLUETOOTH");
+
+#if (BLE_INCLUDED == TRUE)
+  btm_ble_multi_adv_cleanup();
+// TODO(jpawlowski): this should do whole BTA_VendorCleanup(), but it would kill
+// the stack now.
+#endif
+
+  btif_dm_on_disable();
+  /* cleanup rfcomm & l2cap api */
+  btif_sock_cleanup();
+  btif_pan_cleanup();
+  BTA_DisableBluetooth();
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_disable_bluetooth_evt
+ *
+ * Description      Event notifying BT disable is now complete.
+ *                  Terminates main stack tasks and notifies HAL
+ *                  user with updated BT state.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+
+void btif_disable_bluetooth_evt(void) {
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+#if (HCILP_INCLUDED == TRUE)
+  bte_main_enable_lpm(false);
+#endif
+
+  bte_main_disable();
+
+  /* callback to HAL */
+  future_ready(stack_manager_get_hack_future(), FUTURE_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_cleanup_bluetooth
+ *
+ * Description      Cleanup BTIF state.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+
+bt_status_t btif_cleanup_bluetooth(void) {
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+#if (BLE_INCLUDED == TRUE)
+  BTA_VendorCleanup();
+#endif
+
+  btif_dm_cleanup();
+  btif_jni_disassociate();
+  btif_queue_release();
+
+  if (jni_run_loop && message_loop_) {
+    message_loop_->task_runner()->PostTask(FROM_HERE,
+                                           jni_run_loop->QuitClosure());
+  }
+
+  thread_free(bt_jni_workqueue_thread);
+  bt_jni_workqueue_thread = NULL;
+
+  bte_main_cleanup();
+
+  btif_dut_mode = 0;
+
+  BTIF_TRACE_DEBUG("%s done", __func__);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dut_mode_cback
+ *
+ * Description     Callback invoked on completion of vendor specific test mode
+ *                 command
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+static void btif_dut_mode_cback(UNUSED_ATTR tBTM_VSC_CMPL *p) {
+  /* For now nothing to be done. */
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dut_mode_configure
+ *
+ * Description      Configure Test Mode - 'enable' to 1 puts the device in test
+ *                       mode and 0 exits test mode
+ *
+ * Returns          BT_STATUS_SUCCESS on success
+ *
+ ******************************************************************************/
+bt_status_t btif_dut_mode_configure(uint8_t enable) {
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  if (!stack_manager_get_interface()->get_stack_is_running()) {
+    BTIF_TRACE_ERROR("btif_dut_mode_configure : Bluetooth not enabled");
+    return BT_STATUS_NOT_READY;
+  }
+
+  btif_dut_mode = enable;
+  if (enable == 1) {
+    BTA_EnableTestMode();
+  } else {
+    BTA_DisableTestMode();
+  }
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dut_mode_send
+ *
+ * Description     Sends a HCI Vendor specific command to the controller
+ *
+ * Returns          BT_STATUS_SUCCESS on success
+ *
+ ******************************************************************************/
+bt_status_t btif_dut_mode_send(uint16_t opcode, uint8_t* buf, uint8_t len) {
+  /* TODO: Check that opcode is a vendor command group */
+  BTIF_TRACE_DEBUG("%s", __func__);
+  if (!btif_is_dut_mode()) {
+    BTIF_TRACE_ERROR("Bluedroid HAL needs to be init with test_mode set to 1.");
+    return BT_STATUS_FAIL;
+  }
+  BTM_VendorSpecificCommand(opcode, len, buf, btif_dut_mode_cback);
+  return BT_STATUS_SUCCESS;
+}
+
+/*****************************************************************************
+ *
+ *   btif api adapter property functions
+ *
+ ****************************************************************************/
+
+static bt_status_t btif_in_get_adapter_properties(void) {
+  bt_property_t properties[6];
+  uint32_t num_props;
+
+  bt_bdaddr_t addr;
+  bt_bdname_t name;
+  bt_scan_mode_t mode;
+  uint32_t disc_timeout;
+  bt_bdaddr_t bonded_devices[BTM_SEC_MAX_DEVICE_RECORDS];
+  bt_uuid_t local_uuids[BT_MAX_NUM_UUIDS];
+  num_props = 0;
+
+  /* BD_ADDR */
+  BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_BDADDR,
+                             sizeof(addr), &addr);
+  btif_storage_get_adapter_property(&properties[num_props]);
+  num_props++;
+
+  /* BD_NAME */
+  BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_BDNAME,
+                             sizeof(name), &name);
+  btif_storage_get_adapter_property(&properties[num_props]);
+  num_props++;
+
+  /* SCAN_MODE */
+  BTIF_STORAGE_FILL_PROPERTY(&properties[num_props],
+                             BT_PROPERTY_ADAPTER_SCAN_MODE, sizeof(mode),
+                             &mode);
+  btif_storage_get_adapter_property(&properties[num_props]);
+  num_props++;
+
+  /* DISC_TIMEOUT */
+  BTIF_STORAGE_FILL_PROPERTY(&properties[num_props],
+                             BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT,
+                             sizeof(disc_timeout), &disc_timeout);
+  btif_storage_get_adapter_property(&properties[num_props]);
+  num_props++;
+
+  /* BONDED_DEVICES */
+  BTIF_STORAGE_FILL_PROPERTY(&properties[num_props],
+                             BT_PROPERTY_ADAPTER_BONDED_DEVICES,
+                             sizeof(bonded_devices), bonded_devices);
+  btif_storage_get_adapter_property(&properties[num_props]);
+  num_props++;
+
+  /* LOCAL UUIDs */
+  BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_UUIDS,
+                             sizeof(local_uuids), local_uuids);
+  btif_storage_get_adapter_property(&properties[num_props]);
+  num_props++;
+
+  HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, BT_STATUS_SUCCESS, num_props,
+            properties);
+
+  return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t btif_in_get_remote_device_properties(bt_bdaddr_t* bd_addr) {
+  bt_property_t remote_properties[8];
+  uint32_t num_props = 0;
+
+  bt_bdname_t name, alias;
+  uint32_t cod, devtype;
+  bt_uuid_t remote_uuids[BT_MAX_NUM_UUIDS];
+
+  memset(remote_properties, 0, sizeof(remote_properties));
+  BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props], BT_PROPERTY_BDNAME,
+                             sizeof(name), &name);
+  btif_storage_get_remote_device_property(bd_addr,
+                                          &remote_properties[num_props]);
+  num_props++;
+
+  BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props],
+                             BT_PROPERTY_REMOTE_FRIENDLY_NAME, sizeof(alias),
+                             &alias);
+  btif_storage_get_remote_device_property(bd_addr,
+                                          &remote_properties[num_props]);
+  num_props++;
+
+  BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props],
+                             BT_PROPERTY_CLASS_OF_DEVICE, sizeof(cod), &cod);
+  btif_storage_get_remote_device_property(bd_addr,
+                                          &remote_properties[num_props]);
+  num_props++;
+
+  BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props],
+                             BT_PROPERTY_TYPE_OF_DEVICE, sizeof(devtype),
+                             &devtype);
+  btif_storage_get_remote_device_property(bd_addr,
+                                          &remote_properties[num_props]);
+  num_props++;
+
+  BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props], BT_PROPERTY_UUIDS,
+                             sizeof(remote_uuids), remote_uuids);
+  btif_storage_get_remote_device_property(bd_addr,
+                                          &remote_properties[num_props]);
+  num_props++;
+
+  HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, BT_STATUS_SUCCESS,
+            bd_addr, num_props, remote_properties);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         execute_storage_request
+ *
+ * Description      Executes adapter storage request in BTIF context
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+
+static void execute_storage_request(uint16_t event, char* p_param) {
+  bt_status_t status = BT_STATUS_SUCCESS;
+
+  BTIF_TRACE_EVENT("execute storage request event : %d", event);
+
+  switch (event) {
+    case BTIF_CORE_STORAGE_ADAPTER_WRITE: {
+      btif_storage_req_t* p_req = (btif_storage_req_t*)p_param;
+      bt_property_t* p_prop = &(p_req->write_req.prop);
+      BTIF_TRACE_EVENT("type: %d, len %d, 0x%x", p_prop->type, p_prop->len,
+                       p_prop->val);
+
+      status = btif_storage_set_adapter_property(p_prop);
+      HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, status, 1, p_prop);
+    } break;
+
+    case BTIF_CORE_STORAGE_ADAPTER_READ: {
+      btif_storage_req_t* p_req = (btif_storage_req_t*)p_param;
+      char buf[512];
+      bt_property_t prop;
+      prop.type = p_req->read_req.type;
+      prop.val = (void*)buf;
+      prop.len = sizeof(buf);
+      if (prop.type == BT_PROPERTY_LOCAL_LE_FEATURES) {
+#if (BLE_INCLUDED == true)
+        tBTM_BLE_VSC_CB cmn_vsc_cb;
+        bt_local_le_features_t local_le_features;
+
+        /* LE features are not stored in storage. Should be retrived from stack
+         */
+        BTM_BleGetVendorCapabilities(&cmn_vsc_cb);
+        local_le_features.local_privacy_enabled = BTM_BleLocalPrivacyEnabled();
+
+        prop.len = sizeof(bt_local_le_features_t);
+        if (cmn_vsc_cb.filter_support == 1)
+          local_le_features.max_adv_filter_supported = cmn_vsc_cb.max_filter;
+        else
+          local_le_features.max_adv_filter_supported = 0;
+        local_le_features.max_adv_instance = cmn_vsc_cb.adv_inst_max;
+        local_le_features.max_irk_list_size = cmn_vsc_cb.max_irk_list_sz;
+        local_le_features.rpa_offload_supported = cmn_vsc_cb.rpa_offloading;
+        local_le_features.scan_result_storage_size =
+            cmn_vsc_cb.tot_scan_results_strg;
+        local_le_features.activity_energy_info_supported =
+            cmn_vsc_cb.energy_support;
+        local_le_features.version_supported = cmn_vsc_cb.version_supported;
+        local_le_features.total_trackable_advertisers =
+            cmn_vsc_cb.total_trackable_advertisers;
+
+        local_le_features.extended_scan_support =
+            cmn_vsc_cb.extended_scan_support > 0;
+        local_le_features.debug_logging_supported =
+            cmn_vsc_cb.debug_logging_supported > 0;
+        memcpy(prop.val, &local_le_features, prop.len);
+#endif
+      } else {
+        status = btif_storage_get_adapter_property(&prop);
+      }
+      HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, status, 1, &prop);
+    } break;
+
+    case BTIF_CORE_STORAGE_ADAPTER_READ_ALL: {
+      status = btif_in_get_adapter_properties();
+    } break;
+
+    case BTIF_CORE_STORAGE_NOTIFY_STATUS: {
+      HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, status, 0, NULL);
+    } break;
+
+    default:
+      BTIF_TRACE_ERROR("%s invalid event id (%d)", __func__, event);
+      break;
+  }
+}
+
+static void execute_storage_remote_request(uint16_t event, char* p_param) {
+  bt_status_t status = BT_STATUS_FAIL;
+  bt_property_t prop;
+
+  BTIF_TRACE_EVENT("execute storage remote request event : %d", event);
+
+  switch (event) {
+    case BTIF_CORE_STORAGE_REMOTE_READ: {
+      char buf[1024];
+      btif_storage_req_t* p_req = (btif_storage_req_t*)p_param;
+      prop.type = p_req->read_req.type;
+      prop.val = (void*)buf;
+      prop.len = sizeof(buf);
+
+      status = btif_storage_get_remote_device_property(
+          &(p_req->read_req.bd_addr), &prop);
+      HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, status,
+                &(p_req->read_req.bd_addr), 1, &prop);
+    } break;
+    case BTIF_CORE_STORAGE_REMOTE_WRITE: {
+      btif_storage_req_t* p_req = (btif_storage_req_t*)p_param;
+      status = btif_storage_set_remote_device_property(
+          &(p_req->write_req.bd_addr), &(p_req->write_req.prop));
+    } break;
+    case BTIF_CORE_STORAGE_REMOTE_READ_ALL: {
+      btif_storage_req_t* p_req = (btif_storage_req_t*)p_param;
+      btif_in_get_remote_device_properties(&p_req->read_req.bd_addr);
+    } break;
+  }
+}
+
+void btif_adapter_properties_evt(bt_status_t status, uint32_t num_props,
+                                 bt_property_t* p_props) {
+  HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, status, num_props, p_props);
+}
+void btif_remote_properties_evt(bt_status_t status, bt_bdaddr_t* remote_addr,
+                                uint32_t num_props, bt_property_t* p_props) {
+  HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, status, remote_addr,
+            num_props, p_props);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_in_storage_request_copy_cb
+ *
+ * Description     Switch context callback function to perform the deep copy for
+ *                 both the adapter and remote_device property API
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+static void btif_in_storage_request_copy_cb(uint16_t event, char* p_new_buf,
+                                            char* p_old_buf) {
+  btif_storage_req_t* new_req = (btif_storage_req_t*)p_new_buf;
+  btif_storage_req_t* old_req = (btif_storage_req_t*)p_old_buf;
+
+  BTIF_TRACE_EVENT("%s", __func__);
+  switch (event) {
+    case BTIF_CORE_STORAGE_REMOTE_WRITE:
+    case BTIF_CORE_STORAGE_ADAPTER_WRITE: {
+      bdcpy(new_req->write_req.bd_addr.address,
+            old_req->write_req.bd_addr.address);
+      /* Copy the member variables one at a time */
+      new_req->write_req.prop.type = old_req->write_req.prop.type;
+      new_req->write_req.prop.len = old_req->write_req.prop.len;
+
+      new_req->write_req.prop.val =
+          (uint8_t*)(p_new_buf + sizeof(btif_storage_req_t));
+      memcpy(new_req->write_req.prop.val, old_req->write_req.prop.val,
+             old_req->write_req.prop.len);
+    } break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_get_adapter_properties
+ *
+ * Description      Fetch all available properties (local & remote)
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+
+bt_status_t btif_get_adapter_properties(void) {
+  BTIF_TRACE_EVENT("%s", __func__);
+
+  if (!btif_is_enabled()) return BT_STATUS_NOT_READY;
+
+  return btif_transfer_context(execute_storage_request,
+                               BTIF_CORE_STORAGE_ADAPTER_READ_ALL, NULL, 0,
+                               NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_get_adapter_property
+ *
+ * Description      Fetches property value from local cache
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+
+bt_status_t btif_get_adapter_property(bt_property_type_t type) {
+  btif_storage_req_t req;
+
+  BTIF_TRACE_EVENT("%s %d", __func__, type);
+
+  /* Allow get_adapter_property only for BDADDR and BDNAME if BT is disabled */
+  if (!btif_is_enabled() && (type != BT_PROPERTY_BDADDR) &&
+      (type != BT_PROPERTY_BDNAME))
+    return BT_STATUS_NOT_READY;
+
+  memset(&(req.read_req.bd_addr), 0, sizeof(bt_bdaddr_t));
+  req.read_req.type = type;
+
+  return btif_transfer_context(execute_storage_request,
+                               BTIF_CORE_STORAGE_ADAPTER_READ, (char*)&req,
+                               sizeof(btif_storage_req_t), NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_set_adapter_property
+ *
+ * Description      Updates core stack with property value and stores it in
+ *                  local cache
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+
+bt_status_t btif_set_adapter_property(const bt_property_t* property) {
+  btif_storage_req_t req;
+  bt_status_t status = BT_STATUS_SUCCESS;
+  int storage_req_id = BTIF_CORE_STORAGE_NOTIFY_STATUS; /* default */
+  char bd_name[BTM_MAX_LOC_BD_NAME_LEN + 1];
+  uint16_t name_len = 0;
+
+  BTIF_TRACE_EVENT("btif_set_adapter_property type: %d, len %d, 0x%x",
+                   property->type, property->len, property->val);
+
+  if (!btif_is_enabled()) return BT_STATUS_NOT_READY;
+
+  switch (property->type) {
+    case BT_PROPERTY_BDNAME: {
+      name_len = property->len > BTM_MAX_LOC_BD_NAME_LEN
+                     ? BTM_MAX_LOC_BD_NAME_LEN
+                     : property->len;
+      memcpy(bd_name, property->val, name_len);
+      bd_name[name_len] = '\0';
+
+      BTIF_TRACE_EVENT("set property name : %s", (char*)bd_name);
+
+      BTA_DmSetDeviceName((char*)bd_name);
+
+      storage_req_id = BTIF_CORE_STORAGE_ADAPTER_WRITE;
+    } break;
+
+    case BT_PROPERTY_ADAPTER_SCAN_MODE: {
+      bt_scan_mode_t mode = *(bt_scan_mode_t*)property->val;
+      tBTA_DM_DISC disc_mode;
+      tBTA_DM_CONN conn_mode;
+
+      switch (mode) {
+        case BT_SCAN_MODE_NONE:
+          disc_mode = BTA_DM_NON_DISC;
+          conn_mode = BTA_DM_NON_CONN;
+          break;
+
+        case BT_SCAN_MODE_CONNECTABLE:
+          disc_mode = BTA_DM_NON_DISC;
+          conn_mode = BTA_DM_CONN;
+          break;
+
+        case BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE:
+          disc_mode = BTA_DM_GENERAL_DISC;
+          conn_mode = BTA_DM_CONN;
+          break;
+
+        default:
+          BTIF_TRACE_ERROR("invalid scan mode (0x%x)", mode);
+          return BT_STATUS_PARM_INVALID;
+      }
+
+      BTIF_TRACE_EVENT("set property scan mode : %x", mode);
+
+      BTA_DmSetVisibility(disc_mode, conn_mode, BTA_DM_IGNORE, BTA_DM_IGNORE);
+
+      storage_req_id = BTIF_CORE_STORAGE_ADAPTER_WRITE;
+    } break;
+    case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT: {
+      /* Nothing to do beside store the value in NV.  Java
+         will change the SCAN_MODE property after setting timeout,
+         if required */
+      storage_req_id = BTIF_CORE_STORAGE_ADAPTER_WRITE;
+    } break;
+    case BT_PROPERTY_BDADDR:
+    case BT_PROPERTY_UUIDS:
+    case BT_PROPERTY_ADAPTER_BONDED_DEVICES:
+    case BT_PROPERTY_REMOTE_FRIENDLY_NAME:
+      /* no write support through HAL, these properties are only populated from
+       * BTA events */
+      status = BT_STATUS_FAIL;
+      break;
+    default:
+      BTIF_TRACE_ERROR("btif_get_adapter_property : invalid type %d",
+                       property->type);
+      status = BT_STATUS_FAIL;
+      break;
+  }
+
+  if (storage_req_id != BTIF_CORE_STORAGE_NO_ACTION) {
+    /* pass on to storage for updating local database */
+
+    memset(&(req.write_req.bd_addr), 0, sizeof(bt_bdaddr_t));
+    memcpy(&(req.write_req.prop), property, sizeof(bt_property_t));
+
+    return btif_transfer_context(execute_storage_request, storage_req_id,
+                                 (char*)&req,
+                                 sizeof(btif_storage_req_t) + property->len,
+                                 btif_in_storage_request_copy_cb);
+  }
+
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_get_remote_device_property
+ *
+ * Description      Fetches the remote device property from the NVRAM
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_get_remote_device_property(bt_bdaddr_t* remote_addr,
+                                            bt_property_type_t type) {
+  btif_storage_req_t req;
+
+  if (!btif_is_enabled()) return BT_STATUS_NOT_READY;
+
+  memcpy(&(req.read_req.bd_addr), remote_addr, sizeof(bt_bdaddr_t));
+  req.read_req.type = type;
+  return btif_transfer_context(execute_storage_remote_request,
+                               BTIF_CORE_STORAGE_REMOTE_READ, (char*)&req,
+                               sizeof(btif_storage_req_t), NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_get_remote_device_properties
+ *
+ * Description      Fetches all the remote device properties from NVRAM
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_get_remote_device_properties(bt_bdaddr_t* remote_addr) {
+  btif_storage_req_t req;
+
+  if (!btif_is_enabled()) return BT_STATUS_NOT_READY;
+
+  memcpy(&(req.read_req.bd_addr), remote_addr, sizeof(bt_bdaddr_t));
+  return btif_transfer_context(execute_storage_remote_request,
+                               BTIF_CORE_STORAGE_REMOTE_READ_ALL, (char*)&req,
+                               sizeof(btif_storage_req_t), NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_set_remote_device_property
+ *
+ * Description      Writes the remote device property to NVRAM.
+ *                  Currently, BT_PROPERTY_REMOTE_FRIENDLY_NAME is the only
+ *                  remote device property that can be set
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_set_remote_device_property(bt_bdaddr_t* remote_addr,
+                                            const bt_property_t* property) {
+  btif_storage_req_t req;
+
+  if (!btif_is_enabled()) return BT_STATUS_NOT_READY;
+
+  memcpy(&(req.write_req.bd_addr), remote_addr, sizeof(bt_bdaddr_t));
+  memcpy(&(req.write_req.prop), property, sizeof(bt_property_t));
+
+  return btif_transfer_context(execute_storage_remote_request,
+                               BTIF_CORE_STORAGE_REMOTE_WRITE, (char*)&req,
+                               sizeof(btif_storage_req_t) + property->len,
+                               btif_in_storage_request_copy_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_get_remote_service_record
+ *
+ * Description      Looks up the service matching uuid on the remote device
+ *                  and fetches the SCN and service_name if the UUID is found
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_get_remote_service_record(bt_bdaddr_t* remote_addr,
+                                           bt_uuid_t* uuid) {
+  if (!btif_is_enabled()) return BT_STATUS_NOT_READY;
+
+  return btif_dm_get_remote_service_record(remote_addr, uuid);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_get_enabled_services_mask
+ *
+ * Description      Fetches currently enabled services
+ *
+ * Returns          tBTA_SERVICE_MASK
+ *
+ ******************************************************************************/
+
+tBTA_SERVICE_MASK btif_get_enabled_services_mask(void) {
+  return btif_enabled_services;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_enable_service
+ *
+ * Description      Enables the service 'service_ID' to the service_mask.
+ *                  Upon BT enable, BTIF core shall invoke the BTA APIs to
+ *                  enable the profiles
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_enable_service(tBTA_SERVICE_ID service_id) {
+  tBTA_SERVICE_ID* p_id = &service_id;
+
+  /* If BT is enabled, we need to switch to BTIF context and trigger the
+   * enable for that profile
+   *
+   * Otherwise, we just set the flag. On BT_Enable, the DM will trigger
+   * enable for the profiles that have been enabled */
+
+  btif_enabled_services |= (1 << service_id);
+
+  BTIF_TRACE_DEBUG("%s: current services:0x%x", __func__,
+                   btif_enabled_services);
+
+  if (btif_is_enabled()) {
+    btif_transfer_context(btif_dm_execute_service_request,
+                          BTIF_DM_ENABLE_SERVICE, (char*)p_id,
+                          sizeof(tBTA_SERVICE_ID), NULL);
+  }
+
+  return BT_STATUS_SUCCESS;
+}
+/*******************************************************************************
+ *
+ * Function         btif_disable_service
+ *
+ * Description      Disables the service 'service_ID' to the service_mask.
+ *                  Upon BT disable, BTIF core shall invoke the BTA APIs to
+ *                  disable the profiles
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_disable_service(tBTA_SERVICE_ID service_id) {
+  tBTA_SERVICE_ID* p_id = &service_id;
+
+  /* If BT is enabled, we need to switch to BTIF context and trigger the
+   * disable for that profile so that the appropriate uuid_property_changed will
+   * be triggerred. Otherwise, we just need to clear the service_id in the mask
+   */
+
+  btif_enabled_services &= (tBTA_SERVICE_MASK)(~(1 << service_id));
+
+  BTIF_TRACE_DEBUG("%s: Current Services:0x%x", __func__,
+                   btif_enabled_services);
+
+  if (btif_is_enabled()) {
+    btif_transfer_context(btif_dm_execute_service_request,
+                          BTIF_DM_DISABLE_SERVICE, (char*)p_id,
+                          sizeof(tBTA_SERVICE_ID), NULL);
+  }
+
+  return BT_STATUS_SUCCESS;
+}
+
+static void btif_jni_associate() {
+  BTIF_TRACE_DEBUG("%s Associating thread to JVM", __func__);
+  HAL_CBACK(bt_hal_cbacks, thread_evt_cb, ASSOCIATE_JVM);
+}
+
+static void btif_jni_disassociate() {
+  BTIF_TRACE_DEBUG("%s Disassociating thread from JVM", __func__);
+  HAL_CBACK(bt_hal_cbacks, thread_evt_cb, DISASSOCIATE_JVM);
+  bt_hal_cbacks = NULL;
+}
diff --git a/bt/btif/src/btif_debug.cc b/bt/btif/src/btif_debug.cc
new file mode 100644
index 0000000..4aea87a
--- /dev/null
+++ b/bt/btif/src/btif_debug.cc
@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <sys/time.h>
+#include <unistd.h>
+
+#include "btif/include/btif_debug.h"
+#include "btif/include/btif_debug_btsnoop.h"
+#include "include/bt_target.h"
+
+void btif_debug_init(void) {
+#if (BTSNOOP_MEM == TRUE)
+  btif_debug_btsnoop_init();
+#endif
+}
+
+// TODO: Find a better place for this to enable additional re-use
+uint64_t btif_debug_ts(void) {
+  struct timeval tv;
+  gettimeofday(&tv, NULL);
+  return (tv.tv_sec * 1000000LL) + tv.tv_usec;
+}
diff --git a/bt/btif/src/btif_debug_btsnoop.cc b/bt/btif/src/btif_debug_btsnoop.cc
new file mode 100644
index 0000000..6d636e3
--- /dev/null
+++ b/bt/btif/src/btif_debug_btsnoop.cc
@@ -0,0 +1,223 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <assert.h>
+#include <resolv.h>
+#include <zlib.h>
+
+#include "btif/include/btif_debug.h"
+#include "btif/include/btif_debug_btsnoop.h"
+#include "hci/include/btsnoop_mem.h"
+#include "include/bt_target.h"
+#include "osi/include/ringbuffer.h"
+
+#define REDUCE_HCI_TYPE_TO_SIGNIFICANT_BITS(type) ((type) >> 8)
+
+// Total btsnoop memory log buffer size
+#ifndef BTSNOOP_MEM_BUFFER_SIZE
+static const size_t BTSNOOP_MEM_BUFFER_SIZE = (256 * 1024);
+#endif
+
+// Block size for copying buffers (for compression/encoding etc.)
+static const size_t BLOCK_SIZE = 16384;
+
+// Maximum line length in bugreport (should be multiple of 4 for base64 output)
+static const uint8_t MAX_LINE_LENGTH = 128;
+
+static ringbuffer_t* buffer = NULL;
+static uint64_t last_timestamp_ms = 0;
+
+static size_t btsnoop_calculate_packet_length(uint16_t type,
+                                              const uint8_t* data,
+                                              size_t length);
+
+static void btsnoop_cb(const uint16_t type, const uint8_t* data,
+                       const size_t length) {
+  btsnooz_header_t header;
+
+  size_t included_length = btsnoop_calculate_packet_length(type, data, length);
+  if (included_length == 0) return;
+
+  // Make room in the ring buffer
+
+  while (ringbuffer_available(buffer) <
+         (included_length + sizeof(btsnooz_header_t))) {
+    ringbuffer_pop(buffer, (uint8_t*)&header, sizeof(btsnooz_header_t));
+    ringbuffer_delete(buffer, header.length - 1);
+  }
+
+  // Insert data
+
+  const uint64_t now = btif_debug_ts();
+
+  header.type = REDUCE_HCI_TYPE_TO_SIGNIFICANT_BITS(type);
+  header.length = included_length + 1;  // +1 for type byte
+  header.packet_length = length + 1;    // +1 for type byte.
+  header.delta_time_ms = last_timestamp_ms ? now - last_timestamp_ms : 0;
+  last_timestamp_ms = now;
+
+  ringbuffer_insert(buffer, (uint8_t*)&header, sizeof(btsnooz_header_t));
+  ringbuffer_insert(buffer, data, included_length);
+}
+
+static size_t btsnoop_calculate_packet_length(uint16_t type,
+                                              const uint8_t* data,
+                                              size_t length) {
+  static const size_t HCI_ACL_HEADER_SIZE = 4;
+  static const size_t L2CAP_HEADER_SIZE = 4;
+  static const size_t L2CAP_CID_OFFSET = (HCI_ACL_HEADER_SIZE + 2);
+  static const uint16_t L2CAP_SIGNALING_CID = 0x0001;
+
+  // Maximum amount of ACL data to log.
+  // Enough for an RFCOMM frame up to the frame check;
+  // not enough for a HID report or audio data.
+  static const size_t MAX_HCI_ACL_LEN = 14;
+
+  // Calculate packet length to be included
+
+  switch (type) {
+    case BT_EVT_TO_LM_HCI_CMD:
+      return length;
+
+    case BT_EVT_TO_BTU_HCI_EVT:
+      return length;
+
+    case BT_EVT_TO_LM_HCI_ACL:
+    case BT_EVT_TO_BTU_HCI_ACL: {
+      size_t len_hci_acl = HCI_ACL_HEADER_SIZE + L2CAP_HEADER_SIZE;
+      // Check if we have enough data for an L2CAP header
+      if (length > len_hci_acl) {
+        uint16_t l2cap_cid =
+            data[L2CAP_CID_OFFSET] | (data[L2CAP_CID_OFFSET + 1] << 8);
+        if (l2cap_cid == L2CAP_SIGNALING_CID) {
+          // For the signaling CID, take the full packet.
+          // That way, the PSM setup is captured, allowing decoding of PSMs down
+          // the road.
+          return length;
+        } else {
+          // Otherwise, return as much as we reasonably can
+          len_hci_acl = MAX_HCI_ACL_LEN;
+        }
+      }
+      return len_hci_acl < length ? len_hci_acl : length;
+    }
+
+    case BT_EVT_TO_LM_HCI_SCO:
+    case BT_EVT_TO_BTU_HCI_SCO:
+    // We're not logging SCO packets at this time since they are not currently
+    // used.
+    // FALLTHROUGH
+    default:
+      return 0;
+  }
+}
+
+static bool btsnoop_compress(ringbuffer_t* rb_dst, ringbuffer_t* rb_src) {
+  assert(rb_dst != NULL);
+  assert(rb_src != NULL);
+
+  z_stream zs;
+  zs.zalloc = Z_NULL;
+  zs.zfree = Z_NULL;
+  zs.opaque = Z_NULL;
+
+  if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) return false;
+
+  bool rc = true;
+  uint8_t block_src[BLOCK_SIZE];
+  uint8_t block_dst[BLOCK_SIZE];
+
+  const size_t num_blocks =
+      (ringbuffer_size(rb_src) + BLOCK_SIZE - 1) / BLOCK_SIZE;
+  for (size_t i = 0; i < num_blocks; ++i) {
+    zs.avail_in =
+        ringbuffer_peek(rb_src, i * BLOCK_SIZE, block_src, BLOCK_SIZE);
+    zs.next_in = block_src;
+
+    do {
+      zs.avail_out = BLOCK_SIZE;
+      zs.next_out = block_dst;
+
+      int err = deflate(&zs, (i == num_blocks - 1) ? Z_FINISH : Z_NO_FLUSH);
+      if (err == Z_STREAM_ERROR) {
+        rc = false;
+        break;
+      }
+
+      const size_t length = BLOCK_SIZE - zs.avail_out;
+      ringbuffer_insert(rb_dst, block_dst, length);
+    } while (zs.avail_out == 0);
+  }
+
+  deflateEnd(&zs);
+  return rc;
+}
+
+void btif_debug_btsnoop_init(void) {
+  if (buffer == NULL) buffer = ringbuffer_init(BTSNOOP_MEM_BUFFER_SIZE);
+  btsnoop_mem_set_callback(btsnoop_cb);
+}
+
+void btif_debug_btsnoop_dump(int fd) {
+  dprintf(fd, "--- BEGIN:BTSNOOP_LOG_SUMMARY (%zu bytes in) ---\n",
+          ringbuffer_size(buffer));
+
+  ringbuffer_t* ringbuffer = ringbuffer_init(BTSNOOP_MEM_BUFFER_SIZE);
+  if (ringbuffer == NULL) {
+    dprintf(fd, "%s Unable to allocate memory for compression", __func__);
+    return;
+  }
+
+  // Prepend preamble
+
+  btsnooz_preamble_t preamble;
+  preamble.version = BTSNOOZ_CURRENT_VERSION;
+  preamble.last_timestamp_ms = last_timestamp_ms;
+  ringbuffer_insert(ringbuffer, (uint8_t*)&preamble,
+                    sizeof(btsnooz_preamble_t));
+
+  // Compress data
+
+  uint8_t b64_in[3] = {0};
+  char b64_out[5] = {0};
+
+  size_t line_length = 0;
+
+  bool rc = btsnoop_compress(ringbuffer, buffer);
+  if (rc == false) {
+    dprintf(fd, "%s Log compression failed", __func__);
+    goto error;
+  }
+
+  // Base64 encode & output
+
+  while (ringbuffer_size(ringbuffer) > 0) {
+    size_t read = ringbuffer_pop(ringbuffer, b64_in, 3);
+    if (line_length >= MAX_LINE_LENGTH) {
+      dprintf(fd, "\n");
+      line_length = 0;
+    }
+    line_length += b64_ntop(b64_in, read, b64_out, 5);
+    dprintf(fd, "%s", b64_out);
+  }
+
+  dprintf(fd, "\n--- END:BTSNOOP_LOG_SUMMARY ---\n");
+
+error:
+  ringbuffer_free(ringbuffer);
+}
diff --git a/bt/btif/src/btif_debug_conn.cc b/bt/btif/src/btif_debug_conn.cc
new file mode 100644
index 0000000..1b18ae4
--- /dev/null
+++ b/bt/btif/src/btif_debug_conn.cc
@@ -0,0 +1,107 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "btcore/include/bdaddr.h"
+#include "btif/include/btif_debug.h"
+#include "btif/include/btif_debug_conn.h"
+
+#define NUM_CONNECTION_EVENTS 16
+#define TEMP_BUFFER_SIZE 30
+
+typedef struct conn_event_t {
+  uint64_t ts;
+  btif_debug_conn_state_t state;
+  bt_bdaddr_t bda;
+  tGATT_DISCONN_REASON disconnect_reason;
+} conn_event_t;
+
+static conn_event_t connection_events[NUM_CONNECTION_EVENTS];
+static uint8_t current_event = 0;
+
+static char* format_ts(const uint64_t ts, char* buffer, int len) {
+  const uint64_t ms = ts / 1000;
+  const time_t secs = ms / 1000;
+  struct tm* ptm = localtime(&secs);
+
+  char tempbuff[20];
+  strftime(tempbuff, sizeof(tempbuff), "%m-%d %H:%M:%S", ptm);
+  snprintf(buffer, len, "%s.%03u", tempbuff, (uint16_t)(ms % 1000));
+
+  return buffer;
+}
+
+static const char* format_state(const btif_debug_conn_state_t state) {
+  switch (state) {
+    case BTIF_DEBUG_CONNECTED:
+      return "CONNECTED   ";
+    case BTIF_DEBUG_DISCONNECTED:
+      return "DISCONNECTED";
+  }
+  return "UNKNOWN";
+}
+
+static void next_event() {
+  ++current_event;
+  if (current_event == NUM_CONNECTION_EVENTS) current_event = 0;
+}
+
+void btif_debug_conn_state(const bt_bdaddr_t bda,
+                           const btif_debug_conn_state_t state,
+                           const tGATT_DISCONN_REASON disconnect_reason) {
+  next_event();
+
+  conn_event_t* evt = &connection_events[current_event];
+  evt->ts = btif_debug_ts();
+  evt->state = state;
+  evt->disconnect_reason = disconnect_reason;
+  memcpy(&evt->bda, &bda, sizeof(bt_bdaddr_t));
+}
+
+void btif_debug_conn_dump(int fd) {
+  const uint8_t current_event_local =
+      current_event;  // Cache to avoid threading issues
+  uint8_t dump_event = current_event_local;
+  char ts_buffer[TEMP_BUFFER_SIZE] = {0};
+  char name_buffer[TEMP_BUFFER_SIZE] = {0};
+
+  dprintf(fd, "\nConnection Events:\n");
+  if (connection_events[dump_event].ts == 0) dprintf(fd, "  None\n");
+
+  while (connection_events[dump_event].ts) {
+    conn_event_t* evt = &connection_events[dump_event];
+    dprintf(fd, "  %s %s %s", format_ts(evt->ts, ts_buffer, sizeof(ts_buffer)),
+            format_state(evt->state),
+            bdaddr_to_string(&evt->bda, name_buffer, sizeof(name_buffer)));
+    if (evt->state == BTIF_DEBUG_DISCONNECTED)
+      dprintf(fd, " reason=%d", evt->disconnect_reason);
+    dprintf(fd, "\n");
+
+    // Go to previous event; wrap if needed
+    if (dump_event > 0)
+      --dump_event;
+    else
+      dump_event = NUM_CONNECTION_EVENTS - 1;
+
+    // Check if we dumped all events
+    if (dump_event == current_event_local) break;
+  }
+}
diff --git a/bt/btif/src/btif_dm.cc b/bt/btif/src/btif_dm.cc
new file mode 100644
index 0000000..194ffa0
--- /dev/null
+++ b/bt/btif/src/btif_dm.cc
@@ -0,0 +1,3440 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ *  Filename:      btif_dm.c
+ *
+ *  Description:   Contains Device Management (DM) related functionality
+ *
+ *
+ ***********************************************************************************/
+
+#define LOG_TAG "bt_btif_dm"
+
+#include "btif_dm.h"
+
+#include <assert.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <mutex>
+
+#include <hardware/bluetooth.h>
+
+#include "bdaddr.h"
+#include "bt_common.h"
+#include "bta_gatt_api.h"
+#include "btif_api.h"
+#include "btif_config.h"
+#include "btif_hh.h"
+#include "btif_sdp.h"
+#include "btif_storage.h"
+#include "btif_util.h"
+#include "btu.h"
+#include "device/include/interop.h"
+#include "include/stack_config.h"
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+#include "osi/include/metrics.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+#include "stack/btm/btm_int.h"
+#include "stack_config.h"
+
+/******************************************************************************
+ *  Constants & Macros
+ *****************************************************************************/
+
+#define COD_MASK 0x07FF
+
+#define COD_UNCLASSIFIED ((0x1F) << 8)
+#define COD_HID_KEYBOARD 0x0540
+#define COD_HID_POINTING 0x0580
+#define COD_HID_COMBO 0x05C0
+#define COD_HID_MAJOR 0x0500
+#define COD_HID_MASK 0x0700
+#define COD_AV_HEADSETS 0x0404
+#define COD_AV_HANDSFREE 0x0408
+#define COD_AV_HEADPHONES 0x0418
+#define COD_AV_PORTABLE_AUDIO 0x041C
+#define COD_AV_HIFI_AUDIO 0x0428
+
+#define BTIF_DM_DEFAULT_INQ_MAX_RESULTS 0
+#define BTIF_DM_DEFAULT_INQ_MAX_DURATION 10
+#define BTIF_DM_MAX_SDP_ATTEMPTS_AFTER_PAIRING 2
+
+#define NUM_TIMEOUT_RETRIES 5
+
+#define PROPERTY_PRODUCT_MODEL "ro.product.model"
+#define DEFAULT_LOCAL_NAME_MAX 31
+#if (DEFAULT_LOCAL_NAME_MAX > BTM_MAX_LOC_BD_NAME_LEN)
+#error "default btif local name size exceeds stack supported length"
+#endif
+
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+#define BTIF_DM_INTERLEAVE_DURATION_BR_ONE 2
+#define BTIF_DM_INTERLEAVE_DURATION_LE_ONE 2
+#define BTIF_DM_INTERLEAVE_DURATION_BR_TWO 3
+#define BTIF_DM_INTERLEAVE_DURATION_LE_TWO 4
+#endif
+
+#define ENCRYPTED_BREDR 2
+#define ENCRYPTED_LE 4
+
+typedef struct {
+  bt_bond_state_t state;
+  bt_bdaddr_t static_bdaddr;
+  BD_ADDR bd_addr;
+  tBTM_BOND_TYPE bond_type;
+  uint8_t pin_code_len;
+  uint8_t is_ssp;
+  uint8_t auth_req;
+  uint8_t io_cap;
+  uint8_t autopair_attempts;
+  uint8_t timeout_retries;
+  uint8_t is_local_initiated;
+  uint8_t sdp_attempts;
+#if (BLE_INCLUDED == TRUE)
+  bool is_le_only;
+  bool is_le_nc; /* LE Numeric comparison */
+  btif_dm_ble_cb_t ble;
+#endif
+} btif_dm_pairing_cb_t;
+
+typedef struct {
+  uint8_t ir[BT_OCTET16_LEN];
+  uint8_t irk[BT_OCTET16_LEN];
+  uint8_t dhk[BT_OCTET16_LEN];
+} btif_dm_local_key_id_t;
+
+typedef struct {
+  bool is_er_rcvd;
+  uint8_t er[BT_OCTET16_LEN];
+  bool is_id_keys_rcvd;
+  btif_dm_local_key_id_t id_keys; /* ID kyes */
+
+} btif_dm_local_key_cb_t;
+
+typedef struct {
+  BD_ADDR bd_addr;
+  BD_NAME bd_name;
+} btif_dm_remote_name_t;
+
+/* this structure holds optional OOB data for remote device */
+typedef struct {
+  BD_ADDR bdaddr; /* peer bdaddr */
+  bt_out_of_band_data_t oob_data;
+} btif_dm_oob_cb_t;
+
+typedef struct {
+  bt_bdaddr_t bdaddr;
+  uint8_t transport; /* 0=Unknown, 1=BR/EDR, 2=LE */
+} btif_dm_create_bond_cb_t;
+
+typedef struct {
+  uint8_t status;
+  uint8_t ctrl_state;
+  uint64_t tx_time;
+  uint64_t rx_time;
+  uint64_t idle_time;
+  uint64_t energy_used;
+} btif_activity_energy_info_cb_t;
+
+typedef struct { unsigned int manufact_id; } skip_sdp_entry_t;
+
+typedef enum {
+  BTIF_DM_FUNC_CREATE_BOND,
+  BTIF_DM_FUNC_CANCEL_BOND,
+  BTIF_DM_FUNC_REMOVE_BOND,
+  BTIF_DM_FUNC_BOND_STATE_CHANGED,
+} bt_bond_function_t;
+
+typedef struct {
+  bt_bdaddr_t bd_addr;
+  bt_bond_function_t function;
+  bt_bond_state_t state;
+  struct timespec timestamp;
+} btif_bond_event_t;
+
+#define BTA_SERVICE_ID_TO_SERVICE_MASK(id) (1 << (id))
+
+#define UUID_HUMAN_INTERFACE_DEVICE "00001124-0000-1000-8000-00805f9b34fb"
+
+#define MAX_BTIF_BOND_EVENT_ENTRIES 15
+
+static skip_sdp_entry_t sdp_blacklist[] = {{76}};  // Apple Mouse and Keyboard
+
+/* This flag will be true if HCI_Inquiry is in progress */
+static bool btif_dm_inquiry_in_progress = false;
+
+/************************************************************************************
+ *  Static variables
+ ***********************************************************************************/
+static char btif_default_local_name[DEFAULT_LOCAL_NAME_MAX + 1] = {'\0'};
+static uid_set_t* uid_set = NULL;
+
+/* A circular array to keep track of the most recent bond events */
+static btif_bond_event_t btif_dm_bond_events[MAX_BTIF_BOND_EVENT_ENTRIES + 1];
+
+static std::mutex bond_event_lock;
+
+/* |btif_num_bond_events| keeps track of the total number of events and can be
+   greater than |MAX_BTIF_BOND_EVENT_ENTRIES| */
+static size_t btif_num_bond_events = 0;
+static size_t btif_events_start_index = 0;
+static size_t btif_events_end_index = 0;
+
+/******************************************************************************
+ *  Static functions
+ *****************************************************************************/
+static btif_dm_pairing_cb_t pairing_cb;
+static btif_dm_oob_cb_t oob_cb;
+static void btif_dm_generic_evt(uint16_t event, char* p_param);
+static void btif_dm_cb_create_bond(bt_bdaddr_t* bd_addr,
+                                   tBTA_TRANSPORT transport);
+static void btif_dm_cb_hid_remote_name(tBTM_REMOTE_DEV_NAME* p_remote_name);
+static void btif_update_remote_properties(BD_ADDR bd_addr, BD_NAME bd_name,
+                                          DEV_CLASS dev_class,
+                                          tBT_DEVICE_TYPE dev_type);
+#if (BLE_INCLUDED == TRUE)
+static btif_dm_local_key_cb_t ble_local_key_cb;
+static void btif_dm_ble_key_notif_evt(tBTA_DM_SP_KEY_NOTIF* p_ssp_key_notif);
+static void btif_dm_ble_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl);
+static void btif_dm_ble_passkey_req_evt(tBTA_DM_PIN_REQ* p_pin_req);
+static void btif_dm_ble_key_nc_req_evt(tBTA_DM_SP_KEY_NOTIF* p_notif_req);
+static void btif_dm_ble_oob_req_evt(tBTA_DM_SP_RMT_OOB* req_oob_type);
+static void btif_dm_ble_sc_oob_req_evt(tBTA_DM_SP_RMT_OOB* req_oob_type);
+#endif
+
+static void bte_scan_filt_param_cfg_evt(uint8_t action_type,
+                                        tBTA_DM_BLE_PF_AVBL_SPACE avbl_space,
+                                        tBTA_DM_BLE_REF_VALUE ref_value,
+                                        tBTA_STATUS status);
+
+static char* btif_get_default_local_name();
+
+static void btif_stats_add_bond_event(const bt_bdaddr_t* bd_addr,
+                                      bt_bond_function_t function,
+                                      bt_bond_state_t state);
+
+/******************************************************************************
+ *  Externs
+ *****************************************************************************/
+extern bt_status_t btif_hf_execute_service(bool b_enable);
+extern bt_status_t btif_av_execute_service(bool b_enable);
+extern bt_status_t btif_av_sink_execute_service(bool b_enable);
+extern bt_status_t btif_hh_execute_service(bool b_enable);
+extern bt_status_t btif_hf_client_execute_service(bool b_enable);
+extern bt_status_t btif_sdp_execute_service(bool b_enable);
+extern int btif_hh_connect(bt_bdaddr_t* bd_addr);
+extern void bta_gatt_convert_uuid16_to_uuid128(uint8_t uuid_128[LEN_UUID_128],
+                                               uint16_t uuid_16);
+extern void btif_av_move_idle(bt_bdaddr_t bd_addr);
+
+/******************************************************************************
+ *  Functions
+ *****************************************************************************/
+
+static bool is_empty_128bit(uint8_t* data) {
+  static const uint8_t zero[16] = {0};
+  return !memcmp(zero, data, sizeof(zero));
+}
+
+static void btif_dm_data_copy(uint16_t event, char* dst, char* src) {
+  tBTA_DM_SEC* dst_dm_sec = (tBTA_DM_SEC*)dst;
+  tBTA_DM_SEC* src_dm_sec = (tBTA_DM_SEC*)src;
+
+  if (!src_dm_sec) return;
+
+  assert(dst_dm_sec);
+  maybe_non_aligned_memcpy(dst_dm_sec, src_dm_sec, sizeof(*src_dm_sec));
+
+  if (event == BTA_DM_BLE_KEY_EVT) {
+    dst_dm_sec->ble_key.p_key_value =
+        (tBTM_LE_KEY_VALUE*)osi_malloc(sizeof(tBTM_LE_KEY_VALUE));
+    assert(src_dm_sec->ble_key.p_key_value);
+    memcpy(dst_dm_sec->ble_key.p_key_value, src_dm_sec->ble_key.p_key_value,
+           sizeof(tBTM_LE_KEY_VALUE));
+  }
+}
+
+static void btif_dm_data_free(uint16_t event, tBTA_DM_SEC* dm_sec) {
+  if (event == BTA_DM_BLE_KEY_EVT)
+    osi_free_and_reset((void**)&dm_sec->ble_key.p_key_value);
+}
+
+void btif_dm_init(uid_set_t* set) { uid_set = set; }
+
+void btif_dm_cleanup(void) {
+  if (uid_set) {
+    uid_set_destroy(uid_set);
+    uid_set = NULL;
+  }
+}
+
+bt_status_t btif_in_execute_service_request(tBTA_SERVICE_ID service_id,
+                                            bool b_enable) {
+  BTIF_TRACE_DEBUG("%s service_id: %d", __func__, service_id);
+  /* Check the service_ID and invoke the profile's BT state changed API */
+  switch (service_id) {
+    case BTA_HFP_SERVICE_ID:
+    case BTA_HSP_SERVICE_ID: {
+      btif_hf_execute_service(b_enable);
+    } break;
+    case BTA_A2DP_SOURCE_SERVICE_ID: {
+      btif_av_execute_service(b_enable);
+    } break;
+    case BTA_A2DP_SINK_SERVICE_ID: {
+      btif_av_sink_execute_service(b_enable);
+    } break;
+    case BTA_HID_SERVICE_ID: {
+      btif_hh_execute_service(b_enable);
+    } break;
+    case BTA_HFP_HS_SERVICE_ID: {
+      btif_hf_client_execute_service(b_enable);
+    } break;
+    case BTA_SDP_SERVICE_ID: {
+      btif_sdp_execute_service(b_enable);
+    } break;
+    default:
+      BTIF_TRACE_ERROR("%s: Unknown service %d being %s", __func__, service_id,
+                       (b_enable) ? "enabled" : "disabled");
+      return BT_STATUS_FAIL;
+  }
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         check_eir_remote_name
+ *
+ * Description      Check if remote name is in the EIR data
+ *
+ * Returns          true if remote name found
+ *                  Populate p_remote_name, if provided and remote name found
+ *
+ ******************************************************************************/
+static bool check_eir_remote_name(tBTA_DM_SEARCH* p_search_data,
+                                  uint8_t* p_remote_name,
+                                  uint8_t* p_remote_name_len) {
+  uint8_t* p_eir_remote_name = NULL;
+  uint8_t remote_name_len = 0;
+
+  /* Check EIR for remote name and services */
+  if (p_search_data->inq_res.p_eir) {
+    p_eir_remote_name =
+        BTM_CheckEirData(p_search_data->inq_res.p_eir,
+                         BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &remote_name_len);
+    if (!p_eir_remote_name) {
+      p_eir_remote_name =
+          BTM_CheckEirData(p_search_data->inq_res.p_eir,
+                           BTM_EIR_SHORTENED_LOCAL_NAME_TYPE, &remote_name_len);
+    }
+
+    if (p_eir_remote_name) {
+      if (remote_name_len > BD_NAME_LEN) remote_name_len = BD_NAME_LEN;
+
+      if (p_remote_name && p_remote_name_len) {
+        memcpy(p_remote_name, p_eir_remote_name, remote_name_len);
+        *(p_remote_name + remote_name_len) = 0;
+        *p_remote_name_len = remote_name_len;
+      }
+
+      return true;
+    }
+  }
+
+  return false;
+}
+
+/*******************************************************************************
+ *
+ * Function         check_cached_remote_name
+ *
+ * Description      Check if remote name is in the NVRAM cache
+ *
+ * Returns          true if remote name found
+ *                  Populate p_remote_name, if provided and remote name found
+ *
+ ******************************************************************************/
+static bool check_cached_remote_name(tBTA_DM_SEARCH* p_search_data,
+                                     uint8_t* p_remote_name,
+                                     uint8_t* p_remote_name_len) {
+  bt_bdname_t bdname;
+  bt_bdaddr_t remote_bdaddr;
+  bt_property_t prop_name;
+
+  /* check if we already have it in our btif_storage cache */
+  bdcpy(remote_bdaddr.address, p_search_data->inq_res.bd_addr);
+  BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_BDNAME,
+                             sizeof(bt_bdname_t), &bdname);
+  if (btif_storage_get_remote_device_property(&remote_bdaddr, &prop_name) ==
+      BT_STATUS_SUCCESS) {
+    if (p_remote_name && p_remote_name_len) {
+      strcpy((char*)p_remote_name, (char*)bdname.name);
+      *p_remote_name_len = strlen((char*)p_remote_name);
+    }
+    return true;
+  }
+
+  return false;
+}
+
+static uint32_t get_cod(const bt_bdaddr_t* remote_bdaddr) {
+  uint32_t remote_cod;
+  bt_property_t prop_name;
+
+  /* check if we already have it in our btif_storage cache */
+  BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_CLASS_OF_DEVICE,
+                             sizeof(uint32_t), &remote_cod);
+  if (btif_storage_get_remote_device_property(
+          (bt_bdaddr_t*)remote_bdaddr, &prop_name) == BT_STATUS_SUCCESS) {
+    LOG_INFO(LOG_TAG, "%s remote_cod = 0x%08x", __func__, remote_cod);
+    return remote_cod & COD_MASK;
+  }
+
+  return 0;
+}
+
+bool check_cod(const bt_bdaddr_t* remote_bdaddr, uint32_t cod) {
+  return get_cod(remote_bdaddr) == cod;
+}
+
+bool check_cod_hid(const bt_bdaddr_t* remote_bdaddr) {
+  return (get_cod(remote_bdaddr) & COD_HID_MASK) == COD_HID_MAJOR;
+}
+
+bool check_hid_le(const bt_bdaddr_t* remote_bdaddr) {
+  uint32_t remote_dev_type;
+  bt_property_t prop_name;
+
+  /* check if we already have it in our btif_storage cache */
+  BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_TYPE_OF_DEVICE,
+                             sizeof(uint32_t), &remote_dev_type);
+  if (btif_storage_get_remote_device_property(
+          (bt_bdaddr_t*)remote_bdaddr, &prop_name) == BT_STATUS_SUCCESS) {
+    if (remote_dev_type == BT_DEVICE_DEVTYPE_BLE) {
+      bdstr_t bdstr;
+      bdaddr_to_string(remote_bdaddr, bdstr, sizeof(bdstr));
+      if (btif_config_exist(bdstr, "HidAppId")) return true;
+    }
+  }
+  return false;
+}
+
+/*****************************************************************************
+ *
+ * Function        check_sdp_bl
+ *
+ * Description     Checks if a given device is blacklisted to skip sdp
+ *
+ * Parameters     skip_sdp_entry
+ *
+ * Returns         true if the device is present in blacklist, else false
+ *
+ ******************************************************************************/
+bool check_sdp_bl(const bt_bdaddr_t* remote_bdaddr) {
+  uint16_t manufacturer = 0;
+  uint8_t lmp_ver = 0;
+  uint16_t lmp_subver = 0;
+  bt_property_t prop_name;
+  bt_remote_version_t info;
+
+  if (remote_bdaddr == NULL) return false;
+
+  /* fetch additional info about remote device used in iop query */
+  BTM_ReadRemoteVersion(*(BD_ADDR*)remote_bdaddr, &lmp_ver, &manufacturer,
+                        &lmp_subver);
+
+  /* if not available yet, try fetching from config database */
+  BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_REMOTE_VERSION_INFO,
+                             sizeof(bt_remote_version_t), &info);
+
+  if (btif_storage_get_remote_device_property(
+          (bt_bdaddr_t*)remote_bdaddr, &prop_name) != BT_STATUS_SUCCESS) {
+    return false;
+  }
+  manufacturer = info.manufacturer;
+
+  for (unsigned int i = 0; i < ARRAY_SIZE(sdp_blacklist); i++) {
+    if (manufacturer == sdp_blacklist[i].manufact_id) return true;
+  }
+  return false;
+}
+
+static void bond_state_changed(bt_status_t status, bt_bdaddr_t* bd_addr,
+                               bt_bond_state_t state) {
+  btif_stats_add_bond_event(bd_addr, BTIF_DM_FUNC_BOND_STATE_CHANGED, state);
+
+  // Send bonding state only once - based on outgoing/incoming we may receive
+  // duplicates
+  if ((pairing_cb.state == state) && (state == BT_BOND_STATE_BONDING)) {
+    // Cross key pairing so send callback for static address
+    if (!bdaddr_is_empty(&pairing_cb.static_bdaddr)) {
+      HAL_CBACK(bt_hal_cbacks, bond_state_changed_cb, status, bd_addr, state);
+    }
+    return;
+  }
+
+  if (pairing_cb.bond_type == BOND_TYPE_TEMPORARY) state = BT_BOND_STATE_NONE;
+
+  BTIF_TRACE_DEBUG("%s: state=%d, prev_state=%d, sdp_attempts = %d", __func__,
+                   state, pairing_cb.state, pairing_cb.sdp_attempts);
+
+  HAL_CBACK(bt_hal_cbacks, bond_state_changed_cb, status, bd_addr, state);
+
+  if (state == BT_BOND_STATE_BONDING) {
+    pairing_cb.state = state;
+    bdcpy(pairing_cb.bd_addr, bd_addr->address);
+  } else {
+    if (!pairing_cb.sdp_attempts)
+      memset(&pairing_cb, 0, sizeof(pairing_cb));
+    else
+      BTIF_TRACE_DEBUG("%s: BR-EDR service discovery active", __func__);
+  }
+}
+
+/* store remote version in bt config to always have access
+   to it post pairing*/
+static void btif_update_remote_version_property(bt_bdaddr_t* p_bd) {
+  bt_property_t property;
+  uint8_t lmp_ver = 0;
+  uint16_t lmp_subver = 0;
+  uint16_t mfct_set = 0;
+  tBTM_STATUS btm_status;
+  bt_remote_version_t info;
+  bt_status_t status;
+  bdstr_t bdstr;
+
+  btm_status =
+      BTM_ReadRemoteVersion(*(BD_ADDR*)p_bd, &lmp_ver, &mfct_set, &lmp_subver);
+
+  LOG_DEBUG(LOG_TAG, "remote version info [%s]: %x, %x, %x",
+            bdaddr_to_string(p_bd, bdstr, sizeof(bdstr)), lmp_ver, mfct_set,
+            lmp_subver);
+
+  if (btm_status == BTM_SUCCESS) {
+    // Always update cache to ensure we have availability whenever BTM API is
+    // not populated
+    info.manufacturer = mfct_set;
+    info.sub_ver = lmp_subver;
+    info.version = lmp_ver;
+    BTIF_STORAGE_FILL_PROPERTY(&property, BT_PROPERTY_REMOTE_VERSION_INFO,
+                               sizeof(bt_remote_version_t), &info);
+    status = btif_storage_set_remote_device_property(p_bd, &property);
+    ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote version",
+            status);
+  }
+}
+
+static void btif_update_remote_properties(BD_ADDR bd_addr, BD_NAME bd_name,
+                                          DEV_CLASS dev_class,
+                                          tBT_DEVICE_TYPE device_type) {
+  int num_properties = 0;
+  bt_property_t properties[3];
+  bt_bdaddr_t bdaddr;
+  bt_status_t status;
+  uint32_t cod;
+  bt_device_type_t dev_type;
+
+  memset(properties, 0, sizeof(properties));
+  bdcpy(bdaddr.address, bd_addr);
+
+  /* remote name */
+  if (strlen((const char*)bd_name)) {
+    BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties], BT_PROPERTY_BDNAME,
+                               strlen((char*)bd_name), bd_name);
+    status = btif_storage_set_remote_device_property(
+        &bdaddr, &properties[num_properties]);
+    ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device name",
+            status);
+    num_properties++;
+  }
+
+  /* class of device */
+  cod = devclass2uint(dev_class);
+  BTIF_TRACE_DEBUG("%s cod is 0x%06x", __func__, cod);
+  if (cod == 0) {
+    /* Try to retrieve cod from storage */
+    BTIF_TRACE_DEBUG("%s cod is 0, checking cod from storage", __func__);
+    BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+                               BT_PROPERTY_CLASS_OF_DEVICE, sizeof(cod), &cod);
+    status = btif_storage_get_remote_device_property(
+        &bdaddr, &properties[num_properties]);
+    BTIF_TRACE_DEBUG("%s cod retrieved from storage is 0x%06x", __func__, cod);
+    if (cod == 0) {
+      BTIF_TRACE_DEBUG("%s cod is again 0, set as unclassified", __func__);
+      cod = COD_UNCLASSIFIED;
+    }
+  }
+
+  BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+                             BT_PROPERTY_CLASS_OF_DEVICE, sizeof(cod), &cod);
+  status = btif_storage_set_remote_device_property(&bdaddr,
+                                                   &properties[num_properties]);
+  ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device class",
+          status);
+  num_properties++;
+
+  /* device type */
+  bt_property_t prop_name;
+  uint8_t remote_dev_type;
+  BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_TYPE_OF_DEVICE,
+                             sizeof(uint8_t), &remote_dev_type);
+  if (btif_storage_get_remote_device_property(&bdaddr, &prop_name) ==
+      BT_STATUS_SUCCESS)
+    dev_type = (bt_device_type_t)(remote_dev_type | device_type);
+  else
+    dev_type = (bt_device_type_t)device_type;
+
+  BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+                             BT_PROPERTY_TYPE_OF_DEVICE, sizeof(dev_type),
+                             &dev_type);
+  status = btif_storage_set_remote_device_property(&bdaddr,
+                                                   &properties[num_properties]);
+  ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device type",
+          status);
+  num_properties++;
+
+  HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, status, &bdaddr,
+            num_properties, properties);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_cb_hid_remote_name
+ *
+ * Description      Remote name callback for HID device. Called in btif context
+ *                  Special handling for HID devices
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_dm_cb_hid_remote_name(tBTM_REMOTE_DEV_NAME* p_remote_name) {
+  BTIF_TRACE_DEBUG("%s: status=%d pairing_cb.state=%d", __func__,
+                   p_remote_name->status, pairing_cb.state);
+  if (pairing_cb.state == BT_BOND_STATE_BONDING) {
+    bt_bdaddr_t remote_bd;
+
+    bdcpy(remote_bd.address, pairing_cb.bd_addr);
+
+    if (p_remote_name->status == BTM_SUCCESS) {
+      bond_state_changed(BT_STATUS_SUCCESS, &remote_bd, BT_BOND_STATE_BONDED);
+    } else
+      bond_state_changed(BT_STATUS_FAIL, &remote_bd, BT_BOND_STATE_NONE);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_cb_create_bond
+ *
+ * Description      Create bond initiated from the BTIF thread context
+ *                  Special handling for HID devices
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_dm_cb_create_bond(bt_bdaddr_t* bd_addr,
+                                   tBTA_TRANSPORT transport) {
+  bool is_hid = check_cod(bd_addr, COD_HID_POINTING);
+  bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDING);
+
+#if (BLE_INCLUDED == TRUE)
+  int device_type;
+  int addr_type;
+  bdstr_t bdstr;
+  bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr));
+  if (transport == BT_TRANSPORT_LE) {
+    if (!btif_config_get_int((char const*)&bdstr, "DevType", &device_type)) {
+      btif_config_set_int(bdstr, "DevType", BT_DEVICE_TYPE_BLE);
+    }
+    if (btif_storage_get_remote_addr_type(bd_addr, &addr_type) !=
+        BT_STATUS_SUCCESS) {
+
+      // Try to read address type. OOB pairing might have set it earlier, but
+      // didn't store it, it defaults to BLE_ADDR_PUBLIC
+      uint8_t tmp_dev_type;
+      uint8_t tmp_addr_type;
+      BTM_ReadDevInfo(bd_addr->address, &tmp_dev_type, &tmp_addr_type);
+      addr_type = tmp_addr_type;
+
+      btif_storage_set_remote_addr_type(bd_addr, addr_type);
+    }
+  }
+  if ((btif_config_get_int((char const*)&bdstr, "DevType", &device_type) &&
+       (btif_storage_get_remote_addr_type(bd_addr, &addr_type) ==
+        BT_STATUS_SUCCESS) &&
+       (device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE) ||
+      (transport == BT_TRANSPORT_LE)) {
+    BTA_DmAddBleDevice(bd_addr->address, addr_type, device_type);
+  }
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+  if (is_hid && (device_type & BT_DEVICE_TYPE_BLE) == 0)
+#else
+  if (is_hid)
+#endif
+  {
+    bt_status_t status;
+    status = (bt_status_t)btif_hh_connect(bd_addr);
+    if (status != BT_STATUS_SUCCESS)
+      bond_state_changed(status, bd_addr, BT_BOND_STATE_NONE);
+  } else {
+    BTA_DmBondByTransport((uint8_t*)bd_addr->address, transport);
+  }
+  /*  Track  originator of bond creation  */
+  pairing_cb.is_local_initiated = true;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_cb_remove_bond
+ *
+ * Description      remove bond initiated from the BTIF thread context
+ *                  Special handling for HID devices
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btif_dm_cb_remove_bond(bt_bdaddr_t* bd_addr) {
+/*special handling for HID devices */
+/*  VUP needs to be sent if its a HID Device. The HID HOST module will check if
+there
+is a valid hid connection with this bd_addr. If yes VUP will be issued.*/
+#if (BTA_HH_INCLUDED == TRUE)
+  if (btif_hh_virtual_unplug(bd_addr) != BT_STATUS_SUCCESS)
+#endif
+  {
+    BTIF_TRACE_DEBUG("%s: Removing HH device", __func__);
+    BTA_DmRemoveDevice((uint8_t*)bd_addr->address);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_get_connection_state
+ *
+ * Description      Returns whether the remote device is currently connected
+ *                  and whether encryption is active for the connection
+ *
+ * Returns          0 if not connected; 1 if connected and > 1 if connection is
+ *                  encrypted
+ *
+ ******************************************************************************/
+uint16_t btif_dm_get_connection_state(const bt_bdaddr_t* bd_addr) {
+  uint8_t* bda = (uint8_t*)bd_addr->address;
+  uint16_t rc = BTA_DmGetConnectionState(bda);
+
+  if (rc != 0) {
+    uint8_t flags = 0;
+
+    BTM_GetSecurityFlagsByTransport(bda, &flags, BT_TRANSPORT_BR_EDR);
+    BTIF_TRACE_DEBUG("%s: security flags (BR/EDR)=0x%02x", __func__, flags);
+    if (flags & BTM_SEC_FLAG_ENCRYPTED) rc |= ENCRYPTED_BREDR;
+
+    BTM_GetSecurityFlagsByTransport(bda, &flags, BT_TRANSPORT_LE);
+    BTIF_TRACE_DEBUG("%s: security flags (LE)=0x%02x", __func__, flags);
+    if (flags & BTM_SEC_FLAG_ENCRYPTED) rc |= ENCRYPTED_LE;
+  }
+
+  return rc;
+}
+
+/*******************************************************************************
+ *
+ * Function         search_devices_copy_cb
+ *
+ * Description      Deep copy callback for search devices event
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void search_devices_copy_cb(uint16_t event, char* p_dest, char* p_src) {
+  tBTA_DM_SEARCH* p_dest_data = (tBTA_DM_SEARCH*)p_dest;
+  tBTA_DM_SEARCH* p_src_data = (tBTA_DM_SEARCH*)p_src;
+
+  if (!p_src) return;
+
+  BTIF_TRACE_DEBUG("%s: event=%s", __func__, dump_dm_search_event(event));
+  maybe_non_aligned_memcpy(p_dest_data, p_src_data, sizeof(*p_src_data));
+  switch (event) {
+    case BTA_DM_INQ_RES_EVT: {
+      if (p_src_data->inq_res.p_eir) {
+        p_dest_data->inq_res.p_eir =
+            (uint8_t*)(p_dest + sizeof(tBTA_DM_SEARCH));
+        memcpy(p_dest_data->inq_res.p_eir, p_src_data->inq_res.p_eir,
+               HCI_EXT_INQ_RESPONSE_LEN);
+      }
+    } break;
+
+    case BTA_DM_DISC_RES_EVT: {
+      if (p_src_data->disc_res.raw_data_size &&
+          p_src_data->disc_res.p_raw_data) {
+        p_dest_data->disc_res.p_raw_data =
+            (uint8_t*)(p_dest + sizeof(tBTA_DM_SEARCH));
+        memcpy(p_dest_data->disc_res.p_raw_data,
+               p_src_data->disc_res.p_raw_data,
+               p_src_data->disc_res.raw_data_size);
+      }
+    } break;
+  }
+}
+
+static void search_services_copy_cb(uint16_t event, char* p_dest, char* p_src) {
+  tBTA_DM_SEARCH* p_dest_data = (tBTA_DM_SEARCH*)p_dest;
+  tBTA_DM_SEARCH* p_src_data = (tBTA_DM_SEARCH*)p_src;
+
+  if (!p_src) return;
+  maybe_non_aligned_memcpy(p_dest_data, p_src_data, sizeof(*p_src_data));
+  switch (event) {
+    case BTA_DM_DISC_RES_EVT: {
+      if (p_src_data->disc_res.result == BTA_SUCCESS) {
+        if (p_src_data->disc_res.num_uuids > 0) {
+          p_dest_data->disc_res.p_uuid_list =
+              (uint8_t*)(p_dest + sizeof(tBTA_DM_SEARCH));
+          memcpy(p_dest_data->disc_res.p_uuid_list,
+                 p_src_data->disc_res.p_uuid_list,
+                 p_src_data->disc_res.num_uuids * MAX_UUID_SIZE);
+          osi_free_and_reset((void**)&p_src_data->disc_res.p_uuid_list);
+        }
+        osi_free_and_reset((void**)&p_src_data->disc_res.p_raw_data);
+      }
+    } break;
+  }
+}
+/******************************************************************************
+ *
+ *  BTIF DM callback events
+ *
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_pin_req_evt
+ *
+ * Description      Executes pin request event in btif context
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_dm_pin_req_evt(tBTA_DM_PIN_REQ* p_pin_req) {
+  bt_bdaddr_t bd_addr;
+  bt_bdname_t bd_name;
+  uint32_t cod;
+  bt_pin_code_t pin_code;
+  int dev_type;
+
+  /* Remote properties update */
+  if (!btif_get_device_type(p_pin_req->bd_addr, &dev_type)) {
+    dev_type = BT_DEVICE_TYPE_BREDR;
+  }
+  btif_update_remote_properties(p_pin_req->bd_addr, p_pin_req->bd_name,
+                                p_pin_req->dev_class,
+                                (tBT_DEVICE_TYPE)dev_type);
+
+  bdcpy(bd_addr.address, p_pin_req->bd_addr);
+  memcpy(bd_name.name, p_pin_req->bd_name, BD_NAME_LEN);
+
+  bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+
+  cod = devclass2uint(p_pin_req->dev_class);
+
+  if (cod == 0) {
+    BTIF_TRACE_DEBUG("%s cod is 0, set as unclassified", __func__);
+    cod = COD_UNCLASSIFIED;
+  }
+
+  /* check for auto pair possiblity only if bond was initiated by local device
+   */
+  if (pairing_cb.is_local_initiated && (p_pin_req->min_16_digit == false)) {
+    if (check_cod(&bd_addr, COD_AV_HEADSETS) ||
+        check_cod(&bd_addr, COD_AV_HEADPHONES) ||
+        check_cod(&bd_addr, COD_AV_PORTABLE_AUDIO) ||
+        check_cod(&bd_addr, COD_AV_HIFI_AUDIO) ||
+        check_cod(&bd_addr, COD_HID_POINTING)) {
+      /*  Check if this device can be auto paired  */
+      if (!interop_match_addr(INTEROP_DISABLE_AUTO_PAIRING, &bd_addr) &&
+          !interop_match_name(INTEROP_DISABLE_AUTO_PAIRING,
+                              (const char*)bd_name.name) &&
+          (pairing_cb.autopair_attempts == 0)) {
+        BTIF_TRACE_DEBUG("%s() Attempting auto pair", __func__);
+        pin_code.pin[0] = 0x30;
+        pin_code.pin[1] = 0x30;
+        pin_code.pin[2] = 0x30;
+        pin_code.pin[3] = 0x30;
+
+        pairing_cb.autopair_attempts++;
+        BTA_DmPinReply((uint8_t*)bd_addr.address, true, 4, pin_code.pin);
+        return;
+      }
+    } else if (check_cod(&bd_addr, COD_HID_KEYBOARD) ||
+               check_cod(&bd_addr, COD_HID_COMBO)) {
+      if ((interop_match_addr(INTEROP_KEYBOARD_REQUIRES_FIXED_PIN, &bd_addr) ==
+           true) &&
+          (pairing_cb.autopair_attempts == 0)) {
+        BTIF_TRACE_DEBUG("%s() Attempting auto pair", __func__);
+        pin_code.pin[0] = 0x30;
+        pin_code.pin[1] = 0x30;
+        pin_code.pin[2] = 0x30;
+        pin_code.pin[3] = 0x30;
+
+        pairing_cb.autopair_attempts++;
+        BTA_DmPinReply((uint8_t*)bd_addr.address, true, 4, pin_code.pin);
+        return;
+      }
+    }
+  }
+  HAL_CBACK(bt_hal_cbacks, pin_request_cb, &bd_addr, &bd_name, cod,
+            p_pin_req->min_16_digit);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_ssp_cfm_req_evt
+ *
+ * Description      Executes SSP confirm request event in btif context
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_dm_ssp_cfm_req_evt(tBTA_DM_SP_CFM_REQ* p_ssp_cfm_req) {
+  bt_bdaddr_t bd_addr;
+  bt_bdname_t bd_name;
+  uint32_t cod;
+  bool is_incoming = !(pairing_cb.state == BT_BOND_STATE_BONDING);
+  int dev_type;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  /* Remote properties update */
+  if (!btif_get_device_type(p_ssp_cfm_req->bd_addr, &dev_type)) {
+    dev_type = BT_DEVICE_TYPE_BREDR;
+  }
+  btif_update_remote_properties(p_ssp_cfm_req->bd_addr, p_ssp_cfm_req->bd_name,
+                                p_ssp_cfm_req->dev_class,
+                                (tBT_DEVICE_TYPE)dev_type);
+
+  bdcpy(bd_addr.address, p_ssp_cfm_req->bd_addr);
+  memcpy(bd_name.name, p_ssp_cfm_req->bd_name, BD_NAME_LEN);
+
+  /* Set the pairing_cb based on the local & remote authentication requirements
+   */
+  bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+
+  /* if just_works and bonding bit is not set treat this as temporary */
+  if (p_ssp_cfm_req->just_works &&
+      !(p_ssp_cfm_req->loc_auth_req & BTM_AUTH_BONDS) &&
+      !(p_ssp_cfm_req->rmt_auth_req & BTM_AUTH_BONDS) &&
+      !(check_cod((bt_bdaddr_t*)&p_ssp_cfm_req->bd_addr, COD_HID_POINTING)))
+    pairing_cb.bond_type = BOND_TYPE_TEMPORARY;
+  else
+    pairing_cb.bond_type = BOND_TYPE_PERSISTENT;
+
+  btm_set_bond_type_dev(p_ssp_cfm_req->bd_addr, pairing_cb.bond_type);
+
+  pairing_cb.is_ssp = true;
+
+  /* If JustWorks auto-accept */
+  if (p_ssp_cfm_req->just_works) {
+    /* Pairing consent for JustWorks needed if:
+     * 1. Incoming (non-temporary) pairing is detected AND
+     * 2. local IO capabilities are DisplayYesNo AND
+     * 3. remote IO capabiltiies are DisplayOnly or NoInputNoOutput;
+     */
+    if (is_incoming && pairing_cb.bond_type != BOND_TYPE_TEMPORARY &&
+        ((p_ssp_cfm_req->loc_io_caps == HCI_IO_CAP_DISPLAY_YESNO) &&
+         (p_ssp_cfm_req->rmt_io_caps == HCI_IO_CAP_DISPLAY_ONLY ||
+          p_ssp_cfm_req->rmt_io_caps == HCI_IO_CAP_NO_IO))) {
+      BTIF_TRACE_EVENT(
+          "%s: User consent needed for incoming pairing request. loc_io_caps: "
+          "%d, rmt_io_caps: %d",
+          __func__, p_ssp_cfm_req->loc_io_caps, p_ssp_cfm_req->rmt_io_caps);
+    } else {
+      BTIF_TRACE_EVENT("%s: Auto-accept JustWorks pairing", __func__);
+      btif_dm_ssp_reply(&bd_addr, BT_SSP_VARIANT_CONSENT, true, 0);
+      return;
+    }
+  }
+
+  cod = devclass2uint(p_ssp_cfm_req->dev_class);
+
+  if (cod == 0) {
+    LOG_DEBUG(LOG_TAG, "%s cod is 0, set as unclassified", __func__);
+    cod = COD_UNCLASSIFIED;
+  }
+
+  pairing_cb.sdp_attempts = 0;
+  HAL_CBACK(bt_hal_cbacks, ssp_request_cb, &bd_addr, &bd_name, cod,
+            (p_ssp_cfm_req->just_works ? BT_SSP_VARIANT_CONSENT
+                                       : BT_SSP_VARIANT_PASSKEY_CONFIRMATION),
+            p_ssp_cfm_req->num_val);
+}
+
+static void btif_dm_ssp_key_notif_evt(tBTA_DM_SP_KEY_NOTIF* p_ssp_key_notif) {
+  bt_bdaddr_t bd_addr;
+  bt_bdname_t bd_name;
+  uint32_t cod;
+  int dev_type;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  /* Remote properties update */
+  if (!btif_get_device_type(p_ssp_key_notif->bd_addr, &dev_type)) {
+    dev_type = BT_DEVICE_TYPE_BREDR;
+  }
+  btif_update_remote_properties(
+      p_ssp_key_notif->bd_addr, p_ssp_key_notif->bd_name,
+      p_ssp_key_notif->dev_class, (tBT_DEVICE_TYPE)dev_type);
+
+  bdcpy(bd_addr.address, p_ssp_key_notif->bd_addr);
+  memcpy(bd_name.name, p_ssp_key_notif->bd_name, BD_NAME_LEN);
+
+  bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+  pairing_cb.is_ssp = true;
+  cod = devclass2uint(p_ssp_key_notif->dev_class);
+
+  if (cod == 0) {
+    LOG_DEBUG(LOG_TAG, "%s cod is 0, set as unclassified", __func__);
+    cod = COD_UNCLASSIFIED;
+  }
+
+  HAL_CBACK(bt_hal_cbacks, ssp_request_cb, &bd_addr, &bd_name, cod,
+            BT_SSP_VARIANT_PASSKEY_NOTIFICATION, p_ssp_key_notif->passkey);
+}
+/*******************************************************************************
+ *
+ * Function         btif_dm_auth_cmpl_evt
+ *
+ * Description      Executes authentication complete event in btif context
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_dm_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) {
+  /* Save link key, if not temporary */
+  bt_bdaddr_t bd_addr;
+  bt_status_t status = BT_STATUS_FAIL;
+  bt_bond_state_t state = BT_BOND_STATE_NONE;
+  bool skip_sdp = false;
+
+  BTIF_TRACE_DEBUG("%s: bond state=%d", __func__, pairing_cb.state);
+
+  bdcpy(bd_addr.address, p_auth_cmpl->bd_addr);
+  if ((p_auth_cmpl->success == true) && (p_auth_cmpl->key_present)) {
+    if ((p_auth_cmpl->key_type < HCI_LKEY_TYPE_DEBUG_COMB) ||
+        (p_auth_cmpl->key_type == HCI_LKEY_TYPE_AUTH_COMB) ||
+        (p_auth_cmpl->key_type == HCI_LKEY_TYPE_CHANGED_COMB) ||
+        (p_auth_cmpl->key_type == HCI_LKEY_TYPE_AUTH_COMB_P_256) ||
+        pairing_cb.bond_type == BOND_TYPE_PERSISTENT) {
+      bt_status_t ret;
+      BTIF_TRACE_DEBUG("%s: Storing link key. key_type=0x%x, bond_type=%d",
+                       __func__, p_auth_cmpl->key_type, pairing_cb.bond_type);
+      ret = btif_storage_add_bonded_device(&bd_addr, p_auth_cmpl->key,
+                                           p_auth_cmpl->key_type,
+                                           pairing_cb.pin_code_len);
+      ASSERTC(ret == BT_STATUS_SUCCESS, "storing link key failed", ret);
+    } else {
+      BTIF_TRACE_DEBUG(
+          "%s: Temporary key. Not storing. key_type=0x%x, bond_type=%d",
+          __func__, p_auth_cmpl->key_type, pairing_cb.bond_type);
+      if (pairing_cb.bond_type == BOND_TYPE_TEMPORARY) {
+        BTIF_TRACE_DEBUG("%s: sending BT_BOND_STATE_NONE for Temp pairing",
+                         __func__);
+        btif_storage_remove_bonded_device(&bd_addr);
+        bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_NONE);
+        return;
+      }
+    }
+  }
+
+  // We could have received a new link key without going through the pairing
+  // flow.  If so, we don't want to perform SDP or any other operations on the
+  // authenticated device. Also, make sure that the link key is not derived from
+  // secure LTK, because we will need to perform SDP in case of link key
+  // derivation to allow bond state change notification for the BR/EDR transport
+  // so that the subsequent BR/EDR connections to the remote can use the derived
+  // link key.
+  if ((bdcmp(p_auth_cmpl->bd_addr, pairing_cb.bd_addr) != 0) &&
+      (!pairing_cb.ble.is_penc_key_rcvd)) {
+    char address[32];
+    bt_bdaddr_t bt_bdaddr;
+
+    memcpy(bt_bdaddr.address, p_auth_cmpl->bd_addr, sizeof(bt_bdaddr.address));
+    bdaddr_to_string(&bt_bdaddr, address, sizeof(address));
+    LOG_INFO(LOG_TAG,
+             "%s skipping SDP since we did not initiate pairing to %s.",
+             __func__, address);
+    return;
+  }
+
+  // Skip SDP for certain  HID Devices
+  if (p_auth_cmpl->success) {
+#if (BLE_INCLUDED == TRUE)
+    btif_storage_set_remote_addr_type(&bd_addr, p_auth_cmpl->addr_type);
+#endif
+    btif_update_remote_properties(p_auth_cmpl->bd_addr, p_auth_cmpl->bd_name,
+                                  NULL, p_auth_cmpl->dev_type);
+    pairing_cb.timeout_retries = 0;
+    status = BT_STATUS_SUCCESS;
+    state = BT_BOND_STATE_BONDED;
+    bdcpy(bd_addr.address, p_auth_cmpl->bd_addr);
+
+    if (check_sdp_bl(&bd_addr) && check_cod_hid(&bd_addr)) {
+      LOG_WARN(LOG_TAG, "%s:skip SDP", __func__);
+      skip_sdp = true;
+    }
+    if (!pairing_cb.is_local_initiated && skip_sdp) {
+      bond_state_changed(status, &bd_addr, state);
+
+      LOG_WARN(LOG_TAG, "%s: Incoming HID Connection", __func__);
+      bt_property_t prop;
+      bt_bdaddr_t bd_addr;
+      bt_uuid_t uuid;
+      char uuid_str[128] = UUID_HUMAN_INTERFACE_DEVICE;
+
+      string_to_uuid(uuid_str, &uuid);
+
+      prop.type = BT_PROPERTY_UUIDS;
+      prop.val = uuid.uu;
+      prop.len = MAX_UUID_SIZE;
+
+      /* Send the event to the BTIF */
+      HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, BT_STATUS_SUCCESS,
+                &bd_addr, 1, &prop);
+    } else {
+#if (BLE_INCLUDED == TRUE)
+      bool is_crosskey = false;
+      /* If bonded due to cross-key, save the static address too*/
+      if (pairing_cb.state == BT_BOND_STATE_BONDING &&
+          (bdcmp(p_auth_cmpl->bd_addr, pairing_cb.bd_addr) != 0)) {
+        BTIF_TRACE_DEBUG(
+            "%s: bonding initiated due to cross key, adding static address",
+            __func__);
+        bdcpy(pairing_cb.static_bdaddr.address, p_auth_cmpl->bd_addr);
+        is_crosskey = true;
+      }
+      if (!is_crosskey ||
+          !(stack_config_get_interface()->get_pts_crosskey_sdp_disable())) {
+#endif
+
+        // Ensure inquiry is stopped before attempting service discovery
+        btif_dm_cancel_discovery();
+
+        /* Trigger SDP on the device */
+        pairing_cb.sdp_attempts = 1;
+        btif_dm_get_remote_services(&bd_addr);
+#if (BLE_INCLUDED == TRUE)
+      }
+#endif
+    }
+    // Do not call bond_state_changed_cb yet. Wait until remote service
+    // discovery is complete
+  } else {
+    // Map the HCI fail reason  to  bt status
+    switch (p_auth_cmpl->fail_reason) {
+      case HCI_ERR_PAGE_TIMEOUT:
+        if (interop_match_addr(INTEROP_AUTO_RETRY_PAIRING, &bd_addr) &&
+            pairing_cb.timeout_retries) {
+          BTIF_TRACE_WARNING("%s() - Pairing timeout; retrying (%d) ...",
+                             __func__, pairing_cb.timeout_retries);
+          --pairing_cb.timeout_retries;
+          btif_dm_cb_create_bond(&bd_addr, BTA_TRANSPORT_UNKNOWN);
+          return;
+        }
+      /* Fall-through */
+      case HCI_ERR_CONNECTION_TOUT:
+        status = BT_STATUS_RMT_DEV_DOWN;
+        break;
+
+      case HCI_ERR_PAIRING_NOT_ALLOWED:
+        btif_storage_remove_bonded_device(&bd_addr);
+        status = BT_STATUS_AUTH_REJECTED;
+        break;
+
+      case HCI_ERR_LMP_RESPONSE_TIMEOUT:
+        status = BT_STATUS_AUTH_FAILURE;
+        break;
+
+      /* map the auth failure codes, so we can retry pairing if necessary */
+      case HCI_ERR_AUTH_FAILURE:
+      case HCI_ERR_KEY_MISSING:
+        btif_storage_remove_bonded_device(&bd_addr);
+      case HCI_ERR_HOST_REJECT_SECURITY:
+      case HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE:
+      case HCI_ERR_UNIT_KEY_USED:
+      case HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED:
+      case HCI_ERR_INSUFFCIENT_SECURITY:
+      case HCI_ERR_PEER_USER:
+      case HCI_ERR_UNSPECIFIED:
+        BTIF_TRACE_DEBUG(" %s() Authentication fail reason %d", __func__,
+                         p_auth_cmpl->fail_reason);
+        if (pairing_cb.autopair_attempts == 1) {
+          /* Create the Bond once again */
+          BTIF_TRACE_WARNING("%s() auto pair failed. Reinitiate Bond",
+                             __func__);
+          btif_dm_cb_create_bond(&bd_addr, BTA_TRANSPORT_UNKNOWN);
+          return;
+        } else {
+          /* if autopair attempts are more than 1, or not attempted */
+          status = BT_STATUS_AUTH_FAILURE;
+        }
+        break;
+
+      default:
+        status = BT_STATUS_FAIL;
+    }
+    /* Special Handling for HID Devices */
+    if (check_cod(&bd_addr, COD_HID_POINTING)) {
+      /* Remove Device as bonded in nvram as authentication failed */
+      BTIF_TRACE_DEBUG("%s(): removing hid pointing device from nvram",
+                       __func__);
+      btif_storage_remove_bonded_device(&bd_addr);
+    }
+    bond_state_changed(status, &bd_addr, state);
+  }
+}
+
+/******************************************************************************
+ *
+ * Function         btif_dm_search_devices_evt
+ *
+ * Description      Executes search devices callback events in btif context
+ *
+ * Returns          void
+ *
+ *****************************************************************************/
+static void btif_dm_search_devices_evt(uint16_t event, char* p_param) {
+  tBTA_DM_SEARCH* p_search_data;
+  BTIF_TRACE_EVENT("%s event=%s", __func__, dump_dm_search_event(event));
+
+  switch (event) {
+    case BTA_DM_DISC_RES_EVT: {
+      p_search_data = (tBTA_DM_SEARCH*)p_param;
+      /* Remote name update */
+      if (strlen((const char*)p_search_data->disc_res.bd_name)) {
+        bt_property_t properties[1];
+        bt_bdaddr_t bdaddr;
+        bt_status_t status;
+
+        properties[0].type = BT_PROPERTY_BDNAME;
+        properties[0].val = p_search_data->disc_res.bd_name;
+        properties[0].len = strlen((char*)p_search_data->disc_res.bd_name);
+        bdcpy(bdaddr.address, p_search_data->disc_res.bd_addr);
+
+        status =
+            btif_storage_set_remote_device_property(&bdaddr, &properties[0]);
+        ASSERTC(status == BT_STATUS_SUCCESS,
+                "failed to save remote device property", status);
+        HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, status, &bdaddr,
+                  1, properties);
+      }
+      /* TODO: Services? */
+    } break;
+
+    case BTA_DM_INQ_RES_EVT: {
+      /* inquiry result */
+      uint32_t cod;
+      bt_bdname_t bdname;
+      bt_bdaddr_t bdaddr;
+      uint8_t remote_name_len;
+      tBTA_SERVICE_MASK services = 0;
+      bdstr_t bdstr;
+
+      p_search_data = (tBTA_DM_SEARCH*)p_param;
+      bdcpy(bdaddr.address, p_search_data->inq_res.bd_addr);
+
+      BTIF_TRACE_DEBUG("%s() %s device_type = 0x%x\n", __func__,
+                       bdaddr_to_string(&bdaddr, bdstr, sizeof(bdstr)),
+#if (BLE_INCLUDED == TRUE)
+                       p_search_data->inq_res.device_type);
+#else
+                       BT_DEVICE_TYPE_BREDR);
+#endif
+      bdname.name[0] = 0;
+
+      cod = devclass2uint(p_search_data->inq_res.dev_class);
+
+      if (cod == 0) {
+        LOG_DEBUG(LOG_TAG, "%s cod is 0, set as unclassified", __func__);
+        cod = COD_UNCLASSIFIED;
+      }
+
+      if (!check_eir_remote_name(p_search_data, bdname.name, &remote_name_len))
+        check_cached_remote_name(p_search_data, bdname.name, &remote_name_len);
+
+      /* Check EIR for remote name and services */
+      if (p_search_data->inq_res.p_eir) {
+        BTA_GetEirService(p_search_data->inq_res.p_eir, &services);
+        BTIF_TRACE_DEBUG("%s()EIR BTA services = %08X", __func__,
+                         (uint32_t)services);
+        /* TODO:  Get the service list and check to see which uuids we got and
+         * send it back to the client. */
+      }
+
+      {
+        bt_property_t properties[5];
+        bt_device_type_t dev_type;
+        uint32_t num_properties = 0;
+        bt_status_t status;
+        int addr_type = 0;
+
+        memset(properties, 0, sizeof(properties));
+        /* BD_ADDR */
+        BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+                                   BT_PROPERTY_BDADDR, sizeof(bdaddr), &bdaddr);
+        num_properties++;
+        /* BD_NAME */
+        /* Don't send BDNAME if it is empty */
+        if (bdname.name[0]) {
+          BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+                                     BT_PROPERTY_BDNAME,
+                                     strlen((char*)bdname.name), &bdname);
+          num_properties++;
+        }
+
+        /* DEV_CLASS */
+        BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+                                   BT_PROPERTY_CLASS_OF_DEVICE, sizeof(cod),
+                                   &cod);
+        num_properties++;
+/* DEV_TYPE */
+#if (BLE_INCLUDED == TRUE)
+        /* FixMe: Assumption is that bluetooth.h and BTE enums match */
+
+        /* Verify if the device is dual mode in NVRAM */
+        int stored_device_type = 0;
+        if (btif_get_device_type(bdaddr.address, &stored_device_type) &&
+            ((stored_device_type != BT_DEVICE_TYPE_BREDR &&
+              p_search_data->inq_res.device_type == BT_DEVICE_TYPE_BREDR) ||
+             (stored_device_type != BT_DEVICE_TYPE_BLE &&
+              p_search_data->inq_res.device_type == BT_DEVICE_TYPE_BLE))) {
+          dev_type = (bt_device_type_t)BT_DEVICE_TYPE_DUMO;
+        } else {
+          dev_type = (bt_device_type_t)p_search_data->inq_res.device_type;
+        }
+
+        if (p_search_data->inq_res.device_type == BT_DEVICE_TYPE_BLE)
+          addr_type = p_search_data->inq_res.ble_addr_type;
+#else
+        dev_type = BT_DEVICE_TYPE_BREDR;
+#endif
+        BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+                                   BT_PROPERTY_TYPE_OF_DEVICE, sizeof(dev_type),
+                                   &dev_type);
+        num_properties++;
+        /* RSSI */
+        BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+                                   BT_PROPERTY_REMOTE_RSSI, sizeof(int8_t),
+                                   &(p_search_data->inq_res.rssi));
+        num_properties++;
+
+        status =
+            btif_storage_add_remote_device(&bdaddr, num_properties, properties);
+        ASSERTC(status == BT_STATUS_SUCCESS,
+                "failed to save remote device (inquiry)", status);
+#if (BLE_INCLUDED == TRUE)
+        status = btif_storage_set_remote_addr_type(&bdaddr, addr_type);
+        ASSERTC(status == BT_STATUS_SUCCESS,
+                "failed to save remote addr type (inquiry)", status);
+#endif
+        /* Callback to notify upper layer of device */
+        HAL_CBACK(bt_hal_cbacks, device_found_cb, num_properties, properties);
+      }
+    } break;
+
+    case BTA_DM_INQ_CMPL_EVT: {
+#if (BLE_INCLUDED == TRUE)
+      tBTA_DM_BLE_PF_FILT_PARAMS adv_filt_param;
+      memset(&adv_filt_param, 0, sizeof(tBTA_DM_BLE_PF_FILT_PARAMS));
+      BTA_DmBleScanFilterSetup(BTA_DM_BLE_SCAN_COND_DELETE, 0, &adv_filt_param,
+                               NULL, bte_scan_filt_param_cfg_evt, 0);
+#endif
+    } break;
+    case BTA_DM_DISC_CMPL_EVT: {
+      HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb,
+                BT_DISCOVERY_STOPPED);
+    } break;
+    case BTA_DM_SEARCH_CANCEL_CMPL_EVT: {
+      /* if inquiry is not in progress and we get a cancel event, then
+       * it means we are done with inquiry, but remote_name fetches are in
+       * progress
+       *
+       * if inquiry  is in progress, then we don't want to act on this
+       * cancel_cmpl_evt
+       * but instead wait for the cancel_cmpl_evt via the Busy Level
+       *
+       */
+      if (btif_dm_inquiry_in_progress == false) {
+#if (BLE_INCLUDED == TRUE)
+        tBTA_DM_BLE_PF_FILT_PARAMS adv_filt_param;
+        memset(&adv_filt_param, 0, sizeof(tBTA_DM_BLE_PF_FILT_PARAMS));
+        BTA_DmBleScanFilterSetup(BTA_DM_BLE_SCAN_COND_DELETE, 0,
+                                 &adv_filt_param, NULL,
+                                 bte_scan_filt_param_cfg_evt, 0);
+#endif
+        HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb,
+                  BT_DISCOVERY_STOPPED);
+      }
+    } break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_search_services_evt
+ *
+ * Description      Executes search services event in btif context
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_dm_search_services_evt(uint16_t event, char* p_param) {
+  tBTA_DM_SEARCH* p_data = (tBTA_DM_SEARCH*)p_param;
+
+  BTIF_TRACE_EVENT("%s:  event = %d", __func__, event);
+  switch (event) {
+    case BTA_DM_DISC_RES_EVT: {
+      bt_property_t prop;
+      uint32_t i = 0;
+      bt_bdaddr_t bd_addr;
+      bt_status_t ret;
+
+      bdcpy(bd_addr.address, p_data->disc_res.bd_addr);
+
+      BTIF_TRACE_DEBUG("%s:(result=0x%x, services 0x%x)", __func__,
+                       p_data->disc_res.result, p_data->disc_res.services);
+      if ((p_data->disc_res.result != BTA_SUCCESS) &&
+          (pairing_cb.state == BT_BOND_STATE_BONDING) &&
+          (pairing_cb.sdp_attempts < BTIF_DM_MAX_SDP_ATTEMPTS_AFTER_PAIRING)) {
+        BTIF_TRACE_WARNING("%s:SDP failed after bonding re-attempting",
+                           __func__);
+        pairing_cb.sdp_attempts++;
+        btif_dm_get_remote_services(&bd_addr);
+        return;
+      }
+      prop.type = BT_PROPERTY_UUIDS;
+      prop.len = 0;
+      if ((p_data->disc_res.result == BTA_SUCCESS) &&
+          (p_data->disc_res.num_uuids > 0)) {
+        prop.val = p_data->disc_res.p_uuid_list;
+        prop.len = p_data->disc_res.num_uuids * MAX_UUID_SIZE;
+        for (i = 0; i < p_data->disc_res.num_uuids; i++) {
+          char temp[256];
+          uuid_to_string_legacy(
+              (bt_uuid_t*)(p_data->disc_res.p_uuid_list + (i * MAX_UUID_SIZE)),
+              temp, sizeof(temp));
+          LOG_INFO(LOG_TAG, "%s index:%d uuid:%s", __func__, i, temp);
+        }
+      }
+
+      /* onUuidChanged requires getBondedDevices to be populated.
+      ** bond_state_changed needs to be sent prior to remote_device_property
+      */
+      if ((pairing_cb.state == BT_BOND_STATE_BONDING) &&
+          ((bdcmp(p_data->disc_res.bd_addr, pairing_cb.bd_addr) == 0) ||
+           (bdcmp(p_data->disc_res.bd_addr, pairing_cb.static_bdaddr.address) ==
+            0)) &&
+          pairing_cb.sdp_attempts > 0) {
+        BTIF_TRACE_DEBUG(
+            "%s Remote Service SDP done. Call bond_state_changed_cb BONDED",
+            __func__);
+        pairing_cb.sdp_attempts = 0;
+
+        // If bonding occured due to cross-key pairing, send bonding callback
+        // for static address now
+        if (bdcmp(p_data->disc_res.bd_addr, pairing_cb.static_bdaddr.address) ==
+            0)
+          bond_state_changed(BT_STATUS_SUCCESS, &bd_addr,
+                             BT_BOND_STATE_BONDING);
+
+        bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDED);
+      }
+
+      if (p_data->disc_res.num_uuids != 0) {
+        /* Also write this to the NVRAM */
+        ret = btif_storage_set_remote_device_property(&bd_addr, &prop);
+        ASSERTC(ret == BT_STATUS_SUCCESS, "storing remote services failed",
+                ret);
+        /* Send the event to the BTIF */
+        HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, BT_STATUS_SUCCESS,
+                  &bd_addr, 1, &prop);
+      }
+    } break;
+
+    case BTA_DM_DISC_CMPL_EVT:
+      /* fixme */
+      break;
+
+    case BTA_DM_SEARCH_CANCEL_CMPL_EVT:
+      /* no-op */
+      break;
+
+#if (BLE_INCLUDED == TRUE)
+    case BTA_DM_DISC_BLE_RES_EVT: {
+      BTIF_TRACE_DEBUG("%s:, services 0x%x)", __func__,
+                       p_data->disc_ble_res.service.uu.uuid16);
+      bt_uuid_t uuid;
+      int i = 0;
+      int j = 15;
+      int num_properties = 0;
+      if (p_data->disc_ble_res.service.uu.uuid16 == UUID_SERVCLASS_LE_HID) {
+        BTIF_TRACE_DEBUG("%s: Found HOGP UUID", __func__);
+        bt_property_t prop[2];
+        bt_bdaddr_t bd_addr;
+        char temp[256];
+        bt_status_t ret;
+
+        bta_gatt_convert_uuid16_to_uuid128(
+            uuid.uu, p_data->disc_ble_res.service.uu.uuid16);
+
+        while (i < j) {
+          unsigned char c = uuid.uu[j];
+          uuid.uu[j] = uuid.uu[i];
+          uuid.uu[i] = c;
+          i++;
+          j--;
+        }
+
+        uuid_to_string_legacy(&uuid, temp, sizeof(temp));
+        LOG_INFO(LOG_TAG, "%s uuid:%s", __func__, temp);
+
+        bdcpy(bd_addr.address, p_data->disc_ble_res.bd_addr);
+        prop[0].type = BT_PROPERTY_UUIDS;
+        prop[0].val = uuid.uu;
+        prop[0].len = MAX_UUID_SIZE;
+
+        /* Also write this to the NVRAM */
+        ret = btif_storage_set_remote_device_property(&bd_addr, &prop[0]);
+        ASSERTC(ret == BT_STATUS_SUCCESS, "storing remote services failed",
+                ret);
+        num_properties++;
+
+        /* Remote name update */
+        if (strnlen((const char*)p_data->disc_ble_res.bd_name, BD_NAME_LEN)) {
+          prop[1].type = BT_PROPERTY_BDNAME;
+          prop[1].val = p_data->disc_ble_res.bd_name;
+          prop[1].len =
+              strnlen((char*)p_data->disc_ble_res.bd_name, BD_NAME_LEN);
+
+          ret = btif_storage_set_remote_device_property(&bd_addr, &prop[1]);
+          ASSERTC(ret == BT_STATUS_SUCCESS,
+                  "failed to save remote device property", ret);
+          num_properties++;
+        }
+
+        /* Send the event to the BTIF */
+        HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, BT_STATUS_SUCCESS,
+                  &bd_addr, num_properties, prop);
+      }
+    } break;
+#endif /* BLE_INCLUDED */
+
+    default: { ASSERTC(0, "unhandled search services event", event); } break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_remote_service_record_evt
+ *
+ * Description      Executes search service record event in btif context
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_dm_remote_service_record_evt(uint16_t event, char* p_param) {
+  tBTA_DM_SEARCH* p_data = (tBTA_DM_SEARCH*)p_param;
+
+  BTIF_TRACE_EVENT("%s:  event = %d", __func__, event);
+  switch (event) {
+    case BTA_DM_DISC_RES_EVT: {
+      bt_service_record_t rec;
+      bt_property_t prop;
+      bt_bdaddr_t bd_addr;
+
+      memset(&rec, 0, sizeof(bt_service_record_t));
+      bdcpy(bd_addr.address, p_data->disc_res.bd_addr);
+
+      BTIF_TRACE_DEBUG("%s:(result=0x%x, services 0x%x)", __func__,
+                       p_data->disc_res.result, p_data->disc_res.services);
+      prop.type = BT_PROPERTY_SERVICE_RECORD;
+      prop.val = (void*)&rec;
+      prop.len = sizeof(rec);
+
+      /* disc_res.result is overloaded with SCN. Cannot check result */
+      p_data->disc_res.services &= ~BTA_USER_SERVICE_MASK;
+      /* TODO: Get the UUID as well */
+      rec.channel = p_data->disc_res.result - 3;
+      /* TODO: Need to get the service name using p_raw_data */
+      rec.name[0] = 0;
+
+      HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, BT_STATUS_SUCCESS,
+                &bd_addr, 1, &prop);
+    } break;
+
+    default: {
+      ASSERTC(0, "unhandled remote service record event", event);
+    } break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_upstreams_cback
+ *
+ * Description      Executes UPSTREAMS events in btif context
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_dm_upstreams_evt(uint16_t event, char* p_param) {
+  tBTA_DM_SEC* p_data = (tBTA_DM_SEC*)p_param;
+  tBTA_SERVICE_MASK service_mask;
+  uint32_t i;
+  bt_bdaddr_t bd_addr;
+
+  BTIF_TRACE_EVENT("%s: ev: %s", __func__, dump_dm_event(event));
+
+  switch (event) {
+    case BTA_DM_ENABLE_EVT: {
+      BD_NAME bdname;
+      bt_status_t status;
+      bt_property_t prop;
+      prop.type = BT_PROPERTY_BDNAME;
+      prop.len = BD_NAME_LEN;
+      prop.val = (void*)bdname;
+
+      status = btif_storage_get_adapter_property(&prop);
+      if (status == BT_STATUS_SUCCESS) {
+        /* A name exists in the storage. Make this the device name */
+        BTA_DmSetDeviceName((char*)prop.val);
+      } else {
+        /* Storage does not have a name yet.
+         * Use the default name and write it to the chip
+         */
+        BTA_DmSetDeviceName(btif_get_default_local_name());
+      }
+
+#if (BLE_INCLUDED == TRUE)
+      /* Enable local privacy */
+      BTA_DmBleConfigLocalPrivacy(BLE_LOCAL_PRIVACY_ENABLED);
+#endif
+
+      /* for each of the enabled services in the mask, trigger the profile
+       * enable */
+      service_mask = btif_get_enabled_services_mask();
+      for (i = 0; i <= BTA_MAX_SERVICE_ID; i++) {
+        if (service_mask &
+            (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(i))) {
+          btif_in_execute_service_request(i, true);
+        }
+      }
+      /* clear control blocks */
+      memset(&pairing_cb, 0, sizeof(btif_dm_pairing_cb_t));
+      pairing_cb.bond_type = BOND_TYPE_PERSISTENT;
+
+      /* This function will also trigger the adapter_properties_cb
+      ** and bonded_devices_info_cb
+      */
+      btif_storage_load_bonded_devices();
+
+      btif_enable_bluetooth_evt(p_data->enable.status);
+    } break;
+
+    case BTA_DM_DISABLE_EVT:
+      /* for each of the enabled services in the mask, trigger the profile
+       * disable */
+      service_mask = btif_get_enabled_services_mask();
+      for (i = 0; i <= BTA_MAX_SERVICE_ID; i++) {
+        if (service_mask &
+            (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(i))) {
+          btif_in_execute_service_request(i, false);
+        }
+      }
+      btif_disable_bluetooth_evt();
+      break;
+
+    case BTA_DM_PIN_REQ_EVT:
+      btif_dm_pin_req_evt(&p_data->pin_req);
+      break;
+
+    case BTA_DM_AUTH_CMPL_EVT:
+      btif_dm_auth_cmpl_evt(&p_data->auth_cmpl);
+      break;
+
+    case BTA_DM_BOND_CANCEL_CMPL_EVT:
+      if (pairing_cb.state == BT_BOND_STATE_BONDING) {
+        bdcpy(bd_addr.address, pairing_cb.bd_addr);
+        btm_set_bond_type_dev(pairing_cb.bd_addr, BOND_TYPE_UNKNOWN);
+        bond_state_changed((bt_status_t)p_data->bond_cancel_cmpl.result,
+                           &bd_addr, BT_BOND_STATE_NONE);
+      }
+      break;
+
+    case BTA_DM_SP_CFM_REQ_EVT:
+      btif_dm_ssp_cfm_req_evt(&p_data->cfm_req);
+      break;
+    case BTA_DM_SP_KEY_NOTIF_EVT:
+      btif_dm_ssp_key_notif_evt(&p_data->key_notif);
+      break;
+
+    case BTA_DM_DEV_UNPAIRED_EVT:
+      bdcpy(bd_addr.address, p_data->link_down.bd_addr);
+      btm_set_bond_type_dev(p_data->link_down.bd_addr, BOND_TYPE_UNKNOWN);
+
+/*special handling for HID devices */
+#if (defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == true))
+      btif_hh_remove_device(bd_addr);
+#endif
+      btif_storage_remove_bonded_device(&bd_addr);
+      bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_NONE);
+      break;
+
+    case BTA_DM_BUSY_LEVEL_EVT: {
+      if (p_data->busy_level.level_flags & BTM_BL_INQUIRY_PAGING_MASK) {
+        if (p_data->busy_level.level_flags == BTM_BL_INQUIRY_STARTED) {
+          HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb,
+                    BT_DISCOVERY_STARTED);
+          btif_dm_inquiry_in_progress = true;
+        } else if (p_data->busy_level.level_flags == BTM_BL_INQUIRY_CANCELLED) {
+          HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb,
+                    BT_DISCOVERY_STOPPED);
+          btif_dm_inquiry_in_progress = false;
+        } else if (p_data->busy_level.level_flags == BTM_BL_INQUIRY_COMPLETE) {
+          btif_dm_inquiry_in_progress = false;
+        }
+      }
+    } break;
+
+    case BTA_DM_LINK_UP_EVT:
+      bdcpy(bd_addr.address, p_data->link_up.bd_addr);
+      BTIF_TRACE_DEBUG("BTA_DM_LINK_UP_EVT. Sending BT_ACL_STATE_CONNECTED");
+
+      btif_update_remote_version_property(&bd_addr);
+
+      HAL_CBACK(bt_hal_cbacks, acl_state_changed_cb, BT_STATUS_SUCCESS,
+                &bd_addr, BT_ACL_STATE_CONNECTED);
+      break;
+
+    case BTA_DM_LINK_DOWN_EVT:
+      bdcpy(bd_addr.address, p_data->link_down.bd_addr);
+      btm_set_bond_type_dev(p_data->link_down.bd_addr, BOND_TYPE_UNKNOWN);
+      btif_av_move_idle(bd_addr);
+      BTIF_TRACE_DEBUG(
+          "BTA_DM_LINK_DOWN_EVT. Sending BT_ACL_STATE_DISCONNECTED");
+      HAL_CBACK(bt_hal_cbacks, acl_state_changed_cb, BT_STATUS_SUCCESS,
+                &bd_addr, BT_ACL_STATE_DISCONNECTED);
+      break;
+
+    case BTA_DM_HW_ERROR_EVT:
+      BTIF_TRACE_ERROR("Received H/W Error. ");
+      /* Flush storage data */
+      btif_config_flush();
+      usleep(100000); /* 100milliseconds */
+      /* Killing the process to force a restart as part of fault tolerance */
+      kill(getpid(), SIGKILL);
+      break;
+
+#if (BLE_INCLUDED == TRUE)
+    case BTA_DM_BLE_KEY_EVT:
+      BTIF_TRACE_DEBUG("BTA_DM_BLE_KEY_EVT key_type=0x%02x ",
+                       p_data->ble_key.key_type);
+
+      /* If this pairing is by-product of local initiated GATT client Read or
+      Write,
+      BTA would not have sent BTA_DM_BLE_SEC_REQ_EVT event and Bond state would
+      not
+      have setup properly. Setup pairing_cb and notify App about Bonding state
+      now*/
+      if (pairing_cb.state != BT_BOND_STATE_BONDING) {
+        BTIF_TRACE_DEBUG(
+            "Bond state not sent to App so far.Notify the app now");
+        bond_state_changed(BT_STATUS_SUCCESS,
+                           (bt_bdaddr_t*)p_data->ble_key.bd_addr,
+                           BT_BOND_STATE_BONDING);
+      } else if (memcmp(pairing_cb.bd_addr, p_data->ble_key.bd_addr,
+                        BD_ADDR_LEN) != 0) {
+        BTIF_TRACE_ERROR("BD mismatch discard BLE key_type=%d ",
+                         p_data->ble_key.key_type);
+        break;
+      }
+
+      switch (p_data->ble_key.key_type) {
+        case BTA_LE_KEY_PENC:
+          BTIF_TRACE_DEBUG("Rcv BTA_LE_KEY_PENC");
+          pairing_cb.ble.is_penc_key_rcvd = true;
+          pairing_cb.ble.penc_key = p_data->ble_key.p_key_value->penc_key;
+          break;
+
+        case BTA_LE_KEY_PID:
+          BTIF_TRACE_DEBUG("Rcv BTA_LE_KEY_PID");
+          pairing_cb.ble.is_pid_key_rcvd = true;
+          pairing_cb.ble.pid_key = p_data->ble_key.p_key_value->pid_key;
+          break;
+
+        case BTA_LE_KEY_PCSRK:
+          BTIF_TRACE_DEBUG("Rcv BTA_LE_KEY_PCSRK");
+          pairing_cb.ble.is_pcsrk_key_rcvd = true;
+          pairing_cb.ble.pcsrk_key = p_data->ble_key.p_key_value->pcsrk_key;
+          break;
+
+        case BTA_LE_KEY_LENC:
+          BTIF_TRACE_DEBUG("Rcv BTA_LE_KEY_LENC");
+          pairing_cb.ble.is_lenc_key_rcvd = true;
+          pairing_cb.ble.lenc_key = p_data->ble_key.p_key_value->lenc_key;
+          break;
+
+        case BTA_LE_KEY_LCSRK:
+          BTIF_TRACE_DEBUG("Rcv BTA_LE_KEY_LCSRK");
+          pairing_cb.ble.is_lcsrk_key_rcvd = true;
+          pairing_cb.ble.lcsrk_key = p_data->ble_key.p_key_value->lcsrk_key;
+          break;
+
+        case BTA_LE_KEY_LID:
+          BTIF_TRACE_DEBUG("Rcv BTA_LE_KEY_LID");
+          pairing_cb.ble.is_lidk_key_rcvd = true;
+          break;
+
+        default:
+          BTIF_TRACE_ERROR("unknown BLE key type (0x%02x)",
+                           p_data->ble_key.key_type);
+          break;
+      }
+      break;
+    case BTA_DM_BLE_SEC_REQ_EVT:
+      BTIF_TRACE_DEBUG("BTA_DM_BLE_SEC_REQ_EVT. ");
+      btif_dm_ble_sec_req_evt(&p_data->ble_req);
+      break;
+    case BTA_DM_BLE_PASSKEY_NOTIF_EVT:
+      BTIF_TRACE_DEBUG("BTA_DM_BLE_PASSKEY_NOTIF_EVT. ");
+      btif_dm_ble_key_notif_evt(&p_data->key_notif);
+      break;
+    case BTA_DM_BLE_PASSKEY_REQ_EVT:
+      BTIF_TRACE_DEBUG("BTA_DM_BLE_PASSKEY_REQ_EVT. ");
+      btif_dm_ble_passkey_req_evt(&p_data->pin_req);
+      break;
+    case BTA_DM_BLE_NC_REQ_EVT:
+      BTIF_TRACE_DEBUG("BTA_DM_BLE_PASSKEY_REQ_EVT. ");
+      btif_dm_ble_key_nc_req_evt(&p_data->key_notif);
+      break;
+    case BTA_DM_BLE_OOB_REQ_EVT:
+      BTIF_TRACE_DEBUG("BTA_DM_BLE_OOB_REQ_EVT. ");
+      btif_dm_ble_oob_req_evt(&p_data->rmt_oob);
+      break;
+    case BTA_DM_BLE_SC_OOB_REQ_EVT:
+      BTIF_TRACE_DEBUG("BTA_DM_BLE_SC_OOB_REQ_EVT. ");
+      btif_dm_ble_sc_oob_req_evt(&p_data->rmt_oob);
+      break;
+    case BTA_DM_BLE_LOCAL_IR_EVT:
+      BTIF_TRACE_DEBUG("BTA_DM_BLE_LOCAL_IR_EVT. ");
+      ble_local_key_cb.is_id_keys_rcvd = true;
+      memcpy(&ble_local_key_cb.id_keys.irk[0], &p_data->ble_id_keys.irk[0],
+             sizeof(BT_OCTET16));
+      memcpy(&ble_local_key_cb.id_keys.ir[0], &p_data->ble_id_keys.ir[0],
+             sizeof(BT_OCTET16));
+      memcpy(&ble_local_key_cb.id_keys.dhk[0], &p_data->ble_id_keys.dhk[0],
+             sizeof(BT_OCTET16));
+      btif_storage_add_ble_local_key((char*)&ble_local_key_cb.id_keys.irk[0],
+                                     BTIF_DM_LE_LOCAL_KEY_IRK, BT_OCTET16_LEN);
+      btif_storage_add_ble_local_key((char*)&ble_local_key_cb.id_keys.ir[0],
+                                     BTIF_DM_LE_LOCAL_KEY_IR, BT_OCTET16_LEN);
+      btif_storage_add_ble_local_key((char*)&ble_local_key_cb.id_keys.dhk[0],
+                                     BTIF_DM_LE_LOCAL_KEY_DHK, BT_OCTET16_LEN);
+      break;
+    case BTA_DM_BLE_LOCAL_ER_EVT:
+      BTIF_TRACE_DEBUG("BTA_DM_BLE_LOCAL_ER_EVT. ");
+      ble_local_key_cb.is_er_rcvd = true;
+      memcpy(&ble_local_key_cb.er[0], &p_data->ble_er[0], sizeof(BT_OCTET16));
+      btif_storage_add_ble_local_key((char*)&ble_local_key_cb.er[0],
+                                     BTIF_DM_LE_LOCAL_KEY_ER, BT_OCTET16_LEN);
+      break;
+
+    case BTA_DM_BLE_AUTH_CMPL_EVT:
+      BTIF_TRACE_DEBUG("BTA_DM_BLE_AUTH_CMPL_EVT. ");
+      btif_dm_ble_auth_cmpl_evt(&p_data->auth_cmpl);
+      break;
+
+    case BTA_DM_LE_FEATURES_READ: {
+      tBTM_BLE_VSC_CB cmn_vsc_cb;
+      bt_local_le_features_t local_le_features;
+      char buf[512];
+      bt_property_t prop;
+      prop.type = BT_PROPERTY_LOCAL_LE_FEATURES;
+      prop.val = (void*)buf;
+      prop.len = sizeof(buf);
+
+      /* LE features are not stored in storage. Should be retrived from stack */
+      BTM_BleGetVendorCapabilities(&cmn_vsc_cb);
+      local_le_features.local_privacy_enabled = BTM_BleLocalPrivacyEnabled();
+
+      prop.len = sizeof(bt_local_le_features_t);
+      if (cmn_vsc_cb.filter_support == 1)
+        local_le_features.max_adv_filter_supported = cmn_vsc_cb.max_filter;
+      else
+        local_le_features.max_adv_filter_supported = 0;
+      local_le_features.max_adv_instance = cmn_vsc_cb.adv_inst_max;
+      local_le_features.max_irk_list_size = cmn_vsc_cb.max_irk_list_sz;
+      local_le_features.rpa_offload_supported = cmn_vsc_cb.rpa_offloading;
+      local_le_features.activity_energy_info_supported =
+          cmn_vsc_cb.energy_support;
+      local_le_features.scan_result_storage_size =
+          cmn_vsc_cb.tot_scan_results_strg;
+      local_le_features.version_supported = cmn_vsc_cb.version_supported;
+      local_le_features.total_trackable_advertisers =
+          cmn_vsc_cb.total_trackable_advertisers;
+
+      local_le_features.extended_scan_support =
+          cmn_vsc_cb.extended_scan_support > 0;
+      local_le_features.debug_logging_supported =
+          cmn_vsc_cb.debug_logging_supported > 0;
+
+      memcpy(prop.val, &local_le_features, prop.len);
+      HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, BT_STATUS_SUCCESS, 1,
+                &prop);
+      break;
+    }
+
+    case BTA_DM_ENER_INFO_READ: {
+      btif_activity_energy_info_cb_t* p_ener_data =
+          (btif_activity_energy_info_cb_t*)p_param;
+      bt_activity_energy_info energy_info;
+      energy_info.status = p_ener_data->status;
+      energy_info.ctrl_state = p_ener_data->ctrl_state;
+      energy_info.rx_time = p_ener_data->rx_time;
+      energy_info.tx_time = p_ener_data->tx_time;
+      energy_info.idle_time = p_ener_data->idle_time;
+      energy_info.energy_used = p_ener_data->energy_used;
+
+      bt_uid_traffic_t* data = uid_set_read_and_clear(uid_set);
+      HAL_CBACK(bt_hal_cbacks, energy_info_cb, &energy_info, data);
+      osi_free(data);
+      break;
+    }
+#endif
+
+    case BTA_DM_AUTHORIZE_EVT:
+    case BTA_DM_SIG_STRENGTH_EVT:
+    case BTA_DM_SP_RMT_OOB_EVT:
+    case BTA_DM_SP_KEYPRESS_EVT:
+    case BTA_DM_ROLE_CHG_EVT:
+
+    default:
+      BTIF_TRACE_WARNING("btif_dm_cback : unhandled event (%d)", event);
+      break;
+  }
+
+  btif_dm_data_free(event, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_generic_evt
+ *
+ * Description      Executes non-BTA upstream events in BTIF context
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_dm_generic_evt(uint16_t event, char* p_param) {
+  BTIF_TRACE_EVENT("%s: event=%d", __func__, event);
+  switch (event) {
+    case BTIF_DM_CB_DISCOVERY_STARTED: {
+      HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb,
+                BT_DISCOVERY_STARTED);
+    } break;
+
+    case BTIF_DM_CB_CREATE_BOND: {
+      pairing_cb.timeout_retries = NUM_TIMEOUT_RETRIES;
+      btif_dm_create_bond_cb_t* create_bond_cb =
+          (btif_dm_create_bond_cb_t*)p_param;
+      btif_dm_cb_create_bond(&create_bond_cb->bdaddr,
+                             create_bond_cb->transport);
+    } break;
+
+    case BTIF_DM_CB_REMOVE_BOND: {
+      btif_dm_cb_remove_bond((bt_bdaddr_t*)p_param);
+    } break;
+
+    case BTIF_DM_CB_HID_REMOTE_NAME: {
+      btif_dm_cb_hid_remote_name((tBTM_REMOTE_DEV_NAME*)p_param);
+    } break;
+
+    case BTIF_DM_CB_BOND_STATE_BONDING: {
+      bond_state_changed(BT_STATUS_SUCCESS, (bt_bdaddr_t*)p_param,
+                         BT_BOND_STATE_BONDING);
+    } break;
+    case BTIF_DM_CB_LE_TX_TEST:
+    case BTIF_DM_CB_LE_RX_TEST: {
+      uint8_t status;
+      STREAM_TO_UINT8(status, p_param);
+      HAL_CBACK(bt_hal_cbacks, le_test_mode_cb,
+                (status == 0) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL, 0);
+    } break;
+    case BTIF_DM_CB_LE_TEST_END: {
+      uint8_t status;
+      uint16_t count = 0;
+      STREAM_TO_UINT8(status, p_param);
+      if (status == 0) STREAM_TO_UINT16(count, p_param);
+      HAL_CBACK(bt_hal_cbacks, le_test_mode_cb,
+                (status == 0) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL, count);
+    } break;
+    default: {
+      BTIF_TRACE_WARNING("%s : Unknown event 0x%x", __func__, event);
+    } break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bte_dm_evt
+ *
+ * Description      Switches context from BTE to BTIF for all DM events
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+
+void bte_dm_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data) {
+  /* switch context to btif task context (copy full union size for convenience)
+   */
+  bt_status_t status = btif_transfer_context(
+      btif_dm_upstreams_evt, (uint16_t)event, (char*)p_data,
+      sizeof(tBTA_DM_SEC), btif_dm_data_copy);
+
+  /* catch any failed context transfers */
+  ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+/*******************************************************************************
+ *
+ * Function         bte_search_devices_evt
+ *
+ * Description      Switches context from BTE to BTIF for DM search events
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bte_search_devices_evt(tBTA_DM_SEARCH_EVT event,
+                                   tBTA_DM_SEARCH* p_data) {
+  uint16_t param_len = 0;
+
+  if (p_data) param_len += sizeof(tBTA_DM_SEARCH);
+  /* Allocate buffer to hold the pointers (deep copy). The pointers will point
+   * to the end of the tBTA_DM_SEARCH */
+  switch (event) {
+    case BTA_DM_INQ_RES_EVT: {
+      if (p_data->inq_res.p_eir) param_len += HCI_EXT_INQ_RESPONSE_LEN;
+    } break;
+
+    case BTA_DM_DISC_RES_EVT: {
+      if (p_data->disc_res.raw_data_size && p_data->disc_res.p_raw_data)
+        param_len += p_data->disc_res.raw_data_size;
+    } break;
+  }
+  BTIF_TRACE_DEBUG("%s event=%s param_len=%d", __func__,
+                   dump_dm_search_event(event), param_len);
+
+  /* if remote name is available in EIR, set teh flag so that stack doesnt
+   * trigger RNR */
+  if (event == BTA_DM_INQ_RES_EVT)
+    p_data->inq_res.remt_name_not_required =
+        check_eir_remote_name(p_data, NULL, NULL);
+
+  btif_transfer_context(
+      btif_dm_search_devices_evt, (uint16_t)event, (char*)p_data, param_len,
+      (param_len > sizeof(tBTA_DM_SEARCH)) ? search_devices_copy_cb : NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         bte_dm_search_services_evt
+ *
+ * Description      Switches context from BTE to BTIF for DM search services
+ *                  event
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bte_dm_search_services_evt(tBTA_DM_SEARCH_EVT event,
+                                       tBTA_DM_SEARCH* p_data) {
+  uint16_t param_len = 0;
+  if (p_data) param_len += sizeof(tBTA_DM_SEARCH);
+  switch (event) {
+    case BTA_DM_DISC_RES_EVT: {
+      if ((p_data->disc_res.result == BTA_SUCCESS) &&
+          (p_data->disc_res.num_uuids > 0)) {
+        param_len += (p_data->disc_res.num_uuids * MAX_UUID_SIZE);
+      }
+    } break;
+  }
+  /* TODO: The only other member that needs a deep copy is the p_raw_data. But
+   * not sure
+   * if raw_data is needed. */
+  btif_transfer_context(
+      btif_dm_search_services_evt, event, (char*)p_data, param_len,
+      (param_len > sizeof(tBTA_DM_SEARCH)) ? search_services_copy_cb : NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         bte_dm_remote_service_record_evt
+ *
+ * Description      Switches context from BTE to BTIF for DM search service
+ *                  record event
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bte_dm_remote_service_record_evt(tBTA_DM_SEARCH_EVT event,
+                                             tBTA_DM_SEARCH* p_data) {
+  /* TODO: The only member that needs a deep copy is the p_raw_data. But not
+   * sure yet if this is needed. */
+  btif_transfer_context(btif_dm_remote_service_record_evt, event, (char*)p_data,
+                        sizeof(tBTA_DM_SEARCH), NULL);
+}
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function         bta_energy_info_cb
+ *
+ * Description      Switches context from BTE to BTIF for DM energy info event
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bta_energy_info_cb(tBTA_DM_BLE_TX_TIME_MS tx_time,
+                               tBTA_DM_BLE_RX_TIME_MS rx_time,
+                               tBTA_DM_BLE_IDLE_TIME_MS idle_time,
+                               tBTA_DM_BLE_ENERGY_USED energy_used,
+                               tBTA_DM_CONTRL_STATE ctrl_state,
+                               tBTA_STATUS status) {
+  BTIF_TRACE_DEBUG(
+      "energy_info_cb-Status:%d,state=%d,tx_t=%ld, rx_t=%ld, "
+      "idle_time=%ld,used=%ld",
+      status, ctrl_state, tx_time, rx_time, idle_time, energy_used);
+
+  btif_activity_energy_info_cb_t btif_cb;
+  btif_cb.status = status;
+  btif_cb.ctrl_state = ctrl_state;
+  btif_cb.tx_time = (uint64_t)tx_time;
+  btif_cb.rx_time = (uint64_t)rx_time;
+  btif_cb.idle_time = (uint64_t)idle_time;
+  btif_cb.energy_used = (uint64_t)energy_used;
+  btif_transfer_context(btif_dm_upstreams_evt, BTA_DM_ENER_INFO_READ,
+                        (char*)&btif_cb, sizeof(btif_activity_energy_info_cb_t),
+                        NULL);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function         bte_scan_filt_param_cfg_evt
+ *
+ * Description      Scan filter param config event
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void bte_scan_filt_param_cfg_evt(uint8_t action_type,
+                                        tBTA_DM_BLE_PF_AVBL_SPACE avbl_space,
+                                        tBTA_DM_BLE_REF_VALUE ref_value,
+                                        tBTA_STATUS status) {
+  /* This event occurs on calling BTA_DmBleCfgFilterCondition internally,
+  ** and that is why there is no HAL callback
+  */
+  if (BTA_SUCCESS != status) {
+    BTIF_TRACE_ERROR("%s, %d", __func__, status);
+  } else {
+    BTIF_TRACE_DEBUG("%s", __func__);
+  }
+}
+
+/*****************************************************************************
+ *
+ *   btif api functions (no context switch)
+ *
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_start_discovery
+ *
+ * Description      Start device discovery/inquiry
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_start_discovery(void) {
+  tBTA_DM_INQ inq_params;
+  tBTA_SERVICE_MASK services = 0;
+  tBTA_DM_BLE_PF_FILT_PARAMS adv_filt_param;
+
+  BTIF_TRACE_EVENT("%s", __func__);
+
+#if (BLE_INCLUDED == TRUE)
+  memset(&adv_filt_param, 0, sizeof(tBTA_DM_BLE_PF_FILT_PARAMS));
+  /* Cleanup anything remaining on index 0 */
+  BTA_DmBleScanFilterSetup(BTA_DM_BLE_SCAN_COND_DELETE, 0, &adv_filt_param,
+                           NULL, bte_scan_filt_param_cfg_evt, 0);
+
+  /* Add an allow-all filter on index 0*/
+  adv_filt_param.dely_mode = IMMEDIATE_DELY_MODE;
+  adv_filt_param.feat_seln = ALLOW_ALL_FILTER;
+  adv_filt_param.filt_logic_type = BTA_DM_BLE_PF_FILT_LOGIC_OR;
+  adv_filt_param.list_logic_type = BTA_DM_BLE_PF_LIST_LOGIC_OR;
+  adv_filt_param.rssi_low_thres = LOWEST_RSSI_VALUE;
+  adv_filt_param.rssi_high_thres = LOWEST_RSSI_VALUE;
+  BTA_DmBleScanFilterSetup(BTA_DM_BLE_SCAN_COND_ADD, 0, &adv_filt_param, NULL,
+                           bte_scan_filt_param_cfg_evt, 0);
+
+  /* TODO: Do we need to handle multiple inquiries at the same time? */
+
+  /* Set inquiry params and call API */
+  inq_params.mode = BTA_DM_GENERAL_INQUIRY | BTA_BLE_GENERAL_INQUIRY;
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+  inq_params.intl_duration[0] = BTIF_DM_INTERLEAVE_DURATION_BR_ONE;
+  inq_params.intl_duration[1] = BTIF_DM_INTERLEAVE_DURATION_LE_ONE;
+  inq_params.intl_duration[2] = BTIF_DM_INTERLEAVE_DURATION_BR_TWO;
+  inq_params.intl_duration[3] = BTIF_DM_INTERLEAVE_DURATION_LE_TWO;
+#endif
+#else
+  inq_params.mode = BTA_DM_GENERAL_INQUIRY;
+#endif
+  inq_params.duration = BTIF_DM_DEFAULT_INQ_MAX_DURATION;
+
+  inq_params.max_resps = BTIF_DM_DEFAULT_INQ_MAX_RESULTS;
+  inq_params.report_dup = true;
+
+  inq_params.filter_type = BTA_DM_INQ_CLR;
+  /* TODO: Filter device by BDA needs to be implemented here */
+
+  /* Will be enabled to true once inquiry busy level has been received */
+  btif_dm_inquiry_in_progress = false;
+  /* find nearby devices */
+  BTA_DmSearch(&inq_params, services, bte_search_devices_evt);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_cancel_discovery
+ *
+ * Description      Cancels search
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_cancel_discovery(void) {
+  BTIF_TRACE_EVENT("%s", __func__);
+  BTA_DmSearchCancel();
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_create_bond
+ *
+ * Description      Initiate bonding with the specified device
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_create_bond(const bt_bdaddr_t* bd_addr, int transport) {
+  btif_dm_create_bond_cb_t create_bond_cb;
+  create_bond_cb.transport = transport;
+  bdcpy(create_bond_cb.bdaddr.address, bd_addr->address);
+
+  bdstr_t bdstr;
+  BTIF_TRACE_EVENT("%s: bd_addr=%s, transport=%d", __func__,
+                   bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr)), transport);
+  if (pairing_cb.state != BT_BOND_STATE_NONE) return BT_STATUS_BUSY;
+
+  btif_stats_add_bond_event(bd_addr, BTIF_DM_FUNC_CREATE_BOND,
+                            pairing_cb.state);
+
+  btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_CREATE_BOND,
+                        (char*)&create_bond_cb,
+                        sizeof(btif_dm_create_bond_cb_t), NULL);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_create_bond_out_of_band
+ *
+ * Description      Initiate bonding with the specified device using out of band
+ *                  data
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_create_bond_out_of_band(
+    const bt_bdaddr_t* bd_addr, int transport,
+    const bt_out_of_band_data_t* oob_data) {
+  bdcpy(oob_cb.bdaddr, bd_addr->address);
+  memcpy(&oob_cb.oob_data, oob_data, sizeof(bt_out_of_band_data_t));
+
+  uint8_t empty[] = {0, 0, 0, 0, 0, 0, 0};
+  // If LE Bluetooth Device Address is provided, use provided address type
+  // value.
+  if (memcmp(oob_data->le_bt_dev_addr, empty, 7) != 0) {
+    /* byte no 7 is address type in LE Bluetooth Address OOB data */
+    uint8_t address_type = oob_data->le_bt_dev_addr[6];
+    if (address_type == BLE_ADDR_PUBLIC || address_type == BLE_ADDR_RANDOM) {
+      // bd_addr->address is already reversed, so use it instead of
+      // oob_data->le_bt_dev_addr
+      BTM_SecAddBleDevice(bd_addr->address, NULL, BT_DEVICE_TYPE_BLE, address_type);
+    }
+  }
+
+  bdstr_t bdstr;
+  BTIF_TRACE_EVENT("%s: bd_addr=%s, transport=%d", __func__,
+                   bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr)), transport);
+  return btif_dm_create_bond(bd_addr, transport);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_cancel_bond
+ *
+ * Description      Initiate bonding with the specified device
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+
+bt_status_t btif_dm_cancel_bond(const bt_bdaddr_t* bd_addr) {
+  bdstr_t bdstr;
+
+  BTIF_TRACE_EVENT("%s: bd_addr=%s", __func__,
+                   bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr)));
+
+  btif_stats_add_bond_event(bd_addr, BTIF_DM_FUNC_CANCEL_BOND,
+                            pairing_cb.state);
+
+  /* TODO:
+  **  1. Restore scan modes
+  **  2. special handling for HID devices
+  */
+  if (pairing_cb.state == BT_BOND_STATE_BONDING) {
+#if (BLE_INCLUDED == TRUE)
+
+    if (pairing_cb.is_ssp) {
+      if (pairing_cb.is_le_only) {
+        BTA_DmBleSecurityGrant((uint8_t*)bd_addr->address,
+                               BTA_DM_SEC_PAIR_NOT_SPT);
+      } else {
+        BTA_DmConfirm((uint8_t*)bd_addr->address, false);
+        BTA_DmBondCancel((uint8_t*)bd_addr->address);
+        btif_storage_remove_bonded_device((bt_bdaddr_t*)bd_addr);
+      }
+    } else {
+      if (pairing_cb.is_le_only) {
+        BTA_DmBondCancel((uint8_t*)bd_addr->address);
+      } else {
+        BTA_DmPinReply((uint8_t*)bd_addr->address, false, 0, NULL);
+      }
+      /* Cancel bonding, in case it is in ACL connection setup state */
+      BTA_DmBondCancel((uint8_t*)bd_addr->address);
+    }
+
+#else
+    if (pairing_cb.is_ssp) {
+      BTA_DmConfirm((uint8_t*)bd_addr->address, false);
+    } else {
+      BTA_DmPinReply((uint8_t*)bd_addr->address, false, 0, NULL);
+    }
+    /* Cancel bonding, in case it is in ACL connection setup state */
+    BTA_DmBondCancel((uint8_t*)bd_addr->address);
+    btif_storage_remove_bonded_device((bt_bdaddr_t*)bd_addr);
+#endif
+  }
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_hh_open_failed
+ *
+ * Description      informs the upper layers if the HH have failed during
+ *                  bonding
+ *
+ * Returns          none
+ *
+ ******************************************************************************/
+
+void btif_dm_hh_open_failed(bt_bdaddr_t* bdaddr) {
+  if (pairing_cb.state == BT_BOND_STATE_BONDING &&
+      bdcmp(bdaddr->address, pairing_cb.bd_addr) == 0) {
+    bond_state_changed(BT_STATUS_FAIL, bdaddr, BT_BOND_STATE_NONE);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_remove_bond
+ *
+ * Description      Removes bonding with the specified device
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+
+bt_status_t btif_dm_remove_bond(const bt_bdaddr_t* bd_addr) {
+  bdstr_t bdstr;
+
+  BTIF_TRACE_EVENT("%s: bd_addr=%s", __func__,
+                   bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr)));
+
+  btif_stats_add_bond_event(bd_addr, BTIF_DM_FUNC_REMOVE_BOND,
+                            pairing_cb.state);
+
+  btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_REMOVE_BOND,
+                        (char*)bd_addr, sizeof(bt_bdaddr_t), NULL);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_pin_reply
+ *
+ * Description      BT legacy pairing - PIN code reply
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+
+bt_status_t btif_dm_pin_reply(const bt_bdaddr_t* bd_addr, uint8_t accept,
+                              uint8_t pin_len, bt_pin_code_t* pin_code) {
+  BTIF_TRACE_EVENT("%s: accept=%d", __func__, accept);
+  if (pin_code == NULL || pin_len > PIN_CODE_LEN) return BT_STATUS_FAIL;
+#if (BLE_INCLUDED == TRUE)
+
+  if (pairing_cb.is_le_only) {
+    int i;
+    uint32_t passkey = 0;
+    int multi[] = {100000, 10000, 1000, 100, 10, 1};
+    BD_ADDR remote_bd_addr;
+    bdcpy(remote_bd_addr, bd_addr->address);
+    for (i = 0; i < 6; i++) {
+      passkey += (multi[i] * (pin_code->pin[i] - '0'));
+    }
+    BTIF_TRACE_DEBUG("btif_dm_pin_reply: passkey: %d", passkey);
+    BTA_DmBlePasskeyReply(remote_bd_addr, accept, passkey);
+
+  } else {
+    BTA_DmPinReply((uint8_t*)bd_addr->address, accept, pin_len, pin_code->pin);
+    if (accept) pairing_cb.pin_code_len = pin_len;
+  }
+#else
+  BTA_DmPinReply((uint8_t*)bd_addr->address, accept, pin_len, pin_code->pin);
+
+  if (accept) pairing_cb.pin_code_len = pin_len;
+#endif
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_ssp_reply
+ *
+ * Description      BT SSP Reply - Just Works, Numeric Comparison & Passkey
+ *                  Entry
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_ssp_reply(const bt_bdaddr_t* bd_addr,
+                              bt_ssp_variant_t variant, uint8_t accept,
+                              UNUSED_ATTR uint32_t passkey) {
+  if (variant == BT_SSP_VARIANT_PASSKEY_ENTRY) {
+    /* This is not implemented in the stack.
+     * For devices with display, this is not needed
+    */
+    BTIF_TRACE_WARNING("%s: Not implemented", __func__);
+    return BT_STATUS_FAIL;
+  }
+  /* BT_SSP_VARIANT_CONSENT & BT_SSP_VARIANT_PASSKEY_CONFIRMATION supported */
+  BTIF_TRACE_EVENT("%s: accept=%d", __func__, accept);
+#if (BLE_INCLUDED == TRUE)
+  if (pairing_cb.is_le_only) {
+    if (pairing_cb.is_le_nc) {
+      BTA_DmBleConfirmReply((uint8_t*)bd_addr->address, accept);
+    } else {
+      if (accept)
+        BTA_DmBleSecurityGrant((uint8_t*)bd_addr->address, BTA_DM_SEC_GRANTED);
+      else
+        BTA_DmBleSecurityGrant((uint8_t*)bd_addr->address,
+                               BTA_DM_SEC_PAIR_NOT_SPT);
+    }
+  } else {
+    BTA_DmConfirm((uint8_t*)bd_addr->address, accept);
+  }
+#else
+  BTA_DmConfirm((uint8_t*)bd_addr->address, accept);
+#endif
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_get_adapter_property
+ *
+ * Description     Queries the BTA for the adapter property
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_get_adapter_property(bt_property_t* prop) {
+  BTIF_TRACE_EVENT("%s: type=0x%x", __func__, prop->type);
+  switch (prop->type) {
+    case BT_PROPERTY_BDNAME: {
+      bt_bdname_t* bd_name = (bt_bdname_t*)prop->val;
+      strncpy((char*)bd_name->name, (char*)btif_get_default_local_name(),
+              sizeof(bd_name->name) - 1);
+      bd_name->name[sizeof(bd_name->name) - 1] = 0;
+      prop->len = strlen((char*)bd_name->name);
+    } break;
+
+    case BT_PROPERTY_ADAPTER_SCAN_MODE: {
+      /* if the storage does not have it. Most likely app never set it. Default
+       * is NONE */
+      bt_scan_mode_t* mode = (bt_scan_mode_t*)prop->val;
+      *mode = BT_SCAN_MODE_NONE;
+      prop->len = sizeof(bt_scan_mode_t);
+    } break;
+
+    case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT: {
+      uint32_t* tmt = (uint32_t*)prop->val;
+      *tmt = 120; /* default to 120s, if not found in NV */
+      prop->len = sizeof(uint32_t);
+    } break;
+
+    default:
+      prop->len = 0;
+      return BT_STATUS_FAIL;
+  }
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_get_remote_services
+ *
+ * Description      Start SDP to get remote services
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_get_remote_services(bt_bdaddr_t* remote_addr) {
+  bdstr_t bdstr;
+
+  BTIF_TRACE_EVENT("%s: remote_addr=%s", __func__,
+                   bdaddr_to_string(remote_addr, bdstr, sizeof(bdstr)));
+
+  BTA_DmDiscover(remote_addr->address, BTA_ALL_SERVICE_MASK,
+                 bte_dm_search_services_evt, true);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_get_remote_services_transport
+ *
+ * Description      Start SDP to get remote services by transport
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_get_remote_services_by_transport(bt_bdaddr_t* remote_addr,
+                                                     const int transport) {
+  BTIF_TRACE_EVENT("%s", __func__);
+
+  /* Set the mask extension */
+  tBTA_SERVICE_MASK_EXT mask_ext;
+  mask_ext.num_uuid = 0;
+  mask_ext.p_uuid = NULL;
+  mask_ext.srvc_mask = BTA_ALL_SERVICE_MASK;
+
+  BTA_DmDiscoverByTransport(remote_addr->address, &mask_ext,
+                            bte_dm_search_services_evt, true, transport);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_get_remote_service_record
+ *
+ * Description      Start SDP to get remote service record
+ *
+ *
+ * Returns          bt_status_t
+ ******************************************************************************/
+bt_status_t btif_dm_get_remote_service_record(bt_bdaddr_t* remote_addr,
+                                              bt_uuid_t* uuid) {
+  tSDP_UUID sdp_uuid;
+  bdstr_t bdstr;
+
+  BTIF_TRACE_EVENT("%s: remote_addr=%s", __func__,
+                   bdaddr_to_string(remote_addr, bdstr, sizeof(bdstr)));
+
+  sdp_uuid.len = MAX_UUID_SIZE;
+  memcpy(sdp_uuid.uu.uuid128, uuid->uu, MAX_UUID_SIZE);
+
+  BTA_DmDiscoverUUID(remote_addr->address, &sdp_uuid,
+                     bte_dm_remote_service_record_evt, true);
+
+  return BT_STATUS_SUCCESS;
+}
+
+void btif_dm_execute_service_request(uint16_t event, char* p_param) {
+  bool b_enable = false;
+  bt_status_t status;
+  if (event == BTIF_DM_ENABLE_SERVICE) {
+    b_enable = true;
+  }
+  status =
+      btif_in_execute_service_request(*((tBTA_SERVICE_ID*)p_param), b_enable);
+  if (status == BT_STATUS_SUCCESS) {
+    bt_property_t property;
+    bt_uuid_t local_uuids[BT_MAX_NUM_UUIDS];
+
+    /* Now send the UUID_PROPERTY_CHANGED event to the upper layer */
+    BTIF_STORAGE_FILL_PROPERTY(&property, BT_PROPERTY_UUIDS,
+                               sizeof(local_uuids), local_uuids);
+    btif_storage_get_adapter_property(&property);
+    HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, BT_STATUS_SUCCESS, 1,
+              &property);
+  }
+  return;
+}
+
+void btif_dm_proc_io_req(UNUSED_ATTR BD_ADDR bd_addr, UNUSED_ATTR tBTA_IO_CAP *p_io_cap,
+                         UNUSED_ATTR tBTA_OOB_DATA *p_oob_data, tBTA_AUTH_REQ* p_auth_req,
+                         bool is_orig) {
+  uint8_t yes_no_bit = BTA_AUTH_SP_YES & *p_auth_req;
+  /* if local initiated:
+  **      1. set DD + MITM
+  ** if remote initiated:
+  **      1. Copy over the auth_req from peer's io_rsp
+  **      2. Set the MITM if peer has it set or if peer has DisplayYesNo
+  *(iPhone)
+  ** as a fallback set MITM+GB if peer had MITM set
+  */
+
+  BTIF_TRACE_DEBUG("+%s: p_auth_req=%d", __func__, *p_auth_req);
+  if (pairing_cb.is_local_initiated) {
+    /* if initing/responding to a dedicated bonding, use dedicate bonding bit */
+    *p_auth_req = BTA_AUTH_DD_BOND | BTA_AUTH_SP_YES;
+  } else if (!is_orig) {
+    /* peer initiated paring. They probably know what they want.
+    ** Copy the mitm from peer device.
+    */
+    BTIF_TRACE_DEBUG("%s: setting p_auth_req to peer's: %d", __func__,
+                     pairing_cb.auth_req);
+    *p_auth_req = (pairing_cb.auth_req & BTA_AUTH_BONDS);
+
+    /* copy over the MITM bit as well. In addition if the peer has DisplayYesNo,
+     * force MITM */
+    if ((yes_no_bit) || (pairing_cb.io_cap & BTM_IO_CAP_IO))
+      *p_auth_req |= BTA_AUTH_SP_YES;
+  } else if (yes_no_bit) {
+    /* set the general bonding bit for stored device */
+    *p_auth_req = BTA_AUTH_GEN_BOND | yes_no_bit;
+  }
+  BTIF_TRACE_DEBUG("-%s: p_auth_req=%d", __func__, *p_auth_req);
+}
+
+void btif_dm_proc_io_rsp(UNUSED_ATTR BD_ADDR bd_addr, tBTA_IO_CAP io_cap,
+                         UNUSED_ATTR tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req) {
+  if (auth_req & BTA_AUTH_BONDS) {
+    BTIF_TRACE_DEBUG("%s auth_req:%d", __func__, auth_req);
+    pairing_cb.auth_req = auth_req;
+    pairing_cb.io_cap = io_cap;
+  }
+}
+
+void btif_dm_set_oob_for_io_req(tBTA_OOB_DATA* p_has_oob_data) {
+  if (is_empty_128bit(oob_cb.oob_data.c192)) {
+    *p_has_oob_data = false;
+  } else {
+    *p_has_oob_data = true;
+  }
+  BTIF_TRACE_DEBUG("%s: *p_has_oob_data=%d", __func__, *p_has_oob_data);
+}
+
+void btif_dm_set_oob_for_le_io_req(BD_ADDR bd_addr,
+                                   tBTA_OOB_DATA* p_has_oob_data,
+                                   tBTA_LE_AUTH_REQ* p_auth_req) {
+  if (!is_empty_128bit(oob_cb.oob_data.le_sc_c) &&
+      !is_empty_128bit(oob_cb.oob_data.le_sc_r)) {
+    /* We have LE SC OOB data */
+
+    /* make sure OOB data is for this particular device */
+    if (memcmp(bd_addr, oob_cb.bdaddr, BD_ADDR_LEN) == 0) {
+      *p_auth_req = ((*p_auth_req) | BTM_LE_AUTH_REQ_SC_ONLY);
+      *p_has_oob_data = true;
+    } else {
+      *p_has_oob_data = false;
+      BTIF_TRACE_WARNING("%s: remote address didn't match OOB data address",
+                         __func__);
+    }
+  } else if (!is_empty_128bit(oob_cb.oob_data.sm_tk)) {
+    /* We have security manager TK */
+
+    /* make sure OOB data is for this particular device */
+    if (memcmp(bd_addr, oob_cb.bdaddr, BD_ADDR_LEN) == 0) {
+      // When using OOB with TK, SC Secure Connections bit must be disabled.
+      tBTA_LE_AUTH_REQ mask = ~BTM_LE_AUTH_REQ_SC_ONLY;
+      *p_auth_req = ((*p_auth_req) & mask);
+
+      *p_has_oob_data = true;
+    } else {
+      *p_has_oob_data = false;
+      BTIF_TRACE_WARNING("%s: remote address didn't match OOB data address",
+                         __func__);
+    }
+  } else {
+    *p_has_oob_data = false;
+  }
+  BTIF_TRACE_DEBUG("%s *p_has_oob_data=%d", __func__, *p_has_oob_data);
+}
+
+#ifdef BTIF_DM_OOB_TEST
+void btif_dm_load_local_oob(void) {
+  char prop_oob[PROPERTY_VALUE_MAX];
+  osi_property_get("service.brcm.bt.oob", prop_oob, "3");
+  BTIF_TRACE_DEBUG("%s: prop_oob = %s", __func__, prop_oob);
+  if (prop_oob[0] != '3') {
+    if (is_empty_128bit(oob_cb.oob_data.c192)) {
+      BTIF_TRACE_DEBUG("%s: read OOB, call BTA_DmLocalOob()", __func__);
+      BTA_DmLocalOob();
+    }
+  }
+}
+
+void btif_dm_proc_loc_oob(bool valid, BT_OCTET16 c, BT_OCTET16 r) {
+  FILE* fp;
+  const char* path_a = "/data/misc/bluedroid/LOCAL/a.key";
+  const char* path_b = "/data/misc/bluedroid/LOCAL/b.key";
+  const char* path = NULL;
+  char prop_oob[PROPERTY_VALUE_MAX];
+  BTIF_TRACE_DEBUG("%s: valid=%d", __func__, valid);
+  if (is_empty_128bit(oob_cb.oob_data.c192) && valid) {
+    BTIF_TRACE_DEBUG("save local OOB data in memory");
+    memcpy(oob_cb.oob_data.c192, c, BT_OCTET16_LEN);
+    memcpy(oob_cb.oob_data.r192, r, BT_OCTET16_LEN);
+    osi_property_get("service.brcm.bt.oob", prop_oob, "3");
+    BTIF_TRACE_DEBUG("%s: prop_oob = %s", __func__, prop_oob);
+    if (prop_oob[0] == '1')
+      path = path_a;
+    else if (prop_oob[0] == '2')
+      path = path_b;
+    if (path) {
+      fp = fopen(path, "wb+");
+      if (fp == NULL) {
+        BTIF_TRACE_DEBUG("%s: failed to save local OOB data to %s", __func__,
+                         path);
+      } else {
+        BTIF_TRACE_DEBUG("%s: save local OOB data into file %s", __func__,
+                         path);
+        fwrite(c, 1, BT_OCTET16_LEN, fp);
+        fwrite(r, 1, BT_OCTET16_LEN, fp);
+        fclose(fp);
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_get_smp_config
+ *
+ * Description      Retrieve the SMP pairing options from the bt_stack.conf
+ *                  file. To provide specific pairing options for the host
+ *                  add a node with label "SmpOptions" to the config file
+ *                  and assign it a comma separated list of 5 values in the
+ *                  format: auth, io, ikey, rkey, ksize, oob
+ *                  eg: PTS_SmpOptions=0xD,0x4,0xf,0xf,0x10
+ *
+ * Parameters:      tBTE_APPL_CFG*: pointer to struct defining pairing options
+ *
+ * Returns          true if the options were successfully read, else false
+ *
+ ******************************************************************************/
+bool btif_dm_get_smp_config(tBTE_APPL_CFG* p_cfg) {
+  if (!stack_config_get_interface()->get_pts_smp_options()) {
+    BTIF_TRACE_DEBUG("%s: SMP options not found in configuration", __func__);
+    return false;
+  }
+
+  char conf[64];
+  const char* recv = stack_config_get_interface()->get_pts_smp_options();
+  char* pch;
+  char* endptr;
+
+  strncpy(conf, recv, 64);
+  conf[63] = 0;  // null terminate
+
+  if ((pch = strtok(conf, ",")) != NULL)
+    p_cfg->ble_auth_req = (uint8_t)strtoul(pch, &endptr, 16);
+  else
+    return false;
+
+  if ((pch = strtok(NULL, ",")) != NULL)
+    p_cfg->ble_io_cap = (uint8_t)strtoul(pch, &endptr, 16);
+  else
+    return false;
+
+  if ((pch = strtok(NULL, ",")) != NULL)
+    p_cfg->ble_init_key = (uint8_t)strtoul(pch, &endptr, 16);
+  else
+    return false;
+
+  if ((pch = strtok(NULL, ",")) != NULL)
+    p_cfg->ble_resp_key = (uint8_t)strtoul(pch, &endptr, 16);
+  else
+    return false;
+
+  if ((pch = strtok(NULL, ",")) != NULL)
+    p_cfg->ble_max_key_size = (uint8_t)strtoul(pch, &endptr, 16);
+  else
+    return false;
+
+  return true;
+}
+
+bool btif_dm_proc_rmt_oob(BD_ADDR bd_addr, BT_OCTET16 p_c, BT_OCTET16 p_r) {
+  char t[128];
+  FILE* fp;
+  const char* path_a = "/data/misc/bluedroid/LOCAL/a.key";
+  const char* path_b = "/data/misc/bluedroid/LOCAL/b.key";
+  const char* path = NULL;
+  char prop_oob[PROPERTY_VALUE_MAX];
+  bool result = false;
+  bt_bdaddr_t bt_bd_addr;
+  bdcpy(oob_cb.bdaddr, bd_addr);
+  osi_property_get("service.brcm.bt.oob", prop_oob, "3");
+  BTIF_TRACE_DEBUG("%s: prop_oob = %s", __func__, prop_oob);
+  if (prop_oob[0] == '1')
+    path = path_b;
+  else if (prop_oob[0] == '2')
+    path = path_a;
+  if (path) {
+    fp = fopen(path, "rb");
+    if (fp == NULL) {
+      BTIF_TRACE_DEBUG("%s: failed to read OOB keys from %s", __func__, path);
+      return false;
+    } else {
+      BTIF_TRACE_DEBUG("%s: read OOB data from %s", __func__, path);
+      fread(p_c, 1, BT_OCTET16_LEN, fp);
+      fread(p_r, 1, BT_OCTET16_LEN, fp);
+      fclose(fp);
+    }
+    BTIF_TRACE_DEBUG("----%s: true", __func__);
+    snprintf(t, sizeof(t), "%02x:%02x:%02x:%02x:%02x:%02x", oob_cb.bdaddr[0],
+             oob_cb.bdaddr[1], oob_cb.bdaddr[2], oob_cb.bdaddr[3],
+             oob_cb.bdaddr[4], oob_cb.bdaddr[5]);
+    BTIF_TRACE_DEBUG("----%s: peer_bdaddr = %s", __func__, t);
+    snprintf(t, sizeof(t),
+             "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x "
+             "%02x %02x %02x",
+             p_c[0], p_c[1], p_c[2], p_c[3], p_c[4], p_c[5], p_c[6], p_c[7],
+             p_c[8], p_c[9], p_c[10], p_c[11], p_c[12], p_c[13], p_c[14],
+             p_c[15]);
+    BTIF_TRACE_DEBUG("----%s: c = %s", __func__, t);
+    snprintf(t, sizeof(t),
+             "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x "
+             "%02x %02x %02x",
+             p_r[0], p_r[1], p_r[2], p_r[3], p_r[4], p_r[5], p_r[6], p_r[7],
+             p_r[8], p_r[9], p_r[10], p_r[11], p_r[12], p_r[13], p_r[14],
+             p_r[15]);
+    BTIF_TRACE_DEBUG("----%s: r = %s", __func__, t);
+    bdcpy(bt_bd_addr.address, bd_addr);
+    btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_BOND_STATE_BONDING,
+                          (char*)&bt_bd_addr, sizeof(bt_bdaddr_t), NULL);
+    result = true;
+  }
+  BTIF_TRACE_DEBUG("%s: result=%d", __func__, result);
+  return result;
+}
+#endif /*  BTIF_DM_OOB_TEST */
+#if (BLE_INCLUDED == TRUE)
+
+static void btif_dm_ble_key_notif_evt(tBTA_DM_SP_KEY_NOTIF* p_ssp_key_notif) {
+  bt_bdaddr_t bd_addr;
+  bt_bdname_t bd_name;
+  uint32_t cod;
+  int dev_type;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  /* Remote name update */
+  if (!btif_get_device_type(p_ssp_key_notif->bd_addr, &dev_type)) {
+    dev_type = BT_DEVICE_TYPE_BLE;
+  }
+  btif_dm_update_ble_remote_properties(p_ssp_key_notif->bd_addr,
+                                       p_ssp_key_notif->bd_name,
+                                       (tBT_DEVICE_TYPE)dev_type);
+  bdcpy(bd_addr.address, p_ssp_key_notif->bd_addr);
+  memcpy(bd_name.name, p_ssp_key_notif->bd_name, BD_NAME_LEN);
+
+  bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+  pairing_cb.is_ssp = false;
+  cod = COD_UNCLASSIFIED;
+
+  HAL_CBACK(bt_hal_cbacks, ssp_request_cb, &bd_addr, &bd_name, cod,
+            BT_SSP_VARIANT_PASSKEY_NOTIFICATION, p_ssp_key_notif->passkey);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_ble_auth_cmpl_evt
+ *
+ * Description      Executes authentication complete event in btif context
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_dm_ble_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) {
+  /* Save link key, if not temporary */
+  bt_bdaddr_t bd_addr;
+  bt_status_t status = BT_STATUS_FAIL;
+  bt_bond_state_t state = BT_BOND_STATE_NONE;
+
+  bdcpy(bd_addr.address, p_auth_cmpl->bd_addr);
+
+  /* Clear OOB data */
+  memset(&oob_cb, 0, sizeof(oob_cb));
+
+  if ((p_auth_cmpl->success == true) && (p_auth_cmpl->key_present)) {
+    /* store keys */
+  }
+  if (p_auth_cmpl->success) {
+    status = BT_STATUS_SUCCESS;
+    state = BT_BOND_STATE_BONDED;
+    int addr_type;
+    bt_bdaddr_t bdaddr;
+    bdcpy(bdaddr.address, p_auth_cmpl->bd_addr);
+    if (btif_storage_get_remote_addr_type(&bdaddr, &addr_type) !=
+        BT_STATUS_SUCCESS)
+      btif_storage_set_remote_addr_type(&bdaddr, p_auth_cmpl->addr_type);
+
+    /* Test for temporary bonding */
+    if (btm_get_bond_type_dev(p_auth_cmpl->bd_addr) == BOND_TYPE_TEMPORARY) {
+      BTIF_TRACE_DEBUG("%s: sending BT_BOND_STATE_NONE for Temp pairing",
+                       __func__);
+      btif_storage_remove_bonded_device(&bdaddr);
+      state = BT_BOND_STATE_NONE;
+    } else {
+      btif_dm_save_ble_bonding_keys();
+      BTA_GATTC_Refresh(bd_addr.address);
+      btif_dm_get_remote_services_by_transport(&bd_addr, BTA_GATT_TRANSPORT_LE);
+    }
+  } else {
+    /*Map the HCI fail reason  to  bt status  */
+    switch (p_auth_cmpl->fail_reason) {
+      case BTA_DM_AUTH_SMP_PAIR_AUTH_FAIL:
+      case BTA_DM_AUTH_SMP_CONFIRM_VALUE_FAIL:
+      case BTA_DM_AUTH_SMP_UNKNOWN_ERR:
+      case BTA_DM_AUTH_SMP_CONN_TOUT:
+        btif_dm_remove_ble_bonding_keys();
+        status = BT_STATUS_AUTH_FAILURE;
+        break;
+      case BTA_DM_AUTH_SMP_PAIR_NOT_SUPPORT:
+        status = BT_STATUS_AUTH_REJECTED;
+        break;
+      default:
+        btif_dm_remove_ble_bonding_keys();
+        status = BT_STATUS_FAIL;
+        break;
+    }
+  }
+  bond_state_changed(status, &bd_addr, state);
+}
+
+void btif_dm_load_ble_local_keys(void) {
+  memset(&ble_local_key_cb, 0, sizeof(btif_dm_local_key_cb_t));
+
+  if (btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_ER,
+                                     (char*)&ble_local_key_cb.er[0],
+                                     BT_OCTET16_LEN) == BT_STATUS_SUCCESS) {
+    ble_local_key_cb.is_er_rcvd = true;
+    BTIF_TRACE_DEBUG("%s BLE ER key loaded", __func__);
+  }
+
+  if ((btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_IR,
+                                      (char*)&ble_local_key_cb.id_keys.ir[0],
+                                      BT_OCTET16_LEN) == BT_STATUS_SUCCESS) &&
+      (btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_IRK,
+                                      (char*)&ble_local_key_cb.id_keys.irk[0],
+                                      BT_OCTET16_LEN) == BT_STATUS_SUCCESS) &&
+      (btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_DHK,
+                                      (char*)&ble_local_key_cb.id_keys.dhk[0],
+                                      BT_OCTET16_LEN) == BT_STATUS_SUCCESS)) {
+    ble_local_key_cb.is_id_keys_rcvd = true;
+    BTIF_TRACE_DEBUG("%s BLE ID keys loaded", __func__);
+  }
+}
+void btif_dm_get_ble_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask,
+                                BT_OCTET16 er,
+                                tBTA_BLE_LOCAL_ID_KEYS* p_id_keys) {
+  if (ble_local_key_cb.is_er_rcvd) {
+    memcpy(&er[0], &ble_local_key_cb.er[0], sizeof(BT_OCTET16));
+    *p_key_mask |= BTA_BLE_LOCAL_KEY_TYPE_ER;
+  }
+
+  if (ble_local_key_cb.is_id_keys_rcvd) {
+    memcpy(&p_id_keys->ir[0], &ble_local_key_cb.id_keys.ir[0],
+           sizeof(BT_OCTET16));
+    memcpy(&p_id_keys->irk[0], &ble_local_key_cb.id_keys.irk[0],
+           sizeof(BT_OCTET16));
+    memcpy(&p_id_keys->dhk[0], &ble_local_key_cb.id_keys.dhk[0],
+           sizeof(BT_OCTET16));
+    *p_key_mask |= BTA_BLE_LOCAL_KEY_TYPE_ID;
+  }
+  BTIF_TRACE_DEBUG("%s  *p_key_mask=0x%02x", __func__, *p_key_mask);
+}
+
+void btif_dm_save_ble_bonding_keys(void) {
+  bt_bdaddr_t bd_addr;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  bdcpy(bd_addr.address, pairing_cb.bd_addr);
+
+  if (pairing_cb.ble.is_penc_key_rcvd) {
+    btif_storage_add_ble_bonding_key(&bd_addr, (char*)&pairing_cb.ble.penc_key,
+                                     BTIF_DM_LE_KEY_PENC,
+                                     sizeof(tBTM_LE_PENC_KEYS));
+  }
+
+  if (pairing_cb.ble.is_pid_key_rcvd) {
+    btif_storage_add_ble_bonding_key(&bd_addr, (char*)&pairing_cb.ble.pid_key,
+                                     BTIF_DM_LE_KEY_PID,
+                                     sizeof(tBTM_LE_PID_KEYS));
+  }
+
+  if (pairing_cb.ble.is_pcsrk_key_rcvd) {
+    btif_storage_add_ble_bonding_key(&bd_addr, (char*)&pairing_cb.ble.pcsrk_key,
+                                     BTIF_DM_LE_KEY_PCSRK,
+                                     sizeof(tBTM_LE_PCSRK_KEYS));
+  }
+
+  if (pairing_cb.ble.is_lenc_key_rcvd) {
+    btif_storage_add_ble_bonding_key(&bd_addr, (char*)&pairing_cb.ble.lenc_key,
+                                     BTIF_DM_LE_KEY_LENC,
+                                     sizeof(tBTM_LE_LENC_KEYS));
+  }
+
+  if (pairing_cb.ble.is_lcsrk_key_rcvd) {
+    btif_storage_add_ble_bonding_key(&bd_addr, (char*)&pairing_cb.ble.lcsrk_key,
+                                     BTIF_DM_LE_KEY_LCSRK,
+                                     sizeof(tBTM_LE_LCSRK_KEYS));
+  }
+
+  if (pairing_cb.ble.is_lidk_key_rcvd) {
+    btif_storage_add_ble_bonding_key(&bd_addr, NULL, BTIF_DM_LE_KEY_LID, 0);
+  }
+}
+
+void btif_dm_remove_ble_bonding_keys(void) {
+  bt_bdaddr_t bd_addr;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  bdcpy(bd_addr.address, pairing_cb.bd_addr);
+  btif_storage_remove_ble_bonding_keys(&bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_ble_sec_req_evt
+ *
+ * Description      Eprocess security request event in btif context
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btif_dm_ble_sec_req_evt(tBTA_DM_BLE_SEC_REQ* p_ble_req) {
+  bt_bdaddr_t bd_addr;
+  bt_bdname_t bd_name;
+  uint32_t cod;
+  int dev_type;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  if (pairing_cb.state == BT_BOND_STATE_BONDING) {
+    BTIF_TRACE_DEBUG("%s Discard security request", __func__);
+    return;
+  }
+
+  /* Remote name update */
+  if (!btif_get_device_type(p_ble_req->bd_addr, &dev_type)) {
+    dev_type = BT_DEVICE_TYPE_BLE;
+  }
+  btif_dm_update_ble_remote_properties(p_ble_req->bd_addr, p_ble_req->bd_name,
+                                       (tBT_DEVICE_TYPE)dev_type);
+
+  bdcpy(bd_addr.address, p_ble_req->bd_addr);
+  memcpy(bd_name.name, p_ble_req->bd_name, BD_NAME_LEN);
+
+  bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+
+  pairing_cb.bond_type = BOND_TYPE_PERSISTENT;
+  pairing_cb.is_le_only = true;
+  pairing_cb.is_le_nc = false;
+  pairing_cb.is_ssp = true;
+  btm_set_bond_type_dev(p_ble_req->bd_addr, pairing_cb.bond_type);
+
+  cod = COD_UNCLASSIFIED;
+
+  HAL_CBACK(bt_hal_cbacks, ssp_request_cb, &bd_addr, &bd_name, cod,
+            BT_SSP_VARIANT_CONSENT, 0);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_ble_passkey_req_evt
+ *
+ * Description      Executes pin request event in btif context
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_dm_ble_passkey_req_evt(tBTA_DM_PIN_REQ* p_pin_req) {
+  bt_bdaddr_t bd_addr;
+  bt_bdname_t bd_name;
+  uint32_t cod;
+  int dev_type;
+
+  /* Remote name update */
+  if (!btif_get_device_type(p_pin_req->bd_addr, &dev_type)) {
+    dev_type = BT_DEVICE_TYPE_BLE;
+  }
+  btif_dm_update_ble_remote_properties(p_pin_req->bd_addr, p_pin_req->bd_name,
+                                       (tBT_DEVICE_TYPE)dev_type);
+
+  bdcpy(bd_addr.address, p_pin_req->bd_addr);
+  memcpy(bd_name.name, p_pin_req->bd_name, BD_NAME_LEN);
+
+  bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+  pairing_cb.is_le_only = true;
+
+  cod = COD_UNCLASSIFIED;
+
+  HAL_CBACK(bt_hal_cbacks, pin_request_cb, &bd_addr, &bd_name, cod, false);
+}
+static void btif_dm_ble_key_nc_req_evt(tBTA_DM_SP_KEY_NOTIF* p_notif_req) {
+  /* TODO implement key notification for numeric comparison */
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  /* Remote name update */
+  btif_update_remote_properties(p_notif_req->bd_addr, p_notif_req->bd_name,
+                                NULL, BT_DEVICE_TYPE_BLE);
+
+  bt_bdaddr_t bd_addr;
+  bdcpy(bd_addr.address, p_notif_req->bd_addr);
+
+  bt_bdname_t bd_name;
+  memcpy(bd_name.name, p_notif_req->bd_name, BD_NAME_LEN);
+
+  bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+  pairing_cb.is_ssp = false;
+  pairing_cb.is_le_only = true;
+  pairing_cb.is_le_nc = true;
+
+  HAL_CBACK(bt_hal_cbacks, ssp_request_cb, &bd_addr, &bd_name, COD_UNCLASSIFIED,
+            BT_SSP_VARIANT_PASSKEY_CONFIRMATION, p_notif_req->passkey);
+}
+
+static void btif_dm_ble_oob_req_evt(tBTA_DM_SP_RMT_OOB* req_oob_type) {
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  bt_bdaddr_t bd_addr;
+  bdcpy(bd_addr.address, req_oob_type->bd_addr);
+  /* We already checked if OOB data is present in
+   * btif_dm_set_oob_for_le_io_req, but check here again. If it's not present
+   * do nothing, pairing will timeout.
+   */
+  if (is_empty_128bit(oob_cb.oob_data.sm_tk)) {
+    return;
+  }
+
+  /* make sure OOB data is for this particular device */
+  if (memcmp(req_oob_type->bd_addr, oob_cb.bdaddr, BD_ADDR_LEN) != 0) {
+    BTIF_TRACE_WARNING("%s: remote address didn't match OOB data address",
+                       __func__);
+    return;
+  }
+
+  /* Remote name update */
+  btif_update_remote_properties(req_oob_type->bd_addr, req_oob_type->bd_name,
+                                NULL, BT_DEVICE_TYPE_BLE);
+
+  bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+  pairing_cb.is_ssp = false;
+  pairing_cb.is_le_only = true;
+  pairing_cb.is_le_nc = false;
+
+  BTM_BleOobDataReply(req_oob_type->bd_addr, 0, 16, oob_cb.oob_data.sm_tk);
+}
+
+static void btif_dm_ble_sc_oob_req_evt(tBTA_DM_SP_RMT_OOB* req_oob_type) {
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  bt_bdaddr_t bd_addr;
+  bdcpy(bd_addr.address, req_oob_type->bd_addr);
+
+  /* We already checked if OOB data is present in
+   * btif_dm_set_oob_for_le_io_req, but check here again. If it's not present
+   * do nothing, pairing will timeout.
+   */
+  if (is_empty_128bit(oob_cb.oob_data.le_sc_c) &&
+      is_empty_128bit(oob_cb.oob_data.le_sc_r)) {
+    BTIF_TRACE_WARNING("%s: LE SC OOB data is empty", __func__);
+    return;
+  }
+
+  /* make sure OOB data is for this particular device */
+  if (memcmp(req_oob_type->bd_addr, oob_cb.bdaddr, BD_ADDR_LEN) != 0) {
+    BTIF_TRACE_WARNING("%s: remote address didn't match OOB data address",
+                       __func__);
+    return;
+  }
+
+  /* Remote name update */
+  btif_update_remote_properties(req_oob_type->bd_addr, req_oob_type->bd_name,
+                                NULL, BT_DEVICE_TYPE_BLE);
+
+  bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+  pairing_cb.is_ssp = false;
+  pairing_cb.is_le_only =
+      true;  // TODO: we can derive classic pairing from this one
+  pairing_cb.is_le_nc = false;
+
+  BTM_BleSecureConnectionOobDataReply(
+      req_oob_type->bd_addr, oob_cb.oob_data.le_sc_c, oob_cb.oob_data.le_sc_r);
+}
+
+void btif_dm_update_ble_remote_properties(BD_ADDR bd_addr, BD_NAME bd_name,
+                                          tBT_DEVICE_TYPE dev_type) {
+  btif_update_remote_properties(bd_addr, bd_name, NULL, dev_type);
+}
+
+static void btif_dm_ble_tx_test_cback(void* p) {
+  btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_LE_TX_TEST, (char*)p, 1,
+                        NULL);
+}
+
+static void btif_dm_ble_rx_test_cback(void* p) {
+  btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_LE_RX_TEST, (char*)p, 1,
+                        NULL);
+}
+
+static void btif_dm_ble_test_end_cback(void* p) {
+  btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_LE_TEST_END, (char*)p,
+                        3, NULL);
+}
+/*******************************************************************************
+ *
+ * Function         btif_le_test_mode
+ *
+ * Description     Sends a HCI BLE Test command to the Controller
+ *
+ * Returns          BT_STATUS_SUCCESS on success
+ *
+ ******************************************************************************/
+bt_status_t btif_le_test_mode(uint16_t opcode, uint8_t* buf, uint8_t len) {
+  switch (opcode) {
+    case HCI_BLE_TRANSMITTER_TEST:
+      if (len != 3) return BT_STATUS_PARM_INVALID;
+      BTM_BleTransmitterTest(buf[0], buf[1], buf[2], btif_dm_ble_tx_test_cback);
+      break;
+    case HCI_BLE_RECEIVER_TEST:
+      if (len != 1) return BT_STATUS_PARM_INVALID;
+      BTM_BleReceiverTest(buf[0], btif_dm_ble_rx_test_cback);
+      break;
+    case HCI_BLE_TEST_END:
+      BTM_BleTestEnd((tBTM_CMPL_CB*)btif_dm_ble_test_end_cback);
+      break;
+    default:
+      BTIF_TRACE_ERROR("%s: Unknown LE Test Mode Command 0x%x", __func__,
+                       opcode);
+      return BT_STATUS_UNSUPPORTED;
+  }
+  return BT_STATUS_SUCCESS;
+}
+#endif
+
+void btif_dm_on_disable() {
+  /* cancel any pending pairing requests */
+  if (pairing_cb.state == BT_BOND_STATE_BONDING) {
+    bt_bdaddr_t bd_addr;
+
+    BTIF_TRACE_DEBUG("%s: Cancel pending pairing request", __func__);
+    bdcpy(bd_addr.address, pairing_cb.bd_addr);
+    btif_dm_cancel_bond(&bd_addr);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_dm_read_energy_info
+ *
+ * Description     Reads the energy info from controller
+ *
+ * Returns         void
+ *
+ ******************************************************************************/
+void btif_dm_read_energy_info() {
+#if (BLE_INCLUDED == TRUE)
+  BTA_DmBleGetEnergyInfo(bta_energy_info_cb);
+#endif
+}
+
+static char* btif_get_default_local_name() {
+  if (btif_default_local_name[0] == '\0') {
+    int max_len = sizeof(btif_default_local_name) - 1;
+    if (BTM_DEF_LOCAL_NAME[0] != '\0') {
+      strncpy(btif_default_local_name, BTM_DEF_LOCAL_NAME, max_len);
+    } else {
+      char prop_model[PROPERTY_VALUE_MAX];
+      osi_property_get(PROPERTY_PRODUCT_MODEL, prop_model, "");
+      strncpy(btif_default_local_name, prop_model, max_len);
+    }
+    btif_default_local_name[max_len] = '\0';
+  }
+  return btif_default_local_name;
+}
+
+static void btif_stats_add_bond_event(const bt_bdaddr_t* bd_addr,
+                                      bt_bond_function_t function,
+                                      bt_bond_state_t state) {
+  std::unique_lock<std::mutex> lock(bond_event_lock);
+
+  btif_bond_event_t* event = &btif_dm_bond_events[btif_events_end_index];
+  memcpy(&event->bd_addr, bd_addr, sizeof(bt_bdaddr_t));
+  event->function = function;
+  event->state = state;
+  clock_gettime(CLOCK_REALTIME, &event->timestamp);
+
+  btif_num_bond_events++;
+  btif_events_end_index =
+      (btif_events_end_index + 1) % (MAX_BTIF_BOND_EVENT_ENTRIES + 1);
+  if (btif_events_end_index == btif_events_start_index) {
+    btif_events_start_index =
+        (btif_events_start_index + 1) % (MAX_BTIF_BOND_EVENT_ENTRIES + 1);
+  }
+
+  int type;
+  btif_get_device_type(bd_addr->address, &type);
+
+  device_type_t device_type;
+  switch (type) {
+    case BT_DEVICE_TYPE_BREDR:
+      device_type = DEVICE_TYPE_BREDR;
+      break;
+    case BT_DEVICE_TYPE_BLE:
+      device_type = DEVICE_TYPE_LE;
+      break;
+    case BT_DEVICE_TYPE_DUMO:
+      device_type = DEVICE_TYPE_DUMO;
+      break;
+    default:
+      device_type = DEVICE_TYPE_UNKNOWN;
+      break;
+  }
+
+  uint32_t cod = get_cod(bd_addr);
+  uint64_t ts =
+      event->timestamp.tv_sec * 1000 + event->timestamp.tv_nsec / 1000000;
+  metrics_pair_event(0, ts, cod, device_type);
+}
+
+void btif_debug_bond_event_dump(int fd) {
+  std::unique_lock<std::mutex> lock(bond_event_lock);
+  dprintf(fd, "\nBond Events: \n");
+  dprintf(fd, "  Total Number of events: %zu\n", btif_num_bond_events);
+  if (btif_num_bond_events > 0)
+    dprintf(fd,
+            "  Time          BD_ADDR            Function             State\n");
+
+  for (size_t i = btif_events_start_index; i != btif_events_end_index;
+       i = (i + 1) % (MAX_BTIF_BOND_EVENT_ENTRIES + 1)) {
+    btif_bond_event_t* event = &btif_dm_bond_events[i];
+
+    char eventtime[20];
+    char temptime[20];
+    struct tm* tstamp = localtime(&event->timestamp.tv_sec);
+    strftime(temptime, sizeof(temptime), "%H:%M:%S", tstamp);
+    snprintf(eventtime, sizeof(eventtime), "%s.%03ld", temptime,
+             event->timestamp.tv_nsec / 1000000);
+
+    char bdaddr[18];
+    bdaddr_to_string(&event->bd_addr, bdaddr, sizeof(bdaddr));
+
+    const char* func_name;
+    switch (event->function) {
+      case BTIF_DM_FUNC_CREATE_BOND:
+        func_name = "btif_dm_create_bond";
+        break;
+      case BTIF_DM_FUNC_REMOVE_BOND:
+        func_name = "btif_dm_remove_bond";
+        break;
+      case BTIF_DM_FUNC_BOND_STATE_CHANGED:
+        func_name = "bond_state_changed ";
+        break;
+      default:
+        func_name = "Invalid value      ";
+        break;
+    }
+
+    const char* bond_state;
+    switch (event->state) {
+      case BT_BOND_STATE_NONE:
+        bond_state = "BOND_STATE_NONE";
+        break;
+      case BT_BOND_STATE_BONDING:
+        bond_state = "BOND_STATE_BONDING";
+        break;
+      case BT_BOND_STATE_BONDED:
+        bond_state = "BOND_STATE_BONDED";
+        break;
+      default:
+        bond_state = "Invalid bond state";
+        break;
+    }
+    dprintf(fd, "  %s  %s  %s  %s\n", eventtime, bdaddr, func_name, bond_state);
+  }
+}
diff --git a/bt/btif/src/btif_gatt.cc b/bt/btif/src/btif_gatt.cc
new file mode 100644
index 0000000..8465d37
--- /dev/null
+++ b/bt/btif/src/btif_gatt.cc
@@ -0,0 +1,108 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ *  Filename:      btif_gatt.c
+ *
+ *  Description:   GATT Profile Bluetooth Interface
+ *
+ *******************************************************************************/
+
+#define LOG_TAG "bt_btif_gatt"
+
+#include <errno.h>
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "btif_common.h"
+#include "btif_util.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+#include "bta_api.h"
+#include "bta_gatt_api.h"
+#include "btif_gatt.h"
+#include "btif_gatt_util.h"
+#include "btif_storage.h"
+
+const btgatt_callbacks_t* bt_gatt_callbacks = NULL;
+
+/*******************************************************************************
+ *
+ * Function         btif_gatt_init
+ *
+ * Description      Initializes the GATT interface
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t btif_gatt_init(const btgatt_callbacks_t* callbacks) {
+  bt_gatt_callbacks = callbacks;
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_gatt_cleanup
+ *
+ * Description      Closes the GATT interface
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_gatt_cleanup(void) {
+  if (bt_gatt_callbacks) bt_gatt_callbacks = NULL;
+
+  BTA_GATTC_Disable();
+  BTA_GATTS_Disable();
+}
+
+static btgatt_interface_t btgattInterface = {
+    sizeof(btgattInterface),
+
+    btif_gatt_init,
+    btif_gatt_cleanup,
+
+    &btgattClientInterface,
+    &btgattServerInterface,
+    &btgattScannerInterface,
+    nullptr  // filled in btif_gatt_get_interface
+};
+
+/*******************************************************************************
+ *
+ * Function         btif_gatt_get_interface
+ *
+ * Description      Get the gatt callback interface
+ *
+ * Returns          btgatt_interface_t
+ *
+ ******************************************************************************/
+const btgatt_interface_t* btif_gatt_get_interface() {
+  // TODO(jpawlowski) right now initializing advertiser field in static
+  // structure cause explosion of dependencies. It must be initialized here
+  // until those dependencies are properly abstracted for tests.
+  btgattInterface.advertiser = get_ble_advertiser_instance();
+  return &btgattInterface;
+}
+
+#endif
diff --git a/bt/btif/src/btif_gatt_client.cc b/bt/btif/src/btif_gatt_client.cc
new file mode 100644
index 0000000..3c49656
--- /dev/null
+++ b/bt/btif/src/btif_gatt_client.cc
@@ -0,0 +1,565 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-2014 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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ *  Filename:      btif_gatt_client.c
+ *
+ *  Description:   GATT client implementation
+ *
+ *******************************************************************************/
+
+#define LOG_TAG "bt_btif_gattc"
+
+#include <base/at_exit.h>
+#include <base/bind.h>
+#include <base/threading/thread.h>
+#include <errno.h>
+#include <hardware/bluetooth.h>
+#include <stdlib.h>
+#include <string.h>
+#include "device/include/controller.h"
+
+#include "btcore/include/bdaddr.h"
+#include "btif_common.h"
+#include "btif_util.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+#include <hardware/bt_gatt.h>
+
+#include "bta_api.h"
+#include "bta_gatt_api.h"
+#include "btif_config.h"
+#include "btif_dm.h"
+#include "btif_gatt.h"
+#include "btif_gatt_util.h"
+#include "btif_storage.h"
+#include "osi/include/log.h"
+#include "vendor_api.h"
+
+using base::Bind;
+using base::Owned;
+using std::vector;
+
+extern bt_status_t do_in_jni_thread(const base::Closure& task);
+extern bt_status_t btif_gattc_test_command_impl(int command,
+                                                btgatt_test_params_t* params);
+extern const btgatt_callbacks_t* bt_gatt_callbacks;
+
+/*******************************************************************************
+ *  Constants & Macros
+ *******************************************************************************/
+
+#define CLI_CBACK_IN_JNI(P_CBACK, ...)                                         \
+  do {                                                                         \
+    if (bt_gatt_callbacks && bt_gatt_callbacks->client->P_CBACK) {             \
+      BTIF_TRACE_API("HAL bt_gatt_callbacks->client->%s", #P_CBACK);           \
+      do_in_jni_thread(Bind(bt_gatt_callbacks->client->P_CBACK, __VA_ARGS__)); \
+    } else {                                                                   \
+      ASSERTC(0, "Callback is NULL", 0);                                       \
+    }                                                                          \
+  } while (0)
+
+#define CHECK_BTGATT_INIT()                                      \
+  do {                                                           \
+    if (bt_gatt_callbacks == NULL) {                             \
+      LOG_WARN(LOG_TAG, "%s: BTGATT not initialized", __func__); \
+      return BT_STATUS_NOT_READY;                                \
+    } else {                                                     \
+      LOG_VERBOSE(LOG_TAG, "%s", __func__);                      \
+    }                                                            \
+  } while (0)
+
+#define BLE_RESOLVE_ADDR_MSB                                                   \
+  0x40                             /* bit7, bit6 is 01 to be resolvable random \
+                                      */
+#define BLE_RESOLVE_ADDR_MASK 0xc0 /* bit 6, and bit7 */
+#define BTM_BLE_IS_RESOLVE_BDA(x) \
+  (((x)[0] & BLE_RESOLVE_ADDR_MASK) == BLE_RESOLVE_ADDR_MSB)
+
+namespace {
+
+uint8_t rssi_request_client_if;
+
+void btif_gattc_upstreams_evt(uint16_t event, char* p_param) {
+  LOG_VERBOSE(LOG_TAG, "%s: Event %d", __func__, event);
+
+  tBTA_GATTC* p_data = (tBTA_GATTC*)p_param;
+  switch (event) {
+    case BTA_GATTC_REG_EVT: {
+      bt_uuid_t app_uuid;
+      bta_to_btif_uuid(&app_uuid, &p_data->reg_oper.app_uuid);
+      HAL_CBACK(bt_gatt_callbacks, client->register_client_cb,
+                p_data->reg_oper.status, p_data->reg_oper.client_if, &app_uuid);
+      break;
+    }
+
+    case BTA_GATTC_DEREG_EVT:
+      break;
+
+    case BTA_GATTC_EXEC_EVT: {
+      HAL_CBACK(bt_gatt_callbacks, client->execute_write_cb,
+                p_data->exec_cmpl.conn_id, p_data->exec_cmpl.status);
+      break;
+    }
+
+    case BTA_GATTC_SEARCH_CMPL_EVT: {
+      HAL_CBACK(bt_gatt_callbacks, client->search_complete_cb,
+                p_data->search_cmpl.conn_id, p_data->search_cmpl.status);
+      break;
+    }
+
+    case BTA_GATTC_NOTIF_EVT: {
+      btgatt_notify_params_t data;
+
+      bdcpy(data.bda.address, p_data->notify.bda);
+      memcpy(data.value, p_data->notify.value, p_data->notify.len);
+
+      data.handle = p_data->notify.handle;
+      data.is_notify = p_data->notify.is_notify;
+      data.len = p_data->notify.len;
+
+      HAL_CBACK(bt_gatt_callbacks, client->notify_cb, p_data->notify.conn_id,
+                &data);
+
+      if (p_data->notify.is_notify == false)
+        BTA_GATTC_SendIndConfirm(p_data->notify.conn_id, p_data->notify.handle);
+
+      break;
+    }
+
+    case BTA_GATTC_OPEN_EVT: {
+      bt_bdaddr_t bda;
+      bdcpy(bda.address, p_data->open.remote_bda);
+
+      HAL_CBACK(bt_gatt_callbacks, client->open_cb, p_data->open.conn_id,
+                p_data->open.status, p_data->open.client_if, &bda);
+
+      if (GATT_DEF_BLE_MTU_SIZE != p_data->open.mtu && p_data->open.mtu) {
+        HAL_CBACK(bt_gatt_callbacks, client->configure_mtu_cb,
+                  p_data->open.conn_id, p_data->open.status, p_data->open.mtu);
+      }
+
+      if (p_data->open.status == BTA_GATT_OK)
+        btif_gatt_check_encrypted_link(p_data->open.remote_bda,
+                                       p_data->open.transport);
+      break;
+    }
+
+    case BTA_GATTC_CLOSE_EVT: {
+      bt_bdaddr_t bda;
+      bdcpy(bda.address, p_data->close.remote_bda);
+      HAL_CBACK(bt_gatt_callbacks, client->close_cb, p_data->close.conn_id,
+                p_data->status, p_data->close.client_if, &bda);
+      break;
+    }
+
+    case BTA_GATTC_ACL_EVT:
+      LOG_DEBUG(LOG_TAG, "BTA_GATTC_ACL_EVT: status = %d", p_data->status);
+      /* Ignore for now */
+      break;
+
+    case BTA_GATTC_CANCEL_OPEN_EVT:
+      break;
+
+    case BTA_GATTC_CFG_MTU_EVT: {
+      HAL_CBACK(bt_gatt_callbacks, client->configure_mtu_cb,
+                p_data->cfg_mtu.conn_id, p_data->cfg_mtu.status,
+                p_data->cfg_mtu.mtu);
+      break;
+    }
+
+    case BTA_GATTC_CONGEST_EVT:
+      HAL_CBACK(bt_gatt_callbacks, client->congestion_cb,
+                p_data->congest.conn_id, p_data->congest.congested);
+      break;
+
+    default:
+      LOG_ERROR(LOG_TAG, "%s: Unhandled event (%d)!", __func__, event);
+      break;
+  }
+}
+
+void bta_gattc_cback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
+  bt_status_t status =
+      btif_transfer_context(btif_gattc_upstreams_evt, (uint16_t)event,
+                            (char*)p_data, sizeof(tBTA_GATTC), NULL);
+  ASSERTC(status == BT_STATUS_SUCCESS, "Context transfer failed!", status);
+}
+
+
+void btm_read_rssi_cb(tBTM_RSSI_RESULTS* p_result) {
+  if (!p_result) return;
+
+  bt_bdaddr_t* addr = new bt_bdaddr_t;
+  bdcpy(addr->address, p_result->rem_bda);
+  CLI_CBACK_IN_JNI(read_remote_rssi_cb, rssi_request_client_if,
+                   base::Owned(addr), p_result->rssi, p_result->status);
+}
+
+/*******************************************************************************
+ *  Client API Functions
+ *******************************************************************************/
+
+void btif_gattc_register_app_impl(tBT_UUID uuid) {
+  BTA_GATTC_AppRegister(&uuid, bta_gattc_cback);
+}
+
+bt_status_t btif_gattc_register_app(bt_uuid_t* uuid) {
+  CHECK_BTGATT_INIT();
+
+  tBT_UUID bt_uuid;
+  btif_to_bta_uuid(&bt_uuid, uuid);
+  return do_in_jni_thread(Bind(&btif_gattc_register_app_impl, bt_uuid));
+}
+
+void btif_gattc_unregister_app_impl(int client_if) {
+  BTA_GATTC_AppDeregister(client_if);
+}
+
+bt_status_t btif_gattc_unregister_app(int client_if) {
+  CHECK_BTGATT_INIT();
+  return do_in_jni_thread(Bind(&btif_gattc_unregister_app_impl, client_if));
+}
+
+void btif_gattc_open_impl(int client_if, BD_ADDR address, bool is_direct,
+                          int transport_p) {
+  // Ensure device is in inquiry database
+  int addr_type = 0;
+  int device_type = 0;
+  tBTA_GATT_TRANSPORT transport = (tBTA_GATT_TRANSPORT)BTA_GATT_TRANSPORT_LE;
+
+  if (btif_get_address_type(address, &addr_type) &&
+      btif_get_device_type(address, &device_type) &&
+      device_type != BT_DEVICE_TYPE_BREDR) {
+    BTA_DmAddBleDevice(address, addr_type, device_type);
+  }
+
+  // Check for background connections
+  if (!is_direct) {
+    // Check for privacy 1.0 and 1.1 controller and do not start background
+    // connection if RPA offloading is not supported, since it will not
+    // connect after change of random address
+    if (!controller_get_interface()->supports_ble_privacy() &&
+        (addr_type == BLE_ADDR_RANDOM) && BTM_BLE_IS_RESOLVE_BDA(address)) {
+      tBTM_BLE_VSC_CB vnd_capabilities;
+      BTM_BleGetVendorCapabilities(&vnd_capabilities);
+      if (!vnd_capabilities.rpa_offloading) {
+        HAL_CBACK(bt_gatt_callbacks, client->open_cb, 0, BT_STATUS_UNSUPPORTED,
+                  client_if, (bt_bdaddr_t*)&address);
+        return;
+      }
+    }
+    BTA_DmBleSetBgConnType(BTM_BLE_CONN_AUTO, NULL);
+  }
+
+  // Determine transport
+  if (transport_p != GATT_TRANSPORT_AUTO) {
+    transport = transport_p;
+  } else {
+    switch (device_type) {
+      case BT_DEVICE_TYPE_BREDR:
+        transport = BTA_GATT_TRANSPORT_BR_EDR;
+        break;
+
+      case BT_DEVICE_TYPE_BLE:
+        transport = BTA_GATT_TRANSPORT_LE;
+        break;
+
+      case BT_DEVICE_TYPE_DUMO:
+        if (transport == GATT_TRANSPORT_LE)
+          transport = BTA_GATT_TRANSPORT_LE;
+        else
+          transport = BTA_GATT_TRANSPORT_BR_EDR;
+        break;
+    }
+  }
+
+  // Connect!
+  BTIF_TRACE_DEBUG("%s Transport=%d, device type=%d", __func__, transport,
+                   device_type);
+  BTA_GATTC_Open(client_if, address, is_direct, transport);
+}
+
+bt_status_t btif_gattc_open(int client_if, const bt_bdaddr_t* bd_addr,
+                            bool is_direct, int transport) {
+  CHECK_BTGATT_INIT();
+  // Closure will own this value and free it.
+  uint8_t* address = new BD_ADDR;
+  bdcpy(address, bd_addr->address);
+  return do_in_jni_thread(Bind(&btif_gattc_open_impl, client_if,
+                               base::Owned(address), is_direct, transport));
+}
+
+void btif_gattc_close_impl(int client_if, BD_ADDR address, int conn_id) {
+  // Disconnect established connections
+  if (conn_id != 0)
+    BTA_GATTC_Close(conn_id);
+  else
+    BTA_GATTC_CancelOpen(client_if, address, true);
+
+  // Cancel pending background connections (remove from whitelist)
+  BTA_GATTC_CancelOpen(client_if, address, false);
+}
+
+bt_status_t btif_gattc_close(int client_if, const bt_bdaddr_t* bd_addr,
+                             int conn_id) {
+  CHECK_BTGATT_INIT();
+  // Closure will own this value and free it.
+  uint8_t* address = new BD_ADDR;
+  bdcpy(address, bd_addr->address);
+  return do_in_jni_thread(
+      Bind(&btif_gattc_close_impl, client_if, base::Owned(address), conn_id));
+}
+
+bt_status_t btif_gattc_refresh(int client_if, const bt_bdaddr_t* bd_addr) {
+  CHECK_BTGATT_INIT();
+  // Closure will own this value and free it.
+  uint8_t* address = new BD_ADDR;
+  bdcpy(address, bd_addr->address);
+  return do_in_jni_thread(Bind(&BTA_GATTC_Refresh, base::Owned(address)));
+}
+
+bt_status_t btif_gattc_search_service(int conn_id, bt_uuid_t* filter_uuid) {
+  CHECK_BTGATT_INIT();
+
+  if (filter_uuid) {
+    tBT_UUID* uuid = new tBT_UUID;
+    btif_to_bta_uuid(uuid, filter_uuid);
+    return do_in_jni_thread(
+        Bind(&BTA_GATTC_ServiceSearchRequest, conn_id, base::Owned(uuid)));
+  } else {
+    return do_in_jni_thread(
+        Bind(&BTA_GATTC_ServiceSearchRequest, conn_id, nullptr));
+  }
+}
+
+void btif_gattc_get_gatt_db_impl(int conn_id) {
+  btgatt_db_element_t* db = NULL;
+  int count = 0;
+  BTA_GATTC_GetGattDb(conn_id, 0x0000, 0xFFFF, &db, &count);
+
+  HAL_CBACK(bt_gatt_callbacks, client->get_gatt_db_cb, conn_id, db, count);
+  osi_free(db);
+}
+
+bt_status_t btif_gattc_get_gatt_db(int conn_id) {
+  CHECK_BTGATT_INIT();
+  return do_in_jni_thread(Bind(&btif_gattc_get_gatt_db_impl, conn_id));
+}
+
+void read_char_cb(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
+                  uint16_t len, uint8_t* value, void* data) {
+  btgatt_read_params_t* params = new btgatt_read_params_t;
+  params->value_type = 0x00 /* GATTC_READ_VALUE_TYPE_VALUE */;
+  params->status = status;
+  params->handle = handle;
+  params->value.len = len;
+  assert(len <= BTGATT_MAX_ATTR_LEN);
+  if (len > 0) memcpy(params->value.value, value, len);
+
+  CLI_CBACK_IN_JNI(read_characteristic_cb, conn_id, status,
+                   base::Owned(params));
+}
+
+bt_status_t btif_gattc_read_char(int conn_id, uint16_t handle, int auth_req) {
+  CHECK_BTGATT_INIT();
+  return do_in_jni_thread(Bind(&BTA_GATTC_ReadCharacteristic, conn_id, handle,
+                               auth_req, read_char_cb, nullptr));
+}
+
+void read_desc_cb(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
+                  uint16_t len, uint8_t* value, void* data) {
+  btgatt_read_params_t* params = new btgatt_read_params_t;
+  params->value_type = 0x00 /* GATTC_READ_VALUE_TYPE_VALUE */;
+  params->status = status;
+  params->handle = handle;
+  params->value.len = len;
+  assert(len <= BTGATT_MAX_ATTR_LEN);
+  if (len > 0) memcpy(params->value.value, value, len);
+
+  CLI_CBACK_IN_JNI(read_descriptor_cb, conn_id, status, base::Owned(params));
+}
+
+bt_status_t btif_gattc_read_char_descr(int conn_id, uint16_t handle,
+                                       int auth_req) {
+  CHECK_BTGATT_INIT();
+  return do_in_jni_thread(Bind(&BTA_GATTC_ReadCharDescr, conn_id, handle,
+                               auth_req, read_desc_cb, nullptr));
+}
+
+void write_char_cb(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
+                   void* data) {
+  CLI_CBACK_IN_JNI(write_characteristic_cb, conn_id, status, handle);
+}
+
+bt_status_t btif_gattc_write_char(int conn_id, uint16_t handle, int write_type,
+                                  int auth_req, vector<uint8_t> value) {
+  CHECK_BTGATT_INIT();
+
+  if (value.size() > BTGATT_MAX_ATTR_LEN) value.resize(BTGATT_MAX_ATTR_LEN);
+
+  return do_in_jni_thread(Bind(&BTA_GATTC_WriteCharValue, conn_id, handle,
+                               write_type, std::move(value), auth_req,
+                               write_char_cb, nullptr));
+}
+
+void write_descr_cb(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
+                    void* data) {
+  CLI_CBACK_IN_JNI(write_descriptor_cb, conn_id, status, handle);
+}
+
+bt_status_t btif_gattc_write_char_descr(int conn_id, uint16_t handle,
+                                        int auth_req, vector<uint8_t> value) {
+  CHECK_BTGATT_INIT();
+
+  if (value.size() > BTGATT_MAX_ATTR_LEN) value.resize(BTGATT_MAX_ATTR_LEN);
+
+  return do_in_jni_thread(Bind(&BTA_GATTC_WriteCharDescr, conn_id, handle,
+                               std::move(value), auth_req, write_descr_cb,
+                               nullptr));
+}
+
+bt_status_t btif_gattc_execute_write(int conn_id, int execute) {
+  CHECK_BTGATT_INIT();
+  return do_in_jni_thread(
+      Bind(&BTA_GATTC_ExecuteWrite, conn_id, (uint8_t)execute));
+}
+
+void btif_gattc_reg_for_notification_impl(tBTA_GATTC_IF client_if,
+                                          const BD_ADDR bda, uint16_t handle) {
+  tBTA_GATT_STATUS status = BTA_GATTC_RegisterForNotifications(
+      client_if, const_cast<uint8_t*>(bda), handle);
+
+  // TODO(jpawlowski): conn_id is currently unused
+  HAL_CBACK(bt_gatt_callbacks, client->register_for_notification_cb,
+            /* conn_id */ 0, 1, status, handle);
+}
+
+bt_status_t btif_gattc_reg_for_notification(int client_if,
+                                            const bt_bdaddr_t* bd_addr,
+                                            uint16_t handle) {
+  CHECK_BTGATT_INIT();
+
+  uint8_t* address = new BD_ADDR;
+  bdcpy(address, bd_addr->address);
+  return do_in_jni_thread(
+      Bind(base::IgnoreResult(&btif_gattc_reg_for_notification_impl), client_if,
+           base::Owned(address), handle));
+}
+
+void btif_gattc_dereg_for_notification_impl(tBTA_GATTC_IF client_if,
+                                            const BD_ADDR bda,
+                                            uint16_t handle) {
+  tBTA_GATT_STATUS status = BTA_GATTC_DeregisterForNotifications(
+      client_if, const_cast<uint8_t*>(bda), handle);
+
+  // TODO(jpawlowski): conn_id is currently unused
+  HAL_CBACK(bt_gatt_callbacks, client->register_for_notification_cb,
+            /* conn_id */ 0, 0, status, handle);
+}
+
+bt_status_t btif_gattc_dereg_for_notification(int client_if,
+                                              const bt_bdaddr_t* bd_addr,
+                                              uint16_t handle) {
+  CHECK_BTGATT_INIT();
+
+  uint8_t* address = new BD_ADDR;
+  bdcpy(address, bd_addr->address);
+  return do_in_jni_thread(
+      Bind(base::IgnoreResult(&btif_gattc_dereg_for_notification_impl),
+           client_if, base::Owned(address), handle));
+}
+
+bt_status_t btif_gattc_read_remote_rssi(int client_if,
+                                        const bt_bdaddr_t* bd_addr) {
+  CHECK_BTGATT_INIT();
+  rssi_request_client_if = client_if;
+  // Closure will own this value and free it.
+  uint8_t* address = new BD_ADDR;
+  bdcpy(address, bd_addr->address);
+  return do_in_jni_thread(Bind(base::IgnoreResult(&BTM_ReadRSSI),
+                               base::Owned(address),
+                               (tBTM_CMPL_CB*)btm_read_rssi_cb));
+}
+
+bt_status_t btif_gattc_configure_mtu(int conn_id, int mtu) {
+  CHECK_BTGATT_INIT();
+  return do_in_jni_thread(
+      Bind(base::IgnoreResult(&BTA_GATTC_ConfigureMTU), conn_id, mtu));
+}
+
+void btif_gattc_conn_parameter_update_impl(bt_bdaddr_t addr, int min_interval,
+                                           int max_interval, int latency,
+                                           int timeout) {
+  if (BTA_DmGetConnectionState(addr.address))
+    BTA_DmBleUpdateConnectionParams(addr.address, min_interval, max_interval,
+                                    latency, timeout);
+  else
+    BTA_DmSetBlePrefConnParams(addr.address, min_interval, max_interval,
+                               latency, timeout);
+}
+
+bt_status_t btif_gattc_conn_parameter_update(const bt_bdaddr_t* bd_addr,
+                                             int min_interval, int max_interval,
+                                             int latency, int timeout) {
+  CHECK_BTGATT_INIT();
+  return do_in_jni_thread(
+      Bind(base::IgnoreResult(&btif_gattc_conn_parameter_update_impl), *bd_addr,
+           min_interval, max_interval, latency, timeout));
+}
+
+int btif_gattc_get_device_type(const bt_bdaddr_t* bd_addr) {
+  int device_type = 0;
+  char bd_addr_str[18] = {0};
+
+  bdaddr_to_string(bd_addr, bd_addr_str, sizeof(bd_addr_str));
+  if (btif_config_get_int(bd_addr_str, "DevType", &device_type))
+    return device_type;
+  return 0;
+}
+
+bt_status_t btif_gattc_test_command(int command, btgatt_test_params_t* params) {
+  return btif_gattc_test_command_impl(command, params);
+}
+
+}  // namespace
+
+const btgatt_client_interface_t btgattClientInterface = {
+    btif_gattc_register_app,
+    btif_gattc_unregister_app,
+    btif_gattc_open,
+    btif_gattc_close,
+    btif_gattc_refresh,
+    btif_gattc_search_service,
+    btif_gattc_read_char,
+    btif_gattc_write_char,
+    btif_gattc_read_char_descr,
+    btif_gattc_write_char_descr,
+    btif_gattc_execute_write,
+    btif_gattc_reg_for_notification,
+    btif_gattc_dereg_for_notification,
+    btif_gattc_read_remote_rssi,
+    btif_gattc_get_device_type,
+    btif_gattc_configure_mtu,
+    btif_gattc_conn_parameter_update,
+    btif_gattc_test_command,
+    btif_gattc_get_gatt_db};
+
+#endif
diff --git a/bt/btif/src/btif_gatt_server.cc b/bt/btif/src/btif_gatt_server.cc
new file mode 100644
index 0000000..73a81b4
--- /dev/null
+++ b/bt/btif/src/btif_gatt_server.cc
@@ -0,0 +1,427 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ *  Filename:      btif_gatt_server.c
+ *
+ *  Description:   GATT server implementation
+ *
+ ***********************************************************************************/
+
+#define LOG_TAG "bt_btif_gatt"
+
+#include <base/bind.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
+
+#include "btif_common.h"
+#include "btif_util.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_gatt_api.h"
+#include "btif_config.h"
+#include "btif_dm.h"
+#include "btif_gatt.h"
+#include "btif_gatt_util.h"
+#include "btif_storage.h"
+#include "osi/include/log.h"
+
+using base::Bind;
+using base::Owned;
+using std::vector;
+
+extern bt_status_t do_in_jni_thread(const base::Closure& task);
+
+/************************************************************************************
+ *  Constants & Macros
+ ***********************************************************************************/
+
+#define CHECK_BTGATT_INIT()                                      \
+  do {                                                           \
+    if (bt_gatt_callbacks == NULL) {                             \
+      LOG_WARN(LOG_TAG, "%s: BTGATT not initialized", __func__); \
+      return BT_STATUS_NOT_READY;                                \
+    } else {                                                     \
+      LOG_VERBOSE(LOG_TAG, "%s", __func__);                      \
+    }                                                            \
+  } while (0)
+
+/************************************************************************************
+ *  Static variables
+ ***********************************************************************************/
+
+extern const btgatt_callbacks_t* bt_gatt_callbacks;
+
+/************************************************************************************
+ *  Static functions
+ ***********************************************************************************/
+
+static void btapp_gatts_copy_req_data(uint16_t event, char* p_dest,
+                                      char* p_src) {
+  tBTA_GATTS* p_dest_data = (tBTA_GATTS*)p_dest;
+  tBTA_GATTS* p_src_data = (tBTA_GATTS*)p_src;
+
+  if (!p_src_data || !p_dest_data) return;
+
+  // Copy basic structure first
+  maybe_non_aligned_memcpy(p_dest_data, p_src_data, sizeof(*p_src_data));
+
+  // Allocate buffer for request data if necessary
+  switch (event) {
+    case BTA_GATTS_READ_CHARACTERISTIC_EVT:
+    case BTA_GATTS_READ_DESCRIPTOR_EVT:
+    case BTA_GATTS_WRITE_CHARACTERISTIC_EVT:
+    case BTA_GATTS_WRITE_DESCRIPTOR_EVT:
+    case BTA_GATTS_EXEC_WRITE_EVT:
+    case BTA_GATTS_MTU_EVT:
+      p_dest_data->req_data.p_data =
+          (tBTA_GATTS_REQ_DATA*)osi_malloc(sizeof(tBTA_GATTS_REQ_DATA));
+      memcpy(p_dest_data->req_data.p_data, p_src_data->req_data.p_data,
+             sizeof(tBTA_GATTS_REQ_DATA));
+      break;
+
+    default:
+      break;
+  }
+}
+
+static void btapp_gatts_free_req_data(uint16_t event, tBTA_GATTS* p_data) {
+  switch (event) {
+    case BTA_GATTS_READ_CHARACTERISTIC_EVT:
+    case BTA_GATTS_READ_DESCRIPTOR_EVT:
+    case BTA_GATTS_WRITE_CHARACTERISTIC_EVT:
+    case BTA_GATTS_WRITE_DESCRIPTOR_EVT:
+    case BTA_GATTS_EXEC_WRITE_EVT:
+    case BTA_GATTS_MTU_EVT:
+      if (p_data != NULL) osi_free_and_reset((void**)&p_data->req_data.p_data);
+      break;
+
+    default:
+      break;
+  }
+}
+
+static void btapp_gatts_handle_cback(uint16_t event, char* p_param) {
+  LOG_VERBOSE(LOG_TAG, "%s: Event %d", __func__, event);
+
+  tBTA_GATTS* p_data = (tBTA_GATTS*)p_param;
+  switch (event) {
+    case BTA_GATTS_REG_EVT: {
+      bt_uuid_t app_uuid;
+      bta_to_btif_uuid(&app_uuid, &p_data->reg_oper.uuid);
+      HAL_CBACK(bt_gatt_callbacks, server->register_server_cb,
+                p_data->reg_oper.status, p_data->reg_oper.server_if, &app_uuid);
+      break;
+    }
+
+    case BTA_GATTS_DEREG_EVT:
+      break;
+
+    case BTA_GATTS_CONNECT_EVT: {
+      bt_bdaddr_t bda;
+      bdcpy(bda.address, p_data->conn.remote_bda);
+
+      btif_gatt_check_encrypted_link(p_data->conn.remote_bda,
+                                     p_data->conn.transport);
+
+      HAL_CBACK(bt_gatt_callbacks, server->connection_cb, p_data->conn.conn_id,
+                p_data->conn.server_if, true, &bda);
+      break;
+    }
+
+    case BTA_GATTS_DISCONNECT_EVT: {
+      bt_bdaddr_t bda;
+      bdcpy(bda.address, p_data->conn.remote_bda);
+
+      HAL_CBACK(bt_gatt_callbacks, server->connection_cb, p_data->conn.conn_id,
+                p_data->conn.server_if, false, &bda);
+      break;
+    }
+
+    case BTA_GATTS_STOP_EVT:
+      HAL_CBACK(bt_gatt_callbacks, server->service_stopped_cb,
+                p_data->srvc_oper.status, p_data->srvc_oper.server_if,
+                p_data->srvc_oper.service_id);
+      break;
+
+    case BTA_GATTS_DELELTE_EVT:
+      HAL_CBACK(bt_gatt_callbacks, server->service_deleted_cb,
+                p_data->srvc_oper.status, p_data->srvc_oper.server_if,
+                p_data->srvc_oper.service_id);
+      break;
+
+    case BTA_GATTS_READ_CHARACTERISTIC_EVT: {
+      bt_bdaddr_t bda;
+      bdcpy(bda.address, p_data->req_data.remote_bda);
+
+      HAL_CBACK(bt_gatt_callbacks, server->request_read_characteristic_cb,
+                p_data->req_data.conn_id, p_data->req_data.trans_id, &bda,
+                p_data->req_data.p_data->read_req.handle,
+                p_data->req_data.p_data->read_req.offset,
+                p_data->req_data.p_data->read_req.is_long);
+      break;
+    }
+
+    case BTA_GATTS_READ_DESCRIPTOR_EVT: {
+      bt_bdaddr_t bda;
+      bdcpy(bda.address, p_data->req_data.remote_bda);
+
+      HAL_CBACK(bt_gatt_callbacks, server->request_read_descriptor_cb,
+                p_data->req_data.conn_id, p_data->req_data.trans_id, &bda,
+                p_data->req_data.p_data->read_req.handle,
+                p_data->req_data.p_data->read_req.offset,
+                p_data->req_data.p_data->read_req.is_long);
+      break;
+    }
+
+    case BTA_GATTS_WRITE_CHARACTERISTIC_EVT: {
+      bt_bdaddr_t bda;
+      bdcpy(bda.address, p_data->req_data.remote_bda);
+      const auto& req = p_data->req_data.p_data->write_req;
+      vector<uint8_t> value(req.value, req.value + req.len);
+      HAL_CBACK(bt_gatt_callbacks, server->request_write_characteristic_cb,
+                p_data->req_data.conn_id, p_data->req_data.trans_id, &bda,
+                req.handle, req.offset, req.need_rsp, req.is_prep, value);
+      break;
+    }
+
+    case BTA_GATTS_WRITE_DESCRIPTOR_EVT: {
+      bt_bdaddr_t bda;
+      bdcpy(bda.address, p_data->req_data.remote_bda);
+      const auto& req = p_data->req_data.p_data->write_req;
+      vector<uint8_t> value(req.value, req.value + req.len);
+      HAL_CBACK(bt_gatt_callbacks, server->request_write_descriptor_cb,
+                p_data->req_data.conn_id, p_data->req_data.trans_id, &bda,
+                req.handle, req.offset, req.need_rsp, req.is_prep, value);
+      break;
+    }
+
+    case BTA_GATTS_EXEC_WRITE_EVT: {
+      bt_bdaddr_t bda;
+      bdcpy(bda.address, p_data->req_data.remote_bda);
+
+      HAL_CBACK(bt_gatt_callbacks, server->request_exec_write_cb,
+                p_data->req_data.conn_id, p_data->req_data.trans_id, &bda,
+                p_data->req_data.p_data->exec_write);
+      break;
+    }
+
+    case BTA_GATTS_CONF_EVT:
+      HAL_CBACK(bt_gatt_callbacks, server->indication_sent_cb,
+                p_data->req_data.conn_id, p_data->req_data.status);
+      break;
+
+    case BTA_GATTS_CONGEST_EVT:
+      HAL_CBACK(bt_gatt_callbacks, server->congestion_cb,
+                p_data->congest.conn_id, p_data->congest.congested);
+      break;
+
+    case BTA_GATTS_MTU_EVT:
+      HAL_CBACK(bt_gatt_callbacks, server->mtu_changed_cb,
+                p_data->req_data.conn_id, p_data->req_data.p_data->mtu);
+      break;
+
+    case BTA_GATTS_OPEN_EVT:
+    case BTA_GATTS_CANCEL_OPEN_EVT:
+    case BTA_GATTS_CLOSE_EVT:
+      LOG_DEBUG(LOG_TAG, "%s: Empty event (%d)!", __func__, event);
+      break;
+
+    default:
+      LOG_ERROR(LOG_TAG, "%s: Unhandled event (%d)!", __func__, event);
+      break;
+  }
+
+  btapp_gatts_free_req_data(event, p_data);
+}
+
+static void btapp_gatts_cback(tBTA_GATTS_EVT event, tBTA_GATTS* p_data) {
+  bt_status_t status;
+  status = btif_transfer_context(btapp_gatts_handle_cback, (uint16_t)event,
+                                 (char*)p_data, sizeof(tBTA_GATTS),
+                                 btapp_gatts_copy_req_data);
+  ASSERTC(status == BT_STATUS_SUCCESS, "Context transfer failed!", status);
+}
+
+/************************************************************************************
+ *  Server API Functions
+ ***********************************************************************************/
+static bt_status_t btif_gatts_register_app(bt_uuid_t* bt_uuid) {
+  CHECK_BTGATT_INIT();
+  tBT_UUID* uuid = new tBT_UUID;
+  btif_to_bta_uuid(uuid, bt_uuid);
+
+  return do_in_jni_thread(
+      Bind(&BTA_GATTS_AppRegister, base::Owned(uuid), &btapp_gatts_cback));
+}
+
+static bt_status_t btif_gatts_unregister_app(int server_if) {
+  CHECK_BTGATT_INIT();
+  return do_in_jni_thread(Bind(&BTA_GATTS_AppDeregister, server_if));
+}
+
+static void btif_gatts_open_impl(int server_if, BD_ADDR address, bool is_direct,
+                                 int transport_param) {
+  // Ensure device is in inquiry database
+  int addr_type = 0;
+  int device_type = 0;
+  tBTA_GATT_TRANSPORT transport = BTA_GATT_TRANSPORT_LE;
+
+  if (btif_get_address_type(address, &addr_type) &&
+      btif_get_device_type(address, &device_type) &&
+      device_type != BT_DEVICE_TYPE_BREDR) {
+    BTA_DmAddBleDevice(address, addr_type, device_type);
+  }
+
+  // Mark background connections
+  if (!is_direct) BTA_DmBleSetBgConnType(BTM_BLE_CONN_AUTO, NULL);
+
+  // Determine transport
+  if (transport_param != GATT_TRANSPORT_AUTO) {
+    transport = transport_param;
+  } else {
+    switch (device_type) {
+      case BT_DEVICE_TYPE_BREDR:
+        transport = BTA_GATT_TRANSPORT_BR_EDR;
+        break;
+
+      case BT_DEVICE_TYPE_BLE:
+        transport = BTA_GATT_TRANSPORT_LE;
+        break;
+
+      case BT_DEVICE_TYPE_DUMO:
+        if (transport_param == GATT_TRANSPORT_LE)
+          transport = BTA_GATT_TRANSPORT_LE;
+        else
+          transport = BTA_GATT_TRANSPORT_BR_EDR;
+        break;
+
+      default:
+        BTIF_TRACE_ERROR("%s: Invalid device type %d", __func__, device_type);
+        return;
+    }
+  }
+
+  // Connect!
+  BTA_GATTS_Open(server_if, address, is_direct, transport);
+}
+
+static bt_status_t btif_gatts_open(int server_if, const bt_bdaddr_t* bd_addr,
+                                   bool is_direct, int transport) {
+  CHECK_BTGATT_INIT();
+  uint8_t* address = new BD_ADDR;
+  bdcpy(address, bd_addr->address);
+
+  return do_in_jni_thread(Bind(&btif_gatts_open_impl, server_if,
+                               base::Owned(address), is_direct, transport));
+}
+
+static void btif_gatts_close_impl(int server_if, BD_ADDR address, int conn_id) {
+  // Cancel pending foreground/background connections
+  BTA_GATTS_CancelOpen(server_if, address, true);
+  BTA_GATTS_CancelOpen(server_if, address, false);
+
+  // Close active connection
+  if (conn_id != 0) BTA_GATTS_Close(conn_id);
+}
+
+static bt_status_t btif_gatts_close(int server_if, const bt_bdaddr_t* bd_addr,
+                                    int conn_id) {
+  CHECK_BTGATT_INIT();
+  uint8_t* address = new BD_ADDR;
+  bdcpy(address, bd_addr->address);
+
+  return do_in_jni_thread(
+      Bind(&btif_gatts_close_impl, server_if, base::Owned(address), conn_id));
+}
+
+static void add_service_impl(int server_if,
+                             vector<btgatt_db_element_t> service) {
+  int status = BTA_GATTS_AddService(server_if, service);
+  HAL_CBACK(bt_gatt_callbacks, server->service_added_cb, status, server_if,
+            std::move(service));
+}
+
+static bt_status_t btif_gatts_add_service(int server_if,
+                                          vector<btgatt_db_element_t> service) {
+  CHECK_BTGATT_INIT();
+  return do_in_jni_thread(
+      Bind(&add_service_impl, server_if, std::move(service)));
+}
+
+static bt_status_t btif_gatts_stop_service(int server_if, int service_handle) {
+  CHECK_BTGATT_INIT();
+  return do_in_jni_thread(Bind(&BTA_GATTS_StopService, service_handle));
+}
+
+static bt_status_t btif_gatts_delete_service(int server_if,
+                                             int service_handle) {
+  CHECK_BTGATT_INIT();
+  return do_in_jni_thread(Bind(&BTA_GATTS_DeleteService, service_handle));
+}
+
+static bt_status_t btif_gatts_send_indication(int server_if,
+                                              int attribute_handle, int conn_id,
+                                              int confirm,
+                                              vector<uint8_t> value) {
+  CHECK_BTGATT_INIT();
+
+  if (value.size() > BTGATT_MAX_ATTR_LEN) value.resize(BTGATT_MAX_ATTR_LEN);
+
+  return do_in_jni_thread(Bind(&BTA_GATTS_HandleValueIndication, conn_id,
+                               attribute_handle, std::move(value), confirm));
+  // TODO: Might need to send an ACK if handle value indication is
+  //       invoked without need for confirmation.
+}
+
+static void btif_gatts_send_response_impl(int conn_id, int trans_id, int status,
+                                          btgatt_response_t response) {
+  tBTA_GATTS_RSP rsp_struct;
+  btif_to_bta_response(&rsp_struct, &response);
+
+  BTA_GATTS_SendRsp(conn_id, trans_id, status, &rsp_struct);
+
+  HAL_CBACK(bt_gatt_callbacks, server->response_confirmation_cb, 0,
+            rsp_struct.attr_value.handle);
+}
+
+static bt_status_t btif_gatts_send_response(int conn_id, int trans_id,
+                                            int status,
+                                            btgatt_response_t* response) {
+  CHECK_BTGATT_INIT();
+  return do_in_jni_thread(Bind(&btif_gatts_send_response_impl, conn_id,
+                               trans_id, status, *response));
+}
+
+const btgatt_server_interface_t btgattServerInterface = {
+    btif_gatts_register_app,   btif_gatts_unregister_app,
+    btif_gatts_open,           btif_gatts_close,
+    btif_gatts_add_service,    btif_gatts_stop_service,
+    btif_gatts_delete_service, btif_gatts_send_indication,
+    btif_gatts_send_response};
+
+#endif
diff --git a/bt/btif/src/btif_gatt_test.cc b/bt/btif/src/btif_gatt_test.cc
new file mode 100644
index 0000000..39f2952
--- /dev/null
+++ b/bt/btif/src/btif_gatt_test.cc
@@ -0,0 +1,293 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_gatt"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
+
+#include "btif_common.h"
+#include "btif_util.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+#include "bta_gatt_api.h"
+#include "bte_appl.h"
+#include "btif_dm.h"
+#include "btif_gatt.h"
+#include "btif_gatt_util.h"
+#include "btif_storage.h"
+#include "gatt_api.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+/*******************************************************************************
+ * Typedefs & Macros
+ *******************************************************************************/
+
+typedef struct {
+  tGATT_IF gatt_if;
+  uint16_t conn_id;
+} btif_test_cb_t;
+
+/*******************************************************************************
+ * Static variables
+ *******************************************************************************/
+
+static const char* disc_name[GATT_DISC_MAX] = {"Unknown",
+                                               "GATT_DISC_SRVC_ALL",
+                                               "GATT_DISC_SRVC_BY_UUID",
+                                               "GATT_DISC_INC_SRVC",
+                                               "GATT_DISC_CHAR",
+                                               "GATT_DISC_CHAR_DSCPT"};
+
+static btif_test_cb_t test_cb;
+
+/*******************************************************************************
+ * Callback functions
+ *******************************************************************************/
+
+static char* format_uuid(tBT_UUID bt_uuid, char* str_buf, size_t buf_size) {
+  if (bt_uuid.len == LEN_UUID_16) {
+    snprintf(str_buf, buf_size, "0x%04x", bt_uuid.uu.uuid16);
+  } else if (bt_uuid.len == LEN_UUID_128) {
+    int x = snprintf(str_buf, buf_size, "%02x%02x%02x%02x-%02x%02x-%02x%02x",
+                     bt_uuid.uu.uuid128[15], bt_uuid.uu.uuid128[14],
+                     bt_uuid.uu.uuid128[13], bt_uuid.uu.uuid128[12],
+                     bt_uuid.uu.uuid128[11], bt_uuid.uu.uuid128[10],
+                     bt_uuid.uu.uuid128[9], bt_uuid.uu.uuid128[8]);
+    snprintf(&str_buf[x], buf_size - x, "%02x%02x-%02x%02x%02x%02x%02x%02x",
+             bt_uuid.uu.uuid128[7], bt_uuid.uu.uuid128[6],
+             bt_uuid.uu.uuid128[5], bt_uuid.uu.uuid128[4],
+             bt_uuid.uu.uuid128[3], bt_uuid.uu.uuid128[2],
+             bt_uuid.uu.uuid128[1], bt_uuid.uu.uuid128[0]);
+  } else {
+    snprintf(str_buf, buf_size, "Unknown (len=%d)", bt_uuid.len);
+  }
+
+  return str_buf;
+}
+
+static void btif_test_connect_cback(UNUSED_ATTR tGATT_IF gatt_if, UNUSED_ATTR BD_ADDR bda,
+                                    uint16_t conn_id, bool connected,
+                                    UNUSED_ATTR tGATT_DISCONN_REASON reason,
+                                    UNUSED_ATTR tBT_TRANSPORT transport) {
+  LOG_DEBUG(LOG_TAG, "%s: conn_id=%d, connected=%d", __func__, conn_id,
+            connected);
+  test_cb.conn_id = connected ? conn_id : 0;
+}
+
+static void btif_test_command_complete_cback(uint16_t conn_id, tGATTC_OPTYPE op,
+                                             tGATT_STATUS status,
+                                             tGATT_CL_COMPLETE* p_data) {
+  LOG_DEBUG(LOG_TAG, "%s: op_code=0x%02x, conn_id=0x%x. status=0x%x", __func__,
+            op, conn_id, status);
+
+  switch (op) {
+    case GATTC_OPTYPE_READ:
+    case GATTC_OPTYPE_WRITE:
+    case GATTC_OPTYPE_CONFIG:
+    case GATTC_OPTYPE_EXE_WRITE:
+    case GATTC_OPTYPE_NOTIFICATION:
+      break;
+
+    case GATTC_OPTYPE_INDICATION:
+      GATTC_SendHandleValueConfirm(conn_id, p_data->handle);
+      break;
+
+    default:
+      LOG_DEBUG(LOG_TAG, "%s: Unknown op_code (0x%02x)", __func__, op);
+      break;
+  }
+}
+
+static void btif_test_discovery_result_cback(UNUSED_ATTR uint16_t conn_id,
+                                             tGATT_DISC_TYPE disc_type,
+                                             tGATT_DISC_RES* p_data) {
+  char str_buf[50];
+
+  LOG_DEBUG(LOG_TAG, "------ GATT Discovery result %-22s -------",
+            disc_name[disc_type]);
+  LOG_DEBUG(LOG_TAG, "      Attribute handle: 0x%04x (%d)", p_data->handle,
+            p_data->handle);
+
+  if (disc_type != GATT_DISC_CHAR_DSCPT) {
+    LOG_DEBUG(LOG_TAG, "        Attribute type: %s",
+              format_uuid(p_data->type, str_buf, sizeof(str_buf)));
+  }
+
+  switch (disc_type) {
+    case GATT_DISC_SRVC_ALL:
+      LOG_DEBUG(LOG_TAG, "          Handle range: 0x%04x ~ 0x%04x (%d ~ %d)",
+                p_data->handle, p_data->value.group_value.e_handle,
+                p_data->handle, p_data->value.group_value.e_handle);
+      LOG_DEBUG(LOG_TAG, "          Service UUID: %s",
+                format_uuid(p_data->value.group_value.service_type, str_buf,
+                            sizeof(str_buf)));
+      break;
+
+    case GATT_DISC_SRVC_BY_UUID:
+      LOG_DEBUG(LOG_TAG, "          Handle range: 0x%04x ~ 0x%04x (%d ~ %d)",
+                p_data->handle, p_data->value.handle, p_data->handle,
+                p_data->value.handle);
+      break;
+
+    case GATT_DISC_INC_SRVC:
+      LOG_DEBUG(LOG_TAG, "          Handle range: 0x%04x ~ 0x%04x (%d ~ %d)",
+                p_data->value.incl_service.s_handle,
+                p_data->value.incl_service.e_handle,
+                p_data->value.incl_service.s_handle,
+                p_data->value.incl_service.e_handle);
+      LOG_DEBUG(LOG_TAG, "          Service UUID: %s",
+                format_uuid(p_data->value.incl_service.service_type, str_buf,
+                            sizeof(str_buf)));
+      break;
+
+    case GATT_DISC_CHAR:
+      LOG_DEBUG(LOG_TAG, "            Properties: 0x%02x",
+                p_data->value.dclr_value.char_prop);
+      LOG_DEBUG(LOG_TAG, "   Characteristic UUID: %s",
+                format_uuid(p_data->value.dclr_value.char_uuid, str_buf,
+                            sizeof(str_buf)));
+      break;
+
+    case GATT_DISC_CHAR_DSCPT:
+      LOG_DEBUG(LOG_TAG, "       Descriptor UUID: %s",
+                format_uuid(p_data->type, str_buf, sizeof(str_buf)));
+      break;
+  }
+
+  LOG_DEBUG(LOG_TAG,
+            "-----------------------------------------------------------");
+}
+
+static void btif_test_discovery_complete_cback(UNUSED_ATTR uint16_t conn_id,
+                                               UNUSED_ATTR tGATT_DISC_TYPE disc_type,
+                                               tGATT_STATUS status) {
+  LOG_DEBUG(LOG_TAG, "%s: status=%d", __func__, status);
+}
+
+static tGATT_CBACK btif_test_callbacks = {btif_test_connect_cback,
+                                          btif_test_command_complete_cback,
+                                          btif_test_discovery_result_cback,
+                                          btif_test_discovery_complete_cback,
+                                          NULL,
+                                          NULL,
+                                          NULL};
+
+/*******************************************************************************
+ * Implementation
+ *******************************************************************************/
+
+bt_status_t btif_gattc_test_command_impl(int command,
+                                         btgatt_test_params_t* params) {
+  switch (command) {
+    case 0x01: /* Enable */
+    {
+      LOG_DEBUG(LOG_TAG, "%s: ENABLE - enable=%d", __func__, params->u1);
+      if (params->u1) {
+        tBT_UUID app_uuid = {LEN_UUID_128, {0xAE}};
+        test_cb.gatt_if = GATT_Register(&app_uuid, &btif_test_callbacks);
+        GATT_StartIf(test_cb.gatt_if);
+      } else {
+        GATT_Deregister(test_cb.gatt_if);
+        test_cb.gatt_if = 0;
+      }
+      break;
+    }
+
+    case 0x02: /* Connect */
+    {
+      LOG_DEBUG(LOG_TAG,
+                "%s: CONNECT - device=%02x:%02x:%02x:%02x:%02x:%02x "
+                "(dev_type=%d, addr_type=%d)",
+                __func__, params->bda1->address[0], params->bda1->address[1],
+                params->bda1->address[2], params->bda1->address[3],
+                params->bda1->address[4], params->bda1->address[5], params->u1,
+                params->u2);
+
+      if (params->u1 == BT_DEVICE_TYPE_BLE)
+        BTM_SecAddBleDevice(params->bda1->address, NULL, BT_DEVICE_TYPE_BLE,
+                            params->u2);
+
+      if (!GATT_Connect(test_cb.gatt_if, params->bda1->address, true,
+                        BT_TRANSPORT_LE, false)) {
+        LOG_ERROR(LOG_TAG, "%s: GATT_Connect failed!", __func__);
+      }
+      break;
+    }
+
+    case 0x03: /* Disconnect */
+    {
+      LOG_DEBUG(LOG_TAG, "%s: DISCONNECT - conn_id=%d", __func__,
+                test_cb.conn_id);
+      GATT_Disconnect(test_cb.conn_id);
+      break;
+    }
+
+    case 0x04: /* Discover */
+    {
+      char buf[50] = {0};
+      tGATT_DISC_PARAM param;
+      memset(&param, 0, sizeof(tGATT_DISC_PARAM));
+
+      if (params->u1 >= GATT_DISC_MAX) {
+        LOG_ERROR(LOG_TAG, "%s: DISCOVER - Invalid type (%d)!", __func__,
+                  params->u1);
+        return (bt_status_t)0;
+      }
+
+      param.s_handle = params->u2;
+      param.e_handle = params->u3;
+      btif_to_bta_uuid(&param.service, params->uuid1);
+
+      LOG_DEBUG(LOG_TAG,
+                "%s: DISCOVER (%s), conn_id=%d, uuid=%s, handles=0x%04x-0x%04x",
+                __func__, disc_name[params->u1], test_cb.conn_id,
+                format_uuid(param.service, buf, sizeof(buf)), params->u2,
+                params->u3);
+      GATTC_Discover(test_cb.conn_id, params->u1, &param);
+      break;
+    }
+
+    case 0xF0: /* Pairing configuration */
+      LOG_DEBUG(LOG_TAG,
+                "%s: Setting pairing config auth=%d, iocaps=%d, keys=%d/%d/%d",
+                __func__, params->u1, params->u2, params->u3, params->u4,
+                params->u5);
+
+      bte_appl_cfg.ble_auth_req = params->u1;
+      bte_appl_cfg.ble_io_cap = params->u2;
+      bte_appl_cfg.ble_init_key = params->u3;
+      bte_appl_cfg.ble_resp_key = params->u4;
+      bte_appl_cfg.ble_max_key_size = params->u5;
+      break;
+
+    default:
+      LOG_ERROR(LOG_TAG, "%s: UNKNOWN TEST COMMAND 0x%02x", __func__, command);
+      break;
+  }
+  return (bt_status_t)0;
+}
+
+#endif
diff --git a/bt/btif/src/btif_gatt_util.cc b/bt/btif/src/btif_gatt_util.cc
new file mode 100644
index 0000000..f00b10d
--- /dev/null
+++ b/bt/btif/src/btif_gatt_util.cc
@@ -0,0 +1,275 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_gatt"
+
+#include "btif_gatt_util.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
+
+#include "bdaddr.h"
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_gatt_api.h"
+#include "bta_jv_api.h"
+#include "btif_common.h"
+#include "btif_config.h"
+#include "btif_dm.h"
+#include "btif_gatt.h"
+#include "btif_storage.h"
+#include "btif_util.h"
+#include "osi/include/osi.h"
+
+#if (BTA_GATT_INCLUDED == TRUE)
+
+#define GATTC_READ_VALUE_TYPE_VALUE 0x0000 /* Attribute value itself */
+#define GATTC_READ_VALUE_TYPE_AGG_FORMAT \
+  0x2905 /* Characteristic Aggregate Format*/
+
+static unsigned char BASE_UUID[16] = {0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00,
+                                      0x00, 0x80, 0x00, 0x10, 0x00, 0x00,
+                                      0x00, 0x00, 0x00, 0x00};
+
+int uuidType(const unsigned char* p_uuid) {
+  int i = 0;
+  int match = 0;
+  int all_zero = 1;
+
+  for (i = 0; i != 16; ++i) {
+    if (i == 12 || i == 13) continue;
+
+    if (p_uuid[i] == BASE_UUID[i]) ++match;
+
+    if (p_uuid[i] != 0) all_zero = 0;
+  }
+  if (all_zero) return 0;
+  if (match == 12) return LEN_UUID_32;
+  if (match == 14) return LEN_UUID_16;
+  return LEN_UUID_128;
+}
+
+/*******************************************************************************
+ * BTIF -> BTA conversion functions
+ *******************************************************************************/
+
+void btif_to_bta_uuid(tBT_UUID* p_dest, const bt_uuid_t* p_src) {
+  char* p_byte = (char*)p_src;
+  int i = 0;
+
+  p_dest->len = uuidType(p_src->uu);
+
+  switch (p_dest->len) {
+    case LEN_UUID_16:
+      p_dest->uu.uuid16 = (p_src->uu[13] << 8) + p_src->uu[12];
+      break;
+
+    case LEN_UUID_32:
+      p_dest->uu.uuid32 = (p_src->uu[13] << 8) + p_src->uu[12];
+      p_dest->uu.uuid32 += (p_src->uu[15] << 24) + (p_src->uu[14] << 16);
+      break;
+
+    case LEN_UUID_128:
+      for (i = 0; i != 16; ++i) p_dest->uu.uuid128[i] = p_byte[i];
+      break;
+
+    default:
+      LOG_ERROR(LOG_TAG, "%s: Unknown UUID length %d!", __func__, p_dest->len);
+      break;
+  }
+}
+
+void btif_to_bta_response(tBTA_GATTS_RSP* p_dest, btgatt_response_t* p_src) {
+  p_dest->attr_value.auth_req = p_src->attr_value.auth_req;
+  p_dest->attr_value.handle = p_src->attr_value.handle;
+  p_dest->attr_value.len = p_src->attr_value.len;
+  p_dest->attr_value.offset = p_src->attr_value.offset;
+  memcpy(p_dest->attr_value.value, p_src->attr_value.value, GATT_MAX_ATTR_LEN);
+}
+
+void btif_to_bta_uuid_mask(tBTA_DM_BLE_PF_COND_MASK* p_mask,
+                           const bt_uuid_t* uuid_mask,
+                           const bt_uuid_t* svc_uuid) {
+  char* p_byte = (char*)uuid_mask;
+  int uuid_len = uuidType(svc_uuid->uu);
+  int i = 0;
+
+  switch (uuid_len) {
+    case LEN_UUID_16:
+      p_mask->uuid16_mask = (uuid_mask->uu[13] << 8) + uuid_mask->uu[12];
+      break;
+
+    case LEN_UUID_32:
+      p_mask->uuid32_mask = (uuid_mask->uu[13] << 8) + uuid_mask->uu[12];
+      p_mask->uuid32_mask +=
+          (uuid_mask->uu[15] << 24) + (uuid_mask->uu[14] << 16);
+      break;
+
+    case LEN_UUID_128:
+      for (i = 0; i != 16; ++i) p_mask->uuid128_mask[i] = p_byte[i];
+      break;
+
+    default:
+      break;
+  }
+}
+
+/*******************************************************************************
+ * BTA -> BTIF conversion functions
+ *******************************************************************************/
+
+void bta_to_btif_uuid(bt_uuid_t* p_dest, tBT_UUID* p_src) {
+  int i = 0;
+
+  if (p_src->len == LEN_UUID_16 || p_src->len == LEN_UUID_32) {
+    for (i = 0; i != 16; ++i) p_dest->uu[i] = BASE_UUID[i];
+  }
+
+  switch (p_src->len) {
+    case 0:
+      break;
+
+    case LEN_UUID_16:
+      p_dest->uu[12] = p_src->uu.uuid16 & 0xff;
+      p_dest->uu[13] = (p_src->uu.uuid16 >> 8) & 0xff;
+      break;
+
+    case LEN_UUID_32:
+      p_dest->uu[12] = p_src->uu.uuid16 & 0xff;
+      p_dest->uu[13] = (p_src->uu.uuid16 >> 8) & 0xff;
+      p_dest->uu[14] = (p_src->uu.uuid32 >> 16) & 0xff;
+      p_dest->uu[15] = (p_src->uu.uuid32 >> 24) & 0xff;
+      break;
+
+    case LEN_UUID_128:
+      for (i = 0; i != 16; ++i) p_dest->uu[i] = p_src->uu.uuid128[i];
+      break;
+
+    default:
+      LOG_ERROR(LOG_TAG, "%s: Unknown UUID length %d!", __func__, p_src->len);
+      break;
+  }
+}
+
+/*******************************************************************************
+ * Utility functions
+ *******************************************************************************/
+
+uint16_t get_uuid16(tBT_UUID* p_uuid) {
+  if (p_uuid->len == LEN_UUID_16) {
+    return p_uuid->uu.uuid16;
+  } else if (p_uuid->len == LEN_UUID_128) {
+    uint16_t u16;
+    uint8_t* p = &p_uuid->uu.uuid128[LEN_UUID_128 - 4];
+    STREAM_TO_UINT16(u16, p);
+    return u16;
+  } else /* p_uuid->len == LEN_UUID_32 */
+  {
+    return (uint16_t)p_uuid->uu.uuid32;
+  }
+}
+
+uint16_t set_read_value(btgatt_read_params_t* p_dest, tBTA_GATTC_READ* p_src) {
+  uint16_t len = 0;
+
+  p_dest->status = p_src->status;
+  p_dest->handle = p_src->handle;
+
+  if ((p_src->status == BTA_GATT_OK) && (p_src->len != 0)) {
+    LOG_INFO(LOG_TAG, "%s len = %d ", __func__, p_src->len);
+    p_dest->value.len = p_src->len;
+    memcpy(p_dest->value.value, p_src->value, p_src->len);
+
+    len += p_src->len;
+  } else {
+    p_dest->value.len = 0;
+  }
+
+  p_dest->value_type = GATTC_READ_VALUE_TYPE_VALUE;
+  return len;
+}
+
+/*******************************************************************************
+ * Encrypted link map handling
+ *******************************************************************************/
+
+#if (BLE_DELAY_REQUEST_ENC == FALSE)
+static bool btif_gatt_is_link_encrypted(BD_ADDR bd_addr) {
+  if (bd_addr == NULL) return false;
+
+  return BTA_JvIsEncrypted(bd_addr);
+}
+
+static void btif_gatt_set_encryption_cb(UNUSED_ATTR BD_ADDR bd_addr,
+                                        UNUSED_ATTR tBTA_TRANSPORT transport,
+                                        tBTA_STATUS result) {
+  if (result != BTA_SUCCESS && result != BTA_BUSY) {
+    BTIF_TRACE_WARNING("%s() - Encryption failed (%d)", __func__, result);
+  }
+}
+#endif
+
+#if (BLE_DELAY_REQUEST_ENC == FALSE)
+void btif_gatt_check_encrypted_link(BD_ADDR bd_addr,
+                                    tBTA_GATT_TRANSPORT transport_link) {
+  char buf[100];
+
+  bt_bdaddr_t bda;
+  bdcpy(bda.address, bd_addr);
+
+  if ((btif_storage_get_ble_bonding_key(&bda, BTIF_DM_LE_KEY_PENC, buf,
+                                        sizeof(tBTM_LE_PENC_KEYS)) ==
+       BT_STATUS_SUCCESS) &&
+      !btif_gatt_is_link_encrypted(bd_addr)) {
+    BTIF_TRACE_DEBUG("%s: transport = %d", __func__, transport_link);
+    BTA_DmSetEncryption(bd_addr, transport_link, &btif_gatt_set_encryption_cb,
+                        BTM_BLE_SEC_ENCRYPT);
+  }
+}
+#else
+void btif_gatt_check_encrypted_link(UNUSED_ATTR BD_ADDR bd_addr,
+                                    UNUSED_ATTR tBTA_GATT_TRANSPORT transport_link) {
+}
+#endif
+
+#endif  // BTA_GATT_INCLUDED
+
+void btif_gatt_move_track_adv_data(btgatt_track_adv_info_t* p_dest,
+                                   btgatt_track_adv_info_t* p_src) {
+  memset(p_dest, 0, sizeof(btgatt_track_adv_info_t));
+
+  memcpy(p_dest, p_src, sizeof(btgatt_track_adv_info_t));
+
+  if (p_src->adv_pkt_len > 0) {
+    p_dest->p_adv_pkt_data = (uint8_t*)osi_malloc(p_src->adv_pkt_len);
+    memcpy(p_dest->p_adv_pkt_data, p_src->p_adv_pkt_data, p_src->adv_pkt_len);
+    osi_free_and_reset((void**)&p_src->p_adv_pkt_data);
+  }
+
+  if (p_src->scan_rsp_len > 0) {
+    p_dest->p_scan_rsp_data = (uint8_t*)osi_malloc(p_src->scan_rsp_len);
+    memcpy(p_dest->p_scan_rsp_data, p_src->p_scan_rsp_data,
+           p_src->scan_rsp_len);
+    osi_free_and_reset((void**)&p_src->p_scan_rsp_data);
+  }
+}
diff --git a/bt/btif/src/btif_hf.cc b/bt/btif/src/btif_hf.cc
new file mode 100644
index 0000000..4f8f047
--- /dev/null
+++ b/bt/btif/src/btif_hf.cc
@@ -0,0 +1,1603 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ *  Filename:      btif_hf.c
+ *
+ *  Description:   Handsfree Profile Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+
+#define LOG_TAG "bt_btif_hf"
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hf.h>
+
+#include "bta/include/utl.h"
+#include "bta_ag_api.h"
+#include "btcore/include/bdaddr.h"
+#include "btif_common.h"
+#include "btif_hf.h"
+#include "btif_profile_queue.h"
+#include "btif_util.h"
+
+/************************************************************************************
+ *  Constants & Macros
+ ***********************************************************************************/
+#ifndef BTIF_HSAG_SERVICE_NAME
+#define BTIF_HSAG_SERVICE_NAME ("Headset Gateway")
+#endif
+
+#ifndef BTIF_HFAG_SERVICE_NAME
+#define BTIF_HFAG_SERVICE_NAME ("Handsfree Gateway")
+#endif
+
+#ifndef BTIF_HF_SERVICES
+#define BTIF_HF_SERVICES (BTA_HSP_SERVICE_MASK | BTA_HFP_SERVICE_MASK)
+#endif
+
+#ifndef BTIF_HF_SERVICE_NAMES
+#define BTIF_HF_SERVICE_NAMES \
+  { BTIF_HSAG_SERVICE_NAME, BTIF_HFAG_SERVICE_NAME }
+#endif
+
+#ifndef BTIF_HF_SECURITY
+#define BTIF_HF_SECURITY (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
+#endif
+
+#if (BTM_WBS_INCLUDED == TRUE)
+#ifndef BTIF_HF_FEATURES
+#define BTIF_HF_FEATURES                                       \
+  (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR | BTA_AG_FEAT_REJECT |  \
+   BTA_AG_FEAT_ECS | BTA_AG_FEAT_EXTERR | BTA_AG_FEAT_BTRH |   \
+   BTA_AG_FEAT_VREC | BTA_AG_FEAT_CODEC | BTA_AG_FEAT_HF_IND | \
+   BTA_AG_FEAT_ESCO | BTA_AG_FEAT_UNAT)
+#endif
+#else
+#ifndef BTIF_HF_FEATURES
+#define BTIF_HF_FEATURES                                      \
+  (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR | BTA_AG_FEAT_REJECT | \
+   BTA_AG_FEAT_ECS | BTA_AG_FEAT_EXTERR | BTA_AG_FEAT_BTRH |  \
+   BTA_AG_FEAT_VREC | BTA_AG_FEAT_HF_IND | BTA_AG_FEAT_ESCO | \
+   BTA_AG_FEAT_UNAT)
+#endif
+#endif
+
+#define BTIF_HF_CALL_END_TIMEOUT 6
+
+#define BTIF_HF_INVALID_IDX (-1)
+
+/* Number of BTIF-HF control blocks */
+#define BTIF_HF_NUM_CB 2
+
+/* Max HF clients supported from App */
+uint16_t btif_max_hf_clients = 1;
+
+/* HF app ids for service registration */
+typedef enum {
+  BTIF_HF_ID_1 = 0,
+  BTIF_HF_ID_2,
+#if (BTIF_HF_NUM_CB == 3)
+  BTIF_HF_ID_3
+#endif
+} bthf_hf_id_t;
+
+uint16_t bthf_hf_id[BTIF_HF_NUM_CB] = {BTIF_HF_ID_1, BTIF_HF_ID_2,
+#if (BTIF_HF_NUM_CB == 3)
+                                       BTIF_HF_ID_3
+#endif
+};
+
+/************************************************************************************
+ *  Local type definitions
+ ***********************************************************************************/
+
+/************************************************************************************
+ *  Static variables
+ ***********************************************************************************/
+static bthf_callbacks_t* bt_hf_callbacks = NULL;
+static int hf_idx = BTIF_HF_INVALID_IDX;
+
+#define CHECK_BTHF_INIT()                                             \
+  do {                                                                \
+    if (bt_hf_callbacks == NULL) {                                    \
+      BTIF_TRACE_WARNING("BTHF: %s: BTHF not initialized", __func__); \
+      return BT_STATUS_NOT_READY;                                     \
+    } else {                                                          \
+      BTIF_TRACE_EVENT("BTHF: %s", __func__);                         \
+    }                                                                 \
+  } while (0)
+
+#define CHECK_BTHF_SLC_CONNECTED()                                        \
+  do {                                                                    \
+    if (bt_hf_callbacks == NULL) {                                        \
+      BTIF_TRACE_WARNING("BTHF: %s: BTHF not initialized", __func__);     \
+      return BT_STATUS_NOT_READY;                                         \
+    } else if (btif_hf_cb.state != BTHF_CONNECTION_STATE_SLC_CONNECTED) { \
+      BTIF_TRACE_WARNING("BTHF: %s: SLC connection not up. state=%s",     \
+                         __func__, dump_hf_conn_state(btif_hf_cb.state)); \
+      return BT_STATUS_NOT_READY;                                         \
+    } else {                                                              \
+      BTIF_TRACE_EVENT("BTHF: %s", __func__);                             \
+    }                                                                     \
+  } while (0)
+
+/* BTIF-HF control block to map bdaddr to BTA handle */
+typedef struct _btif_hf_cb {
+  uint16_t handle;
+  bt_bdaddr_t connected_bda;
+  bthf_connection_state_t state;
+  bthf_vr_state_t vr_state;
+  tBTA_AG_PEER_FEAT peer_feat;
+  int num_active;
+  int num_held;
+  struct timespec call_end_timestamp;
+  struct timespec connected_timestamp;
+  bthf_call_state_t call_setup_state;
+} btif_hf_cb_t;
+
+static btif_hf_cb_t btif_hf_cb[BTIF_HF_NUM_CB];
+
+/************************************************************************************
+ *  Static functions
+ ***********************************************************************************/
+
+/************************************************************************************
+ *  Externs
+ ***********************************************************************************/
+/* By default, even though codec negotiation is enabled, we will not use WBS as
+* the default
+* codec unless this variable is set to true.
+*/
+#ifndef BTIF_HF_WBS_PREFERRED
+#define BTIF_HF_WBS_PREFERRED false
+#endif
+
+bool btif_conf_hf_force_wbs = BTIF_HF_WBS_PREFERRED;
+
+/************************************************************************************
+ *  Functions
+ ***********************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         is_connected
+ *
+ * Description      Internal function to check if HF is connected
+ *
+ * Returns          true if connected
+ *
+ ******************************************************************************/
+static bool is_connected(bt_bdaddr_t* bd_addr) {
+  int i;
+  for (i = 0; i < btif_max_hf_clients; ++i) {
+    if (((btif_hf_cb[i].state == BTHF_CONNECTION_STATE_CONNECTED) ||
+         (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED)) &&
+        ((bd_addr == NULL) ||
+         (bdcmp(bd_addr->address, btif_hf_cb[i].connected_bda.address) == 0)))
+      return true;
+  }
+  return false;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hf_idx_by_bdaddr
+ *
+ * Description      Internal function to get idx by bdaddr
+ *
+ * Returns          idx
+ *
+ ******************************************************************************/
+static int btif_hf_idx_by_bdaddr(bt_bdaddr_t* bd_addr) {
+  int i;
+  for (i = 0; i < btif_max_hf_clients; ++i) {
+    if ((bdcmp(bd_addr->address, btif_hf_cb[i].connected_bda.address) == 0))
+      return i;
+  }
+  return BTIF_HF_INVALID_IDX;
+}
+
+/*******************************************************************************
+ *
+ * Function         callstate_to_callsetup
+ *
+ * Description      Converts HAL call state to BTA call setup indicator value
+ *
+ * Returns          BTA call indicator value
+ *
+ ******************************************************************************/
+static uint8_t callstate_to_callsetup(bthf_call_state_t call_state) {
+  uint8_t call_setup = 0;
+  if (call_state == BTHF_CALL_STATE_INCOMING) call_setup = 1;
+  if (call_state == BTHF_CALL_STATE_DIALING) call_setup = 2;
+  if (call_state == BTHF_CALL_STATE_ALERTING) call_setup = 3;
+
+  return call_setup;
+}
+
+/*******************************************************************************
+ *
+ * Function         send_at_result
+ *
+ * Description      Send AT result code (OK/ERROR)
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void send_at_result(uint8_t ok_flag, uint16_t errcode, int idx) {
+  tBTA_AG_RES_DATA ag_res;
+  memset(&ag_res, 0, sizeof(ag_res));
+
+  ag_res.ok_flag = ok_flag;
+  if (ok_flag == BTA_AG_OK_ERROR) {
+    ag_res.errcode = errcode;
+  }
+
+  BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_UNAT_RES, &ag_res);
+}
+
+/*******************************************************************************
+ *
+ * Function         send_indicator_update
+ *
+ * Description      Send indicator update (CIEV)
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void send_indicator_update(uint16_t indicator, uint16_t value) {
+  tBTA_AG_RES_DATA ag_res;
+
+  memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+  ag_res.ind.id = indicator;
+  ag_res.ind.value = value;
+
+  BTA_AgResult(BTA_AG_HANDLE_ALL, BTA_AG_IND_RES, &ag_res);
+}
+
+void clear_phone_state_multihf(int idx) {
+  btif_hf_cb[idx].call_setup_state = BTHF_CALL_STATE_IDLE;
+  btif_hf_cb[idx].num_active = btif_hf_cb[idx].num_held = 0;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hf_latest_connected_idx
+ *
+ * Description      Returns idx for latest connected HF
+ *
+ * Returns          int
+ *
+ ******************************************************************************/
+static int btif_hf_latest_connected_idx() {
+  struct timespec now, conn_time_delta;
+  int latest_conn_idx = BTIF_HF_INVALID_IDX, i;
+
+  clock_gettime(CLOCK_MONOTONIC, &now);
+  conn_time_delta.tv_sec = now.tv_sec;
+
+  for (i = 0; i < btif_max_hf_clients; i++) {
+    if (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED) {
+      if ((now.tv_sec - btif_hf_cb[i].connected_timestamp.tv_sec) <
+          conn_time_delta.tv_sec) {
+        conn_time_delta.tv_sec =
+            now.tv_sec - btif_hf_cb[i].connected_timestamp.tv_sec;
+        latest_conn_idx = i;
+      }
+    }
+  }
+  return latest_conn_idx;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hf_check_if_slc_connected
+ *
+ * Description      Returns BT_STATUS_SUCCESS if SLC is up for any HF
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t btif_hf_check_if_slc_connected() {
+  if (bt_hf_callbacks == NULL) {
+    BTIF_TRACE_WARNING("BTHF: %s: BTHF not initialized", __func__);
+    return BT_STATUS_NOT_READY;
+  } else {
+    int i;
+    for (i = 0; i < btif_max_hf_clients; i++) {
+      if (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED) {
+        BTIF_TRACE_EVENT("BTHF: %s: slc connected for idx = %d", __func__, i);
+        return BT_STATUS_SUCCESS;
+      }
+    }
+    BTIF_TRACE_WARNING("BTHF: %s: No SLC connection up", __func__);
+    return BT_STATUS_NOT_READY;
+  }
+}
+
+/*****************************************************************************
+ *   Section name (Group of functions)
+ ****************************************************************************/
+
+/*****************************************************************************
+ *
+ *   btif hf api functions (no context switch)
+ *
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         btif_hf_upstreams_evt
+ *
+ * Description      Executes HF UPSTREAMS events in btif context
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_hf_upstreams_evt(uint16_t event, char* p_param) {
+  tBTA_AG* p_data = (tBTA_AG*)p_param;
+  bdstr_t bdstr;
+  int idx = p_data->hdr.handle - 1;
+
+  BTIF_TRACE_DEBUG("%s: event=%s", __func__, dump_hf_event(event));
+
+  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+    return;
+  }
+
+  switch (event) {
+    case BTA_AG_ENABLE_EVT:
+    case BTA_AG_DISABLE_EVT:
+      break;
+
+    case BTA_AG_REGISTER_EVT:
+      btif_hf_cb[idx].handle = p_data->reg.hdr.handle;
+      BTIF_TRACE_DEBUG(
+          "%s: BTA_AG_REGISTER_EVT,"
+          "btif_hf_cb.handle = %d",
+          __func__, btif_hf_cb[idx].handle);
+      break;
+
+    case BTA_AG_OPEN_EVT:
+      if (p_data->open.status == BTA_AG_SUCCESS) {
+        bdcpy(btif_hf_cb[idx].connected_bda.address, p_data->open.bd_addr);
+        btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_CONNECTED;
+        btif_hf_cb[idx].peer_feat = 0;
+        clear_phone_state_multihf(idx);
+      } else if (btif_hf_cb[idx].state == BTHF_CONNECTION_STATE_CONNECTING) {
+        btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_DISCONNECTED;
+      } else {
+        BTIF_TRACE_WARNING(
+            "%s: AG open failed, but another device connected. status=%d "
+            "state=%d connected device=%s",
+            __func__, p_data->open.status, btif_hf_cb[idx].state,
+            bdaddr_to_string(&btif_hf_cb[idx].connected_bda, bdstr,
+                             sizeof(bdstr)));
+        break;
+      }
+
+      HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb[idx].state,
+                &btif_hf_cb[idx].connected_bda);
+
+      if (btif_hf_cb[idx].state == BTHF_CONNECTION_STATE_DISCONNECTED)
+        bdsetany(btif_hf_cb[idx].connected_bda.address);
+
+      if (p_data->open.status != BTA_AG_SUCCESS) btif_queue_advance();
+      break;
+
+    case BTA_AG_CLOSE_EVT:
+      btif_hf_cb[idx].connected_timestamp.tv_sec = 0;
+      btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_DISCONNECTED;
+      BTIF_TRACE_DEBUG(
+          "%s: BTA_AG_CLOSE_EVT,"
+          "idx = %d, btif_hf_cb.handle = %d",
+          __func__, idx, btif_hf_cb[idx].handle);
+      HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb[idx].state,
+                &btif_hf_cb[idx].connected_bda);
+      bdsetany(btif_hf_cb[idx].connected_bda.address);
+      btif_hf_cb[idx].peer_feat = 0;
+      clear_phone_state_multihf(idx);
+      hf_idx = btif_hf_latest_connected_idx();
+      /* If AG_OPEN was received but SLC was not setup in a specified time (10
+      *seconds),
+      ** then AG_CLOSE may be received. We need to advance the queue here
+      */
+      btif_queue_advance();
+      break;
+
+    case BTA_AG_CONN_EVT:
+      clock_gettime(CLOCK_MONOTONIC, &btif_hf_cb[idx].connected_timestamp);
+      BTIF_TRACE_DEBUG("%s: BTA_AG_CONN_EVT, idx = %d ", __func__, idx);
+      btif_hf_cb[idx].peer_feat = p_data->conn.peer_feat;
+      btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_SLC_CONNECTED;
+      hf_idx = btif_hf_latest_connected_idx();
+
+      HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb[idx].state,
+                &btif_hf_cb[idx].connected_bda);
+      btif_queue_advance();
+      break;
+
+    case BTA_AG_AUDIO_OPEN_EVT:
+      hf_idx = idx;
+      HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_CONNECTED,
+                &btif_hf_cb[idx].connected_bda);
+      break;
+
+    case BTA_AG_AUDIO_CLOSE_EVT:
+      HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_DISCONNECTED,
+                &btif_hf_cb[idx].connected_bda);
+      break;
+
+    /* BTA auto-responds, silently discard */
+    case BTA_AG_SPK_EVT:
+    case BTA_AG_MIC_EVT:
+      HAL_CBACK(bt_hf_callbacks, volume_cmd_cb,
+                (event == BTA_AG_SPK_EVT) ? BTHF_VOLUME_TYPE_SPK
+                                          : BTHF_VOLUME_TYPE_MIC,
+                p_data->val.num, &btif_hf_cb[idx].connected_bda);
+      break;
+
+    case BTA_AG_AT_A_EVT:
+      if ((btif_hf_cb[0].num_held + btif_hf_cb[0].num_active) == 0)
+        hf_idx = idx;
+      else
+        BTIF_TRACE_DEBUG("Donot set hf_idx for ATA since already in a call");
+
+      HAL_CBACK(bt_hf_callbacks, answer_call_cmd_cb,
+                &btif_hf_cb[idx].connected_bda);
+      break;
+
+    /* Java needs to send OK/ERROR for these commands */
+    case BTA_AG_AT_BLDN_EVT:
+    case BTA_AG_AT_D_EVT:
+      if ((btif_hf_cb[0].num_held + btif_hf_cb[0].num_active) == 0)
+        hf_idx = idx;
+      else
+        BTIF_TRACE_DEBUG("Donot set hf_idx for BLDN/D since already in a call");
+
+      HAL_CBACK(bt_hf_callbacks, dial_call_cmd_cb,
+                (event == BTA_AG_AT_D_EVT) ? p_data->val.str : NULL,
+                &btif_hf_cb[idx].connected_bda);
+      break;
+
+    case BTA_AG_AT_CHUP_EVT:
+      HAL_CBACK(bt_hf_callbacks, hangup_call_cmd_cb,
+                &btif_hf_cb[idx].connected_bda);
+      break;
+
+    case BTA_AG_AT_CIND_EVT:
+      HAL_CBACK(bt_hf_callbacks, cind_cmd_cb, &btif_hf_cb[idx].connected_bda);
+      break;
+
+    case BTA_AG_AT_VTS_EVT:
+      HAL_CBACK(bt_hf_callbacks, dtmf_cmd_cb, p_data->val.str[0],
+                &btif_hf_cb[idx].connected_bda);
+      break;
+
+    case BTA_AG_AT_BVRA_EVT:
+      HAL_CBACK(bt_hf_callbacks, vr_cmd_cb,
+                (p_data->val.num == 1) ? BTHF_VR_STATE_STARTED
+                                       : BTHF_VR_STATE_STOPPED,
+                &btif_hf_cb[idx].connected_bda);
+      break;
+
+    case BTA_AG_AT_NREC_EVT:
+      HAL_CBACK(bt_hf_callbacks, nrec_cmd_cb,
+                (p_data->val.num == 1) ? BTHF_NREC_START : BTHF_NREC_STOP,
+                &btif_hf_cb[idx].connected_bda);
+      break;
+
+    /* TODO: Add a callback for CBC */
+    case BTA_AG_AT_CBC_EVT:
+      break;
+
+    case BTA_AG_AT_CKPD_EVT:
+      HAL_CBACK(bt_hf_callbacks, key_pressed_cmd_cb,
+                &btif_hf_cb[idx].connected_bda);
+      break;
+
+#if (BTM_WBS_INCLUDED == TRUE)
+    case BTA_AG_WBS_EVT:
+      BTIF_TRACE_DEBUG(
+          "BTA_AG_WBS_EVT Set codec status %d codec %d 1=CVSD 2=MSBC",
+          p_data->val.hdr.status, p_data->val.num);
+      if (p_data->val.num == BTA_AG_CODEC_CVSD) {
+        HAL_CBACK(bt_hf_callbacks, wbs_cb, BTHF_WBS_NO,
+                  &btif_hf_cb[idx].connected_bda);
+      } else if (p_data->val.num == BTA_AG_CODEC_MSBC) {
+        HAL_CBACK(bt_hf_callbacks, wbs_cb, BTHF_WBS_YES,
+                  &btif_hf_cb[idx].connected_bda);
+      } else {
+        HAL_CBACK(bt_hf_callbacks, wbs_cb, BTHF_WBS_NONE,
+                  &btif_hf_cb[idx].connected_bda);
+      }
+      break;
+#endif
+    /* Java needs to send OK/ERROR for these commands */
+    case BTA_AG_AT_CHLD_EVT:
+      HAL_CBACK(bt_hf_callbacks, chld_cmd_cb,
+                (bthf_chld_type_t)atoi(p_data->val.str),
+                &btif_hf_cb[idx].connected_bda);
+      break;
+
+    case BTA_AG_AT_CLCC_EVT:
+      HAL_CBACK(bt_hf_callbacks, clcc_cmd_cb, &btif_hf_cb[idx].connected_bda);
+      break;
+
+    case BTA_AG_AT_COPS_EVT:
+      HAL_CBACK(bt_hf_callbacks, cops_cmd_cb, &btif_hf_cb[idx].connected_bda);
+      break;
+
+    case BTA_AG_AT_UNAT_EVT:
+      HAL_CBACK(bt_hf_callbacks, unknown_at_cmd_cb, p_data->val.str,
+                &btif_hf_cb[idx].connected_bda);
+      break;
+
+    case BTA_AG_AT_CNUM_EVT:
+      HAL_CBACK(bt_hf_callbacks, cnum_cmd_cb, &btif_hf_cb[idx].connected_bda);
+      break;
+
+    /* TODO: Some of these commands may need to be sent to app. For now respond
+     * with error */
+    case BTA_AG_AT_BINP_EVT:
+    case BTA_AG_AT_BTRH_EVT:
+      send_at_result(BTA_AG_OK_ERROR, BTA_AG_ERR_OP_NOT_SUPPORTED, idx);
+      break;
+    case BTA_AG_AT_BAC_EVT:
+      BTIF_TRACE_DEBUG("AG Bitmap of peer-codecs %d", p_data->val.num);
+#if (BTM_WBS_INCLUDED == TRUE)
+      /* If the peer supports mSBC and the BTIF prefferred codec is also mSBC,
+      then
+      we should set the BTA AG Codec to mSBC. This would trigger a +BCS to mSBC
+      at the time
+      of SCO connection establishment */
+      if ((btif_conf_hf_force_wbs == true) &&
+          (p_data->val.num & BTA_AG_CODEC_MSBC)) {
+        BTIF_TRACE_EVENT("%s btif_hf override-Preferred Codec to MSBC",
+                         __func__);
+        BTA_AgSetCodec(btif_hf_cb[idx].handle, BTA_AG_CODEC_MSBC);
+      } else {
+        BTIF_TRACE_EVENT("%s btif_hf override-Preferred Codec to CVSD",
+                         __func__);
+        BTA_AgSetCodec(btif_hf_cb[idx].handle, BTA_AG_CODEC_CVSD);
+      }
+#endif
+      break;
+    case BTA_AG_AT_BCS_EVT:
+      BTIF_TRACE_DEBUG("AG final seleded codec is %d 1=CVSD 2=MSBC",
+                       p_data->val.num);
+      /*  no BTHF_WBS_NONE case, becuase HF1.6 supported device can send BCS */
+      HAL_CBACK(
+          bt_hf_callbacks, wbs_cb,
+          (p_data->val.num == BTA_AG_CODEC_MSBC) ? BTHF_WBS_YES : BTHF_WBS_NO,
+          &btif_hf_cb[idx].connected_bda);
+      break;
+
+    case BTA_AG_AT_BIND_EVT:
+      if (p_data->val.hdr.status == BTA_AG_SUCCESS) {
+        HAL_CBACK(bt_hf_callbacks, bind_cb, p_data->val.str,
+                  &btif_hf_cb[idx].connected_bda);
+      }
+      break;
+
+    case BTA_AG_AT_BIEV_EVT:
+      if (p_data->val.hdr.status == BTA_AG_SUCCESS) {
+        HAL_CBACK(bt_hf_callbacks, biev_cb,
+                  (bthf_hf_ind_type_t)p_data->val.lidx, (int)p_data->val.num,
+                  &btif_hf_cb[idx].connected_bda);
+      }
+      break;
+    default:
+      BTIF_TRACE_WARNING("%s: Unhandled event: %d", __func__, event);
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bte_hf_evt
+ *
+ * Description      Switches context from BTE to BTIF for all HF events
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+
+static void bte_hf_evt(tBTA_AG_EVT event, tBTA_AG* p_data) {
+  bt_status_t status;
+  int param_len = 0;
+
+  /* TODO: BTA sends the union members and not tBTA_AG. If using
+   * param_len=sizeof(tBTA_AG), we get a crash on memcpy */
+  if (BTA_AG_REGISTER_EVT == event)
+    param_len = sizeof(tBTA_AG_REGISTER);
+  else if (BTA_AG_OPEN_EVT == event)
+    param_len = sizeof(tBTA_AG_OPEN);
+  else if (BTA_AG_CONN_EVT == event)
+    param_len = sizeof(tBTA_AG_CONN);
+  else if ((BTA_AG_CLOSE_EVT == event) || (BTA_AG_AUDIO_OPEN_EVT == event) ||
+           (BTA_AG_AUDIO_CLOSE_EVT == event))
+    param_len = sizeof(tBTA_AG_HDR);
+  else if (p_data)
+    param_len = sizeof(tBTA_AG_VAL);
+
+  /* switch context to btif task context (copy full union size for convenience)
+   */
+  status = btif_transfer_context(btif_hf_upstreams_evt, (uint16_t)event,
+                                 (char*)p_data, param_len, NULL);
+
+  /* catch any failed context transfers */
+  ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_in_hf_generic_evt
+ *
+ * Description     Processes generic events to be sent to JNI that are not
+ *                      triggered from the BTA.
+ *                      Always runs in BTIF context
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_in_hf_generic_evt(uint16_t event, char* p_param) {
+  int idx = btif_hf_idx_by_bdaddr((bt_bdaddr_t*)p_param);
+
+  BTIF_TRACE_EVENT("%s: event=%d", __func__, event);
+
+  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+    return;
+  }
+
+  switch (event) {
+    case BTIF_HFP_CB_AUDIO_CONNECTING: {
+      HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_CONNECTING,
+                &btif_hf_cb[idx].connected_bda);
+    } break;
+    default: {
+      BTIF_TRACE_WARNING("%s : Unknown event 0x%x", __func__, event);
+    } break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hf_init
+ *
+ * Description     initializes the hf interface
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t init(bthf_callbacks_t* callbacks, int max_hf_clients) {
+  btif_max_hf_clients = max_hf_clients;
+  BTIF_TRACE_DEBUG("%s - max_hf_clients=%d", __func__, btif_max_hf_clients);
+
+  bt_hf_callbacks = callbacks;
+  memset(&btif_hf_cb, 0, sizeof(btif_hf_cb));
+
+/* Invoke the enable service API to the core to set the appropriate service_id
+ * Internally, the HSP_SERVICE_ID shall also be enabled if HFP is enabled
+ * (phone)
+ * othwerwise only HSP is enabled (tablet)
+*/
+#if (defined(BTIF_HF_SERVICES) && (BTIF_HF_SERVICES & BTA_HFP_SERVICE_MASK))
+  btif_enable_service(BTA_HFP_SERVICE_ID);
+#else
+  btif_enable_service(BTA_HSP_SERVICE_ID);
+#endif
+
+  for (int i = 0; i < btif_max_hf_clients; i++) clear_phone_state_multihf(i);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         connect
+ *
+ * Description     connect to headset
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t connect_int(bt_bdaddr_t* bd_addr, uint16_t uuid) {
+  CHECK_BTHF_INIT();
+  int i;
+  for (i = 0; i < btif_max_hf_clients;) {
+    if (((btif_hf_cb[i].state == BTHF_CONNECTION_STATE_CONNECTED) ||
+         (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED)))
+      i++;
+    else
+      break;
+  }
+
+  if (i == btif_max_hf_clients) return BT_STATUS_BUSY;
+
+  if (!is_connected(bd_addr)) {
+    btif_hf_cb[i].state = BTHF_CONNECTION_STATE_CONNECTING;
+    bdcpy(btif_hf_cb[i].connected_bda.address, bd_addr->address);
+
+    BTA_AgOpen(btif_hf_cb[i].handle, btif_hf_cb[i].connected_bda.address,
+               BTIF_HF_SECURITY, BTIF_HF_SERVICES);
+    return BT_STATUS_SUCCESS;
+  }
+
+  return BT_STATUS_BUSY;
+}
+
+static bt_status_t connect(bt_bdaddr_t* bd_addr) {
+  CHECK_BTHF_INIT();
+  return btif_queue_connect(UUID_SERVCLASS_AG_HANDSFREE, bd_addr, connect_int);
+}
+
+/*******************************************************************************
+ *
+ * Function         disconnect
+ *
+ * Description      disconnect from headset
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t disconnect(bt_bdaddr_t* bd_addr) {
+  CHECK_BTHF_INIT();
+
+  int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+    return BT_STATUS_FAIL;
+  }
+
+  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+    BTA_AgClose(btif_hf_cb[idx].handle);
+    return BT_STATUS_SUCCESS;
+  }
+
+  return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         connect_audio
+ *
+ * Description     create an audio connection
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t connect_audio(bt_bdaddr_t* bd_addr) {
+  CHECK_BTHF_INIT();
+
+  int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+    return BT_STATUS_FAIL;
+  }
+
+  /* Check if SLC is connected */
+  if (btif_hf_check_if_slc_connected() != BT_STATUS_SUCCESS)
+    return BT_STATUS_NOT_READY;
+
+  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+    BTA_AgAudioOpen(btif_hf_cb[idx].handle);
+
+    /* Inform the application that the audio connection has been initiated
+     * successfully */
+    btif_transfer_context(btif_in_hf_generic_evt, BTIF_HFP_CB_AUDIO_CONNECTING,
+                          (char*)bd_addr, sizeof(bt_bdaddr_t), NULL);
+    return BT_STATUS_SUCCESS;
+  }
+
+  return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         disconnect_audio
+ *
+ * Description      close the audio connection
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t disconnect_audio(bt_bdaddr_t* bd_addr) {
+  CHECK_BTHF_INIT();
+
+  int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+    return BT_STATUS_FAIL;
+  }
+
+  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+    BTA_AgAudioClose(btif_hf_cb[idx].handle);
+    return BT_STATUS_SUCCESS;
+  }
+
+  return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         start_voice_recognition
+ *
+ * Description      start voice recognition
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t start_voice_recognition(bt_bdaddr_t* bd_addr) {
+  CHECK_BTHF_INIT();
+
+  int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+    return BT_STATUS_FAIL;
+  }
+
+  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+    if (btif_hf_cb[idx].peer_feat & BTA_AG_PEER_FEAT_VREC) {
+      tBTA_AG_RES_DATA ag_res;
+      memset(&ag_res, 0, sizeof(ag_res));
+      ag_res.state = 1;
+      BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_BVRA_RES, &ag_res);
+
+      return BT_STATUS_SUCCESS;
+    } else {
+      return BT_STATUS_UNSUPPORTED;
+    }
+  }
+
+  return BT_STATUS_NOT_READY;
+}
+
+/*******************************************************************************
+ *
+ * Function         stop_voice_recognition
+ *
+ * Description      stop voice recognition
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t stop_voice_recognition(bt_bdaddr_t* bd_addr) {
+  CHECK_BTHF_INIT();
+
+  int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+    return BT_STATUS_FAIL;
+  }
+
+  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+    if (btif_hf_cb[idx].peer_feat & BTA_AG_PEER_FEAT_VREC) {
+      tBTA_AG_RES_DATA ag_res;
+      memset(&ag_res, 0, sizeof(ag_res));
+      ag_res.state = 0;
+      BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_BVRA_RES, &ag_res);
+
+      return BT_STATUS_SUCCESS;
+    } else {
+      return BT_STATUS_UNSUPPORTED;
+    }
+  }
+
+  return BT_STATUS_NOT_READY;
+}
+
+/*******************************************************************************
+ *
+ * Function         volume_control
+ *
+ * Description      volume control
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t volume_control(bthf_volume_type_t type, int volume,
+                                  bt_bdaddr_t* bd_addr) {
+  CHECK_BTHF_INIT();
+
+  int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+    return BT_STATUS_FAIL;
+  }
+
+  tBTA_AG_RES_DATA ag_res;
+  memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+    ag_res.num = volume;
+    BTA_AgResult(
+        btif_hf_cb[idx].handle,
+        (type == BTHF_VOLUME_TYPE_SPK) ? BTA_AG_SPK_RES : BTA_AG_MIC_RES,
+        &ag_res);
+    return BT_STATUS_SUCCESS;
+  }
+
+  return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         device_status_notification
+ *
+ * Description      Combined device status change notification
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t device_status_notification(bthf_network_state_t ntk_state,
+                                              bthf_service_type_t svc_type,
+                                              int signal, int batt_chg) {
+  CHECK_BTHF_INIT();
+
+  if (is_connected(NULL)) {
+    /* send all indicators to BTA.
+    ** BTA will make sure no duplicates are sent out
+    */
+    send_indicator_update(BTA_AG_IND_SERVICE,
+                          (ntk_state == BTHF_NETWORK_STATE_AVAILABLE) ? 1 : 0);
+    send_indicator_update(BTA_AG_IND_ROAM,
+                          (svc_type == BTHF_SERVICE_TYPE_HOME) ? 0 : 1);
+    send_indicator_update(BTA_AG_IND_SIGNAL, signal);
+    send_indicator_update(BTA_AG_IND_BATTCHG, batt_chg);
+    return BT_STATUS_SUCCESS;
+  }
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         cops_response
+ *
+ * Description      Response for COPS command
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t cops_response(const char* cops, bt_bdaddr_t* bd_addr) {
+  CHECK_BTHF_INIT();
+
+  int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+    return BT_STATUS_FAIL;
+  }
+
+  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+    tBTA_AG_RES_DATA ag_res;
+
+    /* Format the response */
+    snprintf(ag_res.str, sizeof(ag_res.str), "0,0,\"%.16s\"", cops);
+    ag_res.ok_flag = BTA_AG_OK_DONE;
+
+    BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_COPS_RES, &ag_res);
+    return BT_STATUS_SUCCESS;
+  }
+  return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         cind_response
+ *
+ * Description      Response for CIND command
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t cind_response(int svc, int num_active, int num_held,
+                                 bthf_call_state_t call_setup_state, int signal,
+                                 int roam, int batt_chg, bt_bdaddr_t* bd_addr) {
+  CHECK_BTHF_INIT();
+
+  int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+    return BT_STATUS_FAIL;
+  }
+
+  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+    tBTA_AG_RES_DATA ag_res;
+
+    memset(&ag_res, 0, sizeof(ag_res));
+    /* per the errata 2043, call=1 implies atleast one call is in progress
+    *(active/held)
+    ** https://www.bluetooth.org/errata/errata_view.cfm?errata_id=2043
+    **/
+    snprintf(
+        ag_res.str, sizeof(ag_res.str), "%d,%d,%d,%d,%d,%d,%d",
+        (num_active + num_held) ? 1 : 0,          /* Call state */
+        callstate_to_callsetup(call_setup_state), /* Callsetup state */
+        svc,                                      /* network service */
+        signal,                                   /* Signal strength */
+        roam,                                     /* Roaming indicator */
+        batt_chg,                                 /* Battery level */
+        ((num_held == 0) ? 0 : ((num_active == 0) ? 2 : 1))); /* Call held */
+
+    BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_CIND_RES, &ag_res);
+
+    return BT_STATUS_SUCCESS;
+  }
+
+  return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         bind_response
+ *
+ * Description      Send +BIND response
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t bind_response(bthf_hf_ind_type_t ind_id,
+                                 bthf_hf_ind_status_t ind_status,
+                                 bt_bdaddr_t* bd_addr) {
+  CHECK_BTHF_INIT();
+
+  int index = btif_hf_idx_by_bdaddr(bd_addr);
+  if (!is_connected(bd_addr) || index == BTIF_HF_INVALID_IDX)
+    return BT_STATUS_FAIL;
+
+  tBTA_AG_RES_DATA ag_res;
+  memset(&ag_res, 0, sizeof(ag_res));
+  ag_res.ind.id = ind_id;
+  ag_res.ind.on_demand = (ind_status == BTHF_HF_IND_ENABLED);
+
+  BTA_AgResult(btif_hf_cb[index].handle, BTA_AG_BIND_RES, &ag_res);
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         formatted_at_response
+ *
+ * Description      Pre-formatted AT response, typically in response to unknown
+ *                  AT cmd
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t formatted_at_response(const char* rsp,
+                                         bt_bdaddr_t* bd_addr) {
+  CHECK_BTHF_INIT();
+  tBTA_AG_RES_DATA ag_res;
+  int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+    return BT_STATUS_FAIL;
+  }
+
+  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+    /* Format the response and send */
+    memset(&ag_res, 0, sizeof(ag_res));
+    strncpy(ag_res.str, rsp, BTA_AG_AT_MAX_LEN);
+    BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_UNAT_RES, &ag_res);
+
+    return BT_STATUS_SUCCESS;
+  }
+
+  return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         at_response
+ *
+ * Description      ok/error response
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t at_response(bthf_at_response_t response_code, int error_code,
+                               bt_bdaddr_t* bd_addr) {
+  CHECK_BTHF_INIT();
+
+  int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+    return BT_STATUS_FAIL;
+  }
+
+  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+    send_at_result((response_code == BTHF_AT_RESPONSE_OK) ? BTA_AG_OK_DONE
+                                                          : BTA_AG_OK_ERROR,
+                   error_code, idx);
+    return BT_STATUS_SUCCESS;
+  }
+
+  return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         clcc_response
+ *
+ * Description      response for CLCC command
+ *                  Can be iteratively called for each call index. Call index
+ *                  of 0 will be treated as NULL termination (Completes
+ *                  response)
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t clcc_response(int index, bthf_call_direction_t dir,
+                                 bthf_call_state_t state, bthf_call_mode_t mode,
+                                 bthf_call_mpty_type_t mpty, const char* number,
+                                 bthf_call_addrtype_t type,
+                                 bt_bdaddr_t* bd_addr) {
+  CHECK_BTHF_INIT();
+
+  int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+    return BT_STATUS_FAIL;
+  }
+
+  if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+    tBTA_AG_RES_DATA ag_res;
+    memset(&ag_res, 0, sizeof(ag_res));
+
+    /* Format the response */
+    if (index == 0) {
+      ag_res.ok_flag = BTA_AG_OK_DONE;
+    } else {
+      BTIF_TRACE_EVENT(
+          "clcc_response: [%d] dir %d state %d mode %d number = %s type = %d",
+          index, dir, state, mode, number, type);
+      int res_strlen = snprintf(ag_res.str, sizeof(ag_res.str),
+                                "%d,%d,%d,%d,%d", index, dir, state, mode,
+                                mpty);
+
+      if (number) {
+        size_t rem_bytes = sizeof(ag_res.str) - res_strlen;
+        char dialnum[sizeof(ag_res.str)];
+        size_t newidx = 0;
+        if (type == BTHF_CALL_ADDRTYPE_INTERNATIONAL && *number != '+') {
+          dialnum[newidx++] = '+';
+        }
+        for (size_t i = 0; number[i] != 0; i++) {
+          if (utl_isdialchar(number[i])) {
+            dialnum[newidx++] = number[i];
+          }
+        }
+        dialnum[newidx] = 0;
+        snprintf(&ag_res.str[res_strlen], rem_bytes, ",\"%s\",%d", dialnum,
+                 type);
+      }
+    }
+    BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_CLCC_RES, &ag_res);
+
+    return BT_STATUS_SUCCESS;
+  }
+
+  return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         phone_state_change
+ *
+ * Description      notify of a call state change
+ *                  number & type: valid only for incoming & waiting call
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+
+static bt_status_t phone_state_change(int num_active, int num_held,
+                                      bthf_call_state_t call_setup_state,
+                                      const char* number,
+                                      bthf_call_addrtype_t type) {
+  tBTA_AG_RES res = 0xff;
+  tBTA_AG_RES_DATA ag_res;
+  bt_status_t status = BT_STATUS_SUCCESS;
+  bool activeCallUpdated = false;
+  int idx, i;
+
+  /* hf_idx is index of connected HS that sent ATA/BLDN,
+          otherwise index of latest connected HS */
+  if (hf_idx != BTIF_HF_INVALID_IDX)
+    idx = hf_idx;
+  else
+    idx = btif_hf_latest_connected_idx();
+
+  BTIF_TRACE_DEBUG("phone_state_change: idx = %d", idx);
+
+  /* Check if SLC is connected */
+  if (btif_hf_check_if_slc_connected() != BT_STATUS_SUCCESS)
+    return BT_STATUS_NOT_READY;
+
+  BTIF_TRACE_DEBUG(
+      "phone_state_change: num_active=%d [prev: %d]  num_held=%d[prev: %d]"
+      " call_setup=%s [prev: %s]",
+      num_active, btif_hf_cb[idx].num_active, num_held,
+      btif_hf_cb[idx].num_held, dump_hf_call_state(call_setup_state),
+      dump_hf_call_state(btif_hf_cb[idx].call_setup_state));
+
+  /* if all indicators are 0, send end call and return */
+  if (num_active == 0 && num_held == 0 &&
+      call_setup_state == BTHF_CALL_STATE_IDLE) {
+    BTIF_TRACE_DEBUG("%s: Phone on hook", __func__);
+
+    /* record call termination timestamp  if  there was an active/held call  or
+               callsetup state > BTHF_CALL_STATE_IDLE */
+    if ((btif_hf_cb[idx].call_setup_state != BTHF_CALL_STATE_IDLE) ||
+        (btif_hf_cb[idx].num_active) || (btif_hf_cb[idx].num_held)) {
+      BTIF_TRACE_DEBUG("%s: Record call termination timestamp", __func__);
+      clock_gettime(CLOCK_MONOTONIC, &btif_hf_cb[0].call_end_timestamp);
+    }
+    BTA_AgResult(BTA_AG_HANDLE_ALL, BTA_AG_END_CALL_RES, NULL);
+    hf_idx = BTIF_HF_INVALID_IDX;
+
+    /* if held call was present, reset that as well */
+    if (btif_hf_cb[idx].num_held) send_indicator_update(BTA_AG_IND_CALLHELD, 0);
+
+    goto update_call_states;
+  }
+
+  /* active state can change when:
+  ** 1. an outgoing/incoming call was answered
+  ** 2. an held was resumed
+  ** 3. without callsetup notifications, call became active
+  ** (3) can happen if call is active and a headset connects to us
+  **
+  ** In the case of (3), we will have to notify the stack of an active
+  ** call, instead of sending an indicator update. This will also
+  ** force the SCO to be setup. Handle this special case here prior to
+  ** call setup handling
+  */
+  if (((num_active + num_held) > 0) && (btif_hf_cb[idx].num_active == 0) &&
+      (btif_hf_cb[idx].num_held == 0) &&
+      (btif_hf_cb[idx].call_setup_state == BTHF_CALL_STATE_IDLE)) {
+    BTIF_TRACE_DEBUG(
+        "%s: Active/Held call notification received without call setup update",
+        __func__);
+
+    memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+    ag_res.audio_handle = BTA_AG_HANDLE_SCO_NO_CHANGE;
+    /* Addition call setup with the Active call
+    ** CIND response should have been updated.
+    ** just open SCO conenction.
+    */
+    if (call_setup_state != BTHF_CALL_STATE_IDLE)
+      res = BTA_AG_MULTI_CALL_RES;
+    else
+      res = BTA_AG_OUT_CALL_CONN_RES;
+    BTA_AgResult(BTA_AG_HANDLE_ALL, res, &ag_res);
+    activeCallUpdated = true;
+  }
+
+  /* Ringing call changed? */
+  if (call_setup_state != btif_hf_cb[idx].call_setup_state) {
+    BTIF_TRACE_DEBUG("%s: Call setup states changed. old: %s new: %s", __func__,
+                     dump_hf_call_state(btif_hf_cb[idx].call_setup_state),
+                     dump_hf_call_state(call_setup_state));
+    memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+
+    switch (call_setup_state) {
+      case BTHF_CALL_STATE_IDLE: {
+        switch (btif_hf_cb[idx].call_setup_state) {
+          case BTHF_CALL_STATE_INCOMING:
+            if (num_active > btif_hf_cb[idx].num_active) {
+              res = BTA_AG_IN_CALL_CONN_RES;
+              ag_res.audio_handle = btif_hf_cb[idx].handle;
+            } else if (num_held > btif_hf_cb[idx].num_held)
+              res = BTA_AG_IN_CALL_HELD_RES;
+            else
+              res = BTA_AG_CALL_CANCEL_RES;
+            break;
+          case BTHF_CALL_STATE_DIALING:
+          case BTHF_CALL_STATE_ALERTING:
+            if (num_active > btif_hf_cb[idx].num_active) {
+              ag_res.audio_handle = BTA_AG_HANDLE_SCO_NO_CHANGE;
+              res = BTA_AG_OUT_CALL_CONN_RES;
+            } else
+              res = BTA_AG_CALL_CANCEL_RES;
+            break;
+          default:
+            BTIF_TRACE_ERROR("%s: Incorrect Call setup state transition",
+                             __func__);
+            status = BT_STATUS_PARM_INVALID;
+            break;
+        }
+      } break;
+
+      case BTHF_CALL_STATE_INCOMING:
+        if (num_active || num_held)
+          res = BTA_AG_CALL_WAIT_RES;
+        else
+          res = BTA_AG_IN_CALL_RES;
+        if (number) {
+          int xx = 0;
+          if ((type == BTHF_CALL_ADDRTYPE_INTERNATIONAL) && (*number != '+'))
+            xx = snprintf(ag_res.str, sizeof(ag_res.str), "\"+%s\"", number);
+          else
+            xx = snprintf(ag_res.str, sizeof(ag_res.str), "\"%s\"", number);
+          ag_res.num = type;
+
+          if (res == BTA_AG_CALL_WAIT_RES)
+            snprintf(&ag_res.str[xx], sizeof(ag_res.str) - xx, ",%d", type);
+        }
+        break;
+      case BTHF_CALL_STATE_DIALING:
+        if (!(num_active + num_held))
+          ag_res.audio_handle = btif_hf_cb[idx].handle;
+        res = BTA_AG_OUT_CALL_ORIG_RES;
+        break;
+      case BTHF_CALL_STATE_ALERTING:
+        /* if we went from idle->alert, force SCO setup here. dialing usually
+         * triggers it */
+        if ((btif_hf_cb[idx].call_setup_state == BTHF_CALL_STATE_IDLE) &&
+            !(num_active + num_held))
+          ag_res.audio_handle = btif_hf_cb[idx].handle;
+        res = BTA_AG_OUT_CALL_ALERT_RES;
+        break;
+      default:
+        BTIF_TRACE_ERROR("%s: Incorrect new ringing call state", __func__);
+        status = BT_STATUS_PARM_INVALID;
+        break;
+    }
+    BTIF_TRACE_DEBUG("%s: Call setup state changed. res=%d, audio_handle=%d",
+                     __func__, res, ag_res.audio_handle);
+
+    if (res) BTA_AgResult(BTA_AG_HANDLE_ALL, res, &ag_res);
+
+    /* if call setup is idle, we have already updated call indicator, jump out
+     */
+    if (call_setup_state == BTHF_CALL_STATE_IDLE) {
+      /* check & update callheld */
+      if ((num_held > 0) && (num_active > 0))
+        send_indicator_update(BTA_AG_IND_CALLHELD, 1);
+      goto update_call_states;
+    }
+  }
+
+  memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+
+  /* per the errata 2043, call=1 implies atleast one call is in progress
+  *(active/held)
+  ** https://www.bluetooth.org/errata/errata_view.cfm?errata_id=2043
+  ** Handle call indicator change
+  **/
+  if (!activeCallUpdated &&
+      ((num_active + num_held) !=
+       (btif_hf_cb[idx].num_active + btif_hf_cb[idx].num_held))) {
+    BTIF_TRACE_DEBUG("%s: Active call states changed. old: %d new: %d",
+                     __func__, btif_hf_cb[idx].num_active, num_active);
+    send_indicator_update(BTA_AG_IND_CALL,
+                          ((num_active + num_held) > 0) ? 1 : 0);
+  }
+
+  /* Held Changed? */
+  if (num_held != btif_hf_cb[idx].num_held ||
+      ((num_active == 0) && ((num_held + btif_hf_cb[idx].num_held) > 1))) {
+    BTIF_TRACE_DEBUG("%s: Held call states changed. old: %d new: %d", __func__,
+                     btif_hf_cb[idx].num_held, num_held);
+    send_indicator_update(BTA_AG_IND_CALLHELD,
+                          ((num_held == 0) ? 0 : ((num_active == 0) ? 2 : 1)));
+  }
+
+  /* Calls Swapped? */
+  if ((call_setup_state == btif_hf_cb[idx].call_setup_state) &&
+      (num_active && num_held) && (num_active == btif_hf_cb[idx].num_active) &&
+      (num_held == btif_hf_cb[idx].num_held)) {
+    BTIF_TRACE_DEBUG("%s: Calls swapped", __func__);
+    send_indicator_update(BTA_AG_IND_CALLHELD, 1);
+  }
+
+update_call_states:
+  for (i = 0; i < btif_max_hf_clients; i++) {
+    if (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED) {
+      btif_hf_cb[i].num_active = num_active;
+      btif_hf_cb[i].num_held = num_held;
+      btif_hf_cb[i].call_setup_state = call_setup_state;
+    }
+  }
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hf_is_call_idle
+ *
+ * Description      returns true if no call is in progress
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bool btif_hf_is_call_idle(void) {
+  if (bt_hf_callbacks == NULL) return true;
+
+  for (int i = 0; i < btif_max_hf_clients; ++i) {
+    if ((btif_hf_cb[i].call_setup_state != BTHF_CALL_STATE_IDLE) ||
+        ((btif_hf_cb[i].num_held + btif_hf_cb[i].num_active) > 0))
+      return false;
+  }
+
+  return true;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hf_call_terminated_recently
+ *
+ * Description      Checks if a call has been terminated
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+bool btif_hf_call_terminated_recently() {
+  struct timespec now;
+
+  clock_gettime(CLOCK_MONOTONIC, &now);
+  if (now.tv_sec <
+      btif_hf_cb[0].call_end_timestamp.tv_sec + BTIF_HF_CALL_END_TIMEOUT) {
+    return true;
+  } else {
+    btif_hf_cb[0].call_end_timestamp.tv_sec = 0;
+    return false;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         cleanup
+ *
+ * Description      Closes the HF interface
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static void cleanup(void) {
+  BTIF_TRACE_EVENT("%s", __func__);
+
+  if (bt_hf_callbacks) {
+#if (defined(BTIF_HF_SERVICES) && (BTIF_HF_SERVICES & BTA_HFP_SERVICE_MASK))
+    btif_disable_service(BTA_HFP_SERVICE_ID);
+#else
+    btif_disable_service(BTA_HSP_SERVICE_ID);
+#endif
+    bt_hf_callbacks = NULL;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         configure_wbs
+ *
+ * Description      set to over-ride the current WBS configuration.
+ *                  It will not send codec setting cmd to the controller now.
+ *                  It just change the configure.
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t configure_wbs(bt_bdaddr_t* bd_addr,
+                                 bthf_wbs_config_t config) {
+  CHECK_BTHF_INIT();
+
+  int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+  if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+    BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+    return BT_STATUS_FAIL;
+  }
+
+  BTIF_TRACE_EVENT("%s config is %d", __func__, config);
+  if (config == BTHF_WBS_YES)
+    BTA_AgSetCodec(btif_hf_cb[idx].handle, BTA_AG_CODEC_MSBC);
+  else if (config == BTHF_WBS_NO)
+    BTA_AgSetCodec(btif_hf_cb[idx].handle, BTA_AG_CODEC_CVSD);
+  else
+    BTA_AgSetCodec(btif_hf_cb[idx].handle, BTA_AG_CODEC_NONE);
+
+  return BT_STATUS_SUCCESS;
+}
+
+static const bthf_interface_t bthfInterface = {
+    sizeof(bthfInterface),
+    init,
+    connect,
+    disconnect,
+    connect_audio,
+    disconnect_audio,
+    start_voice_recognition,
+    stop_voice_recognition,
+    volume_control,
+    device_status_notification,
+    cops_response,
+    cind_response,
+    formatted_at_response,
+    at_response,
+    clcc_response,
+    phone_state_change,
+    cleanup,
+    configure_wbs,
+    bind_response,
+};
+
+/*******************************************************************************
+ *
+ * Function         btif_hf_execute_service
+ *
+ * Description      Initializes/Shuts down the service
+ *
+ * Returns          BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_hf_execute_service(bool b_enable) {
+  const char* p_service_names[] = BTIF_HF_SERVICE_NAMES;
+  int i;
+  if (b_enable) {
+    /* Enable and register with BTA-AG */
+    BTA_AgEnable(BTA_AG_PARSE, bte_hf_evt);
+    for (i = 0; i < btif_max_hf_clients; i++) {
+      BTA_AgRegister(BTIF_HF_SERVICES, BTIF_HF_SECURITY, BTIF_HF_FEATURES,
+                     p_service_names, bthf_hf_id[i]);
+    }
+  } else {
+    /* De-register AG */
+    for (i = 0; i < btif_max_hf_clients; i++) {
+      BTA_AgDeregister(btif_hf_cb[i].handle);
+    }
+    /* Disable AG */
+    BTA_AgDisable();
+  }
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hf_get_interface
+ *
+ * Description      Get the hf callback interface
+ *
+ * Returns          bthf_interface_t
+ *
+ ******************************************************************************/
+const bthf_interface_t* btif_hf_get_interface() {
+  BTIF_TRACE_EVENT("%s", __func__);
+  return &bthfInterface;
+}
diff --git a/bt/btif/src/btif_hf_client.cc b/bt/btif/src/btif_hf_client.cc
new file mode 100644
index 0000000..f3f32d7
--- /dev/null
+++ b/bt/btif/src/btif_hf_client.cc
@@ -0,0 +1,971 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ *  Filename:      btif_hf_client.c
+ *
+ *  Description:   Handsfree Profile (HF role) Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+
+#define LOG_TAG "bt_btif_hfc"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hf_client.h>
+
+#include "bt_utils.h"
+#include "bta_hf_client_api.h"
+#include "btcore/include/bdaddr.h"
+#include "btif_common.h"
+#include "btif_profile_queue.h"
+#include "btif_util.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+
+/************************************************************************************
+ *  Constants & Macros
+ ***********************************************************************************/
+
+#ifndef BTIF_HF_CLIENT_SERVICE_NAME
+#define BTIF_HF_CLIENT_SERVICE_NAME ("Handsfree")
+#endif
+
+#ifndef BTIF_HF_CLIENT_SECURITY
+#define BTIF_HF_CLIENT_SECURITY (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
+#endif
+
+#ifndef BTIF_HF_CLIENT_FEATURES
+#define BTIF_HF_CLIENT_FEATURES                                                \
+  (BTA_HF_CLIENT_FEAT_ECNR | BTA_HF_CLIENT_FEAT_3WAY |                         \
+   BTA_HF_CLIENT_FEAT_CLI | BTA_HF_CLIENT_FEAT_VREC | BTA_HF_CLIENT_FEAT_VOL | \
+   BTA_HF_CLIENT_FEAT_ECS | BTA_HF_CLIENT_FEAT_ECC | BTA_HF_CLIENT_FEAT_CODEC)
+#endif
+
+/************************************************************************************
+ *  Local type definitions
+ ***********************************************************************************/
+
+/************************************************************************************
+ *  Static variables
+ ***********************************************************************************/
+static bthf_client_callbacks_t* bt_hf_client_callbacks = NULL;
+static uint32_t btif_hf_client_features = 0;
+
+char btif_hf_client_version[PROPERTY_VALUE_MAX];
+
+#define CHECK_BTHF_CLIENT_INIT()                                        \
+  do {                                                                  \
+    if (bt_hf_client_callbacks == NULL) {                               \
+      BTIF_TRACE_WARNING("BTHF CLIENT: %s: not initialized", __func__); \
+      return BT_STATUS_NOT_READY;                                       \
+    } else {                                                            \
+      BTIF_TRACE_EVENT("BTHF CLIENT: %s", __func__);                    \
+    }                                                                   \
+  } while (0)
+
+#define CHECK_BTHF_CLIENT_SLC_CONNECTED()                                    \
+  do {                                                                       \
+    if (bt_hf_client_callbacks == NULL) {                                    \
+      BTIF_TRACE_WARNING("BTHF CLIENT: %s: not initialized", __func__);      \
+      return BT_STATUS_NOT_READY;                                            \
+    } else if (btif_hf_client_cb.state !=                                    \
+               BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED) {                 \
+      BTIF_TRACE_WARNING("BTHF CLIENT: %s: SLC connection not up. state=%s", \
+                         __func__,                                           \
+                         dump_hf_conn_state(btif_hf_client_cb.state));       \
+      return BT_STATUS_NOT_READY;                                            \
+    } else {                                                                 \
+      BTIF_TRACE_EVENT("BTHF CLIENT: %s", __func__);                         \
+    }                                                                        \
+  } while (0)
+
+/* BTIF-HF control block to map bdaddr to BTA handle */
+typedef struct {
+  uint16_t handle;
+  bt_bdaddr_t connected_bda;
+  bthf_client_connection_state_t state;
+  bthf_client_vr_state_t vr_state;
+  tBTA_HF_CLIENT_PEER_FEAT peer_feat;
+  tBTA_HF_CLIENT_CHLD_FEAT chld_feat;
+} btif_hf_client_cb_t;
+
+static btif_hf_client_cb_t btif_hf_client_cb;
+
+/************************************************************************************
+ *  Static functions
+ ***********************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function        btif_in_hf_client_generic_evt
+ *
+ * Description     Processes generic events to be sent to JNI that are not
+ *                 triggered from the BTA.
+ *                 Always runs in BTIF context
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_in_hf_client_generic_evt(uint16_t event,
+                                          UNUSED_ATTR char *p_param) {
+  BTIF_TRACE_EVENT("%s: event=%d", __func__, event);
+  switch (event) {
+    case BTIF_HF_CLIENT_CB_AUDIO_CONNECTING: {
+      HAL_CBACK(bt_hf_client_callbacks, audio_state_cb,
+                (bthf_client_audio_state_t)BTHF_AUDIO_STATE_CONNECTING,
+                &btif_hf_client_cb.connected_bda);
+    } break;
+    default: {
+      BTIF_TRACE_WARNING("%s : Unknown event 0x%x", __func__, event);
+    } break;
+  }
+}
+
+/************************************************************************************
+ *  Externs
+ ***********************************************************************************/
+
+/************************************************************************************
+ *  Functions
+ ***********************************************************************************/
+
+static void clear_state(void) {
+  memset(&btif_hf_client_cb, 0, sizeof(btif_hf_client_cb_t));
+}
+
+static bool is_connected(bt_bdaddr_t* bd_addr) {
+  if (((btif_hf_client_cb.state == BTHF_CLIENT_CONNECTION_STATE_CONNECTED) ||
+       (btif_hf_client_cb.state ==
+        BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED)) &&
+      ((bd_addr == NULL) ||
+       (bdcmp(bd_addr->address, btif_hf_client_cb.connected_bda.address) == 0)))
+    return true;
+  return false;
+}
+
+/*****************************************************************************
+ *   Section name (Group of functions)
+ ****************************************************************************/
+
+/*****************************************************************************
+ *
+ *   btif hf api functions (no context switch)
+ *
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         btif_hf_client_init
+ *
+ * Description     initializes the hf interface
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t init(bthf_client_callbacks_t* callbacks) {
+  BTIF_TRACE_EVENT("%s", __func__);
+
+  bt_hf_client_callbacks = callbacks;
+
+  btif_enable_service(BTA_HFP_HS_SERVICE_ID);
+
+  clear_state();
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         connect
+ *
+ * Description     connect to audio gateway
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t connect_int(bt_bdaddr_t* bd_addr, uint16_t uuid) {
+  if (is_connected(bd_addr)) return BT_STATUS_BUSY;
+
+  btif_hf_client_cb.state = BTHF_CLIENT_CONNECTION_STATE_CONNECTING;
+  bdcpy(btif_hf_client_cb.connected_bda.address, bd_addr->address);
+
+  BTA_HfClientOpen(btif_hf_client_cb.handle,
+                   btif_hf_client_cb.connected_bda.address,
+                   BTIF_HF_CLIENT_SECURITY);
+
+  return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t connect(bt_bdaddr_t* bd_addr) {
+  BTIF_TRACE_EVENT("HFP Client version is  %s", btif_hf_client_version);
+  CHECK_BTHF_CLIENT_INIT();
+  return btif_queue_connect(UUID_SERVCLASS_HF_HANDSFREE, bd_addr, connect_int);
+}
+
+/*******************************************************************************
+ *
+ * Function         disconnect
+ *
+ * Description      disconnect from audio gateway
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t disconnect(bt_bdaddr_t* bd_addr) {
+  CHECK_BTHF_CLIENT_INIT();
+
+  if (is_connected(bd_addr)) {
+    BTA_HfClientClose(btif_hf_client_cb.handle);
+    return BT_STATUS_SUCCESS;
+  }
+
+  return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         connect_audio
+ *
+ * Description     create an audio connection
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t connect_audio(bt_bdaddr_t* bd_addr) {
+  CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+  if (is_connected(bd_addr)) {
+    if ((BTIF_HF_CLIENT_FEATURES & BTA_HF_CLIENT_FEAT_CODEC) &&
+        (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_CODEC)) {
+      BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BCC, 0,
+                         0, NULL);
+    } else {
+      BTA_HfClientAudioOpen(btif_hf_client_cb.handle);
+    }
+
+    /* Inform the application that the audio connection has been initiated
+     * successfully */
+    btif_transfer_context(btif_in_hf_client_generic_evt,
+                          BTIF_HF_CLIENT_CB_AUDIO_CONNECTING, (char*)bd_addr,
+                          sizeof(bt_bdaddr_t), NULL);
+    return BT_STATUS_SUCCESS;
+  }
+
+  return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         disconnect_audio
+ *
+ * Description      close the audio connection
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t disconnect_audio(bt_bdaddr_t* bd_addr) {
+  CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+  if (is_connected(bd_addr)) {
+    BTA_HfClientAudioClose(btif_hf_client_cb.handle);
+    return BT_STATUS_SUCCESS;
+  }
+
+  return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         start_voice_recognition
+ *
+ * Description      start voice recognition
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t start_voice_recognition() {
+  CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+  if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_VREC) {
+    BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BVRA, 1,
+                       0, NULL);
+
+    return BT_STATUS_SUCCESS;
+  }
+
+  return BT_STATUS_UNSUPPORTED;
+}
+
+/*******************************************************************************
+ *
+ * Function         stop_voice_recognition
+ *
+ * Description      stop voice recognition
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t stop_voice_recognition() {
+  CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+  if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_VREC) {
+    BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BVRA, 0,
+                       0, NULL);
+
+    return BT_STATUS_SUCCESS;
+  }
+
+  return BT_STATUS_UNSUPPORTED;
+}
+
+/*******************************************************************************
+ *
+ * Function         volume_control
+ *
+ * Description      volume control
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t volume_control(bthf_client_volume_type_t type, int volume) {
+  CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+  switch (type) {
+    case BTHF_CLIENT_VOLUME_TYPE_SPK:
+      BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_VGS,
+                         volume, 0, NULL);
+      break;
+    case BTHF_CLIENT_VOLUME_TYPE_MIC:
+      BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_VGM,
+                         volume, 0, NULL);
+      break;
+    default:
+      return BT_STATUS_UNSUPPORTED;
+  }
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         dial
+ *
+ * Description      place a call
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t dial(const char* number) {
+  CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+  if (number) {
+    BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_ATD, 0, 0,
+                       number);
+  } else {
+    BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BLDN, 0,
+                       0, NULL);
+  }
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         dial_memory
+ *
+ * Description      place a call with number specified by location (speed dial)
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t dial_memory(int location) {
+  CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+  BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_ATD,
+                     location, 0, NULL);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         handle_call_action
+ *
+ * Description      handle specified call related action
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t handle_call_action(bthf_client_call_action_t action,
+                                      int idx) {
+  CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+  switch (action) {
+    case BTHF_CLIENT_CALL_ACTION_CHLD_0:
+      if (btif_hf_client_cb.chld_feat & BTA_HF_CLIENT_CHLD_REL) {
+        BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD,
+                           0, 0, NULL);
+        break;
+      }
+      return BT_STATUS_UNSUPPORTED;
+    case BTHF_CLIENT_CALL_ACTION_CHLD_1:
+      // CHLD 1 is mandatory for 3 way calling
+      if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_3WAY) {
+        BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD,
+                           1, 0, NULL);
+        break;
+      }
+      return BT_STATUS_UNSUPPORTED;
+    case BTHF_CLIENT_CALL_ACTION_CHLD_2:
+      // CHLD 2 is mandatory for 3 way calling
+      if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_3WAY) {
+        BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD,
+                           2, 0, NULL);
+        break;
+      }
+      return BT_STATUS_UNSUPPORTED;
+    case BTHF_CLIENT_CALL_ACTION_CHLD_3:
+      if (btif_hf_client_cb.chld_feat & BTA_HF_CLIENT_CHLD_MERGE) {
+        BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD,
+                           3, 0, NULL);
+        break;
+      }
+      return BT_STATUS_UNSUPPORTED;
+    case BTHF_CLIENT_CALL_ACTION_CHLD_4:
+      if (btif_hf_client_cb.chld_feat & BTA_HF_CLIENT_CHLD_MERGE_DETACH) {
+        BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD,
+                           4, 0, NULL);
+        break;
+      }
+      return BT_STATUS_UNSUPPORTED;
+    case BTHF_CLIENT_CALL_ACTION_CHLD_1x:
+      if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_ECC) {
+        if (idx < 1) {
+          return BT_STATUS_FAIL;
+        }
+        BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD,
+                           1, idx, NULL);
+        break;
+      }
+      return BT_STATUS_UNSUPPORTED;
+    case BTHF_CLIENT_CALL_ACTION_CHLD_2x:
+      if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_ECC) {
+        if (idx < 1) {
+          return BT_STATUS_FAIL;
+        }
+        BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD,
+                           2, idx, NULL);
+        break;
+      }
+      return BT_STATUS_UNSUPPORTED;
+    case BTHF_CLIENT_CALL_ACTION_ATA:
+      BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_ATA, 0,
+                         0, NULL);
+      break;
+    case BTHF_CLIENT_CALL_ACTION_CHUP:
+      BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHUP, 0,
+                         0, NULL);
+      break;
+    case BTHF_CLIENT_CALL_ACTION_BTRH_0:
+      BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BTRH, 0,
+                         0, NULL);
+      break;
+    case BTHF_CLIENT_CALL_ACTION_BTRH_1:
+      BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BTRH, 1,
+                         0, NULL);
+      break;
+    case BTHF_CLIENT_CALL_ACTION_BTRH_2:
+      BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BTRH, 2,
+                         0, NULL);
+      break;
+    default:
+      return BT_STATUS_FAIL;
+  }
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         query_current_calls
+ *
+ * Description      query list of current calls
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t query_current_calls(void) {
+  CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+  if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_ECS) {
+    BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CLCC, 0,
+                       0, NULL);
+
+    return BT_STATUS_SUCCESS;
+  }
+
+  return BT_STATUS_UNSUPPORTED;
+}
+
+/*******************************************************************************
+ *
+ * Function         query_current_operator_name
+ *
+ * Description      query current selected operator name
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t query_current_operator_name(void) {
+  CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+  BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_COPS, 0, 0,
+                     NULL);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         retieve_subscriber_info
+ *
+ * Description      retrieve subscriber number information
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t retrieve_subscriber_info(void) {
+  CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+  BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CNUM, 0, 0,
+                     NULL);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         send_dtmf
+ *
+ * Description      send dtmf
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t send_dtmf(char code) {
+  CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+  BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_VTS, code,
+                     0, NULL);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         request_last_voice_tag_number
+ *
+ * Description      Request number from AG for VR purposes
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t request_last_voice_tag_number(void) {
+  CHECK_BTHF_CLIENT_SLC_CONNECTED();
+
+  if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_VTAG) {
+    BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BINP, 1,
+                       0, NULL);
+
+    return BT_STATUS_SUCCESS;
+  }
+
+  return BT_STATUS_UNSUPPORTED;
+}
+
+/*******************************************************************************
+ *
+ * Function         cleanup
+ *
+ * Description      Closes the HF interface
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static void cleanup(void) {
+  BTIF_TRACE_EVENT("%s", __func__);
+
+  if (bt_hf_client_callbacks) {
+    btif_disable_service(BTA_HFP_HS_SERVICE_ID);
+    bt_hf_client_callbacks = NULL;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         send_at_cmd
+ *
+ * Description      Send requested AT command to rempte device.
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t send_at_cmd(int cmd, int val1, int val2, const char* arg) {
+  CHECK_BTHF_CLIENT_SLC_CONNECTED();
+  BTIF_TRACE_EVENT("%s Cmd %d val1 %d val2 %d arg %s", __func__, cmd, val1,
+                   val2, (arg != NULL) ? arg : "<null>");
+  BTA_HfClientSendAT(btif_hf_client_cb.handle, cmd, val1, val2, arg);
+
+  return BT_STATUS_SUCCESS;
+}
+
+static const bthf_client_interface_t bthfClientInterface = {
+    sizeof(bthf_client_interface_t),
+    .init = init,
+    .connect = connect,
+    .disconnect = disconnect,
+    .connect_audio = connect_audio,
+    .disconnect_audio = disconnect_audio,
+    .start_voice_recognition = start_voice_recognition,
+    .stop_voice_recognition = stop_voice_recognition,
+    .volume_control = volume_control,
+    .dial = dial,
+    .dial_memory = dial_memory,
+    .handle_call_action = handle_call_action,
+    .query_current_calls = query_current_calls,
+    .query_current_operator_name = query_current_operator_name,
+    .retrieve_subscriber_info = retrieve_subscriber_info,
+    .send_dtmf = send_dtmf,
+    .request_last_voice_tag_number = request_last_voice_tag_number,
+    .cleanup = cleanup,
+    .send_at_cmd = send_at_cmd,
+};
+
+static void process_ind_evt(tBTA_HF_CLIENT_IND* ind) {
+  switch (ind->type) {
+    case BTA_HF_CLIENT_IND_CALL:
+      HAL_CBACK(bt_hf_client_callbacks, call_cb,
+                (bthf_client_call_t)ind->value);
+      break;
+
+    case BTA_HF_CLIENT_IND_CALLSETUP:
+      HAL_CBACK(bt_hf_client_callbacks, callsetup_cb,
+                (bthf_client_callsetup_t)ind->value);
+      break;
+    case BTA_HF_CLIENT_IND_CALLHELD:
+      HAL_CBACK(bt_hf_client_callbacks, callheld_cb,
+                (bthf_client_callheld_t)ind->value);
+      break;
+
+    case BTA_HF_CLIENT_IND_SERVICE:
+      HAL_CBACK(bt_hf_client_callbacks, network_state_cb,
+                (bthf_client_network_state_t)ind->value);
+      break;
+
+    case BTA_HF_CLIENT_IND_SIGNAL:
+      HAL_CBACK(bt_hf_client_callbacks, network_signal_cb, ind->value);
+      break;
+
+    case BTA_HF_CLIENT_IND_ROAM:
+      HAL_CBACK(bt_hf_client_callbacks, network_roaming_cb,
+                (bthf_client_service_type_t)ind->value);
+      break;
+
+    case BTA_HF_CLIENT_IND_BATTCH:
+      HAL_CBACK(bt_hf_client_callbacks, battery_level_cb, ind->value);
+      break;
+
+    default:
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hf_client_upstreams_evt
+ *
+ * Description      Executes HF CLIENT UPSTREAMS events in btif context
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_hf_client_upstreams_evt(uint16_t event, char* p_param) {
+  tBTA_HF_CLIENT* p_data = (tBTA_HF_CLIENT*)p_param;
+  bdstr_t bdstr;
+
+  BTIF_TRACE_DEBUG("%s: event=%s (%u)", __func__, dump_hf_client_event(event),
+                   event);
+
+  switch (event) {
+    case BTA_HF_CLIENT_ENABLE_EVT:
+    case BTA_HF_CLIENT_DISABLE_EVT:
+      break;
+
+    case BTA_HF_CLIENT_REGISTER_EVT:
+      btif_hf_client_cb.handle = p_data->reg.handle;
+      break;
+
+    case BTA_HF_CLIENT_OPEN_EVT:
+      if (p_data->open.status == BTA_HF_CLIENT_SUCCESS) {
+        bdcpy(btif_hf_client_cb.connected_bda.address, p_data->open.bd_addr);
+        btif_hf_client_cb.state = BTHF_CLIENT_CONNECTION_STATE_CONNECTED;
+        btif_hf_client_cb.peer_feat = 0;
+        btif_hf_client_cb.chld_feat = 0;
+        // clear_phone_state();
+      } else if (btif_hf_client_cb.state ==
+                 BTHF_CLIENT_CONNECTION_STATE_CONNECTING) {
+        btif_hf_client_cb.state = BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED;
+      } else {
+        BTIF_TRACE_WARNING(
+            "%s: HF CLient open failed, but another device connected. "
+            "status=%d state=%d connected device=%s",
+            __func__, p_data->open.status, btif_hf_client_cb.state,
+            bdaddr_to_string(&btif_hf_client_cb.connected_bda, bdstr,
+                             sizeof(bdstr)));
+        break;
+      }
+
+      HAL_CBACK(bt_hf_client_callbacks, connection_state_cb,
+                btif_hf_client_cb.state, 0, 0,
+                &btif_hf_client_cb.connected_bda);
+
+      if (btif_hf_client_cb.state == BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED)
+        bdsetany(btif_hf_client_cb.connected_bda.address);
+
+      if (p_data->open.status != BTA_HF_CLIENT_SUCCESS) btif_queue_advance();
+      break;
+
+    case BTA_HF_CLIENT_CONN_EVT:
+      btif_hf_client_cb.peer_feat = p_data->conn.peer_feat;
+      btif_hf_client_cb.chld_feat = p_data->conn.chld_feat;
+      btif_hf_client_cb.state = BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED;
+
+      HAL_CBACK(bt_hf_client_callbacks, connection_state_cb,
+                btif_hf_client_cb.state, btif_hf_client_cb.peer_feat,
+                btif_hf_client_cb.chld_feat, &btif_hf_client_cb.connected_bda);
+
+      /* Inform the application about in-band ringtone */
+      if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_INBAND) {
+        HAL_CBACK(bt_hf_client_callbacks, in_band_ring_tone_cb,
+                  BTHF_CLIENT_IN_BAND_RINGTONE_PROVIDED);
+      }
+
+      btif_queue_advance();
+      break;
+
+    case BTA_HF_CLIENT_CLOSE_EVT:
+      btif_hf_client_cb.state = BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED;
+      HAL_CBACK(bt_hf_client_callbacks, connection_state_cb,
+                btif_hf_client_cb.state, 0, 0,
+                &btif_hf_client_cb.connected_bda);
+      bdsetany(btif_hf_client_cb.connected_bda.address);
+      btif_hf_client_cb.peer_feat = 0;
+      btif_hf_client_cb.chld_feat = 0;
+      btif_queue_advance();
+      break;
+
+    case BTA_HF_CLIENT_IND_EVT:
+      process_ind_evt(&p_data->ind);
+      break;
+
+    case BTA_HF_CLIENT_MIC_EVT:
+      HAL_CBACK(bt_hf_client_callbacks, volume_change_cb,
+                BTHF_CLIENT_VOLUME_TYPE_MIC, p_data->val.value);
+      break;
+
+    case BTA_HF_CLIENT_SPK_EVT:
+      HAL_CBACK(bt_hf_client_callbacks, volume_change_cb,
+                BTHF_CLIENT_VOLUME_TYPE_SPK, p_data->val.value);
+      break;
+
+    case BTA_HF_CLIENT_VOICE_REC_EVT:
+      HAL_CBACK(bt_hf_client_callbacks, vr_cmd_cb,
+                (bthf_client_vr_state_t)p_data->val.value);
+      break;
+
+    case BTA_HF_CLIENT_OPERATOR_NAME_EVT:
+      HAL_CBACK(bt_hf_client_callbacks, current_operator_cb,
+                p_data->operator_name.name);
+      break;
+
+    case BTA_HF_CLIENT_CLIP_EVT:
+      HAL_CBACK(bt_hf_client_callbacks, clip_cb, p_data->number.number);
+      break;
+
+    case BTA_HF_CLIENT_BINP_EVT:
+      HAL_CBACK(bt_hf_client_callbacks, last_voice_tag_number_callback,
+                p_data->number.number);
+      break;
+
+    case BTA_HF_CLIENT_CCWA_EVT:
+      HAL_CBACK(bt_hf_client_callbacks, call_waiting_cb, p_data->number.number);
+      break;
+
+    case BTA_HF_CLIENT_AT_RESULT_EVT:
+      HAL_CBACK(bt_hf_client_callbacks, cmd_complete_cb,
+                (bthf_client_cmd_complete_t)p_data->result.type,
+                p_data->result.cme);
+      break;
+
+    case BTA_HF_CLIENT_CLCC_EVT:
+      HAL_CBACK(bt_hf_client_callbacks, current_calls_cb, p_data->clcc.idx,
+                p_data->clcc.inc ? BTHF_CLIENT_CALL_DIRECTION_INCOMING
+                                 : BTHF_CLIENT_CALL_DIRECTION_OUTGOING,
+                (bthf_client_call_state_t)p_data->clcc.status,
+                p_data->clcc.mpty ? BTHF_CLIENT_CALL_MPTY_TYPE_MULTI
+                                  : BTHF_CLIENT_CALL_MPTY_TYPE_SINGLE,
+                p_data->clcc.number_present ? p_data->clcc.number : NULL);
+      break;
+
+    case BTA_HF_CLIENT_CNUM_EVT:
+      if (p_data->cnum.service == 4) {
+        HAL_CBACK(bt_hf_client_callbacks, subscriber_info_cb,
+                  p_data->cnum.number, BTHF_CLIENT_SERVICE_VOICE);
+      } else if (p_data->cnum.service == 5) {
+        HAL_CBACK(bt_hf_client_callbacks, subscriber_info_cb,
+                  p_data->cnum.number, BTHF_CLIENT_SERVICE_FAX);
+      } else {
+        HAL_CBACK(bt_hf_client_callbacks, subscriber_info_cb,
+                  p_data->cnum.number, BTHF_CLIENT_SERVICE_UNKNOWN);
+      }
+      break;
+
+    case BTA_HF_CLIENT_BTRH_EVT:
+      if (p_data->val.value <= BTRH_CLIENT_RESP_AND_HOLD_REJECT) {
+        HAL_CBACK(bt_hf_client_callbacks, resp_and_hold_cb,
+                  (bthf_client_resp_and_hold_t)p_data->val.value);
+      }
+      break;
+
+    case BTA_HF_CLIENT_BSIR_EVT:
+      if (p_data->val.value != 0) {
+        HAL_CBACK(bt_hf_client_callbacks, in_band_ring_tone_cb,
+                  BTHF_CLIENT_IN_BAND_RINGTONE_PROVIDED);
+      } else {
+        HAL_CBACK(bt_hf_client_callbacks, in_band_ring_tone_cb,
+                  BTHF_CLIENT_IN_BAND_RINGTONE_NOT_PROVIDED);
+      }
+      break;
+
+    case BTA_HF_CLIENT_AUDIO_OPEN_EVT:
+      HAL_CBACK(bt_hf_client_callbacks, audio_state_cb,
+                BTHF_CLIENT_AUDIO_STATE_CONNECTED,
+                &btif_hf_client_cb.connected_bda);
+      break;
+
+    case BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT:
+      HAL_CBACK(bt_hf_client_callbacks, audio_state_cb,
+                BTHF_CLIENT_AUDIO_STATE_CONNECTED_MSBC,
+                &btif_hf_client_cb.connected_bda);
+      break;
+
+    case BTA_HF_CLIENT_AUDIO_CLOSE_EVT:
+      HAL_CBACK(bt_hf_client_callbacks, audio_state_cb,
+                BTHF_CLIENT_AUDIO_STATE_DISCONNECTED,
+                &btif_hf_client_cb.connected_bda);
+      break;
+    case BTA_HF_CLIENT_RING_INDICATION:
+      HAL_CBACK(bt_hf_client_callbacks, ring_indication_cb);
+      break;
+    default:
+      BTIF_TRACE_WARNING("%s: Unhandled event: %d", __func__, event);
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bte_hf_client_evt
+ *
+ * Description      Switches context from BTE to BTIF for all HF Client events
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+
+static void bte_hf_client_evt(tBTA_HF_CLIENT_EVT event,
+                              tBTA_HF_CLIENT* p_data) {
+  bt_status_t status;
+
+  /* switch context to btif task context (copy full union size for convenience)
+   */
+  status = btif_transfer_context(btif_hf_client_upstreams_evt, (uint16_t)event,
+                                 (char*)p_data, sizeof(*p_data), NULL);
+
+  /* catch any failed context transfers */
+  ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hf_client_execute_service
+ *
+ * Description      Initializes/Shuts down the service
+ *
+ * Returns          BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_hf_client_execute_service(bool b_enable) {
+  BTIF_TRACE_EVENT("%s enable:%d", __func__, b_enable);
+
+  osi_property_get("ro.bluetooth.hfp.ver", btif_hf_client_version, "1.5");
+
+  if (b_enable) {
+    /* Enable and register with BTA-HFClient */
+    BTA_HfClientEnable(bte_hf_client_evt);
+    if (strcmp(btif_hf_client_version, "1.6") == 0) {
+      BTIF_TRACE_EVENT("Support Codec Nego. %d ", BTIF_HF_CLIENT_FEATURES);
+      BTA_HfClientRegister(BTIF_HF_CLIENT_SECURITY, BTIF_HF_CLIENT_FEATURES,
+                           BTIF_HF_CLIENT_SERVICE_NAME);
+    } else {
+      BTIF_TRACE_EVENT("No Codec Nego Supported");
+      btif_hf_client_features = BTIF_HF_CLIENT_FEATURES;
+      btif_hf_client_features =
+          btif_hf_client_features & (~BTA_HF_CLIENT_FEAT_CODEC);
+      BTIF_TRACE_EVENT("btif_hf_client_features is   %d",
+                       btif_hf_client_features);
+      BTA_HfClientRegister(BTIF_HF_CLIENT_SECURITY, btif_hf_client_features,
+                           BTIF_HF_CLIENT_SERVICE_NAME);
+    }
+
+  } else {
+    BTA_HfClientDeregister(btif_hf_client_cb.handle);
+    BTA_HfClientDisable();
+  }
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hf_get_interface
+ *
+ * Description      Get the hf callback interface
+ *
+ * Returns          bthf_interface_t
+ *
+ ******************************************************************************/
+const bthf_client_interface_t* btif_hf_client_get_interface(void) {
+  BTIF_TRACE_EVENT("%s", __func__);
+  return &bthfClientInterface;
+}
diff --git a/bt/btif/src/btif_hh.cc b/bt/btif/src/btif_hh.cc
new file mode 100644
index 0000000..a08da55
--- /dev/null
+++ b/bt/btif/src/btif_hh.cc
@@ -0,0 +1,1655 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ *  Filename:      btif_hh.c
+ *
+ *  Description:   HID Host Profile Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+
+#define LOG_TAG "bt_btif_hh"
+
+#include "btif_hh.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "btif_common.h"
+#include "btif_storage.h"
+#include "btif_util.h"
+#include "l2c_api.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#define BTIF_HH_APP_ID_MI 0x01
+#define BTIF_HH_APP_ID_KB 0x02
+
+#define COD_HID_KEYBOARD 0x0540
+#define COD_HID_POINTING 0x0580
+#define COD_HID_COMBO 0x05C0
+
+#define KEYSTATE_FILEPATH \
+  "/data/misc/bluedroid/bt_hh_ks"  // keep this in sync with HID host jni
+
+#define HID_REPORT_CAPSLOCK 0x39
+#define HID_REPORT_NUMLOCK 0x53
+#define HID_REPORT_SCROLLLOCK 0x47
+
+// For Apple Magic Mouse
+#define MAGICMOUSE_VENDOR_ID 0x05ac
+#define MAGICMOUSE_PRODUCT_ID 0x030d
+
+#define LOGITECH_KB_MX5500_VENDOR_ID 0x046D
+#define LOGITECH_KB_MX5500_PRODUCT_ID 0xB30B
+
+extern fixed_queue_t* btu_general_alarm_queue;
+extern const int BT_UID;
+extern const int BT_GID;
+static int btif_hh_keylockstates = 0;  // The current key state of each key
+
+#define BTIF_HH_ID_1 0
+#define BTIF_HH_DEV_DISCONNECTED 3
+
+#define BTIF_TIMEOUT_VUP_MS (3 * 1000)
+
+#ifndef BTUI_HH_SECURITY
+#define BTUI_HH_SECURITY (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
+#endif
+
+#ifndef BTUI_HH_MOUSE_SECURITY
+#define BTUI_HH_MOUSE_SECURITY (BTA_SEC_NONE)
+#endif
+
+/* HH request events */
+typedef enum {
+  BTIF_HH_CONNECT_REQ_EVT = 0,
+  BTIF_HH_DISCONNECT_REQ_EVT,
+  BTIF_HH_VUP_REQ_EVT
+} btif_hh_req_evt_t;
+
+/************************************************************************************
+ *  Constants & Macros
+ ***********************************************************************************/
+#define BTIF_HH_SERVICES (BTA_HID_SERVICE_MASK)
+
+/************************************************************************************
+ *  Local type definitions
+ ***********************************************************************************/
+
+typedef struct hid_kb_list {
+  uint16_t product_id;
+  uint16_t version_id;
+  const char* kb_name;
+} tHID_KB_LIST;
+
+/************************************************************************************
+ *  Static variables
+ ***********************************************************************************/
+btif_hh_cb_t btif_hh_cb;
+
+static bthh_callbacks_t* bt_hh_callbacks = NULL;
+
+/* List of HID keyboards for which the NUMLOCK state needs to be
+ * turned ON by default. Add devices to this list to apply the
+ * NUMLOCK state toggle on fpr first connect.*/
+static tHID_KB_LIST hid_kb_numlock_on_list[] = {{LOGITECH_KB_MX5500_PRODUCT_ID,
+                                                 LOGITECH_KB_MX5500_VENDOR_ID,
+                                                 "Logitech MX5500 Keyboard"}};
+
+#define CHECK_BTHH_INIT()                                             \
+  do {                                                                \
+    if (bt_hh_callbacks == NULL) {                                    \
+      BTIF_TRACE_WARNING("BTHH: %s: BTHH not initialized", __func__); \
+      return BT_STATUS_NOT_READY;                                     \
+    } else {                                                          \
+      BTIF_TRACE_EVENT("BTHH: %s", __func__);                         \
+    }                                                                 \
+  } while (0)
+
+/************************************************************************************
+ *  Static functions
+ ***********************************************************************************/
+
+/************************************************************************************
+ *  Externs
+ ***********************************************************************************/
+extern void bta_hh_co_destroy(int fd);
+extern void bta_hh_co_write(int fd, uint8_t* rpt, uint16_t len);
+extern bt_status_t btif_dm_remove_bond(const bt_bdaddr_t* bd_addr);
+extern void bta_hh_co_send_hid_info(btif_hh_device_t* p_dev,
+                                    const char* dev_name, uint16_t vendor_id,
+                                    uint16_t product_id, uint16_t version,
+                                    uint8_t ctry_code, int dscp_len,
+                                    uint8_t* p_dscp);
+extern bool check_cod(const bt_bdaddr_t* remote_bdaddr, uint32_t cod);
+extern void btif_dm_cb_remove_bond(bt_bdaddr_t* bd_addr);
+extern bool check_cod_hid(const bt_bdaddr_t* remote_bdaddr);
+extern int scru_ascii_2_hex(char* p_ascii, int len, uint8_t* p_hex);
+extern void btif_dm_hh_open_failed(bt_bdaddr_t* bdaddr);
+
+/*****************************************************************************
+ *  Local Function prototypes
+ ****************************************************************************/
+static void set_keylockstate(int keymask, bool isSet);
+static void toggle_os_keylockstates(int fd, int changedkeystates);
+static void sync_lockstate_on_connect(btif_hh_device_t* p_dev);
+// static void hh_update_keyboard_lockstates(btif_hh_device_t *p_dev);
+void btif_hh_timer_timeout(void* data);
+
+/************************************************************************************
+ *  Functions
+ ***********************************************************************************/
+
+static int get_keylockstates() { return btif_hh_keylockstates; }
+
+static void set_keylockstate(int keymask, bool isSet) {
+  if (isSet) btif_hh_keylockstates |= keymask;
+}
+
+/*******************************************************************************
+ *
+ * Function         toggle_os_keylockstates
+ *
+ * Description      Function to toggle the keyboard lock states managed by the
+ linux.
+ *                  This function is used in by two call paths
+ *                  (1) if the lock state change occurred from an onscreen
+ keyboard,
+ *                  this function is called to update the lock state maintained
+                    for the HID keyboard(s)
+ *                  (2) if a HID keyboard is disconnected and reconnected,
+ *                  this function is called to update the lock state maintained
+                    for the HID keyboard(s)
+ * Returns          void
+ ******************************************************************************/
+
+static void toggle_os_keylockstates(int fd, int changedlockstates) {
+  BTIF_TRACE_EVENT("%s: fd = %d, changedlockstates = 0x%x", __func__, fd,
+                   changedlockstates);
+  uint8_t hidreport[9];
+  int reportIndex;
+  memset(hidreport, 0, 9);
+  hidreport[0] = 1;
+  reportIndex = 4;
+
+  if (changedlockstates & BTIF_HH_KEYSTATE_MASK_CAPSLOCK) {
+    BTIF_TRACE_DEBUG("%s Setting CAPSLOCK", __func__);
+    hidreport[reportIndex++] = (uint8_t)HID_REPORT_CAPSLOCK;
+  }
+
+  if (changedlockstates & BTIF_HH_KEYSTATE_MASK_NUMLOCK) {
+    BTIF_TRACE_DEBUG("%s Setting NUMLOCK", __func__);
+    hidreport[reportIndex++] = (uint8_t)HID_REPORT_NUMLOCK;
+  }
+
+  if (changedlockstates & BTIF_HH_KEYSTATE_MASK_SCROLLLOCK) {
+    BTIF_TRACE_DEBUG("%s Setting SCROLLLOCK", __func__);
+    hidreport[reportIndex++] = (uint8_t)HID_REPORT_SCROLLLOCK;
+  }
+
+  BTIF_TRACE_DEBUG(
+      "Writing hidreport #1 to os: "
+      "%s:  %x %x %x",
+      __func__, hidreport[0], hidreport[1], hidreport[2]);
+  BTIF_TRACE_DEBUG("%s:  %x %x %x", __func__, hidreport[3], hidreport[4],
+                   hidreport[5]);
+  BTIF_TRACE_DEBUG("%s:  %x %x %x", __func__, hidreport[6], hidreport[7],
+                   hidreport[8]);
+  bta_hh_co_write(fd, hidreport, sizeof(hidreport));
+  usleep(200000);
+  memset(hidreport, 0, 9);
+  hidreport[0] = 1;
+  BTIF_TRACE_DEBUG(
+      "Writing hidreport #2 to os: "
+      "%s:  %x %x %x",
+      __func__, hidreport[0], hidreport[1], hidreport[2]);
+  BTIF_TRACE_DEBUG("%s:  %x %x %x", __func__, hidreport[3], hidreport[4],
+                   hidreport[5]);
+  BTIF_TRACE_DEBUG("%s:  %x %x %x ", __func__, hidreport[6], hidreport[7],
+                   hidreport[8]);
+  bta_hh_co_write(fd, hidreport, sizeof(hidreport));
+}
+
+/*******************************************************************************
+ *
+ * Function         create_pbuf
+ *
+ * Description      Helper function to create p_buf for send_data or set_report
+ *
+ ******************************************************************************/
+static BT_HDR* create_pbuf(uint16_t len, uint8_t* data) {
+  BT_HDR* p_buf = (BT_HDR*)osi_malloc(len + BTA_HH_MIN_OFFSET + sizeof(BT_HDR));
+  uint8_t* pbuf_data;
+
+  p_buf->len = len;
+  p_buf->offset = BTA_HH_MIN_OFFSET;
+
+  pbuf_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
+  memcpy(pbuf_data, data, len);
+
+  return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function         update_keyboard_lockstates
+ *
+ * Description      Sends a report to the keyboard to set the lock states of
+ *                  keys.
+ *
+ ******************************************************************************/
+static void update_keyboard_lockstates(btif_hh_device_t* p_dev) {
+  uint8_t len = 2; /* reportid + 1 byte report*/
+  BD_ADDR* bda;
+  BT_HDR* p_buf;
+  uint8_t data[] = {0x01, /* report id */
+                    static_cast<uint8_t>(btif_hh_keylockstates)}; /* keystate */
+
+  /* Set report for other keyboards */
+  BTIF_TRACE_EVENT("%s: setting report on dev_handle %d to 0x%x", __func__,
+                   p_dev->dev_handle, btif_hh_keylockstates);
+
+  /* Get SetReport buffer */
+  p_buf = create_pbuf(len, data);
+  if (p_buf != NULL) {
+    p_buf->layer_specific = BTA_HH_RPTT_OUTPUT;
+    bda = (BD_ADDR*)(&p_dev->bd_addr);
+    BTA_HhSendData(p_dev->dev_handle, *bda, p_buf);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         sync_lockstate_on_connect
+ *
+ * Description      Function to update the keyboard lock states managed by the
+ *                  OS when a HID keyboard is connected or disconnected and
+ *                  reconnected
+ *
+ * Returns          void
+ ******************************************************************************/
+static void sync_lockstate_on_connect(btif_hh_device_t* p_dev) {
+  int keylockstates;
+
+  BTIF_TRACE_EVENT(
+      "%s: Syncing keyboard lock states after "
+      "reconnect...",
+      __func__);
+  /*If the device is connected, update keyboard state */
+  update_keyboard_lockstates(p_dev);
+
+  /*Check if the lockstate of caps,scroll,num is set.
+   If so, send a report to the kernel
+  so the lockstate is in sync */
+  keylockstates = get_keylockstates();
+  if (keylockstates) {
+    BTIF_TRACE_DEBUG(
+        "%s: Sending hid report to kernel "
+        "indicating lock key state 0x%x",
+        __func__, keylockstates);
+    usleep(200000);
+    toggle_os_keylockstates(p_dev->fd, keylockstates);
+  } else {
+    BTIF_TRACE_DEBUG(
+        "%s: NOT sending hid report to kernel "
+        "indicating lock key state 0x%x",
+        __func__, keylockstates);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hh_find_connected_dev_by_handle
+ *
+ * Description      Return the connected device pointer of the specified device
+ *                  handle
+ *
+ * Returns          Device entry pointer in the device table
+ ******************************************************************************/
+btif_hh_device_t* btif_hh_find_connected_dev_by_handle(uint8_t handle) {
+  uint32_t i;
+  for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+    if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_CONNECTED &&
+        btif_hh_cb.devices[i].dev_handle == handle) {
+      return &btif_hh_cb.devices[i];
+    }
+  }
+  return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hh_find_dev_by_bda
+ *
+ * Description      Return the device pointer of the specified bt_bdaddr_t.
+ *
+ * Returns          Device entry pointer in the device table
+ ******************************************************************************/
+static btif_hh_device_t* btif_hh_find_dev_by_bda(bt_bdaddr_t* bd_addr) {
+  uint32_t i;
+  for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+    if (btif_hh_cb.devices[i].dev_status != BTHH_CONN_STATE_UNKNOWN &&
+        memcmp(&(btif_hh_cb.devices[i].bd_addr), bd_addr, BD_ADDR_LEN) == 0) {
+      return &btif_hh_cb.devices[i];
+    }
+  }
+  return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hh_find_connected_dev_by_bda
+ *
+ * Description      Return the connected device pointer of the specified
+ *                  bt_bdaddr_t.
+ *
+ * Returns          Device entry pointer in the device table
+ ******************************************************************************/
+static btif_hh_device_t* btif_hh_find_connected_dev_by_bda(
+    bt_bdaddr_t* bd_addr) {
+  uint32_t i;
+  for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+    if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_CONNECTED &&
+        memcmp(&(btif_hh_cb.devices[i].bd_addr), bd_addr, BD_ADDR_LEN) == 0) {
+      return &btif_hh_cb.devices[i];
+    }
+  }
+  return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hh_stop_vup_timer
+ *
+ * Description  stop vitual unplug timer
+ *
+ * Returns      void
+ ******************************************************************************/
+void btif_hh_stop_vup_timer(bt_bdaddr_t* bd_addr) {
+  btif_hh_device_t* p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+
+  if (p_dev != NULL) {
+    BTIF_TRACE_DEBUG("stop VUP timer");
+    alarm_free(p_dev->vup_timer);
+    p_dev->vup_timer = NULL;
+  }
+}
+/*******************************************************************************
+ *
+ * Function      btif_hh_start_vup_timer
+ *
+ * Description  start virtual unplug timer
+ *
+ * Returns      void
+ ******************************************************************************/
+void btif_hh_start_vup_timer(bt_bdaddr_t* bd_addr) {
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  btif_hh_device_t* p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+  assert(p_dev != NULL);
+
+  alarm_free(p_dev->vup_timer);
+  p_dev->vup_timer = alarm_new("btif_hh.vup_timer");
+  alarm_set_on_queue(p_dev->vup_timer, BTIF_TIMEOUT_VUP_MS,
+                     btif_hh_timer_timeout, p_dev, btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hh_add_added_dev
+ *
+ * Description      Add a new device to the added device list.
+ *
+ * Returns          true if add successfully, otherwise false.
+ ******************************************************************************/
+bool btif_hh_add_added_dev(bt_bdaddr_t bda, tBTA_HH_ATTR_MASK attr_mask) {
+  int i;
+  for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+    if (memcmp(&(btif_hh_cb.added_devices[i].bd_addr), &bda, BD_ADDR_LEN) ==
+        0) {
+      BTIF_TRACE_WARNING(" Device %02X:%02X:%02X:%02X:%02X:%02X already added",
+                         bda.address[0], bda.address[1], bda.address[2],
+                         bda.address[3], bda.address[4], bda.address[5]);
+      return false;
+    }
+  }
+  for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+    if (btif_hh_cb.added_devices[i].bd_addr.address[0] == 0 &&
+        btif_hh_cb.added_devices[i].bd_addr.address[1] == 0 &&
+        btif_hh_cb.added_devices[i].bd_addr.address[2] == 0 &&
+        btif_hh_cb.added_devices[i].bd_addr.address[3] == 0 &&
+        btif_hh_cb.added_devices[i].bd_addr.address[4] == 0 &&
+        btif_hh_cb.added_devices[i].bd_addr.address[5] == 0) {
+      BTIF_TRACE_WARNING(" Added device %02X:%02X:%02X:%02X:%02X:%02X",
+                         bda.address[0], bda.address[1], bda.address[2],
+                         bda.address[3], bda.address[4], bda.address[5]);
+      memcpy(&(btif_hh_cb.added_devices[i].bd_addr), &bda, BD_ADDR_LEN);
+      btif_hh_cb.added_devices[i].dev_handle = BTA_HH_INVALID_HANDLE;
+      btif_hh_cb.added_devices[i].attr_mask = attr_mask;
+      return true;
+    }
+  }
+
+  BTIF_TRACE_WARNING("%s: Error, out of space to add device", __func__);
+  return false;
+}
+
+/*******************************************************************************
+ **
+ ** Function         btif_hh_remove_device
+ **
+ ** Description      Remove an added device from the stack.
+ **
+ ** Returns          void
+ *******************************************************************************/
+void btif_hh_remove_device(bt_bdaddr_t bd_addr) {
+  int i;
+  btif_hh_device_t* p_dev;
+  btif_hh_added_device_t* p_added_dev;
+
+  LOG_INFO(LOG_TAG, "%s: bda = %02x:%02x:%02x:%02x:%02x:%02x", __func__,
+           bd_addr.address[0], bd_addr.address[1], bd_addr.address[2],
+           bd_addr.address[3], bd_addr.address[4], bd_addr.address[5]);
+
+  for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+    p_added_dev = &btif_hh_cb.added_devices[i];
+    if (memcmp(&(p_added_dev->bd_addr), &bd_addr, 6) == 0) {
+      BTA_HhRemoveDev(p_added_dev->dev_handle);
+      btif_storage_remove_hid_info(&(p_added_dev->bd_addr));
+      memset(&(p_added_dev->bd_addr), 0, 6);
+      p_added_dev->dev_handle = BTA_HH_INVALID_HANDLE;
+      break;
+    }
+  }
+
+  p_dev = btif_hh_find_dev_by_bda(&bd_addr);
+  if (p_dev == NULL) {
+    BTIF_TRACE_WARNING(
+        " Oops, can't find device [%02x:%02x:%02x:%02x:%02x:%02x]",
+        bd_addr.address[0], bd_addr.address[1], bd_addr.address[2],
+        bd_addr.address[3], bd_addr.address[4], bd_addr.address[5]);
+    return;
+  }
+
+  /* need to notify up-layer device is disconnected to avoid state out of sync
+   * with up-layer */
+  HAL_CBACK(bt_hh_callbacks, connection_state_cb, &(p_dev->bd_addr),
+            BTHH_CONN_STATE_DISCONNECTED);
+
+  p_dev->dev_status = BTHH_CONN_STATE_UNKNOWN;
+  p_dev->dev_handle = BTA_HH_INVALID_HANDLE;
+  p_dev->ready_for_data = false;
+
+  if (btif_hh_cb.device_num > 0) {
+    btif_hh_cb.device_num--;
+  } else {
+    BTIF_TRACE_WARNING("%s: device_num = 0", __func__);
+  }
+
+  p_dev->hh_keep_polling = 0;
+  p_dev->hh_poll_thread_id = -1;
+  BTIF_TRACE_DEBUG("%s: uhid fd = %d", __func__, p_dev->fd);
+  if (p_dev->fd >= 0) {
+    bta_hh_co_destroy(p_dev->fd);
+    p_dev->fd = -1;
+  }
+}
+
+bool btif_hh_copy_hid_info(tBTA_HH_DEV_DSCP_INFO* dest,
+                           tBTA_HH_DEV_DSCP_INFO* src) {
+  dest->descriptor.dl_len = 0;
+  if (src->descriptor.dl_len > 0) {
+    dest->descriptor.dsc_list = (uint8_t*)osi_malloc(src->descriptor.dl_len);
+  }
+  memcpy(dest->descriptor.dsc_list, src->descriptor.dsc_list,
+         src->descriptor.dl_len);
+  dest->descriptor.dl_len = src->descriptor.dl_len;
+  dest->vendor_id = src->vendor_id;
+  dest->product_id = src->product_id;
+  dest->version = src->version;
+  dest->ctry_code = src->ctry_code;
+  dest->ssr_max_latency = src->ssr_max_latency;
+  dest->ssr_min_tout = src->ssr_min_tout;
+  return true;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hh_virtual_unplug
+ *
+ * Description      Virtual unplug initiated from the BTIF thread context
+ *                  Special handling for HID mouse-
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+
+bt_status_t btif_hh_virtual_unplug(bt_bdaddr_t* bd_addr) {
+  BTIF_TRACE_DEBUG("%s", __func__);
+  btif_hh_device_t* p_dev;
+  char bd_str[18];
+  snprintf(bd_str, sizeof(bd_str), "%02X:%02X:%02X:%02X:%02X:%02X",
+           bd_addr->address[0], bd_addr->address[1], bd_addr->address[2],
+           bd_addr->address[3], bd_addr->address[4], bd_addr->address[5]);
+  p_dev = btif_hh_find_dev_by_bda(bd_addr);
+  if ((p_dev != NULL) && (p_dev->dev_status == BTHH_CONN_STATE_CONNECTED) &&
+      (p_dev->attr_mask & HID_VIRTUAL_CABLE)) {
+    BTIF_TRACE_DEBUG("%s Sending BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG", __func__);
+    /* start the timer */
+    btif_hh_start_vup_timer(bd_addr);
+    p_dev->local_vup = true;
+    BTA_HhSendCtrl(p_dev->dev_handle, BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG);
+    return BT_STATUS_SUCCESS;
+  } else {
+    BTIF_TRACE_ERROR("%s: Error, device %s not opened.", __func__, bd_str);
+    return BT_STATUS_FAIL;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hh_connect
+ *
+ * Description      connection initiated from the BTIF thread context
+ *
+ * Returns          int status
+ *
+ ******************************************************************************/
+
+bt_status_t btif_hh_connect(bt_bdaddr_t* bd_addr) {
+  btif_hh_device_t* dev;
+  btif_hh_added_device_t* added_dev = NULL;
+  char bda_str[20];
+  int i;
+  BD_ADDR* bda = (BD_ADDR*)bd_addr;
+  CHECK_BTHH_INIT();
+  dev = btif_hh_find_dev_by_bda(bd_addr);
+  BTIF_TRACE_DEBUG("Connect _hh");
+  snprintf(bda_str, sizeof(bda_str), "%02X:%02X:%02X:%02X:%02X:%02X", (*bda)[0],
+           (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+  if (dev == NULL && btif_hh_cb.device_num >= BTIF_HH_MAX_HID) {
+    // No space for more HID device now.
+    BTIF_TRACE_WARNING(
+        "%s: Error, exceeded the maximum supported HID device number %d",
+        __func__, BTIF_HH_MAX_HID);
+    return BT_STATUS_FAIL;
+  }
+
+  for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+    if (memcmp(&(btif_hh_cb.added_devices[i].bd_addr), bd_addr, BD_ADDR_LEN) ==
+        0) {
+      added_dev = &btif_hh_cb.added_devices[i];
+      BTIF_TRACE_WARNING("%s: Device %s already added, attr_mask = 0x%x",
+                         __func__, bda_str, added_dev->attr_mask);
+    }
+  }
+
+  if (added_dev != NULL) {
+    if (added_dev->dev_handle == BTA_HH_INVALID_HANDLE) {
+      // No space for more HID device now.
+      BTIF_TRACE_ERROR("%s: Error, device %s added but addition failed",
+                       __func__, bda_str);
+      memset(&(added_dev->bd_addr), 0, 6);
+      added_dev->dev_handle = BTA_HH_INVALID_HANDLE;
+      return BT_STATUS_FAIL;
+    }
+  }
+
+  /* Not checking the NORMALLY_Connectible flags from sdp record, and anyways
+   sending this
+   request from host, for subsequent user initiated connection. If the remote is
+   not in
+   pagescan mode, we will do 2 retries to connect before giving up */
+  tBTA_SEC sec_mask = BTUI_HH_SECURITY;
+  btif_hh_cb.status = BTIF_HH_DEV_CONNECTING;
+  BTA_HhOpen(*bda, BTA_HH_PROTO_RPT_MODE, sec_mask);
+
+  HAL_CBACK(bt_hh_callbacks, connection_state_cb, bd_addr,
+            BTHH_CONN_STATE_CONNECTING);
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hh_disconnect
+ *
+ * Description      disconnection initiated from the BTIF thread context
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+
+void btif_hh_disconnect(bt_bdaddr_t* bd_addr) {
+  btif_hh_device_t* p_dev;
+  p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+  if (p_dev != NULL) {
+    BTA_HhClose(p_dev->dev_handle);
+  } else
+    BTIF_TRACE_DEBUG("%s-- Error: device not connected:", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_btif_hh_setreport
+ *
+ * Description      setreport initiated from the BTIF thread context
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btif_hh_setreport(btif_hh_device_t* p_dev, bthh_report_type_t r_type,
+                       uint16_t size, uint8_t* report) {
+  BT_HDR* p_buf = create_pbuf(size, report);
+  if (p_buf == NULL) {
+    APPL_TRACE_ERROR("%s: Error, failed to allocate RPT buffer, size = %d",
+                     __func__, size);
+    return;
+  }
+  BTA_HhSetReport(p_dev->dev_handle, r_type, p_buf);
+}
+
+/*****************************************************************************
+ *   Section name (Group of functions)
+ ****************************************************************************/
+
+/*****************************************************************************
+ *
+ *   btif hh api functions (no context switch)
+ *
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         btif_hh_upstreams_evt
+ *
+ * Description      Executes HH UPSTREAMS events in btif context
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_hh_upstreams_evt(uint16_t event, char* p_param) {
+  tBTA_HH* p_data = (tBTA_HH*)p_param;
+  btif_hh_device_t* p_dev = NULL;
+  int i;
+  int len, tmplen;
+
+  BTIF_TRACE_DEBUG("%s: event=%s", __func__, dump_hh_event(event));
+
+  switch (event) {
+    case BTA_HH_ENABLE_EVT:
+      BTIF_TRACE_DEBUG("%s: BTA_HH_ENABLE_EVT: status =%d", __func__,
+                       p_data->status);
+      if (p_data->status == BTA_HH_OK) {
+        btif_hh_cb.status = BTIF_HH_ENABLED;
+        BTIF_TRACE_DEBUG("%s--Loading added devices", __func__);
+        /* Add hid descriptors for already bonded hid devices*/
+        btif_storage_load_bonded_hid_info();
+      } else {
+        btif_hh_cb.status = BTIF_HH_DISABLED;
+        BTIF_TRACE_WARNING(
+            "BTA_HH_ENABLE_EVT: Error, HH enabling failed, status = %d",
+            p_data->status);
+      }
+      break;
+
+    case BTA_HH_DISABLE_EVT:
+      btif_hh_cb.status = BTIF_HH_DISABLED;
+      if (p_data->status == BTA_HH_OK) {
+        int i;
+        // Clear the control block
+        for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+          alarm_free(btif_hh_cb.devices[i].vup_timer);
+        }
+        memset(&btif_hh_cb, 0, sizeof(btif_hh_cb));
+        for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+          btif_hh_cb.devices[i].dev_status = BTHH_CONN_STATE_UNKNOWN;
+        }
+      } else
+        BTIF_TRACE_WARNING(
+            "BTA_HH_DISABLE_EVT: Error, HH disabling failed, status = %d",
+            p_data->status);
+      break;
+
+    case BTA_HH_OPEN_EVT:
+      BTIF_TRACE_WARNING("%s: BTA_HH_OPN_EVT: handle=%d, status =%d", __func__,
+                         p_data->conn.handle, p_data->conn.status);
+      if (p_data->conn.status == BTA_HH_OK) {
+        p_dev = btif_hh_find_connected_dev_by_handle(p_data->conn.handle);
+        if (p_dev == NULL) {
+          BTIF_TRACE_WARNING(
+              "BTA_HH_OPEN_EVT: Error, cannot find device with handle %d",
+              p_data->conn.handle);
+          btif_hh_cb.status = (BTIF_HH_STATUS)BTIF_HH_DEV_DISCONNECTED;
+          // The connect request must come from device side and exceeded the
+          // connected
+          // HID device number.
+          BTA_HhClose(p_data->conn.handle);
+          HAL_CBACK(bt_hh_callbacks, connection_state_cb,
+                    (bt_bdaddr_t*)&p_data->conn.bda,
+                    BTHH_CONN_STATE_DISCONNECTED);
+        } else if (p_dev->fd < 0) {
+          BTIF_TRACE_WARNING(
+              "BTA_HH_OPEN_EVT: Error, failed to find the uhid driver...");
+          memcpy(&(p_dev->bd_addr), p_data->conn.bda, BD_ADDR_LEN);
+          // remove the connection  and then try again to reconnect from the
+          // mouse side to recover
+          btif_hh_cb.status = (BTIF_HH_STATUS)BTIF_HH_DEV_DISCONNECTED;
+          BTA_HhClose(p_data->conn.handle);
+        } else {
+          BTIF_TRACE_WARNING(
+              "BTA_HH_OPEN_EVT: Found device...Getting dscp info for handle "
+              "... %d",
+              p_data->conn.handle);
+          memcpy(&(p_dev->bd_addr), p_data->conn.bda, BD_ADDR_LEN);
+          btif_hh_cb.status = (BTIF_HH_STATUS)BTIF_HH_DEV_CONNECTED;
+          // Send set_idle if the peer_device is a keyboard
+          if (check_cod((bt_bdaddr_t*)p_data->conn.bda, COD_HID_KEYBOARD) ||
+              check_cod((bt_bdaddr_t*)p_data->conn.bda, COD_HID_COMBO))
+            BTA_HhSetIdle(p_data->conn.handle, 0);
+          btif_hh_cb.p_curr_dev =
+              btif_hh_find_connected_dev_by_handle(p_data->conn.handle);
+          BTA_HhGetDscpInfo(p_data->conn.handle);
+          p_dev->dev_status = BTHH_CONN_STATE_CONNECTED;
+          HAL_CBACK(bt_hh_callbacks, connection_state_cb, &(p_dev->bd_addr),
+                    p_dev->dev_status);
+        }
+      } else {
+        bt_bdaddr_t* bdaddr = (bt_bdaddr_t*)p_data->conn.bda;
+        btif_dm_hh_open_failed(bdaddr);
+        p_dev = btif_hh_find_dev_by_bda(bdaddr);
+        if (p_dev != NULL) {
+          btif_hh_stop_vup_timer(&(p_dev->bd_addr));
+          if (p_dev->fd >= 0) {
+            bta_hh_co_destroy(p_dev->fd);
+            p_dev->fd = -1;
+          }
+          p_dev->dev_status = BTHH_CONN_STATE_DISCONNECTED;
+        }
+        HAL_CBACK(bt_hh_callbacks, connection_state_cb,
+                  (bt_bdaddr_t*)&p_data->conn.bda,
+                  BTHH_CONN_STATE_DISCONNECTED);
+        btif_hh_cb.status = (BTIF_HH_STATUS)BTIF_HH_DEV_DISCONNECTED;
+      }
+      break;
+
+    case BTA_HH_CLOSE_EVT:
+      BTIF_TRACE_DEBUG("BTA_HH_CLOSE_EVT: status = %d, handle = %d",
+                       p_data->dev_status.status, p_data->dev_status.handle);
+      p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle);
+      if (p_dev != NULL) {
+        BTIF_TRACE_DEBUG("%s: uhid fd=%d local_vup=%d", __func__, p_dev->fd,
+                         p_dev->local_vup);
+        btif_hh_stop_vup_timer(&(p_dev->bd_addr));
+        /* If this is a locally initiated VUP, remove the bond as ACL got
+         *  disconnected while VUP being processed.
+         */
+        if (p_dev->local_vup) {
+          p_dev->local_vup = false;
+          BTA_DmRemoveDevice((uint8_t*)p_dev->bd_addr.address);
+        }
+
+        btif_hh_cb.status = (BTIF_HH_STATUS)BTIF_HH_DEV_DISCONNECTED;
+        p_dev->dev_status = BTHH_CONN_STATE_DISCONNECTED;
+
+        if (p_dev->fd >= 0) {
+          bta_hh_co_destroy(p_dev->fd);
+          p_dev->fd = -1;
+        }
+        HAL_CBACK(bt_hh_callbacks, connection_state_cb, &(p_dev->bd_addr),
+                  p_dev->dev_status);
+      } else {
+        BTIF_TRACE_WARNING("Error: cannot find device with handle %d",
+                           p_data->dev_status.handle);
+      }
+      break;
+
+    case BTA_HH_GET_RPT_EVT: {
+      BT_HDR* hdr = p_data->hs_data.rsp_data.p_rpt_data;
+      uint8_t* data = NULL;
+      uint16_t len = 0;
+
+      BTIF_TRACE_DEBUG("BTA_HH_GET_RPT_EVT: status = %d, handle = %d",
+                       p_data->hs_data.status, p_data->hs_data.handle);
+      p_dev = btif_hh_find_connected_dev_by_handle(p_data->hs_data.handle);
+      if (p_dev) {
+        /* p_rpt_data is NULL in HANDSHAKE response case */
+        if (hdr) {
+          data = (uint8_t*)(hdr + 1) + hdr->offset;
+          len = hdr->len;
+          HAL_CBACK(bt_hh_callbacks, get_report_cb,
+                    (bt_bdaddr_t*)&(p_dev->bd_addr),
+                    (bthh_status_t)p_data->hs_data.status, data, len);
+        } else {
+          HAL_CBACK(bt_hh_callbacks, handshake_cb,
+                    (bt_bdaddr_t*)&(p_dev->bd_addr),
+                    (bthh_status_t)p_data->hs_data.status);
+        }
+      } else {
+        BTIF_TRACE_WARNING("Error: cannot find device with handle %d",
+                           p_data->hs_data.handle);
+      }
+      break;
+    }
+
+    case BTA_HH_SET_RPT_EVT:
+      BTIF_TRACE_DEBUG("BTA_HH_SET_RPT_EVT: status = %d, handle = %d",
+                       p_data->dev_status.status, p_data->dev_status.handle);
+      p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle);
+      if (p_dev != NULL) {
+        HAL_CBACK(bt_hh_callbacks, handshake_cb,
+                  (bt_bdaddr_t*)&(p_dev->bd_addr),
+                  (bthh_status_t)p_data->hs_data.status);
+      }
+      break;
+
+    case BTA_HH_GET_PROTO_EVT:
+      p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle);
+      BTIF_TRACE_WARNING(
+          "BTA_HH_GET_PROTO_EVT: status = %d, handle = %d, proto = [%d], %s",
+          p_data->hs_data.status, p_data->hs_data.handle,
+          p_data->hs_data.rsp_data.proto_mode,
+          (p_data->hs_data.rsp_data.proto_mode == BTA_HH_PROTO_RPT_MODE)
+              ? "Report Mode"
+              : (p_data->hs_data.rsp_data.proto_mode == BTA_HH_PROTO_BOOT_MODE)
+                    ? "Boot Mode"
+                    : "Unsupported");
+      if (p_data->hs_data.rsp_data.proto_mode != BTA_HH_PROTO_UNKNOWN) {
+        HAL_CBACK(bt_hh_callbacks, protocol_mode_cb,
+                  (bt_bdaddr_t*)&(p_dev->bd_addr),
+                  (bthh_status_t)p_data->hs_data.status,
+                  (bthh_protocol_mode_t)p_data->hs_data.rsp_data.proto_mode);
+      } else {
+        HAL_CBACK(bt_hh_callbacks, handshake_cb,
+                  (bt_bdaddr_t*)&(p_dev->bd_addr),
+                  (bthh_status_t)p_data->hs_data.status);
+      }
+      break;
+
+    case BTA_HH_SET_PROTO_EVT:
+      BTIF_TRACE_DEBUG("BTA_HH_SET_PROTO_EVT: status = %d, handle = %d",
+                       p_data->dev_status.status, p_data->dev_status.handle);
+      p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle);
+      if (p_dev) {
+        HAL_CBACK(bt_hh_callbacks, handshake_cb,
+                  (bt_bdaddr_t*)&(p_dev->bd_addr),
+                  (bthh_status_t)p_data->hs_data.status);
+      }
+      break;
+
+    case BTA_HH_GET_IDLE_EVT:
+      BTIF_TRACE_DEBUG(
+          "BTA_HH_GET_IDLE_EVT: handle = %d, status = %d, rate = %d",
+          p_data->hs_data.handle, p_data->hs_data.status,
+          p_data->hs_data.rsp_data.idle_rate);
+      break;
+
+    case BTA_HH_SET_IDLE_EVT:
+      BTIF_TRACE_DEBUG("BTA_HH_SET_IDLE_EVT: status = %d, handle = %d",
+                       p_data->dev_status.status, p_data->dev_status.handle);
+      break;
+
+    case BTA_HH_GET_DSCP_EVT:
+      len = p_data->dscp_info.descriptor.dl_len;
+      BTIF_TRACE_DEBUG("BTA_HH_GET_DSCP_EVT: len = %d", len);
+      p_dev = btif_hh_cb.p_curr_dev;
+      if (p_dev == NULL) {
+        BTIF_TRACE_ERROR(
+            "BTA_HH_GET_DSCP_EVT: No HID device is currently connected");
+        return;
+      }
+      if (p_dev->fd < 0) {
+        LOG_ERROR(
+            LOG_TAG,
+            "BTA_HH_GET_DSCP_EVT: Error, failed to find the uhid driver...");
+        return;
+      }
+      {
+        const char* cached_name = NULL;
+        bt_bdname_t bdname;
+        bt_property_t prop_name;
+        BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_BDNAME,
+                                   sizeof(bt_bdname_t), &bdname);
+        if (btif_storage_get_remote_device_property(
+                &p_dev->bd_addr, &prop_name) == BT_STATUS_SUCCESS) {
+          cached_name = (char*)bdname.name;
+        } else {
+          cached_name = "Bluetooth HID";
+        }
+
+        BTIF_TRACE_WARNING("%s: name = %s", __func__, cached_name);
+        bta_hh_co_send_hid_info(p_dev, cached_name, p_data->dscp_info.vendor_id,
+                                p_data->dscp_info.product_id,
+                                p_data->dscp_info.version,
+                                p_data->dscp_info.ctry_code, len,
+                                p_data->dscp_info.descriptor.dsc_list);
+        if (btif_hh_add_added_dev(p_dev->bd_addr, p_dev->attr_mask)) {
+          BD_ADDR bda;
+          bdcpy(bda, p_dev->bd_addr.address);
+          tBTA_HH_DEV_DSCP_INFO dscp_info;
+          bt_status_t ret;
+          bdcpy(bda, p_dev->bd_addr.address);
+          btif_hh_copy_hid_info(&dscp_info, &p_data->dscp_info);
+          BTIF_TRACE_DEBUG(
+              "BTA_HH_GET_DSCP_EVT:bda = %02x:%02x:%02x:%02x:%02x:%02x",
+              p_dev->bd_addr.address[0], p_dev->bd_addr.address[1],
+              p_dev->bd_addr.address[2], p_dev->bd_addr.address[3],
+              p_dev->bd_addr.address[4], p_dev->bd_addr.address[5]);
+          BTA_HhAddDev(bda, p_dev->attr_mask, p_dev->sub_class, p_dev->app_id,
+                       dscp_info);
+          // write hid info to nvram
+          ret = btif_storage_add_hid_device_info(
+              &(p_dev->bd_addr), p_dev->attr_mask, p_dev->sub_class,
+              p_dev->app_id, p_data->dscp_info.vendor_id,
+              p_data->dscp_info.product_id, p_data->dscp_info.version,
+              p_data->dscp_info.ctry_code, p_data->dscp_info.ssr_max_latency,
+              p_data->dscp_info.ssr_min_tout, len,
+              p_data->dscp_info.descriptor.dsc_list);
+
+          ASSERTC(ret == BT_STATUS_SUCCESS, "storing hid info failed", ret);
+          BTIF_TRACE_WARNING("BTA_HH_GET_DSCP_EVT: Called add device");
+
+          // Free buffer created for dscp_info;
+          if (dscp_info.descriptor.dl_len > 0 &&
+              dscp_info.descriptor.dsc_list != NULL) {
+            osi_free_and_reset((void**)&dscp_info.descriptor.dsc_list);
+            dscp_info.descriptor.dl_len = 0;
+          }
+        } else {
+          // Device already added.
+          BTIF_TRACE_WARNING("%s: Device already added ", __func__);
+        }
+        /*Sync HID Keyboard lockstates */
+        tmplen = sizeof(hid_kb_numlock_on_list) / sizeof(tHID_KB_LIST);
+        for (i = 0; i < tmplen; i++) {
+          if (p_data->dscp_info.vendor_id ==
+                  hid_kb_numlock_on_list[i].version_id &&
+              p_data->dscp_info.product_id ==
+                  hid_kb_numlock_on_list[i].product_id) {
+            BTIF_TRACE_DEBUG(
+                "%s() idx[%d] Enabling "
+                "NUMLOCK for device :: %s",
+                __func__, i, hid_kb_numlock_on_list[i].kb_name);
+            /* Enable NUMLOCK by default so that numeric
+                keys work from first keyboard connect */
+            set_keylockstate(BTIF_HH_KEYSTATE_MASK_NUMLOCK, true);
+            sync_lockstate_on_connect(p_dev);
+            /* End Sync HID Keyboard lockstates */
+            break;
+          }
+        }
+      }
+      break;
+
+    case BTA_HH_ADD_DEV_EVT:
+      BTIF_TRACE_WARNING("BTA_HH_ADD_DEV_EVT: status = %d, handle = %d",
+                         p_data->dev_info.status, p_data->dev_info.handle);
+      int i;
+      for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+        if (memcmp(btif_hh_cb.added_devices[i].bd_addr.address,
+                   p_data->dev_info.bda, 6) == 0) {
+          if (p_data->dev_info.status == BTA_HH_OK) {
+            btif_hh_cb.added_devices[i].dev_handle = p_data->dev_info.handle;
+          } else {
+            memset(btif_hh_cb.added_devices[i].bd_addr.address, 0, 6);
+            btif_hh_cb.added_devices[i].dev_handle = BTA_HH_INVALID_HANDLE;
+          }
+          break;
+        }
+      }
+      break;
+    case BTA_HH_RMV_DEV_EVT:
+      BTIF_TRACE_DEBUG("BTA_HH_RMV_DEV_EVT: status = %d, handle = %d",
+                       p_data->dev_info.status, p_data->dev_info.handle);
+      BTIF_TRACE_DEBUG("BTA_HH_RMV_DEV_EVT:bda = %02x:%02x:%02x:%02x:%02x:%02x",
+                       p_data->dev_info.bda[0], p_data->dev_info.bda[1],
+                       p_data->dev_info.bda[2], p_data->dev_info.bda[3],
+                       p_data->dev_info.bda[4], p_data->dev_info.bda[5]);
+      break;
+
+    case BTA_HH_VC_UNPLUG_EVT:
+      BTIF_TRACE_DEBUG("BTA_HH_VC_UNPLUG_EVT: status = %d, handle = %d",
+                       p_data->dev_status.status, p_data->dev_status.handle);
+      p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle);
+      btif_hh_cb.status = (BTIF_HH_STATUS)BTIF_HH_DEV_DISCONNECTED;
+      if (p_dev != NULL) {
+        BTIF_TRACE_DEBUG(
+            "BTA_HH_VC_UNPLUG_EVT:bda = %02x:%02x:%02x:%02x:%02x:%02x",
+            p_dev->bd_addr.address[0], p_dev->bd_addr.address[1],
+            p_dev->bd_addr.address[2], p_dev->bd_addr.address[3],
+            p_dev->bd_addr.address[4], p_dev->bd_addr.address[5]);
+        /* Stop the VUP timer */
+        btif_hh_stop_vup_timer(&(p_dev->bd_addr));
+        p_dev->dev_status = BTHH_CONN_STATE_DISCONNECTED;
+        BTIF_TRACE_DEBUG("%s---Sending connection state change", __func__);
+        HAL_CBACK(bt_hh_callbacks, connection_state_cb, &(p_dev->bd_addr),
+                  p_dev->dev_status);
+        BTIF_TRACE_DEBUG("%s---Removing HID bond", __func__);
+        /* If it is locally initiated VUP or remote device has its major COD as
+        Peripheral removed the bond.*/
+        if (p_dev->local_vup || check_cod_hid(&(p_dev->bd_addr))) {
+          p_dev->local_vup = false;
+          BTA_DmRemoveDevice((uint8_t*)p_dev->bd_addr.address);
+        } else
+          btif_hh_remove_device(p_dev->bd_addr);
+        HAL_CBACK(bt_hh_callbacks, virtual_unplug_cb, &(p_dev->bd_addr),
+                  (bthh_status_t)p_data->dev_status.status);
+      }
+      break;
+
+    case BTA_HH_API_ERR_EVT:
+      LOG_INFO(LOG_TAG, "BTA_HH API_ERR");
+      break;
+
+    default:
+      BTIF_TRACE_WARNING("%s: Unhandled event: %d", __func__, event);
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         bte_hh_evt
+ *
+ * Description      Switches context from BTE to BTIF for all HH events
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+
+static void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH* p_data) {
+  bt_status_t status;
+  int param_len = 0;
+
+  if (BTA_HH_ENABLE_EVT == event)
+    param_len = sizeof(tBTA_HH_STATUS);
+  else if (BTA_HH_OPEN_EVT == event)
+    param_len = sizeof(tBTA_HH_CONN);
+  else if (BTA_HH_DISABLE_EVT == event)
+    param_len = sizeof(tBTA_HH_STATUS);
+  else if (BTA_HH_CLOSE_EVT == event)
+    param_len = sizeof(tBTA_HH_CBDATA);
+  else if (BTA_HH_GET_DSCP_EVT == event)
+    param_len = sizeof(tBTA_HH_DEV_DSCP_INFO);
+  else if ((BTA_HH_GET_PROTO_EVT == event) || (BTA_HH_GET_RPT_EVT == event) ||
+           (BTA_HH_GET_IDLE_EVT == event))
+    param_len = sizeof(tBTA_HH_HSDATA);
+  else if ((BTA_HH_SET_PROTO_EVT == event) || (BTA_HH_SET_RPT_EVT == event) ||
+           (BTA_HH_VC_UNPLUG_EVT == event) || (BTA_HH_SET_IDLE_EVT == event))
+    param_len = sizeof(tBTA_HH_CBDATA);
+  else if ((BTA_HH_ADD_DEV_EVT == event) || (BTA_HH_RMV_DEV_EVT == event))
+    param_len = sizeof(tBTA_HH_DEV_INFO);
+  else if (BTA_HH_API_ERR_EVT == event)
+    param_len = 0;
+  /* switch context to btif task context (copy full union size for convenience)
+   */
+  status = btif_transfer_context(btif_hh_upstreams_evt, (uint16_t)event,
+                                 (char*)p_data, param_len, NULL);
+
+  /* catch any failed context transfers */
+  ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hh_handle_evt
+ *
+ * Description      Switches context for immediate callback
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+
+static void btif_hh_handle_evt(uint16_t event, char* p_param) {
+  bt_bdaddr_t* bd_addr = (bt_bdaddr_t*)p_param;
+  BTIF_TRACE_EVENT("%s: event=%d", __func__, event);
+  int ret;
+  switch (event) {
+    case BTIF_HH_CONNECT_REQ_EVT: {
+      ret = btif_hh_connect(bd_addr);
+      if (ret == BT_STATUS_SUCCESS) {
+        HAL_CBACK(bt_hh_callbacks, connection_state_cb, bd_addr,
+                  BTHH_CONN_STATE_CONNECTING);
+      } else
+        HAL_CBACK(bt_hh_callbacks, connection_state_cb, bd_addr,
+                  BTHH_CONN_STATE_DISCONNECTED);
+    } break;
+
+    case BTIF_HH_DISCONNECT_REQ_EVT: {
+      BTIF_TRACE_EVENT("%s: event=%d", __func__, event);
+      btif_hh_disconnect(bd_addr);
+      HAL_CBACK(bt_hh_callbacks, connection_state_cb, bd_addr,
+                BTHH_CONN_STATE_DISCONNECTING);
+    } break;
+
+    case BTIF_HH_VUP_REQ_EVT: {
+      BTIF_TRACE_EVENT("%s: event=%d", __func__, event);
+      ret = btif_hh_virtual_unplug(bd_addr);
+    } break;
+
+    default: {
+      BTIF_TRACE_WARNING("%s : Unknown event 0x%x", __func__, event);
+    } break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hh_timer_timeout
+ *
+ * Description   Process timer timeout
+ *
+ * Returns      void
+ ******************************************************************************/
+void btif_hh_timer_timeout(void* data) {
+  btif_hh_device_t* p_dev = (btif_hh_device_t*)data;
+  tBTA_HH_EVT event = BTA_HH_VC_UNPLUG_EVT;
+  tBTA_HH p_data;
+  int param_len = sizeof(tBTA_HH_CBDATA);
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+  if (p_dev->dev_status != BTHH_CONN_STATE_CONNECTED) return;
+
+  memset(&p_data, 0, sizeof(tBTA_HH));
+  p_data.dev_status.status = BTHH_ERR;
+  p_data.dev_status.handle = p_dev->dev_handle;
+
+  /* switch context to btif task context */
+  btif_transfer_context(btif_hh_upstreams_evt, (uint16_t)event, (char*)&p_data,
+                        param_len, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hh_init
+ *
+ * Description     initializes the hh interface
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t init(bthh_callbacks_t* callbacks) {
+  uint32_t i;
+  BTIF_TRACE_EVENT("%s", __func__);
+
+  bt_hh_callbacks = callbacks;
+  memset(&btif_hh_cb, 0, sizeof(btif_hh_cb));
+  for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+    btif_hh_cb.devices[i].dev_status = BTHH_CONN_STATE_UNKNOWN;
+  }
+  /* Invoke the enable service API to the core to set the appropriate service_id
+   */
+  btif_enable_service(BTA_HID_SERVICE_ID);
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function        connect
+ *
+ * Description     connect to hid device
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t connect(bt_bdaddr_t* bd_addr) {
+  if (btif_hh_cb.status != BTIF_HH_DEV_CONNECTING) {
+    btif_transfer_context(btif_hh_handle_evt, BTIF_HH_CONNECT_REQ_EVT,
+                          (char*)bd_addr, sizeof(bt_bdaddr_t), NULL);
+    return BT_STATUS_SUCCESS;
+  } else
+    return BT_STATUS_BUSY;
+}
+
+/*******************************************************************************
+ *
+ * Function         disconnect
+ *
+ * Description      disconnect from hid device
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t disconnect(bt_bdaddr_t* bd_addr) {
+  CHECK_BTHH_INIT();
+  btif_hh_device_t* p_dev;
+
+  if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+    BTIF_TRACE_WARNING("%s: Error, HH status = %d", __func__,
+                       btif_hh_cb.status);
+    return BT_STATUS_FAIL;
+  }
+  p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+  if (p_dev != NULL) {
+    return btif_transfer_context(btif_hh_handle_evt, BTIF_HH_DISCONNECT_REQ_EVT,
+                                 (char*)bd_addr, sizeof(bt_bdaddr_t), NULL);
+  } else {
+    BTIF_TRACE_WARNING("%s: Error, device  not opened.", __func__);
+    return BT_STATUS_FAIL;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         virtual_unplug
+ *
+ * Description      Virtual UnPlug (VUP) the specified HID device.
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t virtual_unplug(bt_bdaddr_t* bd_addr) {
+  CHECK_BTHH_INIT();
+  btif_hh_device_t* p_dev;
+  char bd_str[18];
+  snprintf(bd_str, sizeof(bd_str), "%02X:%02X:%02X:%02X:%02X:%02X",
+           bd_addr->address[0], bd_addr->address[1], bd_addr->address[2],
+           bd_addr->address[3], bd_addr->address[4], bd_addr->address[5]);
+  if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+    BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status);
+    return BT_STATUS_FAIL;
+  }
+  p_dev = btif_hh_find_dev_by_bda(bd_addr);
+  if (!p_dev) {
+    BTIF_TRACE_ERROR("%s: Error, device %s not opened.", __func__, bd_str);
+    return BT_STATUS_FAIL;
+  }
+  btif_transfer_context(btif_hh_handle_evt, BTIF_HH_VUP_REQ_EVT, (char*)bd_addr,
+                        sizeof(bt_bdaddr_t), NULL);
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         set_info
+ *
+ * Description      Set the HID device descriptor for the specified HID device.
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t set_info(bt_bdaddr_t* bd_addr, bthh_hid_info_t hid_info) {
+  CHECK_BTHH_INIT();
+  tBTA_HH_DEV_DSCP_INFO dscp_info;
+  BD_ADDR* bda = (BD_ADDR*)bd_addr;
+
+  BTIF_TRACE_DEBUG("addr = %02X:%02X:%02X:%02X:%02X:%02X", (*bda)[0], (*bda)[1],
+                   (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+  BTIF_TRACE_DEBUG(
+      "%s: sub_class = 0x%02x, app_id = %d, vendor_id = 0x%04x, "
+      "product_id = 0x%04x, version= 0x%04x",
+      __func__, hid_info.sub_class, hid_info.app_id, hid_info.vendor_id,
+      hid_info.product_id, hid_info.version);
+
+  if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+    BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status);
+    return BT_STATUS_FAIL;
+  }
+
+  dscp_info.vendor_id = hid_info.vendor_id;
+  dscp_info.product_id = hid_info.product_id;
+  dscp_info.version = hid_info.version;
+  dscp_info.ctry_code = hid_info.ctry_code;
+
+  dscp_info.descriptor.dl_len = hid_info.dl_len;
+  dscp_info.descriptor.dsc_list =
+      (uint8_t*)osi_malloc(dscp_info.descriptor.dl_len);
+  memcpy(dscp_info.descriptor.dsc_list, &(hid_info.dsc_list), hid_info.dl_len);
+
+  if (btif_hh_add_added_dev(*bd_addr, hid_info.attr_mask)) {
+    BTA_HhAddDev(*bda, hid_info.attr_mask, hid_info.sub_class, hid_info.app_id,
+                 dscp_info);
+  }
+
+  osi_free_and_reset((void**)&dscp_info.descriptor.dsc_list);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         get_protocol
+ *
+ * Description      Get the HID proto mode.
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t get_protocol(bt_bdaddr_t* bd_addr,
+                                UNUSED_ATTR bthh_protocol_mode_t protocolMode) {
+  CHECK_BTHH_INIT();
+  btif_hh_device_t* p_dev;
+  BD_ADDR* bda = (BD_ADDR*)bd_addr;
+
+  BTIF_TRACE_DEBUG(" addr = %02X:%02X:%02X:%02X:%02X:%02X", (*bda)[0],
+                   (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+  if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+    BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status);
+    return BT_STATUS_FAIL;
+  }
+
+  p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+  if (p_dev != NULL) {
+    BTA_HhGetProtoMode(p_dev->dev_handle);
+  } else {
+    return BT_STATUS_FAIL;
+  }
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         set_protocol
+ *
+ * Description      Set the HID proto mode.
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t set_protocol(bt_bdaddr_t* bd_addr,
+                                bthh_protocol_mode_t protocolMode) {
+  CHECK_BTHH_INIT();
+  btif_hh_device_t* p_dev;
+  uint8_t proto_mode = protocolMode;
+  BD_ADDR* bda = (BD_ADDR*)bd_addr;
+
+  BTIF_TRACE_DEBUG("%s:proto_mode = %d", __func__, protocolMode);
+
+  BTIF_TRACE_DEBUG("addr = %02X:%02X:%02X:%02X:%02X:%02X", (*bda)[0], (*bda)[1],
+                   (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+  if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+    BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status);
+    return BT_STATUS_FAIL;
+  }
+
+  p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+  if (p_dev == NULL) {
+    BTIF_TRACE_WARNING(
+        " Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.", (*bda)[0],
+        (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+    return BT_STATUS_FAIL;
+  } else if (protocolMode != BTA_HH_PROTO_RPT_MODE &&
+             protocolMode != BTA_HH_PROTO_BOOT_MODE) {
+    BTIF_TRACE_WARNING("%s: Error, device proto_mode = %d.", __func__,
+                       proto_mode);
+    return BT_STATUS_FAIL;
+  } else {
+    BTA_HhSetProtoMode(p_dev->dev_handle, protocolMode);
+  }
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         get_report
+ *
+ * Description      Send a GET_REPORT to HID device.
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t get_report(bt_bdaddr_t* bd_addr,
+                              bthh_report_type_t reportType, uint8_t reportId,
+                              int bufferSize) {
+  CHECK_BTHH_INIT();
+  btif_hh_device_t* p_dev;
+  BD_ADDR* bda = (BD_ADDR*)bd_addr;
+
+  BTIF_TRACE_DEBUG("%s: r_type = %d, rpt_id = %d, buf_size = %d", __func__,
+                   reportType, reportId, bufferSize);
+
+  BTIF_TRACE_DEBUG("addr = %02X:%02X:%02X:%02X:%02X:%02X", (*bda)[0], (*bda)[1],
+                   (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+  if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+    BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status);
+    return BT_STATUS_FAIL;
+  }
+
+  p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR(
+        "%s: Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.", __func__,
+        (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+    return BT_STATUS_FAIL;
+  } else if (((int)reportType) <= BTA_HH_RPTT_RESRV ||
+             ((int)reportType) > BTA_HH_RPTT_FEATURE) {
+    BTIF_TRACE_ERROR(" Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.",
+                     (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4],
+                     (*bda)[5]);
+    return BT_STATUS_FAIL;
+  } else {
+    BTA_HhGetReport(p_dev->dev_handle, reportType, reportId, bufferSize);
+  }
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         set_report
+ *
+ * Description      Send a SET_REPORT to HID device.
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t set_report(bt_bdaddr_t* bd_addr,
+                              bthh_report_type_t reportType, char* report) {
+  CHECK_BTHH_INIT();
+  btif_hh_device_t* p_dev;
+  BD_ADDR* bda = (BD_ADDR*)bd_addr;
+
+  BTIF_TRACE_DEBUG("%s:reportType = %d", __func__, reportType);
+
+  BTIF_TRACE_DEBUG("addr = %02X:%02X:%02X:%02X:%02X:%02X", (*bda)[0], (*bda)[1],
+                   (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+  if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+    BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status);
+    return BT_STATUS_FAIL;
+  }
+
+  p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR(
+        "%s: Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.", __func__,
+        (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+    return BT_STATUS_FAIL;
+  } else if (((int)reportType) <= BTA_HH_RPTT_RESRV ||
+             ((int)reportType) > BTA_HH_RPTT_FEATURE) {
+    BTIF_TRACE_ERROR(" Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.",
+                     (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4],
+                     (*bda)[5]);
+    return BT_STATUS_FAIL;
+  } else {
+    int hex_bytes_filled;
+    size_t len = (strlen(report) + 1) / 2;
+    uint8_t* hexbuf = (uint8_t*)osi_calloc(len);
+
+    /* Build a SetReport data buffer */
+    // TODO
+    hex_bytes_filled = ascii_2_hex(report, len, hexbuf);
+    LOG_INFO(LOG_TAG, "Hex bytes filled, hex value: %d", hex_bytes_filled);
+    if (hex_bytes_filled) {
+      BT_HDR* p_buf = create_pbuf(hex_bytes_filled, hexbuf);
+      if (p_buf == NULL) {
+        BTIF_TRACE_ERROR("%s: Error, failed to allocate RPT buffer, len = %d",
+                         __func__, hex_bytes_filled);
+        osi_free(hexbuf);
+        return BT_STATUS_FAIL;
+      }
+      BTA_HhSetReport(p_dev->dev_handle, reportType, p_buf);
+      osi_free(hexbuf);
+      return BT_STATUS_SUCCESS;
+    }
+    osi_free(hexbuf);
+    return BT_STATUS_FAIL;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         send_data
+ *
+ * Description      Send a SEND_DATA to HID device.
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t send_data(bt_bdaddr_t* bd_addr, char* data) {
+  CHECK_BTHH_INIT();
+  btif_hh_device_t* p_dev;
+  BD_ADDR* bda = (BD_ADDR*)bd_addr;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  BTIF_TRACE_DEBUG("addr = %02X:%02X:%02X:%02X:%02X:%02X", (*bda)[0], (*bda)[1],
+                   (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+  if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+    BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status);
+    return BT_STATUS_FAIL;
+  }
+
+  p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR(
+        "%s: Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.", __func__,
+        (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+    return BT_STATUS_FAIL;
+  }
+
+  else {
+    int hex_bytes_filled;
+    size_t len = (strlen(data) + 1) / 2;
+    uint8_t* hexbuf = (uint8_t*)osi_calloc(len);
+
+    /* Build a SendData data buffer */
+    hex_bytes_filled = ascii_2_hex(data, len, hexbuf);
+    BTIF_TRACE_ERROR("Hex bytes filled, hex value: %d, %d", hex_bytes_filled,
+                     len);
+
+    if (hex_bytes_filled) {
+      BT_HDR* p_buf = create_pbuf(hex_bytes_filled, hexbuf);
+      if (p_buf == NULL) {
+        BTIF_TRACE_ERROR("%s: Error, failed to allocate RPT buffer, len = %d",
+                         __func__, hex_bytes_filled);
+        osi_free(hexbuf);
+        return BT_STATUS_FAIL;
+      }
+      p_buf->layer_specific = BTA_HH_RPTT_OUTPUT;
+      BTA_HhSendData(p_dev->dev_handle, *bda, p_buf);
+      osi_free(hexbuf);
+      return BT_STATUS_SUCCESS;
+    }
+    osi_free(hexbuf);
+    return BT_STATUS_FAIL;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         cleanup
+ *
+ * Description      Closes the HH interface
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static void cleanup(void) {
+  BTIF_TRACE_EVENT("%s", __func__);
+  btif_hh_device_t* p_dev;
+  int i;
+  if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+    BTIF_TRACE_WARNING("%s: HH disabling or disabled already, status = %d",
+                       __func__, btif_hh_cb.status);
+    return;
+  }
+  btif_hh_cb.status = BTIF_HH_DISABLING;
+  for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+    p_dev = &btif_hh_cb.devices[i];
+    if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN && p_dev->fd >= 0) {
+      BTIF_TRACE_DEBUG("%s: Closing uhid fd = %d", __func__, p_dev->fd);
+      if (p_dev->fd >= 0) {
+        bta_hh_co_destroy(p_dev->fd);
+        p_dev->fd = -1;
+      }
+      p_dev->hh_keep_polling = 0;
+      p_dev->hh_poll_thread_id = -1;
+    }
+  }
+
+  if (bt_hh_callbacks) {
+    btif_disable_service(BTA_HID_SERVICE_ID);
+    bt_hh_callbacks = NULL;
+  }
+}
+
+static const bthh_interface_t bthhInterface = {
+    sizeof(bthhInterface), init, connect, disconnect, virtual_unplug, set_info,
+    get_protocol, set_protocol,
+    //    get_idle_time,
+    //    set_idle_time,
+    get_report, set_report, send_data, cleanup,
+};
+
+/*******************************************************************************
+ *
+ * Function         btif_hh_execute_service
+ *
+ * Description      Initializes/Shuts down the service
+ *
+ * Returns          BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_hh_execute_service(bool b_enable) {
+  if (b_enable) {
+    /* Enable and register with BTA-HH */
+    BTA_HhEnable(BTUI_HH_SECURITY, bte_hh_evt);
+  } else {
+    /* Disable HH */
+    BTA_HhDisable();
+  }
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hh_get_interface
+ *
+ * Description      Get the hh callback interface
+ *
+ * Returns          bthh_interface_t
+ *
+ ******************************************************************************/
+const bthh_interface_t* btif_hh_get_interface() {
+  BTIF_TRACE_EVENT("%s", __func__);
+  return &bthhInterface;
+}
diff --git a/bt/btif/src/btif_hl.cc b/bt/btif/src/btif_hl.cc
new file mode 100644
index 0000000..cb56dd1
--- /dev/null
+++ b/bt/btif/src/btif_hl.cc
@@ -0,0 +1,4715 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ *  Filename:      btif_hl.c
+ *
+ *  Description:   Health Device Profile Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+#define LOG_TAG "bt_btif_hl"
+
+#include "btif_hl.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/poll.h>
+#include <sys/prctl.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <hardware/bt_hl.h>
+
+#include "bta_api.h"
+#include "btif_common.h"
+#include "btif_storage.h"
+#include "btif_util.h"
+#include "btu.h"
+#include "mca_api.h"
+#include "osi/include/list.h"
+#include "osi/include/osi.h"
+#include "osi/include/log.h"
+
+#define MAX_DATATYPE_SUPPORTED 8
+
+extern int btif_hl_update_maxfd(int max_org_s);
+extern void btif_hl_select_monitor_callback(fd_set* p_cur_set,
+                                            UNUSED_ATTR fd_set *p_org_set);
+extern void btif_hl_select_wakeup_callback(fd_set* p_org_set,
+                                           int wakeup_signal);
+extern int btif_hl_update_maxfd(int max_org_s);
+extern void btif_hl_select_monitor_callback(fd_set* p_cur_set,
+                                            UNUSED_ATTR fd_set *p_org_set);
+extern void btif_hl_select_wakeup_callback(fd_set* p_org_set,
+                                           int wakeup_signal);
+extern void btif_hl_soc_thread_init(void);
+extern void btif_hl_release_mcl_sockets(uint8_t app_idx, uint8_t mcl_idx);
+extern bool btif_hl_create_socket(uint8_t app_idx, uint8_t mcl_idx,
+                                  uint8_t mdl_idx);
+extern void btif_hl_release_socket(uint8_t app_idx, uint8_t mcl_idx,
+                                   uint8_t mdl_idx);
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+btif_hl_cb_t btif_hl_cb;
+btif_hl_cb_t* p_btif_hl_cb = &btif_hl_cb;
+
+/************************************************************************************
+ *  Static variables
+ ***********************************************************************************/
+static bthl_callbacks_t bt_hl_callbacks_cb;
+static bthl_callbacks_t* bt_hl_callbacks = NULL;
+
+/* signal socketpair to wake up select loop */
+
+const int btif_hl_signal_select_wakeup = 1;
+const int btif_hl_signal_select_exit = 2;
+const int btif_hl_signal_select_close_connected = 3;
+
+static int listen_s = -1;
+static int connected_s = -1;
+static int select_thread_id = -1;
+static int signal_fds[2] = {-1, -1};
+static list_t* soc_queue;
+static int reg_counter;
+
+static inline int btif_hl_select_wakeup(void);
+static inline int btif_hl_select_close_connected(void);
+static inline int btif_hl_close_select_thread(void);
+static uint8_t btif_hl_get_next_app_id(void);
+static int btif_hl_get_next_channel_id(uint8_t app_id);
+static void btif_hl_init_next_app_id(void);
+static void btif_hl_init_next_channel_id(void);
+static void btif_hl_ctrl_cback(tBTA_HL_CTRL_EVT event, tBTA_HL_CTRL* p_data);
+static void btif_hl_set_state(btif_hl_state_t state);
+static btif_hl_state_t btif_hl_get_state(void);
+static void btif_hl_cback(tBTA_HL_EVT event, tBTA_HL* p_data);
+static void btif_hl_proc_cb_evt(uint16_t event, char* p_param);
+
+#define CHECK_CALL_CBACK(P_CB, P_CBACK, ...) \
+  do {                                       \
+    if ((P_CB) && (P_CB)->P_CBACK) {         \
+      (P_CB)->P_CBACK(__VA_ARGS__);          \
+    } else {                                 \
+      ASSERTC(0, "Callback is NULL", 0);     \
+    }                                        \
+  } while (0)
+
+#define BTIF_HL_CALL_CBACK(P_CB, P_CBACK, ...)              \
+  do {                                                      \
+    if ((p_btif_hl_cb->state != BTIF_HL_STATE_DISABLING) && \
+        (p_btif_hl_cb->state != BTIF_HL_STATE_DISABLED)) {  \
+      if ((P_CB) && (P_CB)->P_CBACK) {                      \
+        (P_CB)->P_CBACK(__VA_ARGS__);                       \
+      } else {                                              \
+        ASSERTC(0, "Callback is NULL", 0);                  \
+      }                                                     \
+    }                                                       \
+  } while (0)
+
+#define CHECK_BTHL_INIT()                                             \
+  do {                                                                \
+    if (bt_hl_callbacks == NULL) {                                    \
+      BTIF_TRACE_WARNING("BTHL: %s: BTHL not initialized", __func__); \
+      return BT_STATUS_NOT_READY;                                     \
+    } else {                                                          \
+      BTIF_TRACE_EVENT("BTHL: %s", __func__);                         \
+    }                                                                 \
+  } while (0)
+
+static const btif_hl_data_type_cfg_t data_type_table[] = {
+    /* Data Specilization                   Ntx     Nrx (from Bluetooth SIG's
+       HDP whitepaper)*/
+    {BTIF_HL_DATA_TYPE_PULSE_OXIMETER, 9216, 256},
+    {BTIF_HL_DATA_TYPE_BLOOD_PRESSURE_MON, 896, 224},
+    {BTIF_HL_DATA_TYPE_BODY_THERMOMETER, 896, 224},
+    {BTIF_HL_DATA_TYPE_BODY_WEIGHT_SCALE, 896, 224},
+    {BTIF_HL_DATA_TYPE_GLUCOSE_METER, 896, 224},
+    {BTIF_HL_DATA_TYPE_STEP_COUNTER, 6624, 224},
+    {BTIF_HL_DATA_TYPE_BCA, 7730, 1230},
+    {BTIF_HL_DATA_TYPE_PEAK_FLOW, 2030, 224},
+    {BTIF_HL_DATA_TYPE_ACTIVITY_HUB, 5120, 224},
+    {BTIF_HL_DATA_TYPE_AMM, 1024, 64}};
+
+#define BTIF_HL_DATA_TABLE_SIZE \
+  (sizeof(data_type_table) / sizeof(btif_hl_data_type_cfg_t))
+#define BTIF_HL_DEFAULT_SRC_TX_APDU_SIZE         \
+  10240 /* use this size if the data type is not \
+           defined in the table; for future proof */
+#define BTIF_HL_DEFAULT_SRC_RX_APDU_SIZE       \
+  512 /* use this size if the data type is not \
+         defined in the table; for future proof */
+
+#define BTIF_HL_ECHO_MAX_TX_RX_APDU_SIZE 1024
+
+/************************************************************************************
+ *  Static utility functions
+ ***********************************************************************************/
+
+#define BTIF_IF_GET_NAME 16
+void btif_hl_display_calling_process_name(void) {
+  char name[16];
+  prctl(BTIF_IF_GET_NAME, name, 0, 0, 0);
+  BTIF_TRACE_DEBUG("Process name (%s)", name);
+}
+#define BTIF_TIMEOUT_CCH_NO_DCH_MS (30 * 1000)
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_if_channel_setup_pending
+ *
+ * Description   check whether channel id is in setup pending state or not
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+bool btif_hl_if_channel_setup_pending(int channel_id, uint8_t* p_app_idx,
+                                      uint8_t* p_mcl_idx) {
+  btif_hl_app_cb_t* p_acb;
+  btif_hl_mcl_cb_t* p_mcb;
+  uint8_t i, j;
+  bool found = false;
+
+  *p_app_idx = 0;
+  *p_mcl_idx = 0;
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+    if (p_acb->in_use) {
+      for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+        p_mcb = BTIF_HL_GET_MCL_CB_PTR(i, j);
+        if (p_mcb->in_use && p_mcb->is_connected &&
+            p_mcb->pcb.channel_id == channel_id) {
+          found = true;
+          *p_app_idx = i;
+          *p_mcl_idx = j;
+          break;
+        }
+      }
+    }
+    if (found) break;
+  }
+  BTIF_TRACE_DEBUG("%s found=%d channel_id=0x%08x", __func__, found, channel_id,
+                   *p_app_idx, *p_mcl_idx);
+  return found;
+}
+/*******************************************************************************
+ *
+ * Function      btif_hl_num_dchs_in_use
+ *
+ * Description find number of DCHs in use
+ *
+ * Returns      uint8_t
+ ******************************************************************************/
+uint8_t btif_hl_num_dchs_in_use(uint8_t mcl_handle) {
+  btif_hl_app_cb_t* p_acb;
+  btif_hl_mcl_cb_t* p_mcb;
+  uint8_t i, j, x;
+  uint8_t cnt = 0;
+
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    BTIF_TRACE_DEBUG("btif_hl_num_dchs:i = %d", i);
+    p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+    if (p_acb && p_acb->in_use) {
+      for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+        if (p_acb->mcb[j].in_use)
+          BTIF_TRACE_DEBUG(
+              "btif_hl_num_dchs:mcb in use j=%d, mcl_handle=%d,mcb handle=%d",
+              j, mcl_handle, p_acb->mcb[j].mcl_handle);
+        if (p_acb->mcb[j].in_use && (p_acb->mcb[j].mcl_handle == mcl_handle)) {
+          p_mcb = &p_acb->mcb[j];
+          BTIF_TRACE_DEBUG("btif_hl_num_dchs: mcl handle found j =%d", j);
+          for (x = 0; x < BTA_HL_NUM_MDLS_PER_MCL; x++) {
+            if (p_mcb->mdl[x].in_use) {
+              BTIF_TRACE_DEBUG("btif_hl_num_dchs_in_use:found x =%d", x);
+              cnt++;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  BTIF_TRACE_DEBUG("%s dch in use count=%d", __func__, cnt);
+  return cnt;
+}
+/*******************************************************************************
+ *
+ * Function      btif_hl_timer_timeout
+ *
+ * Description   Process timer timeout
+ *
+ * Returns      void
+ ******************************************************************************/
+void btif_hl_timer_timeout(void* data) {
+  btif_hl_mcl_cb_t* p_mcb = (btif_hl_mcl_cb_t*)data;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+  if (p_mcb->is_connected) {
+    BTIF_TRACE_DEBUG("Idle timeout Close CCH mcl_handle=%d", p_mcb->mcl_handle);
+    BTA_HlCchClose(p_mcb->mcl_handle);
+  } else {
+    BTIF_TRACE_DEBUG("CCH idle timeout But CCH not connected");
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_stop_cch_timer
+ *
+ * Description  stop CCH timer
+ *
+ * Returns      void
+ ******************************************************************************/
+void btif_hl_stop_cch_timer(uint8_t app_idx, uint8_t mcl_idx) {
+  btif_hl_mcl_cb_t* p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+  BTIF_TRACE_DEBUG("%s app_idx=%d, mcl_idx=%d", __func__, app_idx, mcl_idx);
+  alarm_cancel(p_mcb->cch_timer);
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_start_cch_timer
+ *
+ * Description  start CCH timer
+ *
+ * Returns      void
+ ******************************************************************************/
+void btif_hl_start_cch_timer(uint8_t app_idx, uint8_t mcl_idx) {
+  btif_hl_mcl_cb_t* p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  BTIF_TRACE_DEBUG("%s app_idx=%d, mcl_idx=%d", __func__, app_idx, mcl_idx);
+
+  alarm_free(p_mcb->cch_timer);
+  p_mcb->cch_timer = alarm_new("btif_hl.mcl_cch_timer");
+  alarm_set_on_queue(p_mcb->cch_timer, BTIF_TIMEOUT_CCH_NO_DCH_MS,
+                     btif_hl_timer_timeout, p_mcb, btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_find_mdl_idx
+ *
+ * Description  Find the MDL index using MDL ID
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+static bool btif_hl_find_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
+                                 uint16_t mdl_id, uint8_t* p_mdl_idx) {
+  btif_hl_mcl_cb_t* p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+    if (p_mcb->mdl[i].in_use && (mdl_id != 0) &&
+        (p_mcb->mdl[i].mdl_id == mdl_id)) {
+      found = true;
+      *p_mdl_idx = i;
+      break;
+    }
+  }
+
+  BTIF_TRACE_DEBUG("%s found=%d mdl_id=%d mdl_idx=%d ", __func__, found, mdl_id,
+                   i);
+
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_is_the_first_reliable_existed
+ *
+ * Description  This function checks whether the first reliable DCH channel
+ *              has been setup on the MCL or not
+ *
+ * Returns      bool - true exist
+ *                        false does not exist
+ *
+ ******************************************************************************/
+bool btif_hl_is_the_first_reliable_existed(uint8_t app_idx, uint8_t mcl_idx) {
+  btif_hl_mcl_cb_t* p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  bool is_existed = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+    if (p_mcb->mdl[i].in_use && p_mcb->mdl[i].is_the_first_reliable) {
+      is_existed = true;
+      break;
+    }
+  }
+
+  BTIF_TRACE_DEBUG("bta_hl_is_the_first_reliable_existed is_existed=%d  ",
+                   is_existed);
+  return is_existed;
+}
+/*******************************************************************************
+ *
+ * Function      btif_hl_clean_delete_mdl
+ *
+ * Description   Cleanup the delete mdl control block
+ *
+ * Returns     Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_clean_delete_mdl(btif_hl_delete_mdl_t* p_cb) {
+  BTIF_TRACE_DEBUG("%s", __func__);
+  memset(p_cb, 0, sizeof(btif_hl_delete_mdl_t));
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_clean_pcb
+ *
+ * Description   Cleanup the pending chan control block
+ *
+ * Returns     Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_clean_pcb(btif_hl_pending_chan_cb_t* p_pcb) {
+  BTIF_TRACE_DEBUG("%s", __func__);
+  memset(p_pcb, 0, sizeof(btif_hl_pending_chan_cb_t));
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_clean_mdl_cb
+ *
+ * Description   Cleanup the MDL control block
+ *
+ * Returns     Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_clean_mdl_cb(btif_hl_mdl_cb_t* p_dcb) {
+  BTIF_TRACE_DEBUG("%s", __func__);
+  osi_free_and_reset((void**)&p_dcb->p_rx_pkt);
+  osi_free_and_reset((void**)&p_dcb->p_tx_pkt);
+  memset(p_dcb, 0, sizeof(btif_hl_mdl_cb_t));
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_reset_mcb
+ *
+ * Description   Reset MCL control block
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+static void btif_hl_clean_mcl_cb(uint8_t app_idx, uint8_t mcl_idx) {
+  btif_hl_mcl_cb_t* p_mcb;
+  BTIF_TRACE_DEBUG("%s app_idx=%d, mcl_idx=%d", __func__, app_idx, mcl_idx);
+  p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  alarm_free(p_mcb->cch_timer);
+  memset(p_mcb, 0, sizeof(btif_hl_mcl_cb_t));
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_find_sdp_idx_using_mdep_filter
+ *
+ * Description  This function finds the SDP record index using MDEP filter
+ *              parameters
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+static void btif_hl_reset_mdep_filter(uint8_t app_idx) {
+  btif_hl_app_cb_t* p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+  p_acb->filter.num_elems = 0;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_find_sdp_idx_using_mdep_filter
+ *
+ * Description  This function finds the SDP record index using MDEP filter
+ *              parameters
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+static bool btif_hl_find_sdp_idx_using_mdep_filter(uint8_t app_idx,
+                                                   uint8_t mcl_idx,
+                                                   uint8_t* p_sdp_idx) {
+  btif_hl_app_cb_t* p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+  btif_hl_mcl_cb_t* p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  uint8_t i, j, num_recs, num_elems, num_mdeps, mdep_idx;
+  tBTA_HL_MDEP_ROLE peer_mdep_role;
+  uint16_t data_type;
+  tBTA_HL_SDP_MDEP_CFG* p_mdep;
+  bool found = false;
+  bool elem_found;
+
+  BTIF_TRACE_DEBUG("btif_hl_find_sdp_idx_using_mdep_filter");
+  num_recs = p_mcb->sdp.num_recs;
+  num_elems = p_acb->filter.num_elems;
+  if (!num_elems) {
+    BTIF_TRACE_DEBUG("btif_hl_find_sdp_idx_using_mdep_filter num_elem=0");
+    *p_sdp_idx = 0;
+    found = true;
+    return found;
+  }
+
+  for (i = 0; i < num_recs; i++) {
+    num_mdeps = p_mcb->sdp.sdp_rec[i].num_mdeps;
+    for (j = 0; j < num_elems; j++) {
+      data_type = p_acb->filter.elem[j].data_type;
+      peer_mdep_role = p_acb->filter.elem[j].peer_mdep_role;
+      elem_found = false;
+      mdep_idx = 0;
+      while (!elem_found && mdep_idx < num_mdeps) {
+        p_mdep = &(p_mcb->sdp.sdp_rec[i].mdep_cfg[mdep_idx]);
+        if ((p_mdep->data_type == data_type) &&
+            (p_mdep->mdep_role == peer_mdep_role)) {
+          elem_found = true;
+        } else {
+          mdep_idx++;
+        }
+      }
+
+      if (!elem_found) {
+        found = false;
+        break;
+      } else {
+        found = true;
+      }
+    }
+
+    if (found) {
+      BTIF_TRACE_DEBUG("btif_hl_find_sdp_idx_using_mdep_filter found idx=%d",
+                       i);
+      *p_sdp_idx = i;
+      break;
+    }
+  }
+
+  BTIF_TRACE_DEBUG("%s found=%d sdp_idx=%d", __func__, found, *p_sdp_idx);
+
+  btif_hl_reset_mdep_filter(app_idx);
+
+  return found;
+}
+/*******************************************************************************
+ *
+ * Function      btif_hl_is_reconnect_possible
+ *
+ * Description  check reconnect is possible or not
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+bool btif_hl_is_reconnect_possible(uint8_t app_idx, uint8_t mcl_idx,
+                                   int mdep_cfg_idx,
+                                   tBTA_HL_DCH_OPEN_PARAM* p_dch_open_api,
+                                   tBTA_HL_MDL_ID* p_mdl_id) {
+  btif_hl_app_cb_t* p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+  btif_hl_mcl_cb_t* p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  tBTA_HL_DCH_CFG local_cfg = p_dch_open_api->local_cfg;
+  tBTA_HL_DCH_MODE dch_mode = BTA_HL_DCH_MODE_RELIABLE;
+  bool use_mdl_dch_mode = false;
+  btif_hl_mdl_cfg_t* p_mdl;
+  btif_hl_mdl_cfg_t* p_mdl1;
+  uint8_t i, j;
+  bool is_reconnect_ok = false;
+  bool stream_mode_avail = false;
+  uint16_t data_type =
+      p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg.data_cfg[0].data_type;
+  tBTA_HL_MDEP_ID peer_mdep_id = p_dch_open_api->peer_mdep_id;
+  uint8_t mdl_idx;
+
+  BTIF_TRACE_DEBUG("%s app_idx=%d mcl_idx=%d mdep_cfg_idx=%d", __func__,
+                   app_idx, mcl_idx, mdep_cfg_idx);
+  switch (local_cfg) {
+    case BTA_HL_DCH_CFG_NO_PREF:
+      if (!btif_hl_is_the_first_reliable_existed(app_idx, mcl_idx)) {
+        dch_mode = BTA_HL_DCH_MODE_RELIABLE;
+      } else {
+        use_mdl_dch_mode = true;
+      }
+      break;
+    case BTA_HL_DCH_CFG_RELIABLE:
+      dch_mode = BTA_HL_DCH_MODE_RELIABLE;
+      break;
+    case BTA_HL_DCH_CFG_STREAMING:
+      dch_mode = BTA_HL_DCH_MODE_STREAMING;
+      break;
+    default:
+      BTIF_TRACE_ERROR("Invalid local_cfg=%d", local_cfg);
+      return is_reconnect_ok;
+      break;
+  }
+
+  BTIF_TRACE_DEBUG("local_cfg=%d use_mdl_dch_mode=%d dch_mode=%d ", local_cfg,
+                   use_mdl_dch_mode, dch_mode);
+
+  for (i = 0, p_mdl = &p_acb->mdl_cfg[0]; i < BTA_HL_NUM_MDL_CFGS;
+       i++, p_mdl++) {
+    if (p_mdl->base.active && p_mdl->extra.data_type == data_type &&
+        (p_mdl->extra.peer_mdep_id != BTA_HL_INVALID_MDEP_ID &&
+         p_mdl->extra.peer_mdep_id == peer_mdep_id) &&
+        memcpy(p_mdl->base.peer_bd_addr, p_mcb->bd_addr, sizeof(BD_ADDR)) &&
+        p_mdl->base.mdl_id &&
+        !btif_hl_find_mdl_idx(app_idx, mcl_idx, p_mdl->base.mdl_id, &mdl_idx)) {
+      BTIF_TRACE_DEBUG("i=%d Matched active=%d   mdl_id =%d, mdl_dch_mode=%d",
+                       i, p_mdl->base.active, p_mdl->base.mdl_id,
+                       p_mdl->base.dch_mode);
+      if (!use_mdl_dch_mode) {
+        if (p_mdl->base.dch_mode == dch_mode) {
+          is_reconnect_ok = true;
+          *p_mdl_id = p_mdl->base.mdl_id;
+          BTIF_TRACE_DEBUG("reconnect is possible dch_mode=%d mdl_id=%d",
+                           dch_mode, p_mdl->base.mdl_id);
+          break;
+        }
+      } else {
+        is_reconnect_ok = true;
+        for (j = i, p_mdl1 = &p_acb->mdl_cfg[i]; j < BTA_HL_NUM_MDL_CFGS;
+             j++, p_mdl1++) {
+          if (p_mdl1->base.active && p_mdl1->extra.data_type == data_type &&
+              (p_mdl1->extra.peer_mdep_id != BTA_HL_INVALID_MDEP_ID &&
+               p_mdl1->extra.peer_mdep_id == peer_mdep_id) &&
+              memcpy(p_mdl1->base.peer_bd_addr, p_mcb->bd_addr,
+                     sizeof(BD_ADDR)) &&
+              p_mdl1->base.dch_mode == BTA_HL_DCH_MODE_STREAMING) {
+            stream_mode_avail = true;
+            BTIF_TRACE_DEBUG("found streaming mode mdl index=%d", j);
+            break;
+          }
+        }
+
+        if (stream_mode_avail) {
+          dch_mode = BTA_HL_DCH_MODE_STREAMING;
+          *p_mdl_id = p_mdl1->base.mdl_id;
+          BTIF_TRACE_DEBUG(
+              "reconnect is ok index=%d dch_mode=streaming  mdl_id=%d", j,
+              *p_mdl_id);
+          break;
+        } else {
+          dch_mode = p_mdl->base.dch_mode;
+          *p_mdl_id = p_mdl->base.mdl_id;
+          BTIF_TRACE_DEBUG("reconnect is ok index=%d  dch_mode=%d mdl_id=%d", i,
+                           p_mdl->base.dch_mode, *p_mdl_id);
+          break;
+        }
+      }
+    }
+  }
+
+  BTIF_TRACE_DEBUG("is_reconnect_ok  dch_mode=%d mdl_id=%d", is_reconnect_ok,
+                   dch_mode, *p_mdl_id);
+  return is_reconnect_ok;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_dch_open
+ *
+ * Description   Process DCH open request using the DCH Open API parameters
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+bool btif_hl_dch_open(uint8_t app_id, BD_ADDR bd_addr,
+                      tBTA_HL_DCH_OPEN_PARAM* p_dch_open_api, int mdep_cfg_idx,
+                      btif_hl_pend_dch_op_t op, int* channel_id) {
+  btif_hl_app_cb_t* p_acb;
+  btif_hl_mcl_cb_t* p_mcb;
+  btif_hl_pending_chan_cb_t* p_pcb;
+  uint8_t app_idx, mcl_idx;
+  bool status = false;
+  tBTA_HL_MDL_ID mdl_id;
+  tBTA_HL_DCH_RECONNECT_PARAM reconnect_param;
+
+  BTIF_TRACE_DEBUG("%s app_id=%d ", __func__, app_id);
+  BTIF_TRACE_DEBUG("DB [%02x:%02x:%02x:%02x:%02x:%02x]", bd_addr[0], bd_addr[1],
+                   bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+
+  if (btif_hl_find_app_idx(app_id, &app_idx)) {
+    if (btif_hl_find_mcl_idx(app_idx, bd_addr, &mcl_idx)) {
+      p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+      p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+      if (!p_pcb->in_use) {
+        p_mcb->req_ctrl_psm = p_dch_open_api->ctrl_psm;
+
+        p_pcb->in_use = true;
+        *channel_id = p_pcb->channel_id =
+            (int)btif_hl_get_next_channel_id(app_id);
+        p_pcb->cb_state = BTIF_HL_CHAN_CB_STATE_CONNECTING_PENDING;
+        p_pcb->mdep_cfg_idx = mdep_cfg_idx;
+        memcpy(p_pcb->bd_addr, bd_addr, sizeof(BD_ADDR));
+        p_pcb->op = op;
+
+        if (p_mcb->sdp.num_recs) {
+          if (p_mcb->valid_sdp_idx) {
+            p_dch_open_api->ctrl_psm = p_mcb->ctrl_psm;
+          }
+
+          if (!btif_hl_is_reconnect_possible(app_idx, mcl_idx, mdep_cfg_idx,
+                                             p_dch_open_api, &mdl_id)) {
+            BTIF_TRACE_DEBUG("Issue DCH open");
+            BTA_HlDchOpen(p_mcb->mcl_handle, p_dch_open_api);
+          } else {
+            reconnect_param.ctrl_psm = p_mcb->ctrl_psm;
+            reconnect_param.mdl_id = mdl_id;
+            ;
+            BTIF_TRACE_DEBUG("Issue Reconnect ctrl_psm=0x%x mdl_id=0x%x",
+                             reconnect_param.ctrl_psm, reconnect_param.mdl_id);
+            BTA_HlDchReconnect(p_mcb->mcl_handle, &reconnect_param);
+          }
+
+          status = true;
+        } else {
+          p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+          p_mcb->cch_oper = BTIF_HL_CCH_OP_DCH_OPEN;
+          BTA_HlSdpQuery(app_id, p_acb->app_handle, bd_addr);
+          status = true;
+        }
+      }
+    }
+  }
+
+  BTIF_TRACE_DEBUG("status=%d ", status);
+  return status;
+}
+/*******************************************************************************
+ *
+ * Function      btif_hl_copy_bda
+ *
+ * Description  copy bt_bdaddr_t to BD_ADDR format
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void btif_hl_copy_bda(bt_bdaddr_t* bd_addr, BD_ADDR bda) {
+  uint8_t i;
+  for (i = 0; i < 6; i++) {
+    bd_addr->address[i] = bda[i];
+  }
+}
+/*******************************************************************************
+ *
+ * Function      btif_hl_copy_bda
+ *
+ * Description  display bt_bdaddr_t
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+void btif_hl_display_bt_bda(bt_bdaddr_t* bd_addr) {
+  BTIF_TRACE_DEBUG("DB [%02x:%02x:%02x:%02x:%02x:%02x]", bd_addr->address[0],
+                   bd_addr->address[1], bd_addr->address[2],
+                   bd_addr->address[3], bd_addr->address[4],
+                   bd_addr->address[5]);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_dch_abort
+ *
+ * Description      Process DCH abort request
+ *
+ * Returns          Nothing
+ *
+ ******************************************************************************/
+void btif_hl_dch_abort(uint8_t app_idx, uint8_t mcl_idx) {
+  btif_hl_mcl_cb_t* p_mcb;
+
+  BTIF_TRACE_DEBUG("%s app_idx=%d mcl_idx=%d", __func__, app_idx, mcl_idx);
+  p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  if (p_mcb->is_connected) {
+    BTA_HlDchAbort(p_mcb->mcl_handle);
+  } else {
+    p_mcb->pcb.abort_pending = true;
+  }
+}
+/*******************************************************************************
+ *
+ * Function      btif_hl_cch_open
+ *
+ * Description   Process CCH open request
+ *
+ * Returns     Nothing
+ *
+ ******************************************************************************/
+bool btif_hl_cch_open(uint8_t app_id, BD_ADDR bd_addr, uint16_t ctrl_psm,
+                      int mdep_cfg_idx, btif_hl_pend_dch_op_t op,
+                      int* channel_id) {
+  btif_hl_app_cb_t* p_acb;
+  btif_hl_mcl_cb_t* p_mcb;
+  btif_hl_pending_chan_cb_t* p_pcb;
+  uint8_t app_idx, mcl_idx;
+  bool status = true;
+
+  BTIF_TRACE_DEBUG("%s app_id=%d ctrl_psm=%d mdep_cfg_idx=%d op=%d", __func__,
+                   app_id, ctrl_psm, mdep_cfg_idx, op);
+  BTIF_TRACE_DEBUG("DB [%02x:%02x:%02x:%02x:%02x:%02x]", bd_addr[0], bd_addr[1],
+                   bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+
+  if (btif_hl_find_app_idx(app_id, &app_idx)) {
+    p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+
+    if (!btif_hl_find_mcl_idx(app_idx, bd_addr, &mcl_idx)) {
+      if (btif_hl_find_avail_mcl_idx(app_idx, &mcl_idx)) {
+        p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+        alarm_free(p_mcb->cch_timer);
+        memset(p_mcb, 0, sizeof(btif_hl_mcl_cb_t));
+        p_mcb->in_use = true;
+        bdcpy(p_mcb->bd_addr, bd_addr);
+
+        if (!ctrl_psm) {
+          p_mcb->cch_oper = BTIF_HL_CCH_OP_MDEP_FILTERING;
+        } else {
+          p_mcb->cch_oper = BTIF_HL_CCH_OP_MATCHED_CTRL_PSM;
+          p_mcb->req_ctrl_psm = ctrl_psm;
+        }
+
+        p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+        p_pcb->in_use = true;
+        p_pcb->mdep_cfg_idx = mdep_cfg_idx;
+        memcpy(p_pcb->bd_addr, bd_addr, sizeof(BD_ADDR));
+        p_pcb->op = op;
+
+        switch (op) {
+          case BTIF_HL_PEND_DCH_OP_OPEN:
+            *channel_id = p_pcb->channel_id =
+                (int)btif_hl_get_next_channel_id(app_id);
+            p_pcb->cb_state = BTIF_HL_CHAN_CB_STATE_CONNECTING_PENDING;
+            break;
+          case BTIF_HL_PEND_DCH_OP_DELETE_MDL:
+            p_pcb->channel_id = p_acb->delete_mdl.channel_id;
+            p_pcb->cb_state = BTIF_HL_CHAN_CB_STATE_DESTROYED_PENDING;
+            break;
+          default:
+            break;
+        }
+        BTA_HlSdpQuery(app_id, p_acb->app_handle, bd_addr);
+      } else {
+        status = false;
+        BTIF_TRACE_ERROR("Open CCH request discarded- No mcl cb");
+      }
+    } else {
+      status = false;
+      BTIF_TRACE_ERROR("Open CCH request discarded- already in USE");
+    }
+  } else {
+    status = false;
+    BTIF_TRACE_ERROR("Invalid app_id=%d", app_id);
+  }
+
+  if (channel_id) {
+    BTIF_TRACE_DEBUG("status=%d channel_id=0x%08x", status, *channel_id);
+  } else {
+    BTIF_TRACE_DEBUG("status=%d ", status);
+  }
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_find_mdl_idx_using_handle
+ *
+ * Description  Find the MDL index using channel id
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_mdl_cfg_idx_using_channel_id(int channel_id,
+                                               uint8_t* p_app_idx,
+                                               uint8_t* p_mdl_cfg_idx) {
+  btif_hl_app_cb_t* p_acb;
+  btif_hl_mdl_cfg_t* p_mdl;
+  bool found = false;
+  uint8_t i, j;
+  int mdl_cfg_channel_id;
+
+  *p_app_idx = 0;
+  *p_mdl_cfg_idx = 0;
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+    for (j = 0; j < BTA_HL_NUM_MDL_CFGS; j++) {
+      p_mdl = BTIF_HL_GET_MDL_CFG_PTR(i, j);
+      mdl_cfg_channel_id = *(BTIF_HL_GET_MDL_CFG_CHANNEL_ID_PTR(i, j));
+      if (p_acb->in_use && p_mdl->base.active &&
+          (mdl_cfg_channel_id == channel_id)) {
+        found = true;
+        *p_app_idx = i;
+        *p_mdl_cfg_idx = j;
+        break;
+      }
+    }
+  }
+
+  BTIF_TRACE_EVENT("%s found=%d channel_id=0x%08x, app_idx=%d mdl_cfg_idx=%d  ",
+                   __func__, found, channel_id, i, j);
+  return found;
+}
+/*******************************************************************************
+ *
+ * Function      btif_hl_find_mdl_idx_using_handle
+ *
+ * Description  Find the MDL index using channel id
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_mdl_idx_using_channel_id(int channel_id, uint8_t* p_app_idx,
+                                           uint8_t* p_mcl_idx,
+                                           uint8_t* p_mdl_idx) {
+  btif_hl_app_cb_t* p_acb;
+  btif_hl_mcl_cb_t* p_mcb;
+  btif_hl_mdl_cb_t* p_dcb;
+  bool found = false;
+  uint8_t i, j, k;
+
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+    for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+      p_mcb = BTIF_HL_GET_MCL_CB_PTR(i, j);
+      for (k = 0; k < BTA_HL_NUM_MDLS_PER_MCL; k++) {
+        p_dcb = BTIF_HL_GET_MDL_CB_PTR(i, j, k);
+        if (p_acb->in_use && p_mcb->in_use && p_dcb->in_use &&
+            (p_dcb->channel_id == channel_id)) {
+          found = true;
+          *p_app_idx = i;
+          *p_mcl_idx = j;
+          *p_mdl_idx = k;
+          break;
+        }
+      }
+    }
+  }
+  BTIF_TRACE_DEBUG("%s found=%d app_idx=%d mcl_idx=%d mdl_idx=%d  ", __func__,
+                   found, i, j, k);
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_find_channel_id_using_mdl_id
+ *
+ * Description  Find channel id using mdl_id'
+ *
+ * Returns      bool
+ ********************************************************************************/
+bool btif_hl_find_channel_id_using_mdl_id(uint8_t app_idx,
+                                          tBTA_HL_MDL_ID mdl_id,
+                                          int* p_channel_id) {
+  btif_hl_app_cb_t* p_acb;
+  btif_hl_mdl_cfg_t* p_mdl;
+  bool found = false;
+  uint8_t j = 0;
+  int mdl_cfg_channel_id;
+  p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+  if (p_acb && p_acb->in_use) {
+    for (j = 0; j < BTA_HL_NUM_MDL_CFGS; j++) {
+      p_mdl = BTIF_HL_GET_MDL_CFG_PTR(app_idx, j);
+      mdl_cfg_channel_id = *(BTIF_HL_GET_MDL_CFG_CHANNEL_ID_PTR(app_idx, j));
+      if (p_mdl->base.active && (p_mdl->base.mdl_id == mdl_id)) {
+        found = true;
+        *p_channel_id = mdl_cfg_channel_id;
+        break;
+      }
+    }
+  }
+  BTIF_TRACE_EVENT(
+      "%s found=%d channel_id=0x%08x, mdl_id=0x%x app_idx=%d mdl_cfg_idx=%d  ",
+      __func__, found, *p_channel_id, mdl_id, app_idx, j);
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_find_mdl_idx_using_handle
+ *
+ * Description  Find the MDL index using handle
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_mdl_idx_using_handle(tBTA_HL_MDL_HANDLE mdl_handle,
+                                       uint8_t* p_app_idx, uint8_t* p_mcl_idx,
+                                       uint8_t* p_mdl_idx) {
+  btif_hl_app_cb_t* p_acb;
+  btif_hl_mcl_cb_t* p_mcb;
+  btif_hl_mdl_cb_t* p_dcb;
+  bool found = false;
+  uint8_t i, j, k;
+
+  *p_app_idx = 0;
+  *p_mcl_idx = 0;
+  *p_mdl_idx = 0;
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+    for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+      p_mcb = BTIF_HL_GET_MCL_CB_PTR(i, j);
+      for (k = 0; k < BTA_HL_NUM_MDLS_PER_MCL; k++) {
+        p_dcb = BTIF_HL_GET_MDL_CB_PTR(i, j, k);
+        if (p_acb->in_use && p_mcb->in_use && p_dcb->in_use &&
+            (p_dcb->mdl_handle == mdl_handle)) {
+          found = true;
+          *p_app_idx = i;
+          *p_mcl_idx = j;
+          *p_mdl_idx = k;
+          break;
+        }
+      }
+    }
+  }
+
+  BTIF_TRACE_EVENT("%s found=%d app_idx=%d mcl_idx=%d mdl_idx=%d  ", __func__,
+                   found, i, j, k);
+  return found;
+}
+/*******************************************************************************
+ *
+ * Function        btif_hl_find_peer_mdep_id
+ *
+ * Description      Find the peer MDEP ID from the received SPD records
+ *
+ * Returns          bool
+ *
+ ******************************************************************************/
+static bool btif_hl_find_peer_mdep_id(uint8_t app_id, BD_ADDR bd_addr,
+                                      tBTA_HL_MDEP_ROLE local_mdep_role,
+                                      uint16_t data_type,
+                                      tBTA_HL_MDEP_ID* p_peer_mdep_id) {
+  uint8_t app_idx, mcl_idx;
+  btif_hl_mcl_cb_t* p_mcb;
+  tBTA_HL_SDP_REC* p_rec;
+  uint8_t i, num_mdeps;
+  bool found = false;
+  tBTA_HL_MDEP_ROLE peer_mdep_role;
+
+  BTIF_TRACE_DEBUG("%s app_id=%d local_mdep_role=%d, data_type=%d", __func__,
+                   app_id, local_mdep_role, data_type);
+
+  BTIF_TRACE_DEBUG("DB [%02x:%02x:%02x:%02x:%02x:%02x]", bd_addr[0], bd_addr[1],
+                   bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+
+  BTIF_TRACE_DEBUG("local_mdep_role=%d", local_mdep_role);
+  BTIF_TRACE_DEBUG("data_type=%d", data_type);
+
+  if (local_mdep_role == BTA_HL_MDEP_ROLE_SINK)
+    peer_mdep_role = BTA_HL_MDEP_ROLE_SOURCE;
+  else
+    peer_mdep_role = BTA_HL_MDEP_ROLE_SINK;
+
+  if (btif_hl_find_app_idx(app_id, &app_idx)) {
+    if (btif_hl_find_mcl_idx(app_idx, bd_addr, &mcl_idx)) {
+      p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+      BTIF_TRACE_DEBUG("app_idx=%d mcl_idx=%d", app_idx, mcl_idx);
+      BTIF_TRACE_DEBUG("valid_spd_idx=%d sdp_idx=%d", p_mcb->valid_sdp_idx,
+                       p_mcb->sdp_idx);
+      if (p_mcb->valid_sdp_idx) {
+        p_rec = &p_mcb->sdp.sdp_rec[p_mcb->sdp_idx];
+        num_mdeps = p_rec->num_mdeps;
+        BTIF_TRACE_DEBUG("num_mdeps=%d", num_mdeps);
+
+        for (i = 0; i < num_mdeps; i++) {
+          BTIF_TRACE_DEBUG("p_rec->mdep_cfg[%d].mdep_role=%d", i,
+                           p_rec->mdep_cfg[i].mdep_role);
+          BTIF_TRACE_DEBUG("p_rec->mdep_cfg[%d].data_type =%d", i,
+                           p_rec->mdep_cfg[i].data_type);
+          if ((p_rec->mdep_cfg[i].mdep_role == peer_mdep_role) &&
+              (p_rec->mdep_cfg[i].data_type == data_type)) {
+            found = true;
+            *p_peer_mdep_id = p_rec->mdep_cfg[i].mdep_id;
+            break;
+          }
+        }
+      }
+    }
+  }
+
+  BTIF_TRACE_DEBUG("found =%d  *p_peer_mdep_id=%d", found, *p_peer_mdep_id);
+
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_find_mdep_cfg_idx
+ *
+ * Description  Find the MDEP configuration index using local MDEP_ID
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+static bool btif_hl_find_mdep_cfg_idx(uint8_t app_idx,
+                                      tBTA_HL_MDEP_ID local_mdep_id,
+                                      uint8_t* p_mdep_cfg_idx) {
+  btif_hl_app_cb_t* p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+  tBTA_HL_SUP_FEATURE* p_sup_feature = &p_acb->sup_feature;
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < p_sup_feature->num_of_mdeps; i++) {
+    BTIF_TRACE_DEBUG("btif_hl_find_mdep_cfg_idx: mdep_id=%d app_idx = %d",
+                     p_sup_feature->mdep[i].mdep_id, app_idx);
+    if (p_sup_feature->mdep[i].mdep_id == local_mdep_id) {
+      found = true;
+      *p_mdep_cfg_idx = i;
+      break;
+    }
+  }
+
+  BTIF_TRACE_DEBUG("%s found=%d mdep_idx=%d local_mdep_id=%d app_idx=%d ",
+                   __func__, found, i, local_mdep_id, app_idx);
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_find_mcl_idx
+ *
+ * Description  Find the MCL index using BD address
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_mcl_idx(uint8_t app_idx, BD_ADDR p_bd_addr,
+                          uint8_t* p_mcl_idx) {
+  bool found = false;
+  uint8_t i;
+  btif_hl_mcl_cb_t* p_mcb;
+
+  *p_mcl_idx = 0;
+  for (i = 0; i < BTA_HL_NUM_MCLS; i++) {
+    p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, i);
+    if (p_mcb->in_use && (!memcmp(p_mcb->bd_addr, p_bd_addr, BD_ADDR_LEN))) {
+      found = true;
+      *p_mcl_idx = i;
+      break;
+    }
+  }
+
+  BTIF_TRACE_DEBUG("%s found=%d idx=%d", __func__, found, i);
+  return found;
+}
+/*******************************************************************************
+ *
+ * Function         btif_hl_init
+ *
+ * Description      HL initialization function.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_hl_init(void) {
+  BTIF_TRACE_DEBUG("%s", __func__);
+  memset(p_btif_hl_cb, 0, sizeof(btif_hl_cb_t));
+  btif_hl_init_next_app_id();
+  btif_hl_init_next_channel_id();
+}
+/*******************************************************************************
+ *
+ * Function         btif_hl_disable
+ *
+ * Description      Disable initialization function.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_hl_disable(void) {
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  if ((p_btif_hl_cb->state != BTIF_HL_STATE_DISABLING) &&
+      (p_btif_hl_cb->state != BTIF_HL_STATE_DISABLED)) {
+    btif_hl_set_state(BTIF_HL_STATE_DISABLING);
+    BTA_HlDisable();
+  }
+}
+/*******************************************************************************
+ *
+ * Function      btif_hl_is_no_active_app
+ *
+ * Description  Find whether or not  any APP is still in use
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+static bool btif_hl_is_no_active_app(void) {
+  bool no_active_app = true;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    if (btif_hl_cb.acb[i].in_use) {
+      no_active_app = false;
+      break;
+    }
+  }
+
+  BTIF_TRACE_DEBUG("%s no_active_app=%d  ", __func__, no_active_app);
+  return no_active_app;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_free_app_idx
+ *
+ * Description free an application control block
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+static void btif_hl_free_app_idx(uint8_t app_idx) {
+  if ((app_idx < BTA_HL_NUM_APPS) && btif_hl_cb.acb[app_idx].in_use) {
+    btif_hl_cb.acb[app_idx].in_use = false;
+    for (size_t i = 0; i < BTA_HL_NUM_MCLS; i++)
+      alarm_free(btif_hl_cb.acb[app_idx].mcb[i].cch_timer);
+    memset(&btif_hl_cb.acb[app_idx], 0, sizeof(btif_hl_app_cb_t));
+  }
+}
+/*******************************************************************************
+ *
+ * Function      btif_hl_set_state
+ *
+ * Description set HL state
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+static void btif_hl_set_state(btif_hl_state_t state) {
+  BTIF_TRACE_DEBUG("btif_hl_set_state:  %d ---> %d ", p_btif_hl_cb->state,
+                   state);
+  p_btif_hl_cb->state = state;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_set_state
+ *
+ * Description get HL state
+ *
+ * Returns      btif_hl_state_t
+ *
+ ******************************************************************************/
+
+static btif_hl_state_t btif_hl_get_state(void) {
+  BTIF_TRACE_DEBUG("btif_hl_get_state:  %d   ", p_btif_hl_cb->state);
+  return p_btif_hl_cb->state;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_find_data_type_idx
+ *
+ * Description  Find the index in the data type table
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+static bool btif_hl_find_data_type_idx(uint16_t data_type, uint8_t* p_idx) {
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < BTIF_HL_DATA_TABLE_SIZE; i++) {
+    if (data_type_table[i].data_type == data_type) {
+      found = true;
+      *p_idx = i;
+      break;
+    }
+  }
+
+  BTIF_TRACE_DEBUG("%s found=%d, data_type=0x%x idx=%d", __func__, found,
+                   data_type, i);
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_get_max_tx_apdu_size
+ *
+ * Description  Find the maximum TX APDU size for the specified data type and
+ *              MDEP role
+ *
+ * Returns      uint16_t
+ *
+ ******************************************************************************/
+uint16_t btif_hl_get_max_tx_apdu_size(tBTA_HL_MDEP_ROLE mdep_role,
+                                      uint16_t data_type) {
+  uint8_t idx;
+  uint16_t max_tx_apdu_size = 0;
+
+  if (btif_hl_find_data_type_idx(data_type, &idx)) {
+    if (mdep_role == BTA_HL_MDEP_ROLE_SOURCE) {
+      max_tx_apdu_size = data_type_table[idx].max_tx_apdu_size;
+    } else {
+      max_tx_apdu_size = data_type_table[idx].max_rx_apdu_size;
+    }
+  } else {
+    if (mdep_role == BTA_HL_MDEP_ROLE_SOURCE) {
+      max_tx_apdu_size = BTIF_HL_DEFAULT_SRC_TX_APDU_SIZE;
+    } else {
+      max_tx_apdu_size = BTIF_HL_DEFAULT_SRC_RX_APDU_SIZE;
+    }
+  }
+
+  BTIF_TRACE_DEBUG("%s mdep_role=%d data_type=0x%4x size=%d", __func__,
+                   mdep_role, data_type, max_tx_apdu_size);
+  return max_tx_apdu_size;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_get_max_rx_apdu_size
+ *
+ * Description  Find the maximum RX APDU size for the specified data type and
+ *              MDEP role
+ *
+ * Returns      uint16_t
+ *
+ ******************************************************************************/
+uint16_t btif_hl_get_max_rx_apdu_size(tBTA_HL_MDEP_ROLE mdep_role,
+                                      uint16_t data_type) {
+  uint8_t idx;
+  uint16_t max_rx_apdu_size = 0;
+
+  if (btif_hl_find_data_type_idx(data_type, &idx)) {
+    if (mdep_role == BTA_HL_MDEP_ROLE_SOURCE) {
+      max_rx_apdu_size = data_type_table[idx].max_rx_apdu_size;
+    } else {
+      max_rx_apdu_size = data_type_table[idx].max_tx_apdu_size;
+    }
+  } else {
+    if (mdep_role == BTA_HL_MDEP_ROLE_SOURCE) {
+      max_rx_apdu_size = BTIF_HL_DEFAULT_SRC_RX_APDU_SIZE;
+    } else {
+      max_rx_apdu_size = BTIF_HL_DEFAULT_SRC_TX_APDU_SIZE;
+    }
+  }
+
+  BTIF_TRACE_DEBUG("%s mdep_role=%d data_type=0x%4x size=%d", __func__,
+                   mdep_role, data_type, max_rx_apdu_size);
+
+  return max_rx_apdu_size;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_if_channel_setup_pending
+ *
+ * Description
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+
+static bool btif_hl_get_bta_mdep_role(bthl_mdep_role_t mdep,
+                                      tBTA_HL_MDEP_ROLE* p) {
+  bool status = true;
+  switch (mdep) {
+    case BTHL_MDEP_ROLE_SOURCE:
+      *p = BTA_HL_MDEP_ROLE_SOURCE;
+      break;
+    case BTHL_MDEP_ROLE_SINK:
+      *p = BTA_HL_MDEP_ROLE_SINK;
+      break;
+    default:
+      *p = BTA_HL_MDEP_ROLE_SOURCE;
+      status = false;
+      break;
+  }
+
+  BTIF_TRACE_DEBUG("%s status=%d bta_mdep_role=%d (%d:btif)", __func__, status,
+                   *p, mdep);
+  return status;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_get_bta_channel_type
+ *
+ * Description convert bthl channel type to BTA DCH channel type
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+
+static bool btif_hl_get_bta_channel_type(bthl_channel_type_t channel_type,
+                                         tBTA_HL_DCH_CFG* p) {
+  bool status = true;
+  switch (channel_type) {
+    case BTHL_CHANNEL_TYPE_RELIABLE:
+      *p = BTA_HL_DCH_CFG_RELIABLE;
+      break;
+    case BTHL_CHANNEL_TYPE_STREAMING:
+      *p = BTA_HL_DCH_CFG_STREAMING;
+      break;
+    case BTHL_CHANNEL_TYPE_ANY:
+      *p = BTA_HL_DCH_CFG_NO_PREF;
+      break;
+    default:
+      status = false;
+      break;
+  }
+  BTIF_TRACE_DEBUG("%s status = %d BTA DCH CFG=%d (1-rel 2-strm", __func__,
+                   status, *p);
+  return status;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_get_next_app_id
+ *
+ * Description get next applcation id
+ *
+ * Returns uint8_t
+ *
+ ******************************************************************************/
+
+static uint8_t btif_hl_get_next_app_id() {
+  uint8_t next_app_id = btif_hl_cb.next_app_id;
+
+  btif_hl_cb.next_app_id++;
+  return next_app_id;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_get_next_channel_id
+ *
+ * Description get next channel id
+ *
+ * Returns int
+ *
+ ******************************************************************************/
+static int btif_hl_get_next_channel_id(uint8_t app_id) {
+  uint16_t next_channel_id = btif_hl_cb.next_channel_id;
+  int channel_id;
+  btif_hl_cb.next_channel_id++;
+  channel_id = (app_id << 16) + next_channel_id;
+  BTIF_TRACE_DEBUG("%s channel_id=0x%08x, app_id=0x%02x next_channel_id=0x%04x",
+                   __func__, channel_id, app_id, next_channel_id);
+  return channel_id;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_get_app_id
+ *
+ * Description get the applicaiton id associated with the channel id
+ *
+ * Returns uint8_t
+ *
+ ******************************************************************************/
+
+static uint8_t btif_hl_get_app_id(int channel_id) {
+  uint8_t app_id = (uint8_t)(channel_id >> 16);
+  BTIF_TRACE_DEBUG("%s channel_id=0x%08x, app_id=0x%02x ", __func__, channel_id,
+                   app_id);
+  return app_id;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_init_next_app_id
+ *
+ * Description initialize the application id
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hl_init_next_app_id(void) { btif_hl_cb.next_app_id = 1; }
+/*******************************************************************************
+ *
+ * Function btif_hl_init_next_channel_id
+ *
+ * Description initialize the channel id
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hl_init_next_channel_id(void) {
+  btif_hl_cb.next_channel_id = 1;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_find_app_idx_using_handle
+ *
+ * Description  Find the applicaiton index using handle
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_app_idx_using_handle(tBTA_HL_APP_HANDLE app_handle,
+                                       uint8_t* p_app_idx) {
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    if (btif_hl_cb.acb[i].in_use &&
+        (btif_hl_cb.acb[i].app_handle == app_handle)) {
+      found = true;
+      *p_app_idx = i;
+      break;
+    }
+  }
+
+  BTIF_TRACE_EVENT("%s status=%d handle=%d app_idx=%d ", __func__, found,
+                   app_handle, i);
+
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_find_app_idx_using_app_id
+ *
+ * Description  Find the applicaiton index using app_id
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_app_idx_using_app_id(uint8_t app_id, uint8_t* p_app_idx) {
+  bool found = false;
+  uint8_t i;
+
+  *p_app_idx = 0;
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    if (btif_hl_cb.acb[i].in_use && (btif_hl_cb.acb[i].app_id == app_id)) {
+      found = true;
+      *p_app_idx = i;
+      break;
+    }
+  }
+
+  BTIF_TRACE_EVENT("%s found=%d app_id=%d app_idx=%d ", __func__, found, app_id,
+                   i);
+
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_find_mcl_idx_using_handle
+ *
+ * Description  Find the MCL index using handle
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_mcl_idx_using_handle(tBTA_HL_MCL_HANDLE mcl_handle,
+                                       uint8_t* p_app_idx, uint8_t* p_mcl_idx) {
+  btif_hl_app_cb_t* p_acb;
+  bool found = false;
+  uint8_t i, j;
+
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+    for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+      if (p_acb->mcb[j].in_use)
+        BTIF_TRACE_DEBUG(
+            "btif_hl_find_mcl_idx_using_handle:app_idx=%d,"
+            "mcl_idx =%d mcl_handle=%d",
+            i, j, p_acb->mcb[j].mcl_handle);
+      if (p_acb->mcb[j].in_use && (p_acb->mcb[j].mcl_handle == mcl_handle)) {
+        found = true;
+        *p_app_idx = i;
+        *p_mcl_idx = j;
+        break;
+      }
+    }
+  }
+  BTIF_TRACE_DEBUG("%s found=%d app_idx=%d mcl_idx=%d", __func__, found, i, j);
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_find_mdl_idx_using_mdl_id
+ *
+ * Description  Find the mdl index using mdl_id
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_mcl_idx_using_mdl_id(uint8_t mdl_id, uint8_t mcl_handle,
+                                       uint8_t* p_app_idx, uint8_t* p_mcl_idx) {
+  btif_hl_app_cb_t* p_acb;
+  btif_hl_mcl_cb_t* p_mcb;
+  bool found = false;
+  uint8_t i, j, x;
+
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+    for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+      if (p_acb->mcb[j].in_use && (p_acb->mcb[j].mcl_handle == mcl_handle)) {
+        p_mcb = &p_acb->mcb[j];
+        BTIF_TRACE_DEBUG(
+            "btif_hl_find_mcl_idx_using_mdl_id: mcl handle found j =%d", j);
+        for (x = 0; x < BTA_HL_NUM_MDLS_PER_MCL; x++) {
+          if (p_mcb->mdl[x].in_use && p_mcb->mdl[x].mdl_id == mdl_id) {
+            BTIF_TRACE_DEBUG("btif_hl_find_mcl_idx_using_mdl_id:found x =%d",
+                             x);
+            found = true;
+            *p_app_idx = i;
+            *p_mcl_idx = j;
+            break;
+          }
+        }
+      }
+    }
+  }
+  BTIF_TRACE_DEBUG("%s found=%d app_idx=%d mcl_idx=%d", __func__, found, i, j);
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_find_mcl_idx_using_deleted_mdl_id
+ *
+ * Description  Find the app index deleted_mdl_id
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_app_idx_using_deleted_mdl_id(uint8_t mdl_id,
+                                               uint8_t* p_app_idx) {
+  btif_hl_app_cb_t* p_acb;
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+    if (p_acb->delete_mdl.active) {
+      BTIF_TRACE_DEBUG("%s: app_idx=%d, mdl_id=%d", __func__, i, mdl_id);
+    }
+    if (p_acb->delete_mdl.active && (p_acb->delete_mdl.mdl_id == mdl_id)) {
+      found = true;
+      *p_app_idx = i;
+      break;
+    }
+  }
+  BTIF_TRACE_DEBUG("%s found=%d app_idx=%d", __func__, found, i);
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_stop_timer_using_handle
+ *
+ * Description  clean control channel cb using handle
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+static void btif_hl_stop_timer_using_handle(tBTA_HL_MCL_HANDLE mcl_handle) {
+  btif_hl_app_cb_t* p_acb;
+  uint8_t i, j;
+
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+    for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+      if (p_acb->mcb[j].in_use && (p_acb->mcb[j].mcl_handle == mcl_handle)) {
+        btif_hl_stop_cch_timer(i, j);
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_find_mcl_idx_using_app_idx
+ *
+ * Description  Find the MCL index using handle
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_mcl_idx_using_app_idx(tBTA_HL_MCL_HANDLE mcl_handle,
+                                        uint8_t p_app_idx, uint8_t* p_mcl_idx) {
+  btif_hl_app_cb_t* p_acb;
+  bool found = false;
+  uint8_t j;
+
+  p_acb = BTIF_HL_GET_APP_CB_PTR(p_app_idx);
+  for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+    if (p_acb->mcb[j].in_use && (p_acb->mcb[j].mcl_handle == mcl_handle)) {
+      found = true;
+      *p_mcl_idx = j;
+      break;
+    }
+  }
+  BTIF_TRACE_DEBUG("%s found=%dmcl_idx=%d", __func__, found, j);
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_clean_mdls_using_app_idx
+ *
+ * Description  clean dch cpntrol bloack using app_idx
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+void btif_hl_clean_mdls_using_app_idx(uint8_t app_idx) {
+  btif_hl_app_cb_t* p_acb;
+  btif_hl_mcl_cb_t* p_mcb;
+  btif_hl_mdl_cb_t* p_dcb;
+  uint8_t j, x, y;
+  bt_bdaddr_t bd_addr;
+
+  p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+  for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+    if (p_acb->mcb[j].in_use) {
+      p_mcb = &p_acb->mcb[j];
+      BTIF_TRACE_DEBUG(
+          "btif_hl_find_mcl_idx_using_mdl_id: mcl handle found j =%d", j);
+      for (x = 0; x < BTA_HL_NUM_MDLS_PER_MCL; x++) {
+        if (p_mcb->mdl[x].in_use) {
+          p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, j, x);
+          btif_hl_release_socket(app_idx, j, x);
+          for (y = 0; y < 6; y++) {
+            bd_addr.address[y] = p_mcb->bd_addr[y];
+          }
+          BTIF_HL_CALL_CBACK(bt_hl_callbacks, channel_state_cb, p_acb->app_id,
+                             &bd_addr, p_dcb->local_mdep_cfg_idx,
+                             p_dcb->channel_id, BTHL_CONN_STATE_DISCONNECTED,
+                             0);
+          btif_hl_clean_mdl_cb(p_dcb);
+          if (!btif_hl_num_dchs_in_use(p_mcb->mcl_handle))
+            BTA_HlCchClose(p_mcb->mcl_handle);
+          BTIF_TRACE_DEBUG("remote DCH close success mdl_idx=%d", x);
+        }
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_find_app_idx
+ *
+ * Description  Find the application index using application ID
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_app_idx(uint8_t app_id, uint8_t* p_app_idx) {
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    if (btif_hl_cb.acb[i].in_use && (btif_hl_cb.acb[i].app_id == app_id)) {
+      found = true;
+      *p_app_idx = i;
+      break;
+    }
+  }
+  BTIF_TRACE_DEBUG("%s found=%d app_idx=%d", __func__, found, i);
+
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_find_app_idx
+ *
+ * Description  Find the application index using application ID
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_app_idx_using_mdepId(uint8_t mdep_id, uint8_t* p_app_idx) {
+  bool found = false;
+  uint8_t i;
+
+  *p_app_idx = 0;
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    BTIF_TRACE_DEBUG("btif_hl_find_app_idx_using_mdepId: MDEP-ID = %d",
+                     btif_hl_cb.acb[i].sup_feature.mdep[0].mdep_id);
+    if (btif_hl_cb.acb[i].in_use &&
+        (btif_hl_cb.acb[i].sup_feature.mdep[0].mdep_id == mdep_id)) {
+      found = true;
+      *p_app_idx = i;
+      break;
+    }
+  }
+  BTIF_TRACE_DEBUG("%s found=%d app_idx=%d", __func__, found, i);
+
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_find_avail_mdl_idx
+ *
+ * Description  Find a not in-use MDL index
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_avail_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
+                                uint8_t* p_mdl_idx) {
+  btif_hl_mcl_cb_t* p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+    if (!p_mcb->mdl[i].in_use) {
+      btif_hl_clean_mdl_cb(&p_mcb->mdl[i]);
+      found = true;
+      *p_mdl_idx = i;
+      break;
+    }
+  }
+
+  BTIF_TRACE_DEBUG("%s found=%d idx=%d", __func__, found, i);
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_find_avail_mcl_idx
+ *
+ * Description  Find a not in-use MDL index
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_avail_mcl_idx(uint8_t app_idx, uint8_t* p_mcl_idx) {
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_MCLS; i++) {
+    if (!btif_hl_cb.acb[app_idx].mcb[i].in_use) {
+      found = true;
+      *p_mcl_idx = i;
+      break;
+    }
+  }
+  BTIF_TRACE_DEBUG("%s found=%d mcl_idx=%d", __func__, found, i);
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_find_avail_app_idx
+ *
+ * Description  Find a not in-use APP index
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+static bool btif_hl_find_avail_app_idx(uint8_t* p_idx) {
+  bool found = false;
+  uint8_t i;
+
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    if (!btif_hl_cb.acb[i].in_use) {
+      found = true;
+      *p_idx = i;
+      break;
+    }
+  }
+
+  BTIF_TRACE_DEBUG("%s found=%d app_idx=%d", __func__, found, i);
+  return found;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_proc_dereg_cfm
+ *
+ * Description      Process the de-registration confirmation
+ *
+ * Returns          Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_dereg_cfm(tBTA_HL* p_data)
+
+{
+  btif_hl_app_cb_t* p_acb;
+  uint8_t app_idx;
+  int app_id = 0;
+  bthl_app_reg_state_t state = BTHL_APP_REG_STATE_DEREG_SUCCESS;
+
+  BTIF_TRACE_DEBUG("%s de-reg status=%d app_handle=%d", __func__,
+                   p_data->dereg_cfm.status, p_data->dereg_cfm.app_handle);
+
+  if (btif_hl_find_app_idx_using_app_id(p_data->dereg_cfm.app_id, &app_idx)) {
+    p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+    app_id = (int)p_acb->app_id;
+    if (p_data->dereg_cfm.status == BTA_HL_STATUS_OK) {
+      btif_hl_clean_mdls_using_app_idx(app_idx);
+      for (size_t i = 0; i < BTA_HL_NUM_MCLS; i++)
+        alarm_free(p_acb->mcb[i].cch_timer);
+      memset(p_acb, 0, sizeof(btif_hl_app_cb_t));
+    } else
+      state = BTHL_APP_REG_STATE_DEREG_FAILED;
+
+    BTIF_TRACE_DEBUG("call reg state callback app_id=%d state=%d", app_id,
+                     state);
+    BTIF_HL_CALL_CBACK(bt_hl_callbacks, app_reg_state_cb, app_id, state);
+
+    if (btif_hl_is_no_active_app()) {
+      btif_hl_disable();
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_proc_reg_cfm
+ *
+ * Description      Process the registration confirmation
+ *
+ * Returns          Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_reg_cfm(tBTA_HL* p_data) {
+  btif_hl_app_cb_t* p_acb;
+  uint8_t app_idx;
+  bthl_app_reg_state_t state = BTHL_APP_REG_STATE_REG_SUCCESS;
+
+  BTIF_TRACE_DEBUG("%s reg status=%d app_handle=%d", __func__,
+                   p_data->reg_cfm.status, p_data->reg_cfm.app_handle);
+
+  if (btif_hl_find_app_idx(p_data->reg_cfm.app_id, &app_idx)) {
+    p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+    if (p_data->reg_cfm.status == BTA_HL_STATUS_OK) {
+      p_acb->app_handle = p_data->reg_cfm.app_handle;
+    } else {
+      btif_hl_free_app_idx(app_idx);
+      state = BTHL_APP_REG_STATE_REG_FAILED;
+    }
+
+    BTIF_TRACE_DEBUG("%s call reg state callback app_id=%d reg state=%d",
+                     __func__, p_data->reg_cfm.app_id, state);
+    BTIF_HL_CALL_CBACK(bt_hl_callbacks, app_reg_state_cb,
+                       ((int)p_data->reg_cfm.app_id), state);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_set_chan_cb_state
+ *
+ * Description set the channel callback state
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_set_chan_cb_state(uint8_t app_idx, uint8_t mcl_idx,
+                               btif_hl_chan_cb_state_t state) {
+  btif_hl_pending_chan_cb_t* p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+  btif_hl_chan_cb_state_t cur_state = p_pcb->cb_state;
+
+  if (cur_state != state) {
+    p_pcb->cb_state = state;
+    BTIF_TRACE_DEBUG("%s state %d--->%d", __func__, cur_state, state);
+  }
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_send_destroyed_cb
+ *
+ * Description send the channel destroyed callback
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_send_destroyed_cb(btif_hl_app_cb_t* p_acb) {
+  bt_bdaddr_t bd_addr;
+  int app_id = (int)btif_hl_get_app_id(p_acb->delete_mdl.channel_id);
+
+  btif_hl_copy_bda(&bd_addr, p_acb->delete_mdl.bd_addr);
+  BTIF_TRACE_DEBUG("%s", __func__);
+  BTIF_TRACE_DEBUG(
+      "call channel state callback channel_id=0x%08x mdep_cfg_idx=%d, state=%d "
+      "fd=%d",
+      p_acb->delete_mdl.channel_id, p_acb->delete_mdl.mdep_cfg_idx,
+      BTHL_CONN_STATE_DESTROYED, 0);
+  btif_hl_display_bt_bda(&bd_addr);
+
+  BTIF_HL_CALL_CBACK(bt_hl_callbacks, channel_state_cb, app_id, &bd_addr,
+                     p_acb->delete_mdl.mdep_cfg_idx,
+                     p_acb->delete_mdl.channel_id, BTHL_CONN_STATE_DESTROYED,
+                     0);
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_send_disconnecting_cb
+ *
+ * Description send a channel disconnecting callback
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_send_disconnecting_cb(uint8_t app_idx, uint8_t mcl_idx,
+                                   uint8_t mdl_idx) {
+  btif_hl_mdl_cb_t* p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  btif_hl_soc_cb_t* p_scb = p_dcb->p_scb;
+  bt_bdaddr_t bd_addr;
+  int app_id = (int)btif_hl_get_app_id(p_scb->channel_id);
+
+  btif_hl_copy_bda(&bd_addr, p_scb->bd_addr);
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+  BTIF_TRACE_DEBUG(
+      "call channel state callback  channel_id=0x%08x mdep_cfg_idx=%d, "
+      "state=%d fd=%d",
+      p_scb->channel_id, p_scb->mdep_cfg_idx, BTHL_CONN_STATE_DISCONNECTING,
+      p_scb->socket_id[0]);
+  btif_hl_display_bt_bda(&bd_addr);
+  BTIF_HL_CALL_CBACK(bt_hl_callbacks, channel_state_cb, app_id, &bd_addr,
+                     p_scb->mdep_cfg_idx, p_scb->channel_id,
+                     BTHL_CONN_STATE_DISCONNECTING, p_scb->socket_id[0]);
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_send_setup_connecting_cb
+ *
+ * Description send a channel connecting callback
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_send_setup_connecting_cb(uint8_t app_idx, uint8_t mcl_idx) {
+  btif_hl_pending_chan_cb_t* p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+  bt_bdaddr_t bd_addr;
+  int app_id = (int)btif_hl_get_app_id(p_pcb->channel_id);
+
+  btif_hl_copy_bda(&bd_addr, p_pcb->bd_addr);
+
+  if (p_pcb->in_use &&
+      p_pcb->cb_state == BTIF_HL_CHAN_CB_STATE_CONNECTING_PENDING) {
+    BTIF_TRACE_DEBUG("%s", __func__);
+    BTIF_TRACE_DEBUG(
+        "call channel state callback  channel_id=0x%08x mdep_cfg_idx=%d "
+        "state=%d fd=%d",
+        p_pcb->channel_id, p_pcb->mdep_cfg_idx, BTHL_CONN_STATE_CONNECTING, 0);
+    btif_hl_display_bt_bda(&bd_addr);
+
+    BTIF_HL_CALL_CBACK(bt_hl_callbacks, channel_state_cb, app_id, &bd_addr,
+                       p_pcb->mdep_cfg_idx, p_pcb->channel_id,
+                       BTHL_CONN_STATE_CONNECTING, 0);
+    btif_hl_set_chan_cb_state(app_idx, mcl_idx,
+                              BTIF_HL_CHAN_CB_STATE_CONNECTED_PENDING);
+  }
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_send_setup_disconnected_cb
+ *
+ * Description send a channel disconnected callback
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_send_setup_disconnected_cb(uint8_t app_idx, uint8_t mcl_idx) {
+  btif_hl_pending_chan_cb_t* p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+  bt_bdaddr_t bd_addr;
+  int app_id = (int)btif_hl_get_app_id(p_pcb->channel_id);
+
+  btif_hl_copy_bda(&bd_addr, p_pcb->bd_addr);
+
+  BTIF_TRACE_DEBUG("%s p_pcb->in_use=%d", __func__, p_pcb->in_use);
+  if (p_pcb->in_use) {
+    BTIF_TRACE_DEBUG("%p_pcb->cb_state=%d", p_pcb->cb_state);
+    if (p_pcb->cb_state == BTIF_HL_CHAN_CB_STATE_CONNECTING_PENDING) {
+      BTIF_TRACE_DEBUG(
+          "call channel state callback  channel_id=0x%08x mdep_cfg_idx=%d "
+          "state=%d fd=%d",
+          p_pcb->channel_id, p_pcb->mdep_cfg_idx, BTHL_CONN_STATE_CONNECTING,
+          0);
+      btif_hl_display_bt_bda(&bd_addr);
+      BTIF_HL_CALL_CBACK(bt_hl_callbacks, channel_state_cb, app_id, &bd_addr,
+                         p_pcb->mdep_cfg_idx, p_pcb->channel_id,
+                         BTHL_CONN_STATE_CONNECTING, 0);
+
+      BTIF_TRACE_DEBUG(
+          "call channel state callback  channel_id=0x%08x mdep_cfg_idx=%d "
+          "state=%d fd=%d",
+          p_pcb->channel_id, p_pcb->mdep_cfg_idx, BTHL_CONN_STATE_DISCONNECTED,
+          0);
+      btif_hl_display_bt_bda(&bd_addr);
+      BTIF_HL_CALL_CBACK(bt_hl_callbacks, channel_state_cb, app_id, &bd_addr,
+                         p_pcb->mdep_cfg_idx, p_pcb->channel_id,
+                         BTHL_CONN_STATE_DISCONNECTED, 0);
+    } else if (p_pcb->cb_state == BTIF_HL_CHAN_CB_STATE_CONNECTED_PENDING) {
+      BTIF_TRACE_DEBUG(
+          "call channel state callback  channel_id=0x%08x mdep_cfg_idx=%d "
+          "state=%d fd=%d",
+          p_pcb->channel_id, p_pcb->mdep_cfg_idx, BTHL_CONN_STATE_DISCONNECTED,
+          0);
+      btif_hl_display_bt_bda(&bd_addr);
+      BTIF_HL_CALL_CBACK(bt_hl_callbacks, channel_state_cb, app_id, &bd_addr,
+                         p_pcb->mdep_cfg_idx, p_pcb->channel_id,
+                         BTHL_CONN_STATE_DISCONNECTED, 0);
+    }
+    btif_hl_clean_pcb(p_pcb);
+  }
+}
+/*******************************************************************************
+ *
+ * Function         btif_hl_proc_sdp_query_cfm
+ *
+ * Description      Process the SDP query confirmation
+ *
+ * Returns          Nothing
+ *
+ ******************************************************************************/
+static bool btif_hl_proc_sdp_query_cfm(tBTA_HL* p_data) {
+  btif_hl_app_cb_t* p_acb;
+  btif_hl_mcl_cb_t* p_mcb;
+  tBTA_HL_SDP* p_sdp;
+  tBTA_HL_CCH_OPEN_PARAM open_param;
+  uint8_t app_idx, mcl_idx, sdp_idx = 0;
+  uint8_t num_recs, i, num_mdeps, j;
+  btif_hl_cch_op_t old_cch_oper;
+  bool status = false;
+  btif_hl_pending_chan_cb_t* p_pcb;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  p_sdp = p_data->sdp_query_cfm.p_sdp;
+  num_recs = p_sdp->num_recs;
+
+  BTIF_TRACE_DEBUG("num of SDP records=%d", num_recs);
+  for (i = 0; i < num_recs; i++) {
+    BTIF_TRACE_DEBUG("rec_idx=%d ctrl_psm=0x%x data_psm=0x%x", (i + 1),
+                     p_sdp->sdp_rec[i].ctrl_psm, p_sdp->sdp_rec[i].data_psm);
+    BTIF_TRACE_DEBUG("MCAP supported procedures=0x%x",
+                     p_sdp->sdp_rec[i].mcap_sup_proc);
+    num_mdeps = p_sdp->sdp_rec[i].num_mdeps;
+    BTIF_TRACE_DEBUG("num of mdeps =%d", num_mdeps);
+    for (j = 0; j < num_mdeps; j++) {
+      BTIF_TRACE_DEBUG("mdep_idx=%d mdep_id=0x%x data_type=0x%x mdep_role=0x%x",
+                       (j + 1), p_sdp->sdp_rec[i].mdep_cfg[j].mdep_id,
+                       p_sdp->sdp_rec[i].mdep_cfg[j].data_type,
+                       p_sdp->sdp_rec[i].mdep_cfg[j].mdep_role);
+    }
+  }
+
+  if (btif_hl_find_app_idx_using_app_id(p_data->sdp_query_cfm.app_id,
+                                        &app_idx)) {
+    p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+
+    if (btif_hl_find_mcl_idx(app_idx, p_data->sdp_query_cfm.bd_addr,
+                             &mcl_idx)) {
+      p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+      if (p_mcb->cch_oper != BTIF_HL_CCH_OP_NONE) {
+        memcpy(&p_mcb->sdp, p_sdp, sizeof(tBTA_HL_SDP));
+        old_cch_oper = p_mcb->cch_oper;
+        p_mcb->cch_oper = BTIF_HL_CCH_OP_NONE;
+
+        switch (old_cch_oper) {
+          case BTIF_HL_CCH_OP_MDEP_FILTERING:
+            status = btif_hl_find_sdp_idx_using_mdep_filter(app_idx, mcl_idx,
+                                                            &sdp_idx);
+            break;
+          default:
+            break;
+        }
+
+        if (status) {
+          p_mcb->sdp_idx = sdp_idx;
+          p_mcb->valid_sdp_idx = true;
+          p_mcb->ctrl_psm = p_mcb->sdp.sdp_rec[sdp_idx].ctrl_psm;
+
+          switch (old_cch_oper) {
+            case BTIF_HL_CCH_OP_MDEP_FILTERING:
+              p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+              if (p_pcb->in_use) {
+                if (!p_pcb->abort_pending) {
+                  switch (p_pcb->op) {
+                    case BTIF_HL_PEND_DCH_OP_OPEN:
+                      btif_hl_send_setup_connecting_cb(app_idx, mcl_idx);
+                      break;
+                    case BTIF_HL_PEND_DCH_OP_DELETE_MDL:
+                    default:
+                      break;
+                  }
+                  open_param.ctrl_psm = p_mcb->ctrl_psm;
+                  bdcpy(open_param.bd_addr, p_mcb->bd_addr);
+                  open_param.sec_mask =
+                      (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+                  BTA_HlCchOpen(p_acb->app_id, p_acb->app_handle, &open_param);
+                } else {
+                  BTIF_TRACE_DEBUG("channel abort pending");
+                }
+              }
+              break;
+
+            case BTIF_HL_CCH_OP_DCH_OPEN:
+              status = btif_hl_proc_pending_op(app_idx, mcl_idx);
+              break;
+
+            default:
+              BTIF_TRACE_ERROR("Invalid CCH oper %d", old_cch_oper);
+              break;
+          }
+        } else {
+          BTIF_TRACE_ERROR("Can not find SDP idx discard CCH Open request");
+        }
+      }
+    }
+  }
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_proc_cch_open_ind
+ *
+ * Description      Process the CCH open indication
+ *
+ * Returns          Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_cch_open_ind(tBTA_HL* p_data)
+
+{
+  btif_hl_mcl_cb_t* p_mcb;
+  uint8_t mcl_idx;
+  int i;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    if (btif_hl_cb.acb[i].in_use) {
+      if (!btif_hl_find_mcl_idx(i, p_data->cch_open_ind.bd_addr, &mcl_idx)) {
+        if (btif_hl_find_avail_mcl_idx(i, &mcl_idx)) {
+          p_mcb = BTIF_HL_GET_MCL_CB_PTR(i, mcl_idx);
+          alarm_free(p_mcb->cch_timer);
+          memset(p_mcb, 0, sizeof(btif_hl_mcl_cb_t));
+          p_mcb->in_use = true;
+          p_mcb->is_connected = true;
+          p_mcb->mcl_handle = p_data->cch_open_ind.mcl_handle;
+          bdcpy(p_mcb->bd_addr, p_data->cch_open_ind.bd_addr);
+          btif_hl_start_cch_timer(i, mcl_idx);
+        }
+      } else {
+        BTIF_TRACE_ERROR("The MCL already exist for cch_open_ind");
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_proc_pending_op
+ *
+ * Description      Process the pending dch operation.
+ *
+ * Returns          Nothing
+ *
+ ******************************************************************************/
+bool btif_hl_proc_pending_op(uint8_t app_idx, uint8_t mcl_idx)
+
+{
+  btif_hl_app_cb_t* p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+  btif_hl_mcl_cb_t* p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  btif_hl_pending_chan_cb_t* p_pcb;
+  bool status = false;
+  tBTA_HL_DCH_OPEN_PARAM dch_open;
+  tBTA_HL_MDL_ID mdl_id;
+  tBTA_HL_DCH_RECONNECT_PARAM reconnect_param;
+
+  p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+  if (p_pcb->in_use) {
+    switch (p_pcb->op) {
+      case BTIF_HL_PEND_DCH_OP_OPEN:
+        if (!p_pcb->abort_pending) {
+          BTIF_TRACE_DEBUG("op BTIF_HL_PEND_DCH_OP_OPEN");
+          dch_open.ctrl_psm = p_mcb->ctrl_psm;
+          dch_open.local_mdep_id =
+              p_acb->sup_feature.mdep[p_pcb->mdep_cfg_idx].mdep_id;
+          if (btif_hl_find_peer_mdep_id(
+                  p_acb->app_id, p_mcb->bd_addr,
+                  p_acb->sup_feature.mdep[p_pcb->mdep_cfg_idx]
+                      .mdep_cfg.mdep_role,
+                  p_acb->sup_feature.mdep[p_pcb->mdep_cfg_idx]
+                      .mdep_cfg.data_cfg[0]
+                      .data_type,
+                  &dch_open.peer_mdep_id)) {
+            dch_open.local_cfg = p_acb->channel_type[p_pcb->mdep_cfg_idx];
+            if ((p_acb->sup_feature.mdep[p_pcb->mdep_cfg_idx]
+                     .mdep_cfg.mdep_role == BTA_HL_MDEP_ROLE_SOURCE) &&
+                !btif_hl_is_the_first_reliable_existed(app_idx, mcl_idx)) {
+              dch_open.local_cfg = BTA_HL_DCH_CFG_RELIABLE;
+            }
+            dch_open.sec_mask = (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+            BTIF_TRACE_DEBUG("dch_open.local_cfg=%d  ", dch_open.local_cfg);
+            btif_hl_send_setup_connecting_cb(app_idx, mcl_idx);
+
+            if (!btif_hl_is_reconnect_possible(app_idx, mcl_idx,
+                                               p_pcb->mdep_cfg_idx, &dch_open,
+                                               &mdl_id)) {
+              BTIF_TRACE_DEBUG("Issue DCH open, mcl_handle=%d",
+                               p_mcb->mcl_handle);
+              BTA_HlDchOpen(p_mcb->mcl_handle, &dch_open);
+            } else {
+              reconnect_param.ctrl_psm = p_mcb->ctrl_psm;
+              reconnect_param.mdl_id = mdl_id;
+              ;
+              BTIF_TRACE_DEBUG("Issue Reconnect ctrl_psm=0x%x mdl_id=0x%x",
+                               reconnect_param.ctrl_psm,
+                               reconnect_param.mdl_id);
+              BTA_HlDchReconnect(p_mcb->mcl_handle, &reconnect_param);
+            }
+            status = true;
+          }
+        } else {
+          btif_hl_send_setup_disconnected_cb(app_idx, mcl_idx);
+          status = true;
+        }
+        break;
+      case BTIF_HL_PEND_DCH_OP_DELETE_MDL:
+        BTA_HlDeleteMdl(p_mcb->mcl_handle, p_acb->delete_mdl.mdl_id);
+        status = true;
+        break;
+
+      default:
+        break;
+    }
+  }
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_proc_cch_open_cfm
+ *
+ * Description      Process the CCH open confirmation
+ *
+ * Returns          Nothing
+ *
+ ******************************************************************************/
+static bool btif_hl_proc_cch_open_cfm(tBTA_HL* p_data)
+
+{
+  btif_hl_mcl_cb_t* p_mcb;
+  uint8_t app_idx, mcl_idx;
+  bool status = false;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  if (btif_hl_find_app_idx_using_app_id(p_data->cch_open_cfm.app_id,
+                                        &app_idx)) {
+    BTIF_TRACE_DEBUG("app_idx=%d", app_idx);
+    if (btif_hl_find_mcl_idx(app_idx, p_data->cch_open_cfm.bd_addr, &mcl_idx)) {
+      p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+      BTIF_TRACE_DEBUG("mcl_idx=%d, mcl_handle=%d", mcl_idx,
+                       p_data->cch_open_cfm.mcl_handle);
+      p_mcb->mcl_handle = p_data->cch_open_cfm.mcl_handle;
+      p_mcb->is_connected = true;
+      status = btif_hl_proc_pending_op(app_idx, mcl_idx);
+      if (status) btif_hl_start_cch_timer(app_idx, mcl_idx);
+    }
+  }
+
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_clean_mcb_using_handle
+ *
+ * Description  clean control channel cb using handle
+ *
+ * Returns      void
+ *
+ ******************************************************************************/
+static void btif_hl_clean_mcb_using_handle(tBTA_HL_MCL_HANDLE mcl_handle) {
+  btif_hl_app_cb_t* p_acb;
+  uint8_t i, j;
+
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+    for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+      if (p_acb->mcb[j].in_use)
+        BTIF_TRACE_DEBUG(
+            "btif_hl_find_mcl_idx_using_handle: app_idx=%d,"
+            "mcl_idx =%d mcl_handle=%d",
+            i, j, p_acb->mcb[j].mcl_handle);
+      if (p_acb->mcb[j].in_use && (p_acb->mcb[j].mcl_handle == mcl_handle)) {
+        btif_hl_stop_cch_timer(i, j);
+        btif_hl_release_mcl_sockets(i, j);
+        btif_hl_send_setup_disconnected_cb(i, j);
+        btif_hl_clean_mcl_cb(i, j);
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_proc_cch_close_ind
+ *
+ * Description      Process the CCH close indication
+ *
+ * Returns          Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_cch_close_ind(tBTA_HL* p_data)
+
+{
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  btif_hl_clean_mcb_using_handle(p_data->cch_close_ind.mcl_handle);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_proc_cch_close_cfm
+ *
+ * Description      Process the CCH close confirmation
+ *
+ * Returns          Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_cch_close_cfm(tBTA_HL* p_data) {
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  btif_hl_clean_mcb_using_handle(p_data->cch_close_ind.mcl_handle);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_proc_create_ind
+ *
+ * Description      Process the MDL create indication
+ *
+ * Returns          Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_create_ind(tBTA_HL* p_data) {
+  btif_hl_app_cb_t* p_acb;
+  btif_hl_mcl_cb_t* p_mcb;
+  tBTA_HL_MDEP* p_mdep;
+  uint8_t orig_app_idx, mcl_idx, mdep_cfg_idx;
+  bool first_reliable_exist;
+  bool success = true;
+  tBTA_HL_DCH_CFG rsp_cfg = BTA_HL_DCH_CFG_UNKNOWN;
+  tBTA_HL_DCH_CREATE_RSP rsp_code = BTA_HL_DCH_CREATE_RSP_CFG_REJ;
+  tBTA_HL_DCH_CREATE_RSP_PARAM create_rsp_param;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  // Find the correct app_idx based on the mdep_id;
+  btif_hl_find_app_idx_using_mdepId(p_data->dch_create_ind.local_mdep_id,
+                                    &orig_app_idx);
+  if (btif_hl_find_mcl_idx(orig_app_idx, p_data->dch_create_ind.bd_addr,
+                           &mcl_idx)) {
+    p_acb = BTIF_HL_GET_APP_CB_PTR(orig_app_idx);
+    p_mcb = BTIF_HL_GET_MCL_CB_PTR(orig_app_idx, mcl_idx);
+
+    if (btif_hl_find_mdep_cfg_idx(orig_app_idx,
+                                  p_data->dch_create_ind.local_mdep_id,
+                                  &mdep_cfg_idx)) {
+      p_mdep = &(p_acb->sup_feature.mdep[mdep_cfg_idx]);
+      first_reliable_exist =
+          btif_hl_is_the_first_reliable_existed(orig_app_idx, mcl_idx);
+      switch (p_mdep->mdep_cfg.mdep_role) {
+        case BTA_HL_MDEP_ROLE_SOURCE:
+          if (p_data->dch_create_ind.cfg == BTA_HL_DCH_CFG_NO_PREF) {
+            if (first_reliable_exist) {
+              rsp_cfg = p_acb->channel_type[mdep_cfg_idx];
+            } else {
+              rsp_cfg = BTA_HL_DCH_CFG_RELIABLE;
+            }
+            rsp_code = BTA_HL_DCH_CREATE_RSP_SUCCESS;
+          }
+
+          break;
+        case BTA_HL_MDEP_ROLE_SINK:
+
+          BTIF_TRACE_DEBUG("btif_hl_proc_create_ind:BTA_HL_MDEP_ROLE_SINK");
+          if ((p_data->dch_create_ind.cfg == BTA_HL_DCH_CFG_RELIABLE) ||
+              (first_reliable_exist &&
+               (p_data->dch_create_ind.cfg == BTA_HL_DCH_CFG_STREAMING))) {
+            rsp_code = BTA_HL_DCH_CREATE_RSP_SUCCESS;
+            rsp_cfg = p_data->dch_create_ind.cfg;
+            BTIF_TRACE_DEBUG(
+                "btif_hl_proc_create_ind:BTA_HL_MDEP_ROLE_SINK cfg = %d",
+                rsp_cfg);
+          }
+          break;
+        default:
+          break;
+      }
+    }
+  } else {
+    success = false;
+  }
+
+  if (success) {
+    BTIF_TRACE_DEBUG("create response rsp_code=%d rsp_cfg=%d", rsp_code,
+                     rsp_cfg);
+    create_rsp_param.local_mdep_id = p_data->dch_create_ind.local_mdep_id;
+    create_rsp_param.mdl_id = p_data->dch_create_ind.mdl_id;
+    create_rsp_param.rsp_code = rsp_code;
+    create_rsp_param.cfg_rsp = rsp_cfg;
+    BTA_HlDchCreateRsp(p_mcb->mcl_handle, &create_rsp_param);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_proc_dch_open_ind
+ *
+ * Description      Process the DCH open indication
+ *
+ * Returns          Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_dch_open_ind(tBTA_HL* p_data)
+
+{
+  btif_hl_mdl_cb_t* p_dcb;
+  uint8_t orig_app_idx, mcl_idx, mdl_idx, mdep_cfg_idx;
+  bool close_dch = false;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  // Find the correct app_idx based on the mdep_id;
+  btif_hl_find_app_idx_using_mdepId(p_data->dch_open_ind.local_mdep_id,
+                                    &orig_app_idx);
+
+  if (btif_hl_find_mcl_idx_using_app_idx(p_data->dch_open_ind.mcl_handle,
+                                         orig_app_idx, &mcl_idx)) {
+    if (btif_hl_find_avail_mdl_idx(orig_app_idx, mcl_idx, &mdl_idx)) {
+      p_dcb = BTIF_HL_GET_MDL_CB_PTR(orig_app_idx, mcl_idx, mdl_idx);
+
+      if (btif_hl_find_mdep_cfg_idx(orig_app_idx,
+                                    p_data->dch_open_ind.local_mdep_id,
+                                    &mdep_cfg_idx)) {
+        p_dcb->in_use = true;
+        p_dcb->mdl_handle = p_data->dch_open_ind.mdl_handle;
+        p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+        p_dcb->local_mdep_id = p_data->dch_open_ind.local_mdep_id;
+        p_dcb->mdl_id = p_data->dch_open_ind.mdl_id;
+        p_dcb->dch_mode = p_data->dch_open_ind.dch_mode;
+        p_dcb->dch_mode = p_data->dch_open_ind.dch_mode;
+        p_dcb->is_the_first_reliable = p_data->dch_open_ind.first_reliable;
+        p_dcb->mtu = p_data->dch_open_ind.mtu;
+
+        if (btif_hl_find_channel_id_using_mdl_id(orig_app_idx, p_dcb->mdl_id,
+                                                 &p_dcb->channel_id)) {
+          BTIF_TRACE_DEBUG(" app_idx=%d mcl_idx=%d mdl_idx=%d channel_id=%d",
+                           orig_app_idx, mcl_idx, mdl_idx, p_dcb->channel_id);
+          if (!btif_hl_create_socket(orig_app_idx, mcl_idx, mdl_idx)) {
+            BTIF_TRACE_ERROR("Unable to create socket");
+            close_dch = true;
+          }
+        } else {
+          BTIF_TRACE_ERROR("Unable find channel id for mdl_id=0x%x",
+                           p_dcb->mdl_id);
+          close_dch = true;
+        }
+      } else {
+        BTIF_TRACE_ERROR("INVALID_LOCAL_MDEP_ID mdep_id=%d",
+                         p_data->dch_open_cfm.local_mdep_id);
+        close_dch = true;
+      }
+
+      if (close_dch) btif_hl_clean_mdl_cb(p_dcb);
+    } else
+      close_dch = true;
+  } else
+    close_dch = true;
+
+  if (close_dch) BTA_HlDchClose(p_data->dch_open_cfm.mdl_handle);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_proc_dch_open_cfm
+ *
+ * Description      Process the DCH close confirmation
+ *
+ * Returns          Nothing
+ *
+ ******************************************************************************/
+static bool btif_hl_proc_dch_open_cfm(tBTA_HL* p_data)
+
+{
+  btif_hl_mdl_cb_t* p_dcb;
+  btif_hl_pending_chan_cb_t* p_pcb;
+  uint8_t app_idx, mcl_idx, mdl_idx, mdep_cfg_idx;
+  bool status = false;
+  bool close_dch = false;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  // Find the correct app_idx based on the mdep_id;
+  btif_hl_find_app_idx_using_mdepId(p_data->dch_open_cfm.local_mdep_id,
+                                    &app_idx);
+
+  if (btif_hl_find_mcl_idx_using_app_idx(p_data->dch_open_cfm.mcl_handle,
+                                         app_idx, &mcl_idx)) {
+    p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+
+    if (btif_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
+      p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+      if (btif_hl_find_mdep_cfg_idx(app_idx, p_data->dch_open_cfm.local_mdep_id,
+                                    &mdep_cfg_idx)) {
+        p_dcb->in_use = true;
+        p_dcb->mdl_handle = p_data->dch_open_cfm.mdl_handle;
+        p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+        p_dcb->local_mdep_id = p_data->dch_open_cfm.local_mdep_id;
+        p_dcb->mdl_id = p_data->dch_open_cfm.mdl_id;
+        p_dcb->dch_mode = p_data->dch_open_cfm.dch_mode;
+        p_dcb->is_the_first_reliable = p_data->dch_open_cfm.first_reliable;
+        p_dcb->mtu = p_data->dch_open_cfm.mtu;
+        p_dcb->channel_id = p_pcb->channel_id;
+
+        BTIF_TRACE_DEBUG("app_idx=%d mcl_idx=%d mdl_idx=%d", app_idx, mcl_idx,
+                         mdl_idx);
+        btif_hl_send_setup_connecting_cb(app_idx, mcl_idx);
+        if (btif_hl_create_socket(app_idx, mcl_idx, mdl_idx)) {
+          status = true;
+          BTIF_TRACE_DEBUG(
+              "app_idx=%d mcl_idx=%d mdl_idx=%d p_dcb->channel_id=0x%08x",
+              app_idx, mcl_idx, mdl_idx, p_dcb->channel_id);
+          btif_hl_clean_pcb(p_pcb);
+        } else {
+          BTIF_TRACE_ERROR("Unable to create socket");
+          close_dch = true;
+        }
+      } else {
+        BTIF_TRACE_ERROR("INVALID_LOCAL_MDEP_ID mdep_id=%d",
+                         p_data->dch_open_cfm.local_mdep_id);
+        close_dch = true;
+      }
+
+      if (close_dch) {
+        btif_hl_clean_mdl_cb(p_dcb);
+        BTA_HlDchClose(p_data->dch_open_cfm.mdl_handle);
+      }
+    }
+  }
+
+  return status;
+}
+/*******************************************************************************
+ *
+ * Function         btif_hl_proc_dch_reconnect_cfm
+ *
+ * Description      Process the DCH reconnect indication
+ *
+ * Returns          Nothing
+ *
+ ******************************************************************************/
+static bool btif_hl_proc_dch_reconnect_cfm(tBTA_HL* p_data) {
+  btif_hl_mdl_cb_t* p_dcb;
+  btif_hl_pending_chan_cb_t* p_pcb;
+  uint8_t app_idx, mcl_idx, mdl_idx, mdep_cfg_idx;
+  bool status = false;
+  bool close_dch = false;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  btif_hl_find_app_idx_using_mdepId(p_data->dch_reconnect_cfm.local_mdep_id,
+                                    &app_idx);
+
+  if (btif_hl_find_mcl_idx_using_app_idx(p_data->dch_reconnect_cfm.mcl_handle,
+                                         app_idx, &mcl_idx)) {
+    p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+
+    if (btif_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
+      p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+      if (btif_hl_find_mdep_cfg_idx(app_idx,
+                                    p_data->dch_reconnect_cfm.local_mdep_id,
+                                    &mdep_cfg_idx)) {
+        p_dcb->in_use = true;
+        p_dcb->mdl_handle = p_data->dch_reconnect_cfm.mdl_handle;
+        p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+        p_dcb->local_mdep_id = p_data->dch_reconnect_cfm.local_mdep_id;
+        p_dcb->mdl_id = p_data->dch_reconnect_cfm.mdl_id;
+        p_dcb->dch_mode = p_data->dch_reconnect_cfm.dch_mode;
+        p_dcb->is_the_first_reliable = p_data->dch_reconnect_cfm.first_reliable;
+        p_dcb->mtu = p_data->dch_reconnect_cfm.mtu;
+        p_dcb->channel_id = p_pcb->channel_id;
+
+        BTIF_TRACE_DEBUG("app_idx=%d mcl_idx=%d mdl_idx=%d", app_idx, mcl_idx,
+                         mdl_idx);
+        btif_hl_send_setup_connecting_cb(app_idx, mcl_idx);
+        if (btif_hl_create_socket(app_idx, mcl_idx, mdl_idx)) {
+          status = true;
+          BTIF_TRACE_DEBUG(
+              "app_idx=%d mcl_idx=%d mdl_idx=%d p_dcb->channel_id=0x%08x",
+              app_idx, mcl_idx, mdl_idx, p_dcb->channel_id);
+          btif_hl_clean_pcb(p_pcb);
+        } else {
+          BTIF_TRACE_ERROR("Unable to create socket");
+          close_dch = true;
+        }
+      } else {
+        BTIF_TRACE_ERROR("INVALID_LOCAL_MDEP_ID mdep_id=%d",
+                         p_data->dch_open_cfm.local_mdep_id);
+        close_dch = true;
+      }
+
+      if (close_dch) {
+        btif_hl_clean_mdl_cb(p_dcb);
+        BTA_HlDchClose(p_data->dch_reconnect_cfm.mdl_handle);
+      }
+    }
+  }
+
+  return status;
+}
+/*******************************************************************************
+ *
+ * Function         btif_hl_proc_dch_reconnect_ind
+ *
+ * Description      Process the DCH reconnect indication
+ *
+ * Returns          Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_dch_reconnect_ind(tBTA_HL* p_data)
+
+{
+  btif_hl_app_cb_t* p_acb;
+  btif_hl_mdl_cb_t* p_dcb;
+  uint8_t app_idx, mcl_idx, mdl_idx, mdep_cfg_idx;
+  bool close_dch = false;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  // Find the correct app_idx based on the mdep_id;
+  btif_hl_find_app_idx_using_mdepId(p_data->dch_reconnect_ind.local_mdep_id,
+                                    &app_idx);
+
+  if (btif_hl_find_mcl_idx_using_app_idx(p_data->dch_reconnect_ind.mcl_handle,
+                                         app_idx, &mcl_idx)) {
+    p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+    BTIF_TRACE_DEBUG(
+        "btif_hl_proc_dch_reconnect_ind: app_idx = %d, mcl_idx = %d", app_idx,
+        mcl_idx);
+
+    if (btif_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
+      p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+      if (btif_hl_find_mdep_cfg_idx(app_idx,
+                                    p_data->dch_reconnect_ind.local_mdep_id,
+                                    &mdep_cfg_idx)) {
+        p_dcb->in_use = true;
+        p_dcb->mdl_handle = p_data->dch_reconnect_ind.mdl_handle;
+        p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+        p_dcb->local_mdep_id = p_data->dch_reconnect_ind.local_mdep_id;
+        p_dcb->mdl_id = p_data->dch_reconnect_ind.mdl_id;
+        p_dcb->dch_mode = p_data->dch_reconnect_ind.dch_mode;
+        p_dcb->dch_mode = p_data->dch_reconnect_ind.dch_mode;
+        p_dcb->is_the_first_reliable = p_data->dch_reconnect_ind.first_reliable;
+        p_dcb->mtu = p_data->dch_reconnect_ind.mtu;
+        p_dcb->channel_id = btif_hl_get_next_channel_id(p_acb->app_id);
+
+        BTIF_TRACE_DEBUG(" app_idx=%d mcl_idx=%d mdl_idx=%d channel_id=%d",
+                         app_idx, mcl_idx, mdl_idx, p_dcb->channel_id);
+        if (!btif_hl_create_socket(app_idx, mcl_idx, mdl_idx)) {
+          BTIF_TRACE_ERROR("Unable to create socket");
+          close_dch = true;
+        }
+      } else {
+        BTIF_TRACE_ERROR("INVALID_LOCAL_MDEP_ID mdep_id=%d",
+                         p_data->dch_open_cfm.local_mdep_id);
+        close_dch = true;
+      }
+
+      if (close_dch) btif_hl_clean_mdl_cb(p_dcb);
+    } else
+      close_dch = true;
+  } else
+    close_dch = true;
+
+  if (close_dch) BTA_HlDchClose(p_data->dch_reconnect_ind.mdl_handle);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_proc_dch_close_ind
+ *
+ * Description      Process the DCH close indication
+ *
+ * Returns          Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_dch_close_ind(tBTA_HL* p_data)
+
+{
+  btif_hl_mdl_cb_t* p_dcb;
+  btif_hl_mcl_cb_t* p_mcb;
+  uint8_t app_idx, mcl_idx, mdl_idx;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+  if (btif_hl_find_mdl_idx_using_handle(p_data->dch_close_ind.mdl_handle,
+                                        &app_idx, &mcl_idx, &mdl_idx)) {
+    p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+    btif_hl_release_socket(app_idx, mcl_idx, mdl_idx);
+    btif_hl_send_setup_disconnected_cb(app_idx, mcl_idx);
+    p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+    btif_hl_clean_mdl_cb(p_dcb);
+    if (!btif_hl_num_dchs_in_use(p_mcb->mcl_handle))
+      btif_hl_start_cch_timer(app_idx, mcl_idx);
+    BTIF_TRACE_DEBUG("remote DCH close success mdl_idx=%d", mdl_idx);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_proc_dch_close_cfm
+ *
+ * Description      Process the DCH reconnect confirmation
+ *
+ * Returns          Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_dch_close_cfm(tBTA_HL* p_data)
+
+{
+  btif_hl_mdl_cb_t* p_dcb;
+  btif_hl_mcl_cb_t* p_mcb;
+  uint8_t app_idx, mcl_idx, mdl_idx;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+  if (btif_hl_find_mdl_idx_using_handle(p_data->dch_close_cfm.mdl_handle,
+                                        &app_idx, &mcl_idx, &mdl_idx)) {
+    p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+    btif_hl_release_socket(app_idx, mcl_idx, mdl_idx);
+    btif_hl_clean_mdl_cb(p_dcb);
+    p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+    if (!btif_hl_num_dchs_in_use(p_mcb->mcl_handle))
+      btif_hl_start_cch_timer(app_idx, mcl_idx);
+    BTIF_TRACE_DEBUG(" local DCH close success mdl_idx=%d", mdl_idx);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_proc_abort_ind
+ *
+ * Description      Process the abort indicaiton
+ *
+ * Returns          Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_abort_ind(tBTA_HL_MCL_HANDLE mcl_handle) {
+  BTIF_TRACE_DEBUG("%s", __func__);
+  btif_hl_app_cb_t* p_acb;
+  uint8_t i, j;
+
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+    for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+      if (p_acb->mcb[j].in_use)
+        BTIF_TRACE_DEBUG(
+            "btif_hl_find_mcl_idx_using_handle: app_idx=%d,mcl_idx =%d "
+            "mcl_handle=%d",
+            i, j, p_acb->mcb[j].mcl_handle);
+      if (p_acb->mcb[j].in_use && (p_acb->mcb[j].mcl_handle == mcl_handle)) {
+        btif_hl_stop_cch_timer(i, j);
+        btif_hl_send_setup_disconnected_cb(i, j);
+        btif_hl_clean_mcl_cb(i, j);
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_proc_abort_cfm
+ *
+ * Description      Process the abort confirmation
+ *
+ * Returns          Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_abort_cfm(tBTA_HL_MCL_HANDLE mcl_handle) {
+  BTIF_TRACE_DEBUG("%s", __func__);
+  btif_hl_app_cb_t* p_acb;
+  uint8_t i, j;
+
+  for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+    p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+    for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+      if (p_acb->mcb[j].in_use)
+        BTIF_TRACE_DEBUG(
+            "btif_hl_find_mcl_idx_using_handle: app_idx=%d,mcl_idx =%d "
+            "mcl_handle=%d",
+            i, j, p_acb->mcb[j].mcl_handle);
+      if (p_acb->mcb[j].in_use && (p_acb->mcb[j].mcl_handle == mcl_handle)) {
+        btif_hl_stop_cch_timer(i, j);
+        btif_hl_send_setup_disconnected_cb(i, j);
+        btif_hl_clean_mcl_cb(i, j);
+      }
+    }
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_proc_send_data_cfm
+ *
+ * Description      Process the send data confirmation
+ *
+ * Returns          Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_send_data_cfm(tBTA_HL_MDL_HANDLE mdl_handle,
+                                       UNUSED_ATTR tBTA_HL_STATUS status) {
+  uint8_t app_idx, mcl_idx, mdl_idx;
+  btif_hl_mdl_cb_t* p_dcb;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+  if (btif_hl_find_mdl_idx_using_handle(mdl_handle, &app_idx, &mcl_idx,
+                                        &mdl_idx)) {
+    p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+    osi_free_and_reset((void**)&p_dcb->p_tx_pkt);
+    BTIF_TRACE_DEBUG("send success free p_tx_pkt tx_size=%d", p_dcb->tx_size);
+    p_dcb->tx_size = 0;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_proc_dch_cong_ind
+ *
+ * Description      Process the DCH congestion change indication
+ *
+ * Returns          Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_dch_cong_ind(tBTA_HL* p_data)
+
+{
+  btif_hl_mdl_cb_t* p_dcb;
+  uint8_t app_idx, mcl_idx, mdl_idx;
+
+  BTIF_TRACE_DEBUG("btif_hl_proc_dch_cong_ind");
+
+  if (btif_hl_find_mdl_idx_using_handle(p_data->dch_cong_ind.mdl_handle,
+                                        &app_idx, &mcl_idx, &mdl_idx)) {
+    p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+    p_dcb->cong = p_data->dch_cong_ind.cong;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_proc_reg_request
+ *
+ * Description      Process registration request
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_hl_proc_reg_request(uint8_t app_idx, uint8_t app_id,
+                                     tBTA_HL_REG_PARAM* p_reg_param,
+                                     UNUSED_ATTR tBTA_HL_CBACK *p_cback) {
+  BTIF_TRACE_DEBUG("%s app_idx=%d app_id=%d", __func__, app_idx, app_id);
+
+  if (reg_counter > 1) {
+    BTIF_TRACE_DEBUG("btif_hl_proc_reg_request: calling uPDATE");
+    BTA_HlUpdate(app_id, p_reg_param, true, btif_hl_cback);
+  } else
+    BTA_HlRegister(app_id, p_reg_param, btif_hl_cback);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_proc_cb_evt
+ *
+ * Description      Process HL callback events
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_hl_proc_cb_evt(uint16_t event, char* p_param) {
+  btif_hl_evt_cb_t* p_data = (btif_hl_evt_cb_t*)p_param;
+  bt_bdaddr_t bd_addr;
+  bthl_channel_state_t state = BTHL_CONN_STATE_DISCONNECTED;
+  bool send_chan_cb = true;
+  tBTA_HL_REG_PARAM reg_param;
+  btif_hl_app_cb_t* p_acb;
+
+  BTIF_TRACE_DEBUG("%s event %d", __func__, event);
+  btif_hl_display_calling_process_name();
+
+  switch (event) {
+    case BTIF_HL_SEND_CONNECTED_CB:
+    case BTIF_HL_SEND_DISCONNECTED_CB:
+      if (p_data->chan_cb.cb_state == BTIF_HL_CHAN_CB_STATE_CONNECTED_PENDING)
+        state = BTHL_CONN_STATE_CONNECTED;
+      else if (p_data->chan_cb.cb_state ==
+               BTIF_HL_CHAN_CB_STATE_DISCONNECTED_PENDING)
+        state = BTHL_CONN_STATE_DISCONNECTED;
+      else
+        send_chan_cb = false;
+
+      if (send_chan_cb) {
+        btif_hl_copy_bda(&bd_addr, p_data->chan_cb.bd_addr);
+        BTIF_TRACE_DEBUG(
+            "state callbk: ch_id=0x%08x cb_state=%d state=%d  fd=%d",
+            p_data->chan_cb.channel_id, p_data->chan_cb.cb_state, state,
+            p_data->chan_cb.fd);
+        btif_hl_display_bt_bda(&bd_addr);
+        BTIF_HL_CALL_CBACK(
+            bt_hl_callbacks, channel_state_cb, p_data->chan_cb.app_id, &bd_addr,
+            p_data->chan_cb.mdep_cfg_index, p_data->chan_cb.channel_id, state,
+            p_data->chan_cb.fd);
+      }
+
+      break;
+
+    case BTIF_HL_REG_APP:
+      reg_counter++;
+      p_acb = BTIF_HL_GET_APP_CB_PTR(p_data->reg.app_idx);
+      BTIF_TRACE_DEBUG("Rcv BTIF_HL_REG_APP app_idx=%d reg_pending=%d",
+                       p_data->reg.app_idx, p_acb->reg_pending);
+      if (btif_hl_get_state() == BTIF_HL_STATE_ENABLED && p_acb->reg_pending) {
+        BTIF_TRACE_DEBUG("Rcv BTIF_HL_REG_APP reg_counter=%d", reg_counter);
+        p_acb->reg_pending = false;
+        reg_param.dev_type = p_acb->dev_type;
+        reg_param.sec_mask = BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT;
+        reg_param.p_srv_name = p_acb->srv_name;
+        reg_param.p_srv_desp = p_acb->srv_desp;
+        reg_param.p_provider_name = p_acb->provider_name;
+        btif_hl_proc_reg_request(p_data->reg.app_idx, p_acb->app_id, &reg_param,
+                                 btif_hl_cback);
+      } else {
+        BTIF_TRACE_DEBUG("reg request is processed state=%d reg_pending=%d",
+                         btif_hl_get_state(), p_acb->reg_pending);
+      }
+      break;
+
+    case BTIF_HL_UNREG_APP:
+      reg_counter--;
+      BTIF_TRACE_DEBUG("Rcv BTIF_HL_UNREG_APP app_idx=%d",
+                       p_data->unreg.app_idx);
+      p_acb = BTIF_HL_GET_APP_CB_PTR(p_data->unreg.app_idx);
+      if (btif_hl_get_state() == BTIF_HL_STATE_ENABLED) {
+        if (reg_counter >= 1)
+          BTA_HlUpdate(p_acb->app_id, NULL, false, NULL);
+        else
+          BTA_HlDeregister(p_acb->app_id, p_acb->app_handle);
+      }
+      break;
+
+    case BTIF_HL_UPDATE_MDL:
+      BTIF_TRACE_DEBUG("Rcv BTIF_HL_UPDATE_MDL app_idx=%d",
+                       p_data->update_mdl.app_idx);
+      p_acb = BTIF_HL_GET_APP_CB_PTR(p_data->update_mdl.app_idx);
+      break;
+
+    default:
+      BTIF_TRACE_ERROR("Unknown event %d", event);
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_upstreams_evt
+ *
+ * Description      Process HL events
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_hl_upstreams_evt(uint16_t event, char* p_param) {
+  tBTA_HL* p_data = (tBTA_HL*)p_param;
+  uint8_t app_idx, mcl_idx;
+  btif_hl_app_cb_t* p_acb;
+  btif_hl_mcl_cb_t* p_mcb = NULL;
+  btif_hl_pend_dch_op_t pending_op;
+  bool status;
+
+  BTIF_TRACE_DEBUG("%s event %d", __func__, event);
+  btif_hl_display_calling_process_name();
+  switch (event) {
+    case BTA_HL_REGISTER_CFM_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_REGISTER_CFM_EVT");
+      BTIF_TRACE_DEBUG("app_id=%d app_handle=%d status=%d ",
+                       p_data->reg_cfm.app_id, p_data->reg_cfm.app_handle,
+                       p_data->reg_cfm.status);
+
+      btif_hl_proc_reg_cfm(p_data);
+      break;
+    case BTA_HL_SDP_INFO_IND_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_SDP_INFO_IND_EVT");
+      BTIF_TRACE_DEBUG(
+          "app_handle=%d ctrl_psm=0x%04x data_psm=0x%04x x_spec=%d "
+          "mcap_sup_procs=0x%02x",
+          p_data->sdp_info_ind.app_handle, p_data->sdp_info_ind.ctrl_psm,
+          p_data->sdp_info_ind.data_psm, p_data->sdp_info_ind.data_x_spec,
+          p_data->sdp_info_ind.mcap_sup_procs);
+      // btif_hl_proc_sdp_info_ind(p_data);
+      break;
+
+    case BTA_HL_DEREGISTER_CFM_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_DEREGISTER_CFM_EVT");
+      BTIF_TRACE_DEBUG("app_handle=%d status=%d ", p_data->dereg_cfm.app_handle,
+                       p_data->dereg_cfm.status);
+      btif_hl_proc_dereg_cfm(p_data);
+      break;
+
+    case BTA_HL_SDP_QUERY_CFM_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_SDP_QUERY_CFM_EVT");
+      BTIF_TRACE_DEBUG("app_handle=%d app_id =%d,status =%d",
+                       p_data->sdp_query_cfm.app_handle,
+                       p_data->sdp_query_cfm.app_id,
+                       p_data->sdp_query_cfm.status);
+
+      BTIF_TRACE_DEBUG(
+          "DB [%02x] [%02x] [%02x] [%02x] [%02x] [%02x]",
+          p_data->sdp_query_cfm.bd_addr[0], p_data->sdp_query_cfm.bd_addr[1],
+          p_data->sdp_query_cfm.bd_addr[2], p_data->sdp_query_cfm.bd_addr[3],
+          p_data->sdp_query_cfm.bd_addr[4], p_data->sdp_query_cfm.bd_addr[5]);
+
+      if (p_data->sdp_query_cfm.status == BTA_HL_STATUS_OK)
+        status = btif_hl_proc_sdp_query_cfm(p_data);
+      else
+        status = false;
+
+      if (!status) {
+        BTIF_TRACE_DEBUG("BTA_HL_SDP_QUERY_CFM_EVT Status = %d",
+                         p_data->sdp_query_cfm.status);
+        if (btif_hl_find_app_idx_using_app_id(p_data->sdp_query_cfm.app_id,
+                                              &app_idx)) {
+          p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+          if (btif_hl_find_mcl_idx(app_idx, p_data->sdp_query_cfm.bd_addr,
+                                   &mcl_idx)) {
+            p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+            if ((p_mcb->cch_oper == BTIF_HL_CCH_OP_MDEP_FILTERING) ||
+                (p_mcb->cch_oper == BTIF_HL_CCH_OP_DCH_OPEN)) {
+              pending_op = p_mcb->pcb.op;
+              switch (pending_op) {
+                case BTIF_HL_PEND_DCH_OP_OPEN:
+                  btif_hl_send_setup_disconnected_cb(app_idx, mcl_idx);
+                  break;
+                case BTIF_HL_PEND_DCH_OP_RECONNECT:
+                case BTIF_HL_PEND_DCH_OP_DELETE_MDL:
+                default:
+                  break;
+              }
+              if (!p_mcb->is_connected) btif_hl_clean_mcl_cb(app_idx, mcl_idx);
+            }
+          }
+        }
+      }
+
+      break;
+
+    case BTA_HL_CCH_OPEN_CFM_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_CCH_OPEN_CFM_EVT");
+      BTIF_TRACE_DEBUG(
+          "app_id=%d,app_handle=%d mcl_handle=%d status =%d",
+          p_data->cch_open_cfm.app_id, p_data->cch_open_cfm.app_handle,
+          p_data->cch_open_cfm.mcl_handle, p_data->cch_open_cfm.status);
+      BTIF_TRACE_DEBUG(
+          "DB [%02x] [%02x] [%02x] [%02x] [%02x] [%02x]",
+          p_data->cch_open_cfm.bd_addr[0], p_data->cch_open_cfm.bd_addr[1],
+          p_data->cch_open_cfm.bd_addr[2], p_data->cch_open_cfm.bd_addr[3],
+          p_data->cch_open_cfm.bd_addr[4], p_data->cch_open_cfm.bd_addr[5]);
+
+      if (p_data->cch_open_cfm.status == BTA_HL_STATUS_OK ||
+          p_data->cch_open_cfm.status == BTA_HL_STATUS_DUPLICATE_CCH_OPEN) {
+        status = btif_hl_proc_cch_open_cfm(p_data);
+      } else {
+        status = false;
+      }
+
+      if (!status) {
+        if (btif_hl_find_app_idx_using_app_id(p_data->cch_open_cfm.app_id,
+                                              &app_idx)) {
+          p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+          if (btif_hl_find_mcl_idx(app_idx, p_data->cch_open_cfm.bd_addr,
+                                   &mcl_idx)) {
+            p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+            pending_op = p_mcb->pcb.op;
+            switch (pending_op) {
+              case BTIF_HL_PEND_DCH_OP_OPEN:
+                btif_hl_send_setup_disconnected_cb(app_idx, mcl_idx);
+                break;
+              case BTIF_HL_PEND_DCH_OP_RECONNECT:
+              case BTIF_HL_PEND_DCH_OP_DELETE_MDL:
+              default:
+                break;
+            }
+            btif_hl_clean_mcl_cb(app_idx, mcl_idx);
+          }
+        }
+      }
+      break;
+
+    case BTA_HL_DCH_OPEN_CFM_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_OPEN_CFM_EVT");
+      BTIF_TRACE_DEBUG("mcl_handle=%d mdl_handle=0x%x status=%d ",
+                       p_data->dch_open_cfm.mcl_handle,
+                       p_data->dch_open_cfm.mdl_handle,
+                       p_data->dch_open_cfm.status);
+      BTIF_TRACE_DEBUG(
+          "first_reliable =%d dch_mode=%d local_mdep_id=%d mdl_id=%d mtu=%d",
+          p_data->dch_open_cfm.first_reliable, p_data->dch_open_cfm.dch_mode,
+          p_data->dch_open_cfm.local_mdep_id, p_data->dch_open_cfm.mdl_id,
+          p_data->dch_open_cfm.mtu);
+      if (p_data->dch_open_cfm.status == BTA_HL_STATUS_OK) {
+        status = btif_hl_proc_dch_open_cfm(p_data);
+      } else {
+        status = false;
+      }
+
+      if (!status) {
+        if (btif_hl_find_mcl_idx_using_handle(p_data->dch_open_cfm.mcl_handle,
+                                              &app_idx, &mcl_idx)) {
+          p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+          pending_op = p_mcb->pcb.op;
+          switch (pending_op) {
+            case BTIF_HL_PEND_DCH_OP_OPEN:
+              btif_hl_send_setup_disconnected_cb(app_idx, mcl_idx);
+              break;
+            case BTIF_HL_PEND_DCH_OP_RECONNECT:
+            case BTIF_HL_PEND_DCH_OP_DELETE_MDL:
+            default:
+              break;
+          }
+        }
+      }
+      break;
+
+    case BTA_HL_CCH_OPEN_IND_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_CCH_OPEN_IND_EVT");
+      BTIF_TRACE_DEBUG("app_handle=%d mcl_handle=%d",
+                       p_data->cch_open_ind.app_handle,
+                       p_data->cch_open_ind.mcl_handle);
+      BTIF_TRACE_DEBUG(
+          "DB [%02x] [%02x] [%02x] [%02x] [%02x] [%02x]",
+          p_data->cch_open_ind.bd_addr[0], p_data->cch_open_ind.bd_addr[1],
+          p_data->cch_open_ind.bd_addr[2], p_data->cch_open_ind.bd_addr[3],
+          p_data->cch_open_ind.bd_addr[4], p_data->cch_open_ind.bd_addr[5]);
+
+      btif_hl_proc_cch_open_ind(p_data);
+      break;
+
+    case BTA_HL_DCH_CREATE_IND_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_CREATE_IND_EVT");
+      BTIF_TRACE_DEBUG("mcl_handle=%d", p_data->dch_create_ind.mcl_handle);
+      BTIF_TRACE_DEBUG("local_mdep_id =%d mdl_id=%d cfg=%d",
+                       p_data->dch_create_ind.local_mdep_id,
+                       p_data->dch_create_ind.mdl_id,
+                       p_data->dch_create_ind.cfg);
+      btif_hl_proc_create_ind(p_data);
+      break;
+
+    case BTA_HL_DCH_OPEN_IND_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_OPEN_IND_EVT");
+      BTIF_TRACE_DEBUG("mcl_handle=%d mdl_handle=0x%x",
+                       p_data->dch_open_ind.mcl_handle,
+                       p_data->dch_open_ind.mdl_handle);
+      BTIF_TRACE_DEBUG(
+          "first_reliable =%d dch_mode=%d local_mdep_id=%d mdl_id=%d mtu=%d",
+          p_data->dch_open_ind.first_reliable, p_data->dch_open_ind.dch_mode,
+          p_data->dch_open_ind.local_mdep_id, p_data->dch_open_ind.mdl_id,
+          p_data->dch_open_ind.mtu);
+
+      btif_hl_proc_dch_open_ind(p_data);
+      break;
+
+    case BTA_HL_DELETE_MDL_IND_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_DELETE_MDL_IND_EVT");
+      BTIF_TRACE_DEBUG("mcl_handle=%d mdl_id=0x%x",
+                       p_data->delete_mdl_ind.mcl_handle,
+                       p_data->delete_mdl_ind.mdl_id);
+      break;
+
+    case BTA_HL_DELETE_MDL_CFM_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_DELETE_MDL_CFM_EVT");
+      BTIF_TRACE_DEBUG("mcl_handle=%d mdl_id=0x%x status=%d",
+                       p_data->delete_mdl_cfm.mcl_handle,
+                       p_data->delete_mdl_cfm.mdl_id,
+                       p_data->delete_mdl_cfm.status);
+
+      if (btif_hl_find_app_idx_using_deleted_mdl_id(
+              p_data->delete_mdl_cfm.mdl_id, &app_idx)) {
+        p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+        btif_hl_send_destroyed_cb(p_acb);
+        btif_hl_clean_delete_mdl(&p_acb->delete_mdl);
+      }
+      break;
+
+    case BTA_HL_DCH_RECONNECT_CFM_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_RECONNECT_CFM_EVT");
+      BTIF_TRACE_DEBUG("mcl_handle=%d mdl_handle=%d status=%d   ",
+                       p_data->dch_reconnect_cfm.mcl_handle,
+                       p_data->dch_reconnect_cfm.mdl_handle,
+                       p_data->dch_reconnect_cfm.status);
+      BTIF_TRACE_DEBUG("first_reliable =%d dch_mode=%d mdl_id=%d mtu=%d",
+                       p_data->dch_reconnect_cfm.first_reliable,
+                       p_data->dch_reconnect_cfm.dch_mode,
+                       p_data->dch_reconnect_cfm.mdl_id,
+                       p_data->dch_reconnect_cfm.mtu);
+
+      if (p_data->dch_reconnect_cfm.status == BTA_HL_STATUS_OK) {
+        status = btif_hl_proc_dch_reconnect_cfm(p_data);
+      } else {
+        status = false;
+      }
+
+      if (!status) {
+        if (btif_hl_find_mcl_idx_using_handle(p_data->dch_open_cfm.mcl_handle,
+                                              &app_idx, &mcl_idx)) {
+          p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+          pending_op = p_mcb->pcb.op;
+          switch (pending_op) {
+            case BTIF_HL_PEND_DCH_OP_OPEN:
+              btif_hl_send_setup_disconnected_cb(app_idx, mcl_idx);
+              break;
+            case BTIF_HL_PEND_DCH_OP_RECONNECT:
+            case BTIF_HL_PEND_DCH_OP_DELETE_MDL:
+            default:
+              break;
+          }
+        }
+      }
+
+      break;
+
+    case BTA_HL_CCH_CLOSE_CFM_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_CCH_CLOSE_CFM_EVT");
+      BTIF_TRACE_DEBUG("mcl_handle=%d status =%d",
+                       p_data->cch_close_cfm.mcl_handle,
+                       p_data->cch_close_cfm.status);
+      if (p_data->cch_close_cfm.status == BTA_HL_STATUS_OK) {
+        btif_hl_proc_cch_close_cfm(p_data);
+      }
+      break;
+
+    case BTA_HL_CCH_CLOSE_IND_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_CCH_CLOSE_IND_EVT");
+      BTIF_TRACE_DEBUG("mcl_handle =%d intentional_close=%s",
+                       p_data->cch_close_ind.mcl_handle,
+                       (p_data->cch_close_ind.intentional ? "Yes" : "No"));
+
+      btif_hl_proc_cch_close_ind(p_data);
+      break;
+
+    case BTA_HL_DCH_CLOSE_IND_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_CLOSE_IND_EVT");
+      BTIF_TRACE_DEBUG("mdl_handle=%d intentional_close=%s",
+                       p_data->dch_close_ind.mdl_handle,
+                       (p_data->dch_close_ind.intentional ? "Yes" : "No"));
+
+      btif_hl_proc_dch_close_ind(p_data);
+      break;
+
+    case BTA_HL_DCH_CLOSE_CFM_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_CLOSE_CFM_EVT");
+      BTIF_TRACE_DEBUG("mdl_handle=%d status=%d ",
+                       p_data->dch_close_cfm.mdl_handle,
+                       p_data->dch_close_cfm.status);
+
+      if (p_data->dch_close_cfm.status == BTA_HL_STATUS_OK) {
+        btif_hl_proc_dch_close_cfm(p_data);
+      }
+      break;
+
+    case BTA_HL_DCH_ECHO_TEST_CFM_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_ECHO_TEST_CFM_EVT");
+      BTIF_TRACE_DEBUG("mcl_handle=%d    status=%d",
+                       p_data->echo_test_cfm.mcl_handle,
+                       p_data->echo_test_cfm.status);
+      /* not supported */
+      break;
+
+    case BTA_HL_DCH_RECONNECT_IND_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_RECONNECT_IND_EVT");
+
+      BTIF_TRACE_DEBUG("mcl_handle=%d mdl_handle=5d",
+                       p_data->dch_reconnect_ind.mcl_handle,
+                       p_data->dch_reconnect_ind.mdl_handle);
+      BTIF_TRACE_DEBUG("first_reliable =%d dch_mode=%d mdl_id=%d mtu=%d",
+                       p_data->dch_reconnect_ind.first_reliable,
+                       p_data->dch_reconnect_ind.dch_mode,
+                       p_data->dch_reconnect_ind.mdl_id,
+                       p_data->dch_reconnect_ind.mtu);
+
+      btif_hl_proc_dch_reconnect_ind(p_data);
+      break;
+
+    case BTA_HL_CONG_CHG_IND_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_CONG_CHG_IND_EVT");
+      BTIF_TRACE_DEBUG("mdl_handle=%d cong =%d",
+                       p_data->dch_cong_ind.mdl_handle,
+                       p_data->dch_cong_ind.cong);
+      btif_hl_proc_dch_cong_ind(p_data);
+      break;
+
+    case BTA_HL_DCH_ABORT_IND_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_ABORT_IND_EVT");
+      BTIF_TRACE_DEBUG("mcl_handle=%d", p_data->dch_abort_ind.mcl_handle);
+      btif_hl_proc_abort_ind(p_data->dch_abort_ind.mcl_handle);
+      break;
+    case BTA_HL_DCH_ABORT_CFM_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_ABORT_CFM_EVT");
+      BTIF_TRACE_DEBUG("mcl_handle=%d status =%d",
+                       p_data->dch_abort_cfm.mcl_handle,
+                       p_data->dch_abort_cfm.status);
+      if (p_data->dch_abort_cfm.status == BTA_HL_STATUS_OK) {
+        btif_hl_proc_abort_cfm(p_data->dch_abort_ind.mcl_handle);
+      }
+      break;
+
+    case BTA_HL_DCH_SEND_DATA_CFM_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_SEND_DATA_CFM_EVT");
+      BTIF_TRACE_DEBUG("mdl_handle=0x%x status =%d",
+                       p_data->dch_send_data_cfm.mdl_handle,
+                       p_data->dch_send_data_cfm.status);
+      btif_hl_proc_send_data_cfm(p_data->dch_send_data_cfm.mdl_handle,
+                                 p_data->dch_send_data_cfm.status);
+      break;
+
+    case BTA_HL_DCH_RCV_DATA_IND_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_RCV_DATA_IND_EVT");
+      BTIF_TRACE_DEBUG("mdl_handle=0x%x ", p_data->dch_rcv_data_ind.mdl_handle);
+      /* do nothing here */
+      break;
+
+    default:
+      BTIF_TRACE_DEBUG("Unknown Event (0x%02x)...", event);
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_cback
+ *
+ * Description      Callback function for HL events
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_hl_cback(tBTA_HL_EVT event, tBTA_HL* p_data) {
+  bt_status_t status;
+  int param_len = 0;
+  BTIF_TRACE_DEBUG("%s event %d", __func__, event);
+  btif_hl_display_calling_process_name();
+  switch (event) {
+    case BTA_HL_REGISTER_CFM_EVT:
+      param_len = sizeof(tBTA_HL_REGISTER_CFM);
+      break;
+    case BTA_HL_SDP_INFO_IND_EVT:
+      param_len = sizeof(tBTA_HL_SDP_INFO_IND);
+      break;
+    case BTA_HL_DEREGISTER_CFM_EVT:
+      param_len = sizeof(tBTA_HL_DEREGISTER_CFM);
+      break;
+    case BTA_HL_SDP_QUERY_CFM_EVT:
+      param_len = sizeof(tBTA_HL_SDP_QUERY_CFM);
+      break;
+    case BTA_HL_CCH_OPEN_CFM_EVT:
+      param_len = sizeof(tBTA_HL_CCH_OPEN_CFM);
+      break;
+    case BTA_HL_DCH_OPEN_CFM_EVT:
+      param_len = sizeof(tBTA_HL_DCH_OPEN_CFM);
+      break;
+    case BTA_HL_CCH_OPEN_IND_EVT:
+      param_len = sizeof(tBTA_HL_CCH_OPEN_IND);
+      break;
+    case BTA_HL_DCH_CREATE_IND_EVT:
+      param_len = sizeof(tBTA_HL_DCH_CREATE_IND);
+      break;
+    case BTA_HL_DCH_OPEN_IND_EVT:
+      param_len = sizeof(tBTA_HL_DCH_OPEN_IND);
+      break;
+    case BTA_HL_DELETE_MDL_IND_EVT:
+      param_len = sizeof(tBTA_HL_MDL_IND);
+      break;
+    case BTA_HL_DELETE_MDL_CFM_EVT:
+      param_len = sizeof(tBTA_HL_MDL_CFM);
+      break;
+    case BTA_HL_DCH_RECONNECT_CFM_EVT:
+      param_len = sizeof(tBTA_HL_DCH_OPEN_CFM);
+      break;
+    case BTA_HL_CCH_CLOSE_CFM_EVT:
+      param_len = sizeof(tBTA_HL_MCL_CFM);
+      break;
+    case BTA_HL_CCH_CLOSE_IND_EVT:
+      param_len = sizeof(tBTA_HL_CCH_CLOSE_IND);
+      break;
+    case BTA_HL_DCH_CLOSE_IND_EVT:
+      param_len = sizeof(tBTA_HL_DCH_CLOSE_IND);
+      break;
+    case BTA_HL_DCH_CLOSE_CFM_EVT:
+      param_len = sizeof(tBTA_HL_MDL_CFM);
+      break;
+    case BTA_HL_DCH_ECHO_TEST_CFM_EVT:
+      param_len = sizeof(tBTA_HL_MCL_CFM);
+      break;
+    case BTA_HL_DCH_RECONNECT_IND_EVT:
+      param_len = sizeof(tBTA_HL_DCH_OPEN_IND);
+      break;
+    case BTA_HL_CONG_CHG_IND_EVT:
+      param_len = sizeof(tBTA_HL_DCH_CONG_IND);
+      break;
+    case BTA_HL_DCH_ABORT_IND_EVT:
+      param_len = sizeof(tBTA_HL_MCL_IND);
+      break;
+    case BTA_HL_DCH_ABORT_CFM_EVT:
+      param_len = sizeof(tBTA_HL_MCL_CFM);
+      break;
+    case BTA_HL_DCH_SEND_DATA_CFM_EVT:
+      param_len = sizeof(tBTA_HL_MDL_CFM);
+      break;
+    case BTA_HL_DCH_RCV_DATA_IND_EVT:
+      param_len = sizeof(tBTA_HL_MDL_IND);
+      break;
+    default:
+      param_len = sizeof(tBTA_HL_MDL_IND);
+      break;
+  }
+  status = btif_transfer_context(btif_hl_upstreams_evt, (uint16_t)event,
+                                 (char*)p_data, param_len, NULL);
+
+  /* catch any failed context transfers */
+  ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_upstreams_ctrl_evt
+ *
+ * Description      Callback function for HL control events in the BTIF task
+ *                  context
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_hl_upstreams_ctrl_evt(uint16_t event, char* p_param) {
+  tBTA_HL_CTRL* p_data = (tBTA_HL_CTRL*)p_param;
+  uint8_t i;
+  tBTA_HL_REG_PARAM reg_param;
+  btif_hl_app_cb_t* p_acb;
+
+  BTIF_TRACE_DEBUG("%s event %d", __func__, event);
+  btif_hl_display_calling_process_name();
+
+  switch (event) {
+    case BTA_HL_CTRL_ENABLE_CFM_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_CTRL_ENABLE_CFM_EVT");
+      BTIF_TRACE_DEBUG("status=%d", p_data->enable_cfm.status);
+
+      if (p_data->enable_cfm.status == BTA_HL_STATUS_OK) {
+        btif_hl_set_state(BTIF_HL_STATE_ENABLED);
+
+        for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+          p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+          if (p_acb->in_use && p_acb->reg_pending) {
+            p_acb->reg_pending = false;
+            reg_param.dev_type = p_acb->dev_type;
+            reg_param.sec_mask = BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT;
+            reg_param.p_srv_name = p_acb->srv_name;
+            reg_param.p_srv_desp = p_acb->srv_desp;
+            reg_param.p_provider_name = p_acb->provider_name;
+
+            BTIF_TRACE_DEBUG("Register pending app_id=%d", p_acb->app_id);
+            btif_hl_proc_reg_request(i, p_acb->app_id, &reg_param,
+                                     btif_hl_cback);
+          }
+        }
+      }
+
+      break;
+    case BTA_HL_CTRL_DISABLE_CFM_EVT:
+      BTIF_TRACE_DEBUG("Rcv BTA_HL_CTRL_DISABLE_CFM_EVT");
+      BTIF_TRACE_DEBUG("status=%d", p_data->disable_cfm.status);
+
+      if (p_data->disable_cfm.status == BTA_HL_STATUS_OK) {
+        for (size_t i = 0; i < BTA_HL_NUM_APPS; i++) {
+          for (size_t j = 0; j < BTA_HL_NUM_MCLS; j++) {
+            alarm_free(p_btif_hl_cb->acb[i].mcb[j].cch_timer);
+          }
+        }
+        memset(p_btif_hl_cb, 0, sizeof(btif_hl_cb_t));
+        btif_hl_set_state(BTIF_HL_STATE_DISABLED);
+      }
+
+      break;
+    default:
+      break;
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_ctrl_cback
+ *
+ * Description      Callback function for HL control events
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_hl_ctrl_cback(tBTA_HL_CTRL_EVT event, tBTA_HL_CTRL* p_data) {
+  bt_status_t status;
+  int param_len = 0;
+
+  BTIF_TRACE_DEBUG("%s event %d", __func__, event);
+  btif_hl_display_calling_process_name();
+
+  switch (event) {
+    case BTA_HL_CTRL_ENABLE_CFM_EVT:
+    case BTA_HL_CTRL_DISABLE_CFM_EVT:
+      param_len = sizeof(tBTA_HL_CTRL_ENABLE_DISABLE);
+      break;
+    default:
+      break;
+  }
+
+  status = btif_transfer_context(btif_hl_upstreams_ctrl_evt, (uint16_t)event,
+                                 (char*)p_data, param_len, NULL);
+  ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+/*******************************************************************************
+ *
+ * Function         connect_channel
+ *
+ * Description     connect a data channel
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t connect_channel(int app_id, bt_bdaddr_t* bd_addr,
+                                   int mdep_cfg_index, int* channel_id) {
+  uint8_t app_idx, mcl_idx;
+  btif_hl_app_cb_t* p_acb = NULL;
+  btif_hl_pending_chan_cb_t* p_pcb = NULL;
+  btif_hl_mcl_cb_t* p_mcb = NULL;
+  bt_status_t status = BT_STATUS_SUCCESS;
+  tBTA_HL_DCH_OPEN_PARAM dch_open;
+  BD_ADDR bda;
+  uint8_t i;
+
+  CHECK_BTHL_INIT();
+  BTIF_TRACE_EVENT("%s", __func__);
+  btif_hl_display_calling_process_name();
+
+  for (i = 0; i < 6; i++) {
+    bda[i] = (uint8_t)bd_addr->address[i];
+  }
+  if (btif_hl_find_app_idx(((uint8_t)app_id), &app_idx)) {
+    p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+    if (btif_hl_find_mcl_idx(app_idx, bda, &mcl_idx)) {
+      p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+      if (p_mcb->is_connected) {
+        dch_open.ctrl_psm = p_mcb->ctrl_psm;
+        dch_open.local_mdep_id =
+            p_acb->sup_feature.mdep[mdep_cfg_index].mdep_id;
+        BTIF_TRACE_DEBUG(
+            "connect_channel: app_idx =%d, mdep_cfg_indx =%d, mdep_id =%d "
+            "app_id= %d",
+            app_idx, mdep_cfg_index, dch_open.local_mdep_id, app_id);
+        if (btif_hl_find_peer_mdep_id(
+                p_acb->app_id, p_mcb->bd_addr,
+                p_acb->sup_feature.mdep[mdep_cfg_index].mdep_cfg.mdep_role,
+                p_acb->sup_feature.mdep[mdep_cfg_index]
+                    .mdep_cfg.data_cfg[0]
+                    .data_type,
+                &dch_open.peer_mdep_id)) {
+          dch_open.local_cfg = p_acb->channel_type[mdep_cfg_index];
+          if ((p_acb->sup_feature.mdep[mdep_cfg_index].mdep_cfg.mdep_role ==
+               BTA_HL_MDEP_ROLE_SOURCE) &&
+              !btif_hl_is_the_first_reliable_existed(app_idx, mcl_idx)) {
+            dch_open.local_cfg = BTA_HL_DCH_CFG_RELIABLE;
+          }
+          dch_open.sec_mask = (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+
+          if (!btif_hl_dch_open(p_acb->app_id, bda, &dch_open, mdep_cfg_index,
+                                BTIF_HL_PEND_DCH_OP_OPEN, channel_id)) {
+            status = BT_STATUS_FAIL;
+            BTIF_TRACE_EVENT("%s loc0 status = BT_STATUS_FAIL", __func__);
+          }
+        } else {
+          p_mcb->cch_oper = BTIF_HL_CCH_OP_MDEP_FILTERING;
+
+          p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+          p_pcb->in_use = true;
+          p_pcb->mdep_cfg_idx = mdep_cfg_index;
+          memcpy(p_pcb->bd_addr, bda, sizeof(BD_ADDR));
+          p_pcb->op = BTIF_HL_PEND_DCH_OP_OPEN;
+          BTA_HlSdpQuery(app_id, p_acb->app_handle, bda);
+        }
+      } else {
+        status = BT_STATUS_FAIL;
+      }
+    } else {
+      p_acb->filter.num_elems = 1;
+      p_acb->filter.elem[0].data_type = p_acb->sup_feature.mdep[mdep_cfg_index]
+                                            .mdep_cfg.data_cfg[mdep_cfg_index]
+                                            .data_type;
+      if (p_acb->sup_feature.mdep[mdep_cfg_index].mdep_cfg.mdep_role ==
+          BTA_HL_MDEP_ROLE_SINK)
+        p_acb->filter.elem[0].peer_mdep_role = BTA_HL_MDEP_ROLE_SOURCE;
+      else
+        p_acb->filter.elem[0].peer_mdep_role = BTA_HL_MDEP_ROLE_SINK;
+
+      if (!btif_hl_cch_open(p_acb->app_id, bda, 0, mdep_cfg_index,
+                            BTIF_HL_PEND_DCH_OP_OPEN, channel_id)) {
+        status = BT_STATUS_FAIL;
+      }
+    }
+  } else {
+    status = BT_STATUS_FAIL;
+  }
+
+  BTIF_TRACE_DEBUG("%s status=%d channel_id=0x%08x", __func__, status,
+                   *channel_id);
+
+  return status;
+}
+/*******************************************************************************
+ *
+ * Function         destroy_channel
+ *
+ * Description      destroy a data channel
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t destroy_channel(int channel_id) {
+  uint8_t app_idx, mcl_idx, mdl_cfg_idx, mdep_cfg_idx = 0;
+  bt_status_t status = BT_STATUS_SUCCESS;
+  btif_hl_mdl_cfg_t* p_mdl;
+  btif_hl_mcl_cb_t* p_mcb;
+  btif_hl_app_cb_t* p_acb;
+
+  CHECK_BTHL_INIT();
+  BTIF_TRACE_EVENT("%s channel_id=0x%08x", __func__, channel_id);
+  btif_hl_display_calling_process_name();
+
+  if (btif_hl_if_channel_setup_pending(channel_id, &app_idx, &mcl_idx)) {
+    btif_hl_dch_abort(app_idx, mcl_idx);
+  } else {
+    if (btif_hl_find_mdl_cfg_idx_using_channel_id(channel_id, &app_idx,
+                                                  &mdl_cfg_idx))
+    //       if(btif_hl_find_mdl_idx_using_channel_id(channel_id,
+    //       &app_idx,&mcl_idx, &mdl_idx))
+    {
+      p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+      if (!p_acb->delete_mdl.active) {
+        p_mdl = BTIF_HL_GET_MDL_CFG_PTR(app_idx, mdl_cfg_idx);
+        p_acb->delete_mdl.active = true;
+        p_acb->delete_mdl.mdl_id = p_mdl->base.mdl_id;
+        p_acb->delete_mdl.channel_id = channel_id;
+        p_acb->delete_mdl.mdep_cfg_idx = p_mdl->extra.mdep_cfg_idx;
+        memcpy(p_acb->delete_mdl.bd_addr, p_mdl->base.peer_bd_addr,
+               sizeof(BD_ADDR));
+
+        if (btif_hl_find_mcl_idx(app_idx, p_mdl->base.peer_bd_addr, &mcl_idx)) {
+          p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+          if (p_mcb->is_connected) {
+            BTIF_TRACE_DEBUG("calling BTA_HlDeleteMdl mdl_id=%d",
+                             p_acb->delete_mdl.mdl_id);
+            BTA_HlDeleteMdl(p_mcb->mcl_handle, p_acb->delete_mdl.mdl_id);
+          } else {
+            status = BT_STATUS_FAIL;
+          }
+        } else {
+          BTIF_TRACE_DEBUG("btif_hl_delete_mdl calling btif_hl_cch_open");
+          mdep_cfg_idx = p_mdl->extra.mdep_cfg_idx;
+          p_acb->filter.num_elems = 1;
+          p_acb->filter.elem[0].data_type =
+              p_acb->sup_feature.mdep[mdep_cfg_idx]
+                  .mdep_cfg.data_cfg[mdep_cfg_idx]
+                  .data_type;
+          if (p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg.mdep_role ==
+              BTA_HL_MDEP_ROLE_SINK)
+            p_acb->filter.elem[0].peer_mdep_role = BTA_HL_MDEP_ROLE_SOURCE;
+          else
+            p_acb->filter.elem[0].peer_mdep_role = BTA_HL_MDEP_ROLE_SINK;
+          if (btif_hl_cch_open(p_acb->app_id, p_acb->delete_mdl.bd_addr, 0,
+                               mdep_cfg_idx, BTIF_HL_PEND_DCH_OP_DELETE_MDL,
+                               NULL)) {
+            status = BT_STATUS_FAIL;
+          }
+        }
+
+        if (status == BT_STATUS_FAIL) {
+          /* fail for now  */
+          btif_hl_clean_delete_mdl(&p_acb->delete_mdl);
+        }
+      } else {
+        status = BT_STATUS_BUSY;
+      }
+    } else {
+      status = BT_STATUS_FAIL;
+    }
+  }
+  return status;
+}
+/*******************************************************************************
+ *
+ * Function         unregister_application
+ *
+ * Description     unregister an HDP application
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t unregister_application(int app_id) {
+  uint8_t app_idx;
+  int len;
+  bt_status_t status = BT_STATUS_SUCCESS;
+  btif_hl_evt_cb_t evt_param;
+
+  CHECK_BTHL_INIT();
+  BTIF_TRACE_EVENT("%s app_id=%d", __func__, app_id);
+  btif_hl_display_calling_process_name();
+
+  if (btif_hl_find_app_idx(((uint8_t)app_id), &app_idx)) {
+    evt_param.unreg.app_idx = app_idx;
+    reg_counter--;
+    len = sizeof(btif_hl_unreg_t);
+    status = btif_transfer_context(btif_hl_proc_cb_evt, BTIF_HL_UNREG_APP,
+                                   (char*)&evt_param, len, NULL);
+    ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+  } else {
+    status = BT_STATUS_FAIL;
+  }
+
+  BTIF_TRACE_DEBUG("de-reg return status=%d", status);
+  return status;
+}
+/*******************************************************************************
+ *
+ * Function         register_application
+ *
+ * Description     register an HDP application
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t register_application(bthl_reg_param_t* p_reg_param,
+                                        int* app_id) {
+  btif_hl_app_cb_t* p_acb;
+  tBTA_HL_SUP_FEATURE* p_sup;
+  tBTA_HL_MDEP_CFG* p_cfg;
+  tBTA_HL_MDEP_DATA_TYPE_CFG* p_data;
+  uint8_t app_idx = 0, i = 0;
+  bthl_mdep_cfg_t* p_mdep_cfg;
+  bt_status_t status = BT_STATUS_SUCCESS;
+  btif_hl_evt_cb_t evt_param;
+  int len;
+
+  CHECK_BTHL_INIT();
+  BTIF_TRACE_EVENT("%s", __func__);
+  btif_hl_display_calling_process_name();
+
+  if (btif_hl_get_state() == BTIF_HL_STATE_DISABLED) {
+    btif_hl_init();
+    btif_hl_set_state(BTIF_HL_STATE_ENABLING);
+    BTA_HlEnable(btif_hl_ctrl_cback);
+  }
+
+  if (!btif_hl_find_avail_app_idx(&app_idx)) {
+    BTIF_TRACE_ERROR("Unable to allocate a new application control block");
+    return BT_STATUS_FAIL;
+  }
+
+  p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+  p_acb->in_use = true;
+
+  p_acb->app_id = btif_hl_get_next_app_id();
+
+  if (p_reg_param->application_name != NULL)
+    strncpy(p_acb->application_name, p_reg_param->application_name,
+            BTIF_HL_APPLICATION_NAME_LEN);
+
+  if (p_reg_param->provider_name != NULL)
+    strncpy(p_acb->provider_name, p_reg_param->provider_name,
+            BTA_PROVIDER_NAME_LEN);
+
+  if (p_reg_param->srv_name != NULL)
+    strncpy(p_acb->srv_name, p_reg_param->srv_name, BTA_SERVICE_NAME_LEN);
+
+  if (p_reg_param->srv_desp != NULL)
+    strncpy(p_acb->srv_desp, p_reg_param->srv_desp, BTA_SERVICE_DESP_LEN);
+
+  p_sup = &p_acb->sup_feature;
+  p_sup->advertize_source_sdp = true;
+  p_sup->echo_cfg.max_rx_apdu_size = BTIF_HL_ECHO_MAX_TX_RX_APDU_SIZE;
+  p_sup->echo_cfg.max_tx_apdu_size = BTIF_HL_ECHO_MAX_TX_RX_APDU_SIZE;
+  p_sup->num_of_mdeps = p_reg_param->number_of_mdeps;
+
+  for (i = 0, p_mdep_cfg = p_reg_param->mdep_cfg; i < p_sup->num_of_mdeps;
+       i++, p_mdep_cfg++) {
+    p_cfg = &p_sup->mdep[i].mdep_cfg;
+    p_cfg->num_of_mdep_data_types = 1;
+    p_data = &p_cfg->data_cfg[0];
+
+    if (!btif_hl_get_bta_mdep_role(p_mdep_cfg->mdep_role,
+                                   &(p_cfg->mdep_role))) {
+      BTIF_TRACE_ERROR("Invalid mdep_role=%d", p_mdep_cfg->mdep_role);
+      status = BT_STATUS_FAIL;
+      break;
+    } else {
+      if (p_cfg->mdep_role == BTA_HL_MDEP_ROLE_SINK)
+        p_sup->app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SINK;
+      else
+        p_sup->app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SOURCE;
+
+      if ((p_sup->app_role_mask & BTA_HL_MDEP_ROLE_MASK_SINK) &&
+          (p_sup->app_role_mask & BTA_HL_MDEP_ROLE_MASK_SOURCE)) {
+        p_acb->dev_type = BTA_HL_DEVICE_TYPE_DUAL;
+      } else if (p_sup->app_role_mask & BTA_HL_MDEP_ROLE_MASK_SINK) {
+        p_acb->dev_type = BTA_HL_DEVICE_TYPE_SINK;
+      } else {
+        p_acb->dev_type = BTA_HL_DEVICE_TYPE_SOURCE;
+      }
+
+      p_data->data_type = (uint16_t)p_mdep_cfg->data_type;
+      p_data->max_rx_apdu_size =
+          btif_hl_get_max_rx_apdu_size(p_cfg->mdep_role, p_data->data_type);
+      p_data->max_tx_apdu_size =
+          btif_hl_get_max_tx_apdu_size(p_cfg->mdep_role, p_data->data_type);
+
+      if (p_mdep_cfg->mdep_description != NULL)
+        strncpy(p_data->desp, p_mdep_cfg->mdep_description,
+                BTA_SERVICE_DESP_LEN);
+
+      if (!btif_hl_get_bta_channel_type(p_mdep_cfg->channel_type,
+                                        &(p_acb->channel_type[i]))) {
+        BTIF_TRACE_ERROR("Invalid channel_type=%d", p_mdep_cfg->channel_type);
+        status = BT_STATUS_FAIL;
+        break;
+      }
+    }
+  }
+
+  if (status == BT_STATUS_SUCCESS) {
+    *app_id = (int)p_acb->app_id;
+    evt_param.reg.app_idx = app_idx;
+    len = sizeof(btif_hl_reg_t);
+    p_acb->reg_pending = true;
+    BTIF_TRACE_DEBUG("calling btif_transfer_context status=%d app_id=%d",
+                     status, *app_id);
+    status = btif_transfer_context(btif_hl_proc_cb_evt, BTIF_HL_REG_APP,
+                                   (char*)&evt_param, len, NULL);
+    ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+
+  } else {
+    btif_hl_free_app_idx(app_idx);
+  }
+
+  BTIF_TRACE_DEBUG("register_application status=%d app_id=%d", status, *app_id);
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_save_mdl_cfg
+ *
+ * Description  Save the MDL configuration
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+bool btif_hl_save_mdl_cfg(uint8_t mdep_id, uint8_t item_idx,
+                          tBTA_HL_MDL_CFG* p_mdl_cfg) {
+  btif_hl_mdl_cfg_t* p_mdl = NULL;
+  bool success = false;
+  btif_hl_app_cb_t* p_acb;
+  btif_hl_mcl_cb_t* p_mcb;
+  uint8_t app_idx, mcl_idx, len;
+  bt_status_t bt_status;
+  btif_hl_evt_cb_t evt_param;
+  int* p_channel_id;
+
+  BTIF_TRACE_DEBUG(
+      "%s mdep_id=%d item_idx=%d, local_mdep_id=%d mdl_id=0x%x dch_mode=%d",
+      __func__, mdep_id, item_idx, p_mdl_cfg->local_mdep_id, p_mdl_cfg->mdl_id,
+      p_mdl_cfg->dch_mode);
+
+  if (btif_hl_find_app_idx_using_mdepId(mdep_id, &app_idx)) {
+    p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+    p_mdl = BTIF_HL_GET_MDL_CFG_PTR(app_idx, item_idx);
+    p_channel_id = BTIF_HL_GET_MDL_CFG_CHANNEL_ID_PTR(app_idx, item_idx);
+    if (p_mdl) {
+      memcpy(&p_mdl->base, p_mdl_cfg, sizeof(tBTA_HL_MDL_CFG));
+      if (btif_hl_find_mcl_idx(app_idx, p_mdl->base.peer_bd_addr, &mcl_idx)) {
+        p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+        if (p_mcb->pcb.in_use)
+          *p_channel_id = p_mcb->pcb.channel_id;
+        else
+          *p_channel_id = btif_hl_get_next_channel_id(p_acb->app_id);
+        p_mdl->extra.mdep_cfg_idx = p_mcb->pcb.mdep_cfg_idx;
+        p_mdl->extra.data_type =
+            p_acb->sup_feature.mdep[p_mcb->pcb.mdep_cfg_idx]
+                .mdep_cfg.data_cfg[0]
+                .data_type;
+
+        if (!btif_hl_find_peer_mdep_id(
+                p_acb->app_id, p_mcb->bd_addr,
+                p_acb->sup_feature.mdep[p_mcb->pcb.mdep_cfg_idx]
+                    .mdep_cfg.mdep_role,
+                p_acb->sup_feature.mdep[p_mcb->pcb.mdep_cfg_idx]
+                    .mdep_cfg.data_cfg[0]
+                    .data_type,
+                &p_mdl->extra.peer_mdep_id)) {
+          p_mdl->extra.peer_mdep_id = BTA_HL_INVALID_MDEP_ID;
+        }
+        BTIF_TRACE_DEBUG("%s app_idx=%d item_idx=%d mld_id=0x%x", __func__,
+                         app_idx, item_idx, p_mdl->base.mdl_id);
+        evt_param.update_mdl.app_idx = app_idx;
+        len = sizeof(btif_hl_update_mdl_t);
+        BTIF_TRACE_DEBUG("send BTIF_HL_UPDATE_MDL event app_idx=%d  ", app_idx);
+        if ((bt_status = btif_transfer_context(
+                 btif_hl_proc_cb_evt, BTIF_HL_UPDATE_MDL, (char*)&evt_param,
+                 len, NULL)) == BT_STATUS_SUCCESS) {
+          success = true;
+        }
+        ASSERTC(bt_status == BT_STATUS_SUCCESS, "context transfer failed",
+                bt_status);
+      }
+    }
+  }
+  BTIF_TRACE_DEBUG("%s success=%d  ", __func__, success);
+
+  return success;
+}
+
+/*******************************************************************************
+ *
+ * Function      btif_hl_delete_mdl_cfg
+ *
+ * Description  Delete the MDL configuration
+ *
+ * Returns      bool
+ *
+ ******************************************************************************/
+bool btif_hl_delete_mdl_cfg(uint8_t mdep_id, uint8_t item_idx) {
+  btif_hl_mdl_cfg_t* p_mdl = NULL;
+  bool success = false;
+  uint8_t app_idx, len;
+  bt_status_t bt_status;
+  btif_hl_evt_cb_t evt_param;
+
+  if (btif_hl_find_app_idx_using_mdepId(mdep_id, &app_idx)) {
+    p_mdl = BTIF_HL_GET_MDL_CFG_PTR(app_idx, item_idx);
+    if (p_mdl) {
+      memset(p_mdl, 0, sizeof(btif_hl_mdl_cfg_t));
+      evt_param.update_mdl.app_idx = app_idx;
+      len = sizeof(btif_hl_update_mdl_t);
+      BTIF_TRACE_DEBUG("send BTIF_HL_UPDATE_MDL event app_idx=%d  ", app_idx);
+      if ((bt_status = btif_transfer_context(
+               btif_hl_proc_cb_evt, BTIF_HL_UPDATE_MDL, (char*)&evt_param, len,
+               NULL)) == BT_STATUS_SUCCESS) {
+        success = true;
+      }
+      ASSERTC(bt_status == BT_STATUS_SUCCESS, "context transfer failed",
+              bt_status);
+    }
+  }
+
+  BTIF_TRACE_DEBUG("%s success=%d  ", __func__, success);
+  return success;
+}
+
+/*******************************************************************************
+ *
+ * Function         init
+ *
+ * Description     initializes the hl interface
+ *
+ * Returns         bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t init(bthl_callbacks_t* callbacks) {
+  bt_status_t status = BT_STATUS_SUCCESS;
+
+  BTIF_TRACE_EVENT("%s", __func__);
+  btif_hl_display_calling_process_name();
+  bt_hl_callbacks_cb = *callbacks;
+  bt_hl_callbacks = &bt_hl_callbacks_cb;
+  btif_hl_soc_thread_init();
+  reg_counter = 0;
+  return status;
+}
+/*******************************************************************************
+ *
+ * Function         cleanup
+ *
+ * Description      Closes the HL interface
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void cleanup(void) {
+  BTIF_TRACE_EVENT("%s", __func__);
+  btif_hl_display_calling_process_name();
+  if (bt_hl_callbacks) {
+    btif_disable_service(BTA_HDP_SERVICE_ID);
+    bt_hl_callbacks = NULL;
+    reg_counter = 0;
+  }
+
+  btif_hl_disable();
+  btif_hl_close_select_thread();
+}
+
+static const bthl_interface_t bthlInterface = {
+    sizeof(bthl_interface_t),
+    init,
+    register_application,
+    unregister_application,
+    connect_channel,
+    destroy_channel,
+    cleanup,
+};
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_get_interface
+ *
+ * Description      Get the hl callback interface
+ *
+ * Returns          bthf_interface_t
+ *
+ ******************************************************************************/
+const bthl_interface_t* btif_hl_get_interface() {
+  BTIF_TRACE_EVENT("%s", __func__);
+  return &bthlInterface;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_update_maxfd
+ *
+ * Description Update the max fd if the input fd is greater than the current max
+ * fd
+ *
+ * Returns int
+ *
+ ******************************************************************************/
+int btif_hl_update_maxfd(int max_org_s) {
+  int maxfd = max_org_s;
+
+  BTIF_TRACE_DEBUG("btif_hl_update_maxfd max_org_s= %d", max_org_s);
+  for (const list_node_t* node = list_begin(soc_queue);
+       node != list_end(soc_queue); node = list_next(node)) {
+    btif_hl_soc_cb_t* p_scb = (btif_hl_soc_cb_t*)list_node(node);
+    if (maxfd < p_scb->max_s) {
+      maxfd = p_scb->max_s;
+      BTIF_TRACE_DEBUG("btif_hl_update_maxfd maxfd=%d", maxfd);
+    }
+  }
+
+  BTIF_TRACE_DEBUG("btif_hl_update_maxfd final *p_max_s=%d", maxfd);
+  return maxfd;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_get_socket_state
+ *
+ * Description get socket state
+ *
+ * Returns btif_hl_soc_state_t
+ *
+ ******************************************************************************/
+btif_hl_soc_state_t btif_hl_get_socket_state(btif_hl_soc_cb_t* p_scb) {
+  BTIF_TRACE_DEBUG("btif_hl_get_socket_state state=%d", p_scb->state);
+  return p_scb->state;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_set_socket_state
+ *
+ * Description set socket state
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_set_socket_state(btif_hl_soc_cb_t* p_scb,
+                              btif_hl_soc_state_t new_state) {
+  BTIF_TRACE_DEBUG("btif_hl_set_socket_state %d---->%d", p_scb->state,
+                   new_state);
+  p_scb->state = new_state;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_release_mcl_sockets
+ *
+ * Description Release all sockets on the MCL
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_release_mcl_sockets(uint8_t app_idx, uint8_t mcl_idx) {
+  uint8_t i;
+  btif_hl_mdl_cb_t* p_dcb;
+  bool found = false;
+  BTIF_TRACE_DEBUG("%s", __func__);
+  for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+    p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, i);
+    if (p_dcb && p_dcb->in_use && p_dcb->p_scb) {
+      BTIF_TRACE_DEBUG("found socket for app_idx=%d mcl_id=%d, mdl_idx=%d",
+                       app_idx, mcl_idx, i);
+      btif_hl_set_socket_state(p_dcb->p_scb, BTIF_HL_SOC_STATE_W4_REL);
+      p_dcb->p_scb = NULL;
+      found = true;
+    }
+  }
+  if (found) btif_hl_select_close_connected();
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_release_socket
+ *
+ * Description release a specified socket
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_release_socket(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx) {
+  btif_hl_soc_cb_t* p_scb = NULL;
+  btif_hl_mdl_cb_t* p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+  BTIF_TRACE_DEBUG("app_idx=%d mcl_idx=%d mdl_idx=%d", app_idx, mcl_idx,
+                   mdl_idx);
+
+  if (p_dcb && p_dcb->p_scb) {
+    p_scb = p_dcb->p_scb;
+    btif_hl_set_socket_state(p_scb, BTIF_HL_SOC_STATE_W4_REL);
+    p_dcb->p_scb = NULL;
+    btif_hl_select_close_connected();
+  }
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_create_socket
+ *
+ * Description create a socket
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_create_socket(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx) {
+  btif_hl_mcl_cb_t* p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+  btif_hl_mdl_cb_t* p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+  bool status = false;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  if (p_dcb) {
+    btif_hl_soc_cb_t* p_scb =
+        (btif_hl_soc_cb_t*)osi_malloc(sizeof(btif_hl_soc_cb_t));
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, p_scb->socket_id) >= 0) {
+      BTIF_TRACE_DEBUG("socket id[0]=%d id[1]=%d", p_scb->socket_id[0],
+                       p_scb->socket_id[1]);
+      p_dcb->p_scb = p_scb;
+      p_scb->app_idx = app_idx;
+      p_scb->mcl_idx = mcl_idx;
+      p_scb->mdl_idx = mdl_idx;
+      p_scb->channel_id = p_dcb->channel_id;
+      p_scb->mdep_cfg_idx = p_dcb->local_mdep_cfg_idx;
+      memcpy(p_scb->bd_addr, p_mcb->bd_addr, sizeof(BD_ADDR));
+      btif_hl_set_socket_state(p_scb, BTIF_HL_SOC_STATE_W4_ADD);
+      p_scb->max_s = p_scb->socket_id[1];
+      list_append(soc_queue, (void*)p_scb);
+      btif_hl_select_wakeup();
+      status = true;
+    } else {
+      osi_free_and_reset((void**)&p_scb);
+    }
+  }
+
+  BTIF_TRACE_DEBUG("%s status=%d", __func__, status);
+  return status;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_add_socket_to_set
+ *
+ * Description Add a socket
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_add_socket_to_set(fd_set* p_org_set) {
+  btif_hl_mdl_cb_t* p_dcb = NULL;
+  btif_hl_mcl_cb_t* p_mcb = NULL;
+  btif_hl_app_cb_t* p_acb = NULL;
+  btif_hl_evt_cb_t evt_param;
+  bt_status_t status;
+  int len;
+
+  BTIF_TRACE_DEBUG("entering %s", __func__);
+
+  for (const list_node_t* node = list_begin(soc_queue);
+       node != list_end(soc_queue); node = list_next(node)) {
+    btif_hl_soc_cb_t* p_scb = (btif_hl_soc_cb_t*)list_node(node);
+
+    BTIF_TRACE_DEBUG("btif_hl_add_socket_to_set first p_scb=0x%x", p_scb);
+    if (btif_hl_get_socket_state(p_scb) == BTIF_HL_SOC_STATE_W4_ADD) {
+      btif_hl_set_socket_state(p_scb, BTIF_HL_SOC_STATE_W4_READ);
+      FD_SET(p_scb->socket_id[1], p_org_set);
+      BTIF_TRACE_DEBUG("found and set socket_id=%d is_set=%d",
+                       p_scb->socket_id[1],
+                       FD_ISSET(p_scb->socket_id[1], p_org_set));
+      p_mcb = BTIF_HL_GET_MCL_CB_PTR(p_scb->app_idx, p_scb->mcl_idx);
+      p_dcb = BTIF_HL_GET_MDL_CB_PTR(p_scb->app_idx, p_scb->mcl_idx,
+                                     p_scb->mdl_idx);
+      p_acb = BTIF_HL_GET_APP_CB_PTR(p_scb->app_idx);
+      if (p_mcb && p_dcb) {
+        btif_hl_stop_timer_using_handle(p_mcb->mcl_handle);
+        evt_param.chan_cb.app_id = p_acb->app_id;
+        memcpy(evt_param.chan_cb.bd_addr, p_mcb->bd_addr, sizeof(BD_ADDR));
+        evt_param.chan_cb.channel_id = p_dcb->channel_id;
+        evt_param.chan_cb.fd = p_scb->socket_id[0];
+        evt_param.chan_cb.mdep_cfg_index = (int)p_dcb->local_mdep_cfg_idx;
+        evt_param.chan_cb.cb_state = BTIF_HL_CHAN_CB_STATE_CONNECTED_PENDING;
+        len = sizeof(btif_hl_send_chan_state_cb_t);
+        status = btif_transfer_context(btif_hl_proc_cb_evt,
+                                       BTIF_HL_SEND_CONNECTED_CB,
+                                       (char*)&evt_param, len, NULL);
+        ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+      }
+    }
+  }
+  BTIF_TRACE_DEBUG("leaving %s", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_close_socket
+ *
+ * Description close a socket
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_close_socket(fd_set* p_org_set) {
+  BTIF_TRACE_DEBUG("entering %s", __func__);
+  for (const list_node_t* node = list_begin(soc_queue);
+       node != list_end(soc_queue); node = list_next(node)) {
+    btif_hl_soc_cb_t* p_scb = (btif_hl_soc_cb_t*)list_node(node);
+    if (btif_hl_get_socket_state(p_scb) == BTIF_HL_SOC_STATE_W4_REL) {
+      BTIF_TRACE_DEBUG("app_idx=%d mcl_id=%d, mdl_idx=%d", p_scb->app_idx,
+                       p_scb->mcl_idx, p_scb->mdl_idx);
+      btif_hl_set_socket_state(p_scb, BTIF_HL_SOC_STATE_IDLE);
+      if (p_scb->socket_id[1] != -1) {
+        FD_CLR(p_scb->socket_id[1], p_org_set);
+        shutdown(p_scb->socket_id[1], SHUT_RDWR);
+        close(p_scb->socket_id[1]);
+
+        btif_hl_evt_cb_t evt_param;
+        evt_param.chan_cb.app_id = (int)btif_hl_get_app_id(p_scb->channel_id);
+        memcpy(evt_param.chan_cb.bd_addr, p_scb->bd_addr, sizeof(BD_ADDR));
+        evt_param.chan_cb.channel_id = p_scb->channel_id;
+        evt_param.chan_cb.fd = p_scb->socket_id[0];
+        evt_param.chan_cb.mdep_cfg_index = (int)p_scb->mdep_cfg_idx;
+        evt_param.chan_cb.cb_state = BTIF_HL_CHAN_CB_STATE_DISCONNECTED_PENDING;
+        int len = sizeof(btif_hl_send_chan_state_cb_t);
+        bt_status_t status = btif_transfer_context(
+            btif_hl_proc_cb_evt, BTIF_HL_SEND_DISCONNECTED_CB,
+            (char*)&evt_param, len, NULL);
+        ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+      }
+    }
+  }
+
+  for (const list_node_t* node = list_begin(soc_queue);
+       node != list_end(soc_queue);) {
+    // We may mutate this list so we need keep track of
+    // the current node and only remove items behind.
+    btif_hl_soc_cb_t* p_scb = (btif_hl_soc_cb_t*)list_node(node);
+    BTIF_TRACE_DEBUG("p_scb=0x%x", p_scb);
+    node = list_next(node);
+    if (btif_hl_get_socket_state(p_scb) == BTIF_HL_SOC_STATE_IDLE) {
+      btif_hl_mdl_cb_t* p_dcb = BTIF_HL_GET_MDL_CB_PTR(
+          p_scb->app_idx, p_scb->mcl_idx, p_scb->mdl_idx);
+      BTIF_TRACE_DEBUG(
+          "idle socket app_idx=%d mcl_id=%d, mdl_idx=%d p_dcb->in_use=%d",
+          p_scb->app_idx, p_scb->mcl_idx, p_scb->mdl_idx, p_dcb->in_use);
+      list_remove(soc_queue, p_scb);
+      osi_free(p_scb);
+      p_dcb->p_scb = NULL;
+    }
+  }
+  BTIF_TRACE_DEBUG("leaving %s", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_select_wakeup_callback
+ *
+ * Description Select wakup callback to add or close a socket
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+void btif_hl_select_wakeup_callback(fd_set* p_org_set, int wakeup_signal) {
+  BTIF_TRACE_DEBUG("entering %s wakeup_signal=0x%04x", __func__, wakeup_signal);
+
+  if (wakeup_signal == btif_hl_signal_select_wakeup) {
+    btif_hl_add_socket_to_set(p_org_set);
+  } else if (wakeup_signal == btif_hl_signal_select_close_connected) {
+    btif_hl_close_socket(p_org_set);
+  }
+  BTIF_TRACE_DEBUG("leaving %s", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_select_monitor_callback
+ *
+ * Description Select monitor callback to check pending socket actions
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_select_monitor_callback(fd_set* p_cur_set,
+                                     UNUSED_ATTR fd_set *p_org_set) {
+  BTIF_TRACE_DEBUG("entering %s", __func__);
+
+  for (const list_node_t* node = list_begin(soc_queue);
+       node != list_end(soc_queue); node = list_next(node)) {
+    btif_hl_soc_cb_t* p_scb = (btif_hl_soc_cb_t*)list_node(node);
+    if (btif_hl_get_socket_state(p_scb) == BTIF_HL_SOC_STATE_W4_READ) {
+      if (FD_ISSET(p_scb->socket_id[1], p_cur_set)) {
+        BTIF_TRACE_DEBUG("read data state= BTIF_HL_SOC_STATE_W4_READ");
+        btif_hl_mdl_cb_t* p_dcb = BTIF_HL_GET_MDL_CB_PTR(
+            p_scb->app_idx, p_scb->mcl_idx, p_scb->mdl_idx);
+        assert(p_dcb != NULL);
+        if (p_dcb->p_tx_pkt) {
+          BTIF_TRACE_ERROR(
+              "Rcv new pkt but the last pkt is still not been"
+              "  sent tx_size=%d",
+              p_dcb->tx_size);
+          osi_free_and_reset((void**)&p_dcb->p_tx_pkt);
+        }
+        p_dcb->p_tx_pkt = (uint8_t*)osi_malloc(p_dcb->mtu);
+        ssize_t r;
+        OSI_NO_INTR(r = recv(p_scb->socket_id[1], p_dcb->p_tx_pkt, p_dcb->mtu,
+                             MSG_DONTWAIT));
+        if (r > 0) {
+          BTIF_TRACE_DEBUG("btif_hl_select_monitor_callback send data r =%d",
+                           r);
+          p_dcb->tx_size = r;
+          BTIF_TRACE_DEBUG(
+              "btif_hl_select_monitor_callback send data tx_size=%d",
+              p_dcb->tx_size);
+          BTA_HlSendData(p_dcb->mdl_handle, p_dcb->tx_size);
+        } else {
+          BTIF_TRACE_DEBUG(
+              "btif_hl_select_monitor_callback receive failed r=%d", r);
+          BTA_HlDchClose(p_dcb->mdl_handle);
+        }
+      }
+    }
+  }
+
+  if (list_is_empty(soc_queue))
+    BTIF_TRACE_DEBUG("btif_hl_select_monitor_queue is empty");
+
+  BTIF_TRACE_DEBUG("leaving %s", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_select_wakeup_init
+ *
+ * Description select loop wakup init
+ *
+ * Returns int
+ *
+ ******************************************************************************/
+static inline int btif_hl_select_wakeup_init(fd_set* set) {
+  BTIF_TRACE_DEBUG("%s", __func__);
+  if (signal_fds[0] == -1 &&
+      socketpair(AF_UNIX, SOCK_STREAM, 0, signal_fds) < 0) {
+    BTIF_TRACE_ERROR("socketpair failed: %s", strerror(errno));
+    return -1;
+  }
+
+  BTIF_TRACE_DEBUG(
+      "btif_hl_select_wakeup_init signal_fds[0]=%d signal_fds[1]=%d",
+      signal_fds[0], signal_fds[1]);
+  FD_SET(signal_fds[0], set);
+
+  return signal_fds[0];
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_select_wakeup
+ *
+ * Description send a signal to wakupo the select loop
+ *
+ * Returns int
+ *
+ ******************************************************************************/
+static inline int btif_hl_select_wakeup(void) {
+  char sig_on = btif_hl_signal_select_wakeup;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  ssize_t ret;
+  OSI_NO_INTR(ret = send(signal_fds[1], &sig_on, sizeof(sig_on), 0));
+
+  return (int)ret;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_select_close_connected
+ *
+ * Description send a signal to close a socket
+ *
+ * Returns int
+ *
+ ******************************************************************************/
+static inline int btif_hl_select_close_connected(void) {
+  char sig_on = btif_hl_signal_select_close_connected;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  ssize_t ret;
+  OSI_NO_INTR(ret = send(signal_fds[1], &sig_on, sizeof(sig_on), 0));
+
+  return (int)ret;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_close_select_thread
+ *
+ * Description send signal to close the thread and then close all signal FDs
+ *
+ * Returns int
+ *
+ ******************************************************************************/
+static inline int btif_hl_close_select_thread(void) {
+  ssize_t result = 0;
+  char sig_on = btif_hl_signal_select_exit;
+
+  BTIF_TRACE_DEBUG("%", __func__);
+
+  OSI_NO_INTR(result = send(signal_fds[1], &sig_on, sizeof(sig_on), 0));
+
+  if (btif_is_enabled()) {
+    /* Wait for the select_thread_id to exit if BT is still enabled
+    and only this profile getting  cleaned up*/
+    if (select_thread_id != -1) {
+      pthread_join(select_thread_id, NULL);
+      select_thread_id = -1;
+    }
+  }
+  list_free(soc_queue);
+  soc_queue = NULL;
+
+  return (int)result;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_select_wake_reset
+ *
+ * Description clear the received signal for the select loop
+ *
+ * Returns int
+ *
+ ******************************************************************************/
+static inline int btif_hl_select_wake_reset(void) {
+  char sig_recv = 0;
+
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  ssize_t r;
+  OSI_NO_INTR(
+      r = recv(signal_fds[0], &sig_recv, sizeof(sig_recv), MSG_WAITALL));
+
+  return (int)sig_recv;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_select_wake_signaled
+ *
+ * Description check whether a fd is set or not
+ *
+ * Returns int
+ *
+ ******************************************************************************/
+static inline int btif_hl_select_wake_signaled(fd_set* set) {
+  BTIF_TRACE_DEBUG("btif_hl_select_wake_signaled");
+  return FD_ISSET(signal_fds[0], set);
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_thread_cleanup
+ *
+ * Description  shut down and clean up the select loop
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hl_thread_cleanup() {
+  if (listen_s != -1) close(listen_s);
+  if (connected_s != -1) {
+    shutdown(connected_s, SHUT_RDWR);
+    close(connected_s);
+  }
+  listen_s = connected_s = -1;
+  BTIF_TRACE_DEBUG("hl thread cleanup");
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_select_thread
+ *
+ * Description the select loop
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void* btif_hl_select_thread(UNUSED_ATTR void *arg) {
+  fd_set org_set, curr_set;
+  int r, max_curr_s, max_org_s;
+
+  BTIF_TRACE_DEBUG("entered btif_hl_select_thread");
+  FD_ZERO(&org_set);
+  max_org_s = btif_hl_select_wakeup_init(&org_set);
+  BTIF_TRACE_DEBUG("max_s=%d ", max_org_s);
+
+  for (;;) {
+    r = 0;
+    BTIF_TRACE_DEBUG("set curr_set = org_set ");
+    curr_set = org_set;
+    max_curr_s = max_org_s;
+    int ret = select((max_curr_s + 1), &curr_set, NULL, NULL, NULL);
+    BTIF_TRACE_DEBUG("select unblocked ret=%d", ret);
+    if (ret == -1) {
+      if (errno == EINTR) continue;
+      BTIF_TRACE_DEBUG("select() ret -1, exit the thread");
+      btif_hl_thread_cleanup();
+      select_thread_id = -1;
+      return 0;
+    } else if (ret) {
+      BTIF_TRACE_DEBUG("btif_hl_select_wake_signaled, signal ret=%d", ret);
+      if (btif_hl_select_wake_signaled(&curr_set)) {
+        r = btif_hl_select_wake_reset();
+        BTIF_TRACE_DEBUG("btif_hl_select_wake_signaled, signal:%d", r);
+        if (r == btif_hl_signal_select_wakeup ||
+            r == btif_hl_signal_select_close_connected) {
+          btif_hl_select_wakeup_callback(&org_set, r);
+        } else if (r == btif_hl_signal_select_exit) {
+          btif_hl_thread_cleanup();
+          BTIF_TRACE_DEBUG(
+              "Exit hl_select_thread for btif_hl_signal_select_exit");
+          return 0;
+        }
+      }
+
+      btif_hl_select_monitor_callback(&curr_set, &org_set);
+      max_org_s = btif_hl_update_maxfd(max_org_s);
+    } else
+      BTIF_TRACE_DEBUG("no data, select ret: %d\n", ret);
+  }
+  BTIF_TRACE_DEBUG("leaving hl_select_thread");
+  return 0;
+}
+
+/*******************************************************************************
+ *
+ * Function create_thread
+ *
+ * Description creat a select loop
+ *
+ * Returns pthread_t
+ *
+ ******************************************************************************/
+static inline pthread_t create_thread(void* (*start_routine)(void*),
+                                      void* arg) {
+  BTIF_TRACE_DEBUG("create_thread: entered");
+  pthread_attr_t thread_attr;
+
+  pthread_attr_init(&thread_attr);
+  pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+  pthread_t thread_id = -1;
+  if (pthread_create(&thread_id, &thread_attr, start_routine, arg) != 0) {
+    BTIF_TRACE_ERROR("pthread_create : %s", strerror(errno));
+    return -1;
+  }
+  BTIF_TRACE_DEBUG("create_thread: thread created successfully");
+  return thread_id;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_hl_soc_thread_init
+ *
+ * Description      HL select loop init function.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btif_hl_soc_thread_init(void) {
+  BTIF_TRACE_DEBUG("%s", __func__);
+  soc_queue = list_new(NULL);
+  if (soc_queue == NULL)
+    LOG_ERROR(LOG_TAG, "%s unable to allocate resources for thread", __func__);
+  select_thread_id = create_thread(btif_hl_select_thread, NULL);
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_load_mdl_config
+ *
+ * Description load the MDL configuation from the application control block
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_load_mdl_config(uint8_t app_id, uint8_t buffer_size,
+                             tBTA_HL_MDL_CFG* p_mdl_buf) {
+  uint8_t app_idx;
+  bool result = false;
+  btif_hl_app_cb_t* p_acb;
+  tBTA_HL_MDL_CFG* p;
+  int i;
+  BTIF_TRACE_DEBUG("%s", __func__);
+
+  if (btif_hl_find_app_idx(app_id, &app_idx)) {
+    p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+    for (i = 0, p = p_mdl_buf; i < buffer_size; i++, p++) {
+      memcpy(p, &p_acb->mdl_cfg[i].base, sizeof(tBTA_HL_MDL_CFG));
+    }
+    result = true;
+  }
+
+  BTIF_TRACE_DEBUG("result=%d", result);
+  return result;
+}
diff --git a/bt/btif/src/btif_mce.cc b/bt/btif/src/btif_mce.cc
new file mode 100644
index 0000000..8bb4af7
--- /dev/null
+++ b/bt/btif/src/btif_mce.cc
@@ -0,0 +1,168 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ *  Filename:      btif_mce.c
+ *
+ *  Description:   Message Access Profile (MCE role) Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+
+#define LOG_TAG "bt_btif_mce"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_mce.h>
+
+#include "bt_types.h"
+#include "bta_api.h"
+#include "bta_mce_api.h"
+#include "btcore/include/bdaddr.h"
+#include "btif_common.h"
+#include "btif_profile_queue.h"
+#include "btif_util.h"
+
+/*****************************************************************************
+ *  Static variables
+ *****************************************************************************/
+
+static btmce_callbacks_t* bt_mce_callbacks = NULL;
+
+static void btif_mce_mas_discovery_comp_evt(uint16_t event, char* p_param) {
+  tBTA_MCE_MAS_DISCOVERY_COMP* evt_data = (tBTA_MCE_MAS_DISCOVERY_COMP*)p_param;
+  btmce_mas_instance_t insts[BTA_MCE_MAX_MAS_INSTANCES];
+  bt_bdaddr_t addr;
+  int i;
+
+  BTIF_TRACE_EVENT("%s:  event = %d", __func__, event);
+
+  if (event != BTA_MCE_MAS_DISCOVERY_COMP_EVT) return;
+
+  for (i = 0; i < evt_data->num_mas; i++) {
+    insts[i].id = evt_data->mas[i].instance_id;
+    insts[i].scn = evt_data->mas[i].scn;
+    insts[i].msg_types = evt_data->mas[i].msg_type;
+    insts[i].p_name = evt_data->mas[i].p_srv_name;
+  }
+
+  bdcpy(addr.address, evt_data->remote_addr);
+
+  HAL_CBACK(bt_mce_callbacks, remote_mas_instances_cb,
+            (bt_status_t)evt_data->status, &addr, evt_data->num_mas, insts);
+}
+
+static void mas_discovery_comp_copy_cb(uint16_t event, char* p_dest,
+                                       char* p_src) {
+  tBTA_MCE_MAS_DISCOVERY_COMP* p_dest_data =
+      (tBTA_MCE_MAS_DISCOVERY_COMP*)p_dest;
+  tBTA_MCE_MAS_DISCOVERY_COMP* p_src_data = (tBTA_MCE_MAS_DISCOVERY_COMP*)p_src;
+  char* p_dest_str;
+  int i;
+
+  if (!p_src) return;
+
+  if (event != BTA_MCE_MAS_DISCOVERY_COMP_EVT) return;
+
+  maybe_non_aligned_memcpy(p_dest_data, p_src_data, sizeof(*p_src_data));
+
+  p_dest_str = p_dest + sizeof(tBTA_MCE_MAS_DISCOVERY_COMP);
+
+  for (i = 0; i < p_src_data->num_mas; i++) {
+    p_dest_data->mas[i].p_srv_name = p_dest_str;
+    memcpy(p_dest_str, p_src_data->mas[i].p_srv_name,
+           p_src_data->mas[i].srv_name_len);
+    p_dest_str += p_src_data->mas[i].srv_name_len;
+    *(p_dest_str++) = '\0';
+  }
+}
+
+static void mce_dm_cback(tBTA_MCE_EVT event, tBTA_MCE* p_data,
+                         void* user_data) {
+  switch (event) {
+    case BTA_MCE_MAS_DISCOVERY_COMP_EVT: {
+      int i;
+      uint16_t param_len = sizeof(tBTA_MCE);
+
+      /* include space for all p_srv_name copies including null-termination */
+      for (i = 0; i < p_data->mas_disc_comp.num_mas; i++)
+        param_len += (p_data->mas_disc_comp.mas[i].srv_name_len + 1);
+
+      /* need to deepy copy p_srv_name and null-terminate */
+      btif_transfer_context(btif_mce_mas_discovery_comp_evt, event,
+                            (char*)p_data, param_len,
+                            mas_discovery_comp_copy_cb);
+
+      break;
+    }
+  }
+}
+
+static bt_status_t init(btmce_callbacks_t* callbacks) {
+  BTIF_TRACE_EVENT("%s", __func__);
+
+  bt_mce_callbacks = callbacks;
+
+  btif_enable_service(BTA_MAP_SERVICE_ID);
+
+  return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t get_remote_mas_instances(bt_bdaddr_t* bd_addr) {
+  bdstr_t bdstr;
+
+  BTIF_TRACE_EVENT("%s: remote_addr=%s", __func__,
+                   bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr)));
+
+  BTA_MceGetRemoteMasInstances(bd_addr->address);
+
+  return BT_STATUS_SUCCESS;
+}
+
+static const btmce_interface_t mce_if = {
+    sizeof(btmce_interface_t), init, get_remote_mas_instances,
+};
+
+const btmce_interface_t* btif_mce_get_interface(void) {
+  BTIF_TRACE_EVENT("%s", __func__);
+  return &mce_if;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_mce_execute_service
+ *
+ * Description      Initializes/Shuts down the service
+ *
+ * Returns          BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_mce_execute_service(bool b_enable) {
+  BTIF_TRACE_EVENT("%s enable:%d", __func__, b_enable);
+
+  if (b_enable) {
+    BTA_MceEnable(mce_dm_cback);
+  } else {
+    /* This is called on BT disable so no need to extra cleanup */
+  }
+  return BT_STATUS_SUCCESS;
+}
diff --git a/bt/btif/src/btif_pan.cc b/bt/btif/src/btif_pan.cc
new file mode 100644
index 0000000..59b1017
--- /dev/null
+++ b/bt/btif/src/btif_pan.cc
@@ -0,0 +1,782 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ *  Filename:      btif_pan.c
+ *
+ *  Description:   PAN Profile Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+
+#define LOG_TAG "bt_btif_pan"
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/if_ether.h>
+#include <linux/if_tun.h>
+#include <linux/sockios.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/prctl.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_pan.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_pan_api.h"
+#include "btcore/include/bdaddr.h"
+#include "btif_common.h"
+#include "btif_pan_internal.h"
+#include "btif_sock_thread.h"
+#include "btif_sock_util.h"
+#include "btif_util.h"
+#include "btm_api.h"
+#include "device/include/controller.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#define FORWARD_IGNORE 1
+#define FORWARD_SUCCESS 0
+#define FORWARD_FAILURE (-1)
+#define FORWARD_CONGEST (-2)
+
+#if (PAN_NAP_DISABLED == TRUE && PANU_DISABLED == TRUE)
+#define BTPAN_LOCAL_ROLE BTPAN_ROLE_NONE
+#elif PAN_NAP_DISABLED == TRUE
+#define BTPAN_LOCAL_ROLE BTPAN_ROLE_PANU
+#elif PANU_DISABLED == TRUE
+#define BTPAN_LOCAL_ROLE BTPAN_ROLE_PANNAP
+#else
+#define BTPAN_LOCAL_ROLE (BTPAN_ROLE_PANU | BTPAN_ROLE_PANNAP)
+#endif
+
+#define asrt(s)                                                          \
+  do {                                                                   \
+    if (!(s))                                                            \
+      BTIF_TRACE_ERROR("btif_pan: ## %s assert %s failed at line:%d ##", \
+                       __func__, #s, __LINE__)                           \
+  } while (0)
+
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+
+btpan_cb_t btpan_cb;
+
+static bool jni_initialized;
+static bool stack_initialized;
+
+static bt_status_t btpan_jni_init(const btpan_callbacks_t* callbacks);
+static void btpan_jni_cleanup();
+static bt_status_t btpan_connect(const bt_bdaddr_t* bd_addr, int local_role,
+                                 int remote_role);
+static bt_status_t btpan_disconnect(const bt_bdaddr_t* bd_addr);
+static bt_status_t btpan_enable(int local_role);
+static int btpan_get_local_role(void);
+
+static void btpan_tap_fd_signaled(int fd, int type, int flags,
+                                  uint32_t user_id);
+static void btpan_cleanup_conn(btpan_conn_t* conn);
+static void bta_pan_callback(tBTA_PAN_EVT event, tBTA_PAN* p_data);
+static void btu_exec_tap_fd_read(void* p_param);
+
+static btpan_interface_t pan_if = {
+    sizeof(pan_if), btpan_jni_init,   btpan_enable,     btpan_get_local_role,
+    btpan_connect,  btpan_disconnect, btpan_jni_cleanup};
+
+btpan_interface_t* btif_pan_get_interface() { return &pan_if; }
+
+/*******************************************************************************
+ **
+ ** Function        btif_pan_init
+ **
+ ** Description     initializes the pan interface
+ **
+ ** Returns         bt_status_t
+ **
+ *******************************************************************************/
+void btif_pan_init() {
+  BTIF_TRACE_DEBUG("jni_initialized = %d, btpan_cb.enabled:%d", jni_initialized,
+                   btpan_cb.enabled);
+  stack_initialized = true;
+
+  if (jni_initialized && !btpan_cb.enabled) {
+    BTIF_TRACE_DEBUG("Enabling PAN....");
+    memset(&btpan_cb, 0, sizeof(btpan_cb));
+    btpan_cb.tap_fd = INVALID_FD;
+    btpan_cb.flow = 1;
+    for (int i = 0; i < MAX_PAN_CONNS; i++)
+      btpan_cleanup_conn(&btpan_cb.conns[i]);
+    BTA_PanEnable(bta_pan_callback);
+    btpan_cb.enabled = 1;
+    btpan_enable(BTPAN_LOCAL_ROLE);
+  }
+}
+
+static void pan_disable() {
+  if (btpan_cb.enabled) {
+    btpan_cb.enabled = 0;
+    BTA_PanDisable();
+    if (btpan_cb.tap_fd != INVALID_FD) {
+      btpan_tap_close(btpan_cb.tap_fd);
+      btpan_cb.tap_fd = INVALID_FD;
+    }
+  }
+}
+
+void btif_pan_cleanup() {
+  if (!stack_initialized) return;
+
+  // Bluetooth is shuting down, invalidate all BTA PAN handles
+  for (int i = 0; i < MAX_PAN_CONNS; i++)
+    btpan_cleanup_conn(&btpan_cb.conns[i]);
+
+  pan_disable();
+  stack_initialized = false;
+}
+
+static btpan_callbacks_t callback;
+static bt_status_t btpan_jni_init(const btpan_callbacks_t* callbacks) {
+  BTIF_TRACE_DEBUG("stack_initialized = %d, btpan_cb.enabled:%d",
+                   stack_initialized, btpan_cb.enabled);
+  callback = *callbacks;
+  jni_initialized = true;
+  if (stack_initialized && !btpan_cb.enabled) btif_pan_init();
+  return BT_STATUS_SUCCESS;
+}
+
+static void btpan_jni_cleanup() {
+  pan_disable();
+  jni_initialized = false;
+}
+
+static inline int bta_role_to_btpan(int bta_pan_role) {
+  int btpan_role = 0;
+  BTIF_TRACE_DEBUG("bta_pan_role:0x%x", bta_pan_role);
+  if (bta_pan_role & PAN_ROLE_NAP_SERVER) btpan_role |= BTPAN_ROLE_PANNAP;
+  if (bta_pan_role & PAN_ROLE_CLIENT) btpan_role |= BTPAN_ROLE_PANU;
+  return btpan_role;
+}
+
+static inline int btpan_role_to_bta(int btpan_role) {
+  int bta_pan_role = PAN_ROLE_INACTIVE;
+  BTIF_TRACE_DEBUG("btpan_role:0x%x", btpan_role);
+  if (btpan_role & BTPAN_ROLE_PANNAP) bta_pan_role |= PAN_ROLE_NAP_SERVER;
+  if (btpan_role & BTPAN_ROLE_PANU) bta_pan_role |= PAN_ROLE_CLIENT;
+  return bta_pan_role;
+}
+
+static volatile int btpan_dev_local_role;
+#if (BTA_PAN_INCLUDED == TRUE)
+static tBTA_PAN_ROLE_INFO bta_panu_info = {PANU_SERVICE_NAME, 0, PAN_SECURITY};
+static tBTA_PAN_ROLE_INFO bta_pan_nap_info = {PAN_NAP_SERVICE_NAME, 1,
+                                              PAN_SECURITY};
+#endif
+
+static bt_status_t btpan_enable(int local_role) {
+#if (BTA_PAN_INCLUDED == TRUE)
+  BTIF_TRACE_DEBUG("%s - local_role: %d", __func__, local_role);
+  int bta_pan_role = btpan_role_to_bta(local_role);
+  BTA_PanSetRole(bta_pan_role, &bta_panu_info, NULL, &bta_pan_nap_info);
+  btpan_dev_local_role = local_role;
+  return BT_STATUS_SUCCESS;
+#else
+  return BT_STATUS_FAIL;
+#endif
+}
+
+static int btpan_get_local_role() {
+  BTIF_TRACE_DEBUG("btpan_dev_local_role:%d", btpan_dev_local_role);
+  return btpan_dev_local_role;
+}
+
+static bt_status_t btpan_connect(const bt_bdaddr_t* bd_addr, int local_role,
+                                 int remote_role) {
+  BTIF_TRACE_DEBUG("local_role:%d, remote_role:%d", local_role, remote_role);
+  int bta_local_role = btpan_role_to_bta(local_role);
+  int bta_remote_role = btpan_role_to_bta(remote_role);
+  btpan_new_conn(-1, bd_addr->address, bta_local_role, bta_remote_role);
+  BTA_PanOpen((uint8_t*)bd_addr->address, bta_local_role, bta_remote_role);
+  return BT_STATUS_SUCCESS;
+}
+
+static void btif_in_pan_generic_evt(uint16_t event, char* p_param) {
+  BTIF_TRACE_EVENT("%s: event=%d", __func__, event);
+  switch (event) {
+    case BTIF_PAN_CB_DISCONNECTING: {
+      bt_bdaddr_t* bd_addr = (bt_bdaddr_t*)p_param;
+      btpan_conn_t* conn = btpan_find_conn_addr(bd_addr->address);
+      int btpan_conn_local_role;
+      int btpan_remote_role;
+      asrt(conn != NULL);
+      if (conn) {
+        btpan_conn_local_role = bta_role_to_btpan(conn->local_role);
+        btpan_remote_role = bta_role_to_btpan(conn->remote_role);
+        callback.connection_state_cb(BTPAN_STATE_DISCONNECTING,
+                                     BT_STATUS_SUCCESS,
+                                     (const bt_bdaddr_t*)conn->peer,
+                                     btpan_conn_local_role, btpan_remote_role);
+      }
+    } break;
+    default: {
+      BTIF_TRACE_WARNING("%s : Unknown event 0x%x", __func__, event);
+    } break;
+  }
+}
+
+static bt_status_t btpan_disconnect(const bt_bdaddr_t* bd_addr) {
+  btpan_conn_t* conn = btpan_find_conn_addr(bd_addr->address);
+  if (conn && conn->handle >= 0) {
+    /* Inform the application that the disconnect has been initiated
+     * successfully */
+    btif_transfer_context(btif_in_pan_generic_evt, BTIF_PAN_CB_DISCONNECTING,
+                          (char*)bd_addr, sizeof(bt_bdaddr_t), NULL);
+    BTA_PanClose(conn->handle);
+    return BT_STATUS_SUCCESS;
+  }
+  return BT_STATUS_FAIL;
+}
+
+static int pan_pth = -1;
+void create_tap_read_thread(int tap_fd) {
+  if (pan_pth < 0) pan_pth = btsock_thread_create(btpan_tap_fd_signaled, NULL);
+  if (pan_pth >= 0)
+    btsock_thread_add_fd(pan_pth, tap_fd, 0, SOCK_THREAD_FD_RD, 0);
+}
+
+void destroy_tap_read_thread(void) {
+  if (pan_pth >= 0) {
+    btsock_thread_exit(pan_pth);
+    pan_pth = -1;
+  }
+}
+
+static int tap_if_up(const char* devname, const bt_bdaddr_t* addr) {
+  struct ifreq ifr;
+  int sk, err;
+
+  sk = socket(AF_INET, SOCK_DGRAM, 0);
+  if (sk < 0) return -1;
+
+  // set mac addr
+  memset(&ifr, 0, sizeof(ifr));
+  strncpy(ifr.ifr_name, devname, IFNAMSIZ - 1);
+  err = ioctl(sk, SIOCGIFHWADDR, &ifr);
+  if (err < 0) {
+    BTIF_TRACE_ERROR(
+        "Could not get network hardware for interface:%s, errno:%s", devname,
+        strerror(errno));
+    close(sk);
+    return -1;
+  }
+
+  strncpy(ifr.ifr_name, devname, IFNAMSIZ - 1);
+  memcpy(ifr.ifr_hwaddr.sa_data, addr->address, 6);
+
+  /* The IEEE has specified that the most significant bit of the most
+   * significant byte is used to
+   * determine a multicast address. If its a 1, that means multicast, 0 means
+   * unicast.
+   * Kernel returns an error if we try to set a multicast address for the
+   * tun-tap ethernet interface.
+   * Mask this bit to avoid any issue with auto generated address.
+   */
+  if (ifr.ifr_hwaddr.sa_data[0] & 0x01) {
+    BTIF_TRACE_WARNING(
+        "Not a unicast MAC address, force multicast bit flipping");
+    ifr.ifr_hwaddr.sa_data[0] &= ~0x01;
+  }
+
+  err = ioctl(sk, SIOCSIFHWADDR, (caddr_t)&ifr);
+
+  if (err < 0) {
+    BTIF_TRACE_ERROR("Could not set bt address for interface:%s, errno:%s",
+                     devname, strerror(errno));
+    close(sk);
+    return -1;
+  }
+
+  // bring it up
+  memset(&ifr, 0, sizeof(ifr));
+  strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
+
+  ifr.ifr_flags |= IFF_UP;
+  ifr.ifr_flags |= IFF_MULTICAST;
+
+  err = ioctl(sk, SIOCSIFFLAGS, (caddr_t)&ifr);
+
+  if (err < 0) {
+    BTIF_TRACE_ERROR("Could not bring up network interface:%s, errno:%d",
+                     devname, errno);
+    close(sk);
+    return -1;
+  }
+  close(sk);
+  BTIF_TRACE_DEBUG("network interface: %s is up", devname);
+  return 0;
+}
+
+static int tap_if_down(const char* devname) {
+  struct ifreq ifr;
+  int sk;
+
+  sk = socket(AF_INET, SOCK_DGRAM, 0);
+  if (sk < 0) return -1;
+
+  memset(&ifr, 0, sizeof(ifr));
+  strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
+
+  ifr.ifr_flags &= ~IFF_UP;
+
+  ioctl(sk, SIOCSIFFLAGS, (caddr_t)&ifr);
+
+  close(sk);
+
+  return 0;
+}
+
+void btpan_set_flow_control(bool enable) {
+  if (btpan_cb.tap_fd == -1) return;
+
+  btpan_cb.flow = enable;
+  if (enable) {
+    btsock_thread_add_fd(pan_pth, btpan_cb.tap_fd, 0, SOCK_THREAD_FD_RD, 0);
+    bta_dmexecutecallback(btu_exec_tap_fd_read, INT_TO_PTR(btpan_cb.tap_fd));
+  }
+}
+
+int btpan_tap_open() {
+  struct ifreq ifr;
+  int fd, err;
+  const char* clonedev = "/dev/tun";
+
+  /* open the clone device */
+
+  if ((fd = open(clonedev, O_RDWR)) < 0) {
+    BTIF_TRACE_DEBUG("could not open %s, err:%d", clonedev, errno);
+    return fd;
+  }
+
+  memset(&ifr, 0, sizeof(ifr));
+  ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+
+  strncpy(ifr.ifr_name, TAP_IF_NAME, IFNAMSIZ);
+
+  /* try to create the device */
+  if ((err = ioctl(fd, TUNSETIFF, (void*)&ifr)) < 0) {
+    BTIF_TRACE_DEBUG("ioctl error:%d, errno:%s", err, strerror(errno));
+    close(fd);
+    return err;
+  }
+  if (tap_if_up(TAP_IF_NAME, controller_get_interface()->get_address()) == 0) {
+    int flags = fcntl(fd, F_GETFL, 0);
+    fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+    return fd;
+  }
+  BTIF_TRACE_ERROR("can not bring up tap interface:%s", TAP_IF_NAME);
+  close(fd);
+  return INVALID_FD;
+}
+
+int btpan_tap_send(int tap_fd, const BD_ADDR src, const BD_ADDR dst,
+                   uint16_t proto, const char* buf, uint16_t len, UNUSED_ATTR bool ext,
+                   UNUSED_ATTR bool forward) {
+  if (tap_fd != INVALID_FD) {
+    tETH_HDR eth_hdr;
+    memcpy(&eth_hdr.h_dest, dst, ETH_ADDR_LEN);
+    memcpy(&eth_hdr.h_src, src, ETH_ADDR_LEN);
+    eth_hdr.h_proto = htons(proto);
+    char packet[TAP_MAX_PKT_WRITE_LEN + sizeof(tETH_HDR)];
+    memcpy(packet, &eth_hdr, sizeof(tETH_HDR));
+    if (len > TAP_MAX_PKT_WRITE_LEN) {
+      LOG_ERROR(LOG_TAG, "btpan_tap_send eth packet size:%d is exceeded limit!",
+                len);
+      return -1;
+    }
+    memcpy(packet + sizeof(tETH_HDR), buf, len);
+
+    /* Send data to network interface */
+    ssize_t ret;
+    OSI_NO_INTR(ret = write(tap_fd, packet, len + sizeof(tETH_HDR)));
+    BTIF_TRACE_DEBUG("ret:%d", ret);
+    return (int)ret;
+  }
+  return -1;
+}
+
+int btpan_tap_close(int fd) {
+  if (tap_if_down(TAP_IF_NAME) == 0) close(fd);
+  if (pan_pth >= 0) btsock_thread_wakeup(pan_pth);
+  return 0;
+}
+
+btpan_conn_t* btpan_find_conn_handle(uint16_t handle) {
+  for (int i = 0; i < MAX_PAN_CONNS; i++) {
+    if (btpan_cb.conns[i].handle == handle) return &btpan_cb.conns[i];
+  }
+  return NULL;
+}
+
+btpan_conn_t* btpan_find_conn_addr(const BD_ADDR addr) {
+  for (int i = 0; i < MAX_PAN_CONNS; i++) {
+    if (memcmp(btpan_cb.conns[i].peer, addr, sizeof(BD_ADDR)) == 0)
+      return &btpan_cb.conns[i];
+  }
+  return NULL;
+}
+
+static void btpan_open_conn(btpan_conn_t* conn, tBTA_PAN* p_data) {
+  BTIF_TRACE_API(
+      "btpan_open_conn: local_role:%d, peer_role: %d,  handle:%d, conn: %p",
+      p_data->open.local_role, p_data->open.peer_role, p_data->open.handle,
+      conn);
+
+  if (conn == NULL)
+    conn = btpan_new_conn(p_data->open.handle, p_data->open.bd_addr,
+                          p_data->open.local_role, p_data->open.peer_role);
+  if (conn) {
+    BTIF_TRACE_DEBUG(
+        "btpan_open_conn:tap_fd:%d, open_count:%d, "
+        "conn->handle:%d should = handle:%d, local_role:%d, remote_role:%d",
+        btpan_cb.tap_fd, btpan_cb.open_count, conn->handle, p_data->open.handle,
+        conn->local_role, conn->remote_role);
+
+    btpan_cb.open_count++;
+    conn->handle = p_data->open.handle;
+    if (btpan_cb.tap_fd < 0) {
+      btpan_cb.tap_fd = btpan_tap_open();
+      if (btpan_cb.tap_fd >= 0) create_tap_read_thread(btpan_cb.tap_fd);
+    }
+
+    if (btpan_cb.tap_fd >= 0) {
+      btpan_cb.flow = 1;
+      conn->state = PAN_STATE_OPEN;
+    }
+  }
+}
+
+static void btpan_close_conn(btpan_conn_t* conn) {
+  BTIF_TRACE_API("btpan_close_conn: %p", conn);
+
+  if (conn && conn->state == PAN_STATE_OPEN) {
+    BTIF_TRACE_DEBUG("btpan_close_conn: PAN_STATE_OPEN");
+
+    conn->state = PAN_STATE_CLOSE;
+    btpan_cb.open_count--;
+
+    if (btpan_cb.open_count == 0) {
+      destroy_tap_read_thread();
+      if (btpan_cb.tap_fd != INVALID_FD) {
+        btpan_tap_close(btpan_cb.tap_fd);
+        btpan_cb.tap_fd = INVALID_FD;
+      }
+    }
+  }
+}
+
+static void btpan_cleanup_conn(btpan_conn_t* conn) {
+  if (conn) {
+    conn->handle = -1;
+    conn->state = -1;
+    memset(&conn->peer, 0, sizeof(conn->peer));
+    memset(&conn->eth_addr, 0, sizeof(conn->eth_addr));
+    conn->local_role = conn->remote_role = 0;
+  }
+}
+
+btpan_conn_t* btpan_new_conn(int handle, const BD_ADDR addr, int local_role,
+                             int remote_role) {
+  for (int i = 0; i < MAX_PAN_CONNS; i++) {
+    BTIF_TRACE_DEBUG("conns[%d]:%d", i, btpan_cb.conns[i].handle);
+    if (btpan_cb.conns[i].handle == -1) {
+      BTIF_TRACE_DEBUG("handle:%d, local_role:%d, remote_role:%d", handle,
+                       local_role, remote_role);
+
+      btpan_cb.conns[i].handle = handle;
+      bdcpy(btpan_cb.conns[i].peer, addr);
+      btpan_cb.conns[i].local_role = local_role;
+      btpan_cb.conns[i].remote_role = remote_role;
+      return &btpan_cb.conns[i];
+    }
+  }
+  BTIF_TRACE_DEBUG("MAX_PAN_CONNS:%d exceeded, return NULL as failed",
+                   MAX_PAN_CONNS);
+  return NULL;
+}
+
+void btpan_close_handle(btpan_conn_t* p) {
+  BTIF_TRACE_DEBUG("btpan_close_handle : close handle %d", p->handle);
+  p->handle = -1;
+  p->local_role = -1;
+  p->remote_role = -1;
+  memset(&p->peer, 0, 6);
+}
+
+static inline bool should_forward(tETH_HDR* hdr) {
+  uint16_t proto = ntohs(hdr->h_proto);
+  if (proto == ETH_P_IP || proto == ETH_P_ARP || proto == ETH_P_IPV6)
+    return true;
+  BTIF_TRACE_DEBUG("unknown proto:%x", proto);
+  return false;
+}
+
+static int forward_bnep(tETH_HDR* eth_hdr, BT_HDR* hdr) {
+  int broadcast = eth_hdr->h_dest[0] & 1;
+
+  // Find the right connection to send this frame over.
+  for (int i = 0; i < MAX_PAN_CONNS; i++) {
+    uint16_t handle = btpan_cb.conns[i].handle;
+    if (handle != (uint16_t)-1 &&
+        (broadcast ||
+         memcmp(btpan_cb.conns[i].eth_addr, eth_hdr->h_dest, sizeof(BD_ADDR)) ==
+             0 ||
+         memcmp(btpan_cb.conns[i].peer, eth_hdr->h_dest, sizeof(BD_ADDR)) ==
+             0)) {
+      int result = PAN_WriteBuf(handle, eth_hdr->h_dest, eth_hdr->h_src,
+                                ntohs(eth_hdr->h_proto), hdr, 0);
+      switch (result) {
+        case PAN_Q_SIZE_EXCEEDED:
+          return FORWARD_CONGEST;
+        case PAN_SUCCESS:
+          return FORWARD_SUCCESS;
+        default:
+          return FORWARD_FAILURE;
+      }
+    }
+  }
+  osi_free(hdr);
+  return FORWARD_IGNORE;
+}
+
+static void bta_pan_callback_transfer(uint16_t event, char* p_param) {
+  tBTA_PAN* p_data = (tBTA_PAN*)p_param;
+
+  switch (event) {
+    case BTA_PAN_ENABLE_EVT:
+      BTIF_TRACE_DEBUG("BTA_PAN_ENABLE_EVT");
+      break;
+    case BTA_PAN_SET_ROLE_EVT: {
+      int btpan_role = bta_role_to_btpan(p_data->set_role.role);
+      bt_status_t status = p_data->set_role.status == BTA_PAN_SUCCESS
+                               ? BT_STATUS_SUCCESS
+                               : BT_STATUS_FAIL;
+      btpan_control_state_t state =
+          btpan_role == 0 ? BTPAN_STATE_DISABLED : BTPAN_STATE_ENABLED;
+      callback.control_state_cb(state, btpan_role, status, TAP_IF_NAME);
+      break;
+    }
+    case BTA_PAN_OPENING_EVT: {
+      btpan_conn_t* conn;
+      bdstr_t bds;
+      bdaddr_to_string((bt_bdaddr_t*)p_data->opening.bd_addr, bds, sizeof(bds));
+      BTIF_TRACE_DEBUG("BTA_PAN_OPENING_EVT handle %d, addr: %s",
+                       p_data->opening.handle, bds);
+      conn = btpan_find_conn_addr(p_data->opening.bd_addr);
+
+      asrt(conn != NULL);
+      if (conn) {
+        conn->handle = p_data->opening.handle;
+        int btpan_conn_local_role = bta_role_to_btpan(conn->local_role);
+        int btpan_remote_role = bta_role_to_btpan(conn->remote_role);
+        callback.connection_state_cb(
+            BTPAN_STATE_CONNECTING, BT_STATUS_SUCCESS,
+            (const bt_bdaddr_t*)p_data->opening.bd_addr, btpan_conn_local_role,
+            btpan_remote_role);
+      } else
+        BTIF_TRACE_ERROR("connection not found");
+      break;
+    }
+    case BTA_PAN_OPEN_EVT: {
+      btpan_connection_state_t state;
+      bt_status_t status;
+      btpan_conn_t* conn = btpan_find_conn_handle(p_data->open.handle);
+
+      LOG_VERBOSE(LOG_TAG, "%s pan connection open status: %d", __func__,
+                  p_data->open.status);
+      if (p_data->open.status == BTA_PAN_SUCCESS) {
+        state = BTPAN_STATE_CONNECTED;
+        status = BT_STATUS_SUCCESS;
+        btpan_open_conn(conn, p_data);
+      } else {
+        state = BTPAN_STATE_DISCONNECTED;
+        status = BT_STATUS_FAIL;
+        btpan_cleanup_conn(conn);
+      }
+      /* debug("BTA_PAN_OPEN_EVT handle:%d, conn:%p",  p_data->open.handle,
+       * conn); */
+      /* debug("conn bta local_role:%d, bta remote role:%d", conn->local_role,
+       * conn->remote_role); */
+      int btpan_conn_local_role = bta_role_to_btpan(p_data->open.local_role);
+      int btpan_remote_role = bta_role_to_btpan(p_data->open.peer_role);
+      callback.connection_state_cb(state, status,
+                                   (const bt_bdaddr_t*)p_data->open.bd_addr,
+                                   btpan_conn_local_role, btpan_remote_role);
+      break;
+    }
+    case BTA_PAN_CLOSE_EVT: {
+      LOG_INFO(LOG_TAG, "%s: event = BTA_PAN_CLOSE_EVT handle %d", __func__,
+               p_data->close.handle);
+      btpan_conn_t* conn = btpan_find_conn_handle(p_data->close.handle);
+      btpan_close_conn(conn);
+
+      if (conn && conn->handle >= 0) {
+        int btpan_conn_local_role = bta_role_to_btpan(conn->local_role);
+        int btpan_remote_role = bta_role_to_btpan(conn->remote_role);
+        callback.connection_state_cb(BTPAN_STATE_DISCONNECTED, (bt_status_t)0,
+                                     (const bt_bdaddr_t*)conn->peer,
+                                     btpan_conn_local_role, btpan_remote_role);
+        btpan_cleanup_conn(conn);
+      } else
+        BTIF_TRACE_ERROR("pan handle not found (%d)", p_data->close.handle);
+      break;
+    }
+    default:
+      BTIF_TRACE_WARNING("Unknown pan event %d", event);
+      break;
+  }
+}
+
+static void bta_pan_callback(tBTA_PAN_EVT event, tBTA_PAN* p_data) {
+  btif_transfer_context(bta_pan_callback_transfer, event, (char*)p_data,
+                        sizeof(tBTA_PAN), NULL);
+}
+
+#define IS_EXCEPTION(e) ((e) & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL))
+static void btu_exec_tap_fd_read(void* p_param) {
+  struct pollfd ufd;
+  int fd = PTR_TO_INT(p_param);
+
+  if (fd == INVALID_FD || fd != btpan_cb.tap_fd) return;
+
+  // Don't occupy BTU context too long, avoid buffer overruns and
+  // give other profiles a chance to run by limiting the amount of memory
+  // PAN can use.
+  for (int i = 0; i < PAN_BUF_MAX && btif_is_enabled() && btpan_cb.flow; i++) {
+    BT_HDR* buffer = (BT_HDR*)osi_malloc(PAN_BUF_SIZE);
+    buffer->offset = PAN_MINIMUM_OFFSET;
+    buffer->len = PAN_BUF_SIZE - sizeof(BT_HDR) - buffer->offset;
+
+    uint8_t* packet = (uint8_t*)buffer + sizeof(BT_HDR) + buffer->offset;
+
+    // If we don't have an undelivered packet left over, pull one from the TAP
+    // driver.
+    // We save it in the congest_packet right away in case we can't deliver it
+    // in this
+    // attempt.
+    if (!btpan_cb.congest_packet_size) {
+      ssize_t ret;
+      OSI_NO_INTR(ret = read(fd, btpan_cb.congest_packet,
+                             sizeof(btpan_cb.congest_packet)));
+      switch (ret) {
+        case -1:
+          BTIF_TRACE_ERROR("%s unable to read from driver: %s", __func__,
+                           strerror(errno));
+          osi_free(buffer);
+          // add fd back to monitor thread to try it again later
+          btsock_thread_add_fd(pan_pth, fd, 0, SOCK_THREAD_FD_RD, 0);
+          return;
+        case 0:
+          BTIF_TRACE_WARNING("%s end of file reached.", __func__);
+          osi_free(buffer);
+          // add fd back to monitor thread to process the exception
+          btsock_thread_add_fd(pan_pth, fd, 0, SOCK_THREAD_FD_RD, 0);
+          return;
+        default:
+          btpan_cb.congest_packet_size = ret;
+          break;
+      }
+    }
+
+    memcpy(packet, btpan_cb.congest_packet,
+           MIN(btpan_cb.congest_packet_size, buffer->len));
+    buffer->len = MIN(btpan_cb.congest_packet_size, buffer->len);
+
+    if (buffer->len > sizeof(tETH_HDR) && should_forward((tETH_HDR*)packet)) {
+      // Extract the ethernet header from the buffer since the PAN_WriteBuf
+      // inside
+      // forward_bnep can't handle two pointers that point inside the same GKI
+      // buffer.
+      tETH_HDR hdr;
+      memcpy(&hdr, packet, sizeof(tETH_HDR));
+
+      // Skip the ethernet header.
+      buffer->len -= sizeof(tETH_HDR);
+      buffer->offset += sizeof(tETH_HDR);
+      if (forward_bnep(&hdr, buffer) != FORWARD_CONGEST)
+        btpan_cb.congest_packet_size = 0;
+    } else {
+      BTIF_TRACE_WARNING("%s dropping packet of length %d", __func__,
+                         buffer->len);
+      btpan_cb.congest_packet_size = 0;
+      osi_free(buffer);
+    }
+
+    // Bail out of the loop if reading from the TAP fd would block.
+    ufd.fd = fd;
+    ufd.events = POLLIN;
+    ufd.revents = 0;
+
+    int ret;
+    OSI_NO_INTR(ret = poll(&ufd, 1, 0));
+    if (ret <= 0 || IS_EXCEPTION(ufd.revents)) break;
+  }
+
+  if (btpan_cb.flow) {
+    // add fd back to monitor thread when the flow is on
+    btsock_thread_add_fd(pan_pth, fd, 0, SOCK_THREAD_FD_RD, 0);
+  }
+}
+
+static void btif_pan_close_all_conns() {
+  if (!stack_initialized) return;
+
+  for (int i = 0; i < MAX_PAN_CONNS; ++i) {
+    if (btpan_cb.conns[i].handle != -1) BTA_PanClose(btpan_cb.conns[i].handle);
+  }
+}
+
+static void btpan_tap_fd_signaled(int fd, int type, int flags,
+                                  uint32_t user_id) {
+  assert(btpan_cb.tap_fd == INVALID_FD || btpan_cb.tap_fd == fd);
+
+  if (btpan_cb.tap_fd != fd) {
+    BTIF_TRACE_WARNING("%s Signaled on mismatched fds exp:%d act:%d\n",
+                       __func__, btpan_cb.tap_fd, fd);
+    return;
+  }
+
+  if (flags & SOCK_THREAD_FD_EXCEPTION) {
+    btpan_cb.tap_fd = INVALID_FD;
+    btpan_tap_close(fd);
+    btif_pan_close_all_conns();
+  } else if (flags & SOCK_THREAD_FD_RD)
+    bta_dmexecutecallback(btu_exec_tap_fd_read, INT_TO_PTR(fd));
+}
diff --git a/bt/btif/src/btif_profile_queue.cc b/bt/btif/src/btif_profile_queue.cc
new file mode 100644
index 0000000..9e1d20a
--- /dev/null
+++ b/bt/btif/src/btif_profile_queue.cc
@@ -0,0 +1,175 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ *  Filename:      btif_profile_queue.c
+ *
+ *  Description:   Bluetooth remote device connection queuing implementation.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_queue"
+
+#include "btif_profile_queue.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "btif_common.h"
+#include "osi/include/allocator.h"
+#include "osi/include/list.h"
+#include "stack_manager.h"
+
+/*******************************************************************************
+ *  Local type definitions
+ ******************************************************************************/
+
+typedef enum {
+  BTIF_QUEUE_CONNECT_EVT,
+  BTIF_QUEUE_ADVANCE_EVT,
+} btif_queue_event_t;
+
+typedef struct {
+  bt_bdaddr_t bda;
+  uint16_t uuid;
+  bool busy;
+  btif_connect_cb_t connect_cb;
+} connect_node_t;
+
+/*******************************************************************************
+ *  Static variables
+ ******************************************************************************/
+
+static list_t* connect_queue;
+
+static const size_t MAX_REASONABLE_REQUESTS = 10;
+
+/*******************************************************************************
+ *  Queue helper functions
+ ******************************************************************************/
+
+static void queue_int_add(connect_node_t* p_param) {
+  if (!connect_queue) {
+    connect_queue = list_new(osi_free);
+    assert(connect_queue != NULL);
+  }
+
+  // Sanity check to make sure we're not leaking connection requests
+  assert(list_length(connect_queue) < MAX_REASONABLE_REQUESTS);
+
+  for (const list_node_t* node = list_begin(connect_queue);
+       node != list_end(connect_queue); node = list_next(node)) {
+    if (((connect_node_t*)list_node(node))->uuid == p_param->uuid) {
+      LOG_INFO(LOG_TAG, "%s dropping duplicate connect request for uuid: %04x",
+               __func__, p_param->uuid);
+      return;
+    }
+  }
+
+  connect_node_t* p_node = (connect_node_t*)osi_malloc(sizeof(connect_node_t));
+  memcpy(p_node, p_param, sizeof(connect_node_t));
+  list_append(connect_queue, p_node);
+}
+
+static void queue_int_advance() {
+  if (connect_queue && !list_is_empty(connect_queue))
+    list_remove(connect_queue, list_front(connect_queue));
+}
+
+static void queue_int_handle_evt(uint16_t event, char* p_param) {
+  switch (event) {
+    case BTIF_QUEUE_CONNECT_EVT:
+      queue_int_add((connect_node_t*)p_param);
+      break;
+
+    case BTIF_QUEUE_ADVANCE_EVT:
+      queue_int_advance();
+      break;
+  }
+
+  if (stack_manager_get_interface()->get_stack_is_running())
+    btif_queue_connect_next();
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_queue_connect
+ *
+ * Description      Add a new connection to the queue and trigger the next
+ *                  scheduled connection.
+ *
+ * Returns          BT_STATUS_SUCCESS if successful
+ *
+ ******************************************************************************/
+bt_status_t btif_queue_connect(uint16_t uuid, const bt_bdaddr_t* bda,
+                               btif_connect_cb_t connect_cb) {
+  connect_node_t node;
+  memset(&node, 0, sizeof(connect_node_t));
+  memcpy(&node.bda, bda, sizeof(bt_bdaddr_t));
+  node.uuid = uuid;
+  node.connect_cb = connect_cb;
+
+  return btif_transfer_context(queue_int_handle_evt, BTIF_QUEUE_CONNECT_EVT,
+                               (char*)&node, sizeof(connect_node_t), NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_queue_advance
+ *
+ * Description      Clear the queue's busy status and advance to the next
+ *                  scheduled connection.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btif_queue_advance() {
+  btif_transfer_context(queue_int_handle_evt, BTIF_QUEUE_ADVANCE_EVT, NULL, 0,
+                        NULL);
+}
+
+// This function dispatches the next pending connect request. It is called from
+// stack_manager when the stack comes up.
+bt_status_t btif_queue_connect_next(void) {
+  if (!connect_queue || list_is_empty(connect_queue)) return BT_STATUS_FAIL;
+
+  connect_node_t* p_head = (connect_node_t*)list_front(connect_queue);
+
+  // If the queue is currently busy, we return success anyway,
+  // since the connection has been queued...
+  if (p_head->busy) return BT_STATUS_SUCCESS;
+
+  p_head->busy = true;
+  return p_head->connect_cb(&p_head->bda, p_head->uuid);
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_queue_release
+ *
+ * Description      Free up all the queue nodes and set the queue head to NULL
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void btif_queue_release() {
+  list_free(connect_queue);
+  connect_queue = NULL;
+}
diff --git a/bt/btif/src/btif_rc.cc b/bt/btif/src/btif_rc.cc
new file mode 100644
index 0000000..1e379cf
--- /dev/null
+++ b/bt/btif/src/btif_rc.cc
@@ -0,0 +1,5954 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*****************************************************************************
+ *
+ *  Filename:      btif_rc.cc
+ *
+ *  Description:   Bluetooth AVRC implementation
+ *
+ *****************************************************************************/
+
+#define LOG_TAG "bt_btif_avrc"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <mutex>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_rc.h>
+
+#include "avrc_defs.h"
+#include "bdaddr.h"
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_av_api.h"
+#include "btif_av.h"
+#include "btif_common.h"
+#include "btif_util.h"
+#include "btu.h"
+#include "device/include/interop.h"
+#include "osi/include/list.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+#include "uinput.h"
+#define RC_INVALID_TRACK_ID (0xFFFFFFFFFFFFFFFFULL)
+
+/*****************************************************************************
+ *  Constants & Macros
+ *****************************************************************************/
+
+/* cod value for Headsets */
+#define COD_AV_HEADSETS 0x0404
+/* for AVRC 1.4 need to change this */
+#define MAX_RC_NOTIFICATIONS AVRC_EVT_VOLUME_CHANGE
+
+#define IDX_GET_PLAY_STATUS_RSP 0
+#define IDX_LIST_APP_ATTR_RSP 1
+#define IDX_LIST_APP_VALUE_RSP 2
+#define IDX_GET_CURR_APP_VAL_RSP 3
+#define IDX_SET_APP_VAL_RSP 4
+#define IDX_GET_APP_ATTR_TXT_RSP 5
+#define IDX_GET_APP_VAL_TXT_RSP 6
+#define IDX_GET_ELEMENT_ATTR_RSP 7
+#define IDX_SET_ADDR_PLAYER_RSP 8
+#define IDX_SET_BROWSED_PLAYER_RSP 9
+#define IDX_GET_FOLDER_ITEMS_RSP 10
+#define IDX_CHG_PATH_RSP 11
+#define IDX_GET_ITEM_ATTR_RSP 12
+#define IDX_PLAY_ITEM_RSP 13
+#define IDX_GET_TOTAL_NUM_OF_ITEMS_RSP 14
+#define IDX_SEARCH_RSP 15
+#define IDX_ADD_TO_NOW_PLAYING_RSP 16
+
+/* Update MAX value whenever IDX will be changed */
+#define MAX_CMD_QUEUE_LEN 17
+
+#define MAX_VOLUME 128
+#define MAX_LABEL 16
+#define MAX_TRANSACTIONS_PER_SESSION 16
+#define PLAY_STATUS_PLAYING 1
+#define BTIF_RC_NUM_CONN BT_RC_NUM_APP
+
+#define CHECK_RC_CONNECTED(p_dev)                                          \
+  do {                                                                     \
+    BTIF_TRACE_DEBUG("%s: ", __func__);                                    \
+    if ((p_dev) == NULL || (p_dev)->rc_connected == false) {               \
+      BTIF_TRACE_WARNING("%s: called when RC is not connected", __func__); \
+      return BT_STATUS_NOT_READY;                                          \
+    }                                                                      \
+  } while (0)
+
+#define CHECK_BR_CONNECTED(p_dev)                                         \
+  do {                                                                    \
+    BTIF_TRACE_DEBUG("## %s ##", __FUNCTION__);                           \
+    if ((p_dev) == NULL || (p_dev)->br_connected == false) {              \
+      BTIF_TRACE_WARNING("Function %s() called when BR is not connected", \
+                         __FUNCTION__);                                   \
+      return BT_STATUS_NOT_READY;                                         \
+    }                                                                     \
+  } while (0)
+
+/*****************************************************************************
+ *  Local type definitions
+ *****************************************************************************/
+typedef struct {
+  uint8_t bNotify;
+  uint8_t label;
+} btif_rc_reg_notifications_t;
+
+typedef struct {
+  uint8_t label;
+  uint8_t ctype;
+  bool is_rsp_pending;
+} btif_rc_cmd_ctxt_t;
+
+/* 2 second timeout to get interim response */
+#define BTIF_TIMEOUT_RC_INTERIM_RSP_MS (2 * 1000)
+#define BTIF_TIMEOUT_RC_STATUS_CMD_MS (2 * 1000)
+#define BTIF_TIMEOUT_RC_CONTROL_CMD_MS (2 * 1000)
+
+typedef enum {
+  eNOT_REGISTERED,
+  eREGISTERED,
+  eINTERIM
+} btif_rc_nfn_reg_status_t;
+
+typedef struct {
+  uint8_t event_id;
+  uint8_t label;
+  btif_rc_nfn_reg_status_t status;
+} btif_rc_supported_event_t;
+
+#define BTIF_RC_STS_TIMEOUT 0xFE
+typedef struct {
+  uint8_t label;
+  uint8_t pdu_id;
+} btif_rc_status_cmd_timer_t;
+
+typedef struct {
+  uint8_t label;
+  uint8_t pdu_id;
+} btif_rc_control_cmd_timer_t;
+
+typedef struct {
+  union {
+    btif_rc_status_cmd_timer_t rc_status_cmd;
+    btif_rc_control_cmd_timer_t rc_control_cmd;
+  };
+  BD_ADDR rc_addr;
+} btif_rc_timer_context_t;
+
+typedef struct {
+  bool query_started;
+  uint8_t num_attrs;
+  uint8_t num_ext_attrs;
+
+  uint8_t attr_index;
+  uint8_t ext_attr_index;
+  uint8_t ext_val_index;
+  btrc_player_app_attr_t attrs[AVRC_MAX_APP_ATTR_SIZE];
+  btrc_player_app_ext_attr_t ext_attrs[AVRC_MAX_APP_ATTR_SIZE];
+} btif_rc_player_app_settings_t;
+
+/* TODO : Merge btif_rc_reg_notifications_t and btif_rc_cmd_ctxt_t to a single
+ * struct */
+typedef struct {
+  bool rc_connected;
+  bool br_connected;  // Browsing channel.
+  uint8_t rc_handle;
+  tBTA_AV_FEAT rc_features;
+  btrc_connection_state_t rc_state;
+  BD_ADDR rc_addr;
+  uint16_t rc_pending_play;
+  btif_rc_cmd_ctxt_t rc_pdu_info[MAX_CMD_QUEUE_LEN];
+  btif_rc_reg_notifications_t rc_notif[MAX_RC_NOTIFICATIONS];
+  unsigned int rc_volume;
+  uint8_t rc_vol_label;
+  list_t* rc_supported_event_list;
+  btif_rc_player_app_settings_t rc_app_settings;
+  alarm_t* rc_play_status_timer;
+  bool rc_features_processed;
+  uint64_t rc_playing_uid;
+  bool rc_procedure_complete;
+} btif_rc_device_cb_t;
+
+typedef struct {
+  std::mutex lock;
+  btif_rc_device_cb_t rc_multi_cb[BTIF_RC_NUM_CONN];
+} rc_cb_t;
+
+typedef struct {
+  bool in_use;
+  uint8_t lbl;
+  uint8_t handle;
+  btif_rc_timer_context_t txn_timer_context;
+  alarm_t* txn_timer;
+} rc_transaction_t;
+
+typedef struct {
+  std::recursive_mutex lbllock;
+  rc_transaction_t transaction[MAX_TRANSACTIONS_PER_SESSION];
+} rc_device_t;
+
+typedef struct {
+  uint8_t label;
+  BD_ADDR rc_addr;
+} rc_context_t;
+
+rc_device_t device;
+
+#define MAX_UINPUT_PATHS 3
+static const char* uinput_dev_path[] = {"/dev/uinput", "/dev/input/uinput",
+                                        "/dev/misc/uinput"};
+static int uinput_fd = -1;
+
+static int uinput_driver_check();
+static int uinput_create(const char* name);
+static int init_uinput(void);
+static void close_uinput(void);
+static void sleep_ms(period_ms_t timeout_ms);
+
+static const struct {
+  const char* name;
+  uint8_t avrcp;
+  uint16_t mapped_id;
+  uint8_t release_quirk;
+} key_map[] = {{"PLAY", AVRC_ID_PLAY, KEY_PLAYCD, 1},
+               {"STOP", AVRC_ID_STOP, KEY_STOPCD, 0},
+               {"PAUSE", AVRC_ID_PAUSE, KEY_PAUSECD, 1},
+               {"FORWARD", AVRC_ID_FORWARD, KEY_NEXTSONG, 0},
+               {"BACKWARD", AVRC_ID_BACKWARD, KEY_PREVIOUSSONG, 0},
+               {"REWIND", AVRC_ID_REWIND, KEY_REWIND, 0},
+               {"FAST FORWARD", AVRC_ID_FAST_FOR, KEY_FAST_FORWARD, 0},
+               {NULL, 0, 0, 0}};
+
+/* Response status code - Unknown Error - this is changed to "reserved" */
+#define BTIF_STS_GEN_ERROR 0x06
+
+/* Utility table to map hal status codes to bta status codes for the response
+ * status */
+static const uint8_t status_code_map[] = {
+    /* BTA_Status codes        HAL_Status codes */
+    AVRC_STS_BAD_CMD,         /* BTRC_STS_BAD_CMD */
+    AVRC_STS_BAD_PARAM,       /* BTRC_STS_BAD_PARAM */
+    AVRC_STS_NOT_FOUND,       /* BTRC_STS_NOT_FOUND */
+    AVRC_STS_INTERNAL_ERR,    /* BTRC_STS_INTERNAL_ERR */
+    AVRC_STS_NO_ERROR,        /* BTRC_STS_NO_ERROR */
+    AVRC_STS_UID_CHANGED,     /* BTRC_STS_UID_CHANGED */
+    BTIF_STS_GEN_ERROR,       /* BTRC_STS_RESERVED */
+    AVRC_STS_BAD_DIR,         /* BTRC_STS_INV_DIRN */
+    AVRC_STS_NOT_DIR,         /* BTRC_STS_INV_DIRECTORY */
+    AVRC_STS_NOT_EXIST,       /* BTRC_STS_INV_ITEM */
+    AVRC_STS_BAD_SCOPE,       /* BTRC_STS_INV_SCOPE */
+    AVRC_STS_BAD_RANGE,       /* BTRC_STS_INV_RANGE */
+    AVRC_STS_UID_IS_DIR,      /* BTRC_STS_DIRECTORY */
+    AVRC_STS_IN_USE,          /* BTRC_STS_MEDIA_IN_USE */
+    AVRC_STS_NOW_LIST_FULL,   /* BTRC_STS_PLAY_LIST_FULL */
+    AVRC_STS_SEARCH_NOT_SUP,  /* BTRC_STS_SRCH_NOT_SPRTD */
+    AVRC_STS_SEARCH_BUSY,     /* BTRC_STS_SRCH_IN_PROG */
+    AVRC_STS_BAD_PLAYER_ID,   /* BTRC_STS_INV_PLAYER */
+    AVRC_STS_PLAYER_N_BR,     /* BTRC_STS_PLAY_NOT_BROW */
+    AVRC_STS_PLAYER_N_ADDR,   /* BTRC_STS_PLAY_NOT_ADDR */
+    AVRC_STS_BAD_SEARCH_RES,  /* BTRC_STS_INV_RESULTS */
+    AVRC_STS_NO_AVAL_PLAYER,  /* BTRC_STS_NO_AVBL_PLAY */
+    AVRC_STS_ADDR_PLAYER_CHG, /* BTRC_STS_ADDR_PLAY_CHGD */
+};
+
+static void send_reject_response(uint8_t rc_handle, uint8_t label, uint8_t pdu,
+                                 uint8_t status, uint8_t opcode);
+static uint8_t opcode_from_pdu(uint8_t pdu);
+static void send_metamsg_rsp(btif_rc_device_cb_t* p_dev, int index,
+                             uint8_t label, tBTA_AV_CODE code,
+                             tAVRC_RESPONSE* pmetamsg_resp);
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+static void register_volumechange(uint8_t label, btif_rc_device_cb_t* p_dev);
+#endif
+static void lbl_init();
+static void init_all_transactions();
+static bt_status_t get_transaction(rc_transaction_t** ptransaction);
+static void release_transaction(uint8_t label);
+static rc_transaction_t* get_transaction_by_lbl(uint8_t label);
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg,
+                                  btif_rc_device_cb_t* p_dev);
+#endif
+
+#if (AVRC_CTRL_INCLUDED == TRUE)
+static void handle_avk_rc_metamsg_cmd(tBTA_AV_META_MSG* pmeta_msg);
+static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg);
+static void btif_rc_ctrl_upstreams_rsp_cmd(uint8_t event,
+                                           tAVRC_COMMAND* pavrc_cmd,
+                                           uint8_t label,
+                                           btif_rc_device_cb_t* p_dev);
+static void rc_ctrl_procedure_complete(btif_rc_device_cb_t* p_dev);
+static void rc_stop_play_status_timer(btif_rc_device_cb_t* p_dev);
+static void register_for_event_notification(btif_rc_supported_event_t* p_event,
+                                            btif_rc_device_cb_t* p_dev);
+static void handle_get_capability_response(tBTA_AV_META_MSG* pmeta_msg,
+                                           tAVRC_GET_CAPS_RSP* p_rsp);
+static void handle_app_attr_response(tBTA_AV_META_MSG* pmeta_msg,
+                                     tAVRC_LIST_APP_ATTR_RSP* p_rsp);
+static void handle_app_val_response(tBTA_AV_META_MSG* pmeta_msg,
+                                    tAVRC_LIST_APP_VALUES_RSP* p_rsp);
+static void handle_app_cur_val_response(tBTA_AV_META_MSG* pmeta_msg,
+                                        tAVRC_GET_CUR_APP_VALUE_RSP* p_rsp);
+static void handle_app_attr_txt_response(tBTA_AV_META_MSG* pmeta_msg,
+                                         tAVRC_GET_APP_ATTR_TXT_RSP* p_rsp);
+static void handle_app_attr_val_txt_response(tBTA_AV_META_MSG* pmeta_msg,
+                                             tAVRC_GET_APP_ATTR_TXT_RSP* p_rsp);
+static void handle_get_playstatus_response(tBTA_AV_META_MSG* pmeta_msg,
+                                           tAVRC_GET_PLAY_STATUS_RSP* p_rsp);
+static void handle_set_addressed_player_response(tBTA_AV_META_MSG *pmeta_msg, tAVRC_RSP *p_rsp);
+static void handle_get_elem_attr_response(tBTA_AV_META_MSG* pmeta_msg,
+                                          tAVRC_GET_ELEM_ATTRS_RSP* p_rsp);
+static void handle_set_app_attr_val_response(tBTA_AV_META_MSG* pmeta_msg,
+                                             tAVRC_RSP* p_rsp);
+static bt_status_t get_play_status_cmd(btif_rc_device_cb_t* p_dev);
+static bt_status_t get_player_app_setting_attr_text_cmd(
+    uint8_t* attrs, uint8_t num_attrs, btif_rc_device_cb_t* p_dev);
+static bt_status_t get_player_app_setting_value_text_cmd(
+    uint8_t* vals, uint8_t num_vals, btif_rc_device_cb_t* p_dev);
+static bt_status_t register_notification_cmd(uint8_t label, uint8_t event_id,
+                                             uint32_t event_value,
+                                             btif_rc_device_cb_t* p_dev);
+static bt_status_t get_element_attribute_cmd(uint8_t num_attribute,
+                                             uint32_t* p_attr_ids,
+                                             btif_rc_device_cb_t* p_dev);
+static bt_status_t getcapabilities_cmd(uint8_t cap_id,
+                                       btif_rc_device_cb_t* p_dev);
+static bt_status_t list_player_app_setting_attrib_cmd(
+    btif_rc_device_cb_t* p_dev);
+static bt_status_t list_player_app_setting_value_cmd(
+    uint8_t attrib_id, btif_rc_device_cb_t* p_dev);
+static bt_status_t get_player_app_setting_cmd(uint8_t num_attrib,
+                                              uint8_t* attrib_ids,
+                                              btif_rc_device_cb_t* p_dev);
+void get_folder_item_type_media(const tAVRC_ITEM* avrc_item,
+                                btrc_folder_items_t* btrc_item);
+void get_folder_item_type_folder(const tAVRC_ITEM* avrc_item,
+                                 btrc_folder_items_t* btrc_item);
+void get_folder_item_type_player(const tAVRC_ITEM* avrc_item,
+                                 btrc_folder_items_t* btrc_item);
+static bt_status_t get_folder_items_cmd(bt_bdaddr_t* bd_addr, uint8_t scope,
+                                        uint8_t start_item, uint8_t num_items);
+#endif
+
+static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND* p_param,
+                                  uint8_t ctype, uint8_t label,
+                                  btif_rc_device_cb_t* p_dev);
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+static void btif_rc_upstreams_rsp_evt(uint16_t event,
+                                      tAVRC_RESPONSE* pavrc_resp, uint8_t ctype,
+                                      uint8_t label,
+                                      btif_rc_device_cb_t* p_dev);
+#endif
+static void rc_start_play_status_timer(btif_rc_device_cb_t* p_dev);
+static bool absolute_volume_disabled(void);
+
+/*****************************************************************************
+ *  Static variables
+ *****************************************************************************/
+static rc_cb_t btif_rc_cb;
+static btrc_callbacks_t* bt_rc_callbacks = NULL;
+static btrc_ctrl_callbacks_t* bt_rc_ctrl_callbacks = NULL;
+
+/*****************************************************************************
+ *  Static functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ *  Externs
+ *****************************************************************************/
+extern bool btif_hf_call_terminated_recently();
+extern bool check_cod(const bt_bdaddr_t* remote_bdaddr, uint32_t cod);
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/*****************************************************************************
+ *  Functions
+ *****************************************************************************/
+static btif_rc_device_cb_t* alloc_device() {
+  for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+    if (btif_rc_cb.rc_multi_cb[idx].rc_state ==
+        BTRC_CONNECTION_STATE_DISCONNECTED) {
+      return (&btif_rc_cb.rc_multi_cb[idx]);
+    }
+  }
+  return NULL;
+}
+
+static btif_rc_device_cb_t* get_connected_device(int index) {
+  BTIF_TRACE_DEBUG("%s: index: %d", __func__, index);
+  if (index > BTIF_RC_NUM_CONN) {
+    BTIF_TRACE_ERROR("%s: can't support more than %d connections", __func__,
+                     BTIF_RC_NUM_CONN);
+    return NULL;
+  }
+  if (btif_rc_cb.rc_multi_cb[index].rc_state !=
+      BTRC_CONNECTION_STATE_CONNECTED) {
+    BTIF_TRACE_ERROR("%s: returning NULL", __func__);
+    return NULL;
+  }
+  return (&btif_rc_cb.rc_multi_cb[index]);
+}
+
+static int get_num_connected_devices() {
+  int connected_devices = 0;
+  for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+    if (btif_rc_cb.rc_multi_cb[idx].rc_state ==
+        BTRC_CONNECTION_STATE_CONNECTED) {
+      connected_devices++;
+    }
+  }
+  BTIF_TRACE_DEBUG("%s: returning connected_devices: %d", __func__,
+                   connected_devices);
+  return connected_devices;
+}
+btif_rc_device_cb_t* btif_rc_get_device_by_bda(bt_bdaddr_t* bd_addr) {
+  BTIF_TRACE_DEBUG("%s: bd_addr: %02x-%02x-%02x-%02x-%02x-%02x", __func__,
+                   bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4],
+                   bd_addr[5]);
+
+  for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+    if ((btif_rc_cb.rc_multi_cb[idx].rc_state !=
+         BTRC_CONNECTION_STATE_DISCONNECTED) &&
+        (bdcmp(btif_rc_cb.rc_multi_cb[idx].rc_addr, bd_addr->address) == 0)) {
+      return (&btif_rc_cb.rc_multi_cb[idx]);
+    }
+  }
+  BTIF_TRACE_ERROR("%s: device not found, returning NULL!", __func__);
+  return NULL;
+}
+
+btif_rc_device_cb_t* btif_rc_get_device_by_handle(uint8_t handle) {
+  BTIF_TRACE_DEBUG("%s: handle: 0x%x", __func__, handle);
+  for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+    if ((btif_rc_cb.rc_multi_cb[idx].rc_state !=
+         BTRC_CONNECTION_STATE_DISCONNECTED) &&
+        (btif_rc_cb.rc_multi_cb[idx].rc_handle == handle)) {
+      BTIF_TRACE_DEBUG("%s: btif_rc_cb.rc_multi_cb[idx].rc_handle: 0x%x",
+                       __func__, btif_rc_cb.rc_multi_cb[idx].rc_handle);
+      return (&btif_rc_cb.rc_multi_cb[idx]);
+    }
+  }
+  BTIF_TRACE_ERROR("%s: returning NULL", __func__);
+  return NULL;
+}
+
+void fill_pdu_queue(int index, uint8_t ctype, uint8_t label, bool pending,
+                    btif_rc_device_cb_t* p_dev) {
+  p_dev->rc_pdu_info[index].ctype = ctype;
+  p_dev->rc_pdu_info[index].label = label;
+  p_dev->rc_pdu_info[index].is_rsp_pending = pending;
+}
+
+void fill_avrc_attr_entry(tAVRC_ATTR_ENTRY* attr_vals, int num_attrs,
+                          btrc_element_attr_val_t* p_attrs) {
+  for (int attr_cnt = 0; attr_cnt < num_attrs; attr_cnt++) {
+    attr_vals[attr_cnt].attr_id = p_attrs[attr_cnt].attr_id;
+    attr_vals[attr_cnt].name.charset_id = AVRC_CHARSET_ID_UTF8;
+    attr_vals[attr_cnt].name.str_len =
+        (uint16_t)strlen((char*)p_attrs[attr_cnt].text);
+    attr_vals[attr_cnt].name.p_str = p_attrs[attr_cnt].text;
+    BTIF_TRACE_DEBUG(
+        "%s: attr_id: 0x%x, charset_id: 0x%x, str_len: %d, str: %s", __func__,
+        (unsigned int)attr_vals[attr_cnt].attr_id,
+        attr_vals[attr_cnt].name.charset_id, attr_vals[attr_cnt].name.str_len,
+        attr_vals[attr_cnt].name.p_str);
+  }
+}
+
+/*****************************************************************************
+ *   Local uinput helper functions
+ *****************************************************************************/
+/************** uinput related functions **************/
+int uinput_driver_check() {
+  uint32_t i;
+  for (i = 0; i < MAX_UINPUT_PATHS; i++) {
+    if (access(uinput_dev_path[i], O_RDWR) == 0) {
+      return 0;
+    }
+  }
+  BTIF_TRACE_ERROR("%s: ERROR: uinput device is not in the system", __func__);
+  return -1;
+}
+
+int uinput_create(const char* name) {
+  struct uinput_dev dev;
+  int fd, x = 0;
+
+  for (x = 0; x < MAX_UINPUT_PATHS; x++) {
+    fd = open(uinput_dev_path[x], O_RDWR);
+    if (fd < 0) continue;
+    break;
+  }
+  if (x == MAX_UINPUT_PATHS) {
+    BTIF_TRACE_ERROR("%s: ERROR: uinput device open failed", __func__);
+    return -1;
+  }
+  memset(&dev, 0, sizeof(dev));
+  if (name) strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE - 1);
+
+  dev.id.bustype = BUS_BLUETOOTH;
+  dev.id.vendor = 0x0000;
+  dev.id.product = 0x0000;
+  dev.id.version = 0x0000;
+
+  ssize_t ret;
+  OSI_NO_INTR(ret = write(fd, &dev, sizeof(dev)));
+  if (ret < 0) {
+    BTIF_TRACE_ERROR("%s: Unable to write device information", __func__);
+    close(fd);
+    return -1;
+  }
+
+  ioctl(fd, UI_SET_EVBIT, EV_KEY);
+  ioctl(fd, UI_SET_EVBIT, EV_REL);
+  ioctl(fd, UI_SET_EVBIT, EV_SYN);
+
+  for (x = 0; key_map[x].name != NULL; x++)
+    ioctl(fd, UI_SET_KEYBIT, key_map[x].mapped_id);
+
+  if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) {
+    BTIF_TRACE_ERROR("%s: Unable to create uinput device", __func__);
+    close(fd);
+    return -1;
+  }
+  return fd;
+}
+
+int init_uinput(void) {
+  const char* name = "AVRCP";
+
+  BTIF_TRACE_DEBUG("%s: ", __func__);
+  uinput_fd = uinput_create(name);
+  if (uinput_fd < 0) {
+    BTIF_TRACE_ERROR("%s: AVRCP: Failed to initialize uinput for %s (%d)",
+                     __func__, name, uinput_fd);
+  } else {
+    BTIF_TRACE_DEBUG("%s: AVRCP: Initialized uinput for %s (fd: %d)", __func__,
+                     name, uinput_fd);
+  }
+  return uinput_fd;
+}
+
+void close_uinput(void) {
+  BTIF_TRACE_DEBUG("%s: ", __func__);
+  if (uinput_fd > 0) {
+    ioctl(uinput_fd, UI_DEV_DESTROY);
+
+    close(uinput_fd);
+    uinput_fd = -1;
+  }
+}
+
+#if (AVRC_CTRL_INCLUDED == TRUE)
+void rc_cleanup_sent_cmd(void* p_data) { BTIF_TRACE_DEBUG("%s: ", __func__); }
+
+void handle_rc_ctrl_features(btif_rc_device_cb_t* p_dev) {
+  if (!(p_dev->rc_features & BTA_AV_FEAT_RCTG) &&
+      (!(p_dev->rc_features & BTA_AV_FEAT_RCCT) ||
+       !(p_dev->rc_features & BTA_AV_FEAT_ADV_CTRL))) {
+    return;
+  }
+
+  bt_bdaddr_t rc_addr;
+  int rc_features = 0;
+  bdcpy(rc_addr.address, p_dev->rc_addr);
+
+  if ((p_dev->rc_features & BTA_AV_FEAT_ADV_CTRL) &&
+      (p_dev->rc_features & BTA_AV_FEAT_RCCT)) {
+    rc_features |= BTRC_FEAT_ABSOLUTE_VOLUME;
+  }
+
+  if ((p_dev->rc_features & BTA_AV_FEAT_METADATA) &&
+      (p_dev->rc_features & BTA_AV_FEAT_VENDOR) &&
+      (p_dev->rc_features_processed != true)) {
+    rc_features |= BTRC_FEAT_METADATA;
+
+    /* Mark rc features processed to avoid repeating
+     * the AVRCP procedure every time on receiving this
+     * update.
+     */
+    p_dev->rc_features_processed = true;
+    if (btif_av_is_sink_enabled()) {
+      getcapabilities_cmd(AVRC_CAP_COMPANY_ID, p_dev);
+    }
+  }
+
+  /* Add browsing feature capability */
+  if (p_dev->rc_features & BTA_AV_FEAT_BROWSE) {
+    rc_features |= BTRC_FEAT_BROWSE;
+  }
+
+  BTIF_TRACE_DEBUG("%s: Update rc features to CTRL: %d", __func__, rc_features);
+  HAL_CBACK(bt_rc_ctrl_callbacks, getrcfeatures_cb, &rc_addr, rc_features);
+}
+#endif
+
+void handle_rc_features(btif_rc_device_cb_t* p_dev) {
+  bt_bdaddr_t rc_addr;
+  bdcpy(rc_addr.address, p_dev->rc_addr);
+  bdstr_t addr1, addr2;
+
+  if (bt_rc_callbacks == NULL) {
+    BTIF_TRACE_ERROR("%s: bt_rc_callbacks NULL, disabling TG role for %s",
+                     __func__, bdaddr_to_string(&rc_addr, addr2, sizeof(addr2)));
+    p_dev->rc_features &= ~BTA_AV_FEAT_ADV_CTRL;
+    p_dev->rc_features &= ~BTA_AV_FEAT_BROWSE;
+    p_dev->rc_features &= ~BTA_AV_FEAT_METADATA;
+    return;
+  }
+
+  btrc_remote_features_t rc_features = BTRC_FEAT_NONE;
+  bt_bdaddr_t avdtp_addr  = btif_av_get_addr();
+
+  BTIF_TRACE_DEBUG("%s: AVDTP Address: %s AVCTP address: %s", __func__,
+                   bdaddr_to_string(&avdtp_addr, addr1, sizeof(addr1)),
+                   bdaddr_to_string(&rc_addr, addr2, sizeof(addr2)));
+
+  if (interop_match_addr(INTEROP_DISABLE_ABSOLUTE_VOLUME, &rc_addr) ||
+      absolute_volume_disabled() ||
+      bdcmp(avdtp_addr.address, rc_addr.address)) {
+    p_dev->rc_features &= ~BTA_AV_FEAT_ADV_CTRL;
+  }
+
+  if (p_dev->rc_features & BTA_AV_FEAT_BROWSE) {
+    rc_features = (btrc_remote_features_t)(rc_features | BTRC_FEAT_BROWSE);
+  }
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+  if ((p_dev->rc_features & BTA_AV_FEAT_ADV_CTRL) &&
+      (p_dev->rc_features & BTA_AV_FEAT_RCTG)) {
+    rc_features =
+        (btrc_remote_features_t)(rc_features | BTRC_FEAT_ABSOLUTE_VOLUME);
+  }
+#endif
+
+  if (p_dev->rc_features & BTA_AV_FEAT_METADATA) {
+    rc_features = (btrc_remote_features_t)(rc_features | BTRC_FEAT_METADATA);
+  }
+
+  BTIF_TRACE_DEBUG("%s: rc_features: 0x%x", __func__, rc_features);
+  HAL_CBACK(bt_rc_callbacks, remote_features_cb, &rc_addr, rc_features);
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+  BTIF_TRACE_DEBUG(
+      "%s: Checking for feature flags in btif_rc_handler with label: %d",
+      __func__, p_dev->rc_vol_label);
+  // Register for volume change on connect
+  if (p_dev->rc_features & BTA_AV_FEAT_ADV_CTRL &&
+      p_dev->rc_features & BTA_AV_FEAT_RCTG) {
+    rc_transaction_t* p_transaction = NULL;
+    bt_status_t status = BT_STATUS_NOT_READY;
+    if (MAX_LABEL == p_dev->rc_vol_label) {
+      status = get_transaction(&p_transaction);
+    } else {
+      p_transaction = get_transaction_by_lbl(p_dev->rc_vol_label);
+      if (NULL != p_transaction) {
+        BTIF_TRACE_DEBUG(
+            "%s: register_volumechange already in progress for label: %d",
+            __func__, p_dev->rc_vol_label);
+        return;
+      }
+      status = get_transaction(&p_transaction);
+    }
+    if (BT_STATUS_SUCCESS == status && NULL != p_transaction) {
+      p_dev->rc_vol_label = p_transaction->lbl;
+      register_volumechange(p_dev->rc_vol_label, p_dev);
+    }
+  }
+#endif
+}
+
+/***************************************************************************
+ *  Function       handle_rc_connect
+ *
+ *  - Argument:    tBTA_AV_RC_OPEN  browse RC open data structure
+ *
+ *  - Description: browse RC connection event handler
+ *
+ ***************************************************************************/
+void handle_rc_browse_connect(tBTA_AV_RC_OPEN* p_rc_open) {
+  BTIF_TRACE_DEBUG("%s rc_handle %d status %d", __func__, p_rc_open->rc_handle,
+                   p_rc_open->status);
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  btif_rc_device_cb_t* p_dev =
+      btif_rc_get_device_by_handle(p_rc_open->rc_handle);
+
+  if (!p_dev) {
+    BTIF_TRACE_ERROR("%s p_dev is null", __func__);
+    return;
+  }
+
+  /* check that we are already connected to this address since being connected
+   * to a browse when not connected to the control channel over AVRCP is
+   * probably not preferred anyways. */
+  if (p_rc_open->status == BTA_AV_SUCCESS) {
+    bt_bdaddr_t rc_addr;
+    bdcpy(rc_addr.address, p_dev->rc_addr);
+    p_dev->br_connected = true;
+    HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, true, true, &rc_addr);
+  }
+#endif
+}
+
+/***************************************************************************
+ *  Function       handle_rc_connect
+ *
+ *  - Argument:    tBTA_AV_RC_OPEN  RC open data structure
+ *
+ *  - Description: RC connection event handler
+ *
+ ***************************************************************************/
+void handle_rc_connect(tBTA_AV_RC_OPEN* p_rc_open) {
+  BTIF_TRACE_DEBUG("%s: rc_handle: %d", __func__, p_rc_open->rc_handle);
+  bt_status_t result = BT_STATUS_SUCCESS;
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  bt_bdaddr_t rc_addr;
+#endif
+
+  btif_rc_device_cb_t* p_dev = alloc_device();
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR("%s: p_dev is NULL", __func__);
+    return;
+  }
+
+  if (!(p_rc_open->status == BTA_AV_SUCCESS)) {
+    BTIF_TRACE_ERROR("%s: Connect failed with error code: %d", __func__,
+                     p_rc_open->status);
+    p_dev->rc_connected = false;
+  }
+
+  // check if already some RC is connected
+  if (p_dev->rc_connected) {
+    BTIF_TRACE_ERROR(
+        "%s: Got RC OPEN in connected state, Connected RC: %d \
+            and Current RC: %d",
+        __func__, p_dev->rc_handle, p_rc_open->rc_handle);
+    if ((p_dev->rc_handle != p_rc_open->rc_handle) &&
+        (bdcmp(p_dev->rc_addr, p_rc_open->peer_addr))) {
+      BTIF_TRACE_DEBUG("%s: Got RC connected for some other handle", __func__);
+      BTA_AvCloseRc(p_rc_open->rc_handle);
+      return;
+    }
+  }
+  memcpy(p_dev->rc_addr, p_rc_open->peer_addr, sizeof(BD_ADDR));
+  p_dev->rc_features = p_rc_open->peer_features;
+  BTIF_TRACE_DEBUG("%s: handle_rc_connect in features: 0x%x out features 0x%x",
+                   __func__, p_rc_open->peer_features, p_dev->rc_features);
+  p_dev->rc_vol_label = MAX_LABEL;
+  p_dev->rc_volume = MAX_VOLUME;
+
+  p_dev->rc_connected = true;
+  p_dev->rc_handle = p_rc_open->rc_handle;
+  p_dev->rc_state = BTRC_CONNECTION_STATE_CONNECTED;
+  /* on locally initiated connection we will get remote features as part of
+   * connect */
+  if (p_dev->rc_features != 0 && bt_rc_callbacks != NULL) {
+    handle_rc_features(p_dev);
+  }
+
+  if (bt_rc_callbacks) {
+    result = (bt_status_t)uinput_driver_check();
+    if (result == BT_STATUS_SUCCESS) {
+      init_uinput();
+    }
+  } else {
+    BTIF_TRACE_WARNING("%s: Avrcp TG role not enabled, not initializing UInput",
+                       __func__);
+  }
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  p_dev->rc_playing_uid = RC_INVALID_TRACK_ID;
+  bdcpy(rc_addr.address, p_dev->rc_addr);
+  if (bt_rc_ctrl_callbacks != NULL) {
+    HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, true, false, &rc_addr);
+  }
+  /* report connection state if remote device is AVRCP target */
+  handle_rc_ctrl_features(p_dev);
+#endif
+}
+
+/***************************************************************************
+ *  Function       handle_rc_disconnect
+ *
+ *  - Argument:    tBTA_AV_RC_CLOSE     RC close data structure
+ *
+ *  - Description: RC disconnection event handler
+ *
+ ***************************************************************************/
+void handle_rc_disconnect(tBTA_AV_RC_CLOSE* p_rc_close) {
+  btif_rc_device_cb_t* p_dev = NULL;
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  bt_bdaddr_t rc_addr;
+  tBTA_AV_FEAT features = 0;
+#endif
+  BTIF_TRACE_DEBUG("%s: rc_handle: %d", __func__, p_rc_close->rc_handle);
+
+  p_dev = btif_rc_get_device_by_handle(p_rc_close->rc_handle);
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR("%s: Got disconnect from invalid rc handle", __func__);
+    return;
+  }
+
+  if ((p_rc_close->rc_handle != p_dev->rc_handle) &&
+      (bdcmp(p_dev->rc_addr, p_rc_close->peer_addr))) {
+    BTIF_TRACE_ERROR("Got disconnect of unknown device");
+    return;
+  }
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  bdcpy(rc_addr.address, p_dev->rc_addr);
+  features = p_dev->rc_features;
+  /* Clean up AVRCP procedure flags */
+  memset(&p_dev->rc_app_settings, 0, sizeof(btif_rc_player_app_settings_t));
+  p_dev->rc_features_processed = false;
+  p_dev->rc_procedure_complete = false;
+  rc_stop_play_status_timer(p_dev);
+  /* Check and clear the notification event list */
+  if (p_dev->rc_supported_event_list != NULL) {
+    list_clear(p_dev->rc_supported_event_list);
+    p_dev->rc_supported_event_list = NULL;
+  }
+#endif
+
+  /* check if there is another device connected */
+  if (p_dev->rc_state == BTRC_CONNECTION_STATE_CONNECTED) {
+    p_dev->rc_handle = 0;
+    p_dev->rc_connected = false;
+    p_dev->rc_state = BTRC_CONNECTION_STATE_DISCONNECTED;
+
+    memset(p_dev->rc_notif, 0, sizeof(p_dev->rc_notif));
+
+    p_dev->rc_features = 0;
+    p_dev->rc_vol_label = MAX_LABEL;
+    p_dev->rc_volume = MAX_VOLUME;
+
+    memset(p_dev->rc_addr, 0, sizeof(BD_ADDR));
+  }
+  if (get_num_connected_devices() == 0) {
+    BTIF_TRACE_DEBUG("%s: Closing all handles", __func__);
+    init_all_transactions();
+  }
+
+  memset(p_dev->rc_addr, 0, sizeof(BD_ADDR));
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  /* report connection state if device is AVRCP target */
+  if (bt_rc_ctrl_callbacks != NULL) {
+    HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, false, false,
+              &rc_addr);
+  }
+#endif
+}
+
+/***************************************************************************
+ *  Function       handle_rc_passthrough_cmd
+ *
+ *  - Argument:    tBTA_AV_RC rc_id   remote control command ID
+ *                 tBTA_AV_STATE key_state status of key press
+ *
+ *  - Description: Remote control command handler
+ *
+ ***************************************************************************/
+void handle_rc_passthrough_cmd(tBTA_AV_REMOTE_CMD* p_remote_cmd) {
+  btif_rc_device_cb_t* p_dev =
+      btif_rc_get_device_by_handle(p_remote_cmd->rc_handle);
+
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR("%s: Got passthrough command from invalid rc handle",
+                     __func__);
+    return;
+  }
+
+  if (p_remote_cmd == NULL) {
+    BTIF_TRACE_ERROR("%s: No remote command!", __func__);
+    return;
+  }
+
+  bt_bdaddr_t rc_addr;
+  bdcpy(rc_addr.address, p_dev->rc_addr);
+
+  BTIF_TRACE_DEBUG("%s: p_remote_cmd->rc_id: %d", __func__,
+                   p_remote_cmd->rc_id);
+
+  /* If AVRC is open and peer sends PLAY but there is no AVDT, then we queue-up
+   * this PLAY */
+  if ((p_remote_cmd->rc_id == BTA_AV_RC_PLAY) && (!btif_av_is_connected())) {
+    if (p_remote_cmd->key_state == AVRC_STATE_PRESS) {
+      APPL_TRACE_WARNING("%s: AVDT not open, queuing the PLAY command",
+                           __func__);
+      p_dev->rc_pending_play = true;
+    }
+    return;
+  }
+
+  /* If we previously queued a play and we get a PAUSE, clear it. */
+  if ((p_remote_cmd->rc_id == BTA_AV_RC_PAUSE) && (p_dev->rc_pending_play)) {
+    APPL_TRACE_WARNING("%s: Clear the pending PLAY on PAUSE received",
+                       __func__);
+    p_dev->rc_pending_play = false;
+    return;
+  }
+
+  if ((p_remote_cmd->rc_id == BTA_AV_RC_STOP) &&
+      (!btif_av_stream_started_ready())) {
+    APPL_TRACE_WARNING("%s: Stream suspended, ignore STOP cmd", __func__);
+    return;
+  }
+
+  int pressed = (p_remote_cmd->key_state == AVRC_STATE_PRESS) ? 1 : 0;
+
+  /* pass all commands up */
+  BTIF_TRACE_DEBUG("%s: rc_features: %d, cmd->rc_id: %d, pressed: %d", __func__,
+                   p_dev->rc_features, p_remote_cmd->rc_id, pressed);
+  HAL_CBACK(bt_rc_callbacks, passthrough_cmd_cb, p_remote_cmd->rc_id, pressed,
+            &rc_addr);
+}
+
+/***************************************************************************
+ *  Function       handle_rc_passthrough_rsp
+ *
+ *  - Argument:    tBTA_AV_REMOTE_RSP passthrough command response
+ *
+ *  - Description: Remote control passthrough response handler
+ *
+ ***************************************************************************/
+void handle_rc_passthrough_rsp(tBTA_AV_REMOTE_RSP* p_remote_rsp) {
+  btif_rc_device_cb_t* p_dev = NULL;
+  bt_bdaddr_t rc_addr;
+
+  p_dev = btif_rc_get_device_by_handle(p_remote_rsp->rc_handle);
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR("%s: passthrough response for Invalid rc handle",
+                     __func__);
+    return;
+  }
+
+  bdcpy(rc_addr.address, p_dev->rc_addr);
+
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  if (!(p_dev->rc_features & BTA_AV_FEAT_RCTG)) {
+    BTIF_TRACE_ERROR("%s: DUT does not support AVRCP controller role",
+                     __func__);
+    return;
+  }
+
+  const char *status = (p_remote_rsp->key_state == 1) ? "released" : "pressed";
+  BTIF_TRACE_DEBUG("%s: rc_id: %d state: %s", __func__, p_remote_rsp->rc_id,
+                   status);
+
+  release_transaction(p_remote_rsp->label);
+  if (bt_rc_ctrl_callbacks != NULL) {
+    HAL_CBACK(bt_rc_ctrl_callbacks, passthrough_rsp_cb, &rc_addr,
+              p_remote_rsp->rc_id, p_remote_rsp->key_state);
+  }
+#else
+  BTIF_TRACE_ERROR("%s: AVRCP controller role is not enabled", __func__);
+#endif
+}
+
+/***************************************************************************
+ *  Function       handle_rc_vendorunique_rsp
+ *
+ *  - Argument:    tBTA_AV_REMOTE_RSP  command response
+ *
+ *  - Description: Remote control vendor unique response handler
+ *
+ ***************************************************************************/
+void handle_rc_vendorunique_rsp(tBTA_AV_REMOTE_RSP* p_remote_rsp) {
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  btif_rc_device_cb_t* p_dev = NULL;
+  const char* status;
+  uint8_t vendor_id = 0;
+
+  p_dev = btif_rc_get_device_by_handle(p_remote_rsp->rc_handle);
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR("%s: Got vendorunique rsp from invalid rc handle",
+                     __func__);
+    return;
+  }
+
+  if (p_dev->rc_features & BTA_AV_FEAT_RCTG) {
+    int key_state;
+    if (p_remote_rsp->key_state == AVRC_STATE_RELEASE) {
+      status = "released";
+      key_state = 1;
+    } else {
+      status = "pressed";
+      key_state = 0;
+    }
+
+    if (p_remote_rsp->len > 0) {
+      if (p_remote_rsp->len >= AVRC_PASS_THRU_GROUP_LEN)
+        vendor_id = p_remote_rsp->p_data[AVRC_PASS_THRU_GROUP_LEN - 1];
+      osi_free_and_reset((void**)&p_remote_rsp->p_data);
+    }
+    BTIF_TRACE_DEBUG("%s: vendor_id: %d status: %s", __func__, vendor_id,
+                     status);
+
+    release_transaction(p_remote_rsp->label);
+    HAL_CBACK(bt_rc_ctrl_callbacks, groupnavigation_rsp_cb, vendor_id,
+              key_state);
+  } else {
+    BTIF_TRACE_ERROR("%s: Remote does not support AVRCP TG role", __func__);
+  }
+#else
+  BTIF_TRACE_ERROR("%s: AVRCP controller role is not enabled", __func__);
+#endif
+}
+
+void handle_uid_changed_notification(btif_rc_device_cb_t* p_dev, uint8_t label,
+                                     tAVRC_COMMAND* pavrc_command) {
+  tAVRC_RESPONSE avrc_rsp = {0};
+  avrc_rsp.rsp.pdu = pavrc_command->pdu;
+  avrc_rsp.rsp.status = AVRC_STS_NO_ERROR;
+  avrc_rsp.rsp.opcode = pavrc_command->cmd.opcode;
+
+  avrc_rsp.reg_notif.event_id = pavrc_command->reg_notif.event_id;
+  avrc_rsp.reg_notif.param.uid_counter = 0;
+
+  send_metamsg_rsp(p_dev, -1, label, AVRC_RSP_INTERIM, &avrc_rsp);
+  send_metamsg_rsp(p_dev, -1, label, AVRC_RSP_CHANGED, &avrc_rsp);
+}
+
+/***************************************************************************
+ *  Function       handle_rc_metamsg_cmd
+ *
+ *  - Argument:    tBTA_AV_VENDOR Structure containing the received
+ *                          metamsg command
+ *
+ *  - Description: Remote control metamsg command handler (AVRCP 1.3)
+ *
+ ***************************************************************************/
+void handle_rc_metamsg_cmd(tBTA_AV_META_MSG* pmeta_msg) {
+  /* Parse the metamsg command and pass it on to BTL-IFS */
+  uint8_t scratch_buf[512] = {0};
+  tAVRC_COMMAND avrc_command = {0};
+  tAVRC_STS status;
+  btif_rc_device_cb_t* p_dev = NULL;
+
+  if (NULL == pmeta_msg) {
+    BTIF_TRACE_EVENT("%s: Exiting as pmeta_msg is NULL", __func__);
+    return;
+  }
+
+  if (NULL == pmeta_msg->p_msg) {
+    BTIF_TRACE_EVENT("%s: Exiting as pmeta_msg->p_msg is NULL", __func__);
+    return;
+  }
+
+  BTIF_TRACE_EVENT("%s: pmeta_msg: opcode: %x, code: %x", __func__,
+                   pmeta_msg->p_msg->hdr.opcode, pmeta_msg->code);
+
+  p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR("%s: Meta msg event for Invalid rc handle", __func__);
+    return;
+  }
+
+  if (pmeta_msg->p_msg->hdr.opcode != AVRC_OP_VENDOR &&
+      pmeta_msg->p_msg->hdr.opcode != AVRC_OP_BROWSE) {
+    BTIF_TRACE_WARNING("Invalid opcode: %x", pmeta_msg->p_msg->hdr.opcode);
+    return;
+  }
+
+  if (pmeta_msg->len < 3) {
+    BTIF_TRACE_WARNING("%s: Invalid length. opcode: 0x%x, len: 0x%x", __func__,
+                       pmeta_msg->p_msg->hdr.opcode, pmeta_msg->len);
+    return;
+  }
+
+  if (pmeta_msg->code >= AVRC_RSP_NOT_IMPL) {
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+    {
+      rc_transaction_t* transaction = NULL;
+      transaction = get_transaction_by_lbl(pmeta_msg->label);
+      if (transaction != NULL) {
+        handle_rc_metamsg_rsp(pmeta_msg, p_dev);
+      } else {
+        BTIF_TRACE_DEBUG(
+            "%s: Discard vendor dependent rsp. code: %d label: %d.", __func__,
+            pmeta_msg->code, pmeta_msg->label);
+      }
+      return;
+    }
+#else
+    {
+      BTIF_TRACE_DEBUG(
+          "%s: Received vendor dependent rsp. code: %d len: %d. Not processing "
+          "it.",
+          __func__, pmeta_msg->code, pmeta_msg->len);
+      return;
+    }
+#endif
+  }
+
+  status = AVRC_ParsCommand(pmeta_msg->p_msg, &avrc_command, scratch_buf,
+                            sizeof(scratch_buf));
+  BTIF_TRACE_DEBUG("%s: Received vendor command.code,PDU and label: %d, %d, %d",
+                   __func__, pmeta_msg->code, avrc_command.cmd.pdu,
+                   pmeta_msg->label);
+
+  if (status != AVRC_STS_NO_ERROR) {
+    /* return error */
+    BTIF_TRACE_WARNING(
+        "%s: Error in parsing received metamsg command. status: 0x%02x",
+        __func__, status);
+    send_reject_response(pmeta_msg->rc_handle, pmeta_msg->label,
+                         avrc_command.pdu, status,
+                         pmeta_msg->p_msg->hdr.opcode);
+  } else {
+    /* if RegisterNotification, add it to our registered queue */
+
+    if (avrc_command.cmd.pdu == AVRC_PDU_REGISTER_NOTIFICATION) {
+      uint8_t event_id = avrc_command.reg_notif.event_id;
+
+      BTIF_TRACE_EVENT(
+          "%s: New register notification received.event_id: %s, label: 0x%x, "
+          "code: %x",
+          __func__, dump_rc_notification_event_id(event_id), pmeta_msg->label,
+          pmeta_msg->code);
+      p_dev->rc_notif[event_id - 1].bNotify = true;
+      p_dev->rc_notif[event_id - 1].label = pmeta_msg->label;
+
+      if (event_id == AVRC_EVT_UIDS_CHANGE) {
+        handle_uid_changed_notification(p_dev, pmeta_msg->label, &avrc_command);
+        return;
+      }
+    }
+
+    BTIF_TRACE_EVENT("%s: Passing received metamsg command to app. pdu: %s",
+                     __func__, dump_rc_pdu(avrc_command.cmd.pdu));
+
+    /* Since handle_rc_metamsg_cmd() itself is called from
+        *btif context, no context switching is required. Invoke
+        * btif_rc_upstreams_evt directly from here. */
+    btif_rc_upstreams_evt((uint16_t)avrc_command.cmd.pdu, &avrc_command,
+                          pmeta_msg->code, pmeta_msg->label, p_dev);
+  }
+}
+
+/***************************************************************************
+ **
+ ** Function       btif_rc_handler
+ **
+ ** Description    RC event handler
+ **
+ ***************************************************************************/
+void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV* p_data) {
+  BTIF_TRACE_DEBUG("%s: event: %s", __func__, dump_rc_event(event));
+  btif_rc_device_cb_t* p_dev = NULL;
+  switch (event) {
+    case BTA_AV_RC_OPEN_EVT: {
+      BTIF_TRACE_DEBUG("%s: Peer_features: %x", __func__,
+                       p_data->rc_open.peer_features);
+      handle_rc_connect(&(p_data->rc_open));
+    } break;
+
+    case BTA_AV_RC_BROWSE_OPEN_EVT: {
+      /* tell the UL that we have connection to browse channel and that
+       * browse commands can be directed accordingly. */
+      handle_rc_browse_connect(&(p_data->rc_open));
+    } break;
+
+    case BTA_AV_RC_CLOSE_EVT: {
+      handle_rc_disconnect(&(p_data->rc_close));
+    } break;
+
+    case BTA_AV_RC_BROWSE_CLOSE_EVT: {
+      BTIF_TRACE_DEBUG("%s: BTA_AV_RC_BROWSE_CLOSE_EVT", __func__);
+    } break;
+
+    case BTA_AV_REMOTE_CMD_EVT: {
+      if (bt_rc_callbacks != NULL) {
+        BTIF_TRACE_DEBUG("%s: rc_id: 0x%x key_state: %d", __func__,
+                         p_data->remote_cmd.rc_id,
+                         p_data->remote_cmd.key_state);
+        handle_rc_passthrough_cmd((&p_data->remote_cmd));
+      } else {
+        BTIF_TRACE_ERROR("%s: AVRCP TG role not up, drop passthrough commands",
+                         __func__);
+      }
+    } break;
+
+#if (AVRC_CTRL_INCLUDED == TRUE)
+    case BTA_AV_REMOTE_RSP_EVT: {
+      BTIF_TRACE_DEBUG("%s: RSP: rc_id: 0x%x key_state: %d", __func__,
+                       p_data->remote_rsp.rc_id, p_data->remote_rsp.key_state);
+
+      if (p_data->remote_rsp.rc_id == AVRC_ID_VENDOR) {
+        handle_rc_vendorunique_rsp((&p_data->remote_rsp));
+      } else {
+        handle_rc_passthrough_rsp((&p_data->remote_rsp));
+      }
+    } break;
+
+#endif
+    case BTA_AV_RC_FEAT_EVT: {
+      BTIF_TRACE_DEBUG("%s: Peer_features: %x", __func__,
+                       p_data->rc_feat.peer_features);
+      p_dev = btif_rc_get_device_by_handle(p_data->rc_feat.rc_handle);
+      if (p_dev == NULL) {
+        BTIF_TRACE_ERROR("%s: RC Feature event for Invalid rc handle",
+                         __func__);
+        break;
+      }
+
+      p_dev->rc_features = p_data->rc_feat.peer_features;
+      handle_rc_features(p_dev);
+
+#if (AVRC_CTRL_INCLUDED == TRUE)
+      if ((p_dev->rc_connected) && (bt_rc_ctrl_callbacks != NULL)) {
+        handle_rc_ctrl_features(p_dev);
+      }
+#endif
+    } break;
+
+    case BTA_AV_META_MSG_EVT: {
+      if (bt_rc_callbacks != NULL) {
+        BTIF_TRACE_DEBUG("%s: BTA_AV_META_MSG_EVT code: %d label: %d", __func__,
+                         p_data->meta_msg.code, p_data->meta_msg.label);
+        BTIF_TRACE_DEBUG("%s: company_id: 0x%x len: %d handle: %d", __func__,
+                         p_data->meta_msg.company_id, p_data->meta_msg.len,
+                         p_data->meta_msg.rc_handle);
+
+        /* handle the metamsg command */
+        handle_rc_metamsg_cmd(&(p_data->meta_msg));
+
+        /* Free the Memory allocated for tAVRC_MSG */
+      }
+#if (AVRC_CTRL_INCLUDED == TRUE)
+      else if (bt_rc_ctrl_callbacks != NULL) {
+        /* This is case of Sink + CT + TG(for abs vol)) */
+        BTIF_TRACE_DEBUG(
+            "%s BTA_AV_META_MSG_EVT code:%d label:%d opcode %d ctype %d",
+            __FUNCTION__, p_data->meta_msg.code, p_data->meta_msg.label,
+            p_data->meta_msg.p_msg->hdr.opcode,
+            p_data->meta_msg.p_msg->hdr.ctype);
+        BTIF_TRACE_DEBUG("%s company_id:0x%x len:%d handle:%d", __FUNCTION__,
+                         p_data->meta_msg.company_id, p_data->meta_msg.len,
+                         p_data->meta_msg.rc_handle);
+        switch (p_data->meta_msg.p_msg->hdr.opcode) {
+          case AVRC_OP_VENDOR:
+            if ((p_data->meta_msg.code >= AVRC_RSP_NOT_IMPL) &&
+                (p_data->meta_msg.code <= AVRC_RSP_INTERIM)) {
+              /* Its a response */
+              handle_avk_rc_metamsg_rsp(&(p_data->meta_msg));
+            } else if (p_data->meta_msg.code <= AVRC_CMD_GEN_INQ) {
+              /* Its a command  */
+              handle_avk_rc_metamsg_cmd(&(p_data->meta_msg));
+            }
+            break;
+
+          case AVRC_OP_BROWSE:
+            if (p_data->meta_msg.p_msg->hdr.ctype == AVRC_CMD) {
+              handle_avk_rc_metamsg_cmd(&(p_data->meta_msg));
+            } else if (p_data->meta_msg.p_msg->hdr.ctype == AVRC_RSP) {
+              handle_avk_rc_metamsg_rsp(&(p_data->meta_msg));
+            }
+            break;
+        }
+
+      }
+#endif
+      else {
+        BTIF_TRACE_ERROR("Neither CTRL, nor TG is up, drop meta commands");
+      }
+    } break;
+
+    default:
+      BTIF_TRACE_DEBUG("%s: Unhandled RC event : 0x%x", __func__, event);
+  }
+}
+
+/***************************************************************************
+ **
+ ** Function       btif_rc_get_connected_peer
+ **
+ ** Description    Fetches the connected headset's BD_ADDR if any
+ **
+ ***************************************************************************/
+bool btif_rc_get_connected_peer(BD_ADDR peer_addr) {
+  bt_bdaddr_t rc_addr;
+  bdcpy(rc_addr.address, peer_addr);
+  btif_rc_device_cb_t* p_dev = NULL;
+
+  for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+    p_dev = get_connected_device(idx);
+    if (p_dev != NULL && (p_dev->rc_connected == TRUE)) {
+      bdcpy(peer_addr, p_dev->rc_addr);
+      return TRUE;
+    }
+  }
+  return false;
+}
+
+/***************************************************************************
+ **
+ ** Function       btif_rc_get_connected_peer_handle
+ **
+ ** Description    Fetches the connected headset's handle if any
+ **
+ ***************************************************************************/
+uint8_t btif_rc_get_connected_peer_handle(BD_ADDR peer_addr) {
+  bt_bdaddr_t rc_addr;
+  bdcpy(rc_addr.address, peer_addr);
+
+  btif_rc_device_cb_t* p_dev = NULL;
+  p_dev = btif_rc_get_device_by_bda(&rc_addr);
+
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+    return BTRC_HANDLE_NONE;
+  }
+  return p_dev->rc_handle;
+}
+
+/***************************************************************************
+ **
+ ** Function       btif_rc_check_handle_pending_play
+ **
+ ** Description    Clears the queued PLAY command. if |bSendToApp| is true,
+ **                forwards to app
+ **
+ ***************************************************************************/
+
+/* clear the queued PLAY command. if |bSendToApp| is true, forward to app */
+void btif_rc_check_handle_pending_play(BD_ADDR peer_addr, bool bSendToApp) {
+  bt_bdaddr_t rc_addr;
+  bdcpy(rc_addr.address, peer_addr);
+
+  btif_rc_device_cb_t* p_dev = NULL;
+  p_dev = btif_rc_get_device_by_bda(&rc_addr);
+
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+    return;
+  }
+
+  BTIF_TRACE_DEBUG("%s: bSendToApp: %d", __func__, bSendToApp);
+  if (p_dev->rc_pending_play) {
+    if (bSendToApp) {
+      tBTA_AV_REMOTE_CMD remote_cmd;
+      APPL_TRACE_DEBUG("%s: Sending queued PLAYED event to app", __func__);
+
+      memset(&remote_cmd, 0, sizeof(tBTA_AV_REMOTE_CMD));
+      remote_cmd.rc_handle = p_dev->rc_handle;
+      remote_cmd.rc_id = AVRC_ID_PLAY;
+      remote_cmd.hdr.ctype = AVRC_CMD_CTRL;
+      remote_cmd.hdr.opcode = AVRC_OP_PASS_THRU;
+
+      /* delay sending to app, else there is a timing issue in the framework,
+       ** which causes the audio to be on th device's speaker. Delay between
+       ** OPEN & RC_PLAYs
+      */
+      sleep_ms(200);
+      /* send to app - both PRESSED & RELEASED */
+      remote_cmd.key_state = AVRC_STATE_PRESS;
+      handle_rc_passthrough_cmd(&remote_cmd);
+
+      sleep_ms(100);
+
+      remote_cmd.key_state = AVRC_STATE_RELEASE;
+      handle_rc_passthrough_cmd(&remote_cmd);
+    }
+    p_dev->rc_pending_play = false;
+  }
+}
+
+/* Generic reject response */
+static void send_reject_response(uint8_t rc_handle, uint8_t label, uint8_t pdu,
+                                 uint8_t status, uint8_t opcode) {
+  uint8_t ctype = AVRC_RSP_REJ;
+  tAVRC_RESPONSE avrc_rsp;
+  BT_HDR* p_msg = NULL;
+  memset(&avrc_rsp, 0, sizeof(tAVRC_RESPONSE));
+
+  avrc_rsp.rsp.opcode = opcode;
+  avrc_rsp.rsp.pdu = pdu;
+  avrc_rsp.rsp.status = status;
+
+  status = AVRC_BldResponse(rc_handle, &avrc_rsp, &p_msg);
+
+  if (status != AVRC_STS_NO_ERROR) {
+    BTIF_TRACE_ERROR("%s: status not AVRC_STS_NO_ERROR", __func__);
+    return;
+  }
+
+  BTIF_TRACE_DEBUG(
+      "%s: Sending error notification to handle: %d. pdu: %s,status: 0x%02x",
+      __func__, rc_handle, dump_rc_pdu(pdu), status);
+  BTA_AvMetaRsp(rc_handle, label, ctype, p_msg);
+}
+
+/***************************************************************************
+ *  Function         get_rsp_type_code
+ *
+ *  - Argument:   status
+ *  - Description: Returns response type codes for particular command code and
+ *                 status.
+ *
+ ***************************************************************************/
+static tBTA_AV_CODE get_rsp_type_code(tAVRC_STS status, tBTA_AV_CODE code) {
+  if (status != AVRC_STS_NO_ERROR) {
+    return AVRC_RSP_REJ;
+  }
+
+  if (code < AVRC_RSP_NOT_IMPL) {
+    if (code == AVRC_CMD_NOTIF) return AVRC_RSP_INTERIM;
+
+    if (code == AVRC_CMD_STATUS) return AVRC_RSP_IMPL_STBL;
+
+    return AVRC_RSP_ACCEPT;
+  }
+
+  return code;
+}
+
+/***************************************************************************
+ *  Function       send_metamsg_rsp
+ *
+ *  - Argument:
+ *                  p_dev           Dev pointer
+ *                  index           Command index (= -1 if not used)
+ *                  label           Label of the RC response
+ *                  code            Response type
+ *                  pmetamsg_resp   Vendor response
+ *
+ *  - Description: Remote control metamsg response handler
+ *
+ ***************************************************************************/
+static void send_metamsg_rsp(btif_rc_device_cb_t* p_dev, int index,
+                             uint8_t label, tBTA_AV_CODE code,
+                             tAVRC_RESPONSE* pmetamsg_resp) {
+  uint8_t ctype;
+
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+    return;
+  }
+
+  if (pmetamsg_resp == NULL) {
+    BTIF_TRACE_WARNING("%s: Invalid response received from application",
+                       __func__);
+    return;
+  }
+
+  BTIF_TRACE_EVENT(
+      "%s: rc_handle: %d, index: %d, label: %d, code: 0x%02x, pdu: %s",
+      __func__, p_dev->rc_handle, index, label, code,
+      dump_rc_pdu(pmetamsg_resp->rsp.pdu));
+
+  if (index >= 0 && p_dev->rc_pdu_info[index].is_rsp_pending == false) {
+    BTIF_TRACE_ERROR("%s: is_rsp_pending false, returning", __func__);
+    return;
+  }
+
+  ctype = get_rsp_type_code(pmetamsg_resp->rsp.status, code);
+
+  /* if response is for register_notification, make sure the rc has
+  actually registered for this */
+  if ((pmetamsg_resp->rsp.pdu == AVRC_PDU_REGISTER_NOTIFICATION) &&
+      ((code == AVRC_RSP_CHANGED) || (code == AVRC_RSP_INTERIM))) {
+    bool bSent = false;
+    uint8_t event_id = pmetamsg_resp->reg_notif.event_id;
+    bool bNotify =
+        (p_dev->rc_connected) && (p_dev->rc_notif[event_id - 1].bNotify);
+
+    /* de-register this notification for a CHANGED response */
+    p_dev->rc_notif[event_id - 1].bNotify = false;
+    BTIF_TRACE_DEBUG("%s: rc_handle: %d. event_id: 0x%02d bNotify: %u",
+                     __func__, p_dev->rc_handle, event_id, bNotify);
+    if (bNotify) {
+      BT_HDR* p_msg = NULL;
+      tAVRC_STS status;
+
+      if (AVRC_STS_NO_ERROR == (status = AVRC_BldResponse(
+                                    p_dev->rc_handle, pmetamsg_resp, &p_msg))) {
+        BTIF_TRACE_DEBUG(
+            "%s: Sending notification to rc_handle: %d. event_id: 0x%02d",
+            __func__, p_dev->rc_handle, event_id);
+        bSent = true;
+        BTA_AvMetaRsp(p_dev->rc_handle, p_dev->rc_notif[event_id - 1].label,
+                      ctype, p_msg);
+      } else {
+        BTIF_TRACE_WARNING(
+            "%s: failed to build metamsg response. status: 0x%02x", __func__,
+            status);
+      }
+    }
+
+    if (!bSent) {
+      BTIF_TRACE_DEBUG(
+          "%s: Notification not sent, as there are no RC connections or the \
+                CT has not subscribed for event_id: %s",
+          __func__, dump_rc_notification_event_id(event_id));
+    }
+  } else {
+    /* All other commands go here */
+
+    BT_HDR* p_msg = NULL;
+    tAVRC_STS status;
+
+    status = AVRC_BldResponse(p_dev->rc_handle, pmetamsg_resp, &p_msg);
+
+    if (status == AVRC_STS_NO_ERROR) {
+      BTA_AvMetaRsp(p_dev->rc_handle, label, ctype, p_msg);
+    } else {
+      BTIF_TRACE_ERROR("%s: failed to build metamsg response. status: 0x%02x",
+                       __func__, status);
+    }
+  }
+
+  if (index >= 0) {
+    p_dev->rc_pdu_info[index].ctype = 0;
+    p_dev->rc_pdu_info[index].label = 0;
+    p_dev->rc_pdu_info[index].is_rsp_pending = false;
+  }
+}
+
+static uint8_t opcode_from_pdu(uint8_t pdu) {
+  uint8_t opcode = 0;
+
+  switch (pdu) {
+    case AVRC_PDU_SET_BROWSED_PLAYER:
+    case AVRC_PDU_GET_FOLDER_ITEMS:
+    case AVRC_PDU_CHANGE_PATH:
+    case AVRC_PDU_GET_ITEM_ATTRIBUTES:
+    case AVRC_PDU_ADD_TO_NOW_PLAYING:
+    case AVRC_PDU_SEARCH:
+    case AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS:
+    case AVRC_PDU_GENERAL_REJECT:
+      opcode = AVRC_OP_BROWSE;
+      break;
+
+    case AVRC_PDU_NEXT_GROUP:
+    case AVRC_PDU_PREV_GROUP: /* pass thru */
+      opcode = AVRC_OP_PASS_THRU;
+      break;
+
+    default: /* vendor */
+      opcode = AVRC_OP_VENDOR;
+      break;
+  }
+
+  return opcode;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_rc_upstreams_evt
+ *
+ * Description      Executes AVRC UPSTREAMS events in btif context.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND* pavrc_cmd,
+                                  uint8_t ctype, uint8_t label,
+                                  btif_rc_device_cb_t* p_dev) {
+  BTIF_TRACE_EVENT("%s: pdu: %s handle: 0x%x ctype: %x label: %x event ID: %x",
+                   __func__, dump_rc_pdu(pavrc_cmd->pdu), p_dev->rc_handle,
+                   ctype, label, pavrc_cmd->reg_notif.event_id);
+  bt_bdaddr_t rc_addr;
+
+  bdcpy(rc_addr.address, p_dev->rc_addr);
+
+  switch (event) {
+    case AVRC_PDU_GET_PLAY_STATUS: {
+      fill_pdu_queue(IDX_GET_PLAY_STATUS_RSP, ctype, label, true, p_dev);
+      HAL_CBACK(bt_rc_callbacks, get_play_status_cb, &rc_addr);
+    } break;
+    case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+    case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+    case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+    case AVRC_PDU_SET_PLAYER_APP_VALUE:
+    case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+    case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT: {
+      /* TODO: Add support for Application Settings */
+      send_reject_response(p_dev->rc_handle, label, pavrc_cmd->pdu,
+                           AVRC_STS_BAD_CMD, pavrc_cmd->cmd.opcode);
+    } break;
+    case AVRC_PDU_GET_ELEMENT_ATTR: {
+      btrc_media_attr_t element_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+      uint8_t num_attr;
+      memset(&element_attrs, 0, sizeof(element_attrs));
+      if (pavrc_cmd->get_elem_attrs.num_attr == 0) {
+        /* CT requests for all attributes */
+        int attr_cnt;
+        num_attr = BTRC_MAX_ELEM_ATTR_SIZE;
+        for (attr_cnt = 0; attr_cnt < BTRC_MAX_ELEM_ATTR_SIZE; attr_cnt++) {
+          element_attrs[attr_cnt] = (btrc_media_attr_t)(attr_cnt + 1);
+        }
+      } else if (pavrc_cmd->get_elem_attrs.num_attr == 0xFF) {
+        /* 0xff indicates, no attributes requested - reject */
+        send_reject_response(p_dev->rc_handle, label, pavrc_cmd->pdu,
+                             AVRC_STS_BAD_PARAM, pavrc_cmd->cmd.opcode);
+        return;
+      } else {
+        int attr_cnt, filled_attr_count;
+
+        num_attr = 0;
+        /* Attribute IDs from 1 to AVRC_MAX_NUM_MEDIA_ATTR_ID are only valid,
+         * hence HAL definition limits the attributes to
+         * AVRC_MAX_NUM_MEDIA_ATTR_ID.
+         * Fill only valid entries.
+         */
+        for (attr_cnt = 0; (attr_cnt < pavrc_cmd->get_elem_attrs.num_attr) &&
+                           (num_attr < AVRC_MAX_NUM_MEDIA_ATTR_ID);
+             attr_cnt++) {
+          if ((pavrc_cmd->get_elem_attrs.attrs[attr_cnt] > 0) &&
+              (pavrc_cmd->get_elem_attrs.attrs[attr_cnt] <=
+               AVRC_MAX_NUM_MEDIA_ATTR_ID)) {
+            /* Skip the duplicate entries : PTS sends duplicate entries for
+             * Fragment cases
+             */
+            for (filled_attr_count = 0; filled_attr_count < num_attr;
+                 filled_attr_count++) {
+              if (element_attrs[filled_attr_count] ==
+                  pavrc_cmd->get_elem_attrs.attrs[attr_cnt])
+                break;
+            }
+            if (filled_attr_count == num_attr) {
+              element_attrs[num_attr] =
+                  (btrc_media_attr_t)pavrc_cmd->get_elem_attrs.attrs[attr_cnt];
+              num_attr++;
+            }
+          }
+        }
+      }
+      fill_pdu_queue(IDX_GET_ELEMENT_ATTR_RSP, ctype, label, true, p_dev);
+      HAL_CBACK(bt_rc_callbacks, get_element_attr_cb, num_attr, element_attrs,
+                &rc_addr);
+    } break;
+    case AVRC_PDU_REGISTER_NOTIFICATION: {
+      if (pavrc_cmd->reg_notif.event_id == BTRC_EVT_PLAY_POS_CHANGED &&
+          pavrc_cmd->reg_notif.param == 0) {
+        BTIF_TRACE_WARNING(
+            "%s: Device registering position changed with illegal param 0.",
+            __func__);
+        send_reject_response(p_dev->rc_handle, label, pavrc_cmd->pdu,
+                             AVRC_STS_BAD_PARAM, pavrc_cmd->cmd.opcode);
+        /* de-register this notification for a rejected response */
+        p_dev->rc_notif[BTRC_EVT_PLAY_POS_CHANGED - 1].bNotify = false;
+        return;
+      }
+      HAL_CBACK(bt_rc_callbacks, register_notification_cb,
+                (btrc_event_id_t)pavrc_cmd->reg_notif.event_id,
+                pavrc_cmd->reg_notif.param, &rc_addr);
+    } break;
+    case AVRC_PDU_INFORM_DISPLAY_CHARSET: {
+      tAVRC_RESPONSE avrc_rsp;
+      BTIF_TRACE_EVENT("%s: AVRC_PDU_INFORM_DISPLAY_CHARSET", __func__);
+      if (p_dev->rc_connected == true) {
+        memset(&(avrc_rsp.inform_charset), 0, sizeof(tAVRC_RSP));
+        avrc_rsp.inform_charset.opcode =
+            opcode_from_pdu(AVRC_PDU_INFORM_DISPLAY_CHARSET);
+        avrc_rsp.inform_charset.pdu = AVRC_PDU_INFORM_DISPLAY_CHARSET;
+        avrc_rsp.inform_charset.status = AVRC_STS_NO_ERROR;
+        send_metamsg_rsp(p_dev, -1, label, ctype, &avrc_rsp);
+      }
+    } break;
+
+    case AVRC_PDU_GET_FOLDER_ITEMS: {
+      uint32_t attr_ids[BTRC_MAX_ELEM_ATTR_SIZE];
+      uint8_t num_attr;
+      num_attr = pavrc_cmd->get_items.attr_count;
+
+      BTIF_TRACE_EVENT(
+          "%s: AVRC_PDU_GET_FOLDER_ITEMS num_attr: %d, start_item [%d] \
+                end_item [%d]",
+          __func__, num_attr, pavrc_cmd->get_items.start_item,
+          pavrc_cmd->get_items.end_item);
+
+      /* num_attr requested:
+       *     0x00: All attributes requested
+       *     0xFF: No Attributes requested
+       *     0x01 to 0x07: Specified number of attributes
+       */
+      if ((num_attr != 0xFF && num_attr > BTRC_MAX_ELEM_ATTR_SIZE)) {
+        send_reject_response(p_dev->rc_handle, label, pavrc_cmd->pdu,
+                             AVRC_STS_BAD_PARAM, pavrc_cmd->cmd.opcode);
+        return;
+      }
+
+      /* Except num_attr is None(0xff) / All(0x00), request follows with an
+       * Attribute List */
+      if ((num_attr != 0xFF) && (num_attr != 0x00)) {
+        memcpy(attr_ids, pavrc_cmd->get_items.p_attr_list,
+               sizeof(uint32_t) * num_attr);
+      }
+
+      fill_pdu_queue(IDX_GET_FOLDER_ITEMS_RSP, ctype, label, true, p_dev);
+      HAL_CBACK(bt_rc_callbacks, get_folder_items_cb,
+                pavrc_cmd->get_items.scope, pavrc_cmd->get_items.start_item,
+                pavrc_cmd->get_items.end_item, num_attr, attr_ids, &rc_addr);
+    } break;
+
+    case AVRC_PDU_SET_ADDRESSED_PLAYER: {
+      fill_pdu_queue(IDX_SET_ADDR_PLAYER_RSP, ctype, label, true, p_dev);
+      HAL_CBACK(bt_rc_callbacks, set_addressed_player_cb,
+                pavrc_cmd->addr_player.player_id, &rc_addr);
+    } break;
+
+    case AVRC_PDU_SET_BROWSED_PLAYER: {
+      fill_pdu_queue(IDX_SET_BROWSED_PLAYER_RSP, ctype, label, true, p_dev);
+      HAL_CBACK(bt_rc_callbacks, set_browsed_player_cb,
+                pavrc_cmd->br_player.player_id, &rc_addr);
+    } break;
+
+    case AVRC_PDU_REQUEST_CONTINUATION_RSP: {
+      BTIF_TRACE_EVENT("%s() REQUEST CONTINUATION: target_pdu: 0x%02d",
+                       __func__, pavrc_cmd->continu.target_pdu);
+      tAVRC_RESPONSE avrc_rsp;
+      if (p_dev->rc_connected == TRUE) {
+        memset(&(avrc_rsp.continu), 0, sizeof(tAVRC_NEXT_RSP));
+        avrc_rsp.continu.opcode =
+            opcode_from_pdu(AVRC_PDU_REQUEST_CONTINUATION_RSP);
+        avrc_rsp.continu.pdu = AVRC_PDU_REQUEST_CONTINUATION_RSP;
+        avrc_rsp.continu.status = AVRC_STS_NO_ERROR;
+        avrc_rsp.continu.target_pdu = pavrc_cmd->continu.target_pdu;
+        send_metamsg_rsp(p_dev, -1, label, ctype, &avrc_rsp);
+      }
+    } break;
+
+    case AVRC_PDU_ABORT_CONTINUATION_RSP: {
+      BTIF_TRACE_EVENT("%s() ABORT CONTINUATION: target_pdu: 0x%02d", __func__,
+                       pavrc_cmd->abort.target_pdu);
+      tAVRC_RESPONSE avrc_rsp;
+      if (p_dev->rc_connected == TRUE) {
+        memset(&(avrc_rsp.abort), 0, sizeof(tAVRC_NEXT_RSP));
+        avrc_rsp.abort.opcode =
+            opcode_from_pdu(AVRC_PDU_ABORT_CONTINUATION_RSP);
+        avrc_rsp.abort.pdu = AVRC_PDU_ABORT_CONTINUATION_RSP;
+        avrc_rsp.abort.status = AVRC_STS_NO_ERROR;
+        avrc_rsp.abort.target_pdu = pavrc_cmd->continu.target_pdu;
+        send_metamsg_rsp(p_dev, -1, label, ctype, &avrc_rsp);
+      }
+    } break;
+
+    case AVRC_PDU_CHANGE_PATH: {
+      fill_pdu_queue(IDX_CHG_PATH_RSP, ctype, label, true, p_dev);
+      HAL_CBACK(bt_rc_callbacks, change_path_cb, pavrc_cmd->chg_path.direction,
+                pavrc_cmd->chg_path.folder_uid, &rc_addr);
+    } break;
+
+    case AVRC_PDU_SEARCH: {
+      fill_pdu_queue(IDX_SEARCH_RSP, ctype, label, true, p_dev);
+      HAL_CBACK(bt_rc_callbacks, search_cb, pavrc_cmd->search.string.charset_id,
+                pavrc_cmd->search.string.str_len,
+                pavrc_cmd->search.string.p_str, &rc_addr);
+    } break;
+
+    case AVRC_PDU_GET_ITEM_ATTRIBUTES: {
+      btrc_media_attr_t item_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+      uint8_t num_attr;
+      uint8_t scope;
+      uint16_t uid_counter;
+
+      scope = pavrc_cmd->get_attrs.scope;
+      uid_counter = pavrc_cmd->get_attrs.uid_counter;
+      memset(&item_attrs, 0, sizeof(item_attrs));
+
+      if (pavrc_cmd->get_attrs.attr_count == 0xFF) {
+        BTIF_TRACE_ERROR(
+            "%s: No attributes are requested in GET_ITEM_ATTRIBUTES", __func__);
+        /* 0xff indicates, no attributes requested - reject this */
+        send_reject_response(p_dev->rc_handle, label, pavrc_cmd->pdu,
+                             AVRC_STS_BAD_PARAM, pavrc_cmd->cmd.opcode);
+        return;
+      }
+
+      if (pavrc_cmd->get_attrs.attr_count == 0) {
+        /* CT requests for all attributes */
+        int attr_cnt;
+        num_attr = BTRC_MAX_ELEM_ATTR_SIZE;
+        for (attr_cnt = 0; attr_cnt < BTRC_MAX_ELEM_ATTR_SIZE; attr_cnt++) {
+          item_attrs[attr_cnt] = (btrc_media_attr_t)(attr_cnt + 1);
+        }
+      } else {
+        num_attr = pavrc_cmd->get_attrs.attr_count;
+        memcpy(item_attrs, pavrc_cmd->get_attrs.p_attr_list,
+               sizeof(uint32_t) * pavrc_cmd->get_attrs.attr_count);
+      }
+      fill_pdu_queue(IDX_GET_ITEM_ATTR_RSP, ctype, label, true, p_dev);
+      BTIF_TRACE_DEBUG("%s: GET_ITEM_ATTRIBUTES: num_attr: %d", __func__,
+                       num_attr);
+      HAL_CBACK(bt_rc_callbacks, get_item_attr_cb, scope,
+                pavrc_cmd->get_attrs.uid, uid_counter, num_attr, item_attrs,
+                &rc_addr);
+    } break;
+
+    case AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS: {
+      fill_pdu_queue(IDX_GET_TOTAL_NUM_OF_ITEMS_RSP, ctype, label, true, p_dev);
+      HAL_CBACK(bt_rc_callbacks, get_total_num_of_items_cb,
+                pavrc_cmd->get_num_of_items.scope, &rc_addr);
+    } break;
+
+    case AVRC_PDU_ADD_TO_NOW_PLAYING: {
+      fill_pdu_queue(IDX_ADD_TO_NOW_PLAYING_RSP, ctype, label, true, p_dev);
+      HAL_CBACK(bt_rc_callbacks, add_to_now_playing_cb,
+                pavrc_cmd->add_to_play.scope, pavrc_cmd->add_to_play.uid,
+                pavrc_cmd->add_to_play.uid_counter, &rc_addr);
+    } break;
+
+    case AVRC_PDU_PLAY_ITEM: {
+      fill_pdu_queue(IDX_PLAY_ITEM_RSP, ctype, label, true, p_dev);
+      HAL_CBACK(bt_rc_callbacks, play_item_cb, pavrc_cmd->play_item.scope,
+                pavrc_cmd->play_item.uid_counter, pavrc_cmd->play_item.uid,
+                &rc_addr);
+    } break;
+
+    default: {
+      send_reject_response(p_dev->rc_handle, label, pavrc_cmd->pdu,
+                           AVRC_STS_BAD_CMD, pavrc_cmd->cmd.opcode);
+      return;
+    } break;
+  }
+}
+
+#if (AVRC_CTRL_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function         btif_rc_ctrl_upstreams_rsp_cmd
+ *
+ * Description      Executes AVRC UPSTREAMS response events in btif context.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_rc_ctrl_upstreams_rsp_cmd(uint8_t event,
+                                           tAVRC_COMMAND* pavrc_cmd,
+                                           uint8_t label,
+                                           btif_rc_device_cb_t* p_dev) {
+  BTIF_TRACE_DEBUG("%s: pdu: %s: handle: 0x%x", __func__,
+                   dump_rc_pdu(pavrc_cmd->pdu), p_dev->rc_handle);
+  bt_bdaddr_t rc_addr;
+  bdcpy(rc_addr.address, p_dev->rc_addr);
+  switch (event) {
+    case AVRC_PDU_SET_ABSOLUTE_VOLUME:
+      HAL_CBACK(bt_rc_ctrl_callbacks, setabsvol_cmd_cb, &rc_addr,
+                pavrc_cmd->volume.volume, label);
+      break;
+    case AVRC_PDU_REGISTER_NOTIFICATION:
+      if (pavrc_cmd->reg_notif.event_id == AVRC_EVT_VOLUME_CHANGE) {
+        HAL_CBACK(bt_rc_ctrl_callbacks, registernotification_absvol_cb,
+                  &rc_addr, label);
+      }
+      break;
+  }
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function         btif_rc_upstreams_rsp_evt
+ *
+ * Description      Executes AVRC UPSTREAMS response events in btif context.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+static void btif_rc_upstreams_rsp_evt(uint16_t event,
+                                      tAVRC_RESPONSE* pavrc_resp, uint8_t ctype,
+                                      uint8_t label,
+                                      btif_rc_device_cb_t* p_dev) {
+  BTIF_TRACE_EVENT("%s: pdu: %s: handle: 0x%x ctype: %x label: %x", __func__,
+                   dump_rc_pdu(pavrc_resp->pdu), p_dev->rc_handle, ctype,
+                   label);
+  bt_bdaddr_t rc_addr;
+  bdcpy(rc_addr.address, p_dev->rc_addr);
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+  switch (event) {
+    case AVRC_PDU_REGISTER_NOTIFICATION: {
+      if (AVRC_RSP_CHANGED == ctype)
+        p_dev->rc_volume = pavrc_resp->reg_notif.param.volume;
+      HAL_CBACK(bt_rc_callbacks, volume_change_cb,
+                pavrc_resp->reg_notif.param.volume, ctype, &rc_addr);
+    } break;
+
+    case AVRC_PDU_SET_ABSOLUTE_VOLUME: {
+      BTIF_TRACE_DEBUG(
+          "%s: Set absolute volume change event received: volume: %d, ctype: "
+          "%d",
+          __func__, pavrc_resp->volume.volume, ctype);
+      if (AVRC_RSP_ACCEPT == ctype)
+        p_dev->rc_volume = pavrc_resp->volume.volume;
+      HAL_CBACK(bt_rc_callbacks, volume_change_cb, pavrc_resp->volume.volume,
+                ctype, &rc_addr);
+    } break;
+
+    default:
+      return;
+  }
+#endif
+}
+
+/************************************************************************************
+ *  AVRCP API Functions
+ ***********************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         init
+ *
+ * Description      Initializes the AVRC interface
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t init(btrc_callbacks_t* callbacks) {
+  BTIF_TRACE_EVENT("%s: ", __func__);
+  bt_status_t result = BT_STATUS_SUCCESS;
+
+  if (bt_rc_callbacks) return BT_STATUS_DONE;
+
+  bt_rc_callbacks = callbacks;
+  for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+    memset(&btif_rc_cb.rc_multi_cb[idx], 0,
+           sizeof(btif_rc_cb.rc_multi_cb[idx]));
+    btif_rc_cb.rc_multi_cb[idx].rc_vol_label = MAX_LABEL;
+    btif_rc_cb.rc_multi_cb[idx].rc_volume = MAX_VOLUME;
+    btif_rc_cb.rc_multi_cb[idx].rc_state = BTRC_CONNECTION_STATE_DISCONNECTED;
+  }
+  lbl_init();
+
+  return result;
+}
+
+/*******************************************************************************
+ *
+ * Function         init_ctrl
+ *
+ * Description      Initializes the AVRC interface
+ *
+ * Returns          bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t init_ctrl(btrc_ctrl_callbacks_t* callbacks) {
+  BTIF_TRACE_EVENT("%s: ", __func__);
+  bt_status_t result = BT_STATUS_SUCCESS;
+
+  if (bt_rc_ctrl_callbacks) return BT_STATUS_DONE;
+
+  bt_rc_ctrl_callbacks = callbacks;
+  for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+    memset(&btif_rc_cb.rc_multi_cb[idx], 0,
+           sizeof(btif_rc_cb.rc_multi_cb[idx]));
+    btif_rc_cb.rc_multi_cb[idx].rc_vol_label = MAX_LABEL;
+    btif_rc_cb.rc_multi_cb[idx].rc_volume = MAX_VOLUME;
+  }
+  lbl_init();
+
+  return result;
+}
+
+static void rc_ctrl_procedure_complete(btif_rc_device_cb_t* p_dev) {
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+    return;
+  }
+
+  if (p_dev->rc_procedure_complete == true) {
+    return;
+  }
+  p_dev->rc_procedure_complete = true;
+  uint32_t attr_list[] = {
+      AVRC_MEDIA_ATTR_ID_TITLE,       AVRC_MEDIA_ATTR_ID_ARTIST,
+      AVRC_MEDIA_ATTR_ID_ALBUM,       AVRC_MEDIA_ATTR_ID_TRACK_NUM,
+      AVRC_MEDIA_ATTR_ID_NUM_TRACKS,  AVRC_MEDIA_ATTR_ID_GENRE,
+      AVRC_MEDIA_ATTR_ID_PLAYING_TIME};
+  get_element_attribute_cmd(AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list, p_dev);
+}
+
+/***************************************************************************
+ *
+ * Function         get_play_status_rsp
+ *
+ * Description      Returns the current play status.
+ *                      This method is called in response to
+ *                      GetPlayStatus request.
+ *
+ * Returns          bt_status_t
+ *
+ **************************************************************************/
+static bt_status_t get_play_status_rsp(bt_bdaddr_t* bd_addr,
+                                       btrc_play_status_t play_status,
+                                       uint32_t song_len, uint32_t song_pos) {
+  tAVRC_RESPONSE avrc_rsp;
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  memset(&(avrc_rsp.get_play_status), 0, sizeof(tAVRC_GET_PLAY_STATUS_RSP));
+
+  BTIF_TRACE_DEBUG("%s song len %d song pos %d", __func__, song_len, song_pos);
+  avrc_rsp.get_play_status.song_len = song_len;
+  avrc_rsp.get_play_status.song_pos = song_pos;
+  avrc_rsp.get_play_status.play_status = play_status;
+
+  avrc_rsp.get_play_status.pdu = AVRC_PDU_GET_PLAY_STATUS;
+  avrc_rsp.get_play_status.opcode = opcode_from_pdu(AVRC_PDU_GET_PLAY_STATUS);
+  avrc_rsp.get_play_status.status =
+      ((play_status != BTRC_PLAYSTATE_ERROR) ? AVRC_STS_NO_ERROR
+                                             : AVRC_STS_BAD_PARAM);
+
+  /* Send the response */
+  send_metamsg_rsp(p_dev, IDX_GET_PLAY_STATUS_RSP,
+                   p_dev->rc_pdu_info[IDX_GET_PLAY_STATUS_RSP].label,
+                   p_dev->rc_pdu_info[IDX_GET_PLAY_STATUS_RSP].ctype,
+                   &avrc_rsp);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Function         get_element_attr_rsp
+ *
+ * Description      Returns the current songs' element attributes
+ *                      in text.
+ *
+ * Returns          bt_status_t
+ *
+ **************************************************************************/
+static bt_status_t get_element_attr_rsp(bt_bdaddr_t* bd_addr, uint8_t num_attr,
+                                        btrc_element_attr_val_t* p_attrs) {
+  tAVRC_RESPONSE avrc_rsp;
+  uint32_t i;
+  tAVRC_ATTR_ENTRY element_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  memset(element_attrs, 0, sizeof(tAVRC_ATTR_ENTRY) * num_attr);
+  BTIF_TRACE_ERROR("%s: calling btif_rc_get_device_by_bda", __func__);
+
+  if (num_attr == 0) {
+    avrc_rsp.get_play_status.status = AVRC_STS_BAD_PARAM;
+  } else {
+    for (i = 0; i < num_attr; i++) {
+      element_attrs[i].attr_id = p_attrs[i].attr_id;
+      element_attrs[i].name.charset_id = AVRC_CHARSET_ID_UTF8;
+      element_attrs[i].name.str_len = (uint16_t)strlen((char*)p_attrs[i].text);
+      element_attrs[i].name.p_str = p_attrs[i].text;
+      BTIF_TRACE_DEBUG(
+          "%s: attr_id: 0x%x, charset_id: 0x%x, str_len: %d, str: %s", __func__,
+          (unsigned int)element_attrs[i].attr_id,
+          element_attrs[i].name.charset_id, element_attrs[i].name.str_len,
+          element_attrs[i].name.p_str);
+    }
+    avrc_rsp.get_play_status.status = AVRC_STS_NO_ERROR;
+  }
+  avrc_rsp.get_elem_attrs.num_attr = num_attr;
+  avrc_rsp.get_elem_attrs.p_attrs = element_attrs;
+  avrc_rsp.get_elem_attrs.pdu = AVRC_PDU_GET_ELEMENT_ATTR;
+  avrc_rsp.get_elem_attrs.opcode = opcode_from_pdu(AVRC_PDU_GET_ELEMENT_ATTR);
+
+  /* Send the response */
+  send_metamsg_rsp(p_dev, IDX_GET_ELEMENT_ATTR_RSP,
+                   p_dev->rc_pdu_info[IDX_GET_ELEMENT_ATTR_RSP].label,
+                   p_dev->rc_pdu_info[IDX_GET_ELEMENT_ATTR_RSP].ctype,
+                   &avrc_rsp);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Function         reject_pending_notification
+ *
+ * Description      Utility function to reject a pending notification. When
+ *                  AddressedPlayer change is received, all pending
+ *                  notifications should be completed.
+ *
+ * Returns          void
+ *
+ **************************************************************************/
+static void reject_pending_notification(btrc_event_id_t event_id, int idx) {
+  tAVRC_RESPONSE avrc_rsp;
+  memset(&(avrc_rsp.reg_notif), 0, sizeof(tAVRC_REG_NOTIF_RSP));
+
+  avrc_rsp.reg_notif.event_id = event_id;
+  avrc_rsp.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
+  avrc_rsp.reg_notif.opcode = opcode_from_pdu(AVRC_PDU_REGISTER_NOTIFICATION);
+  avrc_rsp.reg_notif.status = AVRC_STS_ADDR_PLAYER_CHG;
+  BTIF_TRACE_WARNING("%s: Handling event ID: 0x%x", __func__, event_id);
+
+  send_metamsg_rsp(&btif_rc_cb.rc_multi_cb[idx], -1,
+                   btif_rc_cb.rc_multi_cb[idx].rc_notif[event_id - 1].label,
+                   AVRC_RSP_REJ, &avrc_rsp);
+}
+
+/***************************************************************************
+ *
+ * Function         register_notification_rsp
+ *
+ * Description      Response to the register notification request.
+ *
+ * Returns          bt_status_t
+ *
+ **************************************************************************/
+static bt_status_t register_notification_rsp(
+    btrc_event_id_t event_id, btrc_notification_type_t type,
+    btrc_register_notification_t* p_param) {
+  tAVRC_RESPONSE avrc_rsp;
+  BTIF_TRACE_EVENT("%s: event_id: %s", __func__,
+                   dump_rc_notification_event_id(event_id));
+  std::unique_lock<std::mutex> lock(btif_rc_cb.lock);
+
+  memset(&(avrc_rsp.reg_notif), 0, sizeof(tAVRC_REG_NOTIF_RSP));
+
+  avrc_rsp.reg_notif.event_id = event_id;
+  avrc_rsp.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
+  avrc_rsp.reg_notif.opcode = opcode_from_pdu(AVRC_PDU_REGISTER_NOTIFICATION);
+  avrc_rsp.get_play_status.status = AVRC_STS_NO_ERROR;
+
+  for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+    memset(&(avrc_rsp.reg_notif.param), 0, sizeof(tAVRC_NOTIF_RSP_PARAM));
+
+    if (!(btif_rc_cb.rc_multi_cb[idx].rc_connected)) {
+      BTIF_TRACE_ERROR("%s: Avrcp device is not connected, handle: 0x%x",
+                       __func__, btif_rc_cb.rc_multi_cb[idx].rc_handle);
+      continue;
+    }
+
+    if (btif_rc_cb.rc_multi_cb[idx].rc_notif[event_id - 1].bNotify == false) {
+      BTIF_TRACE_WARNING(
+          "%s: Avrcp Event id is not registered: event_id: %x, handle: 0x%x",
+          __func__, event_id, btif_rc_cb.rc_multi_cb[idx].rc_handle);
+      continue;
+    }
+
+    BTIF_TRACE_DEBUG(
+        "%s: Avrcp Event id is registered: event_id: %x handle: 0x%x", __func__,
+        event_id, btif_rc_cb.rc_multi_cb[idx].rc_handle);
+
+    switch (event_id) {
+      case BTRC_EVT_PLAY_STATUS_CHANGED:
+        avrc_rsp.reg_notif.param.play_status = p_param->play_status;
+        if (avrc_rsp.reg_notif.param.play_status == PLAY_STATUS_PLAYING)
+          btif_av_clear_remote_suspend_flag();
+        break;
+      case BTRC_EVT_TRACK_CHANGE:
+        memcpy(&(avrc_rsp.reg_notif.param.track), &(p_param->track),
+               sizeof(btrc_uid_t));
+        break;
+      case BTRC_EVT_PLAY_POS_CHANGED:
+        avrc_rsp.reg_notif.param.play_pos = p_param->song_pos;
+        break;
+      case BTRC_EVT_AVAL_PLAYER_CHANGE:
+        break;
+      case BTRC_EVT_ADDR_PLAYER_CHANGE:
+        avrc_rsp.reg_notif.param.addr_player.player_id =
+            p_param->addr_player_changed.player_id;
+        avrc_rsp.reg_notif.param.addr_player.uid_counter =
+            p_param->addr_player_changed.uid_counter;
+        break;
+      case BTRC_EVT_UIDS_CHANGED:
+        avrc_rsp.reg_notif.param.uid_counter =
+            p_param->uids_changed.uid_counter;
+        break;
+      case BTRC_EVT_NOW_PLAYING_CONTENT_CHANGED:
+        break;
+
+      default:
+        BTIF_TRACE_WARNING("%s: Unhandled event ID: 0x%x", __func__, event_id);
+        return BT_STATUS_UNHANDLED;
+    }
+
+    /* Send the response. */
+    send_metamsg_rsp(
+        &btif_rc_cb.rc_multi_cb[idx], -1,
+        btif_rc_cb.rc_multi_cb[idx].rc_notif[event_id - 1].label,
+        ((type == BTRC_NOTIFICATION_TYPE_INTERIM) ? AVRC_CMD_NOTIF
+                                                  : AVRC_RSP_CHANGED),
+        &avrc_rsp);
+
+    /* if notification type is address player changed, then complete all player
+    * specific
+    * notifications with AV/C C-Type REJECTED with error code Addressed Player
+    * Changed. */
+    if (event_id == BTRC_EVT_ADDR_PLAYER_CHANGE &&
+        type == BTRC_NOTIFICATION_TYPE_CHANGED) {
+      /* array includes notifications to be completed on addressed player change
+       */
+      btrc_event_id_t evt_id[] = {
+          BTRC_EVT_PLAY_STATUS_CHANGED, BTRC_EVT_TRACK_CHANGE,
+          BTRC_EVT_PLAY_POS_CHANGED, BTRC_EVT_NOW_PLAYING_CONTENT_CHANGED};
+      for (uint8_t id = 0; id < sizeof(evt_id) / sizeof((evt_id)[0]); id++) {
+        reject_pending_notification(evt_id[id], idx);
+      }
+    }
+  }
+  return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Function         get_folder_items_list_rsp
+ *
+ * Description      Returns the list of media items in current folder along with
+ *                  requested attributes. This is called in response to
+ *                  GetFolderItems request.
+ *
+ * Returns          bt_status_t
+ *                      BT_STATUS_NOT_READY - when RC is not connected.
+ *                      BT_STATUS_SUCCESS   - always if RC is connected
+ *                      BT_STATUS_UNHANDLED - when rsp is not pending for
+ *                                            get_folder_items_list PDU
+ *
+ **************************************************************************/
+static bt_status_t get_folder_items_list_rsp(bt_bdaddr_t* bd_addr,
+                                             btrc_status_t rsp_status,
+                                             uint16_t uid_counter,
+                                             uint8_t num_items,
+                                             btrc_folder_items_t* p_items) {
+  tAVRC_RESPONSE avrc_rsp;
+  tAVRC_ITEM item;
+  tBTA_AV_CODE code = 0, ctype = 0;
+  BT_HDR* p_msg = NULL;
+  int item_cnt;
+  tAVRC_STS status = AVRC_STS_NO_ERROR;
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+  btrc_folder_items_t* cur_item = NULL;
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  /* check if rsp to previous cmd was completed */
+  if (p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].is_rsp_pending == false) {
+    BTIF_TRACE_WARNING("%s: Not sending response as no PDU was registered",
+                       __func__);
+    return BT_STATUS_UNHANDLED;
+  }
+
+  memset(&avrc_rsp, 0, sizeof(tAVRC_RESPONSE));
+  memset(&item, 0, sizeof(tAVRC_ITEM));
+
+  avrc_rsp.get_items.pdu = AVRC_PDU_GET_FOLDER_ITEMS;
+  avrc_rsp.get_items.opcode = opcode_from_pdu(AVRC_PDU_GET_FOLDER_ITEMS);
+  avrc_rsp.get_items.status = status_code_map[rsp_status];
+
+  if (avrc_rsp.get_items.status != AVRC_STS_NO_ERROR) {
+    BTIF_TRACE_WARNING(
+        "%s: Error in parsing the received getfolderitems cmd. status: 0x%02x",
+        __func__, avrc_rsp.get_items.status);
+    status = avrc_rsp.get_items.status;
+  } else {
+    avrc_rsp.get_items.uid_counter = uid_counter;
+    avrc_rsp.get_items.item_count = 1;
+
+    /* create single item and build response iteratively for all num_items */
+    for (item_cnt = 0; item_cnt < num_items; item_cnt++) {
+      cur_item = &p_items[item_cnt];
+      item.item_type = p_items->item_type;
+      /* build respective item based on item_type. All items should be of same
+       * type within
+       * a response */
+      switch (p_items->item_type) {
+        case AVRC_ITEM_PLAYER: {
+          item.u.player.name.charset_id = cur_item->player.charset_id;
+          memcpy(&(item.u.player.features), &(cur_item->player.features),
+                 sizeof(cur_item->player.features));
+          item.u.player.major_type = cur_item->player.major_type;
+          item.u.player.sub_type = cur_item->player.sub_type;
+          item.u.player.play_status = cur_item->player.play_status;
+          item.u.player.player_id = cur_item->player.player_id;
+          item.u.player.name.p_str = cur_item->player.name;
+          item.u.player.name.str_len =
+              (uint16_t)strlen((char*)(cur_item->player.name));
+        } break;
+
+        case AVRC_ITEM_FOLDER: {
+          memcpy(item.u.folder.uid, cur_item->folder.uid, sizeof(tAVRC_UID));
+          item.u.folder.type = cur_item->folder.type;
+          item.u.folder.playable = cur_item->folder.playable;
+          item.u.folder.name.charset_id = AVRC_CHARSET_ID_UTF8;
+          item.u.folder.name.str_len = strlen((char*)cur_item->folder.name);
+          item.u.folder.name.p_str = cur_item->folder.name;
+        } break;
+
+        case AVRC_ITEM_MEDIA: {
+          tAVRC_ATTR_ENTRY attr_vals[BTRC_MAX_ELEM_ATTR_SIZE];
+
+          memcpy(item.u.media.uid, cur_item->media.uid, sizeof(tAVRC_UID));
+          item.u.media.type = cur_item->media.type;
+          item.u.media.name.charset_id = cur_item->media.charset_id;
+          item.u.media.name.str_len = strlen((char*)cur_item->media.name);
+          item.u.media.name.p_str = cur_item->media.name;
+          item.u.media.attr_count = cur_item->media.num_attrs;
+
+          /* Handle attributes of given item */
+          if (item.u.media.attr_count == 0) {
+            item.u.media.p_attr_list = NULL;
+          } else {
+            memset(&attr_vals, 0,
+                   sizeof(tAVRC_ATTR_ENTRY) * BTRC_MAX_ELEM_ATTR_SIZE);
+            fill_avrc_attr_entry(attr_vals, item.u.media.attr_count,
+                                 cur_item->media.p_attrs);
+            item.u.media.p_attr_list = attr_vals;
+          }
+        } break;
+
+        default: {
+          BTIF_TRACE_ERROR("%s: Unknown item_type: %d. Internal Error",
+                           __func__, p_items->item_type);
+          status = AVRC_STS_INTERNAL_ERR;
+        } break;
+      }
+
+      avrc_rsp.get_items.p_item_list = &item;
+
+      /* Add current item to buffer and build response if no error in item type
+       */
+      if (status != AVRC_STS_NO_ERROR) {
+        /* Reject response due to error occured for unknown item_type, break the
+         * loop */
+        break;
+      }
+
+      int len_before = p_msg ? p_msg->len : 0;
+      BTIF_TRACE_DEBUG("%s: item_cnt: %d len: %d", __func__, item_cnt,
+                       len_before);
+      status = AVRC_BldResponse(p_dev->rc_handle, &avrc_rsp, &p_msg);
+      BTIF_TRACE_DEBUG("%s: Build rsp status: %d len: %d", __func__, status,
+                       (p_msg ? p_msg->len : 0));
+      int len_after = p_msg ? p_msg->len : 0;
+      if (status != AVRC_STS_NO_ERROR || len_before == len_after) {
+        /* Error occured in build response or we ran out of buffer so break the
+         * loop */
+        break;
+      }
+    }
+
+    /* setting the error status */
+    avrc_rsp.get_items.status = status;
+  }
+
+  /* if packet built successfully, send the built items to BTA layer */
+  if (status == AVRC_STS_NO_ERROR) {
+    code = p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].ctype;
+    ctype = get_rsp_type_code(avrc_rsp.get_items.status, code);
+    BTA_AvMetaRsp(p_dev->rc_handle,
+                  p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].label, ctype,
+                  p_msg);
+  } else /* Error occured, send reject response */
+  {
+    BTIF_TRACE_ERROR("%s: Error status: 0x%02X. Sending reject rsp", __func__,
+                     avrc_rsp.rsp.status);
+    send_reject_response(
+        p_dev->rc_handle, p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].label,
+        avrc_rsp.pdu, avrc_rsp.get_items.status, avrc_rsp.get_items.opcode);
+  }
+
+  /* Reset values for current pdu. */
+  p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].ctype = 0;
+  p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].label = 0;
+  p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].is_rsp_pending = false;
+
+  return status == AVRC_STS_NO_ERROR ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/***************************************************************************
+ *
+ * Function         set_addressed_player_rsp
+ *
+ * Description      Response to set the addressed player for specified media
+ *                  player based on id in the media player list.
+ *
+ * Returns          bt_status_t
+ *                      BT_STATUS_NOT_READY - when RC is not connected.
+ *                      BT_STATUS_SUCCESS   - always if RC is connected
+ *
+ **************************************************************************/
+static bt_status_t set_addressed_player_rsp(bt_bdaddr_t* bd_addr,
+                                            btrc_status_t rsp_status) {
+  tAVRC_RESPONSE avrc_rsp;
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  avrc_rsp.addr_player.pdu = AVRC_PDU_SET_ADDRESSED_PLAYER;
+  avrc_rsp.addr_player.opcode = opcode_from_pdu(AVRC_PDU_SET_ADDRESSED_PLAYER);
+  avrc_rsp.addr_player.status = status_code_map[rsp_status];
+
+  /* Send the response. */
+  send_metamsg_rsp(p_dev, IDX_SET_ADDR_PLAYER_RSP,
+                   p_dev->rc_pdu_info[IDX_SET_ADDR_PLAYER_RSP].label,
+                   p_dev->rc_pdu_info[IDX_SET_ADDR_PLAYER_RSP].ctype,
+                   &avrc_rsp);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Function         set_browsed_player_rsp
+ *
+ * Description      Response to set the browsed player command which contains
+ *                  current browsed path of the media player. By default,
+ *                  current_path = root and folder_depth = 0 for
+ *                  every set_browsed_player request.
+ *
+ * Returns          bt_status_t
+ *                      BT_STATUS_NOT_READY - when RC is not connected.
+ *                      BT_STATUS_SUCCESS   - if RC is connected and reponse
+ *                                            sent successfully
+ *                      BT_STATUS_UNHANDLED - when rsp is not pending for
+ *                                            set_browsed_player PDU
+ *
+ **************************************************************************/
+static bt_status_t set_browsed_player_rsp(bt_bdaddr_t* bd_addr,
+                                          btrc_status_t rsp_status,
+                                          uint32_t num_items,
+                                          uint16_t charset_id,
+                                          uint8_t folder_depth,
+                                          btrc_br_folder_name_t* p_folders) {
+  tAVRC_RESPONSE avrc_rsp;
+  tAVRC_NAME item;
+  BT_HDR* p_msg = NULL;
+  tBTA_AV_CODE code = 0;
+  tBTA_AV_CODE ctype = 0;
+  unsigned int item_cnt;
+  tAVRC_STS status = AVRC_STS_NO_ERROR;
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  memset(&avrc_rsp, 0, sizeof(tAVRC_RESPONSE));
+  memset(&item, 0, sizeof(tAVRC_NAME));
+
+  avrc_rsp.br_player.status = status_code_map[rsp_status];
+  avrc_rsp.br_player.pdu = AVRC_PDU_SET_BROWSED_PLAYER;
+  avrc_rsp.br_player.opcode = opcode_from_pdu(AVRC_PDU_SET_BROWSED_PLAYER);
+
+  BTIF_TRACE_DEBUG("%s: rsp_status: 0x%02X avrc_rsp.br_player.status: 0x%02X",
+                   __func__, rsp_status, avrc_rsp.br_player.status);
+
+  /* check if rsp to previous cmd was completed */
+  if (p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].is_rsp_pending == false) {
+    BTIF_TRACE_WARNING("%s: Not sending response as no PDU was registered",
+                       __func__);
+    return BT_STATUS_UNHANDLED;
+  }
+
+  if (AVRC_STS_NO_ERROR == avrc_rsp.get_items.status) {
+    avrc_rsp.br_player.num_items = num_items;
+    avrc_rsp.br_player.charset_id = charset_id;
+    avrc_rsp.br_player.folder_depth = folder_depth;
+    avrc_rsp.br_player.p_folders = (tAVRC_NAME*)p_folders;
+
+    BTIF_TRACE_DEBUG("%s: folder_depth: 0x%02X num_items: %d", __func__,
+                     folder_depth, num_items);
+
+    if (folder_depth > 0) {
+      /* Iteratively build response for all folders across folder depth upto
+       * current path */
+      avrc_rsp.br_player.folder_depth = 1;
+      for (item_cnt = 0; item_cnt < folder_depth; item_cnt++) {
+        BTIF_TRACE_DEBUG("%s: iteration: %d", __func__, item_cnt);
+        item.str_len = p_folders[item_cnt].str_len;
+        item.p_str = p_folders[item_cnt].p_str;
+        avrc_rsp.br_player.p_folders = &item;
+
+        /* Add current item to buffer and build response */
+        status = AVRC_BldResponse(p_dev->rc_handle, &avrc_rsp, &p_msg);
+        if (AVRC_STS_NO_ERROR != status) {
+          BTIF_TRACE_WARNING("%s: Build rsp status: %d", __func__, status);
+          /* if the build fails, it is likely that we ran out of buffer. so if
+        * we have
+        * some items to send, reset this error to no error for sending what we
+        * have */
+          if (item_cnt > 0) status = AVRC_STS_NO_ERROR;
+
+          /* Error occured in build response so break the loop */
+          break;
+        }
+      }
+    } else /* current path is root folder, no folders navigated yet */
+    {
+      status = AVRC_BldResponse(p_dev->rc_handle, &avrc_rsp, &p_msg);
+    }
+
+    /* setting the error status */
+    avrc_rsp.br_player.status = status;
+  } else /* error received from above layer */
+  {
+    BTIF_TRACE_WARNING(
+        "%s: Error in parsing the received setbrowsed command. status: 0x%02x",
+        __func__, avrc_rsp.br_player.status);
+    status = avrc_rsp.br_player.status;
+  }
+
+  /* if packet built successfully, send the built items to BTA layer */
+  if (status == AVRC_STS_NO_ERROR) {
+    code = p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].ctype;
+    ctype = get_rsp_type_code(avrc_rsp.br_player.status, code);
+    BTA_AvMetaRsp(p_dev->rc_handle,
+                  p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].label, ctype,
+                  p_msg);
+  } else /* Error occured, send reject response */
+  {
+    BTIF_TRACE_ERROR("%s: Error status: 0x%02X. Sending reject rsp", __func__,
+                     avrc_rsp.br_player.status);
+    send_reject_response(
+        p_dev->rc_handle, p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].label,
+        avrc_rsp.pdu, avrc_rsp.br_player.status, avrc_rsp.get_items.opcode);
+  }
+
+  /* Reset values for set_browsed_player pdu.*/
+  p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].ctype = 0;
+  p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].label = 0;
+  p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].is_rsp_pending = false;
+
+  return status == AVRC_STS_NO_ERROR ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function         change_path_rsp
+ *
+ * Description      Response to the change path command which
+ *                  contains number of items in the changed path.
+ *
+ * Returns          bt_status_t
+ *                      BT_STATUS_NOT_READY - when RC is not connected.
+ *                      BT_STATUS_SUCCESS   - always if RC is connected
+ *
+ **************************************************************************/
+static bt_status_t change_path_rsp(bt_bdaddr_t* bd_addr,
+                                   btrc_status_t rsp_status,
+                                   uint32_t num_items) {
+  tAVRC_RESPONSE avrc_rsp;
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  avrc_rsp.chg_path.pdu = AVRC_PDU_CHANGE_PATH;
+  avrc_rsp.chg_path.opcode = opcode_from_pdu(AVRC_PDU_CHANGE_PATH);
+  avrc_rsp.chg_path.num_items = num_items;
+  avrc_rsp.chg_path.status = status_code_map[rsp_status];
+
+  /* Send the response. */
+  send_metamsg_rsp(p_dev, IDX_CHG_PATH_RSP,
+                   p_dev->rc_pdu_info[IDX_CHG_PATH_RSP].label,
+                   p_dev->rc_pdu_info[IDX_CHG_PATH_RSP].ctype, &avrc_rsp);
+
+  return BT_STATUS_SUCCESS;
+}
+#endif
+
+/***************************************************************************
+ *
+ * Function         search_rsp
+ *
+ * Description      Response to search a string from media content command.
+ *
+ * Returns          bt_status_t
+ *                      BT_STATUS_NOT_READY - when RC is not connected.
+ *                      BT_STATUS_SUCCESS   - always if RC is connected
+ *
+ **************************************************************************/
+static bt_status_t search_rsp(bt_bdaddr_t* bd_addr, btrc_status_t rsp_status,
+                              uint32_t uid_counter, uint32_t num_items) {
+  tAVRC_RESPONSE avrc_rsp;
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  avrc_rsp.search.pdu = AVRC_PDU_SEARCH;
+  avrc_rsp.search.opcode = opcode_from_pdu(AVRC_PDU_SEARCH);
+  avrc_rsp.search.num_items = num_items;
+  avrc_rsp.search.uid_counter = uid_counter;
+  avrc_rsp.search.status = status_code_map[rsp_status];
+
+  /* Send the response. */
+  send_metamsg_rsp(p_dev, IDX_SEARCH_RSP,
+                   p_dev->rc_pdu_info[IDX_SEARCH_RSP].label,
+                   p_dev->rc_pdu_info[IDX_SEARCH_RSP].ctype, &avrc_rsp);
+
+  return BT_STATUS_SUCCESS;
+}
+/***************************************************************************
+ *
+ * Function         get_item_attr_rsp
+ *
+ * Description      Response to the get item's attributes command which
+ *                  contains number of attributes and values list in text.
+ *
+ * Returns          bt_status_t
+ *                      BT_STATUS_NOT_READY - when RC is not connected.
+ *                      BT_STATUS_SUCCESS   - always if RC is connected
+ *
+ **************************************************************************/
+static bt_status_t get_item_attr_rsp(bt_bdaddr_t* bd_addr,
+                                     btrc_status_t rsp_status, uint8_t num_attr,
+                                     btrc_element_attr_val_t* p_attrs) {
+  tAVRC_RESPONSE avrc_rsp;
+  tAVRC_ATTR_ENTRY item_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  memset(item_attrs, 0, sizeof(tAVRC_ATTR_ENTRY) * num_attr);
+
+  if (num_attr == 0) {
+    avrc_rsp.get_attrs.status = AVRC_STS_INTERNAL_ERR;
+    BTIF_TRACE_ERROR("%s: num_attr in rsp is 0, sending internal error: 0x%02X",
+                     __func__, avrc_rsp.get_attrs.status);
+  } else {
+    avrc_rsp.get_attrs.status = status_code_map[rsp_status];
+    if (rsp_status == BTRC_STS_NO_ERROR) {
+      fill_avrc_attr_entry(item_attrs, num_attr, p_attrs);
+    }
+  }
+  avrc_rsp.get_attrs.attr_count = num_attr;
+  avrc_rsp.get_attrs.p_attr_list = item_attrs;
+  avrc_rsp.get_attrs.pdu = AVRC_PDU_GET_ITEM_ATTRIBUTES;
+  avrc_rsp.get_attrs.opcode = opcode_from_pdu(AVRC_PDU_GET_ITEM_ATTRIBUTES);
+
+  /* Send the response. */
+  send_metamsg_rsp(p_dev, IDX_GET_ITEM_ATTR_RSP,
+                   p_dev->rc_pdu_info[IDX_GET_ITEM_ATTR_RSP].label,
+                   p_dev->rc_pdu_info[IDX_GET_ITEM_ATTR_RSP].ctype, &avrc_rsp);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Function         add_to_now_playing_rsp
+ *
+ * Description      Response to command for adding speciafied media item
+ *                  to Now Playing queue.
+ *
+ * Returns          bt_status_t
+ *                      BT_STATUS_NOT_READY - when RC is not connected.
+ *                      BT_STATUS_SUCCESS   - always if RC is connected
+ *
+ **************************************************************************/
+static bt_status_t add_to_now_playing_rsp(bt_bdaddr_t* bd_addr,
+                                          btrc_status_t rsp_status) {
+  tAVRC_RESPONSE avrc_rsp;
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  avrc_rsp.add_to_play.pdu = AVRC_PDU_ADD_TO_NOW_PLAYING;
+  avrc_rsp.add_to_play.opcode = opcode_from_pdu(AVRC_PDU_ADD_TO_NOW_PLAYING);
+  avrc_rsp.add_to_play.status = status_code_map[rsp_status];
+
+  /* Send the response. */
+  send_metamsg_rsp(p_dev, IDX_ADD_TO_NOW_PLAYING_RSP,
+                   p_dev->rc_pdu_info[IDX_ADD_TO_NOW_PLAYING_RSP].label,
+                   p_dev->rc_pdu_info[IDX_ADD_TO_NOW_PLAYING_RSP].ctype,
+                   &avrc_rsp);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Function         play_item_rsp
+ *
+ * Description      Response to command for playing the specified media item.
+ *
+ * Returns          bt_status_t
+ *                      BT_STATUS_NOT_READY - when RC is not connected.
+ *                      BT_STATUS_SUCCESS   - always if RC is connected
+ *
+ **************************************************************************/
+static bt_status_t play_item_rsp(bt_bdaddr_t* bd_addr,
+                                 btrc_status_t rsp_status) {
+  tAVRC_RESPONSE avrc_rsp;
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  avrc_rsp.play_item.pdu = AVRC_PDU_PLAY_ITEM;
+  avrc_rsp.play_item.opcode = opcode_from_pdu(AVRC_PDU_PLAY_ITEM);
+  avrc_rsp.play_item.status = status_code_map[rsp_status];
+
+  /* Send the response. */
+  send_metamsg_rsp(p_dev, IDX_PLAY_ITEM_RSP,
+                   p_dev->rc_pdu_info[IDX_PLAY_ITEM_RSP].label,
+                   p_dev->rc_pdu_info[IDX_PLAY_ITEM_RSP].ctype, &avrc_rsp);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Function         get_total_num_of_items_rsp
+ *
+ * Description      response to command to get the Number of Items
+ *                  in the selected folder at the selected scope
+ *
+ * Returns          bt_status_t
+ *                      BT_STATUS_NOT_READY - when RC is not connected.
+ *                      BT_STATUS_SUCCESS   - always if RC is connected
+ *
+ **************************************************************************/
+static bt_status_t get_total_num_of_items_rsp(bt_bdaddr_t* bd_addr,
+                                              btrc_status_t rsp_status,
+                                              uint32_t uid_counter,
+                                              uint32_t num_items) {
+  tAVRC_RESPONSE avrc_rsp;
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  avrc_rsp.get_num_of_items.pdu = AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS;
+  avrc_rsp.get_num_of_items.opcode =
+      opcode_from_pdu(AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS);
+  avrc_rsp.get_num_of_items.num_items = num_items;
+  avrc_rsp.get_num_of_items.uid_counter = uid_counter;
+  avrc_rsp.get_num_of_items.status = status_code_map[rsp_status];
+
+  /* Send the response. */
+  send_metamsg_rsp(p_dev, IDX_GET_TOTAL_NUM_OF_ITEMS_RSP,
+                   p_dev->rc_pdu_info[IDX_GET_TOTAL_NUM_OF_ITEMS_RSP].label,
+                   p_dev->rc_pdu_info[IDX_GET_TOTAL_NUM_OF_ITEMS_RSP].ctype,
+                   &avrc_rsp);
+
+  return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Function         set_volume
+ *
+ * Description      Send current volume setting to remote side.
+ *                  Support limited to SetAbsoluteVolume
+ *                  This can be enhanced to support Relative Volume (AVRCP 1.0).
+ *                  With RelateVolume, we will send VOLUME_UP/VOLUME_DOWN
+ *                  as opposed to absolute volume level
+ * volume: Should be in the range 0-127. bit7 is reseved and cannot be set
+ *
+ * Returns          bt_status_t
+ *
+ **************************************************************************/
+static bt_status_t set_volume(uint8_t volume) {
+  BTIF_TRACE_DEBUG("%s: volume: %d", __func__, volume);
+  tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+  rc_transaction_t* p_transaction = NULL;
+
+  for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+    if (!btif_rc_cb.rc_multi_cb[idx].rc_connected) {
+      status = BT_STATUS_NOT_READY;
+      BTIF_TRACE_ERROR("%s: RC is not connected for device: 0x%x", __func__,
+                       btif_rc_cb.rc_multi_cb[idx].rc_addr);
+      continue;
+    }
+
+    if (btif_rc_cb.rc_multi_cb[idx].rc_volume == volume) {
+      status = BT_STATUS_DONE;
+      BTIF_TRACE_ERROR("%s: volume value already set earlier: 0x%02x", __func__,
+                       volume);
+      continue;
+    }
+
+    if ((btif_rc_cb.rc_multi_cb[idx].rc_volume != volume) &&
+        btif_rc_cb.rc_multi_cb[idx].rc_state ==
+            BTRC_CONNECTION_STATE_CONNECTED) {
+      if ((btif_rc_cb.rc_multi_cb[idx].rc_features & BTA_AV_FEAT_RCTG) == 0) {
+        status = BT_STATUS_NOT_READY;
+        continue;
+      } else {
+        tAVRC_COMMAND avrc_cmd = {0};
+        BT_HDR* p_msg = NULL;
+
+        if (btif_rc_cb.rc_multi_cb[idx].rc_features & BTA_AV_FEAT_ADV_CTRL) {
+          BTIF_TRACE_DEBUG("%s: Peer supports absolute volume. newVolume: %d",
+                           __func__, volume);
+          avrc_cmd.volume.opcode = AVRC_OP_VENDOR;
+          avrc_cmd.volume.pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME;
+          avrc_cmd.volume.status = AVRC_STS_NO_ERROR;
+          avrc_cmd.volume.volume = volume;
+
+          if (AVRC_BldCommand(&avrc_cmd, &p_msg) == AVRC_STS_NO_ERROR) {
+            bt_status_t tran_status = get_transaction(&p_transaction);
+
+            if (BT_STATUS_SUCCESS == tran_status && NULL != p_transaction) {
+              BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d",
+                               __func__, p_transaction->lbl);
+              BTA_AvMetaCmd(btif_rc_cb.rc_multi_cb[idx].rc_handle,
+                            p_transaction->lbl, AVRC_CMD_CTRL, p_msg);
+              status = BT_STATUS_SUCCESS;
+            } else {
+              osi_free_and_reset((void**)&p_msg);
+              BTIF_TRACE_ERROR(
+                  "%s: failed to obtain transaction details. status: 0x%02x",
+                  __func__, tran_status);
+              status = BT_STATUS_FAIL;
+            }
+          } else {
+            BTIF_TRACE_ERROR(
+                "%s: failed to build absolute volume command. status: 0x%02x",
+                __func__, status);
+            status = BT_STATUS_FAIL;
+          }
+        }
+      }
+    }
+  }
+  return (bt_status_t)status;
+}
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+/***************************************************************************
+ *
+ * Function         register_volumechange
+ *
+ * Description     Register for volume change notification from remote side.
+ *
+ * Returns          void
+ *
+ **************************************************************************/
+
+static void register_volumechange(uint8_t lbl, btif_rc_device_cb_t* p_dev) {
+  tAVRC_COMMAND avrc_cmd = {0};
+  BT_HDR* p_msg = NULL;
+  tAVRC_STS BldResp = AVRC_STS_BAD_CMD;
+  rc_transaction_t* p_transaction = NULL;
+
+  BTIF_TRACE_DEBUG("%s: label: %d", __func__, lbl);
+
+  avrc_cmd.cmd.opcode = 0x00;
+  avrc_cmd.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
+  avrc_cmd.reg_notif.event_id = AVRC_EVT_VOLUME_CHANGE;
+  avrc_cmd.reg_notif.status = AVRC_STS_NO_ERROR;
+  avrc_cmd.reg_notif.param = 0;
+
+  BldResp = AVRC_BldCommand(&avrc_cmd, &p_msg);
+  if (AVRC_STS_NO_ERROR == BldResp && p_msg) {
+    p_transaction = get_transaction_by_lbl(lbl);
+    if (p_transaction != NULL) {
+      BTA_AvMetaCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_NOTIF,
+                    p_msg);
+      BTIF_TRACE_DEBUG("%s: BTA_AvMetaCmd called", __func__);
+    } else {
+      osi_free(p_msg);
+      BTIF_TRACE_ERROR("%s: transaction not obtained with label: %d", __func__,
+                       lbl);
+    }
+  } else {
+    BTIF_TRACE_ERROR("%s: failed to build command: %d", __func__, BldResp);
+  }
+}
+
+/***************************************************************************
+ *
+ * Function         handle_rc_metamsg_rsp
+ *
+ * Description      Handle RC metamessage response
+ *
+ * Returns          void
+ *
+ **************************************************************************/
+static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg,
+                                  btif_rc_device_cb_t* p_dev) {
+  tAVRC_RESPONSE avrc_response = {0};
+  uint8_t scratch_buf[512] = {0};
+  tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+
+  BTIF_TRACE_DEBUG("%s: ", __func__);
+
+  if (AVRC_OP_VENDOR == pmeta_msg->p_msg->hdr.opcode &&
+      (AVRC_RSP_CHANGED == pmeta_msg->code ||
+       AVRC_RSP_INTERIM == pmeta_msg->code ||
+       AVRC_RSP_ACCEPT == pmeta_msg->code || AVRC_RSP_REJ == pmeta_msg->code ||
+       AVRC_RSP_NOT_IMPL == pmeta_msg->code)) {
+    status = AVRC_ParsResponse(pmeta_msg->p_msg, &avrc_response, scratch_buf,
+                               sizeof(scratch_buf));
+    BTIF_TRACE_DEBUG(
+        "%s: code:%d, event ID: %d, PDU: %x, parsing status: %d, label: %d",
+        __func__, pmeta_msg->code, avrc_response.reg_notif.event_id,
+        avrc_response.reg_notif.pdu, status, pmeta_msg->label);
+
+    if (status != AVRC_STS_NO_ERROR) {
+      if (AVRC_PDU_REGISTER_NOTIFICATION == avrc_response.rsp.pdu &&
+          AVRC_EVT_VOLUME_CHANGE == avrc_response.reg_notif.event_id &&
+          p_dev->rc_vol_label == pmeta_msg->label) {
+        p_dev->rc_vol_label = MAX_LABEL;
+        release_transaction(p_dev->rc_vol_label);
+      } else if (AVRC_PDU_SET_ABSOLUTE_VOLUME == avrc_response.rsp.pdu) {
+        release_transaction(pmeta_msg->label);
+      }
+      return;
+    }
+
+    if (AVRC_PDU_REGISTER_NOTIFICATION == avrc_response.rsp.pdu &&
+        AVRC_EVT_VOLUME_CHANGE == avrc_response.reg_notif.event_id &&
+        p_dev->rc_vol_label != pmeta_msg->label) {
+      // Just discard the message, if the device sends back with an incorrect
+      // label
+      BTIF_TRACE_DEBUG(
+          "%s: Discarding register notification in rsp.code: %d and label: %d",
+          __func__, pmeta_msg->code, pmeta_msg->label);
+      return;
+    }
+  } else {
+    BTIF_TRACE_DEBUG(
+        "%s: Received vendor dependent in adv ctrl rsp. code: %d len: %d. Not "
+        "processing it.",
+        __func__, pmeta_msg->code, pmeta_msg->len);
+    return;
+  }
+
+  if (AVRC_PDU_REGISTER_NOTIFICATION == avrc_response.rsp.pdu &&
+      AVRC_EVT_VOLUME_CHANGE == avrc_response.reg_notif.event_id &&
+      AVRC_RSP_CHANGED == pmeta_msg->code) {
+    /* re-register for volume change notification */
+    // Do not re-register for rejected case, as it might get into endless loop
+    register_volumechange(p_dev->rc_vol_label, p_dev);
+  } else if (AVRC_PDU_SET_ABSOLUTE_VOLUME == avrc_response.rsp.pdu) {
+    /* free up the label here */
+    release_transaction(pmeta_msg->label);
+  }
+
+  BTIF_TRACE_EVENT("%s: Passing received metamsg response to app. pdu: %s",
+                   __func__, dump_rc_pdu(avrc_response.pdu));
+  btif_rc_upstreams_rsp_evt((uint16_t)avrc_response.rsp.pdu, &avrc_response,
+                            pmeta_msg->code, pmeta_msg->label, p_dev);
+}
+#endif
+
+#if (AVRC_CTRL_INCLUDED == TRUE)
+/***************************************************************************
+ *
+ * Function         iterate_supported_event_list_for_interim_rsp
+ *
+ * Description      iterator callback function to match the event and handle
+ *                  timer cleanup
+ * Returns          true to continue iterating, false to stop
+ *
+ **************************************************************************/
+bool iterate_supported_event_list_for_interim_rsp(void* data, void* cb_data) {
+  uint8_t* p_event_id;
+  btif_rc_supported_event_t* p_event = (btif_rc_supported_event_t*)data;
+
+  p_event_id = (uint8_t*)cb_data;
+
+  if (p_event->event_id == *p_event_id) {
+    p_event->status = eINTERIM;
+    return false;
+  }
+  return true;
+}
+
+/***************************************************************************
+ *
+ * Function         iterate_supported_event_list_for_timeout
+ *
+ * Description      Iterator callback function for timeout handling.
+ *                  As part of the failure handling, it releases the
+ *                  transaction label and removes the event from list,
+ *                  this event will not be requested again during
+ *                  the lifetime of the connection.
+ * Returns          false to stop iterating, true to continue
+ *
+ **************************************************************************/
+bool iterate_supported_event_list_for_timeout(void* data, void* cb_data) {
+  bt_bdaddr_t bd_addr;
+  rc_context_t* cntxt = (rc_context_t*)cb_data;
+  uint8_t label = cntxt->label & 0xFF;
+  bdcpy(bd_addr.address, cntxt->rc_addr);
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(&bd_addr);
+  btif_rc_supported_event_t* p_event = (btif_rc_supported_event_t*)data;
+
+  if (p_event->label == label) {
+    list_remove(p_dev->rc_supported_event_list, p_event);
+    return false;
+  }
+  return true;
+}
+
+/***************************************************************************
+ *
+ * Function         rc_notification_interim_timout
+ *
+ * Description      Interim response timeout handler.
+ *                  Runs the iterator to check and clear the timed out event.
+ *                  Proceeds to register for the unregistered events.
+ * Returns          None
+ *
+ **************************************************************************/
+static void rc_notification_interim_timout(uint8_t label,
+                                           btif_rc_device_cb_t* p_dev) {
+  list_node_t* node;
+  rc_context_t cntxt;
+  memset(&cntxt, 0, sizeof(rc_context_t));
+  cntxt.label = label;
+  bdcpy(cntxt.rc_addr, p_dev->rc_addr);
+
+  list_foreach(p_dev->rc_supported_event_list,
+               iterate_supported_event_list_for_timeout, &cntxt);
+  /* Timeout happened for interim response for the registered event,
+   * check if there are any pending for registration
+   */
+  node = list_begin(p_dev->rc_supported_event_list);
+  while (node != NULL) {
+    btif_rc_supported_event_t* p_event;
+
+    p_event = (btif_rc_supported_event_t*)list_node(node);
+    if ((p_event != NULL) && (p_event->status == eNOT_REGISTERED)) {
+      register_for_event_notification(p_event, p_dev);
+      break;
+    }
+    node = list_next(node);
+  }
+  /* Todo. Need to initiate application settings query if this
+   * is the last event registration.
+   */
+}
+
+/***************************************************************************
+ *
+ * Function         btif_rc_status_cmd_timeout_handler
+ *
+ * Description      RC status command timeout handler (Runs in BTIF context).
+ * Returns          None
+ *
+ **************************************************************************/
+static void btif_rc_status_cmd_timeout_handler(UNUSED_ATTR uint16_t event,
+                                               char* data) {
+  btif_rc_timer_context_t* p_context;
+  tAVRC_RESPONSE avrc_response = {0};
+  tBTA_AV_META_MSG meta_msg;
+  btif_rc_device_cb_t* p_dev = NULL;
+  bt_bdaddr_t bd_addr;
+
+  p_context = (btif_rc_timer_context_t*)data;
+  bdcpy(bd_addr.address, p_context->rc_addr);
+  memset(&meta_msg, 0, sizeof(tBTA_AV_META_MSG));
+  p_dev = btif_rc_get_device_by_bda(&bd_addr);
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+    return;
+  }
+  meta_msg.rc_handle = p_dev->rc_handle;
+
+  switch (p_context->rc_status_cmd.pdu_id) {
+    case AVRC_PDU_REGISTER_NOTIFICATION:
+      rc_notification_interim_timout(p_context->rc_status_cmd.label, p_dev);
+      break;
+
+    case AVRC_PDU_GET_CAPABILITIES:
+      avrc_response.get_caps.status = BTIF_RC_STS_TIMEOUT;
+      handle_get_capability_response(&meta_msg, &avrc_response.get_caps);
+      break;
+
+    case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+      avrc_response.list_app_attr.status = BTIF_RC_STS_TIMEOUT;
+      handle_app_attr_response(&meta_msg, &avrc_response.list_app_attr);
+      break;
+
+    case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+      avrc_response.list_app_values.status = BTIF_RC_STS_TIMEOUT;
+      handle_app_val_response(&meta_msg, &avrc_response.list_app_values);
+      break;
+
+    case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+      avrc_response.get_cur_app_val.status = BTIF_RC_STS_TIMEOUT;
+      handle_app_cur_val_response(&meta_msg, &avrc_response.get_cur_app_val);
+      break;
+
+    case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+      avrc_response.get_app_attr_txt.status = BTIF_RC_STS_TIMEOUT;
+      handle_app_attr_txt_response(&meta_msg, &avrc_response.get_app_attr_txt);
+      break;
+
+    case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
+      avrc_response.get_app_val_txt.status = BTIF_RC_STS_TIMEOUT;
+      handle_app_attr_txt_response(&meta_msg, &avrc_response.get_app_val_txt);
+      break;
+
+    case AVRC_PDU_GET_ELEMENT_ATTR:
+      avrc_response.get_elem_attrs.status = BTIF_RC_STS_TIMEOUT;
+      handle_get_elem_attr_response(&meta_msg, &avrc_response.get_elem_attrs);
+      break;
+
+    case AVRC_PDU_GET_PLAY_STATUS:
+      avrc_response.get_play_status.status = BTIF_RC_STS_TIMEOUT;
+      handle_get_playstatus_response(&meta_msg, &avrc_response.get_play_status);
+      break;
+  }
+  release_transaction(p_context->rc_status_cmd.label);
+}
+
+/***************************************************************************
+ *
+ * Function         btif_rc_status_cmd_timer_timeout
+ *
+ * Description      RC status command timeout callback.
+ *                  This is called from BTU context and switches to BTIF
+ *                  context to handle the timeout events
+ * Returns          None
+ *
+ **************************************************************************/
+static void btif_rc_status_cmd_timer_timeout(void* data) {
+  btif_rc_timer_context_t* p_data = (btif_rc_timer_context_t*)data;
+
+  btif_transfer_context(btif_rc_status_cmd_timeout_handler, 0, (char*)p_data,
+                        sizeof(btif_rc_timer_context_t), NULL);
+}
+
+/***************************************************************************
+ *
+ * Function         btif_rc_control_cmd_timeout_handler
+ *
+ * Description      RC control command timeout handler (Runs in BTIF context).
+ * Returns          None
+ *
+ **************************************************************************/
+static void btif_rc_control_cmd_timeout_handler(UNUSED_ATTR uint16_t event,
+                                                char* data) {
+  btif_rc_timer_context_t* p_context = (btif_rc_timer_context_t*)data;
+  tAVRC_RESPONSE avrc_response = {0};
+  tBTA_AV_META_MSG meta_msg;
+  bt_bdaddr_t bd_addr;
+  bdcpy(bd_addr.address, p_context->rc_addr);
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(&bd_addr);
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+    return;
+  }
+
+  memset(&meta_msg, 0, sizeof(tBTA_AV_META_MSG));
+  meta_msg.rc_handle = p_dev->rc_handle;
+
+  switch (p_context->rc_control_cmd.pdu_id) {
+    case AVRC_PDU_SET_PLAYER_APP_VALUE:
+      avrc_response.set_app_val.status = BTIF_RC_STS_TIMEOUT;
+      handle_set_app_attr_val_response(&meta_msg, &avrc_response.set_app_val);
+      break;
+  }
+  release_transaction(p_context->rc_control_cmd.label);
+}
+
+/***************************************************************************
+ *
+ * Function         btif_rc_control_cmd_timer_timeout
+ *
+ * Description      RC control command timeout callback.
+ *                  This is called from BTU context and switches to BTIF
+ *                  context to handle the timeout events
+ * Returns          None
+ *
+ **************************************************************************/
+static void btif_rc_control_cmd_timer_timeout(void* data) {
+  btif_rc_timer_context_t* p_data = (btif_rc_timer_context_t*)data;
+
+  btif_transfer_context(btif_rc_control_cmd_timeout_handler, 0, (char*)p_data,
+                        sizeof(btif_rc_timer_context_t), NULL);
+}
+
+/***************************************************************************
+ *
+ * Function         btif_rc_play_status_timeout_handler
+ *
+ * Description      RC play status timeout handler (Runs in BTIF context).
+ * Returns          None
+ *
+ **************************************************************************/
+static void btif_rc_play_status_timeout_handler(UNUSED_ATTR uint16_t event,
+                                                char* p_data) {
+  uint8_t rc_handle = PTR_TO_UINT(p_data);
+  btif_rc_device_cb_t *p_dev = btif_rc_get_device_by_handle(rc_handle);
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR("%s timeout handler but no device found for handle %d",
+                     __func__, rc_handle);
+    return;
+  }
+  get_play_status_cmd(p_dev);
+  rc_start_play_status_timer(p_dev);
+}
+
+/***************************************************************************
+ *
+ * Function         btif_rc_play_status_timer_timeout
+ *
+ * Description      RC play status timeout callback.
+ *                  This is called from BTU context and switches to BTIF
+ *                  context to handle the timeout events
+ * Returns          None
+ *
+ **************************************************************************/
+static void btif_rc_play_status_timer_timeout(void* data) {
+  bt_bdaddr_t *rc_addr = (bt_bdaddr_t *) data;
+  btif_transfer_context(btif_rc_play_status_timeout_handler, 0,
+                        (char *)rc_addr, BD_ADDR_LEN, NULL);
+}
+
+/***************************************************************************
+ *
+ * Function         rc_start_play_status_timer
+ *
+ * Description      Helper function to start the timer to fetch play status.
+ * Returns          None
+ *
+ **************************************************************************/
+static void rc_start_play_status_timer(btif_rc_device_cb_t *p_dev) {
+  /* Start the Play status timer only if it is not started */
+  if (!alarm_is_scheduled(p_dev->rc_play_status_timer)) {
+    if (p_dev->rc_play_status_timer == NULL) {
+      p_dev->rc_play_status_timer = alarm_new("p_dev->rc_play_status_timer");
+    }
+    alarm_set_on_queue(
+        p_dev->rc_play_status_timer, BTIF_TIMEOUT_RC_INTERIM_RSP_MS,
+        btif_rc_play_status_timer_timeout, UINT_TO_PTR(p_dev->rc_handle),
+        btu_general_alarm_queue);
+  }
+}
+
+/***************************************************************************
+ *
+ * Function         rc_stop_play_status_timer
+ *
+ * Description      Helper function to stop the play status timer.
+ * Returns          None
+ *
+ **************************************************************************/
+void rc_stop_play_status_timer(btif_rc_device_cb_t* p_dev) {
+  alarm_cancel(p_dev->rc_play_status_timer);
+}
+
+/***************************************************************************
+ *
+ * Function         register_for_event_notification
+ *
+ * Description      Helper function registering notification events
+ *                  sets an interim response timeout to handle if the remote
+ *                  does not respond.
+ * Returns          None
+ *
+ **************************************************************************/
+static void register_for_event_notification(btif_rc_supported_event_t* p_event,
+                                            btif_rc_device_cb_t* p_dev) {
+  bt_status_t status;
+  rc_transaction_t* p_transaction;
+
+  status = get_transaction(&p_transaction);
+  if (status == BT_STATUS_SUCCESS) {
+    btif_rc_timer_context_t* p_context = &p_transaction->txn_timer_context;
+
+    status = register_notification_cmd(p_transaction->lbl, p_event->event_id, 0,
+                                       p_dev);
+    if (status != BT_STATUS_SUCCESS) {
+      BTIF_TRACE_ERROR("%s: Error in Notification registration: %d", __func__,
+                       status);
+      release_transaction(p_transaction->lbl);
+      return;
+    }
+    p_event->label = p_transaction->lbl;
+    p_event->status = eREGISTERED;
+    p_context->rc_status_cmd.label = p_transaction->lbl;
+    p_context->rc_status_cmd.pdu_id = AVRC_PDU_REGISTER_NOTIFICATION;
+    bdcpy(p_context->rc_addr, p_dev->rc_addr);
+
+    alarm_free(p_transaction->txn_timer);
+    p_transaction->txn_timer = alarm_new("btif_rc.status_command_txn_timer");
+    alarm_set_on_queue(p_transaction->txn_timer, BTIF_TIMEOUT_RC_INTERIM_RSP_MS,
+                       btif_rc_status_cmd_timer_timeout, p_context,
+                       btu_general_alarm_queue);
+  } else {
+    BTIF_TRACE_ERROR("%s: Error No more Transaction label: %d", __func__,
+                     status);
+  }
+}
+
+static void start_status_command_timer(uint8_t pdu_id, rc_transaction_t* p_txn,
+                                       btif_rc_device_cb_t* p_dev) {
+  btif_rc_timer_context_t* p_context = &p_txn->txn_timer_context;
+  p_context->rc_status_cmd.label = p_txn->lbl;
+  p_context->rc_status_cmd.pdu_id = pdu_id;
+  bdcpy(p_context->rc_addr, p_dev->rc_addr);
+
+  alarm_free(p_txn->txn_timer);
+  p_txn->txn_timer = alarm_new("btif_rc.status_command_txn_timer");
+  alarm_set_on_queue(p_txn->txn_timer, BTIF_TIMEOUT_RC_STATUS_CMD_MS,
+                     btif_rc_status_cmd_timer_timeout, p_context,
+                     btu_general_alarm_queue);
+}
+
+static void start_control_command_timer(uint8_t pdu_id, rc_transaction_t* p_txn,
+                                        btif_rc_device_cb_t* p_dev) {
+  btif_rc_timer_context_t* p_context = &p_txn->txn_timer_context;
+  p_context->rc_control_cmd.label = p_txn->lbl;
+  p_context->rc_control_cmd.pdu_id = pdu_id;
+  bdcpy(p_context->rc_addr, p_dev->rc_addr);
+
+  alarm_free(p_txn->txn_timer);
+  p_txn->txn_timer = alarm_new("btif_rc.control_command_txn_timer");
+  alarm_set_on_queue(p_txn->txn_timer, BTIF_TIMEOUT_RC_CONTROL_CMD_MS,
+                     btif_rc_control_cmd_timer_timeout, p_context,
+                     btu_general_alarm_queue);
+}
+
+/***************************************************************************
+ *
+ * Function         handle_get_capability_response
+ *
+ * Description      Handles the get_cap_response to populate company id info
+ *                  and query the supported events.
+ *                  Initiates Notification registration for events supported
+ * Returns          None
+ *
+ **************************************************************************/
+static void handle_get_capability_response(tBTA_AV_META_MSG* pmeta_msg,
+                                           tAVRC_GET_CAPS_RSP* p_rsp) {
+  int xx = 0;
+  btif_rc_device_cb_t* p_dev =
+      btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+  /* Todo: Do we need to retry on command timeout */
+  if (p_rsp->status != AVRC_STS_NO_ERROR) {
+    BTIF_TRACE_ERROR("%s: Error capability response: 0x%02X", __func__,
+                     p_rsp->status);
+    return;
+  }
+
+  if (p_rsp->capability_id == AVRC_CAP_EVENTS_SUPPORTED) {
+    btif_rc_supported_event_t* p_event;
+
+    /* Todo: Check if list can be active when we hit here */
+    p_dev->rc_supported_event_list = list_new(osi_free);
+    for (xx = 0; xx < p_rsp->count; xx++) {
+      /* Skip registering for Play position change notification */
+      if ((p_rsp->param.event_id[xx] == AVRC_EVT_PLAY_STATUS_CHANGE) ||
+          (p_rsp->param.event_id[xx] == AVRC_EVT_TRACK_CHANGE) ||
+          (p_rsp->param.event_id[xx] == AVRC_EVT_APP_SETTING_CHANGE)) {
+        p_event = (btif_rc_supported_event_t*)osi_malloc(
+            sizeof(btif_rc_supported_event_t));
+        p_event->event_id = p_rsp->param.event_id[xx];
+        p_event->status = eNOT_REGISTERED;
+        list_append(p_dev->rc_supported_event_list, p_event);
+      }
+    }
+    p_event =
+        (btif_rc_supported_event_t*)list_front(p_dev->rc_supported_event_list);
+    if (p_event != NULL) {
+      register_for_event_notification(p_event, p_dev);
+    }
+  } else if (p_rsp->capability_id == AVRC_CAP_COMPANY_ID) {
+    getcapabilities_cmd(AVRC_CAP_EVENTS_SUPPORTED, p_dev);
+    BTIF_TRACE_EVENT("%s: AVRC_CAP_COMPANY_ID: ", __func__);
+    for (xx = 0; xx < p_rsp->count; xx++) {
+      BTIF_TRACE_EVENT("%s: company_id: %d", __func__,
+                       p_rsp->param.company_id[xx]);
+    }
+  }
+}
+
+bool rc_is_track_id_valid(tAVRC_UID uid) {
+  tAVRC_UID invalid_uid = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+  if (memcmp(uid, invalid_uid, sizeof(tAVRC_UID)) == 0) {
+    return false;
+  } else {
+    return true;
+  }
+}
+
+/***************************************************************************
+ *
+ * Function         handle_notification_response
+ *
+ * Description      Main handler for notification responses to registered events
+ *                  1. Register for unregistered event(in interim response path)
+ *                  2. After registering for all supported events, start
+ *                     retrieving application settings and values
+ *                  3. Reregister for events on getting changed response
+ *                  4. Run play status timer for getting position when the
+ *                     status changes to playing
+ *                  5. Get the Media details when the track change happens
+ *                     or track change interim response is received with
+ *                     valid track id
+ *                  6. HAL callback for play status change and application
+ *                     setting change
+ * Returns          None
+ *
+ **************************************************************************/
+static void handle_notification_response(tBTA_AV_META_MSG* pmeta_msg,
+                                         tAVRC_REG_NOTIF_RSP* p_rsp) {
+  bt_bdaddr_t rc_addr;
+  btif_rc_device_cb_t* p_dev =
+      btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+  uint32_t attr_list[] = {
+      AVRC_MEDIA_ATTR_ID_TITLE,       AVRC_MEDIA_ATTR_ID_ARTIST,
+      AVRC_MEDIA_ATTR_ID_ALBUM,       AVRC_MEDIA_ATTR_ID_TRACK_NUM,
+      AVRC_MEDIA_ATTR_ID_NUM_TRACKS,  AVRC_MEDIA_ATTR_ID_GENRE,
+      AVRC_MEDIA_ATTR_ID_PLAYING_TIME};
+
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+    return;
+  }
+
+  bdcpy(rc_addr.address, p_dev->rc_addr);
+
+  if (pmeta_msg->code == AVRC_RSP_INTERIM) {
+    btif_rc_supported_event_t* p_event;
+    list_node_t* node;
+
+    BTIF_TRACE_DEBUG("%s: Interim response: 0x%2X ", __func__, p_rsp->event_id);
+    switch (p_rsp->event_id) {
+      case AVRC_EVT_PLAY_STATUS_CHANGE:
+        /* Start timer to get play status periodically
+         * if the play state is playing.
+         */
+        if (p_rsp->param.play_status == AVRC_PLAYSTATE_PLAYING) {
+          rc_start_play_status_timer(p_dev);
+        }
+        HAL_CBACK(bt_rc_ctrl_callbacks, play_status_changed_cb, &rc_addr,
+                  (btrc_play_status_t)p_rsp->param.play_status);
+        break;
+
+      case AVRC_EVT_TRACK_CHANGE:
+        if (rc_is_track_id_valid(p_rsp->param.track) != true) {
+          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);
+        }
+        break;
+
+      case AVRC_EVT_APP_SETTING_CHANGE:
+        break;
+
+      case AVRC_EVT_NOW_PLAYING_CHANGE:
+        break;
+
+      case AVRC_EVT_AVAL_PLAYERS_CHANGE:
+        break;
+
+      case AVRC_EVT_ADDR_PLAYER_CHANGE:
+        break;
+
+      case AVRC_EVT_UIDS_CHANGE:
+        break;
+
+      case AVRC_EVT_TRACK_REACHED_END:
+      case AVRC_EVT_TRACK_REACHED_START:
+      case AVRC_EVT_PLAY_POS_CHANGED:
+      case AVRC_EVT_BATTERY_STATUS_CHANGE:
+      case AVRC_EVT_SYSTEM_STATUS_CHANGE:
+      default:
+        BTIF_TRACE_ERROR("%s: Unhandled interim response: 0x%2X", __func__,
+                         p_rsp->event_id);
+        return;
+    }
+
+    list_foreach(p_dev->rc_supported_event_list,
+                 iterate_supported_event_list_for_interim_rsp,
+                 &p_rsp->event_id);
+
+    node = list_begin(p_dev->rc_supported_event_list);
+
+    while (node != NULL) {
+      p_event = (btif_rc_supported_event_t*)list_node(node);
+      if ((p_event != NULL) && (p_event->status == eNOT_REGISTERED)) {
+        register_for_event_notification(p_event, p_dev);
+        break;
+      }
+      node = list_next(node);
+      p_event = NULL;
+    }
+    /* Registered for all events, we can request application settings */
+    if (p_event == NULL && p_dev->rc_app_settings.query_started == false) {
+      /* we need to do this only if remote TG supports
+       * player application settings
+       */
+      p_dev->rc_app_settings.query_started = true;
+      if (p_dev->rc_features & BTA_AV_FEAT_APP_SETTING) {
+        list_player_app_setting_attrib_cmd(p_dev);
+      } else {
+        BTIF_TRACE_DEBUG("%s: App setting not supported, complete procedure",
+                         __func__);
+        rc_ctrl_procedure_complete(p_dev);
+      }
+    }
+  } else if (pmeta_msg->code == AVRC_RSP_CHANGED) {
+    btif_rc_supported_event_t* p_event;
+    list_node_t* node;
+
+    BTIF_TRACE_DEBUG("%s: Notification completed: 0x%2X ", __func__,
+                     p_rsp->event_id);
+
+    node = list_begin(p_dev->rc_supported_event_list);
+
+    while (node != NULL) {
+      p_event = (btif_rc_supported_event_t*)list_node(node);
+      if (p_event != NULL && p_event->event_id == p_rsp->event_id) {
+        p_event->status = eNOT_REGISTERED;
+        register_for_event_notification(p_event, p_dev);
+        break;
+      }
+      node = list_next(node);
+    }
+
+    switch (p_rsp->event_id) {
+      case AVRC_EVT_PLAY_STATUS_CHANGE:
+        /* Start timer to get play status periodically
+         * if the play state is playing.
+         */
+        if (p_rsp->param.play_status == AVRC_PLAYSTATE_PLAYING) {
+          rc_start_play_status_timer(p_dev);
+        } else {
+          rc_stop_play_status_timer(p_dev);
+        }
+        HAL_CBACK(bt_rc_ctrl_callbacks, play_status_changed_cb, &rc_addr,
+                  (btrc_play_status_t)p_rsp->param.play_status);
+
+        break;
+
+      case AVRC_EVT_TRACK_CHANGE:
+        if (rc_is_track_id_valid(p_rsp->param.track) != true) {
+          break;
+        }
+        get_element_attribute_cmd(AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list, p_dev);
+        break;
+
+      case AVRC_EVT_APP_SETTING_CHANGE: {
+        btrc_player_settings_t app_settings;
+        uint16_t xx;
+
+        app_settings.num_attr = p_rsp->param.player_setting.num_attr;
+        for (xx = 0; xx < app_settings.num_attr; xx++) {
+          app_settings.attr_ids[xx] = p_rsp->param.player_setting.attr_id[xx];
+          app_settings.attr_values[xx] =
+              p_rsp->param.player_setting.attr_value[xx];
+        }
+        HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_changed_cb,
+                  &rc_addr, &app_settings);
+      } break;
+
+      case AVRC_EVT_NOW_PLAYING_CHANGE:
+        break;
+
+      case AVRC_EVT_AVAL_PLAYERS_CHANGE:
+        break;
+
+      case AVRC_EVT_ADDR_PLAYER_CHANGE:
+        break;
+
+      case AVRC_EVT_UIDS_CHANGE:
+        break;
+
+      case AVRC_EVT_TRACK_REACHED_END:
+      case AVRC_EVT_TRACK_REACHED_START:
+      case AVRC_EVT_PLAY_POS_CHANGED:
+      case AVRC_EVT_BATTERY_STATUS_CHANGE:
+      case AVRC_EVT_SYSTEM_STATUS_CHANGE:
+      default:
+        BTIF_TRACE_ERROR("%s: Unhandled completion response: 0x%2X", __func__,
+                         p_rsp->event_id);
+        return;
+    }
+  }
+}
+
+/***************************************************************************
+ *
+ * Function         handle_app_attr_response
+ *
+ * Description      handles the the application attributes response and
+ *                  initiates procedure to fetch the attribute values
+ * Returns          None
+ *
+ **************************************************************************/
+static void handle_app_attr_response(tBTA_AV_META_MSG* pmeta_msg,
+                                     tAVRC_LIST_APP_ATTR_RSP* p_rsp) {
+  uint8_t xx;
+  btif_rc_device_cb_t* p_dev =
+      btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+  if (p_dev == NULL || p_rsp->status != AVRC_STS_NO_ERROR) {
+    BTIF_TRACE_ERROR("%s: Error getting Player application settings: 0x%2X",
+                     __func__, p_rsp->status);
+    rc_ctrl_procedure_complete(p_dev);
+    return;
+  }
+
+  for (xx = 0; xx < p_rsp->num_attr; xx++) {
+    uint8_t st_index;
+
+    if (p_rsp->attrs[xx] > AVRC_PLAYER_SETTING_LOW_MENU_EXT) {
+      st_index = p_dev->rc_app_settings.num_ext_attrs;
+      p_dev->rc_app_settings.ext_attrs[st_index].attr_id = p_rsp->attrs[xx];
+      p_dev->rc_app_settings.num_ext_attrs++;
+    } else {
+      st_index = p_dev->rc_app_settings.num_attrs;
+      p_dev->rc_app_settings.attrs[st_index].attr_id = p_rsp->attrs[xx];
+      p_dev->rc_app_settings.num_attrs++;
+    }
+  }
+  p_dev->rc_app_settings.attr_index = 0;
+  p_dev->rc_app_settings.ext_attr_index = 0;
+  p_dev->rc_app_settings.ext_val_index = 0;
+  if (p_rsp->num_attr) {
+    list_player_app_setting_value_cmd(p_dev->rc_app_settings.attrs[0].attr_id,
+                                      p_dev);
+  } else {
+    BTIF_TRACE_ERROR("%s: No Player application settings found", __func__);
+  }
+}
+
+/***************************************************************************
+ *
+ * Function         handle_app_val_response
+ *
+ * Description      handles the the attributes value response and if extended
+ *                  menu is available, it initiates query for the attribute
+ *                  text. If not, it initiates procedure to get the current
+ *                  attribute values and calls the HAL callback for provding
+ *                  application settings information.
+ * Returns          None
+ *
+ **************************************************************************/
+static void handle_app_val_response(tBTA_AV_META_MSG* pmeta_msg,
+                                    tAVRC_LIST_APP_VALUES_RSP* p_rsp) {
+  uint8_t xx, attr_index;
+  uint8_t attrs[AVRC_MAX_APP_ATTR_SIZE];
+  btif_rc_player_app_settings_t* p_app_settings;
+  bt_bdaddr_t rc_addr;
+  btif_rc_device_cb_t* p_dev =
+      btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+  /* Todo: Do we need to retry on command timeout */
+  if (p_dev == NULL || p_rsp->status != AVRC_STS_NO_ERROR) {
+    BTIF_TRACE_ERROR("%s: Error fetching attribute values: 0x%02X", __func__,
+                     p_rsp->status);
+    return;
+  }
+
+  p_app_settings = &p_dev->rc_app_settings;
+  bdcpy(rc_addr.address, p_dev->rc_addr);
+
+  if (p_app_settings->attr_index < p_app_settings->num_attrs) {
+    attr_index = p_app_settings->attr_index;
+    p_app_settings->attrs[attr_index].num_val = p_rsp->num_val;
+    for (xx = 0; xx < p_rsp->num_val; xx++) {
+      p_app_settings->attrs[attr_index].attr_val[xx] = p_rsp->vals[xx];
+    }
+    attr_index++;
+    p_app_settings->attr_index++;
+    if (attr_index < p_app_settings->num_attrs) {
+      list_player_app_setting_value_cmd(
+          p_app_settings->attrs[p_app_settings->attr_index].attr_id, p_dev);
+    } else if (p_app_settings->ext_attr_index < p_app_settings->num_ext_attrs) {
+      attr_index = 0;
+      p_app_settings->ext_attr_index = 0;
+      list_player_app_setting_value_cmd(
+          p_app_settings->ext_attrs[attr_index].attr_id, p_dev);
+    } else {
+      for (xx = 0; xx < p_app_settings->num_attrs; xx++) {
+        attrs[xx] = p_app_settings->attrs[xx].attr_id;
+      }
+      get_player_app_setting_cmd(p_app_settings->num_attrs, attrs, p_dev);
+      HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
+                p_app_settings->num_attrs, p_app_settings->attrs, 0, NULL);
+    }
+  } else if (p_app_settings->ext_attr_index < p_app_settings->num_ext_attrs) {
+    attr_index = p_app_settings->ext_attr_index;
+    p_app_settings->ext_attrs[attr_index].num_val = p_rsp->num_val;
+    for (xx = 0; xx < p_rsp->num_val; xx++) {
+      p_app_settings->ext_attrs[attr_index].ext_attr_val[xx].val =
+          p_rsp->vals[xx];
+    }
+    attr_index++;
+    p_app_settings->ext_attr_index++;
+    if (attr_index < p_app_settings->num_ext_attrs) {
+      list_player_app_setting_value_cmd(
+          p_app_settings->ext_attrs[p_app_settings->ext_attr_index].attr_id,
+          p_dev);
+    } else {
+      uint8_t attr[AVRC_MAX_APP_ATTR_SIZE];
+
+      for (uint8_t xx = 0; xx < p_app_settings->num_ext_attrs; xx++) {
+        attr[xx] = p_app_settings->ext_attrs[xx].attr_id;
+      }
+      get_player_app_setting_attr_text_cmd(attr, p_app_settings->num_ext_attrs,
+                                           p_dev);
+    }
+  }
+}
+
+/***************************************************************************
+ *
+ * Function         handle_app_cur_val_response
+ *
+ * Description      handles the the get attributes value response.
+ *
+ * Returns          None
+ *
+ **************************************************************************/
+static void handle_app_cur_val_response(tBTA_AV_META_MSG* pmeta_msg,
+                                        tAVRC_GET_CUR_APP_VALUE_RSP* p_rsp) {
+  btrc_player_settings_t app_settings;
+  bt_bdaddr_t rc_addr;
+  uint16_t xx;
+  btif_rc_device_cb_t* p_dev = NULL;
+
+  /* Todo: Do we need to retry on command timeout */
+  if (p_rsp->status != AVRC_STS_NO_ERROR) {
+    BTIF_TRACE_ERROR("%s: Error fetching current settings: 0x%02X", __func__,
+                     p_rsp->status);
+    return;
+  }
+  p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR("%s: Error in getting Device Address", __func__);
+    osi_free_and_reset((void**)&p_rsp->p_vals);
+    return;
+  }
+
+  bdcpy(rc_addr.address, p_dev->rc_addr);
+
+  app_settings.num_attr = p_rsp->num_val;
+  for (xx = 0; xx < app_settings.num_attr; xx++) {
+    app_settings.attr_ids[xx] = p_rsp->p_vals[xx].attr_id;
+    app_settings.attr_values[xx] = p_rsp->p_vals[xx].attr_val;
+  }
+
+  HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_changed_cb, &rc_addr,
+            &app_settings);
+  /* Application settings are fetched only once for initial values
+   * initiate anything that follows after RC procedure.
+   * Defer it if browsing is supported till players query
+   */
+  rc_ctrl_procedure_complete(p_dev);
+  osi_free_and_reset((void**)&p_rsp->p_vals);
+}
+
+/***************************************************************************
+ *
+ * Function         handle_app_attr_txt_response
+ *
+ * Description      handles the the get attributes text response, if fails
+ *                  calls HAL callback with just normal settings and initiates
+ *                  query for current settings else initiates query for value
+ *                  text
+ * Returns          None
+ *
+ **************************************************************************/
+static void handle_app_attr_txt_response(tBTA_AV_META_MSG* pmeta_msg,
+                                         tAVRC_GET_APP_ATTR_TXT_RSP* p_rsp) {
+  uint8_t xx;
+  uint8_t vals[AVRC_MAX_APP_ATTR_SIZE];
+  btif_rc_player_app_settings_t* p_app_settings;
+  bt_bdaddr_t rc_addr;
+  btif_rc_device_cb_t* p_dev =
+      btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+    return;
+  }
+
+  bdcpy(rc_addr.address, p_dev->rc_addr);
+  p_app_settings = &p_dev->rc_app_settings;
+
+  /* Todo: Do we need to retry on command timeout */
+  if (p_rsp->status != AVRC_STS_NO_ERROR) {
+    uint8_t attrs[AVRC_MAX_APP_ATTR_SIZE];
+
+    BTIF_TRACE_ERROR("%s: Error fetching attribute text: 0x%02X", __func__,
+                     p_rsp->status);
+    /* Not able to fetch Text for extended Menu, skip the process
+     * and cleanup used memory. Proceed to get the current settings
+     * for standard attributes.
+     */
+    p_app_settings->num_ext_attrs = 0;
+    for (xx = 0; xx < p_app_settings->ext_attr_index; xx++) {
+      osi_free_and_reset((void**)&p_app_settings->ext_attrs[xx].p_str);
+    }
+    p_app_settings->ext_attr_index = 0;
+
+    if (p_dev) {
+      for (xx = 0; xx < p_app_settings->num_attrs; xx++) {
+        attrs[xx] = p_app_settings->attrs[xx].attr_id;
+      }
+
+      HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
+                p_app_settings->num_attrs, p_app_settings->attrs, 0, NULL);
+      get_player_app_setting_cmd(xx, attrs, p_dev);
+    }
+    return;
+  }
+
+  for (xx = 0; xx < p_rsp->num_attr; xx++) {
+    uint8_t x;
+    for (x = 0; x < p_app_settings->num_ext_attrs; x++) {
+      if (p_app_settings->ext_attrs[x].attr_id == p_rsp->p_attrs[xx].attr_id) {
+        p_app_settings->ext_attrs[x].charset_id = p_rsp->p_attrs[xx].charset_id;
+        p_app_settings->ext_attrs[x].str_len = p_rsp->p_attrs[xx].str_len;
+        p_app_settings->ext_attrs[x].p_str = p_rsp->p_attrs[xx].p_str;
+        break;
+      }
+    }
+  }
+
+  for (xx = 0; xx < p_app_settings->ext_attrs[0].num_val; xx++) {
+    vals[xx] = p_app_settings->ext_attrs[0].ext_attr_val[xx].val;
+  }
+  get_player_app_setting_value_text_cmd(vals, xx, p_dev);
+}
+
+/***************************************************************************
+ *
+ * Function         handle_app_attr_val_txt_response
+ *
+ * Description      handles the the get attributes value text response, if fails
+ *                  calls HAL callback with just normal settings and initiates
+ *                  query for current settings
+ * Returns          None
+ *
+ **************************************************************************/
+static void handle_app_attr_val_txt_response(
+    tBTA_AV_META_MSG* pmeta_msg, tAVRC_GET_APP_ATTR_TXT_RSP* p_rsp) {
+  uint8_t xx, attr_index;
+  uint8_t vals[AVRC_MAX_APP_ATTR_SIZE];
+  uint8_t attrs[AVRC_MAX_APP_ATTR_SIZE];
+  btif_rc_player_app_settings_t* p_app_settings;
+  bt_bdaddr_t rc_addr;
+  btif_rc_device_cb_t* p_dev =
+      btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+    return;
+  }
+
+  bdcpy(rc_addr.address, p_dev->rc_addr);
+  p_app_settings = &p_dev->rc_app_settings;
+
+  /* Todo: Do we need to retry on command timeout */
+  if (p_rsp->status != AVRC_STS_NO_ERROR) {
+    uint8_t attrs[AVRC_MAX_APP_ATTR_SIZE];
+
+    BTIF_TRACE_ERROR("%s: Error fetching attribute value text: 0x%02X",
+                     __func__, p_rsp->status);
+
+    /* Not able to fetch Text for extended Menu, skip the process
+     * and cleanup used memory. Proceed to get the current settings
+     * for standard attributes.
+     */
+    p_app_settings->num_ext_attrs = 0;
+    for (xx = 0; xx < p_app_settings->ext_attr_index; xx++) {
+      int x;
+      btrc_player_app_ext_attr_t* p_ext_attr = &p_app_settings->ext_attrs[xx];
+
+      for (x = 0; x < p_ext_attr->num_val; x++)
+        osi_free_and_reset((void**)&p_ext_attr->ext_attr_val[x].p_str);
+      p_ext_attr->num_val = 0;
+      osi_free_and_reset((void**)&p_app_settings->ext_attrs[xx].p_str);
+    }
+    p_app_settings->ext_attr_index = 0;
+
+    for (xx = 0; xx < p_app_settings->num_attrs; xx++) {
+      attrs[xx] = p_app_settings->attrs[xx].attr_id;
+    }
+    HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
+              p_app_settings->num_attrs, p_app_settings->attrs, 0, NULL);
+
+    get_player_app_setting_cmd(xx, attrs, p_dev);
+    return;
+  }
+
+  for (xx = 0; xx < p_rsp->num_attr; xx++) {
+    uint8_t x;
+    btrc_player_app_ext_attr_t* p_ext_attr;
+    p_ext_attr = &p_app_settings->ext_attrs[p_app_settings->ext_val_index];
+    for (x = 0; x < p_rsp->num_attr; x++) {
+      if (p_ext_attr->ext_attr_val[x].val == p_rsp->p_attrs[xx].attr_id) {
+        p_ext_attr->ext_attr_val[x].charset_id = p_rsp->p_attrs[xx].charset_id;
+        p_ext_attr->ext_attr_val[x].str_len = p_rsp->p_attrs[xx].str_len;
+        p_ext_attr->ext_attr_val[x].p_str = p_rsp->p_attrs[xx].p_str;
+        break;
+      }
+    }
+  }
+  p_app_settings->ext_val_index++;
+
+  if (p_app_settings->ext_val_index < p_app_settings->num_ext_attrs) {
+    attr_index = p_app_settings->ext_val_index;
+    for (xx = 0; xx < p_app_settings->ext_attrs[attr_index].num_val; xx++) {
+      vals[xx] = p_app_settings->ext_attrs[attr_index].ext_attr_val[xx].val;
+    }
+    get_player_app_setting_value_text_cmd(vals, xx, p_dev);
+  } else {
+    uint8_t x;
+
+    for (xx = 0; xx < p_app_settings->num_attrs; xx++) {
+      attrs[xx] = p_app_settings->attrs[xx].attr_id;
+    }
+    for (x = 0; x < p_app_settings->num_ext_attrs; x++) {
+      attrs[xx + x] = p_app_settings->ext_attrs[x].attr_id;
+    }
+    HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
+              p_app_settings->num_attrs, p_app_settings->attrs,
+              p_app_settings->num_ext_attrs, p_app_settings->ext_attrs);
+    get_player_app_setting_cmd(xx + x, attrs, p_dev);
+
+    /* Free the application settings information after sending to
+     * application.
+     */
+    for (xx = 0; xx < p_app_settings->ext_attr_index; xx++) {
+      int x;
+      btrc_player_app_ext_attr_t* p_ext_attr = &p_app_settings->ext_attrs[xx];
+
+      for (x = 0; x < p_ext_attr->num_val; x++)
+        osi_free_and_reset((void**)&p_ext_attr->ext_attr_val[x].p_str);
+      p_ext_attr->num_val = 0;
+      osi_free_and_reset((void**)&p_app_settings->ext_attrs[xx].p_str);
+    }
+    p_app_settings->num_attrs = 0;
+  }
+}
+
+/***************************************************************************
+ *
+ * Function         handle_set_app_attr_val_response
+ *
+ * Description      handles the the set attributes value response, if fails
+ *                  calls HAL callback to indicate the failure
+ * Returns          None
+ *
+ **************************************************************************/
+static void handle_set_app_attr_val_response(tBTA_AV_META_MSG* pmeta_msg,
+                                             tAVRC_RSP* p_rsp) {
+  uint8_t accepted = 0;
+  bt_bdaddr_t rc_addr;
+  btif_rc_device_cb_t* p_dev =
+      btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+    return;
+  }
+
+  bdcpy(rc_addr.address, p_dev->rc_addr);
+
+  /* For timeout pmeta_msg will be NULL, else we need to
+   * check if this is accepted by TG
+   */
+  if (pmeta_msg && (pmeta_msg->code == AVRC_RSP_ACCEPT)) {
+    accepted = 1;
+  }
+  HAL_CBACK(bt_rc_ctrl_callbacks, setplayerappsetting_rsp_cb, &rc_addr,
+            accepted);
+}
+
+/***************************************************************************
+ *
+ * Function         handle_get_elem_attr_response
+ *
+ * Description      handles the the element attributes response, calls
+ *                  HAL callback to update track change information.
+ * Returns          None
+ *
+ **************************************************************************/
+static void handle_get_elem_attr_response(tBTA_AV_META_MSG* pmeta_msg,
+                                          tAVRC_GET_ELEM_ATTRS_RSP* p_rsp) {
+  btif_rc_device_cb_t* p_dev =
+      btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+  if (p_rsp->status == AVRC_STS_NO_ERROR) {
+    bt_bdaddr_t rc_addr;
+    size_t buf_size = p_rsp->num_attr * sizeof(btrc_element_attr_val_t);
+    btrc_element_attr_val_t* p_attr =
+        (btrc_element_attr_val_t*)osi_calloc(buf_size);
+
+    if (p_dev == NULL) {
+      BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+      return;
+    }
+
+    bdcpy(rc_addr.address, p_dev->rc_addr);
+
+    for (int i = 0; i < p_rsp->num_attr; i++) {
+      p_attr[i].attr_id = p_rsp->p_attrs[i].attr_id;
+      /* Todo. Legth limit check to include null */
+      if (p_rsp->p_attrs[i].name.str_len && p_rsp->p_attrs[i].name.p_str) {
+        memcpy(p_attr[i].text, p_rsp->p_attrs[i].name.p_str,
+               p_rsp->p_attrs[i].name.str_len);
+        osi_free_and_reset((void**)&p_rsp->p_attrs[i].name.p_str);
+      }
+    }
+    HAL_CBACK(bt_rc_ctrl_callbacks, track_changed_cb, &rc_addr, p_rsp->num_attr,
+              p_attr);
+    osi_free(p_attr);
+  } else if (p_rsp->status == BTIF_RC_STS_TIMEOUT) {
+    /* Retry for timeout case, this covers error handling
+     * for continuation failure also.
+     */
+    uint32_t attr_list[] = {
+        AVRC_MEDIA_ATTR_ID_TITLE,       AVRC_MEDIA_ATTR_ID_ARTIST,
+        AVRC_MEDIA_ATTR_ID_ALBUM,       AVRC_MEDIA_ATTR_ID_TRACK_NUM,
+        AVRC_MEDIA_ATTR_ID_NUM_TRACKS,  AVRC_MEDIA_ATTR_ID_GENRE,
+        AVRC_MEDIA_ATTR_ID_PLAYING_TIME};
+    get_element_attribute_cmd(AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list, p_dev);
+  } else {
+    BTIF_TRACE_ERROR("%s: Error in get element attr procedure: %d", __func__,
+                     p_rsp->status);
+  }
+}
+
+/***************************************************************************
+ *
+ * Function         handle_get_playstatus_response
+ *
+ * Description      handles the the play status response, calls
+ *                  HAL callback to update play position.
+ * Returns          None
+ *
+ **************************************************************************/
+static void handle_get_playstatus_response(tBTA_AV_META_MSG* pmeta_msg,
+                                           tAVRC_GET_PLAY_STATUS_RSP* p_rsp) {
+  bt_bdaddr_t rc_addr;
+
+  btif_rc_device_cb_t* p_dev =
+      btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+    return;
+  }
+
+  bdcpy(rc_addr.address, p_dev->rc_addr);
+
+  if (p_rsp->status == AVRC_STS_NO_ERROR) {
+    HAL_CBACK(bt_rc_ctrl_callbacks, play_position_changed_cb, &rc_addr,
+              p_rsp->song_len, p_rsp->song_pos);
+  } else {
+    BTIF_TRACE_ERROR("%s: Error in get play status procedure: %d", __func__,
+                     p_rsp->status);
+  }
+}
+
+/***************************************************************************
+**
+** Function         handle_set_addressed_player_response
+**
+** Description      handles the the set addressed player response, calls
+**                  HAL callback
+** Returns          None
+**
+***************************************************************************/
+static void handle_set_addressed_player_response(tBTA_AV_META_MSG *pmeta_msg,
+                                                 tAVRC_RSP *p_rsp) {
+  bt_bdaddr_t rc_addr;
+
+  btif_rc_device_cb_t* p_dev =
+      btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+  if (p_dev == NULL) {
+    BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+    return;
+  }
+
+  bdcpy(rc_addr.address, p_dev->rc_addr);
+
+  if (p_rsp->status == AVRC_STS_NO_ERROR) {
+    HAL_CBACK(bt_rc_ctrl_callbacks,
+              set_addressed_player_cb,
+              &rc_addr,
+              p_rsp->status);
+  } else {
+    BTIF_TRACE_ERROR("%s: Error in get play status procedure %d",
+                     __FUNCTION__, p_rsp->status);
+  }
+}
+
+/***************************************************************************
+ *
+ * Function         handle_get_folder_items_response
+ *
+ * Description      handles the the get folder items response, calls
+ *                  HAL callback to send the folder items.
+ * Returns          None
+ *
+ **************************************************************************/
+static void handle_get_folder_items_response(tBTA_AV_META_MSG* pmeta_msg,
+                                             tAVRC_GET_ITEMS_RSP* p_rsp) {
+  btif_rc_device_cb_t* p_dev =
+      btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+  bt_bdaddr_t rc_addr;
+  bdcpy(rc_addr.address, p_dev->rc_addr);
+
+  if (p_rsp->status == AVRC_STS_NO_ERROR) {
+    /* Convert the internal folder listing into a response that can
+     * be passed onto JNI via HAL_CBACK
+     */
+    uint8_t item_count = p_rsp->item_count;
+    btrc_folder_items_t* btrc_items = (btrc_folder_items_t*)osi_malloc(
+        sizeof(btrc_folder_items_t) * item_count);
+    for (uint8_t i = 0; i < item_count; i++) {
+      const tAVRC_ITEM* avrc_item = &(p_rsp->p_item_list[i]);
+      btrc_folder_items_t* btrc_item = &(btrc_items[i]);
+      BTIF_TRACE_DEBUG("%s folder item type %d", __func__,
+                       avrc_item->item_type);
+      switch (avrc_item->item_type) {
+        case AVRC_ITEM_MEDIA:
+          BTIF_TRACE_DEBUG("%s setting type to %d", __func__, BTRC_ITEM_MEDIA);
+          get_folder_item_type_media(avrc_item, btrc_item);
+          break;
+
+        case AVRC_ITEM_FOLDER:
+          BTIF_TRACE_DEBUG("%s setting type to BTRC_ITEM_FOLDER", __func__);
+          get_folder_item_type_folder(avrc_item, btrc_item);
+          break;
+
+        case AVRC_ITEM_PLAYER:
+          BTIF_TRACE_DEBUG("%s setting type to BTRC_ITEM_PLAYER", __func__);
+          get_folder_item_type_player(avrc_item, btrc_item);
+          break;
+
+        default:
+          BTIF_TRACE_ERROR("%s cannot understand folder item type %d", __func__,
+                           avrc_item->item_type);
+      }
+    }
+
+    HAL_CBACK(bt_rc_ctrl_callbacks,
+              get_folder_items_cb,
+              &rc_addr,
+              BTRC_STS_NO_ERROR,
+              /* We want to make the ownership explicit in native */
+              (const btrc_folder_items_t*)btrc_items, item_count);
+    BTIF_TRACE_DEBUG("%s HAL CBACK get_folder_items_cb finished", __func__);
+
+    /* Release the memory block for items since we OWN the object */
+    osi_free(btrc_items);
+  } else {
+    BTIF_TRACE_ERROR("%s: Error %d", __func__, p_rsp->status);
+    HAL_CBACK(bt_rc_ctrl_callbacks,
+              get_folder_items_cb,
+              &rc_addr,
+              (btrc_status_t) p_rsp->status,
+              NULL, 0);
+  }
+}
+
+/***************************************************************************
+ *
+ * Function         get_folder_item_type_media
+ *
+ * Description      Converts the AVRC representation of a folder item with
+ *                  TYPE media to BTIF representation.
+ * Returns          None
+ *
+ **************************************************************************/
+void get_folder_item_type_media(const tAVRC_ITEM* avrc_item,
+                                btrc_folder_items_t* btrc_item) {
+  btrc_item->item_type = BTRC_ITEM_MEDIA;
+  const tAVRC_ITEM_MEDIA* avrc_item_media = &(avrc_item->u.media);
+  btrc_item_media_t* btrc_item_media = &(btrc_item->media);
+  /* UID */
+  memset(btrc_item_media->uid, 0, BTRC_UID_SIZE * sizeof(uint8_t));
+  memcpy(btrc_item_media->uid, avrc_item_media->uid,
+         sizeof(uint8_t) * BTRC_UID_SIZE);
+
+  /* Audio/Video type */
+  switch (avrc_item_media->type) {
+    case AVRC_MEDIA_TYPE_AUDIO:
+      btrc_item_media->type = BTRC_MEDIA_TYPE_AUDIO;
+      break;
+    case AVRC_MEDIA_TYPE_VIDEO:
+      btrc_item_media->type = BTRC_MEDIA_TYPE_VIDEO;
+      break;
+  }
+
+  /* Charset ID */
+  btrc_item_media->charset_id = avrc_item_media->name.charset_id;
+
+  /* Copy the name */
+  BTIF_TRACE_DEBUG("%s max len %d str len %d", __func__, BTRC_MAX_ATTR_STR_LEN,
+                   avrc_item_media->name.str_len);
+  memset(btrc_item_media->name, 0, BTRC_MAX_ATTR_STR_LEN * sizeof(uint8_t));
+  memcpy(btrc_item_media->name, avrc_item_media->name.p_str,
+         sizeof(uint8_t) * (avrc_item_media->name.str_len));
+
+  /* Copy the parameters */
+  btrc_item_media->num_attrs = avrc_item_media->attr_count;
+  btrc_item_media->p_attrs = (btrc_element_attr_val_t*)osi_malloc(
+      btrc_item_media->num_attrs * sizeof(btrc_element_attr_val_t));
+
+  /* Extract each attribute */
+  for (int i = 0; i < avrc_item_media->attr_count; i++) {
+    btrc_element_attr_val_t* btrc_attr_pair = &(btrc_item_media->p_attrs[i]);
+    tAVRC_ATTR_ENTRY* avrc_attr_pair = &(avrc_item_media->p_attr_list[i]);
+
+    BTIF_TRACE_DEBUG("%s media attr id 0x%x", __func__,
+                     avrc_attr_pair->attr_id);
+
+    switch (avrc_attr_pair->attr_id) {
+      case AVRC_MEDIA_ATTR_ID_TITLE:
+        btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_TITLE;
+        break;
+      case AVRC_MEDIA_ATTR_ID_ARTIST:
+        btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_ARTIST;
+        break;
+      case AVRC_MEDIA_ATTR_ID_ALBUM:
+        btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_ALBUM;
+        break;
+      case AVRC_MEDIA_ATTR_ID_TRACK_NUM:
+        btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_TRACK_NUM;
+        break;
+      case AVRC_MEDIA_ATTR_ID_NUM_TRACKS:
+        btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_NUM_TRACKS;
+        break;
+      case AVRC_MEDIA_ATTR_ID_GENRE:
+        btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_GENRE;
+        break;
+      case AVRC_MEDIA_ATTR_ID_PLAYING_TIME:
+        btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_PLAYING_TIME;
+        break;
+      default:
+        BTIF_TRACE_ERROR("%s invalid media attr id: 0x%x", __func__,
+                         avrc_attr_pair->attr_id);
+        btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_INVALID;
+    }
+
+    memset(btrc_attr_pair->text, 0, BTRC_MAX_ATTR_STR_LEN * sizeof(uint8_t));
+    memcpy(btrc_attr_pair->text, avrc_attr_pair->name.p_str,
+           avrc_attr_pair->name.str_len);
+  }
+}
+
+/***************************************************************************
+ *
+ * Function         get_folder_item_type_folder
+ *
+ * Description      Converts the AVRC representation of a folder item with
+ *                  TYPE folder to BTIF representation.
+ * Returns          None
+ *
+ **************************************************************************/
+void get_folder_item_type_folder(const tAVRC_ITEM* avrc_item,
+                                 btrc_folder_items_t* btrc_item) {
+  btrc_item->item_type = BTRC_ITEM_FOLDER;
+  const tAVRC_ITEM_FOLDER* avrc_item_folder = &(avrc_item->u.folder);
+  btrc_item_folder_t* btrc_item_folder = &(btrc_item->folder);
+  /* Copy the UID */
+  memset(btrc_item_folder->uid, 0, BTRC_UID_SIZE * sizeof(uint8_t));
+  memcpy(btrc_item_folder->uid, avrc_item_folder->uid,
+         sizeof(uint8_t) * BTRC_UID_SIZE);
+
+  /* Copy the type */
+  switch (avrc_item_folder->type) {
+    case AVRC_FOLDER_TYPE_MIXED:
+      btrc_item_folder->type = BTRC_FOLDER_TYPE_MIXED;
+      break;
+    case AVRC_FOLDER_TYPE_TITLES:
+      btrc_item_folder->type = BTRC_FOLDER_TYPE_TITLES;
+      break;
+    case AVRC_FOLDER_TYPE_ALNUMS:
+      btrc_item_folder->type = BTRC_FOLDER_TYPE_ALBUMS;
+      break;
+    case AVRC_FOLDER_TYPE_ARTISTS:
+      btrc_item_folder->type = BTRC_FOLDER_TYPE_ARTISTS;
+      break;
+    case AVRC_FOLDER_TYPE_GENRES:
+      btrc_item_folder->type = BTRC_FOLDER_TYPE_GENRES;
+      break;
+    case AVRC_FOLDER_TYPE_PLAYLISTS:
+      btrc_item_folder->type = BTRC_FOLDER_TYPE_PLAYLISTS;
+      break;
+    case AVRC_FOLDER_TYPE_YEARS:
+      btrc_item_folder->type = BTRC_FOLDER_TYPE_YEARS;
+      break;
+  }
+
+  /* Copy if playable */
+  btrc_item_folder->playable = avrc_item_folder->playable;
+
+  /* Copy name */
+  BTIF_TRACE_DEBUG("%s max len %d str len %d", __func__, BTRC_MAX_ATTR_STR_LEN,
+                   avrc_item_folder->name.str_len);
+  memset(btrc_item_folder->name, 0, BTRC_MAX_ATTR_STR_LEN * sizeof(uint8_t));
+  memcpy(btrc_item_folder->name, avrc_item_folder->name.p_str,
+         avrc_item_folder->name.str_len * sizeof(uint8_t));
+
+  /* Copy charset */
+  btrc_item_folder->charset_id = avrc_item_folder->name.charset_id;
+}
+
+/***************************************************************************
+ *
+ * Function         get_folder_item_type_player
+ *
+ * Description      Converts the AVRC representation of a folder item with
+ *                  TYPE player to BTIF representation.
+ * Returns          None
+ *
+ **************************************************************************/
+void get_folder_item_type_player(const tAVRC_ITEM* avrc_item,
+                                 btrc_folder_items_t* btrc_item) {
+  btrc_item->item_type = BTRC_ITEM_PLAYER;
+  const tAVRC_ITEM_PLAYER* avrc_item_player = &(avrc_item->u.player);
+  btrc_item_player_t* btrc_item_player = &(btrc_item->player);
+  /* Player ID */
+  btrc_item_player->player_id = avrc_item_player->player_id;
+  /* Major type */
+  btrc_item_player->major_type = avrc_item_player->major_type;
+  /* Sub type */
+  btrc_item_player->sub_type = avrc_item_player->sub_type;
+  /* Features */
+  memcpy(btrc_item_player->features, avrc_item_player->features,
+         BTRC_FEATURE_BIT_MASK_SIZE);
+
+  memset(btrc_item_player->name, 0, BTRC_MAX_ATTR_STR_LEN * sizeof(uint8_t));
+  memcpy(btrc_item_player->name, avrc_item_player->name.p_str,
+         avrc_item_player->name.str_len);
+}
+
+/***************************************************************************
+ *
+ * Function         handle_change_path_response
+ *
+ * Description      handles the the change path response, calls
+ *                  HAL callback to send the updated folder
+ * Returns          None
+ *
+ **************************************************************************/
+static void handle_change_path_response(tBTA_AV_META_MSG* pmeta_msg,
+                                        tAVRC_CHG_PATH_RSP* p_rsp) {
+  btif_rc_device_cb_t* p_dev =
+      btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+  bt_bdaddr_t rc_addr;
+  bdcpy(rc_addr.address, p_dev->rc_addr);
+
+  if (p_rsp->status == AVRC_STS_NO_ERROR) {
+    HAL_CBACK(bt_rc_ctrl_callbacks, change_folder_path_cb, &rc_addr,
+              p_rsp->num_items);
+  } else {
+    BTIF_TRACE_ERROR("%s error in handle_change_path_response %d", __func__,
+                     p_rsp->status);
+  }
+}
+
+/***************************************************************************
+ *
+ * Function         handle_set_browsed_player_response
+ *
+ * Description      handles the the change path response, calls
+ *                  HAL callback to send the updated folder
+ * Returns          None
+ *
+ **************************************************************************/
+static void handle_set_browsed_player_response(tBTA_AV_META_MSG* pmeta_msg,
+                                               tAVRC_SET_BR_PLAYER_RSP* p_rsp) {
+  btif_rc_device_cb_t* p_dev =
+      btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+  bt_bdaddr_t rc_addr;
+  bdcpy(rc_addr.address, p_dev->rc_addr);
+
+  if (p_rsp->status == AVRC_STS_NO_ERROR) {
+    HAL_CBACK(bt_rc_ctrl_callbacks, set_browsed_player_cb, &rc_addr,
+              p_rsp->num_items, p_rsp->folder_depth);
+  } else {
+    BTIF_TRACE_ERROR("%s error %d", __func__, p_rsp->status);
+  }
+}
+
+/***************************************************************************
+ *
+ * Function         clear_cmd_timeout
+ *
+ * Description      helper function to stop the command timeout timer
+ * Returns          None
+ *
+ **************************************************************************/
+static void clear_cmd_timeout(uint8_t label) {
+  rc_transaction_t* p_txn;
+
+  p_txn = get_transaction_by_lbl(label);
+  if (p_txn == NULL) {
+    BTIF_TRACE_ERROR("%s: Error in transaction label lookup", __func__);
+    return;
+  }
+
+  if (p_txn->txn_timer != NULL) alarm_cancel(p_txn->txn_timer);
+}
+
+/***************************************************************************
+ *
+ * Function         handle_avk_rc_metamsg_rsp
+ *
+ * Description      Handle RC metamessage response
+ *
+ * Returns          void
+ *
+ **************************************************************************/
+static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg) {
+  tAVRC_RESPONSE avrc_response = {0};
+  uint8_t scratch_buf[512] = {0};  // this variable is unused
+  uint16_t buf_len;
+  tAVRC_STS status;
+
+  BTIF_TRACE_DEBUG("%s: opcode: %d rsp_code: %d  ", __func__,
+                   pmeta_msg->p_msg->hdr.opcode, pmeta_msg->code);
+
+  status = AVRC_Ctrl_ParsResponse(pmeta_msg->p_msg, &avrc_response, scratch_buf,
+                                  &buf_len);
+  if ((AVRC_OP_VENDOR == pmeta_msg->p_msg->hdr.opcode) &&
+      (pmeta_msg->code >= AVRC_RSP_NOT_IMPL) &&
+      (pmeta_msg->code <= AVRC_RSP_INTERIM)) {
+    BTIF_TRACE_DEBUG("%s parse status %d pdu = %d rsp_status = %d",
+                     __FUNCTION__, status, avrc_response.pdu,
+                     pmeta_msg->p_msg->vendor.hdr.ctype);
+
+    switch (avrc_response.pdu) {
+      case AVRC_PDU_REGISTER_NOTIFICATION:
+        handle_notification_response(pmeta_msg, &avrc_response.reg_notif);
+        if (pmeta_msg->code == AVRC_RSP_INTERIM) {
+          /* Don't free the transaction Id */
+          clear_cmd_timeout(pmeta_msg->label);
+          return;
+        }
+        break;
+
+      case AVRC_PDU_GET_CAPABILITIES:
+        handle_get_capability_response(pmeta_msg, &avrc_response.get_caps);
+        break;
+
+      case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+        handle_app_attr_response(pmeta_msg, &avrc_response.list_app_attr);
+        break;
+
+      case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+        handle_app_val_response(pmeta_msg, &avrc_response.list_app_values);
+        break;
+
+      case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+        handle_app_cur_val_response(pmeta_msg, &avrc_response.get_cur_app_val);
+        break;
+
+      case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+        handle_app_attr_txt_response(pmeta_msg,
+                                     &avrc_response.get_app_attr_txt);
+        break;
+
+      case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
+        handle_app_attr_val_txt_response(pmeta_msg,
+                                         &avrc_response.get_app_val_txt);
+        break;
+
+      case AVRC_PDU_SET_PLAYER_APP_VALUE:
+        handle_set_app_attr_val_response(pmeta_msg, &avrc_response.set_app_val);
+        break;
+
+      case AVRC_PDU_GET_ELEMENT_ATTR:
+        handle_get_elem_attr_response(pmeta_msg, &avrc_response.get_elem_attrs);
+        break;
+
+      case AVRC_PDU_GET_PLAY_STATUS:
+        handle_get_playstatus_response(pmeta_msg,
+                                       &avrc_response.get_play_status);
+        break;
+
+      case AVRC_PDU_SET_ADDRESSED_PLAYER:
+	handle_set_addressed_player_response(pmeta_msg, &avrc_response.rsp);
+	break;
+    }
+  } else if (AVRC_OP_BROWSE == pmeta_msg->p_msg->hdr.opcode) {
+    BTIF_TRACE_DEBUG("%s AVRC_OP_BROWSE pdu %d", __func__, avrc_response.pdu);
+    /* check what kind of command it is for browsing */
+    switch (avrc_response.pdu) {
+      case AVRC_PDU_GET_FOLDER_ITEMS:
+        handle_get_folder_items_response(pmeta_msg, &avrc_response.get_items);
+        break;
+      case AVRC_PDU_CHANGE_PATH:
+        handle_change_path_response(pmeta_msg, &avrc_response.chg_path);
+        break;
+      case AVRC_PDU_SET_BROWSED_PLAYER:
+        handle_set_browsed_player_response(pmeta_msg, &avrc_response.br_player);
+        break;
+      default:
+        BTIF_TRACE_ERROR("%s cannot handle browse pdu %d", __func__,
+                         pmeta_msg->p_msg->hdr.opcode);
+    }
+  } else {
+    BTIF_TRACE_DEBUG(
+        "%s: Invalid Vendor Command code: %d len: %d. Not processing it.",
+        __func__, pmeta_msg->code, pmeta_msg->len);
+    return;
+  }
+  BTIF_TRACE_DEBUG("XX __func__ release transaction %d", pmeta_msg->label);
+  release_transaction(pmeta_msg->label);
+}
+
+/***************************************************************************
+ *
+ * Function         handle_avk_rc_metamsg_cmd
+ *
+ * Description      Handle RC metamessage response
+ *
+ * Returns          void
+ *
+ **************************************************************************/
+static void handle_avk_rc_metamsg_cmd(tBTA_AV_META_MSG* pmeta_msg) {
+  tAVRC_COMMAND avrc_cmd = {0};
+  tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+  btif_rc_device_cb_t* p_dev = NULL;
+
+  BTIF_TRACE_DEBUG("%s: opcode: %d rsp_code: %d", __func__,
+                   pmeta_msg->p_msg->hdr.opcode, pmeta_msg->code);
+  status = AVRC_Ctrl_ParsCommand(pmeta_msg->p_msg, &avrc_cmd);
+  if ((AVRC_OP_VENDOR == pmeta_msg->p_msg->hdr.opcode) &&
+      (pmeta_msg->code <= AVRC_CMD_GEN_INQ)) {
+    BTIF_TRACE_DEBUG("%s Received vendor command.code %d, PDU %d label %d",
+                     __FUNCTION__, pmeta_msg->code, avrc_cmd.pdu,
+                     pmeta_msg->label);
+
+    if (status != AVRC_STS_NO_ERROR) {
+      /* return error */
+      BTIF_TRACE_WARNING(
+          "%s: Error in parsing received metamsg command. status: 0x%02x",
+          __func__, status);
+      send_reject_response(pmeta_msg->rc_handle, pmeta_msg->label, avrc_cmd.pdu,
+                           status, pmeta_msg->p_msg->hdr.opcode);
+    } else {
+      p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+      if (p_dev == NULL) {
+        BTIF_TRACE_ERROR("%s: avk rc meta msg cmd for Invalid rc handle",
+                         __func__);
+        return;
+      }
+
+      if (avrc_cmd.pdu == AVRC_PDU_REGISTER_NOTIFICATION) {
+        uint8_t event_id = avrc_cmd.reg_notif.event_id;
+        BTIF_TRACE_EVENT("%s: Register notification event_id: %s", __func__,
+                         dump_rc_notification_event_id(event_id));
+      } else if (avrc_cmd.pdu == AVRC_PDU_SET_ABSOLUTE_VOLUME) {
+        BTIF_TRACE_EVENT("%s: Abs Volume Cmd Recvd", __func__);
+      }
+
+      btif_rc_ctrl_upstreams_rsp_cmd(avrc_cmd.pdu, &avrc_cmd, pmeta_msg->label,
+                                     p_dev);
+    }
+  } else {
+    BTIF_TRACE_DEBUG(
+        "%s: Invalid Vendor Command  code: %d len: %d. Not processing it.",
+        __func__, pmeta_msg->code, pmeta_msg->len);
+    return;
+  }
+}
+#endif
+
+/***************************************************************************
+ *
+ * Function         cleanup
+ *
+ * Description      Closes the AVRC interface
+ *
+ * Returns          void
+ *
+ **************************************************************************/
+static void cleanup() {
+  BTIF_TRACE_EVENT("%s: ", __func__);
+  close_uinput();
+  if (bt_rc_callbacks) {
+    bt_rc_callbacks = NULL;
+  }
+
+  for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+    alarm_free(btif_rc_cb.rc_multi_cb[idx].rc_play_status_timer);
+    memset(&btif_rc_cb.rc_multi_cb[idx], 0,
+           sizeof(btif_rc_cb.rc_multi_cb[idx]));
+  }
+
+  BTIF_TRACE_EVENT("%s: completed", __func__);
+}
+
+/***************************************************************************
+ *
+ * Function         cleanup_ctrl
+ *
+ * Description      Closes the AVRC Controller interface
+ *
+ * Returns          void
+ *
+ **************************************************************************/
+static void cleanup_ctrl() {
+  BTIF_TRACE_EVENT("%s: ", __func__);
+
+  if (bt_rc_ctrl_callbacks) {
+    bt_rc_ctrl_callbacks = NULL;
+  }
+
+  for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+    alarm_free(btif_rc_cb.rc_multi_cb[idx].rc_play_status_timer);
+    memset(&btif_rc_cb.rc_multi_cb[idx], 0,
+           sizeof(btif_rc_cb.rc_multi_cb[idx]));
+  }
+
+  memset(&btif_rc_cb.rc_multi_cb, 0, sizeof(btif_rc_cb.rc_multi_cb));
+  BTIF_TRACE_EVENT("%s: completed", __func__);
+}
+
+/***************************************************************************
+ *
+ * Function         getcapabilities_cmd
+ *
+ * Description      GetCapabilties from Remote(Company_ID, Events_Supported)
+ *
+ * Returns          void
+ *
+ **************************************************************************/
+static bt_status_t getcapabilities_cmd(uint8_t cap_id,
+                                       btif_rc_device_cb_t* p_dev) {
+  tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+  rc_transaction_t* p_transaction = NULL;
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  BTIF_TRACE_DEBUG("%s: cap_id: %d", __func__, cap_id);
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  bt_status_t tran_status = get_transaction(&p_transaction);
+  if (BT_STATUS_SUCCESS != tran_status) return BT_STATUS_FAIL;
+
+  tAVRC_COMMAND avrc_cmd = {0};
+  BT_HDR* p_msg = NULL;
+  avrc_cmd.get_caps.opcode = AVRC_OP_VENDOR;
+  avrc_cmd.get_caps.capability_id = cap_id;
+  avrc_cmd.get_caps.pdu = AVRC_PDU_GET_CAPABILITIES;
+  avrc_cmd.get_caps.status = AVRC_STS_NO_ERROR;
+  status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+  if ((status == AVRC_STS_NO_ERROR) && (p_msg != NULL)) {
+    uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
+    BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d", __func__,
+                     p_transaction->lbl);
+    BTA_AvVendorCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_STATUS,
+                    data_start, p_msg->len);
+    status = BT_STATUS_SUCCESS;
+    start_status_command_timer(AVRC_PDU_GET_CAPABILITIES, p_transaction, p_dev);
+  } else {
+    BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __func__,
+                     status);
+  }
+  osi_free(p_msg);
+#else
+  BTIF_TRACE_DEBUG("%s: feature not enabled", __func__);
+#endif
+  return (bt_status_t)status;
+}
+
+/***************************************************************************
+ *
+ * Function         list_player_app_setting_attrib_cmd
+ *
+ * Description      Get supported List Player Attributes
+ *
+ * Returns          void
+ *
+ **************************************************************************/
+static bt_status_t list_player_app_setting_attrib_cmd(
+    btif_rc_device_cb_t* p_dev) {
+  tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+  rc_transaction_t* p_transaction = NULL;
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  BTIF_TRACE_DEBUG("%s: ", __func__);
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  bt_status_t tran_status = get_transaction(&p_transaction);
+  if (BT_STATUS_SUCCESS != tran_status) return BT_STATUS_FAIL;
+
+  tAVRC_COMMAND avrc_cmd = {0};
+  BT_HDR* p_msg = NULL;
+  avrc_cmd.list_app_attr.opcode = AVRC_OP_VENDOR;
+  avrc_cmd.list_app_attr.pdu = AVRC_PDU_LIST_PLAYER_APP_ATTR;
+  avrc_cmd.list_app_attr.status = AVRC_STS_NO_ERROR;
+  status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+  if ((status == AVRC_STS_NO_ERROR) && (p_msg != NULL)) {
+    uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
+    BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d", __func__,
+                     p_transaction->lbl);
+    BTA_AvVendorCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_STATUS,
+                    data_start, p_msg->len);
+    status = BT_STATUS_SUCCESS;
+    start_status_command_timer(AVRC_PDU_LIST_PLAYER_APP_ATTR, p_transaction,
+                               p_dev);
+  } else {
+    BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __func__,
+                     status);
+  }
+  osi_free(p_msg);
+#else
+  BTIF_TRACE_DEBUG("%s: feature not enabled", __func__);
+#endif
+  return (bt_status_t)status;
+}
+
+/***************************************************************************
+ *
+ * Function         list_player_app_setting_value_cmd
+ *
+ * Description      Get values of supported Player Attributes
+ *
+ * Returns          void
+ *
+ **************************************************************************/
+static bt_status_t list_player_app_setting_value_cmd(
+    uint8_t attrib_id, btif_rc_device_cb_t* p_dev) {
+  tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+  rc_transaction_t* p_transaction = NULL;
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  BTIF_TRACE_DEBUG("%s: attrib_id: %d", __func__, attrib_id);
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  bt_status_t tran_status = get_transaction(&p_transaction);
+  if (BT_STATUS_SUCCESS != tran_status) return BT_STATUS_FAIL;
+
+  tAVRC_COMMAND avrc_cmd = {0};
+  BT_HDR* p_msg = NULL;
+  avrc_cmd.list_app_values.attr_id = attrib_id;
+  avrc_cmd.list_app_values.opcode = AVRC_OP_VENDOR;
+  avrc_cmd.list_app_values.pdu = AVRC_PDU_LIST_PLAYER_APP_VALUES;
+  avrc_cmd.list_app_values.status = AVRC_STS_NO_ERROR;
+  status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+  if ((status == AVRC_STS_NO_ERROR) && (p_msg != NULL)) {
+    uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
+    BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d", __func__,
+                     p_transaction->lbl);
+    BTA_AvVendorCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_STATUS,
+                    data_start, p_msg->len);
+    status = BT_STATUS_SUCCESS;
+    start_status_command_timer(AVRC_PDU_LIST_PLAYER_APP_VALUES, p_transaction,
+                               p_dev);
+  } else {
+    BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __func__,
+                     status);
+  }
+  osi_free(p_msg);
+#else
+  BTIF_TRACE_DEBUG("%s: feature not enabled", __func__);
+#endif
+  return (bt_status_t)status;
+}
+
+/***************************************************************************
+ *
+ * Function         get_player_app_setting_cmd
+ *
+ * Description      Get current values of Player Attributes
+ *
+ * Returns          void
+ *
+ **************************************************************************/
+static bt_status_t get_player_app_setting_cmd(uint8_t num_attrib,
+                                              uint8_t* attrib_ids,
+                                              btif_rc_device_cb_t* p_dev) {
+  tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+  rc_transaction_t* p_transaction = NULL;
+  int count = 0;
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  BTIF_TRACE_DEBUG("%s: num attrib_id: %d", __func__, num_attrib);
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  bt_status_t tran_status = get_transaction(&p_transaction);
+  if (BT_STATUS_SUCCESS != tran_status) return BT_STATUS_FAIL;
+
+  tAVRC_COMMAND avrc_cmd = {0};
+  BT_HDR* p_msg = NULL;
+  avrc_cmd.get_cur_app_val.opcode = AVRC_OP_VENDOR;
+  avrc_cmd.get_cur_app_val.status = AVRC_STS_NO_ERROR;
+  avrc_cmd.get_cur_app_val.num_attr = num_attrib;
+  avrc_cmd.get_cur_app_val.pdu = AVRC_PDU_GET_CUR_PLAYER_APP_VALUE;
+
+  for (count = 0; count < num_attrib; count++) {
+    avrc_cmd.get_cur_app_val.attrs[count] = attrib_ids[count];
+  }
+  status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+  if ((status == AVRC_STS_NO_ERROR) && (p_msg != NULL)) {
+    uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
+    BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d", __func__,
+                     p_transaction->lbl);
+    BTA_AvVendorCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_STATUS,
+                    data_start, p_msg->len);
+    status = BT_STATUS_SUCCESS;
+    start_status_command_timer(AVRC_PDU_GET_CUR_PLAYER_APP_VALUE, p_transaction,
+                               p_dev);
+  } else {
+    BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __func__,
+                     status);
+  }
+  osi_free(p_msg);
+#else
+  BTIF_TRACE_DEBUG("%s: feature not enabled", __func__);
+#endif
+  return (bt_status_t)status;
+}
+
+/***************************************************************************
+**
+** Function         get_playback_state_cmd
+**
+** Description      Fetch the current playback state for the device
+**
+** Returns          BT_STATUS_SUCCESS if command issued successfully otherwise
+**                  BT_STATUS_FAIL.
+**
+***************************************************************************/
+static bt_status_t get_playback_state_cmd(bt_bdaddr_t *bd_addr) {
+    BTIF_TRACE_DEBUG("%s", __func__);
+    btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+    return get_play_status_cmd(p_dev);
+}
+
+/***************************************************************************
+ *
+ * Function         get_now_playing_list_cmd
+ *
+ * Description      Fetch the now playing list
+ *
+ * Paramters        start_item: First item to fetch (0 to fetch from beganning)
+ *                  end_item: Last item to fetch (0xff to fetch until end)
+ *
+ * Returns          BT_STATUS_SUCCESS if command issued successfully otherwise
+ *                  BT_STATUS_FAIL.
+ *
+ **************************************************************************/
+static bt_status_t get_now_playing_list_cmd(bt_bdaddr_t* bd_addr,
+                                            uint8_t start_item,
+                                            uint8_t num_items) {
+  BTIF_TRACE_DEBUG("%s start, end: (%d, %d)", __func__, start_item, num_items);
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  return get_folder_items_cmd(bd_addr, AVRC_SCOPE_NOW_PLAYING, start_item,
+                              num_items);
+#else
+  BTIF_TRACE_ERROR("%s AVRCP controller role is not enabled", __func__);
+  return BT_STATUS_FAIL;
+#endif
+}
+
+/***************************************************************************
+ *
+ * Function         get_folder_list_cmd
+ *
+ * Description      Fetch the currently selected folder list
+ *
+ * Paramters        start_item: First item to fetch (0 to fetch from beganning)
+ *                  end_item: Last item to fetch (0xff to fetch until end)
+ *
+ * Returns          BT_STATUS_SUCCESS if command issued successfully otherwise
+ *                  BT_STATUS_FAIL.
+ *
+ **************************************************************************/
+static bt_status_t get_folder_list_cmd(bt_bdaddr_t* bd_addr, uint8_t start_item,
+                                       uint8_t num_items) {
+  BTIF_TRACE_DEBUG("%s start, end: (%d, %d)", __func__, start_item, num_items);
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  return get_folder_items_cmd(bd_addr, AVRC_SCOPE_FILE_SYSTEM, start_item,
+                              num_items);
+#else
+  BTIF_TRACE_ERROR("%s AVRCP controller role is not enabled", __func__);
+  return BT_STATUS_FAIL;
+#endif
+}
+
+/***************************************************************************
+ *
+ * Function         get_player_list_cmd
+ *
+ * Description      Fetch the player list
+ *
+ * Paramters        start_item: First item to fetch (0 to fetch from beganning)
+ *                  end_item: Last item to fetch (0xff to fetch until end)
+ *
+ * Returns          BT_STATUS_SUCCESS if command issued successfully otherwise
+ *                  BT_STATUS_FAIL.
+ *
+ **************************************************************************/
+static bt_status_t get_player_list_cmd(bt_bdaddr_t* bd_addr, uint8_t start_item,
+                                       uint8_t num_items) {
+  BTIF_TRACE_DEBUG("%s start, end: (%d, %d)", __func__, start_item, num_items);
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  return get_folder_items_cmd(bd_addr, AVRC_SCOPE_PLAYER_LIST, start_item,
+                              num_items);
+#else
+  BTIF_TRACE_ERROR("%s AVRCP controller role is not enabled", __func__);
+  return BT_STATUS_FAIL;
+#endif
+}
+
+/***************************************************************************
+ *
+ * Function         change_folder_path_cmd
+ *
+ * Description      Change the folder.
+ *
+ * Paramters        direction: Direction (Up/Down) to change folder
+ *                  uid: The UID of folder to move to
+ *                  start_item: First item to fetch (0 to fetch from beganning)
+ *                  end_item: Last item to fetch (0xff to fetch until end)
+ *
+ * Returns          BT_STATUS_SUCCESS if command issued successfully otherwise
+ *                  BT_STATUS_FAIL.
+ *
+ **************************************************************************/
+static bt_status_t change_folder_path_cmd(bt_bdaddr_t* bd_addr,
+                                          uint8_t direction, uint8_t* uid) {
+  BTIF_TRACE_DEBUG("%s direction (%d)", __func__, direction);
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+  CHECK_RC_CONNECTED(p_dev);
+  CHECK_BR_CONNECTED(p_dev);
+
+  tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+  rc_transaction_t* p_transaction = NULL;
+
+  if (p_dev->br_connected) {
+    tAVRC_COMMAND avrc_cmd = {0};
+    BT_HDR* p_msg = NULL;
+
+    avrc_cmd.chg_path.pdu = AVRC_PDU_CHANGE_PATH;
+    avrc_cmd.chg_path.status = AVRC_STS_NO_ERROR;
+    // TODO(sanketa): Improve for database aware clients.
+    avrc_cmd.chg_path.uid_counter = 0;
+    avrc_cmd.chg_path.direction = direction;
+
+    memset(avrc_cmd.chg_path.folder_uid, 0, AVRC_UID_SIZE * sizeof(uint8_t));
+    memcpy(avrc_cmd.chg_path.folder_uid, uid, AVRC_UID_SIZE * sizeof(uint8_t));
+
+    if (AVRC_BldCommand(&avrc_cmd, &p_msg) == AVRC_STS_NO_ERROR) {
+      bt_status_t tran_status = get_transaction(&p_transaction);
+      if (BT_STATUS_SUCCESS == tran_status && p_transaction != NULL) {
+        BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d", __func__,
+                         p_transaction->lbl);
+        BTA_AvMetaCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_CTRL,
+                      p_msg);
+        status = BT_STATUS_SUCCESS;
+      } else {
+        osi_free(p_msg);
+        BTIF_TRACE_ERROR(
+            "%s: failed to obtain transaction details. status: 0x%02x",
+            __func__, tran_status);
+        status = BT_STATUS_FAIL;
+      }
+    } else {
+      BTIF_TRACE_ERROR("%s failed to build command status %d", __func__,
+                       status);
+      status = BT_STATUS_FAIL;
+    }
+  } else {
+    BTIF_TRACE_ERROR("%s command not supported by peer features %d", __func__,
+                     p_dev->rc_features);
+    status = BT_STATUS_FAIL;
+  }
+  return (bt_status_t)status;
+#else
+  BTIF_TRACE_ERROR("%s AVRCP controller role is not enabled", __func__);
+  return BT_STATUS_FAIL;
+#endif
+}
+
+/***************************************************************************
+ *
+ * Function         set_browsed_player_cmd
+ *
+ * Description      Change the browsed player.
+ *
+ * Paramters        id: The UID of player to move to
+ *
+ * Returns          BT_STATUS_SUCCESS if command issued successfully otherwise
+ *                  BT_STATUS_FAIL.
+ *
+ **************************************************************************/
+static bt_status_t set_browsed_player_cmd(bt_bdaddr_t* bd_addr, uint16_t id) {
+  BTIF_TRACE_DEBUG("%s id (%d)", __func__, id);
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+  CHECK_RC_CONNECTED(p_dev);
+  CHECK_BR_CONNECTED(p_dev);
+
+  tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+  rc_transaction_t* p_transaction = NULL;
+
+  if (p_dev->br_connected) {
+    tAVRC_COMMAND avrc_cmd = {0};
+    BT_HDR* p_msg = NULL;
+
+    avrc_cmd.br_player.pdu = AVRC_PDU_SET_BROWSED_PLAYER;
+    avrc_cmd.br_player.status = AVRC_STS_NO_ERROR;
+    // TODO(sanketa): Improve for database aware clients.
+    avrc_cmd.br_player.player_id = id;
+
+    if (AVRC_BldCommand(&avrc_cmd, &p_msg) == AVRC_STS_NO_ERROR) {
+      bt_status_t tran_status = get_transaction(&p_transaction);
+      if (BT_STATUS_SUCCESS == tran_status && p_transaction != NULL) {
+        BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d", __func__,
+                         p_transaction->lbl);
+        BTA_AvMetaCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_CTRL,
+                      p_msg);
+        status = BT_STATUS_SUCCESS;
+      } else {
+        osi_free(p_msg);
+        BTIF_TRACE_ERROR(
+            "%s: failed to obtain transaction details. status: 0x%02x",
+            __func__, tran_status);
+        status = BT_STATUS_FAIL;
+      }
+    } else {
+      BTIF_TRACE_ERROR("%s failed to build command status %d", __func__,
+                       status);
+      status = BT_STATUS_FAIL;
+    }
+  } else {
+    BTIF_TRACE_ERROR("%s command not supported by peer features %d", __func__,
+                     p_dev->rc_features);
+    status = BT_STATUS_FAIL;
+  }
+  return (bt_status_t)status;
+#else
+  BTIF_TRACE_ERROR("%s AVRCP controller role is not enabled", __func__);
+  return BT_STATUS_FAIL;
+#endif
+}
+
+/***************************************************************************
+ **
+ ** Function         set_addressed_player_cmd
+ **
+ ** Description      Change the addressed player.
+ **
+ ** Paramters        id: The UID of player to move to
+ **
+ ** Returns          BT_STATUS_SUCCESS if command issued successfully otherwise
+ **                  BT_STATUS_FAIL.
+ **
+ ***************************************************************************/
+static bt_status_t set_addressed_player_cmd(bt_bdaddr_t *bd_addr, uint16_t id)
+{
+  BTIF_TRACE_DEBUG("%s id (%d)", __func__, id);
+#if (AVRC_CTLR_INCLUDED == TRUE)
+  CHECK_RC_CONNECTED
+      CHECK_BR_CONNECTED
+      tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+  rc_transaction_t *p_transaction = NULL;
+
+  if (btif_rc_cb.br_connected) {
+    tAVRC_COMMAND avrc_cmd = {0};
+    BT_HDR *p_msg = NULL;
+
+    avrc_cmd.addr_player.pdu = AVRC_PDU_SET_ADDRESSED_PLAYER;
+    avrc_cmd.addr_player.status = AVRC_STS_NO_ERROR;
+    // TODO(sanketa): Improve for database aware clients.
+    avrc_cmd.addr_player.player_id = id;
+
+    if (AVRC_BldCommand(&avrc_cmd, &p_msg) == AVRC_STS_NO_ERROR) {
+      bt_status_t tran_status = get_transaction(&p_transaction);
+      if (BT_STATUS_SUCCESS == tran_status && p_transaction != NULL) {
+        BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d",
+                         __func__, p_transaction->lbl);
+        BTA_AvMetaCmd(btif_rc_cb.rc_handle, p_transaction->lbl,
+                      AVRC_CMD_CTRL, p_msg);
+        status = BT_STATUS_SUCCESS;
+      } else {
+        osi_free(p_msg);
+        BTIF_TRACE_ERROR("%s: failed to obtain txn details. status: 0x%02x",
+                         __func__, tran_status);
+        status = BT_STATUS_FAIL;
+      }
+    } else {
+      BTIF_TRACE_ERROR("%s failed to build command status %d",
+                       __func__, status);
+      status = BT_STATUS_FAIL;
+    }
+  } else {
+    BTIF_TRACE_ERROR("%s command not supported by peer features %d",
+                     __func__, btif_rc_cb.rc_features);
+    status = BT_STATUS_FAIL;
+  }
+  return status;
+#else
+  BTIF_TRACE_ERROR("%s AVRCP controller role is not enabled", __func__);
+  return BT_STATUS_FAIL;
+#endif
+}
+
+/***************************************************************************
+ *
+ * Function         get_folder_items_cmd
+ *
+ * Description      Helper function to browse the content hierarchy of the
+ *                  TG device.
+ *
+ * Paramters        scope: AVRC_SCOPE_NOW_PLAYING (etc) for various browseable
+ *                  content
+ *                  start_item: First item to fetch (0 to fetch from beganning)
+ *                  end_item: Last item to fetch (0xff to fetch until end)
+ *
+ * Returns          BT_STATUS_SUCCESS if command issued successfully otherwise
+ *                  BT_STATUS_FAIL.
+ *
+ **************************************************************************/
+static bt_status_t get_folder_items_cmd(bt_bdaddr_t* bd_addr, uint8_t scope,
+                                        uint8_t start_item, uint8_t end_item) {
+  BTIF_TRACE_DEBUG("%s", __func__);
+  /* Check that both avrcp and browse channel are connected. */
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+  CHECK_RC_CONNECTED(p_dev);
+  CHECK_BR_CONNECTED(p_dev);
+
+  tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+  rc_transaction_t* p_transaction = NULL;
+
+  if (p_dev->br_connected) {
+    tAVRC_COMMAND avrc_cmd = {0};
+    BT_HDR* p_msg = NULL;
+
+    /* Set the layer specific to point to browse although this should really
+     * be done by lower layers and looking at the PDU
+     */
+    avrc_cmd.get_items.pdu = AVRC_PDU_GET_FOLDER_ITEMS;
+    avrc_cmd.get_items.status = AVRC_STS_NO_ERROR;
+    avrc_cmd.get_items.scope = scope;
+    avrc_cmd.get_items.start_item = start_item;
+    avrc_cmd.get_items.end_item = end_item;
+    avrc_cmd.get_items.attr_count = 0; /* p_attr_list does not matter hence */
+
+    if (AVRC_BldCommand(&avrc_cmd, &p_msg) == AVRC_STS_NO_ERROR) {
+      bt_status_t tran_status = get_transaction(&p_transaction);
+      if (BT_STATUS_SUCCESS == tran_status && p_transaction != NULL) {
+        BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d", __func__,
+                         p_transaction->lbl);
+        BTA_AvMetaCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_CTRL,
+                      p_msg);
+        status = BT_STATUS_SUCCESS;
+      } else {
+        osi_free(p_msg);
+        BTIF_TRACE_ERROR(
+            "%s: failed to obtain transaction details. status: 0x%02x",
+            __FUNCTION__, tran_status);
+        status = BT_STATUS_FAIL;
+      }
+    } else {
+      BTIF_TRACE_ERROR("%s failed to build command status %d", __func__,
+                       status);
+      status = BT_STATUS_FAIL;
+    }
+  } else {
+    BTIF_TRACE_ERROR("%s command not supported by peer features %d", __func__,
+                     p_dev->rc_features);
+    status = BT_STATUS_FAIL;
+  }
+  return (bt_status_t)status;
+}
+
+/***************************************************************************
+ *
+ * Function         change_player_app_setting
+ *
+ * Description      Set current values of Player Attributes
+ *
+ * Returns          void
+ *
+ **************************************************************************/
+static bt_status_t change_player_app_setting(bt_bdaddr_t* bd_addr,
+                                             uint8_t num_attrib,
+                                             uint8_t* attrib_ids,
+                                             uint8_t* attrib_vals) {
+  tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+  rc_transaction_t* p_transaction = NULL;
+  int count = 0;
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  BTIF_TRACE_DEBUG("%s: num attrib_id: %d", __func__, num_attrib);
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  bt_status_t tran_status = get_transaction(&p_transaction);
+  if (BT_STATUS_SUCCESS != tran_status) return BT_STATUS_FAIL;
+
+  tAVRC_COMMAND avrc_cmd = {0};
+  BT_HDR* p_msg = NULL;
+  avrc_cmd.set_app_val.opcode = AVRC_OP_VENDOR;
+  avrc_cmd.set_app_val.status = AVRC_STS_NO_ERROR;
+  avrc_cmd.set_app_val.num_val = num_attrib;
+  avrc_cmd.set_app_val.pdu = AVRC_PDU_SET_PLAYER_APP_VALUE;
+  avrc_cmd.set_app_val.p_vals =
+      (tAVRC_APP_SETTING*)osi_malloc(sizeof(tAVRC_APP_SETTING) * num_attrib);
+  for (count = 0; count < num_attrib; count++) {
+    avrc_cmd.set_app_val.p_vals[count].attr_id = attrib_ids[count];
+    avrc_cmd.set_app_val.p_vals[count].attr_val = attrib_vals[count];
+  }
+  status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+  if ((status == AVRC_STS_NO_ERROR) && (p_msg != NULL)) {
+    uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
+    BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d", __func__,
+                     p_transaction->lbl);
+    BTA_AvVendorCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_CTRL,
+                    data_start, p_msg->len);
+    status = BT_STATUS_SUCCESS;
+    start_control_command_timer(AVRC_PDU_SET_PLAYER_APP_VALUE, p_transaction,
+                                p_dev);
+  } else {
+    BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __func__,
+                     status);
+  }
+  osi_free(p_msg);
+  osi_free_and_reset((void**)&avrc_cmd.set_app_val.p_vals);
+#else
+  BTIF_TRACE_DEBUG("%s: feature not enabled", __func__);
+#endif
+  return (bt_status_t)status;
+}
+
+/***************************************************************************
+ *
+ * Function         play_item_cmd
+ *
+ * Description      Play the item specified by UID & scope
+ *
+ * Returns          void
+ *
+ **************************************************************************/
+static bt_status_t play_item_cmd(bt_bdaddr_t* bd_addr, uint8_t scope,
+                                 uint8_t* uid, uint16_t uid_counter) {
+  tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  rc_transaction_t* p_transaction = NULL;
+  BTIF_TRACE_DEBUG("%s: scope %d uid_counter %d", __FUNCTION__, scope,
+                   uid_counter);
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+  CHECK_RC_CONNECTED(p_dev);
+  CHECK_BR_CONNECTED(p_dev);
+
+  bt_status_t tran_status = get_transaction(&p_transaction);
+  if (BT_STATUS_SUCCESS != tran_status) return BT_STATUS_FAIL;
+
+  tAVRC_COMMAND avrc_cmd = {0};
+  BT_HDR* p_msg = NULL;
+  avrc_cmd.pdu = AVRC_PDU_PLAY_ITEM;
+  avrc_cmd.play_item.opcode = AVRC_OP_VENDOR;
+  avrc_cmd.play_item.status = AVRC_STS_NO_ERROR;
+  avrc_cmd.play_item.scope = scope;
+  memcpy(avrc_cmd.play_item.uid, uid, AVRC_UID_SIZE);
+  avrc_cmd.play_item.uid_counter = uid_counter;
+
+  status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+  if ((status == AVRC_STS_NO_ERROR) && (p_msg != NULL)) {
+    uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
+    BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d", __FUNCTION__,
+                     p_transaction->lbl);
+    BTA_AvVendorCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_CTRL,
+                    data_start, p_msg->len);
+    status = BT_STATUS_SUCCESS;
+    // start_control_command_timer (AVRC_PDU_PLAY_ITEM, p_transaction);
+  } else {
+    BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x",
+                     __FUNCTION__, status);
+  }
+  osi_free(p_msg);
+#else
+  BTIF_TRACE_DEBUG("%s: feature not enabled", __FUNCTION__);
+#endif
+  return (bt_status_t)status;
+}
+
+/***************************************************************************
+ *
+ * Function         get_player_app_setting_attr_text_cmd
+ *
+ * Description      Get text description for app attribute
+ *
+ * Returns          void
+ *
+ **************************************************************************/
+static bt_status_t get_player_app_setting_attr_text_cmd(
+    uint8_t* attrs, uint8_t num_attrs, btif_rc_device_cb_t* p_dev) {
+  tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+  rc_transaction_t* p_transaction = NULL;
+  int count = 0;
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  tAVRC_COMMAND avrc_cmd = {0};
+  BT_HDR* p_msg = NULL;
+  bt_status_t tran_status;
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  BTIF_TRACE_DEBUG("%s: num attrs: %d", __func__, num_attrs);
+
+  tran_status = get_transaction(&p_transaction);
+  if (BT_STATUS_SUCCESS != tran_status) return BT_STATUS_FAIL;
+
+  avrc_cmd.pdu = AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT;
+  avrc_cmd.get_app_attr_txt.opcode = AVRC_OP_VENDOR;
+  avrc_cmd.get_app_attr_txt.num_attr = num_attrs;
+
+  for (count = 0; count < num_attrs; count++) {
+    avrc_cmd.get_app_attr_txt.attrs[count] = attrs[count];
+  }
+  status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+  if (status == AVRC_STS_NO_ERROR) {
+    uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
+    BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d", __func__,
+                     p_transaction->lbl);
+    BTA_AvVendorCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_STATUS,
+                    data_start, p_msg->len);
+    osi_free(p_msg);
+    status = BT_STATUS_SUCCESS;
+    start_status_command_timer(AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT, p_transaction,
+                               p_dev);
+  } else {
+    BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __func__,
+                     status);
+  }
+  osi_free(p_msg);
+#else
+  BTIF_TRACE_DEBUG("%s: feature not enabled", __func__);
+#endif
+  return (bt_status_t)status;
+}
+
+/***************************************************************************
+ *
+ * Function         get_player_app_setting_val_text_cmd
+ *
+ * Description      Get text description for app attribute values
+ *
+ * Returns          void
+ *
+ **************************************************************************/
+static bt_status_t get_player_app_setting_value_text_cmd(
+    uint8_t* vals, uint8_t num_vals, btif_rc_device_cb_t* p_dev) {
+  tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+  rc_transaction_t* p_transaction = NULL;
+  int count = 0;
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  tAVRC_COMMAND avrc_cmd = {0};
+  BT_HDR* p_msg = NULL;
+  bt_status_t tran_status;
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  BTIF_TRACE_DEBUG("%s: num_vals: %d", __func__, num_vals);
+
+  tran_status = get_transaction(&p_transaction);
+  if (BT_STATUS_SUCCESS != tran_status) return BT_STATUS_FAIL;
+
+  avrc_cmd.pdu = AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT;
+  avrc_cmd.get_app_val_txt.opcode = AVRC_OP_VENDOR;
+  avrc_cmd.get_app_val_txt.num_val = num_vals;
+
+  for (count = 0; count < num_vals; count++) {
+    avrc_cmd.get_app_val_txt.vals[count] = vals[count];
+  }
+  status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+  if (status == AVRC_STS_NO_ERROR) {
+    uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
+    BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d", __func__,
+                     p_transaction->lbl);
+    if (p_msg != NULL) {
+      BTA_AvVendorCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_STATUS,
+                      data_start, p_msg->len);
+      status = BT_STATUS_SUCCESS;
+      start_status_command_timer(AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT,
+                                 p_transaction, p_dev);
+    }
+  } else {
+    BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __func__,
+                     status);
+  }
+  osi_free(p_msg);
+#else
+  BTIF_TRACE_DEBUG("%s: feature not enabled", __func__);
+#endif
+  return (bt_status_t)status;
+}
+
+/***************************************************************************
+ *
+ * Function         register_notification_cmd
+ *
+ * Description      Send Command to register for a Notification ID
+ *
+ * Returns          void
+ *
+ **************************************************************************/
+static bt_status_t register_notification_cmd(uint8_t label, uint8_t event_id,
+                                             uint32_t event_value,
+                                             btif_rc_device_cb_t* p_dev) {
+  tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  tAVRC_COMMAND avrc_cmd = {0};
+  BT_HDR* p_msg = NULL;
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  BTIF_TRACE_DEBUG("%s: event_id: %d  event_value", __func__, event_id,
+                   event_value);
+
+  avrc_cmd.reg_notif.opcode = AVRC_OP_VENDOR;
+  avrc_cmd.reg_notif.status = AVRC_STS_NO_ERROR;
+  avrc_cmd.reg_notif.event_id = event_id;
+  avrc_cmd.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
+  avrc_cmd.reg_notif.param = event_value;
+  status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+  if (status == AVRC_STS_NO_ERROR) {
+    uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
+    BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d", __func__,
+                     label);
+    if (p_msg != NULL) {
+      BTA_AvVendorCmd(p_dev->rc_handle, label, AVRC_CMD_NOTIF, data_start,
+                      p_msg->len);
+      status = BT_STATUS_SUCCESS;
+    }
+  } else {
+    BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __func__,
+                     status);
+  }
+  osi_free(p_msg);
+#else
+  BTIF_TRACE_DEBUG("%s: feature not enabled", __func__);
+#endif
+  return (bt_status_t)status;
+}
+
+/***************************************************************************
+ *
+ * Function         get_element_attribute_cmd
+ *
+ * Description      Get Element Attribute for  attributeIds
+ *
+ * Returns          void
+ *
+ **************************************************************************/
+static bt_status_t get_element_attribute_cmd(uint8_t num_attribute,
+                                             uint32_t* p_attr_ids,
+                                             btif_rc_device_cb_t* p_dev) {
+  tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+  rc_transaction_t* p_transaction = NULL;
+  int count = 0;
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  tAVRC_COMMAND avrc_cmd = {0};
+  BT_HDR* p_msg = NULL;
+  bt_status_t tran_status;
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  BTIF_TRACE_DEBUG("%s: num_attribute: %d attribute_id: %d", __func__,
+                   num_attribute, p_attr_ids[0]);
+
+  tran_status = get_transaction(&p_transaction);
+  if (BT_STATUS_SUCCESS != tran_status) return BT_STATUS_FAIL;
+
+  avrc_cmd.get_elem_attrs.opcode = AVRC_OP_VENDOR;
+  avrc_cmd.get_elem_attrs.status = AVRC_STS_NO_ERROR;
+  avrc_cmd.get_elem_attrs.num_attr = num_attribute;
+  avrc_cmd.get_elem_attrs.pdu = AVRC_PDU_GET_ELEMENT_ATTR;
+  for (count = 0; count < num_attribute; count++) {
+    avrc_cmd.get_elem_attrs.attrs[count] = p_attr_ids[count];
+  }
+
+  status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+  if (status == AVRC_STS_NO_ERROR) {
+    uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
+    BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d", __func__,
+                     p_transaction->lbl);
+    if (p_msg != NULL) {
+      BTA_AvVendorCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_STATUS,
+                      data_start, p_msg->len);
+      status = BT_STATUS_SUCCESS;
+      start_status_command_timer(AVRC_PDU_GET_ELEMENT_ATTR, p_transaction,
+                                 p_dev);
+    }
+  } else {
+    BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __func__,
+                     status);
+  }
+  osi_free(p_msg);
+#else
+  BTIF_TRACE_DEBUG("%s: feature not enabled", __func__);
+#endif
+  return (bt_status_t)status;
+}
+
+/***************************************************************************
+ *
+ * Function         get_play_status_cmd
+ *
+ * Description      Get Playing Status of a Device
+ *
+ * Returns          bt_status_t
+ *
+ **************************************************************************/
+static bt_status_t get_play_status_cmd(btif_rc_device_cb_t* p_dev) {
+  tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+  rc_transaction_t* p_transaction = NULL;
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  tAVRC_COMMAND avrc_cmd = {0};
+  BT_HDR* p_msg = NULL;
+  bt_status_t tran_status;
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  BTIF_TRACE_DEBUG("%s: ", __func__);
+  tran_status = get_transaction(&p_transaction);
+  if (BT_STATUS_SUCCESS != tran_status) return BT_STATUS_FAIL;
+
+  avrc_cmd.get_play_status.opcode = AVRC_OP_VENDOR;
+  avrc_cmd.get_play_status.pdu = AVRC_PDU_GET_PLAY_STATUS;
+  avrc_cmd.get_play_status.status = AVRC_STS_NO_ERROR;
+  status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+  if (status == AVRC_STS_NO_ERROR) {
+    uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
+    BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d", __func__,
+                     p_transaction->lbl);
+    if (p_msg != NULL) {
+      BTA_AvVendorCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_STATUS,
+                      data_start, p_msg->len);
+      status = BT_STATUS_SUCCESS;
+      start_status_command_timer(AVRC_PDU_GET_PLAY_STATUS, p_transaction,
+                                 p_dev);
+    }
+  } else {
+    BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __func__,
+                     status);
+  }
+  osi_free(p_msg);
+#else
+  BTIF_TRACE_DEBUG("%s: feature not enabled", __func__);
+#endif
+  return (bt_status_t)status;
+}
+
+/***************************************************************************
+ *
+ * Function         set_volume_rsp
+ *
+ * Description      Rsp for SetAbsoluteVolume Command
+ *
+ * Returns          void
+ *
+ **************************************************************************/
+static bt_status_t set_volume_rsp(bt_bdaddr_t* bd_addr, uint8_t abs_vol,
+                                  uint8_t label) {
+  tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  tAVRC_RESPONSE avrc_rsp;
+  BT_HDR* p_msg = NULL;
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  BTIF_TRACE_DEBUG("%s: abs_vol: %d", __func__, abs_vol);
+
+  avrc_rsp.volume.opcode = AVRC_OP_VENDOR;
+  avrc_rsp.volume.pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME;
+  avrc_rsp.volume.status = AVRC_STS_NO_ERROR;
+  avrc_rsp.volume.volume = abs_vol;
+  status = AVRC_BldResponse(p_dev->rc_handle, &avrc_rsp, &p_msg);
+  if (status == AVRC_STS_NO_ERROR) {
+    uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
+    BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d", __func__,
+                     p_dev->rc_vol_label);
+    if (p_msg != NULL) {
+      BTA_AvVendorRsp(p_dev->rc_handle, label, BTA_AV_RSP_ACCEPT, data_start,
+                      p_msg->len, 0);
+      status = BT_STATUS_SUCCESS;
+    }
+  } else {
+    BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __func__,
+                     status);
+  }
+  osi_free(p_msg);
+#else
+  BTIF_TRACE_DEBUG("%s: feature not enabled", __func__);
+#endif
+  return (bt_status_t)status;
+}
+
+/***************************************************************************
+ *
+ * Function         send_register_abs_vol_rsp
+ *
+ * Description      Rsp for Notification of Absolute Volume
+ *
+ * Returns          void
+ *
+ **************************************************************************/
+static bt_status_t volume_change_notification_rsp(
+    bt_bdaddr_t* bd_addr, btrc_notification_type_t rsp_type, uint8_t abs_vol,
+    uint8_t label) {
+  tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+  tAVRC_RESPONSE avrc_rsp;
+  BT_HDR* p_msg = NULL;
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  BTIF_TRACE_DEBUG("%s: rsp_type: %d abs_vol: %d", __func__, rsp_type, abs_vol);
+
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  avrc_rsp.reg_notif.opcode = AVRC_OP_VENDOR;
+  avrc_rsp.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
+  avrc_rsp.reg_notif.status = AVRC_STS_NO_ERROR;
+  avrc_rsp.reg_notif.param.volume = abs_vol;
+  avrc_rsp.reg_notif.event_id = AVRC_EVT_VOLUME_CHANGE;
+
+  status = AVRC_BldResponse(p_dev->rc_handle, &avrc_rsp, &p_msg);
+  if (status == AVRC_STS_NO_ERROR) {
+    BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d", __func__,
+                     label);
+    uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
+    BTA_AvVendorRsp(p_dev->rc_handle, label,
+                    (rsp_type == BTRC_NOTIFICATION_TYPE_INTERIM)
+                        ? AVRC_RSP_INTERIM
+                        : AVRC_RSP_CHANGED,
+                    data_start, p_msg->len, 0);
+    status = BT_STATUS_SUCCESS;
+  } else {
+    BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __func__,
+                     status);
+  }
+  osi_free(p_msg);
+
+#else
+  BTIF_TRACE_DEBUG("%s: feature not enabled", __func__);
+#endif
+  return (bt_status_t)status;
+}
+
+/***************************************************************************
+ *
+ * Function         send_groupnavigation_cmd
+ *
+ * Description      Send Pass-Through command
+ *
+ * Returns          void
+ *
+ **************************************************************************/
+static bt_status_t send_groupnavigation_cmd(bt_bdaddr_t* bd_addr,
+                                            uint8_t key_code,
+                                            uint8_t key_state) {
+  tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+#if (AVRC_CTRL_INCLUDED == TRUE)
+  rc_transaction_t* p_transaction = NULL;
+  BTIF_TRACE_DEBUG("%s: key-code: %d, key-state: %d", __func__, key_code,
+                   key_state);
+  btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  if (p_dev->rc_features & BTA_AV_FEAT_RCTG) {
+    bt_status_t tran_status = get_transaction(&p_transaction);
+    if ((BT_STATUS_SUCCESS == tran_status) && (NULL != p_transaction)) {
+      uint8_t buffer[AVRC_PASS_THRU_GROUP_LEN] = {0};
+      uint8_t* start = buffer;
+      UINT24_TO_BE_STREAM(start, AVRC_CO_METADATA);
+      *(start)++ = 0;
+      UINT8_TO_BE_STREAM(start, key_code);
+      BTA_AvRemoteVendorUniqueCmd(p_dev->rc_handle, p_transaction->lbl,
+                                  (tBTA_AV_STATE)key_state, buffer,
+                                  AVRC_PASS_THRU_GROUP_LEN);
+      status = BT_STATUS_SUCCESS;
+      BTIF_TRACE_DEBUG("%s: succesfully sent group_navigation command to BTA",
+                       __func__);
+    } else {
+      status = BT_STATUS_FAIL;
+      BTIF_TRACE_DEBUG("%s: error in fetching transaction", __func__);
+    }
+  } else {
+    status = BT_STATUS_FAIL;
+    BTIF_TRACE_DEBUG("%s: feature not supported", __func__);
+  }
+#else
+  BTIF_TRACE_DEBUG("%s: feature not enabled", __func__);
+#endif
+  return (bt_status_t)status;
+}
+
+/***************************************************************************
+ *
+ * Function         send_passthrough_cmd
+ *
+ * Description      Send Pass-Through command
+ *
+ * Returns          void
+ *
+ **************************************************************************/
+static bt_status_t send_passthrough_cmd(bt_bdaddr_t* bd_addr, uint8_t key_code,
+                                        uint8_t key_state) {
+  tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+  btif_rc_device_cb_t* p_dev = NULL;
+  BTIF_TRACE_ERROR("%s: calling btif_rc_get_device_by_bda", __func__);
+  p_dev = btif_rc_get_device_by_bda(bd_addr);
+#if (AVRC_CTRL_INCLUDED == TRUE)
+
+  CHECK_RC_CONNECTED(p_dev);
+
+  rc_transaction_t* p_transaction = NULL;
+  BTIF_TRACE_DEBUG("%s: key-code: %d, key-state: %d", __func__, key_code,
+                   key_state);
+  if (p_dev->rc_features & BTA_AV_FEAT_RCTG) {
+    bt_status_t tran_status = get_transaction(&p_transaction);
+    if (BT_STATUS_SUCCESS == tran_status && NULL != p_transaction) {
+      BTA_AvRemoteCmd(p_dev->rc_handle, p_transaction->lbl,
+                      (tBTA_AV_RC)key_code, (tBTA_AV_STATE)key_state);
+      status = BT_STATUS_SUCCESS;
+      BTIF_TRACE_DEBUG("%s: succesfully sent passthrough command to BTA",
+                       __func__);
+    } else {
+      status = BT_STATUS_FAIL;
+      BTIF_TRACE_DEBUG("%s: error in fetching transaction", __func__);
+    }
+  } else {
+    status = BT_STATUS_FAIL;
+    BTIF_TRACE_DEBUG("%s: feature not supported", __func__);
+  }
+#else
+  BTIF_TRACE_DEBUG("%s: feature not enabled", __func__);
+#endif
+  return (bt_status_t)status;
+}
+
+static const btrc_interface_t bt_rc_interface = {
+    sizeof(bt_rc_interface),
+    init,
+    get_play_status_rsp,
+    NULL, /* list_player_app_attr_rsp */
+    NULL, /* list_player_app_value_rsp */
+    NULL, /* get_player_app_value_rsp */
+    NULL, /* get_player_app_attr_text_rsp */
+    NULL, /* get_player_app_value_text_rsp */
+    get_element_attr_rsp,
+    NULL, /* set_player_app_value_rsp */
+    register_notification_rsp,
+    set_volume,
+    set_addressed_player_rsp,
+    set_browsed_player_rsp,
+    get_folder_items_list_rsp,
+    change_path_rsp,
+    get_item_attr_rsp,
+    play_item_rsp,
+    get_total_num_of_items_rsp,
+    search_rsp,
+    add_to_now_playing_rsp,
+    cleanup,
+};
+
+static const btrc_ctrl_interface_t bt_rc_ctrl_interface = {
+    sizeof(bt_rc_ctrl_interface),
+    init_ctrl,
+    send_passthrough_cmd,
+    send_groupnavigation_cmd,
+    change_player_app_setting,
+    play_item_cmd,
+    get_playback_state_cmd,
+    get_now_playing_list_cmd,
+    get_folder_list_cmd,
+    get_player_list_cmd,
+    change_folder_path_cmd,
+    set_browsed_player_cmd,
+    set_addressed_player_cmd,
+    set_volume_rsp,
+    volume_change_notification_rsp,
+    cleanup_ctrl,
+};
+
+/*******************************************************************************
+ *
+ * Function         btif_rc_get_interface
+ *
+ * Description      Get the AVRCP Target callback interface
+ *
+ * Returns          btrc_interface_t
+ *
+ ******************************************************************************/
+const btrc_interface_t* btif_rc_get_interface(void) {
+  BTIF_TRACE_EVENT("%s: ", __func__);
+  return &bt_rc_interface;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_rc_ctrl_get_interface
+ *
+ * Description      Get the AVRCP Controller callback interface
+ *
+ * Returns          btrc_ctrl_interface_t
+ *
+ ******************************************************************************/
+const btrc_ctrl_interface_t* btif_rc_ctrl_get_interface(void) {
+  BTIF_TRACE_EVENT("%s: ", __func__);
+  return &bt_rc_ctrl_interface;
+}
+
+/*******************************************************************************
+ *      Function         initialize_transaction
+ *
+ *      Description    Initializes fields of the transaction structure
+ *
+ *      Returns          void
+ ******************************************************************************/
+static void initialize_transaction(int lbl) {
+  std::unique_lock<std::recursive_mutex>(device.lbllock);
+  if (lbl < MAX_TRANSACTIONS_PER_SESSION) {
+    if (alarm_is_scheduled(device.transaction[lbl].txn_timer)) {
+      clear_cmd_timeout(lbl);
+    }
+    device.transaction[lbl].lbl = lbl;
+    device.transaction[lbl].in_use = false;
+    device.transaction[lbl].handle = 0;
+  }
+}
+
+/*******************************************************************************
+ *      Function         lbl_init
+ *
+ *      Description    Initializes label structures and mutexes.
+ *
+ *      Returns         void
+ ******************************************************************************/
+void lbl_init() {
+  memset(&device.transaction, 0, sizeof(device.transaction));
+  init_all_transactions();
+}
+
+/*******************************************************************************
+ *
+ * Function         init_all_transactions
+ *
+ * Description    Initializes all transactions
+ *
+ * Returns          void
+ ******************************************************************************/
+void init_all_transactions() {
+  uint8_t txn_indx = 0;
+  for (txn_indx = 0; txn_indx < MAX_TRANSACTIONS_PER_SESSION; txn_indx++) {
+    initialize_transaction(txn_indx);
+  }
+}
+
+/*******************************************************************************
+ *
+ * Function         get_transaction_by_lbl
+ *
+ * Description    Will return a transaction based on the label. If not inuse
+ *                     will return an error.
+ *
+ * Returns          bt_status_t
+ ******************************************************************************/
+rc_transaction_t* get_transaction_by_lbl(uint8_t lbl) {
+  rc_transaction_t* transaction = NULL;
+  std::unique_lock<std::recursive_mutex> lock(device.lbllock);
+
+  /* Determine if this is a valid label */
+  if (lbl < MAX_TRANSACTIONS_PER_SESSION) {
+    if (false == device.transaction[lbl].in_use) {
+      transaction = NULL;
+    } else {
+      transaction = &(device.transaction[lbl]);
+      BTIF_TRACE_DEBUG("%s: Got transaction.label: %d", __func__, lbl);
+    }
+  }
+
+  return transaction;
+}
+
+/*******************************************************************************
+ *
+ * Function         get_transaction
+ *
+ * Description    Obtains the transaction details.
+ *
+ * Returns          bt_status_t
+ ******************************************************************************/
+
+bt_status_t get_transaction(rc_transaction_t** ptransaction) {
+  bt_status_t result = BT_STATUS_NOMEM;
+  uint8_t i = 0;
+  std::unique_lock<std::recursive_mutex> lock(device.lbllock);
+
+  // Check for unused transactions
+  for (i = 0; i < MAX_TRANSACTIONS_PER_SESSION; i++) {
+    if (false == device.transaction[i].in_use) {
+      BTIF_TRACE_DEBUG("%s: Got transaction.label: %d", __func__,
+                       device.transaction[i].lbl);
+      device.transaction[i].in_use = true;
+      *ptransaction = &(device.transaction[i]);
+      result = BT_STATUS_SUCCESS;
+      break;
+    }
+  }
+
+  return result;
+}
+
+/*******************************************************************************
+ *
+ * Function         release_transaction
+ *
+ * Description    Will release a transaction for reuse
+ *
+ * Returns          bt_status_t
+ ******************************************************************************/
+void release_transaction(uint8_t lbl) {
+  BTIF_TRACE_DEBUG("%s %d", __func__, lbl);
+  rc_transaction_t* transaction = get_transaction_by_lbl(lbl);
+
+  /* If the transaction is in use... */
+  if (transaction != NULL) {
+    BTIF_TRACE_DEBUG("%s: lbl: %d", __func__, lbl);
+    initialize_transaction(lbl);
+  }
+}
+
+/*******************************************************************************
+ *      Function       sleep_ms
+ *
+ *      Description    Sleep the calling thread unconditionally for
+ *                     |timeout_ms| milliseconds.
+ *
+ *      Returns        void
+ ******************************************************************************/
+static void sleep_ms(period_ms_t timeout_ms) {
+  struct timespec delay;
+  delay.tv_sec = timeout_ms / 1000;
+  delay.tv_nsec = 1000 * 1000 * (timeout_ms % 1000);
+
+  OSI_NO_INTR(nanosleep(&delay, &delay));
+}
+
+static bool absolute_volume_disabled() {
+  char volume_disabled[PROPERTY_VALUE_MAX] = {0};
+  osi_property_get("persist.bluetooth.disableabsvol", volume_disabled, "false");
+  if (strncmp(volume_disabled, "true", 4) == 0) {
+    BTIF_TRACE_WARNING("%s: Absolute volume disabled by property", __func__);
+    return true;
+  }
+  return false;
+}
diff --git a/bt/btif/src/btif_sdp.cc b/bt/btif/src/btif_sdp.cc
new file mode 100644
index 0000000..6c337f5
--- /dev/null
+++ b/bt/btif/src/btif_sdp.cc
@@ -0,0 +1,177 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Samsung System LSI
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ *  Filename:      btif_sdp.c
+ *  Description:   SDP Bluetooth Interface.
+ *                 Implements the generic message handling and search
+ *                 functionality.
+ *                 References btif_sdp_server.c for SDP record creation.
+ *
+ ***********************************************************************************/
+
+#define LOG_TAG "bt_btif_sdp"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sdp.h>
+
+#include "bta_api.h"
+#include "bta_sdp_api.h"
+#include "btif_common.h"
+#include "btif_profile_queue.h"
+#include "btif_util.h"
+
+/*****************************************************************************
+ *  Functions implemented in sdp_server.c
+ *****************************************************************************/
+bt_status_t sdp_server_init();
+void sdp_server_cleanup();
+bt_status_t create_sdp_record(bluetooth_sdp_record* records,
+                              int* record_handles);
+bt_status_t remove_sdp_record(int record_handle);
+void on_create_record_event(int handle);
+void on_remove_record_event(int handle);
+
+// Utility functions:
+int get_sdp_records_size(bluetooth_sdp_record* in_record, int count);
+void copy_sdp_records(bluetooth_sdp_record* in_records,
+                      bluetooth_sdp_record* out_records, int count);
+
+/*****************************************************************************
+ *  Static variables
+ *****************************************************************************/
+
+static btsdp_callbacks_t* bt_sdp_callbacks = NULL;
+
+static void btif_sdp_search_comp_evt(uint16_t event, char* p_param) {
+  tBTA_SDP_SEARCH_COMP* evt_data = (tBTA_SDP_SEARCH_COMP*)p_param;
+  bt_bdaddr_t addr;
+  BTIF_TRACE_DEBUG("%s:  event = %d", __func__, event);
+
+  if (event != BTA_SDP_SEARCH_COMP_EVT) return;
+
+  bdcpy(addr.address, evt_data->remote_addr);
+
+  HAL_CBACK(bt_sdp_callbacks, sdp_search_cb, (bt_status_t)evt_data->status,
+            &addr, (uint8_t*)(evt_data->uuid.uu.uuid128),
+            evt_data->record_count, evt_data->records);
+}
+
+static void sdp_search_comp_copy_cb(uint16_t event, char* p_dest, char* p_src) {
+  tBTA_SDP_SEARCH_COMP* p_dest_data = (tBTA_SDP_SEARCH_COMP*)p_dest;
+  tBTA_SDP_SEARCH_COMP* p_src_data = (tBTA_SDP_SEARCH_COMP*)p_src;
+
+  if (!p_src) return;
+
+  if (event != BTA_SDP_SEARCH_COMP_EVT) return;
+
+  maybe_non_aligned_memcpy(p_dest_data, p_src_data, sizeof(*p_src_data));
+
+  copy_sdp_records(p_src_data->records, p_dest_data->records,
+                   p_src_data->record_count);
+}
+
+static void sdp_dm_cback(tBTA_SDP_EVT event, tBTA_SDP* p_data,
+                         void* user_data) {
+  switch (event) {
+    case BTA_SDP_SEARCH_COMP_EVT: {
+      int size = sizeof(tBTA_SDP);
+      size += get_sdp_records_size(p_data->sdp_search_comp.records,
+                                   p_data->sdp_search_comp.record_count);
+
+      /* need to deep copy the record content */
+      btif_transfer_context(btif_sdp_search_comp_evt, event, (char*)p_data,
+                            size, sdp_search_comp_copy_cb);
+      break;
+    }
+    case BTA_SDP_CREATE_RECORD_USER_EVT: {
+      on_create_record_event(PTR_TO_INT(user_data));
+      break;
+    }
+    case BTA_SDP_REMOVE_RECORD_USER_EVT: {
+      on_remove_record_event(PTR_TO_INT(user_data));
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+static bt_status_t init(btsdp_callbacks_t* callbacks) {
+  BTIF_TRACE_DEBUG("Sdp Search %s", __func__);
+
+  bt_sdp_callbacks = callbacks;
+  sdp_server_init();
+
+  btif_enable_service(BTA_SDP_SERVICE_ID);
+
+  return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t deinit() {
+  BTIF_TRACE_DEBUG("Sdp Search %s", __func__);
+
+  bt_sdp_callbacks = NULL;
+  sdp_server_cleanup();
+  btif_disable_service(BTA_SDP_SERVICE_ID);
+
+  return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t search(bt_bdaddr_t* bd_addr, const uint8_t* uuid) {
+  tSDP_UUID sdp_uuid;
+  sdp_uuid.len = 16;
+  memcpy(sdp_uuid.uu.uuid128, uuid, sizeof(sdp_uuid.uu.uuid128));
+
+  BTA_SdpSearch(bd_addr->address, &sdp_uuid);
+
+  return BT_STATUS_SUCCESS;
+}
+
+static const btsdp_interface_t sdp_if = {
+    sizeof(btsdp_interface_t), init, deinit, search, create_sdp_record,
+    remove_sdp_record};
+
+const btsdp_interface_t* btif_sdp_get_interface(void) {
+  BTIF_TRACE_DEBUG("%s", __func__);
+  return &sdp_if;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_sdp_execute_service
+ *
+ * Description      Initializes/Shuts down the service
+ *
+ * Returns          BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_sdp_execute_service(bool b_enable) {
+  BTIF_TRACE_DEBUG("%s enable:%d", __func__, b_enable);
+
+  if (b_enable) {
+    BTA_SdpEnable(sdp_dm_cback);
+  } else {
+    /* This is called on BT disable so no need to extra cleanup */
+  }
+  return BT_STATUS_SUCCESS;
+}
diff --git a/bt/btif/src/btif_sdp_server.cc b/bt/btif/src/btif_sdp_server.cc
new file mode 100644
index 0000000..4830e66
--- /dev/null
+++ b/bt/btif/src/btif_sdp_server.cc
@@ -0,0 +1,762 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Samsung System LSI
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ *  Filename:      btif_sdp_server.cc
+ *  Description:   SDP server Bluetooth Interface to create and remove SDP
+ *                 records.
+ *                 To be used in combination with the RFCOMM/L2CAP(LE) sockets.
+ *
+ *
+ ***********************************************************************************/
+
+#define LOG_TAG "bt_btif_sdp_server"
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <mutex>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sdp.h>
+
+#include "bta_sdp_api.h"
+#include "bta_sys.h"
+#include "btif_common.h"
+#include "btif_sock_util.h"
+#include "btif_util.h"
+#include "osi/include/allocator.h"
+#include "utl.h"
+
+// Protects the sdp_slots array from concurrent access.
+static std::recursive_mutex sdp_lock;
+
+/**
+ * The need for a state variable have been reduced to two states.
+ * The remaining state control is handled by program flow
+ */
+typedef enum {
+  SDP_RECORD_FREE = 0,
+  SDP_RECORD_ALLOCED,
+} sdp_state_t;
+
+typedef struct {
+  sdp_state_t state;
+  int sdp_handle;
+  bluetooth_sdp_record* record_data;
+} sdp_slot_t;
+
+#define MAX_SDP_SLOTS 128
+static sdp_slot_t sdp_slots[MAX_SDP_SLOTS];
+
+/*****************************************************************************
+ * LOCAL Functions
+ *****************************************************************************/
+static int add_maps_sdp(const bluetooth_sdp_mas_record* rec);
+static int add_mapc_sdp(const bluetooth_sdp_mns_record* rec);
+static int add_pbaps_sdp(const bluetooth_sdp_pse_record* rec);
+static int add_opps_sdp(const bluetooth_sdp_ops_record* rec);
+static int add_saps_sdp(const bluetooth_sdp_sap_record* rec);
+bt_status_t remove_sdp_record(int record_id);
+static int free_sdp_slot(int id);
+
+/******************************************************************************
+ * WARNING: Functions below are not called in BTU context.
+ * Introduced to make it possible to create SDP records from JAVA with both a
+ * RFCOMM channel and a L2CAP PSM.
+ * Overall architecture:
+ *  1) JAVA calls createRecord() which returns a pseudo ID which at a later
+ *     point will be linked to a specific SDP handle.
+ *  2) createRecord() requests the BTU task(thread) to call a callback in SDP
+ *     which creates the actual record, and updates the ID<->SDPHandle map
+ *     based on the ID beeing passed to BTA as user_data.
+ *****************************************************************************/
+
+static void init_sdp_slots() {
+  int i;
+  memset(sdp_slots, 0, sizeof(sdp_slot_t) * MAX_SDP_SLOTS);
+  /* if SDP_RECORD_FREE is zero - no need to set the value */
+  if (SDP_RECORD_FREE != 0) {
+    for (i = 0; i < MAX_SDP_SLOTS; i++) {
+      sdp_slots[i].state = SDP_RECORD_FREE;
+    }
+  }
+}
+
+bt_status_t sdp_server_init() {
+  BTIF_TRACE_DEBUG("Sdp Server %s", __func__);
+  init_sdp_slots();
+  return BT_STATUS_SUCCESS;
+}
+
+void sdp_server_cleanup() {
+  BTIF_TRACE_DEBUG("Sdp Server %s", __func__);
+  std::unique_lock<std::recursive_mutex> lock(sdp_lock);
+  int i;
+  for (i = 0; i < MAX_SDP_SLOTS; i++) {
+    /*remove_sdp_record(i); we cannot send messages to the other threads, since
+    * they might
+    *                       have been shut down already. Just do local cleanup.
+    */
+    free_sdp_slot(i);
+  }
+}
+
+int get_sdp_records_size(bluetooth_sdp_record* in_record, int count) {
+  bluetooth_sdp_record* record = in_record;
+  int records_size = 0;
+  int i;
+  for (i = 0; i < count; i++) {
+    record = &in_record[i];
+    records_size += sizeof(bluetooth_sdp_record);
+    records_size += record->hdr.service_name_length;
+    if (record->hdr.service_name_length > 0) {
+      records_size++; /* + '\0' termination of string */
+    }
+    records_size += record->hdr.user1_ptr_len;
+    records_size += record->hdr.user2_ptr_len;
+  }
+  return records_size;
+}
+
+/* Deep copy all content of in_records into out_records.
+ * out_records must point to a chunk of memory large enough to contain all
+ * the data. Use getSdpRecordsSize() to calculate the needed size. */
+void copy_sdp_records(bluetooth_sdp_record* in_records,
+                      bluetooth_sdp_record* out_records, int count) {
+  int i;
+  bluetooth_sdp_record* in_record;
+  bluetooth_sdp_record* out_record;
+  char* free_ptr =
+      (char*)(&out_records[count]); /* set pointer to after the last entry */
+
+  for (i = 0; i < count; i++) {
+    in_record = &in_records[i];
+    out_record = &out_records[i];
+    *out_record = *in_record;
+
+    if (in_record->hdr.service_name == NULL ||
+        in_record->hdr.service_name_length == 0) {
+      out_record->hdr.service_name = NULL;
+      out_record->hdr.service_name_length = 0;
+    } else {
+      out_record->hdr.service_name = free_ptr;  // Update service_name pointer
+      // Copy string
+      memcpy(free_ptr, in_record->hdr.service_name,
+             in_record->hdr.service_name_length);
+      free_ptr += in_record->hdr.service_name_length;
+      *(free_ptr) = '\0';  // Set '\0' termination of string
+      free_ptr++;
+    }
+    if (in_record->hdr.user1_ptr != NULL) {
+      out_record->hdr.user1_ptr = (uint8_t*)free_ptr;  // Update pointer
+      memcpy(free_ptr, in_record->hdr.user1_ptr,
+             in_record->hdr.user1_ptr_len);  // Copy content
+      free_ptr += in_record->hdr.user1_ptr_len;
+    }
+    if (in_record->hdr.user2_ptr != NULL) {
+      out_record->hdr.user2_ptr = (uint8_t*)free_ptr;  // Update pointer
+      memcpy(free_ptr, in_record->hdr.user2_ptr,
+             in_record->hdr.user2_ptr_len);  // Copy content
+      free_ptr += in_record->hdr.user2_ptr_len;
+    }
+  }
+  return;
+}
+
+/* Reserve a slot in sdp_slots, copy data and set a reference to the copy.
+ * The record_data will contain both the record and any data pointed to by
+ * the record.
+ * Currently this covers:
+ *   service_name string,
+ *   user1_ptr and
+ *   user2_ptr. */
+static int alloc_sdp_slot(bluetooth_sdp_record* in_record) {
+  int record_size = get_sdp_records_size(in_record, 1);
+  /* We are optimists here, and preallocate the record.
+   * This is to reduce the time we hold the sdp_lock. */
+  bluetooth_sdp_record* record = (bluetooth_sdp_record*)osi_malloc(record_size);
+
+  copy_sdp_records(in_record, record, 1);
+  {
+    std::unique_lock<std::recursive_mutex> lock(sdp_lock);
+    for (int i = 0; i < MAX_SDP_SLOTS; i++) {
+      if (sdp_slots[i].state == SDP_RECORD_FREE) {
+        sdp_slots[i].state = SDP_RECORD_ALLOCED;
+        sdp_slots[i].record_data = record;
+        return i;
+      }
+    }
+  }
+  APPL_TRACE_ERROR("%s() failed - no more free slots!", __func__);
+  /* Rearly the optimist is too optimistic, and cleanup is needed...*/
+  osi_free(record);
+  return -1;
+}
+
+static int free_sdp_slot(int id) {
+  int handle = -1;
+  bluetooth_sdp_record* record = NULL;
+  if (id >= MAX_SDP_SLOTS) {
+    APPL_TRACE_ERROR("%s() failed - id %d is invalid", __func__, id);
+    return handle;
+  }
+
+  {
+    std::unique_lock<std::recursive_mutex> lock(sdp_lock);
+    handle = sdp_slots[id].sdp_handle;
+    sdp_slots[id].sdp_handle = 0;
+    if (sdp_slots[id].state != SDP_RECORD_FREE) {
+      /* safe a copy of the pointer, and free after unlock() */
+      record = sdp_slots[id].record_data;
+    }
+    sdp_slots[id].state = SDP_RECORD_FREE;
+  }
+
+  if (record != NULL) {
+    osi_free(record);
+  } else {
+    // Record have already been freed
+    handle = -1;
+  }
+  return handle;
+}
+
+/***
+ * Use this to get a reference to a SDP slot AND change the state to
+ * SDP_RECORD_CREATE_INITIATED.
+ */
+static const sdp_slot_t* start_create_sdp(int id) {
+  if (id >= MAX_SDP_SLOTS) {
+    APPL_TRACE_ERROR("%s() failed - id %d is invalid", __func__, id);
+    return NULL;
+  }
+
+  std::unique_lock<std::recursive_mutex> lock(sdp_lock);
+  if (sdp_slots[id].state != SDP_RECORD_ALLOCED) {
+    /* The record have been removed before this event occurred - e.g. deinit */
+    APPL_TRACE_ERROR(
+        "%s() failed - state for id %d is "
+        "sdp_slots[id].state = %d expected %d",
+        __func__, id, sdp_slots[id].state, SDP_RECORD_ALLOCED);
+    return NULL;
+  }
+
+  return &(sdp_slots[id]);
+}
+
+static void set_sdp_handle(int id, int handle) {
+  std::unique_lock<std::recursive_mutex> lock(sdp_lock);
+  sdp_slots[id].sdp_handle = handle;
+  BTIF_TRACE_DEBUG("%s() id=%d to handle=0x%08x", __func__, id, handle);
+}
+
+bt_status_t create_sdp_record(bluetooth_sdp_record* record,
+                              int* record_handle) {
+  int handle;
+
+  handle = alloc_sdp_slot(record);
+  BTIF_TRACE_DEBUG("%s() handle = 0x%08x", __func__, handle);
+
+  if (handle < 0) return BT_STATUS_FAIL;
+
+  BTA_SdpCreateRecordByUser(INT_TO_PTR(handle));
+
+  *record_handle = handle;
+
+  return BT_STATUS_SUCCESS;
+}
+
+bt_status_t remove_sdp_record(int record_id) {
+  int handle;
+
+  /* Get the Record handle, and free the slot */
+  handle = free_sdp_slot(record_id);
+  BTIF_TRACE_DEBUG("Sdp Server %s id=%d to handle=0x%08x", __func__, record_id,
+                   handle);
+
+  /* Pass the actual record handle */
+  if (handle > 0) {
+    BTA_SdpRemoveRecordByUser(INT_TO_PTR(handle));
+    return BT_STATUS_SUCCESS;
+  }
+  BTIF_TRACE_DEBUG("Sdp Server %s - record already removed - or never created",
+                   __func__);
+  return BT_STATUS_FAIL;
+}
+
+/******************************************************************************
+ * CALLBACK FUNCTIONS
+ * Called in BTA context to create/remove SDP records.
+ ******************************************************************************/
+
+void on_create_record_event(int id) {
+  /*
+   * 1) Fetch the record pointer, and change its state?
+   * 2) switch on the type to create the correct record
+   * 3) Update state on completion
+   * 4) What to do at fail?
+   * */
+  BTIF_TRACE_DEBUG("Sdp Server %s", __func__);
+  const sdp_slot_t* sdp_slot = start_create_sdp(id);
+  /* In the case we are shutting down, sdp_slot is NULL */
+  if (sdp_slot != NULL) {
+    bluetooth_sdp_record* record = sdp_slot->record_data;
+    int handle = -1;
+    switch (record->hdr.type) {
+      case SDP_TYPE_MAP_MAS:
+        handle = add_maps_sdp(&record->mas);
+        break;
+      case SDP_TYPE_MAP_MNS:
+        handle = add_mapc_sdp(&record->mns);
+        break;
+      case SDP_TYPE_PBAP_PSE:
+        handle = add_pbaps_sdp(&record->pse);
+        break;
+      case SDP_TYPE_OPP_SERVER:
+        handle = add_opps_sdp(&record->ops);
+        break;
+      case SDP_TYPE_SAP_SERVER:
+        handle = add_saps_sdp(&record->sap);
+        break;
+      case SDP_TYPE_PBAP_PCE:
+      //        break; not yet supported
+      default:
+        BTIF_TRACE_DEBUG("Record type %d is not supported", record->hdr.type);
+        break;
+    }
+    if (handle != -1) {
+      set_sdp_handle(id, handle);
+    }
+  }
+}
+
+void on_remove_record_event(int handle) {
+  BTIF_TRACE_DEBUG("Sdp Server %s", __func__);
+
+  // User data carries the actual SDP handle, not the ID.
+  if (handle != -1 && handle != 0) {
+    bool result;
+    result = SDP_DeleteRecord(handle);
+    if (result == false) {
+      BTIF_TRACE_ERROR("  Unable to remove handle 0x%08x", handle);
+    }
+  }
+}
+
+/****
+ * Below the actual functions accessing BTA context data - hence only call from
+ * BTA context!
+ */
+
+/* Create a MAP MAS SDP record based on information stored in a
+ * bluetooth_sdp_mas_record */
+static int add_maps_sdp(const bluetooth_sdp_mas_record* rec) {
+  tSDP_PROTOCOL_ELEM protoList[3];
+  uint16_t service = UUID_SERVCLASS_MESSAGE_ACCESS;
+  uint16_t browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+  bool status = true;
+  uint32_t sdp_handle = 0;
+  uint8_t temp[4];
+  uint8_t* p_temp = temp;
+
+  APPL_TRACE_DEBUG(
+      "%s(): MASID = 0x%02x, scn 0x%02x, psm = 0x%04x\n  service name %s",
+      __func__, rec->mas_instance_id, rec->hdr.rfcomm_channel_number,
+      rec->hdr.l2cap_psm, rec->hdr.service_name);
+
+  APPL_TRACE_DEBUG("  msg_types: 0x%02x, feature_bits: 0x%08x",
+                   rec->supported_message_types, rec->supported_features);
+
+  if ((sdp_handle = SDP_CreateRecord()) == 0) {
+    APPL_TRACE_ERROR("%s() - Unable to register MAPS Service", __func__);
+    return sdp_handle;
+  }
+
+  /* add service class */
+  status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
+  memset(protoList, 0, 3 * sizeof(tSDP_PROTOCOL_ELEM));
+
+  /* add protocol list, including RFCOMM scn */
+  protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+  protoList[0].num_params = 0;
+  protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+  protoList[1].num_params = 1;
+  protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
+  protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+  protoList[2].num_params = 0;
+  status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
+
+  /* Add a name entry */
+  status &= SDP_AddAttribute(sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
+                             (uint8_t)TEXT_STR_DESC_TYPE,
+                             (uint32_t)(rec->hdr.service_name_length + 1),
+                             (uint8_t*)rec->hdr.service_name);
+
+  /* Add in the Bluetooth Profile Descriptor List */
+  status &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_MAP_PROFILE,
+                                         rec->hdr.profile_version);
+
+  /* Add MAS instance ID */
+  status &=
+      SDP_AddAttribute(sdp_handle, ATTR_ID_MAS_INSTANCE_ID, UINT_DESC_TYPE,
+                       (uint32_t)1, (uint8_t*)&rec->mas_instance_id);
+
+  /* Add supported message types */
+  status &=
+      SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_MSG_TYPE, UINT_DESC_TYPE,
+                       (uint32_t)1, (uint8_t*)&rec->supported_message_types);
+
+  /* Add supported feature */
+  UINT32_TO_BE_STREAM(p_temp, rec->supported_features);
+  status &= SDP_AddAttribute(sdp_handle, ATTR_ID_MAP_SUPPORTED_FEATURES,
+                             UINT_DESC_TYPE, (uint32_t)4, temp);
+
+  /* Add the L2CAP PSM if present */
+  if (rec->hdr.l2cap_psm != -1) {
+    p_temp = temp;  // The macro modifies p_temp, hence rewind.
+    UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
+    status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
+                               UINT_DESC_TYPE, (uint32_t)2, temp);
+  }
+
+  /* Make the service browseable */
+  status &=
+      SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+
+  if (!status) {
+    SDP_DeleteRecord(sdp_handle);
+    sdp_handle = 0;
+    APPL_TRACE_ERROR("%s() FAILED", __func__);
+  } else {
+    bta_sys_add_uuid(service); /* UUID_SERVCLASS_MESSAGE_ACCESS */
+    APPL_TRACE_DEBUG("%s():  SDP Registered (handle 0x%08x)", __func__,
+                     sdp_handle);
+  }
+  return sdp_handle;
+}
+
+/* Create a MAP MNS SDP record based on information stored in a
+ * bluetooth_sdp_mns_record */
+static int add_mapc_sdp(const bluetooth_sdp_mns_record* rec) {
+  tSDP_PROTOCOL_ELEM protoList[3];
+  uint16_t service = UUID_SERVCLASS_MESSAGE_NOTIFICATION;
+  uint16_t browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+  bool status = true;
+  uint32_t sdp_handle = 0;
+  uint8_t temp[4];
+  uint8_t* p_temp = temp;
+
+  APPL_TRACE_DEBUG("%s(): scn 0x%02x, psm = 0x%04x\n  service name %s",
+                   __func__, rec->hdr.rfcomm_channel_number, rec->hdr.l2cap_psm,
+                   rec->hdr.service_name);
+
+  APPL_TRACE_DEBUG("  feature_bits: 0x%08x", rec->supported_features);
+
+  if ((sdp_handle = SDP_CreateRecord()) == 0) {
+    APPL_TRACE_ERROR("%s(): Unable to register MAP Notification Service",
+                     __func__);
+    return sdp_handle;
+  }
+
+  /* add service class */
+  status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
+  memset(protoList, 0, 3 * sizeof(tSDP_PROTOCOL_ELEM));
+
+  /* add protocol list, including RFCOMM scn */
+  protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+  protoList[0].num_params = 0;
+  protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+  protoList[1].num_params = 1;
+  protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
+  protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+  protoList[2].num_params = 0;
+  status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
+
+  /* Add a name entry */
+  status &= SDP_AddAttribute(sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
+                             (uint8_t)TEXT_STR_DESC_TYPE,
+                             (uint32_t)(rec->hdr.service_name_length + 1),
+                             (uint8_t*)rec->hdr.service_name);
+
+  /* Add in the Bluetooth Profile Descriptor List */
+  status &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_MAP_PROFILE,
+                                         rec->hdr.profile_version);
+
+  /* Add supported feature */
+  UINT32_TO_BE_STREAM(p_temp, rec->supported_features);
+  status &= SDP_AddAttribute(sdp_handle, ATTR_ID_MAP_SUPPORTED_FEATURES,
+                             UINT_DESC_TYPE, (uint32_t)4, temp);
+
+  /* Add the L2CAP PSM if present */
+  if (rec->hdr.l2cap_psm != -1) {
+    p_temp = temp;  // The macro modifies p_temp, hence rewind.
+    UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
+    status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
+                               UINT_DESC_TYPE, (uint32_t)2, temp);
+  }
+
+  /* Make the service browseable */
+  status &=
+      SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+
+  if (!status) {
+    SDP_DeleteRecord(sdp_handle);
+    sdp_handle = 0;
+    APPL_TRACE_ERROR("%s() FAILED", __func__);
+  } else {
+    bta_sys_add_uuid(service); /* UUID_SERVCLASS_MESSAGE_ACCESS */
+    APPL_TRACE_DEBUG("%s():  SDP Registered (handle 0x%08x)", __func__,
+                     sdp_handle);
+  }
+  return sdp_handle;
+}
+
+/* Create a PBAP Server SDP record based on information stored in a
+ * bluetooth_sdp_pse_record */
+static int add_pbaps_sdp(const bluetooth_sdp_pse_record* rec) {
+  tSDP_PROTOCOL_ELEM protoList[3];
+  uint16_t service = UUID_SERVCLASS_PBAP_PSE;
+  uint16_t browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+  bool status = true;
+  uint32_t sdp_handle = 0;
+  uint8_t temp[4];
+  uint8_t* p_temp = temp;
+
+  APPL_TRACE_DEBUG("%s(): scn 0x%02x, psm = 0x%04x\n  service name %s",
+                   __func__, rec->hdr.rfcomm_channel_number, rec->hdr.l2cap_psm,
+                   rec->hdr.service_name);
+
+  APPL_TRACE_DEBUG("  supported_repositories: 0x%08x, feature_bits: 0x%08x",
+                   rec->supported_repositories, rec->supported_features);
+
+  if ((sdp_handle = SDP_CreateRecord()) == 0) {
+    APPL_TRACE_ERROR("%s(): Unable to register PBAP Server Service", __func__);
+    return sdp_handle;
+  }
+
+  /* add service class */
+  status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
+  memset(protoList, 0, 3 * sizeof(tSDP_PROTOCOL_ELEM));
+
+  /* add protocol list, including RFCOMM scn */
+  protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+  protoList[0].num_params = 0;
+  protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+  protoList[1].num_params = 1;
+  protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
+  protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+  protoList[2].num_params = 0;
+  status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
+
+  /* Add a name entry */
+  status &= SDP_AddAttribute(sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
+                             (uint8_t)TEXT_STR_DESC_TYPE,
+                             (uint32_t)(rec->hdr.service_name_length + 1),
+                             (uint8_t*)rec->hdr.service_name);
+
+  /* Add in the Bluetooth Profile Descriptor List */
+  status &= SDP_AddProfileDescriptorList(
+      sdp_handle, UUID_SERVCLASS_PHONE_ACCESS, rec->hdr.profile_version);
+
+  /* Add supported repositories 1 byte */
+  status &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_REPOSITORIES,
+                             UINT_DESC_TYPE, (uint32_t)1,
+                             (uint8_t*)&rec->supported_repositories);
+
+  /* Add supported feature 4 bytes*/
+  UINT32_TO_BE_STREAM(p_temp, rec->supported_features);
+  status &= SDP_AddAttribute(sdp_handle, ATTR_ID_PBAP_SUPPORTED_FEATURES,
+                             UINT_DESC_TYPE, (uint32_t)4, temp);
+
+  /* Add the L2CAP PSM if present */
+  if (rec->hdr.l2cap_psm != -1) {
+    p_temp = temp;  // The macro modifies p_temp, hence rewind.
+    UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
+    status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
+                               UINT_DESC_TYPE, (uint32_t)2, temp);
+  }
+
+  /* Make the service browseable */
+  status &=
+      SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+
+  if (!status) {
+    SDP_DeleteRecord(sdp_handle);
+    sdp_handle = 0;
+    APPL_TRACE_ERROR("%s() FAILED", __func__);
+  } else {
+    bta_sys_add_uuid(service); /* UUID_SERVCLASS_MESSAGE_ACCESS */
+    APPL_TRACE_DEBUG("%s():  SDP Registered (handle 0x%08x)", __func__,
+                     sdp_handle);
+  }
+  return sdp_handle;
+}
+
+/* Create a OPP Server SDP record based on information stored in a
+ * bluetooth_sdp_ops_record */
+static int add_opps_sdp(const bluetooth_sdp_ops_record* rec) {
+  tSDP_PROTOCOL_ELEM protoList[3];
+  uint16_t service = UUID_SERVCLASS_OBEX_OBJECT_PUSH;
+  uint16_t browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+  uint8_t type_len[rec->supported_formats_list_len];
+  uint8_t desc_type[rec->supported_formats_list_len];
+  uint8_t* type_value[rec->supported_formats_list_len];
+  bool status = true;
+  uint32_t sdp_handle = 0;
+  uint8_t temp[4];
+  uint8_t* p_temp = temp;
+  tBTA_UTL_COD cod;
+  int i, j;
+
+  APPL_TRACE_DEBUG("%s(): scn 0x%02x, psm = 0x%04x\n  service name %s",
+                   __func__, rec->hdr.rfcomm_channel_number, rec->hdr.l2cap_psm,
+                   rec->hdr.service_name);
+
+  APPL_TRACE_DEBUG("  supported formats count: %d",
+                   rec->supported_formats_list_len);
+
+  if ((sdp_handle = SDP_CreateRecord()) == 0) {
+    APPL_TRACE_ERROR("%s(): Unable to register Object Push Server Service",
+                     __func__);
+    return sdp_handle;
+  }
+
+  /* add service class */
+  status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
+  memset(protoList, 0, 3 * sizeof(tSDP_PROTOCOL_ELEM));
+
+  /* add protocol list, including RFCOMM scn */
+  protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+  protoList[0].num_params = 0;
+  protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+  protoList[1].num_params = 1;
+  protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
+  protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+  protoList[2].num_params = 0;
+  status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
+
+  /* Add a name entry */
+  status &= SDP_AddAttribute(sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
+                             (uint8_t)TEXT_STR_DESC_TYPE,
+                             (uint32_t)(rec->hdr.service_name_length + 1),
+                             (uint8_t*)rec->hdr.service_name);
+
+  /* Add in the Bluetooth Profile Descriptor List */
+  status &= SDP_AddProfileDescriptorList(
+      sdp_handle, UUID_SERVCLASS_OBEX_OBJECT_PUSH, rec->hdr.profile_version);
+
+  /* add sequence for supported types */
+  for (i = 0, j = 0; i < rec->supported_formats_list_len; i++) {
+    type_value[j] = (uint8_t*)&rec->supported_formats_list[i];
+    desc_type[j] = UINT_DESC_TYPE;
+    type_len[j++] = 1;
+  }
+
+  status &=
+      SDP_AddSequence(sdp_handle, (uint16_t)ATTR_ID_SUPPORTED_FORMATS_LIST,
+                      (uint8_t)rec->supported_formats_list_len, desc_type,
+                      type_len, type_value);
+
+  /* Add the L2CAP PSM if present */
+  if (rec->hdr.l2cap_psm != -1) {
+    p_temp = temp;  // The macro modifies p_temp, hence rewind.
+    UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
+    status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
+                               UINT_DESC_TYPE, (uint32_t)2, temp);
+  }
+
+  /* Make the service browseable */
+  status &=
+      SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+
+  if (!status) {
+    SDP_DeleteRecord(sdp_handle);
+    sdp_handle = 0;
+    APPL_TRACE_ERROR("%s() FAILED", __func__);
+  } else {
+    /* set class of device */
+    cod.service = BTM_COD_SERVICE_OBJ_TRANSFER;
+    utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
+
+    bta_sys_add_uuid(service); /* UUID_SERVCLASS_OBEX_OBJECT_PUSH */
+    APPL_TRACE_DEBUG("%s():  SDP Registered (handle 0x%08x)", __func__,
+                     sdp_handle);
+  }
+  return sdp_handle;
+}
+
+// Create a Sim Access Profile SDP record based on information stored in a
+// bluetooth_sdp_sap_record.
+static int add_saps_sdp(const bluetooth_sdp_sap_record* rec) {
+  tSDP_PROTOCOL_ELEM protoList[2];
+  uint16_t services[2];
+  uint16_t browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+  bool status = true;
+  uint32_t sdp_handle = 0;
+
+  APPL_TRACE_DEBUG("%s(): scn 0x%02x, service name %s", __func__,
+                   rec->hdr.rfcomm_channel_number, rec->hdr.service_name);
+
+  if ((sdp_handle = SDP_CreateRecord()) == 0) {
+    APPL_TRACE_ERROR("%s(): Unable to register SAPS Service", __func__);
+    return sdp_handle;
+  }
+
+  services[0] = UUID_SERVCLASS_SAP;
+  services[1] = UUID_SERVCLASS_GENERIC_TELEPHONY;
+
+  // add service class
+  status &= SDP_AddServiceClassIdList(sdp_handle, 2, services);
+  memset(protoList, 0, 2 * sizeof(tSDP_PROTOCOL_ELEM));
+
+  // add protocol list, including RFCOMM scn
+  protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+  protoList[0].num_params = 0;
+  protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+  protoList[1].num_params = 1;
+  protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
+  status &= SDP_AddProtocolList(sdp_handle, 2, protoList);
+
+  // Add a name entry
+  status &= SDP_AddAttribute(sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
+                             (uint8_t)TEXT_STR_DESC_TYPE,
+                             (uint32_t)(rec->hdr.service_name_length + 1),
+                             (uint8_t*)rec->hdr.service_name);
+
+  // Add in the Bluetooth Profile Descriptor List
+  status &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_SAP,
+                                         rec->hdr.profile_version);
+
+  // Make the service browseable
+  status &=
+      SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+
+  if (!status) {
+    SDP_DeleteRecord(sdp_handle);
+    sdp_handle = 0;
+    APPL_TRACE_ERROR("%s(): FAILED deleting record", __func__);
+  } else {
+    bta_sys_add_uuid(UUID_SERVCLASS_SAP);
+    APPL_TRACE_DEBUG("%s(): SDP Registered (handle 0x%08x)", __func__,
+                     sdp_handle);
+  }
+  return sdp_handle;
+}
diff --git a/bt/btif/src/btif_sm.cc b/bt/btif/src/btif_sm.cc
new file mode 100644
index 0000000..8f7bbb2
--- /dev/null
+++ b/bt/btif/src/btif_sm.cc
@@ -0,0 +1,181 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ *  Filename:      btif_sm.c
+ *
+ *  Description:   Generic BTIF state machine API
+ *
+ *****************************************************************************/
+
+#define LOG_TAG "bt_btif"
+
+#include "btif_sm.h"
+
+#include "bt_common.h"
+#include "btif_common.h"
+#include "osi/include/allocator.h"
+
+/*****************************************************************************
+ *  Local type definitions
+ *****************************************************************************/
+typedef struct {
+  btif_sm_state_t state;
+  btif_sm_handler_t* p_handlers;
+} btif_sm_cb_t;
+
+/*****************************************************************************
+ *  Functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ *
+ * Function     btif_sm_init
+ *
+ * Description  Initializes the state machine with the state handlers
+ *              The caller should ensure that the table and the corresponding
+ *              states match. The location that 'p_handlers' points to shall
+ *              be available until the btif_sm_shutdown API is invoked.
+ *
+ * Returns      Returns a pointer to the initialized state machine handle.
+ *
+ *****************************************************************************/
+
+btif_sm_handle_t btif_sm_init(const btif_sm_handler_t* p_handlers,
+                              btif_sm_state_t initial_state) {
+  if (p_handlers == NULL) {
+    BTIF_TRACE_ERROR("%s : p_handlers is NULL", __func__);
+    return NULL;
+  }
+
+  btif_sm_cb_t* p_cb = (btif_sm_cb_t*)osi_malloc(sizeof(btif_sm_cb_t));
+  p_cb->state = initial_state;
+  p_cb->p_handlers = (btif_sm_handler_t*)p_handlers;
+
+  /* Send BTIF_SM_ENTER_EVT to the initial state */
+  p_cb->p_handlers[initial_state](BTIF_SM_ENTER_EVT, NULL);
+
+  return (btif_sm_handle_t)p_cb;
+}
+
+/*****************************************************************************
+ *
+ * Function     btif_sm_shutdown
+ *
+ * Description  Tears down the state machine
+ *
+ * Returns      None
+ *
+ *****************************************************************************/
+void btif_sm_shutdown(btif_sm_handle_t handle) {
+  btif_sm_cb_t* p_cb = (btif_sm_cb_t*)handle;
+
+  if (p_cb == NULL) {
+    BTIF_TRACE_ERROR("%s : Invalid handle", __func__);
+    return;
+  }
+  osi_free(p_cb);
+}
+
+/*****************************************************************************
+ *
+ * Function     btif_sm_get_state
+ *
+ * Description  Fetches the current state of the state machine
+ *
+ * Returns      Current state
+ *
+ *****************************************************************************/
+btif_sm_state_t btif_sm_get_state(btif_sm_handle_t handle) {
+  btif_sm_cb_t* p_cb = (btif_sm_cb_t*)handle;
+
+  if (p_cb == NULL) {
+    BTIF_TRACE_ERROR("%s : Invalid handle", __func__);
+    return 0;
+  }
+
+  return p_cb->state;
+}
+
+/*****************************************************************************
+ *
+ * Function     btif_sm_dispatch
+ *
+ * Description  Dispatches the 'event' along with 'data' to the current state
+ *              handler
+ *
+ * Returns      BT_STATUS_SUCCESS on success
+ *              BT_STATUS_UNHANDLED if event was not processed
+ *              BT_STATUS_FAIL otherwise
+ *
+ *****************************************************************************/
+bt_status_t btif_sm_dispatch(btif_sm_handle_t handle, btif_sm_event_t event,
+                             void* data) {
+  bt_status_t status = BT_STATUS_SUCCESS;
+
+  btif_sm_cb_t* p_cb = (btif_sm_cb_t*)handle;
+
+  if (p_cb == NULL) {
+    BTIF_TRACE_ERROR("%s : Invalid handle", __func__);
+    return BT_STATUS_FAIL;
+  }
+
+  if (p_cb->p_handlers[p_cb->state](event, data) == false)
+    return BT_STATUS_UNHANDLED;
+
+  return status;
+}
+
+/*****************************************************************************
+ *
+ * Function     btif_sm_change_state
+ *
+ * Description  Make a transition to the new 'state'. The 'BTIF_SM_EXIT_EVT'
+ *              shall be invoked before exiting the current state. The
+ *              'BTIF_SM_ENTER_EVT' shall be invoked before entering the new
+ *              state
+ *
+ * Returns      BT_STATUS_SUCCESS on success
+ *              BT_STATUS_UNHANDLED if event was not processed
+ *              BT_STATUS_FAIL otherwise
+ *
+ *****************************************************************************/
+bt_status_t btif_sm_change_state(btif_sm_handle_t handle,
+                                 btif_sm_state_t state) {
+  bt_status_t status = BT_STATUS_SUCCESS;
+  btif_sm_cb_t* p_cb = (btif_sm_cb_t*)handle;
+
+  if (p_cb == NULL) {
+    BTIF_TRACE_ERROR("%s : Invalid handle", __func__);
+    return BT_STATUS_FAIL;
+  }
+
+  /* Send exit event to the current state */
+  if (p_cb->p_handlers[p_cb->state](BTIF_SM_EXIT_EVT, NULL) == false)
+    status = BT_STATUS_UNHANDLED;
+
+  /* Change to the new state */
+  p_cb->state = state;
+
+  /* Send enter event to the new state */
+  if (p_cb->p_handlers[p_cb->state](BTIF_SM_ENTER_EVT, NULL) == false)
+    status = BT_STATUS_UNHANDLED;
+
+  return status;
+}
diff --git a/bt/btif/src/btif_sock.cc b/bt/btif/src/btif_sock.cc
new file mode 100644
index 0000000..deeddb7
--- /dev/null
+++ b/bt/btif/src/btif_sock.cc
@@ -0,0 +1,203 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_btif_sock"
+
+#include <assert.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+
+#include "bta_api.h"
+#include "btif_common.h"
+#include "btif_sock_l2cap.h"
+#include "btif_sock_rfc.h"
+#include "btif_sock_sco.h"
+#include "btif_sock_sdp.h"
+#include "btif_sock_thread.h"
+#include "btif_uid.h"
+#include "btif_util.h"
+#include "osi/include/thread.h"
+
+static bt_status_t btsock_listen(btsock_type_t type, const char* service_name,
+                                 const uint8_t* uuid, int channel, int* sock_fd,
+                                 int flags, int app_uid);
+static bt_status_t btsock_connect(const bt_bdaddr_t* bd_addr,
+                                  btsock_type_t type, const uint8_t* uuid,
+                                  int channel, int* sock_fd, int flags,
+                                  int app_uid);
+
+static void btsock_signaled(int fd, int type, int flags, uint32_t user_id);
+
+static int thread_handle = -1;
+static thread_t* thread;
+
+btsock_interface_t* btif_sock_get_interface(void) {
+  static btsock_interface_t interface = {sizeof(interface), btsock_listen,
+                                         btsock_connect};
+
+  return &interface;
+}
+
+bt_status_t btif_sock_init(uid_set_t* uid_set) {
+  assert(thread_handle == -1);
+  assert(thread == NULL);
+
+  bt_status_t status;
+  btsock_thread_init();
+  thread_handle = btsock_thread_create(btsock_signaled, NULL);
+  if (thread_handle == -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to create btsock_thread.", __func__);
+    goto error;
+  }
+
+  status = btsock_rfc_init(thread_handle, uid_set);
+  if (status != BT_STATUS_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s error initializing RFCOMM sockets: %d", __func__,
+              status);
+    goto error;
+  }
+
+  status = btsock_l2cap_init(thread_handle, uid_set);
+  if (status != BT_STATUS_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s error initializing L2CAP sockets: %d", __func__,
+              status);
+    goto error;
+  }
+
+  thread = thread_new("btif_sock");
+  if (!thread) {
+    LOG_ERROR(LOG_TAG, "%s error creating new thread.", __func__);
+    btsock_rfc_cleanup();
+    goto error;
+  }
+
+  status = btsock_sco_init(thread);
+  if (status != BT_STATUS_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s error initializing SCO sockets: %d", __func__,
+              status);
+    btsock_rfc_cleanup();
+    goto error;
+  }
+
+  return BT_STATUS_SUCCESS;
+
+error:;
+  thread_free(thread);
+  thread = NULL;
+  if (thread_handle != -1) btsock_thread_exit(thread_handle);
+  thread_handle = -1;
+  uid_set = NULL;
+  return BT_STATUS_FAIL;
+}
+
+void btif_sock_cleanup(void) {
+  if (thread_handle == -1) return;
+
+  thread_stop(thread);
+  thread_join(thread);
+  btsock_thread_exit(thread_handle);
+  btsock_rfc_cleanup();
+  btsock_sco_cleanup();
+  btsock_l2cap_cleanup();
+  thread_free(thread);
+  thread_handle = -1;
+  thread = NULL;
+}
+
+static bt_status_t btsock_listen(btsock_type_t type, const char* service_name,
+                                 const uint8_t* service_uuid, int channel,
+                                 int* sock_fd, int flags, int app_uid) {
+  if ((flags & BTSOCK_FLAG_NO_SDP) == 0) {
+    assert(service_uuid != NULL || channel > 0);
+    assert(sock_fd != NULL);
+  }
+
+  *sock_fd = INVALID_FD;
+  bt_status_t status = BT_STATUS_FAIL;
+
+  switch (type) {
+    case BTSOCK_RFCOMM:
+      status = btsock_rfc_listen(service_name, service_uuid, channel, sock_fd,
+                                 flags, app_uid);
+      break;
+    case BTSOCK_L2CAP:
+      status =
+          btsock_l2cap_listen(service_name, channel, sock_fd, flags, app_uid);
+      break;
+
+    case BTSOCK_SCO:
+      status = btsock_sco_listen(sock_fd, flags);
+      break;
+
+    default:
+      LOG_ERROR(LOG_TAG, "%s unknown/unsupported socket type: %d", __func__,
+                type);
+      status = BT_STATUS_UNSUPPORTED;
+      break;
+  }
+  return status;
+}
+
+static bt_status_t btsock_connect(const bt_bdaddr_t* bd_addr,
+                                  btsock_type_t type, const uint8_t* uuid,
+                                  int channel, int* sock_fd, int flags,
+                                  int app_uid) {
+  assert(uuid != NULL || channel > 0);
+  assert(bd_addr != NULL);
+  assert(sock_fd != NULL);
+
+  *sock_fd = INVALID_FD;
+  bt_status_t status = BT_STATUS_FAIL;
+
+  switch (type) {
+    case BTSOCK_RFCOMM:
+      status =
+          btsock_rfc_connect(bd_addr, uuid, channel, sock_fd, flags, app_uid);
+      break;
+
+    case BTSOCK_L2CAP:
+      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);
+      break;
+
+    default:
+      LOG_ERROR(LOG_TAG, "%s unknown/unsupported socket type: %d", __func__,
+                type);
+      status = BT_STATUS_UNSUPPORTED;
+      break;
+  }
+  return status;
+}
+
+static void btsock_signaled(int fd, int type, int flags, uint32_t user_id) {
+  switch (type) {
+    case BTSOCK_RFCOMM:
+      btsock_rfc_signaled(fd, flags, user_id);
+      break;
+    case BTSOCK_L2CAP:
+      btsock_l2cap_signaled(fd, flags, user_id);
+      break;
+    default:
+      assert(false && "Invalid socket type");
+      break;
+  }
+}
diff --git a/bt/btif/src/btif_sock_l2cap.cc b/bt/btif/src/btif_sock_l2cap.cc
new file mode 100644
index 0000000..6587b73
--- /dev/null
+++ b/bt/btif/src/btif_sock_l2cap.cc
@@ -0,0 +1,1101 @@
+/*
+* Copyright (C) 2014 Samsung System LSI
+* Copyright (C) 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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_btif_sock"
+
+#include "btif_sock_l2cap.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <mutex>
+
+#include <hardware/bt_sock.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bta_api.h"
+#include "bta_jv_api.h"
+#include "bta_jv_co.h"
+#include "btif_common.h"
+#include "btif_sock_sdp.h"
+#include "btif_sock_thread.h"
+#include "btif_sock_util.h"
+#include "btif_uid.h"
+#include "btif_util.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "hcimsgs.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "port_api.h"
+#include "sdp_api.h"
+
+#define asrt(s)                                                              \
+  do {                                                                       \
+    if (!(s))                                                                \
+      APPL_TRACE_ERROR("## %s assert %s failed at line:%d ##", __func__, #s, \
+                       __LINE__)                                             \
+  } while (0)
+
+struct packet {
+  struct packet *next, *prev;
+  uint32_t len;
+  uint8_t* data;
+};
+
+typedef struct l2cap_socket {
+  struct l2cap_socket* prev;  // link to prev list item
+  struct l2cap_socket* next;  // link to next list item
+  bt_bdaddr_t addr;           // other side's address
+  char name[256];             // user-friendly name of the service
+  uint32_t id;                // just a tag to find this struct
+  int app_uid;                // The UID of the app who requested this socket
+  int handle;                 // handle from lower layers
+  unsigned security;          // security flags
+  int channel;                // channel (fixed_chan) or PSM (!fixed_chan)
+  int our_fd;                 // fd from our side
+  int app_fd;                 // fd from app's side
+
+  unsigned bytes_buffered;
+  struct packet* first_packet;  // fist packet to be delivered to app
+  struct packet* last_packet;   // last packet to be delivered to app
+
+  fixed_queue_t* incoming_que;    // data that came in but has not yet been read
+  unsigned fixed_chan : 1;        // fixed channel (or psm?)
+  unsigned server : 1;            // is a server? (or connecting?)
+  unsigned connected : 1;         // is connected?
+  unsigned outgoing_congest : 1;  // should we hold?
+  unsigned server_psm_sent : 1;   // The server shall only send PSM once.
+  bool is_le_coc;                 // is le connection oriented channel?
+} l2cap_socket;
+
+static bt_status_t btSock_start_l2cap_server_l(l2cap_socket* sock);
+
+static std::mutex state_lock;
+
+l2cap_socket* socks = NULL;
+static uid_set_t* uid_set = NULL;
+static int pth = -1;
+
+static void btsock_l2cap_cbk(tBTA_JV_EVT event, tBTA_JV* p_data,
+                             void* user_data);
+
+/* TODO: Consider to remove this buffer, as we have a buffer in l2cap as well,
+ * and we risk
+ *       a buffer overflow with this implementation if the socket data is not
+ * read from
+ *       JAVA for a while. In such a case we should use flow control to tell the
+ * sender to
+ *       back off.
+ *       BUT remember we need to avoid blocking the BTA task execution - hence
+ * we cannot
+ *       directly write to the socket.
+ *       we should be able to change to store the data pointer here, and just
+ * wait
+ *       confirming the l2cap_ind until we have more space in the buffer. */
+
+/* returns false if none - caller must free "data" memory when done with it */
+static char packet_get_head_l(l2cap_socket* sock, uint8_t** data,
+                              uint32_t* len) {
+  struct packet* p = sock->first_packet;
+
+  if (!p) return false;
+
+  if (data) *data = sock->first_packet->data;
+  if (len) *len = sock->first_packet->len;
+  sock->first_packet = p->next;
+  if (sock->first_packet)
+    sock->first_packet->prev = NULL;
+  else
+    sock->last_packet = NULL;
+
+  if (len) sock->bytes_buffered -= *len;
+
+  osi_free(p);
+
+  return true;
+}
+
+static struct packet* packet_alloc(const uint8_t* data, uint32_t len) {
+  struct packet* p = (struct packet*)osi_calloc(sizeof(*p));
+  uint8_t* buf = (uint8_t*)osi_malloc(len);
+
+  p->data = buf;
+  p->len = len;
+  memcpy(p->data, data, len);
+  return p;
+}
+
+/* makes a copy of the data, returns true on success */
+static char packet_put_head_l(l2cap_socket* sock, const void* data,
+                              uint32_t len) {
+  struct packet* p = packet_alloc((const uint8_t*)data, len);
+
+  /*
+   * We do not check size limits here since this is used to undo "getting" a
+   * packet that the user read incompletely. That is to say the packet was
+   * already in the queue. We do check thos elimits in packet_put_tail_l() since
+   * that function is used to put new data into the queue.
+   */
+
+  if (!p) return false;
+
+  p->prev = NULL;
+  p->next = sock->first_packet;
+  sock->first_packet = p;
+  if (p->next)
+    p->next->prev = p;
+  else
+    sock->last_packet = p;
+
+  sock->bytes_buffered += len;
+
+  return true;
+}
+
+/* makes a copy of the data, returns true on success */
+static char packet_put_tail_l(l2cap_socket* sock, const void* data,
+                              uint32_t len) {
+  struct packet* p = packet_alloc((const uint8_t*)data, len);
+
+  if (sock->bytes_buffered >= L2CAP_MAX_RX_BUFFER) {
+    LOG_ERROR(LOG_TAG, "packet_put_tail_l: buffer overflow");
+    return false;
+  }
+
+  if (!p) {
+    LOG_ERROR(LOG_TAG, "packet_put_tail_l: unable to allocate packet...");
+    return false;
+  }
+
+  p->next = NULL;
+  p->prev = sock->last_packet;
+  sock->last_packet = p;
+  if (p->prev)
+    p->prev->next = p;
+  else
+    sock->first_packet = p;
+
+  sock->bytes_buffered += len;
+
+  return true;
+}
+
+static inline void bd_copy(uint8_t* dest, uint8_t* src, bool swap) {
+  if (swap) {
+    for (int i = 0; i < 6; i++) dest[i] = src[5 - i];
+  } else {
+    memcpy(dest, src, 6);
+  }
+}
+
+static char is_inited(void) {
+  std::unique_lock<std::mutex> lock(state_lock);
+  return pth != -1;
+}
+
+/* only call with std::mutex taken */
+static l2cap_socket* btsock_l2cap_find_by_id_l(uint32_t id) {
+  l2cap_socket* sock = socks;
+
+  while (sock && sock->id != id) sock = sock->next;
+
+  return sock;
+}
+
+static void btsock_l2cap_free_l(l2cap_socket* sock) {
+  uint8_t* buf;
+  l2cap_socket* t = socks;
+
+  while (t && t != sock) t = t->next;
+
+  if (!t) /* prever double-frees */
+    return;
+
+  if (sock->next) sock->next->prev = sock->prev;
+
+  if (sock->prev)
+    sock->prev->next = sock->next;
+  else
+    socks = sock->next;
+
+  shutdown(sock->our_fd, SHUT_RDWR);
+  close(sock->our_fd);
+  if (sock->app_fd != -1) {
+    close(sock->app_fd);
+  } else {
+    APPL_TRACE_ERROR("SOCK_LIST: free(id = %d) - NO app_fd!", sock->id);
+  }
+
+  while (packet_get_head_l(sock, &buf, NULL)) osi_free(buf);
+
+  // lower-level close() should be idempotent... so let's call it and see...
+  if (sock->is_le_coc) {
+    // Only call if we are non server connections
+    if (sock->handle >= 0 && (sock->server == false)) {
+      BTA_JvL2capClose(sock->handle);
+    }
+    if ((sock->channel >= 0) && (sock->server == true)) {
+      BTA_JvFreeChannel(sock->channel, BTA_JV_CONN_TYPE_L2CAP);
+    }
+  } else {
+    // Only call if we are non server connections
+    if ((sock->handle >= 0) && (sock->server == false)) {
+      if (sock->fixed_chan)
+        BTA_JvL2capCloseLE(sock->handle);
+      else
+        BTA_JvL2capClose(sock->handle);
+    }
+    if ((sock->channel >= 0) && (sock->server == true)) {
+      if (sock->fixed_chan)
+        BTA_JvFreeChannel(sock->channel, BTA_JV_CONN_TYPE_L2CAP_LE);
+      else
+        BTA_JvFreeChannel(sock->channel, BTA_JV_CONN_TYPE_L2CAP);
+
+      if (!sock->fixed_chan) {
+        APPL_TRACE_DEBUG("%s stopping L2CAP server channel %d", __func__,
+                         sock->channel);
+        BTA_JvL2capStopServer(sock->channel, UINT_TO_PTR(sock->id));
+      }
+    }
+  }
+
+  APPL_TRACE_DEBUG("%s: free(id = %d)", __func__, sock->id);
+  osi_free(sock);
+}
+
+static l2cap_socket* btsock_l2cap_alloc_l(const char* name,
+                                          const bt_bdaddr_t* addr,
+                                          char is_server, int flags) {
+  unsigned security = 0;
+  int fds[2];
+  l2cap_socket* sock = (l2cap_socket*)osi_calloc(sizeof(*sock));
+
+  if (flags & BTSOCK_FLAG_ENCRYPT)
+    security |= is_server ? BTM_SEC_IN_ENCRYPT : BTM_SEC_OUT_ENCRYPT;
+  if (flags & BTSOCK_FLAG_AUTH)
+    security |= is_server ? BTM_SEC_IN_AUTHENTICATE : BTM_SEC_OUT_AUTHENTICATE;
+  if (flags & BTSOCK_FLAG_AUTH_MITM)
+    security |= is_server ? BTM_SEC_IN_MITM : BTM_SEC_OUT_MITM;
+  if (flags & BTSOCK_FLAG_AUTH_16_DIGIT)
+    security |= BTM_SEC_IN_MIN_16_DIGIT_PIN;
+
+  if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, fds)) {
+    APPL_TRACE_ERROR("socketpair failed, errno:%d", errno);
+    goto fail_sockpair;
+  }
+
+  sock->our_fd = fds[0];
+  sock->app_fd = fds[1];
+  sock->security = security;
+  sock->server = is_server;
+  sock->connected = false;
+  sock->handle = 0;
+  sock->server_psm_sent = false;
+  sock->app_uid = -1;
+
+  if (name) strncpy(sock->name, name, sizeof(sock->name) - 1);
+  if (addr) sock->addr = *addr;
+
+  sock->first_packet = NULL;
+  sock->last_packet = NULL;
+
+  sock->next = socks;
+  sock->prev = NULL;
+  if (socks) socks->prev = sock;
+  sock->id = (socks ? socks->id : 0) + 1;
+  socks = sock;
+  /* paranoia cap on: verify no ID duplicates due to overflow and fix as needed
+   */
+  while (1) {
+    l2cap_socket* t;
+    t = socks->next;
+    while (t && t->id != sock->id) {
+      t = t->next;
+    }
+    if (!t && sock->id) /* non-zeor handle is unique -> we're done */
+      break;
+    /* if we're here, we found a duplicate */
+    if (!++sock->id) /* no zero IDs allowed */
+      sock->id++;
+  }
+  APPL_TRACE_DEBUG("SOCK_LIST: alloc(id = %d)", sock->id);
+  return sock;
+
+fail_sockpair:
+  osi_free(sock);
+  return NULL;
+}
+
+bt_status_t btsock_l2cap_init(int handle, uid_set_t* set) {
+  APPL_TRACE_DEBUG("%s handle = %d", __func__);
+  std::unique_lock<std::mutex> lock(state_lock);
+  pth = handle;
+  socks = NULL;
+  uid_set = set;
+  return BT_STATUS_SUCCESS;
+}
+
+bt_status_t btsock_l2cap_cleanup() {
+  std::unique_lock<std::mutex> lock(state_lock);
+  pth = -1;
+  while (socks) btsock_l2cap_free_l(socks);
+  return BT_STATUS_SUCCESS;
+}
+
+static inline bool send_app_psm_or_chan_l(l2cap_socket* sock) {
+  return sock_send_all(sock->our_fd, (const uint8_t*)&sock->channel,
+                       sizeof(sock->channel)) == sizeof(sock->channel);
+}
+
+static bool send_app_connect_signal(int fd, const bt_bdaddr_t* addr,
+                                    int channel, int status, int send_fd,
+                                    int tx_mtu) {
+  sock_connect_signal_t cs;
+  cs.size = sizeof(cs);
+  cs.bd_addr = *addr;
+  cs.channel = channel;
+  cs.status = status;
+  cs.max_rx_packet_size = L2CAP_MAX_SDU_LENGTH;
+  cs.max_tx_packet_size = tx_mtu;
+  if (send_fd != -1) {
+    if (sock_send_fd(fd, (const uint8_t*)&cs, sizeof(cs), send_fd) ==
+        sizeof(cs))
+      return true;
+    else
+      APPL_TRACE_ERROR("sock_send_fd failed, fd:%d, send_fd:%d", fd, send_fd);
+  } else if (sock_send_all(fd, (const uint8_t*)&cs, sizeof(cs)) == sizeof(cs)) {
+    return true;
+  }
+  return false;
+}
+
+static void on_srv_l2cap_listen_started(tBTA_JV_L2CAP_START* p_start,
+                                        uint32_t id) {
+  l2cap_socket* sock;
+
+  std::unique_lock<std::mutex> lock(state_lock);
+  sock = btsock_l2cap_find_by_id_l(id);
+  if (!sock) return;
+
+  if (p_start->status != BTA_JV_SUCCESS) {
+    APPL_TRACE_ERROR("Error starting l2cap_listen - status: 0x%04x",
+                     p_start->status);
+    btsock_l2cap_free_l(sock);
+    return;
+  }
+
+  sock->handle = p_start->handle;
+  APPL_TRACE_DEBUG("on_srv_l2cap_listen_started() sock->handle =%d id:%d",
+                   sock->handle, sock->id);
+
+  if (sock->server_psm_sent == false) {
+    if (!send_app_psm_or_chan_l(sock)) {
+      // closed
+      APPL_TRACE_DEBUG("send_app_psm() failed, close rs->id:%d", sock->id);
+      btsock_l2cap_free_l(sock);
+    } else {
+      sock->server_psm_sent = true;
+    }
+  }
+}
+
+static void on_cl_l2cap_init(tBTA_JV_L2CAP_CL_INIT* p_init, uint32_t id) {
+  l2cap_socket* sock;
+
+  std::unique_lock<std::mutex> lock(state_lock);
+  sock = btsock_l2cap_find_by_id_l(id);
+  if (!sock) return;
+
+  if (p_init->status != BTA_JV_SUCCESS) {
+    btsock_l2cap_free_l(sock);
+    return;
+  }
+
+  sock->handle = p_init->handle;
+}
+
+/**
+ * Here we allocate a new sock instance to mimic the BluetoothSocket. The socket
+ * will be a clone
+ * of the sock representing the BluetoothServerSocket.
+ * */
+static void on_srv_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN* p_open,
+                                       l2cap_socket* sock) {
+  l2cap_socket* accept_rs;
+  uint32_t new_listen_id;
+
+  // std::mutex locked by caller
+  accept_rs = btsock_l2cap_alloc_l(
+      sock->name, (const bt_bdaddr_t*)p_open->rem_bda, false, 0);
+  accept_rs->connected = true;
+  accept_rs->security = sock->security;
+  accept_rs->fixed_chan = sock->fixed_chan;
+  accept_rs->channel = sock->channel;
+  accept_rs->handle = sock->handle;
+  accept_rs->app_uid = sock->app_uid;
+  sock->handle =
+      -1; /* We should no longer associate this handle with the server socket */
+  accept_rs->is_le_coc = sock->is_le_coc;
+
+  /* Swap IDs to hand over the GAP connection to the accepted socket, and start
+     a new server on
+     the newly create socket ID. */
+  new_listen_id = accept_rs->id;
+  accept_rs->id = sock->id;
+  sock->id = new_listen_id;
+
+  if (accept_rs) {
+    // start monitor the socket
+    btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP,
+                         SOCK_THREAD_FD_EXCEPTION, sock->id);
+    btsock_thread_add_fd(pth, accept_rs->our_fd, BTSOCK_L2CAP,
+                         SOCK_THREAD_FD_RD, accept_rs->id);
+    APPL_TRACE_DEBUG(
+        "sending connect signal & app fd: %d to app server to accept() the"
+        " connection",
+        accept_rs->app_fd);
+    APPL_TRACE_DEBUG("server fd:%d, scn:%d", sock->our_fd, sock->channel);
+    send_app_connect_signal(sock->our_fd, &accept_rs->addr, sock->channel, 0,
+                            accept_rs->app_fd, p_open->tx_mtu);
+    accept_rs->app_fd =
+        -1;  // The fd is closed after sent to app in send_app_connect_signal()
+    // But for some reason we still leak a FD - either the server socket
+    // one or the accept socket one.
+    if (btSock_start_l2cap_server_l(sock) != BT_STATUS_SUCCESS) {
+      btsock_l2cap_free_l(sock);
+    }
+  }
+}
+
+static void on_srv_l2cap_le_connect_l(tBTA_JV_L2CAP_LE_OPEN* p_open,
+                                      l2cap_socket* sock) {
+  l2cap_socket* accept_rs;
+  uint32_t new_listen_id;
+
+  // std::mutex locked by caller
+  accept_rs = btsock_l2cap_alloc_l(
+      sock->name, (const bt_bdaddr_t*)p_open->rem_bda, false, 0);
+  if (accept_rs) {
+    // swap IDs
+    new_listen_id = accept_rs->id;
+    accept_rs->id = sock->id;
+    sock->id = new_listen_id;
+
+    accept_rs->handle = p_open->handle;
+    accept_rs->connected = true;
+    accept_rs->security = sock->security;
+    accept_rs->fixed_chan = sock->fixed_chan;
+    accept_rs->channel = sock->channel;
+    accept_rs->app_uid = sock->app_uid;
+
+    // if we do not set a callback, this socket will be dropped */
+    *(p_open->p_p_cback) = (void*)btsock_l2cap_cbk;
+    *(p_open->p_user_data) = UINT_TO_PTR(accept_rs->id);
+
+    // start monitor the socket
+    btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP,
+                         SOCK_THREAD_FD_EXCEPTION, sock->id);
+    btsock_thread_add_fd(pth, accept_rs->our_fd, BTSOCK_L2CAP,
+                         SOCK_THREAD_FD_RD, accept_rs->id);
+    APPL_TRACE_DEBUG(
+        "sending connect signal & app fd:%dto app server to accept() the"
+        " connection",
+        accept_rs->app_fd);
+    APPL_TRACE_DEBUG("server fd:%d, scn:%d", sock->our_fd, sock->channel);
+    send_app_connect_signal(sock->our_fd, &accept_rs->addr, sock->channel, 0,
+                            accept_rs->app_fd, p_open->tx_mtu);
+    accept_rs->app_fd = -1;  // the fd is closed after sent to app
+  }
+}
+
+static void on_cl_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN* p_open,
+                                      l2cap_socket* sock) {
+  bd_copy(sock->addr.address, p_open->rem_bda, 0);
+
+  if (!send_app_psm_or_chan_l(sock)) {
+    APPL_TRACE_ERROR("send_app_psm_or_chan_l failed");
+    return;
+  }
+
+  if (send_app_connect_signal(sock->our_fd, &sock->addr, sock->channel, 0, -1,
+                              p_open->tx_mtu)) {
+    // start monitoring the socketpair to get call back when app writing data
+    APPL_TRACE_DEBUG(
+        "on_l2cap_connect_ind, connect signal sent, slot id:%d, psm:%d,"
+        " server:%d",
+        sock->id, sock->channel, sock->server);
+    btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD,
+                         sock->id);
+    sock->connected = true;
+  } else
+    APPL_TRACE_ERROR("send_app_connect_signal failed");
+}
+
+static void on_cl_l2cap_le_connect_l(tBTA_JV_L2CAP_LE_OPEN* p_open,
+                                     l2cap_socket* sock) {
+  bd_copy(sock->addr.address, p_open->rem_bda, 0);
+
+  if (!send_app_psm_or_chan_l(sock)) {
+    APPL_TRACE_ERROR("send_app_psm_or_chan_l failed");
+    return;
+  }
+
+  if (send_app_connect_signal(sock->our_fd, &sock->addr, sock->channel, 0, -1,
+                              p_open->tx_mtu)) {
+    // start monitoring the socketpair to get call back when app writing data
+    APPL_TRACE_DEBUG(
+        "on_l2cap_connect_ind, connect signal sent, slot id:%d, Chan:%d,"
+        " server:%d",
+        sock->id, sock->channel, sock->server);
+    btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD,
+                         sock->id);
+    sock->connected = true;
+  } else
+    APPL_TRACE_ERROR("send_app_connect_signal failed");
+}
+
+static void on_l2cap_connect(tBTA_JV* p_data, uint32_t id) {
+  l2cap_socket* sock;
+  tBTA_JV_L2CAP_OPEN* psm_open = &p_data->l2c_open;
+  tBTA_JV_L2CAP_LE_OPEN* le_open = &p_data->l2c_le_open;
+
+  std::unique_lock<std::mutex> lock(state_lock);
+  sock = btsock_l2cap_find_by_id_l(id);
+  if (!sock) {
+    APPL_TRACE_ERROR("on_l2cap_connect on unknown socket");
+    return;
+  }
+
+  if (sock->fixed_chan && le_open->status == BTA_JV_SUCCESS) {
+    if (!sock->server)
+      on_cl_l2cap_le_connect_l(le_open, sock);
+    else
+      on_srv_l2cap_le_connect_l(le_open, sock);
+  } else if (!sock->fixed_chan && psm_open->status == BTA_JV_SUCCESS) {
+    if (!sock->server)
+      on_cl_l2cap_psm_connect_l(psm_open, sock);
+    else
+      on_srv_l2cap_psm_connect_l(psm_open, sock);
+  } else
+    btsock_l2cap_free_l(sock);
+}
+
+static void on_l2cap_close(tBTA_JV_L2CAP_CLOSE* p_close, uint32_t id) {
+  l2cap_socket* sock;
+
+  std::unique_lock<std::mutex> lock(state_lock);
+  sock = btsock_l2cap_find_by_id_l(id);
+  if (!sock) return;
+
+  APPL_TRACE_DEBUG("on_l2cap_close, slot id:%d, fd:%d, %s:%d, server:%d",
+                   sock->id, sock->our_fd,
+                   sock->fixed_chan ? "fixed_chan" : "PSM", sock->channel,
+                   sock->server);
+  // TODO: This does not seem to be called...
+  // I'm not sure if this will be called for non-server sockets?
+  if (!sock->fixed_chan && (sock->server == true)) {
+    BTA_JvFreeChannel(sock->channel, BTA_JV_CONN_TYPE_L2CAP);
+  }
+  btsock_l2cap_free_l(sock);
+}
+
+static void on_l2cap_outgoing_congest(tBTA_JV_L2CAP_CONG* p, uint32_t id) {
+  l2cap_socket* sock;
+
+  std::unique_lock<std::mutex> lock(state_lock);
+  sock = btsock_l2cap_find_by_id_l(id);
+  if (!sock) return;
+
+  sock->outgoing_congest = p->cong ? 1 : 0;
+  // mointer the fd for any outgoing data
+  if (!sock->outgoing_congest) {
+    APPL_TRACE_DEBUG(
+        "on_l2cap_outgoing_congest: adding fd to btsock_thread...");
+    btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD,
+                         sock->id);
+  }
+}
+
+static void on_l2cap_write_done(void* req_id, uint16_t len, uint32_t id) {
+  l2cap_socket* sock;
+
+  if (req_id != NULL) {
+    osi_free(req_id);  // free the buffer
+  }
+
+  int app_uid = -1;
+
+  std::unique_lock<std::mutex> lock(state_lock);
+  sock = btsock_l2cap_find_by_id_l(id);
+  if (!sock) return;
+
+  app_uid = sock->app_uid;
+  if (!sock->outgoing_congest) {
+    // monitor the fd for any outgoing data
+    APPL_TRACE_DEBUG("on_l2cap_write_done: adding fd to btsock_thread...");
+    btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD,
+                         sock->id);
+  }
+
+  uid_set_add_tx(uid_set, app_uid, len);
+}
+
+static void on_l2cap_write_fixed_done(void* req_id, uint16_t len, uint32_t id) {
+  l2cap_socket* sock;
+
+  if (req_id != NULL) {
+    osi_free(req_id);  // free the buffer
+  }
+
+  int app_uid = -1;
+  std::unique_lock<std::mutex> lock(state_lock);
+  sock = btsock_l2cap_find_by_id_l(id);
+  if (!sock) return;
+
+  app_uid = sock->app_uid;
+  if (!sock->outgoing_congest) {
+    // monitor the fd for any outgoing data
+    btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD,
+                         sock->id);
+  }
+  uid_set_add_tx(uid_set, app_uid, len);
+}
+
+static void on_l2cap_data_ind(tBTA_JV* evt, uint32_t id) {
+  l2cap_socket* sock;
+
+  int app_uid = -1;
+  uint32_t bytes_read = 0;
+
+  std::unique_lock<std::mutex> lock(state_lock);
+  sock = btsock_l2cap_find_by_id_l(id);
+  if (!sock) return;
+
+  app_uid = sock->app_uid;
+
+  if (sock->fixed_chan) { /* we do these differently */
+
+    tBTA_JV_LE_DATA_IND* p_le_data_ind = &evt->le_data_ind;
+    BT_HDR* p_buf = p_le_data_ind->p_buf;
+    uint8_t* data = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+    if (packet_put_tail_l(sock, data, p_buf->len)) {
+      bytes_read = p_buf->len;
+      btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_WR,
+                           sock->id);
+    } else {  // connection must be dropped
+      APPL_TRACE_DEBUG(
+          "on_l2cap_data_ind() unable to push data to socket - closing"
+          " fixed channel");
+      BTA_JvL2capCloseLE(sock->handle);
+      btsock_l2cap_free_l(sock);
+    }
+
+  } else {
+    uint8_t buffer[L2CAP_MAX_SDU_LENGTH];
+    uint32_t count;
+
+    if (BTA_JvL2capReady(sock->handle, &count) == BTA_JV_SUCCESS) {
+      if (BTA_JvL2capRead(sock->handle, sock->id, buffer, count) ==
+          BTA_JV_SUCCESS) {
+        if (packet_put_tail_l(sock, buffer, count)) {
+          bytes_read = count;
+          btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP,
+                               SOCK_THREAD_FD_WR, sock->id);
+        } else {  // connection must be dropped
+          APPL_TRACE_DEBUG(
+              "on_l2cap_data_ind() unable to push data to socket"
+              " - closing channel");
+          BTA_JvL2capClose(sock->handle);
+          btsock_l2cap_free_l(sock);
+        }
+      }
+    }
+  }
+
+  uid_set_add_rx(uid_set, app_uid, bytes_read);
+}
+
+static void btsock_l2cap_cbk(tBTA_JV_EVT event, tBTA_JV* p_data,
+                             void* user_data) {
+  uint32_t sock_id = PTR_TO_UINT(user_data);
+
+  switch (event) {
+    case BTA_JV_L2CAP_START_EVT:
+      on_srv_l2cap_listen_started(&p_data->l2c_start, sock_id);
+      break;
+
+    case BTA_JV_L2CAP_CL_INIT_EVT:
+      on_cl_l2cap_init(&p_data->l2c_cl_init, sock_id);
+      break;
+
+    case BTA_JV_L2CAP_OPEN_EVT:
+      on_l2cap_connect(p_data, sock_id);
+      BTA_JvSetPmProfile(p_data->l2c_open.handle, BTA_JV_PM_ID_1,
+                         BTA_JV_CONN_OPEN);
+      break;
+
+    case BTA_JV_L2CAP_CLOSE_EVT:
+      APPL_TRACE_DEBUG("BTA_JV_L2CAP_CLOSE_EVT: id: %u", sock_id);
+      on_l2cap_close(&p_data->l2c_close, sock_id);
+      break;
+
+    case BTA_JV_L2CAP_DATA_IND_EVT:
+      on_l2cap_data_ind(p_data, sock_id);
+      APPL_TRACE_DEBUG("BTA_JV_L2CAP_DATA_IND_EVT");
+      break;
+
+    case BTA_JV_L2CAP_READ_EVT:
+      APPL_TRACE_DEBUG("BTA_JV_L2CAP_READ_EVT not used");
+      break;
+
+    case BTA_JV_L2CAP_WRITE_EVT:
+      APPL_TRACE_DEBUG("BTA_JV_L2CAP_WRITE_EVT: id: %u", sock_id);
+      on_l2cap_write_done(UINT_TO_PTR(p_data->l2c_write.req_id),
+                          p_data->l2c_write.len, sock_id);
+      break;
+
+    case BTA_JV_L2CAP_WRITE_FIXED_EVT:
+      APPL_TRACE_DEBUG("BTA_JV_L2CAP_WRITE_FIXED_EVT: id: %u", sock_id);
+      on_l2cap_write_fixed_done(UINT_TO_PTR(p_data->l2c_write_fixed.req_id),
+                                p_data->l2c_write.len, sock_id);
+      break;
+
+    case BTA_JV_L2CAP_CONG_EVT:
+      on_l2cap_outgoing_congest(&p_data->l2c_cong, sock_id);
+      break;
+
+    default:
+      APPL_TRACE_ERROR("unhandled event %d, slot id: %u", event, sock_id);
+      break;
+  }
+}
+
+/* L2CAP default options for OBEX socket connections */
+const tL2CAP_FCR_OPTS obex_l2c_fcr_opts_def = {
+    L2CAP_FCR_ERTM_MODE,               /* Mandatory for OBEX over l2cap */
+    OBX_FCR_OPT_TX_WINDOW_SIZE_BR_EDR, /* Tx window size */
+    OBX_FCR_OPT_MAX_TX_B4_DISCNT,      /* Maximum transmissions before
+                                          disconnecting */
+    OBX_FCR_OPT_RETX_TOUT,             /* Retransmission timeout (2 secs) */
+    OBX_FCR_OPT_MONITOR_TOUT,          /* Monitor timeout (12 secs) */
+    OBX_FCR_OPT_MAX_PDU_SIZE           /* MPS segment size */
+};
+const tL2CAP_ERTM_INFO obex_l2c_etm_opt = {
+    L2CAP_FCR_ERTM_MODE,     /* Mandatory for OBEX over l2cap */
+    L2CAP_FCR_CHAN_OPT_ERTM, /* Mandatory for OBEX over l2cap */
+    OBX_USER_RX_BUF_SIZE,    OBX_USER_TX_BUF_SIZE,
+    OBX_FCR_RX_BUF_SIZE,     OBX_FCR_TX_BUF_SIZE};
+
+/**
+ * When using a dynamic PSM, a PSM allocation is requested from
+ * btsock_l2cap_listen_or_connect().
+ * The PSM allocation event is refeived in the JV-callback - currently located
+ * in RFC-code -
+ * and this function is called with the newly allocated PSM.
+ */
+void on_l2cap_psm_assigned(int id, int psm) {
+  /* Setup ETM settings:
+   *  mtu will be set below */
+  std::unique_lock<std::mutex> lock(state_lock);
+  l2cap_socket* sock = btsock_l2cap_find_by_id_l(id);
+  if (!sock) {
+    APPL_TRACE_ERROR("%s: Error: sock is null", __func__);
+    return;
+  }
+
+  sock->channel = psm;
+
+  if (btSock_start_l2cap_server_l(sock) != BT_STATUS_SUCCESS)
+    btsock_l2cap_free_l(sock);
+}
+
+static bt_status_t btSock_start_l2cap_server_l(l2cap_socket* sock) {
+  tL2CAP_CFG_INFO cfg;
+  bt_status_t stat = BT_STATUS_SUCCESS;
+  /* Setup ETM settings:
+   *  mtu will be set below */
+  memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+  cfg.fcr_present = true;
+  cfg.fcr = obex_l2c_fcr_opts_def;
+
+  if (sock->fixed_chan) {
+    if (BTA_JvL2capStartServerLE(sock->security, 0, NULL, sock->channel,
+                                 L2CAP_DEFAULT_MTU, NULL, btsock_l2cap_cbk,
+                                 UINT_TO_PTR(sock->id)) != BTA_JV_SUCCESS)
+      stat = BT_STATUS_FAIL;
+
+  } else {
+    /* If we have a channel specified in the request, just start the server,
+     * else we request a PSM and start the server after we receive a PSM. */
+    if (sock->channel < 0) {
+      if (sock->is_le_coc) {
+        if (BTA_JvGetChannelId(BTA_JV_CONN_TYPE_L2CAP_LE, UINT_TO_PTR(sock->id),
+                               0) != BTA_JV_SUCCESS)
+          stat = BT_STATUS_FAIL;
+      } else {
+        if (BTA_JvGetChannelId(BTA_JV_CONN_TYPE_L2CAP, UINT_TO_PTR(sock->id),
+                               0) != BTA_JV_SUCCESS)
+          stat = BT_STATUS_FAIL;
+      }
+    } else {
+      if (sock->is_le_coc) {
+        if (BTA_JvL2capStartServer(BTA_JV_CONN_TYPE_L2CAP_LE, sock->security, 0,
+                                   NULL, sock->channel, L2CAP_MAX_SDU_LENGTH,
+                                   &cfg, btsock_l2cap_cbk,
+                                   UINT_TO_PTR(sock->id)) != BTA_JV_SUCCESS)
+          stat = BT_STATUS_FAIL;
+      } else {
+        if (BTA_JvL2capStartServer(BTA_JV_CONN_TYPE_L2CAP, sock->security, 0,
+                                   &obex_l2c_etm_opt, sock->channel,
+                                   L2CAP_MAX_SDU_LENGTH, &cfg, btsock_l2cap_cbk,
+                                   UINT_TO_PTR(sock->id)) != BTA_JV_SUCCESS)
+          stat = BT_STATUS_FAIL;
+      }
+    }
+  }
+  return stat;
+}
+
+static bt_status_t btsock_l2cap_listen_or_connect(const char* name,
+                                                  const bt_bdaddr_t* addr,
+                                                  int channel, int* sock_fd,
+                                                  int flags, char listen,
+                                                  int app_uid) {
+  bt_status_t stat;
+  int fixed_chan = 1;
+  l2cap_socket* sock;
+  tL2CAP_CFG_INFO cfg;
+  bool is_le_coc = false;
+
+  if (!sock_fd) return BT_STATUS_PARM_INVALID;
+
+  if (channel < 0) {
+    // We need to auto assign a PSM
+    fixed_chan = 0;
+  } else {
+    fixed_chan = (channel & L2CAP_MASK_FIXED_CHANNEL) != 0;
+    is_le_coc = (channel & L2CAP_MASK_LE_COC_CHANNEL) != 0;
+    channel &= ~(L2CAP_MASK_FIXED_CHANNEL | L2CAP_MASK_LE_COC_CHANNEL);
+  }
+
+  if (!is_inited()) return BT_STATUS_NOT_READY;
+
+  // TODO: This is kind of bad to lock here, but it is needed for the current
+  // design.
+  std::unique_lock<std::mutex> lock(state_lock);
+  sock = btsock_l2cap_alloc_l(name, addr, listen, flags);
+  if (!sock) {
+    return BT_STATUS_NOMEM;
+  }
+
+  sock->fixed_chan = fixed_chan;
+  sock->channel = channel;
+  sock->app_uid = app_uid;
+  sock->is_le_coc = is_le_coc;
+
+  stat = BT_STATUS_SUCCESS;
+
+  /* Setup ETM settings:
+   *  mtu will be set below */
+  memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+  cfg.fcr_present = true;
+  cfg.fcr = obex_l2c_fcr_opts_def;
+
+  /* "role" is never initialized in rfcomm code */
+  if (listen) {
+    stat = btSock_start_l2cap_server_l(sock);
+  } else {
+    if (fixed_chan) {
+      if (BTA_JvL2capConnectLE(sock->security, 0, NULL, channel,
+                               L2CAP_DEFAULT_MTU, NULL, sock->addr.address,
+                               btsock_l2cap_cbk,
+                               UINT_TO_PTR(sock->id)) != BTA_JV_SUCCESS)
+        stat = BT_STATUS_FAIL;
+
+    } else {
+      if (sock->is_le_coc) {
+        if (BTA_JvL2capConnect(BTA_JV_CONN_TYPE_L2CAP_LE, sock->security, 0,
+                               NULL, channel, L2CAP_MAX_SDU_LENGTH, &cfg,
+                               sock->addr.address, btsock_l2cap_cbk,
+                               UINT_TO_PTR(sock->id)) != BTA_JV_SUCCESS)
+          stat = BT_STATUS_FAIL;
+      } else {
+        if (BTA_JvL2capConnect(BTA_JV_CONN_TYPE_L2CAP, sock->security, 0,
+                               &obex_l2c_etm_opt, channel, L2CAP_MAX_SDU_LENGTH,
+                               &cfg, sock->addr.address, btsock_l2cap_cbk,
+                               UINT_TO_PTR(sock->id)) != BTA_JV_SUCCESS)
+          stat = BT_STATUS_FAIL;
+      }
+    }
+  }
+
+  if (stat == BT_STATUS_SUCCESS) {
+    *sock_fd = sock->app_fd;
+    /* We pass the FD to JAVA, but since it runs in another process, we need to
+     * also close
+     * it in native, either straight away, as done when accepting an incoming
+     * connection,
+     * or when doing cleanup after this socket */
+    sock->app_fd =
+        -1; /*This leaks the file descriptor. The FD should be closed in
+              JAVA but it apparently do not work */
+    btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP,
+                         SOCK_THREAD_FD_EXCEPTION, sock->id);
+  } else {
+    btsock_l2cap_free_l(sock);
+  }
+
+  return stat;
+}
+
+bt_status_t btsock_l2cap_listen(const char* name, int channel, int* sock_fd,
+                                int flags, int app_uid) {
+  return btsock_l2cap_listen_or_connect(name, NULL, channel, sock_fd, flags, 1,
+                                        app_uid);
+}
+
+bt_status_t btsock_l2cap_connect(const bt_bdaddr_t* bd_addr, int channel,
+                                 int* sock_fd, int flags, int app_uid) {
+  return btsock_l2cap_listen_or_connect(NULL, bd_addr, channel, sock_fd, flags,
+                                        0, app_uid);
+}
+
+/* return true if we have more to send and should wait for user readiness, false
+ * else
+ * (for example: unrecoverable error or no data)
+ */
+static bool flush_incoming_que_on_wr_signal_l(l2cap_socket* sock) {
+  uint8_t* buf;
+  uint32_t len;
+
+  while (packet_get_head_l(sock, &buf, &len)) {
+    ssize_t sent;
+    OSI_NO_INTR(sent = send(sock->our_fd, buf, len, MSG_DONTWAIT));
+    int saved_errno = errno;
+
+    if (sent == (signed)len)
+      osi_free(buf);
+    else if (sent >= 0) {
+      packet_put_head_l(sock, buf + sent, len - sent);
+      osi_free(buf);
+      if (!sent) /* special case if other end not keeping up */
+        return true;
+    } else {
+      packet_put_head_l(sock, buf, len);
+      osi_free(buf);
+      return saved_errno == EWOULDBLOCK || saved_errno == EAGAIN;
+    }
+  }
+
+  return false;
+}
+
+void btsock_l2cap_signaled(int fd, int flags, uint32_t user_id) {
+  l2cap_socket* sock;
+  char drop_it = false;
+
+  /* We use MSG_DONTWAIT when sending data to JAVA, hence it can be accepted to
+   * hold the lock. */
+  std::unique_lock<std::mutex> lock(state_lock);
+  sock = btsock_l2cap_find_by_id_l(user_id);
+  if (!sock) return;
+
+  if ((flags & SOCK_THREAD_FD_RD) && !sock->server) {
+    // app sending data
+    if (sock->connected) {
+      int size = 0;
+
+      if (!(flags & SOCK_THREAD_FD_EXCEPTION) ||
+          (ioctl(sock->our_fd, FIONREAD, &size) == 0 && size)) {
+        uint8_t* buffer = (uint8_t*)osi_malloc(L2CAP_MAX_SDU_LENGTH);
+        /* Apparently we hijack the req_id (uint32_t) to pass the pointer to the
+         * buffer to the write complete callback, which call a free... wonder if
+         * this works on a 64 bit platform? */
+        /* The socket is created with SOCK_SEQPACKET, hence we read one message
+         * at the time. The maximum size of a message is allocated to ensure
+         * data is not lost. This is okay to do as Android uses virtual memory,
+         * hence even if we only use a fraction of the memory it should not
+         * block for others to use the memory. As the definition of
+         * ioctl(FIONREAD) do not clearly define what value will be returned if
+         * multiple messages are written to the socket before any message is
+         * read from the socket, we could potentially risk to allocate way more
+         * memory than needed. One of the use cases for this socket is obex
+         * where multiple 64kbyte messages are typically written to the socket
+         * in a tight loop, hence we risk the ioctl will return the total amount
+         * of data in the buffer, which could be multiple 64kbyte chunks.
+         * UPDATE: As the stack cannot handle 64kbyte buffers, the size is
+         * reduced to around 8kbyte - and using malloc for buffer allocation
+         * here seems to be wrong
+         * UPDATE: Since we are responsible for freeing the buffer in the
+         * write_complete_ind, it is OK to use malloc. */
+        ssize_t count;
+        OSI_NO_INTR(count = recv(fd, buffer, L2CAP_MAX_SDU_LENGTH,
+                                 MSG_NOSIGNAL | MSG_DONTWAIT));
+        APPL_TRACE_DEBUG(
+            "btsock_l2cap_signaled - %d bytes received from socket", count);
+
+        // TODO(armansito): |buffer|, which is created above via
+        // malloc, is being cast below to uint32_t to be used as
+        // the |req_id| parameter of BTA_JvL2capWriteFixed and
+        // BTA_JvL2capWrite. The "id" then gets freed in an
+        // obscure callback elsewhere. We need to watch out for
+        // this type of unsafe practice, as this is error prone
+        // and difficult to follow.
+        if (sock->fixed_chan) {
+          if (BTA_JvL2capWriteFixed(sock->channel, (BD_ADDR*)&sock->addr,
+                                    PTR_TO_UINT(buffer), btsock_l2cap_cbk,
+                                    buffer, count,
+                                    UINT_TO_PTR(user_id)) != BTA_JV_SUCCESS) {
+            // On fail, free the buffer
+            on_l2cap_write_fixed_done(buffer, count, user_id);
+          }
+        } else {
+          if (BTA_JvL2capWrite(sock->handle, PTR_TO_UINT(buffer), buffer, count,
+                               UINT_TO_PTR(user_id)) != BTA_JV_SUCCESS) {
+            // On fail, free the buffer
+            on_l2cap_write_done(buffer, count, user_id);
+          }
+        }
+      }
+    } else
+      drop_it = true;
+  }
+  if (flags & SOCK_THREAD_FD_WR) {
+    // app is ready to receive more data, tell stack to enable the data flow
+    if (flush_incoming_que_on_wr_signal_l(sock) && sock->connected)
+      btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_WR,
+                           sock->id);
+  }
+  if (drop_it || (flags & SOCK_THREAD_FD_EXCEPTION)) {
+    int size = 0;
+    if (drop_it || ioctl(sock->our_fd, FIONREAD, &size) != 0 || size == 0)
+      btsock_l2cap_free_l(sock);
+  }
+}
diff --git a/bt/btif/src/btif_sock_rfc.cc b/bt/btif/src/btif_sock_rfc.cc
new file mode 100644
index 0000000..7b21a17
--- /dev/null
+++ b/bt/btif/src/btif_sock_rfc.cc
@@ -0,0 +1,936 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_sock_rfcomm"
+
+#include <assert.h>
+#include <errno.h>
+#include <features.h>
+#include <pthread.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <mutex>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bta_api.h"
+#include "bta_jv_api.h"
+#include "bta_jv_co.h"
+#include "btif_common.h"
+#include "btif_sock_sdp.h"
+#include "btif_sock_thread.h"
+#include "btif_sock_util.h"
+#include "btif_uid.h"
+#include "btif_util.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "hcimsgs.h"
+#include "osi/include/compat.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+#include "sdp_api.h"
+
+/* The JV interface can have only one user, hence we need to call a few
+ * L2CAP functions from this file. */
+#include "btif_sock_l2cap.h"
+
+// Maximum number of RFCOMM channels (1-30 inclusive).
+#define MAX_RFC_CHANNEL 30
+
+// Maximum number of devices we can have an RFCOMM connection with.
+#define MAX_RFC_SESSION 7
+
+typedef struct {
+  int outgoing_congest : 1;
+  int pending_sdp_request : 1;
+  int doing_sdp_request : 1;
+  int server : 1;
+  int connected : 1;
+  int closing : 1;
+} flags_t;
+
+typedef struct {
+  flags_t f;
+  uint32_t id;  // Non-zero indicates a valid (in-use) slot.
+  int security;
+  int scn;  // Server channel number
+  int scn_notified;
+  bt_bdaddr_t addr;
+  int is_service_uuid_valid;
+  uint8_t service_uuid[16];
+  char service_name[256];
+  int fd;
+  int app_fd;   // Temporary storage for the half of the socketpair that's sent
+                // back to upper layers.
+  int app_uid;  // UID of the app for which this socket was created.
+  int mtu;
+  uint8_t* packet;
+  int sdp_handle;
+  int rfc_handle;
+  int rfc_port_handle;
+  int role;
+  list_t* incoming_queue;
+} rfc_slot_t;
+
+static rfc_slot_t rfc_slots[MAX_RFC_CHANNEL];
+static uint32_t rfc_slot_id;
+static volatile int pth = -1;  // poll thread handle
+static std::recursive_mutex slot_lock;
+static uid_set_t* uid_set = NULL;
+
+static rfc_slot_t* find_free_slot(void);
+static void cleanup_rfc_slot(rfc_slot_t* rs);
+static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV* p_data, void* user_data);
+static void* rfcomm_cback(tBTA_JV_EVT event, tBTA_JV* p_data, void* user_data);
+static bool send_app_scn(rfc_slot_t* rs);
+
+static bool is_init_done(void) { return pth != -1; }
+
+bt_status_t btsock_rfc_init(int poll_thread_handle, uid_set_t* set) {
+  pth = poll_thread_handle;
+  uid_set = set;
+
+  memset(rfc_slots, 0, sizeof(rfc_slots));
+  for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i) {
+    rfc_slots[i].scn = -1;
+    rfc_slots[i].sdp_handle = 0;
+    rfc_slots[i].fd = INVALID_FD;
+    rfc_slots[i].app_fd = INVALID_FD;
+    rfc_slots[i].incoming_queue = list_new(osi_free);
+    assert(rfc_slots[i].incoming_queue != NULL);
+  }
+
+  BTA_JvEnable(jv_dm_cback);
+
+  return BT_STATUS_SUCCESS;
+}
+
+void btsock_rfc_cleanup(void) {
+  pth = -1;
+  uid_set = NULL;
+
+  BTA_JvDisable();
+
+  std::unique_lock<std::recursive_mutex> lock(slot_lock);
+  for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i) {
+    if (rfc_slots[i].id) cleanup_rfc_slot(&rfc_slots[i]);
+    list_free(rfc_slots[i].incoming_queue);
+    rfc_slots[i].incoming_queue = NULL;
+  }
+}
+
+static rfc_slot_t* find_free_slot(void) {
+  for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i)
+    if (rfc_slots[i].fd == INVALID_FD) return &rfc_slots[i];
+  return NULL;
+}
+
+static rfc_slot_t* find_rfc_slot_by_id(uint32_t id) {
+  assert(id != 0);
+
+  for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i)
+    if (rfc_slots[i].id == id) return &rfc_slots[i];
+
+  LOG_ERROR(LOG_TAG, "%s unable to find RFCOMM slot id: %d", __func__, id);
+  return NULL;
+}
+
+static rfc_slot_t* find_rfc_slot_by_pending_sdp(void) {
+  uint32_t min_id = UINT32_MAX;
+  int slot = -1;
+  for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i)
+    if (rfc_slots[i].id && rfc_slots[i].f.pending_sdp_request &&
+        rfc_slots[i].id < min_id) {
+      min_id = rfc_slots[i].id;
+      slot = i;
+    }
+
+  return (slot == -1) ? NULL : &rfc_slots[slot];
+}
+
+static bool is_requesting_sdp(void) {
+  for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i)
+    if (rfc_slots[i].id && rfc_slots[i].f.doing_sdp_request) return true;
+  return false;
+}
+
+static rfc_slot_t* alloc_rfc_slot(const bt_bdaddr_t* addr, const char* name,
+                                  const uint8_t* uuid, int channel, int flags,
+                                  bool server) {
+  int security = 0;
+  if (flags & BTSOCK_FLAG_ENCRYPT)
+    security |= server ? BTM_SEC_IN_ENCRYPT : BTM_SEC_OUT_ENCRYPT;
+  if (flags & BTSOCK_FLAG_AUTH)
+    security |= server ? BTM_SEC_IN_AUTHENTICATE : BTM_SEC_OUT_AUTHENTICATE;
+  if (flags & BTSOCK_FLAG_AUTH_MITM)
+    security |= server ? BTM_SEC_IN_MITM : BTM_SEC_OUT_MITM;
+  if (flags & BTSOCK_FLAG_AUTH_16_DIGIT)
+    security |= BTM_SEC_IN_MIN_16_DIGIT_PIN;
+
+  rfc_slot_t* slot = find_free_slot();
+  if (!slot) {
+    LOG_ERROR(LOG_TAG, "%s unable to find free RFCOMM slot.", __func__);
+    return NULL;
+  }
+
+  int fds[2] = {INVALID_FD, INVALID_FD};
+  if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) == -1) {
+    LOG_ERROR(LOG_TAG, "%s error creating socketpair: %s", __func__,
+              strerror(errno));
+    return NULL;
+  }
+
+  // Increment slot id and make sure we don't use id=0.
+  if (++rfc_slot_id == 0) rfc_slot_id = 1;
+
+  slot->fd = fds[0];
+  slot->app_fd = fds[1];
+  slot->security = security;
+  slot->scn = channel;
+  slot->app_uid = -1;
+
+  if (!is_uuid_empty(uuid)) {
+    memcpy(slot->service_uuid, uuid, sizeof(slot->service_uuid));
+    slot->is_service_uuid_valid = true;
+  } else {
+    memset(slot->service_uuid, 0, sizeof(slot->service_uuid));
+    slot->is_service_uuid_valid = false;
+  }
+  if (name && *name) {
+    strlcpy(slot->service_name, name, sizeof(slot->service_name));
+  } else {
+    memset(slot->service_name, 0, sizeof(slot->service_name));
+  }
+  if (addr) slot->addr = *addr;
+
+  slot->id = rfc_slot_id;
+  slot->f.server = server;
+
+  return slot;
+}
+
+static rfc_slot_t* create_srv_accept_rfc_slot(rfc_slot_t* srv_rs,
+                                              const bt_bdaddr_t* addr,
+                                              int open_handle,
+                                              int new_listen_handle) {
+  rfc_slot_t* accept_rs = alloc_rfc_slot(
+      addr, srv_rs->service_name, srv_rs->service_uuid, srv_rs->scn, 0, false);
+  if (!accept_rs) {
+    LOG_ERROR(LOG_TAG, "%s unable to allocate RFCOMM slot.", __func__);
+    return NULL;
+  }
+
+  accept_rs->f.server = false;
+  accept_rs->f.connected = true;
+  accept_rs->security = srv_rs->security;
+  accept_rs->mtu = srv_rs->mtu;
+  accept_rs->role = srv_rs->role;
+  accept_rs->rfc_handle = open_handle;
+  accept_rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(open_handle);
+  accept_rs->app_uid = srv_rs->app_uid;
+
+  srv_rs->rfc_handle = new_listen_handle;
+  srv_rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(new_listen_handle);
+
+  assert(accept_rs->rfc_port_handle != srv_rs->rfc_port_handle);
+
+  // now swap the slot id
+  uint32_t new_listen_id = accept_rs->id;
+  accept_rs->id = srv_rs->id;
+  srv_rs->id = new_listen_id;
+
+  return accept_rs;
+}
+
+bt_status_t btsock_rfc_listen(const char* service_name,
+                              const uint8_t* service_uuid, int channel,
+                              int* sock_fd, int flags, int app_uid) {
+  assert(sock_fd != NULL);
+  assert((service_uuid != NULL) ||
+         (channel >= 1 && channel <= MAX_RFC_CHANNEL) ||
+         ((flags & BTSOCK_FLAG_NO_SDP) != 0));
+
+  *sock_fd = INVALID_FD;
+
+  // TODO(sharvil): not sure that this check makes sense; seems like a logic
+  // error to call
+  // functions on RFCOMM sockets before initializing the module. Probably should
+  // be an assert.
+  if (!is_init_done()) return BT_STATUS_NOT_READY;
+
+  if ((flags & BTSOCK_FLAG_NO_SDP) == 0) {
+    if (is_uuid_empty(service_uuid)) {
+      APPL_TRACE_DEBUG(
+          "BTA_JvGetChannelId: service_uuid not set AND "
+          "BTSOCK_FLAG_NO_SDP is not set - changing to SPP");
+      service_uuid =
+          UUID_SPP;  // Use serial port profile to listen to specified channel
+    } else {
+      // Check the service_uuid. overwrite the channel # if reserved
+      int reserved_channel = get_reserved_rfc_channel(service_uuid);
+      if (reserved_channel > 0) {
+        channel = reserved_channel;
+      }
+    }
+  }
+
+  std::unique_lock<std::recursive_mutex> lock(slot_lock);
+
+  rfc_slot_t* slot =
+      alloc_rfc_slot(NULL, service_name, service_uuid, channel, flags, true);
+  if (!slot) {
+    LOG_ERROR(LOG_TAG, "%s unable to allocate RFCOMM slot.", __func__);
+    return BT_STATUS_FAIL;
+  }
+  APPL_TRACE_DEBUG("BTA_JvGetChannelId: service_name: %s - channel: %d",
+                   service_name, channel);
+  BTA_JvGetChannelId(BTA_JV_CONN_TYPE_RFCOMM, UINT_TO_PTR(slot->id), channel);
+  *sock_fd = slot->app_fd;  // Transfer ownership of fd to caller.
+  /*TODO:
+   * We are leaking one of the app_fd's - either the listen socket, or the
+   connection socket.
+   * WE need to close this in native, as the FD might belong to another process
+    - This is the server socket FD
+    - For accepted connections, we close the FD after passing it to JAVA.
+    - Try to simply remove the = -1 to free the FD at rs cleanup.*/
+  //        close(rs->app_fd);
+  slot->app_fd = INVALID_FD;  // Drop our reference to the fd.
+  slot->app_uid = app_uid;
+  btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION,
+                       slot->id);
+
+  return BT_STATUS_SUCCESS;
+}
+
+bt_status_t btsock_rfc_connect(const bt_bdaddr_t* bd_addr,
+                               const uint8_t* service_uuid, int channel,
+                               int* sock_fd, int flags, int app_uid) {
+  assert(sock_fd != NULL);
+  assert(service_uuid != NULL || (channel >= 1 && channel <= MAX_RFC_CHANNEL));
+
+  *sock_fd = INVALID_FD;
+
+  // TODO(sharvil): not sure that this check makes sense; seems like a logic
+  // error to call
+  // functions on RFCOMM sockets before initializing the module. Probably should
+  // be an assert.
+  if (!is_init_done()) return BT_STATUS_NOT_READY;
+
+  std::unique_lock<std::recursive_mutex> lock(slot_lock);
+
+  rfc_slot_t* slot =
+      alloc_rfc_slot(bd_addr, NULL, service_uuid, channel, flags, false);
+  if (!slot) {
+    LOG_ERROR(LOG_TAG, "%s unable to allocate RFCOMM slot.", __func__);
+    return BT_STATUS_FAIL;
+  }
+
+  if (is_uuid_empty(service_uuid)) {
+    tBTA_JV_STATUS ret = BTA_JvRfcommConnect(
+        slot->security, slot->role, slot->scn, slot->addr.address, rfcomm_cback,
+        (void*)(uintptr_t)slot->id);
+    if (ret != BTA_JV_SUCCESS) {
+      LOG_ERROR(LOG_TAG, "%s unable to initiate RFCOMM connection: %d",
+                __func__, ret);
+      cleanup_rfc_slot(slot);
+      return BT_STATUS_FAIL;
+    }
+
+    if (!send_app_scn(slot)) {
+      LOG_ERROR(LOG_TAG, "%s unable to send channel number.", __func__);
+      cleanup_rfc_slot(slot);
+      return BT_STATUS_FAIL;
+    }
+  } else {
+    tSDP_UUID sdp_uuid;
+    sdp_uuid.len = 16;
+    memcpy(sdp_uuid.uu.uuid128, service_uuid, sizeof(sdp_uuid.uu.uuid128));
+
+    if (!is_requesting_sdp()) {
+      BTA_JvStartDiscovery((uint8_t*)bd_addr->address, 1, &sdp_uuid,
+                           (void*)(uintptr_t)slot->id);
+      slot->f.pending_sdp_request = false;
+      slot->f.doing_sdp_request = true;
+    } else {
+      slot->f.pending_sdp_request = true;
+      slot->f.doing_sdp_request = false;
+    }
+  }
+
+  *sock_fd = slot->app_fd;    // Transfer ownership of fd to caller.
+  slot->app_fd = INVALID_FD;  // Drop our reference to the fd.
+  slot->app_uid = app_uid;
+  btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD,
+                       slot->id);
+
+  return BT_STATUS_SUCCESS;
+}
+
+static int create_server_sdp_record(rfc_slot_t* slot) {
+  if (slot->scn == 0) {
+    return false;
+  }
+  slot->sdp_handle =
+      add_rfc_sdp_rec(slot->service_name, slot->service_uuid, slot->scn);
+  return (slot->sdp_handle > 0);
+}
+
+static void free_rfc_slot_scn(rfc_slot_t* slot) {
+  if (slot->scn <= 0) return;
+
+  if (slot->f.server && !slot->f.closing && slot->rfc_handle) {
+    BTA_JvRfcommStopServer(slot->rfc_handle, (void*)(uintptr_t)slot->id);
+    slot->rfc_handle = 0;
+  }
+
+  if (slot->f.server) BTM_FreeSCN(slot->scn);
+  slot->scn = 0;
+}
+
+static void cleanup_rfc_slot(rfc_slot_t* slot) {
+  if (slot->fd != INVALID_FD) {
+    shutdown(slot->fd, SHUT_RDWR);
+    close(slot->fd);
+    slot->fd = INVALID_FD;
+  }
+
+  if (slot->app_fd != INVALID_FD) {
+    close(slot->app_fd);
+    slot->app_fd = INVALID_FD;
+  }
+
+  if (slot->sdp_handle > 0) {
+    del_rfc_sdp_rec(slot->sdp_handle);
+    slot->sdp_handle = 0;
+  }
+
+  if (slot->rfc_handle && !slot->f.closing && !slot->f.server) {
+    BTA_JvRfcommClose(slot->rfc_handle, (void*)(uintptr_t)slot->id);
+    slot->rfc_handle = 0;
+  }
+
+  free_rfc_slot_scn(slot);
+  list_clear(slot->incoming_queue);
+
+  slot->rfc_port_handle = 0;
+  memset(&slot->f, 0, sizeof(slot->f));
+  slot->id = 0;
+  slot->scn_notified = false;
+}
+
+static bool send_app_scn(rfc_slot_t* slot) {
+  if (slot->scn_notified == true) {
+    // already send, just return success.
+    return true;
+  }
+  slot->scn_notified = true;
+  return sock_send_all(slot->fd, (const uint8_t*)&slot->scn,
+                       sizeof(slot->scn)) == sizeof(slot->scn);
+}
+
+static bool send_app_connect_signal(int fd, const bt_bdaddr_t* addr,
+                                    int channel, int status, int send_fd) {
+  sock_connect_signal_t cs;
+  cs.size = sizeof(cs);
+  cs.bd_addr = *addr;
+  cs.channel = channel;
+  cs.status = status;
+  cs.max_rx_packet_size = 0;  // not used for RFCOMM
+  cs.max_tx_packet_size = 0;  // not used for RFCOMM
+  if (send_fd == INVALID_FD)
+    return sock_send_all(fd, (const uint8_t*)&cs, sizeof(cs)) == sizeof(cs);
+
+  return sock_send_fd(fd, (const uint8_t*)&cs, sizeof(cs), send_fd) ==
+         sizeof(cs);
+}
+
+static void on_cl_rfc_init(tBTA_JV_RFCOMM_CL_INIT* p_init, uint32_t id) {
+  std::unique_lock<std::recursive_mutex> lock(slot_lock);
+  rfc_slot_t* slot = find_rfc_slot_by_id(id);
+  if (!slot) return;
+
+  if (p_init->status == BTA_JV_SUCCESS) {
+    slot->rfc_handle = p_init->handle;
+  } else {
+    cleanup_rfc_slot(slot);
+  }
+}
+
+static void on_srv_rfc_listen_started(tBTA_JV_RFCOMM_START* p_start,
+                                      uint32_t id) {
+  std::unique_lock<std::recursive_mutex> lock(slot_lock);
+  rfc_slot_t* slot = find_rfc_slot_by_id(id);
+  if (!slot) return;
+
+  if (p_start->status == BTA_JV_SUCCESS) {
+    slot->rfc_handle = p_start->handle;
+  } else {
+    cleanup_rfc_slot(slot);
+  }
+}
+
+static uint32_t on_srv_rfc_connect(tBTA_JV_RFCOMM_SRV_OPEN* p_open,
+                                   uint32_t id) {
+  std::unique_lock<std::recursive_mutex> lock(slot_lock);
+  rfc_slot_t* accept_rs;
+  rfc_slot_t* srv_rs = find_rfc_slot_by_id(id);
+  if (!srv_rs) return 0;
+
+  accept_rs =
+      create_srv_accept_rfc_slot(srv_rs, (const bt_bdaddr_t*)p_open->rem_bda,
+                                 p_open->handle, p_open->new_listen_handle);
+  if (!accept_rs) return 0;
+
+  // Start monitoring the socket.
+  btsock_thread_add_fd(pth, srv_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION,
+                       srv_rs->id);
+  btsock_thread_add_fd(pth, accept_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD,
+                       accept_rs->id);
+  send_app_connect_signal(srv_rs->fd, &accept_rs->addr, srv_rs->scn, 0,
+                          accept_rs->app_fd);
+  accept_rs->app_fd =
+      INVALID_FD;  // Ownership of the application fd has been transferred.
+  return srv_rs->id;
+}
+
+static void on_cli_rfc_connect(tBTA_JV_RFCOMM_OPEN* p_open, uint32_t id) {
+  std::unique_lock<std::recursive_mutex> lock(slot_lock);
+  rfc_slot_t* slot = find_rfc_slot_by_id(id);
+  if (!slot) return;
+
+  if (p_open->status != BTA_JV_SUCCESS) {
+    cleanup_rfc_slot(slot);
+    return;
+  }
+
+  slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_open->handle);
+  memcpy(slot->addr.address, p_open->rem_bda, 6);
+
+  if (send_app_connect_signal(slot->fd, &slot->addr, slot->scn, 0, -1)) {
+    slot->f.connected = true;
+  } else {
+    LOG_ERROR(LOG_TAG, "%s unable to send connect completion signal to caller.",
+              __func__);
+  }
+}
+
+static void on_rfc_close(UNUSED_ATTR tBTA_JV_RFCOMM_CLOSE* p_close,
+                         uint32_t id) {
+  std::unique_lock<std::recursive_mutex> lock(slot_lock);
+
+  // rfc_handle already closed when receiving rfcomm close event from stack.
+  rfc_slot_t* slot = find_rfc_slot_by_id(id);
+  if (slot) cleanup_rfc_slot(slot);
+}
+
+static void on_rfc_write_done(tBTA_JV_RFCOMM_WRITE* p, uint32_t id) {
+  if (p->status != BTA_JV_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s error writing to RFCOMM socket with slot %u.",
+              __func__, p->req_id);
+    return;
+  }
+
+  int app_uid = -1;
+  std::unique_lock<std::recursive_mutex> lock(slot_lock);
+
+  rfc_slot_t* slot = find_rfc_slot_by_id(id);
+  if (slot) {
+    app_uid = slot->app_uid;
+    if (!slot->f.outgoing_congest) {
+      btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD,
+                           slot->id);
+    }
+  }
+
+  uid_set_add_tx(uid_set, app_uid, p->len);
+}
+
+static void on_rfc_outgoing_congest(tBTA_JV_RFCOMM_CONG* p, uint32_t id) {
+  std::unique_lock<std::recursive_mutex> lock(slot_lock);
+
+  rfc_slot_t* slot = find_rfc_slot_by_id(id);
+  if (slot) {
+    slot->f.outgoing_congest = p->cong ? 1 : 0;
+    if (!slot->f.outgoing_congest)
+      btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD,
+                           slot->id);
+  }
+}
+
+static void* rfcomm_cback(tBTA_JV_EVT event, tBTA_JV* p_data, void* user_data) {
+  void* new_user_data = NULL;
+
+  switch (event) {
+    case BTA_JV_RFCOMM_START_EVT:
+      on_srv_rfc_listen_started(&p_data->rfc_start, (uintptr_t)user_data);
+      break;
+
+    case BTA_JV_RFCOMM_CL_INIT_EVT:
+      on_cl_rfc_init(&p_data->rfc_cl_init, (uintptr_t)user_data);
+      break;
+
+    case BTA_JV_RFCOMM_OPEN_EVT:
+      BTA_JvSetPmProfile(p_data->rfc_open.handle, BTA_JV_PM_ID_1,
+                         BTA_JV_CONN_OPEN);
+      on_cli_rfc_connect(&p_data->rfc_open, (uintptr_t)user_data);
+      break;
+
+    case BTA_JV_RFCOMM_SRV_OPEN_EVT:
+      BTA_JvSetPmProfile(p_data->rfc_srv_open.handle, BTA_JV_PM_ALL,
+                         BTA_JV_CONN_OPEN);
+      new_user_data = (void*)(uintptr_t)on_srv_rfc_connect(
+          &p_data->rfc_srv_open, (uintptr_t)user_data);
+      break;
+
+    case BTA_JV_RFCOMM_CLOSE_EVT:
+      APPL_TRACE_DEBUG("BTA_JV_RFCOMM_CLOSE_EVT: user_data:%d",
+                       (uintptr_t)user_data);
+      on_rfc_close(&p_data->rfc_close, (uintptr_t)user_data);
+      break;
+
+    case BTA_JV_RFCOMM_WRITE_EVT:
+      on_rfc_write_done(&p_data->rfc_write, (uintptr_t)user_data);
+      break;
+
+    case BTA_JV_RFCOMM_CONG_EVT:
+      on_rfc_outgoing_congest(&p_data->rfc_cong, (uintptr_t)user_data);
+      break;
+
+    case BTA_JV_RFCOMM_DATA_IND_EVT:
+      // Unused.
+      break;
+
+    default:
+      LOG_ERROR(LOG_TAG, "%s unhandled event %d, slot id: %zi", __func__, event,
+                (uintptr_t)user_data);
+      break;
+  }
+  return new_user_data;
+}
+
+static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV* p_data, void* user_data) {
+  uint32_t id = PTR_TO_UINT(user_data);
+  switch (event) {
+    case BTA_JV_GET_SCN_EVT: {
+      std::unique_lock<std::recursive_mutex> lock(slot_lock);
+      rfc_slot_t* rs = find_rfc_slot_by_id(id);
+      int new_scn = p_data->scn;
+
+      if (rs && (new_scn != 0)) {
+        rs->scn = new_scn;
+        /* BTA_JvCreateRecordByUser will only create a record if a UUID is
+         * specified,
+         * else it just allocate a RFC channel and start the RFCOMM thread -
+         * needed
+         * for the java
+         * layer to get a RFCOMM channel.
+         * If uuid is null the create_sdp_record() will be called from Java when
+         * it
+         * has received the RFCOMM and L2CAP channel numbers through the
+         * sockets.*/
+
+        // Send channel ID to java layer
+        if (!send_app_scn(rs)) {
+          // closed
+          APPL_TRACE_DEBUG("send_app_scn() failed, close rs->id:%d", rs->id);
+          cleanup_rfc_slot(rs);
+        } else {
+          if (rs->is_service_uuid_valid == true) {
+            // We already have data for SDP record, create it (RFC-only
+            // profiles)
+            BTA_JvCreateRecordByUser(UINT_TO_PTR(rs->id));
+          } else {
+            APPL_TRACE_DEBUG(
+                "is_service_uuid_valid==false - don't set SDP-record, "
+                "just start the RFCOMM server",
+                rs->id);
+            // now start the rfcomm server after sdp & channel # assigned
+            BTA_JvRfcommStartServer(rs->security, rs->role, rs->scn,
+                                    MAX_RFC_SESSION, rfcomm_cback,
+                                    UINT_TO_PTR(rs->id));
+          }
+        }
+      } else if (rs) {
+        APPL_TRACE_ERROR(
+            "jv_dm_cback: Error: allocate channel %d, slot found:%p", rs->scn,
+            rs);
+        cleanup_rfc_slot(rs);
+      }
+      break;
+    }
+    case BTA_JV_GET_PSM_EVT: {
+      APPL_TRACE_DEBUG("Received PSM: 0x%04x", p_data->psm);
+      on_l2cap_psm_assigned(id, p_data->psm);
+      break;
+    }
+    case BTA_JV_CREATE_RECORD_EVT: {
+      std::unique_lock<std::recursive_mutex> lock(slot_lock);
+      rfc_slot_t* slot = find_rfc_slot_by_id(id);
+
+      if (slot && create_server_sdp_record(slot)) {
+        // Start the rfcomm server after sdp & channel # assigned.
+        BTA_JvRfcommStartServer(slot->security, slot->role, slot->scn,
+                                MAX_RFC_SESSION, rfcomm_cback,
+                                (void*)(uintptr_t)slot->id);
+      } else if (slot) {
+        APPL_TRACE_ERROR("jv_dm_cback: cannot start server, slot found:%p",
+                         slot);
+        cleanup_rfc_slot(slot);
+      }
+      break;
+    }
+
+    case BTA_JV_DISCOVERY_COMP_EVT: {
+      std::unique_lock<std::recursive_mutex> lock(slot_lock);
+      rfc_slot_t* slot = find_rfc_slot_by_id(id);
+      if (p_data->disc_comp.status == BTA_JV_SUCCESS && p_data->disc_comp.scn) {
+        if (slot && slot->f.doing_sdp_request) {
+          // Establish the connection if we successfully looked up a channel
+          // number to connect to.
+          if (BTA_JvRfcommConnect(slot->security, slot->role,
+                                  p_data->disc_comp.scn, slot->addr.address,
+                                  rfcomm_cback, (void*)(uintptr_t)slot->id) ==
+              BTA_JV_SUCCESS) {
+            slot->scn = p_data->disc_comp.scn;
+            slot->f.doing_sdp_request = false;
+            if (!send_app_scn(slot)) cleanup_rfc_slot(slot);
+          } else {
+            cleanup_rfc_slot(slot);
+          }
+        } else if (slot) {
+          // TODO(sharvil): this is really a logic error and we should probably
+          // assert.
+          LOG_ERROR(LOG_TAG,
+                    "%s SDP response returned but RFCOMM slot %d did not "
+                    "request SDP record.",
+                    __func__, id);
+        }
+      } else if (slot) {
+        cleanup_rfc_slot(slot);
+      }
+
+      // Find the next slot that needs to perform an SDP request and service it.
+      slot = find_rfc_slot_by_pending_sdp();
+      if (slot) {
+        tSDP_UUID sdp_uuid;
+        sdp_uuid.len = 16;
+        memcpy(sdp_uuid.uu.uuid128, slot->service_uuid,
+               sizeof(sdp_uuid.uu.uuid128));
+        BTA_JvStartDiscovery((uint8_t*)slot->addr.address, 1, &sdp_uuid,
+                             (void*)(uintptr_t)slot->id);
+        slot->f.pending_sdp_request = false;
+        slot->f.doing_sdp_request = true;
+      }
+      break;
+    }
+
+    default:
+      APPL_TRACE_DEBUG("unhandled event:%d, slot id:%d", event, id);
+      break;
+  }
+}
+
+typedef enum {
+  SENT_FAILED,
+  SENT_NONE,
+  SENT_PARTIAL,
+  SENT_ALL,
+} sent_status_t;
+
+static sent_status_t send_data_to_app(int fd, BT_HDR* p_buf) {
+  if (p_buf->len == 0) return SENT_ALL;
+
+  ssize_t sent;
+  OSI_NO_INTR(
+      sent = send(fd, p_buf->data + p_buf->offset, p_buf->len, MSG_DONTWAIT));
+
+  if (sent == -1) {
+    if (errno == EAGAIN || errno == EWOULDBLOCK) return SENT_NONE;
+    LOG_ERROR(LOG_TAG, "%s error writing RFCOMM data back to app: %s", __func__,
+              strerror(errno));
+    return SENT_FAILED;
+  }
+
+  if (sent == 0) return SENT_FAILED;
+
+  if (sent == p_buf->len) return SENT_ALL;
+
+  p_buf->offset += sent;
+  p_buf->len -= sent;
+  return SENT_PARTIAL;
+}
+
+static bool flush_incoming_que_on_wr_signal(rfc_slot_t* slot) {
+  while (!list_is_empty(slot->incoming_queue)) {
+    BT_HDR* p_buf = (BT_HDR*)list_front(slot->incoming_queue);
+    switch (send_data_to_app(slot->fd, p_buf)) {
+      case SENT_NONE:
+      case SENT_PARTIAL:
+        // monitor the fd to get callback when app is ready to receive data
+        btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_WR,
+                             slot->id);
+        return true;
+
+      case SENT_ALL:
+        list_remove(slot->incoming_queue, p_buf);
+        break;
+
+      case SENT_FAILED:
+        list_remove(slot->incoming_queue, p_buf);
+        return false;
+    }
+  }
+
+  // app is ready to receive data, tell stack to start the data flow
+  // fix me: need a jv flow control api to serialize the call in stack
+  APPL_TRACE_DEBUG(
+      "enable data flow, rfc_handle:0x%x, rfc_port_handle:0x%x, user_id:%d",
+      slot->rfc_handle, slot->rfc_port_handle, slot->id);
+  PORT_FlowControl_MaxCredit(slot->rfc_port_handle, true);
+  return true;
+}
+
+void btsock_rfc_signaled(UNUSED_ATTR int fd, int flags, uint32_t user_id) {
+  bool need_close = false;
+  std::unique_lock<std::recursive_mutex> lock(slot_lock);
+  rfc_slot_t* slot = find_rfc_slot_by_id(user_id);
+  if (!slot) return;
+
+  // Data available from app, tell stack we have outgoing data.
+  if (flags & SOCK_THREAD_FD_RD && !slot->f.server) {
+    if (slot->f.connected) {
+      // Make sure there's data pending in case the peer closed the socket.
+      int size = 0;
+      if (!(flags & SOCK_THREAD_FD_EXCEPTION) ||
+          (ioctl(slot->fd, FIONREAD, &size) == 0 && size)) {
+        BTA_JvRfcommWrite(slot->rfc_handle, slot->id);
+      }
+    } else {
+      LOG_ERROR(LOG_TAG,
+                "%s socket signaled for read while disconnected, slot: %d, "
+                "channel: %d",
+                __func__, slot->id, slot->scn);
+      need_close = true;
+    }
+  }
+
+  if (flags & SOCK_THREAD_FD_WR) {
+    // App is ready to receive more data, tell stack to enable data flow.
+    if (!slot->f.connected || !flush_incoming_que_on_wr_signal(slot)) {
+      LOG_ERROR(LOG_TAG,
+                "%s socket signaled for write while disconnected (or write "
+                "failure), slot: %d, channel: %d",
+                __func__, slot->id, slot->scn);
+      need_close = true;
+    }
+  }
+
+  if (need_close || (flags & SOCK_THREAD_FD_EXCEPTION)) {
+    // Clean up if there's no data pending.
+    int size = 0;
+    if (need_close || ioctl(slot->fd, FIONREAD, &size) != 0 || !size)
+      cleanup_rfc_slot(slot);
+  }
+}
+
+int bta_co_rfc_data_incoming(void* user_data, BT_HDR* p_buf) {
+  int app_uid = -1;
+  uint64_t bytes_rx = 0;
+  int ret = 0;
+  uint32_t id = (uintptr_t)user_data;
+  std::unique_lock<std::recursive_mutex> lock(slot_lock);
+  rfc_slot_t* slot = find_rfc_slot_by_id(id);
+  if (!slot) return 0;
+
+  app_uid = slot->app_uid;
+  bytes_rx = p_buf->len;
+
+  if (list_is_empty(slot->incoming_queue)) {
+    switch (send_data_to_app(slot->fd, p_buf)) {
+      case SENT_NONE:
+      case SENT_PARTIAL:
+        list_append(slot->incoming_queue, p_buf);
+        btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_WR,
+                             slot->id);
+        break;
+
+      case SENT_ALL:
+        osi_free(p_buf);
+        ret = 1;  // Enable data flow.
+        break;
+
+      case SENT_FAILED:
+        osi_free(p_buf);
+        cleanup_rfc_slot(slot);
+        break;
+    }
+  } else {
+    list_append(slot->incoming_queue, p_buf);
+  }
+
+  uid_set_add_rx(uid_set, app_uid, bytes_rx);
+
+  return ret;  // Return 0 to disable data flow.
+}
+
+int bta_co_rfc_data_outgoing_size(void* user_data, int* size) {
+  uint32_t id = (uintptr_t)user_data;
+  *size = 0;
+  std::unique_lock<std::recursive_mutex> lock(slot_lock);
+  rfc_slot_t* slot = find_rfc_slot_by_id(id);
+  if (!slot) return false;
+
+  if (ioctl(slot->fd, FIONREAD, size) != 0) {
+    LOG_ERROR(LOG_TAG,
+              "%s unable to determine bytes remaining to be read on fd %d: %s",
+              __func__, slot->fd, strerror(errno));
+    cleanup_rfc_slot(slot);
+    return false;
+  }
+
+  return true;
+}
+
+int bta_co_rfc_data_outgoing(void* user_data, uint8_t* buf, uint16_t size) {
+  std::unique_lock<std::recursive_mutex> lock(slot_lock);
+  uint32_t id = (uintptr_t)user_data;
+  rfc_slot_t* slot = find_rfc_slot_by_id(id);
+  if (!slot) return false;
+
+  ssize_t received;
+  OSI_NO_INTR(received = recv(slot->fd, buf, size, 0));
+
+  if (received != size) {
+    LOG_ERROR(LOG_TAG, "%s error receiving RFCOMM data from app: %s", __func__,
+              strerror(errno));
+    cleanup_rfc_slot(slot);
+    return false;
+  }
+
+  return true;
+}
diff --git a/bt/btif/src/btif_sock_sco.cc b/bt/btif/src/btif_sock_sco.cc
new file mode 100644
index 0000000..80c0794
--- /dev/null
+++ b/bt/btif/src/btif_sock_sco.cc
@@ -0,0 +1,339 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_btif_sock_sco"
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <mutex>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+
+#include "btif_common.h"
+#include "osi/include/allocator.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/socket.h"
+#include "osi/include/thread.h"
+
+// This module provides a socket abstraction for SCO connections to a higher
+// layer. It returns file descriptors representing two types of sockets:
+// listening (server) and connected (client) sockets. No SCO data is
+// transferred across these sockets; instead, they are used to manage SCO
+// connection lifecycles while the data routing takes place over the I2S bus.
+//
+// This code bridges the gap between the BTM layer, which implements SCO
+// connections, and the Android HAL. It adapts the BTM representation of SCO
+// connections (integer handles) to a file descriptor representation usable by
+// Android's LocalSocket implementation.
+//
+// Sample flow for an incoming connection:
+//   btsock_sco_listen()       - listen for incoming connections
+//   connection_request_cb()   - incoming connection request from remote host
+//   connect_completed_cb()    - connection successfully established
+//   socket_read_ready_cb()    - local host closed SCO socket
+//   disconnect_completed_cb() - connection terminated
+
+typedef struct {
+  uint16_t sco_handle;
+  socket_t* socket;
+  bool connect_completed;
+} sco_socket_t;
+
+// TODO: verify packet types that are being sent OTA.
+static tBTM_ESCO_PARAMS sco_parameters = {
+    BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec)              */
+    BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec)              */
+    0x000a,           /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3)  */
+    0x0060,           /* Inp Linear, Air CVSD, 2s Comp, 16bit     */
+    (BTM_SCO_LINK_ALL_PKT_MASK | BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+     BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+    BTM_ESCO_RETRANS_POWER /* Retransmission effort                      */
+};
+
+static sco_socket_t* sco_socket_establish_locked(bool is_listening,
+                                                 const bt_bdaddr_t* bd_addr,
+                                                 int* sock_fd);
+static sco_socket_t* sco_socket_new(void);
+static void sco_socket_free_locked(sco_socket_t* socket);
+static sco_socket_t* sco_socket_find_locked(uint16_t sco_handle);
+static void connection_request_cb(tBTM_ESCO_EVT event,
+                                  tBTM_ESCO_EVT_DATA* data);
+static void connect_completed_cb(uint16_t sco_handle);
+static void disconnect_completed_cb(uint16_t sco_handle);
+static void socket_read_ready_cb(socket_t* socket, void* context);
+
+// |sco_lock| protects all of the static variables below and
+// calls into the BTM layer.
+static std::mutex sco_lock;
+static list_t* sco_sockets;  // Owns a collection of sco_socket_t objects.
+static sco_socket_t* listen_sco_socket;  // Not owned, do not free.
+static thread_t* thread;                 // Not owned, do not free.
+
+bt_status_t btsock_sco_init(thread_t* thread_) {
+  assert(thread_ != NULL);
+
+  sco_sockets = list_new((list_free_cb)sco_socket_free_locked);
+  if (!sco_sockets) return BT_STATUS_FAIL;
+
+  thread = thread_;
+  BTM_SetEScoMode(BTM_LINK_TYPE_ESCO, &sco_parameters);
+
+  return BT_STATUS_SUCCESS;
+}
+
+bt_status_t btsock_sco_cleanup(void) {
+  list_free(sco_sockets);
+  sco_sockets = NULL;
+  return BT_STATUS_SUCCESS;
+}
+
+bt_status_t btsock_sco_listen(int* sock_fd, UNUSED_ATTR int flags) {
+  assert(sock_fd != NULL);
+
+  std::unique_lock<std::mutex> lock(sco_lock);
+
+  sco_socket_t* sco_socket = sco_socket_establish_locked(true, NULL, sock_fd);
+  if (!sco_socket) return BT_STATUS_FAIL;
+
+  BTM_RegForEScoEvts(sco_socket->sco_handle, connection_request_cb);
+  listen_sco_socket = sco_socket;
+
+  return BT_STATUS_SUCCESS;
+}
+
+bt_status_t btsock_sco_connect(const bt_bdaddr_t* bd_addr, int* sock_fd,
+                               UNUSED_ATTR int flags) {
+  assert(bd_addr != NULL);
+  assert(sock_fd != NULL);
+
+  std::unique_lock<std::mutex> lock(sco_lock);
+  sco_socket_t* sco_socket =
+      sco_socket_establish_locked(false, bd_addr, sock_fd);
+
+  return (sco_socket != NULL) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+// Must be called with |lock| held.
+static sco_socket_t* sco_socket_establish_locked(bool is_listening,
+                                                 const bt_bdaddr_t* bd_addr,
+                                                 int* sock_fd) {
+  int pair[2] = {INVALID_FD, INVALID_FD};
+  sco_socket_t* sco_socket = NULL;
+  socket_t* socket = NULL;
+  tBTM_STATUS status;
+
+  if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pair) == -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to allocate socket pair: %s", __func__,
+              strerror(errno));
+    goto error;
+  }
+
+  sco_socket = sco_socket_new();
+  if (!sco_socket) {
+    LOG_ERROR(LOG_TAG, "%s unable to allocate new SCO socket.", __func__);
+    goto error;
+  }
+
+  status = BTM_CreateSco((uint8_t*)bd_addr, !is_listening,
+                         sco_parameters.packet_types, &sco_socket->sco_handle,
+                         connect_completed_cb, disconnect_completed_cb);
+  if (status != BTM_CMD_STARTED) {
+    LOG_ERROR(LOG_TAG, "%s unable to create SCO socket: %d", __func__, status);
+    goto error;
+  }
+
+  socket = socket_new_from_fd(pair[1]);
+  if (!socket) {
+    LOG_ERROR(LOG_TAG, "%s unable to allocate socket from file descriptor %d.",
+              __func__, pair[1]);
+    goto error;
+  }
+
+  *sock_fd = pair[0];           // Transfer ownership of one end to caller.
+  sco_socket->socket = socket;  // Hang on to the other end.
+  list_append(sco_sockets, sco_socket);
+
+  socket_register(socket, thread_get_reactor(thread), sco_socket,
+                  socket_read_ready_cb, NULL);
+  return sco_socket;
+
+error:;
+  if (pair[0] != INVALID_FD) close(pair[0]);
+  if (pair[1] != INVALID_FD) close(pair[1]);
+
+  sco_socket_free_locked(sco_socket);
+  return NULL;
+}
+
+static sco_socket_t* sco_socket_new(void) {
+  sco_socket_t* sco_socket = (sco_socket_t*)osi_calloc(sizeof(sco_socket_t));
+  sco_socket->sco_handle = BTM_INVALID_SCO_INDEX;
+  return sco_socket;
+}
+
+// Must be called with |lock| held except during teardown when we know the
+// socket thread
+// is no longer alive.
+static void sco_socket_free_locked(sco_socket_t* sco_socket) {
+  if (!sco_socket) return;
+
+  if (sco_socket->sco_handle != BTM_INVALID_SCO_INDEX)
+    BTM_RemoveSco(sco_socket->sco_handle);
+  socket_free(sco_socket->socket);
+  osi_free(sco_socket);
+}
+
+// Must be called with |lock| held.
+static sco_socket_t* sco_socket_find_locked(uint16_t sco_handle) {
+  for (const list_node_t* node = list_begin(sco_sockets);
+       node != list_end(sco_sockets); node = list_next(node)) {
+    sco_socket_t* sco_socket = (sco_socket_t*)list_node(node);
+    if (sco_socket->sco_handle == sco_handle) return sco_socket;
+  }
+  return NULL;
+}
+
+static void connection_request_cb(tBTM_ESCO_EVT event,
+                                  tBTM_ESCO_EVT_DATA* data) {
+  assert(data != NULL);
+
+  // Don't care about change of link parameters, only connection requests.
+  if (event != BTM_ESCO_CONN_REQ_EVT) return;
+
+  std::unique_lock<std::mutex> lock(sco_lock);
+
+  const tBTM_ESCO_CONN_REQ_EVT_DATA* conn_data = &data->conn_evt;
+  sco_socket_t* sco_socket = sco_socket_find_locked(conn_data->sco_inx);
+  int client_fd = INVALID_FD;
+
+  uint16_t temp;
+  sco_socket_t* new_sco_socket;
+
+  if (!sco_socket) {
+    LOG_ERROR(LOG_TAG, "%s unable to find sco_socket for handle: %hu", __func__,
+              conn_data->sco_inx);
+    goto error;
+  }
+
+  if (sco_socket != listen_sco_socket) {
+    LOG_ERROR(
+        LOG_TAG,
+        "%s received connection request on non-listening socket handle: %hu",
+        __func__, conn_data->sco_inx);
+    goto error;
+  }
+
+  new_sco_socket = sco_socket_establish_locked(true, NULL, &client_fd);
+  if (!new_sco_socket) {
+    LOG_ERROR(LOG_TAG, "%s unable to allocate new sco_socket.", __func__);
+    goto error;
+  }
+
+  // Swap socket->sco_handle and new_socket->sco_handle
+  temp = sco_socket->sco_handle;
+  sco_socket->sco_handle = new_sco_socket->sco_handle;
+  new_sco_socket->sco_handle = temp;
+
+  sock_connect_signal_t connect_signal;
+  connect_signal.size = sizeof(connect_signal);
+  memcpy(&connect_signal.bd_addr, conn_data->bd_addr, sizeof(bt_bdaddr_t));
+  connect_signal.channel = 0;
+  connect_signal.status = 0;
+
+  if (socket_write_and_transfer_fd(sco_socket->socket, &connect_signal,
+                                   sizeof(connect_signal),
+                                   client_fd) != sizeof(connect_signal)) {
+    LOG_ERROR(LOG_TAG,
+              "%s unable to send new file descriptor to listening socket.",
+              __func__);
+    goto error;
+  }
+
+  BTM_RegForEScoEvts(listen_sco_socket->sco_handle, connection_request_cb);
+  BTM_EScoConnRsp(conn_data->sco_inx, HCI_SUCCESS, NULL);
+
+  return;
+
+error:;
+  if (client_fd != INVALID_FD) close(client_fd);
+  BTM_EScoConnRsp(conn_data->sco_inx, HCI_ERR_HOST_REJECT_RESOURCES, NULL);
+}
+
+static void connect_completed_cb(uint16_t sco_handle) {
+  std::unique_lock<std::mutex> lock(sco_lock);
+
+  sco_socket_t* sco_socket = sco_socket_find_locked(sco_handle);
+  if (!sco_socket) {
+    LOG_ERROR(LOG_TAG, "%s SCO socket not found on connect for handle: %hu",
+              __func__, sco_handle);
+    return;
+  }
+
+  // If sco_socket->socket was closed, we should tear down because there is no
+  // app-level
+  // interest in the SCO socket.
+  if (!sco_socket->socket) {
+    BTM_RemoveSco(sco_socket->sco_handle);
+    list_remove(sco_sockets, sco_socket);
+    return;
+  }
+
+  sco_socket->connect_completed = true;
+}
+
+static void disconnect_completed_cb(uint16_t sco_handle) {
+  std::unique_lock<std::mutex> lock(sco_lock);
+
+  sco_socket_t* sco_socket = sco_socket_find_locked(sco_handle);
+  if (!sco_socket) {
+    LOG_ERROR(LOG_TAG, "%s SCO socket not found on disconnect for handle: %hu",
+              __func__, sco_handle);
+    return;
+  }
+
+  list_remove(sco_sockets, sco_socket);
+}
+
+static void socket_read_ready_cb(UNUSED_ATTR socket_t* socket, void* context) {
+  std::unique_lock<std::mutex> lock(sco_lock);
+
+  sco_socket_t* sco_socket = (sco_socket_t*)context;
+  socket_free(sco_socket->socket);
+  sco_socket->socket = NULL;
+
+  // Defer the underlying disconnect until the connection completes
+  // since the BTM code doesn't behave correctly when a disconnect
+  // request is issued while a connect is in progress. The fact that
+  // sco_socket->socket == NULL indicates to the connect callback
+  // routine that the socket is no longer desired and should be torn
+  // down.
+  if (sco_socket->connect_completed || sco_socket == listen_sco_socket) {
+    if (BTM_RemoveSco(sco_socket->sco_handle) == BTM_SUCCESS)
+      list_remove(sco_sockets, sco_socket);
+    if (sco_socket == listen_sco_socket) listen_sco_socket = NULL;
+  }
+}
diff --git a/bt/btif/src/btif_sock_sdp.cc b/bt/btif/src/btif_sock_sdp.cc
new file mode 100644
index 0000000..21b2c0b
--- /dev/null
+++ b/bt/btif/src/btif_sock_sdp.cc
@@ -0,0 +1,470 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_btif_sock_sdp"
+
+#include "btif_sock_sdp.h"
+
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+
+#include "../bta/pb/bta_pbs_int.h"
+#include "../include/bta_op_api.h"
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bta_api.h"
+#include "bta_jv_api.h"
+#include "btif_common.h"
+#include "btif_sock_util.h"
+#include "btif_util.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "hcimsgs.h"
+#include "sdp_api.h"
+#include "utl.h"
+
+// This module provides an abstraction on top of the lower-level SDP database
+// code for registration and discovery of various bluetooth sockets.
+//
+// This code also provides for on-demand registration of "pre-registered"
+// services as a backwards compatibility function to third-party applications
+// expecting a bluez stack.
+
+// Realm Character Set -- 0 is ASCII
+#define BTA_PBS_REALM_CHARSET 0
+
+// Specifies whether or not client's user id is required during obex
+// authentication
+#define BTA_PBS_USERID_REQ FALSE
+
+static const tBTA_PBS_CFG bta_pbs_cfg = {
+    BTA_PBS_REALM_CHARSET,  // realm_charset: Server only
+    BTA_PBS_USERID_REQ,     // userid_req: Server only
+    (BTA_PBS_SUPF_DOWNLOAD | BTA_PBS_SURF_BROWSE),  // supported_features
+    BTA_PBS_REPOSIT_LOCAL,                          // supported_repositories
+};
+
+// object format lookup table
+#define OBEX_PUSH_NUM_FORMATS 7
+
+static const tBTA_OP_FMT bta_ops_obj_fmt[OBEX_PUSH_NUM_FORMATS] = {
+    BTA_OP_VCARD21_FMT, BTA_OP_VCARD30_FMT, BTA_OP_VCAL_FMT, BTA_OP_ICAL_FMT,
+    BTA_OP_VNOTE_FMT,   BTA_OP_VMSG_FMT,    BTA_OP_OTHER_FMT};
+
+// TODO(jtgans): Figure out if we actually need this define. This is ifndef
+// defined in bt_target.h, but nowhere else, so right now, unless something
+// overrides this before bt_target.h sets it, it will always be bt_target.h's
+// version.
+#ifndef BTUI_OPS_FORMATS
+#define BTUI_OPS_FORMATS                                          \
+  (BTA_OP_VCARD21_MASK | BTA_OP_VCARD30_MASK | BTA_OP_VCAL_MASK | \
+   BTA_OP_ICAL_MASK | BTA_OP_VNOTE_MASK | BTA_OP_VMSG_MASK | BTA_OP_ANY_MASK)
+#endif
+
+#define RESERVED_SCN_PBS 19
+#define RESERVED_SCN_OPS 12
+
+#define UUID_MAX_LENGTH 16
+#define UUID_MATCHES(u1, u2) !memcmp(u1, u2, UUID_MAX_LENGTH)
+
+// Adds a protocol list and service name (if provided) to an SDP record given by
+// |sdp_handle|, and marks it as browseable. This is a shortcut for defining a
+// set of protocols that includes L2CAP, RFCOMM, and optionally OBEX. If
+// |with_obex| is |true|, then an additional OBEX protocol UUID will be included
+// at the end of the protocol list.
+//
+// Returns true if successful, otherwise false.
+static bool create_base_record(const uint32_t sdp_handle, const char* name,
+                               const uint16_t channel, const bool with_obex) {
+  APPL_TRACE_DEBUG("create_base_record: scn: %d, name: %s, with_obex: %d",
+                   channel, name, with_obex);
+
+  // Setup the protocol list and add it.
+  tSDP_PROTOCOL_ELEM proto_list[SDP_MAX_LIST_ELEMS];
+  int num_proto_elements = with_obex ? 3 : 2;
+
+  memset(proto_list, 0, num_proto_elements * sizeof(tSDP_PROTOCOL_ELEM));
+
+  proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+  proto_list[0].num_params = 0;
+  proto_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+  proto_list[1].num_params = 1;
+  proto_list[1].params[0] = channel;
+
+  if (with_obex == true) {
+    proto_list[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+    proto_list[2].num_params = 0;
+  }
+
+  // Mark the service as browseable.
+  uint16_t list = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+
+  const char* stage = "protocol_list";
+  if (!SDP_AddProtocolList(sdp_handle, num_proto_elements, proto_list))
+    goto error;
+
+  // Add the name to the SDP record.
+  if (name[0] != '\0') {
+    stage = "service_name";
+    if (!SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+                          (uint32_t)(strlen(name) + 1), (uint8_t*)name))
+      goto error;
+  }
+
+  stage = "browseable";
+  if (!SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &list))
+    goto error;
+
+  APPL_TRACE_DEBUG(
+      "create_base_record: successfully created base service "
+      "record, handle: 0x%08x, scn: %d, name: %s, with_obex: %d",
+      sdp_handle, channel, name, with_obex);
+  return true;
+
+error:
+  APPL_TRACE_ERROR(
+      "create_base_record: failed to create base service "
+      "record, stage: %s, scn: %d, name: %s, with_obex: %d",
+      stage, channel, name, with_obex);
+  return false;
+}
+
+// Registers a service with the given |name|, |uuid|, and |channel| in the SDP
+// database as a generic L2CAP RFCOMM protocol, storing its |uuid| as a service
+// class sequence.
+static int add_sdp_by_uuid(const char* name, const uint8_t* uuid,
+                           const uint16_t channel) {
+  APPL_TRACE_DEBUG("add_sdp_by_uuid: scn: %d, service_name: %s", channel, name);
+
+  uint32_t handle = SDP_CreateRecord();
+  if (handle == 0) {
+    APPL_TRACE_ERROR(
+        "add_sdp_by_uuid: failed to create sdp record, "
+        "scn: %d, service_name: %s",
+        channel, name);
+    return 0;
+  }
+
+  // Convert the |uuid| into a big-endian representation and add it as a
+  // sequence.
+  uint8_t type = UUID_DESC_TYPE;
+  uint8_t type_len = UUID_MAX_LENGTH;
+  uint8_t type_buf[48];
+  // Store the address of type buf in a pointer on the stack, so we can pass
+  // a double pointer to SDP_AddSequence
+  uint8_t* type_buf_ptr = type_buf;
+  uint8_t* tmp = type_buf;
+
+  // Create the base SDP record.
+  const char* stage = "create_base_record";
+  if (!create_base_record(handle, name, channel, false /* with_obex */))
+    goto error;
+
+  // Do the conversion to big-endian -- tmp is only used to iterate through the
+  // UUID array in the macro and serves no other purpose as the conversion
+  // macros are not hygenic.
+  { ARRAY_TO_BE_STREAM(tmp, uuid, UUID_MAX_LENGTH); }
+
+  stage = "service_class_sequence";
+  if (!SDP_AddSequence(handle, (uint16_t)ATTR_ID_SERVICE_CLASS_ID_LIST, 1,
+                       &type, &type_len, &type_buf_ptr))
+    goto error;
+
+  APPL_TRACE_DEBUG(
+      "add_sdp_by_uuid: service registered successfully, "
+      "service_name: %s, handle: 0x%08x",
+      name, handle);
+  return handle;
+
+error:
+  SDP_DeleteRecord(handle);
+  APPL_TRACE_ERROR(
+      "add_sdp_by_uuid: failed to register service "
+      "stage: %s, service_name: %s",
+      stage, name);
+  return 0;
+}
+
+// Registers a service with the given |name| and |channel| in the SDP
+// database as a PBAP protocol.
+static int add_pbap_sdp(const char* name, const int channel) {
+  APPL_TRACE_DEBUG("add_pbap_sdp: scn %d, service_name %s", channel, name);
+
+  uint32_t handle = SDP_CreateRecord();
+  if (handle == 0) {
+    APPL_TRACE_ERROR(
+        "add_pbap_sdp: failed to create sdp record, "
+        "service_name: %s",
+        name);
+    return 0;
+  }
+
+  uint16_t service = UUID_SERVCLASS_PBAP_PSE;
+
+  // Create the base SDP record.
+  const char* stage = "create_base_record";
+  if (!create_base_record(handle, name, channel, true /* with_obex */))
+    goto error;
+
+  // Add service class
+  stage = "service_class";
+  if (!SDP_AddServiceClassIdList(handle, 1, &service)) goto error;
+
+  // Add in the phone access descriptor
+  stage = "profile_descriptor_list";
+  if (!SDP_AddProfileDescriptorList(handle, UUID_SERVCLASS_PHONE_ACCESS,
+                                    BTA_PBS_DEFAULT_VERSION))
+    goto error;
+
+  // Set up our supported repositories
+  stage = "supported_repositories";
+  if (!SDP_AddAttribute(handle, ATTR_ID_SUPPORTED_REPOSITORIES, UINT_DESC_TYPE,
+                        1, (uint8_t*)&bta_pbs_cfg.supported_repositories))
+    goto error;
+
+  // Notify the system that we've got a new service class UUID.
+  bta_sys_add_uuid(UUID_SERVCLASS_PBAP_PSE);
+  APPL_TRACE_DEBUG(
+      "add_pbap_sdp: service registered successfully, "
+      "service_name: %s, handle: 0x%08x",
+      name, handle);
+
+  return handle;
+
+error:
+  SDP_DeleteRecord(handle);
+  APPL_TRACE_ERROR(
+      "add_pbap_sdp: failed to register PBAP service, stage: %s, "
+      "service_name: %s",
+      stage, name);
+  return 0;
+}
+// Registers a service with the given |name| and |channel| as an OBEX Push
+// protocol.
+static int add_ops_sdp(const char* name, const int channel) {
+  APPL_TRACE_DEBUG("add_ops_sdp: scn %d, service_name %s", channel, name);
+
+  uint32_t handle = SDP_CreateRecord();
+  if (handle == 0) {
+    APPL_TRACE_ERROR(
+        "add_ops_sdp: failed to create sdp record, "
+        "service_name: %s",
+        name);
+    return 0;
+  }
+
+  // Add sequence for supported types.
+  uint8_t desc_type[OBEX_PUSH_NUM_FORMATS];
+  uint8_t type_len[OBEX_PUSH_NUM_FORMATS];
+  uint8_t* type_value[OBEX_PUSH_NUM_FORMATS];
+  uint8_t j = 0;
+
+  uint16_t service = UUID_SERVCLASS_OBEX_OBJECT_PUSH;
+  tBTA_UTL_COD cod;
+
+  // Create the base SDP record.
+  const char* stage = "create_base_record";
+  if (!create_base_record(handle, name, channel, true /* with_obex */))
+    goto error;
+
+  // Add service class.
+  stage = "service_class";
+  if (!SDP_AddServiceClassIdList(handle, 1, &service)) goto error;
+
+  // Add the OBEX push profile descriptor.
+  stage = "profile_descriptor_list";
+  if (!SDP_AddProfileDescriptorList(handle, UUID_SERVCLASS_OBEX_OBJECT_PUSH,
+                                    0x0100))
+    goto error;
+
+  for (int i = 0; i < OBEX_PUSH_NUM_FORMATS; i++) {
+    if ((BTUI_OPS_FORMATS >> i) & 1) {
+      type_value[j] = (uint8_t*)(&bta_ops_obj_fmt[i]);
+      desc_type[j] = UINT_DESC_TYPE;
+      type_len[j++] = 1;
+    }
+  }
+
+  stage = "supported_types";
+  if (!SDP_AddSequence(handle, (uint16_t)ATTR_ID_SUPPORTED_FORMATS_LIST, j,
+                       desc_type, type_len, type_value))
+    goto error;
+
+  // Set class of device.
+  cod.service = BTM_COD_SERVICE_OBJ_TRANSFER;
+  stage = "class_of_device";
+  if (!utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS)) goto error;
+
+  // Notify the system that we've got a new service class UUID.
+  bta_sys_add_uuid(UUID_SERVCLASS_OBEX_OBJECT_PUSH);
+  APPL_TRACE_DEBUG(
+      "ad_maps_sdp: service registered successfully, "
+      "service_name: %s, handle 0x%08x)",
+      name, handle);
+
+  return handle;
+
+error:
+  SDP_DeleteRecord(handle);
+  APPL_TRACE_ERROR(
+      "add_ops_sdp: failed to register OPS service, "
+      "stage: %s, service_name: %s",
+      stage, name);
+  return 0;
+}
+
+// Registers a service with the given |name| and |channel| as a serial port
+// profile protocol.
+static int add_spp_sdp(const char* name, const int channel) {
+  APPL_TRACE_DEBUG("add_spp_sdp: scn %d, service_name %s", channel, name);
+
+  int handle = SDP_CreateRecord();
+  if (handle == 0) {
+    APPL_TRACE_ERROR(
+        "add_spp_sdp: failed to create sdp record, "
+        "service_name: %s",
+        name);
+    return 0;
+  }
+
+  // Create the base SDP record.
+  const char* stage = "create_base_record";
+  uint16_t service = UUID_SERVCLASS_SERIAL_PORT;
+
+  if (!create_base_record(handle, name, channel, false /* with_obex */))
+    goto error;
+
+  stage = "service_class";
+  if (!SDP_AddServiceClassIdList(handle, 1, &service)) goto error;
+
+  APPL_TRACE_DEBUG(
+      "add_spp_sdp: service registered successfully, "
+      "service_name: %s, handle 0x%08x)",
+      name, handle);
+
+  return handle;
+
+error:
+  SDP_DeleteRecord(handle);
+  APPL_TRACE_ERROR(
+      "add_spp_sdp: failed to register SPP service, "
+      "stage: %s, service_name: %s",
+      stage, name);
+  return 0;
+}
+
+// Adds an RFCOMM SDP record for a service with the given |name|, |uuid|, and
+// |channel|. This function attempts to identify the type of the service based
+// upon its |uuid|, and will override the |channel| with a reserved channel
+// number if the |uuid| matches one of the preregistered bluez SDP records.
+static int add_rfc_sdp_by_uuid(const char* name, const uint8_t* uuid,
+                               const int channel) {
+  APPL_TRACE_DEBUG("add_rfc_sdp_by_uuid: service_name: %s, channel: %d", name,
+                   channel);
+
+  /*
+   * Bluetooth Socket API relies on having preregistered bluez sdp records for
+   * HSAG, HFAG, OPP & PBAP that are mapped to rc chan 10, 11,12 & 19. Today
+   * HSAG and HFAG is routed to BRCM AG and are not using BT socket API so for
+   * now we will need to support OPP and PBAP to enable 3rd party developer apps
+   * running on BRCM Android.
+   *
+   * To do this we will check the UUID for the requested service and mimic the
+   * SDP records of bluez upon reception.  See functions add_opush() and
+   * add_pbap() in sdptool.c for actual records.
+   */
+
+  int final_channel = get_reserved_rfc_channel(uuid);
+
+  if (final_channel == -1) {
+    final_channel = channel;
+  }
+
+  int handle = 0;
+
+  if (UUID_MATCHES(UUID_OBEX_OBJECT_PUSH, uuid)) {
+    handle = add_ops_sdp(name, final_channel);
+  } else if (UUID_MATCHES(UUID_PBAP_PSE, uuid)) {
+    // PBAP Server is always channel 19
+    handle = add_pbap_sdp(name, final_channel);
+  } else if (UUID_MATCHES(UUID_SPP, uuid)) {
+    handle = add_spp_sdp(name, final_channel);
+  } else if (UUID_MATCHES(UUID_MAP_MAS, uuid)) {
+    // Record created by new SDP create record interface
+    handle = 0xff;
+  } else {
+    handle = add_sdp_by_uuid(name, uuid, final_channel);
+  }
+
+  return handle;
+}
+
+bool is_reserved_rfc_channel(const int channel) {
+  switch (channel) {
+    case RESERVED_SCN_PBS:
+    case RESERVED_SCN_OPS:
+      return true;
+  }
+
+  return false;
+}
+
+int get_reserved_rfc_channel(const uint8_t* uuid) {
+  if (UUID_MATCHES(UUID_PBAP_PSE, uuid)) {
+    return RESERVED_SCN_PBS;
+  } else if (UUID_MATCHES(UUID_OBEX_OBJECT_PUSH, uuid)) {
+    return RESERVED_SCN_OPS;
+  }
+
+  return -1;
+}
+
+// Adds an SDP record to the SDP database using the given |name|, |uuid|, and
+// |channel|. Note that if the |uuid| is empty, the |uuid| will be set based
+// upon the |channel| passed in.
+int add_rfc_sdp_rec(const char* name, const uint8_t* uuid, const int channel) {
+  if (is_uuid_empty(uuid)) {
+    switch (channel) {
+      case RESERVED_SCN_PBS:  // PBAP Reserved port
+        uuid = UUID_PBAP_PSE;
+        break;
+
+      case RESERVED_SCN_OPS:
+        uuid = UUID_OBEX_OBJECT_PUSH;
+        break;
+
+      default:
+        uuid = UUID_SPP;
+        break;
+    }
+  }
+
+  return add_rfc_sdp_by_uuid(name, uuid, channel);
+}
+
+// Deletes an SDP record with the given |handle|.
+void del_rfc_sdp_rec(int handle) {
+  APPL_TRACE_DEBUG("del_rfc_sdp_rec: handle:0x%x", handle);
+
+  if ((handle != -1) && (handle != 0)) BTA_JvDeleteRecord(handle);
+}
diff --git a/bt/btif/src/btif_sock_thread.cc b/bt/btif/src/btif_sock_thread.cc
new file mode 100644
index 0000000..1283a11
--- /dev/null
+++ b/bt/btif/src/btif_sock_thread.cc
@@ -0,0 +1,548 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ *  Filename:      btif_sock_thread.cc
+ *
+ *  Description:   socket select thread
+ *
+ ***********************************************************************************/
+
+#define LOG_TAG "bt_btif_sock"
+
+#include "btif_sock_thread.h"
+
+#include <alloca.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <features.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/poll.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <mutex>
+
+#include "bta_api.h"
+#include "btif_common.h"
+#include "btif_sock.h"
+#include "btif_sock_util.h"
+#include "btif_util.h"
+#include "osi/include/socket_utils/sockets.h"
+
+#define asrt(s)                                                              \
+  do {                                                                       \
+    if (!(s))                                                                \
+      APPL_TRACE_ERROR("## %s assert %s failed at line:%d ##", __func__, #s, \
+                       __LINE__)                                             \
+  } while (0)
+
+#define print_events(events)                                  \
+  do {                                                        \
+    APPL_TRACE_DEBUG("print poll event:%x", (events));        \
+    if ((events)&POLLIN) APPL_TRACE_DEBUG("   POLLIN ");      \
+    if ((events)&POLLPRI) APPL_TRACE_DEBUG("   POLLPRI ");    \
+    if ((events)&POLLOUT) APPL_TRACE_DEBUG("   POLLOUT ");    \
+    if ((events)&POLLERR) APPL_TRACE_DEBUG("   POLLERR ");    \
+    if ((events)&POLLHUP) APPL_TRACE_DEBUG("   POLLHUP ");    \
+    if ((events)&POLLNVAL) APPL_TRACE_DEBUG("   POLLNVAL ");  \
+    if ((events)&POLLRDHUP) APPL_TRACE_DEBUG("   POLLRDHUP"); \
+  } while (0)
+
+#define MAX_THREAD 8
+#define MAX_POLL 64
+#define POLL_EXCEPTION_EVENTS (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)
+#define IS_EXCEPTION(e) ((e)&POLL_EXCEPTION_EVENTS)
+#define IS_READ(e) ((e)&POLLIN)
+#define IS_WRITE(e) ((e)&POLLOUT)
+/*cmd executes in socket poll thread */
+#define CMD_WAKEUP 1
+#define CMD_EXIT 2
+#define CMD_ADD_FD 3
+#define CMD_REMOVE_FD 4
+#define CMD_USER_PRIVATE 5
+
+typedef struct {
+  struct pollfd pfd;
+  uint32_t user_id;
+  int type;
+  int flags;
+} poll_slot_t;
+typedef struct {
+  int cmd_fdr, cmd_fdw;
+  int poll_count;
+  poll_slot_t ps[MAX_POLL];
+  int psi[MAX_POLL];  // index of poll slot
+  volatile pthread_t thread_id;
+  btsock_signaled_cb callback;
+  btsock_cmd_cb cmd_callback;
+  int used;
+} thread_slot_t;
+static thread_slot_t ts[MAX_THREAD];
+
+static void* sock_poll_thread(void* arg);
+static inline void close_cmd_fd(int h);
+
+static inline void add_poll(int h, int fd, int type, int flags,
+                            uint32_t user_id);
+
+static std::recursive_mutex thread_slot_lock;
+
+static inline int create_thread(void* (*start_routine)(void*), void* arg,
+                                pthread_t* thread_id) {
+  pthread_attr_t thread_attr;
+  pthread_attr_init(&thread_attr);
+  pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+  int policy;
+  int min_pri = 0;
+  int ret = -1;
+  struct sched_param param;
+
+  if ((ret = pthread_create(thread_id, &thread_attr, start_routine, arg)) !=
+      0) {
+    APPL_TRACE_ERROR("pthread_create : %s", strerror(errno));
+    return ret;
+  }
+  /* We need to lower the priority of this thread to ensure the stack gets
+   * priority over transfer to a socket */
+  pthread_getschedparam(*thread_id, &policy, &param);
+  min_pri = sched_get_priority_min(policy);
+  if (param.sched_priority > min_pri) {
+    param.sched_priority -= 1;
+  }
+  pthread_setschedparam(*thread_id, policy, &param);
+  return ret;
+}
+static void init_poll(int cmd_fd);
+static int alloc_thread_slot() {
+  std::unique_lock<std::recursive_mutex> lock(thread_slot_lock);
+  int i;
+  // reversed order to save guard uninitialized access to 0 index
+  for (i = MAX_THREAD - 1; i >= 0; i--) {
+    APPL_TRACE_DEBUG("ts[%d].used:%d", i, ts[i].used);
+    if (!ts[i].used) {
+      ts[i].used = 1;
+      return i;
+    }
+  }
+  APPL_TRACE_ERROR("execeeded max thread count");
+  return -1;
+}
+static void free_thread_slot(int h) {
+  if (0 <= h && h < MAX_THREAD) {
+    close_cmd_fd(h);
+    ts[h].used = 0;
+  } else
+    APPL_TRACE_ERROR("invalid thread handle:%d", h);
+}
+int btsock_thread_init() {
+  static int initialized;
+  APPL_TRACE_DEBUG("in initialized:%d", initialized);
+  if (!initialized) {
+    initialized = 1;
+    int h;
+    for (h = 0; h < MAX_THREAD; h++) {
+      ts[h].cmd_fdr = ts[h].cmd_fdw = -1;
+      ts[h].used = 0;
+      ts[h].thread_id = -1;
+      ts[h].poll_count = 0;
+      ts[h].callback = NULL;
+      ts[h].cmd_callback = NULL;
+    }
+  }
+  return true;
+}
+int btsock_thread_create(btsock_signaled_cb callback,
+                         btsock_cmd_cb cmd_callback) {
+  asrt(callback || cmd_callback);
+  int h = alloc_thread_slot();
+  APPL_TRACE_DEBUG("alloc_thread_slot ret:%d", h);
+  if (h >= 0) {
+    init_poll(h);
+    pthread_t thread;
+    int status = create_thread(sock_poll_thread, (void*)(uintptr_t)h, &thread);
+    if (status) {
+      APPL_TRACE_ERROR("create_thread failed: %s", strerror(status));
+      free_thread_slot(h);
+      return -1;
+    }
+
+    ts[h].thread_id = thread;
+    APPL_TRACE_DEBUG("h:%d, thread id:%d", h, ts[h].thread_id);
+    ts[h].callback = callback;
+    ts[h].cmd_callback = cmd_callback;
+  }
+  return h;
+}
+
+/* create dummy socket pair used to wake up select loop */
+static inline void init_cmd_fd(int h) {
+  asrt(ts[h].cmd_fdr == -1 && ts[h].cmd_fdw == -1);
+  if (socketpair(AF_UNIX, SOCK_STREAM, 0, &ts[h].cmd_fdr) < 0) {
+    APPL_TRACE_ERROR("socketpair failed: %s", strerror(errno));
+    return;
+  }
+  APPL_TRACE_DEBUG("h:%d, cmd_fdr:%d, cmd_fdw:%d", h, ts[h].cmd_fdr,
+                   ts[h].cmd_fdw);
+  // add the cmd fd for read & write
+  add_poll(h, ts[h].cmd_fdr, 0, SOCK_THREAD_FD_RD, 0);
+}
+static inline void close_cmd_fd(int h) {
+  if (ts[h].cmd_fdr != -1) {
+    close(ts[h].cmd_fdr);
+    ts[h].cmd_fdr = -1;
+  }
+  if (ts[h].cmd_fdw != -1) {
+    close(ts[h].cmd_fdw);
+    ts[h].cmd_fdw = -1;
+  }
+}
+typedef struct {
+  int id;
+  int fd;
+  int type;
+  int flags;
+  uint32_t user_id;
+} sock_cmd_t;
+int btsock_thread_add_fd(int h, int fd, int type, int flags, uint32_t user_id) {
+  if (h < 0 || h >= MAX_THREAD) {
+    APPL_TRACE_ERROR("invalid bt thread handle:%d", h);
+    return false;
+  }
+  if (ts[h].cmd_fdw == -1) {
+    APPL_TRACE_ERROR(
+        "cmd socket is not created. socket thread may not initialized");
+    return false;
+  }
+  if (flags & SOCK_THREAD_ADD_FD_SYNC) {
+    // must executed in socket poll thread
+    if (ts[h].thread_id == pthread_self()) {
+      // cleanup one-time flags
+      flags &= ~SOCK_THREAD_ADD_FD_SYNC;
+      add_poll(h, fd, type, flags, user_id);
+      return true;
+    }
+    APPL_TRACE_DEBUG(
+        "THREAD_ADD_FD_SYNC is not called in poll thread, fallback to async");
+  }
+  sock_cmd_t cmd = {CMD_ADD_FD, fd, type, flags, user_id};
+  APPL_TRACE_DEBUG("adding fd:%d, flags:0x%x", fd, flags);
+
+  ssize_t ret;
+  OSI_NO_INTR(ret = send(ts[h].cmd_fdw, &cmd, sizeof(cmd), 0));
+
+  return ret == sizeof(cmd);
+}
+
+bool btsock_thread_remove_fd_and_close(int thread_handle, int fd) {
+  if (thread_handle < 0 || thread_handle >= MAX_THREAD) {
+    APPL_TRACE_ERROR("%s invalid thread handle: %d", __func__, thread_handle);
+    return false;
+  }
+  if (fd == -1) {
+    APPL_TRACE_ERROR("%s invalid file descriptor.", __func__);
+    return false;
+  }
+
+  sock_cmd_t cmd = {CMD_REMOVE_FD, fd, 0, 0, 0};
+
+  ssize_t ret;
+  OSI_NO_INTR(ret = send(ts[thread_handle].cmd_fdw, &cmd, sizeof(cmd), 0));
+
+  return ret == sizeof(cmd);
+}
+
+int btsock_thread_post_cmd(int h, int type, const unsigned char* data, int size,
+                           uint32_t user_id) {
+  if (h < 0 || h >= MAX_THREAD) {
+    APPL_TRACE_ERROR("invalid bt thread handle:%d", h);
+    return false;
+  }
+  if (ts[h].cmd_fdw == -1) {
+    APPL_TRACE_ERROR(
+        "cmd socket is not created. socket thread may not initialized");
+    return false;
+  }
+  sock_cmd_t cmd = {CMD_USER_PRIVATE, 0, type, size, user_id};
+  APPL_TRACE_DEBUG("post cmd type:%d, size:%d, h:%d, ", type, size, h);
+  sock_cmd_t* cmd_send = &cmd;
+  int size_send = sizeof(cmd);
+  if (data && size) {
+    size_send = sizeof(cmd) + size;
+    cmd_send = (sock_cmd_t*)alloca(size_send);
+    if (cmd_send) {
+      *cmd_send = cmd;
+      memcpy(cmd_send + 1, data, size);
+    } else {
+      APPL_TRACE_ERROR("alloca failed at h:%d, cmd type:%d, size:%d", h, type,
+                       size_send);
+      return false;
+    }
+  }
+
+  ssize_t ret;
+  OSI_NO_INTR(ret = send(ts[h].cmd_fdw, cmd_send, size_send, 0));
+
+  return ret == size_send;
+}
+int btsock_thread_wakeup(int h) {
+  if (h < 0 || h >= MAX_THREAD) {
+    APPL_TRACE_ERROR("invalid bt thread handle:%d", h);
+    return false;
+  }
+  if (ts[h].cmd_fdw == -1) {
+    APPL_TRACE_ERROR("thread handle:%d, cmd socket is not created", h);
+    return false;
+  }
+  sock_cmd_t cmd = {CMD_WAKEUP, 0, 0, 0, 0};
+
+  ssize_t ret;
+  OSI_NO_INTR(ret = send(ts[h].cmd_fdw, &cmd, sizeof(cmd), 0));
+
+  return ret == sizeof(cmd);
+}
+int btsock_thread_exit(int h) {
+  if (h < 0 || h >= MAX_THREAD) {
+    APPL_TRACE_ERROR("invalid bt thread handle:%d", h);
+    return false;
+  }
+  if (ts[h].cmd_fdw == -1) {
+    APPL_TRACE_ERROR("cmd socket is not created");
+    return false;
+  }
+  sock_cmd_t cmd = {CMD_EXIT, 0, 0, 0, 0};
+
+  ssize_t ret;
+  OSI_NO_INTR(ret = send(ts[h].cmd_fdw, &cmd, sizeof(cmd), 0));
+
+  if (ret == sizeof(cmd)) {
+    pthread_join(ts[h].thread_id, 0);
+    free_thread_slot(h);
+    return true;
+  }
+  return false;
+}
+static void init_poll(int h) {
+  int i;
+  ts[h].poll_count = 0;
+  ts[h].thread_id = -1;
+  ts[h].callback = NULL;
+  ts[h].cmd_callback = NULL;
+  for (i = 0; i < MAX_POLL; i++) {
+    ts[h].ps[i].pfd.fd = -1;
+    ts[h].psi[i] = -1;
+  }
+  init_cmd_fd(h);
+}
+static inline unsigned int flags2pevents(int flags) {
+  unsigned int pevents = 0;
+  if (flags & SOCK_THREAD_FD_WR) pevents |= POLLOUT;
+  if (flags & SOCK_THREAD_FD_RD) pevents |= POLLIN;
+  pevents |= POLL_EXCEPTION_EVENTS;
+  return pevents;
+}
+
+static inline void set_poll(poll_slot_t* ps, int fd, int type, int flags,
+                            uint32_t user_id) {
+  ps->pfd.fd = fd;
+  ps->user_id = user_id;
+  if (ps->type != 0 && ps->type != type)
+    APPL_TRACE_ERROR(
+        "poll socket type should not changed! type was:%d, type now:%d",
+        ps->type, type);
+  ps->type = type;
+  ps->flags = flags;
+  ps->pfd.events = flags2pevents(flags);
+  ps->pfd.revents = 0;
+}
+static inline void add_poll(int h, int fd, int type, int flags,
+                            uint32_t user_id) {
+  asrt(fd != -1);
+  int i;
+  int empty = -1;
+  poll_slot_t* ps = ts[h].ps;
+
+  for (i = 0; i < MAX_POLL; i++) {
+    if (ps[i].pfd.fd == fd) {
+      asrt(ts[h].poll_count < MAX_POLL);
+
+      set_poll(&ps[i], fd, type, flags | ps[i].flags, user_id);
+      return;
+    } else if (empty < 0 && ps[i].pfd.fd == -1)
+      empty = i;
+  }
+  if (empty >= 0) {
+    asrt(ts[h].poll_count < MAX_POLL);
+    set_poll(&ps[empty], fd, type, flags, user_id);
+    ++ts[h].poll_count;
+    return;
+  }
+  APPL_TRACE_ERROR("exceeded max poll slot:%d!", MAX_POLL);
+}
+static inline void remove_poll(int h, poll_slot_t* ps, int flags) {
+  if (flags == ps->flags) {
+    // all monitored events signaled. To remove it, just clear the slot
+    --ts[h].poll_count;
+    memset(ps, 0, sizeof(*ps));
+    ps->pfd.fd = -1;
+  } else {
+    // one read or one write monitor event signaled, removed the accordding bit
+    ps->flags &= ~flags;
+    // update the poll events mask
+    ps->pfd.events = flags2pevents(ps->flags);
+  }
+}
+static int process_cmd_sock(int h) {
+  sock_cmd_t cmd = {-1, 0, 0, 0, 0};
+  int fd = ts[h].cmd_fdr;
+
+  ssize_t ret;
+  OSI_NO_INTR(ret = recv(fd, &cmd, sizeof(cmd), MSG_WAITALL));
+
+  if (ret != sizeof(cmd)) {
+    APPL_TRACE_ERROR("recv cmd errno:%d", errno);
+    return false;
+  }
+  APPL_TRACE_DEBUG("cmd.id:%d", cmd.id);
+  switch (cmd.id) {
+    case CMD_ADD_FD:
+      add_poll(h, cmd.fd, cmd.type, cmd.flags, cmd.user_id);
+      break;
+    case CMD_REMOVE_FD:
+      for (int i = 1; i < MAX_POLL; ++i) {
+        poll_slot_t* poll_slot = &ts[h].ps[i];
+        if (poll_slot->pfd.fd == cmd.fd) {
+          remove_poll(h, poll_slot, poll_slot->flags);
+          break;
+        }
+      }
+      close(cmd.fd);
+      break;
+    case CMD_WAKEUP:
+      break;
+    case CMD_USER_PRIVATE:
+      asrt(ts[h].cmd_callback);
+      if (ts[h].cmd_callback)
+        ts[h].cmd_callback(fd, cmd.type, cmd.flags, cmd.user_id);
+      break;
+    case CMD_EXIT:
+      return false;
+    default:
+      APPL_TRACE_DEBUG("unknown cmd: %d", cmd.id);
+      break;
+  }
+  return true;
+}
+static void process_data_sock(int h, struct pollfd* pfds, int count) {
+  asrt(count <= ts[h].poll_count);
+  int i;
+  for (i = 1; i < ts[h].poll_count; i++) {
+    if (pfds[i].revents) {
+      int ps_i = ts[h].psi[i];
+      asrt(pfds[i].fd == ts[h].ps[ps_i].pfd.fd);
+      uint32_t user_id = ts[h].ps[ps_i].user_id;
+      int type = ts[h].ps[ps_i].type;
+      int flags = 0;
+      print_events(pfds[i].revents);
+      if (IS_READ(pfds[i].revents)) {
+        flags |= SOCK_THREAD_FD_RD;
+      }
+      if (IS_WRITE(pfds[i].revents)) {
+        flags |= SOCK_THREAD_FD_WR;
+      }
+      if (IS_EXCEPTION(pfds[i].revents)) {
+        flags |= SOCK_THREAD_FD_EXCEPTION;
+        // remove the whole slot not flags
+        remove_poll(h, &ts[h].ps[ps_i], ts[h].ps[ps_i].flags);
+      } else if (flags)
+        remove_poll(h, &ts[h].ps[ps_i],
+                    flags);  // remove the monitor flags that already processed
+      if (flags) ts[h].callback(pfds[i].fd, type, flags, user_id);
+    }
+  }
+}
+
+static void prepare_poll_fds(int h, struct pollfd* pfds) {
+  int count = 0;
+  int ps_i = 0;
+  int pfd_i = 0;
+  asrt(ts[h].poll_count <= MAX_POLL);
+  memset(pfds, 0, sizeof(pfds[0]) * ts[h].poll_count);
+  while (count < ts[h].poll_count) {
+    if (ps_i >= MAX_POLL) {
+      APPL_TRACE_ERROR(
+          "exceed max poll range, ps_i:%d, MAX_POLL:%d, count:%d, "
+          "ts[h].poll_count:%d",
+          ps_i, MAX_POLL, count, ts[h].poll_count);
+      return;
+    }
+    if (ts[h].ps[ps_i].pfd.fd >= 0) {
+      pfds[pfd_i] = ts[h].ps[ps_i].pfd;
+      ts[h].psi[pfd_i] = ps_i;
+      count++;
+      pfd_i++;
+    }
+    ps_i++;
+  }
+}
+static void* sock_poll_thread(void* arg) {
+  struct pollfd pfds[MAX_POLL];
+  memset(pfds, 0, sizeof(pfds));
+  int h = (intptr_t)arg;
+  for (;;) {
+    prepare_poll_fds(h, pfds);
+    int ret;
+    OSI_NO_INTR(ret = poll(pfds, ts[h].poll_count, -1));
+    if (ret == -1) {
+      APPL_TRACE_ERROR("poll ret -1, exit the thread, errno:%d, err:%s", errno,
+                       strerror(errno));
+      break;
+    }
+    if (ret != 0) {
+      int need_process_data_fd = true;
+      if (pfds[0].revents)  // cmd fd always is the first one
+      {
+        asrt(pfds[0].fd == ts[h].cmd_fdr);
+        if (!process_cmd_sock(h)) {
+          APPL_TRACE_DEBUG("h:%d, process_cmd_sock return false, exit...", h);
+          break;
+        }
+        if (ret == 1)
+          need_process_data_fd = false;
+        else
+          ret--;  // exclude the cmd fd
+      }
+      if (need_process_data_fd) process_data_sock(h, pfds, ret);
+    } else {
+      APPL_TRACE_DEBUG("no data, select ret: %d", ret)
+    };
+  }
+  ts[h].thread_id = -1;
+  APPL_TRACE_DEBUG("socket poll thread exiting, h:%d", h);
+  return 0;
+}
diff --git a/bt/btif/src/btif_sock_util.cc b/bt/btif/src/btif_sock_util.cc
new file mode 100644
index 0000000..bf76100
--- /dev/null
+++ b/bt/btif/src/btif_sock_util.cc
@@ -0,0 +1,233 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_sock"
+
+#include "btif_sock_util.h"
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bta_api.h"
+#include "bta_jv_api.h"
+#include "bta_jv_co.h"
+#include "btif_common.h"
+#include "btif_sock_sdp.h"
+#include "btif_sock_thread.h"
+#include "btif_util.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "hcimsgs.h"
+#include "osi/include/log.h"
+#include "port_api.h"
+#include "sdp_api.h"
+
+#define asrt(s)                                                              \
+  do {                                                                       \
+    if (!(s))                                                                \
+      BTIF_TRACE_ERROR("## %s assert %s failed at line:%d ##", __func__, #s, \
+                       __LINE__)                                             \
+  } while (0)
+
+int sock_send_all(int sock_fd, const uint8_t* buf, int len) {
+  int s = len;
+
+  while (s) {
+    ssize_t ret;
+    OSI_NO_INTR(ret = send(sock_fd, buf, s, 0));
+    if (ret <= 0) {
+      BTIF_TRACE_ERROR("sock fd:%d send errno:%d, ret:%d", sock_fd, errno, ret);
+      return -1;
+    }
+    buf += ret;
+    s -= ret;
+  }
+  return len;
+}
+int sock_recv_all(int sock_fd, uint8_t* buf, int len) {
+  int r = len;
+
+  while (r) {
+    ssize_t ret;
+    OSI_NO_INTR(ret = recv(sock_fd, buf, r, MSG_WAITALL));
+    if (ret <= 0) {
+      BTIF_TRACE_ERROR("sock fd:%d recv errno:%d, ret:%d", sock_fd, errno, ret);
+      return -1;
+    }
+    buf += ret;
+    r -= ret;
+  }
+  return len;
+}
+
+int sock_send_fd(int sock_fd, const uint8_t* buf, int len, int send_fd) {
+  struct msghdr msg;
+  unsigned char* buffer = (unsigned char*)buf;
+  memset(&msg, 0, sizeof(msg));
+
+  struct cmsghdr* cmsg;
+  char msgbuf[CMSG_SPACE(1)];
+  asrt(send_fd != -1);
+  if (sock_fd == -1 || send_fd == -1) return -1;
+  // Add any pending outbound file descriptors to the message
+  // See "man cmsg" really
+  msg.msg_control = msgbuf;
+  msg.msg_controllen = sizeof msgbuf;
+  cmsg = CMSG_FIRSTHDR(&msg);
+  cmsg->cmsg_level = SOL_SOCKET;
+  cmsg->cmsg_type = SCM_RIGHTS;
+  cmsg->cmsg_len = CMSG_LEN(sizeof send_fd);
+  memcpy(CMSG_DATA(cmsg), &send_fd, sizeof send_fd);
+
+  // We only write our msg_control during the first write
+  int ret_len = len;
+  while (len > 0) {
+    struct iovec iv;
+    memset(&iv, 0, sizeof(iv));
+
+    iv.iov_base = buffer;
+    iv.iov_len = len;
+
+    msg.msg_iov = &iv;
+    msg.msg_iovlen = 1;
+
+    ssize_t ret;
+    OSI_NO_INTR(ret = sendmsg(sock_fd, &msg, MSG_NOSIGNAL));
+    if (ret < 0) {
+      BTIF_TRACE_ERROR("fd:%d, send_fd:%d, sendmsg ret:%d, errno:%d, %s",
+                       sock_fd, send_fd, (int)ret, errno, strerror(errno));
+      ret_len = -1;
+      break;
+    }
+
+    buffer += ret;
+    len -= ret;
+
+    // Wipes out any msg_control too
+    memset(&msg, 0, sizeof(msg));
+  }
+  BTIF_TRACE_DEBUG("close fd:%d after sent", send_fd);
+  // TODO: This seems wrong - if the FD is not opened in JAVA before this is
+  // called
+  //       we get a "socket closed" exception in java, when reading from the
+  //       socket...
+  close(send_fd);
+  return ret_len;
+}
+
+static const char* hex_table = "0123456789abcdef";
+static inline void byte2hex(const char* data, char** str) {
+  **str = hex_table[(*data >> 4) & 0xf];
+  ++*str;
+  **str = hex_table[*data & 0xf];
+  ++*str;
+}
+static inline void byte2char(const char* data, char** str) {
+  **str = *data < ' ' ? '.' : *data > '~' ? '.' : *data;
+  ++(*str);
+}
+static inline void word2hex(const char* data, char** hex) {
+  byte2hex(&data[1], hex);
+  byte2hex(&data[0], hex);
+}
+void dump_bin(const char* title, const char* data, int size) {
+  char line_buff[256];
+  char* line;
+  int i, j, addr;
+  const int width = 16;
+  LOG_DEBUG(LOG_TAG, "%s, size:%d, dump started {", title, size);
+  if (size <= 0) return;
+  // write offset
+  line = line_buff;
+  *line++ = ' ';
+  *line++ = ' ';
+  *line++ = ' ';
+  *line++ = ' ';
+  *line++ = ' ';
+  *line++ = ' ';
+  for (j = 0; j < width; j++) {
+    byte2hex((const char*)&j, &line);
+    *line++ = ' ';
+  }
+  *line = 0;
+  LOG_DEBUG(LOG_TAG, "%s", line_buff);
+
+  for (i = 0; i < size / width; i++) {
+    line = line_buff;
+    // write address:
+    addr = i * width;
+    word2hex((const char*)&addr, &line);
+    *line++ = ':';
+    *line++ = ' ';
+    // write hex of data
+    for (j = 0; j < width; j++) {
+      byte2hex(&data[j], &line);
+      *line++ = ' ';
+    }
+    // write char of data
+    for (j = 0; j < width; j++) byte2char(data++, &line);
+    // wirte the end of line
+    *line = 0;
+    // output the line
+    LOG_DEBUG(LOG_TAG, "%s", line_buff);
+  }
+  // last line of left over if any
+  int leftover = size % width;
+  if (leftover > 0) {
+    line = line_buff;
+    // write address:
+    addr = i * width;
+    word2hex((const char*)&addr, &line);
+    *line++ = ':';
+    *line++ = ' ';
+    // write hex of data
+    for (j = 0; j < leftover; j++) {
+      byte2hex(&data[j], &line);
+      *line++ = ' ';
+    }
+    // write hex padding
+    for (; j < width; j++) {
+      *line++ = ' ';
+      *line++ = ' ';
+      *line++ = ' ';
+    }
+    // write char of data
+    for (j = 0; j < leftover; j++) byte2char(data++, &line);
+    // write the end of line
+    *line = 0;
+    // output the line
+    LOG_DEBUG(LOG_TAG, "%s", line_buff);
+  }
+  LOG_DEBUG(LOG_TAG, "%s, size:%d, dump ended }", title, size);
+}
diff --git a/bt/btif/src/btif_storage.cc b/bt/btif/src/btif_storage.cc
new file mode 100644
index 0000000..6aee1e4
--- /dev/null
+++ b/bt/btif/src/btif_storage.cc
@@ -0,0 +1,1375 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ *  Filename:      btif_storage.c
+ *
+ *  Description:   Stores the local BT adapter and remote device properties in
+ *                 NVRAM storage, typically as xml file in the
+ *                 mobile's filesystem
+ *
+ *
+ */
+
+#define LOG_TAG "bt_btif_storage"
+
+#include "btif_storage.h"
+
+#include <alloca.h>
+#include <assert.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "bt_common.h"
+#include "bta_hh_api.h"
+#include "btcore/include/bdaddr.h"
+#include "btif_api.h"
+#include "btif_config.h"
+#include "btif_hh.h"
+#include "btif_util.h"
+#include "osi/include/allocator.h"
+#include "osi/include/compat.h"
+#include "osi/include/config.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+/************************************************************************************
+ *  Constants & Macros
+ ***********************************************************************************/
+
+// TODO(armansito): Find a better way than using a hardcoded path.
+#define BTIF_STORAGE_PATH_BLUEDROID "/data/misc/bluedroid"
+
+//#define BTIF_STORAGE_PATH_ADAPTER_INFO "adapter_info"
+//#define BTIF_STORAGE_PATH_REMOTE_DEVICES "remote_devices"
+#define BTIF_STORAGE_PATH_REMOTE_DEVTIME "Timestamp"
+#define BTIF_STORAGE_PATH_REMOTE_DEVCLASS "DevClass"
+#define BTIF_STORAGE_PATH_REMOTE_DEVTYPE "DevType"
+#define BTIF_STORAGE_PATH_REMOTE_NAME "Name"
+#define BTIF_STORAGE_PATH_REMOTE_VER_MFCT "Manufacturer"
+#define BTIF_STORAGE_PATH_REMOTE_VER_VER "LmpVer"
+#define BTIF_STORAGE_PATH_REMOTE_VER_SUBVER "LmpSubVer"
+
+//#define BTIF_STORAGE_PATH_REMOTE_LINKKEYS "remote_linkkeys"
+#define BTIF_STORAGE_PATH_REMOTE_ALIASE "Aliase"
+#define BTIF_STORAGE_PATH_REMOTE_SERVICE "Service"
+#define BTIF_STORAGE_PATH_REMOTE_HIDINFO "HidInfo"
+#define BTIF_STORAGE_KEY_ADAPTER_NAME "Name"
+#define BTIF_STORAGE_KEY_ADAPTER_SCANMODE "ScanMode"
+#define BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT "DiscoveryTimeout"
+
+/* This is a local property to add a device found */
+#define BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP 0xFF
+
+#define BTIF_STORAGE_GET_ADAPTER_PROP(t, v, l, p) \
+  do {                                            \
+    (p).type = (t);                               \
+    (p).val = (v);                                \
+    (p).len = (l);                                \
+    btif_storage_get_adapter_property(&(p));      \
+  } while (0)
+
+#define BTIF_STORAGE_GET_REMOTE_PROP(b, t, v, l, p)     \
+  do {                                                  \
+    (p).type = (t);                                     \
+    (p).val = (v);                                      \
+    (p).len = (l);                                      \
+    btif_storage_get_remote_device_property((b), &(p)); \
+  } while (0)
+
+#define STORAGE_BDADDR_STRING_SZ (18) /* 00:11:22:33:44:55 */
+#define STORAGE_UUID_STRING_SIZE \
+  (36 + 1) /* 00001200-0000-1000-8000-00805f9b34fb; */
+#define STORAGE_PINLEN_STRING_MAX_SIZE (2)  /* ascii pinlen max chars */
+#define STORAGE_KEYTYPE_STRING_MAX_SIZE (1) /* ascii keytype max chars */
+
+#define STORAGE_KEY_TYPE_MAX (10)
+
+#define STORAGE_HID_ATRR_MASK_SIZE (4)
+#define STORAGE_HID_SUB_CLASS_SIZE (2)
+#define STORAGE_HID_APP_ID_SIZE (2)
+#define STORAGE_HID_VENDOR_ID_SIZE (4)
+#define STORAGE_HID_PRODUCT_ID_SIZE (4)
+#define STORAGE_HID_VERSION_SIZE (4)
+#define STORAGE_HID_CTRY_CODE_SIZE (2)
+#define STORAGE_HID_DESC_LEN_SIZE (4)
+#define STORAGE_HID_DESC_MAX_SIZE (2 * 512)
+
+/* <18 char bd addr> <space> LIST< <36 char uuid> <;> > <keytype (dec)> <pinlen>
+ */
+#define BTIF_REMOTE_SERVICES_ENTRY_SIZE_MAX      \
+  (STORAGE_BDADDR_STRING_SZ + 1 +                \
+   STORAGE_UUID_STRING_SIZE * BT_MAX_NUM_UUIDS + \
+   STORAGE_PINLEN_STRING_MAX_SIZE + STORAGE_KEYTYPE_STRING_MAX_SIZE)
+
+#define STORAGE_REMOTE_LINKKEYS_ENTRY_SIZE (LINK_KEY_LEN * 2 + 1 + 2 + 1 + 2)
+
+/* <18 char bd addr> <space>LIST <attr_mask> <space> > <sub_class> <space>
+   <app_id> <space>
+                                <vendor_id> <space> > <product_id> <space>
+   <version> <space>
+                                <ctry_code> <space> > <desc_len> <space>
+   <desc_list> <space> */
+#define BTIF_HID_INFO_ENTRY_SIZE_MAX                                  \
+  (STORAGE_BDADDR_STRING_SZ + 1 + STORAGE_HID_ATRR_MASK_SIZE + 1 +    \
+   STORAGE_HID_SUB_CLASS_SIZE + 1 + STORAGE_HID_APP_ID_SIZE + 1 +     \
+   STORAGE_HID_VENDOR_ID_SIZE + 1 + STORAGE_HID_PRODUCT_ID_SIZE + 1 + \
+   STORAGE_HID_VERSION_SIZE + 1 + STORAGE_HID_CTRY_CODE_SIZE + 1 +    \
+   STORAGE_HID_DESC_LEN_SIZE + 1 + STORAGE_HID_DESC_MAX_SIZE + 1)
+
+/* currently remote services is the potentially largest entry */
+#define BTIF_STORAGE_MAX_LINE_SZ BTIF_REMOTE_SERVICES_ENTRY_SIZE_MAX
+
+/* check against unv max entry size at compile time */
+#if (BTIF_STORAGE_ENTRY_MAX_SIZE > UNV_MAXLINE_LENGTH)
+#error "btif storage entry size exceeds unv max line size"
+#endif
+
+/************************************************************************************
+ *  Local type definitions
+ ***********************************************************************************/
+typedef struct {
+  uint32_t num_devices;
+  bt_bdaddr_t devices[BTM_SEC_MAX_DEVICE_RECORDS];
+} btif_bonded_devices_t;
+
+/************************************************************************************
+ *  External variables
+ ***********************************************************************************/
+extern bt_bdaddr_t btif_local_bd_addr;
+
+/************************************************************************************
+ *  External functions
+ ***********************************************************************************/
+
+extern void btif_gatts_add_bonded_dev_from_nv(BD_ADDR bda);
+
+/************************************************************************************
+ *  Internal Functions
+ ***********************************************************************************/
+
+static bt_status_t btif_in_fetch_bonded_ble_device(
+    const char* remote_bd_addr, int add,
+    btif_bonded_devices_t* p_bonded_devices);
+static bt_status_t btif_in_fetch_bonded_device(const char* bdstr);
+
+static bool btif_has_ble_keys(const char* bdstr);
+
+/************************************************************************************
+ *  Static functions
+ ***********************************************************************************/
+
+static int prop2cfg(bt_bdaddr_t* remote_bd_addr, bt_property_t* prop) {
+  bdstr_t bdstr = {0};
+  if (remote_bd_addr) bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+  BTIF_TRACE_DEBUG("in, bd addr:%s, prop type:%d, len:%d", bdstr, prop->type,
+                   prop->len);
+  char value[1024];
+  if (prop->len <= 0 || prop->len > (int)sizeof(value) - 1) {
+    BTIF_TRACE_ERROR("property type:%d, len:%d is invalid", prop->type,
+                     prop->len);
+    return false;
+  }
+  switch (prop->type) {
+    case BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP:
+      btif_config_set_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVTIME,
+                          (int)time(NULL));
+      break;
+    case BT_PROPERTY_BDNAME:
+      strncpy(value, (char*)prop->val, prop->len);
+      value[prop->len] = '\0';
+      if (remote_bd_addr)
+        btif_config_set_str(bdstr, BTIF_STORAGE_PATH_REMOTE_NAME, value);
+      else
+        btif_config_set_str("Adapter", BTIF_STORAGE_KEY_ADAPTER_NAME, value);
+      break;
+    case BT_PROPERTY_REMOTE_FRIENDLY_NAME:
+      strncpy(value, (char*)prop->val, prop->len);
+      value[prop->len] = '\0';
+      btif_config_set_str(bdstr, BTIF_STORAGE_PATH_REMOTE_ALIASE, value);
+      break;
+    case BT_PROPERTY_ADAPTER_SCAN_MODE:
+      btif_config_set_int("Adapter", BTIF_STORAGE_KEY_ADAPTER_SCANMODE,
+                          *(int*)prop->val);
+      break;
+    case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+      btif_config_set_int("Adapter", BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT,
+                          *(int*)prop->val);
+      break;
+    case BT_PROPERTY_CLASS_OF_DEVICE:
+      btif_config_set_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVCLASS,
+                          *(int*)prop->val);
+      break;
+    case BT_PROPERTY_TYPE_OF_DEVICE:
+      btif_config_set_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVTYPE,
+                          *(int*)prop->val);
+      break;
+    case BT_PROPERTY_UUIDS: {
+      uint32_t i;
+      char buf[64];
+      value[0] = 0;
+      for (i = 0; i < (prop->len) / sizeof(bt_uuid_t); i++) {
+        bt_uuid_t* p_uuid = (bt_uuid_t*)prop->val + i;
+        memset(buf, 0, sizeof(buf));
+        uuid_to_string_legacy(p_uuid, buf, sizeof(buf));
+        strcat(value, buf);
+        // strcat(value, ";");
+        strcat(value, " ");
+      }
+      btif_config_set_str(bdstr, BTIF_STORAGE_PATH_REMOTE_SERVICE, value);
+      break;
+    }
+    case BT_PROPERTY_REMOTE_VERSION_INFO: {
+      bt_remote_version_t* info = (bt_remote_version_t*)prop->val;
+
+      if (!info) return false;
+
+      btif_config_set_int(bdstr, BTIF_STORAGE_PATH_REMOTE_VER_MFCT,
+                          info->manufacturer);
+      btif_config_set_int(bdstr, BTIF_STORAGE_PATH_REMOTE_VER_VER,
+                          info->version);
+      btif_config_set_int(bdstr, BTIF_STORAGE_PATH_REMOTE_VER_SUBVER,
+                          info->sub_ver);
+    } break;
+
+    default:
+      BTIF_TRACE_ERROR("Unknown prop type:%d", prop->type);
+      return false;
+  }
+
+  /* save changes if the device was bonded */
+  if (btif_in_fetch_bonded_device(bdstr) == BT_STATUS_SUCCESS) {
+    btif_config_save();
+  }
+
+  return true;
+}
+
+static int cfg2prop(bt_bdaddr_t* remote_bd_addr, bt_property_t* prop) {
+  bdstr_t bdstr = {0};
+  if (remote_bd_addr) bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+  BTIF_TRACE_DEBUG("in, bd addr:%s, prop type:%d, len:%d", bdstr, prop->type,
+                   prop->len);
+  if (prop->len <= 0) {
+    BTIF_TRACE_ERROR("property type:%d, len:%d is invalid", prop->type,
+                     prop->len);
+    return false;
+  }
+  int ret = false;
+  switch (prop->type) {
+    case BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP:
+      if (prop->len >= (int)sizeof(int))
+        ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVTIME,
+                                  (int*)prop->val);
+      break;
+    case BT_PROPERTY_BDNAME: {
+      int len = prop->len;
+      if (remote_bd_addr)
+        ret = btif_config_get_str(bdstr, BTIF_STORAGE_PATH_REMOTE_NAME,
+                                  (char*)prop->val, &len);
+      else
+        ret = btif_config_get_str("Adapter", BTIF_STORAGE_KEY_ADAPTER_NAME,
+                                  (char*)prop->val, &len);
+      if (ret && len && len <= prop->len)
+        prop->len = len - 1;
+      else {
+        prop->len = 0;
+        ret = false;
+      }
+      break;
+    }
+    case BT_PROPERTY_REMOTE_FRIENDLY_NAME: {
+      int len = prop->len;
+      ret = btif_config_get_str(bdstr, BTIF_STORAGE_PATH_REMOTE_ALIASE,
+                                (char*)prop->val, &len);
+      if (ret && len && len <= prop->len)
+        prop->len = len - 1;
+      else {
+        prop->len = 0;
+        ret = false;
+      }
+      break;
+    }
+    case BT_PROPERTY_ADAPTER_SCAN_MODE:
+      if (prop->len >= (int)sizeof(int))
+        ret = btif_config_get_int("Adapter", BTIF_STORAGE_KEY_ADAPTER_SCANMODE,
+                                  (int*)prop->val);
+      break;
+    case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+      if (prop->len >= (int)sizeof(int))
+        ret = btif_config_get_int(
+            "Adapter", BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT, (int*)prop->val);
+      break;
+    case BT_PROPERTY_CLASS_OF_DEVICE:
+      if (prop->len >= (int)sizeof(int))
+        ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVCLASS,
+                                  (int*)prop->val);
+      break;
+    case BT_PROPERTY_TYPE_OF_DEVICE:
+      if (prop->len >= (int)sizeof(int))
+        ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVTYPE,
+                                  (int*)prop->val);
+      break;
+    case BT_PROPERTY_UUIDS: {
+      char value[1280];
+      int size = sizeof(value);
+      if (btif_config_get_str(bdstr, BTIF_STORAGE_PATH_REMOTE_SERVICE, value,
+                              &size)) {
+        bt_uuid_t* p_uuid = (bt_uuid_t*)prop->val;
+        size_t num_uuids =
+            btif_split_uuids_string(value, p_uuid, BT_MAX_NUM_UUIDS);
+        prop->len = num_uuids * sizeof(bt_uuid_t);
+        ret = true;
+      } else {
+        prop->val = NULL;
+        prop->len = 0;
+      }
+    } break;
+
+    case BT_PROPERTY_REMOTE_VERSION_INFO: {
+      bt_remote_version_t* info = (bt_remote_version_t*)prop->val;
+
+      if (prop->len >= (int)sizeof(bt_remote_version_t)) {
+        ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_VER_MFCT,
+                                  &info->manufacturer);
+
+        if (ret == true)
+          ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_VER_VER,
+                                    &info->version);
+
+        if (ret == true)
+          ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_VER_SUBVER,
+                                    &info->sub_ver);
+      }
+    } break;
+
+    default:
+      BTIF_TRACE_ERROR("Unknow prop type:%d", prop->type);
+      return false;
+  }
+  return ret;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_in_fetch_bonded_devices
+ *
+ * Description      Internal helper function to fetch the bonded devices
+ *                  from NVRAM
+ *
+ * Returns          BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+static bt_status_t btif_in_fetch_bonded_device(const char* bdstr) {
+  bool bt_linkkey_file_found = false;
+
+  LINK_KEY link_key;
+  size_t size = sizeof(link_key);
+  if (btif_config_get_bin(bdstr, "LinkKey", (uint8_t*)link_key, &size)) {
+    int linkkey_type;
+    if (btif_config_get_int(bdstr, "LinkKeyType", &linkkey_type)) {
+      bt_linkkey_file_found = true;
+    } else {
+      bt_linkkey_file_found = false;
+    }
+  }
+#if (BLE_INCLUDED == TRUE)
+  if ((btif_in_fetch_bonded_ble_device(bdstr, false, NULL) !=
+       BT_STATUS_SUCCESS) &&
+      (!bt_linkkey_file_found)) {
+    BTIF_TRACE_DEBUG("Remote device:%s, no link key or ble key found", bdstr);
+    return BT_STATUS_FAIL;
+  }
+#else
+  if ((!bt_linkkey_file_found)) {
+    BTIF_TRACE_DEBUG("Remote device:%s, no link key found", bdstr);
+    return BT_STATUS_FAIL;
+  }
+#endif
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_in_fetch_bonded_devices
+ *
+ * Description      Internal helper function to fetch the bonded devices
+ *                  from NVRAM
+ *
+ * Returns          BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+static bt_status_t btif_in_fetch_bonded_devices(
+    btif_bonded_devices_t* p_bonded_devices, int add) {
+  memset(p_bonded_devices, 0, sizeof(btif_bonded_devices_t));
+
+  bool bt_linkkey_file_found = false;
+  int device_type;
+
+  for (const btif_config_section_iter_t* iter = btif_config_section_begin();
+       iter != btif_config_section_end();
+       iter = btif_config_section_next(iter)) {
+    const char* name = btif_config_section_name(iter);
+    if (!string_is_bdaddr(name)) continue;
+
+    BTIF_TRACE_DEBUG("Remote device:%s", name);
+    LINK_KEY link_key;
+    size_t size = sizeof(link_key);
+    if (btif_config_get_bin(name, "LinkKey", link_key, &size)) {
+      int linkkey_type;
+      if (btif_config_get_int(name, "LinkKeyType", &linkkey_type)) {
+        bt_bdaddr_t bd_addr;
+        string_to_bdaddr(name, &bd_addr);
+        if (add) {
+          DEV_CLASS dev_class = {0, 0, 0};
+          int cod;
+          int pin_length = 0;
+          if (btif_config_get_int(name, "DevClass", &cod))
+            uint2devclass((uint32_t)cod, dev_class);
+          btif_config_get_int(name, "PinLength", &pin_length);
+          BTA_DmAddDevice(bd_addr.address, dev_class, link_key, 0, 0,
+                          (uint8_t)linkkey_type, 0, pin_length);
+
+#if (BLE_INCLUDED == TRUE)
+          if (btif_config_get_int(name, "DevType", &device_type) &&
+              (device_type == BT_DEVICE_TYPE_DUMO)) {
+            btif_gatts_add_bonded_dev_from_nv(bd_addr.address);
+          }
+#endif
+        }
+        bt_linkkey_file_found = true;
+        memcpy(&p_bonded_devices->devices[p_bonded_devices->num_devices++],
+               &bd_addr, sizeof(bt_bdaddr_t));
+      } else {
+#if (BLE_INCLUDED == TRUE)
+        bt_linkkey_file_found = false;
+#else
+        BTIF_TRACE_ERROR(
+            "bounded device:%s, LinkKeyType or PinLength is invalid", name);
+#endif
+      }
+    }
+#if (BLE_INCLUDED == TRUE)
+    if (!btif_in_fetch_bonded_ble_device(name, add, p_bonded_devices) &&
+        !bt_linkkey_file_found) {
+      BTIF_TRACE_DEBUG("Remote device:%s, no link key or ble key found", name);
+    }
+#else
+    if (!bt_linkkey_file_found)
+      BTIF_TRACE_DEBUG("Remote device:%s, no link key", name);
+#endif
+  }
+  return BT_STATUS_SUCCESS;
+}
+
+static void btif_read_le_key(const uint8_t key_type, const size_t key_len,
+                             bt_bdaddr_t bd_addr, const uint8_t addr_type,
+                             const bool add_key, bool* device_added,
+                             bool* key_found) {
+  assert(device_added);
+  assert(key_found);
+
+  char buffer[100];
+  memset(buffer, 0, sizeof(buffer));
+
+  if (btif_storage_get_ble_bonding_key(&bd_addr, key_type, buffer, key_len) ==
+      BT_STATUS_SUCCESS) {
+    if (add_key) {
+      BD_ADDR bta_bd_addr;
+      bdcpy(bta_bd_addr, bd_addr.address);
+
+      if (!*device_added) {
+        BTA_DmAddBleDevice(bta_bd_addr, addr_type, BT_DEVICE_TYPE_BLE);
+        *device_added = true;
+      }
+
+      char bd_str[20] = {0};
+      BTIF_TRACE_DEBUG("%s() Adding key type %d for %s", __func__, key_type,
+                       bdaddr_to_string(&bd_addr, bd_str, sizeof(bd_str)));
+      BTA_DmAddBleKey(bta_bd_addr, (tBTA_LE_KEY_VALUE*)buffer, key_type);
+    }
+
+    *key_found = true;
+  }
+}
+
+/*******************************************************************************
+ * Functions
+ *
+ * Functions are synchronous and can be called by both from internal modules
+ * such as BTIF_DM and by external entiries from HAL via BTIF_context_switch.
+ * For OUT parameters, the caller is expected to provide the memory.
+ * Caller is expected to provide a valid pointer to 'property->value' based on
+ * the property->type.
+ *******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         btif_split_uuids_string
+ *
+ * Description      Internal helper function to split the string of UUIDs
+ *                  read from the NVRAM to an array
+ *
+ * Returns          Number of UUIDs parsed from the supplied string
+ *
+ ******************************************************************************/
+size_t btif_split_uuids_string(const char* str, bt_uuid_t* p_uuid,
+                               size_t max_uuids) {
+  assert(str);
+  assert(p_uuid);
+
+  size_t num_uuids = 0;
+  while (str && num_uuids < max_uuids) {
+    bool rc = string_to_uuid(str, p_uuid++);
+    if (!rc) break;
+    num_uuids++;
+    str = strchr(str, ' ');
+    if (str) str++;
+  }
+
+  return num_uuids;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_get_adapter_property
+ *
+ * Description      BTIF storage API - Fetches the adapter property->type
+ *                  from NVRAM and fills property->val.
+ *                  Caller should provide memory for property->val and
+ *                  set the property->val
+ *
+ * Returns          BT_STATUS_SUCCESS if the fetch was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_get_adapter_property(bt_property_t* property) {
+  /* Special handling for adapter BD_ADDR and BONDED_DEVICES */
+  if (property->type == BT_PROPERTY_BDADDR) {
+    bt_bdaddr_t* bd_addr = (bt_bdaddr_t*)property->val;
+    /* This has been cached in btif. Just fetch it from there */
+    memcpy(bd_addr, &btif_local_bd_addr, sizeof(bt_bdaddr_t));
+    property->len = sizeof(bt_bdaddr_t);
+    return BT_STATUS_SUCCESS;
+  } else if (property->type == BT_PROPERTY_ADAPTER_BONDED_DEVICES) {
+    btif_bonded_devices_t bonded_devices;
+
+    btif_in_fetch_bonded_devices(&bonded_devices, 0);
+
+    BTIF_TRACE_DEBUG(
+        "%s: Number of bonded devices: %d "
+        "Property:BT_PROPERTY_ADAPTER_BONDED_DEVICES",
+        __func__, bonded_devices.num_devices);
+
+    if (bonded_devices.num_devices > 0) {
+      property->len = bonded_devices.num_devices * sizeof(bt_bdaddr_t);
+      memcpy(property->val, bonded_devices.devices, property->len);
+    }
+
+    /* if there are no bonded_devices, then length shall be 0 */
+    return BT_STATUS_SUCCESS;
+  } else if (property->type == BT_PROPERTY_UUIDS) {
+    /* publish list of local supported services */
+    bt_uuid_t* p_uuid = (bt_uuid_t*)property->val;
+    uint32_t num_uuids = 0;
+    uint32_t i;
+
+    tBTA_SERVICE_MASK service_mask = btif_get_enabled_services_mask();
+    LOG_INFO(LOG_TAG, "%s service_mask:0x%x", __func__, service_mask);
+    for (i = 0; i < BTA_MAX_SERVICE_ID; i++) {
+      /* This should eventually become a function when more services are enabled
+       */
+      if (service_mask & (tBTA_SERVICE_MASK)(1 << i)) {
+        switch (i) {
+          case BTA_HFP_SERVICE_ID: {
+            uuid16_to_uuid128(UUID_SERVCLASS_AG_HANDSFREE, p_uuid + num_uuids);
+            num_uuids++;
+          }
+          /* intentional fall through: Send both BFP & HSP UUIDs if HFP is
+           * enabled */
+          case BTA_HSP_SERVICE_ID: {
+            uuid16_to_uuid128(UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY,
+                              p_uuid + num_uuids);
+            num_uuids++;
+          } break;
+          case BTA_A2DP_SOURCE_SERVICE_ID: {
+            uuid16_to_uuid128(UUID_SERVCLASS_AUDIO_SOURCE, p_uuid + num_uuids);
+            num_uuids++;
+          } break;
+          case BTA_A2DP_SINK_SERVICE_ID: {
+            uuid16_to_uuid128(UUID_SERVCLASS_AUDIO_SINK, p_uuid + num_uuids);
+            num_uuids++;
+          } break;
+          case BTA_HFP_HS_SERVICE_ID: {
+            uuid16_to_uuid128(UUID_SERVCLASS_HF_HANDSFREE, p_uuid + num_uuids);
+            num_uuids++;
+          } break;
+        }
+      }
+    }
+    property->len = (num_uuids) * sizeof(bt_uuid_t);
+    return BT_STATUS_SUCCESS;
+  }
+
+  /* fall through for other properties */
+  if (!cfg2prop(NULL, property)) {
+    return btif_dm_get_adapter_property(property);
+  }
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_set_adapter_property
+ *
+ * Description      BTIF storage API - Stores the adapter property
+ *                  to NVRAM
+ *
+ * Returns          BT_STATUS_SUCCESS if the store was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_set_adapter_property(bt_property_t* property) {
+  return prop2cfg(NULL, property) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_get_remote_device_property
+ *
+ * Description      BTIF storage API - Fetches the remote device property->type
+ *                  from NVRAM and fills property->val.
+ *                  Caller should provide memory for property->val and
+ *                  set the property->val
+ *
+ * Returns          BT_STATUS_SUCCESS if the fetch was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_get_remote_device_property(bt_bdaddr_t* remote_bd_addr,
+                                                    bt_property_t* property) {
+  return cfg2prop(remote_bd_addr, property) ? BT_STATUS_SUCCESS
+                                            : BT_STATUS_FAIL;
+}
+/*******************************************************************************
+ *
+ * Function         btif_storage_set_remote_device_property
+ *
+ * Description      BTIF storage API - Stores the remote device property
+ *                  to NVRAM
+ *
+ * Returns          BT_STATUS_SUCCESS if the store was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_set_remote_device_property(bt_bdaddr_t* remote_bd_addr,
+                                                    bt_property_t* property) {
+  return prop2cfg(remote_bd_addr, property) ? BT_STATUS_SUCCESS
+                                            : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_add_remote_device
+ *
+ * Description      BTIF storage API - Adds a newly discovered device to NVRAM
+ *                  along with the timestamp. Also, stores the various
+ *                  properties - RSSI, BDADDR, NAME (if found in EIR)
+ *
+ * Returns          BT_STATUS_SUCCESS if the store was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_add_remote_device(bt_bdaddr_t* remote_bd_addr,
+                                           uint32_t num_properties,
+                                           bt_property_t* properties) {
+  uint32_t i = 0;
+  /* TODO: If writing a property, fails do we go back undo the earlier
+   * written properties? */
+  for (i = 0; i < num_properties; i++) {
+    /* Ignore the RSSI as this is not stored in DB */
+    if (properties[i].type == BT_PROPERTY_REMOTE_RSSI) continue;
+
+    /* BD_ADDR for remote device needs special handling as we also store
+     * timestamp */
+    if (properties[i].type == BT_PROPERTY_BDADDR) {
+      bt_property_t addr_prop;
+      memcpy(&addr_prop, &properties[i], sizeof(bt_property_t));
+      addr_prop.type = (bt_property_type_t)BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP;
+      btif_storage_set_remote_device_property(remote_bd_addr, &addr_prop);
+    } else {
+      btif_storage_set_remote_device_property(remote_bd_addr, &properties[i]);
+    }
+  }
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_add_bonded_device
+ *
+ * Description      BTIF storage API - Adds the newly bonded device to NVRAM
+ *                  along with the link-key, Key type and Pin key length
+ *
+ * Returns          BT_STATUS_SUCCESS if the store was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+
+bt_status_t btif_storage_add_bonded_device(bt_bdaddr_t* remote_bd_addr,
+                                           LINK_KEY link_key, uint8_t key_type,
+                                           uint8_t pin_length) {
+  bdstr_t bdstr;
+  bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+  int ret = btif_config_set_int(bdstr, "LinkKeyType", (int)key_type);
+  ret &= btif_config_set_int(bdstr, "PinLength", (int)pin_length);
+  ret &= btif_config_set_bin(bdstr, "LinkKey", link_key, sizeof(LINK_KEY));
+
+  if (is_restricted_mode()) {
+    BTIF_TRACE_WARNING("%s: '%s' pairing will be removed if unrestricted",
+                       __func__, bdstr);
+    btif_config_set_int(bdstr, "Restricted", 1);
+  }
+
+  /* write bonded info immediately */
+  btif_config_flush();
+  return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_remove_bonded_device
+ *
+ * Description      BTIF storage API - Deletes the bonded device from NVRAM
+ *
+ * Returns          BT_STATUS_SUCCESS if the deletion was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_remove_bonded_device(bt_bdaddr_t* remote_bd_addr) {
+  bdstr_t bdstr;
+  bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+  BTIF_TRACE_DEBUG("in bd addr:%s", bdstr);
+
+#if (BLE_INCLUDED == TRUE)
+  btif_storage_remove_ble_bonding_keys(remote_bd_addr);
+#endif
+
+  int ret = 1;
+  if (btif_config_exist(bdstr, "LinkKeyType"))
+    ret &= btif_config_remove(bdstr, "LinkKeyType");
+  if (btif_config_exist(bdstr, "PinLength"))
+    ret &= btif_config_remove(bdstr, "PinLength");
+  if (btif_config_exist(bdstr, "LinkKey"))
+    ret &= btif_config_remove(bdstr, "LinkKey");
+  /* write bonded info immediately */
+  btif_config_flush();
+  return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_load_bonded_devices
+ *
+ * Description      BTIF storage API - Loads all the bonded devices from NVRAM
+ *                  and adds to the BTA.
+ *                  Additionally, this API also invokes the adaper_properties_cb
+ *                  and remote_device_properties_cb for each of the bonded
+ *                  devices.
+ *
+ * Returns          BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_load_bonded_devices(void) {
+  btif_bonded_devices_t bonded_devices;
+  uint32_t i = 0;
+  bt_property_t adapter_props[6];
+  uint32_t num_props = 0;
+  bt_property_t remote_properties[8];
+  bt_bdaddr_t addr;
+  bt_bdname_t name, alias;
+  bt_scan_mode_t mode;
+  uint32_t disc_timeout;
+  bt_uuid_t local_uuids[BT_MAX_NUM_UUIDS];
+  bt_uuid_t remote_uuids[BT_MAX_NUM_UUIDS];
+
+  btif_in_fetch_bonded_devices(&bonded_devices, 1);
+
+  /* Now send the adapter_properties_cb with all adapter_properties */
+  {
+    memset(adapter_props, 0, sizeof(adapter_props));
+
+    /* BD_ADDR */
+    BTIF_STORAGE_GET_ADAPTER_PROP(BT_PROPERTY_BDADDR, &addr, sizeof(addr),
+                                  adapter_props[num_props]);
+    num_props++;
+
+    /* BD_NAME */
+    BTIF_STORAGE_GET_ADAPTER_PROP(BT_PROPERTY_BDNAME, &name, sizeof(name),
+                                  adapter_props[num_props]);
+    num_props++;
+
+    /* SCAN_MODE */
+    /* TODO: At the time of BT on, always report the scan mode as 0 irrespective
+     of the scan_mode during the previous enable cycle.
+     This needs to be re-visited as part of the app/stack enable sequence
+     synchronization */
+    mode = BT_SCAN_MODE_NONE;
+    adapter_props[num_props].type = BT_PROPERTY_ADAPTER_SCAN_MODE;
+    adapter_props[num_props].len = sizeof(mode);
+    adapter_props[num_props].val = &mode;
+    num_props++;
+
+    /* DISC_TIMEOUT */
+    BTIF_STORAGE_GET_ADAPTER_PROP(BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT,
+                                  &disc_timeout, sizeof(disc_timeout),
+                                  adapter_props[num_props]);
+    num_props++;
+
+    /* BONDED_DEVICES */
+    bt_bdaddr_t* devices_list = (bt_bdaddr_t*)osi_malloc(
+        sizeof(bt_bdaddr_t) * bonded_devices.num_devices);
+    adapter_props[num_props].type = BT_PROPERTY_ADAPTER_BONDED_DEVICES;
+    adapter_props[num_props].len =
+        bonded_devices.num_devices * sizeof(bt_bdaddr_t);
+    adapter_props[num_props].val = devices_list;
+    for (i = 0; i < bonded_devices.num_devices; i++) {
+      memcpy(devices_list + i, &bonded_devices.devices[i], sizeof(bt_bdaddr_t));
+    }
+    num_props++;
+
+    /* LOCAL UUIDs */
+    BTIF_STORAGE_GET_ADAPTER_PROP(BT_PROPERTY_UUIDS, local_uuids,
+                                  sizeof(local_uuids),
+                                  adapter_props[num_props]);
+    num_props++;
+
+    btif_adapter_properties_evt(BT_STATUS_SUCCESS, num_props, adapter_props);
+
+    osi_free(devices_list);
+  }
+
+  BTIF_TRACE_EVENT("%s: %d bonded devices found", __func__,
+                   bonded_devices.num_devices);
+
+  {
+    for (i = 0; i < bonded_devices.num_devices; i++) {
+      bt_bdaddr_t* p_remote_addr;
+
+      /*
+       * TODO: improve handling of missing fields in NVRAM.
+       */
+      uint32_t cod = 0;
+      uint32_t devtype = 0;
+
+      num_props = 0;
+      p_remote_addr = &bonded_devices.devices[i];
+      memset(remote_properties, 0, sizeof(remote_properties));
+      BTIF_STORAGE_GET_REMOTE_PROP(p_remote_addr, BT_PROPERTY_BDNAME, &name,
+                                   sizeof(name), remote_properties[num_props]);
+      num_props++;
+
+      BTIF_STORAGE_GET_REMOTE_PROP(p_remote_addr,
+                                   BT_PROPERTY_REMOTE_FRIENDLY_NAME, &alias,
+                                   sizeof(alias), remote_properties[num_props]);
+      num_props++;
+
+      BTIF_STORAGE_GET_REMOTE_PROP(p_remote_addr, BT_PROPERTY_CLASS_OF_DEVICE,
+                                   &cod, sizeof(cod),
+                                   remote_properties[num_props]);
+      num_props++;
+
+      BTIF_STORAGE_GET_REMOTE_PROP(p_remote_addr, BT_PROPERTY_TYPE_OF_DEVICE,
+                                   &devtype, sizeof(devtype),
+                                   remote_properties[num_props]);
+      num_props++;
+
+      BTIF_STORAGE_GET_REMOTE_PROP(p_remote_addr, BT_PROPERTY_UUIDS,
+                                   remote_uuids, sizeof(remote_uuids),
+                                   remote_properties[num_props]);
+      num_props++;
+
+      btif_remote_properties_evt(BT_STATUS_SUCCESS, p_remote_addr, num_props,
+                                 remote_properties);
+    }
+  }
+  return BT_STATUS_SUCCESS;
+}
+
+#if (BLE_INCLUDED == TRUE)
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_add_ble_bonding_key
+ *
+ * Description      BTIF storage API - Adds the newly bonded device to NVRAM
+ *                  along with the ble-key, Key type and Pin key length
+ *
+ * Returns          BT_STATUS_SUCCESS if the store was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+
+bt_status_t btif_storage_add_ble_bonding_key(bt_bdaddr_t* remote_bd_addr,
+                                             char* key, uint8_t key_type,
+                                             uint8_t key_length) {
+  bdstr_t bdstr;
+  bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+  const char* name;
+  switch (key_type) {
+    case BTIF_DM_LE_KEY_PENC:
+      name = "LE_KEY_PENC";
+      break;
+    case BTIF_DM_LE_KEY_PID:
+      name = "LE_KEY_PID";
+      break;
+    case BTIF_DM_LE_KEY_PCSRK:
+      name = "LE_KEY_PCSRK";
+      break;
+    case BTIF_DM_LE_KEY_LENC:
+      name = "LE_KEY_LENC";
+      break;
+    case BTIF_DM_LE_KEY_LCSRK:
+      name = "LE_KEY_LCSRK";
+      break;
+    case BTIF_DM_LE_KEY_LID:
+      name = "LE_KEY_LID";
+      break;
+    default:
+      return BT_STATUS_FAIL;
+  }
+  int ret = btif_config_set_bin(bdstr, name, (const uint8_t*)key, key_length);
+  btif_config_save();
+  return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_get_ble_bonding_key
+ *
+ * Description
+ *
+ * Returns          BT_STATUS_SUCCESS if the fetch was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_get_ble_bonding_key(bt_bdaddr_t* remote_bd_addr,
+                                             uint8_t key_type, char* key_value,
+                                             int key_length) {
+  bdstr_t bdstr;
+  bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+  const char* name;
+  switch (key_type) {
+    case BTIF_DM_LE_KEY_PENC:
+      name = "LE_KEY_PENC";
+      break;
+    case BTIF_DM_LE_KEY_PID:
+      name = "LE_KEY_PID";
+      break;
+    case BTIF_DM_LE_KEY_PCSRK:
+      name = "LE_KEY_PCSRK";
+      break;
+    case BTIF_DM_LE_KEY_LENC:
+      name = "LE_KEY_LENC";
+      break;
+    case BTIF_DM_LE_KEY_LCSRK:
+      name = "LE_KEY_LCSRK";
+      break;
+    case BTIF_DM_LE_KEY_LID:
+      name = "LE_KEY_LID";
+    default:
+      return BT_STATUS_FAIL;
+  }
+  size_t length = key_length;
+  int ret = btif_config_get_bin(bdstr, name, (uint8_t*)key_value, &length);
+  return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_remove_ble_keys
+ *
+ * Description      BTIF storage API - Deletes the bonded device from NVRAM
+ *
+ * Returns          BT_STATUS_SUCCESS if the deletion was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_remove_ble_bonding_keys(bt_bdaddr_t* remote_bd_addr) {
+  bdstr_t bdstr;
+  bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+  BTIF_TRACE_DEBUG(" %s in bd addr:%s", __func__, bdstr);
+  int ret = 1;
+  if (btif_config_exist(bdstr, "LE_KEY_PENC"))
+    ret &= btif_config_remove(bdstr, "LE_KEY_PENC");
+  if (btif_config_exist(bdstr, "LE_KEY_PID"))
+    ret &= btif_config_remove(bdstr, "LE_KEY_PID");
+  if (btif_config_exist(bdstr, "LE_KEY_PCSRK"))
+    ret &= btif_config_remove(bdstr, "LE_KEY_PCSRK");
+  if (btif_config_exist(bdstr, "LE_KEY_LENC"))
+    ret &= btif_config_remove(bdstr, "LE_KEY_LENC");
+  if (btif_config_exist(bdstr, "LE_KEY_LCSRK"))
+    ret &= btif_config_remove(bdstr, "LE_KEY_LCSRK");
+  btif_config_save();
+  return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_add_ble_local_key
+ *
+ * Description      BTIF storage API - Adds the ble key to NVRAM
+ *
+ * Returns          BT_STATUS_SUCCESS if the store was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_add_ble_local_key(char* key, uint8_t key_type,
+                                           uint8_t key_length) {
+  const char* name;
+  switch (key_type) {
+    case BTIF_DM_LE_LOCAL_KEY_IR:
+      name = "LE_LOCAL_KEY_IR";
+      break;
+    case BTIF_DM_LE_LOCAL_KEY_IRK:
+      name = "LE_LOCAL_KEY_IRK";
+      break;
+    case BTIF_DM_LE_LOCAL_KEY_DHK:
+      name = "LE_LOCAL_KEY_DHK";
+      break;
+    case BTIF_DM_LE_LOCAL_KEY_ER:
+      name = "LE_LOCAL_KEY_ER";
+      break;
+    default:
+      return BT_STATUS_FAIL;
+  }
+  int ret =
+      btif_config_set_bin("Adapter", name, (const uint8_t*)key, key_length);
+  btif_config_save();
+  return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_get_ble_local_key
+ *
+ * Description
+ *
+ * Returns          BT_STATUS_SUCCESS if the fetch was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_get_ble_local_key(uint8_t key_type, char* key_value,
+                                           int key_length) {
+  const char* name;
+  switch (key_type) {
+    case BTIF_DM_LE_LOCAL_KEY_IR:
+      name = "LE_LOCAL_KEY_IR";
+      break;
+    case BTIF_DM_LE_LOCAL_KEY_IRK:
+      name = "LE_LOCAL_KEY_IRK";
+      break;
+    case BTIF_DM_LE_LOCAL_KEY_DHK:
+      name = "LE_LOCAL_KEY_DHK";
+      break;
+    case BTIF_DM_LE_LOCAL_KEY_ER:
+      name = "LE_LOCAL_KEY_ER";
+      break;
+    default:
+      return BT_STATUS_FAIL;
+  }
+  size_t length = key_length;
+  int ret = btif_config_get_bin("Adapter", name, (uint8_t*)key_value, &length);
+  return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_remove_ble_local_keys
+ *
+ * Description      BTIF storage API - Deletes the bonded device from NVRAM
+ *
+ * Returns          BT_STATUS_SUCCESS if the deletion was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_remove_ble_local_keys(void) {
+  int ret = 1;
+  if (btif_config_exist("Adapter", "LE_LOCAL_KEY_IR"))
+    ret &= btif_config_remove("Adapter", "LE_LOCAL_KEY_IR");
+  if (btif_config_exist("Adapter", "LE_LOCAL_KEY_IRK"))
+    ret &= btif_config_remove("Adapter", "LE_LOCAL_KEY_IRK");
+  if (btif_config_exist("Adapter", "LE_LOCAL_KEY_DHK"))
+    ret &= btif_config_remove("Adapter", "LE_LOCAL_KEY_DHK");
+  if (btif_config_exist("Adapter", "LE_LOCAL_KEY_ER"))
+    ret &= btif_config_remove("Adapter", "LE_LOCAL_KEY_ER");
+  btif_config_save();
+  return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+static bt_status_t btif_in_fetch_bonded_ble_device(
+    const char* remote_bd_addr, int add,
+    btif_bonded_devices_t* p_bonded_devices) {
+  int device_type;
+  int addr_type;
+  bt_bdaddr_t bd_addr;
+  BD_ADDR bta_bd_addr;
+  bool device_added = false;
+  bool key_found = false;
+
+  if (!btif_config_get_int(remote_bd_addr, "DevType", &device_type))
+    return BT_STATUS_FAIL;
+
+  if ((device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE ||
+      btif_has_ble_keys(remote_bd_addr)) {
+    BTIF_TRACE_DEBUG("%s Found a LE device: %s", __func__, remote_bd_addr);
+
+    string_to_bdaddr(remote_bd_addr, &bd_addr);
+    bdcpy(bta_bd_addr, bd_addr.address);
+
+    if (btif_storage_get_remote_addr_type(&bd_addr, &addr_type) !=
+        BT_STATUS_SUCCESS) {
+      addr_type = BLE_ADDR_PUBLIC;
+      btif_storage_set_remote_addr_type(&bd_addr, BLE_ADDR_PUBLIC);
+    }
+
+    btif_read_le_key(BTIF_DM_LE_KEY_PENC, sizeof(tBTM_LE_PENC_KEYS), bd_addr,
+                     addr_type, add, &device_added, &key_found);
+
+    btif_read_le_key(BTIF_DM_LE_KEY_PID, sizeof(tBTM_LE_PID_KEYS), bd_addr,
+                     addr_type, add, &device_added, &key_found);
+
+    btif_read_le_key(BTIF_DM_LE_KEY_LID, sizeof(tBTM_LE_PID_KEYS), bd_addr,
+                     addr_type, add, &device_added, &key_found);
+
+    btif_read_le_key(BTIF_DM_LE_KEY_PCSRK, sizeof(tBTM_LE_PCSRK_KEYS), bd_addr,
+                     addr_type, add, &device_added, &key_found);
+
+    btif_read_le_key(BTIF_DM_LE_KEY_LENC, sizeof(tBTM_LE_LENC_KEYS), bd_addr,
+                     addr_type, add, &device_added, &key_found);
+
+    btif_read_le_key(BTIF_DM_LE_KEY_LCSRK, sizeof(tBTM_LE_LCSRK_KEYS), bd_addr,
+                     addr_type, add, &device_added, &key_found);
+
+    // Fill in the bonded devices
+    if (device_added) {
+      memcpy(&p_bonded_devices->devices[p_bonded_devices->num_devices++],
+             &bd_addr, sizeof(bt_bdaddr_t));
+      btif_gatts_add_bonded_dev_from_nv(bta_bd_addr);
+    }
+
+    if (key_found) return BT_STATUS_SUCCESS;
+  }
+  return BT_STATUS_FAIL;
+}
+
+bt_status_t btif_storage_set_remote_addr_type(bt_bdaddr_t* remote_bd_addr,
+                                              uint8_t addr_type) {
+  bdstr_t bdstr;
+  bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+  int ret = btif_config_set_int(bdstr, "AddrType", (int)addr_type);
+  return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+bool btif_has_ble_keys(const char* bdstr) {
+  return btif_config_exist(bdstr, "LE_KEY_PENC");
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_get_remote_addr_type
+ *
+ * Description      BTIF storage API - Fetches the remote addr type
+ *
+ * Returns          BT_STATUS_SUCCESS if the fetch was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_get_remote_addr_type(bt_bdaddr_t* remote_bd_addr,
+                                              int* addr_type) {
+  bdstr_t bdstr;
+  bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+  int ret = btif_config_get_int(bdstr, "AddrType", addr_type);
+  return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+#endif
+/*******************************************************************************
+ *
+ * Function         btif_storage_add_hid_device_info
+ *
+ * Description      BTIF storage API - Adds the hid information of bonded hid
+ *                  devices-to NVRAM
+ *
+ * Returns          BT_STATUS_SUCCESS if the store was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+
+bt_status_t btif_storage_add_hid_device_info(
+    bt_bdaddr_t* remote_bd_addr, uint16_t attr_mask, uint8_t sub_class,
+    uint8_t app_id, uint16_t vendor_id, uint16_t product_id, uint16_t version,
+    uint8_t ctry_code, uint16_t ssr_max_latency, uint16_t ssr_min_tout,
+    uint16_t dl_len, uint8_t* dsc_list) {
+  bdstr_t bdstr;
+  BTIF_TRACE_DEBUG("btif_storage_add_hid_device_info:");
+  bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+  btif_config_set_int(bdstr, "HidAttrMask", attr_mask);
+  btif_config_set_int(bdstr, "HidSubClass", sub_class);
+  btif_config_set_int(bdstr, "HidAppId", app_id);
+  btif_config_set_int(bdstr, "HidVendorId", vendor_id);
+  btif_config_set_int(bdstr, "HidProductId", product_id);
+  btif_config_set_int(bdstr, "HidVersion", version);
+  btif_config_set_int(bdstr, "HidCountryCode", ctry_code);
+  btif_config_set_int(bdstr, "HidSSRMaxLatency", ssr_max_latency);
+  btif_config_set_int(bdstr, "HidSSRMinTimeout", ssr_min_tout);
+  if (dl_len > 0) btif_config_set_bin(bdstr, "HidDescriptor", dsc_list, dl_len);
+  btif_config_save();
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_load_bonded_hid_info
+ *
+ * Description      BTIF storage API - Loads hid info for all the bonded devices
+ *                  from NVRAM and adds those devices  to the BTA_HH.
+ *
+ * Returns          BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_load_bonded_hid_info(void) {
+  bt_bdaddr_t bd_addr;
+  tBTA_HH_DEV_DSCP_INFO dscp_info;
+  uint16_t attr_mask;
+  uint8_t sub_class;
+  uint8_t app_id;
+
+  memset(&dscp_info, 0, sizeof(dscp_info));
+  for (const btif_config_section_iter_t* iter = btif_config_section_begin();
+       iter != btif_config_section_end();
+       iter = btif_config_section_next(iter)) {
+    const char* name = btif_config_section_name(iter);
+    if (!string_is_bdaddr(name)) continue;
+
+    BTIF_TRACE_DEBUG("Remote device:%s", name);
+    int value;
+    if (btif_in_fetch_bonded_device(name) == BT_STATUS_SUCCESS) {
+      if (btif_config_get_int(name, "HidAttrMask", &value)) {
+        attr_mask = (uint16_t)value;
+
+        btif_config_get_int(name, "HidSubClass", &value);
+        sub_class = (uint8_t)value;
+
+        btif_config_get_int(name, "HidAppId", &value);
+        app_id = (uint8_t)value;
+
+        btif_config_get_int(name, "HidVendorId", &value);
+        dscp_info.vendor_id = (uint16_t)value;
+
+        btif_config_get_int(name, "HidProductId", &value);
+        dscp_info.product_id = (uint16_t)value;
+
+        btif_config_get_int(name, "HidVersion", &value);
+        dscp_info.version = (uint8_t)value;
+
+        btif_config_get_int(name, "HidCountryCode", &value);
+        dscp_info.ctry_code = (uint8_t)value;
+
+        value = 0;
+        btif_config_get_int(name, "HidSSRMaxLatency", &value);
+        dscp_info.ssr_max_latency = (uint16_t)value;
+
+        value = 0;
+        btif_config_get_int(name, "HidSSRMinTimeout", &value);
+        dscp_info.ssr_min_tout = (uint16_t)value;
+
+        size_t len = btif_config_get_bin_length(name, "HidDescriptor");
+        if (len > 0) {
+          dscp_info.descriptor.dl_len = (uint16_t)len;
+          dscp_info.descriptor.dsc_list = (uint8_t*)alloca(len);
+          btif_config_get_bin(name, "HidDescriptor",
+                              (uint8_t*)dscp_info.descriptor.dsc_list, &len);
+        }
+        string_to_bdaddr(name, &bd_addr);
+        // add extracted information to BTA HH
+        if (btif_hh_add_added_dev(bd_addr, attr_mask)) {
+          BTA_HhAddDev(bd_addr.address, attr_mask, sub_class, app_id,
+                       dscp_info);
+        }
+      }
+    } else {
+      if (btif_config_get_int(name, "HidAttrMask", &value)) {
+        btif_storage_remove_hid_info(&bd_addr);
+        string_to_bdaddr(name, &bd_addr);
+      }
+    }
+  }
+
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_remove_hid_info
+ *
+ * Description      BTIF storage API - Deletes the bonded hid device info from
+ *                  NVRAM
+ *
+ * Returns          BT_STATUS_SUCCESS if the deletion was successful,
+ *                  BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_remove_hid_info(bt_bdaddr_t* remote_bd_addr) {
+  bdstr_t bdstr;
+  bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+
+  btif_config_remove(bdstr, "HidAttrMask");
+  btif_config_remove(bdstr, "HidSubClass");
+  btif_config_remove(bdstr, "HidAppId");
+  btif_config_remove(bdstr, "HidVendorId");
+  btif_config_remove(bdstr, "HidProductId");
+  btif_config_remove(bdstr, "HidVersion");
+  btif_config_remove(bdstr, "HidCountryCode");
+  btif_config_remove(bdstr, "HidSSRMaxLatency");
+  btif_config_remove(bdstr, "HidSSRMinTimeout");
+  btif_config_remove(bdstr, "HidDescriptor");
+  btif_config_save();
+  return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         btif_storage_is_restricted_device
+ *
+ * Description      BTIF storage API - checks if this device is a restricted
+ *                  device
+ *
+ * Returns          true  if the device is labeled as restricted
+ *                  false otherwise
+ *
+ ******************************************************************************/
+bool btif_storage_is_restricted_device(const bt_bdaddr_t* remote_bd_addr) {
+  bdstr_t bdstr;
+  bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+
+  return btif_config_exist(bdstr, "Restricted");
+}
diff --git a/bt/btif/src/btif_uid.cc b/bt/btif/src/btif_uid.cc
new file mode 100644
index 0000000..d30cdad
--- /dev/null
+++ b/bt/btif/src/btif_uid.cc
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/************************************************************************************
+ *
+ *  Filename:      btif_uid.cc
+ *
+ *  Description:   Contains data structures and functions for keeping track of
+ *                 socket usage per app UID.
+ *
+ ***********************************************************************************/
+#include <mutex>
+
+#include "bt_common.h"
+#include "btif_uid.h"
+
+typedef struct uid_set_node_t {
+  struct uid_set_node_t* next;
+  bt_uid_traffic_t data;
+} uid_set_node_t;
+
+typedef struct uid_set_t {
+  std::mutex lock;
+  uid_set_node_t* head;
+} uid_set_t;
+
+uid_set_t* uid_set_create(void) {
+  uid_set_t* set = (uid_set_t*)osi_calloc(sizeof(uid_set_t));
+  return set;
+}
+
+void uid_set_destroy(uid_set_t* set) {
+  std::unique_lock<std::mutex> lock(set->lock);
+  uid_set_node_t* node = set->head;
+  while (node) {
+    uid_set_node_t* temp = node;
+    node = node->next;
+    osi_free(temp);
+  }
+  set->head = NULL;
+  osi_free(set);
+}
+
+// Lock in uid_set_t must be held.
+static uid_set_node_t* uid_set_find_or_create_node(uid_set_t* set,
+                                                   int32_t app_uid) {
+  uid_set_node_t* node = set->head;
+  while (node && node->data.app_uid != app_uid) {
+    node = node->next;
+  }
+
+  if (!node) {
+    node = (uid_set_node_t*)osi_calloc(sizeof(uid_set_node_t));
+    node->data.app_uid = app_uid;
+    node->next = set->head;
+    set->head = node;
+  }
+  return node;
+}
+
+void uid_set_add_tx(uid_set_t* set, int32_t app_uid, uint64_t bytes) {
+  if (app_uid == -1 || bytes == 0) return;
+
+  std::unique_lock<std::mutex> lock(set->lock);
+  uid_set_node_t* node = uid_set_find_or_create_node(set, app_uid);
+  node->data.tx_bytes += bytes;
+}
+
+void uid_set_add_rx(uid_set_t* set, int32_t app_uid, uint64_t bytes) {
+  if (app_uid == -1 || bytes == 0) return;
+
+  std::unique_lock<std::mutex> lock(set->lock);
+  uid_set_node_t* node = uid_set_find_or_create_node(set, app_uid);
+  node->data.rx_bytes += bytes;
+}
+
+bt_uid_traffic_t* uid_set_read_and_clear(uid_set_t* set) {
+  std::unique_lock<std::mutex> lock(set->lock);
+
+  // Find the length
+  size_t len = 0;
+  uid_set_node_t* node = set->head;
+  while (node) {
+    len++;
+    node = node->next;
+  }
+
+  // Allocate an array of elements + 1, to signify the end with app_uid set to
+  // -1.
+  bt_uid_traffic_t* result =
+      (bt_uid_traffic_t*)osi_calloc(sizeof(bt_uid_traffic_t) * (len + 1));
+
+  bt_uid_traffic_t* data = result;
+  node = set->head;
+  while (node) {
+    // Copy the data.
+    *data = node->data;
+    data++;
+
+    // Clear the counters.
+    node->data.rx_bytes = 0;
+    node->data.tx_bytes = 0;
+    node = node->next;
+  }
+
+  // Mark the last entry
+  data->app_uid = -1;
+
+  return result;
+}
diff --git a/bt/btif/src/btif_util.cc b/bt/btif/src/btif_util.cc
new file mode 100644
index 0000000..5c60e6e
--- /dev/null
+++ b/bt/btif/src/btif_util.cc
@@ -0,0 +1,515 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 2009-2016 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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ *  Filename:      btif_util.c
+ *
+ *  Description:   Miscellaneous helper functions
+ *
+ *
+ ***********************************************************************************/
+
+#define LOG_TAG "bt_btif_util"
+
+#include "btif_util.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <hardware/bt_av.h>
+
+#include "avrc_defs.h"
+#include "bt_common.h"
+#include "bta_ag_api.h"
+#include "bta_api.h"
+#include "bta_av_api.h"
+#include "bta_hf_client_api.h"
+#include "bta_hh_api.h"
+#include "bte.h"
+#include "btif_common.h"
+#include "btif_dm.h"
+#include "btu.h"
+
+/************************************************************************************
+ *  Constants & Macros
+ ***********************************************************************************/
+#define ISDIGIT(a) (((a) >= '0') && ((a) <= '9'))
+#define ISXDIGIT(a)                                                    \
+  ((((a) >= '0') && ((a) <= '9')) || (((a) >= 'A') && ((a) <= 'F')) || \
+   (((a) >= 'a') && ((a) <= 'f')))
+
+/************************************************************************************
+ *  Local type definitions
+ ***********************************************************************************/
+
+/************************************************************************************
+ *  Static variables
+ ***********************************************************************************/
+
+/************************************************************************************
+ *  Static functions
+ ***********************************************************************************/
+
+/************************************************************************************
+ *  Externs
+ ***********************************************************************************/
+
+/************************************************************************************
+ *  Functions
+ ***********************************************************************************/
+
+/*****************************************************************************
+ *   Logging helper functions
+ ****************************************************************************/
+
+uint32_t devclass2uint(DEV_CLASS dev_class) {
+  uint32_t cod = 0;
+
+  if (dev_class != NULL) {
+    /* if COD is 0, irrespective of the device type set it to Unclassified
+     * device */
+    cod = (dev_class[2]) | (dev_class[1] << 8) | (dev_class[0] << 16);
+  }
+  return cod;
+}
+void uint2devclass(uint32_t cod, DEV_CLASS dev_class) {
+  dev_class[2] = (uint8_t)cod;
+  dev_class[1] = (uint8_t)(cod >> 8);
+  dev_class[0] = (uint8_t)(cod >> 16);
+}
+
+static const uint8_t sdp_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                        0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+                                        0x5F, 0x9B, 0x34, 0xFB};
+
+void uuid16_to_uuid128(uint16_t uuid16, bt_uuid_t* uuid128) {
+  uint16_t uuid16_bo;
+  memset(uuid128, 0, sizeof(bt_uuid_t));
+
+  memcpy(uuid128->uu, sdp_base_uuid, MAX_UUID_SIZE);
+  uuid16_bo = ntohs(uuid16);
+  memcpy(uuid128->uu + 2, &uuid16_bo, sizeof(uint16_t));
+}
+
+bool string_to_uuid(const char* str, bt_uuid_t* p_uuid) {
+  assert(p_uuid);
+  if (str == NULL) return false;
+
+  uint32_t uuid0, uuid4;
+  uint16_t uuid1, uuid2, uuid3, uuid5;
+
+  int rc = sscanf(str, "%08x-%04hx-%04hx-%04hx-%08x%04hx", &uuid0, &uuid1,
+                  &uuid2, &uuid3, &uuid4, &uuid5);
+  if (rc != 6) return false;
+
+  uuid0 = htonl(uuid0);
+  uuid1 = htons(uuid1);
+  uuid2 = htons(uuid2);
+  uuid3 = htons(uuid3);
+  uuid4 = htonl(uuid4);
+  uuid5 = htons(uuid5);
+
+  memcpy(&(p_uuid->uu[0]), &uuid0, 4);
+  memcpy(&(p_uuid->uu[4]), &uuid1, 2);
+  memcpy(&(p_uuid->uu[6]), &uuid2, 2);
+  memcpy(&(p_uuid->uu[8]), &uuid3, 2);
+  memcpy(&(p_uuid->uu[10]), &uuid4, 4);
+  memcpy(&(p_uuid->uu[14]), &uuid5, 2);
+
+  return true;
+}
+
+void uuid_to_string_legacy(bt_uuid_t* p_uuid, char* str, size_t str_len) {
+  uint32_t uuid0, uuid4;
+  uint16_t uuid1, uuid2, uuid3, uuid5;
+
+  memcpy(&uuid0, &(p_uuid->uu[0]), 4);
+  memcpy(&uuid1, &(p_uuid->uu[4]), 2);
+  memcpy(&uuid2, &(p_uuid->uu[6]), 2);
+  memcpy(&uuid3, &(p_uuid->uu[8]), 2);
+  memcpy(&uuid4, &(p_uuid->uu[10]), 4);
+  memcpy(&uuid5, &(p_uuid->uu[14]), 2);
+
+  snprintf(str, str_len, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x", ntohl(uuid0),
+           ntohs(uuid1), ntohs(uuid2), ntohs(uuid3), ntohl(uuid4),
+           ntohs(uuid5));
+  return;
+}
+
+/*****************************************************************************
+ *  Function        ascii_2_hex
+ *
+ *  Description     This function converts an ASCII string into HEX
+ *
+ *  Returns         the number of hex bytes filled.
+*/
+int ascii_2_hex(const char* p_ascii, int len, uint8_t* p_hex) {
+  int x;
+  uint8_t c;
+
+  for (x = 0; (x < len) && (*p_ascii); x++) {
+    if (ISDIGIT(*p_ascii))
+      c = (*p_ascii - '0') << 4;
+    else
+      c = (toupper(*p_ascii) - 'A' + 10) << 4;
+
+    p_ascii++;
+    if (*p_ascii) {
+      if (ISDIGIT(*p_ascii))
+        c |= (*p_ascii - '0');
+      else
+        c |= (toupper(*p_ascii) - 'A' + 10);
+
+      p_ascii++;
+    }
+    *p_hex++ = c;
+  }
+
+  return (x);
+}
+
+const char* dump_dm_search_event(uint16_t event) {
+  switch (event) {
+    CASE_RETURN_STR(BTA_DM_INQ_RES_EVT)
+    CASE_RETURN_STR(BTA_DM_INQ_CMPL_EVT)
+    CASE_RETURN_STR(BTA_DM_DISC_RES_EVT)
+    CASE_RETURN_STR(BTA_DM_DISC_BLE_RES_EVT)
+    CASE_RETURN_STR(BTA_DM_DISC_CMPL_EVT)
+    CASE_RETURN_STR(BTA_DM_DI_DISC_CMPL_EVT)
+    CASE_RETURN_STR(BTA_DM_SEARCH_CANCEL_CMPL_EVT)
+
+    default:
+      return "UNKNOWN MSG ID";
+  }
+}
+
+const char* dump_property_type(bt_property_type_t type) {
+  switch (type) {
+    CASE_RETURN_STR(BT_PROPERTY_BDNAME)
+    CASE_RETURN_STR(BT_PROPERTY_BDADDR)
+    CASE_RETURN_STR(BT_PROPERTY_UUIDS)
+    CASE_RETURN_STR(BT_PROPERTY_CLASS_OF_DEVICE)
+    CASE_RETURN_STR(BT_PROPERTY_TYPE_OF_DEVICE)
+    CASE_RETURN_STR(BT_PROPERTY_REMOTE_RSSI)
+    CASE_RETURN_STR(BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT)
+    CASE_RETURN_STR(BT_PROPERTY_ADAPTER_BONDED_DEVICES)
+    CASE_RETURN_STR(BT_PROPERTY_ADAPTER_SCAN_MODE)
+    CASE_RETURN_STR(BT_PROPERTY_REMOTE_FRIENDLY_NAME)
+
+    default:
+      return "UNKNOWN PROPERTY ID";
+  }
+}
+
+const char* dump_dm_event(uint16_t event) {
+  switch (event) {
+    CASE_RETURN_STR(BTA_DM_ENABLE_EVT)
+    CASE_RETURN_STR(BTA_DM_DISABLE_EVT)
+    CASE_RETURN_STR(BTA_DM_PIN_REQ_EVT)
+    CASE_RETURN_STR(BTA_DM_AUTH_CMPL_EVT)
+    CASE_RETURN_STR(BTA_DM_AUTHORIZE_EVT)
+    CASE_RETURN_STR(BTA_DM_LINK_UP_EVT)
+    CASE_RETURN_STR(BTA_DM_LINK_DOWN_EVT)
+    CASE_RETURN_STR(BTA_DM_SIG_STRENGTH_EVT)
+    CASE_RETURN_STR(BTA_DM_BUSY_LEVEL_EVT)
+    CASE_RETURN_STR(BTA_DM_BOND_CANCEL_CMPL_EVT)
+    CASE_RETURN_STR(BTA_DM_SP_CFM_REQ_EVT)
+    CASE_RETURN_STR(BTA_DM_SP_KEY_NOTIF_EVT)
+    CASE_RETURN_STR(BTA_DM_SP_RMT_OOB_EVT)
+    CASE_RETURN_STR(BTA_DM_SP_KEYPRESS_EVT)
+    CASE_RETURN_STR(BTA_DM_ROLE_CHG_EVT)
+    CASE_RETURN_STR(BTA_DM_BLE_KEY_EVT)
+    CASE_RETURN_STR(BTA_DM_BLE_SEC_REQ_EVT)
+    CASE_RETURN_STR(BTA_DM_BLE_PASSKEY_NOTIF_EVT)
+    CASE_RETURN_STR(BTA_DM_BLE_PASSKEY_REQ_EVT)
+    CASE_RETURN_STR(BTA_DM_BLE_OOB_REQ_EVT)
+    CASE_RETURN_STR(BTA_DM_BLE_LOCAL_IR_EVT)
+    CASE_RETURN_STR(BTA_DM_BLE_LOCAL_ER_EVT)
+    CASE_RETURN_STR(BTA_DM_BLE_AUTH_CMPL_EVT)
+    CASE_RETURN_STR(BTA_DM_DEV_UNPAIRED_EVT)
+    CASE_RETURN_STR(BTA_DM_HW_ERROR_EVT)
+    CASE_RETURN_STR(BTA_DM_ENER_INFO_READ)
+
+    default:
+      return "UNKNOWN DM EVENT";
+  }
+}
+
+const char* dump_hf_event(uint16_t event) {
+  switch (event) {
+    CASE_RETURN_STR(BTA_AG_ENABLE_EVT)
+    CASE_RETURN_STR(BTA_AG_REGISTER_EVT)
+    CASE_RETURN_STR(BTA_AG_OPEN_EVT)
+    CASE_RETURN_STR(BTA_AG_CLOSE_EVT)
+    CASE_RETURN_STR(BTA_AG_CONN_EVT)
+    CASE_RETURN_STR(BTA_AG_AUDIO_OPEN_EVT)
+    CASE_RETURN_STR(BTA_AG_AUDIO_CLOSE_EVT)
+    CASE_RETURN_STR(BTA_AG_SPK_EVT)
+    CASE_RETURN_STR(BTA_AG_MIC_EVT)
+    CASE_RETURN_STR(BTA_AG_AT_CKPD_EVT)
+    CASE_RETURN_STR(BTA_AG_DISABLE_EVT)
+#if (BTM_WBS_INCLUDED == TRUE)
+    CASE_RETURN_STR(BTA_AG_WBS_EVT)
+#endif
+    CASE_RETURN_STR(BTA_AG_AT_A_EVT)
+    CASE_RETURN_STR(BTA_AG_AT_D_EVT)
+    CASE_RETURN_STR(BTA_AG_AT_CHLD_EVT)
+    CASE_RETURN_STR(BTA_AG_AT_CHUP_EVT)
+    CASE_RETURN_STR(BTA_AG_AT_CIND_EVT)
+    CASE_RETURN_STR(BTA_AG_AT_VTS_EVT)
+    CASE_RETURN_STR(BTA_AG_AT_BINP_EVT)
+    CASE_RETURN_STR(BTA_AG_AT_BLDN_EVT)
+    CASE_RETURN_STR(BTA_AG_AT_BVRA_EVT)
+    CASE_RETURN_STR(BTA_AG_AT_NREC_EVT)
+    CASE_RETURN_STR(BTA_AG_AT_CNUM_EVT)
+    CASE_RETURN_STR(BTA_AG_AT_BTRH_EVT)
+    CASE_RETURN_STR(BTA_AG_AT_CLCC_EVT)
+    CASE_RETURN_STR(BTA_AG_AT_COPS_EVT)
+    CASE_RETURN_STR(BTA_AG_AT_UNAT_EVT)
+    CASE_RETURN_STR(BTA_AG_AT_CBC_EVT)
+    CASE_RETURN_STR(BTA_AG_AT_BAC_EVT)
+    CASE_RETURN_STR(BTA_AG_AT_BCS_EVT)
+    CASE_RETURN_STR(BTA_AG_AT_BIND_EVT)
+    CASE_RETURN_STR(BTA_AG_AT_BIEV_EVT)
+
+    default:
+      return "UNKNOWN MSG ID";
+  }
+}
+
+const char* dump_hf_client_event(uint16_t event) {
+  switch (event) {
+    CASE_RETURN_STR(BTA_HF_CLIENT_ENABLE_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_REGISTER_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_OPEN_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_CLOSE_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_CONN_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_AUDIO_OPEN_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_AUDIO_CLOSE_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_SPK_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_MIC_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_DISABLE_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_IND_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_VOICE_REC_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_OPERATOR_NAME_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_CLIP_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_CCWA_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_AT_RESULT_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_CLCC_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_CNUM_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_BTRH_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_BSIR_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_BINP_EVT)
+    CASE_RETURN_STR(BTA_HF_CLIENT_RING_INDICATION)
+    default:
+      return "UNKNOWN MSG ID";
+  }
+}
+
+const char* dump_hh_event(uint16_t event) {
+  switch (event) {
+    CASE_RETURN_STR(BTA_HH_ENABLE_EVT)
+    CASE_RETURN_STR(BTA_HH_DISABLE_EVT)
+    CASE_RETURN_STR(BTA_HH_OPEN_EVT)
+    CASE_RETURN_STR(BTA_HH_CLOSE_EVT)
+    CASE_RETURN_STR(BTA_HH_GET_DSCP_EVT)
+    CASE_RETURN_STR(BTA_HH_GET_PROTO_EVT)
+    CASE_RETURN_STR(BTA_HH_GET_RPT_EVT)
+    CASE_RETURN_STR(BTA_HH_GET_IDLE_EVT)
+    CASE_RETURN_STR(BTA_HH_SET_PROTO_EVT)
+    CASE_RETURN_STR(BTA_HH_SET_RPT_EVT)
+    CASE_RETURN_STR(BTA_HH_SET_IDLE_EVT)
+    CASE_RETURN_STR(BTA_HH_VC_UNPLUG_EVT)
+    CASE_RETURN_STR(BTA_HH_ADD_DEV_EVT)
+    CASE_RETURN_STR(BTA_HH_RMV_DEV_EVT)
+    CASE_RETURN_STR(BTA_HH_API_ERR_EVT)
+    default:
+      return "UNKNOWN MSG ID";
+  }
+}
+
+const char* dump_hf_conn_state(uint16_t event) {
+  switch (event) {
+    CASE_RETURN_STR(BTHF_CONNECTION_STATE_DISCONNECTED)
+    CASE_RETURN_STR(BTHF_CONNECTION_STATE_CONNECTING)
+    CASE_RETURN_STR(BTHF_CONNECTION_STATE_CONNECTED)
+    CASE_RETURN_STR(BTHF_CONNECTION_STATE_SLC_CONNECTED)
+    CASE_RETURN_STR(BTHF_CONNECTION_STATE_DISCONNECTING)
+    default:
+      return "UNKNOWN MSG ID";
+  }
+}
+
+const char* dump_hf_call_state(bthf_call_state_t call_state) {
+  switch (call_state) {
+    CASE_RETURN_STR(BTHF_CALL_STATE_IDLE)
+    CASE_RETURN_STR(BTHF_CALL_STATE_HELD)
+    CASE_RETURN_STR(BTHF_CALL_STATE_DIALING)
+    CASE_RETURN_STR(BTHF_CALL_STATE_ALERTING)
+    CASE_RETURN_STR(BTHF_CALL_STATE_INCOMING)
+    CASE_RETURN_STR(BTHF_CALL_STATE_WAITING)
+    CASE_RETURN_STR(BTHF_CALL_STATE_ACTIVE)
+    default:
+      return "UNKNOWN CALL STATE";
+  }
+}
+
+const char* dump_thread_evt(bt_cb_thread_evt evt) {
+  switch (evt) {
+    CASE_RETURN_STR(ASSOCIATE_JVM)
+    CASE_RETURN_STR(DISASSOCIATE_JVM)
+
+    default:
+      return "unknown thread evt";
+  }
+}
+
+const char* dump_hf_audio_state(uint16_t event) {
+  switch (event) {
+    CASE_RETURN_STR(BTHF_AUDIO_STATE_DISCONNECTED)
+    CASE_RETURN_STR(BTHF_AUDIO_STATE_CONNECTING)
+    CASE_RETURN_STR(BTHF_AUDIO_STATE_CONNECTED)
+    CASE_RETURN_STR(BTHF_AUDIO_STATE_DISCONNECTING)
+    default:
+      return "UNKNOWN MSG ID";
+  }
+}
+
+const char* dump_av_conn_state(uint16_t event) {
+  switch (event) {
+    CASE_RETURN_STR(BTAV_CONNECTION_STATE_DISCONNECTED)
+    CASE_RETURN_STR(BTAV_CONNECTION_STATE_CONNECTING)
+    CASE_RETURN_STR(BTAV_CONNECTION_STATE_CONNECTED)
+    CASE_RETURN_STR(BTAV_CONNECTION_STATE_DISCONNECTING)
+    default:
+      return "UNKNOWN MSG ID";
+  }
+}
+
+const char* dump_av_audio_state(uint16_t event) {
+  switch (event) {
+    CASE_RETURN_STR(BTAV_AUDIO_STATE_REMOTE_SUSPEND)
+    CASE_RETURN_STR(BTAV_AUDIO_STATE_STOPPED)
+    CASE_RETURN_STR(BTAV_AUDIO_STATE_STARTED)
+    default:
+      return "UNKNOWN MSG ID";
+  }
+}
+
+const char* dump_adapter_scan_mode(bt_scan_mode_t mode) {
+  switch (mode) {
+    CASE_RETURN_STR(BT_SCAN_MODE_NONE)
+    CASE_RETURN_STR(BT_SCAN_MODE_CONNECTABLE)
+    CASE_RETURN_STR(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE)
+
+    default:
+      return "unknown scan mode";
+  }
+}
+
+const char* dump_bt_status(bt_status_t status) {
+  switch (status) {
+    CASE_RETURN_STR(BT_STATUS_SUCCESS)
+    CASE_RETURN_STR(BT_STATUS_FAIL)
+    CASE_RETURN_STR(BT_STATUS_NOT_READY)
+    CASE_RETURN_STR(BT_STATUS_NOMEM)
+    CASE_RETURN_STR(BT_STATUS_BUSY)
+    CASE_RETURN_STR(BT_STATUS_UNSUPPORTED)
+
+    default:
+      return "unknown scan mode";
+  }
+}
+
+const char* dump_rc_event(uint8_t event) {
+  switch (event) {
+    CASE_RETURN_STR(BTA_AV_RC_OPEN_EVT)
+    CASE_RETURN_STR(BTA_AV_RC_CLOSE_EVT)
+    CASE_RETURN_STR(BTA_AV_RC_BROWSE_OPEN_EVT)
+    CASE_RETURN_STR(BTA_AV_RC_BROWSE_CLOSE_EVT)
+    CASE_RETURN_STR(BTA_AV_REMOTE_CMD_EVT)
+    CASE_RETURN_STR(BTA_AV_REMOTE_RSP_EVT)
+    CASE_RETURN_STR(BTA_AV_VENDOR_CMD_EVT)
+    CASE_RETURN_STR(BTA_AV_VENDOR_RSP_EVT)
+    CASE_RETURN_STR(BTA_AV_META_MSG_EVT)
+    CASE_RETURN_STR(BTA_AV_RC_FEAT_EVT)
+    default:
+      return "UNKNOWN_EVENT";
+  }
+}
+
+const char* dump_rc_notification_event_id(uint8_t event_id) {
+  switch (event_id) {
+    CASE_RETURN_STR(AVRC_EVT_PLAY_STATUS_CHANGE)
+    CASE_RETURN_STR(AVRC_EVT_TRACK_CHANGE)
+    CASE_RETURN_STR(AVRC_EVT_TRACK_REACHED_END)
+    CASE_RETURN_STR(AVRC_EVT_TRACK_REACHED_START)
+    CASE_RETURN_STR(AVRC_EVT_PLAY_POS_CHANGED)
+    CASE_RETURN_STR(AVRC_EVT_BATTERY_STATUS_CHANGE)
+    CASE_RETURN_STR(AVRC_EVT_SYSTEM_STATUS_CHANGE)
+    CASE_RETURN_STR(AVRC_EVT_APP_SETTING_CHANGE)
+    CASE_RETURN_STR(AVRC_EVT_VOLUME_CHANGE)
+    CASE_RETURN_STR(AVRC_EVT_ADDR_PLAYER_CHANGE)
+    CASE_RETURN_STR(AVRC_EVT_AVAL_PLAYERS_CHANGE)
+    CASE_RETURN_STR(AVRC_EVT_NOW_PLAYING_CHANGE)
+    CASE_RETURN_STR(AVRC_EVT_UIDS_CHANGE)
+
+    default:
+      return "Unhandled Event ID";
+  }
+}
+
+const char* dump_rc_pdu(uint8_t pdu) {
+  switch (pdu) {
+    CASE_RETURN_STR(AVRC_PDU_LIST_PLAYER_APP_ATTR)
+    CASE_RETURN_STR(AVRC_PDU_LIST_PLAYER_APP_VALUES)
+    CASE_RETURN_STR(AVRC_PDU_GET_CUR_PLAYER_APP_VALUE)
+    CASE_RETURN_STR(AVRC_PDU_SET_PLAYER_APP_VALUE)
+    CASE_RETURN_STR(AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT)
+    CASE_RETURN_STR(AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT)
+    CASE_RETURN_STR(AVRC_PDU_INFORM_DISPLAY_CHARSET)
+    CASE_RETURN_STR(AVRC_PDU_INFORM_BATTERY_STAT_OF_CT)
+    CASE_RETURN_STR(AVRC_PDU_GET_ELEMENT_ATTR)
+    CASE_RETURN_STR(AVRC_PDU_GET_PLAY_STATUS)
+    CASE_RETURN_STR(AVRC_PDU_REGISTER_NOTIFICATION)
+    CASE_RETURN_STR(AVRC_PDU_REQUEST_CONTINUATION_RSP)
+    CASE_RETURN_STR(AVRC_PDU_ABORT_CONTINUATION_RSP)
+    CASE_RETURN_STR(AVRC_PDU_SET_ABSOLUTE_VOLUME)
+    CASE_RETURN_STR(AVRC_PDU_SET_ADDRESSED_PLAYER)
+    CASE_RETURN_STR(AVRC_PDU_CHANGE_PATH)
+    CASE_RETURN_STR(AVRC_PDU_GET_CAPABILITIES)
+    CASE_RETURN_STR(AVRC_PDU_SET_BROWSED_PLAYER)
+    CASE_RETURN_STR(AVRC_PDU_GET_FOLDER_ITEMS)
+    CASE_RETURN_STR(AVRC_PDU_GET_ITEM_ATTRIBUTES)
+    CASE_RETURN_STR(AVRC_PDU_PLAY_ITEM)
+    CASE_RETURN_STR(AVRC_PDU_SEARCH)
+    CASE_RETURN_STR(AVRC_PDU_ADD_TO_NOW_PLAYING)
+    CASE_RETURN_STR(AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS)
+    CASE_RETURN_STR(AVRC_PDU_GENERAL_REJECT)
+
+    default:
+      return "Unknown PDU";
+  }
+}
diff --git a/bt/btif/src/stack_manager.cc b/bt/btif/src/stack_manager.cc
new file mode 100644
index 0000000..56f8c64
--- /dev/null
+++ b/bt/btif/src/stack_manager.cc
@@ -0,0 +1,255 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_stack_manager"
+
+#include "stack_manager.h"
+
+#include <hardware/bluetooth.h>
+
+#include "btcore/include/module.h"
+#include "btcore/include/osi_module.h"
+#include "btif_api.h"
+#include "btif_common.h"
+#include "device/include/controller.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/semaphore.h"
+#include "osi/include/thread.h"
+
+// Temp includes
+#include "bt_utils.h"
+#include "btif_config.h"
+#include "btif_profile_queue.h"
+
+static thread_t* management_thread;
+
+// If initialized, any of the bluetooth API functions can be called.
+// (e.g. turning logging on and off, enabling/disabling the stack, etc)
+static bool stack_is_initialized;
+// If running, the stack is fully up and able to bluetooth.
+static bool stack_is_running;
+
+static void event_init_stack(void* context);
+static void event_start_up_stack(void* context);
+static void event_shut_down_stack(void* context);
+static void event_clean_up_stack(void* context);
+
+static void event_signal_stack_up(void* context);
+static void event_signal_stack_down(void* context);
+
+// Unvetted includes/imports, etc which should be removed or vetted in the
+// future
+static future_t* hack_future;
+void btif_thread_post(thread_fn func, void* context);
+// End unvetted section
+
+// Interface functions
+
+static void init_stack(void) {
+  // This is a synchronous process. Post it to the thread though, so
+  // state modification only happens there. Using the thread to perform
+  // all stack operations ensures that the operations are done serially
+  // and do not overlap.
+  semaphore_t* semaphore = semaphore_new(0);
+  thread_post(management_thread, event_init_stack, semaphore);
+  semaphore_wait(semaphore);
+  semaphore_free(semaphore);
+}
+
+static void start_up_stack_async(void) {
+  thread_post(management_thread, event_start_up_stack, NULL);
+}
+
+static void shut_down_stack_async(void) {
+  thread_post(management_thread, event_shut_down_stack, NULL);
+}
+
+static void clean_up_stack(void) {
+  // This is a synchronous process. Post it to the thread though, so
+  // state modification only happens there.
+  semaphore_t* semaphore = semaphore_new(0);
+  thread_post(management_thread, event_clean_up_stack, semaphore);
+  semaphore_wait(semaphore);
+  semaphore_free(semaphore);
+}
+
+static bool get_stack_is_running(void) { return stack_is_running; }
+
+// Internal functions
+
+// Synchronous function to initialize the stack
+static void event_init_stack(void* context) {
+  semaphore_t* semaphore = (semaphore_t*)context;
+
+  LOG_INFO(LOG_TAG, "%s is initializing the stack", __func__);
+
+  if (stack_is_initialized) {
+    LOG_INFO(LOG_TAG, "%s found the stack already in initialized state",
+             __func__);
+  } else {
+    module_management_start();
+
+    module_init(get_module(OSI_MODULE));
+    module_init(get_module(BT_UTILS_MODULE));
+    module_init(get_module(BTIF_CONFIG_MODULE));
+    btif_init_bluetooth();
+
+    // stack init is synchronous, so no waiting necessary here
+    stack_is_initialized = true;
+  }
+
+  LOG_INFO(LOG_TAG, "%s finished", __func__);
+
+  if (semaphore) semaphore_post(semaphore);
+}
+
+static void ensure_stack_is_initialized(void) {
+  if (!stack_is_initialized) {
+    LOG_WARN(LOG_TAG, "%s found the stack was uninitialized. Initializing now.",
+             __func__);
+    // No semaphore needed since we are calling it directly
+    event_init_stack(NULL);
+  }
+}
+
+// Synchronous function to start up the stack
+static void event_start_up_stack(UNUSED_ATTR void* context) {
+  if (stack_is_running) {
+    LOG_INFO(LOG_TAG, "%s stack already brought up", __func__);
+    return;
+  }
+
+  ensure_stack_is_initialized();
+
+  LOG_INFO(LOG_TAG, "%s is bringing up the stack", __func__);
+  future_t* local_hack_future = future_new();
+  hack_future = local_hack_future;
+
+  // Include this for now to put btif config into a shutdown-able state
+  module_start_up(get_module(BTIF_CONFIG_MODULE));
+  bte_main_enable();
+
+  if (future_await(local_hack_future) != FUTURE_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s failed to start up the stack", __func__);
+    stack_is_running = true;  // So stack shutdown actually happens
+    event_shut_down_stack(NULL);
+    return;
+  }
+
+  stack_is_running = true;
+  LOG_INFO(LOG_TAG, "%s finished", __func__);
+  btif_thread_post(event_signal_stack_up, NULL);
+}
+
+// Synchronous function to shut down the stack
+static void event_shut_down_stack(UNUSED_ATTR void* context) {
+  if (!stack_is_running) {
+    LOG_INFO(LOG_TAG, "%s stack is already brought down", __func__);
+    return;
+  }
+
+  LOG_INFO(LOG_TAG, "%s is bringing down the stack", __func__);
+  future_t* local_hack_future = future_new();
+  hack_future = local_hack_future;
+  stack_is_running = false;
+
+  btif_disable_bluetooth();
+  module_shut_down(get_module(BTIF_CONFIG_MODULE));
+
+  future_await(local_hack_future);
+  module_shut_down(get_module(CONTROLLER_MODULE));  // Doesn't do any work, just
+                                                    // puts it in a restartable
+                                                    // state
+
+  LOG_INFO(LOG_TAG, "%s finished", __func__);
+  hack_future = future_new();
+  btif_thread_post(event_signal_stack_down, NULL);
+  future_await(hack_future);
+}
+
+static void ensure_stack_is_not_running(void) {
+  if (stack_is_running) {
+    LOG_WARN(LOG_TAG,
+             "%s found the stack was still running. Bringing it down now.",
+             __func__);
+    event_shut_down_stack(NULL);
+  }
+}
+
+// Synchronous function to clean up the stack
+static void event_clean_up_stack(void* context) {
+  future_t* local_hack_future;
+
+  if (!stack_is_initialized) {
+    LOG_INFO(LOG_TAG, "%s found the stack already in a clean state", __func__);
+    goto cleanup;
+  }
+
+  ensure_stack_is_not_running();
+
+  LOG_INFO(LOG_TAG, "%s is cleaning up the stack", __func__);
+  local_hack_future = future_new();
+  hack_future = local_hack_future;
+  stack_is_initialized = false;
+
+  btif_cleanup_bluetooth();
+  module_clean_up(get_module(BTIF_CONFIG_MODULE));
+  module_clean_up(get_module(BT_UTILS_MODULE));
+  module_clean_up(get_module(OSI_MODULE));
+  module_management_stop();
+  LOG_INFO(LOG_TAG, "%s finished", __func__);
+
+cleanup:;
+  semaphore_t* semaphore = (semaphore_t*)context;
+  if (semaphore) semaphore_post(semaphore);
+}
+
+static void event_signal_stack_up(UNUSED_ATTR void* context) {
+  // Notify BTIF connect queue that we've brought up the stack. It's
+  // now time to dispatch all the pending profile connect requests.
+  btif_queue_connect_next();
+  HAL_CBACK(bt_hal_cbacks, adapter_state_changed_cb, BT_STATE_ON);
+}
+
+static void event_signal_stack_down(UNUSED_ATTR void* context) {
+  HAL_CBACK(bt_hal_cbacks, adapter_state_changed_cb, BT_STATE_OFF);
+  future_ready(stack_manager_get_hack_future(), FUTURE_SUCCESS);
+}
+
+static void ensure_manager_initialized(void) {
+  if (management_thread) return;
+
+  management_thread = thread_new("stack_manager");
+  if (!management_thread) {
+    LOG_ERROR(LOG_TAG, "%s unable to create stack management thread", __func__);
+    return;
+  }
+}
+
+static const stack_manager_t interface = {init_stack, start_up_stack_async,
+                                          shut_down_stack_async, clean_up_stack,
+
+                                          get_stack_is_running};
+
+const stack_manager_t* stack_manager_get_interface() {
+  ensure_manager_initialized();
+  return &interface;
+}
+
+future_t* stack_manager_get_hack_future() { return hack_future; }
diff --git a/bt/btif/test/btif_storage_test.cc b/bt/btif/test/btif_storage_test.cc
new file mode 100644
index 0000000..988e23f
--- /dev/null
+++ b/bt/btif/test/btif_storage_test.cc
@@ -0,0 +1,68 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "btif/include/btif_storage.h"
+#include "btif/include/btif_util.h"
+
+TEST(BtifStorageTest, test_string_to_uuid) {
+  const char* s1 = "e39c6285-867f-4b1d-9db0-35fbd9aebf22";
+  const uint8_t u1[] = {0xe3, 0x9c, 0x62, 0x85, 0x86, 0x7f, 0x4b, 0x1d,
+                        0x9d, 0xb0, 0x35, 0xfb, 0xd9, 0xae, 0xbf, 0x22};
+
+  bt_uuid_t uuid;
+  memset(&uuid, 0, sizeof(uuid));
+  EXPECT_FALSE(memcmp(&uuid, u1, sizeof(u1)) == 0);
+
+  bool rc = string_to_uuid(s1, &uuid);
+  EXPECT_TRUE(rc);
+  EXPECT_TRUE(memcmp(&uuid, u1, sizeof(u1)) == 0);
+}
+
+TEST(BtifStorageTest, test_string_to_uuid_invalid) {
+  bt_uuid_t uuid;
+  bool rc = string_to_uuid("This is not a UUID", &uuid);
+  EXPECT_FALSE(rc);
+}
+
+TEST(BtifStorageTest, test_uuid_split_multiple) {
+  const char* s1 =
+      "e39c6285-867f-4b1d-9db0-35fbd9aebf22 "
+      "e39c6285-867f-4b1d-9db0-35fbd9aebf23";
+  const uint8_t u1[] = {0xe3, 0x9c, 0x62, 0x85, 0x86, 0x7f, 0x4b, 0x1d,
+                        0x9d, 0xb0, 0x35, 0xfb, 0xd9, 0xae, 0xbf, 0x22};
+  const uint8_t u2[] = {0xe3, 0x9c, 0x62, 0x85, 0x86, 0x7f, 0x4b, 0x1d,
+                        0x9d, 0xb0, 0x35, 0xfb, 0xd9, 0xae, 0xbf, 0x23};
+
+  bt_uuid_t uuids[2];
+  size_t num_uuids = btif_split_uuids_string(s1, uuids, 2);
+  EXPECT_EQ(num_uuids, 2u);
+  EXPECT_TRUE(memcmp(&uuids[0], u1, sizeof(u1)) == 0);
+  EXPECT_TRUE(memcmp(&uuids[1], u2, sizeof(u2)) == 0);
+}
+
+TEST(BtifStorageTest, test_uuid_split_partial) {
+  const char* s1 =
+      "e39c6285-867f-4b1d-9db0-35fbd9aebf22 "
+      "e39c6285-867f-4b1d-9db0-35fbd9aebf23";
+
+  bt_uuid_t uuids[2];
+  size_t num_uuids = btif_split_uuids_string(s1, uuids, 1);
+  EXPECT_EQ(num_uuids, 1u);
+}
diff --git a/bt/build/BUILD.gn b/bt/build/BUILD.gn
new file mode 100644
index 0000000..ebebf3d
--- /dev/null
+++ b/bt/build/BUILD.gn
@@ -0,0 +1,74 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+config("default_include_dirs") {
+  include_dirs = [
+    "//third_party/libhardware/include/",
+  ]
+}
+
+config("linux") {
+  # TODO(keybuk): AndroidConfig.h or equivalent
+
+  cflags = [
+    #TODO(jpawlowski): uncomment once we have no warnings on linux build
+    #    "-Wall",
+    #    "-Werror",
+    "-g",
+    "-O0",
+    "-fpic",
+    "-fdata-sections",
+    "-ffunction-sections",
+    "-fvisibility=hidden",
+  ]
+
+  cflags_c = [ "-std=c99" ]
+
+  cflags_cc = [
+#TODO(jpawlowski): we should use same c++ version as Android, which is c++11,
+# but we use some c++14 features. Uncomment when this get fixed in code.:
+    "-std=c++14",
+    "-fno-exceptions",
+    "-fpermissive",
+  ]
+
+  defines = [
+    "_FORTIFY_SOURCE=2",
+    "_GNU_SOURCE",
+    "HAS_NO_BDROID_BUILDCFG",
+    "LOG_NDEBUG=1",
+    "EXPORT_SYMBOL=__attribute__((visibility(\"default\")))",
+    "KERNEL_MISSING_CLOCK_BOOTTIME_ALARM=TRUE",
+
+    # This is a macro to that can be used by android hardware/libhardware
+    # to not include dependencies on core project. This is a temporary
+    # workaround until we get rid of dependency on hardware.
+    "_HW_DONT_INCLUDE_CORE_=1",
+
+    # This is a macro to that can be used by source code to detect if the
+    # current build is done by GN or via Android.mk. This is a temporary
+    # workaround until we can remove all Android-specific dependencies.
+    "OS_GENERIC",
+  ]
+}
+
+config("pic") {
+  cflags = [ "-fPIC" ]
+}
+
+config("gc") {
+  ldflags = [ "-Wl,--gc-sections" ]
+}
diff --git a/bt/build/config/BUILDCONFIG.gn b/bt/build/config/BUILDCONFIG.gn
new file mode 100644
index 0000000..fb71af5
--- /dev/null
+++ b/bt/build/config/BUILDCONFIG.gn
@@ -0,0 +1,49 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+set_default_toolchain("//build/toolchain/clang")
+
+set_defaults("executable") {
+  configs = [
+    "//build:linux",
+    "//build:gc",
+    "//build:default_include_dirs",
+  ]
+}
+
+set_defaults("shared_library") {
+  configs = [
+    "//build:linux",
+    "//build:gc",
+    "//build:default_include_dirs",
+  ]
+}
+
+set_defaults("source_set") {
+  configs = [
+    "//build:linux",
+    "//build:gc",
+    "//build:default_include_dirs",
+  ]
+}
+
+set_defaults("static_library") {
+  configs = [
+    "//build:linux",
+    "//build:gc",
+    "//build:default_include_dirs",
+  ]
+}
diff --git a/bt/build/secondary/third_party/googletest/BUILD.gn b/bt/build/secondary/third_party/googletest/BUILD.gn
new file mode 100644
index 0000000..0122adc
--- /dev/null
+++ b/bt/build/secondary/third_party/googletest/BUILD.gn
@@ -0,0 +1,91 @@
+#
+#  Copyright (C) 2016 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+config("gtest_config") {
+  # Gtest headers need to be able to find themselves.
+  include_dirs = [ "googletest/include" ]
+
+  defines = [ "GTEST_HAS_RTTI=0" ]
+}
+
+config("gtest_direct_config") {
+  visibility = [ ":*" ]
+  defines = [ "UNIT_TEST" ]
+}
+
+static_library("gtest") {
+  testonly = true
+  sources = [
+    "googletest/src/gtest-all.cc",
+  ]
+
+  include_dirs = [
+    "googletest/",
+    "googletest/include",
+  ]
+
+  all_dependent_configs = [ ":gtest_config" ]
+  public_configs = [ ":gtest_direct_config" ]
+}
+
+source_set("gtest_main") {
+  testonly = true
+  sources = [
+    "googletest/src/gtest_main.cc",
+  ]
+  deps = [
+    ":gtest",
+  ]
+}
+
+config("gmock_config") {
+  # Gmock headers need to be able to find themselves.
+  include_dirs = [ "googlemock/include" ]
+}
+
+static_library("gmock") {
+  testonly = true
+  sources = [
+    "googlemock/src/gmock-all.cc",
+  ]
+
+  # This project includes some stuff form gtest's guts.
+  include_dirs = [
+    "googlemock",
+    "googlemock/include",
+  ]
+
+  public_configs = [
+    ":gmock_config",
+    ":gtest_config",
+  ]
+}
+
+static_library("gmock_main") {
+  testonly = true
+  sources = [
+    "googlemock/src/gmock_main.cc",
+  ]
+  deps = [
+    ":gmock",
+    ":gtest",
+  ]
+
+  public_configs = [
+    ":gmock_config",
+    ":gtest_config",
+  ]
+}
diff --git a/bt/build/secondary/third_party/libchrome/BUILD.gn b/bt/build/secondary/third_party/libchrome/BUILD.gn
new file mode 100644
index 0000000..fc58cb6
--- /dev/null
+++ b/bt/build/secondary/third_party/libchrome/BUILD.gn
@@ -0,0 +1,258 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+source_set("base_sources") {
+  sources = [
+    "base/at_exit.cc",
+    "base/atomic_ref_count.h",
+    "base/atomic_sequence_num.h",
+    "base/atomicops.h",
+    "base/base64.cc",
+    "base/base64.h",
+    "base/base_export.h",
+    "base/base_switches.cc",
+    "base/bind_helpers.cc",
+    "base/build_time.cc",
+    "base/callback_helpers.cc",
+    "base/callback_internal.cc",
+    "base/command_line.cc",
+    "base/cpu.cc",
+    "base/debug/alias.cc",
+    "base/debug/debugger.cc",
+    "base/debug/debugger_posix.cc",
+    "base/debug/stack_trace.cc",
+    "base/debug/stack_trace_posix.cc",
+    "base/debug/task_annotator.cc",
+    "base/environment.cc",
+    "base/files/file.cc",
+    "base/files/file_enumerator.cc",
+    "base/files/file_enumerator_posix.cc",
+    "base/files/file_path.cc",
+    "base/files/file_path_constants.cc",
+    "base/files/file_path_watcher.cc",
+    "base/files/file_path_watcher_linux.cc",
+    "base/files/file_posix.cc",
+    "base/files/file_tracing.cc",
+    "base/files/file_util.cc",
+    "base/files/file_util_linux.cc",
+    "base/files/file_util_posix.cc",
+    "base/files/important_file_writer.cc",
+    "base/files/scoped_file.cc",
+    "base/files/scoped_temp_dir.cc",
+    "base/guid.cc",
+    "base/json/json_parser.cc",
+    "base/json/json_reader.cc",
+    "base/json/json_string_value_serializer.cc",
+    "base/json/json_writer.cc",
+    "base/json/string_escape.cc",
+    "base/lazy_instance.cc",
+    "base/location.cc",
+    "base/logging.cc",
+    "base/md5.cc",
+    "base/memory/ref_counted.cc",
+    "base/memory/ref_counted_memory.cc",
+    "base/memory/singleton.cc",
+    "base/memory/weak_ptr.cc",
+    "base/message_loop/incoming_task_queue.cc",
+    "base/message_loop/message_loop.cc",
+    "base/message_loop/message_loop_task_runner.cc",
+    "base/message_loop/message_pump.cc",
+    "base/message_loop/message_pump_default.cc",
+
+    # we don't want any glib dependencies.
+    #   "base/message_loop/message_pump_glib.cc",
+    "base/message_loop/message_pump_libevent.cc",
+    "base/metrics/bucket_ranges.cc",
+    "base/metrics/field_trial.cc",
+    "base/metrics/metrics_hashes.cc",
+    "base/metrics/histogram_base.cc",
+    "base/metrics/histogram.cc",
+    "base/metrics/histogram_samples.cc",
+    "base/metrics/histogram_snapshot_manager.cc",
+    "base/metrics/persistent_histogram_allocator.cc",
+    "base/metrics/persistent_memory_allocator.cc",
+    "base/metrics/persistent_sample_map.cc",
+    "base/metrics/sample_map.cc",
+    "base/metrics/sample_vector.cc",
+    "base/metrics/sparse_histogram.cc",
+    "base/metrics/statistics_recorder.cc",
+    "base/pending_task.cc",
+    "base/pickle.cc",
+    "base/posix/file_descriptor_shuffle.cc",
+    "base/posix/safe_strerror.cc",
+    "base/posix/unix_domain_socket_linux.cc",
+    "base/process/internal_linux.cc",
+    "base/process/kill.cc",
+    "base/process/kill_posix.cc",
+    "base/process/launch.cc",
+    "base/process/launch_posix.cc",
+    "base/process/process_handle_linux.cc",
+    "base/process/process_handle_posix.cc",
+    "base/process/process_iterator.cc",
+    "base/process/process_iterator_linux.cc",
+    "base/process/process_metrics.cc",
+    "base/process/process_metrics_linux.cc",
+    "base/process/process_metrics_posix.cc",
+    "base/process/process_posix.cc",
+    "base/profiler/scoped_profile.cc",
+    "base/profiler/scoped_tracker.cc",
+    "base/profiler/tracked_time.cc",
+    "base/rand_util.cc",
+    "base/rand_util_posix.cc",
+    "base/run_loop.cc",
+    "base/sequence_checker_impl.cc",
+    "base/sequenced_task_runner.cc",
+    "base/sha1_portable.cc",
+    "base/strings/pattern.cc",
+    "base/strings/safe_sprintf.cc",
+    "base/strings/string16.cc",
+    "base/strings/string_number_conversions.cc",
+    "base/strings/string_piece.cc",
+    "base/strings/stringprintf.cc",
+    "base/strings/string_split.cc",
+    "base/strings/string_util.cc",
+    "base/strings/string_util_constants.cc",
+    "base/strings/sys_string_conversions_posix.cc",
+    "base/strings/utf_string_conversions.cc",
+    "base/strings/utf_string_conversion_utils.cc",
+    "base/synchronization/cancellation_flag.cc",
+    "base/synchronization/condition_variable_posix.cc",
+    "base/synchronization/lock.cc",
+    "base/synchronization/lock_impl_posix.cc",
+    "base/synchronization/read_write_lock_posix.cc",
+    "base/synchronization/waitable_event_posix.cc",
+    "base/sync_socket_posix.cc",
+    "base/sys_info.cc",
+
+    # TODO(armansito): For our GN builds these platform-specific implementations
+    # don't really make that much sense but instead of removing the line I'm
+    # commenting it out in case we want to re-add it later (it's included in the
+    # libchrome Android.mk).
+    #"sys_info_chromeos.cc",
+    "base/sys_info_linux.cc",
+    "base/sys_info_posix.cc",
+    "base/task/cancelable_task_tracker.cc",
+    "base/task_runner.cc",
+    "base/third_party/icu/icu_utf.cc",
+    "base/third_party/nspr/prtime.cc",
+    "base/threading/non_thread_safe_impl.cc",
+    "base/threading/platform_thread_internal_posix.cc",
+    "base/threading/platform_thread_linux.cc",
+    "base/threading/platform_thread_posix.cc",
+    "base/threading/post_task_and_reply_impl.cc",
+    "base/threading/sequenced_task_runner_handle.cc",
+    "base/threading/sequenced_worker_pool.cc",
+    "base/threading/simple_thread.cc",
+    "base/threading/thread.cc",
+    "base/threading/thread_checker_impl.cc",
+    "base/threading/thread_collision_warner.cc",
+    "base/threading/thread_id_name_manager.cc",
+    "base/threading/thread_local_posix.cc",
+    "base/threading/thread_local_storage.cc",
+    "base/threading/thread_local_storage_posix.cc",
+    "base/threading/thread_restrictions.cc",
+    "base/threading/worker_pool.cc",
+    "base/threading/worker_pool_posix.cc",
+    "base/threading/thread_task_runner_handle.cc",
+    "base/time/clock.cc",
+    "base/time/default_clock.cc",
+    "base/time/default_tick_clock.cc",
+    "base/timer/elapsed_timer.cc",
+    "base/timer/timer.cc",
+    "base/time/tick_clock.cc",
+    "base/time/time.cc",
+    "base/time/time_posix.cc",
+    "base/trace_event/heap_profiler_allocation_context.cc",
+    "base/trace_event/heap_profiler_allocation_context_tracker.cc",
+    "base/trace_event/heap_profiler_stack_frame_deduplicator.cc",
+    "base/trace_event/heap_profiler_type_name_deduplicator.cc",
+    "base/trace_event/malloc_dump_provider.cc",
+    "base/trace_event/memory_allocator_dump.cc",
+    "base/trace_event/memory_allocator_dump_guid.cc",
+    "base/trace_event/memory_dump_manager.cc",
+    "base/trace_event/memory_dump_session_state.cc",
+    "base/trace_event/memory_infra_background_whitelist.cc",
+    "base/trace_event/process_memory_dump.cc",
+    "base/trace_event/process_memory_maps.cc",
+    "base/trace_event/process_memory_totals.cc",
+    "base/trace_event/trace_buffer.cc",
+    "base/trace_event/trace_config.cc",
+    "base/trace_event/trace_event_argument.cc",
+    "base/trace_event/trace_event_impl.cc",
+    "base/trace_event/trace_event_memory_overhead.cc",
+    "base/trace_event/trace_event_synthetic_delay.cc",
+    "base/trace_event/trace_log.cc",
+    "base/trace_event/trace_log_constants.cc",
+    "base/trace_event/trace_sampling_thread.cc",
+    "base/tracked_objects.cc",
+    "base/tracking_info.cc",
+    "base/values.cc",
+    "base/vlog.cc",
+  ]
+
+  defines = [
+    "BASE_IMPLEMENTATION",
+
+    # trick libchrome to think we're building host code within an Android checkout
+    # thanks to it no glib dependency
+    "__ANDROID_HOST__=1",
+    "OS_LINUX=1",
+  ]
+
+  include_dirs = [
+    "//",
+    "//third_party/googletest/googletest/include",
+    "//third_party/libchrome",
+    "//third_party/libevent",
+    "//third_party/libevent/include",
+    "//third_party/libchrome/base",
+    "//third_party/modp_b64",
+  ]
+}
+
+config("libchrome_config") {
+  # libchrome headers need to be able to find themselves.
+  include_dirs = [
+    "//third_party/googletest/googletest/include",
+    "//third_party/libchrome",
+ ]
+}
+
+static_library("base") {
+  deps = [
+    ":base_sources",
+  ]
+
+  cflags = [
+    "-Wno-char-subscripts",
+    "-Wno-missing-field-initializers",
+    "-Wno-unused-function",
+    "-Wno-unused_parameter",
+  ]
+  cflags_cc = [
+    "-Wno-deprecated-register",
+    "-Wno-non-virtual-dtor",
+    "-Wno-sign-promo",
+  ]
+
+  libs = [
+    "-levent",
+    "-levent_core",
+    "-lpthread",
+  ]
+
+  public_configs = [ ":libchrome_config" ]
+}
diff --git a/bt/build/toolchain/clang/BUILD.gn b/bt/build/toolchain/clang/BUILD.gn
new file mode 100644
index 0000000..7035c38
--- /dev/null
+++ b/bt/build/toolchain/clang/BUILD.gn
@@ -0,0 +1,97 @@
+#
+#  Copyright (C) 2016 Android Open Source Project
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+clang = "clang"
+clangxx = "clang++"
+
+toolchain("clang") {
+  tool("cc") {
+    depfile = "{{output}}.d"
+    command = "$clang -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
+    depsformat = "gcc"
+    description = "CC {{output}}"
+    outputs = [
+      "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+    ]
+  }
+
+  tool("cxx") {
+    depfile = "{{output}}.d"
+    command = "$clangxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
+    depsformat = "gcc"
+    description = "CXX {{output}}"
+    outputs = [
+      "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+    ]
+  }
+
+  tool("alink") {
+    rspfile = "{{output}}.rsp"
+    command = "rm -f {{output}} && ar rcs {{output}} @$rspfile"
+    description = "AR {{target_output_name}}{{output_extension}}"
+    rspfile_content = "{{inputs}}"
+    outputs = [
+      "{{target_out_dir}}/{{target_output_name}}{{output_extension}}",
+    ]
+    default_output_extension = ".a"
+
+    output_prefix = "lib"
+  }
+
+  tool("solink") {
+    soname = "{{target_output_name}}{{output_extension}}"  # e.g. "libfoo.so".
+    rspfile = soname + ".rsp"
+
+    command =
+        "$clangxx -shared {{ldflags}} -o $soname -Wl,-soname=$soname @$rspfile"
+    rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}}"
+
+    description = "SOLINK $soname"
+
+    # Use this for {{output_extension}} expansions unless a target manually
+    # overrides it (in which case {{output_extension}} will be what the target
+    # specifies).
+    default_output_extension = ".so"
+
+    outputs = [
+      soname,
+    ]
+    link_output = soname
+    depend_output = soname
+
+    output_prefix = "lib"
+  }
+
+  tool("link") {
+    outfile = "{{target_output_name}}{{output_extension}}"
+    rspfile = "$outfile.rsp"
+    command = "$clangxx {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group {{libs}}"
+    description = "LINK $outfile"
+    rspfile_content = "{{inputs}}"
+    outputs = [
+      outfile,
+    ]
+  }
+
+  tool("stamp") {
+    command = "touch {{output}}"
+    description = "STAMP {{output}}"
+  }
+
+  tool("copy") {
+    command = "cp -af {{source}} {{output}}"
+    description = "COPY {{source}} {{output}}"
+  }
+}
diff --git a/bt/build/toolchain/gcc/BUILD.gn b/bt/build/toolchain/gcc/BUILD.gn
new file mode 100644
index 0000000..888b015
--- /dev/null
+++ b/bt/build/toolchain/gcc/BUILD.gn
@@ -0,0 +1,97 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+cc = "gcc"
+cxx = "g++"
+
+toolchain("gcc") {
+  tool("cc") {
+    depfile = "{{output}}.d"
+    command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
+    depsformat = "gcc"
+    description = "CC {{output}}"
+    outputs = [
+      "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+    ]
+  }
+
+  tool("cxx") {
+    depfile = "{{output}}.d"
+    command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
+    depsformat = "gcc"
+    description = "CXX {{output}}"
+    outputs = [
+      "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+    ]
+  }
+
+  tool("alink") {
+    rspfile = "{{output}}.rsp"
+    command = "rm -f {{output}} && ar rcs {{output}} @$rspfile"
+    description = "AR {{target_output_name}}{{output_extension}}"
+    rspfile_content = "{{inputs}}"
+    outputs = [
+      "{{target_out_dir}}/{{target_output_name}}{{output_extension}}",
+    ]
+    default_output_extension = ".a"
+
+    output_prefix = "lib"
+  }
+
+  tool("solink") {
+    soname = "{{target_output_name}}{{output_extension}}"  # e.g. "libfoo.so".
+    rspfile = soname + ".rsp"
+
+    command =
+        "$cxx -shared {{ldflags}} -o $soname -Wl,-soname=$soname @$rspfile"
+    rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}}"
+
+    description = "SOLINK $soname"
+
+    # Use this for {{output_extension}} expansions unless a target manually
+    # overrides it (in which case {{output_extension}} will be what the target
+    # specifies).
+    default_output_extension = ".so"
+
+    outputs = [
+      soname,
+    ]
+    link_output = soname
+    depend_output = soname
+
+    output_prefix = "lib"
+  }
+
+  tool("link") {
+    outfile = "{{target_output_name}}{{output_extension}}"
+    rspfile = "$outfile.rsp"
+    command = "$cxx {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group {{libs}}"
+    description = "LINK $outfile"
+    rspfile_content = "{{inputs}}"
+    outputs = [
+      outfile,
+    ]
+  }
+
+  tool("stamp") {
+    command = "touch {{output}}"
+    description = "STAMP {{output}}"
+  }
+
+  tool("copy") {
+    command = "cp -af {{source}} {{output}}"
+    description = "COPY {{source}} {{output}}"
+  }
+}
diff --git a/bt/conf/Android.mk b/bt/conf/Android.mk
new file mode 100644
index 0000000..5bc5a63
--- /dev/null
+++ b/bt/conf/Android.mk
@@ -0,0 +1,22 @@
+LOCAL_PATH := $(call my-dir)
+
+# Bluetooth bt_stack.conf config file
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := bt_stack.conf
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/bluetooth
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+
+# Bluetooth bt_did.conf config file
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := bt_did.conf
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/bluetooth
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+
diff --git a/bt/conf/bt_did.conf b/bt/conf/bt_did.conf
new file mode 100644
index 0000000..631cc6d
--- /dev/null
+++ b/bt/conf/bt_did.conf
@@ -0,0 +1,85 @@
+# Device ID (DID) configuration
+[DID1]
+
+# Primary Record - true or false (default)
+# There can be only one primary record
+primaryRecord = true
+
+# Vendor ID '0xFFFF' indicates no Device ID Service Record is present in the device
+# 0x000F = Broadcom Corporation (default)
+#vendorId = 0x000F
+
+# Vendor ID Source
+# 0x0001 = Bluetooth SIG assigned Device ID Vendor ID value (default)
+# 0x0002 = USB Implementer's Forum assigned Device ID Vendor ID value
+#vendorIdSource = 0x0001
+
+# Product ID & Product Version
+# Per spec DID v1.3 0xJJMN for version is interpreted as JJ.M.N
+# JJ: major version number, M: minor version number, N: sub-minor version number
+# For example: 1200, v14.3.6
+productId = 0x1200
+version = 0x1436
+
+# Optional attributes
+#clientExecutableURL =
+#serviceDescription =
+#documentationURL =
+
+#=================================================================================================#
+# Device ID (DID) configuration
+[DID2]
+
+# Primary Record - true or false (default)
+# There can be only one primary record
+#primaryRecord = false
+
+# Vendor ID '0xFFFF' indicates no Device ID Service Record is present in the device
+# 0x000F = Broadcom Corporation (default)
+#vendorId = 0x000F
+
+# Vendor ID Source
+# 0x0001 = Bluetooth SIG assigned Device ID Vendor ID value (default)
+# 0x0002 = USB Implementer's Forum assigned Device ID Vendor ID value
+#vendorIdSource = 0x0001
+
+# Product ID & Product Version
+# Per spec DID v1.3 0xJJMN for version is interpreted as JJ.M.N
+# JJ: major version number, M: minor version number, N: sub-minor version number
+# Default: 0x0000, v00.0.0
+#productId = 0x0000
+#version = 0x0000
+
+# Optional attributes
+#clientExecutableURL =
+#serviceDescription =
+#documentationURL =
+
+#=================================================================================================#
+# Device ID (DID) configuration
+[DID3]
+
+# Primary Record - true or false (default)
+# There can be only one primary record
+#primaryRecord = false
+
+# Vendor ID '0xFFFF' indicates no Device ID Service Record is present in the device
+# 0x000F = Broadcom Corporation (default)
+#vendorId = 0x000F
+
+# Vendor ID Source
+# 0x0001 = Bluetooth SIG assigned Device ID Vendor ID value (default)
+# 0x0002 = USB Implementer's Forum assigned Device ID Vendor ID value
+#vendorIdSource = 0x0001
+
+# Product ID & Product Version
+# Per spec DID v1.3 0xJJMN for version is interpreted as JJ.M.N
+# JJ: major version number, M: minor version number, N: sub-minor version number
+# Default: 0x0000, v00.0.0
+#productId = 0x0000
+#version = 0x0000
+
+# Optional attributes
+#clientExecutableURL =
+#serviceDescription =
+#documentationURL =
diff --git a/bt/conf/bt_stack.conf b/bt/conf/bt_stack.conf
new file mode 100644
index 0000000..41e8ad4
--- /dev/null
+++ b/bt/conf/bt_stack.conf
@@ -0,0 +1,77 @@
+# Enable BtSnoop logging function
+# valid value : true, false
+BtSnoopLogOutput=true
+
+# BtSnoop log output file
+BtSnoopFileName=/data/misc/bluedroid/btsnoop_hci.log
+
+# Preserve existing BtSnoop log before overwriting
+BtSnoopSaveLog=false
+
+# Enable trace level reconfiguration function
+# Must be present before any TRC_ trace level settings
+TraceConf=true
+
+# Trace level configuration
+#   BT_TRACE_LEVEL_NONE    0    ( No trace messages to be generated )
+#   BT_TRACE_LEVEL_ERROR   1    ( Error condition trace messages )
+#   BT_TRACE_LEVEL_WARNING 2    ( Warning condition trace messages )
+#   BT_TRACE_LEVEL_API     3    ( API traces )
+#   BT_TRACE_LEVEL_EVENT   4    ( Debug messages for events )
+#   BT_TRACE_LEVEL_DEBUG   5    ( Full debug messages )
+#   BT_TRACE_LEVEL_VERBOSE 6    ( Verbose messages ) - Currently supported for TRC_BTAPP only.
+TRC_BTM=2
+TRC_HCI=2
+TRC_L2CAP=2
+TRC_RFCOMM=2
+TRC_OBEX=2
+TRC_AVCT=2
+TRC_AVDT=2
+TRC_AVRC=2
+TRC_AVDT_SCB=2
+TRC_AVDT_CCB=2
+TRC_A2D=2
+TRC_SDP=2
+TRC_GATT=2
+TRC_SMP=2
+TRC_BTAPP=2
+TRC_BTIF=2
+TRC_GAP=2
+TRC_BNEP=2
+TRC_PAN=2
+
+# This is Log configuration for new C++ code using LOG() macros.
+# See libchrome/base/logging.h for description on how to configure your logs.
+# sample configuration:
+#LoggingV=--v=0
+#LoggingVModule=--vmodule=*/btm/*=1,btm_ble_multi*=2,btif_*=1
+
+# PTS testing helpers
+
+# Secure connections only mode.
+# PTS_SecurePairOnly=true
+
+# Disable LE Connection updates
+#PTS_DisableConnUpdates=true
+
+# Disable BR/EDR discovery after LE pairing to avoid cross key derivation errors
+#PTS_DisableSDPOnLEPair=true
+
+# SMP Pair options (formatted as hex bytes) auth, io, ikey, rkey, ksize
+#PTS_SmpOptions=0xD,0x4,0xf,0xf,0x10
+
+# SMP Certification Failure Cases
+# Fail case number range from 1 to 9 will set up remote device for test
+# case execution. Setting PTS_SmpFailureCase to 0 means normal operation.
+# Failure modes:
+#  1 = SMP_CONFIRM_VALUE_ERR
+#  2 = SMP_PAIR_AUTH_FAIL
+#  3 = SMP_PAIR_FAIL_UNKNOWN
+#  4 = SMP_PAIR_NOT_SUPPORT
+#  5 = SMP_PASSKEY_ENTRY_FAIL
+#  6 = SMP_REPEATED_ATTEMPTS
+#  7 = PIN generation failure?
+#  8 = SMP_PASSKEY_ENTRY_FAIL
+#  9 = SMP_NUMERIC_COMPAR_FAIL;
+#PTS_SmpFailureCase=0
+
diff --git a/bt/device/Android.mk b/bt/device/Android.mk
new file mode 100644
index 0000000..c66df8b
--- /dev/null
+++ b/bt/device/Android.mk
@@ -0,0 +1,71 @@
+ ##############################################################################
+ #
+ #  Copyright (C) 2014 Google, Inc.
+ #
+ #  Licensed under the Apache License, Version 2.0 (the "License");
+ #  you may not use this file except in compliance with the License.
+ #  You may obtain a copy of the License at:
+ #
+ #  http://www.apache.org/licenses/LICENSE-2.0
+ #
+ #  Unless required by applicable law or agreed to in writing, software
+ #  distributed under the License is distributed on an "AS IS" BASIS,
+ #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ #  See the License for the specific language governing permissions and
+ #  limitations under the License.
+ #
+ ##############################################################################
+
+LOCAL_PATH := $(call my-dir)
+
+# Bluetooth device static library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH)/.. \
+    $(LOCAL_PATH)/include \
+    $(LOCAL_PATH)/../btcore/include \
+    $(LOCAL_PATH)/../hci/include \
+    $(LOCAL_PATH)/../include \
+    $(LOCAL_PATH)/../stack/include \
+    $(bluetooth_C_INCLUDES)
+
+LOCAL_SRC_FILES := \
+    src/controller.cc \
+    src/interop.cc
+
+LOCAL_MODULE := libbtdevice
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES := libc liblog
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_STATIC_LIBRARY)
+
+# Bluetooth device unit tests for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH)/.. \
+    $(bluetooth_C_INCLUDES)
+
+LOCAL_SRC_FILES := \
+    ../osi/test/AllocationTestHarness.cc \
+    ./test/interop_test.cc
+
+LOCAL_MODULE := net_test_device
+LOCAL_MODULE_TAGS := tests
+LOCAL_SHARED_LIBRARIES := liblog libdl
+LOCAL_STATIC_LIBRARIES := libbtdevice libbtcore libosi libcutils
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_NATIVE_TEST)
diff --git a/bt/device/BUILD.gn b/bt/device/BUILD.gn
new file mode 100644
index 0000000..ffaa10d
--- /dev/null
+++ b/bt/device/BUILD.gn
@@ -0,0 +1,52 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+static_library("device") {
+  sources = [
+    "src/controller.cc",
+    "src/interop.cc",
+  ]
+
+  include_dirs = [
+    "//",
+    "//btcore/include",
+    "//hci/include",
+    "//include",
+    "//stack/include",
+  ]
+}
+
+executable("net_test_device") {
+  testonly = true
+  sources = [
+    "//osi/test/AllocationTestHarness.cc",
+  ]
+
+  include_dirs = [ "//" ]
+
+  deps = [
+    "//device",
+    "//btcore",
+    "//osi",
+    "//third_party/googletest:gtest_main",
+  ]
+
+  libs = [
+    "-lpthread",
+    "-lrt",
+    "-ldl",
+  ]
+}
diff --git a/bt/device/include/controller.h b/bt/device/include/controller.h
new file mode 100644
index 0000000..62e9029
--- /dev/null
+++ b/bt/device/include/controller.h
@@ -0,0 +1,94 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+#include <stdint.h>
+
+#include "bdaddr.h"
+#include "device_features.h"
+#include "hci_layer.h"
+#include "hci_packet_factory.h"
+#include "hci_packet_parser.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static const char CONTROLLER_MODULE[] = "controller_module";
+
+typedef struct controller_t {
+  bool (*get_is_ready)(void);
+
+  const bt_bdaddr_t* (*get_address)(void);
+  const bt_version_t* (*get_bt_version)(void);
+
+  const bt_device_features_t* (*get_features_classic)(int index);
+  uint8_t (*get_last_features_classic_index)(void);
+
+  const bt_device_features_t* (*get_features_ble)(void);
+  const uint8_t* (*get_ble_supported_states)(void);
+
+  bool (*supports_simple_pairing)(void);
+  bool (*supports_secure_connections)(void);
+  bool (*supports_simultaneous_le_bredr)(void);
+  bool (*supports_reading_remote_extended_features)(void);
+  bool (*supports_interlaced_inquiry_scan)(void);
+  bool (*supports_rssi_with_inquiry_results)(void);
+  bool (*supports_extended_inquiry_response)(void);
+  bool (*supports_master_slave_role_switch)(void);
+
+  bool (*supports_ble)(void);
+  bool (*supports_ble_packet_extension)(void);
+  bool (*supports_ble_connection_parameters_request)(void);
+  bool (*supports_ble_privacy)(void);
+
+  // Get the cached acl data sizes for the controller.
+  uint16_t (*get_acl_data_size_classic)(void);
+  uint16_t (*get_acl_data_size_ble)(void);
+
+  // Get the cached acl packet sizes for the controller.
+  // This is a convenience function for the respective
+  // acl data size + size of the acl header.
+  uint16_t (*get_acl_packet_size_classic)(void);
+  uint16_t (*get_acl_packet_size_ble)(void);
+
+  uint16_t (*get_ble_default_data_packet_length)(void);
+
+  // Get the number of acl packets the controller can buffer.
+  uint16_t (*get_acl_buffer_count_classic)(void);
+  uint8_t (*get_acl_buffer_count_ble)(void);
+
+  uint8_t (*get_ble_white_list_size)(void);
+
+  uint8_t (*get_ble_resolving_list_max_size)(void);
+  void (*set_ble_resolving_list_max_size)(int resolving_list_max_size);
+  uint8_t* (*get_local_supported_codecs)(uint8_t* number_of_codecs);
+} controller_t;
+
+const controller_t* controller_get_interface();
+
+const controller_t* controller_get_test_interface(
+    const hci_t* hci_interface,
+    const hci_packet_factory_t* packet_factory_interface,
+    const hci_packet_parser_t* packet_parser_interface);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/device/include/interop.h b/bt/device/include/interop.h
new file mode 100644
index 0000000..d7ff6d9
--- /dev/null
+++ b/bt/device/include/interop.h
@@ -0,0 +1,104 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+
+#include "btcore/include/bdaddr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static const char INTEROP_MODULE[] = "interop_module";
+
+// NOTE:
+// Only add values at the end of this enum and do NOT delete values
+// as they may be used in dynamic device configuration.
+typedef enum {
+  // Disable secure connections
+  // This is for pre BT 4.1/2 devices that do not handle secure mode
+  // very well.
+  INTEROP_DISABLE_LE_SECURE_CONNECTIONS = 0,
+
+  // Some devices have proven problematic during the pairing process, often
+  // requiring multiple retries to complete pairing. To avoid degrading the user
+  // experience for those devices, automatically re-try pairing if page
+  // timeouts are received during pairing.
+  INTEROP_AUTO_RETRY_PAIRING,
+
+  // Devices requiring this workaround do not handle Bluetooth Absolute Volume
+  // control correctly, leading to undesirable (potentially harmful) volume
+  // levels or general lack of controlability.
+  INTEROP_DISABLE_ABSOLUTE_VOLUME,
+
+  // Disable automatic pairing with headsets/car-kits
+  // Some car kits do not react kindly to a failed pairing attempt and
+  // do not allow immediate re-pairing. Blacklist these so that the initial
+  // pairing attempt makes it to the user instead.
+  INTEROP_DISABLE_AUTO_PAIRING,
+
+  // Use a fixed pin for specific keyboards
+  // Keyboards should use a variable pin at all times. However, some keyboards
+  // require a fixed pin of all 0000. This workaround enables auto pairing for
+  // those keyboards.
+  INTEROP_KEYBOARD_REQUIRES_FIXED_PIN,
+
+  // Some headsets have audio jitter issues because of increased
+  // re-transmissions as the 3 Mbps packets have a lower link margin, and are
+  // more prone to interference. We can disable 3DH packets (use only 2DH
+  // packets) for the ACL link to improve sensitivity when streaming A2DP audio
+  // to the headset. Air sniffer logs show reduced re-transmissions after
+  // switching to 2DH packets.
+
+  // Disable 3Mbps packets and use only 2Mbps packets for ACL links when
+  // streaming audio.
+  INTEROP_2MBPS_LINK_ONLY
+} interop_feature_t;
+
+// Check if a given |addr| matches a known interoperability workaround as
+// identified by the |interop_feature_t| enum. This API is used for simple
+// address based lookups where more information is not available. No
+// look-ups or random address resolution are performed on |addr|.
+bool interop_match_addr(const interop_feature_t feature,
+                        const bt_bdaddr_t* addr);
+
+// Check if a given remote device |name| matches a known workaround.
+// Name comparisons are case sensitive and do not allow for partial matches.
+// If |name| is "TEST" and a workaround exists for "TESTING", then this function
+// will return false. But, if |name| is "TESTING" and a workaround exists for
+// "TEST", this function will return true.
+// |name| cannot be null and must be null terminated.
+bool interop_match_name(const interop_feature_t feature, const char* name);
+
+// Add a dynamic interop database entry for a device matching the first |length|
+// bytes of |addr|, implementing the workaround identified by |feature|.
+// |addr| may not be null.
+// |length| must be greater than 0 and less than sizeof(bt_bdaddr_t).
+// As |interop_feature_t| is not exposed in the public API, feature must be a
+// valid integer representing an option in the enum.
+void interop_database_add(const uint16_t feature, const bt_bdaddr_t* addr,
+                          size_t length);
+
+// Clear the dynamic portion of the interoperability workaround database.
+void interop_database_clear(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/device/include/interop_database.h b/bt/device/include/interop_database.h
new file mode 100644
index 0000000..41d88ab
--- /dev/null
+++ b/bt/device/include/interop_database.h
@@ -0,0 +1,121 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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/interop.h"
+
+typedef struct {
+  bt_bdaddr_t addr;
+  size_t length;
+  interop_feature_t feature;
+} interop_addr_entry_t;
+
+static const interop_addr_entry_t interop_addr_database[] = {
+    // Nexus Remote (Spike)
+    // Note: May affect other Asus brand devices
+    {{{0x08, 0x62, 0x66, 0, 0, 0}}, 3, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+    {{{0x38, 0x2c, 0x4a, 0xc9, 0, 0}},
+     4,
+     INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+    {{{0x38, 0x2c, 0x4a, 0xe6, 0, 0}},
+     4,
+     INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+    {{{0x54, 0xa0, 0x50, 0xd9, 0, 0}},
+     4,
+     INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+    {{{0xac, 0x9e, 0x17, 0, 0, 0}}, 3, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+    {{{0xf0, 0x79, 0x59, 0, 0, 0}}, 3, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+
+    // Ausdom M05 - unacceptably loud volume
+    {{{0xa0, 0xe9, 0xdb, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+    // BMW car kits (Harman/Becker)
+    {{{0x9c, 0xdf, 0x03, 0, 0, 0}}, 3, INTEROP_AUTO_RETRY_PAIRING},
+
+    // Flic smart button
+    {{{0x80, 0xe4, 0xda, 0x70, 0, 0}},
+     4,
+     INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+
+    // iKross IKBT83B HS - unacceptably loud volume
+    {{{0x00, 0x14, 0x02, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+    // JayBird BlueBuds X - low granularity on volume control
+    {{{0x44, 0x5e, 0xf3, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+    {{{0xd4, 0x9c, 0x28, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+    // JayBird Family
+    {{{0x00, 0x18, 0x91, 0, 0, 0}}, 3, INTEROP_2MBPS_LINK_ONLY},
+
+    // LG Tone HBS-730 - unacceptably loud volume
+    {{{0x00, 0x18, 0x6b, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+    {{{0xb8, 0xad, 0x3e, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+    // LG Tone HV-800 - unacceptably loud volume
+    {{{0xa0, 0xe9, 0xdb, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+    // Motorola Key Link
+    {{{0x1c, 0x96, 0x5a, 0, 0, 0}}, 3, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+
+    // Motorola Roadster
+    {{{0x00, 0x24, 0x1C, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+    // Mpow Cheetah - unacceptably loud volume
+    {{{0x00, 0x11, 0xb1, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+    // Nissan car kits (ALPS) - auto-pairing fails and rejects next pairing
+    {{{0x34, 0xc7, 0x31, 0, 0, 0}}, 3, INTEROP_DISABLE_AUTO_PAIRING},
+
+    // SOL REPUBLIC Tracks Air - unable to adjust volume back off from max
+    {{{0xa4, 0x15, 0x66, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+    // Subaru car kits (ALPS) - auto-pairing fails and rejects next pairing
+    {{{0x00, 0x07, 0x04, 0, 0, 0}}, 3, INTEROP_DISABLE_AUTO_PAIRING},
+    {{{0xe0, 0x75, 0x0a, 0, 0, 0}}, 3, INTEROP_DISABLE_AUTO_PAIRING},
+
+    // Swage Rokitboost HS - unacceptably loud volume
+    {{{0x00, 0x14, 0xf1, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+    // VW Car Kit - not enough granularity with volume
+    {{{0x00, 0x26, 0x7e, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+    {{{0x90, 0x03, 0xb7, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+    // Unknown keyboard (carried over from auto_pair_devlist.conf)
+    {{{0x00, 0x0F, 0xF6, 0, 0, 0}}, 3, INTEROP_KEYBOARD_REQUIRES_FIXED_PIN},
+};
+
+typedef struct {
+  char name[20];
+  size_t length;
+  interop_feature_t feature;
+} interop_name_entry_t;
+
+static const interop_name_entry_t interop_name_database[] = {
+    // Carried over from auto_pair_devlist.conf migration
+    {"Audi", 4, INTEROP_DISABLE_AUTO_PAIRING},
+    {"BMW", 3, INTEROP_DISABLE_AUTO_PAIRING},
+    {"Parrot", 6, INTEROP_DISABLE_AUTO_PAIRING},
+    {"Car", 3, INTEROP_DISABLE_AUTO_PAIRING},
+
+    // Nissan Quest rejects pairing after "0000"
+    {"NISSAN", 6, INTEROP_DISABLE_AUTO_PAIRING},
+
+    // Subaru car kits ("CAR M_MEDIA")
+    {"CAR", 3, INTEROP_DISABLE_AUTO_PAIRING},
+};
diff --git a/bt/device/src/controller.cc b/bt/device/src/controller.cc
new file mode 100644
index 0000000..0304593
--- /dev/null
+++ b/bt/device/src/controller.cc
@@ -0,0 +1,497 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_controller"
+
+#include "device/include/controller.h"
+
+#include <assert.h>
+
+#include "bt_types.h"
+#include "btcore/include/event_mask.h"
+#include "btcore/include/module.h"
+#include "btcore/include/version.h"
+#include "hcimsgs.h"
+#include "osi/include/future.h"
+#include "stack/include/btm_ble_api.h"
+
+const bt_event_mask_t BLE_EVENT_MASK = {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x7f}};
+
+#if (BLE_INCLUDED)
+const bt_event_mask_t CLASSIC_EVENT_MASK = {HCI_DUMO_EVENT_MASK_EXT};
+#else
+const bt_event_mask_t CLASSIC_EVENT_MASK = {HCI_LISBON_EVENT_MASK_EXT};
+#endif
+
+// TODO(zachoverflow): factor out into common module
+const uint8_t SCO_HOST_BUFFER_SIZE = 0xff;
+
+#define HCI_SUPPORTED_COMMANDS_ARRAY_SIZE 64
+#define MAX_FEATURES_CLASSIC_PAGE_COUNT 3
+#define BLE_SUPPORTED_STATES_SIZE 8
+#define BLE_SUPPORTED_FEATURES_SIZE 8
+#define MAX_LOCAL_SUPPORTED_CODECS_SIZE 8
+
+static const hci_t* hci;
+static const hci_packet_factory_t* packet_factory;
+static const hci_packet_parser_t* packet_parser;
+
+static bt_bdaddr_t address;
+static bt_version_t bt_version;
+
+static uint8_t supported_commands[HCI_SUPPORTED_COMMANDS_ARRAY_SIZE];
+static bt_device_features_t features_classic[MAX_FEATURES_CLASSIC_PAGE_COUNT];
+static uint8_t last_features_classic_page_index;
+
+static uint16_t acl_data_size_classic;
+static uint16_t acl_data_size_ble;
+static uint16_t acl_buffer_count_classic;
+static uint8_t acl_buffer_count_ble;
+
+static uint8_t ble_white_list_size;
+static uint8_t ble_resolving_list_max_size;
+static uint8_t ble_supported_states[BLE_SUPPORTED_STATES_SIZE];
+static bt_device_features_t features_ble;
+static uint16_t ble_suggested_default_data_length;
+static uint8_t local_supported_codecs[MAX_LOCAL_SUPPORTED_CODECS_SIZE];
+static uint8_t number_of_local_supported_codecs = 0;
+
+static bool readable;
+static bool ble_supported;
+static bool simple_pairing_supported;
+static bool secure_connections_supported;
+
+#define AWAIT_COMMAND(command) \
+  static_cast<BT_HDR*>(future_await(hci->transmit_command_futured(command)))
+
+// Module lifecycle functions
+
+static future_t* start_up(void) {
+  BT_HDR* response;
+
+  // Send the initial reset command
+  response = AWAIT_COMMAND(packet_factory->make_reset());
+  packet_parser->parse_generic_command_complete(response);
+
+  // Request the classic buffer size next
+  response = AWAIT_COMMAND(packet_factory->make_read_buffer_size());
+  packet_parser->parse_read_buffer_size_response(
+      response, &acl_data_size_classic, &acl_buffer_count_classic);
+
+  // Tell the controller about our buffer sizes and buffer counts next
+  // TODO(zachoverflow): factor this out. eww l2cap contamination. And why just
+  // a hardcoded 10?
+  response = AWAIT_COMMAND(packet_factory->make_host_buffer_size(
+      L2CAP_MTU_SIZE, SCO_HOST_BUFFER_SIZE, L2CAP_HOST_FC_ACL_BUFS, 10));
+
+  packet_parser->parse_generic_command_complete(response);
+
+  // Read the local version info off the controller next, including
+  // information such as manufacturer and supported HCI version
+  response = AWAIT_COMMAND(packet_factory->make_read_local_version_info());
+  packet_parser->parse_read_local_version_info_response(response, &bt_version);
+
+  // Read the bluetooth address off the controller next
+  response = AWAIT_COMMAND(packet_factory->make_read_bd_addr());
+  packet_parser->parse_read_bd_addr_response(response, &address);
+
+  // Request the controller's supported commands next
+  response =
+      AWAIT_COMMAND(packet_factory->make_read_local_supported_commands());
+  packet_parser->parse_read_local_supported_commands_response(
+      response, supported_commands, HCI_SUPPORTED_COMMANDS_ARRAY_SIZE);
+
+  // Read page 0 of the controller features next
+  uint8_t page_number = 0;
+  response = AWAIT_COMMAND(
+      packet_factory->make_read_local_extended_features(page_number));
+  packet_parser->parse_read_local_extended_features_response(
+      response, &page_number, &last_features_classic_page_index,
+      features_classic, MAX_FEATURES_CLASSIC_PAGE_COUNT);
+
+  assert(page_number == 0);
+  page_number++;
+
+  // Inform the controller what page 0 features we support, based on what
+  // it told us it supports. We need to do this first before we request the
+  // next page, because the controller's response for page 1 may be
+  // dependent on what we configure from page 0
+  simple_pairing_supported =
+      HCI_SIMPLE_PAIRING_SUPPORTED(features_classic[0].as_array);
+  if (simple_pairing_supported) {
+    response = AWAIT_COMMAND(
+        packet_factory->make_write_simple_pairing_mode(HCI_SP_MODE_ENABLED));
+    packet_parser->parse_generic_command_complete(response);
+  }
+
+#if (BLE_INCLUDED == TRUE)
+  if (HCI_LE_SPT_SUPPORTED(features_classic[0].as_array)) {
+    uint8_t simultaneous_le_host =
+        HCI_SIMUL_LE_BREDR_SUPPORTED(features_classic[0].as_array)
+            ? BTM_BLE_SIMULTANEOUS_HOST
+            : 0;
+    response = AWAIT_COMMAND(packet_factory->make_ble_write_host_support(
+        BTM_BLE_HOST_SUPPORT, simultaneous_le_host));
+
+    packet_parser->parse_generic_command_complete(response);
+
+    // If we modified the BT_HOST_SUPPORT, we will need ext. feat. page 1
+    if (last_features_classic_page_index < 1)
+      last_features_classic_page_index = 1;
+  }
+#endif
+
+  // Done telling the controller about what page 0 features we support
+  // Request the remaining feature pages
+  while (page_number <= last_features_classic_page_index &&
+         page_number < MAX_FEATURES_CLASSIC_PAGE_COUNT) {
+    response = AWAIT_COMMAND(
+        packet_factory->make_read_local_extended_features(page_number));
+    packet_parser->parse_read_local_extended_features_response(
+        response, &page_number, &last_features_classic_page_index,
+        features_classic, MAX_FEATURES_CLASSIC_PAGE_COUNT);
+
+    page_number++;
+  }
+
+#if (SC_MODE_INCLUDED == TRUE)
+  secure_connections_supported =
+      HCI_SC_CTRLR_SUPPORTED(features_classic[2].as_array);
+  if (secure_connections_supported) {
+    response = AWAIT_COMMAND(
+        packet_factory->make_write_secure_connections_host_support(
+            HCI_SC_MODE_ENABLED));
+    packet_parser->parse_generic_command_complete(response);
+  }
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+  ble_supported = last_features_classic_page_index >= 1 &&
+                  HCI_LE_HOST_SUPPORTED(features_classic[1].as_array);
+  if (ble_supported) {
+    // Request the ble white list size next
+    response = AWAIT_COMMAND(packet_factory->make_ble_read_white_list_size());
+    packet_parser->parse_ble_read_white_list_size_response(
+        response, &ble_white_list_size);
+
+    // Request the ble buffer size next
+    response = AWAIT_COMMAND(packet_factory->make_ble_read_buffer_size());
+    packet_parser->parse_ble_read_buffer_size_response(
+        response, &acl_data_size_ble, &acl_buffer_count_ble);
+
+    // Response of 0 indicates ble has the same buffer size as classic
+    if (acl_data_size_ble == 0) acl_data_size_ble = acl_data_size_classic;
+
+    // Request the ble supported states next
+    response = AWAIT_COMMAND(packet_factory->make_ble_read_supported_states());
+    packet_parser->parse_ble_read_supported_states_response(
+        response, ble_supported_states, sizeof(ble_supported_states));
+
+    // Request the ble supported features next
+    response =
+        AWAIT_COMMAND(packet_factory->make_ble_read_local_supported_features());
+    packet_parser->parse_ble_read_local_supported_features_response(
+        response, &features_ble);
+
+    if (HCI_LE_ENHANCED_PRIVACY_SUPPORTED(features_ble.as_array)) {
+      response =
+          AWAIT_COMMAND(packet_factory->make_ble_read_resolving_list_size());
+      packet_parser->parse_ble_read_resolving_list_size_response(
+          response, &ble_resolving_list_max_size);
+    }
+
+    if (HCI_LE_DATA_LEN_EXT_SUPPORTED(features_ble.as_array)) {
+      response = AWAIT_COMMAND(
+          packet_factory->make_ble_read_suggested_default_data_length());
+      packet_parser->parse_ble_read_suggested_default_data_length_response(
+          response, &ble_suggested_default_data_length);
+    }
+
+    // Set the ble event mask next
+    response =
+        AWAIT_COMMAND(packet_factory->make_ble_set_event_mask(&BLE_EVENT_MASK));
+    packet_parser->parse_generic_command_complete(response);
+  }
+#endif
+
+  if (simple_pairing_supported) {
+    response =
+        AWAIT_COMMAND(packet_factory->make_set_event_mask(&CLASSIC_EVENT_MASK));
+    packet_parser->parse_generic_command_complete(response);
+  }
+
+  // read local supported codecs
+  if (HCI_READ_LOCAL_CODECS_SUPPORTED(supported_commands)) {
+    response =
+        AWAIT_COMMAND(packet_factory->make_read_local_supported_codecs());
+    packet_parser->parse_read_local_supported_codecs_response(
+        response, &number_of_local_supported_codecs, local_supported_codecs);
+  }
+
+  readable = true;
+  return future_new_immediate(FUTURE_SUCCESS);
+}
+
+static future_t* shut_down(void) {
+  readable = false;
+  return future_new_immediate(FUTURE_SUCCESS);
+}
+
+EXPORT_SYMBOL extern const module_t controller_module = {
+    .name = CONTROLLER_MODULE,
+    .init = NULL,
+    .start_up = start_up,
+    .shut_down = shut_down,
+    .clean_up = NULL,
+    .dependencies = {HCI_MODULE, NULL}};
+
+// Interface functions
+
+static bool get_is_ready(void) { return readable; }
+
+static const bt_bdaddr_t* get_address(void) {
+  assert(readable);
+  return &address;
+}
+
+static const bt_version_t* get_bt_version(void) {
+  assert(readable);
+  return &bt_version;
+}
+
+// TODO(zachoverflow): hide inside, move decoder inside too
+static const bt_device_features_t* get_features_classic(int index) {
+  assert(readable);
+  assert(index < MAX_FEATURES_CLASSIC_PAGE_COUNT);
+  return &features_classic[index];
+}
+
+static uint8_t get_last_features_classic_index(void) {
+  assert(readable);
+  return last_features_classic_page_index;
+}
+
+static uint8_t* get_local_supported_codecs(uint8_t* number_of_codecs) {
+  assert(readable);
+  if (number_of_local_supported_codecs) {
+    *number_of_codecs = number_of_local_supported_codecs;
+    return local_supported_codecs;
+  }
+  return NULL;
+}
+
+static const bt_device_features_t* get_features_ble(void) {
+  assert(readable);
+  assert(ble_supported);
+  return &features_ble;
+}
+
+static const uint8_t* get_ble_supported_states(void) {
+  assert(readable);
+  assert(ble_supported);
+  return ble_supported_states;
+}
+
+static bool supports_simple_pairing(void) {
+  assert(readable);
+  return simple_pairing_supported;
+}
+
+static bool supports_secure_connections(void) {
+  assert(readable);
+  return secure_connections_supported;
+}
+
+static bool supports_simultaneous_le_bredr(void) {
+  assert(readable);
+  return HCI_SIMUL_LE_BREDR_SUPPORTED(features_classic[0].as_array);
+}
+
+static bool supports_reading_remote_extended_features(void) {
+  assert(readable);
+  return HCI_READ_REMOTE_EXT_FEATURES_SUPPORTED(supported_commands);
+}
+
+static bool supports_interlaced_inquiry_scan(void) {
+  assert(readable);
+  return HCI_LMP_INTERLACED_INQ_SCAN_SUPPORTED(features_classic[0].as_array);
+}
+
+static bool supports_rssi_with_inquiry_results(void) {
+  assert(readable);
+  return HCI_LMP_INQ_RSSI_SUPPORTED(features_classic[0].as_array);
+}
+
+static bool supports_extended_inquiry_response(void) {
+  assert(readable);
+  return HCI_EXT_INQ_RSP_SUPPORTED(features_classic[0].as_array);
+}
+
+static bool supports_master_slave_role_switch(void) {
+  assert(readable);
+  return HCI_SWITCH_SUPPORTED(features_classic[0].as_array);
+}
+
+static bool supports_ble(void) {
+  assert(readable);
+  return ble_supported;
+}
+
+static bool supports_ble_privacy(void) {
+  assert(readable);
+  assert(ble_supported);
+  return HCI_LE_ENHANCED_PRIVACY_SUPPORTED(features_ble.as_array);
+}
+
+static bool supports_ble_packet_extension(void) {
+  assert(readable);
+  assert(ble_supported);
+  return HCI_LE_DATA_LEN_EXT_SUPPORTED(features_ble.as_array);
+}
+
+static bool supports_ble_connection_parameters_request(void) {
+  assert(readable);
+  assert(ble_supported);
+  return HCI_LE_CONN_PARAM_REQ_SUPPORTED(features_ble.as_array);
+}
+
+static uint16_t get_acl_data_size_classic(void) {
+  assert(readable);
+  return acl_data_size_classic;
+}
+
+static uint16_t get_acl_data_size_ble(void) {
+  assert(readable);
+  assert(ble_supported);
+  return acl_data_size_ble;
+}
+
+static uint16_t get_acl_packet_size_classic(void) {
+  assert(readable);
+  return acl_data_size_classic + HCI_DATA_PREAMBLE_SIZE;
+}
+
+static uint16_t get_acl_packet_size_ble(void) {
+  assert(readable);
+  return acl_data_size_ble + HCI_DATA_PREAMBLE_SIZE;
+}
+
+static uint16_t get_ble_suggested_default_data_length(void) {
+  assert(readable);
+  assert(ble_supported);
+  return ble_suggested_default_data_length;
+}
+
+static uint16_t get_acl_buffer_count_classic(void) {
+  assert(readable);
+  return acl_buffer_count_classic;
+}
+
+static uint8_t get_acl_buffer_count_ble(void) {
+  assert(readable);
+  assert(ble_supported);
+  return acl_buffer_count_ble;
+}
+
+static uint8_t get_ble_white_list_size(void) {
+  assert(readable);
+  assert(ble_supported);
+  return ble_white_list_size;
+}
+
+static uint8_t get_ble_resolving_list_max_size(void) {
+  assert(readable);
+  assert(ble_supported);
+  return ble_resolving_list_max_size;
+}
+
+static void set_ble_resolving_list_max_size(int resolving_list_max_size) {
+  // Setting "resolving_list_max_size" to 0 is done during cleanup,
+  // hence we ignore the "readable" flag already set to false during shutdown.
+  if (resolving_list_max_size != 0) {
+    assert(readable);
+  }
+  assert(ble_supported);
+  ble_resolving_list_max_size = resolving_list_max_size;
+}
+
+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_ble,
+    supports_ble_packet_extension,
+    supports_ble_connection_parameters_request,
+    supports_ble_privacy,
+
+    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_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};
+
+const controller_t* controller_get_interface() {
+  static bool loaded = false;
+  if (!loaded) {
+    loaded = true;
+
+    hci = hci_layer_get_interface();
+    packet_factory = hci_packet_factory_get_interface();
+    packet_parser = hci_packet_parser_get_interface();
+  }
+
+  return &interface;
+}
+
+const controller_t* controller_get_test_interface(
+    const hci_t* hci_interface,
+    const hci_packet_factory_t* packet_factory_interface,
+    const hci_packet_parser_t* packet_parser_interface) {
+  hci = hci_interface;
+  packet_factory = packet_factory_interface;
+  packet_parser = packet_parser_interface;
+  return &interface;
+}
diff --git a/bt/device/src/interop.cc b/bt/device/src/interop.cc
new file mode 100644
index 0000000..a384d4d
--- /dev/null
+++ b/bt/device/src/interop.cc
@@ -0,0 +1,177 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_device_interop"
+
+#include <assert.h>
+#include <string.h>  // For memcmp
+
+#include "btcore/include/module.h"
+#include "device/include/interop.h"
+#include "device/include/interop_database.h"
+#include "osi/include/allocator.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+
+#define CASE_RETURN_STR(const) \
+  case const:                  \
+    return #const;
+
+static list_t* interop_list = NULL;
+
+static const char* interop_feature_string_(const interop_feature_t feature);
+static void interop_free_entry_(void* data);
+static void interop_lazy_init_(void);
+static bool interop_match_fixed_(const interop_feature_t feature,
+                                 const bt_bdaddr_t* addr);
+static bool interop_match_dynamic_(const interop_feature_t feature,
+                                   const bt_bdaddr_t* addr);
+
+// Interface functions
+
+bool interop_match_addr(const interop_feature_t feature,
+                        const bt_bdaddr_t* addr) {
+  assert(addr);
+
+  if (interop_match_fixed_(feature, addr) ||
+      interop_match_dynamic_(feature, addr)) {
+    char bdstr[20] = {0};
+    LOG_WARN(LOG_TAG, "%s() Device %s is a match for interop workaround %s.",
+             __func__, bdaddr_to_string(addr, bdstr, sizeof(bdstr)),
+             interop_feature_string_(feature));
+    return true;
+  }
+
+  return false;
+}
+
+bool interop_match_name(const interop_feature_t feature, const char* name) {
+  assert(name);
+
+  const size_t db_size =
+      sizeof(interop_name_database) / sizeof(interop_name_entry_t);
+  for (size_t i = 0; i != db_size; ++i) {
+    if (feature == interop_name_database[i].feature &&
+        strlen(name) >= interop_name_database[i].length &&
+        strncmp(name, interop_name_database[i].name,
+                interop_name_database[i].length) == 0) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+void interop_database_add(const uint16_t feature, const bt_bdaddr_t* addr,
+                          size_t length) {
+  assert(addr);
+  assert(length > 0);
+  assert(length < sizeof(bt_bdaddr_t));
+
+  interop_addr_entry_t* entry = static_cast<interop_addr_entry_t*>(
+      osi_calloc(sizeof(interop_addr_entry_t)));
+  memcpy(&entry->addr, addr, length);
+  entry->feature = static_cast<interop_feature_t>(feature);
+  entry->length = length;
+
+  interop_lazy_init_();
+  list_append(interop_list, entry);
+}
+
+void interop_database_clear() {
+  if (interop_list) list_clear(interop_list);
+}
+
+// Module life-cycle functions
+
+static future_t* interop_clean_up(void) {
+  list_free(interop_list);
+  interop_list = NULL;
+  return future_new_immediate(FUTURE_SUCCESS);
+}
+
+EXPORT_SYMBOL module_t interop_module = {
+    .name = INTEROP_MODULE,
+    .init = NULL,
+    .start_up = NULL,
+    .shut_down = NULL,
+    .clean_up = interop_clean_up,
+    .dependencies = {NULL},
+};
+
+// Local functions
+
+static const char* interop_feature_string_(const interop_feature_t feature) {
+  switch (feature) {
+    CASE_RETURN_STR(INTEROP_DISABLE_LE_SECURE_CONNECTIONS)
+    CASE_RETURN_STR(INTEROP_AUTO_RETRY_PAIRING)
+    CASE_RETURN_STR(INTEROP_DISABLE_ABSOLUTE_VOLUME)
+    CASE_RETURN_STR(INTEROP_DISABLE_AUTO_PAIRING)
+    CASE_RETURN_STR(INTEROP_KEYBOARD_REQUIRES_FIXED_PIN)
+    CASE_RETURN_STR(INTEROP_2MBPS_LINK_ONLY)
+  }
+
+  return "UNKNOWN";
+}
+
+static void interop_free_entry_(void* data) {
+  interop_addr_entry_t* entry = (interop_addr_entry_t*)data;
+  osi_free(entry);
+}
+
+static void interop_lazy_init_(void) {
+  if (interop_list == NULL) {
+    interop_list = list_new(interop_free_entry_);
+  }
+}
+
+static bool interop_match_dynamic_(const interop_feature_t feature,
+                                   const bt_bdaddr_t* addr) {
+  if (interop_list == NULL || list_length(interop_list) == 0) return false;
+
+  const list_node_t* node = list_begin(interop_list);
+  while (node != list_end(interop_list)) {
+    interop_addr_entry_t* entry =
+        static_cast<interop_addr_entry_t*>(list_node(node));
+    assert(entry);
+
+    if (feature == entry->feature &&
+        memcmp(addr, &entry->addr, entry->length) == 0)
+      return true;
+
+    node = list_next(node);
+  }
+  return false;
+}
+
+static bool interop_match_fixed_(const interop_feature_t feature,
+                                 const bt_bdaddr_t* addr) {
+  assert(addr);
+
+  const size_t db_size =
+      sizeof(interop_addr_database) / sizeof(interop_addr_entry_t);
+  for (size_t i = 0; i != db_size; ++i) {
+    if (feature == interop_addr_database[i].feature &&
+        memcmp(addr, &interop_addr_database[i].addr,
+               interop_addr_database[i].length) == 0) {
+      return true;
+    }
+  }
+
+  return false;
+}
diff --git a/bt/device/test/interop_test.cc b/bt/device/test/interop_test.cc
new file mode 100644
index 0000000..5116f2c
--- /dev/null
+++ b/bt/device/test/interop_test.cc
@@ -0,0 +1,82 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "device/include/interop.h"
+
+TEST(InteropTest, test_lookup_hit) {
+  bt_bdaddr_t test_address;
+  string_to_bdaddr("38:2c:4a:e6:67:89", &test_address);
+  EXPECT_TRUE(
+      interop_match_addr(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address));
+  string_to_bdaddr("9c:df:03:12:34:56", &test_address);
+  EXPECT_TRUE(interop_match_addr(INTEROP_AUTO_RETRY_PAIRING, &test_address));
+}
+
+TEST(InteropTest, test_lookup_miss) {
+  bt_bdaddr_t test_address;
+  string_to_bdaddr("00:00:00:00:00:00", &test_address);
+  EXPECT_FALSE(
+      interop_match_addr(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address));
+  string_to_bdaddr("ff:ff:ff:ff:ff:ff", &test_address);
+  EXPECT_FALSE(interop_match_addr(INTEROP_AUTO_RETRY_PAIRING, &test_address));
+  string_to_bdaddr("42:08:15:ae:ae:ae", &test_address);
+  EXPECT_FALSE(
+      interop_match_addr(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address));
+  string_to_bdaddr("38:2c:4a:59:67:89", &test_address);
+  EXPECT_FALSE(interop_match_addr(INTEROP_AUTO_RETRY_PAIRING, &test_address));
+}
+
+TEST(InteropTest, test_dynamic) {
+  bt_bdaddr_t test_address;
+
+  string_to_bdaddr("11:22:33:44:55:66", &test_address);
+  EXPECT_FALSE(
+      interop_match_addr(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address));
+
+  interop_database_add(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address, 3);
+  EXPECT_TRUE(
+      interop_match_addr(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address));
+  EXPECT_FALSE(interop_match_addr(INTEROP_AUTO_RETRY_PAIRING, &test_address));
+
+  string_to_bdaddr("66:55:44:33:22:11", &test_address);
+  EXPECT_FALSE(interop_match_addr(INTEROP_AUTO_RETRY_PAIRING, &test_address));
+
+  interop_database_add(INTEROP_AUTO_RETRY_PAIRING, &test_address, 3);
+  EXPECT_TRUE(interop_match_addr(INTEROP_AUTO_RETRY_PAIRING, &test_address));
+  EXPECT_FALSE(
+      interop_match_addr(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address));
+
+  interop_database_clear();
+  EXPECT_FALSE(interop_match_addr(INTEROP_AUTO_RETRY_PAIRING, &test_address));
+}
+
+TEST(InteropTest, test_name_hit) {
+  EXPECT_TRUE(interop_match_name(INTEROP_DISABLE_AUTO_PAIRING, "BMW M3"));
+  EXPECT_TRUE(interop_match_name(INTEROP_DISABLE_AUTO_PAIRING, "Audi"));
+  EXPECT_TRUE(interop_match_name(INTEROP_DISABLE_AUTO_PAIRING,
+                                 "Caramel"));  // Starts with "Car" ;)
+}
+
+TEST(InteropTest, test_name_miss) {
+  EXPECT_FALSE(interop_match_name(INTEROP_DISABLE_AUTO_PAIRING, "__GOOGLE__"));
+  EXPECT_FALSE(interop_match_name(INTEROP_DISABLE_AUTO_PAIRING, "BM"));
+  EXPECT_FALSE(interop_match_name(INTEROP_DISABLE_AUTO_PAIRING, "audi"));
+  EXPECT_FALSE(interop_match_name(INTEROP_AUTO_RETRY_PAIRING, "BMW M3"));
+}
diff --git a/bt/doc/btsnoop_net.md b/bt/doc/btsnoop_net.md
new file mode 100644
index 0000000..2500908
--- /dev/null
+++ b/bt/doc/btsnoop_net.md
@@ -0,0 +1,15 @@
+btsnoop_net
+====
+btsnoop_net exposes Bluetooth snoop logs over a local TCP socket which enables
+real-time debugging of HCI data with hcidump.
+
+This feature is enabled by  setting `BtSnoopLogOutput=true` in `bt_stack.conf`.
+Once it has been enabled and the stack restarted, the stack will listen for
+incoming TCP connections on port 8872.
+
+To use this feature with hcidump on a Linux host, you can run:
+
+```
+  $ adb forward tcp:8872 tcp:8872
+  $ nc localhost 8872 | hcidump -r /dev/stdin
+```
diff --git a/bt/doc/directory_layout.md b/bt/doc/directory_layout.md
new file mode 100644
index 0000000..80b17c8
--- /dev/null
+++ b/bt/doc/directory_layout.md
@@ -0,0 +1,29 @@
+## Directory Layout
+
+### General directory layout
+Each directory should be a self contained subsystem consisting
+of one or more modules.
+
+* src/ - All source files for the subsystem.
+* include/ - All include files for the subsystem.
+* test/ - All unit tests for the subsystem.
+
+### Top level directory layout
+* audio_a2dp_hw - A2DP audio HAL implementation.
+* bta - *Bluetooth Application* - Strange collection of a-lot of things **Deprecate?**
+* btcore - *Bluetooth Core* - Bluetooth data type definitions and operations on those data types.
+* btif - *Bluetooth Interface* - JNI interface to Android.
+* conf - *Configuration* - Various configuration text files.
+* doc - *Documentation* - Stack documentation.
+* embdrv - **Deprecated** - Bluetooth SBC Codec.
+* hci - *Host Controller Interface* - Communication protocol with Bluetooth chip.
+* include - **Deprecated** - System global include files.
+* main - *Main stack entrypoint* - Provides HAL for stack access.
+* osi - *Operating System Interface* - General resource support for stack.
+* profiles - *Bluetooth Profiles* - **TBD** Collection of all profiles.
+* stack - **Deprecated** - The Stack - Push to proper spot in *./profiles*
+* test - *Test suite* - Stack level validiation and stress test suite.
+* tools - *Tools* - Various engineering support tools.
+* udrv -  **Deprecated**  *UIPC implementation*
+* utils - **Deprecated** *Bluetooth utilities* - Eliminate.
+* vnd - *Vendor* - Vendor specific APIs - *to be integrated into rest of stack ?*.
diff --git a/bt/doc/log_tags.md b/bt/doc/log_tags.md
new file mode 100644
index 0000000..f460fd0
--- /dev/null
+++ b/bt/doc/log_tags.md
@@ -0,0 +1,59 @@
+Log Tags
+===
+This document lists all of the log tags used by the Bluetooth stack.
+
+* audio_a2dp_hw
+* BTA_AG_CO:
+* bta_sys_main
+* bt_btif
+* bt_btif_config
+* bt_btif_config_transcode
+* bt_classic_peer
+* bte_conf
+* BtGatt.btif
+* BtGatt.btif_test
+* bt_hci
+* bt_hci_h4
+* bt_hci_inject
+* bt_hci_mct
+* bt_hci_packet_fragmenter
+* BTIF_AV
+* BTIF_CORE
+* BTIF_HF
+* BTIF_HF_CLIENT
+* BTIF_HH
+* BTIF_HL
+* BTIF-MEDIA
+* BTIF_PAN
+* BTIF_QUEUE
+* BTIF_RC
+* BTIF_SM
+* btif_sock
+* BTIF_SOCK
+* btif_sock_rfcomm
+* btif_sock_sco
+* BTIF_SOCK_SDP
+* BTIF_STORAGE
+* BTIF_UTIL
+* BTLD
+* bt_low_power_manager
+* bt_module
+* bt_osi_alarm
+* bt_osi_config
+* bt_osi_data_dispatcher
+* bt_osi_reactor
+* bt_osi_socket
+* bt_profile_manager
+* bt_sdp_client
+* btsnoop
+* btsnoop_net
+* bt_stack_config
+* bt_stack_manager
+* bt_task
+* btu_task
+* BT_UTILS
+* bt_vendor
+* osi_eager_reader
+* osi_future
+* osi_semaphore
+* osi_thread
diff --git a/bt/doc/network_ports.md b/bt/doc/network_ports.md
new file mode 100644
index 0000000..03e138e
--- /dev/null
+++ b/bt/doc/network_ports.md
@@ -0,0 +1,8 @@
+Network Ports
+===
+This document lists all of the network ports used by the bluetooth stack.
+It should be used as a reference and as a mechanism to avoid port
+namespace conflicts.
+
+* TCP 8872 (hci/src/btsnoop_net.cc) - read live btsnoop logs
+* TCP 8873 (hci/src/hci_inject.cc) - inject HCI packets into HCI stream
diff --git a/bt/doc/power_management.md b/bt/doc/power_management.md
new file mode 100644
index 0000000..2b90130
--- /dev/null
+++ b/bt/doc/power_management.md
@@ -0,0 +1,202 @@
+## Power Management
+
+### Overview
+
+Power management (PM) is an event-driven state machine, tickled by various
+`bta/sys` events via a callback. The actual state switching calls are handled
+by the BTM HCI interfacing code, with results being posted back to the PM
+code via the BTA workqueue thread.
+
+Power states are managed per-device, per-profile, so every incoming event
+includes a profile ID, app ID, and a `BD_ADDR`.
+
+The events fired to drive the state machine at the time of this writing are:
+
+  - `BTA_SYS_CONN_OPEN`
+  - `BTA_SYS_CONN_CLOSE`
+  - `BTA_SYS_CONN_IDLE`
+  - `BTA_SYS_CONN_BUSY`
+  - `BTA_SYS_APP_OPEN`
+  - `BTA_SYS_APP_CLOSE`
+  - `BTA_SYS_SCO_OPEN`
+  - `BTA_SYS_SCO_CLOSE`
+
+Each of these correspond to a function name in `bta/sys/bta_sys_conn.cc`, which
+are called by each profile definition in `bta/$PROFILE`.
+
+The PM code makes calls into the BTM module to set various power
+states. Responses are handled in an asynchronous fashion, primarily via the
+callbacks `bta_dm_pm_cback` and `bta_dm_pm_timer_cback`. Responses are handled
+through the BTA workqueue thread and the `bta_dm_pm_btm_status` function. Since
+we might possibly get into a bad state where we never hear back from the
+controller, timers are used to post messages to the BTA workqueue thread as
+well, which filters down through the same status function.
+
+Overall power states are managed *per device*, not per connection, but the power
+policy is determined by the greatest allowable power action defined across all
+currently known connections to a given device. Thus, if RFCOMM specifies that
+it's willing to go to into SNIFF and specifies that as an action, and say, a PAN
+connection is up which specifies it is willing to go into SNIFF, but its action
+states it wants ACTIVE, the power management code will change to ACTIVE.
+
+### Power management tables
+
+The tables that determine which power levels are acceptable for which profiles
+and what actions to take for the above events are defined in the
+`bta/dm/bta_dm_cfg.cc` file, as `bta_dm_pm_cfg`, `bta_dm_pm_spec`, and
+`bta_dm_ssr_spec`.
+
+During a lookup attempt, the code iterates over the `bta_dm_pm_cfg` array,
+looking for a match between the profile and app IDs. When it finds one, it uses
+the `spec_idx` field to index into `bta_dm_pm_spec` array to determine which
+power modes are acceptable and what actions to take for each event.
+
+The action constants are defined in `bta_api.h` and are defined as a series of
+hex bitfields. The actual actions taken are determined by the
+`bta_dm_pm_set_mode` function, but a few of the actions listed deserve some
+additional description:
+
+  - `BTA_DM_PM_NO_ACTION` is effectively a no-op and has a value of zero, so any
+    other profile will override this.
+  - `BTA_DM_PM_NO_PREF` overrides `BTA_DM_PM_NO_ACTION` and if selected as the
+    action that `bta_dm_pm_set_mode` will take, the connection will be removed
+    from `bta_dm_conn_srvcs` and no longer be considered for power management
+    decisions.
+  - `BTA_DM_PM_SNIFF` through `BTA_DM_PM_SNIFF4` are special, in that each
+    level specifies a set of parameters for the SNIFF mode which relate to the
+    min and max intervals, the number of attempts and the timeout. The overall
+    action is still the same, however -- SNIFF mode is attempted. There are
+    definitions available up to SNIFF7, but actual SSR values are only defined
+    up to SNIFF4. Params are defined in `bta_dm_ssr_spec`.
+  - `BTA_DM_PM_ACTIVE` is full-on power.
+  - `BTA_DM_PM_RETRY` has the same effect as `BTA_DM_PM_NO_ACTION`, except a
+    timeout is possible to be set, which effectively allows a power operation to
+    be "retried".
+
+### Initialization
+
+`bta_dm_pm.cc`'s `bta_dm_init_pm` function calls out to register
+`bta_dm_pm_cback` with the bta sys module for incoming power management events,
+and also registers `bta_dm_pm_btm_cback` with the btm module to handle responses
+and timeouts of HCI requests (via `bta_dm_pm_btm_status`).
+
+At this point, the power managment code is basically done until the first set of
+events come in through `bta_dm_pm_cback`.
+
+Throughout the `bta_dm_pm.cc` file, connections whose power management states are
+managed are tracked in a global array called `bta_dm_conn_srvcs`. Unfortunately,
+while this variable is declared as an extern in the `bta_dm_int.h` file, it only
+seems to be used in the `bta_dm_act.cc` file, and only for reinitialization.
+
+### Event flow
+
+#### Events fired from SYS
+
+  1. An event is fired from one of the methods mentioned above in
+     `bta/sys/bta_sys_conn.cc`
+  2. The `bta_dm_pm_cback` function is called.
+     - The power mode config is looked up in the `bta_dm_pm_cfg` table. If none
+       are found for the given profile ID and app ID, the function simply
+       returns with no action taken.
+     - If any timers were set for the given `BD_ADDR`, they are stopped.
+     - The SSR params for the CONN_OPEN event are looked up.
+     - The power spec state table (`bta_dm_pm_spec`) is checked to see if
+       there's no action to be performed (`BTA_DM_PM_NO_ACTION`), and if so,
+       returns with no action taken.
+     - `bta_dm_conn_srvcs` is consulted to ensure there's an entry for this
+       connection if it's supposed to be managed according to the power spec
+       state tables. If the spec specifies `BTA_DM_PM_NO_PREF`, then any
+       existing entry in this list is removed, otherwise one is added/updated
+       with the state given to the function.
+  3. `bta_dm_pm_cback` checks to see if the `bta_dm_ssr_spec` specifies SSR
+     adjustments are to be made, and if so, `bta_dm_pm_ssr` is called with the
+     peer `BD_ADDR`.
+     - `bta_dm_pm_ssr` iterates the managed services array to find all connected
+       services for the given `BD_ADDR`, then looks up the ssr values from the
+       `bta_dm_ssr_spec` tables, looking for the smallest max latency to use.
+     - `bta_dm_pm_ssr` calls `BTM_SetSsrParams` to actually send along the SSR
+       params to the bluetooth chip.
+  4. `bta_dm_pm_cback` calls `bta_dm_pm_set_mode` with the peer address and the
+     `timed_out` parameter set to `false`.
+     - For each managed connection, `bta_dm_pm_set_mode` grabs
+       both actions specified for the profile in the `bta_dm_pm_spec` tables. If
+       the first power management action didn't timeout (or was never attempted,
+       according to the `tBTA_DM_PEER_DEVICE` `pm_mode_failed` and
+       `pm_mode_attempted` fields), its timeout and mode are used. Otherwise,
+       the same check is done against the second action and it is used
+       instead. If both actions have been attempted, then the action is set to
+       `BTA_DM_PM_NO_ACTION`. Only the highest power mode action is chosen from
+       all connected profiles.
+     - If the chosen action is `BTA_DM_PM_PARK` or `BTA_DM_PM_SNIFF` but the
+       profile doesn't allow it, this function takes no action.
+     - If a timeout is specified in the power spec table, then an unused timer
+       in `bta_dm_cb.pm_timer` is started.
+     - If the action chosen is `BTA_DM_PM_PARK`, `bta_dm_pm_park` is called,
+       which calls `BTM_ReadPowerMode` and `BTM_SetPowerMode` to make an HCI
+       request to enable PARK for the given peer and connection.
+     - If the action chosen is `BTA_DM_PM_SNIFF`, the peer device's link policy
+       is checked to see if it's allowed. If so, then `bta_dm_pm_sniff` is
+       called, which makes various calls to `BTM_ReadLocalFeatures`,
+       `BTM_ReadRemoteFeatures` and `BTM_SetPowerMode` to ensure SNIFF mode is
+       enabled.
+     - If the action chosen is `BTA_DM_PM_ACTIVE`, a call to `bta_dm_pm_active`
+       is made, which calls `BTM_SetPowerMode` to set the link into ACTIVE
+       mode.
+
+At this point, if one of the timers in `bta_dm_cb.pm_timer` times out, a call is
+made through the BTA workqueue thread to `bta_dm_pm_btm_cback`, which then
+triggers `bta_dm_pm_btm_status`, with the timeout field set to TRUE. HCI
+responses are also fired as messages through the BTA workqueue thread, which are
+handled again, through `bta_dm_pm_btm_status`.
+
+#### Events fired through BTM
+
+Essentially these messages eventually go through the same functions as events
+fired from the SYS side of things, except from the initial path they take:
+
+  1. An event is fired from a callback in BTM to `bta_dm_pm_btm_cback`.
+  2. `bta_dm_pm_btm_cback` packages up the given parameters into a
+     `tBTA_DM_PM_BTM_STATUS` struct and posts it to the BTA workqueue thread via
+     `bta_sys_sendmsg`, with the event header set to
+     `BTA_DM_PM_BTM_STATUS_EVT`.
+  3. This is eventually routed to the `bta_dm_pm_btm_status` function.
+     **Determine if this is running on the workqueue thread or not**
+     - The message `status` passed in is actually the current status of the
+       device.
+     - If the status is `BTM_PM_STS_ACTIVE` (still in the ACTIVE power mode),
+       checks the HCI status code:
+       - If that's non-zero and a PARK or SNIFF mode change was attempted,
+         `bta_dm_pm_btm_status` stops any timers started for the device in
+         `bta_dm_pm_set_mode`, clears some status bits in the peer device
+         structure, and then calls back into `bta_dm_pm_set_mode` with the peer
+         device address and timeout set to FALSE.
+       - If the status is zero, and if the peer device `tBTA_DM_PEER_DEVICE`
+         `prev_low` field is set, calls `bta_dm_pm_ssr` to re-send SSR params,
+         stops all timers for the device, and then re-calls `bta_dm_pm_set_mode`
+         with timeout set to FALSE to re-attempt with a second action (if the
+         previous PARK or SNIFF failed, otherwise it'll re-attempt the first
+         action).
+     - If the status is `BTM_PM_STS_PARK` or `BTM_PM_STS_HOLD`, saves the
+       previous low power mode in the peer device's `prev_low` field.
+     - If the status is `BTM_PM_STS_SSR`, simply clears or sets the device
+       `info` field's `BTA_DM_DI_USE_SSR` bit, depending on the value of
+       `tBTA_DM_MSG.value`, which determines if the device can handle SSR.
+     - If the status is `BTM_PM_STS_SNIFF` and the info field has the
+       `BTA_DM_DI_SET_SNIFF` bit set, then `BTA_DM_DI_INT_SNIFF` is set,
+       otherwise `BTA_DM_DI_ACP_SNIFF` is set.
+     - If `BTA_PM_STS_ERROR`, the `BTA_DM_DI_SET_SNIFF` bit is cleared in the
+       device info field.
+
+At this point, either the method simply returns, or has called back into
+`bta_dm_pm_set_mode`, in which case the usual flow takes over.
+
+#### Events fired from timers
+
+Timers are used exclusively for handling HCI command timeouts, and filter
+through to a call to `bta_dm_pm_set_mode`:
+
+  1. A timer expires, and calls `bta_dm_pm_timer_cback`.
+  2. `bta_dm_pm_timer_cback` clears the use flag on the timer that fired, and
+     sends off an event to the BTA workqueue thread.
+  3. The event eventually fires off a call to `bta_dm_pm_timer`, which just
+     calls `bta_dm_pm_set_mode` with timeout set to `TRUE`.
diff --git a/bt/doc/properties.md b/bt/doc/properties.md
new file mode 100644
index 0000000..c4ab97c
--- /dev/null
+++ b/bt/doc/properties.md
@@ -0,0 +1,20 @@
+Properties
+===
+This document describes all of the Android properties used by the Bluetooth
+stack.
+
+Please keep the following list in alphabetical order.
+
+* ``` bluetooth.enable_timeout_ms ```  
+  Maximum amount of time Bluetooth can take to start-up, upload firmware etc.  
+  Used in hci/src/hci_layer.cc, default 8000.
+
+### TODO: write descriptions of what each property means and how
+it's used.
+
+* ``` debug.sys.noschedgroups ```
+* ``` persist.service.bdroid.bdaddr ```
+* ``` ro.bluetooth.hfp.ver ```
+* ``` ro.bt.bdaddr_path ```
+* ``` ro.product.model ```
+* ``` service.brcm.bt.oob ```
diff --git a/bt/doc/style_guide.md b/bt/doc/style_guide.md
new file mode 100644
index 0000000..f151ce0
--- /dev/null
+++ b/bt/doc/style_guide.md
@@ -0,0 +1,429 @@
+# Fluoride Style Guide
+This document outlines the coding conventions and code style used in Fluoride.
+Its primary purpose is to provide explicit guidance on style so that developers
+are consistent with one another and spend less time debating style.
+
+As a rule, we follow the Google C++
+[Style Guide](https://google.github.io/styleguide/cppguide.html).
+Exceptions will be noted below.
+
+## Directory structure
+Directories at the top-level should consist of major subsystems in Fluoride.
+Each subsystem's purpose should be documented in the `doc/directory_layout.md`
+file, even if it seems obvious from the name.
+
+For a subsystem that contains code, its directory structure should look like:
+```
+  Android.mk
+  include/
+  src/
+  test/
+```
+Further, the directory structure inside `src/` and `include/` should be
+mirrored. In other words, if `src/` contains a subdirectory called `foo/`,
+`include/` must also have a subdirectory named `foo/`.
+
+## Target architecture
+Fluoride targets a variety of hardware and cannot make many assumptions about
+memory layout, sizes, byte order, etc. As a result, some operations are
+considered unsafe and this section outlines the most important ones to watch out
+for.
+
+### Pointer / integer casts
+In general, do not cast pointers to integers or vice versa.
+
+The one exception is if an integer needs to be temporarily converted to a
+pointer and then back to the original integer. This style of code is typically
+needed when providing an integral value as the context to a callback, as in the
+following example.
+```
+void my_callback(void *context) {
+  uintptr_t arg = context;
+}
+
+set_up_callback(my_callback, (uintptr_t)5);
+```
+Note, however, that the integral value was written into the pointer and read
+from the pointer as a `uintptr_t` to avoid a loss of precision (or to make the
+loss explicit).
+
+### Byte order
+It is not safe to assume any particular byte order. When serializing or
+deserializing data, it is unsafe to memcpy unless both source and destination
+pointers have the same type.
+
+## Language
+Fluoride is written in C99 and should take advantage of the features offered by
+it. However, not all language features lend themselves well to the type of
+development required by Fluoride. This section provides guidance on some of the
+features to embrace or avoid.
+
+### C Preprocessor
+The use of the C preprocessor should be minimized. In particular:
+* use functions or, if absolutely necessary, inline functions instead of macros
+* use `static const` variables instead of `#define`
+* use `enum` for enumerations, not a collection of `#define`s
+* minimize the use of feature / conditional macros
+
+The last point is perhaps the most contentious. It's well-understood that
+feature macros are useful in reducing code size but it leads to an exponential
+explosion in build configurations. Setting up, testing, and verifying each of
+the `2^n` build configurations is untenable for `n` greater than, say, 4.
+
+### C++
+Although C++ offers constructs that may make Fluoride development faster,
+safer, more pleasant, etc. the decision _for the time being_ is to stick with
+pure C99. The exceptions are when linking against libraries that are written
+in C++. At the time of writing these libraries are `gtest` and `tinyxml2`,
+where the latter is a dependency that should be eliminated in favor of simpler,
+non-XML formats.
+
+### Variadic functions
+Variadic functions are dangerous and should be avoided for most code. The
+exception is when implementing logging since the benefits of readability
+outweigh the cost of safety.
+
+### Functions with zero arguments
+Functions that do not take any arguments (0 arity) should be declared like so:
+```
+void function(void);
+```
+Note that the function explicitly includes `void` in its parameter list to
+indicate to the compiler that it takes no arguments.
+
+### Variable declarations
+Variables should be declared one per line as close to initialization as possible.
+In nearly all cases, variables should be declared and initialized on the same line.
+Variable declarations should not include extra whitespace to line up fields. For
+example, the following style is preferred:
+```
+  int my_long_variable_name = 0;
+  int x = 5;
+```
+whereas this code is not acceptable:
+```
+  int my_long_variable_name = 0;
+  int                     x = 5;
+```
+
+As a result of the above rule to declare and initialize variables together,
+`for` loops should declare and initialize their iterator variable in the
+initializer statement:
+```
+  for (int i = 0; i < 10; ++i) {
+    // use i
+  }
+```
+
+### Contiguous memory structs
+Use C99 flexible arrays as the last member of a struct if the array needs
+to be allocated in contiguous memory with its containing struct.
+A flexible array member is writen as `array_name[]` without a specified size.
+For example:
+```
+typedef struct {
+  size_t length;
+  uint8_t data[];
+} buffer_t;
+
+// Allocate a buffer with 128 bytes available for my_buffer->data.
+buffer_t *my_buffer = malloc(sizeof(buffer_t) + 128);
+uint8_t *data = my_buffer->data;
+```
+
+### Pointer arithmetic
+Avoid pointer arithmetic when possible as it results in difficult to read code.
+Prefer array-indexing syntax over pointer arithmetic.
+
+In particular, do not write code like this:
+```
+typedef struct {
+  size_t length;
+} buffer_t;
+
+buffer_t *my_buffer = malloc(sizeof(buffer_t) + 128);
+uint8_t *data = (uint8_t *)(my_buffer + 1);
+```
+Instead, use zero-length arrays as described above to avoid pointer arithmetic
+and array indexing entirely.
+
+### Boolean type
+Use the C99 `bool` type with values `true` and `false` defined in `stdbool.h`.
+Not only is this a standardized type, it is also safer and provides more
+compile-time checks.
+
+### Booleans instead of bitfields
+Use booleans to represent boolean state, instead of a set of masks into an
+integer. It's more transparent and readable, and less error prone.
+
+### Function names as strings
+C99 defines `__func__` as an identifier that represents the function's name
+in which it is used. The magic identifier `__FUNCTION__` should not be used
+as it is a non-standard language extension and an equivalent standardized
+mechanism exists. In other words, use `__func__` over `__FUNCTION__`.
+
+## Fluoride conventions
+This section describes coding conventions that are specific to Fluoride.
+Whereas the _Language_ section describes the use of language features, this
+section describes idioms, best practices, and conventions that are independent
+of language features.
+
+### Memory management
+Use `osi_malloc` or `osi_calloc` to allocate bytes instead of plain `malloc`.
+Likewise, use `osi_free` over `free`. These wrapped functions provide additional
+lightweight memory bounds checks that can help track down memory errors.
+
+By convention, functions that contain `*_new` in their name are allocation
+routines and objects returned from those functions must be freed with the
+corresponding `*_free` function. For example, list objects returned from
+`list_new` should be freed with `list_free` and no other freeing routine.
+
+### Asserts
+Use `assert` liberally throughout the code to enforce invariants. Assertions
+should not have any side-effects and should be used to detect programming logic
+errors.
+
+At minimum, every function should assert expectations on its arguments. The
+following example demonstrates the kinds of assertions one should make on
+function arguments.
+```
+  size_t open_and_read_file(const char *filename, void *target_buffer, size_t max_bytes) {
+    assert(filename != NULL);
+    assert(filename[0] != '\0');
+    assert(target_buffer != NULL);
+    assert(max_bytes > 0);
+
+    // function implementation begins here
+  }
+```
+
+## Header files
+In general, every source file (`.c` or `.cpp`) in a `src/` directory should
+have a corresponding header (`.h`) in the `include/` directory.
+
+### Template header file
+```
+[copyright header]
+
+#pragma once
+
+#include <system/a.h>
+#include <system/b.h>
+
+#include "subsystem/include/a.h"
+#include "subsystem/include/b.h"
+
+typedef struct alarm_t alarm_t;
+typedef struct list_t list_t;
+
+// This comment describes the following function. It is not a structured
+// comment, it's English prose. Function arguments can be referred to as
+// |param|. This function returns true if a new object was created, false
+// otherwise.
+bool template_new(const list_t *param);
+
+// Each public function must have a comment describing its semantics. In
+// particular, edge cases, and whether a pointer argument may or may not be
+// NULL.
+void template_use_alarm(alarm_t *alarm);
+```
+
+### License header
+Each header file must begin with the following Apache 2.0 License with `<year>`
+and `<owner>` replaced with the year in which the file was authored and the
+owner of the copyright, respectively.
+```
+/******************************************************************************
+ *
+ *  Copyright (C) <year> <owner>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 guard
+After the license header, each header file must contain the include guard:
+```
+#pragma once
+```
+This form is used over traditional `#define`-based include guards as it is less
+error-prone, doesn't pollute the global namespace, is more compact, and can
+result in faster compilation.
+
+## Formatting
+Code formatting is done automatically using clang-format.
+
+The style file is located at the root of the source tree in .clang-format.  The
+-style=file option instructs clang-format to look for this file.  You may find
+clang-format --help useful for more advanced usage. The [Online clang-format
+Documentation](http://clang.llvm.org/docs/ClangFormat.html) can also be helpful.
+
+`clang-format -style=file -i path_to_files/filename_or_*`
+
+### My Patch Doesn't Apply Anymore!
+Choose one of the options below.  The fewer patches that have been applied to
+the tree since the formatting change was applied, the better.  In this short
+guide, commands you type will be marked as `code`, with output in *italics*.
+
+#### Option 1: The Best Case
+Use this option if your patch touches only a few files with few intermediate
+patches.
+
+##### Find the formatting patch
+
+`git log --oneline path_to_files/filename_or_* | grep clang-format | head -n 5`
+
+***15ce1bd** subtree: Apply **clang-format** for the first time*
+
+##### Revert the formatting patch
+
+`git revert HASH -n`
+
+(Replace HASH with 15ce1bd in this example.)
+
+##### Check for conflicts with your patch
+
+`git status | grep both.modified`
+
+If this list contains files modified by your patch, you should give up
+
+`git revert --abort`
+
+and try a different method.
+
+If this list contains files not modified by your patch, you should unstage them
+
+`git reset HEAD both_modified_file`
+
+and remove their changes
+
+`git checkout both_modified_file`
+
+##### Apply your patch
+
+`git cherry-pick your_patch_that_used_to_apply_cleanly`
+
+##### Reformat the code
+
+`clang-format -style=file -i path_to_files/filename_or_*`
+
+##### Commit the code that your patch touched
+
+`git add path_to_files/filename_or_*`
+
+`git commit --amend`
+
+##### Clean up any other files
+
+`git checkout .`
+
+##### Review your new patch
+
+`git diff`
+
+#### Option 2: Reformat your patch
+
+##### Start with a tree with your patch applied to the tip of tree
+
+`git log --oneline | head -n 1`
+
+***dc5f0e2** Unformatted but vital patch*
+
+(**Remember the HASH from this step**)
+
+##### Create a new branch starting from the first unrelated patch
+
+`git checkout HEAD^ -b reformat_my_patch_branch`
+
+`git log --oneline | head -n 1`
+
+***15ce1bd** First Unrelated patch*
+
+##### Reformat the code
+
+`clang-format -style=file -i path_to_files/filename_or_*`
+
+##### Commit your temporary formatting patch
+
+`git add path_to_files/filename_or_*`
+
+`git commit -m tmp_format_patch`
+
+##### Revert your temporary formatting patch (**Bear with me!**)
+
+`git revert HEAD --no-edit`
+
+##### Apply your patch
+
+`git cherry-pick HASH`
+
+(The HASH of your patch, dc5f0e2 in this case)
+
+##### Reformat the code
+
+`clang-format -style=file -i path_to_files/filename_or_*`
+
+##### Commit your second temporary formatting patch
+
+`git add path_to_files/filename_or_*`
+
+`git commit -m tmp_format_patch_2`
+
+##### Check to see that everything looks right
+
+`git log --oneline | head -n 5`
+
+*04c97cf tmp_format_patch_2*
+
+*cf8560c Unformatted but vital patch*
+
+*04c97cf Revert "tmp_format_patch"*
+
+*d66bb6f tmp_format_patch*
+
+*15ce1bd First Unrelated patch*
+
+##### Squash the last three patches with git rebase
+
+`git rebase -i HEAD^^^`
+
+*pick 04c97cf tmp_format_patch_2*
+
+*squash cf8560c Unformatted but vital patch*
+
+*squash 04c97cf Revert "tmp_format_patch"*
+
+##### Remember to edit the commit message!
+
+`clang-format -style=file -i path_to_files/filename_or_*`
+
+##### Check to see that everything looks right
+
+`git log --oneline | head -n 2`
+
+*523078f Reformatted vital patch*
+
+*d66bb6f tmp_format_patch*
+
+##### Review your new patch
+
+`git show`
+
+##### Checkout the current tree and cherry pick your reformatted patch!
+
+`git checkout aosp/master`
+
+`git cherry-pick HASH`
+
+(HASH is 523078f in this example)
diff --git a/bt/doc/supported_features.md b/bt/doc/supported_features.md
new file mode 100644
index 0000000..60580e2
--- /dev/null
+++ b/bt/doc/supported_features.md
@@ -0,0 +1,20 @@
+# Fluoride 1.1
+
+Declaration ID: [D024527](https://www.bluetooth.org/tpg/QLI_viewQDL.cfm?qid=24527)
+Qualified Design ID: 83953
+
+Protocol / Profile | Version | Roles
+-------------------+---------+-------
+L2CAP              | 4.2     | Initiator, Acceptor, LE Master, LE Slave
+SDP                | 4.2     | Server, Client
+GAP                | 4.2     | BR/EDR, LE Central, LE Periperhal, LE Observer, LE Broadcaster
+GATT               | 4.2     | Client, Server; LE and BR/EDR
+ATT                | 4.2     | Client, Server; LE and BR/EDR
+SM                 | 4.2     | Master (Initiator), Slave (Responder)
+AVCTP              | 1.4     | Controller, Target
+AVDTP              | 1.2     | Source, Initiator, Acceptor
+BNEP               | 1.0     |
+GAVDP              | 1.2     | Initiator, Acceptor
+MCAP               | 1.0     | Sink
+RFCOMM             | 1.2     |
+SPP                | 1.2     | A, B
diff --git a/bt/embdrv/Android.mk b/bt/embdrv/Android.mk
new file mode 100644
index 0000000..c455f97
--- /dev/null
+++ b/bt/embdrv/Android.mk
@@ -0,0 +1,3 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/bt/embdrv/sbc/Android.mk b/bt/embdrv/sbc/Android.mk
new file mode 100644
index 0000000..c455f97
--- /dev/null
+++ b/bt/embdrv/sbc/Android.mk
@@ -0,0 +1,3 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/bt/embdrv/sbc/BUILD.gn b/bt/embdrv/sbc/BUILD.gn
new file mode 100644
index 0000000..7e75633
--- /dev/null
+++ b/bt/embdrv/sbc/BUILD.gn
@@ -0,0 +1,62 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+source_set("sbc_decoder") {
+  sources = [
+    "decoder/srce/alloc.c",
+    "decoder/srce/bitalloc.c",
+    "decoder/srce/bitalloc-sbc.c",
+    "decoder/srce/bitstream-decode.c",
+    "decoder/srce/decoder-oina.c",
+    "decoder/srce/decoder-private.c",
+    "decoder/srce/decoder-sbc.c",
+    "decoder/srce/dequant.c",
+    "decoder/srce/framing.c",
+    "decoder/srce/framing-sbc.c",
+    "decoder/srce/oi_codec_version.c",
+    "decoder/srce/synthesis-8-generated.c",
+    "decoder/srce/synthesis-dct8.c",
+    "decoder/srce/synthesis-sbc.c",
+  ]
+
+  include_dirs = [ "decoder/include" ]
+}
+
+source_set("sbc_encoder") {
+  sources = [
+    "encoder/srce/sbc_analysis.c",
+    "encoder/srce/sbc_dct.c",
+    "encoder/srce/sbc_dct_coeffs.c",
+    "encoder/srce/sbc_enc_bit_alloc_mono.c",
+    "encoder/srce/sbc_enc_bit_alloc_ste.c",
+    "encoder/srce/sbc_enc_coeffs.c",
+    "encoder/srce/sbc_encoder.c",
+    "encoder/srce/sbc_packing.c",
+  ]
+
+  include_dirs = [
+    "encoder/include",
+    "//include",
+    "//stack/include",
+  ]
+}
+
+static_library("sbc") {
+  deps = [
+    ":sbc_decoder",
+    ":sbc_encoder",
+  ]
+}
diff --git a/bt/embdrv/sbc/decoder/Android.mk b/bt/embdrv/sbc/decoder/Android.mk
new file mode 100644
index 0000000..4a967c0
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/Android.mk
@@ -0,0 +1,37 @@
+LOCAL_PATH:= $(call my-dir)
+
+# Bluetooth SBC decoder static library for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_CPP_EXTENSION := .cc
+
+# sbc decoder
+LOCAL_SRC_FILES := \
+        ./srce/alloc.c \
+        ./srce/bitalloc.c \
+        ./srce/bitalloc-sbc.c \
+        ./srce/bitstream-decode.c \
+        ./srce/decoder-oina.c \
+        ./srce/decoder-private.c \
+        ./srce/decoder-sbc.c \
+        ./srce/dequant.c \
+        ./srce/framing.c \
+        ./srce/framing-sbc.c \
+        ./srce/oi_codec_version.c \
+        ./srce/synthesis-sbc.c \
+        ./srce/synthesis-dct8.c \
+        ./srce/synthesis-8-generated.c \
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include \
+	$(LOCAL_PATH)/srce
+
+LOCAL_MODULE := libbt-qcom_sbc_decoder
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/bt/embdrv/sbc/decoder/include/oi_assert.h b/bt/embdrv/sbc/decoder/include/oi_assert.h
new file mode 100644
index 0000000..35d86cf
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/include/oi_assert.h
@@ -0,0 +1,86 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_ASSERT_H
+#define _OI_ASSERT_H
+/** @file
+  This file provides macros and functions for compile-time and run-time assertions.
+
+  When the OI_DEBUG preprocessor value is defined, the macro OI_ASSERT is compiled into
+  the program, providing for a runtime assertion failure check.
+  C_ASSERT is a macro that can be used to perform compile time checks.
+*/
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+
+/** \addtogroup Debugging Debugging APIs */
+/**@{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef OI_DEBUG
+
+/** The macro OI_ASSERT takes a condition argument. If the asserted condition
+    does not evaluate to true, the OI_ASSERT macro calls the host-dependent function,
+    OI_AssertFail(), which reports the failure and generates a runtime error.
+*/
+void OI_AssertFail(char* file, int line, char* reason);
+
+
+#define OI_ASSERT(condition) \
+    { if (!(condition)) OI_AssertFail(__FILE__, __LINE__, #condition); }
+
+#define OI_ASSERT_FAIL(msg) \
+    { OI_AssertFail(__FILE__, __LINE__, msg); }
+
+#else
+
+
+#define OI_ASSERT(condition)
+#define OI_ASSERT_FAIL(msg)
+
+#endif
+
+
+/**
+   C_ASSERT() can be used to perform many compile-time assertions: type sizes, field offsets, etc.
+   An assertion failure results in compile time error C2118: negative subscript.
+   Unfortunately, this elegant macro doesn't work with GCC, so it's all commented out
+   for now. Perhaps later.....
+*/
+
+#ifndef C_ASSERT
+// #define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
+// #define C_ASSERT(e)
+#endif
+
+
+/*****************************************************************************/
+#ifdef __cplusplus
+}
+#endif
+
+/**@}*/
+
+#endif /* _OI_ASSERT_H */
+
diff --git a/bt/embdrv/sbc/decoder/include/oi_bitstream.h b/bt/embdrv/sbc/decoder/include/oi_bitstream.h
new file mode 100644
index 0000000..1c3a8b4
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/include/oi_bitstream.h
@@ -0,0 +1,123 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_BITSTREAM_H
+#define _OI_BITSTREAM_H
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+
+/**
+@file
+Function prototypes and macro definitions for manipulating input and output
+bitstreams.
+
+@ingroup codec_internal
+*/
+
+/**
+@addtogroup codec_internal
+@{
+*/
+
+#include "oi_codec_sbc_private.h"
+#include "oi_stddefs.h"
+
+INLINE void OI_BITSTREAM_ReadInit(OI_BITSTREAM *bs, const OI_BYTE *buffer);
+
+INLINE void OI_BITSTREAM_WriteInit(OI_BITSTREAM *bs, OI_BYTE *buffer);
+
+INLINE uint32_t OI_BITSTREAM_ReadUINT(OI_BITSTREAM *bs, OI_UINT bits);
+
+INLINE uint8_t OI_BITSTREAM_ReadUINT4Aligned(OI_BITSTREAM *bs);
+
+INLINE uint8_t OI_BITSTREAM_ReadUINT8Aligned(OI_BITSTREAM *bs);
+
+INLINE void OI_BITSTREAM_WriteUINT(OI_BITSTREAM *bs,
+                                   uint16_t value,
+                                   OI_UINT bits);
+
+/*
+ * Use knowledge that the bitstream is aligned to optimize the write of a byte
+ */
+PRIVATE void OI_BITSTREAM_WriteUINT8Aligned(OI_BITSTREAM *bs,
+                                            uint8_t datum);
+
+/*
+ * Use knowledge that the bitstream is aligned to optimize the write pair of nibbles
+ */
+PRIVATE void OI_BITSTREAM_Write2xUINT4Aligned(OI_BITSTREAM *bs,
+                                              uint8_t datum1,
+                                              uint8_t datum2);
+
+/** Internally the bitstream looks ahead in the stream. When
+ * OI_SBC_ReadScalefactors() goes to temporarily break the abstraction, it will
+ * need to know where the "logical" pointer is in the stream.
+ */
+#define OI_BITSTREAM_GetWritePtr(bs) ((bs)->ptr.w - 3)
+#define OI_BITSTREAM_GetReadPtr(bs) ((bs)->ptr.r - 3)
+
+/** This is declared here as a macro because decoder.c breaks the bitsream
+ * encapsulation for efficiency reasons.
+ */
+#define OI_BITSTREAM_READUINT(result, bits, ptr, value, bitPtr) \
+do { \
+    OI_ASSERT((bits) <= 16); \
+    OI_ASSERT((bitPtr) < 16); \
+    OI_ASSERT((bitPtr) >= 8); \
+    \
+    (result) = (value) << (bitPtr); \
+    (result) >>= 32 - (bits); \
+    \
+    (bitPtr) += (bits); \
+    while ((bitPtr) >= 16) { \
+        (value) = ((value) << 8) | *(ptr)++; \
+        (bitPtr) -= 8; \
+    } \
+    OI_ASSERT(((bits) == 0) || ((result) < (1u << (bits)))); \
+} while (0)
+
+
+#define OI_BITSTREAM_WRITEUINT(ptr, value, bitPtr, datum, bits) \
+do {\
+    (bitPtr) -= (bits);\
+    (value) |= (datum) << (bitPtr);\
+    \
+    while ((bitPtr) <= 16) {\
+        (bitPtr) += 8;\
+        *(ptr)++ = (uint8_t)((value) >> 24);\
+        (value) <<= 8;\
+    }\
+} while (0)
+
+#define OI_BITSTREAM_WRITEFLUSH(ptr, value, bitPtr) \
+do {\
+    while ((bitPtr) < 32) {\
+        (bitPtr) += 8;\
+        *(ptr)++ = (uint8_t)((value) >> 24);\
+        (value) <<= 8;\
+    }\
+} while (0)
+
+/**
+@}
+*/
+
+#endif /* _OI_BITSTREAM_H */
diff --git a/bt/embdrv/sbc/decoder/include/oi_bt_spec.h b/bt/embdrv/sbc/decoder/include/oi_bt_spec.h
new file mode 100644
index 0000000..7accde6
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/include/oi_bt_spec.h
@@ -0,0 +1,229 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_BT_SPEC_H
+#define _OI_BT_SPEC_H
+/**
+ * @file
+ *
+ * This file contains common definitions from the Bluetooth specification.
+ *
+ */
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+#include "oi_stddefs.h"
+
+/** \addtogroup Misc Miscellaneous APIs */
+/**@{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** The maximum number of active slaves in a piconet. */
+#define OI_BT_MAX_ACTIVE_SLAVES 7
+
+/** the number of bytes in a Bluetooth device address (BD_ADDR) */
+#define OI_BD_ADDR_BYTE_SIZE   6
+
+/**
+ * 48-bit Bluetooth device address
+ *
+ * Because 48-bit integers may not be supported on all platforms, the
+ * address is defined as an array of bytes. This array is big-endian,
+ * meaning that
+ *  - array[0] contains bits 47-40,
+ *  - array[1] contains bits 39-32,
+ *  - array[2] contains bits 31-24,
+ *  - array[3] contains bits 23-16,
+ *  - array[4] contains bits 15-8, and
+ *  - array[5] contains bits 7-0.
+ */
+typedef struct  {
+    uint8_t    addr[OI_BD_ADDR_BYTE_SIZE] ;   /**< Bluetooth device address represented as an array of 8-bit values */
+} OI_BD_ADDR ;
+
+/**
+ * @name Data types for working with UUIDs
+ * UUIDs are 16 bytes (128 bits).
+ *
+ * To avoid having to pass around 128-bit values all the time, 32-bit and 16-bit
+ * UUIDs are defined, along with a mapping from the shorter versions to the full
+ * version.
+ *
+ * @{
+ */
+
+/**
+ * 16-bit representation of a 128-bit UUID
+ */
+typedef uint16_t OI_UUID16;
+
+/**
+ * 32-bit representation of a 128-bit UUID
+ */
+typedef uint32_t OI_UUID32;
+
+/**
+ * number of bytes in a 128 bit UUID
+ */
+#define OI_BT_UUID128_SIZE  16
+
+/**
+ * number of bytes in IPv6 style addresses
+ */
+#define OI_BT_IPV6ADDR_SIZE  16
+
+/**
+ * type definition for a 128-bit UUID
+ *
+ * To simplify conversion between 128-bit UUIDs and 16-bit and 32-bit UUIDs,
+ * the most significant 32 bits are stored with the same endian-ness as is
+ * native on the target (local) device. The remainder of the 128-bit UUID is
+ * stored as bytes in big-endian order.
+ */
+typedef struct {
+    uint32_t ms32bits;                                    /**< most significant 32 bits of 128-bit UUID */
+    uint8_t base[OI_BT_UUID128_SIZE - sizeof(uint32_t)]; /**< remainder of 128-bit UUID, array of 8-bit values */
+} OI_UUID128;
+
+/** @} */
+
+/** number of bytes in a link key */
+#define OI_BT_LINK_KEY_SIZE    16
+
+/**
+ * type definition for a baseband link key
+ *
+ * Because 128-bit integers may not be supported on all platforms, we define
+ * link keys as an array of bytes. Unlike the Bluetooth device address,
+ * the link key is stored in little-endian order, meaning that
+ *  - array[0]  contains bits 0  - 7,
+ *  - array[1]  contains bits 8  - 15,
+ *  - array[2]  contains bits 16 - 23,
+ *  - array[3]  contains bits 24 - 31,
+ *  - array[4]  contains bits 32 - 39,
+ *  - array[5]  contains bits 40 - 47,
+ *  - array[6]  contains bits 48 - 55,
+ *  - array[7]  contains bits 56 - 63,
+ *  - array[8]  contains bits 64 - 71,
+ *  - array[9]  contains bits 72 - 79,
+ *  - array[10] contains bits 80 - 87,
+ *  - array[11] contains bits 88 - 95,
+ *  - array[12] contains bits 96 - 103,
+ *  - array[13] contains bits 104- 111,
+ *  - array[14] contains bits 112- 119, and
+ *  - array[15] contains bits 120- 127.
+ */
+typedef struct {
+    uint8_t    key[OI_BT_LINK_KEY_SIZE] ;   /**< link key represented as an array of 8-bit values */
+} OI_LINK_KEY ;
+
+
+/** Out-of-band data size - C and R values are 16-bytes each */
+#define OI_BT_OOB_NUM_BYTES     16
+
+typedef struct {
+    uint8_t    value[OI_BT_OOB_NUM_BYTES] ;   /**< same struct used for C and R values */
+} OI_OOB_DATA ;
+
+
+/**
+ * link key types
+ */
+typedef enum  {
+    OI_LINK_KEY_TYPE_COMBO              = 0,    /**< combination key */
+    OI_LINK_KEY_TYPE_LOCAL_UNIT         = 1,    /**< local unit key */
+    OI_LINK_KEY_TYPE_REMOTE_UNIT        = 2,    /**< remote unit key */
+    OI_LINK_KEY_TYPE_DEBUG_COMBO        = 3,    /**< debug combination key */
+    OI_LINK_KEY_TYPE_UNAUTHENTICATED    = 4,    /**< Unauthenticated */
+    OI_LINK_KEY_TYPE_AUTHENTICATED      = 5,    /**< Authenticated */
+    OI_LINK_KEY_TYPE_CHANGED_COMBO      = 6     /**< Changed */
+
+} OI_BT_LINK_KEY_TYPE ;
+
+
+/** amount of space allocated for a PIN (personal indentification number) in bytes */
+#define OI_BT_PIN_CODE_SIZE    16
+
+/** data type for a PIN (PINs are treated as strings, so endianness does not apply.) */
+typedef struct  {
+    uint8_t    pin[OI_BT_PIN_CODE_SIZE] ; /**< PIN represented as an array of 8-bit values */
+} OI_PIN_CODE ;
+
+/** maximum number of SCO connections per device, which is 3 as of version 2.0+EDR
+    of the Bluetooth specification (see sec 4.3 of vol 2 part B) */
+#define OI_BT_MAX_SCO_CONNECTIONS  3
+
+/** data type for clock offset */
+typedef uint16_t   OI_BT_CLOCK_OFFSET ;
+
+/** data type for a LM handle */
+typedef uint16_t OI_HCI_LM_HANDLE;
+
+/** opaque data type for a SCO or ACL connection handle */
+typedef struct _OI_HCI_CONNECTION *OI_HCI_CONNECTION_HANDLE;
+
+/** data type for HCI Error Code, as defined in oi_hcispec.h */
+typedef uint8_t    OI_HCI_ERROR_CODE ;
+
+/**
+ * The Bluetooth device type is indicated by a 24-bit bitfield, represented as a
+ * 32-bit number in the stack. The bit layout and values for device class are specified
+ * in the file oi_bt_assigned_nos.h and in the Bluetooth "Assigned Numbers" specification
+ * at http://www.bluetooth.org/assigned-numbers/.
+ */
+typedef uint32_t   OI_BT_DEVICE_CLASS ;
+
+#define OI_BT_DEV_CLASS_FORMAT_MASK        0x000003    /**< Bits 0-1 contain format type. */
+#define OI_BT_DEV_CLASS_MINOR_DEVICE_MASK  0x0000FC    /**< Bits 2-7 contain minor device class value. */
+#define OI_BT_DEV_CLASS_MAJOR_DEVICE_MASK  0x001F00    /**< Bits 8-12 contain major device class value. */
+#define OI_BT_DEV_CLASS_MAJOR_SERVICE_MASK 0xFFE000    /**< Bits 13-23 contain major service class value. */
+
+/** There is currently only one device class format defined, type 00. */
+#define OI_BT_DEV_CLASS_FORMAT_TYPE        00
+
+/** Bit 13 in device class indicates limited discoverability mode (GAP v2.0+EDR, section 4.1.2.2) */
+#define OI_BT_DEV_CLASS_LIMITED_DISCO_BIT  BIT13
+
+/** macro to test validity of the Device Class Format */
+#define OI_BT_VALID_DEVICE_CLASS_FORMAT(class) (OI_BT_DEV_CLASS_FORMAT_TYPE == ((class) & OI_BT_DEV_CLASS_FORMAT_MASK))
+
+/** the time between baseband clock ticks, currently 625 microseconds (one slot) */
+#define OI_BT_TICK 625
+/** some macros to convert to/from baseband clock ticks - use no floating point! */
+#define OI_SECONDS_TO_BT_TICKS(secs)    ((secs)*1600)
+#define OI_BT_TICKS_TO_SECONDS(ticks)   ((ticks)/1600)
+#define OI_MSECS_TO_BT_TICKS(msecs)     (((msecs)*8)/5)
+#define OI_BT_TICKS_TO_MSECS(ticks)     (((ticks)*5)/8)
+
+/** EIR byte order */
+#define OI_EIR_BYTE_ORDER   OI_LITTLE_ENDIAN_BYTE_ORDER
+
+
+#ifdef __cplusplus
+}
+#endif
+
+/**@}*/
+
+/*****************************************************************************/
+#endif /* _OI_BT_SPEC_H */
diff --git a/bt/embdrv/sbc/decoder/include/oi_codec_sbc.h b/bt/embdrv/sbc/decoder/include/oi_codec_sbc.h
new file mode 100644
index 0000000..d102f02
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/include/oi_codec_sbc.h
@@ -0,0 +1,484 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+#ifndef _OI_CODEC_SBC_CORE_H
+#define _OI_CODEC_SBC_CORE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+@file
+Declarations of codec functions, data types, and macros.
+
+@ingroup codec_lib
+*/
+
+/**
+@addtogroup codec_lib
+@{
+*/
+
+/* Non-BM3 users of of the codec must include oi_codec_sbc_bm3defs.h prior to
+ * including this file, or else these includes will fail because the BM3 SDK is
+ * not in the include path */
+#ifndef _OI_CODEC_SBC_BM3DEFS_H
+#include "oi_stddefs.h"
+#include "oi_status.h"
+#endif
+
+#include <stdint.h>
+
+#define SBC_MAX_CHANNELS 2
+#define SBC_MAX_BANDS 8
+#define SBC_MAX_BLOCKS 16
+#define SBC_MIN_BITPOOL 2   /**< Minimum size of the bit allocation pool used to encode the stream */
+#define SBC_MAX_BITPOOL 250 /**< Maximum size of the bit allocation pool used to encode the stream */
+#define SBC_MAX_ONE_CHANNEL_BPS 320000
+#define SBC_MAX_TWO_CHANNEL_BPS 512000
+
+
+#define SBC_WBS_BITRATE 62000
+#define SBC_WBS_BITPOOL 27
+#define SBC_WBS_NROF_BLOCKS 16
+#define SBC_WBS_FRAME_LEN 62
+#define SBC_WBS_SAMPLES_PER_FRAME 128
+
+
+#define SBC_HEADER_LEN 4
+#define SBC_MAX_FRAME_LEN (SBC_HEADER_LEN + \
+                             ((SBC_MAX_BANDS * SBC_MAX_CHANNELS / 2) + \
+                              (SBC_MAX_BANDS + SBC_MAX_BLOCKS * SBC_MAX_BITPOOL + 7)/8))
+#define SBC_MAX_SAMPLES_PER_FRAME   (SBC_MAX_BANDS * SBC_MAX_BLOCKS)
+
+#define SBC_MAX_SCALEFACTOR_BYTES ((4*(SBC_MAX_CHANNELS * SBC_MAX_BANDS) + 7)/8)
+
+#define OI_SBC_SYNCWORD 0x9c
+#define OI_SBC_ENHANCED_SYNCWORD 0x9d
+
+/**@name Sampling frequencies */
+/**@{*/
+#define SBC_FREQ_16000 0 /**< The sampling frequency is 16 kHz. One possible value for the @a frequency parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_FREQ_32000 1 /**< The sampling frequency is 32 kHz. One possible value for the @a frequency parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_FREQ_44100 2 /**< The sampling frequency is 44.1 kHz. One possible value for the @a frequency parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_FREQ_48000 3 /**< The sampling frequency is 48 kHz. One possible value for the @a frequency parameter of OI_CODEC_SBC_EncoderConfigure() */
+/**@}*/
+
+/**@name Channel modes */
+/**@{*/
+#define SBC_MONO 0         /**< The mode of the encoded channel is mono. One possible value for the @a mode parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_DUAL_CHANNEL 1 /**< The mode of the encoded channel is dual-channel. One possible value for the @a mode parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_STEREO 2       /**< The mode of the encoded channel is stereo. One possible value for the @a mode parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_JOINT_STEREO 3 /**< The mode of the encoded channel is joint stereo. One possible value for the @a mode parameter of OI_CODEC_SBC_EncoderConfigure() */
+/**@}*/
+
+/**@name Subbands */
+/**@{*/
+#define SBC_SUBBANDS_4  0 /**< The encoded stream has 4 subbands. One possible value for the @a subbands parameter of OI_CODEC_SBC_EncoderConfigure()*/
+#define SBC_SUBBANDS_8  1 /**< The encoded stream has 8 subbands. One possible value for the @a subbands parameter of OI_CODEC_SBC_EncoderConfigure() */
+/**@}*/
+
+/**@name Block lengths */
+/**@{*/
+#define SBC_BLOCKS_4    0 /**< A block size of 4 blocks was used to encode the stream. One possible value for the @a blocks parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_BLOCKS_8    1 /**< A block size of 8 blocks was used to encode the stream is. One possible value for the @a blocks parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_BLOCKS_12   2 /**< A block size of 12 blocks was used to encode the stream. One possible value for the @a blocks parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_BLOCKS_16   3 /**< A block size of 16 blocks was used to encode the stream. One possible value for the @a blocks parameter of OI_CODEC_SBC_EncoderConfigure() */
+/**@}*/
+
+/**@name Bit allocation methods */
+/**@{*/
+#define SBC_LOUDNESS 0    /**< The bit allocation method. One possible value for the @a loudness parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_SNR 1         /**< The bit allocation method. One possible value for the @a loudness parameter of OI_CODEC_SBC_EncoderConfigure() */
+/**@}*/
+
+/**
+@}
+
+@addtogroup codec_internal
+@{
+*/
+
+typedef int16_t SBC_BUFFER_T;
+
+
+/** Used internally. */
+typedef struct {
+    uint16_t frequency;    /**< The sampling frequency. Input parameter. */
+    uint8_t freqIndex;
+
+    uint8_t nrof_blocks;   /**< The block size used to encode the stream. Input parameter. */
+    uint8_t blocks;
+
+
+    uint8_t nrof_subbands; /**< The number of subbands of the encoded stream. Input parameter. */
+    uint8_t subbands;
+
+    uint8_t mode;          /**< The mode of the encoded channel. Input parameter. */
+    uint8_t nrof_channels; /**< The number of channels of the encoded stream. */
+
+    uint8_t alloc;         /**< The bit allocation method. Input parameter. */
+    uint8_t bitpool;       /**< Size of the bit allocation pool used to encode the stream. Input parameter. */
+    uint8_t crc;           /**< Parity check byte used for error detection. */
+    uint8_t join;          /**< Whether joint stereo has been used. */
+    uint8_t enhanced;
+    uint8_t min_bitpool;   /**< This value is only used when encoding. SBC_MAX_BITPOOL if variable
+                                 bitpools are disallowed, otherwise the minimum bitpool size that will
+                                 be used by the bit allocator.  */
+
+    uint8_t cachedInfo;    /**< Information about the previous frame */
+} OI_CODEC_SBC_FRAME_INFO;
+
+/** Used internally. */
+typedef struct {
+    const OI_CHAR *codecInfo;
+    OI_CODEC_SBC_FRAME_INFO frameInfo;
+    int8_t scale_factor[SBC_MAX_CHANNELS*SBC_MAX_BANDS];
+    uint32_t frameCount;
+    int32_t *subdata;
+
+    SBC_BUFFER_T *filterBuffer[SBC_MAX_CHANNELS];
+    int32_t filterBufferLen;
+    OI_UINT filterBufferOffset;
+
+    union {
+        uint8_t uint8[SBC_MAX_CHANNELS*SBC_MAX_BANDS];
+        uint32_t uint32[SBC_MAX_CHANNELS*SBC_MAX_BANDS/4];
+    } bits;
+    uint8_t maxBitneed;    /**< Running maximum bitneed */
+    OI_BYTE formatByte;
+    uint8_t pcmStride;
+    uint8_t maxChannels;
+} OI_CODEC_SBC_COMMON_CONTEXT;
+
+
+/*
+ * A smaller value reduces RAM usage at the expense of increased CPU usage. Values in the range
+ * 27..50 are recommended, beyond 50 there is a diminishing return on reduced CPU usage.
+ */
+#define SBC_CODEC_MIN_FILTER_BUFFERS 16
+#define SBC_CODEC_FAST_FILTER_BUFFERS 27
+
+/* Expands to the number of uint32_ts needed to ensure enough memory to encode
+ * or decode streams of numChannels channels, using numBuffers buffers.
+ * Example:
+ * uint32_t decoderData[CODEC_DATA_WORDS(SBC_MAX_CHANNELS, SBC_DECODER_FAST_SYNTHESIS_BUFFERS)];
+ * */
+#define CODEC_DATA_WORDS(numChannels, numBuffers) \
+    ((\
+        (sizeof(int32_t) * SBC_MAX_BLOCKS * (numChannels) * SBC_MAX_BANDS) \
+         + (sizeof(SBC_BUFFER_T) * SBC_MAX_CHANNELS * SBC_MAX_BANDS * (numBuffers)) \
+         + (sizeof (uint32_t) - 1) \
+    ) / sizeof(uint32_t))
+
+/** Opaque parameter to decoding functions; maintains decoder context. */
+typedef struct {
+    OI_CODEC_SBC_COMMON_CONTEXT common;
+    uint8_t limitFrameFormat;              /* Boolean, set by OI_CODEC_SBC_DecoderLimit() */
+    uint8_t restrictSubbands;
+    uint8_t enhancedEnabled;
+    uint8_t bufferedBlocks;
+} OI_CODEC_SBC_DECODER_CONTEXT;
+
+typedef struct {
+    uint32_t data[CODEC_DATA_WORDS(1, SBC_CODEC_FAST_FILTER_BUFFERS)];
+} OI_CODEC_SBC_CODEC_DATA_MONO;
+
+typedef struct {
+    uint32_t data[CODEC_DATA_WORDS(2, SBC_CODEC_FAST_FILTER_BUFFERS)];
+} OI_CODEC_SBC_CODEC_DATA_STEREO;
+
+/**
+@}
+
+@addtogroup codec_lib
+@{
+*/
+
+/**
+ * This function resets the decoder. The context must be reset when
+ * changing streams, or if the following stream parameters change:
+ * number of subbands, stereo mode, or frequency.
+ *
+ * @param context   Pointer to the decoder context structure to be reset.
+ *
+ * @param enhanced  If true, enhanced SBC operation is enabled. If enabled,
+ *                  the codec will recognize the alternative syncword for
+ *                  decoding an enhanced SBC stream. Enhancements should not
+ *                  be enabled unless the stream is known to be generated
+ *                  by an enhanced encoder, or there is a small possibility
+ *                  for decoding glitches if synchronization were to be lost.
+ */
+OI_STATUS OI_CODEC_SBC_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT *context,
+                                    uint32_t *decoderData,
+                                    uint32_t decoderDataBytes,
+                                    uint8_t maxChannels,
+                                    uint8_t pcmStride,
+                                    OI_BOOL enhanced);
+
+/**
+ * This function restricts the kind of SBC frames that the Decoder will
+ * process.  Its use is optional.  If used, it must be called after
+ * calling OI_CODEC_SBC_DecoderReset(). After it is called, any calls
+ * to OI_CODEC_SBC_DecodeFrame() with SBC frames that do not conform
+ * to the Subband and Enhanced SBC setting will be rejected with an
+ * OI_STATUS_INVALID_PARAMETERS return.
+ *
+ * @param context   Pointer to the decoder context structure to be limited.
+ *
+ * @param enhanced  If true, all frames passed to the decoder must be
+ *                  Enhanced SBC frames. If false, all frames must be
+ *                  standard SBC frames.
+ *
+ * @param subbands  May be set to SBC_SUBBANDS_4 or SBC_SUBBANDS_8. All
+ *                  frames passed to the decoder must be encoded with
+ *                  the requested number of subbands.
+ *
+ */
+OI_STATUS OI_CODEC_SBC_DecoderLimit(OI_CODEC_SBC_DECODER_CONTEXT *context,
+                                    OI_BOOL enhanced,
+                                    uint8_t subbands);
+
+/**
+ * This function sets the decoder parameters for a raw decode where the decoder parameters are not
+ * available in the sbc data stream. OI_CODEC_SBC_DecoderReset must be called
+ * prior to calling this function.
+ *
+ * @param context        Decoder context structure. This must be the context must be
+ *                       used each time a frame is decoded.
+ *
+ * @param enhanced       Set to true to enable Qualcomm proprietary
+ *                       quality enhancements.
+ *
+ * @param frequency      One of SBC_FREQ_16000, SBC_FREQ_32000, SBC_FREQ_44100,
+ *                       SBC_FREQ_48000
+ *
+ * @param mode           One of SBC_MONO, SBC_DUAL_CHANNEL, SBC_STEREO,
+ *                       SBC_JOINT_STEREO
+ *
+ * @param subbands       One of SBC_SUBBANDS_4, SBC_SUBBANDS_8
+ *
+ * @param blocks         One of SBC_BLOCKS_4, SBC_BLOCKS_8, SBC_BLOCKS_12,
+ *                       SBC_BLOCKS_16
+ *
+ * @param alloc          One of SBC_LOUDNESS, SBC_SNR
+ *
+ * @param maxBitpool     The maximum bitpool size for this context
+ */
+OI_STATUS OI_CODEC_SBC_DecoderConfigureRaw(OI_CODEC_SBC_DECODER_CONTEXT *context,
+                                           OI_BOOL enhanced,
+                                           uint8_t frequency,
+                                           uint8_t mode,
+                                           uint8_t subbands,
+                                           uint8_t blocks,
+                                           uint8_t alloc,
+                                           uint8_t maxBitpool);
+
+/**
+ * Decode one SBC frame. The frame has no header bytes. The context must have been previously
+ * initialized by calling  OI_CODEC_SBC_DecoderConfigureRaw().
+ *
+ * @param context       Pointer to a decoder context structure. The same context
+ *                      must be used each time when decoding from the same stream.
+ *
+ * @param bitpool       The actual bitpool size for this frame. Must be <= the maxbitpool specified
+ *                      in the call to OI_CODEC_SBC_DecoderConfigureRaw(),
+ *
+ * @param frameData     Address of a pointer to the SBC data to decode. This
+ *                      value will be updated to point to the next frame after
+ *                      successful decoding.
+ *
+ * @param frameBytes    Pointer to a uint32_t containing the number of available
+ *                      bytes of frame data. This value will be updated to reflect
+ *                      the number of bytes remaining after a decoding operation.
+ *
+ * @param pcmData       Address of an array of int16_t pairs, which will be
+ *                      populated with the decoded audio data. This address
+ *                      is not updated.
+ *
+ * @param pcmBytes      Pointer to a uint32_t in/out parameter. On input, it
+ *                      should contain the number of bytes available for pcm
+ *                      data. On output, it will contain the number of bytes
+ *                      written. Note that this differs from the semantics of
+ *                      frameBytes.
+ */
+OI_STATUS OI_CODEC_SBC_DecodeRaw(OI_CODEC_SBC_DECODER_CONTEXT *context,
+                                 uint8_t bitpool,
+                                 const OI_BYTE **frameData,
+                                 uint32_t *frameBytes,
+                                 int16_t *pcmData,
+                                 uint32_t *pcmBytes);
+
+/**
+ * Decode one SBC frame.
+ *
+ * @param context       Pointer to a decoder context structure. The same context
+ *                      must be used each time when decoding from the same stream.
+ *
+ * @param frameData     Address of a pointer to the SBC data to decode. This
+ *                      value will be updated to point to the next frame after
+ *                      successful decoding.
+ *
+ * @param frameBytes    Pointer to a uint32_t containing the number of available
+ *                      bytes of frame data. This value will be updated to reflect
+ *                      the number of bytes remaining after a decoding operation.
+ *
+ * @param pcmData       Address of an array of int16_t pairs, which will be
+ *                      populated with the decoded audio data. This address
+ *                      is not updated.
+ *
+ * @param pcmBytes      Pointer to a uint32_t in/out parameter. On input, it
+ *                      should contain the number of bytes available for pcm
+ *                      data. On output, it will contain the number of bytes
+ *                      written. Note that this differs from the semantics of
+ *                      frameBytes.
+ */
+OI_STATUS OI_CODEC_SBC_DecodeFrame(OI_CODEC_SBC_DECODER_CONTEXT *context,
+                                   const OI_BYTE **frameData,
+                                   uint32_t *frameBytes,
+                                   int16_t *pcmData,
+                                   uint32_t *pcmBytes);
+
+/**
+ * Calculate the number of SBC frames but don't decode. CRC's are not checked,
+ * but the Sync word is found prior to count calculation.
+ *
+ * @param frameData     Pointer to the SBC data.
+ *
+ * @param frameBytes    Number of bytes avaiable in the frameData buffer
+ *
+ */
+uint8_t OI_CODEC_SBC_FrameCount(OI_BYTE  *frameData,
+                                 uint32_t frameBytes);
+
+/**
+ * Analyze an SBC frame but don't do the decode.
+ *
+ * @param context       Pointer to a decoder context structure. The same context
+ *                      must be used each time when decoding from the same stream.
+ *
+ * @param frameData     Address of a pointer to the SBC data to decode. This
+ *                      value will be updated to point to the next frame after
+ *                      successful decoding.
+ *
+ * @param frameBytes    Pointer to a uint32_t containing the number of available
+ *                      bytes of frame data. This value will be updated to reflect
+ *                      the number of bytes remaining after a decoding operation.
+ *
+ */
+OI_STATUS OI_CODEC_SBC_SkipFrame(OI_CODEC_SBC_DECODER_CONTEXT *context,
+                                 const OI_BYTE **frameData,
+                                 uint32_t *frameBytes);
+
+/* Common functions */
+
+/**
+  Calculate the frame length.
+
+  @param frame The frame whose length to calculate
+
+  @return the length of an individual encoded frame in
+  bytes
+  */
+uint16_t OI_CODEC_SBC_CalculateFramelen(OI_CODEC_SBC_FRAME_INFO *frame);
+
+
+/**
+ * Calculate the maximum bitpool size that fits within a given frame length.
+ *
+ * @param frame     The frame to calculate the bitpool size for
+ * @param frameLen  The frame length to fit the bitpool to
+ *
+ * @return the maximum bitpool that will fit in the specified frame length
+ */
+uint16_t OI_CODEC_SBC_CalculateBitpool(OI_CODEC_SBC_FRAME_INFO *frame,
+                                        uint16_t frameLen);
+
+/**
+  Calculate the bit rate.
+
+  @param frame The frame whose bit rate to calculate
+
+  @return the approximate bit rate in bits per second,
+  assuming that stream parameters are constant
+  */
+uint32_t OI_CODEC_SBC_CalculateBitrate(OI_CODEC_SBC_FRAME_INFO *frame);
+
+/**
+  Calculate decoded audio data length for one frame.
+
+  @param frame The frame whose audio data length to calculate
+
+  @return length of decoded audio data for a
+  single frame, in bytes
+  */
+uint16_t OI_CODEC_SBC_CalculatePcmBytes(OI_CODEC_SBC_COMMON_CONTEXT *common);
+
+/**
+ * Get the codec version text.
+ *
+ * @return  pointer to text string containing codec version text
+ *
+ */
+OI_CHAR *OI_CODEC_Version(void);
+
+
+/**
+@}
+
+@addtogroup codec_internal
+@{
+*/
+
+extern const OI_CHAR* const OI_CODEC_SBC_FreqText[];
+extern const OI_CHAR* const OI_CODEC_SBC_ModeText[];
+extern const OI_CHAR* const OI_CODEC_SBC_SubbandsText[];
+extern const OI_CHAR* const OI_CODEC_SBC_BlocksText[];
+extern const OI_CHAR* const OI_CODEC_SBC_AllocText[];
+
+/**
+@}
+
+@addtogroup codec_lib
+@{
+*/
+
+#ifdef OI_DEBUG
+void OI_CODEC_SBC_DumpConfig(OI_CODEC_SBC_FRAME_INFO *frameInfo);
+#else
+#define OI_CODEC_SBC_DumpConfig(f)
+#endif
+
+/**
+@}
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _OI_CODEC_SBC_CORE_H */
+
+
diff --git a/bt/embdrv/sbc/decoder/include/oi_codec_sbc_private.h b/bt/embdrv/sbc/decoder/include/oi_codec_sbc_private.h
new file mode 100644
index 0000000..e768a3d
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/include/oi_codec_sbc_private.h
@@ -0,0 +1,229 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_CODEC_SBC_PRIVATE_H
+#define _OI_CODEC_SBC_PRIVATE_H
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+/**
+@file
+Function prototypes and macro definitions used internally by the codec.
+
+@ingroup codec_internal
+*/
+
+/**
+@addtogroup codec_internal
+@{
+*/
+
+#ifdef USE_RESTRICT_KEYWORD
+#define RESTRICT restrict
+#else
+#define RESTRICT
+#endif
+
+#ifdef CODEC_DEBUG
+#include <stdio.h>
+#define ERROR(x) do { printf x; printf("\n"); } while (0)
+#else
+#define ERROR(x)
+#endif
+
+#ifdef TRACE_EXECUTION
+#define TRACE(x) do { printf x; printf("\n"); } while (0)
+#else
+#define TRACE(x)
+#endif
+
+#ifndef PRIVATE
+#define PRIVATE
+#endif
+
+#ifndef INLINE
+#define INLINE
+#endif
+
+#include "oi_assert.h"
+#include "oi_codec_sbc.h"
+
+#ifndef OI_SBC_SYNCWORD
+#define OI_SBC_SYNCWORD 0x9c
+#endif
+
+#ifndef DIVIDE
+#define DIVIDE(a, b) ((a) / (b))
+#endif
+
+typedef union {
+    uint8_t uint8[SBC_MAX_BANDS];
+    uint32_t uint32[SBC_MAX_BANDS / 4];
+} BITNEED_UNION1;
+
+typedef union {
+    uint8_t uint8[2 * SBC_MAX_BANDS];
+    uint32_t uint32[2 * SBC_MAX_BANDS / 4];
+} BITNEED_UNION2;
+
+static const uint16_t freq_values[] =    { 16000, 32000, 44100, 48000 };
+static const uint8_t block_values[] =    { 4, 8, 12, 16 };
+static const uint8_t channel_values[] =  { 1, 2, 2, 2 };
+static const uint8_t band_values[] =     { 4, 8 };
+
+
+#define TEST_MODE_SENTINEL "OINA"
+#define TEST_MODE_SENTINEL_LENGTH 4
+
+/** Used internally. */
+typedef struct {
+    union {
+        const uint8_t *r;
+        uint8_t *w;
+    } ptr;
+    uint32_t value;
+    OI_UINT bitPtr;
+} OI_BITSTREAM;
+
+
+#define VALID_INT16(x) (((x) >= OI_INT16_MIN) && ((x) <= OI_INT16_MAX))
+#define VALID_INT32(x) (((x) >= OI_INT32_MIN) && ((x) <= OI_INT32_MAX))
+
+#define DCTII_8_SHIFT_IN 0
+#define DCTII_8_SHIFT_OUT (16-DCTII_8_SHIFT_IN)
+
+#define DCTII_8_SHIFT_0 (DCTII_8_SHIFT_OUT)
+#define DCTII_8_SHIFT_1 (DCTII_8_SHIFT_OUT)
+#define DCTII_8_SHIFT_2 (DCTII_8_SHIFT_OUT)
+#define DCTII_8_SHIFT_3 (DCTII_8_SHIFT_OUT)
+#define DCTII_8_SHIFT_4 (DCTII_8_SHIFT_OUT)
+#define DCTII_8_SHIFT_5 (DCTII_8_SHIFT_OUT)
+#define DCTII_8_SHIFT_6 (DCTII_8_SHIFT_OUT-1)
+#define DCTII_8_SHIFT_7 (DCTII_8_SHIFT_OUT-2)
+
+#define DCT_SHIFT 15
+
+#define DCTIII_4_SHIFT_IN 2
+#define DCTIII_4_SHIFT_OUT 15
+
+#define DCTIII_8_SHIFT_IN 3
+#define DCTIII_8_SHIFT_OUT 14
+
+OI_UINT computeBitneed(OI_CODEC_SBC_COMMON_CONTEXT *common,
+                              uint8_t *bitneeds,
+                              OI_UINT ch,
+                              OI_UINT *preferredBitpool);
+
+void oneChannelBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT *common,
+                                    BITNEED_UNION1 *bitneeds,
+                                    OI_UINT ch,
+                                    OI_UINT bitcount);
+
+
+OI_INT adjustToFitBitpool(const OI_UINT bitpool,
+                                 uint32_t *bitneeds,
+                                 const OI_UINT subbands,
+                                 OI_UINT bitcount,
+                                 OI_UINT *excess);
+
+INLINE OI_INT allocAdjustedBits(uint8_t *dest,
+                                OI_INT bits,
+                                OI_INT excess);
+
+INLINE OI_INT allocExcessBits(uint8_t *dest,
+                              OI_INT excess);
+
+PRIVATE uint32_t internal_CalculateBitrate(OI_CODEC_SBC_FRAME_INFO *frame);
+
+PRIVATE uint16_t internal_CalculateFramelen(OI_CODEC_SBC_FRAME_INFO *frame);
+
+void monoBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT *common);
+
+typedef void (*BIT_ALLOC)(OI_CODEC_SBC_COMMON_CONTEXT *common);
+
+PRIVATE OI_STATUS internal_DecodeRaw(OI_CODEC_SBC_DECODER_CONTEXT *context,
+                                     uint8_t bitpool,
+                                     const OI_BYTE **frameData,
+                                     uint32_t *frameBytes,
+                                     int16_t *pcmData,
+                                     uint32_t *pcmBytes);
+
+INLINE OI_STATUS internal_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT *context,
+                                       uint32_t *decoderData,
+                                       uint32_t decoderDataBytes,
+                                       OI_BYTE maxChannels,
+                                       OI_BYTE pcmStride,
+                                       OI_BOOL enhanced);
+
+INLINE uint16_t OI_SBC_CalculateFrameAndHeaderlen(OI_CODEC_SBC_FRAME_INFO *frame, OI_UINT *headerLen_);
+
+PRIVATE uint32_t OI_SBC_MaxBitpool(OI_CODEC_SBC_FRAME_INFO *frame);
+
+PRIVATE void OI_SBC_ComputeBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT *frame);
+PRIVATE uint8_t OI_SBC_CalculateChecksum(OI_CODEC_SBC_FRAME_INFO *frame, OI_BYTE const *data);
+
+/* Transform functions */
+PRIVATE void shift_buffer(SBC_BUFFER_T *dest, SBC_BUFFER_T *src, OI_UINT wordCount);
+PRIVATE void cosineModulateSynth4(SBC_BUFFER_T * RESTRICT out, int32_t const * RESTRICT in);
+PRIVATE void SynthWindow40_int32_int32_symmetry_with_sum(int16_t *pcm, SBC_BUFFER_T buffer[80], OI_UINT strideShift);
+
+INLINE void dct3_4(int32_t * RESTRICT out, int32_t const * RESTRICT in);
+PRIVATE void analyze4_generated(SBC_BUFFER_T analysisBuffer[RESTRICT 40],
+                                int16_t *pcm,
+                                OI_UINT strideShift,
+                                int32_t subband[4]);
+
+INLINE void dct3_8(int32_t * RESTRICT out, int32_t const * RESTRICT in);
+
+PRIVATE void analyze8_generated(SBC_BUFFER_T analysisBuffer[RESTRICT 80],
+                                int16_t *pcm,
+                                OI_UINT strideShift,
+                                int32_t subband[8]);
+
+#ifdef SBC_ENHANCED
+PRIVATE void analyze8_enhanced_generated(SBC_BUFFER_T analysisBuffer[RESTRICT 112],
+                                         int16_t *pcm,
+                                         OI_UINT strideShift,
+                                         int32_t subband[8]);
+#endif
+
+/* Decoder functions */
+
+INLINE  void OI_SBC_ReadHeader(OI_CODEC_SBC_COMMON_CONTEXT *common, const OI_BYTE *data);
+PRIVATE void OI_SBC_ReadScalefactors(OI_CODEC_SBC_COMMON_CONTEXT *common, const OI_BYTE *b, OI_BITSTREAM *bs);
+PRIVATE void OI_SBC_ReadSamples(OI_CODEC_SBC_DECODER_CONTEXT *common, OI_BITSTREAM *ob);
+PRIVATE void OI_SBC_ReadSamplesJoint(OI_CODEC_SBC_DECODER_CONTEXT *common, OI_BITSTREAM *global_bs);
+PRIVATE void OI_SBC_SynthFrame(OI_CODEC_SBC_DECODER_CONTEXT *context, int16_t *pcm, OI_UINT start_block, OI_UINT nrof_blocks);
+INLINE int32_t OI_SBC_Dequant(uint32_t raw, OI_UINT scale_factor, OI_UINT bits);
+PRIVATE OI_BOOL OI_SBC_ExamineCommandPacket(OI_CODEC_SBC_DECODER_CONTEXT *context, const OI_BYTE *data, uint32_t len);
+PRIVATE void OI_SBC_GenerateTestSignal(int16_t pcmData[][2], uint32_t sampleCount);
+
+PRIVATE void OI_SBC_ExpandFrameFields(OI_CODEC_SBC_FRAME_INFO *frame);
+PRIVATE OI_STATUS OI_CODEC_SBC_Alloc(OI_CODEC_SBC_COMMON_CONTEXT *common,
+                                     uint32_t *codecDataAligned,
+                                     uint32_t codecDataBytes,
+                                     uint8_t maxChannels,
+                                     uint8_t pcmStride);
+/**
+@}
+*/
+
+#endif /* _OI_CODEC_SBC_PRIVATE_H */
+
diff --git a/bt/embdrv/sbc/decoder/include/oi_common.h b/bt/embdrv/sbc/decoder/include/oi_common.h
new file mode 100644
index 0000000..c4169f9
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/include/oi_common.h
@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_COMMON_H
+#define _OI_COMMON_H
+/**
+ * @file
+ *
+ * This file is used to group commonly used BLUEmagic 3.0 software
+ * header files.
+ *
+ * This file should be included in application source code along with the header
+ * files for the specific modules of the protocol stack being used.
+ */
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+#include "oi_bt_spec.h"
+#include "oi_stddefs.h"
+#include "oi_status.h"
+#include "oi_time.h"
+#include "oi_osinterface.h"
+
+
+/*****************************************************************************/
+#endif /* _OI_COMMON_H */
diff --git a/bt/embdrv/sbc/decoder/include/oi_cpu_dep.h b/bt/embdrv/sbc/decoder/include/oi_cpu_dep.h
new file mode 100644
index 0000000..49dd324
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/include/oi_cpu_dep.h
@@ -0,0 +1,267 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_CPU_DEP_H
+#define _OI_CPU_DEP_H
+
+#include <stdint.h>
+
+/**
+ * @file
+ * This file contains definitions for characteristics of the target CPU and
+ * compiler, including primitive data types and endianness.
+ *
+ * This file defines the byte order and primitive data types for various
+ * CPU families. The preprocessor symbol 'CPU' must be defined to be an
+ * appropriate value or this header will generate a compile-time error.
+ *
+ * @note The documentation for this header file uses the x86 family of processors
+ * as an illustrative example for CPU/compiler-dependent data type definitions.
+ * Go to the source code of this header file to see the details of primitive type
+ * definitions for each platform.
+ *
+ * Additional information is available in the @ref data_types_docpage section.
+ */
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \addtogroup Misc Miscellaneous APIs */
+/**@{*/
+
+/** @name Definitions indicating family of target OI_CPU_TYPE
+ *  @{
+ */
+
+#define OI_CPU_X86         1 /**< x86 processor family */
+#define OI_CPU_ARM         2 /**< ARM processor family.
+                                  @deprecated Use #OI_CPU_ARM7_LEND or
+                                  #OI_CPU_ARM7_BEND. */
+#define OI_CPU_ARC         3 /**< ARC processor family.
+                                  @deprecated Use #OI_CPU_ARC_LEND or
+                                  #OI_CPU_ARC_BEND. */
+#define OI_CPU_SH3         4 /**< Hitachi SH-3 processor family */
+#define OI_CPU_H8          5 /**< Hitachi H8 processor family */
+#define OI_CPU_MIPS        6 /**< MIPS processor family */
+#define OI_CPU_SPARC       7 /**< SPARC processor family */
+#define OI_CPU_M68000      8 /**< Motorola M68000 processor family */
+#define OI_CPU_PPC         9 /**< PowerPC (PPC) processor family */
+#define OI_CPU_SH4_7750   10 /**< Hitachi SH7750 series in SH-4 processor family */
+#define OI_CPU_SH2        11 /**< Hitachi SH-2 processor family */
+#define OI_CPU_ARM7_LEND  12 /**< ARM7, little-endian */
+#define OI_CPU_ARM7_BEND  13 /**< ARM7, big-endian */
+#define OI_CPU_GDM1202    14 /**< GCT GDM1202 */
+#define OI_CPU_ARC_LEND   15 /**< ARC processor family, little-endian */
+#define OI_CPU_ARC_BEND   16 /**< ARC processor family, big-endian */
+#define OI_CPU_M30833F    17 /**< Mitsubishi M308 processor family */
+#define OI_CPU_CR16C      18 /**< National Semiconductor 16 bit processor family */
+#define OI_CPU_M64111     19 /**< Renesas M64111 processor (M32R family) */
+#define OI_CPU_ARMV5_LEND 20 //*< ARM5, little-endian */
+
+#define OI_CPU_TYPE 12
+
+#ifndef OI_CPU_TYPE
+    #error "OI_CPU_TYPE type not defined"
+#endif
+
+/**@}*/
+
+
+/** @name Definitions indicating byte-wise endianness of target CPU
+ *  @{
+ */
+
+#define OI_BIG_ENDIAN_BYTE_ORDER    0  /**< Multiple-byte values are stored in memory beginning with the most significant byte at the lowest address.  */
+#define OI_LITTLE_ENDIAN_BYTE_ORDER 1  /**< Multiple-byte values are stored in memory beginning with the least significant byte at the lowest address. */
+
+/**@}*/
+
+
+/** @name  CPU/compiler-independent primitive data type definitions
+ *  @{
+ */
+
+typedef int             OI_BOOL;  /**< Boolean values use native integer data type for target CPU. */
+typedef int             OI_INT;   /**< Integer values use native integer data type for target CPU. */
+typedef unsigned int    OI_UINT;  /**< Unsigned integer values use native unsigned integer data type for target CPU. */
+typedef unsigned char   OI_BYTE;  /**< Raw bytes type uses native character data type for target CPU. */
+typedef uint32_t OI_ELEMENT_UNION; /**< Type for first element of a union to support all data types up to pointer width. */
+
+/**@}*/
+
+
+
+/*********************************************************************************/
+
+#if OI_CPU_TYPE==OI_CPU_X86
+
+#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER  /**< x86 platform byte ordering is little-endian */
+
+#endif
+
+/*********************************************************************************/
+
+#if OI_CPU_TYPE==OI_CPU_ARM
+/* This CPU type is deprecated (removed from use). Instead, use OI_CPU_ARM7_LEND or OI_CPU_ARM7_BEND for
+   little-endian or big-endian configurations of the ARM7, respectively. */
+#error OI_CPU_ARM is deprecated
+#endif
+
+/*********************************************************************************/
+
+#if OI_CPU_TYPE==OI_CPU_ARC
+/* This CPU type is deprecated (removed from use). Instead, use OI_CPU_ARC_LEND or OI_CPU_ARC_BEND for
+   little-endian or big-endian configurations of the ARC, respectively. */
+#error OI_CPU_ARC is deprecated
+#endif
+
+/*********************************************************************************/
+
+#if OI_CPU_TYPE==OI_CPU_SH3
+/* The Hitachi SH C compiler defines _LIT or _BIG, depending on the endianness
+    specified to the compiler on the command line. */
+#if defined(_LIT)
+    #define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER  /**< If _LIT is defined, SH-3 platform byte ordering is little-endian. */
+#elif defined(_BIG)
+    #define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER     /**< If _BIG is defined, SH-3 platform byte ordering is big-endian. */
+#else
+    #error SH compiler endianness undefined
+#endif
+
+#endif
+/*********************************************************************************/
+
+#if OI_CPU_TYPE==OI_CPU_SH2
+
+#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER /**< SH-2 platform byte ordering is big-endian. */
+
+#endif
+/*********************************************************************************/
+
+#if OI_CPU_TYPE==OI_CPU_H8
+#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER
+#error basic types not defined
+#endif
+
+/*********************************************************************************/
+
+#if OI_CPU_TYPE==OI_CPU_MIPS
+#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER
+#endif
+
+/*********************************************************************************/
+
+#if OI_CPU_TYPE==OI_CPU_SPARC
+#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER
+#error basic types not defined
+#endif
+
+/*********************************************************************************/
+
+#if OI_CPU_TYPE==OI_CPU_M68000
+#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER  /**< M68000 platform byte ordering is big-endian. */
+#endif
+
+/*********************************************************************************/
+
+#if OI_CPU_TYPE==OI_CPU_PPC
+#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER
+#endif
+
+/*********************************************************************************/
+
+#if OI_CPU_TYPE==OI_CPU_SH4_7750
+#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER  /**< SH7750 platform byte ordering is big-endian. */
+#endif
+
+/*********************************************************************************/
+
+#if OI_CPU_TYPE==OI_CPU_ARM7_LEND
+#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER
+#endif
+
+/*********************************************************************************/
+
+#if OI_CPU_TYPE==OI_CPU_ARM7_BEND
+#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER
+#endif
+
+/*********************************************************************************/
+
+#if OI_CPU_TYPE==OI_CPU_GDM1202
+#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER
+#endif
+
+/*********************************************************************************/
+
+#if OI_CPU_TYPE==OI_CPU_ARC_LEND
+
+#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER
+#endif
+
+/*********************************************************************************/
+
+#if OI_CPU_TYPE==OI_CPU_ARC_BEND
+#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER
+#endif
+
+/*********************************************************************************/
+
+#if OI_CPU_TYPE==OI_CPU_M30833F
+#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER
+#endif
+
+/*********************************************************************************/
+
+#if OI_CPU_TYPE==OI_CPU_CR16C
+#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER
+#endif
+
+/*********************************************************************************/
+
+#if OI_CPU_TYPE==OI_CPU_M64111
+#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER
+#endif
+
+/*********************************************************************************/
+
+#if OI_CPU_TYPE==OI_CPU_ARMV5_LEND
+#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER
+#endif
+
+/*********************************************************************************/
+
+
+#ifndef OI_CPU_BYTE_ORDER
+    #error "Byte order (endian-ness) not defined"
+#endif
+
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+/*********************************************************************************/
+#endif /* _OI_CPU_DEP_H */
diff --git a/bt/embdrv/sbc/decoder/include/oi_modules.h b/bt/embdrv/sbc/decoder/include/oi_modules.h
new file mode 100644
index 0000000..a0b68dd
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/include/oi_modules.h
@@ -0,0 +1,171 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_MODULES_H
+#define _OI_MODULES_H
+/**
+ * @file
+ *
+ * Enumeration type defining the inidivual stack components.
+ *
+ */
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+
+/** \addtogroup Misc Miscellaneous APIs */
+/**@{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * This enumeration lists constants for referencing the components of
+ * the BLUEmagic 3.0 protocol stack, profiles, and other functionalities.
+ *
+ * In order to distinguish types of modules, items are grouped with markers to
+ * delineate start and end of the groups
+ *
+ * The module type is used for various purposes:
+ *      identification in debug print statements
+ *      access to initialization flags
+ *      access to the configuration table
+ */
+
+typedef enum {
+    /* profiles and protocols  --> Updates to oi_debug.c and oi_config_table.c */
+
+                                /*   XX --> Keep Enum values up-to-date! */
+    OI_MODULE_AT,               /**< 00 AT command processing */
+    OI_MODULE_A2DP,             /**< 01 Advanced Audio Distribution Profile */
+    OI_MODULE_AVCTP,            /**< 02 Audio-Visual Control Transport Profile */
+    OI_MODULE_AVDTP,            /**< 03 Audio-Visual Distribution Protocol */
+    OI_MODULE_AVRCP,            /**< 04 Audio-Visual Remote Control Profile */
+    OI_MODULE_BIP_CLI,          /**< 05 Basic Imaging Profile protocol client */
+    OI_MODULE_BIP_SRV,          /**< 06 Basic Imaging Profile protocol server */
+    OI_MODULE_BNEP,             /**< 07 Bluetooth Network Encapsulation Protocol */
+    OI_MODULE_BPP_SENDER,       /**< 08 Basic Printing Profile */
+    OI_MODULE_BPP_PRINTER,      /**< 09 Basic Printing Profile */
+    OI_MODULE_CTP,              /**< 10 Cordless Telephony Profile */
+    OI_MODULE_DUN,              /**< 11 Dial-Up Networking Profile */
+    OI_MODULE_FAX,              /**< 12 Fax Profile */
+    OI_MODULE_FTP_CLI,          /**< 13 File Transfer Profile protocol client */
+    OI_MODULE_FTP_SRV,          /**< 14 File Transfer Profile protocol server */
+    OI_MODULE_HANDSFREE,        /**< 15 Hands-Free Profile */
+    OI_MODULE_HANDSFREE_AG,     /**< 16 Hands-Free Profile */
+    OI_MODULE_HCRP_CLI,         /**< 17 Hardcopy Cable Replacement Profile */
+    OI_MODULE_HCRP_SRV,         /**< 18 Hardcopy Cable Replacement Profile */
+    OI_MODULE_HEADSET,          /**< 19 Headset Profile */
+    OI_MODULE_HEADSET_AG,       /**< 20 Headset Profile */
+    OI_MODULE_HID,              /**< 21 Human Interface Device profile */
+    OI_MODULE_INTERCOM,         /**< 22 Intercom Profile */
+    OI_MODULE_OBEX_CLI,         /**< 23 OBEX protocol client, Generic Object Exchange Profile */
+    OI_MODULE_OBEX_SRV,         /**< 24 OBEX protocol server, Generic Object Exchange Profile */
+    OI_MODULE_OPP_CLI,          /**< 25 Object Push Profile protocol client */
+    OI_MODULE_OPP_SRV,          /**< 26 Object Push Profile protocol server */
+    OI_MODULE_PAN,              /**< 27 PAN profile */
+    OI_MODULE_PBAP_CLI,         /**< 28 Phonebook Access Profile client */
+    OI_MODULE_PBAP_SRV,         /**< 29 Phonebook Access Profile server */
+    OI_MODULE_SAP_CLI,          /**< 30 SIM Access Profile */
+    OI_MODULE_SAP_SRV,          /**< 31 SIM Access Profile */
+    OI_MODULE_SPP,              /**< 32 Serial Port Profile */
+    OI_MODULE_SYNC_CLI,         /**< 33 Synchronization Profile */
+    OI_MODULE_SYNC_SRV,         /**< 34 Synchronization Profile */
+    OI_MODULE_SYNC_CMD_CLI,     /**< 35 Synchronization Profile */
+    OI_MODULE_SYNC_CMD_SRV,     /**< 36 Synchronization Profile */
+    OI_MODULE_SYNCML,           /**< 37 SyncML Profile */
+    OI_MODULE_TCS,              /**< 38 TCS Binary */
+    OI_MODULE_VDP,              /**< 39 Video Distribution Profile */
+
+    /* corestack components   --> Updates to oi_debug.c and oi_config_table.c */
+
+    OI_MODULE_COMMON_CONFIG,    /**< 40 Common configuration, module has no meaning other than for config struct */
+    OI_MODULE_CMDCHAIN,         /**< 41 Command chaining utility */
+    OI_MODULE_DISPATCH,         /**< 42 Dispatcher */
+    OI_MODULE_DATAELEM,         /**< 43 Data Elements, marshaller */
+    OI_MODULE_DEVMGR,           /**< 44 Device Manager */
+    OI_MODULE_DEVMGR_MODES,     /**< 45 Device Manager connectability/discoverability modes */
+    OI_MODULE_HCI,              /**< 46 Host Controller Interface command layer */
+    OI_MODULE_L2CAP,            /**< 47 L2CAP */
+    OI_MODULE_MEMMGR,           /**< 48 modules that do memory management */
+    OI_MODULE_POLICYMGR,        /**< 49 Policy Manager */
+    OI_MODULE_RFCOMM,           /**< 50 RFCOMM */
+    OI_MODULE_RFCOMM_SD,        /**< 51 RFCOMM Service discovery */
+    OI_MODULE_SDP_CLI,          /**< 52 Service Discovery Protocol client */
+    OI_MODULE_SDP_SRV,          /**< 53 Service Discovery Protocol server */
+    OI_MODULE_SDPDB,            /**< 54 Service Discovery Protocol database */
+    OI_MODULE_SECMGR,           /**< 55 Security Manager */
+    OI_MODULE_SNIFFLOG,         /**< 56 sniff log */
+    OI_MODULE_SUPPORT,          /**< 57 support functions, including CThru Dispatcher, time functions, and stack initialization */
+    OI_MODULE_TRANSPORT,        /**< 58 transport layer between HCI command layer and driver */
+    OI_MODULE_TEST,             /**< 59 used to debug output from internal test programs */
+    OI_MODULE_XML,              /**< 60 XML/CSS parser */
+
+    OI_MODULE_DI,               /**< 61 Device Identification Profile */
+
+    // bhapi components  --> Updates to oi_debug.c
+
+    OI_MODULE_BHAPI,            /**< 62 BLUEmagic Host API generic */
+    OI_MODULE_BHCLI,            /**< 63 BLUEmagic Host API client side */
+    OI_MODULE_BHSRV,            /**< 64 BLUEmagic Host API server side */
+    OI_MODULE_MSGQ,             /**< 65 module that handles message queuing */
+    OI_MODULE_BHAPI_TRANSPORT,  /**< 66 module that handles message queuing */
+    OI_MODULE_BLST_SRV,         /**< 67 module that provides server side BHAPI Lightweight Serial Transport */
+    OI_MODULE_BLST_CLI,         /**< 68 module that provides client side BHAPI Lightweight Serial Transport */
+
+    // OEM files --> Updates to oi_debug.c
+    OI_MODULE_OEM,              /**< 69 Application Memory allocation */
+
+    // Application glue --> Updates to oi_debug.c
+    OI_MODULE_APP,              /**< 70 Application Memory allocation */
+
+    /* various pieces of code depend on these last 2 elements occuring in a specific order:
+       OI_MODULE_ALL must be the 2nd to last element
+       OI_MODULE_UNKNOWN must be the last element
+       */
+    OI_MODULE_ALL,              /**< 71 special value identifying all modules - used for control of debug print statements */
+    OI_MODULE_UNKNOWN           /**< 72 special value - used for debug print statements */
+} OI_MODULE;
+
+/**
+ * This constant is the number of actual modules in the list.  ALL and UNKNOWN are
+ * special values that are not actually modules.
+ * Used for debug print and memmgr profiling
+ */
+#define OI_NUM_MODULES  OI_MODULE_ALL
+
+
+/**
+ * This constant is the number of profile and core components.  It is used to size
+ * the initialization and configuration tables.
+ */
+#define OI_NUM_STACK_MODULES    OI_MODULE_BHAPI
+
+
+#ifdef __cplusplus
+}
+#endif
+
+/**@}*/
+
+#endif /* _OI_MODULES_H */
+
diff --git a/bt/embdrv/sbc/decoder/include/oi_osinterface.h b/bt/embdrv/sbc/decoder/include/oi_osinterface.h
new file mode 100644
index 0000000..7ad8122
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/include/oi_osinterface.h
@@ -0,0 +1,197 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_OSINTERFACE_H
+#define _OI_OSINTERFACE_H
+/**
+ @file
+ * This file provides the platform-independent interface for functions for which
+ * implementation is platform-specific.
+ *
+ * The functions in this header file define the operating system or hardware
+ * services needed by the BLUEmagic 3.0 protocol stack. The
+ * actual implementation of these services is platform-dependent.
+ *
+ */
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+#include "oi_stddefs.h"
+#include "oi_time.h"
+#include "oi_status.h"
+#include "oi_modules.h"
+
+/** \addtogroup Misc Miscellaneous APIs */
+/**@{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * Terminates execution.
+ *
+ * @param reason  Reason for termination
+ */
+void OI_FatalError(OI_STATUS reason);
+
+/**
+ * This function logs an error.
+ *
+ * When built for release mode, BLUEmagic 3 errors are logged to
+ * this function. (in debug mode, errors are logged via
+ * OI_Print()).
+ *
+ * @param module Module in which the error was detected (see
+ *                oi_modules.h)
+ * @param lineno Line number of the C file OI_SLOG_ERROR called
+ * @param status Status code associated with the error event
+ */
+void OI_LogError(OI_MODULE module, OI_INT lineno, OI_STATUS status);
+
+/**
+ * This function initializes the debug code handling.
+ *
+ * When built for debug mode, this function performs platform
+ * dependent initialization to handle message codes passed in
+ * via OI_SetMsgCode().
+ */
+void OI_InitDebugCodeHandler(void);
+
+
+/**
+ * This function reads the time from the real time clock.
+ *
+ * All timing in BM3 is relative, typically a granularity
+ * of 5 or 10 msecs is adequate.
+ *
+ * @param[out] now  Pointer to the buffer to which the current
+ *       time will be returned
+ */
+void OI_Time_Now(OI_TIME *now);
+
+/**
+ * This function causes the current thread to sleep for the
+ * specified amount of time. This function must be called
+ * without the stack access token.
+ *
+ * @note BM3 corestack and profiles never suspend and never call
+ * OI_Sleep. The use of OI_Sleep is limited to applications and
+ * platform-specific code.
+ *
+ * If your port and applications never use OI_Sleep, this function can be left unimplemented.
+ *
+ * @param milliseconds  Number of milliseconds to sleep
+ */
+void OI_Sleep(uint32_t milliseconds);
+
+
+/**
+ * Defines for message type codes.
+ */
+#define OI_MSG_CODE_APPLICATION               0   /**< Application output */
+#define OI_MSG_CODE_ERROR                     1   /**< Error message output */
+#define OI_MSG_CODE_WARNING                   2   /**< Warning message output */
+#define OI_MSG_CODE_TRACE                     3   /**< User API function trace output */
+#define OI_MSG_CODE_PRINT1                    4   /**< Catagory 1 debug print output */
+#define OI_MSG_CODE_PRINT2                    5   /**< Catagory 2 debug print output */
+#define OI_MSG_CODE_HEADER                    6   /**< Error/Debug output header */
+
+/**
+ * This function is used to indicate the type of text being output with
+ * OI_Print(). For the Linux and Win32 platforms, it will set
+ * the color of the text. Other possible uses could be to insert
+ * HTML style tags, add some other message type indication, or
+ * be completely ignored altogether.
+ *
+ * @param code  OI_MSG_CODE_* indicating setting the message type.
+ */
+void OI_SetMsgCode(uint8_t code);
+
+/**
+ * All output from OI_Printf() and all debug output is sent to OI_Print.
+ * Typically, if the platform has a console, OI_Print() is sent to stdout.
+ * Embedded platforms typically send OI_Print() output to a serial port.
+ *
+ * @param str  String to print
+ */
+void OI_Print(OI_CHAR const *str);
+
+/**
+ *  In cases where OI_Print() is sending output to a logfile in addition to console,
+ *  it is desirable to also put console input into the logfile.
+ *  This function can be called by the console input process.
+ *
+ *  @note This is an optional API which is strictly
+ *  between the platform-specific stack_console and osinterface
+ *  modules. This API need only be implemented on those
+ *  platforms where is serves a useful purpose, e.g., win32.
+ *
+ * @param str  Console input string
+ */
+
+void OI_Print_ConsoleInput(OI_CHAR const *str);
+
+/**
+ *  This function computes the CRC16 of the program image.
+ */
+uint16_t  OI_ProgramImageCRC16(void);
+
+/**
+ * Writes an integer to stdout in hex. This macro is intended
+ * for selective use when debugging in small memory
+ * configurations or other times when it is not possible to use
+ * OI_DBGPRINT.
+ *
+ * @param n  the integer to print
+ */
+
+#define OI_Print_Int(n) \
+{ \
+    static const OI_CHAR _digits[] = "0123456789ABCDEF"; \
+    OI_CHAR _buf[9]; \
+    OI_CHAR *_str = &_buf[8]; \
+    uint32_t _i = n; \
+    *_str = 0; \
+    do { *(--_str) = _digits[(_i & 0xF)]; _i >>= 4; } while (_i); \
+    OI_Print(_str); \
+}
+
+/**
+ *  Application Dynamic Memory allocation.
+ *
+ *  These APIs are provided for application use on those
+ *  platforms which have no dynamic memory support. Memory is
+ *  allocated from the pool-based heap managed by the stack's
+ *  internal memory manager.
+ */
+void *OI_APP_Malloc(int32_t size);
+void OI_APP_Free(void *ptr);
+
+/*****************************************************************************/
+#ifdef __cplusplus
+}
+#endif
+
+/**@}*/
+
+#endif /* _OI_OSINTERFACE_H */
+
diff --git a/bt/embdrv/sbc/decoder/include/oi_status.h b/bt/embdrv/sbc/decoder/include/oi_status.h
new file mode 100644
index 0000000..868d8dc
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/include/oi_status.h
@@ -0,0 +1,579 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_STATUS_H
+#define _OI_STATUS_H
+/**
+ * @file
+ * This file contains status codes for BLUEmagic 3.0 software.
+ */
+
+#include "oi_stddefs.h"
+
+/** \addtogroup Misc Miscellaneous APIs */
+/**@{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+   /** test it **/
+
+/**
+ * OI_STATUS must fit in 16 bits, so status codes can range from 0 to 66535, inclusive.
+ */
+
+typedef enum {
+    OI_STATUS_SUCCESS                      = 0,   /**< function call succeeded alias for #OI_OK */
+    OI_OK                                  = 0,   /**< function call succeeded alias for #OI_STATUS_SUCCESS */
+    OI_STATUS_INVALID_PARAMETERS           = 101, /**< invalid function input parameters */
+    OI_STATUS_NOT_IMPLEMENTED              = 102, /**< attempt to use an unimplemented function */
+    OI_STATUS_NOT_INITIALIZED              = 103, /**< data not initialized */
+    OI_STATUS_NO_RESOURCES                 = 104, /**< generic resource allocation failure status */
+    OI_STATUS_INTERNAL_ERROR               = 105, /**< internal inconsistency */
+    OI_STATUS_OUT_OF_MEMORY                = 106, /**< generally, OI_Malloc failed */
+    OI_ILLEGAL_REENTRANT_CALL              = 107, /**< violation of non-reentrant module policy */
+    OI_STATUS_INITIALIZATION_FAILED        = 108, /**< module initialization failed */
+    OI_STATUS_INITIALIZATION_PENDING       = 109, /**< inititialization not yet complete */
+    OI_STATUS_NO_SCO_SUPPORT               = 110, /**< SCO operation rejected; system not configured for SCO */
+    OI_STATUS_OUT_OF_STATIC_MEMORY         = 111, /**< static malloc failed */
+    OI_TIMEOUT                             = 112, /**< generic timeout */
+    OI_OS_ERROR                            = 113, /**< some operating system error */
+    OI_FAIL                                = 114, /**< generic failure */
+    OI_STRING_FORMAT_ERROR                 = 115, /**< error in VarString formatting string */
+    OI_STATUS_PENDING                      = 116, /**< The operation is pending. */
+    OI_STATUS_INVALID_COMMAND              = 117, /**< The command was invalid. */
+    OI_BUSY_FAIL                           = 118, /**< command rejected due to busy */
+    OI_STATUS_ALREADY_REGISTERED           = 119, /**< The registration has already been performed. */
+    OI_STATUS_NOT_FOUND                    = 120, /**< The referenced resource was not found. */
+    OI_STATUS_NOT_REGISTERED               = 121, /**< not registered */
+    OI_STATUS_NOT_CONNECTED                = 122, /**< not connected */
+    OI_CALLBACK_FUNCTION_REQUIRED          = 123, /**< A callback function parameter was required. */
+    OI_STATUS_MBUF_OVERFLOW                = 124, /**< There is no room to add another buffer to an mbuf. */
+    OI_STATUS_MBUF_UNDERFLOW               = 125, /**< There was an attempt to pull too many bytes from an mbuf. */
+    OI_STATUS_CONNECTION_EXISTS            = 126, /**< connection exists */
+    OI_STATUS_NOT_CONFIGURED               = 127, /**< module not configured */
+    OI_LOWER_STACK_ERROR                   = 128, /**< An error was reported by lower stack API. This is used for embedded platforms. */
+    OI_STATUS_RESET_IN_PROGRESS            = 129, /**< Request failed/rejected because we're busy resetting. */
+    OI_STATUS_ACCESS_DENIED                = 130, /**< Generic access denied error. */
+    OI_STATUS_DATA_ERROR                   = 131, /**< Generic data error. */
+    OI_STATUS_INVALID_ROLE                 = 132, /**< The requested role was invalid. */
+    OI_STATUS_ALREADY_CONNECTED            = 133, /**< The requested connection is already established. */
+    OI_STATUS_PARSE_ERROR                  = 134, /**< Parse error */
+    OI_STATUS_END_OF_FILE                  = 135, /**< End of file */
+    OI_STATUS_READ_ERROR                   = 136, /**< Generic read error */
+    OI_STATUS_WRITE_ERROR                  = 137, /**< Generic write error */
+    OI_STATUS_NEGOTIATION_FAILURE          = 138, /**< Error in negotiation */
+    OI_STATUS_READ_IN_PROGRESS             = 139, /**< A read is already in progress */
+    OI_STATUS_ALREADY_INITIALIZED          = 140, /**< Initialization has already been done */
+    OI_STATUS_STILL_CONNECTED              = 141, /**< The service cannot be shutdown because there are still active connections. */
+    OI_STATUS_MTU_EXCEEDED                 = 142, /**< The packet is too big */
+    OI_STATUS_LINK_TERMINATED              = 143, /**< The link was terminated */
+    OI_STATUS_PIN_CODE_TOO_LONG            = 144, /**< Application gave us a pin code that is too long */
+    OI_STATUS_STILL_REGISTERED             = 145, /**< The service cannot be shutdown because there are still active registrations. */
+    OI_STATUS_SPEC_VIOLATION               = 146, /**< Some application behavior contrary to BT specifications */
+
+
+    OI_STATUS_PSM_ALREADY_REGISTERED       = 402, /**< L2CAP: The specified PSM has already been registered. */
+    OI_STATUS_INVALID_CID                  = 403, /**< L2CAP: CID is invalid or no longer valid (connection terminated) */
+    OI_STATUS_CID_NOT_FOUND                = 404, /**< L2CAP: CID does not represent a current connection */
+    OI_STATUS_CHANNEL_NOT_FOUND            = 406, /**< L2CAP: CID does not represent a current connection */
+    OI_STATUS_PSM_NOT_FOUND                = 407, /**< L2CAP: PSM not found */
+    OI_STATUS_INVALID_STATE                = 408, /**< L2CAP: invalid state */
+    OI_STATUS_WRITE_IN_PROGRESS            = 410, /**< L2CAP: write in progress */
+    OI_STATUS_INVALID_PACKET               = 411, /**< L2CAP: invalid packet */
+    OI_STATUS_SEND_COMPLETE                = 412, /**< L2CAP: send is complete */
+    OI_STATUS_INVALID_HANDLE               = 414, /**< L2CAP: handle is invalid */
+    OI_STATUS_GROUP_FULL                   = 418, /**< L2CAP: No more members can be added to the specified group. */
+    OI_STATUS_DEVICE_ALREADY_IN_GROUP      = 423, /**< L2CAP: The device already exists in the group. */
+    OI_STATUS_DUPLICATE_GROUP              = 425, /**< L2CAP: attempt to add more than one group */
+    OI_STATUS_EMPTY_GROUP                  = 426, /**< L2CAP: group is empty */
+    OI_STATUS_PACKET_NOT_FOUND             = 427, /**< L2CAP: packet not found */
+    OI_STATUS_BUFFER_TOO_SMALL             = 428, /**< L2CAP: The buffer size is too small. */
+    OI_STATUS_IDENTIFIER_NOT_FOUND         = 429, /**< L2CAP: identifier not found */
+
+    OI_L2CAP_DISCONNECT_LOWER_LAYER        = 430, /**< L2CAP: The lower level forced a disconnect. */
+    OI_L2CAP_DISCONNECT_REMOTE_REQUEST     = 431, /**< L2CAP: The remote device requested a disconnect. */
+    OI_L2CAP_GROUP_ADD_CONNECT_FAIL        = 433, /**< L2CAP: Group add connect faiL */
+    OI_L2CAP_GROUP_REMOVE_FAILURE          = 434, /**< L2CAP: Group remove failure */
+    OI_L2CAP_DATA_WRITE_ERROR_LINK_TERM    = 435, /**< L2CAP: Data write error LINK_TERM */
+    OI_L2CAP_DISCONNECT_LOCAL_REQUEST      = 436, /**< L2CAP: Disconnect local request */
+
+    OI_L2CAP_CONNECT_TIMEOUT               = 437, /**< L2CAP: Connect timeout */
+    OI_L2CAP_DISCONNECT_TIMEOUT            = 439, /**< L2CAP: Disconnect timeout */
+    OI_L2CAP_PING_TIMEOUT                  = 440, /**< L2CAP: Ping timeout */
+    OI_L2CAP_GET_INFO_TIMEOUT              = 441, /**< L2CAP: Get info timeout */
+    OI_L2CAP_INVALID_ADDRESS               = 444, /**< L2CAP: Invalid address */
+    OI_L2CAP_CMD_REJECT_RCVD               = 445, /**< L2CAP: remote sent us 'command reject' response */
+
+    OI_L2CAP_CONNECT_BASE                  = 450, /**< L2CAP: Connect base */
+    OI_L2CAP_CONNECT_PENDING               = 451, /**< L2CAP: Connect pending */
+    OI_L2CAP_CONNECT_REFUSED_INVALID_PSM   = 452, /**< L2CAP: Connect refused invalid PSM */
+    OI_L2CAP_CONNECT_REFUSED_SECURITY      = 453, /**< L2CAP: Connect refused security */
+    OI_L2CAP_CONNECT_REFUSED_NO_RESOURCES  = 454, /**< L2CAP: Connect refused no resources */
+
+    OI_L2CAP_CONFIG_BASE                   = 460, /**< L2CAP: Config base */
+    OI_L2CAP_CONFIG_FAIL_INVALID_PARAMETERS= 461, /**< L2CAP: Config fail invalid parameters */
+    OI_L2CAP_CONFIG_FAIL_NO_REASON         = 462, /**< L2CAP: Config fail no reason */
+    OI_L2CAP_CONFIG_FAIL_UNKNOWN_OPTIONS   = 463, /**< L2CAP: Config fail unknown options */
+
+    OI_L2CAP_GET_INFO_BASE                 = 470, /**< L2CAP: Get info base */
+    OI_L2CAP_GET_INFO_NOT_SUPPORTED        = 471, /**< L2CAP: Get info not supported */
+    OI_L2CAP_MTU_EXCEEDED                  = 472, /**< L2CAP: The MTU of the channel was exceeded */
+    OI_L2CAP_INVALID_PSM                   = 482, /**< L2CAP: Invalid PSM */
+    OI_L2CAP_INVALID_MTU                   = 483, /**< L2CAP: Invalid MTU */
+    OI_L2CAP_INVALID_FLUSHTO               = 484, /**< L2CAP: Invalid flush timeout */
+
+    OI_HCI_NO_SUCH_CONNECTION               = 601, /**< HCI: caller specified a non-existent connection handle */
+    OI_HCI_CB_LIST_FULL                     = 603, /**< HCI: callback list is full, cannot attempt to send command */
+    OI_HCI_EVENT_UNDERRUN                   = 605, /**< HCI: parsing event packet, premature end-of-parameters */
+    OI_HCI_UNKNOWN_EVENT_CODE               = 607, /**< HCI: event received - event code is unknown */
+    OI_HCI_BAD_EVENT_PARM_LEN               = 608, /**< HCI: event - parameter length is incorrect */
+    OI_HCI_CMD_QUEUE_FULL                   = 611, /**< HCI: command queue is full */
+    OI_HCI_SHORT_EVENT                      = 612, /**< HCI: event received, missing event code and/or parm len */
+    OI_HCI_TRANSMIT_NOT_READY               = 613, /**< HCI: ACL/SCO transmit request failed - busy or no buffers available */
+    OI_HCI_ORPHAN_SENT_EVENT                = 614, /**< HCI: got spurious 'sent' event from transport layer */
+    OI_HCI_CMD_TABLE_ERROR                  = 615, /**< HCI: inconsistency in the internal command table */
+    OI_HCI_UNKNOWN_CMD_ID                   = 616, /**< HCI: HciApi Command - unknown command id */
+    OI_HCI_UNEXPECTED_EVENT                 = 619, /**< HCI: event received which only occurs in response to our cmd */
+    OI_HCI_EVENT_TABLE_ERROR                = 620, /**< HCI: inconsistency in the internal event table */
+    OI_HCI_EXPECTED_EVENT_TIMOUT            = 621, /**< HCI: timed out waiting for an expected event */
+    OI_HCI_NO_CMD_DESC_FOR_OPCODE           = 622, /**< HCI: event opcode is not known */
+    OI_HCI_INVALID_OPCODE_ERROR             = 623, /**< HCI: command opcode is invalid */
+    OI_HCI_FLOW_CONTROL_DISABLED            = 624, /**< HCI: can not use host flow control APIs if disabled in configuration */
+    OI_HCI_TX_COMPLETE                      = 625, /**< HCI: packet delivery to Host Controler complete */
+    OI_HCI_TX_ERROR                         = 626, /**< HCI: failed to deliver packet to Host Controler */
+    OI_HCI_DEVICE_NOT_INITIALIZED           = 627, /**< HCI: commands from upper layers disallowed until device is up and running */
+    OI_HCI_UNSUPPORTED_COMMAND              = 628, /**< HCI: command requested is not supported by local device */
+    OI_HCI_PASSTHROUGH_ERROR                = 629, /**< HCI: Error processing passthrough command */
+    OI_HCI_PASSTHROUGH_ALREADY_SET          = 630, /**< HCI: Passthrough mode already enabled */
+    OI_HCI_RESET_FAILURE                    = 631, /**< HCI: failed to reset the device/baseband */
+    OI_HCI_TRANSPORT_RESET                  = 632, /**< HCI: some operation failed because of a reset in the transport */
+    OI_HCIERR_HCIIFC_INIT_FAILURE           = 633, /**< HCI: failed to initialize transport layer interface */
+
+    OI_HCIERR_FIRST_ERROR_VALUE                = 701, /**< marker for first HCI protocol error */
+    OI_HCIERR_UNKNOWN_HCI_COMMAND              = 701, /**< HCI: protocol error 0x01 */
+    OI_HCIERR_NO_CONNECTION                    = 702, /**< HCI: protocol error 0x02 */
+    OI_HCIERR_HARDWARE_FAILURE                 = 703, /**< HCI: protocol error 0x03 */
+    OI_HCIERR_PAGE_TIMEOUT                     = 704, /**< HCI: protocol error 0x04 */
+    OI_HCIERR_AUTHENTICATION_FAILURE           = 705, /**< HCI: protocol error 0x05 */
+    OI_HCIERR_KEY_MISSING                      = 706, /**< HCI: protocol error 0x06 */
+    OI_HCIERR_MEMORY_FULL                      = 707, /**< HCI: protocol error 0x07 */
+    OI_HCIERR_CONNECTION_TIMEOUT               = 708, /**< HCI: protocol error 0x08 */
+    OI_HCIERR_MAX_NUM_OF_CONNECTIONS           = 709, /**< HCI: protocol error 0x09 */
+    OI_HCIERR_MAX_NUM_OF_SCO_CONNECTIONS       = 710, /**< HCI: protocol error 0x0A */
+    OI_HCIERR_ACL_CONNECTION_ALREADY_EXISTS    = 711, /**< HCI: protocol error 0x0B */
+    OI_HCIERR_COMMAND_DISALLOWED               = 712, /**< HCI: protocol error 0x0C */
+    OI_HCIERR_HOST_REJECTED_RESOURCES          = 713, /**< HCI: protocol error 0x0D */
+    OI_HCIERR_HOST_REJECTED_SECURITY           = 714, /**< HCI: protocol error 0x0E */
+    OI_HCIERR_HOST_REJECTED_PERSONAL_DEVICE    = 715, /**< HCI: protocol error 0x0F */
+    OI_HCIERR_HOST_TIMEOUT                     = 716, /**< HCI: protocol error 0x10 */
+    OI_HCIERR_UNSUPPORTED                      = 717, /**< HCI: protocol error 0x11 */
+    OI_HCIERR_INVALID_PARAMETERS               = 718, /**< HCI: protocol error 0x12 */
+    OI_HCIERR_OTHER_END_USER_DISCONNECT        = 719, /**< HCI: protocol error 0x13 */
+    OI_HCIERR_OTHER_END_LOW_RESOURCES          = 720, /**< HCI: protocol error 0x14 */
+    OI_HCIERR_OTHER_END_POWERING_OFF           = 721, /**< HCI: protocol error 0x15 */
+    OI_HCIERR_CONNECTION_TERMINATED_LOCALLY    = 722, /**< HCI: protocol error 0x16 */
+    OI_HCIERR_REPEATED_ATTEMPTS                = 723, /**< HCI: protocol error 0x17 */
+    OI_HCIERR_PAIRING_NOT_ALLOWED              = 724, /**< HCI: protocol error 0x18 */
+    OI_HCIERR_UNKNOWN_LMP_PDU                  = 725, /**< HCI: protocol error 0x19 */
+    OI_HCIERR_UNSUPPORTED_REMOTE_FEATURE       = 726, /**< HCI: protocol error 0x1A */
+    OI_HCIERR_SCO_OFFSET_REJECTED              = 727, /**< HCI: protocol error 0x1B */
+    OI_HCIERR_SCO_INTERVAL_REJECTED            = 728, /**< HCI: protocol error 0x1C */
+    OI_HCIERR_SCO_AIR_MODE_REJECTED            = 729, /**< HCI: protocol error 0x1D */
+    OI_HCIERR_INVALID_LMP_PARMS                = 730, /**< HCI: protocol error 0x1E */
+    OI_HCIERR_UNSPECIFIED_ERROR                = 731, /**< HCI: protocol error 0x1F */
+    OI_HCIERR_UNSUPPORTED_LMP_PARAMETERS       = 732, /**< HCI: protocol error 0x20 */
+    OI_HCIERR_ROLE_CHANGE_NOT_ALLOWED          = 733, /**< HCI: protocol error 0x21 */
+    OI_HCIERR_LMP_RESPONSE_TIMEOUT             = 734, /**< HCI: protocol error 0x22 */
+    OI_HCIERR_LMP_ERROR_TRANS_COLLISION        = 735, /**< HCI: protocol error 0x23 */
+    OI_HCIERR_LMP_PDU_NOT_ALLOWED              = 736, /**< HCI: protocol error 0x24 */
+    OI_HCIERR_ENCRYPTION_MODE_NOT_ACCEPTABLE   = 737, /**< HCI: protocol error 0x25 */
+    OI_HCIERR_UNIT_KEY_USED                    = 738, /**< HCI: protocol error 0x26 */
+    OI_HCIERR_QOS_NOT_SUPPORTED                = 739, /**< HCI: protocol error 0x27 */
+    OI_HCIERR_INSTANT_PASSED                   = 740, /**< HCI: protocol error 0x28 */
+    OI_HCIERR_UNIT_KEY_PAIRING_UNSUPPORTED     = 741, /**< HCI: protocol error 0x29 */
+    OI_HCIERR_DIFFERENT_TRANS_COLLISION        = 742, /**< HCI: protocol error 0x2A */
+    OI_HCIERR_RESERVED_2B                      = 743, /**< HCI: protocol error 0x2B */
+    OI_HCIERR_QOS_UNACCEPTABLE_PARAMETER       = 744, /**< HCI: protocol error 0x2C */
+    OI_HCIERR_QOS_REJECTED                     = 745, /**< HCI: protocol error 0x2D */
+    OI_HCIERR_CHANNEL_CLASSIFICATION_NS        = 746, /**< HCI: protocol error 0x2E */
+    OI_HCIERR_INSUFFICIENT_SECURITY            = 747, /**< HCI: protocol error 0x2F */
+    OI_HCIERR_PARM_OUT_OF_MANDATORY_RANGE      = 748, /**< HCI: protocol error 0x30 */
+    OI_HCIERR_RESERVED_31                      = 749, /**< HCI: protocol error 0x31 */
+    OI_HCIERR_ROLE_SWITCH_PENDING              = 750, /**< HCI: protocol error 0x32 */
+    OI_HCIERR_RESERVED_33                      = 751, /**< HCI: protocol error 0x33 */
+    OI_HCIERR_RESERVED_SLOT_VIOLATION          = 752, /**< HCI: protocol error 0x34 */
+    OI_HCIERR_ROLE_SWITCH_FAILED               = 753, /**< HCI: protocol error 0x35 */
+    OI_HCIERR_EIR_TOO_LARGE                    = 754, /**< HCI: protocol error 0x36 */
+    OI_HCIERR_SSP_NOT_SUPPORTED_BY_HOST        = 755, /**< HCI: protocol error 0x37 */
+    OI_HCIERR_HOST_BUSY_PAIRING                = 756, /**< HCI: protocol error 0x38 */
+
+    OI_HCIERR_UNKNOWN_ERROR                    = 757, /**< HCI: unknown error code */
+    OI_HCIERR_LAST_ERROR_VALUE                 = 757, /**< marker for last HCI protocol error */
+
+    OI_SDP_SPEC_ERROR                    = 800, /**< SDP: Base error status for mapping OI_STATUS codes to SDP errors */
+    OI_SDP_INVALID_SERVICE_RECORD_HANDLE = (OI_SDP_SPEC_ERROR + 2), /**< SDP: protocol error Invalid Service Record Handle */
+    OI_SDP_INVALID_REQUEST_SYNTAX        = (OI_SDP_SPEC_ERROR + 3), /**< SDP: protocol error Invalid Request Syntax */
+    OI_SDP_INVALID_PDU_SIZE              = (OI_SDP_SPEC_ERROR + 4), /**< SDP: protocol error Invalid PDU Size */
+    OI_SDP_INVALID_CONTINUATION_STATE    = (OI_SDP_SPEC_ERROR + 5), /**< SDP: protocol error Invalid Continuation State */
+    OI_SDP_INSUFFICIENT_RESOURCES        = (OI_SDP_SPEC_ERROR + 6), /**< SDP: protocol error Insufficient Resources */
+    OI_SDP_ERROR                         = 807, /**< SDP: server returned an error code */
+    OI_SDP_CORRUPT_DATA_ELEMENT          = 808, /**< SDP: Invalid or corrupt data element representation */
+    OI_SDP_SERVER_NOT_CONNECTED          = 810, /**< SDP: Attempt to disconnect from an unconnected server */
+    OI_SDP_ACCESS_DENIED                 = 811, /**< SDP: Server denied access to server */
+    OI_SDP_ATTRIBUTES_OUT_OF_ORDER       = 812, /**< SDP: Attributes in attribute list not in ascending order */
+    OI_SDP_DEVICE_DOES_NOT_SUPPORT_SDP   = 813, /**< SDP: Tried to connect to a device that does not support SDP */
+    OI_SDP_NO_MORE_DATA                  = 815, /**< SDP: Server does not have more continuation data */
+    OI_SDP_REQUEST_PARAMS_TOO_LONG       = 816, /**< SDP: Parameters for a request exceed the L2CAP buffer size */
+    OI_SDP_REQUEST_PENDING               = 817, /**< SDP: Cannot make a request when another request is being processed */
+    OI_SDP_SERVER_CONNECT_FAILED         = 819, /**< SDP: Failed attempt to connect to an SDP server */
+    OI_SDP_SERVER_TOO_MANY_CONNECTIONS   = 821, /**< SDP: Exceeded maximum number of simultaneous server connections */
+    OI_SDP_NO_MATCHING_SERVICE_RECORD    = 823, /**< SDP: No service record matched the UUID list */
+    OI_SDP_PARTIAL_RESPONSE              = 824, /**< SDP: Internal use only */
+    OI_SDP_ILLEGAL_ARGUMENT              = 825, /**< SDP: Illegal argument passed to an SDP function */
+    OI_SDP_ATTRIBUTE_NOT_FOUND           = 826, /**< SDP: A requested attribute was not found in a service record */
+    OI_SDP_DATABASE_OUT_OF_RESOURCES     = 827, /**< SDP: server database is out of memory */
+    OI_SDP_SHORT_PDU                     = 829, /**< SDP: Not enough bytes in the packet */
+    OI_SDP_TRANSACTION_ID_MISMATCH       = 830, /**< SDP: Transaction Id was not as expected */
+    OI_SDP_UNEXPECTED_RESPONSE_PDU_ID    = 831, /**< SDP: Did not expect this response PDU */
+    OI_SDP_REQUEST_TIMEOUT               = 832, /**< SDP: Did not get a response within the timeout period */
+    OI_SDP_INVALID_RESPONSE_SYNTAX       = 833, /**< SDP: Response is not correctly formatted */
+    OI_SDP_CONNECTION_TIMEOUT            = 834, /**< SDP: Connection attempt timed out at a lower layer */
+    OI_SDP_RESPONSE_DATA_ERROR           = 835, /**< SDP: Response to a service request appears to be corrupt */
+    OI_SDP_TOO_MANY_ATTRIBUTE_BYTES      = 836, /**< SDP: Response contained more bytes than requested. */
+    OI_SDP_TOO_MANY_SERVICE_RECORDS      = 837, /**< SDP: Response contained more service records than requested. */
+    OI_SDP_INVALID_CONNECTION_ID         = 838, /**< SDP: Invalid connection ID in an SDP request */
+    OI_SDP_CANNOT_SET_ATTRIBUTE          = 839, /**< SDP: Attempt to set a dynamic attribute value failed */
+    OI_SDP_BADLY_FORMED_ATTRIBUTE_VALUE  = 840, /**< SDP: An attribute value has the wrong type or structure */
+    OI_SDP_NO_ATTRIBUTE_LIST_TO_REMOVE   = 841, /**< SDP: Attempt to remove a non-existent attribute list from a service record */
+    OI_SDP_ATTRIBUTE_LIST_ALREADY_ADDED  = 842, /**< SDP: An attribute list has already been added to the service record */
+    OI_SDP_DATA_ELEMENT_TRUNCATED        = 843, /**< SDP: Data element truncated (too few bytes) */
+
+    OI_RFCOMM_WRITE_IN_PROGRESS          = 901, /**< RFCOMM: Write in progress */
+    OI_RFCOMM_INVALID_BAUDRATE           = 903, /**< RFCOMM: Invalid baudrate */
+    OI_RFCOMM_INVALID_DATABIT            = 904, /**< RFCOMM: Invalid databit */
+    OI_RFCOMM_INVALID_STOPBIT            = 905, /**< RFCOMM: Invalid stopbit */
+    OI_RFCOMM_INVALID_PARITY             = 906, /**< RFCOMM: Invalid parity */
+    OI_RFCOMM_INVALID_PARITYTYPE         = 907, /**< RFCOMM: Invalid paritytype */
+    OI_RFCOMM_INVALID_FLOWCONTROL        = 908, /**< RFCOMM: Invalid flowcontrol */
+    OI_RFCOMM_SESSION_EXISTS             = 909, /**< RFCOMM: Session exists */
+    OI_RFCOMM_INVALID_CHANNEL            = 910, /**< RFCOMM: Invalid channel */
+    OI_RFCOMM_DLCI_EXISTS                = 911, /**< RFCOMM: DLCI exists */
+    OI_RFCOMM_LINK_NOT_FOUND             = 912, /**< RFCOMM: Link not found */
+    OI_RFCOMM_REMOTE_REJECT              = 913, /**< RFCOMM: Remote reject */
+    OI_RFCOMM_TEST_IN_PROGRESS           = 915, /**< RFCOMM: Test in progress */
+    OI_RFCOMM_SESSION_NOT_FOUND          = 916, /**< RFCOMM: Session not found */
+    OI_RFCOMM_INVALID_PACKET             = 917, /**< RFCOMM: Invalid packet */
+    OI_RFCOMM_FRAMESIZE_EXCEEDED         = 918, /**< RFCOMM: Framesize exceeded */
+    OI_RFCOMM_INVALID_DLCI               = 920, /**< RFCOMM: Invalid dlci */
+    OI_RFCOMM_SERVER_NOT_REGISTERED      = 921, /**< RFCOMM: Server not registered */
+    OI_RFCOMM_CREDIT_ERROR               = 922, /**< RFCOMM: Credit error */
+    OI_RFCOMM_NO_CHANNEL_NUMBER          = 923, /**< RFCOMM: No channel number */
+    OI_RFCOMM_QUERY_IN_PROGRESS          = 924, /**< RFCOMM: Query in progress */
+    OI_RFCOMM_SESSION_SHUTDOWN           = 925, /**< RFCOMM: Session shutdown */
+    OI_RFCOMM_LOCAL_DEVICE_DISCONNECTED  = 926, /**< RFCOMM: Local device disconnected */
+    OI_RFCOMM_REMOTE_DEVICE_DISCONNECTED = 927, /**< RFCOMM: Remote device disconnected */
+    OI_RFCOMM_OUT_OF_SERVER_CHANNELS     = 928, /**< RFCOMM: Out of server channels */
+
+    OI_DISPATCH_INVALID_CB_HANDLE        = 1001, /**< Dispatcher was handed an invalid callback handle */
+    OI_DISPATCH_TABLE_OVERFLOW           = 1002, /**< Dispatcher table is full */
+
+    OI_TEST_UNKNOWN_TEST                 = 1101, /**< TEST: Unknown test */
+    OI_TEST_FAIL                         = 1102, /**< TEST: Fail */
+
+    OI_HCITRANS_CANNOT_CONNECT_TO_DEVICE   = 1201, /**< TRANSPORT: Cannot connect to device */
+    OI_HCITRANS_BUFFER_TOO_SMALL           = 1203, /**< TRANSPORT: Buffer too small */
+    OI_HCITRANS_NULL_DEVICE_HANDLE         = 1204, /**< TRANSPORT: Null device handle */
+    OI_HCITRANS_IO_ERROR                   = 1205, /**< TRANSPORT: IO error */
+    OI_HCITRANS_DEVICE_NOT_READY           = 1206, /**< TRANSPORT: Device not ready */
+    OI_HCITRANS_FUNCTION_NOT_SUPPORTED     = 1207, /**< TRANSPORT: Function not supporteD */
+    OI_HCITRANS_ACCESS_DENIED              = 1209, /**< TRANSPORT: win32 */
+    OI_HCITRANS_ACL_DATA_ERROR             = 1210, /**< TRANSPORT: ACL data error */
+    OI_HCITRANS_SCO_DATA_ERROR             = 1211, /**< TRANSPORT: SCO data error */
+    OI_HCITRANS_EVENT_DATA_ERROR           = 1212, /**< TRANSPORT: HCI event data error */
+    OI_HCITRANS_INTERNAL_ERROR             = 1214, /**< TRANSPORT: Internal error in the transport */
+    OI_HCITRANS_LINK_NOT_ACTIVE            = 1215, /**< TRANSPORT: Link to the device is not currently active */
+    OI_HCITRANS_INITIALIZING               = 1216, /**< TRANSPORT: Transport is initializing */
+
+    OI_DEVMGR_NO_CONNECTION                = 1301, /**< DEVMGR: No connection */
+    OI_DEVMGR_HARDWARE_ERROR               = 1305, /**< DEVMGR: error reported by HCI */
+    OI_DEVMGR_PENDING_CONNECT_LIST_FULL    = 1307, /**< DEVMGR: Pending connect list full */
+    OI_DEVMGR_CONNECTION_LIST_FULL         = 1309, /**< DEVMGR: Connection list full */
+    OI_DEVMGR_NO_SUCH_CONNECTION           = 1310, /**< DEVMGR: No such connection */
+    OI_DEVMGR_INQUIRY_IN_PROGRESS          = 1311, /**< DEVMGR: Inquiry in progress */
+    OI_DEVMGR_PERIODIC_INQUIRY_ACTIVE      = 1312, /**< DEVMGR: Periodic inquiry active */
+    OI_DEVMGR_NO_INQUIRIES_ACTIVE          = 1313, /**< DEVMGR: can not cancel/exit if not active */
+    OI_DEVMGR_DUPLICATE_CONNECTION         = 1314, /**< DEVMGR: internal error */
+    OI_DEVMGR_DUPLICATE_EVENT_CALLBACK     = 1316, /**< DEVMGR: attempt to register same callback twice */
+    OI_DEVMGR_EVENT_CALLBACK_LIST_FULL     = 1317, /**< DEVMGR: can not register event callback, list is full */
+    OI_DEVMGR_EVENT_CALLBACK_NOT_FOUND     = 1318, /**< DEVMGR: attempt to unregister callback failed */
+    OI_DEVMGR_BUSY                         = 1319, /**< DEVMGR: some operations can only execute one at a time */
+    OI_DEVMGR_ENUM_UNEXPECTED_INQ_COMPLETE = 1320, /**< DEVMGR: inquiry complete event in inappropriate enumeration state */
+    OI_DEVMGR_ENUM_UNEXPECTED_INQ_RESULT   = 1321, /**< DEVMGR: inquiry result event in inappropriate enumeration state */
+    OI_DEVMGR_ENUM_DATABASE_FULL           = 1322, /**< DEVMGR: device enumeration, database is full, couldn't add a new device */
+    OI_DEVMGR_ENUM_INQUIRIES_OVERLAP       = 1323, /**< DEVMGR: device enumeration, periodic inquiries occurring too close together */
+    OI_DEVMGR_UNKNOWN_LINK_TYPE            = 1324, /**< DEVMGR: HCI connect request with unkown link type */
+    OI_DEVMGR_PARAM_IO_ACTIVE              = 1325, /**< DEVMGR: request for parameter read/write while param read/write active */
+    OI_DEVMGR_UNKNOWN_IAC_LAP              = 1326, /**< DEVMGR: unrecognized IAC LAP */
+    OI_DEVMGR_SCO_ALREADY_REGISTERED       = 1327, /**< DEVMGR: only one application can use SCO */
+    OI_DEVMGR_SCO_NOT_REGISTERED           = 1328, /**< DEVMGR: SCO applications must register before using the API */
+    OI_DEVMGR_SCO_WITHOUT_ACL              = 1329, /**< DEVMGR: Got SCO connection but there is no underlying ACL connection */
+    OI_DEVMGR_NO_SUPPORT                   = 1330, /**< DEVMGR: Request is not supported by the device */
+    OI_DEVMGR_WRITE_POLICY_FAILED          = 1331, /**< DEVMGR: connection attempt failed - unable to write link policy */
+    OI_DEVMGR_NOT_IN_MASTER_MODE           = 1332, /**< DEVMGR: OI_DEVMGR EndMasterMode without prior OI_DEVMGR_BeginMasterMode */
+    OI_DEVMGR_POLICY_VIOLATION             = 1333, /**< DEVMGR: low-power request is rejected - link policy does not allow it */
+    OI_DEVMGR_BUSY_TIMEOUT                 = 1334, /**< DEVMGR: queued operation timed out while in the queue; \n
+        timeout configurable via @ref OI_CONFIG_DEVMGR::connectQueueTimeoutSecs "connectQueueTimeoutSecs" */
+    OI_DEVMGR_REENCRYPT_FAILED             = 1335, /**< DEVMGR: failed to re-encrypt link after role switch */
+    OI_DEVMGR_ROLE_POLICY_CONFLICT         = 1336, /**< DEVMGR: requested role conflicts with current policy */
+    OI_DEVMGR_BAD_INTERVAL                 = 1337, /**< DEVMGR: current linkTO outside range of requested min/max interval */
+    OI_DEVMGR_INVALID_SCO_HANDLE           = 1338, /**< DEVMGR: HCI SCO event, invalid handle */
+    OI_DEVMGR_CONNECTION_OVERLAP           = 1339, /**< DEVMGR: Connection failed due to race condition with remote side */
+    OI_DEVMGR_ORPHAN_SUBRATE_COMPLETE      = 1340, /**< DEVMGR: sniff subrate complete, but no callback */
+    OI_DEVMGR_EIR_RESPONSE_2_LARGE         = 1341, /**< DEVMGR: eir builder, response length would exceed spec max */
+
+    OI_SECMGR_NO_POLICY                    = 1401, /**< SECMGR: no security policy has been established */
+    OI_SECMGR_INTERNAL_ERROR               = 1402, /**< SECMGR: internal inconsistency */
+    OI_SECMGR_ORPHANED_CALLBACK            = 1403, /**< SECMGR: we've been called back, but CB context is gone */
+    OI_SECMGR_BUSY                         = 1404, /**< SECMGR: configure and access request cannot be concurrent */
+    OI_SECMGR_DEVICE_NOT_TRUSTED           = 1405, /**< SECMGR: l2cap access denied - device is not trusted */
+    OI_SECMGR_DEVICE_ENCRYPT_FAIL          = 1407, /**< SECMGR: l2cap access denied - failed to start encryption */
+    OI_SECMGR_DISCONNECTED_FAIL            = 1408, /**< SECMGR: l2cap access denied - disconnected */
+    OI_SECMGR_ACCESS_PENDING               = 1409, /**< SECMGR: l2cap access request is still pending  */
+    OI_SECMGR_PIN_CODE_TOO_SHORT           = 1410, /**< SECMGR: Higher-layer process gave us a pin code that is too short */
+    OI_SECMGR_UNKNOWN_ENCRYPT_VALUE        = 1411, /**< SECMGR: got EncryptionChange event, unknown encryption enable value */
+    OI_SECMGR_INVALID_POLICY               = 1412, /**< SECMGR: the specified security policy is not valid for security mode */
+    OI_SECMGR_AUTHORIZATION_FAILED         = 1413, /**< SECMGR: device authorization failed */
+    OI_SECMGR_ENCRYPTION_FAILED            = 1414, /**< SECMGR: device encryption failed */
+    OI_SECMGR_UNIT_KEY_UNSUPPORTED         = 1415, /**< SECMGR: authentication failed due to non-support of unit keys */
+    OI_SECMGR_NOT_REGISTERED               = 1416, /**< SECMGR: required registrations have not yet occurred */
+    OI_SECMGR_ILLEGAL_WRITE_SSP_MODE       = 1417, /**< SECMGR: 2.1 HCI spec does not allow SSP mode to be disabled */
+    OI_SECMGR_INVALID_SEC_LEVEL            = 1418, /**< SECMGR: security level for a service is not a valid value */
+    OI_SECMGR_INSUFFICIENT_LINK_KEY        = 1419, /**< SECMGR: link key type is not sufficient to meet service requirements */
+    OI_SECMGR_INVALID_KEY_TYPE             = 1420, /**< SECMGR: link key type is not a valid value */
+    OI_SECMGR_SSP_NOT_ENCRYPTED            = 1421, /**< SECMGR: ssp required encryption on incoming link */
+    OI_SECMGR_ORPHAN_EVENT                 = 1422, /**< SECMGR: some HCI security event unrelated to current processes */
+    OI_SECMGR_NOT_BONDABLE                 = 1423, /**< SECMGR: not in bondable mode */
+
+    OI_TCS_INVALID_ELEMENT_TYPE            = 1602, /**< TCS: element type is invalid */
+    OI_TCS_INVALID_PACKET                  = 1603, /**< TCS: packet is invalide */
+    OI_TCS_CALL_IN_PROGRESS                = 1604, /**< TCS: call is in progress */
+    OI_TCS_NO_CALL_IN_PROGRESS             = 1605, /**< TCS: no call in progress */
+
+    OI_OBEX_CONTINUE                       = 1701, /**< OBEX: Continue processing OBEX request */
+    OI_OBEX_COMMAND_ERROR                  = 1702, /**< OBEX: An unrecognized OBEX command opcode */
+    OI_OBEX_CONNECTION_TIMEOUT             = 1703, /**< OBEX: Timeout waiting for a response to a request */
+    OI_OBEX_CONNECT_FAILED                 = 1704, /**< OBEX: An OBEX connection request did not succeed */
+    OI_OBEX_DISCONNECT_FAILED              = 1705, /**< OBEX: A disconnect failed probably because the connection did not exist */
+    OI_OBEX_ERROR                          = 1706, /**< OBEX: Unspecified OBEX error */
+    OI_OBEX_INCOMPLETE_PACKET              = 1707, /**< OBEX: Packet too short or corrupt */
+    OI_OBEX_LENGTH_REQUIRED                = 1708, /**< OBEX: Length header required in OBEX command */
+    OI_OBEX_NOT_CONNECTED                  = 1709, /**< OBEX: No connection to OBEX server */
+    OI_OBEX_NO_MORE_CONNECTIONS            = 1710, /**< OBEX: Reached max connections limit */
+    OI_OBEX_OPERATION_IN_PROGRESS          = 1711, /**< OBEX: Another operation is still in progress on a connection */
+    OI_OBEX_PUT_RESPONSE_ERROR             = 1712, /**< OBEX: An error in the response to a PUT command */
+    OI_OBEX_GET_RESPONSE_ERROR             = 1713, /**< OBEX: An error in the response to a GET command */
+    OI_OBEX_REQUIRED_HEADER_NOT_FOUND      = 1714, /**< OBEX: packet was missing a required header */
+    OI_OBEX_SERVICE_UNAVAILABLE            = 1715, /**< OBEX: Unown OBEX target or required service */
+    OI_OBEX_TOO_MANY_HEADER_BYTES          = 1716, /**< OBEX: Headers will not fit in single OBEX packet */
+    OI_OBEX_UNKNOWN_COMMAND                = 1717, /**< OBEX: Unrecognized OBEX command */
+    OI_OBEX_UNSUPPORTED_VERSION            = 1718, /**< OBEX: Version mismatch */
+    OI_OBEX_CLIENT_ABORTED_COMMAND         = 1719, /**< OBEX: server received abort command */
+    OI_OBEX_BAD_PACKET                     = 1720, /**< OBEX: Any malformed OBEX packet */
+    OI_OBEX_BAD_REQUEST                    = 1721, /**< OBEX: Maps to OBEX response of the same name */
+    OI_OBEX_OBJECT_OVERFLOW                = 1723, /**< OBEX: Too many bytes received. */
+    OI_OBEX_NOT_FOUND                      = 1724, /**< OBEX: Maps to obex response of same name */
+    OI_OBEX_ACCESS_DENIED                  = 1735, /**< OBEX: Object could not be read or written. */
+    OI_OBEX_VALUE_NOT_ACCEPTABLE           = 1736, /**< OBEX: Value in a command was not in the acceptable range. */
+    OI_OBEX_PACKET_OVERFLOW                = 1737, /**< OBEX: Buffer will not fit in a single OBEX packet. */
+    OI_OBEX_NO_SUCH_FOLDER                 = 1738, /**< OBEX: Error returned by a setpath operation. */
+    OI_OBEX_NAME_REQUIRED                  = 1739, /**< OBEX: Name must be non-null and non-empty. */
+    OI_OBEX_PASSWORD_TOO_LONG              = 1740, /**< OBEX: Password exceeds implementation imposed length limit. */
+    OI_OBEX_PRECONDITION_FAILED            = 1741, /**< OBEX: response Precondition Failed */
+    OI_OBEX_UNAUTHORIZED                   = 1742, /**< OBEX: authentication was not successful. */
+    OI_OBEX_NOT_IMPLEMENTED                = 1743, /**< OBEX: Unimplemented feature. */
+    OI_OBEX_INVALID_AUTH_DIGEST            = 1744, /**< OBEX: An authentication digest was bad. */
+    OI_OBEX_INVALID_OPERATION              = 1745, /**< OBEX: Operation not allowed at this time. */
+    OI_OBEX_DATABASE_FULL                  = 1746, /**< OBEX: Sync database full. */
+    OI_OBEX_DATABASE_LOCKED                = 1747, /**< OBEX: Sync database locked. */
+    OI_OBEX_INTERNAL_SERVER_ERROR          = 1748, /**< OBEX: response Internal Server Error */
+    OI_OBEX_UNSUPPORTED_MEDIA_TYPE         = 1749, /**< OBEX: response Unsupported Media Type */
+    OI_OBEX_PARTIAL_CONTENT                = 1750, /**< OBEX: response Partial Content */
+    OI_OBEX_METHOD_NOT_ALLOWED             = 1751, /**< OBEX: response Method Not Allowed */
+    OI_OBEXSRV_INCOMPLETE_GET              = 1752, /**< OBEX: Indicates to a GET handler that the request phase is still in progress */
+    OI_OBEX_FOLDER_BROWSING_NOT_ALLOWED    = 1753, /**< OBEX: Indicates that an FTP server does not allow folder browsing */
+    OI_OBEX_SERVER_FORCED_DISCONNECT       = 1754, /**< OBEX: connection was forcibly terminated by the server */
+    OI_OBEX_OFS_ERROR                      = 1755, /**< OBEX: OPP object file system error occurred */
+    OI_OBEX_FILEOP_ERROR                   = 1756, /**< OBEX: FTP/PBAP file operation system error occurred */
+    OI_OBEX_USERID_TOO_LONG                = 1757, /**< OBEX: User Id exceeds spec limited length limit. */
+
+    OI_HANDSFREE_EVENT_REPORTING_DISABLED  = 1801, /**< HANDSFREE: Event reporting disabled */
+    OI_HANDSFREE_NOT_CONNECTED             = 1802, /**< HANDSFREE: Not connected */
+    OI_HANDSFREE_SERVICE_NOT_STARTED       = 1803, /**< HANDSFREE: Cannot connect to handsfree AG if handsfree service not started */
+    OI_HANDSFREE_AG_SERVICE_NOT_STARTED    = 1804, /**< HANDSFREE: Cannot connect to handsfree device if handsfree AG service not started */
+    OI_HANDSFREE_COMMAND_IN_PROGRESS       = 1805, /**< HANDSFREE: Cannot accept a command at this time */
+    OI_HANDSFREE_AUDIO_ALREADY_CONNECTED   = 1806, /**< HANDSFREE: Audio is already connected */
+    OI_HANDSFREE_AUDIO_NOT_CONNECTED       = 1807, /**< HANDSFREE: Audio is not connected */
+    OI_HANDSFREE_FEATURE_NOT_SUPPORTED     = 1808, /**< HANDSFREE: Local or remote feature not supported for requested command */
+
+    OI_HEADSET_SERVICE_NOT_STARTED         = 1901, /**< HEADSET: Cannot connect to headset AG if headset service not started */
+    OI_HEADSET_AG_SERVICE_NOT_STARTED      = 1902, /**< HEADSET: Cannot connect to headset device if headset AG service not started */
+    OI_HEADSET_COMMAND_IN_PROGRESS         = 1903, /**< HEADSET: Cannot accept a command at this time */
+
+    OI_BNEP_INVALID_MTU                             = 2001, /**< BNEP: The remote device cannot support the minimum BNEP MTU */
+    OI_BNEP_SETUP_TIMEOUT                           = 2002, /**< BNEP: The setup request timed out. */
+    OI_BNEP_SERVICE_NOT_REGISTERED                  = 2003, /**< BNEP: The requested service was not found. */
+    OI_BNEP_INVALID_HANDLE                          = 2004, /**< BNEP: The specified connection handle is not valid. */
+    OI_BNEP_RESPONSE_TIMEOUT                        = 2005, /**< BNEP: The timer for receiving a response has expired. */
+    OI_BNEP_INVALID_CONNECTION                      = 2006, /**< BNEP: Invalid connection */
+    OI_BNEP_INVALID_FILTER                          = 2007, /**< BNEP: The supplied filter was invalid. */
+    OI_BNEP_CONNECTION_EXISTS                       = 2008, /**< BNEP: An attempt was made to create a duplicate connection. */
+    OI_BNEP_NOT_INITIALIZED                         = 2009, /**< BNEP: Init has not been called */
+    OI_BNEP_CONNECT_BASE                            = 2010, /**< BNEP: connection response codes */
+    OI_BNEP_CONNECT_FAILED_INVALID_DEST_UUID        = 2011, /**< BNEP: connect response code Invalid Dest UUID */
+    OI_BNEP_CONNECT_FAILED_INVALID_SOURCE_UUID      = 2012, /**< BNEP: connect response code Invalid Source UUID */
+    OI_BNEP_CONNECT_FAILED_INVALID_UUID_SIZE        = 2013, /**< BNEP: connect response code Invalid UUID Size */
+    OI_BNEP_CONNECT_FAILED_NOT_ALLOWED              = 2014, /**< BNEP: connect response code Not Allowed */
+    OI_BNEP_FILTER_NET_BASE                         = 2020, /**< BNEP: filter response codes */
+    OI_BNEP_FILTER_NET_UNSUPPORTED_REQUEST          = 2021, /**< BNEP: filter response code Unsupported Request */
+    OI_BNEP_FILTER_NET_FAILED_INVALID_PROTOCOL_TYPE = 2022, /**< BNEP: filter response code Invalid Protocol Type */
+    OI_BNEP_FILTER_NET_FAILED_MAX_LIMIT_REACHED     = 2023, /**< BNEP: filter response code Max Limit Reached */
+    OI_BNEP_FILTER_NET_FAILED_SECURITY              = 2024, /**< BNEP: filter response code Security */
+    OI_BNEP_FILTER_MULTI_BASE                       = 2030, /**< BNEP: multicast response codes */
+    OI_BNEP_FILTER_MULTI_UNSUPPORTED_REQUEST        = 2031, /**< BNEP: multicast response code Unsupported Request */
+    OI_BNEP_FILTER_MULTI_FAILED_INVALID_ADDRESS     = 2032, /**< BNEP: multicast response code Invalid Address */
+    OI_BNEP_FILTER_MULTI_FAILED_MAX_LIMIT_REACHED   = 2033, /**< BNEP: multicast response code Max Limit Reached */
+    OI_BNEP_FILTER_MULTI_FAILED_SECURITY            = 2034, /**< BNEP: multicast response code Security */
+    OI_BNEP_LOCAL_DEVICE_MUST_BE_MASTER             = 2040, /**< BNEP: Device must be master of the piconet for this function */
+    OI_BNEP_PACKET_FILTERED_OUT                     = 2041, /**< BNEP: Packet did not pass current filters */
+
+    OI_NETIFC_UP_FAILED                    = 2101, /**< NETIFC: Could not bring up network interface */
+    OI_NETIFC_COULD_NOT_CREATE_THREAD      = 2102, /**< NETIFC: Network interface could not create a read thread */
+    OI_NETIFC_INITIALIZATION_FAILED        = 2103, /**< NETIFC: Error in network interface initialization */
+    OI_NETIFC_INTERFACE_ALREADY_UP         = 2104, /**< NETIFC: Network interface is already up */
+    OI_NETIFC_INTERFACE_NOT_UP             = 2105, /**< NETIFC: Network interface is not up */
+    OI_NETIFC_PACKET_TOO_BIG               = 2106, /**< NETIFC: The packet is too big */
+
+    OI_PAN_ROLE_ALREADY_REGISTERED         = 2201, /**< PAN: This PAN role was already registered */
+    OI_PAN_ROLE_NOT_ALLOWED                = 2202, /**< PAN: The PAN role is not currently allowed */
+    OI_PAN_INCOMPATIBLE_ROLES              = 2203, /**< PAN: Only certain local and remote role combinations are permitted */
+    OI_PAN_INVALID_ROLE                    = 2204, /**< PAN: Role specified is not one the defined PAN roles */
+    OI_PAN_CONNECTION_IN_PROGRESS          = 2205, /**< PAN: A PAN connection is currently being established */
+    OI_PAN_USER_ALREADY_CONNECTED          = 2206, /**< PAN: PAN user role only allows a single connection */
+    OI_PAN_DEVICE_CONNECTED                = 2207, /**< PAN: A PAN connection already exists to specified device */
+
+    OI_CODEC_SBC_NO_SYNCWORD               = 2301, /**< CODEC: Couldn't find an SBC SYNCWORD */
+    OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA    = 2302, /**< CODEC: Not enough data provided to decode an SBC header */
+    OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA      = 2303, /**< CODEC: Decoded the header, but not enough data to contain the rest of the frame */
+    OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA     = 2304, /**< CODEC: Not enough audio data for this frame */
+    OI_CODEC_SBC_CHECKSUM_MISMATCH         = 2305, /**< CODEC: The frame header didn't match the checksum */
+    OI_CODEC_SBC_PARTIAL_DECODE            = 2306, /**< CODEC: Decoding was successful, but frame data still remains. Next call will provide audio without consuming input data. */
+
+    OI_FIFOQ_QUEUE_NOT_ALIGNED             = 2401, /**< FIFOQ: queue must be 32-bit aligned */
+    OI_FIFOQ_INVALID_Q                     = 2402, /**< FIFOQ: queue parameter is not a valid queue */
+    OI_FIFOQ_BUF_TOO_LARGE                 = 2403, /**< FIFOQ: attempt to queue a buffer which is too large */
+    OI_FIFOQ_FULL                          = 2404, /**< FIFOQ: enqueue() failed, queue is full */
+    OI_FIFOQ_NOT_ALLOCATED                 = 2405, /**< FIFOQ: Enqueue QBuf() failed, buffer not allocated */
+    OI_FIFOQ_INVALID_DATA_PTR              = 2406, /**< FIFOQ: Enqueue QBuf() failed, data pointer does not match */
+
+    OI_HID_HOST_SERVICE_NOT_STARTED        = 2601, /**< HID: Cannot connect to a HID device unless HID host is started */
+    OI_HID_DEVICE_SERVICE_NOT_STARTED      = 2602, /**< HID: Cannot connect to a HID host unless HID device is started */
+
+    OI_AT_ERROR                            = 2701, /**< AT: ERROR response */
+    OI_AT_NO_CARRIER                       = 2702, /**< AT: NO CARRIER response */
+    OI_AT_BUSY                             = 2703, /**< AT: BUSY response */
+    OI_AT_NO_ANSWER                        = 2704, /**< AT: NO ANSWER response */
+    OI_AT_DELAYED                          = 2705, /**< AT: DELAYED response */
+    OI_AT_BLACKLISTED                      = 2706, /**< AT: BLACKLISTED response */
+    OI_AT_CME_ERROR                        = 2707, /**< AT: +CME ERROR response */
+    OI_AT_CMS_ERROR                        = 2708, /**< AT: +CMS ERROR response */
+
+    OI_BLST_CHARACTER_TIMEOUT              = 2801, /**< BLST: Timeout expired while waiting for a character from the client. */
+    OI_BLST_ACKNOWLDGE_TIMEOUT             = 2802, /**< BLST: Timeout expired while waiting for event acknowledgment from the client */
+    OI_BLST_TX_NOT_READY                   = 2803, /**< BLST: BLST is not ready to send a BHAPI message to the client. */
+    OI_BLST_TX_BUSY                        = 2804, /**< BLST: BLST transmit buffer is in use. */
+
+    OI_AVDTP_CONNECTION_SEQ_ERROR          = 2901, /**< AVDTP: sequencing of signalling/media channel connections broken. */
+    OI_AVDTP_OUT_OF_RESOURCES              = 2902, /**< AVDTP: Tried to allocate too many endpoints or signalling channels. */
+
+    OI_PBAP_REPOSITORY_NOT_SET             = 3001, /**< PBAP: Phonebook repository must be set for operation to complete. */
+    OI_PBAP_PHONEBOOK_NOT_SET              = 3002, /**< PBAP: Phonebook be set for operation to complete. */
+
+    OI_AADP_BAD_ENDPOINT                   = 3101, /**< AADP: Invalid local endpoint specified */
+    OI_AADP_BAD_STATE                      = 3102, /**< AADP: AADP State is not correct for this operation. */
+
+    OI_UNICODE_INVALID_SOURCE              = 3200, /**< Unicode Conversion: Source string has invalid character encoding. */
+    OI_UNICODE_SOURCE_EXHAUSTED            = 3201, /**< Unicode Conversion: Incomplete Unicode character at end of source buffer. */
+    OI_UNICODE_DESTINATION_EXHAUSTED       = 3202, /**< Unicode Conversion: Destination buffer not large enough to hold resulting Unicode string. */
+
+    OI_AVRCP_TOO_MANY_CONNECTIONS          = 3300, /**< AVRCP: Exceeded maximum number of simultaneous AVCTP connections. */
+    OI_AVRCP_NOT_IMPLEMENTED               = 3301, /**< AVRCP: The target does not implement the command specified by the opcode and operand. */
+    OI_AVRCP_REJECTED                      = 3302, /**< AVRCP: The target cannot respond because of invalid operands in command packet. */
+    OI_AVRCP_INVALID_RESPONSE              = 3303, /**< AVRCP: The controller received the response with invalid parameters */
+    OI_AVRCP_RESPONSE_PACKET_OVERFLOW      = 3304, /**< AVRCP: The response message does not fir in one AVRCP packet (512 bytes), has to be fragmented. */
+    OI_AVRCP_RESPONSE_INVALID_PDU          = 3305, /**< AVRCP: Command rejected: target received a PDU that it did not understand. */
+    OI_AVRCP_RESPONSE_INVALID_PARAMETER    = 3306, /**< AVRCP: Command rejected: target received a PDU with a parameter ID that it did not understand. */
+    OI_AVRCP_RESPONSE_PARAMETER_NOT_FOUND  = 3307, /**< AVRCP: Command rejected: specified parameter not found, sent if the parameter ID is understood, but content is wrong or corrupted.*/
+    OI_AVRCP_RESPONSE_INTERNAL_ERROR       = 3308, /**< AVRCP: Command rejected: target detected other error conditions. */
+    OI_MAX_BM3_STATUS_VAL,       /* Maximum BM3 status code */
+
+    /* Status code values reserved for BM3 SDK platform-specific implementations */
+    OI_STATUS_RESERVED_FOR_BCOT = 9000,
+
+    /* Status code values reserved for BHAPI products */
+    OI_STATUS_RESERVED_FOR_BHAPI = 9200,
+
+    /* Status code values reserved for Soundabout products */
+    OI_STATUS_RESERVED_FOR_SOUNDABOUT= 9400,
+
+    /*
+     * Status code values greater than or equal to this value are reserved for use by applications.
+     * However, because of differences between compilers, and differences between 16-bit and 32-bit
+     * platforms custom status codes should be in the 16-bit range, so status codes can range from 0
+     * to 65534, inclusive (65535 is reserved)
+     */
+    OI_STATUS_RESERVED_FOR_APPS = 10000,
+
+
+
+    OI_STATUS_NONE = 0xffff     /**< Special status code to indicate that there is no status. (Only to be used for special cases involving OI_SLOG_ERROR() and OI_SLOG_WARNING().) */
+
+} OI_STATUS;
+
+
+/* Remeber to update the #define below when new reserved blocks are added to
+ * the list above. */
+#define OI_NUM_RESERVED_STATUS_BLOCKS 4 /**< Number of status code blocks reserved, including user apps */
+
+
+/**
+ * Test for success
+ */
+#define OI_SUCCESS(x)    ((x) == OI_OK)
+
+/*****************************************************************************/
+#ifdef __cplusplus
+}
+#endif
+
+/**@}*/
+
+#endif /* _OI_STATUS_H */
+
diff --git a/bt/embdrv/sbc/decoder/include/oi_stddefs.h b/bt/embdrv/sbc/decoder/include/oi_stddefs.h
new file mode 100644
index 0000000..d3939d7
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/include/oi_stddefs.h
@@ -0,0 +1,232 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef OI_STDDEFS_H
+#define OI_STDDEFS_H
+/**
+ * @file
+ * This file contains BM3 standard type definitions.
+ *
+ */
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+#include "oi_cpu_dep.h"
+
+/** \addtogroup Misc Miscellaneous APIs */
+/**@{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef FALSE
+#define FALSE 0         /**< This define statement sets FALSE as a preprocessor alias for 0. */
+#endif
+
+#ifndef TRUE
+#define TRUE (!FALSE)  /**< This define statement sets TRUE as a preprocessor alias for !FALSE. */
+#endif
+
+#ifdef HEW_TOOLCHAIN
+    #ifdef NULL
+        #undef NULL         /**< Override HEW toolchain NULL definition */
+    #endif
+    #define NULL 0          /**< HEW toolchain does not allow us to compare (void*) type to function pointer */
+#else
+    #ifndef NULL
+        #define NULL ((void*)0) /**< This define statement sets NULL as a preprocessor alias for (void*)0 */
+    #endif
+#endif
+
+/**
+ * @name  Maximum and minimum values for basic types
+ * @{
+ */
+#define OI_INT8_MIN   ((int8_t)0x80)          /**< decimal value: -128 */
+#define OI_INT8_MAX   ((int8_t)0x7F)          /**< decimal value: 127 */
+#define OI_INT16_MIN  ((int16_t)0x8000)       /**< decimal value: -32768 */
+#define OI_INT16_MAX  ((int16_t)0x7FFF)       /**< decimal value: 32767 */
+#define OI_INT32_MIN  ((int32_t)0x80000000)   /**< decimal value: -2,147,483,648 */
+#define OI_INT32_MAX  ((int32_t)0x7FFFFFFF)   /**< decimal value: 2,147,483,647 */
+#define OI_UINT8_MIN  ((uint8_t)0)            /**< decimal value: 0 */
+#define OI_UINT8_MAX  ((uint8_t)0xFF)         /**< decimal value: 255 */
+#define OI_UINT16_MIN ((uint16_t)0)           /**< decimal value: 0 */
+#define OI_UINT16_MAX ((uint16_t)0xFFFF)      /**< decimal value: 65535 */
+#define OI_UINT32_MIN ((uint32_t)0)           /**< decimal value: 0 */
+#define OI_UINT32_MAX ((uint32_t)0xFFFFFFFF)  /**< decimal value: 4,294,967,295 */
+
+/**
+ * @}
+ */
+
+/**
+ * @name  Integer types required by the Service Discovery Protocol
+ * @{
+ */
+
+/** unsigned 64-bit integer as a structure of two unsigned 32-bit integers */
+typedef struct {
+    uint32_t I1; /**< most significant 32 bits */
+    uint32_t I2; /**< least significant 32 bits */
+} OI_UINT64;
+
+#define OI_UINT64_MIN { (uint32_t)0x00000000, (uint32_t)0x00000000 }
+#define OI_UINT64_MAX { (uint32_t)0XFFFFFFFF, (uint32_t)0XFFFFFFFF }
+
+/** signed 64-bit integer as a structure of one unsigned 32-bit integer and one signed 32-bit integer */
+typedef struct {
+    int32_t  I1; /**< most significant 32 bits  as a signed integer */
+    uint32_t I2; /**< least significant 32 bits as an unsigned integer */
+} OI_INT64;
+
+#define OI_INT64_MIN { (int32_t)0x80000000, (uint32_t)0x00000000 }
+#define OI_INT64_MAX { (int32_t)0X7FFFFFFF, (uint32_t)0XFFFFFFFF }
+
+/** unsigned 128-bit integer as a structure of four unsigned 32-bit integers */
+typedef struct {
+    uint32_t I1; /**< most significant 32 bits */
+    uint32_t I2; /**< second-most significant 32 bits */
+    uint32_t I3; /**< third-most significant 32 bits */
+    uint32_t I4; /**< least significant 32 bits */
+} OI_UINT128;
+
+#define OI_UINT128_MIN { (uint32_t)0x00000000, (uint32_t)0x00000000,  (uint32_t)0x00000000, (uint32_t)0x00000000 }
+#define OI_UINT128_MAX { (uint32_t)0XFFFFFFFF, (uint32_t)0XFFFFFFFF,  (uint32_t)0XFFFFFFFF, (uint32_t)0XFFFFFFFF }
+
+/** signed 128-bit integer as a structure of three unsigned 32-bit integers and one signed 32-bit integer */
+typedef struct {
+    int32_t  I1;  /**< most significant 32 bits as a signed integer */
+    uint32_t I2;  /**< second-most significant 32 bits as an unsigned integer */
+    uint32_t I3;  /**< third-most significant 32 bits as an unsigned integer */
+    uint32_t I4;  /**< least significant 32 bits as an unsigned integer */
+} OI_INT128;
+
+#define OI_INT128_MIN { (uint32_t)0x80000000, (uint32_t)0x00000000,  (uint32_t)0x00000000, (uint32_t)0x00000000 }
+#define OI_INT128_MAX { (uint32_t)0X7FFFFFFF, (uint32_t)0XFFFFFFFF,  (uint32_t)0XFFFFFFFF, (uint32_t)0XFFFFFFFF }
+
+/**
+ * @}
+ */
+
+
+/**
+ * type for ASCII character data items
+ */
+typedef char OI_CHAR;
+
+/**
+ * type for double-byte character data items
+ */
+typedef uint16_t OI_CHAR16;
+
+/**
+ * types for UTF encoded strings.
+ */
+typedef uint8_t  OI_UTF8;
+typedef uint16_t OI_UTF16;
+typedef uint32_t OI_UTF32;
+
+
+/**
+ * @name Single-bit operation macros
+ * @{
+ * In these macros, x is the data item for which a bit is to be tested or set and y specifies which bit
+ * is to be tested or set.
+ */
+
+/** This macro's value is true if the bit specified by y is set in data item x. */
+#define OI_BIT_TEST(x,y)   ((x) & (y))
+
+/** This macro's value is true if the bit specified by y is not set in data item x. */
+#define OI_BIT_CLEAR_TEST(x,y)  (((x) & (y)) == 0)
+
+/** This macro sets the bit specified by y in data item x. */
+#define OI_BIT_SET(x,y)    ((x) |= (y))
+
+/** This macro clears the bit specified by y in data item x. */
+#define OI_BIT_CLEAR(x,y)  ((x) &= ~(y))
+
+/** @} */
+
+/**
+ * The OI_ARRAYSIZE macro is set to the number of elements in an array
+ * (instead of the number of bytes, which is returned by sizeof()).
+ */
+
+#ifndef OI_ARRAYSIZE
+#define OI_ARRAYSIZE(a) (sizeof(a)/sizeof((a)[0]))
+#endif
+
+/**
+ * @name Preprocessor aliases for individual bit positions
+ *      Bits are defined here only if they are not already defined.
+ * @{
+ */
+
+#ifndef BIT0
+
+#define BIT0   0x00000001  /**< preprocessor alias for 32-bit value with bit 0 set, used to specify this single bit */
+#define BIT1   0x00000002  /**< preprocessor alias for 32-bit value with bit 1 set, used to specify this single bit */
+#define BIT2   0x00000004  /**< preprocessor alias for 32-bit value with bit 2 set, used to specify this single bit */
+#define BIT3   0x00000008  /**< preprocessor alias for 32-bit value with bit 3 set, used to specify this single bit */
+#define BIT4   0x00000010  /**< preprocessor alias for 32-bit value with bit 4 set, used to specify this single bit */
+#define BIT5   0x00000020  /**< preprocessor alias for 32-bit value with bit 5 set, used to specify this single bit */
+#define BIT6   0x00000040  /**< preprocessor alias for 32-bit value with bit 6 set, used to specify this single bit */
+#define BIT7   0x00000080  /**< preprocessor alias for 32-bit value with bit 7 set, used to specify this single bit */
+#define BIT8   0x00000100  /**< preprocessor alias for 32-bit value with bit 8 set, used to specify this single bit */
+#define BIT9   0x00000200  /**< preprocessor alias for 32-bit value with bit 9 set, used to specify this single bit */
+#define BIT10  0x00000400  /**< preprocessor alias for 32-bit value with bit 10 set, used to specify this single bit */
+#define BIT11  0x00000800  /**< preprocessor alias for 32-bit value with bit 11 set, used to specify this single bit */
+#define BIT12  0x00001000  /**< preprocessor alias for 32-bit value with bit 12 set, used to specify this single bit */
+#define BIT13  0x00002000  /**< preprocessor alias for 32-bit value with bit 13 set, used to specify this single bit */
+#define BIT14  0x00004000  /**< preprocessor alias for 32-bit value with bit 14 set, used to specify this single bit */
+#define BIT15  0x00008000  /**< preprocessor alias for 32-bit value with bit 15 set, used to specify this single bit */
+#define BIT16  0x00010000  /**< preprocessor alias for 32-bit value with bit 16 set, used to specify this single bit */
+#define BIT17  0x00020000  /**< preprocessor alias for 32-bit value with bit 17 set, used to specify this single bit */
+#define BIT18  0x00040000  /**< preprocessor alias for 32-bit value with bit 18 set, used to specify this single bit */
+#define BIT19  0x00080000  /**< preprocessor alias for 32-bit value with bit 19 set, used to specify this single bit */
+#define BIT20  0x00100000  /**< preprocessor alias for 32-bit value with bit 20 set, used to specify this single bit */
+#define BIT21  0x00200000  /**< preprocessor alias for 32-bit value with bit 21 set, used to specify this single bit */
+#define BIT22  0x00400000  /**< preprocessor alias for 32-bit value with bit 22 set, used to specify this single bit */
+#define BIT23  0x00800000  /**< preprocessor alias for 32-bit value with bit 23 set, used to specify this single bit */
+#define BIT24  0x01000000  /**< preprocessor alias for 32-bit value with bit 24 set, used to specify this single bit */
+#define BIT25  0x02000000  /**< preprocessor alias for 32-bit value with bit 25 set, used to specify this single bit */
+#define BIT26  0x04000000  /**< preprocessor alias for 32-bit value with bit 26 set, used to specify this single bit */
+#define BIT27  0x08000000  /**< preprocessor alias for 32-bit value with bit 27 set, used to specify this single bit */
+#define BIT28  0x10000000  /**< preprocessor alias for 32-bit value with bit 28 set, used to specify this single bit */
+#define BIT29  0x20000000  /**< preprocessor alias for 32-bit value with bit 29 set, used to specify this single bit */
+#define BIT30  0x40000000  /**< preprocessor alias for 32-bit value with bit 30 set, used to specify this single bit */
+#define BIT31  0x80000000  /**< preprocessor alias for 32-bit value with bit 31 set, used to specify this single bit */
+
+#endif  /* BIT0 et al */
+
+
+/** @} */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+/**@}*/
+
+/*****************************************************************************/
+#endif /* OI_STDDEFS_H */
diff --git a/bt/embdrv/sbc/decoder/include/oi_string.h b/bt/embdrv/sbc/decoder/include/oi_string.h
new file mode 100644
index 0000000..e72f020
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/include/oi_string.h
@@ -0,0 +1,208 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef OI_STRING_H
+#define OI_STRING_H
+/**
+ * @file
+ * This file contains BM3 supplied portable string.h functions
+ *
+ */
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+#include "oi_cpu_dep.h"
+#include "oi_stddefs.h"
+
+#if defined(USE_NATIVE_MEMCPY) || defined(USE_NATIVE_MALLOC)
+#include <string.h>
+#endif
+
+/** \addtogroup Misc Miscellaneous APIs */
+/**@{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * If we are using Native malloc(), we must also use
+ * native Ansi string.h functions for memory manipulation.
+ */
+#ifdef USE_NATIVE_MALLOC
+#ifndef USE_NATIVE_MEMCPY
+#define USE_NATIVE_MEMCPY
+#endif
+#endif
+
+#ifdef USE_NATIVE_MEMCPY
+
+#define OI_MemCopy(to, from, size)    memcpy((to), (from), (size))
+#define OI_MemSet(block, val, size)   memset((block), (val), (size))
+#define OI_MemZero(block, size)       memset((block), 0, (size))
+#define OI_MemCmp(s1, s2, n)          memcmp((s1), (s2), (n))
+#define OI_Strcpy(dest, src)          strcpy((dest),(src))
+#define OI_Strcat(dest, src)          strcat((dest),(src))
+#define OI_StrLen(str)                strlen((str))
+#define OI_Strcmp(s1, s2)             strcmp((s1), (s2))
+#define OI_Strncmp(s1, s2, n)         strncmp((s1), (s2), (n))
+
+#else
+
+/*
+ * OI_MemCopy
+ *
+ * Copy an arbitrary number of bytes from one memory address to another.
+ * The underlying implementation is the ANSI memmove() or equivalant, so
+ * overlapping memory copies will work correctly.
+ */
+void OI_MemCopy(void *To, void const *From, uint32_t Size);
+
+
+/*
+ * OI_MemSet
+ *
+ * Sets all bytes in a block of memory to the same value
+ */
+void OI_MemSet(void *Block, uint8_t Val, uint32_t Size);
+
+
+/*
+ * OI_MemZero
+ *
+ * Sets all bytes in a block of memory to zero
+ */
+void OI_MemZero(void *Block, uint32_t Size);
+
+
+/*
+ * OI_MemCmp
+ *
+ * Compare two blocks of memory
+ *
+ * Returns:
+ *        0, if s1 == s2
+ *      < 0, if s1 < s2
+ *      > 0, if s2 > s2
+ */
+OI_INT OI_MemCmp(void const *s1, void const *s2, uint32_t n);
+
+/*
+ * OI_Strcpy
+ *
+ * Copies the Null terminated string from pStr to pDest, and
+ * returns pDest.
+ */
+
+OI_CHAR* OI_Strcpy(OI_CHAR *pDest,
+                   OI_CHAR const *pStr);
+
+/*
+ * OI_Strcat
+ *
+ * Concatonates the pStr string to the end of pDest, and
+ * returns pDest.
+ */
+
+OI_CHAR* OI_Strcat(OI_CHAR *pDest,
+                   OI_CHAR const *pStr) ;
+
+/*
+ * OI_StrLen
+ *
+ * Calculates the number of OI_CHARs in pStr (not including
+ * the Null terminator) and returns the value.
+ */
+OI_UINT OI_StrLen(OI_CHAR const *pStr) ;
+
+/*
+ * OI_Strcmp
+ *
+ * Compares two Null terminated strings
+ *
+ * Returns:
+ *        0, if s1 == s2
+ *      < 0, if s1 < s2
+ *      > 0, if s2 > s2
+ */
+OI_INT OI_Strcmp(OI_CHAR const *s1,
+                 OI_CHAR const *s2);
+
+/*
+ * OI_Strncmp
+ *
+ * Compares the first "len" OI_CHARs of strings s1 and s2.
+ *
+ * Returns:
+ *        0, if s1 == s2
+ *      < 0, if s1 < s2
+ *      > 0, if s2 > s2
+ */
+OI_INT OI_Strncmp(OI_CHAR const *s1,
+                  OI_CHAR const *s2,
+                  uint32_t      len);
+
+
+#endif /* USE_NATIVE_MEMCPY */
+
+/*
+ * OI_StrcmpInsensitive
+ *
+ * Compares two Null terminated strings, treating
+ * the Upper and Lower case of 'A' through 'Z' as
+ * equivilent.
+ *
+ * Returns:
+ *        0, if s1 == s2
+ *      < 0, if s1 < s2
+ *      > 0, if s2 > s2
+ */
+OI_INT OI_StrcmpInsensitive(OI_CHAR const *s1,
+                            OI_CHAR const *s2);
+
+/*
+ * OI_StrncmpInsensitive
+ *
+ * Compares the first "len" OI_CHARs of strings s1 and s2,
+ * treating the Upper and Lower case of 'A' through 'Z' as
+ * equivilent.
+ *
+ *
+ * Returns:
+ *        0, if s1 == s2
+ *      < 0, if s1 < s2
+ *      > 0, if s2 > s2
+ */
+OI_INT OI_StrncmpInsensitive(OI_CHAR const *s1,
+                             OI_CHAR const *s2,
+                             OI_UINT        len);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+/*****************************************************************************/
+#endif /* OI_STRING_H */
+
diff --git a/bt/embdrv/sbc/decoder/include/oi_time.h b/bt/embdrv/sbc/decoder/include/oi_time.h
new file mode 100644
index 0000000..67510c3
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/include/oi_time.h
@@ -0,0 +1,200 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_TIME_H
+#define _OI_TIME_H
+/** @file
+ *
+ * This file provides time type definitions and interfaces to time-related functions.
+ *
+ * The stack maintains a 64-bit real-time millisecond clock. The choice of
+ * milliseconds is for convenience, not accuracy.
+ *
+ * Timeouts are specified as tenths of seconds in a 32-bit value. Timeout values
+ * specified by the Bluetooth specification are usually muliple seconds, so
+ * accuracy to a tenth of a second is more than adequate.
+ *
+ * This file also contains macros to convert between seconds and the Link
+ * Manager's 1.28-second units.
+ *
+ */
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+#include "oi_stddefs.h"
+
+
+/** \addtogroup Misc Miscellaneous APIs */
+/**@{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+/**
+ * Within the core stack timeouts are specified in intervals of tenths of seconds
+ */
+
+typedef uint16_t OI_INTERVAL;
+#define OI_INTERVALS_PER_SECOND     10
+#define MSECS_PER_OI_INTERVAL       (1000 / OI_INTERVALS_PER_SECOND)
+
+/** maximum interval (54 min 36.7 sec) */
+#define OI_MAX_INTERVAL   0x7fff
+
+
+/**
+ * Macro to convert seconds to OI_INTERVAL time units
+ */
+
+#define OI_SECONDS(n)    ((OI_INTERVAL) ((n) * OI_INTERVALS_PER_SECOND))
+
+/**
+ * Macro to convert milliseconds to OI_INTERVAL time units (Rounded Up)
+ */
+
+#define OI_MSECONDS(n)   ((OI_INTERVAL) (((n) + MSECS_PER_OI_INTERVAL - 1) / MSECS_PER_OI_INTERVAL))
+
+/**
+ * Macro to convert minutes to OI_INTERVAL time units
+ */
+
+#define OI_MINUTES(n)    ((OI_INTERVAL) ((n) * OI_SECONDS(60)))
+
+/** Convert an OI_INTERVAL to milliseconds. */
+#define OI_INTERVAL_TO_MILLISECONDS(i) ((i) * MSECS_PER_OI_INTERVAL)
+
+/**
+ * The stack depends on relative not absolute time. Any mapping between the
+ * stack's real-time clock and absolute time and date is implementation-dependent.
+ */
+
+typedef struct {
+    int32_t seconds;
+    int16_t mseconds;
+} OI_TIME;
+
+/**
+ * Convert an OI_TIME to milliseconds.
+ *
+ * @param t  the time to convert
+ *
+ * @return the time in milliseconds
+ */
+uint32_t OI_Time_ToMS(OI_TIME *t);
+
+
+/**
+ * This function compares two time values.
+ *
+ * @param T1 first time to compare.
+ *
+ * @param T2 second time to compare.
+ *
+ * @return
+ @verbatim
+     -1 if t1 < t2
+      0 if t1 = t2
+     +1 if t1 > t2
+ @endverbatim
+ */
+
+int16_t OI_Time_Compare(OI_TIME *T1,
+                         OI_TIME *T2);
+
+
+/**
+ * This function returns the interval between two times to a granularity of 0.1 seconds.
+ *
+ * @param Sooner a time value more recent that Later
+ *
+ * @param Later a time value later than Sooner
+ *
+ * @note The result is an OI_INTERVAL value so this function only works for time intervals
+ * that are less than about 71 minutes.
+ *
+ * @return the time interval between the two times = (Later - Sooner)
+ */
+
+OI_INTERVAL OI_Time_Interval(OI_TIME *Sooner,
+                             OI_TIME *Later);
+
+
+
+/**
+ * This function returns the interval between two times to a granularity of milliseconds.
+ *
+ * @param Sooner a time value more recent that Later
+ *
+ * @param Later a time value later than Sooner
+ *
+ * @note The result is an uint32_t value so this function only works for time intervals
+ * that are less than about 50 days.
+ *
+ * @return the time interval between the two times = (Later - Sooner)
+ */
+
+uint32_t OI_Time_IntervalMsecs(OI_TIME *Sooner,
+                                OI_TIME *Later);
+
+
+
+/**
+ * This function answers the question, Have we reached or gone past the target time?
+ *
+ * @param pTargetTime   target time
+ *
+ * @return  true means time now is at or past target time
+ *          false means target time is still some time in the future
+ */
+
+OI_BOOL  OI_Time_NowReachedTime(OI_TIME *pTargetTime);
+
+/**
+ *  Convert seconds to the Link Manager 1.28-second units
+ *  Approximate by using 1.25 conversion factor.
+ */
+
+#define OI_SECONDS_TO_LM_TIME_UNITS(lmUnits) ((lmUnits)<4?(lmUnits):(lmUnits)-((lmUnits)>>2))
+
+
+/**
+ *  Convert Link Manager 1.28-second units to seconds.
+ *  Approximate by using 1.25 conversion factor.
+ */
+
+#define OI_LM_TIME_UNITS_TO_SECONDS(lmUnits) ((lmUnits) + ((lmUnits)>>2))
+
+#ifdef __cplusplus
+}
+#endif
+
+/**@}*/
+
+/* Include for OI_Time_Now() prototype
+ * Must be included at end to obtain OI_TIME typedef
+ */
+#include "oi_osinterface.h"
+
+/*****************************************************************************/
+#endif /* _OI_TIME_H */
+
diff --git a/bt/embdrv/sbc/decoder/include/oi_utils.h b/bt/embdrv/sbc/decoder/include/oi_utils.h
new file mode 100644
index 0000000..a1ca12e
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/include/oi_utils.h
@@ -0,0 +1,377 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_UTILS_H
+#define _OI_UTILS_H
+/**
+ * @file
+ *
+ * This file provides the interface for utility functions.
+ * Among the utilities are strlen (string length), strcmp (string compare), and
+ * other string manipulation functions. These are provided for those plaforms
+ * where this functionality is not available in stdlib.
+ */
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+#include <stdarg.h>
+#include "oi_common.h"
+#include "oi_string.h"
+#include "oi_bt_spec.h"
+
+/** \addtogroup Misc Miscellaneous APIs */
+/**@{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Opaque type for a callback function handle. See OI_ScheduleCallbackFunction()
+ */
+typedef uint32_t OI_CALLBACK_HANDLE;
+
+
+/**
+ * Function prototype for a timed procedure callback.
+ *
+ * @param arg                 Value that was passed into the OI_ScheduleCallback() function
+ *
+ */
+typedef void (*OI_SCHEDULED_CALLBACK)(void *arg);
+
+
+/**
+ * Registers a function to be called when a timeout expires. This API uses BLUEmagic's internal
+ * function dispatch mechanism, so applications that make extensive use of this facility may need to
+ * increase the value of DispatchTableSize in the configuration block for the dispatcher (see
+ * oi_bt_stack_config.h).
+ *
+ * @param callbackFunction    The function that will be called when the timeout expires
+ *
+ * @param arg                 Value that will be returned as the parameter to the callback function.
+ *
+ * @param timeout             A timeout expressed in OI_INTERVALs (tenths of seconds). This can be
+ *                            zero in which case the callback function will be called as soon as
+ *                            possible.
+ *
+ * @param handle              NULL or a pointer receive the callback handle.
+ *
+ * @return                    OI_OK if the function was reqistered, or an error status.
+ */
+OI_STATUS OI_ScheduleCallbackFunction(OI_SCHEDULED_CALLBACK callbackFunction,
+                                      void                 *arg,
+                                      OI_INTERVAL           timeout,
+                                      OI_CALLBACK_HANDLE   *handle);
+
+
+/**
+ * Cancels a function registered with OI_ScheduleCallbackFunction() before its timer expires.
+ *
+ * @param handle              handle returned by  OI_ScheduleCallbackFunction().
+ *
+ * @return                    OI_OK if the function was cancelled, or an error status.
+ */
+OI_STATUS OI_CancelCallbackFunction(OI_CALLBACK_HANDLE handle);
+
+
+/**
+ * Registers a function to be called when a timeout expires. This version does not return a handle
+ * so can only be canceled by calling OI_CancelCallback().
+ *
+ * @param callbackFunction    The function that will be called when the timeout expires
+ *
+ * @param arg                 Value that will be returned as the parameter to the callback function.
+ *
+ * @param timeout             A timeout expressed in OI_INTERVALs (tenths of seconds). This can be
+ *                            zero in which case the callback function will be called as soon as
+ *                            possible.
+ *
+ * @return                    OI_OK if the function was reqistered, or an error status.
+ */
+#define OI_ScheduleCallback(f, a, t)  OI_ScheduleCallbackFunction(f, a, t, NULL);
+
+
+/**
+ * Cancels a function registered with OI_ScheduleCallback() before its timer expires. This
+ * function will cancel the first entry matches the indicated callback function pointer.
+ *
+ * @param callbackFunction    The function that was originally registered
+ *
+ * @return                    OI_OK if the function was cancelled, or an error status.
+ */
+OI_STATUS OI_CancelCallback(OI_SCHEDULED_CALLBACK callbackFunction);
+
+
+/**
+ * Parse a Bluetooth device address from the specified string.
+ *
+ * @param str   the string to parse
+ * @param addr  the parsed address, if successful
+ *
+ * @return true if an address was successfully parsed, false otherwise
+ */
+
+OI_BOOL OI_ParseBdAddr(const OI_CHAR *str,
+                       OI_BD_ADDR    *addr) ;
+
+/**
+ * Printf function for platforms which have no stdio or printf available.
+ * OI_Printf supports the basic formatting types, with the exception of
+ * floating point types. Additionally, OI_Printf supports several formats
+ * specific to BLUEmagic 3.0 software:
+ *
+ * \%!   prints the string for an #OI_STATUS value.
+ *       @code OI_Printf("There was an error %!", status); @endcode
+ *
+ * \%@   prints a hex dump of a buffer.
+ *       Requires a pointer to the buffer and a signed integer length
+ *       (0 for default length). If the buffer is large, only an excerpt will
+ *       be printed.
+ *       @code OI_Printf("Contents of buffer %@", buffer, sizeof(buffer)); @endcode
+ *
+ * \%:   prints a Bluetooth address in the form "HH:HH:HH:HH:HH:HH".
+ *       Requires a pointer to an #OI_BD_ADDR.
+ *       @code OI_Printf("Bluetooth address %:", &bdaddr); @endcode
+ *
+ * \%^   decodes and prints a data element as formatted XML.
+ *       Requires a pointer to an #OI_DATAELEM.
+ *       @code OI_Printf("Service attribute list is:\n%^", &attributes); @endcode
+ *
+ * \%/   prints the base file name of a path, that is, the final substring
+ *       following a '/' or '\\' character. Requires a pointer to a null
+ *       terminated string.
+ *       @code OI_Printf("File %/", "c:\\dir1\\dir2\\file.txt"); @endcode
+ *
+ * \%~   prints a string, escaping characters as needed to display it in
+ *       ASCII. Requires a pointer to an #OI_PSTR and an #OI_UNICODE_ENCODING
+ *       parameter.
+ *       @code OI_Printf("Identifier %~", &id, OI_UNICODE_UTF16_BE); @endcode
+ *
+ * \%[   inserts an ANSI color escape sequence. Requires a single character
+ *       identifying the color to select. Colors are red (r/R), green (g/G),
+ *       blue (b/B), yellow (y/Y), cyan (c/C), magenta (m/M), white (W),
+ *       light-gray (l/L), dark-gray (d/D), and black (0). The lower case is
+ *       dim, the upper case is bright (except in the case of light-gray and
+ *       dark-gray, where bright and dim are identical). Any other value will
+ *       select the default color.
+ *       @code OI_Printf("%[red text %[black %[normal\n", 'r', '0', 0); @endcode
+ *
+ * \%a   same as \%s, except '\\r' and '\\n' are output as "<cr>" and "<lf>".
+ *       \%?a is valid, but \%la is not.
+ *
+ * \%b   prints an integer in base 2.
+ *       @code OI_Printf("Bits are %b", I); @endcode
+ *
+ * \%lb  prints a long integer in base 2.
+ *
+ * \%?b  prints the least significant N bits of an integer (or long integer)
+ *       in base 2. Requires the integer and a length N.
+ *       @code OI_Printf("Bottom 4 bits are: %?b", I, 4); @endcode
+ *
+ * \%B   prints an integer as boolean text, "TRUE" or "FALSE".
+ *       @code OI_Printf("The value 0 is %B, the value 1 is %B", 0, 1); @endcode
+ *
+ * \%?s  prints a substring up to a specified maximum length.
+ *       Requires a pointer to a string and a length parameter.
+ *       @code OI_Printf("String prefix is %?s", str, 3); @endcode
+ *
+ * \%ls  same as \%S.
+ *
+ * \%S   prints a UTF16 string as UTF8 (plain ASCII, plus 8-bit char sequences
+ *       where needed). Requires a pointer to #OI_CHAR16. \%?S is valid. The
+ *       length parameter is in OI_CHAR16 characters.
+ *
+ * \%T   prints time, formatted as "secs.msecs".
+ *       Requires pointer to #OI_TIME struct, NULL pointer prints current time.
+ *       @code OI_Printf("The time now is %T", NULL); @endcode
+ *
+ *  @param format   The format string
+ *
+ */
+void OI_Printf(const OI_CHAR *format, ...);
+
+
+/**
+ * Var-args version OI_Printf
+ *
+ * @param format   Same as for OI_Printf.
+ *
+ * @param argp     Var-args list.
+ */
+void OI_VPrintf(const OI_CHAR *format, va_list argp);
+
+
+/**
+ * Writes a formatted string to a buffer. This function supports the same format specifiers as
+ * OI_Printf().
+ *
+ * @param buffer   Destination buffer for the formatted string.
+ *
+ * @param bufLen   The length of the destination buffer.
+ *
+ * @param format   The format string
+ *
+ * @return   Number of characters written or -1 in the case of an error.
+ */
+int32_t OI_SNPrintf(OI_CHAR *buffer,
+                    uint16_t bufLen,
+                    const OI_CHAR* format, ...);
+
+
+/**
+ * Var-args version OI_SNPrintf
+ *
+ * @param buffer   Destination buffer for the formatted string.
+ *
+ * @param bufLen   The length of the destination buffer.
+ *
+ * @param format   The format string
+ *
+ * @param argp     Var-args list.
+ *
+ * @return   Number of characters written or -1 in the case of an error.
+ */
+int32_t OI_VSNPrintf(OI_CHAR *buffer,
+                     uint16_t bufLen,
+                     const OI_CHAR *format, va_list argp);
+
+
+/**
+ * Convert a string to an integer.
+ *
+ * @param str  the string to parse
+ *
+ * @return the integer value of the string or 0 if the string could not be parsed
+ */
+OI_INT OI_atoi(const OI_CHAR *str);
+
+
+/**
+ * Parse a signed integer in a string.
+ *
+ * Skips leading whitespace (space and tabs only) and parses a decimal or hex string. Hex string
+ * must be prefixed by "0x". Returns pointer to first character following the integer. Returns the
+ * pointer passed in if the string does not describe an integer.
+ *
+ * @param str    String to parse.
+ *
+ * @param val    Pointer to receive the parsed integer value.
+ *
+ * @return       A pointer to the first character following the integer or the pointer passed in.
+ */
+const OI_CHAR* OI_ScanInt(const OI_CHAR *str,
+                          int32_t *val);
+
+
+/**
+ * Parse an unsigned integer in a string.
+ *
+ * Skips leading whitespace (space and tabs only) and parses a decimal or hex string. Hex string
+ * must be prefixed by "0x". Returns pointer to first character following the integer. Returns the
+ * pointer passed in if the string does not describe an integer.
+ *
+ * @param str    String to parse.
+ *
+ * @param val    Pointer to receive the parsed unsigned integer value.
+ *
+ * @return       A pointer to the first character following the unsigned integer or the pointer passed in.
+ */
+const OI_CHAR* OI_ScanUInt(const OI_CHAR *str,
+                           uint32_t *val);
+
+/**
+ * Parse a whitespace delimited substring out of a string.
+ *
+ * @param str     Input string to parse.
+ * @param outStr  Buffer to return the substring
+ * @param len     Length of outStr
+ *
+ *
+ * @return       A pointer to the first character following the substring or the pointer passed in.
+ */
+const OI_CHAR* OI_ScanStr(const OI_CHAR *str,
+                          OI_CHAR *outStr,
+                          uint16_t len);
+
+
+/**
+ * Parse a string for one of a set of alternative value. Skips leading whitespace (space and tabs
+ * only) and parses text matching one of the alternative strings. Returns pointer to first character
+ * following the matched text.
+ *
+ * @param str    String to parse.
+ *
+ * @param alts   Alternative matching strings separated by '|'
+ *
+ * @param index  Pointer to receive the index of the matching alternative, return value is -1 if
+ *               there is no match.
+ *
+ * @return       A pointer to the first character following the matched value or the pointer passed in
+ *               if there was no matching text.
+ */
+const OI_CHAR* OI_ScanAlt(const OI_CHAR *str,
+                          const OI_CHAR *alts,
+                          OI_INT *index);
+
+/**
+ * Parse a string for a BD Addr. Skips leading whitespace (space and tabs only) and parses a
+ * Bluetooth device address with nibbles optionally separated by colons. Return pointet to first
+ * character following the BD Addr.
+ *
+ * @param str    String to parse.
+ *
+ * @param addr   Pointer to receive the Bluetooth device address
+ *
+ * @return       A pointer to the first character following the BD Addr or the pointer passed in.
+ */
+const OI_CHAR* OI_ScanBdAddr(const OI_CHAR *str,
+                             OI_BD_ADDR *addr);
+
+
+/** Get a character from a digit integer value (0 - 9). */
+#define OI_DigitToChar(d) ((d) + '0')
+
+/**
+ * Determine Maximum and Minimum between two arguments.
+ *
+ * @param a  1st value
+ * @param b  2nd value
+ *
+ * @return the max or min value between a & b
+ */
+#define OI_MAX(a, b) (((a) < (b)) ? (b) : (a) )
+#define OI_MIN(a, b) (((a) > (b)) ? (b) : (a) )
+
+/**
+ * Compare two BD_ADDRs
+ * SAME_BD_ADDR - Boolean: true if they are the same address
+ */
+
+#define SAME_BD_ADDR(x, y)      (0 == OI_MemCmp((x),(y),OI_BD_ADDR_BYTE_SIZE) )
+
+#ifdef __cplusplus
+}
+#endif
+
+/**@}*/
+
+#endif /* _OI_UTILS_H */
+
diff --git a/bt/embdrv/sbc/decoder/srce/alloc.c b/bt/embdrv/sbc/decoder/srce/alloc.c
new file mode 100644
index 0000000..db78693
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/srce/alloc.c
@@ -0,0 +1,78 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <stdlib.h>
+#include <oi_codec_sbc_private.h>
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+PRIVATE OI_STATUS OI_CODEC_SBC_Alloc(OI_CODEC_SBC_COMMON_CONTEXT *common,
+                                     uint32_t *codecDataAligned,
+                                     uint32_t codecDataBytes,
+                                     uint8_t maxChannels,
+                                     uint8_t pcmStride)
+{
+    int i;
+    size_t filterBufferCount;
+    size_t subdataSize;
+    OI_BYTE *codecData = (OI_BYTE*)codecDataAligned;
+
+    if (maxChannels < 1 || maxChannels > 2) {
+        return OI_STATUS_INVALID_PARAMETERS;
+    }
+
+    if (pcmStride < 1 || pcmStride > maxChannels) {
+        return OI_STATUS_INVALID_PARAMETERS;
+    }
+
+    common->maxChannels = maxChannels;
+    common->pcmStride = pcmStride;
+
+    /* Compute sizes needed for the memory regions, and bail if we don't have
+     * enough memory for them. */
+    subdataSize = maxChannels * sizeof(common->subdata[0]) * SBC_MAX_BANDS * SBC_MAX_BLOCKS;
+    if (subdataSize > codecDataBytes) {
+        return OI_STATUS_OUT_OF_MEMORY;
+    }
+
+    filterBufferCount = (codecDataBytes - subdataSize) / (sizeof(common->filterBuffer[0][0]) * SBC_MAX_BANDS * maxChannels);
+    if (filterBufferCount < SBC_CODEC_MIN_FILTER_BUFFERS) {
+        return OI_STATUS_OUT_OF_MEMORY;
+    }
+    common->filterBufferLen = filterBufferCount * SBC_MAX_BANDS;
+
+    /* Allocate memory for the subband data */
+    common->subdata = (int32_t*)codecData;
+    codecData += subdataSize;
+    OI_ASSERT(codecDataBytes >= subdataSize);
+    codecDataBytes -= subdataSize;
+
+    /* Allocate memory for the synthesis buffers */
+    for (i = 0; i < maxChannels; ++i) {
+        size_t allocSize = common->filterBufferLen * sizeof(common->filterBuffer[0][0]);
+        common->filterBuffer[i] = (SBC_BUFFER_T*)codecData;
+        OI_ASSERT(codecDataBytes >= allocSize);
+        codecData += allocSize;
+        codecDataBytes -= allocSize;
+    }
+
+    return OI_OK;
+}
diff --git a/bt/embdrv/sbc/decoder/srce/bitalloc-sbc.c b/bt/embdrv/sbc/decoder/srce/bitalloc-sbc.c
new file mode 100644
index 0000000..ac32d01
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/srce/bitalloc-sbc.c
@@ -0,0 +1,165 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+/** @file
+@ingroup codec_internal
+*/
+
+/**@addgroup codec_internal*/
+/**@{*/
+
+#include <oi_codec_sbc_private.h>
+
+static void dualBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT *common)
+{
+    OI_UINT bitcountL;
+    OI_UINT bitcountR;
+    OI_UINT bitpoolPreferenceL = 0;
+    OI_UINT bitpoolPreferenceR = 0;
+    BITNEED_UNION1 bitneedsL;
+    BITNEED_UNION1 bitneedsR;
+
+    bitcountL = computeBitneed(common, bitneedsL.uint8, 0, &bitpoolPreferenceL);
+    bitcountR = computeBitneed(common, bitneedsR.uint8, 1, &bitpoolPreferenceR);
+
+    oneChannelBitAllocation(common, &bitneedsL, 0, bitcountL);
+    oneChannelBitAllocation(common, &bitneedsR, 1, bitcountR);
+}
+
+static void stereoBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT *common)
+{
+    const OI_UINT nrof_subbands = common->frameInfo.nrof_subbands;
+    BITNEED_UNION2 bitneeds;
+    OI_UINT excess;
+    OI_INT bitadjust;
+    OI_UINT bitcount;
+    OI_UINT sbL;
+    OI_UINT sbR;
+    OI_UINT bitpoolPreference = 0;
+
+    bitcount = computeBitneed(common, &bitneeds.uint8[0], 0, &bitpoolPreference);
+    bitcount += computeBitneed(common, &bitneeds.uint8[nrof_subbands], 1, &bitpoolPreference);
+
+    {
+        OI_UINT ex;
+        bitadjust = adjustToFitBitpool(common->frameInfo.bitpool, bitneeds.uint32, 2 * nrof_subbands, bitcount, &ex);
+        /* We want the compiler to put excess into a register */
+        excess = ex;
+    }
+    sbL = 0;
+    sbR = nrof_subbands;
+    while (sbL < nrof_subbands) {
+        excess = allocAdjustedBits(&common->bits.uint8[sbL], bitneeds.uint8[sbL] + bitadjust, excess);
+        ++sbL;
+        excess = allocAdjustedBits(&common->bits.uint8[sbR], bitneeds.uint8[sbR] + bitadjust, excess);
+        ++sbR;
+    }
+    sbL = 0;
+    sbR = nrof_subbands;
+    while (excess) {
+        excess = allocExcessBits(&common->bits.uint8[sbL], excess);
+        ++sbL;
+        if (!excess) {
+            break;
+        }
+        excess = allocExcessBits(&common->bits.uint8[sbR], excess);
+        ++sbR;
+    }
+
+}
+
+static const BIT_ALLOC balloc[] = {
+    monoBitAllocation,    /* SBC_MONO */
+    dualBitAllocation,    /* SBC_DUAL_CHANNEL */
+    stereoBitAllocation,  /* SBC_STEREO */
+    stereoBitAllocation   /* SBC_JOINT_STEREO */
+};
+
+
+PRIVATE void OI_SBC_ComputeBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT *common)
+{
+    OI_ASSERT(common->frameInfo.bitpool <= OI_SBC_MaxBitpool(&common->frameInfo));
+    OI_ASSERT(common->frameInfo.mode < OI_ARRAYSIZE(balloc));
+
+    /*
+     * Using an array of function pointers prevents the compiler from creating a suboptimal
+     * monolithic inlined bit allocation function.
+     */
+    balloc[common->frameInfo.mode](common);
+}
+
+uint32_t OI_CODEC_SBC_CalculateBitrate(OI_CODEC_SBC_FRAME_INFO *frame)
+{
+    return internal_CalculateBitrate(frame);
+}
+
+/*
+ * Return the current maximum bitneed and clear it.
+ */
+uint8_t OI_CODEC_SBC_GetMaxBitneed(OI_CODEC_SBC_COMMON_CONTEXT *common)
+{
+    uint8_t max = common->maxBitneed;
+
+    common->maxBitneed = 0;
+    return max;
+}
+
+/*
+ * Calculates the bitpool size for a given frame length
+ */
+uint16_t OI_CODEC_SBC_CalculateBitpool(OI_CODEC_SBC_FRAME_INFO *frame,
+                                        uint16_t frameLen)
+{
+    uint16_t nrof_subbands = frame->nrof_subbands;
+    uint16_t nrof_blocks = frame->nrof_blocks;
+    uint16_t hdr;
+    uint16_t bits;
+
+    if (frame->mode == SBC_JOINT_STEREO) {
+        hdr = 9 * nrof_subbands;
+    } else {
+        if (frame->mode == SBC_MONO) {
+            hdr = 4 * nrof_subbands;
+        } else {
+            hdr = 8 * nrof_subbands;
+        }
+        if (frame->mode == SBC_DUAL_CHANNEL) {
+            nrof_blocks *= 2;
+        }
+    }
+    bits = 8 * (frameLen - SBC_HEADER_LEN) - hdr;
+    return DIVIDE(bits, nrof_blocks);
+}
+
+uint16_t OI_CODEC_SBC_CalculatePcmBytes(OI_CODEC_SBC_COMMON_CONTEXT *common)
+{
+    return sizeof(int16_t) * common->pcmStride * common->frameInfo.nrof_subbands * common->frameInfo.nrof_blocks;
+}
+
+
+uint16_t OI_CODEC_SBC_CalculateFramelen(OI_CODEC_SBC_FRAME_INFO *frame)
+{
+    return internal_CalculateFramelen(frame);
+}
+
+/**@}*/
diff --git a/bt/embdrv/sbc/decoder/srce/bitalloc.c b/bt/embdrv/sbc/decoder/srce/bitalloc.c
new file mode 100644
index 0000000..5cb10ef
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/srce/bitalloc.c
@@ -0,0 +1,392 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/**********************************************************************************
+  $Revision: #1 $
+ ***********************************************************************************/
+
+/**
+@file
+
+The functions in this file relate to the allocation of available bits to
+subbands within the SBC/eSBC frame, along with support functions for computing
+frame length and bitrate.
+
+@ingroup codec_internal
+*/
+
+/**
+@addtogroup codec_internal
+@{
+*/
+
+#include "oi_utils.h"
+#include <oi_codec_sbc_private.h>
+
+uint32_t OI_SBC_MaxBitpool(OI_CODEC_SBC_FRAME_INFO *frame)
+{
+    switch (frame->mode) {
+        case SBC_MONO:
+        case SBC_DUAL_CHANNEL:
+            return 16 * frame->nrof_subbands;
+        case SBC_STEREO:
+        case SBC_JOINT_STEREO:
+            return 32 * frame->nrof_subbands;
+    }
+
+    ERROR(("Invalid frame mode %d", frame->mode));
+    OI_ASSERT(false);
+    return 0; /* Should never be reached */
+}
+
+
+PRIVATE uint16_t internal_CalculateFramelen(OI_CODEC_SBC_FRAME_INFO *frame)
+{
+    uint16_t nbits = frame->nrof_blocks * frame->bitpool;
+    uint16_t nrof_subbands = frame->nrof_subbands;
+    uint16_t result = nbits;
+
+    if (frame->mode == SBC_JOINT_STEREO) {
+        result += nrof_subbands + (8 * nrof_subbands);
+    } else {
+        if (frame->mode == SBC_DUAL_CHANNEL) { result += nbits; }
+        if (frame->mode == SBC_MONO) { result += 4*nrof_subbands; } else { result += 8*nrof_subbands; }
+    }
+    return SBC_HEADER_LEN + (result + 7) / 8;
+}
+
+
+PRIVATE uint32_t internal_CalculateBitrate(OI_CODEC_SBC_FRAME_INFO *frame)
+{
+    OI_UINT blocksbands;
+    blocksbands = frame->nrof_subbands * frame->nrof_blocks;
+
+    return DIVIDE(8 * internal_CalculateFramelen(frame) * frame->frequency, blocksbands);
+}
+
+
+INLINE uint16_t OI_SBC_CalculateFrameAndHeaderlen(OI_CODEC_SBC_FRAME_INFO *frame, OI_UINT *headerLen_)
+{
+    OI_UINT headerLen = SBC_HEADER_LEN + frame->nrof_subbands * frame->nrof_channels/2;
+
+    if (frame->mode == SBC_JOINT_STEREO) { headerLen++; }
+
+    *headerLen_ = headerLen;
+    return internal_CalculateFramelen(frame);
+}
+
+
+#define MIN(x, y)  ((x) < (y) ? (x) : (y))
+
+
+/*
+ * Computes the bit need for each sample and as also returns a counts of bit needs that are greater
+ * than one. This count is used in the first phase of bit allocation.
+ *
+ * We also compute a preferred bitpool value that this is the minimum bitpool needed to guarantee
+ * lossless representation of the audio data. The preferred bitpool may be larger than the bits
+ * actually required but the only input we have are the scale factors. For example, it takes 2 bits
+ * to represent values in the range -1 .. +1 but the scale factor is 0. To guarantee lossless
+ * representation we add 2 to each scale factor and sum them to come up with the preferred bitpool.
+ * This is not ideal because 0 requires 0 bits but we currently have no way of knowing this.
+ *
+ * @param bitneed       Array to return bitneeds for each subband
+ *
+ * @param ch            Channel 0 or 1
+ *
+ * @param preferredBitpool  Returns the number of reserved bits
+ *
+ * @return              The SBC bit need
+ *
+ */
+OI_UINT computeBitneed(OI_CODEC_SBC_COMMON_CONTEXT *common,
+                              uint8_t *bitneeds,
+                              OI_UINT ch,
+                              OI_UINT *preferredBitpool)
+{
+    static const int8_t offset4[4][4] = {
+        { -1, 0, 0, 0 },
+        { -2, 0, 0, 1 },
+        { -2, 0, 0, 1 },
+        { -2, 0, 0, 1 }
+    };
+
+    static const int8_t offset8[4][8] = {
+        { -2, 0, 0, 0, 0, 0, 0, 1 },
+        { -3, 0, 0, 0, 0, 0, 1, 2 },
+        { -4, 0, 0, 0, 0, 0, 1, 2 },
+        { -4, 0, 0, 0, 0, 0, 1, 2 }
+    };
+
+    const OI_UINT nrof_subbands = common->frameInfo.nrof_subbands;
+    OI_UINT sb;
+    int8_t *scale_factor = &common->scale_factor[ch ? nrof_subbands : 0];
+    OI_UINT bitcount = 0;
+    uint8_t maxBits = 0;
+    uint8_t prefBits = 0;
+
+    if (common->frameInfo.alloc == SBC_SNR) {
+        for (sb = 0; sb < nrof_subbands; sb++) {
+            OI_INT bits = scale_factor[sb];
+            if (bits > maxBits) {
+                maxBits = bits;
+            }
+            if ((bitneeds[sb] = bits) > 1) {
+                bitcount += bits;
+            }
+            prefBits += 2 + bits;
+        }
+    } else {
+        const int8_t *offset;
+        if (nrof_subbands == 4) {
+            offset = offset4[common->frameInfo.freqIndex];
+        } else {
+            offset = offset8[common->frameInfo.freqIndex];
+        }
+        for (sb = 0; sb < nrof_subbands; sb++) {
+            OI_INT bits = scale_factor[sb];
+            if (bits > maxBits) {
+                maxBits = bits;
+            }
+            prefBits += 2 + bits;
+            if (bits) {
+                bits -= offset[sb];
+                if (bits > 0) {
+                    bits /= 2;
+                }
+                bits += 5;
+            }
+            if ((bitneeds[sb] = bits) > 1) {
+                bitcount += bits;
+            }
+        }
+    }
+    common->maxBitneed = OI_MAX(maxBits, common->maxBitneed);
+    *preferredBitpool += prefBits;
+    return bitcount;
+}
+
+
+/*
+ * Explanation of the adjustToFitBitpool inner loop.
+ *
+ * The inner loop computes the effect of adjusting the bit allocation up or
+ * down. Allocations must be 0 or in the range 2..16. This is accomplished by
+ * the following code:
+ *
+ *           for (s = bands - 1; s >= 0; --s) {
+ *              OI_INT bits = bitadjust + bitneeds[s];
+ *              bits = bits < 2 ? 0 : bits;
+ *              bits = bits > 16 ? 16 : bits;
+ *              count += bits;
+ *          }
+ *
+ * This loop can be optimized to perform 4 operations at a time as follows:
+ *
+ * Adjustment is computed as a 7 bit signed value and added to the bitneed.
+ *
+ * Negative allocations are zeroed by masking. (n & 0x40) >> 6 puts the
+ * sign bit into bit 0, adding this to 0x7F give us a mask of 0x80
+ * for -ve values and 0x7F for +ve values.
+ *
+ * n &= 0x7F + (n & 0x40) >> 6)
+ *
+ * Allocations greater than 16 are truncated to 16. Adjusted allocations are in
+ * the range 0..31 so we know that bit 4 indicates values >= 16. We use this bit
+ * to create a mask that zeroes bits 0 .. 3 if bit 4 is set.
+ *
+ * n &= (15 + (n >> 4))
+ *
+ * Allocations of 1 are disallowed. Add and shift creates a mask that
+ * eliminates the illegal value
+ *
+ * n &= ((n + 14) >> 4) | 0x1E
+ *
+ * These operations can be performed in 8 bits without overflowing so we can
+ * operate on 4 values at once.
+ */
+
+
+/*
+ * Encoder/Decoder
+ *
+ * Computes adjustment +/- of bitneeds to fill bitpool and returns overall
+ * adjustment and excess bits.
+ *
+ * @param bitpool   The bitpool we have to work within
+ *
+ * @param bitneeds  An array of bit needs (more acturately allocation prioritities) for each
+ *                  subband across all blocks in the SBC frame
+ *
+ * @param subbands  The number of subbands over which the adkustment is calculated. For mono and
+ *                  dual mode this is 4 or 8, for stereo or joint stereo this is 8 or 16.
+ *
+ * @param bitcount  A starting point for the adjustment
+ *
+ * @param excess    Returns the excess bits after the adjustment
+ *
+ * @return   The adjustment.
+ */
+OI_INT adjustToFitBitpool(const OI_UINT bitpool,
+                                 uint32_t *bitneeds,
+                                 const OI_UINT subbands,
+                                 OI_UINT bitcount,
+                                 OI_UINT *excess)
+{
+    OI_INT maxBitadjust = 0;
+    OI_INT bitadjust = (bitcount > bitpool) ? -8 : 8;
+    OI_INT chop = 8;
+
+    /*
+     * This is essentially a binary search for the optimal adjustment value.
+     */
+    while ((bitcount != bitpool) && chop) {
+        uint32_t total = 0;
+        OI_UINT count;
+        uint32_t adjust4;
+        OI_INT i;
+
+        adjust4 = bitadjust & 0x7F;
+        adjust4 |= (adjust4 << 8);
+        adjust4 |= (adjust4 << 16);
+
+        for (i = (subbands / 4 - 1); i >= 0; --i) {
+            uint32_t mask;
+            uint32_t n = bitneeds[i] + adjust4;
+            mask = 0x7F7F7F7F + ((n & 0x40404040) >> 6);
+            n &= mask;
+            mask = 0x0F0F0F0F + ((n & 0x10101010) >> 4);
+            n &= mask;
+            mask = (((n + 0x0E0E0E0E) >> 4) | 0x1E1E1E1E);
+            n &= mask;
+            total += n;
+        }
+
+        count = (total & 0xFFFF) + (total >> 16);
+        count = (count & 0xFF) + (count >> 8);
+
+        chop >>= 1;
+        if (count > bitpool) {
+            bitadjust -= chop;
+        } else {
+            maxBitadjust = bitadjust;
+            bitcount = count;
+            bitadjust += chop;
+        }
+    }
+
+    *excess = bitpool - bitcount;
+
+    return maxBitadjust;
+}
+
+
+/*
+ * The bit allocator trys to avoid single bit allocations except as a last resort. So in the case
+ * where a bitneed of 1 was passed over during the adsjustment phase 2 bits are now allocated.
+ */
+INLINE OI_INT allocAdjustedBits(uint8_t *dest,
+                                OI_INT bits,
+                                OI_INT excess)
+{
+    if (bits < 16) {
+        if (bits > 1) {
+            if (excess) {
+                ++bits;
+                --excess;
+            }
+        } else if ((bits == 1) && (excess > 1)) {
+            bits = 2;
+            excess -= 2;
+        } else {
+            bits  = 0;
+        }
+    } else {
+        bits = 16;
+    }
+    *dest = (uint8_t)bits;
+    return excess;
+}
+
+
+/*
+ * Excess bits not allocated by allocaAdjustedBits are allocated round-robin.
+ */
+INLINE OI_INT allocExcessBits(uint8_t *dest,
+                              OI_INT excess)
+{
+    if (*dest < 16) {
+        *dest += 1;
+        return excess - 1;
+    } else {
+        return excess;
+    }
+}
+
+void oneChannelBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT *common,
+                                    BITNEED_UNION1 *bitneeds,
+                                    OI_UINT ch,
+                                    OI_UINT bitcount)
+{
+    const uint8_t nrof_subbands = common->frameInfo.nrof_subbands;
+    OI_UINT excess;
+    OI_UINT sb;
+    OI_INT bitadjust;
+    uint8_t RESTRICT *allocBits;
+
+
+    {
+        OI_UINT ex;
+        bitadjust = adjustToFitBitpool(common->frameInfo.bitpool, bitneeds->uint32, nrof_subbands, bitcount, &ex);
+        /* We want the compiler to put excess into a register */
+        excess = ex;
+    }
+
+    /*
+     * Allocate adjusted bits
+     */
+    allocBits = &common->bits.uint8[ch ? nrof_subbands : 0];
+
+    sb = 0;
+    while (sb < nrof_subbands) {
+        excess = allocAdjustedBits(&allocBits[sb], bitneeds->uint8[sb] + bitadjust, excess);
+        ++sb;
+    }
+    sb = 0;
+    while (excess) {
+        excess = allocExcessBits(&allocBits[sb], excess);
+        ++sb;
+    }
+}
+
+
+void monoBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT *common)
+{
+    BITNEED_UNION1 bitneeds;
+    OI_UINT bitcount;
+    OI_UINT bitpoolPreference = 0;
+
+    bitcount = computeBitneed(common, bitneeds.uint8, 0, &bitpoolPreference);
+
+    oneChannelBitAllocation(common, &bitneeds, 0, bitcount);
+}
+
+/**
+@}
+*/
diff --git a/bt/embdrv/sbc/decoder/srce/bitstream-decode.c b/bt/embdrv/sbc/decoder/srce/bitstream-decode.c
new file mode 100644
index 0000000..d5cee27
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/srce/bitstream-decode.c
@@ -0,0 +1,92 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+/**
+@file
+Functions for manipulating input bitstreams.
+
+@ingroup codec_internal
+*/
+
+/**
+@addtogroup codec_internal
+@{
+*/
+
+#include "oi_stddefs.h"
+#include "oi_bitstream.h"
+#include "oi_assert.h"
+
+PRIVATE void OI_BITSTREAM_ReadInit(OI_BITSTREAM *bs,
+                                   const OI_BYTE *buffer)
+{
+    bs->value = ((int32_t)buffer[0] << 16) | ((int32_t)buffer[1] << 8) | (buffer[2]);
+    bs->ptr.r = buffer + 3;
+    bs->bitPtr = 8;
+}
+
+PRIVATE uint32_t OI_BITSTREAM_ReadUINT(OI_BITSTREAM *bs, OI_UINT bits)
+{
+    uint32_t result;
+
+    OI_BITSTREAM_READUINT(result, bits, bs->ptr.r, bs->value, bs->bitPtr);
+
+    return result;
+}
+
+PRIVATE uint8_t OI_BITSTREAM_ReadUINT4Aligned(OI_BITSTREAM *bs)
+{
+    uint32_t result;
+
+    OI_ASSERT(bs->bitPtr < 16);
+    OI_ASSERT(bs->bitPtr % 4 == 0);
+
+    if (bs->bitPtr == 8) {
+        result = bs->value << 8;
+        bs->bitPtr = 12;
+    } else {
+        result = bs->value << 12;
+        bs->value = (bs->value << 8) | *bs->ptr.r++;
+        bs->bitPtr = 8;
+    }
+    result >>= 28;
+    OI_ASSERT(result < (1u << 4));
+    return (uint8_t)result;
+}
+
+PRIVATE uint8_t OI_BITSTREAM_ReadUINT8Aligned(OI_BITSTREAM *bs)
+{
+    uint32_t result;
+    OI_ASSERT(bs->bitPtr == 8);
+
+    result = bs->value >> 16;
+    bs->value = (bs->value << 8) | *bs->ptr.r++;
+
+    return (uint8_t)result;
+}
+
+/**
+@}
+*/
+
+
diff --git a/bt/embdrv/sbc/decoder/srce/decoder-oina.c b/bt/embdrv/sbc/decoder/srce/decoder-oina.c
new file mode 100644
index 0000000..d9db02f
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/srce/decoder-oina.c
@@ -0,0 +1,140 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2006 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/**********************************************************************************
+  $Revision: #1 $
+ ***********************************************************************************/
+
+/**
+@file
+This file exposes OINA-specific interfaces to decoder functions.
+
+@ingroup codec_internal
+*/
+
+/**
+@addtogroup codec_internal
+@{
+*/
+
+
+#include <oi_codec_sbc_private.h>
+
+OI_STATUS OI_CODEC_SBC_DecoderConfigureRaw(OI_CODEC_SBC_DECODER_CONTEXT *context,
+                                           OI_BOOL enhanced,
+                                           uint8_t frequency,
+                                           uint8_t mode,
+                                           uint8_t subbands,
+                                           uint8_t blocks,
+                                           uint8_t alloc,
+                                           uint8_t maxBitpool)
+{
+    if (frequency > SBC_FREQ_48000) {
+        return OI_STATUS_INVALID_PARAMETERS;
+    }
+
+    if (enhanced) {
+#ifdef SBC_ENHANCED
+        if (subbands != SBC_SUBBANDS_8) {
+            return OI_STATUS_INVALID_PARAMETERS;
+        }
+#else
+        return OI_STATUS_INVALID_PARAMETERS;
+#endif
+    }
+
+    if (mode > SBC_JOINT_STEREO) {
+        return OI_STATUS_INVALID_PARAMETERS;
+    }
+
+    if (subbands > SBC_SUBBANDS_8) {
+        return OI_STATUS_INVALID_PARAMETERS;
+    }
+
+    if (blocks > SBC_BLOCKS_16) {
+        return OI_STATUS_INVALID_PARAMETERS;
+    }
+
+    if (alloc > SBC_SNR) {
+        return OI_STATUS_INVALID_PARAMETERS;
+    }
+
+#ifdef SBC_ENHANCED
+    context->common.frameInfo.enhanced = enhanced;
+#else
+    context->common.frameInfo.enhanced = FALSE;
+#endif
+    context->common.frameInfo.freqIndex = frequency;
+    context->common.frameInfo.mode = mode;
+    context->common.frameInfo.subbands = subbands;
+    context->common.frameInfo.blocks = blocks;
+    context->common.frameInfo.alloc = alloc;
+    context->common.frameInfo.bitpool = maxBitpool;
+
+    OI_SBC_ExpandFrameFields(&context->common.frameInfo);
+
+    if (context->common.frameInfo.nrof_channels >= context->common.pcmStride) {
+        return OI_STATUS_INVALID_PARAMETERS;
+    }
+
+    return OI_OK;
+}
+
+
+
+OI_STATUS OI_CODEC_SBC_DecodeRaw(OI_CODEC_SBC_DECODER_CONTEXT *context,
+                                 uint8_t bitpool,
+                                 const OI_BYTE **frameData,
+                                 uint32_t *frameBytes,
+                                 int16_t *pcmData,
+                                 uint32_t *pcmBytes)
+{
+    return internal_DecodeRaw(context,
+                              bitpool,
+                              frameData,
+                              frameBytes,
+                              pcmData,
+                              pcmBytes);
+}
+
+OI_STATUS OI_CODEC_SBC_DecoderLimit(OI_CODEC_SBC_DECODER_CONTEXT *context,
+                                    OI_BOOL                       enhanced,
+                                    uint8_t                      subbands)
+{
+	if (enhanced)
+	{
+#ifdef SBC_ENHANCED
+        context->enhancedEnabled = TRUE;
+#else
+        context->enhancedEnabled = FALSE;
+#endif
+	}
+	else
+	{
+        context->enhancedEnabled = FALSE;
+	}
+    context->restrictSubbands = subbands;
+    context->limitFrameFormat = TRUE;
+    return OI_OK;
+}
+
+
+/**
+@}
+*/
diff --git a/bt/embdrv/sbc/decoder/srce/decoder-private.c b/bt/embdrv/sbc/decoder/srce/decoder-private.c
new file mode 100644
index 0000000..a0c7638
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/srce/decoder-private.c
@@ -0,0 +1,227 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/**********************************************************************************
+  $Revision: #1 $
+ ***********************************************************************************/
+
+/**
+@file
+This file drives SBC decoding.
+
+@ingroup codec_internal
+*/
+
+/**
+@addtogroup codec_internal
+@{
+*/
+
+#include "oi_codec_sbc_private.h"
+#include "oi_bitstream.h"
+#include <stdio.h>
+
+OI_CHAR * const OI_Codec_Copyright = "Copyright 2002-2007 Open Interface North America, Inc. All rights reserved";
+
+INLINE OI_STATUS internal_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT *context,
+                                       uint32_t *decoderData,
+                                       uint32_t decoderDataBytes,
+                                       OI_BYTE maxChannels,
+                                       OI_BYTE pcmStride,
+                                       OI_BOOL enhanced)
+{
+    OI_UINT i;
+    OI_STATUS status;
+
+    for (i = 0; i < sizeof(*context); i++) {
+        ((char *)context)[i] = 0;
+    }
+
+#ifdef SBC_ENHANCED
+    context->enhancedEnabled = enhanced ? TRUE : FALSE;
+#else
+    context->enhancedEnabled = FALSE;
+    if (enhanced){
+        return OI_STATUS_INVALID_PARAMETERS;
+    }
+#endif
+
+    status = OI_CODEC_SBC_Alloc(&context->common, decoderData, decoderDataBytes, maxChannels, pcmStride);
+
+    if (!OI_SUCCESS(status)) {
+        return status;
+    }
+
+    context->common.codecInfo = OI_Codec_Copyright;
+    context->common.maxBitneed = 0;
+    context->limitFrameFormat = FALSE;
+    OI_SBC_ExpandFrameFields(&context->common.frameInfo);
+
+    /*PLATFORM_DECODER_RESET(context);*/
+
+    return OI_OK;
+}
+
+
+
+
+/**
+ * Read the SBC header up to but not including the joint stereo mask.  The syncword has already been
+ * examined, and the enhanced mode flag set, by FindSyncword.
+ */
+INLINE void OI_SBC_ReadHeader(OI_CODEC_SBC_COMMON_CONTEXT *common, const OI_BYTE *data)
+{
+    OI_CODEC_SBC_FRAME_INFO *frame = &common->frameInfo;
+    uint8_t d1;
+
+
+    OI_ASSERT(data[0] == OI_SBC_SYNCWORD || data[0] == OI_SBC_ENHANCED_SYNCWORD);
+
+    /* Avoid filling out all these strucutures if we already remember the values
+     * from last time. Just in case we get a stream corresponding to data[1] ==
+     * 0, DecoderReset is responsible for ensuring the lookup table entries have
+     * already been populated
+     */
+    d1 = data[1];
+    if (d1 != frame->cachedInfo) {
+
+        frame->freqIndex = (d1 & (BIT7 | BIT6)) >> 6;
+        frame->frequency = freq_values[frame->freqIndex];
+
+        frame->blocks = (d1 & (BIT5 | BIT4)) >> 4;
+        frame->nrof_blocks = block_values[frame->blocks];
+
+        frame->mode = (d1 & (BIT3 | BIT2)) >> 2;
+        frame->nrof_channels = channel_values[frame->mode];
+
+        frame->alloc = (d1 & BIT1) >> 1;
+
+        frame->subbands = (d1 & BIT0);
+        frame->nrof_subbands = band_values[frame->subbands];
+
+        frame->cachedInfo = d1;
+    }
+    /*
+     * For decode, the bit allocator needs to know the bitpool value
+     */
+    frame->bitpool = data[2];
+    frame->crc = data[3];
+}
+
+
+#define LOW(x)  ((x)& 0xf)
+#define HIGH(x) ((x) >> 4)
+
+/*
+ * Read scalefactor values and prepare the bitstream for OI_SBC_ReadSamples
+ */
+PRIVATE void OI_SBC_ReadScalefactors(OI_CODEC_SBC_COMMON_CONTEXT *common,
+                             const OI_BYTE *b,
+                             OI_BITSTREAM *bs)
+{
+    OI_UINT i = common->frameInfo.nrof_subbands * common->frameInfo.nrof_channels;
+    int8_t *scale_factor = common->scale_factor;
+    OI_UINT f;
+
+    if (common->frameInfo.nrof_subbands == 8 || common->frameInfo.mode != SBC_JOINT_STEREO) {
+        if (common->frameInfo.mode == SBC_JOINT_STEREO) {
+            common->frameInfo.join = *b++;
+        } else {
+            common->frameInfo.join = 0;
+        }
+        i /= 2;
+        do {
+            *scale_factor++ = HIGH(f = *b++);
+            *scale_factor++ = LOW(f);
+        } while (--i);
+        /*
+         * In this case we know that the scale factors end on a byte boundary so all we need to do
+         * is initialize the bitstream.
+         */
+        OI_BITSTREAM_ReadInit(bs, b);
+    } else {
+        OI_ASSERT(common->frameInfo.nrof_subbands == 4 && common->frameInfo.mode == SBC_JOINT_STEREO);
+        common->frameInfo.join = HIGH(f = *b++);
+        i = (i - 1) / 2;
+        do {
+            *scale_factor++ = LOW(f);
+            *scale_factor++ = HIGH(f = *b++);
+        } while (--i);
+        *scale_factor++ = LOW(f);
+        /*
+         * In 4-subband joint stereo mode, the joint stereo information ends on a half-byte
+         * boundary, so it's necessary to use the bitstream abstraction to read it, since
+         * OI_SBC_ReadSamples will need to pick up in mid-byte.
+         */
+        OI_BITSTREAM_ReadInit(bs, b);
+        *scale_factor++ = OI_BITSTREAM_ReadUINT4Aligned(bs);
+    }
+}
+
+/** Read quantized subband samples from the input bitstream and expand them. */
+PRIVATE void OI_SBC_ReadSamples(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs)
+{
+    OI_CODEC_SBC_COMMON_CONTEXT *common = &context->common;
+    OI_UINT nrof_blocks = common->frameInfo.nrof_blocks;
+    int32_t * RESTRICT s = common->subdata;
+    uint8_t *ptr = global_bs->ptr.w;
+    uint32_t value = global_bs->value;
+    OI_UINT bitPtr = global_bs->bitPtr;
+
+    const OI_UINT iter_count = common->frameInfo.nrof_channels * common->frameInfo.nrof_subbands / 4;
+    do {
+        OI_UINT i;
+        for (i = 0; i < iter_count; ++i) {
+            uint32_t sf_by4 = ((uint32_t*)common->scale_factor)[i];
+            uint32_t bits_by4 = common->bits.uint32[i];
+            OI_UINT n;
+            for (n = 0; n < 4; ++n) {
+                int32_t dequant;
+                OI_UINT bits;
+                OI_INT sf;
+
+                if (OI_CPU_BYTE_ORDER == OI_LITTLE_ENDIAN_BYTE_ORDER) {
+                    bits = bits_by4 & 0xFF;
+                    bits_by4 >>= 8;
+                    sf = sf_by4 & 0xFF;
+                    sf_by4 >>= 8;
+                } else {
+                    bits = (bits_by4 >> 24) & 0xFF;
+                    bits_by4 <<= 8;
+                    sf = (sf_by4 >> 24) & 0xFF;
+                    sf_by4 <<= 8;
+                }
+                if (bits) {
+                    uint32_t raw;
+                    OI_BITSTREAM_READUINT(raw, bits, ptr, value, bitPtr);
+                    dequant = OI_SBC_Dequant(raw, sf, bits);
+                } else {
+                    dequant = 0;
+                }
+                *s++ = dequant;
+            }
+        }
+    } while (--nrof_blocks);
+}
+
+
+
+/**
+@}
+*/
diff --git a/bt/embdrv/sbc/decoder/srce/decoder-sbc.c b/bt/embdrv/sbc/decoder/srce/decoder-sbc.c
new file mode 100644
index 0000000..37e64e6
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/srce/decoder-sbc.c
@@ -0,0 +1,465 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2006 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/**********************************************************************************
+  $Revision: #1 $
+ ***********************************************************************************/
+
+/** @file
+@ingroup codec_internal
+*/
+
+/**@addtogroup codec_internal */
+/**@{*/
+
+#include "oi_codec_sbc_private.h"
+#include "oi_bitstream.h"
+
+#define SPECIALIZE_READ_SAMPLES_JOINT
+
+/**
+ * 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
+ * for both a standard and an enhanced syncword.
+ */
+PRIVATE OI_STATUS FindSyncword(OI_CODEC_SBC_DECODER_CONTEXT *context,
+                               const OI_BYTE **frameData,
+                               uint32_t *frameBytes)
+{
+#ifdef SBC_ENHANCED
+    OI_BYTE search1 = OI_SBC_SYNCWORD;
+    OI_BYTE search2 = OI_SBC_ENHANCED_SYNCWORD;
+#endif // SBC_ENHANCED
+
+    if (*frameBytes == 0) {
+        return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA;
+    }
+
+#ifdef SBC_ENHANCED
+    if (context->limitFrameFormat && context->enhancedEnabled){
+        /* If the context is restricted, only search for specified SYNCWORD */
+        search1 = search2;
+    } else if (context->enhancedEnabled == FALSE) {
+        /* If enhanced is not enabled, only search for classic SBC SYNCWORD*/
+        search2 = search1;
+    }
+    while (*frameBytes && (**frameData != search1) && (**frameData != search2)) {
+        (*frameBytes)--;
+        (*frameData)++;
+    }
+    if (*frameBytes) {
+        /* Syncword found, *frameData points to it, and *frameBytes correctly
+         * reflects the number of bytes available to read, including the
+         * syncword. */
+        context->common.frameInfo.enhanced = (**frameData == OI_SBC_ENHANCED_SYNCWORD);
+        return OI_OK;
+    } else {
+        /* No syncword was found anywhere in the provided input data.
+         * *frameData points past the end of the original input, and
+         * *frameBytes is 0. */
+        return OI_CODEC_SBC_NO_SYNCWORD;
+    }
+#else  // SBC_ENHANCED
+    while (*frameBytes && (**frameData != OI_SBC_SYNCWORD)) {
+        (*frameBytes)--;
+        (*frameData)++;
+    }
+    if (*frameBytes) {
+        /* Syncword found, *frameData points to it, and *frameBytes correctly
+         * reflects the number of bytes available to read, including the
+         * syncword. */
+        context->common.frameInfo.enhanced = FALSE;
+        return OI_OK;
+    } else {
+        /* No syncword was found anywhere in the provided input data.
+         * *frameData points past the end of the original input, and
+         * *frameBytes is 0. */
+        return OI_CODEC_SBC_NO_SYNCWORD;
+    }
+#endif // SBC_ENHANCED
+}
+
+static OI_STATUS DecodeBody(OI_CODEC_SBC_DECODER_CONTEXT *context,
+                            const OI_BYTE *bodyData,
+                            int16_t *pcmData,
+                            uint32_t *pcmBytes,
+                            OI_BOOL allowPartial)
+{
+    OI_BITSTREAM bs;
+    OI_UINT frameSamples = context->common.frameInfo.nrof_blocks * context->common.frameInfo.nrof_subbands;
+    OI_UINT decode_block_count;
+
+    /*
+     * Based on the header data, make sure that there is enough room to write the output samples.
+     */
+    if (*pcmBytes < (sizeof(int16_t) * frameSamples * context->common.pcmStride) && !allowPartial) {
+        /* If we're not allowing partial decodes, we need room for the entire
+         * codec frame */
+        TRACE(("-OI_CODEC_SBC_Decode: OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA"));
+        return OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA;
+    } else if (*pcmBytes < sizeof (int16_t) * context->common.frameInfo.nrof_subbands * context->common.pcmStride) {
+        /* Even if we're allowing partials, we can still only decode on a frame
+         * boundary */
+        return OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA;
+    }
+
+    if (context->bufferedBlocks == 0) {
+        TRACE(("Reading scalefactors"));
+        OI_SBC_ReadScalefactors(&context->common, bodyData, &bs);
+
+        TRACE(("Computing bit allocation"));
+        OI_SBC_ComputeBitAllocation(&context->common);
+
+        TRACE(("Reading samples"));
+        if (context->common.frameInfo.mode == SBC_JOINT_STEREO) {
+            OI_SBC_ReadSamplesJoint(context, &bs);
+        } else {
+            OI_SBC_ReadSamples(context, &bs);
+        }
+
+        context->bufferedBlocks = context->common.frameInfo.nrof_blocks;
+    }
+
+    if (allowPartial) {
+        decode_block_count = *pcmBytes / sizeof(int16_t) / context->common.pcmStride / context->common.frameInfo.nrof_subbands;
+
+        if (decode_block_count > context->bufferedBlocks) {
+            decode_block_count = context->bufferedBlocks;
+        }
+
+    } else {
+        decode_block_count = context->common.frameInfo.nrof_blocks;
+    }
+
+    TRACE(("Synthesizing frame"));
+    {
+        OI_UINT start_block = context->common.frameInfo.nrof_blocks - context->bufferedBlocks;
+        OI_SBC_SynthFrame(context, pcmData, start_block, decode_block_count);
+    }
+
+    OI_ASSERT(context->bufferedBlocks >= decode_block_count);
+    context->bufferedBlocks -= decode_block_count;
+
+    frameSamples = decode_block_count * context->common.frameInfo.nrof_subbands;
+
+    /*
+     * When decoding mono into a stride-2 array, copy pcm data to second channel
+     */
+    if (context->common.frameInfo.nrof_channels == 1 && context->common.pcmStride == 2) {
+        OI_UINT i;
+        for (i = 0; i < frameSamples; ++i) {
+            pcmData[2*i+1] = pcmData[2*i];
+        }
+    }
+
+    /*
+     * Return number of pcm bytes generated by the decode operation.
+     */
+    *pcmBytes = frameSamples * sizeof(int16_t) * context->common.pcmStride;
+    if (context->bufferedBlocks > 0) {
+        return OI_CODEC_SBC_PARTIAL_DECODE;
+    } else {
+        return OI_OK;
+    }
+}
+
+PRIVATE OI_STATUS internal_DecodeRaw(OI_CODEC_SBC_DECODER_CONTEXT *context,
+                                     uint8_t bitpool,
+                                     const OI_BYTE **frameData,
+                                     uint32_t *frameBytes,
+                                     int16_t *pcmData,
+                                     uint32_t *pcmBytes)
+{
+    OI_STATUS status;
+    OI_UINT bodyLen;
+
+    TRACE(("+OI_CODEC_SBC_DecodeRaw"));
+
+    if (context->bufferedBlocks == 0) {
+        /*
+         * The bitallocator needs to know the bitpool value.
+         */
+        context->common.frameInfo.bitpool = bitpool;
+        /*
+         * Compute the frame length and check we have enough frame data to proceed
+         */
+        bodyLen = OI_CODEC_SBC_CalculateFramelen(&context->common.frameInfo) - SBC_HEADER_LEN;
+        if (*frameBytes < bodyLen) {
+            TRACE(("-OI_CODEC_SBC_Decode: OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA"));
+            return OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA;
+        }
+    } else {
+        bodyLen = 0;
+    }
+    /*
+     * Decode the SBC data. Pass TRUE to DecodeBody to allow partial decoding of
+     * tones.
+     */
+    status = DecodeBody(context, *frameData, pcmData, pcmBytes, TRUE);
+    if (OI_SUCCESS(status) || status == OI_CODEC_SBC_PARTIAL_DECODE) {
+        *frameData += bodyLen;
+        *frameBytes -= bodyLen;
+    }
+    TRACE(("-OI_CODEC_SBC_DecodeRaw: %d", status));
+    return status;
+}
+
+OI_STATUS OI_CODEC_SBC_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT *context,
+                                    uint32_t *decoderData,
+                                    uint32_t decoderDataBytes,
+                                    uint8_t maxChannels,
+                                    uint8_t pcmStride,
+                                    OI_BOOL enhanced)
+{
+    return internal_DecoderReset(context, decoderData, decoderDataBytes, maxChannels, pcmStride, enhanced);
+}
+
+OI_STATUS OI_CODEC_SBC_DecodeFrame(OI_CODEC_SBC_DECODER_CONTEXT *context,
+                                   const OI_BYTE **frameData,
+                                   uint32_t *frameBytes,
+                                   int16_t *pcmData,
+                                   uint32_t *pcmBytes)
+{
+    OI_STATUS status;
+    OI_UINT framelen;
+    uint8_t crc;
+
+    TRACE(("+OI_CODEC_SBC_DecodeFrame"));
+
+    TRACE(("Finding syncword"));
+    status = FindSyncword(context, frameData, frameBytes);
+    if (!OI_SUCCESS(status)) {
+        return status;
+    }
+
+    /* Make sure enough data remains to read the header. */
+    if (*frameBytes < SBC_HEADER_LEN) {
+        TRACE(("-OI_CODEC_SBC_DecodeFrame: OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA"));
+        return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA;
+    }
+
+    TRACE(("Reading Header"));
+    OI_SBC_ReadHeader(&context->common, *frameData);
+
+    /*
+     * Some implementations load the decoder into RAM and use overlays for 4 vs 8 subbands. We need
+     * to ensure that the SBC parameters for this frame are compatible with the restrictions imposed
+     * by the loaded overlays.
+     */
+    if (context->limitFrameFormat && (context->common.frameInfo.subbands != context->restrictSubbands)) {
+        ERROR(("SBC parameters incompatible with loaded overlay"));
+        return OI_STATUS_INVALID_PARAMETERS;
+    }
+
+    if (context->common.frameInfo.nrof_channels > context->common.maxChannels) {
+        ERROR(("SBC parameters incompatible with number of channels specified during reset"));
+        return OI_STATUS_INVALID_PARAMETERS;
+    }
+
+    if (context->common.pcmStride < 1 || context->common.pcmStride > 2) {
+        ERROR(("PCM stride not set correctly during reset"));
+        return OI_STATUS_INVALID_PARAMETERS;
+    }
+
+    /*
+     * At this point a header has been read. However, it's possible that we found a false syncword,
+     * so the header data might be invalid. Make sure we have enough bytes to read in the
+     * CRC-protected header, but don't require we have the whole frame. That way, if it turns out
+     * that we're acting on bogus header data, we don't stall the decoding process by waiting for
+     * data that we don't actually need.
+     */
+    framelen = OI_CODEC_SBC_CalculateFramelen(&context->common.frameInfo);
+    if (*frameBytes < framelen) {
+        TRACE(("-OI_CODEC_SBC_DecodeFrame: OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA"));
+        return OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA;
+    }
+
+    TRACE(("Calculating checksum"));
+
+    crc = OI_SBC_CalculateChecksum(&context->common.frameInfo, *frameData);
+    if (crc != context->common.frameInfo.crc) {
+        TRACE(("CRC Mismatch:  calc=%02x read=%02x\n", crc, context->common.frameInfo.crc));
+        TRACE(("-OI_CODEC_SBC_DecodeFrame: OI_CODEC_SBC_CHECKSUM_MISMATCH"));
+        return OI_CODEC_SBC_CHECKSUM_MISMATCH;
+    }
+
+#ifdef OI_DEBUG
+    /*
+     * Make sure the bitpool values are sane.
+     */
+    if ((context->common.frameInfo.bitpool < SBC_MIN_BITPOOL) && !context->common.frameInfo.enhanced) {
+        ERROR(("Bitpool too small: %d (must be >= 2)", context->common.frameInfo.bitpool));
+        return OI_STATUS_INVALID_PARAMETERS;
+    }
+    if (context->common.frameInfo.bitpool > OI_SBC_MaxBitpool(&context->common.frameInfo)) {
+        ERROR(("Bitpool too large: %d (must be <= %ld)", context->common.frameInfo.bitpool, OI_SBC_MaxBitpool(&context->common.frameInfo)));
+        return OI_STATUS_INVALID_PARAMETERS;
+    }
+#endif
+
+    /*
+     * Now decode the SBC data. Partial decode is not yet implemented for an SBC
+     * stream, so pass FALSE to decode body to have it enforce the old rule that
+     * you have to decode a whole packet at a time.
+     */
+    status = DecodeBody(context, *frameData + SBC_HEADER_LEN, pcmData, pcmBytes, FALSE);
+    if (OI_SUCCESS(status)) {
+        *frameData += framelen;
+        *frameBytes -= framelen;
+    }
+    TRACE(("-OI_CODEC_SBC_DecodeFrame: %d", status));
+
+    return status;
+}
+
+OI_STATUS OI_CODEC_SBC_SkipFrame(OI_CODEC_SBC_DECODER_CONTEXT *context,
+                                 const OI_BYTE **frameData,
+                                 uint32_t *frameBytes)
+{
+    OI_STATUS status;
+    OI_UINT framelen;
+    OI_UINT headerlen;
+    uint8_t crc;
+
+    status = FindSyncword(context, frameData, frameBytes);
+    if (!OI_SUCCESS(status)) {
+        return status;
+    }
+    if (*frameBytes < SBC_HEADER_LEN) {
+        return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA;
+    }
+    OI_SBC_ReadHeader(&context->common, *frameData);
+    framelen = OI_SBC_CalculateFrameAndHeaderlen(&context->common.frameInfo, &headerlen);
+    if (*frameBytes < headerlen) {
+        return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA;
+    }
+    crc = OI_SBC_CalculateChecksum(&context->common.frameInfo, *frameData);
+    if (crc != context->common.frameInfo.crc) {
+        return OI_CODEC_SBC_CHECKSUM_MISMATCH;
+    }
+    if (*frameBytes < framelen) {
+        return OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA;
+    }
+    context->bufferedBlocks = 0;
+    *frameData += framelen;
+    *frameBytes -= framelen;
+    return OI_OK;
+}
+
+uint8_t OI_CODEC_SBC_FrameCount(OI_BYTE  *frameData,
+                                 uint32_t frameBytes)
+{
+    uint8_t mode;
+    uint8_t blocks;
+    uint8_t subbands;
+    uint8_t frameCount = 0;
+    OI_UINT  frameLen;
+
+    while (frameBytes){
+        while (frameBytes && ((frameData[0] & 0xFE) != 0x9C)){
+            frameData++;
+            frameBytes--;
+        }
+
+        if (frameBytes < SBC_HEADER_LEN) {
+            return frameCount;
+        }
+
+        /* Extract and translate required fields from Header */
+        subbands = mode = blocks = frameData[1];;
+        mode = (mode & (BIT3 | BIT2)) >> 2;
+        blocks = block_values[(blocks & (BIT5 | BIT4)) >> 4];
+        subbands = band_values[(subbands & BIT0)];
+
+        /* Inline logic to avoid corrupting context */
+        frameLen = blocks * frameData[2];
+        switch (mode){
+            case SBC_JOINT_STEREO:
+                frameLen += subbands + (8 * subbands);
+                break;
+
+            case SBC_DUAL_CHANNEL:
+                frameLen *= 2;
+                /* fall through */
+
+            default:
+                if (mode == SBC_MONO){
+                    frameLen += 4*subbands;
+                } else {
+                    frameLen += 8*subbands;
+                }
+        }
+
+        frameCount++;
+        frameLen = SBC_HEADER_LEN + (frameLen + 7) / 8;
+        if (frameBytes > frameLen){
+            frameBytes -= frameLen;
+            frameData += frameLen;
+        } else {
+            frameBytes = 0;
+        }
+    }
+    return frameCount;
+}
+
+/** Read quantized subband samples from the input bitstream and expand them. */
+
+#ifdef SPECIALIZE_READ_SAMPLES_JOINT
+
+PRIVATE void OI_SBC_ReadSamplesJoint4(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs)
+{
+#define NROF_SUBBANDS 4
+#include "readsamplesjoint.inc"
+#undef NROF_SUBBANDS
+}
+
+PRIVATE void OI_SBC_ReadSamplesJoint8(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs)
+{
+#define NROF_SUBBANDS 8
+#include "readsamplesjoint.inc"
+#undef NROF_SUBBANDS
+}
+
+typedef void (*READ_SAMPLES)(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs);
+
+static const READ_SAMPLES SpecializedReadSamples[] = {
+    OI_SBC_ReadSamplesJoint4,
+    OI_SBC_ReadSamplesJoint8
+};
+
+#endif /* SPECIALIZE_READ_SAMPLES_JOINT */
+
+
+PRIVATE void OI_SBC_ReadSamplesJoint(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs)
+{
+    OI_CODEC_SBC_COMMON_CONTEXT *common = &context->common;
+    OI_UINT nrof_subbands = common->frameInfo.nrof_subbands;
+#ifdef SPECIALIZE_READ_SAMPLES_JOINT
+    OI_ASSERT((nrof_subbands >> 3u) <= 1u);
+    SpecializedReadSamples[nrof_subbands >> 3](context, global_bs);
+#else
+
+#define NROF_SUBBANDS nrof_subbands
+#include "readsamplesjoint.inc"
+#undef NROF_SUBBANDS
+#endif /* SPECIALIZE_READ_SAMPLES_JOINT */
+}
+
+/**@}*/
+
diff --git a/bt/embdrv/sbc/decoder/srce/dequant.c b/bt/embdrv/sbc/decoder/srce/dequant.c
new file mode 100644
index 0000000..4c3474f
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/srce/dequant.c
@@ -0,0 +1,210 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+/**
+ @file
+
+ Dequantizer for SBC decoder; reconstructs quantized representation of subband samples.
+
+ @ingroup codec_internal
+ */
+
+/**
+@addtogroup codec_internal
+@{
+*/
+
+/**
+ This function is a fixed-point approximation of a modification of the following
+ dequantization operation defined in the spec, as inferred from section 12.6.4:
+
+ @code
+ dequant = 2^(scale_factor+1) * ((raw * 2.0 + 1.0) / ((2^bits) - 1) - 1)
+
+ 2 <= bits <= 16
+ 0 <= raw < (2^bits)-1   (the -1 is because quantized values with all 1's are forbidden)
+
+ -65535 < dequant < 65535
+ @endcode
+
+ The code below computes the dequantized value divided by a scaling constant
+ equal to about 1.38. This constant is chosen to ensure that the entry in the
+ dequant_long_scaled table for 16 bits is as accurate as possible, since it has
+ the least relative precision available to it due to its small magnitude.
+
+ This routine outputs in Q16.15 format.
+
+ The helper array dequant_long is defined as follows:
+
+ @code
+ dequant_long_long[bits] = round(2^31 * 1/((2^bits - 1) / 1.38...)  for 2 <= bits <= 16
+ @endcode
+
+
+ Additionally, the table entries have the following property:
+
+ @code
+ dequant_long_scaled[bits] <= 2^31 / ((2^bits - 1))  for 2 <= bits <= 16
+ @endcode
+
+ Therefore
+
+ @code
+ d = 2 * raw + 1              1 <= d <= 2^bits - 2
+
+ d' = d * dequant_long[bits]
+
+                  d * dequant_long_scaled[bits] <= (2^bits - 2) * (2^31 / (2^bits - 1))
+                  d * dequant_long_scaled[bits] <= 2^31 * (2^bits - 2)/(2^bits - 1) < 2^31
+ @endcode
+
+ Therefore, d' doesn't overflow a signed 32-bit value.
+
+ @code
+
+ d' =~ 2^31 * (raw * 2.0 + 1.0) / (2^bits - 1) / 1.38...
+
+ result = d' - 2^31/1.38... =~ 2^31 * ((raw * 2.0 + 1.0) / (2^bits - 1) - 1) / 1.38...
+
+ result is therefore a scaled approximation to dequant. It remains only to
+ turn 2^31 into 2^(scale_factor+1). Since we're aiming for Q16.15 format,
+ this is achieved by shifting right by (15-scale_factor):
+
+  (2^31 * x) >> (15-scale_factor) =~ 2^(31-15+scale_factor) * x = 2^15 * 2^(1+scale_factor) * x
+ @endcode
+
+ */
+
+#include <oi_codec_sbc_private.h>
+
+#ifndef SBC_DEQUANT_LONG_SCALED_OFFSET
+#define SBC_DEQUANT_LONG_SCALED_OFFSET 1555931970
+#endif
+
+#ifndef SBC_DEQUANT_LONG_UNSCALED_OFFSET
+#define SBC_DEQUANT_LONG_UNSCALED_OFFSET 2147483648
+#endif
+
+#ifndef SBC_DEQUANT_SCALING_FACTOR
+#define SBC_DEQUANT_SCALING_FACTOR 1.38019122262781f
+#endif
+
+const uint32_t dequant_long_scaled[17];
+const uint32_t dequant_long_unscaled[17];
+
+/** Scales x by y bits to the right, adding a rounding factor.
+ */
+#ifndef SCALE
+#define SCALE(x, y) (((x) + (1 <<((y)-1))) >> (y))
+#endif
+
+#ifdef DEBUG_DEQUANTIZATION
+
+#include <math.h>
+
+INLINE float dequant_float(uint32_t raw, OI_UINT scale_factor, OI_UINT bits)
+{
+    float result = (1 << (scale_factor+1)) * ((raw * 2.0f + 1.0f) / ((1 << bits) - 1.0f) - 1.0f);
+
+    result /= SBC_DEQUANT_SCALING_FACTOR;
+
+    /* Unless the encoder screwed up, all correct dequantized values should
+     * satisfy this inequality. Non-compliant encoders which generate quantized
+     * values with all 1-bits set can, theoretically, trigger this assert. This
+     * is unlikely, however, and only an issue in debug mode.
+     */
+    OI_ASSERT(fabs(result) < 32768 * 1.6);
+
+    return result;
+}
+
+#endif
+
+
+INLINE int32_t OI_SBC_Dequant(uint32_t raw, OI_UINT scale_factor, OI_UINT bits)
+{
+    uint32_t d;
+    int32_t result;
+
+    OI_ASSERT(scale_factor <= 15);
+    OI_ASSERT(bits <= 16);
+
+    if (bits <= 1) {
+        return 0;
+    }
+
+    d = (raw * 2) + 1;
+    d *= dequant_long_scaled[bits];
+    result = d - SBC_DEQUANT_LONG_SCALED_OFFSET;
+
+#ifdef DEBUG_DEQUANTIZATION
+    {
+        int32_t integerized_float_result;
+        float float_result;
+
+        float_result = dequant_float(raw, scale_factor, bits);
+        integerized_float_result = (int32_t)floor(0.5f+float_result * (1 << 15));
+
+        /* This detects overflow */
+        OI_ASSERT(((result >= 0) && (integerized_float_result >= 0)) ||
+                  ((result <= 0) && (integerized_float_result <= 0)));
+    }
+#endif
+    return result >> (15 - scale_factor);
+}
+
+/* This version of Dequant does not incorporate the scaling factor of 1.38. It
+ * is intended for use with implementations of the filterbank which are
+ * hard-coded into a DSP. Output is Q16.4 format, so that after joint stereo
+ * processing (which leaves the most significant bit equal to the sign bit if
+ * the encoder is conformant) the result will fit a 24 bit fixed point signed
+ * value.*/
+
+INLINE int32_t OI_SBC_Dequant_Unscaled(uint32_t raw, OI_UINT scale_factor, OI_UINT bits)
+{
+    uint32_t d;
+    int32_t result;
+
+    OI_ASSERT(scale_factor <= 15);
+    OI_ASSERT(bits <= 16);
+
+
+    if (bits <= 1) {
+        return 0;
+    }
+    if (bits == 16) {
+        result = (raw << 16) + raw - 0x7fff7fff;
+        return SCALE(result, 24 - scale_factor);
+    }
+
+
+    d = (raw * 2) + 1;
+    d *= dequant_long_unscaled[bits];
+    result = d - 0x80000000;
+
+    return SCALE(result, 24 - scale_factor);
+}
+
+/**
+@}
+*/
diff --git a/bt/embdrv/sbc/decoder/srce/framing-sbc.c b/bt/embdrv/sbc/decoder/srce/framing-sbc.c
new file mode 100644
index 0000000..09540b1
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/srce/framing-sbc.c
@@ -0,0 +1,54 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+/** @file
+@ingroup codec_internal
+*/
+
+/**@addgroup codec_internal*/
+/**@{*/
+
+#include "oi_codec_sbc_private.h"
+
+const OI_CHAR* const OI_CODEC_SBC_FreqText[] =     { "SBC_FREQ_16000", "SBC_FREQ_32000", "SBC_FREQ_44100", "SBC_FREQ_48000" };
+const OI_CHAR* const OI_CODEC_SBC_ModeText[] =     { "SBC_MONO", "SBC_DUAL_CHANNEL", "SBC_STEREO", "SBC_JOINT_STEREO" };
+const OI_CHAR* const OI_CODEC_SBC_SubbandsText[] = { "SBC_SUBBANDS_4", "SBC_SUBBANDS_8" };
+const OI_CHAR* const OI_CODEC_SBC_BlocksText[] =   { "SBC_BLOCKS_4", "SBC_BLOCKS_8", "SBC_BLOCKS_12", "SBC_BLOCKS_16" };
+const OI_CHAR* const OI_CODEC_SBC_AllocText[] =    { "SBC_LOUDNESS", "SBC_SNR" };
+
+#ifdef OI_DEBUG
+void OI_CODEC_SBC_DumpConfig(OI_CODEC_SBC_FRAME_INFO *frameInfo)
+{
+    printf("SBC configuration\n");
+    printf("  enhanced:  %s\n", frameInfo->enhanced ? "true" : "false");
+    printf("  frequency: %d\n", frameInfo->frequency);
+    printf("  subbands:  %d\n", frameInfo->nrof_subbands);
+    printf("  blocks:    %d\n", frameInfo->nrof_blocks);
+    printf("  channels:  %d\n", frameInfo->nrof_channels);
+    printf("  mode:      %s\n", OI_CODEC_SBC_ModeText[frameInfo->mode]);
+    printf("  alloc:     %s\n", OI_CODEC_SBC_AllocText[frameInfo->alloc]);
+    printf("  bitpool:   %d\n", frameInfo->bitpool);
+}
+#endif /* OI_DEBUG */
+
+/**@}*/
diff --git a/bt/embdrv/sbc/decoder/srce/framing.c b/bt/embdrv/sbc/decoder/srce/framing.c
new file mode 100644
index 0000000..959692c
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/srce/framing.c
@@ -0,0 +1,249 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+/**
+@file
+Checksum and header-related functions.
+
+@ingroup codec_internal
+*/
+
+/**
+@addtogroup codec_internal
+@{
+*/
+
+#include "oi_codec_sbc_private.h"
+#include "oi_assert.h"
+
+
+/* asdasd */
+
+#define USE_NIBBLEWISE_CRC
+
+/* #define PRINT_SAMPLES */
+/* #define PRINT_SCALEFACTORS */
+/* #define DEBUG_CRC */
+
+/*
+ * CRC-8 table for X^8 + X^4 + X^3 + X^2 + 1; byte-wise lookup
+ */
+#ifdef USE_WIDE_CRC
+/* Save space if a char is 16 bits, such as on the C54x */
+const OI_BYTE crc8_wide[128] = {
+    0x001d, 0x3a27, 0x7469, 0x4e53, 0xe8f5, 0xd2cf, 0x9c81, 0xa6bb, 0xcdd0, 0xf7ea, 0xb9a4, 0x839e, 0x2538, 0x1f02, 0x514c, 0x6b76, 0x879a, 0xbda0, 0xf3ee, 0xc9d4, 0x6f72, 0x5548, 0x1b06, 0x213c, 0x4a57, 0x706d, 0x3e23, 0x0419, 0xa2bf, 0x9885, 0xd6cb, 0xecf1, 0x130e, 0x2934, 0x677a, 0x5d40, 0xfbe6, 0xc1dc, 0x8f92, 0xb5a8, 0xdec3, 0xe4f9, 0xaab7, 0x908d, 0x362b, 0x0c11, 0x425f, 0x7865, 0x9489, 0xaeb3, 0xe0fd, 0xdac7, 0x7c61, 0x465b, 0x0815, 0x322f, 0x5944, 0x637e, 0x2d30, 0x170a, 0xb1ac, 0x8b96, 0xc5d8, 0xffe2, 0x263b, 0x1c01, 0x524f, 0x6875, 0xced3, 0xf4e9, 0xbaa7, 0x809d, 0xebf6, 0xd1cc, 0x9f82, 0xa5b8, 0x031e, 0x3924, 0x776a, 0x4d50, 0xa1bc, 0x9b86, 0xd5c8, 0xeff2, 0x4954, 0x736e, 0x3d20, 0x071a, 0x6c71, 0x564b, 0x1805, 0x223f, 0x8499, 0xbea3, 0xf0ed, 0xcad7, 0x3528, 0x0f12, 0x415c, 0x7b66, 0xddc0, 0xe7fa, 0xa9b4, 0x938e, 0xf8e5, 0xc2df, 0x8c91, 0xb6ab, 0x100d, 0x2a37, 0x6479, 0x5e43, 0xb2af, 0x8895, 0xc6db, 0xfce1, 0x5a47, 0x607d, 0x2e33, 0x1409, 0x7f62, 0x4558, 0x0b16, 0x312c, 0x978a, 0xadb0, 0xe3fe, 0xd9c4,
+};
+#elif defined(USE_NIBBLEWISE_CRC)
+const OI_BYTE crc8_narrow[16] = {
+    0x00, 0x1d, 0x3a, 0x27, 0x74, 0x69, 0x4e, 0x53, 0xe8, 0xf5, 0xd2, 0xcf, 0x9c, 0x81, 0xa6, 0xbb
+};
+#else
+const OI_BYTE crc8_narrow[256] = {
+    0x00, 0x1d, 0x3a, 0x27, 0x74, 0x69, 0x4e, 0x53, 0xe8, 0xf5, 0xd2, 0xcf, 0x9c, 0x81, 0xa6, 0xbb, 0xcd, 0xd0, 0xf7, 0xea, 0xb9, 0xa4, 0x83, 0x9e, 0x25, 0x38, 0x1f, 0x02, 0x51, 0x4c, 0x6b, 0x76, 0x87, 0x9a, 0xbd, 0xa0, 0xf3, 0xee, 0xc9, 0xd4, 0x6f, 0x72, 0x55, 0x48, 0x1b, 0x06, 0x21, 0x3c, 0x4a, 0x57, 0x70, 0x6d, 0x3e, 0x23, 0x04, 0x19, 0xa2, 0xbf, 0x98, 0x85, 0xd6, 0xcb, 0xec, 0xf1, 0x13, 0x0e, 0x29, 0x34, 0x67, 0x7a, 0x5d, 0x40, 0xfb, 0xe6, 0xc1, 0xdc, 0x8f, 0x92, 0xb5, 0xa8, 0xde, 0xc3, 0xe4, 0xf9, 0xaa, 0xb7, 0x90, 0x8d, 0x36, 0x2b, 0x0c, 0x11, 0x42, 0x5f, 0x78, 0x65, 0x94, 0x89, 0xae, 0xb3, 0xe0, 0xfd, 0xda, 0xc7, 0x7c, 0x61, 0x46, 0x5b, 0x08, 0x15, 0x32, 0x2f, 0x59, 0x44, 0x63, 0x7e, 0x2d, 0x30, 0x17, 0x0a, 0xb1, 0xac, 0x8b, 0x96, 0xc5, 0xd8, 0xff, 0xe2, 0x26, 0x3b, 0x1c, 0x01, 0x52, 0x4f, 0x68, 0x75, 0xce, 0xd3, 0xf4, 0xe9, 0xba, 0xa7, 0x80, 0x9d, 0xeb, 0xf6, 0xd1, 0xcc, 0x9f, 0x82, 0xa5, 0xb8, 0x03, 0x1e, 0x39, 0x24, 0x77, 0x6a, 0x4d, 0x50, 0xa1, 0xbc, 0x9b, 0x86, 0xd5, 0xc8, 0xef, 0xf2, 0x49, 0x54, 0x73, 0x6e, 0x3d, 0x20, 0x07, 0x1a, 0x6c, 0x71, 0x56, 0x4b, 0x18, 0x05, 0x22, 0x3f, 0x84, 0x99, 0xbe, 0xa3, 0xf0, 0xed, 0xca, 0xd7, 0x35, 0x28, 0x0f, 0x12, 0x41, 0x5c, 0x7b, 0x66, 0xdd, 0xc0, 0xe7, 0xfa, 0xa9, 0xb4, 0x93, 0x8e, 0xf8, 0xe5, 0xc2, 0xdf, 0x8c, 0x91, 0xb6, 0xab, 0x10, 0x0d, 0x2a, 0x37, 0x64, 0x79, 0x5e, 0x43, 0xb2, 0xaf, 0x88, 0x95, 0xc6, 0xdb, 0xfc, 0xe1, 0x5a, 0x47, 0x60, 0x7d, 0x2e, 0x33, 0x14, 0x09, 0x7f, 0x62, 0x45, 0x58, 0x0b, 0x16, 0x31, 0x2c, 0x97, 0x8a, 0xad, 0xb0, 0xe3, 0xfe, 0xd9, 0xc4
+};
+#endif
+const uint32_t dequant_long_scaled[17] = {
+    0,
+    0,
+    0x1ee9e116,  /* bits=2  0.24151243  1/3      * (1/1.38019122262781) (0x00000008)*/
+    0x0d3fa99c,  /* bits=3  0.10350533  1/7      * (1/1.38019122262781) (0x00000013)*/
+    0x062ec69e,  /* bits=4  0.04830249  1/15     * (1/1.38019122262781) (0x00000029)*/
+    0x02fddbfa,  /* bits=5  0.02337217  1/31     * (1/1.38019122262781) (0x00000055)*/
+    0x0178d9f5,  /* bits=6  0.01150059  1/63     * (1/1.38019122262781) (0x000000ad)*/
+    0x00baf129,  /* bits=7  0.00570502  1/127    * (1/1.38019122262781) (0x0000015e)*/
+    0x005d1abe,  /* bits=8  0.00284132  1/255    * (1/1.38019122262781) (0x000002bf)*/
+    0x002e760d,  /* bits=9  0.00141788  1/511    * (1/1.38019122262781) (0x00000582)*/
+    0x00173536,  /* bits=10 0.00070825  1/1023   * (1/1.38019122262781) (0x00000b07)*/
+    0x000b9928,  /* bits=11 0.00035395  1/2047   * (1/1.38019122262781) (0x00001612)*/
+    0x0005cc37,  /* bits=12 0.00017693  1/4095   * (1/1.38019122262781) (0x00002c27)*/
+    0x0002e604,  /* bits=13 0.00008846  1/8191   * (1/1.38019122262781) (0x00005852)*/
+    0x000172fc,  /* bits=14 0.00004422  1/16383  * (1/1.38019122262781) (0x0000b0a7)*/
+    0x0000b97d,  /* bits=15 0.00002211  1/32767  * (1/1.38019122262781) (0x00016150)*/
+    0x00005cbe,  /* bits=16 0.00001106  1/65535  * (1/1.38019122262781) (0x0002c2a5)*/
+};
+
+
+const uint32_t dequant_long_unscaled[17] = {
+    0,
+    0,
+    0x2aaaaaab,  /* bits=2  0.33333333  1/3      (0x00000005)*/
+    0x12492492,  /* bits=3  0.14285714  1/7      (0x0000000e)*/
+    0x08888889,  /* bits=4  0.06666667  1/15     (0x0000001d)*/
+    0x04210842,  /* bits=5  0.03225806  1/31     (0x0000003e)*/
+    0x02082082,  /* bits=6  0.01587302  1/63     (0x0000007e)*/
+    0x01020408,  /* bits=7  0.00787402  1/127    (0x000000fe)*/
+    0x00808081,  /* bits=8  0.00392157  1/255    (0x000001fd)*/
+    0x00402010,  /* bits=9  0.00195695  1/511    (0x000003fe)*/
+    0x00200802,  /* bits=10 0.00097752  1/1023   (0x000007fe)*/
+    0x00100200,  /* bits=11 0.00048852  1/2047   (0x00000ffe)*/
+    0x00080080,  /* bits=12 0.00024420  1/4095   (0x00001ffe)*/
+    0x00040020,  /* bits=13 0.00012209  1/8191   (0x00003ffe)*/
+    0x00020008,  /* bits=14 0.00006104  1/16383  (0x00007ffe)*/
+    0x00010002,  /* bits=15 0.00003052  1/32767  (0x0000fffe)*/
+    0x00008001,  /* bits=16 0.00001526  1/65535  (0x0001fffc)*/
+};
+
+#if defined(OI_DEBUG) || defined(PRINT_SAMPLES) || defined(PRINT_SCALEFACTORS)
+#include <stdio.h>
+#endif
+
+#ifdef USE_WIDE_CRC
+INLINE OI_CHAR crc_iterate(uint8_t oldcrc, uint8_t next)
+{
+    OI_UINT crc;
+    OI_UINT idx;
+    idx = oldcrc^next;
+    crc = crc8_wide[idx >> 1];
+    if (idx%2) {
+        crc &= 0xff;
+    } else {
+        crc >>= 8;
+    }
+
+    return crc;
+}
+
+INLINE OI_CHAR crc_iterate_top4(uint8_t oldcrc, uint8_t next)
+{
+    OI_UINT crc;
+    OI_UINT idx;
+    idx = (oldcrc ^ next) >> 4;
+    crc = crc8_wide[idx>>1];
+    if (idx%2) {
+        crc &= 0xff;
+    } else {
+        crc >>= 8;
+    }
+
+    return (oldcrc << 4) ^ crc;
+}
+
+#else // USE_WIDE_CRC
+
+INLINE uint8_t crc_iterate_top4(uint8_t oldcrc, uint8_t next)
+{
+    return (oldcrc << 4) ^ crc8_narrow[(oldcrc^next) >> 4];
+}
+
+#ifdef USE_NIBBLEWISE_CRC
+INLINE uint8_t crc_iterate(uint8_t crc, uint8_t next)
+{
+    crc = (crc << 4) ^ crc8_narrow[(crc^next) >> 4];
+    crc = (crc << 4) ^ crc8_narrow[((crc>>4)^next)&0xf];
+
+    return crc;
+}
+
+#else   // USE_NIBBLEWISE_CRC
+INLINE uint8_t crc_iterate(uint8_t crc, uint8_t next)
+{
+  return crc8_narrow[crc^next];
+}
+
+#endif  // USE_NIBBLEWISE_CRC
+
+#endif // USE_WIDE_CRC
+
+
+PRIVATE uint8_t OI_SBC_CalculateChecksum(OI_CODEC_SBC_FRAME_INFO *frame, OI_BYTE const *data)
+{
+    OI_UINT i;
+    uint8_t crc = 0x0f;
+    /* Count is the number of whole bytes subject to CRC. Actually, it's one
+     * more than this number, because data[3] is the CRC field itself, which is
+     * explicitly skipped. Since crc_iterate (should be) inlined, it's cheaper
+     * spacewise to include the check in the loop. This shouldn't be much of a
+     * bottleneck routine in the first place. */
+    OI_UINT count = (frame->nrof_subbands * frame->nrof_channels / 2u) + 4;
+
+    if (frame->mode == SBC_JOINT_STEREO && frame->nrof_subbands == 8) {
+        count++;
+    }
+
+    for (i = 1; i < count; i++) {
+        if (i != 3) {
+            crc = crc_iterate(crc,data[i]);
+        }
+    }
+
+    if (frame->mode == SBC_JOINT_STEREO && frame->nrof_subbands == 4) {
+        crc = crc_iterate_top4(crc, data[i]);
+    }
+
+    return crc;
+}
+
+void OI_SBC_ExpandFrameFields(OI_CODEC_SBC_FRAME_INFO *frame)
+{
+    frame->nrof_blocks = block_values[frame->blocks];
+    frame->nrof_subbands = band_values[frame->subbands];
+
+    frame->frequency = freq_values[frame->freqIndex];
+    frame->nrof_channels = channel_values[frame->mode];
+}
+
+/**
+ * Unrolled macro to copy 4 32-bit aligned 32-bit values backward in memory
+ */
+#define COPY4WORDS_BACK(_dest, _src)            \
+    do {                                        \
+            int32_t _a, _b, _c, _d;            \
+            _a = *--(_src);                     \
+            _b = *--(_src);                     \
+            _c = *--(_src);                     \
+            _d = *--(_src);                     \
+            *--(_dest) = _a;                    \
+            *--(_dest) = _b;                    \
+            *--(_dest) = _c;                    \
+            *--(_dest) = _d;                    \
+    } while (0)
+
+
+#if defined(USE_PLATFORM_MEMMOVE) || defined(USE_PLATFORM_MEMCPY)
+#include <string.h>
+#endif
+PRIVATE void shift_buffer(SBC_BUFFER_T *dest, SBC_BUFFER_T *src, OI_UINT wordCount)
+{
+#ifdef USE_PLATFORM_MEMMOVE
+    memmove(dest, src, wordCount * sizeof(SBC_BUFFER_T));
+#elif defined(USE_PLATFORM_MEMCPY)
+    OI_ASSERT(((OI_CHAR *)(dest) - (OI_CHAR *)(src)) >= wordCount*sizeof(*dest));
+    memcpy(dest, src, wordCount * sizeof(SBC_BUFFER_T));
+#else
+    OI_UINT n;
+    int32_t *d;
+    int32_t *s;
+    n = wordCount / 4 / (sizeof(int32_t)/sizeof(*dest));
+    OI_ASSERT((n * 4 * (sizeof(int32_t)/sizeof(*dest))) == wordCount);
+
+    d = (void*)(dest + wordCount);
+    s = (void*)(src + wordCount);
+
+    do {
+        COPY4WORDS_BACK(d, s);
+    } while (--n);
+#endif
+}
+/**
+@}
+*/
diff --git a/bt/embdrv/sbc/decoder/srce/oi_codec_version.c b/bt/embdrv/sbc/decoder/srce/oi_codec_version.c
new file mode 100644
index 0000000..25dc162
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/srce/oi_codec_version.c
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/**
+@file
+This file contains a single function, which returns a string indicating the
+version number of the eSBC codec
+
+@ingroup codec_internal
+*/
+
+/**
+@addtogroup codec_internal
+@{
+*/
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+#include "oi_stddefs.h"
+#include "oi_codec_sbc_private.h"
+
+/** Version string for the BLUEmagic 3.0 protocol stack and profiles */
+PRIVATE OI_CHAR * const codecVersion = "v1.5"
+#ifdef OI_SBC_EVAL
+" (Evaluation version)"
+#endif
+;
+
+/** This function returns the version string for the BLUEmagic 3.0 protocol stack
+    and profiles */
+OI_CHAR *OI_CODEC_Version(void) {
+    return codecVersion;
+}
+
+/**********************************************************************************/
+
+/**
+@}
+*/
diff --git a/bt/embdrv/sbc/decoder/srce/readsamplesjoint.inc b/bt/embdrv/sbc/decoder/srce/readsamplesjoint.inc
new file mode 100644
index 0000000..c1d0e08
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/srce/readsamplesjoint.inc
@@ -0,0 +1,111 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ * @file readsamplesjoint.inc
+ *
+ * This is the body of the generic version of OI_SBC_ReadSamplesJoint().
+ * It is designed to be \#included into a function as follows:
+    \code
+    void OI_SBC_ReadSamplesJoint4(OI_CODEC_SBC_COMMON_CONTEXT *common, OI_BITSTREAM *global_bs)
+    {
+        #define NROF_SUBBANDS 4
+        #include "readsamplesjoint.inc"
+        #undef NROF_SUBBANDS
+    }
+
+    void OI_SBC_ReadSamplesJoint8(OI_CODEC_SBC_COMMON_CONTEXT *common, OI_BITSTREAM *global_bs)
+    {
+        #define NROF_SUBBANDS 8
+        #include "readsamplesjoint.inc"
+        #undef NROF_SUBBANDS
+    }
+    \endcode
+ * Or to make a generic version:
+    \code
+    void OI_SBC_ReadSamplesJoint(OI_CODEC_SBC_COMMON_CONTEXT *common, OI_BITSTREAM *global_bs)
+    {
+        OI_UINT nrof_subbands = common->frameInfo.nrof_subbands;
+
+        #define NROF_SUBBANDS nrof_subbands
+        #include "readsamplesjoint.inc"
+        #undef NROF_SUBBANDS
+    }
+    \endcode
+ * @ingroup codec_internal
+ *******************************************************************************/
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+{
+    OI_CODEC_SBC_COMMON_CONTEXT *common = &context->common;
+    OI_UINT bl = common->frameInfo.nrof_blocks;
+    int32_t * RESTRICT s = common->subdata;
+    uint8_t *ptr = global_bs->ptr.w;
+    uint32_t value = global_bs->value;
+    OI_UINT bitPtr = global_bs->bitPtr;
+    uint8_t jmask = common->frameInfo.join << (8 - NROF_SUBBANDS);
+
+    do {
+        int8_t *sf_array = &common->scale_factor[0];
+        uint8_t *bits_array = &common->bits.uint8[0];
+        uint8_t joint = jmask;
+        OI_UINT sb;
+        /*
+         * Left channel
+         */
+        sb = NROF_SUBBANDS;
+        do {
+            uint32_t raw;
+            int32_t dequant;
+            uint8_t bits = *bits_array++;
+            OI_INT sf = *sf_array++;
+
+            OI_BITSTREAM_READUINT(raw, bits, ptr, value, bitPtr);
+            dequant = OI_SBC_Dequant(raw, sf, bits);
+            *s++ = dequant;
+        } while (--sb);
+        /*
+         * Right channel
+         */
+        sb = NROF_SUBBANDS;
+        do {
+            uint32_t raw;
+            int32_t dequant;
+            uint8_t bits = *bits_array++;
+            OI_INT sf = *sf_array++;
+
+            OI_BITSTREAM_READUINT(raw, bits, ptr, value, bitPtr);
+            dequant = OI_SBC_Dequant(raw, sf, bits);
+            /*
+             * Check if we need to do mid/side
+             */
+            if (joint & 0x80) {
+                int32_t mid = *(s - NROF_SUBBANDS);
+                int32_t side = dequant;
+                *(s - NROF_SUBBANDS) = mid + side;
+                dequant = mid - side;
+            }
+            joint <<= 1;
+            *s++ = dequant;
+        } while (--sb);
+    } while (--bl);
+}
diff --git a/bt/embdrv/sbc/decoder/srce/synthesis-8-generated.c b/bt/embdrv/sbc/decoder/srce/synthesis-8-generated.c
new file mode 100644
index 0000000..71aba9e
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/srce/synthesis-8-generated.c
@@ -0,0 +1,135 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/**
+ @file
+
+ DO NOT EDIT THIS FILE DIRECTLY
+
+ This file is automatically generated by the "synthesis-gen.pl" script.
+ Any changes to this generated file will be lost when the script is re-run.
+
+ These functions are called by functions in synthesis.c to perform the synthesis
+ filterbank computations for the SBC decoder.
+
+
+ */
+
+#include <oi_codec_sbc_private.h>
+
+#ifndef CLIP_INT16
+#define CLIP_INT16(x) do { if ((x) > OI_INT16_MAX) { (x) = OI_INT16_MAX; } else if ((x) < OI_INT16_MIN) { (x) = OI_INT16_MIN; } } while (0)
+#endif
+
+#define MUL_16S_16S(_x, _y) ((_x) * (_y))
+
+PRIVATE void SynthWindow80_generated(int16_t *pcm, SBC_BUFFER_T const * RESTRICT buffer, OI_UINT strideShift)
+{
+    int32_t pcm_a, pcm_b;
+    /* 1 - stage 0 */ pcm_b = 0;
+    /* 1 - stage 0 */ pcm_b +=(MUL_16S_16S(8235, buffer[ 12]))>> 3;
+    /* 1 - stage 0 */ pcm_b +=(MUL_16S_16S(-23167, buffer[ 20]))>> 3;
+    /* 1 - stage 0 */ pcm_b +=(MUL_16S_16S(26479, buffer[ 28]))>> 2;
+    /* 1 - stage 0 */ pcm_b +=(MUL_16S_16S(-17397, buffer[ 36]))<< 1;
+    /* 1 - stage 0 */ pcm_b +=(MUL_16S_16S(9399, buffer[ 44]))<< 3;
+    /* 1 - stage 0 */ pcm_b +=(MUL_16S_16S(17397, buffer[ 52]))<< 1;
+    /* 1 - stage 0 */ pcm_b +=(MUL_16S_16S(26479, buffer[ 60]))>> 2;
+    /* 1 - stage 0 */ pcm_b +=(MUL_16S_16S(23167, buffer[ 68]))>> 3;
+    /* 1 - stage 0 */ pcm_b +=(MUL_16S_16S(8235, buffer[ 76]))>> 3;
+    /* 1 - stage 0 */ pcm_b /= 32768; CLIP_INT16(pcm_b); pcm[0<<strideShift] = (int16_t)pcm_b;
+    /* 1 - stage 1 */ pcm_a = 0;
+    /* 1 - stage 1 */ pcm_b = 0;
+    /* 1 - stage 1 */ pcm_a +=(MUL_16S_16S(-3263, buffer[  5]))>> 5;
+    /* 1 - stage 1 */ pcm_b +=(MUL_16S_16S(9293, buffer[  5]))>> 3;
+    /* 1 - stage 1 */ pcm_a +=(MUL_16S_16S(29293, buffer[ 11]))>> 5;
+    /* 1 - stage 1 */ pcm_b +=(MUL_16S_16S(-6087, buffer[ 11]))>> 2;
+    /* 1 - stage 1 */ pcm_a +=(MUL_16S_16S(-5229, buffer[ 21]));
+    /* 1 - stage 1 */ pcm_b +=(MUL_16S_16S(1247, buffer[ 21]))<< 3;
+    /* 1 - stage 1 */ pcm_a +=(MUL_16S_16S(30835, buffer[ 27]))>> 3;
+    /* 1 - stage 1 */ pcm_b +=(MUL_16S_16S(-2893, buffer[ 27]))<< 3;
+    /* 1 - stage 1 */ pcm_a +=(MUL_16S_16S(-27021, buffer[ 37]))<< 1;
+    /* 1 - stage 1 */ pcm_b +=(MUL_16S_16S(23671, buffer[ 37]))<< 2;
+    /* 1 - stage 1 */ pcm_a +=(MUL_16S_16S(31633, buffer[ 43]))<< 1;
+    /* 1 - stage 1 */ pcm_b +=(MUL_16S_16S(18055, buffer[ 43]))<< 1;
+    /* 1 - stage 1 */ pcm_a +=(MUL_16S_16S(17319, buffer[ 53]))<< 1;
+    /* 1 - stage 1 */ pcm_b +=(MUL_16S_16S(11537, buffer[ 53]))>> 1;
+    /* 1 - stage 1 */ pcm_a +=(MUL_16S_16S(26663, buffer[ 59]))>> 2;
+    /* 1 - stage 1 */ pcm_b +=(MUL_16S_16S(1747, buffer[ 59]))<< 1;
+    /* 1 - stage 1 */ pcm_a +=(MUL_16S_16S(4555, buffer[ 69]))>> 1;
+    /* 1 - stage 1 */ pcm_b +=(MUL_16S_16S(685, buffer[ 69]))<< 1;
+    /* 1 - stage 1 */ pcm_a +=(MUL_16S_16S(12419, buffer[ 75]))>> 4;
+    /* 1 - stage 1 */ pcm_b +=(MUL_16S_16S(8721, buffer[ 75]))>> 7;
+    /* 1 - stage 1 */ pcm_a /= 32768; CLIP_INT16(pcm_a); pcm[1<<strideShift] = (int16_t)pcm_a;
+    /* 1 - stage 1 */ pcm_b /= 32768; CLIP_INT16(pcm_b); pcm[7<<strideShift] = (int16_t)pcm_b;
+    /* 1 - stage 2 */ pcm_a = 0;
+    /* 1 - stage 2 */ pcm_b = 0;
+    /* 1 - stage 2 */ pcm_a +=(MUL_16S_16S(-10385, buffer[  6]))>> 6;
+    /* 1 - stage 2 */ pcm_b +=(MUL_16S_16S(11167, buffer[  6]))>> 4;
+    /* 1 - stage 2 */ pcm_a +=(MUL_16S_16S(24995, buffer[ 10]))>> 5;
+    /* 1 - stage 2 */ pcm_b +=(MUL_16S_16S(-10337, buffer[ 10]))>> 4;
+    /* 1 - stage 2 */ pcm_a +=(MUL_16S_16S(-309, buffer[ 22]))<< 4;
+    /* 1 - stage 2 */ pcm_b +=(MUL_16S_16S(1917, buffer[ 22]))<< 2;
+    /* 1 - stage 2 */ pcm_a +=(MUL_16S_16S(9161, buffer[ 26]))>> 3;
+    /* 1 - stage 2 */ pcm_b +=(MUL_16S_16S(-30605, buffer[ 26]))>> 1;
+    /* 1 - stage 2 */ pcm_a +=(MUL_16S_16S(-23063, buffer[ 38]))<< 1;
+    /* 1 - stage 2 */ pcm_b +=(MUL_16S_16S(8317, buffer[ 38]))<< 3;
+    /* 1 - stage 2 */ pcm_a +=(MUL_16S_16S(27561, buffer[ 42]))<< 1;
+    /* 1 - stage 2 */ pcm_b +=(MUL_16S_16S(9553, buffer[ 42]))<< 2;
+    /* 1 - stage 2 */ pcm_a +=(MUL_16S_16S(2309, buffer[ 54]))<< 3;
+    /* 1 - stage 2 */ pcm_b +=(MUL_16S_16S(22117, buffer[ 54]))>> 4;
+    /* 1 - stage 2 */ pcm_a +=(MUL_16S_16S(12705, buffer[ 58]))>> 1;
+    /* 1 - stage 2 */ pcm_b +=(MUL_16S_16S(16383, buffer[ 58]))>> 2;
+    /* 1 - stage 2 */ pcm_a +=(MUL_16S_16S(6239, buffer[ 70]))>> 3;
+    /* 1 - stage 2 */ pcm_b +=(MUL_16S_16S(7543, buffer[ 70]))>> 3;
+    /* 1 - stage 2 */ pcm_a +=(MUL_16S_16S(9251, buffer[ 74]))>> 4;
+    /* 1 - stage 2 */ pcm_b +=(MUL_16S_16S(8603, buffer[ 74]))>> 6;
+    /* 1 - stage 2 */ pcm_a /= 32768; CLIP_INT16(pcm_a); pcm[2<<strideShift] = (int16_t)pcm_a;
+    /* 1 - stage 2 */ pcm_b /= 32768; CLIP_INT16(pcm_b); pcm[6<<strideShift] = (int16_t)pcm_b;
+    /* 1 - stage 3 */ pcm_a = 0;
+    /* 1 - stage 3 */ pcm_b = 0;
+    /* 1 - stage 3 */ pcm_a +=(MUL_16S_16S(-16457, buffer[  7]))>> 6;
+    /* 1 - stage 3 */ pcm_b +=(MUL_16S_16S(16913, buffer[  7]))>> 5;
+    /* 1 - stage 3 */ pcm_a +=(MUL_16S_16S(19083, buffer[  9]))>> 5;
+    /* 1 - stage 3 */ pcm_b +=(MUL_16S_16S(-8443, buffer[  9]))>> 7;
+    /* 1 - stage 3 */ pcm_a +=(MUL_16S_16S(-23641, buffer[ 23]))>> 2;
+    /* 1 - stage 3 */ pcm_b +=(MUL_16S_16S(3687, buffer[ 23]))<< 1;
+    /* 1 - stage 3 */ pcm_a +=(MUL_16S_16S(-29015, buffer[ 25]))>> 4;
+    /* 1 - stage 3 */ pcm_b +=(MUL_16S_16S(-301, buffer[ 25]))<< 5;
+    /* 1 - stage 3 */ pcm_a +=(MUL_16S_16S(-12889, buffer[ 39]))<< 2;
+    /* 1 - stage 3 */ pcm_b +=(MUL_16S_16S(15447, buffer[ 39]))<< 2;
+    /* 1 - stage 3 */ pcm_a +=(MUL_16S_16S(6145, buffer[ 41]))<< 3;
+    /* 1 - stage 3 */ pcm_b +=(MUL_16S_16S(10255, buffer[ 41]))<< 2;
+    /* 1 - stage 3 */ pcm_a +=(MUL_16S_16S(24211, buffer[ 55]))>> 1;
+    /* 1 - stage 3 */ pcm_b +=(MUL_16S_16S(-18233, buffer[ 55]))>> 3;
+    /* 1 - stage 3 */ pcm_a +=(MUL_16S_16S(23469, buffer[ 57]))>> 2;
+    /* 1 - stage 3 */ pcm_b +=(MUL_16S_16S(9405, buffer[ 57]))>> 1;
+    /* 1 - stage 3 */ pcm_a +=(MUL_16S_16S(21223, buffer[ 71]))>> 8;
+    /* 1 - stage 3 */ pcm_b +=(MUL_16S_16S(1499, buffer[ 71]))>> 1;
+    /* 1 - stage 3 */ pcm_a +=(MUL_16S_16S(26913, buffer[ 73]))>> 6;
+    /* 1 - stage 3 */ pcm_b +=(MUL_16S_16S(26189, buffer[ 73]))>> 7;
+    /* 1 - stage 3 */ pcm_a /= 32768; CLIP_INT16(pcm_a); pcm[3<<strideShift] = (int16_t)pcm_a;
+    /* 1 - stage 3 */ pcm_b /= 32768; CLIP_INT16(pcm_b); pcm[5<<strideShift] = (int16_t)pcm_b;
+    /* 1 - stage 4 */ pcm_a = 0;
+    /* 1 - stage 4 */ pcm_a +=(MUL_16S_16S(10445, buffer[  8]))>> 4;
+    /* 1 - stage 4 */ pcm_a +=(MUL_16S_16S(-5297, buffer[ 24]))<< 1;
+    /* 1 - stage 4 */ pcm_a +=(MUL_16S_16S(22299, buffer[ 40]))<< 2;
+    /* 1 - stage 4 */ pcm_a +=(MUL_16S_16S(10603, buffer[ 56]));
+    /* 1 - stage 4 */ pcm_a +=(MUL_16S_16S(9539, buffer[ 72]))>> 4;
+    /* 1 - stage 4 */ pcm_a /= 32768; CLIP_INT16(pcm_a); pcm[4<<strideShift] = (int16_t)pcm_a;
+}
diff --git a/bt/embdrv/sbc/decoder/srce/synthesis-dct8.c b/bt/embdrv/sbc/decoder/srce/synthesis-dct8.c
new file mode 100644
index 0000000..0e82627
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/srce/synthesis-dct8.c
@@ -0,0 +1,305 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+/** @file
+@ingroup codec_internal
+*/
+
+/**@addgroup codec_internal*/
+/**@{*/
+
+/*
+ * Performs an 8-point Type-II scaled DCT using the Arai-Agui-Nakajima
+ * factorization. The scaling factors are folded into the windowing
+ * constants. 29 adds and 5 16x32 multiplies per 8 samples.
+ */
+
+#include "oi_codec_sbc_private.h"
+
+#define AAN_C4_FIX (759250125)/* S1.30  759250125   0.707107*/
+
+#define AAN_C6_FIX (410903207)/* S1.30  410903207   0.382683*/
+
+#define AAN_Q0_FIX (581104888)/* S1.30  581104888   0.541196*/
+
+#define AAN_Q1_FIX (1402911301)/* S1.30 1402911301   1.306563*/
+
+/** Scales x by y bits to the right, adding a rounding factor.
+ */
+#ifndef SCALE
+#define SCALE(x, y) (((x) + (1 <<((y)-1))) >> (y))
+#endif
+
+/**
+ * Default C language implementation of a 32x32->32 multiply. This function may
+ * be replaced by a platform-specific version for speed.
+ *
+ * @param u A signed 32-bit multiplicand
+ * @param v A signed 32-bit multiplier
+
+ * @return  A signed 32-bit value corresponding to the 32 most significant bits
+ * of the 64-bit product of u and v.
+ */
+INLINE int32_t default_mul_32s_32s_hi(int32_t u, int32_t v)
+{
+    uint32_t u0, v0;
+    int32_t u1, v1, w1, w2, t;
+
+    u0 = u & 0xFFFF; u1 = u >> 16;
+    v0 = v & 0xFFFF; v1 = v >> 16;
+    t = u0*v0;
+    t = u1*v0 + ((uint32_t)t >> 16);
+    w1 = t & 0xFFFF;
+    w2 = t >> 16;
+    w1 = u0*v1 + w1;
+    return u1*v1 + w2 + (w1 >> 16);
+}
+
+#define MUL_32S_32S_HI(_x, _y) default_mul_32s_32s_hi(_x, _y)
+
+
+#ifdef DEBUG_DCT
+PRIVATE void float_dct2_8(float * RESTRICT out, int32_t const *RESTRICT in)
+{
+#define FIX(x,bits) (((int)floor(0.5f+((x)*((float)(1<<bits)))))/((float)(1<<bits)))
+#define FLOAT_BUTTERFLY(x,y) x += y; y = x - (y*2); OI_ASSERT(VALID_INT32(x)); OI_ASSERT(VALID_INT32(y));
+#define FLOAT_MULT_DCT(K, sample) (FIX(K,20) * sample)
+#define FLOAT_SCALE(x, y) (((x) / (double)(1 << (y))))
+
+    double L00,L01,L02,L03,L04,L05,L06,L07;
+    double L25;
+
+    double in0,in1,in2,in3;
+    double in4,in5,in6,in7;
+
+    in0 = FLOAT_SCALE(in[0], DCTII_8_SHIFT_IN); OI_ASSERT(VALID_INT32(in0));
+    in1 = FLOAT_SCALE(in[1], DCTII_8_SHIFT_IN); OI_ASSERT(VALID_INT32(in1));
+    in2 = FLOAT_SCALE(in[2], DCTII_8_SHIFT_IN); OI_ASSERT(VALID_INT32(in2));
+    in3 = FLOAT_SCALE(in[3], DCTII_8_SHIFT_IN); OI_ASSERT(VALID_INT32(in3));
+    in4 = FLOAT_SCALE(in[4], DCTII_8_SHIFT_IN); OI_ASSERT(VALID_INT32(in4));
+    in5 = FLOAT_SCALE(in[5], DCTII_8_SHIFT_IN); OI_ASSERT(VALID_INT32(in5));
+    in6 = FLOAT_SCALE(in[6], DCTII_8_SHIFT_IN); OI_ASSERT(VALID_INT32(in6));
+    in7 = FLOAT_SCALE(in[7], DCTII_8_SHIFT_IN); OI_ASSERT(VALID_INT32(in7));
+
+    L00 = (in0 + in7); OI_ASSERT(VALID_INT32(L00));
+    L01 = (in1 + in6); OI_ASSERT(VALID_INT32(L01));
+    L02 = (in2 + in5); OI_ASSERT(VALID_INT32(L02));
+    L03 = (in3 + in4); OI_ASSERT(VALID_INT32(L03));
+
+    L04 = (in3 - in4); OI_ASSERT(VALID_INT32(L04));
+    L05 = (in2 - in5); OI_ASSERT(VALID_INT32(L05));
+    L06 = (in1 - in6); OI_ASSERT(VALID_INT32(L06));
+    L07 = (in0 - in7); OI_ASSERT(VALID_INT32(L07));
+
+    FLOAT_BUTTERFLY(L00, L03);
+    FLOAT_BUTTERFLY(L01, L02);
+
+    L02 += L03; OI_ASSERT(VALID_INT32(L02));
+
+    L02 = FLOAT_MULT_DCT(AAN_C4_FLOAT, L02); OI_ASSERT(VALID_INT32(L02));
+
+    FLOAT_BUTTERFLY(L00, L01);
+
+    out[0] = (float)FLOAT_SCALE(L00, DCTII_8_SHIFT_0); OI_ASSERT(VALID_INT16(out[0]));
+    out[4] = (float)FLOAT_SCALE(L01, DCTII_8_SHIFT_4); OI_ASSERT(VALID_INT16(out[4]));
+
+    FLOAT_BUTTERFLY(L03, L02);
+    out[6] = (float)FLOAT_SCALE(L02, DCTII_8_SHIFT_6); OI_ASSERT(VALID_INT16(out[6]));
+    out[2] = (float)FLOAT_SCALE(L03, DCTII_8_SHIFT_2); OI_ASSERT(VALID_INT16(out[2]));
+
+    L04 += L05; OI_ASSERT(VALID_INT32(L04));
+    L05 += L06; OI_ASSERT(VALID_INT32(L05));
+    L06 += L07; OI_ASSERT(VALID_INT32(L06));
+
+    L04/=2;
+    L05/=2;
+    L06/=2;
+    L07/=2;
+
+    L05 = FLOAT_MULT_DCT(AAN_C4_FLOAT, L05); OI_ASSERT(VALID_INT32(L05));
+
+    L25 = L06 - L04; OI_ASSERT(VALID_INT32(L25));
+    L25 = FLOAT_MULT_DCT(AAN_C6_FLOAT, L25); OI_ASSERT(VALID_INT32(L25));
+
+    L04 = FLOAT_MULT_DCT(AAN_Q0_FLOAT, L04); OI_ASSERT(VALID_INT32(L04));
+    L04 -= L25; OI_ASSERT(VALID_INT32(L04));
+
+    L06 = FLOAT_MULT_DCT(AAN_Q1_FLOAT, L06); OI_ASSERT(VALID_INT32(L06));
+    L06 -= L25; OI_ASSERT(VALID_INT32(L25));
+
+    FLOAT_BUTTERFLY(L07, L05);
+
+    FLOAT_BUTTERFLY(L05, L04);
+    out[3] = (float)(FLOAT_SCALE(L04, DCTII_8_SHIFT_3-1)); OI_ASSERT(VALID_INT16(out[3]));
+    out[5] = (float)(FLOAT_SCALE(L05, DCTII_8_SHIFT_5-1)); OI_ASSERT(VALID_INT16(out[5]));
+
+    FLOAT_BUTTERFLY(L07, L06);
+    out[7] = (float)(FLOAT_SCALE(L06, DCTII_8_SHIFT_7-1)); OI_ASSERT(VALID_INT16(out[7]));
+    out[1] = (float)(FLOAT_SCALE(L07, DCTII_8_SHIFT_1-1)); OI_ASSERT(VALID_INT16(out[1]));
+}
+#undef BUTTERFLY
+#endif
+
+
+/*
+ * This function calculates the AAN DCT. Its inputs are in S16.15 format, as
+ * returned by OI_SBC_Dequant. In practice, abs(in[x]) < 52429.0 / 1.38
+ * (1244918057 integer). The function it computes is an approximation to the array defined
+ * by:
+ *
+ * diag(aan_s) * AAN= C2
+ *
+ *   or
+ *
+ * AAN = diag(1/aan_s) * C2
+ *
+ * where C2 is as it is defined in the comment at the head of this file, and
+ *
+ * aan_s[i] = aan_s = 1/(2*cos(i*pi/16)) with i = 1..7, aan_s[0] = 1;
+ *
+ * aan_s[i] = [ 1.000  0.510  0.541  0.601  0.707  0.900  1.307  2.563 ]
+ *
+ * The output ranges are shown as follows:
+ *
+ * Let Y[0..7] = AAN * X[0..7]
+ *
+ * Without loss of generality, assume the input vector X consists of elements
+ * between -1 and 1. The maximum possible value of a given output element occurs
+ * with some particular combination of input vector elements each of which is -1
+ * or 1. Consider the computation of Y[i]. Y[i] = sum t=0..7 of AAN[t,i]*X[i]. Y is
+ * maximized if the sign of X[i] matches the sign of AAN[t,i], ensuring a
+ * positive contribution to the sum. Equivalently, one may simply sum
+ * abs(AAN)[t,i] over t to get the maximum possible value of Y[i].
+ *
+ * This yields approximately [8.00  10.05   9.66   8.52   8.00   5.70   4.00   2.00]
+ *
+ * Given the maximum magnitude sensible input value of +/-37992, this yields the
+ * following vector of maximum output magnitudes:
+ *
+ * [ 303936  381820  367003  323692  303936  216555  151968   75984 ]
+ *
+ * Ultimately, these values must fit into 16 bit signed integers, so they must
+ * be scaled. A non-uniform scaling helps maximize the kept precision. The
+ * relative number of extra bits of precision maintainable with respect to the
+ * largest value is given here:
+ *
+ * [ 0  0  0  0  0  0  1  2 ]
+ *
+ */
+PRIVATE void dct2_8(SBC_BUFFER_T * RESTRICT out, int32_t const *RESTRICT in)
+{
+#define BUTTERFLY(x,y) x += (y); (y) = (x) - ((y)<<1);
+#define FIX_MULT_DCT(K, x) (MUL_32S_32S_HI(K,x)<<2)
+
+    int32_t L00,L01,L02,L03,L04,L05,L06,L07;
+    int32_t L25;
+
+    int32_t in0,in1,in2,in3;
+    int32_t in4,in5,in6,in7;
+
+#if DCTII_8_SHIFT_IN != 0
+    in0 = SCALE(in[0], DCTII_8_SHIFT_IN);
+    in1 = SCALE(in[1], DCTII_8_SHIFT_IN);
+    in2 = SCALE(in[2], DCTII_8_SHIFT_IN);
+    in3 = SCALE(in[3], DCTII_8_SHIFT_IN);
+    in4 = SCALE(in[4], DCTII_8_SHIFT_IN);
+    in5 = SCALE(in[5], DCTII_8_SHIFT_IN);
+    in6 = SCALE(in[6], DCTII_8_SHIFT_IN);
+    in7 = SCALE(in[7], DCTII_8_SHIFT_IN);
+#else
+    in0 = in[0];
+    in1 = in[1];
+    in2 = in[2];
+    in3 = in[3];
+    in4 = in[4];
+    in5 = in[5];
+    in6 = in[6];
+    in7 = in[7];
+#endif
+
+    L00 = in0 + in7;
+    L01 = in1 + in6;
+    L02 = in2 + in5;
+    L03 = in3 + in4;
+
+    L04 = in3 - in4;
+    L05 = in2 - in5;
+    L06 = in1 - in6;
+    L07 = in0 - in7;
+
+    BUTTERFLY(L00, L03);
+    BUTTERFLY(L01, L02);
+
+    L02 += L03;
+
+    L02 = FIX_MULT_DCT(AAN_C4_FIX, L02);
+
+    BUTTERFLY(L00, L01);
+
+    out[0] = (int16_t)SCALE(L00, DCTII_8_SHIFT_0);
+    out[4] = (int16_t)SCALE(L01, DCTII_8_SHIFT_4);
+
+    BUTTERFLY(L03, L02);
+    out[6] = (int16_t)SCALE(L02, DCTII_8_SHIFT_6);
+    out[2] = (int16_t)SCALE(L03, DCTII_8_SHIFT_2);
+
+    L04 += L05;
+    L05 += L06;
+    L06 += L07;
+
+    L04/=2;
+    L05/=2;
+    L06/=2;
+    L07/=2;
+
+    L05 = FIX_MULT_DCT(AAN_C4_FIX, L05);
+
+    L25 = L06 - L04;
+    L25 = FIX_MULT_DCT(AAN_C6_FIX, L25);
+
+    L04 = FIX_MULT_DCT(AAN_Q0_FIX, L04);
+    L04 -= L25;
+
+    L06 = FIX_MULT_DCT(AAN_Q1_FIX, L06);
+    L06 -= L25;
+
+    BUTTERFLY(L07, L05);
+
+    BUTTERFLY(L05, L04);
+    out[3] = (int16_t)SCALE(L04, DCTII_8_SHIFT_3-1);
+    out[5] = (int16_t)SCALE(L05, DCTII_8_SHIFT_5-1);
+
+    BUTTERFLY(L07, L06);
+    out[7] = (int16_t)SCALE(L06, DCTII_8_SHIFT_7-1);
+    out[1] = (int16_t)SCALE(L07, DCTII_8_SHIFT_1-1);
+#undef BUTTERFLY
+
+#ifdef DEBUG_DCT
+    {
+        float float_out[8];
+        float_dct2_8(float_out, in);
+    }
+#endif
+}
+
+/**@}*/
diff --git a/bt/embdrv/sbc/decoder/srce/synthesis-sbc.c b/bt/embdrv/sbc/decoder/srce/synthesis-sbc.c
new file mode 100644
index 0000000..598c7e9
--- /dev/null
+++ b/bt/embdrv/sbc/decoder/srce/synthesis-sbc.c
@@ -0,0 +1,510 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 The Android Open Source Project
+ *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/**********************************************************************************
+  $Revision: #1 $
+***********************************************************************************/
+
+/** @file
+
+This file, along with synthesis-generated.c, contains the synthesis
+filterbank routines. The operations performed correspond to the
+operations described in A2DP Appendix B, Figure 12.3. Several
+mathematical optimizations are performed, particularly for the
+8-subband case.
+
+One important optimization is to note that the "matrixing" operation
+can be decomposed into the product of a type II discrete cosine kernel
+and another, sparse matrix.
+
+According to Fig 12.3, in the 8-subband case,
+@code
+    N[k][i] = cos((i+0.5)*(k+4)*pi/8), k = 0..15 and i = 0..7
+@endcode
+
+N can be factored as R * C2, where C2 is an 8-point type II discrete
+cosine kernel given by
+@code
+    C2[k][i] = cos((i+0.5)*k*pi/8)), k = 0..7 and i = 0..7
+@endcode
+
+R turns out to be a sparse 16x8 matrix with the following non-zero
+entries:
+@code
+    R[k][k+4]        =  1,   k = 0..3
+    R[k][abs(12-k)]  = -1,   k = 5..15
+@endcode
+
+The spec describes computing V[0..15] as N * R.
+@code
+    V[0..15] = N * R = (R * C2) * R = R * (C2 * R)
+@endcode
+
+C2 * R corresponds to computing the discrete cosine transform of R, so
+V[0..15] can be computed by taking the DCT of R followed by assignment
+and selective negation of the DCT result into V.
+
+        Although this was derived empirically using GNU Octave, it is
+        formally demonstrated in, e.g., Liu, Chi-Min and Lee,
+        Wen-Chieh. "A Unified Fast Algorithm for Cosine Modulated
+        Filter Banks in Current Audio Coding Standards." Journal of
+        the AES 47 (December 1999): 1061.
+
+Given the shift operation performed prior to computing V[0..15], it is
+clear that V[0..159] represents a rolling history of the 10 most
+recent groups of blocks input to the synthesis operation. Interpreting
+the matrix N in light of its factorization into C2 and R, R's
+sparseness has implications for interpreting the values in V. In
+particular, there is considerable redundancy in the values stored in
+V. Furthermore, since R[4][0..7] are all zeros, one out of every 16
+values in V will be zero regardless of the input data. Within each
+block of 16 values in V, fully half of them are redundant or
+irrelevant:
+
+@code
+    V[ 0] =  DCT[4]
+    V[ 1] =  DCT[5]
+    V[ 2] =  DCT[6]
+    V[ 3] =  DCT[7]
+    V[ 4] = 0
+    V[ 5] = -DCT[7] = -V[3] (redundant)
+    V[ 6] = -DCT[6] = -V[2] (redundant)
+    V[ 7] = -DCT[5] = -V[1] (redundant)
+    V[ 8] = -DCT[4] = -V[0] (redundant)
+    V[ 9] = -DCT[3]
+    V[10] = -DCT[2]
+    V[11] = -DCT[1]
+    V[12] = -DCT[0]
+    V[13] = -DCT[1] = V[11] (redundant)
+    V[14] = -DCT[2] = V[10] (redundant)
+    V[15] = -DCT[3] = V[ 9] (redundant)
+@endcode
+
+Since the elements of V beyond 15 were originally computed the same
+way during a previous run, what holds true for V[x] also holds true
+for V[x+16]. Thus, so long as care is taken to maintain the mapping,
+we need only actually store the unique values, which correspond to the
+output of the DCT, in some cases inverted. In fact, instead of storing
+V[0..159], we could store DCT[0..79] which would contain a history of
+DCT results. More on this in a bit.
+
+Going back to figure 12.3 in the spec, it should be clear that the
+vector U need not actually be explicitly constructed, but that with
+suitable indexing into V during the window operation, the same end can
+be accomplished. In the same spirit of the pseudocode shown in the
+figure, the following is the construction of W without using U:
+
+@code
+    for i=0 to 79 do
+        W[i] = D[i]*VSIGN(i)*V[remap_V(i)] where remap_V(i) = 32*(int(i/16)) + (i % 16) + (i % 16 >= 8 ? 16 : 0)
+                                             and VSIGN(i) maps i%16 into {1, 1, 1, 1, 0, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1 }
+                                             These values correspond to the
+                                             signs of the redundant values as
+                                             shown in the explanation three
+                                             paragraphs above.
+@endcode
+
+We saw above how V[4..8,13..15] (and by extension
+V[(4..8,13..15)+16*n]) can be defined in terms of other elements
+within the subblock of V. V[0..3,9..12] correspond to DCT elements.
+
+@code
+    for i=0 to 79 do
+        W[i] = D[i]*DSIGN(i)*DCT[remap_DCT(i)]
+@endcode
+
+The DCT is calculated using the Arai-Agui-Nakajima factorization,
+which saves some computation by producing output that needs to be
+multiplied by scaling factors before being used.
+
+@code
+    for i=0 to 79 do
+        W[i] = D[i]*SCALE[i%8]*AAN_DCT[remap_DCT(i)]
+@endcode
+
+D can be premultiplied with the DCT scaling factors to yield
+
+@code
+    for i=0 to 79 do
+        W[i] = DSCALED[i]*AAN_DCT[remap_DCT(i)] where DSCALED[i] = D[i]*SCALE[i%8]
+@endcode
+
+The output samples X[0..7] are defined as sums of W:
+
+@code
+        X[j] = sum{i=0..9}(W[j+8*i])
+@endcode
+
+@ingroup codec_internal
+*/
+
+/**
+@addtogroup codec_internal
+@{
+*/
+
+#include "oi_codec_sbc_private.h"
+
+const int32_t dec_window_4[21] = {
+           0,        /* +0.00000000E+00 */
+          97,        /* +5.36548976E-04 */
+         270,        /* +1.49188357E-03 */
+         495,        /* +2.73370904E-03 */
+         694,        /* +3.83720193E-03 */
+         704,        /* +3.89205149E-03 */
+         338,        /* +1.86581691E-03 */
+        -554,        /* -3.06012286E-03 */
+        1974,        /* +1.09137620E-02 */
+        3697,        /* +2.04385087E-02 */
+        5224,        /* +2.88757392E-02 */
+        5824,        /* +3.21939290E-02 */
+        4681,        /* +2.58767811E-02 */
+        1109,        /* +6.13245186E-03 */
+       -5214,        /* -2.88217274E-02 */
+      -14047,        /* -7.76463494E-02 */
+       24529,        /* +1.35593274E-01 */
+       35274,        /* +1.94987841E-01 */
+       44618,        /* +2.46636662E-01 */
+       50984,        /* +2.81828203E-01 */
+       53243,        /* +2.94315332E-01 */
+};
+
+#define DCTII_4_K06_FIX ( 11585)/* S1.14      11585   0.707107*/
+
+#define DCTII_4_K08_FIX ( 21407)/* S1.14      21407   1.306563*/
+
+#define DCTII_4_K09_FIX (-15137)/* S1.14     -15137  -0.923880*/
+
+#define DCTII_4_K10_FIX ( -8867)/* S1.14      -8867  -0.541196*/
+
+/** Scales x by y bits to the right, adding a rounding factor.
+ */
+#ifndef SCALE
+#define SCALE(x, y) (((x) + (1 <<((y)-1))) >> (y))
+#endif
+
+#ifndef CLIP_INT16
+#define CLIP_INT16(x) do { if ((x) > OI_INT16_MAX) { (x) = OI_INT16_MAX; } else if ((x) < OI_INT16_MIN) { (x) = OI_INT16_MIN; } } while (0)
+#endif
+
+/**
+ * Default C language implementation of a 16x32->32 multiply. This function may
+ * be replaced by a platform-specific version for speed.
+ *
+ * @param u A signed 16-bit multiplicand
+ * @param v A signed 32-bit multiplier
+
+ * @return  A signed 32-bit value corresponding to the 32 most significant bits
+ * of the 48-bit product of u and v.
+ */
+INLINE int32_t default_mul_16s_32s_hi(int16_t u, int32_t v)
+{
+    uint16_t v0;
+    int16_t v1;
+
+    int32_t w,x;
+
+    v0 = (uint16_t)(v & 0xffff);
+    v1 = (int16_t) (v >> 16);
+
+    w = v1 * u;
+    x = u * v0;
+
+    return w + (x >> 16);
+}
+
+#define MUL_16S_32S_HI(_x, _y) default_mul_16s_32s_hi(_x, _y)
+
+#define LONG_MULT_DCT(K, sample) (MUL_16S_32S_HI(K, sample)<<2)
+
+PRIVATE void SynthWindow80_generated(int16_t *pcm, SBC_BUFFER_T const * RESTRICT buffer, OI_UINT strideShift);
+PRIVATE void SynthWindow112_generated(int16_t *pcm, SBC_BUFFER_T const * RESTRICT buffer, OI_UINT strideShift);
+PRIVATE void dct2_8(SBC_BUFFER_T * RESTRICT out, int32_t const * RESTRICT x);
+
+typedef void (*SYNTH_FRAME)(OI_CODEC_SBC_DECODER_CONTEXT *context, int16_t *pcm, OI_UINT blkstart, OI_UINT blkcount);
+
+#ifndef COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS
+#define COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS(dest, src) do { shift_buffer(dest, src, 72); } while (0)
+#endif
+
+#ifndef DCT2_8
+#define DCT2_8(dst, src) dct2_8(dst, src)
+#endif
+
+#ifndef SYNTH80
+#define SYNTH80 SynthWindow80_generated
+#endif
+
+#ifndef SYNTH112
+#define SYNTH112 SynthWindow112_generated
+#endif
+
+PRIVATE void OI_SBC_SynthFrame_80(OI_CODEC_SBC_DECODER_CONTEXT *context, int16_t *pcm, OI_UINT blkstart, OI_UINT blkcount)
+{
+    OI_UINT blk;
+    OI_UINT ch;
+    OI_UINT nrof_channels = context->common.frameInfo.nrof_channels;
+    OI_UINT pcmStrideShift = context->common.pcmStride == 1 ? 0 : 1;
+    OI_UINT offset = context->common.filterBufferOffset;
+    int32_t *s = context->common.subdata + 8 * nrof_channels * blkstart;
+    OI_UINT blkstop = blkstart + blkcount;
+
+    for (blk = blkstart; blk < blkstop; blk++) {
+        if (offset == 0) {
+            COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS(context->common.filterBuffer[0] + context->common.filterBufferLen - 72, context->common.filterBuffer[0]);
+            if (nrof_channels == 2) {
+                COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS(context->common.filterBuffer[1] + context->common.filterBufferLen - 72, context->common.filterBuffer[1]);
+            }
+            offset = context->common.filterBufferLen - 80;
+        } else {
+            offset -= 1*8;
+        }
+
+        for (ch = 0; ch < nrof_channels; ch++) {
+            DCT2_8(context->common.filterBuffer[ch] + offset, s);
+            SYNTH80(pcm + ch, context->common.filterBuffer[ch] + offset, pcmStrideShift);
+            s += 8;
+        }
+        pcm += (8 << pcmStrideShift);
+    }
+    context->common.filterBufferOffset = offset;
+}
+
+PRIVATE void OI_SBC_SynthFrame_4SB(OI_CODEC_SBC_DECODER_CONTEXT *context, int16_t *pcm, OI_UINT blkstart, OI_UINT blkcount)
+{
+    OI_UINT blk;
+    OI_UINT ch;
+    OI_UINT nrof_channels = context->common.frameInfo.nrof_channels;
+    OI_UINT pcmStrideShift = context->common.pcmStride == 1 ? 0 : 1;
+    OI_UINT offset = context->common.filterBufferOffset;
+    int32_t *s = context->common.subdata + 8 * nrof_channels * blkstart;
+    OI_UINT blkstop = blkstart + blkcount;
+
+    for (blk = blkstart; blk < blkstop; blk++) {
+        if (offset == 0) {
+            COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS(context->common.filterBuffer[0] + context->common.filterBufferLen - 72,context->common.filterBuffer[0]);
+            if (nrof_channels == 2) {
+                COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS(context->common.filterBuffer[1] + context->common.filterBufferLen - 72,context->common.filterBuffer[1]);
+            }
+            offset =context->common.filterBufferLen - 80;
+        } else {
+            offset -= 8;
+        }
+        for (ch = 0; ch < nrof_channels; ch++) {
+            cosineModulateSynth4(context->common.filterBuffer[ch] + offset, s);
+            SynthWindow40_int32_int32_symmetry_with_sum(pcm + ch,
+                                                        context->common.filterBuffer[ch] + offset,
+                                                        pcmStrideShift);
+            s += 4;
+        }
+        pcm += (4 << pcmStrideShift);
+    }
+    context->common.filterBufferOffset = offset;
+}
+
+#ifdef SBC_ENHANCED
+
+PRIVATE void OI_SBC_SynthFrame_Enhanced(OI_CODEC_SBC_DECODER_CONTEXT *context, int16_t *pcm, OI_UINT blkstart, OI_UINT blkcount)
+{
+    OI_UINT blk;
+    OI_UINT ch;
+    OI_UINT nrof_channels = context->common.frameInfo.nrof_channels;
+    OI_UINT pcmStrideShift = context->common.pcmStride == 1 ? 0 : 1;
+    OI_UINT offset = context->common.filterBufferOffset;
+    int32_t *s = context->common.subdata + 8 * nrof_channels * blkstart;
+    OI_UINT blkstop = blkstart + blkcount;
+
+    for (blk = blkstart; blk < blkstop; blk++) {
+        if (offset == 0) {
+            COPY_BACKWARD_32BIT_ALIGNED_104_HALFWORDS(context->common.filterBuffer[0] +context->common.filterBufferLen - 104, context->common.filterBuffer[0]);
+            if (nrof_channels == 2) {
+                COPY_BACKWARD_32BIT_ALIGNED_104_HALFWORDS(context->common.filterBuffer[1] + context->common.filterBufferLen - 104, context->common.filterBuffer[1]);
+            }
+            offset = context->common.filterBufferLen - 112;
+        } else {
+            offset -= 8;
+        }
+        for (ch = 0; ch < nrof_channels; ++ch) {
+            DCT2_8(context->common.filterBuffer[ch] + offset, s);
+            SYNTH112(pcm + ch, context->common.filterBuffer[ch] + offset, pcmStrideShift);
+            s += 8;
+        }
+        pcm += (8 << pcmStrideShift);
+    }
+    context->common.filterBufferOffset = offset;
+}
+
+static const SYNTH_FRAME SynthFrameEnhanced[] = {
+    NULL,                       /* invalid */
+    OI_SBC_SynthFrame_Enhanced, /* mono */
+    OI_SBC_SynthFrame_Enhanced  /* stereo */
+};
+
+#endif
+
+static const SYNTH_FRAME SynthFrame8SB[] = {
+    NULL,             /* invalid */
+    OI_SBC_SynthFrame_80, /* mono */
+    OI_SBC_SynthFrame_80  /* stereo */
+};
+
+
+static const SYNTH_FRAME SynthFrame4SB[] = {
+    NULL,                  /* invalid */
+    OI_SBC_SynthFrame_4SB, /* mono */
+    OI_SBC_SynthFrame_4SB  /* stereo */
+};
+
+PRIVATE void OI_SBC_SynthFrame(OI_CODEC_SBC_DECODER_CONTEXT *context, int16_t *pcm, OI_UINT start_block, OI_UINT nrof_blocks)
+{
+    OI_UINT nrof_subbands = context->common.frameInfo.nrof_subbands;
+    OI_UINT nrof_channels = context->common.frameInfo.nrof_channels;
+
+    OI_ASSERT(nrof_subbands == 4 || nrof_subbands == 8);
+    if (nrof_subbands == 4) {
+        SynthFrame4SB[nrof_channels](context, pcm, start_block, nrof_blocks);
+#ifdef SBC_ENHANCED
+    } else if (context->common.frameInfo.enhanced) {
+        SynthFrameEnhanced[nrof_channels](context, pcm, start_block, nrof_blocks);
+#endif /* SBC_ENHANCED */
+        } else {
+        SynthFrame8SB[nrof_channels](context, pcm, start_block, nrof_blocks);
+    }
+}
+
+
+void SynthWindow40_int32_int32_symmetry_with_sum(int16_t *pcm, SBC_BUFFER_T buffer[80], OI_UINT strideShift)
+{
+    int32_t pa;
+    int32_t pb;
+
+    /* These values should be zero, since out[2] of the 4-band cosine modulation
+     * is always zero. */
+    OI_ASSERT(buffer[ 2] == 0);
+    OI_ASSERT(buffer[10] == 0);
+    OI_ASSERT(buffer[18] == 0);
+    OI_ASSERT(buffer[26] == 0);
+    OI_ASSERT(buffer[34] == 0);
+    OI_ASSERT(buffer[42] == 0);
+    OI_ASSERT(buffer[50] == 0);
+    OI_ASSERT(buffer[58] == 0);
+    OI_ASSERT(buffer[66] == 0);
+    OI_ASSERT(buffer[74] == 0);
+
+
+    pa  = dec_window_4[ 4] * (buffer[12] + buffer[76]);
+    pa += dec_window_4[ 8] * (buffer[16] - buffer[64]);
+    pa += dec_window_4[12] * (buffer[28] + buffer[60]);
+    pa += dec_window_4[16] * (buffer[32] - buffer[48]);
+    pa += dec_window_4[20] *  buffer[44];
+    pa = SCALE(-pa, 15);
+    CLIP_INT16(pa);
+    pcm[0 << strideShift] = (int16_t)pa;
+
+
+    pa  = dec_window_4[ 1] * buffer[ 1]; pb  = dec_window_4[ 1] * buffer[79];
+    pb += dec_window_4[ 3] * buffer[ 3]; pa += dec_window_4[ 3] * buffer[77];
+    pa += dec_window_4[ 5] * buffer[13]; pb += dec_window_4[ 5] * buffer[67];
+    pb += dec_window_4[ 7] * buffer[15]; pa += dec_window_4[ 7] * buffer[65];
+    pa += dec_window_4[ 9] * buffer[17]; pb += dec_window_4[ 9] * buffer[63];
+    pb += dec_window_4[11] * buffer[19]; pa += dec_window_4[11] * buffer[61];
+    pa += dec_window_4[13] * buffer[29]; pb += dec_window_4[13] * buffer[51];
+    pb += dec_window_4[15] * buffer[31]; pa += dec_window_4[15] * buffer[49];
+    pa += dec_window_4[17] * buffer[33]; pb += dec_window_4[17] * buffer[47];
+    pb += dec_window_4[19] * buffer[35]; pa += dec_window_4[19] * buffer[45];
+    pa = SCALE(-pa, 15);
+    CLIP_INT16(pa);
+    pcm[1 << strideShift] = (int16_t)(pa);
+    pb = SCALE(-pb, 15);
+    CLIP_INT16(pb);
+    pcm[3 << strideShift] = (int16_t)(pb);
+
+
+    pa  = dec_window_4[2] * (/*buffer[ 2] + */ buffer[78]);  /* buffer[ 2] is always zero */
+    pa += dec_window_4[6] * (buffer[14] /* + buffer[66]*/);  /* buffer[66] is always zero */
+    pa += dec_window_4[10] * (/*buffer[18] + */ buffer[62]);  /* buffer[18] is always zero */
+    pa += dec_window_4[14] * (buffer[30] /* + buffer[50]*/);  /* buffer[50] is always zero */
+    pa += dec_window_4[18] * (/*buffer[34] + */ buffer[46]);  /* buffer[34] is always zero */
+    pa = SCALE(-pa, 15);
+    CLIP_INT16(pa);
+    pcm[2 << strideShift] = (int16_t)(pa);
+}
+
+
+/**
+  This routine implements the cosine modulation matrix for 4-subband
+  synthesis. This is called "matrixing" in the SBC specification. This
+  matrix, M4,  can be factored into an 8-point Type II Discrete Cosine
+  Transform, DCTII_4 and a matrix S4, given here:
+
+  @code
+        __               __
+       |   0   0   1   0   |
+       |   0   0   0   1   |
+       |   0   0   0   0   |
+       |   0   0   0  -1   |
+  S4 = |   0   0  -1   0   |
+       |   0  -1   0   0   |
+       |  -1   0   0   0   |
+       |__ 0  -1   0   0 __|
+
+  M4 * in = S4 * (DCTII_4 * in)
+  @endcode
+
+  (DCTII_4 * in) is computed using a Fast Cosine Transform. The algorithm
+  here is based on an implementation computed by the SPIRAL computer
+  algebra system, manually converted to fixed-point arithmetic. S4 can be
+  implemented using only assignment and negation.
+  */
+PRIVATE void cosineModulateSynth4(SBC_BUFFER_T * RESTRICT out, int32_t const * RESTRICT in)
+{
+    int32_t f0, f1, f2, f3, f4, f7, f8, f9, f10;
+    int32_t y0, y1, y2, y3;
+
+    f0 = (in[0] - in[3]);
+    f1 = (in[0] + in[3]);
+    f2 = (in[1] - in[2]);
+    f3 = (in[1] + in[2]);
+
+    f4 = f1 - f3;
+
+    y0 = -SCALE(f1 + f3, DCT_SHIFT);
+    y2 = -SCALE(LONG_MULT_DCT(DCTII_4_K06_FIX, f4), DCT_SHIFT);
+    f7 = f0 + f2;
+    f8 = LONG_MULT_DCT(DCTII_4_K08_FIX, f0);
+    f9 = LONG_MULT_DCT(DCTII_4_K09_FIX, f7);
+    f10 = LONG_MULT_DCT(DCTII_4_K10_FIX, f2);
+    y3 = -SCALE(f8 + f9, DCT_SHIFT);
+    y1 = -SCALE(f10 - f9, DCT_SHIFT);
+
+    out[0] = (int16_t)-y2;
+    out[1] = (int16_t)-y3;
+    out[2] = (int16_t)0;
+    out[3] = (int16_t)y3;
+    out[4] = (int16_t)y2;
+    out[5] = (int16_t)y1;
+    out[6] = (int16_t)y0;
+    out[7] = (int16_t)y1;
+}
+
+
+
+/**
+@}
+*/
diff --git a/bt/embdrv/sbc/encoder/include/sbc_dct.h b/bt/embdrv/sbc/encoder/include/sbc_dct.h
new file mode 100644
index 0000000..3f1a4dc
--- /dev/null
+++ b/bt/embdrv/sbc/encoder/include/sbc_dct.h
@@ -0,0 +1,91 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Definitions for the fast DCT.
+ *
+ ******************************************************************************/
+
+#ifndef SBC_DCT_H
+#define SBC_DCT_H
+
+#if (SBC_ARM_ASM_OPT == TRUE)
+#define SBC_MULT_32_16_SIMPLIFIED(s16In2, s32In1, s32OutLow)					\
+{																			    \
+    __asm																		\
+{																				\
+    MUL s32OutLow,(int32_t)s16In2, (s32In1>>15)        \
+}																				\
+}
+#else
+#if (SBC_DSP_OPT == TRUE)
+#define SBC_MULT_32_16_SIMPLIFIED(s16In2, s32In1 , s32OutLow) s32OutLow = SBC_Multiply_32_16_Simplified((int32_t)s16In2,s32In1);
+#else
+#if (SBC_IPAQ_OPT == TRUE)
+/*#define SBC_MULT_32_16_SIMPLIFIED(s16In2, s32In1 , s32OutLow) s32OutLow=(int32_t)((int32_t)(s16In2)*(int32_t)(s32In1>>15)); */
+#define SBC_MULT_32_16_SIMPLIFIED(s16In2, s32In1 , s32OutLow) s32OutLow=(int32_t)(((int64_t)(s16In2)*(int64_t)(s32In1))>>15);
+#if (SBC_IS_64_MULT_IN_IDCT == TRUE)
+#define SBC_MULT_32_32(s32In2, s32In1, s32OutLow)                           \
+{                                                                           \
+    s64Temp = ((int64_t) s32In2) * ((int64_t) s32In1)>>31;            \
+    s32OutLow = (int32_t) s64Temp;                                                    \
+}
+#endif
+#else
+#define SBC_MULT_32_16_SIMPLIFIED(s16In2, s32In1 , s32OutLow)                   \
+{                                                                               \
+    s32In1Temp = s32In1;                                                        \
+    s32In2Temp = (int32_t)s16In2;                                                \
+                                                                                \
+    /* Multiply one +ve and the other -ve number */                             \
+    if (s32In1Temp < 0)                                                         \
+    {                                                                           \
+        s32In1Temp ^= 0xFFFFFFFF;                                               \
+        s32In1Temp++;                                                           \
+        s32OutLow  = (s32In2Temp * (s32In1Temp >> 16));                         \
+        s32OutLow += (( s32In2Temp * (s32In1Temp & 0xFFFF)) >> 16);             \
+        s32OutLow ^= 0xFFFFFFFF;                                                \
+        s32OutLow++;                                                            \
+    }                                                                           \
+    else                                                                        \
+    {                                                                           \
+        s32OutLow  = (s32In2Temp * (s32In1Temp >> 16));                         \
+        s32OutLow += (( s32In2Temp * (s32In1Temp & 0xFFFF)) >> 16);             \
+    }                                                                           \
+    s32OutLow <<= 1;                                                            \
+}
+#if (SBC_IS_64_MULT_IN_IDCT == TRUE)
+#define SBC_MULT_64(s32In1, s32In2, s32OutLow, s32OutHi)  \
+{\
+        s32OutLow=(int32_t)(((int64_t)s32In1*(int64_t)s32In2)& 0x00000000FFFFFFFF);\
+        s32OutHi=(int32_t)(((int64_t)s32In1*(int64_t)s32In2)>>32);\
+}
+#define SBC_MULT_32_32(s32In2, s32In1, s32OutLow)                           \
+{                                                                           \
+    s32HiTemp = 0;                                                          \
+    SBC_MULT_64(s32In2,s32In1 , s32OutLow, s32HiTemp);                      \
+    s32OutLow   = (((s32OutLow>>15)&0x1FFFF) | (s32HiTemp << 17));          \
+}
+#endif
+
+#endif
+#endif
+#endif
+
+#endif
diff --git a/bt/embdrv/sbc/encoder/include/sbc_enc_func_declare.h b/bt/embdrv/sbc/encoder/include/sbc_enc_func_declare.h
new file mode 100644
index 0000000..128086f
--- /dev/null
+++ b/bt/embdrv/sbc/encoder/include/sbc_enc_func_declare.h
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Function declarations.
+ *
+ ******************************************************************************/
+
+#ifndef SBC_FUNCDECLARE_H
+#define SBC_FUNCDECLARE_H
+
+/*#include "sbc_encoder.h"*/
+/* Global data */
+#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == FALSE)
+extern const int16_t gas32CoeffFor4SBs[];
+extern const int16_t gas32CoeffFor8SBs[];
+#else
+extern const int32_t gas32CoeffFor4SBs[];
+extern const int32_t gas32CoeffFor8SBs[];
+#endif
+
+/* Global functions*/
+
+extern void sbc_enc_bit_alloc_mono(SBC_ENC_PARAMS *CodecParams);
+extern void sbc_enc_bit_alloc_ste(SBC_ENC_PARAMS *CodecParams);
+
+extern void SbcAnalysisInit (void);
+
+extern void SbcAnalysisFilter4(SBC_ENC_PARAMS *strEncParams, int16_t *input);
+extern void SbcAnalysisFilter8(SBC_ENC_PARAMS *strEncParams, int16_t *input);
+
+extern void SBC_FastIDCT8 (int32_t *pInVect, int32_t *pOutVect);
+extern void SBC_FastIDCT4 (int32_t *x0, int32_t *pOutVect);
+
+extern uint32_t EncPacking(SBC_ENC_PARAMS *strEncParams, uint8_t *output);
+extern void EncQuantizer(SBC_ENC_PARAMS *);
+#if (SBC_DSP_OPT == TRUE)
+    int32_t SBC_Multiply_32_16_Simplified(int32_t s32In2Temp,int32_t s32In1Temp);
+#endif
+#endif
+
diff --git a/bt/embdrv/sbc/encoder/include/sbc_encoder.h b/bt/embdrv/sbc/encoder/include/sbc_encoder.h
new file mode 100644
index 0000000..41ba0c1
--- /dev/null
+++ b/bt/embdrv/sbc/encoder/include/sbc_encoder.h
@@ -0,0 +1,192 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 constants and structures used by Encoder.
+ *
+ ******************************************************************************/
+
+#ifndef SBC_ENCODER_H
+#define SBC_ENCODER_H
+
+#define ENCODER_VERSION "0025"
+
+#ifdef BUILDCFG
+    #include "bt_target.h"
+#endif
+
+/*DEFINES*/
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+#define SBC_MAX_NUM_OF_SUBBANDS 8
+#define SBC_MAX_NUM_OF_CHANNELS 2
+#define SBC_MAX_NUM_OF_BLOCKS   16
+
+#define SBC_LOUDNESS    0
+#define SBC_SNR 1
+
+#define SUB_BANDS_8 8
+#define SUB_BANDS_4 4
+
+#define SBC_sf16000 0
+#define SBC_sf32000 1
+#define SBC_sf44100 2
+#define SBC_sf48000 3
+
+#define SBC_MONO    0
+#define SBC_DUAL    1
+#define SBC_STEREO  2
+#define SBC_JOINT_STEREO    3
+
+#define SBC_BLOCK_0 4
+#define SBC_BLOCK_1 8
+#define SBC_BLOCK_2 12
+#define SBC_BLOCK_3 16
+
+#define SBC_NULL    0
+
+#ifndef SBC_MAX_NUM_FRAME
+#define SBC_MAX_NUM_FRAME 1
+#endif
+
+#ifndef SBC_DSP_OPT
+#define SBC_DSP_OPT FALSE
+#endif
+
+/* Set SBC_USE_ARM_PRAGMA to TRUE to use "#pragma arm section zidata" */
+#ifndef SBC_USE_ARM_PRAGMA
+#define SBC_USE_ARM_PRAGMA FALSE
+#endif
+
+/* Set SBC_ARM_ASM_OPT to TRUE in case the target is an ARM */
+/* this will replace all the 32 and 64 bit mult by in line assembly code */
+#ifndef SBC_ARM_ASM_OPT
+#define SBC_ARM_ASM_OPT FALSE
+#endif
+
+/* green hill compiler option -> Used to distinguish the syntax for inline assembly code*/
+#ifndef SBC_GHS_COMPILER
+#define SBC_GHS_COMPILER FALSE
+#endif
+
+/* ARM compiler option -> Used to distinguish the syntax for inline assembly code */
+#ifndef SBC_ARM_COMPILER
+#define SBC_ARM_COMPILER TRUE
+#endif
+
+/* Set SBC_IPAQ_OPT to TRUE in case the target is an ARM */
+/* 32 and 64 bit mult will be performed using int64_t ( usualy __int64 ) cast that usualy give optimal performance if supported */
+#ifndef SBC_IPAQ_OPT
+#define SBC_IPAQ_OPT TRUE
+#endif
+
+/* Debug only: set SBC_IS_64_MULT_IN_WINDOW_ACCU to TRUE to use 64 bit multiplication in the windowing */
+/* -> not recomended, more MIPS for the same restitution.  */
+#ifndef SBC_IS_64_MULT_IN_WINDOW_ACCU
+#define SBC_IS_64_MULT_IN_WINDOW_ACCU  FALSE
+#endif /*SBC_IS_64_MULT_IN_WINDOW_ACCU */
+
+/* Set SBC_IS_64_MULT_IN_IDCT to TRUE to use 64 bits multiplication in the DCT of Matrixing */
+/* -> more MIPS required for a better audio quality. comparasion with the SIG utilities shows a division by 10 of the RMS */
+/* CAUTION: It only apply in the if SBC_FAST_DCT is set to TRUE */
+#ifndef SBC_IS_64_MULT_IN_IDCT
+#define SBC_IS_64_MULT_IN_IDCT  FALSE
+#endif /*SBC_IS_64_MULT_IN_IDCT */
+
+/* set SBC_IS_64_MULT_IN_QUANTIZER to TRUE to use 64 bits multiplication in the quantizer */
+/* setting this flag to FALSE add whistling noise at 5.5 and 11 KHz usualy not perceptible by human's hears. */
+#ifndef SBC_IS_64_MULT_IN_QUANTIZER
+#define SBC_IS_64_MULT_IN_QUANTIZER  TRUE
+#endif /*SBC_IS_64_MULT_IN_IDCT */
+
+/* Debug only: set this flag to FALSE to disable fast DCT algorithm */
+#ifndef SBC_FAST_DCT
+#define SBC_FAST_DCT  TRUE
+#endif /*SBC_FAST_DCT */
+
+/* In case we do not use joint stereo mode the flag save some RAM and ROM in case it is set to FALSE */
+#ifndef SBC_JOINT_STE_INCLUDED
+#define SBC_JOINT_STE_INCLUDED TRUE
+#endif
+
+#define MINIMUM_ENC_VX_BUFFER_SIZE (8*10*2)
+#ifndef ENC_VX_BUFFER_SIZE
+#define ENC_VX_BUFFER_SIZE (MINIMUM_ENC_VX_BUFFER_SIZE + 64)
+/*#define ENC_VX_BUFFER_SIZE MINIMUM_ENC_VX_BUFFER_SIZE + 1024*/
+#endif
+
+#ifndef SBC_FOR_EMBEDDED_LINUX
+#define SBC_FOR_EMBEDDED_LINUX FALSE
+#endif
+
+/*constants used for index calculation*/
+#define SBC_BLK (SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS)
+
+#define SBC_MAX_PCM_BUFFER_SIZE (SBC_MAX_NUM_FRAME*SBC_MAX_NUM_OF_BLOCKS * SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS)
+
+#include "sbc_types.h"
+
+typedef struct SBC_ENC_PARAMS_TAG
+{
+    int16_t s16SamplingFreq;                         /* 16k, 32k, 44.1k or 48k*/
+    int16_t s16ChannelMode;                          /* mono, dual, streo or joint streo*/
+    int16_t s16NumOfSubBands;                        /* 4 or 8 */
+    int16_t s16NumOfChannels;
+    int16_t s16NumOfBlocks;                          /* 4, 8, 12 or 16*/
+    int16_t s16AllocationMethod;                     /* loudness or SNR*/
+    int16_t s16BitPool;                              /* 16*numOfSb for mono & dual;
+                                                       32*numOfSb for stereo & joint stereo */
+    uint16_t u16BitRate;
+#if (SBC_JOINT_STE_INCLUDED == TRUE)
+    int16_t as16Join[SBC_MAX_NUM_OF_SUBBANDS];       /*1 if JS, 0 otherwise*/
+#endif
+
+    int16_t s16MaxBitNeed;
+    int16_t as16ScaleFactor[SBC_MAX_NUM_OF_CHANNELS*SBC_MAX_NUM_OF_SUBBANDS];
+
+    int16_t  s16ScartchMemForBitAlloc[16];
+
+    int32_t  s32SbBuffer[SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS * SBC_MAX_NUM_OF_BLOCKS];
+
+    int16_t as16Bits[SBC_MAX_NUM_OF_CHANNELS*SBC_MAX_NUM_OF_SUBBANDS];
+
+    uint16_t FrameHeader;
+
+}SBC_ENC_PARAMS;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Encode the frame using SBC. The output is written into |output|. Return number of
+ * bytes written. */
+extern uint32_t SBC_Encode(SBC_ENC_PARAMS *strEncParams, int16_t *input, uint8_t *output);
+extern void SBC_Encoder_Init(SBC_ENC_PARAMS *strEncParams);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SBC_ENCODER_H */
diff --git a/bt/embdrv/sbc/encoder/include/sbc_if.h b/bt/embdrv/sbc/encoder/include/sbc_if.h
new file mode 100644
index 0000000..de8dd48
--- /dev/null
+++ b/bt/embdrv/sbc/encoder/include/sbc_if.h
@@ -0,0 +1,47 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+
+#ifndef _SBC_IF_H
+#define _SBC_IF_H
+
+#define PCM_BUFFER_SIZE 512
+
+/*
+ SBC_Init - called once for each track played
+
+ pcm_sample_freq - 4000 to 48000
+ channels - 1 mono 2 stereo
+ bits_per_sample - 8 or 16
+ return - 0 sucess
+*/
+
+int SBC_init(int pcm_sample_freq, int channels, int bits_per_sample);
+
+/*
+ SBC_write - called repeatedly with pcm_in pointer
+	increasing by length until track is finished.
+
+ pcm_in - pointer to PCM buffer
+ length - any
+ sbc_out - pointer to SBC output buffer
+ return - number of bytes written to sbc_out
+*/
+
+int SBC_write(unsigned char *pcm_in, int length, unsigned char *sbc_out);
+
+#endif
diff --git a/bt/embdrv/sbc/encoder/include/sbc_types.h b/bt/embdrv/sbc/encoder/include/sbc_types.h
new file mode 100644
index 0000000..f16a22b
--- /dev/null
+++ b/bt/embdrv/sbc/encoder/include/sbc_types.h
@@ -0,0 +1,38 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Data type declarations.
+ *
+ ******************************************************************************/
+
+#ifndef SBC_TYPES_H
+#define SBC_TYPES_H
+
+#include <stdint.h>
+
+#ifdef BUILDCFG
+#include "bt_target.h"
+#endif
+
+#include "bt_types.h"
+
+#define abs32(x) ( ((x) >= 0) ? (x) : (-(x)) )
+
+#endif
diff --git a/bt/embdrv/sbc/encoder/srce/sbc_analysis.c b/bt/embdrv/sbc/encoder/srce/sbc_analysis.c
new file mode 100644
index 0000000..e47c4b9
--- /dev/null
+++ b/bt/embdrv/sbc/encoder/srce/sbc_analysis.c
@@ -0,0 +1,1107 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 code that performs Analysis of the input audio
+ *  stream.
+ *
+ ******************************************************************************/
+#include <string.h>
+#include "sbc_encoder.h"
+#include "sbc_enc_func_declare.h"
+/*#include <math.h>*/
+
+#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE)
+#define WIND_4_SUBBANDS_0_1 (int32_t)0x01659F45  /* gas32CoeffFor4SBs[8] = -gas32CoeffFor4SBs[32] = 0x01659F45 */
+#define WIND_4_SUBBANDS_0_2 (int32_t)0x115B1ED2  /* gas32CoeffFor4SBs[16] = -gas32CoeffFor4SBs[24] = 0x115B1ED2 */
+#define WIND_4_SUBBANDS_1_0 (int32_t)0x001194E6  /* gas32CoeffFor4SBs[1 et 39] = 0x001194E6 */
+#define WIND_4_SUBBANDS_1_1 (int32_t)0x029DBAA3  /* gas32CoeffFor4SBs[9 et 31] = 0x029DBAA3 */
+#define WIND_4_SUBBANDS_1_2 (int32_t)0x18F55C90  /* gas32CoeffFor4SBs[17 et 23] = 0x18F55C90 */
+#define WIND_4_SUBBANDS_1_3 (int32_t)0xF60FAF37  /* gas32CoeffFor4SBs[15 et 25] = 0xF60FAF37 */
+#define WIND_4_SUBBANDS_1_4 (int32_t)0xFF9BB9D5  /* gas32CoeffFor4SBs[7 et 33] = 0xFF9BB9D5 */
+#define WIND_4_SUBBANDS_2_0 (int32_t)0x0030E2D3  /* gas32CoeffFor4SBs[2 et 38] = 0x0030E2D3 */
+#define WIND_4_SUBBANDS_2_1 (int32_t)0x03B23341  /* gas32CoeffFor4SBs[10 et 30] = 0x03B23341 */
+#define WIND_4_SUBBANDS_2_2 (int32_t)0x1F91CA46  /* gas32CoeffFor4SBs[18 et 22] = 0x1F91CA46 */
+#define WIND_4_SUBBANDS_2_3 (int32_t)0xFC4F91D4  /* gas32CoeffFor4SBs[14 et 26] = 0xFC4F91D4 */
+#define WIND_4_SUBBANDS_2_4 (int32_t)0x003D239B  /* gas32CoeffFor4SBs[6 et 34] = 0x003D239B */
+#define WIND_4_SUBBANDS_3_0 (int32_t)0x00599403  /* gas32CoeffFor4SBs[3 et 37] = 0x00599403 */
+#define WIND_4_SUBBANDS_3_1 (int32_t)0x041EEE40  /* gas32CoeffFor4SBs[11 et 29] = 0x041EEE40 */
+#define WIND_4_SUBBANDS_3_2 (int32_t)0x2412F251  /* gas32CoeffFor4SBs[19 et 21] = 0x2412F251 */
+#define WIND_4_SUBBANDS_3_3 (int32_t)0x00C8F2BC  /* gas32CoeffFor4SBs[13 et 27] = 0x00C8F2BC */
+#define WIND_4_SUBBANDS_3_4 (int32_t)0x007F88E4  /* gas32CoeffFor4SBs[5 et 35] = 0x007F88E4 */
+#define WIND_4_SUBBANDS_4_0 (int32_t)0x007DBCC8  /* gas32CoeffFor4SBs[4 et 36] = 0x007DBCC8 */
+#define WIND_4_SUBBANDS_4_1 (int32_t)0x034FEE2C  /* gas32CoeffFor4SBs[12 et 28] = 0x034FEE2C */
+#define WIND_4_SUBBANDS_4_2 (int32_t)0x25AC1FF2  /* gas32CoeffFor4SBs[20] = 0x25AC1FF2 */
+
+#define WIND_8_SUBBANDS_0_1 (int32_t)0x00B97348  /* 16 0x00B97348 */
+#define WIND_8_SUBBANDS_0_2 (int32_t)0x08B4307A  /* 32 0x08B4307A */
+#define WIND_8_SUBBANDS_1_0 (int32_t)0x00052173  /* 1 et 79 = 0x00052173 */
+#define WIND_8_SUBBANDS_1_1 (int32_t)0x01071B96  /* 17 et 63 = 0x01071B96 */
+#define WIND_8_SUBBANDS_1_2 (int32_t)0x0A9F3E9A  /* 33 et 47 = 0x0A9F3E9A*/
+#define WIND_8_SUBBANDS_1_3 (int32_t)0xF9312891  /* 31 et 49 = 0xF9312891 */
+#define WIND_8_SUBBANDS_1_4 (int32_t)0xFF8D6793  /* 15 et 65 = 0xFF8D6793 */
+#define WIND_8_SUBBANDS_2_0 (int32_t)0x000B3F71  /* 2 et 78 = 0x000B3F71 */
+#define WIND_8_SUBBANDS_2_1 (int32_t)0x0156B3CA  /* 18 et 62 = 0x0156B3CA */
+#define WIND_8_SUBBANDS_2_2 (int32_t)0x0C7D59B6  /* 34 et 46 = 0x0C7D59B6 */
+#define WIND_8_SUBBANDS_2_3 (int32_t)0xFAFF95FC  /* 30 et 50 = 0xFAFF95FC */
+#define WIND_8_SUBBANDS_2_4 (int32_t)0xFFC9F10E  /* 14 et 66 = 0xFFC9F10E */
+#define WIND_8_SUBBANDS_3_0 (int32_t)0x00122C7D  /* 3 et 77 = 0x00122C7D*/
+#define WIND_8_SUBBANDS_3_1 (int32_t)0x01A1B38B  /* 19 et 61 = 0x01A1B38B */
+#define WIND_8_SUBBANDS_3_2 (int32_t)0x0E3BB16F  /* 35 et 45 = 0x0E3BB16F */
+#define WIND_8_SUBBANDS_3_3 (int32_t)0xFCA86E7E  /* 29 et 51 = 0xFCA86E7E */
+#define WIND_8_SUBBANDS_3_4 (int32_t)0xFFFA2413  /* 13 et 67 = 0xFFFA2413 */
+#define WIND_8_SUBBANDS_4_0 (int32_t)0x001AFF89  /* 4 et 66 = 0x001AFF89 */
+#define WIND_8_SUBBANDS_4_1 (int32_t)0x01E0224C  /* 20 et 60 = 0x01E0224C */
+#define WIND_8_SUBBANDS_4_2 (int32_t)0x0FC721F9  /* 36 et 44 = 0x0FC721F9 */
+#define WIND_8_SUBBANDS_4_3 (int32_t)0xFE20435D  /* 28 et 52 = 0xFE20435D */
+#define WIND_8_SUBBANDS_4_4 (int32_t)0x001D8FD2  /* 12 et 68 = 0x001D8FD2 */
+#define WIND_8_SUBBANDS_5_0 (int32_t)0x00255A62  /* 5 et 75 = 0x00255A62 */
+#define WIND_8_SUBBANDS_5_1 (int32_t)0x0209291F  /* 21 et 59 = 0x0209291F */
+#define WIND_8_SUBBANDS_5_2 (int32_t)0x110ECEF0  /* 37 et 43 = 0x110ECEF0 */
+#define WIND_8_SUBBANDS_5_3 (int32_t)0xFF5EEB73  /* 27 et  53 = 0xFF5EEB73 */
+#define WIND_8_SUBBANDS_5_4 (int32_t)0x0034F8B6  /* 11 et 69 = 0x0034F8B6 */
+#define WIND_8_SUBBANDS_6_0 (int32_t)0x003060F4  /* 6 et 74 = 0x003060F4 */
+#define WIND_8_SUBBANDS_6_1 (int32_t)0x02138653  /* 22 et 58 = 0x02138653 */
+#define WIND_8_SUBBANDS_6_2 (int32_t)0x120435FA  /* 38 et 42 = 0x120435FA */
+#define WIND_8_SUBBANDS_6_3 (int32_t)0x005FD0FF  /* 26 et 54 = 0x005FD0FF */
+#define WIND_8_SUBBANDS_6_4 (int32_t)0x00415B75  /* 10 et 70 = 0x00415B75 */
+#define WIND_8_SUBBANDS_7_0 (int32_t)0x003A72E7  /* 7 et 73 = 0x003A72E7 */
+#define WIND_8_SUBBANDS_7_1 (int32_t)0x01F5F424  /* 23 et 57 = 0x01F5F424 */
+#define WIND_8_SUBBANDS_7_2 (int32_t)0x129C226F  /* 39 et 41 = 0x129C226F */
+#define WIND_8_SUBBANDS_7_3 (int32_t)0x01223EBA  /* 25 et 55 = 0x01223EBA */
+#define WIND_8_SUBBANDS_7_4 (int32_t)0x0044EF48  /* 9 et 71 = 0x0044EF48 */
+#define WIND_8_SUBBANDS_8_0 (int32_t)0x0041EC6A  /* 8 et 72 = 0x0041EC6A */
+#define WIND_8_SUBBANDS_8_1 (int32_t)0x01A7ECEF  /* 24 et 56 = 0x01A7ECEF */
+#define WIND_8_SUBBANDS_8_2 (int32_t)0x12CF6C75  /* 40 = 0x12CF6C75 */
+#else
+#define WIND_4_SUBBANDS_0_1 (int16_t)0x0166  /* gas32CoeffFor4SBs[8] = -gas32CoeffFor4SBs[32] = 0x01659F45 */
+#define WIND_4_SUBBANDS_0_2 (int16_t)0x115B  /* gas32CoeffFor4SBs[16] = -gas32CoeffFor4SBs[24] = 0x115B1ED2 */
+#define WIND_4_SUBBANDS_1_0 (int16_t)0x0012  /* gas32CoeffFor4SBs[1 et 39] = 0x001194E6 */
+#define WIND_4_SUBBANDS_1_1 (int16_t)0x029E  /* gas32CoeffFor4SBs[9 et 31] = 0x029DBAA3 */
+#define WIND_4_SUBBANDS_1_2 (int16_t)0x18F5  /* gas32CoeffFor4SBs[17 et 23] = 0x18F55C90 */
+#define WIND_4_SUBBANDS_1_3 (int16_t)0xF610  /* gas32CoeffFor4SBs[15 et 25] = 0xF60FAF37 */
+#define WIND_4_SUBBANDS_1_4 (int16_t)0xFF9C  /* gas32CoeffFor4SBs[7 et 33] = 0xFF9BB9D5 */
+#define WIND_4_SUBBANDS_2_0 (int16_t)0x0031  /* gas32CoeffFor4SBs[2 et 38] = 0x0030E2D3 */
+#define WIND_4_SUBBANDS_2_1 (int16_t)0x03B2  /* gas32CoeffFor4SBs[10 et 30] = 0x03B23341 */
+#define WIND_4_SUBBANDS_2_2 (int16_t)0x1F91  /* gas32CoeffFor4SBs[18 et 22] = 0x1F91CA46 */
+#define WIND_4_SUBBANDS_2_3 (int16_t)0xFC50  /* gas32CoeffFor4SBs[14 et 26] = 0xFC4F91D4 */
+#define WIND_4_SUBBANDS_2_4 (int16_t)0x003D  /* gas32CoeffFor4SBs[6 et 34] = 0x003D239B */
+#define WIND_4_SUBBANDS_3_0 (int16_t)0x005A  /* gas32CoeffFor4SBs[3 et 37] = 0x00599403 */
+#define WIND_4_SUBBANDS_3_1 (int16_t)0x041F  /* gas32CoeffFor4SBs[11 et 29] = 0x041EEE40 */
+#define WIND_4_SUBBANDS_3_2 (int16_t)0x2413  /* gas32CoeffFor4SBs[19 et 21] = 0x2412F251 */
+#define WIND_4_SUBBANDS_3_3 (int16_t)0x00C9  /* gas32CoeffFor4SBs[13 et 27] = 0x00C8F2BC */
+#define WIND_4_SUBBANDS_3_4 (int16_t)0x0080  /* gas32CoeffFor4SBs[5 et 35] = 0x007F88E4 */
+#define WIND_4_SUBBANDS_4_0 (int16_t)0x007E  /* gas32CoeffFor4SBs[4 et 36] = 0x007DBCC8 */
+#define WIND_4_SUBBANDS_4_1 (int16_t)0x0350  /* gas32CoeffFor4SBs[12 et 28] = 0x034FEE2C */
+#define WIND_4_SUBBANDS_4_2 (int16_t)0x25AC  /* gas32CoeffFor4SBs[20] = 25AC1FF2 */
+
+#define WIND_8_SUBBANDS_0_1 (int16_t)0x00B9  /* 16 0x12CF6C75 */
+#define WIND_8_SUBBANDS_0_2 (int16_t)0x08B4  /* 32 0x08B4307A */
+#define WIND_8_SUBBANDS_1_0 (int16_t)0x0005  /* 1 et 79 = 0x00052173 */
+#define WIND_8_SUBBANDS_1_1 (int16_t)0x0107  /* 17 et 63 = 0x01071B96 */
+#define WIND_8_SUBBANDS_1_2 (int16_t)0x0A9F  /* 33 et 47 = 0x0A9F3E9A*/
+#define WIND_8_SUBBANDS_1_3 (int16_t)0xF931  /* 31 et 49 = 0xF9312891 */
+#define WIND_8_SUBBANDS_1_4 (int16_t)0xFF8D  /* 15 et 65 = 0xFF8D6793 */
+#define WIND_8_SUBBANDS_2_0 (int16_t)0x000B  /* 2 et 78 = 0x000B3F71 */
+#define WIND_8_SUBBANDS_2_1 (int16_t)0x0157  /* 18 et 62 = 0x0156B3CA */
+#define WIND_8_SUBBANDS_2_2 (int16_t)0x0C7D  /* 34 et 46 = 0x0C7D59B6 */
+#define WIND_8_SUBBANDS_2_3 (int16_t)0xFB00  /* 30 et 50 = 0xFAFF95FC */
+#define WIND_8_SUBBANDS_2_4 (int16_t)0xFFCA  /* 14 et 66 = 0xFFC9F10E */
+#define WIND_8_SUBBANDS_3_0 (int16_t)0x0012  /* 3 et 77 = 0x00122C7D*/
+#define WIND_8_SUBBANDS_3_1 (int16_t)0x01A2  /* 19 et 61 = 0x01A1B38B */
+#define WIND_8_SUBBANDS_3_2 (int16_t)0x0E3C  /* 35 et 45 = 0x0E3BB16F */
+#define WIND_8_SUBBANDS_3_3 (int16_t)0xFCA8  /* 29 et 51 = 0xFCA86E7E */
+#define WIND_8_SUBBANDS_3_4 (int16_t)0xFFFA  /* 13 et 67 = 0xFFFA2413 */
+#define WIND_8_SUBBANDS_4_0 (int16_t)0x001B  /* 4 et 66 = 0x001AFF89 */
+#define WIND_8_SUBBANDS_4_1 (int16_t)0x01E0  /* 20 et 60 = 0x01E0224C */
+#define WIND_8_SUBBANDS_4_2 (int16_t)0x0FC7  /* 36 et 44 = 0x0FC721F9 */
+#define WIND_8_SUBBANDS_4_3 (int16_t)0xFE20  /* 28 et 52 = 0xFE20435D */
+#define WIND_8_SUBBANDS_4_4 (int16_t)0x001E  /* 12 et 68 = 0x001D8FD2 */
+#define WIND_8_SUBBANDS_5_0 (int16_t)0x0025  /* 5 et 75 = 0x00255A62 */
+#define WIND_8_SUBBANDS_5_1 (int16_t)0x0209  /* 21 et 59 = 0x0209291F */
+#define WIND_8_SUBBANDS_5_2 (int16_t)0x110F  /* 37 et 43 = 0x110ECEF0 */
+#define WIND_8_SUBBANDS_5_3 (int16_t)0xFF5F  /* 27 et  53 = 0xFF5EEB73 */
+#define WIND_8_SUBBANDS_5_4 (int16_t)0x0035  /* 11 et 69 = 0x0034F8B6 */
+#define WIND_8_SUBBANDS_6_0 (int16_t)0x0030  /* 6 et 74 = 0x003060F4 */
+#define WIND_8_SUBBANDS_6_1 (int16_t)0x0214  /* 22 et 58 = 0x02138653 */
+#define WIND_8_SUBBANDS_6_2 (int16_t)0x1204  /* 38 et 42 = 0x120435FA */
+#define WIND_8_SUBBANDS_6_3 (int16_t)0x0060  /* 26 et 54 = 0x005FD0FF */
+#define WIND_8_SUBBANDS_6_4 (int16_t)0x0041  /* 10 et 70 = 0x00415B75 */
+#define WIND_8_SUBBANDS_7_0 (int16_t)0x003A  /* 7 et 73 = 0x003A72E7 */
+#define WIND_8_SUBBANDS_7_1 (int16_t)0x01F6  /* 23 et 57 = 0x01F5F424 */
+#define WIND_8_SUBBANDS_7_2 (int16_t)0x129C  /* 39 et 41 = 0x129C226F */
+#define WIND_8_SUBBANDS_7_3 (int16_t)0x0122  /* 25 et 55 = 0x01223EBA */
+#define WIND_8_SUBBANDS_7_4 (int16_t)0x0045  /* 9 et 71 = 0x0044EF48 */
+#define WIND_8_SUBBANDS_8_0 (int16_t)0x0042  /* 8 et 72 = 0x0041EC6A */
+#define WIND_8_SUBBANDS_8_1 (int16_t)0x01A8  /* 24 et 56 = 0x01A7ECEF */
+#define WIND_8_SUBBANDS_8_2 (int16_t)0x12CF  /* 40 = 0x12CF6C75 */
+#endif
+
+#if (SBC_USE_ARM_PRAGMA == TRUE)
+#pragma arm section zidata = "sbc_s32_analysis_section"
+#endif
+static int32_t   s32DCTY[16]  = {0};
+static int32_t   s32X[ENC_VX_BUFFER_SIZE/2];
+static int16_t   *s16X=(int16_t*) s32X;      /* s16X must be 32 bits aligned cf  SHIFTUP_X8_2*/
+#if (SBC_USE_ARM_PRAGMA == TRUE)
+#pragma arm section zidata
+#endif
+
+/* This macro is for 4 subbands */
+#define SHIFTUP_X4                                                               \
+{                                                                                   \
+    ps32X=(int32_t *)(s16X+EncMaxShiftCounter+38);                                 \
+    for (i=0;i<9;i++)                                                               \
+    {                                                                               \
+        *ps32X=*(ps32X-2-(ShiftCounter>>1));  ps32X--;                                 \
+        *ps32X=*(ps32X-2-(ShiftCounter>>1));  ps32X--;                                 \
+    }                                                                               \
+}
+#define SHIFTUP_X4_2                                                              \
+{                                                                                   \
+    ps32X=(int32_t *)(s16X+EncMaxShiftCounter+38);                                   \
+    ps32X2=(int32_t *)(s16X+(EncMaxShiftCounter<<1)+78);                             \
+    for (i=0;i<9;i++)                                                               \
+    {                                                                               \
+        *ps32X=*(ps32X-2-(ShiftCounter>>1));  *(ps32X2)=*(ps32X2-2-(ShiftCounter>>1)); ps32X--;  ps32X2--;                     \
+        *ps32X=*(ps32X-2-(ShiftCounter>>1));  *(ps32X2)=*(ps32X2-2-(ShiftCounter>>1)); ps32X--;  ps32X2--;                     \
+    }                                                                               \
+}
+
+/* This macro is for 8 subbands */
+#define SHIFTUP_X8                                                               \
+{                                                                                   \
+    ps32X=(int32_t *)(s16X+EncMaxShiftCounter+78);                                 \
+    for (i=0;i<9;i++)                                                               \
+    {                                                                               \
+        *ps32X=*(ps32X-4-(ShiftCounter>>1));  ps32X--;                                 \
+        *ps32X=*(ps32X-4-(ShiftCounter>>1));  ps32X--;                                 \
+        *ps32X=*(ps32X-4-(ShiftCounter>>1));  ps32X--;                                 \
+        *ps32X=*(ps32X-4-(ShiftCounter>>1));  ps32X--;                                 \
+    }                                                                               \
+}
+#define SHIFTUP_X8_2                                                               \
+{                                                                                   \
+    ps32X=(int32_t *)(s16X+EncMaxShiftCounter+78);                                   \
+    ps32X2=(int32_t *)(s16X+(EncMaxShiftCounter<<1)+158);                             \
+    for (i=0;i<9;i++)                                                               \
+    {                                                                               \
+        *ps32X=*(ps32X-4-(ShiftCounter>>1));  *(ps32X2)=*(ps32X2-4-(ShiftCounter>>1)); ps32X--;  ps32X2--;                     \
+        *ps32X=*(ps32X-4-(ShiftCounter>>1));  *(ps32X2)=*(ps32X2-4-(ShiftCounter>>1)); ps32X--;  ps32X2--;                     \
+        *ps32X=*(ps32X-4-(ShiftCounter>>1));  *(ps32X2)=*(ps32X2-4-(ShiftCounter>>1)); ps32X--;  ps32X2--;                     \
+        *ps32X=*(ps32X-4-(ShiftCounter>>1));  *(ps32X2)=*(ps32X2-4-(ShiftCounter>>1)); ps32X--;  ps32X2--;                     \
+    }                                                                               \
+}
+
+#if (SBC_ARM_ASM_OPT == TRUE)
+#define WINDOW_ACCU_8_0 \
+{\
+    __asm\
+    {\
+        MUL s32Hi,WIND_8_SUBBANDS_0_1,(s16X[ChOffset+16]-s16X[ChOffset+64]);\
+        MLA s32Hi,WIND_8_SUBBANDS_0_2,(s16X[ChOffset+32]-s16X[ChOffset+48]),s32Hi;\
+        MOV s32DCTY[0],s32Hi;\
+    }\
+}
+#define WINDOW_ACCU_8_1_15 \
+{\
+    __asm\
+    {\
+        MUL s32Hi,WIND_8_SUBBANDS_1_0,s16X[ChOffset+1];\
+        MUL s32Hi2,WIND_8_SUBBANDS_1_0,s16X[ChOffset+64+15];\
+        MLA s32Hi,WIND_8_SUBBANDS_1_1,s16X[ChOffset+16+1],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_1_1,s16X[ChOffset+48+15],s32Hi2;\
+        MLA s32Hi,WIND_8_SUBBANDS_1_2,s16X[ChOffset+32+1],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_1_2,s16X[ChOffset+32+15],s32Hi2;\
+        MLA s32Hi,WIND_8_SUBBANDS_1_3,s16X[ChOffset+48+1],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_1_3,s16X[ChOffset+16+15],s32Hi2;\
+        MLA s32Hi,WIND_8_SUBBANDS_1_4,s16X[ChOffset+64+1],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_1_4,s16X[ChOffset+15],s32Hi2;\
+        MOV s32DCTY[1],s32Hi;\
+        MOV s32DCTY[15],s32Hi2;\
+    }\
+}
+#define WINDOW_ACCU_8_2_14 \
+{\
+    __asm\
+    {\
+        MUL s32Hi,WIND_8_SUBBANDS_2_0,s16X[ChOffset+2];\
+        MUL s32Hi2,WIND_8_SUBBANDS_2_0,s16X[ChOffset+64+14];\
+        MLA s32Hi,WIND_8_SUBBANDS_2_1,s16X[ChOffset+16+2],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_2_1,s16X[ChOffset+48+14],s32Hi2;\
+        MLA s32Hi,WIND_8_SUBBANDS_2_2,s16X[ChOffset+32+2],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_2_2,s16X[ChOffset+32+14],s32Hi2;\
+        MLA s32Hi,WIND_8_SUBBANDS_2_3,s16X[ChOffset+48+2],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_2_3,s16X[ChOffset+16+14],s32Hi2;\
+        MLA s32Hi,WIND_8_SUBBANDS_2_4,s16X[ChOffset+64+2],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_2_4,s16X[ChOffset+14],s32Hi2;\
+        MOV s32DCTY[2],s32Hi;\
+        MOV s32DCTY[14],s32Hi2;\
+    }\
+}
+#define WINDOW_ACCU_8_3_13 \
+{\
+    __asm\
+    {\
+        MUL s32Hi,WIND_8_SUBBANDS_3_0,s16X[ChOffset+3];\
+        MUL s32Hi2,WIND_8_SUBBANDS_3_0,s16X[ChOffset+64+13];\
+        MLA s32Hi,WIND_8_SUBBANDS_3_1,s16X[ChOffset+16+3],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_3_1,s16X[ChOffset+48+13],s32Hi2;\
+        MLA s32Hi,WIND_8_SUBBANDS_3_2,s16X[ChOffset+32+3],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_3_2,s16X[ChOffset+32+13],s32Hi2;\
+        MLA s32Hi,WIND_8_SUBBANDS_3_3,s16X[ChOffset+48+3],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_3_3,s16X[ChOffset+16+13],s32Hi2;\
+        MLA s32Hi,WIND_8_SUBBANDS_3_4,s16X[ChOffset+64+3],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_3_4,s16X[ChOffset+13],s32Hi2;\
+        MOV s32DCTY[3],s32Hi;\
+        MOV s32DCTY[13],s32Hi2;\
+    }\
+}
+#define WINDOW_ACCU_8_4_12 \
+{\
+    __asm\
+    {\
+        MUL s32Hi,WIND_8_SUBBANDS_4_0,s16X[ChOffset+4];\
+        MUL s32Hi2,WIND_8_SUBBANDS_4_0,s16X[ChOffset+64+12];\
+        MLA s32Hi,WIND_8_SUBBANDS_4_1,s16X[ChOffset+16+4],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_4_1,s16X[ChOffset+48+12],s32Hi2;\
+        MLA s32Hi,WIND_8_SUBBANDS_4_2,s16X[ChOffset+32+4],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_4_2,s16X[ChOffset+32+12],s32Hi2;\
+        MLA s32Hi,WIND_8_SUBBANDS_4_3,s16X[ChOffset+48+4],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_4_3,s16X[ChOffset+16+12],s32Hi2;\
+        MLA s32Hi,WIND_8_SUBBANDS_4_4,s16X[ChOffset+64+4],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_4_4,s16X[ChOffset+12],s32Hi2;\
+        MOV s32DCTY[4],s32Hi;\
+        MOV s32DCTY[12],s32Hi2;\
+    }\
+}
+#define WINDOW_ACCU_8_5_11 \
+{\
+    __asm\
+    {\
+        MUL s32Hi,WIND_8_SUBBANDS_5_0,s16X[ChOffset+5];\
+        MUL s32Hi2,WIND_8_SUBBANDS_5_0,s16X[ChOffset+64+11];\
+        MLA s32Hi,WIND_8_SUBBANDS_5_1,s16X[ChOffset+16+5],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_5_1,s16X[ChOffset+48+11],s32Hi2;\
+        MLA s32Hi,WIND_8_SUBBANDS_5_2,s16X[ChOffset+32+5],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_5_2,s16X[ChOffset+32+11],s32Hi2;\
+        MLA s32Hi,WIND_8_SUBBANDS_5_3,s16X[ChOffset+48+5],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_5_3,s16X[ChOffset+16+11],s32Hi2;\
+        MLA s32Hi,WIND_8_SUBBANDS_5_4,s16X[ChOffset+64+5],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_5_4,s16X[ChOffset+11],s32Hi2;\
+        MOV s32DCTY[5],s32Hi;\
+        MOV s32DCTY[11],s32Hi2;\
+    }\
+}
+#define WINDOW_ACCU_8_6_10 \
+{\
+    __asm\
+    {\
+        MUL s32Hi,WIND_8_SUBBANDS_6_0,s16X[ChOffset+6];\
+        MUL s32Hi2,WIND_8_SUBBANDS_6_0,s16X[ChOffset+64+10];\
+        MLA s32Hi,WIND_8_SUBBANDS_6_1,s16X[ChOffset+16+6],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_6_1,s16X[ChOffset+48+10],s32Hi2;\
+        MLA s32Hi,WIND_8_SUBBANDS_6_2,s16X[ChOffset+32+6],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_6_2,s16X[ChOffset+32+10],s32Hi2;\
+        MLA s32Hi,WIND_8_SUBBANDS_6_3,s16X[ChOffset+48+6],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_6_3,s16X[ChOffset+16+10],s32Hi2;\
+        MLA s32Hi,WIND_8_SUBBANDS_6_4,s16X[ChOffset+64+6],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_6_4,s16X[ChOffset+10],s32Hi2;\
+        MOV s32DCTY[6],s32Hi;\
+        MOV s32DCTY[10],s32Hi2;\
+    }\
+}
+#define WINDOW_ACCU_8_7_9 \
+{\
+    __asm\
+    {\
+        MUL s32Hi,WIND_8_SUBBANDS_7_0,s16X[ChOffset+7];\
+        MUL s32Hi2,WIND_8_SUBBANDS_7_0,s16X[ChOffset+64+9];\
+        MLA s32Hi,WIND_8_SUBBANDS_7_1,s16X[ChOffset+16+7],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_7_1,s16X[ChOffset+48+9],s32Hi2;\
+        MLA s32Hi,WIND_8_SUBBANDS_7_2,s16X[ChOffset+32+7],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_7_2,s16X[ChOffset+32+9],s32Hi2;\
+        MLA s32Hi,WIND_8_SUBBANDS_7_3,s16X[ChOffset+48+7],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_7_3,s16X[ChOffset+16+9],s32Hi2;\
+        MLA s32Hi,WIND_8_SUBBANDS_7_4,s16X[ChOffset+64+7],s32Hi;\
+        MLA s32Hi2,WIND_8_SUBBANDS_7_4,s16X[ChOffset+9],s32Hi2;\
+        MOV s32DCTY[7],s32Hi;\
+        MOV s32DCTY[9],s32Hi2;\
+    }\
+}
+#define WINDOW_ACCU_8_8 \
+{\
+    __asm\
+    {\
+        MUL s32Hi,WIND_8_SUBBANDS_8_0,(s16X[ChOffset+8]+s16X[ChOffset+8+64]);\
+        MLA s32Hi,WIND_8_SUBBANDS_8_1,(s16X[ChOffset+8+16]+s16X[ChOffset+8+64]),s32Hi;\
+        MLA s32Hi,WIND_8_SUBBANDS_8_2,s16X[ChOffset+8+32],s32Hi;\
+        MOV s32DCTY[8],s32Hi;\
+    }\
+}
+#define WINDOW_ACCU_4_0 \
+{\
+    __asm\
+    {\
+        MUL s32Hi,WIND_4_SUBBANDS_0_1,(s16X[ChOffset+8]-s16X[ChOffset+32]);\
+        MLA s32Hi,WIND_4_SUBBANDS_0_2,(s16X[ChOffset+16]-s16X[ChOffset+24]),s32Hi;\
+        MOV s32DCTY[0],s32Hi;\
+    }\
+}
+#define WINDOW_ACCU_4_1_7 \
+{\
+    __asm\
+    {\
+        MUL s32Hi,WIND_4_SUBBANDS_1_0,s16X[ChOffset+1];\
+        MUL s32Hi2,WIND_4_SUBBANDS_1_0,s16X[ChOffset+32+7];\
+        MLA s32Hi,WIND_4_SUBBANDS_1_1,s16X[ChOffset+8+1],s32Hi;\
+        MLA s32Hi2,WIND_4_SUBBANDS_1_1,s16X[ChOffset+24+7],s32Hi2;\
+        MLA s32Hi,WIND_4_SUBBANDS_1_2,s16X[ChOffset+16+1],s32Hi;\
+        MLA s32Hi2,WIND_4_SUBBANDS_1_2,s16X[ChOffset+16+7],s32Hi2;\
+        MLA s32Hi,WIND_4_SUBBANDS_1_3,s16X[ChOffset+24+1],s32Hi;\
+        MLA s32Hi2,WIND_4_SUBBANDS_1_3,s16X[ChOffset+8+7],s32Hi2;\
+        MLA s32Hi,WIND_4_SUBBANDS_1_4,s16X[ChOffset+32+1],s32Hi;\
+        MLA s32Hi2,WIND_4_SUBBANDS_1_4,s16X[ChOffset+7],s32Hi2;\
+        MOV s32DCTY[1],s32Hi;\
+        MOV s32DCTY[7],s32Hi2;\
+    }\
+}
+#define WINDOW_ACCU_4_2_6 \
+{\
+    __asm\
+    {\
+        MUL s32Hi,WIND_4_SUBBANDS_2_0,s16X[ChOffset+2];\
+        MUL s32Hi2,WIND_4_SUBBANDS_2_0,s16X[ChOffset+32+6];\
+        MLA s32Hi,WIND_4_SUBBANDS_2_1,s16X[ChOffset+8+2],s32Hi;\
+        MLA s32Hi2,WIND_4_SUBBANDS_2_1,s16X[ChOffset+24+6],s32Hi2;\
+        MLA s32Hi,WIND_4_SUBBANDS_2_2,s16X[ChOffset+16+2],s32Hi;\
+        MLA s32Hi2,WIND_4_SUBBANDS_2_2,s16X[ChOffset+16+6],s32Hi2;\
+        MLA s32Hi,WIND_4_SUBBANDS_2_3,s16X[ChOffset+24+2],s32Hi;\
+        MLA s32Hi2,WIND_4_SUBBANDS_2_3,s16X[ChOffset+8+6],s32Hi2;\
+        MLA s32Hi,WIND_4_SUBBANDS_2_4,s16X[ChOffset+32+2],s32Hi;\
+        MLA s32Hi2,WIND_4_SUBBANDS_2_4,s16X[ChOffset+6],s32Hi2;\
+        MOV s32DCTY[2],s32Hi;\
+        MOV s32DCTY[6],s32Hi2;\
+    }\
+}
+#define WINDOW_ACCU_4_3_5 \
+{\
+    __asm\
+    {\
+        MUL s32Hi,WIND_4_SUBBANDS_3_0,s16X[ChOffset+3];\
+        MUL s32Hi2,WIND_4_SUBBANDS_3_0,s16X[ChOffset+32+5];\
+        MLA s32Hi,WIND_4_SUBBANDS_3_1,s16X[ChOffset+8+3],s32Hi;\
+        MLA s32Hi2,WIND_4_SUBBANDS_3_1,s16X[ChOffset+24+5],s32Hi2;\
+        MLA s32Hi,WIND_4_SUBBANDS_3_2,s16X[ChOffset+16+3],s32Hi;\
+        MLA s32Hi2,WIND_4_SUBBANDS_3_2,s16X[ChOffset+16+5],s32Hi2;\
+        MLA s32Hi,WIND_4_SUBBANDS_3_3,s16X[ChOffset+24+3],s32Hi;\
+        MLA s32Hi2,WIND_4_SUBBANDS_3_3,s16X[ChOffset+8+5],s32Hi2;\
+        MLA s32Hi,WIND_4_SUBBANDS_3_4,s16X[ChOffset+32+3],s32Hi;\
+        MLA s32Hi2,WIND_4_SUBBANDS_3_4,s16X[ChOffset+5],s32Hi2;\
+        MOV s32DCTY[3],s32Hi;\
+        MOV s32DCTY[5],s32Hi2;\
+    }\
+}
+#define WINDOW_ACCU_4_4 \
+{\
+    __asm\
+    {\
+        MUL s32Hi,WIND_4_SUBBANDS_4_0,(s16X[ChOffset+4]+s16X[ChOffset+4+32]);\
+        MLA s32Hi,WIND_4_SUBBANDS_4_1,(s16X[ChOffset+4+8]+s16X[ChOffset+4+24]),s32Hi;\
+        MLA s32Hi,WIND_4_SUBBANDS_4_2,s16X[ChOffset+4+16],s32Hi;\
+        MOV s32DCTY[4],s32Hi;\
+    }\
+}
+
+#define WINDOW_PARTIAL_4 \
+{\
+    WINDOW_ACCU_4_0;     WINDOW_ACCU_4_1_7;\
+    WINDOW_ACCU_4_2_6;   WINDOW_ACCU_4_3_5;\
+    WINDOW_ACCU_4_4;\
+}
+
+#define WINDOW_PARTIAL_8 \
+{\
+    WINDOW_ACCU_8_0;     WINDOW_ACCU_8_1_15;\
+    WINDOW_ACCU_8_2_14;  WINDOW_ACCU_8_3_13;\
+    WINDOW_ACCU_8_4_12;  WINDOW_ACCU_8_5_11;\
+    WINDOW_ACCU_8_6_10;  WINDOW_ACCU_8_7_9;\
+    WINDOW_ACCU_8_8;\
+}
+
+#else
+#if (SBC_IPAQ_OPT == TRUE)
+
+#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE)
+#define WINDOW_ACCU_8_0 \
+{\
+    s64Temp=(int64_t)WIND_8_SUBBANDS_0_1*(int64_t)(s16X[ChOffset+16]-s16X[ChOffset+64]);\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_0_2*(int64_t)(s16X[ChOffset+32]-s16X[ChOffset+48]);\
+    s32DCTY[0]=(int32_t)(s64Temp>>16);\
+}
+#define WINDOW_ACCU_8_1_15 \
+{\
+    s64Temp=(int64_t)WIND_8_SUBBANDS_1_0*(int64_t)s16X[ChOffset+1];\
+    s64Temp2=(int64_t)WIND_8_SUBBANDS_1_0*(int64_t)s16X[ChOffset+64+15];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_1_1*(int64_t)s16X[ChOffset+16+1];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_1_1*(int64_t)s16X[ChOffset+48+15];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_1_2*(int64_t)s16X[ChOffset+32+1];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_1_2*(int64_t)s16X[ChOffset+32+15];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_1_3*(int64_t)s16X[ChOffset+48+1];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_1_3*(int64_t)s16X[ChOffset+16+15];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_1_4*(int64_t)s16X[ChOffset+64+1];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_1_4*(int64_t)s16X[ChOffset+15];\
+    s32DCTY[1]=(int32_t)(s64Temp>>16);\
+    s32DCTY[15]=(int32_t)(s64Temp2>>16);\
+}
+#define WINDOW_ACCU_8_2_14 \
+{\
+    s64Temp=(int64_t)WIND_8_SUBBANDS_2_0*(int64_t)s16X[ChOffset+2];\
+    s64Temp2=(int64_t)WIND_8_SUBBANDS_2_0*(int64_t)s16X[ChOffset+64+14];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_2_1*(int64_t)s16X[ChOffset+16+2];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_2_1*(int64_t)s16X[ChOffset+48+14];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_2_2*(int64_t)s16X[ChOffset+32+2];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_2_2*(int64_t)s16X[ChOffset+32+14];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_2_3*(int64_t)s16X[ChOffset+48+2];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_2_3*(int64_t)s16X[ChOffset+16+14];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_2_4*(int64_t)s16X[ChOffset+64+2];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_2_4*(int64_t)s16X[ChOffset+14];\
+    s32DCTY[2]=(int32_t)(s64Temp>>16);\
+    s32DCTY[14]=(int32_t)(s64Temp2>>16);\
+}
+#define WINDOW_ACCU_8_3_13 \
+{\
+    s64Temp=(int64_t)WIND_8_SUBBANDS_3_0*(int64_t)s16X[ChOffset+3];\
+    s64Temp2=(int64_t)WIND_8_SUBBANDS_3_0*(int64_t)s16X[ChOffset+64+13];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_3_1*(int64_t)s16X[ChOffset+16+3];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_3_1*(int64_t)s16X[ChOffset+48+13];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_3_2*(int64_t)s16X[ChOffset+32+3];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_3_2*(int64_t)s16X[ChOffset+32+13];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_3_3*(int64_t)s16X[ChOffset+48+3];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_3_3*(int64_t)s16X[ChOffset+16+13];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_3_4*(int64_t)s16X[ChOffset+64+3];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_3_4*(int64_t)s16X[ChOffset+13];\
+    s32DCTY[3]=(int32_t)(s64Temp>>16);\
+    s32DCTY[13]=(int32_t)(s64Temp2>>16);\
+}
+#define WINDOW_ACCU_8_4_12 \
+{\
+    s64Temp=(int64_t)WIND_8_SUBBANDS_4_0*(int64_t)s16X[ChOffset+4];\
+    s64Temp2=(int64_t)WIND_8_SUBBANDS_4_0*(int64_t)s16X[ChOffset+64+12];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_4_1*(int64_t)s16X[ChOffset+16+4];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_4_1*(int64_t)s16X[ChOffset+48+12];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_4_2*(int64_t)s16X[ChOffset+32+4];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_4_2*(int64_t)s16X[ChOffset+32+12];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_4_3*(int64_t)s16X[ChOffset+48+4];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_4_3*(int64_t)s16X[ChOffset+16+12];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_4_4*(int64_t)s16X[ChOffset+64+4];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_4_4*(int64_t)s16X[ChOffset+12];\
+    s32DCTY[4]=(int32_t)(s64Temp>>16);\
+    s32DCTY[12]=(int32_t)(s64Temp2>>16);\
+}
+#define WINDOW_ACCU_8_5_11 \
+{\
+    s64Temp=(int64_t)WIND_8_SUBBANDS_5_0*(int64_t)s16X[ChOffset+5];\
+    s64Temp2=(int64_t)WIND_8_SUBBANDS_5_0*(int64_t)s16X[ChOffset+64+11];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_5_1*(int64_t)s16X[ChOffset+16+5];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_5_1*(int64_t)s16X[ChOffset+48+11];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_5_2*(int64_t)s16X[ChOffset+32+5];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_5_2*(int64_t)s16X[ChOffset+32+11];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_5_3*(int64_t)s16X[ChOffset+48+5];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_5_3*(int64_t)s16X[ChOffset+16+11];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_5_4*(int64_t)s16X[ChOffset+64+5];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_5_4*(int64_t)s16X[ChOffset+11];\
+    s32DCTY[5]=(int32_t)(s64Temp>>16);\
+    s32DCTY[11]=(int32_t)(s64Temp2>>16);\
+}
+#define WINDOW_ACCU_8_6_10 \
+{\
+    s64Temp=(int64_t)WIND_8_SUBBANDS_6_0*(int64_t)s16X[ChOffset+6];\
+    s64Temp2=(int64_t)WIND_8_SUBBANDS_6_0*(int64_t)s16X[ChOffset+64+10];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_6_1*(int64_t)s16X[ChOffset+16+6];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_6_1*(int64_t)s16X[ChOffset+48+10];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_6_2*(int64_t)s16X[ChOffset+32+6];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_6_2*(int64_t)s16X[ChOffset+32+10];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_6_3*(int64_t)s16X[ChOffset+48+6];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_6_3*(int64_t)s16X[ChOffset+16+10];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_6_4*(int64_t)s16X[ChOffset+64+6];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_6_4*(int64_t)s16X[ChOffset+10];\
+    s32DCTY[6]=(int32_t)(s64Temp>>16);\
+    s32DCTY[10]=(int32_t)(s64Temp2>>16);\
+}
+#define WINDOW_ACCU_8_7_9 \
+{\
+    s64Temp=(int64_t)WIND_8_SUBBANDS_7_0*(int64_t)s16X[ChOffset+7];\
+    s64Temp2=(int64_t)WIND_8_SUBBANDS_7_0*(int64_t)s16X[ChOffset+64+9];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_7_1*(int64_t)s16X[ChOffset+16+7];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_7_1*(int64_t)s16X[ChOffset+48+9];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_7_2*(int64_t)s16X[ChOffset+32+7];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_7_2*(int64_t)s16X[ChOffset+32+9];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_7_3*(int64_t)s16X[ChOffset+48+7];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_7_3*(int64_t)s16X[ChOffset+16+9];\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_7_4*(int64_t)s16X[ChOffset+64+7];\
+    s64Temp2+=(int64_t)WIND_8_SUBBANDS_7_4*(int64_t)s16X[ChOffset+9];\
+    s32DCTY[7]=(int32_t)(s64Temp>>16);\
+    s32DCTY[9]=(int32_t)(s64Temp2>>16);\
+}
+#define WINDOW_ACCU_8_8 \
+{\
+    s64Temp=(int64_t)WIND_8_SUBBANDS_8_0*(int64_t)(s16X[ChOffset+8]+s16X[ChOffset+64+8]);\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_8_1*(int64_t)(s16X[ChOffset+16+8]+s16X[ChOffset+48+8]);\
+    s64Temp+=(int64_t)WIND_8_SUBBANDS_8_2*(int64_t)s16X[ChOffset+32+8];\
+    s32DCTY[8]=(int32_t)(s64Temp>>16);\
+}
+#define WINDOW_ACCU_4_0 \
+{\
+    s64Temp=(int64_t)WIND_4_SUBBANDS_0_1*(int64_t)(s16X[ChOffset+8]-s16X[ChOffset+32]);\
+    s64Temp+=(int64_t)WIND_4_SUBBANDS_0_2*(int64_t)(s16X[ChOffset+16]-s16X[ChOffset+24]);\
+    s32DCTY[0]=(int32_t)(s64Temp>>16);\
+}
+#define WINDOW_ACCU_4_1_7 \
+{\
+    s64Temp=(int64_t)WIND_4_SUBBANDS_1_0*(int64_t)s16X[ChOffset+1];\
+    s64Temp2=(int64_t)WIND_4_SUBBANDS_1_0*(int64_t)s16X[ChOffset+32+7];\
+    s64Temp+=(int64_t)WIND_4_SUBBANDS_1_1*(int64_t)s16X[ChOffset+8+1];\
+    s64Temp2+=(int64_t)WIND_4_SUBBANDS_1_1*(int64_t)s16X[ChOffset+24+7];\
+    s64Temp+=(int64_t)WIND_4_SUBBANDS_1_2*(int64_t)s16X[ChOffset+16+1];\
+    s64Temp2+=(int64_t)WIND_4_SUBBANDS_1_2*(int64_t)s16X[ChOffset+16+7];\
+    s64Temp+=(int64_t)WIND_4_SUBBANDS_1_3*(int64_t)s16X[ChOffset+24+1];\
+    s64Temp2+=(int64_t)WIND_4_SUBBANDS_1_3*(int64_t)s16X[ChOffset+8+7];\
+    s64Temp+=(int64_t)WIND_4_SUBBANDS_1_4*(int64_t)s16X[ChOffset+32+1];\
+    s64Temp2+=(int64_t)WIND_4_SUBBANDS_1_4*(int64_t)s16X[ChOffset+7];\
+    s32DCTY[1]=(int32_t)(s64Temp>>16);\
+    s32DCTY[7]=(int32_t)(s64Temp2>>16);\
+}
+#define WINDOW_ACCU_4_2_6 \
+{\
+    s64Temp=(int64_t)WIND_4_SUBBANDS_2_0*(int64_t)s16X[ChOffset+2];\
+    s64Temp2=(int64_t)WIND_4_SUBBANDS_2_0*(int64_t)s16X[ChOffset+32+6];\
+    s64Temp+=(int64_t)WIND_4_SUBBANDS_2_1*(int64_t)s16X[ChOffset+8+2];\
+    s64Temp2+=(int64_t)WIND_4_SUBBANDS_2_1*(int64_t)s16X[ChOffset+24+6];\
+    s64Temp+=(int64_t)WIND_4_SUBBANDS_2_2*(int64_t)s16X[ChOffset+16+2];\
+    s64Temp2+=(int64_t)WIND_4_SUBBANDS_2_2*(int64_t)s16X[ChOffset+16+6];\
+    s64Temp+=(int64_t)WIND_4_SUBBANDS_2_3*(int64_t)s16X[ChOffset+24+2];\
+    s64Temp2+=(int64_t)WIND_4_SUBBANDS_2_3*(int64_t)s16X[ChOffset+8+6];\
+    s64Temp+=(int64_t)WIND_4_SUBBANDS_2_4*(int64_t)s16X[ChOffset+32+2];\
+    s64Temp2+=(int64_t)WIND_4_SUBBANDS_2_4*(int64_t)s16X[ChOffset+6];\
+    s32DCTY[2]=(int32_t)(s64Temp>>16);\
+    s32DCTY[6]=(int32_t)(s64Temp2>>16);\
+}
+#define WINDOW_ACCU_4_3_5 \
+{\
+    s64Temp=(int64_t)WIND_4_SUBBANDS_3_0*(int64_t)s16X[ChOffset+3];\
+    s64Temp2=(int64_t)WIND_4_SUBBANDS_3_0*(int64_t)s16X[ChOffset+32+5];\
+    s64Temp+=(int64_t)WIND_4_SUBBANDS_3_1*(int64_t)s16X[ChOffset+8+3];\
+    s64Temp2+=(int64_t)WIND_4_SUBBANDS_3_1*(int64_t)s16X[ChOffset+24+5];\
+    s64Temp+=(int64_t)WIND_4_SUBBANDS_3_2*(int64_t)s16X[ChOffset+16+3];\
+    s64Temp2+=(int64_t)WIND_4_SUBBANDS_3_2*(int64_t)s16X[ChOffset+16+5];\
+    s64Temp+=(int64_t)WIND_4_SUBBANDS_3_3*(int64_t)s16X[ChOffset+24+3];\
+    s64Temp2+=(int64_t)WIND_4_SUBBANDS_3_3*(int64_t)s16X[ChOffset+8+5];\
+    s64Temp+=(int64_t)WIND_4_SUBBANDS_3_4*(int64_t)s16X[ChOffset+32+3];\
+    s64Temp2+=(int64_t)WIND_4_SUBBANDS_3_4*(int64_t)s16X[ChOffset+5];\
+    s32DCTY[3]=(int32_t)(s64Temp>>16);\
+    s32DCTY[5]=(int32_t)(s64Temp2>>16);\
+}
+
+#define WINDOW_ACCU_4_4 \
+{\
+    s64Temp=(int64_t)WIND_4_SUBBANDS_4_0*(int64_t)(s16X[ChOffset+4]+s16X[ChOffset+4+32]);\
+    s64Temp+=(int64_t)WIND_4_SUBBANDS_4_1*(int64_t)(s16X[ChOffset+4+8]+s16X[ChOffset+4+24]);\
+    s64Temp+=(int64_t)WIND_4_SUBBANDS_4_2*(int64_t)s16X[ChOffset+4+16];\
+    s32DCTY[4]=(int32_t)(s64Temp>>16);\
+}
+#else /* SBC_IS_64_MULT_IN_WINDOW_ACCU == FALSE */
+#define WINDOW_ACCU_8_0 \
+{\
+    s32Temp=(int32_t)WIND_8_SUBBANDS_0_1*(int32_t)(s16X[ChOffset+16]-s16X[ChOffset+64]);\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_0_2*(int32_t)(s16X[ChOffset+32]-s16X[ChOffset+48]);\
+    s32DCTY[0]=(int32_t)s32Temp;\
+}
+#define WINDOW_ACCU_8_1_15 \
+{\
+    s32Temp=(int32_t)WIND_8_SUBBANDS_1_0*(int32_t)s16X[ChOffset+1];\
+    s32Temp2=(int32_t)WIND_8_SUBBANDS_1_0*(int32_t)s16X[ChOffset+64+15];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_1_1*(int32_t)s16X[ChOffset+16+1];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_1_1*(int32_t)s16X[ChOffset+48+15];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_1_2*(int32_t)s16X[ChOffset+32+1];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_1_2*(int32_t)s16X[ChOffset+32+15];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_1_3*(int32_t)s16X[ChOffset+48+1];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_1_3*(int32_t)s16X[ChOffset+16+15];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_1_4*(int32_t)s16X[ChOffset+64+1];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_1_4*(int32_t)s16X[ChOffset+15];\
+    s32DCTY[1]=(int32_t)s32Temp;\
+    s32DCTY[15]=(int32_t)s32Temp2;\
+}
+#define WINDOW_ACCU_8_2_14 \
+{\
+    s32Temp=(int32_t)WIND_8_SUBBANDS_2_0*(int32_t)s16X[ChOffset+2];\
+    s32Temp2=(int32_t)WIND_8_SUBBANDS_2_0*(int32_t)s16X[ChOffset+64+14];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_2_1*(int32_t)s16X[ChOffset+16+2];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_2_1*(int32_t)s16X[ChOffset+48+14];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_2_2*(int32_t)s16X[ChOffset+32+2];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_2_2*(int32_t)s16X[ChOffset+32+14];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_2_3*(int32_t)s16X[ChOffset+48+2];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_2_3*(int32_t)s16X[ChOffset+16+14];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_2_4*(int32_t)s16X[ChOffset+64+2];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_2_4*(int32_t)s16X[ChOffset+14];\
+    s32DCTY[2]=(int32_t)s32Temp;\
+    s32DCTY[14]=(int32_t)s32Temp2;\
+}
+#define WINDOW_ACCU_8_3_13 \
+{\
+    s32Temp=(int32_t)WIND_8_SUBBANDS_3_0*(int32_t)s16X[ChOffset+3];\
+    s32Temp2=(int32_t)WIND_8_SUBBANDS_3_0*(int32_t)s16X[ChOffset+64+13];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_3_1*(int32_t)s16X[ChOffset+16+3];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_3_1*(int32_t)s16X[ChOffset+48+13];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_3_2*(int32_t)s16X[ChOffset+32+3];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_3_2*(int32_t)s16X[ChOffset+32+13];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_3_3*(int32_t)s16X[ChOffset+48+3];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_3_3*(int32_t)s16X[ChOffset+16+13];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_3_4*(int32_t)s16X[ChOffset+64+3];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_3_4*(int32_t)s16X[ChOffset+13];\
+    s32DCTY[3]=(int32_t)s32Temp;\
+    s32DCTY[13]=(int32_t)s32Temp2;\
+}
+#define WINDOW_ACCU_8_4_12 \
+{\
+    s32Temp=(int32_t)WIND_8_SUBBANDS_4_0*(int32_t)s16X[ChOffset+4];\
+    s32Temp2=(int32_t)WIND_8_SUBBANDS_4_0*(int32_t)s16X[ChOffset+64+12];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_4_1*(int32_t)s16X[ChOffset+16+4];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_4_1*(int32_t)s16X[ChOffset+48+12];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_4_2*(int32_t)s16X[ChOffset+32+4];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_4_2*(int32_t)s16X[ChOffset+32+12];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_4_3*(int32_t)s16X[ChOffset+48+4];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_4_3*(int32_t)s16X[ChOffset+16+12];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_4_4*(int32_t)s16X[ChOffset+64+4];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_4_4*(int32_t)s16X[ChOffset+12];\
+    s32DCTY[4]=(int32_t)s32Temp;\
+    s32DCTY[12]=(int32_t)s32Temp2;\
+}
+#define WINDOW_ACCU_8_5_11 \
+{\
+    s32Temp=(int32_t)WIND_8_SUBBANDS_5_0*(int32_t)s16X[ChOffset+5];\
+    s32Temp2=(int32_t)WIND_8_SUBBANDS_5_0*(int32_t)s16X[ChOffset+64+11];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_5_1*(int32_t)s16X[ChOffset+16+5];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_5_1*(int32_t)s16X[ChOffset+48+11];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_5_2*(int32_t)s16X[ChOffset+32+5];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_5_2*(int32_t)s16X[ChOffset+32+11];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_5_3*(int32_t)s16X[ChOffset+48+5];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_5_3*(int32_t)s16X[ChOffset+16+11];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_5_4*(int32_t)s16X[ChOffset+64+5];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_5_4*(int32_t)s16X[ChOffset+11];\
+    s32DCTY[5]=(int32_t)s32Temp;\
+    s32DCTY[11]=(int32_t)s32Temp2;\
+}
+#define WINDOW_ACCU_8_6_10 \
+{\
+    s32Temp=(int32_t)WIND_8_SUBBANDS_6_0*(int32_t)s16X[ChOffset+6];\
+    s32Temp2=(int32_t)WIND_8_SUBBANDS_6_0*(int32_t)s16X[ChOffset+64+10];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_6_1*(int32_t)s16X[ChOffset+16+6];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_6_1*(int32_t)s16X[ChOffset+48+10];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_6_2*(int32_t)s16X[ChOffset+32+6];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_6_2*(int32_t)s16X[ChOffset+32+10];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_6_3*(int32_t)s16X[ChOffset+48+6];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_6_3*(int32_t)s16X[ChOffset+16+10];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_6_4*(int32_t)s16X[ChOffset+64+6];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_6_4*(int32_t)s16X[ChOffset+10];\
+    s32DCTY[6]=(int32_t)s32Temp;\
+    s32DCTY[10]=(int32_t)s32Temp2;\
+}
+#define WINDOW_ACCU_8_7_9 \
+{\
+    s32Temp=(int32_t)WIND_8_SUBBANDS_7_0*(int32_t)s16X[ChOffset+7];\
+    s32Temp2=(int32_t)WIND_8_SUBBANDS_7_0*(int32_t)s16X[ChOffset+64+9];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_7_1*(int32_t)s16X[ChOffset+16+7];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_7_1*(int32_t)s16X[ChOffset+48+9];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_7_2*(int32_t)s16X[ChOffset+32+7];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_7_2*(int32_t)s16X[ChOffset+32+9];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_7_3*(int32_t)s16X[ChOffset+48+7];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_7_3*(int32_t)s16X[ChOffset+16+9];\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_7_4*(int32_t)s16X[ChOffset+64+7];\
+    s32Temp2+=(int32_t)WIND_8_SUBBANDS_7_4*(int32_t)s16X[ChOffset+9];\
+    s32DCTY[7]=(int32_t)s32Temp;\
+    s32DCTY[9]=(int32_t)s32Temp2;\
+}
+#define WINDOW_ACCU_8_8 \
+{\
+    s32Temp=(int32_t)WIND_8_SUBBANDS_8_0*(int32_t)(s16X[ChOffset+8]+s16X[ChOffset+64+8]);\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_8_1*(int32_t)(s16X[ChOffset+16+8]+s16X[ChOffset+48+8]);\
+    s32Temp+=(int32_t)WIND_8_SUBBANDS_8_2*(int32_t)s16X[ChOffset+32+8];\
+    s32DCTY[8]=(int32_t)s32Temp;\
+}
+#define WINDOW_ACCU_4_0 \
+{\
+    s32Temp=(int32_t)WIND_4_SUBBANDS_0_1*(int32_t)(s16X[ChOffset+8]-s16X[ChOffset+32]);\
+    s32Temp+=(int32_t)WIND_4_SUBBANDS_0_2*(int32_t)(s16X[ChOffset+16]-s16X[ChOffset+24]);\
+    s32DCTY[0]=(int32_t)(s32Temp);\
+}
+#define WINDOW_ACCU_4_1_7 \
+{\
+    s32Temp=(int32_t)WIND_4_SUBBANDS_1_0*(int32_t)s16X[ChOffset+1];\
+    s32Temp2=(int32_t)WIND_4_SUBBANDS_1_0*(int32_t)s16X[ChOffset+32+7];\
+    s32Temp+=(int32_t)WIND_4_SUBBANDS_1_1*(int32_t)s16X[ChOffset+8+1];\
+    s32Temp2+=(int32_t)WIND_4_SUBBANDS_1_1*(int32_t)s16X[ChOffset+24+7];\
+    s32Temp+=(int32_t)WIND_4_SUBBANDS_1_2*(int32_t)s16X[ChOffset+16+1];\
+    s32Temp2+=(int32_t)WIND_4_SUBBANDS_1_2*(int32_t)s16X[ChOffset+16+7];\
+    s32Temp+=(int32_t)WIND_4_SUBBANDS_1_3*(int32_t)s16X[ChOffset+24+1];\
+    s32Temp2+=(int32_t)WIND_4_SUBBANDS_1_3*(int32_t)s16X[ChOffset+8+7];\
+    s32Temp+=(int32_t)WIND_4_SUBBANDS_1_4*(int32_t)s16X[ChOffset+32+1];\
+    s32Temp2+=(int32_t)WIND_4_SUBBANDS_1_4*(int32_t)s16X[ChOffset+7];\
+    s32DCTY[1]=(int32_t)(s32Temp);\
+    s32DCTY[7]=(int32_t)(s32Temp2);\
+}
+#define WINDOW_ACCU_4_2_6 \
+{\
+    s32Temp=(int32_t)WIND_4_SUBBANDS_2_0*(int32_t)s16X[ChOffset+2];\
+    s32Temp2=(int32_t)WIND_4_SUBBANDS_2_0*(int32_t)s16X[ChOffset+32+6];\
+    s32Temp+=(int32_t)WIND_4_SUBBANDS_2_1*(int32_t)s16X[ChOffset+8+2];\
+    s32Temp2+=(int32_t)WIND_4_SUBBANDS_2_1*(int32_t)s16X[ChOffset+24+6];\
+    s32Temp+=(int32_t)WIND_4_SUBBANDS_2_2*(int32_t)s16X[ChOffset+16+2];\
+    s32Temp2+=(int32_t)WIND_4_SUBBANDS_2_2*(int32_t)s16X[ChOffset+16+6];\
+    s32Temp+=(int32_t)WIND_4_SUBBANDS_2_3*(int32_t)s16X[ChOffset+24+2];\
+    s32Temp2+=(int32_t)WIND_4_SUBBANDS_2_3*(int32_t)s16X[ChOffset+8+6];\
+    s32Temp+=(int32_t)WIND_4_SUBBANDS_2_4*(int32_t)s16X[ChOffset+32+2];\
+    s32Temp2+=(int32_t)WIND_4_SUBBANDS_2_4*(int32_t)s16X[ChOffset+6];\
+    s32DCTY[2]=(int32_t)(s32Temp);\
+    s32DCTY[6]=(int32_t)(s32Temp2);\
+}
+#define WINDOW_ACCU_4_3_5 \
+{\
+    s32Temp=(int32_t)WIND_4_SUBBANDS_3_0*(int32_t)s16X[ChOffset+3];\
+    s32Temp2=(int32_t)WIND_4_SUBBANDS_3_0*(int32_t)s16X[ChOffset+32+5];\
+    s32Temp+=(int32_t)WIND_4_SUBBANDS_3_1*(int32_t)s16X[ChOffset+8+3];\
+    s32Temp2+=(int32_t)WIND_4_SUBBANDS_3_1*(int32_t)s16X[ChOffset+24+5];\
+    s32Temp+=(int32_t)WIND_4_SUBBANDS_3_2*(int32_t)s16X[ChOffset+16+3];\
+    s32Temp2+=(int32_t)WIND_4_SUBBANDS_3_2*(int32_t)s16X[ChOffset+16+5];\
+    s32Temp+=(int32_t)WIND_4_SUBBANDS_3_3*(int32_t)s16X[ChOffset+24+3];\
+    s32Temp2+=(int32_t)WIND_4_SUBBANDS_3_3*(int32_t)s16X[ChOffset+8+5];\
+    s32Temp+=(int32_t)WIND_4_SUBBANDS_3_4*(int32_t)s16X[ChOffset+32+3];\
+    s32Temp2+=(int32_t)WIND_4_SUBBANDS_3_4*(int32_t)s16X[ChOffset+5];\
+    s32DCTY[3]=(int32_t)(s32Temp);\
+    s32DCTY[5]=(int32_t)(s32Temp2);\
+}
+
+#define WINDOW_ACCU_4_4 \
+{\
+    s32Temp=(int32_t)WIND_4_SUBBANDS_4_0*(int32_t)(s16X[ChOffset+4]+s16X[ChOffset+4+32]);\
+    s32Temp+=(int32_t)WIND_4_SUBBANDS_4_1*(int32_t)(s16X[ChOffset+4+8]+s16X[ChOffset+4+24]);\
+    s32Temp+=(int32_t)WIND_4_SUBBANDS_4_2*(int32_t)s16X[ChOffset+4+16];\
+    s32DCTY[4]=(int32_t)(s32Temp);\
+}
+#endif
+#define WINDOW_PARTIAL_4 \
+{\
+    WINDOW_ACCU_4_0;     WINDOW_ACCU_4_1_7;\
+    WINDOW_ACCU_4_2_6;   WINDOW_ACCU_4_3_5;\
+    WINDOW_ACCU_4_4;\
+}
+
+#define WINDOW_PARTIAL_8 \
+{\
+    WINDOW_ACCU_8_0;         WINDOW_ACCU_8_1_15;\
+    WINDOW_ACCU_8_2_14;      WINDOW_ACCU_8_3_13;\
+    WINDOW_ACCU_8_4_12;      WINDOW_ACCU_8_5_11;\
+    WINDOW_ACCU_8_6_10;      WINDOW_ACCU_8_7_9;\
+    WINDOW_ACCU_8_8;\
+}
+#else
+#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE)
+#define WINDOW_ACCU_4(i) \
+{\
+    s64Temp=((int64_t)gas32CoeffFor4SBs[i] * (int64_t)s16X[ChOffset+i]);                                    \
+    s64Temp+=((int64_t)gas32CoeffFor4SBs[(i+8)] * (int64_t)s16X[ChOffset+i+8]);                                    \
+    s64Temp+=((int64_t)gas32CoeffFor4SBs[(i+16)] * (int64_t)s16X[ChOffset+i+16]);                                    \
+    s64Temp+=((int64_t)gas32CoeffFor4SBs[(i+24)] * (int64_t)s16X[ChOffset+i+24]);                                    \
+    s64Temp+=((int64_t)gas32CoeffFor4SBs[(i+32)] * (int64_t)s16X[ChOffset+i+32]);                                    \
+    s32DCTY[i]=(int32_t)(s64Temp>>16);\
+	/*printf("s32DCTY4: 0x%x \n", s32DCTY[i]);*/\
+}
+#else
+#define WINDOW_ACCU_4(i) \
+{\
+    s32DCTY[i]=(gas32CoeffFor4SBs[i * 2] * s16X[ChOffset+i])                                    \
+            +  (((int32_t)(uint16_t)(gas32CoeffFor4SBs[(i * 2) + 1]) * s16X[ChOffset+i]) >> 16);   \
+    s32DCTY[i]+=(gas32CoeffFor4SBs[(i+8) * 2] * s16X[ChOffset+i+8])                                    \
+            +  (((int32_t)(uint16_t)(gas32CoeffFor4SBs[((i+8) * 2) + 1]) * s16X[ChOffset+i+8]) >> 16);   \
+    s32DCTY[i]+=(gas32CoeffFor4SBs[(i+16) * 2] * s16X[ChOffset+i+16])                                    \
+            +  (((int32_t)(uint16_t)(gas32CoeffFor4SBs[((i+16) * 2) + 1]) * s16X[ChOffset+i+16]) >> 16);   \
+    s32DCTY[i]+=(gas32CoeffFor4SBs[(i+24) * 2] * s16X[ChOffset+i+24])                                    \
+            +  (((int32_t)(uint16_t)(gas32CoeffFor4SBs[((i+24) * 2) + 1]) * s16X[ChOffset+i+24]) >> 16);   \
+    s32DCTY[i]+=(gas32CoeffFor4SBs[(i+32) * 2] * s16X[ChOffset+i+32])                                    \
+            +  (((int32_t)(uint16_t)(gas32CoeffFor4SBs[((i+32) * 2) + 1]) * s16X[ChOffset+i+32]) >> 16);   \
+}
+#endif
+#define WINDOW_PARTIAL_4 \
+{\
+    WINDOW_ACCU_4(0);      WINDOW_ACCU_4(1);\
+    WINDOW_ACCU_4(2);      WINDOW_ACCU_4(3);\
+    WINDOW_ACCU_4(4);      WINDOW_ACCU_4(5);\
+    WINDOW_ACCU_4(6);      WINDOW_ACCU_4(7);\
+}
+
+#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE)
+#define WINDOW_ACCU_8(i) \
+{\
+    s64Temp = ((((int64_t)gas32CoeffFor8SBs[i]      * (int64_t)s16X[ChOffset+i]   )));                 \
+    s64Temp+= ((((int64_t)gas32CoeffFor8SBs[(i+16)] * (int64_t)s16X[ChOffset+i+16])));                 \
+    s64Temp+= ((((int64_t)gas32CoeffFor8SBs[(i+32)] * (int64_t)s16X[ChOffset+i+32])));                 \
+    s64Temp+= ((((int64_t)gas32CoeffFor8SBs[(i+48)] * (int64_t)s16X[ChOffset+i+48])));                 \
+    s64Temp+= ((((int64_t)gas32CoeffFor8SBs[(i+64)] * (int64_t)s16X[ChOffset+i+64])));                 \
+	/*printf("s32DCTY8: %d= 0x%x * %d\n", s32DCTY[i], gas32CoeffFor8SBs[i], s16X[ChOffset+i]);*/     \
+    s32DCTY[i]=(int32_t)(s64Temp>>16);\
+}
+#else
+#define WINDOW_ACCU_8(i) \
+{\
+    s32DCTY[i]=(gas32CoeffFor8SBs[i * 2] * s16X[ChOffset+i])                                    \
+            +  (((int32_t)(uint16_t)(gas32CoeffFor8SBs[(i * 2) + 1]) * s16X[ChOffset+i]) >> 16);   \
+    s32DCTY[i]+=(gas32CoeffFor8SBs[(i+16) * 2] * s16X[ChOffset+i+16])                                    \
+            +  (((int32_t)(uint16_t)(gas32CoeffFor8SBs[((i+16) * 2) + 1]) * s16X[ChOffset+i+16]) >> 16);   \
+    s32DCTY[i]+=(gas32CoeffFor8SBs[(i+32) * 2] * s16X[ChOffset+i+32])                                    \
+            +  (((int32_t)(uint16_t)(gas32CoeffFor8SBs[((i+32) * 2) + 1]) * s16X[ChOffset+i+32]) >> 16);   \
+    s32DCTY[i]+=(gas32CoeffFor8SBs[(i+48) * 2] * s16X[ChOffset+i+48])                                    \
+            +  (((int32_t)(uint16_t)(gas32CoeffFor8SBs[((i+48) * 2) + 1]) * s16X[ChOffset+i+48]) >> 16);   \
+    s32DCTY[i]+=(gas32CoeffFor8SBs[(i+64) * 2] * s16X[ChOffset+i+64])                                    \
+            +  (((int32_t)(uint16_t)(gas32CoeffFor8SBs[((i+64) * 2) + 1]) * s16X[ChOffset+i+64]) >> 16);   \
+	/*printf("s32DCTY8: %d = 0x%4x%4x * %d\n", s32DCTY[i], gas32CoeffFor8SBs[i * 2], (gas32CoeffFor8SBs[(i * 2) + 1]), s16X[ChOffset+i]);*/\
+    /*s32DCTY[i]=(int32_t)(s64Temp>>16);*/\
+}
+#endif
+#define WINDOW_PARTIAL_8 \
+{\
+    WINDOW_ACCU_8(0);      WINDOW_ACCU_8(1);\
+    WINDOW_ACCU_8(2);      WINDOW_ACCU_8(3);\
+    WINDOW_ACCU_8(4);      WINDOW_ACCU_8(5);\
+    WINDOW_ACCU_8(6);      WINDOW_ACCU_8(7);\
+    WINDOW_ACCU_8(8);      WINDOW_ACCU_8(9);\
+    WINDOW_ACCU_8(10);     WINDOW_ACCU_8(11);\
+    WINDOW_ACCU_8(12);     WINDOW_ACCU_8(13);\
+    WINDOW_ACCU_8(14);     WINDOW_ACCU_8(15);\
+}
+#endif
+#endif
+
+static int16_t ShiftCounter=0;
+extern int16_t EncMaxShiftCounter;
+/****************************************************************************
+* SbcAnalysisFilter - performs Analysis of the input audio stream
+*
+* RETURNS : N/A
+*/
+void SbcAnalysisFilter4(SBC_ENC_PARAMS *pstrEncParams, int16_t *input)
+{
+    int16_t *ps16PcmBuf;
+    int32_t *ps32SbBuf;
+    int32_t  s32Blk,s32Ch;
+    int32_t  s32NumOfChannels, s32NumOfBlocks;
+    int32_t i,*ps32X,*ps32X2;
+    int32_t Offset,Offset2,ChOffset;
+#if (SBC_ARM_ASM_OPT == TRUE)
+    register int32_t s32Hi,s32Hi2;
+#else
+#if (SBC_IPAQ_OPT == TRUE)
+#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE)
+    register int64_t s64Temp,s64Temp2;
+#else
+	register int32_t s32Temp,s32Temp2;
+#endif
+#else
+
+#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE)
+    int64_t s64Temp;
+#endif
+
+#endif
+#endif
+
+    s32NumOfChannels = pstrEncParams->s16NumOfChannels;
+    s32NumOfBlocks   = pstrEncParams->s16NumOfBlocks;
+
+    ps16PcmBuf = input;
+
+    ps32SbBuf  = pstrEncParams->s32SbBuffer;
+    Offset2=(int32_t)(EncMaxShiftCounter+40);
+    for (s32Blk=0; s32Blk <s32NumOfBlocks; s32Blk++)
+    {
+        Offset=(int32_t)(EncMaxShiftCounter-ShiftCounter);
+        /* Store new samples */
+        if (s32NumOfChannels==1)
+        {
+            s16X[3+Offset] = *ps16PcmBuf;   ps16PcmBuf++;
+            s16X[2+Offset] = *ps16PcmBuf;   ps16PcmBuf++;
+            s16X[1+Offset] = *ps16PcmBuf;   ps16PcmBuf++;
+            s16X[0+Offset] = *ps16PcmBuf;   ps16PcmBuf++;
+        }
+        else
+        {
+            s16X[3+Offset] = *ps16PcmBuf;        ps16PcmBuf++;
+            s16X[Offset2+3+Offset] = *ps16PcmBuf;     ps16PcmBuf++;
+            s16X[2+Offset] = *ps16PcmBuf;        ps16PcmBuf++;
+            s16X[Offset2+2+Offset] = *ps16PcmBuf;     ps16PcmBuf++;
+            s16X[1+Offset] = *ps16PcmBuf;        ps16PcmBuf++;
+            s16X[Offset2+1+Offset] = *ps16PcmBuf;     ps16PcmBuf++;
+            s16X[0+Offset] = *ps16PcmBuf;        ps16PcmBuf++;
+            s16X[Offset2+0+Offset] = *ps16PcmBuf;     ps16PcmBuf++;
+        }
+        for (s32Ch=0;s32Ch<s32NumOfChannels;s32Ch++)
+        {
+            ChOffset=s32Ch*Offset2+Offset;
+
+            WINDOW_PARTIAL_4
+
+            SBC_FastIDCT4(s32DCTY, ps32SbBuf);
+
+            ps32SbBuf +=SUB_BANDS_4;
+        }
+        if (s32NumOfChannels==1)
+        {
+            if (ShiftCounter>=EncMaxShiftCounter)
+            {
+                SHIFTUP_X4;
+                ShiftCounter=0;
+            }
+            else
+            {
+                ShiftCounter+=SUB_BANDS_4;
+            }
+        }
+        else
+        {
+            if (ShiftCounter>=EncMaxShiftCounter)
+            {
+                SHIFTUP_X4_2;
+                ShiftCounter=0;
+            }
+            else
+            {
+                ShiftCounter+=SUB_BANDS_4;
+            }
+        }
+    }
+}
+
+/* //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// */
+void SbcAnalysisFilter8 (SBC_ENC_PARAMS *pstrEncParams, int16_t *input)
+{
+    int16_t *ps16PcmBuf;
+    int32_t *ps32SbBuf;
+    int32_t  s32Blk,s32Ch;                                     /* counter for block*/
+    int32_t Offset,Offset2;
+    int32_t  s32NumOfChannels, s32NumOfBlocks;
+    int32_t i,*ps32X,*ps32X2;
+    int32_t ChOffset;
+#if (SBC_ARM_ASM_OPT == TRUE)
+    register int32_t s32Hi,s32Hi2;
+#else
+#if (SBC_IPAQ_OPT == TRUE)
+#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE)
+    register int64_t s64Temp,s64Temp2;
+#else
+	register int32_t s32Temp,s32Temp2;
+#endif
+#else
+#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE)
+    int64_t s64Temp;
+#endif
+#endif
+#endif
+
+    s32NumOfChannels = pstrEncParams->s16NumOfChannels;
+    s32NumOfBlocks   = pstrEncParams->s16NumOfBlocks;
+
+    ps16PcmBuf = input;
+
+    ps32SbBuf  = pstrEncParams->s32SbBuffer;
+    Offset2=(int32_t)(EncMaxShiftCounter+80);
+    for (s32Blk=0; s32Blk <s32NumOfBlocks; s32Blk++)
+    {
+        Offset=(int32_t)(EncMaxShiftCounter-ShiftCounter);
+        /* Store new samples */
+        if (s32NumOfChannels==1)
+        {
+            s16X[7+Offset] = *ps16PcmBuf;   ps16PcmBuf++;
+            s16X[6+Offset] = *ps16PcmBuf;   ps16PcmBuf++;
+            s16X[5+Offset] = *ps16PcmBuf;   ps16PcmBuf++;
+            s16X[4+Offset] = *ps16PcmBuf;   ps16PcmBuf++;
+            s16X[3+Offset] = *ps16PcmBuf;   ps16PcmBuf++;
+            s16X[2+Offset] = *ps16PcmBuf;   ps16PcmBuf++;
+            s16X[1+Offset] = *ps16PcmBuf;   ps16PcmBuf++;
+            s16X[0+Offset] = *ps16PcmBuf;   ps16PcmBuf++;
+        }
+        else
+        {
+            s16X[7+Offset] = *ps16PcmBuf;        ps16PcmBuf++;
+            s16X[Offset2+7+Offset] = *ps16PcmBuf;     ps16PcmBuf++;
+            s16X[6+Offset] = *ps16PcmBuf;        ps16PcmBuf++;
+            s16X[Offset2+6+Offset] = *ps16PcmBuf;     ps16PcmBuf++;
+            s16X[5+Offset] = *ps16PcmBuf;        ps16PcmBuf++;
+            s16X[Offset2+5+Offset] = *ps16PcmBuf;     ps16PcmBuf++;
+            s16X[4+Offset] = *ps16PcmBuf;        ps16PcmBuf++;
+            s16X[Offset2+4+Offset] = *ps16PcmBuf;     ps16PcmBuf++;
+            s16X[3+Offset] = *ps16PcmBuf;        ps16PcmBuf++;
+            s16X[Offset2+3+Offset] = *ps16PcmBuf;     ps16PcmBuf++;
+            s16X[2+Offset] = *ps16PcmBuf;        ps16PcmBuf++;
+            s16X[Offset2+2+Offset] = *ps16PcmBuf;     ps16PcmBuf++;
+            s16X[1+Offset] = *ps16PcmBuf;        ps16PcmBuf++;
+            s16X[Offset2+1+Offset] = *ps16PcmBuf;     ps16PcmBuf++;
+            s16X[0+Offset] = *ps16PcmBuf;        ps16PcmBuf++;
+            s16X[Offset2+0+Offset] = *ps16PcmBuf;     ps16PcmBuf++;
+        }
+        for (s32Ch=0;s32Ch<s32NumOfChannels;s32Ch++)
+        {
+            ChOffset=s32Ch*Offset2+Offset;
+
+            WINDOW_PARTIAL_8
+
+            SBC_FastIDCT8 (s32DCTY, ps32SbBuf);
+
+            ps32SbBuf +=SUB_BANDS_8;
+        }
+        if (s32NumOfChannels==1)
+        {
+            if (ShiftCounter>=EncMaxShiftCounter)
+            {
+                SHIFTUP_X8;
+                ShiftCounter=0;
+            }
+            else
+            {
+                ShiftCounter+=SUB_BANDS_8;
+            }
+        }
+        else
+        {
+            if (ShiftCounter>=EncMaxShiftCounter)
+            {
+                SHIFTUP_X8_2;
+                ShiftCounter=0;
+            }
+            else
+            {
+                ShiftCounter+=SUB_BANDS_8;
+            }
+        }
+    }
+}
+
+void SbcAnalysisInit (void)
+{
+    memset(s16X,0,ENC_VX_BUFFER_SIZE*sizeof(int16_t));
+    ShiftCounter=0;
+}
diff --git a/bt/embdrv/sbc/encoder/srce/sbc_dct.c b/bt/embdrv/sbc/encoder/srce/sbc_dct.c
new file mode 100644
index 0000000..1f7c49b
--- /dev/null
+++ b/bt/embdrv/sbc/encoder/srce/sbc_dct.c
@@ -0,0 +1,245 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  source file for fast dct operations
+ *
+ ******************************************************************************/
+
+#include "sbc_encoder.h"
+#include "sbc_enc_func_declare.h"
+#include "sbc_dct.h"
+
+
+
+/*******************************************************************************
+**
+** Function         SBC_FastIDCT8
+**
+** Description      implementation of fast DCT algorithm by Feig and Winograd
+**
+**
+** Returns          y = dct(pInVect)
+**
+**
+*******************************************************************************/
+
+#if (SBC_IS_64_MULT_IN_IDCT == FALSE)
+#define SBC_COS_PI_SUR_4            (0x00005a82)  /* ((0x8000) * 0.7071)     = cos(pi/4) */
+#define SBC_COS_PI_SUR_8            (0x00007641)  /* ((0x8000) * 0.9239)     = (cos(pi/8)) */
+#define SBC_COS_3PI_SUR_8           (0x000030fb)  /* ((0x8000) * 0.3827)     = (cos(3*pi/8)) */
+#define SBC_COS_PI_SUR_16           (0x00007d8a)  /* ((0x8000) * 0.9808))     = (cos(pi/16)) */
+#define SBC_COS_3PI_SUR_16          (0x00006a6d)  /* ((0x8000) * 0.8315))     = (cos(3*pi/16)) */
+#define SBC_COS_5PI_SUR_16          (0x0000471c)  /* ((0x8000) * 0.5556))     = (cos(5*pi/16)) */
+#define SBC_COS_7PI_SUR_16          (0x000018f8)  /* ((0x8000) * 0.1951))     = (cos(7*pi/16)) */
+#define SBC_IDCT_MULT(a,b,c) SBC_MULT_32_16_SIMPLIFIED(a,b,c)
+#else
+#define SBC_COS_PI_SUR_4            (0x5A827999)  /* ((0x80000000) * 0.707106781)      = (cos(pi/4)   ) */
+#define SBC_COS_PI_SUR_8            (0x7641AF3C)  /* ((0x80000000) * 0.923879533)      = (cos(pi/8)   ) */
+#define SBC_COS_3PI_SUR_8           (0x30FBC54D)  /* ((0x80000000) * 0.382683432)      = (cos(3*pi/8) ) */
+#define SBC_COS_PI_SUR_16           (0x7D8A5F3F)  /* ((0x80000000) * 0.98078528 ))     = (cos(pi/16)  ) */
+#define SBC_COS_3PI_SUR_16          (0x6A6D98A4)  /* ((0x80000000) * 0.831469612))     = (cos(3*pi/16)) */
+#define SBC_COS_5PI_SUR_16          (0x471CECE6)  /* ((0x80000000) * 0.555570233))     = (cos(5*pi/16)) */
+#define SBC_COS_7PI_SUR_16          (0x18F8B83C)  /* ((0x80000000) * 0.195090322))     = (cos(7*pi/16)) */
+#define SBC_IDCT_MULT(a,b,c) SBC_MULT_32_32(a,b,c)
+#endif /* SBC_IS_64_MULT_IN_IDCT */
+
+#if (SBC_FAST_DCT == FALSE)
+extern const int16_t gas16AnalDCTcoeff8[];
+extern const int16_t gas16AnalDCTcoeff4[];
+#endif
+
+void SBC_FastIDCT8(int32_t *pInVect, int32_t *pOutVect)
+{
+#if (SBC_FAST_DCT == TRUE)
+#if (SBC_ARM_ASM_OPT == TRUE)
+#else
+#if (SBC_IPAQ_OPT == TRUE)
+#if (SBC_IS_64_MULT_IN_IDCT == TRUE)
+    int64_t s64Temp;
+#endif
+#else
+#if (SBC_IS_64_MULT_IN_IDCT == TRUE)
+    int32_t s32HiTemp;
+#else
+    int32_t s32In2Temp;
+    register int32_t s32In1Temp;
+#endif
+#endif
+#endif
+
+    register int32_t x0, x1, x2, x3, x4, x5, x6, x7,temp;
+    int32_t res_even[4], res_odd[4];
+    /*x0= (pInVect[4])/2 ;*/
+    SBC_IDCT_MULT(SBC_COS_PI_SUR_4,pInVect[4], x0);
+    /*printf("x0 0x%x = %d = %d * %d\n", x0, x0, SBC_COS_PI_SUR_4, pInVect[4]);*/
+
+    x1 = (pInVect[3] + pInVect[5])  >>1;
+    x2 = (pInVect[2] + pInVect[6])  >>1;
+    x3 = (pInVect[1] + pInVect[7])  >>1;
+    x4 = (pInVect[0] + pInVect[8])  >>1;
+    x5 = (pInVect[9] - pInVect[15]) >>1;
+    x6 = (pInVect[10] - pInVect[14])>>1;
+    x7 = (pInVect[11] - pInVect[13])>>1;
+
+    /* 2-point IDCT of x0 and x4 as in (11) */
+    temp = x0 ;
+    SBC_IDCT_MULT(SBC_COS_PI_SUR_4, ( x0 + x4 ), x0);          /*x0 = ( x0 + x4 ) * cos(1*pi/4) ; */
+    SBC_IDCT_MULT(SBC_COS_PI_SUR_4, ( temp - x4 ), x4);        /*x4 = ( temp - x4 ) * cos(1*pi/4) ; */
+
+    /* rearrangement of x2 and x6 as in (15) */
+    x2 -=x6;
+    x6 <<= 1 ;
+
+    /* 2-point IDCT of x2 and x6 and post-multiplication as in (15) */
+    SBC_IDCT_MULT(SBC_COS_PI_SUR_4,x6, x6); /*x6 = x6 * cos(1*pi/4) ; */
+    temp = x2 ;
+    SBC_IDCT_MULT(SBC_COS_PI_SUR_8,( x2 + x6 ), x2); /*x2 = ( x2 + x6 ) * cos(1*pi/8) ; */
+    SBC_IDCT_MULT(SBC_COS_3PI_SUR_8,( temp - x6 ), x6); /*x6 = ( temp - x6 ) * cos(3*pi/8) ;*/
+
+    /* 4-point IDCT of x0,x2,x4 and x6 as in (11) */
+    res_even[ 0 ] = x0 + x2 ;
+    res_even[ 1 ] = x4 + x6 ;
+    res_even[ 2 ] = x4 - x6 ;
+    res_even[ 3 ] = x0 - x2 ;
+
+
+    /* rearrangement of x1,x3,x5,x7 as in (15) */
+    x7 <<= 1 ;
+    x5 = ( x5 <<1 ) - x7 ;
+    x3 = ( x3 <<1 ) - x5 ;
+    x1 -= x3 >>1 ;
+
+    /* two-dimensional IDCT of x1 and x5 */
+    SBC_IDCT_MULT(SBC_COS_PI_SUR_4, x5, x5);          /*x5 = x5 * cos(1*pi/4) ; */
+    temp = x1 ;
+    x1 = x1 + x5 ;
+    x5 = temp - x5 ;
+
+    /* rearrangement of x3 and x7 as in (15) */
+    x3 -= x7;
+    x7 <<= 1 ;
+    SBC_IDCT_MULT(SBC_COS_PI_SUR_4, x7, x7);          /*x7 = x7 * cos(1*pi/4) ; */
+
+    /* 2-point IDCT of x3 and x7 and post-multiplication as in (15) */
+    temp = x3 ;
+    SBC_IDCT_MULT( SBC_COS_PI_SUR_8,( x3 + x7 ), x3);          /*x3 = ( x3 + x7 ) * cos(1*pi/8)  ; */
+    SBC_IDCT_MULT( SBC_COS_3PI_SUR_8,( temp - x7 ), x7);          /*x7 = ( temp - x7 ) * cos(3*pi/8) ;*/
+
+    /* 4-point IDCT of x1,x3,x5 and x7 and post multiplication by diagonal matrix as in (14) */
+    SBC_IDCT_MULT((SBC_COS_PI_SUR_16),   ( x1 + x3 ) ,   res_odd[0]); /*res_odd[ 0 ] = ( x1 + x3 ) * cos(1*pi/16) ; */
+    SBC_IDCT_MULT((SBC_COS_3PI_SUR_16),  ( x5 + x7 ) ,   res_odd[1]); /*res_odd[ 1 ] = ( x5 + x7 ) * cos(3*pi/16) ; */
+    SBC_IDCT_MULT((SBC_COS_5PI_SUR_16),  ( x5 - x7 ) ,   res_odd[2]); /*res_odd[ 2 ] = ( x5 - x7 ) * cos(5*pi/16) ; */
+    SBC_IDCT_MULT((SBC_COS_7PI_SUR_16),  ( x1 - x3 ) ,  res_odd[3]); /*res_odd[ 3 ] = ( x1 - x3 ) * cos(7*pi/16) ; */
+
+    /* additions and subtractions as in (9) */
+    pOutVect[0] = (res_even[ 0 ] + res_odd[ 0 ])  ;
+    pOutVect[1] = (res_even[ 1 ] + res_odd[ 1 ])  ;
+    pOutVect[2] = (res_even[ 2 ] + res_odd[ 2 ])  ;
+    pOutVect[3] = (res_even[ 3 ] + res_odd[ 3 ])  ;
+    pOutVect[7] = (res_even[ 0 ] - res_odd[ 0 ])  ;
+    pOutVect[6] = (res_even[ 1 ] - res_odd[ 1 ])  ;
+    pOutVect[5] = (res_even[ 2 ] - res_odd[ 2 ])  ;
+    pOutVect[4] = (res_even[ 3 ] - res_odd[ 3 ])  ;
+#else
+    uint8_t Index, k;
+    int32_t temp;
+	/*Calculate 4 subband samples by matrixing*/
+    for(Index=0; Index<8; Index++)
+    {
+        temp = 0;
+        for(k=0; k<16; k++)
+        {
+            /*temp += (int32_t)(((int64_t)M[(Index*strEncParams->numOfSubBands*2)+k] * Y[k]) >> 16 );*/
+            temp += (gas16AnalDCTcoeff8[(Index*8*2)+k] * (pInVect[k] >> 16));
+            temp += ((gas16AnalDCTcoeff8[(Index*8*2)+k] * (pInVect[k] & 0xFFFF)) >> 16);
+        }
+        pOutVect[Index] = temp;
+    }
+#endif
+/*    printf("pOutVect: 0x%x;0x%x;0x%x;0x%x;0x%x;0x%x;0x%x;0x%x\n",\
+        pOutVect[0],pOutVect[1],pOutVect[2],pOutVect[3],pOutVect[4],pOutVect[5],pOutVect[6],pOutVect[7]);*/
+}
+
+/*******************************************************************************
+**
+** Function         SBC_FastIDCT4
+**
+** Description      implementation of fast DCT algorithm by Feig and Winograd
+**
+**
+** Returns          y = dct(x0)
+**
+**
+*******************************************************************************/
+void SBC_FastIDCT4(int32_t *pInVect, int32_t *pOutVect)
+{
+#if (SBC_FAST_DCT == TRUE)
+#if (SBC_ARM_ASM_OPT == TRUE)
+#else
+#if (SBC_IPAQ_OPT == TRUE)
+#if (SBC_IS_64_MULT_IN_IDCT == TRUE)
+    int64_t s64Temp;
+#endif
+#else
+#if (SBC_IS_64_MULT_IN_IDCT == TRUE)
+    int32_t s32HiTemp;
+#else
+    uint16_t s32In2Temp;
+    int32_t s32In1Temp;
+#endif
+#endif
+#endif
+    int32_t temp,x2;
+    int32_t tmp[8];
+
+    x2=pInVect[2]>>1;
+    temp=(pInVect[0]+pInVect[4]);
+    SBC_IDCT_MULT((SBC_COS_PI_SUR_4>>1), temp , tmp[0]);
+    tmp[1]=x2-tmp[0];
+    tmp[0]+=x2;
+    temp=(pInVect[1]+pInVect[3]);
+    SBC_IDCT_MULT((SBC_COS_3PI_SUR_8>>1), temp , tmp[3]);
+    SBC_IDCT_MULT((SBC_COS_PI_SUR_8>>1), temp , tmp[2]);
+    temp=(pInVect[5]-pInVect[7]);
+    SBC_IDCT_MULT((SBC_COS_3PI_SUR_8>>1), temp , tmp[5]);
+    SBC_IDCT_MULT((SBC_COS_PI_SUR_8>>1), temp , tmp[4]);
+    tmp[6]=tmp[2]+tmp[5];
+    tmp[7]=tmp[3]-tmp[4];
+    pOutVect[0] = (tmp[0]+tmp[6]);
+    pOutVect[1] = (tmp[1]+tmp[7]);
+    pOutVect[2] = (tmp[1]-tmp[7]);
+    pOutVect[3] = (tmp[0]-tmp[6]);
+#else
+    uint8_t Index, k;
+    int32_t temp;
+	/*Calculate 4 subband samples by matrixing*/
+    for(Index=0; Index<4; Index++)
+    {
+        temp = 0;
+        for(k=0; k<8; k++)
+        {
+            /*temp += (int32_t)(((int64_t)M[(Index*strEncParams->numOfSubBands*2)+k] * Y[k]) >> 16 ); */
+            temp += (gas16AnalDCTcoeff4[(Index*4*2)+k] * (pInVect[k] >> 16));
+            temp += ((gas16AnalDCTcoeff4[(Index*4*2)+k] * (pInVect[k] & 0xFFFF)) >> 16);
+        }
+        pOutVect[Index] = temp;
+    }
+#endif
+}
diff --git a/bt/embdrv/sbc/encoder/srce/sbc_dct_coeffs.c b/bt/embdrv/sbc/encoder/srce/sbc_dct_coeffs.c
new file mode 100644
index 0000000..1ac7d0c
--- /dev/null
+++ b/bt/embdrv/sbc/encoder/srce/sbc_dct_coeffs.c
@@ -0,0 +1,200 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 coefficient table used for DCT computation in
+ *  analysis.
+ *
+ ******************************************************************************/
+
+#include "sbc_encoder.h"
+/*DCT coeff for 4 sub-band case.*/
+#if (SBC_FAST_DCT == FALSE)
+const int16_t gas16AnalDCTcoeff4[] =
+{
+	(int16_t)(0.7071*32768),
+	(int16_t)(0.9239*32768),
+	(int16_t)(1.0000*32767),
+	(int16_t)(0.9239*32768),
+	(int16_t)(0.7071*32768),
+	(int16_t)(0.3827*32768),
+	(int16_t)(0.0000*32768),
+	(int16_t)(-0.3827*32768),
+
+	(int16_t)(-0.7071*32768),
+	(int16_t)(0.3827*32768),
+	(int16_t)(1.0000*32767),
+	(int16_t)(0.3827*32768),
+	(int16_t)(-0.7071*32768),
+	(int16_t)(-0.9239*32768),
+	(int16_t)(-0.0000*32768),
+	(int16_t)(0.9239*32768),
+
+	(int16_t)(-0.7071*32768),
+	(int16_t)(-0.3827*32768),
+	(int16_t)(1.0000*32767),
+	(int16_t)(-0.3827*32768),
+	(int16_t)(-0.7071*32768),
+	(int16_t)(0.9239*32768),
+	(int16_t)(0.0000*32768),
+	(int16_t)(-0.9239*32768),
+
+	(int16_t)(0.7071*32768),
+	(int16_t)(-0.9239*32768),
+	(int16_t)(1.0000*32767),
+	(int16_t)(-0.9239*32768),
+	(int16_t)(0.7071*32768),
+	(int16_t)(-0.3827*32768),
+	(int16_t)(-0.0000*32768),
+	(int16_t)(0.3827*32768)
+};
+
+/*DCT coeff for 8 sub-band case.*/
+const int16_t gas16AnalDCTcoeff8[] =
+{
+	(int16_t)(0.7071*32768),
+	(int16_t)(0.8315*32768),
+	(int16_t)(0.9239*32768),
+	(int16_t)(0.9808*32768),
+	(int16_t)(1.0000*32767),
+	(int16_t)(0.9808*32768),
+	(int16_t)(0.9239*32768),
+	(int16_t)(0.8315*32768),
+	(int16_t)(0.7071*32768),
+	(int16_t)(0.5556*32768),
+	(int16_t)(0.3827*32768),
+	(int16_t)(0.1951*32768),
+	(int16_t)(0.0000*32768),
+	(int16_t)(-0.1951*32768),
+	(int16_t)(-0.3827*32768),
+	(int16_t)(-0.5556*32768),
+	(int16_t)(-0.7071*32768),
+	(int16_t)(-0.1951*32768),
+	(int16_t)(0.3827*32768),
+	(int16_t)(0.8315*32768),
+	(int16_t)(1.0000*32767),
+	(int16_t)(0.8315*32768),
+	(int16_t)(0.3827*32768),
+	(int16_t)(-0.1951*32768),
+	(int16_t)(-0.7071*32768),
+	(int16_t)(-0.9808*32768),
+	(int16_t)(-0.9239*32768),
+	(int16_t)(-0.5556*32768),
+	(int16_t)(-0.0000*32768),
+	(int16_t)(0.5556*32768),
+	(int16_t)(0.9239*32768),
+	(int16_t)(0.9808*32768),
+	(int16_t)(-0.7071*32768),
+	(int16_t)(-0.9808*32768),
+	(int16_t)(-0.3827*32768),
+	(int16_t)(0.5556*32768),
+	(int16_t)(1.0000*32767),
+	(int16_t)(0.5556*32768),
+	(int16_t)(-0.3827*32768),
+	(int16_t)(-0.9808*32768),
+	(int16_t)(-0.7071*32768),
+	(int16_t)(0.1951*32768),
+	(int16_t)(0.9239*32768),
+	(int16_t)(0.8315*32768),
+	(int16_t)(0.0000*32768),
+	(int16_t)(-0.8315*32768),
+	(int16_t)(-0.9239*32768),
+	(int16_t)(-0.1951*32768),
+	(int16_t)(0.7071*32768),
+	(int16_t)(-0.5556*32768),
+	(int16_t)(-0.9239*32768),
+	(int16_t)(0.1951*32768),
+	(int16_t)(1.0000*32767),
+	(int16_t)(0.1951*32768),
+	(int16_t)(-0.9239*32768),
+	(int16_t)(-0.5556*32768),
+	(int16_t)(0.7071*32768),
+	(int16_t)(0.8315*32768),
+	(int16_t)(-0.3827*32768),
+	(int16_t)(-0.9808*32768),
+	(int16_t)(-0.0000*32768),
+	(int16_t)(0.9808*32768),
+	(int16_t)(0.3827*32768),
+	(int16_t)(-0.8315*32768),
+	(int16_t)(0.7071*32768),
+	(int16_t)(0.5556*32768),
+	(int16_t)(-0.9239*32768),
+	(int16_t)(-0.1951*32768),
+	(int16_t)(1.0000*32767),
+	(int16_t)(-0.1951*32768),
+	(int16_t)(-0.9239*32768),
+	(int16_t)(0.5556*32768),
+	(int16_t)(0.7071*32768),
+	(int16_t)(-0.8315*32768),
+	(int16_t)(-0.3827*32768),
+	(int16_t)(0.9808*32768),
+	(int16_t)(0.0000*32768),
+	(int16_t)(-0.9808*32768),
+	(int16_t)(0.3827*32768),
+	(int16_t)(0.8315*32768),
+	(int16_t)(-0.7071*32768),
+	(int16_t)(0.9808*32768),
+	(int16_t)(-0.3827*32768),
+	(int16_t)(-0.5556*32768),
+	(int16_t)(1.0000*32767),
+	(int16_t)(-0.5556*32768),
+	(int16_t)(-0.3827*32768),
+	(int16_t)(0.9808*32768),
+	(int16_t)(-0.7071*32768),
+	(int16_t)(-0.1951*32768),
+	(int16_t)(0.9239*32768),
+	(int16_t)(-0.8315*32768),
+	(int16_t)(-0.0000*32768),
+	(int16_t)(0.8315*32768),
+	(int16_t)(-0.9239*32768),
+	(int16_t)(0.1951*32768),
+	(int16_t)(-0.7071*32768),
+	(int16_t)(0.1951*32768),
+	(int16_t)(0.3827*32768),
+	(int16_t)(-0.8315*32768),
+	(int16_t)(1.0000*32767),
+	(int16_t)(-0.8315*32768),
+	(int16_t)(0.3827*32768),
+	(int16_t)(0.1951*32768),
+	(int16_t)(-0.7071*32768),
+	(int16_t)(0.9808*32768),
+	(int16_t)(-0.9239*32768),
+	(int16_t)(0.5556*32768),
+	(int16_t)(-0.0000*32768),
+	(int16_t)(-0.5556*32768),
+	(int16_t)(0.9239*32768),
+	(int16_t)(-0.9808*32768),
+	(int16_t)(0.7071*32768),
+	(int16_t)(-0.8315*32768),
+	(int16_t)(0.9239*32768),
+	(int16_t)(-0.9808*32768),
+	(int16_t)(1.0000*32767),
+	(int16_t)(-0.9808*32768),
+	(int16_t)(0.9239*32768),
+	(int16_t)(-0.8315*32768),
+	(int16_t)(0.7071*32768),
+	(int16_t)(-0.5556*32768),
+	(int16_t)(0.3827*32768),
+	(int16_t)(-0.1951*32768),
+	(int16_t)(-0.0000*32768),
+	(int16_t)(0.1951*32768),
+	(int16_t)(-0.3827*32768),
+	(int16_t)(0.5556*32768)
+};
+#endif
diff --git a/bt/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c b/bt/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c
new file mode 100644
index 0000000..f5d439e
--- /dev/null
+++ b/bt/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c
@@ -0,0 +1,199 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 code for bit allocation algorithm. It calculates
+ *  the number of bits required for the encoded stream of data.
+ *
+ ******************************************************************************/
+
+/*Includes*/
+#include "sbc_encoder.h"
+#include "sbc_enc_func_declare.h"
+
+/*global arrays*/
+const int16_t sbc_enc_as16Offset4[4][4] = {  {-1, 0, 0, 0}, {-2, 0, 0, 1},
+                                    {-2, 0, 0, 1}, {-2, 0, 0, 1} };
+const int16_t sbc_enc_as16Offset8[4][8] = {  {-2, 0, 0, 0, 0, 0, 0, 1},
+                                    {-3, 0, 0, 0, 0, 0, 1, 2},
+                                    {-4, 0, 0, 0, 0, 0, 1, 2},
+                                    {-4, 0, 0, 0, 0, 0, 1, 2} };
+
+/****************************************************************************
+* BitAlloc - Calculates the required number of bits for the given scale factor
+* and the number of subbands.
+*
+* RETURNS : N/A
+*/
+
+void sbc_enc_bit_alloc_mono(SBC_ENC_PARAMS *pstrCodecParams)
+{
+    int32_t s32MaxBitNeed;   /*to store the max bits needed per sb*/
+    int32_t s32BitCount;     /*the used number of bits*/
+    int32_t s32SliceCount;   /*to store hwo many slices can be put in bitpool*/
+    int32_t s32BitSlice;     /*number of bitslices in bitpool*/
+    int32_t s32Sb;           /*counter for sub-band*/
+    int32_t s32Ch;           /*counter for channel*/
+    int16_t *ps16BitNeed;    /*temp memory to store required number of bits*/
+    int32_t s32Loudness;     /*used in Loudness calculation*/
+    int16_t *ps16GenBufPtr;
+    int16_t *ps16GenArrPtr;
+    int16_t *ps16GenTabPtr;
+    int32_t  s32NumOfSubBands = pstrCodecParams->s16NumOfSubBands;
+
+    ps16BitNeed = pstrCodecParams->s16ScartchMemForBitAlloc;
+
+    for (s32Ch = 0; s32Ch < pstrCodecParams->s16NumOfChannels; s32Ch++)
+    {
+        ps16GenBufPtr = ps16BitNeed + s32Ch*s32NumOfSubBands;
+        ps16GenArrPtr = pstrCodecParams->as16Bits+s32Ch*SBC_MAX_NUM_OF_SUBBANDS;
+
+        /* bitneed values are derived from scale factor */
+        if (pstrCodecParams->s16AllocationMethod == SBC_SNR)
+        {
+            ps16BitNeed = pstrCodecParams->as16ScaleFactor;
+            ps16GenBufPtr = ps16BitNeed + s32Ch * s32NumOfSubBands;
+        }
+        else
+        {
+            ps16GenBufPtr = ps16BitNeed + s32Ch*s32NumOfSubBands;
+            if(s32NumOfSubBands == 4)
+            {
+                ps16GenTabPtr = (int16_t *)
+                    sbc_enc_as16Offset4[pstrCodecParams->s16SamplingFreq];
+            }
+            else
+            {
+                ps16GenTabPtr = (int16_t *)
+                    sbc_enc_as16Offset8[pstrCodecParams->s16SamplingFreq];
+            }
+            for(s32Sb=0; s32Sb<s32NumOfSubBands; s32Sb++)
+            {
+                if(pstrCodecParams->as16ScaleFactor[s32Ch*s32NumOfSubBands+s32Sb] == 0)
+                    *(ps16GenBufPtr) = -5;
+                else
+                {
+                    s32Loudness =
+                        (int32_t)(pstrCodecParams->as16ScaleFactor[s32Ch*s32NumOfSubBands+s32Sb]
+                                                            - *ps16GenTabPtr);
+                    if(s32Loudness > 0)
+                        *(ps16GenBufPtr) = (int16_t)(s32Loudness >>1);
+                    else
+                        *(ps16GenBufPtr) = (int16_t)s32Loudness;
+                }
+                ps16GenBufPtr++;
+                ps16GenTabPtr++;
+            }
+
+        }
+
+        /* max bitneed index is searched*/
+        s32MaxBitNeed = 0;
+        ps16GenBufPtr = ps16BitNeed + s32Ch*s32NumOfSubBands;
+        for(s32Sb=0; s32Sb<s32NumOfSubBands; s32Sb++)
+        {
+            if( *(ps16GenBufPtr) > s32MaxBitNeed)
+                s32MaxBitNeed = *(ps16GenBufPtr);
+
+            ps16GenBufPtr++;
+        }
+        ps16GenBufPtr = ps16BitNeed + s32Ch*s32NumOfSubBands;
+        /*iterative process to find hwo many bitslices fit into the bitpool*/
+        s32BitSlice = s32MaxBitNeed + 1;
+        s32BitCount = pstrCodecParams->s16BitPool;
+        s32SliceCount = 0;
+        do
+        {
+            s32BitSlice --;
+            s32BitCount -= s32SliceCount;
+            s32SliceCount = 0;
+
+            for(s32Sb=0; s32Sb<s32NumOfSubBands; s32Sb++)
+            {
+                if( (((*ps16GenBufPtr-s32BitSlice)< 16) && (*ps16GenBufPtr-s32BitSlice) >= 1))
+                {
+                    if((*ps16GenBufPtr-s32BitSlice) == 1)
+                        s32SliceCount+=2;
+                    else
+                        s32SliceCount++;
+                }
+                ps16GenBufPtr++;
+
+            }/*end of for*/
+            ps16GenBufPtr = ps16BitNeed + s32Ch*s32NumOfSubBands;
+        }while(s32BitCount-s32SliceCount>0);
+
+        if(s32BitCount == 0)
+        {
+            s32BitCount -= s32SliceCount;
+            s32BitSlice --;
+        }
+
+        /*Bits are distributed until the last bitslice is reached*/
+        ps16GenArrPtr = pstrCodecParams->as16Bits+s32Ch*s32NumOfSubBands;
+        ps16GenBufPtr = ps16BitNeed + s32Ch*s32NumOfSubBands;
+        for(s32Sb=0; s32Sb<s32NumOfSubBands; s32Sb++)
+        {
+            if(*(ps16GenBufPtr) < s32BitSlice+2)
+                *(ps16GenArrPtr) = 0;
+            else
+                *(ps16GenArrPtr) = ((*(ps16GenBufPtr)-s32BitSlice)<16) ?
+                    (int16_t)(*(ps16GenBufPtr)-s32BitSlice) : 16;
+
+            ps16GenBufPtr++;
+            ps16GenArrPtr++;
+        }
+        ps16GenArrPtr = pstrCodecParams->as16Bits+s32Ch*s32NumOfSubBands;
+        ps16GenBufPtr = ps16BitNeed + s32Ch*s32NumOfSubBands;
+        /*the remaining bits are allocated starting at subband 0*/
+        s32Sb=0;
+        while( (s32BitCount > 0) && (s32Sb < s32NumOfSubBands) )
+        {
+            if( (*(ps16GenArrPtr) >= 2) && (*(ps16GenArrPtr) < 16) )
+            {
+                (*(ps16GenArrPtr))++;
+                s32BitCount--;
+            }
+            else if( (*(ps16GenBufPtr) == s32BitSlice+1) &&
+                (s32BitCount > 1) )
+            {
+                *(ps16GenArrPtr) = 2;
+                s32BitCount -= 2;
+            }
+            s32Sb++;
+            ps16GenArrPtr++;
+            ps16GenBufPtr++;
+        }
+        ps16GenArrPtr = pstrCodecParams->as16Bits+s32Ch*s32NumOfSubBands;
+
+
+        s32Sb=0;
+        while( (s32BitCount > 0) && (s32Sb < s32NumOfSubBands) )
+        {
+            if( *(ps16GenArrPtr) < 16)
+            {
+                (*(ps16GenArrPtr))++;
+                s32BitCount--;
+            }
+            s32Sb++;
+            ps16GenArrPtr++;
+        }
+    }
+}
+/*End of BitAlloc() function*/
diff --git a/bt/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c b/bt/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c
new file mode 100644
index 0000000..410c8d6
--- /dev/null
+++ b/bt/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c
@@ -0,0 +1,212 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 code for bit allocation algorithm. It calculates
+ *  the number of bits required for the encoded stream of data.
+ *
+ ******************************************************************************/
+
+/*Includes*/
+#include "sbc_encoder.h"
+#include "sbc_enc_func_declare.h"
+
+/*global arrays*/
+extern const int16_t sbc_enc_as16Offset4[4][4];
+extern const int16_t sbc_enc_as16Offset8[4][8];
+
+/****************************************************************************
+* BitAlloc - Calculates the required number of bits for the given scale factor
+* and the number of subbands.
+*
+* RETURNS : N/A
+*/
+
+void sbc_enc_bit_alloc_ste(SBC_ENC_PARAMS *pstrCodecParams)
+{
+	/* CAUTIOM -> mips optim for arm 32 require to use int32_t instead of int16_t */
+	/* Do not change variable type or name */
+    int32_t s32MaxBitNeed;   /*to store the max bits needed per sb*/
+    int32_t s32BitCount;     /*the used number of bits*/
+    int32_t s32SliceCount;   /*to store hwo many slices can be put in bitpool*/
+    int32_t s32BitSlice;     /*number of bitslices in bitpool*/
+    int32_t s32Sb;           /*counter for sub-band*/
+    int32_t s32Ch;           /*counter for channel*/
+    int16_t *ps16BitNeed;    /*temp memory to store required number of bits*/
+    int32_t s32Loudness;     /*used in Loudness calculation*/
+    int16_t *ps16GenBufPtr,*pas16ScaleFactor;
+    int16_t *ps16GenArrPtr;
+    int16_t *ps16GenTabPtr;
+    int32_t  s32NumOfSubBands = pstrCodecParams->s16NumOfSubBands;
+    int32_t  s32BitPool       = pstrCodecParams->s16BitPool;
+
+    /* bitneed values are derived from scale factor */
+    if (pstrCodecParams->s16AllocationMethod == SBC_SNR)
+    {
+        ps16BitNeed   = pstrCodecParams->as16ScaleFactor;
+        s32MaxBitNeed = pstrCodecParams->s16MaxBitNeed;
+    }
+    else
+    {
+        ps16BitNeed   = pstrCodecParams->s16ScartchMemForBitAlloc;
+        pas16ScaleFactor=pstrCodecParams->as16ScaleFactor;
+        s32MaxBitNeed = 0;
+        ps16GenBufPtr = ps16BitNeed;
+        for (s32Ch = 0; s32Ch < 2; s32Ch++)
+        {
+            if (s32NumOfSubBands == 4)
+            {
+                ps16GenTabPtr = (int16_t *)sbc_enc_as16Offset4[pstrCodecParams->s16SamplingFreq];
+            }
+            else
+            {
+                ps16GenTabPtr = (int16_t *)sbc_enc_as16Offset8[pstrCodecParams->s16SamplingFreq];
+            }
+
+            for (s32Sb = 0; s32Sb < s32NumOfSubBands; s32Sb++)
+            {
+                if (*pas16ScaleFactor == 0)
+                    *ps16GenBufPtr = -5;
+                else
+                {
+                    s32Loudness = (int32_t)(*pas16ScaleFactor - *ps16GenTabPtr);
+
+                    if (s32Loudness > 0)
+                        *ps16GenBufPtr = (int16_t)(s32Loudness >> 1);
+                    else
+                        *ps16GenBufPtr = (int16_t)s32Loudness;
+                }
+
+                if (*ps16GenBufPtr > s32MaxBitNeed)
+                    s32MaxBitNeed = *ps16GenBufPtr;
+                pas16ScaleFactor++;
+                ps16GenBufPtr++;
+                ps16GenTabPtr++;
+            }
+        }
+    }
+
+    /* iterative process to find out hwo many bitslices fit into the bitpool */
+    s32BitSlice = s32MaxBitNeed + 1;
+    s32BitCount = s32BitPool;
+    s32SliceCount = 0;
+    do
+    {
+        s32BitSlice --;
+        s32BitCount -= s32SliceCount;
+        s32SliceCount = 0;
+        ps16GenBufPtr = ps16BitNeed;
+
+        for (s32Sb = 0; s32Sb < 2*s32NumOfSubBands; s32Sb++)
+        {
+            if ( (*ps16GenBufPtr >= s32BitSlice + 1) && (*ps16GenBufPtr < s32BitSlice + 16) )
+            {
+                if (*(ps16GenBufPtr) == s32BitSlice+1)
+                    s32SliceCount += 2;
+                else
+                    s32SliceCount++;
+            }
+            ps16GenBufPtr++;
+        }
+    } while (s32BitCount-s32SliceCount>0);
+
+    if (s32BitCount-s32SliceCount == 0)
+    {
+        s32BitCount -= s32SliceCount;
+        s32BitSlice --;
+    }
+
+    /* Bits are distributed until the last bitslice is reached */
+    ps16GenBufPtr = ps16BitNeed;
+    ps16GenArrPtr = pstrCodecParams->as16Bits;
+    for (s32Ch = 0; s32Ch < 2; s32Ch++)
+    {
+        for (s32Sb = 0; s32Sb < s32NumOfSubBands; s32Sb++)
+        {
+            if (*ps16GenBufPtr < s32BitSlice+2)
+                *ps16GenArrPtr = 0;
+            else
+                *ps16GenArrPtr = ((*(ps16GenBufPtr)-s32BitSlice) < 16) ?
+                                        (int16_t)(*(ps16GenBufPtr)-s32BitSlice):16;
+            ps16GenBufPtr++;
+            ps16GenArrPtr++;
+        }
+    }
+
+    /* the remaining bits are allocated starting at subband 0 */
+    s32Ch=0;
+    s32Sb=0;
+    ps16GenBufPtr = ps16BitNeed;
+    ps16GenArrPtr -= 2*s32NumOfSubBands;
+
+    while ( (s32BitCount > 0) && (s32Sb < s32NumOfSubBands) )
+    {
+        if ( (*(ps16GenArrPtr) >= 2) && (*(ps16GenArrPtr) < 16) )
+        {
+            (*(ps16GenArrPtr))++;
+            s32BitCount--;
+        }
+        else if ((*ps16GenBufPtr == s32BitSlice+1) && (s32BitCount > 1))
+        {
+            *(ps16GenArrPtr) = 2;
+            s32BitCount -= 2;
+        }
+        if(s32Ch == 1)
+        {
+            s32Ch = 0;
+            s32Sb++;
+            ps16GenBufPtr = ps16BitNeed+s32Sb;
+            ps16GenArrPtr = pstrCodecParams->as16Bits+s32Sb;
+
+        }
+        else
+        {
+            s32Ch =1;
+            ps16GenBufPtr = ps16BitNeed+s32NumOfSubBands+s32Sb;
+            ps16GenArrPtr = pstrCodecParams->as16Bits+s32NumOfSubBands+s32Sb;
+        }
+    }
+
+    s32Ch=0;
+    s32Sb=0;
+    ps16GenArrPtr = pstrCodecParams->as16Bits;
+
+    while ((s32BitCount >0) && (s32Sb < s32NumOfSubBands))
+    {
+        if(*(ps16GenArrPtr) < 16)
+        {
+            (*(ps16GenArrPtr))++;
+            s32BitCount--;
+        }
+        if (s32Ch == 1)
+        {
+            s32Ch = 0;
+            s32Sb++;
+            ps16GenArrPtr = pstrCodecParams->as16Bits+s32Sb;
+        }
+        else
+        {
+            s32Ch = 1;
+            ps16GenArrPtr = pstrCodecParams->as16Bits+s32NumOfSubBands+s32Sb;
+        }
+    }
+}
+
+/*End of BitAlloc() function*/
+
diff --git a/bt/embdrv/sbc/encoder/srce/sbc_enc_coeffs.c b/bt/embdrv/sbc/encoder/srce/sbc_enc_coeffs.c
new file mode 100644
index 0000000..95d1fd9
--- /dev/null
+++ b/bt/embdrv/sbc/encoder/srce/sbc_enc_coeffs.c
@@ -0,0 +1,319 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 Windowing coeffs for synthesis filter
+ *
+ ******************************************************************************/
+
+#include "sbc_encoder.h"
+
+#if (SBC_ARM_ASM_OPT == FALSE && SBC_IPAQ_OPT == FALSE)
+#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == FALSE)
+/*Window coeff for 4 sub band case*/
+const int16_t gas32CoeffFor4SBs[] =
+{
+    (int16_t)((int32_t)0x00000000 >> 16),	(int16_t)0x00000000,
+	(int16_t)((int32_t)0x001194E6 >> 16),	(int16_t)0x001194E6,
+	(int16_t)((int32_t)0x0030E2D3 >> 16),	(int16_t)0x0030E2D3,
+	(int16_t)((int32_t)0x00599403 >> 16),	(int16_t)0x00599403,
+	(int16_t)((int32_t)0x007DBCC8 >> 16),	(int16_t)0x007DBCC8,
+	(int16_t)((int32_t)0x007F88E4 >> 16),	(int16_t)0x007F88E4,
+	(int16_t)((int32_t)0x003D239B >> 16),	(int16_t)0x003D239B,
+	(int16_t)((int32_t)0xFF9BB9D5 >> 16),	(int16_t)0xFF9BB9D5,
+
+	(int16_t)((int32_t)0x01659F45 >> 16),	(int16_t)0x01659F45,
+	(int16_t)((int32_t)0x029DBAA3 >> 16),	(int16_t)0x029DBAA3,
+	(int16_t)((int32_t)0x03B23341 >> 16),	(int16_t)0x03B23341,
+	(int16_t)((int32_t)0x041EEE40 >> 16),	(int16_t)0x041EEE40,
+	(int16_t)((int32_t)0x034FEE2C >> 16),	(int16_t)0x034FEE2C,
+	(int16_t)((int32_t)0x00C8F2BC >> 16),	(int16_t)0x00C8F2BC,
+	(int16_t)((int32_t)0xFC4F91D4 >> 16),	(int16_t)0xFC4F91D4,
+	(int16_t)((int32_t)0xF60FAF37 >> 16),	(int16_t)0xF60FAF37,
+
+	(int16_t)((int32_t)0x115B1ED2 >> 16),	(int16_t)0x115B1ED2,
+	(int16_t)((int32_t)0x18F55C90 >> 16),	(int16_t)0x18F55C90,
+	(int16_t)((int32_t)0x1F91CA46 >> 16),	(int16_t)0x1F91CA46,
+	(int16_t)((int32_t)0x2412F251 >> 16),	(int16_t)0x2412F251,
+	(int16_t)((int32_t)0x25AC1FF2 >> 16),	(int16_t)0x25AC1FF2,
+	(int16_t)((int32_t)0x2412F251 >> 16),	(int16_t)0x2412F251,
+	(int16_t)((int32_t)0x1F91CA46 >> 16),	(int16_t)0x1F91CA46,
+	(int16_t)((int32_t)0x18F55C90 >> 16),	(int16_t)0x18F55C90,
+
+	(int16_t)((int32_t)0xEEA4E12E >> 16),	(int16_t)0xEEA4E12E,
+	(int16_t)((int32_t)0xF60FAF37 >> 16),	(int16_t)0xF60FAF37,
+	(int16_t)((int32_t)0xFC4F91D4 >> 16),	(int16_t)0xFC4F91D4,
+	(int16_t)((int32_t)0x00C8F2BC >> 16),	(int16_t)0x00C8F2BC,
+	(int16_t)((int32_t)0x034FEE2C >> 16),	(int16_t)0x034FEE2C,
+	(int16_t)((int32_t)0x041EEE40 >> 16),	(int16_t)0x041EEE40,
+	(int16_t)((int32_t)0x03B23341 >> 16),	(int16_t)0x03B23341,
+	(int16_t)((int32_t)0x029DBAA3 >> 16),	(int16_t)0x029DBAA3,
+
+	(int16_t)((int32_t)0xFE9A60BB >> 16),	(int16_t)0xFE9A60BB,
+	(int16_t)((int32_t)0xFF9BB9D5 >> 16),	(int16_t)0xFF9BB9D5,
+	(int16_t)((int32_t)0x003D239B >> 16),	(int16_t)0x003D239B,
+	(int16_t)((int32_t)0x007F88E4 >> 16),	(int16_t)0x007F88E4,
+	(int16_t)((int32_t)0x007DBCC8 >> 16),	(int16_t)0x007DBCC8,
+	(int16_t)((int32_t)0x00599403 >> 16),	(int16_t)0x00599403,
+	(int16_t)((int32_t)0x0030E2D3 >> 16),	(int16_t)0x0030E2D3,
+	(int16_t)((int32_t)0x001194E6 >> 16),	(int16_t)0x001194E6
+};
+
+/*Window coeff for 8 sub band case*/
+const int16_t gas32CoeffFor8SBs[] =
+{
+    (int16_t)((int32_t)0x00000000 >>16),	(int16_t)0x00000000,
+	(int16_t)((int32_t)0x00052173 >>16),	(int16_t)0x00052173,
+	(int16_t)((int32_t)0x000B3F71 >>16),	(int16_t)0x000B3F71,
+	(int16_t)((int32_t)0x00122C7D >>16),	(int16_t)0x00122C7D,
+	(int16_t)((int32_t)0x001AFF89 >>16),	(int16_t)0x001AFF89,
+	(int16_t)((int32_t)0x00255A62 >>16),	(int16_t)0x00255A62,
+	(int16_t)((int32_t)0x003060F4 >>16),	(int16_t)0x003060F4,
+	(int16_t)((int32_t)0x003A72E7 >>16),	(int16_t)0x003A72E7,
+
+	(int16_t)((int32_t)0x0041EC6A >>16),	(int16_t)0x0041EC6A,  /* 8 */
+	(int16_t)((int32_t)0x0044EF48 >>16),	(int16_t)0x0044EF48,
+	(int16_t)((int32_t)0x00415B75 >>16),	(int16_t)0x00415B75,
+	(int16_t)((int32_t)0x0034F8B6 >>16),	(int16_t)0x0034F8B6,
+	(int16_t)((int32_t)0x001D8FD2 >>16),	(int16_t)0x001D8FD2,
+	(int16_t)((int32_t)0xFFFA2413 >>16),	(int16_t)0xFFFA2413,
+	(int16_t)((int32_t)0xFFC9F10E >>16),	(int16_t)0xFFC9F10E,
+	(int16_t)((int32_t)0xFF8D6793 >>16),	(int16_t)0xFF8D6793,
+
+	(int16_t)((int32_t)0x00B97348 >>16),	(int16_t)0x00B97348,  /* 16 */
+	(int16_t)((int32_t)0x01071B96 >>16),	(int16_t)0x01071B96,
+	(int16_t)((int32_t)0x0156B3CA >>16),	(int16_t)0x0156B3CA,
+	(int16_t)((int32_t)0x01A1B38B >>16),	(int16_t)0x01A1B38B,
+	(int16_t)((int32_t)0x01E0224C >>16),	(int16_t)0x01E0224C,
+	(int16_t)((int32_t)0x0209291F >>16),	(int16_t)0x0209291F,
+	(int16_t)((int32_t)0x02138653 >>16),	(int16_t)0x02138653,
+	(int16_t)((int32_t)0x01F5F424 >>16),	(int16_t)0x01F5F424,
+
+	(int16_t)((int32_t)0x01A7ECEF >>16),	(int16_t)0x01A7ECEF, /* 24 */
+	(int16_t)((int32_t)0x01223EBA >>16),	(int16_t)0x01223EBA,
+	(int16_t)((int32_t)0x005FD0FF >>16),	(int16_t)0x005FD0FF,
+	(int16_t)((int32_t)0xFF5EEB73 >>16),	(int16_t)0xFF5EEB73,
+	(int16_t)((int32_t)0xFE20435D >>16),	(int16_t)0xFE20435D,
+	(int16_t)((int32_t)0xFCA86E7E >>16),	(int16_t)0xFCA86E7E,
+	(int16_t)((int32_t)0xFAFF95FC >>16),	(int16_t)0xFAFF95FC,
+	(int16_t)((int32_t)0xF9312891 >>16),	(int16_t)0xF9312891,
+
+	(int16_t)((int32_t)0x08B4307A >>16),	(int16_t)0x08B4307A, /* 32 */
+	(int16_t)((int32_t)0x0A9F3E9A >>16),	(int16_t)0x0A9F3E9A,
+	(int16_t)((int32_t)0x0C7D59B6 >>16),	(int16_t)0x0C7D59B6,
+	(int16_t)((int32_t)0x0E3BB16F >>16),	(int16_t)0x0E3BB16F,
+	(int16_t)((int32_t)0x0FC721F9 >>16),	(int16_t)0x0FC721F9,
+	(int16_t)((int32_t)0x110ECEF0 >>16),	(int16_t)0x110ECEF0,
+	(int16_t)((int32_t)0x120435FA >>16),	(int16_t)0x120435FA,
+	(int16_t)((int32_t)0x129C226F >>16),	(int16_t)0x129C226F,
+
+	(int16_t)((int32_t)0x12CF6C75 >>16),	(int16_t)0x12CF6C75, /* 40 */
+	(int16_t)((int32_t)0x129C226F >>16),	(int16_t)0x129C226F,
+	(int16_t)((int32_t)0x120435FA >>16),	(int16_t)0x120435FA,
+	(int16_t)((int32_t)0x110ECEF0 >>16),	(int16_t)0x110ECEF0,
+	(int16_t)((int32_t)0x0FC721F9 >>16),	(int16_t)0x0FC721F9,
+	(int16_t)((int32_t)0x0E3BB16F >>16),	(int16_t)0x0E3BB16F,
+	(int16_t)((int32_t)0x0C7D59B6 >>16),	(int16_t)0x0C7D59B6,
+	(int16_t)((int32_t)0x0A9F3E9A >>16),	(int16_t)0x0A9F3E9A,
+
+	(int16_t)((int32_t)0xF74BCF86 >>16),	(int16_t)0xF74BCF86, /* 48 */
+	(int16_t)((int32_t)0xF9312891 >>16),	(int16_t)0xF9312891,
+	(int16_t)((int32_t)0xFAFF95FC >>16),	(int16_t)0xFAFF95FC,
+	(int16_t)((int32_t)0xFCA86E7E >>16),	(int16_t)0xFCA86E7E,
+	(int16_t)((int32_t)0xFE20435D >>16),	(int16_t)0xFE20435D,
+	(int16_t)((int32_t)0xFF5EEB73 >>16),	(int16_t)0xFF5EEB73,
+	(int16_t)((int32_t)0x005FD0FF >>16),	(int16_t)0x005FD0FF,
+	(int16_t)((int32_t)0x01223EBA >>16),	(int16_t)0x01223EBA,
+
+	(int16_t)((int32_t)0x01A7ECEF >>16),	(int16_t)0x01A7ECEF, /* 56 */
+	(int16_t)((int32_t)0x01F5F424 >>16),	(int16_t)0x01F5F424,
+	(int16_t)((int32_t)0x02138653 >>16),	(int16_t)0x02138653,
+	(int16_t)((int32_t)0x0209291F >>16),	(int16_t)0x0209291F,
+	(int16_t)((int32_t)0x01E0224C >>16),	(int16_t)0x01E0224C,
+	(int16_t)((int32_t)0x01A1B38B >>16),	(int16_t)0x01A1B38B,
+	(int16_t)((int32_t)0x0156B3CA >>16),	(int16_t)0x0156B3CA,
+	(int16_t)((int32_t)0x01071B96 >>16),	(int16_t)0x01071B96,
+
+	(int16_t)((int32_t)0xFF468CB8 >>16),	(int16_t)0xFF468CB8, /* 64 */
+	(int16_t)((int32_t)0xFF8D6793 >>16),	(int16_t)0xFF8D6793,
+	(int16_t)((int32_t)0xFFC9F10E >>16),	(int16_t)0xFFC9F10E,
+	(int16_t)((int32_t)0xFFFA2413 >>16),	(int16_t)0xFFFA2413,
+	(int16_t)((int32_t)0x001D8FD2 >>16),	(int16_t)0x001D8FD2,
+	(int16_t)((int32_t)0x0034F8B6 >>16),	(int16_t)0x0034F8B6,
+	(int16_t)((int32_t)0x00415B75 >>16),	(int16_t)0x00415B75,
+	(int16_t)((int32_t)0x0044EF48 >>16),	(int16_t)0x0044EF48,
+
+	(int16_t)((int32_t)0x0041EC6A >>16),	(int16_t)0x0041EC6A, /* 72 */
+	(int16_t)((int32_t)0x003A72E7 >>16),	(int16_t)0x003A72E7,
+	(int16_t)((int32_t)0x003060F4 >>16),	(int16_t)0x003060F4,
+	(int16_t)((int32_t)0x00255A62 >>16),	(int16_t)0x00255A62,
+	(int16_t)((int32_t)0x001AFF89 >>16),	(int16_t)0x001AFF89,
+	(int16_t)((int32_t)0x00122C7D >>16),	(int16_t)0x00122C7D,
+	(int16_t)((int32_t)0x000B3F71 >>16),	(int16_t)0x000B3F71,
+	(int16_t)((int32_t)0x00052173 >>16),	(int16_t)0x00052173
+};
+
+#else
+
+/*Window coeff for 4 sub band case*/
+const int32_t gas32CoeffFor4SBs[] =
+{
+    (int32_t)0x00000000,
+	(int32_t)0x001194E6,
+	(int32_t)0x0030E2D3,
+	(int32_t)0x00599403,
+	(int32_t)0x007DBCC8,
+	(int32_t)0x007F88E4,
+	(int32_t)0x003D239B,
+	(int32_t)0xFF9BB9D5,
+
+	(int32_t)0x01659F45,
+	(int32_t)0x029DBAA3,
+	(int32_t)0x03B23341,
+	(int32_t)0x041EEE40,
+	(int32_t)0x034FEE2C,
+	(int32_t)0x00C8F2BC,
+	(int32_t)0xFC4F91D4,
+	(int32_t)0xF60FAF37,
+
+	(int32_t)0x115B1ED2,
+	(int32_t)0x18F55C90,
+	(int32_t)0x1F91CA46,
+	(int32_t)0x2412F251,
+	(int32_t)0x25AC1FF2,
+	(int32_t)0x2412F251,
+	(int32_t)0x1F91CA46,
+	(int32_t)0x18F55C90,
+
+	(int32_t)0xEEA4E12E,
+	(int32_t)0xF60FAF37,
+	(int32_t)0xFC4F91D4,
+	(int32_t)0x00C8F2BC,
+	(int32_t)0x034FEE2C,
+	(int32_t)0x041EEE40,
+	(int32_t)0x03B23341,
+	(int32_t)0x029DBAA3,
+
+	(int32_t)0xFE9A60BB,
+	(int32_t)0xFF9BB9D5,
+	(int32_t)0x003D239B,
+	(int32_t)0x007F88E4,
+	(int32_t)0x007DBCC8,
+	(int32_t)0x00599403,
+	(int32_t)0x0030E2D3,
+	(int32_t)0x001194E6
+};
+
+/*Window coeff for 8 sub band case*/
+const int32_t gas32CoeffFor8SBs[] =
+{
+    (int32_t)0x00000000,
+	(int32_t)0x00052173,
+	(int32_t)0x000B3F71,
+	(int32_t)0x00122C7D,
+	(int32_t)0x001AFF89,
+	(int32_t)0x00255A62,
+	(int32_t)0x003060F4,
+	(int32_t)0x003A72E7,
+
+	(int32_t)0x0041EC6A,  /* 8 */
+	(int32_t)0x0044EF48,
+	(int32_t)0x00415B75,
+	(int32_t)0x0034F8B6,
+	(int32_t)0x001D8FD2,
+	(int32_t)0xFFFA2413,
+	(int32_t)0xFFC9F10E,
+	(int32_t)0xFF8D6793,
+
+	(int32_t)0x00B97348,  /* 16 */
+	(int32_t)0x01071B96,
+	(int32_t)0x0156B3CA,
+	(int32_t)0x01A1B38B,
+	(int32_t)0x01E0224C,
+	(int32_t)0x0209291F,
+	(int32_t)0x02138653,
+	(int32_t)0x01F5F424,
+
+	(int32_t)0x01A7ECEF, /* 24 */
+	(int32_t)0x01223EBA,
+	(int32_t)0x005FD0FF,
+	(int32_t)0xFF5EEB73,
+	(int32_t)0xFE20435D,
+	(int32_t)0xFCA86E7E,
+	(int32_t)0xFAFF95FC,
+	(int32_t)0xF9312891,
+
+	(int32_t)0x08B4307A, /* 32 */
+	(int32_t)0x0A9F3E9A,
+	(int32_t)0x0C7D59B6,
+	(int32_t)0x0E3BB16F,
+	(int32_t)0x0FC721F9,
+	(int32_t)0x110ECEF0,
+	(int32_t)0x120435FA,
+	(int32_t)0x129C226F,
+
+	(int32_t)0x12CF6C75, /* 40 */
+	(int32_t)0x129C226F,
+	(int32_t)0x120435FA,
+	(int32_t)0x110ECEF0,
+	(int32_t)0x0FC721F9,
+	(int32_t)0x0E3BB16F,
+	(int32_t)0x0C7D59B6,
+	(int32_t)0x0A9F3E9A,
+
+	(int32_t)0xF74BCF86, /* 48 */
+	(int32_t)0xF9312891,
+	(int32_t)0xFAFF95FC,
+	(int32_t)0xFCA86E7E,
+	(int32_t)0xFE20435D,
+	(int32_t)0xFF5EEB73,
+	(int32_t)0x005FD0FF,
+	(int32_t)0x01223EBA,
+
+	(int32_t)0x01A7ECEF, /* 56 */
+	(int32_t)0x01F5F424,
+	(int32_t)0x02138653,
+	(int32_t)0x0209291F,
+	(int32_t)0x01E0224C,
+	(int32_t)0x01A1B38B,
+	(int32_t)0x0156B3CA,
+	(int32_t)0x01071B96,
+
+	(int32_t)0xFF468CB8, /* 64 */
+	(int32_t)0xFF8D6793,
+	(int32_t)0xFFC9F10E,
+	(int32_t)0xFFFA2413,
+	(int32_t)0x001D8FD2,
+	(int32_t)0x0034F8B6,
+	(int32_t)0x00415B75,
+	(int32_t)0x0044EF48,
+
+	(int32_t)0x0041EC6A, /* 72 */
+	(int32_t)0x003A72E7,
+	(int32_t)0x003060F4,
+	(int32_t)0x00255A62,
+	(int32_t)0x001AFF89,
+	(int32_t)0x00122C7D,
+	(int32_t)0x000B3F71,
+	(int32_t)0x00052173
+};
+
+#endif
+#endif
+
diff --git a/bt/embdrv/sbc/encoder/srce/sbc_encoder.c b/bt/embdrv/sbc/encoder/srce/sbc_encoder.c
new file mode 100644
index 0000000..11ca62c
--- /dev/null
+++ b/bt/embdrv/sbc/encoder/srce/sbc_encoder.c
@@ -0,0 +1,285 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  contains code for encoder flow and initalization of encoder
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_target.h"
+#include "sbc_encoder.h"
+#include "sbc_enc_func_declare.h"
+
+int16_t EncMaxShiftCounter;
+
+#if (SBC_JOINT_STE_INCLUDED == TRUE)
+int32_t   s32LRDiff[SBC_MAX_NUM_OF_BLOCKS]    = {0};
+int32_t   s32LRSum[SBC_MAX_NUM_OF_BLOCKS]     = {0};
+#endif
+
+uint32_t SBC_Encode(SBC_ENC_PARAMS *pstrEncParams, int16_t *input, uint8_t *output)
+{
+    int32_t s32Ch;                               /* counter for ch*/
+    int32_t s32Sb;                               /* counter for sub-band*/
+    uint32_t u32Count, maxBit = 0;                          /* loop count*/
+    int32_t s32MaxValue;                         /* temp variable to store max value */
+
+    int16_t *ps16ScfL;
+    int32_t *SbBuffer;
+    int32_t s32Blk;                              /* counter for block*/
+    int32_t  s32NumOfBlocks   = pstrEncParams->s16NumOfBlocks;
+#if (SBC_JOINT_STE_INCLUDED == TRUE)
+    int32_t s32MaxValue2;
+    uint32_t u32CountSum,u32CountDiff;
+    int32_t *pSum, *pDiff;
+#endif
+    register int32_t  s32NumOfSubBands = pstrEncParams->s16NumOfSubBands;
+
+    /* SBC ananlysis filter*/
+    if (s32NumOfSubBands == 4)
+        SbcAnalysisFilter4(pstrEncParams, input);
+    else
+        SbcAnalysisFilter8(pstrEncParams, input);
+
+    /* compute the scale factor, and save the max */
+    ps16ScfL = pstrEncParams->as16ScaleFactor;
+    s32Ch=pstrEncParams->s16NumOfChannels*s32NumOfSubBands;
+
+    for (s32Sb=0; s32Sb<s32Ch; s32Sb++)
+    {
+        SbBuffer=pstrEncParams->s32SbBuffer+s32Sb;
+        s32MaxValue=0;
+        for (s32Blk=s32NumOfBlocks;s32Blk>0;s32Blk--)
+        {
+            if (s32MaxValue<abs32(*SbBuffer))
+                s32MaxValue=abs32(*SbBuffer);
+            SbBuffer+=s32Ch;
+        }
+
+        u32Count = (s32MaxValue > 0x800000) ? 9 : 0;
+
+        for ( ; u32Count < 15; u32Count++)
+        {
+            if (s32MaxValue <= (int32_t)(0x8000 << u32Count))
+                break;
+        }
+        *ps16ScfL++ = (int16_t)u32Count;
+
+        if (u32Count > maxBit)
+            maxBit = u32Count;
+    }
+    /* In case of JS processing,check whether to use JS */
+#if (SBC_JOINT_STE_INCLUDED == TRUE)
+    if (pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO)
+    {
+        /* Calculate sum and differance  scale factors for making JS decision   */
+        ps16ScfL = pstrEncParams->as16ScaleFactor ;
+        /* calculate the scale factor of Joint stereo max sum and diff */
+        for (s32Sb = 0; s32Sb < s32NumOfSubBands-1; s32Sb++)
+        {
+            SbBuffer=pstrEncParams->s32SbBuffer+s32Sb;
+            s32MaxValue2=0;
+            s32MaxValue=0;
+            pSum       = s32LRSum;
+            pDiff      = s32LRDiff;
+            for (s32Blk=0;s32Blk<s32NumOfBlocks;s32Blk++)
+            {
+                *pSum=(*SbBuffer+*(SbBuffer+s32NumOfSubBands))>>1;
+                if (abs32(*pSum)>s32MaxValue)
+                    s32MaxValue=abs32(*pSum);
+                pSum++;
+                *pDiff=(*SbBuffer-*(SbBuffer+s32NumOfSubBands))>>1;
+                if (abs32(*pDiff)>s32MaxValue2)
+                    s32MaxValue2=abs32(*pDiff);
+                pDiff++;
+                SbBuffer+=s32Ch;
+            }
+            u32Count = (s32MaxValue > 0x800000) ? 9 : 0;
+            for ( ; u32Count < 15; u32Count++)
+            {
+                if (s32MaxValue <= (int32_t)(0x8000 << u32Count))
+                    break;
+            }
+            u32CountSum=u32Count;
+            u32Count = (s32MaxValue2 > 0x800000) ? 9 : 0;
+            for ( ; u32Count < 15; u32Count++)
+            {
+                if (s32MaxValue2 <= (int32_t)(0x8000 << u32Count))
+                    break;
+            }
+            u32CountDiff=u32Count;
+            if ( (*ps16ScfL + *(ps16ScfL+s32NumOfSubBands)) > (int16_t)(u32CountSum + u32CountDiff) )
+            {
+
+                if (u32CountSum > maxBit)
+                    maxBit = u32CountSum;
+
+                if (u32CountDiff > maxBit)
+                    maxBit = u32CountDiff;
+
+                *ps16ScfL = (int16_t)u32CountSum;
+                *(ps16ScfL+s32NumOfSubBands) = (int16_t)u32CountDiff;
+
+                SbBuffer=pstrEncParams->s32SbBuffer+s32Sb;
+                pSum       = s32LRSum;
+                pDiff      = s32LRDiff;
+
+                for (s32Blk = 0; s32Blk < s32NumOfBlocks; s32Blk++)
+                {
+                    *SbBuffer = *pSum;
+                    *(SbBuffer+s32NumOfSubBands) = *pDiff;
+
+                    SbBuffer += s32NumOfSubBands<<1;
+                    pSum++;
+                    pDiff++;
+                }
+
+                pstrEncParams->as16Join[s32Sb] = 1;
+            }
+            else
+            {
+                pstrEncParams->as16Join[s32Sb] = 0;
+            }
+            ps16ScfL++;
+        }
+        pstrEncParams->as16Join[s32Sb] = 0;
+    }
+#endif
+
+    pstrEncParams->s16MaxBitNeed = (int16_t)maxBit;
+
+    /* bit allocation */
+    if ((pstrEncParams->s16ChannelMode == SBC_STEREO) || (pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO))
+        sbc_enc_bit_alloc_ste(pstrEncParams);
+    else
+        sbc_enc_bit_alloc_mono(pstrEncParams);
+
+    /* Quantize the encoded audio */
+    return EncPacking(pstrEncParams, output);
+}
+
+/****************************************************************************
+* InitSbcAnalysisFilt - Initalizes the input data to 0
+*
+* RETURNS : N/A
+*/
+void SBC_Encoder_Init(SBC_ENC_PARAMS *pstrEncParams)
+{
+    uint16_t s16SamplingFreq; /*temp variable to store smpling freq*/
+    int16_t s16Bitpool;      /*to store bit pool value*/
+    int16_t s16BitRate;      /*to store bitrate*/
+    int16_t s16FrameLen;     /*to store frame length*/
+    uint16_t HeaderParams;
+
+    /* Required number of channels */
+    if (pstrEncParams->s16ChannelMode == SBC_MONO)
+        pstrEncParams->s16NumOfChannels = 1;
+    else
+        pstrEncParams->s16NumOfChannels = 2;
+
+    /* Bit pool calculation */
+    if (pstrEncParams->s16SamplingFreq == SBC_sf16000)
+        s16SamplingFreq = 16000;
+    else if (pstrEncParams->s16SamplingFreq == SBC_sf32000)
+        s16SamplingFreq = 32000;
+    else if (pstrEncParams->s16SamplingFreq == SBC_sf44100)
+        s16SamplingFreq = 44100;
+    else
+        s16SamplingFreq = 48000;
+
+    if ( (pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO)
+        ||  (pstrEncParams->s16ChannelMode == SBC_STEREO) )
+    {
+        s16Bitpool = (int16_t)( (pstrEncParams->u16BitRate *
+            pstrEncParams->s16NumOfSubBands * 1000 / s16SamplingFreq)
+            -( (32 + (4 * pstrEncParams->s16NumOfSubBands *
+            pstrEncParams->s16NumOfChannels)
+            + ( (pstrEncParams->s16ChannelMode - 2) *
+            pstrEncParams->s16NumOfSubBands )   )
+            / pstrEncParams->s16NumOfBlocks) );
+
+        s16FrameLen = 4 + (4*pstrEncParams->s16NumOfSubBands*
+            pstrEncParams->s16NumOfChannels)/8
+            + ( ((pstrEncParams->s16ChannelMode - 2) *
+            pstrEncParams->s16NumOfSubBands)
+            + (pstrEncParams->s16NumOfBlocks * s16Bitpool) ) / 8;
+
+        s16BitRate = (8 * s16FrameLen * s16SamplingFreq)
+            / (pstrEncParams->s16NumOfSubBands *
+            pstrEncParams->s16NumOfBlocks * 1000);
+
+        if (s16BitRate > pstrEncParams->u16BitRate)
+            s16Bitpool--;
+
+        if(pstrEncParams->s16NumOfSubBands == 8)
+            pstrEncParams->s16BitPool = (s16Bitpool > 255) ? 255 : s16Bitpool;
+        else
+            pstrEncParams->s16BitPool = (s16Bitpool > 128) ? 128 : s16Bitpool;
+    }
+    else
+    {
+        s16Bitpool = (int16_t)( ((pstrEncParams->s16NumOfSubBands *
+            pstrEncParams->u16BitRate * 1000)
+            / (s16SamplingFreq * pstrEncParams->s16NumOfChannels))
+            -( ( (32 / pstrEncParams->s16NumOfChannels) +
+            (4 * pstrEncParams->s16NumOfSubBands) )
+            /   pstrEncParams->s16NumOfBlocks ) );
+
+        pstrEncParams->s16BitPool = (s16Bitpool >
+            (16 * pstrEncParams->s16NumOfSubBands))
+            ? (16*pstrEncParams->s16NumOfSubBands) : s16Bitpool;
+    }
+
+    if (pstrEncParams->s16BitPool < 0)
+        pstrEncParams->s16BitPool = 0;
+    /* sampling freq */
+    HeaderParams = ((pstrEncParams->s16SamplingFreq & 3)<< 6);
+
+    /* number of blocks*/
+    HeaderParams |= (((pstrEncParams->s16NumOfBlocks -4) & 12) << 2);
+
+    /* channel mode: mono, dual...*/
+    HeaderParams |= ((pstrEncParams->s16ChannelMode & 3)<< 2);
+
+    /* Loudness or SNR */
+    HeaderParams |= ((pstrEncParams->s16AllocationMethod & 1)<< 1);
+    HeaderParams |= ((pstrEncParams->s16NumOfSubBands >> 3) & 1);  /*4 or 8*/
+    pstrEncParams->FrameHeader=HeaderParams;
+
+    if (pstrEncParams->s16NumOfSubBands==4)
+    {
+        if (pstrEncParams->s16NumOfChannels==1)
+            EncMaxShiftCounter=((ENC_VX_BUFFER_SIZE-4*10)>>2)<<2;
+        else
+            EncMaxShiftCounter=((ENC_VX_BUFFER_SIZE-4*10*2)>>3)<<2;
+    }
+    else
+    {
+        if (pstrEncParams->s16NumOfChannels==1)
+            EncMaxShiftCounter=((ENC_VX_BUFFER_SIZE-8*10)>>3)<<3;
+        else
+            EncMaxShiftCounter=((ENC_VX_BUFFER_SIZE-8*10*2)>>4)<<3;
+    }
+
+    APPL_TRACE_EVENT("SBC_Encoder_Init : bitrate %d, bitpool %d",
+            pstrEncParams->u16BitRate, pstrEncParams->s16BitPool);
+
+    SbcAnalysisInit();
+}
diff --git a/bt/embdrv/sbc/encoder/srce/sbc_packing.c b/bt/embdrv/sbc/encoder/srce/sbc_packing.c
new file mode 100644
index 0000000..277eda8
--- /dev/null
+++ b/bt/embdrv/sbc/encoder/srce/sbc_packing.c
@@ -0,0 +1,273 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 code for packing the Encoded data into bit streams.
+ *
+ ******************************************************************************/
+
+#include "sbc_encoder.h"
+#include "sbc_enc_func_declare.h"
+
+#if (SBC_ARM_ASM_OPT == TRUE)
+#define Mult32(s32In1,s32In2,s32OutLow)                                                 \
+{                                                                                       \
+   __asm                                                                                \
+   {                                                                                    \
+        MUL s32OutLow,s32In1,s32In2;                                                    \
+    }                                                                                   \
+}
+#define Mult64(s32In1, s32In2, s32OutLow, s32OutHi)                                     \
+{                                                                                       \
+    __asm													        					\
+    {														    						\
+        SMULL s32OutLow,s32OutHi,s32In1,s32In2          	    						\
+    }														    						\
+}
+#else
+#define Mult32(s32In1,s32In2,s32OutLow) s32OutLow=(int32_t)(s32In1)*(int32_t)(s32In2);
+#define Mult64(s32In1, s32In2, s32OutLow, s32OutHi)                                     \
+{                                                                                       \
+	(s32OutLow) = ((int32_t)(uint16_t)(s32In1) * (uint16_t)(s32In2));                \
+	s32TempVal2 = (int32_t)(((s32In1) >> 16) * (uint16_t)(s32In2));                  \
+	s32Carry    = ((((uint32_t)(s32OutLow)>>16)&0xFFFF) +                           \
+										+ (s32TempVal2 & 0xFFFF) ) >> 16;               \
+	(s32OutLow) += (s32TempVal2 << 16);                                             \
+	(s32OutHi)  = (s32TempVal2 >> 16) + s32Carry;                                   \
+}
+#endif
+
+/* return number of bytes written to output */
+uint32_t EncPacking(SBC_ENC_PARAMS *pstrEncParams, uint8_t *output)
+{
+    uint8_t     *pu8PacketPtr;                      /* packet ptr*/
+    uint8_t Temp;
+    int32_t      s32Blk;                             /* counter for block*/
+    int32_t      s32Ch;                              /* counter for channel*/
+    int32_t      s32Sb;                              /* counter for sub-band*/
+    int32_t s32PresentBit;                      /* represents bit to be stored*/
+    /*int32_t s32LoopCountI;                       loop counter*/
+    int32_t s32LoopCountJ;                      /* loop counter*/
+    uint32_t u32QuantizedSbValue,u32QuantizedSbValue0; /* temp variable to store quantized sb val*/
+    int32_t s32LoopCount;                       /* loop counter*/
+    uint8_t u8XoredVal;                         /* to store XORed value in CRC calculation*/
+    uint8_t u8CRC;                              /* to store CRC value*/
+    int16_t *ps16GenPtr;
+    int32_t s32NumOfBlocks;
+    int32_t s32NumOfSubBands = pstrEncParams->s16NumOfSubBands;
+    int32_t s32NumOfChannels = pstrEncParams->s16NumOfChannels;
+	uint32_t u32SfRaisedToPow2;	/*scale factor raised to power 2*/
+    int16_t *ps16ScfPtr;
+    int32_t *ps32SbPtr;
+	uint16_t u16Levels;	/*to store levels*/
+	int32_t s32Temp1;	/*used in 64-bit multiplication*/
+	int32_t s32Low;	/*used in 64-bit multiplication*/
+#if (SBC_IS_64_MULT_IN_QUANTIZER == TRUE)
+	int32_t s32Hi1,s32Low1,s32Carry,s32TempVal2,s32Hi, s32Temp2;
+#endif
+
+    pu8PacketPtr    = output;    /*Initialize the ptr*/
+    *pu8PacketPtr++ = (uint8_t)0x9C;  /*Sync word*/
+    *pu8PacketPtr++=(uint8_t)(pstrEncParams->FrameHeader);
+
+    *pu8PacketPtr = (uint8_t)(pstrEncParams->s16BitPool & 0x00FF);
+    pu8PacketPtr += 2;  /*skip for CRC*/
+
+    /*here it indicate if it is byte boundary or nibble boundary*/
+    s32PresentBit = 8;
+    Temp=0;
+#if (SBC_JOINT_STE_INCLUDED == TRUE)
+    if (pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO)
+    {
+        /* pack join stero parameters */
+        for (s32Sb = 0; s32Sb < s32NumOfSubBands; s32Sb++)
+        {
+            Temp <<= 1;
+            Temp |= pstrEncParams->as16Join[s32Sb];
+        }
+
+        /* pack RFA */
+        if (s32NumOfSubBands == SUB_BANDS_4)
+        {
+            s32PresentBit = 4;
+        }
+        else
+        {
+            *(pu8PacketPtr++)=Temp;
+            Temp = 0;
+        }
+    }
+#endif
+
+    /* Pack Scale factor */
+    ps16GenPtr = pstrEncParams->as16ScaleFactor;
+    s32Sb=s32NumOfChannels*s32NumOfSubBands;
+    /*Temp=*pu8PacketPtr;*/
+    for (s32Ch = s32Sb; s32Ch >0; s32Ch--)
+    {
+        Temp<<= 4;
+        Temp |= *ps16GenPtr++;
+
+        if(s32PresentBit == 4)
+        {
+            s32PresentBit = 8;
+            *(pu8PacketPtr++)=Temp;
+            Temp = 0;
+        }
+        else
+        {
+            s32PresentBit = 4;
+        }
+    }
+
+    /* Pack samples */
+    ps32SbPtr   = pstrEncParams->s32SbBuffer;
+    /*Temp=*pu8PacketPtr;*/
+    s32NumOfBlocks= pstrEncParams->s16NumOfBlocks;
+    for (s32Blk = s32NumOfBlocks-1; s32Blk >=0; s32Blk--)
+    {
+        ps16GenPtr  = pstrEncParams->as16Bits;
+        ps16ScfPtr  = pstrEncParams->as16ScaleFactor;
+        for (s32Ch = s32Sb-1; s32Ch >= 0; s32Ch--)
+        {
+            s32LoopCount = *ps16GenPtr++;
+            if (s32LoopCount != 0)
+            {
+#if (SBC_IS_64_MULT_IN_QUANTIZER == TRUE)
+                /* finding level from reconstruction part of decoder */
+                u32SfRaisedToPow2 = ((uint32_t)1 << ((*ps16ScfPtr)+1));
+                u16Levels = (uint16_t)(((uint32_t)1 << s32LoopCount) - 1);
+
+                /* quantizer */
+                s32Temp1 = (*ps32SbPtr >> 2) + (u32SfRaisedToPow2 << 12);
+                s32Temp2 = u16Levels;
+
+                Mult64 (s32Temp1, s32Temp2, s32Low, s32Hi);
+
+                s32Low1   = s32Low >> ((*ps16ScfPtr)+2);
+                s32Low1  &= ((uint32_t)1 << (32 - ((*ps16ScfPtr)+2))) - 1;
+                s32Hi1    = s32Hi << (32 - ((*ps16ScfPtr) +2));
+
+                u32QuantizedSbValue0 = (uint16_t)((s32Low1 | s32Hi1) >> 12);
+#else
+                /* finding level from reconstruction part of decoder */
+                u32SfRaisedToPow2 = ((uint32_t)1 << *ps16ScfPtr);
+                u16Levels = (uint16_t)(((uint32_t)1 << s32LoopCount)-1);
+
+                /* quantizer */
+                s32Temp1 = (*ps32SbPtr >> 15) + u32SfRaisedToPow2;
+                Mult32(s32Temp1,u16Levels,s32Low);
+                s32Low>>= (*ps16ScfPtr+1);
+                u32QuantizedSbValue0 = (uint16_t)s32Low;
+#endif
+                /*store the number of bits required and the quantized s32Sb
+                sample to ease the coding*/
+                u32QuantizedSbValue = u32QuantizedSbValue0;
+
+                if(s32PresentBit >= s32LoopCount)
+                {
+                    Temp <<= s32LoopCount;
+                    Temp |= u32QuantizedSbValue;
+                    s32PresentBit -= s32LoopCount;
+                }
+                else
+                {
+                    while (s32PresentBit < s32LoopCount)
+                    {
+                        s32LoopCount -= s32PresentBit;
+                        u32QuantizedSbValue >>= s32LoopCount;
+
+                        /*remove the unwanted msbs*/
+                        /*u32QuantizedSbValue <<= 16 - s32PresentBit;
+                        u32QuantizedSbValue >>= 16 - s32PresentBit;*/
+
+                        Temp <<= s32PresentBit;
+
+                        Temp |= u32QuantizedSbValue ;
+                        /*restore the original*/
+                        u32QuantizedSbValue=u32QuantizedSbValue0;
+
+                        *(pu8PacketPtr++)=Temp;
+                        Temp = 0;
+                        s32PresentBit = 8;
+                    }
+                    Temp <<= s32LoopCount;
+
+                    /* remove the unwanted msbs */
+                    /*u32QuantizedSbValue <<= 16 - s32LoopCount;
+                    u32QuantizedSbValue >>= 16 - s32LoopCount;*/
+
+                    Temp |= u32QuantizedSbValue;
+
+                    s32PresentBit -= s32LoopCount;
+                }
+            }
+            ps16ScfPtr++;
+            ps32SbPtr++;
+        }
+    }
+
+    Temp <<= s32PresentBit;
+    *pu8PacketPtr=Temp;
+    uint32_t u16PacketLength=pu8PacketPtr-output+1;
+    /*find CRC*/
+    pu8PacketPtr = output+1;    /*Initialize the ptr*/
+    u8CRC = 0x0F;
+    s32LoopCount = s32Sb >> 1;
+
+    /*
+    The loops is run from the start of the packet till the scale factor
+    parameters. In case of JS, 'join' parameter is included in the packet
+    so that many more bytes are included in CRC calculation.
+    */
+    Temp=*pu8PacketPtr;
+    for (s32Ch=1; s32Ch < (s32LoopCount+4); s32Ch++)
+    {
+        /* skip sync word and CRC bytes */
+        if (s32Ch != 3)
+        {
+            for (s32LoopCountJ=7; s32LoopCountJ>=0; s32LoopCountJ--)
+            {
+                u8XoredVal = ((u8CRC >> 7) & 0x01) ^((Temp >> s32LoopCountJ) & 0x01);
+                u8CRC <<= 1;
+                u8CRC ^= (u8XoredVal * 0x1D);
+                u8CRC &= 0xFF;
+            }
+        }
+        Temp=*(++pu8PacketPtr);
+    }
+
+    if (pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO)
+    {
+        for (s32LoopCountJ = 7; s32LoopCountJ >= (8 - s32NumOfSubBands); s32LoopCountJ--)
+        {
+            u8XoredVal = ((u8CRC >> 7) & 0x01) ^((Temp >> s32LoopCountJ) & 0x01);
+            u8CRC <<= 1;
+            u8CRC ^= (u8XoredVal * 0x1D);
+            u8CRC &= 0xFF;
+        }
+    }
+
+    /* CRC calculation ends here */
+
+    /* store CRC in packet */
+    output[3] = u8CRC;
+    return u16PacketLength;
+}
+
diff --git a/bt/hci/Android.mk b/bt/hci/Android.mk
new file mode 100644
index 0000000..023c7af
--- /dev/null
+++ b/bt/hci/Android.mk
@@ -0,0 +1,91 @@
+LOCAL_PATH := $(call my-dir)
+
+# HCI static library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+
+LOCAL_SRC_FILES := \
+    src/btsnoop.cc \
+    src/btsnoop_mem.cc \
+    src/btsnoop_net.cc \
+    src/buffer_allocator.cc \
+    src/hci_audio.cc \
+    src/hci_hal.cc \
+    src/hci_hal_h4.cc \
+    src/hci_hal_mct.cc \
+    src/hci_inject.cc \
+    src/hci_layer.cc \
+    src/hci_packet_factory.cc \
+    src/hci_packet_parser.cc \
+    src/low_power_manager.cc \
+    src/packet_fragmenter.cc \
+    src/vendor.cc \
+    ../EventLogTags.logtags
+
+ifneq ($(filter $(TARGET_BUILD_VARIANT), userdebug eng),)
+    LOCAL_CFLAGS += -DBTSNOOP_DEFAULT=TRUE -DBT_NET_DEBUG=TRUE
+endif
+
+
+ifneq ($(filter $(TARGET_BUILD_VARIANT), userdebug eng),)
+    LOCAL_CFLAGS += -DBTSNOOP_DEFAULT=TRUE -DBT_NET_DEBUG=TRUE
+endif
+
+LOCAL_C_INCLUDES += \
+    $(LOCAL_PATH)/include \
+    $(LOCAL_PATH)/.. \
+    $(LOCAL_PATH)/../include \
+    $(LOCAL_PATH)/../btcore/include \
+    $(LOCAL_PATH)/../stack/include \
+    $(LOCAL_PATH)/../utils/include \
+    $(LOCAL_PATH)/../bta/include \
+    $(bluetooth_C_INCLUDES)
+
+LOCAL_MODULE := libbt-hci
+
+ifeq ($(BLUETOOTH_HCI_USE_MCT),true)
+    LOCAL_CFLAGS += -DHCI_USE_MCT
+endif
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_STATIC_LIBRARY)
+
+# HCI unit tests for target
+# ========================================================
+ifeq (,$(strip $(SANITIZE_TARGET)))
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH)/include \
+    $(LOCAL_PATH)/.. \
+    $(LOCAL_PATH)/../include \
+    $(LOCAL_PATH)/../btcore/include \
+    $(LOCAL_PATH)/../osi/test \
+    $(LOCAL_PATH)/../stack/include \
+    $(LOCAL_PATH)/../utils/include \
+    $(bluetooth_C_INCLUDES)
+
+LOCAL_SRC_FILES := \
+    ../osi/test/AllocationTestHarness.cc \
+    ../osi/test/AlarmTestHarness.cc \
+    ./test/hci_hal_h4_test.cc \
+    ./test/hci_hal_mct_test.cc \
+    ./test/hci_layer_test.cc \
+    ./test/low_power_manager_test.cc \
+    ./test/packet_fragmenter_test.cc
+
+LOCAL_MODULE := net_test_hci
+LOCAL_MODULE_TAGS := tests
+LOCAL_SHARED_LIBRARIES := liblog libdl libprotobuf-cpp-lite
+LOCAL_STATIC_LIBRARIES := libbt-hci libosi libcutils libbtcore libbt-protos
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_NATIVE_TEST)
+endif # SANITIZE_TARGET
diff --git a/bt/hci/BUILD.gn b/bt/hci/BUILD.gn
new file mode 100644
index 0000000..ec53c34
--- /dev/null
+++ b/bt/hci/BUILD.gn
@@ -0,0 +1,79 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+static_library("hci") {
+  sources = [
+    "src/btsnoop.cc",
+    "src/btsnoop_mem.cc",
+    "src/btsnoop_net.cc",
+    "src/buffer_allocator.cc",
+    "src/hci_audio.cc",
+    "src/hci_hal.cc",
+    "src/hci_hal_h4.cc",
+    "src/hci_hal_mct.cc",
+    "src/hci_inject.cc",
+    "src/hci_layer.cc",
+    "src/hci_packet_factory.cc",
+    "src/hci_packet_parser.cc",
+    "src/low_power_manager.cc",
+    "src/packet_fragmenter.cc",
+    "src/vendor.cc",
+  ]
+
+  include_dirs = [
+    "include",
+    "//",
+    "//include",
+    "//bta/include",
+    "//btcore/include",
+    "//stack/include",
+  ]
+}
+
+executable("net_test_hci") {
+  testonly = true
+  sources = [
+    "//osi/test/AllocationTestHarness.cc",
+    "//osi/test/AlarmTestHarness.cc",
+    "test/hci_hal_h4_test.cc",
+    "test/hci_hal_mct_test.cc",
+    "test/hci_layer_test.cc",
+    "test/low_power_manager_test.cc",
+    "test/packet_fragmenter_test.cc",
+  ]
+
+  include_dirs = [
+    "//",
+    "//include",
+    "//btcore/include",
+    "//hci/include",
+    "//osi/test",
+    "//stack/include",
+  ]
+
+  deps = [
+    "//hci",
+    "//osi",
+    "//btcore",
+    "//third_party/googletest:gtest_main",
+  ]
+
+  libs = [
+    "-lpthread",
+    "-lrt",
+    "-ldl",
+  ]
+}
diff --git a/bt/hci/include/bt_hci_bdroid.h b/bt/hci/include/bt_hci_bdroid.h
new file mode 100644
index 0000000..3dd9f44
--- /dev/null
+++ b/bt/hci/include/bt_hci_bdroid.h
@@ -0,0 +1,105 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Filename:      bt_hci_bdroid.h
+ *
+ *  Description:   A wrapper header file of bt_hci_lib.h
+ *
+ *                 Contains definitions specific for interfacing with Bluedroid
+ *                 Bluetooth stack
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#ifdef HAS_BDROID_BUILDCFG
+#include "bdroid_buildcfg.h"
+#endif
+
+/******************************************************************************
+ *  Constants & Macros
+ *****************************************************************************/
+
+#include <stdbool.h>
+
+#define HCI_ACL_MAX_SIZE 1024
+#define HCI_MAX_FRAME_SIZE (HCI_ACL_MAX_SIZE + 4)
+
+/* Host/Controller lib internal event ID */
+typedef enum {
+  HC_EVENT_LPM_IDLE_TIMEOUT,
+} bthc_event_t;
+
+/* Message event mask across Host/Controller lib and stack */
+#define MSG_EVT_MASK 0xFF00     /* eq. BT_EVT_MASK */
+#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_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_CMD 0x2000 /* eq. BT_EVT_TO_LM_HCI_CMD */
+
+/* Local Bluetooth Controller ID for BR/EDR */
+#define LOCAL_BR_EDR_CONTROLLER_ID 0
+
+/******************************************************************************
+ *  Type definitions and return values
+ *****************************************************************************/
+
+typedef struct {
+  uint16_t event;
+  uint16_t len;
+  uint16_t offset;
+  uint16_t layer_specific;
+  uint8_t data[];
+} HC_BT_HDR;
+
+#define BT_HC_HDR_SIZE (sizeof(HC_BT_HDR))
+
+typedef struct _hc_buffer_hdr {
+  struct _hc_buffer_hdr* p_next; /* next buffer in the queue */
+  uint8_t reserved1;
+  uint8_t reserved2;
+  uint8_t reserved3;
+  uint8_t reserved4;
+} HC_BUFFER_HDR_T;
+
+#define BT_HC_BUFFER_HDR_SIZE (sizeof(HC_BUFFER_HDR_T))
+
+/******************************************************************************
+ *  Extern variables and functions
+ *****************************************************************************/
+
+/******************************************************************************
+ *  Functions
+ *****************************************************************************/
+
+// Called when a buffer has been produced by the serial layer and should be
+// processed by the HCI layer.
+void bthc_rx_ready(void);
+void bthc_tx(HC_BT_HDR* buf);
+void bthc_idle_timeout(void);
diff --git a/bt/hci/include/bt_vendor_lib.h b/bt/hci/include/bt_vendor_lib.h
new file mode 100644
index 0000000..edfe757
--- /dev/null
+++ b/bt/hci/include/bt_vendor_lib.h
@@ -0,0 +1,419 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BT_VENDOR_LIB_H
+#define BT_VENDOR_LIB_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Struct types */
+
+/** Typedefs and defines */
+
+/** Vendor specific operations OPCODE */
+typedef enum {
+  /*  [operation]
+   *      Power on or off the BT Controller.
+   *  [input param]
+   *      A pointer to int type with content of bt_vendor_power_state_t.
+   *      Typecasting conversion: (int *) param.
+   *  [return]
+   *      0 - default, don't care.
+   *  [callback]
+   *      None.
+   */
+  BT_VND_OP_POWER_CTRL,
+
+  /*  [operation]
+   *      Perform any vendor specific initialization or configuration
+   *      on the BT Controller. This is called before stack initialization.
+   *  [input param]
+   *      None.
+   *  [return]
+   *      0 - default, don't care.
+   *  [callback]
+   *      Must call fwcfg_cb to notify the stack of the completion of vendor
+   *      specific initialization once it has been done.
+   */
+  BT_VND_OP_FW_CFG,
+
+  /*  [operation]
+   *      Perform any vendor specific SCO/PCM configuration on the BT
+   * Controller.
+   *      This is called after stack initialization.
+   *  [input param]
+   *      None.
+   *  [return]
+   *      0 - default, don't care.
+   *  [callback]
+   *      Must call scocfg_cb to notify the stack of the completion of vendor
+   *      specific SCO configuration once it has been done.
+   */
+  BT_VND_OP_SCO_CFG,
+
+  /*  [operation]
+   *      Open UART port on where the BT Controller is attached.
+   *      This is called before stack initialization.
+   *  [input param]
+   *      A pointer to int array type for open file descriptors.
+   *      The mapping of HCI channel to fd slot in the int array is given in
+   *      bt_vendor_hci_channels_t.
+   *      And, it requires the vendor lib to fill up the content before
+   * returning
+   *      the call.
+   *      Typecasting conversion: (int (*)[]) param.
+   *  [return]
+   *      Numbers of opened file descriptors.
+   *      Valid number:
+   *          1 - CMD/EVT/ACL-In/ACL-Out via the same fd (e.g. UART)
+   *          2 - CMD/EVT on one fd, and ACL-In/ACL-Out on the other fd
+   *          4 - CMD, EVT, ACL-In, ACL-Out are on their individual fd
+   *  [callback]
+   *      None.
+   */
+  BT_VND_OP_USERIAL_OPEN,
+
+  /*  [operation]
+   *      Close the previously opened UART port.
+   *  [input param]
+   *      None.
+   *  [return]
+   *      0 - default, don't care.
+   *  [callback]
+   *      None.
+   */
+  BT_VND_OP_USERIAL_CLOSE,
+
+  /*  [operation]
+   *      Get the LPM idle timeout in milliseconds.
+   *      The stack uses this information to launch a timer delay before it
+   *      attempts to de-assert LPM WAKE signal once downstream HCI packet
+   *      has been delivered.
+   *  [input param]
+   *      A pointer to uint32_t type which is passed in by the stack. And, it
+   *      requires the vendor lib to fill up the content before returning
+   *      the call.
+   *      Typecasting conversion: (uint32_t *) param.
+   *  [return]
+   *      0 - default, don't care.
+   *  [callback]
+   *      None.
+   */
+  BT_VND_OP_GET_LPM_IDLE_TIMEOUT,
+
+  /*  [operation]
+   *      Enable or disable LPM mode on BT Controller.
+   *  [input param]
+   *      A pointer to uint8_t type with content of bt_vendor_lpm_mode_t.
+   *      Typecasting conversion: (uint8_t *) param.
+   *  [return]
+   *      0 - default, don't care.
+   *  [callback]
+   *      Must call lpm_cb to notify the stack of the completion of LPM
+   *      disable/enable process once it has been done.
+   */
+  BT_VND_OP_LPM_SET_MODE,
+
+  /*  [operation]
+   *      Assert or Deassert LPM WAKE on BT Controller.
+   *  [input param]
+   *      A pointer to uint8_t type with content of bt_vendor_lpm_wake_state_t.
+   *      Typecasting conversion: (uint8_t *) param.
+   *  [return]
+   *      0 - default, don't care.
+   *  [callback]
+   *      None.
+   */
+  BT_VND_OP_LPM_WAKE_SET_STATE,
+
+  /*  [operation]
+   *      Perform any vendor specific commands related to audio state changes.
+   *  [input param]
+   *      a pointer to bt_vendor_op_audio_state_t indicating what audio state is
+   *      set.
+   *  [return]
+   *      0 - default, don't care.
+   *  [callback]
+   *      None.
+   */
+  BT_VND_OP_SET_AUDIO_STATE,
+
+  /*  [operation]
+   *      The epilog call to the vendor module so that it can perform any
+   *      vendor-specific processes (e.g. send a HCI_RESET to BT Controller)
+   *      before the caller calls for cleanup().
+   *  [input param]
+   *      None.
+   *  [return]
+   *      0 - default, don't care.
+   *  [callback]
+   *      Must call epilog_cb to notify the stack of the completion of vendor
+   *      specific epilog process once it has been done.
+   */
+  BT_VND_OP_EPILOG,
+
+  /*  [operation]
+   *      Call to the vendor module so that it can perform all vendor-specific
+   *      operations to start offloading a2dp media encode & tx.
+   *  [input param]
+   *      pointer to bt_vendor_op_a2dp_offload_start_t containing elements
+   *      required for VND FW to setup a2dp offload.
+   *  [return]
+   *      0  - default, dont care.
+   *  [callback]
+   *      Must call a2dp_offload_start_cb to notify the stack of the
+   *      completion of vendor specific setup process once it has been done.
+   */
+  BT_VND_OP_A2DP_OFFLOAD_START,
+
+  /*  [operation]
+   *      Call to the vendor module so that it can perform all vendor-specific
+   *      operations to suspend offloading a2dp media encode & tx.
+   *  [input param]
+   *      pointer to bt_vendor_op_a2dp_offload_t containing elements
+   *      required for VND FW to setup a2dp offload.
+   *  [return]
+   *      0  - default, dont care.
+   *  [callback]
+   *      Must call a2dp_offload_cb to notify the stack of the
+   *      completion of vendor specific setup process once it has been done.
+   */
+  BT_VND_OP_A2DP_OFFLOAD_STOP,
+
+} bt_vendor_opcode_t;
+
+/** Power on/off control states */
+typedef enum {
+  BT_VND_PWR_OFF,
+  BT_VND_PWR_ON,
+} bt_vendor_power_state_t;
+
+/** Define HCI channel identifier in the file descriptors array
+    used in BT_VND_OP_USERIAL_OPEN operation.
+ */
+typedef enum {
+  CH_CMD,      // HCI Command channel
+  CH_EVT,      // HCI Event channel
+  CH_ACL_OUT,  // HCI ACL downstream channel
+  CH_ACL_IN,   // HCI ACL upstream channel
+
+  CH_MAX  // Total channels
+} bt_vendor_hci_channels_t;
+
+/** LPM disable/enable request */
+typedef enum {
+  BT_VND_LPM_DISABLE,
+  BT_VND_LPM_ENABLE,
+} bt_vendor_lpm_mode_t;
+
+/** LPM WAKE set state request */
+typedef enum {
+  BT_VND_LPM_WAKE_ASSERT,
+  BT_VND_LPM_WAKE_DEASSERT,
+} bt_vendor_lpm_wake_state_t;
+
+/** Callback result values */
+typedef enum {
+  BT_VND_OP_RESULT_SUCCESS,
+  BT_VND_OP_RESULT_FAIL,
+} bt_vendor_op_result_t;
+
+/** audio (SCO) state changes triggering VS commands for configuration */
+typedef struct {
+  uint16_t handle;
+  uint16_t peer_codec;
+  uint16_t state;
+} bt_vendor_op_audio_state_t;
+
+/*
+ * Bluetooth Host/Controller Vendor callback structure.
+ */
+
+/* vendor initialization/configuration callback */
+typedef void (*cfg_result_cb)(bt_vendor_op_result_t result);
+
+/* datapath buffer allocation callback (callout)
+ *
+ *  Vendor lib needs to request a buffer through the alloc callout function
+ *  from HCI lib if the buffer is for constructing a HCI Command packet which
+ *  will be sent through xmit_cb to BT Controller.
+ *
+ *  For each buffer allocation, the requested size needs to be big enough to
+ *  accommodate the below header plus a complete HCI packet --
+ *      typedef struct
+ *      {
+ *          uint16_t          event;
+ *          uint16_t          len;
+ *          uint16_t          offset;
+ *          uint16_t          layer_specific;
+ *      } HC_BT_HDR;
+ *
+ *  HCI lib returns a pointer to the buffer where Vendor lib should use to
+ *  construct a HCI command packet as below format:
+ *
+ *  --------------------------------------------
+ *  |  HC_BT_HDR  |  HCI command               |
+ *  --------------------------------------------
+ *  where
+ *      HC_BT_HDR.event = 0x2000;
+ *      HC_BT_HDR.len = Length of HCI command;
+ *      HC_BT_HDR.offset = 0;
+ *      HC_BT_HDR.layer_specific = 0;
+ *
+ *  For example, a HCI_RESET Command will be formed as
+ *  ------------------------
+ *  |  HC_BT_HDR  |03|0c|00|
+ *  ------------------------
+ *  with
+ *      HC_BT_HDR.event = 0x2000;
+ *      HC_BT_HDR.len = 3;
+ *      HC_BT_HDR.offset = 0;
+ *      HC_BT_HDR.layer_specific = 0;
+ */
+typedef void* (*malloc_cb)(int size);
+
+/* datapath buffer deallocation callback (callout) */
+typedef void (*mdealloc_cb)(void* p_buf);
+
+/* define callback of the cmd_xmit_cb
+ *
+ *  The callback function which HCI lib will call with the return of command
+ *  complete packet. Vendor lib is responsible for releasing the buffer passed
+ *  in at the p_mem parameter by calling dealloc callout function.
+ */
+typedef void (*tINT_CMD_CBACK)(void* p_mem);
+
+/* hci command packet transmit callback (callout)
+ *
+ *  Vendor lib calls xmit_cb callout function in order to send a HCI Command
+ *  packet to BT Controller. The buffer carrying HCI Command packet content
+ *  needs to be first allocated through the alloc callout function.
+ *  HCI lib will release the buffer for Vendor lib once it has delivered the
+ *  packet content to BT Controller.
+ *
+ *  Vendor lib needs also provide a callback function (p_cback) which HCI lib
+ *  will call with the return of command complete packet.
+ *
+ *  The opcode parameter gives the HCI OpCode (combination of OGF and OCF) of
+ *  HCI Command packet. For example, opcode = 0x0c03 for the HCI_RESET command
+ *  packet.
+ */
+typedef uint8_t (*cmd_xmit_cb)(uint16_t opcode, void* p_buf,
+                               tINT_CMD_CBACK p_cback);
+
+typedef void (*cfg_a2dp_cb)(bt_vendor_op_result_t result, bt_vendor_opcode_t op,
+                            uint8_t bta_av_handle);
+
+typedef struct {
+  /** set to sizeof(bt_vendor_callbacks_t) */
+  size_t size;
+
+  /*
+   * Callback and callout functions have implemented in HCI libray
+   * (libbt-hci.so).
+   */
+
+  /* notifies caller result of firmware configuration request */
+  cfg_result_cb fwcfg_cb;
+
+  /* notifies caller result of sco configuration request */
+  cfg_result_cb scocfg_cb;
+
+  /* notifies caller result of lpm enable/disable */
+  cfg_result_cb lpm_cb;
+
+  /* notifies the result of codec setting */
+  cfg_result_cb audio_state_cb;
+
+  /* buffer allocation request */
+  malloc_cb alloc;
+
+  /* buffer deallocation request */
+  mdealloc_cb dealloc;
+
+  /* hci command packet transmit request */
+  cmd_xmit_cb xmit_cb;
+
+  /* notifies caller completion of epilog process */
+  cfg_result_cb epilog_cb;
+
+  /* notifies status of a2dp offload cmd's */
+  cfg_a2dp_cb a2dp_offload_cb;
+} bt_vendor_callbacks_t;
+
+/** A2DP offload request */
+typedef struct {
+  uint8_t bta_av_handle;  /* BTA_AV Handle for callbacks */
+  uint16_t xmit_quota;    /* Total ACL quota for light stack */
+  uint16_t acl_data_size; /* Max ACL data size across HCI transport */
+  uint16_t stream_mtu;
+  uint16_t local_cid;
+  uint16_t remote_cid;
+  uint16_t lm_handle;
+  uint8_t is_flushable; /* true if flushable channel */
+  uint32_t stream_source;
+  uint8_t codec_info[10]; /* Codec capabilities array */
+} bt_vendor_op_a2dp_offload_t;
+
+/*
+ * Bluetooth Host/Controller VENDOR Interface
+ */
+typedef struct {
+  /** Set to sizeof(bt_vndor_interface_t) */
+  size_t size;
+
+  /*
+   * Functions need to be implemented in Vendor libray (libbt-vendor.so).
+   */
+
+  /**
+   * Caller will open the interface and pass in the callback routines
+   * to the implemenation of this interface.
+   */
+  int (*init)(const bt_vendor_callbacks_t* p_cb, unsigned char* local_bdaddr);
+
+  /**  Vendor specific operations */
+  int (*op)(bt_vendor_opcode_t opcode, void* param);
+
+  /** Closes the interface */
+  void (*cleanup)(void);
+} bt_vendor_interface_t;
+
+/*
+ * External shared lib functions/data
+ */
+
+/* Entry point of DLib --
+ *      Vendor library needs to implement the body of bt_vendor_interface_t
+ *      structure and uses the below name as the variable name. HCI library
+ *      will use this symbol name to get address of the object through the
+ *      dlsym call.
+ */
+extern const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BT_VENDOR_LIB_H */
diff --git a/bt/hci/include/btsnoop.h b/bt/hci/include/btsnoop.h
new file mode 100644
index 0000000..14896ca
--- /dev/null
+++ b/bt/hci/include/btsnoop.h
@@ -0,0 +1,47 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+
+#include "bt_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static const char BTSNOOP_MODULE[] = "btsnoop_module";
+
+typedef struct btsnoop_t {
+  // Inform btsnoop whether the API desires to log. If |value| is true.
+  // logging will be enabled. Otherwise it defers to the value from the
+  // config file.
+  void (*set_api_wants_to_log)(bool value);
+
+  // Capture |packet| and dump it to the btsnoop logs. If |is_received| is
+  // true, the packet is marked as incoming. Otherwise, the packet is marked
+  // as outgoing.
+  void (*capture)(const BT_HDR* packet, bool is_received);
+} btsnoop_t;
+
+const btsnoop_t* btsnoop_get_interface(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/hci/include/btsnoop_mem.h b/bt/hci/include/btsnoop_mem.h
new file mode 100644
index 0000000..052b9e8
--- /dev/null
+++ b/bt/hci/include/btsnoop_mem.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 "bt_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Callback invoked for each HCI packet.
+// Highlander mode - there can be only one...
+typedef void (*btsnoop_data_cb)(const uint16_t type, const uint8_t* p_data,
+                                const size_t len);
+
+// This call sets the (one and only) callback that will
+// be invoked once for each HCI packet/event.
+void btsnoop_mem_set_callback(btsnoop_data_cb cb);
+
+// This function is invoked every time an HCI packet
+// is sent/received. Packets will be filtered  and then
+// forwarded to the |btsnoop_data_cb|.
+void btsnoop_mem_capture(const BT_HDR* p_buf);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/hci/include/buffer_allocator.h b/bt/hci/include/buffer_allocator.h
new file mode 100644
index 0000000..7f650ce
--- /dev/null
+++ b/bt/hci/include/buffer_allocator.h
@@ -0,0 +1,31 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 "osi/include/allocator.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const allocator_t* buffer_allocator_get_interface();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/hci/include/hci_audio.h b/bt/hci/include/hci_audio.h
new file mode 100644
index 0000000..764ae3e
--- /dev/null
+++ b/bt/hci/include/hci_audio.h
@@ -0,0 +1,48 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Audio state definitions.
+typedef enum {
+  SCO_STATE_OFF = 0,       // Audio is off.
+  SCO_STATE_OFF_TRANSFER,  // Closed pending final transfer of audio.
+  SCO_STATE_ON,            // Audio is on.
+  SCO_STATE_SETUP,         // Open pending completion of audio setup.
+} sco_state_t;
+
+// Codec type definitions.
+typedef enum {
+  SCO_CODEC_NONE = 0x0000,
+  SCO_CODEC_CVSD = 0x0001,
+  SCO_CODEC_MSBC = 0x0002,
+} sco_codec_t;
+
+// Set the audio state on the controller for SCO (PCM, WBS, ...) using the
+// vendor library.
+void set_audio_state(uint16_t handle, sco_codec_t codec, sco_state_t state);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/hci/include/hci_hal.h b/bt/hci/include/hci_hal.h
new file mode 100644
index 0000000..74f2f67
--- /dev/null
+++ b/bt/hci/include/hci_hal.h
@@ -0,0 +1,100 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+#include <stdint.h>
+
+#include "osi/include/thread.h"
+#include "vendor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+  DATA_TYPE_UNKNOWN = 0,
+  DATA_TYPE_COMMAND = 1,
+  DATA_TYPE_ACL = 2,
+  DATA_TYPE_SCO = 3,
+  DATA_TYPE_EVENT = 4
+} serial_data_type_t;
+
+typedef void (*data_ready_cb)(serial_data_type_t type);
+
+typedef struct {
+  // Called when the HAL detects inbound data.
+  // Data |type| may be ACL, SCO, or EVENT.
+  // Executes in the context of the thread supplied to |init|.
+  data_ready_cb data_ready;
+
+  /*
+  // Called when the HAL detects inbound astronauts named Dave.
+  // HAL will deny all requests to open the pod bay doors after this.
+  dave_ready_cb dave_ready;
+  */
+} hci_hal_callbacks_t;
+
+typedef struct hci_hal_t {
+  // Initialize the HAL, with |upper_callbacks| and |upper_thread| to run in the
+  // context of.
+  bool (*init)(const hci_hal_callbacks_t* upper_callbacks,
+               thread_t* upper_thread);
+
+  // Connect to the underlying hardware, and let data start flowing.
+  bool (*open)(void);
+  // Disconnect from the underlying hardware, and close the HAL.
+  // "Daisy, Daisy..."
+  void (*close)(void);
+
+  // Retrieve up to |max_size| bytes for ACL, SCO, or EVENT data packets into
+  // |buffer|. Only guaranteed to be correct in the context of a data_ready
+  // callback of the corresponding type.
+  size_t (*read_data)(serial_data_type_t type, uint8_t* buffer,
+                      size_t max_size);
+  // The upper layer must call this to notify the HAL that it has finished
+  // reading a packet of the specified |type|. Underlying implementations that
+  // use shared channels for multiple data types depend on this to know when
+  // to reinterpret the data stream.
+  void (*packet_finished)(serial_data_type_t type);
+  // Transmit COMMAND, ACL, or SCO data packets.
+  // |data| may not be NULL. |length| must be greater than zero.
+  //
+  // IMPORTANT NOTE:
+  // Depending on the underlying implementation, the byte right
+  // before the beginning of |data| may be borrowed during this call
+  // and then restored to its original value.
+  // This is safe in the bluetooth context, because there is always a buffer
+  // header that prefixes data you're sending.
+  uint16_t (*transmit_data)(serial_data_type_t type, uint8_t* data,
+                            uint16_t length);
+} hci_hal_t;
+
+// Gets the correct hal implementation, as compiled for.
+const hci_hal_t* hci_hal_get_interface(void);
+
+const hci_hal_t* hci_hal_h4_get_interface(void);
+const hci_hal_t* hci_hal_h4_get_test_interface(vendor_t* vendor_interface);
+
+const hci_hal_t* hci_hal_mct_get_interface(void);
+const hci_hal_t* hci_hal_mct_get_test_interface(vendor_t* vendor_interface);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/hci/include/hci_inject.h b/bt/hci/include/hci_inject.h
new file mode 100644
index 0000000..f194226
--- /dev/null
+++ b/bt/hci/include/hci_inject.h
@@ -0,0 +1,42 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct hci_t hci_t;
+
+typedef struct hci_inject_t {
+  // Starts the HCI injection module. Returns true on success, false on failure.
+  // Once started, this module must be shut down with |close|.
+  bool (*open)(const hci_t* hci_interface);
+
+  // Shuts down the HCI injection module.
+  void (*close)(void);
+} hci_inject_t;
+
+const hci_inject_t* hci_inject_get_interface();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/hci/include/hci_internals.h b/bt/hci/include/hci_internals.h
new file mode 100644
index 0000000..6b9fb01
--- /dev/null
+++ b/bt/hci/include/hci_internals.h
@@ -0,0 +1,28 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+// 2 bytes for opcode, 1 byte for parameter length (Volume 2, Part E, 5.4.1)
+#define HCI_COMMAND_PREAMBLE_SIZE 3
+// 2 bytes for handle, 2 bytes for data length (Volume 2, Part E, 5.4.2)
+#define HCI_ACL_PREAMBLE_SIZE 4
+// 2 bytes for handle, 1 byte for data length (Volume 2, Part E, 5.4.3)
+#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
diff --git a/bt/hci/include/hci_layer.h b/bt/hci/include/hci_layer.h
new file mode 100644
index 0000000..1e6d137
--- /dev/null
+++ b/bt/hci/include/hci_layer.h
@@ -0,0 +1,121 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+
+#include "bt_types.h"
+#include "osi/include/allocator.h"
+#include "osi/include/data_dispatcher.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/future.h"
+#include "osi/include/osi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static const char HCI_MODULE[] = "hci_module";
+
+///// LEGACY DEFINITIONS /////
+
+/* Message event mask across Host/Controller lib and stack */
+#define MSG_EVT_MASK 0xFF00     /* eq. BT_EVT_MASK */
+#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_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_CMD 0x2000 /* eq. BT_EVT_TO_LM_HCI_CMD */
+
+/* Local Bluetooth Controller ID for BR/EDR */
+#define LOCAL_BR_EDR_CONTROLLER_ID 0
+
+///// END LEGACY DEFINITIONS /////
+
+typedef struct hci_hal_t hci_hal_t;
+typedef struct btsnoop_t btsnoop_t;
+typedef struct controller_t controller_t;
+typedef struct hci_inject_t hci_inject_t;
+typedef struct packet_fragmenter_t packet_fragmenter_t;
+typedef struct vendor_t vendor_t;
+typedef struct low_power_manager_t low_power_manager_t;
+
+typedef unsigned char* bdaddr_t;
+typedef uint16_t command_opcode_t;
+
+typedef enum {
+  LPM_DISABLE,
+  LPM_ENABLE,
+  LPM_WAKE_ASSERT,
+  LPM_WAKE_DEASSERT
+} low_power_command_t;
+
+typedef void (*command_complete_cb)(BT_HDR* response, void* context);
+typedef void (*command_status_cb)(uint8_t status, BT_HDR* command,
+                                  void* context);
+
+typedef struct hci_t {
+  // Send a low power command, if supported and the low power manager is
+  // enabled.
+  void (*send_low_power_command)(low_power_command_t command);
+
+  // Do the postload sequence (call after the rest of the BT stack initializes).
+  void (*do_postload)(void);
+
+  // Register with this data dispatcher to receive events flowing upward out of
+  // the HCI layer
+  data_dispatcher_t* event_dispatcher;
+
+  // Set the queue to receive ACL data in
+  void (*set_data_queue)(fixed_queue_t* queue);
+
+  // Send a command through the HCI layer
+  void (*transmit_command)(BT_HDR* command,
+                           command_complete_cb complete_callback,
+                           command_status_cb status_cb, void* context);
+
+  future_t* (*transmit_command_futured)(BT_HDR* command);
+
+  // Send some data downward through the HCI layer
+  void (*transmit_downward)(data_dispatcher_type_t type, void* data);
+} hci_t;
+
+const hci_t* hci_layer_get_interface();
+
+const hci_t* hci_layer_get_test_interface(
+    const allocator_t* buffer_allocator_interface,
+    const hci_hal_t* hal_interface, const btsnoop_t* btsnoop_interface,
+    const hci_inject_t* hci_inject_interface,
+    const packet_fragmenter_t* packet_fragmenter_interface,
+    const vendor_t* vendor_interface,
+    const low_power_manager_t* low_power_manager_interface);
+
+void hci_layer_cleanup_interface();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/hci/include/hci_packet_factory.h b/bt/hci/include/hci_packet_factory.h
new file mode 100644
index 0000000..e2a5b7b
--- /dev/null
+++ b/bt/hci/include/hci_packet_factory.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 "bt_types.h"
+#include "event_mask.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+  BT_HDR* (*make_reset)(void);
+  BT_HDR* (*make_read_buffer_size)(void);
+  BT_HDR* (*make_host_buffer_size)(uint16_t acl_size, uint8_t sco_size,
+                                   uint16_t acl_count, uint16_t sco_count);
+  BT_HDR* (*make_read_local_version_info)(void);
+  BT_HDR* (*make_read_bd_addr)(void);
+  BT_HDR* (*make_read_local_supported_commands)(void);
+  BT_HDR* (*make_read_local_extended_features)(uint8_t page_number);
+  BT_HDR* (*make_write_simple_pairing_mode)(uint8_t mode);
+  BT_HDR* (*make_write_secure_connections_host_support)(uint8_t mode);
+  BT_HDR* (*make_set_event_mask)(const bt_event_mask_t* event_mask);
+  BT_HDR* (*make_ble_write_host_support)(uint8_t supported_host,
+                                         uint8_t simultaneous_host);
+  BT_HDR* (*make_ble_read_white_list_size)(void);
+  BT_HDR* (*make_ble_read_buffer_size)(void);
+  BT_HDR* (*make_ble_read_supported_states)(void);
+  BT_HDR* (*make_ble_read_local_supported_features)(void);
+  BT_HDR* (*make_ble_read_resolving_list_size)(void);
+  BT_HDR* (*make_ble_read_suggested_default_data_length)(void);
+  BT_HDR* (*make_ble_set_event_mask)(const bt_event_mask_t* event_mask);
+  BT_HDR* (*make_read_local_supported_codecs)(void);
+} hci_packet_factory_t;
+
+const hci_packet_factory_t* hci_packet_factory_get_interface();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/hci/include/hci_packet_parser.h b/bt/hci/include/hci_packet_parser.h
new file mode 100644
index 0000000..1604b91
--- /dev/null
+++ b/bt/hci/include/hci_packet_parser.h
@@ -0,0 +1,88 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 "bdaddr.h"
+#include "bt_types.h"
+#include "device_features.h"
+#include "features.h"
+#include "osi/include/allocator.h"
+#include "version.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+  void (*parse_generic_command_complete)(BT_HDR* response);
+
+  void (*parse_read_buffer_size_response)(BT_HDR* response,
+                                          uint16_t* data_size_ptr,
+                                          uint16_t* acl_buffer_count_ptr);
+
+  void (*parse_read_local_version_info_response)(BT_HDR* response,
+                                                 bt_version_t* bt_version_ptr);
+
+  void (*parse_read_bd_addr_response)(BT_HDR* response,
+                                      bt_bdaddr_t* address_ptr);
+
+  void (*parse_read_local_supported_commands_response)(
+      BT_HDR* response, uint8_t* supported_commands_ptr,
+      size_t supported_commands_length);
+
+  void (*parse_read_local_extended_features_response)(
+      BT_HDR* response, uint8_t* page_number_ptr, uint8_t* max_page_number_ptr,
+      bt_device_features_t* feature_pages, size_t feature_pages_count);
+
+  void (*parse_ble_read_white_list_size_response)(BT_HDR* response,
+                                                  uint8_t* white_list_size_ptr);
+
+  void (*parse_ble_read_buffer_size_response)(BT_HDR* response,
+                                              uint16_t* data_size_ptr,
+                                              uint8_t* acl_buffer_count_ptr);
+
+  void (*parse_ble_read_supported_states_response)(
+      BT_HDR* response, uint8_t* supported_states,
+      size_t supported_states_size);
+
+  void (*parse_ble_read_local_supported_features_response)(
+      BT_HDR* response, bt_device_features_t* supported_features);
+
+  void (*parse_ble_read_resolving_list_size_response)(
+      BT_HDR* response, uint8_t* resolving_list_size_ptr);
+
+  void (*parse_ble_read_suggested_default_data_length_response)(
+      BT_HDR* response, uint16_t* ble_default_packet_length_ptr);
+
+  void (*parse_read_local_supported_codecs_response)(
+      BT_HDR* response, uint8_t* number_of_local_supported_codecs,
+      uint8_t* local_supported_codecs);
+
+} hci_packet_parser_t;
+
+const hci_packet_parser_t* hci_packet_parser_get_interface();
+
+const hci_packet_parser_t* hci_packet_parser_get_test_interface(
+    allocator_t* buffer_allocator_interface);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/hci/include/low_power_manager.h b/bt/hci/include/low_power_manager.h
new file mode 100644
index 0000000..e9408bf
--- /dev/null
+++ b/bt/hci/include/low_power_manager.h
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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_layer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct thread_t thread_t;
+typedef struct vendor_t vendor_t;
+
+typedef struct low_power_manager_t {
+  // Initialize the low power manager, and use |post_thread| to synchronize
+  // actions.
+  void (*init)(thread_t* post_thread);
+
+  // Clean up the low power manager and release resources.
+  void (*cleanup)(void);
+
+  // Performs |command| synchronized on the thread that was provided
+  // at initialization time.
+  void (*post_command)(low_power_command_t command);
+
+  // Assert wake (for transmission). Must be called on the thread provided
+  // at initialization time.
+  void (*wake_assert)(void);
+
+  // Tell the low power manager that you're done transmitting data. Must be
+  // called on the thread provided at initialization time.
+  void (*transmit_done)(void);
+} low_power_manager_t;
+
+const low_power_manager_t* low_power_manager_get_interface();
+const low_power_manager_t* low_power_manager_get_test_interface(
+    const vendor_t* vendor_interface);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/hci/include/packet_fragmenter.h b/bt/hci/include/packet_fragmenter.h
new file mode 100644
index 0000000..e072d4b
--- /dev/null
+++ b/bt/hci/include/packet_fragmenter.h
@@ -0,0 +1,72 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 "bt_types.h"
+#include "hci_layer.h"
+#include "osi/include/allocator.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*transmit_finished_cb)(BT_HDR* packet, bool all_fragments_sent);
+typedef void (*packet_reassembled_cb)(BT_HDR* packet);
+typedef void (*packet_fragmented_cb)(BT_HDR* packet,
+                                     bool send_transmit_finished);
+
+typedef struct {
+  // Called for every packet fragment.
+  packet_fragmented_cb fragmented;
+
+  // Called for every completely reassembled packet.
+  packet_reassembled_cb reassembled;
+
+  // Called when the fragmenter finishes sending all requested fragments,
+  // but the packet has not been entirely sent.
+  transmit_finished_cb transmit_finished;
+} packet_fragmenter_callbacks_t;
+
+typedef struct packet_fragmenter_t {
+  // Initialize the fragmenter, specifying the |result_callbacks|.
+  void (*init)(const packet_fragmenter_callbacks_t* result_callbacks);
+
+  // Release all resources associated with the fragmenter.
+  void (*cleanup)(void);
+
+  // Fragments |packet| if necessary and hands off everything to the fragmented
+  // callback.
+  void (*fragment_and_dispatch)(BT_HDR* packet);
+  // If |packet| is a complete packet, forwards to the reassembled callback.
+  // Otherwise
+  // holds onto it until all fragments arrive, at which point the reassembled
+  // callback is called
+  // with the reassembled data.
+  void (*reassemble_and_dispatch)(BT_HDR* packet);
+} packet_fragmenter_t;
+
+const packet_fragmenter_t* packet_fragmenter_get_interface();
+
+const packet_fragmenter_t* packet_fragmenter_get_test_interface(
+    const controller_t* controller_interface,
+    const allocator_t* buffer_allocator_interface);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/hci/include/userial.h b/bt/hci/include/userial.h
new file mode 100644
index 0000000..b428257
--- /dev/null
+++ b/bt/hci/include/userial.h
@@ -0,0 +1,79 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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 module manages the serial port over which HCI commands
+// and data are sent/received.
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+  USERIAL_PORT_1,
+  USERIAL_PORT_2,
+  USERIAL_PORT_3,
+  USERIAL_PORT_4,
+  USERIAL_PORT_5,
+  USERIAL_PORT_6,
+  USERIAL_PORT_7,
+  USERIAL_PORT_8,
+  USERIAL_PORT_9,
+  USERIAL_PORT_10,
+  USERIAL_PORT_11,
+  USERIAL_PORT_12,
+  USERIAL_PORT_13,
+  USERIAL_PORT_14,
+  USERIAL_PORT_15,
+  USERIAL_PORT_16,
+  USERIAL_PORT_17,
+  USERIAL_PORT_18,
+} userial_port_t;
+
+// Initializes the userial module. This function should only be called once.
+// It returns true if the module was initialized, false if there was an error.
+bool userial_init(void);
+
+// Opens the given serial port. Returns true if successful, false otherwise.
+// Once this function is called, the userial module will begin producing
+// buffers from data read off the serial port. If you wish to pause the
+// production of buffers, call |userial_pause_reading|. You can then resume
+// by calling |userial_resume_reading|. This function returns true if the
+// serial port was successfully opened and buffer production has started. It
+// returns false if there was an error.
+bool userial_open(userial_port_t port);
+void userial_close(void);
+void userial_close_reader(void);
+
+// Reads a maximum of |len| bytes from the serial port into |p_buffer|.
+// This function returns the number of bytes actually read, which may be
+// less than |len|. This function will not block.
+uint16_t userial_read(uint16_t msg_id, uint8_t* p_buffer, uint16_t len);
+
+// Writes a maximum of |len| bytes from |p_data| to the serial port.
+// This function returns the number of bytes actually written, which may be
+// less than |len|. This function may block.
+uint16_t userial_write(uint16_t msg_id, const uint8_t* p_data, uint16_t len);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/hci/include/vendor.h b/bt/hci/include/vendor.h
new file mode 100644
index 0000000..1910263
--- /dev/null
+++ b/bt/hci/include/vendor.h
@@ -0,0 +1,78 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+#include <stdint.h>
+
+#include "bt_types.h"
+#include "bt_vendor_lib.h"
+#include "hci_internals.h"
+#include "hci_layer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+  VENDOR_CHIP_POWER_CONTROL = BT_VND_OP_POWER_CTRL,
+  VENDOR_OPEN_USERIAL = BT_VND_OP_USERIAL_OPEN,
+  VENDOR_CLOSE_USERIAL = BT_VND_OP_USERIAL_CLOSE,
+  VENDOR_GET_LPM_IDLE_TIMEOUT = BT_VND_OP_GET_LPM_IDLE_TIMEOUT,
+  VENDOR_SET_LPM_WAKE_STATE = BT_VND_OP_LPM_WAKE_SET_STATE,
+  VENDOR_SET_AUDIO_STATE = BT_VND_OP_SET_AUDIO_STATE
+} vendor_opcode_t;
+
+typedef enum {
+  VENDOR_CONFIGURE_FIRMWARE = BT_VND_OP_FW_CFG,
+  VENDOR_CONFIGURE_SCO = BT_VND_OP_SCO_CFG,
+  VENDOR_SET_LPM_MODE = BT_VND_OP_LPM_SET_MODE,
+  VENDOR_DO_EPILOG = BT_VND_OP_EPILOG,
+  VENDOR_A2DP_OFFLOAD_START = BT_VND_OP_A2DP_OFFLOAD_START,
+  VENDOR_A2DP_OFFLOAD_STOP = BT_VND_OP_A2DP_OFFLOAD_STOP,
+  VENDOR_LAST_OP
+} vendor_async_opcode_t;
+
+typedef void (*vendor_cb)(bool success);
+
+typedef struct vendor_t {
+  // Opens the vendor-specific library and sets the Bluetooth
+  // address of the adapter to |local_bdaddr|. |hci_interface| is
+  // used to send commands on behalf of the vendor library.
+  bool (*open)(const uint8_t* local_bdaddr, const hci_t* hci_interface);
+
+  // Closes the vendor-specific library and frees all associated resources.
+  // Only |vendor_open| may be called after |vendor_close|.
+  void (*close)(void);
+
+  // Sends a vendor-specific command to the library.
+  int (*send_command)(vendor_opcode_t opcode, void* param);
+
+  // Sends an asynchronous vendor-specific command to the library.
+  int (*send_async_command)(vendor_async_opcode_t opcode, void* param);
+
+  // Registers a callback for an asynchronous vendor-specific command.
+  void (*set_callback)(vendor_async_opcode_t opcode, vendor_cb callback);
+} vendor_t;
+
+const vendor_t* vendor_get_interface();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/hci/src/btsnoop.cc b/bt/hci/src/btsnoop.cc
new file mode 100644
index 0000000..db5fbcc
--- /dev/null
+++ b/bt/hci/src/btsnoop.cc
@@ -0,0 +1,237 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_snoop"
+
+#include <arpa/inet.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "bt_types.h"
+#include "hci/include/btsnoop.h"
+#include "hci/include/btsnoop_mem.h"
+#include "hci_layer.h"
+#include "osi/include/log.h"
+#include "stack_config.h"
+
+typedef enum {
+  kCommandPacket = 1,
+  kAclPacket = 2,
+  kScoPacket = 3,
+  kEventPacket = 4
+} packet_type_t;
+
+// Epoch in microseconds since 01/01/0000.
+static const uint64_t BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL;
+
+static const stack_config_t* stack_config;
+
+static int logfile_fd = INVALID_FD;
+static bool module_started;
+static bool is_logging;
+static bool logging_enabled_via_api;
+
+// TODO(zachoverflow): merge btsnoop and btsnoop_net together
+void btsnoop_net_open();
+void btsnoop_net_close();
+void btsnoop_net_write(const void* data, size_t length);
+
+static void btsnoop_write_packet(packet_type_t type, const uint8_t* packet,
+                                 bool is_received);
+static void update_logging();
+
+// Module lifecycle functions
+
+static future_t* start_up(void) {
+  module_started = true;
+  update_logging();
+
+  return NULL;
+}
+
+static future_t* shut_down(void) {
+  module_started = false;
+  update_logging();
+
+  return NULL;
+}
+
+EXPORT_SYMBOL extern const module_t btsnoop_module = {
+    .name = BTSNOOP_MODULE,
+    .init = NULL,
+    .start_up = start_up,
+    .shut_down = shut_down,
+    .clean_up = NULL,
+    .dependencies = {STACK_CONFIG_MODULE, NULL}};
+
+// Interface functions
+
+static void set_api_wants_to_log(bool value) {
+  logging_enabled_via_api = value;
+  update_logging();
+}
+
+static void capture(const BT_HDR* buffer, bool is_received) {
+  const uint8_t* p = buffer->data + buffer->offset;
+
+  btsnoop_mem_capture(buffer);
+
+  if (logfile_fd == INVALID_FD) return;
+
+  switch (buffer->event & MSG_EVT_MASK) {
+    case MSG_HC_TO_STACK_HCI_EVT:
+      btsnoop_write_packet(kEventPacket, p, false);
+      break;
+    case MSG_HC_TO_STACK_HCI_ACL:
+    case MSG_STACK_TO_HC_HCI_ACL:
+      btsnoop_write_packet(kAclPacket, p, is_received);
+      break;
+    case MSG_HC_TO_STACK_HCI_SCO:
+    case MSG_STACK_TO_HC_HCI_SCO:
+      btsnoop_write_packet(kScoPacket, p, is_received);
+      break;
+    case MSG_STACK_TO_HC_HCI_CMD:
+      btsnoop_write_packet(kCommandPacket, p, true);
+      break;
+  }
+}
+
+static const btsnoop_t interface = {set_api_wants_to_log, capture};
+
+const btsnoop_t* btsnoop_get_interface() {
+  stack_config = stack_config_get_interface();
+  return &interface;
+}
+
+// Internal functions
+
+static uint64_t btsnoop_timestamp(void) {
+  struct timeval tv;
+  gettimeofday(&tv, NULL);
+
+  // Timestamp is in microseconds.
+  uint64_t timestamp = tv.tv_sec;
+  timestamp *= (uint64_t)1000000ULL;
+  timestamp += tv.tv_usec;
+  timestamp += BTSNOOP_EPOCH_DELTA;
+  return timestamp;
+}
+
+static void update_logging() {
+  bool should_log = module_started && (logging_enabled_via_api ||
+                                       stack_config->get_btsnoop_turned_on());
+
+  if (should_log == is_logging) return;
+
+  is_logging = should_log;
+  if (should_log) {
+    const char* log_path = stack_config->get_btsnoop_log_path();
+
+    // Save the old log if configured to do so
+    if (stack_config->get_btsnoop_should_save_last()) {
+      char last_log_path[PATH_MAX];
+      snprintf(last_log_path, PATH_MAX, "%s.%" PRIu64, log_path,
+               btsnoop_timestamp());
+      if (!rename(log_path, last_log_path) && errno != ENOENT)
+        LOG_ERROR(LOG_TAG, "%s unable to rename '%s' to '%s': %s", __func__,
+                  log_path, last_log_path, strerror(errno));
+    }
+
+    mode_t prevmask = umask(0);
+    logfile_fd = open(log_path, O_WRONLY | O_CREAT | O_TRUNC,
+                      S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+    if (logfile_fd == INVALID_FD) {
+      LOG_ERROR(LOG_TAG, "%s unable to open '%s': %s", __func__, log_path,
+                strerror(errno));
+      is_logging = false;
+      umask(prevmask);
+      return;
+    }
+    umask(prevmask);
+
+    write(logfile_fd, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16);
+    btsnoop_net_open();
+  } else {
+    if (logfile_fd != INVALID_FD) close(logfile_fd);
+
+    logfile_fd = INVALID_FD;
+    btsnoop_net_close();
+  }
+}
+
+static void btsnoop_write(const void* data, size_t length) {
+  if (logfile_fd != INVALID_FD) write(logfile_fd, data, length);
+
+  btsnoop_net_write(data, length);
+}
+
+static void btsnoop_write_packet(packet_type_t type, const uint8_t* packet,
+                                 bool is_received) {
+  int length_he = 0;
+  int length;
+  int flags;
+  int drops = 0;
+  switch (type) {
+    case kCommandPacket:
+      length_he = packet[2] + 4;
+      flags = 2;
+      break;
+    case kAclPacket:
+      length_he = (packet[3] << 8) + packet[2] + 5;
+      flags = is_received;
+      break;
+    case kScoPacket:
+      length_he = packet[2] + 4;
+      flags = is_received;
+      break;
+    case kEventPacket:
+      length_he = packet[1] + 3;
+      flags = 3;
+      break;
+  }
+
+  uint64_t timestamp = btsnoop_timestamp();
+  uint32_t time_hi = timestamp >> 32;
+  uint32_t time_lo = timestamp & 0xFFFFFFFF;
+
+  length = htonl(length_he);
+  flags = htonl(flags);
+  drops = htonl(drops);
+  time_hi = htonl(time_hi);
+  time_lo = htonl(time_lo);
+
+  btsnoop_write(&length, 4);
+  btsnoop_write(&length, 4);
+  btsnoop_write(&flags, 4);
+  btsnoop_write(&drops, 4);
+  btsnoop_write(&time_hi, 4);
+  btsnoop_write(&time_lo, 4);
+  btsnoop_write(&type, 1);
+  btsnoop_write(packet, length_he - 1);
+}
diff --git a/bt/hci/src/btsnoop_mem.cc b/bt/hci/src/btsnoop_mem.cc
new file mode 100644
index 0000000..443dbb9
--- /dev/null
+++ b/bt/hci/src/btsnoop_mem.cc
@@ -0,0 +1,58 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <assert.h>
+#include <time.h>
+
+#include "hci/include/btsnoop_mem.h"
+
+static btsnoop_data_cb data_callback = NULL;
+
+void btsnoop_mem_set_callback(btsnoop_data_cb cb) { data_callback = cb; }
+
+void btsnoop_mem_capture(const BT_HDR* packet) {
+  if (!data_callback) return;
+
+  assert(packet);
+
+  const uint8_t* data = &packet->data[packet->offset];
+  const uint16_t type = packet->event & BT_EVT_MASK;
+  size_t length = 0;
+
+  switch (type) {
+    case BT_EVT_TO_LM_HCI_CMD:
+      if (packet->len > 2) length = data[2] + 3;
+      break;
+
+    case BT_EVT_TO_BTU_HCI_EVT:
+      if (packet->len > 1) length = data[1] + 2;
+      break;
+
+    case BT_EVT_TO_LM_HCI_ACL:
+    case BT_EVT_TO_BTU_HCI_ACL:
+      if (packet->len > 3) length = (data[2] | (data[3] << 8)) + 4;
+      break;
+
+    case BT_EVT_TO_LM_HCI_SCO:
+    case BT_EVT_TO_BTU_HCI_SCO:
+      if (packet->len > 2) length = data[2] + 3;
+      break;
+  }
+
+  if (length) (*data_callback)(type, data, length);
+}
diff --git a/bt/hci/src/btsnoop_net.cc b/bt/hci/src/btsnoop_net.cc
new file mode 100644
index 0000000..bce7885
--- /dev/null
+++ b/bt/hci/src/btsnoop_net.cc
@@ -0,0 +1,161 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2013 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_snoop_net"
+
+#include <assert.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+static void safe_close_(int* fd);
+static void* listen_fn_(void* context);
+
+static const char* LISTEN_THREAD_NAME_ = "btsnoop_net_listen";
+static const int LOCALHOST_ = 0x7F000001;
+static const int LISTEN_PORT_ = 8872;
+
+static pthread_t listen_thread_;
+static bool listen_thread_valid_ = false;
+static pthread_mutex_t client_socket_lock_ = PTHREAD_MUTEX_INITIALIZER;
+static int listen_socket_ = -1;
+static int client_socket_ = -1;
+
+void btsnoop_net_open() {
+#if (BT_NET_DEBUG != TRUE)
+  return;  // Disable using network sockets for security reasons
+#endif
+
+  listen_thread_valid_ =
+      (pthread_create(&listen_thread_, NULL, listen_fn_, NULL) == 0);
+  if (!listen_thread_valid_) {
+    LOG_ERROR(LOG_TAG, "%s pthread_create failed: %s", __func__,
+              strerror(errno));
+  } else {
+    LOG_DEBUG(LOG_TAG, "initialized");
+  }
+}
+
+void btsnoop_net_close() {
+#if (BT_NET_DEBUG != TRUE)
+  return;  // Disable using network sockets for security reasons
+#endif
+
+  if (listen_thread_valid_) {
+    shutdown(listen_socket_, SHUT_RDWR);
+    pthread_join(listen_thread_, NULL);
+    safe_close_(&client_socket_);
+    listen_thread_valid_ = false;
+  }
+}
+
+void btsnoop_net_write(const void* data, size_t length) {
+#if (BT_NET_DEBUG != TRUE)
+  return;  // Disable using network sockets for security reasons
+#endif
+
+  pthread_mutex_lock(&client_socket_lock_);
+  if (client_socket_ != -1) {
+    ssize_t ret;
+    OSI_NO_INTR(ret = send(client_socket_, data, length, 0));
+
+    if (ret == -1 && errno == ECONNRESET) {
+      safe_close_(&client_socket_);
+    }
+  }
+  pthread_mutex_unlock(&client_socket_lock_);
+}
+
+static void* listen_fn_(UNUSED_ATTR void* context) {
+  int enable = 1;
+
+  prctl(PR_SET_NAME, (unsigned long)LISTEN_THREAD_NAME_, 0, 0, 0);
+
+  listen_socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (listen_socket_ == -1) {
+    LOG_ERROR(LOG_TAG, "%s socket creation failed: %s", __func__,
+              strerror(errno));
+    goto cleanup;
+  }
+
+  if (setsockopt(listen_socket_, SOL_SOCKET, SO_REUSEADDR, &enable,
+                 sizeof(enable)) == -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to set SO_REUSEADDR: %s", __func__,
+              strerror(errno));
+    goto cleanup;
+  }
+
+  struct sockaddr_in addr;
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = htonl(LOCALHOST_);
+  addr.sin_port = htons(LISTEN_PORT_);
+  if (bind(listen_socket_, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to bind listen socket: %s", __func__,
+              strerror(errno));
+    goto cleanup;
+  }
+
+  if (listen(listen_socket_, 10) == -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to listen: %s", __func__, strerror(errno));
+    goto cleanup;
+  }
+
+  for (;;) {
+    int client_socket;
+    OSI_NO_INTR(client_socket = accept(listen_socket_, NULL, NULL));
+    if (client_socket == -1) {
+      if (errno == EINVAL || errno == EBADF) {
+        break;
+      }
+      LOG_WARN(LOG_TAG, "%s error accepting socket: %s", __func__,
+               strerror(errno));
+      continue;
+    }
+
+    /* When a new client connects, we have to send the btsnoop file header. This
+     * allows a decoder to treat the session as a new, valid btsnoop file. */
+    pthread_mutex_lock(&client_socket_lock_);
+    safe_close_(&client_socket_);
+    client_socket_ = client_socket;
+
+    OSI_NO_INTR(send(client_socket_, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16, 0));
+    pthread_mutex_unlock(&client_socket_lock_);
+  }
+
+cleanup:
+  safe_close_(&listen_socket_);
+  return NULL;
+}
+
+static void safe_close_(int* fd) {
+  assert(fd != NULL);
+  if (*fd != -1) {
+    close(*fd);
+    *fd = -1;
+  }
+}
diff --git a/bt/hci/src/buffer_allocator.cc b/bt/hci/src/buffer_allocator.cc
new file mode 100644
index 0000000..3988fc9
--- /dev/null
+++ b/bt/hci/src/buffer_allocator.cc
@@ -0,0 +1,31 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <assert.h>
+
+#include "bt_common.h"
+#include "buffer_allocator.h"
+
+static void* buffer_alloc(size_t size) {
+  assert(size <= BT_DEFAULT_BUFFER_SIZE);
+  return osi_malloc(size);
+}
+
+static const allocator_t interface = {buffer_alloc, osi_free};
+
+const allocator_t* buffer_allocator_get_interface() { return &interface; }
diff --git a/bt/hci/src/hci_audio.cc b/bt/hci/src/hci_audio.cc
new file mode 100644
index 0000000..1714063
--- /dev/null
+++ b/bt/hci/src/hci_audio.cc
@@ -0,0 +1,38 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_hci_audio"
+
+#include "hci/include/hci_audio.h"
+
+#include "hci/include/bt_vendor_lib.h"
+#include "hci/include/vendor.h"
+#include "osi/include/log.h"
+
+void set_audio_state(uint16_t handle, sco_codec_t codec, sco_state_t state) {
+  LOG_INFO(LOG_TAG, "%s handle:%d codec:0x%x state:%d", __func__, handle, codec,
+           state);
+
+  bt_vendor_op_audio_state_t audio_state;
+
+  audio_state.handle = handle;
+  audio_state.peer_codec = codec;
+  audio_state.state = state;
+
+  vendor_get_interface()->send_command(VENDOR_SET_AUDIO_STATE, &audio_state);
+}
diff --git a/bt/hci/src/hci_hal.cc b/bt/hci/src/hci_hal.cc
new file mode 100644
index 0000000..2e83050
--- /dev/null
+++ b/bt/hci/src/hci_hal.cc
@@ -0,0 +1,27 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_hal.h"
+
+const hci_hal_t* hci_hal_get_interface() {
+#if (HCI_USE_MCT == TRUE)
+  return hci_hal_mct_get_interface();
+#else
+  return hci_hal_h4_get_interface();
+#endif
+}
diff --git a/bt/hci/src/hci_hal_h4.cc b/bt/hci/src/hci_hal_h4.cc
new file mode 100644
index 0000000..ec1cf0f
--- /dev/null
+++ b/bt/hci/src/hci_hal_h4.cc
@@ -0,0 +1,293 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_hci_h4"
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "hci_hal.h"
+#include "osi/include/eager_reader.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/reactor.h"
+#include "osi/include/thread.h"
+#include "vendor.h"
+
+#define HCI_HAL_SERIAL_BUFFER_SIZE 1026
+#define HCI_BLE_EVENT 0x3e
+
+// Increased HCI thread priority to keep up with the audio sub-system
+// when streaming time sensitive data (A2DP).
+#define HCI_THREAD_PRIORITY (-19)
+
+#define BT_HCI_UNKNOWN_MESSAGE_TYPE_NUM 1010002
+
+static bool hal_init(const hci_hal_callbacks_t* upper_callbacks,
+                     thread_t* upper_thread);
+static bool hal_open(void);
+static void hal_close(void);
+static void packet_finished(serial_data_type_t type);
+static uint16_t transmit_data(serial_data_type_t type, uint8_t* data,
+                              uint16_t length);
+static size_t read_data(serial_data_type_t type, uint8_t* buffer,
+                        size_t max_size);
+static void event_uart_has_bytes(eager_reader_t* reader, void* context);
+
+// Our interface and modules we import
+static const hci_hal_t interface = {
+    hal_init, hal_open, hal_close, read_data, packet_finished, transmit_data,
+};
+static const hci_hal_callbacks_t* callbacks;
+static const vendor_t* vendor;
+
+static thread_t* thread;  // Not owned by us
+
+static int uart_fd;
+static eager_reader_t* uart_stream;
+static serial_data_type_t current_data_type;
+static bool stream_has_interpretation;
+static bool stream_corruption_detected;
+static uint8_t stream_corruption_bytes_to_ignore;
+
+// Interface functions
+
+static bool hal_init(const hci_hal_callbacks_t* upper_callbacks,
+                     thread_t* upper_thread) {
+  assert(upper_callbacks != NULL);
+  assert(upper_thread != NULL);
+
+  callbacks = upper_callbacks;
+  thread = upper_thread;
+  return true;
+}
+
+static bool hal_open(void) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  // TODO(zachoverflow): close if already open / or don't reopen (maybe at the
+  // hci layer level)
+
+  int fd_array[CH_MAX];
+  int number_of_ports = vendor->send_command(VENDOR_OPEN_USERIAL, &fd_array);
+
+  if (number_of_ports != 1) {
+    LOG_ERROR(LOG_TAG,
+              "%s opened the wrong number of ports: got %d, expected 1.",
+              __func__, number_of_ports);
+    goto error;
+  }
+
+  uart_fd = fd_array[0];
+  if (uart_fd == INVALID_FD) {
+    LOG_ERROR(LOG_TAG, "%s unable to open the uart serial port.", __func__);
+    goto error;
+  }
+
+  uart_stream =
+      eager_reader_new(uart_fd, &allocator_malloc, HCI_HAL_SERIAL_BUFFER_SIZE,
+                       SIZE_MAX, "hci_single_channel");
+  if (!uart_stream) {
+    LOG_ERROR(LOG_TAG,
+              "%s unable to create eager reader for the uart serial port.",
+              __func__);
+    goto error;
+  }
+
+  stream_has_interpretation = false;
+  stream_corruption_detected = false;
+  stream_corruption_bytes_to_ignore = 0;
+  eager_reader_register(uart_stream, thread_get_reactor(thread),
+                        event_uart_has_bytes, NULL);
+
+  // Raise thread priorities to keep up with audio
+  thread_set_priority(thread, HCI_THREAD_PRIORITY);
+  thread_set_priority(eager_reader_get_read_thread(uart_stream),
+                      HCI_THREAD_PRIORITY);
+
+  return true;
+
+error:
+  interface.close();
+  return false;
+}
+
+static void hal_close(void) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+
+  eager_reader_free(uart_stream);
+  uart_stream = NULL;
+
+  vendor->send_command(VENDOR_CLOSE_USERIAL, NULL);
+  uart_fd = INVALID_FD;
+}
+
+static size_t read_data(serial_data_type_t type, uint8_t* buffer,
+                        size_t max_size) {
+  if (type < DATA_TYPE_ACL || type > DATA_TYPE_EVENT) {
+    LOG_ERROR(LOG_TAG, "%s invalid data type: %d", __func__, type);
+    return 0;
+  } else if (!stream_has_interpretation) {
+    LOG_ERROR(LOG_TAG, "%s with no valid stream intepretation.", __func__);
+    return 0;
+  } else if (current_data_type != type) {
+    LOG_ERROR(LOG_TAG, "%s with different type than existing interpretation.",
+              __func__);
+    return 0;
+  }
+
+  return eager_reader_read(uart_stream, buffer, max_size);
+}
+
+static void packet_finished(serial_data_type_t type) {
+  if (!stream_has_interpretation)
+    LOG_ERROR(LOG_TAG, "%s with no existing stream interpretation.", __func__);
+  else if (current_data_type != type)
+    LOG_ERROR(LOG_TAG, "%s with different type than existing interpretation.",
+              __func__);
+
+  stream_has_interpretation = false;
+}
+
+static uint16_t transmit_data(serial_data_type_t type, uint8_t* data,
+                              uint16_t length) {
+  assert(data != NULL);
+  assert(length > 0);
+
+  if (type < DATA_TYPE_COMMAND || type > DATA_TYPE_SCO) {
+    LOG_ERROR(LOG_TAG, "%s invalid data type: %d", __func__, type);
+    return 0;
+  }
+
+  // Write the signal byte right before the data
+  --data;
+  uint8_t previous_byte = *data;
+  *(data) = type;
+  ++length;
+
+  uint16_t transmitted_length = 0;
+  while (length > 0) {
+    ssize_t ret;
+    OSI_NO_INTR(ret = write(uart_fd, data + transmitted_length, length));
+    switch (ret) {
+      case -1:
+        if (errno == EAGAIN) continue;
+
+        LOG_ERROR(LOG_TAG, "In %s, error writing to the uart serial port: %s",
+                  __func__, strerror(errno));
+        goto done;
+      case 0:
+        // If we wrote nothing, don't loop more because we
+        // can't go to infinity or beyond
+        goto done;
+      default:
+        transmitted_length += ret;
+        length -= ret;
+        break;
+    }
+  }
+
+done:;
+  // Be nice and restore the old value of that byte
+  *(data) = previous_byte;
+
+  // Remove the signal byte from our transmitted length, if it was actually
+  // written
+  if (transmitted_length > 0) --transmitted_length;
+
+  return transmitted_length;
+}
+
+// Internal functions
+
+// WORKAROUND:
+// As exhibited by b/23934838, during result-heavy LE scans, the UART byte
+// stream can get corrupted, leading to assertions caused by mis-interpreting
+// the bytes following the corruption.
+// This workaround looks for tell-tale signs of a BLE event and attempts to
+// skip the correct amount of bytes in the stream to re-synchronize onto
+// a packet boundary.
+// Function returns true if |byte_read| has been processed by the workaround.
+static bool stream_corrupted_during_le_scan_workaround(
+    const uint8_t byte_read) {
+  if (!stream_corruption_detected && byte_read == HCI_BLE_EVENT) {
+    LOG_ERROR(LOG_TAG, "%s HCI stream corrupted (message type 0x3E)!",
+              __func__);
+    stream_corruption_detected = true;
+    return true;
+  }
+
+  if (stream_corruption_detected) {
+    if (stream_corruption_bytes_to_ignore == 0) {
+      stream_corruption_bytes_to_ignore = byte_read;
+      LOG_ERROR(LOG_TAG, "%s About to skip %d bytes...", __func__,
+                stream_corruption_bytes_to_ignore);
+    } else {
+      --stream_corruption_bytes_to_ignore;
+    }
+
+    if (stream_corruption_bytes_to_ignore == 0) {
+      LOG_ERROR(LOG_TAG, "%s Back to our regularly scheduled program...",
+                __func__);
+      stream_corruption_detected = false;
+    }
+    return true;
+  }
+
+  return false;
+}
+
+// See what data is waiting, and notify the upper layer
+static void event_uart_has_bytes(eager_reader_t* reader,
+                                 UNUSED_ATTR void* context) {
+  if (stream_has_interpretation) {
+    callbacks->data_ready(current_data_type);
+  } else {
+    uint8_t type_byte;
+    if (eager_reader_read(reader, &type_byte, 1) == 0) {
+      LOG_ERROR(LOG_TAG, "%s could not read HCI message type", __func__);
+      return;
+    }
+
+    if (stream_corrupted_during_le_scan_workaround(type_byte)) return;
+
+    if (type_byte < DATA_TYPE_ACL || type_byte > DATA_TYPE_EVENT) {
+      LOG_ERROR(
+          LOG_TAG,
+          "%s Unknown HCI message type 0x%x (min=0x%x max=0x%x). Aborting...",
+          __func__, type_byte, DATA_TYPE_ACL, DATA_TYPE_EVENT);
+      LOG_EVENT_INT(BT_HCI_UNKNOWN_MESSAGE_TYPE_NUM, type_byte);
+      assert(false && "Unknown HCI message type");
+      return;
+    }
+
+    stream_has_interpretation = true;
+    current_data_type = static_cast<serial_data_type_t>(type_byte);
+  }
+}
+
+const hci_hal_t* hci_hal_h4_get_interface() {
+  vendor = vendor_get_interface();
+  return &interface;
+}
+
+const hci_hal_t* hci_hal_h4_get_test_interface(vendor_t* vendor_interface) {
+  vendor = vendor_interface;
+  return &interface;
+}
diff --git a/bt/hci/src/hci_hal_mct.cc b/bt/hci/src/hci_hal_mct.cc
new file mode 100644
index 0000000..0e7db9c
--- /dev/null
+++ b/bt/hci/src/hci_hal_mct.cc
@@ -0,0 +1,241 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_hci_mct"
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "bt_vendor_lib.h"
+#include "hci_hal.h"
+#include "osi/include/eager_reader.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/reactor.h"
+#include "vendor.h"
+
+#define HCI_HAL_SERIAL_BUFFER_SIZE 1026
+
+static bool hal_init(const hci_hal_callbacks_t* upper_callbacks,
+                     thread_t* upper_thread);
+static bool hal_open(void);
+static void hal_close(void);
+static size_t read_data(serial_data_type_t type, uint8_t* buffer,
+                        size_t max_size);
+static void packet_finished(UNUSED_ATTR serial_data_type_t type);
+static uint16_t transmit_data(serial_data_type_t type, uint8_t* data,
+                              uint16_t length);
+static uint16_t transmit_data_on(int fd, uint8_t* data, uint16_t length);
+static void event_event_stream_has_bytes(eager_reader_t* reader, void* context);
+static void event_acl_stream_has_bytes(eager_reader_t* reader, void* context);
+
+// Our interface and modules we import
+static const hci_hal_t interface = {
+    hal_init, hal_open, hal_close, read_data, packet_finished, transmit_data,
+};
+static const hci_hal_callbacks_t* callbacks;
+static const vendor_t* vendor;
+
+static thread_t* thread;  // Not owned by us
+
+static int uart_fds[CH_MAX];
+static eager_reader_t* event_stream;
+static eager_reader_t* acl_stream;
+
+// Interface functions
+
+static bool hal_init(const hci_hal_callbacks_t* upper_callbacks,
+                     thread_t* upper_thread) {
+  assert(upper_callbacks != NULL);
+  assert(upper_thread != NULL);
+
+  callbacks = upper_callbacks;
+  thread = upper_thread;
+  return true;
+}
+
+static bool hal_open(void) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  // TODO(zachoverflow): close if already open / or don't reopen (maybe at the
+  // hci layer level)
+
+  int number_of_ports = vendor->send_command(VENDOR_OPEN_USERIAL, &uart_fds);
+
+  if (number_of_ports != 2 && number_of_ports != 4) {
+    LOG_ERROR(LOG_TAG,
+              "%s opened the wrong number of ports: got %d, expected 2 or 4.",
+              __func__, number_of_ports);
+    goto error;
+  }
+
+  LOG_INFO(LOG_TAG, "%s got uart fds: CMD=%d, EVT=%d, ACL_OUT=%d, ACL_IN=%d",
+           __func__, uart_fds[CH_CMD], uart_fds[CH_EVT], uart_fds[CH_ACL_OUT],
+           uart_fds[CH_ACL_IN]);
+
+  if (uart_fds[CH_CMD] == INVALID_FD) {
+    LOG_ERROR(LOG_TAG, "%s unable to open the command uart serial port.",
+              __func__);
+    goto error;
+  }
+
+  if (uart_fds[CH_EVT] == INVALID_FD) {
+    LOG_ERROR(LOG_TAG, "%s unable to open the event uart serial port.",
+              __func__);
+    goto error;
+  }
+
+  if (uart_fds[CH_ACL_OUT] == INVALID_FD) {
+    LOG_ERROR(LOG_TAG, "%s unable to open the acl-out uart serial port.",
+              __func__);
+    goto error;
+  }
+
+  if (uart_fds[CH_ACL_IN] == INVALID_FD) {
+    LOG_ERROR(LOG_TAG, "%s unable to open the acl-in uart serial port.",
+              __func__);
+    goto error;
+  }
+
+  event_stream =
+      eager_reader_new(uart_fds[CH_EVT], &allocator_malloc,
+                       HCI_HAL_SERIAL_BUFFER_SIZE, SIZE_MAX, "hci_mct");
+  if (!event_stream) {
+    LOG_ERROR(
+        LOG_TAG,
+        "%s unable to create eager reader for the event uart serial port.",
+        __func__);
+    goto error;
+  }
+
+  acl_stream =
+      eager_reader_new(uart_fds[CH_ACL_IN], &allocator_malloc,
+                       HCI_HAL_SERIAL_BUFFER_SIZE, SIZE_MAX, "hci_mct");
+  if (!acl_stream) {
+    LOG_ERROR(
+        LOG_TAG,
+        "%s unable to create eager reader for the acl-in uart serial port.",
+        __func__);
+    goto error;
+  }
+
+  eager_reader_register(event_stream, thread_get_reactor(thread),
+                        event_event_stream_has_bytes, NULL);
+  eager_reader_register(acl_stream, thread_get_reactor(thread),
+                        event_acl_stream_has_bytes, NULL);
+
+  return true;
+
+error:;
+  interface.close();
+  return false;
+}
+
+static void hal_close(void) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+
+  eager_reader_free(event_stream);
+  event_stream = NULL;
+
+  eager_reader_free(acl_stream);
+  acl_stream = NULL;
+
+  vendor->send_command(VENDOR_CLOSE_USERIAL, NULL);
+
+  for (int i = 0; i < CH_MAX; i++) uart_fds[i] = INVALID_FD;
+}
+
+static size_t read_data(serial_data_type_t type, uint8_t* buffer,
+                        size_t max_size) {
+  if (type == DATA_TYPE_ACL) {
+    return eager_reader_read(acl_stream, buffer, max_size);
+  } else if (type == DATA_TYPE_EVENT) {
+    return eager_reader_read(event_stream, buffer, max_size);
+  }
+
+  LOG_ERROR(LOG_TAG, "%s invalid data type: %d", __func__, type);
+  return 0;
+}
+
+static void packet_finished(UNUSED_ATTR serial_data_type_t type) {
+  // not needed by this protocol
+}
+
+static uint16_t transmit_data(serial_data_type_t type, uint8_t* data,
+                              uint16_t length) {
+  if (type == DATA_TYPE_ACL) {
+    return transmit_data_on(uart_fds[CH_ACL_OUT], data, length);
+  } else if (type == DATA_TYPE_COMMAND) {
+    return transmit_data_on(uart_fds[CH_CMD], data, length);
+  }
+
+  LOG_ERROR(LOG_TAG, "%s invalid data type: %d", __func__, type);
+  return 0;
+}
+
+// Internal functions
+
+static uint16_t transmit_data_on(int fd, uint8_t* data, uint16_t length) {
+  assert(data != NULL);
+  assert(length > 0);
+
+  uint16_t transmitted_length = 0;
+  while (length > 0) {
+    ssize_t ret;
+    OSI_NO_INTR(ret = write(fd, data + transmitted_length, length));
+    switch (ret) {
+      case -1:
+        LOG_ERROR(LOG_TAG,
+                  "In %s, error writing to the serial port with fd %d: %s",
+                  __func__, fd, strerror(errno));
+        return transmitted_length;
+      case 0:
+        // If we wrote nothing, don't loop more because we
+        // can't go to infinity or beyond
+        return transmitted_length;
+      default:
+        transmitted_length += ret;
+        length -= ret;
+        break;
+    }
+  }
+
+  return transmitted_length;
+}
+
+static void event_event_stream_has_bytes(UNUSED_ATTR eager_reader_t* reader,
+                                         UNUSED_ATTR void* context) {
+  callbacks->data_ready(DATA_TYPE_EVENT);
+}
+
+static void event_acl_stream_has_bytes(UNUSED_ATTR eager_reader_t* reader,
+                                       UNUSED_ATTR void* context) {
+  // No real concept of incoming SCO typed data, just ACL
+  callbacks->data_ready(DATA_TYPE_ACL);
+}
+
+const hci_hal_t* hci_hal_mct_get_interface() {
+  vendor = vendor_get_interface();
+  return &interface;
+}
+
+const hci_hal_t* hci_hal_mct_get_test_interface(vendor_t* vendor_interface) {
+  vendor = vendor_interface;
+  return &interface;
+}
diff --git a/bt/hci/src/hci_inject.cc b/bt/hci/src/hci_inject.cc
new file mode 100644
index 0000000..9e4b875
--- /dev/null
+++ b/bt/hci/src/hci_inject.cc
@@ -0,0 +1,204 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_hci_inject"
+
+#include "hci_inject.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include "bt_types.h"
+#include "buffer_allocator.h"
+#include "hci_layer.h"
+#include "osi/include/allocator.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/socket.h"
+#include "osi/include/thread.h"
+
+typedef enum {
+  HCI_PACKET_COMMAND = 1,
+  HCI_PACKET_ACL_DATA = 2,
+  HCI_PACKET_SCO_DATA = 3,
+  HCI_PACKET_EVENT = 4,
+} hci_packet_t;
+
+typedef struct {
+  socket_t* socket;
+  uint8_t buffer[65536 + 3];  // 2 bytes length prefix, 1 byte type prefix.
+  size_t buffer_size;
+} client_t;
+
+static bool hci_inject_open(const hci_t* hci_interface);
+static void hci_inject_close(void);
+static int hci_packet_to_event(hci_packet_t packet);
+static void accept_ready(socket_t* socket, void* context);
+static void read_ready(socket_t* socket, void* context);
+static void client_free(void* ptr);
+
+static const port_t LISTEN_PORT = 8873;
+
+static const hci_inject_t interface = {hci_inject_open, hci_inject_close};
+
+static const hci_t* hci;
+static const allocator_t* buffer_allocator;
+static socket_t* listen_socket;
+static thread_t* thread;
+static list_t* clients;
+
+static bool hci_inject_open(const hci_t* hci_interface) {
+#if (BT_NET_DEBUG != TRUE)
+  return true;  // Disable using network sockets for security reasons
+#endif
+
+  assert(listen_socket == NULL);
+  assert(thread == NULL);
+  assert(clients == NULL);
+  assert(hci_interface != NULL);
+
+  hci = hci_interface;
+
+  thread = thread_new("hci_inject");
+  if (!thread) goto error;
+
+  clients = list_new(client_free);
+  if (!clients) goto error;
+
+  listen_socket = socket_new();
+  if (!listen_socket) goto error;
+
+  if (!socket_listen(listen_socket, LISTEN_PORT)) goto error;
+
+  socket_register(listen_socket, thread_get_reactor(thread), NULL, accept_ready,
+                  NULL);
+  return true;
+
+error:;
+  interface.close();
+  return false;
+}
+
+static void hci_inject_close(void) {
+#if (BT_NET_DEBUG != TRUE)
+  return;  // Disable using network sockets for security reasons
+#endif
+
+  socket_free(listen_socket);
+  list_free(clients);
+  thread_free(thread);
+
+  listen_socket = NULL;
+  thread = NULL;
+  clients = NULL;
+}
+
+static int hci_packet_to_event(hci_packet_t packet) {
+  switch (packet) {
+    case HCI_PACKET_COMMAND:
+      return MSG_STACK_TO_HC_HCI_CMD;
+    case HCI_PACKET_ACL_DATA:
+      return MSG_STACK_TO_HC_HCI_ACL;
+    case HCI_PACKET_SCO_DATA:
+      return MSG_STACK_TO_HC_HCI_SCO;
+    default:
+      LOG_ERROR(LOG_TAG, "%s unsupported packet type: %d", __func__, packet);
+      return -1;
+  }
+}
+
+static void accept_ready(socket_t* socket, UNUSED_ATTR void* context) {
+  assert(socket != NULL);
+  assert(socket == listen_socket);
+
+  socket = socket_accept(socket);
+  if (!socket) return;
+
+  client_t* client = (client_t*)osi_calloc(sizeof(client_t));
+
+  client->socket = socket;
+
+  if (!list_append(clients, client)) {
+    LOG_ERROR(LOG_TAG, "%s unable to add client to list.", __func__);
+    client_free(client);
+    return;
+  }
+
+  socket_register(socket, thread_get_reactor(thread), client, read_ready, NULL);
+}
+
+static void read_ready(UNUSED_ATTR socket_t* socket, void* context) {
+  assert(socket != NULL);
+  assert(context != NULL);
+
+  client_t* client = (client_t*)context;
+
+  ssize_t ret =
+      socket_read(client->socket, client->buffer + client->buffer_size,
+                  sizeof(client->buffer) - client->buffer_size);
+  if (ret == 0 || (ret == -1 && ret != EWOULDBLOCK && ret != EAGAIN)) {
+    list_remove(clients, client);
+    return;
+  }
+  client->buffer_size += ret;
+
+  while (client->buffer_size > 3) {
+    uint8_t* buffer = client->buffer;
+    hci_packet_t packet_type = (hci_packet_t)buffer[0];
+    size_t packet_len = (buffer[2] << 8) | buffer[1];
+    size_t frame_len = 3 + packet_len;
+
+    if (client->buffer_size < frame_len) break;
+
+    // TODO(sharvil): validate incoming HCI messages.
+    // TODO(sharvil): once we have an HCI parser, we can eliminate
+    //   the 2-byte size field since it will be contained in the packet.
+
+    BT_HDR* buf = (BT_HDR*)buffer_allocator->alloc(BT_HDR_SIZE + packet_len);
+    if (buf) {
+      buf->event = hci_packet_to_event(packet_type);
+      buf->offset = 0;
+      buf->layer_specific = 0;
+      buf->len = packet_len;
+      memcpy(buf->data, buffer + 3, packet_len);
+      hci->transmit_downward(buf->event, buf);
+    } else {
+      LOG_ERROR(LOG_TAG, "%s dropping injected packet of length %zu", __func__,
+                packet_len);
+    }
+
+    size_t remainder = client->buffer_size - frame_len;
+    memmove(buffer, buffer + frame_len, remainder);
+    client->buffer_size -= frame_len;
+  }
+}
+
+static void client_free(void* ptr) {
+  if (!ptr) return;
+
+  client_t* client = (client_t*)ptr;
+  socket_free(client->socket);
+  osi_free(client);
+}
+
+const hci_inject_t* hci_inject_get_interface() {
+  buffer_allocator = buffer_allocator_get_interface();
+  return &interface;
+}
diff --git a/bt/hci/src/hci_layer.cc b/bt/hci/src/hci_layer.cc
new file mode 100644
index 0000000..5a87bab
--- /dev/null
+++ b/bt/hci/src/hci_layer.cc
@@ -0,0 +1,877 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_hci"
+
+#include "hci_layer.h"
+
+#include <assert.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "btcore/include/module.h"
+#include "btsnoop.h"
+#include "buffer_allocator.h"
+#include "hci_hal.h"
+#include "hci_inject.h"
+#include "hci_internals.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "low_power_manager.h"
+#include "osi/include/alarm.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+#include "osi/include/reactor.h"
+#include "packet_fragmenter.h"
+#include "vendor.h"
+
+// TODO(zachoverflow): remove this hack extern
+#include <hardware/bluetooth.h>
+extern bt_bdaddr_t btif_local_bd_addr;
+
+#define INBOUND_PACKET_TYPE_COUNT 3
+#define PACKET_TYPE_TO_INBOUND_INDEX(type) ((type)-2)
+#define PACKET_TYPE_TO_INDEX(type) ((type)-1)
+
+#define PREAMBLE_BUFFER_SIZE 4  // max preamble size, ACL
+#define RETRIEVE_ACL_LENGTH(preamble) ((((preamble)[3]) << 8) | (preamble)[2])
+
+#define BT_HCI_TIMEOUT_TAG_NUM 1010000
+
+static const uint8_t preamble_sizes[] = {
+    HCI_COMMAND_PREAMBLE_SIZE, HCI_ACL_PREAMBLE_SIZE, HCI_SCO_PREAMBLE_SIZE,
+    HCI_EVENT_PREAMBLE_SIZE};
+
+static const uint16_t outbound_event_types[] = {
+    MSG_HC_TO_STACK_HCI_ERR, MSG_HC_TO_STACK_HCI_ACL, MSG_HC_TO_STACK_HCI_SCO,
+    MSG_HC_TO_STACK_HCI_EVT};
+
+typedef enum { BRAND_NEW, PREAMBLE, BODY, IGNORE, FINISHED } receive_state_t;
+
+typedef struct {
+  receive_state_t state;
+  uint16_t bytes_remaining;
+  uint8_t preamble[PREAMBLE_BUFFER_SIZE];
+  uint16_t index;
+  BT_HDR* buffer;
+} packet_receive_data_t;
+
+typedef struct {
+  uint16_t opcode;
+  future_t* complete_future;
+  command_complete_cb complete_callback;
+  command_status_cb status_callback;
+  void* context;
+  BT_HDR* command;
+} waiting_command_t;
+
+// Using a define here, because it can be stringified for the property lookup
+#define DEFAULT_STARTUP_TIMEOUT_MS 8000
+#define STRING_VALUE_OF(x) #x
+
+static const uint32_t EPILOG_TIMEOUT_MS = 3000;
+static const uint32_t COMMAND_PENDING_TIMEOUT_MS = 8000;
+
+static future_t* shut_down();
+
+static void event_finish_startup(void* context);
+static void firmware_config_callback(bool success);
+static void startup_timer_expired(void* context);
+
+static void event_postload(void* context);
+static void sco_config_callback(bool success);
+
+static void event_epilog(void* context);
+static void epilog_finished_callback(bool success);
+static void epilog_timer_expired(void* context);
+
+static void event_command_ready(fixed_queue_t* queue, void* context);
+static void event_packet_ready(fixed_queue_t* queue, void* context);
+static void transmit_fragment(BT_HDR* packet, bool send_transmit_finished);
+static void fragmenter_transmit_finished(BT_HDR* packet,
+                                         bool all_fragments_sent);
+static void dispatch_reassembled(BT_HDR* packet);
+static void command_timed_out(void* context);
+
+static void hal_says_data_ready(serial_data_type_t type);
+static bool filter_incoming_event(BT_HDR* packet);
+
+static serial_data_type_t event_to_data_type(uint16_t event);
+static waiting_command_t* get_waiting_command(command_opcode_t opcode);
+static void update_command_response_timer(void);
+
+// Our interface
+static const hci_hal_callbacks_t hal_callbacks = {hal_says_data_ready};
+
+static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks = {
+    transmit_fragment, dispatch_reassembled, fragmenter_transmit_finished};
+static bool interface_created;
+static hci_t interface;
+
+// Modules we import and callbacks we export
+static const allocator_t* buffer_allocator;
+static const btsnoop_t* btsnoop;
+static const hci_hal_t* hal;
+static const hci_inject_t* hci_inject;
+static const low_power_manager_t* low_power_manager;
+static const packet_fragmenter_t* packet_fragmenter;
+static const vendor_t* vendor;
+
+static future_t* startup_future;
+static thread_t* thread;  // We own this
+
+static volatile bool firmware_is_configured = false;
+static alarm_t* epilog_timer;
+static alarm_t* startup_timer;
+
+// Outbound-related
+static int command_credits = 1;
+static fixed_queue_t* command_queue;
+static fixed_queue_t* packet_queue;
+
+// Inbound-related
+static alarm_t* command_response_timer;
+static list_t* commands_pending_response;
+static pthread_mutex_t commands_pending_response_lock;
+static packet_receive_data_t incoming_packets[INBOUND_PACKET_TYPE_COUNT];
+
+// The hand-off point for data going to a higher layer, set by the higher layer
+static fixed_queue_t* upwards_data_queue;
+
+// Module lifecycle functions
+
+static future_t* start_up(void) {
+  int power_state = BT_VND_PWR_OFF;
+  future_t* local_startup_future;
+
+  LOG_INFO(LOG_TAG, "%s", __func__);
+
+  // The host is only allowed to send at most one command initially,
+  // as per the Bluetooth spec, Volume 2, Part E, 4.4 (Command Flow Control)
+  // This value can change when you get a command complete or command status
+  // event.
+  command_credits = 1;
+  firmware_is_configured = false;
+
+  pthread_mutex_init(&commands_pending_response_lock, NULL);
+
+  // For now, always use the default timeout on non-Android builds.
+  period_ms_t startup_timeout_ms = DEFAULT_STARTUP_TIMEOUT_MS;
+
+  // Grab the override startup timeout ms, if present.
+  char timeout_prop[PROPERTY_VALUE_MAX];
+  if (!osi_property_get("bluetooth.enable_timeout_ms", timeout_prop,
+                        STRING_VALUE_OF(DEFAULT_STARTUP_TIMEOUT_MS)) ||
+      (startup_timeout_ms = atoi(timeout_prop)) < 100)
+    startup_timeout_ms = DEFAULT_STARTUP_TIMEOUT_MS;
+
+  startup_timer = alarm_new("hci.startup_timer");
+  if (!startup_timer) {
+    LOG_ERROR(LOG_TAG, "%s unable to create startup timer.", __func__);
+    goto error;
+  }
+
+  epilog_timer = alarm_new("hci.epilog_timer");
+  if (!epilog_timer) {
+    LOG_ERROR(LOG_TAG, "%s unable to create epilog timer.", __func__);
+    goto error;
+  }
+
+  command_response_timer = alarm_new("hci.command_response_timer");
+  if (!command_response_timer) {
+    LOG_ERROR(LOG_TAG, "%s unable to create command response timer.", __func__);
+    goto error;
+  }
+
+  command_queue = fixed_queue_new(SIZE_MAX);
+  if (!command_queue) {
+    LOG_ERROR(LOG_TAG, "%s unable to create pending command queue.", __func__);
+    goto error;
+  }
+
+  packet_queue = fixed_queue_new(SIZE_MAX);
+  if (!packet_queue) {
+    LOG_ERROR(LOG_TAG, "%s unable to create pending packet queue.", __func__);
+    goto error;
+  }
+
+  thread = thread_new("hci_thread");
+  if (!thread) {
+    LOG_ERROR(LOG_TAG, "%s unable to create thread.", __func__);
+    goto error;
+  }
+
+  commands_pending_response = list_new(NULL);
+  if (!commands_pending_response) {
+    LOG_ERROR(LOG_TAG,
+              "%s unable to create list for commands pending response.",
+              __func__);
+    goto error;
+  }
+
+  memset(incoming_packets, 0, sizeof(incoming_packets));
+
+  // Make sure we run in a bounded amount of time
+  local_startup_future = future_new();
+  startup_future = local_startup_future;
+  alarm_set(startup_timer, startup_timeout_ms, startup_timer_expired, NULL);
+
+  packet_fragmenter->init(&packet_fragmenter_callbacks);
+
+  fixed_queue_register_dequeue(command_queue, thread_get_reactor(thread),
+                               event_command_ready, NULL);
+  fixed_queue_register_dequeue(packet_queue, thread_get_reactor(thread),
+                               event_packet_ready, NULL);
+
+  vendor->open(btif_local_bd_addr.address, &interface);
+  hal->init(&hal_callbacks, thread);
+  low_power_manager->init(thread);
+
+  vendor->set_callback(VENDOR_CONFIGURE_FIRMWARE, firmware_config_callback);
+  vendor->set_callback(VENDOR_CONFIGURE_SCO, sco_config_callback);
+  vendor->set_callback(VENDOR_DO_EPILOG, epilog_finished_callback);
+
+  if (!hci_inject->open(&interface)) {
+    // TODO(sharvil): gracefully propagate failures from this layer.
+  }
+
+#if (BT_CLEAN_TURN_ON_DISABLED == TRUE)
+  LOG_WARN(LOG_TAG, "%s not turning off the chip before turning on.", __func__);
+// So apparently this hack was needed in the past because a Wingray kernel
+// driver
+// didn't handle power off commands in a powered off state correctly.
+
+// The comment in the old code said the workaround should be removed when the
+// problem was fixed. Sadly, I have no idea if said bug was fixed or if said
+// kernel is still in use, so we must leave this here for posterity. #sadpanda
+#else
+  // cycle power on the chip to ensure it has been reset
+  vendor->send_command(VENDOR_CHIP_POWER_CONTROL, &power_state);
+#endif
+  power_state = BT_VND_PWR_ON;
+  vendor->send_command(VENDOR_CHIP_POWER_CONTROL, &power_state);
+
+  LOG_DEBUG(LOG_TAG, "%s starting async portion", __func__);
+  thread_post(thread, event_finish_startup, NULL);
+  return local_startup_future;
+
+error:
+  shut_down();  // returns NULL so no need to wait for it
+  return future_new_immediate(FUTURE_FAIL);
+}
+
+static future_t* shut_down() {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+
+  hci_inject->close();
+
+  if (thread) {
+    if (firmware_is_configured) {
+      alarm_set(epilog_timer, EPILOG_TIMEOUT_MS, epilog_timer_expired, NULL);
+      thread_post(thread, event_epilog, NULL);
+    } else {
+      thread_stop(thread);
+    }
+
+    thread_join(thread);
+  }
+
+  fixed_queue_free(command_queue, osi_free);
+  command_queue = NULL;
+  fixed_queue_free(packet_queue, buffer_allocator->free);
+  packet_queue = NULL;
+  list_free(commands_pending_response);
+  commands_pending_response = NULL;
+
+  pthread_mutex_destroy(&commands_pending_response_lock);
+
+  packet_fragmenter->cleanup();
+
+  // Free the timers
+  alarm_free(epilog_timer);
+  epilog_timer = NULL;
+  alarm_free(command_response_timer);
+  command_response_timer = NULL;
+  alarm_free(startup_timer);
+  startup_timer = NULL;
+
+  low_power_manager->cleanup();
+  hal->close();
+
+  // Turn off the chip
+  int power_state = BT_VND_PWR_OFF;
+  vendor->send_command(VENDOR_CHIP_POWER_CONTROL, &power_state);
+  vendor->close();
+
+  thread_free(thread);
+  thread = NULL;
+  firmware_is_configured = false;
+
+  return NULL;
+}
+
+EXPORT_SYMBOL extern const module_t hci_module = {
+    .name = HCI_MODULE,
+    .init = NULL,
+    .start_up = start_up,
+    .shut_down = shut_down,
+    .clean_up = NULL,
+    .dependencies = {BTSNOOP_MODULE, NULL}};
+
+// Interface functions
+
+static void do_postload() {
+  LOG_DEBUG(LOG_TAG, "%s posting postload work item", __func__);
+  thread_post(thread, event_postload, NULL);
+}
+
+static void set_data_queue(fixed_queue_t* queue) { upwards_data_queue = queue; }
+
+static void transmit_command(BT_HDR* command,
+                             command_complete_cb complete_callback,
+                             command_status_cb status_callback, void* context) {
+  waiting_command_t* wait_entry =
+      static_cast<waiting_command_t*>(osi_calloc(sizeof(waiting_command_t)));
+
+  uint8_t* stream = command->data + command->offset;
+  STREAM_TO_UINT16(wait_entry->opcode, stream);
+  wait_entry->complete_callback = complete_callback;
+  wait_entry->status_callback = status_callback;
+  wait_entry->command = command;
+  wait_entry->context = context;
+
+  // Store the command message type in the event field
+  // in case the upper layer didn't already
+  command->event = MSG_STACK_TO_HC_HCI_CMD;
+
+  fixed_queue_enqueue(command_queue, wait_entry);
+}
+
+static future_t* transmit_command_futured(BT_HDR* command) {
+  waiting_command_t* wait_entry =
+      static_cast<waiting_command_t*>(osi_calloc(sizeof(waiting_command_t)));
+  future_t* future = future_new();
+
+  uint8_t* stream = command->data + command->offset;
+  STREAM_TO_UINT16(wait_entry->opcode, stream);
+  wait_entry->complete_future = future;
+  wait_entry->command = command;
+
+  // Store the command message type in the event field
+  // in case the upper layer didn't already
+  command->event = MSG_STACK_TO_HC_HCI_CMD;
+
+  fixed_queue_enqueue(command_queue, wait_entry);
+  return future;
+}
+
+static void transmit_downward(data_dispatcher_type_t type, void* data) {
+  if (type == MSG_STACK_TO_HC_HCI_CMD) {
+    // TODO(zachoverflow): eliminate this call
+    transmit_command((BT_HDR*)data, NULL, NULL, NULL);
+    LOG_WARN(LOG_TAG,
+             "%s legacy transmit of command. Use transmit_command instead.",
+             __func__);
+  } else {
+    fixed_queue_enqueue(packet_queue, data);
+  }
+}
+
+// Start up functions
+
+static void event_finish_startup(UNUSED_ATTR void* context) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  hal->open();
+  vendor->send_async_command(VENDOR_CONFIGURE_FIRMWARE, NULL);
+}
+
+static void firmware_config_callback(bool success) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+
+  alarm_cancel(startup_timer);
+
+  pthread_mutex_lock(&commands_pending_response_lock);
+
+  if (startup_future == NULL) {
+    // The firmware configuration took too long - ignore the callback
+    pthread_mutex_unlock(&commands_pending_response_lock);
+    return;
+  }
+  firmware_is_configured = success;
+  future_ready(startup_future, success ? FUTURE_SUCCESS : FUTURE_FAIL);
+  startup_future = NULL;
+
+  pthread_mutex_unlock(&commands_pending_response_lock);
+}
+
+static void startup_timer_expired(UNUSED_ATTR void* context) {
+  LOG_ERROR(LOG_TAG, "%s", __func__);
+
+  pthread_mutex_lock(&commands_pending_response_lock);
+  future_ready(startup_future, FUTURE_FAIL);
+  startup_future = NULL;
+  pthread_mutex_unlock(&commands_pending_response_lock);
+}
+
+// Postload functions
+
+static void event_postload(UNUSED_ATTR void* context) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  if (vendor->send_async_command(VENDOR_CONFIGURE_SCO, NULL) == -1) {
+    // If couldn't configure sco, we won't get the sco configuration callback
+    // so go pretend to do it now
+    sco_config_callback(false);
+  }
+}
+
+static void sco_config_callback(UNUSED_ATTR bool success) {
+  LOG_INFO(LOG_TAG, "%s postload finished.", __func__);
+}
+
+// Epilog functions
+
+static void event_epilog(UNUSED_ATTR void* context) {
+  vendor->send_async_command(VENDOR_DO_EPILOG, NULL);
+}
+
+static void epilog_finished_callback(UNUSED_ATTR bool success) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  alarm_cancel(epilog_timer);
+  thread_stop(thread);
+}
+
+static void epilog_timer_expired(UNUSED_ATTR void* context) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  thread_stop(thread);
+}
+
+// Command/packet transmitting functions
+
+static void event_command_ready(fixed_queue_t* queue,
+                                UNUSED_ATTR void* context) {
+  if (command_credits > 0) {
+    waiting_command_t* wait_entry =
+        static_cast<waiting_command_t*>(fixed_queue_dequeue(queue));
+    command_credits--;
+
+    // Move it to the list of commands awaiting response
+    pthread_mutex_lock(&commands_pending_response_lock);
+    list_append(commands_pending_response, wait_entry);
+    pthread_mutex_unlock(&commands_pending_response_lock);
+
+    // Send it off
+    low_power_manager->wake_assert();
+    packet_fragmenter->fragment_and_dispatch(wait_entry->command);
+    low_power_manager->transmit_done();
+
+    update_command_response_timer();
+  }
+}
+
+static void event_packet_ready(fixed_queue_t* queue,
+                               UNUSED_ATTR void* context) {
+  // The queue may be the command queue or the packet queue, we don't care
+  BT_HDR* packet = (BT_HDR*)fixed_queue_dequeue(queue);
+
+  low_power_manager->wake_assert();
+  packet_fragmenter->fragment_and_dispatch(packet);
+  low_power_manager->transmit_done();
+}
+
+// Callback for the fragmenter to send a fragment
+static void transmit_fragment(BT_HDR* packet, bool send_transmit_finished) {
+  uint16_t event = packet->event & MSG_EVT_MASK;
+  serial_data_type_t type = event_to_data_type(event);
+
+  btsnoop->capture(packet, false);
+  hal->transmit_data(type, packet->data + packet->offset, packet->len);
+
+  if (event != MSG_STACK_TO_HC_HCI_CMD && send_transmit_finished)
+    buffer_allocator->free(packet);
+}
+
+static void fragmenter_transmit_finished(BT_HDR* packet,
+                                         bool all_fragments_sent) {
+  if (all_fragments_sent) {
+    buffer_allocator->free(packet);
+  } else {
+    // This is kind of a weird case, since we're dispatching a partially sent
+    // packet up to a higher layer.
+    // TODO(zachoverflow): rework upper layer so this isn't necessary.
+    data_dispatcher_dispatch(interface.event_dispatcher,
+                             packet->event & MSG_EVT_MASK, packet);
+  }
+}
+
+static void command_timed_out(UNUSED_ATTR void* context) {
+  pthread_mutex_lock(&commands_pending_response_lock);
+
+  if (list_is_empty(commands_pending_response)) {
+    LOG_ERROR(LOG_TAG, "%s with no commands pending response", __func__);
+  } else {
+    waiting_command_t* wait_entry =
+        static_cast<waiting_command_t*>(list_front(commands_pending_response));
+    pthread_mutex_unlock(&commands_pending_response_lock);
+
+    // We shouldn't try to recover the stack from this command timeout.
+    // If it's caused by a software bug, fix it. If it's a hardware bug, fix it.
+    LOG_ERROR(
+        LOG_TAG,
+        "%s hci layer timeout waiting for response to a command. opcode: 0x%x",
+        __func__, wait_entry->opcode);
+    LOG_EVENT_INT(BT_HCI_TIMEOUT_TAG_NUM, wait_entry->opcode);
+  }
+
+  LOG_ERROR(LOG_TAG, "%s restarting the bluetooth process.", __func__);
+  usleep(10000);
+  kill(getpid(), SIGKILL);
+}
+
+// Event/packet receiving functions
+
+// This function is not required to read all of a packet in one go, so
+// be wary of reentry. But this function must return after finishing a packet.
+static void hal_says_data_ready(serial_data_type_t type) {
+  packet_receive_data_t* incoming =
+      &incoming_packets[PACKET_TYPE_TO_INBOUND_INDEX(type)];
+
+  uint8_t byte;
+  while (hal->read_data(type, &byte, 1) != 0) {
+    switch (incoming->state) {
+      case BRAND_NEW:
+        // Initialize and prepare to jump to the preamble reading state
+        incoming->bytes_remaining = preamble_sizes[PACKET_TYPE_TO_INDEX(type)];
+        memset(incoming->preamble, 0, PREAMBLE_BUFFER_SIZE);
+        incoming->index = 0;
+        incoming->state = PREAMBLE;
+      // INTENTIONAL FALLTHROUGH
+      case PREAMBLE:
+        incoming->preamble[incoming->index] = byte;
+        incoming->index++;
+        incoming->bytes_remaining--;
+
+        if (incoming->bytes_remaining == 0) {
+          // For event and sco preambles, the last byte we read is the length
+          incoming->bytes_remaining =
+              (type == DATA_TYPE_ACL) ? RETRIEVE_ACL_LENGTH(incoming->preamble)
+                                      : byte;
+
+          size_t buffer_size =
+              BT_HDR_SIZE + incoming->index + incoming->bytes_remaining;
+          incoming->buffer = (BT_HDR*)buffer_allocator->alloc(buffer_size);
+
+          if (!incoming->buffer) {
+            LOG_ERROR(LOG_TAG,
+                      "%s error getting buffer for incoming packet of type %d "
+                      "and size %zd",
+                      __func__, type, buffer_size);
+            // Can't read any more of this current packet, so jump out
+            incoming->state =
+                incoming->bytes_remaining == 0 ? BRAND_NEW : IGNORE;
+            break;
+          }
+
+          // Initialize the buffer
+          incoming->buffer->offset = 0;
+          incoming->buffer->layer_specific = 0;
+          incoming->buffer->event =
+              outbound_event_types[PACKET_TYPE_TO_INDEX(type)];
+          memcpy(incoming->buffer->data, incoming->preamble, incoming->index);
+
+          incoming->state = incoming->bytes_remaining > 0 ? BODY : FINISHED;
+        }
+
+        break;
+      case BODY: {
+        incoming->buffer->data[incoming->index] = byte;
+        incoming->index++;
+        incoming->bytes_remaining--;
+
+        size_t bytes_read =
+            hal->read_data(type, (incoming->buffer->data + incoming->index),
+                           incoming->bytes_remaining);
+        incoming->index += bytes_read;
+        incoming->bytes_remaining -= bytes_read;
+
+        incoming->state =
+            incoming->bytes_remaining == 0 ? FINISHED : incoming->state;
+        break;
+      }
+      case IGNORE:
+        incoming->bytes_remaining--;
+        if (incoming->bytes_remaining == 0) {
+          incoming->state = BRAND_NEW;
+          // Don't forget to let the hal know we finished the packet we were
+          // ignoring. Otherwise we'll get out of sync with hals that embed
+          // extra information in the uart stream (like H4). #badnewsbears
+          hal->packet_finished(type);
+          return;
+        }
+
+        break;
+      case FINISHED:
+        LOG_ERROR(LOG_TAG,
+                  "%s the state machine should not have been left in the "
+                  "finished state.",
+                  __func__);
+        break;
+    }
+
+    if (incoming->state == FINISHED) {
+      incoming->buffer->len = incoming->index;
+      btsnoop->capture(incoming->buffer, true);
+
+      if (type != DATA_TYPE_EVENT) {
+        packet_fragmenter->reassemble_and_dispatch(incoming->buffer);
+      } else if (!filter_incoming_event(incoming->buffer)) {
+        // Dispatch the event by event code
+        uint8_t* stream = incoming->buffer->data;
+        uint8_t event_code;
+        STREAM_TO_UINT8(event_code, stream);
+
+        data_dispatcher_dispatch(interface.event_dispatcher, event_code,
+                                 incoming->buffer);
+      }
+
+      // We don't control the buffer anymore
+      incoming->buffer = NULL;
+      incoming->state = BRAND_NEW;
+      hal->packet_finished(type);
+
+      // We return after a packet is finished for two reasons:
+      // 1. The type of the next packet could be different.
+      // 2. We don't want to hog cpu time.
+      return;
+    }
+  }
+}
+
+// Returns true if the event was intercepted and should not proceed to
+// higher layers. Also inspects an incoming event for interesting
+// information, like how many commands are now able to be sent.
+static bool filter_incoming_event(BT_HDR* packet) {
+  waiting_command_t* wait_entry = NULL;
+  uint8_t* stream = packet->data;
+  uint8_t event_code;
+  command_opcode_t opcode;
+
+  STREAM_TO_UINT8(event_code, stream);
+  STREAM_SKIP_UINT8(stream);  // Skip the parameter total length field
+
+  if (event_code == HCI_COMMAND_COMPLETE_EVT) {
+    STREAM_TO_UINT8(command_credits, stream);
+    STREAM_TO_UINT16(opcode, stream);
+
+    wait_entry = get_waiting_command(opcode);
+    if (!wait_entry) {
+      // TODO: Currently command_credits aren't parsed at all; here or in higher
+      // layers...
+      if (opcode != HCI_COMMAND_NONE) {
+        LOG_WARN(LOG_TAG,
+                 "%s command complete event with no matching command (opcode: "
+                 "0x%04x).",
+                 __func__, opcode);
+      }
+    } else if (wait_entry->complete_callback) {
+      wait_entry->complete_callback(packet, wait_entry->context);
+    } else if (wait_entry->complete_future) {
+      future_ready(wait_entry->complete_future, packet);
+    }
+
+    goto intercepted;
+  } else if (event_code == HCI_COMMAND_STATUS_EVT) {
+    uint8_t status;
+    STREAM_TO_UINT8(status, stream);
+    STREAM_TO_UINT8(command_credits, stream);
+    STREAM_TO_UINT16(opcode, stream);
+
+    // If a command generates a command status event, it won't be getting a
+    // command complete event
+
+    wait_entry = get_waiting_command(opcode);
+    if (!wait_entry)
+      LOG_WARN(LOG_TAG,
+               "%s command status event with no matching command. opcode: 0x%x",
+               __func__, opcode);
+    else if (wait_entry->status_callback)
+      wait_entry->status_callback(status, wait_entry->command,
+                                  wait_entry->context);
+
+    goto intercepted;
+  }
+
+  return false;
+
+intercepted:
+  update_command_response_timer();
+
+  if (wait_entry) {
+    // If it has a callback, it's responsible for freeing the packet
+    if (event_code == HCI_COMMAND_STATUS_EVT ||
+        (!wait_entry->complete_callback && !wait_entry->complete_future))
+      buffer_allocator->free(packet);
+
+    // If it has a callback, it's responsible for freeing the command
+    if (event_code == HCI_COMMAND_COMPLETE_EVT || !wait_entry->status_callback)
+      buffer_allocator->free(wait_entry->command);
+
+    osi_free(wait_entry);
+  } else {
+    buffer_allocator->free(packet);
+  }
+
+  return true;
+}
+
+// Callback for the fragmenter to dispatch up a completely reassembled packet
+static void dispatch_reassembled(BT_HDR* packet) {
+  // Events should already have been dispatched before this point
+  assert((packet->event & MSG_EVT_MASK) != MSG_HC_TO_STACK_HCI_EVT);
+  assert(upwards_data_queue != NULL);
+
+  if (upwards_data_queue) {
+    fixed_queue_enqueue(upwards_data_queue, packet);
+  } else {
+    LOG_ERROR(LOG_TAG,
+              "%s had no queue to place upwards data packet in. Dropping it on "
+              "the floor.",
+              __func__);
+    buffer_allocator->free(packet);
+  }
+}
+
+// Misc internal functions
+
+// TODO(zachoverflow): we seem to do this a couple places, like the HCI inject
+// module. #centralize
+static serial_data_type_t event_to_data_type(uint16_t event) {
+  if (event == MSG_STACK_TO_HC_HCI_ACL)
+    return DATA_TYPE_ACL;
+  else if (event == MSG_STACK_TO_HC_HCI_SCO)
+    return DATA_TYPE_SCO;
+  else if (event == MSG_STACK_TO_HC_HCI_CMD)
+    return DATA_TYPE_COMMAND;
+  else
+    LOG_ERROR(LOG_TAG, "%s invalid event type, could not translate 0x%x",
+              __func__, event);
+
+  return DATA_TYPE_UNKNOWN;
+}
+
+static waiting_command_t* get_waiting_command(command_opcode_t opcode) {
+  pthread_mutex_lock(&commands_pending_response_lock);
+
+  for (const list_node_t* node = list_begin(commands_pending_response);
+       node != list_end(commands_pending_response); node = list_next(node)) {
+    waiting_command_t* wait_entry =
+        static_cast<waiting_command_t*>(list_node(node));
+
+    if (!wait_entry || wait_entry->opcode != opcode) continue;
+
+    list_remove(commands_pending_response, wait_entry);
+
+    pthread_mutex_unlock(&commands_pending_response_lock);
+    return wait_entry;
+  }
+
+  pthread_mutex_unlock(&commands_pending_response_lock);
+  return NULL;
+}
+
+static void update_command_response_timer(void) {
+  if (list_is_empty(commands_pending_response)) {
+    alarm_cancel(command_response_timer);
+  } else {
+    alarm_set(command_response_timer, COMMAND_PENDING_TIMEOUT_MS,
+              command_timed_out, NULL);
+  }
+}
+
+static void init_layer_interface() {
+  if (!interface_created) {
+    interface.send_low_power_command = low_power_manager->post_command;
+    interface.do_postload = do_postload;
+
+    // It's probably ok for this to live forever. It's small and
+    // there's only one instance of the hci interface.
+    interface.event_dispatcher = data_dispatcher_new("hci_layer");
+    if (!interface.event_dispatcher) {
+      LOG_ERROR(LOG_TAG, "%s could not create upward dispatcher.", __func__);
+      return;
+    }
+
+    interface.set_data_queue = set_data_queue;
+    interface.transmit_command = transmit_command;
+    interface.transmit_command_futured = transmit_command_futured;
+    interface.transmit_downward = transmit_downward;
+    interface_created = true;
+  }
+}
+
+void hci_layer_cleanup_interface() {
+  if (interface_created) {
+    interface.send_low_power_command = NULL;
+    interface.do_postload = NULL;
+
+    data_dispatcher_free(interface.event_dispatcher);
+    interface.event_dispatcher = NULL;
+
+    interface.set_data_queue = NULL;
+    interface.transmit_command = NULL;
+    interface.transmit_command_futured = NULL;
+    interface.transmit_downward = NULL;
+    interface_created = false;
+  }
+}
+
+const hci_t* hci_layer_get_interface() {
+  buffer_allocator = buffer_allocator_get_interface();
+  hal = hci_hal_get_interface();
+  btsnoop = btsnoop_get_interface();
+  hci_inject = hci_inject_get_interface();
+  packet_fragmenter = packet_fragmenter_get_interface();
+  vendor = vendor_get_interface();
+  low_power_manager = low_power_manager_get_interface();
+
+  init_layer_interface();
+  return &interface;
+}
+
+const hci_t* hci_layer_get_test_interface(
+    const allocator_t* buffer_allocator_interface,
+    const hci_hal_t* hal_interface, const btsnoop_t* btsnoop_interface,
+    const hci_inject_t* hci_inject_interface,
+    const packet_fragmenter_t* packet_fragmenter_interface,
+    const vendor_t* vendor_interface,
+    const low_power_manager_t* low_power_manager_interface) {
+  buffer_allocator = buffer_allocator_interface;
+  hal = hal_interface;
+  btsnoop = btsnoop_interface;
+  hci_inject = hci_inject_interface;
+  packet_fragmenter = packet_fragmenter_interface;
+  vendor = vendor_interface;
+  low_power_manager = low_power_manager_interface;
+
+  init_layer_interface();
+  return &interface;
+}
diff --git a/bt/hci/src/hci_packet_factory.cc b/bt/hci/src/hci_packet_factory.cc
new file mode 100644
index 0000000..261d7cf
--- /dev/null
+++ b/bt/hci/src/hci_packet_factory.cc
@@ -0,0 +1,212 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <assert.h>
+
+#include "bt_types.h"
+#include "buffer_allocator.h"
+#include "hci_internals.h"
+#include "hci_layer.h"
+#include "hci_packet_factory.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "osi/include/allocator.h"
+
+static const allocator_t* buffer_allocator;
+
+static BT_HDR* make_packet(size_t data_size);
+static BT_HDR* make_command_no_params(uint16_t opcode);
+static BT_HDR* make_command(uint16_t opcode, size_t parameter_size,
+                            uint8_t** stream_out);
+
+// Interface functions
+
+static BT_HDR* make_reset(void) { return make_command_no_params(HCI_RESET); }
+
+static BT_HDR* make_read_buffer_size(void) {
+  return make_command_no_params(HCI_READ_BUFFER_SIZE);
+}
+
+static BT_HDR* make_host_buffer_size(uint16_t acl_size, uint8_t sco_size,
+                                     uint16_t acl_count, uint16_t sco_count) {
+  uint8_t* stream;
+  const uint8_t parameter_size = 2 + 1 + 2 + 2;  // from each of the parameters
+  BT_HDR* packet = make_command(HCI_HOST_BUFFER_SIZE, parameter_size, &stream);
+
+  UINT16_TO_STREAM(stream, acl_size);
+  UINT8_TO_STREAM(stream, sco_size);
+  UINT16_TO_STREAM(stream, acl_count);
+  UINT16_TO_STREAM(stream, sco_count);
+  return packet;
+}
+
+static BT_HDR* make_read_local_version_info(void) {
+  return make_command_no_params(HCI_READ_LOCAL_VERSION_INFO);
+}
+
+static BT_HDR* make_read_bd_addr(void) {
+  return make_command_no_params(HCI_READ_BD_ADDR);
+}
+
+static BT_HDR* make_read_local_supported_commands(void) {
+  return make_command_no_params(HCI_READ_LOCAL_SUPPORTED_CMDS);
+}
+
+static BT_HDR* make_read_local_extended_features(uint8_t page_number) {
+  uint8_t* stream;
+  const uint8_t parameter_size = 1;
+  BT_HDR* packet =
+      make_command(HCI_READ_LOCAL_EXT_FEATURES, parameter_size, &stream);
+
+  UINT8_TO_STREAM(stream, page_number);
+  return packet;
+}
+
+static BT_HDR* make_write_simple_pairing_mode(uint8_t mode) {
+  uint8_t* stream;
+  const uint8_t parameter_size = 1;
+  BT_HDR* packet =
+      make_command(HCI_WRITE_SIMPLE_PAIRING_MODE, parameter_size, &stream);
+
+  UINT8_TO_STREAM(stream, mode);
+  return packet;
+}
+
+static BT_HDR* make_write_secure_connections_host_support(uint8_t mode) {
+  uint8_t* stream;
+  const uint8_t parameter_size = 1;
+  BT_HDR* packet =
+      make_command(HCI_WRITE_SECURE_CONNS_SUPPORT, parameter_size, &stream);
+
+  UINT8_TO_STREAM(stream, mode);
+  return packet;
+}
+
+static BT_HDR* make_set_event_mask(const bt_event_mask_t* event_mask) {
+  uint8_t* stream;
+  uint8_t parameter_size = sizeof(bt_event_mask_t);
+  BT_HDR* packet = make_command(HCI_SET_EVENT_MASK, parameter_size, &stream);
+
+  ARRAY8_TO_STREAM(stream, event_mask->as_array);
+  return packet;
+}
+
+static BT_HDR* make_ble_write_host_support(uint8_t supported_host,
+                                           uint8_t simultaneous_host) {
+  uint8_t* stream;
+  const uint8_t parameter_size = 1 + 1;
+  BT_HDR* packet =
+      make_command(HCI_WRITE_LE_HOST_SUPPORT, parameter_size, &stream);
+
+  UINT8_TO_STREAM(stream, supported_host);
+  UINT8_TO_STREAM(stream, simultaneous_host);
+  return packet;
+}
+
+static BT_HDR* make_ble_read_white_list_size(void) {
+  return make_command_no_params(HCI_BLE_READ_WHITE_LIST_SIZE);
+}
+
+static BT_HDR* make_ble_read_buffer_size(void) {
+  return make_command_no_params(HCI_BLE_READ_BUFFER_SIZE);
+}
+
+static BT_HDR* make_ble_read_supported_states(void) {
+  return make_command_no_params(HCI_BLE_READ_SUPPORTED_STATES);
+}
+
+static BT_HDR* make_ble_read_local_supported_features(void) {
+  return make_command_no_params(HCI_BLE_READ_LOCAL_SPT_FEAT);
+}
+
+static BT_HDR* make_ble_read_resolving_list_size(void) {
+  return make_command_no_params(HCI_BLE_READ_RESOLVING_LIST_SIZE);
+}
+
+static BT_HDR* make_ble_read_suggested_default_data_length(void) {
+  return make_command_no_params(HCI_BLE_READ_DEFAULT_DATA_LENGTH);
+}
+
+static BT_HDR* make_read_local_supported_codecs(void) {
+  return make_command_no_params(HCI_READ_LOCAL_SUPPORTED_CODECS);
+}
+
+static BT_HDR* make_ble_set_event_mask(const bt_event_mask_t* event_mask) {
+  uint8_t* stream;
+  uint8_t parameter_size = sizeof(bt_event_mask_t);
+  BT_HDR* packet =
+      make_command(HCI_BLE_SET_EVENT_MASK, parameter_size, &stream);
+
+  ARRAY8_TO_STREAM(stream, event_mask->as_array);
+  return packet;
+}
+
+// Internal functions
+
+static BT_HDR* make_command_no_params(uint16_t opcode) {
+  return make_command(opcode, 0, NULL);
+}
+
+static BT_HDR* make_command(uint16_t opcode, size_t parameter_size,
+                            uint8_t** stream_out) {
+  BT_HDR* packet = make_packet(HCI_COMMAND_PREAMBLE_SIZE + parameter_size);
+
+  uint8_t* stream = packet->data;
+  UINT16_TO_STREAM(stream, opcode);
+  UINT8_TO_STREAM(stream, parameter_size);
+
+  if (stream_out != NULL) *stream_out = stream;
+
+  return packet;
+}
+
+static BT_HDR* make_packet(size_t data_size) {
+  BT_HDR* ret = (BT_HDR*)buffer_allocator->alloc(sizeof(BT_HDR) + data_size);
+  assert(ret);
+  ret->event = 0;
+  ret->offset = 0;
+  ret->layer_specific = 0;
+  ret->len = data_size;
+  return ret;
+}
+
+static const hci_packet_factory_t interface = {
+    make_reset,
+    make_read_buffer_size,
+    make_host_buffer_size,
+    make_read_local_version_info,
+    make_read_bd_addr,
+    make_read_local_supported_commands,
+    make_read_local_extended_features,
+    make_write_simple_pairing_mode,
+    make_write_secure_connections_host_support,
+    make_set_event_mask,
+    make_ble_write_host_support,
+    make_ble_read_white_list_size,
+    make_ble_read_buffer_size,
+    make_ble_read_supported_states,
+    make_ble_read_local_supported_features,
+    make_ble_read_resolving_list_size,
+    make_ble_read_suggested_default_data_length,
+    make_ble_set_event_mask,
+    make_read_local_supported_codecs};
+
+const hci_packet_factory_t* hci_packet_factory_get_interface() {
+  buffer_allocator = buffer_allocator_get_interface();
+  return &interface;
+}
diff --git a/bt/hci/src/hci_packet_parser.cc b/bt/hci/src/hci_packet_parser.cc
new file mode 100644
index 0000000..7242f05
--- /dev/null
+++ b/bt/hci/src/hci_packet_parser.cc
@@ -0,0 +1,263 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_hci"
+
+#include "hci_packet_parser.h"
+
+#include <assert.h>
+
+#include "buffer_allocator.h"
+#include "hci_layer.h"
+#include "hcimsgs.h"
+#include "osi/include/log.h"
+
+static const command_opcode_t NO_OPCODE_CHECKING = 0;
+
+static const allocator_t* buffer_allocator;
+
+static uint8_t* read_command_complete_header(BT_HDR* response,
+                                             command_opcode_t expected_opcode,
+                                             size_t minimum_bytes_after);
+
+static void parse_generic_command_complete(BT_HDR* response) {
+  read_command_complete_header(response, NO_OPCODE_CHECKING,
+                               0 /* bytes after */);
+
+  buffer_allocator->free(response);
+}
+
+static void parse_read_buffer_size_response(BT_HDR* response,
+                                            uint16_t* data_size_ptr,
+                                            uint16_t* acl_buffer_count_ptr) {
+  uint8_t* stream = read_command_complete_header(response, HCI_READ_BUFFER_SIZE,
+                                                 5 /* bytes after */);
+  assert(stream != NULL);
+  STREAM_TO_UINT16(*data_size_ptr, stream);
+  STREAM_SKIP_UINT8(stream);  // skip the sco packet length
+  STREAM_TO_UINT16(*acl_buffer_count_ptr, stream);
+
+  buffer_allocator->free(response);
+}
+
+static void parse_read_local_version_info_response(BT_HDR* response,
+                                                   bt_version_t* bt_version) {
+  uint8_t* stream = read_command_complete_header(
+      response, HCI_READ_LOCAL_VERSION_INFO, 8 /* bytes after */);
+  assert(stream != NULL);
+  STREAM_TO_UINT8(bt_version->hci_version, stream);
+  STREAM_TO_UINT16(bt_version->hci_revision, stream);
+  STREAM_TO_UINT8(bt_version->lmp_version, stream);
+  STREAM_TO_UINT16(bt_version->manufacturer, stream);
+  STREAM_TO_UINT16(bt_version->lmp_subversion, stream);
+
+  buffer_allocator->free(response);
+}
+
+static void parse_read_local_supported_codecs_response(
+    BT_HDR* response, uint8_t* number_of_local_supported_codecs,
+    uint8_t* local_supported_codecs) {
+  uint8_t* stream = read_command_complete_header(
+      response, HCI_READ_LOCAL_SUPPORTED_CODECS, 0 /* bytes after */);
+  if (stream) {
+    STREAM_TO_UINT8(*number_of_local_supported_codecs, stream);
+    for (uint8_t i = 0; i < *number_of_local_supported_codecs; i++) {
+      STREAM_TO_UINT8(*local_supported_codecs, stream);
+      local_supported_codecs++;
+    }
+  }
+
+  buffer_allocator->free(response);
+}
+
+static void parse_read_bd_addr_response(BT_HDR* response,
+                                        bt_bdaddr_t* address_ptr) {
+  uint8_t* stream = read_command_complete_header(
+      response, HCI_READ_BD_ADDR, sizeof(bt_bdaddr_t) /* bytes after */);
+  assert(stream != NULL);
+  STREAM_TO_BDADDR(address_ptr->address, stream);
+
+  buffer_allocator->free(response);
+}
+
+static void parse_read_local_supported_commands_response(
+    BT_HDR* response, uint8_t* supported_commands_ptr,
+    size_t supported_commands_length) {
+  uint8_t* stream =
+      read_command_complete_header(response, HCI_READ_LOCAL_SUPPORTED_CMDS,
+                                   supported_commands_length /* bytes after */);
+  assert(stream != NULL);
+  STREAM_TO_ARRAY(supported_commands_ptr, stream,
+                  (int)supported_commands_length);
+
+  buffer_allocator->free(response);
+}
+
+static void parse_read_local_extended_features_response(
+    BT_HDR* response, uint8_t* page_number_ptr, uint8_t* max_page_number_ptr,
+    bt_device_features_t* feature_pages, size_t feature_pages_count) {
+  uint8_t* stream = read_command_complete_header(
+      response, HCI_READ_LOCAL_EXT_FEATURES,
+      2 + sizeof(bt_device_features_t) /* bytes after */);
+  if (stream != NULL) {
+    STREAM_TO_UINT8(*page_number_ptr, stream);
+    STREAM_TO_UINT8(*max_page_number_ptr, stream);
+
+    assert(*page_number_ptr < feature_pages_count);
+    STREAM_TO_ARRAY(feature_pages[*page_number_ptr].as_array, stream,
+                    (int)sizeof(bt_device_features_t));
+  } else {
+    LOG_ERROR(LOG_TAG,
+              "%s() - WARNING: READING EXTENDED FEATURES FAILED. "
+              "THIS MAY INDICATE A FIRMWARE/CONTROLLER ISSUE.",
+              __func__);
+  }
+
+  buffer_allocator->free(response);
+}
+
+static void parse_ble_read_white_list_size_response(
+    BT_HDR* response, uint8_t* white_list_size_ptr) {
+  uint8_t* stream = read_command_complete_header(
+      response, HCI_BLE_READ_WHITE_LIST_SIZE, 1 /* byte after */);
+  assert(stream != NULL);
+  STREAM_TO_UINT8(*white_list_size_ptr, stream);
+
+  buffer_allocator->free(response);
+}
+
+static void parse_ble_read_buffer_size_response(BT_HDR* response,
+                                                uint16_t* data_size_ptr,
+                                                uint8_t* acl_buffer_count_ptr) {
+  uint8_t* stream = read_command_complete_header(
+      response, HCI_BLE_READ_BUFFER_SIZE, 3 /* bytes after */);
+  assert(stream != NULL);
+  STREAM_TO_UINT16(*data_size_ptr, stream);
+  STREAM_TO_UINT8(*acl_buffer_count_ptr, stream);
+
+  buffer_allocator->free(response);
+}
+
+static void parse_ble_read_supported_states_response(
+    BT_HDR* response, uint8_t* supported_states, size_t supported_states_size) {
+  uint8_t* stream =
+      read_command_complete_header(response, HCI_BLE_READ_SUPPORTED_STATES,
+                                   supported_states_size /* bytes after */);
+  assert(stream != NULL);
+  STREAM_TO_ARRAY(supported_states, stream, (int)supported_states_size);
+
+  buffer_allocator->free(response);
+}
+
+static void parse_ble_read_local_supported_features_response(
+    BT_HDR* response, bt_device_features_t* supported_features) {
+  uint8_t* stream = read_command_complete_header(
+      response, HCI_BLE_READ_LOCAL_SPT_FEAT,
+      sizeof(bt_device_features_t) /* bytes after */);
+  assert(stream != NULL);
+  STREAM_TO_ARRAY(supported_features->as_array, stream,
+                  (int)sizeof(bt_device_features_t));
+
+  buffer_allocator->free(response);
+}
+
+static void parse_ble_read_resolving_list_size_response(
+    BT_HDR* response, uint8_t* resolving_list_size_ptr) {
+  uint8_t* stream = read_command_complete_header(
+      response, HCI_BLE_READ_RESOLVING_LIST_SIZE, 1 /* bytes after */);
+  STREAM_TO_UINT8(*resolving_list_size_ptr, stream);
+
+  buffer_allocator->free(response);
+}
+
+static void parse_ble_read_suggested_default_data_length_response(
+    BT_HDR* response, uint16_t* ble_default_packet_length_ptr) {
+  uint8_t* stream = read_command_complete_header(
+      response, HCI_BLE_READ_DEFAULT_DATA_LENGTH, 2 /* bytes after */);
+  STREAM_TO_UINT8(*ble_default_packet_length_ptr, stream);
+
+  buffer_allocator->free(response);
+}
+
+// Internal functions
+
+static uint8_t* read_command_complete_header(BT_HDR* response,
+                                             command_opcode_t expected_opcode,
+                                             size_t minimum_bytes_after) {
+  uint8_t* stream = response->data + response->offset;
+
+  // Read the event header
+  uint8_t event_code;
+  uint8_t parameter_length;
+  STREAM_TO_UINT8(event_code, stream);
+  STREAM_TO_UINT8(parameter_length, stream);
+
+  const size_t parameter_bytes_we_read_here = 4;
+
+  // Check the event header values against what we expect
+  assert(event_code == HCI_COMMAND_COMPLETE_EVT);
+  assert(parameter_length >=
+         (parameter_bytes_we_read_here + minimum_bytes_after));
+
+  // Read the command complete header
+  command_opcode_t opcode;
+  uint8_t status;
+  STREAM_SKIP_UINT8(stream);  // skip the number of hci command packets field
+  STREAM_TO_UINT16(opcode, stream);
+
+  // Check the command complete header values against what we expect
+  if (expected_opcode != NO_OPCODE_CHECKING) {
+    assert(opcode == expected_opcode);
+  }
+
+  // Assume the next field is the status field
+  STREAM_TO_UINT8(status, stream);
+
+  if (status != HCI_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: return status - 0x%x", __func__, status);
+    return NULL;
+  }
+
+  return stream;
+}
+
+static const hci_packet_parser_t interface = {
+    parse_generic_command_complete,
+    parse_read_buffer_size_response,
+    parse_read_local_version_info_response,
+    parse_read_bd_addr_response,
+    parse_read_local_supported_commands_response,
+    parse_read_local_extended_features_response,
+    parse_ble_read_white_list_size_response,
+    parse_ble_read_buffer_size_response,
+    parse_ble_read_supported_states_response,
+    parse_ble_read_local_supported_features_response,
+    parse_ble_read_resolving_list_size_response,
+    parse_ble_read_suggested_default_data_length_response,
+    parse_read_local_supported_codecs_response};
+
+const hci_packet_parser_t* hci_packet_parser_get_interface() {
+  buffer_allocator = buffer_allocator_get_interface();
+  return &interface;
+}
+
+const hci_packet_parser_t* hci_packet_parser_get_test_interface(
+    allocator_t* buffer_allocator_interface) {
+  buffer_allocator = buffer_allocator_interface;
+  return &interface;
+}
diff --git a/bt/hci/src/low_power_manager.cc b/bt/hci/src/low_power_manager.cc
new file mode 100644
index 0000000..c328ca8
--- /dev/null
+++ b/bt/hci/src/low_power_manager.cc
@@ -0,0 +1,244 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_low_power_manager"
+
+#include "low_power_manager.h"
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "osi/include/alarm.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/thread.h"
+#include "vendor.h"
+
+typedef enum {
+  LPM_DISABLED = 0,
+  LPM_ENABLED,
+  LPM_ENABLING,
+  LPM_DISABLING
+} low_power_mode_state_t;
+
+typedef enum {
+  LPM_WAKE_DEASSERTED = 0,
+  LPM_WAKE_W4_TX_DONE,
+  LPM_WAKE_W4_TIMEOUT,
+  LPM_WAKE_ASSERTED,
+} wake_state_t;
+
+static void init(thread_t* post_thread);
+static void cleanup(void);
+static void post_command(low_power_command_t command);
+static void wake_assert(void);
+static void transmit_done(void);
+static void vendor_enable_disable_callback(bool success);
+
+static void event_disable(void* context);
+static void event_enable(void* context);
+static void event_wake_assert(void* context);
+static void event_allow_device_sleep(void* context);
+static void event_idle_timeout(void* context);
+
+static void reset_state();
+static void start_idle_timer();
+static void stop_idle_timer();
+
+// Our interface and modules we import
+static const low_power_manager_t interface = {init, cleanup, post_command,
+                                              wake_assert, transmit_done};
+static const vendor_t* vendor;
+
+static thread_fn event_functions[] = {
+    event_disable, event_enable, event_wake_assert, event_allow_device_sleep};
+
+static thread_t* thread;
+static low_power_mode_state_t state;
+static wake_state_t wake_state;
+static uint32_t idle_timeout_ms;
+static alarm_t* idle_alarm;
+static bool transmit_is_done;
+static void wake_deassert();
+
+// Interface functions
+
+static void init(thread_t* post_thread) {
+  assert(post_thread != NULL);
+  thread = post_thread;
+
+  vendor->set_callback(VENDOR_SET_LPM_MODE, vendor_enable_disable_callback);
+
+  idle_alarm = alarm_new("hci.idle");
+  if (!idle_alarm) {
+    LOG_ERROR(LOG_TAG, "%s could not create idle alarm.", __func__);
+  }
+
+  reset_state();
+}
+
+static void cleanup(void) {
+  reset_state();
+  alarm_free(idle_alarm);
+  idle_alarm = NULL;
+}
+
+static void post_command(low_power_command_t command) {
+  if (command > LPM_WAKE_DEASSERT) {
+    LOG_ERROR(LOG_TAG, "%s unknown low power command %d", __func__, command);
+    return;
+  }
+
+  thread_post(thread, event_functions[command], NULL);
+}
+
+static void wake_assert(void) {
+  if (state != LPM_DISABLED) {
+    stop_idle_timer();
+
+    uint8_t new_state = BT_VND_LPM_WAKE_ASSERT;
+    vendor->send_command(VENDOR_SET_LPM_WAKE_STATE, &new_state);
+    wake_state = LPM_WAKE_ASSERTED;
+  }
+
+  // TODO(zachoverflow): investigate this interaction. If someone above
+  // HCI asserts wake, we'll wait until we transmit before deasserting.
+  // That doesn't seem quite right.
+  transmit_is_done = false;
+}
+
+static void transmit_done(void) {
+  transmit_is_done = true;
+  if (wake_state == LPM_WAKE_W4_TX_DONE || wake_state == LPM_WAKE_ASSERTED) {
+    wake_state = LPM_WAKE_W4_TIMEOUT;
+    start_idle_timer();
+  }
+}
+
+// Internal functions
+
+static void enable(bool enable) {
+  if (state == LPM_DISABLING) {
+    if (enable)
+      LOG_ERROR(LOG_TAG,
+                "%s still processing prior disable request, cannot enable.",
+                __func__);
+    else
+      LOG_WARN(LOG_TAG,
+               "%s still processing prior disable request, ignoring new "
+               "request to disable.",
+               __func__);
+  } else if (state == LPM_ENABLING) {
+    if (enable)
+      LOG_ERROR(LOG_TAG,
+                "%s still processing prior enable request, ignoring new "
+                "request to enable.",
+                __func__);
+    else
+      LOG_WARN(LOG_TAG,
+               "%s still processing prior enable request, cannot disable.",
+               __func__);
+  } else if (state == LPM_ENABLED && enable) {
+    LOG_INFO(LOG_TAG, "%s already enabled.", __func__);
+  } else if (state == LPM_DISABLED && !enable) {
+    LOG_INFO(LOG_TAG, "%s already disabled.", __func__);
+  } else {
+    uint8_t command = enable ? BT_VND_LPM_ENABLE : BT_VND_LPM_DISABLE;
+    state = enable ? LPM_ENABLING : LPM_DISABLING;
+    if (state == LPM_ENABLING)
+      vendor->send_command(VENDOR_GET_LPM_IDLE_TIMEOUT, &idle_timeout_ms);
+    vendor->send_async_command(VENDOR_SET_LPM_MODE, &command);
+  }
+}
+
+static void allow_device_sleep() {
+  if (state == LPM_ENABLED && wake_state == LPM_WAKE_ASSERTED) {
+    if (transmit_is_done) {
+      wake_state = LPM_WAKE_W4_TIMEOUT;
+      start_idle_timer();
+    } else {
+      wake_state = LPM_WAKE_W4_TX_DONE;
+    }
+  }
+}
+
+static void wake_deassert() {
+  if (state == LPM_ENABLED && transmit_is_done) {
+    uint8_t new_state = BT_VND_LPM_WAKE_DEASSERT;
+    vendor->send_command(VENDOR_SET_LPM_WAKE_STATE, &new_state);
+    wake_state = LPM_WAKE_DEASSERTED;
+  }
+}
+
+static void reset_state() {
+  state = LPM_DISABLED;
+  wake_state = LPM_WAKE_DEASSERTED;
+  transmit_is_done = true;
+  stop_idle_timer();
+}
+
+static void idle_timer_expired(UNUSED_ATTR void* context) {
+  if (state == LPM_ENABLED && wake_state == LPM_WAKE_W4_TIMEOUT)
+    thread_post(thread, event_idle_timeout, NULL);
+}
+
+static void start_idle_timer() {
+  if (state == LPM_ENABLED) {
+    if (idle_timeout_ms == 0) {
+      wake_deassert();
+    } else {
+      alarm_set(idle_alarm, idle_timeout_ms, idle_timer_expired, NULL);
+    }
+  }
+}
+
+static void stop_idle_timer() { alarm_cancel(idle_alarm); }
+
+static void event_disable(UNUSED_ATTR void* context) { enable(false); }
+
+static void event_enable(UNUSED_ATTR void* context) { enable(true); }
+
+static void event_wake_assert(UNUSED_ATTR void* context) { wake_assert(); }
+
+static void event_allow_device_sleep(UNUSED_ATTR void* context) {
+  allow_device_sleep();
+}
+
+static void event_idle_timeout(UNUSED_ATTR void* context) { wake_deassert(); }
+
+static void vendor_enable_disable_callback(bool success) {
+  if (success)
+    state = (state == LPM_ENABLING) ? LPM_ENABLED : LPM_DISABLED;
+  else
+    state = (state == LPM_ENABLING) ? LPM_DISABLED : LPM_ENABLED;
+
+  if (state == LPM_DISABLED) {
+    reset_state();
+  }
+}
+
+const low_power_manager_t* low_power_manager_get_interface() {
+  vendor = vendor_get_interface();
+  return &interface;
+}
+
+const low_power_manager_t* low_power_manager_get_test_interface(
+    const vendor_t* vendor_interface) {
+  vendor = vendor_interface;
+  return &interface;
+}
diff --git a/bt/hci/src/packet_fragmenter.cc b/bt/hci/src/packet_fragmenter.cc
new file mode 100644
index 0000000..f148363
--- /dev/null
+++ b/bt/hci/src/packet_fragmenter.cc
@@ -0,0 +1,258 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_hci_packet_fragmenter"
+
+#include "packet_fragmenter.h"
+
+#include <assert.h>
+#include <string.h>
+#include <unordered_map>
+
+#include "bt_target.h"
+#include "buffer_allocator.h"
+#include "device/include/controller.h"
+#include "hci_internals.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#define APPLY_CONTINUATION_FLAG(handle) (((handle)&0xCFFF) | 0x1000)
+#define APPLY_START_FLAG(handle) (((handle)&0xCFFF) | 0x2000)
+#define SUB_EVENT(event) ((event)&MSG_SUB_EVT_MASK)
+#define GET_BOUNDARY_FLAG(handle) (((handle) >> 12) & 0x0003)
+
+#define HANDLE_MASK 0x0FFF
+#define START_PACKET_BOUNDARY 2
+#define CONTINUATION_PACKET_BOUNDARY 1
+#define L2CAP_HEADER_SIZE 4
+
+// Our interface and callbacks
+
+static const allocator_t* buffer_allocator;
+static const controller_t* controller;
+static const packet_fragmenter_callbacks_t* callbacks;
+
+static std::unordered_map<uint16_t /* handle */, BT_HDR*> partial_packets;
+
+static void init(const packet_fragmenter_callbacks_t* result_callbacks) {
+  callbacks = result_callbacks;
+}
+
+static void cleanup() { partial_packets.clear(); }
+
+static void fragment_and_dispatch(BT_HDR* packet) {
+  assert(packet != NULL);
+
+  uint16_t event = packet->event & MSG_EVT_MASK;
+  uint8_t* stream = packet->data + packet->offset;
+
+  // We only fragment ACL packets
+  if (event != MSG_STACK_TO_HC_HCI_ACL) {
+    callbacks->fragmented(packet, true);
+    return;
+  }
+
+  uint16_t max_data_size =
+      SUB_EVENT(packet->event) == LOCAL_BR_EDR_CONTROLLER_ID
+          ? controller->get_acl_data_size_classic()
+          : controller->get_acl_data_size_ble();
+
+  uint16_t max_packet_size = max_data_size + HCI_ACL_PREAMBLE_SIZE;
+  uint16_t remaining_length = packet->len;
+
+  uint16_t continuation_handle;
+  STREAM_TO_UINT16(continuation_handle, stream);
+  continuation_handle = APPLY_CONTINUATION_FLAG(continuation_handle);
+
+  while (remaining_length > max_packet_size) {
+    // Make sure we use the right ACL packet size
+    stream = packet->data + packet->offset;
+    STREAM_SKIP_UINT16(stream);
+    UINT16_TO_STREAM(stream, max_data_size);
+
+    packet->len = max_packet_size;
+    callbacks->fragmented(packet, false);
+
+    packet->offset += max_data_size;
+    remaining_length -= max_data_size;
+    packet->len = remaining_length;
+
+    // Write the ACL header for the next fragment
+    stream = packet->data + packet->offset;
+    UINT16_TO_STREAM(stream, continuation_handle);
+    UINT16_TO_STREAM(stream, remaining_length - HCI_ACL_PREAMBLE_SIZE);
+
+    // Apparently L2CAP can set layer_specific to a max number of segments to
+    // transmit
+    if (packet->layer_specific) {
+      packet->layer_specific--;
+
+      if (packet->layer_specific == 0) {
+        packet->event = MSG_HC_TO_STACK_L2C_SEG_XMIT;
+        callbacks->transmit_finished(packet, false);
+        return;
+      }
+    }
+  }
+
+  callbacks->fragmented(packet, true);
+}
+
+static bool check_uint16_overflow(uint16_t a, uint16_t b) {
+  return (UINT16_MAX - a) < b;
+}
+
+static void reassemble_and_dispatch(UNUSED_ATTR BT_HDR* packet) {
+  if ((packet->event & MSG_EVT_MASK) == MSG_HC_TO_STACK_HCI_ACL) {
+    uint8_t* stream = packet->data;
+    uint16_t handle;
+    uint16_t l2cap_length;
+    uint16_t acl_length;
+
+    STREAM_TO_UINT16(handle, stream);
+    STREAM_TO_UINT16(acl_length, stream);
+    STREAM_TO_UINT16(l2cap_length, stream);
+
+    assert(acl_length == packet->len - HCI_ACL_PREAMBLE_SIZE);
+
+    uint8_t boundary_flag = GET_BOUNDARY_FLAG(handle);
+    handle = handle & HANDLE_MASK;
+
+    if (boundary_flag == START_PACKET_BOUNDARY) {
+      auto map_iter = partial_packets.find(handle);
+      if (map_iter != partial_packets.end()) {
+        LOG_WARN(LOG_TAG,
+                 "%s found unfinished packet for handle with start packet. "
+                 "Dropping old.",
+                 __func__);
+
+        BT_HDR* hdl = map_iter->second;
+        partial_packets.erase(map_iter);
+        buffer_allocator->free(hdl);
+      }
+
+      if (acl_length < L2CAP_HEADER_SIZE) {
+        LOG_WARN(LOG_TAG, "%s L2CAP packet too small (%d < %d). Dropping it.",
+                 __func__, packet->len, L2CAP_HEADER_SIZE);
+        buffer_allocator->free(packet);
+        return;
+      }
+
+      uint16_t full_length =
+          l2cap_length + L2CAP_HEADER_SIZE + HCI_ACL_PREAMBLE_SIZE;
+
+      // Check for buffer overflow and that the full packet size + BT_HDR size
+      // is less than
+      // the max buffer size
+      if (check_uint16_overflow(l2cap_length,
+                                (L2CAP_HEADER_SIZE + HCI_ACL_PREAMBLE_SIZE)) ||
+          ((full_length + sizeof(BT_HDR)) > BT_DEFAULT_BUFFER_SIZE)) {
+        LOG_ERROR(LOG_TAG,
+                  "%s L2CAP packet has invalid length (%d). Dropping it.",
+                  __func__, l2cap_length);
+        buffer_allocator->free(packet);
+        return;
+      }
+
+      if (full_length <= packet->len) {
+        if (full_length < packet->len)
+          LOG_WARN(LOG_TAG,
+                   "%s found l2cap full length %d less than the hci length %d.",
+                   __func__, l2cap_length, packet->len);
+
+        callbacks->reassembled(packet);
+        return;
+      }
+
+      BT_HDR* partial_packet =
+          (BT_HDR*)buffer_allocator->alloc(full_length + sizeof(BT_HDR));
+      partial_packet->event = packet->event;
+      partial_packet->len = full_length;
+      partial_packet->offset = packet->len;
+
+      memcpy(partial_packet->data, packet->data, packet->len);
+
+      // Update the ACL data size to indicate the full expected length
+      stream = partial_packet->data;
+      STREAM_SKIP_UINT16(stream);  // skip the handle
+      UINT16_TO_STREAM(stream, full_length - HCI_ACL_PREAMBLE_SIZE);
+
+      partial_packets[handle] = partial_packet;
+
+      // Free the old packet buffer, since we don't need it anymore
+      buffer_allocator->free(packet);
+    } else {
+      auto map_iter = partial_packets.find(handle);
+      if (map_iter == partial_packets.end()) {
+        LOG_WARN(LOG_TAG,
+                 "%s got continuation for unknown packet. Dropping it.",
+                 __func__);
+        buffer_allocator->free(packet);
+        return;
+      }
+      BT_HDR* partial_packet = map_iter->second;
+
+      packet->offset = HCI_ACL_PREAMBLE_SIZE;
+      uint16_t projected_offset =
+          partial_packet->offset + (packet->len - HCI_ACL_PREAMBLE_SIZE);
+      if (projected_offset >
+          partial_packet->len) {  // len stores the expected length
+        LOG_WARN(LOG_TAG,
+                 "%s got packet which would exceed expected length of %d. "
+                 "Truncating.",
+                 __func__, partial_packet->len);
+        packet->len = partial_packet->len - partial_packet->offset;
+        projected_offset = partial_packet->len;
+      }
+
+      memcpy(partial_packet->data + partial_packet->offset,
+             packet->data + packet->offset, packet->len - packet->offset);
+
+      // Free the old packet buffer, since we don't need it anymore
+      buffer_allocator->free(packet);
+      partial_packet->offset = projected_offset;
+
+      if (partial_packet->offset == partial_packet->len) {
+        partial_packets.erase(handle);
+        partial_packet->offset = 0;
+        callbacks->reassembled(partial_packet);
+      }
+    }
+  } else {
+    callbacks->reassembled(packet);
+  }
+}
+
+static const packet_fragmenter_t interface = {init, cleanup,
+
+                                              fragment_and_dispatch,
+                                              reassemble_and_dispatch};
+
+const packet_fragmenter_t* packet_fragmenter_get_interface() {
+  controller = controller_get_interface();
+  buffer_allocator = buffer_allocator_get_interface();
+  return &interface;
+}
+
+const packet_fragmenter_t* packet_fragmenter_get_test_interface(
+    const controller_t* controller_interface,
+    const allocator_t* buffer_allocator_interface) {
+  controller = controller_interface;
+  buffer_allocator = buffer_allocator_interface;
+  return &interface;
+}
diff --git a/bt/hci/src/vendor.cc b/bt/hci/src/vendor.cc
new file mode 100644
index 0000000..1c1ab8c
--- /dev/null
+++ b/bt/hci/src/vendor.cc
@@ -0,0 +1,236 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_vendor"
+
+#include "vendor.h"
+
+#include <assert.h>
+#include <dlfcn.h>
+
+#include "bt_vendor_lib.h"
+#include "bta_av_api.h"
+#include "buffer_allocator.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+static bool vendor_open(const uint8_t* local_bdaddr,
+                        const hci_t* hci_interface);
+static void vendor_close(void);
+static int send_command(vendor_opcode_t opcode, void* param);
+static int send_async_command(vendor_async_opcode_t opcode, void* param);
+static void set_callback(vendor_async_opcode_t opcode, vendor_cb callback);
+
+static void firmware_config_cb(bt_vendor_op_result_t result);
+static void sco_config_cb(bt_vendor_op_result_t result);
+static void low_power_mode_cb(bt_vendor_op_result_t result);
+static void sco_audiostate_cb(bt_vendor_op_result_t result);
+static void* buffer_alloc_cb(int size);
+static void buffer_free_cb(void* buffer);
+static uint8_t transmit_cb(UNUSED_ATTR uint16_t opcode, void* buffer,
+                           tINT_CMD_CBACK callback);
+static void epilog_cb(bt_vendor_op_result_t result);
+static void a2dp_offload_cb(bt_vendor_op_result_t result, bt_vendor_opcode_t op,
+                            uint8_t bta_av_handle);
+
+static const char* VENDOR_LIBRARY_NAME = "libbt-vendor.so";
+static const char* VENDOR_LIBRARY_SYMBOL_NAME =
+    "BLUETOOTH_VENDOR_LIB_INTERFACE";
+
+static const allocator_t* buffer_allocator;
+static const hci_t* hci;
+static vendor_cb callbacks[VENDOR_LAST_OP];
+
+static const bt_vendor_callbacks_t lib_callbacks = {
+    sizeof(lib_callbacks), firmware_config_cb, sco_config_cb,
+    low_power_mode_cb,     sco_audiostate_cb,  buffer_alloc_cb,
+    buffer_free_cb,        transmit_cb,        epilog_cb,
+    a2dp_offload_cb};
+
+static const vendor_t interface = {
+    vendor_open, vendor_close, send_command, send_async_command, set_callback,
+};
+
+static void* lib_handle;
+static bt_vendor_interface_t* lib_interface;
+
+// Interface functions
+
+static bool vendor_open(const uint8_t* local_bdaddr,
+                        const hci_t* hci_interface) {
+  int status;
+  assert(lib_handle == NULL);
+  hci = hci_interface;
+
+  lib_handle = dlopen(VENDOR_LIBRARY_NAME, RTLD_NOW);
+  if (!lib_handle) {
+    LOG_ERROR(LOG_TAG, "%s unable to open %s: %s", __func__,
+              VENDOR_LIBRARY_NAME, dlerror());
+    goto error;
+  }
+
+  lib_interface =
+      (bt_vendor_interface_t*)dlsym(lib_handle, VENDOR_LIBRARY_SYMBOL_NAME);
+  if (!lib_interface) {
+    LOG_ERROR(LOG_TAG, "%s unable to find symbol %s in %s: %s", __func__,
+              VENDOR_LIBRARY_SYMBOL_NAME, VENDOR_LIBRARY_NAME, dlerror());
+    goto error;
+  }
+
+  LOG_INFO(LOG_TAG, "alloc value %p", lib_callbacks.alloc);
+
+  status = lib_interface->init(&lib_callbacks, (unsigned char*)local_bdaddr);
+  if (status) {
+    LOG_ERROR(LOG_TAG, "%s unable to initialize vendor library: %d", __func__,
+              status);
+    goto error;
+  }
+
+  return true;
+
+error:;
+  lib_interface = NULL;
+  if (lib_handle) dlclose(lib_handle);
+  lib_handle = NULL;
+  return false;
+}
+
+static void vendor_close(void) {
+  if (lib_interface) lib_interface->cleanup();
+
+  if (lib_handle) dlclose(lib_handle);
+
+  lib_interface = NULL;
+  lib_handle = NULL;
+}
+
+static int send_command(vendor_opcode_t opcode, void* param) {
+  assert(lib_interface != NULL);
+  return lib_interface->op((bt_vendor_opcode_t)opcode, param);
+}
+
+static int send_async_command(vendor_async_opcode_t opcode, void* param) {
+  assert(lib_interface != NULL);
+  return lib_interface->op((bt_vendor_opcode_t)opcode, param);
+}
+
+static void set_callback(vendor_async_opcode_t opcode, vendor_cb callback) {
+  callbacks[opcode] = callback;
+}
+
+// Internal functions
+
+// Called back from vendor library when the firmware configuration
+// completes.
+static void firmware_config_cb(bt_vendor_op_result_t result) {
+  LOG_INFO(LOG_TAG, "firmware callback");
+  vendor_cb callback = callbacks[VENDOR_CONFIGURE_FIRMWARE];
+  assert(callback != NULL);
+  callback(result == BT_VND_OP_RESULT_SUCCESS);
+}
+
+// Called back from vendor library to indicate status of previous
+// SCO configuration request. This should only happen during the
+// postload process.
+static void sco_config_cb(bt_vendor_op_result_t result) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  vendor_cb callback = callbacks[VENDOR_CONFIGURE_SCO];
+  assert(callback != NULL);
+  callback(result == BT_VND_OP_RESULT_SUCCESS);
+}
+
+// Called back from vendor library to indicate status of previous
+// LPM enable/disable request.
+static void low_power_mode_cb(bt_vendor_op_result_t result) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  vendor_cb callback = callbacks[VENDOR_SET_LPM_MODE];
+  assert(callback != NULL);
+  callback(result == BT_VND_OP_RESULT_SUCCESS);
+}
+
+/******************************************************************************
+ *
+ * Function         sco_audiostate_cb
+ *
+ * Description      HOST/CONTROLLER VENDOR LIB CALLBACK API - This function is
+ *                  called when the libbt-vendor completed vendor specific codec
+ *                  setup request
+ *
+ * Returns          None
+ *
+ *****************************************************************************/
+static void sco_audiostate_cb(bt_vendor_op_result_t result) {
+  uint8_t status = (result == BT_VND_OP_RESULT_SUCCESS) ? 0 : 1;
+
+  LOG_INFO(LOG_TAG, "sco_audiostate_cb(status: %d)", status);
+}
+
+// Called by vendor library when it needs an HCI buffer.
+static void* buffer_alloc_cb(int size) { return buffer_allocator->alloc(size); }
+
+// Called by vendor library when it needs to free a buffer allocated with
+// |buffer_alloc_cb|.
+static void buffer_free_cb(void* buffer) { buffer_allocator->free(buffer); }
+
+static void transmit_completed_callback(BT_HDR* response, void* context) {
+  // Call back to the vendor library if it provided a callback to call.
+  if (context) {
+    ((tINT_CMD_CBACK)context)(response);
+  } else {
+    // HCI layer expects us to release the response.
+    buffer_free_cb(response);
+  }
+}
+
+// Called back from vendor library when it wants to send an HCI command.
+static uint8_t transmit_cb(UNUSED_ATTR uint16_t opcode, void* buffer,
+                           tINT_CMD_CBACK callback) {
+  assert(hci != NULL);
+  hci->transmit_command((BT_HDR*)buffer, transmit_completed_callback, NULL,
+                        reinterpret_cast<void*>(callback));
+  return true;
+}
+
+// Called back from vendor library when the epilog procedure has
+// completed. It is safe to call vendor_interface->cleanup() after
+// this callback has been received.
+static void epilog_cb(bt_vendor_op_result_t result) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  vendor_cb callback = callbacks[VENDOR_DO_EPILOG];
+  assert(callback != NULL);
+  callback(result == BT_VND_OP_RESULT_SUCCESS);
+}
+
+// Called back from vendor library when the a2dp offload machine has to report
+// status of
+// an a2dp offload command.
+static void a2dp_offload_cb(bt_vendor_op_result_t result, bt_vendor_opcode_t op,
+                            uint8_t bta_av_handle) {
+  tBTA_AV_STATUS status = (result == BT_VND_OP_RESULT_SUCCESS)
+                              ? BTA_AV_SUCCESS
+                              : BTA_AV_FAIL_RESOURCES;
+
+  if (op == BT_VND_OP_A2DP_OFFLOAD_START) {
+    BTA_AvOffloadStartRsp(bta_av_handle, status);
+  }
+}
+
+const vendor_t* vendor_get_interface() {
+  buffer_allocator = buffer_allocator_get_interface();
+  return &interface;
+}
diff --git a/bt/hci/test/hci_hal_h4_test.cc b/bt/hci/test/hci_hal_h4_test.cc
new file mode 100644
index 0000000..4d9ff86
--- /dev/null
+++ b/bt/hci/test/hci_hal_h4_test.cc
@@ -0,0 +1,271 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "AllocationTestHarness.h"
+
+#include <stdint.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "hci_hal.h"
+#include "osi/include/osi.h"
+#include "osi/include/semaphore.h"
+#include "test_stubs.h"
+#include "vendor.h"
+
+DECLARE_TEST_MODES(init, open, close_fn, transmit, read_synchronous,
+                   read_async_reentry, type_byte_only);
+
+// Use as packet type to test stream_corrupted_during_le_scan_workaround()
+static const uint8_t HCI_BLE_EVENT = 0x3e;
+
+static char sample_data1[100] = "A point is that which has no part.";
+static char sample_data2[100] = "A line is breadthless length.";
+static char sample_data3[100] = "The ends of a line are points.";
+static char acl_data[100] =
+    "A straight line is a line which lies evenly with the points on itself.";
+static char sco_data[100] =
+    "A surface is that which has length and breadth only.";
+static char event_data[100] = "The edges of a surface are lines.";
+
+// Test data for stream_corrupted_during_le_scan_workaround()
+static char corrupted_data[] = {
+    0x5 /* length of remaining data */, 'H', 'e', 'l', 'l', 'o'};
+
+static const hci_hal_t* hal;
+static int dummy_serial_fd;
+static int reentry_i = 0;
+
+static semaphore_t* done;
+static semaphore_t* reentry_semaphore;
+
+static void expect_packet_synchronous(serial_data_type_t type,
+                                      char* packet_data) {
+  int length = strlen(packet_data);
+  for (int i = 0; i < length; i++) {
+    uint8_t byte;
+    EXPECT_EQ((size_t)1, hal->read_data(type, &byte, 1));
+    EXPECT_EQ(packet_data[i], byte);
+  }
+
+  hal->packet_finished(type);
+}
+
+STUB_FUNCTION(int, vendor_send_command, (vendor_opcode_t opcode, void* param))
+DURING(open) AT_CALL(0) {
+  EXPECT_EQ(VENDOR_OPEN_USERIAL, opcode);
+  // Give back the dummy fd and the number 1 to say we opened 1 port
+  ((int*)param)[0] = dummy_serial_fd;
+  return 1;
+}
+
+DURING(close_fn) AT_CALL(0) {
+  EXPECT_EQ(VENDOR_CLOSE_USERIAL, opcode);
+  return 0;
+}
+
+UNEXPECTED_CALL;
+return 0;
+}
+
+STUB_FUNCTION(void, data_ready_callback, (serial_data_type_t type))
+DURING(read_synchronous) {
+  AT_CALL(0) {
+    EXPECT_EQ(DATA_TYPE_ACL, type);
+    expect_packet_synchronous(type, acl_data);
+    return;
+  }
+  AT_CALL(1) {
+    EXPECT_EQ(DATA_TYPE_SCO, type);
+    expect_packet_synchronous(type, sco_data);
+    return;
+  }
+  AT_CALL(2) {
+    EXPECT_EQ(DATA_TYPE_EVENT, type);
+    expect_packet_synchronous(type, event_data);
+    semaphore_post(done);
+    return;
+  }
+}
+
+DURING(read_async_reentry) {
+  EXPECT_EQ(DATA_TYPE_ACL, type);
+
+  uint8_t byte;
+  size_t bytes_read;
+  while ((bytes_read = hal->read_data(type, &byte, 1)) != 0) {
+    EXPECT_EQ(sample_data3[reentry_i], byte);
+    semaphore_post(reentry_semaphore);
+    reentry_i++;
+    if (reentry_i == (int)strlen(sample_data3)) {
+      hal->packet_finished(type);
+      return;
+    }
+  }
+
+  return;
+}
+
+UNEXPECTED_CALL;
+}
+
+static void reset_for(TEST_MODES_T next) {
+  RESET_CALL_COUNT(vendor_send_command);
+  RESET_CALL_COUNT(data_ready_callback);
+  CURRENT_TEST_MODE = next;
+}
+
+class HciHalH4Test : public AllocationTestHarness {
+ protected:
+  virtual void SetUp() {
+    AllocationTestHarness::SetUp();
+    hal = hci_hal_h4_get_test_interface(&vendor);
+    vendor.send_command = vendor_send_command;
+    callbacks.data_ready = data_ready_callback;
+
+    socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
+    dummy_serial_fd = sockfd[0];
+    done = semaphore_new(0);
+    thread = thread_new("hal_test");
+
+    reset_for(init);
+    EXPECT_TRUE(hal->init(&callbacks, thread));
+
+    reset_for(open);
+    EXPECT_TRUE(hal->open());
+    EXPECT_CALL_COUNT(vendor_send_command, 1);
+  }
+
+  virtual void TearDown() {
+    reset_for(close_fn);
+    hal->close();
+    EXPECT_CALL_COUNT(vendor_send_command, 1);
+
+    semaphore_free(done);
+    thread_free(thread);
+    AllocationTestHarness::TearDown();
+  }
+
+  int sockfd[2];
+  vendor_t vendor;
+  thread_t* thread;
+  hci_hal_callbacks_t callbacks;
+};
+
+static void expect_socket_data(int fd, char first_byte, char* data) {
+  int length = strlen(data) + 1;  // + 1 for data type code
+  int i;
+
+  for (i = 0; i < length; i++) {
+    fd_set read_fds;
+    FD_ZERO(&read_fds);
+    FD_SET(fd, &read_fds);
+    select(fd + 1, &read_fds, NULL, NULL, NULL);
+
+    char byte;
+    read(fd, &byte, 1);
+
+    EXPECT_EQ(i == 0 ? first_byte : data[i - 1], byte);
+  }
+}
+
+static void write_packet(int fd, char first_byte, const void* data,
+                         size_t datalen) {
+  write(fd, &first_byte, 1);
+  write(fd, data, datalen);
+}
+
+static void write_packet_reentry(int fd, char first_byte, const void* data,
+                                 size_t datalen) {
+  write(fd, &first_byte, 1);
+
+  for (size_t i = 0; i < datalen; i++) {
+    write(fd, static_cast<const uint8_t*>(data) + i, 1);
+    semaphore_wait(reentry_semaphore);
+  }
+}
+
+TEST_F(HciHalH4Test, test_transmit) {
+  reset_for(transmit);
+
+  // Send a command packet
+  hal->transmit_data(DATA_TYPE_COMMAND, (uint8_t*)(sample_data1 + 1),
+                     strlen(sample_data1 + 1));
+  expect_socket_data(sockfd[1], DATA_TYPE_COMMAND, sample_data1 + 1);
+
+  // Send an acl packet
+  hal->transmit_data(DATA_TYPE_ACL, (uint8_t*)(sample_data2 + 1),
+                     strlen(sample_data2 + 1));
+  expect_socket_data(sockfd[1], DATA_TYPE_ACL, sample_data2 + 1);
+
+  // Send an sco packet
+  hal->transmit_data(DATA_TYPE_SCO, (uint8_t*)(sample_data3 + 1),
+                     strlen(sample_data3 + 1));
+  expect_socket_data(sockfd[1], DATA_TYPE_SCO, sample_data3 + 1);
+}
+
+TEST_F(HciHalH4Test, test_read_synchronous) {
+  reset_for(read_synchronous);
+
+  write_packet(sockfd[1], DATA_TYPE_ACL, acl_data, strlen(acl_data));
+  write_packet(sockfd[1], HCI_BLE_EVENT, corrupted_data,
+               sizeof(corrupted_data));
+  write_packet(sockfd[1], DATA_TYPE_SCO, sco_data, strlen(sco_data));
+  write_packet(sockfd[1], DATA_TYPE_EVENT, event_data, strlen(event_data));
+
+  // Wait for all data to be received before calling the test good
+  semaphore_wait(done);
+  EXPECT_CALL_COUNT(data_ready_callback, 3);
+}
+
+TEST_F(HciHalH4Test, test_read_async_reentry) {
+  reset_for(read_async_reentry);
+
+  reentry_semaphore = semaphore_new(0);
+  reentry_i = 0;
+
+  write_packet_reentry(sockfd[1], DATA_TYPE_ACL, sample_data3,
+                       strlen(sample_data3));
+
+  // write_packet_reentry ensures the data has been received
+  semaphore_free(reentry_semaphore);
+}
+
+TEST_F(HciHalH4Test, test_type_byte_only_must_not_signal_data_ready) {
+  reset_for(type_byte_only);
+
+  char byte = DATA_TYPE_ACL;
+  write(sockfd[1], &byte, 1);
+
+  fd_set read_fds;
+
+  // Wait until the byte we wrote was picked up
+  do {
+    FD_ZERO(&read_fds);
+    FD_SET(sockfd[0], &read_fds);
+
+    struct timeval timeout;
+    timeout.tv_sec = 0;
+    timeout.tv_usec = 0;
+
+    select(sockfd[0] + 1, &read_fds, NULL, NULL, &timeout);
+  } while (FD_ISSET(sockfd[0], &read_fds));
+}
diff --git a/bt/hci/test/hci_hal_mct_test.cc b/bt/hci/test/hci_hal_mct_test.cc
new file mode 100644
index 0000000..dd1b70d
--- /dev/null
+++ b/bt/hci/test/hci_hal_mct_test.cc
@@ -0,0 +1,238 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "AllocationTestHarness.h"
+
+#include <stdint.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "hci_hal.h"
+#include "osi/include/osi.h"
+#include "osi/include/semaphore.h"
+#include "test_stubs.h"
+#include "vendor.h"
+
+DECLARE_TEST_MODES(init, open, close_fn, transmit, read_synchronous,
+                   read_async_reentry);
+
+static char sample_data1[100] = "A point is that which has no part.";
+static char sample_data2[100] = "A line is breadthless length.";
+static char sample_data3[100] = "The ends of a line are points.";
+static char acl_data[100] =
+    "A straight line is a line which lies evenly with the points on itself.";
+static char event_data[100] = "The edges of a surface are lines.";
+
+static const hci_hal_t* hal;
+static int command_out_fd;
+static int acl_out_fd;
+static int acl_in_fd;
+static int event_in_fd;
+static int reentry_i = 0;
+
+static semaphore_t* done;
+static semaphore_t* reentry_semaphore;
+
+static void expect_packet_synchronous(serial_data_type_t type,
+                                      char* packet_data) {
+  int length = strlen(packet_data);
+  for (int i = 0; i < length; i++) {
+    uint8_t byte;
+    EXPECT_EQ((size_t)1, hal->read_data(type, &byte, 1));
+    EXPECT_EQ(packet_data[i], byte);
+  }
+
+  hal->packet_finished(type);
+}
+
+STUB_FUNCTION(int, vendor_send_command, (vendor_opcode_t opcode, void* param))
+DURING(open) AT_CALL(0) {
+  EXPECT_EQ(VENDOR_OPEN_USERIAL, opcode);
+  ((int*)param)[CH_CMD] = command_out_fd;
+  ((int*)param)[CH_ACL_OUT] = acl_out_fd;
+  ((int*)param)[CH_ACL_IN] = acl_in_fd;
+  ((int*)param)[CH_EVT] = event_in_fd;
+  return 4;
+}
+
+DURING(close_fn) AT_CALL(0) {
+  EXPECT_EQ(VENDOR_CLOSE_USERIAL, opcode);
+  return 0;
+}
+
+UNEXPECTED_CALL;
+return 0;
+}
+
+STUB_FUNCTION(void, data_ready_callback, (serial_data_type_t type))
+DURING(read_synchronous) {
+  AT_CALL(0) {
+    EXPECT_EQ(DATA_TYPE_ACL, type);
+    expect_packet_synchronous(type, acl_data);
+    semaphore_post(done);
+    return;
+  }
+  AT_CALL(1) {
+    EXPECT_EQ(DATA_TYPE_EVENT, type);
+    expect_packet_synchronous(type, event_data);
+    semaphore_post(done);
+    return;
+  }
+}
+
+DURING(read_async_reentry) {
+  EXPECT_EQ(DATA_TYPE_ACL, type);
+
+  uint8_t byte;
+  size_t bytes_read;
+  while ((bytes_read = hal->read_data(type, &byte, 1)) != 0) {
+    EXPECT_EQ(sample_data3[reentry_i], byte);
+    semaphore_post(reentry_semaphore);
+    reentry_i++;
+    if (reentry_i == (int)strlen(sample_data3)) {
+      hal->packet_finished(type);
+      return;
+    }
+  }
+
+  return;
+}
+
+UNEXPECTED_CALL;
+}
+
+static void reset_for(TEST_MODES_T next) {
+  RESET_CALL_COUNT(vendor_send_command);
+  RESET_CALL_COUNT(data_ready_callback);
+  CURRENT_TEST_MODE = next;
+}
+
+class HciHalMctTest : public AllocationTestHarness {
+ protected:
+  virtual void SetUp() {
+    AllocationTestHarness::SetUp();
+    hal = hci_hal_mct_get_test_interface(&vendor);
+    vendor.send_command = vendor_send_command;
+    callbacks.data_ready = data_ready_callback;
+
+    socketpair(AF_LOCAL, SOCK_STREAM, 0, command_sockfd);
+    socketpair(AF_LOCAL, SOCK_STREAM, 0, event_sockfd);
+    socketpair(AF_LOCAL, SOCK_STREAM, 0, acl_in_sockfd);
+    socketpair(AF_LOCAL, SOCK_STREAM, 0, acl_out_sockfd);
+    command_out_fd = command_sockfd[0];
+    acl_out_fd = acl_out_sockfd[0];
+    acl_in_fd = acl_in_sockfd[0];
+    event_in_fd = event_sockfd[0];
+
+    done = semaphore_new(0);
+    thread = thread_new("hal_test");
+
+    reset_for(init);
+    EXPECT_TRUE(hal->init(&callbacks, thread));
+
+    reset_for(open);
+    EXPECT_TRUE(hal->open());
+    EXPECT_CALL_COUNT(vendor_send_command, 1);
+  }
+
+  virtual void TearDown() {
+    reset_for(close_fn);
+    hal->close();
+    EXPECT_CALL_COUNT(vendor_send_command, 1);
+
+    semaphore_free(done);
+    thread_free(thread);
+    AllocationTestHarness::TearDown();
+  }
+
+  int command_sockfd[2];
+  int event_sockfd[2];
+  int acl_in_sockfd[2];
+  int acl_out_sockfd[2];
+  vendor_t vendor;
+  thread_t* thread;
+  hci_hal_callbacks_t callbacks;
+};
+
+static void expect_socket_data(int fd, char* data) {
+  int length = strlen(data);
+  int i;
+
+  for (i = 0; i < length; i++) {
+    fd_set read_fds;
+    FD_ZERO(&read_fds);
+    FD_SET(fd, &read_fds);
+    select(fd + 1, &read_fds, NULL, NULL, NULL);
+
+    char byte;
+    read(fd, &byte, 1);
+
+    EXPECT_EQ(data[i], byte);
+  }
+}
+
+static void write_packet(int fd, char* data) { write(fd, data, strlen(data)); }
+
+static void write_packet_reentry(int fd, char* data) {
+  int length = strlen(data);
+  for (int i = 0; i < length; i++) {
+    write(fd, &data[i], 1);
+    semaphore_wait(reentry_semaphore);
+  }
+}
+
+TEST_F(HciHalMctTest, test_transmit) {
+  reset_for(transmit);
+
+  // Send a command packet
+  hal->transmit_data(DATA_TYPE_COMMAND, (uint8_t*)(sample_data1),
+                     strlen(sample_data1));
+  expect_socket_data(command_sockfd[1], sample_data1);
+
+  // Send an acl packet
+  hal->transmit_data(DATA_TYPE_ACL, (uint8_t*)(sample_data2),
+                     strlen(sample_data2));
+  expect_socket_data(acl_out_sockfd[1], sample_data2);
+}
+
+TEST_F(HciHalMctTest, test_read_synchronous) {
+  reset_for(read_synchronous);
+
+  write_packet(acl_in_sockfd[1], acl_data);
+  semaphore_wait(done);
+
+  write_packet(event_sockfd[1], event_data);
+  semaphore_wait(done);
+
+  EXPECT_CALL_COUNT(data_ready_callback, 2);
+}
+
+TEST_F(HciHalMctTest, test_read_async_reentry) {
+  reset_for(read_async_reentry);
+
+  reentry_semaphore = semaphore_new(0);
+  reentry_i = 0;
+
+  write_packet_reentry(acl_in_sockfd[1], sample_data3);
+
+  // write_packet_reentry ensures the data has been received
+  semaphore_free(reentry_semaphore);
+}
diff --git a/bt/hci/test/hci_layer_test.cc b/bt/hci/test/hci_layer_test.cc
new file mode 100644
index 0000000..913c8c0
--- /dev/null
+++ b/bt/hci/test/hci_layer_test.cc
@@ -0,0 +1,753 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "AlarmTestHarness.h"
+
+#include <stdint.h>
+
+#include "btsnoop.h"
+#include "device/include/controller.h"
+#include "hci_hal.h"
+#include "hci_inject.h"
+#include "hci_layer.h"
+#include "hcimsgs.h"
+#include "low_power_manager.h"
+#include "module.h"
+#include "osi/include/allocation_tracker.h"
+#include "osi/include/allocator.h"
+#include "osi/include/osi.h"
+#include "osi/include/semaphore.h"
+#include "packet_fragmenter.h"
+#include "test_stubs.h"
+#include "vendor.h"
+
+extern const module_t hci_module;
+
+DECLARE_TEST_MODES(start_up_async, shut_down, postload, transmit_simple,
+                   receive_simple, transmit_command_no_callbacks,
+                   transmit_command_command_status,
+                   transmit_command_command_complete,
+                   ignoring_packets_ignored_packet,
+                   ignoring_packets_following_packet);
+
+// TODO: Ugly hack to get around another ugly hack in hci_layer.cc
+bt_bdaddr_t btif_local_bd_addr;
+
+static const char* small_sample_data =
+    "\"It is easy to see,\" replied Don Quixote";
+static const char* command_sample_data =
+    "that thou art not used to this business of adventures; those are giants";
+static const char* ignored_data =
+    "and if thou art afraid, away with thee out of this and betake thyself to "
+    "prayer";
+static const char* unignored_data =
+    "while I engage them in fierce and unequal combat";
+
+static const hci_t* hci;
+static const hci_hal_callbacks_t* hal_callbacks;
+static thread_t* internal_thread;
+static vendor_cb firmware_config_callback;
+static vendor_cb sco_config_callback;
+static vendor_cb epilog_callback;
+static semaphore_t* done;
+static const uint16_t test_handle = (0x1992 & 0xCFFF);
+static const uint16_t test_handle_continuation = (0x1992 & 0xCFFF) | 0x1000;
+static int packet_index;
+static unsigned int data_size_sum;
+static BT_HDR* data_to_receive;
+
+static void signal_work_item(UNUSED_ATTR void* context) {
+  semaphore_post(done);
+}
+
+static void flush_thread(thread_t* thread) {
+  // Double flush to ensure we get the next reactor cycle
+  thread_post(thread, signal_work_item, NULL);
+  semaphore_wait(done);
+  thread_post(thread, signal_work_item, NULL);
+  semaphore_wait(done);
+}
+
+// TODO move this to a common packet testing helper
+static BT_HDR* manufacture_packet(uint16_t event, const char* data) {
+  uint16_t data_length = strlen(data);
+  uint16_t size = data_length;
+  if (event == MSG_STACK_TO_HC_HCI_ACL) {
+    size += 4;  // 2 for the handle, 2 for the length;
+  }
+
+  BT_HDR* packet = (BT_HDR*)osi_malloc(size + sizeof(BT_HDR));
+  packet->len = size;
+  packet->offset = 0;
+  packet->layer_specific = 0;
+
+  // The command transmit interface adds the event type automatically.
+  // Make sure it works but omitting it here.
+  if (event != MSG_STACK_TO_HC_HCI_CMD) packet->event = event;
+
+  uint8_t* packet_data = packet->data;
+
+  if (event == MSG_STACK_TO_HC_HCI_ACL) {
+    UINT16_TO_STREAM(packet_data, test_handle);
+    UINT16_TO_STREAM(packet_data, data_length);
+  }
+
+  for (int i = 0; i < data_length; i++) {
+    packet_data[i] = data[i];
+  }
+
+  if (event == MSG_STACK_TO_HC_HCI_CMD) {
+    STREAM_SKIP_UINT16(packet_data);
+    UINT8_TO_STREAM(packet_data, data_length - 3);
+  } else if (event == MSG_HC_TO_STACK_HCI_EVT) {
+    STREAM_SKIP_UINT8(packet_data);
+    UINT8_TO_STREAM(packet_data, data_length - 2);
+  }
+
+  return packet;
+}
+
+static void expect_packet(uint16_t event, int max_acl_data_size,
+                          const uint8_t* data, uint16_t data_length,
+                          const char* expected_data) {
+  int expected_data_offset;
+  int length_to_check;
+
+  if (event == MSG_STACK_TO_HC_HCI_ACL) {
+    uint16_t handle;
+    uint16_t length;
+    STREAM_TO_UINT16(handle, data);
+    STREAM_TO_UINT16(length, data);
+
+    if (packet_index == 0)
+      EXPECT_EQ(test_handle, handle);
+    else
+      EXPECT_EQ(test_handle_continuation, handle);
+
+    int length_remaining = strlen(expected_data) - data_size_sum;
+    int packet_data_length = data_length - HCI_ACL_PREAMBLE_SIZE;
+    EXPECT_EQ(length_remaining, length);
+
+    if (length_remaining < max_acl_data_size)
+      EXPECT_EQ(length, packet_data_length);
+    else
+      EXPECT_EQ(max_acl_data_size, packet_data_length);
+
+    length_to_check = packet_data_length;
+    expected_data_offset = packet_index * max_acl_data_size;
+    packet_index++;
+  } else {
+    length_to_check = strlen(expected_data);
+    expected_data_offset = 0;
+  }
+
+  for (int i = 0; i < length_to_check; i++) {
+    if (event == MSG_STACK_TO_HC_HCI_CMD && (i == 2))
+      EXPECT_EQ(data_length - 3, data[i]);
+    else
+      EXPECT_EQ(expected_data[expected_data_offset + i], data[i]);
+
+    data_size_sum++;
+  }
+}
+
+STUB_FUNCTION(bool, hal_init,
+              (const hci_hal_callbacks_t* callbacks, thread_t* working_thread))
+DURING(start_up_async) AT_CALL(0) {
+  hal_callbacks = callbacks;
+  internal_thread = working_thread;
+  return true;
+}
+
+UNEXPECTED_CALL;
+return false;
+}
+
+STUB_FUNCTION(bool, hal_open, ())
+DURING(start_up_async) AT_CALL(0) return true;
+UNEXPECTED_CALL;
+return false;
+}
+
+STUB_FUNCTION(void, hal_close, ())
+DURING(shut_down) AT_CALL(0) return;
+UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(uint16_t, hal_transmit_data,
+              (serial_data_type_t type, uint8_t* data, uint16_t length))
+DURING(transmit_simple) AT_CALL(0) {
+  EXPECT_EQ(DATA_TYPE_ACL, type);
+  expect_packet(MSG_STACK_TO_HC_HCI_ACL, 1021, data, length, small_sample_data);
+  return length;
+}
+
+DURING(transmit_command_no_callbacks, transmit_command_command_status,
+       transmit_command_command_complete)
+AT_CALL(0) {
+  EXPECT_EQ(DATA_TYPE_COMMAND, type);
+  expect_packet(MSG_STACK_TO_HC_HCI_CMD, 1021, data, length,
+                command_sample_data);
+  return length;
+}
+
+UNEXPECTED_CALL;
+return 0;
+}
+
+static size_t replay_data_to_receive(size_t max_size, uint8_t* buffer) {
+  for (size_t i = 0; i < max_size; i++) {
+    if (data_to_receive->offset >= data_to_receive->len) break;
+
+    buffer[i] = data_to_receive->data[data_to_receive->offset++];
+
+    if (i == (max_size - 1))
+      return i + 1;  // We return the length, not the index;
+  }
+
+  return 0;
+}
+
+STUB_FUNCTION(size_t, hal_read_data,
+              (serial_data_type_t type, uint8_t* buffer, size_t max_size))
+DURING(receive_simple, ignoring_packets_following_packet) {
+  EXPECT_EQ(DATA_TYPE_ACL, type);
+  return replay_data_to_receive(max_size, buffer);
+}
+
+DURING(ignoring_packets_ignored_packet) {
+  EXPECT_EQ(DATA_TYPE_EVENT, type);
+  return replay_data_to_receive(max_size, buffer);
+}
+
+DURING(transmit_command_no_callbacks, transmit_command_command_status,
+       transmit_command_command_complete) {
+  EXPECT_EQ(DATA_TYPE_EVENT, type);
+  return replay_data_to_receive(max_size, buffer);
+}
+
+UNEXPECTED_CALL;
+return 0;
+}
+
+STUB_FUNCTION(void, hal_packet_finished, (serial_data_type_t type))
+DURING(receive_simple, ignoring_packets_following_packet) AT_CALL(0) {
+  EXPECT_EQ(DATA_TYPE_ACL, type);
+  return;
+}
+
+DURING(ignoring_packets_ignored_packet) AT_CALL(0) {
+  EXPECT_EQ(DATA_TYPE_EVENT, type);
+  return;
+}
+
+DURING(transmit_command_no_callbacks, transmit_command_command_status,
+       transmit_command_command_complete)
+AT_CALL(0) {
+  EXPECT_EQ(DATA_TYPE_EVENT, type);
+  return;
+}
+
+UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(bool, hci_inject_open, (UNUSED_ATTR const hci_t* hci_interface))
+DURING(start_up_async) AT_CALL(0) return true;
+UNEXPECTED_CALL;
+return false;
+}
+
+STUB_FUNCTION(void, hci_inject_close, ())
+DURING(shut_down) AT_CALL(0) return;
+UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, btsnoop_capture, (const BT_HDR* buffer, bool is_received))
+DURING(transmit_simple) AT_CALL(0) {
+  EXPECT_FALSE(is_received);
+  expect_packet(MSG_STACK_TO_HC_HCI_ACL, 1021, buffer->data + buffer->offset,
+                buffer->len, small_sample_data);
+  packet_index = 0;
+  data_size_sum = 0;
+  return;
+}
+
+DURING(transmit_command_no_callbacks, transmit_command_command_status,
+       transmit_command_command_complete) {
+  AT_CALL(0) {
+    EXPECT_FALSE(is_received);
+    expect_packet(MSG_STACK_TO_HC_HCI_CMD, 1021, buffer->data + buffer->offset,
+                  buffer->len, command_sample_data);
+    packet_index = 0;
+    data_size_sum = 0;
+    return;
+  }
+  AT_CALL(1) {
+    EXPECT_TRUE(is_received);
+    // not super important to verify the contents right now
+    return;
+  }
+}
+
+DURING(receive_simple, ignoring_packets_following_packet) AT_CALL(0) {
+  EXPECT_TRUE(is_received);
+  EXPECT_TRUE(buffer->len == data_to_receive->len);
+  const uint8_t* buffer_base = buffer->data + buffer->offset;
+  const uint8_t* expected_base = data_to_receive->data;
+  for (int i = 0; i < buffer->len; i++) {
+    EXPECT_EQ(expected_base[i], buffer_base[i]);
+  }
+
+  return;
+}
+
+UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, low_power_init, (UNUSED_ATTR thread_t * thread))
+DURING(start_up_async) AT_CALL(0) return;
+UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, low_power_cleanup, ())
+DURING(shut_down) AT_CALL(0) return;
+UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, low_power_wake_assert, ())
+DURING(transmit_simple, transmit_command_no_callbacks,
+       transmit_command_command_status, transmit_command_command_complete) {
+  AT_CALL(0) return;
+}
+
+UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, low_power_transmit_done, ())
+DURING(transmit_simple, transmit_command_no_callbacks,
+       transmit_command_command_status, transmit_command_command_complete) {
+  AT_CALL(0) return;
+}
+
+UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(bool, vendor_open,
+              (UNUSED_ATTR const uint8_t* addr, const hci_t* hci_interface))
+DURING(start_up_async) AT_CALL(0) {
+  // TODO(zachoverflow): check address value when it gets put into a module
+  EXPECT_EQ(hci, hci_interface);
+  return true;
+}
+
+UNEXPECTED_CALL;
+return true;
+}
+
+STUB_FUNCTION(void, vendor_close, ())
+DURING(shut_down) AT_CALL(0) return;
+UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, vendor_set_callback,
+              (vendor_async_opcode_t opcode, UNUSED_ATTR vendor_cb callback))
+DURING(start_up_async) {
+  AT_CALL(0) {
+    EXPECT_EQ(VENDOR_CONFIGURE_FIRMWARE, opcode);
+    firmware_config_callback = callback;
+    return;
+  }
+  AT_CALL(1) {
+    EXPECT_EQ(VENDOR_CONFIGURE_SCO, opcode);
+    sco_config_callback = callback;
+    return;
+  }
+  AT_CALL(2) {
+    EXPECT_EQ(VENDOR_DO_EPILOG, opcode);
+    epilog_callback = callback;
+    return;
+  }
+}
+
+UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(int, vendor_send_command, (vendor_opcode_t opcode, void* param))
+DURING(start_up_async) {
+#if (BT_CLEAN_TURN_ON_DISABLED == TRUE)
+  AT_CALL(0) {
+    EXPECT_EQ(VENDOR_CHIP_POWER_CONTROL, opcode);
+    EXPECT_EQ(BT_VND_PWR_ON, *(int*)param);
+    return 0;
+  }
+#else
+  AT_CALL(0) {
+    EXPECT_EQ(VENDOR_CHIP_POWER_CONTROL, opcode);
+    EXPECT_EQ(BT_VND_PWR_OFF, *(int*)param);
+    return 0;
+  }
+  AT_CALL(1) {
+    EXPECT_EQ(VENDOR_CHIP_POWER_CONTROL, opcode);
+    EXPECT_EQ(BT_VND_PWR_ON, *(int*)param);
+    return 0;
+  }
+#endif
+}
+
+DURING(shut_down) AT_CALL(0) {
+  EXPECT_EQ(VENDOR_CHIP_POWER_CONTROL, opcode);
+  EXPECT_EQ(BT_VND_PWR_OFF, *(int*)param);
+  return 0;
+}
+
+UNEXPECTED_CALL;
+return 0;
+}
+
+STUB_FUNCTION(int, vendor_send_async_command,
+              (UNUSED_ATTR vendor_async_opcode_t opcode,
+               UNUSED_ATTR void* param))
+DURING(start_up_async) AT_CALL(0) {
+  EXPECT_EQ(VENDOR_CONFIGURE_FIRMWARE, opcode);
+  firmware_config_callback(true);
+  return 0;
+}
+
+DURING(postload) AT_CALL(0) {
+  EXPECT_EQ(VENDOR_CONFIGURE_SCO, opcode);
+  sco_config_callback(true);
+  return 0;
+}
+
+DURING(shut_down) AT_CALL(0) {
+  EXPECT_EQ(VENDOR_DO_EPILOG, opcode);
+  epilog_callback(true);
+  return 0;
+}
+
+UNEXPECTED_CALL;
+return 0;
+}
+
+STUB_FUNCTION(void, command_complete_callback,
+              (BT_HDR * response, UNUSED_ATTR void* context))
+DURING(transmit_command_command_complete) AT_CALL(0) {
+  osi_free(response);
+  return;
+}
+
+UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, command_status_callback,
+              (UNUSED_ATTR uint8_t status, BT_HDR* command,
+               UNUSED_ATTR void* context))
+DURING(transmit_command_command_status) AT_CALL(0) {
+  osi_free(command);
+  return;
+}
+
+UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(uint16_t, controller_get_acl_data_size_classic, (void))
+return 2048;
+}
+
+STUB_FUNCTION(uint16_t, controller_get_acl_data_size_ble, (void))
+return 2048;
+}
+
+STUB_FUNCTION(void*, buffer_allocator_alloc, (size_t size))
+DURING(ignoring_packets_ignored_packet) {
+  AT_CALL(0)
+  return NULL;
+
+  UNEXPECTED_CALL;
+}
+
+return allocator_malloc.alloc(size);
+}
+
+STUB_FUNCTION(void, buffer_allocator_free, (void* ptr))
+allocator_malloc.free(ptr);
+}
+
+static void reset_for(TEST_MODES_T next) {
+  RESET_CALL_COUNT(vendor_open);
+  RESET_CALL_COUNT(vendor_close);
+  RESET_CALL_COUNT(vendor_set_callback);
+  RESET_CALL_COUNT(vendor_send_command);
+  RESET_CALL_COUNT(vendor_send_async_command);
+  RESET_CALL_COUNT(hal_init);
+  RESET_CALL_COUNT(hal_open);
+  RESET_CALL_COUNT(hal_close);
+  RESET_CALL_COUNT(hal_read_data);
+  RESET_CALL_COUNT(hal_packet_finished);
+  RESET_CALL_COUNT(hal_transmit_data);
+  RESET_CALL_COUNT(btsnoop_capture);
+  RESET_CALL_COUNT(hci_inject_open);
+  RESET_CALL_COUNT(hci_inject_close);
+  RESET_CALL_COUNT(low_power_init);
+  RESET_CALL_COUNT(low_power_cleanup);
+  RESET_CALL_COUNT(low_power_wake_assert);
+  RESET_CALL_COUNT(low_power_transmit_done);
+  RESET_CALL_COUNT(command_complete_callback);
+  RESET_CALL_COUNT(command_status_callback);
+  RESET_CALL_COUNT(controller_get_acl_data_size_classic);
+  RESET_CALL_COUNT(controller_get_acl_data_size_ble);
+  RESET_CALL_COUNT(buffer_allocator_alloc);
+  RESET_CALL_COUNT(buffer_allocator_free);
+  CURRENT_TEST_MODE = next;
+}
+
+class HciLayerTest : public AlarmTestHarness {
+ protected:
+  virtual void SetUp() {
+    AlarmTestHarness::SetUp();
+    module_management_start();
+
+    hci = hci_layer_get_test_interface(
+        &buffer_allocator, &hal, &btsnoop, &hci_inject,
+        packet_fragmenter_get_test_interface(&controller, &allocator_malloc),
+        &vendor, &low_power_manager);
+
+    packet_index = 0;
+    data_size_sum = 0;
+
+    vendor.open = vendor_open;
+    vendor.close = vendor_close;
+    vendor.set_callback = vendor_set_callback;
+    vendor.send_command = vendor_send_command;
+    vendor.send_async_command = vendor_send_async_command;
+    hal.init = hal_init;
+    hal.open = hal_open;
+    hal.close = hal_close;
+    hal.read_data = hal_read_data;
+    hal.packet_finished = hal_packet_finished;
+    hal.transmit_data = hal_transmit_data;
+    btsnoop.capture = btsnoop_capture;
+    hci_inject.open = hci_inject_open;
+    hci_inject.close = hci_inject_close;
+    low_power_manager.init = low_power_init;
+    low_power_manager.cleanup = low_power_cleanup;
+    low_power_manager.wake_assert = low_power_wake_assert;
+    low_power_manager.transmit_done = low_power_transmit_done;
+    controller.get_acl_data_size_classic = controller_get_acl_data_size_classic;
+    controller.get_acl_data_size_ble = controller_get_acl_data_size_ble;
+    buffer_allocator.alloc = buffer_allocator_alloc;
+    buffer_allocator.free = buffer_allocator_free;
+
+    done = semaphore_new(0);
+
+    reset_for(start_up_async);
+    EXPECT_TRUE(module_start_up(&hci_module));
+
+    EXPECT_CALL_COUNT(vendor_open, 1);
+    EXPECT_CALL_COUNT(hal_init, 1);
+    EXPECT_CALL_COUNT(low_power_init, 1);
+    EXPECT_CALL_COUNT(vendor_set_callback, 3);
+    EXPECT_CALL_COUNT(hal_open, 1);
+    EXPECT_CALL_COUNT(vendor_send_async_command, 1);
+  }
+
+  virtual void TearDown() {
+    reset_for(shut_down);
+    module_shut_down(&hci_module);
+
+    EXPECT_CALL_COUNT(low_power_cleanup, 1);
+    EXPECT_CALL_COUNT(hal_close, 1);
+    EXPECT_CALL_COUNT(vendor_send_command, 1);
+    EXPECT_CALL_COUNT(vendor_close, 1);
+
+    semaphore_free(done);
+    hci_layer_cleanup_interface();
+    module_management_stop();
+    AlarmTestHarness::TearDown();
+  }
+
+  hci_hal_t hal;
+  btsnoop_t btsnoop;
+  controller_t controller;
+  hci_inject_t hci_inject;
+  vendor_t vendor;
+  low_power_manager_t low_power_manager;
+  allocator_t buffer_allocator;
+};
+
+TEST_F(HciLayerTest, test_postload) {
+  reset_for(postload);
+  hci->do_postload();
+
+  flush_thread(internal_thread);
+  EXPECT_CALL_COUNT(vendor_send_async_command, 1);
+}
+
+TEST_F(HciLayerTest, test_transmit_simple) {
+  reset_for(transmit_simple);
+  BT_HDR* packet =
+      manufacture_packet(MSG_STACK_TO_HC_HCI_ACL, small_sample_data);
+  hci->transmit_downward(MSG_STACK_TO_HC_HCI_ACL, packet);
+
+  flush_thread(internal_thread);
+  EXPECT_CALL_COUNT(hal_transmit_data, 1);
+  EXPECT_CALL_COUNT(btsnoop_capture, 1);
+  EXPECT_CALL_COUNT(low_power_transmit_done, 1);
+  EXPECT_CALL_COUNT(low_power_wake_assert, 1);
+}
+
+TEST_F(HciLayerTest, test_receive_simple) {
+  reset_for(receive_simple);
+  data_to_receive =
+      manufacture_packet(MSG_STACK_TO_HC_HCI_ACL, small_sample_data);
+
+  // Not running on the internal thread, unlike the real hal
+  hal_callbacks->data_ready(DATA_TYPE_ACL);
+  EXPECT_CALL_COUNT(hal_packet_finished, 1);
+  EXPECT_CALL_COUNT(btsnoop_capture, 1);
+
+  osi_free(data_to_receive);
+}
+
+static BT_HDR* manufacture_command_complete(command_opcode_t opcode) {
+  BT_HDR* ret = (BT_HDR*)osi_calloc(sizeof(BT_HDR) + 5);
+  uint8_t* stream = ret->data;
+  UINT8_TO_STREAM(stream, HCI_COMMAND_COMPLETE_EVT);
+  UINT8_TO_STREAM(stream, 3);  // length of the event parameters
+  UINT8_TO_STREAM(stream, 1);  // the number of commands that can be sent
+  UINT16_TO_STREAM(stream, opcode);
+  ret->len = 5;
+
+  return ret;
+}
+
+static BT_HDR* manufacture_command_status(command_opcode_t opcode) {
+  BT_HDR* ret = (BT_HDR*)osi_calloc(sizeof(BT_HDR) + 6);
+  uint8_t* stream = ret->data;
+  UINT8_TO_STREAM(stream, HCI_COMMAND_STATUS_EVT);
+  UINT8_TO_STREAM(stream, 4);            // length of the event parameters
+  UINT8_TO_STREAM(stream, HCI_PENDING);  // status
+  UINT8_TO_STREAM(stream, 1);  // the number of commands that can be sent
+  UINT16_TO_STREAM(stream, opcode);
+  ret->len = 6;
+
+  return ret;
+}
+
+TEST_F(HciLayerTest, test_transmit_command_no_callbacks) {
+  // Send a test command
+  reset_for(transmit_command_no_callbacks);
+  data_to_receive =
+      manufacture_packet(MSG_STACK_TO_HC_HCI_CMD, command_sample_data);
+  hci->transmit_command(data_to_receive, NULL, NULL, NULL);
+
+  flush_thread(internal_thread);
+  EXPECT_CALL_COUNT(hal_transmit_data, 1);
+  EXPECT_CALL_COUNT(btsnoop_capture, 1);
+  EXPECT_CALL_COUNT(low_power_transmit_done, 1);
+  EXPECT_CALL_COUNT(low_power_wake_assert, 1);
+
+  // Send a response
+  command_opcode_t opcode = *((uint16_t*)command_sample_data);
+  data_to_receive = manufacture_command_complete(opcode);
+
+  hal_callbacks->data_ready(DATA_TYPE_EVENT);
+  EXPECT_CALL_COUNT(hal_packet_finished, 1);
+  EXPECT_CALL_COUNT(btsnoop_capture, 2);
+
+  osi_free(data_to_receive);
+}
+
+TEST_F(HciLayerTest, test_transmit_command_command_status) {
+  // Send a test command
+  reset_for(transmit_command_command_status);
+  data_to_receive =
+      manufacture_packet(MSG_STACK_TO_HC_HCI_CMD, command_sample_data);
+  hci->transmit_command(data_to_receive, command_complete_callback,
+                        command_status_callback, NULL);
+
+  flush_thread(internal_thread);
+  EXPECT_CALL_COUNT(hal_transmit_data, 1);
+  EXPECT_CALL_COUNT(btsnoop_capture, 1);
+  EXPECT_CALL_COUNT(low_power_transmit_done, 1);
+  EXPECT_CALL_COUNT(low_power_wake_assert, 1);
+
+  command_opcode_t opcode = *((uint16_t*)command_sample_data);
+
+  // Send status event response
+  data_to_receive = manufacture_command_status(opcode);
+
+  hal_callbacks->data_ready(DATA_TYPE_EVENT);
+  EXPECT_CALL_COUNT(hal_packet_finished, 1);
+  EXPECT_CALL_COUNT(btsnoop_capture, 2);
+  EXPECT_CALL_COUNT(command_status_callback, 1);
+
+  osi_free(data_to_receive);
+}
+
+TEST_F(HciLayerTest, test_transmit_command_command_complete) {
+  // Send a test command
+  reset_for(transmit_command_command_complete);
+  data_to_receive =
+      manufacture_packet(MSG_STACK_TO_HC_HCI_CMD, command_sample_data);
+  hci->transmit_command(data_to_receive, command_complete_callback,
+                        command_status_callback, NULL);
+
+  flush_thread(internal_thread);
+  EXPECT_CALL_COUNT(hal_transmit_data, 1);
+  EXPECT_CALL_COUNT(btsnoop_capture, 1);
+  EXPECT_CALL_COUNT(low_power_transmit_done, 1);
+  EXPECT_CALL_COUNT(low_power_wake_assert, 1);
+
+  command_opcode_t opcode = *((uint16_t*)command_sample_data);
+
+  // Send complete event response
+  data_to_receive = manufacture_command_complete(opcode);
+
+  hal_callbacks->data_ready(DATA_TYPE_EVENT);
+  EXPECT_CALL_COUNT(hal_packet_finished, 1);
+  EXPECT_CALL_COUNT(btsnoop_capture, 2);
+  EXPECT_CALL_COUNT(command_complete_callback, 1);
+
+  osi_free(data_to_receive);
+}
+
+TEST_F(HciLayerTest, test_ignoring_packets) {
+  reset_for(ignoring_packets_ignored_packet);
+  data_to_receive = manufacture_packet(MSG_HC_TO_STACK_HCI_EVT, unignored_data);
+
+  hal_callbacks->data_ready(DATA_TYPE_EVENT);
+  EXPECT_CALL_COUNT(buffer_allocator_alloc, 1);
+  EXPECT_CALL_COUNT(hal_packet_finished, 1);
+  EXPECT_CALL_COUNT(btsnoop_capture, 0);
+  osi_free(data_to_receive);
+
+  reset_for(ignoring_packets_following_packet);
+  data_to_receive = manufacture_packet(MSG_STACK_TO_HC_HCI_ACL, ignored_data);
+
+  hal_callbacks->data_ready(DATA_TYPE_ACL);
+  EXPECT_CALL_COUNT(buffer_allocator_alloc, 1);
+  EXPECT_CALL_COUNT(hal_packet_finished, 1);
+  EXPECT_CALL_COUNT(btsnoop_capture, 1);
+  osi_free(data_to_receive);
+}
+
+// TODO(zachoverflow): test post-reassembly better, stub out fragmenter instead
+// of using it
diff --git a/bt/hci/test/low_power_manager_test.cc b/bt/hci/test/low_power_manager_test.cc
new file mode 100644
index 0000000..cef6ce0
--- /dev/null
+++ b/bt/hci/test/low_power_manager_test.cc
@@ -0,0 +1,136 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "AlarmTestHarness.h"
+
+#include <stdint.h>
+
+#include "low_power_manager.h"
+#include "osi/include/osi.h"
+#include "osi/include/semaphore.h"
+#include "osi/include/thread.h"
+#include "test_stubs.h"
+#include "vendor.h"
+
+DECLARE_TEST_MODES(init, cleanup, enable_disable);
+
+static const low_power_manager_t* manager;
+static thread_t* thread;
+static semaphore_t* done;
+
+static vendor_cb low_power_state_callback;
+
+static void flush_work_queue_item(UNUSED_ATTR void* context) {
+  semaphore_post(done);
+}
+
+STUB_FUNCTION(int, vendor_send_command, (vendor_opcode_t opcode, void* param))
+DURING(enable_disable) AT_CALL(0) {
+  EXPECT_EQ(VENDOR_GET_LPM_IDLE_TIMEOUT, opcode);
+  *((uint32_t*)param) = 100;
+  return 0;
+}
+
+UNEXPECTED_CALL;
+return 0;
+}
+
+STUB_FUNCTION(int, vendor_send_async_command,
+              (vendor_async_opcode_t opcode, void* param))
+DURING(enable_disable) {
+  AT_CALL(0) {
+    EXPECT_EQ(VENDOR_SET_LPM_MODE, opcode);
+    EXPECT_EQ(BT_VND_LPM_ENABLE, *(uint8_t*)param);
+    low_power_state_callback(true);
+    thread_post(thread, flush_work_queue_item, NULL);
+    return 0;
+  }
+  AT_CALL(1) {
+    EXPECT_EQ(VENDOR_SET_LPM_MODE, opcode);
+    EXPECT_EQ(BT_VND_LPM_DISABLE, *(uint8_t*)param);
+    low_power_state_callback(true);
+    thread_post(thread, flush_work_queue_item, NULL);
+    return 0;
+  }
+}
+
+UNEXPECTED_CALL;
+return 0;
+}
+
+STUB_FUNCTION(void, vendor_set_callback,
+              (vendor_async_opcode_t opcode, vendor_cb callback))
+DURING(init) AT_CALL(0) {
+  EXPECT_EQ(VENDOR_SET_LPM_MODE, opcode);
+  low_power_state_callback = callback;
+  return;
+}
+
+UNEXPECTED_CALL;
+}
+
+static void reset_for(TEST_MODES_T next) {
+  RESET_CALL_COUNT(vendor_send_command);
+  RESET_CALL_COUNT(vendor_send_async_command);
+  RESET_CALL_COUNT(vendor_set_callback);
+  CURRENT_TEST_MODE = next;
+}
+
+class LowPowerManagerTest : public AlarmTestHarness {
+ protected:
+  virtual void SetUp() {
+    AlarmTestHarness::SetUp();
+    low_power_state_callback = NULL;
+    vendor.send_command = vendor_send_command;
+    vendor.send_async_command = vendor_send_async_command;
+    vendor.set_callback = vendor_set_callback;
+    manager = low_power_manager_get_test_interface(&vendor);
+    thread = thread_new("test_thread");
+    done = semaphore_new(0);
+
+    reset_for(init);
+    manager->init(thread);
+
+    EXPECT_CALL_COUNT(vendor_set_callback, 1);
+  }
+
+  virtual void TearDown() {
+    reset_for(cleanup);
+    manager->cleanup();
+
+    semaphore_free(done);
+    thread_free(thread);
+    AlarmTestHarness::TearDown();
+  }
+
+  vendor_t vendor;
+};
+
+TEST_F(LowPowerManagerTest, test_enable_disable) {
+  reset_for(enable_disable);
+  manager->post_command(LPM_ENABLE);
+  semaphore_wait(done);
+
+  manager->post_command(LPM_DISABLE);
+  semaphore_wait(done);
+
+  EXPECT_CALL_COUNT(vendor_send_command, 1);
+  EXPECT_CALL_COUNT(vendor_send_async_command, 2);
+}
diff --git a/bt/hci/test/packet_fragmenter_test.cc b/bt/hci/test/packet_fragmenter_test.cc
new file mode 100644
index 0000000..29c130d
--- /dev/null
+++ b/bt/hci/test/packet_fragmenter_test.cc
@@ -0,0 +1,396 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "AllocationTestHarness.h"
+
+#include <stdint.h>
+
+#include "device/include/controller.h"
+#include "hci_internals.h"
+#include "osi/include/allocator.h"
+#include "osi/include/osi.h"
+#include "packet_fragmenter.h"
+#include "test_stubs.h"
+
+DECLARE_TEST_MODES(init, set_data_sizes, no_fragmentation, fragmentation,
+                   ble_no_fragmentation, ble_fragmentation,
+                   non_acl_passthrough_fragmentation, no_reassembly, reassembly,
+                   non_acl_passthrough_reassembly);
+
+#define LOCAL_BLE_CONTROLLER_ID 1
+
+static const char* sample_data =
+    "At this point they came in sight of thirty forty windmills that there are "
+    "on plain, and "
+    "as soon as Don Quixote saw them he said to his squire, \"Fortune is "
+    "arranging matters "
+    "for us better than we could have shaped our desires ourselves, for look "
+    "there, friend "
+    "Sancho Panza, where thirty or more monstrous giants present themselves, "
+    "all of whom I "
+    "mean to engage in battle and slay, and with whose spoils we shall begin "
+    "to make our "
+    "fortunes; for this is righteous warfare, and it is God's good service to "
+    "sweep so evil "
+    "a breed from off the face of the earth.\"";
+
+static const char* small_sample_data = "\"What giants?\" said Sancho Panza.";
+static const uint16_t test_handle_start = (0x1992 & 0xCFFF) | 0x2000;
+static const uint16_t test_handle_continuation = (0x1992 & 0xCFFF) | 0x1000;
+static int packet_index;
+static unsigned int data_size_sum;
+
+static const packet_fragmenter_t* fragmenter;
+
+static BT_HDR* manufacture_packet_for_fragmentation(uint16_t event,
+                                                    const char* data) {
+  uint16_t data_length = strlen(data);
+  uint16_t size = data_length;
+  if (event == MSG_STACK_TO_HC_HCI_ACL) {
+    size += 4;  // 2 for the handle, 2 for the length;
+  }
+
+  BT_HDR* packet = (BT_HDR*)osi_malloc(size + sizeof(BT_HDR));
+  packet->len = size;
+  packet->offset = 0;
+  packet->event = event;
+  packet->layer_specific = 0;
+  uint8_t* packet_data = packet->data;
+
+  if (event == MSG_STACK_TO_HC_HCI_ACL) {
+    UINT16_TO_STREAM(packet_data, test_handle_start);
+    UINT16_TO_STREAM(packet_data, data_length);
+  }
+
+  memcpy(packet_data, data, data_length);
+  return packet;
+}
+
+static void expect_packet_fragmented(uint16_t event, int max_acl_data_size,
+                                     BT_HDR* packet, const char* expected_data,
+                                     bool send_complete) {
+  uint8_t* data = packet->data + packet->offset;
+  int expected_data_offset;
+  int length_to_check;
+
+  if (event == MSG_STACK_TO_HC_HCI_ACL) {
+    uint16_t handle;
+    uint16_t length;
+    STREAM_TO_UINT16(handle, data);
+    STREAM_TO_UINT16(length, data);
+
+    if (packet_index == 0)
+      EXPECT_EQ(test_handle_start, handle);
+    else
+      EXPECT_EQ(test_handle_continuation, handle);
+
+    int length_remaining = strlen(expected_data) - data_size_sum;
+    int packet_data_length = packet->len - HCI_ACL_PREAMBLE_SIZE;
+    EXPECT_EQ(packet_data_length, length);
+
+    if (length_remaining > max_acl_data_size)
+      EXPECT_EQ(max_acl_data_size, packet_data_length);
+
+    length_to_check = packet_data_length;
+    expected_data_offset = packet_index * max_acl_data_size;
+    packet_index++;
+  } else {
+    length_to_check = strlen(expected_data);
+    expected_data_offset = 0;
+  }
+
+  for (int i = 0; i < length_to_check; i++) {
+    EXPECT_EQ(expected_data[expected_data_offset + i], data[i]);
+    data_size_sum++;
+  }
+
+  if (event == MSG_STACK_TO_HC_HCI_ACL)
+    EXPECT_TRUE(send_complete == (data_size_sum == strlen(expected_data)));
+
+  if (send_complete) osi_free(packet);
+}
+
+static void manufacture_packet_and_then_reassemble(uint16_t event,
+                                                   uint16_t acl_size,
+                                                   const char* data) {
+  uint16_t data_length = strlen(data);
+
+  if (event == MSG_HC_TO_STACK_HCI_ACL) {
+    uint16_t total_length = data_length + 2;  // 2 for l2cap length;
+    uint16_t length_sent = 0;
+    uint16_t l2cap_length = data_length - 2;  // l2cap length field, 2 for the
+                                              // pretend channel id borrowed
+                                              // from the data
+
+    do {
+      int length_to_send = (length_sent + (acl_size - 4) < total_length)
+                               ? (acl_size - 4)
+                               : (total_length - length_sent);
+      BT_HDR* packet = (BT_HDR*)osi_malloc(length_to_send + 4 + sizeof(BT_HDR));
+      packet->len = length_to_send + 4;
+      packet->offset = 0;
+      packet->event = event;
+      packet->layer_specific = 0;
+
+      uint8_t* packet_data = packet->data;
+      if (length_sent == 0) {  // first packet
+        UINT16_TO_STREAM(packet_data, test_handle_start);
+        UINT16_TO_STREAM(packet_data, length_to_send);
+        UINT16_TO_STREAM(packet_data, l2cap_length);
+        memcpy(packet_data, data, length_to_send - 2);
+      } else {
+        UINT16_TO_STREAM(packet_data, test_handle_continuation);
+        UINT16_TO_STREAM(packet_data, length_to_send);
+        memcpy(packet_data, data + length_sent - 2, length_to_send);
+      }
+
+      length_sent += length_to_send;
+      fragmenter->reassemble_and_dispatch(packet);
+    } while (length_sent < total_length);
+  } else {
+    BT_HDR* packet = (BT_HDR*)osi_malloc(data_length + sizeof(BT_HDR));
+    packet->len = data_length;
+    packet->offset = 0;
+    packet->event = event;
+    packet->layer_specific = 0;
+    memcpy(packet->data, data, data_length);
+
+    fragmenter->reassemble_and_dispatch(packet);
+  }
+}
+
+static void expect_packet_reassembled(uint16_t event, BT_HDR* packet,
+                                      const char* expected_data) {
+  uint16_t expected_data_length = strlen(expected_data);
+  uint8_t* data = packet->data + packet->offset;
+
+  if (event == MSG_HC_TO_STACK_HCI_ACL) {
+    uint16_t handle;
+    uint16_t length;
+    uint16_t l2cap_length;
+    STREAM_TO_UINT16(handle, data);
+    STREAM_TO_UINT16(length, data);
+    STREAM_TO_UINT16(l2cap_length, data);
+
+    EXPECT_EQ(test_handle_start, handle);
+    EXPECT_EQ(expected_data_length + 2, length);
+    EXPECT_EQ(expected_data_length - 2,
+              l2cap_length);  // -2 for the pretend channel id
+  }
+
+  for (int i = 0; i < expected_data_length; i++) {
+    EXPECT_EQ(expected_data[i], data[i]);
+    data_size_sum++;
+  }
+
+  osi_free(packet);
+}
+
+STUB_FUNCTION(void, fragmented_callback, (BT_HDR * packet, bool send_complete))
+DURING(no_fragmentation) AT_CALL(0) {
+  expect_packet_fragmented(MSG_STACK_TO_HC_HCI_ACL, 42, packet,
+                           small_sample_data, send_complete);
+  return;
+}
+
+DURING(fragmentation) {
+  expect_packet_fragmented(MSG_STACK_TO_HC_HCI_ACL, 10, packet, sample_data,
+                           send_complete);
+  return;
+}
+
+DURING(ble_no_fragmentation) AT_CALL(0) {
+  expect_packet_fragmented(MSG_STACK_TO_HC_HCI_ACL, 42, packet,
+                           small_sample_data, send_complete);
+  return;
+}
+
+DURING(ble_fragmentation) {
+  expect_packet_fragmented(MSG_STACK_TO_HC_HCI_ACL, 10, packet, sample_data,
+                           send_complete);
+  return;
+}
+
+DURING(non_acl_passthrough_fragmentation) AT_CALL(0) {
+  expect_packet_fragmented(MSG_STACK_TO_HC_HCI_CMD, 10, packet, sample_data,
+                           send_complete);
+  return;
+}
+
+UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, reassembled_callback, (BT_HDR * packet))
+DURING(no_reassembly) AT_CALL(0) {
+  expect_packet_reassembled(MSG_HC_TO_STACK_HCI_ACL, packet, small_sample_data);
+  return;
+}
+
+DURING(reassembly) AT_CALL(0) {
+  expect_packet_reassembled(MSG_HC_TO_STACK_HCI_ACL, packet, sample_data);
+  return;
+}
+
+DURING(non_acl_passthrough_reassembly) AT_CALL(0) {
+  expect_packet_reassembled(MSG_HC_TO_STACK_HCI_EVT, packet, sample_data);
+  return;
+}
+
+UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, transmit_finished_callback,
+              (UNUSED_ATTR BT_HDR * packet,
+               UNUSED_ATTR bool sent_all_fragments))
+UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(uint16_t, get_acl_data_size_classic, (void))
+DURING(no_fragmentation, non_acl_passthrough_fragmentation, no_reassembly)
+return 42;
+DURING(fragmentation) return 10;
+DURING(no_reassembly) return 1337;
+
+UNEXPECTED_CALL;
+return 0;
+}
+
+STUB_FUNCTION(uint16_t, get_acl_data_size_ble, (void))
+DURING(ble_no_fragmentation) return 42;
+DURING(ble_fragmentation) return 10;
+
+UNEXPECTED_CALL;
+return 0;
+}
+
+static void reset_for(TEST_MODES_T next) {
+  RESET_CALL_COUNT(fragmented_callback);
+  RESET_CALL_COUNT(reassembled_callback);
+  RESET_CALL_COUNT(transmit_finished_callback);
+  RESET_CALL_COUNT(get_acl_data_size_classic);
+  RESET_CALL_COUNT(get_acl_data_size_ble);
+  CURRENT_TEST_MODE = next;
+}
+
+class PacketFragmenterTest : public AllocationTestHarness {
+ protected:
+  virtual void SetUp() {
+    AllocationTestHarness::SetUp();
+    fragmenter =
+        packet_fragmenter_get_test_interface(&controller, &allocator_malloc);
+
+    packet_index = 0;
+    data_size_sum = 0;
+
+    callbacks.fragmented = fragmented_callback;
+    callbacks.reassembled = reassembled_callback;
+    callbacks.transmit_finished = transmit_finished_callback;
+    controller.get_acl_data_size_classic = get_acl_data_size_classic;
+    controller.get_acl_data_size_ble = get_acl_data_size_ble;
+
+    reset_for(init);
+    fragmenter->init(&callbacks);
+  }
+
+  virtual void TearDown() {
+    fragmenter->cleanup();
+    AllocationTestHarness::TearDown();
+  }
+
+  controller_t controller;
+  packet_fragmenter_callbacks_t callbacks;
+};
+
+TEST_F(PacketFragmenterTest, test_no_fragment_necessary) {
+  reset_for(no_fragmentation);
+  BT_HDR* packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_ACL,
+                                                        small_sample_data);
+  fragmenter->fragment_and_dispatch(packet);
+
+  EXPECT_EQ(strlen(small_sample_data), data_size_sum);
+  EXPECT_CALL_COUNT(fragmented_callback, 1);
+}
+
+TEST_F(PacketFragmenterTest, test_fragment_necessary) {
+  reset_for(fragmentation);
+  BT_HDR* packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_ACL,
+                                                        sample_data);
+  fragmenter->fragment_and_dispatch(packet);
+
+  EXPECT_EQ(strlen(sample_data), data_size_sum);
+}
+
+TEST_F(PacketFragmenterTest, test_ble_no_fragment_necessary) {
+  reset_for(ble_no_fragmentation);
+  BT_HDR* packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_ACL,
+                                                        small_sample_data);
+  packet->event |= LOCAL_BLE_CONTROLLER_ID;
+  fragmenter->fragment_and_dispatch(packet);
+
+  EXPECT_EQ(strlen(small_sample_data), data_size_sum);
+  EXPECT_CALL_COUNT(fragmented_callback, 1);
+}
+
+TEST_F(PacketFragmenterTest, test_ble_fragment_necessary) {
+  reset_for(ble_fragmentation);
+  BT_HDR* packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_ACL,
+                                                        sample_data);
+  packet->event |= LOCAL_BLE_CONTROLLER_ID;
+  fragmenter->fragment_and_dispatch(packet);
+
+  EXPECT_EQ(strlen(sample_data), data_size_sum);
+}
+
+TEST_F(PacketFragmenterTest, test_non_acl_passthrough_fragmentation) {
+  reset_for(non_acl_passthrough_fragmentation);
+  BT_HDR* packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_CMD,
+                                                        sample_data);
+  fragmenter->fragment_and_dispatch(packet);
+
+  EXPECT_EQ(strlen(sample_data), data_size_sum);
+  EXPECT_CALL_COUNT(fragmented_callback, 1);
+}
+
+TEST_F(PacketFragmenterTest, test_no_reassembly_necessary) {
+  reset_for(no_reassembly);
+  manufacture_packet_and_then_reassemble(MSG_HC_TO_STACK_HCI_ACL, 1337,
+                                         small_sample_data);
+
+  EXPECT_EQ(strlen(small_sample_data), data_size_sum);
+  EXPECT_CALL_COUNT(reassembled_callback, 1);
+}
+
+TEST_F(PacketFragmenterTest, test_reassembly_necessary) {
+  reset_for(reassembly);
+  manufacture_packet_and_then_reassemble(MSG_HC_TO_STACK_HCI_ACL, 42,
+                                         sample_data);
+
+  EXPECT_EQ(strlen(sample_data), data_size_sum);
+  EXPECT_CALL_COUNT(reassembled_callback, 1);
+}
+
+TEST_F(PacketFragmenterTest, test_non_acl_passthrough_reasseembly) {
+  reset_for(non_acl_passthrough_reassembly);
+  manufacture_packet_and_then_reassemble(MSG_HC_TO_STACK_HCI_EVT, 42,
+                                         sample_data);
+
+  EXPECT_EQ(strlen(sample_data), data_size_sum);
+  EXPECT_CALL_COUNT(reassembled_callback, 1);
+}
diff --git a/bt/include/bt_common.h b/bt/include/bt_common.h
new file mode 100644
index 0000000..9680792
--- /dev/null
+++ b/bt/include/bt_common.h
@@ -0,0 +1,24 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 "bt_target.h"
+#include "bt_types.h"
+#include "osi/include/allocator.h"
+#include "osi/include/compat.h"
diff --git a/bt/include/bt_target.h b/bt/include/bt_target.h
new file mode 100644
index 0000000..b6837bb
--- /dev/null
+++ b/bt/include/bt_target.h
@@ -0,0 +1,1558 @@
+/******************************************************************************
+ *
+ *  Copyright (c) 2014 The Android Open Source Project
+ *  Copyright (C) 1999-2016 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.
+ *
+ ******************************************************************************/
+
+#ifndef BT_TARGET_H
+#define BT_TARGET_H
+
+#ifndef BUILDCFG
+#define BUILDCFG
+#endif
+
+#if !defined(HAS_BDROID_BUILDCFG) && !defined(HAS_NO_BDROID_BUILDCFG)
+#error \
+    "An Android.mk file did not include bdroid_CFLAGS and possibly not bdroid_C_INCLUDES"
+#endif
+
+#ifdef HAS_BDROID_BUILDCFG
+#include "bdroid_buildcfg.h"
+#endif
+
+#include "bt_types.h" /* This must be defined AFTER buildcfg.h */
+
+//------------------Added from bdroid_buildcfg.h---------------------
+#ifndef L2CAP_EXTFEA_SUPPORTED_MASK
+#define L2CAP_EXTFEA_SUPPORTED_MASK                                            \
+  (L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE | L2CAP_EXTFEA_NO_CRC | \
+   L2CAP_EXTFEA_FIXED_CHNLS)
+#endif
+
+#ifndef BTUI_OPS_FORMATS
+#define BTUI_OPS_FORMATS (BTA_OP_VCARD21_MASK | BTA_OP_ANY_MASK)
+#endif
+
+#ifndef BTA_RFC_MTU_SIZE
+#define BTA_RFC_MTU_SIZE \
+  (L2CAP_MTU_SIZE - L2CAP_MIN_OFFSET - RFCOMM_DATA_OVERHEAD)
+#endif
+
+#ifndef BTA_INCLUDED
+#define BTA_INCLUDED TRUE
+#endif
+
+#ifndef BTA_PAN_INCLUDED
+#define BTA_PAN_INCLUDED TRUE
+#endif
+
+#ifndef BTA_HH_INCLUDED
+#define BTA_HH_INCLUDED TRUE
+#endif
+
+#ifndef BTA_HH_ROLE
+#define BTA_HH_ROLE BTA_MASTER_ROLE_PREF
+#endif
+
+#ifndef BTA_HH_LE_INCLUDED
+#define BTA_HH_LE_INCLUDED TRUE
+#endif
+
+#ifndef BTA_AR_INCLUDED
+#define BTA_AR_INCLUDED TRUE
+#endif
+
+#ifndef BTA_GATT_INCLUDED
+#define BTA_GATT_INCLUDED TRUE
+#endif
+
+#ifndef BTA_AV_SINK_INCLUDED
+#define BTA_AV_SINK_INCLUDED FALSE
+#endif
+
+#ifndef BTA_DISABLE_DELAY
+#define BTA_DISABLE_DELAY 200 /* in milliseconds */
+#endif
+
+#ifndef SBC_FOR_EMBEDDED_LINUX
+#define SBC_FOR_EMBEDDED_LINUX TRUE
+#endif
+
+#ifndef AVDT_VERSION
+#define AVDT_VERSION 0x0102
+#endif
+
+#ifndef BTA_AG_AT_MAX_LEN
+#define BTA_AG_AT_MAX_LEN 512
+#endif
+
+#ifndef BTA_AVRCP_FF_RW_SUPPORT
+#define BTA_AVRCP_FF_RW_SUPPORT TRUE
+#endif
+
+#ifndef BTA_AG_SCO_PKT_TYPES
+#define BTA_AG_SCO_PKT_TYPES                                           \
+  (BTM_SCO_LINK_ONLY_MASK | BTM_SCO_PKT_TYPES_MASK_EV3 |               \
+   BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | \
+   BTM_SCO_PKT_TYPES_MASK_NO_3_EV5)
+#endif
+
+#ifndef BTA_AV_RET_TOUT
+#define BTA_AV_RET_TOUT 15
+#endif
+
+/* TRUE to use SCMS-T content protection */
+#ifndef BTA_AV_CO_CP_SCMS_T
+#define BTA_AV_CO_CP_SCMS_T FALSE
+#endif
+
+#ifndef BTIF_A2DP_SRC_SAMPLING_RATE
+#define BTIF_A2DP_SRC_SAMPLING_RATE 44100
+#endif
+
+#ifndef BTIF_A2DP_SRC_BIT_DEPTH
+#define BTIF_A2DP_SRC_BIT_DEPTH 16
+#endif
+
+#ifndef BTIF_A2DP_SRC_NUM_CHANNELS
+#define BTIF_A2DP_SRC_NUM_CHANNELS 2
+#endif
+
+/* This feature is used to enable interleaved scan */
+#ifndef BTA_HOST_INTERLEAVE_SEARCH
+#define BTA_HOST_INTERLEAVE_SEARCH FALSE
+#endif
+
+#ifndef BT_TRACE_VERBOSE
+#define BT_TRACE_VERBOSE FALSE
+#endif
+
+#ifndef BTA_DM_SDP_DB_SIZE
+#define BTA_DM_SDP_DB_SIZE 8000
+#endif
+
+#ifndef HL_INCLUDED
+#define HL_INCLUDED TRUE
+#endif
+
+#ifndef AG_VOICE_SETTINGS
+#define AG_VOICE_SETTINGS HCI_DEFAULT_VOICE_SETTINGS
+#endif
+
+#ifndef BTIF_DM_OOB_TEST
+#define BTIF_DM_OOB_TEST TRUE
+#endif
+
+// How long to wait before activating sniff mode after entering the
+// idle state for FTS, OPS connections
+#ifndef BTA_FTS_OPS_IDLE_TO_SNIFF_DELAY_MS
+#define BTA_FTS_OPS_IDLE_TO_SNIFF_DELAY_MS 7000
+#endif
+
+//------------------End added from bdroid_buildcfg.h---------------------
+
+/******************************************************************************
+ *
+ * Buffer sizes
+ *
+ *****************************************************************************/
+
+#ifndef BT_DEFAULT_BUFFER_SIZE
+#define BT_DEFAULT_BUFFER_SIZE (4096 + 16)
+#endif
+
+#ifndef BT_SMALL_BUFFER_SIZE
+#define BT_SMALL_BUFFER_SIZE 660
+#endif
+
+/* Receives HCI events from the lower-layer. */
+#ifndef HCI_CMD_BUF_SIZE
+#define HCI_CMD_BUF_SIZE BT_SMALL_BUFFER_SIZE
+#endif
+
+/* Sends SDP data packets. */
+#ifndef SDP_DATA_BUF_SIZE
+#define SDP_DATA_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* Sends RFCOMM command packets. */
+#ifndef RFCOMM_CMD_BUF_SIZE
+#define RFCOMM_CMD_BUF_SIZE BT_SMALL_BUFFER_SIZE
+#endif
+
+/* Sends RFCOMM data packets. */
+#ifndef RFCOMM_DATA_BUF_SIZE
+#define RFCOMM_DATA_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* Sends L2CAP packets to the peer and HCI messages to the controller. */
+#ifndef L2CAP_CMD_BUF_SIZE
+#define L2CAP_CMD_BUF_SIZE BT_SMALL_BUFFER_SIZE
+#endif
+
+#ifndef L2CAP_USER_TX_BUF_SIZE
+#define L2CAP_USER_TX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+#ifndef L2CAP_USER_RX_BUF_SIZE
+#define L2CAP_USER_RX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* Sends L2CAP segmented packets in ERTM mode */
+#ifndef L2CAP_FCR_TX_BUF_SIZE
+#define L2CAP_FCR_TX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* Receives L2CAP segmented packets in ERTM mode */
+#ifndef L2CAP_FCR_RX_BUF_SIZE
+#define L2CAP_FCR_RX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+#ifndef L2CAP_FCR_ERTM_BUF_SIZE
+#define L2CAP_FCR_ERTM_BUF_SIZE (10240 + 24)
+#endif
+
+/* Number of ACL buffers to assign to LE */
+/*
+ * TODO: Do we need this?
+ * It was used when the HCI buffers were shared with BR/EDR.
+ */
+#ifndef L2C_DEF_NUM_BLE_BUF_SHARED
+#define L2C_DEF_NUM_BLE_BUF_SHARED 1
+#endif
+
+/* Used by BTM when it sends HCI commands to the controller. */
+#ifndef BTM_CMD_BUF_SIZE
+#define BTM_CMD_BUF_SIZE BT_SMALL_BUFFER_SIZE
+#endif
+
+#ifndef OBX_LRG_DATA_BUF_SIZE
+#define OBX_LRG_DATA_BUF_SIZE (8080 + 26)
+#endif
+
+/* Used to send data to L2CAP. */
+#ifndef GAP_DATA_BUF_SIZE
+#define GAP_DATA_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* BNEP data and protocol messages. */
+#ifndef BNEP_BUF_SIZE
+#define BNEP_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* AVDTP buffer size for protocol messages */
+#ifndef AVDT_CMD_BUF_SIZE
+#define AVDT_CMD_BUF_SIZE BT_SMALL_BUFFER_SIZE
+#endif
+
+#ifndef PAN_BUF_SIZE
+#define PAN_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* Maximum number of buffers to allocate for PAN */
+#ifndef PAN_BUF_MAX
+#define PAN_BUF_MAX 100
+#endif
+
+/* AVCTP buffer size for protocol messages */
+#ifndef AVCT_CMD_BUF_SIZE
+#define AVCT_CMD_BUF_SIZE 288
+#endif
+
+/* AVRCP buffer size for protocol messages */
+#ifndef AVRC_CMD_BUF_SIZE
+#define AVRC_CMD_BUF_SIZE 288
+#endif
+
+/* AVRCP Metadata buffer size for protocol messages */
+#ifndef AVRC_META_CMD_BUF_SIZE
+#define AVRC_META_CMD_BUF_SIZE BT_SMALL_BUFFER_SIZE
+#endif
+
+#ifndef BTA_HL_LRG_DATA_BUF_SIZE
+#define BTA_HL_LRG_DATA_BUF_SIZE (10240 + 24)
+#endif
+
+/* GATT Server Database buffer size */
+#ifndef GATT_DB_BUF_SIZE
+#define GATT_DB_BUF_SIZE 128
+#endif
+
+/* GATT Data sending buffer size */
+#ifndef GATT_DATA_BUF_SIZE
+#define GATT_DATA_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/******************************************************************************
+ *
+ * BTM
+ *
+ *****************************************************************************/
+
+/* Cancel Inquiry on incoming SSP */
+#ifndef BTM_NO_SSP_ON_INQUIRY
+#define BTM_NO_SSP_ON_INQUIRY FALSE
+#endif
+
+/* Includes SCO if TRUE */
+#ifndef BTM_SCO_INCLUDED
+#define BTM_SCO_INCLUDED TRUE /* TRUE includes SCO code */
+#endif
+
+/* Includes SCO if TRUE */
+#ifndef BTM_SCO_HCI_INCLUDED
+#define BTM_SCO_HCI_INCLUDED FALSE /* TRUE includes SCO over HCI code */
+#endif
+
+/* Includes WBS if TRUE */
+#ifndef BTM_WBS_INCLUDED
+#define BTM_WBS_INCLUDED FALSE /* TRUE includes WBS code */
+#endif
+
+/*  This is used to work around a controller bug that doesn't like Disconnect
+ *  issued while there is a role switch in progress
+*/
+#ifndef BTM_DISC_DURING_RS
+#define BTM_DISC_DURING_RS TRUE
+#endif
+
+/**************************
+ * Initial SCO TX credit
+ ************************/
+/* max TX SCO data packet size */
+#ifndef BTM_SCO_DATA_SIZE_MAX
+#define BTM_SCO_DATA_SIZE_MAX 240
+#endif
+
+/* The size in bytes of the BTM inquiry database. */
+#ifndef BTM_INQ_DB_SIZE
+#define BTM_INQ_DB_SIZE 40
+#endif
+
+/* The default scan mode */
+#ifndef BTM_DEFAULT_SCAN_TYPE
+#define BTM_DEFAULT_SCAN_TYPE BTM_SCAN_TYPE_INTERLACED
+#endif
+
+/* Should connections to unknown devices be allowed when not discoverable? */
+#ifndef BTM_ALLOW_CONN_IF_NONDISCOVER
+#define BTM_ALLOW_CONN_IF_NONDISCOVER TRUE
+#endif
+
+/* Sets the Page_Scan_Window:  the length of time that the device is performing
+ * a page scan. */
+#ifndef BTM_DEFAULT_CONN_WINDOW
+#define BTM_DEFAULT_CONN_WINDOW 0x0012
+#endif
+
+/* Sets the Page_Scan_Activity:  the interval between the start of two
+ * consecutive page scans. */
+#ifndef BTM_DEFAULT_CONN_INTERVAL
+#define BTM_DEFAULT_CONN_INTERVAL 0x0800
+#endif
+
+/* When automatic inquiry scan is enabled, this sets the inquiry scan window. */
+#ifndef BTM_DEFAULT_DISC_WINDOW
+#define BTM_DEFAULT_DISC_WINDOW 0x0012
+#endif
+
+/* When automatic inquiry scan is enabled, this sets the inquiry scan interval.
+ */
+#ifndef BTM_DEFAULT_DISC_INTERVAL
+#define BTM_DEFAULT_DISC_INTERVAL 0x0800
+#endif
+
+/* Default class of device
+* {SERVICE_CLASS, MAJOR_CLASS, MINOR_CLASS}
+*
+* SERVICE_CLASS:0x5A (Bit17 -Networking,Bit19 - Capturing,Bit20 -Object
+* Transfer,Bit22 -Telephony)
+* MAJOR_CLASS:0x02 - PHONE
+* MINOR_CLASS:0x0C - SMART_PHONE
+*
+*/
+#ifndef BTA_DM_COD
+#define BTA_DM_COD \
+  { 0x5A, 0x02, 0x0C }
+#endif
+
+/* The number of SCO links. */
+#ifndef BTM_MAX_SCO_LINKS
+#define BTM_MAX_SCO_LINKS 3
+#endif
+
+/* The preferred type of SCO links (2-eSCO, 0-SCO). */
+#ifndef BTM_DEFAULT_SCO_MODE
+#define BTM_DEFAULT_SCO_MODE 2
+#endif
+
+/* The number of security records for peer devices. */
+#ifndef BTM_SEC_MAX_DEVICE_RECORDS
+#define BTM_SEC_MAX_DEVICE_RECORDS 100
+#endif
+
+/* The number of security records for services. */
+#ifndef BTM_SEC_MAX_SERVICE_RECORDS
+#define BTM_SEC_MAX_SERVICE_RECORDS 32
+#endif
+
+/* If True, force a retrieval of remote device name for each bond in case it's
+ * changed */
+#ifndef BTM_SEC_FORCE_RNR_FOR_DBOND
+#define BTM_SEC_FORCE_RNR_FOR_DBOND FALSE
+#endif
+
+/* Maximum device name length used in btm database. */
+#ifndef BTM_MAX_REM_BD_NAME_LEN
+#define BTM_MAX_REM_BD_NAME_LEN 248
+#endif
+
+/* Maximum local device name length stored btm database */
+#ifndef BTM_MAX_LOC_BD_NAME_LEN
+#define BTM_MAX_LOC_BD_NAME_LEN 248
+#endif
+
+/* Fixed Default String. When this is defined as null string, the device's
+ * product model name is used as the default local name.
+ */
+#ifndef BTM_DEF_LOCAL_NAME
+#define BTM_DEF_LOCAL_NAME ""
+#endif
+
+/* Maximum service name stored with security authorization (0 if not needed) */
+#ifndef BTM_SEC_SERVICE_NAME_LEN
+#define BTM_SEC_SERVICE_NAME_LEN BT_MAX_SERVICE_NAME_LEN
+#endif
+
+/* Maximum length of the service name. */
+#ifndef BT_MAX_SERVICE_NAME_LEN
+#define BT_MAX_SERVICE_NAME_LEN 21
+#endif
+
+/* The maximum number of clients that can register with the power manager. */
+#ifndef BTM_MAX_PM_RECORDS
+#define BTM_MAX_PM_RECORDS 2
+#endif
+
+/* This is set to show debug trace messages for the power manager. */
+#ifndef BTM_PM_DEBUG
+#define BTM_PM_DEBUG FALSE
+#endif
+
+/* This is set to TRUE if link is to be unparked due to BTM_CreateSCO API. */
+#ifndef BTM_SCO_WAKE_PARKED_LINK
+#define BTM_SCO_WAKE_PARKED_LINK TRUE
+#endif
+
+/* If the user does not respond to security process requests within this many
+ * seconds,
+ * a negative response would be sent automatically.
+ * 30 is LMP response timeout value */
+#ifndef BTM_SEC_TIMEOUT_VALUE
+#define BTM_SEC_TIMEOUT_VALUE 35
+#endif
+
+/* Maximum number of callbacks that can be registered using
+ * BTM_RegisterForVSEvents */
+#ifndef BTM_MAX_VSE_CALLBACKS
+#define BTM_MAX_VSE_CALLBACKS 3
+#endif
+
+/******************************************
+ *    Lisbon Features
+ ******************************************/
+/* This is set to TRUE if the FEC is required for EIR packet. */
+#ifndef BTM_EIR_DEFAULT_FEC_REQUIRED
+#define BTM_EIR_DEFAULT_FEC_REQUIRED TRUE
+#endif
+
+/* The IO capability of the local device (for Simple Pairing) */
+#ifndef BTM_LOCAL_IO_CAPS
+#define BTM_LOCAL_IO_CAPS BTM_IO_CAP_IO
+#endif
+
+#ifndef BTM_LOCAL_IO_CAPS_BLE
+#define BTM_LOCAL_IO_CAPS_BLE BTM_IO_CAP_KBDISP
+#endif
+
+/* The default MITM Protection Requirement (for Simple Pairing)
+ * Possible values are BTM_AUTH_SP_YES or BTM_AUTH_SP_NO */
+#ifndef BTM_DEFAULT_AUTH_REQ
+#define BTM_DEFAULT_AUTH_REQ BTM_AUTH_SP_NO
+#endif
+
+/* The default MITM Protection Requirement for dedicated bonding using Simple
+ * Pairing
+ * Possible values are BTM_AUTH_AP_YES or BTM_AUTH_AP_NO */
+#ifndef BTM_DEFAULT_DD_AUTH_REQ
+#define BTM_DEFAULT_DD_AUTH_REQ BTM_AUTH_AP_YES
+#endif
+
+/* TRUE to include Sniff Subrating */
+#ifndef BTM_SSR_INCLUDED
+#define BTM_SSR_INCLUDED TRUE
+#endif
+
+/*************************
+ * End of Lisbon Features
+ *************************/
+
+/* 4.1/4.2 secure connections feature */
+#ifndef SC_MODE_INCLUDED
+#define SC_MODE_INCLUDED TRUE
+#endif
+
+/* Used for conformance testing ONLY */
+#ifndef BTM_BLE_CONFORMANCE_TESTING
+#define BTM_BLE_CONFORMANCE_TESTING FALSE
+#endif
+
+/******************************************************************************
+ *
+ * L2CAP
+ *
+ *****************************************************************************/
+
+/* The maximum number of simultaneous links that L2CAP can support. */
+#ifndef MAX_ACL_CONNECTIONS
+#define MAX_L2CAP_LINKS 7
+#else
+#define MAX_L2CAP_LINKS MAX_ACL_CONNECTIONS
+#endif
+
+/* The maximum number of simultaneous channels that L2CAP can support. */
+#ifndef MAX_L2CAP_CHANNELS
+#define MAX_L2CAP_CHANNELS 16
+#endif
+
+/* The maximum number of simultaneous applications that can register with L2CAP.
+ */
+#ifndef MAX_L2CAP_CLIENTS
+#define MAX_L2CAP_CLIENTS 15
+#endif
+
+/* The number of seconds of link inactivity before a link is disconnected. */
+#ifndef L2CAP_LINK_INACTIVITY_TOUT
+#define L2CAP_LINK_INACTIVITY_TOUT 4
+#endif
+
+/* The number of seconds of link inactivity after bonding before a link is
+ * disconnected. */
+#ifndef L2CAP_BONDING_TIMEOUT
+#define L2CAP_BONDING_TIMEOUT 3
+#endif
+
+/* The time from the HCI connection complete to disconnect if no channel is
+ * established. */
+#ifndef L2CAP_LINK_STARTUP_TOUT
+#define L2CAP_LINK_STARTUP_TOUT 60
+#endif
+
+/* The L2CAP MTU; must be in accord with the HCI ACL buffer size. */
+#ifndef L2CAP_MTU_SIZE
+#define L2CAP_MTU_SIZE 1691
+#endif
+
+/*
+ * The L2CAP MPS over Bluetooth; must be in accord with the FCR tx buffer size
+ * and ACL down buffer size.
+ */
+#ifndef L2CAP_MPS_OVER_BR_EDR
+#define L2CAP_MPS_OVER_BR_EDR 1010
+#endif
+
+/* If host flow control enabled, this is the number of buffers the controller
+ * can have unacknowledged. */
+#ifndef L2CAP_HOST_FC_ACL_BUFS
+#define L2CAP_HOST_FC_ACL_BUFS 20
+#endif
+
+/* This is set to enable L2CAP to  take the ACL link out of park mode when ACL
+ * data is to be sent. */
+#ifndef L2CAP_WAKE_PARKED_LINK
+#define L2CAP_WAKE_PARKED_LINK TRUE
+#endif
+
+/* Whether link wants to be the master or the slave. */
+#ifndef L2CAP_DESIRED_LINK_ROLE
+#define L2CAP_DESIRED_LINK_ROLE HCI_ROLE_SLAVE
+#endif
+
+/* Include Non-Flushable Packet Boundary Flag feature of Lisbon */
+#ifndef L2CAP_NON_FLUSHABLE_PB_INCLUDED
+#define L2CAP_NON_FLUSHABLE_PB_INCLUDED TRUE
+#endif
+
+/* Minimum number of ACL credit for high priority link */
+#ifndef L2CAP_HIGH_PRI_MIN_XMIT_QUOTA
+#define L2CAP_HIGH_PRI_MIN_XMIT_QUOTA 5
+#endif
+
+/* used for monitoring HCI ACL credit management */
+#ifndef L2CAP_HCI_FLOW_CONTROL_DEBUG
+#define L2CAP_HCI_FLOW_CONTROL_DEBUG TRUE
+#endif
+
+/* Unicast Connectionless Data */
+#ifndef L2CAP_UCD_INCLUDED
+#define L2CAP_UCD_INCLUDED FALSE
+#endif
+
+/* Unicast Connectionless Data MTU */
+#ifndef L2CAP_UCD_MTU
+#define L2CAP_UCD_MTU L2CAP_MTU_SIZE
+#endif
+
+/* Unicast Connectionless Data Idle Timeout */
+#ifndef L2CAP_UCD_IDLE_TIMEOUT
+#define L2CAP_UCD_IDLE_TIMEOUT 2
+#endif
+
+/* Unicast Connectionless Data Idle Timeout */
+#ifndef L2CAP_UCD_CH_PRIORITY
+#define L2CAP_UCD_CH_PRIORITY L2CAP_CHNL_PRIORITY_MEDIUM
+#endif
+
+/* Used for features using fixed channels; set to zero if no fixed channels
+ * supported (BLE, etc.) */
+/* Excluding L2CAP signaling channel and UCD */
+#ifndef L2CAP_NUM_FIXED_CHNLS
+#define L2CAP_NUM_FIXED_CHNLS 32
+#endif
+
+/* First fixed channel supported */
+#ifndef L2CAP_FIRST_FIXED_CHNL
+#define L2CAP_FIRST_FIXED_CHNL 4
+#endif
+
+#ifndef L2CAP_LAST_FIXED_CHNL
+#define L2CAP_LAST_FIXED_CHNL \
+  (L2CAP_FIRST_FIXED_CHNL + L2CAP_NUM_FIXED_CHNLS - 1)
+#endif
+
+/* Round Robin service channels in link */
+#ifndef L2CAP_ROUND_ROBIN_CHANNEL_SERVICE
+#define L2CAP_ROUND_ROBIN_CHANNEL_SERVICE TRUE
+#endif
+
+/* used for monitoring eL2CAP data flow */
+#ifndef L2CAP_ERTM_STATS
+#define L2CAP_ERTM_STATS FALSE
+#endif
+
+/* Used for conformance testing ONLY:  When TRUE lets scriptwrapper overwrite
+ * info response */
+#ifndef L2CAP_CONFORMANCE_TESTING
+#define L2CAP_CONFORMANCE_TESTING FALSE
+#endif
+
+/*
+ * Max bytes per connection to buffer locally before dropping the
+ * connection if local client does not receive it  - default is 1MB
+ */
+#ifndef L2CAP_MAX_RX_BUFFER
+#define L2CAP_MAX_RX_BUFFER 0x100000
+#endif
+
+/******************************************************************************
+ *
+ * BLE
+ *
+ *****************************************************************************/
+
+#ifndef BLE_INCLUDED
+#define BLE_INCLUDED TRUE
+#endif
+
+#ifndef BLE_ANDROID_CONTROLLER_SCAN_FILTER
+#define BLE_ANDROID_CONTROLLER_SCAN_FILTER TRUE
+#endif
+
+#ifndef LOCAL_BLE_CONTROLLER_ID
+#define LOCAL_BLE_CONTROLLER_ID (1)
+#endif
+
+/*
+ * Toggles support for general LE privacy features such as remote address
+ * resolution, local address rotation etc.
+ */
+#ifndef BLE_PRIVACY_SPT
+#define BLE_PRIVACY_SPT TRUE
+#endif
+
+/*
+ * Enables or disables support for local privacy (ex. address rotation)
+ */
+#ifndef BLE_LOCAL_PRIVACY_ENABLED
+#define BLE_LOCAL_PRIVACY_ENABLED TRUE
+#endif
+
+/*
+ * Toggles support for vendor specific extensions such as RPA offloading,
+ * feature discovery, multi-adv etc.
+ */
+#ifndef BLE_VND_INCLUDED
+#define BLE_VND_INCLUDED        TRUE
+#endif
+
+#ifndef BTM_BLE_ADV_TX_POWER
+#define BTM_BLE_ADV_TX_POWER \
+  { -21, -15, -7, 9, 9 }
+#endif
+
+/* The maximum number of simultaneous applications that can register with LE
+ * L2CAP. */
+#ifndef BLE_MAX_L2CAP_CLIENTS
+#define BLE_MAX_L2CAP_CLIENTS 15
+#endif
+
+/******************************************************************************
+ *
+ * ATT/GATT Protocol/Profile Settings
+ *
+ *****************************************************************************/
+#ifndef BTA_GATT_INCLUDED
+#if BLE_INCLUDED == TRUE
+#define BTA_GATT_INCLUDED TRUE
+#else
+#define BTA_GATT_INCLUDED FALSE
+#endif
+#endif
+
+#if BTA_GATT_INCLUDED == TRUE && BLE_INCLUDED == FALSE
+#error "can't have GATT without BLE"
+#endif
+
+#ifndef BLE_LLT_INCLUDED
+#define BLE_LLT_INCLUDED TRUE
+#endif
+
+#ifndef ATT_INCLUDED
+#define ATT_INCLUDED TRUE
+#endif
+
+#ifndef ATT_DEBUG
+#define ATT_DEBUG TRUE
+#endif
+
+#ifndef BLE_DELAY_REQUEST_ENC
+/* This flag is to work around IPHONE problem, We need to wait for iPhone ready
+   before send encryption request to iPhone */
+#define BLE_DELAY_REQUEST_ENC FALSE
+#endif
+
+#ifndef GAP_TRANSPORT_SUPPORTED
+#define GAP_TRANSPORT_SUPPORTED GATT_TRANSPORT_LE_BR_EDR
+#endif
+
+#ifndef GATTP_TRANSPORT_SUPPORTED
+#define GATTP_TRANSPORT_SUPPORTED GATT_TRANSPORT_LE_BR_EDR
+#endif
+
+#ifndef GATT_MAX_SR_PROFILES
+#define GATT_MAX_SR_PROFILES 32 /* max is 32 */
+#endif
+
+#ifndef GATT_MAX_APPS
+#define GATT_MAX_APPS 32 /* note: 2 apps used internally GATT and GAP */
+#endif
+
+#ifndef GATT_MAX_PHY_CHANNEL
+#define GATT_MAX_PHY_CHANNEL 7
+#endif
+
+/* Used for conformance testing ONLY */
+#ifndef GATT_CONFORMANCE_TESTING
+#define GATT_CONFORMANCE_TESTING FALSE
+#endif
+
+/* number of background connection device allowence, ideally to be the same as
+ * WL size
+*/
+#ifndef GATT_MAX_BG_CONN_DEV
+#define GATT_MAX_BG_CONN_DEV 32
+#endif
+
+/******************************************************************************
+ *
+ * SMP
+ *
+ *****************************************************************************/
+#ifndef SMP_INCLUDED
+#if (BLE_INCLUDED == TRUE)
+#define SMP_INCLUDED TRUE
+#else
+#define SMP_INCLUDED FALSE
+#endif
+#endif
+
+#if (SMP_INCLUDED == TRUE && BLE_INCLUDED == FALSE)
+#error "can't have SMP without BLE"
+#endif
+
+#ifndef SMP_DEBUG
+#define SMP_DEBUG FALSE
+#endif
+
+#ifndef SMP_DEFAULT_AUTH_REQ
+#define SMP_DEFAULT_AUTH_REQ SMP_AUTH_NB_ENC_ONLY
+#endif
+
+#ifndef SMP_MAX_ENC_KEY_SIZE
+#define SMP_MAX_ENC_KEY_SIZE 16
+#endif
+
+/* minimum link timeout after SMP pairing is done, leave room for key exchange
+   and racing condition for the following service connection.
+   Prefer greater than 0 second, and no less than default inactivity link idle
+   timer(L2CAP_LINK_INACTIVITY_TOUT) in l2cap) */
+#ifndef SMP_LINK_TOUT_MIN
+#if (L2CAP_LINK_INACTIVITY_TOUT > 0)
+#define SMP_LINK_TOUT_MIN L2CAP_LINK_INACTIVITY_TOUT
+#else
+#define SMP_LINK_TOUT_MIN 2
+#endif
+#endif
+/******************************************************************************
+ *
+ * SDP
+ *
+ *****************************************************************************/
+
+/* This is set to enable SDP server functionality. */
+#ifndef SDP_SERVER_ENABLED
+#define SDP_SERVER_ENABLED TRUE
+#endif
+
+/* The maximum number of SDP records the server can support. */
+#ifndef SDP_MAX_RECORDS
+#define SDP_MAX_RECORDS 30
+#endif
+
+/* The maximum number of attributes in each record. */
+#ifndef SDP_MAX_REC_ATTR
+#define SDP_MAX_REC_ATTR 25
+#endif
+
+#ifndef SDP_MAX_PAD_LEN
+#define SDP_MAX_PAD_LEN 600
+#endif
+
+/* The maximum length, in bytes, of an attribute. */
+#ifndef SDP_MAX_ATTR_LEN
+#define SDP_MAX_ATTR_LEN 400
+#endif
+
+/* The maximum number of attribute filters supported by SDP databases. */
+#ifndef SDP_MAX_ATTR_FILTERS
+#define SDP_MAX_ATTR_FILTERS 15
+#endif
+
+/* The maximum number of UUID filters supported by SDP databases. */
+#ifndef SDP_MAX_UUID_FILTERS
+#define SDP_MAX_UUID_FILTERS 3
+#endif
+
+/* This is set to enable SDP client functionality. */
+#ifndef SDP_CLIENT_ENABLED
+#define SDP_CLIENT_ENABLED TRUE
+#endif
+
+/* The maximum number of record handles retrieved in a search. */
+#ifndef SDP_MAX_DISC_SERVER_RECS
+#define SDP_MAX_DISC_SERVER_RECS 21
+#endif
+
+/* The size of a scratchpad buffer, in bytes, for storing the response to an
+ * attribute request. */
+#ifndef SDP_MAX_LIST_BYTE_COUNT
+#define SDP_MAX_LIST_BYTE_COUNT 4096
+#endif
+
+/* The maximum number of parameters in an SDP protocol element. */
+#ifndef SDP_MAX_PROTOCOL_PARAMS
+#define SDP_MAX_PROTOCOL_PARAMS 2
+#endif
+
+/* The maximum number of simultaneous client and server connections. */
+#ifndef SDP_MAX_CONNECTIONS
+#define SDP_MAX_CONNECTIONS 4
+#endif
+
+/* The MTU size for the L2CAP configuration. */
+#ifndef SDP_MTU_SIZE
+#define SDP_MTU_SIZE 672
+#endif
+
+/* The flush timeout for the L2CAP configuration. */
+#ifndef SDP_FLUSH_TO
+#define SDP_FLUSH_TO 0xFFFF
+#endif
+
+/* The name for security authorization. */
+#ifndef SDP_SERVICE_NAME
+#define SDP_SERVICE_NAME "Service Discovery"
+#endif
+
+/* The security level for BTM. */
+#ifndef SDP_SECURITY_LEVEL
+#define SDP_SECURITY_LEVEL BTM_SEC_NONE
+#endif
+
+/******************************************************************************
+ *
+ * RFCOMM
+ *
+ *****************************************************************************/
+
+/* The maximum number of ports supported. */
+#ifndef MAX_RFC_PORTS
+#define MAX_RFC_PORTS 30
+#endif
+
+/* The maximum simultaneous links to different devices. */
+#ifndef MAX_ACL_CONNECTIONS
+#define MAX_BD_CONNECTIONS 7
+#else
+#define MAX_BD_CONNECTIONS MAX_ACL_CONNECTIONS
+#endif
+
+/* The port receive queue low watermark level, in bytes. */
+#ifndef PORT_RX_LOW_WM
+#define PORT_RX_LOW_WM (BTA_RFC_MTU_SIZE * PORT_RX_BUF_LOW_WM)
+#endif
+
+/* The port receive queue high watermark level, in bytes. */
+#ifndef PORT_RX_HIGH_WM
+#define PORT_RX_HIGH_WM (BTA_RFC_MTU_SIZE * PORT_RX_BUF_HIGH_WM)
+#endif
+
+/* The port receive queue critical watermark level, in bytes. */
+#ifndef PORT_RX_CRITICAL_WM
+#define PORT_RX_CRITICAL_WM (BTA_RFC_MTU_SIZE * PORT_RX_BUF_CRITICAL_WM)
+#endif
+
+/* The port receive queue low watermark level, in number of buffers. */
+#ifndef PORT_RX_BUF_LOW_WM
+#define PORT_RX_BUF_LOW_WM 4
+#endif
+
+/* The port receive queue high watermark level, in number of buffers. */
+#ifndef PORT_RX_BUF_HIGH_WM
+#define PORT_RX_BUF_HIGH_WM 10
+#endif
+
+/* The port receive queue critical watermark level, in number of buffers. */
+#ifndef PORT_RX_BUF_CRITICAL_WM
+#define PORT_RX_BUF_CRITICAL_WM 15
+#endif
+
+/* The port transmit queue high watermark level, in bytes. */
+#ifndef PORT_TX_HIGH_WM
+#define PORT_TX_HIGH_WM (BTA_RFC_MTU_SIZE * PORT_TX_BUF_HIGH_WM)
+#endif
+
+/* The port transmit queue critical watermark level, in bytes. */
+#ifndef PORT_TX_CRITICAL_WM
+#define PORT_TX_CRITICAL_WM (BTA_RFC_MTU_SIZE * PORT_TX_BUF_CRITICAL_WM)
+#endif
+
+/* The port transmit queue high watermark level, in number of buffers. */
+#ifndef PORT_TX_BUF_HIGH_WM
+#define PORT_TX_BUF_HIGH_WM 10
+#endif
+
+/* The port transmit queue high watermark level, in number of buffers. */
+#ifndef PORT_TX_BUF_CRITICAL_WM
+#define PORT_TX_BUF_CRITICAL_WM 15
+#endif
+
+/* The RFCOMM multiplexer preferred flow control mechanism. */
+#ifndef PORT_FC_DEFAULT
+#define PORT_FC_DEFAULT PORT_FC_CREDIT
+#endif
+
+/* The maximum number of credits receiver sends to peer when using credit-based
+ * flow control. */
+#ifndef PORT_CREDIT_RX_MAX
+#define PORT_CREDIT_RX_MAX 16
+#endif
+
+/* The credit low watermark level. */
+#ifndef PORT_CREDIT_RX_LOW
+#define PORT_CREDIT_RX_LOW 8
+#endif
+
+/******************************************************************************
+ *
+ * OBEX
+ *
+ *****************************************************************************/
+
+/*
+ * Buffer size to reassemble the SDU.
+ * It will allow buffers to be used that are larger than the L2CAP_MAX_MTU.
+ */
+#ifndef OBX_USER_RX_BUF_SIZE
+#define OBX_USER_RX_BUF_SIZE OBX_LRG_DATA_BUF_SIZE
+#endif
+
+/*
+ * Buffer size to hold the SDU.
+ * It will allow buffers to be used that are larger than the L2CAP_MAX_MTU.
+ */
+#ifndef OBX_USER_TX_BUF_SIZE
+#define OBX_USER_TX_BUF_SIZE OBX_LRG_DATA_BUF_SIZE
+#endif
+
+/* Buffer size used to hold MPS segments during SDU reassembly. */
+#ifndef OBX_FCR_RX_BUF_SIZE
+#define OBX_FCR_RX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/*
+ * Buffer size used to hold MPS segments used in (re)transmissions.
+ * The size of each buffer must be able to hold the maximum MPS segment size
+ * passed in L2CA_SetFCROptions plus BT_HDR (8) + HCI preamble (4) +
+ * L2CAP_MIN_OFFSET (11 - as of BT 2.1 + EDR Spec).
+ */
+#ifndef OBX_FCR_TX_BUF_SIZE
+#define OBX_FCR_TX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/*
+ * Size of the transmission window when using enhanced retransmission mode.
+ * Not used in basic and streaming modes. Range: 1 - 63
+ */
+#ifndef OBX_FCR_OPT_TX_WINDOW_SIZE_BR_EDR
+#define OBX_FCR_OPT_TX_WINDOW_SIZE_BR_EDR 20
+#endif
+
+/*
+ * Number of transmission attempts for a single I-Frame before taking
+ * Down the connection. Used In ERTM mode only. Value is Ignored in basic and
+ * Streaming modes.
+ * Range: 0, 1-0xFF
+ * 0 - infinite retransmissions
+ * 1 - single transmission
+ */
+#ifndef OBX_FCR_OPT_MAX_TX_B4_DISCNT
+#define OBX_FCR_OPT_MAX_TX_B4_DISCNT 20
+#endif
+
+/*
+ * Retransmission Timeout
+ * Range: Minimum 2000 (2 secs) on BR/EDR when supporting PBF.
+ */
+#ifndef OBX_FCR_OPT_RETX_TOUT
+#define OBX_FCR_OPT_RETX_TOUT 2000
+#endif
+
+/*
+ * Monitor Timeout
+ * Range: Minimum 12000 (12 secs) on BR/EDR when supporting PBF.
+ */
+#ifndef OBX_FCR_OPT_MONITOR_TOUT
+#define OBX_FCR_OPT_MONITOR_TOUT 12000
+#endif
+
+/*
+ * Maximum PDU payload size.
+ * Suggestion: The maximum amount of data that will fit into a 3-DH5 packet.
+ * Range: 2 octets
+ */
+#ifndef OBX_FCR_OPT_MAX_PDU_SIZE
+#define OBX_FCR_OPT_MAX_PDU_SIZE L2CAP_MPS_OVER_BR_EDR
+#endif
+
+/******************************************************************************
+ *
+ * BNEP
+ *
+ *****************************************************************************/
+
+#ifndef BNEP_INCLUDED
+#define BNEP_INCLUDED TRUE
+#endif
+
+/* BNEP status API call is used mainly to get the L2CAP handle */
+#ifndef BNEP_SUPPORTS_STATUS_API
+#define BNEP_SUPPORTS_STATUS_API TRUE
+#endif
+
+/*
+ * When BNEP connection changes roles after the connection is established
+ * we will do an authentication check again on the new role
+*/
+#ifndef BNEP_DO_AUTH_FOR_ROLE_SWITCH
+#define BNEP_DO_AUTH_FOR_ROLE_SWITCH TRUE
+#endif
+
+/* Maximum number of protocol filters supported. */
+#ifndef BNEP_MAX_PROT_FILTERS
+#define BNEP_MAX_PROT_FILTERS 5
+#endif
+
+/* Maximum number of multicast filters supported. */
+#ifndef BNEP_MAX_MULTI_FILTERS
+#define BNEP_MAX_MULTI_FILTERS 5
+#endif
+
+/* Minimum MTU size. */
+#ifndef BNEP_MIN_MTU_SIZE
+#define BNEP_MIN_MTU_SIZE L2CAP_MTU_SIZE
+#endif
+
+/* Preferred MTU size. */
+#ifndef BNEP_MTU_SIZE
+#define BNEP_MTU_SIZE BNEP_MIN_MTU_SIZE
+#endif
+
+/* Maximum number of buffers allowed in transmit data queue. */
+#ifndef BNEP_MAX_XMITQ_DEPTH
+#define BNEP_MAX_XMITQ_DEPTH 20
+#endif
+
+/* Maximum number BNEP of connections supported. */
+#ifndef BNEP_MAX_CONNECTIONS
+#define BNEP_MAX_CONNECTIONS 7
+#endif
+
+/******************************************************************************
+ *
+ * AVDTP
+ *
+ *****************************************************************************/
+
+#ifndef AVDT_INCLUDED
+#define AVDT_INCLUDED TRUE
+#endif
+
+/* Include reporting capability in AVDTP */
+#ifndef AVDT_REPORTING
+#define AVDT_REPORTING TRUE
+#endif
+
+/* Number of simultaneous links to different peer devices. */
+#ifndef AVDT_NUM_LINKS
+#define AVDT_NUM_LINKS 2
+#endif
+
+/* Number of simultaneous stream endpoints. */
+#ifndef AVDT_NUM_SEPS
+#define AVDT_NUM_SEPS 3
+#endif
+
+/* Number of transport channels setup by AVDT for all media streams */
+#ifndef AVDT_NUM_TC_TBL
+#define AVDT_NUM_TC_TBL 6
+#endif
+
+/* Maximum size in bytes of the content protection information element. */
+#ifndef AVDT_PROTECT_SIZE
+#define AVDT_PROTECT_SIZE 90
+#endif
+
+/******************************************************************************
+ *
+ * PAN
+ *
+ *****************************************************************************/
+
+#ifndef PAN_INCLUDED
+#define PAN_INCLUDED TRUE
+#endif
+
+#ifndef PAN_NAP_DISABLED
+#define PAN_NAP_DISABLED FALSE
+#endif
+
+#ifndef PANU_DISABLED
+#define PANU_DISABLED FALSE
+#endif
+
+/* This will enable the PANU role */
+#ifndef PAN_SUPPORTS_ROLE_PANU
+#define PAN_SUPPORTS_ROLE_PANU TRUE
+#endif
+
+/* This will enable the GN role */
+#ifndef PAN_SUPPORTS_ROLE_GN
+#define PAN_SUPPORTS_ROLE_GN TRUE
+#endif
+
+/* This will enable the NAP role */
+#ifndef PAN_SUPPORTS_ROLE_NAP
+#define PAN_SUPPORTS_ROLE_NAP TRUE
+#endif
+
+/* This is just for debugging purposes */
+#ifndef PAN_SUPPORTS_DEBUG_DUMP
+#define PAN_SUPPORTS_DEBUG_DUMP TRUE
+#endif
+
+/* Maximum number of PAN connections allowed */
+#ifndef MAX_PAN_CONNS
+#define MAX_PAN_CONNS 7
+#endif
+
+/* Default service name for NAP role */
+#ifndef PAN_NAP_DEFAULT_SERVICE_NAME
+#define PAN_NAP_DEFAULT_SERVICE_NAME "Network Access Point Service"
+#endif
+
+/* Default service name for GN role */
+#ifndef PAN_GN_DEFAULT_SERVICE_NAME
+#define PAN_GN_DEFAULT_SERVICE_NAME "Group Network Service"
+#endif
+
+/* Default service name for PANU role */
+#ifndef PAN_PANU_DEFAULT_SERVICE_NAME
+#define PAN_PANU_DEFAULT_SERVICE_NAME "PAN User Service"
+#endif
+
+/* Default description for NAP role service */
+#ifndef PAN_NAP_DEFAULT_DESCRIPTION
+#define PAN_NAP_DEFAULT_DESCRIPTION "NAP"
+#endif
+
+/* Default description for GN role service */
+#ifndef PAN_GN_DEFAULT_DESCRIPTION
+#define PAN_GN_DEFAULT_DESCRIPTION "GN"
+#endif
+
+/* Default description for PANU role service */
+#ifndef PAN_PANU_DEFAULT_DESCRIPTION
+#define PAN_PANU_DEFAULT_DESCRIPTION "PANU"
+#endif
+
+/* Default Security level for PANU role. */
+#ifndef PAN_PANU_SECURITY_LEVEL
+#define PAN_PANU_SECURITY_LEVEL 0
+#endif
+
+/* Default Security level for GN role. */
+#ifndef PAN_GN_SECURITY_LEVEL
+#define PAN_GN_SECURITY_LEVEL 0
+#endif
+
+/* Default Security level for NAP role. */
+#ifndef PAN_NAP_SECURITY_LEVEL
+#define PAN_NAP_SECURITY_LEVEL 0
+#endif
+
+/******************************************************************************
+ *
+ * GAP
+ *
+ *****************************************************************************/
+
+#ifndef GAP_INCLUDED
+#define GAP_INCLUDED TRUE
+#endif
+
+/* This is set to enable use of GAP L2CAP connections. */
+#ifndef GAP_CONN_INCLUDED
+#define GAP_CONN_INCLUDED TRUE
+#endif
+
+/* The maximum number of simultaneous GAP L2CAP connections. */
+#ifndef GAP_MAX_CONNECTIONS
+#define GAP_MAX_CONNECTIONS 30
+#endif
+
+/* keep the raw data received from SDP server in database. */
+#ifndef SDP_RAW_DATA_INCLUDED
+#define SDP_RAW_DATA_INCLUDED TRUE
+#endif
+
+/* Inquiry duration in 1.28 second units. */
+#ifndef SDP_DEBUG
+#define SDP_DEBUG TRUE
+#endif
+
+/******************************************************************************
+ *
+ * HID
+ *
+ *****************************************************************************/
+
+#ifndef HID_CONTROL_BUF_SIZE
+#define HID_CONTROL_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+#ifndef HID_INTERRUPT_BUF_SIZE
+#define HID_INTERRUPT_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/*************************************************************************
+ * Definitions for Both HID-Host & Device
+*/
+#ifndef HID_MAX_SVC_NAME_LEN
+#define HID_MAX_SVC_NAME_LEN 32
+#endif
+
+#ifndef HID_MAX_SVC_DESCR_LEN
+#define HID_MAX_SVC_DESCR_LEN 32
+#endif
+
+#ifndef HID_MAX_PROV_NAME_LEN
+#define HID_MAX_PROV_NAME_LEN 32
+#endif
+
+/*************************************************************************
+ * Definitions for HID-Host
+*/
+#ifndef HID_HOST_INCLUDED
+#define HID_HOST_INCLUDED TRUE
+#endif
+
+#ifndef HID_HOST_MAX_DEVICES
+#define HID_HOST_MAX_DEVICES 7
+#endif
+
+#ifndef HID_HOST_MTU
+#define HID_HOST_MTU 640
+#endif
+
+#ifndef HID_HOST_FLUSH_TO
+#define HID_HOST_FLUSH_TO 0xffff
+#endif
+
+#ifndef HID_HOST_MAX_CONN_RETRY
+#define HID_HOST_MAX_CONN_RETRY (1)
+#endif
+
+#ifndef HID_HOST_REPAGE_WIN
+#define HID_HOST_REPAGE_WIN (2)
+#endif
+
+/*************************************************************************
+ * A2DP Definitions
+ */
+#ifndef A2D_INCLUDED
+#define A2D_INCLUDED TRUE
+#endif
+
+/******************************************************************************
+ *
+ * AVCTP
+ *
+ *****************************************************************************/
+
+/* Number of simultaneous ACL links to different peer devices. */
+#ifndef AVCT_NUM_LINKS
+#define AVCT_NUM_LINKS 2
+#endif
+
+/* Number of simultaneous AVCTP connections. */
+#ifndef AVCT_NUM_CONN
+#define AVCT_NUM_CONN 3
+#endif
+
+/******************************************************************************
+ *
+ * AVRCP
+ *
+ *****************************************************************************/
+
+#ifndef AVRC_METADATA_INCLUDED
+#define AVRC_METADATA_INCLUDED TRUE
+#endif
+
+#ifndef AVRC_ADV_CTRL_INCLUDED
+#define AVRC_ADV_CTRL_INCLUDED TRUE
+#endif
+
+#ifndef AVRC_CTRL_INCLUDED
+#define AVRC_CTRL_INCLUDED TRUE
+#endif
+
+#ifndef DUMP_PCM_DATA
+#define DUMP_PCM_DATA FALSE
+#endif
+
+/******************************************************************************
+ *
+ * MCAP
+ *
+ *****************************************************************************/
+#ifndef MCA_INCLUDED
+#define MCA_INCLUDED FALSE
+#endif
+
+/* The MTU size for the L2CAP configuration on control channel. 48 is the
+ * minimal */
+#ifndef MCA_CTRL_MTU
+#define MCA_CTRL_MTU 60
+#endif
+
+/* The maximum number of registered MCAP instances. */
+#ifndef MCA_NUM_REGS
+#define MCA_NUM_REGS 12
+#endif
+
+/* The maximum number of control channels (to difference devices) per registered
+ * MCAP instances. */
+#ifndef MCA_NUM_LINKS
+#define MCA_NUM_LINKS 3
+#endif
+
+/* The maximum number of MDEP (including HDP echo) per registered MCAP
+ * instances. */
+#ifndef MCA_NUM_DEPS
+#define MCA_NUM_DEPS 13
+#endif
+
+/* The maximum number of MDL link per control channel. */
+#ifndef MCA_NUM_MDLS
+#define MCA_NUM_MDLS 4
+#endif
+
+/* Buffer size to reassemble the SDU. */
+#ifndef MCA_USER_RX_BUF_SIZE
+#define MCA_USER_RX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* Buffer size to hold the SDU. */
+#ifndef MCA_USER_TX_BUF_SIZE
+#define MCA_USER_TX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/*
+ * Buffer size used to hold MPS segments during SDU reassembly
+ */
+#ifndef MCA_FCR_RX_BUF_SIZE
+#define MCA_FCR_RX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/*
+ * Default buffer size used to hold MPS segments used in (re)transmissions.
+ * The size of each buffer must be able to hold the maximum MPS segment size
+ * passed in tL2CAP_FCR_OPTIONS plus BT_HDR (8) + HCI preamble (4) +
+ * L2CAP_MIN_OFFSET (11 - as of BT 2.1 + EDR Spec).
+ */
+#ifndef MCA_FCR_TX_BUF_SIZE
+#define MCA_FCR_TX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* MCAP control channel FCR Option:
+Size of the transmission window when using enhanced retransmission mode.
+1 is defined by HDP specification for control channel.
+*/
+#ifndef MCA_FCR_OPT_TX_WINDOW_SIZE
+#define MCA_FCR_OPT_TX_WINDOW_SIZE 1
+#endif
+
+/* MCAP control channel FCR Option:
+Number of transmission attempts for a single I-Frame before taking
+Down the connection. Used In ERTM mode only. Value is Ignored in basic and
+Streaming modes.
+Range: 0, 1-0xFF
+0 - infinite retransmissions
+1 - single transmission
+*/
+#ifndef MCA_FCR_OPT_MAX_TX_B4_DISCNT
+#define MCA_FCR_OPT_MAX_TX_B4_DISCNT 20
+#endif
+
+/* MCAP control channel FCR Option: Retransmission Timeout
+The AVRCP specification set a value in the range of 300 - 2000 ms
+Timeout (in msecs) to detect Lost I-Frames. Only used in Enhanced retransmission
+mode.
+Range: Minimum 2000 (2 secs) when supporting PBF.
+ */
+#ifndef MCA_FCR_OPT_RETX_TOUT
+#define MCA_FCR_OPT_RETX_TOUT 2000
+#endif
+
+/* MCAP control channel FCR Option: Monitor Timeout
+The AVRCP specification set a value in the range of 300 - 2000 ms
+Timeout (in msecs) to detect Lost S-Frames. Only used in Enhanced retransmission
+mode.
+Range: Minimum 12000 (12 secs) when supporting PBF.
+*/
+#ifndef MCA_FCR_OPT_MONITOR_TOUT
+#define MCA_FCR_OPT_MONITOR_TOUT 12000
+#endif
+
+/* MCAP control channel FCR Option: Maximum PDU payload size.
+The maximum number of payload octets that the local device can receive in a
+single PDU.
+*/
+#ifndef MCA_FCR_OPT_MPS_SIZE
+#define MCA_FCR_OPT_MPS_SIZE 1000
+#endif
+
+/******************************************************************************
+ *
+ * Sleep Mode (Low Power Mode)
+ *
+ *****************************************************************************/
+
+#ifndef HCILP_INCLUDED
+#define HCILP_INCLUDED TRUE
+#endif
+
+/******************************************************************************
+ *
+ * BTA
+ *
+ *****************************************************************************/
+/* BTA EIR canned UUID list (default is dynamic) */
+#ifndef BTA_EIR_CANNED_UUID_LIST
+#define BTA_EIR_CANNED_UUID_LIST FALSE
+#endif
+
+/* Number of supported customer UUID in EIR */
+#ifndef BTA_EIR_SERVER_NUM_CUSTOM_UUID
+#define BTA_EIR_SERVER_NUM_CUSTOM_UUID 8
+#endif
+
+/* CHLD override */
+#ifndef BTA_AG_CHLD_VAL_ECC
+#define BTA_AG_CHLD_VAL_ECC "(0,1,1x,2,2x,3)"
+#endif
+
+#ifndef BTA_AG_CHLD_VAL
+#define BTA_AG_CHLD_VAL "(0,1,2,3)"
+#endif
+
+/* Set the CIND to match HFP 1.5 */
+#ifndef BTA_AG_CIND_INFO
+#define BTA_AG_CIND_INFO                                                       \
+  "(\"call\",(0,1)),(\"callsetup\",(0-3)),(\"service\",(0-1)),(\"signal\",(0-" \
+  "5)),(\"roam\",(0,1)),(\"battchg\",(0-5)),(\"callheld\",(0-2))"
+#endif
+
+#ifndef BTA_DM_AVOID_A2DP_ROLESWITCH_ON_INQUIRY
+#define BTA_DM_AVOID_A2DP_ROLESWITCH_ON_INQUIRY TRUE
+#endif
+
+/******************************************************************************
+ *
+ * Tracing:  Include trace header file here.
+ *
+ *****************************************************************************/
+
+/* Enable/disable BTSnoop memory logging */
+#ifndef BTSNOOP_MEM
+#define BTSNOOP_MEM TRUE
+#endif
+
+#include "bt_trace.h"
+
+#endif /* BT_TARGET_H */
diff --git a/bt/include/bt_trace.h b/bt/include/bt_trace.h
new file mode 100644
index 0000000..0c68aae
--- /dev/null
+++ b/bt/include/bt_trace.h
@@ -0,0 +1,761 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module";
+
+/* BTE tracing IDs for debug purposes */
+/* LayerIDs for stack */
+#define BTTRC_ID_STK_GKI 1
+#define BTTRC_ID_STK_BTU 2
+#define BTTRC_ID_STK_HCI 3
+#define BTTRC_ID_STK_L2CAP 4
+#define BTTRC_ID_STK_RFCM_MX 5
+#define BTTRC_ID_STK_RFCM_PRT 6
+#define BTTRC_ID_STK_OBEX_C 7
+#define BTTRC_ID_STK_OBEX_S 8
+#define BTTRC_ID_STK_AVCT 9
+#define BTTRC_ID_STK_AVDT 10
+#define BTTRC_ID_STK_AVRC 11
+#define BTTRC_ID_STK_BIC 12
+#define BTTRC_ID_STK_BIS 13
+#define BTTRC_ID_STK_BNEP 14
+#define BTTRC_ID_STK_BPP 15
+#define BTTRC_ID_STK_BTM_ACL 16
+#define BTTRC_ID_STK_BTM_PM 17
+#define BTTRC_ID_STK_BTM_DEV_CTRL 18
+#define BTTRC_ID_STK_BTM_SVC_DSC 19
+#define BTTRC_ID_STK_BTM_INQ 20
+#define BTTRC_ID_STK_BTM_SCO 21
+#define BTTRC_ID_STK_BTM_SEC 22
+#define BTTRC_ID_STK_HID 24
+#define BTTRC_ID_STK_HSP2 25
+#define BTTRC_ID_STK_CTP 26
+#define BTTRC_ID_STK_FTC 27
+#define BTTRC_ID_STK_FTS 28
+#define BTTRC_ID_STK_GAP 29
+#define BTTRC_ID_STK_HCRP 31
+#define BTTRC_ID_STK_ICP 32
+#define BTTRC_ID_STK_OPC 33
+#define BTTRC_ID_STK_OPS 34
+#define BTTRC_ID_STK_PAN 35
+#define BTTRC_ID_STK_SAP 36
+#define BTTRC_ID_STK_SDP 37
+#define BTTRC_ID_STK_SLIP 38
+#define BTTRC_ID_STK_SPP 39
+#define BTTRC_ID_STK_TCS 40
+#define BTTRC_ID_STK_VDP 41
+#define BTTRC_ID_STK_MCAP 42
+#define BTTRC_ID_STK_GATT 43
+#define BTTRC_ID_STK_SMP 44
+#define BTTRC_ID_STK_NFC 45
+#define BTTRC_ID_STK_NCI 46
+#define BTTRC_ID_STK_IDEP 47
+#define BTTRC_ID_STK_NDEP 48
+#define BTTRC_ID_STK_LLCP 49
+#define BTTRC_ID_STK_RW 50
+#define BTTRC_ID_STK_CE 51
+#define BTTRC_ID_STK_SNEP 52
+#define BTTRC_ID_STK_NDEF 53
+
+/* LayerIDs for BTA */
+#define BTTRC_ID_BTA_ACC 55 /* Advanced Camera Client */
+#define BTTRC_ID_BTA_AG 56  /* audio gateway */
+#define BTTRC_ID_BTA_AV 57  /* Advanced audio */
+#define BTTRC_ID_BTA_BIC 58 /* Basic Imaging Client */
+#define BTTRC_ID_BTA_BIS 59 /* Basic Imaging Server */
+#define BTTRC_ID_BTA_BP 60  /* Basic Printing Client */
+#define BTTRC_ID_BTA_CG 61
+#define BTTRC_ID_BTA_CT 62      /* cordless telephony terminal */
+#define BTTRC_ID_BTA_DG 63      /* data gateway */
+#define BTTRC_ID_BTA_DM 64      /* device manager */
+#define BTTRC_ID_BTA_DM_SRCH 65 /* device manager search */
+#define BTTRC_ID_BTA_DM_SEC 66  /* device manager security */
+#define BTTRC_ID_BTA_FM 67
+#define BTTRC_ID_BTA_FTC 68 /* file transfer client */
+#define BTTRC_ID_BTA_FTS 69 /* file transfer server */
+#define BTTRC_ID_BTA_HIDH 70
+#define BTTRC_ID_BTA_HIDD 71
+#define BTTRC_ID_BTA_JV 72
+#define BTTRC_ID_BTA_OPC 73  /* object push client */
+#define BTTRC_ID_BTA_OPS 74  /* object push server */
+#define BTTRC_ID_BTA_PAN 75  /* Personal Area Networking */
+#define BTTRC_ID_BTA_PR 76   /* Printer client */
+#define BTTRC_ID_BTA_SC 77   /* SIM Card Access server */
+#define BTTRC_ID_BTA_SS 78   /* synchronization server */
+#define BTTRC_ID_BTA_SYS 79  /* system manager */
+#define BTTRC_ID_AVDT_SCB 80 /* avdt scb */
+#define BTTRC_ID_AVDT_CCB 81 /* avdt ccb */
+
+/* LayerIDs added for BTL-A. Probably should modify bte_logmsg.cc in future. */
+#define BTTRC_ID_STK_RFCOMM 82
+#define BTTRC_ID_STK_RFCOMM_DATA 83
+#define BTTRC_ID_STK_OBEX 84
+#define BTTRC_ID_STK_A2DP 85
+#define BTTRC_ID_STK_BIP 86
+
+/* LayerIDs for BT APP */
+#define BTTRC_ID_BTAPP 87
+#define BTTRC_ID_BT_PROTOCOL                          \
+  88 /* this is a temporary solution to allow dynamic \
+        enable/disable of BT_PROTOCOL_TRACE */
+#define BTTRC_ID_MAX_ID BTTRC_ID_BT_PROTOCOL
+#define BTTRC_ID_ALL_LAYERS 0xFF /* all trace layers */
+
+/* Enables or disables verbose trace information. */
+#ifndef BT_TRACE_VERBOSE
+#define BT_TRACE_VERBOSE FALSE
+#endif
+
+/******************************************************************************
+ *
+ * Trace Levels
+ *
+ * The following values may be used for different levels:
+ *      BT_TRACE_LEVEL_NONE    0        * No trace messages to be generated
+ *      BT_TRACE_LEVEL_ERROR   1        * Error condition trace messages
+ *      BT_TRACE_LEVEL_WARNING 2        * Warning condition trace messages
+ *      BT_TRACE_LEVEL_API     3        * API traces
+ *      BT_TRACE_LEVEL_EVENT   4        * Debug messages for events
+ *      BT_TRACE_LEVEL_DEBUG   5        * Debug messages (general)
+ *****************************************************************************/
+
+/* Core Stack default trace levels */
+#ifndef HCI_INITIAL_TRACE_LEVEL
+#define HCI_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef BTM_INITIAL_TRACE_LEVEL
+#define BTM_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef L2CAP_INITIAL_TRACE_LEVEL
+#define L2CAP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef RFCOMM_INITIAL_TRACE_LEVEL
+#define RFCOMM_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef SDP_INITIAL_TRACE_LEVEL
+#define SDP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef GAP_INITIAL_TRACE_LEVEL
+#define GAP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef BNEP_INITIAL_TRACE_LEVEL
+#define BNEP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef PAN_INITIAL_TRACE_LEVEL
+#define PAN_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef A2DP_INITIAL_TRACE_LEVEL
+#define A2DP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef AVDT_INITIAL_TRACE_LEVEL
+#define AVDT_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef AVCT_INITIAL_TRACE_LEVEL
+#define AVCT_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef AVRC_INITIAL_TRACE_LEVEL
+#define AVRC_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef MCA_INITIAL_TRACE_LEVEL
+#define MCA_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef HID_INITIAL_TRACE_LEVEL
+#define HID_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef APPL_INITIAL_TRACE_LEVEL
+#define APPL_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef GATT_INITIAL_TRACE_LEVEL
+#define GATT_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef SMP_INITIAL_TRACE_LEVEL
+#define SMP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#define BT_TRACE(l, t, ...) \
+  LogMsg((TRACE_CTRL_GENERAL | (l) | TRACE_ORG_STACK | (t)), ##__VA_ARGS__)
+
+/* Define tracing for the HCI unit
+*/
+
+#define HCI_TRACE_ERROR(...)                                      \
+  {                                                               \
+    if (btu_trace_level >= BT_TRACE_LEVEL_ERROR)                  \
+      BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+  }
+#define HCI_TRACE_WARNING(...)                                      \
+  {                                                                 \
+    if (btu_trace_level >= BT_TRACE_LEVEL_WARNING)                  \
+      BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+  }
+#define HCI_TRACE_EVENT(...)                                      \
+  {                                                               \
+    if (btu_trace_level >= BT_TRACE_LEVEL_EVENT)                  \
+      BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+  }
+#define HCI_TRACE_DEBUG(...)                                      \
+  {                                                               \
+    if (btu_trace_level >= BT_TRACE_LEVEL_DEBUG)                  \
+      BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+  }
+
+/* Define tracing for BTM
+*/
+#define BTM_TRACE_ERROR(...)                                      \
+  {                                                               \
+    if (btm_cb.trace_level >= BT_TRACE_LEVEL_ERROR)               \
+      BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+  }
+#define BTM_TRACE_WARNING(...)                                      \
+  {                                                                 \
+    if (btm_cb.trace_level >= BT_TRACE_LEVEL_WARNING)               \
+      BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+  }
+#define BTM_TRACE_API(...)                                      \
+  {                                                             \
+    if (btm_cb.trace_level >= BT_TRACE_LEVEL_API)               \
+      BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_API, ##__VA_ARGS__); \
+  }
+#define BTM_TRACE_EVENT(...)                                      \
+  {                                                               \
+    if (btm_cb.trace_level >= BT_TRACE_LEVEL_EVENT)               \
+      BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+  }
+#define BTM_TRACE_DEBUG(...)                                      \
+  {                                                               \
+    if (btm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG)               \
+      BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+  }
+
+/* Define tracing for the L2CAP unit
+*/
+#define L2CAP_TRACE_ERROR(...)                                      \
+  {                                                                 \
+    if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_ERROR)             \
+      BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+  }
+#define L2CAP_TRACE_WARNING(...)                                      \
+  {                                                                   \
+    if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_WARNING)             \
+      BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+  }
+#define L2CAP_TRACE_API(...)                                      \
+  {                                                               \
+    if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_API)             \
+      BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_API, ##__VA_ARGS__); \
+  }
+#define L2CAP_TRACE_EVENT(...)                                      \
+  {                                                                 \
+    if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_EVENT)             \
+      BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+  }
+#define L2CAP_TRACE_DEBUG(...)                                      \
+  {                                                                 \
+    if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_DEBUG)             \
+      BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+  }
+
+/* Define tracing for the SDP unit
+*/
+#define SDP_TRACE_ERROR(...)                                      \
+  {                                                               \
+    if (sdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR)               \
+      BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+  }
+#define SDP_TRACE_WARNING(...)                                      \
+  {                                                                 \
+    if (sdp_cb.trace_level >= BT_TRACE_LEVEL_WARNING)               \
+      BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+  }
+#define SDP_TRACE_API(...)                                      \
+  {                                                             \
+    if (sdp_cb.trace_level >= BT_TRACE_LEVEL_API)               \
+      BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_API, ##__VA_ARGS__); \
+  }
+#define SDP_TRACE_EVENT(...)                                      \
+  {                                                               \
+    if (sdp_cb.trace_level >= BT_TRACE_LEVEL_EVENT)               \
+      BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+  }
+#define SDP_TRACE_DEBUG(...)                                      \
+  {                                                               \
+    if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG)               \
+      BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+  }
+
+/* Define tracing for the RFCOMM unit
+*/
+#define RFCOMM_TRACE_ERROR(...)                                      \
+  {                                                                  \
+    if (rfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR)                  \
+      BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+  }
+#define RFCOMM_TRACE_WARNING(...)                                      \
+  {                                                                    \
+    if (rfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING)                  \
+      BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+  }
+#define RFCOMM_TRACE_API(...)                                      \
+  {                                                                \
+    if (rfc_cb.trace_level >= BT_TRACE_LEVEL_API)                  \
+      BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_API, ##__VA_ARGS__); \
+  }
+#define RFCOMM_TRACE_EVENT(...)                                      \
+  {                                                                  \
+    if (rfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT)                  \
+      BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+  }
+#define RFCOMM_TRACE_DEBUG(...)                                      \
+  {                                                                  \
+    if (rfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG)                  \
+      BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+  }
+
+/* Generic Access Profile traces */
+#define GAP_TRACE_ERROR(...)                                      \
+  {                                                               \
+    if (gap_cb.trace_level >= BT_TRACE_LEVEL_ERROR)               \
+      BT_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+  }
+#define GAP_TRACE_EVENT(...)                                      \
+  {                                                               \
+    if (gap_cb.trace_level >= BT_TRACE_LEVEL_EVENT)               \
+      BT_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+  }
+#define GAP_TRACE_API(...)                                      \
+  {                                                             \
+    if (gap_cb.trace_level >= BT_TRACE_LEVEL_API)               \
+      BT_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_API, ##__VA_ARGS__); \
+  }
+#define GAP_TRACE_WARNING(...)                                      \
+  {                                                                 \
+    if (gap_cb.trace_level >= BT_TRACE_LEVEL_WARNING)               \
+      BT_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+  }
+
+/* define traces for HID Host */
+#define HIDH_TRACE_ERROR(...)                                     \
+  {                                                               \
+    if (hh_cb.trace_level >= BT_TRACE_LEVEL_ERROR)                \
+      BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+  }
+#define HIDH_TRACE_WARNING(...)                                     \
+  {                                                                 \
+    if (hh_cb.trace_level >= BT_TRACE_LEVEL_WARNING)                \
+      BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+  }
+#define HIDH_TRACE_API(...)                                     \
+  {                                                             \
+    if (hh_cb.trace_level >= BT_TRACE_LEVEL_API)                \
+      BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_API, ##__VA_ARGS__); \
+  }
+#define HIDH_TRACE_EVENT(...)                                     \
+  {                                                               \
+    if (hh_cb.trace_level >= BT_TRACE_LEVEL_EVENT)                \
+      BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+  }
+#define HIDH_TRACE_DEBUG(...)                                     \
+  {                                                               \
+    if (hh_cb.trace_level >= BT_TRACE_LEVEL_DEBUG)                \
+      BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+  }
+
+/* define traces for BNEP */
+
+#define BNEP_TRACE_ERROR(...)                                      \
+  {                                                                \
+    if (bnep_cb.trace_level >= BT_TRACE_LEVEL_ERROR)               \
+      BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+  }
+#define BNEP_TRACE_WARNING(...)                                      \
+  {                                                                  \
+    if (bnep_cb.trace_level >= BT_TRACE_LEVEL_WARNING)               \
+      BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+  }
+#define BNEP_TRACE_API(...)                                      \
+  {                                                              \
+    if (bnep_cb.trace_level >= BT_TRACE_LEVEL_API)               \
+      BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_API, ##__VA_ARGS__); \
+  }
+#define BNEP_TRACE_EVENT(...)                                      \
+  {                                                                \
+    if (bnep_cb.trace_level >= BT_TRACE_LEVEL_EVENT)               \
+      BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+  }
+#define BNEP_TRACE_DEBUG(...)                                      \
+  {                                                                \
+    if (bnep_cb.trace_level >= BT_TRACE_LEVEL_DEBUG)               \
+      BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+  }
+
+/* define traces for PAN */
+
+#define PAN_TRACE_ERROR(...)                                      \
+  {                                                               \
+    if (pan_cb.trace_level >= BT_TRACE_LEVEL_ERROR)               \
+      BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+  }
+#define PAN_TRACE_WARNING(...)                                      \
+  {                                                                 \
+    if (pan_cb.trace_level >= BT_TRACE_LEVEL_WARNING)               \
+      BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+  }
+#define PAN_TRACE_API(...)                                      \
+  {                                                             \
+    if (pan_cb.trace_level >= BT_TRACE_LEVEL_API)               \
+      BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_API, ##__VA_ARGS__); \
+  }
+#define PAN_TRACE_EVENT(...)                                      \
+  {                                                               \
+    if (pan_cb.trace_level >= BT_TRACE_LEVEL_EVENT)               \
+      BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+  }
+#define PAN_TRACE_DEBUG(...)                                      \
+  {                                                               \
+    if (pan_cb.trace_level >= BT_TRACE_LEVEL_DEBUG)               \
+      BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+  }
+
+/* Define tracing for the A2DP profile
+*/
+#define A2DP_TRACE_ERROR(...)                                      \
+  {                                                                \
+    if (a2dp_cb.trace_level >= BT_TRACE_LEVEL_ERROR)               \
+      BT_TRACE(TRACE_LAYER_A2DP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+  }
+#define A2DP_TRACE_WARNING(...)                                      \
+  {                                                                  \
+    if (a2dp_cb.trace_level >= BT_TRACE_LEVEL_WARNING)               \
+      BT_TRACE(TRACE_LAYER_A2DP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+  }
+#define A2DP_TRACE_EVENT(...)                                      \
+  {                                                                \
+    if (a2dp_cb.trace_level >= BT_TRACE_LEVEL_EVENT)               \
+      BT_TRACE(TRACE_LAYER_A2DP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+  }
+#define A2DP_TRACE_DEBUG(...)                                      \
+  {                                                                \
+    if (a2dp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG)               \
+      BT_TRACE(TRACE_LAYER_A2DP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+  }
+#define A2DP_TRACE_API(...)                                      \
+  {                                                              \
+    if (a2dp_cb.trace_level >= BT_TRACE_LEVEL_API)               \
+      BT_TRACE(TRACE_LAYER_A2DP, TRACE_TYPE_API, ##__VA_ARGS__); \
+  }
+
+/* AVDTP
+*/
+#define AVDT_TRACE_ERROR(...)                                     \
+  {                                                               \
+    if (avdt_cb.trace_level >= BT_TRACE_LEVEL_ERROR)              \
+      BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+  }
+#define AVDT_TRACE_WARNING(...)                                     \
+  {                                                                 \
+    if (avdt_cb.trace_level >= BT_TRACE_LEVEL_WARNING)              \
+      BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+  }
+#define AVDT_TRACE_EVENT(...)                                     \
+  {                                                               \
+    if (avdt_cb.trace_level >= BT_TRACE_LEVEL_EVENT)              \
+      BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+  }
+#define AVDT_TRACE_DEBUG(...)                                     \
+  {                                                               \
+    if (avdt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG)              \
+      BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+  }
+#define AVDT_TRACE_API(...)                                     \
+  {                                                             \
+    if (avdt_cb.trace_level >= BT_TRACE_LEVEL_API)              \
+      BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__); \
+  }
+
+/* Define tracing for the AVCTP protocol
+*/
+#define AVCT_TRACE_ERROR(...)                                     \
+  {                                                               \
+    if (avct_cb.trace_level >= BT_TRACE_LEVEL_ERROR)              \
+      BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+  }
+#define AVCT_TRACE_WARNING(...)                                     \
+  {                                                                 \
+    if (avct_cb.trace_level >= BT_TRACE_LEVEL_WARNING)              \
+      BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+  }
+#define AVCT_TRACE_EVENT(...)                                     \
+  {                                                               \
+    if (avct_cb.trace_level >= BT_TRACE_LEVEL_EVENT)              \
+      BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+  }
+#define AVCT_TRACE_DEBUG(...)                                     \
+  {                                                               \
+    if (avct_cb.trace_level >= BT_TRACE_LEVEL_DEBUG)              \
+      BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+  }
+#define AVCT_TRACE_API(...)                                     \
+  {                                                             \
+    if (avct_cb.trace_level >= BT_TRACE_LEVEL_API)              \
+      BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__); \
+  }
+
+/* Define tracing for the AVRCP profile
+*/
+#define AVRC_TRACE_ERROR(...)                                     \
+  {                                                               \
+    if (avrc_cb.trace_level >= BT_TRACE_LEVEL_ERROR)              \
+      BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+  }
+#define AVRC_TRACE_WARNING(...)                                     \
+  {                                                                 \
+    if (avrc_cb.trace_level >= BT_TRACE_LEVEL_WARNING)              \
+      BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+  }
+#define AVRC_TRACE_EVENT(...)                                     \
+  {                                                               \
+    if (avrc_cb.trace_level >= BT_TRACE_LEVEL_EVENT)              \
+      BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+  }
+#define AVRC_TRACE_DEBUG(...)                                     \
+  {                                                               \
+    if (avrc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG)              \
+      BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+  }
+#define AVRC_TRACE_API(...)                                     \
+  {                                                             \
+    if (avrc_cb.trace_level >= BT_TRACE_LEVEL_API)              \
+      BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__); \
+  }
+
+/* MCAP
+*/
+#define MCA_TRACE_ERROR(...)                                      \
+  {                                                               \
+    if (mca_cb.trace_level >= BT_TRACE_LEVEL_ERROR)               \
+      BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+  }
+#define MCA_TRACE_WARNING(...)                                      \
+  {                                                                 \
+    if (mca_cb.trace_level >= BT_TRACE_LEVEL_WARNING)               \
+      BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+  }
+#define MCA_TRACE_EVENT(...)                                      \
+  {                                                               \
+    if (mca_cb.trace_level >= BT_TRACE_LEVEL_EVENT)               \
+      BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+  }
+#define MCA_TRACE_DEBUG(...)                                      \
+  {                                                               \
+    if (mca_cb.trace_level >= BT_TRACE_LEVEL_DEBUG)               \
+      BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+  }
+#define MCA_TRACE_API(...)                                      \
+  {                                                             \
+    if (mca_cb.trace_level >= BT_TRACE_LEVEL_API)               \
+      BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_API, ##__VA_ARGS__); \
+  }
+
+/* Define tracing for the ATT/GATT unit
+*/
+#define GATT_TRACE_ERROR(...)                                     \
+  {                                                               \
+    if (gatt_cb.trace_level >= BT_TRACE_LEVEL_ERROR)              \
+      BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+  }
+#define GATT_TRACE_WARNING(...)                                     \
+  {                                                                 \
+    if (gatt_cb.trace_level >= BT_TRACE_LEVEL_WARNING)              \
+      BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+  }
+#define GATT_TRACE_API(...)                                     \
+  {                                                             \
+    if (gatt_cb.trace_level >= BT_TRACE_LEVEL_API)              \
+      BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_API, ##__VA_ARGS__); \
+  }
+#define GATT_TRACE_EVENT(...)                                     \
+  {                                                               \
+    if (gatt_cb.trace_level >= BT_TRACE_LEVEL_EVENT)              \
+      BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+  }
+#define GATT_TRACE_DEBUG(...)                                     \
+  {                                                               \
+    if (gatt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG)              \
+      BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+  }
+
+/* Define tracing for the SMP unit
+*/
+#define SMP_TRACE_ERROR(...)                                      \
+  {                                                               \
+    if (smp_cb.trace_level >= BT_TRACE_LEVEL_ERROR)               \
+      BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+  }
+#define SMP_TRACE_WARNING(...)                                      \
+  {                                                                 \
+    if (smp_cb.trace_level >= BT_TRACE_LEVEL_WARNING)               \
+      BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+  }
+#define SMP_TRACE_API(...)                                      \
+  {                                                             \
+    if (smp_cb.trace_level >= BT_TRACE_LEVEL_API)               \
+      BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_API, ##__VA_ARGS__); \
+  }
+#define SMP_TRACE_EVENT(...)                                      \
+  {                                                               \
+    if (smp_cb.trace_level >= BT_TRACE_LEVEL_EVENT)               \
+      BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+  }
+#define SMP_TRACE_DEBUG(...)                                      \
+  {                                                               \
+    if (smp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG)               \
+      BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+  }
+
+extern uint8_t btif_trace_level;
+
+/* define traces for application */
+#define BTIF_TRACE_ERROR(...)                                         \
+  {                                                                   \
+    if (btif_trace_level >= BT_TRACE_LEVEL_ERROR)                     \
+      LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+                 TRACE_TYPE_ERROR,                                    \
+             ##__VA_ARGS__);                                          \
+  }
+#define BTIF_TRACE_WARNING(...)                                       \
+  {                                                                   \
+    if (btif_trace_level >= BT_TRACE_LEVEL_WARNING)                   \
+      LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+                 TRACE_TYPE_WARNING,                                  \
+             ##__VA_ARGS__);                                          \
+  }
+#define BTIF_TRACE_API(...)                                           \
+  {                                                                   \
+    if (btif_trace_level >= BT_TRACE_LEVEL_API)                       \
+      LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+                 TRACE_TYPE_API,                                      \
+             ##__VA_ARGS__);                                          \
+  }
+#define BTIF_TRACE_EVENT(...)                                         \
+  {                                                                   \
+    if (btif_trace_level >= BT_TRACE_LEVEL_EVENT)                     \
+      LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+                 TRACE_TYPE_EVENT,                                    \
+             ##__VA_ARGS__);                                          \
+  }
+#define BTIF_TRACE_DEBUG(...)                                         \
+  {                                                                   \
+    if (btif_trace_level >= BT_TRACE_LEVEL_DEBUG)                     \
+      LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+                 TRACE_TYPE_DEBUG,                                    \
+             ##__VA_ARGS__);                                          \
+  }
+#define BTIF_TRACE_VERBOSE(...)                                       \
+  {                                                                   \
+    if (btif_trace_level >= BT_TRACE_LEVEL_VERBOSE)                   \
+      LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+                 TRACE_TYPE_DEBUG,                                    \
+             ##__VA_ARGS__);                                          \
+  }
+
+/* define traces for application */
+#define APPL_TRACE_ERROR(...)                                         \
+  {                                                                   \
+    if (appl_trace_level >= BT_TRACE_LEVEL_ERROR)                     \
+      LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+                 TRACE_TYPE_ERROR,                                    \
+             ##__VA_ARGS__);                                          \
+  }
+#define APPL_TRACE_WARNING(...)                                       \
+  {                                                                   \
+    if (appl_trace_level >= BT_TRACE_LEVEL_WARNING)                   \
+      LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+                 TRACE_TYPE_WARNING,                                  \
+             ##__VA_ARGS__);                                          \
+  }
+#define APPL_TRACE_API(...)                                           \
+  {                                                                   \
+    if (appl_trace_level >= BT_TRACE_LEVEL_API)                       \
+      LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+                 TRACE_TYPE_API,                                      \
+             ##__VA_ARGS__);                                          \
+  }
+#define APPL_TRACE_EVENT(...)                                         \
+  {                                                                   \
+    if (appl_trace_level >= BT_TRACE_LEVEL_EVENT)                     \
+      LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+                 TRACE_TYPE_EVENT,                                    \
+             ##__VA_ARGS__);                                          \
+  }
+#define APPL_TRACE_DEBUG(...)                                         \
+  {                                                                   \
+    if (appl_trace_level >= BT_TRACE_LEVEL_DEBUG)                     \
+      LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+                 TRACE_TYPE_DEBUG,                                    \
+             ##__VA_ARGS__);                                          \
+  }
+#define APPL_TRACE_VERBOSE(...)                                       \
+  {                                                                   \
+    if (appl_trace_level >= BT_TRACE_LEVEL_VERBOSE)                   \
+      LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+                 TRACE_TYPE_DEBUG,                                    \
+             ##__VA_ARGS__);                                          \
+  }
+
+typedef uint8_t tBTTRC_LAYER_ID;
+typedef uint8_t(tBTTRC_SET_TRACE_LEVEL)(uint8_t);
+
+typedef struct {
+  const tBTTRC_LAYER_ID layer_id_start;
+  const tBTTRC_LAYER_ID layer_id_end;
+  tBTTRC_SET_TRACE_LEVEL* p_f;
+  const char* trc_name;
+  uint8_t trace_level;
+} tBTTRC_FUNC_MAP;
+
+/* External declaration for appl_trace_level here to avoid to add the
+ * declaration in all the files using APPL_TRACExxx macros */
+extern uint8_t appl_trace_level;
+
+void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/include/bte.h b/bt/include/bte.h
new file mode 100644
index 0000000..3436565
--- /dev/null
+++ b/bt/include/bte.h
@@ -0,0 +1,138 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2001-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 constants and definitions for the bte project
+ *
+ ******************************************************************************/
+#ifndef BTE_H
+#define BTE_H
+
+#include <pthread.h>
+#include <semaphore.h>
+#include <signal.h>
+#include "bt_target.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* By default on shutdown, the baud rate is reset to 115kbits. This should NOT
+ * be needed for platforms that kill the BTE driver and remove/reset BT chip.
+ */
+#ifndef BTE_RESET_BAUD_ON_BT_DISABLE
+#define BTE_RESET_BAUD_ON_BT_DISABLE TRUE
+#endif
+
+/* Target Modes (based on jumper settings on hardware [see user manual])
+ *                           BTE                  BBY
+ *                           J3   J4              SW3-3   SW3-2   SW3-1
+ *                          --------------------------------------------
+ * BTE_MODE_SERIAL_APP,      OUT  OUT             OFF     OFF     OFF
+ * BTE_MODE_APPL,            IN   OUT             OFF     OFF     ON
+ * BTE_MODE_RESERVED,        OUT  IN              OFF     ON      OFF
+ * BTE_MODE_SAMPLE_APPS,     IN   IN              OFF     ON      ON
+ * BTE_MODE_DONGLE,          not yet supported    ON      OFF     OFF
+ * BTE_MODE_APPL_PROTOCOL_TRACE,     * this is a fake mode *
+ * BTE_MODE_INVALID
+ */
+enum {
+  BTE_MODE_SERIAL_APP,          /* Sample serial port application      */
+  BTE_MODE_APPL,                /* Target used with Tester through RPC */
+  BTE_MODE_RESERVED,            /* Reserved                            */
+  BTE_MODE_SAMPLE_APPS,         /* Sample applications (ICP/HSP)       */
+  BTE_MODE_DONGLE,              /* Dongle mode                         */
+  BTE_MODE_APPL_PROTOCOL_TRACE, /* Allow protocol tracing without rpc */
+  BTE_MODE_INVALID
+};
+
+extern volatile uint8_t
+    bte_target_mode; /* indicates the mode that the board is running in */
+
+/* Startup options */
+extern uint32_t bte_startup_options; /* Switch and jumper settings at startup */
+void bte_get_startup_options(
+    uint32_t*
+        p_options); /* Platform specific function for getting startup options */
+
+#define BTE_OPTIONS_TARGET_MODE_MASK                                         \
+  0x00000007 /* bits 2-0 indicate target mode (QuickConnect: jp3 & jp4, BBY: \
+                SW3-1 & SW3-2)*/
+
+/****************************************************************************
+ * Definitions to define which type of application gets built
+ ****************************************************************************/
+#define BUILD_HCITOOL FALSE
+#define BUILD_L2PING FALSE
+
+#define LINUX_FM_DRIVER_INCLUDED FALSE
+
+/* hcisu userial operations. should probably go into bt_types to avoid
+ * collisions! */
+#define BT_EVT_TO_HCISU_USERIAL_OP (0x0080 | BT_EVT_HCISU)
+/* operation for above hcisu event */
+#define BT_HCISU_USERIAL_OPEN (0)  /* open serial port calling USERIAL_Open() \
+                                      */
+#define BT_HCISU_USERIAL_CLOSE (1) /* close userial port */
+/* options associated with close op */
+#define BT_HCISU_USERIAL_CL_NO_DIS_BT \
+  0 /* do not touch bt_wake and power gpio */
+#define BT_HCISU_USERIAL_CL_DIS_BT                              \
+  1 /* put power and bt_wake into defined off state to preserve \
+       power */
+/* status codes for callback */
+#define BTE_HCISU_USERIAL_FAIL 0
+#define BTE_HCISU_USERIAL_OK 1
+typedef void(tUSERIAL_MSG_CBACK)(int status);
+typedef struct tHCISU_USERIAL_MSG_tag {
+  BT_HDR hdr;
+  tUSERIAL_MSG_CBACK* p_cback;
+  uint8_t port; /* port number */
+  uint8_t op;
+  uint8_t option; /* option for operation. depends on operation */
+} tHCISU_USERIAL_MSG;
+
+extern void bte_hcisu_userial_oper(tUSERIAL_MSG_CBACK* p_cback, uint8_t port,
+                                   uint8_t op, uint8_t option);
+
+/* Pointer to function for sending HCI commands and data to the HCI tranport */
+extern int (*p_bte_hci_send)(uint16_t port, BT_HDR* p_msg);
+
+// Initialize control block memory for each stack component.
+extern void BTE_InitStack(void);
+
+/* Protocol trace mask */
+extern uint32_t bte_proto_trace_mask;
+
+typedef struct tBAUD_REG_tag {
+  uint8_t DHBR;
+  uint8_t DLBR;
+  uint8_t ExplicitBaudRate0;
+  uint8_t ExplicitBaudRate1;
+  uint8_t ExplicitBaudRate2;
+  uint8_t ExplicitBaudRate3;
+} tBAUD_REG;
+
+extern const tBAUD_REG baud_rate_regs[];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTE_H */
diff --git a/bt/include/bte_appl.h b/bt/include/bte_appl.h
new file mode 100644
index 0000000..e872f33
--- /dev/null
+++ b/bt/include/bte_appl.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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 is the interface file for the bte application task
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+  uint8_t ble_auth_req;
+  uint8_t ble_io_cap;
+  uint8_t ble_init_key;
+  uint8_t ble_resp_key;
+  uint8_t ble_max_key_size;
+#endif
+} tBTE_APPL_CFG;
+
+extern tBTE_APPL_CFG bte_appl_cfg;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/include/stack_config.h b/bt/include/stack_config.h
new file mode 100644
index 0000000..ae6d2ab
--- /dev/null
+++ b/bt/include/stack_config.h
@@ -0,0 +1,49 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+
+#include "module.h"
+#include "osi/include/config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static const char STACK_CONFIG_MODULE[] = "stack_config_module";
+
+typedef struct {
+  const char* (*get_btsnoop_log_path)(void);
+  bool (*get_btsnoop_turned_on)(void);
+  bool (*get_btsnoop_should_save_last)(void);
+  bool (*get_trace_config_enabled)(void);
+  bool (*get_pts_secure_only_mode)(void);
+  bool (*get_pts_conn_updates_disabled)(void);
+  bool (*get_pts_crosskey_sdp_disable)(void);
+  const char* (*get_pts_smp_options)(void);
+  int (*get_pts_smp_failure_case)(void);
+  config_t* (*get_all)(void);
+} stack_config_t;
+
+const stack_config_t* stack_config_get_interface(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/main/Android.mk b/bt/main/Android.mk
new file mode 100644
index 0000000..75c7a3a
--- /dev/null
+++ b/bt/main/Android.mk
@@ -0,0 +1,125 @@
+LOCAL_PATH:= $(call my-dir)
+
+# Bluetooth main HW module / shared library for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_CPP_EXTENSION := .cc
+
+#
+# Workaround for libchrome and -DNDEBUG usage.
+#
+# Test whether the original TARGET_GLOBAL_CFLAGS contains -DNDEBUG.
+# This is needed as a workaround to make sure that
+# libchrome and local files calling logging::InitLogging()
+# are consistent with the usage of -DNDEBUG .
+# ========================================================
+ifneq (,$(findstring NDEBUG,$(TARGET_GLOBAL_CFLAGS)))
+  btmain_orig_TARGET_NDEBUG := -DBT_LIBCHROME_NDEBUG
+else
+  btmain_orig_TARGET_NDEBUG :=
+endif
+
+# platform specific
+LOCAL_SRC_FILES := \
+    bte_conf.cc \
+    bte_init.cc \
+    bte_init_cpp_logging.cc \
+    bte_logmsg.cc \
+    bte_main.cc \
+    stack_config.cc
+
+# sbc encoder
+LOCAL_SRC_FILES += \
+    ../embdrv/sbc/encoder/srce/sbc_analysis.c \
+    ../embdrv/sbc/encoder/srce/sbc_dct.c \
+    ../embdrv/sbc/encoder/srce/sbc_dct_coeffs.c \
+    ../embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c \
+    ../embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c \
+    ../embdrv/sbc/encoder/srce/sbc_enc_coeffs.c \
+    ../embdrv/sbc/encoder/srce/sbc_encoder.c \
+    ../embdrv/sbc/encoder/srce/sbc_packing.c \
+
+LOCAL_SRC_FILES += \
+    ../udrv/ulinux/uipc.cc
+
+LOCAL_C_INCLUDES := . \
+    $(LOCAL_PATH)/../ \
+    $(LOCAL_PATH)/../bta/include \
+    $(LOCAL_PATH)/../bta/sys \
+    $(LOCAL_PATH)/../bta/dm \
+    $(LOCAL_PATH)/../btcore/include \
+    $(LOCAL_PATH)/../include \
+    $(LOCAL_PATH)/../stack/include \
+    $(LOCAL_PATH)/../stack/l2cap \
+    $(LOCAL_PATH)/../stack/a2dp \
+    $(LOCAL_PATH)/../stack/btm \
+    $(LOCAL_PATH)/../stack/avdt \
+    $(LOCAL_PATH)/../hcis \
+    $(LOCAL_PATH)/../hcis/include \
+    $(LOCAL_PATH)/../hcis/patchram \
+    $(LOCAL_PATH)/../udrv/include \
+    $(LOCAL_PATH)/../btif/include \
+    $(LOCAL_PATH)/../btif/co \
+    $(LOCAL_PATH)/../hci/include\
+    $(LOCAL_PATH)/../vnd/include \
+    $(LOCAL_PATH)/../brcm/include \
+    $(LOCAL_PATH)/../embdrv/sbc/encoder/include \
+    $(LOCAL_PATH)/../embdrv/sbc/decoder/include \
+    $(LOCAL_PATH)/../audio_a2dp_hw \
+    $(LOCAL_PATH)/../utils/include \
+    $(bluetooth_C_INCLUDES) \
+    external/tinyxml2 \
+    external/zlib
+
+LOCAL_SHARED_LIBRARIES := \
+    libcutils \
+    libdl \
+    liblog \
+    libz \
+    libpower \
+    libprotobuf-cpp-lite \
+    libmedia \
+    libutils \
+    libchrome
+
+LOCAL_STATIC_LIBRARIES := \
+    libtinyxml2 \
+    libbt-qcom_sbc_decoder
+
+LOCAL_WHOLE_STATIC_LIBRARIES := \
+    libbt-bta \
+    libbtdevice \
+    libbtif \
+    libbt-hci \
+    libbt-protos \
+    libbt-stack \
+    libbt-utils \
+    libbtcore \
+    libosi
+
+LOCAL_MODULE := bluetooth.default
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+
+#
+# Shared library link options.
+# References to global symbols and functions should bind to the library
+# itself. This is to avoid issues with some of the unit/system tests
+# that might link statically with some of the code in the library, and
+# also dlopen(3) the shared library.
+#
+LOCAL_LDLIBS := -Wl,-Bsymbolic,-Bsymbolic-functions
+
+LOCAL_REQUIRED_MODULES := \
+    bt_did.conf \
+    bt_stack.conf \
+    libbt-hci \
+    libbt-vendor
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS) -DBUILDCFG $(btmain_orig_TARGET_NDEBUG)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/bt/main/BUILD.gn b/bt/main/BUILD.gn
new file mode 100644
index 0000000..957068c
--- /dev/null
+++ b/bt/main/BUILD.gn
@@ -0,0 +1,86 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+shared_library("bluetooth.default") {
+  # HAL layer
+  sources = [
+    "//btif/src/bluetooth.cc",
+  ]
+
+  # platform specific
+  sources += [
+    "bte_conf.cc",
+    "bte_init.cc",
+    "bte_init_cpp_logging.cc",
+    "bte_logmsg.cc",
+    "bte_main.cc",
+    "stack_config.cc",
+  ]
+
+  include_dirs = [
+    "//",
+    "//bta/include",
+    "//bta/sys",
+    "//bta/dm",
+    "//btcore/include",
+    "//include",
+    "//stack/include",
+    "//stack/l2cap",
+    "//stack/a2dp",
+    "//stack/btm",
+    "//stack/avdt",
+    "//hci",
+    "//hci/include",
+    "//udrv/include",
+    "//btif/include",
+    "//btif/co",
+    "//hci/includ",
+    "//vnd/include",
+    "//brcm/include",
+    "//embdrv/sbc/encoder/include",
+    "//embdrv/sbc/decoder/include",
+    "//utils/include",
+    "//test/suite",
+  ]
+
+  deps = [
+    "//bta",
+    "//btcore",
+    "//btif",
+    "//device",
+    "//embdrv/sbc",
+    "//hci",
+    "//osi",
+    "//stack",
+    "//third_party/libchrome:base",
+    "//third_party/tinyxml2",
+    "//udrv",
+    "//utils",
+  ]
+
+  cflags_c = [
+    "-Lobj/osi",
+    "-losi",
+  ]
+  libs = [
+    "-ldl",
+    "-lpthread",
+    "-lresolv",
+    "-lrt",
+    "-lz",
+    "-latomic",
+  ]
+}
diff --git a/bt/main/bte_conf.cc b/bt/main/bte_conf.cc
new file mode 100644
index 0000000..655094a
--- /dev/null
+++ b/bt/main/bte_conf.cc
@@ -0,0 +1,85 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bte_conf"
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bta_api.h"
+#include "btif_common.h"
+#include "osi/include/compat.h"
+#include "osi/include/config.h"
+#include "osi/include/log.h"
+
+// Parses the specified Device ID configuration file and registers the
+// Device ID records with SDP.
+void bte_load_did_conf(const char *p_path) {
+    assert(p_path != NULL);
+
+    config_t *config = config_new(p_path);
+    if (!config) {
+        LOG_ERROR(LOG_TAG, "%s unable to load DID config '%s'.", __func__, p_path);
+        return;
+    }
+
+    for (int i = 1; i <= BTA_DI_NUM_MAX; ++i) {
+        char section_name[16] = { 0 };
+        snprintf(section_name, sizeof(section_name), "DID%d", i);
+
+        if (!config_has_section(config, section_name)) {
+            LOG_DEBUG(LOG_TAG, "%s no section named %s.", __func__, section_name);
+            break;
+        }
+
+        tBTA_DI_RECORD record;
+        record.vendor = config_get_int(config, section_name, "vendorId", LMP_COMPID_BROADCOM);
+        record.vendor_id_source = config_get_int(config, section_name, "vendorIdSource", DI_VENDOR_ID_SOURCE_BTSIG);
+        record.product = config_get_int(config, section_name, "productId", 0);
+        record.version = config_get_int(config, section_name, "version", 0);
+        record.primary_record = config_get_bool(config, section_name, "primaryRecord", false);
+        strlcpy(record.client_executable_url, config_get_string(config, section_name, "clientExecutableURL", ""), sizeof(record.client_executable_url));
+        strlcpy(record.service_description, config_get_string(config, section_name, "serviceDescription", ""), sizeof(record.service_description));
+        strlcpy(record.documentation_url, config_get_string(config, section_name, "documentationURL", ""), sizeof(record.documentation_url));
+
+        if (record.vendor_id_source != DI_VENDOR_ID_SOURCE_BTSIG &&
+            record.vendor_id_source != DI_VENDOR_ID_SOURCE_USBIF) {
+            LOG_ERROR(LOG_TAG, "%s invalid vendor id source %d; ignoring DID record %d.", __func__, record.vendor_id_source, i);
+            continue;
+        }
+
+        LOG_DEBUG(LOG_TAG, "Device ID record %d : %s", i, (record.primary_record ? "primary" : "not primary"));
+        LOG_DEBUG(LOG_TAG, "  vendorId            = %04x", record.vendor);
+        LOG_DEBUG(LOG_TAG, "  vendorIdSource      = %04x", record.vendor_id_source);
+        LOG_DEBUG(LOG_TAG, "  product             = %04x", record.product);
+        LOG_DEBUG(LOG_TAG, "  version             = %04x", record.version);
+        LOG_DEBUG(LOG_TAG, "  clientExecutableURL = %s", record.client_executable_url);
+        LOG_DEBUG(LOG_TAG, "  serviceDescription  = %s", record.service_description);
+        LOG_DEBUG(LOG_TAG, "  documentationURL    = %s", record.documentation_url);
+
+        uint32_t record_handle;
+        tBTA_STATUS status = BTA_DmSetLocalDiRecord(&record, &record_handle);
+        if (status != BTA_SUCCESS) {
+            LOG_ERROR(LOG_TAG, "%s unable to set device ID record %d: error %d.", __func__, i, status);
+        }
+    }
+
+    config_free(config);
+}
+
diff --git a/bt/main/bte_init.cc b/bt/main/bte_init.cc
new file mode 100644
index 0000000..751acaa
--- /dev/null
+++ b/bt/main/bte_init.cc
@@ -0,0 +1,129 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2000-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 module contains the routines that initialize the stack components.
+ *  It must be called before the BTU task is started.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+#include <string.h>
+
+#ifndef BTA_INCLUDED
+#define BTA_INCLUDED FALSE
+#endif
+
+#include "bte.h"
+
+/* Include initialization functions definitions */
+#include "port_api.h"
+
+#if (BNEP_INCLUDED == TRUE)
+#include "bnep_api.h"
+#endif
+
+#include "gap_api.h"
+
+#if (PAN_INCLUDED == TRUE)
+#include "pan_api.h"
+#endif
+
+#include "avrc_api.h"
+
+#if (A2D_INCLUDED == TRUE)
+#include "a2dp_api.h"
+#endif
+
+#if (HID_HOST_INCLUDED == TRUE)
+#include "hidh_api.h"
+#endif
+
+#if (MCA_INCLUDED == TRUE)
+#include "mca_api.h"
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+#include "gatt_api.h"
+#if (SMP_INCLUDED == TRUE)
+#include "smp_api.h"
+#endif
+#endif
+
+/*****************************************************************************
+**                          F U N C T I O N S                                *
+******************************************************************************/
+
+/*****************************************************************************
+**
+** Function         BTE_InitStack
+**
+** Description      Initialize control block memory for each component.
+**
+**                  Note: The core stack components must be called
+**                      before creating the BTU Task.  The rest of the
+**                      components can be initialized at a later time if desired
+**                      as long as the component's init function is called
+**                      before accessing any of its functions.
+**
+** Returns          void
+**
+******************************************************************************/
+void BTE_InitStack(void)
+{
+/* Initialize the optional stack components */
+    RFCOMM_Init();
+
+/**************************
+** BNEP and its profiles **
+***************************/
+#if (BNEP_INCLUDED == TRUE)
+    BNEP_Init();
+
+#if (PAN_INCLUDED == TRUE)
+    PAN_Init();
+#endif  /* PAN */
+#endif  /* BNEP Included */
+
+
+/**************************
+** AVDT and its profiles **
+***************************/
+#if (A2D_INCLUDED == TRUE)
+    A2DP_Init();
+#endif  /* AADP */
+
+
+    AVRC_Init();
+
+
+/***********
+** Others **
+************/
+    GAP_Init();
+
+#if (HID_HOST_INCLUDED == TRUE)
+    HID_HostInit();
+#endif
+
+#if (MCA_INCLUDED == TRUE)
+    MCA_Init();
+#endif
+
+}
diff --git a/bt/main/bte_init_cpp_logging.cc b/bt/main/bte_init_cpp_logging.cc
new file mode 100644
index 0000000..cd531bb
--- /dev/null
+++ b/bt/main/bte_init_cpp_logging.cc
@@ -0,0 +1,60 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifdef BT_LIBCHROME_NDEBUG
+#define NDEBUG 1
+#endif
+
+#include <base/command_line.h>
+#include "main_int.h"
+
+void init_cpp_logging(config_t *config) {
+  // Command line and log level might be also configured in service/main.cpp
+  // when running the bluetoothtbd daemon. If it's already configured, skip
+  // configuring.
+  if (base::CommandLine::InitializedForCurrentProcess()) return;
+
+  const char *loggingV =
+      config_get_string(config, CONFIG_DEFAULT_SECTION, "LoggingV", NULL);
+  const char *loggingVModule =
+      config_get_string(config, CONFIG_DEFAULT_SECTION, "LoggingVModule", NULL);
+
+  int argc = 1;
+  const char *argv[] = {"bt_stack", NULL, NULL};
+
+  if (loggingV != NULL) {
+    argv[argc] = loggingV;
+    argc++;
+  }
+
+  if (loggingVModule != NULL) {
+    argv[argc] = loggingVModule;
+    argc++;
+  }
+
+  // Init command line object with logging switches
+  base::CommandLine::Init(argc, argv);
+
+  logging::LoggingSettings log_settings;
+  if (!logging::InitLogging(log_settings)) {
+    LOG(ERROR) << "Failed to set up logging";
+  }
+
+  // Android already logs thread_id, proc_id, timestamp, so disable those.
+  logging::SetLogItems(false, false, false, false);
+}
\ No newline at end of file
diff --git a/bt/main/bte_logmsg.cc b/bt/main/bte_logmsg.cc
new file mode 100644
index 0000000..c23d0cf
--- /dev/null
+++ b/bt/main/bte_logmsg.cc
@@ -0,0 +1,258 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2001-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.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bte"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "avrc_api.h"
+#include "bta_api.h"
+#include "bte.h"
+#include "btm_api.h"
+#include "btu.h"
+#include "gap_api.h"
+#include "bt_common.h"
+#include "l2c_api.h"
+#include "osi/include/config.h"
+#include "osi/include/log.h"
+#include "osi/include/log.h"
+#include "port_api.h"
+#include "sdp_api.h"
+#include "stack_config.h"
+#include "main_int.h"
+
+#if (AVDT_INCLUDED == TRUE)
+#include "avdt_api.h"
+#endif
+#if (A2D_INCLUDED == TRUE)
+#include "a2dp_api.h"
+#endif
+#if (BNEP_INCLUDED == TRUE)
+#include "bnep_api.h"
+#endif
+#if (PAN_INCLUDED == TRUE)
+#include "pan_api.h"
+#endif
+#if (BLE_INCLUDED == TRUE)
+#include "gatt_api.h"
+#include "smp_api.h"
+#endif
+
+#ifndef DEFAULT_CONF_TRACE_LEVEL
+#define DEFAULT_CONF_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef BTE_LOG_BUF_SIZE
+#define BTE_LOG_BUF_SIZE  1024
+#endif
+
+#define BTE_LOG_MAX_SIZE  (BTE_LOG_BUF_SIZE - 12)
+
+#define MSG_BUFFER_OFFSET 0
+
+/* LayerIDs for BTA, currently everything maps onto appl_trace_level */
+static const char * const bt_layer_tags[] = {
+  "bt_btif",
+  "bt_usb",
+  "bt_serial",
+  "bt_socket",
+  "bt_rs232",
+  "bt_lc",
+  "bt_lm",
+  "bt_hci",
+  "bt_l2cap",
+  "bt_rfcomm",
+  "bt_sdp",
+  "bt_tcs",
+  "bt_obex",
+  "bt_btm",
+  "bt_gap",
+  "UNUSED",
+  "UNUSED",
+  "bt_icp",
+  "bt_hsp2",
+  "bt_spp",
+  "bt_ctp",
+  "bt_bpp",
+  "bt_hcrp",
+  "bt_ftp",
+  "bt_opp",
+  "bt_btu",
+  "bt_gki",                             /* OBSOLETED */
+  "bt_bnep",
+  "bt_pan",
+  "bt_hfp",
+  "bt_hid",
+  "bt_bip",
+  "bt_avp",
+  "bt_a2d",
+  "bt_sap",
+  "bt_amp",
+  "bt_mca",
+  "bt_att",
+  "bt_smp",
+  "bt_nfc",
+  "bt_nci",
+  "bt_idep",
+  "bt_ndep",
+  "bt_llcp",
+  "bt_rw",
+  "bt_ce",
+  "bt_snep",
+  "bt_ndef",
+  "bt_nfa",
+};
+static uint8_t BTAPP_SetTraceLevel(uint8_t new_level);
+static uint8_t BTIF_SetTraceLevel(uint8_t new_level);
+static uint8_t BTU_SetTraceLevel(uint8_t new_level);
+
+/* make sure list is order by increasing layer id!!! */
+static tBTTRC_FUNC_MAP bttrc_set_level_map[] = {
+  {BTTRC_ID_STK_BTU, BTTRC_ID_STK_HCI, BTU_SetTraceLevel, "TRC_HCI", DEFAULT_CONF_TRACE_LEVEL},
+  {BTTRC_ID_STK_L2CAP, BTTRC_ID_STK_L2CAP, L2CA_SetTraceLevel, "TRC_L2CAP", DEFAULT_CONF_TRACE_LEVEL},
+  {BTTRC_ID_STK_RFCOMM, BTTRC_ID_STK_RFCOMM_DATA, PORT_SetTraceLevel, "TRC_RFCOMM", DEFAULT_CONF_TRACE_LEVEL},
+#if (AVDT_INCLUDED == TRUE)
+  {BTTRC_ID_STK_AVDT, BTTRC_ID_STK_AVDT, AVDT_SetTraceLevel, "TRC_AVDT", DEFAULT_CONF_TRACE_LEVEL},
+#endif
+  {BTTRC_ID_STK_AVRC, BTTRC_ID_STK_AVRC, AVRC_SetTraceLevel, "TRC_AVRC", DEFAULT_CONF_TRACE_LEVEL},
+#if (AVDT_INCLUDED == TRUE)
+  //{BTTRC_ID_AVDT_SCB, BTTRC_ID_AVDT_CCB, NULL, "TRC_AVDT_SCB", DEFAULT_CONF_TRACE_LEVEL},
+#endif
+#if (A2D_INCLUDED == TRUE)
+  {BTTRC_ID_STK_A2DP, BTTRC_ID_STK_A2DP, A2DP_SetTraceLevel, "TRC_A2D", DEFAULT_CONF_TRACE_LEVEL},
+#endif
+#if (BNEP_INCLUDED == TRUE)
+  {BTTRC_ID_STK_BNEP, BTTRC_ID_STK_BNEP, BNEP_SetTraceLevel, "TRC_BNEP", DEFAULT_CONF_TRACE_LEVEL},
+#endif
+  {BTTRC_ID_STK_BTM_ACL, BTTRC_ID_STK_BTM_SEC, BTM_SetTraceLevel, "TRC_BTM", DEFAULT_CONF_TRACE_LEVEL},
+  {BTTRC_ID_STK_GAP, BTTRC_ID_STK_GAP, GAP_SetTraceLevel, "TRC_GAP", DEFAULT_CONF_TRACE_LEVEL},
+#if (PAN_INCLUDED == TRUE)
+  {BTTRC_ID_STK_PAN, BTTRC_ID_STK_PAN, PAN_SetTraceLevel, "TRC_PAN", DEFAULT_CONF_TRACE_LEVEL},
+#endif
+  {BTTRC_ID_STK_SDP, BTTRC_ID_STK_SDP, SDP_SetTraceLevel, "TRC_SDP", DEFAULT_CONF_TRACE_LEVEL},
+#if (BLE_INCLUDED == TRUE)
+  {BTTRC_ID_STK_GATT, BTTRC_ID_STK_GATT, GATT_SetTraceLevel, "TRC_GATT", DEFAULT_CONF_TRACE_LEVEL},
+  {BTTRC_ID_STK_SMP, BTTRC_ID_STK_SMP, SMP_SetTraceLevel, "TRC_SMP", DEFAULT_CONF_TRACE_LEVEL},
+#endif
+
+  /* LayerIDs for BTA, currently everything maps onto appl_trace_level.
+   */
+  {BTTRC_ID_BTA_ACC, BTTRC_ID_BTAPP, BTAPP_SetTraceLevel, "TRC_BTAPP", DEFAULT_CONF_TRACE_LEVEL},
+  {BTTRC_ID_BTA_ACC, BTTRC_ID_BTAPP, BTIF_SetTraceLevel, "TRC_BTIF", DEFAULT_CONF_TRACE_LEVEL},
+
+  {0, 0, NULL, NULL, DEFAULT_CONF_TRACE_LEVEL}
+};
+
+void LogMsg(uint32_t trace_set_mask, const char *fmt_str, ...) {
+  static char buffer[BTE_LOG_BUF_SIZE];
+  int trace_layer = TRACE_GET_LAYER(trace_set_mask);
+  if (trace_layer >= TRACE_LAYER_MAX_NUM)
+    trace_layer = 0;
+
+  va_list ap;
+  va_start(ap, fmt_str);
+  vsnprintf(&buffer[MSG_BUFFER_OFFSET], BTE_LOG_MAX_SIZE, fmt_str, ap);
+  va_end(ap);
+
+  switch ( TRACE_GET_TYPE(trace_set_mask) ) {
+    case TRACE_TYPE_ERROR:
+      LOG_ERROR(bt_layer_tags[trace_layer], "%s", buffer);
+      break;
+    case TRACE_TYPE_WARNING:
+      LOG_WARN(bt_layer_tags[trace_layer], "%s", buffer);
+      break;
+    case TRACE_TYPE_API:
+    case TRACE_TYPE_EVENT:
+      LOG_INFO(bt_layer_tags[trace_layer], "%s", buffer);
+      break;
+    case TRACE_TYPE_DEBUG:
+      LOG_DEBUG(bt_layer_tags[trace_layer], "%s", buffer);
+      break;
+    default:
+      LOG_ERROR(bt_layer_tags[trace_layer], "%s", buffer);      /* we should never get this */
+      break;
+  }
+}
+
+/* this function should go into BTAPP_DM for example */
+static uint8_t BTAPP_SetTraceLevel(uint8_t new_level) {
+  if (new_level != 0xFF)
+    appl_trace_level = new_level;
+
+  return appl_trace_level;
+}
+
+static uint8_t BTIF_SetTraceLevel(uint8_t new_level) {
+  if (new_level != 0xFF)
+    btif_trace_level = new_level;
+
+  return btif_trace_level;
+}
+
+static uint8_t BTU_SetTraceLevel(uint8_t new_level) {
+  if (new_level != 0xFF)
+    btu_trace_level = new_level;
+
+  return btu_trace_level;
+}
+
+static void load_levels_from_config(const config_t *config) {
+  assert(config != NULL);
+
+  for (tBTTRC_FUNC_MAP *functions = &bttrc_set_level_map[0]; functions->trc_name; ++functions) {
+    LOG_INFO(LOG_TAG, "BTE_InitTraceLevels -- %s", functions->trc_name);
+    int value = config_get_int(config, CONFIG_DEFAULT_SECTION, functions->trc_name, -1);
+    if (value != -1)
+      functions->trace_level = value;
+
+    if (functions->p_f)
+      functions->p_f(functions->trace_level);
+  }
+}
+
+static future_t *init(void) {
+
+  const stack_config_t *stack_config = stack_config_get_interface();
+  if (!stack_config->get_trace_config_enabled()) {
+    LOG_INFO(LOG_TAG, "using compile default trace settings");
+    return NULL;
+  }
+
+  init_cpp_logging(stack_config->get_all());
+
+  load_levels_from_config(stack_config->get_all());
+  return NULL;
+}
+
+EXPORT_SYMBOL extern const module_t bte_logmsg_module = {
+  .name = BTE_LOGMSG_MODULE,
+  .init = init,
+  .start_up = NULL,
+  .shut_down = NULL,
+  .clean_up = NULL,
+  .dependencies = {
+    STACK_CONFIG_MODULE,
+    NULL
+  }
+};
diff --git a/bt/main/bte_main.cc b/bt/main/bte_main.cc
new file mode 100644
index 0000000..4705756
--- /dev/null
+++ b/bt/main/bte_main.cc
@@ -0,0 +1,268 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Filename:      bte_main.cc
+ *
+ *  Description:   Contains BTE core stack initialization and shutdown code
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_main"
+
+#include <assert.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <hardware/bluetooth.h>
+
+#include "bt_hci_bdroid.h"
+#include "bt_utils.h"
+#include "bta_api.h"
+#include "btcore/include/module.h"
+#include "bte.h"
+#include "btif_common.h"
+#include "btsnoop.h"
+#include "btu.h"
+#include "bt_common.h"
+#include "device/include/interop.h"
+#include "hci_layer.h"
+#include "hcimsgs.h"
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/future.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/thread.h"
+#include "stack_config.h"
+
+/*******************************************************************************
+**  Constants & Macros
+*******************************************************************************/
+
+/* Run-time configuration file for BLE*/
+#ifndef BTE_BLE_STACK_CONF_FILE
+// TODO(armansito): Find a better way than searching by a hardcoded path.
+#if defined(OS_GENERIC)
+#define BTE_BLE_STACK_CONF_FILE "ble_stack.conf"
+#else  // !defined(OS_GENERIC)
+#define BTE_BLE_STACK_CONF_FILE "/etc/bluetooth/ble_stack.conf"
+#endif  // defined(OS_GENERIC)
+#endif  // BT_BLE_STACK_CONF_FILE
+
+/******************************************************************************
+**  Variables
+******************************************************************************/
+
+/*******************************************************************************
+**  Static variables
+*******************************************************************************/
+static const hci_t *hci;
+
+/*******************************************************************************
+**  Static functions
+*******************************************************************************/
+
+/*******************************************************************************
+**  Externs
+*******************************************************************************/
+fixed_queue_t *btu_hci_msg_queue;
+
+/******************************************************************************
+**
+** Function         bte_main_boot_entry
+**
+** Description      BTE MAIN API - Entry point for BTE chip/stack initialization
+**
+** Returns          None
+**
+******************************************************************************/
+void bte_main_boot_entry(void)
+{
+    module_init(get_module(INTEROP_MODULE));
+
+    hci = hci_layer_get_interface();
+    if (!hci)
+      LOG_ERROR(LOG_TAG, "%s could not get hci layer interface.", __func__);
+
+    btu_hci_msg_queue = fixed_queue_new(SIZE_MAX);
+    if (btu_hci_msg_queue == NULL) {
+      LOG_ERROR(LOG_TAG, "%s unable to allocate hci message queue.", __func__);
+      return;
+    }
+
+    data_dispatcher_register_default(hci->event_dispatcher, btu_hci_msg_queue);
+    hci->set_data_queue(btu_hci_msg_queue);
+
+    module_init(get_module(STACK_CONFIG_MODULE));
+}
+
+/******************************************************************************
+**
+** Function         bte_main_cleanup
+**
+** Description      BTE MAIN API - Cleanup code for BTE chip/stack
+**
+** Returns          None
+**
+******************************************************************************/
+void bte_main_cleanup()
+{
+    data_dispatcher_register_default(hci_layer_get_interface()->event_dispatcher, NULL);
+    hci->set_data_queue(NULL);
+    fixed_queue_free(btu_hci_msg_queue, NULL);
+
+    btu_hci_msg_queue = NULL;
+
+    module_clean_up(get_module(STACK_CONFIG_MODULE));
+
+    module_clean_up(get_module(INTEROP_MODULE));
+}
+
+/******************************************************************************
+**
+** Function         bte_main_enable
+**
+** Description      BTE MAIN API - Creates all the BTE tasks. Should be called
+**                  part of the Bluetooth stack enable sequence
+**
+** Returns          None
+**
+******************************************************************************/
+void bte_main_enable()
+{
+    APPL_TRACE_DEBUG("%s", __func__);
+
+    module_start_up(get_module(BTSNOOP_MODULE));
+    module_start_up(get_module(HCI_MODULE));
+
+    BTU_StartUp();
+}
+
+/******************************************************************************
+**
+** Function         bte_main_disable
+**
+** Description      BTE MAIN API - Destroys all the BTE tasks. Should be called
+**                  part of the Bluetooth stack disable sequence
+**
+** Returns          None
+**
+******************************************************************************/
+void bte_main_disable(void)
+{
+    APPL_TRACE_DEBUG("%s", __func__);
+
+    module_shut_down(get_module(HCI_MODULE));
+    module_shut_down(get_module(BTSNOOP_MODULE));
+
+    BTU_ShutDown();
+}
+
+/******************************************************************************
+**
+** Function         bte_main_postload_cfg
+**
+** Description      BTE MAIN API - Stack postload configuration
+**
+** Returns          None
+**
+******************************************************************************/
+void bte_main_postload_cfg(void)
+{
+    hci->do_postload();
+}
+
+#if (HCILP_INCLUDED == TRUE)
+/******************************************************************************
+**
+** Function         bte_main_enable_lpm
+**
+** Description      BTE MAIN API - Enable/Disable low power mode operation
+**
+** Returns          None
+**
+******************************************************************************/
+void bte_main_enable_lpm(bool enable)
+{
+    hci->send_low_power_command(enable ? LPM_ENABLE : LPM_DISABLE);
+}
+
+/******************************************************************************
+**
+** Function         bte_main_lpm_allow_bt_device_sleep
+**
+** Description      BTE MAIN API - Allow the BT controller to go to sleep
+**
+** Returns          None
+**
+******************************************************************************/
+void bte_main_lpm_allow_bt_device_sleep()
+{
+    hci->send_low_power_command(LPM_WAKE_DEASSERT);
+}
+
+/******************************************************************************
+**
+** Function         bte_main_lpm_wake_bt_device
+**
+** Description      BTE MAIN API - Wake BT controller up if it is in sleep mode
+**
+** Returns          None
+**
+******************************************************************************/
+void bte_main_lpm_wake_bt_device()
+{
+    hci->send_low_power_command(LPM_WAKE_ASSERT);
+}
+#endif  // HCILP_INCLUDED
+
+/******************************************************************************
+**
+** Function         bte_main_hci_send
+**
+** Description      BTE MAIN API - This function is called by the upper stack to
+**                  send an HCI message. The function displays a protocol trace
+**                  message (if enabled), and then calls the 'transmit' function
+**                  associated with the currently selected HCI transport
+**
+** Returns          None
+**
+******************************************************************************/
+void bte_main_hci_send (BT_HDR *p_msg, uint16_t event)
+{
+    uint16_t sub_event = event & BT_SUB_EVT_MASK;  /* local controller ID */
+
+    p_msg->event = event;
+
+
+    if((sub_event == LOCAL_BR_EDR_CONTROLLER_ID) || \
+       (sub_event == LOCAL_BLE_CONTROLLER_ID))
+    {
+        hci->transmit_downward(event, p_msg);
+    }
+    else
+    {
+        APPL_TRACE_ERROR("Invalid Controller ID. Discarding message.");
+        osi_free(p_msg);
+    }
+}
diff --git a/bt/main/main_int.h b/bt/main/main_int.h
new file mode 100644
index 0000000..dc821bc
--- /dev/null
+++ b/bt/main/main_int.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef MAIN_INT_H
+#define MAIN_INT_H
+
+#include "osi/include/config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Initiates the logging for C++ */
+void init_cpp_logging(config_t *config);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MAIN_INT_H
\ No newline at end of file
diff --git a/bt/main/stack_config.cc b/bt/main/stack_config.cc
new file mode 100644
index 0000000..72044df
--- /dev/null
+++ b/bt/main/stack_config.cc
@@ -0,0 +1,137 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_stack_config"
+
+#include "stack_config.h"
+
+#include <assert.h>
+
+#include "osi/include/future.h"
+#include "osi/include/log.h"
+
+const char *BTSNOOP_LOG_PATH_KEY = "BtSnoopFileName";
+const char *BTSNOOP_TURNED_ON_KEY = "BtSnoopLogOutput";
+const char *BTSNOOP_SHOULD_SAVE_LAST_KEY = "BtSnoopSaveLog";
+const char *TRACE_CONFIG_ENABLED_KEY = "TraceConf";
+const char *PTS_SECURE_ONLY_MODE = "PTS_SecurePairOnly";
+const char *PTS_LE_CONN_UPDATED_DISABLED = "PTS_DisableConnUpdates";
+const char *PTS_DISABLE_SDP_LE_PAIR = "PTS_DisableSDPOnLEPair";
+const char *PTS_SMP_PAIRING_OPTIONS_KEY = "PTS_SmpOptions";
+const char *PTS_SMP_FAILURE_CASE_KEY = "PTS_SmpFailureCase";
+
+static config_t *config;
+
+// Module lifecycle functions
+
+static future_t *init() {
+// TODO(armansito): Find a better way than searching by a hardcoded path.
+#if defined(OS_GENERIC)
+  const char *path = "bt_stack.conf";
+#else  // !defined(OS_GENERIC)
+  const char *path = "/etc/bluetooth/bt_stack.conf";
+#endif  // defined(OS_GENERIC)
+  assert(path != NULL);
+
+  LOG_INFO(LOG_TAG, "%s attempt to load stack conf from %s", __func__, path);
+
+  config = config_new(path);
+  if (!config) {
+    LOG_INFO(LOG_TAG, "%s file >%s< not found", __func__, path);
+    config = config_new_empty();
+  }
+
+  return future_new_immediate(FUTURE_SUCCESS);
+}
+
+static future_t *clean_up() {
+  config_free(config);
+  config = NULL;
+  return future_new_immediate(FUTURE_SUCCESS);
+}
+
+EXPORT_SYMBOL extern const module_t stack_config_module = {
+  .name = STACK_CONFIG_MODULE,
+  .init = init,
+  .start_up = NULL,
+  .shut_down = NULL,
+  .clean_up = clean_up,
+  .dependencies = {
+    NULL
+  }
+};
+
+// Interface functions
+
+static const char *get_btsnoop_log_path(void) {
+  return config_get_string(config, CONFIG_DEFAULT_SECTION, BTSNOOP_LOG_PATH_KEY,
+      "/data/misc/bluetooth/logs/btsnoop_hci.log");
+}
+
+static bool get_btsnoop_turned_on(void) {
+  return config_get_bool(config, CONFIG_DEFAULT_SECTION, BTSNOOP_TURNED_ON_KEY, false);
+}
+
+static bool get_btsnoop_should_save_last(void) {
+  return config_get_bool(config, CONFIG_DEFAULT_SECTION, BTSNOOP_SHOULD_SAVE_LAST_KEY, false);
+}
+
+static bool get_trace_config_enabled(void) {
+  return config_get_bool(config, CONFIG_DEFAULT_SECTION, TRACE_CONFIG_ENABLED_KEY, false);
+}
+
+static bool get_pts_secure_only_mode(void) {
+    return config_get_bool(config, CONFIG_DEFAULT_SECTION, PTS_SECURE_ONLY_MODE, false);
+}
+
+static bool get_pts_conn_updates_disabled(void) {
+  return config_get_bool(config, CONFIG_DEFAULT_SECTION, PTS_LE_CONN_UPDATED_DISABLED, false);
+}
+
+static bool get_pts_crosskey_sdp_disable(void) {
+  return config_get_bool(config, CONFIG_DEFAULT_SECTION, PTS_DISABLE_SDP_LE_PAIR, false);
+}
+
+static const char *get_pts_smp_options(void) {
+  return config_get_string(config, CONFIG_DEFAULT_SECTION, PTS_SMP_PAIRING_OPTIONS_KEY, NULL);
+}
+
+static int get_pts_smp_failure_case(void) {
+  return config_get_int(config, CONFIG_DEFAULT_SECTION, PTS_SMP_FAILURE_CASE_KEY, 0);
+}
+
+static config_t *get_all(void) {
+  return config;
+}
+
+const stack_config_t interface = {
+  get_btsnoop_log_path,
+  get_btsnoop_turned_on,
+  get_btsnoop_should_save_last,
+  get_trace_config_enabled,
+  get_pts_secure_only_mode,
+  get_pts_conn_updates_disabled,
+  get_pts_crosskey_sdp_disable,
+  get_pts_smp_options,
+  get_pts_smp_failure_case,
+  get_all
+};
+
+const stack_config_t *stack_config_get_interface(void) {
+  return &interface;
+}
diff --git a/bt/osi/Android.mk b/bt/osi/Android.mk
new file mode 100644
index 0000000..f93fdfb
--- /dev/null
+++ b/bt/osi/Android.mk
@@ -0,0 +1,198 @@
+ ##############################################################################
+ #
+ #  Copyright (C) 2014 Google, Inc.
+ #
+ #  Licensed under the Apache License, Version 2.0 (the "License");
+ #  you may not use this file except in compliance with the License.
+ #  You may obtain a copy of the License at:
+ #
+ #  http://www.apache.org/licenses/LICENSE-2.0
+ #
+ #  Unless required by applicable law or agreed to in writing, software
+ #  distributed under the License is distributed on an "AS IS" BASIS,
+ #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ #  See the License for the specific language governing permissions and
+ #  limitations under the License.
+ #
+ ##############################################################################
+
+LOCAL_PATH := $(call my-dir)
+
+# Common variables
+# ========================================================
+
+# TODO(mcchou): Remove socket_utils sources after platform specific
+# dependencies are abstracted.
+btosiCommonSrc := \
+    ./src/alarm.cc \
+    ./src/allocation_tracker.cc \
+    ./src/allocator.cc \
+    ./src/array.cc \
+    ./src/buffer.cc \
+    ./src/compat.cc \
+    ./src/config.cc \
+    ./src/data_dispatcher.cc \
+    ./src/eager_reader.cc \
+    ./src/fixed_queue.cc \
+    ./src/future.cc \
+    ./src/hash_map_utils.cc \
+    ./src/list.cc \
+    ./src/metrics.cc \
+    ./src/mutex.cc \
+    ./src/osi.cc \
+    ./src/properties.cc \
+    ./src/reactor.cc \
+    ./src/ringbuffer.cc \
+    ./src/semaphore.cc \
+    ./src/socket.cc \
+    ./src/socket_utils/socket_local_client.cc \
+    ./src/socket_utils/socket_local_server.cc \
+    ./src/thread.cc \
+    ./src/time.cc \
+    ./src/wakelock.cc
+
+btosiCommonTestSrc := \
+    ./test/AlarmTestHarness.cc \
+    ./test/AllocationTestHarness.cc \
+    ./test/alarm_test.cc \
+    ./test/allocation_tracker_test.cc \
+    ./test/allocator_test.cc \
+    ./test/array_test.cc \
+    ./test/config_test.cc \
+    ./test/data_dispatcher_test.cc \
+    ./test/eager_reader_test.cc \
+    ./test/fixed_queue_test.cc \
+    ./test/future_test.cc \
+    ./test/hash_map_utils_test.cc \
+    ./test/list_test.cc \
+    ./test/properties_test.cc \
+    ./test/rand_test.cc \
+    ./test/reactor_test.cc \
+    ./test/ringbuffer_test.cc \
+    ./test/semaphore_test.cc \
+    ./test/thread_test.cc \
+    ./test/time_test.cc \
+    ./test/wakelock_test.cc
+
+btosiCommonIncludes := \
+    $(LOCAL_PATH)/.. \
+    $(LOCAL_PATH)/../utils/include \
+    $(LOCAL_PATH)/../stack/include \
+    $(bluetooth_C_INCLUDES)
+
+# Bluetooth Protobuf static library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_MODULE := libbt-protos
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+generated_sources_dir := $(call local-generated-sources-dir)
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+    $(generated_sources_dir)/proto/system/bt
+LOCAL_SRC_FILES := $(call all-proto-files-under,src/protos/)
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_STATIC_LIBRARY)
+
+# Bluetooth Protobuf static library for host
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_MODULE := libbt-protos
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_IS_HOST_MODULE := true
+generated_sources_dir := $(call local-generated-sources-dir)
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+    $(generated_sources_dir)/proto/system/bt
+LOCAL_SRC_FILES := $(call all-proto-files-under,src/protos/)
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# libosi static library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_C_INCLUDES := $(btosiCommonIncludes)
+LOCAL_SRC_FILES := $(btosiCommonSrc)
+LOCAL_MODULE := libosi
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES := libc liblog libchrome
+LOCAL_STATIC_LIBRARIES := libbt-protos
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_STATIC_LIBRARY)
+
+# libosi static library for host
+# ========================================================
+ifeq ($(HOST_OS),linux)
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_C_INCLUDES := $(btosiCommonIncludes)
+LOCAL_SRC_FILES := $(btosiCommonSrc)
+LOCAL_MODULE := libosi-host
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES := liblog libchrome
+LOCAL_STATIC_LIBRARIES := libbt-protos
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+# TODO(armansito): Setting _GNU_SOURCE isn't very platform-independent but
+# should be compatible for a Linux host OS. We should figure out what to do for
+# a non-Linux host OS.
+LOCAL_CFLAGS += $(bluetooth_CFLAGS) -D_GNU_SOURCE -DOS_GENERIC
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+endif
+
+#
+# Note: It's good to get the tests compiled both for the host and the target so
+# we get to test with both Bionic libc and glibc
+#
+# libosi unit tests for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_C_INCLUDES := $(btosiCommonIncludes)
+LOCAL_SRC_FILES := $(btosiCommonTestSrc)
+LOCAL_MODULE := net_test_osi
+LOCAL_MODULE_TAGS := tests
+LOCAL_SHARED_LIBRARIES := libc liblog libprotobuf-cpp-lite libchrome libcutils
+LOCAL_STATIC_LIBRARIES := libosi libbt-protos
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_NATIVE_TEST)
+
+# libosi unit tests for host
+# ========================================================
+ifeq ($(HOST_OS),linux)
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_C_INCLUDES := $(btosiCommonIncludes)
+LOCAL_SRC_FILES := $(btosiCommonTestSrc)
+LOCAL_LDLIBS := -lrt -lpthread
+LOCAL_MODULE := net_test_osi
+LOCAL_MODULE_TAGS := tests
+LOCAL_SHARED_LIBRARIES := liblog libprotobuf-cpp-lite libchrome
+LOCAL_STATIC_LIBRARIES := libosi-host libbt-protos
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS) -DOS_GENERIC
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_HOST_NATIVE_TEST)
+endif
diff --git a/bt/osi/BUILD.gn b/bt/osi/BUILD.gn
new file mode 100644
index 0000000..d32472d
--- /dev/null
+++ b/bt/osi/BUILD.gn
@@ -0,0 +1,94 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+static_library("osi") {
+  sources = [
+    "src/alarm.cc",
+    "src/allocation_tracker.cc",
+    "src/allocator.cc",
+    "src/array.cc",
+    "src/buffer.cc",
+    "src/compat.cc",
+    "src/config.cc",
+    "src/data_dispatcher.cc",
+    "src/eager_reader.cc",
+    "src/fixed_queue.cc",
+    "src/future.cc",
+    "src/hash_map_utils.cc",
+    "src/list.cc",
+    "src/metrics_linux.cc",
+    "src/mutex.cc",
+    "src/osi.cc",
+    "src/properties.cc",
+    "src/reactor.cc",
+    "src/ringbuffer.cc",
+    "src/semaphore.cc",
+    "src/socket.cc",
+
+    # TODO(mcchou): Remove these sources after platform specific
+    # dependencies are abstracted.
+    "src/socket_utils/socket_local_client.cc",
+    "src/socket_utils/socket_local_server.cc",
+    "src/thread.cc",
+    "src/time.cc",
+    "src/wakelock.cc",
+  ]
+
+  include_dirs = [
+    "//",
+    "//utils/include",
+    "//stack/include",
+  ]
+}
+
+executable("net_test_osi") {
+  testonly = true
+  sources = [
+    "test/AlarmTestHarness.cc",
+    "test/AllocationTestHarness.cc",
+    "test/alarm_test.cc",
+    "test/allocation_tracker_test.cc",
+    "test/allocator_test.cc",
+    "test/array_test.cc",
+    "test/config_test.cc",
+    "test/data_dispatcher_test.cc",
+    "test/eager_reader_test.cc",
+    "test/future_test.cc",
+    "test/hash_map_utils_test.cc",
+    "test/list_test.cc",
+    "test/properties_test.cc",
+    "test/rand_test.cc",
+    "test/reactor_test.cc",
+    "test/ringbuffer_test.cc",
+    "test/thread_test.cc",
+    "test/time_test.cc",
+  ]
+
+  include_dirs = [
+    "//",
+    "//osi/test",
+  ]
+
+  deps = [
+    "//osi",
+    "//third_party/googletest:gtest_main",
+  ]
+
+  libs = [
+    "-lpthread",
+    "-lrt",
+  ]
+}
diff --git a/bt/osi/include/alarm.h b/bt/osi/include/alarm.h
new file mode 100644
index 0000000..5899d15
--- /dev/null
+++ b/bt/osi/include/alarm.h
@@ -0,0 +1,127 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+#include <stdint.h>
+#include "osi/include/time.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct alarm_t alarm_t;
+typedef struct fixed_queue_t fixed_queue_t;
+typedef struct thread_t thread_t;
+
+// Prototype for the alarm callback function.
+typedef void (*alarm_callback_t)(void* data);
+
+// Creates a new one-time off alarm object with user-assigned
+// |name|. |name| may not be NULL, and a copy of the string will
+// be stored internally. The value of |name| has no semantic
+// meaning. It is recommended that the name is unique (for
+// better debuggability), but that is not enforced. The returned
+// object must be freed by calling |alarm_free|. Returns NULL on
+// failure.
+alarm_t* alarm_new(const char* name);
+
+// Creates a new periodic alarm object with user-assigned |name|.
+// |name| may not be NULL, and a copy of the string will be
+// stored internally. The value of |name| has no semantic
+// meaning. It is recommended that the name is unique (for better
+// debuggability), but that is not enforced. The returned object
+// must be freed by calling |alarm_free|. Returns NULL on
+// failure.
+alarm_t* alarm_new_periodic(const char* name);
+
+// Frees an |alarm| object created by |alarm_new| or
+// |alarm_new_periodic|. |alarm| may be NULL. If the alarm is
+// pending, it will be cancelled first. It is not safe to call
+// |alarm_free| from inside the callback of |alarm|.
+void alarm_free(alarm_t* alarm);
+
+// Sets an |alarm| to execute a callback in the future. The |cb|
+// callback is called after the given |interval_ms|, where
+// |interval_ms| is the number of milliseconds relative to the
+// current time. If |alarm| was created with
+// |alarm_new_periodic|, the alarm is scheduled to fire
+// periodically every |interval_ms|, otherwise it is a one time
+// only alarm. A periodic alarm repeats every |interval_ms| until
+// it is cancelled or freed. When the alarm fires, the |cb|
+// callback is called with the context argument |data|:
+//
+//      void cb(void *data) {...}
+//
+// The |data| argument may be NULL, but the |cb| callback may not
+// be NULL. All |cb| callbacks scheduled through this call are
+// called within a single (internally created) thread. That
+// thread is not same as the caller’s thread. If two (or more)
+// alarms are set back-to-back with the same |interval_ms|, the
+// callbacks will be called in the order the alarms are set.
+void alarm_set(alarm_t* alarm, period_ms_t interval_ms, alarm_callback_t cb,
+               void* data);
+
+// Sets an |alarm| to execute a callback in the future on a
+// specific |queue|. This function is same as |alarm_set| except
+// that the |cb| callback is scheduled for execution in the
+// context of the thread responsible for processing |queue|.
+// Also, the callback execution ordering guarantee exists only
+// among alarms that are scheduled on the same queue. |queue|
+// may not be NULL.
+void alarm_set_on_queue(alarm_t* alarm, period_ms_t interval_ms,
+                        alarm_callback_t cb, void* data, fixed_queue_t* queue);
+
+// This function cancels the |alarm| if it was previously set.
+// When this call returns, the caller has a guarantee that the
+// callback is not in progress and will not be called if it
+// hasn't already been called. This function is idempotent.
+// |alarm| may not be NULL.
+void alarm_cancel(alarm_t* alarm);
+
+// Tests whether the |alarm| is scheduled.
+// Return true if the |alarm| is scheduled or NULL, otherwise false.
+bool alarm_is_scheduled(const alarm_t* alarm);
+
+// Registers |queue| for processing alarm callbacks on |thread|.
+// |queue| may not be NULL. |thread| may not be NULL.
+void alarm_register_processing_queue(fixed_queue_t* queue, thread_t* thread);
+
+// Unregisters |queue| for processing alarm callbacks on whichever thread
+// it is registered with. All alarms currently set for execution on |queue|
+// will be canceled. |queue| may not be NULL. This function is idempotent.
+void alarm_unregister_processing_queue(fixed_queue_t* queue);
+
+// Figure out how much time until next expiration.
+// Returns 0 if not armed. |alarm| may not be NULL.
+// TODO: Remove this function once PM timers can be re-factored
+period_ms_t alarm_get_remaining_ms(const alarm_t* alarm);
+
+// Cleanup the alarm internal state.
+// This function should be called by the OSI module cleanup during
+// graceful shutdown.
+void alarm_cleanup(void);
+
+// Dump alarm-related statistics and debug info to the |fd| file descriptor.
+// The information is in user-readable text format. The |fd| must be valid.
+void alarm_debug_dump(int fd);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/allocation_tracker.h b/bt/osi/include/allocation_tracker.h
new file mode 100644
index 0000000..9496ce6
--- /dev/null
+++ b/bt/osi/include/allocation_tracker.h
@@ -0,0 +1,67 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct allocation_tracker_t allocation_tracker_t;
+typedef uint8_t allocator_id_t;
+
+// Initialize the allocation tracker. If you do not call this function,
+// the allocation tracker functions do nothing but are still safe to call.
+void allocation_tracker_init(void);
+
+// Reset the allocation tracker. Don't call this in the normal course of
+// operations. Useful mostly for testing.
+void allocation_tracker_reset(void);
+
+// Expects that there are no allocations at the time of this call. Dumps
+// information about unfreed allocations to the log. Returns the amount of
+// unallocated memory.
+size_t allocation_tracker_expect_no_allocations(void);
+
+// Notify the tracker of a new allocation belonging to |allocator_id|.
+// If |ptr| is NULL, this function does nothing. |requested_size| is the
+// size of the allocation without any canaries. The caller must allocate
+// enough memory for canaries; the total allocation size can be determined
+// by calling |allocation_tracker_resize_for_canary|. Returns |ptr| offset
+// to the the beginning of the uncanaried region.
+void* allocation_tracker_notify_alloc(allocator_id_t allocator_id, void* ptr,
+                                      size_t requested_size);
+
+// Notify the tracker of an allocation that is being freed. |ptr| must be a
+// pointer returned by a call to |allocation_tracker_notify_alloc| with the
+// same |allocator_id|. If |ptr| is NULL, this function does nothing. Returns
+// |ptr| offset to the real beginning of the allocation including any canary
+// space.
+void* allocation_tracker_notify_free(allocator_id_t allocator_id, void* ptr);
+
+// Get the full size for an allocation, taking into account the size of
+// canaries.
+size_t allocation_tracker_resize_for_canary(size_t size);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/allocator.h b/bt/osi/include/allocator.h
new file mode 100644
index 0000000..c7e870a
--- /dev/null
+++ b/bt/osi/include/allocator.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void* (*alloc_fn)(size_t size);
+typedef void (*free_fn)(void* ptr);
+
+typedef struct {
+  alloc_fn alloc;
+  free_fn free;
+} allocator_t;
+
+// allocator_t abstractions for the osi_*alloc and osi_free functions
+extern const allocator_t allocator_malloc;
+extern const allocator_t allocator_calloc;
+
+char* osi_strdup(const char* str);
+char* osi_strndup(const char* str, size_t len);
+
+void* osi_malloc(size_t size);
+void* osi_calloc(size_t size);
+void osi_free(void* ptr);
+
+// Free a buffer that was previously allocated with function |osi_malloc|
+// or |osi_calloc| and reset the pointer to that buffer to NULL.
+// |p_ptr| is a pointer to the buffer pointer to be reset.
+// |p_ptr| cannot be NULL.
+void osi_free_and_reset(void** p_ptr);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/array.h b/bt/osi/include/array.h
new file mode 100644
index 0000000..fa05d87
--- /dev/null
+++ b/bt/osi/include/array.h
@@ -0,0 +1,71 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct array_t array_t;
+
+// Returns a new array object that stores elements of size |element_size|. The
+// returned
+// object must be freed with |array_free|. |element_size| must be greater than
+// 0. Returns
+// NULL on failure.
+array_t* array_new(size_t element_size);
+
+// Frees an array that was allocated with |array_new|. |array| may be NULL.
+void array_free(array_t* array);
+
+// Returns a pointer to the first stored element in |array|. |array| must not be
+// NULL.
+void* array_ptr(const array_t* array);
+
+// Returns a pointer to the |index|th element of |array|. |index| must be less
+// than
+// the array's length. |array| must not be NULL.
+void* array_at(const array_t* array, size_t index);
+
+// Returns the number of elements stored in |array|. |array| must not be NULL.
+size_t array_length(const array_t* array);
+
+// Inserts an element to the end of |array| by value. For example, a caller
+// may simply call array_append_value(array, 5) instead of storing 5 into a
+// variable and then inserting by pointer. Although |value| is a uint32_t,
+// only the lowest |element_size| bytes will be stored. |array| must not be
+// NULL. Returns true if the element could be inserted into the array, false
+// on error.
+bool array_append_value(array_t* array, uint32_t value);
+
+// Inserts an element to the end of |array|. The value pointed to by |data| must
+// be at least |element_size| bytes long and will be copied into the array.
+// Neither
+// |array| nor |data| may be NULL. Returns true if the element could be inserted
+// into
+// the array, false on error.
+bool array_append_ptr(array_t* array, void* data);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/buffer.h b/bt/osi/include/buffer.h
new file mode 100644
index 0000000..211f0d6
--- /dev/null
+++ b/bt/osi/include/buffer.h
@@ -0,0 +1,65 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct buffer_t buffer_t;
+
+// Returns a new buffer of |size| bytes. Returns NULL if a buffer could not be
+// allocated. |size| must be non-zero. The caller must release this buffer with
+// |buffer_free|.
+buffer_t* buffer_new(size_t size);
+
+// Creates a new reference to the buffer |buf|. A reference is indistinguishable
+// from the original: writes to the original will be reflected in the reference
+// and vice versa. In other words, this function creates an alias to |buf|. The
+// caller must release the returned buffer with |buffer_free|. Note that
+// releasing
+// the returned buffer does not release |buf|. |buf| must not be NULL.
+buffer_t* buffer_new_ref(const buffer_t* buf);
+
+// Creates a new reference to the last |slice_size| bytes of |buf|. See
+// |buffer_new_ref| for a description of references. |slice_size| must be
+// greater than 0 and may be at most |buffer_length|
+// (0 < slice_size <= buffer_length). |buf| must not be NULL.
+buffer_t* buffer_new_slice(const buffer_t* buf, size_t slice_size);
+
+// Frees a buffer object. |buf| may be NULL.
+void buffer_free(buffer_t* buf);
+
+// Returns a pointer to a writeable memory region for |buf|. All references
+// and slices that share overlapping bytes will also be written to when
+// writing to the returned pointer. The caller may safely write up to
+// |buffer_length| consecutive bytes starting at the address returned by
+// this function. |buf| must not be NULL.
+void* buffer_ptr(const buffer_t* buf);
+
+// Returns the length of the writeable memory region referred to by |buf|.
+// |buf| must not be NULL.
+size_t buffer_length(const buffer_t* buf);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/compat.h b/bt/osi/include/compat.h
new file mode 100644
index 0000000..981c452
--- /dev/null
+++ b/bt/osi/include/compat.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ *  Copyright 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <features.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if __GLIBC__
+
+#include <unistd.h>
+
+/* Get thread identification. */
+pid_t gettid(void);
+
+/* Copy src to string dst of size siz. */
+size_t strlcpy(char* dst, const char* src, size_t siz);
+
+/* Appends src to string dst of size siz. */
+size_t strlcat(char* dst, const char* src, size_t siz);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/config.h b/bt/osi/include/config.h
new file mode 100644
index 0000000..2243c27
--- /dev/null
+++ b/bt/osi/include/config.h
@@ -0,0 +1,170 @@
+#pragma once
+
+// This module implements a configuration parser. Clients can query the
+// contents of a configuration file through the interface provided here.
+// The current implementation is read-only; mutations are only kept in
+// memory. This parser supports the INI file format.
+
+// Implementation notes:
+// - Key/value pairs that are not within a section are assumed to be under
+//   the |CONFIG_DEFAULT_SECTION| section.
+// - Multiple sections with the same name will be merged as if they were in
+//   a single section.
+// - Empty sections with no key/value pairs will be treated as if they do
+//   not exist. In other words, |config_has_section| will return false for
+//   empty sections.
+// - Duplicate keys in a section will overwrite previous values.
+// - All strings are case sensitive.
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// The default section name to use if a key/value pair is not defined within
+// a section.
+#define CONFIG_DEFAULT_SECTION "Global"
+
+typedef struct config_t config_t;
+typedef struct config_section_node_t config_section_node_t;
+
+// Creates a new config object with no entries (i.e. not backed by a file).
+// This function returns a config object or NULL on error. Clients must call
+// |config_free| on the returned handle when it is no longer required.
+config_t* config_new_empty(void);
+
+// Loads the specified file and returns a handle to the config file. If there
+// was a problem loading the file or allocating memory, this function returns
+// NULL. Clients must call |config_free| on the returned handle when it is no
+// longer required. |filename| must not be NULL and must point to a readable
+// file on the filesystem.
+config_t* config_new(const char* filename);
+
+// Clones |src|, including all of it's sections, keys, and values.
+// Returns a new config which is a copy and separated from the original;
+// changes to the new config are not reflected in any way in the original.
+//
+// |src| must not be NULL
+// This function will not return NULL.
+// Clients must call config_free on the returned object.
+config_t* config_new_clone(const config_t* src);
+
+// Frees resources associated with the config file. No further operations may
+// be performed on the |config| object after calling this function. |config|
+// may be NULL.
+void config_free(config_t* config);
+
+// Returns true if the config file contains a section named |section|. If
+// the section has no key/value pairs in it, this function will return false.
+// |config| and |section| must not be NULL.
+bool config_has_section(const config_t* config, const char* section);
+
+// Returns true if the config file has a key named |key| under |section|.
+// Returns false otherwise. |config|, |section|, and |key| must not be NULL.
+bool config_has_key(const config_t* config, const char* section,
+                    const char* key);
+
+// Returns the integral value for a given |key| in |section|. If |section|
+// or |key| do not exist, or the value cannot be fully converted to an integer,
+// this function returns |def_value|. |config|, |section|, and |key| must not
+// be NULL.
+int config_get_int(const config_t* config, const char* section, const char* key,
+                   int def_value);
+
+// Returns the boolean value for a given |key| in |section|. If |section|
+// or |key| do not exist, or the value cannot be converted to a boolean, this
+// function returns |def_value|. |config|, |section|, and |key| must not be
+// NULL.
+bool config_get_bool(const config_t* config, const char* section,
+                     const char* key, bool def_value);
+
+// Returns the string value for a given |key| in |section|. If |section| or
+// |key| do not exist, this function returns |def_value|. The returned string
+// is owned by the config module and must not be freed. |config|, |section|,
+// and |key| must not be NULL. |def_value| may be NULL.
+const char* config_get_string(const config_t* config, const char* section,
+                              const char* key, const char* def_value);
+
+// Sets an integral value for the |key| in |section|. If |key| or |section| do
+// not already exist, this function creates them. |config|, |section|, and |key|
+// must not be NULL.
+void config_set_int(config_t* config, const char* section, const char* key,
+                    int value);
+
+// Sets a boolean value for the |key| in |section|. If |key| or |section| do
+// not already exist, this function creates them. |config|, |section|, and |key|
+// must not be NULL.
+void config_set_bool(config_t* config, const char* section, const char* key,
+                     bool value);
+
+// Sets a string value for the |key| in |section|. If |key| or |section| do
+// not already exist, this function creates them. |config|, |section|, |key|,
+// and
+// |value| must not be NULL.
+void config_set_string(config_t* config, const char* section, const char* key,
+                       const char* value);
+
+// Removes |section| from the |config| (and, as a result, all keys in the
+// section).
+// Returns true if |section| was found and removed from |config|, false
+// otherwise.
+// Neither |config| nor |section| may be NULL.
+bool config_remove_section(config_t* config, const char* section);
+
+// Removes one specific |key| residing in |section| of the |config|. Returns
+// true
+// if the section and key were found and the key was removed, false otherwise.
+// None of |config|, |section|, or |key| may be NULL.
+bool config_remove_key(config_t* config, const char* section, const char* key);
+
+// Returns an iterator to the first section in the config file. If there are no
+// sections, the iterator will equal the return value of |config_section_end|.
+// The returned pointer must be treated as an opaque handle and must not be
+// freed.
+// The iterator is invalidated on any config mutating operation. |config| may
+// not
+// be NULL.
+const config_section_node_t* config_section_begin(const config_t* config);
+
+// Returns an iterator to one past the last section in the config file. It does
+// not
+// represent a valid section, but can be used to determine if all sections have
+// been
+// iterated over. The returned pointer must be treated as an opaque handle and
+// must
+// not be freed and must not be iterated on (must not call |config_section_next|
+// on
+// it). |config| may not be NULL.
+const config_section_node_t* config_section_end(const config_t* config);
+
+// Moves |iter| to the next section. If there are no more sections, |iter| will
+// equal the value of |config_section_end|. |iter| may not be NULL and must be
+// a pointer returned by either |config_section_begin| or |config_section_next|.
+const config_section_node_t* config_section_next(
+    const config_section_node_t* iter);
+
+// Returns the name of the section referred to by |iter|. The returned pointer
+// is
+// owned by the config module and must not be freed by the caller. The pointer
+// will
+// remain valid until |config_free| is called. |iter| may not be NULL and must
+// not
+// equal the value returned by |config_section_end|.
+const char* config_section_name(const config_section_node_t* iter);
+
+// Saves |config| to a file given by |filename|. Note that this could be a
+// destructive
+// operation: if |filename| already exists, it will be overwritten. The config
+// module does not preserve comments or formatting so if a config file was
+// opened
+// with |config_new| and subsequently overwritten with |config_save|, all
+// comments
+// and special formatting in the original file will be lost. Neither |config|
+// nor
+// |filename| may be NULL.
+bool config_save(const config_t* config, const char* filename);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/data_dispatcher.h b/bt/osi/include/data_dispatcher.h
new file mode 100644
index 0000000..7349444
--- /dev/null
+++ b/bt/osi/include/data_dispatcher.h
@@ -0,0 +1,68 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+#include <stdint.h>
+
+#include "osi/include/fixed_queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DISPATCHER_NAME_MAX 16
+
+typedef struct data_dispatcher_t data_dispatcher_t;
+typedef uintptr_t data_dispatcher_type_t;
+
+// Creates a new data dispatcher object, with the given name.
+// The returned object must be freed by calling |data_dispatcher_free|.
+// Returns NULL on failure. |name| may not be NULL.
+data_dispatcher_t* data_dispatcher_new(const char* name);
+
+// Frees a data dispatcher object created by |data_dispatcher_new|.
+// |data_dispatcher| may be NULL.
+void data_dispatcher_free(data_dispatcher_t* dispatcher);
+
+// Registers |type| and |queue| with the data dispatcher so that data
+// sent under |type| ends up in |queue|. If |type| is already registered,
+// it is replaced. If |queue| is NULL, the existing registration is
+// removed, if it exists. |dispatcher| may not be NULL.
+void data_dispatcher_register(data_dispatcher_t* dispatcher,
+                              data_dispatcher_type_t type,
+                              fixed_queue_t* queue);
+
+// Registers a default queue to send data to when there is not a specific
+// type/queue relationship registered. If a default queue is already registered,
+// it is replaced. If |queue| is NULL, the existing registration is
+// removed, if it exists. |dispatcher| may not be NULL.
+void data_dispatcher_register_default(data_dispatcher_t* dispatcher,
+                                      fixed_queue_t* queue);
+
+// Dispatches |data| to the queue registered for |type|. If no such registration
+// exists, it is dispatched to the default queue if it exists.
+// Neither |dispatcher| nor |data| may be NULL.
+// Returns true if data dispatch was successful.
+bool data_dispatcher_dispatch(data_dispatcher_t* dispatcher,
+                              data_dispatcher_type_t type, void* data);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/eager_reader.h b/bt/osi/include/eager_reader.h
new file mode 100644
index 0000000..ad4887b
--- /dev/null
+++ b/bt/osi/include/eager_reader.h
@@ -0,0 +1,78 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/thread.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct eager_reader_t eager_reader_t;
+typedef struct reactor_t reactor_t;
+
+typedef void (*eager_reader_cb)(eager_reader_t* reader, void* context);
+
+// Creates a new eager reader object, which pulls data from |fd_to_read| into
+// buffers of size |buffer_size| allocated using |allocator|, and has an
+// internal read thread named |thread_name|. The returned object must be freed
+// using
+// |eager_reader_free|. |fd_to_read| must be valid, |buffer_size| and
+// |max_buffer_count|
+// must be greater than zero. |allocator| and |thread_name| may not be NULL.
+eager_reader_t* eager_reader_new(int fd_to_read, const allocator_t* allocator,
+                                 size_t buffer_size, size_t max_buffer_count,
+                                 const char* thread_name);
+
+// Frees an eager reader object, and associated internal resources.
+// |reader| may be NULL.
+void eager_reader_free(eager_reader_t* reader);
+
+// Registers |reader| with the |reactor|. When the reader has data
+// |read_cb| will be called. The |context| parameter is passed, untouched, to
+// |read_cb|.
+// Neither |reader|, nor |reactor|, nor |read_cb| may be NULL. |context| may be
+// NULL.
+void eager_reader_register(eager_reader_t* reader, reactor_t* reactor,
+                           eager_reader_cb read_cb, void* context);
+
+// Unregisters |reader| from whichever reactor it is registered with, if any.
+// This
+// function is idempotent.
+void eager_reader_unregister(eager_reader_t* reader);
+
+// Reads up to |max_size| bytes into |buffer| from currently available bytes.
+// NOT SAFE FOR READING FROM MULTIPLE THREADS
+// but you should probably only be reading from one thread anyway,
+// otherwise the byte stream probably doesn't make sense.
+size_t eager_reader_read(eager_reader_t* reader, uint8_t* buffer,
+                         size_t max_size);
+
+// Returns the inbound read thread for a given |reader| or NULL if the thread
+// is not running.
+thread_t* eager_reader_get_read_thread(const eager_reader_t* reader);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/fixed_queue.h b/bt/osi/include/fixed_queue.h
new file mode 100644
index 0000000..c067e63
--- /dev/null
+++ b/bt/osi/include/fixed_queue.h
@@ -0,0 +1,144 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+#include <stdlib.h>
+
+#include "osi/include/list.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct fixed_queue_t;
+typedef struct fixed_queue_t fixed_queue_t;
+typedef struct reactor_t reactor_t;
+
+typedef void (*fixed_queue_free_cb)(void* data);
+typedef void (*fixed_queue_cb)(fixed_queue_t* queue, void* context);
+
+// Creates a new fixed queue with the given |capacity|. If more elements than
+// |capacity| are added to the queue, the caller is blocked until space is
+// made available in the queue. Returns NULL on failure. The caller must free
+// the returned queue with |fixed_queue_free|.
+fixed_queue_t* fixed_queue_new(size_t capacity);
+
+// Frees a queue and (optionally) the enqueued elements.
+// |queue| is the queue to free. If the |free_cb| callback is not null,
+// it is called on each queue element to free it.
+// Freeing a queue that is currently in use (i.e. has waiters
+// blocked on it) results in undefined behaviour.
+void fixed_queue_free(fixed_queue_t* queue, fixed_queue_free_cb free_cb);
+
+// Flushes a queue and (optionally) frees the enqueued elements.
+// |queue| is the queue to flush. If the |free_cb| callback is not null,
+// it is called on each queue element to free it.
+void fixed_queue_flush(fixed_queue_t* queue, fixed_queue_free_cb free_cb);
+
+// Returns a value indicating whether the given |queue| is empty. If |queue|
+// is NULL, the return value is true.
+bool fixed_queue_is_empty(fixed_queue_t* queue);
+
+// Returns the length of the |queue|. If |queue| is NULL, the return value
+// is 0.
+size_t fixed_queue_length(fixed_queue_t* queue);
+
+// Returns the maximum number of elements this queue may hold. |queue| may
+// not be NULL.
+size_t fixed_queue_capacity(fixed_queue_t* queue);
+
+// Enqueues the given |data| into the |queue|. The caller will be blocked
+// if no more space is available in the queue. Neither |queue| nor |data|
+// may be NULL.
+void fixed_queue_enqueue(fixed_queue_t* queue, void* data);
+
+// Dequeues the next element from |queue|. If the queue is currently empty,
+// this function will block the caller until an item is enqueued. This
+// function will never return NULL. |queue| may not be NULL.
+void* fixed_queue_dequeue(fixed_queue_t* queue);
+
+// Tries to enqueue |data| into the |queue|. This function will never block
+// the caller. If the queue capacity would be exceeded by adding one more
+// element, this function returns false immediately. Otherwise, this function
+// returns true. Neither |queue| nor |data| may be NULL.
+bool fixed_queue_try_enqueue(fixed_queue_t* queue, void* data);
+
+// Tries to dequeue an element from |queue|. This function will never block
+// the caller. If the queue is empty or NULL, this function returns NULL
+// immediately. Otherwise, the next element in the queue is returned.
+void* fixed_queue_try_dequeue(fixed_queue_t* queue);
+
+// Returns the first element from |queue|, if present, without dequeuing it.
+// This function will never block the caller. Returns NULL if there are no
+// elements in the queue or |queue| is NULL.
+void* fixed_queue_try_peek_first(fixed_queue_t* queue);
+
+// Returns the last element from |queue|, if present, without dequeuing it.
+// This function will never block the caller. Returns NULL if there are no
+// elements in the queue or |queue| is NULL.
+void* fixed_queue_try_peek_last(fixed_queue_t* queue);
+
+// Tries to remove a |data| element from the middle of the |queue|. This
+// function will never block the caller. If the queue is empty or NULL, this
+// function returns NULL immediately. |data| may not be NULL. If the |data|
+// element is found in the queue, a pointer to the removed data is returned,
+// otherwise NULL.
+void* fixed_queue_try_remove_from_queue(fixed_queue_t* queue, void* data);
+
+// Returns the iterateable list with all entries in the |queue|. This function
+// will never block the caller. |queue| may not be NULL.
+//
+// NOTE: The return result of this function is not thread safe: the list could
+// be modified by another thread, and the result would be unpredictable.
+// TODO: The usage of this function should be refactored, and the function
+// itself should be removed.
+list_t* fixed_queue_get_list(fixed_queue_t* queue);
+
+// This function returns a valid file descriptor. Callers may perform one
+// operation on the fd: select(2). If |select| indicates that the file
+// descriptor is readable, the caller may call |fixed_queue_enqueue| without
+// blocking. The caller must not close the returned file descriptor. |queue|
+// may not be NULL.
+int fixed_queue_get_enqueue_fd(const fixed_queue_t* queue);
+
+// This function returns a valid file descriptor. Callers may perform one
+// operation on the fd: select(2). If |select| indicates that the file
+// descriptor is readable, the caller may call |fixed_queue_dequeue| without
+// blocking. The caller must not close the returned file descriptor. |queue|
+// may not be NULL.
+int fixed_queue_get_dequeue_fd(const fixed_queue_t* queue);
+
+// Registers |queue| with |reactor| for dequeue operations. When there is an
+// element
+// in the queue, ready_cb will be called. The |context| parameter is passed,
+// untouched,
+// to the callback routine. Neither |queue|, nor |reactor|, nor |read_cb| may be
+// NULL.
+// |context| may be NULL.
+void fixed_queue_register_dequeue(fixed_queue_t* queue, reactor_t* reactor,
+                                  fixed_queue_cb ready_cb, void* context);
+
+// Unregisters the dequeue ready callback for |queue| from whichever reactor
+// it is registered with, if any. This function is idempotent.
+void fixed_queue_unregister_dequeue(fixed_queue_t* queue);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/future.h b/bt/osi/include/future.h
new file mode 100644
index 0000000..e9928d3
--- /dev/null
+++ b/bt/osi/include/future.h
@@ -0,0 +1,49 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct future_t future_t;
+
+#define FUTURE_SUCCESS ((void*)1)
+#define FUTURE_FAIL ((void*)0)
+
+// Constructs a new future_t object. Returns NULL on failure.
+future_t* future_new(void);
+
+// Constructs a new future_t object with an immediate |value|. No waiting will
+// occur in the call to |future_await| because the value is already present.
+// Returns NULL on failure.
+future_t* future_new_immediate(void* value);
+
+// Signals that the |future| is ready, passing |value| back to the context
+// waiting for the result. Must only be called once for every future.
+// |future| may not be NULL.
+void future_ready(future_t* future, void* value);
+
+// Waits for the |future| to be ready. Returns the value set in |future_ready|.
+// Frees the future before return. |future| may not be NULL.
+void* future_await(future_t* async_result);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/hash_map_utils.h b/bt/osi/include/hash_map_utils.h
new file mode 100644
index 0000000..1ea3996
--- /dev/null
+++ b/bt/osi/include/hash_map_utils.h
@@ -0,0 +1,40 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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>
+
+// Creates a hash map based on the |params| string containing key and value
+// pairs.  Pairs are expected in the form "key=value" separated by the ';'
+// character.  Both ';' and '=' characters are invalid in keys or values.
+// |params| cannot be NULL, is not modified and is owned by the caller.
+// Examples:
+//   "key0=value10;key1=value1;" -> map: [key0]="value0" [key1]="value1"
+//   "key0=;key1=value1;"        -> map: [key0]="" [key1]="value1"
+//   "=value0;key1=value1;"      -> map: [key1]="value1"
+// A new hash map or NULL is returned and is owned by the caller.
+std::unordered_map<std::string, std::string>
+hash_map_utils_new_from_string_params(const char* params);
+
+// Dumps the contents of the hash_map to the log for debugging purposes.
+// If |map| is not NULL, all entries of |map| will be dumped, otherwise nothing
+// will be dumped. Note that this function does not take the ownership of |map|.
+void hash_map_utils_dump_string_keys_string_values(
+    std::unordered_map<std::string, std::string>& map);
diff --git a/bt/osi/include/list.h b/bt/osi/include/list.h
new file mode 100644
index 0000000..1ecded9
--- /dev/null
+++ b/bt/osi/include/list.h
@@ -0,0 +1,159 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct list_node_t;
+typedef struct list_node_t list_node_t;
+
+struct list_t;
+typedef struct list_t list_t;
+
+typedef void (*list_free_cb)(void* data);
+
+// Iterator callback prototype used for |list_foreach|.
+// |data| represents the list item currently being iterated, |context| is a
+// user defined value passed into |list_foreach|.
+// Callback must return true to continue iterating or false to stop iterating.
+typedef bool (*list_iter_cb)(void* data, void* context);
+
+// Returns a new, empty list. Returns NULL if not enough memory could be
+// allocated
+// for the list structure. The returned list must be freed with |list_free|. The
+// |callback| specifies a function to be called whenever a list element is
+// removed
+// from the list. It can be used to release resources held by the list element,
+// e.g.
+// memory or file descriptor. |callback| may be NULL if no cleanup is necessary
+// on
+// element removal.
+list_t* list_new(list_free_cb callback);
+
+// Frees the list. This function accepts NULL as an argument, in which case it
+// behaves like a no-op.
+void list_free(list_t* list);
+
+// Returns true if |list| is empty (has no elements), false otherwise.
+// |list| may not be NULL.
+bool list_is_empty(const list_t* list);
+
+// Returns true if the list contains |data|, false otherwise.
+// |list| may not be NULL.
+bool list_contains(const list_t* list, const void* data);
+
+// Returns the length of the |list|. |list| may not be NULL.
+size_t list_length(const list_t* list);
+
+// Returns the first element in the list without removing it. |list| may not
+// be NULL or empty.
+void* list_front(const list_t* list);
+
+// Returns the last element in the list without removing it. |list| may not
+// be NULL or empty.
+void* list_back(const list_t* list);
+
+// Returns the last node in the list without removing it. |list| may not
+// be NULL or empty.
+list_node_t* list_back_node(const list_t* list);
+
+// Inserts |data| after |prev_node| in |list|. |data|, |list|, and |prev_node|
+// may not be NULL. This function does not make a copy of |data| so the pointer
+// must remain valid at least until the element is removed from the list or the
+// list is freed. Returns true if |data| could be inserted, false otherwise
+// (e.g. out of memory).
+bool list_insert_after(list_t* list, list_node_t* prev_node, void* data);
+
+// Inserts |data| at the beginning of |list|. Neither |data| nor |list| may be
+// NULL.
+// This function does not make a copy of |data| so the pointer must remain valid
+// at least until the element is removed from the list or the list is freed.
+// Returns true if |data| could be inserted, false otherwise (e.g. out of
+// memory).
+bool list_prepend(list_t* list, void* data);
+
+// Inserts |data| at the end of |list|. Neither |data| nor |list| may be NULL.
+// This function does not make a copy of |data| so the pointer must remain valid
+// at least until the element is removed from the list or the list is freed.
+// Returns true if |data| could be inserted, false otherwise (e.g. out of
+// memory).
+bool list_append(list_t* list, void* data);
+
+// Removes |data| from the list. Neither |list| nor |data| may be NULL. If
+// |data|
+// is inserted multiple times in the list, this function will only remove the
+// first
+// instance. If a free function was specified in |list_new|, it will be called
+// back
+// with |data|. This function returns true if |data| was found in the list and
+// removed,
+// false otherwise.
+bool list_remove(list_t* list, void* data);
+
+// Removes all elements in the list. Calling this function will return the list
+// to the
+// same state it was in after |list_new|. |list| may not be NULL.
+void list_clear(list_t* list);
+
+// Iterates through the |list| and calls |callback| for each data element.
+// Iteration
+// continues until |callback| returns false. The function returns the pointer to
+// last
+// processed element, or NULL if the list is empty, or all calls to |callback|
+// returned
+// true. |context| is passed to |callback| on each iteration.
+// If the list is empty, |callback| will never be called. It is safe to mutate
+// the
+// list inside the callback. If an element is added before the node being
+// visited,
+// there will be no callback for the newly-inserted node. Neither |list| nor
+// |callback| may be NULL.
+list_node_t* list_foreach(const list_t* list, list_iter_cb callback,
+                          void* context);
+
+// Returns an iterator to the first element in |list|. |list| may not be NULL.
+// The returned iterator is valid as long as it does not equal the value
+// returned
+// by |list_end|.
+list_node_t* list_begin(const list_t* list);
+
+// Returns an iterator that points past the end of the list. In other words,
+// this function returns the value of an invalid iterator for the given list.
+// When an iterator has the same value as what's returned by this function, you
+// may no longer call |list_next| with the iterator. |list| may not be NULL.
+list_node_t* list_end(const list_t* list);
+
+// Given a valid iterator |node|, this function returns the next value for the
+// iterator. If the returned value equals the value returned by |list_end|, the
+// iterator has reached the end of the list and may no longer be used for any
+// purpose.
+list_node_t* list_next(const list_node_t* node);
+
+// Returns the value stored at the location pointed to by the iterator |node|.
+// |node| must not equal the value returned by |list_end|.
+void* list_node(const list_node_t* node);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/log.h b/bt/osi/include/log.h
new file mode 100644
index 0000000..d42ea62
--- /dev/null
+++ b/bt/osi/include/log.h
@@ -0,0 +1,86 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+/*
+ * TODO(armansito): Work-around until we figure out a way to generate logs in a
+ * platform-independent manner.
+ */
+#if defined(OS_GENERIC)
+
+/* syslog didn't work well here since we would be redefining LOG_DEBUG. */
+#include <stdio.h>
+
+#define LOGWRAPPER(tag, fmt, args...) \
+  fprintf(stderr, "%s: " fmt "\n", tag, ##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_EVENT_INT(...)
+
+#else /* !defined(OS_GENERIC) */
+
+#include <log/log.h>
+
+/**
+ * These log statements are effectively executing only ALOG(_________, tag, fmt,
+ * ## args ).
+ * fprintf is only to cause compilation error when LOG_TAG is not provided,
+ * which breaks build on Linux (for OS_GENERIC).
+ */
+
+#if LOG_NDEBUG
+#define LOG_VERBOSE(tag, fmt, args...)                          \
+  do {                                                          \
+    (true) ? ((int)0) : fprintf(stderr, "%s" fmt, tag, ##args); \
+  } while (0)
+#else  // LOG_NDEBUG
+#define LOG_VERBOSE(tag, fmt, args...)               \
+  do {                                               \
+    (true) ? ALOG(LOG_VERBOSE, tag, fmt, ##args)     \
+           : fprintf(stderr, "%s" fmt, tag, ##args); \
+  } while (0)
+#endif  // !LOG_NDEBUG
+
+#define LOG_DEBUG(tag, fmt, args...)                 \
+  do {                                               \
+    (true) ? ALOG(LOG_DEBUG, tag, fmt, ##args)       \
+           : fprintf(stderr, "%s" fmt, tag, ##args); \
+  } while (0)
+#define LOG_INFO(tag, fmt, args...)                  \
+  do {                                               \
+    (true) ? ALOG(LOG_INFO, tag, fmt, ##args)        \
+           : fprintf(stderr, "%s" fmt, tag, ##args); \
+  } while (0)
+#define LOG_WARN(tag, fmt, args...)                  \
+  do {                                               \
+    (true) ? ALOG(LOG_WARN, tag, fmt, ##args)        \
+           : fprintf(stderr, "%s" fmt, tag, ##args); \
+  } while (0)
+#define LOG_ERROR(tag, fmt, args...)                 \
+  do {                                               \
+    (true) ? ALOG(LOG_ERROR, tag, fmt, ##args)       \
+           : fprintf(stderr, "%s" fmt, tag, ##args); \
+  } while (0)
+
+#endif /* defined(OS_GENERIC) */
diff --git a/bt/osi/include/metrics.h b/bt/osi/include/metrics.h
new file mode 100644
index 0000000..05ad191
--- /dev/null
+++ b/bt/osi/include/metrics.h
@@ -0,0 +1,97 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+  DEVICE_TYPE_UNKNOWN,
+  DEVICE_TYPE_BREDR,
+  DEVICE_TYPE_LE,
+  DEVICE_TYPE_DUMO,
+} device_type_t;
+
+// Record a pairing event at Unix epoch time |timestamp_ms|
+// |device_class| and |device_type| denote the type of device paired.
+// |disconnect_reason| is the HCI reason for pairing disconnection,
+// see stack/include/hcidefs.h
+void metrics_pair_event(uint32_t disconnect_reason, uint64_t timestamp_ms,
+                        uint32_t device_class, device_type_t device_type);
+
+typedef enum {
+  WAKE_EVENT_UNKNOWN,
+  WAKE_EVENT_ACQUIRED,
+  WAKE_EVENT_RELEASED,
+} wake_event_type_t;
+
+// Record a wake event at Unix epoch time |timestamp_ms|.
+// |type| specifies whether it was acquired or relased,
+// |requestor| if provided is the service requesting the wake lock.
+// |name| is the name of the wake lock held.
+void metrics_wake_event(wake_event_type_t type, const char* requestor,
+                        const char* name, uint64_t timestamp_ms);
+
+typedef enum {
+  SCAN_TYPE_UNKNOWN,
+  SCAN_TECH_TYPE_LE,
+  SCAN_TECH_TYPE_BREDR,
+  SCAN_TECH_TYPE_BOTH,
+} scan_tech_t;
+
+// Record a scan event at Unix epoch time |timestamp_ms|.
+// |start| is true if this is the beginning of the scan.
+// |initiator| is a unique ID identifying the app starting the scan.
+// |type| is whether the scan reports BR/EDR, LE, or both.
+// |results| is the number of results to be reported.
+void metrics_scan_event(bool start, const char* initator, scan_tech_t type,
+                        uint32_t results, uint64_t timestamp_ms);
+
+// Record A2DP session information.
+// |session_duration_sec| is the session duration (in seconds).
+// |device_class| is the device class of the paired device.
+// |media_timer_min_ms| is the minimum scheduled time (in milliseconds)
+// of the media timer.
+// |media_timer_max_ms| is the maximum scheduled time (in milliseconds)
+// of the media timer.
+// |media_timer_avg_ms| is the average scheduled time (in milliseconds)
+// of the media timer.
+// |buffer_overruns_max_count| - TODO - not clear what this is.
+// |buffer_overruns_total| is the number of times the media buffer with
+// audio data has overrun.
+// |buffer_underruns_average| - TODO - not clear what this is.
+// |buffer_underruns_count| is the number of times there was no enough
+// audio data to add to the media buffer.
+void metrics_a2dp_session(
+    int64_t session_duration_sec, const char* disconnect_reason,
+    uint32_t device_class, int32_t media_timer_min_ms,
+    int32_t media_timer_max_ms, int32_t media_timer_avg_ms,
+    int32_t buffer_overruns_max_count, int32_t buffer_overruns_total,
+    float buffer_underruns_average, int32_t buffer_underruns_count);
+
+// Writes the metrics, in packed protobuf format, into the descriptor |fd|.
+// If |clear| is true, metrics events are cleared afterwards.
+void metrics_write(int fd, bool clear);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/mutex.h b/bt/osi/include/mutex.h
new file mode 100644
index 0000000..3d1b306
--- /dev/null
+++ b/bt/osi/include/mutex.h
@@ -0,0 +1,41 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Mutex-related state init
+void mutex_init(void);
+
+// Mutex-related state cleanup
+void mutex_cleanup(void);
+
+// Lock the global mutex
+void mutex_global_lock(void);
+
+// Unlock the global mutex
+void mutex_global_unlock(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/osi.h b/bt/osi/include/osi.h
new file mode 100644
index 0000000..c540812
--- /dev/null
+++ b/bt/osi/include/osi.h
@@ -0,0 +1,75 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define UNUSED_ATTR __attribute__((unused))
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#define INVALID_FD (-1)
+
+#define CONCAT(a, b) a##b
+
+// Use during compile time to check conditional values
+// NOTE: The the failures will present as a generic error
+// "error: initialization makes pointer from integer without a cast"
+// but the file and line number will present the condition that
+// failed.
+#define DUMMY_COUNTER(c) CONCAT(__osi_dummy_, c)
+#define DUMMY_PTR DUMMY_COUNTER(__COUNTER__)
+
+// base/macros.h defines a COMPILE_ASSERT macro to the C++11 keyword
+// "static_assert" (it undef's COMPILE_ASSERT before redefining it).
+// C++ code that includes base and osi/include/osi.h can thus easily default to
+// the definition from libbase but we should check here to avoid compile errors.
+#ifndef COMPILE_ASSERT
+#define COMPILE_ASSERT(COND) \
+  typedef int failed_compile_assert[(COND) ? 1 : -1] __attribute__((unused))
+#endif  // COMPILE_ASSERT
+
+// Macros for safe integer to pointer conversion. In the C language, data is
+// commonly cast to opaque pointer containers and back for generic parameter
+// passing in callbacks. These macros should be used sparingly in new code
+// (never in C++ code). Whenever integers need to be passed as a pointer, use
+// these macros.
+#define PTR_TO_UINT(p) ((unsigned int)((uintptr_t)(p)))
+#define UINT_TO_PTR(u) ((void*)((uintptr_t)(u)))
+
+#define PTR_TO_INT(p) ((int)((intptr_t)(p)))
+#define INT_TO_PTR(i) ((void*)((intptr_t)(i)))
+
+// Obtain a random number between 0 and INT_MAX inclusive.
+// Taken from a system random source such as /dev/random.
+// No guarantees of distribution are made.
+// Effort is made for this to come from a real random source.
+int osi_rand(void);
+
+// Re-run |fn| system call until the system call doesn't cause EINTR.
+#define OSI_NO_INTR(fn) \
+  do {                  \
+  } while ((fn) == -1 && errno == EINTR)
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/properties.h b/bt/osi/include/properties.h
new file mode 100644
index 0000000..c20a3f8
--- /dev/null
+++ b/bt/osi/include/properties.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#if defined(OS_GENERIC)
+#define PROPERTY_VALUE_MAX 92
+#else
+#include <cutils/properties.h>
+#endif  // defined(OS_GENERIC)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Get value associated with key |key| into |value|.
+// Returns the length of the value which will never be greater than
+// PROPERTY_VALUE_MAX - 1 and will always be zero terminated.
+// (the length does not include the terminating zero).
+// If the property read fails or returns an empty value, the |default_value|
+// is used (if nonnull).
+int osi_property_get(const char* key, char* value, const char* default_value);
+
+// Write value of property associated with key |key| to |value|.
+// Returns 0 on success, < 0 on failure
+int osi_property_set(const char* key, const char* value);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/reactor.h b/bt/osi/include/reactor.h
new file mode 100644
index 0000000..d3eca37
--- /dev/null
+++ b/bt/osi/include/reactor.h
@@ -0,0 +1,107 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+#include <stdint.h>
+
+#include "osi/include/osi.h"
+
+// This module implements the Reactor pattern.
+// See http://en.wikipedia.org/wiki/Reactor_pattern for details.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct reactor_t reactor_t;
+typedef struct reactor_object_t reactor_object_t;
+
+// Enumerates the reasons a reactor has stopped.
+typedef enum {
+  REACTOR_STATUS_STOP,   // |reactor_stop| was called.
+  REACTOR_STATUS_ERROR,  // there was an error during the operation.
+  REACTOR_STATUS_DONE,   // the reactor completed its work (for the _run_once*
+                         // variants).
+} reactor_status_t;
+
+// Creates a new reactor object. Returns NULL on failure. The returned object
+// must be freed by calling |reactor_free|.
+reactor_t* reactor_new(void);
+
+// Frees a reactor object created with |reactor_new|. |reactor| may be NULL.
+void reactor_free(reactor_t* reactor);
+
+// Starts the reactor. This function blocks the caller until |reactor_stop| is
+// called
+// from another thread or in a callback. |reactor| may not be NULL.
+reactor_status_t reactor_start(reactor_t* reactor);
+
+// Runs one iteration of the reactor. This function blocks until at least one
+// registered object
+// becomes ready. |reactor| may not be NULL.
+reactor_status_t reactor_run_once(reactor_t* reactor);
+
+// Immediately unblocks the reactor. This function is safe to call from any
+// thread.
+// |reactor| may not be NULL.
+void reactor_stop(reactor_t* reactor);
+
+// Registers a file descriptor with the reactor. The file descriptor, |fd|, must
+// be valid
+// when this function is called and its ownership is not transferred to the
+// reactor. The
+// |context| variable is a user-defined opaque handle that is passed back to the
+// |read_ready|
+// and |write_ready| functions. It is not copied or even dereferenced by the
+// reactor so it
+// may contain any value including NULL. The |read_ready| and |write_ready|
+// arguments are
+// optional and may be NULL. This function returns an opaque object that
+// represents the
+// file descriptor's registration with the reactor. When the caller is no longer
+// interested
+// in events on the |fd|, it must free the returned object by calling
+// |reactor_unregister|.
+reactor_object_t* reactor_register(reactor_t* reactor, int fd, void* context,
+                                   void (*read_ready)(void* context),
+                                   void (*write_ready)(void* context));
+
+// Changes the subscription mode for the file descriptor represented by
+// |object|. If the
+// caller has already registered a file descriptor with a reactor, has a valid
+// |object|,
+// and decides to change the |read_ready| and/or |write_ready| callback
+// routines, they
+// can call this routine. Returns true if the subscription was changed, false
+// otherwise.
+// |object| may not be NULL, |read_ready| and |write_ready| may be NULL.
+bool reactor_change_registration(reactor_object_t* object,
+                                 void (*read_ready)(void* context),
+                                 void (*write_ready)(void* context));
+
+// Unregisters a previously registered file descriptor with its reactor. |obj|
+// may not be NULL.
+// |obj| is invalid after calling this function so the caller must drop all
+// references to it.
+void reactor_unregister(reactor_object_t* obj);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/ringbuffer.h b/bt/osi/include/ringbuffer.h
new file mode 100644
index 0000000..34d8dc4
--- /dev/null
+++ b/bt/osi/include/ringbuffer.h
@@ -0,0 +1,70 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ringbuffer_t ringbuffer_t;
+
+// NOTE:
+// None of the functions below are thread safe when it comes to accessing the
+// *rb pointer. It is *NOT* possible to insert and pop/delete at the same time.
+// Callers must protect the *rb pointer separately.
+
+// Create a ringbuffer with the specified size
+// Returns NULL if memory allocation failed. Resulting pointer must be freed
+// using |ringbuffer_free|.
+ringbuffer_t* ringbuffer_init(const size_t size);
+
+// Frees the ringbuffer structure and buffer
+// Save to call with NULL.
+void ringbuffer_free(ringbuffer_t* rb);
+
+// Returns remaining buffer size
+size_t ringbuffer_available(const ringbuffer_t* rb);
+
+// Returns size of data in buffer
+size_t ringbuffer_size(const ringbuffer_t* rb);
+
+// Attempts to insert up to |length| bytes of data at |p| into the buffer
+// Return actual number of bytes added. Can be less than |length| if buffer
+// is full.
+size_t ringbuffer_insert(ringbuffer_t* rb, const uint8_t* p, size_t length);
+
+// Peek |length| number of bytes from the ringbuffer, starting at |offset|,
+// into the buffer |p|. Return the actual number of bytes peeked. Can be less
+// than |length| if there is less than |length| data available. |offset| must
+// be non-negative.
+size_t ringbuffer_peek(const ringbuffer_t* rb, off_t offset, uint8_t* p,
+                       size_t length);
+
+// Does the same as |ringbuffer_peek|, but also advances the ring buffer head
+size_t ringbuffer_pop(ringbuffer_t* rb, uint8_t* p, size_t length);
+
+// Deletes |length| bytes from the ringbuffer starting from the head
+// Return actual number of bytes deleted.
+size_t ringbuffer_delete(ringbuffer_t* rb, size_t length);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/semaphore.h b/bt/osi/include/semaphore.h
new file mode 100644
index 0000000..29d03fd
--- /dev/null
+++ b/bt/osi/include/semaphore.h
@@ -0,0 +1,66 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct semaphore_t;
+typedef struct semaphore_t semaphore_t;
+
+// Creates a new semaphore with an initial value of |value|.
+// Returns NULL on failure. The returned object must be released
+// with |semaphore_free|.
+semaphore_t* semaphore_new(unsigned int value);
+
+// Frees a semaphore allocated with |semaphore_new|. |semaphore| may
+// be NULL.
+void semaphore_free(semaphore_t* semaphore);
+
+// Decrements the value of |semaphore|. If it is 0, this call blocks until
+// it becomes non-zero. |semaphore| may not be NULL.
+void semaphore_wait(semaphore_t* semaphore);
+
+// Tries to decrement the value of |semaphore|. Returns true if the value was
+// decremented, false if the value was 0. This function never blocks.
+// |semaphore|
+// may not be NULL.
+bool semaphore_try_wait(semaphore_t* semaphore);
+
+// Increments the value of |semaphore|. |semaphore| may not be NULL.
+void semaphore_post(semaphore_t* semaphore);
+
+// Returns a file descriptor representing this semaphore. The caller may
+// only perform one operation on the file descriptor: select(2). If |select|
+// indicates the fd is readable, the caller may call |semaphore_wait|
+// without blocking. If select indicates the fd is writable, the caller may
+// call |semaphore_post| without blocking. Note that there may be a race
+// condition between calling |select| and |semaphore_wait| or |semaphore_post|
+// which results in blocking behaviour.
+//
+// The caller must not close the returned file descriptor. |semaphore| may not
+// be NULL.
+int semaphore_get_fd(const semaphore_t* semaphore);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/socket.h b/bt/osi/include/socket.h
new file mode 100644
index 0000000..e5d4c8e
--- /dev/null
+++ b/bt/osi/include/socket.h
@@ -0,0 +1,129 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct reactor_t reactor_t;
+typedef struct socket_t socket_t;
+typedef uint16_t port_t;
+
+typedef void (*socket_cb)(socket_t* socket, void* context);
+
+// Returns a new socket object. The socket is in an idle, disconnected state
+// when
+// it is returned by this function. The returned object must be freed by calling
+// |socket_free|. Returns NULL on failure.
+socket_t* socket_new(void);
+
+// Returns a new socket object backed by |fd|. The socket object is in whichever
+// state |fd| is in when it was passed to this function. The returned object
+// must
+// be freed by calling |socket_free|. Returns NULL on failure. If this function
+// is successful, ownership of |fd| is transferred and the caller must not close
+// it.
+socket_t* socket_new_from_fd(int fd);
+
+// Frees a socket object created by |socket_new| or |socket_accept|. |socket|
+// may
+// be NULL. If the socket was connected, it will be disconnected.
+void socket_free(socket_t* socket);
+
+// Puts |socket| in listening mode for incoming TCP connections on the specified
+// |port| and the loopback IPv4 address. Returns true on success, false on
+// failure (e.g. |port| is bound by another socket). |socket| may not be NULL.
+bool socket_listen(const socket_t* socket, port_t port);
+
+// Blocks on a listening socket, |socket|, until a client connects to it.
+// Returns
+// a connected socket on success, NULL on failure. The returned object must be
+// freed by calling |socket_free|. |socket| may not be NULL.
+socket_t* socket_accept(const socket_t* socket);
+
+// Reads up to |count| bytes from |socket| into |buf|. This function will not
+// block. This function returns a positive integer representing the number
+// of bytes copied into |buf| on success, 0 if the socket has disconnected,
+// and -1 on error. This function may return a value less than |count| if not
+// enough data is currently available. If this function returns -1, errno will
+// also be set (see recv(2) for possible errno values). However, if the reading
+// system call was interrupted with errno of EINTR, the read operation is
+// restarted internally without propagating EINTR back to the caller. If there
+// were no bytes available to be read, this function returns -1 and sets errno
+// to EWOULDBLOCK. Neither |socket| nor |buf| may be NULL.
+ssize_t socket_read(const socket_t* socket, void* buf, size_t count);
+
+// Writes up to |count| bytes from |buf| into |socket|. This function will not
+// block. Returns a positive integer representing the number of bytes written
+// to |socket| on success, 0 if the socket has disconnected, and -1 on error.
+// This function may return a value less than |count| if writing more bytes
+// would result in blocking. If this function returns -1, errno will also be
+// set (see send(2) for possible errno values). However, if the writing system
+// call was interrupted with errno of EINTR, the write operation is restarted
+// internally without propagating EINTR back to the caller. If no bytes could
+// be written without blocking, this function will return -1 and set errno to
+// EWOULDBLOCK. Neither |socket| nor |buf| may be NULL.
+ssize_t socket_write(const socket_t* socket, const void* buf, size_t count);
+
+// This function performs the same write operation as |socket_write| and also
+// sends the file descriptor |fd| over the socket to a remote process. Ownership
+// of |fd| transfers to this function and the descriptor must not be used any
+// longer.
+// If |fd| is INVALID_FD, this function behaves the same as |socket_write|.
+ssize_t socket_write_and_transfer_fd(const socket_t* socket, const void* buf,
+                                     size_t count, int fd);
+
+// Returns the number of bytes that can be read from |socket| without blocking.
+// On error,
+// this function returns -1. |socket| may not be NULL.
+//
+// Note: this function should not be part of the socket interface. It is only
+// provided as
+//       a stop-gap until we can refactor away code that depends on a priori
+//       knowledge of
+//       the byte count. Do not use this function unless you need it while
+//       refactoring
+//       legacy bluedroid code.
+ssize_t socket_bytes_available(const socket_t* socket);
+
+// Registers |socket| with the |reactor|. When the socket becomes readable,
+// |read_cb|
+// will be called. When the socket becomes writeable, |write_cb| will be called.
+// The
+// |context| parameter is passed, untouched, to each of the callback routines.
+// Neither
+// |socket| nor |reactor| may be NULL. |read_cb|, |write_cb|, and |context| may
+// be NULL.
+void socket_register(socket_t* socket, reactor_t* reactor, void* context,
+                     socket_cb read_cb, socket_cb write_cb);
+
+// Unregisters |socket| from whichever reactor it is registered with, if any.
+// This
+// function is idempotent.
+void socket_unregister(socket_t* socket);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/socket_utils/socket_local.h b/bt/osi/include/socket_utils/socket_local.h
new file mode 100644
index 0000000..08b20c3
--- /dev/null
+++ b/bt/osi/include/socket_utils/socket_local.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define FILESYSTEM_SOCKET_PREFIX "/tmp/"
+#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/"
+
+/*
+ * Set up a given sockaddr_un, to have it refer to the given
+ * name in the given namespace. The namespace must be one
+ * of <code>ANDROID_SOCKET_NAMESPACE_ABSTRACT</code>,
+ * <code>ANDROID_SOCKET_NAMESPACE_RESERVED</code>, or
+ * <code>ANDROID_SOCKET_NAMESPACE_FILESYSTEM</code>. Upon success,
+ * the pointed at sockaddr_un is filled in and the pointed at
+ * socklen_t is set to indicate the final length. This function
+ * will fail if the namespace is invalid (not one of the indicated
+ * constants) or if the name is too long.
+ *
+ * @return 0 on success or -1 on failure
+ */
+int osi_socket_make_sockaddr_un(const char* name, int namespaceId,
+                                struct sockaddr_un* p_addr, socklen_t* alen);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/socket_utils/sockets.h b/bt/osi/include/socket_utils/sockets.h
new file mode 100644
index 0000000..4508a30
--- /dev/null
+++ b/bt/osi/include/socket_utils/sockets.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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 <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#define ANDROID_SOCKET_ENV_PREFIX "ANDROID_SOCKET_"
+#define ANDROID_SOCKET_DIR "/dev/socket"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * osi_android_get_control_socket - simple helper function to get the file
+ * descriptor of our init-managed Unix domain socket. `name' is the name of the
+ * socket, as given in init.rc. Returns -1 on error.
+ *
+ * This is inline and not in libcutils proper because we want to use this in
+ * third-party daemons with minimal modification.
+ */
+static inline int osi_android_get_control_socket(const char* name) {
+  char key[64];
+  snprintf(key, sizeof(key), ANDROID_SOCKET_ENV_PREFIX "%s", name);
+
+  const char* val = getenv(key);
+  if (!val) {
+    return -1;
+  }
+
+  errno = 0;
+  int fd = strtol(val, NULL, 10);
+  if (errno) {
+    return -1;
+  }
+
+  return fd;
+}
+
+/*
+ * See also android.os.LocalSocketAddress.Namespace
+ */
+// Linux "abstract" (non-filesystem) namespace
+#define ANDROID_SOCKET_NAMESPACE_ABSTRACT 0
+// Android "reserved" (/dev/socket) namespace
+#define ANDROID_SOCKET_NAMESPACE_RESERVED 1
+// Normal filesystem namespace
+#define ANDROID_SOCKET_NAMESPACE_FILESYSTEM 2
+
+extern int osi_socket_local_server(const char* name, int namespaceId, int type);
+extern int osi_socket_local_server_bind(int s, const char* name,
+                                        int namespaceId);
+extern int osi_socket_local_client_connect(int fd, const char* name,
+                                           int namespaceId, int type);
+extern int osi_socket_local_client(const char* name, int namespaceId, int type);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/thread.h b/bt/osi/include/thread.h
new file mode 100644
index 0000000..7f9ef80
--- /dev/null
+++ b/bt/osi/include/thread.h
@@ -0,0 +1,85 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <stdbool.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define THREAD_NAME_MAX 16
+
+typedef struct reactor_t reactor_t;
+typedef struct thread_t thread_t;
+
+typedef void (*thread_fn)(void* context);
+
+// Creates and starts a new thread with the given name. Only THREAD_NAME_MAX
+// bytes from |name| will be assigned to the newly-created thread. Returns a
+// thread object if the thread was successfully started, NULL otherwise. The
+// returned thread object must be freed with |thread_free|. |name| may not
+// be NULL.
+thread_t* thread_new(const char* name);
+
+// Similar to |thread_new| but creates with a given queue |size|.
+thread_t* thread_new_sized(const char* name, size_t size);
+
+// Frees the given |thread|. If the thread is still running, it is stopped
+// and the calling thread will block until |thread| terminates. |thread|
+// may be NULL.
+void thread_free(thread_t* thread);
+
+// Waits for |thread_stop|. Upon returning, the only other operations a caller
+// may perform on |thread| are |thread_free| and |thread_join|. |thread_join|
+// is idempotent and may be called from any thread. |thread| may not be NULL.
+void thread_join(thread_t* thread);
+
+// Call |func| with the argument |context| on |thread|. This function typically
+// does not block unless there are an excessive number of functions posted to
+// |thread| that have not been dispatched yet. Neither |thread| nor |func| may
+// be NULL. |context| may be NULL.
+// Return true on success, otherwise false.
+bool thread_post(thread_t* thread, thread_fn func, void* context);
+
+// Requests |thread| to stop. Only |thread_free| and |thread_name| may be called
+// after calling |thread_stop|. This function is guaranteed to not block.
+// |thread| may not be NULL.
+void thread_stop(thread_t* thread);
+
+// Attempts to sets the |priority| of a given |thread|.
+// The |thread| has to be running for this call to succeed.
+// Returns true on success.
+bool thread_set_priority(thread_t* thread, int priority);
+
+// Returns true if the current thread is the same as the one represented by
+// |thread|.
+// |thread| may not be NULL.
+bool thread_is_self(const thread_t* thread);
+
+// Returns the reactor for the given |thread|. |thread| may not be NULL.
+reactor_t* thread_get_reactor(const thread_t* thread);
+
+// Returns the name of the given |thread|. |thread| may not be NULL.
+const char* thread_name(const thread_t* thread);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/time.h b/bt/osi/include/time.h
new file mode 100644
index 0000000..8392484
--- /dev/null
+++ b/bt/osi/include/time.h
@@ -0,0 +1,47 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef uint64_t period_ms_t;
+
+// Get the OS boot time in milliseconds.
+//
+// NOTE: The return value will rollover every 49.7 days,
+// hence it cannot be used for absolute time comparison.
+// Relative time comparison using 32-bits integers such
+// as (t2_u32 - t1_u32 < delta_u32) should work as expected as long
+// as there is no multiple rollover between t2_u32 and t1_u32.
+//
+// TODO: This function's return type should be modified to |period_ms_t|.
+// Be careful: some of the code that is using it assumes the return type
+// is uint32_t.
+uint32_t time_get_os_boottime_ms(void);
+
+// Get the OS boot time in microseconds.
+uint64_t time_get_os_boottime_us(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/include/wakelock.h b/bt/osi/include/wakelock.h
new file mode 100644
index 0000000..0d8415f
--- /dev/null
+++ b/bt/osi/include/wakelock.h
@@ -0,0 +1,62 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <hardware/bluetooth.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Set the Bluetooth OS callouts to |callouts|.
+// This function should be called when native kernel wakelocks are not used
+// directly. If this function is not called, or |callouts| is NULL, then native
+// kernel wakelocks will be used.
+void wakelock_set_os_callouts(bt_os_callouts_t* callouts);
+
+// Acquire the Bluetooth wakelock.
+// The function is thread safe.
+// Return true on success, otherwise false.
+bool wakelock_acquire(void);
+
+// Release the Bluetooth wakelock.
+// The function is thread safe.
+// Return true on success, otherwise false.
+bool wakelock_release(void);
+
+// Cleanup the wakelock internal state.
+// This function should be called by the OSI module cleanup during
+// graceful shutdown.
+void wakelock_cleanup(void);
+
+// This function should not need to be called normally.
+// /sys/power/wake_{|un}lock are used by default.
+// This is not guaranteed to have any effect after an alarm has been
+// set with alarm_set.
+// If |lock_path| or |unlock_path| are NULL, that path is not changed.
+void wakelock_set_paths(const char* lock_path, const char* unlock_path);
+
+// Dump wakelock-related debug info to the |fd| file descriptor.
+// The caller is responsible for closing the |fd|.
+void wakelock_debug_dump(int fd);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/src/alarm.cc b/bt/osi/src/alarm.cc
new file mode 100644
index 0000000..d4e437a
--- /dev/null
+++ b/bt/osi/src/alarm.cc
@@ -0,0 +1,769 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "include/bt_target.h"
+
+#define LOG_TAG "bt_osi_alarm"
+
+#include "osi/include/alarm.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <malloc.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include <time.h>
+
+#include <hardware/bluetooth.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/semaphore.h"
+#include "osi/include/thread.h"
+#include "osi/include/wakelock.h"
+
+// Make callbacks run at high thread priority. Some callbacks are used for audio
+// related timer tasks as well as re-transmissions etc. Since we at this point
+// cannot differentiate what callback we are dealing with, assume high priority
+// for now.
+// TODO(eisenbach): Determine correct thread priority (from parent?/per alarm?)
+static const int CALLBACK_THREAD_PRIORITY_HIGH = -19;
+
+typedef struct {
+  size_t count;
+  period_ms_t total_ms;
+  period_ms_t max_ms;
+} stat_t;
+
+// Alarm-related information and statistics
+typedef struct {
+  const char* name;
+  size_t scheduled_count;
+  size_t canceled_count;
+  size_t rescheduled_count;
+  size_t total_updates;
+  period_ms_t last_update_ms;
+  stat_t callback_execution;
+  stat_t overdue_scheduling;
+  stat_t premature_scheduling;
+} alarm_stats_t;
+
+struct alarm_t {
+  // The lock is held while the callback for this alarm is being executed.
+  // It allows us to release the coarse-grained monitor lock while a
+  // potentially long-running callback is executing. |alarm_cancel| uses this
+  // lock to provide a guarantee to its caller that the callback will not be
+  // in progress when it returns.
+  pthread_mutex_t callback_lock;
+  period_ms_t creation_time;
+  period_ms_t period;
+  period_ms_t deadline;
+  period_ms_t prev_deadline;  // Previous deadline - used for accounting of
+                              // periodic timers
+  bool is_periodic;
+  fixed_queue_t* queue;  // The processing queue to add this alarm to
+  alarm_callback_t callback;
+  void* data;
+  alarm_stats_t stats;
+};
+
+// If the next wakeup time is less than this threshold, we should acquire
+// a wakelock instead of setting a wake alarm so we're not bouncing in
+// and out of suspend frequently. This value is externally visible to allow
+// unit tests to run faster. It should not be modified by production code.
+int64_t TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 3000;
+static const clockid_t CLOCK_ID = CLOCK_BOOTTIME;
+
+#define KERNEL_MISSING_CLOCK_BOOTTIME_ALARM TRUE
+
+#if (KERNEL_MISSING_CLOCK_BOOTTIME_ALARM == TRUE)
+static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME;
+#else
+static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME_ALARM;
+#endif
+
+// This mutex ensures that the |alarm_set|, |alarm_cancel|, and alarm callback
+// functions execute serially and not concurrently. As a result, this mutex
+// also protects the |alarms| list.
+static pthread_mutex_t monitor;
+static list_t* alarms;
+static timer_t timer;
+static timer_t wakeup_timer;
+static bool timer_set;
+
+// All alarm callbacks are dispatched from |dispatcher_thread|
+static thread_t* dispatcher_thread;
+static bool dispatcher_thread_active;
+static semaphore_t* alarm_expired;
+
+// Default alarm callback thread and queue
+static thread_t* default_callback_thread;
+static fixed_queue_t* default_callback_queue;
+
+static alarm_t* alarm_new_internal(const char* name, bool is_periodic);
+static bool lazy_initialize(void);
+static period_ms_t now(void);
+static void alarm_set_internal(alarm_t* alarm, period_ms_t period,
+                               alarm_callback_t cb, void* data,
+                               fixed_queue_t* queue);
+static void alarm_cancel_internal(alarm_t* alarm);
+static void remove_pending_alarm(alarm_t* alarm);
+static void schedule_next_instance(alarm_t* alarm);
+static void reschedule_root_alarm(void);
+static void alarm_queue_ready(fixed_queue_t* queue, void* context);
+static void timer_callback(void* data);
+static void callback_dispatch(void* context);
+static bool timer_create_internal(const clockid_t clock_id, timer_t* timer);
+static void update_scheduling_stats(alarm_stats_t* stats, period_ms_t now_ms,
+                                    period_ms_t deadline_ms,
+                                    period_ms_t execution_delta_ms);
+
+static void update_stat(stat_t* stat, period_ms_t delta) {
+  if (stat->max_ms < delta) stat->max_ms = delta;
+  stat->total_ms += delta;
+  stat->count++;
+}
+
+alarm_t* alarm_new(const char* name) { return alarm_new_internal(name, false); }
+
+alarm_t* alarm_new_periodic(const char* name) {
+  return alarm_new_internal(name, true);
+}
+
+static alarm_t* alarm_new_internal(const char* name, bool is_periodic) {
+  // Make sure we have a list we can insert alarms into.
+  if (!alarms && !lazy_initialize()) {
+    assert(false);  // if initialization failed, we should not continue
+    return NULL;
+  }
+
+  pthread_mutexattr_t attr;
+  pthread_mutexattr_init(&attr);
+
+  alarm_t* ret = static_cast<alarm_t*>(osi_calloc(sizeof(alarm_t)));
+
+  // Make this a recursive mutex to make it safe to call |alarm_cancel| from
+  // within the callback function of the alarm.
+  int error = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+  if (error) {
+    LOG_ERROR(LOG_TAG, "%s unable to create a recursive mutex: %s", __func__,
+              strerror(error));
+    goto error;
+  }
+
+  error = pthread_mutex_init(&ret->callback_lock, &attr);
+  if (error) {
+    LOG_ERROR(LOG_TAG, "%s unable to initialize mutex: %s", __func__,
+              strerror(error));
+    goto error;
+  }
+
+  ret->is_periodic = is_periodic;
+  ret->stats.name = osi_strdup(name);
+  // NOTE: The stats were reset by osi_calloc() above
+
+  pthread_mutexattr_destroy(&attr);
+  return ret;
+
+error:
+  pthread_mutexattr_destroy(&attr);
+  osi_free(ret);
+  return NULL;
+}
+
+void alarm_free(alarm_t* alarm) {
+  if (!alarm) return;
+
+  alarm_cancel(alarm);
+  pthread_mutex_destroy(&alarm->callback_lock);
+  osi_free((void*)alarm->stats.name);
+  osi_free(alarm);
+}
+
+period_ms_t alarm_get_remaining_ms(const alarm_t* alarm) {
+  assert(alarm != NULL);
+  period_ms_t remaining_ms = 0;
+  period_ms_t just_now = now();
+
+  pthread_mutex_lock(&monitor);
+  if (alarm->deadline > just_now) remaining_ms = alarm->deadline - just_now;
+  pthread_mutex_unlock(&monitor);
+
+  return remaining_ms;
+}
+
+void alarm_set(alarm_t* alarm, period_ms_t interval_ms, alarm_callback_t cb,
+               void* data) {
+  alarm_set_on_queue(alarm, interval_ms, cb, data, default_callback_queue);
+}
+
+void alarm_set_on_queue(alarm_t* alarm, period_ms_t interval_ms,
+                        alarm_callback_t cb, void* data, fixed_queue_t* queue) {
+  assert(queue != NULL);
+  alarm_set_internal(alarm, interval_ms, cb, data, queue);
+}
+
+// Runs in exclusion with alarm_cancel and timer_callback.
+static void alarm_set_internal(alarm_t* alarm, period_ms_t period,
+                               alarm_callback_t cb, void* data,
+                               fixed_queue_t* queue) {
+  assert(alarms != NULL);
+  assert(alarm != NULL);
+  assert(cb != NULL);
+
+  pthread_mutex_lock(&monitor);
+
+  alarm->creation_time = now();
+  alarm->period = period;
+  alarm->queue = queue;
+  alarm->callback = cb;
+  alarm->data = data;
+
+  schedule_next_instance(alarm);
+  alarm->stats.scheduled_count++;
+
+  pthread_mutex_unlock(&monitor);
+}
+
+void alarm_cancel(alarm_t* alarm) {
+  assert(alarms != NULL);
+  if (!alarm) return;
+
+  pthread_mutex_lock(&monitor);
+  alarm_cancel_internal(alarm);
+  pthread_mutex_unlock(&monitor);
+
+  // If the callback for |alarm| is in progress, wait here until it completes.
+  pthread_mutex_lock(&alarm->callback_lock);
+  pthread_mutex_unlock(&alarm->callback_lock);
+}
+
+// Internal implementation of canceling an alarm.
+// The caller must hold the |monitor| lock.
+static void alarm_cancel_internal(alarm_t* alarm) {
+  bool needs_reschedule =
+      (!list_is_empty(alarms) && list_front(alarms) == alarm);
+
+  remove_pending_alarm(alarm);
+
+  alarm->deadline = 0;
+  alarm->prev_deadline = 0;
+  alarm->callback = NULL;
+  alarm->data = NULL;
+  alarm->stats.canceled_count++;
+  alarm->queue = NULL;
+
+  if (needs_reschedule) reschedule_root_alarm();
+}
+
+bool alarm_is_scheduled(const alarm_t* alarm) {
+  if ((alarms == NULL) || (alarm == NULL)) return false;
+  return (alarm->callback != NULL);
+}
+
+void alarm_cleanup(void) {
+  // If lazy_initialize never ran there is nothing else to do
+  if (!alarms) return;
+
+  dispatcher_thread_active = false;
+  semaphore_post(alarm_expired);
+  thread_free(dispatcher_thread);
+  dispatcher_thread = NULL;
+
+  pthread_mutex_lock(&monitor);
+
+  fixed_queue_free(default_callback_queue, NULL);
+  default_callback_queue = NULL;
+  thread_free(default_callback_thread);
+  default_callback_thread = NULL;
+
+  timer_delete(wakeup_timer);
+  timer_delete(timer);
+  semaphore_free(alarm_expired);
+  alarm_expired = NULL;
+
+  list_free(alarms);
+  alarms = NULL;
+
+  pthread_mutex_unlock(&monitor);
+  pthread_mutex_destroy(&monitor);
+}
+
+static bool lazy_initialize(void) {
+  assert(alarms == NULL);
+
+  // timer_t doesn't have an invalid value so we must track whether
+  // the |timer| variable is valid ourselves.
+  bool timer_initialized = false;
+  bool wakeup_timer_initialized = false;
+
+  pthread_mutex_init(&monitor, NULL);
+
+  alarms = list_new(NULL);
+  if (!alarms) {
+    LOG_ERROR(LOG_TAG, "%s unable to allocate alarm list.", __func__);
+    goto error;
+  }
+
+  if (!timer_create_internal(CLOCK_ID, &timer)) goto error;
+  timer_initialized = true;
+
+  if (!timer_create_internal(CLOCK_ID_ALARM, &wakeup_timer)) goto error;
+  wakeup_timer_initialized = true;
+
+  alarm_expired = semaphore_new(0);
+  if (!alarm_expired) {
+    LOG_ERROR(LOG_TAG, "%s unable to create alarm expired semaphore", __func__);
+    goto error;
+  }
+
+  default_callback_thread =
+      thread_new_sized("alarm_default_callbacks", SIZE_MAX);
+  if (default_callback_thread == NULL) {
+    LOG_ERROR(LOG_TAG, "%s unable to create default alarm callbacks thread.",
+              __func__);
+    goto error;
+  }
+  thread_set_priority(default_callback_thread, CALLBACK_THREAD_PRIORITY_HIGH);
+  default_callback_queue = fixed_queue_new(SIZE_MAX);
+  if (default_callback_queue == NULL) {
+    LOG_ERROR(LOG_TAG, "%s unable to create default alarm callbacks queue.",
+              __func__);
+    goto error;
+  }
+  alarm_register_processing_queue(default_callback_queue,
+                                  default_callback_thread);
+
+  dispatcher_thread_active = true;
+  dispatcher_thread = thread_new("alarm_dispatcher");
+  if (!dispatcher_thread) {
+    LOG_ERROR(LOG_TAG, "%s unable to create alarm callback thread.", __func__);
+    goto error;
+  }
+
+  thread_set_priority(dispatcher_thread, CALLBACK_THREAD_PRIORITY_HIGH);
+  thread_post(dispatcher_thread, callback_dispatch, NULL);
+  return true;
+
+error:
+  fixed_queue_free(default_callback_queue, NULL);
+  default_callback_queue = NULL;
+  thread_free(default_callback_thread);
+  default_callback_thread = NULL;
+
+  thread_free(dispatcher_thread);
+  dispatcher_thread = NULL;
+
+  dispatcher_thread_active = false;
+
+  semaphore_free(alarm_expired);
+  alarm_expired = NULL;
+
+  if (wakeup_timer_initialized) timer_delete(wakeup_timer);
+
+  if (timer_initialized) timer_delete(timer);
+
+  list_free(alarms);
+  alarms = NULL;
+
+  pthread_mutex_destroy(&monitor);
+
+  return false;
+}
+
+static period_ms_t now(void) {
+  assert(alarms != NULL);
+
+  struct timespec ts;
+  if (clock_gettime(CLOCK_ID, &ts) == -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to get current time: %s", __func__,
+              strerror(errno));
+    return 0;
+  }
+
+  return (ts.tv_sec * 1000LL) + (ts.tv_nsec / 1000000LL);
+}
+
+// Remove alarm from internal alarm list and the processing queue
+// The caller must hold the |monitor| lock.
+static void remove_pending_alarm(alarm_t* alarm) {
+  list_remove(alarms, alarm);
+  while (fixed_queue_try_remove_from_queue(alarm->queue, alarm) != NULL) {
+    // Remove all repeated alarm instances from the queue.
+    // NOTE: We are defensive here - we shouldn't have repeated alarm instances
+  }
+}
+
+// Must be called with monitor held
+static void schedule_next_instance(alarm_t* alarm) {
+  // If the alarm is currently set and it's at the start of the list,
+  // we'll need to re-schedule since we've adjusted the earliest deadline.
+  bool needs_reschedule =
+      (!list_is_empty(alarms) && list_front(alarms) == alarm);
+  if (alarm->callback) remove_pending_alarm(alarm);
+
+  // Calculate the next deadline for this alarm
+  period_ms_t just_now = now();
+  period_ms_t ms_into_period = 0;
+  if ((alarm->is_periodic) && (alarm->period != 0))
+    ms_into_period = ((just_now - alarm->creation_time) % alarm->period);
+  alarm->deadline = just_now + (alarm->period - ms_into_period);
+
+  // Add it into the timer list sorted by deadline (earliest deadline first).
+  if (list_is_empty(alarms) ||
+      ((alarm_t*)list_front(alarms))->deadline > alarm->deadline) {
+    list_prepend(alarms, alarm);
+  } else {
+    for (list_node_t* node = list_begin(alarms); node != list_end(alarms);
+         node = list_next(node)) {
+      list_node_t* next = list_next(node);
+      if (next == list_end(alarms) ||
+          ((alarm_t*)list_node(next))->deadline > alarm->deadline) {
+        list_insert_after(alarms, node, alarm);
+        break;
+      }
+    }
+  }
+
+  // If the new alarm has the earliest deadline, we need to re-evaluate our
+  // schedule.
+  if (needs_reschedule ||
+      (!list_is_empty(alarms) && list_front(alarms) == alarm)) {
+    reschedule_root_alarm();
+  }
+}
+
+// NOTE: must be called with monitor lock.
+static void reschedule_root_alarm(void) {
+  assert(alarms != NULL);
+
+  const bool timer_was_set = timer_set;
+  alarm_t* next;
+  int64_t next_expiration;
+
+  // If used in a zeroed state, disarms the timer.
+  struct itimerspec timer_time;
+  memset(&timer_time, 0, sizeof(timer_time));
+
+  if (list_is_empty(alarms)) goto done;
+
+  next = static_cast<alarm_t*>(list_front(alarms));
+  next_expiration = next->deadline - now();
+  if (next_expiration < TIMER_INTERVAL_FOR_WAKELOCK_IN_MS) {
+    if (!timer_set) {
+      if (!wakelock_acquire()) {
+        LOG_ERROR(LOG_TAG, "%s unable to acquire wake lock", __func__);
+        goto done;
+      }
+    }
+
+    timer_time.it_value.tv_sec = (next->deadline / 1000);
+    timer_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL;
+
+    // It is entirely unsafe to call timer_settime(2) with a zeroed timerspec
+    // for timers with *_ALARM clock IDs. Although the man page states that the
+    // timer would be canceled, the current behavior (as of Linux kernel 3.17)
+    // is that the callback is issued immediately. The only way to cancel an
+    // *_ALARM timer is to delete the timer. But unfortunately, deleting and
+    // re-creating a timer is rather expensive; every timer_create(2) spawns a
+    // new thread. So we simply set the timer to fire at the largest possible
+    // time.
+    //
+    // If we've reached this code path, we're going to grab a wake lock and
+    // wait for the next timer to fire. In that case, there's no reason to
+    // have a pending wakeup timer so we simply cancel it.
+    struct itimerspec end_of_time;
+    memset(&end_of_time, 0, sizeof(end_of_time));
+    end_of_time.it_value.tv_sec = (time_t)(1LL << (sizeof(time_t) * 8 - 2));
+    timer_settime(wakeup_timer, TIMER_ABSTIME, &end_of_time, NULL);
+  } else {
+    // WARNING: do not attempt to use relative timers with *_ALARM clock IDs
+    // in kernels before 3.17 unless you have the following patch:
+    // https://lkml.org/lkml/2014/7/7/576
+    struct itimerspec wakeup_time;
+    memset(&wakeup_time, 0, sizeof(wakeup_time));
+
+    wakeup_time.it_value.tv_sec = (next->deadline / 1000);
+    wakeup_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL;
+    if (timer_settime(wakeup_timer, TIMER_ABSTIME, &wakeup_time, NULL) == -1)
+      LOG_ERROR(LOG_TAG, "%s unable to set wakeup timer: %s", __func__,
+                strerror(errno));
+  }
+
+done:
+  timer_set =
+      timer_time.it_value.tv_sec != 0 || timer_time.it_value.tv_nsec != 0;
+  if (timer_was_set && !timer_set) {
+    wakelock_release();
+  }
+
+  if (timer_settime(timer, TIMER_ABSTIME, &timer_time, NULL) == -1)
+    LOG_ERROR(LOG_TAG, "%s unable to set timer: %s", __func__, strerror(errno));
+
+  // If next expiration was in the past (e.g. short timer that got context
+  // switched) then the timer might have diarmed itself. Detect this case and
+  // work around it by manually signalling the |alarm_expired| semaphore.
+  //
+  // It is possible that the timer was actually super short (a few
+  // milliseconds) and the timer expired normally before we called
+  // |timer_gettime|. Worst case, |alarm_expired| is signaled twice for that
+  // alarm. Nothing bad should happen in that case though since the callback
+  // dispatch function checks to make sure the timer at the head of the list
+  // actually expired.
+  if (timer_set) {
+    struct itimerspec time_to_expire;
+    timer_gettime(timer, &time_to_expire);
+    if (time_to_expire.it_value.tv_sec == 0 &&
+        time_to_expire.it_value.tv_nsec == 0) {
+      LOG_DEBUG(
+          LOG_TAG,
+          "%s alarm expiration too close for posix timers, switching to guns",
+          __func__);
+      semaphore_post(alarm_expired);
+    }
+  }
+}
+
+void alarm_register_processing_queue(fixed_queue_t* queue, thread_t* thread) {
+  assert(queue != NULL);
+  assert(thread != NULL);
+
+  fixed_queue_register_dequeue(queue, thread_get_reactor(thread),
+                               alarm_queue_ready, NULL);
+}
+
+void alarm_unregister_processing_queue(fixed_queue_t* queue) {
+  assert(alarms != NULL);
+  assert(queue != NULL);
+
+  fixed_queue_unregister_dequeue(queue);
+
+  // Cancel all alarms that are using this queue
+  pthread_mutex_lock(&monitor);
+  for (list_node_t* node = list_begin(alarms); node != list_end(alarms);) {
+    alarm_t* alarm = (alarm_t*)list_node(node);
+    node = list_next(node);
+    // TODO: Each module is responsible for tearing down its alarms; currently,
+    // this is not the case. In the future, this check should be replaced by
+    // an assert.
+    if (alarm->queue == queue) alarm_cancel_internal(alarm);
+  }
+  pthread_mutex_unlock(&monitor);
+}
+
+static void alarm_queue_ready(fixed_queue_t* queue, UNUSED_ATTR void* context) {
+  assert(queue != NULL);
+
+  pthread_mutex_lock(&monitor);
+  alarm_t* alarm = (alarm_t*)fixed_queue_try_dequeue(queue);
+  if (alarm == NULL) {
+    pthread_mutex_unlock(&monitor);
+    return;  // The alarm was probably canceled
+  }
+
+  //
+  // If the alarm is not periodic, we've fully serviced it now, and can reset
+  // some of its internal state. This is useful to distinguish between expired
+  // alarms and active ones.
+  //
+  alarm_callback_t callback = alarm->callback;
+  void* data = alarm->data;
+  period_ms_t deadline = alarm->deadline;
+  if (alarm->is_periodic) {
+    // The periodic alarm has been rescheduled and alarm->deadline has been
+    // updated, hence we need to use the previous deadline.
+    deadline = alarm->prev_deadline;
+  } else {
+    alarm->deadline = 0;
+    alarm->callback = NULL;
+    alarm->data = NULL;
+  }
+
+  pthread_mutex_lock(&alarm->callback_lock);
+  pthread_mutex_unlock(&monitor);
+
+  period_ms_t t0 = now();
+  callback(data);
+  period_ms_t t1 = now();
+
+  // Update the statistics
+  assert(t1 >= t0);
+  period_ms_t delta = t1 - t0;
+  update_scheduling_stats(&alarm->stats, t0, deadline, delta);
+
+  pthread_mutex_unlock(&alarm->callback_lock);
+}
+
+// Callback function for wake alarms and our posix timer
+static void timer_callback(UNUSED_ATTR void* ptr) {
+  semaphore_post(alarm_expired);
+}
+
+// Function running on |dispatcher_thread| that performs the following:
+//   (1) Receives a signal using |alarm_exired| that the alarm has expired
+//   (2) Dispatches the alarm callback for processing by the corresponding
+// thread for that alarm.
+static void callback_dispatch(UNUSED_ATTR void* context) {
+  while (true) {
+    semaphore_wait(alarm_expired);
+    if (!dispatcher_thread_active) break;
+
+    pthread_mutex_lock(&monitor);
+    alarm_t* alarm;
+
+    // Take into account that the alarm may get cancelled before we get to it.
+    // We're done here if there are no alarms or the alarm at the front is in
+    // the future. Release the monitor lock and exit right away since there's
+    // nothing left to do.
+    if (list_is_empty(alarms) ||
+        (alarm = static_cast<alarm_t*>(list_front(alarms)))->deadline > now()) {
+      reschedule_root_alarm();
+      pthread_mutex_unlock(&monitor);
+      continue;
+    }
+
+    list_remove(alarms, alarm);
+
+    if (alarm->is_periodic) {
+      alarm->prev_deadline = alarm->deadline;
+      schedule_next_instance(alarm);
+      alarm->stats.rescheduled_count++;
+    }
+    reschedule_root_alarm();
+
+    // Enqueue the alarm for processing
+    fixed_queue_enqueue(alarm->queue, alarm);
+
+    pthread_mutex_unlock(&monitor);
+  }
+
+  LOG_DEBUG(LOG_TAG, "%s Callback thread exited", __func__);
+}
+
+static bool timer_create_internal(const clockid_t clock_id, timer_t* timer) {
+  assert(timer != NULL);
+
+  struct sigevent sigevent;
+  memset(&sigevent, 0, sizeof(sigevent));
+  sigevent.sigev_notify = SIGEV_THREAD;
+  sigevent.sigev_notify_function = (void (*)(union sigval))timer_callback;
+  if (timer_create(clock_id, &sigevent, timer) == -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to create timer with clock %d: %s", __func__,
+              clock_id, strerror(errno));
+    if (clock_id == CLOCK_BOOTTIME_ALARM) {
+      LOG_ERROR(LOG_TAG,
+                "The kernel might not have support for "
+                "timer_create(CLOCK_BOOTTIME_ALARM): "
+                "https://lwn.net/Articles/429925/");
+      LOG_ERROR(LOG_TAG,
+                "See following patches: "
+                "https://git.kernel.org/cgit/linux/kernel/git/torvalds/"
+                "linux.git/log/?qt=grep&q=CLOCK_BOOTTIME_ALARM");
+    }
+    return false;
+  }
+
+  return true;
+}
+
+static void update_scheduling_stats(alarm_stats_t* stats, period_ms_t now_ms,
+                                    period_ms_t deadline_ms,
+                                    period_ms_t execution_delta_ms) {
+  stats->total_updates++;
+  stats->last_update_ms = now_ms;
+
+  update_stat(&stats->callback_execution, execution_delta_ms);
+
+  if (deadline_ms < now_ms) {
+    // Overdue scheduling
+    period_ms_t delta_ms = now_ms - deadline_ms;
+    update_stat(&stats->overdue_scheduling, delta_ms);
+  } else if (deadline_ms > now_ms) {
+    // Premature scheduling
+    period_ms_t delta_ms = deadline_ms - now_ms;
+    update_stat(&stats->premature_scheduling, delta_ms);
+  }
+}
+
+static void dump_stat(int fd, stat_t* stat, const char* description) {
+  period_ms_t average_time_ms = 0;
+  if (stat->count != 0) average_time_ms = stat->total_ms / stat->count;
+
+  dprintf(fd, "%-51s: %llu / %llu / %llu\n", description,
+          (unsigned long long)stat->total_ms, (unsigned long long)stat->max_ms,
+          (unsigned long long)average_time_ms);
+}
+
+void alarm_debug_dump(int fd) {
+  dprintf(fd, "\nBluetooth Alarms Statistics:\n");
+
+  pthread_mutex_lock(&monitor);
+
+  if (alarms == NULL) {
+    pthread_mutex_unlock(&monitor);
+    dprintf(fd, "  None\n");
+    return;
+  }
+
+  period_ms_t just_now = now();
+
+  dprintf(fd, "  Total Alarms: %zu\n\n", list_length(alarms));
+
+  // Dump info for each alarm
+  for (list_node_t* node = list_begin(alarms); node != list_end(alarms);
+       node = list_next(node)) {
+    alarm_t* alarm = (alarm_t*)list_node(node);
+    alarm_stats_t* stats = &alarm->stats;
+
+    dprintf(fd, "  Alarm : %s (%s)\n", stats->name,
+            (alarm->is_periodic) ? "PERIODIC" : "SINGLE");
+
+    dprintf(fd, "%-51s: %zu / %zu / %zu / %zu\n",
+            "    Action counts (sched/resched/exec/cancel)",
+            stats->scheduled_count, stats->rescheduled_count,
+            stats->callback_execution.count, stats->canceled_count);
+
+    dprintf(fd, "%-51s: %zu / %zu\n",
+            "    Deviation counts (overdue/premature)",
+            stats->overdue_scheduling.count, stats->premature_scheduling.count);
+
+    dprintf(fd, "%-51s: %llu / %llu / %lld\n",
+            "    Time in ms (since creation/interval/remaining)",
+            (unsigned long long)(just_now - alarm->creation_time),
+            (unsigned long long)alarm->period,
+            (long long)(alarm->deadline - just_now));
+
+    dump_stat(fd, &stats->callback_execution,
+              "    Callback execution time in ms (total/max/avg)");
+
+    dump_stat(fd, &stats->overdue_scheduling,
+              "    Overdue scheduling time in ms (total/max/avg)");
+
+    dump_stat(fd, &stats->premature_scheduling,
+              "    Premature scheduling time in ms (total/max/avg)");
+
+    dprintf(fd, "\n");
+  }
+  pthread_mutex_unlock(&monitor);
+}
diff --git a/bt/osi/src/allocation_tracker.cc b/bt/osi/src/allocation_tracker.cc
new file mode 100644
index 0000000..7312cb2
--- /dev/null
+++ b/bt/osi/src/allocation_tracker.cc
@@ -0,0 +1,158 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_osi_allocation_tracker"
+
+#include "osi/include/allocation_tracker.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mutex>
+#include <unordered_map>
+
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+typedef struct {
+  uint8_t allocator_id;
+  void* ptr;
+  size_t size;
+  bool freed;
+} allocation_t;
+
+static const size_t canary_size = 8;
+static char canary[canary_size];
+static std::unordered_map<void*, allocation_t*> allocations;
+static std::mutex tracker_lock;
+static bool enabled = false;
+
+void allocation_tracker_init(void) {
+  std::unique_lock<std::mutex> lock(tracker_lock);
+  if (enabled) return;
+
+  // randomize the canary contents
+  for (size_t i = 0; i < canary_size; i++) canary[i] = (char)osi_rand();
+
+  LOG_DEBUG(LOG_TAG, "canary initialized");
+
+  enabled = true;
+}
+
+// Test function only. Do not call in the normal course of operations.
+void allocation_tracker_uninit(void) {
+  std::unique_lock<std::mutex> lock(tracker_lock);
+  if (!enabled) return;
+
+  allocations.clear();
+  enabled = false;
+}
+
+void allocation_tracker_reset(void) {
+  std::unique_lock<std::mutex> lock(tracker_lock);
+  if (!enabled) return;
+
+  allocations.clear();
+}
+
+size_t allocation_tracker_expect_no_allocations(void) {
+  std::unique_lock<std::mutex> lock(tracker_lock);
+  if (!enabled) return 0;
+
+  size_t unfreed_memory_size = 0;
+
+  for (const auto& entry : allocations) {
+    allocation_t* allocation = entry.second;
+    if (!allocation->freed) {
+      unfreed_memory_size +=
+          allocation->size;  // Report back the unfreed byte count
+      LOG_ERROR(LOG_TAG,
+                "%s found unfreed allocation. address: 0x%zx size: %zd bytes",
+                __func__, (uintptr_t)allocation->ptr, allocation->size);
+    }
+  }
+
+  return unfreed_memory_size;
+}
+
+void* allocation_tracker_notify_alloc(uint8_t allocator_id, void* ptr,
+                                      size_t requested_size) {
+  char* return_ptr;
+  {
+    std::unique_lock<std::mutex> lock(tracker_lock);
+    if (!enabled || !ptr) return ptr;
+
+    return_ptr = ((char*)ptr) + canary_size;
+
+    auto map_entry = allocations.find(return_ptr);
+    allocation_t* allocation;
+    if (map_entry != allocations.end()) {
+      allocation = map_entry->second;
+      assert(allocation->freed);  // Must have been freed before
+    } else {
+      allocation = (allocation_t*)calloc(1, sizeof(allocation_t));
+      allocations[return_ptr] = allocation;
+    }
+
+    allocation->allocator_id = allocator_id;
+    allocation->freed = false;
+    allocation->size = requested_size;
+    allocation->ptr = return_ptr;
+  }
+
+  // Add the canary on both sides
+  memcpy(return_ptr - canary_size, canary, canary_size);
+  memcpy(return_ptr + requested_size, canary, canary_size);
+
+  return return_ptr;
+}
+
+void* allocation_tracker_notify_free(UNUSED_ATTR uint8_t allocator_id,
+                                     void* ptr) {
+  std::unique_lock<std::mutex> lock(tracker_lock);
+  if (!enabled || !ptr) return ptr;
+
+  auto map_entry = allocations.find(ptr);
+  assert(map_entry != allocations.end());
+  allocation_t* allocation = map_entry->second;
+  assert(allocation);          // Must have been tracked before
+  assert(!allocation->freed);  // Must not be a double free
+  assert(allocation->allocator_id ==
+         allocator_id);  // Must be from the same allocator
+  allocation->freed = true;
+
+  UNUSED_ATTR const char* beginning_canary = ((char*)ptr) - canary_size;
+  UNUSED_ATTR const char* end_canary = ((char*)ptr) + allocation->size;
+
+  for (size_t i = 0; i < canary_size; i++) {
+    assert(beginning_canary[i] == canary[i]);
+    assert(end_canary[i] == canary[i]);
+  }
+
+  // Free the hash map entry to avoid unlimited memory usage growth.
+  // Double-free of memory is detected with "assert(allocation)" above
+  // as the allocation entry will not be present.
+  allocations.erase(ptr);
+
+  return ((char*)ptr) - canary_size;
+}
+
+size_t allocation_tracker_resize_for_canary(size_t size) {
+  return (!enabled) ? size : size + (2 * canary_size);
+}
diff --git a/bt/osi/src/allocator.cc b/bt/osi/src/allocator.cc
new file mode 100644
index 0000000..aab1964
--- /dev/null
+++ b/bt/osi/src/allocator.cc
@@ -0,0 +1,84 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "osi/include/allocation_tracker.h"
+#include "osi/include/allocator.h"
+
+static const allocator_id_t alloc_allocator_id = 42;
+
+char* osi_strdup(const char* str) {
+  size_t size = strlen(str) + 1;  // + 1 for the null terminator
+  size_t real_size = allocation_tracker_resize_for_canary(size);
+  void* ptr = malloc(real_size);
+  assert(ptr);
+
+  char* new_string = static_cast<char*>(
+      allocation_tracker_notify_alloc(alloc_allocator_id, ptr, size));
+  if (!new_string) return NULL;
+
+  memcpy(new_string, str, size);
+  return new_string;
+}
+
+char* osi_strndup(const char* str, size_t len) {
+  size_t size = strlen(str);
+  if (len < size) size = len;
+
+  size_t real_size = allocation_tracker_resize_for_canary(size + 1);
+  void* ptr = malloc(real_size);
+  assert(ptr);
+
+  char* new_string = static_cast<char*>(
+      allocation_tracker_notify_alloc(alloc_allocator_id, ptr, size + 1));
+  if (!new_string) return NULL;
+
+  memcpy(new_string, str, size);
+  new_string[size] = '\0';
+  return new_string;
+}
+
+void* osi_malloc(size_t size) {
+  size_t real_size = allocation_tracker_resize_for_canary(size);
+  void* ptr = malloc(real_size);
+  assert(ptr);
+  return allocation_tracker_notify_alloc(alloc_allocator_id, ptr, size);
+}
+
+void* osi_calloc(size_t size) {
+  size_t real_size = allocation_tracker_resize_for_canary(size);
+  void* ptr = calloc(1, real_size);
+  assert(ptr);
+  return allocation_tracker_notify_alloc(alloc_allocator_id, ptr, size);
+}
+
+void osi_free(void* ptr) {
+  free(allocation_tracker_notify_free(alloc_allocator_id, ptr));
+}
+
+void osi_free_and_reset(void** p_ptr) {
+  assert(p_ptr != NULL);
+  osi_free(*p_ptr);
+  *p_ptr = NULL;
+}
+
+const allocator_t allocator_calloc = {osi_calloc, osi_free};
+
+const allocator_t allocator_malloc = {osi_malloc, osi_free};
diff --git a/bt/osi/src/array.cc b/bt/osi/src/array.cc
new file mode 100644
index 0000000..1248e92
--- /dev/null
+++ b/bt/osi/src/array.cc
@@ -0,0 +1,111 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_osi_array"
+
+#include "osi/include/array.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+
+struct array_t {
+  size_t element_size;
+  size_t length;
+  size_t capacity;
+  uint8_t* data;
+  uint8_t internal_storage[];
+};
+
+static bool grow(array_t* array);
+
+static const size_t INTERNAL_ELEMENTS = 16;
+
+array_t* array_new(size_t element_size) {
+  assert(element_size > 0);
+
+  array_t* array = static_cast<array_t*>(
+      osi_calloc(sizeof(array_t) + element_size * INTERNAL_ELEMENTS));
+
+  array->element_size = element_size;
+  array->capacity = INTERNAL_ELEMENTS;
+  array->data = array->internal_storage;
+  return array;
+}
+
+void array_free(array_t* array) {
+  if (!array) return;
+
+  if (array->data != array->internal_storage) free(array->data);
+
+  osi_free(array);
+}
+
+void* array_ptr(const array_t* array) { return array_at(array, 0); }
+
+void* array_at(const array_t* array, size_t index) {
+  assert(array != NULL);
+  assert(index < array->length);
+  return array->data + (index * array->element_size);
+}
+
+size_t array_length(const array_t* array) {
+  assert(array != NULL);
+  return array->length;
+}
+
+bool array_append_value(array_t* array, uint32_t value) {
+  return array_append_ptr(array, &value);
+}
+
+bool array_append_ptr(array_t* array, void* data) {
+  assert(array != NULL);
+  assert(data != NULL);
+
+  if (array->length == array->capacity && !grow(array)) {
+    LOG_ERROR(LOG_TAG,
+              "%s unable to grow array past current capacity of %zu elements "
+              "of size %zu.",
+              __func__, array->capacity, array->element_size);
+    return false;
+  }
+
+  ++array->length;
+  memcpy(array_at(array, array->length - 1), data, array->element_size);
+  return true;
+}
+
+static bool grow(array_t* array) {
+  const size_t new_capacity = array->capacity + (array->capacity / 2);
+  const bool is_moving = (array->data == array->internal_storage);
+
+  void* new_data = realloc(is_moving ? NULL : array->data,
+                           new_capacity * array->element_size);
+  if (!new_data) return false;
+
+  if (is_moving)
+    memcpy(new_data, array->internal_storage,
+           array->length * array->element_size);
+
+  array->data = static_cast<uint8_t*>(new_data);
+  array->capacity = new_capacity;
+  return true;
+}
diff --git a/bt/osi/src/buffer.cc b/bt/osi/src/buffer.cc
new file mode 100644
index 0000000..c66e37b
--- /dev/null
+++ b/bt/osi/src/buffer.cc
@@ -0,0 +1,91 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_osi_buffer"
+
+#include "osi/include/buffer.h"
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+
+struct buffer_t {
+  buffer_t* root;
+  size_t refcount;
+  size_t length;
+  uint8_t data[];
+};
+
+buffer_t* buffer_new(size_t size) {
+  assert(size > 0);
+
+  buffer_t* buffer =
+      static_cast<buffer_t*>(osi_calloc(sizeof(buffer_t) + size));
+
+  buffer->root = buffer;
+  buffer->refcount = 1;
+  buffer->length = size;
+
+  return buffer;
+}
+
+buffer_t* buffer_new_ref(const buffer_t* buf) {
+  assert(buf != NULL);
+  return buffer_new_slice(buf, buf->length);
+}
+
+buffer_t* buffer_new_slice(const buffer_t* buf, size_t slice_size) {
+  assert(buf != NULL);
+  assert(slice_size > 0);
+  assert(slice_size <= buf->length);
+
+  buffer_t* ret = static_cast<buffer_t*>(osi_calloc(sizeof(buffer_t)));
+
+  ret->root = buf->root;
+  ret->refcount = SIZE_MAX;
+  ret->length = slice_size;
+
+  ++buf->root->refcount;
+
+  return ret;
+}
+
+void buffer_free(buffer_t* buffer) {
+  if (!buffer) return;
+
+  if (buffer->root != buffer) {
+    // We're a leaf node. Delete the root node if we're the last referent.
+    if (--buffer->root->refcount == 0) osi_free(buffer->root);
+    osi_free(buffer);
+  } else if (--buffer->refcount == 0) {
+    // We're a root node. Roots are only deleted when their refcount goes to 0.
+    osi_free(buffer);
+  }
+}
+
+void* buffer_ptr(const buffer_t* buf) {
+  assert(buf != NULL);
+  return buf->root->data + buf->root->length - buf->length;
+}
+
+size_t buffer_length(const buffer_t* buf) {
+  assert(buf != NULL);
+  return buf->length;
+}
diff --git a/bt/osi/src/compat.cc b/bt/osi/src/compat.cc
new file mode 100644
index 0000000..c228c75
--- /dev/null
+++ b/bt/osi/src/compat.cc
@@ -0,0 +1,121 @@
+/******************************************************************************
+ *
+ *  Copyright 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ *  Filename:      compat.cc
+ *
+ *  Description:   Compatibility functions for non-bionic C libraries
+ *
+ *
+ ***********************************************************************************/
+
+#include <features.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "osi/include/compat.h"
+#include "osi/include/osi.h"
+
+#if __GLIBC__
+pid_t gettid(void) { return syscall(SYS_gettid); }
+#endif
+
+/* These functions from bionic
+ *
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if __GLIBC__
+/*
+ * Copy src to string dst of size siz.  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t strlcpy(char* dst, const char* src, size_t siz) {
+  char* d = dst;
+  const char* s = src;
+  size_t n = siz;
+
+  /* Copy as many bytes as will fit */
+  if (n != 0) {
+    while (--n != 0) {
+      if ((*d++ = *s++) == '\0') break;
+    }
+  }
+
+  /* Not enough room in dst, add NUL and traverse rest of src */
+  if (n == 0) {
+    if (siz != 0) *d = '\0'; /* NUL-terminate dst */
+    while (*s++)
+      ;
+  }
+
+  return (s - src - 1); /* count does not include NUL */
+}
+#endif
+
+#if __GLIBC__
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left).  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t strlcat(char* dst, const char* src, size_t siz) {
+  char* d = dst;
+  const char* s = src;
+  size_t n = siz;
+  size_t dlen;
+
+  /* Find the end of dst and adjust bytes left but don't go past end */
+  while (n-- != 0 && *d != '\0') d++;
+  dlen = d - dst;
+  n = siz - dlen;
+
+  if (n == 0) return (dlen + strlen(s));
+
+  while (*s != '\0') {
+    if (n != 1) {
+      *d++ = *s;
+      n--;
+    }
+
+    s++;
+  }
+
+  *d = '\0';
+
+  return (dlen + (s - src)); /* count does not include NUL */
+}
+#endif
diff --git a/bt/osi/src/config.cc b/bt/osi/src/config.cc
new file mode 100644
index 0000000..fb3a6f7
--- /dev/null
+++ b/bt/osi/src/config.cc
@@ -0,0 +1,517 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_osi_config"
+
+#include "osi/include/config.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+
+typedef struct {
+  char* key;
+  char* value;
+} entry_t;
+
+typedef struct {
+  char* name;
+  list_t* entries;
+} section_t;
+
+struct config_t {
+  list_t* sections;
+};
+
+// Empty definition; this type is aliased to list_node_t.
+struct config_section_iter_t {};
+
+static bool config_parse(FILE* fp, config_t* config);
+
+static section_t* section_new(const char* name);
+static void section_free(void* ptr);
+static section_t* section_find(const config_t* config, const char* section);
+
+static entry_t* entry_new(const char* key, const char* value);
+static void entry_free(void* ptr);
+static entry_t* entry_find(const config_t* config, const char* section,
+                           const char* key);
+
+config_t* config_new_empty(void) {
+  config_t* config = static_cast<config_t*>(osi_calloc(sizeof(config_t)));
+
+  config->sections = list_new(section_free);
+  if (!config->sections) {
+    LOG_ERROR(LOG_TAG, "%s unable to allocate list for sections.", __func__);
+    goto error;
+  }
+
+  return config;
+
+error:;
+  config_free(config);
+  return NULL;
+}
+
+config_t* config_new(const char* filename) {
+  assert(filename != NULL);
+
+  config_t* config = config_new_empty();
+  if (!config) return NULL;
+
+  FILE* fp = fopen(filename, "rt");
+  if (!fp) {
+    LOG_ERROR(LOG_TAG, "%s unable to open file '%s': %s", __func__, filename,
+              strerror(errno));
+    config_free(config);
+    return NULL;
+  }
+
+  if (!config_parse(fp, config)) {
+    config_free(config);
+    config = NULL;
+  }
+
+  fclose(fp);
+  return config;
+}
+
+config_t* config_new_clone(const config_t* src) {
+  assert(src != NULL);
+
+  config_t* ret = config_new_empty();
+
+  assert(ret != NULL);
+
+  for (const list_node_t* node = list_begin(src->sections);
+       node != list_end(src->sections); node = list_next(node)) {
+    section_t* sec = static_cast<section_t*>(list_node(node));
+
+    for (const list_node_t* node_entry = list_begin(sec->entries);
+         node_entry != list_end(sec->entries);
+         node_entry = list_next(node_entry)) {
+      entry_t* entry = static_cast<entry_t*>(list_node(node_entry));
+
+      config_set_string(ret, sec->name, entry->key, entry->value);
+    }
+  }
+
+  return ret;
+}
+
+void config_free(config_t* config) {
+  if (!config) return;
+
+  list_free(config->sections);
+  osi_free(config);
+}
+
+bool config_has_section(const config_t* config, const char* section) {
+  assert(config != NULL);
+  assert(section != NULL);
+
+  return (section_find(config, section) != NULL);
+}
+
+bool config_has_key(const config_t* config, const char* section,
+                    const char* key) {
+  assert(config != NULL);
+  assert(section != NULL);
+  assert(key != NULL);
+
+  return (entry_find(config, section, key) != NULL);
+}
+
+int config_get_int(const config_t* config, const char* section, const char* key,
+                   int def_value) {
+  assert(config != NULL);
+  assert(section != NULL);
+  assert(key != NULL);
+
+  entry_t* entry = entry_find(config, section, key);
+  if (!entry) return def_value;
+
+  char* endptr;
+  int ret = strtol(entry->value, &endptr, 0);
+  return (*endptr == '\0') ? ret : def_value;
+}
+
+bool config_get_bool(const config_t* config, const char* section,
+                     const char* key, bool def_value) {
+  assert(config != NULL);
+  assert(section != NULL);
+  assert(key != NULL);
+
+  entry_t* entry = entry_find(config, section, key);
+  if (!entry) return def_value;
+
+  if (!strcmp(entry->value, "true")) return true;
+  if (!strcmp(entry->value, "false")) return false;
+
+  return def_value;
+}
+
+const char* config_get_string(const config_t* config, const char* section,
+                              const char* key, const char* def_value) {
+  assert(config != NULL);
+  assert(section != NULL);
+  assert(key != NULL);
+
+  entry_t* entry = entry_find(config, section, key);
+  if (!entry) return def_value;
+
+  return entry->value;
+}
+
+void config_set_int(config_t* config, const char* section, const char* key,
+                    int value) {
+  assert(config != NULL);
+  assert(section != NULL);
+  assert(key != NULL);
+
+  char value_str[32] = {0};
+  snprintf(value_str, sizeof(value_str), "%d", value);
+  config_set_string(config, section, key, value_str);
+}
+
+void config_set_bool(config_t* config, const char* section, const char* key,
+                     bool value) {
+  assert(config != NULL);
+  assert(section != NULL);
+  assert(key != NULL);
+
+  config_set_string(config, section, key, value ? "true" : "false");
+}
+
+void config_set_string(config_t* config, const char* section, const char* key,
+                       const char* value) {
+  section_t* sec = section_find(config, section);
+  if (!sec) {
+    sec = section_new(section);
+    list_append(config->sections, sec);
+  }
+
+  for (const list_node_t* node = list_begin(sec->entries);
+       node != list_end(sec->entries); node = list_next(node)) {
+    entry_t* entry = static_cast<entry_t*>(list_node(node));
+    if (!strcmp(entry->key, key)) {
+      osi_free(entry->value);
+      entry->value = osi_strdup(value);
+      return;
+    }
+  }
+
+  entry_t* entry = entry_new(key, value);
+  list_append(sec->entries, entry);
+}
+
+bool config_remove_section(config_t* config, const char* section) {
+  assert(config != NULL);
+  assert(section != NULL);
+
+  section_t* sec = section_find(config, section);
+  if (!sec) return false;
+
+  return list_remove(config->sections, sec);
+}
+
+bool config_remove_key(config_t* config, const char* section, const char* key) {
+  assert(config != NULL);
+  assert(section != NULL);
+  assert(key != NULL);
+
+  section_t* sec = section_find(config, section);
+  entry_t* entry = entry_find(config, section, key);
+  if (!sec || !entry) return false;
+
+  return list_remove(sec->entries, entry);
+}
+
+const config_section_node_t* config_section_begin(const config_t* config) {
+  assert(config != NULL);
+  return (const config_section_node_t*)list_begin(config->sections);
+}
+
+const config_section_node_t* config_section_end(const config_t* config) {
+  assert(config != NULL);
+  return (const config_section_node_t*)list_end(config->sections);
+}
+
+const config_section_node_t* config_section_next(
+    const config_section_node_t* node) {
+  assert(node != NULL);
+  return (const config_section_node_t*)list_next((const list_node_t*)node);
+}
+
+const char* config_section_name(const config_section_node_t* node) {
+  assert(node != NULL);
+  const list_node_t* lnode = (const list_node_t*)node;
+  const section_t* section = (const section_t*)list_node(lnode);
+  return section->name;
+}
+
+bool config_save(const config_t* config, const char* filename) {
+  assert(config != NULL);
+  assert(filename != NULL);
+  assert(*filename != '\0');
+
+  // Steps to ensure content of config file gets to disk:
+  //
+  // 1) Open and write to temp file (e.g. bt_config.conf.new).
+  // 2) Sync the temp file to disk with fsync().
+  // 3) Rename temp file to actual config file (e.g. bt_config.conf).
+  //    This ensures atomic update.
+  // 4) Sync directory that has the conf file with fsync().
+  //    This ensures directory entries are up-to-date.
+  int dir_fd = -1;
+  FILE* fp = NULL;
+
+  // Build temp config file based on config file (e.g. bt_config.conf.new).
+  static const char* temp_file_ext = ".new";
+  const int filename_len = strlen(filename);
+  const int temp_filename_len = filename_len + strlen(temp_file_ext) + 1;
+  char* temp_filename = static_cast<char*>(osi_calloc(temp_filename_len));
+  snprintf(temp_filename, temp_filename_len, "%s%s", filename, temp_file_ext);
+
+  // Extract directory from file path (e.g. /data/misc/bluedroid).
+  char* temp_dirname = osi_strdup(filename);
+  const char* directoryname = dirname(temp_dirname);
+  if (!directoryname) {
+    LOG_ERROR(LOG_TAG, "%s error extracting directory from '%s': %s", __func__,
+              filename, strerror(errno));
+    goto error;
+  }
+
+  dir_fd = open(directoryname, O_RDONLY);
+  if (dir_fd < 0) {
+    LOG_ERROR(LOG_TAG, "%s unable to open dir '%s': %s", __func__,
+              directoryname, strerror(errno));
+    goto error;
+  }
+
+  fp = fopen(temp_filename, "wt");
+  if (!fp) {
+    LOG_ERROR(LOG_TAG, "%s unable to write file '%s': %s", __func__,
+              temp_filename, strerror(errno));
+    goto error;
+  }
+
+  for (const list_node_t* node = list_begin(config->sections);
+       node != list_end(config->sections); node = list_next(node)) {
+    const section_t* section = (const section_t*)list_node(node);
+    if (fprintf(fp, "[%s]\n", section->name) < 0) {
+      LOG_ERROR(LOG_TAG, "%s unable to write to file '%s': %s", __func__,
+                temp_filename, strerror(errno));
+      goto error;
+    }
+
+    for (const list_node_t* enode = list_begin(section->entries);
+         enode != list_end(section->entries); enode = list_next(enode)) {
+      const entry_t* entry = (const entry_t*)list_node(enode);
+      if (fprintf(fp, "%s = %s\n", entry->key, entry->value) < 0) {
+        LOG_ERROR(LOG_TAG, "%s unable to write to file '%s': %s", __func__,
+                  temp_filename, strerror(errno));
+        goto error;
+      }
+    }
+
+    // Only add a separating newline if there are more sections.
+    if (list_next(node) != list_end(config->sections)) {
+      if (fputc('\n', fp) == EOF) {
+        LOG_ERROR(LOG_TAG, "%s unable to write to file '%s': %s", __func__,
+                  temp_filename, strerror(errno));
+        goto error;
+      }
+    }
+  }
+
+  // Sync written temp file out to disk. fsync() is blocking until data makes it
+  // to disk.
+  if (fsync(fileno(fp)) < 0) {
+    LOG_WARN(LOG_TAG, "%s unable to fsync file '%s': %s", __func__,
+             temp_filename, strerror(errno));
+  }
+
+  if (fclose(fp) == EOF) {
+    LOG_ERROR(LOG_TAG, "%s unable to close file '%s': %s", __func__,
+              temp_filename, strerror(errno));
+    goto error;
+  }
+  fp = NULL;
+
+  // Change the file's permissions to Read/Write by User and Group
+  if (chmod(temp_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) == -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to change file permissions '%s': %s",
+              __func__, filename, strerror(errno));
+    goto error;
+  }
+
+  // Rename written temp file to the actual config file.
+  if (rename(temp_filename, filename) == -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to commit file '%s': %s", __func__, filename,
+              strerror(errno));
+    goto error;
+  }
+
+  // This should ensure the directory is updated as well.
+  if (fsync(dir_fd) < 0) {
+    LOG_WARN(LOG_TAG, "%s unable to fsync dir '%s': %s", __func__,
+             directoryname, strerror(errno));
+  }
+
+  if (close(dir_fd) < 0) {
+    LOG_ERROR(LOG_TAG, "%s unable to close dir '%s': %s", __func__,
+              directoryname, strerror(errno));
+    goto error;
+  }
+
+  osi_free(temp_filename);
+  osi_free(temp_dirname);
+  return true;
+
+error:
+  // This indicates there is a write issue.  Unlink as partial data is not
+  // acceptable.
+  unlink(temp_filename);
+  if (fp) fclose(fp);
+  if (dir_fd != -1) close(dir_fd);
+  osi_free(temp_filename);
+  osi_free(temp_dirname);
+  return false;
+}
+
+static char* trim(char* str) {
+  while (isspace(*str)) ++str;
+
+  if (!*str) return str;
+
+  char* end_str = str + strlen(str) - 1;
+  while (end_str > str && isspace(*end_str)) --end_str;
+
+  end_str[1] = '\0';
+  return str;
+}
+
+static bool config_parse(FILE* fp, config_t* config) {
+  assert(fp != NULL);
+  assert(config != NULL);
+
+  int line_num = 0;
+  char line[1024];
+  char section[1024];
+  strcpy(section, CONFIG_DEFAULT_SECTION);
+
+  while (fgets(line, sizeof(line), fp)) {
+    char* line_ptr = trim(line);
+    ++line_num;
+
+    // Skip blank and comment lines.
+    if (*line_ptr == '\0' || *line_ptr == '#') continue;
+
+    if (*line_ptr == '[') {
+      size_t len = strlen(line_ptr);
+      if (line_ptr[len - 1] != ']') {
+        LOG_DEBUG(LOG_TAG, "%s unterminated section name on line %d.", __func__,
+                  line_num);
+        return false;
+      }
+      strncpy(section, line_ptr + 1, len - 2);
+      section[len - 2] = '\0';
+    } else {
+      char* split = strchr(line_ptr, '=');
+      if (!split) {
+        LOG_DEBUG(LOG_TAG, "%s no key/value separator found on line %d.",
+                  __func__, line_num);
+        return false;
+      }
+
+      *split = '\0';
+      config_set_string(config, section, trim(line_ptr), trim(split + 1));
+    }
+  }
+  return true;
+}
+
+static section_t* section_new(const char* name) {
+  section_t* section = static_cast<section_t*>(osi_calloc(sizeof(section_t)));
+
+  section->name = osi_strdup(name);
+  section->entries = list_new(entry_free);
+  return section;
+}
+
+static void section_free(void* ptr) {
+  if (!ptr) return;
+
+  section_t* section = static_cast<section_t*>(ptr);
+  osi_free(section->name);
+  list_free(section->entries);
+  osi_free(section);
+}
+
+static section_t* section_find(const config_t* config, const char* section) {
+  for (const list_node_t* node = list_begin(config->sections);
+       node != list_end(config->sections); node = list_next(node)) {
+    section_t* sec = static_cast<section_t*>(list_node(node));
+    if (!strcmp(sec->name, section)) return sec;
+  }
+
+  return NULL;
+}
+
+static entry_t* entry_new(const char* key, const char* value) {
+  entry_t* entry = static_cast<entry_t*>(osi_calloc(sizeof(entry_t)));
+
+  entry->key = osi_strdup(key);
+  entry->value = osi_strdup(value);
+  return entry;
+}
+
+static void entry_free(void* ptr) {
+  if (!ptr) return;
+
+  entry_t* entry = static_cast<entry_t*>(ptr);
+  osi_free(entry->key);
+  osi_free(entry->value);
+  osi_free(entry);
+}
+
+static entry_t* entry_find(const config_t* config, const char* section,
+                           const char* key) {
+  section_t* sec = section_find(config, section);
+  if (!sec) return NULL;
+
+  for (const list_node_t* node = list_begin(sec->entries);
+       node != list_end(sec->entries); node = list_next(node)) {
+    entry_t* entry = static_cast<entry_t*>(list_node(node));
+    if (!strcmp(entry->key, key)) return entry;
+  }
+
+  return NULL;
+}
diff --git a/bt/osi/src/data_dispatcher.cc b/bt/osi/src/data_dispatcher.cc
new file mode 100644
index 0000000..e1a59cc
--- /dev/null
+++ b/bt/osi/src/data_dispatcher.cc
@@ -0,0 +1,108 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_osi_data_dispatcher"
+
+#include "osi/include/data_dispatcher.h"
+
+#include <assert.h>
+#include <unordered_map>
+
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#define DEFAULT_TABLE_BUCKETS 10
+
+typedef std::unordered_map<data_dispatcher_type_t, fixed_queue_t*>
+    DispatchTableMap;
+
+struct data_dispatcher_t {
+  char* name;
+  DispatchTableMap* dispatch_table;
+  fixed_queue_t* default_queue;  // We don't own this queue
+};
+
+data_dispatcher_t* data_dispatcher_new(const char* name) {
+  assert(name != NULL);
+
+  data_dispatcher_t* ret =
+      (data_dispatcher_t*)osi_calloc(sizeof(data_dispatcher_t));
+
+  ret->dispatch_table = new DispatchTableMap();
+
+  ret->name = osi_strdup(name);
+  if (!ret->name) {
+    LOG_ERROR(LOG_TAG, "%s unable to duplicate provided name.", __func__);
+    goto error;
+  }
+
+  return ret;
+
+error:;
+  data_dispatcher_free(ret);
+  return NULL;
+}
+
+void data_dispatcher_free(data_dispatcher_t* dispatcher) {
+  if (!dispatcher) return;
+
+  delete dispatcher->dispatch_table;
+  osi_free(dispatcher->name);
+  osi_free(dispatcher);
+}
+
+void data_dispatcher_register(data_dispatcher_t* dispatcher,
+                              data_dispatcher_type_t type,
+                              fixed_queue_t* queue) {
+  assert(dispatcher != NULL);
+
+  if (queue)
+    (*dispatcher->dispatch_table)[type] = queue;
+  else
+    dispatcher->dispatch_table->erase(type);
+}
+
+void data_dispatcher_register_default(data_dispatcher_t* dispatcher,
+                                      fixed_queue_t* queue) {
+  assert(dispatcher != NULL);
+
+  dispatcher->default_queue = queue;
+}
+
+bool data_dispatcher_dispatch(data_dispatcher_t* dispatcher,
+                              data_dispatcher_type_t type, void* data) {
+  assert(dispatcher != NULL);
+  assert(data != NULL);
+
+  fixed_queue_t* queue;
+  auto iter = dispatcher->dispatch_table->find(type);
+  if (iter == dispatcher->dispatch_table->end())
+    queue = dispatcher->default_queue;
+  else
+    queue = iter->second;
+
+  if (queue)
+    fixed_queue_enqueue(queue, data);
+  else
+    LOG_WARN(LOG_TAG,
+             "%s has no handler for type (%zd) in data dispatcher named: %s",
+             __func__, type, dispatcher->name);
+
+  return queue != NULL;
+}
diff --git a/bt/osi/src/eager_reader.cc b/bt/osi/src/eager_reader.cc
new file mode 100644
index 0000000..0f4ff29
--- /dev/null
+++ b/bt/osi/src/eager_reader.cc
@@ -0,0 +1,281 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_osi_eager_reader"
+
+#include "osi/include/eager_reader.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/eventfd.h>
+#include <unistd.h>
+
+#include "osi/include/fixed_queue.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/reactor.h"
+
+#if !defined(EFD_SEMAPHORE)
+#define EFD_SEMAPHORE (1 << 0)
+#endif
+
+typedef struct {
+  size_t length;
+  size_t offset;
+  uint8_t data[];
+} data_buffer_t;
+
+struct eager_reader_t {
+  int bytes_available_fd;  // semaphore mode eventfd which counts the number of
+                           // available bytes
+  int inbound_fd;
+
+  const allocator_t* allocator;
+  size_t buffer_size;
+  fixed_queue_t* buffers;
+  data_buffer_t* current_buffer;
+
+  thread_t* inbound_read_thread;
+  reactor_object_t* inbound_read_object;
+
+  reactor_object_t* outbound_registration;
+  eager_reader_cb outbound_read_ready;
+  void* outbound_context;
+};
+
+static bool has_byte(const eager_reader_t* reader);
+static void inbound_data_waiting(void* context);
+static void internal_outbound_read_ready(void* context);
+
+eager_reader_t* eager_reader_new(int fd_to_read, const allocator_t* allocator,
+                                 size_t buffer_size, size_t max_buffer_count,
+                                 const char* thread_name) {
+  assert(fd_to_read != INVALID_FD);
+  assert(allocator != NULL);
+  assert(buffer_size > 0);
+  assert(max_buffer_count > 0);
+  assert(thread_name != NULL && *thread_name != '\0');
+
+  eager_reader_t* ret =
+      static_cast<eager_reader_t*>(osi_calloc(sizeof(eager_reader_t)));
+
+  ret->allocator = allocator;
+  ret->inbound_fd = fd_to_read;
+
+  ret->bytes_available_fd = eventfd(0, 0);
+  if (ret->bytes_available_fd == INVALID_FD) {
+    LOG_ERROR(LOG_TAG, "%s unable to create output reading semaphore.",
+              __func__);
+    goto error;
+  }
+
+  ret->buffer_size = buffer_size;
+
+  ret->buffers = fixed_queue_new(max_buffer_count);
+  if (!ret->buffers) {
+    LOG_ERROR(LOG_TAG, "%s unable to create buffers queue.", __func__);
+    goto error;
+  }
+
+  ret->inbound_read_thread = thread_new(thread_name);
+  if (!ret->inbound_read_thread) {
+    LOG_ERROR(LOG_TAG, "%s unable to make reading thread.", __func__);
+    goto error;
+  }
+
+  ret->inbound_read_object =
+      reactor_register(thread_get_reactor(ret->inbound_read_thread), fd_to_read,
+                       ret, inbound_data_waiting, NULL);
+
+  return ret;
+
+error:;
+  eager_reader_free(ret);
+  return NULL;
+}
+
+void eager_reader_free(eager_reader_t* reader) {
+  if (!reader) return;
+
+  eager_reader_unregister(reader);
+
+  // Only unregister from the input if we actually did register
+  if (reader->inbound_read_object)
+    reactor_unregister(reader->inbound_read_object);
+
+  if (reader->bytes_available_fd != INVALID_FD)
+    close(reader->bytes_available_fd);
+
+  // Free the current buffer, because it's not in the queue
+  // and won't be freed below
+  if (reader->current_buffer) reader->allocator->free(reader->current_buffer);
+
+  fixed_queue_free(reader->buffers, reader->allocator->free);
+  thread_free(reader->inbound_read_thread);
+  osi_free(reader);
+}
+
+void eager_reader_register(eager_reader_t* reader, reactor_t* reactor,
+                           eager_reader_cb read_cb, void* context) {
+  assert(reader != NULL);
+  assert(reactor != NULL);
+  assert(read_cb != NULL);
+
+  // Make sure the reader isn't currently registered.
+  eager_reader_unregister(reader);
+
+  reader->outbound_read_ready = read_cb;
+  reader->outbound_context = context;
+  reader->outbound_registration =
+      reactor_register(reactor, reader->bytes_available_fd, reader,
+                       internal_outbound_read_ready, NULL);
+}
+
+void eager_reader_unregister(eager_reader_t* reader) {
+  assert(reader != NULL);
+
+  if (reader->outbound_registration) {
+    reactor_unregister(reader->outbound_registration);
+    reader->outbound_registration = NULL;
+  }
+}
+
+// SEE HEADER FOR THREAD SAFETY NOTE
+size_t eager_reader_read(eager_reader_t* reader, uint8_t* buffer,
+                         size_t max_size) {
+  assert(reader != NULL);
+  assert(buffer != NULL);
+
+  // Poll to see if we have any bytes available before reading.
+  if (!has_byte(reader)) return 0;
+
+  // Find out how many bytes we have available in our various buffers.
+  eventfd_t bytes_available;
+  if (eventfd_read(reader->bytes_available_fd, &bytes_available) == -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to read semaphore for output data.",
+              __func__);
+    return 0;
+  }
+
+  if (max_size > bytes_available) max_size = bytes_available;
+
+  size_t bytes_consumed = 0;
+  while (bytes_consumed < max_size) {
+    if (!reader->current_buffer)
+      reader->current_buffer =
+          static_cast<data_buffer_t*>(fixed_queue_dequeue(reader->buffers));
+
+    size_t bytes_to_copy =
+        reader->current_buffer->length - reader->current_buffer->offset;
+    if (bytes_to_copy > (max_size - bytes_consumed))
+      bytes_to_copy = max_size - bytes_consumed;
+
+    memcpy(&buffer[bytes_consumed],
+           &reader->current_buffer->data[reader->current_buffer->offset],
+           bytes_to_copy);
+    bytes_consumed += bytes_to_copy;
+    reader->current_buffer->offset += bytes_to_copy;
+
+    if (reader->current_buffer->offset >= reader->current_buffer->length) {
+      reader->allocator->free(reader->current_buffer);
+      reader->current_buffer = NULL;
+    }
+  }
+
+  bytes_available -= bytes_consumed;
+  if (eventfd_write(reader->bytes_available_fd, bytes_available) == -1) {
+    LOG_ERROR(LOG_TAG,
+              "%s unable to write back bytes available for output data.",
+              __func__);
+  }
+
+  return bytes_consumed;
+}
+
+thread_t* eager_reader_get_read_thread(const eager_reader_t* reader) {
+  assert(reader != NULL);
+  return reader->inbound_read_thread;
+}
+
+static bool has_byte(const eager_reader_t* reader) {
+  assert(reader != NULL);
+
+  fd_set read_fds;
+
+  for (;;) {
+    FD_ZERO(&read_fds);
+    FD_SET(reader->bytes_available_fd, &read_fds);
+
+    // Immediate timeout
+    struct timeval timeout;
+    timeout.tv_sec = 0;
+    timeout.tv_usec = 0;
+
+    int ret =
+        select(reader->bytes_available_fd + 1, &read_fds, NULL, NULL, &timeout);
+    if (ret == -1 && errno == EINTR) continue;
+    break;
+  }
+
+  return FD_ISSET(reader->bytes_available_fd, &read_fds);
+}
+
+static void inbound_data_waiting(void* context) {
+  eager_reader_t* reader = (eager_reader_t*)context;
+
+  data_buffer_t* buffer = (data_buffer_t*)reader->allocator->alloc(
+      reader->buffer_size + sizeof(data_buffer_t));
+  if (!buffer) {
+    LOG_ERROR(LOG_TAG, "%s couldn't aquire memory for inbound data buffer.",
+              __func__);
+    return;
+  }
+
+  buffer->length = 0;
+  buffer->offset = 0;
+
+  ssize_t bytes_read;
+  OSI_NO_INTR(bytes_read =
+                  read(reader->inbound_fd, buffer->data, reader->buffer_size));
+  if (bytes_read > 0) {
+    // Save the data for later
+    buffer->length = bytes_read;
+    fixed_queue_enqueue(reader->buffers, buffer);
+
+    // Tell consumers data is available by incrementing
+    // the semaphore by the number of bytes we just read
+    eventfd_write(reader->bytes_available_fd, bytes_read);
+  } else {
+    if (bytes_read == 0)
+      LOG_WARN(LOG_TAG, "%s fd said bytes existed, but none were found.",
+               __func__);
+    else
+      LOG_WARN(LOG_TAG, "%s unable to read from file descriptor: %s", __func__,
+               strerror(errno));
+
+    reader->allocator->free(buffer);
+  }
+}
+
+static void internal_outbound_read_ready(void* context) {
+  assert(context != NULL);
+
+  eager_reader_t* reader = (eager_reader_t*)context;
+  reader->outbound_read_ready(reader, reader->outbound_context);
+}
diff --git a/bt/osi/src/fixed_queue.cc b/bt/osi/src/fixed_queue.cc
new file mode 100644
index 0000000..a4cd08d
--- /dev/null
+++ b/bt/osi/src/fixed_queue.cc
@@ -0,0 +1,265 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <assert.h>
+#include <pthread.h>
+#include <string.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/list.h"
+#include "osi/include/osi.h"
+#include "osi/include/reactor.h"
+#include "osi/include/semaphore.h"
+
+typedef struct fixed_queue_t {
+  list_t* list;
+  semaphore_t* enqueue_sem;
+  semaphore_t* dequeue_sem;
+  pthread_mutex_t lock;
+  size_t capacity;
+
+  reactor_object_t* dequeue_object;
+  fixed_queue_cb dequeue_ready;
+  void* dequeue_context;
+} fixed_queue_t;
+
+static void internal_dequeue_ready(void* context);
+
+fixed_queue_t* fixed_queue_new(size_t capacity) {
+  fixed_queue_t* ret =
+      static_cast<fixed_queue_t*>(osi_calloc(sizeof(fixed_queue_t)));
+
+  pthread_mutex_init(&ret->lock, NULL);
+  ret->capacity = capacity;
+
+  ret->list = list_new(NULL);
+  if (!ret->list) goto error;
+
+  ret->enqueue_sem = semaphore_new(capacity);
+  if (!ret->enqueue_sem) goto error;
+
+  ret->dequeue_sem = semaphore_new(0);
+  if (!ret->dequeue_sem) goto error;
+
+  return ret;
+
+error:
+  fixed_queue_free(ret, NULL);
+  return NULL;
+}
+
+void fixed_queue_free(fixed_queue_t* queue, fixed_queue_free_cb free_cb) {
+  if (!queue) return;
+
+  fixed_queue_unregister_dequeue(queue);
+
+  if (free_cb)
+    for (const list_node_t* node = list_begin(queue->list);
+         node != list_end(queue->list); node = list_next(node))
+      free_cb(list_node(node));
+
+  list_free(queue->list);
+  semaphore_free(queue->enqueue_sem);
+  semaphore_free(queue->dequeue_sem);
+  pthread_mutex_destroy(&queue->lock);
+  osi_free(queue);
+}
+
+void fixed_queue_flush(fixed_queue_t* queue, fixed_queue_free_cb free_cb) {
+  if (!queue) return;
+
+  while (!fixed_queue_is_empty(queue)) {
+    void* data = fixed_queue_try_dequeue(queue);
+    if (free_cb != NULL) {
+      free_cb(data);
+    }
+  }
+}
+
+bool fixed_queue_is_empty(fixed_queue_t* queue) {
+  if (queue == NULL) return true;
+
+  pthread_mutex_lock(&queue->lock);
+  bool is_empty = list_is_empty(queue->list);
+  pthread_mutex_unlock(&queue->lock);
+
+  return is_empty;
+}
+
+size_t fixed_queue_length(fixed_queue_t* queue) {
+  if (queue == NULL) return 0;
+
+  pthread_mutex_lock(&queue->lock);
+  size_t length = list_length(queue->list);
+  pthread_mutex_unlock(&queue->lock);
+
+  return length;
+}
+
+size_t fixed_queue_capacity(fixed_queue_t* queue) {
+  assert(queue != NULL);
+
+  return queue->capacity;
+}
+
+void fixed_queue_enqueue(fixed_queue_t* queue, void* data) {
+  assert(queue != NULL);
+  assert(data != NULL);
+
+  semaphore_wait(queue->enqueue_sem);
+
+  pthread_mutex_lock(&queue->lock);
+  list_append(queue->list, data);
+  pthread_mutex_unlock(&queue->lock);
+
+  semaphore_post(queue->dequeue_sem);
+}
+
+void* fixed_queue_dequeue(fixed_queue_t* queue) {
+  assert(queue != NULL);
+
+  semaphore_wait(queue->dequeue_sem);
+
+  pthread_mutex_lock(&queue->lock);
+  void* ret = list_front(queue->list);
+  list_remove(queue->list, ret);
+  pthread_mutex_unlock(&queue->lock);
+
+  semaphore_post(queue->enqueue_sem);
+
+  return ret;
+}
+
+bool fixed_queue_try_enqueue(fixed_queue_t* queue, void* data) {
+  assert(queue != NULL);
+  assert(data != NULL);
+
+  if (!semaphore_try_wait(queue->enqueue_sem)) return false;
+
+  pthread_mutex_lock(&queue->lock);
+  list_append(queue->list, data);
+  pthread_mutex_unlock(&queue->lock);
+
+  semaphore_post(queue->dequeue_sem);
+  return true;
+}
+
+void* fixed_queue_try_dequeue(fixed_queue_t* queue) {
+  if (queue == NULL) return NULL;
+
+  if (!semaphore_try_wait(queue->dequeue_sem)) return NULL;
+
+  pthread_mutex_lock(&queue->lock);
+  void* ret = list_front(queue->list);
+  list_remove(queue->list, ret);
+  pthread_mutex_unlock(&queue->lock);
+
+  semaphore_post(queue->enqueue_sem);
+
+  return ret;
+}
+
+void* fixed_queue_try_peek_first(fixed_queue_t* queue) {
+  if (queue == NULL) return NULL;
+
+  pthread_mutex_lock(&queue->lock);
+  void* ret = list_is_empty(queue->list) ? NULL : list_front(queue->list);
+  pthread_mutex_unlock(&queue->lock);
+
+  return ret;
+}
+
+void* fixed_queue_try_peek_last(fixed_queue_t* queue) {
+  if (queue == NULL) return NULL;
+
+  pthread_mutex_lock(&queue->lock);
+  void* ret = list_is_empty(queue->list) ? NULL : list_back(queue->list);
+  pthread_mutex_unlock(&queue->lock);
+
+  return ret;
+}
+
+void* fixed_queue_try_remove_from_queue(fixed_queue_t* queue, void* data) {
+  if (queue == NULL) return NULL;
+
+  bool removed = false;
+  pthread_mutex_lock(&queue->lock);
+  if (list_contains(queue->list, data) &&
+      semaphore_try_wait(queue->dequeue_sem)) {
+    removed = list_remove(queue->list, data);
+    assert(removed);
+  }
+  pthread_mutex_unlock(&queue->lock);
+
+  if (removed) {
+    semaphore_post(queue->enqueue_sem);
+    return data;
+  }
+  return NULL;
+}
+
+list_t* fixed_queue_get_list(fixed_queue_t* queue) {
+  assert(queue != NULL);
+
+  // NOTE: This function is not thread safe, and there is no point for
+  // calling pthread_mutex_lock() / pthread_mutex_unlock()
+  return queue->list;
+}
+
+int fixed_queue_get_dequeue_fd(const fixed_queue_t* queue) {
+  assert(queue != NULL);
+  return semaphore_get_fd(queue->dequeue_sem);
+}
+
+int fixed_queue_get_enqueue_fd(const fixed_queue_t* queue) {
+  assert(queue != NULL);
+  return semaphore_get_fd(queue->enqueue_sem);
+}
+
+void fixed_queue_register_dequeue(fixed_queue_t* queue, reactor_t* reactor,
+                                  fixed_queue_cb ready_cb, void* context) {
+  assert(queue != NULL);
+  assert(reactor != NULL);
+  assert(ready_cb != NULL);
+
+  // Make sure we're not already registered
+  fixed_queue_unregister_dequeue(queue);
+
+  queue->dequeue_ready = ready_cb;
+  queue->dequeue_context = context;
+  queue->dequeue_object =
+      reactor_register(reactor, fixed_queue_get_dequeue_fd(queue), queue,
+                       internal_dequeue_ready, NULL);
+}
+
+void fixed_queue_unregister_dequeue(fixed_queue_t* queue) {
+  assert(queue != NULL);
+
+  if (queue->dequeue_object) {
+    reactor_unregister(queue->dequeue_object);
+    queue->dequeue_object = NULL;
+  }
+}
+
+static void internal_dequeue_ready(void* context) {
+  assert(context != NULL);
+
+  fixed_queue_t* queue = static_cast<fixed_queue_t*>(context);
+  queue->dequeue_ready(queue, queue->dequeue_context);
+}
diff --git a/bt/osi/src/future.cc b/bt/osi/src/future.cc
new file mode 100644
index 0000000..1b2f79b
--- /dev/null
+++ b/bt/osi/src/future.cc
@@ -0,0 +1,88 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_osi_future"
+
+#include "osi/include/future.h"
+
+#include <assert.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/semaphore.h"
+
+struct future_t {
+  bool ready_can_be_called;
+  semaphore_t* semaphore;  // NULL semaphore means immediate future
+  void* result;
+};
+
+static void future_free(future_t* future);
+
+future_t* future_new(void) {
+  future_t* ret = static_cast<future_t*>(osi_calloc(sizeof(future_t)));
+
+  ret->semaphore = semaphore_new(0);
+  if (!ret->semaphore) {
+    LOG_ERROR(LOG_TAG, "%s unable to allocate memory for the semaphore.",
+              __func__);
+    goto error;
+  }
+
+  ret->ready_can_be_called = true;
+  return ret;
+error:;
+  future_free(ret);
+  return NULL;
+}
+
+future_t* future_new_immediate(void* value) {
+  future_t* ret = static_cast<future_t*>(osi_calloc(sizeof(future_t)));
+
+  ret->result = value;
+  ret->ready_can_be_called = false;
+  return ret;
+}
+
+void future_ready(future_t* future, void* value) {
+  assert(future != NULL);
+  assert(future->ready_can_be_called);
+
+  future->ready_can_be_called = false;
+  future->result = value;
+  semaphore_post(future->semaphore);
+}
+
+void* future_await(future_t* future) {
+  assert(future != NULL);
+
+  // If the future is immediate, it will not have a semaphore
+  if (future->semaphore) semaphore_wait(future->semaphore);
+
+  void* result = future->result;
+  future_free(future);
+  return result;
+}
+
+static void future_free(future_t* future) {
+  if (!future) return;
+
+  semaphore_free(future->semaphore);
+  osi_free(future);
+}
diff --git a/bt/osi/src/hash_map_utils.cc b/bt/osi/src/hash_map_utils.cc
new file mode 100644
index 0000000..3dfdc6e
--- /dev/null
+++ b/bt/osi/src/hash_map_utils.cc
@@ -0,0 +1,84 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "hash_map_utils"
+
+#include "osi/include/hash_map_utils.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+std::unordered_map<std::string, std::string>
+hash_map_utils_new_from_string_params(const char* params) {
+  assert(params != NULL);
+
+  std::unordered_map<std::string, std::string> map;
+
+  char* str = osi_strdup(params);
+  if (!str) return map;
+
+  LOG_VERBOSE(LOG_TAG, "%s: source string: '%s'", __func__, str);
+
+  // Parse |str| and add extracted key-and-value pair(s) in |map|.
+  int items = 0;
+  char* tmpstr;
+  char* kvpair = strtok_r(str, ";", &tmpstr);
+  while (kvpair && *kvpair) {
+    char* eq = strchr(kvpair, '=');
+
+    if (eq == kvpair) goto next_pair;
+
+    char* key;
+    char* value;
+    if (eq) {
+      key = osi_strndup(kvpair, eq - kvpair);
+
+      // The increment of |eq| moves |eq| to the beginning of the value.
+      ++eq;
+      value = (*eq != '\0') ? osi_strdup(eq) : osi_strdup("");
+    } else {
+      key = osi_strdup(kvpair);
+      value = osi_strdup("");
+    }
+
+    map[key] = value;
+
+    osi_free(key);
+    osi_free(value);
+
+    items++;
+  next_pair:
+    kvpair = strtok_r(NULL, ";", &tmpstr);
+  }
+
+  if (!items) LOG_VERBOSE(LOG_TAG, "%s: no items found in string\n", __func__);
+
+  osi_free(str);
+  return map;
+}
+
+void hash_map_utils_dump_string_keys_string_values(
+    std::unordered_map<std::string, std::string>& map) {
+  for (const auto& ptr : map) {
+    LOG_INFO(LOG_TAG, "key: '%s' value: '%s'\n", ptr.first.c_str(),
+             ptr.second.c_str());
+  }
+}
diff --git a/bt/osi/src/list.cc b/bt/osi/src/list.cc
new file mode 100644
index 0000000..e13c31e
--- /dev/null
+++ b/bt/osi/src/list.cc
@@ -0,0 +1,215 @@
+#include <assert.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/list.h"
+#include "osi/include/osi.h"
+
+struct list_node_t {
+  struct list_node_t* next;
+  void* data;
+};
+
+typedef struct list_t {
+  list_node_t* head;
+  list_node_t* tail;
+  size_t length;
+  list_free_cb free_cb;
+  const allocator_t* allocator;
+} list_t;
+
+static list_node_t* list_free_node_(list_t* list, list_node_t* node);
+
+// Hidden constructor, only to be used by the hash map for the allocation
+// tracker.
+// Behaves the same as |list_new|, except you get to specify the allocator.
+list_t* list_new_internal(list_free_cb callback,
+                          const allocator_t* zeroed_allocator) {
+  list_t* list = (list_t*)zeroed_allocator->alloc(sizeof(list_t));
+  if (!list) return NULL;
+
+  list->free_cb = callback;
+  list->allocator = zeroed_allocator;
+  return list;
+}
+
+list_t* list_new(list_free_cb callback) {
+  return list_new_internal(callback, &allocator_calloc);
+}
+
+void list_free(list_t* list) {
+  if (!list) return;
+
+  list_clear(list);
+  list->allocator->free(list);
+}
+
+bool list_is_empty(const list_t* list) {
+  assert(list != NULL);
+  return (list->length == 0);
+}
+
+bool list_contains(const list_t* list, const void* data) {
+  assert(list != NULL);
+  assert(data != NULL);
+
+  for (const list_node_t* node = list_begin(list); node != list_end(list);
+       node = list_next(node)) {
+    if (list_node(node) == data) return true;
+  }
+
+  return false;
+}
+
+size_t list_length(const list_t* list) {
+  assert(list != NULL);
+  return list->length;
+}
+
+void* list_front(const list_t* list) {
+  assert(list != NULL);
+  assert(!list_is_empty(list));
+
+  return list->head->data;
+}
+
+void* list_back(const list_t* list) {
+  assert(list != NULL);
+  assert(!list_is_empty(list));
+
+  return list->tail->data;
+}
+
+list_node_t* list_back_node(const list_t* list) {
+  assert(list != NULL);
+  assert(!list_is_empty(list));
+
+  return list->tail;
+}
+
+bool list_insert_after(list_t* list, list_node_t* prev_node, void* data) {
+  assert(list != NULL);
+  assert(prev_node != NULL);
+  assert(data != NULL);
+
+  list_node_t* node = (list_node_t*)list->allocator->alloc(sizeof(list_node_t));
+  if (!node) return false;
+
+  node->next = prev_node->next;
+  node->data = data;
+  prev_node->next = node;
+  if (list->tail == prev_node) list->tail = node;
+  ++list->length;
+  return true;
+}
+
+bool list_prepend(list_t* list, void* data) {
+  assert(list != NULL);
+  assert(data != NULL);
+
+  list_node_t* node = (list_node_t*)list->allocator->alloc(sizeof(list_node_t));
+  if (!node) return false;
+  node->next = list->head;
+  node->data = data;
+  list->head = node;
+  if (list->tail == NULL) list->tail = list->head;
+  ++list->length;
+  return true;
+}
+
+bool list_append(list_t* list, void* data) {
+  assert(list != NULL);
+  assert(data != NULL);
+
+  list_node_t* node = (list_node_t*)list->allocator->alloc(sizeof(list_node_t));
+  if (!node) return false;
+  node->next = NULL;
+  node->data = data;
+  if (list->tail == NULL) {
+    list->head = node;
+    list->tail = node;
+  } else {
+    list->tail->next = node;
+    list->tail = node;
+  }
+  ++list->length;
+  return true;
+}
+
+bool list_remove(list_t* list, void* data) {
+  assert(list != NULL);
+  assert(data != NULL);
+
+  if (list_is_empty(list)) return false;
+
+  if (list->head->data == data) {
+    list_node_t* next = list_free_node_(list, list->head);
+    if (list->tail == list->head) list->tail = next;
+    list->head = next;
+    return true;
+  }
+
+  for (list_node_t *prev = list->head, *node = list->head->next; node;
+       prev = node, node = node->next)
+    if (node->data == data) {
+      prev->next = list_free_node_(list, node);
+      if (list->tail == node) list->tail = prev;
+      return true;
+    }
+
+  return false;
+}
+
+void list_clear(list_t* list) {
+  assert(list != NULL);
+  for (list_node_t* node = list->head; node;)
+    node = list_free_node_(list, node);
+  list->head = NULL;
+  list->tail = NULL;
+  list->length = 0;
+}
+
+list_node_t* list_foreach(const list_t* list, list_iter_cb callback,
+                          void* context) {
+  assert(list != NULL);
+  assert(callback != NULL);
+
+  for (list_node_t* node = list->head; node;) {
+    list_node_t* next = node->next;
+    if (!callback(node->data, context)) return node;
+    node = next;
+  }
+  return NULL;
+}
+
+list_node_t* list_begin(const list_t* list) {
+  assert(list != NULL);
+  return list->head;
+}
+
+list_node_t* list_end(UNUSED_ATTR const list_t* list) {
+  assert(list != NULL);
+  return NULL;
+}
+
+list_node_t* list_next(const list_node_t* node) {
+  assert(node != NULL);
+  return node->next;
+}
+
+void* list_node(const list_node_t* node) {
+  assert(node != NULL);
+  return node->data;
+}
+
+static list_node_t* list_free_node_(list_t* list, list_node_t* node) {
+  assert(list != NULL);
+  assert(node != NULL);
+
+  list_node_t* next = node->next;
+
+  if (list->free_cb) list->free_cb(node->data);
+  list->allocator->free(node);
+  --list->length;
+
+  return next;
+}
diff --git a/bt/osi/src/metrics.cc b/bt/osi/src/metrics.cc
new file mode 100644
index 0000000..8f18829
--- /dev/null
+++ b/bt/osi/src/metrics.cc
@@ -0,0 +1,187 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_osi_metrics"
+
+#include "osi/include/metrics.h"
+
+#include <errno.h>
+
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#include "osi/src/protos/bluetooth.pb.h"
+
+#include <base/base64.h>
+#include <google/protobuf/text_format.h>
+#include <mutex>
+
+using clearcut::connectivity::A2DPSession;
+using clearcut::connectivity::BluetoothLog;
+using clearcut::connectivity::BluetoothSession;
+using clearcut::connectivity::DeviceInfo;
+using clearcut::connectivity::DeviceInfo_DeviceType;
+using clearcut::connectivity::PairEvent;
+using clearcut::connectivity::ScanEvent;
+using clearcut::connectivity::ScanEvent_ScanTechnologyType;
+using clearcut::connectivity::ScanEvent_ScanEventType;
+using clearcut::connectivity::WakeEvent;
+using clearcut::connectivity::WakeEvent_WakeEventType;
+
+BluetoothLog* pending;
+std::mutex log_lock;
+
+static void lazy_initialize(void) {
+  if (pending == nullptr) {
+    pending = BluetoothLog::default_instance().New();
+  }
+}
+
+void metrics_pair_event(uint32_t disconnect_reason, uint64_t timestamp_ms,
+                        uint32_t device_class, device_type_t device_type) {
+  std::lock_guard<std::mutex> lock(log_lock);
+  lazy_initialize();
+
+  PairEvent* event = pending->add_pair_event();
+
+  DeviceInfo* info = event->mutable_device_paired_with();
+
+  info->set_device_class(device_class);
+
+  DeviceInfo_DeviceType type = DeviceInfo::DEVICE_TYPE_UNKNOWN;
+
+  if (device_type == DEVICE_TYPE_BREDR) type = DeviceInfo::DEVICE_TYPE_BREDR;
+  if (device_type == DEVICE_TYPE_LE) type = DeviceInfo::DEVICE_TYPE_LE;
+  if (device_type == DEVICE_TYPE_DUMO) type = DeviceInfo::DEVICE_TYPE_DUMO;
+
+  info->set_device_type(type);
+
+  event->set_disconnect_reason(disconnect_reason);
+
+  event->set_event_time_millis(timestamp_ms);
+}
+
+void metrics_wake_event(wake_event_type_t type, const char* requestor,
+                        const char* name, uint64_t timestamp_ms) {
+  std::lock_guard<std::mutex> lock(log_lock);
+  lazy_initialize();
+
+  WakeEvent* event = pending->add_wake_event();
+
+  WakeEvent_WakeEventType waketype = WakeEvent::UNKNOWN;
+
+  if (type == WAKE_EVENT_ACQUIRED) waketype = WakeEvent::ACQUIRED;
+  if (type == WAKE_EVENT_RELEASED) waketype = WakeEvent::RELEASED;
+
+  event->set_wake_event_type(waketype);
+
+  if (requestor) event->set_requestor(requestor);
+
+  if (name) event->set_name(name);
+
+  event->set_event_time_millis(timestamp_ms);
+}
+
+void metrics_scan_event(bool start, const char* initator, scan_tech_t type,
+                        uint32_t results, uint64_t timestamp_ms) {
+  std::lock_guard<std::mutex> lock(log_lock);
+  lazy_initialize();
+
+  ScanEvent* event = pending->add_scan_event();
+
+  if (start)
+    event->set_scan_event_type(ScanEvent::SCAN_EVENT_START);
+  else
+    event->set_scan_event_type(ScanEvent::SCAN_EVENT_STOP);
+
+  if (initator) event->set_initiator(initator);
+
+  ScanEvent::ScanTechnologyType scantype = ScanEvent::SCAN_TYPE_UNKNOWN;
+
+  if (type == SCAN_TECH_TYPE_LE) scantype = ScanEvent::SCAN_TECH_TYPE_LE;
+  if (type == SCAN_TECH_TYPE_BREDR) scantype = ScanEvent::SCAN_TECH_TYPE_BREDR;
+  if (type == SCAN_TECH_TYPE_BOTH) scantype = ScanEvent::SCAN_TECH_TYPE_BOTH;
+
+  event->set_scan_technology_type(scantype);
+
+  event->set_number_results(results);
+
+  event->set_event_time_millis(timestamp_ms);
+}
+
+void metrics_a2dp_session(
+    int64_t session_duration_sec, const char* disconnect_reason,
+    uint32_t device_class, int32_t media_timer_min_ms,
+    int32_t media_timer_max_ms, int32_t media_timer_avg_ms,
+    int32_t buffer_overruns_max_count, int32_t buffer_overruns_total,
+    float buffer_underruns_average, int32_t buffer_underruns_count) {
+  std::lock_guard<std::mutex> lock(log_lock);
+  lazy_initialize();
+
+  BluetoothSession* bt_session = pending->add_session();
+
+  // Set connection type: for A2DP it is always BR/EDR
+  BluetoothSession::ConnectionTechnologyType conn_type =
+      BluetoothSession::CONNECTION_TECHNOLOGY_TYPE_BREDR;
+  bt_session->set_connection_technology_type(conn_type);
+
+  bt_session->set_session_duration_sec(session_duration_sec);
+  if (disconnect_reason != NULL)
+    bt_session->set_disconnect_reason(disconnect_reason);
+
+  // Set device: class and type are pre-defined
+  DeviceInfo* info = bt_session->mutable_device_connected_to();
+  info->set_device_class(device_class);
+  info->set_device_type(DeviceInfo::DEVICE_TYPE_BREDR);
+
+  A2DPSession* a2dp_session = bt_session->mutable_a2dp_session();
+  a2dp_session->set_media_timer_min_millis(media_timer_min_ms);
+  a2dp_session->set_media_timer_max_millis(media_timer_max_ms);
+  a2dp_session->set_media_timer_avg_millis(media_timer_avg_ms);
+  a2dp_session->set_buffer_overruns_max_count(buffer_overruns_max_count);
+  a2dp_session->set_buffer_overruns_total(buffer_overruns_total);
+  a2dp_session->set_buffer_underruns_average(buffer_underruns_average);
+  a2dp_session->set_buffer_underruns_count(buffer_underruns_count);
+}
+
+void metrics_write(int fd, bool clear) {
+  log_lock.lock();
+  LOG_DEBUG(LOG_TAG, "%s serializing metrics", __func__);
+  lazy_initialize();
+
+  std::string serialized;
+  if (!pending->SerializeToString(&serialized)) {
+    LOG_ERROR(LOG_TAG, "%s: error serializing metrics", __func__);
+    return;
+  }
+
+  if (clear) {
+    pending->Clear();
+  }
+  log_lock.unlock();
+
+  std::string protoBase64;
+  base::Base64Encode(serialized, &protoBase64);
+
+  ssize_t ret;
+  OSI_NO_INTR(ret = write(fd, protoBase64.c_str(), protoBase64.size()));
+  if (ret == -1) {
+    LOG_ERROR(LOG_TAG, "%s: error writing to dumpsys fd: %s (%d)", __func__,
+              strerror(errno), errno);
+  }
+}
diff --git a/bt/osi/src/metrics_linux.cc b/bt/osi/src/metrics_linux.cc
new file mode 100644
index 0000000..6c4cc94
--- /dev/null
+++ b/bt/osi/src/metrics_linux.cc
@@ -0,0 +1,49 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_osi_metrics"
+
+#include "osi/include/metrics.h"
+
+void metrics_pair_event(uint32_t disconnect_reason, uint64_t timestamp_ms,
+                        uint32_t device_class, device_type_t device_type) {
+  // TODO(jpawlowski): implement
+}
+
+void metrics_wake_event(wake_event_type_t type, const char* requestor,
+                        const char* name, uint64_t timestamp_ms) {
+  // TODO(jpawlowski): implement
+}
+
+void metrics_scan_event(bool start, const char* initator, scan_tech_t type,
+                        uint32_t results, uint64_t timestamp_ms) {
+  // TODO(jpawlowski): implement
+}
+
+void metrics_a2dp_session(
+    int64_t session_duration_sec, const char* disconnect_reason,
+    uint32_t device_class, int32_t media_timer_min_ms,
+    int32_t media_timer_max_ms, int32_t media_timer_avg_ms,
+    int32_t buffer_overruns_max_count, int32_t buffer_overruns_total,
+    float buffer_underruns_average, int32_t buffer_underruns_count) {
+  // TODO(jpawlowski): implement
+}
+
+void metrics_write(int fd, bool clear) {
+  // TODO(jpawlowski): implement
+}
diff --git a/bt/osi/src/mutex.cc b/bt/osi/src/mutex.cc
new file mode 100644
index 0000000..4cbb45f
--- /dev/null
+++ b/bt/osi/src/mutex.cc
@@ -0,0 +1,38 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_osi_mutex"
+
+#include <pthread.h>
+
+#include "osi/include/mutex.h"
+
+static pthread_mutex_t global_lock;
+
+void mutex_init(void) {
+  pthread_mutexattr_t attr;
+  pthread_mutexattr_init(&attr);
+  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
+  pthread_mutex_init(&global_lock, &attr);
+}
+
+void mutex_cleanup(void) { pthread_mutex_destroy(&global_lock); }
+
+void mutex_global_lock(void) { pthread_mutex_lock(&global_lock); }
+
+void mutex_global_unlock(void) { pthread_mutex_unlock(&global_lock); }
diff --git a/bt/osi/src/osi.cc b/bt/osi/src/osi.cc
new file mode 100644
index 0000000..f06ca60
--- /dev/null
+++ b/bt/osi/src/osi.cc
@@ -0,0 +1,53 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_osi_rand"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#define RANDOM_PATH "/dev/urandom"
+
+int osi_rand(void) {
+  int rand;
+  int rand_fd = open(RANDOM_PATH, O_RDONLY);
+
+  if (rand_fd == INVALID_FD) {
+    LOG_ERROR(LOG_TAG, "%s can't open rand fd %s: %s ", __func__, RANDOM_PATH,
+              strerror(errno));
+    assert(0);
+  }
+
+  ssize_t read_bytes = read(rand_fd, &rand, sizeof(rand));
+  close(rand_fd);
+
+  assert(read_bytes == sizeof(rand));
+
+  if (rand < 0) rand = -rand;
+
+  return rand;
+}
diff --git a/bt/osi/src/properties.cc b/bt/osi/src/properties.cc
new file mode 100644
index 0000000..a484fd1
--- /dev/null
+++ b/bt/osi/src/properties.cc
@@ -0,0 +1,46 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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.h>
+
+#include "osi/include/properties.h"
+
+int osi_property_get(const char* key, char* value, const char* default_value) {
+#if defined(OS_GENERIC)
+  /* For linux right now just return default value, if present */
+  int len = -1;
+  if (!default_value) return len;
+
+  len = strlen(default_value);
+  if (len >= PROPERTY_VALUE_MAX) len = PROPERTY_VALUE_MAX - 1;
+
+  memcpy(value, default_value, len);
+  value[len] = '\0';
+  return len;
+#else
+  return property_get(key, value, default_value);
+#endif  // defined(OS_GENERIC)
+}
+
+int osi_property_set(const char* key, const char* value) {
+#if defined(OS_GENERIC)
+  return -1;
+#else
+  return property_set(key, value);
+#endif  // defined(OS_GENERIC)
+}
diff --git a/bt/osi/src/protos/bluetooth.proto b/bt/osi/src/protos/bluetooth.proto
new file mode 100644
index 0000000..1b281d3
--- /dev/null
+++ b/bt/osi/src/protos/bluetooth.proto
@@ -0,0 +1,192 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+// Author: pkanwar@google.com (Pankaj Kanwar)
+// Protos for uploading bluetooth metrics.
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+package clearcut.connectivity;
+
+option java_package = "com.google.wireless.android.play.playlog.connectivity";
+// option (datapol.file_vetting_status) = "latest";
+
+// import "storage/datapol/annotations/proto/semantic_annotations.proto";
+
+message BluetoothLog {
+  // Session information that gets logged for every BT connection.
+  repeated BluetoothSession session = 1;
+
+  // Session information that gets logged for every Pair event.
+  repeated PairEvent pair_event = 2;
+
+  // Information for Wake locks.
+  repeated WakeEvent wake_event = 3;
+
+  // Scan event information.
+  repeated ScanEvent scan_event = 4;
+}
+
+// The information about the device.
+message DeviceInfo {
+  // Device type.
+  enum DeviceType {
+    // Type is unknown.
+    DEVICE_TYPE_UNKNOWN = 0;
+
+    DEVICE_TYPE_BREDR = 1;
+
+    DEVICE_TYPE_LE = 2;
+
+    DEVICE_TYPE_DUMO = 3;
+  }
+
+  // Device class
+  // https://cs.corp.google.com/#android/system/bt/stack/include/btm_api.h&q=major_computer.
+  optional int32 device_class = 1;
+
+  // Device type.
+  optional DeviceType device_type = 2;
+}
+
+// Information that gets logged for every Bluetooth connection.
+message BluetoothSession {
+  // Type of technology used in the connection.
+  enum ConnectionTechnologyType {
+    CONNECTION_TECHNOLOGY_TYPE_UNKNOWN = 0;
+
+    CONNECTION_TECHNOLOGY_TYPE_LE = 1;
+
+    CONNECTION_TECHNOLOGY_TYPE_BREDR = 2;
+  }
+
+  // Duration of the session.
+  optional int64 session_duration_sec = 2;
+
+  // Technology type.
+  optional ConnectionTechnologyType connection_technology_type = 3;
+
+  // Reason for disconnecting.
+  optional string disconnect_reason = 4;
+
+  // The information about the device which it is connected to.
+  optional DeviceInfo device_connected_to = 5;
+
+  // The information about the RFComm session.
+  optional RFCommSession rfcomm_session = 6;
+
+  // The information about the A2DP session.
+  optional A2DPSession a2dp_session = 7;
+}
+
+message RFCommSession {
+  // bytes transmitted.
+  optional int32 rx_bytes = 1;
+
+  // bytes transmitted.
+  optional int32 tx_bytes = 2;
+}
+
+// Session information that gets logged for every A2DP session.
+message A2DPSession {
+  // Media timer in milliseconds.
+  optional int32 media_timer_min_millis = 1;
+
+  // Media timer in milliseconds.
+  optional int32 media_timer_max_millis = 2;
+
+  // Media timer in milliseconds.
+  optional int32 media_timer_avg_millis = 3;
+
+  // Buffer overruns count.
+  optional int32 buffer_overruns_max_count = 4;
+
+  // Buffer overruns total.
+  optional int32 buffer_overruns_total = 5;
+
+  // Buffer underruns average.
+  optional float buffer_underruns_average = 6;
+
+  // Buffer underruns count.
+  optional int32 buffer_underruns_count = 7;
+}
+
+message PairEvent {
+  // The reason for disconnecting
+  // https://cs.corp.google.com/#android/system/bt/stack/include/hcidefs.h&q=failed_establish.
+  optional int32 disconnect_reason = 1;
+
+  // Pair event time
+  optional int64 event_time_millis =
+      2;  // [(datapol.semantic_type) = ST_TIMESTAMP];
+
+  // The information about the device which it is paired to.
+  optional DeviceInfo device_paired_with = 3;
+}
+
+message WakeEvent {
+  // Information about the wake event type.
+  enum WakeEventType {
+    // Type is unknown.
+    UNKNOWN = 0;
+
+    // WakeLock was acquired.
+    ACQUIRED = 1;
+
+    // WakeLock was released.
+    RELEASED = 2;
+  }
+
+  // Information about the wake event type.
+  optional WakeEventType wake_event_type = 1;
+
+  // Initiator of the scan. Only the first three names will be stored.
+  // e.g. com.google.gms.
+  optional string requestor = 2;
+
+  // Name of the wakelock (e.g. bluedroid_timer).
+  optional string name = 3;
+
+  // Time of the event.
+  optional int64 event_time_millis =
+      4;  // [(datapol.semantic_type) = ST_TIMESTAMP];
+}
+
+message ScanEvent {
+  // Scan type.
+  enum ScanTechnologyType {
+    // Scan Type is unknown.
+    SCAN_TYPE_UNKNOWN = 0;
+
+    SCAN_TECH_TYPE_LE = 1;
+
+    SCAN_TECH_TYPE_BREDR = 2;
+
+    SCAN_TECH_TYPE_BOTH = 3;
+  }
+
+  // Scan event type.
+  enum ScanEventType {
+    // Scan started.
+    SCAN_EVENT_START = 0;
+
+    // Scan stopped.
+    SCAN_EVENT_STOP = 1;
+  }
+
+  // Scan event type.
+  optional ScanEventType scan_event_type = 1;
+
+  // Initiator of the scan. Only the first three names will be stored.
+  // e.g. com.google.gms.
+  optional string initiator = 2;
+
+  // Technology used for scanning.
+  optional ScanTechnologyType scan_technology_type = 3;
+
+  // Number of results returned.
+  optional int32 number_results = 4;
+
+  // Time of the event.
+  optional int64 event_time_millis =
+      5;  // [(datapol.semantic_type) = ST_TIMESTAMP];
+}
diff --git a/bt/osi/src/reactor.cc b/bt/osi/src/reactor.cc
new file mode 100644
index 0000000..b77809a
--- /dev/null
+++ b/bt/osi/src/reactor.cc
@@ -0,0 +1,295 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_osi_reactor"
+
+#include "osi/include/reactor.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <unistd.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+
+#if !defined(EFD_SEMAPHORE)
+#define EFD_SEMAPHORE (1 << 0)
+#endif
+
+struct reactor_t {
+  int epoll_fd;
+  int event_fd;
+  pthread_mutex_t list_lock;  // protects invalidation_list.
+  list_t* invalidation_list;  // reactor objects that have been unregistered.
+  pthread_t run_thread;       // the pthread on which reactor_run is executing.
+  bool is_running;            // indicates whether |run_thread| is valid.
+  bool object_removed;
+};
+
+struct reactor_object_t {
+  int fd;              // the file descriptor to monitor for events.
+  void* context;       // a context that's passed back to the *_ready functions.
+  reactor_t* reactor;  // the reactor instance this object is registered with.
+  pthread_mutex_t
+      lock;  // protects the lifetime of this object and all variables.
+
+  void (*read_ready)(void* context);   // function to call when the file
+                                       // descriptor becomes readable.
+  void (*write_ready)(void* context);  // function to call when the file
+                                       // descriptor becomes writeable.
+};
+
+static reactor_status_t run_reactor(reactor_t* reactor, int iterations);
+
+static const size_t MAX_EVENTS = 64;
+static const eventfd_t EVENT_REACTOR_STOP = 1;
+
+reactor_t* reactor_new(void) {
+  reactor_t* ret = (reactor_t*)osi_calloc(sizeof(reactor_t));
+
+  ret->epoll_fd = INVALID_FD;
+  ret->event_fd = INVALID_FD;
+
+  ret->epoll_fd = epoll_create(MAX_EVENTS);
+  if (ret->epoll_fd == INVALID_FD) {
+    LOG_ERROR(LOG_TAG, "%s unable to create epoll instance: %s", __func__,
+              strerror(errno));
+    goto error;
+  }
+
+  ret->event_fd = eventfd(0, 0);
+  if (ret->event_fd == INVALID_FD) {
+    LOG_ERROR(LOG_TAG, "%s unable to create eventfd: %s", __func__,
+              strerror(errno));
+    goto error;
+  }
+
+  pthread_mutex_init(&ret->list_lock, NULL);
+  ret->invalidation_list = list_new(NULL);
+  if (!ret->invalidation_list) {
+    LOG_ERROR(LOG_TAG, "%s unable to allocate object invalidation list.",
+              __func__);
+    goto error;
+  }
+
+  struct epoll_event event;
+  memset(&event, 0, sizeof(event));
+  event.events = EPOLLIN;
+  event.data.ptr = NULL;
+  if (epoll_ctl(ret->epoll_fd, EPOLL_CTL_ADD, ret->event_fd, &event) == -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to register eventfd with epoll set: %s",
+              __func__, strerror(errno));
+    goto error;
+  }
+
+  return ret;
+
+error:;
+  reactor_free(ret);
+  return NULL;
+}
+
+void reactor_free(reactor_t* reactor) {
+  if (!reactor) return;
+
+  list_free(reactor->invalidation_list);
+  close(reactor->event_fd);
+  close(reactor->epoll_fd);
+  osi_free(reactor);
+}
+
+reactor_status_t reactor_start(reactor_t* reactor) {
+  assert(reactor != NULL);
+  return run_reactor(reactor, 0);
+}
+
+reactor_status_t reactor_run_once(reactor_t* reactor) {
+  assert(reactor != NULL);
+  return run_reactor(reactor, 1);
+}
+
+void reactor_stop(reactor_t* reactor) {
+  assert(reactor != NULL);
+
+  eventfd_write(reactor->event_fd, EVENT_REACTOR_STOP);
+}
+
+reactor_object_t* reactor_register(reactor_t* reactor, int fd, void* context,
+                                   void (*read_ready)(void* context),
+                                   void (*write_ready)(void* context)) {
+  assert(reactor != NULL);
+  assert(fd != INVALID_FD);
+
+  reactor_object_t* object =
+      (reactor_object_t*)osi_calloc(sizeof(reactor_object_t));
+
+  object->reactor = reactor;
+  object->fd = fd;
+  object->context = context;
+  object->read_ready = read_ready;
+  object->write_ready = write_ready;
+  pthread_mutex_init(&object->lock, NULL);
+
+  struct epoll_event event;
+  memset(&event, 0, sizeof(event));
+  if (read_ready) event.events |= (EPOLLIN | EPOLLRDHUP);
+  if (write_ready) event.events |= EPOLLOUT;
+  event.data.ptr = object;
+
+  if (epoll_ctl(reactor->epoll_fd, EPOLL_CTL_ADD, fd, &event) == -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to register fd %d to epoll set: %s", __func__,
+              fd, strerror(errno));
+    pthread_mutex_destroy(&object->lock);
+    osi_free(object);
+    return NULL;
+  }
+
+  return object;
+}
+
+bool reactor_change_registration(reactor_object_t* object,
+                                 void (*read_ready)(void* context),
+                                 void (*write_ready)(void* context)) {
+  assert(object != NULL);
+
+  struct epoll_event event;
+  memset(&event, 0, sizeof(event));
+  if (read_ready) event.events |= (EPOLLIN | EPOLLRDHUP);
+  if (write_ready) event.events |= EPOLLOUT;
+  event.data.ptr = object;
+
+  if (epoll_ctl(object->reactor->epoll_fd, EPOLL_CTL_MOD, object->fd, &event) ==
+      -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to modify interest set for fd %d: %s",
+              __func__, object->fd, strerror(errno));
+    return false;
+  }
+
+  pthread_mutex_lock(&object->lock);
+  object->read_ready = read_ready;
+  object->write_ready = write_ready;
+  pthread_mutex_unlock(&object->lock);
+
+  return true;
+}
+
+void reactor_unregister(reactor_object_t* obj) {
+  assert(obj != NULL);
+
+  reactor_t* reactor = obj->reactor;
+
+  if (epoll_ctl(reactor->epoll_fd, EPOLL_CTL_DEL, obj->fd, NULL) == -1)
+    LOG_ERROR(LOG_TAG, "%s unable to unregister fd %d from epoll set: %s",
+              __func__, obj->fd, strerror(errno));
+
+  if (reactor->is_running &&
+      pthread_equal(pthread_self(), reactor->run_thread)) {
+    reactor->object_removed = true;
+    return;
+  }
+
+  pthread_mutex_lock(&reactor->list_lock);
+  list_append(reactor->invalidation_list, obj);
+  pthread_mutex_unlock(&reactor->list_lock);
+
+  // Taking the object lock here makes sure a callback for |obj| isn't
+  // currently executing. The reactor thread must then either be before
+  // the callbacks or after. If after, we know that the object won't be
+  // referenced because it has been taken out of the epoll set. If before,
+  // it won't be referenced because the reactor thread will check the
+  // invalidation_list and find it in there. So by taking this lock, we
+  // are waiting until the reactor thread drops all references to |obj|.
+  // One the wait completes, we can unlock and destroy |obj| safely.
+  pthread_mutex_lock(&obj->lock);
+  pthread_mutex_unlock(&obj->lock);
+  pthread_mutex_destroy(&obj->lock);
+  osi_free(obj);
+}
+
+// Runs the reactor loop for a maximum of |iterations|.
+// 0 |iterations| means loop forever.
+// |reactor| may not be NULL.
+static reactor_status_t run_reactor(reactor_t* reactor, int iterations) {
+  assert(reactor != NULL);
+
+  reactor->run_thread = pthread_self();
+  reactor->is_running = true;
+
+  struct epoll_event events[MAX_EVENTS];
+  for (int i = 0; iterations == 0 || i < iterations; ++i) {
+    pthread_mutex_lock(&reactor->list_lock);
+    list_clear(reactor->invalidation_list);
+    pthread_mutex_unlock(&reactor->list_lock);
+
+    int ret;
+    OSI_NO_INTR(ret = epoll_wait(reactor->epoll_fd, events, MAX_EVENTS, -1));
+    if (ret == -1) {
+      LOG_ERROR(LOG_TAG, "%s error in epoll_wait: %s", __func__,
+                strerror(errno));
+      reactor->is_running = false;
+      return REACTOR_STATUS_ERROR;
+    }
+
+    for (int j = 0; j < ret; ++j) {
+      // The event file descriptor is the only one that registers with
+      // a NULL data pointer. We use the NULL to identify it and break
+      // out of the reactor loop.
+      if (events[j].data.ptr == NULL) {
+        eventfd_t value;
+        eventfd_read(reactor->event_fd, &value);
+        reactor->is_running = false;
+        return REACTOR_STATUS_STOP;
+      }
+
+      reactor_object_t* object = (reactor_object_t*)events[j].data.ptr;
+
+      pthread_mutex_lock(&reactor->list_lock);
+      if (list_contains(reactor->invalidation_list, object)) {
+        pthread_mutex_unlock(&reactor->list_lock);
+        continue;
+      }
+
+      // Downgrade the list lock to an object lock.
+      pthread_mutex_lock(&object->lock);
+      pthread_mutex_unlock(&reactor->list_lock);
+
+      reactor->object_removed = false;
+      if (events[j].events & (EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR) &&
+          object->read_ready)
+        object->read_ready(object->context);
+      if (!reactor->object_removed && events[j].events & EPOLLOUT &&
+          object->write_ready)
+        object->write_ready(object->context);
+      pthread_mutex_unlock(&object->lock);
+
+      if (reactor->object_removed) {
+        pthread_mutex_destroy(&object->lock);
+        osi_free(object);
+      }
+    }
+  }
+
+  reactor->is_running = false;
+  return REACTOR_STATUS_DONE;
+}
diff --git a/bt/osi/src/ringbuffer.cc b/bt/osi/src/ringbuffer.cc
new file mode 100644
index 0000000..3ab6023
--- /dev/null
+++ b/bt/osi/src/ringbuffer.cc
@@ -0,0 +1,116 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <assert.h>
+#include <stdlib.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/ringbuffer.h"
+
+struct ringbuffer_t {
+  size_t total;
+  size_t available;
+  uint8_t* base;
+  uint8_t* head;
+  uint8_t* tail;
+};
+
+ringbuffer_t* ringbuffer_init(const size_t size) {
+  ringbuffer_t* p =
+      static_cast<ringbuffer_t*>(osi_calloc(sizeof(ringbuffer_t)));
+
+  p->base = static_cast<uint8_t*>(osi_calloc(size));
+  p->head = p->tail = p->base;
+  p->total = p->available = size;
+
+  return p;
+}
+
+void ringbuffer_free(ringbuffer_t* rb) {
+  if (rb != NULL) osi_free(rb->base);
+  osi_free(rb);
+}
+
+size_t ringbuffer_available(const ringbuffer_t* rb) {
+  assert(rb);
+  return rb->available;
+}
+
+size_t ringbuffer_size(const ringbuffer_t* rb) {
+  assert(rb);
+  return rb->total - rb->available;
+}
+
+size_t ringbuffer_insert(ringbuffer_t* rb, const uint8_t* p, size_t length) {
+  assert(rb);
+  assert(p);
+
+  if (length > ringbuffer_available(rb)) length = ringbuffer_available(rb);
+
+  for (size_t i = 0; i != length; ++i) {
+    *rb->tail++ = *p++;
+    if (rb->tail >= (rb->base + rb->total)) rb->tail = rb->base;
+  }
+
+  rb->available -= length;
+  return length;
+}
+
+size_t ringbuffer_delete(ringbuffer_t* rb, size_t length) {
+  assert(rb);
+
+  if (length > ringbuffer_size(rb)) length = ringbuffer_size(rb);
+
+  rb->head += length;
+  if (rb->head >= (rb->base + rb->total)) rb->head -= rb->total;
+
+  rb->available += length;
+  return length;
+}
+
+size_t ringbuffer_peek(const ringbuffer_t* rb, off_t offset, uint8_t* p,
+                       size_t length) {
+  assert(rb);
+  assert(p);
+  assert(offset >= 0);
+  assert((size_t)offset <= ringbuffer_size(rb));
+
+  uint8_t* b = ((rb->head - rb->base + offset) % rb->total) + rb->base;
+  const size_t bytes_to_copy = (offset + length > ringbuffer_size(rb))
+                                   ? ringbuffer_size(rb) - offset
+                                   : length;
+
+  for (size_t copied = 0; copied < bytes_to_copy; ++copied) {
+    *p++ = *b++;
+    if (b >= (rb->base + rb->total)) b = rb->base;
+  }
+
+  return bytes_to_copy;
+}
+
+size_t ringbuffer_pop(ringbuffer_t* rb, uint8_t* p, size_t length) {
+  assert(rb);
+  assert(p);
+
+  const size_t copied = ringbuffer_peek(rb, 0, p, length);
+  rb->head += copied;
+  if (rb->head >= (rb->base + rb->total)) rb->head -= rb->total;
+
+  rb->available += copied;
+  return copied;
+}
diff --git a/bt/osi/src/semaphore.cc b/bt/osi/src/semaphore.cc
new file mode 100644
index 0000000..8760958
--- /dev/null
+++ b/bt/osi/src/semaphore.cc
@@ -0,0 +1,111 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_osi_semaphore"
+
+#include "osi/include/semaphore.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <string.h>
+#include <sys/eventfd.h>
+#include <unistd.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#if !defined(EFD_SEMAPHORE)
+#define EFD_SEMAPHORE (1 << 0)
+#endif
+
+struct semaphore_t {
+  int fd;
+};
+
+semaphore_t* semaphore_new(unsigned int value) {
+  semaphore_t* ret = static_cast<semaphore_t*>(osi_malloc(sizeof(semaphore_t)));
+  ret->fd = eventfd(value, EFD_SEMAPHORE);
+  if (ret->fd == INVALID_FD) {
+    LOG_ERROR(LOG_TAG, "%s unable to allocate semaphore: %s", __func__,
+              strerror(errno));
+    osi_free(ret);
+    ret = NULL;
+  }
+  return ret;
+}
+
+void semaphore_free(semaphore_t* semaphore) {
+  if (!semaphore) return;
+
+  if (semaphore->fd != INVALID_FD) close(semaphore->fd);
+  osi_free(semaphore);
+}
+
+void semaphore_wait(semaphore_t* semaphore) {
+  assert(semaphore != NULL);
+  assert(semaphore->fd != INVALID_FD);
+
+  eventfd_t value;
+  if (eventfd_read(semaphore->fd, &value) == -1)
+    LOG_ERROR(LOG_TAG, "%s unable to wait on semaphore: %s", __func__,
+              strerror(errno));
+}
+
+bool semaphore_try_wait(semaphore_t* semaphore) {
+  assert(semaphore != NULL);
+  assert(semaphore->fd != INVALID_FD);
+
+  int flags = fcntl(semaphore->fd, F_GETFL);
+  if (flags == -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to get flags for semaphore fd: %s", __func__,
+              strerror(errno));
+    return false;
+  }
+  if (fcntl(semaphore->fd, F_SETFL, flags | O_NONBLOCK) == -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to set O_NONBLOCK for semaphore fd: %s",
+              __func__, strerror(errno));
+    return false;
+  }
+
+  bool rc = true;
+  eventfd_t value;
+  if (eventfd_read(semaphore->fd, &value) == -1) rc = false;
+
+  if (fcntl(semaphore->fd, F_SETFL, flags) == -1)
+    LOG_ERROR(LOG_TAG, "%s unable to restore flags for semaphore fd: %s",
+              __func__, strerror(errno));
+  return rc;
+}
+
+void semaphore_post(semaphore_t* semaphore) {
+  assert(semaphore != NULL);
+  assert(semaphore->fd != INVALID_FD);
+
+  if (eventfd_write(semaphore->fd, 1ULL) == -1)
+    LOG_ERROR(LOG_TAG, "%s unable to post to semaphore: %s", __func__,
+              strerror(errno));
+}
+
+int semaphore_get_fd(const semaphore_t* semaphore) {
+  assert(semaphore != NULL);
+  assert(semaphore->fd != INVALID_FD);
+  return semaphore->fd;
+}
diff --git a/bt/osi/src/socket.cc b/bt/osi/src/socket.cc
new file mode 100644
index 0000000..7370246
--- /dev/null
+++ b/bt/osi/src/socket.cc
@@ -0,0 +1,232 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_osi_socket"
+
+#include "osi/include/socket.h"
+
+#include <asm/ioctls.h>
+#include <assert.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/reactor.h"
+
+// The IPv4 loopback address: 127.0.0.1
+static const in_addr_t LOCALHOST_ = 0x7f000001;
+
+struct socket_t {
+  int fd;
+  reactor_object_t* reactor_object;
+  socket_cb read_ready;
+  socket_cb write_ready;
+  void* context;  // Not owned, do not free.
+};
+
+static void internal_read_ready(void* context);
+static void internal_write_ready(void* context);
+
+socket_t* socket_new(void) {
+  socket_t* ret = (socket_t*)osi_calloc(sizeof(socket_t));
+  int enable = 1;
+
+  ret->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (ret->fd == INVALID_FD) {
+    LOG_ERROR(LOG_TAG, "%s unable to create socket: %s", __func__,
+              strerror(errno));
+    goto error;
+  }
+
+  if (setsockopt(ret->fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) ==
+      -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to set SO_REUSEADDR: %s", __func__,
+              strerror(errno));
+    goto error;
+  }
+
+  return ret;
+
+error:;
+  if (ret) close(ret->fd);
+  osi_free(ret);
+  return NULL;
+}
+
+socket_t* socket_new_from_fd(int fd) {
+  assert(fd != INVALID_FD);
+
+  socket_t* ret = (socket_t*)osi_calloc(sizeof(socket_t));
+
+  ret->fd = fd;
+  return ret;
+}
+
+void socket_free(socket_t* socket) {
+  if (!socket) return;
+
+  socket_unregister(socket);
+  close(socket->fd);
+  osi_free(socket);
+}
+
+bool socket_listen(const socket_t* socket, port_t port) {
+  assert(socket != NULL);
+
+  struct sockaddr_in addr;
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = htonl(LOCALHOST_);
+  addr.sin_port = htons(port);
+  if (bind(socket->fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to bind socket to port %u: %s", __func__,
+              port, strerror(errno));
+    return false;
+  }
+
+  if (listen(socket->fd, 10) == -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to listen on port %u: %s", __func__, port,
+              strerror(errno));
+    return false;
+  }
+
+  return true;
+}
+
+socket_t* socket_accept(const socket_t* socket) {
+  assert(socket != NULL);
+
+  int fd;
+  OSI_NO_INTR(fd = accept(socket->fd, NULL, NULL));
+  if (fd == INVALID_FD) {
+    LOG_ERROR(LOG_TAG, "%s unable to accept socket: %s", __func__,
+              strerror(errno));
+    return NULL;
+  }
+
+  socket_t* ret = (socket_t*)osi_calloc(sizeof(socket_t));
+
+  ret->fd = fd;
+  return ret;
+}
+
+ssize_t socket_read(const socket_t* socket, void* buf, size_t count) {
+  assert(socket != NULL);
+  assert(buf != NULL);
+
+  ssize_t ret;
+  OSI_NO_INTR(ret = recv(socket->fd, buf, count, MSG_DONTWAIT));
+
+  return ret;
+}
+
+ssize_t socket_write(const socket_t* socket, const void* buf, size_t count) {
+  assert(socket != NULL);
+  assert(buf != NULL);
+
+  ssize_t ret;
+  OSI_NO_INTR(ret = send(socket->fd, buf, count, MSG_DONTWAIT));
+
+  return ret;
+}
+
+ssize_t socket_write_and_transfer_fd(const socket_t* socket, const void* buf,
+                                     size_t count, int fd) {
+  assert(socket != NULL);
+  assert(buf != NULL);
+
+  if (fd == INVALID_FD) return socket_write(socket, buf, count);
+
+  struct msghdr msg;
+  struct iovec iov;
+  char control_buf[CMSG_SPACE(sizeof(int))];
+
+  iov.iov_base = (void*)buf;
+  iov.iov_len = count;
+
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = control_buf;
+  msg.msg_controllen = sizeof(control_buf);
+  msg.msg_name = NULL;
+  msg.msg_namelen = 0;
+
+  struct cmsghdr* header = CMSG_FIRSTHDR(&msg);
+  header->cmsg_level = SOL_SOCKET;
+  header->cmsg_type = SCM_RIGHTS;
+  header->cmsg_len = CMSG_LEN(sizeof(int));
+  *(int*)CMSG_DATA(header) = fd;
+
+  ssize_t ret;
+  OSI_NO_INTR(ret = sendmsg(socket->fd, &msg, MSG_DONTWAIT));
+
+  close(fd);
+  return ret;
+}
+
+ssize_t socket_bytes_available(const socket_t* socket) {
+  assert(socket != NULL);
+
+  int size = 0;
+  if (ioctl(socket->fd, FIONREAD, &size) == -1) return -1;
+  return size;
+}
+
+void socket_register(socket_t* socket, reactor_t* reactor, void* context,
+                     socket_cb read_cb, socket_cb write_cb) {
+  assert(socket != NULL);
+
+  // Make sure the socket isn't currently registered.
+  socket_unregister(socket);
+
+  socket->read_ready = read_cb;
+  socket->write_ready = write_cb;
+  socket->context = context;
+
+  void (*read_fn)(void*) = (read_cb != NULL) ? internal_read_ready : NULL;
+  void (*write_fn)(void*) = (write_cb != NULL) ? internal_write_ready : NULL;
+
+  socket->reactor_object =
+      reactor_register(reactor, socket->fd, socket, read_fn, write_fn);
+}
+
+void socket_unregister(socket_t* socket) {
+  assert(socket != NULL);
+
+  if (socket->reactor_object) reactor_unregister(socket->reactor_object);
+  socket->reactor_object = NULL;
+}
+
+static void internal_read_ready(void* context) {
+  assert(context != NULL);
+
+  socket_t* socket = static_cast<socket_t*>(context);
+  socket->read_ready(socket, socket->context);
+}
+
+static void internal_write_ready(void* context) {
+  assert(context != NULL);
+
+  socket_t* socket = static_cast<socket_t*>(context);
+  socket->write_ready(socket, socket->context);
+}
diff --git a/bt/osi/src/socket_utils/README b/bt/osi/src/socket_utils/README
new file mode 100644
index 0000000..9ed210a
--- /dev/null
+++ b/bt/osi/src/socket_utils/README
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+The sources in this folder re -
+    implement some of the sources in libcutils / sockets to provide a short -
+    term solution eliminating libcutils dependency from system /
+        bt.Once a long -
+    term platform - independent abstraction is presented,
+    these sources and the corresponding headers should be removed.
+
+        Note that only a part of the source files are pulled from libcutils /
+        sockets,
+    and"osi_" prefix is added to all functions
+            .The developers who want to pull sockets sources other than the
+                existing ones must put the sources in this folder and refactor
+                    the functions as well.
+
+        The current sources include :
+
+        [Headers] -
+        osi / include / socket_utils / sockets.h -
+        osi / include / socket_utils / socket_local.h[Source files] -
+        osi / src / socket_utils / socket_local_client.cc -
+        osi / src / socket_utils /
+            socket_local_server
+                .cc
+
+                    Please update the above list if adding more sources.
diff --git a/bt/osi/src/socket_utils/socket_local_client.cc b/bt/osi/src/socket_utils/socket_local_client.cc
new file mode 100644
index 0000000..7338407
--- /dev/null
+++ b/bt/osi/src/socket_utils/socket_local_client.cc
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "osi/include/osi.h"
+#include "osi/include/socket_utils/socket_local.h"
+#include "osi/include/socket_utils/sockets.h"
+
+#define LISTEN_BACKLOG 4
+
+/* Documented in header file. */
+int osi_socket_make_sockaddr_un(const char* name, int namespaceId,
+                                struct sockaddr_un* p_addr, socklen_t* alen) {
+  memset(p_addr, 0, sizeof(*p_addr));
+  size_t namelen;
+
+  switch (namespaceId) {
+    case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
+#if defined(__linux__)
+      namelen = strlen(name);
+
+      // Test with length +1 for the *initial* '\0'.
+      if ((namelen + 1) > sizeof(p_addr->sun_path)) {
+        goto error;
+      }
+
+      /*
+       * Note: The path in this case is *not* supposed to be
+       * '\0'-terminated. ("man 7 unix" for the gory details.)
+       */
+
+      p_addr->sun_path[0] = 0;
+      memcpy(p_addr->sun_path + 1, name, namelen);
+#else
+      /* this OS doesn't have the Linux abstract namespace */
+
+      namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
+      /* unix_path_max appears to be missing on linux */
+      if (namelen >
+          sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) {
+        goto error;
+      }
+
+      strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
+      strcat(p_addr->sun_path, name);
+#endif
+      break;
+
+    case ANDROID_SOCKET_NAMESPACE_RESERVED:
+      namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
+      /* unix_path_max appears to be missing on linux */
+      if (namelen >
+          sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) {
+        goto error;
+      }
+
+      strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
+      strcat(p_addr->sun_path, name);
+      break;
+
+    case ANDROID_SOCKET_NAMESPACE_FILESYSTEM:
+      namelen = strlen(name);
+      /* unix_path_max appears to be missing on linux */
+      if (namelen >
+          sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) {
+        goto error;
+      }
+
+      strcpy(p_addr->sun_path, name);
+      break;
+    default:
+      // invalid namespace id
+      return -1;
+  }
+
+  p_addr->sun_family = AF_LOCAL;
+  *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
+  return 0;
+error:
+  return -1;
+}
+
+/**
+ * connect to peer named "name" on fd
+ * returns same fd or -1 on error.
+ * fd is not closed on error. that's your job.
+ *
+ * Used by AndroidSocketImpl
+ */
+int osi_socket_local_client_connect(int fd, const char* name, int namespaceId,
+                                    int type UNUSED_ATTR) {
+  struct sockaddr_un addr;
+  socklen_t alen;
+  int err;
+
+  err = osi_socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
+
+  if (err < 0) {
+    goto error;
+  }
+
+  OSI_NO_INTR(err = connect(fd, (struct sockaddr*)&addr, alen));
+  if (err < 0) {
+    goto error;
+  }
+
+  return fd;
+
+error:
+  return -1;
+}
+
+/**
+ * connect to peer named "name"
+ * returns fd or -1 on error
+ */
+int osi_socket_local_client(const char* name, int namespaceId, int type) {
+  int s;
+
+  s = socket(AF_LOCAL, type, 0);
+  if (s < 0) return -1;
+
+  if (0 > osi_socket_local_client_connect(s, name, namespaceId, type)) {
+    close(s);
+    return -1;
+  }
+
+  return s;
+}
diff --git a/bt/osi/src/socket_utils/socket_local_server.cc b/bt/osi/src/socket_utils/socket_local_server.cc
new file mode 100644
index 0000000..9bfdf54
--- /dev/null
+++ b/bt/osi/src/socket_utils/socket_local_server.cc
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2006, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <errno.h>
+#include <netinet/in.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "osi/include/socket_utils/socket_local.h"
+#include "osi/include/socket_utils/sockets.h"
+
+#define LISTEN_BACKLOG 4
+
+/* Only the bottom bits are really the socket type; there are flags too. */
+#define SOCK_TYPE_MASK 0xf
+
+/**
+ * Binds a pre-created socket(AF_LOCAL) 's' to 'name'
+ * returns 's' on success, -1 on fail
+ *
+ * Does not call listen()
+ */
+int osi_socket_local_server_bind(int s, const char* name, int namespaceId) {
+  struct sockaddr_un addr;
+  socklen_t alen;
+  int n;
+  int err;
+
+  err = osi_socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
+
+  if (err < 0) {
+    return -1;
+  }
+
+/* basically: if this is a filesystem path, unlink first */
+#if !defined(__linux__)
+  if (1) {
+#else
+  if (namespaceId == ANDROID_SOCKET_NAMESPACE_RESERVED ||
+      namespaceId == ANDROID_SOCKET_NAMESPACE_FILESYSTEM) {
+#endif
+    /*ignore ENOENT*/
+    unlink(addr.sun_path);
+  }
+
+  n = 1;
+  setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
+
+  if (bind(s, (struct sockaddr*)&addr, alen) < 0) {
+    return -1;
+  }
+
+  return s;
+}
+
+/** Open a server-side UNIX domain datagram socket in the Linux non-filesystem
+ *  namespace
+ *
+ *  Returns fd on success, -1 on fail
+ */
+int osi_socket_local_server(const char* name, int namespaceId, int type) {
+  int err;
+  int s;
+
+  s = socket(AF_LOCAL, type, 0);
+  if (s < 0) return -1;
+
+  err = osi_socket_local_server_bind(s, name, namespaceId);
+
+  if (err < 0) {
+    close(s);
+    return -1;
+  }
+
+  if ((type & SOCK_TYPE_MASK) == SOCK_STREAM) {
+    int ret;
+
+    ret = listen(s, LISTEN_BACKLOG);
+
+    if (ret < 0) {
+      close(s);
+      return -1;
+    }
+  }
+
+  return s;
+}
diff --git a/bt/osi/src/thread.cc b/bt/osi/src/thread.cc
new file mode 100644
index 0000000..92017a3
--- /dev/null
+++ b/bt/osi/src/thread.cc
@@ -0,0 +1,237 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_osi_thread"
+
+#include "osi/include/thread.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <malloc.h>
+#include <pthread.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/compat.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/log.h"
+#include "osi/include/reactor.h"
+#include "osi/include/semaphore.h"
+
+struct thread_t {
+  bool is_joined;
+  pthread_t pthread;
+  pid_t tid;
+  char name[THREAD_NAME_MAX + 1];
+  reactor_t* reactor;
+  fixed_queue_t* work_queue;
+};
+
+struct start_arg {
+  thread_t* thread;
+  semaphore_t* start_sem;
+  int error;
+};
+
+typedef struct {
+  thread_fn func;
+  void* context;
+} work_item_t;
+
+static void* run_thread(void* start_arg);
+static void work_queue_read_cb(void* context);
+
+static const size_t DEFAULT_WORK_QUEUE_CAPACITY = 128;
+
+thread_t* thread_new_sized(const char* name, size_t work_queue_capacity) {
+  assert(name != NULL);
+  assert(work_queue_capacity != 0);
+
+  thread_t* ret = static_cast<thread_t*>(osi_calloc(sizeof(thread_t)));
+
+  ret->reactor = reactor_new();
+  if (!ret->reactor) goto error;
+
+  ret->work_queue = fixed_queue_new(work_queue_capacity);
+  if (!ret->work_queue) goto error;
+
+  // Start is on the stack, but we use a semaphore, so it's safe
+  struct start_arg start;
+  start.start_sem = semaphore_new(0);
+  if (!start.start_sem) goto error;
+
+  strncpy(ret->name, name, THREAD_NAME_MAX);
+  start.thread = ret;
+  start.error = 0;
+  pthread_create(&ret->pthread, NULL, run_thread, &start);
+  semaphore_wait(start.start_sem);
+  semaphore_free(start.start_sem);
+
+  if (start.error) goto error;
+
+  return ret;
+
+error:;
+  if (ret) {
+    fixed_queue_free(ret->work_queue, osi_free);
+    reactor_free(ret->reactor);
+  }
+  osi_free(ret);
+  return NULL;
+}
+
+thread_t* thread_new(const char* name) {
+  return thread_new_sized(name, DEFAULT_WORK_QUEUE_CAPACITY);
+}
+
+void thread_free(thread_t* thread) {
+  if (!thread) return;
+
+  thread_stop(thread);
+  thread_join(thread);
+
+  fixed_queue_free(thread->work_queue, osi_free);
+  reactor_free(thread->reactor);
+  osi_free(thread);
+}
+
+void thread_join(thread_t* thread) {
+  assert(thread != NULL);
+
+  // TODO(zachoverflow): use a compare and swap when ready
+  if (!thread->is_joined) {
+    thread->is_joined = true;
+    pthread_join(thread->pthread, NULL);
+  }
+}
+
+bool thread_post(thread_t* thread, thread_fn func, void* context) {
+  assert(thread != NULL);
+  assert(func != NULL);
+
+  // TODO(sharvil): if the current thread == |thread| and we've run out
+  // of queue space, we should abort this operation, otherwise we'll
+  // deadlock.
+
+  // Queue item is freed either when the queue itself is destroyed
+  // or when the item is removed from the queue for dispatch.
+  work_item_t* item = (work_item_t*)osi_malloc(sizeof(work_item_t));
+  item->func = func;
+  item->context = context;
+  fixed_queue_enqueue(thread->work_queue, item);
+  return true;
+}
+
+void thread_stop(thread_t* thread) {
+  assert(thread != NULL);
+  reactor_stop(thread->reactor);
+}
+
+bool thread_set_priority(thread_t* thread, int priority) {
+  if (!thread) return false;
+
+  const int rc = setpriority(PRIO_PROCESS, thread->tid, priority);
+  if (rc < 0) {
+    LOG_ERROR(LOG_TAG,
+              "%s unable to set thread priority %d for tid %d, error %d",
+              __func__, priority, thread->tid, rc);
+    return false;
+  }
+
+  return true;
+}
+
+bool thread_is_self(const thread_t* thread) {
+  assert(thread != NULL);
+  return !!pthread_equal(pthread_self(), thread->pthread);
+}
+
+reactor_t* thread_get_reactor(const thread_t* thread) {
+  assert(thread != NULL);
+  return thread->reactor;
+}
+
+const char* thread_name(const thread_t* thread) {
+  assert(thread != NULL);
+  return thread->name;
+}
+
+static void* run_thread(void* start_arg) {
+  assert(start_arg != NULL);
+
+  struct start_arg* start = static_cast<struct start_arg*>(start_arg);
+  thread_t* thread = start->thread;
+
+  assert(thread != NULL);
+
+  if (prctl(PR_SET_NAME, (unsigned long)thread->name) == -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to set thread name: %s", __func__,
+              strerror(errno));
+    start->error = errno;
+    semaphore_post(start->start_sem);
+    return NULL;
+  }
+  thread->tid = gettid();
+
+  LOG_WARN(LOG_TAG, "%s: thread id %d, thread name %s started", __func__,
+           thread->tid, thread->name);
+
+  semaphore_post(start->start_sem);
+
+  int fd = fixed_queue_get_dequeue_fd(thread->work_queue);
+  void* context = thread->work_queue;
+
+  reactor_object_t* work_queue_object =
+      reactor_register(thread->reactor, fd, context, work_queue_read_cb, NULL);
+  reactor_start(thread->reactor);
+  reactor_unregister(work_queue_object);
+
+  // Make sure we dispatch all queued work items before exiting the thread.
+  // This allows a caller to safely tear down by enqueuing a teardown
+  // work item and then joining the thread.
+  size_t count = 0;
+  work_item_t* item =
+      static_cast<work_item_t*>(fixed_queue_try_dequeue(thread->work_queue));
+  while (item && count <= fixed_queue_capacity(thread->work_queue)) {
+    item->func(item->context);
+    osi_free(item);
+    item =
+        static_cast<work_item_t*>(fixed_queue_try_dequeue(thread->work_queue));
+    ++count;
+  }
+
+  if (count > fixed_queue_capacity(thread->work_queue))
+    LOG_DEBUG(LOG_TAG, "%s growing event queue on shutdown.", __func__);
+
+  LOG_WARN(LOG_TAG, "%s: thread id %d, thread name %s exited", __func__,
+           thread->tid, thread->name);
+  return NULL;
+}
+
+static void work_queue_read_cb(void* context) {
+  assert(context != NULL);
+
+  fixed_queue_t* queue = (fixed_queue_t*)context;
+  work_item_t* item = static_cast<work_item_t*>(fixed_queue_dequeue(queue));
+  item->func(item->context);
+  osi_free(item);
+}
diff --git a/bt/osi/src/time.cc b/bt/osi/src/time.cc
new file mode 100644
index 0000000..a36d411
--- /dev/null
+++ b/bt/osi/src/time.cc
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_osi_time"
+
+#include <time.h>
+
+#include "osi/include/time.h"
+
+uint32_t time_get_os_boottime_ms(void) {
+  return (uint32_t)(time_get_os_boottime_us() / 1000);
+}
+
+uint64_t time_get_os_boottime_us(void) {
+  struct timespec ts_now;
+  clock_gettime(CLOCK_BOOTTIME, &ts_now);
+
+  return ((uint64_t)ts_now.tv_sec * 1000000L) +
+         ((uint64_t)ts_now.tv_nsec / 1000);
+}
diff --git a/bt/osi/src/wakelock.cc b/bt/osi/src/wakelock.cc
new file mode 100644
index 0000000..777aa8c
--- /dev/null
+++ b/bt/osi/src/wakelock.cc
@@ -0,0 +1,380 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_osi_wakelock"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <hardware/bluetooth.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <pthread.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "osi/include/alarm.h"
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+#include "osi/include/metrics.h"
+#include "osi/include/osi.h"
+#include "osi/include/thread.h"
+#include "osi/include/wakelock.h"
+
+static bt_os_callouts_t* wakelock_os_callouts = NULL;
+static bool is_native = true;
+
+static const clockid_t CLOCK_ID = CLOCK_BOOTTIME;
+static const char* WAKE_LOCK_ID = "bluetooth_timer";
+static const std::string DEFAULT_WAKE_LOCK_PATH = "/sys/power/wake_lock";
+static const std::string DEFAULT_WAKE_UNLOCK_PATH = "/sys/power/wake_unlock";
+static std::string wake_lock_path;
+static std::string wake_unlock_path;
+static ssize_t locked_id_len = -1;
+static pthread_once_t initialized = PTHREAD_ONCE_INIT;
+static int wake_lock_fd = INVALID_FD;
+static int wake_unlock_fd = INVALID_FD;
+
+// Wakelock statistics for the "bluetooth_timer"
+typedef struct {
+  bool is_acquired;
+  size_t acquired_count;
+  size_t released_count;
+  size_t acquired_errors;
+  size_t released_errors;
+  period_ms_t min_acquired_interval_ms;
+  period_ms_t max_acquired_interval_ms;
+  period_ms_t last_acquired_interval_ms;
+  period_ms_t total_acquired_interval_ms;
+  period_ms_t last_acquired_timestamp_ms;
+  period_ms_t last_released_timestamp_ms;
+  period_ms_t last_reset_timestamp_ms;
+  int last_acquired_error;
+  int last_released_error;
+} wakelock_stats_t;
+
+static wakelock_stats_t wakelock_stats;
+
+// This mutex ensures that the functions that update and dump the statistics
+// are executed serially.
+static pthread_mutex_t monitor;
+
+static bt_status_t wakelock_acquire_callout(void);
+static bt_status_t wakelock_acquire_native(void);
+static bt_status_t wakelock_release_callout(void);
+static bt_status_t wakelock_release_native(void);
+static void wakelock_initialize(void);
+static void wakelock_initialize_native(void);
+static void reset_wakelock_stats(void);
+static void update_wakelock_acquired_stats(bt_status_t acquired_status);
+static void update_wakelock_released_stats(bt_status_t released_status);
+
+void wakelock_set_os_callouts(bt_os_callouts_t* callouts) {
+  wakelock_os_callouts = callouts;
+  is_native = (wakelock_os_callouts == NULL);
+  LOG_INFO(LOG_TAG, "%s set to %s", __func__,
+           (is_native) ? "native" : "non-native");
+}
+
+bool wakelock_acquire(void) {
+  pthread_once(&initialized, wakelock_initialize);
+
+  bt_status_t status = BT_STATUS_FAIL;
+
+  if (is_native)
+    status = wakelock_acquire_native();
+  else
+    status = wakelock_acquire_callout();
+
+  update_wakelock_acquired_stats(status);
+
+  if (status != BT_STATUS_SUCCESS)
+    LOG_ERROR(LOG_TAG, "%s unable to acquire wake lock: %d", __func__, status);
+
+  return (status == BT_STATUS_SUCCESS);
+}
+
+static bt_status_t wakelock_acquire_callout(void) {
+  return static_cast<bt_status_t>(
+      wakelock_os_callouts->acquire_wake_lock(WAKE_LOCK_ID));
+}
+
+static bt_status_t wakelock_acquire_native(void) {
+  if (wake_lock_fd == INVALID_FD) {
+    LOG_ERROR(LOG_TAG, "%s lock not acquired, invalid fd", __func__);
+    return BT_STATUS_PARM_INVALID;
+  }
+
+  if (wake_unlock_fd == INVALID_FD) {
+    LOG_ERROR(LOG_TAG, "%s not acquiring lock: can't release lock", __func__);
+    return BT_STATUS_PARM_INVALID;
+  }
+
+  long lock_name_len = strlen(WAKE_LOCK_ID);
+  locked_id_len = write(wake_lock_fd, WAKE_LOCK_ID, lock_name_len);
+  if (locked_id_len == -1) {
+    LOG_ERROR(LOG_TAG, "%s wake lock not acquired: %s", __func__,
+              strerror(errno));
+    return BT_STATUS_FAIL;
+  } else if (locked_id_len < lock_name_len) {
+    // TODO (jamuraa): this is weird. maybe we should release and retry.
+    LOG_WARN(LOG_TAG, "%s wake lock truncated to %zd chars", __func__,
+             locked_id_len);
+  }
+  return BT_STATUS_SUCCESS;
+}
+
+bool wakelock_release(void) {
+  pthread_once(&initialized, wakelock_initialize);
+
+  bt_status_t status = BT_STATUS_FAIL;
+
+  if (is_native)
+    status = wakelock_release_native();
+  else
+    status = wakelock_release_callout();
+
+  update_wakelock_released_stats(status);
+
+  return (status == BT_STATUS_SUCCESS);
+}
+
+static bt_status_t wakelock_release_callout(void) {
+  return static_cast<bt_status_t>(
+      wakelock_os_callouts->release_wake_lock(WAKE_LOCK_ID));
+}
+
+static bt_status_t wakelock_release_native(void) {
+  if (wake_unlock_fd == INVALID_FD) {
+    LOG_ERROR(LOG_TAG, "%s lock not released, invalid fd", __func__);
+    return BT_STATUS_PARM_INVALID;
+  }
+
+  ssize_t wrote_name_len = write(wake_unlock_fd, WAKE_LOCK_ID, locked_id_len);
+  if (wrote_name_len == -1) {
+    LOG_ERROR(LOG_TAG, "%s can't release wake lock: %s", __func__,
+              strerror(errno));
+  } else if (wrote_name_len < locked_id_len) {
+    LOG_ERROR(LOG_TAG, "%s lock release only wrote %zd, assuming released",
+              __func__, wrote_name_len);
+  }
+  return BT_STATUS_SUCCESS;
+}
+
+static void wakelock_initialize(void) {
+  pthread_mutex_init(&monitor, NULL);
+  reset_wakelock_stats();
+
+  if (is_native) wakelock_initialize_native();
+}
+
+static void wakelock_initialize_native(void) {
+  LOG_DEBUG(LOG_TAG, "%s opening wake locks", __func__);
+
+  if (wake_lock_path.empty()) wake_lock_path = DEFAULT_WAKE_LOCK_PATH;
+
+  wake_lock_fd = open(wake_lock_path.c_str(), O_RDWR | O_CLOEXEC);
+  if (wake_lock_fd == INVALID_FD) {
+    LOG_ERROR(LOG_TAG, "%s can't open wake lock %s: %s", __func__,
+              wake_lock_path.c_str(), strerror(errno));
+  }
+
+  if (wake_unlock_path.empty()) wake_unlock_path = DEFAULT_WAKE_UNLOCK_PATH;
+
+  wake_unlock_fd = open(wake_unlock_path.c_str(), O_RDWR | O_CLOEXEC);
+  if (wake_unlock_fd == INVALID_FD) {
+    LOG_ERROR(LOG_TAG, "%s can't open wake unlock %s: %s", __func__,
+              wake_unlock_path.c_str(), strerror(errno));
+  }
+}
+
+void wakelock_cleanup(void) {
+  wake_lock_path.clear();
+  wake_unlock_path.clear();
+  initialized = PTHREAD_ONCE_INIT;
+  pthread_mutex_destroy(&monitor);
+}
+
+void wakelock_set_paths(const char* lock_path, const char* unlock_path) {
+  if (lock_path) wake_lock_path = lock_path;
+
+  if (unlock_path) wake_unlock_path = unlock_path;
+}
+
+static period_ms_t now(void) {
+  struct timespec ts;
+  if (clock_gettime(CLOCK_ID, &ts) == -1) {
+    LOG_ERROR(LOG_TAG, "%s unable to get current time: %s", __func__,
+              strerror(errno));
+    return 0;
+  }
+
+  return (ts.tv_sec * 1000LL) + (ts.tv_nsec / 1000000LL);
+}
+
+// Reset the Bluetooth wakelock statistics.
+// This function is thread-safe.
+static void reset_wakelock_stats(void) {
+  pthread_mutex_lock(&monitor);
+
+  wakelock_stats.is_acquired = false;
+  wakelock_stats.acquired_count = 0;
+  wakelock_stats.released_count = 0;
+  wakelock_stats.acquired_errors = 0;
+  wakelock_stats.released_errors = 0;
+  wakelock_stats.min_acquired_interval_ms = 0;
+  wakelock_stats.max_acquired_interval_ms = 0;
+  wakelock_stats.last_acquired_interval_ms = 0;
+  wakelock_stats.total_acquired_interval_ms = 0;
+  wakelock_stats.last_acquired_timestamp_ms = 0;
+  wakelock_stats.last_released_timestamp_ms = 0;
+  wakelock_stats.last_reset_timestamp_ms = now();
+
+  pthread_mutex_unlock(&monitor);
+}
+
+//
+// Update the Bluetooth acquire wakelock statistics.
+//
+// This function should be called every time when the wakelock is acquired.
+// |acquired_status| is the status code that was return when the wakelock was
+// acquired.
+// This function is thread-safe.
+//
+static void update_wakelock_acquired_stats(bt_status_t acquired_status) {
+  const period_ms_t now_ms = now();
+
+  pthread_mutex_lock(&monitor);
+
+  if (acquired_status != BT_STATUS_SUCCESS) {
+    wakelock_stats.acquired_errors++;
+    wakelock_stats.last_acquired_error = acquired_status;
+  }
+
+  if (wakelock_stats.is_acquired) {
+    pthread_mutex_unlock(&monitor);
+    return;
+  }
+
+  wakelock_stats.is_acquired = true;
+  wakelock_stats.acquired_count++;
+  wakelock_stats.last_acquired_timestamp_ms = now_ms;
+
+  pthread_mutex_unlock(&monitor);
+
+  metrics_wake_event(WAKE_EVENT_ACQUIRED, NULL, WAKE_LOCK_ID, now_ms);
+}
+
+//
+// Update the Bluetooth release wakelock statistics.
+//
+// This function should be called every time when the wakelock is released.
+// |released_status| is the status code that was return when the wakelock was
+// released.
+// This function is thread-safe.
+//
+static void update_wakelock_released_stats(bt_status_t released_status) {
+  const period_ms_t now_ms = now();
+
+  pthread_mutex_lock(&monitor);
+
+  if (released_status != BT_STATUS_SUCCESS) {
+    wakelock_stats.released_errors++;
+    wakelock_stats.last_released_error = released_status;
+  }
+
+  if (!wakelock_stats.is_acquired) {
+    pthread_mutex_unlock(&monitor);
+    return;
+  }
+
+  wakelock_stats.is_acquired = false;
+  wakelock_stats.released_count++;
+  wakelock_stats.last_released_timestamp_ms = now_ms;
+
+  // Compute the acquired interval and update the statistics
+  period_ms_t delta_ms = now_ms - wakelock_stats.last_acquired_timestamp_ms;
+  if (delta_ms < wakelock_stats.min_acquired_interval_ms ||
+      wakelock_stats.released_count == 1) {
+    wakelock_stats.min_acquired_interval_ms = delta_ms;
+  }
+  if (delta_ms > wakelock_stats.max_acquired_interval_ms) {
+    wakelock_stats.max_acquired_interval_ms = delta_ms;
+  }
+  wakelock_stats.last_acquired_interval_ms = delta_ms;
+  wakelock_stats.total_acquired_interval_ms += delta_ms;
+
+  pthread_mutex_unlock(&monitor);
+
+  metrics_wake_event(WAKE_EVENT_RELEASED, NULL, WAKE_LOCK_ID, now_ms);
+}
+
+void wakelock_debug_dump(int fd) {
+  const period_ms_t now_ms = now();
+
+  // Need to keep track for lock errors - e.g., the "monitor" mutex
+  // might not be initialized
+  const int lock_error = pthread_mutex_lock(&monitor);
+
+  // Compute the last acquired interval if the wakelock is still acquired
+  period_ms_t delta_ms = 0;
+  period_ms_t last_interval = wakelock_stats.last_acquired_interval_ms;
+  period_ms_t min_interval = wakelock_stats.min_acquired_interval_ms;
+  period_ms_t max_interval = wakelock_stats.max_acquired_interval_ms;
+  period_ms_t ave_interval = 0;
+
+  if (wakelock_stats.is_acquired) {
+    delta_ms = now_ms - wakelock_stats.last_acquired_timestamp_ms;
+    if (delta_ms > max_interval) max_interval = delta_ms;
+    if (delta_ms < min_interval) min_interval = delta_ms;
+    last_interval = delta_ms;
+  }
+  period_ms_t total_interval =
+      wakelock_stats.total_acquired_interval_ms + delta_ms;
+
+  if (wakelock_stats.acquired_count > 0)
+    ave_interval = total_interval / wakelock_stats.acquired_count;
+
+  dprintf(fd, "\nBluetooth Wakelock Statistics:\n");
+  dprintf(fd, "  Is acquired                    : %s\n",
+          wakelock_stats.is_acquired ? "true" : "false");
+  dprintf(fd, "  Acquired/released count        : %zu / %zu\n",
+          wakelock_stats.acquired_count, wakelock_stats.released_count);
+  dprintf(fd, "  Acquired/released error count  : %zu / %zu\n",
+          wakelock_stats.acquired_errors, wakelock_stats.released_errors);
+  dprintf(fd, "  Last acquire/release error code: %d / %d\n",
+          wakelock_stats.last_acquired_error,
+          wakelock_stats.last_released_error);
+  dprintf(fd, "  Last acquired time (ms)        : %llu\n",
+          (unsigned long long)last_interval);
+  dprintf(fd, "  Acquired time min/max/avg (ms) : %llu / %llu / %llu\n",
+          (unsigned long long)min_interval, (unsigned long long)max_interval,
+          (unsigned long long)ave_interval);
+  dprintf(fd, "  Total acquired time (ms)       : %llu\n",
+          (unsigned long long)total_interval);
+  dprintf(
+      fd, "  Total run time (ms)            : %llu\n",
+      (unsigned long long)(now_ms - wakelock_stats.last_reset_timestamp_ms));
+
+  if (lock_error == 0) pthread_mutex_unlock(&monitor);
+}
diff --git a/bt/osi/test/AlarmTestHarness.cc b/bt/osi/test/AlarmTestHarness.cc
new file mode 100644
index 0000000..ee6aaa3
--- /dev/null
+++ b/bt/osi/test/AlarmTestHarness.cc
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "AlarmTestHarness.h"
+
+#include <hardware/bluetooth.h>
+
+#include "osi/include/alarm.h"
+#include "osi/include/wakelock.h"
+
+static bool is_wake_lock_acquired = false;
+
+static int acquire_wake_lock_cb(const char* lock_name) {
+  is_wake_lock_acquired = true;
+  return BT_STATUS_SUCCESS;
+}
+
+static int release_wake_lock_cb(const char* lock_name) {
+  is_wake_lock_acquired = false;
+  return BT_STATUS_SUCCESS;
+}
+
+static bt_os_callouts_t bt_wakelock_callouts = {
+    sizeof(bt_os_callouts_t), NULL, acquire_wake_lock_cb, release_wake_lock_cb};
+
+void AlarmTestHarness::SetUp() {
+  AllocationTestHarness::SetUp();
+
+  TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 500;
+
+  wakelock_set_os_callouts(&bt_wakelock_callouts);
+}
+
+void AlarmTestHarness::TearDown() {
+  alarm_cleanup();
+  wakelock_cleanup();
+  wakelock_set_os_callouts(NULL);
+
+  AllocationTestHarness::TearDown();
+}
+
+bool AlarmTestHarness::WakeLockHeld() { return is_wake_lock_acquired; }
diff --git a/bt/osi/test/AlarmTestHarness.h b/bt/osi/test/AlarmTestHarness.h
new file mode 100644
index 0000000..39dd218
--- /dev/null
+++ b/bt/osi/test/AlarmTestHarness.h
@@ -0,0 +1,33 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 "AllocationTestHarness.h"
+
+extern int64_t TIMER_INTERVAL_FOR_WAKELOCK_IN_MS;
+
+class AlarmTestHarness : public AllocationTestHarness {
+ protected:
+  virtual void SetUp();
+  virtual void TearDown();
+
+ public:
+  // Returns true if a wake lock is held.
+  bool WakeLockHeld();
+};
diff --git a/bt/osi/test/AllocationTestHarness.cc b/bt/osi/test/AllocationTestHarness.cc
new file mode 100644
index 0000000..8df097f
--- /dev/null
+++ b/bt/osi/test/AllocationTestHarness.cc
@@ -0,0 +1,33 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "osi/test/AllocationTestHarness.h"
+
+#include "osi/include/allocation_tracker.h"
+
+void AllocationTestHarness::SetUp() {
+  allocation_tracker_init();
+  allocation_tracker_reset();
+}
+
+void AllocationTestHarness::TearDown() {
+  EXPECT_EQ(0U, allocation_tracker_expect_no_allocations())
+      << "not all memory freed";
+}
diff --git a/bt/osi/test/AllocationTestHarness.h b/bt/osi/test/AllocationTestHarness.h
new file mode 100644
index 0000000..cbf29d8
--- /dev/null
+++ b/bt/osi/test/AllocationTestHarness.h
@@ -0,0 +1,27 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <gtest/gtest.h>
+
+class AllocationTestHarness : public ::testing::Test {
+ protected:
+  virtual void SetUp();
+  virtual void TearDown();
+};
diff --git a/bt/osi/test/alarm_test.cc b/bt/osi/test/alarm_test.cc
new file mode 100644
index 0000000..dd4bbc1
--- /dev/null
+++ b/bt/osi/test/alarm_test.cc
@@ -0,0 +1,453 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "AlarmTestHarness.h"
+
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/osi.h"
+#include "osi/include/semaphore.h"
+#include "osi/include/thread.h"
+
+static semaphore_t* semaphore;
+static int cb_counter;
+static int cb_misordered_counter;
+
+static const uint64_t EPSILON_MS = 50;
+
+static void msleep(uint64_t ms) { usleep(ms * 1000); }
+
+class AlarmTest : public AlarmTestHarness {
+ protected:
+  virtual void SetUp() {
+    AlarmTestHarness::SetUp();
+    cb_counter = 0;
+    cb_misordered_counter = 0;
+
+    semaphore = semaphore_new(0);
+  }
+
+  virtual void TearDown() {
+    semaphore_free(semaphore);
+    AlarmTestHarness::TearDown();
+  }
+};
+
+static void cb(UNUSED_ATTR void* data) {
+  ++cb_counter;
+  semaphore_post(semaphore);
+}
+
+static void ordered_cb(void* data) {
+  int i = PTR_TO_INT(data);
+  if (i != cb_counter) cb_misordered_counter++;
+  ++cb_counter;
+  semaphore_post(semaphore);
+}
+
+TEST_F(AlarmTest, test_new_free_simple) {
+  alarm_t* alarm = alarm_new("alarm_test.test_new_free_simple");
+  ASSERT_TRUE(alarm != NULL);
+  alarm_free(alarm);
+}
+
+TEST_F(AlarmTest, test_free_null) { alarm_free(NULL); }
+
+TEST_F(AlarmTest, test_simple_cancel) {
+  alarm_t* alarm = alarm_new("alarm_test.test_simple_cancel");
+  alarm_cancel(alarm);
+  alarm_free(alarm);
+}
+
+TEST_F(AlarmTest, test_cancel) {
+  alarm_t* alarm = alarm_new("alarm_test.test_cancel");
+  alarm_set(alarm, 10, cb, NULL);
+  alarm_cancel(alarm);
+
+  msleep(10 + EPSILON_MS);
+
+  EXPECT_EQ(cb_counter, 0);
+  EXPECT_FALSE(WakeLockHeld());
+  alarm_free(alarm);
+}
+
+TEST_F(AlarmTest, test_cancel_idempotent) {
+  alarm_t* alarm = alarm_new("alarm_test.test_cancel_idempotent");
+  alarm_set(alarm, 10, cb, NULL);
+  alarm_cancel(alarm);
+  alarm_cancel(alarm);
+  alarm_cancel(alarm);
+  alarm_free(alarm);
+}
+
+TEST_F(AlarmTest, test_set_short) {
+  alarm_t* alarm = alarm_new("alarm_test.test_set_short");
+
+  alarm_set(alarm, 10, cb, NULL);
+
+  EXPECT_EQ(cb_counter, 0);
+  EXPECT_TRUE(WakeLockHeld());
+
+  semaphore_wait(semaphore);
+
+  EXPECT_EQ(cb_counter, 1);
+  EXPECT_FALSE(WakeLockHeld());
+
+  alarm_free(alarm);
+}
+
+TEST_F(AlarmTest, test_set_short_periodic) {
+  alarm_t* alarm = alarm_new_periodic("alarm_test.test_set_short_periodic");
+
+  alarm_set(alarm, 10, cb, NULL);
+
+  EXPECT_EQ(cb_counter, 0);
+  EXPECT_TRUE(WakeLockHeld());
+
+  for (int i = 1; i <= 10; i++) {
+    semaphore_wait(semaphore);
+
+    EXPECT_GE(cb_counter, i);
+    EXPECT_TRUE(WakeLockHeld());
+  }
+  alarm_cancel(alarm);
+  EXPECT_FALSE(WakeLockHeld());
+
+  alarm_free(alarm);
+}
+
+TEST_F(AlarmTest, test_set_zero_periodic) {
+  alarm_t* alarm = alarm_new_periodic("alarm_test.test_set_zero_periodic");
+
+  alarm_set(alarm, 0, cb, NULL);
+
+  EXPECT_TRUE(WakeLockHeld());
+
+  for (int i = 1; i <= 10; i++) {
+    semaphore_wait(semaphore);
+
+    EXPECT_GE(cb_counter, i);
+    EXPECT_TRUE(WakeLockHeld());
+  }
+  alarm_cancel(alarm);
+  EXPECT_FALSE(WakeLockHeld());
+
+  alarm_free(alarm);
+}
+
+TEST_F(AlarmTest, test_set_long) {
+  alarm_t* alarm = alarm_new("alarm_test.test_set_long");
+  alarm_set(alarm, TIMER_INTERVAL_FOR_WAKELOCK_IN_MS + EPSILON_MS, cb, NULL);
+
+  EXPECT_EQ(cb_counter, 0);
+  EXPECT_FALSE(WakeLockHeld());
+
+  semaphore_wait(semaphore);
+
+  EXPECT_EQ(cb_counter, 1);
+  EXPECT_FALSE(WakeLockHeld());
+
+  alarm_free(alarm);
+}
+
+TEST_F(AlarmTest, test_set_short_short) {
+  alarm_t* alarm[2] = {alarm_new("alarm_test.test_set_short_short_0"),
+                       alarm_new("alarm_test.test_set_short_short_1")};
+
+  alarm_set(alarm[0], 10, cb, NULL);
+  alarm_set(alarm[1], 20, cb, NULL);
+
+  EXPECT_EQ(cb_counter, 0);
+  EXPECT_TRUE(WakeLockHeld());
+
+  semaphore_wait(semaphore);
+
+  EXPECT_EQ(cb_counter, 1);
+  EXPECT_TRUE(WakeLockHeld());
+
+  semaphore_wait(semaphore);
+
+  EXPECT_EQ(cb_counter, 2);
+  EXPECT_FALSE(WakeLockHeld());
+
+  alarm_free(alarm[0]);
+  alarm_free(alarm[1]);
+}
+
+TEST_F(AlarmTest, test_set_short_long) {
+  alarm_t* alarm[2] = {alarm_new("alarm_test.test_set_short_long_0"),
+                       alarm_new("alarm_test.test_set_short_long_1")};
+
+  alarm_set(alarm[0], 10, cb, NULL);
+  alarm_set(alarm[1], 10 + TIMER_INTERVAL_FOR_WAKELOCK_IN_MS + EPSILON_MS, cb,
+            NULL);
+
+  EXPECT_EQ(cb_counter, 0);
+  EXPECT_TRUE(WakeLockHeld());
+
+  semaphore_wait(semaphore);
+
+  EXPECT_EQ(cb_counter, 1);
+  EXPECT_FALSE(WakeLockHeld());
+
+  semaphore_wait(semaphore);
+
+  EXPECT_EQ(cb_counter, 2);
+  EXPECT_FALSE(WakeLockHeld());
+
+  alarm_free(alarm[0]);
+  alarm_free(alarm[1]);
+}
+
+TEST_F(AlarmTest, test_set_long_long) {
+  alarm_t* alarm[2] = {alarm_new("alarm_test.test_set_long_long_0"),
+                       alarm_new("alarm_test.test_set_long_long_1")};
+
+  alarm_set(alarm[0], TIMER_INTERVAL_FOR_WAKELOCK_IN_MS + EPSILON_MS, cb, NULL);
+  alarm_set(alarm[1], 2 * (TIMER_INTERVAL_FOR_WAKELOCK_IN_MS + EPSILON_MS), cb,
+            NULL);
+
+  EXPECT_EQ(cb_counter, 0);
+  EXPECT_FALSE(WakeLockHeld());
+
+  semaphore_wait(semaphore);
+
+  EXPECT_EQ(cb_counter, 1);
+  EXPECT_FALSE(WakeLockHeld());
+
+  semaphore_wait(semaphore);
+
+  EXPECT_EQ(cb_counter, 2);
+  EXPECT_FALSE(WakeLockHeld());
+
+  alarm_free(alarm[0]);
+  alarm_free(alarm[1]);
+}
+
+TEST_F(AlarmTest, test_is_scheduled) {
+  alarm_t* alarm = alarm_new("alarm_test.test_is_scheduled");
+
+  EXPECT_FALSE(alarm_is_scheduled((alarm_t*)NULL));
+  EXPECT_FALSE(alarm_is_scheduled(alarm));
+  alarm_set(alarm, TIMER_INTERVAL_FOR_WAKELOCK_IN_MS + EPSILON_MS, cb, NULL);
+  EXPECT_TRUE(alarm_is_scheduled(alarm));
+
+  EXPECT_EQ(cb_counter, 0);
+  EXPECT_FALSE(WakeLockHeld());
+
+  semaphore_wait(semaphore);
+
+  EXPECT_FALSE(alarm_is_scheduled(alarm));
+  EXPECT_EQ(cb_counter, 1);
+  EXPECT_FALSE(WakeLockHeld());
+
+  alarm_free(alarm);
+}
+
+// Test whether the callbacks are invoked in the expected order
+TEST_F(AlarmTest, test_callback_ordering) {
+  alarm_t* alarms[100];
+
+  for (int i = 0; i < 100; i++) {
+    const std::string alarm_name =
+        "alarm_test.test_callback_ordering[" + std::to_string(i) + "]";
+    alarms[i] = alarm_new(alarm_name.c_str());
+  }
+
+  for (int i = 0; i < 100; i++) {
+    alarm_set(alarms[i], 100, ordered_cb, INT_TO_PTR(i));
+  }
+
+  for (int i = 1; i <= 100; i++) {
+    semaphore_wait(semaphore);
+    EXPECT_GE(cb_counter, i);
+  }
+  EXPECT_EQ(cb_counter, 100);
+  EXPECT_EQ(cb_misordered_counter, 0);
+
+  for (int i = 0; i < 100; i++) alarm_free(alarms[i]);
+
+  EXPECT_FALSE(WakeLockHeld());
+}
+
+// Test whether the callbacks are involed in the expected order on a
+// separate queue.
+TEST_F(AlarmTest, test_callback_ordering_on_queue) {
+  alarm_t* alarms[100];
+  fixed_queue_t* queue = fixed_queue_new(SIZE_MAX);
+  thread_t* thread =
+      thread_new("timers.test_callback_ordering_on_queue.thread");
+
+  alarm_register_processing_queue(queue, thread);
+
+  for (int i = 0; i < 100; i++) {
+    const std::string alarm_name =
+        "alarm_test.test_callback_ordering_on_queue[" + std::to_string(i) + "]";
+    alarms[i] = alarm_new(alarm_name.c_str());
+  }
+
+  for (int i = 0; i < 100; i++) {
+    alarm_set_on_queue(alarms[i], 100, ordered_cb, INT_TO_PTR(i), queue);
+  }
+
+  for (int i = 1; i <= 100; i++) {
+    semaphore_wait(semaphore);
+    EXPECT_GE(cb_counter, i);
+  }
+  EXPECT_EQ(cb_counter, 100);
+  EXPECT_EQ(cb_misordered_counter, 0);
+
+  for (int i = 0; i < 100; i++) alarm_free(alarms[i]);
+
+  EXPECT_FALSE(WakeLockHeld());
+
+  alarm_unregister_processing_queue(queue);
+  fixed_queue_free(queue, NULL);
+  thread_free(thread);
+}
+
+// Test whether unregistering a processing queue cancels all timers using
+// that queue.
+TEST_F(AlarmTest, test_unregister_processing_queue) {
+  alarm_t* alarms[100];
+  fixed_queue_t* queue = fixed_queue_new(SIZE_MAX);
+  thread_t* thread =
+      thread_new("timers.test_unregister_processing_queue.thread");
+
+  alarm_register_processing_queue(queue, thread);
+
+  for (int i = 0; i < 100; i++) {
+    const std::string alarm_name =
+        "alarm_test.test_unregister_processing_queue[" + std::to_string(i) +
+        "]";
+    alarms[i] = alarm_new(alarm_name.c_str());
+  }
+
+  // Schedule half of the timers to expire soon, and the rest far in the future
+  for (int i = 0; i < 50; i++) {
+    alarm_set_on_queue(alarms[i], 100, ordered_cb, INT_TO_PTR(i), queue);
+  }
+  for (int i = 50; i < 100; i++) {
+    alarm_set_on_queue(alarms[i], 1000 * 1000, ordered_cb, INT_TO_PTR(i),
+                       queue);
+  }
+
+  // Wait until half of the timers have expired
+  for (int i = 1; i <= 50; i++) {
+    semaphore_wait(semaphore);
+    EXPECT_GE(cb_counter, i);
+  }
+  EXPECT_EQ(cb_counter, 50);
+  EXPECT_EQ(cb_misordered_counter, 0);
+
+  // Test that only the expired timers are not scheduled
+  for (int i = 0; i < 50; i++) {
+    EXPECT_FALSE(alarm_is_scheduled(alarms[i]));
+  }
+  for (int i = 50; i < 100; i++) {
+    EXPECT_TRUE(alarm_is_scheduled(alarms[i]));
+  }
+
+  alarm_unregister_processing_queue(queue);
+
+  // Test that none of the timers are scheduled
+  for (int i = 0; i < 100; i++) {
+    EXPECT_FALSE(alarm_is_scheduled(alarms[i]));
+  }
+
+  for (int i = 0; i < 100; i++) {
+    alarm_free(alarms[i]);
+  }
+
+  EXPECT_FALSE(WakeLockHeld());
+
+  fixed_queue_free(queue, NULL);
+  thread_free(thread);
+}
+
+// Test whether unregistering a processing queue cancels all periodic timers
+// using that queue.
+TEST_F(AlarmTest, test_periodic_unregister_processing_queue) {
+  alarm_t* alarms[5];
+  fixed_queue_t* queue = fixed_queue_new(SIZE_MAX);
+  thread_t* thread =
+      thread_new("timers.test_periodic_unregister_processing_queue.thread");
+
+  alarm_register_processing_queue(queue, thread);
+
+  for (int i = 0; i < 5; i++) {
+    const std::string alarm_name =
+        "alarm_test.test_periodic_unregister_processing_queue[" +
+        std::to_string(i) + "]";
+    alarms[i] = alarm_new_periodic(alarm_name.c_str());
+  }
+
+  // Schedule each of the timers with different period
+  for (int i = 0; i < 5; i++) {
+    alarm_set_on_queue(alarms[i], 20 + i, cb, INT_TO_PTR(i), queue);
+  }
+  EXPECT_TRUE(WakeLockHeld());
+
+  for (int i = 1; i <= 20; i++) {
+    semaphore_wait(semaphore);
+
+    EXPECT_GE(cb_counter, i);
+    EXPECT_TRUE(WakeLockHeld());
+  }
+
+  // Test that all timers are still scheduled
+  for (int i = 0; i < 5; i++) {
+    EXPECT_TRUE(alarm_is_scheduled(alarms[i]));
+  }
+
+  alarm_unregister_processing_queue(queue);
+
+  int saved_cb_counter = cb_counter;
+
+  // Test that none of the timers are scheduled
+  for (int i = 0; i < 5; i++) {
+    EXPECT_FALSE(alarm_is_scheduled(alarms[i]));
+  }
+
+  // Sleep for 500ms and test again that the cb_counter hasn't been modified
+  usleep(500 * 1000);
+  EXPECT_TRUE(cb_counter == saved_cb_counter);
+
+  for (int i = 0; i < 5; i++) {
+    alarm_free(alarms[i]);
+  }
+
+  EXPECT_FALSE(WakeLockHeld());
+
+  fixed_queue_free(queue, NULL);
+  thread_free(thread);
+}
+
+// Try to catch any race conditions between the timer callback and |alarm_free|.
+TEST_F(AlarmTest, test_callback_free_race) {
+  for (int i = 0; i < 1000; ++i) {
+    const std::string alarm_name =
+        "alarm_test.test_callback_free_race[" + std::to_string(i) + "]";
+    alarm_t* alarm = alarm_new(alarm_name.c_str());
+    alarm_set(alarm, 0, cb, NULL);
+    alarm_free(alarm);
+  }
+  alarm_cleanup();
+}
diff --git a/bt/osi/test/allocation_tracker_test.cc b/bt/osi/test/allocation_tracker_test.cc
new file mode 100644
index 0000000..cf979cb
--- /dev/null
+++ b/bt/osi/test/allocation_tracker_test.cc
@@ -0,0 +1,64 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "osi/include/allocation_tracker.h"
+
+void allocation_tracker_uninit(void);
+
+static const allocator_id_t allocator_id = 5;
+
+TEST(AllocationTrackerTest, test_uninit_no_bad_effects) {
+  void* dummy_allocation = malloc(4);
+
+  // Ensure uninitialized state (previous tests may have called init)
+  allocation_tracker_uninit();
+
+  EXPECT_EQ(4U, allocation_tracker_resize_for_canary(4));
+  allocation_tracker_notify_alloc(allocator_id, dummy_allocation, 4);
+  EXPECT_EQ(0U, allocation_tracker_expect_no_allocations());  // should not have
+                                                              // registered an
+                                                              // allocation
+  allocation_tracker_notify_free(allocator_id, dummy_allocation);
+  EXPECT_EQ(0U, allocation_tracker_expect_no_allocations());
+
+  free(dummy_allocation);
+}
+
+TEST(AllocationTrackerTest, test_canaries_on) {
+  allocation_tracker_uninit();
+  allocation_tracker_init();
+
+  size_t with_canary_size = allocation_tracker_resize_for_canary(4);
+  EXPECT_TRUE(with_canary_size > 4);
+
+  void* dummy_allocation = malloc(with_canary_size);
+  void* useable_ptr =
+      allocation_tracker_notify_alloc(allocator_id, dummy_allocation, 4);
+  EXPECT_TRUE(useable_ptr > dummy_allocation);
+  EXPECT_EQ(4U, allocation_tracker_expect_no_allocations());  // should have
+                                                              // registered the
+                                                              // allocation
+  void* freeable_ptr =
+      allocation_tracker_notify_free(allocator_id, useable_ptr);
+  EXPECT_EQ(dummy_allocation, freeable_ptr);
+  EXPECT_EQ(0U, allocation_tracker_expect_no_allocations());
+
+  free(dummy_allocation);
+}
diff --git a/bt/osi/test/allocator_test.cc b/bt/osi/test/allocator_test.cc
new file mode 100644
index 0000000..9dc6302
--- /dev/null
+++ b/bt/osi/test/allocator_test.cc
@@ -0,0 +1,52 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <gtest/gtest.h>
+
+#include "AllocationTestHarness.h"
+
+#include "osi/include/allocator.h"
+
+class AllocatorTest : public AllocationTestHarness {};
+
+TEST_F(AllocatorTest, test_osi_strndup) {
+  char str[] = "IloveBluetooth";
+  size_t len = strlen(str);
+  char* copy_str = NULL;
+
+  // len == 0
+  copy_str = osi_strndup(str, 0);
+  EXPECT_EQ(0, strcmp(copy_str, ""));
+  osi_free(copy_str);
+
+  // len == strlen(str)
+  copy_str = osi_strndup(str, len);
+  EXPECT_EQ(0, strcmp(str, copy_str));
+  osi_free(copy_str);
+
+  // len < strlen(str)
+  copy_str = osi_strndup(str, len - 5);
+  EXPECT_EQ(0, strcmp("IloveBlue", copy_str));
+  osi_free(copy_str);
+
+  // len > strlen(str)
+  copy_str = osi_strndup(str, len + 5);
+  EXPECT_EQ(0, strcmp(str, copy_str));
+  osi_free(copy_str);
+}
diff --git a/bt/osi/test/array_test.cc b/bt/osi/test/array_test.cc
new file mode 100644
index 0000000..2addadc
--- /dev/null
+++ b/bt/osi/test/array_test.cc
@@ -0,0 +1,67 @@
+#include <gtest/gtest.h>
+
+#include "AllocationTestHarness.h"
+
+#include "osi/include/array.h"
+
+class ArrayTest : public AllocationTestHarness {};
+
+TEST_F(ArrayTest, test_new_free_simple) {
+  array_t* array = array_new(4);
+  ASSERT_TRUE(array != NULL);
+  array_free(array);
+}
+
+TEST_F(ArrayTest, test_free_null) { array_free(NULL); }
+
+TEST_F(ArrayTest, test_invalid_ptr) {
+  array_t* array = array_new(4);
+  EXPECT_DEATH(array_ptr(array), "");
+  array_free(array);
+}
+
+TEST_F(ArrayTest, test_invalid_at) {
+  array_t* array = array_new(4);
+  EXPECT_DEATH(array_at(array, 1), "");
+  array_free(array);
+}
+
+TEST_F(ArrayTest, test_append_value) {
+  array_t* array = array_new(sizeof(int));
+  for (int i = 0; i < 100; ++i) {
+    array_append_value(array, i * i);
+  }
+  for (int i = 0; i < 100; ++i) {
+    EXPECT_EQ(*(int*)array_at(array, i), i * i);
+  }
+  array_free(array);
+}
+
+TEST_F(ArrayTest, test_append_ptr) {
+  int items[100];
+  array_t* array = array_new(sizeof(int));
+  for (int i = 0; i < 100; ++i) {
+    items[i] = i * i;
+    array_append_ptr(array, &items[i]);
+  }
+  for (int i = 0; i < 100; ++i) {
+    EXPECT_EQ(*(int*)array_at(array, i), i * i);
+  }
+  array_free(array);
+}
+
+TEST_F(ArrayTest, test_large_element) {
+  char strings[][128] = {
+      "string 1", "string 2", "string 3", "string 4",
+      "string 5", "string 6", "string 7", "string 8",
+  };
+
+  array_t* array = array_new(128);
+  for (int i = 0; i < 100; ++i) {
+    array_append_ptr(array, strings[i % 8]);
+  }
+  for (int i = 0; i < 100; ++i) {
+    EXPECT_TRUE(!memcmp(array_at(array, i), strings[i % 8], 128));
+  }
+  array_free(array);
+}
diff --git a/bt/osi/test/config_test.cc b/bt/osi/test/config_test.cc
new file mode 100644
index 0000000..6712222
--- /dev/null
+++ b/bt/osi/test/config_test.cc
@@ -0,0 +1,202 @@
+#include <gtest/gtest.h>
+
+#include "AllocationTestHarness.h"
+
+#include "osi/include/config.h"
+
+static const char CONFIG_FILE[] = "/data/local/tmp/config_test.conf";
+static const char CONFIG_FILE_CONTENT[] =
+    "                                                                                    \n\
+first_key=value                                                                      \n\
+                                                                                     \n\
+# Device ID (DID) configuration                                                      \n\
+[DID]                                                                                \n\
+                                                                                     \n\
+# Record Number: 1, 2 or 3 - maximum of 3 records                                    \n\
+recordNumber = 1                                                                     \n\
+                                                                                     \n\
+# Primary Record - true or false (default)                                           \n\
+# There can be only one primary record                                               \n\
+primaryRecord = true                                                                 \n\
+                                                                                     \n\
+# Vendor ID '0xFFFF' indicates no Device ID Service Record is present in the device  \n\
+# 0x000F = Broadcom Corporation (default)                                            \n\
+#vendorId = 0x000F                                                                   \n\
+                                                                                     \n\
+# Vendor ID Source                                                                   \n\
+# 0x0001 = Bluetooth SIG assigned Device ID Vendor ID value (default)                \n\
+# 0x0002 = USB Implementer's Forum assigned Device ID Vendor ID value                \n\
+#vendorIdSource = 0x0001                                                             \n\
+                                                                                     \n\
+# Product ID & Product Version                                                       \n\
+# Per spec DID v1.3 0xJJMN for version is interpreted as JJ.M.N                      \n\
+# JJ: major version number, M: minor version number, N: sub-minor version number     \n\
+# For example: 1200, v14.3.6                                                         \n\
+productId = 0x1200                                                                   \n\
+version = 0x1111                                                                     \n\
+                                                                                     \n\
+# Optional attributes                                                                \n\
+#clientExecutableURL =                                                               \n\
+#serviceDescription =                                                                \n\
+#documentationURL =                                                                  \n\
+                                                                                     \n\
+# Additional optional DID records. Bluedroid supports up to 3 records.               \n\
+[DID]                                                                                \n\
+[DID]                                                                                \n\
+version = 0x1436                                                                     \n\
+";
+
+class ConfigTest : public AllocationTestHarness {
+ protected:
+  virtual void SetUp() {
+    AllocationTestHarness::SetUp();
+    FILE* fp = fopen(CONFIG_FILE, "wt");
+    fwrite(CONFIG_FILE_CONTENT, 1, sizeof(CONFIG_FILE_CONTENT), fp);
+    fclose(fp);
+  }
+};
+
+TEST_F(ConfigTest, config_new_empty) {
+  config_t* config = config_new_empty();
+  EXPECT_TRUE(config != NULL);
+  config_free(config);
+}
+
+TEST_F(ConfigTest, config_new_no_file) {
+  config_t* config = config_new("/meow");
+  EXPECT_TRUE(config == NULL);
+  config_free(config);
+}
+
+TEST_F(ConfigTest, config_new) {
+  config_t* config = config_new(CONFIG_FILE);
+  EXPECT_TRUE(config != NULL);
+  config_free(config);
+}
+
+TEST_F(ConfigTest, config_free_null) { config_free(NULL); }
+
+TEST_F(ConfigTest, config_new_clone) {
+  config_t* config = config_new(CONFIG_FILE);
+  config_t* clone = config_new_clone(config);
+
+  config_set_string(clone, CONFIG_DEFAULT_SECTION, "first_key", "not_value");
+
+  EXPECT_STRNE(
+      config_get_string(config, CONFIG_DEFAULT_SECTION, "first_key", "one"),
+      config_get_string(clone, CONFIG_DEFAULT_SECTION, "first_key", "one"));
+
+  config_free(config);
+  config_free(clone);
+}
+
+TEST_F(ConfigTest, config_has_section) {
+  config_t* config = config_new(CONFIG_FILE);
+  EXPECT_TRUE(config_has_section(config, "DID"));
+  config_free(config);
+}
+
+TEST_F(ConfigTest, config_has_key_in_default_section) {
+  config_t* config = config_new(CONFIG_FILE);
+  EXPECT_TRUE(config_has_key(config, CONFIG_DEFAULT_SECTION, "first_key"));
+  EXPECT_STREQ(
+      config_get_string(config, CONFIG_DEFAULT_SECTION, "first_key", "meow"),
+      "value");
+  config_free(config);
+}
+
+TEST_F(ConfigTest, config_has_keys) {
+  config_t* config = config_new(CONFIG_FILE);
+  EXPECT_TRUE(config_has_key(config, "DID", "recordNumber"));
+  EXPECT_TRUE(config_has_key(config, "DID", "primaryRecord"));
+  EXPECT_TRUE(config_has_key(config, "DID", "productId"));
+  EXPECT_TRUE(config_has_key(config, "DID", "version"));
+  config_free(config);
+}
+
+TEST_F(ConfigTest, config_no_bad_keys) {
+  config_t* config = config_new(CONFIG_FILE);
+  EXPECT_FALSE(config_has_key(config, "DID_BAD", "primaryRecord"));
+  EXPECT_FALSE(config_has_key(config, "DID", "primaryRecord_BAD"));
+  EXPECT_FALSE(config_has_key(config, CONFIG_DEFAULT_SECTION, "primaryRecord"));
+  config_free(config);
+}
+
+TEST_F(ConfigTest, config_get_int_version) {
+  config_t* config = config_new(CONFIG_FILE);
+  EXPECT_EQ(config_get_int(config, "DID", "version", 0), 0x1436);
+  config_free(config);
+}
+
+TEST_F(ConfigTest, config_get_int_default) {
+  config_t* config = config_new(CONFIG_FILE);
+  EXPECT_EQ(config_get_int(config, "DID", "primaryRecord", 123), 123);
+  config_free(config);
+}
+
+TEST_F(ConfigTest, config_remove_section) {
+  config_t* config = config_new(CONFIG_FILE);
+  EXPECT_TRUE(config_remove_section(config, "DID"));
+  EXPECT_FALSE(config_has_section(config, "DID"));
+  EXPECT_FALSE(config_has_key(config, "DID", "productId"));
+  config_free(config);
+}
+
+TEST_F(ConfigTest, config_remove_section_missing) {
+  config_t* config = config_new(CONFIG_FILE);
+  EXPECT_FALSE(config_remove_section(config, "not a section"));
+  config_free(config);
+}
+
+TEST_F(ConfigTest, config_remove_key) {
+  config_t* config = config_new(CONFIG_FILE);
+  EXPECT_EQ(config_get_int(config, "DID", "productId", 999), 0x1200);
+  EXPECT_TRUE(config_remove_key(config, "DID", "productId"));
+  EXPECT_FALSE(config_has_key(config, "DID", "productId"));
+  config_free(config);
+}
+
+TEST_F(ConfigTest, config_remove_key_missing) {
+  config_t* config = config_new(CONFIG_FILE);
+  EXPECT_EQ(config_get_int(config, "DID", "productId", 999), 0x1200);
+  EXPECT_TRUE(config_remove_key(config, "DID", "productId"));
+  EXPECT_EQ(config_get_int(config, "DID", "productId", 999), 999);
+  config_free(config);
+}
+
+TEST_F(ConfigTest, config_section_begin) {
+  config_t* config = config_new(CONFIG_FILE);
+  const config_section_node_t* section = config_section_begin(config);
+  EXPECT_TRUE(section != NULL);
+  const char* section_name = config_section_name(section);
+  EXPECT_TRUE(section != NULL);
+  EXPECT_TRUE(!strcmp(section_name, CONFIG_DEFAULT_SECTION));
+  config_free(config);
+}
+
+TEST_F(ConfigTest, config_section_next) {
+  config_t* config = config_new(CONFIG_FILE);
+  const config_section_node_t* section = config_section_begin(config);
+  EXPECT_TRUE(section != NULL);
+  section = config_section_next(section);
+  EXPECT_TRUE(section != NULL);
+  const char* section_name = config_section_name(section);
+  EXPECT_TRUE(section != NULL);
+  EXPECT_TRUE(!strcmp(section_name, "DID"));
+  config_free(config);
+}
+
+TEST_F(ConfigTest, config_section_end) {
+  config_t* config = config_new(CONFIG_FILE);
+  const config_section_node_t* section = config_section_begin(config);
+  section = config_section_next(section);
+  section = config_section_next(section);
+  EXPECT_EQ(section, config_section_end(config));
+  config_free(config);
+}
+
+TEST_F(ConfigTest, config_save_basic) {
+  config_t* config = config_new(CONFIG_FILE);
+  EXPECT_TRUE(config_save(config, CONFIG_FILE));
+  config_free(config);
+}
diff --git a/bt/osi/test/data_dispatcher_test.cc b/bt/osi/test/data_dispatcher_test.cc
new file mode 100644
index 0000000..cc7d78d
--- /dev/null
+++ b/bt/osi/test/data_dispatcher_test.cc
@@ -0,0 +1,258 @@
+#include <gtest/gtest.h>
+
+#include <climits>
+
+#include "AllocationTestHarness.h"
+
+#include "osi/include/data_dispatcher.h"
+
+#include "osi/include/fixed_queue.h"
+#include "osi/include/osi.h"
+
+#define DUMMY_TYPE_0 34
+#define DUMMY_TYPE_1 42
+#define TYPE_EDGE_CASE_ZERO 0
+#define TYPE_EDGE_CASE_MAX INT_MAX
+
+#define DUMMY_QUEUE_SIZE 10
+
+class DataDispatcherTest : public AllocationTestHarness {};
+
+static char dummy_data_0[42] = "please test your code";
+static char dummy_data_1[42] = "testing is good for your sanity";
+
+TEST_F(DataDispatcherTest, test_new_free_simple) {
+  data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+  ASSERT_TRUE(dispatcher != NULL);
+  data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_single_to_nowhere) {
+  data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+  EXPECT_FALSE(
+      data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
+  data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_single_to_single) {
+  data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+
+  // Register a queue
+  fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
+  data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue);
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+  // Send data to the queue
+  EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
+
+  // Did we get it?
+  EXPECT_FALSE(fixed_queue_is_empty(dummy_queue));
+  EXPECT_STREQ(dummy_data_0, (char*)fixed_queue_try_dequeue(dummy_queue));
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+  fixed_queue_free(dummy_queue, NULL);
+  data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_single_to_multiple) {
+  data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+
+  // Register two queues
+  fixed_queue_t* dummy_queue0 = fixed_queue_new(DUMMY_QUEUE_SIZE);
+  fixed_queue_t* dummy_queue1 = fixed_queue_new(DUMMY_QUEUE_SIZE);
+  data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue0);
+  data_dispatcher_register(dispatcher, DUMMY_TYPE_1, dummy_queue1);
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue0));
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue1));
+
+  // Send data to one of them
+  EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
+
+  // Did we get it?
+  EXPECT_FALSE(fixed_queue_is_empty(dummy_queue0));
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue1));
+  EXPECT_STREQ(dummy_data_0, (char*)fixed_queue_try_dequeue(dummy_queue0));
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue0));
+
+  fixed_queue_free(dummy_queue0, NULL);
+  fixed_queue_free(dummy_queue1, NULL);
+  data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_single_to_default) {
+  data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+
+  // Register two queues, a default and a typed one
+  fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
+  fixed_queue_t* default_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
+  data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue);
+  data_dispatcher_register_default(dispatcher, default_queue);
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+  EXPECT_TRUE(fixed_queue_is_empty(default_queue));
+
+  // Send data to nowhere
+  EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_1, dummy_data_1));
+
+  // Did we get it?
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+  EXPECT_FALSE(fixed_queue_is_empty(default_queue));
+  EXPECT_STREQ(dummy_data_1, (char*)fixed_queue_try_dequeue(default_queue));
+  EXPECT_TRUE(fixed_queue_is_empty(default_queue));
+
+  fixed_queue_free(dummy_queue, NULL);
+  fixed_queue_free(default_queue, NULL);
+  data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_multiple_to_single) {
+  data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+
+  // Register a queue
+  fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
+  data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue);
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+  // Send data to the queue
+  EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
+  EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_1));
+
+  // Did we get it?
+  EXPECT_FALSE(fixed_queue_is_empty(dummy_queue));
+  EXPECT_STREQ(dummy_data_0, (char*)fixed_queue_try_dequeue(dummy_queue));
+  EXPECT_FALSE(fixed_queue_is_empty(dummy_queue));
+  EXPECT_STREQ(dummy_data_1, (char*)fixed_queue_try_dequeue(dummy_queue));
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+  fixed_queue_free(dummy_queue, NULL);
+  data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_multiple_to_multiple) {
+  data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+
+  // Register two queues
+  fixed_queue_t* dummy_queue0 = fixed_queue_new(DUMMY_QUEUE_SIZE);
+  fixed_queue_t* dummy_queue1 = fixed_queue_new(DUMMY_QUEUE_SIZE);
+  data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue0);
+  data_dispatcher_register(dispatcher, DUMMY_TYPE_1, dummy_queue1);
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue0));
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue1));
+
+  // Send data to both of them
+  EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
+  EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_1, dummy_data_1));
+
+  // Did we get it?
+  EXPECT_FALSE(fixed_queue_is_empty(dummy_queue0));
+  EXPECT_FALSE(fixed_queue_is_empty(dummy_queue1));
+  EXPECT_STREQ(dummy_data_0, (char*)fixed_queue_try_dequeue(dummy_queue0));
+  EXPECT_STREQ(dummy_data_1, (char*)fixed_queue_try_dequeue(dummy_queue1));
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue0));
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue1));
+
+  fixed_queue_free(dummy_queue0, NULL);
+  fixed_queue_free(dummy_queue1, NULL);
+  data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_single_to_single_reregistered) {
+  data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+
+  // Register a queue, then reregister
+  fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
+  fixed_queue_t* dummy_queue_reregistered = fixed_queue_new(DUMMY_QUEUE_SIZE);
+  data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue);
+  data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue_reregistered);
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue_reregistered));
+
+  // Send data to the queue
+  EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
+
+  // Did we get it?
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+  EXPECT_FALSE(fixed_queue_is_empty(dummy_queue_reregistered));
+  EXPECT_STREQ(dummy_data_0,
+               (char*)fixed_queue_try_dequeue(dummy_queue_reregistered));
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue_reregistered));
+
+  fixed_queue_free(dummy_queue, NULL);
+  fixed_queue_free(dummy_queue_reregistered, NULL);
+  data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_single_to_reregistered_null) {
+  data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+
+  // Register a queue
+  fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
+  data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue);
+  data_dispatcher_register(dispatcher, DUMMY_TYPE_0, NULL);
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+  EXPECT_FALSE(
+      data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+  fixed_queue_free(dummy_queue, NULL);
+  data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_single_to_default_reregistered_null) {
+  data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+
+  // Register a queue
+  fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
+  data_dispatcher_register_default(dispatcher, dummy_queue);
+  data_dispatcher_register_default(dispatcher, NULL);
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+  EXPECT_FALSE(
+      data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+  fixed_queue_free(dummy_queue, NULL);
+  data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_edge_zero) {
+  data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+
+  // Register a queue
+  fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
+  data_dispatcher_register(dispatcher, TYPE_EDGE_CASE_ZERO, dummy_queue);
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+  // Send data to the queue
+  EXPECT_TRUE(
+      data_dispatcher_dispatch(dispatcher, TYPE_EDGE_CASE_ZERO, dummy_data_0));
+
+  // Did we get it?
+  EXPECT_FALSE(fixed_queue_is_empty(dummy_queue));
+  EXPECT_STREQ(dummy_data_0, (char*)fixed_queue_try_dequeue(dummy_queue));
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+  fixed_queue_free(dummy_queue, NULL);
+  data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_edge_max) {
+  data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+
+  // Register a queue
+  fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
+  data_dispatcher_register(dispatcher, TYPE_EDGE_CASE_MAX, dummy_queue);
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+  // Send data to the queue
+  EXPECT_TRUE(
+      data_dispatcher_dispatch(dispatcher, TYPE_EDGE_CASE_MAX, dummy_data_0));
+
+  // Did we get it?
+  EXPECT_FALSE(fixed_queue_is_empty(dummy_queue));
+  EXPECT_STREQ(dummy_data_0, (char*)fixed_queue_try_dequeue(dummy_queue));
+  EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+  fixed_queue_free(dummy_queue, NULL);
+  data_dispatcher_free(dispatcher);
+}
diff --git a/bt/osi/test/eager_reader_test.cc b/bt/osi/test/eager_reader_test.cc
new file mode 100644
index 0000000..58f1bb4
--- /dev/null
+++ b/bt/osi/test/eager_reader_test.cc
@@ -0,0 +1,152 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "AllocationTestHarness.h"
+
+#include <stdint.h>
+#include <unistd.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/eager_reader.h"
+#include "osi/include/osi.h"
+#include "osi/include/semaphore.h"
+#include "osi/include/thread.h"
+
+#define BUFFER_SIZE 32
+
+static const char* small_data = "white chocolate lindor truffles";
+static const char* large_data =
+    "Let him make him examine and thoroughly sift everything he reads, and "
+    "lodge nothing in his fancy upon simple authority and upon trust. "
+    "Aristotle's principles will then be no more principles to him, than those "
+    "of Epicurus and the Stoics: let this diversity of opinions be propounded "
+    "to, and laid before him; he will himself choose, if he be able; if not, "
+    "he will remain in doubt. "
+    ""
+    "   \"Che non men the saver, dubbiar m' aggrata.\" "
+    "   [\"I love to doubt, as well as to know.\"--Dante, Inferno, xi. 93] "
+    ""
+    "for, if he embrace the opinions of Xenophon and Plato, by his own reason, "
+    "they will no more be theirs, but become his own.  Who follows another, "
+    "follows nothing, finds nothing, nay, is inquisitive after nothing. "
+    ""
+    "   \"Non sumus sub rege; sibi quisque se vindicet.\" "
+    "   [\"We are under no king; let each vindicate himself.\" --Seneca, "
+    "Ep.,33] "
+    ""
+    "let him, at least, know that he knows.  it will be necessary that he "
+    "imbibe their knowledge, not that he be corrupted with their precepts; "
+    "and no matter if he forget where he had his learning, provided he know "
+    "how to apply it to his own use.  truth and reason are common to every "
+    "one, and are no more his who spake them first, than his who speaks them "
+    "after: 'tis no more according to plato, than according to me, since both "
+    "he and i equally see and understand them.  bees cull their several sweets "
+    "from this flower and that blossom, here and there where they find them, "
+    "but themselves afterwards make the honey, which is all and purely their "
+    "own, and no more thyme and marjoram: so the several fragments he borrows "
+    "from others, he will transform and shuffle together to compile a work "
+    "that shall be absolutely his own; that is to say, his judgment: "
+    "his instruction, labour and study, tend to nothing else but to form "
+    "that. ";
+
+static semaphore_t* done;
+
+class EagerReaderTest : public AllocationTestHarness {
+ protected:
+  virtual void SetUp() {
+    AllocationTestHarness::SetUp();
+    pipe(pipefd);
+    done = semaphore_new(0);
+  }
+
+  virtual void TearDown() {
+    semaphore_free(done);
+    AllocationTestHarness::TearDown();
+  }
+
+  int pipefd[2];
+};
+
+static void expect_data(eager_reader_t* reader, void* context) {
+  char* data = (char*)context;
+  int length = strlen(data);
+
+  for (int i = 0; i < length; i++) {
+    uint8_t byte;
+    EXPECT_EQ((size_t)1, eager_reader_read(reader, &byte, 1));
+    EXPECT_EQ(data[i], byte);
+  }
+
+  semaphore_post(done);
+}
+
+static void expect_data_multibyte(eager_reader_t* reader, void* context) {
+  char* data = (char*)context;
+  size_t length = strlen(data);
+
+  for (size_t i = 0; i < length;) {
+    uint8_t buffer[28];
+    size_t bytes_to_read = (length - i) > 28 ? 28 : (length - i);
+    size_t bytes_read = eager_reader_read(reader, buffer, bytes_to_read);
+    EXPECT_LE(bytes_read, bytes_to_read);
+    for (size_t j = 0; j < bytes_read && i < length; j++, i++) {
+      EXPECT_EQ(data[i], buffer[j]);
+    }
+  }
+
+  semaphore_post(done);
+}
+
+TEST_F(EagerReaderTest, test_new_free_simple) {
+  eager_reader_t* reader = eager_reader_new(
+      pipefd[0], &allocator_malloc, BUFFER_SIZE, SIZE_MAX, "test_thread");
+  ASSERT_TRUE(reader != NULL);
+  eager_reader_free(reader);
+}
+
+TEST_F(EagerReaderTest, test_small_data) {
+  eager_reader_t* reader = eager_reader_new(
+      pipefd[0], &allocator_malloc, BUFFER_SIZE, SIZE_MAX, "test_thread");
+
+  thread_t* read_thread = thread_new("read_thread");
+  eager_reader_register(reader, thread_get_reactor(read_thread), expect_data,
+                        (void*)small_data);
+
+  write(pipefd[1], small_data, strlen(small_data));
+
+  semaphore_wait(done);
+  eager_reader_free(reader);
+  thread_free(read_thread);
+}
+
+TEST_F(EagerReaderTest, test_large_data_multibyte) {
+  eager_reader_t* reader = eager_reader_new(
+      pipefd[0], &allocator_malloc, BUFFER_SIZE, SIZE_MAX, "test_thread");
+
+  thread_t* read_thread = thread_new("read_thread");
+  eager_reader_register(reader, thread_get_reactor(read_thread),
+                        expect_data_multibyte, (void*)large_data);
+
+  write(pipefd[1], large_data, strlen(large_data));
+
+  semaphore_wait(done);
+  eager_reader_free(reader);
+  thread_free(read_thread);
+}
diff --git a/bt/osi/test/fixed_queue_test.cc b/bt/osi/test/fixed_queue_test.cc
new file mode 100644
index 0000000..56917ef
--- /dev/null
+++ b/bt/osi/test/fixed_queue_test.cc
@@ -0,0 +1,350 @@
+#include <gtest/gtest.h>
+
+#include <climits>
+
+#include "AllocationTestHarness.h"
+
+#include "osi/include/allocator.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/future.h"
+#include "osi/include/osi.h"
+#include "osi/include/thread.h"
+
+static const size_t TEST_QUEUE_SIZE = 10;
+static const char* DUMMY_DATA_STRING = "Dummy data string";
+static const char* DUMMY_DATA_STRING1 = "Dummy data string1";
+static const char* DUMMY_DATA_STRING2 = "Dummy data string2";
+static const char* DUMMY_DATA_STRING3 = "Dummy data string3";
+static future_t* received_message_future = NULL;
+
+static int test_queue_entry_free_counter = 0;
+
+// Test whether a file descriptor |fd| is readable.
+// Return true if the file descriptor is readable, otherwise false.
+static bool is_fd_readable(int fd) {
+  fd_set rfds;
+  struct timeval tv;
+
+  FD_ZERO(&rfds);
+  tv.tv_sec = 0;
+  tv.tv_usec = 0;
+  FD_SET(fd, &rfds);
+  // Only the enqueue_fd should be readable
+  int result = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);
+  EXPECT_TRUE(result >= 0);
+
+  return FD_ISSET(fd, &rfds);
+}
+
+// Function for performing dequeue operations from the queue when is ready
+static void fixed_queue_ready(fixed_queue_t* queue, UNUSED_ATTR void* context) {
+  void* msg = fixed_queue_try_dequeue(queue);
+  EXPECT_TRUE(msg != NULL);
+  future_ready(received_message_future, msg);
+}
+
+static void test_queue_entry_free_cb(void* data) {
+  // Don't free the data, because we are testing only whether the callback
+  // is called.
+  test_queue_entry_free_counter++;
+}
+
+class FixedQueueTest : public AllocationTestHarness {};
+
+TEST_F(FixedQueueTest, test_fixed_queue_new_free) {
+  fixed_queue_t* queue;
+
+  // Test a corner case: queue of size 0
+  queue = fixed_queue_new(0);
+  EXPECT_TRUE(queue != NULL);
+  fixed_queue_free(queue, NULL);
+
+  // Test a corner case: queue of size 1
+  queue = fixed_queue_new(1);
+  EXPECT_TRUE(queue != NULL);
+  fixed_queue_free(queue, NULL);
+
+  // Test a corner case: queue of maximum size
+  queue = fixed_queue_new((size_t)-1);
+  EXPECT_TRUE(queue != NULL);
+  fixed_queue_free(queue, NULL);
+
+  // Test a queue of some size
+  queue = fixed_queue_new(TEST_QUEUE_SIZE);
+  EXPECT_TRUE(queue != NULL);
+  fixed_queue_free(queue, NULL);
+
+  // Test free-ing a NULL queue
+  fixed_queue_free(NULL, NULL);
+  fixed_queue_free(NULL, osi_free);
+}
+
+TEST_F(FixedQueueTest, test_fixed_queue_flush) {
+  fixed_queue_t* queue;
+
+  // Test a corner case: queue of size 0 and no callback to free entries
+  queue = fixed_queue_new(0);
+  EXPECT_TRUE(queue != NULL);
+  fixed_queue_flush(queue, NULL);
+  EXPECT_TRUE(fixed_queue_is_empty(queue));
+  fixed_queue_free(queue, osi_free);
+
+  // Test a corner case: queue of size 0 and a callback to free entries
+  queue = fixed_queue_new(0);
+  EXPECT_TRUE(queue != NULL);
+  fixed_queue_flush(queue, osi_free);
+  EXPECT_TRUE(fixed_queue_is_empty(queue));
+  fixed_queue_free(queue, osi_free);
+
+  // Test a queue of some size and no callback to free entries
+  queue = fixed_queue_new(TEST_QUEUE_SIZE);
+  EXPECT_TRUE(queue != NULL);
+  fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING1);
+  fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING2);
+  fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING3);
+  EXPECT_FALSE(fixed_queue_is_empty(queue));
+  fixed_queue_flush(queue, NULL);
+  EXPECT_TRUE(fixed_queue_is_empty(queue));
+  fixed_queue_free(queue, osi_free);
+
+  // Test a queue of some size and a callback to free entries
+  test_queue_entry_free_counter = 0;
+  queue = fixed_queue_new(TEST_QUEUE_SIZE);
+  EXPECT_TRUE(queue != NULL);
+  fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING1);
+  fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING2);
+  fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING3);
+  EXPECT_FALSE(fixed_queue_is_empty(queue));
+  fixed_queue_flush(queue, test_queue_entry_free_cb);
+  EXPECT_TRUE(test_queue_entry_free_counter == 3);
+  EXPECT_TRUE(fixed_queue_is_empty(queue));
+  fixed_queue_free(queue, osi_free);
+}
+
+TEST_F(FixedQueueTest, test_fixed_queue_is_empty) {
+  fixed_queue_t* queue;
+
+  // Test a NULL queue
+  EXPECT_TRUE(fixed_queue_is_empty(NULL));
+
+  // Test an empty queue
+  queue = fixed_queue_new(TEST_QUEUE_SIZE);
+  ASSERT_TRUE(queue != NULL);
+  EXPECT_TRUE(fixed_queue_is_empty(queue));
+
+  // Test a non-empty queue
+  fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING);
+  EXPECT_FALSE(fixed_queue_is_empty(queue));
+
+  // Test an empty dequeued queue
+  ASSERT_EQ(DUMMY_DATA_STRING, fixed_queue_try_dequeue(queue));
+  EXPECT_TRUE(fixed_queue_is_empty(queue));
+
+  fixed_queue_free(queue, NULL);
+}
+
+TEST_F(FixedQueueTest, test_fixed_queue_length) {
+  fixed_queue_t* queue;
+
+  // Test a NULL queue
+  EXPECT_EQ((size_t)0, fixed_queue_length(NULL));
+
+  // Test an empty queue
+  queue = fixed_queue_new(TEST_QUEUE_SIZE);
+  ASSERT_TRUE(queue != NULL);
+  EXPECT_EQ((size_t)0, fixed_queue_length(queue));
+
+  // Test a non-empty queue
+  fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING);
+  EXPECT_EQ((size_t)1, fixed_queue_length(queue));
+
+  // Test an empty dequeued queue
+  ASSERT_EQ(DUMMY_DATA_STRING, fixed_queue_try_dequeue(queue));
+  EXPECT_EQ((size_t)0, fixed_queue_length(queue));
+
+  fixed_queue_free(queue, NULL);
+}
+
+TEST_F(FixedQueueTest, test_fixed_queue_capacity) {
+  fixed_queue_t* queue;
+
+  // Test a corner case: queue of size 0
+  queue = fixed_queue_new(0);
+  ASSERT_TRUE(queue != NULL);
+  EXPECT_EQ((size_t)0, fixed_queue_capacity(queue));
+  fixed_queue_free(queue, NULL);
+
+  // Test a corner case: queue of size 1
+  queue = fixed_queue_new(1);
+  ASSERT_TRUE(queue != NULL);
+  EXPECT_EQ((size_t)1, fixed_queue_capacity(queue));
+  fixed_queue_free(queue, NULL);
+
+  // Test a corner case: queue of maximum size
+  queue = fixed_queue_new((size_t)-1);
+  ASSERT_TRUE(queue != NULL);
+  EXPECT_EQ((size_t)-1, fixed_queue_capacity(queue));
+  fixed_queue_free(queue, NULL);
+
+  // Test a queue of some size
+  queue = fixed_queue_new(TEST_QUEUE_SIZE);
+  ASSERT_TRUE(queue != NULL);
+  EXPECT_EQ(TEST_QUEUE_SIZE, fixed_queue_capacity(queue));
+  fixed_queue_free(queue, NULL);
+}
+
+TEST_F(FixedQueueTest, test_fixed_queue_enqueue_dequeue) {
+  fixed_queue_t* queue = fixed_queue_new(TEST_QUEUE_SIZE);
+  ASSERT_TRUE(queue != NULL);
+
+  // Test blocking enqueue and blocking dequeue
+  fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING);
+  EXPECT_EQ((size_t)1, fixed_queue_length(queue));
+  EXPECT_EQ(DUMMY_DATA_STRING, fixed_queue_dequeue(queue));
+  EXPECT_EQ((size_t)0, fixed_queue_length(queue));
+
+  // Test non-blocking enqueue and non-blocking dequeue
+  EXPECT_TRUE(fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING));
+  EXPECT_EQ((size_t)1, fixed_queue_length(queue));
+  EXPECT_EQ(DUMMY_DATA_STRING, fixed_queue_try_dequeue(queue));
+  EXPECT_EQ((size_t)0, fixed_queue_length(queue));
+
+  // Test non-blocking enqueue beyond queue capacity
+  for (size_t i = 0; i < TEST_QUEUE_SIZE; i++) {
+    EXPECT_TRUE(fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING));
+  }
+  // The next enqueue operation is beyond the queue capacity, so it should fail
+  EXPECT_FALSE(fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING));
+
+  // Test non-blocking dequeue from a queue that is full to max capacity
+  for (size_t i = 0; i < TEST_QUEUE_SIZE; i++) {
+    EXPECT_EQ(DUMMY_DATA_STRING, fixed_queue_try_dequeue(queue));
+  }
+
+  // Test non-blocking dequeue from an empty queue
+  EXPECT_EQ(NULL, fixed_queue_try_dequeue(queue));
+
+  // Test non-blocking dequeue from a NULL queue
+  EXPECT_EQ(NULL, fixed_queue_try_dequeue(NULL));
+
+  fixed_queue_free(queue, NULL);
+}
+
+TEST_F(FixedQueueTest, test_fixed_queue_try_peek_first_last) {
+  fixed_queue_t* queue = fixed_queue_new(TEST_QUEUE_SIZE);
+  ASSERT_TRUE(queue != NULL);
+
+  // Test peek first/last from a NULL queue
+  EXPECT_EQ(NULL, fixed_queue_try_peek_first(NULL));
+  EXPECT_EQ(NULL, fixed_queue_try_peek_last(NULL));
+
+  // Test peek first/last from an empty queue
+  EXPECT_EQ(NULL, fixed_queue_try_peek_first(queue));
+  EXPECT_EQ(NULL, fixed_queue_try_peek_last(queue));
+
+  // Test peek first/last from a queue with one element
+  fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING1);
+  EXPECT_EQ(DUMMY_DATA_STRING1, fixed_queue_try_peek_first(queue));
+  EXPECT_EQ(DUMMY_DATA_STRING1, fixed_queue_try_peek_last(queue));
+
+  // Test peek first/last from a queue with two elements
+  fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING2);
+  EXPECT_EQ(DUMMY_DATA_STRING1, fixed_queue_try_peek_first(queue));
+  EXPECT_EQ(DUMMY_DATA_STRING2, fixed_queue_try_peek_last(queue));
+
+  // Test peek first/last from a queue with three elements
+  fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING3);
+  EXPECT_EQ(DUMMY_DATA_STRING1, fixed_queue_try_peek_first(queue));
+  EXPECT_EQ(DUMMY_DATA_STRING3, fixed_queue_try_peek_last(queue));
+
+  fixed_queue_free(queue, NULL);
+}
+
+TEST_F(FixedQueueTest, test_fixed_queue_try_remove_from_queue) {
+  fixed_queue_t* queue = fixed_queue_new(TEST_QUEUE_SIZE);
+  ASSERT_TRUE(queue != NULL);
+
+  // Test removing from a NULL queue
+  EXPECT_EQ(NULL,
+            fixed_queue_try_remove_from_queue(NULL, (void*)DUMMY_DATA_STRING));
+
+  // Test removing from an empty queue
+  EXPECT_EQ(NULL,
+            fixed_queue_try_remove_from_queue(queue, (void*)DUMMY_DATA_STRING));
+
+  // Test removing a queued string from a queue
+  fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING1);
+  fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING2);
+  fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING3);
+  EXPECT_EQ((size_t)3, fixed_queue_length(queue));
+  EXPECT_EQ(DUMMY_DATA_STRING2, fixed_queue_try_remove_from_queue(
+                                    queue, (void*)DUMMY_DATA_STRING2));
+  EXPECT_EQ((size_t)2, fixed_queue_length(queue));
+  // Removing again should fail
+  EXPECT_EQ(NULL, fixed_queue_try_remove_from_queue(queue,
+                                                    (void*)DUMMY_DATA_STRING2));
+
+  // Test removing a non-queued string from a queue
+  EXPECT_EQ(NULL,
+            fixed_queue_try_remove_from_queue(queue, (void*)DUMMY_DATA_STRING));
+
+  fixed_queue_free(queue, NULL);
+}
+
+TEST_F(FixedQueueTest, test_fixed_queue_get_enqueue_dequeue_fd) {
+  fixed_queue_t* queue = fixed_queue_new(TEST_QUEUE_SIZE);
+  ASSERT_TRUE(queue != NULL);
+
+  // Test validity of enqueue and dequeue file descriptors
+  int enqueue_fd = fixed_queue_get_enqueue_fd(queue);
+  int dequeue_fd = fixed_queue_get_dequeue_fd(queue);
+  EXPECT_TRUE(enqueue_fd >= 0);
+  EXPECT_TRUE(dequeue_fd >= 0);
+  EXPECT_TRUE(enqueue_fd < FD_SETSIZE);
+  EXPECT_TRUE(dequeue_fd < FD_SETSIZE);
+
+  // Test the file descriptors of an empty queue
+  // Only the enqueue_fd should be readable
+  EXPECT_TRUE(is_fd_readable(enqueue_fd));
+  EXPECT_FALSE(is_fd_readable(dequeue_fd));
+
+  // Test the file descriptors of a non-empty queue
+  // Both the enqueue_fd and dequeue_fd should be readable
+  fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING);
+  EXPECT_TRUE(is_fd_readable(enqueue_fd));
+  EXPECT_TRUE(is_fd_readable(dequeue_fd));
+  fixed_queue_dequeue(queue);
+
+  // Test the file descriptors of a full queue
+  // Only the dequeue_fd should be readable
+  for (size_t i = 0; i < TEST_QUEUE_SIZE; i++) {
+    EXPECT_TRUE(fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING));
+  }
+  EXPECT_FALSE(is_fd_readable(enqueue_fd));
+  EXPECT_TRUE(is_fd_readable(dequeue_fd));
+
+  fixed_queue_free(queue, NULL);
+}
+
+TEST_F(FixedQueueTest, test_fixed_queue_register_dequeue) {
+  fixed_queue_t* queue = fixed_queue_new(TEST_QUEUE_SIZE);
+  ASSERT_TRUE(queue != NULL);
+
+  received_message_future = future_new();
+  ASSERT_TRUE(received_message_future != NULL);
+
+  thread_t* worker_thread = thread_new("test_fixed_queue_worker_thread");
+  ASSERT_TRUE(worker_thread != NULL);
+
+  fixed_queue_register_dequeue(queue, thread_get_reactor(worker_thread),
+                               fixed_queue_ready, NULL);
+
+  // Add a message to the queue, and expect to receive it
+  fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING);
+  const char* msg = (const char*)future_await(received_message_future);
+  EXPECT_EQ(DUMMY_DATA_STRING, msg);
+
+  fixed_queue_unregister_dequeue(queue);
+  thread_free(worker_thread);
+  fixed_queue_free(queue, NULL);
+}
diff --git a/bt/osi/test/future_test.cc b/bt/osi/test/future_test.cc
new file mode 100644
index 0000000..fe5e7fd
--- /dev/null
+++ b/bt/osi/test/future_test.cc
@@ -0,0 +1,53 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "AllocationTestHarness.h"
+
+#include "osi/include/future.h"
+#include "osi/include/osi.h"
+#include "osi/include/thread.h"
+
+static const char* pass_back_data0 = "fancy a sandwich? it's a fancy sandwich";
+static const char* pass_back_data1 =
+    "what kind of ice cream truck plays the worst christmas song of all time?";
+
+class FutureTest : public AllocationTestHarness {};
+
+static void post_to_future(void* context) {
+  future_ready((future_t*)context, (void*)pass_back_data0);
+}
+
+TEST_F(FutureTest, test_future_non_immediate) {
+  future_t* future = future_new();
+  ASSERT_TRUE(future != NULL);
+
+  thread_t* worker_thread = thread_new("worker thread");
+  thread_post(worker_thread, post_to_future, future);
+
+  EXPECT_EQ(pass_back_data0, future_await(future));
+
+  thread_free(worker_thread);
+}
+
+TEST_F(FutureTest, test_future_immediate) {
+  future_t* future = future_new_immediate((void*)pass_back_data1);
+  ASSERT_TRUE(future != NULL);
+  EXPECT_EQ(pass_back_data1, future_await(future));
+}
diff --git a/bt/osi/test/hash_map_utils_test.cc b/bt/osi/test/hash_map_utils_test.cc
new file mode 100644
index 0000000..0e483e5
--- /dev/null
+++ b/bt/osi/test/hash_map_utils_test.cc
@@ -0,0 +1,113 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <gtest/gtest.h>
+
+#include "AllocationTestHarness.h"
+
+#include "osi/include/hash_map_utils.h"
+
+#include "osi/include/allocator.h"
+
+class HashMapUtilsTest : public AllocationTestHarness {
+ protected:
+  virtual void SetUp() { AllocationTestHarness::SetUp(); }
+  virtual void TearDown() {
+    map.clear();
+    AllocationTestHarness::TearDown();
+  }
+
+  std::unordered_map<std::string, std::string> map;
+};
+
+TEST_F(HashMapUtilsTest, test_empty_string_params) {
+  char params[] = "";
+  map = hash_map_utils_new_from_string_params(params);
+  EXPECT_TRUE(map.empty());
+}
+
+TEST_F(HashMapUtilsTest, test_semicolons) {
+  char params[] = ";;;";
+  map = hash_map_utils_new_from_string_params(params);
+  EXPECT_TRUE(map.empty());
+}
+
+TEST_F(HashMapUtilsTest, test_equal_sign_in_value) {
+  char params[] = "keyOfSomething=value=OfSomething";
+  char key[] = "keyOfSomething";
+  char value[] = "value=OfSomething";
+  map = hash_map_utils_new_from_string_params(params);
+  EXPECT_EQ(1u, map.size());
+  EXPECT_EQ(value, map[key]);
+  map.clear();
+}
+
+TEST_F(HashMapUtilsTest, test_two_pairs_with_same_key) {
+  char params[] = "key=valu0;key=value1";
+  char key[] = "key";
+  char value1[] = "value1";
+  map = hash_map_utils_new_from_string_params(params);
+  EXPECT_EQ(1u, map.size());
+  EXPECT_EQ(value1, map[key]);
+}
+
+TEST_F(HashMapUtilsTest, test_one_key_value_pair_without_semicolon) {
+  char params[] = "keyOfSomething=valueOfSomething";
+  char key[] = "keyOfSomething";
+  char value[] = "valueOfSomething";
+  map = hash_map_utils_new_from_string_params(params);
+  EXPECT_EQ(1u, map.size());
+  EXPECT_EQ(value, map[key]);
+}
+
+TEST_F(HashMapUtilsTest, test_one_key_value_pair_with_semicolon) {
+  char params[] = "keyOfSomething=valueOfSomething;";
+  char key[] = "keyOfSomething";
+  char value[] = "valueOfSomething";
+  map = hash_map_utils_new_from_string_params(params);
+  EXPECT_EQ(1u, map.size());
+  EXPECT_EQ(value, map[key]);
+}
+
+TEST_F(HashMapUtilsTest, test_one_pair_with_empty_value) {
+  char params[] = "keyOfSomething=;";
+  char key[] = "keyOfSomething";
+  char value[] = "";
+  map = hash_map_utils_new_from_string_params(params);
+  EXPECT_EQ(1u, map.size());
+  EXPECT_EQ(value, map[key]);
+}
+
+TEST_F(HashMapUtilsTest, test_one_pair_with_empty_key) {
+  char params[] = "=valueOfSomething;";
+  map = hash_map_utils_new_from_string_params(params);
+  EXPECT_TRUE(map.empty());
+}
+
+TEST_F(HashMapUtilsTest, test_two_key_value_pairs) {
+  char params[] = "key0=value0;key1=value1;";
+  char key0[] = "key0";
+  char value0[] = "value0";
+  char key1[] = "key1";
+  char value1[] = "value1";
+  map = hash_map_utils_new_from_string_params(params);
+  EXPECT_EQ(2u, map.size());
+  EXPECT_EQ(value0, map[key0]);
+  EXPECT_EQ(value1, map[key1]);
+}
diff --git a/bt/osi/test/list_test.cc b/bt/osi/test/list_test.cc
new file mode 100644
index 0000000..a4d1b6f
--- /dev/null
+++ b/bt/osi/test/list_test.cc
@@ -0,0 +1,209 @@
+#include <gtest/gtest.h>
+
+#include "AllocationTestHarness.h"
+
+#include "osi/include/list.h"
+#include "osi/include/osi.h"
+
+class ListTest : public AllocationTestHarness {};
+
+TEST_F(ListTest, test_new_free_simple) {
+  list_t* list = list_new(NULL);
+  ASSERT_TRUE(list != NULL);
+  list_free(list);
+}
+
+TEST_F(ListTest, test_free_null) {
+  // In this test we just verify that list_free is callable with NULL.
+  list_free(NULL);
+}
+
+TEST_F(ListTest, test_empty_list_is_empty) {
+  list_t* list = list_new(NULL);
+  EXPECT_TRUE(list_is_empty(list));
+  list_free(list);
+}
+
+TEST_F(ListTest, test_empty_list_has_no_length) {
+  list_t* list = list_new(NULL);
+  EXPECT_EQ(list_length(list), 0U);
+  list_free(list);
+}
+
+TEST_F(ListTest, test_simple_list_prepend) {
+  list_t* list = list_new(NULL);
+  EXPECT_TRUE(list_prepend(list, &list));
+  EXPECT_FALSE(list_is_empty(list));
+  EXPECT_EQ(list_length(list), 1U);
+  list_free(list);
+}
+
+TEST_F(ListTest, test_simple_list_append) {
+  list_t* list = list_new(NULL);
+  EXPECT_TRUE(list_append(list, &list));
+  EXPECT_FALSE(list_is_empty(list));
+  EXPECT_EQ(list_length(list), 1U);
+  list_free(list);
+}
+
+TEST_F(ListTest, test_list_remove_found) {
+  list_t* list = list_new(NULL);
+  list_append(list, &list);
+  EXPECT_TRUE(list_remove(list, &list));
+  EXPECT_TRUE(list_is_empty(list));
+  EXPECT_EQ(list_length(list), 0U);
+  list_free(list);
+}
+
+TEST_F(ListTest, test_list_remove_not_found) {
+  int x;
+  list_t* list = list_new(NULL);
+  list_append(list, &list);
+  EXPECT_FALSE(list_remove(list, &x));
+  EXPECT_FALSE(list_is_empty(list));
+  EXPECT_EQ(list_length(list), 1U);
+  list_free(list);
+}
+
+TEST_F(ListTest, test_list_front) {
+  int x[] = {1, 2, 3, 4, 5};
+  list_t* list = list_new(NULL);
+
+  for (size_t i = 0; i < ARRAY_SIZE(x); ++i) list_append(list, &x[i]);
+
+  EXPECT_EQ(list_front(list), &x[0]);
+
+  list_free(list);
+}
+
+TEST_F(ListTest, test_list_back) {
+  int x[] = {1, 2, 3, 4, 5};
+  list_t* list = list_new(NULL);
+
+  for (size_t i = 0; i < ARRAY_SIZE(x); ++i) list_append(list, &x[i]);
+
+  EXPECT_EQ(list_back(list), &x[ARRAY_SIZE(x) - 1]);
+
+  list_free(list);
+}
+
+TEST_F(ListTest, test_list_clear) {
+  int x[] = {1, 2, 3, 4, 5};
+  list_t* list = list_new(NULL);
+
+  for (size_t i = 0; i < ARRAY_SIZE(x); ++i) list_append(list, &x[i]);
+
+  list_clear(list);
+  EXPECT_TRUE(list_is_empty(list));
+  EXPECT_EQ(list_length(list), 0U);
+
+  list_free(list);
+}
+
+TEST_F(ListTest, test_list_append_multiple) {
+  int x[] = {1, 2, 3, 4, 5};
+  list_t* list = list_new(NULL);
+
+  for (size_t i = 0; i < ARRAY_SIZE(x); ++i) list_append(list, &x[i]);
+
+  int i = 0;
+  for (const list_node_t *node = list_begin(list); node != list_end(list);
+       node = list_next(node), ++i)
+    EXPECT_EQ(list_node(node), &x[i]);
+
+  list_free(list);
+}
+
+TEST_F(ListTest, test_list_prepend_multiple) {
+  int x[] = {1, 2, 3, 4, 5};
+  list_t* list = list_new(NULL);
+
+  for (size_t i = 0; i < ARRAY_SIZE(x); ++i) list_prepend(list, &x[i]);
+
+  int i = ARRAY_SIZE(x) - 1;
+  for (const list_node_t *node = list_begin(list); node != list_end(list);
+       node = list_next(node), --i)
+    EXPECT_EQ(list_node(node), &x[i]);
+
+  list_free(list);
+}
+
+TEST_F(ListTest, test_list_begin_empty_list) {
+  list_t* list = list_new(NULL);
+  EXPECT_EQ(list_begin(list), list_end(list));
+  list_free(list);
+}
+
+TEST_F(ListTest, test_list_next) {
+  list_t* list = list_new(NULL);
+  list_append(list, &list);
+  EXPECT_NE(list_begin(list), list_end(list));
+  EXPECT_EQ(list_next(list_begin(list)), list_end(list));
+  list_free(list);
+}
+
+static bool list_callback_sum(void* data, void* context) {
+  assert(data);
+  assert(context);
+  int* sum = (int*)context;
+  int* value = (int*)data;
+  *sum += *value;
+  return true;
+}
+
+static bool list_callback_find_int(void* data, void* context) {
+  assert(data);
+  assert(context);
+  return (*(int*)data != *(int*)context);
+}
+
+TEST_F(ListTest, test_list_foreach_full) {
+  list_t* list = list_new(NULL);
+
+  // Fill in test data
+  int x[] = {1, 2, 3, 4, 5};
+  for (size_t i = 0; i < ARRAY_SIZE(x); ++i) list_append(list, &x[i]);
+  EXPECT_EQ(list_length(list), (size_t)5);
+
+  // Test complete iteration
+  int sum = 0;
+  list_node_t* rc = list_foreach(list, list_callback_sum, &sum);
+  EXPECT_EQ(sum, 15);
+  EXPECT_TRUE(rc == NULL);
+
+  list_free(list);
+}
+
+TEST_F(ListTest, test_list_foreach_partial) {
+  list_t* list = list_new(NULL);
+
+  // Fill in test data
+  int x[] = {1, 2, 3, 4, 5};
+  for (size_t i = 0; i < ARRAY_SIZE(x); ++i) list_append(list, &x[i]);
+  EXPECT_EQ(list_length(list), (size_t)5);
+
+  // Test partial iteration
+  int find = 4;
+  list_node_t* rc = list_foreach(list, list_callback_find_int, &find);
+  EXPECT_TRUE(rc != NULL);
+  int* rc_val = (int*)list_node(rc);
+  EXPECT_TRUE(*rc_val == 4);
+
+  find = 1;
+  rc = list_foreach(list, list_callback_find_int, &find);
+  EXPECT_TRUE(rc != NULL);
+  rc_val = (int*)list_node(rc);
+  EXPECT_TRUE(*rc_val == 1);
+
+  find = 5;
+  rc = list_foreach(list, list_callback_find_int, &find);
+  EXPECT_TRUE(rc != NULL);
+  rc_val = (int*)list_node(rc);
+  EXPECT_TRUE(*rc_val == 5);
+
+  find = 0;
+  rc = list_foreach(list, list_callback_find_int, &find);
+  EXPECT_TRUE(rc == NULL);
+
+  list_free(list);
+}
diff --git a/bt/osi/test/properties_test.cc b/bt/osi/test/properties_test.cc
new file mode 100644
index 0000000..17cbd6c
--- /dev/null
+++ b/bt/osi/test/properties_test.cc
@@ -0,0 +1,41 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "AllocationTestHarness.h"
+
+#include "osi/include/properties.h"
+
+class PropertiesTest : public AllocationTestHarness {};
+
+TEST_F(PropertiesTest, test_default_value) {
+  char value[PROPERTY_VALUE_MAX] = {0};
+  osi_property_get("very.useful.test", value, "very_useful_value");
+  ASSERT_STREQ(value, "very_useful_value");
+}
+
+TEST_F(PropertiesTest, test_successfull_set_and_get_value) {
+  char value[PROPERTY_VALUE_MAX] = "nothing_interesting";
+  int ret = osi_property_set("very.useful.set.test", value);
+  ASSERT_EQ(0, ret);
+
+  char received[PROPERTY_VALUE_MAX];
+  osi_property_get("very.useful.set.test", received, NULL);
+  ASSERT_STREQ(received, "nothing_interesting");
+}
diff --git a/bt/osi/test/rand_test.cc b/bt/osi/test/rand_test.cc
new file mode 100644
index 0000000..720617b
--- /dev/null
+++ b/bt/osi/test/rand_test.cc
@@ -0,0 +1,17 @@
+#include <gtest/gtest.h>
+
+#include "AllocationTestHarness.h"
+
+#include "osi/include/osi.h"
+
+class RandTest : public AllocationTestHarness {};
+
+TEST_F(RandTest, test_rand) {
+  // We can't guarantee any distribution
+  // We'd like it to not crash though.
+  for (int i = 0; i < 10; i++) {
+    int x;
+    x = osi_rand();
+    EXPECT_TRUE(x >= 0);
+  }
+}
diff --git a/bt/osi/test/reactor_test.cc b/bt/osi/test/reactor_test.cc
new file mode 100644
index 0000000..0164227
--- /dev/null
+++ b/bt/osi/test/reactor_test.cc
@@ -0,0 +1,113 @@
+#include <gtest/gtest.h>
+#include <pthread.h>
+#include <sys/eventfd.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "AllocationTestHarness.h"
+
+#include "osi/include/reactor.h"
+
+class ReactorTest : public AllocationTestHarness {};
+
+static pthread_t thread;
+static volatile bool thread_running;
+
+static void* reactor_thread(void* ptr) {
+  reactor_t* reactor = (reactor_t*)ptr;
+
+  thread_running = true;
+  reactor_start(reactor);
+  thread_running = false;
+
+  return NULL;
+}
+
+static void spawn_reactor_thread(reactor_t* reactor) {
+  int ret = pthread_create(&thread, NULL, reactor_thread, reactor);
+  EXPECT_EQ(ret, 0);
+}
+
+static void join_reactor_thread() { pthread_join(thread, NULL); }
+
+TEST_F(ReactorTest, reactor_new) {
+  reactor_t* reactor = reactor_new();
+  EXPECT_TRUE(reactor != NULL);
+  reactor_free(reactor);
+}
+
+TEST_F(ReactorTest, reactor_free_null) { reactor_free(NULL); }
+
+TEST_F(ReactorTest, reactor_stop_start) {
+  reactor_t* reactor = reactor_new();
+  reactor_stop(reactor);
+  reactor_start(reactor);
+  reactor_free(reactor);
+}
+
+TEST_F(ReactorTest, reactor_repeated_stop_start) {
+  reactor_t* reactor = reactor_new();
+  for (int i = 0; i < 10; ++i) {
+    reactor_stop(reactor);
+    reactor_start(reactor);
+  }
+  reactor_free(reactor);
+}
+
+TEST_F(ReactorTest, reactor_start_wait_stop) {
+  reactor_t* reactor = reactor_new();
+
+  spawn_reactor_thread(reactor);
+  usleep(50 * 1000);
+  EXPECT_TRUE(thread_running);
+
+  reactor_stop(reactor);
+  join_reactor_thread();
+  EXPECT_FALSE(thread_running);
+
+  reactor_free(reactor);
+}
+
+typedef struct {
+  reactor_t* reactor;
+  reactor_object_t* object;
+} unregister_arg_t;
+
+static void unregister_cb(void* context) {
+  unregister_arg_t* arg = (unregister_arg_t*)context;
+  reactor_unregister(arg->object);
+  reactor_stop(arg->reactor);
+}
+
+TEST_F(ReactorTest, reactor_unregister_from_callback) {
+  reactor_t* reactor = reactor_new();
+
+  int fd = eventfd(0, 0);
+  unregister_arg_t arg;
+  arg.reactor = reactor;
+  arg.object = reactor_register(reactor, fd, &arg, unregister_cb, NULL);
+  spawn_reactor_thread(reactor);
+  eventfd_write(fd, 1);
+
+  join_reactor_thread();
+
+  close(fd);
+  reactor_free(reactor);
+}
+
+TEST_F(ReactorTest, reactor_unregister_from_separate_thread) {
+  reactor_t* reactor = reactor_new();
+
+  int fd = eventfd(0, 0);
+
+  reactor_object_t* object = reactor_register(reactor, fd, NULL, NULL, NULL);
+  spawn_reactor_thread(reactor);
+  usleep(50 * 1000);
+  reactor_unregister(object);
+
+  reactor_stop(reactor);
+  join_reactor_thread();
+
+  close(fd);
+  reactor_free(reactor);
+}
diff --git a/bt/osi/test/ringbuffer_test.cc b/bt/osi/test/ringbuffer_test.cc
new file mode 100644
index 0000000..3475973
--- /dev/null
+++ b/bt/osi/test/ringbuffer_test.cc
@@ -0,0 +1,139 @@
+#include <gtest/gtest.h>
+
+#include "osi/include/osi.h"
+#include "osi/include/ringbuffer.h"
+
+TEST(RingbufferTest, test_new_simple) {
+  ringbuffer_t* rb = ringbuffer_init(4096);
+  ASSERT_TRUE(rb != NULL);
+  EXPECT_EQ((size_t)4096, ringbuffer_available(rb));
+  EXPECT_EQ((size_t)0, ringbuffer_size(rb));
+  ringbuffer_free(rb);
+}
+
+TEST(RingbufferTest, test_insert_basic) {
+  ringbuffer_t* rb = ringbuffer_init(16);
+
+  uint8_t buffer[10] = {0x01, 0x02, 0x03, 0x04, 0x05,
+                        0x06, 0x07, 0x08, 0x09, 0x0A};
+  ringbuffer_insert(rb, buffer, 10);
+  EXPECT_EQ((size_t)10, ringbuffer_size(rb));
+  EXPECT_EQ((size_t)6, ringbuffer_available(rb));
+
+  uint8_t peek[10] = {0};
+  size_t peeked = ringbuffer_peek(rb, 0, peek, 10);
+  EXPECT_EQ((size_t)10, ringbuffer_size(rb));  // Ensure size doesn't change
+  EXPECT_EQ((size_t)6, ringbuffer_available(rb));
+  EXPECT_EQ((size_t)10, peeked);
+  ASSERT_TRUE(0 == memcmp(buffer, peek, peeked));
+
+  ringbuffer_free(rb);
+}
+
+TEST(RingbufferTest, test_insert_full) {
+  ringbuffer_t* rb = ringbuffer_init(5);
+
+  uint8_t aa[] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
+  uint8_t bb[] = {0xBB, 0xBB, 0xBB, 0xBB, 0xBB};
+  uint8_t peek[5] = {0};
+
+  size_t added = ringbuffer_insert(rb, aa, 7);
+  EXPECT_EQ((size_t)5, added);
+  EXPECT_EQ((size_t)0, ringbuffer_available(rb));
+  EXPECT_EQ((size_t)5, ringbuffer_size(rb));
+
+  added = ringbuffer_insert(rb, bb, 5);
+  EXPECT_EQ((size_t)0, added);
+  EXPECT_EQ((size_t)0, ringbuffer_available(rb));
+  EXPECT_EQ((size_t)5, ringbuffer_size(rb));
+
+  size_t peeked = ringbuffer_peek(rb, 0, peek, 5);
+  EXPECT_EQ((size_t)5, peeked);
+  EXPECT_EQ((size_t)0, ringbuffer_available(rb));
+  EXPECT_EQ((size_t)5, ringbuffer_size(rb));
+
+  ASSERT_TRUE(0 == memcmp(aa, peek, peeked));
+
+  ringbuffer_free(rb);
+}
+
+TEST(RingbufferTest, test_multi_insert_delete) {
+  ringbuffer_t* rb = ringbuffer_init(16);
+  EXPECT_EQ((size_t)16, ringbuffer_available(rb));
+  EXPECT_EQ((size_t)0, ringbuffer_size(rb));
+
+  // Insert some bytes
+
+  uint8_t aa[] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
+  size_t added = ringbuffer_insert(rb, aa, sizeof(aa));
+  EXPECT_EQ((size_t)8, added);
+  EXPECT_EQ((size_t)8, ringbuffer_available(rb));
+  EXPECT_EQ((size_t)8, ringbuffer_size(rb));
+
+  uint8_t bb[] = {0xBB, 0xBB, 0xBB, 0xBB, 0xBB};
+  ringbuffer_insert(rb, bb, sizeof(bb));
+  EXPECT_EQ((size_t)3, ringbuffer_available(rb));
+  EXPECT_EQ((size_t)13, ringbuffer_size(rb));
+
+  uint8_t content[] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+                       0xAA, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB};
+  uint8_t peek[16] = {0};
+  size_t peeked = ringbuffer_peek(rb, 0, peek, 16);
+  EXPECT_EQ((size_t)13, peeked);
+  ASSERT_TRUE(0 == memcmp(content, peek, peeked));
+
+  // Delete some bytes
+
+  ringbuffer_delete(rb, sizeof(aa));
+  EXPECT_EQ((size_t)11, ringbuffer_available(rb));
+  EXPECT_EQ((size_t)5, ringbuffer_size(rb));
+
+  // Add some more to wrap buffer
+
+  uint8_t cc[] = {0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC};
+  ringbuffer_insert(rb, cc, sizeof(cc));
+  EXPECT_EQ((size_t)2, ringbuffer_available(rb));
+  EXPECT_EQ((size_t)14, ringbuffer_size(rb));
+
+  uint8_t content2[] = {0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xCC, 0xCC};
+  peeked = ringbuffer_peek(rb, 0, peek, 7);
+  EXPECT_EQ((size_t)7, peeked);
+  ASSERT_TRUE(0 == memcmp(content2, peek, peeked));
+
+  // Pop buffer
+
+  memset(peek, 0, 16);
+  size_t popped = ringbuffer_pop(rb, peek, 7);
+  EXPECT_EQ((size_t)7, popped);
+  EXPECT_EQ((size_t)9, ringbuffer_available(rb));
+  ASSERT_TRUE(0 == memcmp(content2, peek, peeked));
+
+  // Add more again to check head motion
+
+  uint8_t dd[] = {0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD};
+  added = ringbuffer_insert(rb, dd, sizeof(dd));
+  EXPECT_EQ((size_t)8, added);
+  EXPECT_EQ((size_t)1, ringbuffer_available(rb));
+
+  // Delete everything
+
+  ringbuffer_delete(rb, 16);
+  EXPECT_EQ((size_t)16, ringbuffer_available(rb));
+  EXPECT_EQ((size_t)0, ringbuffer_size(rb));
+
+  // Add small token
+
+  uint8_t ae[] = {0xAE, 0xAE, 0xAE};
+  added = ringbuffer_insert(rb, ae, sizeof(ae));
+  EXPECT_EQ((size_t)13, ringbuffer_available(rb));
+
+  // Get everything
+
+  popped = ringbuffer_pop(rb, peek, 16);
+  EXPECT_EQ(added, popped);
+  EXPECT_EQ((size_t)16, ringbuffer_available(rb));
+  EXPECT_EQ((size_t)0, ringbuffer_size(rb));
+  ASSERT_TRUE(0 == memcmp(ae, peek, popped));
+
+  ringbuffer_free(rb);
+}
diff --git a/bt/osi/test/semaphore_test.cc b/bt/osi/test/semaphore_test.cc
new file mode 100644
index 0000000..711ae49
--- /dev/null
+++ b/bt/osi/test/semaphore_test.cc
@@ -0,0 +1,85 @@
+#include <gtest/gtest.h>
+
+#include "AllocationTestHarness.h"
+
+#include <sys/select.h>
+#include <unistd.h>
+
+#include "osi/include/osi.h"
+#include "osi/include/reactor.h"
+#include "osi/include/semaphore.h"
+#include "osi/include/thread.h"
+
+struct SemaphoreTestSequenceHelper {
+  semaphore_t* semaphore;
+  int counter;
+};
+
+namespace {
+void sleep_then_increment_counter(void* context) {
+  SemaphoreTestSequenceHelper* helper =
+      reinterpret_cast<SemaphoreTestSequenceHelper*>(context);
+  assert(helper);
+  assert(helper->semaphore);
+  sleep(1);
+  ++helper->counter;
+  semaphore_post(helper->semaphore);
+}
+}  // namespace
+
+class SemaphoreTest : public AllocationTestHarness {};
+
+TEST_F(SemaphoreTest, test_new_simple) {
+  semaphore_t* semaphore = semaphore_new(0);
+  ASSERT_TRUE(semaphore != NULL);
+  semaphore_free(semaphore);
+}
+
+TEST_F(SemaphoreTest, test_new_with_value) {
+  semaphore_t* semaphore = semaphore_new(3);
+  ASSERT_TRUE(semaphore != NULL);
+
+  EXPECT_TRUE(semaphore_try_wait(semaphore));
+  EXPECT_TRUE(semaphore_try_wait(semaphore));
+  EXPECT_TRUE(semaphore_try_wait(semaphore));
+  EXPECT_FALSE(semaphore_try_wait(semaphore));
+
+  semaphore_free(semaphore);
+}
+
+TEST_F(SemaphoreTest, test_try_wait) {
+  semaphore_t* semaphore = semaphore_new(0);
+  ASSERT_TRUE(semaphore != NULL);
+
+  EXPECT_FALSE(semaphore_try_wait(semaphore));
+  semaphore_post(semaphore);
+  EXPECT_TRUE(semaphore_try_wait(semaphore));
+  EXPECT_FALSE(semaphore_try_wait(semaphore));
+
+  semaphore_free(semaphore);
+}
+
+TEST_F(SemaphoreTest, test_wait_after_post) {
+  semaphore_t* semaphore = semaphore_new(0);
+  ASSERT_TRUE(semaphore != NULL);
+  semaphore_post(semaphore);
+  semaphore_wait(semaphore);
+  semaphore_free(semaphore);
+}
+
+TEST_F(SemaphoreTest, test_ensure_wait) {
+  semaphore_t* semaphore = semaphore_new(0);
+  ASSERT_TRUE(semaphore != NULL);
+  thread_t* thread = thread_new("semaphore_test_thread");
+  ASSERT_TRUE(thread != NULL);
+
+  EXPECT_FALSE(semaphore_try_wait(semaphore));
+  SemaphoreTestSequenceHelper sequence_helper = {semaphore, 0};
+  thread_post(thread, sleep_then_increment_counter, &sequence_helper);
+  semaphore_wait(semaphore);
+  EXPECT_EQ(sequence_helper.counter, 1)
+      << "semaphore_wait() did not wait for counter to increment";
+
+  semaphore_free(semaphore);
+  thread_free(thread);
+}
diff --git a/bt/osi/test/test_stubs.h b/bt/osi/test/test_stubs.h
new file mode 100644
index 0000000..007d9a4
--- /dev/null
+++ b/bt/osi/test/test_stubs.h
@@ -0,0 +1,109 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Helper macros for stubbing out functions and modules for testing.
+
+// Stub out a function, with call counting and mode awareness
+#define STUB_FUNCTION(ret, name, params)                 \
+  UNUSED_ATTR static int name##_callcount;               \
+  static ret name params {                               \
+    UNUSED_ATTR int _local_callcount = name##_callcount; \
+    name##_callcount++;
+
+// Expect a certain number of calls to the specified stub function
+#define EXPECT_CALL_COUNT(name, count)   \
+  EXPECT_EQ((count), (name##_callcount)) \
+      << "expected " #name " to be called " #count " times"
+
+// Reset the call count for the specificed stub function
+#define RESET_CALL_COUNT(name) ((name##_callcount) = 0)
+
+// Use this in a stub function to catch unexpected calls.
+// Prints out a nice message including the call count, the
+// stub function name, and the mode index (sadly no mode name)
+#define UNEXPECTED_CALL                                                  \
+  EXPECT_TRUE(false) << "unexpected call " << _local_callcount << " to " \
+                     << __func__ << " during mode " << (int)_current_mode
+
+#define MODE_IS(mode) (_current_mode == (mode))
+
+// Macro selection helpers
+#define OVERLOAD_CAT(A, B) A##B
+#define OVERLOAD_SELECT(NAME, NUM) OVERLOAD_CAT(NAME##_, NUM)
+#define OVERLOAD_GET_COUNT(_1, _2, _3, _4, _5, _6, COUNT, ...) COUNT
+#define OVERLOAD_VA_SIZE(...) OVERLOAD_GET_COUNT(__VA_ARGS__, 6, 5, 4, 3, 2, 1)
+#define OVERLOAD_OF(NAME, ...) \
+  OVERLOAD_SELECT(NAME, OVERLOAD_VA_SIZE(__VA_ARGS__))(__VA_ARGS__)
+
+// Use this to branch stub function execution to a specific mode or modes.
+// Treat it like an if statement. For example:
+//
+// DURING(dinner) EXPECT_EQ(bread_pudding, food);
+// DURING(midday_snack, midnight_snack) EXPECT_EQ(chocolate, food);
+#define DURING(...) OVERLOAD_OF(DURING, __VA_ARGS__)
+
+#define DURING_1(mode0) if (MODE_IS(mode0))
+#define DURING_2(mode0, mode1) if (MODE_IS(mode0) || MODE_IS(mode1))
+#define DURING_3(mode0, mode1, mode2) \
+  if (MODE_IS(mode0) || MODE_IS(mode1) || MODE_IS(mode2))
+#define DURING_4(mode0, mode1, mode2, mode3) \
+  if (MODE_IS(mode0) || MODE_IS(mode1) || MODE_IS(mode2) || MODE_IS(mode3))
+#define DURING_5(mode0, mode1, mode2, mode3, mode4)                           \
+  if (MODE_IS(mode0) || MODE_IS(mode1) || MODE_IS(mode2) || MODE_IS(mode3) || \
+      MODE_IS(mode4))
+#define DURING_6(mode0, mode1, mode2, mode3, mode4, mode5)                    \
+  if (MODE_IS(mode0) || MODE_IS(mode1) || MODE_IS(mode2) || MODE_IS(mode3) || \
+      MODE_IS(mode4) || MODE_IS(mode5))
+
+// Use this to branch stub function exeuction to a specific call
+// count index (zero based). Treat it like an if statement.
+// Usually most helpful following a DURING clause. For example:
+//
+// DURING (breakfast) AT_CALL(0) EXPECT_EQ(bacon, food);
+//
+// or
+//
+// DURING (three_course_meal) {
+//   AT_CALL(0) EXPECT_EQ(shrimp_cocktail, food);
+//   AT_CALL(1) EXPECT_EQ(bacon_wrapped_bacon, food);
+//   AT_CALL(1) EXPECT_EQ(chocolate_covered_fake_blueberries, food);
+// }
+#define AT_CALL(index) if (_local_callcount == (index))
+
+// Declare all the available test modes for the DURING clauses
+// For example:
+//
+// DECLARE_TEST_MODES(breakfast, lunch, dinner);
+#define DECLARE_TEST_MODES(...)               \
+  typedef enum { __VA_ARGS__ } _test_modes_t; \
+  static _test_modes_t _current_mode;
+
+// Get the current test mode
+#define CURRENT_TEST_MODE _current_mode
+
+#define TEST_MODES_T _test_modes_t
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bt/osi/test/thread_test.cc b/bt/osi/test/thread_test.cc
new file mode 100644
index 0000000..debf250
--- /dev/null
+++ b/bt/osi/test/thread_test.cc
@@ -0,0 +1,57 @@
+#include <gtest/gtest.h>
+
+#include "AllocationTestHarness.h"
+
+#include <sys/select.h>
+
+#include "osi/include/osi.h"
+#include "osi/include/reactor.h"
+#include "osi/include/thread.h"
+
+class ThreadTest : public AllocationTestHarness {};
+
+TEST_F(ThreadTest, test_new_simple) {
+  thread_t* thread = thread_new("test_thread");
+  ASSERT_TRUE(thread != NULL);
+  thread_free(thread);
+}
+
+TEST_F(ThreadTest, test_free_simple) {
+  thread_t* thread = thread_new("test_thread");
+  thread_free(thread);
+}
+
+TEST_F(ThreadTest, test_name) {
+  thread_t* thread = thread_new("test_name");
+  ASSERT_STREQ(thread_name(thread), "test_name");
+  thread_free(thread);
+}
+
+TEST_F(ThreadTest, test_long_name) {
+  thread_t* thread = thread_new("0123456789abcdef");
+  ASSERT_STREQ("0123456789abcdef", thread_name(thread));
+  thread_free(thread);
+}
+
+TEST_F(ThreadTest, test_very_long_name) {
+  thread_t* thread = thread_new("0123456789abcdefg");
+  ASSERT_STREQ("0123456789abcdef", thread_name(thread));
+  thread_free(thread);
+}
+
+static void thread_is_self_fn(void* context) {
+  thread_t* thread = (thread_t*)context;
+  EXPECT_TRUE(thread_is_self(thread));
+}
+
+TEST_F(ThreadTest, test_thread_is_self) {
+  thread_t* thread = thread_new("test_thread");
+  thread_post(thread, thread_is_self_fn, thread);
+  thread_free(thread);
+}
+
+TEST_F(ThreadTest, test_thread_is_not_self) {
+  thread_t* thread = thread_new("test_thread");
+  EXPECT_FALSE(thread_is_self(thread));
+  thread_free(thread);
+}
diff --git a/bt/osi/test/time_test.cc b/bt/osi/test/time_test.cc
new file mode 100644
index 0000000..79f21a3
--- /dev/null
+++ b/bt/osi/test/time_test.cc
@@ -0,0 +1,114 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "AllocationTestHarness.h"
+
+#include "osi/include/time.h"
+
+// Generous upper bound: 10 seconds
+static const uint32_t TEST_TIME_DELTA_UPPER_BOUND_MS = 10 * 1000;
+
+class TimeTest : public AllocationTestHarness {};
+
+//
+// Test that the return value of time_get_os_boottime_ms() is not zero.
+//
+// NOTE: For now this test is disabled, because the return value
+// of time_get_os_boottime_ms() is 32-bits integer that could wrap-around
+// in 49.7 days. It should be re-enabled if/after the wrap-around issue
+// is resolved (e.g., if the return value is 64-bits integer).
+//
+#if 0
+TEST_F(TimeTest, test_time_get_os_boottime_ms_not_zero) {
+  uint32_t t1 = time_get_os_boottime_ms();
+  ASSERT_TRUE(t1 > 0);
+}
+#endif
+
+//
+// Test that the return value of time_get_os_boottime_us() is not zero.
+//
+TEST_F(TimeTest, test_time_get_os_boottime_us_not_zero) {
+  uint64_t t1 = time_get_os_boottime_us();
+  ASSERT_TRUE(t1 > 0);
+}
+
+//
+// Test that the return value of time_get_os_boottime_ms()
+// is monotonically increasing within reasonable boundries.
+//
+TEST_F(TimeTest, test_time_get_os_boottime_ms_increases_upper_bound) {
+  uint32_t t1 = time_get_os_boottime_ms();
+  uint32_t t2 = time_get_os_boottime_ms();
+  ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS);
+}
+
+//
+// Test that the return value of time_get_os_boottime_us()
+// is monotonically increasing within reasonable boundries.
+//
+TEST_F(TimeTest, test_time_get_os_boottime_us_increases_upper_bound) {
+  uint64_t t1 = time_get_os_boottime_us();
+  uint64_t t2 = time_get_os_boottime_us();
+  ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS * 1000);
+}
+
+//
+// Test that the return value of time_get_os_boottime_ms()
+// is increasing.
+//
+TEST_F(TimeTest, test_time_get_os_boottime_ms_increases_lower_bound) {
+  static const uint32_t TEST_TIME_SLEEP_MS = 100;
+  struct timespec delay;
+
+  delay.tv_sec = TEST_TIME_SLEEP_MS / 1000;
+  delay.tv_nsec = 1000 * 1000 * (TEST_TIME_SLEEP_MS % 1000);
+
+  // Take two timestamps with sleep in-between
+  uint32_t t1 = time_get_os_boottime_ms();
+  int err = nanosleep(&delay, &delay);
+  uint32_t t2 = time_get_os_boottime_ms();
+
+  ASSERT_TRUE(err == 0);
+  ASSERT_TRUE((t2 - t1) >= TEST_TIME_SLEEP_MS);
+  ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS);
+}
+
+//
+// Test that the return value of time_get_os_boottime_us()
+// is increasing.
+//
+TEST_F(TimeTest, test_time_get_os_boottime_us_increases_lower_bound) {
+  static const uint64_t TEST_TIME_SLEEP_US = 100 * 1000;
+  struct timespec delay;
+
+  delay.tv_sec = TEST_TIME_SLEEP_US / (1000 * 1000);
+  delay.tv_nsec = 1000 * (TEST_TIME_SLEEP_US % (1000 * 1000));
+
+  // Take two timestamps with sleep in-between
+  uint64_t t1 = time_get_os_boottime_us();
+  int err = nanosleep(&delay, &delay);
+  uint64_t t2 = time_get_os_boottime_us();
+
+  ASSERT_TRUE(err == 0);
+  ASSERT_TRUE(t2 > t1);
+  ASSERT_TRUE((t2 - t1) >= TEST_TIME_SLEEP_US);
+  ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS * 1000);
+}
diff --git a/bt/osi/test/wakelock_test.cc b/bt/osi/test/wakelock_test.cc
new file mode 100644
index 0000000..f62eb80
--- /dev/null
+++ b/bt/osi/test/wakelock_test.cc
@@ -0,0 +1,156 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "osi/include/wakelock.h"
+
+#include "AllocationTestHarness.h"
+
+static bool is_wake_lock_acquired = false;
+
+static int acquire_wake_lock_cb(const char* lock_name) {
+  is_wake_lock_acquired = true;
+  return BT_STATUS_SUCCESS;
+}
+
+static int release_wake_lock_cb(const char* lock_name) {
+  is_wake_lock_acquired = false;
+  return BT_STATUS_SUCCESS;
+}
+
+static bt_os_callouts_t bt_wakelock_callouts = {
+    sizeof(bt_os_callouts_t), NULL, acquire_wake_lock_cb, release_wake_lock_cb};
+
+class WakelockTest : public AllocationTestHarness {
+ protected:
+  virtual void SetUp() {
+    AllocationTestHarness::SetUp();
+
+// TODO (jamuraa): maybe use base::CreateNewTempDirectory instead?
+#if defined(OS_GENERIC)
+    tmp_dir_ = "/tmp/btwlXXXXXX";
+#else
+    tmp_dir_ = "/data/local/tmp/btwlXXXXXX";
+#endif  // !defined(OS_GENERIC)
+
+    char* buffer = const_cast<char*>(tmp_dir_.c_str());
+    char* dtemp = mkdtemp(buffer);
+    if (!dtemp) {
+      perror("Can't make wake lock test directory: ");
+      assert(false);
+    }
+
+    lock_path_ = tmp_dir_ + "/wake_lock";
+    unlock_path_ = tmp_dir_ + "/wake_unlock";
+
+    creat(lock_path_.c_str(), S_IRWXU);
+    creat(unlock_path_.c_str(), S_IRWXU);
+  }
+
+  virtual void TearDown() {
+    is_wake_lock_acquired = false;
+    wakelock_cleanup();
+    wakelock_set_os_callouts(NULL);
+
+    // Clean up the temp wake lock directory
+    unlink(lock_path_.c_str());
+    unlink(unlock_path_.c_str());
+    rmdir(tmp_dir_.c_str());
+
+    AllocationTestHarness::TearDown();
+  }
+
+  //
+  // Test whether the file-based wakelock is acquired.
+  //
+  bool IsFileWakeLockAcquired() {
+    bool acquired = false;
+
+    int lock_fd = open(lock_path_.c_str(), O_RDONLY);
+    assert(lock_fd >= 0);
+
+    int unlock_fd = open(unlock_path_.c_str(), O_RDONLY);
+    assert(unlock_fd >= 0);
+
+    struct stat lock_stat, unlock_stat;
+    fstat(lock_fd, &lock_stat);
+    fstat(unlock_fd, &unlock_stat);
+
+    assert(lock_stat.st_size >= unlock_stat.st_size);
+
+    void* lock_file =
+        mmap(nullptr, lock_stat.st_size, PROT_READ, MAP_PRIVATE, lock_fd, 0);
+
+    void* unlock_file = mmap(nullptr, unlock_stat.st_size, PROT_READ,
+                             MAP_PRIVATE, unlock_fd, 0);
+
+    if (memcmp(lock_file, unlock_file, unlock_stat.st_size) == 0) {
+      acquired = lock_stat.st_size > unlock_stat.st_size;
+    } else {
+      // these files should always either be with a lock that has more,
+      // or equal.
+      assert(false);
+    }
+
+    munmap(lock_file, lock_stat.st_size);
+    munmap(unlock_file, unlock_stat.st_size);
+    close(lock_fd);
+    close(unlock_fd);
+
+    return acquired;
+  }
+
+  std::string tmp_dir_;
+  std::string lock_path_;
+  std::string unlock_path_;
+};
+
+TEST_F(WakelockTest, test_set_os_callouts) {
+  wakelock_set_os_callouts(&bt_wakelock_callouts);
+
+  // Initially, the wakelock is not acquired
+  ASSERT_FALSE(is_wake_lock_acquired);
+
+  for (size_t i = 0; i < 1000; i++) {
+    wakelock_acquire();
+    ASSERT_TRUE(is_wake_lock_acquired);
+    wakelock_release();
+    ASSERT_FALSE(is_wake_lock_acquired);
+  }
+}
+
+TEST_F(WakelockTest, test_set_paths) {
+  wakelock_set_os_callouts(NULL);  // Make sure we use native wakelocks
+  wakelock_set_paths(lock_path_.c_str(), unlock_path_.c_str());
+
+  // Initially, the wakelock is not acquired
+  ASSERT_FALSE(IsFileWakeLockAcquired());
+
+  for (size_t i = 0; i < 1000; i++) {
+    wakelock_acquire();
+    ASSERT_TRUE(IsFileWakeLockAcquired());
+    wakelock_release();
+    ASSERT_FALSE(IsFileWakeLockAcquired());
+  }
+}
diff --git a/bt/service/Android.mk b/bt/service/Android.mk
new file mode 100644
index 0000000..51e5671
--- /dev/null
+++ b/bt/service/Android.mk
@@ -0,0 +1,292 @@
+#
+#  Copyright (C) 2015 Google
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+#
+# Workaround for libchrome and -DNDEBUG usage.
+#
+# Test whether the original HOST_GLOBAL_CFLAGS and
+# TARGET_GLOBAL_CFLAGS contain -DNDEBUG .
+# This is needed as a workaround to make sure that
+# libchrome and local files calling logging::InitLogging()
+# are consistent with the usage of -DNDEBUG .
+# ========================================================
+ifneq (,$(findstring NDEBUG,$(HOST_GLOBAL_CFLAGS)))
+  btservice_orig_HOST_NDEBUG := -DBT_LIBCHROME_NDEBUG
+else
+  btservice_orig_HOST_NDEBUG :=
+endif
+ifneq (,$(findstring NDEBUG,$(TARGET_GLOBAL_CFLAGS)))
+  btservice_orig_TARGET_NDEBUG := -DBT_LIBCHROME_NDEBUG
+else
+  btservice_orig_TARGET_NDEBUG :=
+endif
+
+# Source variables
+# ========================================================
+btserviceCommonSrc := \
+	common/bluetooth/adapter_state.cc \
+	common/bluetooth/advertise_data.cc \
+	common/bluetooth/advertise_settings.cc \
+	common/bluetooth/descriptor.cc \
+	common/bluetooth/characteristic.cc \
+	common/bluetooth/scan_filter.cc \
+	common/bluetooth/scan_result.cc \
+	common/bluetooth/scan_settings.cc \
+	common/bluetooth/service.cc \
+	common/bluetooth/util/address_helper.cc \
+	common/bluetooth/util/atomic_string.cc \
+	common/bluetooth/uuid.cc
+
+btserviceCommonBinderSrc := \
+	common/android/bluetooth/IBluetooth.aidl \
+	common/android/bluetooth/IBluetoothCallback.aidl \
+	common/android/bluetooth/IBluetoothGattClient.aidl \
+	common/android/bluetooth/IBluetoothGattClientCallback.aidl \
+	common/android/bluetooth/IBluetoothGattServer.aidl \
+	common/android/bluetooth/IBluetoothGattServerCallback.aidl \
+	common/android/bluetooth/IBluetoothLeAdvertiser.aidl \
+	common/android/bluetooth/IBluetoothLeAdvertiserCallback.aidl \
+	common/android/bluetooth/IBluetoothLeScanner.aidl \
+	common/android/bluetooth/IBluetoothLeScannerCallback.aidl \
+	common/android/bluetooth/IBluetoothLowEnergy.aidl \
+	common/android/bluetooth/IBluetoothLowEnergyCallback.aidl \
+	common/android/bluetooth/advertise_data.cc \
+	common/android/bluetooth/advertise_settings.cc \
+	common/android/bluetooth/bluetooth_gatt_characteristic.cc \
+	common/android/bluetooth/bluetooth_gatt_descriptor.cc \
+	common/android/bluetooth/bluetooth_gatt_included_service.cc \
+	common/android/bluetooth/bluetooth_gatt_service.cc \
+	common/android/bluetooth/scan_filter.cc \
+	common/android/bluetooth/scan_result.cc \
+	common/android/bluetooth/scan_settings.cc \
+	common/android/bluetooth/uuid.cc \
+
+btserviceCommonAidlInclude := \
+	system/bt/service/common \
+	frameworks/native/aidl/binder
+
+btserviceDaemonSrc := \
+	adapter.cc \
+	daemon.cc \
+	gatt_client.cc \
+	gatt_server.cc \
+	gatt_server_old.cc \
+	hal/bluetooth_gatt_interface.cc \
+	hal/bluetooth_interface.cc \
+	ipc/ipc_handler.cc \
+	ipc/ipc_manager.cc \
+	logging_helpers.cc \
+	low_energy_advertiser.cc \
+	low_energy_scanner.cc \
+	low_energy_client.cc \
+	settings.cc
+
+btserviceLinuxSrc := \
+	ipc/ipc_handler_linux.cc \
+	ipc/linux_ipc_host.cc
+
+btserviceBinderDaemonImplSrc := \
+	ipc/binder/bluetooth_binder_server.cc \
+	ipc/binder/bluetooth_gatt_client_binder_server.cc \
+	ipc/binder/bluetooth_gatt_server_binder_server.cc \
+	ipc/binder/bluetooth_le_advertiser_binder_server.cc \
+	ipc/binder/bluetooth_le_scanner_binder_server.cc \
+	ipc/binder/bluetooth_low_energy_binder_server.cc \
+	ipc/binder/interface_with_instances_base.cc \
+	ipc/binder/ipc_handler_binder.cc \
+
+btserviceBinderDaemonSrc := \
+	$(btserviceCommonBinderSrc) \
+	$(btserviceBinderDaemonImplSrc)
+
+btserviceCommonIncludes := \
+	$(LOCAL_PATH)/../ \
+	$(LOCAL_PATH)/common
+
+# Main unit test sources. These get built for host and target.
+# ========================================================
+btserviceBaseTestSrc := \
+	hal/fake_bluetooth_gatt_interface.cc \
+	hal/fake_bluetooth_interface.cc \
+	test/adapter_unittest.cc \
+	test/advertise_data_unittest.cc \
+	test/fake_hal_util.cc \
+	test/gatt_client_unittest.cc \
+	test/gatt_server_unittest.cc \
+	test/low_energy_advertiser_unittest.cc \
+	test/low_energy_client_unittest.cc \
+	test/low_energy_scanner_unittest.cc \
+	test/settings_unittest.cc \
+	test/util_unittest.cc \
+	test/uuid_unittest.cc
+
+# Native system service for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_SRC_FILES := \
+	$(btserviceCommonSrc) \
+	$(btserviceBinderDaemonSrc) \
+	$(btserviceLinuxSrc) \
+	$(btserviceDaemonSrc) \
+	main.cc
+LOCAL_AIDL_INCLUDES = $(btserviceCommonAidlInclude)
+LOCAL_C_INCLUDES := $(btserviceCommonIncludes)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := bluetoothtbd
+LOCAL_REQUIRED_MODULES := bluetooth.default
+LOCAL_STATIC_LIBRARIES := libbtcore
+LOCAL_SHARED_LIBRARIES := \
+	libbinder \
+	libchrome \
+	libcutils \
+	libhardware \
+	liblog \
+	libutils
+LOCAL_INIT_RC := bluetoothtbd.rc
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS) $(btservice_orig_TARGET_NDEBUG)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_EXECUTABLE)
+
+# Native system service unit tests for host
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_SRC_FILES := \
+	$(btserviceBaseTestSrc) \
+	$(btserviceCommonSrc) \
+	$(btserviceDaemonSrc) \
+	test/main.cc \
+	test/stub_ipc_handler_binder.cc
+ifeq ($(HOST_OS),linux)
+LOCAL_SRC_FILES += \
+	$(btserviceLinuxSrc) \
+	test/ipc_linux_unittest.cc
+LOCAL_LDLIBS += -lrt
+else
+LOCAL_SRC_FILES += \
+	test/stub_ipc_handler_linux.cc
+endif
+LOCAL_C_INCLUDES := $(btserviceCommonIncludes)
+LOCAL_MODULE_TAGS := debug tests
+LOCAL_MODULE := bluetoothtbd-host_test
+LOCAL_SHARED_LIBRARIES := libchrome
+LOCAL_STATIC_LIBRARIES := libgmock_host libgtest_host liblog
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS) $(btservice_orig_HOST_NDEBUG)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_HOST_NATIVE_TEST)
+
+# Native system service unit tests for target.
+# This includes Binder related tests that can only be run
+# on target.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_SRC_FILES := \
+	$(btserviceBaseTestSrc) \
+	$(btserviceCommonSrc) \
+	$(btserviceBinderDaemonSrc) \
+	$(btserviceDaemonSrc) \
+	test/main.cc \
+	test/parcelable_unittest.cc \
+	test/ParcelableTest.aidl
+LOCAL_AIDL_INCLUDES := $(btserviceCommonAidlInclude)
+LOCAL_AIDL_INCLUDES += ./
+LOCAL_C_INCLUDES := $(btserviceCommonIncludes)
+LOCAL_MODULE_TAGS := debug tests
+LOCAL_MODULE := bluetoothtbd_test
+LOCAL_SHARED_LIBRARIES := \
+	libbinder \
+	libchrome \
+	libutils
+LOCAL_STATIC_LIBRARIES := libgmock libgtest liblog
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS) $(btservice_orig_TARGET_NDEBUG)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_NATIVE_TEST)
+
+# Client library for interacting with Bluetooth daemon
+# This is a static library for target.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_SRC_FILES := \
+	$(btserviceCommonSrc) \
+	$(btserviceCommonBinderSrc)
+LOCAL_AIDL_INCLUDES := $(btserviceCommonAidlInclude)
+LOCAL_C_INCLUDES := $(btserviceCommonIncludes)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/common
+LOCAL_MODULE := libbluetooth-client
+LOCAL_SHARED_LIBRARIES := libbinder libchrome libutils
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS) $(btservice_orig_TARGET_NDEBUG)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_STATIC_LIBRARY)
+
+# Native system service CLI for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_SRC_FILES := client/main.cc
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := bluetooth-cli
+LOCAL_STATIC_LIBRARIES := libbluetooth-client
+LOCAL_SHARED_LIBRARIES := \
+	libbinder \
+	libchrome \
+	libutils
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS) $(btservice_orig_TARGET_NDEBUG)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_EXECUTABLE)
+
+# Heart Rate GATT service example for target
+# ========================================================
+# TODO(armansito): Move this into a new makefile under examples/ once we build
+# a client static library that the examples can depend on.
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_SRC_FILES := \
+	example/heart_rate/heart_rate_server.cc \
+	example/heart_rate/server_main.cc
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := bt-example-hr-server
+LOCAL_STATIC_LIBRARIES := libbluetooth-client
+LOCAL_SHARED_LIBRARIES := \
+	libbinder \
+	libchrome \
+	libutils
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS) $(btservice_orig_TARGET_NDEBUG)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_EXECUTABLE)
diff --git a/bt/service/BUILD.gn b/bt/service/BUILD.gn
new file mode 100644
index 0000000..19134c1
--- /dev/null
+++ b/bt/service/BUILD.gn
@@ -0,0 +1,99 @@
+#
+#  Copyright (C) 2015 Google
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+source_set("service") {
+  sources = [
+    "adapter.cc",
+    "common/bluetooth/adapter_state.cc",
+    "common/bluetooth/advertise_data.cc",
+    "common/bluetooth/advertise_settings.cc",
+    "common/bluetooth/characteristic.cc",
+    "common/bluetooth/descriptor.cc",
+    "common/bluetooth/scan_filter.cc",
+    "common/bluetooth/scan_result.cc",
+    "common/bluetooth/scan_settings.cc",
+    "common/bluetooth/service.cc",
+    "common/bluetooth/util/address_helper.cc",
+    "common/bluetooth/util/atomic_string.cc",
+    "common/bluetooth/uuid.cc",
+    "daemon.cc",
+    "gatt_client.cc",
+    "gatt_server.cc",
+    "gatt_server_old.cc",
+    "hal/bluetooth_gatt_interface.cc",
+    "hal/bluetooth_interface.cc",
+    "hal/fake_bluetooth_gatt_interface.cc",
+    "hal/fake_bluetooth_interface.cc",
+    "ipc/ipc_handler.cc",
+    "ipc/ipc_manager.cc",
+    "ipc/linux_ipc_host.cc",
+    "logging_helpers.cc",
+    "low_energy_advertiser.cc",
+    "low_energy_scanner.cc",
+    "low_energy_client.cc",
+    "settings.cc",
+  ]
+
+  include_dirs = [
+    "//",
+    "//service/common",
+    "//third_party/modp_b64/modp64",
+    "//third_party/libhardware/include",
+  ]
+
+  deps = [
+    "//third_party/libchrome:base"
+  ]
+}
+
+executable("bluetoothtbd") {
+  sources = [
+    "main.cc",
+  ]
+
+  deps = [
+    ":service",
+    "//btcore",
+    "//third_party/libchrome:base",
+    "//third_party/modp_b64",
+  ]
+
+  include_dirs = [ "//" ]
+
+  libs = [
+    "-ldl",
+    "-lpthread",
+    "-lrt",
+  ]
+}
+
+executable("service_unittests") {
+  testonly = true
+  sources = [
+    "test/fake_hal_util.cc",
+    "test/settings_unittest.cc",
+    "test/uuid_unittest.cc",
+  ]
+
+  include_dirs = [ "//" ]
+
+  deps = [
+    ":service",
+    "//third_party/googletest:gmock_main",
+    "//third_party/libchrome:base",
+    "//third_party/modp_b64",
+  ]
+}
diff --git a/bt/service/adapter.cc b/bt/service/adapter.cc
new file mode 100644
index 0000000..e97b595
--- /dev/null
+++ b/bt/service/adapter.cc
@@ -0,0 +1,421 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/adapter.h"
+
+#include <atomic>
+#include <mutex>
+#include <string>
+#include <unordered_set>
+
+#include <base/logging.h>
+#include <base/observer_list.h>
+
+#include "service/common/bluetooth/util/atomic_string.h"
+#include "service/gatt_client.h"
+#include "service/gatt_server.h"
+#include "service/hal/bluetooth_interface.h"
+#include "service/logging_helpers.h"
+#include "service/low_energy_advertiser.h"
+#include "service/low_energy_scanner.h"
+#include "service/low_energy_client.h"
+
+using std::lock_guard;
+using std::mutex;
+
+namespace bluetooth {
+
+// static
+const char Adapter::kDefaultAddress[] = "00:00:00:00:00:00";
+// static
+const char Adapter::kDefaultName[] = "not-initialized";
+
+// TODO(armansito): The following constants come straight from
+// packages/apps/Bluetooth/src/c/a/b/btservice/AdapterService.java. It would be
+// nice to know if there were a way to obtain these values from the stack
+// instead of hardcoding them here.
+
+// The minimum number of advertising instances required for multi-advertisement
+// support.
+const int kMinAdvInstancesForMultiAdv = 5;
+
+// Used when determining if offloaded scan filtering is supported.
+const int kMinOffloadedFilters = 10;
+
+// Used when determining if offloaded scan batching is supported.
+const int kMinOffloadedScanStorageBytes = 1024;
+
+void Adapter::Observer::OnAdapterStateChanged(Adapter* adapter,
+                                              AdapterState prev_state,
+                                              AdapterState new_state) {
+  // Default implementation does nothing
+}
+
+void Adapter::Observer::OnDeviceConnectionStateChanged(
+    Adapter* adapter, const std::string& device_address, bool connected) {
+  // Default implementation does nothing
+}
+
+// The real Adapter implementation used in production.
+class AdapterImpl : public Adapter,
+                    public hal::BluetoothInterface::Observer {
+ public:
+  AdapterImpl()
+    : state_(ADAPTER_STATE_OFF),
+      address_(kDefaultAddress),
+      name_(kDefaultName) {
+    memset(&local_le_features_, 0, sizeof(local_le_features_));
+    hal::BluetoothInterface::Get()->AddObserver(this);
+    ble_client_factory_.reset(new LowEnergyClientFactory(*this));
+    ble_advertiser_factory_.reset(new LowEnergyAdvertiserFactory());
+    ble_scanner_factory_.reset(new LowEnergyScannerFactory(*this));
+    gatt_client_factory_.reset(new GattClientFactory());
+    gatt_server_factory_.reset(new GattServerFactory());
+    hal::BluetoothInterface::Get()->GetHALInterface()->get_adapter_properties();
+  }
+
+  ~AdapterImpl() override {
+    hal::BluetoothInterface::Get()->RemoveObserver(this);
+  }
+
+  void AddObserver(Adapter::Observer* observer) override {
+    lock_guard<mutex> lock(observers_lock_);
+    observers_.AddObserver(observer);
+  }
+
+  void RemoveObserver(Adapter::Observer* observer) override {
+    lock_guard<mutex> lock(observers_lock_);
+    observers_.RemoveObserver(observer);
+  }
+
+  AdapterState GetState() const override {
+    return state_.load();
+  }
+
+  bool IsEnabled() const override {
+    return state_.load() == ADAPTER_STATE_ON;
+  }
+
+  bool Enable(bool start_restricted) override {
+    AdapterState current_state = GetState();
+    if (current_state != ADAPTER_STATE_OFF) {
+      LOG(INFO) << "Adapter not disabled - state: "
+                << AdapterStateToString(current_state);
+      return false;
+    }
+
+    // Set the state before calling enable() as there might be a race between
+    // here and the AdapterStateChangedCallback.
+    state_ = ADAPTER_STATE_TURNING_ON;
+    NotifyAdapterStateChanged(current_state, state_);
+
+    int status = hal::BluetoothInterface::Get()->GetHALInterface()->enable(start_restricted);
+    if (status != BT_STATUS_SUCCESS) {
+      LOG(ERROR) << "Failed to enable Bluetooth - status: "
+                 << BtStatusText((const bt_status_t)status);
+      state_ = ADAPTER_STATE_OFF;
+      NotifyAdapterStateChanged(ADAPTER_STATE_TURNING_ON, state_);
+      return false;
+    }
+
+    return true;
+  }
+
+  bool Disable() override {
+    if (!IsEnabled()) {
+      LOG(INFO) << "Adapter is not enabled";
+      return false;
+    }
+
+    AdapterState current_state = GetState();
+
+    // Set the state before calling enable() as there might be a race between
+    // here and the AdapterStateChangedCallback.
+    state_ = ADAPTER_STATE_TURNING_OFF;
+    NotifyAdapterStateChanged(current_state, state_);
+
+    int status = hal::BluetoothInterface::Get()->GetHALInterface()->disable();
+    if (status != BT_STATUS_SUCCESS) {
+      LOG(ERROR) << "Failed to disable Bluetooth - status: "
+                 << BtStatusText((const bt_status_t)status);
+      state_ = current_state;
+      NotifyAdapterStateChanged(ADAPTER_STATE_TURNING_OFF, state_);
+      return false;
+    }
+
+    return true;
+  }
+
+  std::string GetName() const override {
+    return name_.Get();
+  }
+
+  bool SetName(const std::string& name) override {
+    bt_bdname_t hal_name;
+    size_t max_name_len = sizeof(hal_name.name);
+
+    // Include the \0 byte in size measurement.
+    if (name.length() >= max_name_len) {
+      LOG(ERROR) << "Given name \"" << name << "\" is larger than maximum"
+                 << " allowed size: " << max_name_len;
+      return false;
+    }
+
+    strncpy(reinterpret_cast<char*>(hal_name.name), name.c_str(),
+            name.length() + 1);
+
+    VLOG(1) << "Setting adapter name: " << name;
+
+    if (!SetAdapterProperty(BT_PROPERTY_BDNAME, &hal_name, sizeof(hal_name))) {
+      LOG(ERROR) << "Failed to set adapter name: " << name;
+      return false;
+    }
+
+    return true;
+  }
+
+  std::string GetAddress() const override {
+    return address_.Get();
+  }
+
+  bool IsMultiAdvertisementSupported() override {
+    lock_guard<mutex> lock(local_le_features_lock_);
+    return local_le_features_.max_adv_instance >= kMinAdvInstancesForMultiAdv;
+  }
+
+  bool IsDeviceConnected(const std::string& device_address) override {
+    lock_guard<mutex> lock(connected_devices_lock_);
+    return connected_devices_.find(device_address) != connected_devices_.end();
+  }
+
+  int GetTotalNumberOfTrackableAdvertisements() override {
+    lock_guard<mutex> lock(local_le_features_lock_);
+    return local_le_features_.total_trackable_advertisers;
+  }
+
+  bool IsOffloadedFilteringSupported() override {
+    lock_guard<mutex> lock(local_le_features_lock_);
+    return local_le_features_.max_adv_filter_supported >= kMinOffloadedFilters;
+  }
+
+  bool IsOffloadedScanBatchingSupported() override {
+    lock_guard<mutex> lock(local_le_features_lock_);
+    return local_le_features_.scan_result_storage_size >=
+        kMinOffloadedScanStorageBytes;
+  }
+
+  LowEnergyClientFactory* GetLowEnergyClientFactory() const override {
+    return ble_client_factory_.get();
+  }
+
+  LowEnergyAdvertiserFactory* GetLeAdvertiserFactory() const override {
+    return ble_advertiser_factory_.get();
+  }
+
+  LowEnergyScannerFactory* GetLeScannerFactory() const override {
+    return ble_scanner_factory_.get();
+  }
+
+  GattClientFactory* GetGattClientFactory() const override {
+    return gatt_client_factory_.get();
+  }
+
+  GattServerFactory* GetGattServerFactory() const override {
+    return gatt_server_factory_.get();
+  }
+
+  // hal::BluetoothInterface::Observer overrides.
+  void AdapterStateChangedCallback(bt_state_t state) override {
+    LOG(INFO) << "Adapter state changed: " << BtStateText(state);
+
+    AdapterState prev_state = GetState();
+
+    switch (state) {
+    case BT_STATE_OFF:
+      state_ = ADAPTER_STATE_OFF;
+      break;
+
+    case BT_STATE_ON:
+      state_ = ADAPTER_STATE_ON;
+      break;
+
+    default:
+      NOTREACHED();
+    }
+
+    NotifyAdapterStateChanged(prev_state, GetState());
+  }
+
+  void AdapterPropertiesCallback(bt_status_t status,
+                                 int num_properties,
+                                 bt_property_t* properties) override {
+    LOG(INFO) << "Adapter properties changed";
+
+    if (status != BT_STATUS_SUCCESS) {
+      LOG(ERROR) << "status: " << BtStatusText(status);
+      return;
+    }
+
+    for (int i = 0; i < num_properties; i++) {
+      bt_property_t* property = properties + i;
+      switch (property->type) {
+        case BT_PROPERTY_BDADDR: {
+          std::string address = BtAddrString(reinterpret_cast<bt_bdaddr_t*>(
+              property->val));
+          LOG(INFO) << "Adapter address changed: " << address;
+          address_.Set(address);
+          break;
+        }
+        case BT_PROPERTY_BDNAME: {
+          bt_bdname_t* hal_name = reinterpret_cast<bt_bdname_t*>(property->val);
+          std::string name = reinterpret_cast<char*>(hal_name->name);
+          LOG(INFO) << "Adapter name changed: " << name;
+          name_.Set(name);
+          break;
+        }
+        case BT_PROPERTY_LOCAL_LE_FEATURES: {
+          lock_guard<mutex> lock(local_le_features_lock_);
+          if (property->len != sizeof(bt_local_le_features_t)) {
+            LOG(WARNING) << "Malformed value received for property: "
+                         << "BT_PROPERTY_LOCAL_LE_FEATURES";
+            break;
+          }
+          bt_local_le_features_t* features =
+              reinterpret_cast<bt_local_le_features_t*>(property->val);
+          memcpy(&local_le_features_, features, sizeof(*features));
+          LOG(INFO) << "Supported LE features updated";
+          break;
+        }
+        default:
+          VLOG(1) << "Unhandled adapter property: "
+                  << BtPropertyText(property->type);
+          break;
+      }
+
+      // TODO(armansito): notify others of the updated properties
+    }
+  }
+
+  void AclStateChangedCallback(bt_status_t status,
+                               const bt_bdaddr_t& remote_bdaddr,
+                               bt_acl_state_t state) override {
+    std::string device_address = BtAddrString(&remote_bdaddr);
+    bool connected = (state == BT_ACL_STATE_CONNECTED);
+    LOG(INFO) << "ACL state changed: " << device_address << " - connected: "
+              << (connected ? "true" : "false");
+
+    // If this is reported with an error status, I suppose the best thing we can
+    // do is to log it and ignore the event.
+    if (status != BT_STATUS_SUCCESS) {
+      LOG(ERROR) << "status: " << BtStatusText(status);
+      return;
+    }
+
+    // Introduce a scope to manage |connected_devices_lock_| with RAII.
+    {
+      lock_guard<mutex> lock(connected_devices_lock_);
+      if (connected)
+        connected_devices_.insert(device_address);
+      else
+        connected_devices_.erase(device_address);
+    }
+
+    lock_guard<mutex> lock(observers_lock_);
+    FOR_EACH_OBSERVER(
+        Adapter::Observer, observers_,
+        OnDeviceConnectionStateChanged(this, device_address, connected));
+  }
+
+  // Sends a request to set the given HAL adapter property type and value.
+  bool SetAdapterProperty(bt_property_type_t type, void* value, int length) {
+    CHECK(length > 0);
+    CHECK(value);
+
+    bt_property_t property;
+    property.len = length;
+    property.val = value;
+    property.type = type;
+
+    int status = hal::BluetoothInterface::Get()->GetHALInterface()->
+        set_adapter_property(&property);
+    if (status != BT_STATUS_SUCCESS) {
+      VLOG(1) << "Failed to set property";
+      return false;
+    }
+
+    return true;
+  }
+
+  // Helper for invoking the AdapterStateChanged observer method.
+  void NotifyAdapterStateChanged(AdapterState prev_state,
+                                 AdapterState new_state) {
+    if (prev_state == new_state)
+      return;
+
+    lock_guard<mutex> lock(observers_lock_);
+    FOR_EACH_OBSERVER(Adapter::Observer, observers_,
+                      OnAdapterStateChanged(this, prev_state, new_state));
+  }
+
+ private:
+  // The current adapter state.
+  std::atomic<AdapterState> state_;
+
+  // The Bluetooth device address of the local adapter in string from
+  // (i.e.. XX:XX:XX:XX:XX:XX)
+  util::AtomicString address_;
+
+  // The current local adapter name.
+  util::AtomicString name_;
+
+  // The current set of supported LE features as obtained from the stack. The
+  // values here are all initially set to 0 and updated when the corresponding
+  // adapter property has been received from the stack.
+  std::mutex local_le_features_lock_;
+  bt_local_le_features_t local_le_features_;
+
+  // List of observers that are interested in notifications from us.
+  std::mutex observers_lock_;
+  base::ObserverList<Adapter::Observer> observers_;
+
+  // List of devices addresses that are currently connected.
+  std::mutex connected_devices_lock_;
+  std::unordered_set<std::string> connected_devices_;
+
+  // Factory used to create per-app LowEnergyClient instances.
+  std::unique_ptr<LowEnergyClientFactory> ble_client_factory_;
+
+  // Factory used to create per-app LeAdvertiser instances.
+  std::unique_ptr<LowEnergyAdvertiserFactory> ble_advertiser_factory_;
+
+  // Factory used to create per-app LeScanner instances.
+  std::unique_ptr<LowEnergyScannerFactory> ble_scanner_factory_;
+
+  // Factory used to create per-app GattClient instances.
+  std::unique_ptr<GattClientFactory> gatt_client_factory_;
+
+  // Factory used to create per-app GattServer instances.
+  std::unique_ptr<GattServerFactory> gatt_server_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(AdapterImpl);
+};
+
+// static
+std::unique_ptr<Adapter> Adapter::Create() {
+  return std::unique_ptr<Adapter>(new AdapterImpl());
+}
+
+}  // namespace bluetooth
diff --git a/bt/service/adapter.h b/bt/service/adapter.h
new file mode 100644
index 0000000..75a5491
--- /dev/null
+++ b/bt/service/adapter.h
@@ -0,0 +1,153 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <base/macros.h>
+
+#include "service/common/bluetooth/adapter_state.h"
+
+namespace bluetooth {
+
+class GattClientFactory;
+class GattServerFactory;
+class LowEnergyAdvertiserFactory;
+class LowEnergyScannerFactory;
+class LowEnergyClientFactory;
+
+// Represents the local Bluetooth adapter.
+class Adapter {
+ public:
+  // The default values returned before the Adapter is fully initialized and
+  // powered. The complete values for these fields are obtained following a
+  // successful call to "Enable".
+  static const char kDefaultAddress[];
+  static const char kDefaultName[];
+
+  // Observer interface allows other classes to receive notifications from us.
+  // All of the methods in this interface are declared as optional to allow
+  // different layers to process only those events that they are interested in.
+  //
+  // All methods take in an |adapter| argument which points to the Adapter
+  // object that the Observer instance was added to.
+  class Observer {
+   public:
+    virtual ~Observer() = default;
+
+    // Called when there is a change in the state of the local Bluetooth
+    // |adapter| from |prev_state| to |new_state|.
+    virtual void OnAdapterStateChanged(Adapter* adapter,
+                                       AdapterState prev_state,
+                                       AdapterState new_state);
+
+    // Called when there is a change in the connection state between the local
+    // |adapter| and a remote device with address |device_address|. If the ACL
+    // state changes from disconnected to connected, then |connected| will be
+    // true and vice versa.
+    virtual void OnDeviceConnectionStateChanged(
+        Adapter* adapter, const std::string& device_address, bool connected);
+  };
+
+  // Returns an Adapter implementation to be used in production. Don't use these
+  // in tests; use MockAdapter instead.
+  static std::unique_ptr<Adapter> Create();
+
+  virtual ~Adapter() = default;
+
+  // Add or remove an observer.
+  virtual void AddObserver(Observer* observer) = 0;
+  virtual void RemoveObserver(Observer* observer) = 0;
+
+  // Returns the current Adapter state.
+  virtual AdapterState GetState() const = 0;
+
+  // Returns true, if the adapter radio is current powered.
+  virtual bool IsEnabled() const = 0;
+
+  // Enables Bluetooth. This method will send a request to the Bluetooth adapter
+  // to power up its radio. Returns true, if the request was successfully sent
+  // to the controller, otherwise returns false. A successful call to this
+  // method only means that the enable request has been sent to the Bluetooth
+  // controller and does not imply that the operation itself succeeded.
+  // The |start_restricted| flag enables the adapter in restricted mode. In
+  // restricted mode, bonds that are created are marked as restricted in the
+  // config file. These devices are deleted upon leaving restricted mode.
+  virtual bool Enable(bool start_restricted) = 0;
+
+  // Powers off the Bluetooth radio. Returns true, if the disable request was
+  // successfully sent to the Bluetooth controller.
+  virtual bool Disable() = 0;
+
+  // Returns the name currently assigned to the local adapter.
+  virtual std::string GetName() const = 0;
+
+  // Sets the name assigned to the local Bluetooth adapter. This is the name
+  // that the local controller will present to remote devices.
+  virtual bool SetName(const std::string& name) = 0;
+
+  // Returns the local adapter addess in string form (XX:XX:XX:XX:XX:XX).
+  virtual std::string GetAddress() const = 0;
+
+  // Returns true if the local adapter supports the Low-Energy
+  // multi-advertisement feature.
+  virtual bool IsMultiAdvertisementSupported() = 0;
+
+  // Returns true if the remote device with address |device_address| is
+  // currently connected. This is not a const method as it modifies the state of
+  // the associated internal mutex.
+  virtual bool IsDeviceConnected(const std::string& device_address) = 0;
+
+  // Returns the total number of trackable advertisements as supported by the
+  // underlying hardware.
+  virtual int GetTotalNumberOfTrackableAdvertisements() = 0;
+
+  // Returns true if hardware-backed scan filtering is supported.
+  virtual bool IsOffloadedFilteringSupported() = 0;
+
+  // Returns true if hardware-backed batch scanning is supported.
+  virtual bool IsOffloadedScanBatchingSupported() = 0;
+
+  // Returns a pointer to the LowEnergyClientFactory. This can be used to
+  // register per-application LowEnergyClient instances to perform BLE GAP
+  // operations.
+  virtual LowEnergyClientFactory* GetLowEnergyClientFactory() const = 0;
+
+  // Returns a pointer to the LowEnergyScannerFactory. This can be used to
+  // register per-application LowEnergyScanner instances to perform scanning.
+  virtual LowEnergyScannerFactory* GetLeScannerFactory() const = 0;
+
+  // Returns a pointer to the LowEnergyAdvertiserFactory. This can be used to
+  // register per-application LowEnergyAdvertiser instances to perform advertising.
+  virtual LowEnergyAdvertiserFactory* GetLeAdvertiserFactory() const = 0;
+
+  // Returns a pointer to the GattClientFactory. This can be used to register
+  // per-application GATT server instances.
+  virtual GattClientFactory* GetGattClientFactory() const = 0;
+
+  // Returns a pointer to the GattServerFactory. This can be used to register
+  // per-application GATT server instances.
+  virtual GattServerFactory* GetGattServerFactory() const = 0;
+
+ protected:
+  Adapter() = default;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Adapter);
+};
+
+}  // namespace bluetooth
diff --git a/bt/service/bluetooth_instance.h b/bt/service/bluetooth_instance.h
new file mode 100644
index 0000000..c2e06f3
--- /dev/null
+++ b/bt/service/bluetooth_instance.h
@@ -0,0 +1,75 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <memory>
+
+#include <base/macros.h>
+
+#include "service/common/bluetooth/low_energy_constants.h"
+#include "service/common/bluetooth/uuid.h"
+
+namespace bluetooth {
+
+// A BluetoothInstance represents an application's handle to an instance
+// that is registered with the underlying Bluetooth stack using a UUID and has a
+// stack-assigned integer "instance_id" ID associated with it.
+class BluetoothInstance {
+ public:
+  virtual ~BluetoothInstance() = default;
+
+  // Returns the app-specific unique ID used while registering this instance.
+  virtual const UUID& GetAppIdentifier() const = 0;
+
+  // Returns the HAL "interface ID" assigned to this instance by the stack.
+  virtual int GetInstanceId() const = 0;
+
+ protected:
+  // Constructor shouldn't be called directly as instances are meant to be
+  // obtained from the factory.
+  BluetoothInstance() = default;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BluetoothInstance);
+};
+
+// A BluetoothInstanceFactory provides a common interface for factory
+// classes that handle asynchronously registering a per-application instance of
+// a BluetoothInstance with the underlying stack.
+class BluetoothInstanceFactory {
+ public:
+  BluetoothInstanceFactory() = default;
+  virtual ~BluetoothInstanceFactory() = default;
+
+  // Callback invoked as a result of a call to RegisterInstance.
+  using RegisterCallback = std::function<void(
+      BLEStatus status, const UUID& app_uuid,
+      std::unique_ptr<BluetoothInstance> instance)>;
+
+  // Registers an instance for the given unique identifier |app_uuid|.
+  // On success, this asynchronously invokes |callback| with a unique pointer
+  // to a BluetoothInstance whose ownership can be taken by the caller. In
+  // the case of an error, the pointer will contain nullptr.
+  virtual bool RegisterInstance(const UUID& app_uuid,
+                                const RegisterCallback& callback) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BluetoothInstanceFactory);
+};
+
+}  // namespace bluetooth
diff --git a/bt/service/bluetoothtbd.rc b/bt/service/bluetoothtbd.rc
new file mode 100644
index 0000000..ee7c27d
--- /dev/null
+++ b/bt/service/bluetoothtbd.rc
@@ -0,0 +1,4 @@
+service bluetoothtbd /system/bin/bluetoothtbd
+    class main
+    user root
+    group wakelock net_bt_admin net_bt_stack net_admin
diff --git a/bt/service/client/main.cc b/bt/service/client/main.cc
new file mode 100644
index 0000000..442b751
--- /dev/null
+++ b/bt/service/client/main.cc
@@ -0,0 +1,1113 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 <iostream>
+#include <string>
+
+#ifdef BT_LIBCHROME_NDEBUG
+#define NDEBUG 1
+#endif
+
+#include <base/at_exit.h>
+#include <base/command_line.h>
+#include <base/logging.h>
+#include <base/macros.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_split.h>
+#include <base/strings/string_util.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include <bluetooth/adapter_state.h>
+#include <android/bluetooth/BnBluetoothCallback.h>
+#include <android/bluetooth/BnBluetoothGattClientCallback.h>
+#include <android/bluetooth/BnBluetoothLowEnergyCallback.h>
+#include <android/bluetooth/BnBluetoothLeAdvertiserCallback.h>
+#include <android/bluetooth/BnBluetoothLeScannerCallback.h>
+#include <android/bluetooth/IBluetooth.h>
+#include <android/bluetooth/IBluetoothGattClient.h>
+#include <android/bluetooth/IBluetoothLeAdvertiser.h>
+#include <android/bluetooth/IBluetoothLeScanner.h>
+#include <android/bluetooth/IBluetoothLowEnergy.h>
+#include <bluetooth/low_energy_constants.h>
+#include <bluetooth/scan_filter.h>
+#include <bluetooth/scan_settings.h>
+#include <bluetooth/uuid.h>
+
+using namespace std;
+
+using android::sp;
+using android::String8;
+using android::String16;
+using android::binder::Status;
+using android::OK;
+using android::getService;
+
+using android::bluetooth::IBluetooth;
+using android::bluetooth::IBluetoothGattClient;
+using android::bluetooth::IBluetoothLeAdvertiser;
+using android::bluetooth::IBluetoothLeScanner;
+using android::bluetooth::IBluetoothLowEnergy;
+
+namespace {
+
+#define COLOR_OFF "\x1B[0m"
+#define COLOR_RED "\x1B[0;91m"
+#define COLOR_GREEN "\x1B[0;92m"
+#define COLOR_YELLOW "\x1B[0;93m"
+#define COLOR_BLUE "\x1B[0;94m"
+#define COLOR_MAGENTA "\x1B[0;95m"
+#define COLOR_BOLDGRAY "\x1B[1;30m"
+#define COLOR_BOLDWHITE "\x1B[1;37m"
+#define COLOR_BOLDYELLOW "\x1B[1;93m"
+#define CLEAR_LINE "\x1B[2K"
+
+#define CHECK_ARGS_COUNT(args, op, num, msg) \
+  if (!((args).size() op num)) {             \
+    PrintError(msg);                         \
+    return;                                  \
+  }
+#define CHECK_NO_ARGS(args) \
+  CHECK_ARGS_COUNT(args, ==, 0, "Expected no arguments")
+
+// TODO(armansito): Clean up this code. Right now everything is in this
+// monolithic file. We should organize this into different classes for command
+// handling, console output/printing, callback handling, etc.
+// (See http://b/23387611)
+
+// Used to synchronize the printing of the command-line prompt and incoming
+// Binder callbacks.
+std::atomic_bool showing_prompt(false);
+
+// The registered IBluetoothLowEnergy client handle. If |ble_registering| is
+// true then an operation to register the client is in progress.
+std::atomic_bool ble_registering(false);
+std::atomic_int ble_client_id(0);
+
+// The registered IBluetoothLeAdvertiser handle. If |ble_advertiser_registering| is
+// true then an operation to register the advertiser is in progress.
+std::atomic_bool ble_advertiser_registering(false);
+std::atomic_int ble_advertiser_id(0);
+
+// The registered IBluetoothLeScanner handle. If |ble_scanner_registering| is
+// true then an operation to register the scanner is in progress.
+std::atomic_bool ble_scanner_registering(false);
+std::atomic_int ble_scanner_id(0);
+
+// The registered IBluetoothGattClient client handle. If |gatt_registering| is
+// true then an operation to register the client is in progress.
+std::atomic_bool gatt_registering(false);
+std::atomic_int gatt_client_id(0);
+
+// True if we should dump the scan record bytes for incoming scan results.
+std::atomic_bool dump_scan_record(false);
+
+// True if the remote process has died and we should exit.
+std::atomic_bool should_exit(false);
+
+std::string kServiceName = "bluetooth-service";
+
+void PrintPrompt() { cout << COLOR_BLUE "[FCLI] " COLOR_OFF << flush; }
+
+void PrintError(const string& message) {
+  cout << COLOR_RED << message << COLOR_OFF << endl;
+}
+
+void PrintOpStatus(const std::string& op, bool status) {
+  cout << COLOR_BOLDWHITE << op << " status: " COLOR_OFF
+       << (status ? (COLOR_GREEN "success") : (COLOR_RED "failure"))
+       << COLOR_OFF << endl;
+}
+
+inline void BeginAsyncOut() {
+  if (showing_prompt.load()) cout << CLEAR_LINE << "\r";
+}
+
+inline void EndAsyncOut() {
+  std::flush(cout);
+  if (showing_prompt.load())
+    PrintPrompt();
+  else
+    cout << endl;
+}
+
+class CLIBluetoothCallback : public android::bluetooth::BnBluetoothCallback {
+ public:
+  CLIBluetoothCallback() = default;
+  ~CLIBluetoothCallback() override = default;
+
+  // IBluetoothCallback overrides:
+  Status OnBluetoothStateChange(int32_t prev_state,
+                                int32_t new_state) override {
+    BeginAsyncOut();
+    cout << COLOR_BOLDWHITE "Adapter state changed: " COLOR_OFF << COLOR_MAGENTA
+         << AdapterStateToString(bluetooth::AdapterState(prev_state))
+         << COLOR_OFF << COLOR_BOLDWHITE " -> " COLOR_OFF << COLOR_BOLDYELLOW
+         << AdapterStateToString(bluetooth::AdapterState(new_state))
+         << COLOR_OFF;
+    EndAsyncOut();
+
+    return Status::ok();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CLIBluetoothCallback);
+};
+
+class CLIBluetoothLowEnergyCallback
+    : public android::bluetooth::BnBluetoothLowEnergyCallback {
+ public:
+  CLIBluetoothLowEnergyCallback() = default;
+  ~CLIBluetoothLowEnergyCallback() override = default;
+
+  // IBluetoothLowEnergyCallback overrides:
+  Status OnClientRegistered(int status, int client_id) override {
+    BeginAsyncOut();
+    if (status != bluetooth::BLE_STATUS_SUCCESS) {
+      PrintError("Failed to register BLE client");
+    } else {
+      ble_client_id = client_id;
+      cout << COLOR_BOLDWHITE "Registered BLE client with ID: " COLOR_OFF
+           << COLOR_GREEN << client_id << COLOR_OFF;
+    }
+    EndAsyncOut();
+
+    ble_registering = false;
+    return Status::ok();
+  }
+
+  Status OnConnectionState(int status, int client_id, const String16& address,
+                           bool connected) override {
+    BeginAsyncOut();
+    cout << COLOR_BOLDWHITE "Connection state: " << COLOR_BOLDYELLOW "["
+         << address << " connected: " << (connected ? "true" : "false") << " ] "
+         << COLOR_BOLDWHITE "- status: " << status
+         << COLOR_BOLDWHITE " - client_id: " << client_id << COLOR_OFF;
+    EndAsyncOut();
+    return Status::ok();
+  }
+
+  Status OnMtuChanged(int status, const String16& address, int mtu) override {
+    BeginAsyncOut();
+    cout << COLOR_BOLDWHITE "MTU changed: " << COLOR_BOLDYELLOW "[" << address
+         << " ] " << COLOR_BOLDWHITE " - status: " << status
+         << COLOR_BOLDWHITE " - mtu: " << mtu << COLOR_OFF;
+    EndAsyncOut();
+    return Status::ok();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CLIBluetoothLowEnergyCallback);
+};
+
+class CLIBluetoothLeAdvertiserCallback
+    : public android::bluetooth::BnBluetoothLeAdvertiserCallback {
+ public:
+  CLIBluetoothLeAdvertiserCallback() = default;
+  ~CLIBluetoothLeAdvertiserCallback() override = default;
+
+  // IBluetoothLowEnergyCallback overrides:
+  Status OnAdvertiserRegistered(int status, int advertiser_id) override {
+    BeginAsyncOut();
+    if (status != bluetooth::BLE_STATUS_SUCCESS) {
+      PrintError("Failed to register BLE advertiser");
+    } else {
+      ble_advertiser_id = advertiser_id;
+      cout << COLOR_BOLDWHITE "Registered BLE advertiser with ID: " COLOR_OFF
+           << COLOR_GREEN << advertiser_id << COLOR_OFF;
+    }
+    EndAsyncOut();
+
+    ble_advertiser_registering = false;
+    return Status::ok();
+  }
+
+  Status OnMultiAdvertiseCallback(
+      int status, bool is_start,
+      const android::bluetooth::AdvertiseSettings& /* settings */) {
+    BeginAsyncOut();
+    std::string op = is_start ? "start" : "stop";
+
+    PrintOpStatus("Advertising " + op, status == bluetooth::BLE_STATUS_SUCCESS);
+    EndAsyncOut();
+    return Status::ok();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CLIBluetoothLeAdvertiserCallback);
+};
+
+class CLIBluetoothLeScannerCallback
+    : public android::bluetooth::BnBluetoothLeScannerCallback {
+ public:
+  CLIBluetoothLeScannerCallback() = default;
+  ~CLIBluetoothLeScannerCallback() override = default;
+
+  // IBluetoothLowEnergyCallback overrides:
+  Status OnScannerRegistered(int status, int scanner_id) override {
+    BeginAsyncOut();
+    if (status != bluetooth::BLE_STATUS_SUCCESS) {
+      PrintError("Failed to register BLE client");
+    } else {
+      ble_scanner_id = scanner_id;
+      cout << COLOR_BOLDWHITE "Registered BLE client with ID: " COLOR_OFF
+           << COLOR_GREEN << scanner_id << COLOR_OFF;
+    }
+    EndAsyncOut();
+
+    ble_scanner_registering = false;
+    return Status::ok();
+  }
+
+  Status OnScanResult(
+      const android::bluetooth::ScanResult& scan_result) override {
+    BeginAsyncOut();
+    cout << COLOR_BOLDWHITE "Scan result: " << COLOR_BOLDYELLOW "["
+         << scan_result.device_address() << "] "
+         << COLOR_BOLDWHITE "- RSSI: " << scan_result.rssi() << COLOR_OFF;
+
+    if (dump_scan_record) {
+      cout << " - Record: "
+           << base::HexEncode(scan_result.scan_record().data(),
+                              scan_result.scan_record().size());
+    }
+    EndAsyncOut();
+    return Status::ok();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CLIBluetoothLeScannerCallback);
+};
+
+class CLIGattClientCallback
+    : public android::bluetooth::BnBluetoothGattClientCallback {
+ public:
+  CLIGattClientCallback() = default;
+  ~CLIGattClientCallback() override = default;
+
+  // IBluetoothGattClientCallback overrides:
+  Status OnClientRegistered(int status, int client_id) override {
+    BeginAsyncOut();
+    if (status != bluetooth::BLE_STATUS_SUCCESS) {
+      PrintError("Failed to register GATT client");
+    } else {
+      gatt_client_id = client_id;
+      cout << COLOR_BOLDWHITE "Registered GATT client with ID: " COLOR_OFF
+           << COLOR_GREEN << client_id << COLOR_OFF;
+    }
+    EndAsyncOut();
+
+    gatt_registering = false;
+    return Status::ok();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CLIGattClientCallback);
+};
+
+void PrintCommandStatus(bool status) { PrintOpStatus("Command", status); }
+
+void PrintFieldAndValue(const string& field, const string& value) {
+  cout << COLOR_BOLDWHITE << field << ": " << COLOR_BOLDYELLOW << value
+       << COLOR_OFF << endl;
+}
+
+void PrintFieldAndBoolValue(const string& field, bool value) {
+  PrintFieldAndValue(field, (value ? "true" : "false"));
+}
+
+void HandleDisable(IBluetooth* bt_iface, const vector<string>& args) {
+  CHECK_NO_ARGS(args);
+  bool status;
+  bt_iface->Disable(&status);
+  PrintCommandStatus(status);
+}
+
+void HandleEnable(IBluetooth* bt_iface, const vector<string>& args) {
+  bool is_restricted_mode = false;
+
+  for (auto iter : args) {
+    const std::string& arg = iter;
+    if (arg == "-h") {
+      static const char kUsage[] =
+          "Usage: start-adv [flags]\n"
+          "\n"
+          "Flags:\n"
+          "\t--restricted|-r\tStart in restricted mode\n";
+      cout << kUsage << endl;
+      return;
+    } else if (arg == "--restricted" || arg == "-r") {
+      is_restricted_mode = true;
+    }
+  }
+
+  bool status;
+  bt_iface->Enable(is_restricted_mode, &status);
+  PrintCommandStatus(status);
+}
+
+void HandleGetState(IBluetooth* bt_iface, const vector<string>& args) {
+  CHECK_NO_ARGS(args);
+
+  int32_t st;
+  bt_iface->GetState(&st);
+  bluetooth::AdapterState state = static_cast<bluetooth::AdapterState>(st);
+  PrintFieldAndValue("Adapter state", bluetooth::AdapterStateToString(state));
+}
+
+void HandleIsEnabled(IBluetooth* bt_iface, const vector<string>& args) {
+  CHECK_NO_ARGS(args);
+  bool enabled;
+  bt_iface->IsEnabled(&enabled);
+  PrintFieldAndBoolValue("Adapter enabled", enabled);
+}
+
+void HandleGetLocalAddress(IBluetooth* bt_iface, const vector<string>& args) {
+  CHECK_NO_ARGS(args);
+  String16 address;
+  bt_iface->GetAddress(&address);
+  PrintFieldAndValue("Adapter address", std::string(String8(address).string()));
+}
+
+void HandleSetLocalName(IBluetooth* bt_iface, const vector<string>& args) {
+  CHECK_ARGS_COUNT(args, >=, 1, "No name was given");
+
+  std::string name;
+  for (const auto& arg : args) name += arg + " ";
+
+  base::TrimWhitespaceASCII(name, base::TRIM_TRAILING, &name);
+
+  bool status;
+  bt_iface->SetName(String16(String8(name.c_str())), &status);
+  PrintCommandStatus(status);
+}
+
+void HandleGetLocalName(IBluetooth* bt_iface, const vector<string>& args) {
+  CHECK_NO_ARGS(args);
+  String16 name;
+  bt_iface->GetName(&name);
+  PrintFieldAndValue("Adapter name", std::string(String8(name).string()));
+}
+
+void HandleAdapterInfo(IBluetooth* bt_iface, const vector<string>& args) {
+  CHECK_NO_ARGS(args);
+
+  cout << COLOR_BOLDWHITE "Adapter Properties: " COLOR_OFF << endl;
+
+  String16 address;
+  bt_iface->GetAddress(&address);
+  PrintFieldAndValue("\tAddress", std::string(String8(address).string()));
+
+  int adapter_state;
+  bt_iface->GetState(&adapter_state);
+  PrintFieldAndValue("\tState",
+                     bluetooth::AdapterStateToString(
+                         static_cast<bluetooth::AdapterState>(adapter_state)));
+
+  String16 name;
+  bt_iface->GetName(&name);
+  PrintFieldAndValue("\tName", std::string(String8(name).string()));
+
+  bool multi_adv;
+  bt_iface->IsMultiAdvertisementSupported(&multi_adv);
+  PrintFieldAndBoolValue("\tMulti-Adv. supported", multi_adv);
+}
+
+void HandleSupportsMultiAdv(IBluetooth* bt_iface, const vector<string>& args) {
+  CHECK_NO_ARGS(args);
+
+  bool multi_adv;
+  bt_iface->IsMultiAdvertisementSupported(&multi_adv);
+  PrintFieldAndBoolValue("Multi-advertisement support", multi_adv);
+}
+
+void HandleRegisterBLEAdvertiser(IBluetooth* bt_iface, const vector<string>& args) {
+  CHECK_NO_ARGS(args);
+
+  if (ble_advertiser_registering.load()) {
+    PrintError("In progress");
+    return;
+  }
+
+  if (ble_advertiser_id.load()) {
+    PrintError("Already registered");
+    return;
+  }
+
+  sp<IBluetoothLeAdvertiser> ble_advertiser_iface;
+  bt_iface->GetLeAdvertiserInterface(&ble_advertiser_iface);
+  if (!ble_advertiser_iface.get()) {
+    PrintError("Failed to obtain handle to Bluetooth Le Advertiser interface");
+    return;
+  }
+
+  bool status;
+  ble_advertiser_iface->RegisterAdvertiser(new CLIBluetoothLeAdvertiserCallback(), &status);
+  ble_advertiser_registering = status;
+  PrintCommandStatus(status);
+}
+
+void HandleUnregisterBLEAdvertiser(IBluetooth* bt_iface, const vector<string>& args) {
+  CHECK_NO_ARGS(args);
+
+  if (!ble_advertiser_id.load()) {
+    PrintError("Not registered");
+    return;
+  }
+
+  sp<IBluetoothLeAdvertiser> ble_advertiser_iface;
+  bt_iface->GetLeAdvertiserInterface(&ble_advertiser_iface);
+  if (!ble_advertiser_iface.get()) {
+    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
+    return;
+  }
+
+  ble_advertiser_iface->UnregisterAdvertiser(ble_advertiser_id.load());
+  ble_advertiser_id = 0;
+  PrintCommandStatus(true);
+}
+
+void HandleRegisterBLE(IBluetooth* bt_iface, const vector<string>& args) {
+  CHECK_NO_ARGS(args);
+
+  if (ble_registering.load()) {
+    PrintError("In progress");
+    return;
+  }
+
+  if (ble_client_id.load()) {
+    PrintError("Already registered");
+    return;
+  }
+
+  sp<IBluetoothLowEnergy> ble_iface;
+  bt_iface->GetLowEnergyInterface(&ble_iface);
+  if (!ble_iface.get()) {
+    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
+    return;
+  }
+
+  bool status;
+  ble_iface->RegisterClient(new CLIBluetoothLowEnergyCallback(), &status);
+  ble_registering = status;
+  PrintCommandStatus(status);
+}
+
+void HandleUnregisterBLE(IBluetooth* bt_iface, const vector<string>& args) {
+  CHECK_NO_ARGS(args);
+
+  if (!ble_client_id.load()) {
+    PrintError("Not registered");
+    return;
+  }
+
+  sp<IBluetoothLowEnergy> ble_iface;
+  bt_iface->GetLowEnergyInterface(&ble_iface);
+  if (!ble_iface.get()) {
+    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
+    return;
+  }
+
+  ble_iface->UnregisterClient(ble_client_id.load());
+  ble_client_id = 0;
+  PrintCommandStatus(true);
+}
+
+void HandleUnregisterAllBLE(IBluetooth* bt_iface, const vector<string>& args) {
+  CHECK_NO_ARGS(args);
+
+  sp<IBluetoothLowEnergy> ble_iface;
+  bt_iface->GetLowEnergyInterface(&ble_iface);
+  if (!ble_iface.get()) {
+    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
+    return;
+  }
+
+  ble_iface->UnregisterAll();
+  PrintCommandStatus(true);
+}
+
+void HandleRegisterGATT(IBluetooth* bt_iface, const vector<string>& args) {
+  CHECK_NO_ARGS(args);
+
+  if (gatt_registering.load()) {
+    PrintError("In progress");
+    return;
+  }
+
+  if (gatt_client_id.load()) {
+    PrintError("Already registered");
+    return;
+  }
+
+  sp<IBluetoothGattClient> gatt_iface;
+  bt_iface->GetGattClientInterface(&gatt_iface);
+  if (!gatt_iface.get()) {
+    PrintError("Failed to obtain handle to Bluetooth GATT Client interface");
+    return;
+  }
+
+  bool status;
+  gatt_iface->RegisterClient(new CLIGattClientCallback(), &status);
+  gatt_registering = status;
+  PrintCommandStatus(status);
+}
+
+void HandleUnregisterGATT(IBluetooth* bt_iface, const vector<string>& args) {
+  CHECK_NO_ARGS(args);
+
+  if (!gatt_client_id.load()) {
+    PrintError("Not registered");
+    return;
+  }
+
+  sp<IBluetoothGattClient> gatt_iface;
+  bt_iface->GetGattClientInterface(&gatt_iface);
+  if (!gatt_iface.get()) {
+    PrintError("Failed to obtain handle to Bluetooth GATT Client interface");
+    return;
+  }
+
+  gatt_iface->UnregisterClient(gatt_client_id.load());
+  gatt_client_id = 0;
+  PrintCommandStatus(true);
+}
+
+void HandleStartAdv(IBluetooth* bt_iface, const vector<string>& args) {
+  bool include_name = false;
+  bool include_tx_power = false;
+  bool connectable = false;
+  bool set_manufacturer_data = false;
+  bool set_uuid = false;
+  bluetooth::UUID uuid;
+
+  for (auto iter = args.begin(); iter != args.end(); ++iter) {
+    const std::string& arg = *iter;
+    if (arg == "-n")
+      include_name = true;
+    else if (arg == "-t")
+      include_tx_power = true;
+    else if (arg == "-c")
+      connectable = true;
+    else if (arg == "-m")
+      set_manufacturer_data = true;
+    else if (arg == "-u") {
+      // This flag has a single argument.
+      ++iter;
+      if (iter == args.end()) {
+        PrintError("Expected a UUID after -u");
+        return;
+      }
+
+      std::string uuid_str = *iter;
+      uuid = bluetooth::UUID(uuid_str);
+      if (!uuid.is_valid()) {
+        PrintError("Invalid UUID: " + uuid_str);
+        return;
+      }
+
+      set_uuid = true;
+    } else if (arg == "-h") {
+      static const char kUsage[] =
+          "Usage: start-adv [flags]\n"
+          "\n"
+          "Flags:\n"
+          "\t-n\tInclude device name\n"
+          "\t-t\tInclude TX power\n"
+          "\t-c\tSend connectable adv. packets (default is non-connectable)\n"
+          "\t-m\tInclude random manufacturer data\n"
+          "\t-h\tShow this help message\n";
+      cout << kUsage << endl;
+      return;
+    } else {
+      PrintError("Unrecognized option: " + arg);
+      return;
+    }
+  }
+
+  if (!ble_advertiser_id.load()) {
+    PrintError("BLE advertiser not registered");
+    return;
+  }
+
+  sp<IBluetoothLeAdvertiser> ble_advertiser_iface;
+  bt_iface->GetLeAdvertiserInterface(&ble_advertiser_iface);
+  if (!ble_advertiser_iface.get()) {
+    PrintError("Failed to obtain handle to Bluetooth Le Advertiser interface");
+    return;
+  }
+
+  std::vector<uint8_t> data;
+  if (set_manufacturer_data) {
+    data = {{0x07, bluetooth::kEIRTypeManufacturerSpecificData, 0xe0, 0x00, 'T',
+             'e', 's', 't'}};
+  }
+
+  if (set_uuid) {
+    // Determine the type and length bytes.
+    int uuid_size = uuid.GetShortestRepresentationSize();
+    uint8_t type;
+    if (uuid_size == bluetooth::UUID::kNumBytes128)
+      type = bluetooth::kEIRTypeComplete128BitUUIDs;
+    else if (uuid_size == bluetooth::UUID::kNumBytes32)
+      type = bluetooth::kEIRTypeComplete32BitUUIDs;
+    else if (uuid_size == bluetooth::UUID::kNumBytes16)
+      type = bluetooth::kEIRTypeComplete16BitUUIDs;
+    else
+      NOTREACHED() << "Unexpected size: " << uuid_size;
+
+    data.push_back(uuid_size + 1);
+    data.push_back(type);
+
+    auto uuid_bytes = uuid.GetFullLittleEndian();
+    int index = (uuid_size == 16) ? 0 : 12;
+    data.insert(data.end(), uuid_bytes.data() + index,
+                uuid_bytes.data() + index + uuid_size);
+  }
+
+  base::TimeDelta timeout;
+
+  bluetooth::AdvertiseSettings settings(
+      bluetooth::AdvertiseSettings::MODE_LOW_POWER, timeout,
+      bluetooth::AdvertiseSettings::TX_POWER_LEVEL_MEDIUM, connectable);
+
+  if (include_tx_power) {
+    data.push_back(0x02);
+    data.push_back(bluetooth::kEIRTypeTxPower);
+    data.push_back(0x00);
+  }
+
+  bluetooth::AdvertiseData adv_data(data);
+
+  if (include_name) {
+    String16 name_param;
+    bt_iface->GetName(&name_param);
+    std::string name(String8(name_param).string());
+    data.push_back(name.length() + 1);
+    data.push_back(bluetooth::kEIRTypeCompleteLocalName);
+    data.insert(data.begin(), name.c_str(), name.c_str() + name.length());
+  }
+
+  bluetooth::AdvertiseData scan_rsp;
+
+  bool status;
+  ble_advertiser_iface->StartMultiAdvertising(ble_advertiser_id.load(), adv_data, scan_rsp,
+                                   settings, &status);
+  PrintCommandStatus(status);
+}
+
+void HandleStopAdv(IBluetooth* bt_iface, const vector<string>& args) {
+  if (!ble_advertiser_id.load()) {
+    PrintError("BLE advertiser not registered");
+    return;
+  }
+
+  sp<IBluetoothLeAdvertiser> ble_advertiser_iface;
+  bt_iface->GetLeAdvertiserInterface(&ble_advertiser_iface);
+  if (!ble_advertiser_iface.get()) {
+    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
+    return;
+  }
+
+  bool status;
+  ble_advertiser_iface->StopMultiAdvertising(ble_advertiser_id.load(), &status);
+  PrintCommandStatus(status);
+}
+
+void HandleConnect(IBluetooth* bt_iface, const vector<string>& args) {
+  string address;
+
+  if (args.size() != 1) {
+    PrintError("Expected MAC address as only argument");
+    return;
+  }
+
+  address = args[0];
+
+  if (!ble_client_id.load()) {
+    PrintError("BLE not registered");
+    return;
+  }
+
+  sp<IBluetoothLowEnergy> ble_iface;
+  bt_iface->GetLowEnergyInterface(&ble_iface);
+  if (!ble_iface.get()) {
+    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
+    return;
+  }
+
+  bool status;
+  ble_iface->Connect(ble_client_id.load(),
+                     String16(address.c_str(), address.length()),
+                     false /*  is_direct */, &status);
+
+  PrintCommandStatus(status);
+}
+
+void HandleDisconnect(IBluetooth* bt_iface, const vector<string>& args) {
+  string address;
+
+  if (args.size() != 1) {
+    PrintError("Expected MAC address as only argument");
+    return;
+  }
+
+  address = args[0];
+
+  if (!ble_client_id.load()) {
+    PrintError("BLE not registered");
+    return;
+  }
+
+  sp<IBluetoothLowEnergy> ble_iface;
+  bt_iface->GetLowEnergyInterface(&ble_iface);
+  if (!ble_iface.get()) {
+    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
+    return;
+  }
+
+  bool status;
+  ble_iface->Disconnect(ble_client_id.load(),
+                        String16(address.c_str(), address.length()), &status);
+  PrintCommandStatus(status);
+}
+
+void HandleSetMtu(IBluetooth* bt_iface, const vector<string>& args) {
+  string address;
+  int mtu;
+
+  if (args.size() != 2) {
+    PrintError("Usage: set-mtu [address] [mtu]");
+    return;
+  }
+
+  address = args[0];
+  mtu = std::stoi(args[1]);
+
+  if (mtu < 23) {
+    PrintError("MTU must be 23 or larger");
+    return;
+  }
+
+  if (!ble_client_id.load()) {
+    PrintError("BLE not registered");
+    return;
+  }
+
+  sp<IBluetoothLowEnergy> ble_iface;
+  bt_iface->GetLowEnergyInterface(&ble_iface);
+  if (!ble_iface.get()) {
+    PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
+    return;
+  }
+
+  bool status;
+  ble_iface->SetMtu(ble_client_id.load(),
+                    String16(address.c_str(), address.length()), mtu, &status);
+  PrintCommandStatus(status);
+}
+
+
+void HandleRegisterBLEScanner(IBluetooth* bt_iface, const vector<string>& args) {
+  CHECK_NO_ARGS(args);
+
+  if (ble_scanner_registering.load()) {
+    PrintError("In progress");
+    return;
+  }
+
+  if (ble_scanner_id.load()) {
+    PrintError("Already registered");
+    return;
+  }
+
+  sp<IBluetoothLeScanner> ble_scanner_iface;
+  bt_iface->GetLeScannerInterface(&ble_scanner_iface);
+  if (!ble_scanner_iface.get()) {
+    PrintError("Failed to obtain handle to Bluetooth LE Scanner interface");
+    return;
+  }
+
+  bool status;
+  ble_scanner_iface->RegisterScanner(new CLIBluetoothLeScannerCallback(), &status);
+  ble_scanner_registering = status;
+  PrintCommandStatus(status);
+}
+
+void HandleUnregisterBLEScanner(IBluetooth* bt_iface, const vector<string>& args) {
+  CHECK_NO_ARGS(args);
+
+  if (!ble_scanner_id.load()) {
+    PrintError("Not registered");
+    return;
+  }
+
+  sp<IBluetoothLeScanner> ble_scanner_iface;
+  bt_iface->GetLeScannerInterface(&ble_scanner_iface);
+  if (!ble_scanner_iface.get()) {
+    PrintError("Failed to obtain handle to Bluetooth LE scanner interface");
+    return;
+  }
+
+  ble_scanner_iface->UnregisterScanner(ble_scanner_id.load());
+  ble_scanner_id = 0;
+  PrintCommandStatus(true);
+}
+
+void HandleStartLeScan(IBluetooth* bt_iface, const vector<string>& args) {
+  if (!ble_client_id.load()) {
+    PrintError("BLE not registered");
+    return;
+  }
+
+  for (const auto& arg : args) {
+    if (arg == "-d") {
+      dump_scan_record = true;
+    } else if (arg == "-h") {
+      static const char kUsage[] =
+          "Usage: start-le-scan [flags]\n"
+          "\n"
+          "Flags:\n"
+          "\t-d\tDump scan record\n"
+          "\t-h\tShow this help message\n";
+      cout << kUsage << endl;
+      return;
+    }
+  }
+
+  sp<IBluetoothLeScanner> ble_scanner_iface;
+  bt_iface->GetLeScannerInterface(&ble_scanner_iface);
+  if (!ble_scanner_iface.get()) {
+    PrintError("Failed to obtain handle to Bluetooth LE scanner interface");
+    return;
+  }
+
+  bluetooth::ScanSettings settings;
+  std::vector<android::bluetooth::ScanFilter> filters;
+
+  bool status;
+  ble_scanner_iface->StartScan(ble_scanner_id.load(), settings, filters, &status);
+  PrintCommandStatus(status);
+}
+
+void HandleStopLeScan(IBluetooth* bt_iface, const vector<string>& args) {
+  if (!ble_client_id.load()) {
+    PrintError("BLE not registered");
+    return;
+  }
+
+  sp<IBluetoothLeScanner> ble_scanner_iface;
+  bt_iface->GetLeScannerInterface(&ble_scanner_iface);
+  if (!ble_scanner_iface.get()) {
+    PrintError("Failed to obtain handle to Bluetooth LE scanner interface");
+    return;
+  }
+
+  bool status;
+  ble_scanner_iface->StopScan(ble_scanner_id.load(), &status);
+  PrintCommandStatus(status);
+}
+
+void HandleHelp(IBluetooth* bt_iface, const vector<string>& args);
+
+struct {
+  string command;
+  void (*func)(IBluetooth*, const vector<string>& args);
+  string help;
+} kCommandMap[] = {
+    {"help", HandleHelp, "\t\t\tDisplay this message"},
+    {"disable", HandleDisable, "\t\t\tDisable Bluetooth"},
+    {"enable", HandleEnable, "\t\t\tEnable Bluetooth (-h for options)"},
+    {"get-state", HandleGetState, "\t\tGet the current adapter state"},
+    {"is-enabled", HandleIsEnabled, "\t\tReturn if Bluetooth is enabled"},
+    {"get-local-address", HandleGetLocalAddress,
+     "\tGet the local adapter address"},
+    {"set-local-name", HandleSetLocalName, "\t\tSet the local adapter name"},
+    {"get-local-name", HandleGetLocalName, "\t\tGet the local adapter name"},
+    {"adapter-info", HandleAdapterInfo, "\t\tPrint adapter properties"},
+    {"supports-multi-adv", HandleSupportsMultiAdv,
+     "\tWhether multi-advertisement is currently supported"},
+    {"register-le-advertiser", HandleRegisterBLEAdvertiser,
+     "\t\tRegister with the Bluetooth Low Energy Advertiser interface"},
+    {"unregister-le-advertiser", HandleUnregisterBLEAdvertiser,
+     "\t\tUnregister from the Bluetooth LE Advertiser interface"},
+    {"register-ble", HandleRegisterBLE,
+     "\t\tRegister with the Bluetooth Low Energy interface"},
+    {"unregister-ble", HandleUnregisterBLE,
+     "\t\tUnregister from the Bluetooth Low Energy interface"},
+    {"unregister-all-ble", HandleUnregisterAllBLE,
+     "\tUnregister all clients from the Bluetooth Low Energy interface"},
+    {"register-gatt", HandleRegisterGATT,
+     "\t\tRegister with the Bluetooth GATT Client interface"},
+    {"unregister-gatt", HandleUnregisterGATT,
+     "\t\tUnregister from the Bluetooth GATT Client interface"},
+    {"connect-le", HandleConnect, "\t\tConnect to LE device (-h for options)"},
+    {"disconnect-le", HandleDisconnect,
+     "\t\tDisconnect LE device (-h for options)"},
+    {"set-mtu", HandleSetMtu, "\t\tSet MTU (-h for options)"},
+    {"start-adv", HandleStartAdv, "\t\tStart advertising (-h for options)"},
+    {"stop-adv", HandleStopAdv, "\t\tStop advertising"},
+    {"register-le-scanner", HandleRegisterBLEScanner,
+     "\t\tRegister with the Bluetooth Low Energy scanner interface"},
+    {"unregister-le-scanner", HandleUnregisterBLEScanner,
+     "\t\tUnregister from the Bluetooth LE scanner interface"},
+    {"start-le-scan", HandleStartLeScan,
+     "\t\tStart LE device scan (-h for options)"},
+    {"stop-le-scan", HandleStopLeScan, "\t\tStop LE device scan"},
+    {},
+};
+
+void HandleHelp(IBluetooth* /* bt_iface */, const vector<string>& /* args */) {
+  cout << endl;
+  for (int i = 0; kCommandMap[i].func; i++)
+    cout << "\t" << kCommandMap[i].command << kCommandMap[i].help << endl;
+  cout << endl;
+}
+
+const char kExecuteLong[] = "exec";
+const char kExecuteShort[] = "e";
+
+bool ExecuteCommand(const sp<IBluetooth>& bt_iface, std::string &command) {
+  vector<string> args =
+      base::SplitString(command, " ", base::TRIM_WHITESPACE,
+                        base::SPLIT_WANT_ALL);
+
+  if (args.empty())
+    return true;
+
+  // The first argument is the command while the remaining are what we pass to
+  // the handler functions.
+  command = args[0];
+  args.erase(args.begin());
+
+  for (int i = 0; kCommandMap[i].func; i++) {
+    if (command == kCommandMap[i].command) {
+      kCommandMap[i].func(bt_iface.get(), args);
+      return true;
+    }
+  }
+
+  cout << "Unrecognized command: " << command << endl;
+  return false;
+}
+
+}  // namespace
+
+class BluetoothDeathRecipient : public android::IBinder::DeathRecipient {
+ public:
+  BluetoothDeathRecipient() = default;
+  ~BluetoothDeathRecipient() override = default;
+
+  // android::IBinder::DeathRecipient override:
+  void binderDied(const android::wp<android::IBinder>& /* who */) override {
+    BeginAsyncOut();
+    cout << COLOR_BOLDWHITE "The Bluetooth daemon has died" COLOR_OFF << endl;
+    cout << "\nPress 'ENTER' to exit.";
+    EndAsyncOut();
+
+    android::IPCThreadState::self()->stopProcess();
+    should_exit = true;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BluetoothDeathRecipient);
+};
+
+
+int main(int argc, char* argv[]) {
+  base::AtExitManager exit_manager;
+  base::CommandLine::Init(argc, argv);
+  logging::LoggingSettings log_settings;
+
+  if (!logging::InitLogging(log_settings)) {
+    LOG(ERROR) << "Failed to set up logging";
+    return EXIT_FAILURE;
+  }
+
+  sp<IBluetooth> bt_iface;
+  status_t status = getService(String16(kServiceName.c_str()), &bt_iface);
+  if (status != OK) {
+    LOG(ERROR) << "Failed to get service binder: '" << kServiceName
+               << "' status=" << status;
+    return EXIT_FAILURE;
+  }
+
+  sp<BluetoothDeathRecipient> dr(new BluetoothDeathRecipient());
+  if (android::IInterface::asBinder(bt_iface.get())->linkToDeath(dr) !=
+      android::NO_ERROR) {
+    LOG(ERROR) << "Failed to register DeathRecipient for IBluetooth";
+    return EXIT_FAILURE;
+  }
+
+  // Initialize the Binder process thread pool. We have to set this up,
+  // otherwise, incoming callbacks from IBluetoothCallback will block the main
+  // thread (in other words, we have to do this as we are a "Binder server").
+  android::ProcessState::self()->startThreadPool();
+
+  // Register Adapter state-change callback
+  sp<CLIBluetoothCallback> callback = new CLIBluetoothCallback();
+  bt_iface->RegisterCallback(callback);
+
+  cout << COLOR_BOLDWHITE << "Fluoride Command-Line Interface\n"
+       << COLOR_OFF << endl
+       << "Type \"help\" to see possible commands.\n"
+       << endl;
+
+  string command;
+
+  // Add commands from the command line, if they exist.
+  auto command_line = base::CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(kExecuteLong)) {
+    command += command_line->GetSwitchValueASCII(kExecuteLong);
+  }
+
+  if (command_line->HasSwitch(kExecuteShort)) {
+    if (!command.empty())
+      command += " ; ";
+    command += command_line->GetSwitchValueASCII(kExecuteShort);
+  }
+
+  while (true) {
+    vector<string> commands = base::SplitString(command, ";",
+                                                base::TRIM_WHITESPACE,
+                                                base::SPLIT_WANT_ALL);
+    for (string command : commands) {
+      if (!ExecuteCommand(bt_iface, command))
+        break;
+    }
+
+    commands.clear();
+
+    PrintPrompt();
+
+    showing_prompt = true;
+    auto& istream = getline(cin, command);
+    showing_prompt = false;
+
+    if (istream.eof() || should_exit.load()) {
+      cout << "\nExiting" << endl;
+      return EXIT_SUCCESS;
+    }
+
+    if (!istream.good()) {
+      LOG(ERROR) << "An error occured while reading input";
+      return EXIT_FAILURE;
+    }
+  }
+
+  return EXIT_SUCCESS;
+}
diff --git a/bt/service/common/README b/bt/service/common/README
new file mode 100644
index 0000000..de9e914
--- /dev/null
+++ b/bt/service/common/README
@@ -0,0 +1,18 @@
+This directory contains all the "common" sources between the bluetooth daemon
+and our client library. All source files here are under the "bluetooth"
+subdirectory, which is the exported root path for the client static library.
+Only common files should go here. All headers that go into common/bluetooth must
+only include other headers from common/bluetooth and must use "bluetooth" as the
+root path, e.g.:
+
+#include <bluetooth/uuid.h>
+
+This is so that client applications that link against the client library have
+one common include path exported to them, and our headers can find eachother
+within that.
+
+It is however OK to include from the package root when including common headers
+from source files as these are pre-compiled. For example,
+common/bluetooth/adapter_state.cpp should do:
+
+#include "service/common/bluetooth/adapter_state.h"
diff --git a/bt/service/common/android/bluetooth/AdvertiseData.aidl b/bt/service/common/android/bluetooth/AdvertiseData.aidl
new file mode 100644
index 0000000..3005670
--- /dev/null
+++ b/bt/service/common/android/bluetooth/AdvertiseData.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable AdvertiseData cpp_header "android/bluetooth/advertise_data.h";
diff --git a/bt/service/common/android/bluetooth/AdvertiseSettings.aidl b/bt/service/common/android/bluetooth/AdvertiseSettings.aidl
new file mode 100644
index 0000000..f479e5a
--- /dev/null
+++ b/bt/service/common/android/bluetooth/AdvertiseSettings.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable AdvertiseSettings cpp_header "android/bluetooth/advertise_settings.h";
diff --git a/bt/service/common/android/bluetooth/BluetoothGattCharacteristic.aidl b/bt/service/common/android/bluetooth/BluetoothGattCharacteristic.aidl
new file mode 100644
index 0000000..5f3f729
--- /dev/null
+++ b/bt/service/common/android/bluetooth/BluetoothGattCharacteristic.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothGattCharacteristic cpp_header "android/bluetooth/bluetooth_gatt_characteristic.h";
diff --git a/bt/service/common/android/bluetooth/BluetoothGattDescriptor.aidl b/bt/service/common/android/bluetooth/BluetoothGattDescriptor.aidl
new file mode 100644
index 0000000..51af33e
--- /dev/null
+++ b/bt/service/common/android/bluetooth/BluetoothGattDescriptor.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothGattDescriptor cpp_header "android/bluetooth/bluetooth_gatt_descriptor.h";
diff --git a/bt/service/common/android/bluetooth/BluetoothGattIncludedService.aidl b/bt/service/common/android/bluetooth/BluetoothGattIncludedService.aidl
new file mode 100644
index 0000000..0ee3f63
--- /dev/null
+++ b/bt/service/common/android/bluetooth/BluetoothGattIncludedService.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothGattIncludedService cpp_header "android/bluetooth/bluetooth_gatt_included_service.h";
diff --git a/bt/service/common/android/bluetooth/BluetoothGattService.aidl b/bt/service/common/android/bluetooth/BluetoothGattService.aidl
new file mode 100644
index 0000000..92bdfe0
--- /dev/null
+++ b/bt/service/common/android/bluetooth/BluetoothGattService.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothGattService cpp_header "android/bluetooth/bluetooth_gatt_service.h";
diff --git a/bt/service/common/android/bluetooth/IBluetooth.aidl b/bt/service/common/android/bluetooth/IBluetooth.aidl
new file mode 100644
index 0000000..1e96952
--- /dev/null
+++ b/bt/service/common/android/bluetooth/IBluetooth.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetoothCallback;
+import android.bluetooth.IBluetoothLowEnergy;
+import android.bluetooth.IBluetoothLeAdvertiser;
+import android.bluetooth.IBluetoothLeScanner;
+import android.bluetooth.IBluetoothGattClient;
+import android.bluetooth.IBluetoothGattServer;
+
+import android.bluetooth.UUID;
+
+interface IBluetooth {
+  boolean IsEnabled();
+  int GetState();
+  boolean Enable(boolean startRestricted);
+  boolean EnableNoAutoConnect();
+  boolean Disable();
+
+  String GetAddress();
+  UUID[] GetUUIDs();
+  boolean SetName(String name);
+  String GetName();
+
+  void RegisterCallback(IBluetoothCallback callback);
+  void UnregisterCallback(IBluetoothCallback callback);
+
+  boolean IsMultiAdvertisementSupported();
+
+  IBluetoothLowEnergy GetLowEnergyInterface();
+  IBluetoothLeAdvertiser GetLeAdvertiserInterface();
+  IBluetoothLeScanner GetLeScannerInterface();
+  IBluetoothGattClient GetGattClientInterface();
+  IBluetoothGattServer GetGattServerInterface();
+}
diff --git a/bt/service/common/android/bluetooth/IBluetoothCallback.aidl b/bt/service/common/android/bluetooth/IBluetoothCallback.aidl
new file mode 100644
index 0000000..24ac89b
--- /dev/null
+++ b/bt/service/common/android/bluetooth/IBluetoothCallback.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+oneway interface IBluetoothCallback {
+   void OnBluetoothStateChange(int prev_state, int new_state);
+}
diff --git a/bt/service/common/android/bluetooth/IBluetoothGattClient.aidl b/bt/service/common/android/bluetooth/IBluetoothGattClient.aidl
new file mode 100644
index 0000000..ccd05b0
--- /dev/null
+++ b/bt/service/common/android/bluetooth/IBluetoothGattClient.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetoothGattClientCallback;
+
+interface IBluetoothGattClient {
+
+  boolean RegisterClient(in IBluetoothGattClientCallback callback);
+  void UnregisterClient(int client_id);
+  void UnregisterAll();
+}
diff --git a/bt/service/common/android/bluetooth/IBluetoothGattClientCallback.aidl b/bt/service/common/android/bluetooth/IBluetoothGattClientCallback.aidl
new file mode 100644
index 0000000..94dec9d
--- /dev/null
+++ b/bt/service/common/android/bluetooth/IBluetoothGattClientCallback.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+oneway interface IBluetoothGattClientCallback {
+  void OnClientRegistered(int status, int client_id);
+}
diff --git a/bt/service/common/android/bluetooth/IBluetoothGattServer.aidl b/bt/service/common/android/bluetooth/IBluetoothGattServer.aidl
new file mode 100644
index 0000000..50d0a82
--- /dev/null
+++ b/bt/service/common/android/bluetooth/IBluetoothGattServer.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothGattService;
+import android.bluetooth.IBluetoothGattServerCallback;
+import android.bluetooth.UUID;
+
+interface IBluetoothGattServer {
+
+  boolean RegisterServer(in IBluetoothGattServerCallback callback);
+  void UnregisterServer(int server_id);
+  void UnregisterAll();
+
+  boolean AddService(int server_id, in BluetoothGattService service);
+
+  boolean SendResponse(
+      int server_id,
+      String device_address,
+      int request_id,
+      int status, int offset,
+      in byte[] value);
+
+  boolean SendNotification(
+      int server_id,
+      String device_address,
+      int handle,
+      boolean confirm,
+      in byte[] value);
+}
diff --git a/bt/service/common/android/bluetooth/IBluetoothGattServerCallback.aidl b/bt/service/common/android/bluetooth/IBluetoothGattServerCallback.aidl
new file mode 100644
index 0000000..06340d0
--- /dev/null
+++ b/bt/service/common/android/bluetooth/IBluetoothGattServerCallback.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothGattService;
+
+oneway interface IBluetoothGattServerCallback {
+  void OnServerRegistered(int status, int server_id);
+
+  void OnServiceAdded(int status, in BluetoothGattService service);
+
+  void OnCharacteristicReadRequest(String device_address,
+    int request_id, int offset, boolean is_long, int handle);
+
+  void OnDescriptorReadRequest(String device_address,
+    int request_id, int offset, boolean is_long, int handle);
+
+  void OnCharacteristicWriteRequest(String device_address,
+    int request_id, int offset, boolean is_prepare_write, boolean need_response,
+    in byte[] value, int handle);
+
+  void OnDescriptorWriteRequest(String device_address,
+    int request_id, int offset, boolean is_prepare_write, boolean need_response,
+    in byte[] value, int handle);
+
+  void OnExecuteWriteRequest(String device_address,
+    int request_id, boolean is_execute);
+
+  void OnNotificationSent(String device_address,
+    int status);
+
+  void OnConnectionStateChanged(String device_address, boolean connected);
+  }
diff --git a/bt/service/common/android/bluetooth/IBluetoothLeAdvertiser.aidl b/bt/service/common/android/bluetooth/IBluetoothLeAdvertiser.aidl
new file mode 100644
index 0000000..5435af3
--- /dev/null
+++ b/bt/service/common/android/bluetooth/IBluetoothLeAdvertiser.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetoothLeAdvertiserCallback;
+
+import android.bluetooth.AdvertiseData;
+import android.bluetooth.AdvertiseSettings;
+
+interface IBluetoothLeAdvertiser {
+  boolean RegisterAdvertiser(in IBluetoothLeAdvertiserCallback callback);
+  void UnregisterAdvertiser(int advertiser_id);
+  void UnregisterAll();
+
+  boolean StartMultiAdvertising(
+      int advertiser_id,
+      in AdvertiseData advertise_data,
+      in AdvertiseData scan_response,
+      in AdvertiseSettings settings);
+  boolean StopMultiAdvertising(int advertiser_id);
+}
\ No newline at end of file
diff --git a/bt/service/common/android/bluetooth/IBluetoothLeAdvertiserCallback.aidl b/bt/service/common/android/bluetooth/IBluetoothLeAdvertiserCallback.aidl
new file mode 100644
index 0000000..d51657e
--- /dev/null
+++ b/bt/service/common/android/bluetooth/IBluetoothLeAdvertiserCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.AdvertiseSettings;
+
+oneway interface IBluetoothLeAdvertiserCallback {
+  void OnAdvertiserRegistered(int status, int advertiser_id);
+  void OnMultiAdvertiseCallback(int status, boolean is_start, in AdvertiseSettings settings);
+}
\ No newline at end of file
diff --git a/bt/service/common/android/bluetooth/IBluetoothLeScanner.aidl b/bt/service/common/android/bluetooth/IBluetoothLeScanner.aidl
new file mode 100644
index 0000000..2f9506d
--- /dev/null
+++ b/bt/service/common/android/bluetooth/IBluetoothLeScanner.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetoothLeScannerCallback;
+import android.bluetooth.ScanFilter;
+import android.bluetooth.ScanSettings;
+
+interface IBluetoothLeScanner {
+  boolean RegisterScanner(in IBluetoothLeScannerCallback callback);
+  void UnregisterScanner(int scanner_id);
+  void UnregisterAll();
+
+  boolean StartScan(int client_id,
+      in ScanSettings settings,
+      in ScanFilter[] filters);
+  boolean StopScan(int client_id);
+}
diff --git a/bt/service/common/android/bluetooth/IBluetoothLeScannerCallback.aidl b/bt/service/common/android/bluetooth/IBluetoothLeScannerCallback.aidl
new file mode 100644
index 0000000..4ee6be3
--- /dev/null
+++ b/bt/service/common/android/bluetooth/IBluetoothLeScannerCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.ScanResult;
+
+oneway interface IBluetoothLeScannerCallback {
+  void OnScannerRegistered(int status, int client_id);
+  void OnScanResult(in ScanResult scan_result);
+}
\ No newline at end of file
diff --git a/bt/service/common/android/bluetooth/IBluetoothLowEnergy.aidl b/bt/service/common/android/bluetooth/IBluetoothLowEnergy.aidl
new file mode 100644
index 0000000..4d49430
--- /dev/null
+++ b/bt/service/common/android/bluetooth/IBluetoothLowEnergy.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetoothLowEnergyCallback;
+
+import android.bluetooth.AdvertiseData;
+import android.bluetooth.AdvertiseSettings;
+
+interface IBluetoothLowEnergy {
+  boolean RegisterClient(in IBluetoothLowEnergyCallback callback);
+  void UnregisterClient(int client_if);
+  void UnregisterAll();
+
+  boolean Connect(int client_id, String address, boolean is_direct);
+  boolean Disconnect(int client_id, String address);
+
+  boolean SetMtu(int client_id, String address, int mtu);
+}
\ No newline at end of file
diff --git a/bt/service/common/android/bluetooth/IBluetoothLowEnergyCallback.aidl b/bt/service/common/android/bluetooth/IBluetoothLowEnergyCallback.aidl
new file mode 100644
index 0000000..858506a
--- /dev/null
+++ b/bt/service/common/android/bluetooth/IBluetoothLowEnergyCallback.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.ScanResult;
+import android.bluetooth.AdvertiseSettings;
+
+oneway interface IBluetoothLowEnergyCallback {
+  void OnClientRegistered(int status, int client_id);
+  void OnConnectionState(int status, int client_id, String address, boolean connected);
+  void OnMtuChanged(int status, String address, int mtu);
+}
\ No newline at end of file
diff --git a/bt/service/common/android/bluetooth/ScanFilter.aidl b/bt/service/common/android/bluetooth/ScanFilter.aidl
new file mode 100644
index 0000000..2787a99
--- /dev/null
+++ b/bt/service/common/android/bluetooth/ScanFilter.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable ScanFilter cpp_header "android/bluetooth/scan_filter.h";
diff --git a/bt/service/common/android/bluetooth/ScanResult.aidl b/bt/service/common/android/bluetooth/ScanResult.aidl
new file mode 100644
index 0000000..7ba2df5
--- /dev/null
+++ b/bt/service/common/android/bluetooth/ScanResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable ScanResult cpp_header "android/bluetooth/scan_result.h";
diff --git a/bt/service/common/android/bluetooth/ScanSettings.aidl b/bt/service/common/android/bluetooth/ScanSettings.aidl
new file mode 100644
index 0000000..3b11b24
--- /dev/null
+++ b/bt/service/common/android/bluetooth/ScanSettings.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable ScanSettings cpp_header "android/bluetooth/scan_settings.h";
diff --git a/bt/service/common/android/bluetooth/UUID.aidl b/bt/service/common/android/bluetooth/UUID.aidl
new file mode 100644
index 0000000..54f993f
--- /dev/null
+++ b/bt/service/common/android/bluetooth/UUID.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable UUID cpp_header "android/bluetooth/uuid.h";
diff --git a/bt/service/common/android/bluetooth/advertise_data.cc b/bt/service/common/android/bluetooth/advertise_data.cc
new file mode 100644
index 0000000..07eb50a
--- /dev/null
+++ b/bt/service/common/android/bluetooth/advertise_data.cc
@@ -0,0 +1,35 @@
+//
+//  Copyright (C) 2016 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/android/bluetooth/advertise_data.h"
+
+using android::OK;
+
+namespace android {
+namespace bluetooth {
+
+status_t AdvertiseData::writeToParcel(Parcel* parcel) const {
+  status_t status = parcel->writeByteVector(data_);
+  return status;
+}
+
+status_t AdvertiseData::readFromParcel(const Parcel* parcel) {
+  status_t status = parcel->readByteVector(&data_);
+  return status;
+}
+
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bt/service/common/android/bluetooth/advertise_data.h b/bt/service/common/android/bluetooth/advertise_data.h
new file mode 100644
index 0000000..cde0eac
--- /dev/null
+++ b/bt/service/common/android/bluetooth/advertise_data.h
@@ -0,0 +1,54 @@
+//
+//  Copyright (C) 2016 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 "bluetooth/advertise_data.h"
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class AdvertiseData : public Parcelable, public ::bluetooth::AdvertiseData {
+ public:
+  // NOLINT, implicit converter
+  AdvertiseData(const ::bluetooth::AdvertiseData& advertise_data)  // NOLINT
+      : ::bluetooth::AdvertiseData(advertise_data){};
+  AdvertiseData() = default;
+  ~AdvertiseData() = default;
+
+  // Write |this| parcelable to the given |parcel|.  Keep in mind that
+  // implementations of writeToParcel must be manually kept in sync
+  // with readFromParcel and the Java equivalent versions of these methods.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t writeToParcel(Parcel* parcel) const override;
+
+  // Read data from the given |parcel| into |this|.  After readFromParcel
+  // completes, |this| should have equivalent state to the object that
+  // wrote itself to the parcel.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t readFromParcel(const Parcel* parcel) override;
+};
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bt/service/common/android/bluetooth/advertise_settings.cc b/bt/service/common/android/bluetooth/advertise_settings.cc
new file mode 100644
index 0000000..b8fb1d1
--- /dev/null
+++ b/bt/service/common/android/bluetooth/advertise_settings.cc
@@ -0,0 +1,63 @@
+//
+//  Copyright (C) 2016 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "android/bluetooth/advertise_settings.h"
+
+using android::OK;
+
+namespace android {
+namespace bluetooth {
+
+status_t AdvertiseSettings::writeToParcel(Parcel* parcel) const {
+  status_t status = parcel->writeInt32(mode_);
+  if (status != OK) return status;
+
+  status = parcel->writeInt32(tx_power_level_);
+  if (status != OK) return status;
+
+  status = parcel->writeInt32(connectable_);
+  if (status != OK) return status;
+
+  status = parcel->writeInt32(timeout_.InMilliseconds());
+  return status;
+}
+
+status_t AdvertiseSettings::readFromParcel(const Parcel* parcel) {
+  int32_t value;
+  status_t status = parcel->readInt32(&value);
+  if (status != OK) return status;
+
+  mode_ = static_cast<AdvertiseSettings::Mode>(value);
+
+  status = parcel->readInt32(&value);
+  if (status != OK) return status;
+
+  tx_power_level_ = static_cast<AdvertiseSettings::TxPowerLevel>(value);
+
+  status = parcel->readInt32(&value);
+  if (status != OK) return status;
+
+  connectable_ = static_cast<bool>(value);
+
+  status = parcel->readInt32(&value);
+  if (status != OK) return status;
+
+  timeout_ = ::base::TimeDelta::FromMilliseconds(value);
+  return status;
+}
+
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bt/service/common/android/bluetooth/advertise_settings.h b/bt/service/common/android/bluetooth/advertise_settings.h
new file mode 100644
index 0000000..19eeda5
--- /dev/null
+++ b/bt/service/common/android/bluetooth/advertise_settings.h
@@ -0,0 +1,55 @@
+//
+//  Copyright (C) 2016 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 "bluetooth/advertise_settings.h"
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class AdvertiseSettings : public Parcelable,
+                          public ::bluetooth::AdvertiseSettings {
+ public:
+  // NOLINT, implicit converter
+  AdvertiseSettings(const ::bluetooth::AdvertiseSettings& advertise_settings) // NOLINT
+      : ::bluetooth::AdvertiseSettings(advertise_settings){};
+  AdvertiseSettings() = default;
+  ~AdvertiseSettings() = default;
+
+  // Write |this| parcelable to the given |parcel|.  Keep in mind that
+  // implementations of writeToParcel must be manually kept in sync
+  // with readFromParcel and the Java equivalent versions of these methods.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t writeToParcel(Parcel* parcel) const override;
+
+  // Read data from the given |parcel| into |this|.  After readFromParcel
+  // completes, |this| should have equivalent state to the object that
+  // wrote itself to the parcel.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t readFromParcel(const Parcel* parcel) override;
+};
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bt/service/common/android/bluetooth/bluetooth_gatt_characteristic.cc b/bt/service/common/android/bluetooth/bluetooth_gatt_characteristic.cc
new file mode 100644
index 0000000..cf1fb2f
--- /dev/null
+++ b/bt/service/common/android/bluetooth/bluetooth_gatt_characteristic.cc
@@ -0,0 +1,84 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/android/bluetooth/bluetooth_gatt_characteristic.h"
+#include "service/common/android/bluetooth/bluetooth_gatt_descriptor.h"
+#include "service/common/android/bluetooth/uuid.h"
+
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+using android::OK;
+using android::String8;
+using android::String16;
+
+namespace android {
+namespace bluetooth {
+
+status_t BluetoothGattCharacteristic::writeToParcel(Parcel* parcel) const {
+  status_t status = parcel->writeInt32(handle_);
+  if (status != OK) return status;
+
+  status = parcel->writeParcelable((UUID)uuid_);
+  if (status != OK) return status;
+
+  status = parcel->writeInt32(properties_);
+  if (status != OK) return status;
+
+  status = parcel->writeInt32(permissions_);
+  if (status != OK) return status;
+
+  std::vector<BluetoothGattDescriptor> descriptors;
+  for (const auto& desc : descriptors_) {
+    descriptors.push_back(desc);
+  }
+
+  status = parcel->writeParcelableVector(descriptors);
+  return status;
+}
+
+status_t BluetoothGattCharacteristic::readFromParcel(const Parcel* parcel) {
+  int32_t tmp;
+  status_t status = parcel->readInt32(&tmp);
+  if (status != OK) return status;
+  handle_ = tmp;
+
+  UUID uuid;
+  status = parcel->readParcelable(&uuid);
+  if (status != OK) return status;
+  uuid_ = uuid;
+
+  status = parcel->readInt32(&tmp);
+  if (status != OK) return status;
+  properties_ = tmp;
+
+  status = parcel->readInt32(&tmp);
+  if (status != OK) return status;
+  permissions_ = tmp;
+
+  std::vector<BluetoothGattDescriptor> descriptors;
+  status = parcel->readParcelableVector(&descriptors);
+  if (status != OK) return status;
+
+  for (const auto& desc : descriptors) {
+    descriptors_.push_back(desc);
+  }
+
+  return status;
+}
+
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bt/service/common/android/bluetooth/bluetooth_gatt_characteristic.h b/bt/service/common/android/bluetooth/bluetooth_gatt_characteristic.h
new file mode 100644
index 0000000..2286068
--- /dev/null
+++ b/bt/service/common/android/bluetooth/bluetooth_gatt_characteristic.h
@@ -0,0 +1,53 @@
+//
+//  Copyright (C) 2016 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 "bluetooth/characteristic.h"
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class BluetoothGattCharacteristic : public Parcelable, public ::bluetooth::Characteristic {
+ public:
+  BluetoothGattCharacteristic() = default;
+  BluetoothGattCharacteristic(const ::bluetooth::Characteristic& characteristic)  // NOLINT(implicit)
+      : ::bluetooth::Characteristic(characteristic){};
+  ~BluetoothGattCharacteristic() = default;
+
+  // Write |this| parcelable to the given |parcel|.  Keep in mind that
+  // implementations of writeToParcel must be manually kept in sync
+  // with readFromParcel and the Java equivalent versions of these methods.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t writeToParcel(Parcel* parcel) const override;
+
+  // Read data from the given |parcel| into |this|.  After readFromParcel
+  // completes, |this| should have equivalent state to the object that
+  // wrote itself to the parcel.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t readFromParcel(const Parcel* parcel) override;
+};
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bt/service/common/android/bluetooth/bluetooth_gatt_descriptor.cc b/bt/service/common/android/bluetooth/bluetooth_gatt_descriptor.cc
new file mode 100644
index 0000000..7749404
--- /dev/null
+++ b/bt/service/common/android/bluetooth/bluetooth_gatt_descriptor.cc
@@ -0,0 +1,60 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/android/bluetooth/bluetooth_gatt_descriptor.h"
+#include "service/common/android/bluetooth/uuid.h"
+
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+using android::OK;
+using android::String8;
+using android::String16;
+
+namespace android {
+namespace bluetooth {
+
+status_t BluetoothGattDescriptor::writeToParcel(Parcel* parcel) const {
+  status_t status = parcel->writeParcelable((UUID)uuid_);
+  if (status != OK) return status;
+
+  status = parcel->writeInt32(handle_);
+  if (status != OK) return status;
+
+  status = parcel->writeInt32(permissions_);
+  return status;
+}
+
+status_t BluetoothGattDescriptor::readFromParcel(const Parcel* parcel) {
+  UUID uuid;
+  status_t status = parcel->readParcelable(&uuid);
+  if (status != OK) return status;
+  uuid_ = (bluetooth::UUID)uuid;
+
+  int32_t tmp;
+  status = parcel->readInt32(&tmp);
+  if (status != OK) return status;
+  handle_ = tmp;
+
+  status = parcel->readInt32(&tmp);
+  if (status != OK) return status;
+  permissions_ = tmp;
+
+  return status;
+}
+
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bt/service/common/android/bluetooth/bluetooth_gatt_descriptor.h b/bt/service/common/android/bluetooth/bluetooth_gatt_descriptor.h
new file mode 100644
index 0000000..c791c24
--- /dev/null
+++ b/bt/service/common/android/bluetooth/bluetooth_gatt_descriptor.h
@@ -0,0 +1,53 @@
+//
+//  Copyright (C) 2016 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 "bluetooth/descriptor.h"
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class BluetoothGattDescriptor : public Parcelable, public ::bluetooth::Descriptor {
+ public:
+  BluetoothGattDescriptor() = default;
+  BluetoothGattDescriptor(const ::bluetooth::Descriptor& characteristic)  // NOLINT(implicit)
+      : ::bluetooth::Descriptor(characteristic){};
+  ~BluetoothGattDescriptor() = default;
+
+  // Write |this| parcelable to the given |parcel|.  Keep in mind that
+  // implementations of writeToParcel must be manually kept in sync
+  // with readFromParcel and the Java equivalent versions of these methods.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t writeToParcel(Parcel* parcel) const override;
+
+  // Read data from the given |parcel| into |this|.  After readFromParcel
+  // completes, |this| should have equivalent state to the object that
+  // wrote itself to the parcel.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t readFromParcel(const Parcel* parcel) override;
+};
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bt/service/common/android/bluetooth/bluetooth_gatt_included_service.cc b/bt/service/common/android/bluetooth/bluetooth_gatt_included_service.cc
new file mode 100644
index 0000000..9b4090e
--- /dev/null
+++ b/bt/service/common/android/bluetooth/bluetooth_gatt_included_service.cc
@@ -0,0 +1,58 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/android/bluetooth/bluetooth_gatt_service.h"
+#include "service/common/android/bluetooth/bluetooth_gatt_characteristic.h"
+#include "service/common/android/bluetooth/uuid.h"
+
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+using android::OK;
+using android::String8;
+using android::String16;
+
+namespace android {
+namespace bluetooth {
+
+status_t BluetoothGattIncludedService::writeToParcel(Parcel* parcel) const {
+  status_t status = parcel->writeParcelable((UUID)uuid_);
+  if (status != OK) return status;
+
+  status = parcel->writeInt32(handle_);
+  if (status != OK) return status;
+
+  status = parcel->writeBool(primary_);
+  return status;
+}
+
+status_t BluetoothGattIncludedService::readFromParcel(const Parcel* parcel) {
+  UUID uuid;
+  status_t status = parcel->readParcelable(&uuid);
+  if (status != OK) return status;
+  uuid_ = uuid;
+
+  int32_t tmp;
+  status = parcel->readInt32(&tmp);
+  if (status != OK) return status;
+  handle_ = tmp;
+
+  status = parcel->readBool(&primary_);
+  return status;
+}
+
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bt/service/common/android/bluetooth/bluetooth_gatt_included_service.h b/bt/service/common/android/bluetooth/bluetooth_gatt_included_service.h
new file mode 100644
index 0000000..7ff344f
--- /dev/null
+++ b/bt/service/common/android/bluetooth/bluetooth_gatt_included_service.h
@@ -0,0 +1,65 @@
+//
+//  Copyright (C) 2016 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 "bluetooth/service.h"
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+using ::bluetooth::UUID;
+
+namespace android {
+namespace bluetooth {
+
+class BluetoothGattIncludedService : public Parcelable {
+ public:
+  BluetoothGattIncludedService() = default;
+  BluetoothGattIncludedService(const ::bluetooth::Service& service)  // NOLINT(implicit)
+    : handle_(service.handle()), uuid_(service.uuid()),
+      primary_(service.primary()) {};
+  ~BluetoothGattIncludedService() = default;
+
+  // Write |this| parcelable to the given |parcel|.  Keep in mind that
+  // implementations of writeToParcel must be manually kept in sync
+  // with readFromParcel and the Java equivalent versions of these methods.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t writeToParcel(Parcel* parcel) const override;
+
+  // Read data from the given |parcel| into |this|.  After readFromParcel
+  // completes, |this| should have equivalent state to the object that
+  // wrote itself to the parcel.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t readFromParcel(const Parcel* parcel) override;
+
+  uint16_t handle() const { return handle_; }
+  bool primary() const { return primary_; }
+  UUID uuid() const { return uuid_; }
+
+protected:
+  uint16_t handle_;
+  UUID uuid_;
+  bool primary_;
+};
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bt/service/common/android/bluetooth/bluetooth_gatt_service.cc b/bt/service/common/android/bluetooth/bluetooth_gatt_service.cc
new file mode 100644
index 0000000..cdbd73f
--- /dev/null
+++ b/bt/service/common/android/bluetooth/bluetooth_gatt_service.cc
@@ -0,0 +1,88 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/android/bluetooth/bluetooth_gatt_service.h"
+#include "service/common/android/bluetooth/bluetooth_gatt_characteristic.h"
+#include "service/common/android/bluetooth/uuid.h"
+
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+using android::OK;
+using android::String8;
+using android::String16;
+
+namespace android {
+namespace bluetooth {
+
+status_t BluetoothGattService::writeToParcel(Parcel* parcel) const {
+  status_t status = parcel->writeInt32(handle_);
+  if (status != OK) return status;
+
+  status = parcel->writeBool(primary_);
+  if (status != OK) return status;
+
+  status = parcel->writeParcelable((UUID)uuid_);
+  if (status != OK) return status;
+
+  std::vector<BluetoothGattCharacteristic> characteristics;
+  for (const auto& chrc : characteristics_)
+    characteristics.push_back(chrc);
+
+  status = parcel->writeParcelableVector(characteristics);
+
+  std::vector<BluetoothGattIncludedService> includedServices;
+  for (const auto& service : included_services_)
+    includedServices.push_back(service);
+
+  status = parcel->writeParcelableVector(includedServices);
+
+  return status;
+}
+
+status_t BluetoothGattService::readFromParcel(const Parcel* parcel) {
+  int32_t tmp;
+  status_t status = parcel->readInt32(&tmp);
+  if (status != OK) return status;
+  handle_ = tmp;
+
+  status = parcel->readBool(&primary_);
+  if (status != OK) return status;
+
+  UUID uuid;
+  status = parcel->readParcelable(&uuid);
+  if (status != OK) return status;
+  uuid_ = uuid;
+
+  std::vector<BluetoothGattCharacteristic> characteristics;
+  status = parcel->readParcelableVector(&characteristics);
+  if (status != OK) return status;
+
+  for (const auto& chrc : characteristics)
+    characteristics_.push_back(chrc);
+
+  std::vector<BluetoothGattIncludedService> includedServices;
+  status = parcel->readParcelableVector(&includedServices);
+  if (status != OK) return status;
+
+  for (const auto& srvc : includedServices)
+    included_services_.push_back(BluetoothGattService(srvc));
+
+  return status;
+}
+
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bt/service/common/android/bluetooth/bluetooth_gatt_service.h b/bt/service/common/android/bluetooth/bluetooth_gatt_service.h
new file mode 100644
index 0000000..eb6a30e
--- /dev/null
+++ b/bt/service/common/android/bluetooth/bluetooth_gatt_service.h
@@ -0,0 +1,56 @@
+//
+//  Copyright (C) 2016 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 "bluetooth/service.h"
+#include "android/bluetooth/bluetooth_gatt_included_service.h"
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class BluetoothGattService : public Parcelable, public ::bluetooth::Service {
+ public:
+  BluetoothGattService() = default;
+  BluetoothGattService(const ::bluetooth::Service& service) : ::bluetooth::Service(service){};  // NOLINT(implicit)
+  BluetoothGattService(const BluetoothGattIncludedService& includedService)  // NOLINT(implicit)
+    : ::bluetooth::Service(includedService.handle(), includedService.primary(),
+                           includedService.uuid(), {}, {}) {};
+  ~BluetoothGattService() = default;
+
+  // Write |this| parcelable to the given |parcel|.  Keep in mind that
+  // implementations of writeToParcel must be manually kept in sync
+  // with readFromParcel and the Java equivalent versions of these methods.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t writeToParcel(Parcel* parcel) const override;
+
+  // Read data from the given |parcel| into |this|.  After readFromParcel
+  // completes, |this| should have equivalent state to the object that
+  // wrote itself to the parcel.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t readFromParcel(const Parcel* parcel) override;
+};
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bt/service/common/android/bluetooth/scan_filter.cc b/bt/service/common/android/bluetooth/scan_filter.cc
new file mode 100644
index 0000000..514b932
--- /dev/null
+++ b/bt/service/common/android/bluetooth/scan_filter.cc
@@ -0,0 +1,93 @@
+//
+//  Copyright (C) 2016 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/android/bluetooth/scan_filter.h"
+#include "service/common/android/bluetooth/uuid.h"
+
+#include <binder/Parcel.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+using android::Parcelable;
+using android::Parcel;
+using android::String8;
+using android::String16;
+using android::status_t;
+using android::OK;
+
+namespace android {
+namespace bluetooth {
+
+status_t ScanFilter::writeToParcel(Parcel* parcel) const {
+  status_t status =
+      parcel->writeString16(String16(String8(device_name_.c_str())));
+  if (status != OK) return status;
+
+  status = parcel->writeString16(String16(String8(device_address_.c_str())));
+  if (status != OK) return status;
+
+  //TODO(jpawlowski) make type casting nicer
+  // uuid won't really keep ownership, it's just for type casting
+  std::unique_ptr<UUID> uuid;
+  UUID tmp;
+
+  if (service_uuid_) {
+    tmp = *service_uuid_;
+    uuid.reset(&tmp);
+  } else {
+    uuid.reset(nullptr);
+  }
+  status = parcel->writeNullableParcelable(uuid);
+  uuid.release();
+  if (status != OK) return status;
+
+  if (service_uuid_mask_) {
+    tmp = *service_uuid_mask_;
+    uuid.reset(&tmp);
+  } else {
+    uuid.reset(nullptr);
+  }
+  status = parcel->writeNullableParcelable(uuid);
+  uuid.release();
+
+  return status;
+}
+
+status_t ScanFilter::readFromParcel(const Parcel* parcel) {
+  String16 name;
+  status_t status = parcel->readString16(&name);
+  if (status != OK) return status;
+  device_name_ = std::string(String8(name).string());
+
+  String16 addr;
+  status = parcel->readString16(&addr);
+  if (status != OK) return status;
+  device_address_ = std::string(String8(addr).string());
+
+  std::unique_ptr<UUID> uuid;
+  status = parcel->readParcelable(&uuid);
+  if (status != OK) return status;
+  service_uuid_ = std::move(uuid);
+
+  status = parcel->readParcelable(&uuid);
+  if (status != OK) return status;
+  service_uuid_mask_ = std::move(uuid);
+
+  return status;
+}
+
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bt/service/common/android/bluetooth/scan_filter.h b/bt/service/common/android/bluetooth/scan_filter.h
new file mode 100644
index 0000000..90dcbd9
--- /dev/null
+++ b/bt/service/common/android/bluetooth/scan_filter.h
@@ -0,0 +1,54 @@
+//
+//  Copyright (C) 2016 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 "bluetooth/scan_filter.h"
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class ScanFilter : public Parcelable, public ::bluetooth::ScanFilter {
+ public:
+  ScanFilter() = default;
+  // NOLINT, implicit converter
+  ScanFilter(const ::bluetooth::ScanFilter& scan_filter) // NOLINT
+      : ::bluetooth::ScanFilter(scan_filter){};
+  ~ScanFilter() = default;
+
+  // Write |this| parcelable to the given |parcel|.  Keep in mind that
+  // implementations of writeToParcel must be manually kept in sync
+  // with readFromParcel and the Java equivalent versions of these methods.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t writeToParcel(Parcel* parcel) const override;
+
+  // Read data from the given |parcel| into |this|.  After readFromParcel
+  // completes, |this| should have equivalent state to the object that
+  // wrote itself to the parcel.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t readFromParcel(const Parcel* parcel) override;
+};
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bt/service/common/android/bluetooth/scan_result.cc b/bt/service/common/android/bluetooth/scan_result.cc
new file mode 100644
index 0000000..17378df
--- /dev/null
+++ b/bt/service/common/android/bluetooth/scan_result.cc
@@ -0,0 +1,60 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/android/bluetooth/scan_result.h"
+
+#include <base/logging.h>
+#include <binder/Parcel.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+using android::Parcelable;
+using android::Parcel;
+using android::String8;
+using android::String16;
+using android::status_t;
+using android::OK;
+
+namespace android {
+namespace bluetooth {
+
+status_t ScanResult::writeToParcel(Parcel* parcel) const {
+  status_t status =
+      parcel->writeString16(String16(String8(device_address_.c_str())));
+  if (status != OK) return status;
+
+  status = parcel->writeByteVector(scan_record_);
+  if (status != OK) return status;
+
+  status = parcel->writeInt32(rssi_);
+  return status;
+}
+
+status_t ScanResult::readFromParcel(const Parcel* parcel) {
+  String16 addr;
+  status_t status = parcel->readString16(&addr);
+  if (status != OK) return status;
+  device_address_ = std::string(String8(addr).string());
+
+  status = parcel->readByteVector(&scan_record_);
+  if (status != OK) return status;
+
+  status = parcel->readInt32(&rssi_);
+  return status;
+}
+
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bt/service/common/android/bluetooth/scan_result.h b/bt/service/common/android/bluetooth/scan_result.h
new file mode 100644
index 0000000..732ef0c
--- /dev/null
+++ b/bt/service/common/android/bluetooth/scan_result.h
@@ -0,0 +1,54 @@
+//
+//  Copyright (C) 2016 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 "bluetooth/scan_result.h"
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class ScanResult : public Parcelable, public ::bluetooth::ScanResult {
+ public:
+  ScanResult() = default;
+  // NOLINT, implicit converter
+  ScanResult(const ::bluetooth::ScanResult& scan_result)  // NOLINT
+      : ::bluetooth::ScanResult(scan_result){};
+  ~ScanResult() = default;
+
+  // Write |this| parcelable to the given |parcel|.  Keep in mind that
+  // implementations of writeToParcel must be manually kept in sync
+  // with readFromParcel and the Java equivalent versions of these methods.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t writeToParcel(Parcel* parcel) const override;
+
+  // Read data from the given |parcel| into |this|.  After readFromParcel
+  // completes, |this| should have equivalent state to the object that
+  // wrote itself to the parcel.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t readFromParcel(const Parcel* parcel) override;
+};
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bt/service/common/android/bluetooth/scan_settings.cc b/bt/service/common/android/bluetooth/scan_settings.cc
new file mode 100644
index 0000000..0920cca
--- /dev/null
+++ b/bt/service/common/android/bluetooth/scan_settings.cc
@@ -0,0 +1,80 @@
+//
+//  Copyright (C) 2016 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/android/bluetooth/scan_settings.h"
+
+#include <binder/Parcel.h>
+
+using android::Parcelable;
+using android::Parcel;
+using android::String16;
+using android::status_t;
+using android::OK;
+
+namespace android {
+namespace bluetooth {
+
+status_t ScanSettings::writeToParcel(Parcel* parcel) const {
+  status_t status = parcel->writeInt32(mode_);
+  if (status != OK) return status;
+
+  status = parcel->writeInt32(callback_type_);
+  if (status != OK) return status;
+
+  status = parcel->writeInt32(result_type_);
+  if (status != OK) return status;
+
+  status = parcel->writeInt64(report_delay_ms_.InMilliseconds());
+  if (status != OK) return status;
+
+  status = parcel->writeInt32(match_mode_);
+  if (status != OK) return status;
+
+  status = parcel->writeInt32(match_count_per_filter_);
+  return status;
+}
+
+status_t ScanSettings::readFromParcel(const Parcel* parcel) {
+  int value;
+  status_t status = parcel->readInt32(&value);
+  if (status != OK) return status;
+  mode_ = static_cast<ScanSettings::Mode>(value);
+
+  status = parcel->readInt32(&value);
+  if (status != OK) return status;
+  callback_type_ = static_cast<ScanSettings::CallbackType>(value);
+
+  status = parcel->readInt32(&value);
+  if (status != OK) return status;
+  result_type_ = static_cast<ScanSettings::ResultType>(value);
+
+  int64_t value64;
+  status = parcel->readInt64(&value64);
+  report_delay_ms_ = ::base::TimeDelta::FromMilliseconds(value64);
+
+  status = parcel->readInt32(&value);
+  if (status != OK) return status;
+  match_mode_ = static_cast<ScanSettings::MatchMode>(value);
+
+  status = parcel->readInt32(&value);
+  if (status != OK) return status;
+  match_count_per_filter_ = static_cast<ScanSettings::MatchCount>(value);
+
+  return status;
+}
+
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bt/service/common/android/bluetooth/scan_settings.h b/bt/service/common/android/bluetooth/scan_settings.h
new file mode 100644
index 0000000..bae0125
--- /dev/null
+++ b/bt/service/common/android/bluetooth/scan_settings.h
@@ -0,0 +1,54 @@
+//
+//  Copyright (C) 2016 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 "bluetooth/scan_settings.h"
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class ScanSettings : public Parcelable, public ::bluetooth::ScanSettings {
+ public:
+  ScanSettings() = default;
+  // NOLINT, implicit converter
+  ScanSettings(const ::bluetooth::ScanSettings& scan_settings) // NOLINT
+      : ::bluetooth::ScanSettings(scan_settings){};
+  ~ScanSettings() = default;
+
+  // Write |this| parcelable to the given |parcel|.  Keep in mind that
+  // implementations of writeToParcel must be manually kept in sync
+  // with readFromParcel and the Java equivalent versions of these methods.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t writeToParcel(Parcel* parcel) const override;
+
+  // Read data from the given |parcel| into |this|.  After readFromParcel
+  // completes, |this| should have equivalent state to the object that
+  // wrote itself to the parcel.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t readFromParcel(const Parcel* parcel) override;
+};
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bt/service/common/android/bluetooth/uuid.cc b/bt/service/common/android/bluetooth/uuid.cc
new file mode 100644
index 0000000..6d03bb6
--- /dev/null
+++ b/bt/service/common/android/bluetooth/uuid.cc
@@ -0,0 +1,91 @@
+//
+//  Copyright (C) 2016 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/android/bluetooth/uuid.h"
+
+#include <binder/Parcel.h>
+
+using android::Parcelable;
+using android::Parcel;
+using android::String16;
+using android::status_t;
+using android::OK;
+
+namespace android {
+namespace bluetooth {
+
+status_t UUID::writeToParcel(Parcel* parcel) const {
+  // The scheme used by android.os.ParcelUuid is to wrote the most significant
+  // bits first as one 64-bit integer, followed by the least significant bits in
+  // a second 64-bit integer. This is the same as writing the raw-bytes in
+  // sequence, but we don't want to assume any host-endianness here. So follow
+  // the same scheme and use the same Parcel APIs.
+  UUID::UUID128Bit bytes = GetFullBigEndian();
+
+  uint64_t most_sig_bits =
+      ((((uint64_t)bytes[0]) << 56) | (((uint64_t)bytes[1]) << 48) |
+       (((uint64_t)bytes[2]) << 40) | (((uint64_t)bytes[3]) << 32) |
+       (((uint64_t)bytes[4]) << 24) | (((uint64_t)bytes[5]) << 16) |
+       (((uint64_t)bytes[6]) << 8) | bytes[7]);
+
+  uint64_t least_sig_bits =
+      ((((uint64_t)bytes[8]) << 56) | (((uint64_t)bytes[9]) << 48) |
+       (((uint64_t)bytes[10]) << 40) | (((uint64_t)bytes[11]) << 32) |
+       (((uint64_t)bytes[12]) << 24) | (((uint64_t)bytes[13]) << 16) |
+       (((uint64_t)bytes[14]) << 8) | bytes[15]);
+
+  status_t status = parcel->writeUint64(most_sig_bits);
+  if (status != OK) return status;
+
+  status = parcel->writeUint64(least_sig_bits);
+  return status;
+}
+
+status_t UUID::readFromParcel(const Parcel* parcel) {
+  UUID::UUID128Bit bytes;
+
+  uint64_t most_sig_bits, least_sig_bits;
+  status_t status = parcel->readUint64(&most_sig_bits);
+  if (status != OK) return status;
+
+  status = parcel->readUint64(&least_sig_bits);
+  if (status != OK) return status;
+
+  bytes[0] = (most_sig_bits >> 56) & 0xFF;
+  bytes[1] = (most_sig_bits >> 48) & 0xFF;
+  bytes[2] = (most_sig_bits >> 40) & 0xFF;
+  bytes[3] = (most_sig_bits >> 32) & 0xFF;
+  bytes[4] = (most_sig_bits >> 24) & 0xFF;
+  bytes[5] = (most_sig_bits >> 16) & 0xFF;
+  bytes[6] = (most_sig_bits >> 8) & 0xFF;
+  bytes[7] = most_sig_bits & 0xFF;
+
+  bytes[8] = (least_sig_bits >> 56) & 0xFF;
+  bytes[9] = (least_sig_bits >> 48) & 0xFF;
+  bytes[10] = (least_sig_bits >> 40) & 0xFF;
+  bytes[11] = (least_sig_bits >> 32) & 0xFF;
+  bytes[12] = (least_sig_bits >> 24) & 0xFF;
+  bytes[13] = (least_sig_bits >> 16) & 0xFF;
+  bytes[14] = (least_sig_bits >> 8) & 0xFF;
+  bytes[15] = least_sig_bits & 0xFF;
+
+  id_ = bytes;
+  is_valid_ = true;
+  return status;
+}
+
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bt/service/common/android/bluetooth/uuid.h b/bt/service/common/android/bluetooth/uuid.h
new file mode 100644
index 0000000..c0a09e0
--- /dev/null
+++ b/bt/service/common/android/bluetooth/uuid.h
@@ -0,0 +1,53 @@
+//
+//  Copyright (C) 2016 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 "bluetooth/uuid.h"
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class UUID : public Parcelable, public ::bluetooth::UUID {
+ public:
+  UUID() = default;
+  // NOLINT, implicit converter
+  UUID(const ::bluetooth::UUID& uuid) : ::bluetooth::UUID(uuid){};  // NOLINT
+  ~UUID() = default;
+
+  // Write |this| parcelable to the given |parcel|.  Keep in mind that
+  // implementations of writeToParcel must be manually kept in sync
+  // with readFromParcel and the Java equivalent versions of these methods.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t writeToParcel(Parcel* parcel) const override;
+
+  // Read data from the given |parcel| into |this|.  After readFromParcel
+  // completes, |this| should have equivalent state to the object that
+  // wrote itself to the parcel.
+  //
+  // Returns android::OK on success and an appropriate error otherwise.
+  status_t readFromParcel(const Parcel* parcel) override;
+};
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bt/service/common/bluetooth/adapter_state.cc b/bt/service/common/bluetooth/adapter_state.cc
new file mode 100644
index 0000000..87d23b1
--- /dev/null
+++ b/bt/service/common/bluetooth/adapter_state.cc
@@ -0,0 +1,44 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/bluetooth/adapter_state.h"
+
+namespace bluetooth {
+
+std::string AdapterStateToString(AdapterState state) {
+  switch (state) {
+  case ADAPTER_STATE_DISCONNECTED:
+    return "ADAPTER_STATE_DISCONNECTED";
+  case ADAPTER_STATE_CONNECTING:
+    return "ADAPTER_STATE_CONNECTING";
+  case ADAPTER_STATE_CONNECTED:
+    return "ADAPTER_STATE_CONNECTED";
+  case ADAPTER_STATE_DISCONNECTING:
+    return "ADAPTER_STATE_DISCONNECTING";
+  case ADAPTER_STATE_OFF:
+    return "ADAPTER_STATE_OFF";
+  case ADAPTER_STATE_TURNING_ON:
+    return "ADAPTER_STATE_TURNING_ON";
+  case ADAPTER_STATE_ON:
+    return "ADAPTER_STATE_ON";
+  case ADAPTER_STATE_TURNING_OFF:
+    return "ADAPTER_STATE_TURNING_OFF";
+  default:
+    return "unknown state";
+  }
+}
+
+}  // namespace bluetooth
diff --git a/bt/service/common/bluetooth/adapter_state.h b/bt/service/common/bluetooth/adapter_state.h
new file mode 100644
index 0000000..1b2fbe4
--- /dev/null
+++ b/bt/service/common/bluetooth/adapter_state.h
@@ -0,0 +1,43 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 {
+
+// Possible Adapter states. The values for each enumration have been copied
+// from frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java.
+// These values need to match their android.bluetooth.BluetoothAdapter
+// counterparts for this to be compatible with the framework, hence we
+// redeclare them here.
+enum AdapterState {
+  ADAPTER_STATE_DISCONNECTED = 0,
+  ADAPTER_STATE_CONNECTING = 1,
+  ADAPTER_STATE_CONNECTED = 2,
+  ADAPTER_STATE_DISCONNECTING = 3,
+  ADAPTER_STATE_OFF = 10,
+  ADAPTER_STATE_TURNING_ON = 11,
+  ADAPTER_STATE_ON = 12,
+  ADAPTER_STATE_TURNING_OFF = 13,
+  ADAPTER_STATE_INVALID = 0xFFFF
+};
+
+// Returns a string for the given Adapter state |state|.
+std::string AdapterStateToString(AdapterState state);
+
+}  // namespace bluetooth
diff --git a/bt/service/common/bluetooth/advertise_data.cc b/bt/service/common/bluetooth/advertise_data.cc
new file mode 100644
index 0000000..93bffa8
--- /dev/null
+++ b/bt/service/common/bluetooth/advertise_data.cc
@@ -0,0 +1,83 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/bluetooth/advertise_data.h"
+
+#include <base/logging.h>
+
+#include "stack/include/bt_types.h"
+#include "stack/include/hcidefs.h"
+
+namespace bluetooth {
+
+AdvertiseData::AdvertiseData(const std::vector<uint8_t>& data) : data_(data) {}
+
+AdvertiseData::AdvertiseData() {}
+
+AdvertiseData::AdvertiseData(const AdvertiseData& other) : data_(other.data_) {}
+
+bool AdvertiseData::IsValid() const {
+  size_t len = data_.size();
+
+  // Consider empty data as valid.
+  if (!len) return true;
+
+  for (size_t i = 0, field_len = 0; i < len; i += (field_len + 1)) {
+    field_len = data_[i];
+
+    // If the length of the current field would exceed the total data length,
+    // then the data is badly formatted.
+    if (i + field_len >= len) {
+      VLOG(1) << "Advertising data badly formatted";
+      return false;
+    }
+
+    // A field length of 0 would be invalid as it should at least contain the
+    // EIR field type.
+    if (field_len < 1) return false;
+
+    uint8_t type = data_[i + 1];
+
+    // Clients are not allowed to set the following EIR fields as these are
+    // managed by stack.
+    switch (type) {
+      case HCI_EIR_FLAGS_TYPE:
+      case HCI_EIR_OOB_BD_ADDR_TYPE:
+      case HCI_EIR_OOB_COD_TYPE:
+      case HCI_EIR_OOB_SSP_HASH_C_TYPE:
+      case HCI_EIR_OOB_SSP_RAND_R_TYPE:
+        VLOG(1) << "Cannot set EIR field type: " << type;
+        return false;
+      default:
+        break;
+    }
+  }
+
+  return true;
+}
+
+bool AdvertiseData::operator==(const AdvertiseData& rhs) const {
+  return data_ == rhs.data_;
+}
+
+AdvertiseData& AdvertiseData::operator=(const AdvertiseData& other) {
+  if (this == &other) return *this;
+
+  data_ = other.data_;
+  return *this;
+}
+
+}  // namespace bluetooth
diff --git a/bt/service/common/bluetooth/advertise_data.h b/bt/service/common/bluetooth/advertise_data.h
new file mode 100644
index 0000000..f5f5b5c
--- /dev/null
+++ b/bt/service/common/bluetooth/advertise_data.h
@@ -0,0 +1,64 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <vector>
+
+#include <base/macros.h>
+
+namespace bluetooth {
+
+// Represents a data packet for Bluetooth Low Energy advertisements. This is the
+// native equivalent of the Android framework class defined in
+// frameworks/base/core/j/android/bluetooth/le/AdvertiseData.java
+class AdvertiseData {
+ public:
+  // Constructs an AdvertiseData with the given parameters. |data| can only
+  // contain the "Service UUIDs", "Service Data", "Manufacturer Data",
+  // "Tx Power" and "Device name" fields as specified in the Core Specification
+  //  Supplement. |data| must be properly formatted according to the supplement
+  // and contains the data as it will be sent over the wire.
+  //
+  // Tx Power field value will be filled with proper value.
+  explicit AdvertiseData(const std::vector<uint8_t>& data);
+
+  // Default constructor initializes all fields to be empty/false.
+  AdvertiseData();
+  AdvertiseData(const AdvertiseData& other);
+  ~AdvertiseData() = default;
+
+  // Returns true if the advertising data is formatted correctly according to
+  // the TLV format.
+  bool IsValid() const;
+
+  // data() returns the current advertising data contained by this instance. The
+  // data is in the TLV format as specified in the Bluetooth Core Specification.
+  const std::vector<uint8_t>& data() const { return data_; }
+
+  // Comparison operator.
+  bool operator==(const AdvertiseData& rhs) const;
+
+  // Assignment operator
+  AdvertiseData& operator=(const AdvertiseData& other);
+
+ protected:
+  std::vector<uint8_t> data_;
+};
+
+}  // namespace bluetooth
diff --git a/bt/service/common/bluetooth/advertise_settings.cc b/bt/service/common/bluetooth/advertise_settings.cc
new file mode 100644
index 0000000..ffe65ea
--- /dev/null
+++ b/bt/service/common/bluetooth/advertise_settings.cc
@@ -0,0 +1,55 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/bluetooth/advertise_settings.h"
+
+namespace bluetooth {
+
+AdvertiseSettings::AdvertiseSettings(
+    Mode mode,
+    base::TimeDelta timeout,
+    TxPowerLevel tx_power_level,
+    bool connectable)
+    : mode_(mode),
+      timeout_(timeout),
+      tx_power_level_(tx_power_level),
+      connectable_(connectable) {
+}
+
+// Default values are taken from the AdvertiseSettings.java
+AdvertiseSettings::AdvertiseSettings()
+    : mode_(MODE_LOW_POWER),
+      tx_power_level_(TX_POWER_LEVEL_MEDIUM),
+      connectable_(true) {
+}
+
+bool AdvertiseSettings::operator==(const AdvertiseSettings& rhs) const {
+  if (mode_ != rhs.mode_)
+    return false;
+
+  if (timeout_ != rhs.timeout_)
+    return false;
+
+  if (tx_power_level_ != rhs.tx_power_level_)
+    return false;
+
+  if (connectable_ != rhs.connectable_)
+    return false;
+
+  return true;
+}
+
+}  // namespace bluetooth
diff --git a/bt/service/common/bluetooth/advertise_settings.h b/bt/service/common/bluetooth/advertise_settings.h
new file mode 100644
index 0000000..6e787c1
--- /dev/null
+++ b/bt/service/common/bluetooth/advertise_settings.h
@@ -0,0 +1,98 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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/macros.h>
+#include <base/time/time.h>
+
+namespace bluetooth {
+
+// AdvertiseSettings provides a way to adjust advertising preferences for each
+// Bluetooth LE advertisement instance. This is the native equivalent of the
+// Android framework class defined in
+// frameworks/base/core/java/android/bluetooth/le/AdvertiseSettings.java
+class AdvertiseSettings {
+ public:
+  // Advertising mode describes power consumption mode used for advertising.
+  enum Mode {
+    // Perform Bluetooth LE advertising in low power mode. This is the default
+    // and preferred advertising mode as it consumes the least power.
+    MODE_LOW_POWER = 0x00,
+
+    // Perform Bluetooth LE advertising in balanced power mode. This is balanced
+    // between advertising frequency and power consumption.
+    MODE_BALANCED = 0x01,
+
+    // Perform Bluetooth LE advertising in low latency, high power mode. This
+    // has the highest power consumption and should not be used for continuous
+    // background advertising.
+    MODE_LOW_LATENCY = 0x02,
+  };
+
+  // Levels that can be set for advertising transmission power.
+  enum TxPowerLevel {
+    // Advertise using the lowest transmission (TX) power level. Low
+    // transmission power can be used to restrict the visibility range of
+    // advertising packets.
+    TX_POWER_LEVEL_ULTRA_LOW = 0x00,
+
+    // Advertise using low TX power level.
+    TX_POWER_LEVEL_LOW = 0x01,
+
+    // Advertise using medium TX power level.
+    TX_POWER_LEVEL_MEDIUM = 0x02,
+
+    // Advertise using high TX power level. This corresponds to largest
+    // visibility range of the advertising packet.
+    TX_POWER_LEVEL_HIGH = 0x03,
+  };
+
+  AdvertiseSettings(Mode mode,
+                    base::TimeDelta timeout,
+                    TxPowerLevel tx_power_level,
+                    bool connectable);
+
+  // The default constructor sets all fields to defaults:
+  //   mode: MODE_LOW_POWER
+  //   TX power level: TX_POWER_LEVEL_MEDIUM
+  //   connectable: true
+  AdvertiseSettings();
+  ~AdvertiseSettings() = default;
+
+  // Returns the advertise mode.
+  Mode mode() const { return mode_; }
+
+  // Returns the advertising time limit in milliseconds.
+  const base::TimeDelta& timeout() const { return timeout_; }
+
+  // Returns the TX power level for advertising.
+  TxPowerLevel tx_power_level() const { return tx_power_level_; }
+
+  // Returns whether the advertisement will indicate connectable.
+  bool connectable() const { return connectable_; }
+
+  // Comparison operator.
+  bool operator==(const AdvertiseSettings& rhs) const;
+
+ protected:
+  Mode mode_;
+  base::TimeDelta timeout_;
+  TxPowerLevel tx_power_level_;
+  bool connectable_;
+};
+
+}  // namespace bluetooth
diff --git a/bt/service/common/bluetooth/characteristic.cc b/bt/service/common/bluetooth/characteristic.cc
new file mode 100644
index 0000000..4968d33
--- /dev/null
+++ b/bt/service/common/bluetooth/characteristic.cc
@@ -0,0 +1,53 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 <bluetooth/characteristic.h>
+
+namespace bluetooth {
+Characteristic::Characteristic(const Characteristic& other) {
+  handle_ = other.handle_;
+  uuid_ = other.uuid_;
+  properties_ = other.properties_;
+  permissions_ = other.permissions_;
+  descriptors_ = other.descriptors_;
+}
+
+Characteristic& Characteristic::operator=(const Characteristic& other) {
+  if (*this == other) return *this;
+
+  handle_ = other.handle_;
+  uuid_ = other.uuid_;
+  properties_ = other.properties_;
+  permissions_ = other.permissions_;
+  descriptors_ = other.descriptors_;
+
+  return *this;
+}
+
+bool Characteristic::Equals(const Characteristic& other) const {
+  return handle_ == other.handle_ && uuid_ == other.uuid_ &&
+         properties_ == other.properties_ && permissions_ == other.permissions_ &&
+         descriptors_ == other.descriptors_;
+}
+
+bool Characteristic::operator==(const Characteristic& rhs) const {
+  return Equals(rhs);
+}
+
+bool Characteristic::operator!=(const Characteristic& rhs) const {
+  return !Equals(rhs);
+}
+}
diff --git a/bt/service/common/bluetooth/characteristic.h b/bt/service/common/bluetooth/characteristic.h
new file mode 100644
index 0000000..b0a4aa0
--- /dev/null
+++ b/bt/service/common/bluetooth/characteristic.h
@@ -0,0 +1,57 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <bluetooth/descriptor.h>
+#include <bluetooth/uuid.h>
+
+#include <vector>
+
+namespace bluetooth {
+class Characteristic {
+ public:
+  Characteristic() = default;
+  Characteristic(const Characteristic& other);
+  Characteristic(uint16_t handle, const UUID& uuid,
+                 uint8_t properties, uint16_t permissions,
+                 const std::vector<Descriptor>& descriptors)
+      : handle_(handle), uuid_(uuid),
+        properties_(properties), permissions_(permissions),
+        descriptors_(descriptors) {};
+  Characteristic& operator=(const Characteristic& other);
+  ~Characteristic() = default;
+
+  // Comparison function and operator.
+  bool Equals(const Characteristic& other) const;
+  bool operator==(const Characteristic& rhs) const;
+  bool operator!=(const Characteristic& rhs) const;
+
+  uint16_t handle() const { return handle_; }
+  const UUID& uuid() const { return uuid_; }
+  uint8_t properties() const { return properties_; }
+  uint16_t permissions() const { return permissions_; }
+  const std::vector<Descriptor>& descriptors() const { return descriptors_; }
+  std::vector<Descriptor>& descriptors() { return descriptors_; }
+
+ protected:
+  uint16_t handle_;
+  UUID uuid_;
+  uint8_t properties_;
+  uint16_t permissions_;
+  std::vector<Descriptor> descriptors_;
+};
+}
diff --git a/bt/service/common/bluetooth/descriptor.cc b/bt/service/common/bluetooth/descriptor.cc
new file mode 100644
index 0000000..7e37596
--- /dev/null
+++ b/bt/service/common/bluetooth/descriptor.cc
@@ -0,0 +1,46 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 <bluetooth/descriptor.h>
+
+namespace bluetooth {
+Descriptor::Descriptor(const Descriptor& other) {
+  handle_ = other.handle_;
+  uuid_ = other.uuid_;
+  permissions_ = other.permissions_;
+}
+
+Descriptor& Descriptor::operator=(const Descriptor& other) {
+  if (*this == other) return *this;
+
+  handle_ = other.handle_;
+  uuid_ = other.uuid_;
+  permissions_ = other.permissions_;
+
+  return *this;
+}
+
+bool Descriptor::Equals(const Descriptor& other) const {
+  return handle_ == other.handle_ && uuid_ == other.uuid_ &&
+         permissions_ == other.permissions_;
+}
+
+bool Descriptor::operator==(const Descriptor& rhs) const { return Equals(rhs); }
+
+bool Descriptor::operator!=(const Descriptor& rhs) const {
+  return !Equals(rhs);
+}
+}
diff --git a/bt/service/common/bluetooth/descriptor.h b/bt/service/common/bluetooth/descriptor.h
new file mode 100644
index 0000000..a1cd8b9
--- /dev/null
+++ b/bt/service/common/bluetooth/descriptor.h
@@ -0,0 +1,45 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <bluetooth/uuid.h>
+
+namespace bluetooth {
+class Descriptor {
+ public:
+  Descriptor() = default;
+  Descriptor(const Descriptor& other);
+  Descriptor& operator=(const Descriptor& other);
+  Descriptor(uint16_t handle, const UUID& uuid, uint16_t permissions)
+      : handle_(handle), uuid_(uuid), permissions_(permissions) {};
+  ~Descriptor() = default;
+
+  // Comparison function and operator.
+  bool Equals(const Descriptor& other) const;
+  bool operator==(const Descriptor& rhs) const;
+  bool operator!=(const Descriptor& rhs) const;
+
+  uint16_t handle() const { return handle_; }
+  uint16_t permissions() const { return permissions_; }
+  const UUID& uuid() const { return uuid_; }
+
+ protected:
+  uint16_t handle_;
+  UUID uuid_;
+  uint16_t permissions_;
+};
+}
diff --git a/bt/service/common/bluetooth/low_energy_constants.h b/bt/service/common/bluetooth/low_energy_constants.h
new file mode 100644
index 0000000..1f8d3eb
--- /dev/null
+++ b/bt/service/common/bluetooth/low_energy_constants.h
@@ -0,0 +1,128 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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>
+
+namespace bluetooth {
+
+// Defined here are various status codes that can be returned from the stack for
+// BLE operations.
+enum BLEStatus {
+  BLE_STATUS_SUCCESS = 0,
+  BLE_STATUS_ADV_ERROR_DATA_TOO_LARGE = 1,
+  BLE_STATUS_ADV_ERROR_TOO_MANY_ADVERTISERS = 2,
+  BLE_STATUS_ADV_ERROR_ALREADY_STARTED = 3,
+  BLE_STATUS_ADV_ERROR_FEATURE_UNSUPPORTED = 5,
+  BLE_STATUS_FAILURE = 0x101,
+};
+
+enum GATTError {
+  GATT_ERROR_NONE = 0,
+  GATT_ERROR_INVALID_HANDLE = 0x01,
+  GATT_ERROR_READ_NOT_PERMITTED = 0x02,
+  GATT_ERROR_WRITE_NOT_PERMITTED = 0x03,
+  GATT_ERROR_INVALID_PDU = 0x04,
+  GATT_ERROR_INSUFFICIENT_AUTHEN = 0x05,
+  GATT_ERROR_REQUEST_NOT_SUPPORTED = 0x06,
+  GATT_ERROR_INVALID_OFFSET = 0x07,
+  GATT_ERROR_INSUFFICIENT_AUTHOR = 0x08,
+  GATT_ERROR_PREP_QUEUE_FULL = 0x09,
+  GATT_ERROR_ATTRIBUTE_NOT_FOUND = 0x0a,
+  GATT_ERROR_ATTRIBUTE_NOT_LONG = 0x0b,
+  GATT_ERROR_INSUFFICIENT_KEY_SIZE = 0x0c,
+  GATT_ERROR_INVALID_ATTRIBUTE_LENGTH = 0x0d,
+  GATT_ERROR_UNLIKELY = 0x0e,
+  GATT_ERROR_INSUFFICIENT_ENCR = 0x0f,
+  GATT_ERROR_UNSUPPORTED_GRP_TYPE = 0x10,
+  GATT_ERROR_INSUFFICIENT_RESOURCES = 0x11,
+  GATT_ERROR_CCCD_IMPROPERLY_CONFIGURED = 0xFD,
+  GATT_ERROR_PROCEDURE_IN_PROGRESS = 0xFE,
+  GATT_ERROR_OUT_OF_RANGE = 0xFF
+};
+
+enum Transport {
+  TRANSPORT_AUTO = 0,
+  TRANSPORT_BREDR = 1,
+  TRANSPORT_LE = 2
+};
+
+// Android attribute permission values
+const uint16_t kAttributePermissionNone = 0x0;
+const uint16_t kAttributePermissionRead = 0x1;
+const uint16_t kAttributePermissionReadEncrypted = 0x2;
+const uint16_t kAttributePermissionReadEncryptedMITM = 0x4;
+const uint16_t kAttributePermissionWrite = 0x10;
+const uint16_t kAttributePermissionWriteEncrypted = 0x20;
+const uint16_t kAttributePermissionWriteEncryptedMITM = 0x40;
+const uint16_t kAttributePermissionWriteSigned = 0x80;
+const uint16_t kAttributePermissionWriteSignedMITM = 0x100;
+
+// GATT characteristic properties bit-field values (not including the
+// characteristic extended properties).
+const uint8_t kCharacteristicPropertyNone = 0x0;
+const uint8_t kCharacteristicPropertyBroadcast = 0x1;
+const uint8_t kCharacteristicPropertyRead = 0x2;
+const uint8_t kCharacteristicPropertyWriteNoResponse = 0x4;
+const uint8_t kCharacteristicPropertyWrite = 0x8;
+const uint8_t kCharacteristicPropertyNotify = 0x10;
+const uint8_t kCharacteristicPropertyIndicate = 0x20;
+const uint8_t kCharacteristicPropertySignedWrite = 0x40;
+const uint8_t kCharacteristicPropertyExtendedProps = 0x80;
+
+// Advertising interval for different modes.
+const int kAdvertisingIntervalHighMs = 1000;
+const int kAdvertisingIntervalMediumMs = 250;
+const int kAdvertisingIntervalLowMs = 100;
+
+// Add some randomness to the advertising min/max interval so the controller can
+// do some optimization.
+// TODO(armansito): I took this directly from packages/apps/Bluetooth but based
+// on code review comments this constant and the accompanying logic doesn't make
+// sense. Let's remove this constant and figure out how to properly calculate
+// the Max. Adv. Interval. (See http://b/24344075).
+const int kAdvertisingIntervalDeltaUnit = 10;
+
+// Advertising types (ADV_IND, ADV_SCAN_IND, etc.) that are exposed to
+// applications.
+const int kAdvertisingEventTypeConnectable = 0;
+const int kAdvertisingEventTypeScannable = 2;
+const int kAdvertisingEventTypeNonConnectable = 3;
+
+// Advertising channels. These should be kept the same as those defined in the
+// stack.
+const int kAdvertisingChannel37 = (1 << 0);
+const int kAdvertisingChannel38 = (1 << 1);
+const int kAdvertisingChannel39 = (1 << 2);
+const int kAdvertisingChannelAll =
+    (kAdvertisingChannel37 | kAdvertisingChannel38 | kAdvertisingChannel39);
+
+// Various Extended Inquiry Response fields types that are used for advertising
+// data fields as defined in the Core Specification Supplement.
+const uint8_t kEIRTypeFlags = 0x01;
+const uint8_t kEIRTypeIncomplete16BitUUIDs = 0x02;
+const uint8_t kEIRTypeComplete16BitUUIDs = 0x03;
+const uint8_t kEIRTypeIncomplete32BitUUIDs = 0x04;
+const uint8_t kEIRTypeComplete32BitUUIDs = 0x05;
+const uint8_t kEIRTypeIncomplete128BitUUIDs = 0x06;
+const uint8_t kEIRTypeComplete128BitUUIDs = 0x07;
+const uint8_t kEIRTypeShortenedLocalName = 0x08;
+const uint8_t kEIRTypeCompleteLocalName = 0x09;
+const uint8_t kEIRTypeTxPower = 0x0A;
+const uint8_t kEIRTypeManufacturerSpecificData = 0xFF;
+
+}  // namespace bluetooth
diff --git a/bt/service/common/bluetooth/scan_filter.cc b/bt/service/common/bluetooth/scan_filter.cc
new file mode 100644
index 0000000..beeeedc
--- /dev/null
+++ b/bt/service/common/bluetooth/scan_filter.cc
@@ -0,0 +1,98 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/bluetooth/scan_filter.h"
+
+#include "service/common/bluetooth/util/address_helper.h"
+
+namespace bluetooth {
+
+ScanFilter::ScanFilter(const ScanFilter& other) {
+  device_name_ = other.device_name_;
+  device_address_ = other.device_address_;
+
+  if (other.service_uuid_)
+    service_uuid_.reset(new UUID(*other.service_uuid_));
+
+  if (other.service_uuid_mask_)
+    service_uuid_mask_.reset(new UUID(*other.service_uuid_mask_));
+}
+
+ScanFilter& ScanFilter::operator=(const ScanFilter& other) {
+  device_name_ = other.device_name_;
+  device_address_ = other.device_address_;
+
+  if (other.service_uuid_)
+    service_uuid_.reset(new UUID(*other.service_uuid_));
+  else
+    service_uuid_ = nullptr;
+
+  if (other.service_uuid_mask_)
+    service_uuid_mask_.reset(new UUID(*other.service_uuid_mask_));
+  else
+    service_uuid_mask_ = nullptr;
+
+  return *this;
+}
+
+bool ScanFilter::SetDeviceAddress(const std::string& device_address) {
+  if (!util::IsAddressValid(device_address))
+    return false;
+
+  device_address_ = device_address;
+  return true;
+}
+
+void ScanFilter::SetServiceUuid(const UUID& service_uuid) {
+  service_uuid_.reset(new UUID(service_uuid));
+  service_uuid_mask_.reset();
+}
+
+void ScanFilter::SetServiceUuidWithMask(const UUID& service_uuid,
+                                        const UUID& mask) {
+  service_uuid_.reset(new UUID(service_uuid));
+  service_uuid_mask_.reset(new UUID(mask));
+}
+
+bool ScanFilter::operator==(const ScanFilter& rhs) const {
+  if (device_name_ != rhs.device_name_)
+    return false;
+
+  if (device_address_ != rhs.device_address_)
+    return false;
+
+  // Both must be either NULL or non-NULL. If only one of them is NULL, then
+  // return false.
+  if (!!service_uuid_ != !!rhs.service_uuid_)
+    return false;
+
+  if (service_uuid_ && rhs.service_uuid_ &&
+      *service_uuid_ != *rhs.service_uuid_)
+    return false;
+
+  // Both must be either NULL or non-NULL. If only one of them is NULL, then
+  // return false.
+  if (!!service_uuid_mask_ != !!rhs.service_uuid_mask_)
+    return false;
+
+  if (service_uuid_mask_ && rhs.service_uuid_mask_ &&
+      *service_uuid_mask_ != *rhs.service_uuid_mask_)
+    return false;
+
+  return true;
+}
+
+}  // namespace bluetooth
diff --git a/bt/service/common/bluetooth/scan_filter.h b/bt/service/common/bluetooth/scan_filter.h
new file mode 100644
index 0000000..74cfcb8
--- /dev/null
+++ b/bt/service/common/bluetooth/scan_filter.h
@@ -0,0 +1,77 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <bluetooth/uuid.h>
+
+namespace bluetooth {
+
+// Used for filtering scan results by allowing clients to restrict scan results
+// to only those that are of interest to them.
+class ScanFilter {
+ public:
+  ScanFilter() = default;
+  ~ScanFilter() = default;
+
+  // Copy constructor and assignment operator.
+  ScanFilter(const ScanFilter& other);
+  ScanFilter& operator=(const ScanFilter& other);
+
+  // The device name used while filtering scan results.
+  const std::string& device_name() const { return device_name_; }
+  void set_device_name(const std::string& name) { device_name_ = name; }
+
+  // The device address used while filtering scan results. Address should be in
+  // the XX:XX:XX:XX:XX:XX where X is a hexadecimal digit.
+  const std::string& device_address() const { return device_address_; }
+
+  // Sets the device address used for filtering. Returns false if
+  // |device_address| is in an illegal format.
+  bool SetDeviceAddress(const std::string& device_address);
+
+  // The service UUID and its mask used while filtering scan results. See
+  // SetServiceUuidWithMask for what this mask does. The raw pointer returned
+  // from these getters belongs to the ScanFilter object. nullptr will be
+  // returned if these fields have not been set on this filter.
+  UUID* service_uuid() const { return service_uuid_.get(); }
+  UUID* service_uuid_mask() const { return service_uuid_mask_.get(); }
+
+  // Sets the service UUID for this filter.
+  void SetServiceUuid(const UUID& service_uuid);
+
+  // Sets the service UUID for this filter with a 128-bit mask. The mask allows
+  // the caller to partially filter scanned service UUIDs. For any of the
+  // 128-bits of a UUID, set the corresponding bit in the mask to 1 to match the
+  // advertised value, and 0 to ignore that bit.
+  void SetServiceUuidWithMask(const UUID& service_uuid, const UUID& mask);
+
+  // Comparison operator.
+  bool operator==(const ScanFilter& rhs) const;
+
+ protected:
+  std::string device_name_;
+  std::string device_address_;
+
+  std::unique_ptr<UUID> service_uuid_;
+  std::unique_ptr<UUID> service_uuid_mask_;
+
+  // TODO(armansito): Add service and manufacturer data filter fields.
+};
+
+}  // namespace bluetooth
diff --git a/bt/service/common/bluetooth/scan_result.cc b/bt/service/common/bluetooth/scan_result.cc
new file mode 100644
index 0000000..9e28e41
--- /dev/null
+++ b/bt/service/common/bluetooth/scan_result.cc
@@ -0,0 +1,49 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/bluetooth/scan_result.h"
+
+#include <base/logging.h>
+
+#include "service/common/bluetooth/util/address_helper.h"
+
+
+namespace bluetooth {
+
+ScanResult::ScanResult(const std::string& device_address,
+                       const std::vector<uint8_t>& scan_record,
+                       int rssi)
+    : device_address_(device_address),
+      scan_record_(scan_record),
+      rssi_(rssi) {
+  CHECK(util::IsAddressValid(device_address)) << "Invalid BD_ADDR given: "
+                                              << device_address;
+}
+
+bool ScanResult::operator==(const ScanResult& rhs) const {
+  if (device_address_ != rhs.device_address_)
+    return false;
+
+  if (scan_record_ != rhs.scan_record_)
+    return false;
+
+  if (rssi_ != rhs.rssi_)
+    return false;
+
+  return true;
+}
+
+}  // namespace bluetooth
diff --git a/bt/service/common/bluetooth/scan_result.h b/bt/service/common/bluetooth/scan_result.h
new file mode 100644
index 0000000..9be25b5
--- /dev/null
+++ b/bt/service/common/bluetooth/scan_result.h
@@ -0,0 +1,55 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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>
+#include <vector>
+
+namespace bluetooth {
+
+// ScanResult represents a single Bluetooth LE device scan result. It
+// encapsulates information about discovered LE devices.
+class ScanResult {
+ public:
+  ScanResult(const std::string& device_address,
+             const std::vector<uint8_t>& scan_record,
+             int rssi);
+  ScanResult() = default;
+  ~ScanResult() = default;
+
+  // Returns the remote BD_ADDR associated with this scan result.
+  const std::string& device_address() const { return device_address_; }
+
+  // Returns the scan record (advertising +scan-response data) associated with
+  // this scan result.
+  const std::vector<uint8_t>& scan_record() const { return scan_record_; }
+
+  // Returns the RSSI associated with this scan result.
+  int rssi() const { return rssi_; }
+
+  // Comparison operator.
+  bool operator==(const ScanResult& rhs) const;
+
+ protected:
+  std::string device_address_;
+  std::vector<uint8_t> scan_record_;
+  int rssi_;
+};
+
+}  // namespace bluetooth
diff --git a/bt/service/common/bluetooth/scan_settings.cc b/bt/service/common/bluetooth/scan_settings.cc
new file mode 100644
index 0000000..2c807c0
--- /dev/null
+++ b/bt/service/common/bluetooth/scan_settings.cc
@@ -0,0 +1,65 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/bluetooth/scan_settings.h"
+
+namespace bluetooth {
+
+ScanSettings::ScanSettings()
+    : mode_(MODE_LOW_POWER),
+      callback_type_(CALLBACK_TYPE_ALL_MATCHES),
+      result_type_(RESULT_TYPE_FULL),
+      match_count_per_filter_(MATCH_COUNT_MAX_ADVERTISEMENTS) {
+}
+
+ScanSettings::ScanSettings(
+    Mode mode,
+    CallbackTypeBitField callback_type,
+    ResultType result_type,
+    base::TimeDelta report_delay_ms,
+    MatchMode match_mode,
+    MatchCount match_count_per_filter)
+    : mode_(mode),
+      callback_type_(callback_type),
+      result_type_(result_type),
+      report_delay_ms_(report_delay_ms),
+      match_mode_(match_mode),
+      match_count_per_filter_(match_count_per_filter) {
+}
+
+bool ScanSettings::operator==(const ScanSettings& rhs) const {
+  if (mode_ != rhs.mode_)
+    return false;
+
+  if (callback_type_ != rhs.callback_type_)
+    return false;
+
+  if (result_type_ != rhs.result_type_)
+    return false;
+
+  if (report_delay_ms_ != rhs.report_delay_ms_)
+    return false;
+
+  if (match_mode_ != rhs.match_mode_)
+    return false;
+
+  if (match_count_per_filter_ != rhs.match_count_per_filter_)
+    return false;
+
+  return true;
+}
+
+}  // namespace bluetooth
diff --git a/bt/service/common/bluetooth/scan_settings.h b/bt/service/common/bluetooth/scan_settings.h
new file mode 100644
index 0000000..7771ac9
--- /dev/null
+++ b/bt/service/common/bluetooth/scan_settings.h
@@ -0,0 +1,164 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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/time/time.h>
+
+namespace bluetooth {
+
+// ScanSettings encapsulates Bluetooth LE device scan parameters. This is the
+// native equivalent of the Android framework class defined in
+// frameworks/base/core/java/android/bluetooth/le/ScanSettings.java.
+class ScanSettings {
+ public:
+  // A scan mode describes the power consumption involved in LE scans.
+  enum Mode {
+    // A special Bluetooth LE scan mode. Applications using this scan mode will
+    // passively listen for other scan results without starting BLE scans
+    // themselves.
+    MODE_OPPORTUNISTIC = -1,
+
+    // Perform Bluetooth LE scan in low power mode. This is the default scan
+    // mode as it consumes the least power.
+    MODE_LOW_POWER = 0,
+
+    // Perform Bluetooth LE scan in balanced power mode. Scan results are
+    // returned at a rate that provides a good trade-off between scan frequency
+    // and power consumption.
+    MODE_BALANCED = 1,
+
+    // Scan using the highest duty cycle. It's recommended to only use this mode
+    // when the application is running in the foreground.
+    MODE_LOW_LATENCY = 2,
+  };
+
+  // A callback type describes how scan results will be reported to applications
+  // in asynchronous callbacks.
+  enum CallbackType {
+    // Trigger a callback for every Bluetooth advertisement found that matches
+    // the filter criteria. If no filter is active, all advertisement packets
+    // are reported.
+    CALLBACK_TYPE_ALL_MATCHES = 1,
+
+    // A result callback is only triggered for the first advertisement packet
+    // received that matches the filter criteria. This requires that the
+    // hardware support the offloaded filtering feature.
+    CALLBACK_TYPE_FIRST_MATCH = 2,
+
+    // Receive a callback when advertisements are no longer received from a
+    // device that has been previously reported by a first match callback. This
+    // requires that the hardware support the offloaded filtering feature.
+    CALLBACK_TYPE_MATCH_LOST = 4,
+  };
+  using CallbackTypeBitField = int;
+
+  // Determines how many advertisements to match per filter.
+  enum MatchCount {
+    // Match one advertisement per filter.
+    MATCH_COUNT_ONE_ADVERTISEMENT = 1,
+
+    // Match few advertisements per filter depending on the current capability
+    // and availability of hardware resources.
+    MATCH_COUNT_FEW_ADVERTISEMENTS = 2,
+
+    // Match as many advertisements per filter as the underlying hardware can
+    // allow, depending on the current capability and availability of hardware
+    // resources.
+    MATCH_COUNT_MAX_ADVERTISEMENTS = 3,
+  };
+
+  // Hardware filter match mode.
+  enum MatchMode {
+    // In aggressive mode the hardware will determine a match sooner even with
+    // feeble signal strength and a low number of sightings in a duration.
+    MATCH_MODE_AGGRESSIVE = 1,
+
+    // In sticky mode a higher threshold of signal strength and sightings is
+    // required before a scan result is reported by the hardware.
+    MATCH_MODE_STICKY = 2,
+  };
+
+  // Scan result type describes the contents of each scan result.
+  enum ResultType {
+    // Request full scan results which contain the device name, RSSI,
+    // advertising data, scan response data, and the scan timestamp.
+    RESULT_TYPE_FULL = 0,
+
+    // Request abbreviated scan results which contain the device name, RSSI, and
+    // scan timestamp.
+    // Note: It is possible for an application to get more scan results than it
+    // asked for, if there are multiple apps using this type.
+    RESULT_TYPE_ABBREVIATED = 1,
+  };
+
+  // The default constructor sets all fields to defaults:
+  //   mode: MODE_LOW_POWER
+  //   callback_type: CALLBACK_TYPE_ALL_MATCHES
+  //   result_type: RESULT_TYPE_FULL
+  //   report_delay_ms: 0
+  //   match_mode: MATCH_MODE_AGGRESSIVE
+  //   match_count_per_filter: MATCH_COUNT_MAX_ADVERTISEMENTS
+  ScanSettings();
+  ScanSettings(Mode mode,
+               CallbackTypeBitField callback_type,
+               ResultType result_type,
+               base::TimeDelta report_delay_ms,
+               MatchMode match_mode,
+               MatchCount match_count_per_filter);
+  ~ScanSettings() = default;
+
+  // Returns the scan mode.
+  Mode mode() const { return mode_; }
+  void set_mode(Mode mode) { mode_ = mode; }
+
+  // Returns the callback type.
+  CallbackTypeBitField callback_type() const { return callback_type_; }
+  void set_callback_type(CallbackTypeBitField type) { callback_type_ = type; }
+
+  // Returns the scan result type.
+  ResultType result_type() const { return result_type_; }
+  void set_result_type(ResultType type) { result_type_ = type; }
+
+  // Returns the report delay value in milliseconds.
+  const base::TimeDelta& report_delay() const { return report_delay_ms_; }
+  void set_report_delay(const base::TimeDelta& delay) {
+    report_delay_ms_ = delay;
+  }
+
+  // Returns the hardware filter match mode.
+  MatchMode match_mode() const { return match_mode_; }
+  void set_match_mode(MatchMode mode) { match_mode_ = mode; }
+
+  // Returns the count of advertisements to match per filter.
+  MatchCount match_count_per_filter() const { return match_count_per_filter_; }
+  void set_match_count_per_filter(MatchCount count) {
+    match_count_per_filter_ = count;
+  }
+
+  // Comparison operator.
+  bool operator==(const ScanSettings& rhs) const;
+
+ protected:
+  Mode mode_;
+  CallbackTypeBitField callback_type_;
+  ResultType result_type_;
+  base::TimeDelta report_delay_ms_;
+  MatchMode match_mode_;
+  MatchCount match_count_per_filter_;
+};
+
+}  // namespace bluetooth
diff --git a/bt/service/common/bluetooth/service.cc b/bt/service/common/bluetooth/service.cc
new file mode 100644
index 0000000..b5f9a75
--- /dev/null
+++ b/bt/service/common/bluetooth/service.cc
@@ -0,0 +1,50 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 <bluetooth/service.h>
+
+namespace bluetooth {
+Service::Service(const Service& other) {
+  handle_ = other.handle_;
+  primary_ = other.primary_;
+  uuid_ = other.uuid_;
+  characteristics_ = other.characteristics_;
+  included_services_ = other.included_services_;
+}
+
+Service& Service::operator=(const Service& other) {
+  if (*this == other) return *this;
+
+  handle_ = other.handle_;
+  primary_ = other.primary_;
+  uuid_ = other.uuid_;
+  characteristics_ = other.characteristics_;
+  included_services_ = other.included_services_;
+  return *this;
+}
+
+bool Service::Equals(const Service& other) const {
+  return handle_ == other.handle_ &&
+         primary_ == other.primary_ &&
+         uuid_ == other.uuid_ &&
+         characteristics_ == other.characteristics_ &&
+         included_services_ == other.included_services_;
+}
+
+bool Service::operator==(const Service& rhs) const { return Equals(rhs); }
+
+bool Service::operator!=(const Service& rhs) const { return !Equals(rhs); }
+}
diff --git a/bt/service/common/bluetooth/service.h b/bt/service/common/bluetooth/service.h
new file mode 100644
index 0000000..19fbadc
--- /dev/null
+++ b/bt/service/common/bluetooth/service.h
@@ -0,0 +1,63 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <bluetooth/characteristic.h>
+#include <bluetooth/uuid.h>
+
+#include <vector>
+
+namespace bluetooth {
+class Service {
+ public:
+  Service() = default;
+  Service(const Service& other);
+  Service(uint16_t handle, bool primary, const UUID& uuid,
+          const std::vector<Characteristic>& characteristics,
+          const std::vector<Service>& included_services)
+      : handle_(handle), primary_(primary), uuid_(uuid),
+        characteristics_(characteristics),
+        included_services_(included_services) {};
+  Service& operator=(const Service& other);
+  ~Service() = default;
+
+  // Comparison function and operator.
+  bool Equals(const Service& other) const;
+  bool operator==(const Service& rhs) const;
+  bool operator!=(const Service& rhs) const;
+
+  uint16_t handle() const { return handle_; }
+  bool primary() const { return primary_; }
+  const UUID& uuid() const { return uuid_; }
+  const std::vector<Characteristic>& characteristics() const {
+    return characteristics_;
+  }
+  std::vector<Characteristic>& characteristics() {
+    return characteristics_;
+  }
+  const std::vector<Service>& included_services() const {
+    return included_services_;
+  }
+
+ protected:
+  uint16_t handle_;
+  bool primary_;
+  UUID uuid_;
+  std::vector<Characteristic> characteristics_;
+  std::vector<Service> included_services_;
+};
+}
diff --git a/bt/service/common/bluetooth/util/address_helper.cc b/bt/service/common/bluetooth/util/address_helper.cc
new file mode 100644
index 0000000..51f8962
--- /dev/null
+++ b/bt/service/common/bluetooth/util/address_helper.cc
@@ -0,0 +1,58 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/bluetooth/util/address_helper.h"
+
+#include <cstdlib>
+
+#include <base/logging.h>
+#include <base/strings/string_split.h>
+
+namespace util {
+
+bool IsAddressValid(const std::string& address) {
+  bt_bdaddr_t addr;
+  return BdAddrFromString(address, &addr);
+}
+
+bool BdAddrFromString(const std::string& address, bt_bdaddr_t* out_addr) {
+  CHECK(out_addr);
+
+  if (address.length() != 17)
+    return false;
+
+  std::vector<std::string> byte_tokens = base::SplitString(
+      address, ":", 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;
+    out_addr->address[i] = strtol(token.c_str(), &temp, 16);
+    if (*temp != '\0')
+      return false;
+  }
+
+  return true;
+}
+
+}  // namespace util
diff --git a/bt/service/common/bluetooth/util/address_helper.h b/bt/service/common/bluetooth/util/address_helper.h
new file mode 100644
index 0000000..d71d907
--- /dev/null
+++ b/bt/service/common/bluetooth/util/address_helper.h
@@ -0,0 +1,36 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <hardware/bluetooth.h>
+#include <string>
+
+namespace util {
+
+// Checks if the given string representing a Bluetooth device address (BD_ADDR)
+// is correctly formatted. The correct formatting is of the form
+//
+//   XX:XX:XX:XX:XX:XX
+//
+// where X is an alpha-numeric character.
+bool IsAddressValid(const std::string& address);
+
+// Populates a bt_bdaddr_t from a given string. Returns false if the data is
+// invalid.
+bool BdAddrFromString(const std::string& address, bt_bdaddr_t* out_addr);
+
+}  // namespace util
diff --git a/bt/service/common/bluetooth/util/atomic_string.cc b/bt/service/common/bluetooth/util/atomic_string.cc
new file mode 100644
index 0000000..0084700
--- /dev/null
+++ b/bt/service/common/bluetooth/util/atomic_string.cc
@@ -0,0 +1,36 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/bluetooth/util/atomic_string.h"
+
+namespace util {
+
+AtomicString::AtomicString(const std::string& str)
+    : str_(str) {
+}
+
+std::string AtomicString::Get() const {
+  std::mutex* mutex = const_cast<std::mutex*>(&lock_);
+  std::lock_guard<std::mutex> lock(*mutex);
+  return str_;
+}
+
+void AtomicString::Set(const std::string& str) {
+  std::lock_guard<std::mutex> lock(lock_);
+  str_ = str;
+}
+
+}  // namespace util
diff --git a/bt/service/common/bluetooth/util/atomic_string.h b/bt/service/common/bluetooth/util/atomic_string.h
new file mode 100644
index 0000000..e1c2526
--- /dev/null
+++ b/bt/service/common/bluetooth/util/atomic_string.h
@@ -0,0 +1,40 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 <mutex>
+#include <string>
+
+#include <base/macros.h>
+
+namespace util {
+
+// A simple atomic container class for std::string.
+class AtomicString final {
+ public:
+  explicit AtomicString(const std::string& str);
+  ~AtomicString() = default;
+
+  std::string Get() const;
+  void Set(const std::string& str);
+
+ private:
+  std::mutex lock_;
+  std::string str_;
+
+  DISALLOW_COPY_AND_ASSIGN(AtomicString);
+};
+
+}  // namespace util
diff --git a/bt/service/common/bluetooth/uuid.cc b/bt/service/common/bluetooth/uuid.cc
new file mode 100644
index 0000000..575b055
--- /dev/null
+++ b/bt/service/common/bluetooth/uuid.cc
@@ -0,0 +1,177 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/bluetooth/uuid.h"
+
+#include <algorithm>
+#include <array>
+#include <stack>
+#include <string>
+
+#include <base/rand_util.h>
+#include <base/strings/stringprintf.h>
+#include <base/strings/string_split.h>
+#include <base/strings/string_util.h>
+
+namespace bluetooth {
+
+namespace {
+
+const UUID::UUID128Bit kSigBaseUUID = {
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+    0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb }
+};
+
+}  // namespace
+
+// static
+UUID UUID::GetRandom() {
+  UUID128Bit bytes;
+  base::RandBytes(bytes.data(), bytes.size());
+  return UUID(bytes);
+}
+
+// static
+UUID UUID::GetNil() {
+  UUID128Bit bytes;
+  bytes.fill(0);
+  return UUID(bytes);
+}
+
+// static
+UUID UUID::GetMax() {
+  UUID128Bit bytes;
+  bytes.fill(1);
+  return UUID(bytes);
+}
+
+void UUID::InitializeDefault() {
+  // Initialize to Bluetooth SIG base UUID.
+  id_ = kSigBaseUUID;
+  is_valid_ = true;
+}
+
+UUID::UUID() {
+  InitializeDefault();
+}
+
+UUID::UUID(std::string uuid) {
+  InitializeDefault();
+  is_valid_ = false;
+
+  if (uuid.empty())
+    return;
+
+  if (uuid.size() < 11 && uuid.find("0x") == 0)
+    uuid = uuid.substr(2);
+
+  if (uuid.size() != 4 && uuid.size() != 8 && uuid.size() != 36)
+    return;
+
+  if (uuid.size() == 36) {
+    if (uuid[8] != '-')
+      return;
+    if (uuid[13] != '-')
+      return;
+    if (uuid[18] != '-')
+      return;
+    if (uuid[23] != '-')
+      return;
+
+    std::vector<std::string> tokens = base::SplitString(
+        uuid, "-", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+    if (tokens.size() != 5)
+      return;
+
+    uuid = base::JoinString(tokens, "");
+  }
+
+  const int start_index = uuid.size() == 4 ? 2 : 0;
+  const size_t copy_size = std::min(id_.size(), uuid.size() / 2);
+  for (size_t i = 0; i < copy_size; ++i) {
+      std::string octet_text(uuid, i * 2, 2);
+      char* temp = nullptr;
+      id_[start_index + i] = strtol(octet_text.c_str(), &temp, 16);
+      if (*temp != '\0')
+        return;
+  }
+
+  is_valid_ = true;
+}
+
+UUID::UUID(const bt_uuid_t& uuid) {
+  std::reverse_copy(uuid.uu, uuid.uu + sizeof(uuid.uu), id_.begin());
+  is_valid_ = true;
+}
+
+UUID::UUID(const UUID16Bit& uuid) {
+  InitializeDefault();
+  std::copy(uuid.begin(), uuid.end(), id_.begin() + kNumBytes16);
+}
+
+UUID::UUID(const UUID32Bit& uuid) {
+  InitializeDefault();
+  std::copy(uuid.begin(), uuid.end(), id_.begin());
+}
+
+UUID::UUID(const UUID128Bit& uuid) : id_(uuid), is_valid_(true) {}
+
+UUID::UUID128Bit UUID::GetFullBigEndian() const {
+  return id_;
+}
+
+UUID::UUID128Bit UUID::GetFullLittleEndian() const {
+  UUID::UUID128Bit ret;
+  std::reverse_copy(id_.begin(), id_.end(), ret.begin());
+  return ret;
+}
+
+bt_uuid_t UUID::GetBlueDroid() const {
+  bt_uuid_t ret;
+  std::reverse_copy(id_.begin(), id_.end(), ret.uu);
+  return ret;
+}
+
+std::string UUID::ToString() const {
+  return base::StringPrintf(
+      "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+      id_[0], id_[1], id_[2], id_[3],
+      id_[4], id_[5], id_[6], id_[7],
+      id_[8], id_[9], id_[10], id_[11],
+      id_[12], id_[13], id_[14], id_[15]);
+}
+
+size_t UUID::GetShortestRepresentationSize() const {
+  if (memcmp(id_.data() + 4, kSigBaseUUID.data() + 4, id_.size() - 4) != 0)
+    return kNumBytes128;
+
+  if (id_[0] == 0 && id_[1] == 0)
+    return kNumBytes16;
+
+  return kNumBytes32;
+}
+
+bool UUID::operator<(const UUID& rhs) const {
+  return std::lexicographical_compare(id_.begin(), id_.end(), rhs.id_.begin(),
+                                      rhs.id_.end());
+}
+
+bool UUID::operator==(const UUID& rhs) const {
+  return std::equal(id_.begin(), id_.end(), rhs.id_.begin());
+}
+
+}  // namespace bluetooth
diff --git a/bt/service/common/bluetooth/uuid.h b/bt/service/common/bluetooth/uuid.h
new file mode 100644
index 0000000..d3028c8
--- /dev/null
+++ b/bt/service/common/bluetooth/uuid.h
@@ -0,0 +1,110 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <string>
+
+// TODO: Find places that break include what you use and remove this.
+#include <base/logging.h>
+#include <hardware/bluetooth.h>
+
+namespace bluetooth {
+
+class UUID {
+ public:
+  static constexpr size_t kNumBytes128 = 16;
+  static constexpr size_t kNumBytes32 = 4;
+  static constexpr size_t kNumBytes16 = 2;
+
+  typedef std::array<uint8_t, kNumBytes16> UUID16Bit;
+  typedef std::array<uint8_t, kNumBytes32> UUID32Bit;
+  typedef std::array<uint8_t, kNumBytes128> UUID128Bit;
+
+  // Creates and returns a random 128-bit UUID.
+  static UUID GetRandom();
+
+  // Creates and returns a UUID in which all 128 bits are equal to 0.
+  static UUID GetNil();
+
+  // Creates and returns a UUID in which all 128 bits are equal to 1.
+  static UUID GetMax();
+
+  // Construct a Bluetooth 'base' UUID.
+  UUID();
+
+  // BlueDroid constructor.
+  explicit UUID(const bt_uuid_t& uuid);
+
+  // String constructor. Only hex ASCII accepted.
+  explicit UUID(std::string uuid);
+
+  // std::array variants constructors.
+  explicit UUID(const UUID16Bit& uuid);
+  explicit UUID(const UUID32Bit& uuid);
+  explicit UUID(const UUID128Bit& uuid);
+
+  // Provide the full network-byte-ordered blob.
+  UUID128Bit GetFullBigEndian() const;
+
+  // Provide blob in Little endian (BlueDroid expects this).
+  UUID128Bit GetFullLittleEndian() const;
+
+  // Helper for bluedroid LE type.
+  bt_uuid_t GetBlueDroid() const;
+
+  // Returns a string representation for the UUID.
+  std::string ToString() const;
+
+  // Returns whether or not this UUID was initialized correctly.
+  bool is_valid() const { return is_valid_; }
+
+  // Returns the shortest possible representation of this UUID in bytes.
+  size_t GetShortestRepresentationSize() const;
+
+  bool operator<(const UUID& rhs) const;
+  bool operator==(const UUID& rhs) const;
+  inline bool operator!=(const UUID& rhs) const {
+    return !(*this == rhs);
+  }
+
+ protected:
+  void InitializeDefault();
+
+  // Network-byte-ordered ID.
+  UUID128Bit id_;
+
+  // True if this UUID was initialized with a correct representation.
+  bool is_valid_;
+};
+
+}  // namespace bluetooth
+
+// Custom std::hash specialization so that bluetooth::UUID can be used as a key
+// in std::unordered_map.
+namespace std {
+
+template<>
+struct hash<bluetooth::UUID> {
+  std::size_t operator()(const bluetooth::UUID& key) const {
+    const auto& uuid_bytes = key.GetFullBigEndian();
+    std::hash<std::string> hash_fn;
+    return hash_fn(std::string((char *)uuid_bytes.data(), uuid_bytes.size()));
+  }
+};
+
+}  // namespace std
diff --git a/bt/service/daemon.cc b/bt/service/daemon.cc
new file mode 100644
index 0000000..0439c36
--- /dev/null
+++ b/bt/service/daemon.cc
@@ -0,0 +1,182 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/daemon.h"
+
+#include <memory>
+
+#include <base/logging.h>
+
+#include "service/adapter.h"
+#include "service/hal/bluetooth_gatt_interface.h"
+#include "service/hal/bluetooth_interface.h"
+#include "service/ipc/ipc_manager.h"
+#include "service/settings.h"
+
+namespace bluetooth {
+
+namespace {
+
+// The global Daemon instance.
+Daemon* g_daemon = nullptr;
+
+class DaemonImpl : public Daemon {
+ public:
+  DaemonImpl() : initialized_(false) {
+  }
+
+  ~DaemonImpl() override {
+    if (!initialized_)
+      return;
+
+    CleanUpBluetoothStack();
+  }
+
+  void StartMainLoop() override {
+    message_loop_->Run();
+  }
+
+  Settings* GetSettings() const override {
+    return settings_.get();
+  }
+
+  base::MessageLoop* GetMessageLoop() const override {
+    return message_loop_.get();
+  }
+
+ private:
+  bool StartUpBluetoothInterfaces() {
+    if (!hal::BluetoothInterface::Initialize())
+      goto failed;
+
+    if (!hal::BluetoothGattInterface::Initialize())
+      goto failed;
+
+    return true;
+
+  failed:
+    ShutDownBluetoothInterfaces();
+    return false;
+  }
+
+  void ShutDownBluetoothInterfaces() {
+    if (hal::BluetoothGattInterface::IsInitialized())
+      hal::BluetoothGattInterface::CleanUp();
+    if (hal::BluetoothInterface::IsInitialized())
+      hal::BluetoothInterface::CleanUp();
+  }
+
+  void CleanUpBluetoothStack() {
+    // The Adapter object needs to be cleaned up before the HAL interfaces.
+    ipc_manager_.reset();
+    adapter_.reset();
+    ShutDownBluetoothInterfaces();
+  }
+
+  bool SetUpIPC() {
+    // If an IPC socket path was given, initialize IPC with it. Otherwise
+    // initialize Binder IPC.
+    if (settings_->UseSocketIPC()) {
+      if (!ipc_manager_->Start(ipc::IPCManager::TYPE_LINUX, nullptr)) {
+        LOG(ERROR) << "Failed to set up UNIX domain-socket IPCManager";
+        return false;
+      }
+    } else if (!ipc_manager_->Start(ipc::IPCManager::TYPE_BINDER, nullptr)) {
+      LOG(ERROR) << "Failed to set up Binder IPCManager";
+      return false;
+    }
+
+    return true;
+  }
+
+  bool Init() override {
+    CHECK(!initialized_);
+    message_loop_.reset(new base::MessageLoop());
+
+    settings_.reset(new Settings());
+    if (!settings_->Init()) {
+      LOG(ERROR) << "Failed to set up Settings";
+      return false;
+    }
+
+    if (!StartUpBluetoothInterfaces()) {
+      LOG(ERROR) << "Failed to set up HAL Bluetooth interfaces";
+      return false;
+    }
+
+    adapter_ = Adapter::Create();
+    ipc_manager_.reset(new ipc::IPCManager(adapter_.get()));
+
+    if (!SetUpIPC()) {
+      CleanUpBluetoothStack();
+      return false;
+    }
+
+    initialized_ = true;
+    LOG(INFO) << "Daemon initialized";
+
+    return true;
+  }
+
+  bool initialized_;
+  std::unique_ptr<base::MessageLoop> message_loop_;
+  std::unique_ptr<Settings> settings_;
+  std::unique_ptr<Adapter> adapter_;
+  std::unique_ptr<ipc::IPCManager> ipc_manager_;
+
+  DISALLOW_COPY_AND_ASSIGN(DaemonImpl);
+};
+
+}  // namespace
+
+// static
+bool Daemon::Initialize() {
+  CHECK(!g_daemon);
+
+  g_daemon = new DaemonImpl();
+  if (g_daemon->Init())
+    return true;
+
+  LOG(ERROR) << "Failed to initialize the Daemon object";
+
+  delete g_daemon;
+  g_daemon = nullptr;
+
+  return false;
+}
+
+// static
+void Daemon::ShutDown() {
+  CHECK(g_daemon);
+  delete g_daemon;
+  g_daemon = nullptr;
+}
+
+// static
+void Daemon::InitializeForTesting(Daemon* test_daemon) {
+  CHECK(test_daemon);
+  CHECK(!g_daemon);
+
+  g_daemon = test_daemon;
+}
+
+// static
+Daemon* Daemon::Get() {
+  CHECK(g_daemon);
+  return g_daemon;
+}
+
+}  // namespace bluetooth
diff --git a/bt/service/daemon.h b/bt/service/daemon.h
new file mode 100644
index 0000000..c792dfc
--- /dev/null
+++ b/bt/service/daemon.h
@@ -0,0 +1,74 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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/macros.h>
+#include <base/message_loop/message_loop.h>
+
+namespace ipc {
+class IPCManager;
+}  // namespace ipc
+
+namespace bluetooth {
+
+class CoreStack;
+class Settings;
+
+// The Daemon class is a singleton that represents the root of the ownership
+// hierarchy. The single instance sets up and owns the main event loop, the IPC
+// handlers, global Settings, and the core Bluetooth stack.
+class Daemon {
+ public:
+  // Initializes the daemon. This must be called to at the start of the
+  // application to set up the global daemon instance and everything it manages.
+  // Returns false in case of a failure.
+  static bool Initialize();
+
+  // Cleans up all the resources associated with the global Daemon object.
+  static void ShutDown();
+
+  // Assigns the global Daemon instance for testing. Should only be called from
+  // test code.
+  static void InitializeForTesting(Daemon* test_daemon);
+
+  // Returns the singleton Daemon instance. All classes can interact with the
+  // Daemon, obtain its resources etc using this getter.
+  static Daemon* Get();
+
+  // The global Settings object. All classes have direct access to this through
+  // the Daemon object.
+  virtual Settings* GetSettings() const  = 0;
+
+  // The main event loop. This should be used for any events and delayed tasks
+  // that should be executed on the daemon's main thread.
+  virtual base::MessageLoop* GetMessageLoop() const = 0;
+
+  // Starts the daemon's main loop.
+  virtual void StartMainLoop() = 0;
+
+ protected:
+  Daemon() = default;
+  virtual ~Daemon() = default;
+
+ private:
+  // Internal instance helper called by Initialize().
+  virtual bool Init() = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(Daemon);
+};
+
+}  // namespace bluetooth
diff --git a/bt/service/doc/IBluetooth.txt b/bt/service/doc/IBluetooth.txt
new file mode 100644
index 0000000..54695e6
--- /dev/null
+++ b/bt/service/doc/IBluetooth.txt
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Binder IPC API for talking with the Bluetooth service and perform high-level
+ * operations on the adapter.
+ */
+interface IBluetooth {
+  /**
+   * Returns true if the Bluetooth adapter is powered and ready to use. This
+   * is equivalent to "getState() == ADAPTER_STATE_ON".
+   */
+  boolean isEnabled();
+
+  /**
+   * Returns the current Bluetooth adapter state. The return value can be one of
+   * the following:
+   *
+   *  - ADAPTER_STATE_OFF = 10
+   *  - ADAPTER_STATE_TURNING_ON = 11
+   *  - ADAPTER_STATE_ON = 12
+   *  - ADAPTER_STATE_TURNING_OFF = 13
+   */
+  int getState();
+
+  /**
+   * Turns on the Bluetooth radio. This function initiates the procedure to
+   * bring the adapter state from ADAPTER_STATE_OFF to ADAPTER_STATE_ON. Returns
+   * false, if the state is not ADAPTER_STATE_OFF or if there is an error while
+   * initiating the operation. On success, the adapter state will be
+   * asynchronously updated to ADAPTER_STATE_TURNING_ON and eventually to
+   * ADAPTER_STATE_ON. Callers can monitor the status of this call by observing
+   * the IBluetoothCallback.onBluetoothStateChange callback.
+   */
+  boolean enable();
+
+  /**
+   * Turns off the Bluetooth radio. This function initiates the procedure to
+   * bring the adapter state from ADAPTER_STATE_ON to ADAPTER_STATE_OFF. Returns
+   * false, if the state is not ADAPTER_STATE_ON or if there is an error while
+   * initiating the operation. On success, the adapter state will be
+   * asynchronously updated to ADAPTER_STATE_TURNING_OFF and eventually to
+   * ADAPTER_STATE_OFF. Callers can monitor the status of this call by observing
+   * the IBluetoothCallback.onBluetoothStateChange callback.
+   */
+  boolean disable();
+
+  /**
+   * Returns the identity Bluetooth Device Address (BD_ADDR) assigned to the
+   * underlying Bluetooth controller. Returns a string of the form
+   * "XX:XX:XX:XX:XX:XX", where each "X" is a hexadecimal digit. Returns
+   * "00:00:00:00:00:00" if the address is not known, which is usually the case
+   * before the adapter is enabled for the first time.
+   */
+  String getAddress();
+
+  /**
+   * Sets the name assigned to the Bluetooth adapter. This is the name that will
+   * be seen by remote devices during discovery. Returns false if the operation
+   * fails.
+   */
+  boolean setName(in String name);
+
+  /**
+   * Returns the current name assigned to the Bluetooth adapter. This is the
+   * name that is seen by remote devices during discovery. If the controller has
+   * not been initialized yet (before the first time it gets enabled), this will
+   * return "not-initialized".
+   */
+  String getName();
+
+  /**
+   * Registers a callback receiver which can be used to listen to state updates
+   * from the adapter. The Bluetooth daemon will automatically register this if
+   * the owning process dies.
+   */
+  void registerCallback(in IBluetoothCallback callback);
+
+  /**
+   * Unregisters a previously registered callback.
+   */
+  void unregisterCallback(in IBluetoothCallback callback);
+
+  /**
+   * Returns true, if the multi-advertisement feature is supported. Returns
+   * false, if this device can only advertise a single instance.
+   */
+  boolean isMultiAdvertisementSupported();
+
+  /**
+   * Returns a binder that can be used to interact with Low-Energy features.
+   */
+  IBluetoothLowEnergy getLowEnergyInterface();
+
+  /**
+   * Returns a binder that can be used to interact with GATT client-role
+   * features.
+   */
+  IBluetoothGattClient getGattClientInterface();
+
+  /**
+   * Returns a binder that can be used to interact with GATT server-role
+   * features.
+   */
+  IBluetoothGattServer getGattServerInterface();
+}
diff --git a/bt/service/doc/IBluetoothCallback.txt b/bt/service/doc/IBluetoothCallback.txt
new file mode 100644
index 0000000..612ecca
--- /dev/null
+++ b/bt/service/doc/IBluetoothCallback.txt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Binder IPC callback interface for receiving notifications about the
+ * high-level Bluetooth adapter state.
+ */
+interface IBluetoothCallback {
+  /**
+   * Called when the adapter state changes from |prev_state| to |new_state|.
+   */
+  void onBluetoothStateChange(in int prev_state, in int new_state);
+}
diff --git a/bt/service/doc/IBluetoothGattClient.txt b/bt/service/doc/IBluetoothGattClient.txt
new file mode 100644
index 0000000..8e55005
--- /dev/null
+++ b/bt/service/doc/IBluetoothGattClient.txt
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Binder IPC interface for interacting with Bluetooth GATT client-role
+ * features.
+ * TODO(armansito): Not yet supported.
+ */
+interface IBluetoothGattClient {
+  /**
+   * Registers a client application with this interface. This creates a unique
+   * GATT client instance for the application. Returns true on success; false
+   * otherwise. If successful, the caller will be assigned a "client_id" which
+   * will be reported asynchronously via
+   * IBluetoothGattClientCallback.onRegistered. This ID is required to make
+   * calls to the functions defined below.
+   */
+  boolean registerClient(in IBluetoothGattClientCallback callback);
+
+  /**
+   * Unregisters a previously registered client with interface ID |client_id|.
+   */
+  void unregisterClient(in int client_id);
+
+  /**
+   * Unregisters all previously registered clients.
+   */
+  void unregisterAll();
+
+  /**
+   * Refreshes the local client-side attribute cache that mirrors the attribute
+   * database of remote device with address |device_address|. Returns false in
+   * case of an error. |client_id| is the identifier obtained via
+   * registerClient.
+   */
+  boolean refreshDevice(in int client_id, in String device_address);
+
+  /**
+   * Returns the GATT services, characteristics, and descriptors on the remote
+   * device with address |device_address| asynchronously via the corresponding
+   * IBluetoothGattClientCallback callbacks. Based on the current connection and
+   * bonding state, either GATT service discovery will be initiated or the
+   * results will be returned from the attribute cache. Returns false in case of
+   * an error. |client_id| is the identifier obtained via registerClient.
+   */
+  boolean discoverServices(in int client_id, in String device_address);
+
+  /**
+   * Initiate a read request for the remote characteristic with identifier
+   * |characteristic_id|. The result will be asynchronously reported in
+   * IBluetoothGattClientCallback.onCharacteristicRead. Returns false if the
+   * request cannot be started, e.g. if a read is already pending on this remote
+   * device. If the read request fails due to characteristic permissions,
+   * this function will try to raise the connection security level based on the
+   * characteristic's permission requirements. If that operation fails, then the
+   * |status| parameter of the onCharacteristicRead callback will contain the
+   * appropriate ATT protocol error code. |client_id| is obtained via
+   * registerClient.
+   */
+  boolean readCharacteristic(in int client_id,
+                             in GattIdentifier characteristic_id);
+
+  /**
+   * Initiate a write request for the remote characteristic with identifier
+   * |characteristic_id| with the value |value|. The |write_type| parameter
+   * indicates which of the following GATT write procedure should be used:
+   *
+   *   - WRITE_TYPE_DEFAULT (0x02): Regular Write Procedure
+   *   - WRITE_TYPE_NO_RESPONSE (0x01): Write Without Response procedure
+   *   - WRITE_TYPE_SIGNED (0x04): Signed Write Without Response procedure.
+   *
+   * The result will be asynchronously reported in
+   * IBluetoothGattClientCallback.onCharacteristicWrite. Returns false if the
+   * request cannot be started. If the write request fails due to attribute
+   * permissions, this function will try to raise the connection security level
+   * based on the characteristic's permission requirements. If that operation
+   * fails, then the |status| parameter of the onCharacteristicWrite callback
+   * will contain the appropriate ATT protocol error code. |client_id| is
+   * obtained via registerClient.
+   */
+  boolean writeCharacteristic(in int client_id,
+                              in GattIdentifier characteristic_id,
+                              in int write_type,
+                              in byte[] value);
+
+  /**
+   * Initiate a read request for the remote descriptor with identifier
+   * |descriptor_id|. The result will be asynchronously reported in
+   * IBluetoothGattClientCallback.onDescriptorRead. Returns false if the
+   * request cannot be started, e.g. if a read is already pending on this remote
+   * device. If the read request fails due to descriptor permissions,
+   * this function will try to raise the connection security level based on the
+   * descriptor's permission requirements. If that operation fails, then the
+   * |status| parameter of the onDescriptorRead callback will contain the
+   * appropriate ATT protocol error code. |client_id| is obtained via
+   * registerClient.
+   */
+  boolean readDescriptor(in int client_id,
+                         in GattIdentifier descriptor_id);
+
+  /**
+   * Initiate a write request for the remote descriptor with identifier
+   * |descriptor_id| with the value |value|. The |write_type| parameter
+   * indicates which of the following GATT write procedure should be used:
+   *
+   *   - WRITE_TYPE_DEFAULT (0x02): Regular write procedure
+   *   - WRITE_TYPE_NO_RESPONSE (0x01): Write without response procedure
+   *   - WRITE_TYPE_SIGNED (0x04): Authenticated-signed write procedure
+   *
+   * The result will be asynchronously reported in
+   * IBluetoothGattClientCallback.onDescriptorWrite. Returns false if the
+   * request cannot be started. If the write request fails due to attribute
+   * permissions, this function will try to raise the connection security level
+   * based on the descriptor's permission requirements. If that operation fails,
+   * then the |status| parameter of the onDescriptorWrite callback will contain
+   * the appropriate ATT protocol error code. |client_id| is obtained via
+   * registerClient.
+   */
+  boolean writeDescriptor(in int client_id,
+                          in GattIdentifier descriptor_id,
+                          in int write_type,
+                          in byte[] value);
+
+  /**
+   * Enables handle-value notifications from the remote characteristic with ID
+   * |characteristic_id|. If successful, notifications will be signaled via
+   * IBluetoothGattClientCallback.onNotify. Returns false if the request cannot
+   * be initiated. |client_id| is obtained via registerClient.
+   */
+  boolean registerForNotifications(in int client_id,
+                                   in GattIdentifier characteristic_id);
+
+  /**
+   * Disables handle-value notifications from the remote characteristic with ID
+   * |characteristic_id|. Returns false if the request cannot be initiated, e.g.
+   * if notifications from this characteristic have not been enabled.
+   * |client_id| is obtained via registerClient.
+   */
+  boolean unregisterForNotifications(in int client_id,
+                                     in GattIdentifier characteristic_id);
+
+  /**
+   * Initiates a reliable write procedure for the remote device with address
+   * |device_address|. Once a reliable write transaction has been initiated, all
+   * calls to writeCharacteristic are sent to the remote device for verification
+   * and queued up for atomic execution. The application can verify each write
+   * payload using the IBluetoothGattClientCallback.onCharacteristicWrite
+   * callback and abort reliable write in case of a mismatch. The queued writes
+   * will be processed atomically by the remote device after calling
+   * endReliableWrite. Returns false if the procedure cannot be started, e.g. if
+   * it has already been started earlier. |client_id| is obtained via
+   * registerClient.
+   */
+  boolean beginReliableWrite(in int client_id, in String device_address);
+
+  /**
+   * Ends a previously started reliable write procedure for the remote device
+   * with address |device_address|. If |execute| is true, then a request will be
+   * sent to execute the queued writes, else a request will be sent to abort the
+   * queued writes. Returns false in case of a failure, e.g. if a reliable write
+   * procedure was not started. IBluetoothGattClientCallback.onExecuteWrite will
+   * be used to asynchronously report the result of the execute write request.
+   * |client_id| is obtained via registerClient.
+   */
+  boolean endReliableWrite(in int client_id, in String device_address,
+                           in boolean execute);
+}
diff --git a/bt/service/doc/IBluetoothGattClientCallback.txt b/bt/service/doc/IBluetoothGattClientCallback.txt
new file mode 100644
index 0000000..d3ec6ed
--- /dev/null
+++ b/bt/service/doc/IBluetoothGattClientCallback.txt
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Binder IPC interface for receiving callbacks related to Bluetooth GATT
+ * client-role operations.
+ * TODO(armansito): Not yet supported.
+ */
+oneway interface IBluetoothGattClientCallback {
+  /**
+   * Called as a result of IBluetoothGattClient.registerClient.
+   * |status| will contain BLE_STATUS_SUCCESS (0) if the client was successfully
+   * registered. |client_id| is the owning application's unique GATT client
+   * handle and can be used to perform further operations on the
+   * IBluetoothGattClient interface.
+   */
+  void onClientRegistered(in int status, in int client_id);
+
+  /**
+   * Called for each GATT service that was discovered on the remote device. The
+   * device that this service belongs to can be obtained from the |service_id|
+   * structure. |is_primary| is true if this refers to a primary service,
+   * otherwise this refers to a secondary service.
+   */
+  void onGetService(in boolean is_primary, in GattIdentifier service_id);
+
+  /**
+   * Called for each include definition that was discovered on the remote
+   * device.
+   */
+  void onGetIncludedService(in GattIdentifier included_service_id);
+
+  /**
+   * Called for each characteristic that was discovered on the remote device.
+   * The service that this characteristic belongs to can be obtained from the
+   * |characteristic_id| structure. |properties| contains the bitmask of GATT
+   * characteristic properties as defined in the Bluetooth Core Specification.
+   */
+  void onGetCharacteristic(in GattIdentifier characteristic_id,
+                           in int properties);
+
+  /**
+   * Called for each descriptor that was discovered on the remote device. The
+   * service and characteristic that this descriptor belongs to can be obtained
+   * from the |descriptor_id| structure.
+   */
+  void onGetDescriptor(in GattIdentifier descriptor_id);
+
+  /**
+   * Called to mark the end of GATT service discovery on the remote device with
+   * address |device_address|. |status| will contain BLE_STATUS_SUCCESS (0) if
+   * the operation was successful.
+   */
+  void onSearchComplete(in String device_address, in int status);
+
+  /**
+   * Called as a result of IBluetoothGattClient.readCharacteristic. |status|
+   * will contain BLE_STATUS_SUCCESS (0) on success and an ATT protocol error
+   * code in case of an error. |characteristic_id| refers to the characteristic
+   * this operation was performed on. On success, |value| will contain the
+   * characteristic value that was read from the remote device. This argument
+   * can be ignored in case of failure.
+   */
+  void onCharacteristicRead(in int status, in GattIdentifier characteristic_id,
+                            in byte[] value);
+
+  /**
+   * Called as a result of IBluetoothGattClient.writeCharacteristic. |status|
+   * will contain BLE_STATUS_SUCCESS (0) on success and an ATT protocol error
+   * code in case of an error. |characteristic_id| refers to the characteristic
+   * this operation was performed on.
+   */
+  void onCharacteristicWrite(in int status,
+                             in GattIdentifier characteristic_id);
+
+  /**
+   * Called as a result of IBluetoothGattClient.endReliableWrite.
+   * |device_address| refers to the remote device that the endReliableWrite
+   * method was called on. |status| will contain BLE_STATUS_SUCCESS (0) on
+   * success and an ATT error code in case of an error.
+   */
+  void onExecuteWrite(in String device_address, in int status);
+
+  /**
+   * Called as a result of IBluetoothGattClient.readDescriptor. |status|
+   * will contain BLE_STATUS_SUCCESS (0) on success and an ATT protocol error
+   * code in case of an error. |descriptor_id| refers to the descriptor this
+   * operation was performed on. On success, |value| will contain the
+   * descriptor value that was read from the remote device. This argument
+   * can be ignored in case of failure.
+   */
+  void onDescriptorRead(in int status, in GattIdentifier descriptor_id,
+                        in byte[] value);
+
+  /**
+   * Called as a result of IBluetoothGattClient.writeDescriptor. |status|
+   * will contain BLE_STATUS_SUCCESS (0) on success and an ATT protocol error
+   * code in case of an error. |descriptor_id| refers to the descriptor this
+   * operation was performed on.
+   */
+  void onDescriptorWrite(in int status, in GattIdentifier descriptor_id);
+
+  /**
+   * Called when there is an incoming ATT Handle-Value notification or
+   * indication for the characteristic with identifier |characteristic_id|.
+   */
+  void onNotify(in GattIdentifier characteristic_id, in byte[] value);
+}
diff --git a/bt/service/doc/IBluetoothGattServer.txt b/bt/service/doc/IBluetoothGattServer.txt
new file mode 100644
index 0000000..0efecab
--- /dev/null
+++ b/bt/service/doc/IBluetoothGattServer.txt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Binder IPC interface for interacting with Bluetooth GATT server-role
+ * features.
+ */
+interface IBluetoothGattServer {
+  /**
+   * Registers a client application with this interface. This creates a unique
+   * GATT server instance for the application that will contain the GATT
+   * services belonging to the calling application. A special interface ID will
+   * be returned in a callback to the application that can be used to perform
+   * GATT server operations. Returns false in case of an error.
+   */
+  boolean registerServer(in IBluetoothGattServerCallback callback);
+
+  /**
+   * Unregisters a previously registered server with interface ID |server_if|.
+   */
+  void unregisterServer(in int server_if);
+
+  /**
+   * Unregisters all previously registered servers.
+   */
+  void unregisterAll();
+
+  /**
+   * Adds new GATT service. This will execute synchronously, and result in
+   * IBluetoothGattServerCallback.onServiceAdded.
+   *
+   * Returns true on success, false otherwise.
+   */
+  boolean AddService(int server_id, in BluetoothGattService service);
+
+  /**
+   * Sends a response to a currently pending read or write request. The request
+   * will be propagated to the application via IBluetoothGattServerCallback with
+   * a unique |request_id| which must be passed to this method along with the
+   * |device_address| of the device that the request originated from.
+   *
+   * The |status| field should contain the result of the operation. In the case
+   * of success, the application should pass in "0". Otherwise this should
+   * contain an ATT protocol error code.
+   */
+  boolean sendResponse(in int server_if, in String device_address,
+                       in int request_id, in int status,
+                       in int offset, in byte[] value);
+
+  /**
+   * Sends a handle-value notification or indication to the device with the
+   * given address for the characteristic with the given handle. |confirm|
+   * should be set to true, if a handle-value indication should be sent, which
+   * will remain pending until the remote device sends a handle-value
+   * confirmation. Returns false if a call to this method is pending. Otherwise
+   * reports the result asynchronously in
+   * IBluetoothGattServerCallback.onNotificationSent.
+   */
+  boolean sendNotification(in int server_if, in String device_address,
+                           in int handle,
+                           in boolean confirm, in byte[] value);
+}
diff --git a/bt/service/doc/IBluetoothGattServerCallback.txt b/bt/service/doc/IBluetoothGattServerCallback.txt
new file mode 100644
index 0000000..3744ff1
--- /dev/null
+++ b/bt/service/doc/IBluetoothGattServerCallback.txt
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Binder IPC interface for receiving callbacks related to Bluetooth GATT
+ * server-role operations.
+ */
+oneway interface IBluetoothGattServerCallback {
+  /**
+   * Called to report the result of a call to
+   * IBluetoothGattServer.registerServer. |status| will be 0 (or
+   * BLE_STATUS_SUCCESS) if the server was successfully registered. |server_if|
+   * is the owning application's unique GATT server handle and can be used to
+   * perform further operations on the IBluetoothGattServer interface.
+   */
+  void onServerRegistered(in int status, in int server_if);
+
+  /**
+   * Called to report the result of a call to IBluetoothGattServer.AddService.
+   * A |status| of 0 denotes success, which means that the GATT service has
+   * been published and is discoverable. In this case handles of added service,
+   * it's characteristics and descriptors are filled.
+   */
+  void onServiceAdded(in int status, in BluetoothGattServer service_id);
+
+  /**
+   * Called when there is an incoming read request from the remote device with
+   * address |device_address| for the characteristic with handle |handle|.
+   * |offset| is the index of the characteristic value that
+   * the remote device wants to read from. If |is_long| is true, then this
+   * request is part of a Long Read procedure. An implementation should handle
+   * this request by calling IBluetoothGattServer.sendResponse with the given
+   * |request_id| and the appropriate characteristic value.
+   *
+   * If |offset| is invalid then sendResponse should be called with
+   * GATT_ERROR_INVALID_OFFSET. If |is_long| is true but this characteristic is
+   * not a long attribute (i.e. its value would fit within the current ATT MTU),
+   * then GATT_ERROR_ATTRIBUTE_NOT_LONG should be returned.
+   */
+  void onCharacteristicReadRequest(in String device_address, in int request_id,
+                                   in int offset, in boolean is_long,
+                                   in int handle);
+
+  /**
+   * Called when there is an incoming read request from the remote device with
+   * address |device_address| for the descriptor with handle |handle|.
+   * |offset| is the index of the descriptor value that
+   * the remote device wants to read from. If |is_long| is true, then this
+   * request is part of a Long Read procedure. An implementation should handle
+   * this request by calling IBluetoothGattServer.sendResponse with the given
+   * |request_id| and the appropriate descriptor value.
+   *
+   * If |offset| is invalid then sendResponse should be called with
+   * GATT_ERROR_INVALID_OFFSET. If |is_long| is true but this descriptor is
+   * not a long attribute (i.e. its value would fit within the current ATT MTU),
+   * then GATT_ERROR_ATTRIBUTE_NOT_LONG should be returned.
+   */
+  void onDescriptorReadRequest(in String device_address, in int request_id,
+                               in int offset, in boolean is_long,
+                               in int handle);
+
+  /**
+   * Called when there is an incoming write request from the remote device with
+   * address |device_address| for the characteristic with handle |handle|
+   * with the value |value|. An implementation should handle
+   * this request by calling IBluetoothGattServer.sendResponse with the given
+   * |request_id|. |offset| is the index of the characteristic value that the
+   * remote device wants to write to, so the value should be written starting at
+   * |offset|. If |need_response| is false, then this is a "Write Without
+   * Response" procedure and sendResponse should not be called. If
+   * |is_prepare_write| is true, then the implementation should not commit this
+   * write until a call to onExecuteWriteRequest is received.
+   *
+   * If |offset| is invalid, then sendResponse should be called with
+   * GATT_ERROR_INVALID_OFFSET.
+   */
+  void onCharacteristicWriteRequest(in String device_address, in int request_id,
+                                    in int offset, in boolean is_prepare_write,
+                                    in boolean need_response, in byte[] value,
+                                    in int handle);
+
+  /**
+   * Called when there is an incoming write request from the remote device with
+   * address |device_address| for the descriptor with handle |handle|
+   * with the value |value|. An implementation should handle
+   * this request by calling IBluetoothGattServer.sendResponse with the given
+   * |request_id|. |offset| is the index of the descriptor value that the
+   * remote device wants to write to, so the value should be written starting at
+   * |offset|. If |need_response| is false, then this is a "Write Without
+   * Response" procedure and sendResponse should not be called. If
+   * |is_prepare_write| is true, then the implementation should not commit this
+   * write until a call to onExecuteWriteRequest is received.
+   *
+   * If |offset| is invalid, then sendResponse should be called with
+   * GATT_ERROR_INVALID_OFFSET.
+   */
+  void onDescriptorWriteRequest(in String device_address, in int request_id,
+                                in int offset, in boolean is_prepare_write,
+                                in boolean need_response, in byte[] value,
+                                in int handle);
+
+  /**
+   * Called when there is an incoming execute-write request to commit or abort
+   * previously prepared writes. If |is_execute| is true, then the
+   * implementation should commit all previously prepared writes. Otherwise all
+   * prepared writes should dropped (aborted). The application should report the
+   * result of the execute write by calling IBluetoothGattServer.sendResponse
+   * with the given |request_id|.
+   */
+  void onExecuteWriteRequest(in String device_address, in int request_id,
+                             in boolean is_execute);
+
+  /**
+   * Reports the result of a previous call to
+   * IBluetoothGattServer.sendNotification. If an indication was sent, this will
+   * be called when the remote device sends a confirmation packet. Otherwise
+   * this will be called as soon as the notification packet is successfully sent
+   * out over the radio.
+   */
+  void onNotificationSent(in String device_address, in int status);
+}
diff --git a/bt/service/doc/IBluetoothLowEnergy.txt b/bt/service/doc/IBluetoothLowEnergy.txt
new file mode 100644
index 0000000..b7218cb
--- /dev/null
+++ b/bt/service/doc/IBluetoothLowEnergy.txt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Binder IPC API for interacting with Bluetooth Low-Energy features.
+ */
+interface IBluetoothLowEnergy {
+  /**
+   * Registers a client application that can manage its own Low Energy
+   * instance. A special client interface ID will be returned in a callback to
+   * the application that can be used to perform Low Energy operations. Returns
+   * false in case of an error.
+   */
+  boolean registerClient(in IBluetoothLowEnergyCallback callback);
+
+  /**
+   * Unregisters a previously registered client with "client interface ID"
+   * |client_if|.
+   */
+  void unregisterClient(in int client_if);
+
+  /**
+   * Unregisters all previously registered clients.
+   */
+  void unregisterAll();
+
+  /* Initiates a BLE connection do device with address |address|. If
+   * |is_direct| is set, use direct connect procedure. Return true on success,
+   * false otherwise.
+   */
+  boolean Connect(in int client_id, in const char* address,
+                  in boolean is_direct);
+
+  /* Disconnect from previously connected BLE device with address |address|.
+   * Returns true on success, false otherwise.
+   */
+  boolean Disconnect(in int client_id, in const char* address);
+
+  /**
+   * Sends request to set MTU to |mtu| for the device with address |address|.
+   * OnMtuChanged callback will be triggered as a result of this call. Returns
+   * true when the command was sent, false otherwise.
+   */
+   boolean setMtu(in int client_id, in char* address, int mtu);
+
+  /**
+   * Initiates a BLE device scan for the scan client with ID |client_id|, using
+   * the parameters defined in |settings|. Scan results that are reported to the
+   * application with the associated IBluetoothLowEnergyCallback event will be
+   * filtered using a combination of hardware and software filtering based on
+   * |filters|. Return true on success, false otherwise.
+   */
+  boolean startScan(in int client_id, in ScanSettings settings,
+                    in ScanFilter[] filters);
+
+  /**
+   * Stops a previously initiated scan session for the client with ID
+   * |client_id|. Return true on success, false otherwise.
+   */
+  boolean stopScan(in int client_id);
+
+  /**
+   * Starts a multi-advertising instance using |advertising_data| and
+   * |scan_response_data|, both of which can be empty. Each of these parameters
+   * must contain the raw advertising packet. Returns false if there were any
+   * synchronous failures, e.g. if the advertising or scan response data are
+   * incorrectly formatted. Otherwise, the result of the operation will be
+   * asynchronously reported in
+   * IBluetoothLowEnergyCallback.onMultiAdvertiseCallback. See the headers in
+   * common/bluetooth/binder for documentation on the AdvertiseData and
+   * AdvertiseSettings data types.
+   */
+  boolean startMultiAdvertising(in int client_if,
+                                in AdvertiseData advertise_data,
+                                in AdvertiseData scan_response_data,
+                                in AdvertiseSettings settings);
+
+  /**
+   * Stops the previously started multi-advertising instance for the given
+   * client. Returns false in case of an error, e.g. this client has not started
+   * an instance.
+   */
+  boolean stopMultiAdvertising(in int client_if);
+}
diff --git a/bt/service/doc/IBluetoothLowEnergyCallback.txt b/bt/service/doc/IBluetoothLowEnergyCallback.txt
new file mode 100644
index 0000000..1ced0aa
--- /dev/null
+++ b/bt/service/doc/IBluetoothLowEnergyCallback.txt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Binder IPC interface for receiving callbacks related to Bluetooth Low Energy
+ * operations.
+ */
+oneway interface IBluetoothLowEnergyCallback {
+  /**
+   * Called to report the result of a call to
+   * IBluetoothLowEnergy.registerClient. |status| will be BLE_STATUS_SUCCESS (0)
+   * if the client was successfully registered. |client_if| is the owning
+   * application's unique Low Energy client handle and can be used
+   * to perform further operations on the IBluetoothLowEnergy interface.
+   */
+  void onClientRegistered(in int status, in int client_if);
+
+  /* Called asynchronously to notify the delegate of connection state change.
+   */
+  void OnConnectionState(in int status, in int client_id, in const char* address,
+                         in bool connected);
+
+  /* Called to report current MTU value. Can be a result of calling
+   * IBluetoothLowEnergy.setMtu or remote device trying to change MTU.
+   */
+  void OnMtuChanged(in int status, in const char* address, in int mtu);
+
+  /**
+   * Called to report BLE device scan results once a scan session is started for
+   * this client using IBluetoothLowEnergy.startScan. |scan_result| contains all
+   * the data related to the discovered BLE device.
+   */
+  void onScanResult(in ScanResult scan_result);
+
+  /**
+   * Called to report the result of a call to
+   * IBluetoothLowEnergy.startMultiAdvertising or stopMultiAdvertising.
+   */
+  void onMultiAdvertiseCallback(in int status, in boolean is_start,
+                                in AdvertiseSettings settings);
+}
diff --git a/bt/service/example/heart_rate/constants.h b/bt/service/example/heart_rate/constants.h
new file mode 100644
index 0000000..6159997
--- /dev/null
+++ b/bt/service/example/heart_rate/constants.h
@@ -0,0 +1,45 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <bluetooth/uuid.h>
+
+// This header defines constants specific to the GATT Heart Rate Service.
+
+namespace heart_rate {
+
+// HR Measurement characteristic value flags
+const uint8_t kHRValueFormat8Bit = (0 << 0);
+const uint8_t kHRValueFormat16Bit = (1 << 0);
+const uint16_t kHRSensorContactDetected = (3 << 1);
+const uint8_t kHREnergyExpendedPresent = (1 << 3);
+
+const bluetooth::UUID kCCCDescriptorUUID("2902");
+const bluetooth::UUID kHRServiceUUID("180D");
+const bluetooth::UUID kHRMeasurementUUID("2A37");
+const bluetooth::UUID kBodySensorLocationUUID("2A38");
+const bluetooth::UUID kHRControlPointUUID("2A39");
+
+const uint8_t kHRBodyLocationOther = 0;
+const uint8_t kHRBodyLocationChest = 1;
+const uint8_t kHRBodyLocationWrist = 2;
+const uint8_t kHRBodyLocationFinger = 3;
+const uint8_t kHRBodyLocationHand = 4;
+const uint8_t kHRBodyLocationEarLobe = 5;
+const uint8_t kHRBodyLocationFoot = 6;
+
+}  // namespace heart_rate
diff --git a/bt/service/example/heart_rate/heart_rate_server.cc b/bt/service/example/heart_rate/heart_rate_server.cc
new file mode 100644
index 0000000..e1ae7f6
--- /dev/null
+++ b/bt/service/example/heart_rate/heart_rate_server.cc
@@ -0,0 +1,478 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/example/heart_rate/heart_rate_server.h"
+
+#include <base/bind.h>
+#include <base/location.h>
+#include <base/logging.h>
+#include <base/rand_util.h>
+
+#include <android/bluetooth/BnBluetoothLeAdvertiserCallback.h>
+#include <android/bluetooth/IBluetoothLeAdvertiser.h>
+#include <bluetooth/low_energy_constants.h>
+
+#include "service/example/heart_rate/constants.h"
+
+using android::binder::Status;
+using android::String8;
+using android::String16;
+
+using android::bluetooth::IBluetoothLeAdvertiser;
+using android::bluetooth::BluetoothGattService;
+
+namespace heart_rate {
+
+class CLIBluetoothLeAdvertiserCallback
+    : public android::bluetooth::BnBluetoothLeAdvertiserCallback {
+ public:
+  explicit CLIBluetoothLeAdvertiserCallback(android::sp<android::bluetooth::IBluetooth> bt)
+      : bt_(bt) {}
+
+  // IBluetoothLeAdvertiserCallback overrides:
+  Status OnAdvertiserRegistered(int status, int advertiser_id) {
+    if (status != bluetooth::BLE_STATUS_SUCCESS) {
+      LOG(ERROR) << "Failed to register BLE advertiser, will not start advertising";
+      return Status::ok();
+    }
+
+    LOG(INFO) << "Registered BLE advertiser with ID: " << advertiser_id;
+
+    String16 name_param;
+    bt_->GetName(&name_param);
+    std::string name(String8(name_param).string());
+
+    /* Advertising data: 16-bit Service UUID: Heart Rate Service, Tx power*/
+    std::vector<uint8_t> data{
+      0x03, bluetooth::kEIRTypeComplete16BitUUIDs, 0x0D, 0x18,
+      0x02, bluetooth::kEIRTypeTxPower, 0x00};
+    data.push_back(name.length() + 1);
+    data.push_back(bluetooth::kEIRTypeCompleteLocalName);
+    data.insert(data.begin(), name.c_str(), name.c_str() + name.length());
+
+    base::TimeDelta timeout;
+
+    bluetooth::AdvertiseSettings settings(
+        bluetooth::AdvertiseSettings::MODE_LOW_POWER, timeout,
+        bluetooth::AdvertiseSettings::TX_POWER_LEVEL_MEDIUM, true);
+
+    bluetooth::AdvertiseData adv_data(data);
+    bluetooth::AdvertiseData scan_rsp;
+
+    android::sp<IBluetoothLeAdvertiser> ble;
+    bt_->GetLeAdvertiserInterface(&ble);
+    bool start_status;
+    ble->StartMultiAdvertising(advertiser_id, adv_data, scan_rsp, settings,
+                               &start_status);
+    return Status::ok();
+  }
+
+  Status OnMultiAdvertiseCallback(
+      int status, bool is_start,
+      const android::bluetooth::AdvertiseSettings& /* settings */) {
+    LOG(INFO) << "Advertising" << (is_start ? " started" : " stopped");
+    return Status::ok();
+  };
+
+ private:
+  android::sp<android::bluetooth::IBluetooth> bt_;
+  DISALLOW_COPY_AND_ASSIGN(CLIBluetoothLeAdvertiserCallback);
+};
+
+
+HeartRateServer::HeartRateServer(
+    android::sp<android::bluetooth::IBluetooth> bluetooth,
+    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+    bool advertise)
+    : simulation_started_(false),
+      bluetooth_(bluetooth),
+      server_if_(-1),
+      hr_notification_count_(0),
+      energy_expended_(0),
+      advertise_(advertise),
+      main_task_runner_(main_task_runner),
+      weak_ptr_factory_(this) {
+  CHECK(bluetooth_.get());
+}
+
+HeartRateServer::~HeartRateServer() {
+  std::lock_guard<std::mutex> lock(mutex_);
+  if (!gatt_.get() || server_if_ == -1) return;
+
+  if (!android::IInterface::asBinder(gatt_.get())->isBinderAlive()) return;
+
+  // Manually unregister ourselves from the daemon. It's good practice to do
+  // this, even though the daemon will automatically unregister us if this
+  // process exits.
+  gatt_->UnregisterServer(server_if_);
+}
+
+bool HeartRateServer::Run(const RunCallback& callback) {
+  std::lock_guard<std::mutex> lock(mutex_);
+
+  if (pending_run_cb_) {
+    LOG(ERROR) << "Already started";
+    return false;
+  }
+
+  // Grab the IBluetoothGattServer binder from the Bluetooth daemon.
+  bluetooth_->GetGattServerInterface(&gatt_);
+  if (!gatt_.get()) {
+    LOG(ERROR) << "Failed to obtain handle to IBluetoothGattServer interface";
+    return false;
+  }
+
+  // Register this instance as a GATT server. If this call succeeds, we will
+  // asynchronously receive a server ID via the OnServerRegistered callback.
+  bool status;
+  gatt_->RegisterServer(this, &status);
+  if (!status) {
+    LOG(ERROR) << "Failed to register with the server interface";
+    return false;
+  }
+
+  pending_run_cb_ = callback;
+
+  return true;
+}
+
+void HeartRateServer::ScheduleNextMeasurement() {
+  main_task_runner_->PostDelayedTask(
+      FROM_HERE, base::Bind(&HeartRateServer::SendHeartRateMeasurement,
+                            weak_ptr_factory_.GetWeakPtr()),
+      base::TimeDelta::FromSeconds(1));
+}
+
+void HeartRateServer::SendHeartRateMeasurement() {
+  std::lock_guard<std::mutex> lock(mutex_);
+
+  // Send a notification or indication to all enabled devices.
+  bool found = false;
+  for (const auto& iter : device_ccc_map_) {
+    uint8_t ccc_val = iter.second;
+
+    if (!ccc_val) continue;
+
+    found = true;
+
+    // Don't send a notification if one is already pending for this device.
+    if (pending_notification_map_[iter.first]) continue;
+
+    std::vector<uint8_t> value;
+    BuildHeartRateMeasurementValue(&value);
+
+    bool status;
+    gatt_->SendNotification(server_if_, String16(String8(iter.first.c_str())),
+                            hr_measurement_handle_, false, value, &status);
+    if (status) pending_notification_map_[iter.first] = true;
+  }
+
+  // Still enabled!
+  if (found) {
+    ScheduleNextMeasurement();
+    return;
+  }
+
+  // All clients disabled notifications.
+  simulation_started_ = false;
+
+  // TODO(armansito): We should keep track of closed connections here so that we
+  // don't send notifications to uninterested clients.
+}
+
+void HeartRateServer::BuildHeartRateMeasurementValue(
+    std::vector<uint8_t>* out_value) {
+  CHECK(out_value);  // Assert that |out_value| is not nullptr.
+
+  // Default flags field. Here is what we put in there:
+  //   Bit 0: 0 - 8-bit Heart Rate value
+  //   Bits 1 & 2: 11 - Sensor contact feature supported and contact detected.
+  uint8_t flags = kHRValueFormat8Bit | kHRSensorContactDetected;
+
+  // Our demo's heart rate. Pick a value between 90 and 130.
+  uint8_t heart_rate = base::RandInt(90, 130);
+
+  // On every tenth beat we include the Energy Expended value.
+  bool include_ee = false;
+  if (!(hr_notification_count_ % 10)) {
+    include_ee = true;
+    flags |= kHREnergyExpendedPresent;
+  }
+
+  hr_notification_count_++;
+  energy_expended_ = std::min(UINT16_MAX, (int)energy_expended_ + 1);
+
+  // Add all the value bytes.
+  out_value->push_back(flags);
+  out_value->push_back(heart_rate);
+  if (include_ee) {
+    out_value->push_back(energy_expended_);
+    out_value->push_back(energy_expended_ >> 8);
+  }
+}
+
+Status HeartRateServer::OnServerRegistered(int status, int server_if) {
+  std::lock_guard<std::mutex> lock(mutex_);
+
+  if (status != bluetooth::BLE_STATUS_SUCCESS) {
+    LOG(ERROR) << "Failed to register GATT server";
+    pending_run_cb_(false);
+    return Status::ok();
+  }
+
+  // Registration succeeded. Store our ID, as we need it for GATT server
+  // operations.
+  server_if_ = server_if;
+
+  LOG(INFO) << "Heart Rate server registered - server_if: " << server_if_;
+
+  bluetooth::Service hrService(0, true, kHRServiceUUID, {
+    {0, kHRMeasurementUUID, bluetooth::kCharacteristicPropertyNotify, 0,
+      { {0, kCCCDescriptorUUID, (bluetooth::kAttributePermissionRead | bluetooth::kAttributePermissionWrite)}} },
+    {0, kBodySensorLocationUUID, bluetooth::kCharacteristicPropertyRead, bluetooth::kAttributePermissionRead, {}},
+    {0, kHRControlPointUUID, bluetooth::kCharacteristicPropertyWrite, bluetooth::kAttributePermissionWrite, {}}
+    }, {});
+
+  bool op_status = true;
+
+  Status stat = gatt_->AddService(server_if_, (BluetoothGattService)hrService, &op_status);
+  if (!stat.isOk()) {
+    LOG(ERROR) << "Failed to add service, status is: " /*<< stat*/;
+    pending_run_cb_(false);
+    return Status::ok();
+  }
+
+  if (!op_status) {
+    LOG(ERROR) << "Failed to add service";
+    pending_run_cb_(false);
+    return Status::ok();
+  }
+
+  LOG(INFO) << "Initiated AddService request";
+  return Status::ok();
+}
+
+Status HeartRateServer::OnServiceAdded(
+    int status, const android::bluetooth::BluetoothGattService& service) {
+  std::lock_guard<std::mutex> lock(mutex_);
+
+  if (status != bluetooth::BLE_STATUS_SUCCESS) {
+    LOG(ERROR) << "Failed to add Heart Rate service";
+    pending_run_cb_(false);
+    return Status::ok();
+  }
+
+  hr_service_handle_ = service.handle();
+  hr_measurement_handle_ = service.characteristics()[0].handle();
+  hr_measurement_cccd_handle_ =
+      service.characteristics()[0].descriptors()[0].handle();
+  body_sensor_loc_handle_ = service.characteristics()[1].handle();
+  hr_control_point_handle_ = service.characteristics()[2].handle();
+
+  LOG(INFO) << "Heart Rate service added";
+  pending_run_cb_(true);
+
+  if (advertise_) {
+    android::sp<IBluetoothLeAdvertiser> ble;
+    bluetooth_->GetLeAdvertiserInterface(&ble);
+    bool status;
+    ble->RegisterAdvertiser(new CLIBluetoothLeAdvertiserCallback(bluetooth_), &status);
+  }
+
+  return Status::ok();
+}
+
+Status HeartRateServer::OnCharacteristicReadRequest(
+    const String16& device_address, int request_id, int offset,
+    bool /* is_long */, int handle) {
+
+  std::lock_guard<std::mutex> lock(mutex_);
+
+  // This is where we handle an incoming characteristic read. Only the body
+  // sensor location characteristic is readable.
+  CHECK(handle == body_sensor_loc_handle_);
+
+  std::vector<uint8_t> value;
+  bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE;
+  if (offset > 1)
+    error = bluetooth::GATT_ERROR_INVALID_OFFSET;
+  else if (offset == 0)
+    value.push_back(kHRBodyLocationFoot);
+
+  bool status;
+  gatt_->SendResponse(server_if_, device_address, request_id, error, offset,
+                      value, &status);
+  return Status::ok();
+}
+
+Status HeartRateServer::OnDescriptorReadRequest(
+    const String16& device_address, int request_id, int offset,
+    bool /* is_long */, int handle) {
+  std::lock_guard<std::mutex> lock(mutex_);
+
+  // This is where we handle an incoming characteristic descriptor read. There
+  // is only one descriptor.
+  if (handle != hr_measurement_cccd_handle_) {
+    std::vector<uint8_t> value;
+    bool status;
+    gatt_->SendResponse(server_if_, device_address, request_id,
+                        bluetooth::GATT_ERROR_ATTRIBUTE_NOT_FOUND, offset,
+                        value, &status);
+    return Status::ok();
+  }
+
+  // 16-bit value encoded as little-endian.
+  const uint8_t value_bytes[] = {
+      device_ccc_map_[std::string(String8(device_address).string())], 0x00};
+
+  std::vector<uint8_t> value;
+  bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE;
+  if (offset > 2)
+    error = bluetooth::GATT_ERROR_INVALID_OFFSET;
+  else
+    value.insert(value.begin(), value_bytes + offset, value_bytes + 2 - offset);
+
+  bool status;
+  gatt_->SendResponse(server_if_, device_address, request_id, error, offset,
+                      value, &status);
+  return Status::ok();
+}
+
+Status HeartRateServer::OnCharacteristicWriteRequest(
+    const String16& device_address, int request_id, int offset,
+    bool is_prepare_write, bool need_response,
+    const std::vector<uint8_t>& value, int handle) {
+  std::lock_guard<std::mutex> lock(mutex_);
+
+  std::vector<uint8_t> dummy;
+
+  // This is where we handle an incoming characteristic write. The Heart Rate
+  // service doesn't really support prepared writes, so we just reject them to
+  // keep things simple.
+  if (is_prepare_write) {
+    bool status;
+    gatt_->SendResponse(server_if_, device_address, request_id,
+                        bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, offset,
+                        dummy, &status);
+    return Status::ok();
+  }
+
+  // Heart Rate Control point is the only writable characteristic.
+  CHECK(handle == hr_control_point_handle_);
+
+  // Writes to the Heart Rate Control Point characteristic must contain a single
+  // byte with the value 0x01.
+  if (value.size() != 1 || value[0] != 0x01) {
+    bool status;
+    gatt_->SendResponse(server_if_, device_address, request_id,
+                        bluetooth::GATT_ERROR_OUT_OF_RANGE, offset, dummy,
+                        &status);
+    return Status::ok();
+  }
+
+  LOG(INFO) << "Heart Rate Control Point written; Enery Expended reset!";
+  energy_expended_ = 0;
+
+  if (!need_response) return Status::ok();
+
+  bool status;
+  gatt_->SendResponse(server_if_, device_address, request_id,
+                      bluetooth::GATT_ERROR_NONE, offset, dummy, &status);
+  return Status::ok();
+}
+
+Status HeartRateServer::OnDescriptorWriteRequest(
+    const String16& device_address, int request_id, int offset,
+    bool is_prepare_write, bool need_response,
+    const std::vector<uint8_t>& value, int handle) {
+  std::lock_guard<std::mutex> lock(mutex_);
+
+  std::vector<uint8_t> dummy;
+
+  // This is where we handle an incoming characteristic write. The Heart Rate
+  // service doesn't really support prepared writes, so we just reject them to
+  // keep things simple.
+  if (is_prepare_write) {
+    bool status;
+    gatt_->SendResponse(server_if_, device_address, request_id,
+                        bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, offset,
+                        dummy, &status);
+    return Status::ok();
+  }
+
+  // CCC is the only descriptor we have.
+  CHECK(handle == hr_measurement_cccd_handle_);
+
+  // CCC must contain 2 bytes for a 16-bit value in little-endian. The only
+  // allowed values here are 0x0000 and 0x0001.
+  if (value.size() != 2 || value[1] != 0x00 || value[0] > 0x01) {
+    bool status;
+    gatt_->SendResponse(server_if_, device_address, request_id,
+                        bluetooth::GATT_ERROR_CCCD_IMPROPERLY_CONFIGURED,
+                        offset, dummy, &status);
+    return Status::ok();
+  }
+
+  device_ccc_map_[std::string(String8(device_address).string())] = value[0];
+
+  LOG(INFO) << "Heart Rate Measurement CCC written - device: " << device_address
+            << " value: " << (int)value[0];
+
+  // Start the simulation.
+  if (!simulation_started_ && value[0]) {
+    simulation_started_ = true;
+    ScheduleNextMeasurement();
+  }
+
+  if (!need_response) return Status::ok();
+
+  bool status;
+  gatt_->SendResponse(server_if_, device_address, request_id,
+                      bluetooth::GATT_ERROR_NONE, offset, dummy, &status);
+  return Status::ok();
+}
+
+Status HeartRateServer::OnExecuteWriteRequest(const String16& device_address,
+                                              int request_id,
+                                              bool /* is_execute */) {
+  // We don't support Prepared Writes so, simply return Not Supported error.
+  std::vector<uint8_t> dummy;
+  bool status;
+  gatt_->SendResponse(server_if_, device_address, request_id,
+                      bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, 0, dummy,
+                      &status);
+
+  return Status::ok();
+}
+
+Status HeartRateServer::OnNotificationSent(const String16& device_address,
+                                           int status) {
+  LOG(INFO) << "Notification was sent - device: " << device_address
+            << " status: " << status;
+  std::lock_guard<std::mutex> lock(mutex_);
+  pending_notification_map_[std::string(String8(device_address).string())] =
+      false;
+
+  return Status::ok();
+}
+
+Status HeartRateServer::OnConnectionStateChanged(const String16& device_address,
+                                                 bool connected) {
+  LOG(INFO) << "Connection state changed - device: " << device_address
+            << " connected: " << (connected? "true" : "false");
+  return Status::ok();
+}
+}  // namespace heart_rate
diff --git a/bt/service/example/heart_rate/heart_rate_server.h b/bt/service/example/heart_rate/heart_rate_server.h
new file mode 100644
index 0000000..b247653
--- /dev/null
+++ b/bt/service/example/heart_rate/heart_rate_server.h
@@ -0,0 +1,141 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <base/macros.h>
+#include <base/memory/ref_counted.h>
+#include <base/memory/weak_ptr.h>
+#include <base/single_thread_task_runner.h>
+
+#include <android/bluetooth/BnBluetoothGattServerCallback.h>
+#include <android/bluetooth/IBluetooth.h>
+
+using android::binder::Status;
+using android::String16;
+
+namespace heart_rate {
+
+// Implements an example GATT Heart Rate service. This class emulates the
+// behavior of a heart rate service by sending fake heart-rate pulses.
+class HeartRateServer
+    : public android::bluetooth::BnBluetoothGattServerCallback {
+ public:
+  HeartRateServer(android::sp<android::bluetooth::IBluetooth> bluetooth,
+                  scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+                  bool advertise);
+  ~HeartRateServer() override;
+
+  // Set up the server and register the GATT services with the stack. This
+  // initiates a set of asynchronous procedures. Invokes |callback|
+  // asynchronously with the result of the operation.
+  using RunCallback = std::function<void(bool success)>;
+  bool Run(const RunCallback& callback);
+
+ private:
+  // Helpers for posting heart rate measurement notifications.
+  void ScheduleNextMeasurement();
+  void SendHeartRateMeasurement();
+  void BuildHeartRateMeasurementValue(std::vector<uint8_t>* out_value);
+
+  // ipc::binder::IBluetoothGattServerCallback override:
+  Status OnServerRegistered(int status, int server_id) override;
+  Status OnServiceAdded(
+      int status, const android::bluetooth::BluetoothGattService& service) override;
+  Status OnCharacteristicReadRequest(
+      const String16& device_address, int request_id, int offset, bool is_long,
+      int handle) override;
+  Status OnDescriptorReadRequest(
+      const String16& device_address, int request_id, int offset, bool is_long,
+      int handle) override;
+  Status OnCharacteristicWriteRequest(
+      const String16& device_address, int request_id, int offset,
+      bool is_prepare_write, bool need_response,
+      const std::vector<uint8_t>& value, int handle) override;
+  Status OnDescriptorWriteRequest(
+      const String16& device_address, int request_id, int offset,
+      bool is_prepare_write, bool need_response,
+      const std::vector<uint8_t>& value, int handle) override;
+  Status OnExecuteWriteRequest(const String16& device_address, int request_id,
+                               bool is_execute) override;
+  Status OnNotificationSent(const String16& device_address,
+                            int status) override;
+  Status OnConnectionStateChanged(const String16& device_address,
+                                  bool connected) override;
+
+  // Single mutex to protect all variables below.
+  std::mutex mutex_;
+
+  // This stores whether or not at least one remote device has written to the
+  // CCC descriptor.
+  bool simulation_started_;
+
+  // The IBluetooth and IBluetoothGattServer binders that we use to communicate
+  // with the Bluetooth daemon's GATT server features.
+  android::sp<android::bluetooth::IBluetooth> bluetooth_;
+  android::sp<android::bluetooth::IBluetoothGattServer> gatt_;
+
+  // ID assigned to us by the daemon to operate on our dedicated GATT server
+  // instance.
+  int server_if_;
+
+  // Callback passed to Run(). We use this to tell main that all attributes have
+  // been registered with the daemon.
+  RunCallback pending_run_cb_;
+
+  // Stores whether or not an outgoing notification is still pending. We use
+  // this to throttle notifications so that we don't accidentally congest the
+  // connection.
+  std::unordered_map<std::string, bool> pending_notification_map_;
+
+  // The current HR notification count.
+  int hr_notification_count_;
+
+  // The Energy Expended value we use in our notifications.
+  uint16_t energy_expended_;
+
+  // Handles that refer to Heart Rate Service GATT objects.
+  // These returned to us from the Bluetooth daemon as we populate the database.
+  uint16_t hr_service_handle_;
+  uint16_t hr_measurement_handle_;
+  uint16_t hr_measurement_cccd_handle_;
+  uint16_t body_sensor_loc_handle_;
+  uint16_t hr_control_point_handle_;
+
+  // The daemon itself doesn't maintain a Client Characteristic Configuration
+  // mapping, so we do it ourselves here.
+  std::unordered_map<std::string, uint8_t> device_ccc_map_;
+
+  // Wether we should also start advertising
+  bool advertise_;
+
+  // libchrome task runner that we use to post heart rate measurement
+  // notifications on the main thread.
+  scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+
+  // We use this to pass weak_ptr's to base::Bind, which won't execute if the
+  // HeartRateServer object gets deleted. This is a convenience utility from
+  // libchrome and we use it here since base::TaskRunner uses base::Callback.
+  // Note: This should remain the last member so that it'll be destroyed and
+  // invalidate its weak pointers before any other members are destroyed.
+  base::WeakPtrFactory<HeartRateServer> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(HeartRateServer);
+};
+
+}  // namespace heart_rate
diff --git a/bt/service/example/heart_rate/server_main.cc b/bt/service/example/heart_rate/server_main.cc
new file mode 100644
index 0000000..c7477f5
--- /dev/null
+++ b/bt/service/example/heart_rate/server_main.cc
@@ -0,0 +1,164 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+
+#ifdef BT_LIBCHROME_NDEBUG
+#define NDEBUG 1
+#endif
+
+#include <base/at_exit.h>
+#include <base/bind.h>
+#include <base/command_line.h>
+#include <base/location.h>
+#include <base/logging.h>
+#include <base/message_loop/message_loop.h>
+#include <base/run_loop.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include <android/bluetooth/IBluetooth.h>
+
+#include "service/example/heart_rate/heart_rate_server.h"
+
+using android::sp;
+using android::OK;
+using android::bluetooth::IBluetooth;
+
+using android::getService;
+
+namespace {
+
+std::string kServiceName = "bluetooth-service";
+
+void QuitMessageLoop() {
+  // I don't know why both of these calls are necessary but the message loop
+  // doesn't stop unless I call both. Bug in base::MessageLoop?
+  base::RunLoop().Quit();
+  base::MessageLoop::current()->QuitNow();
+}
+
+// Handles the case where the Bluetooth process dies.
+class BluetoothDeathRecipient : public android::IBinder::DeathRecipient {
+ public:
+  explicit BluetoothDeathRecipient(
+      scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
+      : main_task_runner_(main_task_runner) {}
+
+  ~BluetoothDeathRecipient() override = default;
+
+  // android::IBinder::DeathRecipient override:
+  void binderDied(const android::wp<android::IBinder>& /* who */) override {
+    LOG(ERROR) << "The Bluetooth daemon has died. Aborting.";
+
+    // binderDied executes on a dedicated thread. We need to stop the main loop
+    // on the main thread so we post a message to it here. The main loop only
+    // runs on the main thread.
+    main_task_runner_->PostTask(FROM_HERE, base::Bind(&QuitMessageLoop));
+
+    android::IPCThreadState::self()->stopProcess();
+  }
+
+ private:
+  scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+};
+
+}  // namespace
+
+int main(int argc, char* argv[]) {
+  base::AtExitManager exit_manager;
+  base::CommandLine::Init(argc, argv);
+  logging::LoggingSettings log_settings;
+
+  // Initialize global logging based on command-line parameters (this is a
+  // libchrome pattern).
+  if (!logging::InitLogging(log_settings)) {
+    LOG(ERROR) << "Failed to set up logging";
+    return EXIT_FAILURE;
+  }
+
+  // Set up a message loop so that we can schedule timed Heart Rate
+  // notifications.
+  base::MessageLoop main_loop;
+
+  LOG(INFO) << "Starting GATT Heart Rate Service sample";
+
+  sp<IBluetooth> bluetooth;
+  status_t status = getService(String16(kServiceName.c_str()), &bluetooth);
+  if (status != OK) {
+    LOG(ERROR) << "Failed to get service binder: '" << kServiceName
+               << "' status=" << status;
+    return EXIT_FAILURE;
+  }
+
+  // Bluetooth needs to be enabled for our demo to work.
+  bool enabled;
+  bluetooth->IsEnabled(&enabled);
+  if (!enabled) {
+    LOG(ERROR) << "Bluetooth is not enabled.";
+    return EXIT_FAILURE;
+  }
+
+  // Register for death notifications on the IBluetooth binder. This let's us
+  // handle the case where the Bluetooth daemon process (bluetoothtbd) dies
+  // outside of our control.
+  sp<BluetoothDeathRecipient> dr(
+      new BluetoothDeathRecipient(main_loop.task_runner()));
+  if (android::IInterface::asBinder(bluetooth.get())->linkToDeath(dr) !=
+      android::NO_ERROR) {
+    LOG(ERROR) << "Failed to register DeathRecipient for IBluetooth";
+    return EXIT_FAILURE;
+  }
+
+  // Initialize the Binder process thread pool. We have to set this up,
+  // otherwise, incoming callbacks from the Bluetooth daemon would block the
+  // main thread (in other words, we have to do this as we are a "Binder
+  // server").
+  android::ProcessState::self()->startThreadPool();
+
+  // heart_rate::HeartRateServer notifies success or failure asynchronously
+  // using a closure, so we set up a lambda for that here.
+  auto callback = [&](bool success) {
+    if (success) {
+      LOG(INFO) << "Heart Rate service started successfully";
+      return;
+    }
+
+    LOG(ERROR) << "Starting Heart Rate server failed asynchronously";
+    main_loop.QuitWhenIdle();
+  };
+
+  bool advertise =
+      base::CommandLine::ForCurrentProcess()->HasSwitch("advertise");
+
+  // Create the Heart Rate server.
+  std::unique_ptr<heart_rate::HeartRateServer> hr(
+      new heart_rate::HeartRateServer(bluetooth, main_loop.task_runner(),
+                                      advertise));
+  if (!hr->Run(callback)) {
+    LOG(ERROR) << "Failed to start Heart Rate server";
+    return EXIT_FAILURE;
+  }
+
+  // Run the main loop on the main process thread. Binder callbacks will be
+  // received in dedicated threads set up by the ProcessState::startThreadPool
+  // call above but we use this main loop for sending out heart rate
+  // notifications.
+  main_loop.Run();
+
+  LOG(INFO) << "Exiting";
+  return EXIT_SUCCESS;
+}
diff --git a/bt/service/gatt_client.cc b/bt/service/gatt_client.cc
new file mode 100644
index 0000000..a8f48c8
--- /dev/null
+++ b/bt/service/gatt_client.cc
@@ -0,0 +1,111 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/gatt_client.h"
+
+#include <base/logging.h>
+
+using std::lock_guard;
+using std::mutex;
+
+namespace bluetooth {
+
+// GattClient implementation
+// ========================================================
+
+GattClient::GattClient(const UUID& uuid, int client_id)
+    : app_identifier_(uuid),
+      client_id_(client_id) {
+}
+
+GattClient::~GattClient() {
+  // Automatically unregister the client.
+  VLOG(1) << "GattClient unregistering client: " << client_id_;
+
+  hal::BluetoothGattInterface::Get()->GetClientHALInterface()->
+      unregister_client(client_id_);
+}
+
+const UUID& GattClient::GetAppIdentifier() const {
+  return app_identifier_;
+}
+
+int GattClient::GetInstanceId() const {
+  return client_id_;
+}
+
+// GattClientFactory implementation
+// ========================================================
+
+GattClientFactory::GattClientFactory() {
+  hal::BluetoothGattInterface::Get()->AddClientObserver(this);
+}
+
+GattClientFactory::~GattClientFactory() {
+  hal::BluetoothGattInterface::Get()->RemoveClientObserver(this);
+}
+
+bool GattClientFactory::RegisterInstance(
+    const UUID& uuid,
+    const RegisterCallback& callback) {
+  VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+  lock_guard<mutex> lock(pending_calls_lock_);
+
+  if (pending_calls_.find(uuid) != pending_calls_.end()) {
+    LOG(ERROR) << "GATT client with given UUID already registered - "
+               << "UUID: " << uuid.ToString();
+    return false;
+  }
+
+  const btgatt_client_interface_t* hal_iface =
+      hal::BluetoothGattInterface::Get()->GetClientHALInterface();
+  bt_uuid_t app_uuid = uuid.GetBlueDroid();
+
+  if (hal_iface->register_client(&app_uuid) != BT_STATUS_SUCCESS)
+    return false;
+
+  pending_calls_[uuid] = callback;
+
+  return true;
+}
+
+void GattClientFactory::RegisterClientCallback(
+    hal::BluetoothGattInterface* /* gatt_iface */,
+    int status, int client_id,
+    const bt_uuid_t& app_uuid) {
+  UUID uuid(app_uuid);
+
+  auto iter = pending_calls_.find(uuid);
+  if (iter == pending_calls_.end()) {
+    VLOG(1) << "Ignoring callback for unknown app_id: " << uuid.ToString();
+    return;
+  }
+
+  bool success = (status == BT_STATUS_SUCCESS);
+  BLEStatus result = success ? BLE_STATUS_SUCCESS : BLE_STATUS_FAILURE;
+
+  // No need to construct a client if the call wasn't successful.
+  std::unique_ptr<GattClient> client;
+  if (success)
+    client.reset(new GattClient(uuid, client_id));
+
+  // Notify the result via the result callback.
+  iter->second(result, uuid, std::move(client));
+
+  pending_calls_.erase(iter);
+}
+
+}  // namespace bluetooth
diff --git a/bt/service/gatt_client.h b/bt/service/gatt_client.h
new file mode 100644
index 0000000..eb94405
--- /dev/null
+++ b/bt/service/gatt_client.h
@@ -0,0 +1,84 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <mutex>
+#include <unordered_map>
+
+#include <base/macros.h>
+
+#include "service/bluetooth_instance.h"
+#include "service/common/bluetooth/uuid.h"
+#include "service/hal/bluetooth_gatt_interface.h"
+
+namespace bluetooth {
+
+// A GattClient instance represents an application's handle to perform GATT
+// client-role operations. Instances cannot be created directly and should be
+// obtained through the factory.
+class GattClient : public BluetoothInstance {
+ public:
+  ~GattClient() override;
+
+  // BluetoothClientInstace overrides:
+  const UUID& GetAppIdentifier() const override;
+  int GetInstanceId() const override;
+
+ private:
+  friend class GattClientFactory;
+
+  // Constructor shouldn't be called directly as instances are meant to be
+  // obtained from the factory.
+  GattClient(const UUID& uuid, int client_id);
+
+  // See getters above for documentation.
+  UUID app_identifier_;
+  int client_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(GattClient);
+};
+
+// GattClientFactory is used to register and obtain a per-application GattClient
+// instance. Users should call RegisterClient to obtain their own unique
+// GattClient instance that has been registered with the Bluetooth stack.
+class GattClientFactory : public BluetoothInstanceFactory,
+                          private hal::BluetoothGattInterface::ClientObserver {
+ public:
+  // Don't construct/destruct directly except in tests. Instead, obtain a handle
+  // from an Adapter instance.
+  GattClientFactory();
+  ~GattClientFactory() override;
+
+  // BluetoothInstanceFactory override:
+  bool RegisterInstance(const UUID& uuid,
+                        const RegisterCallback& callback) override;
+
+ private:
+  // hal::BluetoothGattInterface::ClientObserver override:
+  void RegisterClientCallback(
+      hal::BluetoothGattInterface* gatt_iface,
+      int status, int client_id,
+      const bt_uuid_t& app_uuid) override;
+
+  // Map of pending calls to register.
+  std::mutex pending_calls_lock_;
+  std::unordered_map<UUID, RegisterCallback> pending_calls_;
+
+  DISALLOW_COPY_AND_ASSIGN(GattClientFactory);
+};
+
+}  // namespace bluetooth
diff --git a/bt/service/gatt_server.cc b/bt/service/gatt_server.cc
new file mode 100644
index 0000000..efedbf0
--- /dev/null
+++ b/bt/service/gatt_server.cc
@@ -0,0 +1,696 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/gatt_server.h"
+
+#include "service/common/bluetooth/util/address_helper.h"
+#include "service/logging_helpers.h"
+
+using std::lock_guard;
+using std::mutex;
+
+namespace bluetooth {
+
+namespace {
+
+bool operator==(const bt_bdaddr_t& lhs, const bt_bdaddr_t& rhs) {
+  return memcmp(&lhs, &rhs, sizeof(lhs)) == 0;
+}
+
+bool operator!=(const bt_bdaddr_t& lhs, const bt_bdaddr_t& rhs) {
+  return !(lhs == rhs);
+}
+
+}  // namespace
+
+// GattServer implementation
+// ========================================================
+
+GattServer::GattServer(const UUID& uuid, int server_id)
+    : app_identifier_(uuid),
+      server_id_(server_id),
+      delegate_(nullptr) {
+}
+
+GattServer::~GattServer() {
+  // Automatically unregister the server.
+  VLOG(1) << "GattServer unregistering: " << server_id_;
+
+  // Unregister as observer so we no longer receive any callbacks.
+  hal::BluetoothGattInterface::Get()->RemoveServerObserver(this);
+
+  // Unregister this server, stop all services, and ignore the result.
+  // TODO(armansito): stop and remove all services here? unregister_server
+  // should really take care of that.
+  hal::BluetoothGattInterface::Get()->
+      GetServerHALInterface()->unregister_server(server_id_);
+}
+
+void GattServer::SetDelegate(Delegate* delegate) {
+  lock_guard<mutex> lock(mutex_);
+  delegate_ = delegate;
+}
+
+const UUID& GattServer::GetAppIdentifier() const {
+  return app_identifier_;
+}
+
+int GattServer::GetInstanceId() const {
+  return server_id_;
+}
+
+bool GattServer::AddService(
+    const bluetooth::Service& service, const ResultCallback& callback) {
+  VLOG(1) << __func__ << " server_id: " << server_id_;
+  lock_guard<mutex> lock(mutex_);
+
+  if (!callback) {
+    LOG(ERROR) << "|callback| cannot be NULL";
+    return false;
+  }
+
+  std::vector<btgatt_db_element_t> svc;
+
+  svc.push_back({.type = (service.primary() ? BTGATT_DB_PRIMARY_SERVICE : BTGATT_DB_SECONDARY_SERVICE),
+           .uuid = service.uuid().GetBlueDroid()});
+
+  for (const auto &  characteristic : service.characteristics()) {
+    svc.push_back({.type = BTGATT_DB_CHARACTERISTIC,
+             .uuid = characteristic.uuid().GetBlueDroid(),
+             .properties = characteristic.properties(),
+             .permissions = characteristic.permissions()
+           });
+    for (const auto &  descriptor : characteristic.descriptors())
+      svc.push_back({.type = BTGATT_DB_DESCRIPTOR,
+               .uuid = descriptor.uuid().GetBlueDroid(),
+               .permissions = descriptor.permissions()
+             });
+  }
+
+  for (const auto &  incl_svc : service.included_services())
+    svc.push_back({.type = BTGATT_DB_INCLUDED_SERVICE,
+             .attribute_handle = incl_svc.handle() });
+
+  pending_end_decl_cb_ = callback;
+
+  bt_status_t status = hal::BluetoothGattInterface::Get()->
+      GetServerHALInterface()->add_service(server_id_, svc);
+  if (status != BT_STATUS_SUCCESS) {
+    LOG(ERROR) << "Failed to initiate call to populate GATT service";
+    CleanUpPendingData();
+    return false;
+  }
+
+  return true;
+}
+
+bool GattServer::SendResponse(
+    const std::string& device_address, int request_id,
+    GATTError error, int offset,
+    const std::vector<uint8_t>& value) {
+  VLOG(1) << __func__ << " - server_id: " << server_id_
+          << " device_address: " << device_address
+          << " request_id: " << request_id
+          << " error: " << error
+          << " offset: " << offset;
+  lock_guard<mutex> lock(mutex_);
+
+  bt_bdaddr_t addr;
+  if (!util::BdAddrFromString(device_address, &addr)) {
+    LOG(ERROR) << "Invalid device address given: " << device_address;
+    return false;
+  }
+
+  if (value.size() + offset > BTGATT_MAX_ATTR_LEN) {
+    LOG(ERROR) << "Value is too large";
+    return false;
+  }
+
+  // Find the correct connection ID for |device_address| and |request_id|.
+  auto iter = conn_addr_map_.find(device_address);
+  if (iter == conn_addr_map_.end()) {
+    LOG(ERROR) << "No known connections for device address: " << device_address;
+    return false;
+  }
+
+  std::shared_ptr<Connection> connection;
+  for (const auto& tmp : iter->second) {
+    if (tmp->request_id_to_handle.find(request_id) ==
+        tmp->request_id_to_handle.end())
+      continue;
+
+    connection = tmp;
+  }
+
+  if (!connection) {
+    LOG(ERROR) << "Pending request with ID " << request_id
+               << " not found for device with BD_ADDR: " << device_address;
+    return false;
+  }
+
+  btgatt_response_t response;
+  memset(&response, 0, sizeof(response));
+
+  // We keep -1 as the handle for "Execute Write Request". In that case,
+  // there is no need to populate the response data. Just send zeros back.
+  int handle = connection->request_id_to_handle[request_id];
+  response.handle = handle;
+  response.attr_value.handle = handle;
+  if (handle != -1) {
+    memcpy(response.attr_value.value, value.data(), value.size());
+    response.attr_value.offset = offset;
+    response.attr_value.len = value.size();
+  }
+
+  bt_status_t result = hal::BluetoothGattInterface::Get()->
+      GetServerHALInterface()->send_response(
+          connection->conn_id, request_id, error, &response);
+  if (result != BT_STATUS_SUCCESS) {
+    LOG(ERROR) << "Failed to initiate call to send GATT response";
+    return false;
+  }
+
+  connection->request_id_to_handle.erase(request_id);
+
+  return true;
+}
+
+bool GattServer::SendNotification(
+    const std::string& device_address,
+    const uint16_t handle,
+    bool confirm,
+    const std::vector<uint8_t>& value,
+    const GattCallback& callback) {
+  VLOG(1) << " - server_id: " << server_id_
+          << " device_address: " << device_address
+          << " confirm: " << confirm;
+  lock_guard<mutex> lock(mutex_);
+
+  bt_bdaddr_t addr;
+  if (!util::BdAddrFromString(device_address, &addr)) {
+    LOG(ERROR) << "Invalid device address given: " << device_address;
+    return false;
+  }
+
+  // Get the connection IDs for which we will send this notification.
+  auto conn_iter = conn_addr_map_.find(device_address);
+  if (conn_iter == conn_addr_map_.end()) {
+    LOG(ERROR) << "No known connections for device with address: "
+               << device_address;
+    return false;
+  }
+
+  std::shared_ptr<PendingIndication> pending_ind(
+      new PendingIndication(callback));
+
+  if (conn_iter->second.size() == 0) {
+      LOG(ERROR) << "Empty conneciton list.";
+  }
+
+  // Send the notification/indication on all matching connections.
+  int send_count = 0;
+  for (const auto& conn : conn_iter->second) {
+    // Make sure that one isn't already pending for this connection.
+    if (pending_indications_.find(conn->conn_id) !=
+        pending_indications_.end()) {
+      LOG(ERROR) << "A" << (confirm ? "n indication" : " notification")
+              << " is already pending for connection: " << conn->conn_id;
+      continue;
+    }
+
+    // The HAL API takes char* rather const char* for |value|, so we have to
+    // cast away the const.
+    // TODO(armansito): Make HAL accept const char*.
+    bt_status_t status = hal::BluetoothGattInterface::Get()->
+        GetServerHALInterface()->send_indication(
+            server_id_,
+            handle,
+            conn->conn_id,
+            confirm,
+            value);
+
+    // Increment the send count if this was successful. We don't immediately
+    // fail if the HAL returned an error. It's better to report success as long
+    // as we sent out at least one notification to this device as
+    // multi-transport GATT connections from the same BD_ADDR will be rare
+    // enough already.
+    if (status != BT_STATUS_SUCCESS) {
+      LOG(ERROR) << "HAL returned error when sending " << (confirm ? "indication" : " notification")
+              << " for connection: " << conn->conn_id;
+      continue;
+    }
+
+    send_count++;
+    pending_indications_[conn->conn_id] = pending_ind;
+  }
+
+  if (send_count == 0) {
+    LOG(ERROR) << "Failed to send notifications/indications to device: "
+               << device_address;
+    return false;
+  }
+
+  return true;
+}
+
+void GattServer::ConnectionCallback(
+    hal::BluetoothGattInterface* /* gatt_iface */,
+    int conn_id, int server_id,
+    int connected,
+    const bt_bdaddr_t& bda) {
+  lock_guard<mutex> lock(mutex_);
+
+  if (server_id != server_id_)
+    return;
+
+  std::string device_address = BtAddrString(&bda);
+
+  VLOG(1) << __func__ << " conn_id: " << conn_id << " connected: " << connected
+          << " BD_ADDR: " << device_address;
+
+  if (!connected) {
+    // Erase the entry if we were connected to it.
+    VLOG(1) << "No longer connected: " << device_address;
+    conn_id_map_.erase(conn_id);
+    auto iter = conn_addr_map_.find(device_address);
+    if (iter == conn_addr_map_.end())
+      return;
+
+    // Remove the appropriate connection objects in the address.
+    for (auto conn_iter = iter->second.begin(); conn_iter != iter->second.end();
+         ++conn_iter) {
+      if ((*conn_iter)->conn_id != conn_id)
+        continue;
+
+      iter->second.erase(conn_iter);
+      break;
+    }
+
+    // clear any pending indications
+    const auto& pending_ind_iter = pending_indications_.find(conn_id);
+    if (pending_ind_iter != pending_indications_.end()) {
+        LOG(WARNING) << "Cleaning up pending indication";
+        pending_indications_.erase(pending_ind_iter);
+    }
+
+
+    if (delegate_)
+      delegate_->OnConnectionStateChanged(this, device_address, false);
+
+    return;
+  }
+
+  if (conn_id_map_.find(conn_id) != conn_id_map_.end()) {
+    LOG(WARNING) << "Connection entry already exists; "
+                 << "ignoring ConnectionCallback";
+    return;
+  }
+
+  LOG(INFO) << "Added connection entry for conn_id: " << conn_id
+            << " device address: " << device_address;
+  std::shared_ptr<Connection> connection(new Connection(conn_id, bda));
+  conn_id_map_[conn_id] = connection;
+  conn_addr_map_[device_address].push_back(connection);
+
+  if (delegate_)
+    delegate_->OnConnectionStateChanged(this, device_address, true);
+}
+
+void GattServer::ServiceAddedCallback(
+    hal::BluetoothGattInterface* gatt_iface,
+    int status, int server_id,
+    vector<btgatt_db_element_t> svc) {
+  lock_guard<mutex> lock(mutex_);
+
+  if (server_id != server_id_)
+    return;
+
+  VLOG(1) << __func__ << " - status: " << status
+          << " server_id: " << server_id
+          << " first handle: " << svc[0].attribute_handle
+          << " service UUID: " << UUID(svc[0].uuid).ToString()
+          << " count: " << svc.size();
+
+  Service service(svc[0].attribute_handle, true, UUID(svc[0].uuid), {}, {});
+
+  for (size_t i=1; i<svc.size(); i++) {
+    const btgatt_db_element_t &curr = svc[i];
+    VLOG(1) << " - processing item no: " << i << " handle: " << curr.attribute_handle;
+    if (curr.type == BTGATT_DB_CHARACTERISTIC) {
+      service.characteristics().push_back({curr.attribute_handle, UUID(curr.uuid), curr.properties, curr.permissions, {}});
+    } else if (curr.type == BTGATT_DB_DESCRIPTOR) {
+      service.characteristics().back().descriptors().push_back({curr.attribute_handle, UUID(curr.uuid), curr.permissions});
+    } else if (svc[i].type == BTGATT_DB_INCLUDED_SERVICE) {
+    }
+  }
+
+  pending_end_decl_cb_((bluetooth::BLEStatus)status, service);
+
+  CleanUpPendingData();
+
+}
+
+void GattServer::ServiceStoppedCallback(
+    hal::BluetoothGattInterface* /* gatt_iface */,
+    int /* status */,
+    int /* server_id */,
+    int /* service_handle */) {
+  // TODO(armansito): Support stopping a service.
+}
+
+void GattServer::RequestReadCharacteristicCallback(
+    hal::BluetoothGattInterface* /* gatt_iface */,
+    int conn_id, int trans_id,
+    const bt_bdaddr_t& bda,
+    int attribute_handle, int offset,
+    bool is_long) {
+  lock_guard<mutex> lock(mutex_);
+
+  // Check to see if we know about this connection. Otherwise ignore the
+  // request.
+  auto conn = GetConnection(conn_id, bda, trans_id);
+  if (!conn)
+    return;
+
+  std::string device_address = BtAddrString(&bda);
+
+  VLOG(1) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+          << " BD_ADDR: " << device_address
+          << " attribute_handle: " << attribute_handle << " offset: " << offset
+          << " is_long: " << is_long;
+
+  conn->request_id_to_handle[trans_id] = attribute_handle;
+
+  // If there is no delegate then there is nobody to handle request. The request
+  // will eventually timeout and we should get a connection update that
+  // terminates the connection.
+  if (!delegate_) {
+    // TODO(armansito): Require a delegate at server registration so that this
+    // is never possible.
+    LOG(WARNING) << "No delegate was assigned to GattServer. Incoming request "
+                 << "will time out.";
+    return;
+  }
+
+  delegate_->OnCharacteristicReadRequest(
+      this, device_address, trans_id, offset, is_long, attribute_handle);
+}
+void GattServer::RequestReadDescriptorCallback(
+    hal::BluetoothGattInterface* /* gatt_iface */,
+    int conn_id, int trans_id,
+    const bt_bdaddr_t& bda,
+    int attribute_handle, int offset,
+    bool is_long) {
+  lock_guard<mutex> lock(mutex_);
+
+  // Check to see if we know about this connection. Otherwise ignore the
+  // request.
+  auto conn = GetConnection(conn_id, bda, trans_id);
+  if (!conn)
+    return;
+
+  std::string device_address = BtAddrString(&bda);
+
+  VLOG(1) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+          << " BD_ADDR: " << device_address
+          << " attribute_handle: " << attribute_handle << " offset: " << offset
+          << " is_long: " << is_long;
+
+  conn->request_id_to_handle[trans_id] = attribute_handle;
+
+  // If there is no delegate then there is nobody to handle request. The request
+  // will eventually timeout and we should get a connection update that
+  // terminates the connection.
+  if (!delegate_) {
+    // TODO(armansito): Require a delegate at server registration so that this
+    // is never possible.
+    LOG(WARNING) << "No delegate was assigned to GattServer. Incoming request "
+                 << "will time out.";
+    return;
+  }
+
+  delegate_->OnDescriptorReadRequest(
+      this, device_address, trans_id, offset, is_long, attribute_handle);
+}
+
+void GattServer::RequestWriteCharacteristicCallback(
+    hal::BluetoothGattInterface* /* gatt_iface */,
+    int conn_id, int trans_id,
+    const bt_bdaddr_t& bda,
+    int attr_handle, int offset,
+    bool need_rsp, bool is_prep,
+    vector<uint8_t> value) {
+  lock_guard<mutex> lock(mutex_);
+
+  // Check to see if we know about this connection. Otherwise ignore the
+  // request.
+  auto conn = GetConnection(conn_id, bda, trans_id);
+  if (!conn)
+    return;
+
+  std::string device_address = BtAddrString(&bda);
+
+  VLOG(1) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+          << " BD_ADDR: " << device_address
+          << " attr_handle: " << attr_handle << " offset: " << offset
+          << " length: " << value.size() << " need_rsp: " << need_rsp
+          << " is_prep: " << is_prep;
+
+  // Store the request ID only if this is not a write-without-response. If
+  // another request occurs after this with the same request ID, then we'll
+  // simply process it normally, though that shouldn't ever happen.
+  if (need_rsp)
+    conn->request_id_to_handle[trans_id] = attr_handle;
+
+  // If there is no delegate then there is nobody to handle request. The request
+  // will eventually timeout and we should get a connection update that
+  // terminates the connection.
+  if (!delegate_) {
+    // TODO(armansito): Require a delegate at server registration so that this
+    // is never possible.
+    LOG(WARNING) << "No delegate was assigned to GattServer. Incoming request "
+                 << "will time out.";
+    return;
+  }
+
+  delegate_->OnCharacteristicWriteRequest(
+      this, device_address, trans_id, offset, is_prep, need_rsp,
+      std::move(value), attr_handle);
+}
+
+void GattServer::RequestWriteDescriptorCallback(
+    hal::BluetoothGattInterface* /* gatt_iface */,
+    int conn_id, int trans_id,
+    const bt_bdaddr_t& bda,
+    int attr_handle, int offset,
+    bool need_rsp, bool is_prep,
+    vector<uint8_t> value) {
+  lock_guard<mutex> lock(mutex_);
+
+  // Check to see if we know about this connection. Otherwise ignore the
+  // request.
+  auto conn = GetConnection(conn_id, bda, trans_id);
+  if (!conn)
+    return;
+
+  std::string device_address = BtAddrString(&bda);
+
+  VLOG(1) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+          << " BD_ADDR: " << device_address
+          << " attr_handle: " << attr_handle << " offset: " << offset
+          << " length: " << value.size() << " need_rsp: " << need_rsp
+          << " is_prep: " << is_prep;
+
+  // Store the request ID only if this is not a write-without-response. If
+  // another request occurs after this with the same request ID, then we'll
+  // simply process it normally, though that shouldn't ever happen.
+  if (need_rsp)
+    conn->request_id_to_handle[trans_id] = attr_handle;
+
+  // If there is no delegate then there is nobody to handle request. The request
+  // will eventually timeout and we should get a connection update that
+  // terminates the connection.
+  if (!delegate_) {
+    // TODO(armansito): Require a delegate at server registration so that this
+    // is never possible.
+    LOG(WARNING) << "No delegate was assigned to GattServer. Incoming request "
+                 << "will time out.";
+    return;
+  }
+
+  delegate_->OnDescriptorWriteRequest(
+      this, device_address, trans_id, offset, is_prep, need_rsp,
+      std::move(value), attr_handle);
+}
+
+void GattServer::RequestExecWriteCallback(
+    hal::BluetoothGattInterface* /* gatt_iface */,
+    int conn_id, int trans_id,
+    const bt_bdaddr_t& bda, int exec_write) {
+  lock_guard<mutex> lock(mutex_);
+
+  // Check to see if we know about this connection. Otherwise ignore the
+  // request.
+  auto conn = GetConnection(conn_id, bda, trans_id);
+  if (!conn)
+    return;
+
+  std::string device_address = BtAddrString(&bda);
+
+  VLOG(1) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+          << " BD_ADDR: " << device_address << " exec_write: " << exec_write;
+
+  // Just store a dummy invalid handle as this request doesn't apply to a
+  // specific handle.
+  conn->request_id_to_handle[trans_id] = -1;
+
+  // If there is no delegate then there is nobody to handle request. The request
+  // will eventually timeout and we should get a connection update that
+  // terminates the connection.
+  if (!delegate_) {
+    // TODO(armansito): Require a delegate at server registration so that this
+    // is never possible.
+    LOG(WARNING) << "No delegate was assigned to GattServer. Incoming request "
+                 << "will time out.";
+    return;
+  }
+
+  delegate_->OnExecuteWriteRequest(this, device_address, trans_id, exec_write);
+}
+
+void GattServer::IndicationSentCallback(
+    hal::BluetoothGattInterface* /* gatt_iface */,
+    int conn_id, int status) {
+  VLOG(1) << __func__ << " conn_id: " << conn_id << " status: " << status;
+  lock_guard<mutex> lock(mutex_);
+
+  const auto& pending_ind_iter = pending_indications_.find(conn_id);
+  if (pending_ind_iter == pending_indications_.end()) {
+    VLOG(1) << "Unknown connection: " << conn_id;
+    return;
+  }
+
+  std::shared_ptr<PendingIndication> pending_ind = pending_ind_iter->second;
+  pending_indications_.erase(pending_ind_iter);
+
+  if (status == BT_STATUS_SUCCESS)
+    pending_ind->has_success = true;
+
+  // Invoke it if this was the last reference to the confirmation callback.
+  if (pending_ind.unique() && pending_ind->callback) {
+    pending_ind->callback(
+        pending_ind->has_success ?
+        GATT_ERROR_NONE : static_cast<GATTError>(status));
+  }
+}
+
+void GattServer::CleanUpPendingData() {
+  pending_end_decl_cb_ = ResultCallback();
+}
+
+std::shared_ptr<GattServer::Connection> GattServer::GetConnection(
+    int conn_id, const bt_bdaddr_t& bda, int request_id) {
+  auto iter = conn_id_map_.find(conn_id);
+  if (iter == conn_id_map_.end()) {
+    VLOG(1) << "Connection doesn't belong to this server";
+    return nullptr;
+  }
+
+  auto conn = iter->second;
+  if (conn->bdaddr != bda) {
+    LOG(WARNING) << "BD_ADDR: " << BtAddrString(&bda) << " doesn't match "
+                 << "connection ID: " << conn_id;
+    return nullptr;
+  }
+
+  if (conn->request_id_to_handle.find(request_id) !=
+      conn->request_id_to_handle.end()) {
+    VLOG(1) << "Request with ID: " << request_id << " already exists for "
+            << " connection: " << conn_id;
+    return nullptr;
+  }
+
+  return conn;
+}
+
+// GattServerFactory implementation
+// ========================================================
+
+GattServerFactory::GattServerFactory() {
+  hal::BluetoothGattInterface::Get()->AddServerObserver(this);
+}
+
+GattServerFactory::~GattServerFactory() {
+  hal::BluetoothGattInterface::Get()->RemoveServerObserver(this);
+}
+
+bool GattServerFactory::RegisterInstance(
+    const UUID& uuid,
+    const RegisterCallback& callback) {
+  VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+  lock_guard<mutex> lock(pending_calls_lock_);
+
+  if (pending_calls_.find(uuid) != pending_calls_.end()) {
+    LOG(ERROR) << "GATT-server client with given UUID already being registered "
+               << " - UUID: " << uuid.ToString();
+    return false;
+  }
+
+  const btgatt_server_interface_t* hal_iface =
+      hal::BluetoothGattInterface::Get()->GetServerHALInterface();
+  bt_uuid_t app_uuid = uuid.GetBlueDroid();
+
+  if (hal_iface->register_server(&app_uuid) != BT_STATUS_SUCCESS)
+    return false;
+
+  pending_calls_[uuid] = callback;
+
+  return true;
+}
+
+void GattServerFactory::RegisterServerCallback(
+    hal::BluetoothGattInterface* gatt_iface,
+    int status, int server_id,
+    const bt_uuid_t& app_uuid) {
+  UUID uuid(app_uuid);
+
+  VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+  lock_guard<mutex> lock(pending_calls_lock_);
+
+  auto iter = pending_calls_.find(uuid);
+  if (iter == pending_calls_.end()) {
+    VLOG(1) << "Ignoring callback for unknown app_id: " << uuid.ToString();
+    return;
+  }
+
+  // No need to construct a server if the call wasn't successful.
+  std::unique_ptr<GattServer> server;
+  BLEStatus result = BLE_STATUS_FAILURE;
+  if (status == BT_STATUS_SUCCESS) {
+    server.reset(new GattServer(uuid, server_id));
+
+    gatt_iface->AddServerObserver(server.get());
+
+    result = BLE_STATUS_SUCCESS;
+  }
+
+  // Notify the result via the result callback.
+  iter->second(result, uuid, std::move(server));
+
+  pending_calls_.erase(iter);
+}
+
+}  // namespace bluetooth
diff --git a/bt/service/gatt_server.h b/bt/service/gatt_server.h
new file mode 100644
index 0000000..aa0be81
--- /dev/null
+++ b/bt/service/gatt_server.h
@@ -0,0 +1,317 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <functional>
+#include <mutex>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include <base/macros.h>
+
+#include "service/bluetooth_instance.h"
+#include "service/common/bluetooth/service.h"
+#include "service/common/bluetooth/uuid.h"
+#include "service/hal/bluetooth_gatt_interface.h"
+
+namespace bluetooth {
+
+// A GattServer instance represents an application's handle to perform GATT
+// server-role operations. Instances cannot be created directly and should be
+// obtained through the factory.
+class GattServer : public BluetoothInstance,
+                   private hal::BluetoothGattInterface::ServerObserver {
+ public:
+  // Delegate interface is used to handle incoming requests and confirmations
+  // for a GATT service.
+  class Delegate {
+   public:
+    Delegate() = default;
+    virtual ~Delegate() = default;
+
+    // Called when there is an incoming read request for the characteristic with
+    // ID |characteristic_id| from a remote device with address
+    // |device_address|. |request_id| can be used to respond to this request by
+    // calling SendResponse below.
+    virtual void OnCharacteristicReadRequest(
+        GattServer* gatt_server,
+        const std::string& device_address,
+        int request_id, int offset, bool is_long, uint16_t handle) = 0;
+
+    // Called when there is an incoming read request for the descriptor with
+    // ID |descriptor_id| from a remote device with address |device_address|.
+    // |request_id| can be used to respond to this request by
+    // calling SendResponse below.
+    virtual void OnDescriptorReadRequest(
+        GattServer* gatt_server,
+        const std::string& device_address,
+        int request_id, int offset, bool is_long, uint16_t handle) = 0;
+
+    // Called when there is an incoming write request for the characteristic
+    // with ID |characteristic_id| from a remote device with address
+    // |device_address|. |request_id| can be used to respond to this request by
+    // calling SendResponse, if the |need_response| parameter is true. Otherwise
+    // this is a "Write Without Reponse" procedure and SendResponse will fail.
+    // If |is_prepare_write| is true, then the write should not be committed
+    // immediately as this is a "Prepared Write Request". Instead, the Delegate
+    // should hold on to the value and either discard it or complete the write
+    // when it receives the OnExecuteWriteRequest event.
+    virtual void OnCharacteristicWriteRequest(
+        GattServer* gatt_server,
+        const std::string& device_address,
+        int request_id, int offset, bool is_prepare_write, bool need_response,
+        const std::vector<uint8_t>& value, uint16_t handle) = 0;
+
+    // Called when there is an incoming write request for the descriptor
+    // with ID |descriptor_id| from a remote device with address
+    // |device_address|. |request_id| can be used to respond to this request by
+    // calling SendResponse, if the |need_response| parameter is true. Otherwise
+    // this is a "Write Without Response" procedure and SendResponse will fail.
+    // If |is_prepare_write| is true, then the write should not be committed
+    // immediately as this is a "Prepared Write Request". Instead, the Delegate
+    // should hold on to the value and either discard it or complete the write
+    // when it receives the OnExecuteWriteRequest event.
+    virtual void OnDescriptorWriteRequest(
+        GattServer* gatt_server,
+        const std::string& device_address,
+        int request_id, int offset, bool is_prepare_write, bool need_response,
+        const std::vector<uint8_t>& value, uint16_t handle) = 0;
+
+    // Called when there is an incoming "Execute Write Request". If |is_execute|
+    // is true, then the Delegate should commit all previously prepared writes.
+    // Otherwise, all prepared writes should be aborted. The Delegate should
+    // call "SendResponse" to complete the procedure.
+    virtual void OnExecuteWriteRequest(
+        GattServer* gatt_server,
+        const std::string& device_address,
+        int request_id, bool is_execute) = 0;
+
+    virtual void OnConnectionStateChanged(
+        GattServer* gatt_server,
+        const std::string& device_addres,
+        bool connected) = 0;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Delegate);
+  };
+
+  // The desctructor automatically unregisters this instance from the stack.
+  ~GattServer() override;
+
+  // Assigns a delegate to this instance. |delegate| must out-live this
+  // GattServer instance.
+  void SetDelegate(Delegate* delegate);
+
+  // BluetoothClientInstace overrides:
+  const UUID& GetAppIdentifier() const override;
+  int GetInstanceId() const override;
+
+  // Callback type used to report the status of an asynchronous GATT server
+  // operation.
+  using ResultCallback =
+      std::function<void(BLEStatus status, const Service& id)>;
+  using GattCallback = std::function<void(GATTError error)>;
+
+  // Add service declaration. This method immediately
+  // returns false if a service hasn't been started. Otherwise, |callback| will
+  // be called asynchronously with the result of the operation.
+  //
+  // TODO(armansito): It is unclear to me what it means for this function to
+  // fail. What is the state that we're in? Is the service declaration over so
+  // we can add other services to this server instance? Do we need to clean up
+  // all the entries or does the upper-layer need to remove the service? Or are
+  // we in a stuck-state where the service declaration hasn't ended?
+  bool AddService(const bluetooth::Service&, const ResultCallback& callback);
+
+
+  // Sends a response for a pending notification. |request_id| and
+  // |device_address| should match those that were received through one of the
+  // Delegate callbacks. |value| and |offset| are used for read requests and
+  // prepare write requests and should match the value of the attribute. Returns
+  // false if the pending request could not be resolved using the given
+  // parameters or if the call to the underlying stack fails.
+  bool SendResponse(const std::string& device_address, int request_id,
+                    GATTError error, int offset,
+                    const std::vector<uint8_t>& value);
+
+  // Sends an ATT Handle-Value Notification to the device with BD_ADDR
+  // |device_address| for the characteristic with handle |handle| and
+  // value |value|. If |confirm| is true, then an ATT Handle-Value Indication
+  // will be sent instead, which requires the remote to confirm receipt. Returns
+  // false if there was an immediate error in initiating the notification
+  // procedure. Otherwise, returns true and reports the asynchronous result of
+  // the operation in |callback|.
+  //
+  // If |confirm| is true, then |callback| will be run when the remote device
+  // sends a ATT Handle-Value Confirmation packet. Otherwise, it will be run as
+  // soon as the notification has been sent out.
+  bool SendNotification(const std::string& device_address,
+                        const uint16_t handle,
+                        bool confirm, const std::vector<uint8_t>& value,
+                        const GattCallback& callback);
+
+ private:
+  friend class GattServerFactory;
+
+  // Used for the internal remote connection tracking. Keeps track of the
+  // request ID and the device address for the connection. If |request_id| is -1
+  // then no ATT read/write request is currently pending.
+  struct Connection {
+    Connection(int conn_id, const bt_bdaddr_t& bdaddr)
+        : conn_id(conn_id), bdaddr(bdaddr) {}
+    Connection() : conn_id(-1) {
+      memset(&bdaddr, 0, sizeof(bdaddr));
+    }
+
+    int conn_id;
+    std::unordered_map<int, int> request_id_to_handle;
+    bt_bdaddr_t bdaddr;
+  };
+
+  // Used to keep track of a pending Handle-Value indication.
+  struct PendingIndication {
+    explicit PendingIndication(const GattCallback& callback)
+        : has_success(false), callback(callback) {}
+
+    bool has_success;
+    GattCallback callback;
+  };
+
+  // Constructor shouldn't be called directly as instances are meant to be
+  // obtained from the factory.
+  GattServer(const UUID& uuid, int server_id);
+
+  // hal::BluetoothGattInterface::ServerObserver overrides:
+  void ConnectionCallback(
+      hal::BluetoothGattInterface* gatt_iface,
+      int conn_id, int server_id,
+      int connected,
+      const bt_bdaddr_t& bda) override;
+  void ServiceAddedCallback(
+      hal::BluetoothGattInterface* gatt_iface,
+      int status, int server_if,
+      vector<btgatt_db_element_t>) override;
+  void ServiceStoppedCallback(
+      hal::BluetoothGattInterface* gatt_iface,
+      int status, int server_id,
+      int service_handle) override;
+  void RequestReadCharacteristicCallback(
+      hal::BluetoothGattInterface* gatt_iface,
+      int conn_id, int trans_id,
+      const bt_bdaddr_t& bda,
+      int attribute_handle, int offset,
+      bool is_long) override;
+  void RequestReadDescriptorCallback(
+      hal::BluetoothGattInterface* gatt_iface,
+      int conn_id, int trans_id,
+      const bt_bdaddr_t& bda,
+      int attribute_handle, int offset,
+      bool is_long) override;
+  void RequestWriteCharacteristicCallback(
+      hal::BluetoothGattInterface* gatt_iface,
+      int conn_id, int trans_id,
+      const bt_bdaddr_t& bda,
+      int attr_handle, int offset,
+      bool need_rsp, bool is_prep,
+      vector<uint8_t> value) override;
+  void RequestWriteDescriptorCallback(
+      hal::BluetoothGattInterface* gatt_iface,
+      int conn_id, int trans_id,
+      const bt_bdaddr_t& bda,
+      int attr_handle, int offset,
+      bool need_rsp, bool is_prep,
+      vector<uint8_t> value) override;
+  void RequestExecWriteCallback(
+      hal::BluetoothGattInterface* gatt_iface,
+      int conn_id, int trans_id,
+      const bt_bdaddr_t& bda, int exec_write) override;
+  void IndicationSentCallback(
+      hal::BluetoothGattInterface* gatt_iface,
+      int conn_id, int status) override;
+
+  // Helper function that notifies and clears the pending callback.
+  void CleanUpPendingData();
+
+  // Handles the next attribute entry in the pending service declaration.
+  void HandleNextEntry(hal::BluetoothGattInterface* gatt_iface);
+
+  // Helper method that returns a pointer to an internal Connection instance
+  // that matches the given parameters.
+  std::shared_ptr<Connection> GetConnection(int conn_id, const bt_bdaddr_t& bda,
+                                            int request_id);
+
+  // See getters for documentation.
+  UUID app_identifier_;
+  int server_id_;
+
+  // Mutex that synchronizes access to the entries below.
+  std::mutex mutex_;
+  ResultCallback pending_end_decl_cb_;
+
+  // GATT connection mappings from stack-provided "conn_id" IDs and remote
+  // device addresses to Connection structures. The conn_id map is one-to-one
+  // while the conn_addr map is one to many, as a remote device may support
+  // multiple transports (BR/EDR & LE) and use the same device address for both.
+  std::unordered_map<int, std::shared_ptr<Connection>> conn_id_map_;
+  std::unordered_map<std::string, std::vector<std::shared_ptr<Connection>>>
+      conn_addr_map_;
+
+  // Connections for which a Handle-Value indication is pending. Since there can
+  // be multiple indications to the same device (in the case of a dual-mode
+  // device with simulatenous BR/EDR & LE GATT connections), we also keep track
+  // of whether there has been at least one successful confirmation.
+  std::unordered_map<int, std::shared_ptr<PendingIndication>>
+      pending_indications_;
+
+  // Raw handle to the Delegate, which must outlive this GattServer instance.
+  Delegate* delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(GattServer);
+};
+
+// GattServerFactory is used to register and obtain a per-application GattServer
+// instance. Users should call RegisterClient to obtain their own unique
+// GattServer instance that has been registered with the Bluetooth stack.
+class GattServerFactory : public BluetoothInstanceFactory,
+                          private hal::BluetoothGattInterface::ServerObserver {
+ public:
+  // Don't construct/destruct directly except in tests. Instead, obtain a handle
+  // from an Adapter instance.
+  GattServerFactory();
+  ~GattServerFactory() override;
+
+  // BluetoothInstanceFactory override:
+  bool RegisterInstance(const UUID& uuid,
+                        const RegisterCallback& callback) override;
+
+ private:
+  // hal::BluetoothGattInterface::ServerObserver override:
+  void RegisterServerCallback(
+      hal::BluetoothGattInterface* gatt_iface,
+      int status, int server_id,
+      const bt_uuid_t& app_uuid) override;
+
+  // Map of pending calls to register.
+  std::mutex pending_calls_lock_;
+  std::unordered_map<UUID, RegisterCallback> pending_calls_;
+
+  DISALLOW_COPY_AND_ASSIGN(GattServerFactory);
+};
+
+}  // namespace bluetooth
diff --git a/bt/service/gatt_server_old.cc b/bt/service/gatt_server_old.cc
new file mode 100644
index 0000000..ceda435
--- /dev/null
+++ b/bt/service/gatt_server_old.cc
@@ -0,0 +1,747 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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_gatts"
+
+#include "gatt_server_old.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <base/bind.h>
+#include <algorithm>
+#include <array>
+#include <condition_variable>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
+
+#include "service/hal/bluetooth_interface.h"
+#include "service/logging_helpers.h"
+
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+namespace {
+
+const size_t kMaxGattAttributeSize = 512;
+std::vector<btgatt_db_element_t> pending_svc_decl;
+std::unordered_set<int> blob_index;
+
+// TODO(icoolidge): Support multiple instances
+// TODO(armansito): Remove this variable. No point of having this if
+// each bluetooth::gatt::Server instance already keeps a pointer to the
+// ServerInternals that is associated with it (which is much cleaner). It looks
+// like this variable exists because the btif callbacks don't allow the
+// upper-layer to pass user data to them. We could:
+//
+//    1. Fix the btif callbacks so that some sort of continuation can be
+//    attached to a callback. This might be a long shot since the callback
+//    interface doesn't allow more than one caller to register its own callbacks
+//    (which might be what we want though, since this would make the API more
+//    flexible).
+//
+//    2. Allow creation of Server objects using a factory method that returns
+//    the result asynchronously in a base::Callback. The RegisterServerCallback
+//    provides an |app_uuid|, which can be used to store callback structures in
+//    a map and lazily instantiate the Server and invoke the correct callback.
+//    This is a general pattern that we should use throughout the daemon, since
+//    all operations can timeout or fail and this is best reported in an
+//    asynchronous base::Callback.
+//
+static bluetooth::gatt::ServerInternals *g_internal = nullptr;
+
+enum { kPipeReadEnd = 0, kPipeWriteEnd = 1, kPipeNumEnds = 2 };
+
+}  // namespace
+
+namespace bluetooth {
+namespace gatt {
+
+struct Characteristic {
+  UUID uuid;
+  int blob_section;
+  std::vector<uint8_t> blob;
+
+  // Support synchronized blob updates by latching under mutex.
+  std::vector<uint8_t> next_blob;
+  bool next_blob_pending;
+  bool notify;
+};
+
+struct ServerInternals {
+  ServerInternals();
+  ~ServerInternals();
+  int Initialize();
+  bt_status_t AddCharacteristic(
+      const UUID& uuid,
+      uint8_t properties,
+      uint16_t permissions);
+
+  // This maps API attribute UUIDs to BlueDroid handles.
+  std::map<UUID, int> uuid_to_attribute;
+
+  // The attribute cache, indexed by BlueDroid handles.
+  std::unordered_map<int, Characteristic> characteristics;
+
+  // Associate a control attribute with its value attribute.
+  std::unordered_map<int, int> controlled_blobs;
+
+  ScanResults scan_results;
+
+  UUID last_write;
+  const btgatt_interface_t *gatt;
+  int server_if;
+  int client_if;
+  int service_handle;
+  std::set<int> connections;
+
+  std::mutex lock;
+  std::condition_variable api_synchronize;
+  int pipefd[kPipeNumEnds];
+};
+
+}  // namespace gatt
+}  // namespace bluetooth
+
+namespace {
+
+/** Callback invoked in response to register_server */
+void RegisterServerCallback(int status, int server_if, bt_uuid_t *app_uuid) {
+  LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d app_uuid:%p", __func__, status,
+           server_if, app_uuid);
+
+  g_internal->server_if = server_if;
+  pending_svc_decl.push_back({.type = BTGATT_DB_PRIMARY_SERVICE, .uuid = *app_uuid});
+}
+
+void ServiceAddedCallback(int status, int server_if, vector<btgatt_db_element_t> service) {
+  LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d count:%zu svc_handle:%d",
+           __func__, status, server_if, service.size(), service[0].attribute_handle);
+
+  std::lock_guard<std::mutex> lock(g_internal->lock);
+  g_internal->server_if = server_if;
+
+  g_internal->service_handle = service[0].attribute_handle;
+
+  uint16_t prev_char_handle = 0;
+  uint16_t prev_char_properties = 0;
+  for (size_t i = 1; i<service.size(); i++) {
+    const btgatt_db_element_t &el = service[i];
+    if (el.type == BTGATT_DB_DESCRIPTOR) {
+      LOG_INFO(LOG_TAG, "%s: descr_handle:%d", __func__, el.attribute_handle);
+    } else if (el.type == BTGATT_DB_CHARACTERISTIC) {
+      bluetooth::UUID id(el.uuid);
+      uint16_t char_handle = el.attribute_handle;
+
+      LOG_INFO(LOG_TAG, "%s: char_handle:%d", __func__, char_handle);
+
+      g_internal->uuid_to_attribute[id] = char_handle;
+      g_internal->characteristics[char_handle].uuid = id;
+      g_internal->characteristics[char_handle].blob_section = 0;
+
+      // If the added characteristic is blob
+      if (blob_index.find(i) != blob_index.end()) {
+        // Finally, associate the control attribute with the value attribute.
+        // Also, initialize the control attribute to a readable zero.
+        const uint16_t control_attribute = char_handle;
+        const uint16_t blob_attribute = prev_char_handle;
+        g_internal->controlled_blobs[control_attribute] = blob_attribute;
+        g_internal->characteristics[blob_attribute].notify =
+            prev_char_properties & bluetooth::gatt::kPropertyNotify;
+
+        bluetooth::gatt::Characteristic &ctrl =
+            g_internal->characteristics[control_attribute];
+        ctrl.next_blob.clear();
+        ctrl.next_blob.push_back(0);
+        ctrl.next_blob_pending = true;
+        ctrl.blob_section = 0;
+        ctrl.notify = false;
+      }
+      prev_char_handle = char_handle;
+      prev_char_properties = el.properties;
+    }
+  }
+
+  pending_svc_decl.clear();
+  blob_index.clear();
+
+  // The UUID provided here is unimportant, and is only used to satisfy
+  // BlueDroid.
+  // It must be different than any other registered UUID.
+  bt_uuid_t client_id = service[0].uuid;
+  ++client_id.uu[15];
+
+  bt_status_t btstat = g_internal->gatt->client->register_client(&client_id);
+  if (btstat != BT_STATUS_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: Failed to register client", __func__);
+  }
+}
+
+void RequestReadCallback(int conn_id, int trans_id, bt_bdaddr_t *bda,
+                         int attr_handle, int attribute_offset_octets,
+                         bool is_long) {
+  std::lock_guard<std::mutex> lock(g_internal->lock);
+
+  bluetooth::gatt::Characteristic &ch = g_internal->characteristics[attr_handle];
+
+  // Latch next_blob to blob on a 'fresh' read.
+  if (ch.next_blob_pending && attribute_offset_octets == 0 &&
+      ch.blob_section == 0) {
+    std::swap(ch.blob, ch.next_blob);
+    ch.next_blob_pending = false;
+  }
+
+  const size_t blob_offset_octets =
+      std::min(ch.blob.size(), ch.blob_section * kMaxGattAttributeSize);
+  const size_t blob_remaining = ch.blob.size() - blob_offset_octets;
+  const size_t attribute_size = std::min(kMaxGattAttributeSize, blob_remaining);
+
+  std::string addr(BtAddrString(bda));
+  LOG_INFO(LOG_TAG,
+      "%s: connection:%d (%s) reading attr:%d attribute_offset_octets:%d "
+      "blob_section:%u (is_long:%u)",
+      __func__, conn_id, addr.c_str(), attr_handle, attribute_offset_octets,
+      ch.blob_section, is_long);
+
+  btgatt_response_t response;
+  response.attr_value.len = 0;
+
+  if (attribute_offset_octets < static_cast<int>(attribute_size)) {
+    std::copy(ch.blob.begin() + blob_offset_octets + attribute_offset_octets,
+              ch.blob.begin() + blob_offset_octets + attribute_size,
+              response.attr_value.value);
+    response.attr_value.len = attribute_size - attribute_offset_octets;
+  }
+
+  response.attr_value.handle = attr_handle;
+  response.attr_value.offset = attribute_offset_octets;
+  response.attr_value.auth_req = 0;
+  g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response);
+}
+
+void RequestWriteCallback(int conn_id, int trans_id, bt_bdaddr_t *bda,
+                          int attr_handle, int attribute_offset,
+                          bool need_rsp, bool is_prep,
+                          vector<uint8_t> value) {
+  std::string addr(BtAddrString(bda));
+  LOG_INFO(LOG_TAG,
+      "%s: connection:%d (%s:trans:%d) write attr:%d attribute_offset:%d "
+      "length:%zu "
+      "need_resp:%u is_prep:%u",
+      __func__, conn_id, addr.c_str(), trans_id, attr_handle, attribute_offset,
+      value.size(), need_rsp, is_prep);
+
+  std::lock_guard<std::mutex> lock(g_internal->lock);
+
+  bluetooth::gatt::Characteristic &ch =
+      g_internal->characteristics[attr_handle];
+
+  ch.blob.resize(attribute_offset + value.size());
+
+  std::copy(value.begin(), value.end(), ch.blob.begin() + attribute_offset);
+
+  auto target_blob = g_internal->controlled_blobs.find(attr_handle);
+  // If this is a control attribute, adjust offset of the target blob.
+  if (target_blob != g_internal->controlled_blobs.end() &&
+      ch.blob.size() == 1u) {
+    g_internal->characteristics[target_blob->second].blob_section = ch.blob[0];
+    LOG_INFO(LOG_TAG, "%s: updating attribute %d blob_section to %u", __func__,
+        target_blob->second, ch.blob[0]);
+  } else if (!is_prep) {
+    // This is a single frame characteristic write.
+    // Notify upwards because we're done now.
+    const bluetooth::UUID::UUID128Bit &attr_uuid = ch.uuid.GetFullBigEndian();
+    ssize_t status;
+    OSI_NO_INTR(status = write(g_internal->pipefd[kPipeWriteEnd],
+                               attr_uuid.data(), attr_uuid.size()));
+    if (-1 == status)
+      LOG_ERROR(LOG_TAG, "%s: write failed: %s", __func__, strerror(errno));
+  } else {
+    // This is a multi-frame characteristic write.
+    // Wait for an 'RequestExecWriteCallback' to notify completion.
+    g_internal->last_write = ch.uuid;
+  }
+
+  // Respond only if needed.
+  if (!need_rsp) return;
+
+  btgatt_response_t response;
+  response.attr_value.handle = attr_handle;
+  response.attr_value.offset = attribute_offset;
+  response.attr_value.len = value.size();
+  response.attr_value.auth_req = 0;
+  // Provide written data back to sender for the response.
+  // Remote stacks use this to validate the success of the write.
+  std::copy(value.begin(), value.end(), response.attr_value.value);
+  g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response);
+}
+
+void RequestExecWriteCallback(int conn_id, int trans_id, bt_bdaddr_t *bda,
+                              int exec_write) {
+  std::string addr(BtAddrString(bda));
+  LOG_INFO(LOG_TAG, "%s: connection:%d (%s:trans:%d) exec_write:%d", __func__,
+      conn_id, addr.c_str(), trans_id, exec_write);
+
+  // This 'response' data is unused for ExecWriteResponses.
+  // It is only used to pass BlueDroid argument validation.
+  btgatt_response_t response = {};
+  g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response);
+
+  if (!exec_write)
+    return;
+
+  std::lock_guard<std::mutex> lock(g_internal->lock);
+  // Communicate the attribute UUID as notification of a write update.
+  const bluetooth::UUID::UUID128Bit uuid =
+      g_internal->last_write.GetFullBigEndian();
+  ssize_t status;
+  OSI_NO_INTR(status = write(g_internal->pipefd[kPipeWriteEnd], uuid.data(),
+                             uuid.size()));
+  if (-1 == status)
+    LOG_ERROR(LOG_TAG, "%s: write failed: %s", __func__, strerror(errno));
+}
+
+void ConnectionCallback(int conn_id, int server_if, int connected,
+                        bt_bdaddr_t *bda) {
+  std::string addr(BtAddrString(bda));
+  LOG_INFO(LOG_TAG, "%s: connection:%d server_if:%d connected:%d addr:%s",
+      __func__, conn_id, server_if, connected, addr.c_str());
+  if (connected == 1) {
+    g_internal->connections.insert(conn_id);
+  } else if (connected == 0) {
+    g_internal->connections.erase(conn_id);
+  }
+}
+
+void EnableAdvertisingCallback(uint8_t status) {
+  LOG_INFO(LOG_TAG, "%s: status:%d", __func__, status);
+  // This terminates a Start call.
+  std::lock_guard<std::mutex> lock(g_internal->lock);
+  g_internal->api_synchronize.notify_one();
+}
+
+void RegisterClientCallback(int status, int client_if, bt_uuid_t *app_uuid) {
+  LOG_INFO(LOG_TAG, "%s: status:%d client_if:%d uuid[0]:%u", __func__, status,
+      client_if, app_uuid->uu[0]);
+  g_internal->client_if = client_if;
+
+  // Setup our advertisement. This has no callback.
+  g_internal->gatt->advertiser->SetData(false, {/*TODO: put inverval 2,2 here*/});
+
+  // TODO(icoolidge): Deprecated, use multi-adv interface.
+  // This calls back to EnableAdvertisingCallback.
+  g_internal->gatt->advertiser->Enable(true,
+                                       base::Bind(&EnableAdvertisingCallback));
+}
+
+void RegisterScannerCallback(int status, int scanner_id, bt_uuid_t *app_uuid) {
+  LOG_INFO(LOG_TAG, "%s: status:%d scanner_id:%d uuid[0]:%u", __func__, status,
+      scanner_id, app_uuid->uu[0]);
+}
+
+void ServiceStoppedCallback(int status, int server_if, int srvc_handle) {
+  LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d srvc_handle:%d", __func__,
+      status, server_if, srvc_handle);
+  // This terminates a Stop call.
+  // TODO(icoolidge): make this symmetric with start
+  std::lock_guard<std::mutex> lock(g_internal->lock);
+  g_internal->api_synchronize.notify_one();
+}
+
+void ScanResultCallback(bt_bdaddr_t *bda, int rssi, vector<uint8_t> adv_data) {
+  std::string addr(BtAddrString(bda));
+  (void)adv_data;
+  std::lock_guard<std::mutex> lock(g_internal->lock);
+  g_internal->scan_results[addr] = rssi;
+}
+
+void ClientConnectCallback(int conn_id, int status, int client_if,
+                           bt_bdaddr_t *bda) {
+  std::string addr(BtAddrString(bda));
+  LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__,
+      conn_id, status, client_if, addr.c_str());
+}
+
+void ClientDisconnectCallback(int conn_id, int status, int client_if,
+                              bt_bdaddr_t *bda) {
+  std::string addr(BtAddrString(bda));
+  LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__,
+      conn_id, status, client_if, addr.c_str());
+}
+
+void IndicationSentCallback(UNUSED_ATTR int conn_id,
+                            UNUSED_ATTR int status) {
+  // TODO(icoolidge): what to do
+}
+
+void ResponseConfirmationCallback(UNUSED_ATTR int status,
+                                  UNUSED_ATTR int handle) {
+  // TODO(icoolidge): what to do
+}
+
+const btgatt_server_callbacks_t gatt_server_callbacks = {
+    RegisterServerCallback,
+    ConnectionCallback,
+    ServiceAddedCallback,
+    ServiceStoppedCallback,
+    nullptr, /* service_deleted_cb */
+    RequestReadCallback,
+    RequestReadCallback,
+    RequestWriteCallback,
+    RequestWriteCallback,
+    RequestExecWriteCallback,
+    ResponseConfirmationCallback,
+    IndicationSentCallback,
+    nullptr, /* congestion_cb*/
+    nullptr, /* mtu_changed_cb */
+};
+
+// TODO(eisenbach): Refactor GATT interface to not require servers
+// to refer to the client interface.
+const btgatt_client_callbacks_t gatt_client_callbacks = {
+    RegisterClientCallback,
+    ClientConnectCallback,
+    ClientDisconnectCallback,
+    nullptr, /* search_complete_cb; */
+    nullptr, /* register_for_notification_cb; */
+    nullptr, /* notify_cb; */
+    nullptr, /* read_characteristic_cb; */
+    nullptr, /* write_characteristic_cb; */
+    nullptr, /* read_descriptor_cb; */
+    nullptr, /* write_descriptor_cb; */
+    nullptr, /* execute_write_cb; */
+    nullptr, /* read_remote_rssi_cb; */
+    nullptr, /* configure_mtu_cb; */
+    nullptr, /* congestion_cb; */
+    nullptr, /* get_gatt_db_cb; */
+    nullptr, /* services_removed_cb */
+    nullptr, /* services_added_cb */
+};
+
+const btgatt_scanner_callbacks_t gatt_scanner_callbacks = {
+    RegisterScannerCallback,
+    ScanResultCallback,
+    nullptr, /* batchscan_cfg_storage_cb; */
+    nullptr, /* batchscan_enb_disable_cb; */
+    nullptr, /* batchscan_reports_cb; */
+    nullptr, /* batchscan_threshold_cb; */
+    nullptr, /* track_adv_event_cb; */
+    nullptr, /* scan_parameter_setup_completed_cb; */
+    nullptr, /* scan_filter_cfg_cb; */
+    nullptr, /* scan_filter_param_cb; */
+    nullptr, /* scan_filter_status_cb; */
+
+};
+
+const btgatt_callbacks_t gatt_callbacks = {
+    /** Set to sizeof(btgatt_callbacks_t) */
+    sizeof(btgatt_callbacks_t),
+
+    /** GATT Client callbacks */
+    &gatt_client_callbacks,
+
+    /** GATT Server callbacks */
+    &gatt_server_callbacks,
+
+    /** GATT Server callbacks */
+    &gatt_scanner_callbacks,
+};
+
+}  // namespace
+
+namespace bluetooth {
+namespace gatt {
+
+int ServerInternals::Initialize() {
+  // Get the interface to the GATT profile.
+  const bt_interface_t* bt_iface =
+      hal::BluetoothInterface::Get()->GetHALInterface();
+  gatt = reinterpret_cast<const btgatt_interface_t *>(
+      bt_iface->get_profile_interface(BT_PROFILE_GATT_ID));
+  if (!gatt) {
+    LOG_ERROR(LOG_TAG, "Error getting GATT interface");
+    return -1;
+  }
+
+  bt_status_t btstat = gatt->init(&gatt_callbacks);
+  if (btstat != BT_STATUS_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "Failed to initialize gatt interface");
+    return -1;
+  }
+
+  int status = pipe(pipefd);
+  if (status == -1) {
+    LOG_ERROR(LOG_TAG, "pipe creation failed: %s", strerror(errno));
+    return -1;
+  }
+
+  return 0;
+}
+
+bt_status_t ServerInternals::AddCharacteristic(
+    const UUID& uuid,
+    uint8_t properties,
+    uint16_t permissions) {
+  bt_uuid_t c_uuid = uuid.GetBlueDroid();
+
+  pending_svc_decl.push_back({.type = BTGATT_DB_CHARACTERISTIC, .uuid = c_uuid,
+                        .properties = properties, .permissions = permissions});
+  return BT_STATUS_SUCCESS;
+}
+
+ServerInternals::ServerInternals()
+    : gatt(nullptr),
+      server_if(0),
+      client_if(0),
+      service_handle(0),
+      pipefd{INVALID_FD, INVALID_FD} {}
+
+ServerInternals::~ServerInternals() {
+  if (pipefd[0] != INVALID_FD)
+    close(pipefd[0]);
+  if (pipefd[1] != INVALID_FD)
+    close(pipefd[1]);
+
+  gatt->server->delete_service(server_if, service_handle);
+  gatt->server->unregister_server(server_if);
+  gatt->client->unregister_client(client_if);
+}
+
+Server::Server() : internal_(nullptr) {}
+
+Server::~Server() {}
+
+bool Server::Initialize(const UUID& service_id, int* gatt_pipe) {
+  internal_.reset(new ServerInternals);
+  if (!internal_) {
+    LOG_ERROR(LOG_TAG, "Error creating internals");
+    return false;
+  }
+  g_internal = internal_.get();
+
+  std::unique_lock<std::mutex> lock(internal_->lock);
+  int status = internal_->Initialize();
+  if (status) {
+    LOG_ERROR(LOG_TAG, "Error initializing internals");
+    return false;
+  }
+
+  bt_uuid_t uuid = service_id.GetBlueDroid();
+
+  bt_status_t btstat = internal_->gatt->server->register_server(&uuid);
+  if (btstat != BT_STATUS_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "Failed to register server");
+    return false;
+  }
+
+  internal_->api_synchronize.wait(lock);
+  // TODO(icoolidge): Better error handling.
+  if (internal_->server_if == 0) {
+    LOG_ERROR(LOG_TAG, "Initialization of server failed");
+    return false;
+  }
+
+  *gatt_pipe = internal_->pipefd[kPipeReadEnd];
+  LOG_INFO(LOG_TAG, "Server Initialize succeeded");
+  return true;
+}
+
+bool Server::SetAdvertisement(const std::vector<UUID>& ids,
+                              const std::vector<uint8_t>& service_data,
+                              const std::vector<uint8_t>& manufacturer_data,
+                              bool transmit_name) {
+  // std::vector<uint8_t> id_data;
+  // const auto& mutable_manufacturer_data = manufacturer_data;
+  // const auto& mutable_service_data = service_data;
+
+  // for (const UUID &id : ids) {
+  //   const auto le_id = id.GetFullLittleEndian();
+  //   id_data.insert(id_data.end(), le_id.begin(), le_id.end());
+  // }
+
+  std::lock_guard<std::mutex> lock(internal_->lock);
+
+  // Setup our advertisement. This has no callback.
+  internal_->gatt->advertiser->SetData(
+      false, /* beacon, not scan response */
+      {});
+      // transmit_name,               /* name */
+      // 2, 2,                         interval 
+      // mutable_manufacturer_data,
+      // mutable_service_data,
+      // id_data);
+  return true;
+}
+
+bool Server::SetScanResponse(const std::vector<UUID>& ids,
+                             const std::vector<uint8_t>& service_data,
+                             const std::vector<uint8_t>& manufacturer_data,
+                             bool transmit_name) {
+  // std::vector<uint8_t> id_data;
+  // const auto& mutable_manufacturer_data = manufacturer_data;
+  // const auto& mutable_service_data = service_data;
+
+  // for (const UUID &id : ids) {
+  //   const auto le_id = id.GetFullLittleEndian();
+  //   id_data.insert(id_data.end(), le_id.begin(), le_id.end());
+  // }
+
+  std::lock_guard<std::mutex> lock(internal_->lock);
+
+  // Setup our advertisement. This has no callback.
+  internal_->gatt->advertiser->SetData(
+      true, /* scan response */
+      {});
+      // transmit_name,              /* name */
+      // false,                      /* no txpower */
+      // 2, 2,                        interval 
+      // 0,                          /* appearance */
+      // mutable_manufacturer_data,
+      // mutable_service_data,
+      // id_data);
+  return true;
+}
+
+bool Server::AddCharacteristic(
+    const UUID &id, int properties, int permissions) {
+  std::unique_lock<std::mutex> lock(internal_->lock);
+  bt_status_t btstat = internal_->AddCharacteristic(
+      id, properties, permissions);
+  if (btstat != BT_STATUS_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "Failed to add characteristic to service: 0x%04x",
+              internal_->service_handle);
+    return false;
+  }
+  internal_->api_synchronize.wait(lock);
+  const int handle = internal_->uuid_to_attribute[id];
+  internal_->characteristics[handle].notify = properties & kPropertyNotify;
+  return true;
+}
+
+bool Server::AddBlob(const UUID &id, const UUID &control_id, int properties,
+                    int permissions) {
+  std::unique_lock<std::mutex> lock(internal_->lock);
+
+  // First, add the primary attribute (characteristic value)
+  bt_status_t btstat = internal_->AddCharacteristic(
+      id, properties, permissions);
+  if (btstat != BT_STATUS_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "Failed to set scan response data");
+    return false;
+  }
+
+  // Next, add the secondary attribute (blob control).
+  // Control attributes have fixed permissions/properties.
+  // Remember position at which blob was added.
+  blob_index.insert(pending_svc_decl.size());
+  btstat = internal_->AddCharacteristic(
+      control_id,
+      kPropertyRead | kPropertyWrite,
+      kPermissionRead | kPermissionWrite);
+
+  return true;
+}
+
+bool Server::Start() {
+  std::unique_lock<std::mutex> lock(internal_->lock);
+  bt_status_t btstat = internal_->gatt->server->add_service(
+      internal_->server_if, pending_svc_decl);
+  if (btstat != BT_STATUS_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "Failed to start service with handle: 0x%04x",
+              internal_->service_handle);
+    return false;
+  }
+  internal_->api_synchronize.wait(lock);
+  return true;
+}
+
+bool Server::Stop() {
+  std::unique_lock<std::mutex> lock(internal_->lock);
+  bt_status_t btstat = internal_->gatt->server->stop_service(
+      internal_->server_if, internal_->service_handle);
+  if (btstat != BT_STATUS_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "Failed to stop service with handle: 0x%04x",
+              internal_->service_handle);
+    return false;
+  }
+  internal_->api_synchronize.wait(lock);
+  return true;
+}
+
+bool Server::ScanEnable() {
+  bt_status_t btstat = internal_->gatt->scanner->scan(true);
+  if (btstat) {
+    LOG_ERROR(LOG_TAG, "Enable scan failed: %d", btstat);
+    return false;
+  }
+  return true;
+}
+
+bool Server::ScanDisable() {
+  bt_status_t btstat = internal_->gatt->scanner->scan(false);
+  if (btstat) {
+    LOG_ERROR(LOG_TAG, "Disable scan failed: %d", btstat);
+    return false;
+  }
+  return true;
+}
+
+bool Server::GetScanResults(ScanResults *results) {
+  std::lock_guard<std::mutex> lock(internal_->lock);
+  *results = internal_->scan_results;
+  return true;
+}
+
+bool Server::SetCharacteristicValue(const UUID &id,
+                              const std::vector<uint8_t> &value) {
+  std::lock_guard<std::mutex> lock(internal_->lock);
+  const int attribute_id = internal_->uuid_to_attribute[id];
+  Characteristic &ch = internal_->characteristics[attribute_id];
+  ch.next_blob = value;
+  ch.next_blob_pending = true;
+
+  if (!ch.notify)
+    return true;
+
+  for (auto connection : internal_->connections) {
+    internal_->gatt->server->send_indication(internal_->server_if,
+                                             attribute_id,
+                                             connection,
+                                             true,
+                                             {0});
+  }
+  return true;
+}
+
+bool Server::GetCharacteristicValue(const UUID &id, std::vector<uint8_t> *value) {
+  std::lock_guard<std::mutex> lock(internal_->lock);
+  const int attribute_id = internal_->uuid_to_attribute[id];
+  *value = internal_->characteristics[attribute_id].blob;
+  return true;
+}
+
+}  // namespace gatt
+}  // namespace bluetooth
diff --git a/bt/service/gatt_server_old.h b/bt/service/gatt_server_old.h
new file mode 100644
index 0000000..84ceb26
--- /dev/null
+++ b/bt/service/gatt_server_old.h
@@ -0,0 +1,125 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <memory>
+#include <unordered_map>
+#include <vector>
+
+#include "hardware/bluetooth.h"
+#include "hardware/bt_gatt.h"
+#include "service/common/bluetooth/uuid.h"
+
+namespace bluetooth {
+namespace gatt {
+
+// Attribute permission values
+const int kPermissionRead = 0x1;
+const int kPermissionReadEncrypted = 0x2;
+const int kPermissionReadEncryptedMitm = 0x4;
+const int kPermissionWrite = 0x10;
+const int kPermissionWriteEnecrypted = 0x20;
+const int KPermissionWriteEncryptedMitm = 0x40;
+const int kPermissionWriteSigned = 0x80;
+const int kPermissionWriteSignedMitm = 0x100;
+
+// GATT characteristic properties bit-field values
+const int kPropertyBroadcast = 0x1;
+const int kPropertyRead = 0x2;
+const int kPropertyWriteNoResponse = 0x4;
+const int kPropertyWrite = 0x8;
+const int kPropertyNotify = 0x10;
+const int kPropertyIndicate = 0x20;
+const int kPropertySignedWrite = 0x40;
+const int kPropertyExtendedProps = 0x80;
+
+// A mapping from string bluetooth addresses to RSSI measurements.
+typedef std::unordered_map<std::string, int> ScanResults;
+
+// TODO(armansito): This should be a private internal class though I don't see
+// why we even need this class. Instead it should probably be merged into
+// Server.
+struct ServerInternals;
+
+// Server is threadsafe and internally locked.
+// Asynchronous IO is identified via a gatt_pipe FD,
+// and synchronously read with 'GetCharacteristicValue'
+//
+// ****DEPRECATED****
+//
+// TODO(armansito): This class has been deprecated and is being replaced by
+// bluetooth::GattServer. We will remove this entirely once the new code is
+// ready.
+class Server {
+ public:
+  Server();
+  ~Server();
+
+  // Register GATT interface, initialize internal state,
+  // and open a pipe for characteristic write notification.
+  bool Initialize(const UUID& service_id, int* gatt_pipe);
+
+  // Control the content of service advertisement.
+  bool SetAdvertisement(const std::vector<UUID>& ids,
+                        const std::vector<uint8_t>& service_data,
+                        const std::vector<uint8_t>& manufacturer_data,
+                        bool transmit_name);
+
+  // Control the content of service scan response.
+  bool SetScanResponse(const std::vector<UUID>& ids,
+                       const std::vector<uint8_t>& service_data,
+                       const std::vector<uint8_t>& manufacturer_data,
+                       bool transmit_name);
+
+  // Add an ordinary characteristic for reading and/or writing.
+  bool AddCharacteristic(const UUID &id, int properties, int permissions);
+
+  // Add a special 'blob' characteristic with a corresponding control
+  // attribute to manipulate which part of the blob the attribute represents.
+  bool AddBlob(const UUID &id, const UUID &control_id, int properties,
+               int permissions);
+
+  // Put a new value into a characeteristic.
+  // It will be read from a client starting at the next 0-offset read.
+  bool SetCharacteristicValue(const UUID &id, const std::vector<uint8_t> &value);
+
+  // Get the current value of a characteristic.
+  bool GetCharacteristicValue(const UUID &id, std::vector<uint8_t> *value);
+
+  // Start this service. Activate advertisements, allow connections.
+  // Characteristics should all be created before this.
+  bool Start();
+
+  // Cease advertisements and disallow connections.
+  bool Stop();
+
+  // Enable LE scan. Scan results will be cached internally.
+  bool ScanEnable();
+
+  // Disable LE scan.
+  bool ScanDisable();
+
+  // Copy out the cached scan results.
+  bool GetScanResults(ScanResults *results);
+
+ private:
+  // Internal data.
+  std::unique_ptr<ServerInternals> internal_;
+};
+
+}  // namespace gatt
+}  // namespace bluetooth
diff --git a/bt/service/hal/bluetooth_gatt_interface.cc b/bt/service/hal/bluetooth_gatt_interface.cc
new file mode 100644
index 0000000..f7ddecb
--- /dev/null
+++ b/bt/service/hal/bluetooth_gatt_interface.cc
@@ -0,0 +1,920 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/hal/bluetooth_gatt_interface.h"
+
+#include <mutex>
+#define _LIBCPP_BUILDING_SHARED_MUTEX
+#include <shared_mutex>
+#undef _LIBCPP_BUILDING_SHARED_MUTEX
+
+#include <base/logging.h>
+#include <base/observer_list.h>
+
+#include "service/hal/bluetooth_interface.h"
+#include "service/logging_helpers.h"
+
+using std::lock_guard;
+using std::unique_lock;
+using std::shared_lock;
+using std::mutex;
+using std::shared_timed_mutex;
+
+namespace bluetooth {
+namespace hal {
+
+namespace {
+
+// The global BluetoothGattInterface instance.
+BluetoothGattInterface* g_interface = nullptr;
+
+// Mutex used by callbacks to access |g_interface|. If we initialize or clean it
+// use unique_lock. If only accessing |g_interface| use shared lock.
+//TODO(jpawlowski): this should be just shared_mutex, as we currently don't use
+// timed methods. Change to shared_mutex when we upgrade to C++14
+shared_timed_mutex g_instance_lock;
+
+// Helper for obtaining the observer lists. This is forward declared here
+// and defined below since it depends on BluetoothInterfaceImpl.
+base::ObserverList<BluetoothGattInterface::ScannerObserver>*
+    GetScannerObservers();
+base::ObserverList<BluetoothGattInterface::ClientObserver>*
+    GetClientObservers();
+base::ObserverList<BluetoothGattInterface::ServerObserver>*
+    GetServerObservers();
+
+#define FOR_EACH_SCANNER_OBSERVER(func) \
+  FOR_EACH_OBSERVER(BluetoothGattInterface::ScannerObserver, \
+                    *GetScannerObservers(), func)
+
+#define FOR_EACH_CLIENT_OBSERVER(func) \
+  FOR_EACH_OBSERVER(BluetoothGattInterface::ClientObserver, \
+                    *GetClientObservers(), func)
+
+#define FOR_EACH_SERVER_OBSERVER(func) \
+  FOR_EACH_OBSERVER(BluetoothGattInterface::ServerObserver, \
+                    *GetServerObservers(), func)
+
+#define VERIFY_INTERFACE_OR_RETURN() \
+  do { \
+    if (!g_interface) { \
+      LOG(WARNING) << "Callback received while |g_interface| is NULL"; \
+      return; \
+    } \
+  } while (0)
+
+void RegisterClientCallback(int status, int client_if, bt_uuid_t* app_uuid) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VLOG(2) << __func__ << " - status: " << status << " client_if: " << client_if;
+  VERIFY_INTERFACE_OR_RETURN();
+  CHECK(app_uuid);
+
+  FOR_EACH_CLIENT_OBSERVER(
+      RegisterClientCallback(g_interface, status, client_if, *app_uuid));
+}
+
+void RegisterScannerCallback(int status, int scanner_id, bt_uuid_t* app_uuid) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VLOG(2) << __func__ << " - status: " << status << " scanner_id: " << scanner_id;
+  VERIFY_INTERFACE_OR_RETURN();
+  CHECK(app_uuid);
+
+  FOR_EACH_SCANNER_OBSERVER(
+      RegisterScannerCallback(g_interface, status, scanner_id, *app_uuid));
+}
+
+void ScanResultCallback(bt_bdaddr_t* bda, int rssi, vector<uint8_t> adv_data) {  // NOLINT(pass-by-value)
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VERIFY_INTERFACE_OR_RETURN();
+  CHECK(bda);
+
+  VLOG(2) << __func__ << " - BD_ADDR: " << BtAddrString(bda)
+          << " RSSI: " << rssi;
+  FOR_EACH_SCANNER_OBSERVER(
+    ScanResultCallback(g_interface, *bda, rssi, adv_data));
+}
+
+void ConnectCallback(int conn_id, int status, int client_if, bt_bdaddr_t* bda) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VERIFY_INTERFACE_OR_RETURN();
+  CHECK(bda);
+
+  VLOG(2) << __func__ << " - status: " << status
+          << " client_if: " << client_if
+          << " - BD_ADDR: " << BtAddrString(bda)
+          << " - conn_id: " << conn_id;
+
+  FOR_EACH_CLIENT_OBSERVER(
+    ConnectCallback(g_interface, conn_id, status, client_if, *bda));
+}
+
+void DisconnectCallback(int conn_id, int status, int client_if,
+                        bt_bdaddr_t* bda) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VERIFY_INTERFACE_OR_RETURN();
+  CHECK(bda);
+
+  VLOG(2) << __func__ << " - conn_id: " << conn_id
+             << " - status: " << status
+             << " client_if: " << client_if
+             << " - BD_ADDR: " << BtAddrString(bda);
+  FOR_EACH_CLIENT_OBSERVER(
+    DisconnectCallback(g_interface, conn_id, status, client_if, *bda));
+}
+
+void SearchCompleteCallback(int conn_id, int status) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VERIFY_INTERFACE_OR_RETURN();
+
+  VLOG(2) << __func__ << " - conn_id: " << conn_id
+          << " - status: " << status;
+  FOR_EACH_CLIENT_OBSERVER(
+    SearchCompleteCallback(g_interface, conn_id, status));
+}
+
+void RegisterForNotificationCallback(int conn_id, int registered, int status, uint16_t handle) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VERIFY_INTERFACE_OR_RETURN();
+
+  LOG(INFO) << __func__ << " - conn_id: " << conn_id
+          << " - status: " << status
+          << " - registered: " << registered
+          << " - handle: " << handle;
+  FOR_EACH_CLIENT_OBSERVER(
+    RegisterForNotificationCallback(g_interface, conn_id, status, registered, handle));
+}
+
+void NotifyCallback(int conn_id, btgatt_notify_params_t *p_data) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VERIFY_INTERFACE_OR_RETURN();
+
+  VLOG(2) << __func__ << " - conn_id: " << conn_id
+          << " - address: " << BtAddrString(&p_data->bda)
+          << " - handle: " << p_data->handle
+          << " - len: " << p_data->len
+          << " - is_notify: " << p_data->is_notify;
+
+  FOR_EACH_CLIENT_OBSERVER(
+    NotifyCallback(g_interface, conn_id, p_data));
+}
+
+void WriteCharacteristicCallback(int conn_id, int status, uint16_t handle) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VERIFY_INTERFACE_OR_RETURN();
+
+  VLOG(2) << __func__ << " - conn_id: " << conn_id
+          << " - status: " << status;
+
+  FOR_EACH_CLIENT_OBSERVER(
+    WriteCharacteristicCallback(g_interface, conn_id, status, handle));
+}
+
+void WriteDescriptorCallback(int conn_id, int status,
+      uint16_t handle) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VERIFY_INTERFACE_OR_RETURN();
+
+  VLOG(2) << __func__ << " - conn_id: " << conn_id
+          << " - status: " << status;
+
+  FOR_EACH_CLIENT_OBSERVER(
+    WriteDescriptorCallback(g_interface, conn_id, status, handle));
+}
+
+void MtuChangedCallback(int conn_id, int status, int mtu) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VERIFY_INTERFACE_OR_RETURN();
+
+  VLOG(2) << __func__ << " - conn_id: " << conn_id
+          << " status: " << status
+          << " mtu: " << mtu;
+
+  FOR_EACH_CLIENT_OBSERVER(MtuChangedCallback(g_interface, conn_id, status, mtu));
+}
+
+void GetGattDbCallback(int conn_id, btgatt_db_element_t *db, int size) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VLOG(2) << __func__ << " - conn_id: " << conn_id << " size: " << size;
+  VERIFY_INTERFACE_OR_RETURN();
+
+  FOR_EACH_CLIENT_OBSERVER(
+      GetGattDbCallback(g_interface, conn_id, db, size));
+}
+
+void ServicesRemovedCallback(int conn_id, uint16_t start_handle, uint16_t end_handle) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VLOG(2) << __func__ << " - conn_id: " << conn_id
+          << " start_handle: " << start_handle
+          << " end_handle: " << end_handle;
+  VERIFY_INTERFACE_OR_RETURN();
+
+  FOR_EACH_CLIENT_OBSERVER(
+      ServicesRemovedCallback(g_interface, conn_id, start_handle, end_handle));
+}
+
+void ServicesAddedCallback(int conn_id, btgatt_db_element_t *added, int added_count) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VLOG(2) << __func__ << " - conn_id: " << conn_id
+          << " added_count: " << added_count;
+  VERIFY_INTERFACE_OR_RETURN();
+
+  FOR_EACH_CLIENT_OBSERVER(
+      ServicesAddedCallback(g_interface, conn_id, added, added_count));
+}
+
+void RegisterServerCallback(int status, int server_if, bt_uuid_t* app_uuid) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VLOG(2) << __func__ << " - status: " << status << " server_if: " << server_if;
+  VERIFY_INTERFACE_OR_RETURN();
+  CHECK(app_uuid);
+
+  FOR_EACH_SERVER_OBSERVER(
+      RegisterServerCallback(g_interface, status, server_if, *app_uuid));
+}
+
+void ConnectionCallback(int conn_id, int server_if, int connected,
+                        bt_bdaddr_t* bda) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VLOG(2) << __func__ << " - conn_id: " << conn_id
+          << " server_if: " << server_if << " connected: " << connected;
+  VERIFY_INTERFACE_OR_RETURN();
+  CHECK(bda);
+
+  FOR_EACH_SERVER_OBSERVER(
+      ConnectionCallback(g_interface, conn_id, server_if, connected, *bda));
+}
+
+void ServiceAddedCallback(
+    int status,
+    int server_if,
+    vector<btgatt_db_element_t> service) {  // NOLINT(pass-by-value)
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VLOG(2) << __func__ << " - status: " << status << " server_if: " << server_if
+          << " count: " << service.size();
+  VERIFY_INTERFACE_OR_RETURN();
+  CHECK(service.size());
+
+  FOR_EACH_SERVER_OBSERVER(ServiceAddedCallback(
+      g_interface, status, server_if, service));
+}
+
+void ServiceStoppedCallback(int status, int server_if, int srvc_handle) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VLOG(2) << __func__ << " - status: " << status << " server_if: " << server_if
+          << " handle: " << srvc_handle;
+  VERIFY_INTERFACE_OR_RETURN();
+
+  FOR_EACH_SERVER_OBSERVER(ServiceStoppedCallback(
+      g_interface, status, server_if, srvc_handle));
+}
+
+void ServiceDeletedCallback(int status, int server_if, int srvc_handle) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VLOG(2) << __func__ << " - status: " << status << " server_if: " << server_if
+          << " handle: " << srvc_handle;
+  VERIFY_INTERFACE_OR_RETURN();
+
+  FOR_EACH_SERVER_OBSERVER(ServiceDeletedCallback(
+      g_interface, status, server_if, srvc_handle));
+}
+
+void RequestReadCharacteristicCallback(int conn_id, int trans_id, bt_bdaddr_t* bda,
+                         int attr_handle, int offset, bool is_long) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VLOG(2) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+          << " attr_handle: " << attr_handle << " offset: " << offset
+          << " is_long: " << is_long;
+  VERIFY_INTERFACE_OR_RETURN();
+  CHECK(bda);
+
+  FOR_EACH_SERVER_OBSERVER(RequestReadCharacteristicCallback(
+      g_interface, conn_id, trans_id, *bda, attr_handle, offset, is_long));
+}
+
+void RequestReadDescriptorCallback(int conn_id, int trans_id, bt_bdaddr_t* bda,
+                         int attr_handle, int offset, bool is_long) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VLOG(2) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+          << " attr_handle: " << attr_handle << " offset: " << offset
+          << " is_long: " << is_long;
+  VERIFY_INTERFACE_OR_RETURN();
+  CHECK(bda);
+
+  FOR_EACH_SERVER_OBSERVER(RequestReadDescriptorCallback(
+      g_interface, conn_id, trans_id, *bda, attr_handle, offset, is_long));
+}
+
+void RequestWriteCharacteristicCallback(int conn_id, int trans_id,
+                          bt_bdaddr_t* bda,
+                          int attr_handle, int offset,
+                          bool need_rsp, bool is_prep,
+                          vector<uint8_t> value) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VLOG(2) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+          << " attr_handle: " << attr_handle << " offset: " << offset
+          << " length: " << value.size() << " need_rsp: " << need_rsp
+          << " is_prep: " << is_prep;
+  VERIFY_INTERFACE_OR_RETURN();
+  CHECK(bda);
+
+  FOR_EACH_SERVER_OBSERVER(RequestWriteCharacteristicCallback(
+      g_interface, conn_id, trans_id, *bda, attr_handle, offset,
+      need_rsp, is_prep, value));
+}
+
+void RequestWriteDescriptorCallback(int conn_id, int trans_id,
+                          bt_bdaddr_t* bda,
+                          int attr_handle, int offset,
+                          bool need_rsp, bool is_prep,
+                          vector<uint8_t> value) {  // NOLINT(pass-by-value)
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VLOG(2) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+          << " attr_handle: " << attr_handle << " offset: " << offset
+          << " length: " << value.size() << " need_rsp: " << need_rsp
+          << " is_prep: " << is_prep;
+  VERIFY_INTERFACE_OR_RETURN();
+  CHECK(bda);
+
+  FOR_EACH_SERVER_OBSERVER(RequestWriteDescriptorCallback(
+      g_interface, conn_id, trans_id, *bda, attr_handle, offset,
+      need_rsp, is_prep, value));
+}
+
+void RequestExecWriteCallback(int conn_id, int trans_id,
+                              bt_bdaddr_t* bda, int exec_write) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VLOG(2) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+          << " exec_write: " << exec_write;
+  VERIFY_INTERFACE_OR_RETURN();
+  CHECK(bda);
+
+  FOR_EACH_SERVER_OBSERVER(RequestExecWriteCallback(
+      g_interface, conn_id, trans_id, *bda, exec_write));
+}
+
+void ResponseConfirmationCallback(int status, int handle) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VLOG(2) << __func__ << " - status: " << status << " handle: " << handle;
+  VERIFY_INTERFACE_OR_RETURN();
+
+  FOR_EACH_SERVER_OBSERVER(ResponseConfirmationCallback(
+      g_interface, status, handle));
+}
+
+void IndicationSentCallback(int conn_id, int status) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VLOG(2) << __func__ << " - conn_id: " << conn_id << " status: " << status;
+  VERIFY_INTERFACE_OR_RETURN();
+
+  FOR_EACH_SERVER_OBSERVER(IndicationSentCallback(
+      g_interface, conn_id, status));
+}
+
+void MtuChangedCallback(int conn_id, int mtu) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VLOG(2) << __func__ << " - conn_id: " << conn_id << " mtu: " << mtu;
+  VERIFY_INTERFACE_OR_RETURN();
+
+  FOR_EACH_SERVER_OBSERVER(MtuChangedCallback(g_interface, conn_id, mtu));
+}
+
+// The HAL Bluetooth GATT client interface callbacks. These signal a mixture of
+// GATT client-role and GAP events.
+
+const btgatt_scanner_callbacks_t gatt_scanner_callbacks = {
+    RegisterScannerCallback,
+    ScanResultCallback,
+    nullptr,  // batchscan_cfg_storage_cb
+    nullptr,  // batchscan_enb_disable_cb
+    nullptr,  // batchscan_reports_cb
+    nullptr,  // batchscan_threshold_cb
+    nullptr,  // track_adv_event_cb
+    nullptr,  // scan_parameter_setup_completed_cb
+    nullptr,  // scan_filter_cfg_cb
+    nullptr,  // scan_filter_param_cb
+    nullptr,  // scan_filter_status_cb
+};
+
+const btgatt_client_callbacks_t gatt_client_callbacks = {
+    RegisterClientCallback,
+    ConnectCallback,
+    DisconnectCallback,
+    SearchCompleteCallback,
+    RegisterForNotificationCallback,
+    NotifyCallback,
+    nullptr,  // read_characteristic_cb
+    WriteCharacteristicCallback,
+    nullptr,  // read_descriptor_cb
+    WriteDescriptorCallback,
+    nullptr,  // execute_write_cb
+    nullptr,  // read_remote_rssi_cb
+    MtuChangedCallback,
+    nullptr,  // congestion_cb
+    GetGattDbCallback,
+    ServicesRemovedCallback,
+    ServicesAddedCallback,
+};
+
+const btgatt_server_callbacks_t gatt_server_callbacks = {
+    RegisterServerCallback,
+    ConnectionCallback,
+    ServiceAddedCallback,
+    ServiceStoppedCallback,
+    ServiceDeletedCallback,
+    RequestReadCharacteristicCallback,
+    RequestReadDescriptorCallback,
+    RequestWriteCharacteristicCallback,
+    RequestWriteDescriptorCallback,
+    RequestExecWriteCallback,
+    ResponseConfirmationCallback,
+    IndicationSentCallback,
+    nullptr,  // congestion_cb
+    MtuChangedCallback,
+};
+
+const btgatt_callbacks_t gatt_callbacks = {
+  sizeof(btgatt_callbacks_t),
+  &gatt_client_callbacks,
+  &gatt_server_callbacks,
+  &gatt_scanner_callbacks,
+};
+
+}  // namespace
+
+// BluetoothGattInterface implementation for production.
+class BluetoothGattInterfaceImpl : public BluetoothGattInterface {
+ public:
+  BluetoothGattInterfaceImpl() : hal_iface_(nullptr) {
+  }
+
+  ~BluetoothGattInterfaceImpl() override {
+    if (hal_iface_)
+        hal_iface_->cleanup();
+  }
+
+  void AddScannerObserver(ScannerObserver* observer) override {
+    scanner_observers_.AddObserver(observer);
+  }
+
+  void RemoveScannerObserver(ScannerObserver* observer) override {
+    scanner_observers_.RemoveObserver(observer);
+  }
+
+  void AddClientObserver(ClientObserver* observer) override {
+    client_observers_.AddObserver(observer);
+  }
+
+  void RemoveClientObserver(ClientObserver* observer) override {
+    client_observers_.RemoveObserver(observer);
+  }
+
+  void AddServerObserver(ServerObserver* observer) override {
+    server_observers_.AddObserver(observer);
+  }
+
+  void RemoveServerObserver(ServerObserver* observer) override {
+    server_observers_.RemoveObserver(observer);
+  }
+
+  BleAdvertiserInterface* GetAdvertiserHALInterface() const override {
+    return hal_iface_->advertiser;
+  }
+
+  const btgatt_scanner_interface_t* GetScannerHALInterface() const override {
+    return hal_iface_->scanner;
+  }
+
+  const btgatt_client_interface_t* GetClientHALInterface() const override {
+    return hal_iface_->client;
+  }
+
+  const btgatt_server_interface_t* GetServerHALInterface() const override {
+    return hal_iface_->server;
+  }
+
+  // Initialize the interface.
+  bool Initialize() {
+    const bt_interface_t* bt_iface =
+        BluetoothInterface::Get()->GetHALInterface();
+    CHECK(bt_iface);
+
+    const btgatt_interface_t* gatt_iface =
+        reinterpret_cast<const btgatt_interface_t*>(
+            bt_iface->get_profile_interface(BT_PROFILE_GATT_ID));
+    if (!gatt_iface) {
+      LOG(ERROR) << "Failed to obtain HAL GATT interface handle";
+      return false;
+    }
+
+    bt_status_t status = gatt_iface->init(&gatt_callbacks);
+    if (status != BT_STATUS_SUCCESS) {
+      LOG(ERROR) << "Failed to initialize HAL GATT interface";
+      return false;
+    }
+
+    hal_iface_ = gatt_iface;
+
+    return true;
+  }
+
+  base::ObserverList<ScannerObserver>* scanner_observers() {
+    return &scanner_observers_;
+  }
+
+  base::ObserverList<ClientObserver>* client_observers() {
+    return &client_observers_;
+  }
+
+  base::ObserverList<ServerObserver>* server_observers() {
+    return &server_observers_;
+  }
+
+ private:
+  // List of observers that are interested in notifications from us.
+  // We're not using a base::ObserverListThreadSafe, which it posts observer
+  // events automatically on the origin threads, as we want to avoid that
+  // overhead and simply forward the events to the upper layer.
+  base::ObserverList<ScannerObserver> scanner_observers_;
+  base::ObserverList<ClientObserver> client_observers_;
+  base::ObserverList<ServerObserver> server_observers_;
+
+  // The HAL handle obtained from the shared library. We hold a weak reference
+  // to this since the actual data resides in the shared Bluetooth library.
+  const btgatt_interface_t* hal_iface_;
+
+  DISALLOW_COPY_AND_ASSIGN(BluetoothGattInterfaceImpl);
+};
+
+namespace {
+
+base::ObserverList<BluetoothGattInterface::ScannerObserver>*
+GetScannerObservers() {
+  CHECK(g_interface);
+  return static_cast<BluetoothGattInterfaceImpl*>(
+      g_interface)->scanner_observers();
+}
+
+base::ObserverList<BluetoothGattInterface::ClientObserver>*
+GetClientObservers() {
+  CHECK(g_interface);
+  return static_cast<BluetoothGattInterfaceImpl*>(
+      g_interface)->client_observers();
+}
+
+base::ObserverList<BluetoothGattInterface::ServerObserver>*
+GetServerObservers() {
+  CHECK(g_interface);
+  return static_cast<BluetoothGattInterfaceImpl*>(
+      g_interface)->server_observers();
+}
+
+}  // namespace
+
+// Default observer implementations. These are provided so that the methods
+// themselves are optional.
+
+void BluetoothGattInterface::ScannerObserver::RegisterScannerCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* status */,
+    int /* scanner_id */,
+    const bt_uuid_t& /* app_uuid */) {
+  // Do nothing.
+}
+
+void BluetoothGattInterface::ScannerObserver::ScanResultCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    const bt_bdaddr_t& /* bda */,
+    int /* rssi */,
+    vector<uint8_t>  /* adv_data */) {  // NOLINT(pass-by-value)
+  // Do Nothing.
+}
+
+void BluetoothGattInterface::ClientObserver::RegisterClientCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* status */,
+    int /* client_if */,
+    const bt_uuid_t& /* app_uuid */) {
+  // Do nothing.
+}
+
+void BluetoothGattInterface::ClientObserver::ConnectCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* conn_id */,
+    int /* status */,
+    int /* client_if */,
+    const bt_bdaddr_t& /* bda */) {
+  // Do nothing
+}
+
+void BluetoothGattInterface::ClientObserver::DisconnectCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* conn_id */,
+    int /* status */,
+    int /* client_if */,
+    const bt_bdaddr_t& /* bda */) {
+  // Do nothing
+}
+
+void BluetoothGattInterface::ClientObserver::SearchCompleteCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* conn_id */,
+    int /* status */) {
+  // Do nothing
+}
+
+void BluetoothGattInterface::ClientObserver::RegisterForNotificationCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* conn_id */,
+    int /* status */,
+    int /* registered */,
+    uint16_t /* handle */) {
+  // Do nothing
+}
+
+void BluetoothGattInterface::ClientObserver::NotifyCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* conn_id */,
+    btgatt_notify_params_t* /* p_data */) {
+  // Do nothing
+}
+
+void BluetoothGattInterface::ClientObserver::WriteCharacteristicCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* conn_id */,
+    int /* status */,
+    uint16_t /* handle */) {
+  // Do nothing
+}
+
+void BluetoothGattInterface::ClientObserver::WriteDescriptorCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* conn_id */,
+    int /* status */,
+    uint16_t /* handle */) {
+  // Do nothing
+}
+
+void BluetoothGattInterface::ClientObserver::MtuChangedCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* conn_id */,
+    int /* statis*/,
+    int /* mtu */) {
+  // Do nothing.
+}
+
+void BluetoothGattInterface::ClientObserver::GetGattDbCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* conn_id */,
+    btgatt_db_element_t* /* gatt_db */,
+    int /* size */) {
+  // Do nothing.
+}
+
+void BluetoothGattInterface::ClientObserver::ServicesRemovedCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* conn_id */,
+    uint16_t /* start_handle */,
+    uint16_t /* end_handle */) {
+  // Do nothing.
+}
+
+void BluetoothGattInterface::ClientObserver::ServicesAddedCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* conn_id */,
+    btgatt_db_element_t* /* added */,
+    int /* added_count */) {
+  // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::RegisterServerCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* status */,
+    int /* server_if */,
+    const bt_uuid_t& /* app_uuid */) {
+  // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::ConnectionCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* conn_id */,
+    int /* server_if */,
+    int /* connected */,
+    const bt_bdaddr_t& /* bda */) {
+  // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::ServiceAddedCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* status */,
+    int /* server_if */,
+    vector<btgatt_db_element_t> /* service */) {  // NOLINT(pass-by-value)
+  // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::ServiceStoppedCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* status */,
+    int /* server_if */,
+    int /* srvc_handle */) {
+  // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::ServiceDeletedCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* status */,
+    int /* server_if */,
+    int /* srvc_handle */) {
+  // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::RequestReadCharacteristicCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* conn_id */,
+    int /* trans_id */,
+    const bt_bdaddr_t& /* bda */,
+    int /* attr_handle */,
+    int /* offset */,
+    bool /* is_long */) {
+  // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::RequestReadDescriptorCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* conn_id */,
+    int /* trans_id */,
+    const bt_bdaddr_t& /* bda */,
+    int /* attr_handle */,
+    int /* offset */,
+    bool /* is_long */) {
+  // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::RequestWriteCharacteristicCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* conn_id */,
+    int /* trans_id */,
+    const bt_bdaddr_t& /* bda */,
+    int /* attr_handle */,
+    int /* offset */,
+    bool /* need_rsp */,
+    bool /* is_prep */,
+    vector<uint8_t> /* value */) {  // NOLINT(pass-by-value)
+  // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::RequestWriteDescriptorCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* conn_id */,
+    int /* trans_id */,
+    const bt_bdaddr_t& /* bda */,
+    int /* attr_handle */,
+    int /* offset */,
+    bool /* need_rsp */,
+    bool /* is_prep */,
+    vector<uint8_t> /* value */) {  // NOLINT(pass-by-value)
+  // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::RequestExecWriteCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* conn_id */,
+    int /* trans_id */,
+    const bt_bdaddr_t& /* bda */,
+    int /* exec_write */) {
+  // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::ResponseConfirmationCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* status */,
+    int /* handle */) {
+  // Do nothing
+}
+
+void BluetoothGattInterface::ServerObserver::IndicationSentCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* conn_id */,
+    int /* status */) {
+  // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::MtuChangedCallback(
+    BluetoothGattInterface* /* gatt_iface */,
+    int /* conn_id */,
+    int /* mtu */) {
+  // Do nothing.
+}
+
+// static
+bool BluetoothGattInterface::Initialize() {
+  unique_lock<shared_timed_mutex> lock(g_instance_lock);
+  CHECK(!g_interface);
+
+  std::unique_ptr<BluetoothGattInterfaceImpl> impl(
+      new BluetoothGattInterfaceImpl());
+  if (!impl->Initialize()) {
+    LOG(ERROR) << "Failed to initialize BluetoothGattInterface";
+    return false;
+  }
+
+  g_interface = impl.release();
+
+  return true;
+}
+
+// static
+void BluetoothGattInterface::CleanUp() {
+  unique_lock<shared_timed_mutex> lock(g_instance_lock);
+  CHECK(g_interface);
+
+  delete g_interface;
+  g_interface = nullptr;
+}
+
+// static
+bool BluetoothGattInterface::IsInitialized() {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+
+  return g_interface != nullptr;
+}
+
+// static
+BluetoothGattInterface* BluetoothGattInterface::Get() {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  CHECK(g_interface);
+  return g_interface;
+}
+
+// static
+void BluetoothGattInterface::InitializeForTesting(
+    BluetoothGattInterface* test_instance) {
+  unique_lock<shared_timed_mutex> lock(g_instance_lock);
+  CHECK(test_instance);
+  CHECK(!g_interface);
+
+  g_interface = test_instance;
+}
+
+bt_status_t BluetoothGattInterface::StartScan(int client_id) {
+  lock_guard<mutex> lock(scan_clients_lock_);
+
+  // Scan already initiated for this client.
+  if (scan_client_set_.find(client_id) != scan_client_set_.end()) {
+    // Assume starting scan multiple times is not error, but warn user.
+    LOG(WARNING) << "Scan already initiated for client";
+    return BT_STATUS_SUCCESS;
+  }
+
+  // If this is the first scan client, then make a call into the stack. We
+  // only do this when the reference count changes to or from 0.
+  if (scan_client_set_.empty()) {
+    bt_status_t status = GetScannerHALInterface()->scan(true);
+    if (status != BT_STATUS_SUCCESS) {
+      LOG(ERROR) << "HAL call to scan failed";
+      return status;
+    }
+  }
+
+  scan_client_set_.insert(client_id);
+
+  return BT_STATUS_SUCCESS;
+}
+
+bt_status_t BluetoothGattInterface::StopScan(int client_id) {
+  lock_guard<mutex> lock(scan_clients_lock_);
+
+  // Scan not initiated for this client.
+  auto iter = scan_client_set_.find(client_id);
+  if (iter == scan_client_set_.end()) {
+    // Assume stopping scan multiple times is not error, but warn user.
+    LOG(WARNING) << "Scan already stopped or not initiated for client";
+    return BT_STATUS_SUCCESS;
+  }
+
+  if (scan_client_set_.size() == 1) {
+    bt_status_t status = GetScannerHALInterface()->scan(false);
+    if (status != BT_STATUS_SUCCESS) {
+      LOG(ERROR) << "HAL call to stop scan failed";
+      return status;
+    }
+  }
+
+  scan_client_set_.erase(iter);
+  return BT_STATUS_SUCCESS;
+}
+
+}  // namespace hal
+}  // namespace bluetooth
diff --git a/bt/service/hal/bluetooth_gatt_interface.h b/bt/service/hal/bluetooth_gatt_interface.h
new file mode 100644
index 0000000..2112c30
--- /dev/null
+++ b/bt/service/hal/bluetooth_gatt_interface.h
@@ -0,0 +1,308 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <mutex>
+#include <unordered_set>
+#include <vector>
+
+#include <base/macros.h>
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
+
+using namespace std;
+
+namespace bluetooth {
+namespace hal {
+
+// This class represents the standard BT-GATT interface. This class combines
+// GATT profile server and client role operations with general GAP profile
+// operations of various roles (central, scanner, peripheral, advertiser),
+// wrapping around the underlying bt_gatt_interface_t structure. A single
+// instance of this class exists per application and it allows multiple classes
+// to interface with the global HAL interface by multiplexing callbacks among
+// registered clients.
+//
+// This is declared as an abstract interface so that a fake implementation can
+// be injected for testing the upper layer.
+class BluetoothGattInterface {
+ public:
+
+  // The HAL interface doesn't allow registering "user data" that carries
+  // context beyond the callback parameters, forcing implementations to deal
+  // with global variables. The *Observer interface is to redirect these events
+  // to interested parties in an object-oriented manner.
+
+  // The standard LE scanner callback interface.
+  class ScannerObserver {
+   public:
+
+    virtual ~ScannerObserver() = default;
+
+    // All of the events below correspond to callbacks defined in
+    // "btgatt_scanner_callbacks_t" in the HAL API definitions.
+
+    virtual void RegisterScannerCallback(
+        BluetoothGattInterface* gatt_iface,
+        int status, int scanner_id,
+        const bt_uuid_t& app_uuid);
+
+    virtual void ScanResultCallback(
+        BluetoothGattInterface* gatt_iface,
+        const bt_bdaddr_t& bda, int rssi,
+        vector<uint8_t> adv_data);  // NOLINT(pass-by-value)
+  };
+
+  // The standard BT-GATT client callback interface.
+  class ClientObserver {
+   public:
+
+    virtual ~ClientObserver() = default;
+
+    // All of the events below correspond to callbacks defined in
+    // "bt_gatt_client_callbacks_t" in the HAL API definitions.
+
+    virtual void RegisterClientCallback(
+        BluetoothGattInterface* gatt_iface,
+        int status, int client_if,
+        const bt_uuid_t& app_uuid);
+
+    virtual void ConnectCallback(
+        BluetoothGattInterface* gatt_iface,
+        int conn_id,
+        int status,
+        int client_if,
+        const bt_bdaddr_t& bda);
+
+    virtual void DisconnectCallback(
+        BluetoothGattInterface* gatt_iface,
+        int conn_id,
+        int status,
+        int client_if,
+        const bt_bdaddr_t& bda);
+
+    virtual void SearchCompleteCallback(
+        BluetoothGattInterface* gatt_iface,
+        int conn_id,
+        int status);
+
+    virtual void RegisterForNotificationCallback(
+        BluetoothGattInterface* gatt_iface,
+        int conn_id, int status, int registered, uint16_t handle);
+
+    virtual void NotifyCallback(
+        BluetoothGattInterface* gatt_iface,
+        int conn_id, btgatt_notify_params_t* p_data);
+
+    virtual void WriteCharacteristicCallback(
+        BluetoothGattInterface* gatt_iface,
+        int conn_id, int status, uint16_t handle);
+
+    virtual void WriteDescriptorCallback(
+        BluetoothGattInterface* gatt_iface,
+        int conn_id, int status, uint16_t handle);
+
+    virtual void MtuChangedCallback(
+        BluetoothGattInterface* gatt_iface,
+        int conn_id, int status, int mtu);
+
+    virtual void GetGattDbCallback(
+        BluetoothGattInterface* gatt_iface,
+        int conn_id,
+        btgatt_db_element_t* gatt_db,
+        int size);
+
+    virtual void ServicesRemovedCallback(
+        BluetoothGattInterface* gatt_iface,
+        int conn_id,
+        uint16_t start_handle,
+        uint16_t end_handle);
+
+    virtual void ServicesAddedCallback(
+        BluetoothGattInterface* gatt_iface,
+        int conn_id,
+        btgatt_db_element_t *added,
+        int added_count);
+  };
+
+  // The standard BT-GATT server callback interface.
+  class ServerObserver {
+   public:
+    virtual ~ServerObserver() = default;
+
+    virtual void RegisterServerCallback(
+        BluetoothGattInterface* gatt_iface,
+        int status, int server_if,
+        const bt_uuid_t& app_uuid);
+
+    virtual void ConnectionCallback(
+        BluetoothGattInterface* gatt_iface,
+        int conn_id, int server_if,
+        int connected,
+        const bt_bdaddr_t& bda);
+
+    virtual void ServiceAddedCallback(
+        BluetoothGattInterface* gatt_iface,
+        int status, int server_if,
+        vector<btgatt_db_element_t> service);  // NOLINT(pass-by-value)
+
+    virtual void ServiceStoppedCallback(
+        BluetoothGattInterface* gatt_iface,
+        int status, int server_if,
+        int srvc_handle);
+
+    virtual void ServiceDeletedCallback(
+        BluetoothGattInterface* gatt_iface,
+        int status, int server_if,
+        int srvc_handle);
+
+    virtual void RequestReadCharacteristicCallback(
+        BluetoothGattInterface* gatt_iface,
+        int conn_id, int trans_id,
+        const bt_bdaddr_t& bda,
+        int attr_handle, int offset,
+        bool is_long);
+
+    virtual void RequestReadDescriptorCallback(
+        BluetoothGattInterface* gatt_iface,
+        int conn_id, int trans_id,
+        const bt_bdaddr_t& bda,
+        int attr_handle, int offset,
+        bool is_long);
+
+    virtual void RequestWriteCharacteristicCallback(
+        BluetoothGattInterface* gatt_iface,
+        int conn_id, int trans_id,
+        const bt_bdaddr_t& bda,
+        int attr_handle, int offset,
+        bool need_rsp, bool is_prep,
+        vector<uint8_t> value);  // NOLINT(pass-by-value)
+
+    virtual void RequestWriteDescriptorCallback(
+        BluetoothGattInterface* gatt_iface,
+        int conn_id, int trans_id,
+        const bt_bdaddr_t& bda,
+        int attr_handle, int offset,
+        bool need_rsp, bool is_prep,
+        vector<uint8_t> value);  // NOLINT(pass-by-alue)
+
+    virtual void RequestExecWriteCallback(
+        BluetoothGattInterface* gatt_iface,
+        int conn_id, int trans_id,
+        const bt_bdaddr_t& bda, int exec_write);
+
+    virtual void ResponseConfirmationCallback(
+        BluetoothGattInterface* gatt_iface,
+        int status,
+        int handle);
+
+    virtual void IndicationSentCallback(
+        BluetoothGattInterface* gatt_iface, int conn_id, int status);
+
+    virtual void MtuChangedCallback(
+        BluetoothGattInterface* gatt_iface, int conn_id, int mtu);
+  };
+
+  // Initialize and clean up the BluetoothInterface singleton. Returns false if
+  // the underlying HAL interface failed to initialize, and true on success.
+  static bool Initialize();
+
+  // Shuts down and cleans up the interface. CleanUp must be called on the same
+  // thread that called Initialize.
+  static void CleanUp();
+
+  // Returns true if the interface was initialized and a global singleton has
+  // been created.
+  static bool IsInitialized();
+
+  // Initialize for testing. Use this to inject a test version of
+  // BluetoothGattInterface. To be used from unit tests only.
+  static void InitializeForTesting(BluetoothGattInterface* test_instance);
+
+  // Returns the BluetoothGattInterface singleton. If the interface has
+  // not been initialized, returns nullptr. This method is thread-safe, in that
+  // it will block if the internal lock is being held by another thread. Don't
+  // call this re-entrantly from an observer event as this may cause a deadlock.
+  static BluetoothGattInterface* Get();
+
+  // Add or remove an observer that is interested in LE scanner interface
+  // notifications from us. Thread-safety is guaranteed by ObserverList.
+  virtual void AddScannerObserver(ScannerObserver* observer) = 0;
+  virtual void RemoveScannerObserver(ScannerObserver* observer) = 0;
+
+  // Add or remove an observer that is interested in GATT client interface
+  // notifications from us. Thread-safety is guaranteed by ObserverList.
+  virtual void AddClientObserver(ClientObserver* observer) = 0;
+  virtual void RemoveClientObserver(ClientObserver* observer) = 0;
+
+  // Add or remove an observer that is interested in GATT server interface
+  // notifications from us. Thread-safety is guaranteed by ObserverList.
+  virtual void AddServerObserver(ServerObserver* observer) = 0;
+  virtual void RemoveServerObserver(ServerObserver* observer) = 0;
+
+  // The HAL module pointer that represents the standard BT LE advertiser
+  // interface. This is implemented in and provided by the shared Bluetooth
+  // library, so this isn't owned by us.
+  //
+  // Upper layers can make ble_advertiser_interface_t API calls through this
+  // structure.
+  virtual BleAdvertiserInterface* GetAdvertiserHALInterface() const = 0;
+
+  // The HAL module pointer that represents the standard BT LE scanner
+  // interface. This is implemented in and provided by the shared Bluetooth
+  // library, so this isn't owned by us.
+  //
+  // Upper layers can make ble_scanner_interface_t API calls through this
+  // structure.
+  virtual const btgatt_scanner_interface_t* GetScannerHALInterface() const = 0;
+
+  // The HAL module pointer that represents the standard BT-GATT client
+  // interface. This is implemented in and provided by the shared Bluetooth
+  // library, so this isn't owned by us.
+  //
+  // Upper layers can make btgatt_client_interface_t API calls through this
+  // structure.
+  virtual const btgatt_client_interface_t* GetClientHALInterface() const = 0;
+
+  // The HAL module pointer that represents the standard BT-GATT server
+  // interface. This is implemented in and provided by the shared Bluetooth
+  // library, so this isn't owned by us.
+  //
+  // Upper layers can make btgatt_server_interface_t API calls through this
+  // structure.
+  virtual const btgatt_server_interface_t* GetServerHALInterface() const = 0;
+
+  // Initiates a regular BLE device scan. This is called internally from each
+  // LowEnergyClient. This function synchronizes the scan requests and maintains
+  // an internal reference count for each scan client that is interested.
+  bt_status_t StartScan(int client_id);
+  bt_status_t StopScan(int client_id);
+
+ protected:
+  BluetoothGattInterface() = default;
+  virtual ~BluetoothGattInterface() = default;
+
+ private:
+  // Used to keep a reference count for the different BLE scan clients.
+  std::mutex scan_clients_lock_;
+  std::unordered_set<int> scan_client_set_;
+
+  DISALLOW_COPY_AND_ASSIGN(BluetoothGattInterface);
+};
+
+}  // namespace hal
+}  // namespace bluetooth
diff --git a/bt/service/hal/bluetooth_interface.cc b/bt/service/hal/bluetooth_interface.cc
new file mode 100644
index 0000000..88d29c7
--- /dev/null
+++ b/bt/service/hal/bluetooth_interface.cc
@@ -0,0 +1,432 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/hal/bluetooth_interface.h"
+
+#include <mutex>
+#define _LIBCPP_BUILDING_SHARED_MUTEX
+#include <shared_mutex>
+#undef _LIBCPP_BUILDING_SHARED_MUTEX
+
+#include <base/logging.h>
+#include <base/observer_list.h>
+
+#include "service/logging_helpers.h"
+
+#include "btcore/include/hal_util.h"
+
+using std::lock_guard;
+using std::unique_lock;
+using std::shared_lock;
+using std::mutex;
+using std::shared_timed_mutex;
+
+namespace bluetooth {
+namespace hal {
+
+namespace {
+
+// The global BluetoothInterface instance.
+BluetoothInterface* g_bluetooth_interface = nullptr;
+
+// Mutex used by callbacks to access |g_interface|. If we initialize or clean it
+// use unique_lock. If only accessing |g_interface| use shared lock.
+//TODO(jpawlowski): this should be just shared_mutex, as we currently don't use
+// timed methods. Change to shared_mutex when we upgrade to C++14
+shared_timed_mutex g_instance_lock;
+
+// Helper for obtaining the observer list. This is forward declared here and
+// defined below since it depends on BluetoothInterfaceImpl.
+base::ObserverList<BluetoothInterface::Observer>* GetObservers();
+
+#define FOR_EACH_BLUETOOTH_OBSERVER(func) \
+  FOR_EACH_OBSERVER(BluetoothInterface::Observer, *GetObservers(), func)
+
+#define VERIFY_INTERFACE_OR_RETURN() \
+  do { \
+    if (!g_bluetooth_interface) { \
+      LOG(WARNING) << "Callback received while |g_interface| is NULL"; \
+      return; \
+    } \
+  } while (0)
+
+void AdapterStateChangedCallback(bt_state_t state) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VERIFY_INTERFACE_OR_RETURN();
+  VLOG(1) << "Adapter state changed: " << BtStateText(state);
+  FOR_EACH_BLUETOOTH_OBSERVER(AdapterStateChangedCallback(state));
+}
+
+void AdapterPropertiesCallback(bt_status_t status,
+                               int num_properties,
+                               bt_property_t* properties) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VERIFY_INTERFACE_OR_RETURN();
+  VLOG(1) << "Adapter properties changed - status: " << BtStatusText(status)
+          << ", num_properties: " << num_properties;
+  FOR_EACH_BLUETOOTH_OBSERVER(
+      AdapterPropertiesCallback(status, num_properties, properties));
+}
+
+void RemoteDevicePropertiesCallback(bt_status_t status,
+                               bt_bdaddr_t *remote_bd_addr,
+                               int num_properties,
+                               bt_property_t* properties) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VERIFY_INTERFACE_OR_RETURN();
+  VLOG(1) << " Remote device properties changed - status: " << BtStatusText(status)
+          << " - BD_ADDR: " << BtAddrString(remote_bd_addr)
+          << ", num_properties: " << num_properties;
+  FOR_EACH_BLUETOOTH_OBSERVER(
+      RemoteDevicePropertiesCallback(status, remote_bd_addr, num_properties,
+                                     properties));
+}
+
+void DiscoveryStateChangedCallback(bt_discovery_state_t state) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VERIFY_INTERFACE_OR_RETURN();
+  VLOG(1) << "Discovery state changed - state: " << BtDiscoveryStateText(state);
+  FOR_EACH_BLUETOOTH_OBSERVER(DiscoveryStateChangedCallback(state));
+}
+
+void PinRequestCallback(bt_bdaddr_t *remote_bd_addr, bt_bdname_t *bd_name,
+    uint32_t cod, bool min_16_digit) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VERIFY_INTERFACE_OR_RETURN();
+  VLOG(2) << __func__
+          << " - remote_bd_addr: " << remote_bd_addr
+          << " - bd_name: " << bd_name
+          << " - cod: " << cod
+          << " - min_16_digit: " << min_16_digit;
+  FOR_EACH_BLUETOOTH_OBSERVER(PinRequestCallback(remote_bd_addr, bd_name, cod, min_16_digit));
+}
+
+void SSPRequestCallback(bt_bdaddr_t *remote_bd_addr,
+    bt_bdname_t *bd_name, uint32_t cod, bt_ssp_variant_t pairing_variant, uint32_t pass_key) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VERIFY_INTERFACE_OR_RETURN();
+  VLOG(2) << __func__
+          << " - remote_bd_addr: " << remote_bd_addr
+          << " - bd_name: " << bd_name
+          << " - cod: " << cod
+          << " - pairing_variant: " << pairing_variant;
+  FOR_EACH_BLUETOOTH_OBSERVER(SSPRequestCallback(remote_bd_addr, bd_name, cod,
+      pairing_variant, pass_key));
+}
+
+void BondStateChangedCallback(
+    bt_status_t status,
+    bt_bdaddr_t *remote_bd_addr,
+    bt_bond_state_t state) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VERIFY_INTERFACE_OR_RETURN();
+  VLOG(2) << __func__
+          << " - remote_bd_addr: " << BtAddrString(remote_bd_addr)
+          << " - status: " << status
+          << " - state: " << state;
+  FOR_EACH_BLUETOOTH_OBSERVER(BondStateChangedCallback(status, remote_bd_addr, state));
+}
+
+void AclStateChangedCallback(bt_status_t status,
+                             bt_bdaddr_t *remote_bd_addr,
+                             bt_acl_state_t state) {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  VERIFY_INTERFACE_OR_RETURN();
+  CHECK(remote_bd_addr);
+  VLOG(1) << "Remote device ACL state changed - status: "
+          << BtStatusText(status)
+          << " - BD_ADDR: " << BtAddrString(remote_bd_addr)
+          << " - state: "
+          << ((state == BT_ACL_STATE_CONNECTED) ? "CONNECTED" : "DISCONNECTED");
+  FOR_EACH_BLUETOOTH_OBSERVER(
+      AclStateChangedCallback(status, *remote_bd_addr, state));
+}
+
+void ThreadEventCallback(bt_cb_thread_evt evt) {
+  VLOG(1) << "ThreadEventCallback" << BtEventText(evt);
+
+  // TODO(armansito): This callback is completely useless to us but btif borks
+  // out if this is not set. Consider making this optional.
+}
+
+bool SetWakeAlarmCallout(uint64_t /* delay_millis */,
+                         bool /* should_wake */,
+                         alarm_cb /* cb */,
+                         void* /* data */) {
+  // TODO(armansito): According to sharvil@, this interface doesn't even need to
+  // exist and can be done entirely from within osi by interfacing directly with
+  // the kernel. Remove these stubs once that's fixed. (See http://b/23390297)
+  return false;
+}
+
+int AcquireWakeLockCallout(const char* /* lock_name */) {
+  // TODO(armansito): According to sharvil@, this interface doesn't even need to
+  // exist and can be done entirely from within osi by interfacing directly with
+  // the kernel. Remove these stubs once that's fixed. (See http://b/23390297)
+  // Lie here and return success so that enabling and disabling the controller
+  // works before this is properly implemented.
+  return BT_STATUS_SUCCESS;
+}
+
+int ReleaseWakeLockCallout(const char* /* lock_name */) {
+  // TODO(armansito): According to sharvil@, this interface doesn't even need to
+  // exist and can be done entirely from within osi by interfacing directly with
+  // the kernel. Remove these stubs once that's fixed. (See http://b/23390297)
+  // Lie here and return success so that enabling and disabling the controller
+  // works before this is properly implemented.
+  return BT_STATUS_SUCCESS;
+}
+
+// The HAL Bluetooth DM callbacks.
+bt_callbacks_t bt_callbacks = {
+  sizeof(bt_callbacks_t),
+  AdapterStateChangedCallback,
+  AdapterPropertiesCallback,
+  RemoteDevicePropertiesCallback,
+  nullptr, /* device_found_cb */
+  DiscoveryStateChangedCallback,
+  PinRequestCallback,
+  SSPRequestCallback,
+  BondStateChangedCallback,
+  AclStateChangedCallback,
+  ThreadEventCallback,
+  nullptr, /* dut_mode_recv_cb */
+  nullptr, /* le_test_mode_cb */
+  nullptr  /* energy_info_cb */
+};
+
+bt_os_callouts_t bt_os_callouts = {
+  sizeof(bt_os_callouts_t),
+  SetWakeAlarmCallout,
+  AcquireWakeLockCallout,
+  ReleaseWakeLockCallout
+};
+
+}  // namespace
+
+// BluetoothInterface implementation for production.
+class BluetoothInterfaceImpl : public BluetoothInterface {
+ public:
+  BluetoothInterfaceImpl()
+      : hal_iface_(nullptr),
+        hal_adapter_(nullptr) {
+  }
+
+  ~BluetoothInterfaceImpl() override {
+    if (hal_iface_)
+        hal_iface_->cleanup();
+  }
+
+  // BluetoothInterface overrides.
+  void AddObserver(Observer* observer) override {
+    shared_lock<shared_timed_mutex> lock(g_instance_lock);
+    observers_.AddObserver(observer);
+  }
+
+  void RemoveObserver(Observer* observer) override {
+    shared_lock<shared_timed_mutex> lock(g_instance_lock);
+    observers_.RemoveObserver(observer);
+  }
+
+  const bt_interface_t* GetHALInterface() const override {
+    return hal_iface_;
+  }
+
+  const bluetooth_device_t* GetHALAdapter() const override {
+    return hal_adapter_;
+  }
+
+  // Initialize the interface. This loads the shared Bluetooth library and sets
+  // up the callbacks.
+  bool Initialize() {
+    // Load the Bluetooth shared library module.
+    const hw_module_t* module;
+    int status = hal_util_load_bt_library(&module);
+    if (status) {
+      LOG(ERROR) << "Failed to load Bluetooth library: " << status;
+      return false;
+    }
+
+    // Open the Bluetooth adapter.
+    hw_device_t* device;
+    status = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
+    if (status) {
+      LOG(ERROR) << "Failed to open the Bluetooth module";
+      return false;
+    }
+
+    hal_adapter_ = reinterpret_cast<bluetooth_device_t*>(device);
+    hal_iface_ = hal_adapter_->get_bluetooth_interface();
+
+    // Initialize the Bluetooth interface. Set up the adapter (Bluetooth DM) API
+    // callbacks.
+    status = hal_iface_->init(&bt_callbacks);
+    if (status != BT_STATUS_SUCCESS) {
+      LOG(ERROR) << "Failed to initialize Bluetooth stack";
+      return false;
+    }
+
+    status = hal_iface_->set_os_callouts(&bt_os_callouts);
+    if (status != BT_STATUS_SUCCESS) {
+      LOG(ERROR) << "Failed to set up Bluetooth OS callouts";
+      return false;
+    }
+
+    return true;
+  }
+
+  base::ObserverList<Observer>* observers() { return &observers_; }
+
+ private:
+  // List of observers that are interested in notifications from us. We're not
+  // using a base::ObserverListThreadSafe, which it posts observer events
+  // automatically on the origin threads, as we want to avoid that overhead and
+  // simply forward the events to the upper layer.
+  base::ObserverList<Observer> observers_;
+
+  // The HAL handle obtained from the shared library. We hold a weak reference
+  // to this since the actual data resides in the shared Bluetooth library.
+  const bt_interface_t* hal_iface_;
+
+  // The HAL handle that represents the underlying Bluetooth adapter. We hold a
+  // weak reference to this since the actual data resides in the shared
+  // Bluetooth library.
+  const bluetooth_device_t* hal_adapter_;
+
+  DISALLOW_COPY_AND_ASSIGN(BluetoothInterfaceImpl);
+};
+
+namespace {
+
+// Helper for obtaining the observer list from the global instance. This
+// function is NOT thread safe.
+base::ObserverList<BluetoothInterface::Observer>* GetObservers() {
+  CHECK(g_bluetooth_interface);
+  return static_cast<BluetoothInterfaceImpl*>(
+      g_bluetooth_interface)->observers();
+}
+
+}  // namespace
+
+// Default observer implementations. These are provided so that the methods
+// themselves are optional.
+void BluetoothInterface::Observer::AdapterStateChangedCallback(
+    bt_state_t /* state*/) {
+  // Do nothing.
+}
+
+void BluetoothInterface::Observer::AdapterPropertiesCallback(
+    bt_status_t /* status */,
+    int /* num_properties */,
+    bt_property_t* /* properties */) {
+  // Do nothing.
+}
+
+void BluetoothInterface::Observer::RemoteDevicePropertiesCallback(
+    bt_status_t /* status */,
+    bt_bdaddr_t* /* remote_bd_addr */,
+    int /* num_properties */,
+    bt_property_t* /* properties */) {
+  // Do nothing.
+}
+
+void BluetoothInterface::Observer::DiscoveryStateChangedCallback(
+    bt_discovery_state_t /* state */) {
+  // Do nothing.
+}
+
+void BluetoothInterface::Observer::PinRequestCallback(
+    bt_bdaddr_t *remote_bd_addr,
+    bt_bdname_t *bd_name,
+    uint32_t cod,
+    bool min_16_digit) {
+  // Do nothing.
+}
+
+void BluetoothInterface::Observer::SSPRequestCallback(
+    bt_bdaddr_t *remote_bd_addr,
+    bt_bdname_t *bd_name,
+    uint32_t cod,
+    bt_ssp_variant_t pairing_variant,
+    uint32_t pass_key) {
+  // Do nothing.
+}
+
+void BluetoothInterface::Observer::BondStateChangedCallback(
+    bt_status_t status,
+    bt_bdaddr_t *remote_bd_addr,
+    bt_bond_state_t state) {
+  // Do nothing.
+}
+
+void BluetoothInterface::Observer::AclStateChangedCallback(
+    bt_status_t /* status */,
+    const bt_bdaddr_t& /* remote_bdaddr */,
+    bt_acl_state_t /* state */) {
+  // Do nothing.
+}
+
+// static
+bool BluetoothInterface::Initialize() {
+  unique_lock<shared_timed_mutex> lock(g_instance_lock);
+  CHECK(!g_bluetooth_interface);
+
+  std::unique_ptr<BluetoothInterfaceImpl> impl(new BluetoothInterfaceImpl());
+  if (!impl->Initialize()) {
+    LOG(ERROR) << "Failed to initialize BluetoothInterface";
+    return false;
+  }
+
+  g_bluetooth_interface = impl.release();
+
+  return true;
+}
+
+// static
+void BluetoothInterface::CleanUp() {
+  unique_lock<shared_timed_mutex> lock(g_instance_lock);
+  CHECK(g_bluetooth_interface);
+
+  delete g_bluetooth_interface;
+  g_bluetooth_interface = nullptr;
+}
+
+// static
+bool BluetoothInterface::IsInitialized() {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+
+  return g_bluetooth_interface != nullptr;
+}
+
+// static
+BluetoothInterface* BluetoothInterface::Get() {
+  shared_lock<shared_timed_mutex> lock(g_instance_lock);
+  CHECK(g_bluetooth_interface);
+  return g_bluetooth_interface;
+}
+
+// static
+void BluetoothInterface::InitializeForTesting(
+    BluetoothInterface* test_instance) {
+  unique_lock<shared_timed_mutex> lock(g_instance_lock);
+  CHECK(test_instance);
+  CHECK(!g_bluetooth_interface);
+
+  g_bluetooth_interface = test_instance;
+}
+
+}  // namespace hal
+}  // namespace bluetooth
diff --git a/bt/service/hal/bluetooth_interface.h b/bt/service/hal/bluetooth_interface.h
new file mode 100644
index 0000000..34e1897
--- /dev/null
+++ b/bt/service/hal/bluetooth_interface.h
@@ -0,0 +1,127 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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/macros.h>
+#include <hardware/bluetooth.h>
+
+namespace bluetooth {
+namespace hal {
+
+// This class represents the HAL Bluetooth adapter interface, wrapping around
+// the underlying bt_interface_t structure, its methods, and callbacks. A single
+// instance of this class exists per application and it allows multiple classes
+// to interface with the global HAL interface by multiplexing callbacks among
+// registered clients.
+//
+// This is declared as an abstract interface so that a fake implementation can
+// be injected for testing the upper layer.
+//
+// TODO: (expose callback types directly but via redirection) methods for
+// initialize, clean up, and set for testing.
+class BluetoothInterface {
+ public:
+  // The standard Bluetooth adapter management callback interface. The HAL
+  // interface doesn't allow registering "user data" that carries context beyond
+  // the callback parameters, forcing implementations to deal with global
+  // variables. The Observer interface is to redirect these events to interested
+  // parties in an object-oriented manner.
+  //
+  // TODO(armansito): We should fix this in the HAL.
+  class Observer {
+   public:
+    virtual ~Observer() = default;
+
+    // All of the events below correspond to callbacks defined in
+    // "bt_callbacks_t" in the HAL API definitions.
+
+    virtual void AdapterStateChangedCallback(bt_state_t state);
+    virtual void AdapterPropertiesCallback(bt_status_t status,
+                                           int num_properties,
+                                           bt_property_t* properties);
+    virtual void RemoteDevicePropertiesCallback(bt_status_t status,
+                                                bt_bdaddr_t *remote_bd_addr,
+                                                int num_properties,
+                                                bt_property_t* properties);
+    virtual void DiscoveryStateChangedCallback(bt_discovery_state_t state);
+    virtual void PinRequestCallback(bt_bdaddr_t *remote_bd_addr,
+                                    bt_bdname_t *bd_name,
+                                    uint32_t cod,
+                                    bool min_16_digit);
+    virtual void SSPRequestCallback(bt_bdaddr_t *remote_bd_addr,
+                                    bt_bdname_t *bd_name,
+                                    uint32_t cod,
+                                    bt_ssp_variant_t pairing_variant,
+                                    uint32_t pass_key);
+    virtual void BondStateChangedCallback(bt_status_t status,
+                                          bt_bdaddr_t *remote_bd_addr,
+                                          bt_bond_state_t state);
+    virtual void AclStateChangedCallback(bt_status_t status,
+                                         const bt_bdaddr_t& remote_bdaddr,
+                                         bt_acl_state_t state);
+
+    // TODO(armansito): Complete the list of callbacks.
+  };
+
+  // Initialize and clean up the BluetoothInterface singleton. Returns false if
+  // the underlying HAL interface failed to initialize, and true on success.
+  static bool Initialize();
+
+  // Shuts down and cleans up the interface. CleanUp must be called on the same
+  // thread that called Initialize.
+  static void CleanUp();
+
+  // Returns true if the interface was initialized and a global singleton has
+  // been created.
+  static bool IsInitialized();
+
+  // Initialize for testing. Use this to inject a test version of
+  // BlueoothInterface. To be used from unit tests only.
+  static void InitializeForTesting(BluetoothInterface* test_instance);
+
+  // Returns the BluetoothInterface singleton. If the interface has not been
+  // initialized, returns nullptr.
+  static BluetoothInterface* Get();
+
+  // Add or remove an observer that is interested in notifications from us.
+  virtual void AddObserver(Observer* observer) = 0;
+  virtual void RemoveObserver(Observer* observer) = 0;
+
+  // The HAL module pointer that represents the standard Bluetooth adapter
+  // management interface. This is implemented in and provided by the shared
+  // Bluetooth library, so this isn't owned by us.
+  //
+  // Upper layers can make bt_interface_t API calls through this structure.
+  // However, DO NOT call the "init" function as this is called and managed by
+  // us. The behavior is undefined if "init" is called directly by upper layers.
+  virtual const bt_interface_t* GetHALInterface() const = 0;
+
+  // The HAL module pointer that represents the underlying Bluetooth adapter.
+  // This is implemented in and provided by the shared Bluetooth library, so
+  // this isn't owned by us.
+  virtual const bluetooth_device_t* GetHALAdapter() const = 0;
+
+ protected:
+  BluetoothInterface() = default;
+  virtual ~BluetoothInterface() = default;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BluetoothInterface);
+};
+
+}  // namespace hal
+}  // namespace bluetooth
diff --git a/bt/service/hal/fake_bluetooth_gatt_interface.cc b/bt/service/hal/fake_bluetooth_gatt_interface.cc
new file mode 100644
index 0000000..dbbd533
--- /dev/null
+++ b/bt/service/hal/fake_bluetooth_gatt_interface.cc
@@ -0,0 +1,383 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/hal/fake_bluetooth_gatt_interface.h"
+
+namespace bluetooth {
+namespace hal {
+namespace {
+
+// The global test handler instances. We have to have globals since the HAL
+// interface methods all have to be global and their signatures don't allow us
+// to pass in user_data.
+std::shared_ptr<BleAdvertiserInterface> g_advertiser_handler;
+std::shared_ptr<FakeBluetoothGattInterface::TestScannerHandler> g_scanner_handler;
+std::shared_ptr<FakeBluetoothGattInterface::TestClientHandler> g_client_handler;
+std::shared_ptr<FakeBluetoothGattInterface::TestServerHandler> g_server_handler;
+
+bt_status_t FakeRegisterClient(bt_uuid_t* app_uuid) {
+  if (g_client_handler)
+    return g_client_handler->RegisterClient(app_uuid);
+
+  return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeUnregisterClient(int client_if) {
+  if (g_client_handler)
+    return g_client_handler->UnregisterClient(client_if);
+
+  return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeRegisterScanner(bt_uuid_t* app_uuid) {
+  if (g_scanner_handler)
+    return g_scanner_handler->RegisterScanner(app_uuid);
+
+  return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeUnregisterScanner(int client_if) {
+  if (g_scanner_handler)
+    return g_scanner_handler->UnregisterScanner(client_if);
+
+  return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeScan(bool start) {
+  if (g_scanner_handler)
+    return g_scanner_handler->Scan(start);
+
+  return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeConnect(int client_if, const bt_bdaddr_t *bd_addr,
+                        bool is_direct, int transport) {
+  if (g_client_handler)
+    return g_client_handler->Connect(client_if, bd_addr, is_direct, transport);
+
+  return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeDisconnect(int client_if, const bt_bdaddr_t *bd_addr,
+                           int conn_id) {
+  if (g_client_handler)
+    return g_client_handler->Disconnect(client_if, bd_addr, conn_id);
+
+  return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeRegisterServer(bt_uuid_t* app_uuid) {
+  if (g_server_handler)
+    return g_server_handler->RegisterServer(app_uuid);
+
+  return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeUnregisterServer(int server_if) {
+  if (g_server_handler)
+    return g_server_handler->UnregisterServer(server_if);
+
+  return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeAddService(
+    int server_if, vector<btgatt_db_element_t> service) {
+  if (g_server_handler)
+    return g_server_handler->AddService(server_if, std::move(service));
+
+  return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeDeleteService(int server_if, int srvc_handle) {
+  if (g_server_handler)
+    return g_server_handler->DeleteService(server_if, srvc_handle);
+
+  return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeSendIndication(int server_if, int attribute_handle,
+                               int conn_id, int confirm,
+                               vector<uint8_t> value) {
+  if (g_server_handler)
+    return g_server_handler->SendIndication(server_if, attribute_handle,
+                                            conn_id, confirm, std::move(value));
+
+  return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeSendResponse(int conn_id, int trans_id, int status,
+                             btgatt_response_t* response) {
+  if (g_server_handler)
+    return g_server_handler->SendResponse(conn_id, trans_id, status, response);
+
+  return BT_STATUS_FAIL;
+}
+
+btgatt_scanner_interface_t fake_scanner_iface = {
+  FakeRegisterScanner,
+  FakeUnregisterScanner,
+  FakeScan,
+  nullptr,  // scan_filter_param_setup
+  nullptr,  // scan_filter_add_remove
+  nullptr,  // scan_filter_clear
+  nullptr,  // scan_filter_enable
+  nullptr,  // set_scan_parameters
+  nullptr,  // batchscan_cfg_storate
+  nullptr,  // batchscan_enb_batch_scan
+  nullptr,  // batchscan_dis_batch_scan
+  nullptr,  // batchscan_read_reports
+};
+
+btgatt_client_interface_t fake_btgattc_iface = {
+  FakeRegisterClient,
+  FakeUnregisterClient,
+  FakeConnect,
+  FakeDisconnect,
+  nullptr,  // refresh
+  nullptr,  // search_service
+  nullptr,  // read_characteristic
+  nullptr,  // write_characteristic
+  nullptr,  // read_descriptor
+  nullptr,  // write_descriptor
+  nullptr,  // execute_write
+  nullptr,  // register_for_notification
+  nullptr,  // deregister_for_notification
+  nullptr,  // read_remote_rssi
+  nullptr,  // get_device_type
+  nullptr,  // configure_mtu
+  nullptr,  // conn_parameter_update
+  nullptr,  // test_command
+  nullptr,  // get_gatt_db
+};
+
+btgatt_server_interface_t fake_btgatts_iface = {
+  FakeRegisterServer,
+  FakeUnregisterServer,
+  nullptr,  // connect
+  nullptr,  // disconnect
+  FakeAddService,
+  nullptr,  // stop_service
+  FakeDeleteService,
+  FakeSendIndication,
+  FakeSendResponse,
+};
+
+}  // namespace
+
+FakeBluetoothGattInterface::FakeBluetoothGattInterface(
+    std::shared_ptr<BleAdvertiserInterface> advertiser_handler,
+    std::shared_ptr<TestScannerHandler> scanner_handler,
+    std::shared_ptr<TestClientHandler> client_handler,
+    std::shared_ptr<TestServerHandler> server_handler)
+    : client_handler_(client_handler) {
+  CHECK(!g_advertiser_handler);
+  CHECK(!g_scanner_handler);
+  CHECK(!g_client_handler);
+  CHECK(!g_server_handler);
+
+  // We allow passing NULL. In this case all calls we fail by default.
+  if (advertiser_handler)
+    g_advertiser_handler = advertiser_handler;
+
+  if (scanner_handler)
+    g_scanner_handler = scanner_handler;
+
+  if (client_handler)
+    g_client_handler = client_handler;
+
+  if (server_handler)
+    g_server_handler = server_handler;
+}
+
+FakeBluetoothGattInterface::~FakeBluetoothGattInterface() {
+  if (g_advertiser_handler)
+    g_advertiser_handler = nullptr;
+
+  if (g_scanner_handler)
+    g_scanner_handler = nullptr;
+
+  if (g_client_handler)
+    g_client_handler = nullptr;
+
+  if (g_server_handler)
+    g_server_handler = nullptr;
+}
+
+// The methods below can be used to notify observers with certain events and
+// given parameters.
+void FakeBluetoothGattInterface::NotifyRegisterScannerCallback(
+    int status, int client_if,
+    const bt_uuid_t& app_uuid) {
+  FOR_EACH_OBSERVER(ScannerObserver, scanner_observers_,
+                    RegisterScannerCallback(this, status, client_if, app_uuid));
+}
+
+void FakeBluetoothGattInterface::NotifyScanResultCallback(
+    const bt_bdaddr_t& bda, int rssi, vector<uint8_t> adv_data) {
+  FOR_EACH_OBSERVER(ScannerObserver, scanner_observers_,
+                    ScanResultCallback(this, bda, rssi, adv_data));
+}
+
+void FakeBluetoothGattInterface::NotifyRegisterClientCallback(
+    int status, int client_if,
+    const bt_uuid_t& app_uuid) {
+  FOR_EACH_OBSERVER(ClientObserver, client_observers_,
+                    RegisterClientCallback(this, status, client_if, app_uuid));
+}
+
+void FakeBluetoothGattInterface::NotifyConnectCallback(
+    int conn_id, int status, int client_if, const bt_bdaddr_t& bda) {
+  FOR_EACH_OBSERVER(ClientObserver, client_observers_,
+                    ConnectCallback(this, conn_id, status, client_if, bda));
+}
+
+void FakeBluetoothGattInterface::NotifyDisconnectCallback(
+    int conn_id, int status, int client_if, const bt_bdaddr_t& bda) {
+  FOR_EACH_OBSERVER(ClientObserver, client_observers_,
+                    DisconnectCallback(this, conn_id, status, client_if, bda));
+}
+
+void FakeBluetoothGattInterface::NotifyRegisterServerCallback(
+    int status, int server_if,
+    const bt_uuid_t& app_uuid) {
+  FOR_EACH_OBSERVER(ServerObserver, server_observers_,
+                    RegisterServerCallback(this, status, server_if, app_uuid));
+}
+
+void FakeBluetoothGattInterface::NotifyServerConnectionCallback(
+    int conn_id, int server_if, int connected, const bt_bdaddr_t& bda) {
+  FOR_EACH_OBSERVER(
+      ServerObserver, server_observers_,
+      ConnectionCallback(this, conn_id, server_if, connected, bda));
+}
+
+void FakeBluetoothGattInterface::NotifyServiceAddedCallback(
+    int status, int server_if,
+    vector<btgatt_db_element_t> service) {
+  FOR_EACH_OBSERVER(
+      ServerObserver, server_observers_,
+      ServiceAddedCallback(this, status, server_if, service));
+}
+
+void FakeBluetoothGattInterface::NotifyRequestReadCharacteristicCallback(
+    int conn_id, int trans_id, const bt_bdaddr_t& bda, int attr_handle,
+    int offset, bool is_long) {
+  FOR_EACH_OBSERVER(
+      ServerObserver, server_observers_,
+      RequestReadCharacteristicCallback(
+          this, conn_id, trans_id, bda, attr_handle, offset, is_long));
+}
+
+void FakeBluetoothGattInterface::NotifyRequestReadDescriptorCallback(
+    int conn_id, int trans_id, const bt_bdaddr_t& bda, int attr_handle,
+    int offset, bool is_long) {
+  FOR_EACH_OBSERVER(
+      ServerObserver, server_observers_,
+      RequestReadDescriptorCallback(
+          this, conn_id, trans_id, bda, attr_handle, offset, is_long));
+}
+
+void FakeBluetoothGattInterface::NotifyRequestWriteCharacteristicCallback(
+    int conn_id, int trans_id, const bt_bdaddr_t& bda, int attr_handle,
+    int offset, bool need_rsp, bool is_prep, vector<uint8_t> value) {
+  FOR_EACH_OBSERVER(
+      ServerObserver, server_observers_,
+      RequestWriteCharacteristicCallback(
+          this, conn_id, trans_id, bda, attr_handle, offset, need_rsp,
+          is_prep, value));
+}
+
+void FakeBluetoothGattInterface::NotifyRequestWriteDescriptorCallback(
+    int conn_id, int trans_id,
+    const bt_bdaddr_t& bda, int attr_handle,
+    int offset, bool need_rsp, bool is_prep,
+    vector<uint8_t> value) {
+  FOR_EACH_OBSERVER(
+      ServerObserver, server_observers_,
+      RequestWriteDescriptorCallback(
+          this, conn_id, trans_id, bda, attr_handle, offset, need_rsp,
+          is_prep, value));
+}
+
+void FakeBluetoothGattInterface::NotifyRequestExecWriteCallback(
+    int conn_id, int trans_id, const bt_bdaddr_t& bda, int exec_write) {
+  FOR_EACH_OBSERVER(
+      ServerObserver, server_observers_,
+      RequestExecWriteCallback(this, conn_id, trans_id, bda, exec_write));
+}
+
+void FakeBluetoothGattInterface::NotifyIndicationSentCallback(
+    int conn_id, int status) {
+  FOR_EACH_OBSERVER(ServerObserver, server_observers_,
+                    IndicationSentCallback(this, conn_id, status));
+}
+
+void FakeBluetoothGattInterface::AddScannerObserver(ScannerObserver* observer) {
+  CHECK(observer);
+  scanner_observers_.AddObserver(observer);
+}
+
+void FakeBluetoothGattInterface::RemoveScannerObserver(
+    ScannerObserver* observer) {
+  CHECK(observer);
+  scanner_observers_.RemoveObserver(observer);
+}
+
+void FakeBluetoothGattInterface::AddClientObserver(ClientObserver* observer) {
+  CHECK(observer);
+  client_observers_.AddObserver(observer);
+}
+
+void FakeBluetoothGattInterface::RemoveClientObserver(
+    ClientObserver* observer) {
+  CHECK(observer);
+  client_observers_.RemoveObserver(observer);
+}
+
+void FakeBluetoothGattInterface::AddServerObserver(ServerObserver* observer) {
+  CHECK(observer);
+  server_observers_.AddObserver(observer);
+}
+
+void FakeBluetoothGattInterface::RemoveServerObserver(
+    ServerObserver* observer) {
+  CHECK(observer);
+  server_observers_.RemoveObserver(observer);
+}
+
+BleAdvertiserInterface* FakeBluetoothGattInterface::GetAdvertiserHALInterface()
+    const {
+  return g_advertiser_handler.get();
+}
+
+const btgatt_scanner_interface_t*
+FakeBluetoothGattInterface::GetScannerHALInterface() const {
+  return &fake_scanner_iface;
+}
+
+
+const btgatt_client_interface_t*
+FakeBluetoothGattInterface::GetClientHALInterface() const {
+  return &fake_btgattc_iface;
+}
+
+const btgatt_server_interface_t*
+FakeBluetoothGattInterface::GetServerHALInterface() const {
+  return &fake_btgatts_iface;
+}
+
+}  // namespace hal
+}  // namespace bluetooth
diff --git a/bt/service/hal/fake_bluetooth_gatt_interface.h b/bt/service/hal/fake_bluetooth_gatt_interface.h
new file mode 100644
index 0000000..363e053
--- /dev/null
+++ b/bt/service/hal/fake_bluetooth_gatt_interface.h
@@ -0,0 +1,161 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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/macros.h>
+#include <base/observer_list.h>
+
+#include "service/hal/bluetooth_gatt_interface.h"
+
+namespace bluetooth {
+namespace hal {
+
+class FakeBluetoothGattInterface : public BluetoothGattInterface {
+ public:
+
+  // Handles HAL LE scanner API calls for testing. Test code can
+  // provide a fake or mock implementation of this and all calls will be routed
+  // to it.
+  class TestScannerHandler {
+   public:
+    virtual ~TestScannerHandler() = default;
+
+    virtual bt_status_t RegisterScanner(bt_uuid_t* app_uuid) = 0;
+    virtual bt_status_t UnregisterScanner(int client_if) = 0;
+
+    virtual bt_status_t Scan(bool start) = 0;
+  };
+
+  // Handles HAL Bluetooth GATT client API calls for testing. Test code can
+  // provide a fake or mock implementation of this and all calls will be routed
+  // to it.
+  class TestClientHandler {
+   public:
+    virtual ~TestClientHandler() = default;
+
+    virtual bt_status_t RegisterClient(bt_uuid_t* app_uuid) = 0;
+    virtual bt_status_t UnregisterClient(int client_if) = 0;
+
+    virtual bt_status_t Connect(int client_if, const bt_bdaddr_t *bd_addr,
+                                bool is_direct, int transport) = 0;
+    virtual bt_status_t Disconnect(int client_if, const bt_bdaddr_t *bd_addr,
+                                   int conn_id) = 0;
+  };
+
+  // Handles HAL Bluetooth GATT server API calls for testing. Test code can
+  // provide a fake or mock implementation of this and all calls will be routed
+  // to it.
+  class TestServerHandler {
+   public:
+    virtual ~TestServerHandler() = default;
+
+    virtual bt_status_t RegisterServer(bt_uuid_t* app_uuid) = 0;
+    virtual bt_status_t UnregisterServer(int server_if) = 0;
+    virtual bt_status_t AddService(
+        int server_if, vector<btgatt_db_element_t> service) = 0;
+    virtual bt_status_t DeleteService(int server_if, int srvc_handle) = 0;
+    virtual bt_status_t SendIndication(int server_if, int attribute_handle,
+                                       int conn_id, int confirm,
+                                       vector<uint8_t> value) = 0;
+    virtual bt_status_t SendResponse(int conn_id, int trans_id, int status,
+                                     btgatt_response_t* response) = 0;
+  };
+
+  // Constructs the fake with the given handlers. Implementations can
+  // provide their own handlers or simply pass "nullptr" for the default
+  // behavior in which BT_STATUS_FAIL will be returned from all calls.
+  FakeBluetoothGattInterface(std::shared_ptr<BleAdvertiserInterface> advertiser_handler,
+                             std::shared_ptr<TestScannerHandler> scanner_handler,
+                             std::shared_ptr<TestClientHandler> client_handler,
+                             std::shared_ptr<TestServerHandler> server_handler);
+  ~FakeBluetoothGattInterface();
+
+  // The methods below can be used to notify observers with certain events and
+  // given parameters.
+
+  void NotifyRegisterScannerCallback(int status, int client_if,
+                                    const bt_uuid_t& app_uuid);
+  void NotifyScanResultCallback(const bt_bdaddr_t& bda, int rssi,
+                                vector<uint8_t> adv_data);
+
+  // Client callbacks:
+  void NotifyRegisterClientCallback(int status, int client_if,
+                                    const bt_uuid_t& app_uuid);
+  void NotifyConnectCallback(int conn_id, int status, int client_if,
+                             const bt_bdaddr_t& bda);
+  void NotifyDisconnectCallback(int conn_id, int status, int client_if,
+                                const bt_bdaddr_t& bda);
+
+  // Server callbacks:
+  void NotifyRegisterServerCallback(int status, int server_if,
+                                    const bt_uuid_t& app_uuid);
+  void NotifyServerConnectionCallback(int conn_id, int server_if,
+                                      int connected,
+                                      const bt_bdaddr_t& bda);
+  void NotifyServiceAddedCallback(int status, int server_if,
+                                  vector<btgatt_db_element_t> srvc);
+  void NotifyCharacteristicAddedCallback(int status, int server_if,
+                                         const bt_uuid_t& uuid,
+                                         int srvc_handle, int char_handle);
+  void NotifyDescriptorAddedCallback(int status, int server_if,
+                                     const bt_uuid_t& uuid,
+                                     int srvc_handle, int desc_handle);
+  void NotifyServiceStartedCallback(int status, int server_if, int srvc_handle);
+  void NotifyRequestReadCharacteristicCallback(int conn_id, int trans_id,
+                                 const bt_bdaddr_t& bda, int attr_handle,
+                                 int offset, bool is_long);
+  void NotifyRequestReadDescriptorCallback(int conn_id, int trans_id,
+                                 const bt_bdaddr_t& bda, int attr_handle,
+                                 int offset, bool is_long);
+  void NotifyRequestWriteCharacteristicCallback(int conn_id, int trans_id,
+                                  const bt_bdaddr_t& bda, int attr_handle,
+                                  int offset, bool need_rsp, bool is_prep,
+                                  vector<uint8_t> value);
+  void NotifyRequestWriteDescriptorCallback(int conn_id, int trans_id,
+                                  const bt_bdaddr_t& bda, int attr_handle,
+                                  int offset, bool need_rsp, bool is_prep,
+                                  vector<uint8_t> value);
+  void NotifyRequestExecWriteCallback(int conn_id, int trans_id,
+                                      const bt_bdaddr_t& bda, int exec_write);
+  void NotifyIndicationSentCallback(int conn_id, int status);
+
+  // BluetoothGattInterface overrides:
+  void AddScannerObserver(ScannerObserver* observer) override;
+  void RemoveScannerObserver(ScannerObserver* observer) override;
+  void AddClientObserver(ClientObserver* observer) override;
+  void RemoveClientObserver(ClientObserver* observer) override;
+  void AddServerObserver(ServerObserver* observer) override;
+  void RemoveServerObserver(ServerObserver* observer) override;
+  BleAdvertiserInterface* GetAdvertiserHALInterface() const override;
+  const btgatt_scanner_interface_t* GetScannerHALInterface() const override;
+  const btgatt_client_interface_t* GetClientHALInterface() const override;
+  const btgatt_server_interface_t* GetServerHALInterface() const override;
+
+ private:
+  base::ObserverList<ScannerObserver> scanner_observers_;
+  base::ObserverList<ClientObserver> client_observers_;
+  base::ObserverList<ServerObserver> server_observers_;
+  std::shared_ptr<TestScannerHandler> scanner_handler_;
+  std::shared_ptr<TestClientHandler> client_handler_;
+  std::shared_ptr<TestServerHandler> server_handler_;
+
+
+  DISALLOW_COPY_AND_ASSIGN(FakeBluetoothGattInterface);
+};
+
+}  // namespace hal
+}  // namespace bluetooth
diff --git a/bt/service/hal/fake_bluetooth_interface.cc b/bt/service/hal/fake_bluetooth_interface.cc
new file mode 100644
index 0000000..5036c63
--- /dev/null
+++ b/bt/service/hal/fake_bluetooth_interface.cc
@@ -0,0 +1,168 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/hal/fake_bluetooth_interface.h"
+
+namespace bluetooth {
+namespace hal {
+
+namespace {
+
+FakeBluetoothInterface::Manager g_hal_manager;
+
+int FakeHALEnable(bool start_restricted) {
+  return g_hal_manager.enable_succeed ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+int FakeHALDisable() {
+  return g_hal_manager.disable_succeed ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+int FakeHALGetAdapterProperties() {
+  return BT_STATUS_SUCCESS;
+}
+
+int FakeHALSetAdapterProperty(const bt_property_t* /* property */) {
+  LOG(INFO) << __func__;
+  return (g_hal_manager.set_property_succeed ? BT_STATUS_SUCCESS :
+          BT_STATUS_FAIL);
+}
+
+bt_interface_t fake_bt_iface = {
+  sizeof(bt_interface_t),
+  nullptr, /* init */
+  FakeHALEnable,
+  FakeHALDisable,
+  nullptr, /* cleanup */
+  FakeHALGetAdapterProperties,
+  nullptr, /* get_adapter_property */
+  FakeHALSetAdapterProperty,
+  nullptr, /* get_remote_device_properties */
+  nullptr, /* get_remote_device_property */
+  nullptr, /* set_remote_device_property */
+  nullptr, /* get_remote_service_record */
+  nullptr, /* get_remote_services */
+  nullptr, /* start_discovery */
+  nullptr, /* cancel_discovery */
+  nullptr, /* create_bond */
+  nullptr, /* create_bond_out_of_band */
+  nullptr, /* remove_bond */
+  nullptr, /* cancel_bond */
+  nullptr, /* get_connection_state */
+  nullptr, /* pin_reply */
+  nullptr, /* ssp_reply */
+  nullptr, /* get_profile_interface */
+  nullptr, /* dut_mode_configure */
+  nullptr, /* dut_more_send */
+  nullptr, /* le_test_mode */
+  nullptr, /* config_hci_snoop_log */
+  nullptr, /* set_os_callouts */
+  nullptr, /* read_energy_info */
+  nullptr, /* dump */
+  nullptr, /* config clear */
+  nullptr, /* interop_database_clear */
+  nullptr  /* interop_database_add */
+};
+
+}  // namespace
+
+// static
+FakeBluetoothInterface::Manager* FakeBluetoothInterface::GetManager() {
+  return &g_hal_manager;
+}
+
+FakeBluetoothInterface::Manager::Manager()
+    : enable_succeed(false),
+      disable_succeed(false),
+      set_property_succeed(false) {
+}
+
+void FakeBluetoothInterface::NotifyAdapterStateChanged(bt_state_t state) {
+  FOR_EACH_OBSERVER(Observer, observers_, AdapterStateChangedCallback(state));
+}
+
+void FakeBluetoothInterface::NotifyAdapterPropertiesChanged(
+    int num_properties,
+    bt_property_t* properties) {
+  FOR_EACH_OBSERVER(
+      Observer, observers_,
+      AdapterPropertiesCallback(BT_STATUS_SUCCESS, num_properties, properties));
+}
+
+void FakeBluetoothInterface::NotifyAdapterNamePropertyChanged(
+    const std::string& name) {
+  bt_bdname_t hal_name;
+  strncpy(reinterpret_cast<char*>(hal_name.name),
+          name.c_str(),
+          std::min(sizeof(hal_name)-1, name.length()));
+  reinterpret_cast<char*>(hal_name.name)[name.length()] = '\0';
+
+  bt_property_t property;
+  property.len = sizeof(hal_name);
+  property.val = &hal_name;
+  property.type = BT_PROPERTY_BDNAME;
+
+  NotifyAdapterPropertiesChanged(1, &property);
+}
+
+void FakeBluetoothInterface::NotifyAdapterAddressPropertyChanged(
+    const bt_bdaddr_t* address) {
+  bt_property_t property;
+  property.len = sizeof(bt_bdaddr_t);
+  property.val = (void*)address;
+  property.type = BT_PROPERTY_BDADDR;
+
+  NotifyAdapterPropertiesChanged(1, &property);
+}
+
+void FakeBluetoothInterface::NotifyAdapterLocalLeFeaturesPropertyChanged(
+      const bt_local_le_features_t* features) {
+  bt_property_t property;
+  property.len = sizeof(*features);
+  property.val = (void*)features;
+  property.type = BT_PROPERTY_LOCAL_LE_FEATURES;
+
+  NotifyAdapterPropertiesChanged(1, &property);
+}
+
+void FakeBluetoothInterface::NotifyAclStateChangedCallback(
+    bt_status_t status,
+    const bt_bdaddr_t& remote_bdaddr,
+    bt_acl_state_t state) {
+  FOR_EACH_OBSERVER(
+      Observer, observers_,
+      AclStateChangedCallback(status, remote_bdaddr, state));
+}
+
+void FakeBluetoothInterface::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void FakeBluetoothInterface::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+const bt_interface_t* FakeBluetoothInterface::GetHALInterface() const {
+  return &fake_bt_iface;
+}
+
+const bluetooth_device_t* FakeBluetoothInterface::GetHALAdapter() const {
+  // TODO(armansito): Do something meaningful here to simulate test behavior.
+  return nullptr;
+}
+
+}  // namespace hal
+}  // namespace bluetooth
diff --git a/bt/service/hal/fake_bluetooth_interface.h b/bt/service/hal/fake_bluetooth_interface.h
new file mode 100644
index 0000000..553d4e0
--- /dev/null
+++ b/bt/service/hal/fake_bluetooth_interface.h
@@ -0,0 +1,75 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 <base/macros.h>
+#include <base/observer_list.h>
+
+#include "service/hal/bluetooth_interface.h"
+
+namespace bluetooth {
+namespace hal {
+
+class FakeBluetoothInterface : public BluetoothInterface {
+ public:
+  // A Fake HAL Bluetooth interface. This is kept as a global singleton as the
+  // Bluetooth HAL doesn't support anything otherwise.
+  //
+  // TODO(armansito): Use an abstract "TestHandler" interface instead.
+  struct Manager {
+    Manager();
+    ~Manager() = default;
+
+    // Values that should be returned from bt_interface_t methods.
+    bool enable_succeed;
+    bool disable_succeed;
+    bool set_property_succeed;
+  };
+
+  // Returns the global Manager.
+  static Manager* GetManager();
+
+  FakeBluetoothInterface() = default;
+  ~FakeBluetoothInterface() override = default;
+
+  // Notifies the observers that the adapter state changed to |state|.
+  void NotifyAdapterStateChanged(bt_state_t state);
+
+  // Triggers an adapter property change event.
+  void NotifyAdapterPropertiesChanged(int num_properties,
+                                      bt_property_t* properties);
+  void NotifyAdapterNamePropertyChanged(const std::string& name);
+  void NotifyAdapterAddressPropertyChanged(const bt_bdaddr_t* address);
+  void NotifyAdapterLocalLeFeaturesPropertyChanged(
+      const bt_local_le_features_t* features);
+  void NotifyAclStateChangedCallback(
+      bt_status_t status,
+      const bt_bdaddr_t& remote_bdaddr,
+      bt_acl_state_t state);
+
+  // hal::BluetoothInterface overrides:
+  void AddObserver(Observer* observer) override;
+  void RemoveObserver(Observer* observer) override;
+  const bt_interface_t* GetHALInterface() const override;
+  const bluetooth_device_t* GetHALAdapter() const override;
+
+ private:
+  base::ObserverList<Observer> observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeBluetoothInterface);
+};
+
+}  // namespace hal
+}  // namespace bluetooth
diff --git a/bt/service/ipc/binder/bluetooth_binder_server.cc b/bt/service/ipc/binder/bluetooth_binder_server.cc
new file mode 100644
index 0000000..953f974
--- /dev/null
+++ b/bt/service/ipc/binder/bluetooth_binder_server.cc
@@ -0,0 +1,251 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/ipc/binder/bluetooth_binder_server.h"
+
+#include <base/logging.h>
+
+#include "service/ipc/binder/bluetooth_gatt_client_binder_server.h"
+#include "service/ipc/binder/bluetooth_gatt_server_binder_server.h"
+#include "service/ipc/binder/bluetooth_low_energy_binder_server.h"
+#include "service/ipc/binder/bluetooth_le_advertiser_binder_server.h"
+#include "service/ipc/binder/bluetooth_le_scanner_binder_server.h"
+
+#include "service/hal/bluetooth_interface.h"
+
+using android::sp;
+using android::String8;
+using android::String16;
+
+using android::bluetooth::IBluetoothCallback;
+using android::bluetooth::IBluetoothGattClient;
+using android::bluetooth::IBluetoothGattServer;
+
+namespace ipc {
+namespace binder {
+
+BluetoothBinderServer::BluetoothBinderServer(bluetooth::Adapter* adapter)
+    : adapter_(adapter) {
+  CHECK(adapter_);
+  adapter_->AddObserver(this);
+}
+
+BluetoothBinderServer::~BluetoothBinderServer() {
+  adapter_->RemoveObserver(this);
+}
+
+// binder::BnBluetooth overrides:
+Status BluetoothBinderServer::IsEnabled(bool* _aidl_return) {
+  VLOG(2) << __func__;
+  *_aidl_return = adapter_->IsEnabled();
+  return Status::ok();
+}
+
+Status BluetoothBinderServer::GetState(int32_t* _aidl_return) {
+  VLOG(2) << __func__;
+  *_aidl_return = adapter_->GetState();
+  return Status::ok();
+}
+
+Status BluetoothBinderServer::Enable(bool start_restricted, bool* _aidl_return) {
+  VLOG(2) << __func__;
+  *_aidl_return = adapter_->Enable(start_restricted);
+  return Status::ok();
+}
+
+Status BluetoothBinderServer::EnableNoAutoConnect(bool* _aidl_return) {
+  VLOG(2) << __func__;
+  // TODO(armansito): Implement.
+  *_aidl_return = false;
+  return Status::ok();
+}
+
+Status BluetoothBinderServer::Disable(bool* _aidl_return) {
+  VLOG(2) << __func__;
+  *_aidl_return = adapter_->Disable();
+  return Status::ok();
+}
+
+Status BluetoothBinderServer::GetAddress(::android::String16* _aidl_return) {
+  VLOG(2) << __func__;
+  *_aidl_return = String16(String8(adapter_->GetAddress().c_str()));
+  return Status::ok();
+}
+
+Status BluetoothBinderServer::GetUUIDs(
+    ::std::vector<::android::bluetooth::UUID>* _aidl_return) {
+  VLOG(2) << __func__;
+  // TODO(armansito): Implement.
+  *_aidl_return = std::vector<android::bluetooth::UUID>();
+  return Status::ok();
+}
+
+Status BluetoothBinderServer::SetName(const ::android::String16& name,
+                                      bool* _aidl_return) {
+  VLOG(2) << __func__;
+  *_aidl_return = adapter_->SetName(std::string(String8(name).string()));
+  return Status::ok();
+}
+
+Status BluetoothBinderServer::GetName(::android::String16* _aidl_return) {
+  VLOG(2) << __func__;
+  *_aidl_return = String16(String8(adapter_->GetName().c_str()));
+  return Status::ok();
+}
+
+Status BluetoothBinderServer::RegisterCallback(
+    const ::android::sp<IBluetoothCallback>& callback) {
+  VLOG(2) << __func__;
+  if (!callback.get()) {
+    LOG(ERROR) << "RegisterCallback called with NULL binder. Ignoring.";
+    return Status::ok();
+  }
+  callbacks_.Register(callback);
+  return Status::ok();
+}
+
+Status BluetoothBinderServer::UnregisterCallback(
+    const ::android::sp<IBluetoothCallback>& callback) {
+  VLOG(2) << __func__;
+  if (!callback.get()) {
+    LOG(ERROR) << "UnregisterCallback called with NULL binder. Ignoring.";
+    return Status::ok();
+  }
+  callbacks_.Unregister(callback);
+  return Status::ok();
+}
+
+Status BluetoothBinderServer::IsMultiAdvertisementSupported(
+    bool* _aidl_return) {
+  VLOG(2) << __func__;
+  *_aidl_return = adapter_->IsMultiAdvertisementSupported();
+  return Status::ok();
+}
+
+Status BluetoothBinderServer::GetLowEnergyInterface(
+    ::android::sp<IBluetoothLowEnergy>* _aidl_return) {
+  VLOG(2) << __func__;
+
+  if (!adapter_->IsEnabled()) {
+    LOG(ERROR) << "Cannot obtain IBluetoothLowEnergy interface while disabled";
+    *_aidl_return = NULL;
+    return Status::ok();
+  }
+
+  if (!low_energy_interface_.get())
+    low_energy_interface_ = new BluetoothLowEnergyBinderServer(adapter_);
+
+  *_aidl_return = low_energy_interface_;
+  return Status::ok();
+}
+
+Status BluetoothBinderServer::GetLeAdvertiserInterface(
+    ::android::sp<IBluetoothLeAdvertiser>* _aidl_return) {
+  VLOG(2) << __func__;
+
+  if (!adapter_->IsEnabled()) {
+    LOG(ERROR) << "Cannot obtain IBluetoothLeAdvertiser interface while disabled";
+    *_aidl_return = NULL;
+    return Status::ok();
+  }
+
+  if (!le_advertiser_interface_.get())
+    le_advertiser_interface_ = new BluetoothLeAdvertiserBinderServer(adapter_);
+
+  *_aidl_return = le_advertiser_interface_;
+  return Status::ok();
+}
+
+Status BluetoothBinderServer::GetLeScannerInterface(
+    ::android::sp<IBluetoothLeScanner>* _aidl_return) {
+  VLOG(2) << __func__;
+
+  if (!adapter_->IsEnabled()) {
+    LOG(ERROR) << "Cannot obtain IBluetoothLeScanner interface while disabled";
+    *_aidl_return = NULL;
+    return Status::ok();
+  }
+
+  if (!le_scanner_interface_.get())
+    le_scanner_interface_ = new BluetoothLeScannerBinderServer(adapter_);
+
+  *_aidl_return = le_scanner_interface_;
+  return Status::ok();
+}
+
+Status BluetoothBinderServer::GetGattClientInterface(
+    ::android::sp<IBluetoothGattClient>* _aidl_return) {
+  VLOG(2) << __func__;
+
+  if (!adapter_->IsEnabled()) {
+    LOG(ERROR) << "Cannot obtain IBluetoothGattClient interface while disabled";
+    *_aidl_return = NULL;
+    return Status::ok();
+  }
+
+  if (!gatt_client_interface_.get())
+    gatt_client_interface_ = new BluetoothGattClientBinderServer(adapter_);
+
+  *_aidl_return = gatt_client_interface_;
+  return Status::ok();
+}
+
+Status BluetoothBinderServer::GetGattServerInterface(
+    ::android::sp<IBluetoothGattServer>* _aidl_return) {
+  VLOG(2) << __func__;
+
+  if (!adapter_->IsEnabled()) {
+    LOG(ERROR) << "Cannot obtain IBluetoothGattServer interface while disabled";
+    *_aidl_return = NULL;
+    return Status::ok();
+  }
+
+  if (!gatt_server_interface_.get())
+    gatt_server_interface_ = new BluetoothGattServerBinderServer(adapter_);
+
+  *_aidl_return = gatt_server_interface_;
+  return Status::ok();
+}
+
+android::status_t BluetoothBinderServer::dump(
+    int fd, const android::Vector<android::String16>& args) {
+  VLOG(2) << __func__ << " called with fd " << fd;
+  if (args.size() > 0) {
+    // TODO (jamuraa): Parse arguments and switch on --proto, --proto_text
+    for (const auto& x : args) {
+      VLOG(2) << __func__ << "argument: " << x.string();
+    }
+  }
+  // TODO (jamuraa): enumerate profiles and dump profile information
+  const bt_interface_t* iface =
+      bluetooth::hal::BluetoothInterface::Get()->GetHALInterface();
+  iface->dump(fd, NULL);
+  return android::NO_ERROR;
+}
+
+void BluetoothBinderServer::OnAdapterStateChanged(
+    bluetooth::Adapter* adapter, bluetooth::AdapterState prev_state,
+    bluetooth::AdapterState new_state) {
+  CHECK_EQ(adapter, adapter_);
+  VLOG(2) << "Received adapter state update - prev: " << prev_state
+          << " new: " << new_state;
+  callbacks_.ForEach([prev_state, new_state](IBluetoothCallback* callback) {
+    callback->OnBluetoothStateChange(prev_state, new_state);
+  });
+}
+
+}  // namespace binder
+}  // namespace ipc
diff --git a/bt/service/ipc/binder/bluetooth_binder_server.h b/bt/service/ipc/binder/bluetooth_binder_server.h
new file mode 100644
index 0000000..5bb794e
--- /dev/null
+++ b/bt/service/ipc/binder/bluetooth_binder_server.h
@@ -0,0 +1,124 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <vector>
+
+#include <base/macros.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+#include <android/bluetooth/BnBluetooth.h>
+#include <android/bluetooth/IBluetoothCallback.h>
+#include <android/bluetooth/IBluetoothGattClient.h>
+#include <android/bluetooth/IBluetoothGattServer.h>
+#include <android/bluetooth/IBluetoothLowEnergy.h>
+#include <android/bluetooth/IBluetoothLeAdvertiser.h>
+#include <android/bluetooth/IBluetoothLeScanner.h>
+
+#include "service/adapter.h"
+#include "service/common/bluetooth/uuid.h"
+#include "service/ipc/binder/remote_callback_list.h"
+
+using android::String16;
+using android::binder::Status;
+
+using android::bluetooth::BnBluetooth;
+using android::bluetooth::IBluetoothCallback;
+using android::bluetooth::IBluetoothGattClient;
+using android::bluetooth::IBluetoothGattServer;
+using android::bluetooth::IBluetoothLowEnergy;
+using android::bluetooth::IBluetoothLeAdvertiser;
+using android::bluetooth::IBluetoothLeScanner;
+
+namespace ipc {
+namespace binder {
+
+// Implements the server side of the IBluetooth Binder interface.
+class BluetoothBinderServer : public BnBluetooth,
+                              public bluetooth::Adapter::Observer {
+ public:
+  explicit BluetoothBinderServer(bluetooth::Adapter* adapter);
+  ~BluetoothBinderServer() override;
+
+  // IBluetooth overrides:
+  Status IsEnabled(bool* _aidl_return) override;
+  Status GetState(int32_t* _aidl_return) override;
+  Status Enable(bool start_restricted, bool* _aidl_return) override;
+  Status EnableNoAutoConnect(bool* _aidl_return) override;
+  Status Disable(bool* _aidl_return) override;
+
+  Status GetAddress(::android::String16* _aidl_return) override;
+  Status GetUUIDs(
+      ::std::vector<::android::bluetooth::UUID>* _aidl_return) override;
+  Status SetName(const ::android::String16& name, bool* _aidl_return) override;
+  Status GetName(::android::String16* _aidl_return) override;
+
+  Status RegisterCallback(
+      const ::android::sp<IBluetoothCallback>& callback) override;
+  Status UnregisterCallback(
+      const ::android::sp<IBluetoothCallback>& callback) override;
+  Status IsMultiAdvertisementSupported(bool* _aidl_return) override;
+  Status GetLowEnergyInterface(
+      ::android::sp<IBluetoothLowEnergy>* _aidl_return) override;
+  Status GetLeAdvertiserInterface(
+      ::android::sp<IBluetoothLeAdvertiser>* _aidl_return) override;
+  Status GetLeScannerInterface(
+      ::android::sp<IBluetoothLeScanner>* _aidl_return) override;
+  Status GetGattClientInterface(
+      ::android::sp<IBluetoothGattClient>* _aidl_return) override;
+  Status GetGattServerInterface(
+      ::android::sp<IBluetoothGattServer>* _aidl_return) override;
+
+  android::status_t dump(
+      int fd, const android::Vector<android::String16>& args) override;
+
+  // bluetooth::Adapter::Observer overrides:
+  void OnAdapterStateChanged(bluetooth::Adapter* adapter,
+                             bluetooth::AdapterState prev_state,
+                             bluetooth::AdapterState new_state) override;
+
+ private:
+  bluetooth::Adapter* adapter_;  // weak
+  RemoteCallbackList<IBluetoothCallback> callbacks_;
+
+  // The IBluetoothLowEnergy interface handle. This is lazily initialized on the
+  // first call to GetLowEnergyInterface().
+  android::sp<IBluetoothLowEnergy> low_energy_interface_;
+
+  // The IBluetoothLeAdvertiser interface handle. This is lazily initialized on the
+  // first call to GetLeAdvertiserInterface().
+  android::sp<IBluetoothLeAdvertiser> le_advertiser_interface_;
+
+  // The IBluetoothLeScanner interface handle. This is lazily initialized on the
+  // first call to GetLeScannerInterface().
+  android::sp<IBluetoothLeScanner> le_scanner_interface_;
+
+  // The IBluetoothGattClient interface handle. This is lazily initialized on
+  // the first call to GetGattClientInterface().
+  android::sp<IBluetoothGattClient> gatt_client_interface_;
+
+  // The IBluetoothGattServer interface handle. This is lazily initialized on
+  // the first call to GetGattServerInterface().
+  android::sp<IBluetoothGattServer> gatt_server_interface_;
+
+  DISALLOW_COPY_AND_ASSIGN(BluetoothBinderServer);
+};
+
+}  // namespace binder
+}  // namespace ipc
diff --git a/bt/service/ipc/binder/bluetooth_gatt_client_binder_server.cc b/bt/service/ipc/binder/bluetooth_gatt_client_binder_server.cc
new file mode 100644
index 0000000..77a5f75
--- /dev/null
+++ b/bt/service/ipc/binder/bluetooth_gatt_client_binder_server.cc
@@ -0,0 +1,89 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/ipc/binder/bluetooth_gatt_client_binder_server.h"
+
+#include <base/logging.h>
+
+#include "service/adapter.h"
+
+using android::bluetooth::IBluetoothGattClientCallback;
+
+namespace ipc {
+namespace binder {
+
+namespace {
+const int kInvalidInstanceId = -1;
+}  // namespace
+
+BluetoothGattClientBinderServer::BluetoothGattClientBinderServer(
+    bluetooth::Adapter* adapter)
+    : adapter_(adapter) {
+  CHECK(adapter_);
+}
+
+Status BluetoothGattClientBinderServer::RegisterClient(
+    const android::sp<IBluetoothGattClientCallback>& callback,
+    bool* _aidl_return) {
+  VLOG(2) << __func__;
+
+  bluetooth::GattClientFactory* gatt_client_factory =
+      adapter_->GetGattClientFactory();
+
+  *_aidl_return = RegisterInstanceBase(callback, gatt_client_factory);
+  return Status::ok();
+}
+
+Status BluetoothGattClientBinderServer::UnregisterClient(int client_id) {
+  VLOG(2) << __func__;
+  UnregisterInstanceBase(client_id);
+  return Status::ok();
+}
+
+Status BluetoothGattClientBinderServer::UnregisterAll() {
+  VLOG(2) << __func__;
+  UnregisterAllBase();
+  return Status::ok();
+}
+
+android::sp<IBluetoothGattClientCallback>
+BluetoothGattClientBinderServer::GetGattClientCallback(int client_id) {
+  auto cb = GetCallback(client_id);
+  return android::sp<IBluetoothGattClientCallback>(
+      static_cast<IBluetoothGattClientCallback*>(cb.get()));
+}
+
+std::shared_ptr<bluetooth::GattClient>
+BluetoothGattClientBinderServer::GetGattClient(int client_id) {
+  return std::static_pointer_cast<bluetooth::GattClient>(
+      GetInstance(client_id));
+}
+
+void BluetoothGattClientBinderServer::OnRegisterInstanceImpl(
+    bluetooth::BLEStatus status, android::sp<IInterface> callback,
+    bluetooth::BluetoothInstance* instance) {
+  VLOG(1) << __func__ << " client ID: " << instance->GetInstanceId()
+          << " status: " << status;
+
+  android::sp<IBluetoothGattClientCallback> cb(
+      static_cast<IBluetoothGattClientCallback*>(callback.get()));
+  cb->OnClientRegistered(status, (status == bluetooth::BLE_STATUS_SUCCESS)
+                                     ? instance->GetInstanceId()
+                                     : kInvalidInstanceId);
+}
+
+}  // namespace binder
+}  // namespace ipc
diff --git a/bt/service/ipc/binder/bluetooth_gatt_client_binder_server.h b/bt/service/ipc/binder/bluetooth_gatt_client_binder_server.h
new file mode 100644
index 0000000..390b0ad
--- /dev/null
+++ b/bt/service/ipc/binder/bluetooth_gatt_client_binder_server.h
@@ -0,0 +1,75 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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/macros.h>
+
+#include <android/bluetooth/BnBluetoothGattClient.h>
+#include <android/bluetooth/IBluetoothGattClientCallback.h>
+
+#include "service/gatt_client.h"
+#include "service/ipc/binder/interface_with_instances_base.h"
+
+using android::bluetooth::BnBluetoothGattClient;
+using android::bluetooth::IBluetoothGattClientCallback;
+
+using ::android::binder::Status;
+
+namespace bluetooth {
+class Adapter;
+}  // namespace bluetooth
+
+namespace ipc {
+namespace binder {
+
+// Implements the server side of the IBluetoothGattClient interface.
+class BluetoothGattClientBinderServer : public BnBluetoothGattClient,
+                                        public InterfaceWithInstancesBase {
+ public:
+  explicit BluetoothGattClientBinderServer(bluetooth::Adapter* adapter);
+  ~BluetoothGattClientBinderServer() override = default;
+
+  // IBluetoothGattClient overrides:
+  Status RegisterClient(
+      const android::sp<IBluetoothGattClientCallback>& callback,
+      bool* _aidl_return) override;
+  Status UnregisterClient(int client_id) override;
+  Status UnregisterAll() override;
+
+ private:
+  // Returns a pointer to the IBluetoothGattClientCallback instance
+  // associated with |client_id|. Returns NULL if such a callback cannot be
+  // found.
+  android::sp<IBluetoothGattClientCallback> GetGattClientCallback(
+      int client_id);
+
+  // Returns a pointer to the GattClient instance associated with |client_id|.
+  // Returns NULL if such a client cannot be found.
+  std::shared_ptr<bluetooth::GattClient> GetGattClient(int client_id);
+
+  // InterfaceWithInstancesBase override:
+  void OnRegisterInstanceImpl(bluetooth::BLEStatus status,
+                              android::sp<IInterface> callback,
+                              bluetooth::BluetoothInstance* instance) override;
+
+  bluetooth::Adapter* adapter_;  // weak
+
+  DISALLOW_COPY_AND_ASSIGN(BluetoothGattClientBinderServer);
+};
+
+}  // namespace binder
+}  // namespace ipc
diff --git a/bt/service/ipc/binder/bluetooth_gatt_server_binder_server.cc b/bt/service/ipc/binder/bluetooth_gatt_server_binder_server.cc
new file mode 100644
index 0000000..228e9cb
--- /dev/null
+++ b/bt/service/ipc/binder/bluetooth_gatt_server_binder_server.cc
@@ -0,0 +1,308 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/ipc/binder/bluetooth_gatt_server_binder_server.h"
+
+#include <base/logging.h>
+
+#include "service/adapter.h"
+
+using ::android::String8;
+using ::android::String16;
+using ::android::binder::Status;
+
+using ::android::bluetooth::IBluetoothGattServerCallback;
+
+namespace ipc {
+namespace binder {
+
+namespace {
+const int kInvalidInstanceId = -1;
+}  // namespace
+
+BluetoothGattServerBinderServer::BluetoothGattServerBinderServer(
+    bluetooth::Adapter* adapter)
+    : adapter_(adapter) {
+  CHECK(adapter_);
+}
+
+Status BluetoothGattServerBinderServer::RegisterServer(
+    const ::android::sp<IBluetoothGattServerCallback>& callback,
+    bool* _aidl_return) {
+  VLOG(2) << __func__;
+  bluetooth::GattServerFactory* gatt_server_factory =
+      adapter_->GetGattServerFactory();
+
+  *_aidl_return = RegisterInstanceBase(callback, gatt_server_factory);
+  return Status::ok();
+}
+
+Status BluetoothGattServerBinderServer::UnregisterServer(int server_id) {
+  VLOG(2) << __func__;
+  UnregisterInstanceBase(server_id);
+  return Status::ok();
+}
+
+Status BluetoothGattServerBinderServer::UnregisterAll() {
+  VLOG(2) << __func__;
+  UnregisterAllBase();
+  return Status::ok();
+}
+
+Status BluetoothGattServerBinderServer::AddService(
+    int server_id, const android::bluetooth::BluetoothGattService& service,
+    bool* _aidl_return) {
+  VLOG(2) << __func__;
+  std::lock_guard<std::mutex> lock(*maps_lock());
+
+  auto gatt_server = GetGattServer(server_id);
+  if (!gatt_server) {
+    LOG(ERROR) << "Unknown server_id: " << server_id;
+    *_aidl_return = false;
+    return Status::ok();
+  }
+
+  // Create a weak pointer and pass that to the callback to prevent a potential
+  // use after free.
+  android::wp<BluetoothGattServerBinderServer> weak_ptr_to_this(this);
+  auto callback = [=](bluetooth::BLEStatus status,
+                      const bluetooth::Service& service) {
+    auto sp_to_this = weak_ptr_to_this.promote();
+    if (!sp_to_this.get()) {
+      VLOG(2) << "BluetoothLowEnergyBinderServer was deleted";
+      return;
+    }
+
+    std::lock_guard<std::mutex> lock(*maps_lock());
+
+    auto gatt_cb = GetGattServerCallback(server_id);
+    if (!gatt_cb.get()) {
+      VLOG(2) << "The callback was deleted";
+      return;
+    }
+
+    gatt_cb->OnServiceAdded(status, service);
+  };
+
+  if (!gatt_server->AddService(service, callback)) {
+    LOG(ERROR) << "Failed to add service";
+    *_aidl_return = false;
+    return Status::ok();
+  }
+
+  *_aidl_return = true;
+  return Status::ok();
+}
+
+Status BluetoothGattServerBinderServer::SendResponse(
+    int server_id, const String16& device_address, int request_id, int status,
+    int offset, const std::vector<uint8_t>& value, bool* _aidl_return) {
+  VLOG(2) << __func__;
+  std::lock_guard<std::mutex> lock(*maps_lock());
+
+  auto gatt_server = GetGattServer(server_id);
+  if (!gatt_server) {
+    LOG(ERROR) << "Unknown server_id: " << server_id;
+    *_aidl_return = false;
+    return Status::ok();
+  }
+
+  *_aidl_return = gatt_server->SendResponse(
+      std::string(String8(device_address).string()), request_id,
+      static_cast<bluetooth::GATTError>(status), offset, value);
+
+  return Status::ok();
+}
+
+Status BluetoothGattServerBinderServer::SendNotification(
+    int server_id, const String16& device_address, int handle, bool confirm,
+    const std::vector<uint8_t>& value, bool* _aidl_return) {
+  VLOG(2) << __func__;
+  std::lock_guard<std::mutex> lock(*maps_lock());
+
+  auto gatt_server = GetGattServer(server_id);
+  if (!gatt_server) {
+    LOG(ERROR) << "Unknown server_id: " << server_id;
+    *_aidl_return = false;
+    return Status::ok();
+  }
+
+  // Create a weak pointer and pass that to the callback to prevent a potential
+  // use after free.
+  android::wp<BluetoothGattServerBinderServer> weak_ptr_to_this(this);
+  auto callback = [=](bluetooth::GATTError error) {
+    auto sp_to_this = weak_ptr_to_this.promote();
+    if (!sp_to_this.get()) {
+      VLOG(2) << "BluetoothLowEnergyBinderServer was deleted";
+      return;
+    }
+
+    std::lock_guard<std::mutex> lock(*maps_lock());
+
+    auto gatt_cb = GetGattServerCallback(server_id);
+    if (!gatt_cb.get()) {
+      VLOG(2) << "The callback was deleted";
+      return;
+    }
+
+    gatt_cb->OnNotificationSent(device_address, error);
+  };
+
+  if (!gatt_server->SendNotification(
+          std::string(String8(device_address).string()), handle,
+          confirm, value, callback)) {
+    LOG(ERROR) << "Failed to send notification";
+    *_aidl_return = false;
+    return Status::ok();
+  }
+
+  *_aidl_return = true;
+  return Status::ok();
+}
+
+void BluetoothGattServerBinderServer::OnCharacteristicReadRequest(
+    bluetooth::GattServer* gatt_server, const std::string& device_address,
+    int request_id, int offset, bool is_long, uint16_t handle) {
+  VLOG(2) << __func__;
+  std::lock_guard<std::mutex> lock(*maps_lock());
+
+  auto gatt_cb = GetGattServerCallback(gatt_server->GetInstanceId());
+  if (!gatt_cb.get()) {
+    LOG(WARNING) << "Callback for this GattServer was deleted.";
+    return;
+  }
+
+  gatt_cb->OnCharacteristicReadRequest(
+      String16(device_address.c_str(), device_address.length()), request_id,
+      offset, is_long, handle);
+}
+
+void BluetoothGattServerBinderServer::OnDescriptorReadRequest(
+    bluetooth::GattServer* gatt_server, const std::string& device_address,
+    int request_id, int offset, bool is_long, uint16_t handle) {
+  VLOG(2) << __func__;
+  std::lock_guard<std::mutex> lock(*maps_lock());
+
+  auto gatt_cb = GetGattServerCallback(gatt_server->GetInstanceId());
+  if (!gatt_cb.get()) {
+    LOG(WARNING) << "Callback for this GattServer was deleted.";
+    return;
+  }
+
+  gatt_cb->OnDescriptorReadRequest(
+      String16(device_address.c_str(), device_address.length()), request_id,
+      offset, is_long, handle);
+}
+
+android::sp<IBluetoothGattServerCallback>
+BluetoothGattServerBinderServer::GetGattServerCallback(int server_id) {
+  auto cb = GetCallback(server_id);
+  return android::sp<IBluetoothGattServerCallback>(
+      static_cast<IBluetoothGattServerCallback*>(cb.get()));
+}
+
+std::shared_ptr<bluetooth::GattServer>
+BluetoothGattServerBinderServer::GetGattServer(int server_id) {
+  return std::static_pointer_cast<bluetooth::GattServer>(
+      GetInstance(server_id));
+}
+
+void BluetoothGattServerBinderServer::OnRegisterInstanceImpl(
+    bluetooth::BLEStatus status, android::sp<IInterface> callback,
+    bluetooth::BluetoothInstance* instance) {
+  VLOG(1) << __func__ << " instance ID: " << instance->GetInstanceId()
+          << " status: " << status;
+  bluetooth::GattServer* gatt_server =
+      static_cast<bluetooth::GattServer*>(instance);
+  gatt_server->SetDelegate(this);
+
+  android::sp<IBluetoothGattServerCallback> cb(
+      static_cast<IBluetoothGattServerCallback*>(callback.get()));
+  cb->OnServerRegistered(status, (status == bluetooth::BLE_STATUS_SUCCESS)
+                                     ? instance->GetInstanceId()
+                                     : kInvalidInstanceId);
+}
+
+void BluetoothGattServerBinderServer::OnCharacteristicWriteRequest(
+    bluetooth::GattServer* gatt_server, const std::string& device_address,
+    int request_id, int offset, bool is_prepare_write, bool need_response,
+    const std::vector<uint8_t>& value, uint16_t handle) {
+  VLOG(2) << __func__;
+  std::lock_guard<std::mutex> lock(*maps_lock());
+
+  auto gatt_cb = GetGattServerCallback(gatt_server->GetInstanceId());
+  if (!gatt_cb.get()) {
+    LOG(WARNING) << "Callback for this GattServer was deleted.";
+    return;
+  }
+
+  gatt_cb->OnCharacteristicWriteRequest(
+      String16(device_address.c_str(), device_address.length()), request_id,
+      offset, is_prepare_write, need_response, value, handle);
+}
+
+void BluetoothGattServerBinderServer::OnDescriptorWriteRequest(
+    bluetooth::GattServer* gatt_server, const std::string& device_address,
+    int request_id, int offset, bool is_prepare_write, bool need_response,
+    const std::vector<uint8_t>& value, uint16_t handle) {
+  VLOG(2) << __func__;
+  std::lock_guard<std::mutex> lock(*maps_lock());
+
+  auto gatt_cb = GetGattServerCallback(gatt_server->GetInstanceId());
+  if (!gatt_cb.get()) {
+    LOG(WARNING) << "Callback for this GattServer was deleted.";
+    return;
+  }
+
+  gatt_cb->OnDescriptorWriteRequest(
+      String16(device_address.c_str(), device_address.length()), request_id,
+      offset, is_prepare_write, need_response, value, handle);
+}
+
+void BluetoothGattServerBinderServer::OnExecuteWriteRequest(
+    bluetooth::GattServer* gatt_server, const std::string& device_address,
+    int request_id, bool is_execute) {
+  VLOG(2) << __func__;
+  std::lock_guard<std::mutex> lock(*maps_lock());
+
+  auto gatt_cb = GetGattServerCallback(gatt_server->GetInstanceId());
+  if (!gatt_cb.get()) {
+    LOG(WARNING) << "Callback for this GattServer was deleted.";
+    return;
+  }
+
+  gatt_cb->OnExecuteWriteRequest(
+      String16(device_address.c_str(), device_address.length()), request_id,
+      is_execute);
+}
+
+void BluetoothGattServerBinderServer::OnConnectionStateChanged(
+    bluetooth::GattServer* gatt_server, const std::string& device_address, bool connected) {
+  VLOG(2) << __func__;
+  std::lock_guard<std::mutex> lock(*maps_lock());
+
+  auto gatt_cb = GetGattServerCallback(gatt_server->GetInstanceId());
+  if (!gatt_cb.get()) {
+    LOG(WARNING) << "Callback for this GattServer was deleted.";
+    return;
+  }
+
+  gatt_cb->OnConnectionStateChanged(
+      String16(device_address.c_str(), device_address.length()), connected);
+}
+
+}  // namespace binder
+}  // namespace ipc
diff --git a/bt/service/ipc/binder/bluetooth_gatt_server_binder_server.h b/bt/service/ipc/binder/bluetooth_gatt_server_binder_server.h
new file mode 100644
index 0000000..0d8f1d9
--- /dev/null
+++ b/bt/service/ipc/binder/bluetooth_gatt_server_binder_server.h
@@ -0,0 +1,110 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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/macros.h>
+
+#include <android/bluetooth/BnBluetoothGattServer.h>
+#include <android/bluetooth/IBluetoothGattServerCallback.h>
+
+#include "service/gatt_server.h"
+#include "service/ipc/binder/interface_with_instances_base.h"
+
+using android::bluetooth::BnBluetoothGattServer;
+using android::bluetooth::IBluetoothGattServerCallback;
+
+using ::android::binder::Status;
+
+namespace bluetooth {
+class Adapter;
+}  // namespace bluetooth
+
+namespace ipc {
+namespace binder {
+
+// Implements the server side of the IBluetoothGattServer interface.
+class BluetoothGattServerBinderServer : public BnBluetoothGattServer,
+                                        public InterfaceWithInstancesBase,
+                                        public bluetooth::GattServer::Delegate {
+ public:
+  explicit BluetoothGattServerBinderServer(bluetooth::Adapter* adapter);
+  ~BluetoothGattServerBinderServer() override = default;
+
+  // IBluetoothGattServer overrides:
+  Status RegisterServer(
+      const ::android::sp<::android::bluetooth::IBluetoothGattServerCallback>&
+          callback,
+      bool* _aidl_return) override;
+  Status UnregisterServer(int32_t server_id) override;
+  Status UnregisterAll() override;
+  Status AddService(int32_t server_id, const ::android::bluetooth::BluetoothGattService& service,
+                    bool* _aidl_return) override;
+  Status SendResponse(int32_t server_id,
+                      const ::android::String16& device_address,
+                      int32_t request_id, int32_t status, int32_t offset,
+                      const ::std::vector<uint8_t>& value,
+                      bool* _aidl_return) override;
+  Status SendNotification(
+      int32_t server_id, const ::android::String16& device_address,
+      int handle, bool confirm, const ::std::vector<uint8_t>& value,
+      bool* _aidl_return) override;
+
+  // bluetooth::GattServer::Delegate overrides:
+  void OnCharacteristicReadRequest(
+      bluetooth::GattServer* gatt_server, const std::string& device_address,
+      int request_id, int offset, bool is_long, uint16_t handle) override;
+  void OnDescriptorReadRequest(
+      bluetooth::GattServer* gatt_server, const std::string& device_address,
+      int request_id, int offset, bool is_long, uint16_t handle) override;
+  void OnCharacteristicWriteRequest(
+      bluetooth::GattServer* gatt_server, const std::string& device_address,
+      int request_id, int offset, bool is_prepare_write, bool need_response,
+      const std::vector<uint8_t>& value, uint16_t handle) override;
+  void OnDescriptorWriteRequest(
+      bluetooth::GattServer* gatt_server, const std::string& device_address,
+      int request_id, int offset, bool is_prepare_write, bool need_response,
+      const std::vector<uint8_t>& value, uint16_t handle) override;
+  void OnExecuteWriteRequest(bluetooth::GattServer* gatt_server,
+                             const std::string& device_address, int request_id,
+                             bool is_execute) override;
+  void OnConnectionStateChanged(bluetooth::GattServer* gatt_server,
+                                const std::string& device_addres,
+                                bool connected) override;
+
+ private:
+  // Returns a pointer to the IBluetoothGattServerCallback instance
+  // associated with |server_id|. Returns NULL if such a callback cannot be
+  // found.
+  android::sp<IBluetoothGattServerCallback> GetGattServerCallback(
+      int server_id);
+
+  // Returns a pointer to the GattServer instance associated with |server_id|.
+  // Returns NULL if such an instance cannot be found.
+  std::shared_ptr<bluetooth::GattServer> GetGattServer(int server_id);
+
+  // InterfaceWithInstancesBase override:
+  void OnRegisterInstanceImpl(bluetooth::BLEStatus status,
+                              android::sp<IInterface> callback,
+                              bluetooth::BluetoothInstance* instance) override;
+
+  bluetooth::Adapter* adapter_;  // weak
+
+  DISALLOW_COPY_AND_ASSIGN(BluetoothGattServerBinderServer);
+};
+
+}  // namespace binder
+}  // namespace ipc
diff --git a/bt/service/ipc/binder/bluetooth_le_advertiser_binder_server.cc b/bt/service/ipc/binder/bluetooth_le_advertiser_binder_server.cc
new file mode 100644
index 0000000..a992c32
--- /dev/null
+++ b/bt/service/ipc/binder/bluetooth_le_advertiser_binder_server.cc
@@ -0,0 +1,182 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/ipc/binder/bluetooth_le_advertiser_binder_server.h"
+
+#include <base/logging.h>
+
+#include "service/adapter.h"
+
+using android::String8;
+using android::String16;
+using android::binder::Status;
+
+namespace ipc {
+namespace binder {
+
+namespace {
+const int kInvalidInstanceId = -1;
+}  // namespace
+
+BluetoothLeAdvertiserBinderServer::BluetoothLeAdvertiserBinderServer(
+    bluetooth::Adapter* adapter)
+    : adapter_(adapter) {
+  CHECK(adapter_);
+}
+
+BluetoothLeAdvertiserBinderServer::~BluetoothLeAdvertiserBinderServer() {}
+
+Status BluetoothLeAdvertiserBinderServer::RegisterAdvertiser(
+    const android::sp<IBluetoothLeAdvertiserCallback>& callback,
+    bool* _aidl_return) {
+  VLOG(2) << __func__;
+  bluetooth::LowEnergyAdvertiserFactory* adv_factory =
+      adapter_->GetLeAdvertiserFactory();
+
+  *_aidl_return = RegisterInstanceBase(callback, adv_factory);
+  return Status::ok();
+}
+
+Status BluetoothLeAdvertiserBinderServer::UnregisterAdvertiser(int advertiser_id) {
+  VLOG(2) << __func__;
+  UnregisterInstanceBase(advertiser_id);
+  return Status::ok();
+}
+
+Status BluetoothLeAdvertiserBinderServer::UnregisterAll() {
+  VLOG(2) << __func__;
+  UnregisterAllBase();
+  return Status::ok();
+}
+
+Status BluetoothLeAdvertiserBinderServer::StartMultiAdvertising(
+    int advertiser_id, const android::bluetooth::AdvertiseData& advertise_data,
+    const android::bluetooth::AdvertiseData& scan_response,
+    const android::bluetooth::AdvertiseSettings& settings, bool* _aidl_return) {
+  VLOG(2) << __func__ << " advertiser_id: " << advertiser_id;
+  std::lock_guard<std::mutex> lock(*maps_lock());
+
+  auto advertiser = GetLEAdvertiser(advertiser_id);
+  if (!advertiser) {
+    LOG(ERROR) << "Unknown advertiser_id: " << advertiser_id;
+    *_aidl_return = false;
+    return Status::ok();
+  }
+
+  // Create a weak pointer and pass that to the callback to prevent a potential
+  // use after free.
+  android::wp<BluetoothLeAdvertiserBinderServer> weak_ptr_to_this(this);
+  auto settings_copy = settings;
+  auto callback = [=](bluetooth::BLEStatus status) {
+    auto sp_to_this = weak_ptr_to_this.promote();
+    if (!sp_to_this.get()) {
+      VLOG(2) << "BluetoothLeAdvertiserBinderServer was deleted";
+      return;
+    }
+
+    std::lock_guard<std::mutex> lock(*maps_lock());
+
+    auto cb = GetLECallback(advertiser_id);
+    if (!cb.get()) {
+      VLOG(1) << "Advertiser was removed before callback: " << advertiser_id;
+      return;
+    }
+
+    cb->OnMultiAdvertiseCallback(status, true /* is_start */, settings_copy);
+  };
+
+  if (!advertiser->StartAdvertising(settings, advertise_data, scan_response,
+                                callback)) {
+    LOG(ERROR) << "Failed to initiate call to start advertising";
+    *_aidl_return = false;
+    return Status::ok();
+  }
+
+  *_aidl_return = true;
+  return Status::ok();
+}
+
+Status BluetoothLeAdvertiserBinderServer::StopMultiAdvertising(
+    int advertiser_id, bool* _aidl_return) {
+  VLOG(2) << __func__;
+  std::lock_guard<std::mutex> lock(*maps_lock());
+
+  auto advertiser = GetLEAdvertiser(advertiser_id);
+  if (!advertiser) {
+    LOG(ERROR) << "Unknown advertiser_id: " << advertiser_id;
+    *_aidl_return = false;
+    return Status::ok();
+  }
+
+  // Create a weak pointer and pass that to the callback to prevent a potential
+  // use after free.
+  android::wp<BluetoothLeAdvertiserBinderServer> weak_ptr_to_this(this);
+  auto settings_copy = advertiser->advertise_settings();
+  auto callback = [=](bluetooth::BLEStatus status) {
+    auto sp_to_this = weak_ptr_to_this.promote();
+    if (!sp_to_this.get()) {
+      VLOG(2) << "BluetoothLeAdvertiserBinderServer was deleted";
+      return;
+    }
+
+    auto cb = GetLECallback(advertiser_id);
+    if (!cb.get()) {
+      VLOG(2) << "Advertiser was unregistered - advertiser_id: " << advertiser_id;
+      return;
+    }
+
+    std::lock_guard<std::mutex> lock(*maps_lock());
+
+    cb->OnMultiAdvertiseCallback(status, false /* is_start */, settings_copy);
+  };
+
+  if (!advertiser->StopAdvertising(callback)) {
+    LOG(ERROR) << "Failed to initiate call to start advertising";
+    *_aidl_return = false;
+    return Status::ok();
+  }
+
+  *_aidl_return = true;
+  return Status::ok();
+}
+
+android::sp<IBluetoothLeAdvertiserCallback>
+BluetoothLeAdvertiserBinderServer::GetLECallback(int advertiser_id) {
+  auto cb = GetCallback(advertiser_id);
+  return android::sp<IBluetoothLeAdvertiserCallback>(
+      static_cast<IBluetoothLeAdvertiserCallback*>(cb.get()));
+}
+
+std::shared_ptr<bluetooth::LowEnergyAdvertiser>
+BluetoothLeAdvertiserBinderServer::GetLEAdvertiser(int advertiser_id) {
+  return std::static_pointer_cast<bluetooth::LowEnergyAdvertiser>(
+      GetInstance(advertiser_id));
+}
+
+void BluetoothLeAdvertiserBinderServer::OnRegisterInstanceImpl(
+    bluetooth::BLEStatus status, android::sp<IInterface> callback,
+    bluetooth::BluetoothInstance* instance) {
+  VLOG(1) << __func__ << " status: " << status;
+
+  android::sp<IBluetoothLeAdvertiserCallback> cb(
+      static_cast<IBluetoothLeAdvertiserCallback*>(callback.get()));
+  cb->OnAdvertiserRegistered(status, (status == bluetooth::BLE_STATUS_SUCCESS)
+                                     ? instance->GetInstanceId()
+                                     : kInvalidInstanceId);
+}
+
+}  // namespace binder
+}  // namespace ipc
diff --git a/bt/service/ipc/binder/bluetooth_le_advertiser_binder_server.h b/bt/service/ipc/binder/bluetooth_le_advertiser_binder_server.h
new file mode 100644
index 0000000..5a9f84d
--- /dev/null
+++ b/bt/service/ipc/binder/bluetooth_le_advertiser_binder_server.h
@@ -0,0 +1,84 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <base/macros.h>
+
+#include <android/bluetooth/IBluetoothLeAdvertiserCallback.h>
+#include "android/bluetooth/BnBluetoothLeAdvertiser.h"
+
+#include "service/common/bluetooth/low_energy_constants.h"
+#include "service/ipc/binder/interface_with_instances_base.h"
+#include "service/low_energy_advertiser.h"
+
+using android::binder::Status;
+using android::String16;
+
+using android::bluetooth::BnBluetoothLeAdvertiser;
+using android::bluetooth::IBluetoothLeAdvertiserCallback;
+
+namespace bluetooth {
+class Adapter;
+}  // namespace bluetooth
+
+namespace ipc {
+namespace binder {
+
+// Implements the server side of the IBluetoothLowEnergy interface.
+class BluetoothLeAdvertiserBinderServer
+    : public BnBluetoothLeAdvertiser,
+      public InterfaceWithInstancesBase {
+ public:
+  explicit BluetoothLeAdvertiserBinderServer(bluetooth::Adapter* adapter);
+  ~BluetoothLeAdvertiserBinderServer() override;
+
+  // IBluetoothLowEnergy overrides:
+  Status RegisterAdvertiser(
+      const android::sp<IBluetoothLeAdvertiserCallback>& callback,
+      bool* _aidl_return) override;
+  Status UnregisterAdvertiser(int advertiser_id) override;
+  Status UnregisterAll() override;
+  Status StartMultiAdvertising(
+      int advertiser_id, const android::bluetooth::AdvertiseData& advertise_data,
+      const android::bluetooth::AdvertiseData& scan_response,
+      const android::bluetooth::AdvertiseSettings& settings,
+      bool* _aidl_return) override;
+  Status StopMultiAdvertising(int advertiser_id, bool* _aidl_return) override;
+
+ private:
+  // Returns a pointer to the IBluetoothLeAdvertiserCallback instance associated
+  // with |advertiser_id|. Returns NULL if such a callback cannot be found.
+  android::sp<IBluetoothLeAdvertiserCallback> GetLECallback(int advertiser_id);
+
+  // Returns a pointer to the LowEnergyAdvertiser instance associated with
+  // |advertiser_id|. Returns NULL if such a advertiser cannot be found.
+  std::shared_ptr<bluetooth::LowEnergyAdvertiser> GetLEAdvertiser(int advertiser_id);
+
+  // InterfaceWithInstancesBase override:
+  void OnRegisterInstanceImpl(bluetooth::BLEStatus status,
+                              android::sp<IInterface> callback,
+                              bluetooth::BluetoothInstance* instance) override;
+
+  bluetooth::Adapter* adapter_;  // weak
+
+  DISALLOW_COPY_AND_ASSIGN(BluetoothLeAdvertiserBinderServer);
+};
+
+}  // namespace binder
+}  // namespace ipc
diff --git a/bt/service/ipc/binder/bluetooth_le_scanner_binder_server.cc b/bt/service/ipc/binder/bluetooth_le_scanner_binder_server.cc
new file mode 100644
index 0000000..e65ed06
--- /dev/null
+++ b/bt/service/ipc/binder/bluetooth_le_scanner_binder_server.cc
@@ -0,0 +1,148 @@
+//
+//  Copyright (C) 2016 The Android Open Source Project
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+
+#include "service/ipc/binder/bluetooth_le_scanner_binder_server.h"
+
+#include <base/logging.h>
+
+#include "service/adapter.h"
+
+using android::String8;
+using android::String16;
+using android::binder::Status;
+
+namespace ipc {
+namespace binder {
+
+namespace {
+const int kInvalidInstanceId = -1;
+}  // namespace
+
+BluetoothLeScannerBinderServer::BluetoothLeScannerBinderServer(
+    bluetooth::Adapter* adapter)
+    : adapter_(adapter) {
+  CHECK(adapter_);
+}
+
+BluetoothLeScannerBinderServer::~BluetoothLeScannerBinderServer() {}
+
+Status BluetoothLeScannerBinderServer::RegisterScanner(
+    const android::sp<IBluetoothLeScannerCallback>& callback,
+    bool* _aidl_return) {
+  VLOG(2) << __func__;
+  bluetooth::LowEnergyScannerFactory* ble_factory =
+      adapter_->GetLeScannerFactory();
+
+  *_aidl_return = RegisterInstanceBase(callback, ble_factory);
+  return Status::ok();
+}
+
+Status BluetoothLeScannerBinderServer::UnregisterScanner(int scanner_id) {
+  VLOG(2) << __func__;
+  UnregisterInstanceBase(scanner_id);
+  return Status::ok();
+}
+
+Status BluetoothLeScannerBinderServer::UnregisterAll() {
+  VLOG(2) << __func__;
+  UnregisterAllBase();
+  return Status::ok();
+}
+
+Status BluetoothLeScannerBinderServer::StartScan(
+    int scanner_id, const android::bluetooth::ScanSettings& settings,
+    const std::vector<android::bluetooth::ScanFilter>& filters,
+    bool* _aidl_return) {
+  VLOG(2) << __func__ << " scanner_id: " << scanner_id;
+  std::lock_guard<std::mutex> lock(*maps_lock());
+
+  auto scanner = GetLEScanner(scanner_id);
+  if (!scanner) {
+    LOG(ERROR) << "Unknown scanner_id: " << scanner_id;
+    *_aidl_return = false;
+    return Status::ok();
+  }
+
+  std::vector<bluetooth::ScanFilter> flt;
+  for (const auto& filter : filters) {
+    flt.push_back(filter);
+  }
+
+  *_aidl_return = scanner->StartScan(settings, flt);
+  return Status::ok();
+}
+
+Status BluetoothLeScannerBinderServer::StopScan(int scanner_id,
+                                                bool* _aidl_return) {
+  VLOG(2) << __func__ << " scanner_id: " << scanner_id;
+  std::lock_guard<std::mutex> lock(*maps_lock());
+
+  auto scanner = GetLEScanner(scanner_id);
+  if (!scanner) {
+    LOG(ERROR) << "Unknown scanner_id: " << scanner_id;
+    *_aidl_return = false;
+    return Status::ok();
+  }
+
+  *_aidl_return = scanner->StopScan();
+  return Status::ok();
+}
+
+void BluetoothLeScannerBinderServer::OnScanResult(
+    bluetooth::LowEnergyScanner* scanner, const bluetooth::ScanResult& result) {
+  VLOG(2) << __func__;
+  std::lock_guard<std::mutex> lock(*maps_lock());
+
+  int scanner_id = scanner->GetInstanceId();
+  auto cb = GetLECallback(scanner->GetInstanceId());
+  if (!cb.get()) {
+    VLOG(2) << "Scanner was unregistered - scanner_id: " << scanner_id;
+    return;
+  }
+
+  cb->OnScanResult(result);
+}
+
+android::sp<IBluetoothLeScannerCallback>
+BluetoothLeScannerBinderServer::GetLECallback(int scanner_id) {
+  auto cb = GetCallback(scanner_id);
+  return android::sp<IBluetoothLeScannerCallback>(
+      static_cast<IBluetoothLeScannerCallback*>(cb.get()));
+}
+
+std::shared_ptr<bluetooth::LowEnergyScanner>
+BluetoothLeScannerBinderServer::GetLEScanner(int scanner_id) {
+  return std::static_pointer_cast<bluetooth::LowEnergyScanner>(
+      GetInstance(scanner_id));
+}
+
+void BluetoothLeScannerBinderServer::OnRegisterInstanceImpl(
+    bluetooth::BLEStatus status, android::sp<IInterface> callback,
+    bluetooth::BluetoothInstance* instance) {
+  VLOG(1) << __func__ << " status: " << status;
+  bluetooth::LowEnergyScanner* le_scanner =
+      static_cast<bluetooth::LowEnergyScanner*>(instance);
+  le_scanner->SetDelegate(this);
+
+  android::sp<IBluetoothLeScannerCallback> cb(
+      static_cast<IBluetoothLeScannerCallback*>(callback.get()));
+  cb->OnScannerRegistered(status, (status == bluetooth::BLE_STATUS_SUCCESS)
+                                     ? instance->GetInstanceId()
+                                     : kInvalidInstanceId);
+}
+
+}  // namespace binder
+}  // namespace ipc
diff --git a/bt/service/ipc/binder/bluetooth_le_scanner_binder_server.h b/bt/service/ipc/binder/bluetooth_le_scanner_binder_server.h
new file mode 100644
index 0000000..655c91b
--- /dev/null
+++ b/bt/service/ipc/binder/bluetooth_le_scanner_binder_server.h
@@ -0,0 +1,86 @@
+//
+//  Copyright (C) 2016 The Android Open Source Project
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+
+#pragma once
+
+#include <memory>
+
+#include <base/macros.h>
+
+#include <android/bluetooth/IBluetoothLeScannerCallback.h>
+#include "android/bluetooth/BnBluetoothLeScanner.h"
+
+#include "service/common/bluetooth/low_energy_constants.h"
+#include "service/ipc/binder/interface_with_instances_base.h"
+#include "service/low_energy_scanner.h"
+
+using android::binder::Status;
+using android::String16;
+
+using android::bluetooth::BnBluetoothLeScanner;
+using android::bluetooth::IBluetoothLeScannerCallback;
+
+namespace bluetooth {
+class Adapter;
+}  // namespace bluetooth
+
+namespace ipc {
+namespace binder {
+
+// Implements the server side of the IBluetoothLowEnergy interface.
+class BluetoothLeScannerBinderServer
+    : public BnBluetoothLeScanner,
+      public InterfaceWithInstancesBase,
+      public bluetooth::LowEnergyScanner::Delegate {
+ public:
+  explicit BluetoothLeScannerBinderServer(bluetooth::Adapter* adapter);
+  ~BluetoothLeScannerBinderServer() override;
+
+  // IBluetoothLowEnergy overrides:
+  Status RegisterScanner(
+      const android::sp<IBluetoothLeScannerCallback>& callback,
+      bool* _aidl_return) override;
+  Status UnregisterScanner(int scanner_id) override;
+  Status UnregisterAll() override;
+  Status StartScan(int scanner_id,
+                   const android::bluetooth::ScanSettings& settings,
+                   const std::vector<android::bluetooth::ScanFilter>& filters,
+                   bool* _aidl_return) override;
+  Status StopScan(int scanner_id, bool* _aidl_return) override;
+
+  void OnScanResult(bluetooth::LowEnergyScanner* scanner,
+                    const bluetooth::ScanResult& result) override;
+ private:
+  // Returns a pointer to the IBluetoothLowEnergyCallback instance associated
+  // with |scanner_id|. Returns NULL if such a callback cannot be found.
+  android::sp<IBluetoothLeScannerCallback> GetLECallback(int scanner_id);
+
+  // Returns a pointer to the LowEnergyScanner instance associated with
+  // |scanner_id|. Returns NULL if such a scanner cannot be found.
+  std::shared_ptr<bluetooth::LowEnergyScanner> GetLEScanner(int scanner_id);
+
+  // InterfaceWithInstancesBase override:
+  void OnRegisterInstanceImpl(bluetooth::BLEStatus status,
+                              android::sp<IInterface> callback,
+                              bluetooth::BluetoothInstance* instance) override;
+
+  bluetooth::Adapter* adapter_;  // weak
+
+  DISALLOW_COPY_AND_ASSIGN(BluetoothLeScannerBinderServer);
+};
+
+}  // namespace binder
+}  // namespace ipc
diff --git a/bt/service/ipc/binder/bluetooth_low_energy_binder_server.cc b/bt/service/ipc/binder/bluetooth_low_energy_binder_server.cc
new file mode 100644
index 0000000..9b8a863
--- /dev/null
+++ b/bt/service/ipc/binder/bluetooth_low_energy_binder_server.cc
@@ -0,0 +1,181 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/ipc/binder/bluetooth_low_energy_binder_server.h"
+
+#include <base/logging.h>
+
+#include "service/adapter.h"
+
+using android::String8;
+using android::String16;
+using android::binder::Status;
+
+namespace ipc {
+namespace binder {
+
+namespace {
+const int kInvalidInstanceId = -1;
+}  // namespace
+
+BluetoothLowEnergyBinderServer::BluetoothLowEnergyBinderServer(
+    bluetooth::Adapter* adapter)
+    : adapter_(adapter) {
+  CHECK(adapter_);
+}
+
+BluetoothLowEnergyBinderServer::~BluetoothLowEnergyBinderServer() {}
+
+Status BluetoothLowEnergyBinderServer::RegisterClient(
+    const android::sp<IBluetoothLowEnergyCallback>& callback,
+    bool* _aidl_return) {
+  VLOG(2) << __func__;
+  bluetooth::LowEnergyClientFactory* ble_factory =
+      adapter_->GetLowEnergyClientFactory();
+
+  *_aidl_return = RegisterInstanceBase(callback, ble_factory);
+  return Status::ok();
+}
+
+Status BluetoothLowEnergyBinderServer::UnregisterClient(int client_id) {
+  VLOG(2) << __func__;
+  UnregisterInstanceBase(client_id);
+  return Status::ok();
+}
+
+Status BluetoothLowEnergyBinderServer::UnregisterAll() {
+  VLOG(2) << __func__;
+  UnregisterAllBase();
+  return Status::ok();
+}
+
+Status BluetoothLowEnergyBinderServer::Connect(int client_id,
+                                               const String16& address,
+                                               bool is_direct,
+                                               bool* _aidl_return) {
+  VLOG(2) << __func__ << " client_id: " << client_id << " address: " << address
+          << " is_direct: " << is_direct;
+  std::lock_guard<std::mutex> lock(*maps_lock());
+
+  auto client = GetLEClient(client_id);
+  if (!client) {
+    LOG(ERROR) << "Unknown client_id: " << client_id;
+    *_aidl_return = false;
+    return Status::ok();
+  }
+
+  *_aidl_return =
+      client->Connect(std::string(String8(address).string()), is_direct);
+  return Status::ok();
+}
+
+Status BluetoothLowEnergyBinderServer::Disconnect(int client_id,
+                                                  const String16& address,
+                                                  bool* _aidl_return) {
+  VLOG(2) << __func__ << " client_id: " << client_id << " address: " << address;
+  std::lock_guard<std::mutex> lock(*maps_lock());
+
+  auto client = GetLEClient(client_id);
+  if (!client) {
+    LOG(ERROR) << "Unknown client_id: " << client_id;
+    *_aidl_return = false;
+    return Status::ok();
+  }
+
+  *_aidl_return = client->Disconnect(std::string(String8(address).string()));
+  return Status::ok();
+}
+
+Status BluetoothLowEnergyBinderServer::SetMtu(int client_id,
+                                              const String16& address, int mtu,
+                                              bool* _aidl_return) {
+  VLOG(2) << __func__ << " client_id: " << client_id << " address: " << address
+          << " mtu: " << mtu;
+  std::lock_guard<std::mutex> lock(*maps_lock());
+
+  auto client = GetLEClient(client_id);
+  if (!client) {
+    LOG(ERROR) << "Unknown client_id: " << client_id;
+    *_aidl_return = false;
+    return Status::ok();
+  }
+
+  *_aidl_return = client->SetMtu(std::string(String8(address).string()), mtu);
+  return Status::ok();
+}
+
+void BluetoothLowEnergyBinderServer::OnConnectionState(
+    bluetooth::LowEnergyClient* client, int status, const char* address,
+    bool connected) {
+  VLOG(2) << __func__ << " address: " << address << " connected: " << connected;
+
+  int client_id = client->GetInstanceId();
+  auto cb = GetLECallback(client->GetInstanceId());
+  if (!cb.get()) {
+    VLOG(2) << "Client was unregistered - client_id: " << client_id;
+    return;
+  }
+
+  cb->OnConnectionState(status, client_id,
+                        String16(address, std::strlen(address)), connected);
+}
+
+void BluetoothLowEnergyBinderServer::OnMtuChanged(
+    bluetooth::LowEnergyClient* client, int status, const char* address,
+    int mtu) {
+  VLOG(2) << __func__ << " address: " << address << " status: " << status
+          << " mtu: " << mtu;
+
+  int client_id = client->GetInstanceId();
+  auto cb = GetLECallback(client_id);
+  if (!cb.get()) {
+    VLOG(2) << "Client was unregistered - client_id: " << client_id;
+    return;
+  }
+
+  cb->OnMtuChanged(status, String16(address, std::strlen(address)), mtu);
+}
+
+android::sp<IBluetoothLowEnergyCallback>
+BluetoothLowEnergyBinderServer::GetLECallback(int client_id) {
+  auto cb = GetCallback(client_id);
+  return android::sp<IBluetoothLowEnergyCallback>(
+      static_cast<IBluetoothLowEnergyCallback*>(cb.get()));
+}
+
+std::shared_ptr<bluetooth::LowEnergyClient>
+BluetoothLowEnergyBinderServer::GetLEClient(int client_id) {
+  return std::static_pointer_cast<bluetooth::LowEnergyClient>(
+      GetInstance(client_id));
+}
+
+void BluetoothLowEnergyBinderServer::OnRegisterInstanceImpl(
+    bluetooth::BLEStatus status, android::sp<IInterface> callback,
+    bluetooth::BluetoothInstance* instance) {
+  VLOG(1) << __func__ << " status: " << status;
+  bluetooth::LowEnergyClient* le_client =
+      static_cast<bluetooth::LowEnergyClient*>(instance);
+  le_client->SetDelegate(this);
+
+  android::sp<IBluetoothLowEnergyCallback> cb(
+      static_cast<IBluetoothLowEnergyCallback*>(callback.get()));
+  cb->OnClientRegistered(status, (status == bluetooth::BLE_STATUS_SUCCESS)
+                                     ? instance->GetInstanceId()
+                                     : kInvalidInstanceId);
+}
+
+}  // namespace binder
+}  // namespace ipc
diff --git a/bt/service/ipc/binder/bluetooth_low_energy_binder_server.h b/bt/service/ipc/binder/bluetooth_low_energy_binder_server.h
new file mode 100644
index 0000000..d393c7d
--- /dev/null
+++ b/bt/service/ipc/binder/bluetooth_low_energy_binder_server.h
@@ -0,0 +1,91 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <base/macros.h>
+
+#include <android/bluetooth/IBluetoothLowEnergyCallback.h>
+#include "android/bluetooth/BnBluetoothLowEnergy.h"
+
+#include "service/common/bluetooth/low_energy_constants.h"
+#include "service/ipc/binder/interface_with_instances_base.h"
+#include "service/low_energy_client.h"
+
+using android::binder::Status;
+using android::String16;
+
+using android::bluetooth::BnBluetoothLowEnergy;
+using android::bluetooth::IBluetoothLowEnergyCallback;
+
+namespace bluetooth {
+class Adapter;
+}  // namespace bluetooth
+
+namespace ipc {
+namespace binder {
+
+// Implements the server side of the IBluetoothLowEnergy interface.
+class BluetoothLowEnergyBinderServer
+    : public BnBluetoothLowEnergy,
+      public InterfaceWithInstancesBase,
+      public bluetooth::LowEnergyClient::Delegate {
+ public:
+  explicit BluetoothLowEnergyBinderServer(bluetooth::Adapter* adapter);
+  ~BluetoothLowEnergyBinderServer() override;
+
+  // IBluetoothLowEnergy overrides:
+  Status RegisterClient(
+      const android::sp<IBluetoothLowEnergyCallback>& callback,
+      bool* _aidl_return) override;
+  Status UnregisterClient(int client_id) override;
+  Status UnregisterAll() override;
+  Status Connect(int client_id, const String16& address, bool is_direct,
+                 bool* _aidl_return) override;
+  Status Disconnect(int client_id, const String16& address,
+                    bool* _aidl_return) override;
+  Status SetMtu(int client_id, const String16& address, int mtu,
+                bool* _aidl_return) override;
+
+  // bluetooth::LowEnergyClient::Delegate overrides:
+  void OnConnectionState(bluetooth::LowEnergyClient* client, int status,
+                         const char* address, bool connected) override;
+  void OnMtuChanged(bluetooth::LowEnergyClient* client, int status,
+                    const char* address, int mtu) override;
+
+ private:
+  // Returns a pointer to the IBluetoothLowEnergyCallback instance associated
+  // with |client_id|. Returns NULL if such a callback cannot be found.
+  android::sp<IBluetoothLowEnergyCallback> GetLECallback(int client_id);
+
+  // Returns a pointer to the LowEnergyClient instance associated with
+  // |client_id|. Returns NULL if such a client cannot be found.
+  std::shared_ptr<bluetooth::LowEnergyClient> GetLEClient(int client_id);
+
+  // InterfaceWithInstancesBase override:
+  void OnRegisterInstanceImpl(bluetooth::BLEStatus status,
+                              android::sp<IInterface> callback,
+                              bluetooth::BluetoothInstance* instance) override;
+
+  bluetooth::Adapter* adapter_;  // weak
+
+  DISALLOW_COPY_AND_ASSIGN(BluetoothLowEnergyBinderServer);
+};
+
+}  // namespace binder
+}  // namespace ipc
diff --git a/bt/service/ipc/binder/interface_with_instances_base.cc b/bt/service/ipc/binder/interface_with_instances_base.cc
new file mode 100644
index 0000000..2005bf0
--- /dev/null
+++ b/bt/service/ipc/binder/interface_with_instances_base.cc
@@ -0,0 +1,153 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/ipc/binder/interface_with_instances_base.h"
+
+#include <base/logging.h>
+
+namespace ipc {
+namespace binder {
+
+bool InterfaceWithInstancesBase::RegisterInstanceBase(
+    const android::sp<IInterface>& callback,
+    bluetooth::BluetoothInstanceFactory* factory) {
+  VLOG(2) << __func__;
+  CHECK(factory);
+
+  if (!callback.get()) {
+    LOG(ERROR) << "Cannot register a NULL callback";
+    return false;
+  }
+
+  // Store the callback in the pending list. It will get removed later when the
+  // stack notifies us asynchronously.
+  bluetooth::UUID app_uuid = bluetooth::UUID::GetRandom();
+  if (!pending_callbacks_.Register(app_uuid, callback)) {
+    LOG(ERROR) << "Failed to store |callback| to map";
+    return false;
+  }
+
+  // Create a weak pointer and pass that to the callback to prevent an invalid
+  // access later. Since this object is managed using Android's StrongPointer
+  // (sp) we are using a wp here rather than std::weak_ptr.
+  android::wp<InterfaceWithInstancesBase> weak_ptr_to_this(this);
+
+  bluetooth::BluetoothInstanceFactory::RegisterCallback cb = [weak_ptr_to_this](
+      bluetooth::BLEStatus status, const bluetooth::UUID& in_uuid,
+      std::unique_ptr<bluetooth::BluetoothInstance> instance) {
+    // If the weak pointer was invalidated then there is nothing we can do.
+    android::sp<InterfaceWithInstancesBase> strong_ptr_to_this =
+        weak_ptr_to_this.promote();
+    if (!strong_ptr_to_this.get()) {
+      VLOG(2) << "InterfaceWithInstancesBase was deleted while instance was"
+              << " being registered";
+      return;
+    }
+
+    strong_ptr_to_this->OnRegisterInstance(status, in_uuid,
+                                           std::move(instance));
+  };
+
+  if (factory->RegisterInstance(app_uuid, cb)) return true;
+
+  LOG(ERROR) << "Failed to register instance";
+  pending_callbacks_.Remove(app_uuid);
+
+  return false;
+}
+
+void InterfaceWithInstancesBase::UnregisterInstanceBase(int instance_id) {
+  VLOG(2) << __func__;
+  std::lock_guard<std::mutex> lock(maps_lock_);
+
+  id_to_cb_.Remove(instance_id);
+  id_to_instance_.erase(instance_id);
+}
+
+void InterfaceWithInstancesBase::UnregisterAllBase() {
+  VLOG(2) << __func__;
+  std::lock_guard<std::mutex> lock(maps_lock_);
+
+  id_to_cb_.Clear();
+  id_to_instance_.clear();
+}
+
+android::sp<IInterface> InterfaceWithInstancesBase::GetCallback(
+    int instance_id) {
+  return id_to_cb_.Get(instance_id);
+}
+
+std::shared_ptr<bluetooth::BluetoothInstance>
+InterfaceWithInstancesBase::GetInstance(int instance_id) {
+  auto iter = id_to_instance_.find(instance_id);
+  if (iter == id_to_instance_.end())
+    return std::shared_ptr<bluetooth::BluetoothInstance>();
+  return iter->second;
+}
+
+void InterfaceWithInstancesBase::OnRegisterInstance(
+    bluetooth::BLEStatus status, const bluetooth::UUID& uuid,
+    std::unique_ptr<bluetooth::BluetoothInstance> instance) {
+  VLOG(2) << __func__ << " - status: " << status;
+
+  // Simply remove the callback from |pending_callbacks_| as it no longer
+  // belongs in there.
+  sp<IInterface> callback = pending_callbacks_.Remove(uuid);
+
+  // |callback| might be NULL if it was removed from the pending list, e.g. the
+  // remote process that owns the callback died.
+  if (!callback.get()) {
+    VLOG(1) << "Callback was removed before the call to \"RegisterInstance\" "
+            << "returned; unregistering instance";
+    return;
+  }
+
+  if (status != bluetooth::BLE_STATUS_SUCCESS) {
+    // The call wasn't successful. Notify the implementation and return.
+    LOG(ERROR) << "Failed to register instance: " << status;
+    OnRegisterInstanceImpl(status, callback, nullptr);
+    return;
+  }
+
+  std::lock_guard<std::mutex> lock(maps_lock_);
+  int instance_id = instance->GetInstanceId();
+  CHECK(instance_id);
+  if (!id_to_cb_.Register(instance_id, callback, this)) {
+    LOG(ERROR) << "Failed to store callback";
+    OnRegisterInstanceImpl(bluetooth::BLE_STATUS_FAILURE, callback, nullptr);
+    return;
+  }
+
+  VLOG(1) << "Registered BluetoothInstance - ID: " << instance_id;
+
+  auto shared_instance =
+      std::shared_ptr<bluetooth::BluetoothInstance>(instance.release());
+  id_to_instance_[instance_id] = shared_instance;
+
+  OnRegisterInstanceImpl(status, callback, shared_instance.get());
+}
+
+void InterfaceWithInstancesBase::OnRemoteCallbackRemoved(const int& key) {
+  VLOG(2) << __func__ << " instance_id: " << key;
+  std::lock_guard<std::mutex> lock(maps_lock_);
+
+  // No need to remove from the callback map as the entry should be already
+  // removed when this callback gets called.
+  id_to_instance_.erase(key);
+}
+
+}  // namespace binder
+}  // namespace ipc
diff --git a/bt/service/ipc/binder/interface_with_instances_base.h b/bt/service/ipc/binder/interface_with_instances_base.h
new file mode 100644
index 0000000..f0aa762
--- /dev/null
+++ b/bt/service/ipc/binder/interface_with_instances_base.h
@@ -0,0 +1,105 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <base/macros.h>
+
+#include "service/bluetooth_instance.h"
+#include "service/common/bluetooth/uuid.h"
+#include "service/ipc/binder/remote_callback_map.h"
+
+namespace ipc {
+namespace binder {
+
+// InterfaceWithInstancesBase provides a common base class for Binder interface
+// servers that involve instance callback Binders registered with an integer
+// instance ID over an asynchronous lower-level stack API. This class abstracts
+// away the common procedures of managing pending callbacks, listening to death
+// notifications, and maintaining multiple internal maps in one common base
+// class.
+// TODO: add code example here.
+class InterfaceWithInstancesBase
+    : public RemoteCallbackMap<int, android::IInterface>::Delegate,
+      virtual public android::RefBase {
+ public:
+  InterfaceWithInstancesBase() = default;
+  ~InterfaceWithInstancesBase() override = default;
+
+ protected:
+  // The initial entry point for registering a instance. Invoke this from the
+  // registration API to add a instance/UUID pair to the pending list and set up
+  // the generic asynchronous callback handler and initiate the process with the
+  // given |factory| instance. Returns false, if there were any errors that
+  // could be synchronously reported.
+  bool RegisterInstanceBase(const android::sp<IInterface>& callback,
+                            bluetooth::BluetoothInstanceFactory* factory);
+
+  // Unregister the instance with the given ID, if it was registered before.
+  void UnregisterInstanceBase(int instance_id);
+
+  // Unregisters all registered instances.
+  void UnregisterAllBase();
+
+  // Returns a handle to the lock used to synchronize access to the internal
+  // data structures. Subclasses should acquire this before accessing the maps.
+  std::mutex* maps_lock() { return &maps_lock_; }
+
+  // Returns the callback interface binder that is assigned to the given
+  // instance ID |instance_id|. The returned pointer will contain NULL if an
+  // entry for the given ID cannot be found.
+  android::sp<IInterface> GetCallback(int instance_id);
+
+  // Returns the instance instance that is assigned to the given instance ID
+  // |instance_id|. The returned pointer will contain NULL if an entry for the
+  // given ID cannot be found.
+  std::shared_ptr<bluetooth::BluetoothInstance> GetInstance(int instance_id);
+
+ private:
+  // Base implementation of the register callback.
+  void OnRegisterInstance(
+      bluetooth::BLEStatus status, const bluetooth::UUID& uuid,
+      std::unique_ptr<bluetooth::BluetoothInstance> instance);
+
+  // Called when the callback registration has completed. |instance| is owned by
+  // the base class and should not be deleted by the implementation. If the
+  // operation failed, nullptr will be passed for |instance|.
+  virtual void OnRegisterInstanceImpl(
+      bluetooth::BLEStatus status, android::sp<IInterface> callback,
+      bluetooth::BluetoothInstance* instance) = 0;
+
+  // RemoteCallbackMap<int, IBluetoothLowEnergyCallback>::Delegate override:
+  void OnRemoteCallbackRemoved(const int& key) override;
+
+  // Instances that are pending registration. Once their registration is
+  // complete, the entry will be removed from this map.
+  RemoteCallbackMap<bluetooth::UUID, android::IInterface> pending_callbacks_;
+
+  // We keep two maps here: one from instance_id IDs to callback Binders and one
+  // from instance_id IDs to the BluetoothInstance structures themselves.
+  std::mutex maps_lock_;  // Needed for |id_to_instance_|.
+  RemoteCallbackMap<int, IInterface> id_to_cb_;
+  std::unordered_map<int, std::shared_ptr<bluetooth::BluetoothInstance>>
+      id_to_instance_;
+
+  DISALLOW_COPY_AND_ASSIGN(InterfaceWithInstancesBase);
+};
+
+}  // namespace binder
+}  // namespace ipc
diff --git a/bt/service/ipc/binder/ipc_handler_binder.cc b/bt/service/ipc/binder/ipc_handler_binder.cc
new file mode 100644
index 0000000..c1757d0
--- /dev/null
+++ b/bt/service/ipc/binder/ipc_handler_binder.cc
@@ -0,0 +1,85 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/ipc/binder/ipc_handler_binder.h"
+
+#include <base/bind.h>
+#include <base/logging.h>
+#include <base/message_loop/message_loop.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include "service/ipc/binder/bluetooth_binder_server.h"
+
+using android::defaultServiceManager;
+using android::sp;
+using android::status_t;
+using android::String8;
+using android::String16;
+
+namespace ipc {
+
+std::string kServiceName = "bluetooth-service";
+
+IPCHandlerBinder::IPCHandlerBinder(
+    bluetooth::Adapter* adapter,
+    IPCManager::Delegate* delegate)
+    : IPCHandler(adapter, delegate) {
+}
+
+IPCHandlerBinder::~IPCHandlerBinder() {
+}
+
+bool IPCHandlerBinder::Run() {
+  CHECK(adapter());
+
+  // Register the IBluetooth service with the Android ServiceManager.
+  android::sp<binder::BluetoothBinderServer> bt_server =
+      new binder::BluetoothBinderServer(adapter());
+  status_t status = defaultServiceManager()->addService(
+      String16(String8(kServiceName.c_str())),
+      bt_server);
+  if (status != android::NO_ERROR) {
+    LOG(ERROR) << "Failed to register Bluetooth service with ServiceManager";
+    return false;
+  }
+
+  // Notify the delegate. We do this in the message loop to avoid reentrancy.
+  if (delegate()) {
+    base::MessageLoop::current()->task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&IPCHandlerBinder::NotifyStarted, this));
+  }
+
+  android::ProcessState::self()->startThreadPool();
+
+  return true;
+}
+
+void IPCHandlerBinder::Stop() {
+  // TODO(armansito): There are several methods in android::IPCThreadState that
+  // are related to shutting down the threadpool, however I haven't been able to
+  // make them shut things down cleanly. Figure out the right way to stop the
+  // Binder IPC here.
+}
+
+void IPCHandlerBinder::NotifyStarted() {
+  if (delegate())
+    delegate()->OnIPCHandlerStarted(IPCManager::TYPE_BINDER);
+}
+
+}  // namespace ipc
diff --git a/bt/service/ipc/binder/ipc_handler_binder.h b/bt/service/ipc/binder/ipc_handler_binder.h
new file mode 100644
index 0000000..060548b
--- /dev/null
+++ b/bt/service/ipc/binder/ipc_handler_binder.h
@@ -0,0 +1,45 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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/macros.h>
+
+#include "service/ipc/ipc_handler.h"
+#include "service/ipc/ipc_manager.h"
+
+namespace ipc {
+
+// Implements a Binder based IPCHandler.
+class IPCHandlerBinder : public IPCHandler {
+ public:
+  IPCHandlerBinder(bluetooth::Adapter* adapter, IPCManager::Delegate* delegate);
+  ~IPCHandlerBinder() override;
+
+  // IPCHandler overrides:
+  bool Run() override;
+  void Stop() override;
+
+ private:
+  IPCHandlerBinder() = default;
+
+  // Notify the delegate that IPC has started.
+  void NotifyStarted();
+
+  DISALLOW_COPY_AND_ASSIGN(IPCHandlerBinder);
+};
+
+}  // namespace ipc
diff --git a/bt/service/ipc/binder/remote_callback_list.h b/bt/service/ipc/binder/remote_callback_list.h
new file mode 100644
index 0000000..aa612fa
--- /dev/null
+++ b/bt/service/ipc/binder/remote_callback_list.h
@@ -0,0 +1,207 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <mutex>
+#include <unordered_map>
+
+#include <base/logging.h>
+#include <base/macros.h>
+#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+
+namespace ipc {
+namespace binder {
+
+// Takes care of the grunt work of maintaining a list of remote interfaces,
+// typically for the use of performing registered callbacks from a remote
+// service. This is a native equivalent of the the android.os.RemoteCallbackList
+// Java class. The type "T" must inherit from android::IInterface.
+//
+// TODO(armansito): We need to unit test this class. Right now it's defined as a
+// simple template interface over the native libbinder types directly and we
+// can't compile libbinder for host unless the Binder kernel module is enabled
+// on the system. Figure out whether to:
+//    1) write the Binder test-code in a new target-only executable;
+//    2) conditionally compile into the host-native test suite if the Binder
+//       module is built;
+//    3) provide a test-only static library that re-defines the libbinder
+//       classes as mocks.
+// (See http://b/23386387)
+//
+// TODO(armansito): We should make this class non-final and the template
+// interface abstract, so that code that depends on this can be unit tested
+// against a mock version of this class.
+//
+// TODO(armansito): Consider submitting this class to frameworks/native/binder.
+template<typename T>
+class RemoteCallbackList final {
+ public:
+  RemoteCallbackList() = default;
+  ~RemoteCallbackList();
+
+  // Register and unregister a callback interface. Registering will
+  // automatically start tracking for death notifications in case the remote
+  // process hosting the Binder dies. In such a case, the Binder is
+  // automatically removed from the list.
+  bool Register(const android::sp<T>& callback);
+  bool Unregister(const android::sp<T>& callback);
+
+  // Calls the given function on each of the contained callbacks. The internal
+  // mutex is locked for the duration of the iteration.
+  void ForEach(const std::function<void(T*)>& callback);
+
+ private:
+  class CallbackDeathRecipient : public android::IBinder::DeathRecipient {
+   public:
+    CallbackDeathRecipient(const android::sp<T>& callback,
+                           RemoteCallbackList* owner);
+
+    android::sp<T> get_callback() const { return callback_; }
+
+    // android::IBinder::DeathRecipient override:
+    void binderDied(const android::wp<android::IBinder>& who) override;
+
+   private:
+    android::sp<T> callback_;
+    RemoteCallbackList<T>* owner_;  // weak
+  };
+
+  // Typedef for internal map container. This keeps track of a given Binder and
+  // a death receiver associated with it.
+  using CallbackMap = std::unordered_map<android::IBinder*,
+                                         android::sp<CallbackDeathRecipient>>;
+
+  bool UnregisterInternal(typename CallbackMap::iterator iter);
+
+  std::mutex map_lock_;
+  CallbackMap callbacks_;
+
+  DISALLOW_COPY_AND_ASSIGN(RemoteCallbackList);
+};
+
+// Template Implementation details below
+// ========================================================
+
+using android::IBinder;
+using android::IInterface;
+using android::sp;
+using android::wp;
+
+template<typename T>
+RemoteCallbackList<T>::~RemoteCallbackList() {
+  std::lock_guard<std::mutex> lock(map_lock_);
+  for (auto iter = callbacks_.begin(); iter != callbacks_.end(); ++iter)
+    UnregisterInternal(iter);
+}
+
+template<typename T>
+bool RemoteCallbackList<T>::Register(const sp<T>& callback) {
+  std::lock_guard<std::mutex> lock(map_lock_);
+
+  sp<IBinder> binder = IInterface::asBinder(callback.get());
+  if (callbacks_.find(binder.get()) != callbacks_.end()) {
+    VLOG(1) << "Callback list already contains given callback";
+    return false;
+  }
+
+  sp<CallbackDeathRecipient> dr(new CallbackDeathRecipient(callback, this));
+
+  if (binder->linkToDeath(dr) != android::NO_ERROR) {
+    LOG(ERROR) << "Failed to link death recipient to binder";
+    return false;
+  }
+
+  callbacks_[binder.get()] = dr;
+
+  VLOG(2) << "Callback successfully registered with list";
+
+  return true;
+}
+
+template<typename T>
+bool RemoteCallbackList<T>::Unregister(const sp<T>& callback) {
+  std::lock_guard<std::mutex> lock(map_lock_);
+
+  sp<IBinder> binder = IInterface::asBinder(callback.get());
+  auto iter = callbacks_.find(binder.get());
+  if (iter == callbacks_.end()) {
+    VLOG(2) << "Given callback not registered with this list";
+    return false;
+  }
+
+  return UnregisterInternal(iter);
+}
+
+template<typename T>
+void RemoteCallbackList<T>::ForEach(const std::function<void(T*)>& callback) {
+  std::lock_guard<std::mutex> lock(map_lock_);
+  for (const auto& iter : callbacks_)
+    callback(iter.second->get_callback().get());
+}
+
+template<typename T>
+bool RemoteCallbackList<T>::UnregisterInternal(
+    typename CallbackMap::iterator iter) {
+  sp<CallbackDeathRecipient> dr = iter->second;
+  callbacks_.erase(iter);
+
+  if (IInterface::asBinder(dr->get_callback().get())->unlinkToDeath(dr) !=
+      android::NO_ERROR) {
+    LOG(ERROR) << "Failed to unlink death recipient from binder";
+
+    // We removed the entry from |map_| but unlinkToDeath failed. There isn't
+    // really much we can do here other than deleting the binder and returning
+    // an error.
+    return false;
+  }
+
+  VLOG(2) << "Callback successfully removed from list";
+
+  return true;
+}
+
+template<typename T>
+RemoteCallbackList<T>::CallbackDeathRecipient::CallbackDeathRecipient(
+    const sp<T>& callback,
+    RemoteCallbackList<T>* owner)
+    : callback_(callback),
+      owner_(owner) {
+  CHECK(callback_.get());
+  CHECK(owner_);
+}
+
+template<typename T>
+void RemoteCallbackList<T>::CallbackDeathRecipient::binderDied(
+    const wp<IBinder>& who) {
+  VLOG(1) << "Received binderDied";
+
+  sp<IBinder> binder = IInterface::asBinder(callback_.get());
+  CHECK(who.unsafe_get() == binder.get());
+
+  // Remove the callback but no need to call unlinkToDeath.
+  std::lock_guard<std::mutex> lock(owner_->map_lock_);
+  auto iter = owner_->callbacks_.find(binder.get());
+  CHECK(iter != owner_->callbacks_.end());
+  owner_->callbacks_.erase(iter);
+
+  VLOG(1) << "Callback from dead process unregistered";
+}
+
+}  // namespace binder
+}  // namespace ipc
diff --git a/bt/service/ipc/binder/remote_callback_map.h b/bt/service/ipc/binder/remote_callback_map.h
new file mode 100644
index 0000000..f6aaf05
--- /dev/null
+++ b/bt/service/ipc/binder/remote_callback_map.h
@@ -0,0 +1,260 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <mutex>
+#include <unordered_map>
+
+#include <base/logging.h>
+#include <base/macros.h>
+#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+
+namespace ipc {
+namespace binder {
+
+// A map of remote interfaces where the value type "V" must inherit from
+// android::IInterface. This is just like RemoteCallbackList except it provides
+// a key-value mapping.
+//
+// TODO(armansito): We should make this class non-final and the template
+// interface abstract, so that code that depends on this can be unit tested
+// against a mock version of this class.
+template<typename K, typename V>
+class RemoteCallbackMap final {
+ public:
+  RemoteCallbackMap() = default;
+  ~RemoteCallbackMap();
+
+  // The Delegate interface is used to notify when a registered callback is
+  // removed from the map as a result of the death of the remote process that
+  // owns the registered callback.
+  class Delegate {
+   public:
+    virtual ~Delegate() = default;
+
+    // Called when a remote callback associated with the key |key| has been
+    // removed. This won't get called if the callback was removed as a result of
+    // a call to RemoteCallbackMap::Unregister.
+    virtual void OnRemoteCallbackRemoved(const K& key) = 0;
+  };
+
+  // Register a callback interface and associate it with the given key.
+  // Registering will automatically start tracking for death notifications in
+  // case the remote process hosting the Binder dies. In such a case, the Binder
+  // is automatically removed from the map.
+  //
+  // An optional |delegate| can be passed which will be assocated with the given
+  // key/value pair. |delegate| must outlive this map.
+  bool Register(const K& key,
+                const android::sp<V>& callback,
+                Delegate* delegate = nullptr);
+
+  // Unregisters a previously registered callback with the given key. Returns
+  // false if |key| doesn't exist.
+  bool Unregister(const K& key);
+
+  // Returns the callback associated with the given key. Returns NULL if |key|
+  // doesn't exist.
+  android::sp<V> Get(const K& key);
+
+  // Removes the callback associated with the given key from the map and returns
+  // the value. Returns NULL if the key doesn't exists.
+  android::sp<V> Remove(const K& key);
+
+  // Clear the contents of the map.
+  void Clear();
+
+ private:
+  class CallbackDeathRecipient : public android::IBinder::DeathRecipient {
+   public:
+    CallbackDeathRecipient(
+        const K& key,
+        const android::sp<V>& callback,
+        RemoteCallbackMap<K, V>* owner,
+        Delegate* delegate);
+
+    android::sp<V> get_callback() const { return callback_; }
+
+    // android::IBinder::DeathRecipient override:
+    void binderDied(const android::wp<android::IBinder>& who) override;
+
+   private:
+    K key_;
+    android::sp<V> callback_;
+    RemoteCallbackMap<K, V>* owner_;  // weak
+    Delegate* delegate_;  // weak
+  };
+
+  // Typedef for internal map container.
+  using CallbackMap =
+      std::unordered_map<K, android::sp<CallbackDeathRecipient>>;
+
+  bool UnregisterInternal(typename CallbackMap::iterator iter);
+
+  std::mutex map_lock_;
+  CallbackMap map_;
+
+  DISALLOW_COPY_AND_ASSIGN(RemoteCallbackMap);
+};
+
+// Template Implementation details below
+// ========================================================
+
+using android::IBinder;
+using android::IInterface;
+using android::sp;
+using android::wp;
+using std::lock_guard;
+using std::mutex;
+
+template<typename K, typename V>
+RemoteCallbackMap<K, V>::~RemoteCallbackMap() {
+  Clear();
+}
+
+template<typename K, typename V>
+bool RemoteCallbackMap<K, V>::Register(
+    const K& key,
+    const sp<V>& callback,
+    Delegate* delegate) {
+  lock_guard<mutex> lock(map_lock_);
+
+  if (map_.find(key) != map_.end()) {
+    VLOG(1) << "Callback map already contains key";
+    return false;
+  }
+
+  sp<CallbackDeathRecipient> dr(
+      new CallbackDeathRecipient(key, callback, this, delegate));
+  sp<IBinder> binder = IInterface::asBinder(callback.get());
+  if (binder->linkToDeath(dr) != android::NO_ERROR) {
+    LOG(ERROR) << "Failed to link death recipient to binder";
+    return false;
+  }
+
+  map_[key] = dr;
+
+  VLOG(2) << "Callback successfully registered with map";
+
+  return true;
+}
+
+template<typename K, typename V>
+bool RemoteCallbackMap<K, V>::Unregister(const K& key) {
+  lock_guard<mutex> lock(map_lock_);
+
+  auto iter = map_.find(key);
+  if (iter == map_.end()) {
+    VLOG(1) << "Callback with given key not found";
+    return false;
+  }
+
+  return UnregisterInternal(iter);
+}
+
+template<typename K, typename V>
+sp<V> RemoteCallbackMap<K, V>::Get(const K& key) {
+  lock_guard<mutex> lock(map_lock_);
+
+  auto iter = map_.find(key);
+  if (iter == map_.end())
+    return nullptr;
+
+  return iter->second->get_callback();
+}
+
+template<typename K, typename V>
+sp<V> RemoteCallbackMap<K, V>::Remove(const K& key) {
+  lock_guard<mutex> lock(map_lock_);
+
+  auto iter = map_.find(key);
+  if (iter == map_.end())
+    return nullptr;
+
+  sp<V> val = iter->second->get_callback();
+  UnregisterInternal(iter);
+
+  return val;
+}
+template<typename K, typename V>
+void RemoteCallbackMap<K, V>::Clear() {
+  lock_guard<mutex> lock(map_lock_);
+
+  for (auto iter = map_.begin(); iter != map_.end();)
+    UnregisterInternal(iter++);
+}
+
+template<typename K, typename V>
+bool RemoteCallbackMap<K, V>::UnregisterInternal(
+    typename CallbackMap::iterator iter) {
+  sp<CallbackDeathRecipient> dr = iter->second;
+  map_.erase(iter);
+
+  if (IInterface::asBinder(dr->get_callback().get())->unlinkToDeath(dr) !=
+      android::NO_ERROR) {
+    LOG(ERROR) << "Failed to unlink death recipient from binder";
+
+    // We removed the entry from |map_| but unlinkToDeath failed. There isn't
+    // really much we can do here other than deleting the binder and returning
+    // an error.
+    return false;
+  }
+
+  VLOG(2) << "Callback successfully removed from map";
+
+  return true;
+}
+
+template<typename K, typename V>
+RemoteCallbackMap<K, V>::CallbackDeathRecipient::CallbackDeathRecipient(
+    const K& key,
+    const sp<V>& callback,
+    RemoteCallbackMap<K, V>* owner,
+    Delegate* delegate)
+    : key_(key),
+      callback_(callback),
+      owner_(owner),
+      delegate_(delegate) {
+  CHECK(callback_.get());
+}
+
+template<typename K, typename V>
+void RemoteCallbackMap<K, V>::CallbackDeathRecipient::binderDied(
+    const wp<IBinder>& who) {
+  VLOG(1) << "Received binderDied";
+
+  sp<IBinder> binder = IInterface::asBinder(callback_.get());
+  CHECK(who.unsafe_get() == binder.get());
+
+  // Remove the callback but no need to call unlinkToDeath.
+  {
+    lock_guard<mutex> lock(owner_->map_lock_);
+    auto iter = owner_->map_.find(key_);
+    CHECK(iter != owner_->map_.end());
+    owner_->map_.erase(iter);
+  }
+
+  VLOG(1) << "Callback from dead process unregistered; notifying delegate";
+
+  // Notify delegate.
+  if (delegate_)
+    delegate_->OnRemoteCallbackRemoved(key_);
+}
+
+}  // namespace binder
+}  // namespace ipc
diff --git a/bt/service/ipc/ipc_handler.cc b/bt/service/ipc/ipc_handler.cc
new file mode 100644
index 0000000..ffea0ee
--- /dev/null
+++ b/bt/service/ipc/ipc_handler.cc
@@ -0,0 +1,33 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/ipc/ipc_handler.h"
+
+#include <base/logging.h>
+
+namespace ipc {
+
+IPCHandler::IPCHandler(bluetooth::Adapter* adapter,
+                       IPCManager::Delegate* delegate)
+    : adapter_(adapter),
+      delegate_(delegate) {
+  CHECK(adapter_);
+}
+
+IPCHandler::~IPCHandler() {
+}
+
+}  // namespace ipc
diff --git a/bt/service/ipc/ipc_handler.h b/bt/service/ipc/ipc_handler.h
new file mode 100644
index 0000000..b1029ca
--- /dev/null
+++ b/bt/service/ipc/ipc_handler.h
@@ -0,0 +1,62 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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/macros.h>
+#include <base/memory/ref_counted.h>
+
+#include "service/ipc/ipc_manager.h"
+
+namespace bluetooth {
+class Adapter;
+}  // namespace bluetooth
+
+namespace ipc {
+
+// IPCHandler is an interface that classes implementing different IPC mechanisms
+// must conform to.
+class IPCHandler : public base::RefCountedThreadSafe<IPCHandler> {
+ public:
+  IPCHandler(bluetooth::Adapter* adapter, IPCManager::Delegate* delegate);
+  virtual ~IPCHandler();
+
+  // Initializes and runs the IPC mechanism. Returns true on success, false
+  // otherwise.
+  virtual bool Run() = 0;
+
+  // Stops the IPC mechanism.
+  virtual void Stop() = 0;
+
+ protected:
+  // Getters for private members to allow subclasses to access them in read-only
+  // fashion.
+  bluetooth::Adapter* adapter() const { return adapter_; }
+  IPCManager::Delegate* delegate() const { return delegate_; }
+
+ private:
+  IPCHandler() = default;
+
+  // Weak reference to the global Adapter instance.
+  bluetooth::Adapter* adapter_;
+
+  // The delegate that is interested in notifications from us.
+  IPCManager::Delegate* delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(IPCHandler);
+};
+
+}  // namespace ipc
diff --git a/bt/service/ipc/ipc_handler_linux.cc b/bt/service/ipc/ipc_handler_linux.cc
new file mode 100644
index 0000000..b9f181e
--- /dev/null
+++ b/bt/service/ipc/ipc_handler_linux.cc
@@ -0,0 +1,215 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/ipc/ipc_handler_linux.h"
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <base/bind.h>
+
+#include "osi/include/socket_utils/sockets.h"
+#include "service/daemon.h"
+#include "service/ipc/linux_ipc_host.h"
+#include "service/settings.h"
+
+namespace ipc {
+
+IPCHandlerLinux::IPCHandlerLinux(bluetooth::Adapter* adapter,
+                               IPCManager::Delegate* delegate)
+    : IPCHandler(adapter, delegate),
+      running_(false),
+      thread_("IPCHandlerLinux"),
+      keep_running_(true) {
+}
+
+IPCHandlerLinux::~IPCHandlerLinux() {
+  // This will only be set if the Settings::create_ipc_socket_path() was
+  // originally provided.
+  if (!socket_path_.empty())
+    unlink(socket_path_.value().c_str());
+}
+
+bool IPCHandlerLinux::Run() {
+  CHECK(!running_);
+
+  const std::string& android_suffix =
+      bluetooth::Daemon::Get()->GetSettings()->android_ipc_socket_suffix();
+  const base::FilePath& path =
+      bluetooth::Daemon::Get()->GetSettings()->create_ipc_socket_path();
+
+  // Both flags cannot be set at the same time.
+  CHECK(android_suffix.empty() || path.empty());
+  if (android_suffix.empty() && path.empty()) {
+    LOG(ERROR) << "No domain socket path provided";
+    return false;
+  }
+
+  CHECK(base::MessageLoop::current());  // An origin event loop is required.
+  origin_task_runner_ = base::MessageLoop::current()->task_runner();
+
+  if (!android_suffix.empty()) {
+    int server_fd = osi_android_get_control_socket(android_suffix.c_str());
+    if (server_fd == -1) {
+      LOG(ERROR) << "Unable to get Android socket from: " << android_suffix;
+      return false;
+    }
+    LOG(INFO) << "Binding to Android server socket:" << android_suffix;
+    socket_.reset(server_fd);
+  } else {
+    LOG(INFO) << "Creating a Unix domain socket:" << path.value();
+
+    // TODO(armansito): This is opens the door to potentially unlinking files in
+    // the current directory that we're not supposed to. For now we will have an
+    // assumption that the daemon runs in a sandbox but we should generally do
+    // this properly.
+    unlink(path.value().c_str());
+
+    base::ScopedFD server_socket(socket(PF_UNIX, SOCK_SEQPACKET, 0));
+    if (!server_socket.is_valid()) {
+      LOG(ERROR) << "Failed to open domain socket for IPC";
+      return false;
+    }
+
+    struct sockaddr_un address;
+    memset(&address, 0, sizeof(address));
+    address.sun_family = AF_UNIX;
+    strncpy(address.sun_path, path.value().c_str(),
+            sizeof(address.sun_path) - 1);
+    if (bind(server_socket.get(), (struct sockaddr*)&address, sizeof(address)) <
+        0) {
+      LOG(ERROR) << "Failed to bind IPC socket to address: " << strerror(errno);
+      return false;
+    }
+
+    socket_.swap(server_socket);
+    socket_path_ = path;
+  }
+
+  CHECK(socket_.is_valid());
+
+  running_ = true;  // Set this here before launching the thread.
+
+  // Start an IO thread and post the listening task.
+  base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
+  if (!thread_.StartWithOptions(options)) {
+    LOG(ERROR) << "Failed to start IPCHandlerLinux thread";
+    running_ = false;
+    return false;
+  }
+
+  thread_.task_runner()->PostTask(
+      FROM_HERE,
+      base::Bind(&IPCHandlerLinux::StartListeningOnThread, this));
+
+  return true;
+}
+
+void IPCHandlerLinux::Stop() {
+  keep_running_ = false;
+
+  // At this moment the listening thread might be blocking on the accept
+  // syscall. Shutdown and close the server socket before joining the thread to
+  // interrupt accept so that the main thread doesn't keep blocking.
+  shutdown(socket_.get(), SHUT_RDWR);
+  socket_.reset();
+
+  // Join and clean up the thread.
+  thread_.Stop();
+
+  // Thread exited. Notify the delegate. Post this on the event loop so that the
+  // callback isn't reentrant.
+  NotifyStoppedOnOriginThread();
+}
+
+void IPCHandlerLinux::StartListeningOnThread() {
+  CHECK(socket_.is_valid());
+  CHECK(adapter());
+  CHECK(running_);
+
+  LOG(INFO) << "Listening to incoming connections";
+
+  int status = listen(socket_.get(), SOMAXCONN);
+  if (status < 0) {
+    LOG(ERROR) << "Failed to listen on domain socket: " << strerror(errno);
+    origin_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(&IPCHandlerLinux::ShutDownOnOriginThread, this));
+    return;
+  }
+
+  NotifyStartedOnOriginThread();
+
+  // TODO(armansito): The code below can cause the daemon to run indefinitely if
+  // the thread is joined while it's in the middle of the EventLoop() call. The
+  // EventLoop() won't exit until a client terminates the connection, however
+  // this can be fixed by using the |thread_|'s MessageLoopForIO instead (since
+  // it gets stopped along with the thread).
+  // TODO(icoolidge): accept simultaneous clients
+  while (keep_running_.load()) {
+    int client_socket = accept4(socket_.get(), nullptr, nullptr, SOCK_NONBLOCK);
+    if (client_socket < 0) {
+      LOG(ERROR) << "Failed to accept client connection: " << strerror(errno);
+      continue;
+    }
+
+    LOG(INFO) << "Established client connection: fd=" << client_socket;
+
+    LinuxIPCHost ipc_host(client_socket, adapter());
+
+    // TODO(armansito): Use |thread_|'s MessageLoopForIO instead of using a
+    // custom event loop to poll from the socket.
+    ipc_host.EventLoop();
+  }
+}
+
+void IPCHandlerLinux::ShutDownOnOriginThread() {
+  LOG(INFO) << "Shutting down IPCHandlerLinux thread";
+  thread_.Stop();
+  running_ = false;
+
+  NotifyStoppedOnCurrentThread();
+}
+
+void IPCHandlerLinux::NotifyStartedOnOriginThread() {
+  if (!delegate())
+    return;
+
+  origin_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&IPCHandlerLinux::NotifyStartedOnCurrentThread, this));
+}
+
+void IPCHandlerLinux::NotifyStartedOnCurrentThread() {
+  if (delegate())
+    delegate()->OnIPCHandlerStarted(IPCManager::TYPE_LINUX);
+}
+
+void IPCHandlerLinux::NotifyStoppedOnOriginThread() {
+  if (!delegate())
+    return;
+
+  origin_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&IPCHandlerLinux::NotifyStoppedOnCurrentThread, this));
+}
+
+void IPCHandlerLinux::NotifyStoppedOnCurrentThread() {
+  if (delegate())
+    delegate()->OnIPCHandlerStopped(IPCManager::TYPE_LINUX);
+}
+
+}  // namespace ipc
diff --git a/bt/service/ipc/ipc_handler_linux.h b/bt/service/ipc/ipc_handler_linux.h
new file mode 100644
index 0000000..82e3142
--- /dev/null
+++ b/bt/service/ipc/ipc_handler_linux.h
@@ -0,0 +1,90 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <atomic>
+
+#include <base/files/file_path.h>
+#include <base/files/scoped_file.h>
+#include <base/macros.h>
+#include <base/threading/thread.h>
+
+#include "service/ipc/ipc_handler.h"
+#include "service/ipc/ipc_manager.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}  // namespace base
+
+namespace ipc {
+
+// Implements a Linux sequential packet domain-socket based IPCHandler
+class IPCHandlerLinux : public IPCHandler {
+ public:
+  IPCHandlerLinux(bluetooth::Adapter* adapter,
+                 IPCManager::Delegate* delegate);
+  ~IPCHandlerLinux() override;
+
+  // IPCHandler overrides:
+  bool Run() override;
+  void Stop() override;
+
+ private:
+  IPCHandlerLinux() = default;
+
+  // Starts listening for incoming connections. Posted on |thread_| by Run().
+  void StartListeningOnThread();
+
+  // Stops the IPC thread. This helper is needed since base::Thread requires
+  // threads to be stopped on the thread that started them.
+  void ShutDownOnOriginThread();
+
+  // Notifies the delegate that we started or stoppedlistening for incoming
+  // connections.
+  void NotifyStartedOnOriginThread();
+  void NotifyStartedOnCurrentThread();
+  void NotifyStoppedOnOriginThread();
+  void NotifyStoppedOnCurrentThread();
+
+  // True, if the IPC mechanism is running.
+#if defined(__APPLE__)
+  bool running_ ATTRIBUTE_UNUSED;
+#else
+  bool running_;
+#endif
+
+  // The server socket on which we listen to incoming connections.
+  base::ScopedFD socket_;
+
+  // The file path to |socket_|. This is only set if we create and manage the
+  // life time of the socket.
+  base::FilePath socket_path_;
+
+  // We use a dedicated thread for listening to incoming connections and
+  // polling from the socket to avoid blocking the main thread.
+  base::Thread thread_;
+
+  // Whether or not the listening thread should continue to run.
+  std::atomic<bool> keep_running_;
+
+  // The origin thread's task runner.
+  scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(IPCHandlerLinux);
+};
+
+}  // namespace ipc
diff --git a/bt/service/ipc/ipc_manager.cc b/bt/service/ipc/ipc_manager.cc
new file mode 100644
index 0000000..b0e82c8
--- /dev/null
+++ b/bt/service/ipc/ipc_manager.cc
@@ -0,0 +1,83 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/ipc/ipc_manager.h"
+
+#if !defined(OS_GENERIC)
+#include "service/ipc/binder/ipc_handler_binder.h"
+#endif  // !defined(OS_GENERIC)
+#include "service/ipc/ipc_handler_linux.h"
+
+namespace ipc {
+
+IPCManager::IPCManager(bluetooth::Adapter* adapter)
+    : adapter_(adapter) {
+  CHECK(adapter_);
+}
+
+IPCManager::~IPCManager() {
+  // Don't rely on the handlers getting destroyed since another thread might be
+  // holding a reference to them. Instead, explicitly stop them here.
+  if (BinderStarted())
+    binder_handler_->Stop();
+  if (LinuxStarted())
+    linux_handler_->Stop();
+}
+
+bool IPCManager::Start(Type type, Delegate* delegate) {
+  switch (type) {
+  case TYPE_LINUX:
+    if (LinuxStarted()) {
+      LOG(ERROR) << "IPCManagerLinux already started.";
+      return false;
+    }
+
+    linux_handler_ = new IPCHandlerLinux(adapter_, delegate);
+    if (!linux_handler_->Run()) {
+      linux_handler_ = nullptr;
+      return false;
+    }
+    return true;
+#if !defined(OS_GENERIC)
+  case TYPE_BINDER:
+    if (BinderStarted()) {
+      LOG(ERROR) << "IPCManagerBinder already started.";
+      return false;
+    }
+
+    binder_handler_ = new IPCHandlerBinder(adapter_, delegate);
+    if (!binder_handler_->Run()) {
+      binder_handler_ = nullptr;
+      return false;
+    }
+    return true;
+#endif  // !defined(OS_GENERIC)
+  default:
+    LOG(ERROR) << "Unsupported IPC type given: " << type;
+  }
+
+  return false;
+}
+
+bool IPCManager::BinderStarted() const {
+  return binder_handler_.get();
+}
+
+bool IPCManager::LinuxStarted() const {
+  return linux_handler_.get();
+}
+
+}  // namespace ipc
diff --git a/bt/service/ipc/ipc_manager.h b/bt/service/ipc/ipc_manager.h
new file mode 100644
index 0000000..c0ade0e
--- /dev/null
+++ b/bt/service/ipc/ipc_manager.h
@@ -0,0 +1,100 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <base/macros.h>
+#include <base/memory/ref_counted.h>
+
+namespace bluetooth {
+class Adapter;
+}  // namespace bluetooth
+
+namespace ipc {
+
+class IPCHandler;
+
+// IPCManager is a class for initializing and running supported IPC mechanisms.
+// It manages the life-time of different IPC flavors that are available on the
+// system. There are two flavors: a Linux sequential packet domain socket based
+// system and one based on the Binder-based android.bluetooth framework.
+class IPCManager {
+ public:
+  // Possible IPC types.
+  enum Type {
+    TYPE_LINUX,  // IPC based on a Linux sequential packet domain socket
+    TYPE_BINDER  // IPC based on the Binder
+  };
+
+  // Interface for observing events from an IPC mechanism. These methods will be
+  // called on the thread that started the particular IPC type.
+  class Delegate {
+   public:
+    Delegate() = default;
+    virtual ~Delegate() = default;
+
+    // Called when an IPC mechanism has successfully started and is ready for
+    // client connections.
+    virtual void OnIPCHandlerStarted(Type type) = 0;
+
+    // Called when an IPC mechanism has stopped. This may happen due to an error
+    // in initialization or due to a regular shut down routine.
+    virtual void OnIPCHandlerStopped(Type type) = 0;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Delegate);
+  };
+
+  explicit IPCManager(bluetooth::Adapter* adapter);
+  ~IPCManager();
+
+  // Initialize the underlying IPC handler based on |type|, if that type has not
+  // yet been initialized and returns true on success. Returns false if that
+  // type has already been initialized or an error occurs.
+  //
+  // If TYPE_LINUX is given, the file path to use for the domain socket will be
+  // obtained from the global Settings object. Hence, the Settings object must
+  // have been initialized before calling this method.
+  //
+  // |delegate| must out-live the IPCManager and the underlying handler. Users
+  // can guarantee proper clean up by deallocating |delegate| when or after
+  // Delegate::OnIPCHandlerStopped is called. It is safe to destroy |delegate|
+  // after destroying the IPCManager instance, as the destructor will join and
+  // clean up all underlying threads.
+  bool Start(Type type, Delegate* delegate);
+
+  // Returns true if an IPC type has been initialized.
+  bool BinderStarted() const;
+  bool LinuxStarted() const;
+
+ private:
+  IPCManager() = default;
+
+  // Pointers to the different IPC handler classes. These are initialized and
+  // owned by us.
+  scoped_refptr<IPCHandler> binder_handler_;
+  scoped_refptr<IPCHandler> linux_handler_;
+
+  // The Bluetooth adapter instance. This is owned by Daemon so we keep a raw
+  // pointer to it.
+  bluetooth::Adapter* adapter_;
+
+  DISALLOW_COPY_AND_ASSIGN(IPCManager);
+};
+
+}  // namespace ipc
diff --git a/bt/service/ipc/linux_ipc_host.cc b/bt/service/ipc/linux_ipc_host.cc
new file mode 100644
index 0000000..a3176a9
--- /dev/null
+++ b/bt/service/ipc/linux_ipc_host.cc
@@ -0,0 +1,343 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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_bluetooth_host"
+
+#include "service/ipc/linux_ipc_host.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <algorithm>
+
+#include <base/base64.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_split.h>
+
+#include "osi/include/osi.h"
+#include "osi/include/log.h"
+#include "service/adapter.h"
+
+using bluetooth::Adapter;
+using bluetooth::UUID;
+
+using namespace bluetooth::gatt;
+
+namespace {
+
+// IPC API is according to:
+// https://docs.google.com/document/d/1eRnku-jAyVU1wGJsLT2CzWi0-8bs2g49s1b3FR_GApM
+const char kSetAdapterNameCommand[] = "set-device-name";
+const char kCreateServiceCommand[] = "create-service";
+const char kDestroyServiceCommand[] = "destroy-service";
+const char kAddCharacteristicCommand[] = "add-characteristic";
+const char kSetCharacteristicValueCommand[] = "set-characteristic-value";
+const char kSetAdvertisementCommand[] = "set-advertisement";
+const char kSetScanResponseCommand[] = "set-scan-response";
+const char kStartServiceCommand[] = "start-service";
+const char kStopServiceCommand[] = "stop-service";
+const char kWriteCharacteristicCommand[] = "write-characteristic";
+
+// Useful values for indexing LinuxIPCHost::pfds_
+// Not super general considering that we should be able to support
+// many GATT FDs owned by one LinuxIPCHost.
+enum {
+  kFdIpc = 0,
+  kFdGatt = 1,
+  kPossibleFds = 2,
+};
+
+bool TokenBool(const std::string& text) {
+  return text == "true";
+}
+
+}  // namespace
+
+namespace ipc {
+
+LinuxIPCHost::LinuxIPCHost(int sockfd, Adapter* adapter)
+    : adapter_(adapter), pfds_(1, {sockfd, POLLIN, 0}) {}
+
+LinuxIPCHost::~LinuxIPCHost() {
+  close(pfds_[0].fd);
+}
+
+bool LinuxIPCHost::EventLoop() {
+  while (true) {
+    int status =
+        TEMP_FAILURE_RETRY(ppoll(pfds_.data(), pfds_.size(), nullptr, nullptr));
+    if (status < 1) {
+      LOG_ERROR(LOG_TAG, "ppoll error");
+      return false;
+    }
+
+    if (pfds_[kFdIpc].revents && !OnMessage()) {
+      return false;
+    }
+
+    if (pfds_.size() == kPossibleFds &&
+        pfds_[kFdGatt].revents &&
+        !OnGattWrite()) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool LinuxIPCHost::OnSetAdapterName(const std::string& name) {
+  std::string decoded_data;
+  base::Base64Decode(name, &decoded_data);
+  return adapter_->SetName(decoded_data);
+}
+
+bool LinuxIPCHost::OnCreateService(const std::string& service_uuid) {
+  gatt_servers_[service_uuid] = std::unique_ptr<Server>(new Server);
+
+  int gattfd;
+  bool status = gatt_servers_[service_uuid]->Initialize(
+          UUID(service_uuid), &gattfd);
+  if (!status) {
+    LOG_ERROR(LOG_TAG, "Failed to initialize bluetooth");
+    return false;
+  }
+  pfds_.resize(kPossibleFds);
+  pfds_[kFdGatt] = {gattfd, POLLIN, 0};
+  return true;
+}
+
+bool LinuxIPCHost::OnDestroyService(const std::string& service_uuid) {
+  gatt_servers_.erase(service_uuid);
+  close(pfds_[1].fd);
+  pfds_.resize(1);
+  return true;
+}
+
+bool LinuxIPCHost::OnAddCharacteristic(const std::string& service_uuid,
+                               const std::string& characteristic_uuid,
+                               const std::string& control_uuid,
+                               const std::string& options) {
+  std::vector<std::string> option_tokens = base::SplitString(
+      options, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+  int properties_mask = 0;
+  int permissions_mask = 0;
+
+  if (std::find(option_tokens.begin(), option_tokens.end(), "notify") !=
+      option_tokens.end()) {
+    permissions_mask |= kPermissionRead;
+    properties_mask |= kPropertyRead;
+    properties_mask |= kPropertyNotify;
+  }
+  if (std::find(option_tokens.begin(), option_tokens.end(), "read") !=
+      option_tokens.end()) {
+    permissions_mask |= kPermissionRead;
+    properties_mask |= kPropertyRead;
+  }
+  if (std::find(option_tokens.begin(), option_tokens.end(), "write") !=
+      option_tokens.end()) {
+    permissions_mask |= kPermissionWrite;
+    properties_mask |= kPropertyWrite;
+  }
+
+  if (control_uuid.empty()) {
+    gatt_servers_[service_uuid]->AddCharacteristic(
+        UUID(characteristic_uuid), properties_mask, permissions_mask);
+  } else {
+    gatt_servers_[service_uuid]->AddBlob(UUID(characteristic_uuid),
+                                         UUID(control_uuid), properties_mask,
+                                         permissions_mask);
+  }
+  return true;
+}
+
+bool LinuxIPCHost::OnSetCharacteristicValue(const std::string& service_uuid,
+                                    const std::string& characteristic_uuid,
+                                    const std::string& value) {
+  std::string decoded_data;
+  base::Base64Decode(value, &decoded_data);
+  std::vector<uint8_t> blob_data(decoded_data.begin(), decoded_data.end());
+  gatt_servers_[service_uuid]->SetCharacteristicValue(UUID(characteristic_uuid),
+                                                      blob_data);
+  return true;
+}
+
+bool LinuxIPCHost::OnSetAdvertisement(const std::string& service_uuid,
+                              const std::string& advertise_uuids,
+                              const std::string& advertise_data,
+                              const std::string& manufacturer_data,
+                              const std::string& transmit_name) {
+  LOG_INFO(LOG_TAG, "%s: service:%s uuids:%s data:%s", __func__, service_uuid.c_str(),
+           advertise_uuids.c_str(), advertise_data.c_str());
+
+  std::vector<std::string> advertise_uuid_tokens = base::SplitString(
+      advertise_uuids, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+  // string -> vector<UUID>
+  std::vector<UUID> ids;
+  for (const auto& uuid_token : advertise_uuid_tokens)
+    ids.emplace_back(uuid_token);
+
+  std::string decoded_data;
+  base::Base64Decode(advertise_data, &decoded_data);
+  std::vector<uint8_t> decoded_advertise_data(decoded_data.begin(),
+                                              decoded_data.end());
+
+  base::Base64Decode(manufacturer_data, &decoded_data);
+  std::vector<uint8_t> decoded_manufacturer_data(decoded_data.begin(),
+                                                 decoded_data.end());
+
+  gatt_servers_[service_uuid]->SetAdvertisement(ids, decoded_advertise_data,
+                                                decoded_manufacturer_data,
+                                                TokenBool(transmit_name));
+  return true;
+}
+
+bool LinuxIPCHost::OnSetScanResponse(const std::string& service_uuid,
+                             const std::string& scan_response_uuids,
+                             const std::string& scan_response_data,
+                             const std::string& manufacturer_data,
+                             const std::string& transmit_name) {
+  std::vector<std::string> scan_response_uuid_tokens = base::SplitString(
+      scan_response_uuids, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+  // string -> vector<UUID>
+  std::vector<UUID> ids;
+  for (const auto& uuid_token : scan_response_uuid_tokens)
+    ids.emplace_back(uuid_token);
+
+  std::string decoded_data;
+  base::Base64Decode(scan_response_data, &decoded_data);
+  std::vector<uint8_t> decoded_advertise_data(decoded_data.begin(),
+                                              decoded_data.end());
+
+  base::Base64Decode(manufacturer_data, &decoded_data);
+  std::vector<uint8_t> decoded_manufacturer_data(decoded_data.begin(),
+                                                 decoded_data.end());
+
+  gatt_servers_[service_uuid]->SetScanResponse(ids, decoded_advertise_data,
+                                               decoded_manufacturer_data,
+                                               TokenBool(transmit_name));
+  return true;
+}
+
+bool LinuxIPCHost::OnStartService(const std::string& service_uuid) {
+  return gatt_servers_[service_uuid]->Start();
+}
+
+bool LinuxIPCHost::OnStopService(const std::string& service_uuid) {
+  return gatt_servers_[service_uuid]->Stop();
+}
+
+bool LinuxIPCHost::OnMessage() {
+  std::string ipc_msg;
+  ssize_t size;
+
+  OSI_NO_INTR(size = recv(pfds_[kFdIpc].fd, &ipc_msg[0], 0,
+                          MSG_PEEK | MSG_TRUNC));
+  if (-1 == size) {
+    LOG_ERROR(LOG_TAG, "Error reading datagram size: %s", strerror(errno));
+    return false;
+  } else if (0 == size) {
+    LOG_INFO(LOG_TAG, "%s:%d: Connection closed", __func__, __LINE__);
+    return false;
+  }
+
+  ipc_msg.resize(size);
+  OSI_NO_INTR(size = read(pfds_[kFdIpc].fd, &ipc_msg[0], ipc_msg.size()));
+  if (-1 == size) {
+    LOG_ERROR(LOG_TAG, "Error reading IPC: %s", strerror(errno));
+    return false;
+  } else if (0 == size) {
+    LOG_INFO(LOG_TAG, "%s:%d: Connection closed", __func__, __LINE__);
+    return false;
+  }
+
+  std::vector<std::string> tokens = base::SplitString(
+      ipc_msg, "|", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+  switch (tokens.size()) {
+    case 2:
+      if (tokens[0] == kSetAdapterNameCommand)
+        return OnSetAdapterName(tokens[1]);
+      if (tokens[0] == kCreateServiceCommand)
+        return OnCreateService(tokens[1]);
+      if (tokens[0] == kDestroyServiceCommand)
+        return OnDestroyService(tokens[1]);
+      if (tokens[0] == kStartServiceCommand)
+        return OnStartService(tokens[1]);
+      if (tokens[0] == kStopServiceCommand)
+        return OnStopService(tokens[1]);
+      break;
+    case 4:
+      if (tokens[0] == kSetCharacteristicValueCommand)
+        return OnSetCharacteristicValue(tokens[1], tokens[2], tokens[3]);
+      break;
+    case 5:
+      if (tokens[0] == kAddCharacteristicCommand)
+        return OnAddCharacteristic(tokens[1], tokens[2], tokens[3], tokens[4]);
+      break;
+    case 6:
+      if (tokens[0] == kSetAdvertisementCommand)
+        return OnSetAdvertisement(tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]);
+      if (tokens[0] == kSetScanResponseCommand)
+        return OnSetScanResponse(tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]);
+      break;
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "Malformed IPC message: %s", ipc_msg.c_str());
+  return false;
+}
+
+bool LinuxIPCHost::OnGattWrite() {
+  UUID::UUID128Bit id;
+  ssize_t r;
+
+  OSI_NO_INTR(r = read(pfds_[kFdGatt].fd, id.data(), id.size()));
+  if (r != id.size()) {
+    LOG_ERROR(LOG_TAG, "Error reading GATT attribute ID");
+    return false;
+  }
+
+  std::vector<uint8_t> value;
+  // TODO(icoolidge): Generalize this for multiple clients.
+  auto server = gatt_servers_.begin();
+  server->second->GetCharacteristicValue(UUID(id), &value);
+  const std::string value_string(value.begin(), value.end());
+  std::string encoded_value;
+  base::Base64Encode(value_string, &encoded_value);
+
+  std::string transmit(kWriteCharacteristicCommand);
+  transmit += "|" + server->first;
+  transmit += "|" + base::HexEncode(id.data(), id.size());
+  transmit += "|" + encoded_value;
+
+  OSI_NO_INTR(r = write(pfds_[kFdIpc].fd, transmit.data(), transmit.size()));
+  if (-1 == r) {
+    LOG_ERROR(LOG_TAG, "Error replying to IPC: %s", strerror(errno));
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace ipc
diff --git a/bt/service/ipc/linux_ipc_host.h b/bt/service/ipc/linux_ipc_host.h
new file mode 100644
index 0000000..48d25cb
--- /dev/null
+++ b/bt/service/ipc/linux_ipc_host.h
@@ -0,0 +1,107 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <poll.h>
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include "service/common/bluetooth/uuid.h"
+#include "service/gatt_server_old.h"
+
+namespace bluetooth {
+class Adapter;
+}  // namespace bluetooth
+
+namespace ipc {
+
+// This implements a single threaded event loop which dispatches
+// reads from a set of FDs (pfds_) to a set of handlers.
+// Reads from the GATT pipe read end will result in a write to
+// to the IPC socket, and vise versa.
+class LinuxIPCHost {
+ public:
+  // LinuxIPCHost owns the passed sockfd.
+  LinuxIPCHost(int sockfd, bluetooth::Adapter* adapter);
+  ~LinuxIPCHost();
+
+  // Synchronously handle all events on input FDs.
+  bool EventLoop();
+
+ private:
+  // Handler for IPC message receives.
+  // Decodes protocol and dispatches to another handler.
+  bool OnMessage();
+
+  // Handler for GATT characteristic writes.
+  // Encodes to protocol and transmits IPC.
+  bool OnGattWrite();
+
+  // Applies adapter name changes to stack.
+  bool OnSetAdapterName(const std::string& name);
+
+  // Handles service creation.
+  bool OnCreateService(const std::string& service_uuid);
+
+  // Handles service destruction.
+  bool OnDestroyService(const std::string& service_uuid);
+
+  // Creates a characteristic for a service.
+  bool OnAddCharacteristic(const std::string& service_uuid,
+                           const std::string& characteristic_uuid,
+                           const std::string& control_uuid,
+                           const std::string& options);
+
+  // Sets the value of a characetistic.
+  bool OnSetCharacteristicValue(const std::string& service_uuid,
+                                const std::string& characteristic_uuid,
+                                const std::string& value);
+
+  // Applies settings to service advertisement.
+  bool OnSetAdvertisement(const std::string& service_uuid,
+                          const std::string& advertise_uuids,
+                          const std::string& advertise_data,
+                          const std::string& manufacturer_data,
+                          const std::string& transmit_name);
+
+  // Applies settings to scan response.
+  bool OnSetScanResponse(const std::string& service_uuid,
+                         const std::string& advertise_uuids,
+                         const std::string& advertise_data,
+                         const std::string& manufacturer_data,
+                         const std::string& transmit_name);
+
+  // Starts service (advertisement and connections)
+  bool OnStartService(const std::string& service_uuid);
+
+  // Stops service.
+  bool OnStopService(const std::string& service_uuid);
+
+  // weak reference.
+  bluetooth::Adapter *adapter_;
+
+  // File descripters that we will block against.
+  std::vector<struct pollfd> pfds_;
+
+  // Container for multiple GATT servers. Currently only one is supported.
+  // TODO(icoolidge): support many to one for real.
+  std::unordered_map<std::string, std::unique_ptr<bluetooth::gatt::Server>>
+      gatt_servers_;
+};
+
+}  // namespace ipc
diff --git a/bt/service/logging_helpers.cc b/bt/service/logging_helpers.cc
new file mode 100644
index 0000000..287a763
--- /dev/null
+++ b/bt/service/logging_helpers.cc
@@ -0,0 +1,149 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "logging_helpers.h"
+
+#include <string.h>
+
+#include <string>
+
+#define CASE_RETURN_TEXT(code) \
+  case code:                   \
+    return #code
+
+const char *BtAvConnectionStateText(const btav_connection_state_t state) {
+  switch (state) {
+    CASE_RETURN_TEXT(BTAV_CONNECTION_STATE_DISCONNECTED);
+    CASE_RETURN_TEXT(BTAV_CONNECTION_STATE_CONNECTING);
+    CASE_RETURN_TEXT(BTAV_CONNECTION_STATE_CONNECTED);
+    CASE_RETURN_TEXT(BTAV_CONNECTION_STATE_DISCONNECTING);
+    default:
+      return "Invalid AV connection state";
+  }
+}
+
+const char *BtAvAudioStateText(const btav_audio_state_t state) {
+  switch (state) {
+    CASE_RETURN_TEXT(BTAV_AUDIO_STATE_REMOTE_SUSPEND);
+    CASE_RETURN_TEXT(BTAV_AUDIO_STATE_STOPPED);
+    CASE_RETURN_TEXT(BTAV_AUDIO_STATE_STARTED);
+    default:
+      return "Invalid audio state";
+  }
+}
+
+const char *BtTransportText(const btgatt_transport_t t) {
+  switch(t) {
+    CASE_RETURN_TEXT(GATT_TRANSPORT_AUTO);
+    CASE_RETURN_TEXT(GATT_TRANSPORT_BREDR);
+    CASE_RETURN_TEXT(GATT_TRANSPORT_LE);
+    default:
+      return "unknown transport";
+  }
+}
+
+const char *BtStateText(const bt_state_t state) {
+  switch (state) {
+    CASE_RETURN_TEXT(BT_STATE_OFF);
+    CASE_RETURN_TEXT(BT_STATE_ON);
+    default:
+      return "unknown state code";
+  }
+}
+
+const char *BtDiscoveryStateText(const bt_discovery_state_t state) {
+  switch (state) {
+    CASE_RETURN_TEXT(BT_DISCOVERY_STOPPED);
+    CASE_RETURN_TEXT(BT_DISCOVERY_STARTED);
+    default:
+      return "unknown discovery state code";
+  }
+}
+
+const char *BtScanModeText(const bt_scan_mode_t mode) {
+  switch (mode) {
+    CASE_RETURN_TEXT(BT_SCAN_MODE_NONE);
+    CASE_RETURN_TEXT(BT_SCAN_MODE_CONNECTABLE);
+    CASE_RETURN_TEXT(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+    default:
+      return "unknown scan mode";
+  }
+}
+
+const char *BtStatusText(const bt_status_t status) {
+  switch (status) {
+    CASE_RETURN_TEXT(BT_STATUS_SUCCESS);
+    CASE_RETURN_TEXT(BT_STATUS_FAIL);
+    CASE_RETURN_TEXT(BT_STATUS_NOT_READY);
+    CASE_RETURN_TEXT(BT_STATUS_NOMEM);
+    CASE_RETURN_TEXT(BT_STATUS_DONE);
+    CASE_RETURN_TEXT(BT_STATUS_BUSY);
+    CASE_RETURN_TEXT(BT_STATUS_UNSUPPORTED);
+    CASE_RETURN_TEXT(BT_STATUS_PARM_INVALID);
+    CASE_RETURN_TEXT(BT_STATUS_UNHANDLED);
+    CASE_RETURN_TEXT(BT_STATUS_AUTH_FAILURE);
+    CASE_RETURN_TEXT(BT_STATUS_RMT_DEV_DOWN);
+    CASE_RETURN_TEXT(BT_STATUS_AUTH_REJECTED);
+    default:
+      return "unknown status code";
+  }
+}
+
+const char *BtPropertyText(const bt_property_type_t prop) {
+  switch (prop) {
+    CASE_RETURN_TEXT(BT_PROPERTY_BDNAME);
+    CASE_RETURN_TEXT(BT_PROPERTY_BDADDR);
+    CASE_RETURN_TEXT(BT_PROPERTY_UUIDS);
+    CASE_RETURN_TEXT(BT_PROPERTY_CLASS_OF_DEVICE);
+    CASE_RETURN_TEXT(BT_PROPERTY_TYPE_OF_DEVICE);
+    CASE_RETURN_TEXT(BT_PROPERTY_SERVICE_RECORD);
+    CASE_RETURN_TEXT(BT_PROPERTY_ADAPTER_SCAN_MODE);
+    CASE_RETURN_TEXT(BT_PROPERTY_ADAPTER_BONDED_DEVICES);
+    CASE_RETURN_TEXT(BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT);
+    CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_FRIENDLY_NAME);
+    CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_RSSI);
+    CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_VERSION_INFO);
+    CASE_RETURN_TEXT(BT_PROPERTY_LOCAL_LE_FEATURES);
+    CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP);
+    default:
+      return "Invalid property";
+  }
+}
+
+const char *BtEventText(const bt_cb_thread_evt evt) {
+  switch (evt) {
+    CASE_RETURN_TEXT(ASSOCIATE_JVM);
+    CASE_RETURN_TEXT(DISASSOCIATE_JVM);
+    default:
+      return "unknown state code";
+  }
+}
+
+const char *BtAclText(const bt_acl_state_t code) {
+  switch (code) {
+    CASE_RETURN_TEXT(BT_ACL_STATE_CONNECTED);
+    CASE_RETURN_TEXT(BT_ACL_STATE_DISCONNECTED);
+    default:
+      return "unknown ACL code";
+  }
+}
+
+std::string BtAddrString(const bt_bdaddr_t *addr) {
+  char buffer[20];
+  snprintf(buffer, sizeof(buffer), "%02X:%02X:%02X:%02X:%02X:%02X",
+           addr->address[0], addr->address[1], addr->address[2],
+           addr->address[3], addr->address[4], addr->address[5]);
+  return std::string(buffer);
+}
diff --git a/bt/service/logging_helpers.h b/bt/service/logging_helpers.h
new file mode 100644
index 0000000..6eb1cb1
--- /dev/null
+++ b/bt/service/logging_helpers.h
@@ -0,0 +1,47 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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.h>
+
+#include <string>
+
+#include "hardware/bluetooth.h"
+#include "hardware/bt_av.h"
+#include "hardware/bt_gatt_types.h"
+
+const char *BtAvConnectionStateText(const btav_connection_state_t state);
+
+const char *BtAvAudioStateText(const btav_audio_state_t state);
+
+const char *BtTransportText(const btgatt_transport_t t);
+
+const char *BtStateText(const bt_state_t state);
+
+const char *BtDiscoveryStateText(const bt_discovery_state_t);
+
+const char *BtScanModeText(const bt_scan_mode_t mode);
+
+const char *BtStatusText(const bt_status_t status);
+
+const char *BtPropertyText(const bt_property_type_t prop);
+
+const char *BtEventText(const bt_cb_thread_evt evt);
+
+const char *BtAclText(const bt_acl_state_t state);
+
+// TODO(icoolidge): Address object.
+std::string BtAddrString(const bt_bdaddr_t *addr);
diff --git a/bt/service/low_energy_advertiser.cc b/bt/service/low_energy_advertiser.cc
new file mode 100644
index 0000000..045dbe7
--- /dev/null
+++ b/bt/service/low_energy_advertiser.cc
@@ -0,0 +1,469 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/low_energy_advertiser.h"
+
+#include <base/bind.h>
+#include <base/logging.h>
+
+#include "service/adapter.h"
+#include "service/common/bluetooth/util/address_helper.h"
+#include "service/logging_helpers.h"
+#include "stack/include/bt_types.h"
+#include "stack/include/hcidefs.h"
+
+using std::lock_guard;
+using std::mutex;
+
+namespace bluetooth {
+
+namespace {
+
+BLEStatus GetBLEStatus(int status) {
+  if (status == BT_STATUS_FAIL)
+    return BLE_STATUS_FAILURE;
+
+  return static_cast<BLEStatus>(status);
+}
+
+// The Bluetooth Core Specification defines time interval (e.g. Page Scan
+// Interval, Advertising Interval, etc) units as 0.625 milliseconds (or 1
+// Baseband slot). The HAL advertising functions expect the interval in this
+// unit. This function maps an AdvertiseSettings::Mode value to the
+// corresponding time unit.
+int GetAdvertisingIntervalUnit(AdvertiseSettings::Mode mode) {
+  int ms;
+
+  switch (mode) {
+  case AdvertiseSettings::MODE_BALANCED:
+    ms = kAdvertisingIntervalMediumMs;
+    break;
+  case AdvertiseSettings::MODE_LOW_LATENCY:
+    ms = kAdvertisingIntervalLowMs;
+    break;
+  case AdvertiseSettings::MODE_LOW_POWER:
+    // Fall through
+  default:
+    ms = kAdvertisingIntervalHighMs;
+    break;
+  }
+
+  // Convert milliseconds to Bluetooth units.
+  return (ms * 1000) / 625;
+}
+
+struct AdvertiseParams {
+  int min_interval;
+  int max_interval;
+  int event_type;
+  int tx_power_level;
+  int timeout_s;
+};
+
+void GetAdvertiseParams(const AdvertiseSettings& settings, bool has_scan_rsp,
+                        AdvertiseParams* out_params) {
+  CHECK(out_params);
+
+  out_params->min_interval = GetAdvertisingIntervalUnit(settings.mode());
+  out_params->max_interval =
+      out_params->min_interval + kAdvertisingIntervalDeltaUnit;
+
+  if (settings.connectable())
+    out_params->event_type = kAdvertisingEventTypeConnectable;
+  else if (has_scan_rsp)
+    out_params->event_type = kAdvertisingEventTypeScannable;
+  else
+    out_params->event_type = kAdvertisingEventTypeNonConnectable;
+
+  out_params->tx_power_level = settings.tx_power_level();
+  out_params->timeout_s = settings.timeout().InSeconds();
+}
+
+void DoNothing(uint8_t status) {}
+
+}  // namespace
+
+// LowEnergyAdvertiser implementation
+// ========================================================
+
+LowEnergyAdvertiser::LowEnergyAdvertiser(const UUID& uuid, int advertiser_id) :
+      app_identifier_(uuid),
+      advertiser_id_(advertiser_id),
+      adv_data_needs_update_(false),
+      scan_rsp_needs_update_(false),
+      is_setting_adv_data_(false),
+      adv_started_(false),
+      adv_start_callback_(nullptr),
+      adv_stop_callback_(nullptr) {
+}
+
+LowEnergyAdvertiser::~LowEnergyAdvertiser() {
+  // Automatically unregister the advertiser.
+  VLOG(1) << "LowEnergyAdvertiser unregistering advertiser: " << advertiser_id_;
+
+  // Stop advertising and ignore the result.
+  hal::BluetoothGattInterface::Get()->
+      GetAdvertiserHALInterface()->MultiAdvEnable(advertiser_id_, false, base::Bind(&DoNothing), 0, base::Bind(&DoNothing));
+  hal::BluetoothGattInterface::Get()->
+      GetAdvertiserHALInterface()->Unregister(advertiser_id_);
+}
+
+bool LowEnergyAdvertiser::StartAdvertising(const AdvertiseSettings& settings,
+                                       const AdvertiseData& advertise_data,
+                                       const AdvertiseData& scan_response,
+                                       const StatusCallback& callback) {
+  VLOG(2) << __func__;
+  lock_guard<mutex> lock(adv_fields_lock_);
+
+  if (IsAdvertisingStarted()) {
+    LOG(WARNING) << "Already advertising";
+    return false;
+  }
+
+  if (IsStartingAdvertising()) {
+    LOG(WARNING) << "StartAdvertising already pending";
+    return false;
+  }
+
+  if (!advertise_data.IsValid()) {
+    LOG(ERROR) << "Invalid advertising data";
+    return false;
+  }
+
+  if (!scan_response.IsValid()) {
+    LOG(ERROR) << "Invalid scan response data";
+    return false;
+  }
+
+  CHECK(!adv_data_needs_update_.load());
+  CHECK(!scan_rsp_needs_update_.load());
+
+  adv_data_ = advertise_data;
+  scan_response_ = scan_response;
+  advertise_settings_ = settings;
+
+  AdvertiseParams params;
+  GetAdvertiseParams(settings, !scan_response_.data().empty(), &params);
+
+  hal::BluetoothGattInterface::Get()->
+      GetAdvertiserHALInterface()->MultiAdvSetParameters(
+          advertiser_id_,
+          params.min_interval,
+          params.max_interval,
+          params.event_type,
+          kAdvertisingChannelAll,
+          params.tx_power_level,
+          base::Bind(&LowEnergyAdvertiser::MultiAdvSetParamsCallback, base::Unretained(this), advertiser_id_));
+
+  // Always update advertising data.
+  adv_data_needs_update_ = true;
+
+  // Update scan response only if it has data, since otherwise we just won't
+  // send ADV_SCAN_IND.
+  if (!scan_response_.data().empty())
+    scan_rsp_needs_update_ = true;
+
+  // OK to set this at the end since we're still holding |adv_fields_lock_|.
+  adv_start_callback_.reset(new StatusCallback(callback));
+
+  return true;
+}
+
+bool LowEnergyAdvertiser::StopAdvertising(const StatusCallback& callback) {
+  VLOG(2) << __func__;
+  lock_guard<mutex> lock(adv_fields_lock_);
+
+  if (!IsAdvertisingStarted()) {
+    LOG(ERROR) << "Not advertising";
+    return false;
+  }
+
+  if (IsStoppingAdvertising()) {
+    LOG(ERROR) << "StopAdvertising already pending";
+    return false;
+  }
+
+  CHECK(!adv_start_callback_);
+
+  hal::BluetoothGattInterface::Get()
+      ->GetAdvertiserHALInterface()
+      ->MultiAdvEnable(
+          advertiser_id_, false,
+          base::Bind(&LowEnergyAdvertiser::MultiAdvEnableCallback,
+                     base::Unretained(this), false, advertiser_id_),
+          0, base::Bind(&LowEnergyAdvertiser::MultiAdvEnableCallback,
+                        base::Unretained(this), false, advertiser_id_));
+
+  // OK to set this at the end since we're still holding |adv_fields_lock_|.
+  adv_stop_callback_.reset(new StatusCallback(callback));
+
+  return true;
+}
+
+bool LowEnergyAdvertiser::IsAdvertisingStarted() const {
+  return adv_started_.load();
+}
+
+bool LowEnergyAdvertiser::IsStartingAdvertising() const {
+  return !IsAdvertisingStarted() && adv_start_callback_;
+}
+
+bool LowEnergyAdvertiser::IsStoppingAdvertising() const {
+  return IsAdvertisingStarted() && adv_stop_callback_;
+}
+
+const UUID& LowEnergyAdvertiser::GetAppIdentifier() const {
+  return app_identifier_;
+}
+
+int LowEnergyAdvertiser::GetInstanceId() const {
+  return advertiser_id_;
+}
+
+void LowEnergyAdvertiser::HandleDeferredAdvertiseData() {
+  VLOG(2) << __func__;
+
+  CHECK(!IsAdvertisingStarted());
+  CHECK(!IsStoppingAdvertising());
+  CHECK(IsStartingAdvertising());
+  CHECK(!is_setting_adv_data_.load());
+
+  if (adv_data_needs_update_.load()) {
+    bt_status_t status = SetAdvertiseData(adv_data_, false);
+    if (status != BT_STATUS_SUCCESS) {
+      LOG(ERROR) << "Failed setting advertisement data";
+      InvokeAndClearStartCallback(GetBLEStatus(status));
+    }
+    return;
+  }
+
+  if (scan_rsp_needs_update_.load()) {
+    bt_status_t status = SetAdvertiseData(scan_response_, true);
+    if (status != BT_STATUS_SUCCESS) {
+      LOG(ERROR) << "Failed setting scan response data";
+      InvokeAndClearStartCallback(GetBLEStatus(status));
+    }
+    return;
+  }
+
+  AdvertiseParams params;
+  GetAdvertiseParams(advertise_settings_, !scan_response_.data().empty(), &params);
+
+  hal::BluetoothGattInterface::Get()
+      ->GetAdvertiserHALInterface()
+      ->MultiAdvEnable(
+          advertiser_id_, true,
+          base::Bind(&LowEnergyAdvertiser::MultiAdvEnableCallback,
+                     base::Unretained(this), true, advertiser_id_),
+          params.timeout_s,
+          base::Bind(&LowEnergyAdvertiser::MultiAdvEnableCallback,
+                     base::Unretained(this), false, advertiser_id_));
+}
+
+void LowEnergyAdvertiser::MultiAdvSetParamsCallback(
+    uint8_t advertiser_id, uint8_t status) {
+  if (advertiser_id != advertiser_id_)
+    return;
+
+  lock_guard<mutex> lock(adv_fields_lock_);
+
+  VLOG(1) << __func__ << "advertiser_id: " << advertiser_id << " status: " << status;
+
+  // Terminate operation in case of error.
+  if (status != BT_STATUS_SUCCESS) {
+    LOG(ERROR) << "Failed to set advertising parameters";
+    InvokeAndClearStartCallback(GetBLEStatus(status));
+    return;
+  }
+
+  // Now handle deferred tasks.
+  HandleDeferredAdvertiseData();
+}
+
+void LowEnergyAdvertiser::MultiAdvDataCallback(
+    uint8_t advertiser_id, uint8_t status) {
+  if (advertiser_id != advertiser_id_)
+    return;
+
+  lock_guard<mutex> lock(adv_fields_lock_);
+
+  VLOG(1) << __func__ << "advertiser_id: " << advertiser_id << " status: " << status;
+
+  is_setting_adv_data_ = false;
+
+  // Terminate operation in case of error.
+  if (status != BT_STATUS_SUCCESS) {
+    LOG(ERROR) << "Failed to set advertising data";
+    InvokeAndClearStartCallback(GetBLEStatus(status));
+    return;
+  }
+
+  // Now handle deferred tasks.
+  HandleDeferredAdvertiseData();
+}
+
+void LowEnergyAdvertiser::MultiAdvEnableCallback(
+    bool enable, uint8_t advertiser_id, uint8_t status) {
+  if (advertiser_id != advertiser_id_)
+    return;
+
+  lock_guard<mutex> lock(adv_fields_lock_);
+
+  VLOG(1) << __func__ << "advertiser_id: " << advertiser_id
+          << " status: " << status
+          << " enable: " << enable;
+
+  if (enable) {
+    CHECK(adv_start_callback_);
+    CHECK(!adv_stop_callback_);
+
+    // Terminate operation in case of error.
+    if (status != BT_STATUS_SUCCESS) {
+      LOG(ERROR) << "Failed to enable multi-advertising";
+      InvokeAndClearStartCallback(GetBLEStatus(status));
+      return;
+    }
+
+    // All pending tasks are complete. Report success.
+    adv_started_ = true;
+    InvokeAndClearStartCallback(BLE_STATUS_SUCCESS);
+
+  } else {
+    CHECK(!adv_start_callback_);
+    CHECK(adv_stop_callback_);
+
+    if (status == BT_STATUS_SUCCESS) {
+      VLOG(1) << "Multi-advertising stopped for advertiser_id: " << advertiser_id;
+      adv_started_ = false;
+    } else {
+      LOG(ERROR) << "Failed to stop multi-advertising";
+    }
+
+    InvokeAndClearStopCallback(GetBLEStatus(status));
+  }
+}
+
+bt_status_t LowEnergyAdvertiser::SetAdvertiseData(
+    const AdvertiseData& data,
+    bool set_scan_rsp) {
+  VLOG(2) << __func__;
+
+  if (is_setting_adv_data_.load()) {
+    LOG(ERROR) << "Setting advertising data already in progress.";
+    return BT_STATUS_FAIL;
+  }
+
+  // TODO(armansito): The length fields in the BTIF function below are signed
+  // integers so a call to std::vector::size might get capped. This is very
+  // unlikely anyway but it's safer to stop using signed-integer types for
+  // length in APIs, so we should change that.
+  hal::BluetoothGattInterface::Get()
+      ->GetAdvertiserHALInterface()
+      ->MultiAdvSetInstData(
+          advertiser_id_, set_scan_rsp, data.data(),
+          base::Bind(&LowEnergyAdvertiser::MultiAdvDataCallback, base::Unretained(this), advertiser_id_));
+
+  if (set_scan_rsp)
+    scan_rsp_needs_update_ = false;
+  else
+    adv_data_needs_update_ = false;
+
+  is_setting_adv_data_ = true;
+
+  return BT_STATUS_SUCCESS;
+}
+
+void LowEnergyAdvertiser::InvokeAndClearStartCallback(BLEStatus status) {
+  adv_data_needs_update_ = false;
+  scan_rsp_needs_update_ = false;
+
+  // We allow NULL callbacks.
+  if (*adv_start_callback_)
+    (*adv_start_callback_)(status);
+
+  adv_start_callback_ = nullptr;
+}
+
+void LowEnergyAdvertiser::InvokeAndClearStopCallback(BLEStatus status) {
+  // We allow NULL callbacks.
+  if (*adv_stop_callback_)
+    (*adv_stop_callback_)(status);
+
+  adv_stop_callback_ = nullptr;
+}
+
+// LowEnergyAdvertiserFactory implementation
+// ========================================================
+
+LowEnergyAdvertiserFactory::LowEnergyAdvertiserFactory() {
+}
+
+LowEnergyAdvertiserFactory::~LowEnergyAdvertiserFactory() {
+}
+
+bool LowEnergyAdvertiserFactory::RegisterInstance(
+    const UUID& app_uuid, const RegisterCallback& callback) {
+  VLOG(1) << __func__;
+  lock_guard<mutex> lock(pending_calls_lock_);
+
+  if (pending_calls_.find(app_uuid) != pending_calls_.end()) {
+    LOG(ERROR) << "Low-Energy advertiser with given UUID already registered - "
+               << "UUID: " << app_uuid.ToString();
+    return false;
+  }
+
+  BleAdvertiserInterface* hal_iface =
+      hal::BluetoothGattInterface::Get()->GetAdvertiserHALInterface();
+
+  VLOG(1) << __func__ << " calling register!";
+  hal_iface->RegisterAdvertiser(
+      base::Bind(&LowEnergyAdvertiserFactory::RegisterAdvertiserCallback,
+                 base::Unretained(this), callback, app_uuid));
+  VLOG(1) << __func__ << " call finished!";
+
+  pending_calls_.insert(app_uuid);
+
+  return true;
+}
+
+void LowEnergyAdvertiserFactory::RegisterAdvertiserCallback(
+    const RegisterCallback& callback, const UUID& app_uuid,
+    uint8_t advertiser_id, uint8_t status) {
+  VLOG(1) << __func__;
+  lock_guard<mutex> lock(pending_calls_lock_);
+
+  auto iter = pending_calls_.find(app_uuid);
+  if (iter == pending_calls_.end()) {
+    VLOG(1) << "Ignoring callback for unknown app_id: " << app_uuid.ToString();
+    return;
+  }
+
+  // No need to construct a advertiser if the call wasn't successful.
+  std::unique_ptr<LowEnergyAdvertiser> advertiser;
+  BLEStatus result = BLE_STATUS_FAILURE;
+  if (status == BT_STATUS_SUCCESS) {
+    advertiser.reset(new LowEnergyAdvertiser(app_uuid, advertiser_id));
+
+    result = BLE_STATUS_SUCCESS;
+  }
+
+  // Notify the result via the result callback.
+  callback(result, app_uuid, std::move(advertiser));
+
+  pending_calls_.erase(iter);
+}
+
+}  // namespace bluetooth
diff --git a/bt/service/low_energy_advertiser.h b/bt/service/low_energy_advertiser.h
new file mode 100644
index 0000000..076eb3d
--- /dev/null
+++ b/bt/service/low_energy_advertiser.h
@@ -0,0 +1,169 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <atomic>
+#include <functional>
+#include <map>
+#include <mutex>
+
+#include <base/macros.h>
+
+#include "service/bluetooth_instance.h"
+#include "service/common/bluetooth/advertise_data.h"
+#include "service/common/bluetooth/advertise_settings.h"
+#include "service/common/bluetooth/low_energy_constants.h"
+#include "service/common/bluetooth/scan_filter.h"
+#include "service/common/bluetooth/scan_result.h"
+#include "service/common/bluetooth/scan_settings.h"
+#include "service/common/bluetooth/uuid.h"
+#include "service/hal/bluetooth_gatt_interface.h"
+
+namespace bluetooth {
+
+class Adapter;
+
+// A LowEnergyAdvertiser represents an application's handle to perform various
+// Bluetooth Low Energy GAP operations. Instances cannot be created directly and
+// should be obtained through the factory.
+class LowEnergyAdvertiser : public BluetoothInstance {
+ public:
+
+  // The destructor automatically unregisters this client instance from the
+  // stack.
+  ~LowEnergyAdvertiser() override;
+
+  // Callback type used to return the result of asynchronous operations below.
+  using StatusCallback = std::function<void(BLEStatus)>;
+
+  // Starts advertising based on the given advertising and scan response
+  // data and the provided |settings|. Reports the result of the operation in
+  // |callback|. Return true on success, false otherwise. Please see logs for
+  // details in case of error.
+  bool StartAdvertising(const AdvertiseSettings& settings,
+                        const AdvertiseData& advertise_data,
+                        const AdvertiseData& scan_response,
+                        const StatusCallback& callback);
+
+  // Stops advertising if it was already started. Reports the result of the
+  // operation in |callback|.
+  bool StopAdvertising(const StatusCallback& callback);
+
+  // Returns true if advertising has been started.
+  bool IsAdvertisingStarted() const;
+
+  // Returns the state of pending advertising operations.
+  bool IsStartingAdvertising() const;
+  bool IsStoppingAdvertising() const;
+
+  // Returns the current advertising settings.
+  const AdvertiseSettings& advertise_settings() const {
+    return advertise_settings_;
+  }
+
+  // BluetoothClientInstace overrides:
+  const UUID& GetAppIdentifier() const override;
+  int GetInstanceId() const override;
+
+ private:
+  friend class LowEnergyAdvertiserFactory;
+
+  // Constructor shouldn't be called directly as instances are meant to be
+  // obtained from the factory.
+  LowEnergyAdvertiser(const UUID& uuid, int advertiser_id);
+
+  // BluetoothGattInterface::AdvertiserObserver overrides:
+  void MultiAdvDataCallback(
+      uint8_t advertiser_id, uint8_t status);
+  void MultiAdvSetParamsCallback(
+      uint8_t advertiser_id, uint8_t status);
+  void MultiAdvEnableCallback(
+      bool enable, uint8_t advertiser_id, uint8_t status);
+
+  // Helper method called from SetAdvertiseData/SetScanResponse.
+  bt_status_t SetAdvertiseData(
+      const AdvertiseData& data,
+      bool set_scan_rsp);
+
+  // Handles deferred advertise/scan-response data updates. We set the data if
+  // there's data to be set, otherwise we either defer it if advertisements
+  // aren't enabled or do nothing.
+  void HandleDeferredAdvertiseData();
+
+  // Calls and clears the pending callbacks.
+  void InvokeAndClearStartCallback(BLEStatus status);
+  void InvokeAndClearStopCallback(BLEStatus status);
+
+  // See getters above for documentation.
+  UUID app_identifier_;
+  int advertiser_id_;
+
+  // Protects advertising-related members below.
+  std::mutex adv_fields_lock_;
+
+  // The advertising and scan response data fields that will be sent to the
+  // controller.
+  AdvertiseData adv_data_;
+  AdvertiseData scan_response_;
+  std::atomic_bool adv_data_needs_update_;
+  std::atomic_bool scan_rsp_needs_update_;
+
+  // Latest advertising settings.
+  AdvertiseSettings advertise_settings_;
+
+  // Whether or not there is a pending call to update advertising or scan
+  // response data.
+  std::atomic_bool is_setting_adv_data_;
+
+  std::atomic_bool adv_started_;
+  std::unique_ptr<StatusCallback> adv_start_callback_;
+  std::unique_ptr<StatusCallback> adv_stop_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(LowEnergyAdvertiser);
+};
+
+// LowEnergyAdvertiserFactory is used to register and obtain a per-application
+// LowEnergyAdvertiser instance. Users should call RegisterInstance to obtain their
+// own unique LowEnergyAdvertiser instance that has been registered with the
+// Bluetooth stack.
+class LowEnergyAdvertiserFactory
+    : public BluetoothInstanceFactory {
+ public:
+  // Don't construct/destruct directly except in tests. Instead, obtain a handle
+  // from an Adapter instance.
+  explicit LowEnergyAdvertiserFactory();
+  ~LowEnergyAdvertiserFactory() override;
+
+  // BluetoothInstanceFactory override:
+  bool RegisterInstance(const UUID& app_uuid, const RegisterCallback& callback) override;
+
+ private:
+  friend class LowEnergyAdvertiser;
+
+  // BluetoothGattInterface::AdvertiserObserver overrides:
+  void RegisterAdvertiserCallback(const RegisterCallback& callback,
+                                  const UUID& app_uuid, uint8_t advertiser_id,
+                                  uint8_t status);
+
+  // Map of pending calls to register.
+  std::mutex pending_calls_lock_;
+  std::unordered_set<UUID> pending_calls_;
+
+  DISALLOW_COPY_AND_ASSIGN(LowEnergyAdvertiserFactory);
+};
+
+}  // namespace bluetooth
diff --git a/bt/service/low_energy_client.cc b/bt/service/low_energy_client.cc
new file mode 100644
index 0000000..3fce035
--- /dev/null
+++ b/bt/service/low_energy_client.cc
@@ -0,0 +1,270 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/low_energy_client.h"
+
+#include <base/logging.h>
+
+#include "service/adapter.h"
+#include "service/common/bluetooth/util/address_helper.h"
+#include "service/logging_helpers.h"
+#include "stack/include/bt_types.h"
+#include "stack/include/hcidefs.h"
+
+using std::lock_guard;
+using std::mutex;
+
+namespace bluetooth {
+
+// LowEnergyClient implementation
+// ========================================================
+
+LowEnergyClient::LowEnergyClient(
+    Adapter& adapter, const UUID& uuid, int client_id)
+    : adapter_(adapter),
+      app_identifier_(uuid),
+      client_id_(client_id),
+      delegate_(nullptr) {
+}
+
+LowEnergyClient::~LowEnergyClient() {
+  // Automatically unregister the client.
+  VLOG(1) << "LowEnergyClient unregistering client: " << client_id_;
+
+  // Unregister as observer so we no longer receive any callbacks.
+  hal::BluetoothGattInterface::Get()->RemoveClientObserver(this);
+
+  hal::BluetoothGattInterface::Get()->
+      GetClientHALInterface()->unregister_client(client_id_);
+}
+
+bool LowEnergyClient::Connect(const std::string& address, bool is_direct) {
+  VLOG(2) << __func__ << "Address: " << address << " is_direct: " << is_direct;
+
+  bt_bdaddr_t bda;
+  util::BdAddrFromString(address, &bda);
+
+  bt_status_t status = hal::BluetoothGattInterface::Get()->
+      GetClientHALInterface()->connect(client_id_, &bda, is_direct,
+                                       BT_TRANSPORT_LE);
+  if (status != BT_STATUS_SUCCESS) {
+    LOG(ERROR) << "HAL call to connect failed";
+    return false;
+  }
+
+  return true;
+}
+
+bool LowEnergyClient::Disconnect(const std::string& address) {
+  VLOG(2) << __func__ << "Address: " << address;
+
+  bt_bdaddr_t bda;
+  util::BdAddrFromString(address, &bda);
+
+  std::map<const bt_bdaddr_t, int>::iterator conn_id;
+  {
+    lock_guard<mutex> lock(connection_fields_lock_);
+    conn_id = connection_ids_.find(bda);
+    if (conn_id == connection_ids_.end()) {
+      LOG(WARNING) << "Can't disconnect, no existing connection to " << address;
+      return false;
+    }
+  }
+
+  bt_status_t status = hal::BluetoothGattInterface::Get()->
+      GetClientHALInterface()->disconnect(client_id_, &bda, conn_id->second);
+  if (status != BT_STATUS_SUCCESS) {
+    LOG(ERROR) << "HAL call to disconnect failed";
+    return false;
+  }
+
+  return true;
+}
+
+bool LowEnergyClient::SetMtu(const std::string& address, int mtu) {
+  VLOG(2) << __func__ << "Address: " << address
+          << " MTU: " << mtu;
+
+  bt_bdaddr_t bda;
+  util::BdAddrFromString(address, &bda);
+
+  std::map<const bt_bdaddr_t, int>::iterator conn_id;
+  {
+    lock_guard<mutex> lock(connection_fields_lock_);
+    conn_id = connection_ids_.find(bda);
+    if (conn_id == connection_ids_.end()) {
+      LOG(WARNING) << "Can't set MTU, no existing connection to " << address;
+      return false;
+    }
+  }
+
+  bt_status_t status = hal::BluetoothGattInterface::Get()->
+      GetClientHALInterface()->configure_mtu(conn_id->second, mtu);
+  if (status != BT_STATUS_SUCCESS) {
+    LOG(ERROR) << "HAL call to set MTU failed";
+    return false;
+  }
+
+  return true;
+}
+
+void LowEnergyClient::SetDelegate(Delegate* delegate) {
+  lock_guard<mutex> lock(delegate_mutex_);
+  delegate_ = delegate;
+}
+
+const UUID& LowEnergyClient::GetAppIdentifier() const {
+  return app_identifier_;
+}
+
+int LowEnergyClient::GetInstanceId() const {
+  return client_id_;
+}
+
+void LowEnergyClient::ConnectCallback(
+      hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
+      int client_id, const bt_bdaddr_t& bda) {
+  if (client_id != client_id_)
+    return;
+
+  VLOG(1) << __func__ << "client_id: " << client_id << " status: " << status;
+
+  {
+    lock_guard<mutex> lock(connection_fields_lock_);
+    auto success = connection_ids_.emplace(bda, conn_id);
+    if (!success.second) {
+      LOG(ERROR) << __func__ << " Insertion into connection_ids_ failed!";
+    }
+  }
+
+  if (delegate_)
+    delegate_->OnConnectionState(this, status, BtAddrString(&bda).c_str(),
+                                 true);
+}
+
+void LowEnergyClient::DisconnectCallback(
+      hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
+      int client_id, const bt_bdaddr_t& bda) {
+  if (client_id != client_id_)
+    return;
+
+  VLOG(1) << __func__ << " client_id: " << client_id << " status: " << status;
+  {
+    lock_guard<mutex> lock(connection_fields_lock_);
+    if (!connection_ids_.erase(bda)) {
+      LOG(ERROR) << __func__ << " Erasing from connection_ids_ failed!";
+    }
+  }
+
+  if (delegate_)
+    delegate_->OnConnectionState(this, status, BtAddrString(&bda).c_str(),
+                                 false);
+}
+
+void LowEnergyClient::MtuChangedCallback(
+      hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
+      int mtu) {
+  VLOG(1) << __func__ << " conn_id: " << conn_id << " status: " << status
+          << " mtu: " << mtu;
+
+  const bt_bdaddr_t *bda = nullptr;
+  {
+    lock_guard<mutex> lock(connection_fields_lock_);
+    for (auto& connection: connection_ids_) {
+      if (connection.second == conn_id) {
+        bda = &connection.first;
+        break;
+      }
+    }
+  }
+
+  if (!bda)
+    return;
+
+  const char *addr = BtAddrString(bda).c_str();
+  if (delegate_)
+    delegate_->OnMtuChanged(this, status, addr, mtu);
+}
+
+// LowEnergyClientFactory implementation
+// ========================================================
+
+LowEnergyClientFactory::LowEnergyClientFactory(Adapter& adapter)
+    : adapter_(adapter) {
+  hal::BluetoothGattInterface::Get()->AddClientObserver(this);
+}
+
+LowEnergyClientFactory::~LowEnergyClientFactory() {
+  hal::BluetoothGattInterface::Get()->RemoveClientObserver(this);
+}
+
+bool LowEnergyClientFactory::RegisterInstance(
+    const UUID& uuid,
+    const RegisterCallback& callback) {
+  VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+  lock_guard<mutex> lock(pending_calls_lock_);
+
+  if (pending_calls_.find(uuid) != pending_calls_.end()) {
+    LOG(ERROR) << "Low-Energy client with given UUID already registered - "
+               << "UUID: " << uuid.ToString();
+    return false;
+  }
+
+  const btgatt_client_interface_t* hal_iface =
+      hal::BluetoothGattInterface::Get()->GetClientHALInterface();
+  bt_uuid_t app_uuid = uuid.GetBlueDroid();
+
+  if (hal_iface->register_client(&app_uuid) != BT_STATUS_SUCCESS)
+    return false;
+
+  pending_calls_[uuid] = callback;
+
+  return true;
+}
+
+void LowEnergyClientFactory::RegisterClientCallback(
+    hal::BluetoothGattInterface* gatt_iface,
+    int status, int client_id,
+    const bt_uuid_t& app_uuid) {
+  UUID uuid(app_uuid);
+
+  VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+  lock_guard<mutex> lock(pending_calls_lock_);
+
+  auto iter = pending_calls_.find(uuid);
+  if (iter == pending_calls_.end()) {
+    VLOG(1) << "Ignoring callback for unknown app_id: " << uuid.ToString();
+    return;
+  }
+
+  // No need to construct a client if the call wasn't successful.
+  std::unique_ptr<LowEnergyClient> client;
+  BLEStatus result = BLE_STATUS_FAILURE;
+  if (status == BT_STATUS_SUCCESS) {
+    client.reset(new LowEnergyClient(adapter_, uuid, client_id));
+
+    gatt_iface->AddClientObserver(client.get());
+
+    result = BLE_STATUS_SUCCESS;
+  }
+
+  // Notify the result via the result callback.
+  iter->second(result, uuid, std::move(client));
+
+  pending_calls_.erase(iter);
+}
+
+}  // namespace bluetooth
diff --git a/bt/service/low_energy_client.h b/bt/service/low_energy_client.h
new file mode 100644
index 0000000..b8e4fec
--- /dev/null
+++ b/bt/service/low_energy_client.h
@@ -0,0 +1,177 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <atomic>
+#include <functional>
+#include <map>
+#include <mutex>
+
+#include <base/macros.h>
+
+#include "service/bluetooth_instance.h"
+#include "service/common/bluetooth/low_energy_constants.h"
+#include "service/common/bluetooth/scan_filter.h"
+#include "service/common/bluetooth/scan_result.h"
+#include "service/common/bluetooth/scan_settings.h"
+#include "service/common/bluetooth/uuid.h"
+#include "service/hal/bluetooth_gatt_interface.h"
+
+namespace bluetooth {
+
+struct ConnComparator {
+    bool operator()(const bt_bdaddr_t& a, const bt_bdaddr_t& b) const {
+        return memcmp(&a, &b, sizeof(bt_bdaddr_t)) < 0;
+    }
+};
+
+class Adapter;
+
+// A LowEnergyClient represents an application's handle to perform various
+// Bluetooth Low Energy GAP operations. Instances cannot be created directly and
+// should be obtained through the factory.
+class LowEnergyClient : private hal::BluetoothGattInterface::ClientObserver,
+                        public BluetoothInstance {
+ public:
+  // The Delegate interface is used to notify asynchronous events related to BLE
+  // GAP operations.
+  class Delegate {
+   public:
+    Delegate() = default;
+    virtual ~Delegate() = default;
+
+    // Called asynchronously to notify the delegate of connection state change
+    virtual void OnConnectionState(LowEnergyClient* client, int status,
+                                   const char* address, bool connected) = 0;
+
+    // Called asynchronously to notify the delegate of mtu change
+    virtual void OnMtuChanged(LowEnergyClient* client, int status, const char* address,
+                              int mtu) = 0;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Delegate);
+  };
+
+  // The destructor automatically unregisters this client instance from the
+  // stack.
+  ~LowEnergyClient() override;
+
+  // Assigns a delegate to this instance. |delegate| must out-live this
+  // LowEnergyClient instance.
+  void SetDelegate(Delegate* delegate);
+
+  // Callback type used to return the result of asynchronous operations below.
+  using StatusCallback = std::function<void(BLEStatus)>;
+
+  // Initiates a BLE connection do device with address |address|. If
+  // |is_direct| is set, use direct connect procedure. Return true on success
+  //, false otherwise.
+  bool Connect(const std::string& address, bool is_direct);
+
+  // Disconnect from previously connected BLE device with address |address|.
+  // Return true on success, false otherwise.
+  bool Disconnect(const std::string& address);
+
+  // Sends request to set MTU to |mtu| for device with address |address|.
+  // Return true on success, false otherwise.
+  bool SetMtu(const std::string& address, int mtu);
+
+  // BluetoothClientInstace overrides:
+  const UUID& GetAppIdentifier() const override;
+  int GetInstanceId() const override;
+
+ private:
+  friend class LowEnergyClientFactory;
+
+  // Constructor shouldn't be called directly as instances are meant to be
+  // obtained from the factory.
+  LowEnergyClient(Adapter& adapter, const UUID& uuid, int client_id);
+
+  // BluetoothGattInterface::ClientObserver overrides:
+  void ConnectCallback(
+      hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
+      int client_id, const bt_bdaddr_t& bda) override;
+  void DisconnectCallback(
+      hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
+      int client_id, const bt_bdaddr_t& bda) override;
+  void MtuChangedCallback(
+      hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
+      int mtu) override;
+
+  // Calls and clears the pending callbacks.
+  void InvokeAndClearStartCallback(BLEStatus status);
+  void InvokeAndClearStopCallback(BLEStatus status);
+
+  // Raw pointer to the Bluetooth Adapter.
+  Adapter& adapter_;
+
+  // See getters above for documentation.
+  UUID app_identifier_;
+  int client_id_;
+
+  // Raw handle to the Delegate, which must outlive this LowEnergyClient
+  // instance.
+  std::mutex delegate_mutex_;
+  Delegate* delegate_;
+
+  // Protects device connection related members below.
+  std::mutex connection_fields_lock_;
+
+  // Maps bluetooth address to connection id
+  //TODO(jpawlowski): change type to bimap
+  std::map<const bt_bdaddr_t, int, ConnComparator> connection_ids_;
+
+  DISALLOW_COPY_AND_ASSIGN(LowEnergyClient);
+};
+
+// LowEnergyClientFactory is used to register and obtain a per-application
+// LowEnergyClient instance. Users should call RegisterInstance to obtain their
+// own unique LowEnergyClient instance that has been registered with the
+// Bluetooth stack.
+class LowEnergyClientFactory
+    : private hal::BluetoothGattInterface::ClientObserver,
+      public BluetoothInstanceFactory {
+ public:
+  // Don't construct/destruct directly except in tests. Instead, obtain a handle
+  // from an Adapter instance.
+  explicit LowEnergyClientFactory(Adapter& adapter);
+  ~LowEnergyClientFactory() override;
+
+  // BluetoothInstanceFactory override:
+  bool RegisterInstance(const UUID& uuid,
+                        const RegisterCallback& callback) override;
+
+ private:
+  friend class LowEnergyClient;
+
+  // BluetoothGattInterface::ClientObserver overrides:
+  void RegisterClientCallback(
+      hal::BluetoothGattInterface* gatt_iface,
+      int status, int client_id,
+      const bt_uuid_t& app_uuid) override;
+
+  // Map of pending calls to register.
+  std::mutex pending_calls_lock_;
+  std::map<UUID, RegisterCallback> pending_calls_;
+
+  // Raw pointer to the Adapter that owns this factory.
+  Adapter& adapter_;
+
+  DISALLOW_COPY_AND_ASSIGN(LowEnergyClientFactory);
+};
+
+}  // namespace bluetooth
diff --git a/bt/service/low_energy_scanner.cc b/bt/service/low_energy_scanner.cc
new file mode 100644
index 0000000..c865e9b
--- /dev/null
+++ b/bt/service/low_energy_scanner.cc
@@ -0,0 +1,234 @@
+//
+//  Copyright (C) 2016 The Android Open Source Project
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+
+#include "service/low_energy_scanner.h"
+
+#include <base/bind.h>
+#include <base/logging.h>
+
+#include "service/adapter.h"
+#include "service/common/bluetooth/util/address_helper.h"
+#include "service/logging_helpers.h"
+#include "stack/include/bt_types.h"
+#include "stack/include/hcidefs.h"
+
+using std::lock_guard;
+using std::mutex;
+
+namespace bluetooth {
+
+namespace {
+
+// 31 + 31 for advertising data and scan response. This is the maximum length
+// TODO(armansito): Fix the HAL to return a concatenated blob that contains the
+// true length of each field and also provide a length parameter so that we
+// can support advertising length extensions in the future.
+const size_t kScanRecordLength = 62;
+
+// Returns the length of the given scan record array. We have to calculate this
+// based on the maximum possible data length and the TLV data. See TODO above
+// |kScanRecordLength|.
+size_t GetScanRecordLength(vector<uint8_t> bytes) {
+  for (size_t i = 0, field_len = 0; i < kScanRecordLength;
+       i += (field_len + 1)) {
+    field_len = bytes[i];
+
+    // Assert here that the data returned from the stack is correctly formatted
+    // in TLV form and that the length of the current field won't exceed the
+    // total data length.
+    CHECK(i + field_len < kScanRecordLength);
+
+    // If the field length is zero and we haven't reached the maximum length,
+    // then we have found the length, as the stack will pad the data with zeros
+    // accordingly.
+    if (field_len == 0)
+      return i;
+  }
+
+  // We have reached the end.
+  return kScanRecordLength;
+}
+
+}  // namespace
+
+// LowEnergyScanner implementation
+// ========================================================
+
+LowEnergyScanner::LowEnergyScanner(Adapter& adapter, const UUID& uuid,
+                                   int scanner_id)
+    : adapter_(adapter),
+      app_identifier_(uuid),
+      scanner_id_(scanner_id),
+      scan_started_(false),
+      delegate_(nullptr) {}
+
+LowEnergyScanner::~LowEnergyScanner() {
+  // Automatically unregister the scanner.
+  VLOG(1) << "LowEnergyScanner unregistering scanner: " << scanner_id_;
+
+  // Unregister as observer so we no longer receive any callbacks.
+  hal::BluetoothGattInterface::Get()->RemoveScannerObserver(this);
+
+  hal::BluetoothGattInterface::Get()->
+      GetScannerHALInterface()->unregister_scanner(scanner_id_);
+
+  // Stop any scans started by this client.
+  if (scan_started_.load())
+    StopScan();
+}
+
+void LowEnergyScanner::SetDelegate(Delegate* delegate) {
+  lock_guard<mutex> lock(delegate_mutex_);
+  delegate_ = delegate;
+}
+
+bool LowEnergyScanner::StartScan(const ScanSettings& settings,
+                                const std::vector<ScanFilter>& filters) {
+  VLOG(2) << __func__;
+
+  // Cannot start a scan if the adapter is not enabled.
+  if (!adapter_.IsEnabled()) {
+    LOG(ERROR) << "Cannot scan while Bluetooth is disabled";
+    return false;
+  }
+
+  // TODO(jpawlowski): Push settings and filtering logic below the HAL.
+  bt_status_t status = hal::BluetoothGattInterface::Get()->
+      StartScan(scanner_id_);
+  if (status != BT_STATUS_SUCCESS) {
+    LOG(ERROR) << "Failed to initiate scanning for client: " << scanner_id_;
+    return false;
+  }
+
+  scan_started_ = true;
+  return true;
+}
+
+bool LowEnergyScanner::StopScan() {
+  VLOG(2) << __func__;
+
+  // TODO(armansito): We don't support batch scanning yet so call
+  // StopRegularScanForClient directly. In the future we will need to
+  // conditionally call a batch scan API here.
+  bt_status_t status = hal::BluetoothGattInterface::Get()->
+      StopScan(scanner_id_);
+  if (status != BT_STATUS_SUCCESS) {
+    LOG(ERROR) << "Failed to stop scan for client: " << scanner_id_;
+    return false;
+  }
+
+  scan_started_ = false;
+  return true;
+}
+
+const UUID& LowEnergyScanner::GetAppIdentifier() const {
+  return app_identifier_;
+}
+
+int LowEnergyScanner::GetInstanceId() const {
+  return scanner_id_;
+}
+
+void LowEnergyScanner::ScanResultCallback(
+    hal::BluetoothGattInterface* gatt_iface,
+    const bt_bdaddr_t& bda, int rssi, vector<uint8_t> adv_data) {
+  // Ignore scan results if this client didn't start a scan.
+  if (!scan_started_.load())
+    return;
+
+  lock_guard<mutex> lock(delegate_mutex_);
+  if (!delegate_)
+    return;
+
+  // TODO(armansito): Apply software filters here.
+
+  size_t record_len = GetScanRecordLength(adv_data);
+  std::vector<uint8_t> scan_record(adv_data.begin(), adv_data.begin() + record_len);
+
+  ScanResult result(BtAddrString(&bda), scan_record, rssi);
+
+  delegate_->OnScanResult(this, result);
+}
+
+// LowEnergyScannerFactory implementation
+// ========================================================
+
+LowEnergyScannerFactory::LowEnergyScannerFactory(Adapter& adapter) : adapter_(adapter) {
+  hal::BluetoothGattInterface::Get()->AddScannerObserver(this);
+}
+
+LowEnergyScannerFactory::~LowEnergyScannerFactory() {
+  hal::BluetoothGattInterface::Get()->RemoveScannerObserver(this);
+}
+
+bool LowEnergyScannerFactory::RegisterInstance(
+    const UUID& uuid,
+    const RegisterCallback& callback) {
+  VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+  lock_guard<mutex> lock(pending_calls_lock_);
+
+  if (pending_calls_.find(uuid) != pending_calls_.end()) {
+    LOG(ERROR) << "Low-Energy scanner with given UUID already registered - "
+               << "UUID: " << uuid.ToString();
+    return false;
+  }
+
+  const btgatt_scanner_interface_t* hal_iface =
+      hal::BluetoothGattInterface::Get()->GetScannerHALInterface();
+  bt_uuid_t app_uuid = uuid.GetBlueDroid();
+
+  if (hal_iface->register_scanner(&app_uuid) != BT_STATUS_SUCCESS)
+    return false;
+
+  pending_calls_[uuid] = callback;
+
+  return true;
+}
+
+void LowEnergyScannerFactory::RegisterScannerCallback(
+    hal::BluetoothGattInterface* gatt_iface,
+    int status, int scanner_id,
+    const bt_uuid_t& app_uuid) {
+  UUID uuid(app_uuid);
+
+  VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+  lock_guard<mutex> lock(pending_calls_lock_);
+
+  auto iter = pending_calls_.find(uuid);
+  if (iter == pending_calls_.end()) {
+    VLOG(1) << "Ignoring callback for unknown app_id: " << uuid.ToString();
+    return;
+  }
+
+  // No need to construct a scanner if the call wasn't successful.
+  std::unique_ptr<LowEnergyScanner> scanner;
+  BLEStatus result = BLE_STATUS_FAILURE;
+  if (status == BT_STATUS_SUCCESS) {
+    scanner.reset(new LowEnergyScanner(adapter_, uuid, scanner_id));
+
+    gatt_iface->AddScannerObserver(scanner.get());
+
+    result = BLE_STATUS_SUCCESS;
+  }
+
+  // Notify the result via the result callback.
+  iter->second(result, uuid, std::move(scanner));
+
+  pending_calls_.erase(iter);
+}
+
+
+}  // namespace bluetooth
diff --git a/bt/service/low_energy_scanner.h b/bt/service/low_energy_scanner.h
new file mode 100644
index 0000000..cae1f58
--- /dev/null
+++ b/bt/service/low_energy_scanner.h
@@ -0,0 +1,160 @@
+//
+//  Copyright (C) 2016 The Android Open Source Project
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+
+#pragma once
+
+#include <atomic>
+#include <functional>
+#include <map>
+#include <mutex>
+
+#include <base/macros.h>
+
+#include "service/bluetooth_instance.h"
+#include "service/common/bluetooth/advertise_data.h"
+#include "service/common/bluetooth/advertise_settings.h"
+#include "service/common/bluetooth/low_energy_constants.h"
+#include "service/common/bluetooth/scan_filter.h"
+#include "service/common/bluetooth/scan_result.h"
+#include "service/common/bluetooth/scan_settings.h"
+#include "service/common/bluetooth/uuid.h"
+#include "service/hal/bluetooth_gatt_interface.h"
+
+namespace bluetooth {
+
+class Adapter;
+
+// A LowEnergyScanner represents an application's handle to perform various
+// Bluetooth Low Energy GAP operations. Instances cannot be created directly and
+// should be obtained through the factory.
+class LowEnergyScanner : private hal::BluetoothGattInterface::ScannerObserver,
+                         public BluetoothInstance {
+ public:
+  // The Delegate interface is used to notify asynchronous events related to LE
+  // scan.
+  class Delegate {
+   public:
+    Delegate() = default;
+    virtual ~Delegate() = default;
+
+    // Called asynchronously to notify the delegate of nearby BLE advertisers
+    // found during a device scan.
+    virtual void OnScanResult(LowEnergyScanner* client,
+                              const ScanResult& scan_result) = 0;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Delegate);
+  };
+
+  // The destructor automatically unregisters this client instance from the
+  // stack.
+  ~LowEnergyScanner() override;
+
+  // Assigns a delegate to this instance. |delegate| must out-live this
+  // LowEnergyClient instance.
+  void SetDelegate(Delegate* delegate);
+
+  // Initiates a BLE device scan for this client using the given |settings| and
+  // |filters|. See the documentation for ScanSettings and ScanFilter for how
+  // these parameters can be configured. Return true on success, false
+  // otherwise. Please see logs for details in case of error.
+  bool StartScan(const ScanSettings& settings,
+                 const std::vector<ScanFilter>& filters);
+
+  // Stops an ongoing BLE device scan for this client.
+  bool StopScan();
+
+  // Returns the current scan settings.
+  const ScanSettings& scan_settings() const { return scan_settings_; }
+
+  // BluetoothInstace overrides:
+  const UUID& GetAppIdentifier() const override;
+  int GetInstanceId() const override;
+
+  void ScanResultCallback(
+      hal::BluetoothGattInterface* gatt_iface,
+      const bt_bdaddr_t& bda, int rssi,
+      vector<uint8_t> adv_data) override;
+
+ private:
+  friend class LowEnergyScannerFactory;
+
+  // Constructor shouldn't be called directly as instances are meant to be
+  // obtained from the factory.
+  LowEnergyScanner(Adapter& adapter, const UUID& uuid, int scanner_id);
+
+  // Calls and clears the pending callbacks.
+  void InvokeAndClearStartCallback(BLEStatus status);
+  void InvokeAndClearStopCallback(BLEStatus status);
+
+  // Raw pointer to the Bluetooth Adapter.
+  Adapter& adapter_;
+
+  // See getters above for documentation.
+  UUID app_identifier_;
+  int scanner_id_;
+
+  // Protects device scan related members below.
+  std::mutex scan_fields_lock_;
+
+  // Current scan settings.
+  ScanSettings scan_settings_;
+
+  // If true, then this client have a BLE device scan in progress.
+  std::atomic_bool scan_started_;
+
+  // Raw handle to the Delegate, which must outlive this LowEnergyScanner
+  // instance.
+  std::mutex delegate_mutex_;
+  Delegate* delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(LowEnergyScanner);
+};
+
+// LowEnergyScannerFactory is used to register and obtain a per-application
+// LowEnergyScanner instance. Users should call RegisterInstance to obtain their
+// own unique LowEnergyScanner instance that has been registered with the
+// Bluetooth stack.
+class LowEnergyScannerFactory
+    : private hal::BluetoothGattInterface::ScannerObserver,
+      public BluetoothInstanceFactory {
+ public:
+  // Don't construct/destruct directly except in tests. Instead, obtain a handle
+  // from an Adapter instance.
+  explicit LowEnergyScannerFactory(Adapter& adapter);
+  ~LowEnergyScannerFactory() override;
+
+  // BluetoothInstanceFactory override:
+  bool RegisterInstance(const UUID& app_uuid, const RegisterCallback& callback) override;
+
+ private:
+  friend class LowEnergyScanner;
+
+  // BluetoothGattInterface::ScannerObserver overrides:
+  void RegisterScannerCallback(hal::BluetoothGattInterface* gatt_iface, int status,
+                               int scanner_id, const bt_uuid_t& app_uuid);
+
+  // Map of pending calls to register.
+  std::mutex pending_calls_lock_;
+  std::map<UUID, RegisterCallback> pending_calls_;
+
+  // Raw pointer to the Adapter that owns this factory.
+  Adapter& adapter_;
+
+  DISALLOW_COPY_AND_ASSIGN(LowEnergyScannerFactory);
+};
+
+}  // namespace bluetooth
diff --git a/bt/service/main.cc b/bt/service/main.cc
new file mode 100644
index 0000000..fc5eec6
--- /dev/null
+++ b/bt/service/main.cc
@@ -0,0 +1,85 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+
+#ifdef BT_LIBCHROME_NDEBUG
+#define NDEBUG 1
+#endif
+
+#include <base/at_exit.h>
+#include <base/command_line.h>
+#include <base/files/scoped_file.h>
+#include <base/logging.h>
+
+#include "osi/include/properties.h"
+#include "service/daemon.h"
+#include "service/switches.h"
+
+namespace {
+
+// TODO(armansito): None of these should be hardcoded here. Instead, pass these
+// via commandline.
+const char kDisableProperty[] = "persist.bluetooth.disable";
+
+}  // namespace
+
+int main(int argc, char *argv[]) {
+  base::AtExitManager exit_manager;
+  base::CommandLine::Init(argc, argv);
+
+  logging::LoggingSettings log_settings;
+  if (!logging::InitLogging(log_settings)) {
+    LOG(ERROR) << "Failed to set up logging";
+    return EXIT_FAILURE;
+  }
+
+  // TODO(armansito): Initialize base/logging. By default it will dump to stdout
+  // but we might want to change that based on a command-line switch. Figure out
+  // how to route the logging to Android's syslog. Once that's done, we won't
+  // need to use osi/include/log.h anymore.
+
+  // TODO(armansito): Register exit-time clean-up handlers for the IPC sockets.
+  // Register signal handlers.
+  auto command_line = base::CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(bluetooth::switches::kHelpLong) ||
+      command_line->HasSwitch(bluetooth::switches::kHelpShort)) {
+    LOG(INFO) << bluetooth::switches::kHelpMessage;
+    return EXIT_SUCCESS;
+  }
+
+#if !defined(OS_GENERIC)
+  // TODO(armansito): Remove Chromecast specific property out of here. This
+  // should just be obtained from global config.
+  char disable_value[PROPERTY_VALUE_MAX];
+  int status = property_get(kDisableProperty, disable_value, nullptr);
+  if (status && !strcmp(disable_value, "1")) {
+    LOG(INFO) << "service disabled";
+    return EXIT_SUCCESS;
+  }
+#endif  // !defined(OS_GENERIC)
+
+  if (!bluetooth::Daemon::Initialize()) {
+    LOG(ERROR) << "Failed to initialize Daemon";
+    return EXIT_FAILURE;
+  }
+
+  // Start the main event loop.
+  bluetooth::Daemon::Get()->StartMainLoop();
+
+  // The main message loop has exited; clean up the Daemon.
+  bluetooth::Daemon::Get()->ShutDown();
+
+  return EXIT_SUCCESS;
+}
diff --git a/bt/service/settings.cc b/bt/service/settings.cc
new file mode 100644
index 0000000..dee0e69
--- /dev/null
+++ b/bt/service/settings.cc
@@ -0,0 +1,86 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/settings.h"
+
+#include <base/base_switches.h>
+#include <base/command_line.h>
+#include <base/logging.h>
+
+#include "service/switches.h"
+
+namespace bluetooth {
+
+Settings::Settings()
+    : initialized_(false) {
+}
+
+Settings::~Settings() {
+}
+
+bool Settings::Init() {
+  CHECK(!initialized_);
+  auto command_line = base::CommandLine::ForCurrentProcess();
+  const auto& switches = command_line->GetSwitches();
+
+  for (const auto& iter : switches) {
+    if (iter.first == switches::kCreateIPCSocketPath) {
+      // kCreateIPCSocketPath: An optional argument that initializes an IPC
+      // socket path for IPC.
+      base::FilePath path(iter.second);
+      if (path.empty() || path.EndsWithSeparator()) {
+        LOG(ERROR) << "Invalid IPC create socket path";
+        return false;
+      }
+
+      create_ipc_socket_path_ = path;
+    } else if (iter.first == switches::kAndroidIPCSocketSuffix) {
+      // kAndroidIPCSocketSuffix: An optional argument used to express
+      // a socket that Android init created for us. We bind to this.
+      const std::string& suffix = iter.second;
+      if (suffix.empty()) {
+        LOG(ERROR) << "Invalid Android socket suffix";
+        return false;
+      }
+
+      android_ipc_socket_suffix_ = suffix;
+    }
+    // Check for libbase logging switches. These get processed by
+    // logging::InitLogging directly.
+    else if (iter.first != ::switches::kV) {
+      LOG(ERROR) << "Unexpected command-line switches found: " << iter.first;
+      return false;
+    }
+  }
+
+  // Two IPC methods/paths were provided.
+  if (!android_ipc_socket_suffix_.empty() &&
+      !create_ipc_socket_path_.empty()) {
+    LOG(ERROR) << "Too many IPC methods provided";
+    return false;
+  }
+
+  // The daemon has no arguments
+  if (command_line->GetArgs().size()) {
+    LOG(ERROR) << "Unexpected command-line arguments found";
+    return false;
+  }
+
+  initialized_ = true;
+  return true;
+}
+
+}  // namespace bluetooth
diff --git a/bt/service/settings.h b/bt/service/settings.h
new file mode 100644
index 0000000..4c4ea4f
--- /dev/null
+++ b/bt/service/settings.h
@@ -0,0 +1,71 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 <base/files/file_path.h>
+#include <base/macros.h>
+
+namespace bluetooth {
+
+// The Settings class stores global runtime configurations, such as IPC domain
+// namespace, configuration file locations, and other system properties and
+// flags.
+class Settings {
+ public:
+  // Constant for the "--help" command-line switches.
+  static const char kHelp[];
+
+  Settings();
+  ~Settings();
+
+  // TODO(armansito): Write an instance method for storing things into a file.
+
+  // Initializes the Settings object. This reads the command-line options for
+  // the current process (which must have been initialized using
+  // base::CommandLine) and sets up the initial global settings. Returns false
+  // if there is an error, e.g. if the parameters/switches are malformed.
+  bool Init();
+
+  // If Android init created a server socket for the daemon,
+  // we can retrieve it through this suffix.
+  const std::string& android_ipc_socket_suffix() const {
+    return android_ipc_socket_suffix_;
+  }
+
+  // Path to create a Unix domain socket server for Bluetooth IPC.
+  const base::FilePath& create_ipc_socket_path() const {
+    return create_ipc_socket_path_;
+  }
+
+  // Returns true if domain-socket based IPC should be used. If false, then
+  // Binder IPC must be used.
+  inline bool UseSocketIPC() const {
+    return !android_ipc_socket_suffix().empty() ||
+        !create_ipc_socket_path().empty();
+  }
+
+ private:
+  bool initialized_;
+  std::string android_ipc_socket_suffix_;
+  base::FilePath create_ipc_socket_path_;
+
+  DISALLOW_COPY_AND_ASSIGN(Settings);
+};
+
+}  // namespace bluetooth
diff --git a/bt/service/switches.h b/bt/service/switches.h
new file mode 100644
index 0000000..af23398
--- /dev/null
+++ b/bt/service/switches.h
@@ -0,0 +1,42 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 switches {
+
+// List of command-line switches used by the daemon.
+const char kHelpLong[] = "help";
+const char kHelpShort[] = "h";
+const char kAndroidIPCSocketSuffix[] = "android-ipc-socket-suffix";
+const char kCreateIPCSocketPath[] = "create-ipc-socket";
+
+const char kHelpMessage[] =
+    "\nBluetooth System Service\n"
+    "\n"
+    "Usage:\n"
+    "\t--help,-h\t\t\tShow this help message\n"
+    "\t--android-ipc-socket-suffix\tSuffix of socket created by Android init. "
+    "Mutually exclusive with --create-ipc-socket.\n"
+    "\t--create-ipc-socket\t\tSocket path created for Unix domain socket based "
+    "IPC. Mutually exclusive with --android-ipc-socket-suffix.\n"
+    "\t--v\t\t\t\tLog verbosity level (e.g. -v=1)\n";
+
+}  // namespace switches
+}  // namespace bluetooth
diff --git a/bt/service/test/ParcelableTest.aidl b/bt/service/test/ParcelableTest.aidl
new file mode 100644
index 0000000..b69aadf
--- /dev/null
+++ b/bt/service/test/ParcelableTest.aidl
@@ -0,0 +1,30 @@
+package test;
+
+/* This file is just a test to make sure all parcelables
+ * are correct. It will be removed once they're used in
+ * real AIDL files.
+ */
+
+import android.bluetooth.AdvertiseData;
+import android.bluetooth.AdvertiseSettings;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
+import android.bluetooth.BluetoothGattIncludedService;
+import android.bluetooth.BluetoothGattService;
+import android.bluetooth.ScanFilter;
+import android.bluetooth.ScanResult;
+import android.bluetooth.ScanSettings;
+import android.bluetooth.UUID;
+
+interface ParcelableTest {
+  void OnAdvertiseData(in AdvertiseData advertise_data);
+  void OnAdvertiseSettings(in AdvertiseSettings advertise_settings);
+  void OnScanFilter(in ScanFilter scan_filter);
+  void OnScanResult(in ScanResult scan_result);
+  void OnScanSettings(in ScanSettings scan_settings);
+  void OnUUID(in UUID uuid);
+  void OnDescripor(in BluetoothGattDescriptor descriptor);
+  void OnCharacteristic(in BluetoothGattCharacteristic characteristic);
+  void OnIncludedService(in BluetoothGattIncludedService service);
+  void OnService(in BluetoothGattService service);
+}
diff --git a/bt/service/test/adapter_unittest.cc b/bt/service/test/adapter_unittest.cc
new file mode 100644
index 0000000..ca64618
--- /dev/null
+++ b/bt/service/test/adapter_unittest.cc
@@ -0,0 +1,288 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 <base/macros.h>
+#include <gtest/gtest.h>
+
+#include "service/adapter.h"
+#include "service/common/bluetooth/util/address_helper.h"
+#include "service/hal/fake_bluetooth_gatt_interface.h"
+#include "service/hal/fake_bluetooth_interface.h"
+
+namespace bluetooth {
+namespace {
+
+class AdapterTest : public ::testing::Test {
+ public:
+  AdapterTest() = default;
+  ~AdapterTest() override = default;
+
+  void SetUp() override {
+    fake_hal_manager_ = hal::FakeBluetoothInterface::GetManager();
+    fake_hal_iface_ = new hal::FakeBluetoothInterface();
+    hal::BluetoothInterface::InitializeForTesting(fake_hal_iface_);
+
+    // Initialize GATT interface with default handlers.
+    hal::BluetoothGattInterface::InitializeForTesting(
+        new hal::FakeBluetoothGattInterface(nullptr, nullptr, nullptr, nullptr));
+
+    adapter_ = Adapter::Create();
+  }
+
+  void TearDown() override {
+    adapter_.reset();
+    hal::BluetoothGattInterface::CleanUp();
+    hal::BluetoothInterface::CleanUp();
+  }
+
+ protected:
+  hal::FakeBluetoothInterface* fake_hal_iface_;
+  hal::FakeBluetoothInterface::Manager* fake_hal_manager_;
+  std::unique_ptr<Adapter> adapter_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AdapterTest);
+};
+
+class TestObserver final : public bluetooth::Adapter::Observer {
+ public:
+  explicit TestObserver(bluetooth::Adapter* adapter)
+      : adapter_(adapter),
+        prev_state_(bluetooth::ADAPTER_STATE_INVALID),
+        cur_state_(bluetooth::ADAPTER_STATE_INVALID),
+        last_device_connected_state_(false) {
+    CHECK(adapter_);
+    adapter_->AddObserver(this);
+  }
+
+  ~TestObserver() override {
+    adapter_->RemoveObserver(this);
+  }
+
+  bluetooth::AdapterState prev_state() const { return prev_state_; }
+  bluetooth::AdapterState cur_state() const { return cur_state_; }
+
+  std::string last_connection_state_address() const {
+    return last_connection_state_address_;
+  }
+
+  bool last_device_connected_state() const {
+    return last_device_connected_state_;
+  }
+
+  // bluetooth::Adapter::Observer override:
+  void OnAdapterStateChanged(bluetooth::Adapter* adapter,
+                             bluetooth::AdapterState prev_state,
+                             bluetooth::AdapterState new_state) override {
+    ASSERT_EQ(adapter_, adapter);
+    prev_state_ = prev_state;
+    cur_state_ = new_state;
+  }
+
+  void OnDeviceConnectionStateChanged(
+      Adapter* adapter,
+      const std::string& device_address,
+      bool connected) override {
+    ASSERT_EQ(adapter_, adapter);
+    last_connection_state_address_ = device_address;
+    last_device_connected_state_ = connected;
+  }
+
+ private:
+  bluetooth::Adapter* adapter_;
+  bluetooth::AdapterState prev_state_, cur_state_;
+  std::string last_connection_state_address_;
+  bool last_device_connected_state_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestObserver);
+};
+
+TEST_F(AdapterTest, IsEnabled) {
+  EXPECT_FALSE(adapter_->IsEnabled());
+
+  fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_ON);
+  EXPECT_TRUE(adapter_->IsEnabled());
+
+  fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_OFF);
+  EXPECT_FALSE(adapter_->IsEnabled());
+}
+
+TEST_F(AdapterTest, Enable) {
+  TestObserver observer(adapter_.get());
+
+  EXPECT_FALSE(adapter_->IsEnabled());
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, adapter_->GetState());
+
+  // Enable fails at HAL level
+  EXPECT_FALSE(adapter_->Enable(false));
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, adapter_->GetState());
+
+  // Enable success
+  fake_hal_manager_->enable_succeed = true;
+  EXPECT_TRUE(adapter_->Enable(false));
+
+  // Should have received a state update.
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, observer.prev_state());
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_ON, observer.cur_state());
+
+  // Enable fails because not disabled
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_ON, adapter_->GetState());
+  EXPECT_FALSE(adapter_->Enable(false));
+
+  // Adapter state updates properly
+  fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_ON);
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, adapter_->GetState());
+
+  // Should have received a state update.
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_ON, observer.prev_state());
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, observer.cur_state());
+
+  // Enable fails because already enabled
+  EXPECT_FALSE(adapter_->Enable(false));
+}
+
+TEST_F(AdapterTest, Disable) {
+  TestObserver observer(adapter_.get());
+
+  fake_hal_manager_->disable_succeed = true;
+  EXPECT_FALSE(adapter_->IsEnabled());
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, adapter_->GetState());
+
+  // Disable fails because already disabled
+  EXPECT_FALSE(adapter_->Disable());
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, adapter_->GetState());
+
+  // Disable success
+  fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_ON);
+
+  // Should have received a state update.
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, observer.prev_state());
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, observer.cur_state());
+
+  EXPECT_TRUE(adapter_->Disable());
+
+  // Should have received a state update.
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, observer.prev_state());
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_OFF, observer.cur_state());
+
+  // Disable fails because not enabled
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_OFF, adapter_->GetState());
+  EXPECT_FALSE(adapter_->Disable());
+
+  fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_ON);
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, adapter_->GetState());
+
+  // Should have received a state update.
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_OFF, observer.prev_state());
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, observer.cur_state());
+
+  // Disable fails at HAL level
+  fake_hal_manager_->disable_succeed = false;
+  EXPECT_FALSE(adapter_->Disable());
+
+  // Should have received a state update. In this case we will receive two
+  // updates: one going from OFF to TURNING_OFF, and one going from TURNING_OFF
+  // back to ON since we failed to initiate the disable operation.
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_OFF, observer.prev_state());
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, observer.cur_state());
+
+  // Update state to OFF. Should receive a state update.
+  fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_OFF);
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, observer.prev_state());
+  EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, observer.cur_state());
+}
+
+TEST_F(AdapterTest, GetName) {
+  EXPECT_EQ(bluetooth::Adapter::kDefaultName, adapter_->GetName());
+
+  const char kTestAdapterName[] = "Test Adapter Name";
+
+  fake_hal_iface_->NotifyAdapterNamePropertyChanged(kTestAdapterName);
+  EXPECT_EQ(kTestAdapterName, adapter_->GetName());
+}
+
+TEST_F(AdapterTest, SetName) {
+  bt_bdname_t hal_name;
+
+  // Name too large.
+  EXPECT_FALSE(adapter_->SetName(std::string(sizeof(hal_name.name), 'a')));
+
+  // Valid length.
+  EXPECT_FALSE(adapter_->SetName("Test Name"));
+  fake_hal_manager_->set_property_succeed = true;
+  EXPECT_TRUE(adapter_->SetName("Test Name"));
+}
+
+TEST_F(AdapterTest, GetAddress) {
+  EXPECT_EQ(bluetooth::Adapter::kDefaultAddress, adapter_->GetAddress());
+
+  const bt_bdaddr_t kTestAdapterInput = {
+    { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc }
+  };
+  const char kTestAdapterAddressOutput[] = "12:34:56:78:9A:BC";
+
+  fake_hal_iface_->NotifyAdapterAddressPropertyChanged(&kTestAdapterInput);
+  EXPECT_EQ(kTestAdapterAddressOutput, adapter_->GetAddress());
+}
+
+TEST_F(AdapterTest, IsMultiAdvertisementSupported) {
+  EXPECT_FALSE(adapter_->IsMultiAdvertisementSupported());
+
+  bt_local_le_features_t features;
+  memset(&features, 0, sizeof(features));
+
+  features.max_adv_instance = 10;  // Some high number.
+  fake_hal_iface_->NotifyAdapterLocalLeFeaturesPropertyChanged(&features);
+  EXPECT_TRUE(adapter_->IsMultiAdvertisementSupported());
+
+  features.max_adv_instance = 0;  // Low number.
+  fake_hal_iface_->NotifyAdapterLocalLeFeaturesPropertyChanged(&features);
+  EXPECT_FALSE(adapter_->IsMultiAdvertisementSupported());
+}
+
+TEST_F(AdapterTest, IsDeviceConnected) {
+  const char kDeviceAddr[] = "12:34:56:78:9A:BC";
+  TestObserver observer(adapter_.get());
+
+  EXPECT_FALSE(adapter_->IsDeviceConnected(kDeviceAddr));
+
+  bt_bdaddr_t hal_addr;
+  ASSERT_TRUE(util::BdAddrFromString(kDeviceAddr, &hal_addr));
+
+  // status != BT_STATUS_SUCCESS should be ignored
+  fake_hal_iface_->NotifyAclStateChangedCallback(
+      BT_STATUS_FAIL, hal_addr, BT_ACL_STATE_CONNECTED);
+  EXPECT_FALSE(adapter_->IsDeviceConnected(kDeviceAddr));
+  EXPECT_TRUE(observer.last_connection_state_address().empty());
+  EXPECT_FALSE(observer.last_device_connected_state());
+
+  // Connected
+  fake_hal_iface_->NotifyAclStateChangedCallback(
+      BT_STATUS_SUCCESS, hal_addr, BT_ACL_STATE_CONNECTED);
+  EXPECT_TRUE(adapter_->IsDeviceConnected(kDeviceAddr));
+  EXPECT_EQ(kDeviceAddr, observer.last_connection_state_address());
+  EXPECT_TRUE(observer.last_device_connected_state());
+
+  // Disconnected
+  fake_hal_iface_->NotifyAclStateChangedCallback(
+      BT_STATUS_SUCCESS, hal_addr, BT_ACL_STATE_DISCONNECTED);
+  EXPECT_FALSE(adapter_->IsDeviceConnected(kDeviceAddr));
+  EXPECT_EQ(kDeviceAddr, observer.last_connection_state_address());
+  EXPECT_FALSE(observer.last_device_connected_state());
+}
+
+}  // namespace
+}  // namespace bluetooth
diff --git a/bt/service/test/advertise_data_unittest.cc b/bt/service/test/advertise_data_unittest.cc
new file mode 100644
index 0000000..c052608
--- /dev/null
+++ b/bt/service/test/advertise_data_unittest.cc
@@ -0,0 +1,120 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/bluetooth/advertise_data.h"
+#include "stack/include/bt_types.h"
+#include "stack/include/hcidefs.h"
+
+namespace bluetooth {
+
+TEST(AdvertiseDataTest, EmptyData) {
+  const std::vector<uint8_t> data0;
+  AdvertiseData adv0(data0);
+  EXPECT_TRUE(adv0.IsValid());
+
+  // Single empty field not allowed.
+  const std::vector<uint8_t> data1{ 0x00 };
+  AdvertiseData adv1(data1);
+  EXPECT_FALSE(adv1.IsValid());
+}
+
+TEST(AdvertiseDataTest, BadTLV) {
+  // Single field, field empty.
+  const std::vector<uint8_t> data0{ 0x01 };
+  AdvertiseData adv0(data0);
+  EXPECT_FALSE(adv0.IsValid());
+
+  // Single field, first field length too long.
+  const std::vector<uint8_t> data1{ 0x05, 0x02, 0x00, 0x00, 0x00 };
+  AdvertiseData adv1(data1);
+  EXPECT_FALSE(adv1.IsValid());
+
+  // Two fields, second field length too long.
+  const std::vector<uint8_t> data2{ 0x02, 0x02, 0x00, 0x02, 0x00 };
+  AdvertiseData adv2(data2);
+  EXPECT_FALSE(adv2.IsValid());
+
+  // Two fields, second field empty.
+  const std::vector<uint8_t> data3{ 0x02, 0x02, 0x00, 0x01 };
+  AdvertiseData adv3(data3);
+  EXPECT_FALSE(adv3.IsValid());
+}
+
+TEST(AdvertiseDataTest, GoodTLV) {
+  // Singe field.
+  const std::vector<uint8_t> data0{ 0x03, 0x02, 0x01, 0x02 };
+  AdvertiseData adv0(data0);
+  EXPECT_TRUE(adv0.IsValid());
+
+  // Twi fields.
+  const std::vector<uint8_t> data1{ 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x01 };
+  AdvertiseData adv1(data1);
+  EXPECT_TRUE(adv0.IsValid());
+}
+
+TEST(AdvertiseDataTest, DisallowedFields) {
+  // Singe field.
+  const std::vector<uint8_t> data0{ 0x02, HCI_EIR_FLAGS_TYPE, 0x00 };
+  AdvertiseData adv0(data0);
+  EXPECT_FALSE(adv0.IsValid());
+
+  // Two fields, first invalid.
+  const std::vector<uint8_t> data1{
+      0x02, HCI_EIR_FLAGS_TYPE, 0x00,
+      0x03, 0x02, 0x01, 0x02
+  };
+  AdvertiseData adv1(data1);
+  EXPECT_FALSE(adv1.IsValid());
+
+  // Two fields, second invalid.
+  const std::vector<uint8_t> data2{
+      0x03, 0x02, 0x01, 0x02,
+      0x02, HCI_EIR_FLAGS_TYPE, 0x00
+  };
+  AdvertiseData adv2(data2);
+  EXPECT_FALSE(adv2.IsValid());
+
+  // Check all blacklisted fields
+  uint8_t blacklist[] = {
+      HCI_EIR_FLAGS_TYPE,
+      HCI_EIR_OOB_BD_ADDR_TYPE,
+      HCI_EIR_OOB_COD_TYPE,
+      HCI_EIR_OOB_SSP_HASH_C_TYPE,
+      HCI_EIR_OOB_SSP_RAND_R_TYPE
+  };
+  for (size_t i = 0; i < sizeof(blacklist); i++) {
+    const std::vector<uint8_t> data{ 0x02, blacklist[i], 0x00 };
+    AdvertiseData adv(data);
+    EXPECT_FALSE(adv.IsValid());
+  }
+}
+
+TEST(AdvertiseDataTest, EqualsData) {
+  const std::vector<uint8_t> data0{ 0x02, 0x02, 0x00 };
+  const std::vector<uint8_t> data1{ 0x02, 0x03, 0x00 };
+
+  AdvertiseData adv0(data0);
+  AdvertiseData adv1(data1);
+
+  EXPECT_FALSE(adv0 == adv1);
+
+  AdvertiseData adv2(data1);
+  EXPECT_TRUE(adv1 == adv2);
+}
+
+}  // namespace bluetooth
diff --git a/bt/service/test/fake_hal_util.cc b/bt/service/test/fake_hal_util.cc
new file mode 100644
index 0000000..46acf73
--- /dev/null
+++ b/bt/service/test/fake_hal_util.cc
@@ -0,0 +1,27 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "btcore/include/hal_util.h"
+
+// TODO(armansito): This provides a fake implementation of the function defined
+// in btcore/include/hal_util.h. We have to provide this to prevent having to
+// pull in libbtcore and transitively libhardware as dependencies for the unit
+// tests. Instead of doing it this way, however, we should instead provide a C++
+// class abstraction for this (and all other btif interfaces) that we can mock
+// for testing.
+int hal_util_load_bt_library(const struct hw_module_t** module) {
+  return -1;
+}
diff --git a/bt/service/test/gatt_client_unittest.cc b/bt/service/test/gatt_client_unittest.cc
new file mode 100644
index 0000000..1628a7b
--- /dev/null
+++ b/bt/service/test/gatt_client_unittest.cc
@@ -0,0 +1,165 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 <base/macros.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "service/gatt_client.h"
+#include "service/hal/fake_bluetooth_gatt_interface.h"
+
+using ::testing::_;
+using ::testing::Return;
+
+namespace bluetooth {
+namespace {
+
+class MockGattHandler
+    : public hal::FakeBluetoothGattInterface::TestClientHandler {
+ public:
+  MockGattHandler() = default;
+  ~MockGattHandler() override = default;
+
+  MOCK_METHOD1(RegisterClient, bt_status_t(bt_uuid_t*));
+  MOCK_METHOD1(UnregisterClient, bt_status_t(int));
+  MOCK_METHOD1(Scan, bt_status_t(bool));
+  MOCK_METHOD4(Connect, bt_status_t(int , const bt_bdaddr_t *, bool, int));
+  MOCK_METHOD3(Disconnect, bt_status_t(int , const bt_bdaddr_t *, int));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockGattHandler);
+};
+
+class GattClientTest : public ::testing::Test {
+ public:
+  GattClientTest() = default;
+  ~GattClientTest() override = default;
+
+  void SetUp() override {
+    // Only set |mock_handler_| if a previous test case hasn't set it.
+    if (!mock_handler_)
+      mock_handler_.reset(new MockGattHandler());
+
+    fake_hal_gatt_iface_ = new hal::FakeBluetoothGattInterface(
+        nullptr,
+        nullptr,
+        std::static_pointer_cast<
+            hal::FakeBluetoothGattInterface::TestClientHandler>(mock_handler_),
+        nullptr);
+    hal::BluetoothGattInterface::InitializeForTesting(fake_hal_gatt_iface_);
+
+    factory_.reset(new GattClientFactory());
+  }
+
+  void TearDown() override {
+    factory_.reset();
+    hal::BluetoothGattInterface::CleanUp();
+  }
+
+ protected:
+  hal::FakeBluetoothGattInterface* fake_hal_gatt_iface_;
+  std::shared_ptr<MockGattHandler> mock_handler_;
+  std::unique_ptr<GattClientFactory> factory_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GattClientTest);
+};
+
+TEST_F(GattClientTest, RegisterInstance) {
+  EXPECT_CALL(*mock_handler_, RegisterClient(_))
+      .Times(2)
+      .WillOnce(Return(BT_STATUS_FAIL))
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+
+  // These will be asynchronously populated with a result when the callback
+  // executes.
+  BLEStatus status = BLE_STATUS_SUCCESS;
+  UUID cb_uuid;
+  std::unique_ptr<GattClient> client;
+  int callback_count = 0;
+
+  auto callback = [&](BLEStatus in_status, const UUID& uuid,
+                      std::unique_ptr<BluetoothInstance> in_client) {
+        status = in_status;
+        cb_uuid = uuid;
+        client = std::unique_ptr<GattClient>(
+            static_cast<GattClient*>(in_client.release()));
+        callback_count++;
+      };
+
+  UUID uuid0 = UUID::GetRandom();
+
+  // HAL returns failure.
+  EXPECT_FALSE(factory_->RegisterInstance(uuid0, callback));
+  EXPECT_EQ(0, callback_count);
+
+  // HAL returns success.
+  EXPECT_TRUE(factory_->RegisterInstance(uuid0, callback));
+  EXPECT_EQ(0, callback_count);
+
+  // Calling twice with the same UUID should fail with no additional call into
+  // the stack.
+  EXPECT_FALSE(factory_->RegisterInstance(uuid0, callback));
+
+  testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+  // Call with a different UUID while one is pending.
+  UUID uuid1 = UUID::GetRandom();
+  EXPECT_CALL(*mock_handler_, RegisterClient(_))
+      .Times(1)
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+  EXPECT_TRUE(factory_->RegisterInstance(uuid1, callback));
+
+  // Trigger callback with an unknown UUID. This should get ignored.
+  UUID uuid2 = UUID::GetRandom();
+  bt_uuid_t hal_uuid = uuid2.GetBlueDroid();
+  fake_hal_gatt_iface_->NotifyRegisterClientCallback(0, 0, hal_uuid);
+  EXPECT_EQ(0, callback_count);
+
+  // |uuid0| succeeds.
+  int client_id0 = 2;  // Pick something that's not 0.
+  hal_uuid = uuid0.GetBlueDroid();
+  fake_hal_gatt_iface_->NotifyRegisterClientCallback(
+      BT_STATUS_SUCCESS, client_id0, hal_uuid);
+
+  EXPECT_EQ(1, callback_count);
+  ASSERT_TRUE(client.get() != nullptr);  // Assert to terminate in case of error
+  EXPECT_EQ(BLE_STATUS_SUCCESS, status);
+  EXPECT_EQ(client_id0, client->GetInstanceId());
+  EXPECT_EQ(uuid0, client->GetAppIdentifier());
+  EXPECT_EQ(uuid0, cb_uuid);
+
+  // The client should unregister itself when deleted.
+  EXPECT_CALL(*mock_handler_, UnregisterClient(client_id0))
+      .Times(1)
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+  client.reset();
+  testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+  // |uuid1| fails.
+  int client_id1 = 3;
+  hal_uuid = uuid1.GetBlueDroid();
+  fake_hal_gatt_iface_->NotifyRegisterClientCallback(
+      BT_STATUS_FAIL, client_id1, hal_uuid);
+
+  EXPECT_EQ(2, callback_count);
+  ASSERT_TRUE(client.get() == nullptr);  // Assert to terminate in case of error
+  EXPECT_EQ(BLE_STATUS_FAILURE, status);
+  EXPECT_EQ(uuid1, cb_uuid);
+}
+
+}  // namespace
+}  // namespace bluetooth
diff --git a/bt/service/test/gatt_server_unittest.cc b/bt/service/test/gatt_server_unittest.cc
new file mode 100644
index 0000000..ca4c2fe
--- /dev/null
+++ b/bt/service/test/gatt_server_unittest.cc
@@ -0,0 +1,756 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/bluetooth/util/address_helper.h"
+#include "service/gatt_server.h"
+#include "service/hal/fake_bluetooth_gatt_interface.h"
+
+using ::testing::_;
+using ::testing::Return;
+
+namespace bluetooth {
+namespace {
+
+class MockGattHandler
+    : public hal::FakeBluetoothGattInterface::TestServerHandler {
+ public:
+  MockGattHandler() = default;
+  ~MockGattHandler() override = default;
+
+  MOCK_METHOD1(RegisterServer, bt_status_t(bt_uuid_t*));
+  MOCK_METHOD1(UnregisterServer, bt_status_t(int));
+  MOCK_METHOD2(AddService, bt_status_t(int, vector<btgatt_db_element_t>));
+  MOCK_METHOD5(AddCharacteristic, bt_status_t(int, int, bt_uuid_t*, int, int));
+  MOCK_METHOD4(AddDescriptor, bt_status_t(int, int, bt_uuid_t*, int));
+  MOCK_METHOD3(StartService, bt_status_t(int, int, int));
+  MOCK_METHOD2(DeleteService, bt_status_t(int, int));
+  MOCK_METHOD5(SendIndication, bt_status_t(int, int, int, int, vector<uint8_t>));
+  MOCK_METHOD4(SendResponse, bt_status_t(int, int, int, btgatt_response_t*));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockGattHandler);
+};
+
+class TestDelegate : public GattServer::Delegate {
+ public:
+  TestDelegate() = default;
+  ~TestDelegate() override = default;
+
+  struct RequestData {
+    RequestData() : id(-1), offset(-1), is_long(false), is_prep(false),
+                    need_rsp(false), is_exec(false), count(0),
+                    connected(false) {}
+    ~RequestData() = default;
+
+    std::string device_address;
+    int id;
+    int offset;
+    bool is_long;
+    bool is_prep;
+    bool need_rsp;
+    bool is_exec;
+    uint16_t handle;
+    int count;
+    std::vector<uint8_t> write_value;
+    bool connected;
+  };
+
+  void OnCharacteristicReadRequest(
+      GattServer* gatt_server,
+      const std::string& device_address,
+      int request_id, int offset, bool is_long, uint16_t handle) override {
+    ASSERT_TRUE(gatt_server);
+    char_read_req_.device_address = device_address;
+    char_read_req_.id = request_id;
+    char_read_req_.offset = offset;
+    char_read_req_.is_long = is_long;
+    char_read_req_.handle = handle;
+    char_read_req_.count++;
+  }
+
+  void OnDescriptorReadRequest(
+      GattServer* gatt_server,
+      const std::string& device_address,
+      int request_id, int offset, bool is_long, uint16_t handle) override {
+    ASSERT_TRUE(gatt_server);
+    desc_read_req_.device_address = device_address;
+    desc_read_req_.id = request_id;
+    desc_read_req_.offset = offset;
+    desc_read_req_.is_long = is_long;
+    desc_read_req_.handle = handle;
+    desc_read_req_.count++;
+  }
+
+  void OnCharacteristicWriteRequest(
+      GattServer* gatt_server,
+      const std::string& device_address,
+      int request_id, int offset, bool is_prepare_write, bool need_response,
+      const std::vector<uint8_t>& value, uint16_t handle) override {
+    ASSERT_TRUE(gatt_server);
+    char_write_req_.device_address = device_address;
+    char_write_req_.id = request_id;
+    char_write_req_.offset = offset;
+    char_write_req_.is_prep = is_prepare_write;
+    char_write_req_.need_rsp = need_response;
+    char_write_req_.handle = handle;
+    char_write_req_.count++;
+    char_write_req_.write_value = value;
+  }
+
+  void OnDescriptorWriteRequest(
+      GattServer* gatt_server,
+      const std::string& device_address,
+      int request_id, int offset, bool is_prepare_write, bool need_response,
+      const std::vector<uint8_t>& value, uint16_t handle) override {
+    ASSERT_TRUE(gatt_server);
+    desc_write_req_.device_address = device_address;
+    desc_write_req_.id = request_id;
+    desc_write_req_.offset = offset;
+    desc_write_req_.is_prep = is_prepare_write;
+    desc_write_req_.need_rsp = need_response;
+    desc_write_req_.handle = handle;
+    desc_write_req_.count++;
+    desc_write_req_.write_value = value;
+  }
+
+  void OnExecuteWriteRequest(
+      GattServer* gatt_server,
+      const std::string& device_address,
+      int request_id, bool is_execute) override {
+    ASSERT_TRUE(gatt_server);
+    exec_req_.device_address = device_address;
+    exec_req_.id = request_id;
+    exec_req_.is_exec = is_execute;
+    exec_req_.count++;
+  }
+
+  void OnConnectionStateChanged(
+      GattServer* gatt_server,
+      const std::string& device_address,
+      bool connected) override {
+    ASSERT_TRUE(gatt_server);
+    conn_state_changed_.device_address = device_address;
+    conn_state_changed_.connected = connected;
+    conn_state_changed_.count++;
+  }
+
+  const RequestData& char_read_req() const { return char_read_req_; }
+  const RequestData& desc_read_req() const { return desc_read_req_; }
+  const RequestData& char_write_req() const { return char_write_req_; }
+  const RequestData& desc_write_req() const { return desc_write_req_; }
+  const RequestData& conn_state_changed() const { return conn_state_changed_; }
+
+ private:
+  RequestData char_read_req_;
+  RequestData desc_read_req_;
+  RequestData char_write_req_;
+  RequestData desc_write_req_;
+  RequestData exec_req_;
+  RequestData conn_state_changed_;
+};
+
+class GattServerTest : public ::testing::Test {
+ public:
+  GattServerTest() = default;
+  ~GattServerTest() override = default;
+
+  void SetUp() override {
+    mock_handler_.reset(new MockGattHandler());
+    fake_hal_gatt_iface_ = new hal::FakeBluetoothGattInterface(
+        nullptr,
+        nullptr,
+        nullptr,
+        std::static_pointer_cast<
+            hal::FakeBluetoothGattInterface::TestServerHandler>(mock_handler_));
+
+    hal::BluetoothGattInterface::InitializeForTesting(fake_hal_gatt_iface_);
+    factory_.reset(new GattServerFactory());
+  }
+
+  void TearDown() override {
+    factory_.reset();
+    hal::BluetoothGattInterface::CleanUp();
+  }
+
+ protected:
+  hal::FakeBluetoothGattInterface* fake_hal_gatt_iface_;
+  std::shared_ptr<MockGattHandler> mock_handler_;
+  std::unique_ptr<GattServerFactory> factory_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GattServerTest);
+};
+
+const int kDefaultServerId = 4;
+
+class GattServerPostRegisterTest : public GattServerTest {
+ public:
+  GattServerPostRegisterTest() = default;
+  ~GattServerPostRegisterTest() override = default;
+
+  void SetUp() override {
+    GattServerTest::SetUp();
+    UUID uuid = UUID::GetRandom();
+    auto callback = [&](BLEStatus status, const UUID& in_uuid,
+                        std::unique_ptr<BluetoothInstance> in_client) {
+      CHECK(in_uuid == uuid);
+      CHECK(in_client.get());
+      CHECK(status == BLE_STATUS_SUCCESS);
+
+      gatt_server_ = std::unique_ptr<GattServer>(
+          static_cast<GattServer*>(in_client.release()));
+    };
+
+    EXPECT_CALL(*mock_handler_, RegisterServer(_))
+        .Times(1)
+        .WillOnce(Return(BT_STATUS_SUCCESS));
+
+    factory_->RegisterInstance(uuid, callback);
+
+    bt_uuid_t hal_uuid = uuid.GetBlueDroid();
+    fake_hal_gatt_iface_->NotifyRegisterServerCallback(
+        BT_STATUS_SUCCESS,
+        kDefaultServerId,
+        hal_uuid);
+  }
+
+  void TearDown() override {
+    EXPECT_CALL(*mock_handler_, UnregisterServer(_))
+        .Times(1)
+        .WillOnce(Return(BT_STATUS_SUCCESS));
+    gatt_server_ = nullptr;
+    GattServerTest::TearDown();
+  }
+
+  void SetUpTestService() {
+    EXPECT_CALL(*mock_handler_, AddService(_, _))
+        .Times(1)
+        .WillOnce(Return(BT_STATUS_SUCCESS));
+
+    UUID uuid0 = UUID::GetRandom();
+    UUID uuid1 = UUID::GetRandom();
+    UUID uuid2 = UUID::GetRandom();
+
+    bool register_success = false;
+
+    Service service(0, true, uuid0, {}, {} );
+
+    ASSERT_TRUE(gatt_server_->AddService(service, [&](
+        BLEStatus status, const Service& added_service) {
+      ASSERT_EQ(BLE_STATUS_SUCCESS, status);
+      ASSERT_TRUE(UUID(added_service.uuid()) == UUID(service.uuid()));
+      ASSERT_TRUE(added_service.handle() == 0x0001);
+      register_success = true;
+    }));
+
+    srvc_handle_ = 0x0001;
+    char_handle_ = 0x0002;
+    desc_handle_ = 0x0004;
+
+    vector<btgatt_db_element_t> service_with_handles = {
+      {.type = BTGATT_DB_PRIMARY_SERVICE, .uuid = uuid0.GetBlueDroid(), .attribute_handle = srvc_handle_},
+      {.type = BTGATT_DB_CHARACTERISTIC, .uuid = uuid1.GetBlueDroid(), .attribute_handle = char_handle_},
+      {.type = BTGATT_DB_DESCRIPTOR, .uuid = uuid2.GetBlueDroid(), .attribute_handle = desc_handle_},
+    };
+
+    fake_hal_gatt_iface_->NotifyServiceAddedCallback(
+        BT_STATUS_SUCCESS, kDefaultServerId, service_with_handles);
+
+    testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+    ASSERT_TRUE(register_success);
+  }
+
+ protected:
+  std::unique_ptr<GattServer> gatt_server_;
+
+  uint16_t srvc_handle_;
+  uint16_t char_handle_;
+  uint16_t desc_handle_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GattServerPostRegisterTest);
+};
+
+TEST_F(GattServerTest, RegisterServer) {
+  EXPECT_CALL(*mock_handler_, RegisterServer(_))
+      .Times(2)
+      .WillOnce(Return(BT_STATUS_FAIL))
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+
+  // These will be asynchronously populate with a result when the callback
+  // executes.
+  BLEStatus status = BLE_STATUS_SUCCESS;
+  UUID cb_uuid;
+  std::unique_ptr<GattServer> server;
+  int callback_count = 0;
+
+  auto callback = [&](BLEStatus in_status, const UUID& uuid,
+                      std::unique_ptr<BluetoothInstance> in_server) {
+    status = in_status;
+    cb_uuid = uuid;
+    server = std::unique_ptr<GattServer>(
+        static_cast<GattServer*>(in_server.release()));
+    callback_count++;
+  };
+
+  UUID uuid0 = UUID::GetRandom();
+
+  // HAL returns failure.
+  EXPECT_FALSE(factory_->RegisterInstance(uuid0, callback));
+  EXPECT_EQ(0, callback_count);
+
+  // HAL returns success.
+  EXPECT_TRUE(factory_->RegisterInstance(uuid0, callback));
+  EXPECT_EQ(0, callback_count);
+
+  // Calling twice with the same UUID should fail with no additional calls into
+  // the stack.
+  EXPECT_FALSE(factory_->RegisterInstance(uuid0, callback));
+
+  testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+  // Call with a different UUID while one is pending.
+  UUID uuid1 = UUID::GetRandom();
+  EXPECT_CALL(*mock_handler_, RegisterServer(_))
+      .Times(1)
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+  EXPECT_TRUE(factory_->RegisterInstance(uuid1, callback));
+
+  // Trigger callback with an unknown UUID. This should get ignored.
+  UUID uuid2 = UUID::GetRandom();
+  bt_uuid_t hal_uuid = uuid2.GetBlueDroid();
+  fake_hal_gatt_iface_->NotifyRegisterServerCallback(0, 0, hal_uuid);
+  EXPECT_EQ(0, callback_count);
+
+  // |uuid0| succeeds.
+  int server_if0 = 2;  // Pick something that's not 0.
+  hal_uuid = uuid0.GetBlueDroid();
+  fake_hal_gatt_iface_->NotifyRegisterServerCallback(
+      BT_STATUS_SUCCESS, server_if0, hal_uuid);
+
+  EXPECT_EQ(1, callback_count);
+  ASSERT_TRUE(server.get() != nullptr);  // Assert to terminate in case of error
+  EXPECT_EQ(BLE_STATUS_SUCCESS, status);
+  EXPECT_EQ(server_if0, server->GetInstanceId());
+  EXPECT_EQ(uuid0, server->GetAppIdentifier());
+  EXPECT_EQ(uuid0, cb_uuid);
+
+  // The server should unregister itself when deleted.
+  EXPECT_CALL(*mock_handler_, UnregisterServer(server_if0))
+      .Times(1)
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+  server.reset();
+
+  testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+  // |uuid1| fails.
+  int server_if1 = 3;
+  hal_uuid = uuid1.GetBlueDroid();
+  fake_hal_gatt_iface_->NotifyRegisterServerCallback(
+      BT_STATUS_FAIL, server_if1, hal_uuid);
+
+  EXPECT_EQ(2, callback_count);
+  ASSERT_TRUE(server.get() == nullptr);  // Assert to terminate in case of error
+  EXPECT_EQ(BLE_STATUS_FAILURE, status);
+  EXPECT_EQ(uuid1, cb_uuid);
+}
+
+TEST_F(GattServerPostRegisterTest, RequestRead) {
+  SetUpTestService();
+
+  TestDelegate test_delegate;
+  gatt_server_->SetDelegate(&test_delegate);
+
+  const std::vector<uint8_t> kTestValue = { 0x01, 0x02, 0x03 };
+  const std::vector<uint8_t> kTestValueTooLarge(BTGATT_MAX_ATTR_LEN + 1, 0);
+  const std::string kTestAddress0 = "01:23:45:67:89:AB";
+  const std::string kTestAddress1 = "CD:EF:01:23:45:67";
+  const int kReqId0 = 0;
+  const int kReqId1 = 1;
+  const int kConnId0 = 1;
+
+  // No pending request.
+  EXPECT_FALSE(gatt_server_->SendResponse(
+      kTestAddress0, kReqId0,
+      GATT_ERROR_NONE, 0, kTestValue));
+
+  bt_bdaddr_t hal_addr0, hal_addr1;
+  ASSERT_TRUE(util::BdAddrFromString(kTestAddress0, &hal_addr0));
+  ASSERT_TRUE(util::BdAddrFromString(kTestAddress1, &hal_addr1));
+
+  // Send a connection callback. The GattServer should store the connection
+  // information and be able to process the incoming read requests for this
+  // connection.
+  fake_hal_gatt_iface_->NotifyServerConnectionCallback(
+      kConnId0, kDefaultServerId, true, hal_addr0);
+
+  // Unknown connection ID shouldn't trigger anything.
+  fake_hal_gatt_iface_->NotifyRequestReadCharacteristicCallback(
+      kConnId0 + 1, kReqId0, hal_addr0, char_handle_, 0, false);
+  EXPECT_EQ(0, test_delegate.char_read_req().count);
+  EXPECT_EQ(0, test_delegate.desc_read_req().count);
+
+  // Unknown device address shouldn't trigger anything.
+  fake_hal_gatt_iface_->NotifyRequestReadCharacteristicCallback(
+      kConnId0, kReqId0, hal_addr1, char_handle_, 0, false);
+  EXPECT_EQ(0, test_delegate.char_read_req().count);
+  EXPECT_EQ(0, test_delegate.desc_read_req().count);
+
+  // Characteristic and descriptor handles should trigger correct callbacks.
+  fake_hal_gatt_iface_->NotifyRequestReadCharacteristicCallback(
+      kConnId0, kReqId0, hal_addr0, char_handle_, 0, false);
+  EXPECT_EQ(1, test_delegate.char_read_req().count);
+  EXPECT_EQ(kTestAddress0, test_delegate.char_read_req().device_address);
+  EXPECT_EQ(kReqId0, test_delegate.char_read_req().id);
+  EXPECT_EQ(0, test_delegate.char_read_req().offset);
+  EXPECT_FALSE(test_delegate.char_read_req().is_long);
+  EXPECT_TRUE(char_handle_ == test_delegate.char_read_req().handle);
+  EXPECT_EQ(0, test_delegate.desc_read_req().count);
+
+  fake_hal_gatt_iface_->NotifyRequestReadDescriptorCallback(
+      kConnId0, kReqId1, hal_addr0, desc_handle_, 2, true);
+  EXPECT_EQ(1, test_delegate.char_read_req().count);
+  EXPECT_EQ(1, test_delegate.desc_read_req().count);
+  EXPECT_EQ(kTestAddress0, test_delegate.desc_read_req().device_address);
+  EXPECT_EQ(kReqId1, test_delegate.desc_read_req().id);
+  EXPECT_EQ(2, test_delegate.desc_read_req().offset);
+  EXPECT_TRUE(test_delegate.desc_read_req().is_long);
+  EXPECT_TRUE(desc_handle_ == test_delegate.desc_read_req().handle);
+
+  // Callback with a pending request ID will be ignored.
+  fake_hal_gatt_iface_->NotifyRequestReadCharacteristicCallback(
+      kConnId0, kReqId0, hal_addr0, char_handle_, 0, false);
+  fake_hal_gatt_iface_->NotifyRequestReadCharacteristicCallback(
+      kConnId0, kReqId1, hal_addr0, char_handle_, 0, false);
+  EXPECT_EQ(1, test_delegate.char_read_req().count);
+  EXPECT_EQ(1, test_delegate.desc_read_req().count);
+
+  // Send response for wrong device address.
+  EXPECT_FALSE(gatt_server_->SendResponse(
+      kTestAddress1, kReqId0,
+      GATT_ERROR_NONE, 0, kTestValue));
+
+  // Send response for a value that's too large.
+  EXPECT_FALSE(gatt_server_->SendResponse(
+      kTestAddress0, kReqId0,
+      GATT_ERROR_NONE, 0, kTestValueTooLarge));
+
+  EXPECT_CALL(*mock_handler_, SendResponse(kConnId0, kReqId0,
+                                           BT_STATUS_SUCCESS, _))
+      .Times(2)
+      .WillOnce(Return(BT_STATUS_FAIL))
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+
+  // Stack call fails.
+  EXPECT_FALSE(gatt_server_->SendResponse(
+      kTestAddress0, kReqId0,
+      GATT_ERROR_NONE, 0, kTestValue));
+
+  // Successful send response for characteristic.
+  EXPECT_TRUE(gatt_server_->SendResponse(
+      kTestAddress0, kReqId0,
+      GATT_ERROR_NONE, 0, kTestValue));
+
+  // Characteristic request ID no longer pending.
+  EXPECT_FALSE(gatt_server_->SendResponse(
+      kTestAddress0, kReqId0,
+      GATT_ERROR_NONE, 0, kTestValue));
+
+  EXPECT_CALL(*mock_handler_, SendResponse(kConnId0, kReqId1,
+                                           BT_STATUS_SUCCESS, _))
+      .Times(1)
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+
+  // Successful send response for descriptor.
+  EXPECT_TRUE(gatt_server_->SendResponse(
+      kTestAddress0, kReqId1,
+      GATT_ERROR_NONE, 0, kTestValue));
+
+  // Descriptor request ID no longer pending.
+  EXPECT_FALSE(gatt_server_->SendResponse(
+      kTestAddress0, kReqId1,
+      GATT_ERROR_NONE, 0, kTestValue));
+
+  gatt_server_->SetDelegate(nullptr);
+}
+
+TEST_F(GattServerPostRegisterTest, RequestWrite) {
+  SetUpTestService();
+
+  TestDelegate test_delegate;
+  gatt_server_->SetDelegate(&test_delegate);
+
+  const std::vector<uint8_t> kTestValue = { 0x01, 0x02, 0x03 };
+  const std::string kTestAddress0 = "01:23:45:67:89:AB";
+  const std::string kTestAddress1 = "CD:EF:01:23:45:67";
+  const int kReqId0 = 0;
+  const int kReqId1 = 1;
+  const int kConnId0 = 1;
+
+  // No pending request.
+  EXPECT_FALSE(gatt_server_->SendResponse(
+      kTestAddress0, kReqId0,
+      GATT_ERROR_NONE, 0, kTestValue));
+
+  bt_bdaddr_t hal_addr0, hal_addr1;
+  ASSERT_TRUE(util::BdAddrFromString(kTestAddress0, &hal_addr0));
+  ASSERT_TRUE(util::BdAddrFromString(kTestAddress1, &hal_addr1));
+
+  // Send a connection callback. The GattServer should store the connection
+  // information and be able to process the incoming read requests for this
+  // connection.
+  fake_hal_gatt_iface_->NotifyServerConnectionCallback(
+      kConnId0, kDefaultServerId, true, hal_addr0);
+
+  // Unknown connection ID shouldn't trigger anything.
+  fake_hal_gatt_iface_->NotifyRequestWriteCharacteristicCallback(
+      kConnId0 + 1, kReqId0, hal_addr0, char_handle_, 0,
+      true, false, kTestValue);
+  EXPECT_EQ(0, test_delegate.char_write_req().count);
+  EXPECT_EQ(0, test_delegate.desc_write_req().count);
+
+  // Unknown device address shouldn't trigger anything.
+  fake_hal_gatt_iface_->NotifyRequestWriteCharacteristicCallback(
+      kConnId0, kReqId0, hal_addr1, char_handle_, 0,
+      true, false, kTestValue);
+  EXPECT_EQ(0, test_delegate.char_write_req().count);
+  EXPECT_EQ(0, test_delegate.desc_write_req().count);
+
+  // Characteristic and descriptor handles should trigger correct callbacks.
+  fake_hal_gatt_iface_->NotifyRequestWriteCharacteristicCallback(
+      kConnId0, kReqId0, hal_addr0, char_handle_, 0,
+      true, false, kTestValue);
+  EXPECT_EQ(1, test_delegate.char_write_req().count);
+  EXPECT_EQ(kTestAddress0, test_delegate.char_write_req().device_address);
+  EXPECT_EQ(kReqId0, test_delegate.char_write_req().id);
+  EXPECT_EQ(0, test_delegate.char_write_req().offset);
+  EXPECT_EQ(true, test_delegate.char_write_req().need_rsp);
+  EXPECT_EQ(false, test_delegate.char_write_req().is_exec);
+  EXPECT_EQ(kTestValue, test_delegate.char_write_req().write_value);
+  EXPECT_TRUE(char_handle_ == test_delegate.char_write_req().handle);
+  EXPECT_EQ(0, test_delegate.desc_write_req().count);
+
+  fake_hal_gatt_iface_->NotifyRequestWriteDescriptorCallback(
+      kConnId0, kReqId1, hal_addr0, desc_handle_, 2,
+      true, false, kTestValue);
+  EXPECT_EQ(1, test_delegate.char_write_req().count);
+  EXPECT_EQ(1, test_delegate.desc_write_req().count);
+  EXPECT_EQ(kTestAddress0, test_delegate.desc_write_req().device_address);
+  EXPECT_EQ(kReqId1, test_delegate.desc_write_req().id);
+  EXPECT_EQ(2, test_delegate.desc_write_req().offset);
+  EXPECT_EQ(true, test_delegate.desc_write_req().need_rsp);
+  EXPECT_EQ(false, test_delegate.desc_write_req().is_exec);
+  EXPECT_EQ(kTestValue, test_delegate.desc_write_req().write_value);
+  EXPECT_TRUE(desc_handle_ == test_delegate.desc_write_req().handle);
+
+  // Callback with a pending request ID will be ignored.
+  fake_hal_gatt_iface_->NotifyRequestWriteCharacteristicCallback(
+      kConnId0, kReqId0, hal_addr0, char_handle_, 0,
+      true, false, kTestValue);
+  fake_hal_gatt_iface_->NotifyRequestWriteCharacteristicCallback(
+      kConnId0, kReqId1, hal_addr0, char_handle_, 0,
+      true, false, kTestValue);
+  EXPECT_EQ(1, test_delegate.char_write_req().count);
+  EXPECT_EQ(1, test_delegate.desc_write_req().count);
+
+  // Send response for wrong device address.
+  EXPECT_FALSE(gatt_server_->SendResponse(
+      kTestAddress1, kReqId0,
+      GATT_ERROR_NONE, 0, kTestValue));
+
+  EXPECT_CALL(*mock_handler_, SendResponse(kConnId0, kReqId0,
+                                           BT_STATUS_SUCCESS, _))
+      .Times(2)
+      .WillOnce(Return(BT_STATUS_FAIL))
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+
+  // Stack call fails.
+  EXPECT_FALSE(gatt_server_->SendResponse(
+      kTestAddress0, kReqId0,
+      GATT_ERROR_NONE, 0, kTestValue));
+
+  // Successful send response for characteristic.
+  EXPECT_TRUE(gatt_server_->SendResponse(
+      kTestAddress0, kReqId0,
+      GATT_ERROR_NONE, 0, kTestValue));
+
+  // Characteristic request ID no longer pending.
+  EXPECT_FALSE(gatt_server_->SendResponse(
+      kTestAddress0, kReqId0,
+      GATT_ERROR_NONE, 0, kTestValue));
+
+  EXPECT_CALL(*mock_handler_, SendResponse(kConnId0, kReqId1,
+                                           BT_STATUS_SUCCESS, _))
+      .Times(1)
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+
+  // Successful send response for descriptor.
+  EXPECT_TRUE(gatt_server_->SendResponse(
+      kTestAddress0, kReqId1,
+      GATT_ERROR_NONE, 0, kTestValue));
+
+  // Descriptor request ID no longer pending.
+  EXPECT_FALSE(gatt_server_->SendResponse(
+      kTestAddress0, kReqId1,
+      GATT_ERROR_NONE, 0, kTestValue));
+
+  // SendResponse should fail for a "Write Without Response".
+  fake_hal_gatt_iface_->NotifyRequestWriteCharacteristicCallback(
+      kConnId0, kReqId0, hal_addr0, char_handle_, 0,
+      false, false, kTestValue);
+  EXPECT_EQ(false, test_delegate.char_write_req().need_rsp);
+  EXPECT_FALSE(gatt_server_->SendResponse(
+      kTestAddress0, kReqId0,
+      GATT_ERROR_NONE, 0, kTestValue));
+
+  gatt_server_->SetDelegate(nullptr);
+}
+
+TEST_F(GattServerPostRegisterTest, SendNotification) {
+  SetUpTestService();
+
+  const std::string kTestAddress0 = "01:23:45:67:89:AB";
+  const std::string kTestAddress1 = "cd:ef:01:23:45:67";
+  const std::string kInvalidAddress = "thingamajig blabbidyboop";
+  const int kConnId0 = 0;
+  const int kConnId1 = 1;
+  std::vector<uint8_t> value;
+  bt_bdaddr_t hal_addr0;
+  ASSERT_TRUE(util::BdAddrFromString(kTestAddress0, &hal_addr0));
+
+  // Set up two connections with the same address.
+  fake_hal_gatt_iface_->NotifyServerConnectionCallback(
+      kConnId0, kDefaultServerId, true, hal_addr0);
+  fake_hal_gatt_iface_->NotifyServerConnectionCallback(
+      kConnId1, kDefaultServerId, true, hal_addr0);
+
+  // Set up a test callback.
+  GATTError gatt_error;
+  int callback_count = 0;
+  auto callback = [&](GATTError in_error) {
+    gatt_error = in_error;
+    callback_count++;
+  };
+
+  // Bad device address.
+  EXPECT_FALSE(gatt_server_->SendNotification(
+      kInvalidAddress,
+      char_handle_, false, value, callback));
+
+  // Bad connection.
+  EXPECT_FALSE(gatt_server_->SendNotification(
+      kTestAddress1,
+      char_handle_, false, value, callback));
+
+  // We should get a HAL call for each connection for this address. The calls
+  // fail.
+  EXPECT_CALL(*mock_handler_,
+              SendIndication(kDefaultServerId, char_handle_, kConnId0,
+                             0, value))
+      .Times(1)
+      .WillOnce(Return(BT_STATUS_FAIL));
+  EXPECT_CALL(*mock_handler_,
+              SendIndication(kDefaultServerId, char_handle_, kConnId1,
+                             0, value))
+      .Times(1)
+      .WillOnce(Return(BT_STATUS_FAIL));
+  EXPECT_FALSE(gatt_server_->SendNotification(
+      kTestAddress0,
+      char_handle_, false, value, callback));
+
+  // One of the calls succeeds.
+  EXPECT_CALL(*mock_handler_,
+              SendIndication(kDefaultServerId, char_handle_, kConnId0,
+                             0, value))
+      .Times(1)
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+  EXPECT_CALL(*mock_handler_,
+              SendIndication(kDefaultServerId, char_handle_, kConnId1,
+                             0, value))
+      .Times(1)
+      .WillOnce(Return(BT_STATUS_FAIL));
+  EXPECT_TRUE(gatt_server_->SendNotification(
+      kTestAddress0,
+      char_handle_, false, value, callback));
+
+  // One of the connections is already pending so there should be only one call.
+  // This one we send with confirm=true.
+  EXPECT_CALL(*mock_handler_,
+              SendIndication(kDefaultServerId, char_handle_, kConnId1,
+                             1, value))
+      .Times(1)
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+  EXPECT_TRUE(gatt_server_->SendNotification(
+      kTestAddress0,
+      char_handle_, true, value, callback));
+
+  // Calls are already pending.
+  EXPECT_FALSE(gatt_server_->SendNotification(
+      kTestAddress0, char_handle_, true, value, callback));
+
+  // Trigger one confirmation callback. We should get calls for two callbacks
+  // since we have two separate calls pending.
+  fake_hal_gatt_iface_->NotifyIndicationSentCallback(
+      kConnId0, BT_STATUS_SUCCESS);
+  fake_hal_gatt_iface_->NotifyIndicationSentCallback(
+      kConnId1, BT_STATUS_SUCCESS);
+  EXPECT_EQ(2, callback_count);
+  EXPECT_EQ(GATT_ERROR_NONE, gatt_error);
+
+  callback_count = 0;
+
+  // Restart. Both calls succeed now.
+  EXPECT_CALL(*mock_handler_,
+              SendIndication(kDefaultServerId, char_handle_, kConnId0,
+                             0, value))
+      .Times(1)
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+  EXPECT_CALL(*mock_handler_,
+              SendIndication(kDefaultServerId, char_handle_, kConnId1,
+                             0, value))
+      .Times(1)
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+  EXPECT_TRUE(gatt_server_->SendNotification(
+      kTestAddress0,
+      char_handle_, false, value, callback));
+
+  // Trigger one confirmation callback. The callback we passed should still be
+  // pending. The first callback is for the wrong connection ID.
+  fake_hal_gatt_iface_->NotifyIndicationSentCallback(
+      kConnId0 + 50, BT_STATUS_FAIL);
+  fake_hal_gatt_iface_->NotifyIndicationSentCallback(
+      kConnId0, BT_STATUS_SUCCESS);
+  EXPECT_EQ(0, callback_count);
+
+  // This should be ignored since |kConnId0| was already processed.
+  fake_hal_gatt_iface_->NotifyIndicationSentCallback(
+      kConnId0, BT_STATUS_SUCCESS);
+  EXPECT_EQ(0, callback_count);
+
+  // Run the callback with failure. Since the previous callback reported
+  // success, we should report success.
+  fake_hal_gatt_iface_->NotifyIndicationSentCallback(
+      kConnId1, BT_STATUS_SUCCESS);
+  EXPECT_EQ(1, callback_count);
+  EXPECT_EQ(GATT_ERROR_NONE, gatt_error);
+}
+
+}  // namespace
+}  // namespace bluetooth
diff --git a/bt/service/test/ipc_linux_unittest.cc b/bt/service/test/ipc_linux_unittest.cc
new file mode 100644
index 0000000..efd50ac
--- /dev/null
+++ b/bt/service/test/ipc_linux_unittest.cc
@@ -0,0 +1,206 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 <sys/socket.h>
+#include <sys/un.h>
+
+#include <base/at_exit.h>
+#include <base/command_line.h>
+#include <base/files/scoped_file.h>
+#include <base/macros.h>
+#include <base/strings/stringprintf.h>
+#include <gtest/gtest.h>
+
+#include "service/adapter.h"
+#include "service/hal/fake_bluetooth_gatt_interface.h"
+#include "service/hal/fake_bluetooth_interface.h"
+#include "service/ipc/ipc_manager.h"
+#include "service/settings.h"
+#include "service/test/mock_daemon.h"
+
+
+namespace {
+
+using testing::Return;
+
+const char kTestSocketPath[] = "test_socket_path";
+
+class IPCLinuxTest : public ::testing::Test {
+ public:
+  IPCLinuxTest() = default;
+  ~IPCLinuxTest() override = default;
+
+  void SetUp() override {
+    SetUpCommandLine();
+    ASSERT_TRUE(settings_.Init());
+
+    auto mock_daemon = new bluetooth::testing::MockDaemon();
+
+    ON_CALL(*mock_daemon, GetSettings()).WillByDefault(Return(&settings_));
+    ON_CALL(*mock_daemon, GetMessageLoop())
+        .WillByDefault(Return(&message_loop_));
+
+    bluetooth::Daemon::InitializeForTesting(mock_daemon);
+    bluetooth::hal::BluetoothInterface::InitializeForTesting(
+        new bluetooth::hal::FakeBluetoothInterface());
+    bluetooth::hal::BluetoothGattInterface::InitializeForTesting(
+        new bluetooth::hal::FakeBluetoothGattInterface(nullptr, nullptr, nullptr, nullptr));
+
+    adapter_ = bluetooth::Adapter::Create();
+    ipc_manager_.reset(new ipc::IPCManager(adapter_.get()));
+  }
+
+  void TearDown() override {
+    client_fd_.reset();
+    ipc_manager_.reset();
+    adapter_.reset();
+    bluetooth::hal::BluetoothGattInterface::CleanUp();
+    bluetooth::hal::BluetoothInterface::CleanUp();
+    bluetooth::Daemon::ShutDown();
+    base::CommandLine::Reset();
+  }
+
+  virtual void SetUpCommandLine() {
+    std::string ipc_socket_arg =
+        base::StringPrintf("--create-ipc-socket=%s", kTestSocketPath);
+    const base::CommandLine::CharType* argv[] = {
+      "program", ipc_socket_arg.c_str(),
+    };
+    base::CommandLine::Init(arraysize(argv), argv);
+  }
+
+  void ConnectToTestSocket() {
+    client_fd_.reset(socket(PF_UNIX, SOCK_SEQPACKET, 0));
+    ASSERT_TRUE(client_fd_.is_valid());
+
+    struct sockaddr_un address;
+    memset(&address, 0, sizeof(address));
+    address.sun_family = AF_UNIX;
+    strncpy(address.sun_path, kTestSocketPath, sizeof(address.sun_path) - 1);
+
+    int status = connect(client_fd_.get(), (struct sockaddr *)&address,
+                         sizeof(address));
+    EXPECT_EQ(0, status);
+  }
+
+ protected:
+  base::AtExitManager exit_manager_;
+  base::MessageLoop message_loop_;
+  bluetooth::Settings settings_;
+
+  std::unique_ptr<bluetooth::Adapter> adapter_;
+  std::unique_ptr<ipc::IPCManager> ipc_manager_;
+  base::ScopedFD client_fd_;
+
+  DISALLOW_COPY_AND_ASSIGN(IPCLinuxTest);
+};
+
+class IPCLinuxTestDisabled : public IPCLinuxTest {
+ public:
+  IPCLinuxTestDisabled() = default;
+  ~IPCLinuxTestDisabled() override = default;
+
+  void SetUpCommandLine() override {
+    // Set up with no --ipc-socket-path
+    const base::CommandLine::CharType* argv[] = { "program" };
+    base::CommandLine::Init(arraysize(argv), argv);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(IPCLinuxTestDisabled);
+};
+
+class TestDelegate : public ipc::IPCManager::Delegate,
+                     public base::SupportsWeakPtr<TestDelegate> {
+ public:
+  TestDelegate() : started_count_(0), stopped_count_(0) {
+  }
+
+  void OnIPCHandlerStarted(ipc::IPCManager::Type type) override {
+    ASSERT_EQ(ipc::IPCManager::TYPE_LINUX, type);
+    started_count_++;
+    base::MessageLoop::current()->QuitWhenIdle();
+  }
+
+  void OnIPCHandlerStopped(ipc::IPCManager::Type type) override {
+    ASSERT_EQ(ipc::IPCManager::TYPE_LINUX, type);
+    stopped_count_++;
+    base::MessageLoop::current()->QuitWhenIdle();
+  }
+
+  int started_count() const { return started_count_; }
+  int stopped_count() const { return stopped_count_; }
+
+ private:
+  int started_count_;
+  int stopped_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestDelegate);
+};
+
+TEST_F(IPCLinuxTestDisabled, StartWithNoSocketPath) {
+  TestDelegate delegate;
+  EXPECT_FALSE(ipc_manager_->Start(ipc::IPCManager::TYPE_LINUX, &delegate));
+  EXPECT_FALSE(ipc_manager_->LinuxStarted());
+  EXPECT_EQ(0, delegate.started_count());
+  EXPECT_EQ(0, delegate.stopped_count());
+}
+
+TEST_F(IPCLinuxTest, BasicStartAndExit) {
+  TestDelegate delegate;
+  EXPECT_TRUE(ipc_manager_->Start(ipc::IPCManager::TYPE_LINUX, &delegate));
+  EXPECT_TRUE(ipc_manager_->LinuxStarted());
+
+  // Run the message loop. We will stop the loop when we receive a delegate
+  // event.
+  message_loop_.Run();
+
+  // We should have received the started event.
+  EXPECT_EQ(1, delegate.started_count());
+  EXPECT_EQ(0, delegate.stopped_count());
+
+  // At this point the thread is blocking on accept and listening for incoming
+  // connections. TearDown should gracefully clean up the thread and the test
+  // should succeed without hanging.
+  ipc_manager_.reset();
+  message_loop_.Run();
+  EXPECT_EQ(1, delegate.stopped_count());
+}
+
+TEST_F(IPCLinuxTest, BasicStartAndConnect) {
+  TestDelegate delegate;
+  EXPECT_TRUE(ipc_manager_->Start(ipc::IPCManager::TYPE_LINUX, &delegate));
+  EXPECT_TRUE(ipc_manager_->LinuxStarted());
+
+  // Run the message loop. We will stop the loop when we receive a delegate
+  // event.
+  message_loop_.Run();
+
+  // We should have received the started event.
+  EXPECT_EQ(1, delegate.started_count());
+  EXPECT_EQ(0, delegate.stopped_count());
+
+  // IPC successfully started. Now attempt to connect to the socket.
+  ConnectToTestSocket();
+
+  // TODO(armansito): Test that the IPC event loop shuts down cleanly while a
+  // client is connected. Currently this will fail and the fix is to use
+  // MessageLoopForIO rather than a custom event loop.
+}
+
+}  // namespace
diff --git a/bt/service/test/low_energy_advertiser_unittest.cc b/bt/service/test/low_energy_advertiser_unittest.cc
new file mode 100644
index 0000000..13c4eed
--- /dev/null
+++ b/bt/service/test/low_energy_advertiser_unittest.cc
@@ -0,0 +1,740 @@
+//
+//  Copyright (C) 2016 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 <base/macros.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "service/adapter.h"
+#include "service/hal/fake_bluetooth_gatt_interface.h"
+#include "service/low_energy_advertiser.h"
+#include "stack/include/bt_types.h"
+#include "stack/include/hcidefs.h"
+#include "test/mock_adapter.h"
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Exactly;
+using ::testing::Invoke;
+using ::testing::Pointee;
+using ::testing::Return;
+using ::testing::SaveArg;
+using ::testing::Matcher;
+using status_cb = base::Callback<void(uint8_t)>;
+using reg_cb =
+    base::Callback<void(uint8_t /* advertiser_id */, uint8_t /* status */)>;
+
+namespace bluetooth {
+namespace {
+
+class MockAdvertiserHandler : public BleAdvertiserInterface {
+ public:
+  MockAdvertiserHandler() {}
+  ~MockAdvertiserHandler() override = default;
+
+  MOCK_METHOD1(RegisterAdvertiser,
+               void(base::Callback<void(uint8_t /* advertiser_id */,
+                                        uint8_t /* status */)>));
+  MOCK_METHOD1(Unregister, void(uint8_t));
+
+  MOCK_METHOD2(SetData, void(bool set_scan_rsp, vector<uint8_t> data));
+  MOCK_METHOD2(Enable, void(bool enablle, BleAdvertiserCb cb));
+  MOCK_METHOD7(MultiAdvSetParameters,
+               void(int advertiser_id, int min_interval, int max_interval,
+                    int adv_type, int chnl_map, int tx_power,
+                    BleAdvertiserCb cb));
+  MOCK_METHOD4(MultiAdvSetInstData,
+               void(int advertiser_id, bool set_scan_rsp, vector<uint8_t> data,
+                    BleAdvertiserCb cb));
+  MOCK_METHOD5(MultiAdvEnable,
+               void(uint8_t advertiser_id, bool enable, BleAdvertiserCb cb,
+                    int timeout_s, BleAdvertiserCb timeout_cb));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockAdvertiserHandler);
+};
+
+class LowEnergyAdvertiserTest : public ::testing::Test {
+ public:
+  LowEnergyAdvertiserTest() = default;
+  ~LowEnergyAdvertiserTest() override = default;
+
+  void SetUp() override {
+    // Only set |mock_handler_| if a test hasn't set it.
+    if (!mock_handler_) mock_handler_.reset(new MockAdvertiserHandler());
+    hal::BluetoothGattInterface::InitializeForTesting(
+        new hal::FakeBluetoothGattInterface(
+            std::static_pointer_cast<BleAdvertiserInterface>(mock_handler_),
+            nullptr, nullptr, nullptr));
+    ble_advertiser_factory_.reset(new LowEnergyAdvertiserFactory());
+  }
+
+  void TearDown() override {
+    ble_advertiser_factory_.reset();
+    hal::BluetoothGattInterface::CleanUp();
+  }
+
+ protected:
+  std::shared_ptr<MockAdvertiserHandler> mock_handler_;
+  std::unique_ptr<LowEnergyAdvertiserFactory> ble_advertiser_factory_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LowEnergyAdvertiserTest);
+};
+
+// Used for tests that operate on a pre-registered advertiser.
+class LowEnergyAdvertiserPostRegisterTest : public LowEnergyAdvertiserTest {
+ public:
+  LowEnergyAdvertiserPostRegisterTest() : next_client_id_(0) {}
+  ~LowEnergyAdvertiserPostRegisterTest() override = default;
+
+  void SetUp() override {
+    LowEnergyAdvertiserTest::SetUp();
+    auto callback = [&](std::unique_ptr<LowEnergyAdvertiser> advertiser) {
+      le_advertiser_ = std::move(advertiser);
+    };
+    RegisterTestAdvertiser(callback);
+  }
+
+  void TearDown() override {
+    EXPECT_CALL(*mock_handler_, MultiAdvEnable(_, false, _, _, _)).Times(1);
+    EXPECT_CALL(*mock_handler_, Unregister(_)).Times(1);
+    le_advertiser_.reset();
+    LowEnergyAdvertiserTest::TearDown();
+  }
+
+  void RegisterTestAdvertiser(
+      const std::function<void(std::unique_ptr<LowEnergyAdvertiser> advertiser)>
+          callback) {
+    UUID uuid = UUID::GetRandom();
+    auto api_callback = [&](BLEStatus status, const UUID& in_uuid,
+                        std::unique_ptr<BluetoothInstance> in_client) {
+      CHECK(in_uuid == uuid);
+      CHECK(in_client.get());
+      CHECK(status == BLE_STATUS_SUCCESS);
+
+      callback(std::unique_ptr<LowEnergyAdvertiser>(
+          static_cast<LowEnergyAdvertiser*>(in_client.release())));
+    };
+
+    reg_cb reg_adv_cb;
+    EXPECT_CALL(*mock_handler_, RegisterAdvertiser(_))
+        .Times(1)
+        .WillOnce(SaveArg<0>(&reg_adv_cb));
+
+    ble_advertiser_factory_->RegisterInstance(uuid, api_callback);
+
+    reg_adv_cb.Run(next_client_id_++, BT_STATUS_SUCCESS);
+    ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+  }
+
+  void StartAdvertising() {
+    ASSERT_FALSE(le_advertiser_->IsAdvertisingStarted());
+    ASSERT_FALSE(le_advertiser_->IsStartingAdvertising());
+    ASSERT_FALSE(le_advertiser_->IsStoppingAdvertising());
+
+    status_cb set_params_cb;
+    EXPECT_CALL(*mock_handler_, MultiAdvSetParameters(_, _, _, _, _, _, _))
+        .Times(1)
+        .WillOnce(SaveArg<6>(&set_params_cb));
+    status_cb set_data_cb;
+    EXPECT_CALL(*mock_handler_, MultiAdvSetInstData(_, _, _, _))
+        .Times(1)
+        .WillOnce(SaveArg<3>(&set_data_cb));
+    status_cb enable_cb;
+    EXPECT_CALL(*mock_handler_, MultiAdvEnable(_, true, _, _, _))
+        .Times(1)
+        .WillOnce(SaveArg<2>(&enable_cb));
+
+    AdvertiseSettings settings;
+    AdvertiseData adv, scan_rsp;
+    ASSERT_TRUE(le_advertiser_->StartAdvertising(
+        settings, adv, scan_rsp, LowEnergyAdvertiser::StatusCallback()));
+    ASSERT_TRUE(le_advertiser_->IsStartingAdvertising());
+
+    set_params_cb.Run(BT_STATUS_SUCCESS);
+    set_data_cb.Run(BT_STATUS_SUCCESS);
+    enable_cb.Run(BT_STATUS_SUCCESS);
+
+    ASSERT_TRUE(le_advertiser_->IsAdvertisingStarted());
+    ASSERT_FALSE(le_advertiser_->IsStartingAdvertising());
+    ASSERT_FALSE(le_advertiser_->IsStoppingAdvertising());
+  }
+
+  void AdvertiseDataTestHelper(AdvertiseData data, std::function<void(BLEStatus)> callback, status_cb *set_data_cb) {
+    AdvertiseSettings settings;
+
+    LOG_ASSERT(set_data_cb) << "set_data_cb must be set";
+
+    status_cb set_params_cb;
+    EXPECT_CALL(*mock_handler_, MultiAdvSetParameters(_, _, _, _, _, _, _))
+        .Times(1)
+        .WillOnce(SaveArg<6>(&set_params_cb));
+
+    status_cb enable_cb;
+    EXPECT_CALL(*mock_handler_, MultiAdvEnable(_, true, _, _, _))
+        .Times(1)
+        .WillOnce(SaveArg<2>(&enable_cb));
+
+    EXPECT_TRUE(le_advertiser_->StartAdvertising(
+        settings, data, AdvertiseData(), callback));
+
+    set_params_cb.Run(BT_STATUS_SUCCESS);
+    set_data_cb->Run(BT_STATUS_SUCCESS);
+    enable_cb.Run(BT_STATUS_SUCCESS);
+
+    status_cb disable_cb;
+    EXPECT_CALL(*mock_handler_, MultiAdvEnable(_, false, _, _, _))
+        .Times(1)
+        .WillOnce(SaveArg<2>(&disable_cb));
+
+    EXPECT_TRUE(le_advertiser_->StopAdvertising(LowEnergyAdvertiser::StatusCallback()));
+    disable_cb.Run(BT_STATUS_SUCCESS);
+  }
+
+ protected:
+  std::unique_ptr<LowEnergyAdvertiser> le_advertiser_;
+
+ private:
+  int next_client_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(LowEnergyAdvertiserPostRegisterTest);
+};
+
+TEST_F(LowEnergyAdvertiserTest, RegisterInstance) {
+  // These will be asynchronously populated with a result when the callback
+  // executes.
+  BLEStatus status = BLE_STATUS_SUCCESS;
+  UUID cb_uuid;
+  std::unique_ptr<LowEnergyAdvertiser> advertiser;
+  int callback_count = 0;
+
+  auto callback = [&](BLEStatus in_status, const UUID& uuid,
+                      std::unique_ptr<BluetoothInstance> in_client) {
+        status = in_status;
+        cb_uuid = uuid;
+        advertiser = std::unique_ptr<LowEnergyAdvertiser>(
+            static_cast<LowEnergyAdvertiser*>(in_client.release()));
+        callback_count++;
+      };
+
+  UUID uuid0 = UUID::GetRandom();
+
+  reg_cb reg_adv1_cb;
+  EXPECT_CALL(*mock_handler_, RegisterAdvertiser(_))
+      .Times(1)
+      .WillOnce(SaveArg<0>(&reg_adv1_cb));
+
+  // Success.
+  EXPECT_TRUE(ble_advertiser_factory_->RegisterInstance(uuid0, callback));
+  EXPECT_EQ(0, callback_count);
+
+  // Calling twice with the same UUID should fail with no additional call into
+  // the stack.
+  EXPECT_FALSE(ble_advertiser_factory_->RegisterInstance(uuid0, callback));
+
+  ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+  // Call with a different UUID while one is pending.
+  UUID uuid1 = UUID::GetRandom();
+  reg_cb reg_adv2_cb;
+  EXPECT_CALL(*mock_handler_, RegisterAdvertiser(_))
+      .Times(1)
+      .WillOnce(SaveArg<0>(&reg_adv2_cb));
+  EXPECT_TRUE(ble_advertiser_factory_->RegisterInstance(uuid1, callback));
+
+  // |uuid0| succeeds.
+  int client_if0 = 2;  // Pick something that's not 0.
+  reg_adv1_cb.Run(client_if0, BT_STATUS_SUCCESS);
+
+  EXPECT_EQ(1, callback_count);
+  ASSERT_TRUE(advertiser.get() != nullptr);  // Assert to terminate in case of error
+  EXPECT_EQ(BLE_STATUS_SUCCESS, status);
+  EXPECT_EQ(client_if0, advertiser->GetInstanceId());
+  EXPECT_EQ(uuid0, advertiser->GetAppIdentifier());
+  EXPECT_EQ(uuid0, cb_uuid);
+
+  // The advertiser should unregister itself when deleted.
+  EXPECT_CALL(*mock_handler_, MultiAdvEnable(client_if0, false, _, _, _))
+      .Times(1);
+  EXPECT_CALL(*mock_handler_, Unregister(client_if0))
+      .Times(1);
+  advertiser.reset();
+  ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+  // |uuid1| fails.
+  uint8_t client_if1 = 10;
+  reg_adv2_cb.Run(client_if1, BT_STATUS_FAIL);
+
+  EXPECT_EQ(2, callback_count);
+  ASSERT_TRUE(advertiser.get() == nullptr);  // Assert to terminate in case of error
+  EXPECT_EQ(BLE_STATUS_FAILURE, status);
+  EXPECT_EQ(uuid1, cb_uuid);
+}
+
+TEST_F(LowEnergyAdvertiserPostRegisterTest, StartAdvertisingBasic) {
+  EXPECT_FALSE(le_advertiser_->IsAdvertisingStarted());
+  EXPECT_FALSE(le_advertiser_->IsStartingAdvertising());
+  EXPECT_FALSE(le_advertiser_->IsStoppingAdvertising());
+
+  // Use default advertising settings and data.
+  AdvertiseSettings settings;
+  AdvertiseData adv_data, scan_rsp;
+  int callback_count = 0;
+  BLEStatus last_status = BLE_STATUS_FAILURE;
+  auto callback = [&](BLEStatus status) {
+    last_status = status;
+    callback_count++;
+  };
+
+  status_cb set_params_cb;
+  EXPECT_CALL(*mock_handler_, MultiAdvSetParameters(_, _, _, _, _, _, _))
+      .Times(3)
+      .WillRepeatedly(SaveArg<6>(&set_params_cb));
+
+  // Stack call returns success.
+  EXPECT_TRUE(le_advertiser_->StartAdvertising(
+      settings, adv_data, scan_rsp, callback));
+
+  EXPECT_FALSE(le_advertiser_->IsAdvertisingStarted());
+  EXPECT_TRUE(le_advertiser_->IsStartingAdvertising());
+  EXPECT_FALSE(le_advertiser_->IsStoppingAdvertising());
+  EXPECT_EQ(0, callback_count);
+
+  // Already starting.
+  EXPECT_FALSE(le_advertiser_->StartAdvertising(
+      settings, adv_data, scan_rsp, callback));
+
+  // Notify failure.
+  set_params_cb.Run(BT_STATUS_FAIL);
+
+  EXPECT_FALSE(le_advertiser_->IsAdvertisingStarted());
+  EXPECT_FALSE(le_advertiser_->IsStartingAdvertising());
+  EXPECT_FALSE(le_advertiser_->IsStoppingAdvertising());
+  EXPECT_EQ(1, callback_count);
+  EXPECT_EQ(BLE_STATUS_FAILURE, last_status);
+
+  // Try again.
+  EXPECT_TRUE(le_advertiser_->StartAdvertising(
+      settings, adv_data, scan_rsp, callback));
+  EXPECT_FALSE(le_advertiser_->IsAdvertisingStarted());
+  EXPECT_TRUE(le_advertiser_->IsStartingAdvertising());
+  EXPECT_FALSE(le_advertiser_->IsStoppingAdvertising());
+  EXPECT_EQ(1, callback_count);
+
+  // Success notification should trigger advertise data update.
+  status_cb set_data_cb;
+  EXPECT_CALL(*mock_handler_, MultiAdvSetInstData(_, false, /* set_scan_rsp */
+                                                  _, _))
+      .Times(2)
+      .WillRepeatedly(SaveArg<3>(&set_data_cb));
+
+  // Notify success for set params. the advertise data call should succeed but
+  // operation will remain pending.
+  set_params_cb.Run(BT_STATUS_SUCCESS);
+  EXPECT_FALSE(le_advertiser_->IsAdvertisingStarted());
+  EXPECT_TRUE(le_advertiser_->IsStartingAdvertising());
+  EXPECT_FALSE(le_advertiser_->IsStoppingAdvertising());
+  EXPECT_EQ(1, callback_count);
+
+  // Notify failure from advertising call.
+  set_data_cb.Run(BT_STATUS_FAIL);
+  EXPECT_FALSE(le_advertiser_->IsAdvertisingStarted());
+  EXPECT_FALSE(le_advertiser_->IsStartingAdvertising());
+  EXPECT_FALSE(le_advertiser_->IsStoppingAdvertising());
+  EXPECT_EQ(2, callback_count);
+  EXPECT_EQ(BLE_STATUS_FAILURE, last_status);
+
+  // Try again. Make everything succeed.
+  EXPECT_TRUE(le_advertiser_->StartAdvertising(
+      settings, adv_data, scan_rsp, callback));
+  EXPECT_FALSE(le_advertiser_->IsAdvertisingStarted());
+  EXPECT_TRUE(le_advertiser_->IsStartingAdvertising());
+  EXPECT_FALSE(le_advertiser_->IsStoppingAdvertising());
+  EXPECT_EQ(2, callback_count);
+
+  status_cb enable_cb;
+  EXPECT_CALL(*mock_handler_, MultiAdvEnable(_, true, _, _, _))
+      .Times(1)
+      .WillOnce(SaveArg<2>(&enable_cb));
+
+  set_params_cb.Run(BT_STATUS_SUCCESS);
+  set_data_cb.Run(BT_STATUS_SUCCESS);
+  enable_cb.Run(BT_STATUS_SUCCESS);
+  EXPECT_TRUE(le_advertiser_->IsAdvertisingStarted());
+  EXPECT_FALSE(le_advertiser_->IsStartingAdvertising());
+  EXPECT_FALSE(le_advertiser_->IsStoppingAdvertising());
+  EXPECT_EQ(3, callback_count);
+  EXPECT_EQ(BLE_STATUS_SUCCESS, last_status);
+
+  // Already started.
+  EXPECT_FALSE(le_advertiser_->StartAdvertising(
+      settings, adv_data, scan_rsp, callback));
+}
+
+TEST_F(LowEnergyAdvertiserPostRegisterTest, StopAdvertisingBasic) {
+  AdvertiseSettings settings;
+
+  // Not enabled.
+  EXPECT_FALSE(le_advertiser_->IsAdvertisingStarted());
+  EXPECT_FALSE(le_advertiser_->StopAdvertising(LowEnergyAdvertiser::StatusCallback()));
+
+  // Start advertising for testing.
+  StartAdvertising();
+
+  int callback_count = 0;
+  BLEStatus last_status = BLE_STATUS_FAILURE;
+  auto callback = [&](BLEStatus status) {
+    last_status = status;
+    callback_count++;
+  };
+
+  status_cb enable_cb;
+  EXPECT_CALL(*mock_handler_, MultiAdvEnable(_, false, _, _, _))
+      .Times(2)
+      .WillRepeatedly(SaveArg<2>(&enable_cb));
+
+  // Stack returns success.
+  EXPECT_TRUE(le_advertiser_->StopAdvertising(callback));
+  EXPECT_TRUE(le_advertiser_->IsAdvertisingStarted());
+  EXPECT_FALSE(le_advertiser_->IsStartingAdvertising());
+  EXPECT_TRUE(le_advertiser_->IsStoppingAdvertising());
+  EXPECT_EQ(0, callback_count);
+
+  // Already disabling.
+  EXPECT_FALSE(le_advertiser_->StopAdvertising(callback));
+  EXPECT_TRUE(le_advertiser_->IsAdvertisingStarted());
+  EXPECT_FALSE(le_advertiser_->IsStartingAdvertising());
+  EXPECT_TRUE(le_advertiser_->IsStoppingAdvertising());
+  EXPECT_EQ(0, callback_count);
+
+  // Notify failure.
+  enable_cb.Run(BT_STATUS_FAIL);
+  EXPECT_TRUE(le_advertiser_->IsAdvertisingStarted());
+  EXPECT_FALSE(le_advertiser_->IsStartingAdvertising());
+  EXPECT_FALSE(le_advertiser_->IsStoppingAdvertising());
+  EXPECT_EQ(1, callback_count);
+  EXPECT_EQ(BLE_STATUS_FAILURE, last_status);
+
+  // Try again.
+  EXPECT_TRUE(le_advertiser_->StopAdvertising(callback));
+  EXPECT_TRUE(le_advertiser_->IsAdvertisingStarted());
+  EXPECT_FALSE(le_advertiser_->IsStartingAdvertising());
+  EXPECT_TRUE(le_advertiser_->IsStoppingAdvertising());
+  EXPECT_EQ(1, callback_count);
+
+  // Notify success.
+  enable_cb.Run(BT_STATUS_SUCCESS);
+  EXPECT_FALSE(le_advertiser_->IsAdvertisingStarted());
+  EXPECT_FALSE(le_advertiser_->IsStartingAdvertising());
+  EXPECT_FALSE(le_advertiser_->IsStoppingAdvertising());
+  EXPECT_EQ(2, callback_count);
+  EXPECT_EQ(BLE_STATUS_SUCCESS, last_status);
+
+  // Already stopped.
+  EXPECT_FALSE(le_advertiser_->StopAdvertising(callback));
+}
+
+TEST_F(LowEnergyAdvertiserPostRegisterTest, InvalidAdvertiseData) {
+  const std::vector<uint8_t> data0{ 0x02, HCI_EIR_FLAGS_TYPE, 0x00 };
+  const std::vector<uint8_t> data1{
+      0x04, HCI_EIR_MANUFACTURER_SPECIFIC_TYPE, 0x01, 0x02, 0x00
+  };
+  AdvertiseData invalid_adv(data0);
+  AdvertiseData valid_adv(data1);
+
+  AdvertiseSettings settings;
+
+  EXPECT_FALSE(le_advertiser_->StartAdvertising(
+      settings, valid_adv, invalid_adv, LowEnergyAdvertiser::StatusCallback()));
+  EXPECT_FALSE(le_advertiser_->StartAdvertising(
+      settings, invalid_adv, valid_adv, LowEnergyAdvertiser::StatusCallback()));
+
+  // Manufacturer data not correctly formatted according to spec. We let the
+  // stack handle this case.
+  const std::vector<uint8_t> data2{ 0x01, HCI_EIR_MANUFACTURER_SPECIFIC_TYPE };
+  AdvertiseData invalid_mfc(data2);
+
+  EXPECT_CALL(*mock_handler_, MultiAdvSetParameters(_, _, _, _, _, _, _))
+      .Times(1);
+  EXPECT_TRUE(le_advertiser_->StartAdvertising(
+      settings, invalid_mfc, valid_adv, LowEnergyAdvertiser::StatusCallback()));
+}
+
+TEST_F(LowEnergyAdvertiserPostRegisterTest, ScanResponse) {
+  EXPECT_FALSE(le_advertiser_->IsAdvertisingStarted());
+  EXPECT_FALSE(le_advertiser_->IsStartingAdvertising());
+  EXPECT_FALSE(le_advertiser_->IsStoppingAdvertising());
+
+  AdvertiseSettings settings(
+      AdvertiseSettings::MODE_LOW_POWER,
+      base::TimeDelta::FromMilliseconds(300),
+      AdvertiseSettings::TX_POWER_LEVEL_MEDIUM,
+      false /* connectable */);
+
+  const std::vector<uint8_t> data0{0x02, HCI_EIR_TX_POWER_LEVEL_TYPE, 0x00};
+  const std::vector<uint8_t> data1{
+      0x05, HCI_EIR_COMPLETE_LOCAL_NAME_TYPE, 'a', 'b', 'c', 'd',
+      0x04, HCI_EIR_MANUFACTURER_SPECIFIC_TYPE, 0x01, 0x02, 0x00
+  };
+
+  int callback_count = 0;
+  BLEStatus last_status = BLE_STATUS_FAILURE;
+  auto callback = [&](BLEStatus status) {
+    last_status = status;
+    callback_count++;
+  };
+
+  AdvertiseData adv0(data0);
+  AdvertiseData adv1(data1);
+
+  status_cb set_params_cb;
+  EXPECT_CALL(*mock_handler_,
+              MultiAdvSetParameters(le_advertiser_->GetInstanceId(), _, _,
+                             kAdvertisingEventTypeScannable,
+                             _, _, _))
+      .Times(2)
+      .WillRepeatedly(SaveArg<6>(&set_params_cb));
+  status_cb set_adv_data_cb;
+  EXPECT_CALL(
+      *mock_handler_,
+      MultiAdvSetInstData(_,
+          false,  // set_scan_rsp
+          _, _))
+      .Times(2)
+      .WillRepeatedly(SaveArg<3>(&set_adv_data_cb));
+  status_cb set_scan_rsp_cb;
+  EXPECT_CALL(*mock_handler_,
+              MultiAdvSetInstData(_, true /* set_scan_rsp */, _, _))
+      .Times(2)
+      .WillRepeatedly(SaveArg<3>(&set_scan_rsp_cb));
+
+  // Enable success; Adv. data success; Scan rsp. fail.
+  EXPECT_TRUE(le_advertiser_->StartAdvertising(settings, adv0, adv1, callback));
+  set_params_cb.Run(BT_STATUS_SUCCESS);
+  set_adv_data_cb.Run(BT_STATUS_SUCCESS);
+  set_adv_data_cb.Run(BT_STATUS_FAIL);
+
+  EXPECT_EQ(1, callback_count);
+  EXPECT_EQ(BLE_STATUS_FAILURE, last_status);
+  EXPECT_FALSE(le_advertiser_->IsAdvertisingStarted());
+
+  status_cb enable_cb;
+  EXPECT_CALL(*mock_handler_,
+              MultiAdvEnable(le_advertiser_->GetInstanceId(), true, _, _, _))
+      .Times(1)
+      .WillOnce(SaveArg<2>(&enable_cb));
+
+  // Second time everything succeeds.
+  EXPECT_TRUE(le_advertiser_->StartAdvertising(settings, adv0, adv1, callback));
+  set_params_cb.Run(BT_STATUS_SUCCESS);
+  set_adv_data_cb.Run(BT_STATUS_SUCCESS);
+  set_adv_data_cb.Run(BT_STATUS_SUCCESS);
+  enable_cb.Run(BT_STATUS_SUCCESS);
+
+  EXPECT_EQ(2, callback_count);
+  EXPECT_EQ(BLE_STATUS_SUCCESS, last_status);
+  EXPECT_TRUE(le_advertiser_->IsAdvertisingStarted());
+}
+
+TEST_F(LowEnergyAdvertiserPostRegisterTest, AdvertiseDataParsing) {
+  const std::vector<uint8_t> kUUID16BitData{
+    0x03, HCI_EIR_COMPLETE_16BITS_UUID_TYPE, 0xDE, 0xAD,
+  };
+
+  const std::vector<uint8_t> kUUID32BitData{
+    0x05, HCI_EIR_COMPLETE_32BITS_UUID_TYPE, 0xDE, 0xAD, 0x01, 0x02
+  };
+
+  const std::vector<uint8_t> kUUID128BitData{
+    0x11, HCI_EIR_COMPLETE_128BITS_UUID_TYPE,
+    0xDE, 0xAD, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+    0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E
+  };
+
+  const std::vector<uint8_t> kMultiUUIDData{
+    0x11, HCI_EIR_COMPLETE_128BITS_UUID_TYPE,
+    0xDE, 0xAD, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+    0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
+    0x05, HCI_EIR_COMPLETE_32BITS_UUID_TYPE, 0xDE, 0xAD, 0xBE, 0xEF
+  };
+
+  const std::vector<uint8_t> kServiceData16Bit{
+    0x05, HCI_EIR_SERVICE_DATA_16BITS_UUID_TYPE, 0xDE, 0xAD, 0xBE, 0xEF
+  };
+
+  const std::vector<uint8_t> kServiceData32Bit{
+    0x07, HCI_EIR_SERVICE_DATA_32BITS_UUID_TYPE, 0xDE, 0xAD, 0x01, 0x02, 0xBE, 0xEF
+  };
+
+  const std::vector<uint8_t> kServiceData128Bit{
+    0x13, HCI_EIR_SERVICE_DATA_128BITS_UUID_TYPE,
+    0xDE, 0xAD, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+    0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0xBE, 0xEF
+  };
+
+  const std::vector<uint8_t> kMultiServiceData{
+    0x13, HCI_EIR_SERVICE_DATA_128BITS_UUID_TYPE,
+    0xDE, 0xAD, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xBE, 0xEF,
+    0xDE, 0xAD, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+    0x05, HCI_EIR_SERVICE_DATA_16BITS_UUID_TYPE, 0xDE, 0xAD, 0xBE, 0xEF
+  };
+
+  const std::vector<uint8_t> kServiceUUIDMatch{
+    0x05, HCI_EIR_COMPLETE_32BITS_UUID_TYPE, 0xDE, 0xAD, 0x01, 0x02,
+    0x07, HCI_EIR_SERVICE_DATA_32BITS_UUID_TYPE, 0xDE, 0xAD, 0x01, 0x02, 0xBE, 0xEF
+  };
+
+  const std::vector<uint8_t> kServiceUUIDMismatch{
+    0x05, HCI_EIR_COMPLETE_32BITS_UUID_TYPE, 0xDE, 0xAD, 0x01, 0x01,
+    0x07, HCI_EIR_SERVICE_DATA_32BITS_UUID_TYPE, 0xDE, 0xAD, 0x01, 0x02, 0xBE, 0xEF
+  };
+
+  AdvertiseData uuid_16bit_adv(kUUID16BitData);
+  AdvertiseData uuid_32bit_adv(kUUID32BitData);
+  AdvertiseData uuid_128bit_adv(kUUID128BitData);
+  AdvertiseData multi_uuid_adv(kMultiUUIDData);
+
+  AdvertiseData service_16bit_adv(kServiceData16Bit);
+  AdvertiseData service_32bit_adv(kServiceData32Bit);
+  AdvertiseData service_128bit_adv(kServiceData128Bit);
+  AdvertiseData multi_service_adv(kMultiServiceData);
+
+  AdvertiseData service_uuid_match(kServiceUUIDMatch);
+  AdvertiseData service_uuid_mismatch(kServiceUUIDMismatch);
+
+  AdvertiseSettings settings;
+
+  int callback_count = 0;
+  BLEStatus last_status = BLE_STATUS_FAILURE;
+  auto callback = [&](BLEStatus status) {
+    last_status = status;
+    callback_count++;
+  };
+
+  status_cb set_data_cb;
+  // Multiple UUID test
+  EXPECT_CALL(*mock_handler_, MultiAdvSetInstData(_, _, _, _))
+            .Times(1)
+      .WillOnce(SaveArg<3>(&set_data_cb));
+  AdvertiseDataTestHelper(multi_uuid_adv, callback, &set_data_cb);
+  EXPECT_EQ(1, callback_count);
+  ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+  // Multiple Service Data test
+  EXPECT_CALL(*mock_handler_, MultiAdvSetInstData(_, _, _, _))
+            .Times(1)
+      .WillOnce(SaveArg<3>(&set_data_cb));
+  AdvertiseDataTestHelper(multi_service_adv, callback, &set_data_cb);
+  EXPECT_EQ(2, callback_count);
+  ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+  // 16bit uuid test, should succeed with correctly parsed uuid in little-endian
+  // 128-bit format.
+  const std::vector<uint8_t> uuid_16bit_canonical{
+      0xFB, 0x34, 0x9b, 0x5F, 0x80, 0x00, 0x00, 0x80,
+      0x00, 0x10, 0x00, 0x00, 0xDE, 0xAD, 0x00, 0x00};
+  EXPECT_CALL(*mock_handler_,
+              MultiAdvSetInstData(_, _, _, _))
+      .Times(1)
+      .WillOnce(SaveArg<3>(&set_data_cb));
+  AdvertiseDataTestHelper(uuid_16bit_adv, callback, &set_data_cb);
+  EXPECT_EQ(3, callback_count);
+  ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+  // 32bit uuid test, should succeed with correctly parsed uuid
+  const std::vector<uint8_t> uuid_32bit_canonical{
+    0xFB, 0x34, 0x9b, 0x5F, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00,
+    0xDE, 0xAD, 0x01, 0x02
+  };
+  EXPECT_CALL(*mock_handler_,
+              MultiAdvSetInstData(_, _, _, _))
+      .Times(1)
+      .WillOnce(SaveArg<3>(&set_data_cb));
+  AdvertiseDataTestHelper(uuid_32bit_adv, callback, &set_data_cb);
+  EXPECT_EQ(4, callback_count);
+  ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+  // 128bit uuid test, should succeed with correctly parsed uuid
+  const std::vector<uint8_t> uuid_128bit{
+    0xDE, 0xAD, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+    0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E
+  };
+  EXPECT_CALL(*mock_handler_,
+              MultiAdvSetInstData(_, _, _, _))
+      .Times(1)
+      .WillOnce(SaveArg<3>(&set_data_cb));
+  AdvertiseDataTestHelper(uuid_128bit_adv, callback, &set_data_cb);
+  EXPECT_EQ(5, callback_count);
+  ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+  const std::vector<uint8_t> service_data{0xBE, 0xEF};
+
+  // Service data with 16bit uuid included, should succeed with
+  // uuid and service data parsed out
+  EXPECT_CALL(*mock_handler_,
+              MultiAdvSetInstData(_, _, _, _))
+      .Times(1)
+      .WillOnce(SaveArg<3>(&set_data_cb));
+  AdvertiseDataTestHelper(service_16bit_adv, callback, &set_data_cb);
+  EXPECT_EQ(6, callback_count);
+  ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+  // Service data with 32bit uuid included, should succeed with
+  // uuid and service data parsed out
+  EXPECT_CALL(*mock_handler_,
+              MultiAdvSetInstData(_, _, _, _))
+      .Times(1)
+      .WillOnce(SaveArg<3>(&set_data_cb));
+  AdvertiseDataTestHelper(service_32bit_adv, callback, &set_data_cb);
+  EXPECT_EQ(7, callback_count);
+  ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+  // Service data with 128bit uuid included, should succeed with
+  // uuid and service data parsed out
+  EXPECT_CALL(*mock_handler_, MultiAdvSetInstData(_, _, _, _))
+      .Times(1)
+      .WillOnce(SaveArg<3>(&set_data_cb));
+  AdvertiseDataTestHelper(service_128bit_adv, callback, &set_data_cb);
+  EXPECT_EQ(8, callback_count);
+  ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+  // Service data and UUID where the UUID for both match, should succeed.
+  EXPECT_CALL(*mock_handler_, MultiAdvSetInstData(_, _, _, _))
+      .Times(1)
+      .WillOnce(SaveArg<3>(&set_data_cb));
+  AdvertiseDataTestHelper(service_uuid_match, callback, &set_data_cb);
+  EXPECT_EQ(9, callback_count);
+  ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+  // Service data and UUID where the UUID for dont match, should fail
+  EXPECT_CALL(*mock_handler_, MultiAdvSetInstData(_, _, _, _))
+      .Times(1)
+      .WillOnce(SaveArg<3>(&set_data_cb));
+  AdvertiseDataTestHelper(service_uuid_match, callback, &set_data_cb);
+  EXPECT_EQ(10, callback_count);
+  ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+}
+
+MATCHER_P(BitEq, x, std::string(negation ? "isn't" : "is") +
+                        " bitwise equal to " + ::testing::PrintToString(x)) {
+  static_assert(sizeof(x) == sizeof(arg), "Size mismatch");
+  return std::memcmp(&arg, &x, sizeof(x)) == 0;
+}
+
+
+}  // namespace
+}  // namespace bluetooth
diff --git a/bt/service/test/low_energy_client_unittest.cc b/bt/service/test/low_energy_client_unittest.cc
new file mode 100644
index 0000000..1fc2393
--- /dev/null
+++ b/bt/service/test/low_energy_client_unittest.cc
@@ -0,0 +1,312 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 <base/macros.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "service/adapter.h"
+#include "service/hal/fake_bluetooth_gatt_interface.h"
+#include "service/low_energy_client.h"
+#include "stack/include/bt_types.h"
+#include "stack/include/hcidefs.h"
+#include "test/mock_adapter.h"
+
+using ::testing::_;
+using ::testing::Return;
+using ::testing::Pointee;
+using ::testing::DoAll;
+using ::testing::Invoke;
+
+namespace bluetooth {
+namespace {
+
+class MockGattHandler
+    : public hal::FakeBluetoothGattInterface::TestClientHandler {
+ public:
+  MockGattHandler() {};
+  ~MockGattHandler() override = default;
+
+  MOCK_METHOD1(RegisterClient, bt_status_t(bt_uuid_t*));
+  MOCK_METHOD1(UnregisterClient, bt_status_t(int));
+  MOCK_METHOD4(Connect, bt_status_t(int , const bt_bdaddr_t *, bool, int));
+  MOCK_METHOD3(Disconnect, bt_status_t(int , const bt_bdaddr_t *, int));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockGattHandler);
+};
+
+class TestDelegate : public LowEnergyClient::Delegate {
+ public:
+  TestDelegate() : connection_state_count_(0), last_mtu_(0) {
+  }
+
+  ~TestDelegate() override = default;
+
+  int connection_state_count() const { return connection_state_count_; }
+
+  void OnConnectionState(LowEnergyClient* client, int status,
+                         const char* address, bool connected)  {
+    ASSERT_TRUE(client);
+    connection_state_count_++;
+  }
+
+  void OnMtuChanged(LowEnergyClient* client, int status, const char* address,
+                    int mtu) {
+    ASSERT_TRUE(client);
+    last_mtu_ = mtu;
+  }
+
+ private:
+  int connection_state_count_;
+
+  int last_mtu_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestDelegate);
+};
+
+class LowEnergyClientTest : public ::testing::Test {
+ public:
+  LowEnergyClientTest() = default;
+  ~LowEnergyClientTest() override = default;
+
+  void SetUp() override {
+    // Only set |mock_handler_| if a test hasn't set it.
+    if (!mock_handler_)
+        mock_handler_.reset(new MockGattHandler());
+    fake_hal_gatt_iface_ = new hal::FakeBluetoothGattInterface(
+        nullptr,
+        nullptr,
+        std::static_pointer_cast<
+            hal::FakeBluetoothGattInterface::TestClientHandler>(mock_handler_),
+        nullptr);
+    hal::BluetoothGattInterface::InitializeForTesting(fake_hal_gatt_iface_);
+    ble_factory_.reset(new LowEnergyClientFactory(mock_adapter_));
+  }
+
+  void TearDown() override {
+    ble_factory_.reset();
+    hal::BluetoothGattInterface::CleanUp();
+  }
+
+ protected:
+  hal::FakeBluetoothGattInterface* fake_hal_gatt_iface_;
+  testing::MockAdapter mock_adapter_;
+  std::shared_ptr<MockGattHandler> mock_handler_;
+  std::unique_ptr<LowEnergyClientFactory> ble_factory_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LowEnergyClientTest);
+};
+
+// Used for tests that operate on a pre-registered client.
+class LowEnergyClientPostRegisterTest : public LowEnergyClientTest {
+ public:
+  LowEnergyClientPostRegisterTest() : next_client_id_(0) {
+  }
+  ~LowEnergyClientPostRegisterTest() override = default;
+
+  void SetUp() override {
+    LowEnergyClientTest::SetUp();
+    auto callback = [&](std::unique_ptr<LowEnergyClient> client) {
+      le_client_ = std::move(client);
+    };
+    RegisterTestClient(callback);
+  }
+
+  void TearDown() override {
+    EXPECT_CALL(*mock_handler_, UnregisterClient(_))
+        .Times(1)
+        .WillOnce(Return(BT_STATUS_SUCCESS));
+    le_client_.reset();
+    LowEnergyClientTest::TearDown();
+  }
+
+  void RegisterTestClient(
+      const std::function<void(std::unique_ptr<LowEnergyClient> client)>
+          callback) {
+    UUID uuid = UUID::GetRandom();
+    auto api_callback = [&](BLEStatus status, const UUID& in_uuid,
+                        std::unique_ptr<BluetoothInstance> in_client) {
+      CHECK(in_uuid == uuid);
+      CHECK(in_client.get());
+      CHECK(status == BLE_STATUS_SUCCESS);
+
+      callback(std::unique_ptr<LowEnergyClient>(
+          static_cast<LowEnergyClient*>(in_client.release())));
+    };
+
+    EXPECT_CALL(*mock_handler_, RegisterClient(_))
+        .Times(1)
+        .WillOnce(Return(BT_STATUS_SUCCESS));
+
+    ble_factory_->RegisterInstance(uuid, api_callback);
+
+    bt_uuid_t hal_uuid = uuid.GetBlueDroid();
+    fake_hal_gatt_iface_->NotifyRegisterClientCallback(
+        0, next_client_id_++, hal_uuid);
+    ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+  }
+
+ protected:
+  std::unique_ptr<LowEnergyClient> le_client_;
+
+ private:
+  int next_client_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(LowEnergyClientPostRegisterTest);
+};
+
+TEST_F(LowEnergyClientTest, RegisterInstance) {
+  EXPECT_CALL(*mock_handler_, RegisterClient(_))
+      .Times(2)
+      .WillOnce(Return(BT_STATUS_FAIL))
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+
+  // These will be asynchronously populated with a result when the callback
+  // executes.
+  BLEStatus status = BLE_STATUS_SUCCESS;
+  UUID cb_uuid;
+  std::unique_ptr<LowEnergyClient> client;
+  int callback_count = 0;
+
+  auto callback = [&](BLEStatus in_status, const UUID& uuid,
+                      std::unique_ptr<BluetoothInstance> in_client) {
+        status = in_status;
+        cb_uuid = uuid;
+        client = std::unique_ptr<LowEnergyClient>(
+            static_cast<LowEnergyClient*>(in_client.release()));
+        callback_count++;
+      };
+
+  UUID uuid0 = UUID::GetRandom();
+
+  // HAL returns failure.
+  EXPECT_FALSE(ble_factory_->RegisterInstance(uuid0, callback));
+  EXPECT_EQ(0, callback_count);
+
+  // HAL returns success.
+  EXPECT_TRUE(ble_factory_->RegisterInstance(uuid0, callback));
+  EXPECT_EQ(0, callback_count);
+
+  // Calling twice with the same UUID should fail with no additional call into
+  // the stack.
+  EXPECT_FALSE(ble_factory_->RegisterInstance(uuid0, callback));
+
+  ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+  // Call with a different UUID while one is pending.
+  UUID uuid1 = UUID::GetRandom();
+  EXPECT_CALL(*mock_handler_, RegisterClient(_))
+      .Times(1)
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+  EXPECT_TRUE(ble_factory_->RegisterInstance(uuid1, callback));
+
+  // Trigger callback with an unknown UUID. This should get ignored.
+  UUID uuid2 = UUID::GetRandom();
+  bt_uuid_t hal_uuid = uuid2.GetBlueDroid();
+  fake_hal_gatt_iface_->NotifyRegisterClientCallback(0, 0, hal_uuid);
+  EXPECT_EQ(0, callback_count);
+
+  // |uuid0| succeeds.
+  int client_if0 = 2;  // Pick something that's not 0.
+  hal_uuid = uuid0.GetBlueDroid();
+  fake_hal_gatt_iface_->NotifyRegisterClientCallback(
+      BT_STATUS_SUCCESS, client_if0, hal_uuid);
+
+  EXPECT_EQ(1, callback_count);
+  ASSERT_TRUE(client.get() != nullptr);  // Assert to terminate in case of error
+  EXPECT_EQ(BLE_STATUS_SUCCESS, status);
+  EXPECT_EQ(client_if0, client->GetInstanceId());
+  EXPECT_EQ(uuid0, client->GetAppIdentifier());
+  EXPECT_EQ(uuid0, cb_uuid);
+
+  // The client should unregister itself when deleted.
+  EXPECT_CALL(*mock_handler_, UnregisterClient(client_if0))
+      .Times(1)
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+  client.reset();
+  ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+  // |uuid1| fails.
+  int client_if1 = 3;
+  hal_uuid = uuid1.GetBlueDroid();
+  fake_hal_gatt_iface_->NotifyRegisterClientCallback(
+      BT_STATUS_FAIL, client_if1, hal_uuid);
+
+  EXPECT_EQ(2, callback_count);
+  ASSERT_TRUE(client.get() == nullptr);  // Assert to terminate in case of error
+  EXPECT_EQ(BLE_STATUS_FAILURE, status);
+  EXPECT_EQ(uuid1, cb_uuid);
+}
+
+MATCHER_P(BitEq, x, std::string(negation ? "isn't" : "is") +
+                        " bitwise equal to " + ::testing::PrintToString(x)) {
+  static_assert(sizeof(x) == sizeof(arg), "Size mismatch");
+  return std::memcmp(&arg, &x, sizeof(x)) == 0;
+}
+
+TEST_F(LowEnergyClientPostRegisterTest, Connect) {
+  const bt_bdaddr_t kTestAddress = {
+    { 0x01, 0x02, 0x03, 0x0A, 0x0B, 0x0C }
+  };
+  const char kTestAddressStr[] = "01:02:03:0A:0B:0C";
+  const bool kTestDirect = false;
+  const int connId = 12;
+
+  TestDelegate delegate;
+  le_client_->SetDelegate(&delegate);
+
+  // TODO(jpawlowski): NotifyConnectCallback should be called after returning
+  // success, fix it when it becomes important.
+  // These should succeed and result in a HAL call
+  EXPECT_CALL(*mock_handler_, Connect(le_client_->GetInstanceId(),
+          Pointee(BitEq(kTestAddress)), kTestDirect, BT_TRANSPORT_LE))
+      .Times(1)
+      .WillOnce(DoAll(
+        Invoke([&](int client_id, const bt_bdaddr_t *bd_addr, bool is_direct,
+                   int transport){
+          fake_hal_gatt_iface_->NotifyConnectCallback(connId, BT_STATUS_SUCCESS,
+                                                      client_id, *bd_addr);
+        }),
+        Return(BT_STATUS_SUCCESS)));
+
+  EXPECT_TRUE(le_client_->Connect(kTestAddressStr, kTestDirect));
+  EXPECT_EQ(1, delegate.connection_state_count());
+
+  // TODO(jpawlowski): same as above
+  // These should succeed and result in a HAL call
+  EXPECT_CALL(*mock_handler_, Disconnect(le_client_->GetInstanceId(),
+        Pointee(BitEq(kTestAddress)), connId))
+      .Times(1)
+      .WillOnce(DoAll(
+        Invoke([&](int client_id, const bt_bdaddr_t *bd_addr, int connId){
+          fake_hal_gatt_iface_->NotifyDisconnectCallback(connId,
+                                                         BT_STATUS_SUCCESS,
+                                                         client_id, *bd_addr);
+        }),
+        Return(BT_STATUS_SUCCESS)));
+
+  EXPECT_TRUE(le_client_->Disconnect(kTestAddressStr));
+  EXPECT_EQ(2, delegate.connection_state_count());
+
+  le_client_->SetDelegate(nullptr);
+  ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+}
+
+
+}  // namespace
+}  // namespace bluetooth
diff --git a/bt/service/test/low_energy_scanner_unittest.cc b/bt/service/test/low_energy_scanner_unittest.cc
new file mode 100644
index 0000000..f966a14
--- /dev/null
+++ b/bt/service/test/low_energy_scanner_unittest.cc
@@ -0,0 +1,346 @@
+//
+//  Copyright (C) 2016 The Android Open Source Project
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+
+#include <base/macros.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "service/adapter.h"
+#include "service/hal/fake_bluetooth_gatt_interface.h"
+#include "service/low_energy_scanner.h"
+#include "stack/include/bt_types.h"
+#include "stack/include/hcidefs.h"
+#include "test/mock_adapter.h"
+
+using ::testing::_;
+using ::testing::Return;
+using ::testing::Pointee;
+using ::testing::DoAll;
+using ::testing::Invoke;
+
+namespace bluetooth {
+namespace {
+
+class MockGattHandler
+    : public hal::FakeBluetoothGattInterface::TestScannerHandler {
+ public:
+  MockGattHandler() {
+    ON_CALL(*this, Scan(false))
+        .WillByDefault(Return(BT_STATUS_SUCCESS));
+  }
+  ~MockGattHandler() override = default;
+
+  MOCK_METHOD1(RegisterScanner, bt_status_t(bt_uuid_t*));
+  MOCK_METHOD1(UnregisterScanner, bt_status_t(int));
+  MOCK_METHOD1(Scan, bt_status_t(bool));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockGattHandler);
+};
+
+class TestDelegate : public LowEnergyScanner::Delegate {
+ public:
+  TestDelegate() : scan_result_count_(0) {
+  }
+
+  ~TestDelegate() override = default;
+
+  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) {
+    ASSERT_TRUE(scanner);
+    scan_result_count_++;
+    last_scan_result_ = scan_result;
+  }
+
+ private:
+  int scan_result_count_;
+  ScanResult last_scan_result_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestDelegate);
+};
+
+class LowEnergyScannerTest : public ::testing::Test {
+ public:
+  LowEnergyScannerTest() = default;
+  ~LowEnergyScannerTest() override = default;
+
+  void SetUp() override {
+    // Only set |mock_handler_| if a test hasn't set it.
+    if (!mock_handler_)
+        mock_handler_.reset(new MockGattHandler());
+    fake_hal_gatt_iface_ = new hal::FakeBluetoothGattInterface(
+        nullptr,
+        std::static_pointer_cast<
+            hal::FakeBluetoothGattInterface::TestScannerHandler>(mock_handler_),
+        nullptr,
+        nullptr);
+    hal::BluetoothGattInterface::InitializeForTesting(fake_hal_gatt_iface_);
+    ble_factory_.reset(new LowEnergyScannerFactory(mock_adapter_));
+  }
+
+  void TearDown() override {
+    ble_factory_.reset();
+    hal::BluetoothGattInterface::CleanUp();
+  }
+
+ protected:
+  hal::FakeBluetoothGattInterface* fake_hal_gatt_iface_;
+  testing::MockAdapter mock_adapter_;
+  std::shared_ptr<MockGattHandler> mock_handler_;
+  std::unique_ptr<LowEnergyScannerFactory> ble_factory_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LowEnergyScannerTest);
+};
+
+// Used for tests that operate on a pre-registered scanner.
+class LowEnergyScannerPostRegisterTest : public LowEnergyScannerTest {
+ public:
+  LowEnergyScannerPostRegisterTest() : next_scanner_id_(0) {
+  }
+  ~LowEnergyScannerPostRegisterTest() override = default;
+
+  void SetUp() override {
+    LowEnergyScannerTest::SetUp();
+    auto callback = [&](std::unique_ptr<LowEnergyScanner> scanner) {
+      le_scanner_ = std::move(scanner);
+    };
+    RegisterTestScanner(callback);
+  }
+
+  void TearDown() override {
+    EXPECT_CALL(*mock_handler_, UnregisterScanner(_))
+        .Times(1)
+        .WillOnce(Return(BT_STATUS_SUCCESS));
+    le_scanner_.reset();
+    LowEnergyScannerTest::TearDown();
+  }
+
+  void RegisterTestScanner(
+      const std::function<void(std::unique_ptr<LowEnergyScanner> scanner)>
+          callback) {
+    UUID uuid = UUID::GetRandom();
+    auto api_callback = [&](BLEStatus status, const UUID& in_uuid,
+                        std::unique_ptr<BluetoothInstance> in_scanner) {
+      CHECK(in_uuid == uuid);
+      CHECK(in_scanner.get());
+      CHECK(status == BLE_STATUS_SUCCESS);
+
+      callback(std::unique_ptr<LowEnergyScanner>(
+          static_cast<LowEnergyScanner*>(in_scanner.release())));
+    };
+
+    EXPECT_CALL(*mock_handler_, RegisterScanner(_))
+        .Times(1)
+        .WillOnce(Return(BT_STATUS_SUCCESS));
+
+    ble_factory_->RegisterInstance(uuid, api_callback);
+
+    bt_uuid_t hal_uuid = uuid.GetBlueDroid();
+    fake_hal_gatt_iface_->NotifyRegisterScannerCallback(
+        0, next_scanner_id_++, hal_uuid);
+    ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+  }
+
+ protected:
+  std::unique_ptr<LowEnergyScanner> le_scanner_;
+
+ private:
+  int next_scanner_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(LowEnergyScannerPostRegisterTest);
+};
+
+TEST_F(LowEnergyScannerTest, RegisterInstance) {
+  EXPECT_CALL(*mock_handler_, RegisterScanner(_))
+      .Times(2)
+      .WillOnce(Return(BT_STATUS_FAIL))
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+
+  // These will be asynchronously populated with a result when the callback
+  // executes.
+  BLEStatus status = BLE_STATUS_SUCCESS;
+  UUID cb_uuid;
+  std::unique_ptr<LowEnergyScanner> scanner;
+  int callback_count = 0;
+
+  auto callback = [&](BLEStatus in_status, const UUID& uuid,
+                      std::unique_ptr<BluetoothInstance> in_scanner) {
+        status = in_status;
+        cb_uuid = uuid;
+        scanner = std::unique_ptr<LowEnergyScanner>(
+            static_cast<LowEnergyScanner*>(in_scanner.release()));
+        callback_count++;
+      };
+
+  UUID uuid0 = UUID::GetRandom();
+
+  // HAL returns failure.
+  EXPECT_FALSE(ble_factory_->RegisterInstance(uuid0, callback));
+  EXPECT_EQ(0, callback_count);
+
+  // HAL returns success.
+  EXPECT_TRUE(ble_factory_->RegisterInstance(uuid0, callback));
+  EXPECT_EQ(0, callback_count);
+
+  // Calling twice with the same UUID should fail with no additional call into
+  // the stack.
+  EXPECT_FALSE(ble_factory_->RegisterInstance(uuid0, callback));
+
+  ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+  // Call with a different UUID while one is pending.
+  UUID uuid1 = UUID::GetRandom();
+  EXPECT_CALL(*mock_handler_, RegisterScanner(_))
+      .Times(1)
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+  EXPECT_TRUE(ble_factory_->RegisterInstance(uuid1, callback));
+
+  // Trigger callback with an unknown UUID. This should get ignored.
+  UUID uuid2 = UUID::GetRandom();
+  bt_uuid_t hal_uuid = uuid2.GetBlueDroid();
+  fake_hal_gatt_iface_->NotifyRegisterScannerCallback(0, 0, hal_uuid);
+  EXPECT_EQ(0, callback_count);
+
+  // |uuid0| succeeds.
+  int scanner_if0 = 2;  // Pick something that's not 0.
+  hal_uuid = uuid0.GetBlueDroid();
+  fake_hal_gatt_iface_->NotifyRegisterScannerCallback(
+      BT_STATUS_SUCCESS, scanner_if0, hal_uuid);
+
+  EXPECT_EQ(1, callback_count);
+  ASSERT_TRUE(scanner.get() != nullptr);  // Assert to terminate in case of error
+  EXPECT_EQ(BLE_STATUS_SUCCESS, status);
+  EXPECT_EQ(scanner_if0, scanner->GetInstanceId());
+  EXPECT_EQ(uuid0, scanner->GetAppIdentifier());
+  EXPECT_EQ(uuid0, cb_uuid);
+
+  // The scanner should unregister itself when deleted.
+  EXPECT_CALL(*mock_handler_, UnregisterScanner(scanner_if0))
+      .Times(1)
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+  scanner.reset();
+  ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+  // |uuid1| fails.
+  int scanner_if1 = 3;
+  hal_uuid = uuid1.GetBlueDroid();
+  fake_hal_gatt_iface_->NotifyRegisterScannerCallback(
+      BT_STATUS_FAIL, scanner_if1, hal_uuid);
+
+  EXPECT_EQ(2, callback_count);
+  ASSERT_TRUE(scanner.get() == nullptr);  // Assert to terminate in case of error
+  EXPECT_EQ(BLE_STATUS_FAILURE, status);
+  EXPECT_EQ(uuid1, cb_uuid);
+}
+
+TEST_F(LowEnergyScannerPostRegisterTest, ScanSettings) {
+  EXPECT_CALL(mock_adapter_, IsEnabled())
+      .WillOnce(Return(false))
+      .WillRepeatedly(Return(true));
+
+  ScanSettings settings;
+  std::vector<ScanFilter> filters;
+
+  // Adapter is not enabled.
+  EXPECT_FALSE(le_scanner_->StartScan(settings, filters));
+
+  // TODO(jpawlowski): add tests checking settings and filter parsing when
+  // implemented
+
+  // These should succeed and result in a HAL call
+  EXPECT_CALL(*mock_handler_, Scan(true))
+      .Times(1)
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+  EXPECT_TRUE(le_scanner_->StartScan(settings, filters));
+
+  // These should succeed and result in a HAL call
+  EXPECT_CALL(*mock_handler_, Scan(false))
+      .Times(1)
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+  EXPECT_TRUE(le_scanner_->StopScan());
+
+  ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+}
+
+TEST_F(LowEnergyScannerPostRegisterTest, ScanRecord) {
+  TestDelegate delegate;
+  le_scanner_->SetDelegate(&delegate);
+
+  EXPECT_EQ(0, delegate.scan_result_count());
+
+  vector<uint8_t> kTestRecord0({ 0x02, 0x01, 0x00, 0x00 });
+  vector<uint8_t> kTestRecord1({ 0x00 });
+  vector<uint8_t> kTestRecord2({
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+    0x01, 0x00
+  });
+  const bt_bdaddr_t kTestAddress = {
+    { 0x01, 0x02, 0x03, 0x0A, 0x0B, 0x0C }
+  };
+  const char kTestAddressStr[] = "01:02:03:0A:0B:0C";
+  const int kTestRssi = 64;
+
+  // Scan wasn't started. Result should be ignored.
+  fake_hal_gatt_iface_->NotifyScanResultCallback(
+      kTestAddress, kTestRssi, kTestRecord0);
+  EXPECT_EQ(0, delegate.scan_result_count());
+
+  // Start a scan session for |le_scanner_|.
+  EXPECT_CALL(mock_adapter_, IsEnabled())
+      .Times(1)
+      .WillOnce(Return(true));
+  EXPECT_CALL(*mock_handler_, Scan(_))
+      .Times(2)
+      .WillOnce(Return(BT_STATUS_SUCCESS))
+      .WillOnce(Return(BT_STATUS_SUCCESS));
+  ScanSettings settings;
+  std::vector<ScanFilter> filters;
+  ASSERT_TRUE(le_scanner_->StartScan(settings, filters));
+
+  fake_hal_gatt_iface_->NotifyScanResultCallback(
+      kTestAddress, kTestRssi, kTestRecord0);
+  EXPECT_EQ(1, delegate.scan_result_count());
+  EXPECT_EQ(kTestAddressStr, delegate.last_scan_result().device_address());
+  EXPECT_EQ(kTestRssi, delegate.last_scan_result().rssi());
+  EXPECT_EQ(3U, delegate.last_scan_result().scan_record().size());
+
+  fake_hal_gatt_iface_->NotifyScanResultCallback(
+      kTestAddress, kTestRssi, kTestRecord1);
+  EXPECT_EQ(2, delegate.scan_result_count());
+  EXPECT_EQ(kTestAddressStr, delegate.last_scan_result().device_address());
+  EXPECT_EQ(kTestRssi, delegate.last_scan_result().rssi());
+  EXPECT_TRUE(delegate.last_scan_result().scan_record().empty());
+
+  fake_hal_gatt_iface_->NotifyScanResultCallback(
+      kTestAddress, kTestRssi, kTestRecord2);
+  EXPECT_EQ(3, delegate.scan_result_count());
+  EXPECT_EQ(kTestAddressStr, delegate.last_scan_result().device_address());
+  EXPECT_EQ(kTestRssi, delegate.last_scan_result().rssi());
+  EXPECT_EQ(62U, delegate.last_scan_result().scan_record().size());
+
+  le_scanner_->SetDelegate(nullptr);
+}
+
+
+}  // namespace
+}  // namespace bluetooth
diff --git a/bt/service/test/main.cc b/bt/service/test/main.cc
new file mode 100644
index 0000000..458a83b
--- /dev/null
+++ b/bt/service/test/main.cc
@@ -0,0 +1,36 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+
+#ifdef BT_LIBCHROME_NDEBUG
+#define NDEBUG 1
+#endif
+
+#include <base/at_exit.h>
+#include <base/command_line.h>
+#include <base/logging.h>
+
+#include <gtest/gtest.h>
+
+GTEST_API_ int main(int argc, char **argv) {
+  base::AtExitManager exit_manager;
+  base::CommandLine::Init(argc, argv);
+  logging::LoggingSettings log_settings;
+  logging::InitLogging(log_settings);
+
+  LOG(INFO) << "Running Bluetooth daemon unit tests.";
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/bt/service/test/mock_adapter.h b/bt/service/test/mock_adapter.h
new file mode 100644
index 0000000..1a762fb
--- /dev/null
+++ b/bt/service/test/mock_adapter.h
@@ -0,0 +1,56 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 "service/daemon.h"
+
+namespace bluetooth {
+namespace testing {
+
+class MockAdapter : public Adapter {
+ public:
+  MockAdapter() = default;
+  ~MockAdapter() override = default;
+
+  MOCK_METHOD1(AddObserver, void(Observer*));
+  MOCK_METHOD1(RemoveObserver, void(Observer*));
+  MOCK_CONST_METHOD0(GetState, AdapterState());
+  MOCK_CONST_METHOD0(IsEnabled, bool());
+  MOCK_METHOD1(Enable, bool(bool));
+  MOCK_METHOD0(Disable, bool());
+  MOCK_CONST_METHOD0(GetName, std::string());
+  MOCK_METHOD1(SetName, bool(const std::string&));
+  MOCK_CONST_METHOD0(GetAddress, std::string());
+  MOCK_METHOD0(IsMultiAdvertisementSupported, bool());
+  MOCK_METHOD1(IsDeviceConnected, bool(const std::string&));
+  MOCK_METHOD0(GetTotalNumberOfTrackableAdvertisements, int());
+  MOCK_METHOD0(IsOffloadedFilteringSupported, bool());
+  MOCK_METHOD0(IsOffloadedScanBatchingSupported, bool());
+  MOCK_CONST_METHOD0(GetLowEnergyClientFactory, LowEnergyClientFactory*());
+  MOCK_CONST_METHOD0(GetLeAdvertiserFactory, LowEnergyAdvertiserFactory*());
+  MOCK_CONST_METHOD0(GetLeScannerFactory, LowEnergyScannerFactory*());
+  MOCK_CONST_METHOD0(GetGattClientFactory, GattClientFactory*());
+  MOCK_CONST_METHOD0(GetGattServerFactory, GattServerFactory*());
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockAdapter);
+};
+
+}  // namespace testing
+}  // namespace bluetooth
diff --git a/bt/service/test/mock_daemon.h b/bt/service/test/mock_daemon.h
new file mode 100644
index 0000000..a5dd974
--- /dev/null
+++ b/bt/service/test/mock_daemon.h
@@ -0,0 +1,41 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR 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 "service/daemon.h"
+
+namespace bluetooth {
+namespace testing {
+
+class MockDaemon : public Daemon {
+ public:
+  MockDaemon() = default;
+  ~MockDaemon() override = default;
+
+  MOCK_CONST_METHOD0(GetSettings, Settings*());
+  MOCK_CONST_METHOD0(GetMessageLoop, base::MessageLoop*());
+  MOCK_METHOD0(StartMainLoop, void());
+  MOCK_METHOD0(Init, bool());
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockDaemon);
+};
+
+}  // namespace testing
+}  // namespace bluetooth
diff --git a/bt/service/test/parcelable_unittest.cc b/bt/service/test/parcelable_unittest.cc
new file mode 100644
index 0000000..5b53448
--- /dev/null
+++ b/bt/service/test/parcelable_unittest.cc
@@ -0,0 +1,199 @@
+//
+//  Copyright (C) 2016 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/android/bluetooth/advertise_data.h"
+#include "service/common/android/bluetooth/advertise_settings.h"
+#include "service/common/android/bluetooth/bluetooth_gatt_characteristic.h"
+#include "service/common/android/bluetooth/bluetooth_gatt_descriptor.h"
+#include "service/common/android/bluetooth/bluetooth_gatt_service.h"
+#include "service/common/android/bluetooth/scan_filter.h"
+#include "service/common/android/bluetooth/scan_result.h"
+#include "service/common/android/bluetooth/scan_settings.h"
+#include "service/common/android/bluetooth/uuid.h"
+#include "service/common/bluetooth/low_energy_constants.h"
+
+using android::Parcel;
+
+using bluetooth::AdvertiseData;
+using bluetooth::AdvertiseSettings;
+using bluetooth::Characteristic;
+using bluetooth::Descriptor;
+using bluetooth::ScanFilter;
+using bluetooth::ScanResult;
+using bluetooth::ScanSettings;
+using bluetooth::Service;
+using bluetooth::UUID;
+
+namespace bluetooth {
+namespace {
+
+template <class IN, class OUT>
+bool TestData(IN& in) {
+  Parcel parcel;
+
+  parcel.writeParcelable((OUT)in);
+  parcel.setDataPosition(0);
+  OUT out;
+  parcel.readParcelable(&out);
+  //in case of error this display nice log message
+  EXPECT_EQ(out, in);
+  return in == out;
+}
+
+TEST(ParcelableTest, NonEmptyAdvertiseData) {
+  std::vector<uint8_t> data{0x02, 0x02, 0x00};
+  AdvertiseData adv0(data);
+  bool result = TestData<AdvertiseData, android::bluetooth::AdvertiseData>(adv0);
+  EXPECT_TRUE(result);
+}
+
+TEST(ParcelableTest, DefaultAdvertiseSettings) {
+  AdvertiseSettings settings;
+  bool result =
+      TestData<AdvertiseSettings, android::bluetooth::AdvertiseSettings>(
+          settings);
+  EXPECT_TRUE(result);
+}
+
+TEST(ParcelableTest, NonEmptyAdvertiseSettings) {
+  AdvertiseSettings settings(
+      AdvertiseSettings::MODE_BALANCED, base::TimeDelta::FromMilliseconds(150),
+      AdvertiseSettings::TX_POWER_LEVEL_HIGH, false /* connectable */);
+
+  bool result =
+      TestData<AdvertiseSettings, android::bluetooth::AdvertiseSettings>(
+          settings);
+  EXPECT_TRUE(result);
+}
+
+TEST(ParcelableTest, UUID) {
+  // Try a whole bunch of UUIDs.
+  for (int i = 0; i < 10; i++) {
+    UUID uuid = UUID::GetRandom();
+    TestData<UUID, android::bluetooth::UUID>(uuid);
+  }
+}
+
+TEST(ParcelableTest, ScanSettings) {
+  ScanSettings settings0;
+  ScanSettings settings1(
+      ScanSettings::MODE_BALANCED, ScanSettings::CALLBACK_TYPE_FIRST_MATCH,
+      ScanSettings::RESULT_TYPE_ABBREVIATED,
+      base::TimeDelta::FromMilliseconds(150), ScanSettings::MATCH_MODE_STICKY,
+      ScanSettings::MATCH_COUNT_FEW_ADVERTISEMENTS);
+
+  bool result =
+      TestData<ScanSettings, android::bluetooth::ScanSettings>(settings0);
+  EXPECT_TRUE(result);
+
+  result = TestData<ScanSettings, android::bluetooth::ScanSettings>(settings0);
+  EXPECT_TRUE(result);
+}
+
+TEST(ParcelableTest, ScanFilter) {
+  ScanFilter filter;
+
+  filter.set_device_name("Test Device Name");
+  ASSERT_TRUE(filter.SetDeviceAddress("01:02:04:AB:CD:EF"));
+
+  bool result = TestData<ScanFilter, android::bluetooth::ScanFilter>(filter);
+  EXPECT_TRUE(result);
+
+  UUID uuid = UUID::GetRandom();
+  filter.SetServiceUuid(uuid);
+
+  result = TestData<ScanFilter, android::bluetooth::ScanFilter>(filter);
+  EXPECT_TRUE(result);
+
+  UUID mask = UUID::GetRandom();
+  filter.SetServiceUuidWithMask(uuid, mask);
+  result = TestData<ScanFilter, android::bluetooth::ScanFilter>(filter);
+  EXPECT_TRUE(result);
+}
+
+TEST(ParcelableTest, ScanResult) {
+  const char kTestAddress[] = "01:02:03:AB:CD:EF";
+
+  const std::vector<uint8_t> kEmptyBytes;
+  const std::vector<uint8_t> kTestBytes{0x01, 0x02, 0x03};
+
+  const int kTestRssi = 127;
+
+  ScanResult result0(kTestAddress, kEmptyBytes, kTestRssi);
+  ScanResult result1(kTestAddress, kTestBytes, kTestRssi);
+
+  bool result = TestData<ScanResult, android::bluetooth::ScanResult>(result0);
+  EXPECT_TRUE(result);
+
+  result = TestData<ScanResult, android::bluetooth::ScanResult>(result1);
+  EXPECT_TRUE(result);
+}
+
+TEST(ParcelableTest, GattDescriptor) {
+  Descriptor s = Descriptor(0x0000, UUID::GetRandom(), bluetooth::kAttributePermissionRead);
+  Descriptor s2 = Descriptor(0xFFFE, UUID::GetRandom(), bluetooth::kAttributePermissionWrite);
+  Descriptor s3 = Descriptor(0x003D, UUID::GetRandom(),
+      bluetooth::kAttributePermissionReadEncryptedMITM | bluetooth::kAttributePermissionRead);
+
+  bool result = TestData<Descriptor, android::bluetooth::BluetoothGattDescriptor>(s);
+  EXPECT_TRUE(result);
+
+  result = TestData<Descriptor, android::bluetooth::BluetoothGattDescriptor>(s2);
+  EXPECT_TRUE(result);
+
+  result = TestData<Descriptor, android::bluetooth::BluetoothGattDescriptor>(s3);
+  EXPECT_TRUE(result);
+}
+
+TEST(ParcelableTest, GattCharacteristic) {
+  Characteristic c = Characteristic(0x0004, UUID::GetRandom(), 0, 0,
+    {Descriptor(0x0005, UUID::GetRandom(), 0),
+     Descriptor(0x0007, UUID::GetRandom(), 0),
+     Descriptor(0x00A1, UUID::GetRandom(), 0)});
+
+  bool result = TestData<Characteristic, android::bluetooth::BluetoothGattCharacteristic>(c);
+  EXPECT_TRUE(result);
+}
+
+TEST(ParcelableTest, GattService) {
+  Service s = Service(0x0001, true, UUID("CAFE"),
+    {Characteristic(0x0004, UUID::GetRandom(),bluetooth::kCharacteristicPropertyNotify,
+                                              bluetooth::kAttributePermissionRead,
+      {Descriptor(0x0005, UUID::GetRandom(), 0),
+       Descriptor(0x0007, UUID::GetRandom(), 0),
+       Descriptor(0x0009, UUID::GetRandom(), 0)}),
+     Characteristic(0x000D, UUID::GetRandom(), bluetooth::kCharacteristicPropertyWrite,
+                                               bluetooth::kAttributePermissionWrite,
+      {Descriptor(0x0010, UUID::GetRandom(), 0),
+       Descriptor(0x0012, UUID::GetRandom(), 0)}),
+     Characteristic(0x0015, UUID::GetRandom(), 0, 0, {})
+       }, {});
+
+ Parcel parcel;
+
+  parcel.writeParcelable((android::bluetooth::BluetoothGattService)s);
+  parcel.setDataPosition(0);
+  android::bluetooth::BluetoothGattService out;
+  parcel.readParcelable(&out);
+
+  bool result = TestData<Service, android::bluetooth::BluetoothGattService>(s);
+  EXPECT_TRUE(result);
+}
+
+}  // namespace
+}  // namespace bluetooth
diff --git a/bt/service/test/settings_unittest.cc b/bt/service/test/settings_unittest.cc
new file mode 100644
index 0000000..52145a8
--- /dev/null
+++ b/bt/service/test/settings_unittest.cc
@@ -0,0 +1,112 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 <base/at_exit.h>
+#include <base/command_line.h>
+#include <base/macros.h>
+#include <gtest/gtest.h>
+
+#include "service/settings.h"
+#include "service/switches.h"
+
+using bluetooth::Settings;
+using namespace bluetooth::switches;
+
+namespace {
+
+class SettingsTest : public ::testing::Test {
+ public:
+  SettingsTest() = default;
+
+  void SetUp() override {
+    base::CommandLine::Reset();
+  }
+
+  void TearDown() override {
+    base::CommandLine::Reset();
+  }
+
+ protected:
+  base::AtExitManager exit_manager_;
+  Settings settings_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SettingsTest);
+};
+
+TEST_F(SettingsTest, EmptyCommandLine) {
+  const base::CommandLine::CharType* argv[] = { "program" };
+  EXPECT_TRUE(base::CommandLine::Init(arraysize(argv), argv));
+  EXPECT_TRUE(settings_.Init());
+}
+
+TEST_F(SettingsTest, UnexpectedSwitches1) {
+  const base::CommandLine::CharType* argv[] = {
+    "program", "--create-ipc-socket=foobar", "--foobarbaz"
+  };
+  EXPECT_TRUE(base::CommandLine::Init(arraysize(argv), argv));
+  EXPECT_FALSE(settings_.Init());
+}
+
+TEST_F(SettingsTest, UnexpectedSwitches2) {
+  const base::CommandLine::CharType* argv[] = {
+    "program", "--foobarbaz"
+  };
+  EXPECT_TRUE(base::CommandLine::Init(arraysize(argv), argv));
+  EXPECT_FALSE(settings_.Init());
+}
+
+TEST_F(SettingsTest, UnexpectedArguments1) {
+  const base::CommandLine::CharType* argv[] = {
+    "program", "foobarbaz"
+  };
+  EXPECT_TRUE(base::CommandLine::Init(arraysize(argv), argv));
+  EXPECT_FALSE(settings_.Init());
+}
+
+TEST_F(SettingsTest, UnexpectedArguments2) {
+  const base::CommandLine::CharType* argv[] = {
+    "program", "--create-ipc-socket=foobar", "foobarbaz"
+  };
+  EXPECT_TRUE(base::CommandLine::Init(arraysize(argv), argv));
+  EXPECT_FALSE(settings_.Init());
+}
+
+TEST_F(SettingsTest, TooManyIpcOptions) {
+  const base::CommandLine::CharType* argv[] = {
+      "program", "--create-ipc-socket=foobar",
+      "--android-ipc-socket-suffix=foobar"};
+  EXPECT_TRUE(base::CommandLine::Init(arraysize(argv), argv));
+  EXPECT_FALSE(settings_.Init());
+}
+
+TEST_F(SettingsTest, GoodArgumentsCreateIpc) {
+  const base::CommandLine::CharType* argv[] = {
+    "program", "--create-ipc-socket=foobar"
+  };
+  EXPECT_TRUE(base::CommandLine::Init(arraysize(argv), argv));
+  EXPECT_TRUE(settings_.Init());
+}
+
+TEST_F(SettingsTest, GoodArgumentsAndroidIpc) {
+  const base::CommandLine::CharType* argv[] = {
+    "program", "--android-ipc-socket-suffix=foobar"
+  };
+  EXPECT_TRUE(base::CommandLine::Init(arraysize(argv), argv));
+  EXPECT_TRUE(settings_.Init());
+}
+
+}  // namespace
diff --git a/bt/service/test/stub_ipc_handler_binder.cc b/bt/service/test/stub_ipc_handler_binder.cc
new file mode 100644
index 0000000..6f5a13d
--- /dev/null
+++ b/bt/service/test/stub_ipc_handler_binder.cc
@@ -0,0 +1,49 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/ipc/binder/ipc_handler_binder.h"
+
+// TODO(armansito): This is a crappy workaround to link IPCHandlerBinder into
+// host-native unit tests. We should instead figure out a way to build Binder
+// unit tests for host.
+
+namespace ipc {
+
+IPCHandlerBinder::IPCHandlerBinder(
+    bluetooth::Adapter* adapter,
+    IPCManager::Delegate* delegate)
+    : IPCHandler(adapter, delegate) {
+  // Stub
+}
+
+IPCHandlerBinder::~IPCHandlerBinder() {
+  // Stub
+}
+
+bool IPCHandlerBinder::Run() {
+  // Stub
+  return false;
+}
+
+void IPCHandlerBinder::Stop() {
+  // Stub
+}
+
+void IPCHandlerBinder::NotifyStarted() {
+  // Stub
+}
+
+}  // namespace
diff --git a/bt/service/test/stub_ipc_handler_linux.cc b/bt/service/test/stub_ipc_handler_linux.cc
new file mode 100644
index 0000000..a36717e
--- /dev/null
+++ b/bt/service/test/stub_ipc_handler_linux.cc
@@ -0,0 +1,72 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/ipc/ipc_handler_linux.h"
+
+// TODO(keybuk): This is a crappy workaround to link IPCHandlerLinux into
+// host-native unit tests. IPCManager shouldn't explicitly reference these
+// classes.
+
+namespace ipc {
+
+IPCHandlerLinux::IPCHandlerLinux(
+    bluetooth::Adapter* adapter,
+    IPCManager::Delegate* delegate)
+    : IPCHandler(adapter, delegate),
+      running_(false),
+      thread_("IPCHandlerLinux"),
+      keep_running_(true) {
+  // Stub
+}
+
+IPCHandlerLinux::~IPCHandlerLinux() {
+  // Stub
+}
+
+bool IPCHandlerLinux::Run() {
+  // Stub
+  return false;
+}
+
+void IPCHandlerLinux::Stop() {
+  // Stub
+}
+
+void IPCHandlerLinux::StartListeningOnThread() {
+  // Stub
+}
+
+void IPCHandlerLinux::ShutDownOnOriginThread() {
+  // Stub
+}
+
+void IPCHandlerLinux::NotifyStartedOnOriginThread() {
+  // Stub
+}
+
+void IPCHandlerLinux::NotifyStartedOnCurrentThread() {
+  // Stub
+}
+
+void IPCHandlerLinux::NotifyStoppedOnOriginThread() {
+  // Stub
+}
+
+void IPCHandlerLinux::NotifyStoppedOnCurrentThread() {
+  // Stub
+}
+
+}  // namespace
diff --git a/bt/service/test/util_unittest.cc b/bt/service/test/util_unittest.cc
new file mode 100644
index 0000000..78960d9
--- /dev/null
+++ b/bt/service/test/util_unittest.cc
@@ -0,0 +1,46 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 "service/common/bluetooth/util/address_helper.h"
+
+namespace util {
+
+TEST(UtilTest, IsAddressValid) {
+  EXPECT_FALSE(IsAddressValid(""));
+  EXPECT_FALSE(IsAddressValid("000000000000"));
+  EXPECT_FALSE(IsAddressValid("00:00:00:00:0000"));
+  EXPECT_FALSE(IsAddressValid("00:00:00:00:00:0"));
+  EXPECT_FALSE(IsAddressValid("00:00:00:00:00:0;"));
+  EXPECT_TRUE(IsAddressValid("00:00:00:00:00:00"));
+  EXPECT_FALSE(IsAddressValid("aB:cD:eF:Gh:iJ:Kl"));
+}
+
+TEST(UtilTest, BdAddrFromString) {
+  bt_bdaddr_t addr;
+  memset(&addr, 0, sizeof(addr));
+
+  EXPECT_TRUE(BdAddrFromString("00:00:00:00:00:00", &addr));
+  const bt_bdaddr_t result0 = {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }};
+  EXPECT_EQ(0, memcmp(&addr, &result0, sizeof(addr)));
+
+  EXPECT_TRUE(BdAddrFromString("ab:01:4C:d5:21:9f", &addr));
+  const bt_bdaddr_t result1 = {{ 0xab, 0x01, 0x4c, 0xd5, 0x21, 0x9f }};
+  EXPECT_EQ(0, memcmp(&addr, &result1, sizeof(addr)));
+}
+
+}  // namespace util
diff --git a/bt/service/test/uuid_unittest.cc b/bt/service/test/uuid_unittest.cc
new file mode 100644
index 0000000..207be4a
--- /dev/null
+++ b/bt/service/test/uuid_unittest.cc
@@ -0,0 +1,162 @@
+//
+//  Copyright (C) 2015 Google, Inc.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT 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 <algorithm>
+#include <array>
+#include <stdint.h>
+
+#include <gtest/gtest.h>
+
+#include "service/common/bluetooth/uuid.h"
+
+using namespace bluetooth;
+
+namespace {
+
+const std::array<uint8_t, UUID::kNumBytes128> kBtSigBaseUUID = {
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+      0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb, }
+};
+
+}  // namespace
+
+// Verify that an uninitialized UUID is equal
+// To the BT SIG Base UUID.
+TEST(UUIDTest, DefaultUUID) {
+  UUID uuid;
+  ASSERT_TRUE(uuid.is_valid());
+  ASSERT_TRUE(uuid.GetFullBigEndian() == kBtSigBaseUUID);
+}
+
+// Verify that we initialize a 16-bit UUID in a
+// way consistent with how we read it.
+TEST(UUIDTest, Init16Bit) {
+  auto my_uuid_16 = kBtSigBaseUUID;
+  my_uuid_16[2] = 0xde;
+  my_uuid_16[3] = 0xad;
+  UUID uuid(UUID::UUID16Bit({{ 0xde, 0xad }}));
+  ASSERT_TRUE(uuid.is_valid());
+  ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_16);
+  ASSERT_TRUE(UUID::kNumBytes16 == uuid.GetShortestRepresentationSize());
+}
+
+// Verify that we initialize a 16-bit UUID in a
+// way consistent with how we read it.
+TEST(UUIDTest, Init16BitString) {
+  auto my_uuid_16 = kBtSigBaseUUID;
+  my_uuid_16[2] = 0xde;
+  my_uuid_16[3] = 0xad;
+  UUID uuid("dead");
+  ASSERT_TRUE(uuid.is_valid());
+  ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_16);
+  ASSERT_TRUE(UUID::kNumBytes16 == uuid.GetShortestRepresentationSize());
+
+  uuid = UUID("0xdead");
+  ASSERT_TRUE(uuid.is_valid());
+  ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_16);
+  ASSERT_TRUE(UUID::kNumBytes16 == uuid.GetShortestRepresentationSize());
+}
+
+
+// Verify that we initialize a 32-bit UUID in a
+// way consistent with how we read it.
+TEST(UUIDTest, Init32Bit) {
+  auto my_uuid_32 = kBtSigBaseUUID;
+  my_uuid_32[0] = 0xde;
+  my_uuid_32[1] = 0xad;
+  my_uuid_32[2] = 0xbe;
+  my_uuid_32[3] = 0xef;
+  UUID uuid(UUID::UUID32Bit({{ 0xde, 0xad, 0xbe, 0xef }}));
+  ASSERT_TRUE(uuid.is_valid());
+  ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_32);
+  ASSERT_TRUE(UUID::kNumBytes32 == uuid.GetShortestRepresentationSize());
+}
+
+// Verify correct reading of a 32-bit UUID initialized from string.
+TEST(UUIDTest, Init32BitString) {
+  auto my_uuid_32 = kBtSigBaseUUID;
+  my_uuid_32[0] = 0xde;
+  my_uuid_32[1] = 0xad;
+  my_uuid_32[2] = 0xbe;
+  my_uuid_32[3] = 0xef;
+  UUID uuid("deadbeef");
+  ASSERT_TRUE(uuid.is_valid());
+  ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_32);
+  ASSERT_TRUE(UUID::kNumBytes32 == uuid.GetShortestRepresentationSize());
+}
+
+// Verify that we initialize a 128-bit UUID in a
+// way consistent with how we read it.
+TEST(UUIDTest, Init128Bit) {
+  auto my_uuid_128 = kBtSigBaseUUID;
+  for (int i = 0; i < static_cast<int>(my_uuid_128.size()); ++i) {
+    my_uuid_128[i] = i;
+  }
+
+  UUID uuid(my_uuid_128);
+  ASSERT_TRUE(uuid.is_valid());
+  ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_128);
+  ASSERT_TRUE(UUID::kNumBytes128 == uuid.GetShortestRepresentationSize());
+}
+
+// Verify that we initialize a 128-bit UUID in a
+// way consistent with how we read it as LE.
+TEST(UUIDTest, Init128BitLittleEndian) {
+  auto my_uuid_128 = kBtSigBaseUUID;
+  for (int i = 0; i < static_cast<int>(my_uuid_128.size()); ++i) {
+    my_uuid_128[i] = i;
+  }
+
+  UUID uuid(my_uuid_128);
+  std::reverse(my_uuid_128.begin(), my_uuid_128.end());
+  ASSERT_TRUE(uuid.is_valid());
+  ASSERT_TRUE(uuid.GetFullLittleEndian() == my_uuid_128);
+}
+
+// Verify that we initialize a 128-bit UUID in a
+// way consistent with how we read it.
+TEST(UUIDTest, Init128BitString) {
+  UUID::UUID128Bit my_uuid{
+    { 7, 1, 6, 8, 14, 255, 16, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
+  };
+  std::string my_uuid_string("07010608-0eff-1002-0304-05060708090a");
+
+  UUID uuid0(my_uuid);
+  UUID uuid1(my_uuid_string);
+
+  ASSERT_TRUE(uuid0.is_valid());
+  ASSERT_TRUE(uuid1.is_valid());
+  ASSERT_TRUE(uuid0 == uuid1);
+  ASSERT_TRUE(UUID::kNumBytes128 == uuid0.GetShortestRepresentationSize());
+}
+
+TEST(UUIDTest, InitInvalid) {
+  UUID uuid0("000102030405060708090A0B0C0D0E0F");
+  ASSERT_FALSE(uuid0.is_valid());
+
+  UUID uuid1("1*90");
+  ASSERT_FALSE(uuid1.is_valid());
+
+  UUID uuid2("109g");
+  ASSERT_FALSE(uuid1.is_valid());
+}
+
+TEST(UUIDTest, ToString) {
+  const UUID::UUID16Bit data{{ 0x18, 0x0d }};
+  UUID uuid(data);
+  std::string uuid_string = uuid.ToString();
+  EXPECT_EQ("0000180d-0000-1000-8000-00805f9b34fb", uuid_string);
+}
diff --git a/bt/stack/Android.mk b/bt/stack/Android.mk
new file mode 100644
index 0000000..27a79ee
--- /dev/null
+++ b/bt/stack/Android.mk
@@ -0,0 +1,222 @@
+LOCAL_PATH:= $(call my-dir)
+
+# Bluetooth stack static library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_C_INCLUDES := \
+                   $(LOCAL_PATH)/include \
+                   $(LOCAL_PATH)/avct \
+                   $(LOCAL_PATH)/btm \
+                   $(LOCAL_PATH)/avrc \
+                   $(LOCAL_PATH)/l2cap \
+                   $(LOCAL_PATH)/avdt \
+                   $(LOCAL_PATH)/gatt \
+                   $(LOCAL_PATH)/gap \
+                   $(LOCAL_PATH)/pan \
+                   $(LOCAL_PATH)/bnep \
+                   $(LOCAL_PATH)/hid \
+                   $(LOCAL_PATH)/sdp \
+                   $(LOCAL_PATH)/smp \
+                   $(LOCAL_PATH)/srvc \
+                   $(LOCAL_PATH)/../btcore/include \
+                   $(LOCAL_PATH)/../vnd/include \
+                   $(LOCAL_PATH)/../vnd/ble \
+                   $(LOCAL_PATH)/../btif/include \
+                   $(LOCAL_PATH)/../hci/include \
+                   $(LOCAL_PATH)/../include \
+                   $(LOCAL_PATH)/../udrv/include \
+                   $(LOCAL_PATH)/../rpc/include \
+                   $(LOCAL_PATH)/../hcis \
+                   $(LOCAL_PATH)/../ctrlr/include \
+                   $(LOCAL_PATH)/../bta/include \
+                   $(LOCAL_PATH)/../bta/sys \
+                   $(LOCAL_PATH)/../utils/include \
+                   $(LOCAL_PATH)/../ \
+                   $(bluetooth_C_INCLUDES)
+
+LOCAL_SRC_FILES := \
+    ./a2dp/a2dp_api.cc \
+    ./a2dp/a2dp_sbc.cc \
+    ./a2dp/a2dp_sbc_encoder.cc \
+    ./a2dp/a2dp_sbc_up_sample.cc \
+    ./a2dp/a2dp_vendor.cc \
+    ./avct/avct_api.cc \
+    ./avct/avct_bcb_act.cc \
+    ./avct/avct_ccb.cc \
+    ./avct/avct_l2c.cc \
+    ./avct/avct_l2c_br.cc \
+    ./avct/avct_lcb.cc \
+    ./avct/avct_lcb_act.cc \
+    ./avdt/avdt_ad.cc \
+    ./avdt/avdt_api.cc \
+    ./avdt/avdt_ccb.cc \
+    ./avdt/avdt_ccb_act.cc \
+    ./avdt/avdt_l2c.cc \
+    ./avdt/avdt_msg.cc \
+    ./avdt/avdt_scb.cc \
+    ./avdt/avdt_scb_act.cc \
+    ./avrc/avrc_api.cc \
+    ./avrc/avrc_bld_ct.cc \
+    ./avrc/avrc_bld_tg.cc \
+    ./avrc/avrc_opt.cc \
+    ./avrc/avrc_pars_ct.cc \
+    ./avrc/avrc_pars_tg.cc \
+    ./avrc/avrc_sdp.cc \
+    ./avrc/avrc_utils.cc \
+    ./bnep/bnep_api.cc \
+    ./bnep/bnep_main.cc \
+    ./bnep/bnep_utils.cc \
+    ./btm/ble_advertiser_hci_interface.cc \
+    ./btm/btm_acl.cc \
+    ./btm/btm_ble.cc \
+    ./btm/btm_ble_addr.cc \
+    ./btm/btm_ble_adv_filter.cc \
+    ./btm/btm_ble_batchscan.cc \
+    ./btm/btm_ble_bgconn.cc \
+    ./btm/btm_ble_cont_energy.cc \
+    ./btm/btm_ble_gap.cc \
+    ./btm/btm_ble_multi_adv.cc \
+    ./btm/btm_ble_privacy.cc \
+    ./btm/btm_dev.cc \
+    ./btm/btm_devctl.cc \
+    ./btm/btm_inq.cc \
+    ./btm/btm_main.cc \
+    ./btm/btm_pm.cc \
+    ./btm/btm_sco.cc \
+    ./btm/btm_sec.cc \
+    ./btu/btu_hcif.cc \
+    ./btu/btu_init.cc \
+    ./btu/btu_task.cc \
+    ./gap/gap_api.cc \
+    ./gap/gap_ble.cc \
+    ./gap/gap_conn.cc \
+    ./gap/gap_utils.cc \
+    ./gatt/att_protocol.cc \
+    ./gatt/gatt_api.cc \
+    ./gatt/gatt_attr.cc \
+    ./gatt/gatt_auth.cc \
+    ./gatt/gatt_cl.cc \
+    ./gatt/gatt_db.cc \
+    ./gatt/gatt_main.cc \
+    ./gatt/gatt_sr.cc \
+    ./gatt/gatt_utils.cc \
+    ./hcic/hciblecmds.cc \
+    ./hcic/hcicmds.cc \
+    ./hid/hidh_api.cc \
+    ./hid/hidh_conn.cc \
+    ./l2cap/l2c_api.cc \
+    ./l2cap/l2c_ble.cc \
+    ./l2cap/l2c_csm.cc \
+    ./l2cap/l2c_fcr.cc \
+    ./l2cap/l2c_link.cc \
+    ./l2cap/l2c_main.cc \
+    ./l2cap/l2c_ucd.cc \
+    ./l2cap/l2c_utils.cc \
+    ./l2cap/l2cap_client.cc \
+    ./mcap/mca_api.cc \
+    ./mcap/mca_cact.cc \
+    ./mcap/mca_csm.cc \
+    ./mcap/mca_dact.cc \
+    ./mcap/mca_dsm.cc \
+    ./mcap/mca_l2c.cc \
+    ./mcap/mca_main.cc \
+    ./pan/pan_api.cc \
+    ./pan/pan_main.cc \
+    ./pan/pan_utils.cc \
+    ./rfcomm/port_api.cc \
+    ./rfcomm/port_rfc.cc \
+    ./rfcomm/port_utils.cc \
+    ./rfcomm/rfc_l2cap_if.cc \
+    ./rfcomm/rfc_mx_fsm.cc \
+    ./rfcomm/rfc_port_fsm.cc \
+    ./rfcomm/rfc_port_if.cc \
+    ./rfcomm/rfc_ts_frames.cc \
+    ./rfcomm/rfc_utils.cc \
+    ./sdp/sdp_api.cc \
+    ./sdp/sdp_db.cc \
+    ./sdp/sdp_discovery.cc \
+    ./sdp/sdp_main.cc \
+    ./sdp/sdp_server.cc \
+    ./sdp/sdp_utils.cc \
+    ./smp/aes.cc \
+    ./smp/p_256_curvepara.cc \
+    ./smp/p_256_ecc_pp.cc \
+    ./smp/p_256_multprecision.cc \
+    ./smp/smp_act.cc \
+    ./smp/smp_api.cc \
+    ./smp/smp_br_main.cc \
+    ./smp/smp_cmac.cc \
+    ./smp/smp_keys.cc \
+    ./smp/smp_l2c.cc \
+    ./smp/smp_main.cc \
+    ./smp/smp_utils.cc \
+    ./srvc/srvc_battery.cc \
+    ./srvc/srvc_dis.cc \
+    ./srvc/srvc_eng.cc
+
+LOCAL_MODULE := libbt-stack
+LOCAL_STATIC_LIBRARIES := libbt-hci
+LOCAL_SHARED_LIBRARIES := libcutils libchrome
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_STATIC_LIBRARY)
+
+# Bluetooth stack unit tests for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_CPP_EXTENSION := .cc
+
+LOCAL_C_INCLUDES := \
+                   $(LOCAL_PATH)/include \
+                   $(LOCAL_PATH)/../include \
+                   $(LOCAL_PATH)/../ \
+                   $(bluetooth_C_INCLUDES)
+
+LOCAL_SRC_FILES := test/stack_a2dp_test.cc
+LOCAL_SHARED_LIBRARIES :=
+LOCAL_STATIC_LIBRARIES := libbt-stack liblog
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE := net_test_stack
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_NATIVE_TEST)
+
+
+# Bluetooth stack multi-advertising unit tests for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_CPP_EXTENSION := .cc
+
+LOCAL_C_INCLUDES := \
+                   $(LOCAL_PATH)/include \
+                   $(LOCAL_PATH)/../include \
+                   $(LOCAL_PATH)/../ \
+                   $(LOCAL_PATH)/btm \
+                   $(LOCAL_PATH)/../btcore/include \
+                   $(LOCAL_PATH)/../hci/include \
+                   $(LOCAL_PATH)/../include \
+                   $(LOCAL_PATH)/../utils/include \
+                   $(LOCAL_PATH)/../ \
+                   $(bluetooth_C_INCLUDES)
+
+LOCAL_SRC_FILES := btm/btm_ble_multi_adv.cc \
+                   test/ble_advertiser_test.cc
+LOCAL_SHARED_LIBRARIES := libcutils libchrome
+LOCAL_STATIC_LIBRARIES := liblog libgmock libgtest
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE := net_test_stack_multi_adv
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_NATIVE_TEST)
diff --git a/bt/stack/BUILD.gn b/bt/stack/BUILD.gn
new file mode 100644
index 0000000..41353ed
--- /dev/null
+++ b/bt/stack/BUILD.gn
@@ -0,0 +1,251 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+static_library("stack") {
+  sources = [
+    "a2dp/a2dp_api.cc",
+    "a2dp/a2dp_sbc.cc",
+    "a2dp/a2dp_sbc_encoder.cc",
+    "a2dp/a2dp_sbc_up_sample.cc",
+    "a2dp/a2dp_vendor.cc",
+    "avct/avct_api.cc",
+    "avct/avct_bcb_act.cc",
+    "avct/avct_ccb.cc",
+    "avct/avct_l2c.cc",
+    "avct/avct_l2c_br.cc",
+    "avct/avct_lcb.cc",
+    "avct/avct_lcb_act.cc",
+    "avdt/avdt_ad.cc",
+    "avdt/avdt_api.cc",
+    "avdt/avdt_ccb.cc",
+    "avdt/avdt_ccb_act.cc",
+    "avdt/avdt_l2c.cc",
+    "avdt/avdt_msg.cc",
+    "avdt/avdt_scb.cc",
+    "avdt/avdt_scb_act.cc",
+    "avrc/avrc_api.cc",
+    "avrc/avrc_bld_ct.cc",
+    "avrc/avrc_bld_tg.cc",
+    "avrc/avrc_opt.cc",
+    "avrc/avrc_pars_ct.cc",
+    "avrc/avrc_pars_tg.cc",
+    "avrc/avrc_sdp.cc",
+    "avrc/avrc_utils.cc",
+    "bnep/bnep_api.cc",
+    "bnep/bnep_main.cc",
+    "bnep/bnep_utils.cc",
+    "btm/ble_advertiser_hci_interface.cc",
+    "btm/btm_acl.cc",
+    "btm/btm_ble.cc",
+    "btm/btm_ble_addr.cc",
+    "btm/btm_ble_adv_filter.cc",
+    "btm/btm_ble_batchscan.cc",
+    "btm/btm_ble_bgconn.cc",
+    "btm/btm_ble_cont_energy.cc",
+    "btm/btm_ble_gap.cc",
+    "btm/btm_ble_multi_adv.cc",
+    "btm/btm_ble_privacy.cc",
+    "btm/btm_dev.cc",
+    "btm/btm_devctl.cc",
+    "btm/btm_inq.cc",
+    "btm/btm_main.cc",
+    "btm/btm_pm.cc",
+    "btm/btm_sco.cc",
+    "btm/btm_sec.cc",
+    "btu/btu_hcif.cc",
+    "btu/btu_init.cc",
+    "btu/btu_task.cc",
+    "gap/gap_api.cc",
+    "gap/gap_ble.cc",
+    "gap/gap_conn.cc",
+    "gap/gap_utils.cc",
+    "gatt/att_protocol.cc",
+    "gatt/gatt_api.cc",
+    "gatt/gatt_attr.cc",
+    "gatt/gatt_auth.cc",
+    "gatt/gatt_cl.cc",
+    "gatt/gatt_db.cc",
+    "gatt/gatt_main.cc",
+    "gatt/gatt_sr.cc",
+    "gatt/gatt_utils.cc",
+    "hcic/hciblecmds.cc",
+    "hcic/hcicmds.cc",
+    "hid/hidh_api.cc",
+    "hid/hidh_conn.cc",
+    "l2cap/l2c_api.cc",
+    "l2cap/l2c_ble.cc",
+    "l2cap/l2c_csm.cc",
+    "l2cap/l2c_fcr.cc",
+    "l2cap/l2c_link.cc",
+    "l2cap/l2c_main.cc",
+    "l2cap/l2c_ucd.cc",
+    "l2cap/l2c_utils.cc",
+    "l2cap/l2cap_client.cc",
+    "mcap/mca_api.cc",
+    "mcap/mca_cact.cc",
+    "mcap/mca_csm.cc",
+    "mcap/mca_dact.cc",
+    "mcap/mca_dsm.cc",
+    "mcap/mca_l2c.cc",
+    "mcap/mca_main.cc",
+    "pan/pan_api.cc",
+    "pan/pan_main.cc",
+    "pan/pan_utils.cc",
+    "rfcomm/port_api.cc",
+    "rfcomm/port_rfc.cc",
+    "rfcomm/port_utils.cc",
+    "rfcomm/rfc_l2cap_if.cc",
+    "rfcomm/rfc_mx_fsm.cc",
+    "rfcomm/rfc_port_fsm.cc",
+    "rfcomm/rfc_port_if.cc",
+    "rfcomm/rfc_ts_frames.cc",
+    "rfcomm/rfc_utils.cc",
+    "sdp/sdp_api.cc",
+    "sdp/sdp_db.cc",
+    "sdp/sdp_discovery.cc",
+    "sdp/sdp_main.cc",
+    "sdp/sdp_server.cc",
+    "sdp/sdp_utils.cc",
+    "smp/aes.cc",
+    "smp/p_256_curvepara.cc",
+    "smp/p_256_ecc_pp.cc",
+    "smp/p_256_multprecision.cc",
+    "smp/smp_act.cc",
+    "smp/smp_api.cc",
+    "smp/smp_br_main.cc",
+    "smp/smp_cmac.cc",
+    "smp/smp_keys.cc",
+    "smp/smp_l2c.cc",
+    "smp/smp_main.cc",
+    "smp/smp_utils.cc",
+    "srvc/srvc_battery.cc",
+    "srvc/srvc_dis.cc",
+    "srvc/srvc_eng.cc",
+  ]
+
+  include_dirs = [
+    "include",
+    "avct",
+    "btm",
+    "avrc",
+    "l2cap",
+    "avdt",
+    "gatt",
+    "gap",
+    "pan",
+    "bnep",
+    "hid",
+    "sdp",
+    "smp",
+    "srvc",
+    "//btcore/include",
+    "//vnd/include",
+    "//vnd/ble",
+    "//btif/include",
+    "//hci/include",
+    "//include",
+    "//udrv/include",
+    "//rpc/include",
+    "//hcis",
+    "//ctrlr/include",
+    "//bta/include",
+    "//bta/sys",
+    "//utils/include",
+    "//",
+  ]
+
+  deps = [
+    "//third_party/libchrome:base"
+  ]
+}
+
+executable("stack_unittests") {
+  testonly = true
+  sources = [
+    "test/stack_a2dp_test.cc",
+  ]
+
+  include_dirs = [
+    "include",
+    "//",
+    "//audio_a2dp_hw",
+    "//bta/include",
+    "//bta/sys",
+    "//btcore/include",
+    "//embdrv/sbc/encoder/include",
+    "//hci/include",
+    "//include",
+    "//stack/a2dp",
+    "//stack/btm",
+    "//stack/include",
+    "//third_party/tinyxml2",
+    "//udrv/include",
+    "//utils/include",
+    "//vnd/include"
+  ]
+
+  libs = [
+    "-ldl",
+    "-lpthread",
+    "-lresolv",
+    "-lrt",
+    "-lz",
+    "-latomic",
+  ]
+
+  deps = [
+    ":stack",
+    "//osi",
+    "//btcore",
+    "//device",
+    "//hci",
+    "//main:bluetooth.default",
+    "//third_party/googletest:gmock_main",
+    "//third_party/libchrome:base",
+  ]
+}
+
+executable("net_test_stack_multi_adv") {
+  testonly = true
+  sources = [
+    "btm/btm_ble_multi_adv.cc",
+    "test/ble_advertiser_test.cc",
+  ]
+
+  include_dirs = [
+    "include",
+    "//",
+    "//btcore/include",
+    "//hci/include",
+    "//include",
+    "//stack/btm",
+  ]
+
+libs = [
+    "-ldl",
+    "-lpthread",
+    "-lresolv",
+    "-lrt",
+    "-lz",
+    "-latomic",
+  ]
+
+  deps = [
+    "//third_party/googletest:gmock_main",
+    "//third_party/libchrome:base",
+  ]
+}
+
diff --git a/bt/stack/a2dp/a2dp_api.cc b/bt/stack/a2dp/a2dp_api.cc
new file mode 100644
index 0000000..2c3a04d
--- /dev/null
+++ b/bt/stack/a2dp/a2dp_api.cc
@@ -0,0 +1,1007 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Common API for the Advanced Audio Distribution Profile (A2DP)
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "a2dp_api"
+
+#include "a2dp_api.h"
+#include <string.h>
+#include "a2dp_int.h"
+#include "a2dp_sbc.h"
+#include "a2dp_vendor.h"
+#include "avdt_api.h"
+#include "bt_common.h"
+#include "bt_target.h"
+#include "osi/include/log.h"
+#include "sdpdefs.h"
+
+/* The Media Type offset within the codec info byte array */
+#define A2DP_MEDIA_TYPE_OFFSET 1
+
+/*****************************************************************************
+**  Global data
+*****************************************************************************/
+tA2DP_CB a2dp_cb;
+
+/******************************************************************************
+**
+** Function         a2dp_sdp_cback
+**
+** Description      This is the SDP callback function used by A2DP_FindService.
+**                  This function will be executed by SDP when the service
+**                  search is completed.  If the search is successful, it
+**                  finds the first record in the database that matches the
+**                  UUID of the search.  Then retrieves various parameters
+**                  from the record.  When it is finished it calls the
+**                  application callback function.
+**
+** Returns          Nothing.
+**
+******************************************************************************/
+static void a2dp_sdp_cback(uint16_t status) {
+  tSDP_DISC_REC* p_rec = NULL;
+  tSDP_DISC_ATTR* p_attr;
+  bool found = false;
+  tA2DP_Service a2dp_svc;
+  tSDP_PROTOCOL_ELEM elem;
+
+  LOG_VERBOSE(LOG_TAG, "%s: status: %d", __func__, status);
+
+  if (status == SDP_SUCCESS) {
+    /* loop through all records we found */
+    do {
+      /* get next record; if none found, we're done */
+      if ((p_rec = SDP_FindServiceInDb(
+               a2dp_cb.find.p_db, a2dp_cb.find.service_uuid, p_rec)) == NULL) {
+        break;
+      }
+      memset(&a2dp_svc, 0, sizeof(tA2DP_Service));
+
+      /* get service name */
+      if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) !=
+          NULL) {
+        a2dp_svc.p_service_name = (char*)p_attr->attr_value.v.array;
+        a2dp_svc.service_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+      }
+
+      /* get provider name */
+      if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_PROVIDER_NAME)) !=
+          NULL) {
+        a2dp_svc.p_provider_name = (char*)p_attr->attr_value.v.array;
+        a2dp_svc.provider_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+      }
+
+      /* get supported features */
+      if ((p_attr = SDP_FindAttributeInRec(
+               p_rec, ATTR_ID_SUPPORTED_FEATURES)) != NULL) {
+        a2dp_svc.features = p_attr->attr_value.v.u16;
+      }
+
+      /* get AVDTP version */
+      if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_AVDTP, &elem)) {
+        a2dp_svc.avdt_version = elem.params[0];
+        LOG_VERBOSE(LOG_TAG, "avdt_version: 0x%x", a2dp_svc.avdt_version);
+      }
+
+      /* we've got everything, we're done */
+      found = true;
+      break;
+
+    } while (true);
+  }
+
+  a2dp_cb.find.service_uuid = 0;
+  osi_free_and_reset((void**)&a2dp_cb.find.p_db);
+  /* return info from sdp record in app callback function */
+  if (a2dp_cb.find.p_cback != NULL) {
+    (*a2dp_cb.find.p_cback)(found, &a2dp_svc);
+  }
+
+  return;
+}
+
+/*******************************************************************************
+**
+** Function         a2dp_set_avdt_sdp_ver
+**
+** Description      This function allows the script wrapper to change the
+**                  avdt version of a2dp.
+**
+** Returns          None
+**
+*******************************************************************************/
+void a2dp_set_avdt_sdp_ver(uint16_t avdt_sdp_ver) {
+  a2dp_cb.avdt_sdp_ver = avdt_sdp_ver;
+}
+
+/******************************************************************************
+**
+** Function         A2DP_AddRecord
+**
+** Description      This function is called by a server application to add
+**                  SRC or SNK information to an SDP record.  Prior to
+**                  calling this function the application must call
+**                  SDP_CreateRecord() to create an SDP record.
+**
+**                  Input Parameters:
+**                      service_uuid:  Indicates SRC or SNK.
+**
+**                      p_service_name:  Pointer to a null-terminated character
+**                      string containing the service name.
+**
+**                      p_provider_name:  Pointer to a null-terminated character
+**                      string containing the provider name.
+**
+**                      features:  Profile supported features.
+**
+**                      sdp_handle:  SDP handle returned by SDP_CreateRecord().
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          A2DP_SUCCESS if function execution succeeded,
+**                  A2DP_INVALID_PARAMS if bad parameters are given.
+**                  A2DP_FAIL if function execution failed.
+**
+******************************************************************************/
+tA2DP_STATUS A2DP_AddRecord(uint16_t service_uuid, char* p_service_name,
+                            char* p_provider_name, uint16_t features,
+                            uint32_t sdp_handle) {
+  uint16_t browse_list[1];
+  bool result = true;
+  uint8_t temp[8];
+  uint8_t* p;
+  tSDP_PROTOCOL_ELEM proto_list[A2DP_NUM_PROTO_ELEMS];
+
+  LOG_VERBOSE(LOG_TAG, "%s: uuid: 0x%x", __func__, service_uuid);
+
+  if ((sdp_handle == 0) || (service_uuid != UUID_SERVCLASS_AUDIO_SOURCE &&
+                            service_uuid != UUID_SERVCLASS_AUDIO_SINK))
+    return A2DP_INVALID_PARAMS;
+
+  /* add service class id list */
+  result &= SDP_AddServiceClassIdList(sdp_handle, 1, &service_uuid);
+
+  memset((void*)proto_list, 0,
+         A2DP_NUM_PROTO_ELEMS * sizeof(tSDP_PROTOCOL_ELEM));
+
+  /* add protocol descriptor list   */
+  proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+  proto_list[0].num_params = 1;
+  proto_list[0].params[0] = AVDT_PSM;
+  proto_list[1].protocol_uuid = UUID_PROTOCOL_AVDTP;
+  proto_list[1].num_params = 1;
+  proto_list[1].params[0] = a2dp_cb.avdt_sdp_ver;
+
+  result &= SDP_AddProtocolList(sdp_handle, A2DP_NUM_PROTO_ELEMS, proto_list);
+
+  /* add profile descriptor list   */
+  result &= SDP_AddProfileDescriptorList(
+      sdp_handle, UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION, A2DP_VERSION);
+
+  /* add supported feature */
+  if (features != 0) {
+    p = temp;
+    UINT16_TO_BE_STREAM(p, features);
+    result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES,
+                               UINT_DESC_TYPE, (uint32_t)2, (uint8_t*)temp);
+  }
+
+  /* add provider name */
+  if (p_provider_name != NULL) {
+    result &= SDP_AddAttribute(
+        sdp_handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE,
+        (uint32_t)(strlen(p_provider_name) + 1), (uint8_t*)p_provider_name);
+  }
+
+  /* add service name */
+  if (p_service_name != NULL) {
+    result &= SDP_AddAttribute(
+        sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+        (uint32_t)(strlen(p_service_name) + 1), (uint8_t*)p_service_name);
+  }
+
+  /* add browse group list */
+  browse_list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+  result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1,
+                                browse_list);
+
+  return (result ? A2DP_SUCCESS : A2DP_FAIL);
+}
+
+/******************************************************************************
+**
+** Function         A2DP_FindService
+**
+** Description      This function is called by a client application to
+**                  perform service discovery and retrieve SRC or SNK SDP
+**                  record information from a server.  Information is
+**                  returned for the first service record found on the
+**                  server that matches the service UUID.  The callback
+**                  function will be executed when service discovery is
+**                  complete.  There can only be one outstanding call to
+**                  A2DP_FindService() at a time; the application must wait
+**                  for the callback before it makes another call to
+**                  the function.
+**
+**                  Input Parameters:
+**                      service_uuid:  Indicates SRC or SNK.
+**
+**                      bd_addr:  BD address of the peer device.
+**
+**                      p_db:  Pointer to the information to initialize
+**                             the discovery database.
+**
+**                      p_cback:  Pointer to the A2DP_FindService()
+**                      callback function.
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          A2DP_SUCCESS if function execution succeeded,
+**                  A2DP_INVALID_PARAMS if bad parameters are given.
+**                  A2DP_BUSY if discovery is already in progress.
+**                  A2DP_FAIL if function execution failed.
+**
+******************************************************************************/
+tA2DP_STATUS A2DP_FindService(uint16_t service_uuid, BD_ADDR bd_addr,
+                              tA2DP_SDP_DB_PARAMS* p_db,
+                              tA2DP_FIND_CBACK* p_cback) {
+  tSDP_UUID uuid_list;
+  bool result = true;
+  uint16_t a2dp_attr_list[] = {
+      ATTR_ID_SERVICE_CLASS_ID_LIST, /* update A2DP_NUM_ATTR, if changed */
+      ATTR_ID_BT_PROFILE_DESC_LIST,  ATTR_ID_SUPPORTED_FEATURES,
+      ATTR_ID_SERVICE_NAME,          ATTR_ID_PROTOCOL_DESC_LIST,
+      ATTR_ID_PROVIDER_NAME};
+
+  LOG_VERBOSE(LOG_TAG, "%s: uuid: 0x%x", __func__, service_uuid);
+  if ((service_uuid != UUID_SERVCLASS_AUDIO_SOURCE &&
+       service_uuid != UUID_SERVCLASS_AUDIO_SINK) ||
+      p_db == NULL || p_cback == NULL)
+    return A2DP_INVALID_PARAMS;
+
+  if (a2dp_cb.find.service_uuid == UUID_SERVCLASS_AUDIO_SOURCE ||
+      a2dp_cb.find.service_uuid == UUID_SERVCLASS_AUDIO_SINK)
+    return A2DP_BUSY;
+
+  /* set up discovery database */
+  uuid_list.len = LEN_UUID_16;
+  uuid_list.uu.uuid16 = service_uuid;
+
+  if (p_db->p_attrs == NULL || p_db->num_attr == 0) {
+    p_db->p_attrs = a2dp_attr_list;
+    p_db->num_attr = A2DP_NUM_ATTR;
+  }
+
+  if (a2dp_cb.find.p_db == NULL)
+    a2dp_cb.find.p_db = (tSDP_DISCOVERY_DB*)osi_malloc(p_db->db_len);
+
+  result = SDP_InitDiscoveryDb(a2dp_cb.find.p_db, p_db->db_len, 1, &uuid_list,
+                               p_db->num_attr, p_db->p_attrs);
+
+  if (result == true) {
+    /* store service_uuid */
+    a2dp_cb.find.service_uuid = service_uuid;
+    a2dp_cb.find.p_cback = p_cback;
+
+    /* perform service search */
+    result = SDP_ServiceSearchAttributeRequest(bd_addr, a2dp_cb.find.p_db,
+                                               a2dp_sdp_cback);
+    if (false == result) {
+      a2dp_cb.find.service_uuid = 0;
+    }
+  }
+
+  return (result ? A2DP_SUCCESS : A2DP_FAIL);
+}
+
+/******************************************************************************
+**
+** Function         A2DP_SetTraceLevel
+**
+** Description      Sets the trace level for A2D. If 0xff is passed, the
+**                  current trace level is returned.
+**
+**                  Input Parameters:
+**                      new_level:  The level to set the A2DP tracing to:
+**                      0xff-returns the current setting.
+**                      0-turns off tracing.
+**                      >= 1-Errors.
+**                      >= 2-Warnings.
+**                      >= 3-APIs.
+**                      >= 4-Events.
+**                      >= 5-Debug.
+**
+** Returns          The new trace level or current trace level if
+**                  the input parameter is 0xff.
+**
+******************************************************************************/
+uint8_t A2DP_SetTraceLevel(uint8_t new_level) {
+  if (new_level != 0xFF) a2dp_cb.trace_level = new_level;
+
+  return (a2dp_cb.trace_level);
+}
+
+/******************************************************************************
+** Function         A2DP_BitsSet
+**
+** Description      Check the given num for the number of bits set
+** Returns          A2DP_SET_ONE_BIT, if one and only one bit is set
+**                  A2DP_SET_ZERO_BIT, if all bits clear
+**                  A2DP_SET_MULTL_BIT, if multiple bits are set
+******************************************************************************/
+uint8_t A2DP_BitsSet(uint8_t num) {
+  uint8_t count;
+  bool res;
+  if (num == 0)
+    res = A2DP_SET_ZERO_BIT;
+  else {
+    count = (num & (num - 1));
+    res = ((count == 0) ? A2DP_SET_ONE_BIT : A2DP_SET_MULTL_BIT);
+  }
+  return res;
+}
+
+/*******************************************************************************
+**
+** Function         A2DP_Init
+**
+** Description      This function is called to initialize the control block
+**                  for this layer.  It must be called before accessing any
+**                  other API functions for this layer.  It is typically called
+**                  once during the start up of the stack.
+**
+** Returns          void
+**
+*******************************************************************************/
+void A2DP_Init(void) {
+  memset(&a2dp_cb, 0, sizeof(tA2DP_CB));
+
+  a2dp_cb.avdt_sdp_ver = AVDT_VERSION;
+
+#if defined(A2DP_INITIAL_TRACE_LEVEL)
+  a2dp_cb.trace_level = A2DP_INITIAL_TRACE_LEVEL;
+#else
+  a2dp_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+}
+
+tA2DP_CODEC_TYPE A2DP_GetCodecType(const uint8_t* p_codec_info) {
+  return (tA2DP_CODEC_TYPE)(p_codec_info[AVDT_CODEC_TYPE_INDEX]);
+}
+
+bool A2DP_IsSourceCodecValid(const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_IsSourceCodecValidSbc(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_IsVendorSourceCodecValid(p_codec_info);
+    default:
+      break;
+  }
+
+  return false;
+}
+
+bool A2DP_IsSinkCodecValid(const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_IsSinkCodecValidSbc(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_IsVendorSinkCodecValid(p_codec_info);
+    default:
+      break;
+  }
+
+  return false;
+}
+
+bool A2DP_IsPeerSourceCodecValid(const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_IsPeerSourceCodecValidSbc(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_IsVendorPeerSourceCodecValid(p_codec_info);
+    default:
+      break;
+  }
+
+  return false;
+}
+
+bool A2DP_IsPeerSinkCodecValid(const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_IsPeerSinkCodecValidSbc(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_IsVendorPeerSinkCodecValid(p_codec_info);
+    default:
+      break;
+  }
+
+  return false;
+}
+
+bool A2DP_IsSourceCodecSupported(const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_IsSourceCodecSupportedSbc(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_IsVendorSourceCodecSupported(p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return false;
+}
+
+bool A2DP_IsSinkCodecSupported(const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_IsSinkCodecSupportedSbc(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_IsVendorSinkCodecSupported(p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return false;
+}
+
+bool A2DP_IsPeerSourceCodecSupported(const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_IsPeerSourceCodecSupportedSbc(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_IsVendorPeerSourceCodecSupported(p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return false;
+}
+
+void A2DP_InitDefaultCodec(uint8_t* p_codec_info) {
+  A2DP_InitDefaultCodecSbc(p_codec_info);
+}
+
+bool A2DP_SetSourceCodec(tA2DP_CODEC_SEP_INDEX source_codec_sep_index,
+                         const tA2DP_FEEDING_PARAMS* p_feeding_params,
+                         uint8_t* p_codec_info) {
+  switch (source_codec_sep_index) {
+    case A2DP_CODEC_SEP_INDEX_SOURCE_SBC:
+      return A2DP_SetSourceCodecSbc(p_feeding_params, p_codec_info);
+    case A2DP_CODEC_SEP_INDEX_SINK_SBC:
+      return false;             // Not a source codec
+    default:
+      break;
+  }
+
+  if (source_codec_sep_index < A2DP_CODEC_SEP_INDEX_MAX) {
+    return A2DP_VendorSetSourceCodec(source_codec_sep_index,
+                                     p_feeding_params,
+                                     p_codec_info);
+  }
+
+  return false;
+}
+
+tA2DP_STATUS A2DP_BuildSrc2SinkConfig(const uint8_t* p_src_cap,
+                                      uint8_t* p_pref_cfg) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_src_cap);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_BuildSrc2SinkConfigSbc(p_src_cap, p_pref_cfg);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorBuildSrc2SinkConfig(p_src_cap, p_pref_cfg);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return A2DP_NS_CODEC_TYPE;
+}
+
+tA2DP_STATUS A2DP_BuildSinkConfig(const uint8_t* p_src_config,
+                                  const uint8_t* p_sink_cap,
+                                  uint8_t* p_result_sink_config) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_src_config);
+
+  if (codec_type != A2DP_GetCodecType(p_sink_cap)) return A2DP_FAIL;
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_BuildSinkConfigSbc(p_src_config, p_sink_cap,
+                                     p_result_sink_config);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorBuildSinkConfig(p_src_config, p_sink_cap,
+                                        p_result_sink_config);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return A2DP_NS_CODEC_TYPE;
+}
+
+bool A2DP_UsesRtpHeader(bool content_protection_enabled,
+                        const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  if (codec_type != A2DP_MEDIA_CT_NON_A2DP) return true;
+
+  return A2DP_VendorUsesRtpHeader(content_protection_enabled, p_codec_info);
+}
+
+const char* A2DP_CodecSepIndexStr(tA2DP_CODEC_SEP_INDEX codec_sep_index) {
+  switch (codec_sep_index) {
+    case A2DP_CODEC_SEP_INDEX_SOURCE_SBC:
+      return A2DP_CodecSepIndexStrSbc();
+    case A2DP_CODEC_SEP_INDEX_SINK_SBC:
+      return A2DP_CodecSepIndexStrSbcSink();
+    default:
+      break;
+  }
+
+  if (codec_sep_index < A2DP_CODEC_SEP_INDEX_MAX)
+    return A2DP_VendorCodecSepIndexStr(codec_sep_index);
+
+  return "UNKNOWN CODEC SEP INDEX";
+}
+
+bool A2DP_InitCodecConfig(tA2DP_CODEC_SEP_INDEX codec_sep_index,
+                          tAVDT_CFG* p_cfg) {
+  LOG_VERBOSE(LOG_TAG, "%s: codec %s", __func__,
+              A2DP_CodecSepIndexStr(codec_sep_index));
+
+  /* Default: no content protection info */
+  p_cfg->num_protect = 0;
+  p_cfg->protect_info[0] = 0;
+
+  switch (codec_sep_index) {
+    case A2DP_CODEC_SEP_INDEX_SOURCE_SBC:
+      return A2DP_InitCodecConfigSbc(p_cfg);
+    case A2DP_CODEC_SEP_INDEX_SINK_SBC:
+      return A2DP_InitCodecConfigSbcSink(p_cfg);
+    default:
+      break;
+  }
+
+  if (codec_sep_index < A2DP_CODEC_SEP_INDEX_MAX)
+    return A2DP_VendorInitCodecConfig(codec_sep_index, p_cfg);
+
+  return false;
+}
+
+uint8_t A2DP_GetMediaType(const uint8_t* p_codec_info) {
+  uint8_t media_type = (p_codec_info[A2DP_MEDIA_TYPE_OFFSET] >> 4) & 0x0f;
+  return media_type;
+}
+
+const char* A2DP_CodecName(const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_CodecNameSbc(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorCodecName(p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return "UNKNOWN CODEC";
+}
+
+bool A2DP_CodecTypeEquals(const uint8_t* p_codec_info_a,
+                          const uint8_t* p_codec_info_b) {
+  tA2DP_CODEC_TYPE codec_type_a = A2DP_GetCodecType(p_codec_info_a);
+  tA2DP_CODEC_TYPE codec_type_b = A2DP_GetCodecType(p_codec_info_b);
+
+  if (codec_type_a != codec_type_b) return false;
+
+  switch (codec_type_a) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_CodecTypeEqualsSbc(p_codec_info_a, p_codec_info_b);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorCodecTypeEquals(p_codec_info_a, p_codec_info_b);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type_a);
+  return false;
+}
+
+bool A2DP_CodecEquals(const uint8_t* p_codec_info_a,
+                      const uint8_t* p_codec_info_b) {
+  tA2DP_CODEC_TYPE codec_type_a = A2DP_GetCodecType(p_codec_info_a);
+  tA2DP_CODEC_TYPE codec_type_b = A2DP_GetCodecType(p_codec_info_b);
+
+  if (codec_type_a != codec_type_b) return false;
+
+  switch (codec_type_a) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_CodecEqualsSbc(p_codec_info_a, p_codec_info_b);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorCodecEquals(p_codec_info_a, p_codec_info_b);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type_a);
+  return false;
+}
+
+bool A2DP_CodecRequiresReconfig(const uint8_t* p_codec_info_a,
+                                const uint8_t* p_codec_info_b) {
+  tA2DP_CODEC_TYPE codec_type_a = A2DP_GetCodecType(p_codec_info_a);
+  tA2DP_CODEC_TYPE codec_type_b = A2DP_GetCodecType(p_codec_info_b);
+
+  if (codec_type_a != codec_type_b) return true;
+
+  switch (codec_type_a) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_CodecRequiresReconfigSbc(p_codec_info_a, p_codec_info_b);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorCodecRequiresReconfig(p_codec_info_a, p_codec_info_b);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type_a);
+  return true;
+}
+
+bool A2DP_CodecConfigMatchesCapabilities(const uint8_t* p_codec_config,
+                                         const uint8_t* p_codec_caps) {
+  tA2DP_CODEC_TYPE codec_type_a = A2DP_GetCodecType(p_codec_config);
+  tA2DP_CODEC_TYPE codec_type_b = A2DP_GetCodecType(p_codec_caps);
+
+  if (codec_type_a != codec_type_b) return false;
+
+  switch (codec_type_a) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_CodecConfigMatchesCapabilitiesSbc(p_codec_config,
+                                                    p_codec_caps);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorCodecConfigMatchesCapabilities(p_codec_config,
+                                                       p_codec_caps);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type_a);
+  return false;
+}
+
+int A2DP_GetTrackFrequency(const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_GetTrackFrequencySbc(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorGetTrackFrequency(p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return -1;
+}
+
+int A2DP_GetTrackChannelCount(const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_GetTrackChannelCountSbc(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorGetTrackChannelCount(p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return -1;
+}
+
+int A2DP_GetNumberOfSubbands(const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_GetNumberOfSubbandsSbc(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorGetNumberOfSubbands(p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return -1;
+}
+
+int A2DP_GetNumberOfBlocks(const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_GetNumberOfBlocksSbc(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorGetNumberOfBlocks(p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return -1;
+}
+
+int A2DP_GetAllocationMethodCode(const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_GetAllocationMethodCodeSbc(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorGetAllocationMethodCode(p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return -1;
+}
+
+int A2DP_GetChannelModeCode(const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_GetChannelModeCodeSbc(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorGetChannelModeCode(p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return -1;
+}
+
+int A2DP_GetSamplingFrequencyCode(const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_GetSamplingFrequencyCodeSbc(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorGetSamplingFrequencyCode(p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return -1;
+}
+
+int A2DP_GetMinBitpool(const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_GetMinBitpoolSbc(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorGetMinBitpool(p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return -1;
+}
+
+int A2DP_GetMaxBitpool(const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_GetMaxBitpoolSbc(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorGetMaxBitpool(p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return -1;
+}
+
+int A2DP_GetSinkTrackChannelType(const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_GetSinkTrackChannelTypeSbc(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorGetSinkTrackChannelType(p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return -1;
+}
+
+int A2DP_GetSinkFramesCountToProcess(uint64_t time_interval_ms,
+                                     const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_GetSinkFramesCountToProcessSbc(time_interval_ms,
+                                                 p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorGetSinkFramesCountToProcess(time_interval_ms,
+                                                    p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return -1;
+}
+
+bool A2DP_GetPacketTimestamp(const uint8_t* p_codec_info, const uint8_t* p_data,
+                             uint32_t* p_timestamp) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_GetPacketTimestampSbc(p_codec_info, p_data, p_timestamp);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorGetPacketTimestamp(p_codec_info, p_data, p_timestamp);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return false;
+}
+
+bool A2DP_BuildCodecHeader(const uint8_t* p_codec_info, BT_HDR* p_buf,
+                           uint16_t frames_per_packet) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_BuildCodecHeaderSbc(p_codec_info, p_buf, frames_per_packet);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorBuildCodecHeader(p_codec_info, p_buf,
+                                         frames_per_packet);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return false;
+}
+
+const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterface(
+    const uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_GetEncoderInterfaceSbc(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorGetEncoderInterface(p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return NULL;
+}
+
+bool A2DP_AdjustCodec(uint8_t* p_codec_info) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+  switch (codec_type) {
+    case A2DP_MEDIA_CT_SBC:
+      return A2DP_AdjustCodecSbc(p_codec_info);
+    case A2DP_MEDIA_CT_NON_A2DP:
+      return A2DP_VendorAdjustCodec(p_codec_info);
+    default:
+      break;
+  }
+
+  LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+  return false;
+}
diff --git a/bt/stack/a2dp/a2dp_int.h b/bt/stack/a2dp/a2dp_int.h
new file mode 100644
index 0000000..b016c95
--- /dev/null
+++ b/bt/stack/a2dp/a2dp_int.h
@@ -0,0 +1,73 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  2DP internal header file
+ *
+ ******************************************************************************/
+#ifndef A2DP_INT_H
+#define A2DP_INT_H
+
+#include "a2dp_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+#define A2DP_VERSION 0x0102
+
+/* Number of attributes in A2DP SDP record. */
+#define A2DP_NUM_ATTR 6
+
+/* Number of protocol elements in protocol element list. */
+#define A2DP_NUM_PROTO_ELEMS 2
+
+/*****************************************************************************
+**  Type definitions
+*****************************************************************************/
+
+/* Control block used by A2DP_FindService(). */
+typedef struct {
+  tA2DP_FIND_CBACK* p_cback; /* pointer to application callback */
+  tSDP_DISCOVERY_DB* p_db;   /* pointer to discovery database */
+  uint16_t service_uuid;     /* service UUID of search */
+} tA2DP_FIND_CB;
+
+typedef struct {
+  tA2DP_FIND_CB find; /* find service control block */
+  uint8_t trace_level;
+  uint16_t avdt_sdp_ver; /* AVDTP version */
+} tA2DP_CB;
+
+/******************************************************************************
+** Main Control Block
+*******************************************************************************/
+extern tA2DP_CB a2dp_cb;
+
+/* Used only for conformance testing */
+extern void a2dp_set_avdt_sdp_ver(uint16_t avdt_sdp_ver);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* A2DP_INT_H */
diff --git a/bt/stack/a2dp/a2dp_sbc.cc b/bt/stack/a2dp/a2dp_sbc.cc
new file mode 100644
index 0000000..0e33b4a
--- /dev/null
+++ b/bt/stack/a2dp/a2dp_sbc.cc
@@ -0,0 +1,1183 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Utility functions to help build and parse SBC Codec Information Element
+ *  and Media Payload.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "a2dp_sbc"
+
+#include "bt_target.h"
+
+#include <string.h>
+#include "a2dp_api.h"
+#include "a2dp_int.h"
+#include "a2dp_sbc.h"
+#include "a2dp_sbc_encoder.h"
+#include "bt_utils.h"
+#include "embdrv/sbc/encoder/include/sbc_encoder.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#define A2DP_SBC_MAX_BITPOOL 53
+
+/* data type for the SBC Codec Information Element */
+typedef struct {
+  uint8_t samp_freq;    /* Sampling frequency */
+  uint8_t ch_mode;      /* Channel mode */
+  uint8_t block_len;    /* Block length */
+  uint8_t num_subbands; /* Number of subbands */
+  uint8_t alloc_method; /* Allocation method */
+  uint8_t min_bitpool;  /* Minimum bitpool */
+  uint8_t max_bitpool;  /* Maximum bitpool */
+} tA2DP_SBC_CIE;
+
+/* SBC SRC codec capabilities */
+static const tA2DP_SBC_CIE a2dp_sbc_caps = {
+    A2DP_SBC_IE_SAMP_FREQ_44, /* samp_freq */
+    A2DP_SBC_IE_CH_MD_JOINT,  /* ch_mode */
+    A2DP_SBC_IE_BLOCKS_16,    /* block_len */
+    A2DP_SBC_IE_SUBBAND_8,    /* num_subbands */
+    A2DP_SBC_IE_ALLOC_MD_L,   /* alloc_method */
+    A2DP_SBC_IE_MIN_BITPOOL,  /* min_bitpool */
+    A2DP_SBC_MAX_BITPOOL      /* max_bitpool */
+};
+
+/* SBC SINK codec capabilities */
+static const tA2DP_SBC_CIE a2dp_sbc_sink_caps = {
+    (A2DP_SBC_IE_SAMP_FREQ_48 | A2DP_SBC_IE_SAMP_FREQ_44), /* samp_freq */
+    (A2DP_SBC_IE_CH_MD_MONO | A2DP_SBC_IE_CH_MD_STEREO |
+     A2DP_SBC_IE_CH_MD_JOINT | A2DP_SBC_IE_CH_MD_DUAL), /* ch_mode */
+    (A2DP_SBC_IE_BLOCKS_16 | A2DP_SBC_IE_BLOCKS_12 | A2DP_SBC_IE_BLOCKS_8 |
+     A2DP_SBC_IE_BLOCKS_4),                            /* block_len */
+    (A2DP_SBC_IE_SUBBAND_4 | A2DP_SBC_IE_SUBBAND_8),   /* num_subbands */
+    (A2DP_SBC_IE_ALLOC_MD_L | A2DP_SBC_IE_ALLOC_MD_S), /* alloc_method */
+    A2DP_SBC_IE_MIN_BITPOOL,                           /* min_bitpool */
+    A2DP_SBC_IE_MAX_BITPOOL                            /* max_bitpool */
+};
+
+/* Default SBC codec configuration */
+const tA2DP_SBC_CIE a2dp_sbc_default_config = {
+    A2DP_SBC_IE_SAMP_FREQ_44, /* samp_freq */
+    A2DP_SBC_IE_CH_MD_JOINT,  /* ch_mode */
+    A2DP_SBC_IE_BLOCKS_16,    /* block_len */
+    A2DP_SBC_IE_SUBBAND_8,    /* num_subbands */
+    A2DP_SBC_IE_ALLOC_MD_L,   /* alloc_method */
+    A2DP_SBC_IE_MIN_BITPOOL,  /* min_bitpool */
+    A2DP_SBC_MAX_BITPOOL      /* max_bitpool */
+};
+
+static const tA2DP_ENCODER_INTERFACE a2dp_encoder_interface_sbc = {
+    a2dp_sbc_encoder_init,
+    a2dp_sbc_encoder_update,
+    a2dp_sbc_encoder_cleanup,
+    a2dp_sbc_feeding_init,
+    a2dp_sbc_feeding_reset,
+    a2dp_sbc_feeding_flush,
+    a2dp_sbc_get_encoder_interval_ms,
+    a2dp_sbc_send_frames,
+    a2dp_sbc_debug_codec_dump
+};
+
+static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilitySbc(
+    const tA2DP_SBC_CIE* p_cap, const uint8_t* p_codec_info,
+    bool is_peer_codec_info);
+static void A2DP_ParseMplHeaderSbc(uint8_t* p_src, bool* p_frag, bool* p_start,
+                                   bool* p_last, uint8_t* p_num);
+
+// Builds the SBC Media Codec Capabilities byte sequence beginning from the
+// LOSC octet. |media_type| is the media type |AVDT_MEDIA_TYPE_*|.
+// |p_ie| is a pointer to the SBC Codec Information Element information.
+// The result is stored in |p_result|. Returns A2DP_SUCCESS on success,
+// otherwise the corresponding A2DP error status code.
+static tA2DP_STATUS A2DP_BuildInfoSbc(uint8_t media_type,
+                                      const tA2DP_SBC_CIE* p_ie,
+                                      uint8_t* p_result) {
+  tA2DP_STATUS status;
+
+  if (p_ie == NULL || p_result == NULL ||
+      (p_ie->samp_freq & ~A2DP_SBC_IE_SAMP_FREQ_MSK) ||
+      (p_ie->ch_mode & ~A2DP_SBC_IE_CH_MD_MSK) ||
+      (p_ie->block_len & ~A2DP_SBC_IE_BLOCKS_MSK) ||
+      (p_ie->num_subbands & ~A2DP_SBC_IE_SUBBAND_MSK) ||
+      (p_ie->alloc_method & ~A2DP_SBC_IE_ALLOC_MD_MSK) ||
+      (p_ie->min_bitpool > p_ie->max_bitpool) ||
+      (p_ie->min_bitpool < A2DP_SBC_IE_MIN_BITPOOL) ||
+      (p_ie->min_bitpool > A2DP_SBC_IE_MAX_BITPOOL) ||
+      (p_ie->max_bitpool < A2DP_SBC_IE_MIN_BITPOOL) ||
+      (p_ie->max_bitpool > A2DP_SBC_IE_MAX_BITPOOL)) {
+    /* if any unused bit is set */
+    status = A2DP_INVALID_PARAMS;
+  } else {
+    status = A2DP_SUCCESS;
+    *p_result++ = A2DP_SBC_INFO_LEN;
+    *p_result++ = (media_type << 4);
+    *p_result++ = A2DP_MEDIA_CT_SBC;
+
+    /* Media Codec Specific Information Element */
+    *p_result++ = p_ie->samp_freq | p_ie->ch_mode;
+
+    *p_result++ = p_ie->block_len | p_ie->num_subbands | p_ie->alloc_method;
+
+    *p_result++ = p_ie->min_bitpool;
+    *p_result = p_ie->max_bitpool;
+  }
+  return status;
+}
+
+// Parses the SBC Media Codec Capabilities byte sequence beginning from the
+// LOSC octet. The result is stored in |p_ie|. The byte sequence to parse is
+// |p_codec_info|. If |is_peer_src_codec_info| is true, the byte sequence is
+// for get capabilities response from a peer Source.
+// Returns A2DP_SUCCESS on success, otherwise the corresponding A2DP error
+// status code.
+static tA2DP_STATUS A2DP_ParseInfoSbc(tA2DP_SBC_CIE* p_ie,
+                                      const uint8_t* p_codec_info,
+                                      bool is_peer_src_codec_info) {
+  tA2DP_STATUS status = A2DP_SUCCESS;
+  uint8_t losc;
+  uint8_t media_type;
+  tA2DP_CODEC_TYPE codec_type;
+
+  if (p_ie == NULL || p_codec_info == NULL) return A2DP_INVALID_PARAMS;
+
+  // Check the codec capability length
+  losc = *p_codec_info++;
+  if (losc != A2DP_SBC_INFO_LEN) return A2DP_WRONG_CODEC;
+
+  media_type = (*p_codec_info++) >> 4;
+  codec_type = *p_codec_info++;
+  /* Check the Media Type and Media Codec Type */
+  if (media_type != AVDT_MEDIA_TYPE_AUDIO || codec_type != A2DP_MEDIA_CT_SBC) {
+    return A2DP_WRONG_CODEC;
+  }
+
+  p_ie->samp_freq = *p_codec_info & A2DP_SBC_IE_SAMP_FREQ_MSK;
+  p_ie->ch_mode = *p_codec_info & A2DP_SBC_IE_CH_MD_MSK;
+  p_codec_info++;
+  p_ie->block_len = *p_codec_info & A2DP_SBC_IE_BLOCKS_MSK;
+  p_ie->num_subbands = *p_codec_info & A2DP_SBC_IE_SUBBAND_MSK;
+  p_ie->alloc_method = *p_codec_info & A2DP_SBC_IE_ALLOC_MD_MSK;
+  p_codec_info++;
+  p_ie->min_bitpool = *p_codec_info++;
+  p_ie->max_bitpool = *p_codec_info;
+  if (p_ie->min_bitpool < A2DP_SBC_IE_MIN_BITPOOL ||
+      p_ie->min_bitpool > A2DP_SBC_IE_MAX_BITPOOL) {
+    status = A2DP_BAD_MIN_BITPOOL;
+  }
+
+  if (p_ie->max_bitpool < A2DP_SBC_IE_MIN_BITPOOL ||
+      p_ie->max_bitpool > A2DP_SBC_IE_MAX_BITPOOL ||
+      p_ie->max_bitpool < p_ie->min_bitpool) {
+    status = A2DP_BAD_MAX_BITPOOL;
+  }
+
+  if (is_peer_src_codec_info) return status;
+
+  if (A2DP_BitsSet(p_ie->samp_freq) != A2DP_SET_ONE_BIT)
+    status = A2DP_BAD_SAMP_FREQ;
+  if (A2DP_BitsSet(p_ie->ch_mode) != A2DP_SET_ONE_BIT)
+    status = A2DP_BAD_CH_MODE;
+  if (A2DP_BitsSet(p_ie->block_len) != A2DP_SET_ONE_BIT)
+    status = A2DP_BAD_BLOCK_LEN;
+  if (A2DP_BitsSet(p_ie->num_subbands) != A2DP_SET_ONE_BIT)
+    status = A2DP_BAD_SUBBANDS;
+  if (A2DP_BitsSet(p_ie->alloc_method) != A2DP_SET_ONE_BIT)
+    status = A2DP_BAD_ALLOC_METHOD;
+
+  return status;
+}
+
+/******************************************************************************
+**
+** Function         A2DP_BldSbcMplHdr
+**
+** Description      This function is called by an application to parse
+**                  the SBC Media Payload header.
+**                  Input Parameters:
+**                      frag:  1, if fragmented. 0, otherwise.
+**
+**                      start:  1, if the starting packet of a fragmented frame.
+**
+**                      last:  1, if the last packet of a fragmented frame.
+**
+**                      num:  If frag is 1, this is the number of remaining
+**                            fragments (including this fragment) of this frame.
+**                            If frag is 0, this is the number of frames in
+**                            this packet.
+**
+**                  Output Parameters:
+**                      p_dst:  the resulting media payload header byte
+**                              sequence.
+**
+** Returns          void.
+******************************************************************************/
+static void A2DP_BldSbcMplHdr(uint8_t* p_dst, bool frag, bool start, bool last,
+                              uint8_t num) {
+  if (p_dst == NULL) return;
+
+  *p_dst = 0;
+  if (frag) *p_dst |= A2DP_SBC_HDR_F_MSK;
+  if (start) *p_dst |= A2DP_SBC_HDR_S_MSK;
+  if (last) *p_dst |= A2DP_SBC_HDR_L_MSK;
+  *p_dst |= (A2DP_SBC_HDR_NUM_MSK & num);
+}
+
+/******************************************************************************
+**
+** Function         A2DP_ParseMplHeaderSbc
+**
+** Description      This function is called by an application to parse
+**                  the SBC Media Payload header.
+**                  Input Parameters:
+**                      p_src:  the byte sequence to parse..
+**
+**                  Output Parameters:
+**                      frag:  1, if fragmented. 0, otherwise.
+**
+**                      start:  1, if the starting packet of a fragmented frame.
+**
+**                      last:  1, if the last packet of a fragmented frame.
+**
+**                      num:  If frag is 1, this is the number of remaining
+**                            fragments
+**                            (including this fragment) of this frame.
+**                            If frag is 0, this is the number of frames in
+**                            this packet.
+**
+** Returns          void.
+******************************************************************************/
+UNUSED_ATTR static void A2DP_ParseMplHeaderSbc(uint8_t* p_src, bool* p_frag,
+                                               bool* p_start, bool* p_last,
+                                               uint8_t* p_num) {
+  if (p_src && p_frag && p_start && p_last && p_num) {
+    *p_frag = (*p_src & A2DP_SBC_HDR_F_MSK) ? true : false;
+    *p_start = (*p_src & A2DP_SBC_HDR_S_MSK) ? true : false;
+    *p_last = (*p_src & A2DP_SBC_HDR_L_MSK) ? true : false;
+    *p_num = (*p_src & A2DP_SBC_HDR_NUM_MSK);
+  }
+}
+
+const char* A2DP_CodecSepIndexStrSbc(void) {
+  return "SBC";
+}
+
+const char* A2DP_CodecSepIndexStrSbcSink(void) {
+  return "SBC SINK";
+}
+
+bool A2DP_InitCodecConfigSbc(tAVDT_CFG* p_cfg) {
+  if (A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &a2dp_sbc_caps,
+                        p_cfg->codec_info) != A2DP_SUCCESS) {
+    return false;
+  }
+
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+  /* Content protection info - support SCMS-T */
+  uint8_t* p = p_cfg->protect_info;
+  *p++ = AVDT_CP_LOSC;
+  UINT16_TO_STREAM(p, AVDT_CP_SCMS_T_ID);
+  p_cfg->num_protect = 1;
+#endif
+
+  return true;
+}
+
+const char* A2DP_CodecNameSbc(UNUSED_ATTR const uint8_t* p_codec_info) {
+  return "SBC";
+}
+
+bool A2DP_InitCodecConfigSbcSink(tAVDT_CFG* p_cfg) {
+  if (A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &a2dp_sbc_sink_caps,
+                        p_cfg->codec_info) != A2DP_SUCCESS) {
+    return false;
+  }
+
+  return true;
+}
+
+bool A2DP_IsSourceCodecValidSbc(const uint8_t* p_codec_info) {
+  tA2DP_SBC_CIE cfg_cie;
+
+  /* Use a liberal check when parsing the codec info */
+  return (A2DP_ParseInfoSbc(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+         (A2DP_ParseInfoSbc(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsSinkCodecValidSbc(const uint8_t* p_codec_info) {
+  tA2DP_SBC_CIE cfg_cie;
+
+  /* Use a liberal check when parsing the codec info */
+  return (A2DP_ParseInfoSbc(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+         (A2DP_ParseInfoSbc(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsPeerSourceCodecValidSbc(const uint8_t* p_codec_info) {
+  tA2DP_SBC_CIE cfg_cie;
+
+  /* Use a liberal check when parsing the codec info */
+  return (A2DP_ParseInfoSbc(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+         (A2DP_ParseInfoSbc(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsPeerSinkCodecValidSbc(const uint8_t* p_codec_info) {
+  tA2DP_SBC_CIE cfg_cie;
+
+  /* Use a liberal check when parsing the codec info */
+  return (A2DP_ParseInfoSbc(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+         (A2DP_ParseInfoSbc(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsSourceCodecSupportedSbc(const uint8_t* p_codec_info) {
+  return (A2DP_CodecInfoMatchesCapabilitySbc(&a2dp_sbc_caps, p_codec_info,
+                                             false) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsSinkCodecSupportedSbc(const uint8_t* p_codec_info) {
+  return (A2DP_CodecInfoMatchesCapabilitySbc(&a2dp_sbc_sink_caps, p_codec_info,
+                                             false) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsPeerSourceCodecSupportedSbc(const uint8_t* p_codec_info) {
+  return (A2DP_CodecInfoMatchesCapabilitySbc(&a2dp_sbc_sink_caps, p_codec_info,
+                                             true) == A2DP_SUCCESS);
+}
+
+void A2DP_InitDefaultCodecSbc(uint8_t* p_codec_info) {
+  if (A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &a2dp_sbc_default_config,
+                        p_codec_info) != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: A2DP_BuildInfoSbc failed", __func__);
+  }
+}
+
+bool A2DP_SetSourceCodecSbc(const tA2DP_FEEDING_PARAMS* p_feeding_params,
+                            uint8_t* p_codec_info) {
+  tA2DP_SBC_CIE sbc_config = a2dp_sbc_default_config;
+
+  LOG_VERBOSE(LOG_TAG, "%s", __func__);
+
+  /* Check the number of channels */
+  if ((p_feeding_params->num_channel != 1) &&
+      (p_feeding_params->num_channel != 2)) {
+    LOG_ERROR(LOG_TAG, "%s: Unsupported PCM channel number %d", __func__,
+              p_feeding_params->num_channel);
+    return false;
+  }
+
+  /* Check the bits per sample */
+  if ((p_feeding_params->bit_per_sample != 8) &&
+      (p_feeding_params->bit_per_sample != 16)) {
+    LOG_ERROR(LOG_TAG, "%s: Unsupported PCM sample size %d", __func__,
+              p_feeding_params->bit_per_sample);
+    return false;
+  }
+
+  /* Check the sampling frequency */
+  switch (p_feeding_params->sampling_freq) {
+    case 8000:
+    case 12000:
+    case 16000:
+    case 24000:
+    case 32000:
+    case 48000:
+      sbc_config.samp_freq = A2DP_SBC_IE_SAMP_FREQ_48;
+      break;
+    case 11025:
+    case 22050:
+    case 44100:
+      sbc_config.samp_freq = A2DP_SBC_IE_SAMP_FREQ_44;
+      break;
+    default:
+      LOG_ERROR(LOG_TAG, "%s: Unsupported PCM sampling frequency %d", __func__,
+                p_feeding_params->sampling_freq);
+      return false;
+  }
+
+  /* Build the codec config */
+  if (A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &sbc_config, p_codec_info) !=
+      A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: A2DP_BuildInfoSbc failed", __func__);
+    return false;
+  }
+
+  return true;
+}
+
+// Checks whether A2DP SBC codec configuration matches with a device's codec
+// capabilities. |p_cap| is the SBC codec configuration. |p_codec_info| is
+// the device's codec capabilities. |is_peer_src_codec_info| is true if
+// |p_codec_info| contains the codec capabilities for a peer device that
+// is acting as an A2DP source.
+// Returns A2DP_SUCCESS if the codec configuration matches with capabilities,
+// otherwise the corresponding A2DP error status code.
+static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilitySbc(
+    const tA2DP_SBC_CIE* p_cap, const uint8_t* p_codec_info,
+    bool is_peer_src_codec_info) {
+  tA2DP_STATUS status;
+  tA2DP_SBC_CIE cfg_cie;
+
+  /* parse configuration */
+  status = A2DP_ParseInfoSbc(&cfg_cie, p_codec_info, is_peer_src_codec_info);
+  if (status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: parsing failed %d", __func__, status);
+    return status;
+  }
+
+  /* verify that each parameter is in range */
+
+  LOG_DEBUG(LOG_TAG, "FREQ peer: 0x%x, capability 0x%x", cfg_cie.samp_freq,
+            p_cap->samp_freq);
+  LOG_DEBUG(LOG_TAG, "CH_MODE peer: 0x%x, capability 0x%x", cfg_cie.ch_mode,
+            p_cap->ch_mode);
+  LOG_DEBUG(LOG_TAG, "BLOCK_LEN peer: 0x%x, capability 0x%x", cfg_cie.block_len,
+            p_cap->block_len);
+  LOG_DEBUG(LOG_TAG, "SUB_BAND peer: 0x%x, capability 0x%x",
+            cfg_cie.num_subbands, p_cap->num_subbands);
+  LOG_DEBUG(LOG_TAG, "ALLOC_METHOD peer: 0x%x, capability 0x%x",
+            cfg_cie.alloc_method, p_cap->alloc_method);
+  LOG_DEBUG(LOG_TAG, "MIN_BitPool peer: 0x%x, capability 0x%x",
+            cfg_cie.min_bitpool, p_cap->min_bitpool);
+  LOG_DEBUG(LOG_TAG, "MAX_BitPool peer: 0x%x, capability 0x%x",
+            cfg_cie.max_bitpool, p_cap->max_bitpool);
+
+  /* sampling frequency */
+  if ((cfg_cie.samp_freq & p_cap->samp_freq) == 0) return A2DP_NS_SAMP_FREQ;
+
+  /* channel mode */
+  if ((cfg_cie.ch_mode & p_cap->ch_mode) == 0) return A2DP_NS_CH_MODE;
+
+  /* block length */
+  if ((cfg_cie.block_len & p_cap->block_len) == 0) return A2DP_BAD_BLOCK_LEN;
+
+  /* subbands */
+  if ((cfg_cie.num_subbands & p_cap->num_subbands) == 0)
+    return A2DP_NS_SUBBANDS;
+
+  /* allocation method */
+  if ((cfg_cie.alloc_method & p_cap->alloc_method) == 0)
+    return A2DP_NS_ALLOC_METHOD;
+
+  /* min bitpool */
+  if (cfg_cie.min_bitpool < p_cap->min_bitpool) return A2DP_NS_MIN_BITPOOL;
+
+  /* max bitpool */
+  if (cfg_cie.max_bitpool > p_cap->max_bitpool) return A2DP_NS_MAX_BITPOOL;
+
+  return A2DP_SUCCESS;
+}
+
+tA2DP_STATUS A2DP_BuildSrc2SinkConfigSbc(const uint8_t* p_src_cap,
+                                         uint8_t* p_pref_cfg) {
+  tA2DP_SBC_CIE src_cap;
+  tA2DP_SBC_CIE pref_cap;
+
+  /* initialize it to default SBC configuration */
+  A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &a2dp_sbc_default_config,
+                    p_pref_cfg);
+
+  /* now try to build a preferred one */
+  /* parse configuration */
+  tA2DP_STATUS status = A2DP_ParseInfoSbc(&src_cap, p_src_cap, true);
+  if (status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: can't parse src cap ret = %d", __func__, status);
+    return A2DP_FAIL;
+  }
+
+  if (src_cap.samp_freq & A2DP_SBC_IE_SAMP_FREQ_48)
+    pref_cap.samp_freq = A2DP_SBC_IE_SAMP_FREQ_48;
+  else if (src_cap.samp_freq & A2DP_SBC_IE_SAMP_FREQ_44)
+    pref_cap.samp_freq = A2DP_SBC_IE_SAMP_FREQ_44;
+
+  if (src_cap.ch_mode & A2DP_SBC_IE_CH_MD_JOINT)
+    pref_cap.ch_mode = A2DP_SBC_IE_CH_MD_JOINT;
+  else if (src_cap.ch_mode & A2DP_SBC_IE_CH_MD_STEREO)
+    pref_cap.ch_mode = A2DP_SBC_IE_CH_MD_STEREO;
+  else if (src_cap.ch_mode & A2DP_SBC_IE_CH_MD_DUAL)
+    pref_cap.ch_mode = A2DP_SBC_IE_CH_MD_DUAL;
+  else if (src_cap.ch_mode & A2DP_SBC_IE_CH_MD_MONO)
+    pref_cap.ch_mode = A2DP_SBC_IE_CH_MD_MONO;
+
+  if (src_cap.block_len & A2DP_SBC_IE_BLOCKS_16)
+    pref_cap.block_len = A2DP_SBC_IE_BLOCKS_16;
+  else if (src_cap.block_len & A2DP_SBC_IE_BLOCKS_12)
+    pref_cap.block_len = A2DP_SBC_IE_BLOCKS_12;
+  else if (src_cap.block_len & A2DP_SBC_IE_BLOCKS_8)
+    pref_cap.block_len = A2DP_SBC_IE_BLOCKS_8;
+  else if (src_cap.block_len & A2DP_SBC_IE_BLOCKS_4)
+    pref_cap.block_len = A2DP_SBC_IE_BLOCKS_4;
+
+  if (src_cap.num_subbands & A2DP_SBC_IE_SUBBAND_8)
+    pref_cap.num_subbands = A2DP_SBC_IE_SUBBAND_8;
+  else if (src_cap.num_subbands & A2DP_SBC_IE_SUBBAND_4)
+    pref_cap.num_subbands = A2DP_SBC_IE_SUBBAND_4;
+
+  if (src_cap.alloc_method & A2DP_SBC_IE_ALLOC_MD_L)
+    pref_cap.alloc_method = A2DP_SBC_IE_ALLOC_MD_L;
+  else if (src_cap.alloc_method & A2DP_SBC_IE_ALLOC_MD_S)
+    pref_cap.alloc_method = A2DP_SBC_IE_ALLOC_MD_S;
+
+  pref_cap.min_bitpool = src_cap.min_bitpool;
+  pref_cap.max_bitpool = src_cap.max_bitpool;
+
+  A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &pref_cap, p_pref_cfg);
+
+  return A2DP_SUCCESS;
+}
+
+tA2DP_STATUS A2DP_BuildSinkConfigSbc(const uint8_t* p_src_config,
+                                     const uint8_t* p_sink_cap,
+                                     uint8_t* p_result_sink_config) {
+  tA2DP_SBC_CIE src_config_cie;
+  tA2DP_SBC_CIE sink_cap_cie;
+
+  /* Decode the source codec config */
+  tA2DP_STATUS a2dp_status =
+      A2DP_ParseInfoSbc(&src_config_cie, p_src_config, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode source codec information: %d",
+              __func__, a2dp_status);
+    return A2DP_FAIL;
+  }
+
+  /* Decode the sink codec capabilities */
+  a2dp_status = A2DP_ParseInfoSbc(&sink_cap_cie, p_sink_cap, true);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode sink capability information: %d",
+              __func__, a2dp_status);
+    return A2DP_FAIL;
+  }
+
+  /* Update the bitpool boundaries from the sink codec capabilities */
+  src_config_cie.min_bitpool = sink_cap_cie.min_bitpool;
+  src_config_cie.max_bitpool = sink_cap_cie.max_bitpool;
+
+  /* Build the result sink config from the source config */
+  A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &src_config_cie,
+                    p_result_sink_config);
+
+  return A2DP_SUCCESS;
+}
+
+bool A2DP_CodecTypeEqualsSbc(const uint8_t* p_codec_info_a,
+                             const uint8_t* p_codec_info_b) {
+  tA2DP_SBC_CIE sbc_cie_a;
+  tA2DP_SBC_CIE sbc_cie_b;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status =
+      A2DP_ParseInfoSbc(&sbc_cie_a, p_codec_info_a, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return false;
+  }
+  a2dp_status = A2DP_ParseInfoSbc(&sbc_cie_b, p_codec_info_b, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return false;
+  }
+
+  tA2DP_CODEC_TYPE codec_type_a = A2DP_GetCodecType(p_codec_info_a);
+  tA2DP_CODEC_TYPE codec_type_b = A2DP_GetCodecType(p_codec_info_b);
+
+  return (codec_type_a == codec_type_b) && (codec_type_a == A2DP_MEDIA_CT_SBC);
+}
+
+bool A2DP_CodecEqualsSbc(const uint8_t* p_codec_info_a,
+                         const uint8_t* p_codec_info_b) {
+  tA2DP_SBC_CIE sbc_cie_a;
+  tA2DP_SBC_CIE sbc_cie_b;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status =
+      A2DP_ParseInfoSbc(&sbc_cie_a, p_codec_info_a, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return false;
+  }
+  a2dp_status = A2DP_ParseInfoSbc(&sbc_cie_b, p_codec_info_b, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return false;
+  }
+
+  tA2DP_CODEC_TYPE codec_type_a = A2DP_GetCodecType(p_codec_info_a);
+  tA2DP_CODEC_TYPE codec_type_b = A2DP_GetCodecType(p_codec_info_b);
+
+  if ((codec_type_a != codec_type_b) || (codec_type_a != A2DP_MEDIA_CT_SBC))
+    return false;
+
+  return (sbc_cie_a.samp_freq == sbc_cie_b.samp_freq) &&
+         (sbc_cie_a.ch_mode == sbc_cie_b.ch_mode) &&
+         (sbc_cie_a.block_len == sbc_cie_b.block_len) &&
+         (sbc_cie_a.num_subbands == sbc_cie_b.num_subbands) &&
+         (sbc_cie_a.alloc_method == sbc_cie_b.alloc_method) &&
+         (sbc_cie_a.min_bitpool == sbc_cie_b.min_bitpool) &&
+         (sbc_cie_a.max_bitpool == sbc_cie_b.max_bitpool);
+}
+
+bool A2DP_CodecRequiresReconfigSbc(const uint8_t* p_codec_info_a,
+                                   const uint8_t* p_codec_info_b) {
+  tA2DP_SBC_CIE sbc_cie_a;
+  tA2DP_SBC_CIE sbc_cie_b;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status =
+      A2DP_ParseInfoSbc(&sbc_cie_a, p_codec_info_a, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return true;
+  }
+  a2dp_status = A2DP_ParseInfoSbc(&sbc_cie_b, p_codec_info_b, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return true;
+  }
+
+  tA2DP_CODEC_TYPE codec_type_a = A2DP_GetCodecType(p_codec_info_a);
+  tA2DP_CODEC_TYPE codec_type_b = A2DP_GetCodecType(p_codec_info_b);
+
+  if ((codec_type_a != codec_type_b) || (codec_type_a != A2DP_MEDIA_CT_SBC))
+    return true;
+
+  /* NOTE: The min_bitpool and max_bitpool fields are ignored */
+  return (sbc_cie_a.samp_freq != sbc_cie_b.samp_freq) ||
+         (sbc_cie_a.ch_mode != sbc_cie_b.ch_mode) ||
+         (sbc_cie_a.block_len != sbc_cie_b.block_len) ||
+         (sbc_cie_a.num_subbands != sbc_cie_b.num_subbands) ||
+         (sbc_cie_a.alloc_method != sbc_cie_b.alloc_method);
+}
+
+bool A2DP_CodecConfigMatchesCapabilitiesSbc(const uint8_t* p_codec_config,
+                                            const uint8_t* p_codec_caps) {
+  tA2DP_SBC_CIE sbc_cie_config;
+  tA2DP_SBC_CIE sbc_cie_caps;
+
+  // Check whether the codec info contains valid data
+  tA2DP_STATUS a2dp_status =
+      A2DP_ParseInfoSbc(&sbc_cie_config, p_codec_config, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec config: %d", __func__,
+              a2dp_status);
+    return false;
+  }
+  a2dp_status = A2DP_ParseInfoSbc(&sbc_cie_caps, p_codec_caps, true);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec capabilities: %d", __func__,
+              a2dp_status);
+    return false;
+  }
+
+  /*
+   * Must match all SBC codec fields except min/max bitpool boundaries which
+   * can be adjusted.
+   */
+  bool result = (sbc_cie_config.samp_freq & sbc_cie_caps.samp_freq) &&
+                (sbc_cie_config.ch_mode & sbc_cie_caps.ch_mode) &&
+                (sbc_cie_config.block_len & sbc_cie_caps.block_len) &&
+                (sbc_cie_config.num_subbands & sbc_cie_caps.num_subbands) &&
+                (sbc_cie_config.alloc_method & sbc_cie_caps.alloc_method);
+
+  LOG_DEBUG(LOG_TAG, "%s: result=%s", __func__, result ? "true" : "false");
+  LOG_DEBUG(LOG_TAG,
+            "%s: config samp_freq=0x%x ch_mode=0x%x "
+            "block_len=0x%x num_subbands=0x%x alloc_method=0x%x",
+            __func__, sbc_cie_config.samp_freq, sbc_cie_config.ch_mode,
+            sbc_cie_config.block_len, sbc_cie_config.num_subbands,
+            sbc_cie_config.alloc_method);
+  LOG_DEBUG(LOG_TAG,
+            "%s: caps   samp_freq=0x%x ch_mode=0x%x "
+            "block_len=0x%x num_subbands=0x%x alloc_method=0x%x",
+            __func__, sbc_cie_caps.samp_freq, sbc_cie_caps.ch_mode,
+            sbc_cie_caps.block_len, sbc_cie_caps.num_subbands,
+            sbc_cie_caps.alloc_method);
+
+  return result;
+}
+
+int A2DP_GetTrackFrequencySbc(const uint8_t* p_codec_info) {
+  tA2DP_SBC_CIE sbc_cie;
+
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  switch (sbc_cie.samp_freq) {
+    case A2DP_SBC_IE_SAMP_FREQ_16:
+      return 16000;
+    case A2DP_SBC_IE_SAMP_FREQ_32:
+      return 32000;
+    case A2DP_SBC_IE_SAMP_FREQ_44:
+      return 44100;
+    case A2DP_SBC_IE_SAMP_FREQ_48:
+      return 48000;
+    default:
+      break;
+  }
+
+  return -1;
+}
+
+int A2DP_GetTrackChannelCountSbc(const uint8_t* p_codec_info) {
+  tA2DP_SBC_CIE sbc_cie;
+
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  switch (sbc_cie.ch_mode) {
+    case A2DP_SBC_IE_CH_MD_MONO:
+      return 1;
+    case A2DP_SBC_IE_CH_MD_DUAL:
+    case A2DP_SBC_IE_CH_MD_STEREO:
+    case A2DP_SBC_IE_CH_MD_JOINT:
+      return 2;
+    default:
+      break;
+  }
+
+  return -1;
+}
+
+int A2DP_GetNumberOfSubbandsSbc(const uint8_t* p_codec_info) {
+  tA2DP_SBC_CIE sbc_cie;
+
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  switch (sbc_cie.num_subbands) {
+    case A2DP_SBC_IE_SUBBAND_4:
+      return 4;
+    case A2DP_SBC_IE_SUBBAND_8:
+      return 8;
+    default:
+      break;
+  }
+
+  return -1;
+}
+
+int A2DP_GetNumberOfBlocksSbc(const uint8_t* p_codec_info) {
+  tA2DP_SBC_CIE sbc_cie;
+
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  switch (sbc_cie.block_len) {
+    case A2DP_SBC_IE_BLOCKS_4:
+      return 4;
+    case A2DP_SBC_IE_BLOCKS_8:
+      return 8;
+    case A2DP_SBC_IE_BLOCKS_12:
+      return 12;
+    case A2DP_SBC_IE_BLOCKS_16:
+      return 16;
+    default:
+      break;
+  }
+
+  return -1;
+}
+
+int A2DP_GetAllocationMethodCodeSbc(const uint8_t* p_codec_info) {
+  tA2DP_SBC_CIE sbc_cie;
+
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  switch (sbc_cie.alloc_method) {
+    case A2DP_SBC_IE_ALLOC_MD_S:
+      return SBC_SNR;
+    case A2DP_SBC_IE_ALLOC_MD_L:
+      return SBC_LOUDNESS;
+    default:
+      break;
+  }
+
+  return -1;
+}
+
+int A2DP_GetChannelModeCodeSbc(const uint8_t* p_codec_info) {
+  tA2DP_SBC_CIE sbc_cie;
+
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  switch (sbc_cie.ch_mode) {
+    case A2DP_SBC_IE_CH_MD_MONO:
+      return SBC_MONO;
+    case A2DP_SBC_IE_CH_MD_DUAL:
+      return SBC_DUAL;
+    case A2DP_SBC_IE_CH_MD_STEREO:
+      return SBC_STEREO;
+    case A2DP_SBC_IE_CH_MD_JOINT:
+      return SBC_JOINT_STEREO;
+    default:
+      break;
+  }
+
+  return -1;
+}
+
+int A2DP_GetSamplingFrequencyCodeSbc(const uint8_t* p_codec_info) {
+  tA2DP_SBC_CIE sbc_cie;
+
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  switch (sbc_cie.samp_freq) {
+    case A2DP_SBC_IE_SAMP_FREQ_16:
+      return SBC_sf16000;
+    case A2DP_SBC_IE_SAMP_FREQ_32:
+      return SBC_sf32000;
+    case A2DP_SBC_IE_SAMP_FREQ_44:
+      return SBC_sf44100;
+    case A2DP_SBC_IE_SAMP_FREQ_48:
+      return SBC_sf48000;
+    default:
+      break;
+  }
+
+  return -1;
+}
+
+int A2DP_GetMinBitpoolSbc(const uint8_t* p_codec_info) {
+  tA2DP_SBC_CIE sbc_cie;
+
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  return sbc_cie.min_bitpool;
+}
+
+int A2DP_GetMaxBitpoolSbc(const uint8_t* p_codec_info) {
+  tA2DP_SBC_CIE sbc_cie;
+
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  return sbc_cie.max_bitpool;
+}
+
+int A2DP_GetSinkTrackChannelTypeSbc(const uint8_t* p_codec_info) {
+  tA2DP_SBC_CIE sbc_cie;
+
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  switch (sbc_cie.ch_mode) {
+    case A2DP_SBC_IE_CH_MD_MONO:
+      return 1;
+    case A2DP_SBC_IE_CH_MD_DUAL:
+    case A2DP_SBC_IE_CH_MD_STEREO:
+    case A2DP_SBC_IE_CH_MD_JOINT:
+      return 3;
+    default:
+      break;
+  }
+
+  return -1;
+}
+
+int A2DP_GetSinkFramesCountToProcessSbc(uint64_t time_interval_ms,
+                                        const uint8_t* p_codec_info) {
+  tA2DP_SBC_CIE sbc_cie;
+  uint32_t freq_multiple;
+  uint32_t num_blocks;
+  uint32_t num_subbands;
+  int frames_to_process;
+
+  tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+              a2dp_status);
+    return -1;
+  }
+
+  // Check the sample frequency
+  switch (sbc_cie.samp_freq) {
+    case A2DP_SBC_IE_SAMP_FREQ_16:
+      LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (16000)", __func__,
+                  sbc_cie.samp_freq);
+      freq_multiple = 16 * time_interval_ms;
+      break;
+    case A2DP_SBC_IE_SAMP_FREQ_32:
+      LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (32000)", __func__,
+                  sbc_cie.samp_freq);
+      freq_multiple = 32 * time_interval_ms;
+      break;
+    case A2DP_SBC_IE_SAMP_FREQ_44:
+      LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (44100)", __func__,
+                  sbc_cie.samp_freq);
+      freq_multiple = (441 * time_interval_ms) / 10;
+      break;
+    case A2DP_SBC_IE_SAMP_FREQ_48:
+      LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (48000)", __func__,
+                  sbc_cie.samp_freq);
+      freq_multiple = 48 * time_interval_ms;
+      break;
+    default:
+      LOG_ERROR(LOG_TAG, "%s: unknown frequency: %d", __func__,
+                sbc_cie.samp_freq);
+      return -1;
+  }
+
+  // Check the channel mode
+  switch (sbc_cie.ch_mode) {
+    case A2DP_SBC_IE_CH_MD_MONO:
+      LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (Mono)", __func__, sbc_cie.ch_mode);
+      break;
+    case A2DP_SBC_IE_CH_MD_DUAL:
+      LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (DUAL)", __func__, sbc_cie.ch_mode);
+      break;
+    case A2DP_SBC_IE_CH_MD_STEREO:
+      LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (STEREO)", __func__,
+                  sbc_cie.ch_mode);
+      break;
+    case A2DP_SBC_IE_CH_MD_JOINT:
+      LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (JOINT)", __func__, sbc_cie.ch_mode);
+      break;
+    default:
+      LOG_ERROR(LOG_TAG, "%s: unknown channel mode: %d", __func__,
+                sbc_cie.ch_mode);
+      return -1;
+  }
+
+  // Check the block length
+  switch (sbc_cie.block_len) {
+    case A2DP_SBC_IE_BLOCKS_4:
+      LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (4)", __func__, sbc_cie.block_len);
+      num_blocks = 4;
+      break;
+    case A2DP_SBC_IE_BLOCKS_8:
+      LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (8)", __func__, sbc_cie.block_len);
+      num_blocks = 8;
+      break;
+    case A2DP_SBC_IE_BLOCKS_12:
+      LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (12)", __func__,
+                  sbc_cie.block_len);
+      num_blocks = 12;
+      break;
+    case A2DP_SBC_IE_BLOCKS_16:
+      LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (16)", __func__,
+                  sbc_cie.block_len);
+      num_blocks = 16;
+      break;
+    default:
+      LOG_ERROR(LOG_TAG, "%s: unknown block length: %d", __func__,
+                sbc_cie.block_len);
+      return -1;
+  }
+
+  // Check the number of sub-bands
+  switch (sbc_cie.num_subbands) {
+    case A2DP_SBC_IE_SUBBAND_4:
+      LOG_VERBOSE(LOG_TAG, "%s: num_subbands:%d (4)", __func__,
+                  sbc_cie.num_subbands);
+      num_subbands = 4;
+      break;
+    case A2DP_SBC_IE_SUBBAND_8:
+      LOG_VERBOSE(LOG_TAG, "%s: num_subbands:%d (8)", __func__,
+                  sbc_cie.num_subbands);
+      num_subbands = 8;
+      break;
+    default:
+      LOG_ERROR(LOG_TAG, "%s: unknown number of subbands: %d", __func__,
+                sbc_cie.num_subbands);
+      return -1;
+  }
+
+  // Check the allocation method
+  switch (sbc_cie.alloc_method) {
+    case A2DP_SBC_IE_ALLOC_MD_S:
+      LOG_VERBOSE(LOG_TAG, "%s: alloc_method:%d (SNR)", __func__,
+                  sbc_cie.alloc_method);
+      break;
+    case A2DP_SBC_IE_ALLOC_MD_L:
+      LOG_VERBOSE(LOG_TAG, "%s: alloc_method:%d (Loudness)", __func__,
+                  sbc_cie.alloc_method);
+      break;
+    default:
+      LOG_ERROR(LOG_TAG, "%s: unknown allocation method: %d", __func__,
+                sbc_cie.alloc_method);
+      return -1;
+  }
+
+  LOG_VERBOSE(LOG_TAG, "%s: Bit pool Min:%d Max:%d", __func__,
+              sbc_cie.min_bitpool, sbc_cie.max_bitpool);
+
+  frames_to_process = ((freq_multiple) / (num_blocks * num_subbands)) + 1;
+
+  return frames_to_process;
+}
+
+bool A2DP_GetPacketTimestampSbc(UNUSED_ATTR const uint8_t* p_codec_info,
+                                const uint8_t* p_data, uint32_t* p_timestamp) {
+  *p_timestamp = *(const uint32_t*)p_data;
+  return true;
+}
+
+bool A2DP_BuildCodecHeaderSbc(UNUSED_ATTR const uint8_t* p_codec_info,
+                              BT_HDR* p_buf, uint16_t frames_per_packet) {
+  uint8_t* p;
+
+  p_buf->offset -= A2DP_SBC_MPL_HDR_LEN;
+  p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+  p_buf->len += A2DP_SBC_MPL_HDR_LEN;
+  A2DP_BldSbcMplHdr(p, false, false, false, (uint8_t)frames_per_packet);
+
+  return true;
+}
+
+void A2DP_DumpCodecInfoSbc(const uint8_t* p_codec_info) {
+  tA2DP_STATUS a2dp_status;
+  tA2DP_SBC_CIE sbc_cie;
+
+  LOG_DEBUG(LOG_TAG, "%s", __func__);
+
+  a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+  if (a2dp_status != A2DP_SUCCESS) {
+    LOG_ERROR(LOG_TAG, "%s: A2DP_ParseInfoSbc fail:%d", __func__, a2dp_status);
+    return;
+  }
+
+  if (sbc_cie.samp_freq == A2DP_SBC_IE_SAMP_FREQ_16) {
+    LOG_DEBUG(LOG_TAG, "\tsamp_freq:%d (16000)", sbc_cie.samp_freq);
+  } else if (sbc_cie.samp_freq == A2DP_SBC_IE_SAMP_FREQ_32) {
+    LOG_DEBUG(LOG_TAG, "\tsamp_freq:%d (32000)", sbc_cie.samp_freq);
+  } else if (sbc_cie.samp_freq == A2DP_SBC_IE_SAMP_FREQ_44) {
+    LOG_DEBUG(LOG_TAG, "\tsamp_freq:%d (44.100)", sbc_cie.samp_freq);
+  } else if (sbc_cie.samp_freq == A2DP_SBC_IE_SAMP_FREQ_48) {
+    LOG_DEBUG(LOG_TAG, "\tsamp_freq:%d (48000)", sbc_cie.samp_freq);
+  } else {
+    LOG_DEBUG(LOG_TAG, "\tBAD samp_freq:%d", sbc_cie.samp_freq);
+  }
+
+  if (sbc_cie.ch_mode == A2DP_SBC_IE_CH_MD_MONO) {
+    LOG_DEBUG(LOG_TAG, "\tch_mode:%d (Mono)", sbc_cie.ch_mode);
+  } else if (sbc_cie.ch_mode == A2DP_SBC_IE_CH_MD_DUAL) {
+    LOG_DEBUG(LOG_TAG, "\tch_mode:%d (Dual)", sbc_cie.ch_mode);
+  } else if (sbc_cie.ch_mode == A2DP_SBC_IE_CH_MD_STEREO) {
+    LOG_DEBUG(LOG_TAG, "\tch_mode:%d (Stereo)", sbc_cie.ch_mode);
+  } else if (sbc_cie.ch_mode == A2DP_SBC_IE_CH_MD_JOINT) {
+    LOG_DEBUG(LOG_TAG, "\tch_mode:%d (Joint)", sbc_cie.ch_mode);
+  } else {
+    LOG_DEBUG(LOG_TAG, "\tBAD ch_mode:%d", sbc_cie.ch_mode);
+  }
+
+  if (sbc_cie.block_len == A2DP_SBC_IE_BLOCKS_4) {
+    LOG_DEBUG(LOG_TAG, "\tblock_len:%d (4)", sbc_cie.block_len);
+  } else if (sbc_cie.block_len == A2DP_SBC_IE_BLOCKS_8) {
+    LOG_DEBUG(LOG_TAG, "\tblock_len:%d (8)", sbc_cie.block_len);
+  } else if (sbc_cie.block_len == A2DP_SBC_IE_BLOCKS_12) {
+    LOG_DEBUG(LOG_TAG, "\tblock_len:%d (12)", sbc_cie.block_len);
+  } else if (sbc_cie.block_len == A2DP_SBC_IE_BLOCKS_16) {
+    LOG_DEBUG(LOG_TAG, "\tblock_len:%d (16)", sbc_cie.block_len);
+  } else {
+    LOG_DEBUG(LOG_TAG, "\tBAD block_len:%d", sbc_cie.block_len);
+  }
+
+  if (sbc_cie.num_subbands == A2DP_SBC_IE_SUBBAND_4) {
+    LOG_DEBUG(LOG_TAG, "\tnum_subbands:%d (4)", sbc_cie.num_subbands);
+  } else if (sbc_cie.num_subbands == A2DP_SBC_IE_SUBBAND_8) {
+    LOG_DEBUG(LOG_TAG, "\tnum_subbands:%d (8)", sbc_cie.num_subbands);
+  } else {
+    LOG_DEBUG(LOG_TAG, "\tBAD num_subbands:%d", sbc_cie.num_subbands);
+  }
+
+  if (sbc_cie.alloc_method == A2DP_SBC_IE_ALLOC_MD_S) {
+    LOG_DEBUG(LOG_TAG, "\talloc_method:%d (SNR)", sbc_cie.alloc_method);
+  } else if (sbc_cie.alloc_method == A2DP_SBC_IE_ALLOC_MD_L) {
+    LOG_DEBUG(LOG_TAG, "\talloc_method:%d (Loundess)", sbc_cie.alloc_method);
+  } else {
+    LOG_DEBUG(LOG_TAG, "\tBAD alloc_method:%d", sbc_cie.alloc_method);
+  }
+
+  LOG_DEBUG(LOG_TAG, "\tBit pool Min:%d Max:%d", sbc_cie.min_bitpool,
+            sbc_cie.max_bitpool);
+}
+
+const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterfaceSbc(
+    const uint8_t* p_codec_info) {
+  if (!A2DP_IsSourceCodecValidSbc(p_codec_info)) return NULL;
+
+  return &a2dp_encoder_interface_sbc;
+}
+
+bool A2DP_AdjustCodecSbc(uint8_t* p_codec_info) {
+  tA2DP_SBC_CIE cfg_cie;
+
+  if (A2DP_ParseInfoSbc(&cfg_cie, p_codec_info, false) != A2DP_SUCCESS)
+    return false;
+
+  // Updated the max bitpool
+  if (cfg_cie.max_bitpool > A2DP_SBC_MAX_BITPOOL) {
+    LOG_WARN(LOG_TAG, "Updated the SBC codec max bitpool from %d to %d",
+             cfg_cie.max_bitpool, A2DP_SBC_MAX_BITPOOL);
+    cfg_cie.max_bitpool = A2DP_SBC_MAX_BITPOOL;
+  }
+
+  return (A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &cfg_cie, p_codec_info) ==
+          A2DP_SUCCESS);
+}
diff --git a/bt/stack/a2dp/a2dp_sbc_encoder.cc b/bt/stack/a2dp/a2dp_sbc_encoder.cc
new file mode 100644
index 0000000..1869243
--- /dev/null
+++ b/bt/stack/a2dp/a2dp_sbc_encoder.cc
@@ -0,0 +1,938 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "a2dp_sbc_encoder"
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "a2dp_api.h"
+#include "a2dp_sbc.h"
+#include "a2dp_sbc_encoder.h"
+#include "a2dp_sbc_up_sample.h"
+#include "bt_common.h"
+#include "embdrv/sbc/encoder/include/sbc_encoder.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#define STATS_UPDATE_MAX(current_value_storage, new_value) \
+  do {                                                     \
+    if ((new_value) > (current_value_storage))             \
+      (current_value_storage) = (new_value);               \
+  } while (0)
+
+/* Buffer pool */
+#define A2DP_SBC_BUFFER_SIZE BT_DEFAULT_BUFFER_SIZE
+
+// A2DP SBC encoder interval in milliseconds.
+#define A2DP_SBC_ENCODER_INTERVAL_MS 20
+
+/* High quality quality setting @ 44.1 khz */
+#define A2DP_SBC_DEFAULT_BITRATE 328
+
+#define A2DP_SBC_NON_EDR_MAX_RATE 229
+
+/*
+ * 2DH5 payload size of:
+ * 679 bytes - (4 bytes L2CAP Header + 12 bytes AVDTP Header)
+ */
+#define MAX_2MBPS_AVDTP_MTU 663
+#define A2DP_SBC_MAX_PCM_ITER_NUM_PER_TICK 3
+
+#define A2DP_SBC_MAX_HQ_FRAME_SIZE_44_1 119
+#define A2DP_SBC_MAX_HQ_FRAME_SIZE_48 115
+
+/* Define the bitrate step when trying to match bitpool value */
+#define A2DP_SBC_BITRATE_STEP 5
+
+/* Readability constants */
+#define A2DP_SBC_FRAME_HEADER_SIZE_BYTES 4  // A2DP Spec v1.3, 12.4, Table 12.12
+#define A2DP_SBC_SCALE_FACTOR_BITS 4        // A2DP Spec v1.3, 12.4, Table 12.13
+
+/* offset */
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+/* A2DP header will contain a CP header of size 1 */
+#define A2DP_HDR_SIZE 2
+#define A2DP_SBC_OFFSET (AVDT_MEDIA_OFFSET + A2DP_SBC_MPL_HDR_LEN + 1)
+#else
+#define A2DP_HDR_SIZE 1
+#define A2DP_SBC_OFFSET (AVDT_MEDIA_OFFSET + A2DP_SBC_MPL_HDR_LEN)
+#endif
+
+typedef struct {
+  uint32_t aa_frame_counter;
+  int32_t aa_feed_counter;
+  int32_t aa_feed_residue;
+  uint32_t counter;
+  uint32_t bytes_per_tick; /* pcm bytes read each media task tick */
+  uint64_t last_frame_us;
+} tA2DP_SBC_FEEDING_STATE;
+
+typedef struct {
+  uint64_t session_start_us;
+
+  size_t media_read_total_expected_frames;
+  size_t media_read_max_expected_frames;
+  size_t media_read_expected_count;
+
+  size_t media_read_total_limited_frames;
+  size_t media_read_max_limited_frames;
+  size_t media_read_limited_count;
+} a2dp_sbc_encoder_stats_t;
+
+typedef struct {
+  a2dp_source_read_callback_t read_callback;
+  a2dp_source_enqueue_callback_t enqueue_callback;
+  uint16_t TxAaMtuSize;
+  uint8_t tx_sbc_frames;
+  bool is_peer_edr;         /* True if the peer device supports EDR */
+  bool peer_supports_3mbps; /* True if the peer device supports 3Mbps EDR */
+  uint32_t timestamp;       /* Timestamp for the A2DP frames */
+  SBC_ENC_PARAMS sbc_encoder_params;
+  tA2DP_FEEDING_PARAMS feeding_params;
+  tA2DP_SBC_FEEDING_STATE feeding_state;
+  int16_t pcmBuffer[SBC_MAX_PCM_BUFFER_SIZE];
+
+  a2dp_sbc_encoder_stats_t stats;
+} tA2DP_SBC_ENCODER_CB;
+
+static tA2DP_SBC_ENCODER_CB a2dp_sbc_encoder_cb;
+
+static bool a2dp_sbc_read_feeding(void);
+static void a2dp_sbc_encode_frames(uint8_t nb_frame);
+static void a2dp_sbc_get_num_frame_iteration(uint8_t* num_of_iterations,
+                                             uint8_t* num_of_frames,
+                                             uint64_t timestamp_us);
+static uint8_t calculate_max_frames_per_packet(void);
+static uint16_t a2dp_sbc_source_rate(void);
+static uint32_t a2dp_sbc_frame_length(void);
+
+void a2dp_sbc_encoder_init(bool is_peer_edr, bool peer_supports_3mbps,
+                           const tA2DP_ENCODER_INIT_PARAMS* p_init_params,
+                           a2dp_source_read_callback_t read_callback,
+                           a2dp_source_enqueue_callback_t enqueue_callback) {
+  SBC_ENC_PARAMS* p_encoder_params = &a2dp_sbc_encoder_cb.sbc_encoder_params;
+
+  memset(&a2dp_sbc_encoder_cb, 0, sizeof(a2dp_sbc_encoder_cb));
+
+  a2dp_sbc_encoder_cb.stats.session_start_us = time_get_os_boottime_us();
+
+  a2dp_sbc_encoder_cb.read_callback = read_callback;
+  a2dp_sbc_encoder_cb.enqueue_callback = enqueue_callback;
+  a2dp_sbc_encoder_cb.is_peer_edr = is_peer_edr;
+  a2dp_sbc_encoder_cb.peer_supports_3mbps = peer_supports_3mbps;
+  a2dp_sbc_encoder_cb.timestamp = 0;
+
+  /* SBC encoder config (enforced even if not used) */
+  p_encoder_params->s16ChannelMode = p_init_params->ChannelMode;
+  p_encoder_params->s16NumOfSubBands = p_init_params->NumOfSubBands;
+  p_encoder_params->s16NumOfBlocks = p_init_params->NumOfBlocks;
+  p_encoder_params->s16AllocationMethod = p_init_params->AllocationMethod;
+  p_encoder_params->s16SamplingFreq = p_init_params->SamplingFreq;
+
+  p_encoder_params->u16BitRate = a2dp_sbc_source_rate();
+
+  uint16_t mtu_size = A2DP_SBC_BUFFER_SIZE - A2DP_SBC_OFFSET - sizeof(BT_HDR);
+  if (mtu_size < p_init_params->MtuSize) {
+    a2dp_sbc_encoder_cb.TxAaMtuSize = mtu_size;
+  } else {
+    a2dp_sbc_encoder_cb.TxAaMtuSize = p_init_params->MtuSize;
+  }
+
+  LOG_DEBUG(LOG_TAG, "%s: mtu %d, peer mtu %d", __func__,
+            a2dp_sbc_encoder_cb.TxAaMtuSize, p_init_params->MtuSize);
+  LOG_DEBUG(LOG_TAG,
+            "%s: ch mode %d, subnd %d, nb blk %d, alloc %d, rate %d, freq %d",
+            __func__, p_encoder_params->s16ChannelMode,
+            p_encoder_params->s16NumOfSubBands,
+            p_encoder_params->s16NumOfBlocks,
+            p_encoder_params->s16AllocationMethod, p_encoder_params->u16BitRate,
+            p_encoder_params->s16SamplingFreq);
+
+  /* Reset entirely the SBC encoder */
+  SBC_Encoder_Init(&a2dp_sbc_encoder_cb.sbc_encoder_params);
+  a2dp_sbc_encoder_cb.tx_sbc_frames = calculate_max_frames_per_packet();
+
+  LOG_DEBUG(LOG_TAG, "%s: bit pool %d", __func__, p_encoder_params->s16BitPool);
+}
+
+void a2dp_sbc_encoder_update(
+    const tA2DP_ENCODER_UPDATE_PARAMS* p_update_params) {
+  SBC_ENC_PARAMS* p_encoder_params = &a2dp_sbc_encoder_cb.sbc_encoder_params;
+  uint16_t s16SamplingFreq;
+  int16_t s16BitPool = 0;
+  int16_t s16BitRate;
+  int16_t s16FrameLen;
+  uint8_t protect = 0;
+
+  LOG_DEBUG(LOG_TAG, "%s: minmtu %d, maxbp %d minbp %d", __func__,
+            p_update_params->MinMtuSize, p_update_params->MaxBitPool,
+            p_update_params->MinBitPool);
+
+  if (!p_encoder_params->s16NumOfSubBands) {
+    LOG_WARN(LOG_TAG, "%s: SubBands are set to 0, resetting to max (%d)",
+             __func__, SBC_MAX_NUM_OF_SUBBANDS);
+    p_encoder_params->s16NumOfSubBands = SBC_MAX_NUM_OF_SUBBANDS;
+  }
+
+  if (!p_encoder_params->s16NumOfBlocks) {
+    LOG_WARN(LOG_TAG, "%s: Blocks are set to 0, resetting to max (%d)",
+             __func__, SBC_MAX_NUM_OF_BLOCKS);
+    p_encoder_params->s16NumOfBlocks = SBC_MAX_NUM_OF_BLOCKS;
+  }
+
+  if (!p_encoder_params->s16NumOfChannels) {
+    LOG_WARN(LOG_TAG, "%s: Channels are set to 0, resetting to max (%d)",
+             __func__, SBC_MAX_NUM_OF_CHANNELS);
+    p_encoder_params->s16NumOfChannels = SBC_MAX_NUM_OF_CHANNELS;
+  }
+
+  uint16_t mtu_size = A2DP_SBC_BUFFER_SIZE - A2DP_SBC_OFFSET - sizeof(BT_HDR);
+  if (mtu_size < p_update_params->MinMtuSize) {
+    a2dp_sbc_encoder_cb.TxAaMtuSize = mtu_size;
+  } else {
+    a2dp_sbc_encoder_cb.TxAaMtuSize = p_update_params->MinMtuSize;
+  }
+
+  /* Set the initial target bit rate */
+  p_encoder_params->u16BitRate = a2dp_sbc_source_rate();
+
+  if (p_encoder_params->s16SamplingFreq == SBC_sf16000)
+    s16SamplingFreq = 16000;
+  else if (p_encoder_params->s16SamplingFreq == SBC_sf32000)
+    s16SamplingFreq = 32000;
+  else if (p_encoder_params->s16SamplingFreq == SBC_sf44100)
+    s16SamplingFreq = 44100;
+  else
+    s16SamplingFreq = 48000;
+
+  do {
+    if (p_encoder_params->s16NumOfBlocks == 0 ||
+        p_encoder_params->s16NumOfSubBands == 0 ||
+        p_encoder_params->s16NumOfChannels == 0) {
+      LOG_ERROR(LOG_TAG, "%s: avoiding division by zero...", __func__);
+      LOG_ERROR(LOG_TAG, "%s: block=%d, subBands=%d, channels=%d", __func__,
+                p_encoder_params->s16NumOfBlocks,
+                p_encoder_params->s16NumOfSubBands,
+                p_encoder_params->s16NumOfChannels);
+      break;
+    }
+
+    if ((p_encoder_params->s16ChannelMode == SBC_JOINT_STEREO) ||
+        (p_encoder_params->s16ChannelMode == SBC_STEREO)) {
+      s16BitPool = (int16_t)((p_encoder_params->u16BitRate *
+                              p_encoder_params->s16NumOfSubBands * 1000 /
+                              s16SamplingFreq) -
+                             ((32 + (4 * p_encoder_params->s16NumOfSubBands *
+                                     p_encoder_params->s16NumOfChannels) +
+                               ((p_encoder_params->s16ChannelMode - 2) *
+                                p_encoder_params->s16NumOfSubBands)) /
+                              p_encoder_params->s16NumOfBlocks));
+
+      s16FrameLen = 4 +
+                    (4 * p_encoder_params->s16NumOfSubBands *
+                     p_encoder_params->s16NumOfChannels) /
+                        8 +
+                    (((p_encoder_params->s16ChannelMode - 2) *
+                      p_encoder_params->s16NumOfSubBands) +
+                     (p_encoder_params->s16NumOfBlocks * s16BitPool)) /
+                        8;
+
+      s16BitRate = (8 * s16FrameLen * s16SamplingFreq) /
+                   (p_encoder_params->s16NumOfSubBands *
+                    p_encoder_params->s16NumOfBlocks * 1000);
+
+      if (s16BitRate > p_encoder_params->u16BitRate) s16BitPool--;
+
+      if (p_encoder_params->s16NumOfSubBands == 8)
+        s16BitPool = (s16BitPool > 255) ? 255 : s16BitPool;
+      else
+        s16BitPool = (s16BitPool > 128) ? 128 : s16BitPool;
+    } else {
+      s16BitPool =
+          (int16_t)(((p_encoder_params->s16NumOfSubBands *
+                      p_encoder_params->u16BitRate * 1000) /
+                     (s16SamplingFreq * p_encoder_params->s16NumOfChannels)) -
+                    (((32 / p_encoder_params->s16NumOfChannels) +
+                      (4 * p_encoder_params->s16NumOfSubBands)) /
+                     p_encoder_params->s16NumOfBlocks));
+
+      p_encoder_params->s16BitPool =
+          (s16BitPool > (16 * p_encoder_params->s16NumOfSubBands))
+              ? (16 * p_encoder_params->s16NumOfSubBands)
+              : s16BitPool;
+    }
+
+    if (s16BitPool < 0) s16BitPool = 0;
+
+    LOG_DEBUG(LOG_TAG, "%s: bitpool candidate: %d (%d kbps)", __func__,
+              s16BitPool, p_encoder_params->u16BitRate);
+
+    if (s16BitPool > p_update_params->MaxBitPool) {
+      LOG_DEBUG(LOG_TAG, "%s: computed bitpool too large (%d)", __func__,
+                s16BitPool);
+      /* Decrease bitrate */
+      p_encoder_params->u16BitRate -= A2DP_SBC_BITRATE_STEP;
+      /* Record that we have decreased the bitrate */
+      protect |= 1;
+    } else if (s16BitPool < p_update_params->MinBitPool) {
+      LOG_WARN(LOG_TAG, "%s: computed bitpool too small (%d)", __func__,
+               s16BitPool);
+
+      /* Increase bitrate */
+      uint16_t previous_u16BitRate = p_encoder_params->u16BitRate;
+      p_encoder_params->u16BitRate += A2DP_SBC_BITRATE_STEP;
+      /* Record that we have increased the bitrate */
+      protect |= 2;
+      /* Check over-flow */
+      if (p_encoder_params->u16BitRate < previous_u16BitRate) protect |= 3;
+    } else {
+      break;
+    }
+    /* In case we have already increased and decreased the bitrate, just stop */
+    if (protect == 3) {
+      LOG_ERROR(LOG_TAG, "%s: could not find bitpool in range", __func__);
+      break;
+    }
+  } while (true);
+
+  /* Finally update the bitpool in the encoder structure */
+  p_encoder_params->s16BitPool = s16BitPool;
+
+  LOG_DEBUG(LOG_TAG, "%s: final bit rate %d, final bit pool %d", __func__,
+            p_encoder_params->u16BitRate, p_encoder_params->s16BitPool);
+
+  /* make sure we reinitialize encoder with new settings */
+  SBC_Encoder_Init(&a2dp_sbc_encoder_cb.sbc_encoder_params);
+
+  a2dp_sbc_encoder_cb.tx_sbc_frames = calculate_max_frames_per_packet();
+}
+
+void a2dp_sbc_encoder_cleanup(void) {
+  memset(&a2dp_sbc_encoder_cb, 0, sizeof(a2dp_sbc_encoder_cb));
+}
+
+void a2dp_sbc_feeding_init(const tA2DP_FEEDING_PARAMS* p_feeding_params) {
+  SBC_ENC_PARAMS* p_encoder_params = &a2dp_sbc_encoder_cb.sbc_encoder_params;
+  bool reconfig_needed = false;
+
+  LOG_DEBUG(
+      LOG_TAG,
+      "%s: PCM feeding: sampling_freq:%d num_channel:%d bit_per_sample:%d",
+      __func__, p_feeding_params->sampling_freq, p_feeding_params->num_channel,
+      p_feeding_params->bit_per_sample);
+
+  /* Save the feeding information */
+  memcpy(&a2dp_sbc_encoder_cb.feeding_params, p_feeding_params,
+         sizeof(tA2DP_FEEDING_PARAMS));
+
+  /* Check the PCM feeding sampling_freq */
+  switch (p_feeding_params->sampling_freq) {
+    case 8000:
+    case 12000:
+    case 16000:
+    case 24000:
+    case 32000:
+    case 48000:
+      /* For these sampling_freq the AV connection must be 48000 */
+      if (p_encoder_params->s16SamplingFreq != SBC_sf48000) {
+        /* Reconfiguration needed at 48000 */
+        LOG_DEBUG(LOG_TAG, "%s: SBC Reconfiguration needed at 48000", __func__);
+        p_encoder_params->s16SamplingFreq = SBC_sf48000;
+        reconfig_needed = true;
+      }
+      break;
+
+    case 11025:
+    case 22050:
+    case 44100:
+      /* For these sampling_freq the AV connection must be 44100 */
+      if (p_encoder_params->s16SamplingFreq != SBC_sf44100) {
+        /* Reconfiguration needed at 44100 */
+        LOG_DEBUG(LOG_TAG, "%s: SBC Reconfiguration needed at 44100", __func__);
+        p_encoder_params->s16SamplingFreq = SBC_sf44100;
+        reconfig_needed = true;
+      }
+      break;
+    default:
+      LOG_DEBUG(LOG_TAG, "%s: Feeding PCM sampling_freq unsupported", __func__);
+      break;
+  }
+
+  /* Some AV Headsets do not support Mono => always ask for Stereo */
+  if (p_encoder_params->s16ChannelMode == SBC_MONO) {
+    LOG_DEBUG(LOG_TAG, "%s: SBC Reconfiguration needed in Stereo", __func__);
+    p_encoder_params->s16ChannelMode = SBC_JOINT_STEREO;
+    reconfig_needed = true;
+  }
+
+  if (reconfig_needed) {
+    LOG_DEBUG(
+        LOG_TAG,
+        "%s: mtu %d ch mode %d, nbsubd %d, nb %d, alloc %d, rate %d, freq %d",
+        __func__, a2dp_sbc_encoder_cb.TxAaMtuSize,
+        p_encoder_params->s16ChannelMode, p_encoder_params->s16NumOfSubBands,
+        p_encoder_params->s16NumOfBlocks, p_encoder_params->s16AllocationMethod,
+        p_encoder_params->u16BitRate, p_encoder_params->s16SamplingFreq);
+    SBC_Encoder_Init(p_encoder_params);
+  } else {
+    LOG_DEBUG(LOG_TAG, "%s: no SBC reconfig needed", __func__);
+  }
+}
+
+void a2dp_sbc_feeding_reset(void) {
+  /* By default, just clear the entire state */
+  memset(&a2dp_sbc_encoder_cb.feeding_state, 0,
+         sizeof(a2dp_sbc_encoder_cb.feeding_state));
+
+  a2dp_sbc_encoder_cb.feeding_state.bytes_per_tick =
+      (a2dp_sbc_encoder_cb.feeding_params.sampling_freq *
+       a2dp_sbc_encoder_cb.feeding_params.bit_per_sample / 8 *
+       a2dp_sbc_encoder_cb.feeding_params.num_channel *
+       A2DP_SBC_ENCODER_INTERVAL_MS) /
+      1000;
+
+  LOG_DEBUG(LOG_TAG, "%s: PCM bytes per tick %u", __func__,
+            a2dp_sbc_encoder_cb.feeding_state.bytes_per_tick);
+}
+
+void a2dp_sbc_feeding_flush(void) {
+  a2dp_sbc_encoder_cb.feeding_state.counter = 0;
+  a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue = 0;
+}
+
+period_ms_t a2dp_sbc_get_encoder_interval_ms(void) {
+  return A2DP_SBC_ENCODER_INTERVAL_MS;
+}
+
+void a2dp_sbc_send_frames(uint64_t timestamp_us) {
+  uint8_t nb_frame = 0;
+  uint8_t nb_iterations = 0;
+
+  a2dp_sbc_get_num_frame_iteration(&nb_iterations, &nb_frame, timestamp_us);
+  LOG_VERBOSE(LOG_TAG, "%s: Sending %d frames per iteration, %d iterations",
+              __func__, nb_frame, nb_iterations);
+  if (nb_frame == 0) return;
+
+  for (uint8_t counter = 0; counter < nb_iterations; counter++) {
+    // Transcode frame and enqueue
+    a2dp_sbc_encode_frames(nb_frame);
+  }
+}
+
+// Obtains the number of frames to send and number of iterations
+// to be used. |num_of_iterations| and |num_of_frames| parameters
+// are used as output param for returning the respective values.
+static void a2dp_sbc_get_num_frame_iteration(uint8_t* num_of_iterations,
+                                             uint8_t* num_of_frames,
+                                             uint64_t timestamp_us) {
+  uint8_t nof = 0;
+  uint8_t noi = 1;
+
+  uint32_t projected_nof = 0;
+  uint32_t pcm_bytes_per_frame =
+      a2dp_sbc_encoder_cb.sbc_encoder_params.s16NumOfSubBands *
+      a2dp_sbc_encoder_cb.sbc_encoder_params.s16NumOfBlocks *
+      a2dp_sbc_encoder_cb.feeding_params.num_channel *
+      a2dp_sbc_encoder_cb.feeding_params.bit_per_sample / 8;
+  LOG_VERBOSE(LOG_TAG, "%s: pcm_bytes_per_frame %u", __func__,
+              pcm_bytes_per_frame);
+
+  uint32_t us_this_tick = A2DP_SBC_ENCODER_INTERVAL_MS * 1000;
+  uint64_t now_us = timestamp_us;
+  if (a2dp_sbc_encoder_cb.feeding_state.last_frame_us != 0)
+    us_this_tick = (now_us - a2dp_sbc_encoder_cb.feeding_state.last_frame_us);
+  a2dp_sbc_encoder_cb.feeding_state.last_frame_us = now_us;
+
+  a2dp_sbc_encoder_cb.feeding_state.counter +=
+      a2dp_sbc_encoder_cb.feeding_state.bytes_per_tick * us_this_tick /
+      (A2DP_SBC_ENCODER_INTERVAL_MS * 1000);
+
+  /* Calculate the number of frames pending for this media tick */
+  projected_nof =
+      a2dp_sbc_encoder_cb.feeding_state.counter / pcm_bytes_per_frame;
+  // Update the stats
+  STATS_UPDATE_MAX(a2dp_sbc_encoder_cb.stats.media_read_max_expected_frames,
+                   projected_nof);
+  a2dp_sbc_encoder_cb.stats.media_read_total_expected_frames += projected_nof;
+  a2dp_sbc_encoder_cb.stats.media_read_expected_count++;
+
+  if (projected_nof > MAX_PCM_FRAME_NUM_PER_TICK) {
+    LOG_WARN(LOG_TAG, "%s: limiting frames to be sent from %d to %d", __func__,
+             projected_nof, MAX_PCM_FRAME_NUM_PER_TICK);
+
+    // Update the stats
+    size_t delta = projected_nof - MAX_PCM_FRAME_NUM_PER_TICK;
+    a2dp_sbc_encoder_cb.stats.media_read_limited_count++;
+    a2dp_sbc_encoder_cb.stats.media_read_total_limited_frames += delta;
+    STATS_UPDATE_MAX(a2dp_sbc_encoder_cb.stats.media_read_max_limited_frames,
+                     delta);
+
+    projected_nof = MAX_PCM_FRAME_NUM_PER_TICK;
+  }
+
+  LOG_VERBOSE(LOG_TAG, "%s: frames for available PCM data %u", __func__,
+              projected_nof);
+
+  if (a2dp_sbc_encoder_cb.is_peer_edr) {
+    if (!a2dp_sbc_encoder_cb.tx_sbc_frames) {
+      LOG_ERROR(LOG_TAG, "%s: tx_sbc_frames not updated, update from here",
+                __func__);
+      a2dp_sbc_encoder_cb.tx_sbc_frames = calculate_max_frames_per_packet();
+    }
+
+    nof = a2dp_sbc_encoder_cb.tx_sbc_frames;
+    if (!nof) {
+      LOG_ERROR(LOG_TAG,
+                "%s: number of frames not updated, set calculated values",
+                __func__);
+      nof = projected_nof;
+      noi = 1;
+    } else {
+      if (nof < projected_nof) {
+        noi = projected_nof / nof;  // number of iterations would vary
+        if (noi > A2DP_SBC_MAX_PCM_ITER_NUM_PER_TICK) {
+          LOG_ERROR(LOG_TAG, "%s: Audio Congestion (iterations:%d > max (%d))",
+                    __func__, noi, A2DP_SBC_MAX_PCM_ITER_NUM_PER_TICK);
+          noi = A2DP_SBC_MAX_PCM_ITER_NUM_PER_TICK;
+          a2dp_sbc_encoder_cb.feeding_state.counter =
+              noi * nof * pcm_bytes_per_frame;
+        }
+        projected_nof = nof;
+      } else {
+        noi = 1;  // number of iterations is 1
+        LOG_VERBOSE(LOG_TAG, "%s: reducing frames for available PCM data",
+                    __func__);
+        nof = projected_nof;
+      }
+    }
+  } else {
+    // For BR cases nof will be same as the value retrieved at projected_nof
+    LOG_VERBOSE(LOG_TAG, "%s: headset BR, number of frames %u", __func__, nof);
+    if (projected_nof > MAX_PCM_FRAME_NUM_PER_TICK) {
+      LOG_ERROR(LOG_TAG, "%s: Audio Congestion (frames: %d > max (%d))",
+                __func__, projected_nof, MAX_PCM_FRAME_NUM_PER_TICK);
+      projected_nof = MAX_PCM_FRAME_NUM_PER_TICK;
+      a2dp_sbc_encoder_cb.feeding_state.counter =
+          noi * projected_nof * pcm_bytes_per_frame;
+    }
+    nof = projected_nof;
+  }
+  a2dp_sbc_encoder_cb.feeding_state.counter -= noi * nof * pcm_bytes_per_frame;
+  LOG_VERBOSE(LOG_TAG, "%s: effective num of frames %u, iterations %u",
+              __func__, nof, noi);
+
+  *num_of_frames = nof;
+  *num_of_iterations = noi;
+}
+
+static void a2dp_sbc_encode_frames(uint8_t nb_frame) {
+  SBC_ENC_PARAMS* p_encoder_params = &a2dp_sbc_encoder_cb.sbc_encoder_params;
+  uint8_t remain_nb_frame = nb_frame;
+  uint16_t blocm_x_subband =
+      p_encoder_params->s16NumOfSubBands * p_encoder_params->s16NumOfBlocks;
+
+  uint8_t last_frame_len = 0;
+  while (nb_frame) {
+    BT_HDR* p_buf = (BT_HDR*)osi_malloc(A2DP_SBC_BUFFER_SIZE);
+
+    /* Init buffer */
+    p_buf->offset = A2DP_SBC_OFFSET;
+    p_buf->len = 0;
+    p_buf->layer_specific = 0;
+
+    do {
+      /* Fill allocated buffer with 0 */
+      memset(a2dp_sbc_encoder_cb.pcmBuffer, 0,
+             blocm_x_subband * p_encoder_params->s16NumOfChannels);
+
+      /* Read PCM data and upsample them if needed */
+      if (a2dp_sbc_read_feeding()) {
+
+        uint8_t *output = (uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len;
+        int16_t *input = a2dp_sbc_encoder_cb.pcmBuffer;
+        uint16_t output_len = SBC_Encode(p_encoder_params, input, output);
+        last_frame_len = output_len;
+
+        /* Update SBC frame length */
+        p_buf->len += output_len;
+        nb_frame--;
+        p_buf->layer_specific++;
+      } else {
+        LOG_WARN(LOG_TAG, "%s: underflow %d, %d", __func__, nb_frame,
+                 a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue);
+        a2dp_sbc_encoder_cb.feeding_state.counter +=
+            nb_frame * p_encoder_params->s16NumOfSubBands *
+            p_encoder_params->s16NumOfBlocks *
+            a2dp_sbc_encoder_cb.feeding_params.num_channel *
+            a2dp_sbc_encoder_cb.feeding_params.bit_per_sample / 8;
+        /* no more pcm to read */
+        nb_frame = 0;
+      }
+    } while (((p_buf->len + last_frame_len) <
+              a2dp_sbc_encoder_cb.TxAaMtuSize) &&
+             (p_buf->layer_specific < 0x0F) && nb_frame);
+
+    if (p_buf->len) {
+      /*
+       * Timestamp of the media packet header represent the TS of the
+       * first SBC frame, i.e the timestamp before including this frame.
+       */
+      *((uint32_t*)(p_buf + 1)) = a2dp_sbc_encoder_cb.timestamp;
+
+      a2dp_sbc_encoder_cb.timestamp += p_buf->layer_specific * blocm_x_subband;
+
+      uint8_t done_nb_frame = remain_nb_frame - nb_frame;
+      remain_nb_frame = nb_frame;
+      if (!a2dp_sbc_encoder_cb.enqueue_callback(p_buf, done_nb_frame)) return;
+    } else {
+      osi_free(p_buf);
+    }
+  }
+}
+
+static bool a2dp_sbc_read_feeding(void) {
+  SBC_ENC_PARAMS* p_encoder_params = &a2dp_sbc_encoder_cb.sbc_encoder_params;
+  uint16_t blocm_x_subband =
+      p_encoder_params->s16NumOfSubBands * p_encoder_params->s16NumOfBlocks;
+  uint32_t read_size;
+  uint32_t sbc_sampling = 48000;
+  uint32_t src_samples;
+  uint16_t bytes_needed = blocm_x_subband * p_encoder_params->s16NumOfChannels *
+                          a2dp_sbc_encoder_cb.feeding_params.bit_per_sample / 8;
+  static uint16_t up_sampled_buffer[SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS *
+                                    SBC_MAX_NUM_OF_CHANNELS *
+                                    SBC_MAX_NUM_OF_SUBBANDS * 2];
+  static uint16_t read_buffer[SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS *
+                              SBC_MAX_NUM_OF_CHANNELS *
+                              SBC_MAX_NUM_OF_SUBBANDS];
+  uint32_t src_size_used;
+  uint32_t dst_size_used;
+  bool fract_needed;
+  int32_t fract_max;
+  int32_t fract_threshold;
+  uint32_t nb_byte_read;
+
+  /* Get the SBC sampling rate */
+  switch (p_encoder_params->s16SamplingFreq) {
+    case SBC_sf48000:
+      sbc_sampling = 48000;
+      break;
+    case SBC_sf44100:
+      sbc_sampling = 44100;
+      break;
+    case SBC_sf32000:
+      sbc_sampling = 32000;
+      break;
+    case SBC_sf16000:
+      sbc_sampling = 16000;
+      break;
+  }
+
+  if (sbc_sampling == a2dp_sbc_encoder_cb.feeding_params.sampling_freq) {
+    read_size =
+        bytes_needed - a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue;
+    nb_byte_read = a2dp_sbc_encoder_cb.read_callback(
+        ((uint8_t*)a2dp_sbc_encoder_cb.pcmBuffer) +
+            a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue,
+        read_size);
+    if (nb_byte_read != read_size) {
+      a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue += nb_byte_read;
+      return false;
+    }
+    a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue = 0;
+    return true;
+  }
+
+  /*
+   * Some Feeding PCM frequencies require to split the number of sample
+   * to read.
+   * E.g 128 / 6 = 21.3333 => read 22 and 21 and 21 => max = 2; threshold = 0
+   */
+  fract_needed = false; /* Default */
+  switch (a2dp_sbc_encoder_cb.feeding_params.sampling_freq) {
+    case 32000:
+    case 8000:
+      fract_needed = true;
+      fract_max = 2;       /* 0, 1 and 2 */
+      fract_threshold = 0; /* Add one for the first */
+      break;
+    case 16000:
+      fract_needed = true;
+      fract_max = 2;       /* 0, 1 and 2 */
+      fract_threshold = 1; /* Add one for the first two frames*/
+      break;
+  }
+
+  /* Compute number of sample to read from source */
+  src_samples = blocm_x_subband;
+  src_samples *= a2dp_sbc_encoder_cb.feeding_params.sampling_freq;
+  src_samples /= sbc_sampling;
+
+  /* The previous division may have a remainder not null */
+  if (fract_needed) {
+    if (a2dp_sbc_encoder_cb.feeding_state.aa_feed_counter <= fract_threshold) {
+      src_samples++; /* for every read before threshold add one sample */
+    }
+
+    /* do nothing if counter >= threshold */
+    a2dp_sbc_encoder_cb.feeding_state.aa_feed_counter++; /* one more read */
+    if (a2dp_sbc_encoder_cb.feeding_state.aa_feed_counter > fract_max) {
+      a2dp_sbc_encoder_cb.feeding_state.aa_feed_counter = 0;
+    }
+  }
+
+  /* Compute number of bytes to read from source */
+  read_size = src_samples;
+  read_size *= a2dp_sbc_encoder_cb.feeding_params.num_channel;
+  read_size *= (a2dp_sbc_encoder_cb.feeding_params.bit_per_sample / 8);
+
+  /* Read Data from UIPC channel */
+  nb_byte_read =
+      a2dp_sbc_encoder_cb.read_callback((uint8_t*)read_buffer, read_size);
+
+  if (nb_byte_read < read_size) {
+    if (nb_byte_read == 0) return false;
+
+    /* Fill the unfilled part of the read buffer with silence (0) */
+    memset(((uint8_t*)read_buffer) + nb_byte_read, 0, read_size - nb_byte_read);
+    nb_byte_read = read_size;
+  }
+
+  /* Initialize PCM up-sampling engine */
+  a2dp_sbc_init_up_sample(a2dp_sbc_encoder_cb.feeding_params.sampling_freq,
+                          sbc_sampling,
+                          a2dp_sbc_encoder_cb.feeding_params.bit_per_sample,
+                          a2dp_sbc_encoder_cb.feeding_params.num_channel);
+
+  /*
+   * Re-sample the read buffer.
+   * The output PCM buffer will be stereo, 16 bit per sample.
+   */
+  dst_size_used = a2dp_sbc_up_sample(
+      (uint8_t*)read_buffer,
+      (uint8_t*)up_sampled_buffer +
+          a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue,
+      nb_byte_read, sizeof(up_sampled_buffer) -
+                        a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue,
+      &src_size_used);
+
+  /* update the residue */
+  a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue += dst_size_used;
+
+  /* only copy the pcm sample when we have up-sampled enough PCM */
+  if (a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue < bytes_needed)
+    return false;
+
+  /* Copy the output pcm samples in SBC encoding buffer */
+  memcpy((uint8_t*)a2dp_sbc_encoder_cb.pcmBuffer, (uint8_t*)up_sampled_buffer,
+         bytes_needed);
+  /* update the residue */
+  a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue -= bytes_needed;
+
+  if (a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue != 0) {
+    memcpy((uint8_t*)up_sampled_buffer,
+           (uint8_t*)up_sampled_buffer + bytes_needed,
+           a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue);
+  }
+  return true;
+}
+
+static uint8_t calculate_max_frames_per_packet(void) {
+  uint16_t effective_mtu_size = a2dp_sbc_encoder_cb.TxAaMtuSize;
+  SBC_ENC_PARAMS* p_encoder_params = &a2dp_sbc_encoder_cb.sbc_encoder_params;
+  uint16_t result = 0;
+  uint32_t frame_len;
+
+  LOG_VERBOSE(LOG_TAG, "%s: original AVDTP MTU size: %d", __func__,
+              a2dp_sbc_encoder_cb.TxAaMtuSize);
+  if (a2dp_sbc_encoder_cb.is_peer_edr &&
+      !a2dp_sbc_encoder_cb.peer_supports_3mbps) {
+    // This condition would be satisfied only if the remote device is
+    // EDR and supports only 2 Mbps, but the effective AVDTP MTU size
+    // exceeds the 2DH5 packet size.
+    LOG_VERBOSE(LOG_TAG,
+                "%s: The remote devce is EDR but does not support 3 Mbps",
+                __func__);
+
+    if (effective_mtu_size > MAX_2MBPS_AVDTP_MTU) {
+      LOG_WARN(LOG_TAG, "%s: Restricting AVDTP MTU size to %d", __func__,
+               MAX_2MBPS_AVDTP_MTU);
+      effective_mtu_size = MAX_2MBPS_AVDTP_MTU;
+      a2dp_sbc_encoder_cb.TxAaMtuSize = effective_mtu_size;
+    }
+  }
+
+  if (!p_encoder_params->s16NumOfSubBands) {
+    LOG_ERROR(LOG_TAG, "%s: SubBands are set to 0, resetting to %d", __func__,
+              SBC_MAX_NUM_OF_SUBBANDS);
+    p_encoder_params->s16NumOfSubBands = SBC_MAX_NUM_OF_SUBBANDS;
+  }
+  if (!p_encoder_params->s16NumOfBlocks) {
+    LOG_ERROR(LOG_TAG, "%s: Blocks are set to 0, resetting to %d", __func__,
+              SBC_MAX_NUM_OF_BLOCKS);
+    p_encoder_params->s16NumOfBlocks = SBC_MAX_NUM_OF_BLOCKS;
+  }
+  if (!p_encoder_params->s16NumOfChannels) {
+    LOG_ERROR(LOG_TAG, "%s: Channels are set to 0, resetting to %d", __func__,
+              SBC_MAX_NUM_OF_CHANNELS);
+    p_encoder_params->s16NumOfChannels = SBC_MAX_NUM_OF_CHANNELS;
+  }
+
+  frame_len = a2dp_sbc_frame_length();
+
+  LOG_VERBOSE(LOG_TAG, "%s: Effective Tx MTU to be considered: %d", __func__,
+              effective_mtu_size);
+
+  switch (p_encoder_params->s16SamplingFreq) {
+    case SBC_sf44100:
+      if (frame_len == 0) {
+        LOG_ERROR(LOG_TAG,
+                  "%s: Calculating frame length, resetting it to default %d",
+                  __func__, A2DP_SBC_MAX_HQ_FRAME_SIZE_44_1);
+        frame_len = A2DP_SBC_MAX_HQ_FRAME_SIZE_44_1;
+      }
+      result = (effective_mtu_size - A2DP_HDR_SIZE) / frame_len;
+      LOG_VERBOSE(LOG_TAG, "%s: Max number of SBC frames: %d", __func__,
+                  result);
+      break;
+
+    case SBC_sf48000:
+      if (frame_len == 0) {
+        LOG_ERROR(LOG_TAG,
+                  "%s: Calculating frame length, resetting it to default %d",
+                  __func__, A2DP_SBC_MAX_HQ_FRAME_SIZE_48);
+        frame_len = A2DP_SBC_MAX_HQ_FRAME_SIZE_48;
+      }
+      result = (effective_mtu_size - A2DP_HDR_SIZE) / frame_len;
+      LOG_VERBOSE(LOG_TAG, "%s: Max number of SBC frames: %d", __func__,
+                  result);
+      break;
+
+    default:
+      LOG_ERROR(LOG_TAG, "%s: Max number of SBC frames: %d", __func__, result);
+      break;
+  }
+  return result;
+}
+
+static uint16_t a2dp_sbc_source_rate(void) {
+  uint16_t rate = A2DP_SBC_DEFAULT_BITRATE;
+
+  /* restrict bitrate if a2dp link is non-edr */
+  if (!a2dp_sbc_encoder_cb.is_peer_edr) {
+    rate = A2DP_SBC_NON_EDR_MAX_RATE;
+    LOG_VERBOSE(LOG_TAG, "%s: non-edr a2dp sink detected, restrict rate to %d",
+                __func__, rate);
+  }
+
+  return rate;
+}
+
+static uint32_t a2dp_sbc_frame_length(void) {
+  SBC_ENC_PARAMS* p_encoder_params = &a2dp_sbc_encoder_cb.sbc_encoder_params;
+  uint32_t frame_len = 0;
+
+  LOG_VERBOSE(LOG_TAG,
+              "%s: channel mode: %d, sub-band: %d, number of block: %d, "
+              "bitpool: %d, sampling frequency: %d, num channels: %d",
+              __func__, p_encoder_params->s16ChannelMode,
+              p_encoder_params->s16NumOfSubBands,
+              p_encoder_params->s16NumOfBlocks, p_encoder_params->s16BitPool,
+              p_encoder_params->s16SamplingFreq,
+              p_encoder_params->s16NumOfChannels);
+
+  switch (p_encoder_params->s16ChannelMode) {
+    case SBC_MONO:
+    /* FALLTHROUGH */
+    case SBC_DUAL:
+      frame_len = A2DP_SBC_FRAME_HEADER_SIZE_BYTES +
+                  ((uint32_t)(A2DP_SBC_SCALE_FACTOR_BITS *
+                              p_encoder_params->s16NumOfSubBands *
+                              p_encoder_params->s16NumOfChannels) /
+                   CHAR_BIT) +
+                  ((uint32_t)(p_encoder_params->s16NumOfBlocks *
+                              p_encoder_params->s16NumOfChannels *
+                              p_encoder_params->s16BitPool) /
+                   CHAR_BIT);
+      break;
+    case SBC_STEREO:
+      frame_len = A2DP_SBC_FRAME_HEADER_SIZE_BYTES +
+                  ((uint32_t)(A2DP_SBC_SCALE_FACTOR_BITS *
+                              p_encoder_params->s16NumOfSubBands *
+                              p_encoder_params->s16NumOfChannels) /
+                   CHAR_BIT) +
+                  ((uint32_t)(p_encoder_params->s16NumOfBlocks *
+                              p_encoder_params->s16BitPool) /
+                   CHAR_BIT);
+      break;
+    case SBC_JOINT_STEREO:
+      frame_len = A2DP_SBC_FRAME_HEADER_SIZE_BYTES +
+                  ((uint32_t)(A2DP_SBC_SCALE_FACTOR_BITS *
+                              p_encoder_params->s16NumOfSubBands *
+                              p_encoder_params->s16NumOfChannels) /
+                   CHAR_BIT) +
+                  ((uint32_t)(p_encoder_params->s16NumOfSubBands +
+                              (p_encoder_params->s16NumOfBlocks *
+                               p_encoder_params->s16BitPool)) /
+                   CHAR_BIT);
+      break;
+    default:
+      LOG_VERBOSE(LOG_TAG, "%s: Invalid channel number: %d", __func__,
+                  p_encoder_params->s16ChannelMode);
+      break;
+  }
+  LOG_VERBOSE(LOG_TAG, "%s: calculated frame length: %d", __func__, frame_len);
+  return frame_len;
+}
+
+void a2dp_sbc_debug_codec_dump(int fd) {
+  a2dp_sbc_encoder_stats_t* stats = &a2dp_sbc_encoder_cb.stats;
+  size_t ave_size;
+
+  dprintf(fd, "\nA2DP SBC State:\n");
+
+  ave_size = 0;
+  if (stats->media_read_expected_count != 0) {
+    ave_size = stats->media_read_total_expected_frames /
+               stats->media_read_expected_count;
+  }
+  dprintf(fd,
+          "  Frames expected (total/max/ave)                         : %zu / "
+          "%zu / %zu\n",
+          stats->media_read_total_expected_frames,
+          stats->media_read_max_expected_frames, ave_size);
+
+  ave_size = 0;
+  if (stats->media_read_limited_count != 0) {
+    ave_size = stats->media_read_total_limited_frames /
+               stats->media_read_limited_count;
+  }
+  dprintf(fd,
+          "  Frames limited (total/max/ave)                          : %zu / "
+          "%zu / %zu\n",
+          stats->media_read_total_limited_frames,
+          stats->media_read_max_limited_frames, ave_size);
+
+  dprintf(
+      fd,
+      "  Counts (expected/limited)                               : %zu / %zu\n",
+      stats->media_read_expected_count, stats->media_read_limited_count);
+}
diff --git a/bt/stack/a2dp/a2dp_sbc_up_sample.cc b/bt/stack/a2dp/a2dp_sbc_up_sample.cc
new file mode 100644
index 0000000..5cea704
--- /dev/null
+++ b/bt/stack/a2dp/a2dp_sbc_up_sample.cc
@@ -0,0 +1,370 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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 module contains utility functions for dealing with SBC data frames
+ *  and codec capabilities.
+ *
+ ******************************************************************************/
+
+#include "a2dp_sbc_up_sample.h"
+
+typedef int(tA2DP_SBC_ACT)(void* p_src, void* p_dst, uint32_t src_samples,
+                           uint32_t dst_samples, uint32_t* p_ret);
+
+typedef struct {
+  int32_t cur_pos;      /* current position */
+  uint32_t src_sps;     /* samples per second (source audio data) */
+  uint32_t dst_sps;     /* samples per second (converted audio data) */
+  tA2DP_SBC_ACT* p_act; /* the action function to do the conversion */
+  uint8_t bits;         /* number of bits per pcm sample */
+  uint8_t n_channels;   /* number of channels (i.e. mono(1), stereo(2)...) */
+  int16_t worker1;
+  int16_t worker2;
+  uint8_t div;
+} tA2DP_SBC_UPS_CB;
+
+tA2DP_SBC_UPS_CB a2dp_sbc_ups_cb;
+
+/*******************************************************************************
+**
+** Function         a2dp_sbc_init_up_sample
+**
+** Description      initialize the up sample
+**
+**                  src_sps: samples per second (source audio data)
+**                  dst_sps: samples per second (converted audio data)
+**                  bits: number of bits per pcm sample
+**                  n_channels: number of channels (i.e. mono(1), stereo(2)...)
+**
+** Returns          none
+**
+*******************************************************************************/
+void a2dp_sbc_init_up_sample(uint32_t src_sps, uint32_t dst_sps, uint8_t bits,
+                             uint8_t n_channels) {
+  a2dp_sbc_ups_cb.cur_pos = -1;
+  a2dp_sbc_ups_cb.src_sps = src_sps;
+  a2dp_sbc_ups_cb.dst_sps = dst_sps;
+  a2dp_sbc_ups_cb.bits = bits;
+  a2dp_sbc_ups_cb.n_channels = n_channels;
+
+  if (n_channels == 1) {
+    /* mono */
+    if (bits == 8) {
+      a2dp_sbc_ups_cb.p_act = a2dp_sbc_up_sample_8m;
+      a2dp_sbc_ups_cb.div = 1;
+    } else {
+      a2dp_sbc_ups_cb.p_act = a2dp_sbc_up_sample_16m;
+      a2dp_sbc_ups_cb.div = 2;
+    }
+  } else {
+    /* stereo */
+    if (bits == 8) {
+      a2dp_sbc_ups_cb.p_act = a2dp_sbc_up_sample_8s;
+      a2dp_sbc_ups_cb.div = 2;
+    } else {
+      a2dp_sbc_ups_cb.p_act = a2dp_sbc_up_sample_16s;
+      a2dp_sbc_ups_cb.div = 4;
+    }
+  }
+}
+
+/*******************************************************************************
+**
+** Function         a2dp_sbc_up_sample
+**
+** Description      Given the source (p_src) audio data and
+**                  source speed (src_sps, samples per second),
+**                  This function converts it to audio data in the desired
+**                  format
+**
+**                  p_src: the data buffer that holds the source audio data
+**                  p_dst: the data buffer to hold the converted audio data
+**                  src_samples: The number of source samples (number of bytes)
+**                  dst_samples: The size of p_dst (number of bytes)
+**
+** Note:            An AE reported an issue with this function.
+**                  When called with a2dp_sbc_up_sample(src, uint8_array_dst..)
+**                  the byte before uint8_array_dst may get overwritten.
+**                  Using uint16_array_dst avoids the problem.
+**                  This issue is related to endian-ness and is hard to resolve
+**                  in a generic manner.
+** **************** Please use uint16 array as dst.
+**
+** Returns          The number of bytes used in p_dst
+**                  The number of bytes used in p_src (in *p_ret)
+**
+*******************************************************************************/
+int a2dp_sbc_up_sample(void* p_src, void* p_dst, uint32_t src_samples,
+                       uint32_t dst_samples, uint32_t* p_ret) {
+  uint32_t src;
+  uint32_t dst;
+
+  if (a2dp_sbc_ups_cb.p_act) {
+    src = src_samples / a2dp_sbc_ups_cb.div;
+    dst = dst_samples / a2dp_sbc_ups_cb.div;
+    return (*a2dp_sbc_ups_cb.p_act)(p_src, p_dst, src, dst, p_ret);
+  } else {
+    *p_ret = 0;
+    return 0;
+  }
+}
+
+/*******************************************************************************
+**
+** Function         a2dp_sbc_up_sample_16s (16bits-stereo)
+**
+** Description      Given the source (p_src) audio data and
+**                  source speed (src_sps, samples per second),
+**                  This function converts it to audio data in the desired
+**                  format
+**
+**                  p_src: the data buffer that holds the source audio data
+**                  p_dst: the data buffer to hold the converted audio data
+**                  src_samples: The number of source samples (in uint of 4
+**                               bytes)
+**                  dst_samples: The size of p_dst (in uint of 4 bytes)
+**
+** Returns          The number of bytes used in p_dst
+**                  The number of bytes used in p_src (in *p_ret)
+**
+*******************************************************************************/
+int a2dp_sbc_up_sample_16s(void* p_src, void* p_dst, uint32_t src_samples,
+                           uint32_t dst_samples, uint32_t* p_ret) {
+  int16_t* p_src_tmp = (int16_t*)p_src;
+  int16_t* p_dst_tmp = (int16_t*)p_dst;
+  int16_t* p_worker1 = &a2dp_sbc_ups_cb.worker1;
+  int16_t* p_worker2 = &a2dp_sbc_ups_cb.worker2;
+  uint32_t src_sps = a2dp_sbc_ups_cb.src_sps;
+  uint32_t dst_sps = a2dp_sbc_ups_cb.dst_sps;
+
+  while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples) {
+    *p_dst_tmp++ = *p_worker1;
+    *p_dst_tmp++ = *p_worker2;
+
+    a2dp_sbc_ups_cb.cur_pos -= src_sps;
+    dst_samples--;
+  }
+
+  a2dp_sbc_ups_cb.cur_pos = dst_sps;
+
+  while (src_samples-- && dst_samples) {
+    *p_worker1 = *p_src_tmp++;
+    *p_worker2 = *p_src_tmp++;
+
+    do {
+      *p_dst_tmp++ = *p_worker1;
+      *p_dst_tmp++ = *p_worker2;
+
+      a2dp_sbc_ups_cb.cur_pos -= src_sps;
+      dst_samples--;
+    } while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples);
+
+    a2dp_sbc_ups_cb.cur_pos += dst_sps;
+  }
+
+  if (a2dp_sbc_ups_cb.cur_pos == (int32_t)dst_sps) a2dp_sbc_ups_cb.cur_pos = 0;
+
+  *p_ret = ((char*)p_src_tmp - (char*)p_src);
+  return ((char*)p_dst_tmp - (char*)p_dst);
+}
+
+/*******************************************************************************
+**
+** Function         a2dp_sbc_up_sample_16m (16bits-mono)
+**
+** Description      Given the source (p_src) audio data and
+**                  source speed (src_sps, samples per second),
+**                  This function converts it to audio data in the desired
+**                  format
+**
+**                  p_src: the data buffer that holds the source audio data
+**                  p_dst: the data buffer to hold the converted audio data
+**                  src_samples: The number of source samples (in uint of 2
+**                               bytes)
+**                  dst_samples: The size of p_dst (in uint of 2 bytes)
+**
+** Returns          The number of bytes used in p_dst
+**                  The number of bytes used in p_src (in *p_ret)
+**
+*******************************************************************************/
+int a2dp_sbc_up_sample_16m(void* p_src, void* p_dst, uint32_t src_samples,
+                           uint32_t dst_samples, uint32_t* p_ret) {
+  int16_t* p_src_tmp = (int16_t*)p_src;
+  int16_t* p_dst_tmp = (int16_t*)p_dst;
+  int16_t* p_worker = &a2dp_sbc_ups_cb.worker1;
+  uint32_t src_sps = a2dp_sbc_ups_cb.src_sps;
+  uint32_t dst_sps = a2dp_sbc_ups_cb.dst_sps;
+
+  while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples) {
+    *p_dst_tmp++ = *p_worker;
+    *p_dst_tmp++ = *p_worker;
+
+    a2dp_sbc_ups_cb.cur_pos -= src_sps;
+    dst_samples--;
+    dst_samples--;
+  }
+
+  a2dp_sbc_ups_cb.cur_pos = dst_sps;
+
+  while (src_samples-- && dst_samples) {
+    *p_worker = *p_src_tmp++;
+
+    do {
+      *p_dst_tmp++ = *p_worker;
+      *p_dst_tmp++ = *p_worker;
+
+      a2dp_sbc_ups_cb.cur_pos -= src_sps;
+      dst_samples--;
+      dst_samples--;
+
+    } while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples);
+
+    a2dp_sbc_ups_cb.cur_pos += dst_sps;
+  }
+
+  if (a2dp_sbc_ups_cb.cur_pos == (int32_t)dst_sps) a2dp_sbc_ups_cb.cur_pos = 0;
+
+  *p_ret = ((char*)p_src_tmp - (char*)p_src);
+  return ((char*)p_dst_tmp - (char*)p_dst);
+}
+
+/*******************************************************************************
+**
+** Function         a2dp_sbc_up_sample_8s (8bits-stereo)
+**
+** Description      Given the source (p_src) audio data and
+**                  source speed (src_sps, samples per second),
+**                  This function converts it to audio data in the desired
+**                  format
+**
+**                  p_src: the data buffer that holds the source audio data
+**                  p_dst: the data buffer to hold the converted audio data
+**                  src_samples: The number of source samples (in uint of 2
+**                               bytes)
+**                  dst_samples: The size of p_dst (in uint of 2 bytes)
+**
+** Returns          The number of bytes used in p_dst
+**                  The number of bytes used in p_src (in *p_ret)
+**
+*******************************************************************************/
+int a2dp_sbc_up_sample_8s(void* p_src, void* p_dst, uint32_t src_samples,
+                          uint32_t dst_samples, uint32_t* p_ret) {
+  uint8_t* p_src_tmp = (uint8_t*)p_src;
+  int16_t* p_dst_tmp = (int16_t*)p_dst;
+  int16_t* p_worker1 = &a2dp_sbc_ups_cb.worker1;
+  int16_t* p_worker2 = &a2dp_sbc_ups_cb.worker2;
+  uint32_t src_sps = a2dp_sbc_ups_cb.src_sps;
+  uint32_t dst_sps = a2dp_sbc_ups_cb.dst_sps;
+
+  while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples) {
+    *p_dst_tmp++ = *p_worker1;
+    *p_dst_tmp++ = *p_worker2;
+
+    a2dp_sbc_ups_cb.cur_pos -= src_sps;
+    dst_samples--;
+    dst_samples--;
+  }
+
+  a2dp_sbc_ups_cb.cur_pos = dst_sps;
+
+  while (src_samples-- && dst_samples) {
+    *p_worker1 = *(uint8_t*)p_src_tmp++;
+    *p_worker1 -= 0x80;
+    *p_worker1 <<= 8;
+    *p_worker2 = *(uint8_t*)p_src_tmp++;
+    *p_worker2 -= 0x80;
+    *p_worker2 <<= 8;
+
+    do {
+      *p_dst_tmp++ = *p_worker1;
+      *p_dst_tmp++ = *p_worker2;
+
+      a2dp_sbc_ups_cb.cur_pos -= src_sps;
+      dst_samples--;
+      dst_samples--;
+    } while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples);
+
+    a2dp_sbc_ups_cb.cur_pos += dst_sps;
+  }
+
+  if (a2dp_sbc_ups_cb.cur_pos == (int32_t)dst_sps) a2dp_sbc_ups_cb.cur_pos = 0;
+
+  *p_ret = ((char*)p_src_tmp - (char*)p_src);
+  return ((char*)p_dst_tmp - (char*)p_dst);
+}
+
+/*******************************************************************************
+**
+** Function         a2dp_sbc_up_sample_8m (8bits-mono)
+**
+** Description      Given the source (p_src) audio data and
+**                  source speed (src_sps, samples per second),
+**                  This function converts it to audio data in the desired
+**                  format
+**
+**                  p_src: the data buffer that holds the source audio data
+**                  p_dst: the data buffer to hold the converted audio data
+**                  src_samples: The number of source samples (number of bytes)
+**                  dst_samples: The size of p_dst (number of bytes)
+**
+** Returns          The number of bytes used in p_dst
+**                  The number of bytes used in p_src (in *p_ret)
+**
+*******************************************************************************/
+int a2dp_sbc_up_sample_8m(void* p_src, void* p_dst, uint32_t src_samples,
+                          uint32_t dst_samples, uint32_t* p_ret) {
+  uint8_t* p_src_tmp = (uint8_t*)p_src;
+  int16_t* p_dst_tmp = (int16_t*)p_dst;
+  int16_t* p_worker = &a2dp_sbc_ups_cb.worker1;
+  uint32_t src_sps = a2dp_sbc_ups_cb.src_sps;
+  uint32_t dst_sps = a2dp_sbc_ups_cb.dst_sps;
+
+  while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples) {
+    *p_dst_tmp++ = *p_worker;
+    *p_dst_tmp++ = *p_worker;
+
+    a2dp_sbc_ups_cb.cur_pos -= src_sps;
+    dst_samples -= 4;
+  }
+
+  a2dp_sbc_ups_cb.cur_pos = dst_sps;
+
+  while (src_samples-- && dst_samples) {
+    *p_worker = *(uint8_t*)p_src_tmp++;
+    *p_worker -= 0x80;
+    *p_worker <<= 8;
+
+    do {
+      *p_dst_tmp++ = *p_worker;
+      *p_dst_tmp++ = *p_worker;
+
+      a2dp_sbc_ups_cb.cur_pos -= src_sps;
+      dst_samples -= 4;
+
+    } while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples);
+
+    a2dp_sbc_ups_cb.cur_pos += dst_sps;
+  }
+
+  if (a2dp_sbc_ups_cb.cur_pos == (int32_t)dst_sps) a2dp_sbc_ups_cb.cur_pos = 0;
+
+  *p_ret = ((char*)p_src_tmp - (char*)p_src);
+  return ((char*)p_dst_tmp - (char*)p_dst);
+}
diff --git a/bt/stack/a2dp/a2dp_vendor.cc b/bt/stack/a2dp/a2dp_vendor.cc
new file mode 100644
index 0000000..79fd70f
--- /dev/null
+++ b/bt/stack/a2dp/a2dp_vendor.cc
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Vendor Specific A2DP Codecs Support
+ */
+
+#define LOG_TAG "a2dp_vendor"
+
+#include "a2dp_vendor.h"
+#include "bt_target.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+const char* A2DP_VendorCodecSepIndexStr(tA2DP_CODEC_SEP_INDEX codec_sep_index)
+{
+  // Add checks based on codec_sep_index
+  switch (codec_sep_index) {
+    case A2DP_CODEC_SEP_INDEX_SOURCE_SBC:
+    case A2DP_CODEC_SEP_INDEX_SINK_SBC:
+      break;                    // This is not a vendor-specific codec
+    case A2DP_CODEC_SEP_INDEX_MAX:
+      break;
+  }
+
+  return "UNKNOWN CODEC SEP INDEX";
+}
+
+bool A2DP_VendorInitCodecConfig(tA2DP_CODEC_SEP_INDEX codec_sep_index,
+                                UNUSED_ATTR tAVDT_CFG* p_cfg)
+{
+  // Add checks based on codec_sep_index
+  switch (codec_sep_index) {
+    case A2DP_CODEC_SEP_INDEX_SOURCE_SBC:
+    case A2DP_CODEC_SEP_INDEX_SINK_SBC:
+      break;                    // This is not a vendor-specific codec
+    case A2DP_CODEC_SEP_INDEX_MAX:
+      break;
+  }
+
+  return false;
+}
+
+bool A2DP_IsVendorSourceCodecValid(UNUSED_ATTR const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return false;
+}
+
+bool A2DP_IsVendorSinkCodecValid(UNUSED_ATTR const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return false;
+}
+
+bool A2DP_IsVendorPeerSourceCodecValid(
+    UNUSED_ATTR const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return false;
+}
+
+bool A2DP_IsVendorPeerSinkCodecValid(UNUSED_ATTR const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return false;
+}
+
+bool A2DP_IsVendorSourceCodecSupported(
+    UNUSED_ATTR const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return false;
+}
+
+bool A2DP_IsVendorSinkCodecSupported(UNUSED_ATTR const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return false;
+}
+
+bool A2DP_IsVendorPeerSourceCodecSupported(
+    UNUSED_ATTR const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id> and peer codec capabilities
+
+  return false;
+}
+
+bool A2DP_VendorSetSourceCodec(tA2DP_CODEC_SEP_INDEX source_codec_sep_index,
+                               const tA2DP_FEEDING_PARAMS* p_feeding_params,
+                               uint8_t* p_codec_info) {
+  // Add checks based on codec_sep_index
+  switch (source_codec_sep_index) {
+    case A2DP_CODEC_SEP_INDEX_SOURCE_SBC:
+    case A2DP_CODEC_SEP_INDEX_SINK_SBC:
+      break;                    // This is not a vendor-specific codec
+    case A2DP_CODEC_SEP_INDEX_MAX:
+      break;
+  }
+
+  return false;
+}
+
+tA2DP_STATUS A2DP_VendorBuildSrc2SinkConfig(
+    UNUSED_ATTR const uint8_t* p_src_cap, UNUSED_ATTR uint8_t* p_pref_cfg) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return A2DP_NS_CODEC_TYPE;
+}
+
+tA2DP_STATUS A2DP_VendorBuildSinkConfig(
+    UNUSED_ATTR const uint8_t* p_src_config,
+    UNUSED_ATTR const uint8_t* p_sink_cap,
+    UNUSED_ATTR uint8_t* p_result_sink_config) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_src_config);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_src_config);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return A2DP_NS_CODEC_TYPE;
+}
+
+uint32_t A2DP_VendorCodecGetVendorId(const uint8_t* p_codec_info) {
+  const uint8_t* p = &p_codec_info[A2DP_VENDOR_CODEC_VENDOR_ID_START_IDX];
+
+  uint32_t vendor_id = (p[0] & 0x000000ff) | ((p[1] << 8) & 0x0000ff00) |
+                       ((p[2] << 16) & 0x00ff0000) |
+                       ((p[3] << 24) & 0xff000000);
+
+  return vendor_id;
+}
+
+uint16_t A2DP_VendorCodecGetCodecId(const uint8_t* p_codec_info) {
+  const uint8_t* p = &p_codec_info[A2DP_VENDOR_CODEC_CODEC_ID_START_IDX];
+
+  uint16_t codec_id = (p[0] & 0x00ff) | ((p[1] << 8) & 0xff00);
+
+  return codec_id;
+}
+
+bool A2DP_VendorUsesRtpHeader(UNUSED_ATTR bool content_protection_enabled,
+                              UNUSED_ATTR const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <content_protection_enabled, vendor_id, codec_id>
+
+  return true;
+}
+
+const char* A2DP_VendorCodecName(UNUSED_ATTR const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_src_config);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_src_config);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return "UNKNOWN VENDOR CODEC";
+}
+
+bool A2DP_VendorCodecTypeEquals(const uint8_t* p_codec_info_a,
+                                const uint8_t* p_codec_info_b) {
+  tA2DP_CODEC_TYPE codec_type_a = A2DP_GetCodecType(p_codec_info_a);
+  tA2DP_CODEC_TYPE codec_type_b = A2DP_GetCodecType(p_codec_info_b);
+
+  if ((codec_type_a != codec_type_b) ||
+      (codec_type_a != A2DP_MEDIA_CT_NON_A2DP)) {
+    return false;
+  }
+
+  uint32_t vendor_id_a = A2DP_VendorCodecGetVendorId(p_codec_info_a);
+  uint16_t codec_id_a = A2DP_VendorCodecGetCodecId(p_codec_info_a);
+  uint32_t vendor_id_b = A2DP_VendorCodecGetVendorId(p_codec_info_b);
+  uint16_t codec_id_b = A2DP_VendorCodecGetCodecId(p_codec_info_b);
+
+  // OPTIONAL: Add extra vendor-specific checks based on the
+  // vendor-specific data stored in "p_codec_info_a" and "p_codec_info_b".
+
+  return (vendor_id_a == vendor_id_b) && (codec_id_a == codec_id_b);
+}
+
+bool A2DP_VendorCodecEquals(const uint8_t* p_codec_info_a,
+                            const uint8_t* p_codec_info_b) {
+  tA2DP_CODEC_TYPE codec_type_a = A2DP_GetCodecType(p_codec_info_a);
+  tA2DP_CODEC_TYPE codec_type_b = A2DP_GetCodecType(p_codec_info_b);
+
+  if ((codec_type_a != codec_type_b) ||
+      (codec_type_a != A2DP_MEDIA_CT_NON_A2DP)) {
+    return false;
+  }
+
+  uint32_t vendor_id_a = A2DP_VendorCodecGetVendorId(p_codec_info_a);
+  uint16_t codec_id_a = A2DP_VendorCodecGetCodecId(p_codec_info_a);
+  uint32_t vendor_id_b = A2DP_VendorCodecGetVendorId(p_codec_info_b);
+  uint16_t codec_id_b = A2DP_VendorCodecGetCodecId(p_codec_info_b);
+
+  if ((vendor_id_a != vendor_id_b) || (codec_id_a != codec_id_b)) return false;
+
+  // Add extra vendor-specific checks based on the
+  // vendor-specific data stored in "p_codec_info_a" and "p_codec_info_b".
+
+  return false;
+}
+
+bool A2DP_VendorCodecRequiresReconfig(const uint8_t* p_codec_info_a,
+                                      const uint8_t* p_codec_info_b) {
+  tA2DP_CODEC_TYPE codec_type_a = A2DP_GetCodecType(p_codec_info_a);
+  tA2DP_CODEC_TYPE codec_type_b = A2DP_GetCodecType(p_codec_info_b);
+
+  if ((codec_type_a != codec_type_b) ||
+      (codec_type_a != A2DP_MEDIA_CT_NON_A2DP)) {
+    return true;
+  }
+
+  uint32_t vendor_id_a = A2DP_VendorCodecGetVendorId(p_codec_info_a);
+  uint16_t codec_id_a = A2DP_VendorCodecGetCodecId(p_codec_info_a);
+  uint32_t vendor_id_b = A2DP_VendorCodecGetVendorId(p_codec_info_b);
+  uint16_t codec_id_b = A2DP_VendorCodecGetCodecId(p_codec_info_b);
+
+  if ((vendor_id_a != vendor_id_b) || (codec_id_a != codec_id_b)) return true;
+
+  // Add extra vendor-specific checks based on the
+  // vendor-specific data stored in "p_codec_info_a" and "p_codec_info_b".
+
+  return true;
+}
+
+bool A2DP_VendorCodecConfigMatchesCapabilities(const uint8_t* p_codec_config,
+                                               const uint8_t* p_codec_caps) {
+  if (!A2DP_VendorCodecTypeEquals(p_codec_config, p_codec_caps)) return false;
+
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_config);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_config);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return false;
+}
+
+int A2DP_VendorGetTrackFrequency(UNUSED_ATTR const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return -1;
+}
+
+int A2DP_VendorGetTrackChannelCount(UNUSED_ATTR const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return -1;
+}
+
+int A2DP_VendorGetNumberOfSubbands(UNUSED_ATTR const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return -1;
+}
+
+int A2DP_VendorGetNumberOfBlocks(UNUSED_ATTR const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return -1;
+}
+
+int A2DP_VendorGetAllocationMethodCode(
+    UNUSED_ATTR const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return -1;
+}
+
+int A2DP_VendorGetChannelModeCode(UNUSED_ATTR const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return -1;
+}
+
+int A2DP_VendorGetSamplingFrequencyCode(
+    UNUSED_ATTR const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return -1;
+}
+
+int A2DP_VendorGetMinBitpool(UNUSED_ATTR const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return -1;
+}
+
+int A2DP_VendorGetMaxBitpool(UNUSED_ATTR const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return -1;
+}
+
+int A2DP_VendorGetSinkTrackChannelType(
+    UNUSED_ATTR const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return -1;
+}
+
+int A2DP_VendorGetSinkFramesCountToProcess(
+    UNUSED_ATTR uint64_t time_interval_ms,
+    UNUSED_ATTR const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return -1;
+}
+
+bool A2DP_VendorGetPacketTimestamp(UNUSED_ATTR const uint8_t* p_codec_info,
+                                   UNUSED_ATTR const uint8_t* p_data,
+                                   UNUSED_ATTR uint32_t* p_timestamp) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return false;
+}
+
+bool A2DP_VendorBuildCodecHeader(UNUSED_ATTR const uint8_t* p_codec_info,
+                                 UNUSED_ATTR BT_HDR* p_buf,
+                                 UNUSED_ATTR uint16_t frames_per_packet) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return false;
+}
+
+const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterface(
+    const uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return NULL;
+}
+
+bool A2DP_VendorAdjustCodec(uint8_t* p_codec_info) {
+  // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+  // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+  // Add checks based on <vendor_id, codec_id>
+
+  return false;
+}
diff --git a/bt/stack/avct/avct_api.cc b/bt/stack/avct/avct_api.cc
new file mode 100644
index 0000000..5e3a465
--- /dev/null
+++ b/bt/stack/avct/avct_api.cc
@@ -0,0 +1,457 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2016 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 module contains API of the audio/video control transport protocol.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "bt_common.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "btm_api.h"
+#include "avct_api.h"
+#include "avct_int.h"
+#include "osi/include/osi.h"
+
+/* Control block for AVCT */
+tAVCT_CB avct_cb;
+
+/*******************************************************************************
+**
+** Function         AVCT_Register
+**
+** Description      This is the system level registration function for the
+**                  AVCTP protocol.  This function initializes AVCTP and
+**                  prepares the protocol stack for its use.  This function
+**                  must be called once by the system or platform using AVCTP
+**                  before the other functions of the API an be used.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void AVCT_Register(uint16_t mtu,
+                   UNUSED_ATTR uint16_t mtu_br, uint8_t sec_mask)
+{
+    AVCT_TRACE_API("AVCT_Register");
+
+    /* register PSM with L2CAP */
+    L2CA_Register(AVCT_PSM, (tL2CAP_APPL_INFO *) &avct_l2c_appl);
+
+    /* set security level */
+    BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_PSM, 0, 0);
+    BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_PSM, 0, 0);
+
+    /* initialize AVCTP data structures */
+    memset(&avct_cb, 0, sizeof(tAVCT_CB));
+
+    /* Include the browsing channel which uses eFCR */
+    L2CA_Register(AVCT_BR_PSM, (tL2CAP_APPL_INFO *) &avct_l2c_br_appl);
+
+    /* AVCTP browsing channel uses the same security service as AVCTP control channel */
+    BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_BR_PSM, 0, 0);
+    BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_BR_PSM, 0, 0);
+
+    if (mtu_br < AVCT_MIN_BROWSE_MTU)
+        mtu_br = AVCT_MIN_BROWSE_MTU;
+    avct_cb.mtu_br = mtu_br;
+
+#if defined(AVCT_INITIAL_TRACE_LEVEL)
+    avct_cb.trace_level = AVCT_INITIAL_TRACE_LEVEL;
+#else
+    avct_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+
+    if (mtu < AVCT_MIN_CONTROL_MTU)
+        mtu = AVCT_MIN_CONTROL_MTU;
+    /* store mtu */
+    avct_cb.mtu = mtu;
+}
+
+/*******************************************************************************
+**
+** Function         AVCT_Deregister
+**
+** Description      This function is called to deregister use AVCTP protocol.
+**                  It is called when AVCTP is no longer being used by any
+**                  application in the system.  Before this function can be
+**                  called, all connections must be removed with
+**                  AVCT_RemoveConn().
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void AVCT_Deregister(void)
+{
+    AVCT_TRACE_API("AVCT_Deregister");
+
+    /* deregister PSM with L2CAP */
+    L2CA_Deregister(AVCT_PSM);
+}
+
+/*******************************************************************************
+**
+** Function         AVCT_CreateConn
+**
+** Description      Create an AVCTP connection.  There are two types of
+**                  connections, initiator and acceptor, as determined by
+**                  the p_cc->role parameter.  When this function is called to
+**                  create an initiator connection, an AVCTP connection to
+**                  the peer device is initiated if one does not already exist.
+**                  If an acceptor connection is created, the connection waits
+**                  passively for an incoming AVCTP connection from a peer device.
+**
+**
+** Returns          AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVCT_CreateConn(uint8_t *p_handle, tAVCT_CC *p_cc, BD_ADDR peer_addr)
+{
+    uint16_t    result = AVCT_SUCCESS;
+    tAVCT_CCB   *p_ccb;
+    tAVCT_LCB   *p_lcb;
+
+    AVCT_TRACE_API("AVCT_CreateConn: %d, control:%d", p_cc->role, p_cc->control);
+
+    /* Allocate ccb; if no ccbs, return failure */
+    if ((p_ccb = avct_ccb_alloc(p_cc)) == NULL)
+    {
+        result = AVCT_NO_RESOURCES;
+    }
+    else
+    {
+        /* get handle */
+        *p_handle = avct_ccb_to_idx(p_ccb);
+
+        /* if initiator connection */
+        if (p_cc->role == AVCT_INT)
+        {
+            /* find link; if none allocate a new one */
+            if ((p_lcb = avct_lcb_by_bd(peer_addr)) == NULL)
+            {
+                if ((p_lcb = avct_lcb_alloc(peer_addr)) == NULL)
+                {
+                    /* no link resources; free ccb as well */
+                    avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
+                    result = AVCT_NO_RESOURCES;
+                }
+            }
+            /* check if PID already in use */
+            else if (avct_lcb_has_pid(p_lcb, p_cc->pid))
+            {
+                avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
+                result = AVCT_PID_IN_USE;
+            }
+
+            if (result == AVCT_SUCCESS)
+            {
+                /* bind lcb to ccb */
+                p_ccb->p_lcb = p_lcb;
+                AVCT_TRACE_DEBUG("ch_state: %d", p_lcb->ch_state);
+                avct_lcb_event(p_lcb, AVCT_LCB_UL_BIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
+            }
+        }
+    }
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         AVCT_RemoveConn
+**
+** Description      Remove an AVCTP connection.  This function is called when
+**                  the application is no longer using a connection.  If this
+**                  is the last connection to a peer the L2CAP channel for AVCTP
+**                  will be closed.
+**
+**
+** Returns          AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVCT_RemoveConn(uint8_t handle)
+{
+    uint16_t            result = AVCT_SUCCESS;
+    tAVCT_CCB           *p_ccb;
+
+    AVCT_TRACE_API("AVCT_RemoveConn");
+
+    /* map handle to ccb */
+    if ((p_ccb = avct_ccb_by_idx(handle)) == NULL)
+    {
+        result = AVCT_BAD_HANDLE;
+    }
+    /* if connection not bound to lcb, dealloc */
+    else if (p_ccb->p_lcb == NULL)
+    {
+        avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
+    }
+    /* send unbind event to lcb */
+    else
+    {
+        avct_lcb_event(p_ccb->p_lcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
+    }
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         AVCT_CreateBrowse
+**
+** Description      Create an AVCTP Browse channel.  There are two types of
+**                  connections, initiator and acceptor, as determined by
+**                  the role parameter.  When this function is called to
+**                  create an initiator connection, the Browse channel to
+**                  the peer device is initiated if one does not already exist.
+**                  If an acceptor connection is created, the connection waits
+**                  passively for an incoming AVCTP connection from a peer device.
+**
+**
+** Returns          AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVCT_CreateBrowse (uint8_t handle, uint8_t role)
+{
+    uint16_t    result = AVCT_SUCCESS;
+    tAVCT_CCB   *p_ccb;
+    tAVCT_BCB   *p_bcb;
+    int         index;
+
+    AVCT_TRACE_API("AVCT_CreateBrowse: %d", role);
+
+    /* map handle to ccb */
+    if ((p_ccb = avct_ccb_by_idx(handle)) == NULL)
+    {
+        return AVCT_BAD_HANDLE;
+    }
+    else
+    {
+        /* mark this CCB as supporting browsing channel */
+        if ((p_ccb->allocated & AVCT_ALOC_BCB) == 0)
+        {
+            p_ccb->allocated |= AVCT_ALOC_BCB;
+        }
+    }
+
+    /* if initiator connection */
+    if (role == AVCT_INT)
+    {
+        /* the link control block must exist before this function is called as INT. */
+        if ((p_ccb->p_lcb == NULL) || (p_ccb->p_lcb->allocated == 0))
+        {
+            result = AVCT_NOT_OPEN;
+        }
+        else
+        {
+            /* find link; if none allocate a new one */
+            index = p_ccb->p_lcb->allocated;
+            if (index > AVCT_NUM_LINKS)
+            {
+                result = AVCT_BAD_HANDLE;
+            }
+            else
+            {
+                p_bcb = &avct_cb.bcb[index - 1];
+                p_bcb->allocated = index;
+            }
+        }
+
+        if (result == AVCT_SUCCESS)
+        {
+            /* bind bcb to ccb */
+            p_ccb->p_bcb = p_bcb;
+            memcpy(p_bcb->peer_addr, p_ccb->p_lcb->peer_addr, BD_ADDR_LEN);
+            AVCT_TRACE_DEBUG("ch_state: %d", p_bcb->ch_state);
+            avct_bcb_event(p_bcb, AVCT_LCB_UL_BIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
+        }
+    }
+
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         AVCT_RemoveBrowse
+**
+** Description      Remove an AVCTP Browse channel.  This function is called when
+**                  the application is no longer using a connection.  If this
+**                  is the last connection to a peer the L2CAP channel for AVCTP
+**                  will be closed.
+**
+**
+** Returns          AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVCT_RemoveBrowse (uint8_t handle)
+{
+    uint16_t            result = AVCT_SUCCESS;
+    tAVCT_CCB           *p_ccb;
+
+    AVCT_TRACE_API("AVCT_RemoveBrowse");
+
+    /* map handle to ccb */
+    if ((p_ccb = avct_ccb_by_idx(handle)) == NULL)
+    {
+        result = AVCT_BAD_HANDLE;
+    }
+    else if (p_ccb->p_bcb != NULL)
+    /* send unbind event to bcb */
+    {
+        avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
+    }
+
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         AVCT_GetBrowseMtu
+**
+** Description      Get the peer_mtu for the AVCTP Browse channel of the given
+**                  connection.
+**
+** Returns          the peer browsing channel MTU.
+**
+*******************************************************************************/
+uint16_t AVCT_GetBrowseMtu (uint8_t handle)
+{
+    uint16_t peer_mtu = AVCT_MIN_BROWSE_MTU;
+
+    tAVCT_CCB           *p_ccb;
+
+    if ((p_ccb = avct_ccb_by_idx(handle)) != NULL && p_ccb->p_bcb != NULL)
+    {
+        peer_mtu = p_ccb->p_bcb->peer_mtu;
+    }
+
+    return peer_mtu;
+}
+
+/*******************************************************************************
+**
+** Function         AVCT_GetPeerMtu
+**
+** Description      Get the peer_mtu for the AVCTP channel of the given
+**                  connection.
+**
+** Returns          the peer MTU size.
+**
+*******************************************************************************/
+uint16_t AVCT_GetPeerMtu (uint8_t handle)
+{
+    uint16_t    peer_mtu = L2CAP_DEFAULT_MTU;
+    tAVCT_CCB   *p_ccb;
+
+    /* map handle to ccb */
+    if ((p_ccb = avct_ccb_by_idx(handle)) != NULL)
+    {
+        if (p_ccb->p_lcb)
+        {
+            peer_mtu = p_ccb->p_lcb->peer_mtu;
+        }
+    }
+
+    return peer_mtu;
+}
+
+/*******************************************************************************
+**
+** Function         AVCT_MsgReq
+**
+** Description      Send an AVCTP message to a peer device.  In calling
+**                  AVCT_MsgReq(), the application should keep track of the
+**                  congestion state of AVCTP as communicated with events
+**                  AVCT_CONG_IND_EVT and AVCT_UNCONG_IND_EVT.   If the
+**                  application calls AVCT_MsgReq() when AVCTP is congested
+**                  the message may be discarded.  The application may make its
+**                  first call to AVCT_MsgReq() after it receives an
+**                  AVCT_CONNECT_CFM_EVT or AVCT_CONNECT_IND_EVT on control channel or
+**                  AVCT_BROWSE_CONN_CFM_EVT or AVCT_BROWSE_CONN_IND_EVT on browsing channel.
+**
+**                  p_msg->layer_specific must be set to
+**                  AVCT_DATA_CTRL for control channel traffic;
+**                  AVCT_DATA_BROWSE for for browse channel traffic.
+**
+** Returns          AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVCT_MsgReq(uint8_t handle, uint8_t label, uint8_t cr, BT_HDR *p_msg)
+{
+    uint16_t        result = AVCT_SUCCESS;
+    tAVCT_CCB       *p_ccb;
+    tAVCT_UL_MSG    ul_msg;
+
+    AVCT_TRACE_API("%s", __func__);
+
+    /* verify p_msg parameter */
+    if (p_msg == NULL)
+    {
+        return AVCT_NO_RESOURCES;
+    }
+    AVCT_TRACE_API("%s len: %d layer_specific: %d", __func__, p_msg->len, p_msg->layer_specific);
+
+    /* map handle to ccb */
+    if ((p_ccb = avct_ccb_by_idx(handle)) == NULL)
+    {
+        result = AVCT_BAD_HANDLE;
+        osi_free(p_msg);
+    }
+    /* verify channel is bound to link */
+    else if (p_ccb->p_lcb == NULL)
+    {
+        result = AVCT_NOT_OPEN;
+        osi_free(p_msg);
+    }
+
+    if (result == AVCT_SUCCESS)
+    {
+        ul_msg.p_buf = p_msg;
+        ul_msg.p_ccb = p_ccb;
+        ul_msg.label = label;
+        ul_msg.cr = cr;
+
+        /* send msg event to bcb */
+        if (p_msg->layer_specific == AVCT_DATA_BROWSE)
+        {
+            if (p_ccb->p_bcb == NULL && (p_ccb->allocated & AVCT_ALOC_BCB) == 0)
+            {
+                /* BCB channel is not open and not allocated */
+                result = AVCT_BAD_HANDLE;
+                osi_free(p_msg);
+            }
+            else
+            {
+                p_ccb->p_bcb = avct_bcb_by_lcb(p_ccb->p_lcb);
+                avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_MSG_EVT, (tAVCT_LCB_EVT *) &ul_msg);
+            }
+        }
+        /* send msg event to lcb */
+        else
+        {
+            avct_lcb_event(p_ccb->p_lcb, AVCT_LCB_UL_MSG_EVT, (tAVCT_LCB_EVT *) &ul_msg);
+        }
+    }
+    return result;
+}
+
diff --git a/bt/stack/avct/avct_bcb_act.cc b/bt/stack/avct/avct_bcb_act.cc
new file mode 100644
index 0000000..903c3f7
--- /dev/null
+++ b/bt/stack/avct/avct_bcb_act.cc
@@ -0,0 +1,736 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2016 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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+*
+*  Name:           avct_bcb_act.cc
+*
+*  Description:    This module contains action functions of the browsing control
+*                  state machine.
+*
+******************************************************************************/
+
+
+#include <string.h>
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avct_api.h"
+#include "avct_int.h"
+#include "btm_api.h"
+#include "osi/include/osi.h"
+
+/* action function list */
+const tAVCT_BCB_ACTION avct_bcb_action[] = {
+    avct_bcb_chnl_open,     /* AVCT_LCB_CHNL_OPEN */
+    avct_bcb_chnl_disc,     /* AVCT_LCB_CHNL_DISC */
+    avct_bcb_send_msg,      /* AVCT_LCB_SEND_MSG */
+    avct_bcb_open_ind,      /* AVCT_LCB_OPEN_IND */
+    avct_bcb_open_fail,     /* AVCT_LCB_OPEN_FAIL */
+    avct_bcb_close_ind,     /* AVCT_LCB_CLOSE_IND */
+    avct_bcb_close_cfm,     /* AVCT_LCB_CLOSE_CFM */
+    avct_bcb_msg_ind,       /* AVCT_LCB_MSG_IND */
+    avct_bcb_cong_ind,      /* AVCT_LCB_CONG_IND */
+    avct_bcb_bind_conn,     /* AVCT_LCB_BIND_CONN */
+    avct_bcb_bind_fail,     /* AVCT_LCB_BIND_FAIL */
+    avct_bcb_unbind_disc,   /* AVCT_LCB_UNBIND_DISC */
+    avct_bcb_chk_disc,      /* AVCT_LCB_CHK_DISC */
+    avct_bcb_discard_msg,   /* AVCT_LCB_DISCARD_MSG */
+    avct_bcb_dealloc,       /* AVCT_LCB_DEALLOC */
+    avct_bcb_free_msg_ind   /* AVCT_LCB_FREE_MSG_IND */
+};
+
+
+/*******************************************************************************
+**
+** Function         avct_bcb_msg_asmbl
+**
+** Description      Reassemble incoming message.
+**
+**
+** Returns          Pointer to reassembled message;  NULL if no message
+**                  available.
+**
+*******************************************************************************/
+static BT_HDR *avct_bcb_msg_asmbl(UNUSED_ATTR tAVCT_BCB *p_bcb, BT_HDR *p_buf)
+{
+    uint8_t   *p;
+    uint8_t   pkt_type;
+
+    /* parse the message header */
+    p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+    pkt_type = AVCT_PKT_TYPE(p);
+
+    /* must be single packet - can not fragment */
+    if (pkt_type != AVCT_PKT_TYPE_SINGLE)
+    {
+        osi_free_and_reset((void **)&p_buf);
+        AVCT_TRACE_WARNING("Pkt type=%d - fragmentation not allowed. drop it", pkt_type);
+    }
+    return p_buf;
+}
+
+
+/*******************************************************************************
+**
+** Function         avct_bcb_chnl_open
+**
+** Description      Open L2CAP channel to peer
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_chnl_open(tAVCT_BCB *p_bcb,
+                        UNUSED_ATTR tAVCT_LCB_EVT *p_data)
+{
+    uint16_t              result = AVCT_RESULT_FAIL;
+    tAVCT_LCB           *p_lcb = avct_lcb_by_bcb(p_bcb);
+    tL2CAP_ERTM_INFO    ertm_info;
+
+    BTM_SetOutService(p_lcb->peer_addr, BTM_SEC_SERVICE_AVCTP_BROWSE, 0);
+
+    /* Set the FCR options: Browsing channel mandates ERTM */
+    ertm_info.preferred_mode  = avct_l2c_br_fcr_opts_def.mode;
+    ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
+    ertm_info.user_rx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+    ertm_info.user_tx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+    ertm_info.fcr_rx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+    ertm_info.fcr_tx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+
+    /* call l2cap connect req */
+    p_bcb->ch_state = AVCT_CH_CONN;
+    p_bcb->ch_lcid = L2CA_ErtmConnectReq(AVCT_BR_PSM, p_lcb->peer_addr, &ertm_info);
+    if (p_bcb->ch_lcid == 0)
+    {
+        /* if connect req failed, send ourselves close event */
+        avct_bcb_event(p_bcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_unbind_disc
+**
+** Description      call callback with disconnect event.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_unbind_disc(UNUSED_ATTR tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    p_data->p_ccb->p_bcb = NULL;
+    (*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb),
+            AVCT_BROWSE_DISCONN_CFM_EVT, 0, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_open_ind
+**
+** Description      Handle an LL_OPEN event.
+**                  For the allocated ccb already bound to the bcb, send a connect event.
+**                  For the unbound ccb with a new PID, bind that ccb to the bcb with the
+**                  same bd_addr and send a connect event.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_open_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_CCB       *p_ccb = &avct_cb.ccb[0];
+    tAVCT_CCB       *p_ccb_bind = NULL;
+    bool         bind = false;
+    tAVCT_UL_MSG    ul_msg;
+
+    for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++)
+    {
+        /* if ccb allocated and */
+        if (p_ccb->allocated)
+        {
+            /* if bound to this bcb send connect confirm event */
+            if (p_ccb->p_bcb == p_bcb)
+            {
+                bind = true;
+                p_ccb_bind = p_ccb;
+                p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_CONN_CFM_EVT,
+                                       0, p_ccb->p_lcb->peer_addr);
+            }
+            /* if unbound acceptor and lcb allocated and bd_addr are the same for bcb and lcb */
+            else if ((p_ccb->p_bcb == NULL) && (p_ccb->cc.role == AVCT_ACP) &&
+                     (p_ccb->p_lcb != NULL) &&
+                     (!memcmp(p_bcb->peer_addr, p_ccb->p_lcb->peer_addr, BD_ADDR_LEN)))
+            {
+                /* bind bcb to ccb and send connect ind event */
+                bind = true;
+                p_ccb_bind = p_ccb;
+                p_ccb->p_bcb = p_bcb;
+                p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_CONN_IND_EVT,
+                                    0, p_ccb->p_lcb->peer_addr);
+            }
+        }
+    }
+
+    /* if no ccbs bound to this lcb, disconnect */
+    if (bind == false)
+    {
+        avct_bcb_event(p_bcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
+        return;
+    }
+
+    if (!p_bcb->p_tx_msg || !p_ccb_bind)
+    {
+        return;
+    }
+
+    ul_msg.p_buf = p_bcb->p_tx_msg;
+    ul_msg.p_ccb = p_ccb_bind;
+    ul_msg.label = (uint8_t)(p_bcb->p_tx_msg->layer_specific & 0xFF);
+    ul_msg.cr = (uint8_t)((p_bcb->p_tx_msg->layer_specific & 0xFF00) >> 8);
+    p_bcb->p_tx_msg->layer_specific = AVCT_DATA_BROWSE;
+    p_bcb->p_tx_msg = NULL;
+
+    /* send msg event to bcb */
+    avct_bcb_event(p_bcb, AVCT_LCB_UL_MSG_EVT, (tAVCT_LCB_EVT *) &ul_msg);
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_open_fail
+**
+** Description      L2CAP channel open attempt failed.  Mark the ccbs
+**                  as NULL bcb.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_open_fail(tAVCT_BCB *p_bcb,
+                        UNUSED_ATTR tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
+
+    for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++)
+    {
+        if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb))
+        {
+            p_ccb->p_bcb = NULL;
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_close_ind
+**
+** Description      L2CAP channel closed by peer.  Deallocate any initiator
+**                  ccbs on this lcb and send disconnect ind event.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_close_ind(tAVCT_BCB *p_bcb,
+                        UNUSED_ATTR tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
+    tAVCT_LCB   *p_lcb = avct_lcb_by_bcb(p_bcb);
+
+    for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++)
+    {
+        if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb))
+        {
+            if (p_ccb->cc.role == AVCT_INT)
+            {
+                (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_DISCONN_CFM_EVT,
+                        0, p_lcb->peer_addr);
+            }
+            else
+            {
+                (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_DISCONN_IND_EVT,
+                        0, NULL);
+            }
+            p_ccb->p_bcb = NULL;
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_close_cfm
+**
+** Description      L2CAP channel closed by us.  Deallocate any initiator
+**                  ccbs on this lcb and send disconnect ind or cfm event.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_close_cfm(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_CCB           *p_ccb = &avct_cb.ccb[0];
+    uint8_t               event = 0;
+    bool             ch_close = p_bcb->ch_close;    /* Whether BCB initiated channel close */
+    tAVCT_CTRL_CBACK    *p_cback;
+
+    p_bcb->ch_close = false;
+    p_bcb->allocated = 0;
+    for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++)
+    {
+        if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb))
+        {
+            /* if this ccb initiated close send disconnect cfm otherwise ind */
+            if (ch_close)
+            {
+                event = AVCT_BROWSE_DISCONN_CFM_EVT;
+            }
+            else
+            {
+                event = AVCT_BROWSE_DISCONN_IND_EVT;
+            }
+
+            p_cback = p_ccb->cc.p_ctrl_cback;
+            p_ccb->p_bcb = NULL;
+            if (p_ccb->p_lcb == NULL)
+                avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
+            (*p_cback)(avct_ccb_to_idx(p_ccb), event,
+                                       p_data->result, p_bcb->peer_addr);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_bind_conn
+**
+** Description      Bind ccb to lcb and send connect cfm event.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_bind_conn(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_LCB *p_lcb = avct_lcb_by_bcb(p_bcb);
+    p_data->p_ccb->p_bcb = p_bcb;
+    (*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb),
+                                      AVCT_BROWSE_CONN_CFM_EVT, 0, p_lcb->peer_addr);
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_chk_disc
+**
+** Description      A ccb wants to close; if it is the last ccb on this lcb,
+**                  close channel.  Otherwise just deallocate and call
+**                  callback.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_chk_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    p_bcb->ch_close = avct_bcb_get_last_ccb_index(p_bcb, p_data->p_ccb);
+    if (p_bcb->ch_close)
+    {
+        avct_bcb_event(p_bcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
+        return;
+    }
+
+    avct_bcb_unbind_disc(p_bcb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_chnl_disc
+**
+** Description      Disconnect L2CAP channel.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_chnl_disc(tAVCT_BCB *p_bcb,
+                        UNUSED_ATTR tAVCT_LCB_EVT *p_data)
+{
+    L2CA_DisconnectReq(p_bcb->ch_lcid);
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_bind_fail
+**
+** Description      Deallocate ccb and call callback with connect event
+**                  with failure result.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_bind_fail(UNUSED_ATTR tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    p_data->p_ccb->p_bcb = NULL;
+    (*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb),
+            AVCT_BROWSE_CONN_CFM_EVT, AVCT_RESULT_FAIL, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_cong_ind
+**
+** Description      Handle congestion indication from L2CAP.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_cong_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
+    uint8_t       event;
+    tAVCT_LCB   *p_lcb = avct_lcb_by_bcb(p_bcb);
+
+    /* set event */
+    event = (p_data->cong) ? AVCT_BROWSE_CONG_IND_EVT : AVCT_BROWSE_UNCONG_IND_EVT;
+
+    /* send event to all ccbs on this lcb */
+    for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++)
+    {
+        if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb))
+        {
+            (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), event, 0, p_lcb->peer_addr);
+        }
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_discard_msg
+**
+** Description      Discard a message sent in from the API.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_discard_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    osi_free_and_reset((void **)&p_bcb->p_tx_msg);
+
+    /* if control channel is up, save the message and open the browsing channel */
+    if (p_data->ul_msg.p_ccb->p_lcb == NULL)
+    {
+        osi_free_and_reset((void **)&p_data->ul_msg.p_buf);
+        return;
+    }
+    p_bcb->p_tx_msg = p_data->ul_msg.p_buf;
+
+    if (p_bcb->p_tx_msg)
+    {
+        p_bcb->p_tx_msg->layer_specific = (p_data->ul_msg.cr << 8) + p_data->ul_msg.label;
+
+        /* the channel is closed, opening or closing - open it again */
+        AVCT_TRACE_DEBUG("ch_state: %d, allocated:%d->%d", p_bcb->ch_state, p_bcb->allocated,
+            p_data->ul_msg.p_ccb->p_lcb->allocated);
+        p_bcb->allocated = p_data->ul_msg.p_ccb->p_lcb->allocated;
+        avct_bcb_event(p_bcb, AVCT_LCB_UL_BIND_EVT, (tAVCT_LCB_EVT *) p_data->ul_msg.p_ccb);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_send_msg
+**
+** Description      Build and send an AVCTP message.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_send_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    uint16_t  curr_msg_len;
+    uint8_t   pkt_type = AVCT_PKT_TYPE_SINGLE;
+    uint8_t   hdr_len;
+    BT_HDR  *p_buf;
+    uint8_t   *p;
+
+    /* store msg len */
+    curr_msg_len = p_data->ul_msg.p_buf->len;
+
+    /* initialize packet type and other stuff */
+    if (curr_msg_len > (p_bcb->peer_mtu - AVCT_HDR_LEN_SINGLE))
+    {
+        AVCT_TRACE_ERROR ("%s msg len (%d) exceeds peer mtu(%d-%d)!!", __func__,
+                    curr_msg_len, p_bcb->peer_mtu, AVCT_HDR_LEN_SINGLE);
+        osi_free_and_reset((void **)&p_data->ul_msg.p_buf);
+        return;
+    }
+
+    /* set header len */
+    hdr_len = avct_lcb_pkt_type_len[pkt_type];
+    p_buf = p_data->ul_msg.p_buf;
+
+    /* set up to build header */
+    p_buf->len += hdr_len;
+    p_buf->offset -= hdr_len;
+    p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+    /* build header */
+    AVCT_BUILD_HDR(p, p_data->ul_msg.label, pkt_type, p_data->ul_msg.cr);
+    UINT16_TO_BE_STREAM(p, p_data->ul_msg.p_ccb->cc.pid);
+
+    p_buf->layer_specific = AVCT_DATA_BROWSE;
+
+    /* send message to L2CAP */
+    L2CA_DataWrite(p_bcb->ch_lcid, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_free_msg_ind
+**
+** Description      Discard an incoming AVCTP message.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_free_msg_ind(UNUSED_ATTR tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    if (p_data)
+        osi_free_and_reset((void **)&p_data->p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_msg_ind
+**
+** Description      Handle an incoming AVCTP message.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_msg_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data)
+{
+    uint8_t       *p;
+    uint8_t       label, type, cr_ipid;
+    uint16_t      pid;
+    tAVCT_CCB   *p_ccb;
+    tAVCT_LCB   *p_lcb = avct_lcb_by_bcb(p_bcb);
+
+    if ((p_data == NULL) || (p_data->p_buf == NULL))
+    {
+        AVCT_TRACE_WARNING("%s p_data is NULL, returning!", __func__);
+        return;
+    }
+
+    /* this p_buf is to be reported through p_msg_cback. The layer_specific
+     * needs to be set properly to indicate that it is received through
+     * browsing channel */
+    p_data->p_buf->layer_specific = AVCT_DATA_BROWSE;
+
+    /* reassemble message; if no message available (we received a fragment) return */
+    p_data->p_buf = avct_bcb_msg_asmbl(p_bcb, p_data->p_buf);
+    if (p_data->p_buf == NULL)
+    {
+        return;
+    }
+
+    p = (uint8_t *)(p_data->p_buf + 1) + p_data->p_buf->offset;
+
+    /* parse header byte */
+    AVCT_PARSE_HDR(p, label, type, cr_ipid);
+
+    /* check for invalid cr_ipid */
+    if (cr_ipid == AVCT_CR_IPID_INVALID)
+    {
+        AVCT_TRACE_WARNING("Invalid cr_ipid", cr_ipid);
+        osi_free_and_reset((void **)&p_data->p_buf);
+        return;
+    }
+
+    /* parse and lookup PID */
+    BE_STREAM_TO_UINT16(pid, p);
+    p_ccb = avct_lcb_has_pid(p_lcb, pid);
+    if (p_ccb)
+    {
+        /* PID found; send msg up, adjust bt hdr and call msg callback */
+        p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE;
+        p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE;
+        (*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid, p_data->p_buf);
+        return;
+    }
+
+    /* PID not found; drop message */
+    AVCT_TRACE_WARNING("No ccb for PID=%x", pid);
+    osi_free_and_reset((void **)&p_data->p_buf);
+
+    /* if command send reject */
+    if (cr_ipid == AVCT_CMD)
+    {
+        BT_HDR *p_buf = (BT_HDR *) osi_malloc(AVRC_CMD_BUF_SIZE);
+        p_buf->len = AVCT_HDR_LEN_SINGLE;
+        p_buf->offset = AVCT_MSG_OFFSET - AVCT_HDR_LEN_SINGLE;
+        p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+        AVCT_BUILD_HDR(p, label, AVCT_PKT_TYPE_SINGLE, AVCT_REJ);
+        UINT16_TO_BE_STREAM(p, pid);
+        p_buf->layer_specific = AVCT_DATA_BROWSE;
+        L2CA_DataWrite(p_bcb->ch_lcid, p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_dealloc
+**
+** Description      Deallocate a browse control block.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avct_bcb_dealloc(tAVCT_BCB *p_bcb,
+                      UNUSED_ATTR tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
+
+    AVCT_TRACE_DEBUG("%s %d", __func__, p_bcb->allocated);
+
+    for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++)
+    {
+        /* if ccb allocated and */
+        if ((p_ccb->allocated) && (p_ccb->p_bcb == p_bcb))
+        {
+            p_ccb->p_bcb = NULL;
+            AVCT_TRACE_DEBUG("%s used by ccb: %d", __func__, idx);
+            break;
+        }
+    }
+
+    /* the browsing channel is down. Check if we have pending messages */
+    osi_free_and_reset((void **)&p_bcb->p_tx_msg);
+    memset(p_bcb, 0, sizeof(tAVCT_BCB));
+}
+
+/*******************************************************************************
+**
+** Function         avct_close_bcb
+**
+** Description      this function is called right before LCB disconnects.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_close_bcb(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_BCB   *p_bcb = avct_bcb_by_lcb(p_lcb);
+    if (p_bcb->allocated)
+    {
+        avct_bcb_event(p_bcb, AVCT_LCB_UL_UNBIND_EVT, p_data);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         avct_lcb_by_bcb
+**
+** Description      This lookup function finds the lcb for a bcb.
+**
+** Returns          pointer to the lcb.
+**
+*******************************************************************************/
+tAVCT_LCB *avct_lcb_by_bcb(tAVCT_BCB *p_bcb)
+{
+    return &avct_cb.lcb[p_bcb->allocated - 1];
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_by_lcb
+**
+** Description      This lookup function finds the bcb for a lcb.
+**
+** Returns          pointer to the lcb.
+**
+*******************************************************************************/
+tAVCT_BCB *avct_bcb_by_lcb(tAVCT_LCB *p_lcb)
+{
+    return &avct_cb.bcb[p_lcb->allocated - 1];
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_get_last_ccb_index
+**
+** Description      See if given ccb is only one on the bcb.
+**
+**
+** Returns          0, if ccb is last,  (ccb index + 1) otherwise.
+**
+*******************************************************************************/
+uint8_t avct_bcb_get_last_ccb_index(tAVCT_BCB *p_bcb, tAVCT_CCB *p_ccb_last)
+{
+    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
+    uint8_t       idx = 0;
+
+    for (int i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+    {
+        if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb))
+        {
+            if (p_ccb != p_ccb_last)
+                return 0;
+            idx = (uint8_t)(i + 1);
+        }
+    }
+    return idx;
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_by_lcid
+**
+** Description      Find the BCB associated with the L2CAP LCID
+**
+**
+** Returns          pointer to the lcb, or NULL if none found.
+**
+*******************************************************************************/
+tAVCT_BCB *avct_bcb_by_lcid(uint16_t lcid)
+{
+    tAVCT_BCB   *p_bcb = &avct_cb.bcb[0];
+    int         idx;
+
+    for (idx = 0; idx < AVCT_NUM_LINKS; idx++, p_bcb++)
+    {
+        if (p_bcb->allocated && (p_bcb->ch_lcid == lcid))
+        {
+            return p_bcb;
+        }
+    }
+
+    /* out of lcbs */
+    AVCT_TRACE_WARNING("No bcb for lcid %x", lcid);
+    return NULL;
+}
diff --git a/bt/stack/avct/avct_ccb.cc b/bt/stack/avct/avct_ccb.cc
new file mode 100644
index 0000000..7516853
--- /dev/null
+++ b/bt/stack/avct/avct_ccb.cc
@@ -0,0 +1,149 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 module contains functions which operate on the AVCTP connection
+ *  control block.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "avct_api.h"
+#include "avct_int.h"
+
+/*******************************************************************************
+**
+** Function         avct_ccb_alloc
+**
+** Description      Allocate a connection control block; copy parameters to ccb.
+**
+**
+** Returns          pointer to the ccb, or NULL if none could be allocated.
+**
+*******************************************************************************/
+tAVCT_CCB *avct_ccb_alloc(tAVCT_CC *p_cc)
+{
+    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
+    int         i;
+
+    for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+    {
+        if (!p_ccb->allocated)
+        {
+            p_ccb->allocated = AVCT_ALOC_LCB;
+            memcpy(&p_ccb->cc, p_cc, sizeof(tAVCT_CC));
+            AVCT_TRACE_DEBUG("avct_ccb_alloc %d", i);
+            break;
+        }
+    }
+
+    if (i == AVCT_NUM_CONN)
+    {
+        /* out of ccbs */
+        p_ccb = NULL;
+        AVCT_TRACE_WARNING("Out of ccbs");
+    }
+    return p_ccb;
+}
+
+/*******************************************************************************
+**
+** Function         avct_ccb_dealloc
+**
+** Description      Deallocate a connection control block and call application
+**                  callback.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avct_ccb_dealloc(tAVCT_CCB *p_ccb, uint8_t event, uint16_t result, BD_ADDR bd_addr)
+{
+    tAVCT_CTRL_CBACK    *p_cback = p_ccb->cc.p_ctrl_cback;
+
+    AVCT_TRACE_DEBUG("avct_ccb_dealloc %d", avct_ccb_to_idx(p_ccb));
+
+    if(p_ccb->p_bcb == NULL)
+    {
+        memset(p_ccb, 0, sizeof(tAVCT_CCB));
+    }
+    else
+    {
+        /* control channel is down, but the browsing channel is still connected 0 disconnect it now */
+        avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
+        p_ccb->p_lcb = NULL;
+    }
+
+    if (event != AVCT_NO_EVT)
+    {
+        (*p_cback)(avct_ccb_to_idx(p_ccb), event, result, bd_addr);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_ccb_to_idx
+**
+** Description      Given a pointer to an ccb, return its index.
+**
+**
+** Returns          Index of ccb.
+**
+*******************************************************************************/
+uint8_t avct_ccb_to_idx(tAVCT_CCB *p_ccb)
+{
+    /* use array arithmetic to determine index */
+    return (uint8_t) (p_ccb - avct_cb.ccb);
+}
+
+/*******************************************************************************
+**
+** Function         avct_ccb_by_idx
+**
+** Description      Return ccb pointer based on ccb index (or handle).
+**
+**
+** Returns          pointer to the ccb, or NULL if none found.
+**
+*******************************************************************************/
+tAVCT_CCB *avct_ccb_by_idx(uint8_t idx)
+{
+    tAVCT_CCB   *p_ccb;
+
+    /* verify index */
+    if (idx < AVCT_NUM_CONN)
+    {
+        p_ccb = &avct_cb.ccb[idx];
+
+        /* verify ccb is allocated */
+        if (!p_ccb->allocated)
+        {
+            p_ccb = NULL;
+            AVCT_TRACE_WARNING("ccb %d not allocated", idx);
+        }
+    }
+    else
+    {
+        p_ccb = NULL;
+        AVCT_TRACE_WARNING("No ccb for idx %d", idx);
+    }
+    return p_ccb;
+}
diff --git a/bt/stack/avct/avct_defs.h b/bt/stack/avct/avct_defs.h
new file mode 100644
index 0000000..c149d04
--- /dev/null
+++ b/bt/stack/avct/avct_defs.h
@@ -0,0 +1,63 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 contains constants definitions and other information from the AVCTP
+ *  specification.  This file is intended for use internal to AVCT only.
+ *
+ ******************************************************************************/
+#ifndef AVCT_DEFS_H
+#define AVCT_DEFS_H
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* packet type */
+#define AVCT_PKT_TYPE_SINGLE        0       /* single packet */
+#define AVCT_PKT_TYPE_START         1       /* start packet */
+#define AVCT_PKT_TYPE_CONT          2       /* continue packet */
+#define AVCT_PKT_TYPE_END           3       /* end packet */
+
+/* header lengths for different packet types */
+#define AVCT_HDR_LEN_SINGLE         3
+#define AVCT_HDR_LEN_START          4
+#define AVCT_HDR_LEN_CONT           1
+#define AVCT_HDR_LEN_END            1
+
+/* invalid cr+ipid value */
+#define AVCT_CR_IPID_INVALID        1
+
+/*****************************************************************************
+** message parsing and building macros
+*****************************************************************************/
+
+#define AVCT_BUILD_HDR(p, label, type, cr_ipid) \
+  *(p)++ = ((label) << 4) | ((type) << 2) | (cr_ipid);
+
+#define AVCT_PARSE_HDR(p, label, type, cr_ipid) \
+  do {                                          \
+    (label) = *(p) >> 4;                        \
+    (type) = (*(p) >> 2) & 3;                   \
+    (cr_ipid) = *(p)++ & 3;                     \
+  } while (0)
+
+#define AVCT_PKT_TYPE(p) ((*(p) >> 2) & 3)
+
+#endif /* AVCT_DEFS_H */
diff --git a/bt/stack/avct/avct_int.h b/bt/stack/avct/avct_int.h
new file mode 100644
index 0000000..6d9fe4a
--- /dev/null
+++ b/bt/stack/avct/avct_int.h
@@ -0,0 +1,228 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2016 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 interfaces which are internal to AVCTP.
+ *
+ ******************************************************************************/
+#ifndef AVCT_INT_H
+#define AVCT_INT_H
+
+#include "osi/include/fixed_queue.h"
+#include "bt_common.h"
+#include "avct_api.h"
+#include "avct_defs.h"
+#include "l2c_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* lcb state machine events */
+enum {
+    AVCT_LCB_UL_BIND_EVT,
+    AVCT_LCB_UL_UNBIND_EVT,
+    AVCT_LCB_UL_MSG_EVT,
+    AVCT_LCB_INT_CLOSE_EVT,
+    AVCT_LCB_LL_OPEN_EVT,
+    AVCT_LCB_LL_CLOSE_EVT,
+    AVCT_LCB_LL_MSG_EVT,
+    AVCT_LCB_LL_CONG_EVT
+};
+
+
+/* "states" used for L2CAP channel */
+#define AVCT_CH_IDLE    0       /* No connection */
+#define AVCT_CH_CONN    1       /* Waiting for connection confirm */
+#define AVCT_CH_CFG     2       /* Waiting for configuration complete */
+#define AVCT_CH_OPEN    3       /* Channel opened */
+
+/* "no event" indicator used by ccb dealloc */
+#define AVCT_NO_EVT     0xFF
+
+/*****************************************************************************
+** data types
+*****************************************************************************/
+/* sub control block type - common data members for tAVCT_LCB and tAVCT_BCB */
+typedef struct {
+    uint16_t            peer_mtu;	    /* peer l2c mtu */
+    uint16_t            ch_result;      /* L2CAP connection result value */
+    uint16_t            ch_lcid;        /* L2CAP channel LCID */
+    uint8_t             allocated;      /* 0, not allocated. index+1, otherwise. */
+    uint8_t             state;          /* The state machine state */
+    uint8_t             ch_state;       /* L2CAP channel state */
+    uint8_t             ch_flags;       /* L2CAP configuration flags */
+} tAVCT_SCB;
+
+/* link control block type */
+typedef struct {
+    uint16_t            peer_mtu;	    /* peer l2c mtu */
+    uint16_t            ch_result;      /* L2CAP connection result value */
+    uint16_t            ch_lcid;        /* L2CAP channel LCID */
+    uint8_t             allocated;      /* 0, not allocated. index+1, otherwise. */
+    uint8_t             state;          /* The state machine state */
+    uint8_t             ch_state;       /* L2CAP channel state */
+    uint8_t             ch_flags;       /* L2CAP configuration flags */
+    BT_HDR              *p_rx_msg;      /* Message being reassembled */
+    uint16_t            conflict_lcid;  /* L2CAP channel LCID */
+    BD_ADDR             peer_addr;      /* BD address of peer */
+    fixed_queue_t       *tx_q;          /* Transmit data buffer queue       */
+    bool                cong;           /* true, if congested */
+} tAVCT_LCB;
+
+/* browse control block type */
+typedef struct {
+    uint16_t            peer_mtu;	    /* peer l2c mtu */
+    uint16_t            ch_result;      /* L2CAP connection result value */
+    uint16_t            ch_lcid;        /* L2CAP channel LCID */
+    uint8_t             allocated;      /* 0, not allocated. index+1, otherwise. */
+    uint8_t             state;          /* The state machine state */
+    uint8_t             ch_state;       /* L2CAP channel state */
+    uint8_t             ch_flags;       /* L2CAP configuration flags */
+    BT_HDR              *p_tx_msg;      /* Message to be sent - in case the browsing channel is not open when MsgReg is called */
+    uint8_t             ch_close;       /* CCB index+1, if CCB initiated channel close */
+    BD_ADDR             peer_addr;      /* BD address of peer */
+} tAVCT_BCB;
+
+#define AVCT_ALOC_LCB       0x01
+#define AVCT_ALOC_BCB       0x02
+/* connection control block */
+typedef struct {
+    tAVCT_CC            cc;                 /* parameters from connection creation */
+    tAVCT_LCB           *p_lcb;             /* Associated LCB */
+    tAVCT_BCB           *p_bcb;             /* associated BCB */
+    bool                ch_close;           /* Whether CCB initiated channel close */
+    uint8_t             allocated;          /* Whether LCB/BCB is allocated */
+} tAVCT_CCB;
+
+/* data type associated with UL_MSG_EVT */
+typedef struct {
+    BT_HDR                  *p_buf;
+    tAVCT_CCB               *p_ccb;
+    uint8_t                 label;
+    uint8_t                 cr;
+} tAVCT_UL_MSG;
+
+/* union associated with lcb state machine events */
+typedef union {
+    tAVCT_UL_MSG            ul_msg;
+    BT_HDR                  *p_buf;
+    tAVCT_CCB               *p_ccb;
+    uint16_t                result;
+    bool                    cong;
+    uint8_t                 err_code;
+} tAVCT_LCB_EVT;
+
+/* Control block for AVCT */
+typedef struct {
+    tAVCT_LCB       lcb[AVCT_NUM_LINKS];    /* link control blocks */
+    tAVCT_BCB       bcb[AVCT_NUM_LINKS];    /* browse control blocks */
+    tAVCT_CCB       ccb[AVCT_NUM_CONN];     /* connection control blocks */
+    uint16_t        mtu;                    /* our L2CAP MTU */
+    uint16_t        mtu_br;                 /* our L2CAP MTU for the Browsing channel */
+    uint8_t         trace_level;            /* trace level */
+} tAVCT_CB;
+
+/*****************************************************************************
+** function declarations
+*****************************************************************************/
+
+/* LCB function declarations */
+extern void avct_lcb_event(tAVCT_LCB *p_lcb, uint8_t event, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_event(tAVCT_BCB *p_bcb, uint8_t event, tAVCT_LCB_EVT *p_data);
+extern void avct_close_bcb(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern tAVCT_LCB *avct_lcb_by_bcb(tAVCT_BCB *p_bcb);
+extern tAVCT_BCB *avct_bcb_by_lcb(tAVCT_LCB *p_lcb);
+extern uint8_t avct_bcb_get_last_ccb_index(tAVCT_BCB *p_bcb, tAVCT_CCB *p_ccb_last);
+extern tAVCT_BCB *avct_bcb_by_lcid(uint16_t lcid);
+extern tAVCT_LCB *avct_lcb_by_bd(BD_ADDR bd_addr);
+extern tAVCT_LCB *avct_lcb_alloc(BD_ADDR bd_addr);
+extern void avct_lcb_dealloc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern tAVCT_LCB *avct_lcb_by_lcid(uint16_t lcid);
+extern tAVCT_CCB *avct_lcb_has_pid(tAVCT_LCB *p_lcb, uint16_t pid);
+extern bool    avct_lcb_last_ccb(tAVCT_LCB *p_lcb, tAVCT_CCB *p_ccb_last);
+
+/* LCB action functions */
+extern void avct_lcb_chnl_open(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_unbind_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_open_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_open_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_close_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_close_cfm(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_bind_conn(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_chk_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_chnl_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_bind_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_cong_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_discard_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_send_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+extern void avct_lcb_free_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
+
+/* BCB action functions */
+typedef void (*tAVCT_BCB_ACTION)(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_chnl_open(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_unbind_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_open_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_open_fail(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_close_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_close_cfm(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_bind_conn(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_chk_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_chnl_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_bind_fail(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_cong_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_discard_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_send_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_msg_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+extern void avct_bcb_free_msg_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+
+extern void avct_bcb_dealloc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
+
+extern const tAVCT_BCB_ACTION avct_bcb_action[];
+extern const uint8_t avct_lcb_pkt_type_len[];
+extern const tL2CAP_FCR_OPTS avct_l2c_br_fcr_opts_def;
+
+/* CCB function declarations */
+extern tAVCT_CCB *avct_ccb_alloc(tAVCT_CC *p_cc);
+extern void avct_ccb_dealloc(tAVCT_CCB *p_ccb, uint8_t event, uint16_t result, BD_ADDR bd_addr);
+extern uint8_t avct_ccb_to_idx(tAVCT_CCB *p_ccb);
+extern tAVCT_CCB *avct_ccb_by_idx(uint8_t idx);
+
+
+/*****************************************************************************
+** global data
+*****************************************************************************/
+
+/* Main control block */
+extern tAVCT_CB avct_cb;
+
+/* L2CAP callback registration structure */
+extern const tL2CAP_APPL_INFO avct_l2c_appl;
+extern const tL2CAP_APPL_INFO avct_l2c_br_appl;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVCT_INT_H */
diff --git a/bt/stack/avct/avct_l2c.cc b/bt/stack/avct/avct_l2c.cc
new file mode 100644
index 0000000..f7f362e
--- /dev/null
+++ b/bt/stack/avct/avct_l2c.cc
@@ -0,0 +1,435 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 AVCTP module interfaces to L2CAP
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avct_api.h"
+#include "avct_int.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "osi/include/osi.h"
+
+/* Configuration flags. */
+#define AVCT_L2C_CFG_IND_DONE   (1<<0)
+#define AVCT_L2C_CFG_CFM_DONE   (1<<1)
+
+/* callback function declarations */
+void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, uint16_t lcid, uint16_t psm, uint8_t id);
+void avct_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result);
+void avct_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg);
+void avct_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg);
+void avct_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed);
+void avct_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result);
+void avct_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested);
+void avct_l2c_data_ind_cback(uint16_t lcid, BT_HDR *p_buf);
+
+/* L2CAP callback function structure */
+const tL2CAP_APPL_INFO avct_l2c_appl = {
+    avct_l2c_connect_ind_cback,
+    avct_l2c_connect_cfm_cback,
+    NULL,
+    avct_l2c_config_ind_cback,
+    avct_l2c_config_cfm_cback,
+    avct_l2c_disconnect_ind_cback,
+    avct_l2c_disconnect_cfm_cback,
+    NULL,
+    avct_l2c_data_ind_cback,
+    avct_l2c_congestion_ind_cback,
+    NULL                                /* tL2CA_TX_COMPLETE_CB */
+};
+
+/*******************************************************************************
+**
+** Function         avct_l2c_is_passive
+**
+** Description      check is the CCB associated with the given LCB was created
+**                  as passive
+**
+** Returns          true, if the given LCB is created as AVCT_PASSIVE
+**
+*******************************************************************************/
+static bool avct_l2c_is_passive (tAVCT_LCB *p_lcb)
+{
+    bool        is_passive = false;
+    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
+    int         i;
+
+    for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+    {
+        if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb))
+        {
+            AVCT_TRACE_DEBUG("avct_l2c_is_ct control:x%x", p_ccb->cc.control);
+            if (p_ccb->cc.control & AVCT_PASSIVE)
+            {
+                is_passive = true;
+                break;
+            }
+        }
+    }
+    return is_passive;
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_connect_ind_cback
+**
+** Description      This is the L2CAP connect indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, uint16_t lcid,
+                                UNUSED_ATTR uint16_t psm, uint8_t id)
+{
+    tAVCT_LCB       *p_lcb;
+    uint16_t        result = L2CAP_CONN_OK;
+    tL2CAP_CFG_INFO cfg;
+
+    /* do we already have a channel for this peer? */
+    if ((p_lcb = avct_lcb_by_bd(bd_addr)) == NULL)
+    {
+        /* no, allocate lcb */
+        if ((p_lcb = avct_lcb_alloc(bd_addr)) == NULL)
+        {
+            /* no ccb available, reject L2CAP connection */
+            result = L2CAP_CONN_NO_RESOURCES;
+        }
+    }
+    /* else we already have a channel for this peer */
+    else
+    {
+        if (!avct_l2c_is_passive (p_lcb) || (p_lcb->ch_state == AVCT_CH_OPEN))
+        {
+            /* this LCB included CT role - reject */
+            result = L2CAP_CONN_NO_RESOURCES;
+        }
+        else
+        {
+            /* TG role only - accept the connection from CT. move the channel ID to the conflict list */
+            p_lcb->conflict_lcid = p_lcb->ch_lcid;
+            AVCT_TRACE_DEBUG("avct_l2c_connect_ind_cback conflict_lcid:0x%x", p_lcb->conflict_lcid);
+        }
+    }
+
+    if(p_lcb)
+    {
+        AVCT_TRACE_DEBUG("avct_l2c_connect_ind_cback: 0x%x, res: %d, ch_state: %d",
+            lcid, result, p_lcb->ch_state);
+    }
+    /* Send L2CAP connect rsp */
+    L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
+
+    /* if result ok, proceed with connection */
+    if (result == L2CAP_CONN_OK)
+    {
+        /* store LCID */
+        p_lcb->ch_lcid = lcid;
+
+        /* transition to configuration state */
+        p_lcb->ch_state = AVCT_CH_CFG;
+
+        /* Send L2CAP config req */
+        memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+        cfg.mtu_present = true;
+        cfg.mtu = avct_cb.mtu;
+        L2CA_ConfigReq(lcid, &cfg);
+        AVCT_TRACE_DEBUG("avct_l2c snd Cfg Req");
+    }
+
+    if (p_lcb)
+      AVCT_TRACE_DEBUG("ch_state cni: %d ", p_lcb->ch_state);
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_connect_cfm_cback
+**
+** Description      This is the L2CAP connect confirm callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result)
+{
+    tAVCT_LCB       *p_lcb;
+    tL2CAP_CFG_INFO cfg;
+
+    /* look up lcb for this channel */
+    if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
+    {
+        AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback lcid:0x%x result: %d ch_state: %d, conflict_lcid:0x%x",
+            lcid, result, p_lcb->ch_state, p_lcb->conflict_lcid);
+        /* if in correct state */
+        if (p_lcb->ch_state == AVCT_CH_CONN)
+        {
+            /* if result successful */
+            if (result == L2CAP_CONN_OK)
+            {
+                /* set channel state */
+                p_lcb->ch_state = AVCT_CH_CFG;
+
+                /* Send L2CAP config req */
+                memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+                cfg.mtu_present = true;
+                cfg.mtu = avct_cb.mtu;
+                L2CA_ConfigReq(lcid, &cfg);
+                AVCT_TRACE_DEBUG("avct_l2c snd Cfg Req");
+            }
+            /* else failure */
+            else
+            {
+                AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback conflict_lcid:0x%x", p_lcb->conflict_lcid);
+                if (p_lcb->conflict_lcid == lcid)
+                    p_lcb->conflict_lcid = 0;
+                else
+                    avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
+            }
+        }
+        else if (p_lcb->conflict_lcid == lcid)
+        {
+            /* we must be in AVCT_CH_CFG state for the ch_lcid channel */
+            AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback ch_state: %d, conflict_lcid:0x%x", p_lcb->ch_state, p_lcb->conflict_lcid);
+            if (result == L2CAP_CONN_OK)
+            {
+                /* just in case the peer also accepts our connection - Send L2CAP disconnect req */
+                L2CA_DisconnectReq(lcid);
+            }
+            p_lcb->conflict_lcid = 0;
+        }
+        AVCT_TRACE_DEBUG("ch_state cnc: %d ", p_lcb->ch_state);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_config_cfm_cback
+**
+** Description      This is the L2CAP config confirm callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+    tAVCT_LCB       *p_lcb;
+
+    /* look up lcb for this channel */
+    if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
+    {
+        AVCT_TRACE_DEBUG("avct_l2c_config_cfm_cback: 0x%x, ch_state: %d, res: %d",
+            lcid, p_lcb->ch_state, p_cfg->result);
+        /* if in correct state */
+        if (p_lcb->ch_state == AVCT_CH_CFG)
+        {
+            /* if result successful */
+            if (p_cfg->result == L2CAP_CFG_OK)
+            {
+                /* update flags */
+                p_lcb->ch_flags |= AVCT_L2C_CFG_CFM_DONE;
+
+                /* if configuration complete */
+                if (p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE)
+                {
+                    p_lcb->ch_state = AVCT_CH_OPEN;
+                    avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
+                }
+            }
+            /* else failure */
+            else
+            {
+                AVCT_TRACE_DEBUG("ERROR avct_l2c_config_cfm_cback L2CA_DisconnectReq %d ", p_lcb->ch_state);
+                /* store result value */
+                p_lcb->ch_result = p_cfg->result;
+
+                /* Send L2CAP disconnect req */
+                L2CA_DisconnectReq(lcid);
+            }
+        }
+        AVCT_TRACE_DEBUG("ch_state cfc: %d ", p_lcb->ch_state);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_config_ind_cback
+**
+** Description      This is the L2CAP config indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+    tAVCT_LCB       *p_lcb;
+
+    /* look up lcb for this channel */
+    if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
+    {
+        AVCT_TRACE_DEBUG("avct_l2c_config_ind_cback: 0x%x, ch_state: %d", lcid, p_lcb->ch_state);
+        /* store the mtu in tbl */
+        if (p_cfg->mtu_present)
+        {
+            p_lcb->peer_mtu = p_cfg->mtu;
+        }
+        else
+        {
+            p_lcb->peer_mtu = L2CAP_DEFAULT_MTU;
+        }
+
+        /* send L2CAP configure response */
+        memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+        p_cfg->result = L2CAP_CFG_OK;
+        L2CA_ConfigRsp(lcid, p_cfg);
+
+        /* if first config ind */
+        if ((p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) == 0)
+        {
+            /* update flags */
+            p_lcb->ch_flags |= AVCT_L2C_CFG_IND_DONE;
+
+            /* if configuration complete */
+            if (p_lcb->ch_flags & AVCT_L2C_CFG_CFM_DONE)
+            {
+                p_lcb->ch_state = AVCT_CH_OPEN;
+                avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
+            }
+        }
+        AVCT_TRACE_DEBUG("ch_state cfi: %d ", p_lcb->ch_state);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_disconnect_ind_cback
+**
+** Description      This is the L2CAP disconnect indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed)
+{
+    tAVCT_LCB       *p_lcb;
+    uint16_t        result = AVCT_RESULT_FAIL;
+
+    /* look up lcb for this channel */
+    if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
+    {
+        AVCT_TRACE_DEBUG("avct_l2c_disconnect_ind_cback: 0x%x, ch_state: %d", lcid, p_lcb->ch_state);
+        if (ack_needed)
+        {
+            /* send L2CAP disconnect response */
+            L2CA_DisconnectRsp(lcid);
+        }
+
+        avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
+        AVCT_TRACE_DEBUG("ch_state di: %d ", p_lcb->ch_state);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_disconnect_cfm_cback
+**
+** Description      This is the L2CAP disconnect confirm callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result)
+{
+    tAVCT_LCB       *p_lcb;
+    uint16_t        res;
+
+    /* look up lcb for this channel */
+    if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
+    {
+        AVCT_TRACE_DEBUG("avct_l2c_disconnect_cfm_cback: 0x%x, ch_state: %d, res: %d",
+            lcid, p_lcb->ch_state, result);
+        /* result value may be previously stored */
+        res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result;
+        p_lcb->ch_result = 0;
+
+        avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &res);
+        AVCT_TRACE_DEBUG("ch_state dc: %d ", p_lcb->ch_state);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_congestion_ind_cback
+**
+** Description      This is the L2CAP congestion indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested)
+{
+    tAVCT_LCB       *p_lcb;
+
+    AVCT_TRACE_DEBUG("avct_l2c_congestion_ind_cback: 0x%x", lcid);
+    /* look up lcb for this channel */
+    if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
+    {
+        avct_lcb_event(p_lcb, AVCT_LCB_LL_CONG_EVT, (tAVCT_LCB_EVT *) &is_congested);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_data_ind_cback
+**
+** Description      This is the L2CAP data indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_data_ind_cback(uint16_t lcid, BT_HDR *p_buf)
+{
+    tAVCT_LCB       *p_lcb;
+
+    AVCT_TRACE_DEBUG("avct_l2c_data_ind_cback: 0x%x", lcid);
+    /* look up lcb for this channel */
+    if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
+    {
+        avct_lcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, (tAVCT_LCB_EVT *) &p_buf);
+    }
+    else /* prevent buffer leak */
+    {
+        AVCT_TRACE_WARNING("ERROR -> avct_l2c_data_ind_cback drop buffer");
+        osi_free(p_buf);
+    }
+}
+
diff --git a/bt/stack/avct/avct_l2c_br.cc b/bt/stack/avct/avct_l2c_br.cc
new file mode 100644
index 0000000..adc1c50
--- /dev/null
+++ b/bt/stack/avct/avct_l2c_br.cc
@@ -0,0 +1,442 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2008-2016 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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+**
+**  Name:           avct_l2c_br.cc
+**
+**  Description:    This AVCTP module interfaces to L2CAP
+**
+******************************************************************************/
+
+#include <string.h>
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avct_api.h"
+#include "avct_int.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "osi/include/osi.h"
+
+/* Configuration flags. */
+#define AVCT_L2C_CFG_IND_DONE   (1<<0)
+#define AVCT_L2C_CFG_CFM_DONE   (1<<1)
+
+/* AVCTP Browsing channel FCR Option:
+ * Size of the transmission window when using enhanced retransmission mode. Not used
+ * in basic and streaming modes. Range: 1 - 63
+ */
+#define AVCT_BR_FCR_OPT_TX_WINDOW_SIZE      10
+
+/* AVCTP Browsing channel FCR Option:
+ * Number of transmission attempts for a single I-Frame before taking
+ * Down the connection. Used In ERTM mode only. Value is Ignored in basic and
+ * Streaming modes.
+ * Range: 0, 1-0xFF
+ *     0 - infinite retransmissions
+ *     1 - single transmission
+ */
+#define AVCT_BR_FCR_OPT_MAX_TX_B4_DISCNT    20
+
+/* AVCTP Browsing channel FCR Option: Retransmission Timeout
+ * The AVRCP specification set a value in the range of 300 - 2000 ms
+ * Timeout (in msecs) to detect Lost I-Frames. Only used in Enhanced retransmission mode.
+ * Range: Minimum 2000 (2 secs) when supporting PBF.
+ */
+#define AVCT_BR_FCR_OPT_RETX_TOUT           2000
+
+/* AVCTP Browsing channel FCR Option: Monitor Timeout
+ * The AVRCP specification set a value in the range of 300 - 2000 ms
+ * Timeout (in msecs) to detect Lost S-Frames. Only used in Enhanced retransmission mode.
+ * Range: Minimum 12000 (12 secs) when supporting PBF.
+ */
+#define AVCT_BR_FCR_OPT_MONITOR_TOUT        12000
+
+/* callback function declarations */
+void avct_l2c_br_connect_ind_cback(BD_ADDR bd_addr, uint16_t lcid, uint16_t psm, uint8_t id);
+void avct_l2c_br_connect_cfm_cback(uint16_t lcid, uint16_t result);
+void avct_l2c_br_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg);
+void avct_l2c_br_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg);
+void avct_l2c_br_disconnect_ind_cback(uint16_t lcid, bool ack_needed);
+void avct_l2c_br_disconnect_cfm_cback(uint16_t lcid, uint16_t result);
+void avct_l2c_br_congestion_ind_cback(uint16_t lcid, bool is_congested);
+void avct_l2c_br_data_ind_cback(uint16_t lcid, BT_HDR *p_buf);
+
+/* L2CAP callback function structure */
+const tL2CAP_APPL_INFO avct_l2c_br_appl = {
+    avct_l2c_br_connect_ind_cback,
+    avct_l2c_br_connect_cfm_cback,
+    NULL,
+    avct_l2c_br_config_ind_cback,
+    avct_l2c_br_config_cfm_cback,
+    avct_l2c_br_disconnect_ind_cback,
+    avct_l2c_br_disconnect_cfm_cback,
+    NULL,
+    avct_l2c_br_data_ind_cback,
+    avct_l2c_br_congestion_ind_cback,
+    NULL                                /* tL2CA_TX_COMPLETE_CB */
+};
+
+/* Browsing channel eL2CAP default options */
+const tL2CAP_FCR_OPTS avct_l2c_br_fcr_opts_def = {
+    L2CAP_FCR_ERTM_MODE,                /* Mandatory for Browsing channel */
+    AVCT_BR_FCR_OPT_TX_WINDOW_SIZE,     /* Tx window size */
+    AVCT_BR_FCR_OPT_MAX_TX_B4_DISCNT,   /* Maximum transmissions before disconnecting */
+    AVCT_BR_FCR_OPT_RETX_TOUT,          /* Retransmission timeout (2 secs) */
+    AVCT_BR_FCR_OPT_MONITOR_TOUT,       /* Monitor timeout (12 secs) */
+    L2CAP_DEFAULT_ERM_MPS               /* MPS segment size */
+};
+
+/*******************************************************************************
+**
+** Function         avct_l2c_br_connect_ind_cback
+**
+** Description      This is the L2CAP connect indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_br_connect_ind_cback(BD_ADDR bd_addr, uint16_t lcid,
+                                   UNUSED_ATTR uint16_t psm, uint8_t id)
+{
+    tAVCT_LCB           *p_lcb;
+    uint16_t              result = L2CAP_CONN_NO_RESOURCES;
+    tL2CAP_CFG_INFO     cfg;
+    tAVCT_BCB           *p_bcb;
+    tL2CAP_ERTM_INFO    ertm_info;
+
+    memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+    cfg.mtu_present = true;
+
+    if ((p_lcb = avct_lcb_by_bd(bd_addr)) != NULL)
+    {
+        /* control channel exists */
+        p_bcb = avct_bcb_by_lcb(p_lcb);
+        memcpy(p_bcb->peer_addr, bd_addr, BD_ADDR_LEN);
+
+        if (p_bcb->allocated == 0)
+        {
+            /* browsing channel does not exist yet and the browsing channel is registered
+             * - accept connection */
+            p_bcb->allocated = p_lcb->allocated; /* copy the index from lcb */
+
+            result = L2CAP_CONN_OK;
+            cfg.mtu = avct_cb.mtu_br;
+
+            cfg.fcr_present = true;
+            cfg.fcr         = avct_l2c_br_fcr_opts_def;
+        }
+    }
+    /* else no control channel yet, reject */
+
+    /* Set the FCR options: Browsing channel mandates ERTM */
+    ertm_info.preferred_mode = cfg.fcr.mode;
+    ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
+    ertm_info.user_rx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+    ertm_info.user_tx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+    ertm_info.fcr_rx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+    ertm_info.fcr_tx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+
+    /* Send L2CAP connect rsp */
+    L2CA_ErtmConnectRsp(bd_addr, id, lcid, result, 0, &ertm_info);
+
+    /* if result ok, proceed with connection */
+    if (result == L2CAP_CONN_OK)
+    {
+        /* store LCID */
+        p_bcb->ch_lcid = lcid;
+
+        /* transition to configuration state */
+        p_bcb->ch_state = AVCT_CH_CFG;
+
+        /* Send L2CAP config req */
+        L2CA_ConfigReq(lcid, &cfg);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_br_connect_cfm_cback
+**
+** Description      This is the L2CAP connect confirm callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_br_connect_cfm_cback(uint16_t lcid, uint16_t result)
+{
+    tAVCT_BCB       *p_lcb;
+    tL2CAP_CFG_INFO cfg;
+
+    /* look up lcb for this channel */
+    p_lcb = avct_bcb_by_lcid(lcid);
+    if ((p_lcb == NULL) || (p_lcb->ch_state != AVCT_CH_CONN))
+        return;
+
+    if (result != L2CAP_CONN_OK)
+    {
+        /* failure */
+        avct_bcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
+        return;
+    }
+
+    /* result is successful */
+    /* set channel state */
+    p_lcb->ch_state = AVCT_CH_CFG;
+
+    /* Send L2CAP config req */
+    memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+    cfg.mtu_present = true;
+    cfg.mtu = avct_cb.mtu_br;
+
+    cfg.fcr_present  = true;
+    cfg.fcr          = avct_l2c_br_fcr_opts_def;
+
+    L2CA_ConfigReq(lcid, &cfg);
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_br_config_cfm_cback
+**
+** Description      This is the L2CAP config confirm callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_br_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+    tAVCT_BCB   *p_lcb;
+
+    /* look up lcb for this channel */
+    p_lcb = avct_bcb_by_lcid(lcid);
+    if ((p_lcb == NULL) || (p_lcb->ch_state != AVCT_CH_CFG))
+        return;
+
+    /* if result successful */
+    if (p_cfg->result == L2CAP_CFG_OK)
+    {
+        /* update flags */
+        p_lcb->ch_flags |= AVCT_L2C_CFG_CFM_DONE;
+
+        /* if configuration complete */
+        if (p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE)
+        {
+            p_lcb->ch_state = AVCT_CH_OPEN;
+            avct_bcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
+        }
+    }
+    /* else failure */
+    else
+    {
+        /* store result value */
+        p_lcb->ch_result = p_cfg->result;
+
+        /* Send L2CAP disconnect req */
+        L2CA_DisconnectReq(lcid);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_br_config_ind_cback
+**
+** Description      This is the L2CAP config indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_br_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+    tAVCT_BCB   *p_lcb;
+    uint16_t      max_mtu = BT_DEFAULT_BUFFER_SIZE - L2CAP_MIN_OFFSET - BT_HDR_SIZE;
+
+    /* Don't include QoS nor flush timeout in the response since we
+       currently always accept these values.  Note: fcr_present is left
+       untouched since l2cap negotiates this internally
+    */
+    p_cfg->flush_to_present = false;
+    p_cfg->qos_present = false;
+
+    /* look up lcb for this channel */
+    p_lcb = avct_bcb_by_lcid(lcid);
+    if (p_lcb == NULL)
+        return;
+
+    /* store the mtu in tbl */
+    p_lcb->peer_mtu = L2CAP_DEFAULT_MTU;
+    if (p_cfg->mtu_present)
+    {
+        p_lcb->peer_mtu = p_cfg->mtu;
+    }
+
+    if (p_lcb->peer_mtu > max_mtu)
+    {
+        p_lcb->peer_mtu = p_cfg->mtu = max_mtu;
+
+        /* Must tell the peer what the adjusted value is */
+        p_cfg->mtu_present = true;
+    }
+    else    /* Don't include in the response */
+        p_cfg->mtu_present = false;
+
+    AVCT_TRACE_DEBUG ("%s peer_mtu:%d use:%d", __func__,
+            p_lcb->peer_mtu, max_mtu);
+
+    if (p_lcb->peer_mtu >= AVCT_MIN_BROWSE_MTU)
+        p_cfg->result = L2CAP_CFG_OK;
+    else
+    {
+        p_cfg->result       = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+        p_cfg->mtu_present  = true;
+        p_cfg->mtu          = AVCT_MIN_BROWSE_MTU;
+    }
+
+    /* send L2CAP configure response */
+    L2CA_ConfigRsp(lcid, p_cfg);
+
+    if (p_cfg->result != L2CAP_CFG_OK)
+    {
+        return;
+    }
+
+    /* if first config ind */
+    if ((p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) == 0)
+    {
+        /* update flags */
+        p_lcb->ch_flags |= AVCT_L2C_CFG_IND_DONE;
+
+        /* if configuration complete */
+        if (p_lcb->ch_flags & AVCT_L2C_CFG_CFM_DONE)
+        {
+            p_lcb->ch_state = AVCT_CH_OPEN;
+            avct_bcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_br_disconnect_ind_cback
+**
+** Description      This is the L2CAP disconnect indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_br_disconnect_ind_cback(uint16_t lcid, bool ack_needed)
+{
+    tAVCT_BCB   *p_lcb;
+    uint16_t      result = AVCT_RESULT_FAIL;
+
+    /* look up lcb for this channel */
+    p_lcb = avct_bcb_by_lcid(lcid);
+    if (p_lcb == NULL)
+        return;
+
+    if (ack_needed)
+    {
+        /* send L2CAP disconnect response */
+        L2CA_DisconnectRsp(lcid);
+    }
+
+    avct_bcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_br_disconnect_cfm_cback
+**
+** Description      This is the L2CAP disconnect confirm callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_br_disconnect_cfm_cback(uint16_t lcid, uint16_t result)
+{
+    tAVCT_BCB   *p_lcb;
+    uint16_t      res;
+
+    /* look up lcb for this channel */
+    p_lcb = avct_bcb_by_lcid(lcid);
+    if (p_lcb == NULL)
+        return;
+
+    /* result value may be previously stored */
+    res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result;
+    p_lcb->ch_result = 0;
+
+    avct_bcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &res);
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_br_congestion_ind_cback
+**
+** Description      This is the L2CAP congestion indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_br_congestion_ind_cback(uint16_t lcid, bool is_congested)
+{
+    tAVCT_BCB   *p_lcb;
+
+    /* look up lcb for this channel */
+    p_lcb = avct_bcb_by_lcid(lcid);
+    if (p_lcb == NULL)
+        return;
+
+    avct_bcb_event(p_lcb, AVCT_LCB_LL_CONG_EVT, (tAVCT_LCB_EVT *) &is_congested);
+}
+
+/*******************************************************************************
+**
+** Function         avct_l2c_br_data_ind_cback
+**
+** Description      This is the L2CAP data indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avct_l2c_br_data_ind_cback(uint16_t lcid, BT_HDR *p_buf)
+{
+    tAVCT_BCB   *p_lcb;
+    tAVCT_LCB_EVT   evt_data;
+
+    /* look up lcb for this channel */
+    p_lcb = avct_bcb_by_lcid(lcid);
+    if (p_lcb == NULL)
+    {
+        /* prevent buffer leak */
+        osi_free(p_buf);
+        return;
+    }
+
+    evt_data.p_buf = p_buf;
+    avct_bcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, &evt_data);
+}
diff --git a/bt/stack/avct/avct_lcb.cc b/bt/stack/avct/avct_lcb.cc
new file mode 100644
index 0000000..636da97
--- /dev/null
+++ b/bt/stack/avct/avct_lcb.cc
@@ -0,0 +1,462 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 module contains the link control state machine and functions which
+ *  operate on the link control block.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avct_api.h"
+#include "avct_int.h"
+#include "bt_common.h"
+#include "osi/include/osi.h"
+
+/*****************************************************************************
+** state machine constants and types
+*****************************************************************************/
+
+#if (BT_TRACE_VERBOSE == TRUE)
+
+/* verbose state strings for trace */
+const char * const avct_lcb_st_str[] = {
+    "LCB_IDLE_ST",
+    "LCB_OPENING_ST",
+    "LCB_OPEN_ST",
+    "LCB_CLOSING_ST"
+};
+
+/* verbose event strings for trace */
+const char * const avct_lcb_evt_str[] = {
+    "UL_BIND_EVT",
+    "UL_UNBIND_EVT",
+    "UL_MSG_EVT",
+    "INT_CLOSE_EVT",
+    "LL_OPEN_EVT",
+    "LL_CLOSE_EVT",
+    "LL_MSG_EVT",
+    "LL_CONG_EVT"
+};
+
+#endif
+
+/* lcb state machine states */
+enum {
+    AVCT_LCB_IDLE_ST,
+    AVCT_LCB_OPENING_ST,
+    AVCT_LCB_OPEN_ST,
+    AVCT_LCB_CLOSING_ST
+};
+
+/* state machine action enumeration list */
+enum {
+    AVCT_LCB_CHNL_OPEN,
+    AVCT_LCB_CHNL_DISC,
+    AVCT_LCB_SEND_MSG,
+    AVCT_LCB_OPEN_IND,
+    AVCT_LCB_OPEN_FAIL,
+    AVCT_LCB_CLOSE_IND,
+    AVCT_LCB_CLOSE_CFM,
+    AVCT_LCB_MSG_IND,
+    AVCT_LCB_CONG_IND,
+    AVCT_LCB_BIND_CONN,
+    AVCT_LCB_BIND_FAIL,
+    AVCT_LCB_UNBIND_DISC,
+    AVCT_LCB_CHK_DISC,
+    AVCT_LCB_DISCARD_MSG,
+    AVCT_LCB_DEALLOC,
+    AVCT_LCB_FREE_MSG_IND,
+    AVCT_LCB_NUM_ACTIONS
+};
+
+#define AVCT_LCB_IGNORE     AVCT_LCB_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tAVCT_LCB_ACTION)(tAVCT_LCB *p_ccb, tAVCT_LCB_EVT *p_data);
+
+/* action function list */
+const tAVCT_LCB_ACTION avct_lcb_action[] = {
+    avct_lcb_chnl_open,
+    avct_lcb_chnl_disc,
+    avct_lcb_send_msg,
+    avct_lcb_open_ind,
+    avct_lcb_open_fail,
+    avct_lcb_close_ind,
+    avct_lcb_close_cfm,
+    avct_lcb_msg_ind,
+    avct_lcb_cong_ind,
+    avct_lcb_bind_conn,
+    avct_lcb_bind_fail,
+    avct_lcb_unbind_disc,
+    avct_lcb_chk_disc,
+    avct_lcb_discard_msg,
+    avct_lcb_dealloc,
+    avct_lcb_free_msg_ind
+};
+
+/* state table information */
+#define AVCT_LCB_ACTIONS            2       /* number of actions */
+#define AVCT_LCB_NEXT_STATE         2       /* position of next state */
+#define AVCT_LCB_NUM_COLS           3       /* number of columns in state tables */
+
+/* state table for idle state */
+const uint8_t avct_lcb_st_idle[][AVCT_LCB_NUM_COLS] = {
+/* Event                Action 1                    Action 2                    Next state */
+/* UL_BIND_EVT */       {AVCT_LCB_CHNL_OPEN,        AVCT_LCB_IGNORE,            AVCT_LCB_OPENING_ST},
+/* UL_UNBIND_EVT */     {AVCT_LCB_UNBIND_DISC,      AVCT_LCB_IGNORE,            AVCT_LCB_IDLE_ST},
+/* UL_MSG_EVT */        {AVCT_LCB_DISCARD_MSG,      AVCT_LCB_IGNORE,            AVCT_LCB_IDLE_ST},
+/* INT_CLOSE_EVT */     {AVCT_LCB_IGNORE,           AVCT_LCB_IGNORE,            AVCT_LCB_IDLE_ST},
+/* LL_OPEN_EVT */       {AVCT_LCB_OPEN_IND,         AVCT_LCB_IGNORE,            AVCT_LCB_OPEN_ST},
+/* LL_CLOSE_EVT */      {AVCT_LCB_CLOSE_IND,        AVCT_LCB_DEALLOC,           AVCT_LCB_IDLE_ST},
+/* LL_MSG_EVT */        {AVCT_LCB_FREE_MSG_IND,     AVCT_LCB_IGNORE,            AVCT_LCB_IDLE_ST},
+/* LL_CONG_EVT */       {AVCT_LCB_IGNORE,           AVCT_LCB_IGNORE,            AVCT_LCB_IDLE_ST}
+};
+
+/* state table for opening state */
+const uint8_t avct_lcb_st_opening[][AVCT_LCB_NUM_COLS] = {
+/* Event                Action 1                    Action 2                    Next state */
+/* UL_BIND_EVT */       {AVCT_LCB_IGNORE,           AVCT_LCB_IGNORE,            AVCT_LCB_OPENING_ST},
+/* UL_UNBIND_EVT */     {AVCT_LCB_UNBIND_DISC,      AVCT_LCB_IGNORE,            AVCT_LCB_OPENING_ST},
+/* UL_MSG_EVT */        {AVCT_LCB_DISCARD_MSG,      AVCT_LCB_IGNORE,            AVCT_LCB_OPENING_ST},
+/* INT_CLOSE_EVT */     {AVCT_LCB_CHNL_DISC,        AVCT_LCB_IGNORE,            AVCT_LCB_CLOSING_ST},
+/* LL_OPEN_EVT */       {AVCT_LCB_OPEN_IND,         AVCT_LCB_IGNORE,            AVCT_LCB_OPEN_ST},
+/* LL_CLOSE_EVT */      {AVCT_LCB_OPEN_FAIL,        AVCT_LCB_DEALLOC,           AVCT_LCB_IDLE_ST},
+/* LL_MSG_EVT */        {AVCT_LCB_FREE_MSG_IND,     AVCT_LCB_IGNORE,            AVCT_LCB_OPENING_ST},
+/* LL_CONG_EVT */       {AVCT_LCB_CONG_IND,         AVCT_LCB_IGNORE,            AVCT_LCB_OPENING_ST}
+};
+
+/* state table for open state */
+const uint8_t avct_lcb_st_open[][AVCT_LCB_NUM_COLS] = {
+/* Event                Action 1                    Action 2                    Next state */
+/* UL_BIND_EVT */       {AVCT_LCB_BIND_CONN,        AVCT_LCB_IGNORE,            AVCT_LCB_OPEN_ST},
+/* UL_UNBIND_EVT */     {AVCT_LCB_CHK_DISC,         AVCT_LCB_IGNORE,            AVCT_LCB_OPEN_ST},
+/* UL_MSG_EVT */        {AVCT_LCB_SEND_MSG,         AVCT_LCB_IGNORE,            AVCT_LCB_OPEN_ST},
+/* INT_CLOSE_EVT */     {AVCT_LCB_CHNL_DISC,        AVCT_LCB_IGNORE,            AVCT_LCB_CLOSING_ST},
+/* LL_OPEN_EVT */       {AVCT_LCB_IGNORE,           AVCT_LCB_IGNORE,            AVCT_LCB_OPEN_ST},
+/* LL_CLOSE_EVT */      {AVCT_LCB_CLOSE_IND,        AVCT_LCB_DEALLOC,           AVCT_LCB_IDLE_ST},
+/* LL_MSG_EVT */        {AVCT_LCB_MSG_IND,          AVCT_LCB_IGNORE,            AVCT_LCB_OPEN_ST},
+/* LL_CONG_EVT */       {AVCT_LCB_CONG_IND,         AVCT_LCB_IGNORE,            AVCT_LCB_OPEN_ST}
+};
+
+/* state table for closing state */
+const uint8_t avct_lcb_st_closing[][AVCT_LCB_NUM_COLS] = {
+/* Event                Action 1                    Action 2                    Next state */
+/* UL_BIND_EVT */       {AVCT_LCB_BIND_FAIL,        AVCT_LCB_IGNORE,            AVCT_LCB_CLOSING_ST},
+/* UL_UNBIND_EVT */     {AVCT_LCB_IGNORE,           AVCT_LCB_IGNORE,            AVCT_LCB_CLOSING_ST},
+/* UL_MSG_EVT */        {AVCT_LCB_DISCARD_MSG,      AVCT_LCB_IGNORE,            AVCT_LCB_CLOSING_ST},
+/* INT_CLOSE_EVT */     {AVCT_LCB_IGNORE,           AVCT_LCB_IGNORE,            AVCT_LCB_CLOSING_ST},
+/* LL_OPEN_EVT */       {AVCT_LCB_IGNORE,           AVCT_LCB_IGNORE,            AVCT_LCB_CLOSING_ST},
+/* LL_CLOSE_EVT */      {AVCT_LCB_CLOSE_CFM,        AVCT_LCB_DEALLOC,           AVCT_LCB_IDLE_ST},
+/* LL_MSG_EVT */        {AVCT_LCB_FREE_MSG_IND,     AVCT_LCB_IGNORE,            AVCT_LCB_CLOSING_ST},
+/* LL_CONG_EVT */       {AVCT_LCB_IGNORE,           AVCT_LCB_IGNORE,            AVCT_LCB_CLOSING_ST}
+};
+
+/* type for state table */
+typedef const uint8_t (*tAVCT_LCB_ST_TBL)[AVCT_LCB_NUM_COLS];
+
+/* state table */
+const tAVCT_LCB_ST_TBL avct_lcb_st_tbl[] = {
+    avct_lcb_st_idle,
+    avct_lcb_st_opening,
+    avct_lcb_st_open,
+    avct_lcb_st_closing
+};
+
+/*******************************************************************************
+**
+** Function         avct_lcb_event
+**
+** Description      State machine event handling function for lcb
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_lcb_event(tAVCT_LCB *p_lcb, uint8_t event, tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_LCB_ST_TBL    state_table;
+    uint8_t             action;
+    int                 i;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+    AVCT_TRACE_EVENT("LCB lcb=%d event=%s state=%s", p_lcb->allocated, avct_lcb_evt_str[event], avct_lcb_st_str[p_lcb->state]);
+#else
+    AVCT_TRACE_EVENT("LCB lcb=%d event=%d state=%d", p_lcb->allocated, event, p_lcb->state);
+#endif
+
+    /* look up the state table for the current state */
+    state_table = avct_lcb_st_tbl[p_lcb->state];
+
+    /* set next state */
+    p_lcb->state = state_table[event][AVCT_LCB_NEXT_STATE];
+
+    /* execute action functions */
+    for (i = 0; i < AVCT_LCB_ACTIONS; i++)
+    {
+        if ((action = state_table[event][i]) != AVCT_LCB_IGNORE)
+        {
+            (*avct_lcb_action[action])(p_lcb, p_data);
+        }
+        else
+        {
+            break;
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_bcb_event
+**
+** Description      State machine event handling function for lcb
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_bcb_event(tAVCT_BCB *p_bcb, uint8_t event, tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_LCB_ST_TBL    state_table;
+    uint8_t             action;
+    int                 i;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+    AVCT_TRACE_EVENT("BCB lcb=%d event=%s state=%s", p_bcb->allocated, avct_lcb_evt_str[event], avct_lcb_st_str[p_bcb->state]);
+#else
+    AVCT_TRACE_EVENT("BCB lcb=%d event=%d state=%d", p_bcb->allocated, event, p_bcb->state);
+#endif
+
+    /* look up the state table for the current state */
+    state_table = avct_lcb_st_tbl[p_bcb->state];
+
+    /* set next state */
+    p_bcb->state = state_table[event][AVCT_LCB_NEXT_STATE];
+
+    /* execute action functions */
+    for (i = 0; i < AVCT_LCB_ACTIONS; i++)
+    {
+        if ((action = state_table[event][i]) != AVCT_LCB_IGNORE)
+        {
+            (*avct_bcb_action[action])(p_bcb, p_data);
+        }
+        else
+        {
+            break;
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_lcb_by_bd
+**
+** Description      This lookup function finds the lcb for a BD address.
+**
+**
+** Returns          pointer to the lcb, or NULL if none found.
+**
+*******************************************************************************/
+tAVCT_LCB *avct_lcb_by_bd(BD_ADDR bd_addr)
+{
+    tAVCT_LCB   *p_lcb = &avct_cb.lcb[0];
+    int         i;
+
+    for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++)
+    {
+        /* if allocated lcb has matching lcb */
+        if (p_lcb->allocated && (!memcmp(p_lcb->peer_addr, bd_addr, BD_ADDR_LEN)))
+        {
+            break;
+        }
+    }
+
+    if (i == AVCT_NUM_LINKS)
+    {
+        /* if no lcb found */
+        p_lcb = NULL;
+
+        AVCT_TRACE_DEBUG("No lcb for addr %02x-%02x-%02x-%02x-%02x-%02x",
+                          bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+    }
+    return p_lcb;
+}
+
+/*******************************************************************************
+**
+** Function         avct_lcb_alloc
+**
+** Description      Allocate a link control block.
+**
+**
+** Returns          pointer to the lcb, or NULL if none could be allocated.
+**
+*******************************************************************************/
+tAVCT_LCB *avct_lcb_alloc(BD_ADDR bd_addr)
+{
+    tAVCT_LCB   *p_lcb = &avct_cb.lcb[0];
+    int         i;
+
+    for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++)
+    {
+        if (!p_lcb->allocated)
+        {
+            p_lcb->allocated = (uint8_t)(i + 1);
+            memcpy(p_lcb->peer_addr, bd_addr, BD_ADDR_LEN);
+            AVCT_TRACE_DEBUG("avct_lcb_alloc %d", p_lcb->allocated);
+            p_lcb->tx_q = fixed_queue_new(SIZE_MAX);
+            break;
+        }
+    }
+
+    if (i == AVCT_NUM_LINKS)
+    {
+        /* out of lcbs */
+        p_lcb = NULL;
+        AVCT_TRACE_WARNING("Out of lcbs");
+    }
+    return p_lcb;
+}
+
+/*******************************************************************************
+**
+** Function         avct_lcb_dealloc
+**
+** Description      Deallocate a link control block.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avct_lcb_dealloc(tAVCT_LCB *p_lcb,
+                      UNUSED_ATTR tAVCT_LCB_EVT *p_data)
+{
+    AVCT_TRACE_DEBUG("%s allocated: %d", __func__, p_lcb->allocated);
+
+    // Check if the LCB is still referenced
+
+    tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
+    for (size_t i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+    {
+        if (p_ccb->allocated && p_ccb->p_lcb == p_lcb)
+        {
+            AVCT_TRACE_DEBUG("%s LCB in use; lcb index: %d", __func__, i);
+            return;
+        }
+    }
+
+    // If not, de-allocate now...
+
+    AVCT_TRACE_DEBUG("%s Freeing LCB", __func__);
+    osi_free(p_lcb->p_rx_msg);
+    fixed_queue_free(p_lcb->tx_q, NULL);
+    memset(p_lcb, 0, sizeof(tAVCT_LCB));
+}
+
+/*******************************************************************************
+**
+** Function         avct_lcb_by_lcid
+**
+** Description      Find the LCB associated with the L2CAP LCID
+**
+**
+** Returns          pointer to the lcb, or NULL if none found.
+**
+*******************************************************************************/
+tAVCT_LCB *avct_lcb_by_lcid(uint16_t lcid)
+{
+    tAVCT_LCB   *p_lcb = &avct_cb.lcb[0];
+    int         i;
+
+    for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++)
+    {
+        if (p_lcb->allocated && ((p_lcb->ch_lcid == lcid) || (p_lcb->conflict_lcid == lcid)))
+        {
+            break;
+        }
+    }
+
+    if (i == AVCT_NUM_LINKS)
+    {
+        /* out of lcbs */
+        p_lcb = NULL;
+        AVCT_TRACE_WARNING("No lcb for lcid %x", lcid);
+    }
+
+    return p_lcb;
+}
+
+/*******************************************************************************
+**
+** Function         avct_lcb_has_pid
+**
+** Description      See if any ccbs on this lcb have a particular pid.
+**
+**
+** Returns          Pointer to CCB if PID found, NULL otherwise.
+**
+*******************************************************************************/
+tAVCT_CCB *avct_lcb_has_pid(tAVCT_LCB *p_lcb, uint16_t pid)
+{
+    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
+    int         i;
+
+    for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+    {
+        if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb->cc.pid == pid))
+        {
+            return p_ccb;
+        }
+    }
+    return NULL;
+}
+
+/*******************************************************************************
+**
+** Function         avct_lcb_last_ccb
+**
+** Description      See if given ccb is only one on the lcb.
+**
+**
+** Returns          true if ccb is last, false otherwise.
+**
+*******************************************************************************/
+bool    avct_lcb_last_ccb(tAVCT_LCB *p_lcb, tAVCT_CCB *p_ccb_last)
+{
+    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
+    int         i;
+
+    AVCT_TRACE_WARNING("avct_lcb_last_ccb");
+    for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+    {
+        AVCT_TRACE_WARNING("%x: aloc:%d, lcb:0x%x/0x%x, ccb:0x%x/0x%x",
+            i, p_ccb->allocated, p_ccb->p_lcb, p_lcb, p_ccb, p_ccb_last);
+        if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb != p_ccb_last))
+        {
+            return false;
+        }
+    }
+    return true;
+}
+
+
+
diff --git a/bt/stack/avct/avct_lcb_act.cc b/bt/stack/avct/avct_lcb_act.cc
new file mode 100644
index 0000000..9fcc323
--- /dev/null
+++ b/bt/stack/avct/avct_lcb_act.cc
@@ -0,0 +1,711 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 module contains action functions of the link control state machine.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avct_api.h"
+#include "avct_int.h"
+#include "bt_common.h"
+#include "btm_api.h"
+#include "osi/include/osi.h"
+
+/* packet header length lookup table */
+const uint8_t avct_lcb_pkt_type_len[] = {
+    AVCT_HDR_LEN_SINGLE,
+    AVCT_HDR_LEN_START,
+    AVCT_HDR_LEN_CONT,
+    AVCT_HDR_LEN_END
+};
+
+/*******************************************************************************
+**
+** Function         avct_lcb_msg_asmbl
+**
+** Description      Reassemble incoming message.
+**
+**
+** Returns          Pointer to reassembled message;  NULL if no message
+**                  available.
+**
+*******************************************************************************/
+static BT_HDR *avct_lcb_msg_asmbl(tAVCT_LCB *p_lcb, BT_HDR *p_buf)
+{
+    uint8_t *p;
+    uint8_t pkt_type;
+    BT_HDR  *p_ret;
+
+    /* parse the message header */
+    p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+    pkt_type = AVCT_PKT_TYPE(p);
+
+    /* quick sanity check on length */
+    if (p_buf->len < avct_lcb_pkt_type_len[pkt_type])
+    {
+        osi_free(p_buf);
+        AVCT_TRACE_WARNING("Bad length during reassembly");
+        p_ret = NULL;
+    }
+    /* single packet */
+    else if (pkt_type == AVCT_PKT_TYPE_SINGLE)
+    {
+        /* if reassembly in progress drop message and process new single */
+        if (p_lcb->p_rx_msg != NULL)
+            AVCT_TRACE_WARNING("Got single during reassembly");
+
+        osi_free_and_reset((void **)&p_lcb->p_rx_msg);
+
+        p_ret = p_buf;
+    }
+    /* start packet */
+    else if (pkt_type == AVCT_PKT_TYPE_START)
+    {
+        /* if reassembly in progress drop message and process new start */
+        if (p_lcb->p_rx_msg != NULL)
+            AVCT_TRACE_WARNING("Got start during reassembly");
+
+        osi_free(p_lcb->p_rx_msg);
+
+        /*
+         * Allocate bigger buffer for reassembly. As lower layers are
+         * not aware of possible packet size after reassembly, they
+         * would have allocated smaller buffer.
+         */
+        p_lcb->p_rx_msg = (BT_HDR *)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+        memcpy(p_lcb->p_rx_msg, p_buf,
+               sizeof(BT_HDR) + p_buf->offset + p_buf->len);
+
+        /* Free original buffer */
+        osi_free(p_buf);
+
+        /* update p to point to new buffer */
+        p = (uint8_t *)(p_lcb->p_rx_msg + 1) + p_lcb->p_rx_msg->offset;
+
+        /* copy first header byte over nosp */
+        *(p + 1) = *p;
+
+        /* set offset to point to where to copy next */
+        p_lcb->p_rx_msg->offset += p_lcb->p_rx_msg->len;
+
+        /* adjust length for packet header */
+        p_lcb->p_rx_msg->len -= 1;
+
+        p_ret = NULL;
+    }
+    /* continue or end */
+    else
+    {
+        /* if no reassembly in progress drop message */
+        if (p_lcb->p_rx_msg == NULL)
+        {
+            osi_free(p_buf);
+            AVCT_TRACE_WARNING("Pkt type=%d out of order", pkt_type);
+            p_ret = NULL;
+        }
+        else
+        {
+            /* get size of buffer holding assembled message */
+            /*
+             * NOTE: The buffer is allocated above at the beginning of the
+             * reassembly, and is always of size BT_DEFAULT_BUFFER_SIZE.
+             */
+            uint16_t buf_len = BT_DEFAULT_BUFFER_SIZE - sizeof(BT_HDR);
+
+            /* adjust offset and len of fragment for header byte */
+            p_buf->offset += AVCT_HDR_LEN_CONT;
+            p_buf->len -= AVCT_HDR_LEN_CONT;
+
+            /* verify length */
+            if ((p_lcb->p_rx_msg->offset + p_buf->len) > buf_len) {
+                /* won't fit; free everything */
+                AVCT_TRACE_WARNING("%s: Fragmented message too big!", __func__);
+                osi_free_and_reset((void **)&p_lcb->p_rx_msg);
+                osi_free(p_buf);
+                p_ret = NULL;
+            } else {
+                /* copy contents of p_buf to p_rx_msg */
+                memcpy((uint8_t *)(p_lcb->p_rx_msg + 1) + p_lcb->p_rx_msg->offset,
+                       (uint8_t *)(p_buf + 1) + p_buf->offset, p_buf->len);
+
+                if (pkt_type == AVCT_PKT_TYPE_END)
+                {
+                    p_lcb->p_rx_msg->offset -= p_lcb->p_rx_msg->len;
+                    p_lcb->p_rx_msg->len += p_buf->len;
+                    p_ret = p_lcb->p_rx_msg;
+                    p_lcb->p_rx_msg = NULL;
+                }
+                else
+                {
+                    p_lcb->p_rx_msg->offset += p_buf->len;
+                    p_lcb->p_rx_msg->len += p_buf->len;
+                    p_ret = NULL;
+                }
+                osi_free(p_buf);
+            }
+        }
+    }
+    return p_ret;
+}
+
+
+/*******************************************************************************
+**
+** Function         avct_lcb_chnl_open
+**
+** Description      Open L2CAP channel to peer
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_lcb_chnl_open(tAVCT_LCB *p_lcb,
+                        UNUSED_ATTR tAVCT_LCB_EVT *p_data)
+{
+    uint16_t result = AVCT_RESULT_FAIL;
+
+    BTM_SetOutService(p_lcb->peer_addr, BTM_SEC_SERVICE_AVCTP, 0);
+    /* call l2cap connect req */
+    p_lcb->ch_state = AVCT_CH_CONN;
+    p_lcb->ch_lcid = L2CA_ConnectReq(AVCT_PSM, p_lcb->peer_addr);
+    if (p_lcb->ch_lcid == 0)
+    {
+        /* if connect req failed, send ourselves close event */
+        avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_lcb_unbind_disc
+**
+** Description      Deallocate ccb and call callback with disconnect event.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_lcb_unbind_disc(UNUSED_ATTR tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+    avct_ccb_dealloc(p_data->p_ccb, AVCT_DISCONNECT_CFM_EVT, 0, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         avct_lcb_open_ind
+**
+** Description      Handle an LL_OPEN event.  For each allocated ccb already
+**                  bound to this lcb, send a connect event.  For each
+**                  unbound ccb with a new PID, bind that ccb to this lcb and
+**                  send a connect event.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_lcb_open_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
+    int         i;
+    bool        bind = false;
+
+    for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+    {
+        /* if ccb allocated and */
+        if (p_ccb->allocated)
+        {
+            /* if bound to this lcb send connect confirm event */
+            if (p_ccb->p_lcb == p_lcb)
+            {
+                bind = true;
+                L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH);
+                p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_CFM_EVT,
+                                       0, p_lcb->peer_addr);
+            }
+            /* if unbound acceptor and lcb doesn't already have a ccb for this PID */
+            else if ((p_ccb->p_lcb == NULL) && (p_ccb->cc.role == AVCT_ACP) &&
+                     (avct_lcb_has_pid(p_lcb, p_ccb->cc.pid) == NULL))
+            {
+                /* bind ccb to lcb and send connect ind event */
+                bind = true;
+                p_ccb->p_lcb = p_lcb;
+                L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH);
+                p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_IND_EVT,
+                                    0, p_lcb->peer_addr);
+            }
+        }
+    }
+
+    /* if no ccbs bound to this lcb, disconnect */
+    if (bind == false)
+    {
+        avct_lcb_event(p_lcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_lcb_open_fail
+**
+** Description      L2CAP channel open attempt failed.  Deallocate any ccbs
+**                  on this lcb and send connect confirm event with failure.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_lcb_open_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_CCB           *p_ccb = &avct_cb.ccb[0];
+    int                 i;
+
+    for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+    {
+        if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb))
+        {
+            avct_ccb_dealloc(p_ccb, AVCT_CONNECT_CFM_EVT,
+                             p_data->result, p_lcb->peer_addr);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_lcb_close_ind
+**
+** Description      L2CAP channel closed by peer.  Deallocate any initiator
+**                  ccbs on this lcb and send disconnect ind event.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_lcb_close_ind(tAVCT_LCB *p_lcb,
+                        UNUSED_ATTR tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_CCB           *p_ccb = &avct_cb.ccb[0];
+    int                 i;
+
+    for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+    {
+        if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb))
+        {
+            if (p_ccb->cc.role == AVCT_INT)
+            {
+                avct_ccb_dealloc(p_ccb, AVCT_DISCONNECT_IND_EVT,
+                                 0, p_lcb->peer_addr);
+            }
+            else
+            {
+                p_ccb->p_lcb = NULL;
+                (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), AVCT_DISCONNECT_IND_EVT,
+                                          0, p_lcb->peer_addr);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_lcb_close_cfm
+**
+** Description      L2CAP channel closed by us.  Deallocate any initiator
+**                  ccbs on this lcb and send disconnect ind or cfm event.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_lcb_close_cfm(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_CCB           *p_ccb = &avct_cb.ccb[0];
+    int                 i;
+    uint8_t             event;
+
+    for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+    {
+        if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb))
+        {
+            /* if this ccb initiated close send disconnect cfm otherwise ind */
+            if (p_ccb->ch_close)
+            {
+                p_ccb->ch_close = false;
+                event = AVCT_DISCONNECT_CFM_EVT;
+            }
+            else
+            {
+                event = AVCT_DISCONNECT_IND_EVT;
+            }
+
+            if (p_ccb->cc.role == AVCT_INT)
+            {
+                avct_ccb_dealloc(p_ccb, event, p_data->result, p_lcb->peer_addr);
+            }
+            else
+            {
+                p_ccb->p_lcb = NULL;
+                (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), event,
+                                       p_data->result, p_lcb->peer_addr);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_lcb_bind_conn
+**
+** Description      Bind ccb to lcb and send connect cfm event.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_lcb_bind_conn(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+    p_data->p_ccb->p_lcb = p_lcb;
+    (*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb),
+                                      AVCT_CONNECT_CFM_EVT, 0, p_lcb->peer_addr);
+}
+
+/*******************************************************************************
+**
+** Function         avct_lcb_chk_disc
+**
+** Description      A ccb wants to close; if it is the last ccb on this lcb,
+**                  close channel.  Otherwise just deallocate and call
+**                  callback.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_lcb_chk_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+    AVCT_TRACE_WARNING("%s", __func__);
+
+    avct_close_bcb(p_lcb, p_data);
+    if (avct_lcb_last_ccb(p_lcb, p_data->p_ccb))
+    {
+        AVCT_TRACE_WARNING("%s: closing", __func__);
+        p_data->p_ccb->ch_close = true;
+        avct_lcb_event(p_lcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
+    }
+    else
+    {
+        AVCT_TRACE_WARNING("%s: dealloc ccb", __func__);
+        avct_lcb_unbind_disc(p_lcb, p_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_lcb_chnl_disc
+**
+** Description      Disconnect L2CAP channel.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_lcb_chnl_disc(tAVCT_LCB *p_lcb,
+                        UNUSED_ATTR tAVCT_LCB_EVT *p_data)
+{
+    L2CA_DisconnectReq(p_lcb->ch_lcid);
+}
+
+/*******************************************************************************
+**
+** Function         avct_lcb_bind_fail
+**
+** Description      Deallocate ccb and call callback with connect event
+**                  with failure result.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_lcb_bind_fail(UNUSED_ATTR tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+    avct_ccb_dealloc(p_data->p_ccb, AVCT_CONNECT_CFM_EVT, AVCT_RESULT_FAIL, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         avct_lcb_cong_ind
+**
+** Description      Handle congestion indication from L2CAP.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_lcb_cong_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+    tAVCT_CCB           *p_ccb = &avct_cb.ccb[0];
+    int                 i;
+    uint8_t             event;
+    BT_HDR          *p_buf;
+
+    /* set event */
+    event = (p_data->cong) ? AVCT_CONG_IND_EVT : AVCT_UNCONG_IND_EVT;
+    p_lcb->cong = p_data->cong;
+    if (p_lcb->cong == false && !fixed_queue_is_empty(p_lcb->tx_q))
+    {
+        while (!p_lcb->cong &&
+               (p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_lcb->tx_q)) != NULL)
+        {
+            if (L2CA_DataWrite(p_lcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED)
+            {
+                p_lcb->cong = true;
+            }
+        }
+    }
+
+    /* send event to all ccbs on this lcb */
+    for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
+    {
+        if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb))
+        {
+            (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), event, 0, p_lcb->peer_addr);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avct_lcb_discard_msg
+**
+** Description      Discard a message sent in from the API.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_lcb_discard_msg(UNUSED_ATTR tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+    AVCT_TRACE_WARNING("%s Dropping message", __func__);
+    osi_free_and_reset((void **)&p_data->ul_msg.p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         avct_lcb_send_msg
+**
+** Description      Build and send an AVCTP message.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_lcb_send_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+    uint16_t        curr_msg_len;
+    uint8_t         pkt_type;
+    uint8_t         hdr_len;
+    uint8_t         *p;
+    uint8_t         nosp = 0;       /* number of subsequent packets */
+    uint16_t        temp;
+    uint16_t        buf_size = p_lcb->peer_mtu + L2CAP_MIN_OFFSET + BT_HDR_SIZE;
+
+
+    /* store msg len */
+    curr_msg_len = p_data->ul_msg.p_buf->len;
+
+    /* initialize packet type and other stuff */
+    if (curr_msg_len <= (p_lcb->peer_mtu - AVCT_HDR_LEN_SINGLE))
+    {
+        pkt_type = AVCT_PKT_TYPE_SINGLE;
+    }
+    else
+    {
+        pkt_type = AVCT_PKT_TYPE_START;
+        temp = (curr_msg_len + AVCT_HDR_LEN_START - p_lcb->peer_mtu);
+        nosp = temp / (p_lcb->peer_mtu - 1) + 1;
+        if ( (temp % (p_lcb->peer_mtu - 1)) != 0)
+            nosp++;
+    }
+
+    /* while we haven't sent all packets */
+    while (curr_msg_len != 0) {
+        BT_HDR *p_buf;
+
+        /* set header len */
+        hdr_len = avct_lcb_pkt_type_len[pkt_type];
+
+        /* if remaining msg must be fragmented */
+        if (p_data->ul_msg.p_buf->len > (p_lcb->peer_mtu - hdr_len))
+        {
+            /* get a new buffer for fragment we are sending */
+            p_buf = (BT_HDR *)osi_malloc(buf_size);
+
+            /* copy portion of data from current message to new buffer */
+            p_buf->offset = L2CAP_MIN_OFFSET + hdr_len;
+            p_buf->len = p_lcb->peer_mtu - hdr_len;
+
+            memcpy((uint8_t *)(p_buf + 1) + p_buf->offset,
+                   (uint8_t *)(p_data->ul_msg.p_buf + 1) + p_data->ul_msg.p_buf->offset, p_buf->len);
+
+            p_data->ul_msg.p_buf->offset += p_buf->len;
+            p_data->ul_msg.p_buf->len -= p_buf->len;
+        }
+        else
+        {
+            p_buf = p_data->ul_msg.p_buf;
+        }
+
+        curr_msg_len -= p_buf->len;
+
+        /* set up to build header */
+        p_buf->len += hdr_len;
+        p_buf->offset -= hdr_len;
+        p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+        /* build header */
+        AVCT_BUILD_HDR(p, p_data->ul_msg.label, pkt_type, p_data->ul_msg.cr);
+        if (pkt_type == AVCT_PKT_TYPE_START)
+        {
+            UINT8_TO_STREAM(p, nosp);
+        }
+        if ((pkt_type == AVCT_PKT_TYPE_START) || (pkt_type == AVCT_PKT_TYPE_SINGLE))
+        {
+            UINT16_TO_BE_STREAM(p, p_data->ul_msg.p_ccb->cc.pid);
+        }
+
+        if (p_lcb->cong == true)
+        {
+            fixed_queue_enqueue(p_lcb->tx_q, p_buf);
+        }
+
+        /* send message to L2CAP */
+        else
+        {
+            if (L2CA_DataWrite(p_lcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED)
+            {
+                p_lcb->cong = true;
+            }
+        }
+
+        /* update pkt type for next packet */
+        if (curr_msg_len > (p_lcb->peer_mtu - AVCT_HDR_LEN_END))
+        {
+            pkt_type = AVCT_PKT_TYPE_CONT;
+        }
+        else
+        {
+            pkt_type = AVCT_PKT_TYPE_END;
+        }
+    }
+    AVCT_TRACE_DEBUG ("%s tx_q_count:%d", __func__,
+                      fixed_queue_length(p_lcb->tx_q));
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         avct_lcb_free_msg_ind
+**
+** Description      Discard an incoming AVCTP message.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_lcb_free_msg_ind(UNUSED_ATTR tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+    if (p_data == NULL)
+        return;
+
+    osi_free_and_reset((void **)&p_data->p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         avct_lcb_msg_ind
+**
+** Description      Handle an incoming AVCTP message.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avct_lcb_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
+{
+    uint8_t     *p;
+    uint8_t     label, type, cr_ipid;
+    uint16_t    pid;
+    tAVCT_CCB   *p_ccb;
+
+    /* this p_buf is to be reported through p_msg_cback. The layer_specific
+     * needs to be set properly to indicate that it is received through
+     * control channel */
+    p_data->p_buf->layer_specific = AVCT_DATA_CTRL;
+
+    /* reassemble message; if no message available (we received a fragment) return */
+    if ((p_data->p_buf = avct_lcb_msg_asmbl(p_lcb, p_data->p_buf)) == NULL)
+    {
+        return;
+    }
+
+    p = (uint8_t *)(p_data->p_buf + 1) + p_data->p_buf->offset;
+
+    /* parse header byte */
+    AVCT_PARSE_HDR(p, label, type, cr_ipid);
+
+    /* check for invalid cr_ipid */
+    if (cr_ipid == AVCT_CR_IPID_INVALID)
+    {
+        AVCT_TRACE_WARNING("Invalid cr_ipid", cr_ipid);
+        osi_free_and_reset((void **)&p_data->p_buf);
+        return;
+    }
+
+    /* parse and lookup PID */
+    BE_STREAM_TO_UINT16(pid, p);
+    p_ccb = avct_lcb_has_pid(p_lcb, pid);
+    if (p_ccb)
+    {
+        /* PID found; send msg up, adjust bt hdr and call msg callback */
+        p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE;
+        p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE;
+        (*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid, p_data->p_buf);
+        return;
+    }
+
+    /* PID not found; drop message */
+    AVCT_TRACE_WARNING("No ccb for PID=%x", pid);
+    osi_free_and_reset((void **)&p_data->p_buf);
+
+    /* if command send reject */
+    if (cr_ipid == AVCT_CMD)
+    {
+        BT_HDR *p_buf = (BT_HDR *)osi_malloc(AVCT_CMD_BUF_SIZE);
+        p_buf->len = AVCT_HDR_LEN_SINGLE;
+        p_buf->offset = AVCT_MSG_OFFSET - AVCT_HDR_LEN_SINGLE;
+        p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+        AVCT_BUILD_HDR(p, label, AVCT_PKT_TYPE_SINGLE, AVCT_REJ);
+        UINT16_TO_BE_STREAM(p, pid);
+        L2CA_DataWrite(p_lcb->ch_lcid, p_buf);
+    }
+}
diff --git a/bt/stack/avdt/avdt_ad.cc b/bt/stack/avdt/avdt_ad.cc
new file mode 100644
index 0000000..00c838c
--- /dev/null
+++ b/bt/stack/avdt/avdt_ad.cc
@@ -0,0 +1,641 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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 module contains the AVDTP adaption layer.
+ *
+ ******************************************************************************/
+
+#include <assert.h>
+#include <string.h>
+
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "osi/include/osi.h"
+
+
+/*******************************************************************************
+**
+** Function         avdt_ad_type_to_tcid
+**
+** Description      Derives the TCID from the channel type and SCB.
+**
+**
+** Returns          TCID value.
+**
+*******************************************************************************/
+uint8_t avdt_ad_type_to_tcid(uint8_t type, tAVDT_SCB *p_scb)
+{
+    uint8_t scb_idx;
+
+    if (type == AVDT_CHAN_SIG)
+    {
+        return 0;
+    }
+    else
+    {
+        scb_idx = avdt_scb_to_hdl(p_scb) - 1;
+        /*
+        AVDT_TRACE_DEBUG("type: %d, tcid: %d", type, ((scb_idx * (AVDT_CHAN_NUM_TYPES - 1)) + type));
+        */
+        return ((scb_idx * (AVDT_CHAN_NUM_TYPES - 1)) + type);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ad_tcid_to_type
+**
+** Description      Derives the channel type from the TCID.
+**
+**
+** Returns          Channel type value.
+**
+*******************************************************************************/
+static uint8_t avdt_ad_tcid_to_type(uint8_t tcid)
+{
+    uint8_t type;
+
+    if (tcid == 0)
+    {
+        type = AVDT_CHAN_SIG;
+    }
+    else
+    {
+        /* tcid translates to type based on number of channels, as follows:
+        ** only media channel   :  tcid=1,2,3,4,5,6...  type=1,1,1,1,1,1...
+        ** media and report     :  tcid=1,2,3,4,5,6...  type=1,2,1,2,1,2...
+        ** media, report, recov :  tcid=1,2,3,4,5,6...  type=1,2,3,1,2,3...
+        */
+        type = ((tcid + AVDT_CHAN_NUM_TYPES - 2) % (AVDT_CHAN_NUM_TYPES - 1)) + 1;
+    }
+    AVDT_TRACE_DEBUG("tcid: %d, type: %d", tcid, type);
+    return type;
+}
+
+
+/*******************************************************************************
+**
+** Function         avdt_ad_init
+**
+** Description      Initialize adaption layer.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_ad_init(void)
+{
+    int             i;
+    tAVDT_TC_TBL    *p_tbl = avdt_cb.ad.tc_tbl;
+    memset(&avdt_cb.ad, 0, sizeof(tAVDT_AD));
+
+    /* make sure the peer_mtu is a valid value */
+    for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
+    {
+        p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         avdt_ad_tc_tbl_by_st
+**
+** Description      Find adaption layer transport channel table entry matching
+**                  the given state.
+**
+**
+** Returns          Pointer to matching entry.  For control channel it returns
+**                  the matching entry.  For media or other it returns the
+**                  first matching entry (there could be more than one).
+**
+*******************************************************************************/
+tAVDT_TC_TBL *avdt_ad_tc_tbl_by_st(uint8_t type, tAVDT_CCB *p_ccb, uint8_t state)
+{
+    int             i;
+    tAVDT_TC_TBL    *p_tbl = avdt_cb.ad.tc_tbl;
+    uint8_t         ccb_idx;
+
+    if (p_ccb == NULL)
+    {
+        /* resending security req */
+        for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
+        {
+            /* must be AVDT_CHAN_SIG - tcid always zero */
+            if ((p_tbl->tcid == 0) &&
+                (p_tbl->state == state))
+            {
+                break;
+            }
+        }
+    }
+    else
+    {
+        ccb_idx = avdt_ccb_to_idx(p_ccb);
+
+        for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
+        {
+            if (type == AVDT_CHAN_SIG)
+            {
+                /* if control channel, tcid always zero */
+                if ((p_tbl->tcid == 0) &&
+                    (p_tbl->ccb_idx == ccb_idx) &&
+                    (p_tbl->state == state))
+                {
+                    break;
+                }
+            }
+            else
+            {
+                /* if other channel, tcid is always > zero */
+                if ((p_tbl->tcid > 0) &&
+                    (p_tbl->ccb_idx == ccb_idx) &&
+                    (p_tbl->state == state))
+                {
+                    break;
+                }
+            }
+        }
+    }
+
+    /* if nothing found return null */
+    if (i == AVDT_NUM_TC_TBL)
+    {
+        p_tbl = NULL;
+    }
+
+    return p_tbl;
+}
+
+
+/*******************************************************************************
+**
+** Function         avdt_ad_tc_tbl_by_lcid
+**
+** Description      Find adaption layer transport channel table entry by LCID.
+**
+**
+** Returns          Pointer to entry.
+**
+*******************************************************************************/
+tAVDT_TC_TBL *avdt_ad_tc_tbl_by_lcid(uint16_t lcid)
+{
+    uint8_t idx;
+
+    idx = avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
+
+    if (idx < AVDT_NUM_TC_TBL)
+    {
+        return &avdt_cb.ad.tc_tbl[idx];
+    }
+    else
+    {
+        return NULL;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         avdt_ad_tc_tbl_by_type
+**
+** Description      This function retrieves the transport channel table entry
+**                  for a particular channel.
+**
+**
+** Returns          Pointer to transport channel table entry.
+**
+*******************************************************************************/
+tAVDT_TC_TBL *avdt_ad_tc_tbl_by_type(uint8_t type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb)
+{
+    uint8_t         tcid;
+    int             i;
+    tAVDT_TC_TBL    *p_tbl = avdt_cb.ad.tc_tbl;
+    uint8_t         ccb_idx = avdt_ccb_to_idx(p_ccb);
+
+    /* get tcid from type, scb */
+    tcid = avdt_ad_type_to_tcid(type, p_scb);
+
+    for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
+    {
+        if ((p_tbl->tcid == tcid) && (p_tbl->ccb_idx == ccb_idx))
+        {
+            break;
+        }
+    }
+
+    assert(i != AVDT_NUM_TC_TBL);
+
+    return p_tbl;
+}
+
+
+/*******************************************************************************
+**
+** Function         avdt_ad_tc_tbl_alloc
+**
+** Description      Allocate an entry in the traffic channel table.
+**
+**
+** Returns          Pointer to entry.
+**
+*******************************************************************************/
+tAVDT_TC_TBL *avdt_ad_tc_tbl_alloc(tAVDT_CCB *p_ccb)
+{
+    int             i;
+    tAVDT_TC_TBL    *p_tbl = avdt_cb.ad.tc_tbl;
+
+    /* find next free entry in tc table */
+    for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
+    {
+        if (p_tbl->state == AVDT_AD_ST_UNUSED)
+        {
+            break;
+        }
+    }
+
+    /* sanity check */
+    assert(i != AVDT_NUM_TC_TBL);
+
+
+    /* initialize entry */
+    p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+    p_tbl->cfg_flags = 0;
+    p_tbl->ccb_idx = avdt_ccb_to_idx(p_ccb);
+    p_tbl->state = AVDT_AD_ST_IDLE;
+    return p_tbl;
+
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ad_tc_tbl_to_idx
+**
+** Description      Convert a transport channel table entry to an index.
+**
+**
+** Returns          Index value.
+**
+*******************************************************************************/
+uint8_t avdt_ad_tc_tbl_to_idx(tAVDT_TC_TBL *p_tbl)
+{
+    AVDT_TRACE_DEBUG("avdt_ad_tc_tbl_to_idx: %d", (p_tbl - avdt_cb.ad.tc_tbl));
+    /* use array arithmetic to determine index */
+    return (uint8_t) (p_tbl - avdt_cb.ad.tc_tbl);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ad_tc_close_ind
+**
+** Description      This function is called by the L2CAP interface when the
+**                  L2CAP channel is closed.  It looks up the CCB or SCB for
+**                  the channel and sends it a close event.  The reason
+**                  parameter is the same value passed by the L2CAP
+**                  callback function.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_ad_tc_close_ind(tAVDT_TC_TBL *p_tbl,
+                          UNUSED_ATTR uint16_t reason)
+{
+    tAVDT_CCB   *p_ccb;
+    tAVDT_SCB   *p_scb;
+    tAVDT_SCB_TC_CLOSE  close;
+
+    close.old_tc_state = p_tbl->state;
+    /* clear avdt_ad_tc_tbl entry */
+    p_tbl->state = AVDT_AD_ST_UNUSED;
+    p_tbl->cfg_flags = 0;
+    p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+
+    AVDT_TRACE_DEBUG("avdt_ad_tc_close_ind tcid: %d, old: %d",
+        p_tbl->tcid, close.old_tc_state);
+    /* if signaling channel, notify ccb that channel open */
+    if (p_tbl->tcid == 0)
+    {
+        p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
+        avdt_ccb_event(p_ccb, AVDT_CCB_LL_CLOSE_EVT, NULL);
+    }
+    /* if media or other channel, notify scb that channel close */
+    else
+    {
+        /* look up scb in stream routing table by ccb, tcid */
+        p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
+        if (p_scb != NULL)
+        {
+            close.tcid = p_tbl->tcid;
+            close.type = avdt_ad_tcid_to_type(p_tbl->tcid);
+            avdt_scb_event(p_scb, AVDT_SCB_TC_CLOSE_EVT, (tAVDT_SCB_EVT *)&close);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ad_tc_open_ind
+**
+** Description      This function is called by the L2CAP interface when
+**                  the L2CAP channel is opened.  It looks up the CCB or SCB
+**                  for the channel and sends it an open event.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_ad_tc_open_ind(tAVDT_TC_TBL *p_tbl)
+{
+    tAVDT_CCB   *p_ccb;
+    tAVDT_SCB   *p_scb;
+    tAVDT_OPEN  open;
+    tAVDT_EVT_HDR evt;
+
+    p_tbl->state = AVDT_AD_ST_OPEN;
+
+    /* if signaling channel, notify ccb that channel open */
+    if (p_tbl->tcid == 0)
+    {
+        /* set the signal channel to use high priority within the ACL link */
+        L2CA_SetTxPriority(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][AVDT_CHAN_SIG].lcid, L2CAP_CHNL_PRIORITY_HIGH);
+
+        p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
+        /* use err_param to indicate the role of connection.
+         * AVDT_ACP, if ACP */
+        evt.err_param = AVDT_INT;
+        if(p_tbl->cfg_flags & AVDT_L2C_CFG_CONN_ACP)
+        {
+            evt.err_param = AVDT_ACP;
+        }
+        avdt_ccb_event(p_ccb, AVDT_CCB_LL_OPEN_EVT, (tAVDT_CCB_EVT *)&evt);
+    }
+    /* if media or other channel, notify scb that channel open */
+    else
+    {
+        /* look up scb in stream routing table by ccb, tcid */
+        p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
+
+        /* put lcid in event data */
+        if (p_scb != NULL)
+        {
+            open.peer_mtu = p_tbl->peer_mtu;
+            open.lcid = avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].lcid;
+            open.hdr.err_code = avdt_ad_tcid_to_type(p_tbl->tcid);
+            avdt_scb_event(p_scb, AVDT_SCB_TC_OPEN_EVT, (tAVDT_SCB_EVT *) &open);
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         avdt_ad_tc_cong_ind
+**
+** Description      This function is called by the L2CAP interface layer when
+**                  L2CAP calls the congestion callback.  It looks up the CCB
+**                  or SCB for the channel and sends it a congestion event.
+**                  The is_congested parameter is the same value passed by
+**                  the L2CAP callback function.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_ad_tc_cong_ind(tAVDT_TC_TBL *p_tbl, bool    is_congested)
+{
+    tAVDT_CCB   *p_ccb;
+    tAVDT_SCB   *p_scb;
+
+    /* if signaling channel, notify ccb of congestion */
+    if (p_tbl->tcid == 0)
+    {
+        p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
+        avdt_ccb_event(p_ccb, AVDT_CCB_LL_CONG_EVT, (tAVDT_CCB_EVT *) &is_congested);
+    }
+    /* if media or other channel, notify scb that channel open */
+    else
+    {
+        /* look up scb in stream routing table by ccb, tcid */
+        p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
+        if (p_scb != NULL)
+        {
+            avdt_scb_event(p_scb, AVDT_SCB_TC_CONG_EVT, (tAVDT_SCB_EVT *) &is_congested);
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         avdt_ad_tc_data_ind
+**
+** Description      This function is called by the L2CAP interface layer when
+**                  incoming data is received from L2CAP.  It looks up the CCB
+**                  or SCB for the channel and routes the data accordingly.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_ad_tc_data_ind(tAVDT_TC_TBL *p_tbl, BT_HDR *p_buf)
+{
+    tAVDT_CCB   *p_ccb;
+    tAVDT_SCB   *p_scb;
+
+    /* store type (media, recovery, reporting) */
+    p_buf->layer_specific = avdt_ad_tcid_to_type(p_tbl->tcid);
+
+
+    /* if signaling channel, handle control message */
+    if (p_tbl->tcid == 0)
+    {
+        p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
+        avdt_msg_ind(p_ccb, p_buf);
+    }
+    /* if media or other channel, send event to scb */
+    else
+    {
+        p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
+        if (p_scb != NULL)
+        {
+            avdt_scb_event(p_scb, AVDT_SCB_TC_DATA_EVT, (tAVDT_SCB_EVT *) &p_buf);
+        }
+        else
+        {
+            osi_free(p_buf);
+            AVDT_TRACE_ERROR(" avdt_ad_tc_data_ind buffer freed");
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ad_write_req
+**
+** Description      This function is called by a CCB or SCB to send data to a
+**                  transport channel.  It looks up the LCID of the channel
+**                  based on the type, CCB, and SCB (if present).  Then it
+**                  passes the data to L2CA_DataWrite().
+**
+**
+** Returns          AVDT_AD_SUCCESS, if data accepted, else false
+**                  AVDT_AD_CONGESTED, if data accepted and the channel is congested
+**                  AVDT_AD_FAILED, if error
+**
+*******************************************************************************/
+uint8_t avdt_ad_write_req(uint8_t type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, BT_HDR *p_buf)
+{
+    uint8_t tcid;
+
+    /* get tcid from type, scb */
+    tcid = avdt_ad_type_to_tcid(type, p_scb);
+
+
+    return L2CA_DataWrite(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         avdt_ad_open_req
+**
+** Description      This function is called by a CCB or SCB to open a transport
+**                  channel.  This function allocates and initializes a
+**                  transport channel table entry.  The channel can be opened
+**                  in two roles:  as an initiator or acceptor.  When opened
+**                  as an initiator the function will start an L2CAP connection.
+**                  When opened as an acceptor the function simply configures
+**                  the table entry to listen for an incoming channel.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_ad_open_req(uint8_t type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, uint8_t role)
+{
+    tAVDT_TC_TBL    *p_tbl;
+    uint16_t        lcid;
+
+    if((p_tbl = avdt_ad_tc_tbl_alloc(p_ccb)) == NULL)
+    {
+        AVDT_TRACE_ERROR("avdt_ad_open_req: Cannot allocate p_tbl");
+        return;
+    }
+
+
+    p_tbl->tcid = avdt_ad_type_to_tcid(type, p_scb);
+    AVDT_TRACE_DEBUG("avdt_ad_open_req: type: %d, role: %d, tcid:%d",
+        type, role, p_tbl->tcid);
+
+    if (type == AVDT_CHAN_SIG)
+    {
+        /* if signaling, get mtu from registration control block */
+        p_tbl->my_mtu = avdt_cb.rcb.ctrl_mtu;
+        p_tbl->my_flush_to = L2CAP_DEFAULT_FLUSH_TO;
+    }
+    else
+    {
+        /* otherwise get mtu from scb */
+        p_tbl->my_mtu = p_scb->cs.mtu;
+        p_tbl->my_flush_to = p_scb->cs.flush_to;
+
+        /* also set scb_hdl in rt_tbl */
+        avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].scb_hdl = avdt_scb_to_hdl(p_scb);
+        AVDT_TRACE_DEBUG("avdt_cb.ad.rt_tbl[%d][%d].scb_hdl = %d",
+            avdt_ccb_to_idx(p_ccb), p_tbl->tcid,
+            avdt_scb_to_hdl(p_scb));
+    }
+
+    /* if we're acceptor, we're done; just sit back and listen */
+    if (role == AVDT_ACP)
+    {
+        p_tbl->state = AVDT_AD_ST_ACP;
+    }
+    /* else we're inititator, start the L2CAP connection */
+    else
+    {
+        p_tbl->state = AVDT_AD_ST_CONN;
+
+        /* call l2cap connect req */
+        if ((lcid = L2CA_ConnectReq(AVDT_PSM, p_ccb->peer_addr)) != 0)
+        {
+            /* if connect req ok, store tcid in lcid table  */
+            avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl);
+            AVDT_TRACE_DEBUG("avdt_cb.ad.lcid_tbl[%d] = %d",
+                (lcid - L2CAP_BASE_APPL_CID), avdt_ad_tc_tbl_to_idx(p_tbl));
+
+            avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
+            AVDT_TRACE_DEBUG("avdt_cb.ad.rt_tbl[%d][%d].lcid = 0x%x",
+                avdt_ccb_to_idx(p_ccb), p_tbl->tcid,
+                lcid);
+        }
+        else
+        {
+            /* if connect req failed, call avdt_ad_tc_close_ind() */
+            avdt_ad_tc_close_ind(p_tbl, 0);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ad_close_req
+**
+** Description      This function is called by a CCB or SCB to close a
+**                  transport channel.  The function looks up the LCID for the
+**                  channel and calls L2CA_DisconnectReq().
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_ad_close_req(uint8_t type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb)
+{
+    uint8_t         tcid;
+    tAVDT_TC_TBL    *p_tbl;
+
+    p_tbl = avdt_ad_tc_tbl_by_type(type, p_ccb, p_scb);
+    AVDT_TRACE_DEBUG("avdt_ad_close_req state: %d", p_tbl->state);
+
+    switch(p_tbl->state)
+    {
+    case AVDT_AD_ST_UNUSED:
+        /* probably for reporting */
+        break;
+    case AVDT_AD_ST_ACP:
+        /* if we're listening on this channel, send ourselves a close ind */
+        avdt_ad_tc_close_ind(p_tbl, 0);
+        break;
+    default:
+        /* get tcid from type, scb */
+        tcid = avdt_ad_type_to_tcid(type, p_scb);
+
+        /* call l2cap disconnect req */
+        L2CA_DisconnectReq(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid);
+    }
+}
+
diff --git a/bt/stack/avdt/avdt_api.cc b/bt/stack/avdt/avdt_api.cc
new file mode 100644
index 0000000..bdd0e79
--- /dev/null
+++ b/bt/stack/avdt/avdt_api.cc
@@ -0,0 +1,1191 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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 module contains API of the audio/video distribution transport
+ *  protocol.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "l2c_api.h"
+#include "btm_api.h"
+#include "btu.h"
+
+
+/* Control block for AVDT */
+tAVDT_CB avdt_cb;
+
+void avdt_ccb_idle_ccb_timer_timeout(void *data)
+{
+    tAVDT_CCB *p_ccb = (tAVDT_CCB *)data;
+    uint8_t avdt_event = AVDT_CCB_IDLE_TOUT_EVT;
+    uint8_t err_code = AVDT_ERR_TIMEOUT;
+
+    avdt_ccb_event(p_ccb, avdt_event, (tAVDT_CCB_EVT *)&err_code);
+}
+
+void avdt_ccb_ret_ccb_timer_timeout(void *data)
+{
+    tAVDT_CCB *p_ccb = (tAVDT_CCB *)data;
+    uint8_t avdt_event = AVDT_CCB_RET_TOUT_EVT;
+    uint8_t err_code = AVDT_ERR_TIMEOUT;
+
+    avdt_ccb_event(p_ccb, avdt_event, (tAVDT_CCB_EVT *)&err_code);
+}
+
+void avdt_ccb_rsp_ccb_timer_timeout(void *data)
+{
+    tAVDT_CCB *p_ccb = (tAVDT_CCB *)data;
+    uint8_t avdt_event = AVDT_CCB_RSP_TOUT_EVT;
+    uint8_t err_code = AVDT_ERR_TIMEOUT;
+
+    avdt_ccb_event(p_ccb, avdt_event, (tAVDT_CCB_EVT *)&err_code);
+}
+
+void avdt_scb_transport_channel_timer_timeout(void *data)
+{
+    tAVDT_SCB *p_scb = (tAVDT_SCB *)data;
+    uint8_t avdt_event = AVDT_SCB_TC_TOUT_EVT;
+
+    avdt_scb_event(p_scb, avdt_event, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_Register
+**
+** Description      This is the system level registration function for the
+**                  AVDTP protocol.  This function initializes AVDTP and
+**                  prepares the protocol stack for its use.  This function
+**                  must be called once by the system or platform using AVDTP
+**                  before the other functions of the API an be used.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void AVDT_Register(tAVDT_REG *p_reg, tAVDT_CTRL_CBACK *p_cback)
+{
+    /* register PSM with L2CAP */
+    L2CA_Register(AVDT_PSM, (tL2CAP_APPL_INFO *) &avdt_l2c_appl);
+
+    /* set security level */
+    BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVDTP, p_reg->sec_mask,
+        AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG);
+    BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_AVDTP, p_reg->sec_mask,
+        AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG);
+
+    /* do not use security on the media channel */
+    BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE,
+        AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_MEDIA);
+    BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE,
+        AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_MEDIA);
+
+#if (AVDT_REPORTING == TRUE)
+    /* do not use security on the reporting channel */
+    BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE,
+        AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_REPORT);
+    BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE,
+        AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_REPORT);
+#endif
+
+    /* initialize AVDTP data structures */
+    avdt_scb_init();
+    avdt_ccb_init();
+    avdt_ad_init();
+
+    /* copy registration struct */
+    memcpy(&avdt_cb.rcb, p_reg, sizeof(tAVDT_REG));
+    avdt_cb.p_conn_cback = p_cback;
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_Deregister
+**
+** Description      This function is called to deregister use AVDTP protocol.
+**                  It is called when AVDTP is no longer being used by any
+**                  application in the system.  Before this function can be
+**                  called, all streams must be removed with AVDT_RemoveStream().
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void AVDT_Deregister(void)
+{
+    /* deregister PSM with L2CAP */
+    L2CA_Deregister(AVDT_PSM);
+}
+
+void AVDT_AbortReq(uint8_t handle)
+{
+    AVDT_TRACE_ERROR("%s", __func__);
+
+    tAVDT_SCB *p_scb = avdt_scb_by_hdl(handle);
+    if (p_scb != NULL)
+    {
+        avdt_scb_event(p_scb, AVDT_SCB_API_ABORT_REQ_EVT, NULL);
+    } else {
+        AVDT_TRACE_ERROR("%s Improper SCB, can not abort the stream", __func__);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_CreateStream
+**
+** Description      Create a stream endpoint.  After a stream endpoint is
+**                  created an application can initiate a connection between
+**                  this endpoint and an endpoint on a peer device.  In
+**                  addition, a peer device can discover, get the capabilities,
+**                  and connect to this endpoint.
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVDT_CreateStream(uint8_t *p_handle, tAVDT_CS *p_cs)
+{
+    uint16_t    result = AVDT_SUCCESS;
+    tAVDT_SCB   *p_scb;
+
+    /* Verify parameters; if invalid, return failure */
+    if (((p_cs->cfg.psc_mask & (~AVDT_PSC)) != 0) || (p_cs->p_ctrl_cback == NULL))
+    {
+        result = AVDT_BAD_PARAMS;
+    }
+    /* Allocate scb; if no scbs, return failure */
+    else if ((p_scb = avdt_scb_alloc(p_cs)) == NULL)
+    {
+        result = AVDT_NO_RESOURCES;
+    }
+    else
+    {
+        *p_handle = avdt_scb_to_hdl(p_scb);
+    }
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_RemoveStream
+**
+** Description      Remove a stream endpoint.  This function is called when
+**                  the application is no longer using a stream endpoint.
+**                  If this function is called when the endpoint is connected
+**                  the connection is closed and then the stream endpoint
+**                  is removed.
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVDT_RemoveStream(uint8_t handle)
+{
+    uint16_t    result = AVDT_SUCCESS;
+    tAVDT_SCB   *p_scb;
+
+    /* look up scb */
+    if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+    {
+        result = AVDT_BAD_HANDLE;
+    }
+    else
+    {
+        /* send remove event to scb */
+        avdt_scb_event(p_scb, AVDT_SCB_API_REMOVE_EVT, NULL);
+    }
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_DiscoverReq
+**
+** Description      This function initiates a connection to the AVDTP service
+**                  on the peer device, if not already present, and discovers
+**                  the stream endpoints on the peer device.  (Please note
+**                  that AVDTP discovery is unrelated to SDP discovery).
+**                  This function can be called at any time regardless of whether
+**                  there is an AVDTP connection to the peer device.
+**
+**                  When discovery is complete, an AVDT_DISCOVER_CFM_EVT
+**                  is sent to the application via its callback function.
+**                  The application must not call AVDT_GetCapReq() or
+**                  AVDT_DiscoverReq() again to the same device until
+**                  discovery is complete.
+**
+**                  The memory addressed by sep_info is allocated by the
+**                  application.  This memory is written to by AVDTP as part
+**                  of the discovery procedure.  This memory must remain
+**                  accessible until the application receives the
+**                  AVDT_DISCOVER_CFM_EVT.
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVDT_DiscoverReq(BD_ADDR bd_addr, tAVDT_SEP_INFO *p_sep_info,
+                        uint8_t max_seps, tAVDT_CTRL_CBACK *p_cback)
+{
+    tAVDT_CCB       *p_ccb;
+    uint16_t        result = AVDT_SUCCESS;
+    tAVDT_CCB_EVT   evt;
+
+    /* find channel control block for this bd addr; if none, allocate one */
+    if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
+    {
+        if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL)
+        {
+            /* could not allocate channel control block */
+            result = AVDT_NO_RESOURCES;
+        }
+    }
+
+    if (result == AVDT_SUCCESS)
+    {
+        /* make sure no discovery or get capabilities req already in progress */
+        if (p_ccb->proc_busy)
+        {
+            result = AVDT_BUSY;
+        }
+        /* send event to ccb */
+        else
+        {
+            evt.discover.p_sep_info = p_sep_info;
+            evt.discover.num_seps = max_seps;
+            evt.discover.p_cback = p_cback;
+            avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCOVER_REQ_EVT, &evt);
+        }
+    }
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_get_cap_req
+**
+** Description      internal function to serve both AVDT_GetCapReq and
+**                  AVDT_GetAllCapReq
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+static uint16_t avdt_get_cap_req(BD_ADDR bd_addr, tAVDT_CCB_API_GETCAP *p_evt)
+{
+    tAVDT_CCB       *p_ccb = NULL;
+    uint16_t        result = AVDT_SUCCESS;
+
+    /* verify SEID */
+    if ((p_evt->single.seid < AVDT_SEID_MIN) || (p_evt->single.seid > AVDT_SEID_MAX))
+    {
+        AVDT_TRACE_ERROR("seid: %d", p_evt->single.seid);
+        result = AVDT_BAD_PARAMS;
+    }
+    /* find channel control block for this bd addr; if none, allocate one */
+    else if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
+    {
+        if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL)
+        {
+            /* could not allocate channel control block */
+            result = AVDT_NO_RESOURCES;
+        }
+    }
+
+    if (result == AVDT_SUCCESS)
+    {
+        /* make sure no discovery or get capabilities req already in progress */
+        if (p_ccb->proc_busy)
+        {
+            result = AVDT_BUSY;
+        }
+        /* send event to ccb */
+        else
+        {
+            avdt_ccb_event(p_ccb, AVDT_CCB_API_GETCAP_REQ_EVT, (tAVDT_CCB_EVT *)p_evt);
+        }
+    }
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_GetCapReq
+**
+** Description      This function initiates a connection to the AVDTP service
+**                  on the peer device, if not already present, and gets the
+**                  capabilities of a stream endpoint on the peer device.
+**                  This function can be called at any time regardless of
+**                  whether there is an AVDTP connection to the peer device.
+**
+**                  When the procedure is complete, an AVDT_GETCAP_CFM_EVT is
+**                  sent to the application via its callback function.  The
+**                  application must not call AVDT_GetCapReq() or
+**                  AVDT_DiscoverReq() again until the procedure is complete.
+**
+**                  The memory pointed to by p_cfg is allocated by the
+**                  application.  This memory is written to by AVDTP as part
+**                  of the get capabilities procedure.  This memory must
+**                  remain accessible until the application receives
+**                  the AVDT_GETCAP_CFM_EVT.
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVDT_GetCapReq(BD_ADDR bd_addr, uint8_t seid, tAVDT_CFG *p_cfg, tAVDT_CTRL_CBACK *p_cback)
+{
+    tAVDT_CCB_API_GETCAP    getcap;
+
+    getcap.single.seid = seid;
+    getcap.single.sig_id = AVDT_SIG_GETCAP;
+    getcap.p_cfg = p_cfg;
+    getcap.p_cback = p_cback;
+    return avdt_get_cap_req (bd_addr, &getcap);
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_GetAllCapReq
+**
+** Description      This function initiates a connection to the AVDTP service
+**                  on the peer device, if not already present, and gets the
+**                  capabilities of a stream endpoint on the peer device.
+**                  This function can be called at any time regardless of
+**                  whether there is an AVDTP connection to the peer device.
+**
+**                  When the procedure is complete, an AVDT_GETCAP_CFM_EVT is
+**                  sent to the application via its callback function.  The
+**                  application must not call AVDT_GetCapReq() or
+**                  AVDT_DiscoverReq() again until the procedure is complete.
+**
+**                  The memory pointed to by p_cfg is allocated by the
+**                  application.  This memory is written to by AVDTP as part
+**                  of the get capabilities procedure.  This memory must
+**                  remain accessible until the application receives
+**                  the AVDT_GETCAP_CFM_EVT.
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVDT_GetAllCapReq(BD_ADDR bd_addr, uint8_t seid, tAVDT_CFG *p_cfg, tAVDT_CTRL_CBACK *p_cback)
+{
+    tAVDT_CCB_API_GETCAP    getcap;
+
+    getcap.single.seid = seid;
+    getcap.single.sig_id = AVDT_SIG_GET_ALLCAP;
+    getcap.p_cfg = p_cfg;
+    getcap.p_cback = p_cback;
+    return avdt_get_cap_req (bd_addr, &getcap);
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_DelayReport
+**
+** Description      This functions sends a Delay Report to the peer device
+**                  that is associated with a particular SEID.
+**                  This function is called by SNK device.
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVDT_DelayReport(uint8_t handle, uint8_t seid, uint16_t delay)
+{
+    tAVDT_SCB       *p_scb;
+    uint16_t        result = AVDT_SUCCESS;
+    tAVDT_SCB_EVT   evt;
+
+    /* map handle to scb */
+    if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+    {
+        result = AVDT_BAD_HANDLE;
+    }
+    else
+    /* send event to scb */
+    {
+        evt.apidelay.hdr.seid   = seid;
+        evt.apidelay.delay      = delay;
+        avdt_scb_event(p_scb, AVDT_SCB_API_DELAY_RPT_REQ_EVT, &evt);
+    }
+
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_OpenReq
+**
+** Description      This function initiates a connection to the AVDTP service
+**                  on the peer device, if not already present, and connects
+**                  to a stream endpoint on a peer device.  When the connection
+**                  is completed, an AVDT_OPEN_CFM_EVT is sent to the
+**                  application via the control callback function for this handle.
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVDT_OpenReq(uint8_t handle, BD_ADDR bd_addr, uint8_t seid, tAVDT_CFG *p_cfg)
+{
+    tAVDT_CCB       *p_ccb = NULL;
+    tAVDT_SCB       *p_scb = NULL;
+    uint16_t        result = AVDT_SUCCESS;
+    tAVDT_SCB_EVT   evt;
+
+    /* verify SEID */
+    if ((seid < AVDT_SEID_MIN) || (seid > AVDT_SEID_MAX))
+    {
+        result = AVDT_BAD_PARAMS;
+    }
+    /* map handle to scb */
+    else if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+    {
+        result = AVDT_BAD_HANDLE;
+    }
+    /* find channel control block for this bd addr; if none, allocate one */
+    else if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
+    {
+        if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL)
+        {
+            /* could not allocate channel control block */
+            result = AVDT_NO_RESOURCES;
+        }
+    }
+
+    /* send event to scb */
+    if (result == AVDT_SUCCESS)
+    {
+        evt.msg.config_cmd.hdr.seid = seid;
+        evt.msg.config_cmd.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb);
+        evt.msg.config_cmd.int_seid = handle;
+        evt.msg.config_cmd.p_cfg = p_cfg;
+        avdt_scb_event(p_scb, AVDT_SCB_API_SETCONFIG_REQ_EVT, &evt);
+    }
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_ConfigRsp
+**
+** Description      Respond to a configure request from the peer device.  This
+**                  function must be called if the application receives an
+**                  AVDT_CONFIG_IND_EVT through its control callback.
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVDT_ConfigRsp(uint8_t handle, uint8_t label, uint8_t error_code, uint8_t category)
+{
+    tAVDT_SCB       *p_scb;
+    tAVDT_SCB_EVT   evt;
+    uint16_t        result = AVDT_SUCCESS;
+    uint8_t         event_code;
+
+    /* map handle to scb */
+    if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+    {
+        result = AVDT_BAD_HANDLE;
+    }
+    /* handle special case when this function is called but peer has not send
+    ** a configuration cmd; ignore and return error result
+    */
+    else if (!p_scb->in_use)
+    {
+        result = AVDT_BAD_HANDLE;
+    }
+    /* send event to scb */
+    else
+    {
+        evt.msg.hdr.err_code = error_code;
+        evt.msg.hdr.err_param = category;
+        evt.msg.hdr.label = label;
+        if (error_code == 0)
+        {
+            event_code = AVDT_SCB_API_SETCONFIG_RSP_EVT;
+        }
+        else
+        {
+            event_code = AVDT_SCB_API_SETCONFIG_REJ_EVT;
+        }
+        avdt_scb_event(p_scb, event_code, &evt);
+    }
+
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_StartReq
+**
+** Description      Start one or more stream endpoints.  This initiates the
+**                  transfer of media packets for the streams.  All stream
+**                  endpoints must previously be opened.  When the streams
+**                  are started, an AVDT_START_CFM_EVT is sent to the
+**                  application via the control callback function for each stream.
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVDT_StartReq(uint8_t *p_handles, uint8_t num_handles)
+{
+    tAVDT_SCB       *p_scb = NULL;
+    tAVDT_CCB_EVT   evt;
+    uint16_t        result = AVDT_SUCCESS;
+    int             i;
+
+    if ((num_handles == 0) || (num_handles > AVDT_NUM_SEPS))
+    {
+        result = AVDT_BAD_PARAMS;
+    }
+    else
+    {
+        /* verify handles */
+        for (i = 0; i < num_handles; i++)
+        {
+            if ((p_scb = avdt_scb_by_hdl(p_handles[i])) == NULL)
+            {
+                result = AVDT_BAD_HANDLE;
+                break;
+            }
+        }
+    }
+
+    if (result == AVDT_SUCCESS)
+    {
+        if (p_scb->p_ccb == NULL)
+        {
+            result = AVDT_BAD_HANDLE;
+        }
+        else
+        {
+            /* send event to ccb */
+            memcpy(evt.msg.multi.seid_list, p_handles, num_handles);
+            evt.msg.multi.num_seps = num_handles;
+            avdt_ccb_event(p_scb->p_ccb, AVDT_CCB_API_START_REQ_EVT, &evt);
+        }
+    }
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_SuspendReq
+**
+** Description      Suspend one or more stream endpoints. This suspends the
+**                  transfer of media packets for the streams.  All stream
+**                  endpoints must previously be open and started.  When the
+**                  streams are suspended, an AVDT_SUSPEND_CFM_EVT is sent to
+**                  the application via the control callback function for
+**                  each stream.
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVDT_SuspendReq(uint8_t *p_handles, uint8_t num_handles)
+{
+    tAVDT_SCB       *p_scb = NULL;
+    tAVDT_CCB_EVT   evt;
+    uint16_t        result = AVDT_SUCCESS;
+    int             i;
+
+    if ((num_handles == 0) || (num_handles > AVDT_NUM_SEPS))
+    {
+        result = AVDT_BAD_PARAMS;
+    }
+    else
+    {
+        /* verify handles */
+        for (i = 0; i < num_handles; i++)
+        {
+            if ((p_scb = avdt_scb_by_hdl(p_handles[i])) == NULL)
+            {
+                result = AVDT_BAD_HANDLE;
+                break;
+            }
+        }
+    }
+
+    if (result == AVDT_SUCCESS)
+    {
+        if (p_scb->p_ccb == NULL)
+        {
+            result = AVDT_BAD_HANDLE;
+        }
+        else
+        {
+            /* send event to ccb */
+            memcpy(evt.msg.multi.seid_list, p_handles, num_handles);
+            evt.msg.multi.num_seps = num_handles;
+            avdt_ccb_event(p_scb->p_ccb, AVDT_CCB_API_SUSPEND_REQ_EVT, &evt);
+        }
+    }
+
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_CloseReq
+**
+** Description      Close a stream endpoint.  This stops the transfer of media
+**                  packets and closes the transport channel associated with
+**                  this stream endpoint.  When the stream is closed, an
+**                  AVDT_CLOSE_CFM_EVT is sent to the application via the
+**                  control callback function for this handle.
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVDT_CloseReq(uint8_t handle)
+{
+    tAVDT_SCB       *p_scb;
+    uint16_t        result = AVDT_SUCCESS;
+
+    /* map handle to scb */
+    if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+    {
+        result = AVDT_BAD_HANDLE;
+    }
+    else
+    /* send event to scb */
+    {
+        avdt_scb_event(p_scb, AVDT_SCB_API_CLOSE_REQ_EVT, NULL);
+    }
+
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_ReconfigReq
+**
+** Description      Reconfigure a stream endpoint.  This allows the application
+**                  to change the codec or content protection capabilities of
+**                  a stream endpoint after it has been opened.  This function
+**                  can only be called if the stream is opened but not started
+**                  or if the stream has been suspended.  When the procedure
+**                  is completed, an AVDT_RECONFIG_CFM_EVT is sent to the
+**                  application via the control callback function for this handle.
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVDT_ReconfigReq(uint8_t handle, tAVDT_CFG *p_cfg)
+{
+    tAVDT_SCB       *p_scb;
+    uint16_t        result = AVDT_SUCCESS;
+    tAVDT_SCB_EVT   evt;
+
+    /* map handle to scb */
+    if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+    {
+        result = AVDT_BAD_HANDLE;
+    }
+    /* send event to scb */
+    else
+    {
+        /* force psc_mask to zero */
+        p_cfg->psc_mask = 0;
+
+        evt.msg.reconfig_cmd.p_cfg = p_cfg;
+        avdt_scb_event(p_scb, AVDT_SCB_API_RECONFIG_REQ_EVT, &evt);
+    }
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_ReconfigRsp
+**
+** Description      Respond to a reconfigure request from the peer device.
+**                  This function must be called if the application receives
+**                  an AVDT_RECONFIG_IND_EVT through its control callback.
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVDT_ReconfigRsp(uint8_t handle, uint8_t label, uint8_t error_code, uint8_t category)
+{
+    tAVDT_SCB       *p_scb;
+    tAVDT_SCB_EVT   evt;
+    uint16_t        result = AVDT_SUCCESS;
+
+    /* map handle to scb */
+    if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+    {
+        result = AVDT_BAD_HANDLE;
+    }
+    /* send event to scb */
+    else
+    {
+        evt.msg.hdr.err_code = error_code;
+        evt.msg.hdr.err_param = category;
+        evt.msg.hdr.label = label;
+        avdt_scb_event(p_scb, AVDT_SCB_API_RECONFIG_RSP_EVT, &evt);
+    }
+
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_SecurityReq
+**
+** Description      Send a security request to the peer device.  When the
+**                  security procedure is completed, an AVDT_SECURITY_CFM_EVT
+**                  is sent to the application via the control callback function
+**                  for this handle.  (Please note that AVDTP security procedures
+**                  are unrelated to Bluetooth link level security.)
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVDT_SecurityReq(uint8_t handle, uint8_t *p_data, uint16_t len)
+{
+    tAVDT_SCB       *p_scb;
+    uint16_t        result = AVDT_SUCCESS;
+    tAVDT_SCB_EVT   evt;
+
+    /* map handle to scb */
+    if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+    {
+        result = AVDT_BAD_HANDLE;
+    }
+    /* send event to scb */
+    else
+    {
+        evt.msg.security_rsp.p_data = p_data;
+        evt.msg.security_rsp.len = len;
+        avdt_scb_event(p_scb, AVDT_SCB_API_SECURITY_REQ_EVT, &evt);
+    }
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_SecurityRsp
+**
+** Description      Respond to a security request from the peer device.
+**                  This function must be called if the application receives
+**                  an AVDT_SECURITY_IND_EVT through its control callback.
+**                  (Please note that AVDTP security procedures are unrelated
+**                  to Bluetooth link level security.)
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVDT_SecurityRsp(uint8_t handle, uint8_t label, uint8_t error_code,
+                        uint8_t *p_data, uint16_t len)
+{
+    tAVDT_SCB       *p_scb;
+    uint16_t        result = AVDT_SUCCESS;
+    tAVDT_SCB_EVT   evt;
+
+    /* map handle to scb */
+    if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+    {
+        result = AVDT_BAD_HANDLE;
+    }
+    /* send event to scb */
+    else
+    {
+        evt.msg.security_rsp.hdr.err_code = error_code;
+        evt.msg.security_rsp.hdr.label = label;
+        evt.msg.security_rsp.p_data = p_data;
+        evt.msg.security_rsp.len = len;
+        avdt_scb_event(p_scb, AVDT_SCB_API_SECURITY_RSP_EVT, &evt);
+    }
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_WriteReqOpt
+**
+** Description      Send a media packet to the peer device.  The stream must
+**                  be started before this function is called.  Also, this
+**                  function can only be called if the stream is a SRC.
+**
+**                  When AVDTP has sent the media packet and is ready for the
+**                  next packet, an AVDT_WRITE_CFM_EVT is sent to the
+**                  application via the control callback.  The application must
+**                  wait for the AVDT_WRITE_CFM_EVT before it makes the next
+**                  call to AVDT_WriteReq().  If the applications calls
+**                  AVDT_WriteReq() before it receives the event the packet
+**                  will not be sent.  The application may make its first call
+**                  to AVDT_WriteReq() after it receives an AVDT_START_CFM_EVT
+**                  or AVDT_START_IND_EVT.
+**
+**                  The application passes the packet using the BT_HDR structure.
+**                  This structure is described in section 2.1.  The offset
+**                  field must be equal to or greater than AVDT_MEDIA_OFFSET
+**                  (if NO_RTP is specified, L2CAP_MIN_OFFSET can be used).
+**                  This allows enough space in the buffer for the L2CAP and
+**                  AVDTP headers.
+**
+**                  The memory pointed to by p_pkt must be a GKI buffer
+**                  allocated by the application.  This buffer will be freed
+**                  by the protocol stack; the application must not free
+**                  this buffer.
+**
+**                  The opt parameter allows passing specific options like:
+**                  - NO_RTP : do not add the RTP header to buffer
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVDT_WriteReqOpt(uint8_t handle, BT_HDR *p_pkt, uint32_t time_stamp, uint8_t m_pt, tAVDT_DATA_OPT_MASK opt)
+{
+    tAVDT_SCB       *p_scb;
+    tAVDT_SCB_EVT   evt;
+    uint16_t        result = AVDT_SUCCESS;
+
+    /* map handle to scb */
+    if ((p_scb = avdt_scb_by_hdl(handle)) == NULL)
+    {
+        result = AVDT_BAD_HANDLE;
+    }
+    else
+    {
+        evt.apiwrite.p_buf = p_pkt;
+        evt.apiwrite.time_stamp = time_stamp;
+        evt.apiwrite.m_pt = m_pt;
+        evt.apiwrite.opt = opt;
+        avdt_scb_event(p_scb, AVDT_SCB_API_WRITE_REQ_EVT, &evt);
+    }
+
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_WriteReq
+**
+** Description      Send a media packet to the peer device.  The stream must
+**                  be started before this function is called.  Also, this
+**                  function can only be called if the stream is a SRC.
+**
+**                  When AVDTP has sent the media packet and is ready for the
+**                  next packet, an AVDT_WRITE_CFM_EVT is sent to the
+**                  application via the control callback.  The application must
+**                  wait for the AVDT_WRITE_CFM_EVT before it makes the next
+**                  call to AVDT_WriteReq().  If the applications calls
+**                  AVDT_WriteReq() before it receives the event the packet
+**                  will not be sent.  The application may make its first call
+**                  to AVDT_WriteReq() after it receives an AVDT_START_CFM_EVT
+**                  or AVDT_START_IND_EVT.
+**
+**                  The application passes the packet using the BT_HDR structure.
+**                  This structure is described in section 2.1.  The offset
+**                  field must be equal to or greater than AVDT_MEDIA_OFFSET.
+**                  This allows enough space in the buffer for the L2CAP and
+**                  AVDTP headers.
+**
+**                  The memory pointed to by p_pkt must be a GKI buffer
+**                  allocated by the application.  This buffer will be freed
+**                  by the protocol stack; the application must not free
+**                  this buffer.
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVDT_WriteReq(uint8_t handle, BT_HDR *p_pkt, uint32_t time_stamp, uint8_t m_pt)
+{
+    return AVDT_WriteReqOpt(handle, p_pkt, time_stamp, m_pt, AVDT_DATA_OPT_NONE);
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_ConnectReq
+**
+** Description      This function initiates an AVDTP signaling connection
+**                  to the peer device.  When the connection is completed, an
+**                  AVDT_CONNECT_IND_EVT is sent to the application via its
+**                  control callback function.  If the connection attempt fails
+**                  an AVDT_DISCONNECT_IND_EVT is sent.  The security mask
+**                  parameter overrides the outgoing security mask set in
+**                  AVDT_Register().
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVDT_ConnectReq(BD_ADDR bd_addr, uint8_t sec_mask, tAVDT_CTRL_CBACK *p_cback)
+{
+    tAVDT_CCB       *p_ccb = NULL;
+    uint16_t        result = AVDT_SUCCESS;
+    tAVDT_CCB_EVT   evt;
+
+    /* find channel control block for this bd addr; if none, allocate one */
+    if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
+    {
+        if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL)
+        {
+            /* could not allocate channel control block */
+            result = AVDT_NO_RESOURCES;
+        }
+    }
+    else if (p_ccb->ll_opened == false)
+    {
+        AVDT_TRACE_WARNING("AVDT_ConnectReq: CCB LL is in the middle of opening");
+
+        /* ccb was already allocated for the incoming signalling. */
+        result = AVDT_BUSY;
+    }
+
+    if (result == AVDT_SUCCESS)
+    {
+        /* send event to ccb */
+        evt.connect.p_cback = p_cback;
+        evt.connect.sec_mask = sec_mask;
+        avdt_ccb_event(p_ccb, AVDT_CCB_API_CONNECT_REQ_EVT, &evt);
+    }
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_DisconnectReq
+**
+** Description      This function disconnect an AVDTP signaling connection
+**                  to the peer device.  When disconnected an
+**                  AVDT_DISCONNECT_IND_EVT is sent to the application via its
+**                  control callback function.
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVDT_DisconnectReq(BD_ADDR bd_addr, tAVDT_CTRL_CBACK *p_cback)
+{
+    tAVDT_CCB       *p_ccb = NULL;
+    uint16_t        result = AVDT_SUCCESS;
+    tAVDT_CCB_EVT   evt;
+
+    /* find channel control block for this bd addr; if none, error */
+    if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
+    {
+        result = AVDT_BAD_PARAMS;
+    }
+
+    if (result == AVDT_SUCCESS)
+    {
+        /* send event to ccb */
+        evt.disconnect.p_cback = p_cback;
+        avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCONNECT_REQ_EVT, &evt);
+    }
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_GetL2CapChannel
+**
+** Description      Get the L2CAP CID used by the handle.
+**
+** Returns          CID if successful, otherwise 0.
+**
+*******************************************************************************/
+uint16_t AVDT_GetL2CapChannel(uint8_t handle)
+{
+    tAVDT_SCB       *p_scb;
+    tAVDT_CCB       *p_ccb;
+    uint8_t         tcid;
+    uint16_t        lcid = 0;
+
+    /* map handle to scb */
+    if (((p_scb = avdt_scb_by_hdl(handle)) != NULL)
+     && ((p_ccb = p_scb->p_ccb) != NULL))
+    {
+        /* get tcid from type, scb */
+        tcid = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb);
+
+        lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
+    }
+
+    return (lcid);
+}
+
+/*******************************************************************************
+**
+** Function         AVDT_GetSignalChannel
+**
+** Description      Get the L2CAP CID used by the signal channel of the given handle.
+**
+** Returns          CID if successful, otherwise 0.
+**
+*******************************************************************************/
+uint16_t AVDT_GetSignalChannel(uint8_t handle, BD_ADDR bd_addr)
+{
+    tAVDT_SCB       *p_scb;
+    tAVDT_CCB       *p_ccb;
+    uint8_t         tcid = 0; /* tcid is always 0 for signal channel */
+    uint16_t        lcid = 0;
+
+    /* map handle to scb */
+    if (((p_scb = avdt_scb_by_hdl(handle)) != NULL)
+     && ((p_ccb = p_scb->p_ccb) != NULL))
+    {
+        lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
+    }
+    else if ((p_ccb = avdt_ccb_by_bd(bd_addr)) != NULL)
+    {
+        lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
+    }
+
+    return (lcid);
+}
+
+#if (AVDT_REPORTING == TRUE)
+/*******************************************************************************
+**
+** Function         AVDT_SendReport
+**
+** Description
+**
+**
+**
+** Returns
+**
+*******************************************************************************/
+uint16_t AVDT_SendReport(uint8_t handle, AVDT_REPORT_TYPE type,
+                       tAVDT_REPORT_DATA *p_data)
+{
+    tAVDT_SCB       *p_scb;
+    uint16_t        result = AVDT_BAD_PARAMS;
+    tAVDT_TC_TBL    *p_tbl;
+    uint8_t         *p, *plen, *pm1, *p_end;
+    uint32_t ssrc;
+    uint16_t len;
+
+    /* map handle to scb && verify parameters */
+    if (((p_scb = avdt_scb_by_hdl(handle)) != NULL)
+     && (p_scb->p_ccb != NULL)
+     && (((type == AVDT_RTCP_PT_SR) && (p_scb->cs.tsep == AVDT_TSEP_SRC)) ||
+        ((type == AVDT_RTCP_PT_RR) && (p_scb->cs.tsep == AVDT_TSEP_SNK)) ||
+        (type == AVDT_RTCP_PT_SDES)) )
+    {
+        result = AVDT_NO_RESOURCES;
+
+        /* build SR - assume fit in one packet */
+        p_tbl = avdt_ad_tc_tbl_by_type(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb);
+        if (p_tbl->state == AVDT_AD_ST_OPEN) {
+            BT_HDR *p_pkt = (BT_HDR *)osi_malloc(p_tbl->peer_mtu + sizeof(BT_HDR));
+
+            p_pkt->offset = L2CAP_MIN_OFFSET;
+            p = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+            pm1 = p;
+            *p++ = AVDT_MEDIA_OCTET1 | 1;
+            *p++ = type;
+            /* save the location for length */
+            plen = p;
+            p+= 2;
+            ssrc = avdt_scb_gen_ssrc(p_scb);
+            UINT32_TO_BE_STREAM(p, ssrc);
+
+            switch(type)
+            {
+            case AVDT_RTCP_PT_SR:   /* Sender Report */
+                *pm1 = AVDT_MEDIA_OCTET1;
+                UINT32_TO_BE_STREAM(p, p_data->sr.ntp_sec);
+                UINT32_TO_BE_STREAM(p, p_data->sr.ntp_frac);
+                UINT32_TO_BE_STREAM(p, p_data->sr.rtp_time);
+                UINT32_TO_BE_STREAM(p, p_data->sr.pkt_count);
+                UINT32_TO_BE_STREAM(p, p_data->sr.octet_count);
+                break;
+
+            case AVDT_RTCP_PT_RR:   /* Receiver Report */
+                *p++ = p_data->rr.frag_lost;
+                AVDT_TRACE_API("packet_lost: %d", p_data->rr.packet_lost);
+                p_data->rr.packet_lost &= 0xFFFFFF;
+                AVDT_TRACE_API("packet_lost: %d", p_data->rr.packet_lost);
+                UINT24_TO_BE_STREAM(p, p_data->rr.packet_lost);
+                UINT32_TO_BE_STREAM(p, p_data->rr.seq_num_rcvd);
+                UINT32_TO_BE_STREAM(p, p_data->rr.jitter);
+                UINT32_TO_BE_STREAM(p, p_data->rr.lsr);
+                UINT32_TO_BE_STREAM(p, p_data->rr.dlsr);
+                break;
+
+            case AVDT_RTCP_PT_SDES: /* Source Description */
+                *p++ = AVDT_RTCP_SDES_CNAME;
+                len = strlen((char *)p_data->cname);
+                if(len > AVDT_MAX_CNAME_SIZE)
+                    len = AVDT_MAX_CNAME_SIZE;
+                *p++ = (uint8_t)len;
+                strlcpy((char *)p, (char *)p_data->cname, len+1);
+                p += len;
+                break;
+            }
+            p_end = p;
+            len = p - pm1 - 1;
+            UINT16_TO_BE_STREAM(plen, len);
+
+            /* set the actual payload length */
+            p_pkt->len = p_end - p;
+            /* send the packet */
+            if(L2CAP_DW_FAILED != avdt_ad_write_req(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb, p_pkt))
+                result = AVDT_SUCCESS;
+        }
+    }
+
+    return result;
+}
+#endif
+
+/******************************************************************************
+**
+** Function         AVDT_SetTraceLevel
+**
+** Description      Sets the trace level for AVDT. If 0xff is passed, the
+**                  current trace level is returned.
+**
+**                  Input Parameters:
+**                      new_level:  The level to set the AVDT tracing to:
+**                      0xff-returns the current setting.
+**                      0-turns off tracing.
+**                      >= 1-Errors.
+**                      >= 2-Warnings.
+**                      >= 3-APIs.
+**                      >= 4-Events.
+**                      >= 5-Debug.
+**
+** Returns          The new trace level or current trace level if
+**                  the input parameter is 0xff.
+**
+******************************************************************************/
+uint8_t AVDT_SetTraceLevel (uint8_t new_level)
+{
+    if (new_level != 0xFF)
+        avdt_cb.trace_level = new_level;
+
+    return (avdt_cb.trace_level);
+}
diff --git a/bt/stack/avdt/avdt_ccb.cc b/bt/stack/avdt/avdt_ccb.cc
new file mode 100644
index 0000000..e5f135f
--- /dev/null
+++ b/bt/stack/avdt/avdt_ccb.cc
@@ -0,0 +1,471 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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 module contains the channel control block state machine and
+ *  functions which operate on the channel control block.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "bt_common.h"
+#include "btu.h"
+#include "osi/include/osi.h"
+
+/*****************************************************************************
+** state machine constants and types
+*****************************************************************************/
+#if (AVDT_DEBUG == TRUE)
+
+/* verbose state strings for trace */
+const char * const avdt_ccb_st_str[] = {
+    "CCB_IDLE_ST",
+    "CCB_OPENING_ST",
+    "CCB_OPEN_ST",
+    "CCB_CLOSING_ST"
+};
+
+/* verbose event strings for trace */
+const char * const avdt_ccb_evt_str[] = {
+    "API_DISCOVER_REQ_EVT",
+    "API_GETCAP_REQ_EVT",
+    "API_START_REQ_EVT",
+    "API_SUSPEND_REQ_EVT",
+    "API_DISCOVER_RSP_EVT",
+    "API_GETCAP_RSP_EVT",
+    "API_START_RSP_EVT",
+    "API_SUSPEND_RSP_EVT",
+    "API_CONNECT_REQ_EVT",
+    "API_DISCONNECT_REQ_EVT",
+    "MSG_DISCOVER_CMD_EVT",
+    "MSG_GETCAP_CMD_EVT",
+    "MSG_START_CMD_EVT",
+    "MSG_SUSPEND_CMD_EVT",
+    "MSG_DISCOVER_RSP_EVT",
+    "MSG_GETCAP_RSP_EVT",
+    "MSG_START_RSP_EVT",
+    "MSG_SUSPEND_RSP_EVT",
+    "RCVRSP_EVT",
+    "SENDMSG_EVT",
+    "RET_TOUT_EVT",
+    "RSP_TOUT_EVT",
+    "IDLE_TOUT_EVT",
+    "UL_OPEN_EVT",
+    "UL_CLOSE_EVT",
+    "LL_OPEN_EVT",
+    "LL_CLOSE_EVT",
+    "LL_CONG_EVT"
+};
+
+#endif
+
+
+/* action function list */
+const tAVDT_CCB_ACTION avdt_ccb_action[] = {
+    avdt_ccb_chan_open,
+    avdt_ccb_chan_close,
+    avdt_ccb_chk_close,
+    avdt_ccb_hdl_discover_cmd,
+    avdt_ccb_hdl_discover_rsp,
+    avdt_ccb_hdl_getcap_cmd,
+    avdt_ccb_hdl_getcap_rsp,
+    avdt_ccb_hdl_start_cmd,
+    avdt_ccb_hdl_start_rsp,
+    avdt_ccb_hdl_suspend_cmd,
+    avdt_ccb_hdl_suspend_rsp,
+    avdt_ccb_snd_discover_cmd,
+    avdt_ccb_snd_discover_rsp,
+    avdt_ccb_snd_getcap_cmd,
+    avdt_ccb_snd_getcap_rsp,
+    avdt_ccb_snd_start_cmd,
+    avdt_ccb_snd_start_rsp,
+    avdt_ccb_snd_suspend_cmd,
+    avdt_ccb_snd_suspend_rsp,
+    avdt_ccb_clear_cmds,
+    avdt_ccb_cmd_fail,
+    avdt_ccb_free_cmd,
+    avdt_ccb_cong_state,
+    avdt_ccb_ret_cmd,
+    avdt_ccb_snd_cmd,
+    avdt_ccb_snd_msg,
+    avdt_ccb_set_reconn,
+    avdt_ccb_clr_reconn,
+    avdt_ccb_chk_reconn,
+    avdt_ccb_chk_timer,
+    avdt_ccb_set_conn,
+    avdt_ccb_set_disconn,
+    avdt_ccb_do_disconn,
+    avdt_ccb_ll_closed,
+    avdt_ccb_ll_opened,
+    avdt_ccb_dealloc
+};
+
+/* state table information */
+#define AVDT_CCB_ACTIONS            2       /* number of actions */
+#define AVDT_CCB_NEXT_STATE         2       /* position of next state */
+#define AVDT_CCB_NUM_COLS           3       /* number of columns in state tables */
+
+/* state table for idle state */
+const uint8_t avdt_ccb_st_idle[][AVDT_CCB_NUM_COLS] = {
+/* Event                      Action 1                    Action 2                    Next state */
+/* API_DISCOVER_REQ_EVT */   {AVDT_CCB_SND_DISCOVER_CMD,  AVDT_CCB_CHAN_OPEN,         AVDT_CCB_OPENING_ST},
+/* API_GETCAP_REQ_EVT */     {AVDT_CCB_SND_GETCAP_CMD,    AVDT_CCB_CHAN_OPEN,         AVDT_CCB_OPENING_ST},
+/* API_START_REQ_EVT */      {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* API_SUSPEND_REQ_EVT */    {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* API_DISCOVER_RSP_EVT */   {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* API_GETCAP_RSP_EVT */     {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* API_START_RSP_EVT */      {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* API_SUSPEND_RSP_EVT */    {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* API_CONNECT_REQ_EVT */    {AVDT_CCB_SET_CONN,          AVDT_CCB_CHAN_OPEN,         AVDT_CCB_OPENING_ST},
+/* API_DISCONNECT_REQ_EVT */ {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* MSG_DISCOVER_CMD_EVT */   {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* MSG_GETCAP_CMD_EVT */     {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* MSG_START_CMD_EVT */      {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* MSG_SUSPEND_CMD_EVT */    {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* MSG_DISCOVER_RSP_EVT */   {AVDT_CCB_HDL_DISCOVER_RSP,  AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* MSG_GETCAP_RSP_EVT */     {AVDT_CCB_HDL_GETCAP_RSP,    AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* MSG_START_RSP_EVT */      {AVDT_CCB_HDL_START_RSP,     AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* MSG_SUSPEND_RSP_EVT */    {AVDT_CCB_HDL_SUSPEND_RSP,   AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* RCVRSP_EVT */             {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* SENDMSG_EVT */            {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* RET_TOUT_EVT */           {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* RSP_TOUT_EVT */           {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* IDLE_TOUT_EVT */          {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* UL_OPEN_EVT */            {AVDT_CCB_CHAN_OPEN,         AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* UL_CLOSE_EVT */           {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* LL_OPEN_EVT */            {AVDT_CCB_LL_OPENED,         AVDT_CCB_IGNORE,            AVDT_CCB_OPEN_ST},
+/* LL_CLOSE_EVT */           {AVDT_CCB_LL_CLOSED,         AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* LL_CONG_EVT */            {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST}
+};
+
+/* state table for opening state */
+const uint8_t avdt_ccb_st_opening[][AVDT_CCB_NUM_COLS] = {
+/* Event                      Action 1                    Action 2                    Next state */
+/* API_DISCOVER_REQ_EVT */   {AVDT_CCB_SND_DISCOVER_CMD,  AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* API_GETCAP_REQ_EVT */     {AVDT_CCB_SND_GETCAP_CMD,    AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* API_START_REQ_EVT */      {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* API_SUSPEND_REQ_EVT */    {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* API_DISCOVER_RSP_EVT */   {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* API_GETCAP_RSP_EVT */     {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* API_START_RSP_EVT */      {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* API_SUSPEND_RSP_EVT */    {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* API_CONNECT_REQ_EVT */    {AVDT_CCB_SET_CONN,          AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* API_DISCONNECT_REQ_EVT */ {AVDT_CCB_SET_DISCONN,       AVDT_CCB_DO_DISCONN,        AVDT_CCB_CLOSING_ST},
+/* MSG_DISCOVER_CMD_EVT */   {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* MSG_GETCAP_CMD_EVT */     {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* MSG_START_CMD_EVT */      {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* MSG_SUSPEND_CMD_EVT */    {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* MSG_DISCOVER_RSP_EVT */   {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* MSG_GETCAP_RSP_EVT */     {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* MSG_START_RSP_EVT */      {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* MSG_SUSPEND_RSP_EVT */    {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* RCVRSP_EVT */             {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* SENDMSG_EVT */            {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* RET_TOUT_EVT */           {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* RSP_TOUT_EVT */           {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* IDLE_TOUT_EVT */          {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* UL_OPEN_EVT */            {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST},
+/* UL_CLOSE_EVT */           {AVDT_CCB_CLEAR_CMDS,        AVDT_CCB_CHAN_CLOSE,        AVDT_CCB_CLOSING_ST},
+/* LL_OPEN_EVT */            {AVDT_CCB_SND_CMD,           AVDT_CCB_LL_OPENED,         AVDT_CCB_OPEN_ST},
+/* LL_CLOSE_EVT */           {AVDT_CCB_LL_CLOSED,         AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* LL_CONG_EVT */            {AVDT_CCB_CONG_STATE,        AVDT_CCB_IGNORE,            AVDT_CCB_OPENING_ST}
+};
+
+/* state table for open state */
+const uint8_t avdt_ccb_st_open[][AVDT_CCB_NUM_COLS] = {
+/* Event                      Action 1                    Action 2                    Next state */
+/* API_DISCOVER_REQ_EVT */   {AVDT_CCB_SND_DISCOVER_CMD,  AVDT_CCB_SND_CMD,           AVDT_CCB_OPEN_ST},
+/* API_GETCAP_REQ_EVT */     {AVDT_CCB_SND_GETCAP_CMD,    AVDT_CCB_SND_CMD,           AVDT_CCB_OPEN_ST},
+/* API_START_REQ_EVT */      {AVDT_CCB_SND_START_CMD,     AVDT_CCB_SND_CMD,           AVDT_CCB_OPEN_ST},
+/* API_SUSPEND_REQ_EVT */    {AVDT_CCB_SND_SUSPEND_CMD,   AVDT_CCB_SND_CMD,           AVDT_CCB_OPEN_ST},
+/* API_DISCOVER_RSP_EVT */   {AVDT_CCB_SND_DISCOVER_RSP,  AVDT_CCB_SND_CMD,           AVDT_CCB_OPEN_ST},
+/* API_GETCAP_RSP_EVT */     {AVDT_CCB_SND_GETCAP_RSP,    AVDT_CCB_SND_CMD,           AVDT_CCB_OPEN_ST},
+/* API_START_RSP_EVT */      {AVDT_CCB_SND_START_RSP,     AVDT_CCB_SND_CMD,           AVDT_CCB_OPEN_ST},
+/* API_SUSPEND_RSP_EVT */    {AVDT_CCB_SND_SUSPEND_RSP,   AVDT_CCB_SND_CMD,           AVDT_CCB_OPEN_ST},
+/* API_CONNECT_REQ_EVT */    {AVDT_CCB_SET_CONN,          AVDT_CCB_LL_OPENED,         AVDT_CCB_OPEN_ST},
+/* API_DISCONNECT_REQ_EVT */ {AVDT_CCB_SET_DISCONN,       AVDT_CCB_DO_DISCONN,        AVDT_CCB_CLOSING_ST},
+/* MSG_DISCOVER_CMD_EVT */   {AVDT_CCB_HDL_DISCOVER_CMD,  AVDT_CCB_IGNORE,            AVDT_CCB_OPEN_ST},
+/* MSG_GETCAP_CMD_EVT */     {AVDT_CCB_HDL_GETCAP_CMD,    AVDT_CCB_IGNORE,            AVDT_CCB_OPEN_ST},
+/* MSG_START_CMD_EVT */      {AVDT_CCB_HDL_START_CMD,     AVDT_CCB_IGNORE,            AVDT_CCB_OPEN_ST},
+/* MSG_SUSPEND_CMD_EVT */    {AVDT_CCB_HDL_SUSPEND_CMD,   AVDT_CCB_IGNORE,            AVDT_CCB_OPEN_ST},
+/* MSG_DISCOVER_RSP_EVT */   {AVDT_CCB_CHK_CLOSE,         AVDT_CCB_HDL_DISCOVER_RSP,  AVDT_CCB_OPEN_ST},
+/* MSG_GETCAP_RSP_EVT */     {AVDT_CCB_CHK_CLOSE,         AVDT_CCB_HDL_GETCAP_RSP,    AVDT_CCB_OPEN_ST},
+/* MSG_START_RSP_EVT */      {AVDT_CCB_HDL_START_RSP,     AVDT_CCB_IGNORE,            AVDT_CCB_OPEN_ST},
+/* MSG_SUSPEND_RSP_EVT */    {AVDT_CCB_HDL_SUSPEND_RSP,   AVDT_CCB_IGNORE,            AVDT_CCB_OPEN_ST},
+/* RCVRSP_EVT */             {AVDT_CCB_FREE_CMD,          AVDT_CCB_SND_CMD,           AVDT_CCB_OPEN_ST},
+/* SENDMSG_EVT */            {AVDT_CCB_SND_MSG,           AVDT_CCB_IGNORE,            AVDT_CCB_OPEN_ST},
+/* RET_TOUT_EVT */           {AVDT_CCB_RET_CMD,           AVDT_CCB_IGNORE,            AVDT_CCB_OPEN_ST},
+/* RSP_TOUT_EVT */           {AVDT_CCB_CMD_FAIL,          AVDT_CCB_SND_CMD,           AVDT_CCB_OPEN_ST},
+/* IDLE_TOUT_EVT */          {AVDT_CCB_CLEAR_CMDS,        AVDT_CCB_CHAN_CLOSE,        AVDT_CCB_CLOSING_ST},
+/* UL_OPEN_EVT */            {AVDT_CCB_CHK_TIMER,         AVDT_CCB_IGNORE,            AVDT_CCB_OPEN_ST},
+/* UL_CLOSE_EVT */           {AVDT_CCB_CHK_CLOSE,         AVDT_CCB_IGNORE,            AVDT_CCB_OPEN_ST},
+/* LL_OPEN_EVT */            {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_OPEN_ST},
+/* LL_CLOSE_EVT */           {AVDT_CCB_LL_CLOSED,         AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* LL_CONG_EVT */            {AVDT_CCB_CONG_STATE,        AVDT_CCB_SND_MSG,           AVDT_CCB_OPEN_ST}
+};
+
+/* state table for closing state */
+const uint8_t avdt_ccb_st_closing[][AVDT_CCB_NUM_COLS] = {
+/* Event                      Action 1                    Action 2                    Next state */
+/* API_DISCOVER_REQ_EVT */   {AVDT_CCB_SET_RECONN,        AVDT_CCB_SND_DISCOVER_CMD,  AVDT_CCB_CLOSING_ST},
+/* API_GETCAP_REQ_EVT */     {AVDT_CCB_SET_RECONN,        AVDT_CCB_SND_GETCAP_CMD,    AVDT_CCB_CLOSING_ST},
+/* API_START_REQ_EVT */      {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* API_SUSPEND_REQ_EVT */    {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* API_DISCOVER_RSP_EVT */   {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* API_GETCAP_RSP_EVT */     {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* API_START_RSP_EVT */      {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* API_SUSPEND_RSP_EVT */    {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* API_CONNECT_REQ_EVT */    {AVDT_CCB_SET_RECONN,        AVDT_CCB_SET_CONN,          AVDT_CCB_CLOSING_ST},
+/* API_DISCONNECT_REQ_EVT */ {AVDT_CCB_CLR_RECONN,        AVDT_CCB_SET_DISCONN,       AVDT_CCB_CLOSING_ST},
+/* MSG_DISCOVER_CMD_EVT */   {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* MSG_GETCAP_CMD_EVT */     {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* MSG_START_CMD_EVT */      {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* MSG_SUSPEND_CMD_EVT */    {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* MSG_DISCOVER_RSP_EVT */   {AVDT_CCB_HDL_DISCOVER_RSP,  AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* MSG_GETCAP_RSP_EVT */     {AVDT_CCB_HDL_GETCAP_RSP,    AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* MSG_START_RSP_EVT */      {AVDT_CCB_HDL_START_RSP,     AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* MSG_SUSPEND_RSP_EVT */    {AVDT_CCB_HDL_SUSPEND_RSP,   AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* RCVRSP_EVT */             {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* SENDMSG_EVT */            {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* RET_TOUT_EVT */           {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* RSP_TOUT_EVT */           {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* IDLE_TOUT_EVT */          {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* UL_OPEN_EVT */            {AVDT_CCB_SET_RECONN,        AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* UL_CLOSE_EVT */           {AVDT_CCB_CLR_RECONN,        AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* LL_OPEN_EVT */            {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST},
+/* LL_CLOSE_EVT */           {AVDT_CCB_CHK_RECONN,        AVDT_CCB_IGNORE,            AVDT_CCB_IDLE_ST},
+/* LL_CONG_EVT */            {AVDT_CCB_IGNORE,            AVDT_CCB_IGNORE,            AVDT_CCB_CLOSING_ST}
+};
+
+/* type for state table */
+typedef const uint8_t (*tAVDT_CCB_ST_TBL)[AVDT_CCB_NUM_COLS];
+
+/* state table */
+const tAVDT_CCB_ST_TBL avdt_ccb_st_tbl[] = {
+    avdt_ccb_st_idle,
+    avdt_ccb_st_opening,
+    avdt_ccb_st_open,
+    avdt_ccb_st_closing
+};
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_init
+**
+** Description      Initialize channel control block module.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_ccb_init(void)
+{
+    memset(&avdt_cb.ccb[0], 0, sizeof(tAVDT_CCB) * AVDT_NUM_LINKS);
+    avdt_cb.p_ccb_act = (tAVDT_CCB_ACTION *) avdt_ccb_action;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_event
+**
+** Description      State machine event handling function for ccb
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_ccb_event(tAVDT_CCB *p_ccb, uint8_t event, tAVDT_CCB_EVT *p_data)
+{
+    tAVDT_CCB_ST_TBL    state_table;
+    uint8_t             action;
+    int                 i;
+
+#if (AVDT_DEBUG == TRUE)
+    AVDT_TRACE_EVENT("CCB ccb=%d event=%s state=%s", avdt_ccb_to_idx(p_ccb), avdt_ccb_evt_str[event], avdt_ccb_st_str[p_ccb->state]);
+#endif
+
+    /* look up the state table for the current state */
+    state_table = avdt_ccb_st_tbl[p_ccb->state];
+
+    /* set next state */
+    if (p_ccb->state != state_table[event][AVDT_CCB_NEXT_STATE]) {
+        p_ccb->state = state_table[event][AVDT_CCB_NEXT_STATE];
+    }
+
+    /* execute action functions */
+    for (i = 0; i < AVDT_CCB_ACTIONS; i++)
+    {
+        if ((action = state_table[event][i]) != AVDT_CCB_IGNORE)
+        {
+            (*avdt_cb.p_ccb_act[action])(p_ccb, p_data);
+        }
+        else
+        {
+            break;
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_by_bd
+**
+** Description      This lookup function finds the ccb for a BD address.
+**
+**
+** Returns          pointer to the ccb, or NULL if none found.
+**
+*******************************************************************************/
+tAVDT_CCB *avdt_ccb_by_bd(BD_ADDR bd_addr)
+{
+    tAVDT_CCB   *p_ccb = &avdt_cb.ccb[0];
+    int         i;
+
+    for (i = 0; i < AVDT_NUM_LINKS; i++, p_ccb++)
+    {
+        /* if allocated ccb has matching ccb */
+        if (p_ccb->allocated && (!memcmp(p_ccb->peer_addr, bd_addr, BD_ADDR_LEN)))
+        {
+            break;
+        }
+    }
+
+    if (i == AVDT_NUM_LINKS)
+    {
+        /* if no ccb found */
+        p_ccb = NULL;
+
+        AVDT_TRACE_DEBUG("No ccb for addr %02x-%02x-%02x-%02x-%02x-%02x",
+                          bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+    }
+    return p_ccb;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_alloc
+**
+** Description      Allocate a channel control block.
+**
+**
+** Returns          pointer to the ccb, or NULL if none could be allocated.
+**
+*******************************************************************************/
+tAVDT_CCB *avdt_ccb_alloc(BD_ADDR bd_addr)
+{
+    tAVDT_CCB   *p_ccb = &avdt_cb.ccb[0];
+    int         i;
+
+    for (i = 0; i < AVDT_NUM_LINKS; i++, p_ccb++)
+    {
+        if (!p_ccb->allocated)
+        {
+            p_ccb->allocated = true;
+            memcpy(p_ccb->peer_addr, bd_addr, BD_ADDR_LEN);
+            p_ccb->cmd_q = fixed_queue_new(SIZE_MAX);
+            p_ccb->rsp_q = fixed_queue_new(SIZE_MAX);
+            p_ccb->idle_ccb_timer = alarm_new("avdt_ccb.idle_ccb_timer");
+            p_ccb->ret_ccb_timer = alarm_new("avdt_ccb.ret_ccb_timer");
+            p_ccb->rsp_ccb_timer = alarm_new("avdt_ccb.rsp_ccb_timer");
+            AVDT_TRACE_DEBUG("avdt_ccb_alloc %d", i);
+            break;
+        }
+    }
+
+    if (i == AVDT_NUM_LINKS)
+    {
+        /* out of ccbs */
+        p_ccb = NULL;
+        AVDT_TRACE_WARNING("Out of ccbs");
+    }
+    return p_ccb;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_dealloc
+**
+** Description      Deallocate a stream control block.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_dealloc(tAVDT_CCB *p_ccb,
+                      UNUSED_ATTR tAVDT_CCB_EVT *p_data)
+{
+    AVDT_TRACE_DEBUG("avdt_ccb_dealloc %d", avdt_ccb_to_idx(p_ccb));
+    alarm_free(p_ccb->idle_ccb_timer);
+    alarm_free(p_ccb->ret_ccb_timer);
+    alarm_free(p_ccb->rsp_ccb_timer);
+    fixed_queue_free(p_ccb->cmd_q, NULL);
+    fixed_queue_free(p_ccb->rsp_q, NULL);
+    memset(p_ccb, 0, sizeof(tAVDT_CCB));
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_to_idx
+**
+** Description      Given a pointer to an ccb, return its index.
+**
+**
+** Returns          Index of ccb.
+**
+*******************************************************************************/
+uint8_t avdt_ccb_to_idx(tAVDT_CCB *p_ccb)
+{
+    /* use array arithmetic to determine index */
+    return (uint8_t) (p_ccb - avdt_cb.ccb);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_by_idx
+**
+** Description      Return ccb pointer based on ccb index.
+**
+**
+** Returns          pointer to the ccb, or NULL if none found.
+**
+*******************************************************************************/
+tAVDT_CCB *avdt_ccb_by_idx(uint8_t idx)
+{
+    tAVDT_CCB   *p_ccb;
+
+    /* verify index */
+    if (idx < AVDT_NUM_LINKS)
+    {
+        p_ccb = &avdt_cb.ccb[idx];
+    }
+    else
+    {
+        p_ccb = NULL;
+        AVDT_TRACE_WARNING("No ccb for idx %d", idx);
+    }
+    return p_ccb;
+}
+
diff --git a/bt/stack/avdt/avdt_ccb_act.cc b/bt/stack/avdt/avdt_ccb_act.cc
new file mode 100644
index 0000000..2ed2294
--- /dev/null
+++ b/bt/stack/avdt/avdt_ccb_act.cc
@@ -0,0 +1,1111 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2006-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 module contains the action functions associated with the channel
+ *  control block state machine.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "bt_common.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "osi/include/osi.h"
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_clear_ccb
+**
+** Description      This function clears out certain buffers, queues, and
+**                  other data elements of a ccb.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+static void avdt_ccb_clear_ccb(tAVDT_CCB *p_ccb)
+{
+    BT_HDR          *p_buf;
+
+    /* clear certain ccb variables */
+    p_ccb->cong = false;
+    p_ccb->ret_count = 0;
+
+    /* free message being fragmented */
+    osi_free_and_reset((void **)&p_ccb->p_curr_msg);
+
+    /* free message being reassembled */
+    osi_free_and_reset((void **)&p_ccb->p_rx_msg);
+
+    /* clear out response queue */
+    while ((p_buf = (BT_HDR *) fixed_queue_try_dequeue(p_ccb->rsp_q)) != NULL)
+        osi_free(p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_chan_open
+**
+** Description      This function calls avdt_ad_open_req() to
+**                  initiate a signaling channel connection.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_chan_open(tAVDT_CCB *p_ccb,
+                        UNUSED_ATTR tAVDT_CCB_EVT *p_data)
+{
+    BTM_SetOutService(p_ccb->peer_addr, BTM_SEC_SERVICE_AVDTP, AVDT_CHAN_SIG);
+    avdt_ad_open_req(AVDT_CHAN_SIG, p_ccb, NULL, AVDT_INT);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_chan_close
+**
+** Description      This function calls avdt_ad_close_req() to close a
+**                  signaling channel connection.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_chan_close(tAVDT_CCB *p_ccb,
+                         UNUSED_ATTR tAVDT_CCB_EVT *p_data)
+{
+    /* close the transport channel used by this CCB */
+    avdt_ad_close_req(AVDT_CHAN_SIG, p_ccb, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_chk_close
+**
+** Description      This function checks for active streams on this CCB.
+**                  If there are none, it starts an idle timer.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_chk_close(tAVDT_CCB *p_ccb,
+                        UNUSED_ATTR tAVDT_CCB_EVT *p_data)
+{
+    int         i;
+    tAVDT_SCB   *p_scb = &avdt_cb.scb[0];
+
+    /* see if there are any active scbs associated with this ccb */
+    for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
+    {
+        if ((p_scb->allocated) && (p_scb->p_ccb == p_ccb))
+        {
+            break;
+        }
+    }
+
+    /* if no active scbs start idle timer */
+    if (i == AVDT_NUM_SEPS)
+    {
+        alarm_cancel(p_ccb->ret_ccb_timer);
+        alarm_cancel(p_ccb->rsp_ccb_timer);
+        period_ms_t interval_ms = avdt_cb.rcb.idle_tout * 1000;
+        alarm_set_on_queue(p_ccb->idle_ccb_timer, interval_ms,
+                           avdt_ccb_idle_ccb_timer_timeout, p_ccb,
+                           btu_general_alarm_queue);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_hdl_discover_cmd
+**
+** Description      This function is called when a discover command is
+**                  received from the peer.  It gathers up the stream
+**                  information for all allocated streams and initiates
+**                  sending of a discover response.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    tAVDT_SEP_INFO      sep_info[AVDT_NUM_SEPS];
+    tAVDT_SCB           *p_scb = &avdt_cb.scb[0];
+    int                 i;
+
+    p_data->msg.discover_rsp.p_sep_info = sep_info;
+    p_data->msg.discover_rsp.num_seps = 0;
+
+    /* for all allocated scbs */
+    for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
+    {
+        if (p_scb->allocated)
+        {
+            /* copy sep info */
+            sep_info[p_data->msg.discover_rsp.num_seps].in_use = p_scb->in_use;
+            sep_info[p_data->msg.discover_rsp.num_seps].seid = i + 1;
+            sep_info[p_data->msg.discover_rsp.num_seps].media_type = p_scb->cs.media_type;
+            sep_info[p_data->msg.discover_rsp.num_seps].tsep = p_scb->cs.tsep;
+
+            p_data->msg.discover_rsp.num_seps++;
+        }
+    }
+
+    /* send response */
+    avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCOVER_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_hdl_discover_rsp
+**
+** Description      This function is called when a discover response or
+**                  reject is received from the peer.  It calls the application
+**                  callback function with the results.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    /* we're done with procedure */
+    p_ccb->proc_busy = false;
+
+    /* call app callback with results */
+    (*p_ccb->proc_cback)(0, p_ccb->peer_addr, AVDT_DISCOVER_CFM_EVT,
+                         (tAVDT_CTRL *)(&p_data->msg.discover_rsp));
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_hdl_getcap_cmd
+**
+** Description      This function is called when a get capabilities command
+**                  is received from the peer.  It retrieves the stream
+**                  configuration for the requested stream and initiates
+**                  sending of a get capabilities response.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    tAVDT_SCB       *p_scb;
+
+    /* look up scb for seid sent to us */
+    p_scb = avdt_scb_by_hdl(p_data->msg.single.seid);
+
+    p_data->msg.svccap.p_cfg = &p_scb->cs.cfg;
+
+    avdt_ccb_event(p_ccb, AVDT_CCB_API_GETCAP_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_hdl_getcap_rsp
+**
+** Description      This function is called with a get capabilities response
+**                  or reject is received from the peer.  It calls the
+**                  application callback function with the results.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    /* we're done with procedure */
+    p_ccb->proc_busy = false;
+
+    /* call app callback with results */
+    (*p_ccb->proc_cback)(0, p_ccb->peer_addr, AVDT_GETCAP_CFM_EVT,
+                         (tAVDT_CTRL *)(&p_data->msg.svccap));
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_hdl_start_cmd
+**
+** Description      This function is called when a start command is received
+**                  from the peer.  It verifies that all requested streams
+**                  are in the proper state.  If so, it initiates sending of
+**                  a start response.  Otherwise it sends a start reject.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    uint8_t err_code = 0;
+
+    /* verify all streams in the right state */
+    uint8_t seid = avdt_scb_verify(p_ccb, AVDT_VERIFY_START, p_data->msg.multi.seid_list,
+                                 p_data->msg.multi.num_seps, &err_code);
+    if (seid == 0 && err_code == 0)
+    {
+        /* we're ok, send response */
+        avdt_ccb_event(p_ccb, AVDT_CCB_API_START_RSP_EVT, p_data);
+    } else {
+        /* not ok, send reject */
+        p_data->msg.hdr.err_code = err_code;
+        p_data->msg.hdr.err_param = seid;
+        avdt_msg_send_rej(p_ccb, AVDT_SIG_START, &p_data->msg);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_hdl_start_rsp
+**
+** Description      This function is called when a start response or reject
+**                  is received from the peer.  Using the SEIDs stored in the
+**                  current command message, it sends a start response or start
+**                  reject event to each SCB associated with the command.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_start_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    uint8_t     event;
+    int         i;
+    uint8_t     *p;
+    tAVDT_SCB   *p_scb;
+
+    /* determine rsp or rej event */
+    event = (p_data->msg.hdr.err_code == 0) ?
+            AVDT_SCB_MSG_START_RSP_EVT : AVDT_SCB_MSG_START_REJ_EVT;
+
+    /* get to where seid's are stashed in current cmd */
+    p = (uint8_t *)(p_ccb->p_curr_cmd + 1);
+
+    /* little trick here; length of current command equals number of streams */
+    for (i = 0; i < p_ccb->p_curr_cmd->len; i++)
+    {
+        if ((p_scb = avdt_scb_by_hdl(p[i])) != NULL)
+        {
+            avdt_scb_event(p_scb, event, (tAVDT_SCB_EVT *) &p_data->msg);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_hdl_suspend_cmd
+**
+** Description      This function is called when a suspend command is received
+**                  from the peer.  It verifies that all requested streams are
+**                  in the proper state.  If so, it initiates sending of a
+**                  suspend response.  Otherwise it sends a suspend reject.
+
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    uint8_t seid;
+    uint8_t err_code = 0;
+
+    /* verify all streams in the right state */
+    if ((seid = avdt_scb_verify(p_ccb, AVDT_VERIFY_SUSPEND, p_data->msg.multi.seid_list,
+                                p_data->msg.multi.num_seps, &err_code)) == 0 &&
+                                err_code == 0)
+    {
+        /* we're ok, send response */
+        avdt_ccb_event(p_ccb, AVDT_CCB_API_SUSPEND_RSP_EVT, p_data);
+    }
+    else
+    {
+        /* not ok, send reject */
+        p_data->msg.hdr.err_code = err_code;
+        p_data->msg.hdr.err_param = seid;
+        avdt_msg_send_rej(p_ccb, AVDT_SIG_SUSPEND, &p_data->msg);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_hdl_suspend_rsp
+**
+** Description      This function is called when a suspend response or reject
+**                  is received from the peer.  Using the SEIDs stored in the
+**                  current command message, it sends a suspend response or
+**                  suspend reject event to each SCB associated with the command.
+**
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_hdl_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    uint8_t     event;
+    int         i;
+    uint8_t     *p;
+    tAVDT_SCB   *p_scb;
+
+    /* determine rsp or rej event */
+    event = (p_data->msg.hdr.err_code == 0) ?
+            AVDT_SCB_MSG_SUSPEND_RSP_EVT : AVDT_SCB_MSG_SUSPEND_REJ_EVT;
+
+    /* get to where seid's are stashed in current cmd */
+    p = (uint8_t *)(p_ccb->p_curr_cmd + 1);
+
+    /* little trick here; length of current command equals number of streams */
+    for (i = 0; i < p_ccb->p_curr_cmd->len; i++)
+    {
+        if ((p_scb = avdt_scb_by_hdl(p[i])) != NULL)
+        {
+            avdt_scb_event(p_scb, event, (tAVDT_SCB_EVT *) &p_data->msg);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_snd_discover_cmd
+**
+** Description      This function is called to send a discover command to the
+**                  peer.  It copies variables needed for the procedure from
+**                  the event to the CCB.  It marks the CCB as busy and then
+**                  sends a discover command.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    /* store info in ccb struct */
+    p_ccb->p_proc_data = p_data->discover.p_sep_info;
+    p_ccb->proc_cback = p_data->discover.p_cback;
+    p_ccb->proc_param = p_data->discover.num_seps;
+
+    /* we're busy */
+    p_ccb->proc_busy = true;
+
+    /* build and queue discover req */
+    avdt_msg_send_cmd(p_ccb, NULL, AVDT_SIG_DISCOVER, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_snd_discover_rsp
+**
+** Description      This function is called to send a discover response to
+**                  the peer.  It takes the stream information passed in the
+**                  event and sends a discover response.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    /* send response */
+    avdt_msg_send_rsp(p_ccb, AVDT_SIG_DISCOVER, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_snd_getcap_cmd
+**
+** Description      This function is called to send a get capabilities command
+**                  to the peer.  It copies variables needed for the procedure
+**                  from the event to the CCB.  It marks the CCB as busy and
+**                  then sends a get capabilities command.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    uint8_t sig_id = AVDT_SIG_GETCAP;
+
+    /* store info in ccb struct */
+    p_ccb->p_proc_data = p_data->getcap.p_cfg;
+    p_ccb->proc_cback = p_data->getcap.p_cback;
+
+    /* we're busy */
+    p_ccb->proc_busy = true;
+
+    /* build and queue discover req */
+    if (p_data->msg.hdr.sig_id == AVDT_SIG_GET_ALLCAP)
+        sig_id = AVDT_SIG_GET_ALLCAP;
+
+    avdt_msg_send_cmd(p_ccb, NULL, sig_id, (tAVDT_MSG *) &p_data->getcap.single);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_snd_getcap_rsp
+**
+** Description      This function is called to send a get capabilities response
+**                  to the peer.  It takes the stream information passed in the
+**                  event and sends a get capabilities response.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    uint8_t sig_id = AVDT_SIG_GETCAP;
+
+    if (p_data->msg.hdr.sig_id == AVDT_SIG_GET_ALLCAP)
+        sig_id = AVDT_SIG_GET_ALLCAP;
+
+    /* send response */
+    avdt_msg_send_rsp(p_ccb, sig_id, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_snd_start_cmd
+**
+** Description      This function is called to send a start command to the
+**                  peer.  It verifies that all requested streams are in the
+**                  proper state.  If so, it sends a start command.  Otherwise
+**                  send ourselves back a start reject.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    int             i;
+    tAVDT_SCB       *p_scb;
+    tAVDT_MSG       avdt_msg;
+    uint8_t         seid_list[AVDT_NUM_SEPS];
+
+    /* make copy of our seid list */
+    memcpy(seid_list, p_data->msg.multi.seid_list, p_data->msg.multi.num_seps);
+
+    /* verify all streams in the right state */
+    if ((avdt_msg.hdr.err_param = avdt_scb_verify(p_ccb, AVDT_VERIFY_OPEN, p_data->msg.multi.seid_list,
+                                         p_data->msg.multi.num_seps, &avdt_msg.hdr.err_code)) == 0)
+    {
+        /* set peer seid list in messsage */
+        avdt_scb_peer_seid_list(&p_data->msg.multi);
+
+        /* send command */
+        avdt_msg_send_cmd(p_ccb, seid_list, AVDT_SIG_START, &p_data->msg);
+    }
+    else
+    {
+        /* failed; send ourselves a reject for each stream */
+        for (i = 0; i < p_data->msg.multi.num_seps; i++)
+        {
+            if ((p_scb = avdt_scb_by_hdl(seid_list[i])) != NULL)
+            {
+                avdt_scb_event(p_scb, AVDT_SCB_MSG_START_REJ_EVT, (tAVDT_SCB_EVT *) &avdt_msg.hdr);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_snd_start_rsp
+**
+** Description      This function is called to send a start response to the
+**                  peer.  It takes the stream information passed in the event
+**                  and sends a start response.  Then it sends a start event
+**                  to the SCB for each stream.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_start_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    tAVDT_SCB *p_scb;
+    int i;
+
+    /* send response message */
+    avdt_msg_send_rsp(p_ccb, AVDT_SIG_START, &p_data->msg);
+
+    /* send start event to each scb */
+    for (i = 0; i < p_data->msg.multi.num_seps; i++)
+    {
+        if ((p_scb = avdt_scb_by_hdl(p_data->msg.multi.seid_list[i])) != NULL)
+        {
+            avdt_scb_event(p_scb, AVDT_SCB_MSG_START_CMD_EVT, NULL);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_snd_suspend_cmd
+**
+** Description      This function is called to send a suspend command to the
+**                  peer.  It verifies that all requested streams are in the
+**                  proper state.  If so, it sends a suspend command.
+**                  Otherwise it calls the callback function for each requested
+**                  stream and sends a suspend confirmation with failure.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    int             i;
+    tAVDT_SCB       *p_scb;
+    tAVDT_MSG       avdt_msg;
+    uint8_t         seid_list[AVDT_NUM_SEPS];
+
+    /* make copy of our seid list */
+    memcpy(seid_list, p_data->msg.multi.seid_list, p_data->msg.multi.num_seps);
+
+    /* verify all streams in the right state */
+    if ((avdt_msg.hdr.err_param = avdt_scb_verify(p_ccb, AVDT_VERIFY_STREAMING, p_data->msg.multi.seid_list,
+                                         p_data->msg.multi.num_seps, &avdt_msg.hdr.err_code)) == 0)
+    {
+        /* set peer seid list in messsage */
+        avdt_scb_peer_seid_list(&p_data->msg.multi);
+
+        /* send command */
+        avdt_msg_send_cmd(p_ccb, seid_list, AVDT_SIG_SUSPEND, &p_data->msg);
+    }
+    else
+    {
+        /* failed; send ourselves a reject for each stream */
+        for (i = 0; i < p_data->msg.multi.num_seps; i++)
+        {
+            if ((p_scb = avdt_scb_by_hdl(seid_list[i])) != NULL)
+            {
+                avdt_scb_event(p_scb, AVDT_SCB_MSG_SUSPEND_REJ_EVT, (tAVDT_SCB_EVT *) &avdt_msg.hdr);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_snd_suspend_rsp
+**
+** Description      This function is called to send a suspend response to the
+**                  peer.  It takes the stream information passed in the event
+**                  and sends a suspend response.  Then it sends a suspend event
+**                  to the SCB for each stream.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    tAVDT_SCB *p_scb;
+    int i;
+
+    /* send response message */
+    avdt_msg_send_rsp(p_ccb, AVDT_SIG_SUSPEND, &p_data->msg);
+
+    /* send start event to each scb */
+    for (i = 0; i < p_data->msg.multi.num_seps; i++)
+    {
+        if ((p_scb = avdt_scb_by_hdl(p_data->msg.multi.seid_list[i])) != NULL)
+        {
+            avdt_scb_event(p_scb, AVDT_SCB_MSG_SUSPEND_CMD_EVT, NULL);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_clear_cmds
+**
+** Description      This function is called when the signaling channel is
+**                  closed to clean up any pending commands.  For each pending
+**                  command in the command queue, it frees the command and
+**                  calls the application callback function indicating failure.
+**                  Certain CCB variables are also initialized.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_clear_cmds(tAVDT_CCB *p_ccb,
+                         UNUSED_ATTR tAVDT_CCB_EVT *p_data)
+{
+    int             i;
+    tAVDT_SCB       *p_scb = &avdt_cb.scb[0];
+    uint8_t         err_code = AVDT_ERR_CONNECT;
+
+    /* clear the ccb */
+    avdt_ccb_clear_ccb(p_ccb);
+
+    /* clear out command queue; this is a little tricky here; we need
+    ** to handle the case where there is a command on deck in p_curr_cmd,
+    ** plus we need to clear out the queue
+    */
+    do
+    {
+        /* we know p_curr_cmd = NULL after this */
+        avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT *) &err_code);
+
+        /* set up next message */
+        p_ccb->p_curr_cmd = (BT_HDR *) fixed_queue_try_dequeue(p_ccb->cmd_q);
+
+    } while (p_ccb->p_curr_cmd != NULL);
+
+    /* send a CC_CLOSE_EVT any active scbs associated with this ccb */
+    for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
+    {
+        if ((p_scb->allocated) && (p_scb->p_ccb == p_ccb))
+        {
+            avdt_scb_event(p_scb, AVDT_SCB_CC_CLOSE_EVT, NULL);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_cmd_fail
+**
+** Description      This function is called when there is a response timeout.
+**                  The currently pending command is freed and we fake a
+**                  reject message back to ourselves.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_cmd_fail(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    tAVDT_MSG       msg;
+    uint8_t         evt;
+    tAVDT_SCB       *p_scb;
+
+    if (p_ccb->p_curr_cmd != NULL)
+    {
+        /* set up data */
+        msg.hdr.err_code = p_data->err_code;
+        msg.hdr.err_param = 0;
+        msg.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb);
+
+        /* pretend that we received a rej message */
+        evt = avdt_msg_rej_2_evt[p_ccb->p_curr_cmd->event - 1];
+
+        if (evt & AVDT_CCB_MKR)
+        {
+            avdt_ccb_event(p_ccb, (uint8_t) (evt & ~AVDT_CCB_MKR), (tAVDT_CCB_EVT *) &msg);
+        }
+        else
+        {
+            /* we get the scb out of the current cmd */
+            p_scb = avdt_scb_by_hdl(*((uint8_t *)(p_ccb->p_curr_cmd + 1)));
+            if (p_scb != NULL)
+            {
+                avdt_scb_event(p_scb, evt, (tAVDT_SCB_EVT *) &msg);
+            }
+        }
+
+        osi_free_and_reset((void **)&p_ccb->p_curr_cmd);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_free_cmd
+**
+** Description      This function is called when a response is received for a
+**                  currently pending command.  The command is freed.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_free_cmd(tAVDT_CCB *p_ccb,
+                       UNUSED_ATTR tAVDT_CCB_EVT *p_data)
+{
+    osi_free_and_reset((void **)&p_ccb->p_curr_cmd);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_cong_state
+**
+** Description      This function is called to set the congestion state for
+**                  the CCB.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_cong_state(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    p_ccb->cong = p_data->llcong;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_ret_cmd
+**
+** Description      This function is called to retransmit the currently
+**                  pending command.  The retransmission count is incremented.
+**                  If the count reaches the maximum number of retransmissions,
+**                  the event is treated as a response timeout.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_ret_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    uint8_t err_code = AVDT_ERR_TIMEOUT;
+
+    p_ccb->ret_count++;
+    if (p_ccb->ret_count == AVDT_RET_MAX)
+    {
+        /* command failed */
+        p_ccb->ret_count = 0;
+        avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT *) &err_code);
+
+        /* go to next queued command */
+        avdt_ccb_snd_cmd(p_ccb, p_data);
+    }
+    else
+    {
+        /* if command pending and we're not congested and not sending a fragment */
+        if ((!p_ccb->cong) && (p_ccb->p_curr_msg == NULL) && (p_ccb->p_curr_cmd != NULL))
+        {
+            /* make copy of message in p_curr_cmd and send it */
+            BT_HDR *p_msg = (BT_HDR *)osi_malloc(AVDT_CMD_BUF_SIZE);
+            memcpy(p_msg, p_ccb->p_curr_cmd,
+                   (sizeof(BT_HDR) + p_ccb->p_curr_cmd->offset + p_ccb->p_curr_cmd->len));
+            avdt_msg_send(p_ccb, p_msg);
+        }
+
+        /* restart ret timer */
+        alarm_cancel(p_ccb->idle_ccb_timer);
+        alarm_cancel(p_ccb->rsp_ccb_timer);
+        period_ms_t interval_ms = avdt_cb.rcb.ret_tout * 1000;
+        alarm_set_on_queue(p_ccb->ret_ccb_timer, interval_ms,
+                           avdt_ccb_ret_ccb_timer_timeout, p_ccb,
+                           btu_general_alarm_queue);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_snd_cmd
+**
+** Description      This function is called the send the next command,
+**                  if any, in the command queue.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_cmd(tAVDT_CCB *p_ccb,
+                      UNUSED_ATTR tAVDT_CCB_EVT *p_data)
+{
+    BT_HDR  *p_msg;
+
+    /* do we have commands to send?  send next command;  make sure we're clear;
+    ** not congested, not sending fragment, not waiting for response
+    */
+    if ((!p_ccb->cong) && (p_ccb->p_curr_msg == NULL) && (p_ccb->p_curr_cmd == NULL))
+    {
+        if ((p_msg = (BT_HDR *) fixed_queue_try_dequeue(p_ccb->cmd_q)) != NULL)
+        {
+            /* make a copy of buffer in p_curr_cmd */
+            p_ccb->p_curr_cmd = (BT_HDR *)osi_malloc(AVDT_CMD_BUF_SIZE);
+            memcpy(p_ccb->p_curr_cmd, p_msg,
+                   (sizeof(BT_HDR) + p_msg->offset + p_msg->len));
+            avdt_msg_send(p_ccb, p_msg);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_snd_msg
+**
+** Description
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_snd_msg(tAVDT_CCB *p_ccb,
+                      UNUSED_ATTR tAVDT_CCB_EVT *p_data)
+{
+    BT_HDR      *p_msg;
+
+    /* if not congested */
+    if (!p_ccb->cong)
+    {
+        /* are we sending a fragmented message? continue sending fragment */
+        if (p_ccb->p_curr_msg != NULL)
+        {
+            avdt_msg_send(p_ccb, NULL);
+        }
+        /* do we have responses to send?  send them */
+        else if (!fixed_queue_is_empty(p_ccb->rsp_q))
+        {
+            while ((p_msg = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->rsp_q)) != NULL)
+            {
+                if (avdt_msg_send(p_ccb, p_msg) == true)
+                {
+                    /* break out if congested */
+                    break;
+                }
+            }
+        }
+
+        /* do we have commands to send?  send next command */
+        avdt_ccb_snd_cmd(p_ccb, NULL);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_set_reconn
+**
+** Description      This function is called to enable a reconnect attempt when
+**                  a channel transitions from closing to idle state.  It sets
+**                  the reconn variable to true.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_set_reconn(tAVDT_CCB *p_ccb,
+                         UNUSED_ATTR tAVDT_CCB_EVT *p_data)
+{
+    p_ccb->reconn = true;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_clr_reconn
+**
+** Description      This function is called to clear the reconn variable.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_clr_reconn(tAVDT_CCB *p_ccb,
+                         UNUSED_ATTR tAVDT_CCB_EVT *p_data)
+{
+    p_ccb->reconn = false;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_chk_reconn
+**
+** Description      This function is called to check if a reconnect attempt
+**                  is enabled.  If enabled, it sends an AVDT_CCB_UL_OPEN_EVT
+**                  to the CCB.  If disabled, the CCB is deallocated.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_chk_reconn(tAVDT_CCB *p_ccb,
+                         UNUSED_ATTR tAVDT_CCB_EVT *p_data)
+{
+    uint8_t err_code = AVDT_ERR_CONNECT;
+
+    if (p_ccb->reconn)
+    {
+        p_ccb->reconn = false;
+
+        /* clear out ccb */
+        avdt_ccb_clear_ccb(p_ccb);
+
+        /* clear out current command, if any */
+        avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT *) &err_code);
+
+        /* reopen the signaling channel */
+        avdt_ccb_event(p_ccb, AVDT_CCB_UL_OPEN_EVT, NULL);
+    }
+    else
+    {
+        avdt_ccb_ll_closed(p_ccb, NULL);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_chk_timer
+**
+** Description      This function stops the CCB timer if the idle timer is
+**                  running.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_chk_timer(tAVDT_CCB *p_ccb,
+                        UNUSED_ATTR tAVDT_CCB_EVT *p_data)
+{
+    alarm_cancel(p_ccb->idle_ccb_timer);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_set_conn
+**
+** Description      Set CCB variables associated with AVDT_ConnectReq().
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_set_conn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    /* save callback */
+    p_ccb->p_conn_cback = p_data->connect.p_cback;
+
+    /* set security level */
+    BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVDTP, p_data->connect.sec_mask,
+                         AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_set_disconn
+**
+** Description      Set CCB variables associated with AVDT_DisconnectReq().
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_set_disconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    /*
+    AVDT_TRACE_EVENT("avdt_ccb_set_disconn:conn:x%x, api:x%x",
+        p_ccb->p_conn_cback, p_data->disconnect.p_cback);
+        */
+    /* save callback */
+    if (p_data->disconnect.p_cback)
+        p_ccb->p_conn_cback = p_data->disconnect.p_cback;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_do_disconn
+**
+** Description      Do action associated with AVDT_DisconnectReq().
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_do_disconn(tAVDT_CCB *p_ccb,
+                         UNUSED_ATTR tAVDT_CCB_EVT *p_data)
+{
+    /* clear any pending commands */
+    avdt_ccb_clear_cmds(p_ccb, NULL);
+
+    /* close channel */
+    avdt_ccb_chan_close(p_ccb, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_ll_closed
+**
+** Description      Clear commands from and deallocate CCB.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_ll_closed(tAVDT_CCB *p_ccb,
+                        UNUSED_ATTR tAVDT_CCB_EVT *p_data)
+{
+    tAVDT_CTRL_CBACK    *p_cback;
+    BD_ADDR             bd_addr;
+    tAVDT_CTRL          avdt_ctrl;
+
+    /* clear any pending commands */
+    avdt_ccb_clear_cmds(p_ccb, NULL);
+
+    /* save callback pointer, bd addr */
+    p_cback = p_ccb->p_conn_cback;
+    if (!p_cback)
+        p_cback = avdt_cb.p_conn_cback;
+    memcpy(bd_addr, p_ccb->peer_addr, BD_ADDR_LEN);
+
+    /* dealloc ccb */
+    avdt_ccb_dealloc(p_ccb, NULL);
+
+    /* call callback */
+    if (p_cback)
+    {
+        avdt_ctrl.hdr.err_code = 0;
+        (*p_cback)(0, bd_addr, AVDT_DISCONNECT_IND_EVT, &avdt_ctrl);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_ccb_ll_opened
+**
+** Description      Call callback on open.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_ccb_ll_opened(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
+{
+    tAVDT_CTRL          avdt_ctrl;
+
+    p_ccb->ll_opened = true;
+
+    if (!p_ccb->p_conn_cback)
+        p_ccb->p_conn_cback = avdt_cb.p_conn_cback;
+
+    /* call callback */
+    if (p_ccb->p_conn_cback)
+    {
+        avdt_ctrl.hdr.err_code = 0;
+        avdt_ctrl.hdr.err_param = p_data->msg.hdr.err_param;
+        (*p_ccb->p_conn_cback)(0, p_ccb->peer_addr, AVDT_CONNECT_IND_EVT, &avdt_ctrl);
+    }
+}
diff --git a/bt/stack/avdt/avdt_defs.h b/bt/stack/avdt/avdt_defs.h
new file mode 100644
index 0000000..f7fe3c6
--- /dev/null
+++ b/bt/stack/avdt/avdt_defs.h
@@ -0,0 +1,232 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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 contains constants definitions and other information from the AVDTP
+ *  specification.  This file is intended for use internal to AVDT only.
+ *
+ ******************************************************************************/
+#ifndef AVDT_DEFS_H
+#define AVDT_DEFS_H
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* signalling packet type */
+#define AVDT_PKT_TYPE_SINGLE        0       /* single packet */
+#define AVDT_PKT_TYPE_START         1       /* start packet */
+#define AVDT_PKT_TYPE_CONT          2       /* continue packet */
+#define AVDT_PKT_TYPE_END           3       /* end packet */
+
+/* signalling message type */
+#define AVDT_MSG_TYPE_CMD           0       /* command */
+#define AVDT_MSG_TYPE_GRJ           1       /* general reject */
+#define AVDT_MSG_TYPE_RSP           2       /* response accept */
+#define AVDT_MSG_TYPE_REJ           3       /* response reject */
+
+/* signalling messages */
+#define AVDT_SIG_DISCOVER           1       /* discover */
+#define AVDT_SIG_GETCAP             2       /* get capabilities */
+#define AVDT_SIG_SETCONFIG          3       /* set configuration */
+#define AVDT_SIG_GETCONFIG          4       /* get configuration */
+#define AVDT_SIG_RECONFIG           5       /* reconfigure */
+#define AVDT_SIG_OPEN               6       /* open */
+#define AVDT_SIG_START              7       /* start */
+#define AVDT_SIG_CLOSE              8       /* close */
+#define AVDT_SIG_SUSPEND            9       /* suspend */
+#define AVDT_SIG_ABORT              10      /* abort */
+#define AVDT_SIG_SECURITY           11      /* security control */
+#define AVDT_SIG_GET_ALLCAP         12      /* get all capabilities */
+#define AVDT_SIG_DELAY_RPT          13      /* delay report */
+
+/* maximum signal value */
+#define AVDT_SIG_MAX                AVDT_SIG_DELAY_RPT
+
+/* used for general reject */
+#define AVDT_SIG_NONE               0
+
+/* some maximum and minimum sizes of signalling messages */
+#define AVDT_DISCOVER_REQ_MIN       1
+#define AVDT_DISCOVER_REQ_MAX       124
+
+/* service category information element field values */
+#define AVDT_CAT_TRANS              1       /* Media Transport */
+#define AVDT_CAT_REPORT             2       /* Reporting */
+#define AVDT_CAT_RECOV              3       /* Recovery */
+#define AVDT_CAT_PROTECT            4       /* Content Protection */
+#define AVDT_CAT_HDRCMP             5       /* Header Compression */
+#define AVDT_CAT_MUX                6       /* Multiplexing */
+#define AVDT_CAT_CODEC              7       /* Media Codec */
+#define AVDT_CAT_DELAY_RPT          8       /* Delay Reporting */
+#define AVDT_CAT_MAX_CUR            AVDT_CAT_DELAY_RPT
+
+/* min/max lengths of service category information elements */
+#define AVDT_LEN_TRANS_MIN          0
+#define AVDT_LEN_REPORT_MIN         0
+#define AVDT_LEN_RECOV_MIN          3
+#define AVDT_LEN_PROTECT_MIN        2
+#define AVDT_LEN_HDRCMP_MIN         1
+#define AVDT_LEN_MUX_MIN            3
+#define AVDT_LEN_CODEC_MIN          2
+#define AVDT_LEN_DELAY_RPT_MIN      0
+
+#define AVDT_LEN_TRANS_MAX          0
+#define AVDT_LEN_REPORT_MAX         0
+#define AVDT_LEN_RECOV_MAX          3
+#define AVDT_LEN_PROTECT_MAX        255
+#define AVDT_LEN_HDRCMP_MAX         1
+#define AVDT_LEN_MUX_MAX            7
+#define AVDT_LEN_CODEC_MAX          255
+#define AVDT_LEN_DELAY_RPT_MAX      0
+
+/* minimum possible size of configuration or capabilities data */
+#define AVDT_LEN_CFG_MIN            2
+
+/* minimum and maximum lengths for different message types */
+#define AVDT_LEN_SINGLE             1
+#define AVDT_LEN_SETCONFIG_MIN      2
+#define AVDT_LEN_RECONFIG_MIN       1
+#define AVDT_LEN_MULTI_MIN          1
+#define AVDT_LEN_SECURITY_MIN       1
+#define AVDT_LEN_DELAY_RPT          3
+
+/* header lengths for different packet types */
+#define AVDT_LEN_TYPE_SINGLE        2       /* single packet */
+#define AVDT_LEN_TYPE_START         3       /* start packet */
+#define AVDT_LEN_TYPE_CONT          1       /* continue packet */
+#define AVDT_LEN_TYPE_END           1       /* end packet */
+
+/* length of general reject message */
+#define AVDT_LEN_GEN_REJ            2
+
+/* recovery service capabilities information elements */
+#define AVDT_RECOV_MRWS_MIN         0x01    /* min value for maximum recovery window */
+#define AVDT_RECOV_MRWS_MAX         0x18    /* max value for maximum recovery window */
+#define AVDT_RECOV_MNMP_MIN         0x01    /* min value for maximum number of media packets */
+#define AVDT_RECOV_MNMP_MAX         0x18    /* max value for maximum number of media packets */
+
+/* SEID value range */
+#define AVDT_SEID_MIN               0x01
+#define AVDT_SEID_MAX               0x3E
+
+/* first byte of media packet header */
+#define AVDT_MEDIA_OCTET1           0x80
+
+/* for adaptation layer header */
+#define AVDT_ALH_LCODE_MASK     0x03    /* coding of length field */
+#define AVDT_ALH_LCODE_NONE     0x00    /* No length field present. Take length from l2cap */
+#define AVDT_ALH_LCODE_16BIT    0x01    /* 16bit length field */
+#define AVDT_ALH_LCODE_9BITM0   0x02    /* 9 bit length field, MSB = 0, 8 LSBs in 1 octet following */
+#define AVDT_ALH_LCODE_9BITM1   0x03    /* 9 bit length field, MSB = 1, 8 LSBs in 1 octet following */
+
+#define AVDT_ALH_FRAG_MASK      0x04    /* set this for continuation packet */
+
+/*****************************************************************************
+** message parsing and building macros
+*****************************************************************************/
+
+#define AVDT_MSG_PRS_HDR(p, lbl, pkt, msg) \
+do { \
+    (lbl) = (*(p) >> 4) & 0x0F; \
+    (pkt) = (*(p) >> 2) & 0x03; \
+    (msg) = *(p)++ & 0x03; \
+} while (0)
+
+#define AVDT_MSG_PRS_DISC(p, seid, in_use, type, tsep) \
+do { \
+    (seid) = *(p) >> 2; \
+    (in_use) = (*(p)++ >> 1) & 0x01; \
+    (type) = (*(p) >> 4) & 0x0F; \
+    (tsep) = (*(p)++ >> 3) & 0x01; \
+} while (0)
+
+#define AVDT_MSG_PRS_SIG(p, sig) \
+do { \
+    (sig) = (*(p)++) & 0x3F; \
+} while (0)
+
+#define AVDT_MSG_PRS_SEID(p, seid) \
+do { \
+    (seid) = ((*(p)++) >> 2) & 0x3F; \
+} while (0)
+
+#define AVDT_MSG_PRS_PKT_TYPE(p, pkt) \
+do { \
+    (pkt) = (*(p) >> 2) & 0x03; \
+} while (0)
+
+#define AVDT_MSG_PRS_OCTET1(p, o_v, o_p, o_x, o_cc) \
+do { \
+    (o_v) = (*(p) >> 6) & 0x02; \
+    (o_p) = (*(p) >> 5) & 0x01; \
+    (o_x) = (*(p) >> 4) & 0x01; \
+    (o_cc) = (*(p)++) & 0x0F; \
+} while (0)
+
+#define AVDT_MSG_PRS_RPT_OCTET1(p, o_v, o_p, o_cc) \
+do { \
+    (o_v) = (*(p) >> 6) & 0x02; \
+    (o_p) = (*(p) >> 5) & 0x01; \
+    (o_cc) = (*(p)++) & 0x1F; \
+} while (0)
+
+#define AVDT_MSG_PRS_M_PT(p, m_pt, marker) \
+do { \
+    (marker) = (*(p) >> 7) & 0x01; \
+    (m_pt) = (*(p)++) & 0x7F; \
+} while (0)
+
+#define AVDT_MSG_BLD_HDR(p, lbl, pkt, msg) \
+do { \
+    *(p)++ = (uint8_t) ((lbl) << 4) | ((pkt) << 2) | (msg); \
+} while (0)
+
+#define AVDT_MSG_BLD_DISC(p, seid, in_use, type, tsep) \
+do { \
+    *(p)++ = (uint8_t) (((seid) << 2) | ((in_use) << 1)); \
+    *(p)++ = (uint8_t) (((type) << 4) | ((tsep) << 3)); \
+} while (0)
+
+#define AVDT_MSG_BLD_SIG(p, sig) \
+do { \
+    *(p)++ = (uint8_t) (sig); \
+} while (0)
+
+#define AVDT_MSG_BLD_SEID(p, seid) \
+do { \
+    *(p)++ = (uint8_t) ((seid) << 2); \
+} while (0)
+
+#define AVDT_MSG_BLD_ERR(p, err) \
+do { \
+    *(p)++ = (uint8_t) (err); \
+} while (0)
+
+#define AVDT_MSG_BLD_PARAM(p, param) \
+do { \
+    *(p)++ = (uint8_t) (param); \
+} while (0)
+
+#define AVDT_MSG_BLD_NOSP(p, nosp) \
+do { \
+    *(p)++ = (uint8_t) (nosp); \
+} while (0)
+
+#endif /* AVDT_DEFS_H */
diff --git a/bt/stack/avdt/avdt_int.h b/bt/stack/avdt/avdt_int.h
new file mode 100644
index 0000000..35a6989
--- /dev/null
+++ b/bt/stack/avdt/avdt_int.h
@@ -0,0 +1,715 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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 interfaces which are internal to AVDTP.
+ *
+ ******************************************************************************/
+#ifndef AVDT_INT_H
+#define AVDT_INT_H
+
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+#include "bt_common.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_defs.h"
+#include "l2c_api.h"
+#include "btm_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef AVDT_DEBUG
+#define AVDT_DEBUG  false
+#endif
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* channel types */
+enum {
+    AVDT_CHAN_SIG,                  /* signaling channel */
+    AVDT_CHAN_MEDIA,                /* media channel */
+#if (AVDT_REPORTING == TRUE)
+    AVDT_CHAN_REPORT,               /* reporting channel */
+#endif
+    AVDT_CHAN_NUM_TYPES
+};
+
+/* protocol service capabilities of this AVDTP implementation */
+#if (AVDT_REPORTING == TRUE)
+#define AVDT_PSC                (AVDT_PSC_TRANS | AVDT_PSC_REPORT | AVDT_PSC_DELAY_RPT)
+#define AVDT_LEG_PSC            (AVDT_PSC_TRANS | AVDT_PSC_REPORT)
+#else /* AVDT_REPORTING  */
+#define AVDT_PSC                (AVDT_PSC_TRANS | AVDT_PSC_DELAY_RPT)
+#define AVDT_LEG_PSC            (AVDT_PSC_TRANS)
+#endif /* AVDT_REPORTING  */
+
+/* initiator/acceptor signaling roles */
+#define AVDT_CLOSE_ACP          0
+#define AVDT_CLOSE_INT          1
+#define AVDT_OPEN_ACP           2
+#define AVDT_OPEN_INT           3
+
+/* states for avdt_scb_verify */
+#define AVDT_VERIFY_OPEN        0
+#define AVDT_VERIFY_STREAMING   1
+#define AVDT_VERIFY_SUSPEND     2
+#define AVDT_VERIFY_START       3
+
+/* to distinguish CCB events from SCB events */
+#define AVDT_CCB_MKR            0x80
+
+/* offset where AVDTP signaling message content starts;
+** use the size of a start header since it's the largest possible
+** layout of signaling message in a buffer is:
+**
+** |  BT_HDR  | SCB handles | L2CAP + HCI header | AVDTP header | data ... |
+**
+** Note that we "hide" the scb handles at the top of the message buffer.
+*/
+#define AVDT_MSG_OFFSET         (L2CAP_MIN_OFFSET + AVDT_NUM_SEPS + AVDT_LEN_TYPE_START)
+
+/* scb transport channel connect timeout value (in milliseconds) */
+#define AVDT_SCB_TC_CONN_TIMEOUT_MS   (10 * 1000)
+
+/* scb transport channel disconnect timeout value (in milliseconds) */
+#define AVDT_SCB_TC_DISC_TIMEOUT_MS   (10 * 1000)
+
+/* maximum number of command retransmissions */
+#ifndef AVDT_RET_MAX
+#define AVDT_RET_MAX            1
+#endif
+
+
+/* ccb state machine states */
+enum {
+    AVDT_CCB_IDLE_ST,
+    AVDT_CCB_OPENING_ST,
+    AVDT_CCB_OPEN_ST,
+    AVDT_CCB_CLOSING_ST
+};
+
+/* state machine action enumeration list */
+enum {
+    AVDT_CCB_CHAN_OPEN,
+    AVDT_CCB_CHAN_CLOSE,
+    AVDT_CCB_CHK_CLOSE,
+    AVDT_CCB_HDL_DISCOVER_CMD,
+    AVDT_CCB_HDL_DISCOVER_RSP,
+    AVDT_CCB_HDL_GETCAP_CMD,
+    AVDT_CCB_HDL_GETCAP_RSP,
+    AVDT_CCB_HDL_START_CMD,
+    AVDT_CCB_HDL_START_RSP,
+    AVDT_CCB_HDL_SUSPEND_CMD,
+    AVDT_CCB_HDL_SUSPEND_RSP,
+    AVDT_CCB_SND_DISCOVER_CMD,
+    AVDT_CCB_SND_DISCOVER_RSP,
+    AVDT_CCB_SND_GETCAP_CMD,
+    AVDT_CCB_SND_GETCAP_RSP,
+    AVDT_CCB_SND_START_CMD,
+    AVDT_CCB_SND_START_RSP,
+    AVDT_CCB_SND_SUSPEND_CMD,
+    AVDT_CCB_SND_SUSPEND_RSP,
+    AVDT_CCB_CLEAR_CMDS,
+    AVDT_CCB_CMD_FAIL,
+    AVDT_CCB_FREE_CMD,
+    AVDT_CCB_CONG_STATE,
+    AVDT_CCB_RET_CMD,
+    AVDT_CCB_SND_CMD,
+    AVDT_CCB_SND_MSG,
+    AVDT_CCB_SET_RECONN,
+    AVDT_CCB_CLR_RECONN,
+    AVDT_CCB_CHK_RECONN,
+    AVDT_CCB_CHK_TIMER,
+    AVDT_CCB_SET_CONN,
+    AVDT_CCB_SET_DISCONN,
+    AVDT_CCB_DO_DISCONN,
+    AVDT_CCB_LL_CLOSED,
+    AVDT_CCB_LL_OPENED,
+    AVDT_CCB_DEALLOC,
+    AVDT_CCB_NUM_ACTIONS
+};
+
+#define AVDT_CCB_IGNORE     AVDT_CCB_NUM_ACTIONS
+
+/* ccb state machine events */
+enum {
+    AVDT_CCB_API_DISCOVER_REQ_EVT,
+    AVDT_CCB_API_GETCAP_REQ_EVT,
+    AVDT_CCB_API_START_REQ_EVT,
+    AVDT_CCB_API_SUSPEND_REQ_EVT,
+    AVDT_CCB_API_DISCOVER_RSP_EVT,
+    AVDT_CCB_API_GETCAP_RSP_EVT,
+    AVDT_CCB_API_START_RSP_EVT,
+    AVDT_CCB_API_SUSPEND_RSP_EVT,
+    AVDT_CCB_API_CONNECT_REQ_EVT,
+    AVDT_CCB_API_DISCONNECT_REQ_EVT,
+    AVDT_CCB_MSG_DISCOVER_CMD_EVT,
+    AVDT_CCB_MSG_GETCAP_CMD_EVT,
+    AVDT_CCB_MSG_START_CMD_EVT,
+    AVDT_CCB_MSG_SUSPEND_CMD_EVT,
+    AVDT_CCB_MSG_DISCOVER_RSP_EVT,
+    AVDT_CCB_MSG_GETCAP_RSP_EVT,
+    AVDT_CCB_MSG_START_RSP_EVT,
+    AVDT_CCB_MSG_SUSPEND_RSP_EVT,
+    AVDT_CCB_RCVRSP_EVT,
+    AVDT_CCB_SENDMSG_EVT,
+    AVDT_CCB_RET_TOUT_EVT,
+    AVDT_CCB_RSP_TOUT_EVT,
+    AVDT_CCB_IDLE_TOUT_EVT,
+    AVDT_CCB_UL_OPEN_EVT,
+    AVDT_CCB_UL_CLOSE_EVT,
+    AVDT_CCB_LL_OPEN_EVT,
+    AVDT_CCB_LL_CLOSE_EVT,
+    AVDT_CCB_LL_CONG_EVT
+};
+
+
+/* scb state machine states; these state values are private to this module so
+** the scb state cannot be read or set by actions functions
+*/
+enum {
+    AVDT_SCB_IDLE_ST,
+    AVDT_SCB_CONF_ST,
+    AVDT_SCB_OPENING_ST,
+    AVDT_SCB_OPEN_ST,
+    AVDT_SCB_STREAM_ST,
+    AVDT_SCB_CLOSING_ST
+};
+
+/* state machine action enumeration list */
+enum {
+    AVDT_SCB_HDL_ABORT_CMD,
+    AVDT_SCB_HDL_ABORT_RSP,
+    AVDT_SCB_HDL_CLOSE_CMD,
+    AVDT_SCB_HDL_CLOSE_RSP,
+    AVDT_SCB_HDL_GETCONFIG_CMD,
+    AVDT_SCB_HDL_GETCONFIG_RSP,
+    AVDT_SCB_HDL_OPEN_CMD,
+    AVDT_SCB_HDL_OPEN_REJ,
+    AVDT_SCB_HDL_OPEN_RSP,
+    AVDT_SCB_HDL_PKT,
+    AVDT_SCB_DROP_PKT,
+    AVDT_SCB_HDL_RECONFIG_CMD,
+    AVDT_SCB_HDL_RECONFIG_RSP,
+    AVDT_SCB_HDL_SECURITY_CMD,
+    AVDT_SCB_HDL_SECURITY_RSP,
+    AVDT_SCB_HDL_SETCONFIG_CMD,
+    AVDT_SCB_HDL_SETCONFIG_REJ,
+    AVDT_SCB_HDL_SETCONFIG_RSP,
+    AVDT_SCB_HDL_START_CMD,
+    AVDT_SCB_HDL_START_RSP,
+    AVDT_SCB_HDL_SUSPEND_CMD,
+    AVDT_SCB_HDL_SUSPEND_RSP,
+    AVDT_SCB_HDL_TC_CLOSE,
+#if (AVDT_REPORTING == TRUE)
+    AVDT_SCB_HDL_TC_CLOSE_STO,
+#endif
+    AVDT_SCB_HDL_TC_OPEN,
+#if (AVDT_REPORTING == TRUE)
+    AVDT_SCB_HDL_TC_OPEN_STO,
+#endif
+    AVDT_SCB_SND_DELAY_RPT_REQ,
+    AVDT_SCB_HDL_DELAY_RPT_CMD,
+    AVDT_SCB_HDL_DELAY_RPT_RSP,
+    AVDT_SCB_HDL_WRITE_REQ,
+    AVDT_SCB_SND_ABORT_REQ,
+    AVDT_SCB_SND_ABORT_RSP,
+    AVDT_SCB_SND_CLOSE_REQ,
+    AVDT_SCB_SND_STREAM_CLOSE,
+    AVDT_SCB_SND_CLOSE_RSP,
+    AVDT_SCB_SND_GETCONFIG_REQ,
+    AVDT_SCB_SND_GETCONFIG_RSP,
+    AVDT_SCB_SND_OPEN_REQ,
+    AVDT_SCB_SND_OPEN_RSP,
+    AVDT_SCB_SND_RECONFIG_REQ,
+    AVDT_SCB_SND_RECONFIG_RSP,
+    AVDT_SCB_SND_SECURITY_REQ,
+    AVDT_SCB_SND_SECURITY_RSP,
+    AVDT_SCB_SND_SETCONFIG_REQ,
+    AVDT_SCB_SND_SETCONFIG_REJ,
+    AVDT_SCB_SND_SETCONFIG_RSP,
+    AVDT_SCB_SND_TC_CLOSE,
+    AVDT_SCB_CB_ERR,
+    AVDT_SCB_CONG_STATE,
+    AVDT_SCB_REJ_STATE,
+    AVDT_SCB_REJ_IN_USE,
+    AVDT_SCB_REJ_NOT_IN_USE,
+    AVDT_SCB_SET_REMOVE,
+    AVDT_SCB_FREE_PKT,
+    AVDT_SCB_CLR_PKT,
+    AVDT_SCB_CHK_SND_PKT,
+    AVDT_SCB_TC_TIMER,
+    AVDT_SCB_CLR_VARS,
+    AVDT_SCB_DEALLOC,
+    AVDT_SCB_NUM_ACTIONS
+};
+
+#define AVDT_SCB_IGNORE     AVDT_SCB_NUM_ACTIONS
+
+/* scb state machine events */
+enum {
+    AVDT_SCB_API_REMOVE_EVT,
+    AVDT_SCB_API_WRITE_REQ_EVT,
+    AVDT_SCB_API_GETCONFIG_REQ_EVT,
+    AVDT_SCB_API_DELAY_RPT_REQ_EVT,
+    AVDT_SCB_API_SETCONFIG_REQ_EVT,
+    AVDT_SCB_API_OPEN_REQ_EVT,
+    AVDT_SCB_API_CLOSE_REQ_EVT,
+    AVDT_SCB_API_RECONFIG_REQ_EVT,
+    AVDT_SCB_API_SECURITY_REQ_EVT,
+    AVDT_SCB_API_ABORT_REQ_EVT,
+    AVDT_SCB_API_GETCONFIG_RSP_EVT,
+    AVDT_SCB_API_SETCONFIG_RSP_EVT,
+    AVDT_SCB_API_SETCONFIG_REJ_EVT,
+    AVDT_SCB_API_OPEN_RSP_EVT,
+    AVDT_SCB_API_CLOSE_RSP_EVT,
+    AVDT_SCB_API_RECONFIG_RSP_EVT,
+    AVDT_SCB_API_SECURITY_RSP_EVT,
+    AVDT_SCB_API_ABORT_RSP_EVT,
+    AVDT_SCB_MSG_SETCONFIG_CMD_EVT,
+    AVDT_SCB_MSG_GETCONFIG_CMD_EVT,
+    AVDT_SCB_MSG_OPEN_CMD_EVT,
+    AVDT_SCB_MSG_START_CMD_EVT,
+    AVDT_SCB_MSG_SUSPEND_CMD_EVT,
+    AVDT_SCB_MSG_CLOSE_CMD_EVT,
+    AVDT_SCB_MSG_ABORT_CMD_EVT,
+    AVDT_SCB_MSG_RECONFIG_CMD_EVT,
+    AVDT_SCB_MSG_SECURITY_CMD_EVT,
+    AVDT_SCB_MSG_DELAY_RPT_CMD_EVT,
+    AVDT_SCB_MSG_DELAY_RPT_RSP_EVT,
+    AVDT_SCB_MSG_SETCONFIG_RSP_EVT,
+    AVDT_SCB_MSG_GETCONFIG_RSP_EVT,
+    AVDT_SCB_MSG_OPEN_RSP_EVT,
+    AVDT_SCB_MSG_START_RSP_EVT,
+    AVDT_SCB_MSG_SUSPEND_RSP_EVT,
+    AVDT_SCB_MSG_CLOSE_RSP_EVT,
+    AVDT_SCB_MSG_ABORT_RSP_EVT,
+    AVDT_SCB_MSG_RECONFIG_RSP_EVT,
+    AVDT_SCB_MSG_SECURITY_RSP_EVT,
+    AVDT_SCB_MSG_SETCONFIG_REJ_EVT,
+    AVDT_SCB_MSG_OPEN_REJ_EVT,
+    AVDT_SCB_MSG_START_REJ_EVT,
+    AVDT_SCB_MSG_SUSPEND_REJ_EVT,
+    AVDT_SCB_TC_TOUT_EVT,
+    AVDT_SCB_TC_OPEN_EVT,
+    AVDT_SCB_TC_CLOSE_EVT,
+    AVDT_SCB_TC_CONG_EVT,
+    AVDT_SCB_TC_DATA_EVT,
+    AVDT_SCB_CC_CLOSE_EVT
+};
+
+/* adaption layer number of stream routing table entries */
+#if (AVDT_REPORTING == TRUE)
+/* 2 channels(1 media, 1 report) for each SEP and one for signalling */
+#define AVDT_NUM_RT_TBL     ((AVDT_NUM_SEPS<<1) + 1)
+#else
+#define AVDT_NUM_RT_TBL     (AVDT_NUM_SEPS + 1)
+#endif
+
+/* adaption layer number of transport channel table entries - moved to target.h
+#define AVDT_NUM_TC_TBL     (AVDT_NUM_SEPS + AVDT_NUM_LINKS) */
+
+/* "states" used in transport channel table */
+#define AVDT_AD_ST_UNUSED   0       /* Unused - unallocated */
+#define AVDT_AD_ST_IDLE     1       /* No connection */
+#define AVDT_AD_ST_ACP      2       /* Waiting to accept a connection */
+#define AVDT_AD_ST_INT      3       /* Initiating a connection */
+#define AVDT_AD_ST_CONN     4       /* Waiting for connection confirm */
+#define AVDT_AD_ST_CFG      5       /* Waiting for configuration complete */
+#define AVDT_AD_ST_OPEN     6       /* Channel opened */
+#define AVDT_AD_ST_SEC_INT  7       /* Security process as INT */
+#define AVDT_AD_ST_SEC_ACP  8       /* Security process as ACP */
+
+/* Configuration flags. tAVDT_TC_TBL.cfg_flags */
+#define AVDT_L2C_CFG_IND_DONE   (1<<0)
+#define AVDT_L2C_CFG_CFM_DONE   (1<<1)
+#define AVDT_L2C_CFG_CONN_INT   (1<<2)
+#define AVDT_L2C_CFG_CONN_ACP   (1<<3)
+
+
+/* result code for avdt_ad_write_req() (L2CA_DataWrite()) */
+#define AVDT_AD_FAILED       L2CAP_DW_FAILED        /* FALSE */
+#define AVDT_AD_SUCCESS      L2CAP_DW_SUCCESS       /* TRUE */
+#define AVDT_AD_CONGESTED    L2CAP_DW_CONGESTED     /* 2 */
+
+/*****************************************************************************
+** data types
+*****************************************************************************/
+
+/* msg union of all message parameter types */
+typedef union {
+    tAVDT_EVT_HDR           hdr;
+    tAVDT_EVT_HDR           single;
+    tAVDT_SETCONFIG         config_cmd;
+    tAVDT_CONFIG            reconfig_cmd;
+    tAVDT_MULTI             multi;
+    tAVDT_SECURITY          security_cmd;
+    tAVDT_DISCOVER          discover_rsp;
+    tAVDT_CONFIG            svccap;
+    tAVDT_SECURITY          security_rsp;
+    tAVDT_DELAY_RPT         delay_rpt_cmd;
+} tAVDT_MSG;
+
+/* data type for AVDT_CCB_API_DISCOVER_REQ_EVT */
+typedef struct {
+    tAVDT_CTRL_CBACK    *p_cback;
+    tAVDT_SEP_INFO      *p_sep_info;
+    uint8_t             num_seps;
+} tAVDT_CCB_API_DISCOVER;
+
+/* data type for AVDT_CCB_API_GETCAP_REQ_EVT */
+typedef struct {
+    tAVDT_EVT_HDR       single;
+    tAVDT_CTRL_CBACK    *p_cback;
+    tAVDT_CFG           *p_cfg;
+} tAVDT_CCB_API_GETCAP;
+
+/* data type for AVDT_CCB_API_CONNECT_REQ_EVT */
+typedef struct {
+    tAVDT_CTRL_CBACK    *p_cback;
+    uint8_t             sec_mask;
+} tAVDT_CCB_API_CONNECT;
+
+/* data type for AVDT_CCB_API_DISCONNECT_REQ_EVT */
+typedef struct {
+    tAVDT_CTRL_CBACK    *p_cback;
+} tAVDT_CCB_API_DISCONNECT;
+
+/* union associated with ccb state machine events */
+typedef union {
+    tAVDT_CCB_API_DISCOVER      discover;
+    tAVDT_CCB_API_GETCAP        getcap;
+    tAVDT_CCB_API_CONNECT       connect;
+    tAVDT_CCB_API_DISCONNECT    disconnect;
+    tAVDT_MSG                   msg;
+    bool                        llcong;
+    uint8_t                     err_code;
+} tAVDT_CCB_EVT;
+
+/* channel control block type */
+typedef struct {
+    BD_ADDR             peer_addr;      /* BD address of peer */
+    /*
+     * NOTE: idle_ccb_timer, ret_ccb_timer and rsp_ccb_timer are mutually
+     * exclusive - no more than one timer should be running at the same time.
+     */
+    alarm_t             *idle_ccb_timer; /* Idle CCB timer entry */
+    alarm_t             *ret_ccb_timer; /* Ret CCB timer entry */
+    alarm_t             *rsp_ccb_timer; /* Rsp CCB timer entry */
+    fixed_queue_t       *cmd_q;         /* Queue for outgoing command messages */
+    fixed_queue_t       *rsp_q;         /* Queue for outgoing response and reject messages */
+    tAVDT_CTRL_CBACK    *proc_cback;    /* Procedure callback function */
+    tAVDT_CTRL_CBACK    *p_conn_cback;  /* Connection/disconnection callback function */
+    void                *p_proc_data;   /* Pointer to data storage for procedure */
+    BT_HDR              *p_curr_cmd;    /* Current command being sent awaiting response */
+    BT_HDR              *p_curr_msg;    /* Current message being sent */
+    BT_HDR              *p_rx_msg;      /* Current message being received */
+    bool                allocated;      /* Whether ccb is allocated */
+    uint8_t             state;          /* The CCB state machine state */
+    bool                ll_opened;      /* true if LL is opened */
+    bool                proc_busy;      /* true when a discover or get capabilities procedure in progress */
+    uint8_t             proc_param;     /* Procedure parameter; either SEID for get capabilities or number of SEPS for discover */
+    bool                cong;           /* Whether signaling channel is congested */
+    uint8_t             label;          /* Message header "label" (sequence number) */
+    bool                reconn;         /* If true, reinitiate connection after transitioning from CLOSING to IDLE state */
+    uint8_t             ret_count;      /* Command retransmission count */
+} tAVDT_CCB;
+
+/* type for action functions */
+typedef void (*tAVDT_CCB_ACTION)(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+
+/* type for AVDT_SCB_API_WRITE_REQ_EVT */
+typedef struct {
+    BT_HDR      *p_buf;
+    uint32_t    time_stamp;
+    uint8_t     m_pt;
+    tAVDT_DATA_OPT_MASK     opt;
+} tAVDT_SCB_APIWRITE;
+
+/* type for AVDT_SCB_TC_CLOSE_EVT */
+typedef struct {
+    uint8_t         old_tc_state;       /* channel state before closed */
+    uint8_t         tcid;               /* TCID  */
+    uint8_t         type;               /* channel type */
+} tAVDT_SCB_TC_CLOSE;
+
+/* type for scb event data */
+typedef union {
+    tAVDT_MSG           msg;
+    tAVDT_SCB_APIWRITE  apiwrite;
+    tAVDT_DELAY_RPT     apidelay;
+    tAVDT_OPEN          open;
+    tAVDT_SCB_TC_CLOSE  close;
+    bool                llcong;
+    BT_HDR              *p_pkt;
+} tAVDT_SCB_EVT;
+
+/* stream control block type */
+typedef struct {
+    tAVDT_CS        cs;             /* stream creation struct */
+    tAVDT_CFG       curr_cfg;       /* current configuration */
+    tAVDT_CFG       req_cfg;        /* requested configuration */
+    alarm_t         *transport_channel_timer; /* transport channel connect timer */
+    BT_HDR          *p_pkt;         /* packet waiting to be sent */
+    tAVDT_CCB       *p_ccb;         /* ccb associated with this scb */
+    uint16_t        media_seq;      /* media packet sequence number */
+    bool            allocated;      /* whether scb is allocated or unused */
+    bool            in_use;         /* whether stream being used by peer */
+    uint8_t         role;           /* initiator/acceptor role in current procedure */
+    bool            remove;         /* whether CB is marked for removal */
+    uint8_t         state;          /* state machine state */
+    uint8_t         peer_seid;      /* SEID of peer stream */
+    uint8_t         curr_evt;       /* current event; set only by state machine */
+    bool            cong;           /* Whether media transport channel is congested */
+    uint8_t         close_code;     /* Error code received in close response */
+} tAVDT_SCB;
+
+/* type for action functions */
+typedef void (*tAVDT_SCB_ACTION)(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+
+/* adaption layer type for transport channel table */
+typedef struct {
+    uint16_t peer_mtu;       /* L2CAP mtu of the peer device */
+    uint16_t my_mtu;         /* Our MTU for this channel */
+    uint16_t my_flush_to;    /* Our flush timeout for this channel */
+    uint16_t lcid;
+    uint8_t tcid;           /* transport channel id */
+    uint8_t ccb_idx;        /* channel control block associated with this tc */
+    uint8_t state;          /* transport channel state */
+    uint8_t cfg_flags;      /* L2CAP configuration flags */
+    uint8_t id;
+} tAVDT_TC_TBL;
+
+/* adaption layer type for stream routing table */
+typedef struct {
+    uint16_t lcid;           /* L2CAP LCID of the associated transport channel */
+    uint8_t scb_hdl;        /* stream control block associated with this tc */
+} tAVDT_RT_TBL;
+
+
+/* adaption layer control block */
+typedef struct {
+    tAVDT_RT_TBL    rt_tbl[AVDT_NUM_LINKS][AVDT_NUM_RT_TBL];
+    tAVDT_TC_TBL    tc_tbl[AVDT_NUM_TC_TBL];
+    uint8_t         lcid_tbl[MAX_L2CAP_CHANNELS];   /* map LCID to tc_tbl index */
+} tAVDT_AD;
+
+/* Control block for AVDT */
+typedef struct {
+    tAVDT_REG           rcb;                    /* registration control block */
+    tAVDT_CCB           ccb[AVDT_NUM_LINKS];    /* channel control blocks */
+    tAVDT_SCB           scb[AVDT_NUM_SEPS];     /* stream control blocks */
+    tAVDT_AD            ad;                     /* adaption layer control block */
+    tAVDTC_CTRL_CBACK   *p_conf_cback;          /* conformance callback function */
+    tAVDT_CCB_ACTION    *p_ccb_act;             /* pointer to CCB action functions */
+    tAVDT_SCB_ACTION    *p_scb_act;             /* pointer to SCB action functions */
+    tAVDT_CTRL_CBACK    *p_conn_cback;          /* connection callback function */
+    uint8_t             trace_level;            /* trace level */
+} tAVDT_CB;
+
+
+/*****************************************************************************
+** function declarations
+*****************************************************************************/
+
+/* CCB function declarations */
+extern void avdt_ccb_init(void);
+extern void avdt_ccb_event(tAVDT_CCB *p_ccb, uint8_t event, tAVDT_CCB_EVT *p_data);
+extern tAVDT_CCB *avdt_ccb_by_bd(BD_ADDR bd_addr);
+extern tAVDT_CCB *avdt_ccb_alloc(BD_ADDR bd_addr);
+extern void avdt_ccb_dealloc(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern uint8_t avdt_ccb_to_idx(tAVDT_CCB *p_ccb);
+extern tAVDT_CCB *avdt_ccb_by_idx(uint8_t idx);
+
+/* CCB action functions */
+extern void avdt_ccb_chan_open(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_chan_close(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_chk_close(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_start_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_hdl_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_start_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_clear_cmds(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_cmd_fail(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_free_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_cong_state(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_ret_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_snd_msg(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_set_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_clr_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_chk_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_chk_timer(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_set_conn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_set_disconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_do_disconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_ll_closed(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+extern void avdt_ccb_ll_opened(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
+
+/* SCB function prototypes */
+extern void avdt_scb_event(tAVDT_SCB *p_scb, uint8_t event, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_init(void);
+extern tAVDT_SCB *avdt_scb_alloc(tAVDT_CS *p_cs);
+extern void avdt_scb_dealloc(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern uint8_t avdt_scb_to_hdl(tAVDT_SCB *p_scb);
+extern tAVDT_SCB *avdt_scb_by_hdl(uint8_t hdl);
+extern uint8_t avdt_scb_verify(tAVDT_CCB *p_ccb, uint8_t state, uint8_t *p_seid, uint16_t num_seid, uint8_t *p_err_code);
+extern void avdt_scb_peer_seid_list(tAVDT_MULTI *p_multi);
+extern uint32_t avdt_scb_gen_ssrc(tAVDT_SCB *p_scb);
+
+/* SCB action functions */
+extern void avdt_scb_hdl_abort_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_abort_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_close_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_getconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_getconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_open_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_open_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_open_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_drop_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_reconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_security_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_setconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_setconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_start_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_start_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_suspend_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_suspend_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_delay_rpt_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_delay_rpt_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_delay_rpt_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_tc_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_tc_open(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_tc_close_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_tc_open_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_hdl_write_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_abort_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_abort_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_close_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_stream_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_getconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_getconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_open_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_open_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_reconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_security_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_setconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_setconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_snd_tc_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_cb_err(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_cong_state(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_rej_state(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_rej_in_use(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_rej_not_in_use(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_set_remove(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_free_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_chk_snd_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_clr_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_transport_channel_timer(tAVDT_SCB *p_scb,
+                                             tAVDT_SCB_EVT *p_data);
+extern void avdt_scb_clr_vars(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
+
+/* msg function declarations */
+extern bool    avdt_msg_send(tAVDT_CCB *p_ccb, BT_HDR *p_msg);
+extern void avdt_msg_send_cmd(tAVDT_CCB *p_ccb, void *p_scb, uint8_t sig_id, tAVDT_MSG *p_params);
+extern void avdt_msg_send_rsp(tAVDT_CCB *p_ccb, uint8_t sig_id, tAVDT_MSG *p_params);
+extern void avdt_msg_send_rej(tAVDT_CCB *p_ccb, uint8_t sig_id, tAVDT_MSG *p_params);
+extern void avdt_msg_send_grej(tAVDT_CCB *p_ccb, uint8_t sig_id, tAVDT_MSG *p_params);
+extern void avdt_msg_ind(tAVDT_CCB *p_ccb, BT_HDR *p_buf);
+
+/* adaption layer function declarations */
+extern void avdt_ad_init(void);
+extern uint8_t avdt_ad_type_to_tcid(uint8_t type, tAVDT_SCB *p_scb);
+extern tAVDT_TC_TBL *avdt_ad_tc_tbl_by_st(uint8_t type, tAVDT_CCB *p_ccb, uint8_t state);
+extern tAVDT_TC_TBL *avdt_ad_tc_tbl_by_lcid(uint16_t lcid);
+extern tAVDT_TC_TBL *avdt_ad_tc_tbl_alloc(tAVDT_CCB *p_ccb);
+extern uint8_t avdt_ad_tc_tbl_to_idx(tAVDT_TC_TBL *p_tbl);
+extern void avdt_ad_tc_close_ind(tAVDT_TC_TBL *p_tbl, uint16_t reason);
+extern void avdt_ad_tc_open_ind(tAVDT_TC_TBL *p_tbl);
+extern void avdt_ad_tc_cong_ind(tAVDT_TC_TBL *p_tbl, bool    is_congested);
+extern void avdt_ad_tc_data_ind(tAVDT_TC_TBL *p_tbl, BT_HDR *p_buf);
+extern tAVDT_TC_TBL *avdt_ad_tc_tbl_by_type(uint8_t type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb);
+extern uint8_t avdt_ad_write_req(uint8_t type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, BT_HDR *p_buf);
+extern void avdt_ad_open_req(uint8_t type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, uint8_t role);
+extern void avdt_ad_close_req(uint8_t type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb);
+
+extern void avdt_ccb_idle_ccb_timer_timeout(void *data);
+extern void avdt_ccb_ret_ccb_timer_timeout(void *data);
+extern void avdt_ccb_rsp_ccb_timer_timeout(void *data);
+extern void avdt_scb_transport_channel_timer_timeout(void *data);
+
+/*****************************************************************************
+** macros
+*****************************************************************************/
+
+/* we store the scb and the label in the layer_specific field of the
+** current cmd
+*/
+#define AVDT_BLD_LAYERSPEC(ls, msg, label) \
+            ls = (((label) << 4) | (msg))
+
+#define AVDT_LAYERSPEC_LABEL(ls)    ((uint8_t)((ls) >> 4))
+
+#define AVDT_LAYERSPEC_MSG(ls)      ((uint8_t)((ls) & 0x000F))
+
+/*****************************************************************************
+** global data
+*****************************************************************************/
+
+/******************************************************************************
+** Main Control Block
+*******************************************************************************/
+extern tAVDT_CB avdt_cb;
+
+/* L2CAP callback registration structure */
+extern const tL2CAP_APPL_INFO avdt_l2c_appl;
+
+/* reject message event lookup table */
+extern const uint8_t avdt_msg_rej_2_evt[];
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVDT_INT_H */
diff --git a/bt/stack/avdt/avdt_l2c.cc b/bt/stack/avdt/avdt_l2c.cc
new file mode 100644
index 0000000..6d29d06
--- /dev/null
+++ b/bt/stack/avdt/avdt_l2c.cc
@@ -0,0 +1,547 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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 AVDTP adaption layer module interfaces to L2CAP
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "device/include/interop.h"
+#include "osi/include/osi.h"
+
+/* callback function declarations */
+void avdt_l2c_connect_ind_cback(BD_ADDR bd_addr, uint16_t lcid,
+                                uint16_t psm, uint8_t id);
+void avdt_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result);
+void avdt_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg);
+void avdt_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg);
+void avdt_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed);
+void avdt_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result);
+void avdt_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested);
+void avdt_l2c_data_ind_cback(uint16_t lcid, BT_HDR *p_buf);
+
+/* L2CAP callback function structure */
+const tL2CAP_APPL_INFO avdt_l2c_appl = {
+    avdt_l2c_connect_ind_cback,
+    avdt_l2c_connect_cfm_cback,
+    NULL,
+    avdt_l2c_config_ind_cback,
+    avdt_l2c_config_cfm_cback,
+    avdt_l2c_disconnect_ind_cback,
+    avdt_l2c_disconnect_cfm_cback,
+    NULL,
+    avdt_l2c_data_ind_cback,
+    avdt_l2c_congestion_ind_cback,
+    NULL                /* tL2CA_TX_COMPLETE_CB */
+};
+
+/*******************************************************************************
+**
+** Function         avdt_sec_check_complete_term
+**
+** Description      The function called when Security Manager finishes
+**                  verification of the service side connection
+**
+** Returns          void
+**
+*******************************************************************************/
+static void avdt_sec_check_complete_term (BD_ADDR bd_addr, tBT_TRANSPORT transport,
+                                                 UNUSED_ATTR void *p_ref_data, uint8_t res)
+{
+    tAVDT_CCB       *p_ccb = NULL;
+    tL2CAP_CFG_INFO cfg;
+    tAVDT_TC_TBL    *p_tbl;
+
+    AVDT_TRACE_DEBUG("avdt_sec_check_complete_term res: %d", res);
+    if (!bd_addr)
+    {
+        AVDT_TRACE_WARNING("avdt_sec_check_complete_term: NULL BD_ADDR");
+        return;
+
+    }
+    p_ccb = avdt_ccb_by_bd(bd_addr);
+
+    p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_SEC_ACP);
+    if (p_tbl == NULL)
+        return;
+
+    if (res == BTM_SUCCESS)
+    {
+        /* Send response to the L2CAP layer. */
+        L2CA_ConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+
+        /* store idx in LCID table, store LCID in routing table */
+        avdt_cb.ad.lcid_tbl[p_tbl->lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl);
+        avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = p_tbl->lcid;
+
+        /* transition to configuration state */
+        p_tbl->state = AVDT_AD_ST_CFG;
+
+        /* Send L2CAP config req */
+        memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+        cfg.mtu_present = true;
+        cfg.mtu = p_tbl->my_mtu;
+        cfg.flush_to_present = true;
+        cfg.flush_to = p_tbl->my_flush_to;
+        L2CA_ConfigReq(p_tbl->lcid, &cfg);
+    }
+    else
+    {
+        L2CA_ConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
+        avdt_ad_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_sec_check_complete_orig
+**
+** Description      The function called when Security Manager finishes
+**                  verification of the service side connection
+**
+** Returns          void
+**
+*******************************************************************************/
+static void avdt_sec_check_complete_orig (BD_ADDR bd_addr, tBT_TRANSPORT trasnport,
+                                                UNUSED_ATTR void *p_ref_data, uint8_t res)
+{
+    tAVDT_CCB       *p_ccb = NULL;
+    tL2CAP_CFG_INFO cfg;
+    tAVDT_TC_TBL    *p_tbl;
+
+    AVDT_TRACE_DEBUG("avdt_sec_check_complete_orig res: %d", res);
+    if (bd_addr)
+        p_ccb = avdt_ccb_by_bd(bd_addr);
+    p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_SEC_INT);
+    if(p_tbl == NULL)
+        return;
+
+    if( res == BTM_SUCCESS )
+    {
+        /* set channel state */
+        p_tbl->state = AVDT_AD_ST_CFG;
+
+        /* Send L2CAP config req */
+        memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+        cfg.mtu_present = true;
+        cfg.mtu = p_tbl->my_mtu;
+        cfg.flush_to_present = true;
+        cfg.flush_to = p_tbl->my_flush_to;
+        L2CA_ConfigReq(p_tbl->lcid, &cfg);
+    }
+    else
+    {
+        L2CA_DisconnectReq (p_tbl->lcid);
+        avdt_ad_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
+    }
+}
+/*******************************************************************************
+**
+** Function         avdt_l2c_connect_ind_cback
+**
+** Description      This is the L2CAP connect indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avdt_l2c_connect_ind_cback(BD_ADDR bd_addr, uint16_t lcid,
+                                UNUSED_ATTR uint16_t psm, uint8_t id)
+{
+    tAVDT_CCB       *p_ccb;
+    tAVDT_TC_TBL    *p_tbl = NULL;
+    uint16_t        result;
+    tL2CAP_CFG_INFO cfg;
+    tBTM_STATUS rc;
+
+    /* do we already have a control channel for this peer? */
+    if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
+    {
+        /* no, allocate ccb */
+        if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL)
+        {
+            /* no ccb available, reject L2CAP connection */
+            result = L2CAP_CONN_NO_RESOURCES;
+        }
+        else
+        {
+            /* allocate and set up entry; first channel is always signaling */
+            p_tbl = avdt_ad_tc_tbl_alloc(p_ccb);
+            p_tbl->my_mtu = avdt_cb.rcb.ctrl_mtu;
+            p_tbl->my_flush_to = L2CAP_DEFAULT_FLUSH_TO;
+            p_tbl->tcid = AVDT_CHAN_SIG;
+            p_tbl->lcid = lcid;
+            p_tbl->id   = id;
+            p_tbl->state = AVDT_AD_ST_SEC_ACP;
+            p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_ACP;
+
+            if (interop_match_addr(INTEROP_2MBPS_LINK_ONLY, (const bt_bdaddr_t *)&bd_addr)) {
+                // Disable 3DH packets for AVDT ACL to improve sensitivity on HS
+                tACL_CONN *p_acl_cb = btm_bda_to_acl(bd_addr, BT_TRANSPORT_BR_EDR);
+                btm_set_packet_types(p_acl_cb, (btm_cb.btm_acl_pkt_types_supported |
+                                                HCI_PKT_TYPES_MASK_NO_3_DH1 |
+                                                HCI_PKT_TYPES_MASK_NO_3_DH3 |
+                                                HCI_PKT_TYPES_MASK_NO_3_DH5));
+            }
+
+            /* Check the security */
+            rc = btm_sec_mx_access_request (bd_addr, AVDT_PSM,
+                false, BTM_SEC_PROTO_AVDT,
+                AVDT_CHAN_SIG,
+                &avdt_sec_check_complete_term, NULL);
+            if(rc == BTM_CMD_STARTED)
+            {
+                L2CA_ConnectRsp (p_ccb->peer_addr, p_tbl->id, lcid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
+            }
+            return;
+        }
+    }
+    /* deal with simultaneous control channel connect case */
+    else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_CONN)) != NULL)
+    {
+        /* reject their connection */
+        result = L2CAP_CONN_NO_RESOURCES;
+    }
+    /* this must be a traffic channel; are we accepting a traffic channel
+    ** for this ccb?
+    */
+    else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_MEDIA, p_ccb, AVDT_AD_ST_ACP)) != NULL)
+    {
+        /* yes; proceed with connection */
+        result = L2CAP_CONN_OK;
+    }
+#if (AVDT_REPORTING == TRUE)
+    /* this must be a reporting channel; are we accepting a reporting channel
+    ** for this ccb?
+    */
+    else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_REPORT, p_ccb, AVDT_AD_ST_ACP)) != NULL)
+    {
+        /* yes; proceed with connection */
+        result = L2CAP_CONN_OK;
+    }
+#endif
+    /* else we're not listening for traffic channel; reject */
+    else
+    {
+        result = L2CAP_CONN_NO_PSM;
+    }
+
+    /* Send L2CAP connect rsp */
+    L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
+
+    /* if result ok, proceed with connection */
+    if (result == L2CAP_CONN_OK)
+    {
+        /* store idx in LCID table, store LCID in routing table */
+        avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl);
+        avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
+
+        /* transition to configuration state */
+        p_tbl->state = AVDT_AD_ST_CFG;
+
+        /* Send L2CAP config req */
+        memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+        cfg.mtu_present = true;
+        cfg.mtu = p_tbl->my_mtu;
+        cfg.flush_to_present = true;
+        cfg.flush_to = p_tbl->my_flush_to;
+        L2CA_ConfigReq(lcid, &cfg);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_l2c_connect_cfm_cback
+**
+** Description      This is the L2CAP connect confirm callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avdt_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result)
+{
+    tAVDT_TC_TBL    *p_tbl;
+    tL2CAP_CFG_INFO cfg;
+    tAVDT_CCB *p_ccb;
+
+    AVDT_TRACE_DEBUG("avdt_l2c_connect_cfm_cback lcid: %d, result: %d",
+        lcid, result);
+    /* look up info for this channel */
+    if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
+    {
+        /* if in correct state */
+        if (p_tbl->state == AVDT_AD_ST_CONN)
+        {
+            /* if result successful */
+            if (result == L2CAP_CONN_OK)
+            {
+                if(p_tbl->tcid != AVDT_CHAN_SIG)
+                {
+                    /* set channel state */
+                    p_tbl->state = AVDT_AD_ST_CFG;
+
+                    /* Send L2CAP config req */
+                    memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+                    cfg.mtu_present = true;
+                    cfg.mtu = p_tbl->my_mtu;
+                    cfg.flush_to_present = true;
+                    cfg.flush_to = p_tbl->my_flush_to;
+                    L2CA_ConfigReq(lcid, &cfg);
+                }
+                else
+                {
+                    p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
+                    if(p_ccb == NULL)
+                    {
+                        result = L2CAP_CONN_NO_RESOURCES;
+                    }
+                    else
+                    {
+                        /* set channel state */
+                        p_tbl->state = AVDT_AD_ST_SEC_INT;
+                        p_tbl->lcid = lcid;
+                        p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_INT;
+
+                        if (interop_match_addr(INTEROP_2MBPS_LINK_ONLY, (const bt_bdaddr_t *) &p_ccb->peer_addr)) {
+                            // Disable 3DH packets for AVDT ACL to improve sensitivity on HS
+                            tACL_CONN *p_acl_cb = btm_bda_to_acl(p_ccb->peer_addr, BT_TRANSPORT_BR_EDR);
+                            btm_set_packet_types(p_acl_cb, (btm_cb.btm_acl_pkt_types_supported |
+                                                            HCI_PKT_TYPES_MASK_NO_3_DH1 |
+                                                            HCI_PKT_TYPES_MASK_NO_3_DH3 |
+                                                            HCI_PKT_TYPES_MASK_NO_3_DH5));
+                        }
+
+                        /* Check the security */
+                        btm_sec_mx_access_request (p_ccb->peer_addr, AVDT_PSM,
+                            true, BTM_SEC_PROTO_AVDT,
+                            AVDT_CHAN_SIG,
+                            &avdt_sec_check_complete_orig, NULL);
+                    }
+                }
+            }
+
+            /* failure; notify adaption that channel closed */
+            if (result != L2CAP_CONN_OK)
+            {
+                avdt_ad_tc_close_ind(p_tbl, result);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_l2c_config_cfm_cback
+**
+** Description      This is the L2CAP config confirm callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avdt_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+    tAVDT_TC_TBL    *p_tbl;
+
+    /* look up info for this channel */
+    if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
+    {
+        p_tbl->lcid = lcid;
+
+        /* if in correct state */
+        if (p_tbl->state == AVDT_AD_ST_CFG)
+        {
+            /* if result successful */
+            if (p_cfg->result == L2CAP_CONN_OK)
+            {
+                /* update cfg_flags */
+                p_tbl->cfg_flags |= AVDT_L2C_CFG_CFM_DONE;
+
+                /* if configuration complete */
+                if (p_tbl->cfg_flags & AVDT_L2C_CFG_IND_DONE)
+                {
+                    avdt_ad_tc_open_ind(p_tbl);
+                }
+            }
+            /* else failure */
+            else
+            {
+                /* Send L2CAP disconnect req */
+                L2CA_DisconnectReq(lcid);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_l2c_config_ind_cback
+**
+** Description      This is the L2CAP config indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avdt_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+    tAVDT_TC_TBL    *p_tbl;
+
+    /* look up info for this channel */
+    if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
+    {
+        /* store the mtu in tbl */
+        if (p_cfg->mtu_present)
+        {
+            p_tbl->peer_mtu = p_cfg->mtu;
+        }
+        else
+        {
+            p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+        }
+        AVDT_TRACE_DEBUG("peer_mtu: %d, lcid: x%x",p_tbl->peer_mtu, lcid);
+
+        /* send L2CAP configure response */
+        memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+        p_cfg->result = L2CAP_CFG_OK;
+        L2CA_ConfigRsp(lcid, p_cfg);
+
+        /* if first config ind */
+        if ((p_tbl->cfg_flags & AVDT_L2C_CFG_IND_DONE) == 0)
+        {
+            /* update cfg_flags */
+            p_tbl->cfg_flags |= AVDT_L2C_CFG_IND_DONE;
+
+            /* if configuration complete */
+            if (p_tbl->cfg_flags & AVDT_L2C_CFG_CFM_DONE)
+            {
+                avdt_ad_tc_open_ind(p_tbl);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_l2c_disconnect_ind_cback
+**
+** Description      This is the L2CAP disconnect indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avdt_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed)
+{
+    tAVDT_TC_TBL    *p_tbl;
+
+    AVDT_TRACE_DEBUG("avdt_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d",
+        lcid, ack_needed);
+    /* look up info for this channel */
+    if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
+    {
+        if (ack_needed)
+        {
+            /* send L2CAP disconnect response */
+            L2CA_DisconnectRsp(lcid);
+        }
+
+        avdt_ad_tc_close_ind(p_tbl, 0);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_l2c_disconnect_cfm_cback
+**
+** Description      This is the L2CAP disconnect confirm callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avdt_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result)
+{
+    tAVDT_TC_TBL    *p_tbl;
+
+    AVDT_TRACE_DEBUG("avdt_l2c_disconnect_cfm_cback lcid: %d, result: %d",
+        lcid, result);
+    /* look up info for this channel */
+    if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
+    {
+        avdt_ad_tc_close_ind(p_tbl, result);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_l2c_congestion_ind_cback
+**
+** Description      This is the L2CAP congestion indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avdt_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested)
+{
+    tAVDT_TC_TBL    *p_tbl;
+
+    /* look up info for this channel */
+    if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
+    {
+        avdt_ad_tc_cong_ind(p_tbl, is_congested);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_l2c_data_ind_cback
+**
+** Description      This is the L2CAP data indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void avdt_l2c_data_ind_cback(uint16_t lcid, BT_HDR *p_buf)
+{
+    tAVDT_TC_TBL    *p_tbl;
+
+    /* look up info for this channel */
+    if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
+    {
+        avdt_ad_tc_data_ind(p_tbl, p_buf);
+    }
+    else /* prevent buffer leak */
+        osi_free(p_buf);
+}
+
diff --git a/bt/stack/avdt/avdt_msg.cc b/bt/stack/avdt/avdt_msg.cc
new file mode 100644
index 0000000..dc9549e
--- /dev/null
+++ b/bt/stack/avdt/avdt_msg.cc
@@ -0,0 +1,1797 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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 module contains functions for parsing and building AVDTP signaling
+ *  messages.  It also contains functions called by the SCB or CCB state
+ *  machines for sending command, response, and reject messages.  It also
+ *  contains a function that processes incoming messages and dispatches them
+ *  to the appropriate SCB or CCB.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "bt_common.h"
+#include "btu.h"
+#include "osi/include/osi.h"
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* mask of all psc values */
+#define AVDT_MSG_PSC_MASK   (AVDT_PSC_TRANS | AVDT_PSC_REPORT | AVDT_PSC_DELAY_RPT | \
+                             AVDT_PSC_RECOV | AVDT_PSC_HDRCMP | AVDT_PSC_MUX)
+#define AVDT_PSC_PROTECT    (1<<4)  /* Content Protection */
+#define AVDT_PSC_CODEC      (1<<7)  /* codec */
+
+
+/*****************************************************************************
+** type definitions
+*****************************************************************************/
+
+/* type for message building functions */
+typedef void (*tAVDT_MSG_BLD)(uint8_t **p, tAVDT_MSG *p_msg);
+
+/* type for message parsing functions */
+typedef uint8_t (*tAVDT_MSG_PRS)(tAVDT_MSG *p_msg, uint8_t *p, uint16_t len);
+
+
+/*****************************************************************************
+** local function declarations
+*****************************************************************************/
+
+static void avdt_msg_bld_none(uint8_t **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_single(uint8_t **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_setconfig_cmd(uint8_t **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_reconfig_cmd(uint8_t **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_multi(uint8_t **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_security_cmd(uint8_t **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_discover_rsp(uint8_t **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_svccap(uint8_t **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_security_rsp(uint8_t **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_all_svccap(uint8_t **p, tAVDT_MSG *p_msg);
+static void avdt_msg_bld_delay_rpt(uint8_t **p, tAVDT_MSG *p_msg);
+
+static uint8_t avdt_msg_prs_none(tAVDT_MSG *p_msg, uint8_t *p, uint16_t len);
+static uint8_t avdt_msg_prs_single(tAVDT_MSG *p_msg, uint8_t *p, uint16_t len);
+static uint8_t avdt_msg_prs_setconfig_cmd(tAVDT_MSG *p_msg, uint8_t *p, uint16_t len);
+static uint8_t avdt_msg_prs_reconfig_cmd(tAVDT_MSG *p_msg, uint8_t *p, uint16_t len);
+static uint8_t avdt_msg_prs_multi(tAVDT_MSG *p_msg, uint8_t *p, uint16_t len);
+static uint8_t avdt_msg_prs_security_cmd(tAVDT_MSG *p_msg, uint8_t *p, uint16_t len);
+static uint8_t avdt_msg_prs_discover_rsp(tAVDT_MSG *p_msg, uint8_t *p, uint16_t len);
+static uint8_t avdt_msg_prs_svccap(tAVDT_MSG *p_msg, uint8_t *p, uint16_t len);
+static uint8_t avdt_msg_prs_all_svccap(tAVDT_MSG *p_msg, uint8_t *p, uint16_t len);
+static uint8_t avdt_msg_prs_security_rsp(tAVDT_MSG *p_msg, uint8_t *p, uint16_t len);
+static uint8_t avdt_msg_prs_delay_rpt (tAVDT_MSG *p_msg, uint8_t *p, uint16_t len);
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* table of information element minimum lengths used for parsing */
+const uint8_t avdt_msg_ie_len_min[] = {
+    0,                              /* unused */
+    AVDT_LEN_TRANS_MIN,             /* media transport */
+    AVDT_LEN_REPORT_MIN,            /* reporting */
+    AVDT_LEN_RECOV_MIN,             /* recovery */
+    AVDT_LEN_PROTECT_MIN,           /* content protection */
+    AVDT_LEN_HDRCMP_MIN,            /* header compression */
+    AVDT_LEN_MUX_MIN,               /* multiplexing */
+    AVDT_LEN_CODEC_MIN,             /* codec */
+    AVDT_LEN_DELAY_RPT_MIN          /* delay report */
+};
+
+/* table of information element minimum lengths used for parsing */
+const uint8_t avdt_msg_ie_len_max[] = {
+    0,                              /* unused */
+    AVDT_LEN_TRANS_MAX,             /* media transport */
+    AVDT_LEN_REPORT_MAX,            /* reporting */
+    AVDT_LEN_RECOV_MAX,             /* recovery */
+    AVDT_LEN_PROTECT_MAX,           /* content protection */
+    AVDT_LEN_HDRCMP_MAX,            /* header compression */
+    AVDT_LEN_MUX_MAX,               /* multiplexing */
+    AVDT_LEN_CODEC_MAX,             /* codec */
+    AVDT_LEN_DELAY_RPT_MAX          /* delay report */
+};
+
+/* table of error codes used when decoding information elements */
+const uint8_t avdt_msg_ie_err[] = {
+    0,                              /* unused */
+    AVDT_ERR_MEDIA_TRANS,           /* media transport */
+    AVDT_ERR_LENGTH,                /* reporting */
+    AVDT_ERR_RECOV_FMT,             /* recovery */
+    AVDT_ERR_CP_FMT,                /* content protection */
+    AVDT_ERR_ROHC_FMT,              /* header compression */
+    AVDT_ERR_MUX_FMT,               /* multiplexing */
+    AVDT_ERR_SERVICE,               /* codec */
+    AVDT_ERR_SERVICE                /* delay report ?? */
+};
+
+/* table of packet type minimum lengths */
+static const uint8_t avdt_msg_pkt_type_len[] = {
+    AVDT_LEN_TYPE_SINGLE,
+    AVDT_LEN_TYPE_START,
+    AVDT_LEN_TYPE_CONT,
+    AVDT_LEN_TYPE_END
+};
+
+/* function table for building command messages */
+const tAVDT_MSG_BLD avdt_msg_bld_cmd[] = {
+    avdt_msg_bld_none,            /* discover */
+    avdt_msg_bld_single,          /* get capabilities */
+    avdt_msg_bld_setconfig_cmd,   /* set configuration */
+    avdt_msg_bld_single,          /* get configuration */
+    avdt_msg_bld_reconfig_cmd,    /* reconfigure */
+    avdt_msg_bld_single,          /* open */
+    avdt_msg_bld_multi,           /* start */
+    avdt_msg_bld_single,          /* close */
+    avdt_msg_bld_multi,           /* suspend */
+    avdt_msg_bld_single,          /* abort */
+    avdt_msg_bld_security_cmd,    /* security control */
+    avdt_msg_bld_single,          /* get all capabilities */
+    avdt_msg_bld_delay_rpt        /* delay report */
+};
+
+/* function table for building response messages */
+const tAVDT_MSG_BLD avdt_msg_bld_rsp[] = {
+    avdt_msg_bld_discover_rsp,    /* discover */
+    avdt_msg_bld_svccap,          /* get capabilities */
+    avdt_msg_bld_none,            /* set configuration */
+    avdt_msg_bld_all_svccap,      /* get configuration */
+    avdt_msg_bld_none,            /* reconfigure */
+    avdt_msg_bld_none,            /* open */
+    avdt_msg_bld_none,            /* start */
+    avdt_msg_bld_none,            /* close */
+    avdt_msg_bld_none,            /* suspend */
+    avdt_msg_bld_none,            /* abort */
+    avdt_msg_bld_security_rsp,    /* security control */
+    avdt_msg_bld_all_svccap,      /* get all capabilities */
+    avdt_msg_bld_none             /* delay report */
+};
+
+/* function table for parsing command messages */
+const tAVDT_MSG_PRS avdt_msg_prs_cmd[] = {
+    avdt_msg_prs_none,            /* discover */
+    avdt_msg_prs_single,          /* get capabilities */
+    avdt_msg_prs_setconfig_cmd,   /* set configuration */
+    avdt_msg_prs_single,          /* get configuration */
+    avdt_msg_prs_reconfig_cmd,    /* reconfigure */
+    avdt_msg_prs_single,          /* open */
+    avdt_msg_prs_multi,           /* start */
+    avdt_msg_prs_single,          /* close */
+    avdt_msg_prs_multi,           /* suspend */
+    avdt_msg_prs_single,          /* abort */
+    avdt_msg_prs_security_cmd,    /* security control */
+    avdt_msg_prs_single,          /* get all capabilities */
+    avdt_msg_prs_delay_rpt        /* delay report */
+};
+
+/* function table for parsing response messages */
+const tAVDT_MSG_PRS avdt_msg_prs_rsp[] = {
+    avdt_msg_prs_discover_rsp,    /* discover */
+    avdt_msg_prs_svccap,          /* get capabilities */
+    avdt_msg_prs_none,            /* set configuration */
+    avdt_msg_prs_all_svccap,      /* get configuration */
+    avdt_msg_prs_none,            /* reconfigure */
+    avdt_msg_prs_none,            /* open */
+    avdt_msg_prs_none,            /* start */
+    avdt_msg_prs_none,            /* close */
+    avdt_msg_prs_none,            /* suspend */
+    avdt_msg_prs_none,            /* abort */
+    avdt_msg_prs_security_rsp,    /* security control */
+    avdt_msg_prs_all_svccap,      /* get all capabilities */
+    avdt_msg_prs_none             /* delay report */
+};
+
+/* command message-to-event lookup table */
+const uint8_t avdt_msg_cmd_2_evt[] = {
+    AVDT_CCB_MSG_DISCOVER_CMD_EVT + AVDT_CCB_MKR,   /* discover */
+    AVDT_CCB_MSG_GETCAP_CMD_EVT + AVDT_CCB_MKR,     /* get capabilities */
+    AVDT_SCB_MSG_SETCONFIG_CMD_EVT,                 /* set configuration */
+    AVDT_SCB_MSG_GETCONFIG_CMD_EVT,                 /* get configuration */
+    AVDT_SCB_MSG_RECONFIG_CMD_EVT,                  /* reconfigure */
+    AVDT_SCB_MSG_OPEN_CMD_EVT,                      /* open */
+    AVDT_CCB_MSG_START_CMD_EVT + AVDT_CCB_MKR,      /* start */
+    AVDT_SCB_MSG_CLOSE_CMD_EVT,                     /* close */
+    AVDT_CCB_MSG_SUSPEND_CMD_EVT + AVDT_CCB_MKR,    /* suspend */
+    AVDT_SCB_MSG_ABORT_CMD_EVT,                     /* abort */
+    AVDT_SCB_MSG_SECURITY_CMD_EVT,                  /* security control */
+    AVDT_CCB_MSG_GETCAP_CMD_EVT + AVDT_CCB_MKR,     /* get all capabilities */
+    AVDT_SCB_MSG_DELAY_RPT_CMD_EVT                  /* delay report */
+};
+
+/* response message-to-event lookup table */
+const uint8_t avdt_msg_rsp_2_evt[] = {
+    AVDT_CCB_MSG_DISCOVER_RSP_EVT + AVDT_CCB_MKR,   /* discover */
+    AVDT_CCB_MSG_GETCAP_RSP_EVT + AVDT_CCB_MKR,     /* get capabilities */
+    AVDT_SCB_MSG_SETCONFIG_RSP_EVT,                 /* set configuration */
+    AVDT_SCB_MSG_GETCONFIG_RSP_EVT,                 /* get configuration */
+    AVDT_SCB_MSG_RECONFIG_RSP_EVT,                  /* reconfigure */
+    AVDT_SCB_MSG_OPEN_RSP_EVT,                      /* open */
+    AVDT_CCB_MSG_START_RSP_EVT + AVDT_CCB_MKR,      /* start */
+    AVDT_SCB_MSG_CLOSE_RSP_EVT,                     /* close */
+    AVDT_CCB_MSG_SUSPEND_RSP_EVT + AVDT_CCB_MKR,    /* suspend */
+    AVDT_SCB_MSG_ABORT_RSP_EVT,                     /* abort */
+    AVDT_SCB_MSG_SECURITY_RSP_EVT,                  /* security control */
+    AVDT_CCB_MSG_GETCAP_RSP_EVT + AVDT_CCB_MKR,     /* get all capabilities */
+    AVDT_SCB_MSG_DELAY_RPT_RSP_EVT                  /* delay report */
+};
+
+/* reject message-to-event lookup table */
+const uint8_t avdt_msg_rej_2_evt[] = {
+    AVDT_CCB_MSG_DISCOVER_RSP_EVT + AVDT_CCB_MKR,   /* discover */
+    AVDT_CCB_MSG_GETCAP_RSP_EVT + AVDT_CCB_MKR,     /* get capabilities */
+    AVDT_SCB_MSG_SETCONFIG_REJ_EVT,                 /* set configuration */
+    AVDT_SCB_MSG_GETCONFIG_RSP_EVT,                 /* get configuration */
+    AVDT_SCB_MSG_RECONFIG_RSP_EVT,                  /* reconfigure */
+    AVDT_SCB_MSG_OPEN_REJ_EVT,                      /* open */
+    AVDT_CCB_MSG_START_RSP_EVT + AVDT_CCB_MKR,      /* start */
+    AVDT_SCB_MSG_CLOSE_RSP_EVT,                     /* close */
+    AVDT_CCB_MSG_SUSPEND_RSP_EVT + AVDT_CCB_MKR,    /* suspend */
+    AVDT_SCB_MSG_ABORT_RSP_EVT,                     /* abort */
+    AVDT_SCB_MSG_SECURITY_RSP_EVT,                  /* security control */
+    AVDT_CCB_MSG_GETCAP_RSP_EVT + AVDT_CCB_MKR,     /* get all capabilities */
+    0                                               /* delay report */
+};
+
+/*******************************************************************************
+**
+** Function         avdt_msg_bld_cfg
+**
+** Description      This function builds the configuration parameters contained
+**                  in a command or response message.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_cfg(uint8_t **p, tAVDT_CFG *p_cfg)
+{
+    uint8_t len;
+
+    /* for now, just build media transport, codec, and content protection, and multiplexing */
+
+    /* media transport */
+    if (p_cfg->psc_mask & AVDT_PSC_TRANS)
+    {
+        *(*p)++ = AVDT_CAT_TRANS;
+        *(*p)++ = 0; /* length */
+    }
+
+#if (AVDT_REPORTING == TRUE)
+    /* reporting transport */
+    if (p_cfg->psc_mask & AVDT_PSC_REPORT)
+    {
+        *(*p)++ = AVDT_CAT_REPORT;
+        *(*p)++ = 0; /* length */
+    }
+#endif
+
+    /* codec */
+    if (p_cfg->num_codec != 0)
+    {
+        *(*p)++ = AVDT_CAT_CODEC;
+        len = p_cfg->codec_info[0] + 1;
+        if( len > AVDT_CODEC_SIZE )
+            len = AVDT_CODEC_SIZE;
+
+        memcpy(*p, p_cfg->codec_info, len);
+        *p += len;
+    }
+
+    /* content protection */
+    if (p_cfg->num_protect != 0)
+    {
+        *(*p)++ = AVDT_CAT_PROTECT;
+        len = p_cfg->protect_info[0] + 1;
+        if( len > AVDT_PROTECT_SIZE )
+            len = AVDT_PROTECT_SIZE;
+
+        memcpy(*p, p_cfg->protect_info, len);
+        *p += len;
+    }
+
+    /* delay report */
+    if (p_cfg->psc_mask & AVDT_PSC_DELAY_RPT)
+    {
+        *(*p)++ = AVDT_CAT_DELAY_RPT;
+        *(*p)++ = 0; /* length */
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_bld_none
+**
+** Description      This message building function builds an empty message.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_none(UNUSED_ATTR uint8_t **p,
+                              UNUSED_ATTR tAVDT_MSG *p_msg)
+{
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_bld_single
+**
+** Description      This message building function builds a message containing
+**                  a single SEID.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_single(uint8_t **p, tAVDT_MSG *p_msg)
+{
+    AVDT_MSG_BLD_SEID(*p, p_msg->single.seid);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_bld_setconfig_cmd
+**
+** Description      This message building function builds a set configuration
+**                  command message.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_setconfig_cmd(uint8_t **p, tAVDT_MSG *p_msg)
+{
+    AVDT_MSG_BLD_SEID(*p, p_msg->config_cmd.hdr.seid);
+    AVDT_MSG_BLD_SEID(*p, p_msg->config_cmd.int_seid);
+    avdt_msg_bld_cfg(p, p_msg->config_cmd.p_cfg);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_bld_reconfig_cmd
+**
+** Description      This message building function builds a reconfiguration
+**                  command message.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_reconfig_cmd(uint8_t **p, tAVDT_MSG *p_msg)
+{
+    AVDT_MSG_BLD_SEID(*p, p_msg->reconfig_cmd.hdr.seid);
+
+    /* force psc mask zero to build only codec and security */
+    p_msg->reconfig_cmd.p_cfg->psc_mask = 0;
+    avdt_msg_bld_cfg(p, p_msg->reconfig_cmd.p_cfg);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_bld_multi
+**
+** Description      This message building function builds a message containing
+**                  multiple SEID's.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_multi(uint8_t **p, tAVDT_MSG *p_msg)
+{
+    int i;
+
+    for (i = 0; i < p_msg->multi.num_seps; i++)
+    {
+        AVDT_MSG_BLD_SEID(*p, p_msg->multi.seid_list[i]);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_bld_security_cmd
+**
+** Description      This message building function builds a security
+**                  command message.
+**
+** Returns          void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_security_cmd(uint8_t **p, tAVDT_MSG *p_msg)
+{
+    AVDT_MSG_BLD_SEID(*p, p_msg->security_cmd.hdr.seid);
+    memcpy(*p, p_msg->security_cmd.p_data, p_msg->security_cmd.len);
+    *p += p_msg->security_cmd.len;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_bld_delay_rpt
+**
+** Description      This message building function builds a delay report
+**                  command message.
+**
+** Returns          void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_delay_rpt(uint8_t **p, tAVDT_MSG *p_msg)
+{
+    AVDT_MSG_BLD_SEID(*p, p_msg->delay_rpt_cmd.hdr.seid);
+    UINT16_TO_BE_STREAM(*p, p_msg->delay_rpt_cmd.delay);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_bld_discover_rsp
+**
+** Description      This message building function builds a discover
+**                  response message.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_discover_rsp(uint8_t **p, tAVDT_MSG *p_msg)
+{
+    int     i;
+
+    for (i = 0; i < p_msg->discover_rsp.num_seps; i++)
+    {
+        /* build discover rsp info */
+        AVDT_MSG_BLD_DISC(*p, p_msg->discover_rsp.p_sep_info[i].seid,
+                              p_msg->discover_rsp.p_sep_info[i].in_use,
+                              p_msg->discover_rsp.p_sep_info[i].media_type,
+                              p_msg->discover_rsp.p_sep_info[i].tsep);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_bld_svccap
+**
+** Description      This message building function builds a message containing
+**                  service capabilities parameters.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_svccap(uint8_t **p, tAVDT_MSG *p_msg)
+{
+    tAVDT_CFG cfg;
+
+    /* make sure the delay report category is not reported */
+    memcpy (&cfg, p_msg->svccap.p_cfg, sizeof(tAVDT_CFG));
+    cfg.psc_mask &= ~AVDT_PSC_DELAY_RPT;
+    avdt_msg_bld_cfg(p, &cfg);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_bld_all_svccap
+**
+** Description      This message building function builds a message containing
+**                  service capabilities parameters.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_all_svccap(uint8_t **p, tAVDT_MSG *p_msg)
+{
+    avdt_msg_bld_cfg(p, p_msg->svccap.p_cfg);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_bld_security_rsp
+**
+** Description      This message building function builds a security
+**                  response message.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+static void avdt_msg_bld_security_rsp(uint8_t **p, tAVDT_MSG *p_msg)
+{
+    memcpy(*p, p_msg->security_rsp.p_data, p_msg->security_rsp.len);
+    *p += p_msg->security_rsp.len;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_prs_cfg
+**
+** Description      This message parsing function parses the configuration
+**                  parameters field of a message.
+**
+**
+** Returns          Error code or zero if no error, and element that failed
+**                  in p_elem.
+**
+*******************************************************************************/
+static uint8_t avdt_msg_prs_cfg(tAVDT_CFG *p_cfg, uint8_t *p, uint16_t len, uint8_t* p_elem, uint8_t sig_id)
+{
+    uint8_t *p_end;
+    uint8_t elem = 0;
+    uint8_t elem_len;
+    uint8_t tmp;
+    uint8_t err = 0;
+    uint8_t protect_offset = 0;
+
+    if (!p_cfg)
+    {
+        AVDT_TRACE_ERROR ("not expecting this cfg");
+        return AVDT_ERR_BAD_STATE;
+    }
+
+    p_cfg->psc_mask = 0;
+    p_cfg->num_codec = 0;
+    p_cfg->num_protect = 0;
+
+    /* while there is still data to parse */
+    p_end = p + len;
+    while ((p < p_end) && (err == 0))
+    {
+        /* verify overall length */
+        if ((p_end - p) < AVDT_LEN_CFG_MIN)
+        {
+            err = AVDT_ERR_PAYLOAD;
+            break;
+        }
+
+        /* get and verify info elem id, length */
+        elem = *p++;
+        elem_len = *p++;
+
+        if ((elem == 0) || (elem > AVDT_CAT_MAX_CUR))
+        {
+            /* this may not be really bad.
+             * It may be a service category that is too new for us.
+             * allow these to be parsed without reporting an error.
+             * If this is a "capability" (as in GetCapRsp & GetConfigRsp), this is filtered out.
+             * If this is a Configuration (as in SetConfigCmd & ReconfigCmd),
+             *    this will be marked as an error in the caller of this function */
+            if ((sig_id == AVDT_SIG_SETCONFIG) || (sig_id == AVDT_SIG_RECONFIG))
+            {
+                /* Cannot accept unknown category. */
+                err = AVDT_ERR_CATEGORY;
+                break;
+            }
+            else    /* GETCAP or GET_ALLCAP */
+            {
+                /* Skip unknown categories. */
+                p += elem_len;
+                AVDT_TRACE_DEBUG("skipping unknown service category=%d len: %d", elem, elem_len);
+                continue;
+            }
+        }
+
+        if ((elem_len > avdt_msg_ie_len_max[elem]) ||
+            (elem_len < avdt_msg_ie_len_min[elem]))
+        {
+            err = avdt_msg_ie_err[elem];
+            break;
+        }
+
+        /* add element to psc mask, but mask out codec or protect */
+        p_cfg->psc_mask |= (1 << elem);
+        AVDT_TRACE_DEBUG("elem=%d elem_len: %d psc_mask=0x%x", elem, elem_len, p_cfg->psc_mask);
+
+        /* parse individual information elements with additional parameters */
+        switch (elem)
+        {
+            case AVDT_CAT_RECOV:
+                p_cfg->recov_type = *p++;
+                p_cfg->recov_mrws = *p++;
+                p_cfg->recov_mnmp = *p++;
+                if (p_cfg->recov_type != AVDT_RECOV_RFC2733)
+                {
+                    err = AVDT_ERR_RECOV_TYPE;
+                }
+                else if ((p_cfg->recov_mrws < AVDT_RECOV_MRWS_MIN) ||
+                         (p_cfg->recov_mrws > AVDT_RECOV_MRWS_MAX) ||
+                         (p_cfg->recov_mnmp < AVDT_RECOV_MNMP_MIN) ||
+                         (p_cfg->recov_mnmp > AVDT_RECOV_MNMP_MAX))
+                {
+                    err = AVDT_ERR_RECOV_FMT;
+                }
+                break;
+
+            case AVDT_CAT_PROTECT:
+                p_cfg->psc_mask &= ~AVDT_PSC_PROTECT;
+                if ((elem_len + protect_offset) < AVDT_PROTECT_SIZE)
+                {
+                    p_cfg->num_protect++;
+                    p_cfg->protect_info[protect_offset] = elem_len;
+                    protect_offset++;
+                    memcpy(&p_cfg->protect_info[protect_offset], p, elem_len);
+                    protect_offset += elem_len;
+                }
+                p += elem_len;
+                break;
+
+            case AVDT_CAT_HDRCMP:
+                p_cfg->hdrcmp_mask = *p++;
+                break;
+
+            case AVDT_CAT_CODEC:
+                p_cfg->psc_mask &= ~AVDT_PSC_CODEC;
+                tmp = elem_len;
+                if (elem_len >= AVDT_CODEC_SIZE)
+                {
+                    tmp = AVDT_CODEC_SIZE - 1;
+                }
+                p_cfg->num_codec++;
+                p_cfg->codec_info[0] = elem_len;
+                memcpy(&p_cfg->codec_info[1], p, tmp);
+                p += elem_len;
+                break;
+
+            case AVDT_CAT_DELAY_RPT:
+                break;
+
+            default:
+                p += elem_len;
+                break;
+        } /* switch */
+    } /* while ! err, !end*/
+    *p_elem = elem;
+    AVDT_TRACE_DEBUG("err=0x%x, elem:0x%x psc_mask=0x%x", err, elem, p_cfg->psc_mask);
+
+    return err;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_prs_none
+**
+** Description      This message parsing function parses a message with no parameters.
+
+**
+**
+** Returns          Error code or zero if no error.
+**
+*******************************************************************************/
+static uint8_t avdt_msg_prs_none(UNUSED_ATTR tAVDT_MSG *p_msg, UNUSED_ATTR uint8_t *p,
+                                 UNUSED_ATTR uint16_t len)
+{
+    return 0;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_prs_single
+**
+** Description      This message parsing function parses a message with a
+**                  single SEID.
+**
+**
+** Returns          Error code or zero if no error.
+**
+*******************************************************************************/
+static uint8_t avdt_msg_prs_single(tAVDT_MSG *p_msg, uint8_t *p, uint16_t len)
+{
+    uint8_t     err = 0;
+
+    /* verify len */
+    if (len != AVDT_LEN_SINGLE)
+    {
+        err = AVDT_ERR_LENGTH;
+    }
+    else
+    {
+        AVDT_MSG_PRS_SEID(p, p_msg->single.seid);
+
+        if (avdt_scb_by_hdl(p_msg->single.seid) == NULL)
+        {
+            err = AVDT_ERR_SEID;
+        }
+    }
+    return err;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_prs_setconfig_cmd
+**
+** Description      This message parsing function parses a set configuration
+**                  command message.
+**
+**
+** Returns          Error code or zero if no error.
+**
+*******************************************************************************/
+static uint8_t avdt_msg_prs_setconfig_cmd(tAVDT_MSG *p_msg, uint8_t *p, uint16_t len)
+{
+    uint8_t     err = 0;
+
+    p_msg->hdr.err_param = 0;
+
+    /* verify len */
+    if (len < AVDT_LEN_SETCONFIG_MIN)
+    {
+        err = AVDT_ERR_LENGTH;
+    }
+    else
+    {
+        /* get seids */
+        AVDT_MSG_PRS_SEID(p, p_msg->config_cmd.hdr.seid);
+        if (avdt_scb_by_hdl(p_msg->config_cmd.hdr.seid) == NULL)
+        {
+            err = AVDT_ERR_SEID;
+        }
+
+        AVDT_MSG_PRS_SEID(p, p_msg->config_cmd.int_seid);
+        if ((p_msg->config_cmd.int_seid < AVDT_SEID_MIN) ||
+            (p_msg->config_cmd.int_seid > AVDT_SEID_MAX))
+        {
+            err = AVDT_ERR_SEID;
+        }
+    }
+
+    if (!err)
+    {
+        /* parse configuration parameters */
+        len -= 2;
+        err = avdt_msg_prs_cfg(p_msg->config_cmd.p_cfg, p, len, &p_msg->hdr.err_param, AVDT_SIG_SETCONFIG);
+
+        if (!err)
+        {
+            /* verify protocol service capabilities are supported */
+            if (((p_msg->config_cmd.p_cfg->psc_mask & (~AVDT_PSC)) != 0) ||
+                (p_msg->config_cmd.p_cfg->num_codec == 0))
+            {
+                err = AVDT_ERR_INVALID_CAP;
+            }
+        }
+    }
+
+    return err;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_prs_reconfig_cmd
+**
+** Description      This message parsing function parses a reconfiguration
+**                  command message.
+**
+**
+** Returns          Error code or zero if no error.
+**
+*******************************************************************************/
+static uint8_t avdt_msg_prs_reconfig_cmd(tAVDT_MSG *p_msg, uint8_t *p, uint16_t len)
+{
+    uint8_t     err = 0;
+
+    p_msg->hdr.err_param = 0;
+
+    /* verify len */
+    if (len < AVDT_LEN_RECONFIG_MIN)
+    {
+        err = AVDT_ERR_LENGTH;
+    }
+    else
+    {
+        /* get seid */
+        AVDT_MSG_PRS_SEID(p, p_msg->reconfig_cmd.hdr.seid);
+        if (avdt_scb_by_hdl(p_msg->reconfig_cmd.hdr.seid) == NULL)
+        {
+            err = AVDT_ERR_SEID;
+        }
+        else
+        {
+            /* parse config parameters */
+            len--;
+            err = avdt_msg_prs_cfg(p_msg->config_cmd.p_cfg, p, len, &p_msg->hdr.err_param, AVDT_SIG_RECONFIG);
+
+            /* verify no protocol service capabilities in parameters */
+            if (!err)
+            {
+                AVDT_TRACE_DEBUG("avdt_msg_prs_reconfig_cmd psc_mask=0x%x/0x%x", p_msg->config_cmd.p_cfg->psc_mask, AVDT_MSG_PSC_MASK);
+                if ((p_msg->config_cmd.p_cfg->psc_mask != 0) ||
+                    (p_msg->config_cmd.p_cfg->num_codec == 0 && p_msg->config_cmd.p_cfg->num_protect == 0))
+                {
+                    err = AVDT_ERR_INVALID_CAP;
+                }
+            }
+        }
+    }
+    return err;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_prs_multi
+**
+** Description      This message parsing function parses a message containing
+**                  multiple SEID's.
+**
+**
+** Returns          Error code or zero if no error.
+**
+*******************************************************************************/
+static uint8_t avdt_msg_prs_multi(tAVDT_MSG *p_msg, uint8_t *p, uint16_t len)
+{
+    int     i;
+    uint8_t err = 0;
+
+    p_msg->hdr.err_param = 0;
+
+    /* verify len */
+    if (len < AVDT_LEN_MULTI_MIN || (len > AVDT_NUM_SEPS))
+    {
+        err = AVDT_ERR_LENGTH;
+    }
+    else
+    {
+        /* get and verify all seps */
+        for (i = 0; i < len; i++)
+        {
+            AVDT_MSG_PRS_SEID(p, p_msg->multi.seid_list[i]);
+            if (avdt_scb_by_hdl(p_msg->multi.seid_list[i]) == NULL)
+            {
+                err = AVDT_ERR_SEID;
+                p_msg->hdr.err_param = p_msg->multi.seid_list[i];
+                break;
+            }
+        }
+        p_msg->multi.num_seps = (uint8_t)i;
+    }
+
+    return err;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_prs_security_cmd
+**
+** Description      This message parsing function parses a security
+**                  command message.
+**
+**
+** Returns          Error code or zero if no error.
+**
+*******************************************************************************/
+static uint8_t avdt_msg_prs_security_cmd(tAVDT_MSG *p_msg, uint8_t *p, uint16_t len)
+{
+    uint8_t     err = 0;
+
+    /* verify len */
+    if (len < AVDT_LEN_SECURITY_MIN)
+    {
+        err = AVDT_ERR_LENGTH;
+    }
+    else
+    {
+        /* get seid */
+        AVDT_MSG_PRS_SEID(p, p_msg->security_cmd.hdr.seid);
+        if (avdt_scb_by_hdl(p_msg->security_cmd.hdr.seid) == NULL)
+        {
+            err = AVDT_ERR_SEID;
+        }
+        else
+        {
+            p_msg->security_cmd.p_data = p;
+            p_msg->security_cmd.len = len - 1;
+        }
+    }
+    return err;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_prs_discover_rsp
+**
+** Description      This message parsing function parses a discover
+**                  response message.
+**
+**
+** Returns          Error code or zero if no error.
+**
+*******************************************************************************/
+static uint8_t avdt_msg_prs_discover_rsp(tAVDT_MSG *p_msg, uint8_t *p, uint16_t len)
+{
+    int     i;
+    uint8_t err = 0;
+
+    /* determine number of seps; seps in msg is len/2, but set to minimum
+    ** of seps app has supplied memory for and seps in msg
+    */
+    if (p_msg->discover_rsp.num_seps > (len / 2))
+    {
+        p_msg->discover_rsp.num_seps = (len / 2);
+    }
+
+    /* parse out sep info */
+    for (i = 0; i < p_msg->discover_rsp.num_seps; i++)
+    {
+        /* parse discover rsp info */
+        AVDT_MSG_PRS_DISC(p, p_msg->discover_rsp.p_sep_info[i].seid,
+                          p_msg->discover_rsp.p_sep_info[i].in_use,
+                          p_msg->discover_rsp.p_sep_info[i].media_type,
+                          p_msg->discover_rsp.p_sep_info[i].tsep);
+
+        /* verify that seid is valid */
+        if ((p_msg->discover_rsp.p_sep_info[i].seid < AVDT_SEID_MIN) ||
+            (p_msg->discover_rsp.p_sep_info[i].seid > AVDT_SEID_MAX))
+        {
+            err = AVDT_ERR_SEID;
+            break;
+        }
+    }
+
+    return err;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_prs_svccap
+**
+** Description      This message parsing function parses a message containing
+**                  service capabilities parameters.
+**
+**
+** Returns          Error code or zero if no error.
+**
+*******************************************************************************/
+static uint8_t avdt_msg_prs_svccap(tAVDT_MSG *p_msg, uint8_t *p, uint16_t len)
+{
+    /* parse parameters */
+    uint8_t err = avdt_msg_prs_cfg(p_msg->svccap.p_cfg, p, len, &p_msg->hdr.err_param, AVDT_SIG_GETCAP);
+    if (p_msg->svccap.p_cfg)
+    {
+        p_msg->svccap.p_cfg->psc_mask &= AVDT_LEG_PSC;
+    }
+
+    return (err);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_prs_all_svccap
+**
+** Description      This message parsing function parses a message containing
+**                  service capabilities parameters.
+**
+**
+** Returns          Error code or zero if no error.
+**
+*******************************************************************************/
+static uint8_t avdt_msg_prs_all_svccap(tAVDT_MSG *p_msg, uint8_t *p, uint16_t len)
+{
+    uint8_t err = avdt_msg_prs_cfg(p_msg->svccap.p_cfg, p, len, &p_msg->hdr.err_param, AVDT_SIG_GET_ALLCAP);
+    if (p_msg->svccap.p_cfg)
+    {
+        p_msg->svccap.p_cfg->psc_mask &= AVDT_MSG_PSC_MASK;
+    }
+    return (err);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_prs_security_rsp
+**
+** Description      This message parsing function parsing a security
+**                  response message.
+**
+**
+** Returns          Error code or zero if no error.
+**
+*******************************************************************************/
+static uint8_t avdt_msg_prs_security_rsp(tAVDT_MSG *p_msg, uint8_t *p, uint16_t len)
+{
+    p_msg->security_rsp.p_data = p;
+    p_msg->security_rsp.len = len;
+
+    return 0;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_prs_rej
+**
+** Description
+**
+**
+** Returns          Error code or zero if no error.
+**
+*******************************************************************************/
+static uint8_t avdt_msg_prs_rej(tAVDT_MSG *p_msg, uint8_t *p, uint8_t sig)
+{
+    if ((sig == AVDT_SIG_SETCONFIG) || (sig == AVDT_SIG_RECONFIG))
+    {
+        p_msg->hdr.err_param = *p++;
+        p_msg->hdr.err_code = *p;
+    }
+    else if ((sig == AVDT_SIG_START) || (sig == AVDT_SIG_SUSPEND))
+    {
+        AVDT_MSG_PRS_SEID(p, p_msg->hdr.err_param);
+        p_msg->hdr.err_code = *p;
+    }
+    else
+    {
+        p_msg->hdr.err_code = *p;
+    }
+
+    return 0;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_prs_delay_rpt
+**
+** Description      This message parsing function parses a security
+**                  command message.
+**
+**
+** Returns          Error code or zero if no error.
+**
+*******************************************************************************/
+static uint8_t avdt_msg_prs_delay_rpt (tAVDT_MSG *p_msg, uint8_t *p, uint16_t len)
+{
+    uint8_t     err = 0;
+
+    /* verify len */
+    if (len != AVDT_LEN_DELAY_RPT)
+    {
+        AVDT_TRACE_WARNING("avdt_msg_prs_delay_rpt expected len: %u  got: %u", AVDT_LEN_DELAY_RPT, len);
+        err = AVDT_ERR_LENGTH;
+    }
+    else
+    {
+        /* get seid */
+        AVDT_MSG_PRS_SEID (p, p_msg->delay_rpt_cmd.hdr.seid);
+
+        if (avdt_scb_by_hdl(p_msg->delay_rpt_cmd.hdr.seid) == NULL)
+        {
+            err = AVDT_ERR_SEID;
+        }
+        else
+        {
+            BE_STREAM_TO_UINT16 (p_msg->delay_rpt_cmd.delay, p);
+            AVDT_TRACE_DEBUG("avdt_msg_prs_delay_rpt delay: %u", p_msg->delay_rpt_cmd.delay);
+        }
+    }
+    return err;
+}
+
+
+/*******************************************************************************
+**
+** Function         avdt_msg_send
+**
+** Description      Send, and if necessary fragment the next message.
+**
+**
+** Returns          Congested state; true if CCB congested, false if not.
+**
+*******************************************************************************/
+bool    avdt_msg_send(tAVDT_CCB *p_ccb, BT_HDR *p_msg)
+{
+    uint16_t        curr_msg_len;
+    uint8_t         pkt_type;
+    uint8_t         hdr_len;
+    tAVDT_TC_TBL    *p_tbl;
+    BT_HDR          *p_buf;
+    uint8_t         *p;
+    uint8_t         label;
+    uint8_t         msg;
+    uint8_t         sig;
+    uint8_t         nosp = 0;       /* number of subsequent packets */
+
+    /* look up transport channel table entry to get peer mtu */
+    p_tbl = avdt_ad_tc_tbl_by_type(AVDT_CHAN_SIG, p_ccb, NULL);
+
+    /* set the current message if there is a message passed in */
+    if (p_msg != NULL)
+    {
+        p_ccb->p_curr_msg = p_msg;
+    }
+
+    /* store copy of curr_msg->len */
+    curr_msg_len = p_ccb->p_curr_msg->len;
+
+    /* while not congested and we haven't sent it all */
+    while ((!p_ccb->cong) && (p_ccb->p_curr_msg != NULL))
+    {
+        /* check what kind of message we've got here; we are using the offset
+        ** to indicate that a message is being fragmented
+        */
+
+        /* if message isn't being fragmented and it fits in mtu */
+        if ((p_ccb->p_curr_msg->offset == AVDT_MSG_OFFSET) &&
+            (p_ccb->p_curr_msg->len <= p_tbl->peer_mtu - AVDT_LEN_TYPE_SINGLE))
+        {
+            pkt_type = AVDT_PKT_TYPE_SINGLE;
+            hdr_len = AVDT_LEN_TYPE_SINGLE;
+            p_buf = p_ccb->p_curr_msg;
+        }
+        /* if message isn't being fragmented and it doesn't fit in mtu */
+        else if ((p_ccb->p_curr_msg->offset == AVDT_MSG_OFFSET) &&
+                 (p_ccb->p_curr_msg->len > p_tbl->peer_mtu - AVDT_LEN_TYPE_SINGLE))
+        {
+            pkt_type = AVDT_PKT_TYPE_START;
+            hdr_len = AVDT_LEN_TYPE_START;
+            nosp = (p_ccb->p_curr_msg->len + AVDT_LEN_TYPE_START - p_tbl->peer_mtu) /
+                   (p_tbl->peer_mtu - 1) + 2;
+
+            /* get a new buffer for fragment we are sending */
+            p_buf = (BT_HDR *)osi_malloc(AVDT_CMD_BUF_SIZE);
+
+            /* copy portion of data from current message to new buffer */
+            p_buf->offset = L2CAP_MIN_OFFSET + hdr_len;
+            p_buf->len = p_tbl->peer_mtu - hdr_len;
+            memcpy((uint8_t *)(p_buf + 1) + p_buf->offset,
+                   (uint8_t *)(p_ccb->p_curr_msg + 1) + p_ccb->p_curr_msg->offset, p_buf->len);
+        }
+        /* if message is being fragmented and remaining bytes don't fit in mtu */
+        else if ((p_ccb->p_curr_msg->offset > AVDT_MSG_OFFSET) &&
+                 (p_ccb->p_curr_msg->len > (p_tbl->peer_mtu - AVDT_LEN_TYPE_CONT)))
+        {
+            pkt_type = AVDT_PKT_TYPE_CONT;
+            hdr_len = AVDT_LEN_TYPE_CONT;
+
+            /* get a new buffer for fragment we are sending */
+            p_buf = (BT_HDR *)osi_malloc(AVDT_CMD_BUF_SIZE);
+
+            /* copy portion of data from current message to new buffer */
+            p_buf->offset = L2CAP_MIN_OFFSET + hdr_len;
+            p_buf->len = p_tbl->peer_mtu - hdr_len;
+            memcpy((uint8_t *)(p_buf + 1) + p_buf->offset,
+                   (uint8_t *)(p_ccb->p_curr_msg + 1) + p_ccb->p_curr_msg->offset, p_buf->len);
+        }
+        /* if message is being fragmented and remaining bytes do fit in mtu */
+        else
+        {
+            pkt_type = AVDT_PKT_TYPE_END;
+            hdr_len = AVDT_LEN_TYPE_END;
+            p_buf = p_ccb->p_curr_msg;
+        }
+
+        /* label, sig id, msg type are in hdr of p_curr_msg */
+        label = AVDT_LAYERSPEC_LABEL(p_ccb->p_curr_msg->layer_specific);
+        msg = AVDT_LAYERSPEC_MSG(p_ccb->p_curr_msg->layer_specific);
+        sig = (uint8_t) p_ccb->p_curr_msg->event;
+        AVDT_TRACE_DEBUG("avdt_msg_send label:%d, msg:%d, sig:%d", label, msg, sig);
+
+        /* keep track of how much of msg we've sent */
+        curr_msg_len -= p_buf->len;
+        if (curr_msg_len == 0)
+        {
+            /* entire message sent; mark as finished */
+            p_ccb->p_curr_msg = NULL;
+
+            /* start timer here for commands */
+            if (msg == AVDT_MSG_TYPE_CMD)
+            {
+                /* if retransmit timeout set to zero, sig doesn't use retransmit */
+                if ((sig == AVDT_SIG_DISCOVER) || (sig == AVDT_SIG_GETCAP) ||
+                    (sig == AVDT_SIG_SECURITY) || (avdt_cb.rcb.ret_tout == 0))
+                {
+                    alarm_cancel(p_ccb->idle_ccb_timer);
+                    alarm_cancel(p_ccb->ret_ccb_timer);
+                    period_ms_t interval_ms = avdt_cb.rcb.sig_tout * 1000;
+                    alarm_set_on_queue(p_ccb->rsp_ccb_timer, interval_ms,
+                                       avdt_ccb_rsp_ccb_timer_timeout, p_ccb,
+                                       btu_general_alarm_queue);
+                }
+                else if (sig != AVDT_SIG_DELAY_RPT)
+                {
+                    alarm_cancel(p_ccb->idle_ccb_timer);
+                    alarm_cancel(p_ccb->rsp_ccb_timer);
+                    period_ms_t interval_ms = avdt_cb.rcb.ret_tout * 1000;
+                    alarm_set_on_queue(p_ccb->ret_ccb_timer, interval_ms,
+                                       avdt_ccb_ret_ccb_timer_timeout, p_ccb,
+                                       btu_general_alarm_queue);
+                }
+            }
+        }
+        else
+        {
+            /* message being fragmented and not completely sent */
+            p_ccb->p_curr_msg->len -= p_buf->len;
+            p_ccb->p_curr_msg->offset += p_buf->len;
+        }
+
+        /* set up to build header */
+        p_buf->len += hdr_len;
+        p_buf->offset -= hdr_len;
+        p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+        /* build header */
+        AVDT_MSG_BLD_HDR(p, label, pkt_type, msg);
+        if (pkt_type == AVDT_PKT_TYPE_START)
+        {
+            AVDT_MSG_BLD_NOSP(p, nosp);
+        }
+        if ((pkt_type == AVDT_PKT_TYPE_START) || (pkt_type == AVDT_PKT_TYPE_SINGLE))
+        {
+            AVDT_MSG_BLD_SIG(p, sig);
+        }
+
+        /* send msg buffer down */
+        avdt_ad_write_req(AVDT_CHAN_SIG, p_ccb, NULL, p_buf);
+    }
+    return (p_ccb->cong);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_asmbl
+**
+** Description      Reassemble incoming message.
+**
+**
+** Returns          Pointer to reassembled message;  NULL if no message
+**                  available.
+**
+*******************************************************************************/
+BT_HDR *avdt_msg_asmbl(tAVDT_CCB *p_ccb, BT_HDR *p_buf)
+{
+    uint8_t *p;
+    uint8_t pkt_type;
+    BT_HDR  *p_ret;
+
+    /* parse the message header */
+    p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+    AVDT_MSG_PRS_PKT_TYPE(p, pkt_type);
+
+    /* quick sanity check on length */
+    if (p_buf->len < avdt_msg_pkt_type_len[pkt_type])
+    {
+        osi_free(p_buf);
+        AVDT_TRACE_WARNING("Bad length during reassembly");
+        p_ret = NULL;
+    }
+    /* single packet */
+    else if (pkt_type == AVDT_PKT_TYPE_SINGLE)
+    {
+        /* if reassembly in progress drop message and process new single */
+        if (p_ccb->p_rx_msg != NULL)
+            AVDT_TRACE_WARNING("Got single during reassembly");
+
+        osi_free_and_reset((void **)&p_ccb->p_rx_msg);
+
+        p_ret = p_buf;
+    }
+    /* start packet */
+    else if (pkt_type == AVDT_PKT_TYPE_START)
+    {
+        /* if reassembly in progress drop message and process new single */
+        if (p_ccb->p_rx_msg != NULL)
+            AVDT_TRACE_WARNING("Got start during reassembly");
+
+        osi_free_and_reset((void **)&p_ccb->p_rx_msg);
+
+        /*
+         * Allocate bigger buffer for reassembly. As lower layers are
+         * not aware of possible packet size after reassembly, they
+         * would have allocated smaller buffer.
+         */
+        p_ccb->p_rx_msg = (BT_HDR *)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+        memcpy(p_ccb->p_rx_msg, p_buf,
+               sizeof(BT_HDR) + p_buf->offset + p_buf->len);
+
+        /* Free original buffer */
+        osi_free(p_buf);
+
+        /* update p to point to new buffer */
+        p = (uint8_t *)(p_ccb->p_rx_msg + 1) + p_ccb->p_rx_msg->offset;
+
+        /* copy first header byte over nosp */
+        *(p + 1) = *p;
+
+        /* set offset to point to where to copy next */
+        p_ccb->p_rx_msg->offset += p_ccb->p_rx_msg->len;
+
+        /* adjust length for packet header */
+        p_ccb->p_rx_msg->len -= 1;
+
+        p_ret = NULL;
+    }
+    /* continue or end */
+    else
+    {
+        /* if no reassembly in progress drop message */
+        if (p_ccb->p_rx_msg == NULL)
+        {
+            osi_free(p_buf);
+            AVDT_TRACE_WARNING("Pkt type=%d out of order", pkt_type);
+            p_ret = NULL;
+        }
+        else
+        {
+            /* get size of buffer holding assembled message */
+            /*
+             * NOTE: The buffer is allocated above at the beginning of the
+             * reassembly, and is always of size BT_DEFAULT_BUFFER_SIZE.
+             */
+            uint16_t buf_len = BT_DEFAULT_BUFFER_SIZE - sizeof(BT_HDR);
+
+            /* adjust offset and len of fragment for header byte */
+            p_buf->offset += AVDT_LEN_TYPE_CONT;
+            p_buf->len -= AVDT_LEN_TYPE_CONT;
+
+            /* verify length */
+            if ((p_ccb->p_rx_msg->offset + p_buf->len) > buf_len) {
+                /* won't fit; free everything */
+                AVDT_TRACE_WARNING("%s: Fragmented message too big!", __func__);
+                osi_free_and_reset((void **)&p_ccb->p_rx_msg);
+                osi_free(p_buf);
+                p_ret = NULL;
+            } else {
+                /* copy contents of p_buf to p_rx_msg */
+                memcpy((uint8_t *)(p_ccb->p_rx_msg + 1) + p_ccb->p_rx_msg->offset,
+                       (uint8_t *)(p_buf + 1) + p_buf->offset, p_buf->len);
+
+                if (pkt_type == AVDT_PKT_TYPE_END)
+                {
+                    p_ccb->p_rx_msg->offset -= p_ccb->p_rx_msg->len;
+                    p_ccb->p_rx_msg->len += p_buf->len;
+                    p_ret = p_ccb->p_rx_msg;
+                    p_ccb->p_rx_msg = NULL;
+                }
+                else
+                {
+                    p_ccb->p_rx_msg->offset += p_buf->len;
+                    p_ccb->p_rx_msg->len += p_buf->len;
+                    p_ret = NULL;
+                }
+                osi_free(p_buf);
+            }
+        }
+    }
+    return p_ret;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_send_cmd
+**
+** Description      This function is called to send a command message.  The
+**                  sig_id parameter indicates the message type, p_params
+**                  points to the message parameters, if any.  It gets a buffer
+**                  from the AVDTP command pool, executes the message building
+**                  function for this message type.  It then queues the message
+**                  in the command queue for this CCB.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_msg_send_cmd(tAVDT_CCB *p_ccb, void *p_scb, uint8_t sig_id, tAVDT_MSG *p_params)
+{
+    uint8_t *p;
+    uint8_t *p_start;
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(AVDT_CMD_BUF_SIZE);
+
+    /* set up buf pointer and offset */
+    p_buf->offset = AVDT_MSG_OFFSET;
+    p_start = p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+    /* execute parameter building function to build message */
+    (*avdt_msg_bld_cmd[sig_id - 1])(&p, p_params);
+
+    /* set len */
+    p_buf->len = (uint16_t) (p - p_start);
+
+    /* now store scb hdls, if any, in buf */
+    if (p_scb != NULL)
+    {
+        p = (uint8_t *)(p_buf + 1);
+
+        /* for start and suspend, p_scb points to array of handles */
+        if ((sig_id == AVDT_SIG_START) || (sig_id == AVDT_SIG_SUSPEND))
+        {
+            memcpy(p, (uint8_t *) p_scb, p_buf->len);
+        }
+        /* for all others, p_scb points to scb as usual */
+        else
+        {
+            *p = avdt_scb_to_hdl((tAVDT_SCB *) p_scb);
+        }
+    }
+
+    /* stash sig, label, and message type in buf */
+    p_buf->event = sig_id;
+    AVDT_BLD_LAYERSPEC(p_buf->layer_specific, AVDT_MSG_TYPE_CMD, p_ccb->label);
+
+    /* increment label */
+    p_ccb->label = (p_ccb->label + 1) % 16;
+
+    /* queue message and trigger ccb to send it */
+    fixed_queue_enqueue(p_ccb->cmd_q, p_buf);
+    avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         avdt_msg_send_rsp
+**
+** Description      This function is called to send a response message.  The
+**                  sig_id parameter indicates the message type, p_params
+**                  points to the message parameters, if any.  It gets a buffer
+**                  from the AVDTP command pool, executes the message building
+**                  function for this message type.  It then queues the message
+**                  in the response queue for this CCB.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_msg_send_rsp(tAVDT_CCB *p_ccb, uint8_t sig_id, tAVDT_MSG *p_params)
+{
+    uint8_t *p;
+    uint8_t *p_start;
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(AVDT_CMD_BUF_SIZE);
+
+    /* set up buf pointer and offset */
+    p_buf->offset = AVDT_MSG_OFFSET;
+    p_start = p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+    /* execute parameter building function to build message */
+    (*avdt_msg_bld_rsp[sig_id - 1])(&p, p_params);
+
+    /* set length */
+    p_buf->len = (uint16_t) (p - p_start);
+
+    /* stash sig, label, and message type in buf */
+    p_buf->event = sig_id;
+    AVDT_BLD_LAYERSPEC(p_buf->layer_specific, AVDT_MSG_TYPE_RSP, p_params->hdr.label);
+
+    /* queue message and trigger ccb to send it */
+    fixed_queue_enqueue(p_ccb->rsp_q, p_buf);
+    avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         avdt_msg_send_rej
+**
+** Description      This function is called to send a reject message.  The
+**                  sig_id parameter indicates the message type.  It gets
+**                  a buffer from the AVDTP command pool and builds the
+**                  message based on the message type and the error code.
+**                  It then queues the message in the response queue for
+**                  this CCB.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_msg_send_rej(tAVDT_CCB *p_ccb, uint8_t sig_id, tAVDT_MSG *p_params)
+{
+    uint8_t *p;
+    uint8_t *p_start;
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(AVDT_CMD_BUF_SIZE);
+
+    /* set up buf pointer and offset */
+    p_buf->offset = AVDT_MSG_OFFSET;
+    p_start = p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+    /* if sig id included, build into message */
+    if (sig_id != AVDT_SIG_NONE)
+    {
+        /* if this sig has a parameter, add the parameter */
+        if ((sig_id == AVDT_SIG_SETCONFIG) ||
+            (sig_id == AVDT_SIG_RECONFIG))
+        {
+            AVDT_MSG_BLD_PARAM(p, p_params->hdr.err_param);
+        }
+        else if ((sig_id == AVDT_SIG_START) ||
+                 (sig_id == AVDT_SIG_SUSPEND))
+        {
+            AVDT_MSG_BLD_SEID(p, p_params->hdr.err_param);
+        }
+
+        /* add the error code */
+        AVDT_MSG_BLD_ERR(p, p_params->hdr.err_code);
+    }
+    AVDT_TRACE_DEBUG("avdt_msg_send_rej");
+
+    /* calculate length */
+    p_buf->len = (uint16_t) (p - p_start);
+
+    /* stash sig, label, and message type in buf */
+    p_buf->event = sig_id;
+    AVDT_BLD_LAYERSPEC(p_buf->layer_specific, AVDT_MSG_TYPE_REJ, p_params->hdr.label);
+
+    /* queue message and trigger ccb to send it */
+    fixed_queue_enqueue(p_ccb->rsp_q, p_buf);
+    avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_send_grej
+**
+** Description      This function is called to send a general reject message.  The
+**                  sig_id parameter indicates the message type.  It gets
+**                  a buffer from the AVDTP command pool and builds the
+**                  message based on the message type and the error code.
+**                  It then queues the message in the response queue for
+**                  this CCB.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_msg_send_grej(tAVDT_CCB *p_ccb, uint8_t sig_id, tAVDT_MSG *p_params)
+{
+    uint8_t *p;
+    uint8_t *p_start;
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(AVDT_CMD_BUF_SIZE);
+
+    /* set up buf pointer and offset */
+    p_buf->offset = AVDT_MSG_OFFSET;
+    p_start = p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+    /* calculate length */
+    p_buf->len = (uint16_t) (p - p_start);
+
+    /* stash sig, label, and message type in buf */
+    p_buf->event = sig_id;
+    AVDT_BLD_LAYERSPEC(p_buf->layer_specific, AVDT_MSG_TYPE_GRJ, p_params->hdr.label);
+    AVDT_TRACE_DEBUG(__func__);
+
+    /* queue message and trigger ccb to send it */
+    fixed_queue_enqueue(p_ccb->rsp_q, p_buf);
+    avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_msg_ind
+**
+** Description      This function is called by the adaption layer when an
+**                  incoming message is received on the signaling channel.
+**                  It parses the message and sends an event to the appropriate
+**                  SCB or CCB for the message.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_msg_ind(tAVDT_CCB *p_ccb, BT_HDR *p_buf)
+{
+    tAVDT_SCB   *p_scb;
+    uint8_t     *p;
+    bool        ok = true;
+    bool        handle_rsp = false;
+    bool        gen_rej = false;
+    uint8_t     label;
+    uint8_t     pkt_type;
+    uint8_t     msg_type;
+    uint8_t     sig = 0;
+    tAVDT_MSG   msg;
+    tAVDT_CFG   cfg;
+    uint8_t     err;
+    uint8_t     evt = 0;
+    uint8_t     scb_hdl;
+
+    /* reassemble message; if no message available (we received a fragment) return */
+    if ((p_buf = avdt_msg_asmbl(p_ccb, p_buf)) == NULL)
+    {
+        return;
+    }
+
+    p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+    /* parse the message header */
+    AVDT_MSG_PRS_HDR(p, label, pkt_type, msg_type);
+
+    AVDT_TRACE_DEBUG("msg_type=%d, sig=%d", msg_type, sig);
+    /* set up label and ccb_idx in message hdr */
+    msg.hdr.label = label;
+    msg.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb);
+
+    /* verify msg type */
+    if (msg_type == AVDT_MSG_TYPE_GRJ)
+    {
+        AVDT_TRACE_WARNING("Dropping msg msg_type=%d", msg_type);
+        ok = false;
+    }
+    /* check for general reject */
+    else if ((msg_type == AVDT_MSG_TYPE_REJ) && (p_buf->len == AVDT_LEN_GEN_REJ))
+    {
+        gen_rej = true;
+        if (p_ccb->p_curr_cmd != NULL)
+        {
+            msg.hdr.sig_id = sig = (uint8_t) p_ccb->p_curr_cmd->event;
+            evt = avdt_msg_rej_2_evt[sig - 1];
+            msg.hdr.err_code = AVDT_ERR_NSC;
+            msg.hdr.err_param = 0;
+        }
+    }
+    else /* not a general reject */
+    {
+        /* get and verify signal */
+        AVDT_MSG_PRS_SIG(p, sig);
+        msg.hdr.sig_id = sig;
+        if ((sig == 0) || (sig > AVDT_SIG_MAX))
+        {
+            AVDT_TRACE_WARNING("Dropping msg sig=%d msg_type:%d", sig, msg_type);
+            ok = false;
+
+            /* send a general reject */
+            if (msg_type == AVDT_MSG_TYPE_CMD)
+            {
+                avdt_msg_send_grej(p_ccb, sig, &msg);
+            }
+        }
+    }
+
+    if (ok && !gen_rej)
+    {
+        /* skip over header (msg length already verified during reassembly) */
+        p_buf->len -= AVDT_LEN_TYPE_SINGLE;
+
+        /* set up to parse message */
+        if ((msg_type == AVDT_MSG_TYPE_RSP) && (sig == AVDT_SIG_DISCOVER))
+        {
+            /* parse discover rsp message to struct supplied by app */
+            msg.discover_rsp.p_sep_info = (tAVDT_SEP_INFO *) p_ccb->p_proc_data;
+            msg.discover_rsp.num_seps = p_ccb->proc_param;
+        }
+        else if ((msg_type == AVDT_MSG_TYPE_RSP) &&
+            ((sig == AVDT_SIG_GETCAP) || (sig == AVDT_SIG_GET_ALLCAP)))
+        {
+            /* parse discover rsp message to struct supplied by app */
+            msg.svccap.p_cfg = (tAVDT_CFG *) p_ccb->p_proc_data;
+        }
+        else if ((msg_type == AVDT_MSG_TYPE_RSP) && (sig == AVDT_SIG_GETCONFIG))
+        {
+            /* parse get config rsp message to struct allocated locally */
+            msg.svccap.p_cfg = &cfg;
+        }
+        else if ((msg_type == AVDT_MSG_TYPE_CMD) && (sig == AVDT_SIG_SETCONFIG))
+        {
+            /* parse config cmd message to struct allocated locally */
+            msg.config_cmd.p_cfg = &cfg;
+        }
+        else if ((msg_type == AVDT_MSG_TYPE_CMD) && (sig == AVDT_SIG_RECONFIG))
+        {
+            /* parse reconfig cmd message to struct allocated locally */
+            msg.reconfig_cmd.p_cfg = &cfg;
+        }
+
+        /* parse message; while we're at it map message sig to event */
+        if (msg_type == AVDT_MSG_TYPE_CMD)
+        {
+            msg.hdr.err_code = err = (*avdt_msg_prs_cmd[sig - 1])(&msg, p, p_buf->len);
+            evt = avdt_msg_cmd_2_evt[sig - 1];
+        }
+        else if (msg_type == AVDT_MSG_TYPE_RSP)
+        {
+            msg.hdr.err_code = err = (*avdt_msg_prs_rsp[sig - 1])(&msg, p, p_buf->len);
+            evt = avdt_msg_rsp_2_evt[sig - 1];
+        }
+        else /* msg_type == AVDT_MSG_TYPE_REJ */
+        {
+            err = avdt_msg_prs_rej(&msg, p, sig);
+            evt = avdt_msg_rej_2_evt[sig - 1];
+        }
+
+        /* if parsing failed */
+        if (err != 0)
+        {
+            AVDT_TRACE_WARNING("Parsing failed sig=%d err=0x%x", sig, err);
+
+            /* if its a rsp or rej, drop it; if its a cmd, send a rej;
+            ** note special case for abort; never send abort reject
+            */
+            ok = false;
+            if ((msg_type == AVDT_MSG_TYPE_CMD) && (sig != AVDT_SIG_ABORT))
+            {
+                avdt_msg_send_rej(p_ccb, sig, &msg);
+            }
+        }
+    }
+
+    /* if its a rsp or rej, check sent cmd to see if we're waiting for
+    ** the rsp or rej.  If we didn't send a cmd for it, drop it.  If
+    ** it does match a cmd, stop timer for the cmd.
+    */
+    if (ok)
+    {
+        if ((msg_type == AVDT_MSG_TYPE_RSP) || (msg_type == AVDT_MSG_TYPE_REJ))
+        {
+            if ((p_ccb->p_curr_cmd != NULL) &&
+                (p_ccb->p_curr_cmd->event == sig) &&
+                (AVDT_LAYERSPEC_LABEL(p_ccb->p_curr_cmd->layer_specific) == label))
+            {
+                /* stop timer */
+                alarm_cancel(p_ccb->idle_ccb_timer);
+                alarm_cancel(p_ccb->ret_ccb_timer);
+                alarm_cancel(p_ccb->rsp_ccb_timer);
+
+                /* clear retransmission count */
+                p_ccb->ret_count = 0;
+
+                /* later in this function handle ccb event */
+                handle_rsp = true;
+            }
+            else
+            {
+                ok = false;
+                AVDT_TRACE_WARNING("Cmd not found for rsp sig=%d label=%d", sig, label);
+            }
+        }
+    }
+
+    if (ok)
+    {
+        /* if it's a ccb event send to ccb */
+        if (evt & AVDT_CCB_MKR)
+        {
+            avdt_ccb_event(p_ccb, (uint8_t)(evt & ~AVDT_CCB_MKR), (tAVDT_CCB_EVT *) &msg);
+        }
+        /* if it's a scb event */
+        else
+        {
+            /* Scb events always have a single seid.  For cmd, get seid from
+            ** message.  For rej and rsp, get seid from p_curr_cmd.
+            */
+            if (msg_type == AVDT_MSG_TYPE_CMD)
+            {
+                scb_hdl = msg.single.seid;
+            }
+            else
+            {
+                scb_hdl = *((uint8_t *)(p_ccb->p_curr_cmd + 1));
+            }
+
+            /* Map seid to the scb and send it the event.  For cmd, seid has
+            ** already been verified by parsing function.
+            */
+            if (evt && (p_scb = avdt_scb_by_hdl(scb_hdl)) != NULL)
+            {
+                avdt_scb_event(p_scb, evt, (tAVDT_SCB_EVT *) &msg);
+            }
+        }
+    }
+
+    /* free message buffer */
+    osi_free(p_buf);
+
+    /* if its a rsp or rej, send event to ccb to free associated
+    ** cmd msg buffer and handle cmd queue
+    */
+    if (handle_rsp)
+    {
+        avdt_ccb_event(p_ccb, AVDT_CCB_RCVRSP_EVT, NULL);
+    }
+}
diff --git a/bt/stack/avdt/avdt_scb.cc b/bt/stack/avdt/avdt_scb.cc
new file mode 100644
index 0000000..8280759
--- /dev/null
+++ b/bt/stack/avdt/avdt_scb.cc
@@ -0,0 +1,770 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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 module contains the stream control block and functions which
+ *  operate on the stream control block.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "bt_common.h"
+#include "btu.h"
+#include "osi/include/osi.h"
+
+/*****************************************************************************
+** state machine constants and types
+*****************************************************************************/
+#if (AVDT_DEBUG == TRUE)
+
+/* verbose state strings for trace */
+const char * const avdt_scb_st_str[] = {
+    "SCB_IDLE_ST",
+    "SCB_CONF_ST",
+    "SCB_OPENING_ST",
+    "SCB_OPEN_ST",
+    "SCB_STREAM_ST",
+    "SCB_CLOSING_ST"
+};
+
+/* verbose event strings for trace */
+const char * const avdt_scb_evt_str[] = {
+    "API_REMOVE_EVT",
+    "API_WRITE_REQ_EVT",
+    "API_GETCONFIG_REQ_EVT",
+    "API_DELAY_RPT_REQ",
+    "API_SETCONFIG_REQ_EVT",
+    "API_OPEN_REQ_EVT",
+    "API_CLOSE_REQ_EVT",
+    "API_RECONFIG_REQ_EVT",
+    "API_SECURITY_REQ_EVT",
+    "API_ABORT_REQ_EVT",
+    "API_GETCONFIG_RSP_EVT",
+    "API_SETCONFIG_RSP_EVT",
+    "API_SETCONFIG_REJ_EVT",
+    "API_OPEN_RSP_EVT",
+    "API_CLOSE_RSP_EVT",
+    "API_RECONFIG_RSP_EVT",
+    "API_SECURITY_RSP_EVT",
+    "API_ABORT_RSP_EVT",
+    "MSG_SETCONFIG_CMD_EVT",
+    "MSG_GETCONFIG_CMD_EVT",
+    "MSG_OPEN_CMD_EVT",
+    "MSG_START_CMD_EVT",
+    "MSG_SUSPEND_CMD_EVT",
+    "MSG_CLOSE_CMD_EVT",
+    "MSG_ABORT_CMD_EVT",
+    "MSG_RECONFIG_CMD_EVT",
+    "MSG_SECURITY_CMD_EVT",
+    "MSG_DELAY_RPT_CMD_EVT",
+    "MSG_DELAY_RPT_RSP_EVT",
+    "MSG_SETCONFIG_RSP_EVT",
+    "MSG_GETCONFIG_RSP_EVT",
+    "MSG_OPEN_RSP_EVT",
+    "MSG_START_RSP_EVT",
+    "MSG_SUSPEND_RSP_EVT",
+    "MSG_CLOSE_RSP_EVT",
+    "MSG_ABORT_RSP_EVT",
+    "MSG_RECONFIG_RSP_EVT",
+    "MSG_SECURITY_RSP_EVT",
+    "MSG_SETCONFIG_REJ_EVT",
+    "MSG_OPEN_REJ_EVT",
+    "MSG_START_REJ_EVT",
+    "MSG_SUSPEND_REJ_EVT",
+    "TC_TOUT_EVT",
+    "TC_OPEN_EVT",
+    "TC_CLOSE_EVT",
+    "TC_CONG_EVT",
+    "TC_DATA_EVT",
+    "CC_CLOSE_EVT"
+};
+
+#endif
+
+
+/* action function list */
+const tAVDT_SCB_ACTION avdt_scb_action[] = {
+    avdt_scb_hdl_abort_cmd,
+    avdt_scb_hdl_abort_rsp,
+    avdt_scb_hdl_close_cmd,
+    avdt_scb_hdl_close_rsp,
+    avdt_scb_hdl_getconfig_cmd,
+    avdt_scb_hdl_getconfig_rsp,
+    avdt_scb_hdl_open_cmd,
+    avdt_scb_hdl_open_rej,
+    avdt_scb_hdl_open_rsp,
+    avdt_scb_hdl_pkt,
+    avdt_scb_drop_pkt,
+    avdt_scb_hdl_reconfig_cmd,
+    avdt_scb_hdl_reconfig_rsp,
+    avdt_scb_hdl_security_cmd,
+    avdt_scb_hdl_security_rsp,
+    avdt_scb_hdl_setconfig_cmd,
+    avdt_scb_hdl_setconfig_rej,
+    avdt_scb_hdl_setconfig_rsp,
+    avdt_scb_hdl_start_cmd,
+    avdt_scb_hdl_start_rsp,
+    avdt_scb_hdl_suspend_cmd,
+    avdt_scb_hdl_suspend_rsp,
+    avdt_scb_hdl_tc_close,
+#if (AVDT_REPORTING == TRUE)
+    avdt_scb_hdl_tc_close_sto,
+#endif
+    avdt_scb_hdl_tc_open,
+#if (AVDT_REPORTING == TRUE)
+    avdt_scb_hdl_tc_open_sto,
+#endif
+    avdt_scb_snd_delay_rpt_req,
+    avdt_scb_hdl_delay_rpt_cmd,
+    avdt_scb_hdl_delay_rpt_rsp,
+    avdt_scb_hdl_write_req,
+    avdt_scb_snd_abort_req,
+    avdt_scb_snd_abort_rsp,
+    avdt_scb_snd_close_req,
+    avdt_scb_snd_stream_close,
+    avdt_scb_snd_close_rsp,
+    avdt_scb_snd_getconfig_req,
+    avdt_scb_snd_getconfig_rsp,
+    avdt_scb_snd_open_req,
+    avdt_scb_snd_open_rsp,
+    avdt_scb_snd_reconfig_req,
+    avdt_scb_snd_reconfig_rsp,
+    avdt_scb_snd_security_req,
+    avdt_scb_snd_security_rsp,
+    avdt_scb_snd_setconfig_req,
+    avdt_scb_snd_setconfig_rej,
+    avdt_scb_snd_setconfig_rsp,
+    avdt_scb_snd_tc_close,
+    avdt_scb_cb_err,
+    avdt_scb_cong_state,
+    avdt_scb_rej_state,
+    avdt_scb_rej_in_use,
+    avdt_scb_rej_not_in_use,
+    avdt_scb_set_remove,
+    avdt_scb_free_pkt,
+    avdt_scb_clr_pkt,
+    avdt_scb_chk_snd_pkt,
+    avdt_scb_transport_channel_timer,
+    avdt_scb_clr_vars,
+    avdt_scb_dealloc
+};
+
+/* state table information */
+#define AVDT_SCB_ACTIONS            2       /* number of actions */
+#define AVDT_SCB_NEXT_STATE         2       /* position of next state */
+#define AVDT_SCB_NUM_COLS           3       /* number of columns in state tables */
+
+/* state table for idle state */
+const uint8_t avdt_scb_st_idle[][AVDT_SCB_NUM_COLS] = {
+/* Event                     Action 1                       Action 2                    Next state */
+/* API_REMOVE_EVT */        {AVDT_SCB_DEALLOC,              AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* API_WRITE_REQ_EVT */     {AVDT_SCB_FREE_PKT,             AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_SND_SETCONFIG_REQ,    AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* API_OPEN_REQ_EVT */      {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* API_CLOSE_REQ_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* API_RECONFIG_REQ_EVT */  {AVDT_SCB_CB_ERR,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* API_SECURITY_REQ_EVT */  {AVDT_SCB_CB_ERR,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* API_ABORT_REQ_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_SND_SETCONFIG_RSP,    AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_SND_SETCONFIG_REJ,    AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* API_OPEN_RSP_EVT */      {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* API_CLOSE_RSP_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* API_RECONFIG_RSP_EVT */  {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* API_SECURITY_RSP_EVT */  {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* API_ABORT_RSP_EVT */     {AVDT_SCB_SND_ABORT_RSP,        AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_SETCONFIG_CMD,    AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_OPEN_CMD_EVT */      {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_START_CMD_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_SUSPEND_CMD_EVT */   {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_CLOSE_CMD_EVT */     {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_ABORT_CMD_EVT */     {AVDT_SCB_HDL_ABORT_CMD,        AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_RECONFIG_CMD_EVT */  {AVDT_SCB_REJ_NOT_IN_USE,       AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_SECURITY_CMD_EVT */  {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP,    AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_SETCONFIG_RSP,    AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_OPEN_RSP_EVT */      {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_START_RSP_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_SUSPEND_RSP_EVT */   {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_CLOSE_RSP_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_ABORT_RSP_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_RECONFIG_RSP_EVT */  {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_SECURITY_RSP_EVT */  {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_HDL_SETCONFIG_REJ,    AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_OPEN_REJ_EVT */      {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_START_REJ_EVT */     {AVDT_SCB_HDL_START_RSP,        AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_SUSPEND_REJ_EVT */   {AVDT_SCB_HDL_SUSPEND_RSP,      AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* TC_TOUT_EVT */           {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* TC_OPEN_EVT */           {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* TC_CLOSE_EVT */          {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* TC_CONG_EVT */           {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* TC_DATA_EVT */           {AVDT_SCB_DROP_PKT,             AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* CC_CLOSE_EVT */          {AVDT_SCB_CLR_VARS,             AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST}
+};
+
+/* state table for configured state */
+const uint8_t avdt_scb_st_conf[][AVDT_SCB_NUM_COLS] = {
+/* Event                     Action 1                       Action 2                    Next state */
+/* API_REMOVE_EVT */        {AVDT_SCB_SND_ABORT_REQ,        AVDT_SCB_SET_REMOVE,        AVDT_SCB_CONF_ST},
+/* API_WRITE_REQ_EVT */     {AVDT_SCB_FREE_PKT,             AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_SND_GETCONFIG_REQ,    AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_SND_DELAY_RPT_REQ,    AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR,               AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* API_OPEN_REQ_EVT */      {AVDT_SCB_SND_OPEN_REQ,         AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* API_CLOSE_REQ_EVT */     {AVDT_SCB_SND_ABORT_REQ,        AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* API_RECONFIG_REQ_EVT */  {AVDT_SCB_CB_ERR,               AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* API_SECURITY_REQ_EVT */  {AVDT_SCB_SND_SECURITY_REQ,     AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* API_ABORT_REQ_EVT */     {AVDT_SCB_SND_ABORT_REQ,        AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_SND_GETCONFIG_RSP,    AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* API_OPEN_RSP_EVT */      {AVDT_SCB_SND_OPEN_RSP,         AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* API_CLOSE_RSP_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* API_RECONFIG_RSP_EVT */  {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* API_SECURITY_RSP_EVT */  {AVDT_SCB_SND_SECURITY_RSP,     AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* API_ABORT_RSP_EVT */     {AVDT_SCB_SND_ABORT_RSP,        AVDT_SCB_HDL_TC_CLOSE,      AVDT_SCB_IDLE_ST},
+/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_IN_USE,           AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_GETCONFIG_CMD,    AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* MSG_OPEN_CMD_EVT */      {AVDT_SCB_HDL_OPEN_CMD,         AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* MSG_START_CMD_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* MSG_SUSPEND_CMD_EVT */   {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* MSG_CLOSE_CMD_EVT */     {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* MSG_ABORT_CMD_EVT */     {AVDT_SCB_HDL_ABORT_CMD,        AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* MSG_RECONFIG_CMD_EVT */  {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* MSG_SECURITY_CMD_EVT */  {AVDT_SCB_HDL_SECURITY_CMD,     AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_HDL_DELAY_RPT_CMD,    AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP,    AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_GETCONFIG_RSP,    AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* MSG_OPEN_RSP_EVT */      {AVDT_SCB_HDL_OPEN_RSP,         AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_START_RSP_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* MSG_SUSPEND_RSP_EVT */   {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* MSG_CLOSE_RSP_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* MSG_ABORT_RSP_EVT */     {AVDT_SCB_HDL_ABORT_RSP,        AVDT_SCB_HDL_TC_CLOSE,      AVDT_SCB_IDLE_ST},
+/* MSG_RECONFIG_RSP_EVT */  {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* MSG_SECURITY_RSP_EVT */  {AVDT_SCB_HDL_SECURITY_RSP,     AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* MSG_OPEN_REJ_EVT */      {AVDT_SCB_HDL_OPEN_REJ,         AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_START_REJ_EVT */     {AVDT_SCB_HDL_START_RSP,        AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* MSG_SUSPEND_REJ_EVT */   {AVDT_SCB_HDL_SUSPEND_RSP,      AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* TC_TOUT_EVT */           {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* TC_OPEN_EVT */           {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* TC_CLOSE_EVT */          {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* TC_CONG_EVT */           {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* TC_DATA_EVT */           {AVDT_SCB_DROP_PKT,             AVDT_SCB_IGNORE,            AVDT_SCB_CONF_ST},
+/* CC_CLOSE_EVT */          {AVDT_SCB_HDL_TC_CLOSE,         AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST}
+};
+
+/* state table for opening state */
+const uint8_t avdt_scb_st_opening[][AVDT_SCB_NUM_COLS] = {
+/* Event                     Action 1                       Action 2                    Next state */
+/* API_REMOVE_EVT */        {AVDT_SCB_SND_CLOSE_REQ,        AVDT_SCB_SET_REMOVE,        AVDT_SCB_CLOSING_ST},
+/* API_WRITE_REQ_EVT */     {AVDT_SCB_FREE_PKT,             AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_SND_GETCONFIG_REQ,    AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_SND_DELAY_RPT_REQ,    AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR,               AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* API_OPEN_REQ_EVT */      {AVDT_SCB_CB_ERR,               AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* API_CLOSE_REQ_EVT */     {AVDT_SCB_SND_CLOSE_REQ,        AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_REQ_EVT */  {AVDT_SCB_CB_ERR,               AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* API_SECURITY_REQ_EVT */  {AVDT_SCB_SND_SECURITY_REQ,     AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* API_ABORT_REQ_EVT */     {AVDT_SCB_SND_ABORT_REQ,        AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_SND_GETCONFIG_RSP,    AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* API_OPEN_RSP_EVT */      {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* API_CLOSE_RSP_EVT */     {AVDT_SCB_SND_CLOSE_RSP,        AVDT_SCB_SND_TC_CLOSE,      AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_RSP_EVT */  {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* API_SECURITY_RSP_EVT */  {AVDT_SCB_SND_SECURITY_RSP,     AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* API_ABORT_RSP_EVT */     {AVDT_SCB_SND_ABORT_RSP,        AVDT_SCB_SND_TC_CLOSE,      AVDT_SCB_CLOSING_ST},
+/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_GETCONFIG_CMD,    AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_OPEN_CMD_EVT */      {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_START_CMD_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_SUSPEND_CMD_EVT */   {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_CLOSE_CMD_EVT */     {AVDT_SCB_HDL_CLOSE_CMD,        AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_ABORT_CMD_EVT */     {AVDT_SCB_HDL_ABORT_CMD,        AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_RECONFIG_CMD_EVT */  {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_SECURITY_CMD_EVT */  {AVDT_SCB_HDL_SECURITY_CMD,     AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_HDL_DELAY_RPT_CMD,    AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP,    AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_GETCONFIG_RSP,    AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_OPEN_RSP_EVT */      {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_START_RSP_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_SUSPEND_RSP_EVT */   {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_CLOSE_RSP_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_ABORT_RSP_EVT */     {AVDT_SCB_SND_TC_CLOSE,         AVDT_SCB_HDL_ABORT_RSP,     AVDT_SCB_CLOSING_ST},
+/* MSG_RECONFIG_RSP_EVT */  {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_SECURITY_RSP_EVT */  {AVDT_SCB_HDL_SECURITY_RSP,     AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_OPEN_REJ_EVT */      {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_START_REJ_EVT */     {AVDT_SCB_HDL_START_RSP,        AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* MSG_SUSPEND_REJ_EVT */   {AVDT_SCB_HDL_SUSPEND_RSP,      AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* TC_TOUT_EVT */           {AVDT_SCB_SND_ABORT_REQ,        AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* TC_OPEN_EVT */           {AVDT_SCB_HDL_TC_OPEN,          AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* TC_CLOSE_EVT */          {AVDT_SCB_HDL_TC_CLOSE,         AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* TC_CONG_EVT */           {AVDT_SCB_CONG_STATE,           AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* TC_DATA_EVT */           {AVDT_SCB_DROP_PKT,             AVDT_SCB_IGNORE,            AVDT_SCB_OPENING_ST},
+/* CC_CLOSE_EVT */          {AVDT_SCB_SND_TC_CLOSE,         AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST}
+};
+
+/* state table for open state */
+const uint8_t avdt_scb_st_open[][AVDT_SCB_NUM_COLS] = {
+/* Event                     Action 1                       Action 2                    Next state */
+/* API_REMOVE_EVT */        {AVDT_SCB_SND_CLOSE_REQ,        AVDT_SCB_SET_REMOVE,        AVDT_SCB_CLOSING_ST},
+/* API_WRITE_REQ_EVT */     {AVDT_SCB_FREE_PKT,             AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_SND_GETCONFIG_REQ,    AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_SND_DELAY_RPT_REQ,    AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR,               AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* API_OPEN_REQ_EVT */      {AVDT_SCB_CB_ERR,               AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* API_CLOSE_REQ_EVT */     {AVDT_SCB_SND_CLOSE_REQ,        AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_REQ_EVT */  {AVDT_SCB_SND_RECONFIG_REQ,     AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* API_SECURITY_REQ_EVT */  {AVDT_SCB_SND_SECURITY_REQ,     AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* API_ABORT_REQ_EVT */     {AVDT_SCB_SND_ABORT_REQ,        AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_SND_GETCONFIG_RSP,    AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* API_OPEN_RSP_EVT */      {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* API_CLOSE_RSP_EVT */     {AVDT_SCB_SND_CLOSE_RSP,        AVDT_SCB_TC_TIMER,          AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_RSP_EVT */  {AVDT_SCB_SND_RECONFIG_RSP,     AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* API_SECURITY_RSP_EVT */  {AVDT_SCB_SND_SECURITY_RSP,     AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* API_ABORT_RSP_EVT */     {AVDT_SCB_SND_ABORT_RSP,        AVDT_SCB_TC_TIMER,          AVDT_SCB_CLOSING_ST},
+/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_GETCONFIG_CMD,    AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* MSG_OPEN_CMD_EVT */      {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* MSG_START_CMD_EVT */     {AVDT_SCB_HDL_START_CMD,        AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_SUSPEND_CMD_EVT */   {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* MSG_CLOSE_CMD_EVT */     {AVDT_SCB_HDL_CLOSE_CMD,        AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* MSG_ABORT_CMD_EVT */     {AVDT_SCB_HDL_ABORT_CMD,        AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* MSG_RECONFIG_CMD_EVT */  {AVDT_SCB_HDL_RECONFIG_CMD,     AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* MSG_SECURITY_CMD_EVT */  {AVDT_SCB_HDL_SECURITY_CMD,     AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_HDL_DELAY_RPT_CMD,    AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP,    AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_GETCONFIG_RSP,    AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* MSG_OPEN_RSP_EVT */      {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* MSG_START_RSP_EVT */     {AVDT_SCB_HDL_START_RSP,        AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_SUSPEND_RSP_EVT */   {AVDT_SCB_HDL_SUSPEND_RSP,      AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* MSG_CLOSE_RSP_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* MSG_ABORT_RSP_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* MSG_RECONFIG_RSP_EVT */  {AVDT_SCB_HDL_RECONFIG_RSP,     AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* MSG_SECURITY_RSP_EVT */  {AVDT_SCB_HDL_SECURITY_RSP,     AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* MSG_OPEN_REJ_EVT */      {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* MSG_START_REJ_EVT */     {AVDT_SCB_HDL_START_RSP,        AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* MSG_SUSPEND_REJ_EVT */   {AVDT_SCB_HDL_SUSPEND_RSP,      AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* TC_TOUT_EVT */           {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+#if (AVDT_REPORTING == TRUE)
+/* TC_OPEN_EVT */           {AVDT_SCB_HDL_TC_OPEN_STO,      AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* TC_CLOSE_EVT */          {AVDT_SCB_HDL_TC_CLOSE_STO,     AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+#else
+/* TC_OPEN_EVT */           {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* TC_CLOSE_EVT */          {AVDT_SCB_HDL_TC_CLOSE,         AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+#endif
+/* TC_CONG_EVT */           {AVDT_SCB_CONG_STATE,           AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* TC_DATA_EVT */           {AVDT_SCB_DROP_PKT,             AVDT_SCB_IGNORE,            AVDT_SCB_OPEN_ST},
+/* CC_CLOSE_EVT */          {AVDT_SCB_SND_TC_CLOSE,         AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST}
+};
+
+/* state table for streaming state */
+const uint8_t avdt_scb_st_stream[][AVDT_SCB_NUM_COLS] = {
+/* Event                     Action 1                       Action 2                    Next state */
+/* API_REMOVE_EVT */        {AVDT_SCB_SND_STREAM_CLOSE,     AVDT_SCB_SET_REMOVE,        AVDT_SCB_CLOSING_ST},
+/* API_WRITE_REQ_EVT */     {AVDT_SCB_HDL_WRITE_REQ,        AVDT_SCB_CHK_SND_PKT,       AVDT_SCB_STREAM_ST},
+/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_SND_GETCONFIG_REQ,    AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_SND_DELAY_RPT_REQ,    AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR,               AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* API_OPEN_REQ_EVT */      {AVDT_SCB_CB_ERR,               AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* API_CLOSE_REQ_EVT */     {AVDT_SCB_SND_STREAM_CLOSE,     AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_REQ_EVT */  {AVDT_SCB_CB_ERR,               AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* API_SECURITY_REQ_EVT */  {AVDT_SCB_SND_SECURITY_REQ,     AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* API_ABORT_REQ_EVT */     {AVDT_SCB_SND_ABORT_REQ,        AVDT_SCB_CLR_PKT,           AVDT_SCB_CLOSING_ST},
+/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_SND_GETCONFIG_RSP,    AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* API_OPEN_RSP_EVT */      {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* API_CLOSE_RSP_EVT */     {AVDT_SCB_SND_CLOSE_RSP,        AVDT_SCB_TC_TIMER,          AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_RSP_EVT */  {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* API_SECURITY_RSP_EVT */  {AVDT_SCB_SND_SECURITY_RSP,     AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* API_ABORT_RSP_EVT */     {AVDT_SCB_SND_ABORT_RSP,        AVDT_SCB_TC_TIMER,          AVDT_SCB_CLOSING_ST},
+/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_GETCONFIG_CMD,    AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_OPEN_CMD_EVT */      {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_START_CMD_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_SUSPEND_CMD_EVT */   {AVDT_SCB_HDL_SUSPEND_CMD,      AVDT_SCB_CLR_PKT,           AVDT_SCB_OPEN_ST},
+/* MSG_CLOSE_CMD_EVT */     {AVDT_SCB_HDL_CLOSE_CMD,        AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_ABORT_CMD_EVT */     {AVDT_SCB_HDL_ABORT_CMD,        AVDT_SCB_CLR_PKT,           AVDT_SCB_STREAM_ST},
+/* MSG_RECONFIG_CMD_EVT */  {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_SECURITY_CMD_EVT */  {AVDT_SCB_HDL_SECURITY_CMD,     AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_HDL_DELAY_RPT_CMD,    AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP,    AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_GETCONFIG_RSP,    AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_OPEN_RSP_EVT */      {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_START_RSP_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_SUSPEND_RSP_EVT */   {AVDT_SCB_HDL_SUSPEND_RSP,      AVDT_SCB_CLR_PKT,           AVDT_SCB_OPEN_ST},
+/* MSG_CLOSE_RSP_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_ABORT_RSP_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_RECONFIG_RSP_EVT */  {AVDT_SCB_HDL_RECONFIG_RSP,     AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_SECURITY_RSP_EVT */  {AVDT_SCB_HDL_SECURITY_RSP,     AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_OPEN_REJ_EVT */      {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_START_REJ_EVT */     {AVDT_SCB_HDL_START_RSP,        AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* MSG_SUSPEND_REJ_EVT */   {AVDT_SCB_HDL_SUSPEND_RSP,      AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* TC_TOUT_EVT */           {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* TC_OPEN_EVT */           {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* TC_CLOSE_EVT */          {AVDT_SCB_HDL_TC_CLOSE,         AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* TC_CONG_EVT */           {AVDT_SCB_CONG_STATE,           AVDT_SCB_CHK_SND_PKT,       AVDT_SCB_STREAM_ST},
+/* TC_DATA_EVT */           {AVDT_SCB_HDL_PKT,              AVDT_SCB_IGNORE,            AVDT_SCB_STREAM_ST},
+/* CC_CLOSE_EVT */          {AVDT_SCB_SND_TC_CLOSE,         AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST}
+};
+
+/* state table for closing state */
+const uint8_t avdt_scb_st_closing[][AVDT_SCB_NUM_COLS] = {
+/* Event                     Action 1                       Action 2                    Next state */
+/* API_REMOVE_EVT */        {AVDT_SCB_SET_REMOVE,           AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_WRITE_REQ_EVT */     {AVDT_SCB_FREE_PKT,             AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_OPEN_REQ_EVT */      {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_CLOSE_REQ_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_REQ_EVT */  {AVDT_SCB_CB_ERR,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_SECURITY_REQ_EVT */  {AVDT_SCB_CB_ERR,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_ABORT_REQ_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_OPEN_RSP_EVT */      {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_CLOSE_RSP_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_RECONFIG_RSP_EVT */  {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_SECURITY_RSP_EVT */  {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* API_ABORT_RSP_EVT */     {AVDT_SCB_SND_ABORT_RSP,        AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_OPEN_CMD_EVT */      {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_START_CMD_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_SUSPEND_CMD_EVT */   {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_CLOSE_CMD_EVT */     {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_ABORT_CMD_EVT */     {AVDT_SCB_HDL_ABORT_CMD,        AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_RECONFIG_CMD_EVT */  {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_SECURITY_CMD_EVT */  {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_REJ_STATE,            AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP,    AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_OPEN_RSP_EVT */      {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_START_RSP_EVT */     {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_SUSPEND_RSP_EVT */   {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_CLOSE_RSP_EVT */     {AVDT_SCB_SND_TC_CLOSE,         AVDT_SCB_HDL_CLOSE_RSP,     AVDT_SCB_CLOSING_ST},
+/* MSG_ABORT_RSP_EVT */     {AVDT_SCB_SND_TC_CLOSE,         AVDT_SCB_HDL_ABORT_RSP,     AVDT_SCB_CLOSING_ST},
+/* MSG_RECONFIG_RSP_EVT */  {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_SECURITY_RSP_EVT */  {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_OPEN_REJ_EVT */      {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_START_REJ_EVT */     {AVDT_SCB_HDL_START_RSP,        AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* MSG_SUSPEND_REJ_EVT */   {AVDT_SCB_HDL_SUSPEND_RSP,      AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* TC_TOUT_EVT */           {AVDT_SCB_SND_TC_CLOSE,         AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* TC_OPEN_EVT */           {AVDT_SCB_SND_TC_CLOSE,         AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* TC_CLOSE_EVT */          {AVDT_SCB_HDL_TC_CLOSE,         AVDT_SCB_IGNORE,            AVDT_SCB_IDLE_ST},
+/* TC_CONG_EVT */           {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* TC_DATA_EVT */           {AVDT_SCB_DROP_PKT,             AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST},
+/* CC_CLOSE_EVT */          {AVDT_SCB_IGNORE,               AVDT_SCB_IGNORE,            AVDT_SCB_CLOSING_ST}
+};
+
+/* type for state table */
+typedef const uint8_t (*tAVDT_SCB_ST_TBL)[AVDT_SCB_NUM_COLS];
+
+/* state table */
+const tAVDT_SCB_ST_TBL avdt_scb_st_tbl[] = {
+    avdt_scb_st_idle,
+    avdt_scb_st_conf,
+    avdt_scb_st_opening,
+    avdt_scb_st_open,
+    avdt_scb_st_stream,
+    avdt_scb_st_closing
+};
+
+
+/*******************************************************************************
+**
+** Function         avdt_scb_event
+**
+** Description      State machine event handling function for scb
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_event(tAVDT_SCB *p_scb, uint8_t event, tAVDT_SCB_EVT *p_data)
+{
+    tAVDT_SCB_ST_TBL    state_table;
+    uint8_t             action;
+    int                 i;
+
+#if (AVDT_DEBUG == TRUE)
+    AVDT_TRACE_EVENT("SCB hdl=%d event=%d/%s state=%s", avdt_scb_to_hdl(p_scb), event, avdt_scb_evt_str[event], avdt_scb_st_str[p_scb->state]);
+#endif
+    /* set current event */
+    p_scb->curr_evt = event;
+
+    /* look up the state table for the current state */
+    state_table = avdt_scb_st_tbl[p_scb->state];
+
+    /* set next state */
+    if (p_scb->state != state_table[event][AVDT_SCB_NEXT_STATE]) {
+        p_scb->state = state_table[event][AVDT_SCB_NEXT_STATE];
+    }
+
+    /* execute action functions */
+    for (i = 0; i < AVDT_SCB_ACTIONS; i++)
+    {
+        if ((action = state_table[event][i]) != AVDT_SCB_IGNORE)
+        {
+            (*avdt_cb.p_scb_act[action])(p_scb, p_data);
+        }
+        else
+        {
+            break;
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         avdt_scb_init
+**
+** Description      Initialize stream control block module.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_init(void)
+{
+    memset(&avdt_cb.scb[0], 0, sizeof(tAVDT_SCB) * AVDT_NUM_SEPS);
+    avdt_cb.p_scb_act = (tAVDT_SCB_ACTION *) avdt_scb_action;
+}
+
+
+/*******************************************************************************
+**
+** Function         avdt_scb_alloc
+**
+** Description      Allocate a stream control block.
+**
+**
+** Returns          pointer to the scb, or NULL if none could be allocated.
+**
+*******************************************************************************/
+tAVDT_SCB *avdt_scb_alloc(tAVDT_CS *p_cs)
+{
+    tAVDT_SCB   *p_scb = &avdt_cb.scb[0];
+    int         i;
+
+    /* find available scb */
+    for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
+    {
+        if (!p_scb->allocated)
+        {
+            memset(p_scb,0,sizeof(tAVDT_SCB));
+            p_scb->allocated = true;
+            p_scb->p_ccb = NULL;
+
+            memcpy(&p_scb->cs, p_cs, sizeof(tAVDT_CS));
+            p_scb->transport_channel_timer =
+                alarm_new("avdt_scb.transport_channel_timer");
+            AVDT_TRACE_DEBUG("%s: hdl=%d, psc_mask:0x%x",
+                             __func__, i + 1, p_cs->cfg.psc_mask);
+            break;
+        }
+    }
+
+    if (i == AVDT_NUM_SEPS)
+    {
+        /* out of ccbs */
+        p_scb = NULL;
+        AVDT_TRACE_WARNING("Out of scbs");
+    }
+
+    return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_dealloc
+**
+** Description      Deallocate a stream control block.
+**
+**
+** Returns          void.
+**
+*******************************************************************************/
+void avdt_scb_dealloc(tAVDT_SCB *p_scb,
+                      UNUSED_ATTR tAVDT_SCB_EVT *p_data)
+{
+    AVDT_TRACE_DEBUG("%s: hdl=%d", __func__, avdt_scb_to_hdl(p_scb));
+    alarm_free(p_scb->transport_channel_timer);
+    memset(p_scb, 0, sizeof(tAVDT_SCB));
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_to_hdl
+**
+** Description      Given a pointer to an scb, return its handle (or seid).
+**
+**
+** Returns          Index of scb.
+**
+*******************************************************************************/
+uint8_t avdt_scb_to_hdl(tAVDT_SCB *p_scb)
+{
+    return (uint8_t) (p_scb - avdt_cb.scb + 1);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_by_hdl
+**
+** Description      Given an scb handle (or seid), return a pointer to the scb.
+**
+**
+** Returns          Pointer to scb or NULL if index is out of range or scb
+**                  is not allocated.
+**
+*******************************************************************************/
+tAVDT_SCB *avdt_scb_by_hdl(uint8_t hdl)
+{
+    tAVDT_SCB   *p_scb;
+
+    /* verify index */
+    if ((hdl > 0) && (hdl <= AVDT_NUM_SEPS))
+    {
+        p_scb = &avdt_cb.scb[hdl - 1];
+
+        /* verify scb is allocated */
+        if (!p_scb->allocated)
+        {
+            p_scb = NULL;
+            AVDT_TRACE_WARNING("scb hdl %d not allocated", hdl);
+        }
+    }
+    else
+    {
+        p_scb = NULL;
+        AVDT_TRACE_WARNING("scb hdl %d out of range", hdl);
+    }
+    return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_verify
+**
+** Description      Verify the condition of a list of scbs.
+**
+**
+** Returns          SEID that failed, or 0 if success.
+**
+*******************************************************************************/
+uint8_t avdt_scb_verify(tAVDT_CCB *p_ccb, uint8_t state, uint8_t *p_seid, uint16_t num_seid, uint8_t *p_err_code)
+{
+    int         i;
+    tAVDT_SCB   *p_scb;
+    uint8_t     nsc_mask;
+    uint8_t     ret = 0;
+
+    AVDT_TRACE_DEBUG("avdt_scb_verify state %d", state);
+    /* set nonsupported command mask */
+    /* translate public state into private state */
+    nsc_mask = 0;
+    if (state == AVDT_VERIFY_SUSPEND)
+      nsc_mask = AVDT_NSC_SUSPEND;
+
+    /* verify every scb */
+    for (i = 0, *p_err_code = 0; (i < num_seid) && (*p_err_code == 0) && (i < AVDT_NUM_SEPS); i++)
+    {
+        if ((p_scb = avdt_scb_by_hdl(p_seid[i])) == NULL)
+            *p_err_code = AVDT_ERR_BAD_STATE;
+        else if (p_scb->p_ccb != p_ccb)
+            *p_err_code = AVDT_ERR_BAD_STATE;
+        else if (p_scb->cs.nsc_mask & nsc_mask)
+            *p_err_code = AVDT_ERR_NSC;
+
+        switch (state) {
+          case AVDT_VERIFY_OPEN:
+          case AVDT_VERIFY_START:
+            if (p_scb->state != AVDT_SCB_OPEN_ST && p_scb->state != AVDT_SCB_STREAM_ST)
+              *p_err_code = AVDT_ERR_BAD_STATE;
+            break;
+
+          case AVDT_VERIFY_SUSPEND:
+          case AVDT_VERIFY_STREAMING:
+            if (p_scb->state != AVDT_SCB_STREAM_ST)
+              *p_err_code = AVDT_ERR_BAD_STATE;
+            break;
+        }
+    }
+
+    if ((i != num_seid) && (i < AVDT_NUM_SEPS))
+    {
+        ret = p_seid[i];
+    }
+
+    return ret;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_peer_seid_list
+**
+** Description      Given a list of SCB handles, return a list of peer SEIDs
+**                  for the handles, copied in place into the struct passed in.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_peer_seid_list(tAVDT_MULTI *p_multi)
+{
+    int         i;
+    tAVDT_SCB   *p_scb;
+
+    for (i = 0; i < p_multi->num_seps; i++)
+    {
+        if ((p_scb = avdt_scb_by_hdl(p_multi->seid_list[i])) != NULL)
+        {
+            p_multi->seid_list[i] = p_scb->peer_seid;
+        }
+    }
+}
+
diff --git a/bt/stack/avdt/avdt_scb_act.cc b/bt/stack/avdt/avdt_scb_act.cc
new file mode 100644
index 0000000..cd36517
--- /dev/null
+++ b/bt/stack/avdt/avdt_scb_act.cc
@@ -0,0 +1,1578 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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 module contains the action functions associated with the stream
+ *  control block state machine.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "a2dp_api.h"
+#include "avdt_api.h"
+#include "avdtc_api.h"
+#include "avdt_int.h"
+#include "bt_common.h"
+#include "btu.h"
+#include "osi/include/osi.h"
+
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+/* This table is used to lookup the callback event that matches a particular
+** state machine API request event.  Note that state machine API request
+** events are at the beginning of the event list starting at zero, thus
+** allowing for this table.
+*/
+const uint8_t avdt_scb_cback_evt[] = {
+    0,                          /* API_REMOVE_EVT (no event) */
+    AVDT_WRITE_CFM_EVT,         /* API_WRITE_REQ_EVT */
+    0,                          /* API_GETCONFIG_REQ_EVT (no event) */
+    0,                          /* API_DELAY_RPT_REQ_EVT (no event) */
+    AVDT_OPEN_CFM_EVT,          /* API_SETCONFIG_REQ_EVT */
+    AVDT_OPEN_CFM_EVT,          /* API_OPEN_REQ_EVT */
+    AVDT_CLOSE_CFM_EVT,         /* API_CLOSE_REQ_EVT */
+    AVDT_RECONFIG_CFM_EVT,      /* API_RECONFIG_REQ_EVT */
+    AVDT_SECURITY_CFM_EVT,      /* API_SECURITY_REQ_EVT */
+    0                           /* API_ABORT_REQ_EVT (no event) */
+};
+
+/*******************************************************************************
+**
+** Function         avdt_scb_gen_ssrc
+**
+** Description      This function generates a SSRC number unique to the stream.
+**
+** Returns          SSRC value.
+**
+*******************************************************************************/
+uint32_t avdt_scb_gen_ssrc(tAVDT_SCB *p_scb)
+{
+    /* combine the value of the media type and codec type of the SCB */
+    return ((uint32_t)(p_scb->cs.cfg.codec_info[1] | p_scb->cs.cfg.codec_info[2]));
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_abort_cmd
+**
+** Description      This function sends the SCB an AVDT_SCB_API_ABORT_RSP_EVT
+**                  to initiate sending of an abort response message.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_abort_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    p_scb->role = AVDT_CLOSE_ACP;
+    avdt_scb_event(p_scb, AVDT_SCB_API_ABORT_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_abort_rsp
+**
+** Description      This function is an empty function; it serves as a
+**                  placeholder for a conformance API action function.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_abort_rsp(UNUSED_ATTR tAVDT_SCB *p_scb,
+                            UNUSED_ATTR tAVDT_SCB_EVT *p_data)
+{
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_close_cmd
+**
+** Description      This function sends the SCB an AVDT_SCB_API_CLOSE_RSP_EVT
+**                  to initiate sending of a close response message.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_close_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    p_scb->role = AVDT_CLOSE_ACP;
+    avdt_scb_event(p_scb, AVDT_SCB_API_CLOSE_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_close_rsp
+**
+** Description      This function sets the close_code variable to the error
+**                  code returned in the close response.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    p_scb->close_code = p_data->msg.hdr.err_code;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_getconfig_cmd
+**
+** Description      This function retrieves the configuration parameters of
+**                  the SCB and sends the SCB an AVDT_SCB_API_GETCONFIG_RSP_EVT
+**                  to initiate sending of a get configuration response message.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_getconfig_cmd(tAVDT_SCB *p_scb,tAVDT_SCB_EVT *p_data)
+{
+    p_data->msg.svccap.p_cfg = &p_scb->curr_cfg;
+
+    avdt_scb_event(p_scb, AVDT_SCB_API_GETCONFIG_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_getconfig_rsp
+**
+** Description      This function is an empty function; it serves as a
+**                  placeholder for a conformance API action function.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_getconfig_rsp(UNUSED_ATTR tAVDT_SCB *p_scb,
+                                UNUSED_ATTR tAVDT_SCB_EVT *p_data)
+{
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_open_cmd
+**
+** Description      This function sends the SCB an AVDT_SCB_API_OPEN_RSP_EVT
+**                  to initiate sending of an open response message.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_open_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    avdt_scb_event(p_scb, AVDT_SCB_API_OPEN_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_open_rej
+**
+** Description      This function calls the application callback function
+**                  indicating the open request has failed.  It initializes
+**                  certain SCB variables and sends a AVDT_CCB_UL_CLOSE_EVT
+**                  to the CCB.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_open_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    /* do exactly same as setconfig reject */
+    avdt_scb_hdl_setconfig_rej(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_open_rsp
+**
+** Description      This function calls avdt_ad_open_req() to initiate
+**                  connection of the transport channel for this stream.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_open_rsp(tAVDT_SCB *p_scb, UNUSED_ATTR tAVDT_SCB_EVT *p_data)
+{
+    /* initiate opening of trans channels for this SEID */
+    p_scb->role = AVDT_OPEN_INT;
+    avdt_ad_open_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, AVDT_INT);
+
+    /* start tc connect timer */
+    alarm_set_on_queue(p_scb->transport_channel_timer,
+                       AVDT_SCB_TC_CONN_TIMEOUT_MS,
+                       avdt_scb_transport_channel_timer_timeout, p_scb,
+                       btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_pkt_no_frag
+**
+** Description
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_pkt_no_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    uint8_t *p, *p_start;
+    uint8_t o_v, o_p, o_x, o_cc;
+    uint8_t m_pt;
+    uint8_t marker;
+    uint16_t seq;
+    uint32_t time_stamp;
+    uint16_t offset;
+    uint16_t ex_len;
+    uint8_t pad_len = 0;
+
+    p = p_start = (uint8_t *)(p_data->p_pkt + 1) + p_data->p_pkt->offset;
+
+    /* parse media packet header */
+    AVDT_MSG_PRS_OCTET1(p, o_v, o_p, o_x, o_cc);
+    AVDT_MSG_PRS_M_PT(p, m_pt, marker);
+    BE_STREAM_TO_UINT16(seq, p);
+    BE_STREAM_TO_UINT32(time_stamp, p);
+    p += 4;
+
+    /* skip over any csrc's in packet */
+    p += o_cc * 4;
+
+    /* check for and skip over extension header */
+    if (o_x)
+    {
+        p += 2;
+        BE_STREAM_TO_UINT16(ex_len, p);
+        p += ex_len * 4;
+    }
+
+    /* save our new offset */
+    offset = (uint16_t) (p - p_start);
+
+    /* adjust length for any padding at end of packet */
+    if (o_p)
+    {
+        /* padding length in last byte of packet */
+        pad_len =  *(p_start + p_data->p_pkt->len);
+    }
+
+    /* do sanity check */
+    if ((offset > p_data->p_pkt->len) || ((pad_len + offset) > p_data->p_pkt->len))
+    {
+        AVDT_TRACE_WARNING("Got bad media packet");
+        osi_free_and_reset((void **)&p_data->p_pkt);
+    }
+    /* adjust offset and length and send it up */
+    else
+    {
+        p_data->p_pkt->len -= (offset + pad_len);
+        p_data->p_pkt->offset += offset;
+
+        if (p_scb->cs.p_sink_data_cback != NULL)
+        {
+            /* report sequence number */
+            p_data->p_pkt->layer_specific = seq;
+            (*p_scb->cs.p_sink_data_cback)(avdt_scb_to_hdl(p_scb),
+                p_data->p_pkt, time_stamp, (uint8_t)(m_pt | (marker << 7)));
+        }
+        else
+        {
+            osi_free_and_reset((void **)&p_data->p_pkt);
+        }
+    }
+}
+
+#if (AVDT_REPORTING == TRUE)
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_report
+**
+** Description
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+uint8_t * avdt_scb_hdl_report(tAVDT_SCB *p_scb, uint8_t *p, uint16_t len)
+{
+    uint16_t result = AVDT_SUCCESS;
+    uint8_t *p_start = p;
+    uint32_t ssrc;
+    uint8_t o_v, o_p, o_cc;
+    AVDT_REPORT_TYPE    pt;
+    tAVDT_REPORT_DATA   report, *p_rpt;
+
+    AVDT_TRACE_DEBUG("%s", __func__);
+    if(p_scb->cs.p_report_cback)
+    {
+        p_rpt = &report;
+        /* parse report packet header */
+        AVDT_MSG_PRS_RPT_OCTET1(p, o_v, o_p, o_cc);
+        pt = *p++;
+        p += 2;
+        BE_STREAM_TO_UINT32(ssrc, p);
+
+        switch(pt)
+        {
+        case AVDT_RTCP_PT_SR:   /* the packet type - SR (Sender Report) */
+            BE_STREAM_TO_UINT32(report.sr.ntp_sec, p);
+            BE_STREAM_TO_UINT32(report.sr.ntp_frac, p);
+            BE_STREAM_TO_UINT32(report.sr.rtp_time, p);
+            BE_STREAM_TO_UINT32(report.sr.pkt_count, p);
+            BE_STREAM_TO_UINT32(report.sr.octet_count, p);
+            break;
+
+        case AVDT_RTCP_PT_RR:   /* the packet type - RR (Receiver Report) */
+            report.rr.frag_lost = *p;
+            BE_STREAM_TO_UINT32(report.rr.packet_lost, p);
+            report.rr.packet_lost &= 0xFFFFFF;
+            BE_STREAM_TO_UINT32(report.rr.seq_num_rcvd, p);
+            BE_STREAM_TO_UINT32(report.rr.jitter, p);
+            BE_STREAM_TO_UINT32(report.rr.lsr, p);
+            BE_STREAM_TO_UINT32(report.rr.dlsr, p);
+            break;
+
+        case AVDT_RTCP_PT_SDES: /* the packet type - SDES (Source Description) */
+            if(*p == AVDT_RTCP_SDES_CNAME)
+            {
+                p_rpt = (tAVDT_REPORT_DATA *)(p+2);
+            }
+            else
+            {
+                AVDT_TRACE_WARNING( " - SDES SSRC=0x%08x sc=%d %d len=%d %s",
+                    ssrc, o_cc, *p, *(p+1), p+2);
+                result = AVDT_BUSY;
+            }
+            break;
+
+        default:
+            AVDT_TRACE_ERROR( "Bad Report pkt - packet type: %d", pt);
+            result = AVDT_BAD_PARAMS;
+        }
+
+        if(result == AVDT_SUCCESS)
+            (*p_scb->cs.p_report_cback)(avdt_scb_to_hdl(p_scb), pt, p_rpt);
+
+    }
+    p_start += len;
+    return p_start;
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_pkt
+**
+** Description
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+#if (AVDT_REPORTING == TRUE)
+    if(p_data->p_pkt->layer_specific == AVDT_CHAN_REPORT)
+    {
+        uint8_t *p = (uint8_t *)(p_data->p_pkt + 1) + p_data->p_pkt->offset;
+        avdt_scb_hdl_report(p_scb, p, p_data->p_pkt->len);
+        osi_free_and_reset((void **)&p_data->p_pkt);
+    }
+    else
+#endif
+        avdt_scb_hdl_pkt_no_frag(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_drop_pkt
+**
+** Description      Drop an incoming media packet.  This function is called if
+**                  a media packet is received in any state besides streaming.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_drop_pkt(UNUSED_ATTR tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    AVDT_TRACE_ERROR("%s dropped incoming media packet", __func__);
+    osi_free_and_reset((void **)&p_data->p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_reconfig_cmd
+**
+** Description      This function calls the application callback function
+**                  with a reconfiguration indication.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_reconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    /* if command not supported */
+    if (p_scb->cs.nsc_mask & AVDT_NSC_RECONFIG)
+    {
+        /* send reject */
+        p_data->msg.hdr.err_code = AVDT_ERR_NSC;
+        p_data->msg.hdr.err_param = 0;
+        avdt_scb_event(p_scb, AVDT_SCB_API_RECONFIG_RSP_EVT, p_data);
+    }
+    else
+    {
+        /* store requested configuration */
+        memcpy(&p_scb->req_cfg, p_data->msg.reconfig_cmd.p_cfg, sizeof(tAVDT_CFG));
+
+        /* call application callback */
+        (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+                                  NULL,
+                                  AVDT_RECONFIG_IND_EVT,
+                                  (tAVDT_CTRL *) &p_data->msg.reconfig_cmd);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_reconfig_rsp
+**
+** Description      This function calls the application callback function
+**                  with a reconfiguration confirm.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    if (p_data->msg.hdr.err_code == 0)
+    {
+        /* store new configuration */
+        if (p_scb->req_cfg.num_codec > 0)
+        {
+            p_scb->curr_cfg.num_codec = p_scb->req_cfg.num_codec;
+            memcpy(p_scb->curr_cfg.codec_info, p_scb->req_cfg.codec_info, AVDT_CODEC_SIZE);
+        }
+        if (p_scb->req_cfg.num_protect > 0)
+        {
+            p_scb->curr_cfg.num_protect = p_scb->req_cfg.num_protect;
+            memcpy(p_scb->curr_cfg.protect_info, p_scb->req_cfg.protect_info, AVDT_PROTECT_SIZE);
+        }
+    }
+
+    p_data->msg.svccap.p_cfg = &p_scb->curr_cfg;
+
+    /* call application callback */
+    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+                              NULL,
+                              AVDT_RECONFIG_CFM_EVT,
+                              (tAVDT_CTRL *) &p_data->msg.svccap);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_security_cmd
+**
+** Description      This function calls the application callback with a
+**                  security indication.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_security_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    /* if command not supported */
+    if (p_scb->cs.nsc_mask & AVDT_NSC_SECURITY)
+    {
+        /* send reject */
+        p_data->msg.hdr.err_code = AVDT_ERR_NSC;
+        avdt_scb_event(p_scb, AVDT_SCB_API_SECURITY_RSP_EVT, p_data);
+    }
+    else
+    {
+        /* call application callback */
+        (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+                                  NULL,
+                                  AVDT_SECURITY_IND_EVT,
+                                  (tAVDT_CTRL *) &p_data->msg.security_cmd);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_security_rsp
+**
+** Description      This function calls the application callback with a
+**                  security confirm.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    /* call application callback */
+    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+                              NULL,
+                              AVDT_SECURITY_CFM_EVT,
+                              (tAVDT_CTRL *) &p_data->msg.security_cmd);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_setconfig_cmd
+**
+** Description      This function marks the SCB as in use and copies the
+**                  configuration and peer SEID to the SCB.  It then calls
+**                  the application callback with a configuration indication.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_setconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    tAVDT_CFG *p_cfg;
+
+    if (!p_scb->in_use)
+    {
+        p_cfg = p_data->msg.config_cmd.p_cfg;
+        if (A2DP_GetCodecType(p_scb->cs.cfg.codec_info) ==
+            A2DP_GetCodecType(p_cfg->codec_info))
+        {
+            /* set sep as in use */
+            p_scb->in_use = true;
+
+            /* copy info to scb */
+            p_scb->p_ccb = avdt_ccb_by_idx(p_data->msg.config_cmd.hdr.ccb_idx);
+            p_scb->peer_seid = p_data->msg.config_cmd.int_seid;
+            memcpy(&p_scb->req_cfg, p_cfg, sizeof(tAVDT_CFG));
+            /* call app callback */
+            (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), /* handle of scb- which is same as sep handle of bta_av_cb.p_scb*/
+                                      p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+                                      AVDT_CONFIG_IND_EVT,
+                                      (tAVDT_CTRL *) &p_data->msg.config_cmd);
+        }
+        else
+        {
+            p_data->msg.hdr.err_code = AVDT_ERR_UNSUP_CFG;
+            p_data->msg.hdr.err_param = 0;
+            avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
+                              p_data->msg.hdr.sig_id, &p_data->msg);
+        }
+    }
+    else
+    {
+        avdt_scb_rej_in_use(p_scb, p_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_setconfig_rej
+**
+** Description      This function marks the SCB as not in use and calls the
+**                  application callback with an open confirm indicating failure.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    /* clear scb variables */
+    avdt_scb_clr_vars(p_scb, p_data);
+
+    /* tell ccb we're done with signaling channel */
+    avdt_ccb_event(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx), AVDT_CCB_UL_CLOSE_EVT, NULL);
+
+    /* call application callback */
+    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+                              NULL,
+                              AVDT_OPEN_CFM_EVT,
+                              (tAVDT_CTRL *) &p_data->msg.hdr);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_setconfig_rsp
+**
+** Description      This function sends the SCB an AVDT_SCB_API_OPEN_REQ_EVT
+**                  to initiate sending of an open command message.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_setconfig_rsp(tAVDT_SCB *p_scb,
+                                UNUSED_ATTR tAVDT_SCB_EVT *p_data)
+{
+    tAVDT_EVT_HDR   single;
+
+    if (p_scb->p_ccb != NULL)
+    {
+        /* save configuration */
+        memcpy(&p_scb->curr_cfg, &p_scb->req_cfg, sizeof(tAVDT_CFG));
+
+        /* initiate open */
+        single.seid = p_scb->peer_seid;
+        avdt_scb_event(p_scb, AVDT_SCB_API_OPEN_REQ_EVT, (tAVDT_SCB_EVT *) &single);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_start_cmd
+**
+** Description      This function calls the application callback with a
+**                  start indication.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_start_cmd(tAVDT_SCB *p_scb,
+			    UNUSED_ATTR tAVDT_SCB_EVT *p_data)
+{
+    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+                              p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+                              AVDT_START_IND_EVT,
+                              NULL);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_start_rsp
+**
+** Description      This function calls the application callback with a
+**                  start confirm.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_start_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+                              p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+                              AVDT_START_CFM_EVT,
+                              (tAVDT_CTRL *) &p_data->msg.hdr);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_suspend_cmd
+**
+** Description      This function calls the application callback with a suspend
+**                  indication.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_suspend_cmd(tAVDT_SCB *p_scb,
+			      UNUSED_ATTR tAVDT_SCB_EVT *p_data)
+{
+    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+                              p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+                              AVDT_SUSPEND_IND_EVT,
+                              NULL);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_suspend_rsp
+**
+** Description      This function calls the application callback with a suspend
+**                  confirm.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_suspend_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+                              p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+                              AVDT_SUSPEND_CFM_EVT,
+                              (tAVDT_CTRL *) &p_data->msg.hdr);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_tc_close
+**
+** Description      This function is called when the transport channel is
+**                  closed.  It marks the SCB as not in use and
+**                  initializes certain SCB parameters.  It then sends
+**                  an AVDT_CCB_UL_CLOSE_EVT to the CCB if the SCB
+**                  initiated the close.  It then checks to see if the SCB
+**                  is to be removed.  If it is it deallocates the SCB.  Finally,
+**                  it calls the application callback with a close indication.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_tc_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    uint8_t             hdl = avdt_scb_to_hdl(p_scb);
+    tAVDT_CTRL_CBACK    *p_ctrl_cback = p_scb->cs.p_ctrl_cback;
+    tAVDT_CTRL          avdt_ctrl;
+    uint8_t             event;
+    tAVDT_CCB           *p_ccb = p_scb->p_ccb;
+    BD_ADDR remote_addr;
+
+
+    memcpy (remote_addr, p_ccb->peer_addr, BD_ADDR_LEN);
+
+    /* set up hdr */
+    avdt_ctrl.hdr.err_code = p_scb->close_code;
+
+    /* clear sep variables */
+    avdt_scb_clr_vars(p_scb, p_data);
+    p_scb->media_seq = 0;
+    p_scb->cong = false;
+
+    /* free pkt we're holding, if any */
+    osi_free_and_reset((void **)&p_scb->p_pkt);
+
+    alarm_cancel(p_scb->transport_channel_timer);
+
+    if ((p_scb->role == AVDT_CLOSE_INT) || (p_scb->role == AVDT_OPEN_INT))
+    {
+        /* tell ccb we're done with signaling channel */
+        avdt_ccb_event(p_ccb, AVDT_CCB_UL_CLOSE_EVT, NULL);
+    }
+    event = (p_scb->role == AVDT_CLOSE_INT) ? AVDT_CLOSE_CFM_EVT : AVDT_CLOSE_IND_EVT;
+    p_scb->role = AVDT_CLOSE_ACP;
+
+    if (p_scb->remove)
+    {
+        avdt_scb_dealloc(p_scb, NULL);
+    }
+
+    /* call app callback */
+    (*p_ctrl_cback)(hdl, remote_addr, event, &avdt_ctrl);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_snd_delay_rpt_req
+**
+** Description      This function calls the application callback with a delay
+**                  report.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_delay_rpt_req (tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_DELAY_RPT, (tAVDT_MSG *) &p_data->apidelay);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_delay_rpt_cmd
+**
+** Description      This function calls the application callback with a delay
+**                  report.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_delay_rpt_cmd (tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+                              p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+                              AVDT_DELAY_REPORT_EVT,
+                              (tAVDT_CTRL *) &p_data->msg.hdr);
+
+    if (p_scb->p_ccb)
+        avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_DELAY_RPT, &p_data->msg);
+    else
+        avdt_scb_rej_not_in_use(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_delay_rpt_rsp
+**
+** Description      This function calls the application callback with a delay
+**                  report.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_delay_rpt_rsp (tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+                              p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+                              AVDT_DELAY_REPORT_CFM_EVT,
+                              (tAVDT_CTRL *) &p_data->msg.hdr);
+}
+
+#if (AVDT_REPORTING == TRUE)
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_tc_close_sto
+**
+** Description      This function is called when a channel is closed in OPEN
+**                  state.  Check the channel type and process accordingly.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_tc_close_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    tAVDT_CTRL          avdt_ctrl;
+    /* AVDT_CHAN_SIG does not visit this action */
+    if(p_data && p_data->close.type != AVDT_CHAN_MEDIA)
+    {
+        /* it's reporting or recovery channel,
+         * the channel close in open state means the peer does not support it */
+        if(p_data->close.old_tc_state == AVDT_AD_ST_OPEN)
+        {
+            avdt_ctrl.hdr.err_code = 0;
+            avdt_ctrl.hdr.err_param = 0;
+            /* call app callback */
+            (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+                                      p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+                                      AVDT_REPORT_DISCONN_EVT, &avdt_ctrl);
+        }
+    }
+    else
+    {
+        /* must be in OPEN state. need to go back to idle */
+        avdt_scb_event(p_scb, AVDT_SCB_MSG_ABORT_RSP_EVT, NULL);
+        avdt_scb_hdl_tc_close(p_scb, p_data);
+    }
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_tc_open
+**
+** Description      This function is called when the transport channel is
+**                  opened while in the opening state.  It calls the
+**                  application callback with an open indication or open
+**                  confirm depending on who initiated the open procedure.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_tc_open(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    uint8_t event;
+#if (AVDT_REPORTING == TRUE)
+    uint8_t role;
+#endif
+
+    alarm_cancel(p_scb->transport_channel_timer);
+
+    event = (p_scb->role == AVDT_OPEN_INT) ? AVDT_OPEN_CFM_EVT : AVDT_OPEN_IND_EVT;
+    p_data->open.hdr.err_code = 0;
+
+    AVDT_TRACE_DEBUG("psc_mask: cfg: 0x%x, req:0x%x, cur: 0x%x",
+        p_scb->cs.cfg.psc_mask, p_scb->req_cfg.psc_mask, p_scb->curr_cfg.psc_mask);
+#if (AVDT_REPORTING == TRUE)
+    if(p_scb->curr_cfg.psc_mask & AVDT_PSC_REPORT)
+    {
+        /* open the reporting channel, if both devices support it */
+        role = (p_scb->role == AVDT_OPEN_INT) ? AVDT_INT : AVDT_ACP;
+        avdt_ad_open_req(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb, role);
+    }
+#endif
+
+    /* call app callback */
+    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+                              p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+                              event,
+                              (tAVDT_CTRL *) &p_data->open);
+}
+
+#if (AVDT_REPORTING == TRUE)
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_tc_open_sto
+**
+** Description      This function is called when the transport channel is
+**                  opened while in the opening state.  It calls the
+**                  application callback with an open indication or open
+**                  confirm depending on who initiated the open procedure.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_tc_open_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    tAVDT_CTRL          avdt_ctrl;
+    /* open reporting channel here, when it is implemented */
+
+    /* call app callback */
+    if(p_data->open.hdr.err_code == AVDT_CHAN_REPORT)
+    {
+        avdt_ctrl.hdr.err_code = 0;
+        avdt_ctrl.hdr.err_param = 1;
+        (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+                              p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+                              AVDT_REPORT_CONN_EVT, &avdt_ctrl);
+    }
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         avdt_scb_hdl_write_req
+**
+** Description      This function frees the media packet currently stored in
+**                  the SCB, if any.  Then it builds a new media packet from
+**                  with the passed in buffer and stores it in the SCB.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_hdl_write_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    uint8_t *p;
+    uint32_t ssrc;
+    bool add_rtp_header = !(p_data->apiwrite.opt & AVDT_DATA_OPT_NO_RTP);
+
+    /* free packet we're holding, if any; to be replaced with new */
+    if (p_scb->p_pkt != NULL) {
+        /* this shouldn't be happening */
+        AVDT_TRACE_WARNING("Dropped media packet; congested");
+    }
+    osi_free_and_reset((void **)&p_scb->p_pkt);
+
+    /* Recompute only if the RTP header wasn't disabled by the API */
+    if (add_rtp_header) {
+        bool is_content_protection = (p_scb->curr_cfg.num_protect > 0);
+        add_rtp_header = A2DP_UsesRtpHeader(is_content_protection,
+                                           p_scb->curr_cfg.codec_info);
+    }
+
+    /* Build a media packet, and add an RTP header if required. */
+    if (add_rtp_header) {
+        ssrc = avdt_scb_gen_ssrc(p_scb);
+
+        p_data->apiwrite.p_buf->len += AVDT_MEDIA_HDR_SIZE;
+        p_data->apiwrite.p_buf->offset -= AVDT_MEDIA_HDR_SIZE;
+        p_scb->media_seq++;
+        p = (uint8_t *)(p_data->apiwrite.p_buf + 1) + p_data->apiwrite.p_buf->offset;
+
+        UINT8_TO_BE_STREAM(p, AVDT_MEDIA_OCTET1);
+        UINT8_TO_BE_STREAM(p, p_data->apiwrite.m_pt);
+        UINT16_TO_BE_STREAM(p, p_scb->media_seq);
+        UINT32_TO_BE_STREAM(p, p_data->apiwrite.time_stamp);
+        UINT32_TO_BE_STREAM(p, ssrc);
+    }
+
+    /* store it */
+    p_scb->p_pkt = p_data->apiwrite.p_buf;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_snd_abort_req
+**
+** Description      This function sends an abort command message.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_abort_req(tAVDT_SCB *p_scb,
+                            UNUSED_ATTR tAVDT_SCB_EVT *p_data)
+{
+    tAVDT_EVT_HDR   hdr;
+
+    if (p_scb->p_ccb != NULL)
+    {
+        p_scb->role = AVDT_CLOSE_INT;
+
+        hdr.seid = p_scb->peer_seid;
+
+        avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_ABORT, (tAVDT_MSG *) &hdr);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_snd_abort_rsp
+**
+** Description      This function sends an abort response message.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_abort_rsp(UNUSED_ATTR tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    avdt_msg_send_rsp(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx), AVDT_SIG_ABORT,
+                      &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_snd_close_req
+**
+** Description      This function sends a close command message.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_close_req(tAVDT_SCB *p_scb,
+                            UNUSED_ATTR tAVDT_SCB_EVT *p_data)
+{
+    tAVDT_EVT_HDR   hdr;
+
+    p_scb->role = AVDT_CLOSE_INT;
+
+    hdr.seid = p_scb->peer_seid;
+
+    avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_CLOSE, (tAVDT_MSG *) &hdr);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_snd_stream_close
+**
+** Description      This function sends a close command message.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_stream_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    osi_free_and_reset((void **)&p_scb->p_pkt);
+    avdt_scb_snd_close_req(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_snd_close_rsp
+**
+** Description      This function sends a close response message.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_CLOSE, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_snd_getconfig_req
+**
+** Description      This function sends a get configuration command message.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_getconfig_req(tAVDT_SCB *p_scb,
+                                UNUSED_ATTR tAVDT_SCB_EVT *p_data)
+{
+    tAVDT_EVT_HDR   hdr;
+
+    hdr.seid = p_scb->peer_seid;
+
+    avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_GETCONFIG, (tAVDT_MSG *) &hdr);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_snd_getconfig_rsp
+**
+** Description      This function sends a get configuration response message.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_getconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_GETCONFIG, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_snd_open_req
+**
+** Description      This function sends an open command message.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_open_req(tAVDT_SCB *p_scb,
+                           UNUSED_ATTR tAVDT_SCB_EVT *p_data)
+{
+    tAVDT_EVT_HDR   hdr;
+
+    hdr.seid = p_scb->peer_seid;
+
+    avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_OPEN, (tAVDT_MSG *) &hdr);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_snd_open_rsp
+**
+** Description      This function sends an open response message.  It also
+**                  calls avdt_ad_open_req() to accept a transport channel
+**                  connection.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_open_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    /* notify adaption that we're waiting for transport channel open */
+    p_scb->role = AVDT_OPEN_ACP;
+    avdt_ad_open_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, AVDT_ACP);
+
+    /* send response */
+    avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_OPEN, &p_data->msg);
+
+    alarm_set_on_queue(p_scb->transport_channel_timer,
+                       AVDT_SCB_TC_CONN_TIMEOUT_MS,
+                       avdt_scb_transport_channel_timer_timeout, p_scb,
+                       btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_snd_reconfig_req
+**
+** Description      This function stores the configuration parameters in the
+**                  SCB and sends a reconfiguration command message.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_reconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    memcpy(&p_scb->req_cfg, p_data->msg.config_cmd.p_cfg, sizeof(tAVDT_CFG));
+    p_data->msg.hdr.seid = p_scb->peer_seid;
+    avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_RECONFIG, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_snd_reconfig_rsp
+**
+** Description      This function stores the configuration parameters in the
+**                  SCB and sends a reconfiguration response message.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    if (p_data->msg.hdr.err_code == 0)
+    {
+        /* store new configuration */
+        if (p_scb->req_cfg.num_codec > 0)
+        {
+            p_scb->curr_cfg.num_codec = p_scb->req_cfg.num_codec;
+            memcpy(p_scb->curr_cfg.codec_info, p_scb->req_cfg.codec_info, AVDT_CODEC_SIZE);
+        }
+        if (p_scb->req_cfg.num_protect > 0)
+        {
+            p_scb->curr_cfg.num_protect = p_scb->req_cfg.num_protect;
+            memcpy(p_scb->curr_cfg.protect_info, p_scb->req_cfg.protect_info, AVDT_PROTECT_SIZE);
+        }
+
+        /* send response */
+        avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_RECONFIG, &p_data->msg);
+    }
+    else
+    {
+        /* send reject */
+        avdt_msg_send_rej(p_scb->p_ccb, AVDT_SIG_RECONFIG, &p_data->msg);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_snd_security_req
+**
+** Description      This function sends a security command message.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_security_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    p_data->msg.hdr.seid = p_scb->peer_seid;
+    avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_SECURITY, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_snd_security_rsp
+**
+** Description      This function sends a security response message.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    if (p_data->msg.hdr.err_code == 0)
+    {
+        avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_SECURITY, &p_data->msg);
+    }
+    else
+    {
+        avdt_msg_send_rej(p_scb->p_ccb, AVDT_SIG_SECURITY, &p_data->msg);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_snd_setconfig_rej
+**
+** Description      This function marks the SCB as not in use and sends a
+**                  set configuration reject message.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    if (p_scb->p_ccb != NULL)
+    {
+        avdt_msg_send_rej(p_scb->p_ccb, AVDT_SIG_SETCONFIG, &p_data->msg);
+
+        /* clear scb variables */
+        avdt_scb_clr_vars(p_scb, p_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_snd_setconfig_req
+**
+** Description      This function marks the SCB as in use and copies the
+**                  configuration parameters to the SCB.  Then the function
+**                  sends a set configuration command message and initiates
+**                  opening of the signaling channel.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_setconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    tAVDT_CFG *p_req, *p_cfg;
+
+    /* copy API parameters to scb, set scb as in use */
+    p_scb->in_use = true;
+    p_scb->p_ccb = avdt_ccb_by_idx(p_data->msg.config_cmd.hdr.ccb_idx);
+    p_scb->peer_seid = p_data->msg.config_cmd.hdr.seid;
+    p_req = p_data->msg.config_cmd.p_cfg;
+    p_cfg = &p_scb->cs.cfg;
+    memcpy(&p_scb->req_cfg, p_data->msg.config_cmd.p_cfg, sizeof(tAVDT_CFG));
+
+    avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_SETCONFIG, &p_data->msg);
+
+    /* tell ccb to open channel */
+    avdt_ccb_event(p_scb->p_ccb, AVDT_CCB_UL_OPEN_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_snd_setconfig_rsp
+**
+** Description      This function copies the requested configuration into the
+**                  current configuration and sends a set configuration
+**                  response message.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_setconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    if (p_scb->p_ccb != NULL)
+    {
+        memcpy(&p_scb->curr_cfg, &p_scb->req_cfg, sizeof(tAVDT_CFG));
+
+        avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_SETCONFIG, &p_data->msg);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_snd_tc_close
+**
+** Description      This function calls avdt_ad_close_req() to close the
+**                  transport channel for this SCB.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_snd_tc_close(tAVDT_SCB *p_scb,
+                           UNUSED_ATTR tAVDT_SCB_EVT *p_data)
+{
+#if (AVDT_REPORTING == TRUE)
+    if(p_scb->curr_cfg.psc_mask & AVDT_PSC_REPORT)
+        avdt_ad_close_req(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb);
+#endif
+    avdt_ad_close_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_cb_err
+**
+** Description      This function calls the application callback function
+**                  indicating an error.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_cb_err(tAVDT_SCB *p_scb,
+		     UNUSED_ATTR tAVDT_SCB_EVT *p_data)
+{
+    tAVDT_CTRL          avdt_ctrl;
+
+    /* set error code and parameter */
+    avdt_ctrl.hdr.err_code = AVDT_ERR_BAD_STATE;
+    avdt_ctrl.hdr.err_param = 0;
+
+    /* call callback, using lookup table to get callback event */
+    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+                              NULL,
+                              avdt_scb_cback_evt[p_scb->curr_evt],
+                              &avdt_ctrl);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_cong_state
+**
+** Description      This function sets the congestion state of the SCB media
+**                  transport channel.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_cong_state(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    p_scb->cong = p_data->llcong;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_rej_state
+**
+** Description      This function sends a reject message to the peer indicating
+**                  incorrect state for the received command message.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_rej_state(UNUSED_ATTR tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    p_data->msg.hdr.err_code = AVDT_ERR_BAD_STATE;
+    p_data->msg.hdr.err_param = 0;
+    avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
+                      p_data->msg.hdr.sig_id, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_rej_in_use
+**
+** Description      This function sends a reject message to the peer indicating
+**                  the stream is in use.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_rej_in_use(UNUSED_ATTR tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    p_data->msg.hdr.err_code = AVDT_ERR_IN_USE;
+    p_data->msg.hdr.err_param = 0;
+    avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
+                      p_data->msg.hdr.sig_id, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_rej_not_in_use
+**
+** Description      This function sends a reject message to the peer indicating
+**                  the stream is in use.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_rej_not_in_use(UNUSED_ATTR tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    p_data->msg.hdr.err_code = AVDT_ERR_NOT_IN_USE;
+    p_data->msg.hdr.err_param = 0;
+    avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
+                      p_data->msg.hdr.sig_id, &p_data->msg);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_set_remove
+**
+** Description      This function marks an SCB to be removed.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_set_remove(tAVDT_SCB *p_scb,
+                         UNUSED_ATTR tAVDT_SCB_EVT *p_data)
+{
+    p_scb->remove = true;
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_free_pkt
+**
+** Description      This function frees the media packet passed in.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_free_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
+{
+    tAVDT_CTRL      avdt_ctrl;
+
+    /* set error code and parameter */
+    avdt_ctrl.hdr.err_code = AVDT_ERR_BAD_STATE;
+    avdt_ctrl.hdr.err_param = 0;
+
+    osi_free_and_reset((void **)&p_data->apiwrite.p_buf);
+
+    AVDT_TRACE_WARNING("Dropped media packet");
+
+    /* we need to call callback to keep data flow going */
+    (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT,
+                              &avdt_ctrl);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_clr_pkt
+**
+** Description      This function frees the media packet stored in the SCB.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_clr_pkt(tAVDT_SCB *p_scb,
+                      UNUSED_ATTR tAVDT_SCB_EVT *p_data)
+{
+    tAVDT_CTRL      avdt_ctrl;
+    tAVDT_CCB       *p_ccb;
+    uint8_t         tcid;
+    uint16_t        lcid;
+
+    /* set error code and parameter */
+    avdt_ctrl.hdr.err_code = AVDT_ERR_BAD_STATE;
+    avdt_ctrl.hdr.err_param = 0;
+    /* flush the media data queued at L2CAP */
+    if((p_ccb = p_scb->p_ccb) != NULL)
+    {
+        /* get tcid from type, scb */
+        tcid = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb);
+
+        lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
+        L2CA_FlushChannel (lcid, L2CAP_FLUSH_CHANS_ALL);
+    }
+
+    if (p_scb->p_pkt != NULL)
+    {
+        osi_free_and_reset((void **)&p_scb->p_pkt);
+
+        AVDT_TRACE_DEBUG("Dropped stored media packet");
+
+        /* we need to call callback to keep data flow going */
+        (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT,
+                                  &avdt_ctrl);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         avdt_scb_chk_snd_pkt
+**
+** Description      This function checks if the SCB is congested, and if not
+**                  congested it sends a stored media packet, if any.  After it
+**                  sends the packet it calls the application callback function
+**                  with a write confirm.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_chk_snd_pkt(tAVDT_SCB *p_scb,
+                          UNUSED_ATTR tAVDT_SCB_EVT *p_data)
+{
+    tAVDT_CTRL      avdt_ctrl;
+    BT_HDR          *p_pkt;
+
+    avdt_ctrl.hdr.err_code = 0;
+
+    if (!p_scb->cong)
+    {
+        if (p_scb->p_pkt != NULL)
+        {
+            p_pkt = p_scb->p_pkt;
+            p_scb->p_pkt = NULL;
+            avdt_ad_write_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, p_pkt);
+
+            (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT, &avdt_ctrl);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_transport_channel_timer
+**
+** Description      This function is called to start a timer when the peer
+**                  initiates closing of the stream.  The timer verifies that
+**                  the peer disconnects the transport channel.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_transport_channel_timer(tAVDT_SCB *p_scb,
+				      UNUSED_ATTR tAVDT_SCB_EVT *p_data)
+{
+    alarm_set_on_queue(p_scb->transport_channel_timer,
+                       AVDT_SCB_TC_DISC_TIMEOUT_MS,
+                       avdt_scb_transport_channel_timer_timeout, p_scb,
+                       btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+**
+** Function         avdt_scb_clr_vars
+**
+** Description      This function initializes certain SCB variables.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void avdt_scb_clr_vars(tAVDT_SCB *p_scb,
+                       UNUSED_ATTR tAVDT_SCB_EVT *p_data)
+{
+    p_scb->in_use = false;
+    p_scb->p_ccb = NULL;
+    p_scb->peer_seid = 0;
+}
diff --git a/bt/stack/avrc/avrc_api.cc b/bt/stack/avrc/avrc_api.cc
new file mode 100644
index 0000000..8b4eeb1
--- /dev/null
+++ b/bt/stack/avrc/avrc_api.cc
@@ -0,0 +1,1446 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2016 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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Interface to AVRCP mandatory commands
+ *
+ ******************************************************************************/
+#include <assert.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "btu.h"
+#include "avrc_api.h"
+#include "avrc_int.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/osi.h"
+
+/*****************************************************************************
+**  Global data
+*****************************************************************************/
+extern fixed_queue_t *btu_general_alarm_queue;
+
+
+#define AVRC_MAX_RCV_CTRL_EVT   AVCT_BROWSE_UNCONG_IND_EVT
+
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+static const uint8_t avrc_ctrl_event_map[] =
+{
+    AVRC_OPEN_IND_EVT,  /* AVCT_CONNECT_CFM_EVT */
+    AVRC_OPEN_IND_EVT,  /* AVCT_CONNECT_IND_EVT */
+    AVRC_CLOSE_IND_EVT, /* AVCT_DISCONNECT_CFM_EVT */
+    AVRC_CLOSE_IND_EVT, /* AVCT_DISCONNECT_IND_EVT */
+    AVRC_CONG_IND_EVT,  /* AVCT_CONG_IND_EVT */
+    AVRC_UNCONG_IND_EVT,/* AVCT_UNCONG_IND_EVT */
+    AVRC_BROWSE_OPEN_IND_EVT,  /* AVCT_BROWSE_CONN_CFM_EVT   */
+    AVRC_BROWSE_OPEN_IND_EVT,  /* AVCT_BROWSE_CONN_IND_EVT   */
+    AVRC_BROWSE_CLOSE_IND_EVT, /* AVCT_BROWSE_DISCONN_CFM_EVT */
+    AVRC_BROWSE_CLOSE_IND_EVT, /* AVCT_BROWSE_DISCONN_IND_EVT */
+    AVRC_BROWSE_CONG_IND_EVT,  /* AVCT_BROWSE_CONG_IND_EVT    */
+    AVRC_BROWSE_UNCONG_IND_EVT /* AVCT_BROWSE_UNCONG_IND_EVT  */
+};
+
+#define AVRC_OP_DROP        0xFE    /* use this unused opcode to indication no need to call the callback function */
+#define AVRC_OP_DROP_N_FREE 0xFD    /* use this unused opcode to indication no need to call the callback function & free buffer */
+
+#define AVRC_OP_UNIT_INFO_RSP_LEN       8
+#define AVRC_OP_SUB_UNIT_INFO_RSP_LEN   8
+#define AVRC_OP_REJ_MSG_LEN            11
+
+/* Flags definitions for AVRC_MsgReq */
+#define AVRC_MSG_MASK_IS_VENDOR_CMD         0x01
+#define AVRC_MSG_MASK_IS_CONTINUATION_RSP   0x02
+
+/******************************************************************************
+**
+** Function         avrc_ctrl_cback
+**
+** Description      This is the callback function used by AVCTP to report
+**                  received link events.
+**
+** Returns          Nothing.
+**
+******************************************************************************/
+static void avrc_ctrl_cback(uint8_t handle, uint8_t event, uint16_t result,
+                                BD_ADDR peer_addr)
+{
+    uint8_t avrc_event;
+
+    if (event <= AVRC_MAX_RCV_CTRL_EVT && avrc_cb.ccb[handle].p_ctrl_cback)
+    {
+        avrc_event = avrc_ctrl_event_map[event];
+        if (event == AVCT_CONNECT_CFM_EVT)
+        {
+            if (result != 0) /* failed */
+                avrc_event = AVRC_CLOSE_IND_EVT;
+        }
+        (*avrc_cb.ccb[handle].p_ctrl_cback)(handle, avrc_event, result, peer_addr);
+    }
+
+    if ((event ==  AVCT_DISCONNECT_CFM_EVT) || (event == AVCT_DISCONNECT_IND_EVT))
+    {
+        avrc_flush_cmd_q(handle);
+        alarm_free(avrc_cb.ccb_int[handle].tle);
+    }
+}
+
+/******************************************************************************
+**
+** Function         avrc_flush_cmd_q
+**
+** Description      Flush command queue for the specified avrc handle
+**
+** Returns          Nothing.
+**
+******************************************************************************/
+void avrc_flush_cmd_q(uint8_t handle)
+{
+    AVRC_TRACE_DEBUG("AVRC: Flushing command queue for handle=0x%02x", handle);
+    avrc_cb.ccb_int[handle].flags &= ~AVRC_CB_FLAGS_RSP_PENDING;
+
+    alarm_cancel(avrc_cb.ccb_int[handle].tle);
+    fixed_queue_free(avrc_cb.ccb_int[handle].cmd_q, osi_free);
+}
+
+/******************************************************************************
+**
+** Function         avrc_process_timeout
+**
+** Description      Handle avrc command timeout
+**
+** Returns          Nothing.
+**
+******************************************************************************/
+void avrc_process_timeout(void *data)
+{
+    tAVRC_PARAM *param = (tAVRC_PARAM *)data;
+
+    AVRC_TRACE_DEBUG("AVRC: command timeout (handle=0x%02x, label=0x%02x)", param->handle,
+            param->label);
+
+    /* Notify app */
+    if (avrc_cb.ccb[param->handle].p_ctrl_cback)
+    {
+        (*avrc_cb.ccb[param->handle].p_ctrl_cback)(param->handle, AVRC_CMD_TIMEOUT_EVT,
+                param->label, NULL);
+    }
+
+    /* If vendor command timed-out, then send next command in the queue */
+    if (param->msg_mask & AVRC_MSG_MASK_IS_VENDOR_CMD)
+    {
+        avrc_send_next_vendor_cmd(param->handle);
+    }
+    osi_free(param);
+}
+
+/******************************************************************************
+**
+** Function         avrc_send_next_vendor_cmd
+**
+** Description      Dequeue and send next vendor command for given handle
+**
+** Returns          Nothing.
+**
+******************************************************************************/
+void avrc_send_next_vendor_cmd(uint8_t handle)
+{
+    BT_HDR *p_next_cmd;
+    uint8_t   next_label;
+
+    while ((p_next_cmd = (BT_HDR *)fixed_queue_try_dequeue(avrc_cb.ccb_int[handle].cmd_q)) != NULL)
+    {
+        p_next_cmd->event &= 0xFF;                      /* opcode */
+        next_label = (p_next_cmd->layer_specific) >> 8; /* extract label */
+        p_next_cmd->layer_specific &= 0xFF;             /* AVCT_DATA_CTRL or AVCT_DATA_BROWSE */
+
+        AVRC_TRACE_DEBUG("AVRC: Dequeuing command 0x%08x (handle=0x%02x, label=0x%02x)",
+            p_next_cmd, handle, next_label);
+
+        /* Send the message */
+        if ((AVCT_MsgReq(handle, next_label, AVCT_CMD, p_next_cmd)) == AVCT_SUCCESS)
+        {
+            /* Start command timer to wait for response */
+            avrc_start_cmd_timer(handle, next_label, AVRC_MSG_MASK_IS_VENDOR_CMD);
+            return;
+        }
+    }
+
+    if (p_next_cmd == NULL)
+    {
+        /* cmd queue empty */
+        avrc_cb.ccb_int[handle].flags &= ~AVRC_CB_FLAGS_RSP_PENDING;
+    }
+}
+
+/******************************************************************************
+**
+** Function         avrc_start_cmd_timer
+**
+** Description      Start timer for waiting for responses
+**
+** Returns          Nothing.
+**
+******************************************************************************/
+void avrc_start_cmd_timer(uint8_t handle, uint8_t label, uint8_t msg_mask)
+{
+    tAVRC_PARAM *param = static_cast<tAVRC_PARAM *>(osi_malloc(sizeof(tAVRC_PARAM)));
+    param->handle = handle;
+    param->label = label;
+    param->msg_mask = msg_mask;
+
+    AVRC_TRACE_DEBUG("AVRC: starting timer (handle=0x%02x, label=0x%02x)", handle, label);
+
+    alarm_set_on_queue(avrc_cb.ccb_int[handle].tle,
+                       AVRC_CMD_TOUT_MS,
+                       avrc_process_timeout, param,
+                       btu_general_alarm_queue);
+}
+
+/******************************************************************************
+**
+** Function         avrc_get_data_ptr
+**
+** Description      Gets a pointer to the data payload in the packet.
+**
+** Returns          A pointer to the data payload.
+**
+******************************************************************************/
+static uint8_t * avrc_get_data_ptr(BT_HDR *p_pkt)
+{
+    return (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+}
+
+/******************************************************************************
+**
+** Function         avrc_copy_packet
+**
+** Description      Copies an AVRC packet to a new buffer. In the new buffer,
+**                  the payload offset is at least AVCT_MSG_OFFSET octets.
+**
+** Returns          The buffer with the copied data.
+**
+******************************************************************************/
+static BT_HDR * avrc_copy_packet(BT_HDR *p_pkt, int rsp_pkt_len)
+{
+    const int offset = MAX(AVCT_MSG_OFFSET, p_pkt->offset);
+    const int pkt_len = MAX(rsp_pkt_len, p_pkt->len);
+    BT_HDR *p_pkt_copy = (BT_HDR *)osi_malloc(BT_HDR_SIZE + offset + pkt_len);
+
+    /* Copy the packet header, set the new offset, and copy the payload */
+    memcpy(p_pkt_copy, p_pkt, BT_HDR_SIZE);
+    p_pkt_copy->offset = offset;
+    uint8_t *p_data = avrc_get_data_ptr(p_pkt);
+    uint8_t *p_data_copy = avrc_get_data_ptr(p_pkt_copy);
+    memcpy(p_data_copy, p_data, p_pkt->len);
+
+    return p_pkt_copy;
+}
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+/******************************************************************************
+**
+** Function         avrc_prep_end_frag
+**
+** Description      This function prepares an end response fragment
+**
+** Returns          Nothing.
+**
+******************************************************************************/
+static void avrc_prep_end_frag(uint8_t handle)
+{
+    tAVRC_FRAG_CB   *p_fcb;
+    BT_HDR  *p_pkt_new;
+    uint8_t *p_data, *p_orig_data;
+    uint8_t rsp_type;
+
+    AVRC_TRACE_DEBUG ("%s", __func__ );
+    p_fcb = &avrc_cb.fcb[handle];
+
+    /* The response type of the end fragment should be the same as the the PDU of "End Fragment
+    ** Response" Errata: https://www.bluetooth.org/errata/errata_view.cfm?errata_id=4383
+    */
+    p_orig_data = ((uint8_t *)(p_fcb->p_fmsg + 1) + p_fcb->p_fmsg->offset);
+    rsp_type = ((*p_orig_data) & AVRC_CTYPE_MASK);
+
+    p_pkt_new           = p_fcb->p_fmsg;
+    p_pkt_new->len      -= (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE);
+    p_pkt_new->offset   += (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE);
+    p_data = (uint8_t *)(p_pkt_new+1) + p_pkt_new->offset;
+    *p_data++       = rsp_type;
+    *p_data++       = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
+    *p_data++       = AVRC_OP_VENDOR;
+    AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
+    *p_data++       = p_fcb->frag_pdu;
+    *p_data++       = AVRC_PKT_END;
+
+    /* 4=pdu, pkt_type & len */
+    UINT16_TO_BE_STREAM(p_data, (p_pkt_new->len - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE));
+}
+
+/******************************************************************************
+**
+** Function         avrc_send_continue_frag
+**
+** Description      This function sends a continue response fragment
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+static uint16_t avrc_send_continue_frag(uint8_t handle, uint8_t label)
+{
+    tAVRC_FRAG_CB   *p_fcb;
+    BT_HDR  *p_pkt_old, *p_pkt;
+    uint8_t *p_old, *p_data;
+    uint8_t cr = AVCT_RSP;
+
+    p_fcb = &avrc_cb.fcb[handle];
+    p_pkt = p_fcb->p_fmsg;
+
+    AVRC_TRACE_DEBUG("%s handle = %u label = %u len = %d",
+                     __func__, handle, label, p_pkt->len);
+    if (p_pkt->len > AVRC_MAX_CTRL_DATA_LEN) {
+        int offset_len = MAX(AVCT_MSG_OFFSET, p_pkt->offset);
+        p_pkt_old = p_fcb->p_fmsg;
+        p_pkt = (BT_HDR *)osi_malloc(AVRC_PACKET_LEN + offset_len + BT_HDR_SIZE);
+        p_pkt->len = AVRC_MAX_CTRL_DATA_LEN;
+        p_pkt->offset = AVCT_MSG_OFFSET;
+        p_pkt->layer_specific = p_pkt_old->layer_specific;
+        p_pkt->event = p_pkt_old->event;
+        p_old = (uint8_t *)(p_pkt_old + 1) + p_pkt_old->offset;
+        p_data = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+        memcpy (p_data, p_old, AVRC_MAX_CTRL_DATA_LEN);
+        /* use AVRC continue packet type */
+        p_data += AVRC_VENDOR_HDR_SIZE;
+        p_data++; /* pdu */
+        *p_data++ = AVRC_PKT_CONTINUE;
+        /* 4=pdu, pkt_type & len */
+        UINT16_TO_BE_STREAM(p_data, (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - 4));
+
+        /* prepare the left over for as an end fragment */
+        avrc_prep_end_frag (handle);
+    } else {
+        /* end fragment. clean the control block */
+        p_fcb->frag_enabled = false;
+        p_fcb->p_fmsg       = NULL;
+    }
+    return AVCT_MsgReq( handle, label, cr, p_pkt);
+}
+
+/******************************************************************************
+**
+** Function         avrc_proc_vendor_command
+**
+** Description      This function processes received vendor command.
+**
+** Returns          if not NULL, the response to send right away.
+**
+******************************************************************************/
+static BT_HDR * avrc_proc_vendor_command(uint8_t handle, uint8_t label,
+                               BT_HDR *p_pkt, tAVRC_MSG_VENDOR *p_msg)
+{
+    BT_HDR      *p_rsp = NULL;
+    uint8_t     *p_data;
+    uint8_t     *p_begin;
+    uint8_t     pkt_type;
+    bool        abort_frag = false;
+    tAVRC_STS   status = AVRC_STS_NO_ERROR;
+    tAVRC_FRAG_CB   *p_fcb;
+
+    p_begin  = (uint8_t *)(p_pkt+1) + p_pkt->offset;
+    p_data   = p_begin + AVRC_VENDOR_HDR_SIZE;
+    pkt_type = *(p_data + 1) & AVRC_PKT_TYPE_MASK;
+
+    if (pkt_type != AVRC_PKT_SINGLE)
+    {
+        /* reject - commands can only be in single packets at AVRCP level */
+        AVRC_TRACE_ERROR ("commands must be in single packet pdu:0x%x", *p_data );
+        /* use the current GKI buffer to send the reject */
+        status = AVRC_STS_BAD_CMD;
+    }
+    /* check if there are fragments waiting to be sent */
+    else if (avrc_cb.fcb[handle].frag_enabled)
+    {
+        p_fcb = &avrc_cb.fcb[handle];
+        if (p_msg->company_id == AVRC_CO_METADATA)
+        {
+            switch (*p_data)
+            {
+            case AVRC_PDU_ABORT_CONTINUATION_RSP:
+                /* aborted by CT - send accept response */
+                abort_frag = true;
+                p_begin = (uint8_t *)(p_pkt+1) + p_pkt->offset;
+                *p_begin = (AVRC_RSP_ACCEPT & AVRC_CTYPE_MASK);
+                if (*(p_data + 4) != p_fcb->frag_pdu)
+                {
+                    *p_begin = (AVRC_RSP_REJ & AVRC_CTYPE_MASK);
+                    *(p_data + 4) = AVRC_STS_BAD_PARAM;
+                }
+                else
+                {
+                    p_data = (p_begin + AVRC_VENDOR_HDR_SIZE + 2);
+                    UINT16_TO_BE_STREAM(p_data, 0);
+                    p_pkt->len = (p_data - p_begin);
+                }
+                AVCT_MsgReq( handle, label, AVCT_RSP, p_pkt);
+                p_msg->hdr.opcode = AVRC_OP_DROP; /* used the p_pkt to send response */
+                break;
+
+            case AVRC_PDU_REQUEST_CONTINUATION_RSP:
+                if (*(p_data + 4) == p_fcb->frag_pdu)
+                {
+                    avrc_send_continue_frag(handle, label);
+                    p_msg->hdr.opcode = AVRC_OP_DROP_N_FREE;
+                }
+                else
+                {
+                    /* the pdu id does not match - reject the command using the current GKI buffer */
+                    AVRC_TRACE_ERROR("%s continue pdu: 0x%x does not match the current pdu: 0x%x",
+                            __func__, *(p_data + 4), p_fcb->frag_pdu);
+                    status = AVRC_STS_BAD_PARAM;
+                    abort_frag = true;
+                }
+                break;
+
+            default:
+                /* implicit abort */
+                abort_frag = true;
+            }
+        }
+        else
+        {
+            abort_frag = true;
+            /* implicit abort */
+        }
+
+        if (abort_frag)
+        {
+            osi_free_and_reset((void **)&p_fcb->p_fmsg);
+            p_fcb->frag_enabled = false;
+        }
+    }
+
+    if (status != AVRC_STS_NO_ERROR)
+    {
+        /* use the current GKI buffer to build/send the reject message */
+        p_data = (uint8_t *)(p_pkt+1) + p_pkt->offset;
+        *p_data++ = AVRC_RSP_REJ;
+        p_data += AVRC_VENDOR_HDR_SIZE; /* pdu */
+        *p_data++ = 0;                  /* pkt_type */
+        UINT16_TO_BE_STREAM(p_data, 1); /* len */
+        *p_data++ = status;             /* error code */
+        p_pkt->len = AVRC_VENDOR_HDR_SIZE + 5;
+        p_rsp = p_pkt;
+    }
+
+    return p_rsp;
+}
+
+/******************************************************************************
+**
+** Function         avrc_proc_far_msg
+**
+** Description      This function processes metadata fragmenation
+**                  and reassembly
+**
+** Returns          0, to report the message with msg_cback .
+**
+******************************************************************************/
+static uint8_t avrc_proc_far_msg(uint8_t handle, uint8_t label, uint8_t cr, BT_HDR **pp_pkt,
+    tAVRC_MSG_VENDOR *p_msg)
+{
+    BT_HDR      *p_pkt = *pp_pkt;
+    uint8_t     *p_data;
+    uint8_t     drop_code = 0;
+    bool        buf_overflow = false;
+    BT_HDR      *p_rsp = NULL;
+    BT_HDR      *p_cmd = NULL;
+    bool        req_continue = false;
+    BT_HDR      *p_pkt_new = NULL;
+    uint8_t     pkt_type;
+    tAVRC_RASM_CB   *p_rcb;
+    tAVRC_NEXT_CMD   avrc_cmd;
+    tAVRC_STS   status;
+
+    p_data  = (uint8_t *)(p_pkt+1) + p_pkt->offset;
+
+    /* Skip over vendor header (ctype, subunit*, opcode, CO_ID) */
+    p_data += AVRC_VENDOR_HDR_SIZE;
+
+    pkt_type = *(p_data + 1) & AVRC_PKT_TYPE_MASK;
+    AVRC_TRACE_DEBUG ("pkt_type %d", pkt_type );
+    p_rcb = &avrc_cb.rcb[handle];
+
+    /* check if the message needs to be re-assembled */
+    if (pkt_type == AVRC_PKT_SINGLE || pkt_type == AVRC_PKT_START)
+    {
+        /* previous fragments need to be dropped, when received another new message */
+        p_rcb->rasm_offset = 0;
+        osi_free_and_reset((void **)&p_rcb->p_rmsg);
+    }
+
+    if (pkt_type != AVRC_PKT_SINGLE && cr == AVCT_RSP)
+    {
+        /* not a single response packet - need to re-assemble metadata messages */
+        if (pkt_type == AVRC_PKT_START) {
+            /* Allocate buffer for re-assembly */
+            p_rcb->rasm_pdu = *p_data;
+            p_rcb->p_rmsg = (BT_HDR *)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+            /* Copy START packet to buffer for re-assembling fragments */
+            memcpy(p_rcb->p_rmsg, p_pkt, sizeof(BT_HDR)); /* Copy bt hdr */
+
+            /* Copy metadata message */
+            memcpy((uint8_t *)(p_rcb->p_rmsg + 1),
+                    (uint8_t *)(p_pkt+1) + p_pkt->offset, p_pkt->len);
+
+            /* offset of start of metadata response in reassembly buffer */
+            p_rcb->p_rmsg->offset = p_rcb->rasm_offset = 0;
+
+            /*
+                * Free original START packet, replace with pointer to
+                * reassembly buffer.
+                */
+            osi_free(p_pkt);
+            *pp_pkt = p_rcb->p_rmsg;
+
+            /*
+                * Set offset to point to where to copy next - use the same
+                * reassembly logic as AVCT.
+                */
+            p_rcb->p_rmsg->offset += p_rcb->p_rmsg->len;
+            req_continue = true;
+        } else if (p_rcb->p_rmsg == NULL) {
+            /* Received a CONTINUE/END, but no corresponding START
+                            (or previous fragmented response was dropped) */
+            AVRC_TRACE_DEBUG ("Received a CONTINUE/END without no corresponding START \
+                                (or previous fragmented response was dropped)");
+            drop_code = 5;
+            osi_free(p_pkt);
+            *pp_pkt = NULL;
+        }
+        else
+        {
+            /* get size of buffer holding assembled message */
+            /*
+                * NOTE: The buffer is allocated above at the beginning of the
+                * reassembly, and is always of size BT_DEFAULT_BUFFER_SIZE.
+                */
+            uint16_t buf_len = BT_DEFAULT_BUFFER_SIZE - sizeof(BT_HDR);
+            /* adjust offset and len of fragment for header byte */
+            p_pkt->offset += (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE);
+            p_pkt->len -= (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE);
+            /* verify length */
+            if ((p_rcb->p_rmsg->offset + p_pkt->len) > buf_len)
+            {
+                AVRC_TRACE_WARNING("Fragmented message too big! - report the partial message");
+                p_pkt->len = buf_len - p_rcb->p_rmsg->offset;
+                pkt_type = AVRC_PKT_END;
+                buf_overflow = true;
+            }
+
+            /* copy contents of p_pkt to p_rx_msg */
+            memcpy((uint8_t *)(p_rcb->p_rmsg + 1) + p_rcb->p_rmsg->offset,
+                    (uint8_t *)(p_pkt + 1) + p_pkt->offset, p_pkt->len);
+
+            if (pkt_type == AVRC_PKT_END)
+            {
+                p_rcb->p_rmsg->offset = p_rcb->rasm_offset;
+                p_rcb->p_rmsg->len += p_pkt->len;
+                p_pkt_new = p_rcb->p_rmsg;
+                p_rcb->rasm_offset = 0;
+                p_rcb->p_rmsg = NULL;
+                p_msg->p_vendor_data   = (uint8_t *)(p_pkt_new+1) + p_pkt_new->offset;
+                p_msg->hdr.ctype       = p_msg->p_vendor_data[0] & AVRC_CTYPE_MASK;
+                /* 6 = ctype, subunit*, opcode & CO_ID */
+                p_msg->p_vendor_data  += AVRC_VENDOR_HDR_SIZE;
+                p_msg->vendor_len      = p_pkt_new->len - AVRC_VENDOR_HDR_SIZE;
+                p_data = p_msg->p_vendor_data + 1; /* skip pdu */
+                *p_data++ = AVRC_PKT_SINGLE;
+                UINT16_TO_BE_STREAM(p_data, (p_msg->vendor_len - AVRC_MIN_META_HDR_SIZE));
+                AVRC_TRACE_DEBUG("end frag:%d, total len:%d, offset:%d", p_pkt->len,
+                    p_pkt_new->len, p_pkt_new->offset);
+            }
+            else
+            {
+                p_rcb->p_rmsg->offset += p_pkt->len;
+                p_rcb->p_rmsg->len += p_pkt->len;
+                p_pkt_new = NULL;
+                req_continue = true;
+            }
+            osi_free(p_pkt);
+            *pp_pkt = p_pkt_new;
+        }
+    }
+
+    if (cr == AVCT_CMD)
+    {
+        p_rsp = avrc_proc_vendor_command(handle, label, *pp_pkt, p_msg);
+        if (p_rsp)
+        {
+            AVCT_MsgReq( handle, label, AVCT_RSP, p_rsp);
+            drop_code = 3;
+        }
+        else if (p_msg->hdr.opcode == AVRC_OP_DROP)
+        {
+            drop_code = 1;
+        }
+        else if (p_msg->hdr.opcode == AVRC_OP_DROP_N_FREE)
+            drop_code = 4;
+
+    }
+    else if (cr == AVCT_RSP)
+    {
+        if (req_continue == true)
+        {
+            avrc_cmd.pdu    = AVRC_PDU_REQUEST_CONTINUATION_RSP;
+            drop_code = 2;
+        }
+        else if (buf_overflow == true)
+        {
+            /* Incoming message too big to fit in BT_DEFAULT_BUFFER_SIZE. Send abort to peer  */
+            avrc_cmd.pdu    = AVRC_PDU_ABORT_CONTINUATION_RSP;
+            drop_code = 4;
+        }
+        else
+        {
+            return drop_code;
+        }
+        avrc_cmd.status = AVRC_STS_NO_ERROR;
+        avrc_cmd.target_pdu = p_rcb->rasm_pdu;
+        status = AVRC_BldCommand ((tAVRC_COMMAND *)&avrc_cmd, &p_cmd);
+        if (status == AVRC_STS_NO_ERROR)
+        {
+            AVRC_MsgReq (handle, (uint8_t)(label), AVRC_CMD_CTRL, p_cmd);
+        }
+    }
+
+    return drop_code;
+}
+#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
+
+/******************************************************************************
+**
+** Function         avrc_msg_cback
+**
+** Description      This is the callback function used by AVCTP to report
+**                  received AV control messages.
+**
+** Returns          Nothing.
+**
+******************************************************************************/
+static void avrc_msg_cback(uint8_t handle, uint8_t label, uint8_t cr,
+                               BT_HDR *p_pkt)
+{
+    uint8_t     opcode;
+    tAVRC_MSG   msg;
+    uint8_t     *p_data;
+    uint8_t     *p_begin;
+    bool        drop = false;
+    bool        do_free = true;
+    BT_HDR      *p_rsp = NULL;
+    uint8_t     *p_rsp_data;
+    int         xx;
+    bool        reject = false;
+    const char  *p_drop_msg = "dropped";
+    tAVRC_MSG_VENDOR *p_msg = &msg.vendor;
+
+    if (cr == AVCT_CMD &&
+        (p_pkt->layer_specific & AVCT_DATA_CTRL && AVRC_PACKET_LEN < sizeof(p_pkt->len)))
+    {
+        /* Ignore the invalid AV/C command frame */
+        p_drop_msg = "dropped - too long AV/C cmd frame size";
+        osi_free(p_pkt);
+        return;
+    }
+
+    if (cr == AVCT_REJ)
+    {
+        /* The peer thinks that this PID is no longer open - remove this handle */
+        /*  */
+        osi_free(p_pkt);
+        AVCT_RemoveConn(handle);
+        return;
+    }
+    else if (cr == AVCT_RSP)
+    {
+        /* Received response. Stop command timeout timer */
+        AVRC_TRACE_DEBUG("AVRC: stopping timer (handle=0x%02x)", handle);
+        alarm_cancel(avrc_cb.ccb_int[handle].tle);
+    }
+
+    p_data  = (uint8_t *)(p_pkt+1) + p_pkt->offset;
+    memset(&msg, 0, sizeof(tAVRC_MSG) );
+
+    if (p_pkt->layer_specific == AVCT_DATA_BROWSE)
+    {
+        opcode = AVRC_OP_BROWSE;
+        msg.browse.hdr.ctype= cr;
+        msg.browse.p_browse_data   = p_data;
+        msg.browse.browse_len      = p_pkt->len;
+        msg.browse.p_browse_pkt    = p_pkt;
+    }
+    else
+    {
+        msg.hdr.ctype           = p_data[0] & AVRC_CTYPE_MASK;
+        AVRC_TRACE_DEBUG("%s handle:%d, ctype:%d, offset:%d, len: %d", __func__,
+                handle, msg.hdr.ctype, p_pkt->offset, p_pkt->len);
+        msg.hdr.subunit_type    = (p_data[1] & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
+        msg.hdr.subunit_id      = p_data[1] & AVRC_SUBID_MASK;
+        opcode                  = p_data[2];
+    }
+
+    if ( ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD)) ||
+        ((avrc_cb.ccb[handle].control & AVRC_CT_CONTROL) && (cr == AVCT_RSP)) )
+    {
+
+        switch(opcode)
+        {
+        case AVRC_OP_UNIT_INFO:
+            if (cr == AVCT_CMD)
+            {
+                /* send the response to the peer */
+                p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_UNIT_INFO_RSP_LEN);
+                p_rsp_data = avrc_get_data_ptr(p_rsp);
+                *p_rsp_data = AVRC_RSP_IMPL_STBL;
+                /* check & set the offset. set response code, set subunit_type & subunit_id,
+                   set AVRC_OP_UNIT_INFO */
+                /* 3 bytes: ctype, subunit*, opcode */
+                p_rsp_data      += AVRC_AVC_HDR_SIZE;
+                *p_rsp_data++   = 7;
+                /* Panel subunit & id=0 */
+                *p_rsp_data++   = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
+                AVRC_CO_ID_TO_BE_STREAM(p_rsp_data, avrc_cb.ccb[handle].company_id);
+                p_rsp->len      = (uint16_t) (p_rsp_data - (uint8_t *)(p_rsp + 1) - p_rsp->offset);
+                cr = AVCT_RSP;
+                p_drop_msg = "auto respond";
+            }
+            else
+            {
+                /* parse response */
+                p_data += 4; /* 3 bytes: ctype, subunit*, opcode + octet 3 (is 7)*/
+                msg.unit.unit_type  = (*p_data & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
+                msg.unit.unit       = *p_data & AVRC_SUBID_MASK;
+                p_data++;
+                AVRC_BE_STREAM_TO_CO_ID(msg.unit.company_id, p_data);
+            }
+            break;
+
+        case AVRC_OP_SUB_INFO:
+            if (cr == AVCT_CMD)
+            {
+                /* send the response to the peer */
+                p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_SUB_UNIT_INFO_RSP_LEN);
+                p_rsp_data = avrc_get_data_ptr(p_rsp);
+                *p_rsp_data = AVRC_RSP_IMPL_STBL;
+                /* check & set the offset. set response code, set (subunit_type & subunit_id),
+                   set AVRC_OP_SUB_INFO, set (page & extention code) */
+                p_rsp_data      += 4;
+                /* Panel subunit & id=0 */
+                *p_rsp_data++   = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
+                memset(p_rsp_data, AVRC_CMD_OPRND_PAD, AVRC_SUBRSP_OPRND_BYTES);
+                p_rsp_data      += AVRC_SUBRSP_OPRND_BYTES;
+                p_rsp->len      = (uint16_t) (p_rsp_data - (uint8_t *)(p_rsp + 1) - p_rsp->offset);
+                cr = AVCT_RSP;
+                p_drop_msg = "auto responded";
+            }
+            else
+            {
+                /* parse response */
+                p_data += AVRC_AVC_HDR_SIZE; /* 3 bytes: ctype, subunit*, opcode */
+                msg.sub.page    = (*p_data++ >> AVRC_SUB_PAGE_SHIFT) & AVRC_SUB_PAGE_MASK;
+                xx      = 0;
+                while (*p_data != AVRC_CMD_OPRND_PAD && xx<AVRC_SUB_TYPE_LEN)
+                {
+                    msg.sub.subunit_type[xx] = *p_data++ >> AVRC_SUBTYPE_SHIFT;
+                    if (msg.sub.subunit_type[xx] == AVRC_SUB_PANEL)
+                        msg.sub.panel   = true;
+                    xx++;
+                }
+            }
+            break;
+
+        case AVRC_OP_VENDOR:
+        {
+            p_data  = (uint8_t *)(p_pkt+1) + p_pkt->offset;
+            p_begin = p_data;
+            if (p_pkt->len < AVRC_VENDOR_HDR_SIZE) /* 6 = ctype, subunit*, opcode & CO_ID */
+            {
+                if (cr == AVCT_CMD)
+                    reject = true;
+                else
+                    drop = true;
+                break;
+            }
+            p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */
+            AVRC_BE_STREAM_TO_CO_ID(p_msg->company_id, p_data);
+            p_msg->p_vendor_data   = p_data;
+            p_msg->vendor_len      = p_pkt->len - (p_data - p_begin);
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+            uint8_t drop_code = 0;
+            if (p_msg->company_id == AVRC_CO_METADATA)
+            {
+                /* Validate length for metadata message */
+                if (p_pkt->len < (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE))
+                {
+                    if (cr == AVCT_CMD)
+                        reject = true;
+                    else
+                        drop = true;
+                    break;
+                }
+
+                /* Check+handle fragmented messages */
+                drop_code = avrc_proc_far_msg(handle, label, cr, &p_pkt, p_msg);
+                if (drop_code > 0)
+                    drop = true;
+            }
+            if (drop_code > 0)
+            {
+                if (drop_code != 4)
+                    do_free = false;
+                switch (drop_code)
+                {
+                case 1:
+                    p_drop_msg = "sent_frag";
+                    break;
+                case 2:
+                    p_drop_msg = "req_cont";
+                    break;
+                case 3:
+                    p_drop_msg = "sent_frag3";
+                    break;
+                case 4:
+                    p_drop_msg = "sent_frag_free";
+                    break;
+                default:
+                    p_drop_msg = "sent_fragd";
+                }
+            }
+#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
+           /* If vendor response received, and did not ask for continuation */
+           /* then check queue for addition commands to send */
+            if ((cr == AVCT_RSP) && (drop_code != 2))
+            {
+                avrc_send_next_vendor_cmd(handle);
+            }
+        }
+        break;
+
+        case AVRC_OP_PASS_THRU:
+            if (p_pkt->len < 5) /* 3 bytes: ctype, subunit*, opcode & op_id & len */
+            {
+                if (cr == AVCT_CMD)
+                    reject = true;
+                else
+                    drop = true;
+                break;
+            }
+            p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*, opcode */
+            msg.pass.op_id  = (AVRC_PASS_OP_ID_MASK & *p_data);
+            if (AVRC_PASS_STATE_MASK & *p_data)
+                msg.pass.state  = true;
+            else
+                msg.pass.state  = false;
+            p_data++;
+            msg.pass.pass_len    = *p_data++;
+            if (msg.pass.pass_len != p_pkt->len - 5)
+                msg.pass.pass_len = p_pkt->len - 5;
+            if (msg.pass.pass_len)
+                msg.pass.p_pass_data = p_data;
+            else
+                msg.pass.p_pass_data = NULL;
+            break;
+
+         case AVRC_OP_BROWSE:
+             /* If browse response received, then check queue for addition commands to send */
+             if (cr == AVCT_RSP)
+             {
+                 avrc_send_next_vendor_cmd(handle);
+             }
+             break;
+
+        default:
+            if ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD))
+            {
+                /* reject unsupported opcode */
+                reject = true;
+            }
+            drop    = true;
+            break;
+        }
+    }
+    else /* drop the event */
+    {
+        if (opcode != AVRC_OP_BROWSE)
+            drop    = true;
+    }
+
+    if (reject)
+    {
+        /* reject unsupported opcode */
+        p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_REJ_MSG_LEN);
+        p_rsp_data = avrc_get_data_ptr(p_rsp);
+        *p_rsp_data = AVRC_RSP_REJ;
+        p_drop_msg = "rejected";
+        cr      = AVCT_RSP;
+        drop    = true;
+    }
+
+    if (p_rsp)
+    {
+        /* set to send response right away */
+        AVCT_MsgReq( handle, label, cr, p_rsp);
+        drop = true;
+    }
+
+    if (drop == false)
+    {
+        msg.hdr.opcode = opcode;
+        (*avrc_cb.ccb[handle].p_msg_cback)(handle, label, opcode, &msg);
+    } else {
+        AVRC_TRACE_WARNING("%s %s msg handle:%d, control:%d, cr:%d, opcode:x%x",
+                __func__, p_drop_msg,
+                handle, avrc_cb.ccb[handle].control, cr, opcode);
+    }
+
+    if (opcode == AVRC_OP_BROWSE && msg.browse.p_browse_pkt == NULL)
+    {
+        do_free = false;
+    }
+
+    if (do_free)
+        osi_free(p_pkt);
+}
+
+static void AVRC_build_empty_packet(BT_HDR *p_pkt) {
+    uint8_t *p_start = ((uint8_t *)(p_pkt + 1) + p_pkt->offset);
+    *p_start = AVRC_RSP_ACCEPT & AVRC_CTYPE_MASK;
+    p_start += AVRC_VENDOR_HDR_SIZE;
+    UINT8_TO_BE_STREAM(p_start, 0);
+    UINT8_TO_BE_STREAM(p_start, AVRC_PKT_SINGLE);
+    UINT16_TO_BE_STREAM(p_start, 0);
+    p_pkt->len = AVRC_VENDOR_HDR_SIZE + 4;
+}
+
+static void AVRC_build_error_packet(BT_HDR *p_pkt) {
+    uint8_t *p_start = ((uint8_t *)(p_pkt + 1) + p_pkt->offset);
+    *p_start = AVRC_RSP_REJ & AVRC_CTYPE_MASK;
+    p_start += AVRC_VENDOR_HDR_SIZE;
+    UINT8_TO_BE_STREAM(p_start, 0);
+    UINT8_TO_BE_STREAM(p_start, AVRC_PKT_SINGLE);
+    UINT16_TO_BE_STREAM(p_start, 1);
+    UINT8_TO_BE_STREAM(p_start, AVRC_STS_BAD_PARAM);
+    p_pkt->len = AVRC_VENDOR_HDR_SIZE + 5;
+}
+
+static uint16_t AVRC_HandleContinueRsp(uint8_t handle, uint8_t label, BT_HDR *p_pkt)
+{
+    AVRC_TRACE_DEBUG("%s()", __func__);
+
+    uint8_t *p_data = ((uint8_t *)(p_pkt + 1) + p_pkt->offset + AVRC_VENDOR_HDR_SIZE);
+    tAVRC_FRAG_CB   *p_fcb = &avrc_cb.fcb[handle];
+
+    uint8_t pdu, pkt_type, target_pdu;
+    uint16_t len;
+
+    BE_STREAM_TO_UINT8(pdu, p_data);
+    BE_STREAM_TO_UINT8(pkt_type, p_data);
+    BE_STREAM_TO_UINT16(len, p_data);
+    BE_STREAM_TO_UINT8(target_pdu, p_data);
+
+    if (pdu == AVRC_PDU_REQUEST_CONTINUATION_RSP &&
+        target_pdu == p_fcb->frag_pdu) {
+        return avrc_send_continue_frag(handle, label);
+    }
+
+    if (pdu == AVRC_PDU_ABORT_CONTINUATION_RSP &&
+        target_pdu == p_fcb->frag_pdu) {
+        AVRC_build_empty_packet(p_pkt);
+    } else {
+        AVRC_TRACE_ERROR("%s() error: target_pdu: 0x%02x, frag_pdu: 0x%02x",
+                         __func__, *(p_data+4), p_fcb->frag_pdu);
+        AVRC_build_error_packet(p_pkt);
+    }
+
+    p_fcb->frag_enabled = FALSE;
+    osi_free_and_reset((void **)&p_fcb->p_fmsg);
+
+    return AVCT_MsgReq(handle, label, AVCT_RSP, p_pkt);
+}
+
+
+/******************************************************************************
+**
+** Function         avrc_pass_msg
+**
+** Description      Compose a PASS THROUGH command according to p_msg
+**
+**                  Input Parameters:
+**                      p_msg: Pointer to PASS THROUGH message structure.
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          pointer to a valid GKI buffer if successful.
+**                  NULL if p_msg is NULL.
+**
+******************************************************************************/
+static BT_HDR  * avrc_pass_msg(tAVRC_MSG_PASS *p_msg)
+{
+    assert(p_msg != NULL);
+    assert(AVRC_CMD_BUF_SIZE > (AVRC_MIN_CMD_LEN+p_msg->pass_len));
+
+    BT_HDR  *p_cmd = (BT_HDR *)osi_malloc(AVRC_CMD_BUF_SIZE);
+    p_cmd->offset = AVCT_MSG_OFFSET;
+    p_cmd->layer_specific = AVCT_DATA_CTRL;
+
+    uint8_t *p_data = (uint8_t *)(p_cmd + 1) + p_cmd->offset;
+    *p_data++ = (p_msg->hdr.ctype & AVRC_CTYPE_MASK);
+    *p_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT); /* Panel subunit & id=0 */
+    *p_data++ = AVRC_OP_PASS_THRU;
+    *p_data = (AVRC_PASS_OP_ID_MASK&p_msg->op_id);
+    if (p_msg->state)
+        *p_data     |= AVRC_PASS_STATE_MASK;
+    p_data++;
+
+    if (p_msg->op_id == AVRC_ID_VENDOR) {
+        *p_data++ = p_msg->pass_len;
+        if (p_msg->pass_len && p_msg->p_pass_data) {
+            memcpy(p_data, p_msg->p_pass_data, p_msg->pass_len);
+            p_data += p_msg->pass_len;
+        }
+    } else {
+        /* set msg len to 0 for other op_id */
+        *p_data++       = 0;
+    }
+    p_cmd->len = (uint16_t) (p_data - (uint8_t *)(p_cmd + 1) - p_cmd->offset);
+
+    return p_cmd;
+}
+
+/******************************************************************************
+**
+** Function         AVRC_Open
+**
+** Description      This function is called to open a connection to AVCTP.
+**                  The connection can be either an initiator or acceptor, as
+**                  determined by the p_ccb->stream parameter.
+**                  The connection can be a target, a controller or for both role,
+**                  as determined by the p_ccb->control parameter.
+**                  By definition, a target connection is an acceptor connection
+**                  that waits for an incoming AVCTP connection from the peer.
+**                  The connection remains available to the application until
+**                  the application closes it by calling AVRC_Close().  The
+**                  application does not need to reopen the connection after an
+**                  AVRC_CLOSE_IND_EVT is received.
+**
+**                  Input Parameters:
+**                      p_ccb->company_id: Company Identifier.
+**
+**                      p_ccb->p_ctrl_cback:  Pointer to control callback function.
+**
+**                      p_ccb->p_msg_cback:  Pointer to message callback function.
+**
+**                      p_ccb->conn: AVCTP connection role.  This is set to
+**                      AVCTP_INT for initiator connections and AVCTP_ACP
+**                      for acceptor connections.
+**
+**                      p_ccb->control: Control role.  This is set to
+**                      AVRC_CT_TARGET for target connections, AVRC_CT_CONTROL
+**                      for control connections or (AVRC_CT_TARGET|AVRC_CT_CONTROL)
+**                      for connections that support both roles.
+**
+**                      peer_addr: BD address of peer device.  This value is
+**                      only used for initiator connections; for acceptor
+**                      connections it can be set to NULL.
+**
+**                  Output Parameters:
+**                      p_handle: Pointer to handle.  This parameter is only
+**                                valid if AVRC_SUCCESS is returned.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_NO_RESOURCES if there are not enough resources to open
+**                  the connection.
+**
+******************************************************************************/
+uint16_t AVRC_Open(uint8_t *p_handle, tAVRC_CONN_CB *p_ccb, BD_ADDR_PTR peer_addr)
+{
+    uint16_t    status;
+    tAVCT_CC    cc;
+
+    cc.p_ctrl_cback = avrc_ctrl_cback;      /* Control callback */
+    cc.p_msg_cback  = avrc_msg_cback;       /* Message callback */
+    cc.pid          = UUID_SERVCLASS_AV_REMOTE_CONTROL;  /* Profile ID */
+    cc.role         = p_ccb->conn;          /* Initiator/acceptor role */
+    cc.control      = p_ccb->control;       /* Control role (Control/Target) */
+
+    status = AVCT_CreateConn(p_handle, &cc, peer_addr);
+    if (status == AVCT_SUCCESS)
+    {
+        memcpy(&avrc_cb.ccb[*p_handle], p_ccb, sizeof(tAVRC_CONN_CB));
+        memset(&avrc_cb.ccb_int[*p_handle], 0, sizeof(tAVRC_CONN_INT_CB));
+#if (AVRC_METADATA_INCLUDED == TRUE)
+        memset(&avrc_cb.fcb[*p_handle], 0, sizeof(tAVRC_FRAG_CB));
+        memset(&avrc_cb.rcb[*p_handle], 0, sizeof(tAVRC_RASM_CB));
+#endif
+        avrc_cb.ccb_int[*p_handle].tle = alarm_new("avrcp.commandTimer");
+        avrc_cb.ccb_int[*p_handle].cmd_q = fixed_queue_new(SIZE_MAX);
+    }
+    AVRC_TRACE_DEBUG("%s role: %d, control:%d status:%d, handle:%d", __func__,
+                      cc.role, cc.control, status, *p_handle);
+
+    return status;
+}
+
+/******************************************************************************
+**
+** Function         AVRC_Close
+**
+** Description      Close a connection opened with AVRC_Open().
+**                  This function is called when the
+**                  application is no longer using a connection.
+**
+**                  Input Parameters:
+**                      handle: Handle of this connection.
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+uint16_t AVRC_Close(uint8_t handle)
+{
+    AVRC_TRACE_DEBUG("%s handle:%d", __func__, handle);
+    return AVCT_RemoveConn(handle);
+}
+
+/******************************************************************************
+**
+** Function         AVRC_OpenBrowse
+**
+** Description      This function is called to open a browsing connection to AVCTP.
+**                  The connection can be either an initiator or acceptor, as
+**                  determined by the p_conn_role.
+**                  The handle is returned by a previous call to AVRC_Open.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_NO_RESOURCES if there are not enough resources to open
+**                  the connection.
+**
+******************************************************************************/
+uint16_t AVRC_OpenBrowse(uint8_t handle, uint8_t conn_role)
+{
+    return AVCT_CreateBrowse(handle, conn_role);
+}
+
+/******************************************************************************
+**
+** Function         AVRC_CloseBrowse
+**
+** Description      Close a connection opened with AVRC_OpenBrowse().
+**                  This function is called when the
+**                  application is no longer using a connection.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+uint16_t AVRC_CloseBrowse(uint8_t handle)
+{
+    return AVCT_RemoveBrowse(handle);
+}
+
+/******************************************************************************
+**
+** Function         AVRC_MsgReq
+**
+** Description      This function is used to send the AVRCP byte stream in p_pkt
+**                  down to AVCTP.
+**
+**                  It is expected that p_pkt->offset is at least AVCT_MSG_OFFSET
+**                  p_pkt->layer_specific is AVCT_DATA_CTRL or AVCT_DATA_BROWSE
+**                  p_pkt->event is AVRC_OP_VENDOR, AVRC_OP_PASS_THRU or AVRC_OP_BROWSE
+**                  The above BT_HDR settings are set by the AVRC_Bld* functions.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+uint16_t AVRC_MsgReq (uint8_t handle, uint8_t label, uint8_t ctype, BT_HDR *p_pkt)
+{
+#if (AVRC_METADATA_INCLUDED == TRUE)
+    uint8_t *p_data;
+    uint8_t cr = AVCT_CMD;
+    bool    chk_frag = true;
+    uint8_t *p_start = NULL;
+    tAVRC_FRAG_CB   *p_fcb;
+    uint16_t len;
+    uint16_t status;
+    uint8_t msg_mask = 0;
+    uint16_t  peer_mtu;
+
+    if (!p_pkt)
+        return AVRC_BAD_PARAM;
+
+    AVRC_TRACE_DEBUG("%s handle = %u label = %u ctype = %u len = %d",
+                     __func__, handle, label, ctype, p_pkt->len);
+
+    if (ctype >= AVRC_RSP_NOT_IMPL)
+        cr = AVCT_RSP;
+
+    p_data = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    if (*p_data == AVRC_PDU_REQUEST_CONTINUATION_RSP ||
+        *p_data == AVRC_PDU_ABORT_CONTINUATION_RSP) {
+        return AVRC_HandleContinueRsp(handle, label, p_pkt);
+    }
+
+    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);
+
+        /* 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;
+            }
+        }
+    }
+    else if (p_pkt->event == AVRC_OP_PASS_THRU)
+    {
+        /* add AVRCP Pass Through headers */
+        p_start = ((uint8_t *)(p_pkt + 1) + p_pkt->offset);
+        p_pkt->offset -= AVRC_PASS_THRU_SIZE;
+        p_pkt->len += AVRC_PASS_THRU_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_PASS_THRU;/* opcode */
+        *p_data++       = AVRC_ID_VENDOR;   /* operation id */
+        *p_data++       = 5;                /* operation data len */
+        AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
+    }
+    else
+    {
+        chk_frag = false;
+        peer_mtu = AVCT_GetBrowseMtu (handle);
+        if (p_pkt->len > (peer_mtu-AVCT_HDR_LEN_SINGLE))
+        {
+            AVRC_TRACE_ERROR ("%s bigger than peer mtu (p_pkt->len(%d) > peer_mtu(%d-%d))",
+                               __func__, p_pkt->len, peer_mtu, AVCT_HDR_LEN_SINGLE );
+            osi_free(p_pkt);
+            return AVRC_MSG_TOO_BIG;
+        }
+    }
+
+    /* abandon previous fragments */
+    p_fcb = &avrc_cb.fcb[handle];
+
+    if(p_fcb == NULL)
+    {
+        AVRC_TRACE_ERROR ("%s p_fcb is NULL", __func__ );
+        osi_free(p_pkt);
+        return AVRC_NOT_OPEN;
+    }
+
+    if (p_fcb->frag_enabled)
+        p_fcb->frag_enabled = false;
+
+    osi_free_and_reset((void **)&p_fcb->p_fmsg);
+
+    /* AVRCP spec has not defined any control channel commands that needs fragmentation at this level
+     * check for fragmentation only on the response */
+    if ((cr == AVCT_RSP) && (chk_frag == true))
+    {
+        if (p_pkt->len > AVRC_MAX_CTRL_DATA_LEN)
+        {
+            int offset_len = MAX(AVCT_MSG_OFFSET, p_pkt->offset);
+            BT_HDR *p_pkt_new =
+                (BT_HDR *)osi_malloc(AVRC_PACKET_LEN + offset_len + BT_HDR_SIZE);
+            if (p_start != NULL) {
+                p_fcb->frag_enabled = true;
+                p_fcb->p_fmsg       = p_pkt;
+                p_fcb->frag_pdu     = *p_start;
+                p_pkt               = p_pkt_new;
+                p_pkt_new           = p_fcb->p_fmsg;
+                p_pkt->len          = AVRC_MAX_CTRL_DATA_LEN;
+                p_pkt->offset       = p_pkt_new->offset;
+                p_pkt->layer_specific = p_pkt_new->layer_specific;
+                p_pkt->event = p_pkt_new->event;
+                p_data = (uint8_t *)(p_pkt+1) + p_pkt->offset;
+                p_start -= AVRC_VENDOR_HDR_SIZE;
+                memcpy (p_data, p_start, AVRC_MAX_CTRL_DATA_LEN);
+                /* use AVRC start packet type */
+                p_data += AVRC_VENDOR_HDR_SIZE;
+                p_data++; /* pdu */
+                *p_data++ = AVRC_PKT_START;
+
+                /* 4 pdu, pkt_type & len */
+                len = (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE);
+                UINT16_TO_BE_STREAM(p_data, len);
+
+                /* prepare the left over for as an end fragment */
+                avrc_prep_end_frag (handle);
+                AVRC_TRACE_DEBUG ("%s p_pkt len:%d/%d, next len:%d", __func__,
+                                  p_pkt->len, len, p_fcb->p_fmsg->len );
+            } else {
+                /* TODO: Is this "else" block valid? Remove it? */
+                AVRC_TRACE_ERROR ("%s no buffers for fragmentation", __func__ );
+                osi_free(p_pkt);
+                return AVRC_NO_RESOURCES;
+            }
+        }
+    }
+    else if ((p_pkt->event == AVRC_OP_VENDOR) && (cr == AVCT_CMD) &&
+        (avrc_cb.ccb_int[handle].flags & AVRC_CB_FLAGS_RSP_PENDING) &&
+        !(msg_mask & AVRC_MSG_MASK_IS_CONTINUATION_RSP))
+    {
+        /* If we are sending a vendor specific command, and a response is pending,
+         * then enqueue the command until the response has been received.
+         * This is to interop with TGs that abort sending responses whenever a new command
+         * is received (exception is continuation request command
+         * must sent that to get additional response frags) */
+        AVRC_TRACE_DEBUG("AVRC: Enqueuing command 0x%08x (handle=0x%02x, label=0x%02x)",
+                           p_pkt, handle, label);
+
+        /* label in BT_HDR (will need this later when the command is dequeued) */
+        p_pkt->layer_specific = (label << 8) | (p_pkt->layer_specific & 0xFF);
+
+        /* Enqueue the command */
+        fixed_queue_enqueue(avrc_cb.ccb_int[handle].cmd_q, p_pkt);
+        return AVRC_SUCCESS;
+    }
+
+    /* Send the message */
+    status = AVCT_MsgReq( handle, label, cr, p_pkt);
+    if ((status == AVCT_SUCCESS) && (cr == AVCT_CMD))
+    {
+        /* If a command was successfully sent, indicate that a response is pending */
+        avrc_cb.ccb_int[handle].flags |= AVRC_CB_FLAGS_RSP_PENDING;
+
+        /* Start command timer to wait for response */
+        avrc_start_cmd_timer(handle, label, msg_mask);
+    }
+
+    return status;
+#else
+    return AVRC_NO_RESOURCES;
+#endif
+}
+
+
+/******************************************************************************
+**
+** Function         AVRC_PassCmd
+**
+** Description      Send a PASS THROUGH command to the peer device.  This
+**                  function can only be called for controller role connections.
+**                  Any response message from the peer is passed back through
+**                  the tAVRC_MSG_CBACK callback function.
+**
+**                  Input Parameters:
+**                      handle: Handle of this connection.
+**
+**                      label: Transaction label.
+**
+**                      p_msg: Pointer to PASS THROUGH message structure.
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+uint16_t AVRC_PassCmd(uint8_t handle, uint8_t label, tAVRC_MSG_PASS *p_msg)
+{
+    BT_HDR *p_buf;
+    uint16_t status = AVRC_NO_RESOURCES;
+    if (!p_msg)
+        return AVRC_BAD_PARAM;
+
+    p_msg->hdr.ctype    = AVRC_CMD_CTRL;
+    p_buf = avrc_pass_msg(p_msg);
+    if (p_buf)
+    {
+        status = AVCT_MsgReq( handle, label, AVCT_CMD, p_buf);
+        if (status == AVCT_SUCCESS)
+        {
+            /* Start command timer to wait for response */
+            avrc_start_cmd_timer(handle, label, 0);
+        }
+    }
+    return (status);
+}
+
+/******************************************************************************
+**
+** Function         AVRC_PassRsp
+**
+** Description      Send a PASS THROUGH response to the peer device.  This
+**                  function can only be called for target role connections.
+**                  This function must be called when a PASS THROUGH command
+**                  message is received from the peer through the
+**                  tAVRC_MSG_CBACK callback function.
+**
+**                  Input Parameters:
+**                      handle: Handle of this connection.
+**
+**                      label: Transaction label.  Must be the same value as
+**                      passed with the command message in the callback function.
+**
+**                      p_msg: Pointer to PASS THROUGH message structure.
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+uint16_t AVRC_PassRsp(uint8_t handle, uint8_t label, tAVRC_MSG_PASS *p_msg)
+{
+    BT_HDR *p_buf;
+    if (!p_msg)
+        return AVRC_BAD_PARAM;
+
+    p_buf = avrc_pass_msg(p_msg);
+    if (p_buf)
+        return AVCT_MsgReq( handle, label, AVCT_RSP, p_buf);
+    return AVRC_NO_RESOURCES;
+}
+
diff --git a/bt/stack/avrc/avrc_bld_ct.cc b/bt/stack/avrc/avrc_bld_ct.cc
new file mode 100644
index 0000000..04ce575
--- /dev/null
+++ b/bt/stack/avrc/avrc_bld_ct.cc
@@ -0,0 +1,671 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2006-2013 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.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_common.h"
+#include "avrc_api.h"
+#include "avrc_defs.h"
+#include "avrc_int.h"
+
+/*****************************************************************************
+**  Global data
+*****************************************************************************/
+
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function         avrc_bld_next_cmd
+**
+** Description      This function builds the Request Continue or Abort command.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_next_cmd (tAVRC_NEXT_CMD *p_cmd, BT_HDR *p_pkt)
+{
+    uint8_t *p_data, *p_start;
+
+    AVRC_TRACE_API("avrc_bld_next_cmd");
+
+    /* get the existing length, if any, and also the num attributes */
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_start + 2; /* pdu + rsvd */
+
+    /* add fixed lenth 1 - pdu_id (1) */
+    UINT16_TO_BE_STREAM(p_data, 1);
+    UINT8_TO_BE_STREAM(p_data, p_cmd->target_pdu);
+    p_pkt->len = (p_data - p_start);
+
+    return AVRC_STS_NO_ERROR;
+}
+
+/*****************************************************************************
+**  the following commands are introduced in AVRCP 1.4
+*****************************************************************************/
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function         avrc_bld_set_abs_volume_cmd
+**
+** Description      This function builds the Set Absolute Volume command.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_set_abs_volume_cmd (tAVRC_SET_VOLUME_CMD *p_cmd, BT_HDR *p_pkt)
+{
+    uint8_t *p_data, *p_start;
+
+    AVRC_TRACE_API("avrc_bld_set_abs_volume_cmd");
+    /* get the existing length, if any, and also the num attributes */
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_start + 2; /* pdu + rsvd */
+    /* add fixed lenth 1 - volume (1) */
+    UINT16_TO_BE_STREAM(p_data, 1);
+    UINT8_TO_BE_STREAM(p_data, (AVRC_MAX_VOLUME & p_cmd->volume));
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_register_notifn
+**
+** Description      This function builds the register notification.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_register_notifn(BT_HDR * p_pkt, uint8_t event_id, uint32_t event_param)
+{
+    uint8_t *p_data, *p_start;
+
+    AVRC_TRACE_API("avrc_bld_register_notifn");
+    /* get the existing length, if any, and also the num attributes */
+    // Set the notify value
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_start + 2; /* pdu + rsvd */
+    /* add fixed length 5 -*/
+    UINT16_TO_BE_STREAM(p_data, 5);
+    UINT8_TO_BE_STREAM(p_data,event_id);
+    UINT32_TO_BE_STREAM(p_data, event_param);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+#endif
+#if (AVRC_CTRL_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function         avrc_bld_get_capability_cmd
+**
+** Description      This function builds the get capability command.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_capability_cmd(BT_HDR * p_pkt, uint8_t cap_id)
+{
+    AVRC_TRACE_API("avrc_bld_get_capability_cmd");
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    uint8_t *p_data = p_start + 2; /* pdu + rsvd */
+    /* add fixed length 1 -*/
+    UINT16_TO_BE_STREAM(p_data, 1);
+    UINT8_TO_BE_STREAM(p_data,cap_id);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_list_player_app_attr_cmd
+**
+** Description      This function builds the list player app attrib command.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_list_player_app_attr_cmd(BT_HDR * p_pkt)
+{
+    AVRC_TRACE_API("avrc_bld_list_player_app_attr_cmd");
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    uint8_t *p_data = p_start + 2; /* pdu + rsvd */
+    /* add fixed length 1 -*/
+    UINT16_TO_BE_STREAM(p_data, 0);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_list_player_app_values_cmd
+**
+** Description      This function builds the list player app values command.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_list_player_app_values_cmd(BT_HDR * p_pkt, uint8_t attrib_id)
+{
+    AVRC_TRACE_API("avrc_bld_list_player_app_values_cmd");
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    uint8_t *p_data = p_start + 2; /* pdu + rsvd */
+    /* add fixed length 1 -*/
+    UINT16_TO_BE_STREAM(p_data, 1);
+    UINT8_TO_BE_STREAM(p_data,attrib_id);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_current_player_app_values_cmd
+**
+** Description      This function builds the get current player app setting values command.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_current_player_app_values_cmd(
+    BT_HDR * p_pkt, uint8_t num_attrib_id, uint8_t* attrib_ids)
+{
+    AVRC_TRACE_API("avrc_bld_get_current_player_app_values_cmd");
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    uint8_t *p_data = p_start + 2; /* pdu + rsvd */
+    uint8_t param_len = num_attrib_id + 1; // 1 additional to hold num attributes feild
+    /* add length -*/
+    UINT16_TO_BE_STREAM(p_data, param_len);
+    UINT8_TO_BE_STREAM(p_data,num_attrib_id);
+    for(int count = 0; count < num_attrib_id; count ++)
+    {
+        UINT8_TO_BE_STREAM(p_data,attrib_ids[count]);
+    }
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_set_current_player_app_values_cmd
+**
+** Description      This function builds the set current player app setting values command.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_set_current_player_app_values_cmd(BT_HDR * p_pkt, uint8_t num_attrib_id, tAVRC_APP_SETTING* p_val)
+{
+    AVRC_TRACE_API("avrc_bld_set_current_player_app_values_cmd");
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    uint8_t *p_data = p_start + 2; /* pdu + rsvd */
+    /* we have to store attrib- value pair
+     * 1 additional to store num elements
+     */
+    uint8_t param_len = (2*num_attrib_id) + 1;
+    /* add length */
+    UINT16_TO_BE_STREAM(p_data, param_len);
+    UINT8_TO_BE_STREAM(p_data,num_attrib_id);
+    for(int count = 0; count < num_attrib_id; count ++)
+    {
+        UINT8_TO_BE_STREAM(p_data,p_val[count].attr_id);
+        UINT8_TO_BE_STREAM(p_data,p_val[count].attr_val);
+    }
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_player_app_setting_attr_text_cmd
+**
+** Description      This function builds the get player app setting attribute text command.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_player_app_setting_attr_text_cmd (BT_HDR * p_pkt, tAVRC_GET_APP_ATTR_TXT_CMD *p_cmd)
+{
+    AVRC_TRACE_API("%s", __func__);
+
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    uint8_t *p_data = p_start + 2; /* pdu + rsvd */
+
+    uint8_t param_len = p_cmd->num_attr + 1;
+    /* add length */
+    UINT16_TO_BE_STREAM(p_data, param_len);
+    UINT8_TO_BE_STREAM(p_data, p_cmd->num_attr);
+    for(int count = 0; count < p_cmd->num_attr; count++)
+    {
+        UINT8_TO_BE_STREAM(p_data, p_cmd->attrs[count]);
+    }
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_player_app_setting_value_text_cmd
+**
+** Description      This function builds the get player app setting value text command.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_player_app_setting_value_text_cmd (BT_HDR * p_pkt, tAVRC_GET_APP_VAL_TXT_CMD *p_cmd)
+{
+    AVRC_TRACE_API("%s", __func__);
+
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    uint8_t *p_data = p_start + 2; /* pdu + rsvd */
+
+    uint8_t param_len = p_cmd->num_val + 1;
+    /* add length */
+    UINT16_TO_BE_STREAM(p_data, param_len);
+    UINT8_TO_BE_STREAM(p_data, p_cmd->num_val);
+    for(int count = 0; count < p_cmd->num_val; count++)
+    {
+        UINT8_TO_BE_STREAM(p_data, p_cmd->vals[count]);
+    }
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_element_attr_cmd
+**
+** Description      This function builds the get element attribute command.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_element_attr_cmd(BT_HDR * p_pkt, uint8_t num_attrib, uint32_t* attrib_ids)
+{
+    AVRC_TRACE_API("avrc_bld_get_element_attr_cmd");
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    uint8_t *p_data = p_start + 2; /* pdu + rsvd */
+    /* we have to store attrib- value pair
+     * 1 additional to store num elements
+     */
+    uint8_t param_len = (4*num_attrib) + 9;
+    /* add length */
+    UINT16_TO_BE_STREAM(p_data, param_len);
+    /* 8 bytes of identifier as 0 (playing)*/
+    UINT32_TO_BE_STREAM(p_data,0);
+    UINT32_TO_BE_STREAM(p_data,0);
+    UINT8_TO_BE_STREAM(p_data,num_attrib);
+    for(int count = 0; count < num_attrib; count ++)
+    {
+        UINT32_TO_BE_STREAM(p_data,attrib_ids[count]);
+    }
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_play_item_cmd
+**
+** Description      This function builds the play item cmd
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_play_item_cmd(
+    BT_HDR * p_pkt, uint8_t scope, uint8_t *uid, uint16_t uid_counter)
+{
+    AVRC_TRACE_API("avrc_bld_get_element_attr_cmd");
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    uint8_t *p_data = p_start + 2; /* pdu + rsvd */
+    /* add fixed length 11 */
+    UINT16_TO_BE_STREAM(p_data, 0xb);
+    /* Add scope */
+    UINT8_TO_BE_STREAM(p_data, scope);
+    /* Add UID */
+    ARRAY_TO_BE_STREAM(p_data, uid, AVRC_UID_SIZE);
+    /* Add UID Counter */
+    UINT16_TO_BE_STREAM(p_data, uid_counter);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_play_status_cmd
+**
+** Description      This function builds the get play status command.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_play_status_cmd(BT_HDR * p_pkt)
+{
+    AVRC_TRACE_API("avrc_bld_list_player_app_attr_cmd");
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    uint8_t *p_data = p_start + 2; /* pdu + rsvd */
+    /* add fixed length 0 -*/
+    UINT16_TO_BE_STREAM(p_data, 0);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_folder_items_cmd
+**
+** Description      This function builds the get folder items cmd.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_folder_items_cmd(BT_HDR *p_pkt, const tAVRC_GET_ITEMS_CMD *cmd)
+{
+    AVRC_TRACE_API("avrc_bld_get_folder_items_cmd scope %d, start_item %d, end_item %d",
+                   cmd->scope, cmd->start_item, cmd->end_item);
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    /* This is where the PDU specific for AVRC starts
+     * AVRCP Spec 1.4 section 22.19 */
+    uint8_t *p_data = p_start + 1; /* pdu */
+
+    /* To get the list of all media players we simply need to use the predefined
+     * PDU mentioned in above spec. */
+    /* scope (1) + st item (4) + end item (4) + attr (1) */
+    UINT16_TO_BE_STREAM(p_data, 10);
+    UINT8_TO_BE_STREAM(p_data, cmd->scope); /* scope (1bytes) */
+    UINT32_TO_BE_STREAM(p_data, cmd->start_item); /* start item (4bytes) */
+    UINT32_TO_BE_STREAM(p_data, cmd->end_item); /* end item (4bytes) */
+    UINT8_TO_BE_STREAM(p_data, 0); /* attribute count = 0 (1bytes) */
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_change_folder_cmd
+**
+** Description      This function builds the change folder command
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_change_folder_cmd(BT_HDR *p_pkt, const tAVRC_CHG_PATH_CMD *cmd)
+{
+    AVRC_TRACE_API("avrc_bld_change_folder_cmd");
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    /* This is where the PDU specific for AVRC starts
+     * AVRCP Spec 1.4 section 22.19 */
+    uint8_t *p_data = p_start + 1; /* pdu */
+
+    /* To change folder we need to provide the following:
+     * UID Counter (2) + Direction (1) + UID (8) = 11bytes
+     */
+    UINT16_TO_BE_STREAM(p_data, 11);
+    UINT16_TO_BE_STREAM(p_data, cmd->uid_counter);
+    UINT8_TO_BE_STREAM(p_data, cmd->direction);
+    ARRAY_TO_BE_STREAM(p_data, cmd->folder_uid, AVRC_UID_SIZE);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_set_browsed_player_cmd
+**
+** Description      This function builds the set browsed player cmd.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_set_browsed_player_cmd(BT_HDR *p_pkt, const tAVRC_SET_BR_PLAYER_CMD *cmd)
+{
+    AVRC_TRACE_API("%s", __func__);
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    /* This is where the PDU specific for AVRC starts
+     * AVRCP Spec 1.4 section 22.19 */
+    uint8_t *p_data = p_start + 1; /* pdu */
+
+    /* To change browsed player the following is the total length:
+     * Player ID (2)
+     */
+    UINT16_TO_BE_STREAM(p_data, 2); /* fixed length */
+    UINT16_TO_BE_STREAM(p_data, cmd->player_id);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_set_addressed_player_cmd
+**
+** Description      This function builds the set addressed player cmd.
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_set_addressed_player_cmd(
+    BT_HDR *p_pkt, const tAVRC_SET_ADDR_PLAYER_CMD *cmd)
+{
+    AVRC_TRACE_API("%s", __func__);
+    /* get the existing length, if any, and also the num attributes */
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    uint8_t *p_data = p_data = p_start + 2; /* pdu + rsvd */
+
+    /* To change addressed player the following is the total length:
+     * Player ID (2)
+     */
+    UINT16_TO_BE_STREAM(p_data, 2); /* fixed length */
+    UINT16_TO_BE_STREAM(p_data, cmd->player_id);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         avrc_bld_init_cmd_buffer
+**
+** Description      This function initializes the command buffer based on PDU
+**
+** Returns          NULL, if no GKI buffer or failure to build the message.
+**                  Otherwise, the GKI buffer that contains the initialized message.
+**
+*******************************************************************************/
+static BT_HDR *avrc_bld_init_cmd_buffer(tAVRC_COMMAND *p_cmd)
+{
+    uint16_t chnl = AVCT_DATA_CTRL;
+    uint8_t  opcode = avrc_opcode_from_pdu(p_cmd->pdu);
+    AVRC_TRACE_API("avrc_bld_init_cmd_buffer: pdu=%x, opcode=%x", p_cmd->pdu, opcode);
+
+    uint16_t offset = 0;
+    switch (opcode)
+    {
+    case AVRC_OP_BROWSE:
+        chnl = AVCT_DATA_BROWSE;
+        offset = AVCT_BROWSE_OFFSET;
+        break;
+
+    case AVRC_OP_PASS_THRU:
+        offset  = AVRC_MSG_PASS_THRU_OFFSET;
+        break;
+
+    case AVRC_OP_VENDOR:
+        offset  = AVRC_MSG_VENDOR_OFFSET;
+        break;
+    }
+
+    /* allocate and initialize the buffer */
+    BT_HDR *p_pkt = (BT_HDR *)osi_malloc(AVRC_META_CMD_BUF_SIZE);
+    uint8_t *p_data, *p_start;
+
+    p_pkt->layer_specific = chnl;
+    p_pkt->event = opcode;
+    p_pkt->offset = offset;
+    p_data = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_start = p_data;
+
+    /* pass thru - group navigation - has a two byte op_id, so dont do it here */
+    if (opcode != AVRC_OP_PASS_THRU)
+        *p_data++ = p_cmd->pdu;
+
+    switch (opcode) {
+    case AVRC_OP_VENDOR:
+        /* reserved 0, packet_type 0 */
+        UINT8_TO_BE_STREAM(p_data, 0);
+        /* continue to the next "case to add length */
+        /* add fixed lenth - 0 */
+        UINT16_TO_BE_STREAM(p_data, 0);
+        break;
+    }
+
+    p_pkt->len = (p_data - p_start);
+    p_cmd->cmd.opcode = opcode;
+
+    return p_pkt;
+}
+
+/*******************************************************************************
+**
+** Function         AVRC_BldCommand
+**
+** Description      This function builds the given AVRCP command to the given
+**                  GKI buffer
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+tAVRC_STS AVRC_BldCommand( tAVRC_COMMAND *p_cmd, BT_HDR **pp_pkt)
+{
+    tAVRC_STS status = AVRC_STS_BAD_PARAM;
+    bool    alloc = false;
+    AVRC_TRACE_API("AVRC_BldCommand: pdu=%x status=%x", p_cmd->cmd.pdu, p_cmd->cmd.status);
+    if (!p_cmd || !pp_pkt)
+    {
+        AVRC_TRACE_API("AVRC_BldCommand. Invalid parameters passed. p_cmd=%p, pp_pkt=%p",
+            p_cmd, pp_pkt);
+        return AVRC_STS_BAD_PARAM;
+    }
+
+    if (*pp_pkt == NULL)
+    {
+        if ((*pp_pkt = avrc_bld_init_cmd_buffer(p_cmd)) == NULL)
+        {
+            AVRC_TRACE_API("AVRC_BldCommand: Failed to initialize command buffer");
+            return AVRC_STS_INTERNAL_ERR;
+        }
+        alloc = true;
+    }
+    status = AVRC_STS_NO_ERROR;
+    BT_HDR* p_pkt = *pp_pkt;
+
+    switch (p_cmd->pdu)
+    {
+    case AVRC_PDU_REQUEST_CONTINUATION_RSP:     /*        0x40 */
+        status = avrc_bld_next_cmd(&p_cmd->continu, p_pkt);
+        break;
+
+    case AVRC_PDU_ABORT_CONTINUATION_RSP:       /*          0x41 */
+        status = avrc_bld_next_cmd(&p_cmd->abort, p_pkt);
+        break;
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+    case AVRC_PDU_SET_ABSOLUTE_VOLUME:         /* 0x50 */
+        status = avrc_bld_set_abs_volume_cmd(&p_cmd->volume, p_pkt);
+        break;
+#endif
+    case AVRC_PDU_REGISTER_NOTIFICATION:      /* 0x31 */
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+        status=avrc_bld_register_notifn(p_pkt,p_cmd->reg_notif.event_id,p_cmd->reg_notif.param);
+#endif
+        break;
+#if (AVRC_CTRL_INCLUDED == TRUE)
+    case AVRC_PDU_GET_CAPABILITIES:
+        status = avrc_bld_get_capability_cmd(p_pkt, p_cmd->get_caps.capability_id);
+        break;
+    case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+        status = avrc_bld_list_player_app_attr_cmd(p_pkt);
+        break;
+    case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+        status = avrc_bld_list_player_app_values_cmd(p_pkt,p_cmd->list_app_values.attr_id);
+        break;
+    case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+        status = avrc_bld_get_current_player_app_values_cmd(p_pkt,
+             p_cmd->get_cur_app_val.num_attr,p_cmd->get_cur_app_val.attrs);
+        break;
+    case AVRC_PDU_SET_PLAYER_APP_VALUE:
+        status = avrc_bld_set_current_player_app_values_cmd(p_pkt,
+                     p_cmd->set_app_val.num_val,p_cmd->set_app_val.p_vals);
+        break;
+    case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+        avrc_bld_get_player_app_setting_attr_text_cmd(p_pkt, &p_cmd->get_app_attr_txt);
+        break;
+    case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
+        avrc_bld_get_player_app_setting_value_text_cmd(p_pkt, &p_cmd->get_app_val_txt);
+        break;
+    case AVRC_PDU_GET_ELEMENT_ATTR:
+        status = avrc_bld_get_element_attr_cmd(p_pkt,
+              p_cmd->get_elem_attrs.num_attr,p_cmd->get_elem_attrs.attrs);
+        break;
+    case AVRC_PDU_PLAY_ITEM:
+        status = avrc_bld_play_item_cmd(
+            p_pkt, p_cmd->play_item.scope, p_cmd->play_item.uid, p_cmd->play_item.uid_counter);
+        break;
+    case AVRC_PDU_GET_PLAY_STATUS:
+        status = avrc_bld_get_play_status_cmd(p_pkt);
+        break;
+    case AVRC_PDU_GET_FOLDER_ITEMS:
+        status = avrc_bld_get_folder_items_cmd(p_pkt, &(p_cmd->get_items));
+        break;
+    case AVRC_PDU_CHANGE_PATH:
+        status = avrc_bld_change_folder_cmd(p_pkt, &(p_cmd->chg_path));
+        break;
+    case AVRC_PDU_SET_BROWSED_PLAYER:
+        status = avrc_bld_set_browsed_player_cmd(p_pkt, &(p_cmd->br_player));
+        break;
+    case AVRC_PDU_SET_ADDRESSED_PLAYER:
+        status = avrc_bld_set_addressed_player_cmd(p_pkt, &(p_cmd->addr_player));
+        break;
+#endif
+    }
+
+    if (alloc && (status != AVRC_STS_NO_ERROR) )
+    {
+        osi_free(p_pkt);
+        *pp_pkt = NULL;
+    }
+    AVRC_TRACE_API("AVRC_BldCommand: returning %d", status);
+    return status;
+}
+#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
diff --git a/bt/stack/avrc/avrc_bld_tg.cc b/bt/stack/avrc/avrc_bld_tg.cc
new file mode 100644
index 0000000..4f2569a
--- /dev/null
+++ b/bt/stack/avrc/avrc_bld_tg.cc
@@ -0,0 +1,1604 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2016 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.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_common.h"
+#include "avrc_api.h"
+#include "avrc_defs.h"
+#include "avrc_int.h"
+#include "bt_utils.h"
+#include "osi/include/osi.h"
+
+/*****************************************************************************
+**  Global data
+*****************************************************************************/
+#if (AVRC_METADATA_INCLUDED == TRUE)
+#define AVRC_ITEM_PLAYER_IS_VALID(_p_player) ((_p_player)->name.p_str && \
+               ((_p_player)->major_type & AVRC_MJ_TYPE_INVALID) == 0 && \
+               ((_p_player)->sub_type & AVRC_SUB_TYPE_INVALID) == 0 && \
+               (((_p_player)->play_status <= AVRC_PLAYSTATE_REV_SEEK) || \
+                ((_p_player)->play_status == AVRC_PLAYSTATE_ERROR)) )
+
+
+#define AVRC_MIN_LEN_GET_FOLDER_ITEMS_RSP   17 /* 17 = item_type(1) + item len(2) + min item (14) */
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_capability_rsp
+**
+** Description      This function builds the Get Capability response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_capability_rsp (tAVRC_GET_CAPS_RSP *p_rsp, BT_HDR *p_pkt)
+{
+    uint8_t *p_data, *p_start, *p_len, *p_count;
+    uint16_t len = 0;
+    uint8_t xx;
+    uint32_t *p_company_id;
+    uint8_t *p_event_id;
+    tAVRC_STS status = AVRC_STS_NO_ERROR;
+
+    if (!(AVRC_IS_VALID_CAP_ID(p_rsp->capability_id)))
+    {
+        AVRC_TRACE_ERROR("%s bad parameter. p_rsp: %x", __func__, p_rsp);
+        status = AVRC_STS_BAD_PARAM;
+        return status;
+    }
+
+    AVRC_TRACE_API("%s", __func__);
+    /* get the existing length, if any, and also the num attributes */
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_len = p_start + 2; /* pdu + rsvd */
+
+    BE_STREAM_TO_UINT16(len, p_data);
+    UINT8_TO_BE_STREAM(p_data, p_rsp->capability_id);
+    p_count = p_data;
+
+    if (len == 0)
+    {
+        *p_count = p_rsp->count;
+        p_data++;
+        len = 2; /* move past the capability_id and count */
+    }
+    else
+    {
+        p_data = p_start + p_pkt->len;
+        *p_count += p_rsp->count;
+    }
+
+    if (p_rsp->capability_id == AVRC_CAP_COMPANY_ID)
+    {
+        p_company_id = p_rsp->param.company_id;
+        for (xx=0; xx< p_rsp->count; xx++)
+        {
+            UINT24_TO_BE_STREAM(p_data, p_company_id[xx]);
+        }
+        len += p_rsp->count * 3;
+    }
+    else
+    {
+        p_event_id = p_rsp->param.event_id;
+        *p_count = 0;
+        for (xx=0; xx< p_rsp->count; xx++)
+        {
+            if (AVRC_IS_VALID_EVENT_ID(p_event_id[xx]))
+            {
+                (*p_count)++;
+                UINT8_TO_BE_STREAM(p_data, p_event_id[xx]);
+            }
+        }
+        len += (*p_count);
+    }
+    UINT16_TO_BE_STREAM(p_len, len);
+    p_pkt->len = (p_data - p_start);
+    status = AVRC_STS_NO_ERROR;
+
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_list_app_settings_attr_rsp
+**
+** Description      This function builds the List Application Settings Attribute
+**                  response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_list_app_settings_attr_rsp (tAVRC_LIST_APP_ATTR_RSP *p_rsp,
+        BT_HDR *p_pkt)
+{
+    uint8_t *p_data, *p_start, *p_len, *p_num;
+    uint16_t len = 0;
+    uint8_t xx;
+
+    AVRC_TRACE_API("%s", __func__);
+    /* get the existing length, if any, and also the num attributes */
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_len = p_start + 2; /* pdu + rsvd */
+
+    BE_STREAM_TO_UINT16(len, p_data);
+    p_num = p_data;
+    if (len == 0)
+    {
+        /* first time initialize the attribute count */
+        *p_num = 0;
+        p_data++;
+    }
+    else
+    {
+        p_data = p_start + p_pkt->len;
+    }
+
+    for (xx=0; xx<p_rsp->num_attr; xx++)
+    {
+        if(AVRC_IsValidPlayerAttr(p_rsp->attrs[xx]))
+        {
+            (*p_num)++;
+            UINT8_TO_BE_STREAM(p_data, p_rsp->attrs[xx]);
+        }
+    }
+
+    len = *p_num + 1;
+    UINT16_TO_BE_STREAM(p_len, len);
+    p_pkt->len = (p_data - p_start);
+
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_list_app_settings_values_rsp
+**
+** Description      This function builds the List Application Setting Values
+**                  response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_list_app_settings_values_rsp (tAVRC_LIST_APP_VALUES_RSP *p_rsp,
+    BT_HDR *p_pkt)
+{
+    uint8_t *p_data, *p_start, *p_len, *p_num;
+    uint8_t xx;
+    uint16_t len;
+
+    AVRC_TRACE_API("%s", __func__);
+
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_len = p_start + 2; /* pdu + rsvd */
+
+    /* get the existing length, if any, and also the num attributes */
+    BE_STREAM_TO_UINT16(len, p_data);
+    p_num = p_data;
+    /* first time initialize the attribute count */
+    if (len == 0)
+    {
+        *p_num = p_rsp->num_val;
+        p_data++;
+    }
+    else
+    {
+        p_data = p_start + p_pkt->len;
+        *p_num += p_rsp->num_val;
+    }
+
+
+    for (xx=0; xx<p_rsp->num_val; xx++)
+    {
+        UINT8_TO_BE_STREAM(p_data, p_rsp->vals[xx]);
+    }
+
+    len = *p_num + 1;
+    UINT16_TO_BE_STREAM(p_len, len);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_cur_app_setting_value_rsp
+**
+** Description      This function builds the Get Current Application Setting Value
+**                  response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_cur_app_setting_value_rsp (tAVRC_GET_CUR_APP_VALUE_RSP *p_rsp,
+    BT_HDR *p_pkt)
+{
+    uint8_t *p_data, *p_start, *p_len, *p_count;
+    uint16_t len;
+    uint8_t xx;
+
+    if (!p_rsp->p_vals)
+    {
+        AVRC_TRACE_ERROR("%s NULL parameter", __func__);
+        return AVRC_STS_BAD_PARAM;
+    }
+
+    AVRC_TRACE_API("%s", __func__);
+    /* get the existing length, if any, and also the num attributes */
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_len = p_start + 2; /* pdu + rsvd */
+
+    BE_STREAM_TO_UINT16(len, p_data);
+    p_count = p_data;
+    if (len == 0)
+    {
+        /* first time initialize the attribute count */
+        *p_count = 0;
+        p_data++;
+    }
+    else
+    {
+        p_data = p_start + p_pkt->len;
+    }
+
+    for (xx=0; xx<p_rsp->num_val; xx++)
+    {
+        if (avrc_is_valid_player_attrib_value(p_rsp->p_vals[xx].attr_id,
+            p_rsp->p_vals[xx].attr_val))
+        {
+            (*p_count)++;
+            UINT8_TO_BE_STREAM(p_data, p_rsp->p_vals[xx].attr_id);
+            UINT8_TO_BE_STREAM(p_data, p_rsp->p_vals[xx].attr_val);
+        }
+    }
+    len = ((*p_count) << 1) + 1;
+    UINT16_TO_BE_STREAM(p_len, len);
+    p_pkt->len = (p_data - p_start);
+
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_set_app_setting_value_rsp
+**
+** Description      This function builds the Set Application Setting Value
+**                  response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_set_app_setting_value_rsp (UNUSED_ATTR tAVRC_RSP *p_rsp,
+                                                     UNUSED_ATTR BT_HDR *p_pkt)
+{
+    /* nothing to be added. */
+    AVRC_TRACE_API("%s", __func__);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_app_setting_text_rsp
+**
+** Description      This function builds the Get Application Settings Attribute Text
+**                  or Get Application Settings Value Text response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_app_setting_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp,
+    BT_HDR *p_pkt)
+{
+    uint8_t *p_data, *p_start, *p_len, *p_count;
+    uint16_t len, len_left;
+    uint8_t xx;
+    tAVRC_STS   sts = AVRC_STS_NO_ERROR;
+    uint8_t     num_added = 0;
+
+    if (!p_rsp->p_attrs)
+    {
+        AVRC_TRACE_ERROR("%s NULL parameter", __func__);
+        return AVRC_STS_BAD_PARAM;
+    }
+    /* get the existing length, if any, and also the num attributes */
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_len = p_start + 2; /* pdu + rsvd */
+
+    /*
+     * NOTE: The buffer is allocated within avrc_bld_init_rsp_buffer(), and is
+     * always of size BT_DEFAULT_BUFFER_SIZE.
+     */
+    len_left = BT_DEFAULT_BUFFER_SIZE - BT_HDR_SIZE - p_pkt->offset - p_pkt->len;
+
+    BE_STREAM_TO_UINT16(len, p_data);
+    p_count = p_data;
+
+    if (len == 0)
+    {
+        *p_count = 0;
+        p_data++;
+    }
+    else
+    {
+        p_data = p_start + p_pkt->len;
+    }
+
+    for (xx=0; xx<p_rsp->num_attr; xx++)
+    {
+        if  (len_left < (p_rsp->p_attrs[xx].str_len + 4))
+        {
+            AVRC_TRACE_ERROR("%s out of room (str_len:%d, left:%d)",
+                             __func__, xx, p_rsp->p_attrs[xx].str_len, len_left);
+            p_rsp->num_attr = num_added;
+            sts = AVRC_STS_INTERNAL_ERR;
+            break;
+        }
+        if ( !p_rsp->p_attrs[xx].str_len || !p_rsp->p_attrs[xx].p_str )
+        {
+            AVRC_TRACE_ERROR("%s NULL attr text[%d]", __func__, xx);
+            continue;
+        }
+        UINT8_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].attr_id);
+        UINT16_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].charset_id);
+        UINT8_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].str_len);
+        ARRAY_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].p_str, p_rsp->p_attrs[xx].str_len);
+        (*p_count)++;
+        num_added++;
+    }
+    len = p_data - p_count;
+    UINT16_TO_BE_STREAM(p_len, len);
+    p_pkt->len = (p_data - p_start);
+
+    return sts;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_app_setting_attr_text_rsp
+**
+** Description      This function builds the Get Application Setting Attribute Text
+**                  response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_app_setting_attr_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp,
+    BT_HDR *p_pkt)
+{
+    AVRC_TRACE_API("%s", __func__);
+    return avrc_bld_app_setting_text_rsp(p_rsp, p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_app_setting_value_text_rsp
+**
+** Description      This function builds the Get Application Setting Value Text
+**                  response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_app_setting_value_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rsp,
+    BT_HDR *p_pkt)
+{
+    AVRC_TRACE_API("%s", __func__);
+    return avrc_bld_app_setting_text_rsp(p_rsp, p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_inform_charset_rsp
+**
+** Description      This function builds the Inform Displayable Character Set
+**                  response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_inform_charset_rsp (UNUSED_ATTR tAVRC_RSP *p_rsp,
+                                              UNUSED_ATTR BT_HDR *p_pkt)
+{
+    /* nothing to be added. */
+    AVRC_TRACE_API("%s", __func__);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_inform_battery_status_rsp
+**
+** Description      This function builds the Inform Battery Status
+**                  response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_inform_battery_status_rsp (UNUSED_ATTR tAVRC_RSP *p_rsp,
+                                                     UNUSED_ATTR BT_HDR *p_pkt)
+{
+    /* nothing to be added. */
+    AVRC_TRACE_API("%s", __func__);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_elem_attrs_rsp
+**
+** Description      This function builds the Get Element Attributes
+**                  response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_elem_attrs_rsp (tAVRC_GET_ELEM_ATTRS_RSP *p_rsp, BT_HDR *p_pkt)
+{
+    uint8_t *p_data, *p_start, *p_len, *p_count;
+    uint16_t len;
+    uint8_t xx;
+
+    AVRC_TRACE_API("%s", __func__);
+    if (!p_rsp->p_attrs)
+    {
+        AVRC_TRACE_ERROR("%s NULL parameter", __func__);
+        return AVRC_STS_BAD_PARAM;
+    }
+
+    /* get the existing length, if any, and also the num attributes */
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_len = p_start + 2; /* pdu + rsvd */
+
+    BE_STREAM_TO_UINT16(len, p_data);
+    p_count = p_data;
+
+    if (len == 0)
+    {
+        *p_count = 0;
+        p_data++;
+    }
+    else
+    {
+        p_data = p_start + p_pkt->len;
+    }
+
+    for (xx=0; xx<p_rsp->num_attr; xx++)
+    {
+        if (!AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_rsp->p_attrs[xx].attr_id))
+        {
+            AVRC_TRACE_ERROR("%s invalid attr id[%d]: %d",
+                __func__, xx, p_rsp->p_attrs[xx].attr_id);
+            continue;
+        }
+        if ( !p_rsp->p_attrs[xx].name.p_str )
+        {
+            p_rsp->p_attrs[xx].name.str_len = 0;
+        }
+        UINT32_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].attr_id);
+        UINT16_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].name.charset_id);
+        UINT16_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].name.str_len);
+        ARRAY_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].name.p_str, p_rsp->p_attrs[xx].name.str_len);
+        (*p_count)++;
+    }
+    len = p_data - p_count;
+    UINT16_TO_BE_STREAM(p_len, len);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_play_status_rsp
+**
+** Description      This function builds the Get Play Status
+**                  response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_play_status_rsp (tAVRC_GET_PLAY_STATUS_RSP *p_rsp,
+    BT_HDR *p_pkt)
+{
+    uint8_t *p_data, *p_start;
+
+    AVRC_TRACE_API("%s", __func__);
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_start + 2;
+
+    /* add fixed lenth - song len(4) + song position(4) + status(1) */
+    UINT16_TO_BE_STREAM(p_data, 9);
+    UINT32_TO_BE_STREAM(p_data, p_rsp->song_len);
+    UINT32_TO_BE_STREAM(p_data, p_rsp->song_pos);
+    UINT8_TO_BE_STREAM(p_data, p_rsp->play_status);
+    p_pkt->len = (p_data - p_start);
+
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_notify_rsp
+**
+** Description      This function builds the Notification response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_notify_rsp (tAVRC_REG_NOTIF_RSP *p_rsp, BT_HDR *p_pkt)
+{
+    uint8_t *p_data, *p_start;
+    uint8_t *p_len;
+    uint16_t len = 0;
+    uint8_t xx;
+    tAVRC_STS status = AVRC_STS_NO_ERROR;
+
+    AVRC_TRACE_API("%s event_id %d", __func__, p_rsp->event_id);
+
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_len = p_start + 2; /* pdu + rsvd */
+    p_data += 2;
+
+    UINT8_TO_BE_STREAM(p_data, p_rsp->event_id);
+    switch (p_rsp->event_id)
+    {
+    case AVRC_EVT_PLAY_STATUS_CHANGE:       /* 0x01 */
+        /* p_rsp->param.play_status >= AVRC_PLAYSTATE_STOPPED is always true */
+        if ((p_rsp->param.play_status <= AVRC_PLAYSTATE_REV_SEEK) ||
+            (p_rsp->param.play_status == AVRC_PLAYSTATE_ERROR) )
+        {
+            UINT8_TO_BE_STREAM(p_data, p_rsp->param.play_status);
+            len = 2;
+        }
+        else
+        {
+            AVRC_TRACE_ERROR("%s bad play state", __func__);
+            status = AVRC_STS_BAD_PARAM;
+        }
+        break;
+
+    case AVRC_EVT_TRACK_CHANGE:             /* 0x02 */
+        ARRAY_TO_BE_STREAM(p_data, p_rsp->param.track, AVRC_UID_SIZE);
+        len = (uint8_t)(AVRC_UID_SIZE + 1);
+        break;
+
+    case AVRC_EVT_TRACK_REACHED_END:        /* 0x03 */
+    case AVRC_EVT_TRACK_REACHED_START:      /* 0x04 */
+    case AVRC_EVT_NOW_PLAYING_CHANGE:       /* 0x09 */
+    case AVRC_EVT_AVAL_PLAYERS_CHANGE:      /* 0x0a */
+        len = 1;
+        break;
+
+    case AVRC_EVT_PLAY_POS_CHANGED:         /* 0x05 */
+        UINT32_TO_BE_STREAM(p_data, p_rsp->param.play_pos);
+        len = 5;
+        break;
+
+    case AVRC_EVT_BATTERY_STATUS_CHANGE:    /* 0x06 */
+        if (AVRC_IS_VALID_BATTERY_STATUS(p_rsp->param.battery_status))
+        {
+            UINT8_TO_BE_STREAM(p_data, p_rsp->param.battery_status);
+            len = 2;
+        }
+        else
+        {
+            AVRC_TRACE_ERROR("%s bad battery status", __func__);
+            status = AVRC_STS_BAD_PARAM;
+        }
+        break;
+
+    case AVRC_EVT_SYSTEM_STATUS_CHANGE:     /* 0x07 */
+        if (AVRC_IS_VALID_SYSTEM_STATUS(p_rsp->param.system_status))
+        {
+            UINT8_TO_BE_STREAM(p_data, p_rsp->param.system_status);
+            len = 2;
+        }
+        else
+        {
+            AVRC_TRACE_ERROR("%s bad system status", __func__);
+            status = AVRC_STS_BAD_PARAM;
+        }
+        break;
+
+    case AVRC_EVT_APP_SETTING_CHANGE:       /* 0x08 */
+        if (p_rsp->param.player_setting.num_attr > AVRC_MAX_APP_SETTINGS)
+            p_rsp->param.player_setting.num_attr = AVRC_MAX_APP_SETTINGS;
+
+        if (p_rsp->param.player_setting.num_attr > 0)
+        {
+            UINT8_TO_BE_STREAM(p_data, p_rsp->param.player_setting.num_attr);
+            len = 2;
+            for (xx=0; xx<p_rsp->param.player_setting.num_attr; xx++)
+            {
+                if (avrc_is_valid_player_attrib_value(p_rsp->param.player_setting.attr_id[xx],
+                    p_rsp->param.player_setting.attr_value[xx]))
+                {
+                    UINT8_TO_BE_STREAM(p_data, p_rsp->param.player_setting.attr_id[xx]);
+                    UINT8_TO_BE_STREAM(p_data, p_rsp->param.player_setting.attr_value[xx]);
+                }
+                else
+                {
+                    AVRC_TRACE_ERROR("%s bad player app seeting attribute or value", __func__);
+                    status = AVRC_STS_BAD_PARAM;
+                    break;
+                }
+                len += 2;
+            }
+        }
+        else
+            status = AVRC_STS_BAD_PARAM;
+        break;
+
+    case AVRC_EVT_VOLUME_CHANGE:            /* 0x0d */
+        len = 2;
+        UINT8_TO_BE_STREAM(p_data, (AVRC_MAX_VOLUME & p_rsp->param.volume));
+        break;
+
+    case AVRC_EVT_ADDR_PLAYER_CHANGE:       /* 0x0b */
+        UINT16_TO_BE_STREAM(p_data, p_rsp->param.addr_player.player_id); /* player_id */
+        UINT16_TO_BE_STREAM(p_data, p_rsp->param.addr_player.uid_counter); /* uid counter */
+        len = 5;
+        break;
+
+    case AVRC_EVT_UIDS_CHANGE:              /* 0x0c */
+        UINT16_TO_BE_STREAM(p_data, p_rsp->param.uid_counter); /* uid counter */
+        len = 3;
+        break;
+
+    default:
+        status = AVRC_STS_BAD_PARAM;
+        AVRC_TRACE_ERROR("%s unknown event_id", __func__);
+    }
+
+    UINT16_TO_BE_STREAM(p_len, len);
+    p_pkt->len = (p_data - p_start);
+
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_next_rsp
+**
+** Description      This function builds the Request Continue or Abort
+**                  response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_next_rsp (tAVRC_NEXT_RSP *p_rsp, BT_HDR *p_pkt)
+{
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    uint8_t *p_data = (p_start + 2); /* Skip the pdu and reserved bits */
+
+    UINT16_TO_BE_STREAM(p_data, 0x0001); /* only one attribute to be sent */
+    UINT8_TO_BE_STREAM(p_data, p_rsp->target_pdu);
+
+    AVRC_TRACE_API("%s: target_pdu: 0x%02x", __func__, p_rsp->target_pdu);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*****************************************************************************
+**
+** Function      avrc_bld_set_absolute_volume_rsp
+**
+** Description   This function builds the set absolute volume response
+**
+** Returns       AVRC_STS_NO_ERROR, if the response is build successfully
+**
+******************************************************************************/
+static tAVRC_STS avrc_bld_set_absolute_volume_rsp(uint8_t abs_vol, BT_HDR *p_pkt)
+{
+    AVRC_TRACE_API("%s", __func__);
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    /* To calculate length */
+    uint8_t *p_data = p_start + 2;
+    /* add fixed lenth status(1) */
+    UINT16_TO_BE_STREAM(p_data, 1);
+    UINT8_TO_BE_STREAM(p_data, abs_vol);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_group_navigation_rsp
+**
+** Description      This function builds the Group Navigation
+**                  response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+tAVRC_STS avrc_bld_group_navigation_rsp (uint16_t navi_id, BT_HDR *p_pkt)
+{
+    if (!AVRC_IS_VALID_GROUP(navi_id))
+    {
+        AVRC_TRACE_ERROR("%s bad navigation op id: %d", __func__, navi_id);
+        return AVRC_STS_BAD_PARAM;
+    }
+    AVRC_TRACE_API("%s", __func__);
+    uint8_t *p_data = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    UINT16_TO_BE_STREAM(p_data, navi_id);
+    p_pkt->len = 2;
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_rejected_rsp
+**
+** Description      This function builds the General Response response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_rejected_rsp( tAVRC_RSP *p_rsp, BT_HDR *p_pkt )
+{
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    uint8_t *p_data;
+    uint8_t opcode = p_rsp->opcode;
+
+    AVRC_TRACE_API("%s: status=%d, pdu:x%x, opcode=%x", __func__, p_rsp->status,
+                     p_rsp->pdu, opcode);
+
+    if (opcode == AVRC_OP_BROWSE)
+    {
+        p_data = p_start + 1;
+        if ((AVRC_PDU_INVALID == *p_start) || (avrc_opcode_from_pdu(*p_start) != AVRC_OP_BROWSE))
+        {
+            /* if invalid or the given opcode is not recognized as a browsing command opcode, */
+            /* use general reject command */
+            *p_start = AVRC_PDU_GENERAL_REJECT;
+        }
+    }
+    else
+    {
+        p_data = p_start + 2;
+    }
+    AVRC_TRACE_DEBUG("%s pdu:x%x, Opcode:%x", __func__, *p_start,opcode);
+    UINT16_TO_BE_STREAM(p_data, 1);
+    UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+    p_pkt->len = p_data - p_start;
+    return AVRC_STS_NO_ERROR;
+}
+
+/*****************************************************************************
+**  the following commands are introduced in AVRCP 1.4
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function         avrc_bld_ctrl_status_rsp
+**
+** Description      This function builds the responses with a uint8_t parameter.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_ctrl_status_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+    uint8_t *p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    AVRC_TRACE_DEBUG("pdu:x%x", *p_start);
+
+    /* To calculate length */
+    uint8_t *p_data = p_start + 2; /* pdu + rsvd */
+
+    /* add fixed lenth - status(1) */
+    UINT16_TO_BE_STREAM(p_data, 1);
+    UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_set_addr_player_rsp
+**
+** Description      This function builds the Set Addresses Player response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_set_addr_player_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+    AVRC_TRACE_API("%s", __func__);
+    return avrc_bld_ctrl_status_rsp(p_rsp, p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_set_browsed_player_rsp
+**
+** Description      This function builds the Set Browsed Player response.
+**
+**                  This message goes through the Browsing channel
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_set_browsed_player_rsp (tAVRC_SET_BR_PLAYER_RSP *p_rsp,
+    BT_HDR *p_pkt)
+{
+    uint8_t   *p_data, *p_start;
+    uint8_t   *p_len;
+    uint16_t  len;
+    tAVRC_NAME  *p_folders = p_rsp->p_folders;
+    uint16_t  len_left;
+    uint8_t   *p_folder_depth;
+    uint16_t  mtu;
+
+    /* make sure the given buffer can accomodate this response */
+    len_left = BT_DEFAULT_BUFFER_SIZE - BT_HDR_SIZE;
+    p_data = (uint8_t *)(p_pkt + 1);
+    BE_STREAM_TO_UINT16 (mtu, p_data);
+    if (len_left > mtu)
+    {
+        len_left = mtu;
+    }
+    len_left = len_left - p_pkt->offset - p_pkt->len;
+    AVRC_TRACE_DEBUG("len_left:%d, mtu:%d ", len_left, mtu);
+
+    /* get the existing length, if any, and also the num attributes */
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_len = p_start + 1; /* pdu */
+
+    /* the existing len */
+    BE_STREAM_TO_UINT16(len, p_data);
+    /* find the position to add the folder depth.
+     * 9 is sizeof (status + uid_counter + num_items + charset_id) */
+    p_folder_depth = p_data + 9;
+    if (len == 0)
+    {
+        /* first time initialize the attribute count */
+        UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+        UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter);
+        UINT32_TO_BE_STREAM(p_data, p_rsp->num_items);
+        UINT16_TO_BE_STREAM(p_data, p_rsp->charset_id);
+        *p_folder_depth = 0;
+        p_data++;
+        len = 10;
+        /* assuming that we would never use a buffer that is too small for headers */
+        len_left -= 12;
+    }
+    else
+    {
+        p_data = p_start + p_pkt->len;
+    }
+
+    for (uint8_t xx = 0; (xx < p_rsp->folder_depth) && (len_left > (p_folders[xx].str_len + 2)); xx++)
+    {
+        (*p_folder_depth)++;
+        UINT16_TO_BE_STREAM(p_data, p_folders[xx].str_len);
+        ARRAY_TO_BE_STREAM(p_data, p_folders[xx].p_str, p_folders[xx].str_len);
+        len += (p_folders[xx].str_len + 2);
+    }
+    UINT16_TO_BE_STREAM(p_len, len);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_folder_items_rsp
+**
+** Description      This function builds the Get Folder Items response.
+**                  The error code is returned in *p_status.
+**                  AVRC_STS_INTERNAL_ERR means no buffers.
+**                  Try again later or with smaller item_count
+**
+**                  This message goes through the Browsing channel
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  AVRC_STS_INTERNAL_ERR, if the given buffer does not have enough room
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_folder_items_rsp (tAVRC_GET_ITEMS_RSP *p_rsp, BT_HDR *p_pkt)
+{
+    uint8_t   *p_data, *p_start;
+    uint8_t   *p_len, xx;
+    uint16_t  len;
+    uint16_t  item_len;
+    uint8_t   *p_item_len, yy;
+    tAVRC_ITEM_PLAYER   *p_player;
+    tAVRC_ITEM_FOLDER   *p_folder;
+    tAVRC_ITEM_MEDIA    *p_media;
+    tAVRC_ATTR_ENTRY    *p_attr;
+    tAVRC_ITEM          *p_item_list = p_rsp->p_item_list;
+    tAVRC_STS           status = AVRC_STS_NO_ERROR;
+    uint16_t  len_left;
+    uint8_t   *p_num, *p;
+    uint8_t   *p_item_start, *p_attr_count;
+    uint16_t  item_count;
+    uint16_t  mtu;
+    bool multi_items_add_fail = FALSE;
+    AVRC_TRACE_API("%s", __func__);
+
+    /* make sure the given buffer can accomodate this response */
+    len_left = BT_DEFAULT_BUFFER_SIZE - BT_HDR_SIZE;
+    p = (uint8_t *)(p_pkt + 1);
+    BE_STREAM_TO_UINT16 (mtu, p);
+    if (len_left > mtu)
+        len_left = mtu;
+    len_left = len_left - p_pkt->offset - p_pkt->len;
+
+    /* get the existing length, if any, and also the num attributes */
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_len = p_start + 1; /* pdu */
+
+    /* the existing len */
+    BE_STREAM_TO_UINT16(len, p_data);
+    p_num = p_data + 3;
+    if (len == 0)
+    {
+        /* first time initialize the attribute count */
+        UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+        UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter);
+        item_count = 0;
+        p_data += 2;
+        len = 5;
+        len_left -= 5;
+    }
+    else
+    {
+        p_data = p_start + p_pkt->len;
+        p = p_num;
+        BE_STREAM_TO_UINT16 (item_count, p);
+    }
+    AVRC_TRACE_DEBUG("len:%d, len_left:%d, num:%d", len, len_left, item_count);
+
+    /* min len required = item_type(1) + item len(2) + min item (14) = 17 */
+    for (xx = 0; xx < p_rsp->item_count && len_left > AVRC_MIN_LEN_GET_FOLDER_ITEMS_RSP && multi_items_add_fail == FALSE; xx++)
+    {
+        p_item_start = p_data;
+        UINT8_TO_BE_STREAM(p_data, p_item_list[xx].item_type);
+        /* variable item lenth - save the location to add length */
+        p_item_len = p_data;
+        p_data += 2;
+        item_len = 0;
+        len_left -= 3; /* item_type(1) + item len(2) */
+        switch (p_item_list[xx].item_type)
+        {
+        case AVRC_ITEM_PLAYER:
+            /* min len required: 2 + 1 + 4 + 1 + 16 + 2 + 2 = 30 + str_len */
+            p_player = &p_item_list[xx].u.player;
+            item_len = AVRC_FEATURE_MASK_SIZE + p_player->name.str_len + 12;
+
+            if ((len_left <= item_len) || AVRC_ITEM_PLAYER_IS_VALID(p_player) == false)
+            {
+                p_data = p_item_start;
+            }
+            else
+            {
+                UINT16_TO_BE_STREAM(p_data, p_player->player_id);
+                UINT8_TO_BE_STREAM(p_data, p_player->major_type);
+                UINT32_TO_BE_STREAM(p_data, p_player->sub_type);
+                UINT8_TO_BE_STREAM(p_data, p_player->play_status);
+                ARRAY_TO_BE_STREAM(p_data, p_player->features, AVRC_FEATURE_MASK_SIZE);
+                UINT16_TO_BE_STREAM(p_data, p_player->name.charset_id);
+                UINT16_TO_BE_STREAM(p_data, p_player->name.str_len);
+                ARRAY_TO_BE_STREAM(p_data, p_player->name.p_str, p_player->name.str_len);
+            }
+            break;
+
+        case AVRC_ITEM_FOLDER:
+            /* min len required: 8 + 1 + 1 + 2 + 2 = 14 + str_len */
+            p_folder = &p_item_list[xx].u.folder;
+            item_len = AVRC_UID_SIZE + p_folder->name.str_len + 6;
+
+            if ((len_left > item_len) &&
+                p_folder->name.p_str &&
+                p_folder->type <= AVRC_FOLDER_TYPE_YEARS)
+            {
+                ARRAY_TO_BE_STREAM(p_data, p_folder->uid, AVRC_UID_SIZE);
+                UINT8_TO_BE_STREAM(p_data, p_folder->type);
+                UINT8_TO_BE_STREAM(p_data, p_folder->playable);
+                UINT16_TO_BE_STREAM(p_data, p_folder->name.charset_id);
+                UINT16_TO_BE_STREAM(p_data, p_folder->name.str_len);
+                ARRAY_TO_BE_STREAM(p_data, p_folder->name.p_str, p_folder->name.str_len);
+            }
+            else
+            {
+                p_data = p_item_start;
+            }
+            break;
+
+        case AVRC_ITEM_MEDIA:
+            /* min len required: 8 + 1 + 2 + 2 + 1 = 14 + str_len */
+            p_media = &p_item_list[xx].u.media;
+            item_len = AVRC_UID_SIZE + p_media->name.str_len + 6;
+
+            if ((len_left >= item_len) &&
+                p_media->name.p_str &&
+                p_media->type <= AVRC_MEDIA_TYPE_VIDEO)
+            {
+                ARRAY_TO_BE_STREAM(p_data, p_media->uid, AVRC_UID_SIZE);
+                UINT8_TO_BE_STREAM(p_data, p_media->type);
+                UINT16_TO_BE_STREAM(p_data, p_media->name.charset_id);
+                UINT16_TO_BE_STREAM(p_data, p_media->name.str_len);
+                ARRAY_TO_BE_STREAM(p_data, p_media->name.p_str, p_media->name.str_len);
+                p_attr_count = p_data++;
+                *p_attr_count = 0;
+                len_left -= item_len;
+                if (p_media->attr_count > 0)
+                {
+                    p_attr = p_media->p_attr_list;
+                    for (yy = 0; yy < p_media->attr_count; yy++)
+                    {
+                        if (p_attr[yy].name.p_str &&
+                            AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_attr[yy].attr_id) &&
+                            (len_left >= (p_attr[yy].name.str_len + 8)) )
+                        {
+                            (*p_attr_count) ++;
+                            UINT32_TO_BE_STREAM(p_data, p_attr[yy].attr_id);
+                            UINT16_TO_BE_STREAM(p_data, p_attr[yy].name.charset_id);
+                            UINT16_TO_BE_STREAM(p_data, p_attr[yy].name.str_len);
+                            ARRAY_TO_BE_STREAM(p_data, p_attr[yy].name.p_str,
+                                p_attr[yy].name.str_len);
+                            item_len += (p_attr[yy].name.str_len + 8);
+                            len_left -= (p_attr[yy].name.str_len + 8);
+                        }
+                        else if ((len_left < (p_attr[yy].name.str_len + 8)) && item_count > 0)
+                        {
+                            p_data = p_item_start;
+                            multi_items_add_fail = TRUE;
+                            break;
+                        }
+                    }
+                }
+            }
+            else
+            {
+                if (len_left < item_len && item_count > 0)
+                    multi_items_add_fail = TRUE;
+                p_data = p_item_start;
+            }
+            break;
+        } /* switch item_type */
+
+        if (p_item_start != p_data)
+        {
+            /* successfully added the item */
+            item_count++;
+            /* fill in variable item lenth */
+            UINT16_TO_BE_STREAM(p_item_len, item_len);
+        }
+        else
+        {
+            if (multi_items_add_fail == FALSE)
+            {
+                /* some item is not added properly - set an error status */
+                if (len_left < item_len)
+                    status = AVRC_STS_INTERNAL_ERR;
+                else
+                    status = AVRC_STS_BAD_PARAM;
+            }
+        }
+        if (multi_items_add_fail == FALSE)
+        {
+            len += item_len;
+            len += 3; /* the item_type(1) and item_len(2) */
+        }
+        AVRC_TRACE_DEBUG("len:%d, len_left:%d, num:%d, item_len:%d",
+            len, len_left, item_count, item_len);
+    } /* for item_count */
+
+    UINT16_TO_BE_STREAM(p_num, item_count);
+    UINT16_TO_BE_STREAM(p_len, len);
+    p_pkt->len = (p_data - p_start);
+
+    if (p_rsp->item_count != xx)
+    {
+        p_rsp->item_count = xx;
+        AVRC_TRACE_DEBUG("xx value = 0x%02X", xx);
+        if (status == AVRC_STS_NO_ERROR)
+            status = AVRC_STS_INTERNAL_ERR;
+    }
+
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_change_path_rsp
+**
+** Description      This function builds the Change Path response.
+**
+**                  This message goes through the Browsing channel
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_change_path_rsp (tAVRC_CHG_PATH_RSP *p_rsp, BT_HDR *p_pkt)
+{
+    uint8_t   *p_data, *p_start;
+
+    /* get the existing length, if any, and also the num attributes */
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_start + 1; /* pdu */
+    /* add fixed length - status(1) + num_items(4) */
+    UINT16_TO_BE_STREAM(p_data, 5);
+    UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+    UINT32_TO_BE_STREAM(p_data, p_rsp->num_items);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_item_attrs_rsp
+**
+** Description      This function builds the Get Item Attributes response.
+**
+**                  This message goes through the Browsing channel
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  AVRC_STS_INTERNAL_ERR, if the given buffer does not have enough room
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_item_attrs_rsp (tAVRC_GET_ATTRS_RSP *p_rsp, BT_HDR *p_pkt)
+{
+    uint8_t   *p_data, *p_start;
+    uint8_t   *p_len;
+    uint16_t  len, len_left;
+    uint8_t   *p_num;
+    uint16_t  mtu;
+
+    AVRC_TRACE_API("%s", __func__);
+    /* calculate the buffer size needed and validate the parameters */
+    if (!p_rsp || !p_rsp->p_attr_list)
+    {
+        AVRC_TRACE_ERROR("NULL p_attr_list");
+        return AVRC_STS_BAD_PARAM;
+    }
+
+    /* check the length before adding the attr to the message */
+    len = 2;
+    for (uint8_t xx = 0; xx < p_rsp->attr_count; xx++)
+    {
+        if(p_rsp->p_attr_list[xx].name.p_str == 0 ||
+            !AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_rsp->p_attr_list[xx].attr_id))
+        {
+            AVRC_TRACE_ERROR("[%d] NULL p_attr_list str or bad attr_id:%d", xx,
+                p_rsp->p_attr_list[xx].attr_id);
+            return AVRC_STS_BAD_PARAM;
+        }
+        len += (p_rsp->p_attr_list[xx].name.str_len + 8);
+    }
+    len_left = BT_DEFAULT_BUFFER_SIZE - BT_HDR_SIZE;
+    p_data = (uint8_t *)(p_pkt + 1);
+    BE_STREAM_TO_UINT16 (mtu, p_data);
+    if (len_left > mtu)
+    {
+        len_left = mtu;
+    }
+    len_left = len_left - p_pkt->offset - p_pkt->len;
+
+    AVRC_TRACE_DEBUG("len_left:%d, mtu:%d len needed:%d", len_left, mtu, len);
+    if (len_left < 11) /* 11 is 4/attr_id + 2/charset_id + 2/str_len + 3/1st timer/attr cnt & len */
+    {
+        return AVRC_STS_INTERNAL_ERR;
+    }
+    if (len > len_left)
+    {
+        AVRC_TRACE_ERROR("The buffer does not have enough room to hold the given data.");
+    }
+
+    /* get the existing length, if any, and also the num attributes */
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_len = p_start + 1; /* pdu */
+
+    /* the existing len */
+    BE_STREAM_TO_UINT16(len, p_data);
+    p_num = p_data + 1;
+    if (len == 0)
+    {
+        /* first time initialize the attribute count */
+        UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+        *p_num = 0;
+        p_data++;
+        len = 2;
+        len_left -= 3;
+    }
+    else
+    {
+        p_data = p_start + p_pkt->len;
+    }
+
+
+    for (uint8_t xx = 0; (xx < p_rsp->attr_count) && (len_left > 9); xx++)
+    {
+        (*p_num)++;
+        UINT32_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].attr_id);
+        UINT16_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].name.charset_id);
+        UINT16_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].name.str_len);
+        len_left -= 8;
+        if (p_rsp->p_attr_list[xx].name.str_len > len_left)
+            p_rsp->p_attr_list[xx].name.str_len = len_left;
+        ARRAY_TO_BE_STREAM(p_data, p_rsp->p_attr_list[xx].name.p_str,
+            p_rsp->p_attr_list[xx].name.str_len);
+        len_left -= p_rsp->p_attr_list[xx].name.str_len;
+        len += (p_rsp->p_attr_list[xx].name.str_len + 8);
+    }
+
+    UINT16_TO_BE_STREAM(p_len, len);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_get_num_of_item_rsp
+**
+** Description      This function builds the Get Total Number of Items response.
+**
+**                  This message goes through the Browsing channel
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  AVRC_STS_INTERNAL_ERR, if the given buffer does not have enough room
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_get_num_of_item_rsp (tAVRC_GET_NUM_OF_ITEMS_RSP *p_rsp, BT_HDR *p_pkt)
+{
+    uint8_t   *p_data, *p_start, *p_len;
+
+    AVRC_TRACE_API("%s", __func__);
+    /* get the existing length, if any, and also the num attributes */
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_len = p_start + 1; /* pdu */
+
+    if (p_rsp->status == AVRC_STS_NO_ERROR)
+    {
+        /* add fixed lenth - status(1) + uid_counter(2) + num_items(4) */
+        UINT16_TO_BE_STREAM(p_data, 7);
+        UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+        UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter);
+        UINT32_TO_BE_STREAM(p_data, p_rsp->num_items);
+        p_pkt->len = (p_data - p_start);
+        return AVRC_STS_NO_ERROR;
+    }
+    else
+    {
+        /* add fixed lenth - status(1) */
+        UINT16_TO_BE_STREAM(p_data, 7);
+        UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+        p_pkt->len = (p_data - p_start);
+        return p_rsp->status;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_search_rsp
+**
+** Description      This function builds the Search response.
+**
+**                  This message goes through the Browsing channel
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_search_rsp (tAVRC_SEARCH_RSP *p_rsp, BT_HDR *p_pkt)
+{
+    uint8_t   *p_data, *p_start, *p_len;
+
+    AVRC_TRACE_API("%s", __func__);
+    /* get the existing length, if any, and also the num attributes */
+    p_start = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_data = p_len = p_start + 1; /* pdu */
+
+    /* add fixed lenth - status(1) + uid_counter(2) + num_items(4) */
+    UINT16_TO_BE_STREAM(p_data, 7);
+    UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+    UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter);
+    UINT32_TO_BE_STREAM(p_data, p_rsp->num_items);
+    p_pkt->len = (p_data - p_start);
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_play_item_rsp
+**
+** Description      This function builds the Play Item response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_play_item_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+    AVRC_TRACE_API("%s", __func__);
+    return avrc_bld_ctrl_status_rsp(p_rsp, p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_add_to_now_playing_rsp
+**
+** Description      This function builds the Add to Now Playing response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+static tAVRC_STS avrc_bld_add_to_now_playing_rsp (tAVRC_RSP *p_rsp, BT_HDR *p_pkt)
+{
+    AVRC_TRACE_API("%s", __func__);
+    return avrc_bld_ctrl_status_rsp(p_rsp, p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function         avrc_bld_init_rsp_buffer
+**
+** Description      This function initializes the response buffer based on PDU
+**
+** Returns          NULL, if no buffer or failure to build the message.
+**                  Otherwise, the buffer that contains the initialized message.
+**
+*******************************************************************************/
+static BT_HDR *avrc_bld_init_rsp_buffer(tAVRC_RESPONSE *p_rsp)
+{
+    uint16_t offset = 0;
+    uint16_t chnl = AVCT_DATA_CTRL;
+    uint8_t  opcode = avrc_opcode_from_pdu(p_rsp->pdu);
+
+    AVRC_TRACE_API("%s: pdu=%x, opcode=%x/%x", __func__, p_rsp->pdu, opcode, p_rsp->rsp.opcode);
+    if (opcode != p_rsp->rsp.opcode && p_rsp->rsp.status != AVRC_STS_NO_ERROR &&
+        avrc_is_valid_opcode(p_rsp->rsp.opcode))
+    {
+        opcode = p_rsp->rsp.opcode;
+        AVRC_TRACE_API("%s opcode=%x", __func__, opcode);
+    }
+
+    switch (opcode)
+    {
+        case AVRC_OP_BROWSE:
+            chnl    = AVCT_DATA_BROWSE;
+            offset  = AVCT_BROWSE_OFFSET;
+            break;
+
+        case AVRC_OP_PASS_THRU:
+            offset  = AVRC_MSG_PASS_THRU_OFFSET;
+            break;
+
+        case AVRC_OP_VENDOR:
+            offset  = AVRC_MSG_VENDOR_OFFSET;
+            break;
+    }
+
+    /* allocate and initialize the buffer */
+    BT_HDR *p_pkt = (BT_HDR *)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+    uint8_t *p_data, *p_start;
+
+    p_pkt->layer_specific = chnl;
+    p_pkt->event    = opcode;
+    p_pkt->offset   = offset;
+    p_data = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    p_start = p_data;
+
+    /* pass thru - group navigation - has a two byte op_id, so dont do it here */
+    if (opcode != AVRC_OP_PASS_THRU)
+        *p_data++ = p_rsp->pdu;
+
+    switch (opcode) {
+    case AVRC_OP_VENDOR:
+        /* reserved 0, packet_type 0 */
+        UINT8_TO_BE_STREAM(p_data, 0);
+        /* continue to the next "case to add length */
+
+    case AVRC_OP_BROWSE:
+        /* add fixed lenth - 0 */
+        UINT16_TO_BE_STREAM(p_data, 0);
+        break;
+    }
+
+    p_pkt->len = (p_data - p_start);
+    p_rsp->rsp.opcode = opcode;
+
+    return p_pkt;
+}
+
+/*******************************************************************************
+**
+** Function         AVRC_BldResponse
+**
+** Description      This function builds the given AVRCP response to the given
+**                  buffer
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+tAVRC_STS AVRC_BldResponse( uint8_t handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt)
+{
+    tAVRC_STS status = AVRC_STS_BAD_PARAM;
+    BT_HDR *p_pkt;
+    bool alloc = false;
+    uint8_t   *p;
+    uint16_t  peer_mtu;
+
+    if (!p_rsp || !pp_pkt)
+    {
+        AVRC_TRACE_API("%s Invalid parameters passed. p_rsp=%p, pp_pkt=%p",
+                       __func__, p_rsp, pp_pkt);
+        return AVRC_STS_BAD_PARAM;
+    }
+
+    if (*pp_pkt == NULL)
+    {
+        if ((*pp_pkt = avrc_bld_init_rsp_buffer(p_rsp)) == NULL)
+        {
+            AVRC_TRACE_API("%s Failed to initialize response buffer", __func__);
+            return AVRC_STS_INTERNAL_ERR;
+        }
+
+        if ((*pp_pkt)->layer_specific == AVCT_DATA_BROWSE)
+        {
+            p = (uint8_t *)((*pp_pkt) + 1);
+            peer_mtu = AVCT_GetBrowseMtu(handle) - AVCT_HDR_LEN_SINGLE;
+            UINT16_TO_BE_STREAM(p, peer_mtu);
+        }
+
+        alloc = true;
+    }
+    status = AVRC_STS_NO_ERROR;
+    p_pkt = *pp_pkt;
+
+    AVRC_TRACE_API("%s pdu=%x status=%x", __func__, p_rsp->rsp.pdu, p_rsp->rsp.status);
+    if (p_rsp->rsp.status != AVRC_STS_NO_ERROR)
+    {
+        return( avrc_bld_rejected_rsp(&p_rsp->rsp, p_pkt) );
+    }
+
+    switch (p_rsp->pdu)
+    {
+    case AVRC_PDU_NEXT_GROUP:
+    case AVRC_PDU_PREV_GROUP:
+        status = avrc_bld_group_navigation_rsp(p_rsp->pdu, p_pkt);
+        break;
+
+    case AVRC_PDU_GET_CAPABILITIES:
+        status = avrc_bld_get_capability_rsp(&p_rsp->get_caps, p_pkt);
+        break;
+
+    case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+        status = avrc_bld_list_app_settings_attr_rsp(&p_rsp->list_app_attr, p_pkt);
+        break;
+
+    case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+        status = avrc_bld_list_app_settings_values_rsp(&p_rsp->list_app_values, p_pkt);
+        break;
+
+    case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+        status = avrc_bld_get_cur_app_setting_value_rsp(&p_rsp->get_cur_app_val, p_pkt);
+        break;
+
+    case AVRC_PDU_SET_PLAYER_APP_VALUE:
+        status = avrc_bld_set_app_setting_value_rsp(&p_rsp->set_app_val, p_pkt);
+        break;
+
+    case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+        status = avrc_bld_get_app_setting_attr_text_rsp(&p_rsp->get_app_attr_txt, p_pkt);
+        break;
+
+    case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
+        status = avrc_bld_get_app_setting_value_text_rsp(&p_rsp->get_app_val_txt, p_pkt);
+        break;
+
+    case AVRC_PDU_INFORM_DISPLAY_CHARSET:
+        status = avrc_bld_inform_charset_rsp(&p_rsp->inform_charset, p_pkt);
+        break;
+
+    case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT:
+        status = avrc_bld_inform_battery_status_rsp(&p_rsp->inform_battery_status, p_pkt);
+        break;
+
+    case AVRC_PDU_GET_ELEMENT_ATTR:
+        status = avrc_bld_get_elem_attrs_rsp(&p_rsp->get_elem_attrs, p_pkt);
+        break;
+
+    case AVRC_PDU_GET_PLAY_STATUS:
+        status = avrc_bld_get_play_status_rsp(&p_rsp->get_play_status, p_pkt);
+        break;
+
+    case AVRC_PDU_REGISTER_NOTIFICATION:
+        status = avrc_bld_notify_rsp(&p_rsp->reg_notif, p_pkt);
+        break;
+
+    case AVRC_PDU_REQUEST_CONTINUATION_RSP:     /*        0x40 */
+        status = avrc_bld_next_rsp(&p_rsp->continu, p_pkt);
+        break;
+
+    case AVRC_PDU_ABORT_CONTINUATION_RSP:       /*          0x41 */
+        status = avrc_bld_next_rsp(&p_rsp->abort, p_pkt);
+        break;
+
+    case AVRC_PDU_SET_ADDRESSED_PLAYER:        /* 0x60 */
+        status = avrc_bld_set_addr_player_rsp(&p_rsp->addr_player, p_pkt);
+        break;
+
+    case AVRC_PDU_PLAY_ITEM:                   /* 0x74 */
+        status = avrc_bld_play_item_rsp(&p_rsp->play_item, p_pkt);
+        break;
+
+    case AVRC_PDU_SET_ABSOLUTE_VOLUME:
+        status = avrc_bld_set_absolute_volume_rsp(p_rsp->volume.volume, p_pkt);
+        break;
+
+    case AVRC_PDU_ADD_TO_NOW_PLAYING:          /* 0x90 */
+        status = avrc_bld_add_to_now_playing_rsp(&p_rsp->add_to_play, p_pkt);
+        break;
+
+    case AVRC_PDU_SET_BROWSED_PLAYER:          /* 0x70 */
+        status = avrc_bld_set_browsed_player_rsp(&p_rsp->br_player, p_pkt);
+        break;
+
+    case AVRC_PDU_GET_FOLDER_ITEMS:            /* 0x71 */
+        status = avrc_bld_get_folder_items_rsp(&p_rsp->get_items, p_pkt);
+        break;
+
+    case AVRC_PDU_CHANGE_PATH:                 /* 0x72 */
+        status = avrc_bld_change_path_rsp(&p_rsp->chg_path, p_pkt);
+        break;
+
+    case AVRC_PDU_GET_ITEM_ATTRIBUTES:         /* 0x73 */
+        status = avrc_bld_get_item_attrs_rsp(&p_rsp->get_attrs, p_pkt);
+        break;
+
+    case AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS:      /* 0x75 */
+        status = avrc_bld_get_num_of_item_rsp(&p_rsp->get_num_of_items, p_pkt);
+        break;
+
+    case AVRC_PDU_SEARCH:                      /* 0x80 */
+       status = avrc_bld_search_rsp(&p_rsp->search, p_pkt);
+       break;
+    }
+
+    if (alloc && (status != AVRC_STS_NO_ERROR) )
+    {
+        osi_free(p_pkt);
+        *pp_pkt = NULL;
+    }
+    AVRC_TRACE_API("%s returning %d", __func__, status);
+    return status;
+}
+
+#endif /* (AVRC_METADATA_INCLUDED == true)*/
+
diff --git a/bt/stack/avrc/avrc_int.h b/bt/stack/avrc/avrc_int.h
new file mode 100644
index 0000000..d55c061
--- /dev/null
+++ b/bt/stack/avrc/avrc_int.h
@@ -0,0 +1,171 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2016 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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  VRCP internal header file.
+ *
+ ******************************************************************************/
+
+
+#ifndef AVRC_INT_H
+#define AVRC_INT_H
+
+#include "avct_defs.h"
+#include "avrc_api.h"
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*      DEBUG FLAGS
+ *
+ * #define META_DEBUG_ENABLED
+ */
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+/* Number of attributes in AVRC SDP record. */
+#define AVRC_NUM_ATTR            6
+
+/* Number of protocol elements in protocol element list. */
+#define AVRC_NUM_PROTO_ELEMS     2
+
+#ifndef AVRC_MIN_CMD_LEN
+#define AVRC_MIN_CMD_LEN    20
+#endif
+
+#define AVRC_UNIT_OPRND_BYTES   5
+#define AVRC_SUB_OPRND_BYTES    4
+#define AVRC_SUBRSP_OPRND_BYTES 3
+#define AVRC_SUB_PAGE_MASK      7
+#define AVRC_SUB_PAGE_SHIFT     4
+#define AVRC_SUB_EXT_CODE       7
+#define AVRC_PASS_OP_ID_MASK    0x7F
+#define AVRC_PASS_STATE_MASK    0x80
+#define AVRC_CMD_OPRND_PAD      0xFF
+
+#define AVRC_CTYPE_MASK         0x0F
+#define AVRC_SUBTYPE_MASK       0xF8
+#define AVRC_SUBTYPE_SHIFT      3
+#define AVRC_SUBID_MASK         0x07
+#define AVRC_SUBID_IGNORE       0x07
+
+#define AVRC_SINGLE_PARAM_SIZE      1
+#define AVRC_METADATA_PKT_TYPE_MASK 0x03
+#define AVRC_PASS_THOUGH_MSG_MASK   0x80           /* MSB of msg_type indicates the PAS THROUGH msg */
+#define AVRC_VENDOR_UNIQUE_MASK     0x70           /* vendor unique id */
+
+
+/* Company ID is 24-bit integer We can not use the macros in bt_types.h */
+#define AVRC_CO_ID_TO_BE_STREAM(p, u32) {*(p)++ = (uint8_t)((u32) >> 16); *(p)++ = (uint8_t)((u32) >> 8); *(p)++ = (uint8_t)(u32); }
+#define AVRC_BE_STREAM_TO_CO_ID(u32, p) {(u32) = (((uint32_t)(*((p) + 2))) + (((uint32_t)(*((p) + 1))) << 8) + (((uint32_t)(*(p))) << 16)); (p) += 3;}
+
+#define AVRC_AVC_HDR_SIZE           3   /* ctype, subunit*, opcode */
+
+#define AVRC_MIN_META_HDR_SIZE      4   /* pdu id(1), packet type(1), param len(2) */
+#define AVRC_MIN_BROWSE_HDR_SIZE    3   /* pdu id(1), param len(2) */
+
+#define AVRC_VENDOR_HDR_SIZE        6   /* ctype, subunit*, opcode, CO_ID */
+#define AVRC_MSG_VENDOR_OFFSET      23
+#define AVRC_MIN_VENDOR_SIZE        (AVRC_MSG_VENDOR_OFFSET + BT_HDR_SIZE + AVRC_MIN_META_HDR_SIZE)
+
+#define AVRC_PASS_THRU_SIZE         8
+#define AVRC_MSG_PASS_THRU_OFFSET   25
+#define AVRC_MIN_PASS_THRU_SIZE     (AVRC_MSG_PASS_THRU_OFFSET + BT_HDR_SIZE + 4)
+
+#define AVRC_MIN_BROWSE_SIZE        (AVCT_BROWSE_OFFSET + BT_HDR_SIZE + AVRC_MIN_BROWSE_HDR_SIZE)
+
+#define AVRC_CTRL_PKT_LEN(pf, pk)   {(pf) = (uint8_t *)((pk) + 1) + (pk)->offset + 2;}
+
+#define AVRC_MAX_CTRL_DATA_LEN      (AVRC_PACKET_LEN)
+
+/* Timeout for waiting for avrc command responses (in milliseconds) */
+#ifndef AVRC_CMD_TOUT_MS
+#define AVRC_CMD_TOUT_MS               (2*1000)
+#endif
+
+/* Flags for avrc_cb.ccb_int[].flags */
+#define AVRC_CB_FLAGS_RSP_PENDING   0x01        /* Waiting for AVRC response */
+
+/*****************************************************************************
+**  Type definitions
+*****************************************************************************/
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+/* type for Metadata fragmentation control block */
+typedef struct
+{
+    BT_HDR              *p_fmsg;        /* the fragmented message */
+    uint8_t             frag_pdu;       /* the PDU ID for fragmentation */
+    bool                frag_enabled;   /* fragmentation flag */
+} tAVRC_FRAG_CB;
+
+/* type for Metadata re-assembly control block */
+typedef struct
+{
+    BT_HDR              *p_rmsg;        /* the received message */
+    uint16_t            rasm_offset;    /* re-assembly flag, the offset of the start fragment */
+    uint8_t             rasm_pdu;       /* the PDU ID for re-assembly */
+} tAVRC_RASM_CB;
+#endif
+
+/* AVRC internal connection control block */
+typedef struct
+{
+    fixed_queue_t       *cmd_q;         /* Command queue for serializing vendor specific commands */
+    uint8_t             flags;          /* See AVRC_CB_FLAGS_* definitions */
+    alarm_t *           tle;            /* Command timeout timer */
+} tAVRC_CONN_INT_CB;
+
+typedef struct {
+    tAVRC_CONN_CB       ccb[AVCT_NUM_CONN];     /* Connection control block from AVRC_Open API */
+    tAVRC_CONN_INT_CB   ccb_int[AVCT_NUM_CONN]; /* Internal connection control block  */
+#if (AVRC_METADATA_INCLUDED == TRUE)
+    tAVRC_FRAG_CB       fcb[AVCT_NUM_CONN];
+    tAVRC_RASM_CB       rcb[AVCT_NUM_CONN];
+#endif
+    tAVRC_FIND_CBACK    *p_cback;       /* pointer to application callback */
+    tSDP_DISCOVERY_DB   *p_db;          /* pointer to discovery database */
+    uint16_t            service_uuid;   /* service UUID to search */
+    uint8_t             trace_level;
+} tAVRC_CB;
+
+/******************************************************************************
+** Main Control Block
+*******************************************************************************/
+extern tAVRC_CB  avrc_cb;
+
+extern bool avrc_is_valid_pdu_id(uint8_t pdu_id);
+extern bool avrc_is_valid_player_attrib_value(uint8_t attrib, uint8_t value);
+extern BT_HDR * avrc_alloc_ctrl_pkt (uint8_t pdu);
+extern tAVRC_STS avrc_pars_pass_thru(tAVRC_MSG_PASS *p_msg, uint16_t *p_vendor_unique_id);
+extern uint8_t avrc_opcode_from_pdu(uint8_t pdu);
+extern bool avrc_is_valid_opcode(uint8_t opcode);
+extern void avrc_flush_cmd_q(uint8_t handle);
+void avrc_start_cmd_timer(uint8_t handle, uint8_t label, uint8_t msg_mask);
+void avrc_send_next_vendor_cmd (uint8_t handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVRC_INT_H */
diff --git a/bt/stack/avrc/avrc_opt.cc b/bt/stack/avrc/avrc_opt.cc
new file mode 100644
index 0000000..25e58fe
--- /dev/null
+++ b/bt/stack/avrc/avrc_opt.cc
@@ -0,0 +1,227 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Interface to AVRCP optional commands
+ *
+ ******************************************************************************/
+#include <assert.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "avrc_api.h"
+#include "avrc_int.h"
+
+/******************************************************************************
+**
+** Function         avrc_vendor_msg
+**
+** Description      Compose a VENDOR DEPENDENT command according to p_msg
+**
+**                  Input Parameters:
+**                      p_msg: Pointer to VENDOR DEPENDENT message structure.
+**
+**                  Output Parameters:
+*                      None.
+**
+** Returns          pointer to a valid GKI buffer if successful.
+**                  NULL if p_msg is NULL.
+**
+******************************************************************************/
+static BT_HDR  * avrc_vendor_msg(tAVRC_MSG_VENDOR *p_msg)
+{
+    BT_HDR  *p_cmd;
+    uint8_t *p_data;
+
+    assert(p_msg != NULL);
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+    assert(AVRC_META_CMD_BUF_SIZE > (AVRC_MIN_CMD_LEN + p_msg->vendor_len));
+    p_cmd = (BT_HDR *)osi_malloc(AVRC_META_CMD_BUF_SIZE);
+#else
+    assert(AVRC_CMD_BUF_SIZE > (AVRC_MIN_CMD_LEN + p_msg->vendor_len));
+    p_cmd = (BT_HDR *)osi_malloc(AVRC_CMD_BUF_SIZE);
+#endif
+
+    p_cmd->offset = AVCT_MSG_OFFSET;
+    p_data = (uint8_t *)(p_cmd + 1) + p_cmd->offset;
+    *p_data++ = (p_msg->hdr.ctype & AVRC_CTYPE_MASK);
+    *p_data++ = (p_msg->hdr.subunit_type << AVRC_SUBTYPE_SHIFT) | p_msg->hdr.subunit_id;
+    *p_data++ = AVRC_OP_VENDOR;
+    AVRC_CO_ID_TO_BE_STREAM(p_data, p_msg->company_id);
+    if (p_msg->vendor_len && p_msg->p_vendor_data)
+        memcpy(p_data, p_msg->p_vendor_data, p_msg->vendor_len);
+    p_cmd->len  = (uint16_t)(p_data + p_msg->vendor_len - (uint8_t *)(p_cmd + 1) - p_cmd->offset);
+    p_cmd->layer_specific = AVCT_DATA_CTRL;
+
+    return p_cmd;
+}
+
+/******************************************************************************
+**
+** Function         AVRC_UnitCmd
+**
+** Description      Send a UNIT INFO command to the peer device.  This
+**                  function can only be called for controller role connections.
+**                  Any response message from the peer is passed back through
+**                  the tAVRC_MSG_CBACK callback function.
+**
+**                  Input Parameters:
+**                      handle: Handle of this connection.
+**
+**                      label: Transaction label.
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+uint16_t AVRC_UnitCmd(uint8_t handle, uint8_t label)
+{
+    BT_HDR  *p_cmd = (BT_HDR *)osi_malloc(AVRC_CMD_BUF_SIZE);
+    uint8_t *p_data;
+
+    p_cmd->offset = AVCT_MSG_OFFSET;
+    p_data = (uint8_t *)(p_cmd + 1) + p_cmd->offset;
+    *p_data++ = AVRC_CMD_STATUS;
+    /* unit & id ignore */
+    *p_data++ = (AVRC_SUB_UNIT << AVRC_SUBTYPE_SHIFT) | AVRC_SUBID_IGNORE;
+    *p_data++ = AVRC_OP_UNIT_INFO;
+    memset(p_data, AVRC_CMD_OPRND_PAD, AVRC_UNIT_OPRND_BYTES);
+    p_cmd->len = p_data + AVRC_UNIT_OPRND_BYTES - (uint8_t *)(p_cmd + 1) - p_cmd->offset;
+    p_cmd->layer_specific = AVCT_DATA_CTRL;
+
+    return AVCT_MsgReq(handle, label, AVCT_CMD, p_cmd);
+}
+
+/******************************************************************************
+**
+** Function         AVRC_SubCmd
+**
+** Description      Send a SUBUNIT INFO command to the peer device.  This
+**                  function can only be called for controller role connections.
+**                  Any response message from the peer is passed back through
+**                  the tAVRC_MSG_CBACK callback function.
+**
+**                  Input Parameters:
+**                      handle: Handle of this connection.
+**
+**                      label: Transaction label.
+**
+**                      page: Specifies which part of the subunit type table
+**                      is requested.  For AVRCP it is typically zero.
+**                      Value range is 0-7.
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+uint16_t AVRC_SubCmd(uint8_t handle, uint8_t label, uint8_t page)
+{
+    BT_HDR  *p_cmd = (BT_HDR *)osi_malloc(AVRC_CMD_BUF_SIZE);
+    uint8_t *p_data;
+
+    p_cmd->offset = AVCT_MSG_OFFSET;
+    p_data = (uint8_t *)(p_cmd + 1) + p_cmd->offset;
+    *p_data++ = AVRC_CMD_STATUS;
+    /* unit & id ignore */
+    *p_data++ = (AVRC_SUB_UNIT << AVRC_SUBTYPE_SHIFT) | AVRC_SUBID_IGNORE;
+    *p_data++ = AVRC_OP_SUB_INFO;
+    *p_data++ = ((page&AVRC_SUB_PAGE_MASK) << AVRC_SUB_PAGE_SHIFT) | AVRC_SUB_EXT_CODE;
+    memset(p_data, AVRC_CMD_OPRND_PAD, AVRC_SUB_OPRND_BYTES);
+    p_cmd->len = p_data + AVRC_SUB_OPRND_BYTES - (uint8_t *)(p_cmd + 1) - p_cmd->offset;
+    p_cmd->layer_specific = AVCT_DATA_CTRL;
+
+    return AVCT_MsgReq(handle, label, AVCT_CMD, p_cmd);
+}
+
+/******************************************************************************
+**
+** Function         AVRC_VendorCmd
+**
+** Description      Send a VENDOR DEPENDENT command to the peer device.  This
+**                  function can only be called for controller role connections.
+**                  Any response message from the peer is passed back through
+**                  the tAVRC_MSG_CBACK callback function.
+**
+**                  Input Parameters:
+**                      handle: Handle of this connection.
+**
+**                      label: Transaction label.
+**
+**                      p_msg: Pointer to VENDOR DEPENDENT message structure.
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+uint16_t AVRC_VendorCmd(uint8_t handle, uint8_t label, tAVRC_MSG_VENDOR *p_msg)
+{
+    BT_HDR *p_buf = avrc_vendor_msg(p_msg);
+    if (p_buf)
+        return AVCT_MsgReq( handle, label, AVCT_CMD, p_buf);
+    else
+        return AVCT_NO_RESOURCES;
+}
+
+
+/******************************************************************************
+**
+** Function         AVRC_VendorRsp
+**
+** Description      Send a VENDOR DEPENDENT response to the peer device.  This
+**                  function can only be called for target role connections.
+**                  This function must be called when a VENDOR DEPENDENT
+**                  command message is received from the peer through the
+**                  tAVRC_MSG_CBACK callback function.
+**
+**                  Input Parameters:
+**                      handle: Handle of this connection.
+**
+**                      label: Transaction label.  Must be the same value as
+**                      passed with the command message in the callback function.
+**
+**                      p_msg: Pointer to VENDOR DEPENDENT message structure.
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+uint16_t AVRC_VendorRsp(uint8_t handle, uint8_t label, tAVRC_MSG_VENDOR *p_msg)
+{
+    BT_HDR *p_buf = avrc_vendor_msg(p_msg);
+    if (p_buf)
+        return AVCT_MsgReq( handle, label, AVCT_RSP, p_buf);
+    else
+        return AVCT_NO_RESOURCES;
+}
+
+
+
diff --git a/bt/stack/avrc/avrc_pars_ct.cc b/bt/stack/avrc/avrc_pars_ct.cc
new file mode 100644
index 0000000..a4b98cb
--- /dev/null
+++ b/bt/stack/avrc/avrc_pars_ct.cc
@@ -0,0 +1,714 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2006-2013 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.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_common.h"
+#include "avrc_api.h"
+#include "avrc_defs.h"
+#include "avrc_int.h"
+#include "bt_utils.h"
+#include "osi/include/osi.h"
+
+/*****************************************************************************
+**  Global data
+*****************************************************************************/
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+
+/*******************************************************************************
+**
+** Function         avrc_pars_vendor_rsp
+**
+** Description      This function parses the vendor specific commands defined by
+**                  Bluetooth SIG
+**
+** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+**                  Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p_result)
+{
+    tAVRC_STS  status = AVRC_STS_NO_ERROR;
+    uint8_t *p;
+    uint16_t len;
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+    uint8_t eventid=0;
+#endif
+
+    /* Check the vendor data */
+    if (p_msg->vendor_len == 0)
+        return AVRC_STS_NO_ERROR;
+    if (p_msg->p_vendor_data == NULL)
+        return AVRC_STS_INTERNAL_ERR;
+
+    p = p_msg->p_vendor_data;
+    BE_STREAM_TO_UINT8 (p_result->pdu, p);
+    p++; /* skip the reserved/packe_type byte */
+    BE_STREAM_TO_UINT16 (len, p);
+    AVRC_TRACE_DEBUG("%s ctype:0x%x pdu:0x%x, len:%d/0x%x",
+                     __func__, p_msg->hdr.ctype, p_result->pdu, len, len);
+    if (p_msg->hdr.ctype == AVRC_RSP_REJ)
+    {
+        p_result->rsp.status = *p;
+        return p_result->rsp.status;
+    }
+
+    switch (p_result->pdu)
+    {
+    /* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */
+    /* case AVRC_PDU_ABORT_CONTINUATION_RSP:   0x41 */
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+    case AVRC_PDU_SET_ABSOLUTE_VOLUME:      /* 0x50 */
+        if (len != 1)
+            status = AVRC_STS_INTERNAL_ERR;
+        else
+        {
+            BE_STREAM_TO_UINT8 (p_result->volume.volume, p);
+        }
+        break;
+#endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */
+
+    case AVRC_PDU_REGISTER_NOTIFICATION:    /* 0x31 */
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+        BE_STREAM_TO_UINT8 (eventid, p);
+        if(AVRC_EVT_VOLUME_CHANGE==eventid
+            && (AVRC_RSP_CHANGED==p_msg->hdr.ctype || AVRC_RSP_INTERIM==p_msg->hdr.ctype
+            || AVRC_RSP_REJ==p_msg->hdr.ctype || AVRC_RSP_NOT_IMPL==p_msg->hdr.ctype))
+        {
+            p_result->reg_notif.status=p_msg->hdr.ctype;
+            p_result->reg_notif.event_id=eventid;
+            BE_STREAM_TO_UINT8 (p_result->reg_notif.param.volume, p);
+        }
+        AVRC_TRACE_DEBUG("%s PDU reg notif response:event %x, volume %x",
+                         __func__, eventid, p_result->reg_notif.param.volume);
+#endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */
+        break;
+    default:
+        status = AVRC_STS_BAD_CMD;
+        break;
+    }
+
+    return status;
+}
+
+void avrc_parse_notification_rsp (uint8_t *p_stream, tAVRC_REG_NOTIF_RSP *p_rsp)
+{
+    BE_STREAM_TO_UINT8(p_rsp->event_id, p_stream);
+    switch (p_rsp->event_id)
+    {
+        case AVRC_EVT_PLAY_STATUS_CHANGE:
+            BE_STREAM_TO_UINT8(p_rsp->param.play_status, p_stream);
+            break;
+
+        case AVRC_EVT_TRACK_CHANGE:
+            BE_STREAM_TO_ARRAY(p_stream, p_rsp->param.track, 8);
+            break;
+
+        case AVRC_EVT_APP_SETTING_CHANGE:
+            BE_STREAM_TO_UINT8(p_rsp->param.player_setting.num_attr, p_stream);
+            for (int index = 0; index < p_rsp->param.player_setting.num_attr; index++)
+            {
+                BE_STREAM_TO_UINT8(p_rsp->param.player_setting.attr_id[index], p_stream);
+                BE_STREAM_TO_UINT8(p_rsp->param.player_setting.attr_value[index], p_stream);
+            }
+            break;
+
+        case AVRC_EVT_NOW_PLAYING_CHANGE:
+            break;
+
+        case AVRC_EVT_AVAL_PLAYERS_CHANGE:
+            break;
+
+        case AVRC_EVT_ADDR_PLAYER_CHANGE:
+            break;
+
+        case AVRC_EVT_UIDS_CHANGE:
+            break;
+
+        case AVRC_EVT_TRACK_REACHED_END:
+        case AVRC_EVT_TRACK_REACHED_START:
+        case AVRC_EVT_PLAY_POS_CHANGED:
+        case AVRC_EVT_BATTERY_STATUS_CHANGE:
+        case AVRC_EVT_SYSTEM_STATUS_CHANGE:
+        default:
+            break;
+    }
+}
+
+static tAVRC_STS avrc_pars_browse_rsp(tAVRC_MSG_BROWSE *p_msg, tAVRC_RESPONSE *p_rsp)
+{
+    tAVRC_STS status = AVRC_STS_NO_ERROR;
+    uint8_t pdu;
+
+    if (p_msg->browse_len == 0)
+    {
+        AVRC_TRACE_ERROR("%s length ", p_msg->browse_len);
+        return AVRC_STS_BAD_PARAM;
+    }
+
+    uint8_t *p = p_msg->p_browse_data;
+
+    /* read the pdu */
+    BE_STREAM_TO_UINT8(pdu, p);
+    uint8_t pkt_len;
+    /* read the entire packet len */
+    BE_STREAM_TO_UINT16(pkt_len, p);
+
+    AVRC_TRACE_DEBUG("%s pdu %d", __func__, pdu);
+
+    /* used to track how much we have read, if we cannot read anymore but the
+     * packet says so then we have a malformed packet. Also vice versa. */
+    uint16_t pkt_len_read = 0;
+
+
+    switch (pdu)
+    {
+    case AVRC_PDU_GET_FOLDER_ITEMS:
+    {
+        tAVRC_GET_ITEMS_RSP *get_item_rsp = &(p_rsp->get_items);
+        /* Copy back the PDU */
+        get_item_rsp->pdu = pdu;
+        /* read the status */
+        BE_STREAM_TO_UINT8(get_item_rsp->status, p);
+        /* read the UID counter */
+        BE_STREAM_TO_UINT16(get_item_rsp->uid_counter, p);
+        /* read the number of items */
+        BE_STREAM_TO_UINT16(get_item_rsp->item_count, p);
+        pkt_len_read += 5;
+
+        AVRC_TRACE_DEBUG("%s pdu %d status %d pkt_len %d uid counter %d item count %d",
+                            __func__, get_item_rsp->pdu, get_item_rsp->status, pkt_len,
+                            get_item_rsp->uid_counter, get_item_rsp->item_count);
+
+        if (get_item_rsp->status != AVRC_STS_NO_ERROR) {
+            AVRC_TRACE_WARNING("%s returning error %d", __func__, get_item_rsp->status);
+            return get_item_rsp->status;
+        }
+
+        /* get each of the items */
+        get_item_rsp->p_item_list =
+            (tAVRC_ITEM *) osi_malloc (get_item_rsp->item_count * (sizeof(tAVRC_ITEM)));
+        tAVRC_ITEM *curr_item = get_item_rsp->p_item_list;
+        for (int i = 0; i < get_item_rsp->item_count; i++)
+        {
+            BE_STREAM_TO_UINT8(curr_item->item_type, p);
+            pkt_len_read += 1;
+            AVRC_TRACE_DEBUG("%s item type %d", __func__, curr_item->item_type);
+            switch (curr_item->item_type)
+            {
+                case AVRC_ITEM_PLAYER:
+                {
+                    /* Handle player */
+                    tAVRC_ITEM_PLAYER *player = &(curr_item->u.player);
+                    uint8_t player_len;
+                    BE_STREAM_TO_UINT16(player_len, p);
+                    BE_STREAM_TO_UINT16(player->player_id, p);
+                    BE_STREAM_TO_UINT8(player->major_type, p);
+                    BE_STREAM_TO_UINT32(player->sub_type, p);
+                    BE_STREAM_TO_UINT8(player->play_status, p);
+                    BE_STREAM_TO_ARRAY(p, player->features, AVRC_FEATURE_MASK_SIZE);
+                    pkt_len_read += (10 + AVRC_FEATURE_MASK_SIZE);
+
+                    /* read str */
+                    BE_STREAM_TO_UINT16(player->name.charset_id, p);
+                    BE_STREAM_TO_UINT16(player->name.str_len, p);
+                    player->name.p_str = (uint8_t *) osi_malloc (
+                        (player->name.str_len + 1) * sizeof (uint8_t));
+                    BE_STREAM_TO_ARRAY(p, player->name.p_str, player->name.str_len);
+                    pkt_len_read += (4 + player->name.str_len);
+                    AVRC_TRACE_DEBUG(
+                        "%s type %d id %d mtype %d stype %d ps %d cs %d name len %d",
+                        __func__, curr_item->item_type, player->player_id,
+                        player->major_type, player->sub_type, player->play_status,
+                        player->name.charset_id, player->name.str_len);
+                } break;
+
+                case AVRC_ITEM_FOLDER:
+                {
+                    tAVRC_ITEM_FOLDER *folder = &(curr_item->u.folder);
+                    uint16_t folder_len;
+                    BE_STREAM_TO_UINT16(folder_len, p);
+
+                    BE_STREAM_TO_ARRAY(p, folder->uid, AVRC_UID_SIZE);
+                    BE_STREAM_TO_UINT8(folder->type, p);
+                    BE_STREAM_TO_UINT8(folder->playable, p);
+                    pkt_len_read += (4 + AVRC_UID_SIZE);
+
+                    /* read str, encoding to be handled by upper layers */
+                    BE_STREAM_TO_UINT16(folder->name.charset_id, p);
+                    BE_STREAM_TO_UINT16(folder->name.str_len, p);
+                    folder->name.p_str = (uint8_t *) osi_malloc (
+                        (folder->name.str_len + 1) * sizeof (uint8_t));
+                    BE_STREAM_TO_ARRAY(p, folder->name.p_str, folder->name.str_len);
+                    pkt_len_read += (4 + folder->name.str_len);
+                    AVRC_TRACE_DEBUG(
+                        "%s type %d playable %d cs %d name len %d",
+                        __func__, folder->type, folder->playable, folder->name.charset_id,
+                        folder->name.str_len);
+                } break;
+
+                case AVRC_ITEM_MEDIA:
+                {
+                    tAVRC_ITEM_MEDIA *media = &(curr_item->u.media);
+                    uint8_t media_len;
+                    BE_STREAM_TO_UINT16(media_len, p);
+                    BE_STREAM_TO_ARRAY(p, media->uid, AVRC_UID_SIZE);
+                    BE_STREAM_TO_UINT8(media->type, p);
+                    pkt_len_read += (3 + AVRC_UID_SIZE);
+
+                    /* read str, encoding to be handled by upper layers */
+                    BE_STREAM_TO_UINT16(media->name.charset_id, p);
+                    BE_STREAM_TO_UINT16(media->name.str_len, p);
+                    media->name.p_str = (uint8_t *) osi_malloc (
+                        (media->name.str_len) * sizeof (uint8_t));
+                    BE_STREAM_TO_ARRAY(p, media->name.p_str, media->name.str_len);
+
+                    BE_STREAM_TO_UINT8(media->attr_count, p);
+                    AVRC_TRACE_DEBUG("%s media type %d charset id %d len %d attr ct %d",
+                                        __func__, media->type, media->name.charset_id,
+                                        media->name.str_len, media->attr_count);
+                    pkt_len_read += (5 + media->name.str_len);
+
+                    media->p_attr_list = (tAVRC_ATTR_ENTRY *) osi_malloc (
+                        media->attr_count * sizeof (tAVRC_ATTR_ENTRY));
+                    for (int jk = 0; jk < media->attr_count; jk++)
+                    {
+                        tAVRC_ATTR_ENTRY *attr_entry = &(media->p_attr_list[jk]);
+                        BE_STREAM_TO_UINT32(attr_entry->attr_id, p);
+
+                        /* Parse the name now */
+                        BE_STREAM_TO_UINT16(attr_entry->name.charset_id, p);
+                        BE_STREAM_TO_UINT16(attr_entry->name.str_len, p);
+                        attr_entry->name.p_str = (uint8_t *) osi_malloc (
+                            attr_entry->name.str_len * sizeof (uint8_t));
+                        BE_STREAM_TO_ARRAY(p, attr_entry->name.p_str, attr_entry->name.str_len);
+                        pkt_len_read += (8 + attr_entry->name.str_len);
+                        AVRC_TRACE_DEBUG("%s media attr id %d cs %d name len %d",
+                                         __func__, attr_entry->attr_id,
+                                         attr_entry->name.charset_id, attr_entry->name.str_len);
+                    }
+                } break;
+
+                default:
+                    AVRC_TRACE_ERROR("%s item type not handled %d", __func__, curr_item->item_type);
+                    return AVRC_STS_INTERNAL_ERR;
+            }
+
+            /* we check if we have overrun */
+            if (pkt_len_read > pkt_len)
+            {
+                AVRC_TRACE_ERROR("%s overflow in read pkt_len %d pkt_len_read %d",
+                                    __func__, pkt_len, pkt_len_read);
+                return AVRC_STS_BAD_CMD;
+            }
+            AVRC_TRACE_DEBUG("%s pkt_len %d pkt_len_read %d", __func__, pkt_len, pkt_len_read);
+
+            /* advance to populate the next item */
+            curr_item++;
+        }
+        break;
+    }
+
+    case AVRC_PDU_CHANGE_PATH:
+    {
+        tAVRC_CHG_PATH_RSP *change_path_rsp = &(p_rsp->chg_path);
+        /* Copyback the PDU */
+        change_path_rsp->pdu = pdu;
+        /* Read the status */
+        BE_STREAM_TO_UINT8(change_path_rsp->status, p);
+        /* Read the number of items in folder */
+        BE_STREAM_TO_UINT32(change_path_rsp->num_items, p);
+        pkt_len_read += 5;
+
+        AVRC_TRACE_DEBUG("%s pdu %d status %d item count %d",
+                         __func__, change_path_rsp->pdu, change_path_rsp->status,
+                         change_path_rsp->num_items);
+        break;
+    }
+
+    case AVRC_PDU_SET_BROWSED_PLAYER:
+    {
+        tAVRC_SET_BR_PLAYER_RSP *set_br_pl_rsp = &(p_rsp->br_player);
+        /* Copyback the PDU */
+        set_br_pl_rsp->pdu = pdu;
+
+        /* Read the status */
+        BE_STREAM_TO_UINT8(set_br_pl_rsp->status, p);
+
+        if (set_br_pl_rsp->status != AVRC_STS_NO_ERROR) {
+            AVRC_TRACE_ERROR(
+                "%s Stopping further parsing because player not browsable sts %d",
+                __func__, set_br_pl_rsp->status);
+            break;
+        }
+        BE_STREAM_TO_UINT16(set_br_pl_rsp->uid_counter, p);
+        BE_STREAM_TO_UINT32(set_br_pl_rsp->num_items, p);
+        BE_STREAM_TO_UINT16(set_br_pl_rsp->charset_id, p);
+        BE_STREAM_TO_UINT8(set_br_pl_rsp->folder_depth, p);
+        AVRC_TRACE_DEBUG("%s AVRC_PDU_SET_BROWSED_PLAYER status %d items %d cs %d depth %d",
+                         __func__,
+                         set_br_pl_rsp->status,
+                         set_br_pl_rsp->num_items,
+                         set_br_pl_rsp->charset_id,
+                         set_br_pl_rsp->folder_depth);
+        pkt_len_read += 10;
+
+        set_br_pl_rsp->p_folders = (tAVRC_NAME *) osi_malloc (
+            set_br_pl_rsp->num_items * sizeof (tAVRC_NAME));
+
+        /* Read each of the folder in the depth */
+        for (uint32_t i = 0; i < set_br_pl_rsp->folder_depth; i++) {
+            tAVRC_NAME *folder_name = &(set_br_pl_rsp->p_folders[i]);
+            BE_STREAM_TO_UINT16(folder_name->str_len, p);
+            AVRC_TRACE_DEBUG("%s AVRC_PDU_SET_BROWSED_PLAYER item: %d len: %d",
+                             __func__, i, folder_name->str_len);
+            folder_name->p_str = (uint8_t *) osi_malloc (
+                (folder_name->str_len + 1) * sizeof (uint8_t));
+            BE_STREAM_TO_ARRAY(p, folder_name->p_str, folder_name->str_len);
+            pkt_len_read += (2 + folder_name->str_len);
+        }
+        break;
+    }
+
+    default:
+        AVRC_TRACE_ERROR("%s pdu %d not handled", __func__, pdu);
+    }
+
+    if (pkt_len != pkt_len_read)
+    {
+        AVRC_TRACE_ERROR("%s finished pkt_len %d pkt_len_read %d", __func__, pkt_len, pkt_len_read);
+        return AVRC_STS_BAD_CMD;
+    }
+    return status;
+}
+
+#if (AVRC_CTRL_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function         avrc_ctrl_pars_vendor_rsp
+**
+** Description      This function parses the vendor specific commands defined by
+**                  Bluetooth SIG
+**
+** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+**                  Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+static tAVRC_STS avrc_ctrl_pars_vendor_rsp(
+    tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p_result, uint8_t* p_buf, uint16_t* buf_len)
+{
+    uint8_t *p = p_msg->p_vendor_data;
+    BE_STREAM_TO_UINT8 (p_result->pdu, p);
+    p++; /* skip the reserved/packe_type byte */
+
+    uint16_t len;
+    BE_STREAM_TO_UINT16 (len, p);
+    AVRC_TRACE_DEBUG("%s ctype:0x%x pdu:0x%x, len:%d",
+                     __func__, p_msg->hdr.ctype, p_result->pdu, len);
+    /* Todo: Issue in handling reject, check */
+    if (p_msg->hdr.ctype == AVRC_RSP_REJ)
+    {
+        p_result->rsp.status = *p;
+        return p_result->rsp.status;
+    }
+
+    /* TODO: Break the big switch into functions. */
+    switch (p_result->pdu)
+    {
+    /* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */
+    /* case AVRC_PDU_ABORT_CONTINUATION_RSP:   0x41 */
+
+    case AVRC_PDU_REGISTER_NOTIFICATION:
+        avrc_parse_notification_rsp(p, &p_result->reg_notif);
+        break;
+
+    case AVRC_PDU_GET_CAPABILITIES:
+        if (len == 0)
+        {
+            p_result->get_caps.count = 0;
+            p_result->get_caps.capability_id = 0;
+            break;
+        }
+        BE_STREAM_TO_UINT8(p_result->get_caps.capability_id, p);
+        BE_STREAM_TO_UINT8(p_result->get_caps.count, p);
+        AVRC_TRACE_DEBUG("%s cap id = %d, cap_count = %d ",
+                         __func__, p_result->get_caps.capability_id, p_result->get_caps.count);
+        if (p_result->get_caps.capability_id == AVRC_CAP_COMPANY_ID)
+        {
+            for(int xx = 0; ((xx < p_result->get_caps.count) && (xx < AVRC_CAP_MAX_NUM_COMP_ID));
+                xx++)
+            {
+                BE_STREAM_TO_UINT24(p_result->get_caps.param.company_id[xx], p);
+            }
+        }
+        else if (p_result->get_caps.capability_id == AVRC_CAP_EVENTS_SUPPORTED)
+        {
+            for(int xx = 0; ((xx < p_result->get_caps.count) && (xx < AVRC_CAP_MAX_NUM_EVT_ID));
+                xx++)
+            {
+                BE_STREAM_TO_UINT8(p_result->get_caps.param.event_id[xx], p);
+            }
+        }
+        break;
+
+    case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+        if (len == 0)
+        {
+            p_result->list_app_attr.num_attr = 0;
+            break;
+        }
+        BE_STREAM_TO_UINT8(p_result->list_app_attr.num_attr, p);
+        AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, p_result->list_app_attr.num_attr);
+        for(int xx = 0; xx < p_result->list_app_attr.num_attr; xx++)
+        {
+            BE_STREAM_TO_UINT8(p_result->list_app_attr.attrs[xx], p);
+        }
+        break;
+
+    case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+        if (len == 0)
+        {
+            p_result->list_app_values.num_val = 0;
+            break;
+        }
+        BE_STREAM_TO_UINT8(p_result->list_app_values.num_val, p);
+        AVRC_TRACE_DEBUG("%s value count = %d ", __func__, p_result->list_app_values.num_val);
+        for(int xx = 0; xx < p_result->list_app_values.num_val; xx++)
+        {
+            BE_STREAM_TO_UINT8(p_result->list_app_values.vals[xx], p);
+        }
+        break;
+
+    case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+    {
+        if (len == 0)
+        {
+            p_result->get_cur_app_val.num_val = 0;
+            break;
+        }
+        BE_STREAM_TO_UINT8(p_result->get_cur_app_val.num_val, p);
+        tAVRC_APP_SETTING *app_sett =
+            (tAVRC_APP_SETTING*)osi_malloc(p_result->get_cur_app_val.num_val*sizeof(tAVRC_APP_SETTING));
+        AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, p_result->get_cur_app_val.num_val);
+        for (int xx = 0; xx < p_result->get_cur_app_val.num_val; xx++)
+        {
+            BE_STREAM_TO_UINT8(app_sett[xx].attr_id, p);
+            BE_STREAM_TO_UINT8(app_sett[xx].attr_val, p);
+        }
+        p_result->get_cur_app_val.p_vals = app_sett;
+    }
+        break;
+
+    case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+    {
+        tAVRC_APP_SETTING_TEXT   *p_setting_text;
+        uint8_t                  num_attrs;
+
+        if (len == 0)
+        {
+            p_result->get_app_attr_txt.num_attr = 0;
+            break;
+        }
+        BE_STREAM_TO_UINT8(num_attrs, p);
+        AVRC_TRACE_DEBUG("%s attr count = %d ", __func__, p_result->get_app_attr_txt.num_attr);
+        p_result->get_app_attr_txt.num_attr = num_attrs;
+        p_setting_text = (tAVRC_APP_SETTING_TEXT*)osi_malloc(num_attrs * sizeof(tAVRC_APP_SETTING_TEXT));
+        for (int xx = 0; xx < num_attrs; xx++)
+        {
+            BE_STREAM_TO_UINT8(p_result->get_app_attr_txt.p_attrs[xx].attr_id, p);
+            BE_STREAM_TO_UINT16(p_result->get_app_attr_txt.p_attrs[xx].charset_id, p);
+            BE_STREAM_TO_UINT8(p_result->get_app_attr_txt.p_attrs[xx].str_len, p);
+            if (p_result->get_app_attr_txt.p_attrs[xx].str_len != 0)
+            {
+                uint8_t *p_str = (uint8_t *)osi_malloc(p_result->get_app_attr_txt.p_attrs[xx].str_len);
+                BE_STREAM_TO_ARRAY(p, p_str, p_result->get_app_attr_txt.p_attrs[xx].str_len);
+                p_result->get_app_attr_txt.p_attrs[xx].p_str = p_str;
+            } else {
+                p_result->get_app_attr_txt.p_attrs[xx].p_str = NULL;
+            }
+        }
+    }
+        break;
+
+    case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
+    {
+        tAVRC_APP_SETTING_TEXT   *p_setting_text;
+        uint8_t                  num_vals;
+
+        if (len == 0)
+        {
+            p_result->get_app_val_txt.num_attr = 0;
+            break;
+        }
+        BE_STREAM_TO_UINT8(num_vals, p);
+        p_result->get_app_val_txt.num_attr = num_vals;
+        AVRC_TRACE_DEBUG("%s value count = %d ", __func__, p_result->get_app_val_txt.num_attr);
+
+        p_setting_text = (tAVRC_APP_SETTING_TEXT *)osi_malloc(num_vals * sizeof(tAVRC_APP_SETTING_TEXT));
+        for (int i = 0; i < num_vals; i++) {
+            BE_STREAM_TO_UINT8(p_result->get_app_val_txt.p_attrs[i].attr_id, p);
+            BE_STREAM_TO_UINT16(p_result->get_app_val_txt.p_attrs[i].charset_id, p);
+            BE_STREAM_TO_UINT8(p_result->get_app_val_txt.p_attrs[i].str_len, p);
+            if (p_result->get_app_val_txt.p_attrs[i].str_len != 0) {
+                uint8_t *p_str = (uint8_t *)osi_malloc(p_result->get_app_val_txt.p_attrs[i].str_len);
+                BE_STREAM_TO_ARRAY(p, p_str, p_result->get_app_val_txt.p_attrs[i].str_len);
+                p_result->get_app_val_txt.p_attrs[i].p_str = p_str;
+            } else {
+                p_result->get_app_val_txt.p_attrs[i].p_str = NULL;
+            }
+        }
+    }
+        break;
+
+    case AVRC_PDU_SET_PLAYER_APP_VALUE:
+        /* nothing comes as part of this rsp */
+        break;
+
+    case AVRC_PDU_GET_ELEMENT_ATTR:
+    {
+        uint8_t             num_attrs;
+
+        if (len <= 0)
+        {
+            p_result->get_elem_attrs.num_attr = 0;
+            break;
+        }
+        BE_STREAM_TO_UINT8(num_attrs, p);
+        p_result->get_elem_attrs.num_attr = num_attrs;
+        if (num_attrs)
+        {
+            tAVRC_ATTR_ENTRY *p_attrs =
+                (tAVRC_ATTR_ENTRY*)osi_malloc(num_attrs * sizeof(tAVRC_ATTR_ENTRY));
+            for (int i = 0; i < num_attrs; i++) {
+                BE_STREAM_TO_UINT32(p_attrs[i].attr_id, p);
+                BE_STREAM_TO_UINT16(p_attrs[i].name.charset_id, p);
+                BE_STREAM_TO_UINT16(p_attrs[i].name.str_len, p);
+                if (p_attrs[i].name.str_len > 0) {
+                    p_attrs[i].name.p_str = (uint8_t *)osi_malloc(p_attrs[i].name.str_len);
+                    BE_STREAM_TO_ARRAY(p, p_attrs[i].name.p_str, p_attrs[i].name.str_len);
+                }
+            }
+            p_result->get_elem_attrs.p_attrs = p_attrs;
+        }
+    }
+        break;
+
+    case AVRC_PDU_GET_PLAY_STATUS:
+        if (len == 0)
+        {
+            break;
+        }
+        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);
+        break;
+
+    case AVRC_PDU_SET_ADDRESSED_PLAYER:
+        if (len != 1)
+        {
+            AVRC_TRACE_ERROR("%s pdu: %d len %d", __func__, p_result->pdu, len);
+            return AVRC_STS_BAD_CMD;
+        }
+        BE_STREAM_TO_UINT8(p_result->rsp.status, p);
+        break;
+
+    default:
+        return AVRC_STS_BAD_CMD;
+    }
+    return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+**
+** Function         AVRC_Ctrl_ParsResponse
+**
+** Description      This function is a parse response for AVRCP Controller.
+**
+** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+**                  Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+tAVRC_STS AVRC_Ctrl_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result, uint8_t *p_buf, uint16_t* buf_len)
+{
+    tAVRC_STS  status = AVRC_STS_INTERNAL_ERR;
+    if (p_msg && p_result)
+    {
+        switch (p_msg->hdr.opcode)
+        {
+        case AVRC_OP_VENDOR:     /*  0x00    Vendor-dependent commands */
+            status = avrc_ctrl_pars_vendor_rsp(&p_msg->vendor, p_result, p_buf,buf_len);
+            break;
+
+        case AVRC_OP_BROWSE:  /* 0xff Browse commands */
+            status = avrc_pars_browse_rsp(&p_msg->browse, p_result);
+            break;
+
+        default:
+            AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
+            break;
+        }
+        p_result->rsp.opcode = p_msg->hdr.opcode;
+        p_result->rsp.status = status;
+    }
+    return status;
+}
+#endif /* (AVRC_CTRL_INCLUDED) == TRUE) */
+/*******************************************************************************
+**
+** Function         AVRC_ParsResponse
+**
+** Description      This function is a superset of AVRC_ParsMetadata to parse the response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+**                  Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+tAVRC_STS AVRC_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result,
+                             UNUSED_ATTR uint8_t *p_buf,
+                             UNUSED_ATTR uint16_t buf_len)
+{
+    tAVRC_STS  status = AVRC_STS_INTERNAL_ERR;
+    uint16_t id;
+
+    if (p_msg && p_result)
+    {
+        switch (p_msg->hdr.opcode)
+        {
+        case AVRC_OP_VENDOR:     /*  0x00    Vendor-dependent commands */
+            status = avrc_pars_vendor_rsp(&p_msg->vendor, p_result);
+            break;
+
+        case AVRC_OP_PASS_THRU:  /*  0x7C    panel subunit opcode */
+            status = avrc_pars_pass_thru(&p_msg->pass, &id);
+            if (status == AVRC_STS_NO_ERROR)
+            {
+                p_result->pdu = (uint8_t)id;
+            }
+            break;
+
+        default:
+            AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
+            break;
+        }
+        p_result->rsp.opcode = p_msg->hdr.opcode;
+        p_result->rsp.status = status;
+    }
+    return status;
+}
+#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
diff --git a/bt/stack/avrc/avrc_pars_tg.cc b/bt/stack/avrc/avrc_pars_tg.cc
new file mode 100644
index 0000000..3917077
--- /dev/null
+++ b/bt/stack/avrc/avrc_pars_tg.cc
@@ -0,0 +1,596 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2016 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.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_common.h"
+#include "avrc_api.h"
+#include "avrc_defs.h"
+#include "avrc_int.h"
+
+/*****************************************************************************
+**  Global data
+*****************************************************************************/
+#if (AVRC_METADATA_INCLUDED == TRUE)
+
+#if (AVRC_CTRL_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function         avrc_ctrl_pars_vendor_cmd
+**
+** Description      This function parses the vendor specific commands defined by
+**                  Bluetooth SIG for AVRCP Conroller.
+**
+** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+**                  Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+static tAVRC_STS avrc_ctrl_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_result)
+{
+    tAVRC_STS  status = AVRC_STS_NO_ERROR;
+
+    uint8_t *p = p_msg->p_vendor_data;
+    p_result->pdu = *p++;
+    AVRC_TRACE_DEBUG("%s pdu:0x%x", __func__, p_result->pdu);
+    if (!AVRC_IsValidAvcType (p_result->pdu, p_msg->hdr.ctype))
+    {
+        AVRC_TRACE_DEBUG("%s detects wrong AV/C type!", __func__);
+        status = AVRC_STS_BAD_CMD;
+    }
+
+    p++; /* skip the reserved byte */
+    uint16_t len;
+    BE_STREAM_TO_UINT16 (len, p);
+    if ((len+4) != (p_msg->vendor_len))
+    {
+        status = AVRC_STS_INTERNAL_ERR;
+    }
+
+    if (status != AVRC_STS_NO_ERROR)
+        return status;
+
+    switch (p_result->pdu)
+    {
+        case AVRC_PDU_SET_ABSOLUTE_VOLUME:
+        {
+            if(len!=1)
+                status = AVRC_STS_INTERNAL_ERR;
+            else
+            {
+                BE_STREAM_TO_UINT8 (p_result->volume.volume, p);
+                p_result->volume.volume = AVRC_MAX_VOLUME & p_result->volume.volume;
+            }
+            break;
+        }
+        case AVRC_PDU_REGISTER_NOTIFICATION:    /* 0x31 */
+            BE_STREAM_TO_UINT8 (p_result->reg_notif.event_id, p);
+            BE_STREAM_TO_UINT32 (p_result->reg_notif.param, p);
+            break;
+        default:
+            status = AVRC_STS_BAD_CMD;
+            break;
+    }
+    return status;
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         avrc_pars_vendor_cmd
+**
+** Description      This function parses the vendor specific commands defined by
+**                  Bluetooth SIG
+**
+** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+**                  Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_result,
+                                      uint8_t *p_buf, uint16_t buf_len)
+{
+    tAVRC_STS  status = AVRC_STS_NO_ERROR;
+    uint8_t *p;
+    uint16_t len;
+    uint8_t xx, yy;
+    uint8_t *p_u8;
+    uint16_t *p_u16;
+    uint32_t u32, u32_2, *p_u32;
+    tAVRC_APP_SETTING       *p_app_set;
+    uint16_t size_needed;
+
+    /* Check the vendor data */
+    if (p_msg->vendor_len == 0)
+        return AVRC_STS_NO_ERROR;
+    if (p_msg->p_vendor_data == NULL)
+        return AVRC_STS_INTERNAL_ERR;
+
+    p = p_msg->p_vendor_data;
+    p_result->pdu = *p++;
+    AVRC_TRACE_DEBUG("%s pdu:0x%x", __func__, p_result->pdu);
+    if (!AVRC_IsValidAvcType (p_result->pdu, p_msg->hdr.ctype))
+    {
+        AVRC_TRACE_DEBUG("%s detects wrong AV/C type(0x%x)!", __func__,
+                           p_msg->hdr.ctype);
+        status = AVRC_STS_BAD_CMD;
+    }
+
+    p++; /* skip the reserved byte */
+    BE_STREAM_TO_UINT16 (len, p);
+    if ((len+4) != (p_msg->vendor_len))
+    {
+        AVRC_TRACE_ERROR("%s incorrect length :%d, %d", __func__, len, p_msg->vendor_len);
+        status = AVRC_STS_INTERNAL_ERR;
+    }
+
+    if (status != AVRC_STS_NO_ERROR)
+        return status;
+
+    switch (p_result->pdu)
+    {
+    case AVRC_PDU_GET_CAPABILITIES:         /* 0x10 */
+        p_result->get_caps.capability_id = *p++;
+        if (!AVRC_IS_VALID_CAP_ID(p_result->get_caps.capability_id))
+            status = AVRC_STS_BAD_PARAM;
+        else if (len != 1)
+            status = AVRC_STS_INTERNAL_ERR;
+        break;
+
+    case AVRC_PDU_LIST_PLAYER_APP_ATTR:     /* 0x11 */
+        /* no additional parameters */
+        if (len != 0)
+            status = AVRC_STS_INTERNAL_ERR;
+        break;
+
+    case AVRC_PDU_LIST_PLAYER_APP_VALUES:   /* 0x12 */
+        p_result->list_app_values.attr_id = *p++;
+        if (!AVRC_IS_VALID_ATTRIBUTE(p_result->list_app_values.attr_id))
+            status = AVRC_STS_BAD_PARAM;
+        else if (len != 1)
+            status = AVRC_STS_INTERNAL_ERR;
+        break;
+
+    case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: /* 0x13 */
+    case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: /* 0x15 */
+        BE_STREAM_TO_UINT8 (p_result->get_cur_app_val.num_attr, p);
+        if (len != (p_result->get_cur_app_val.num_attr+1))
+        {
+            status = AVRC_STS_INTERNAL_ERR;
+            break;
+        }
+        p_u8 = p_result->get_cur_app_val.attrs;
+        for (xx=0, yy=0; xx< p_result->get_cur_app_val.num_attr; xx++)
+        {
+            /* only report the valid player app attributes */
+            if (AVRC_IsValidPlayerAttr(*p))
+                p_u8[yy++] = *p;
+            p++;
+        }
+        p_result->get_cur_app_val.num_attr = yy;
+        if (yy == 0)
+        {
+            status = AVRC_STS_BAD_PARAM;
+        }
+        break;
+
+    case AVRC_PDU_SET_PLAYER_APP_VALUE:     /* 0x14 */
+        BE_STREAM_TO_UINT8 (p_result->set_app_val.num_val, p);
+        size_needed = sizeof(tAVRC_APP_SETTING);
+        if (p_buf && (len == ((p_result->set_app_val.num_val<<1) + 1)))
+        {
+            p_result->set_app_val.p_vals = (tAVRC_APP_SETTING *)p_buf;
+            p_app_set = p_result->set_app_val.p_vals;
+            for (xx=0; ((xx< p_result->set_app_val.num_val) && (buf_len > size_needed)); xx++)
+            {
+                p_app_set[xx].attr_id = *p++;
+                p_app_set[xx].attr_val = *p++;
+                if (!avrc_is_valid_player_attrib_value(p_app_set[xx].attr_id,
+                    p_app_set[xx].attr_val))
+                    status = AVRC_STS_BAD_PARAM;
+            }
+            if (xx != p_result->set_app_val.num_val)
+            {
+                AVRC_TRACE_ERROR(
+                    "%s AVRC_PDU_SET_PLAYER_APP_VALUE not enough room:%d orig num_val:%d",
+                    __func__, xx, p_result->set_app_val.num_val);
+                p_result->set_app_val.num_val = xx;
+            }
+        }
+        else
+        {
+            AVRC_TRACE_ERROR("%s AVRC_PDU_SET_PLAYER_APP_VALUE NULL decode buffer or bad len",
+                             __func__);
+            status = AVRC_STS_INTERNAL_ERR;
+        }
+        break;
+
+    case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:/* 0x16 */
+        if (len < 3)
+            status = AVRC_STS_INTERNAL_ERR;
+        else
+        {
+            BE_STREAM_TO_UINT8 (p_result->get_app_val_txt.attr_id, p);
+            if (!AVRC_IS_VALID_ATTRIBUTE(p_result->get_app_val_txt.attr_id))
+                status = AVRC_STS_BAD_PARAM;
+            else
+            {
+                BE_STREAM_TO_UINT8 (p_result->get_app_val_txt.num_val, p);
+                if ( (len - 2/* attr_id & num_val */) != p_result->get_app_val_txt.num_val)
+                    status = AVRC_STS_INTERNAL_ERR;
+                else
+                {
+                    p_u8 = p_result->get_app_val_txt.vals;
+                    for (xx=0; xx< p_result->get_app_val_txt.num_val; xx++)
+                    {
+                        p_u8[xx] = *p++;
+                        if (!avrc_is_valid_player_attrib_value(p_result->get_app_val_txt.attr_id,
+                            p_u8[xx]))
+                        {
+                            status = AVRC_STS_BAD_PARAM;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        break;
+
+    case AVRC_PDU_INFORM_DISPLAY_CHARSET:  /* 0x17 */
+        if (len < 3)
+            status = AVRC_STS_INTERNAL_ERR;
+        else
+        {
+            BE_STREAM_TO_UINT8 (p_result->inform_charset.num_id, p);
+            if ( (len - 1/* num_id */) != p_result->inform_charset.num_id * 2)
+                status = AVRC_STS_INTERNAL_ERR;
+            else
+            {
+                p_u16 = p_result->inform_charset.charsets;
+                if (p_result->inform_charset.num_id > AVRC_MAX_CHARSET_SIZE)
+                    p_result->inform_charset.num_id = AVRC_MAX_CHARSET_SIZE;
+                for (xx=0; xx< p_result->inform_charset.num_id; xx++)
+                {
+                    BE_STREAM_TO_UINT16 (p_u16[xx], p);
+                }
+            }
+        }
+        break;
+
+    case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT:/* 0x18 */
+        if (len != 1)
+            status = AVRC_STS_INTERNAL_ERR;
+        else
+        {
+            p_result->inform_battery_status.battery_status = *p++;
+            if (!AVRC_IS_VALID_BATTERY_STATUS(p_result->inform_battery_status.battery_status))
+                status = AVRC_STS_BAD_PARAM;
+        }
+        break;
+
+    case AVRC_PDU_GET_ELEMENT_ATTR:         /* 0x20 */
+        if (len < 9) /* UID/8 and num_attr/1 */
+            status = AVRC_STS_INTERNAL_ERR;
+        else
+        {
+            BE_STREAM_TO_UINT32 (u32, p);
+            BE_STREAM_TO_UINT32 (u32_2, p);
+            if (u32== 0 && u32_2 == 0)
+            {
+                BE_STREAM_TO_UINT8 (p_result->get_elem_attrs.num_attr, p);
+                if ( (len - 9/* UID/8 and num_attr/1 */) != (p_result->get_elem_attrs.num_attr * 4))
+                    status = AVRC_STS_INTERNAL_ERR;
+                else
+                {
+                    p_u32 = p_result->get_elem_attrs.attrs;
+                    if (p_result->get_elem_attrs.num_attr > AVRC_MAX_ELEM_ATTR_SIZE)
+                        p_result->get_elem_attrs.num_attr = AVRC_MAX_ELEM_ATTR_SIZE;
+                    for (xx=0; xx< p_result->get_elem_attrs.num_attr; xx++)
+                    {
+                        BE_STREAM_TO_UINT32 (p_u32[xx], p);
+                    }
+                }
+            }
+            else
+                status = AVRC_STS_NOT_FOUND;
+        }
+        break;
+
+    case AVRC_PDU_GET_PLAY_STATUS:          /* 0x30 */
+        /* no additional parameters */
+        if (len != 0)
+            status = AVRC_STS_INTERNAL_ERR;
+        break;
+
+    case AVRC_PDU_REGISTER_NOTIFICATION:    /* 0x31 */
+        if (len != 5)
+            status = AVRC_STS_INTERNAL_ERR;
+        else
+        {
+            BE_STREAM_TO_UINT8 (p_result->reg_notif.event_id, p);
+            BE_STREAM_TO_UINT32 (p_result->reg_notif.param, p);
+        }
+        break;
+
+    case AVRC_PDU_SET_ABSOLUTE_VOLUME:      /* 0x50 */
+        if (len != 1)
+            status = AVRC_STS_INTERNAL_ERR;
+        else
+            p_result->volume.volume = *p++;
+        break;
+
+    case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */
+        if (len != 1) {
+            status = AVRC_STS_INTERNAL_ERR;
+        }
+        BE_STREAM_TO_UINT8(p_result->continu.target_pdu, p);
+        break;
+
+    case AVRC_PDU_ABORT_CONTINUATION_RSP:   /* 0x41 */
+        if (len != 1){
+            status = AVRC_STS_INTERNAL_ERR;
+        }
+        BE_STREAM_TO_UINT8(p_result->abort.target_pdu, p);
+        break;
+
+    case AVRC_PDU_SET_ADDRESSED_PLAYER:     /* 0x60 */
+        if (len != 2)
+        {
+            AVRC_TRACE_ERROR("AVRC_PDU_SET_ADDRESSED_PLAYER length is incorrect:%d",len);
+            status = AVRC_STS_INTERNAL_ERR;
+        }
+        BE_STREAM_TO_UINT16 (p_result->addr_player.player_id, p);
+        break;
+
+    case AVRC_PDU_PLAY_ITEM:                /* 0x74 */
+    case AVRC_PDU_ADD_TO_NOW_PLAYING:       /* 0x90 */
+        if (len != (AVRC_UID_SIZE + 3))
+            status = AVRC_STS_INTERNAL_ERR;
+        BE_STREAM_TO_UINT8 (p_result->play_item.scope, p);
+        if (p_result->play_item.scope > AVRC_SCOPE_NOW_PLAYING)
+        {
+            status = AVRC_STS_BAD_SCOPE;
+        }
+        BE_STREAM_TO_ARRAY (p, p_result->play_item.uid, AVRC_UID_SIZE);
+        BE_STREAM_TO_UINT16 (p_result->play_item.uid_counter, p);
+        break;
+
+    default:
+        status = AVRC_STS_BAD_CMD;
+        break;
+    }
+
+    return status;
+}
+
+#if (AVRC_CTRL_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function         AVRC_Ctrl_ParsCommand
+**
+** Description      This function is used to parse cmds received for CTRL
+**                  Currently it is for SetAbsVolume and Volume Change Notification..
+**
+** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+**                  Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+tAVRC_STS AVRC_Ctrl_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result)
+{
+    tAVRC_STS  status = AVRC_STS_INTERNAL_ERR;
+
+    if (p_msg && p_result)
+    {
+        switch (p_msg->hdr.opcode)
+        {
+        case AVRC_OP_VENDOR:     /*  0x00    Vendor-dependent commands */
+            status = avrc_ctrl_pars_vendor_cmd(&p_msg->vendor, p_result);
+            break;
+
+        default:
+            AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
+            break;
+        }
+        p_result->cmd.opcode = p_msg->hdr.opcode;
+        p_result->cmd.status = status;
+    }
+    AVRC_TRACE_DEBUG("%s return status:0x%x", __func__, status);
+    return status;
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         avrc_pars_browsing_cmd
+**
+** Description      This function parses the commands that go through the
+**                  browsing channel
+**
+** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+**                  Otherwise, the error code defined by AVRCP+1
+**
+*******************************************************************************/
+static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE *p_msg, tAVRC_COMMAND *p_result,
+                                                uint8_t *p_buf, uint16_t buf_len)
+{
+    tAVRC_STS  status = AVRC_STS_NO_ERROR;
+    uint8_t   *p = p_msg->p_browse_data;
+    int     count;
+
+    p_result->pdu = *p++;
+    AVRC_TRACE_DEBUG("avrc_pars_browsing_cmd() pdu:0x%x", p_result->pdu);
+    /* skip over len */
+    p += 2;
+
+    switch (p_result->pdu)
+    {
+    case AVRC_PDU_SET_BROWSED_PLAYER:   /* 0x70 */
+        // For current implementation all players are browsable.
+        BE_STREAM_TO_UINT16 (p_result->br_player.player_id, p);
+        break;
+
+    case AVRC_PDU_GET_FOLDER_ITEMS:     /* 0x71 */
+        STREAM_TO_UINT8 (p_result->get_items.scope, p);
+        // To be modified later here (Scope) when all browsing commands are supported
+        if (p_result->get_items.scope > AVRC_SCOPE_NOW_PLAYING)
+        {
+            status = AVRC_STS_BAD_SCOPE;
+        }
+        BE_STREAM_TO_UINT32 (p_result->get_items.start_item, p);
+        BE_STREAM_TO_UINT32 (p_result->get_items.end_item, p);
+        if (p_result->get_items.start_item > p_result->get_items.end_item)
+        {
+            status = AVRC_STS_BAD_RANGE;
+        }
+        STREAM_TO_UINT8 (p_result->get_items.attr_count, p);
+        p_result->get_items.p_attr_list = NULL;
+        if (p_result->get_items.attr_count && p_buf &&
+            (p_result->get_items.attr_count != AVRC_FOLDER_ITEM_COUNT_NONE))
+        {
+            p_result->get_items.p_attr_list = (uint32_t *)p_buf;
+            count = p_result->get_items.attr_count;
+            if (buf_len < (count << 2))
+                p_result->get_items.attr_count = count = (buf_len >> 2);
+            for (int idx = 0; idx < count; idx++)
+            {
+                BE_STREAM_TO_UINT32 (p_result->get_items.p_attr_list[idx], p);
+            }
+        }
+        break;
+
+    case AVRC_PDU_CHANGE_PATH:          /* 0x72 */
+        BE_STREAM_TO_UINT16 (p_result->chg_path.uid_counter, p);
+        BE_STREAM_TO_UINT8 (p_result->chg_path.direction, p);
+        if (p_result->chg_path.direction != AVRC_DIR_UP
+            && p_result->chg_path.direction != AVRC_DIR_DOWN)
+        {
+            status = AVRC_STS_BAD_DIR;
+        }
+        BE_STREAM_TO_ARRAY (p, p_result->chg_path.folder_uid, AVRC_UID_SIZE);
+        break;
+
+    case AVRC_PDU_GET_ITEM_ATTRIBUTES:  /* 0x73 */
+        BE_STREAM_TO_UINT8 (p_result->get_attrs.scope, p);
+        if (p_result->get_attrs.scope > AVRC_SCOPE_NOW_PLAYING)
+        {
+            status = AVRC_STS_BAD_SCOPE;
+            break;
+        }
+        BE_STREAM_TO_ARRAY (p, p_result->get_attrs.uid, AVRC_UID_SIZE);
+        BE_STREAM_TO_UINT16 (p_result->get_attrs.uid_counter, p);
+        BE_STREAM_TO_UINT8 (p_result->get_attrs.attr_count, p);
+        p_result->get_attrs.p_attr_list = NULL;
+        if (p_result->get_attrs.attr_count && p_buf)
+        {
+            p_result->get_attrs.p_attr_list = (uint32_t *)p_buf;
+            count = p_result->get_attrs.attr_count;
+            if (buf_len < (count << 2))
+                p_result->get_attrs.attr_count = count = (buf_len >> 2);
+            for (int idx = 0, count = 0; idx < p_result->get_attrs.attr_count; idx++)
+            {
+                BE_STREAM_TO_UINT32 (p_result->get_attrs.p_attr_list[count], p);
+                if (AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_result->get_attrs.p_attr_list[count]))
+                {
+                    count++;
+                }
+            }
+
+            if (p_result->get_attrs.attr_count != count && count == 0)
+                status = AVRC_STS_BAD_PARAM;
+            else
+                p_result->get_attrs.attr_count = count;
+        }
+        break;
+
+    case AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS:   /* 0x75 */
+        BE_STREAM_TO_UINT8 (p_result->get_num_of_items.scope, p);
+        if (p_result->get_num_of_items.scope > AVRC_SCOPE_NOW_PLAYING)
+        {
+            status = AVRC_STS_BAD_SCOPE;
+        }
+        break;
+
+    case AVRC_PDU_SEARCH:               /* 0x80 */
+        BE_STREAM_TO_UINT16 (p_result->search.string.charset_id, p);
+        BE_STREAM_TO_UINT16 (p_result->search.string.str_len, p);
+        p_result->search.string.p_str = p_buf;
+        if (p_buf)
+        {
+            if (buf_len > p_result->search.string.str_len)
+                buf_len = p_result->search.string.str_len;
+            BE_STREAM_TO_ARRAY (p, p_buf, p_result->search.string.str_len);
+        }
+        else
+        {
+            status = AVRC_STS_INTERNAL_ERR;
+        }
+        break;
+
+    default:
+        status = AVRC_STS_BAD_CMD;
+        break;
+    }
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         AVRC_ParsCommand
+**
+** Description      This function is a superset of AVRC_ParsMetadata to parse the command.
+**
+** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+**                  Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+tAVRC_STS AVRC_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result,
+                                     uint8_t *p_buf, uint16_t buf_len)
+{
+    tAVRC_STS  status = AVRC_STS_INTERNAL_ERR;
+    uint16_t  id;
+
+    if (p_msg && p_result)
+    {
+        switch (p_msg->hdr.opcode)
+        {
+        case AVRC_OP_VENDOR:     /*  0x00    Vendor-dependent commands */
+            status = avrc_pars_vendor_cmd(&p_msg->vendor, p_result, p_buf, buf_len);
+            break;
+
+        case AVRC_OP_PASS_THRU:  /*  0x7C    panel subunit opcode */
+            status = avrc_pars_pass_thru(&p_msg->pass, &id);
+            if (status == AVRC_STS_NO_ERROR)
+            {
+                p_result->pdu = (uint8_t)id;
+            }
+            break;
+
+        case AVRC_OP_BROWSE:
+            status = avrc_pars_browsing_cmd(&p_msg->browse, p_result, p_buf, buf_len);
+            break;
+
+        default:
+            AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
+            break;
+        }
+        p_result->cmd.opcode = p_msg->hdr.opcode;
+        p_result->cmd.status = status;
+    }
+    AVRC_TRACE_DEBUG("%s return status:0x%x", __func__, status);
+    return status;
+}
+
+#endif /* (AVRC_METADATA_INCLUDED == true) */
+
diff --git a/bt/stack/avrc/avrc_sdp.cc b/bt/stack/avrc/avrc_sdp.cc
new file mode 100644
index 0000000..ce2743e
--- /dev/null
+++ b/bt/stack/avrc/avrc_sdp.cc
@@ -0,0 +1,327 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2016 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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  AVRCP SDP related functions
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_common.h"
+#include "avrc_api.h"
+#include "avrc_int.h"
+
+/*****************************************************************************
+**  Global data
+*****************************************************************************/
+tAVRC_CB avrc_cb;
+
+/******************************************************************************
+**
+** Function         avrc_sdp_cback
+**
+** Description      This is the SDP callback function used by A2DP_FindService.
+**                  This function will be executed by SDP when the service
+**                  search is completed.  If the search is successful, it
+**                  finds the first record in the database that matches the
+**                  UUID of the search.  Then retrieves various parameters
+**                  from the record.  When it is finished it calls the
+**                  application callback function.
+**
+** Returns          Nothing.
+**
+******************************************************************************/
+static void avrc_sdp_cback(uint16_t status)
+{
+    AVRC_TRACE_API("%s status: %d", __func__, status);
+
+    /* reset service_uuid, so can start another find service */
+    avrc_cb.service_uuid = 0;
+
+    /* return info from sdp record in app callback function */
+    (*avrc_cb.p_cback) (status);
+
+    return;
+}
+
+/******************************************************************************
+**
+** Function         AVRC_FindService
+**
+** Description      This function is called by the application to perform service
+**                  discovery and retrieve AVRCP SDP record information from a
+**                  peer device.  Information is returned for the first service
+**                  record found on the server that matches the service UUID.
+**                  The callback function will be executed when service discovery
+**                  is complete.  There can only be one outstanding call to
+**                  AVRC_FindService() at a time; the application must wait for
+**                  the callback before it makes another call to the function.
+**                  The application is responsible for allocating memory for the
+**                  discovery database.  It is recommended that the size of the
+**                  discovery database be at least 300 bytes.  The application
+**                  can deallocate the memory after the callback function has
+**                  executed.
+**
+**                  Input Parameters:
+**                      service_uuid: Indicates TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET)
+**                                           or CT(UUID_SERVCLASS_AV_REMOTE_CONTROL)
+**
+**                      bd_addr:  BD address of the peer device.
+**
+**                      p_db:  SDP discovery database parameters.
+**
+**                      p_cback:  Pointer to the callback function.
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_PARAMS if discovery database parameters are invalid.
+**                  AVRC_NO_RESOURCES if there are not enough resources to
+**                                    perform the service search.
+**
+******************************************************************************/
+uint16_t AVRC_FindService(uint16_t service_uuid, BD_ADDR bd_addr,
+                tAVRC_SDP_DB_PARAMS *p_db, tAVRC_FIND_CBACK *p_cback)
+{
+    tSDP_UUID   uuid_list;
+    bool        result = true;
+    uint16_t    a2dp_attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST, /* update AVRC_NUM_ATTR, if changed */
+                                   ATTR_ID_PROTOCOL_DESC_LIST,
+                                   ATTR_ID_BT_PROFILE_DESC_LIST,
+                                   ATTR_ID_SERVICE_NAME,
+                                   ATTR_ID_SUPPORTED_FEATURES,
+                                   ATTR_ID_PROVIDER_NAME};
+
+    AVRC_TRACE_API("%s uuid: %x", __func__, service_uuid);
+    if( (service_uuid != UUID_SERVCLASS_AV_REM_CTRL_TARGET && service_uuid != UUID_SERVCLASS_AV_REMOTE_CONTROL) ||
+        p_db == NULL || p_db->p_db == NULL || p_cback == NULL)
+        return AVRC_BAD_PARAM;
+
+    /* check if it is busy */
+    if( avrc_cb.service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET ||
+        avrc_cb.service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL)
+        return AVRC_NO_RESOURCES;
+
+    /* set up discovery database */
+    uuid_list.len = LEN_UUID_16;
+    uuid_list.uu.uuid16 = service_uuid;
+
+    if(p_db->p_attrs == NULL || p_db->num_attr == 0)
+    {
+        p_db->p_attrs  = a2dp_attr_list;
+        p_db->num_attr = AVRC_NUM_ATTR;
+    }
+
+    result = SDP_InitDiscoveryDb(p_db->p_db, p_db->db_len, 1, &uuid_list, p_db->num_attr,
+                                 p_db->p_attrs);
+
+    if (result == true)
+    {
+        /* store service_uuid and discovery db pointer */
+        avrc_cb.p_db = p_db->p_db;
+        avrc_cb.service_uuid = service_uuid;
+        avrc_cb.p_cback = p_cback;
+
+        /* perform service search */
+        result = SDP_ServiceSearchAttributeRequest(bd_addr, p_db->p_db, avrc_sdp_cback);
+    }
+
+    return (result ? AVRC_SUCCESS : AVRC_FAIL);
+}
+
+/******************************************************************************
+**
+** Function         AVRC_AddRecord
+**
+** Description      This function is called to build an AVRCP SDP record.
+**                  Prior to calling this function the application must
+**                  call SDP_CreateRecord() to create an SDP record.
+**
+**                  Input Parameters:
+**                      service_uuid:  Indicates TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET)
+**                                            or CT(UUID_SERVCLASS_AV_REMOTE_CONTROL)
+**
+**                      p_service_name:  Pointer to a null-terminated character
+**                      string containing the service name.
+**                      If service name is not used set this to NULL.
+**
+**                      p_provider_name:  Pointer to a null-terminated character
+**                      string containing the provider name.
+**                      If provider name is not used set this to NULL.
+**
+**                      categories:  Supported categories.
+**
+**                      sdp_handle:  SDP handle returned by SDP_CreateRecord().
+**
+**                      browse_supported:  browse support info.
+**
+**                      profile_version:  profile version of avrcp record.
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_NO_RESOURCES if not enough resources to build the SDP record.
+**
+******************************************************************************/
+uint16_t AVRC_AddRecord(uint16_t service_uuid, const char *p_service_name,
+                        const char *p_provider_name, uint16_t categories,
+                        uint32_t sdp_handle, bool browse_supported,
+                        uint16_t profile_version)
+{
+    uint16_t    browse_list[1];
+    bool        result = true;
+    uint8_t     temp[8];
+    uint8_t     *p;
+    uint16_t    count = 1;
+    uint8_t     index = 0;
+    uint16_t    class_list[2];
+
+
+    AVRC_TRACE_API("%s uuid: %x", __func__, service_uuid);
+
+    if( service_uuid != UUID_SERVCLASS_AV_REM_CTRL_TARGET && service_uuid != UUID_SERVCLASS_AV_REMOTE_CONTROL )
+        return AVRC_BAD_PARAM;
+
+    /* add service class id list */
+    class_list[0] = service_uuid;
+    if((service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL ) && (profile_version > AVRC_REV_1_3))
+    {
+        class_list[1] = UUID_SERVCLASS_AV_REM_CTRL_CONTROL;
+        count = 2;
+    }
+    result &= SDP_AddServiceClassIdList(sdp_handle, count, class_list);
+
+    /* add protocol descriptor list   */
+    tSDP_PROTOCOL_ELEM  avrc_proto_desc_list [AVRC_NUM_PROTO_ELEMS];
+    avrc_proto_desc_list[0].num_params = 1;
+    avrc_proto_desc_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+    avrc_proto_desc_list[0].params[0] = AVCT_PSM;
+    avrc_proto_desc_list[0].params[1] = 0;
+    for (index = 1; index < AVRC_NUM_PROTO_ELEMS; index++)
+    {
+        avrc_proto_desc_list[index].num_params = 1;
+        avrc_proto_desc_list[index].protocol_uuid = UUID_PROTOCOL_AVCTP;
+        avrc_proto_desc_list[index].params[0] = AVCT_REV_1_4;
+        avrc_proto_desc_list[index].params[1] = 0;
+    }
+    result &= SDP_AddProtocolList(sdp_handle, AVRC_NUM_PROTO_ELEMS,
+                                                  (tSDP_PROTOCOL_ELEM *)avrc_proto_desc_list);
+
+    /* additional protocal descriptor, required only for version > 1.3    */
+    if ((profile_version > AVRC_REV_1_3) && (browse_supported))
+    {
+        tSDP_PROTO_LIST_ELEM  avrc_add_proto_desc_list;
+        avrc_add_proto_desc_list.num_elems = 2;
+        avrc_add_proto_desc_list.list_elem[0].num_params = 1;
+        avrc_add_proto_desc_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+        avrc_add_proto_desc_list.list_elem[0].params[0] = AVCT_BR_PSM;
+        avrc_add_proto_desc_list.list_elem[0].params[1] = 0;
+        avrc_add_proto_desc_list.list_elem[1].num_params = 1;
+        avrc_add_proto_desc_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_AVCTP;
+        avrc_add_proto_desc_list.list_elem[1].params[0] = AVCT_REV_1_4;
+        avrc_add_proto_desc_list.list_elem[1].params[1] = 0;
+
+        result &= SDP_AddAdditionProtoLists( sdp_handle, 1, (tSDP_PROTO_LIST_ELEM *)&avrc_add_proto_desc_list);
+    }
+    /* add profile descriptor list   */
+    result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, profile_version);
+
+    /* add supported categories */
+    p = temp;
+    UINT16_TO_BE_STREAM(p, categories);
+    result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE,
+              (uint32_t)2, (uint8_t*)temp);
+
+    /* add provider name */
+    if (p_provider_name != NULL)
+    {
+        result &= SDP_AddAttribute(sdp_handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE,
+                    (uint32_t)(strlen(p_provider_name)+1), (uint8_t *) p_provider_name);
+    }
+
+    /* add service name */
+    if (p_service_name != NULL)
+    {
+        result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+                    (uint32_t)(strlen(p_service_name)+1), (uint8_t *) p_service_name);
+    }
+
+    /* add browse group list */
+    browse_list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+    result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list);
+
+
+    return (result ? AVRC_SUCCESS : AVRC_FAIL);
+}
+
+
+
+/******************************************************************************
+**
+** Function         AVRC_SetTraceLevel
+**
+** Description      Sets the trace level for AVRC. If 0xff is passed, the
+**                  current trace level is returned.
+**
+**                  Input Parameters:
+**                      new_level:  The level to set the AVRC tracing to:
+**                      0xff-returns the current setting.
+**                      0-turns off tracing.
+**                      >= 1-Errors.
+**                      >= 2-Warnings.
+**                      >= 3-APIs.
+**                      >= 4-Events.
+**                      >= 5-Debug.
+**
+** Returns          The new trace level or current trace level if
+**                  the input parameter is 0xff.
+**
+******************************************************************************/
+uint8_t AVRC_SetTraceLevel (uint8_t new_level)
+{
+    if (new_level != 0xFF)
+        avrc_cb.trace_level = new_level;
+
+    return (avrc_cb.trace_level);
+}
+
+/*******************************************************************************
+**
+** Function         AVRC_Init
+**
+** Description      This function is called at stack startup to allocate the
+**                  control block (if using dynamic memory), and initializes the
+**                  control block and tracing level.
+**
+** Returns          void
+**
+*******************************************************************************/
+void AVRC_Init(void)
+{
+    memset(&avrc_cb, 0, sizeof(tAVRC_CB));
+
+#if defined(AVRC_INITIAL_TRACE_LEVEL)
+    avrc_cb.trace_level  = AVRC_INITIAL_TRACE_LEVEL;
+#else
+    avrc_cb.trace_level  = BT_TRACE_LEVEL_NONE;
+#endif
+}
+
diff --git a/bt/stack/avrc/avrc_utils.cc b/bt/stack/avrc/avrc_utils.cc
new file mode 100644
index 0000000..d0c203f
--- /dev/null
+++ b/bt/stack/avrc/avrc_utils.cc
@@ -0,0 +1,261 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2016 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.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_common.h"
+#include "avrc_api.h"
+#include "avrc_int.h"
+
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+
+/**************************************************************************
+**
+** Function         AVRC_IsValidAvcType
+**
+** Description      Check if correct AVC type is specified
+**
+** Returns          returns true if it is valid
+**
+**
+*******************************************************************************/
+bool AVRC_IsValidAvcType(uint8_t pdu_id, uint8_t avc_type)
+{
+    bool result=false;
+
+    if (avc_type < AVRC_RSP_NOT_IMPL) /* command msg */
+    {
+        switch (pdu_id)
+        {
+        case AVRC_PDU_GET_CAPABILITIES:            /* 0x10 */
+        case AVRC_PDU_LIST_PLAYER_APP_ATTR:        /* 0x11 */
+        case AVRC_PDU_LIST_PLAYER_APP_VALUES:      /* 0x12 */
+        case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:    /* 0x13 */
+        case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:    /* 0x15 */
+        case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:   /* 0x16 */
+        case AVRC_PDU_GET_ELEMENT_ATTR:            /* 0x20 */
+        case AVRC_PDU_GET_PLAY_STATUS:             /* 0x30 */
+             if (avc_type == AVRC_CMD_STATUS)
+                result=true;
+             break;
+
+        case AVRC_PDU_SET_PLAYER_APP_VALUE:        /* 0x14 */
+        case AVRC_PDU_INFORM_DISPLAY_CHARSET:      /* 0x17 */
+        case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT:   /* 0x18 */
+        case AVRC_PDU_REQUEST_CONTINUATION_RSP:    /* 0x40 */
+        case AVRC_PDU_ABORT_CONTINUATION_RSP:      /* 0x41 */
+             if (avc_type == AVRC_CMD_CTRL)
+                result=true;
+             break;
+
+        case AVRC_PDU_GET_FOLDER_ITEMS:            /* 0x71 */
+            result = true;
+            break;
+
+        case AVRC_PDU_SET_ABSOLUTE_VOLUME:         /* 0x50 */
+        case AVRC_PDU_SET_ADDRESSED_PLAYER:        /* 0x60 */
+        case AVRC_PDU_PLAY_ITEM:                   /* 0x74 */
+        case AVRC_PDU_ADD_TO_NOW_PLAYING:          /* 0x90 */
+             if (avc_type == AVRC_CMD_CTRL)
+                result=true;
+             break;
+
+        case AVRC_PDU_REGISTER_NOTIFICATION:       /* 0x31 */
+             if (avc_type == AVRC_CMD_NOTIF)
+                result=true;
+             break;
+        }
+    }
+    else  /* response msg */
+    {
+        if (avc_type >= AVRC_RSP_NOT_IMPL  &&
+           avc_type <= AVRC_RSP_INTERIM    )
+           result=true;
+    }
+
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_is_valid_player_attrib_value
+**
+** Description      Check if the given attrib value is valid for its attribute
+**
+** Returns          returns true if it is valid
+**
+*******************************************************************************/
+bool    avrc_is_valid_player_attrib_value(uint8_t attrib, uint8_t value)
+{
+    bool    result=false;
+
+    switch(attrib)
+    {
+    case AVRC_PLAYER_SETTING_EQUALIZER:
+         if ((value > 0)  &&
+            (value <= AVRC_PLAYER_VAL_ON))
+            result=true;
+         break;
+
+    case AVRC_PLAYER_SETTING_REPEAT:
+         if ((value > 0)  &&
+            (value <= AVRC_PLAYER_VAL_GROUP_REPEAT))
+            result=true;
+         break;
+
+    case AVRC_PLAYER_SETTING_SHUFFLE:
+    case AVRC_PLAYER_SETTING_SCAN:
+         if ((value > 0)  &&
+            (value <= AVRC_PLAYER_VAL_GROUP_SHUFFLE))
+            result=true;
+         break;
+    }
+
+    if (attrib >= AVRC_PLAYER_SETTING_LOW_MENU_EXT)
+       result = true;
+
+    if (!result)
+    {
+        AVRC_TRACE_ERROR(" %s found not matching attrib(x%x)-value(x%x) pair!",
+                          __FUNCTION__, attrib, value);
+    }
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         AVRC_IsValidPlayerAttr
+**
+** Description      Check if the given attrib value is a valid one
+**
+** Returns          returns true if it is valid
+**
+*******************************************************************************/
+bool    AVRC_IsValidPlayerAttr(uint8_t attr)
+{
+    bool    result=false;
+
+    if ( (attr >= AVRC_PLAYER_SETTING_EQUALIZER && attr <= AVRC_PLAYER_SETTING_SCAN) ||
+         (attr >= AVRC_PLAYER_SETTING_LOW_MENU_EXT) )
+    {
+       result = true;
+    }
+
+    return result;
+}
+
+
+
+/*******************************************************************************
+**
+** Function         avrc_pars_pass_thru
+**
+** Description      This function parses the pass thru commands defined by
+**                  Bluetooth SIG
+**
+** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+**                  Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+tAVRC_STS avrc_pars_pass_thru(tAVRC_MSG_PASS *p_msg, uint16_t *p_vendor_unique_id)
+{
+    uint8_t    *p_data;
+    uint32_t    co_id;
+    uint16_t    id;
+    tAVRC_STS  status = AVRC_STS_BAD_CMD;
+
+    if (p_msg->op_id == AVRC_ID_VENDOR && p_msg->pass_len == AVRC_PASS_THRU_GROUP_LEN)
+    {
+        p_data = p_msg->p_pass_data;
+        AVRC_BE_STREAM_TO_CO_ID (co_id, p_data);
+        if (co_id == AVRC_CO_METADATA)
+        {
+            BE_STREAM_TO_UINT16 (id, p_data);
+            if (AVRC_IS_VALID_GROUP(id))
+            {
+                *p_vendor_unique_id = id;
+                status = AVRC_STS_NO_ERROR;
+            }
+        }
+    }
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_opcode_from_pdu
+**
+** Description      This function returns the opcode of the given pdu
+**
+** Returns          AVRC_OP_VENDOR, AVRC_OP_PASS_THRU or AVRC_OP_BROWSE
+**
+*******************************************************************************/
+uint8_t avrc_opcode_from_pdu(uint8_t pdu)
+{
+    uint8_t opcode = 0;
+
+    switch (pdu)
+    {
+    case AVRC_PDU_SET_BROWSED_PLAYER:
+    case AVRC_PDU_GET_FOLDER_ITEMS:
+    case AVRC_PDU_CHANGE_PATH:
+    case AVRC_PDU_GET_ITEM_ATTRIBUTES:
+    case AVRC_PDU_SEARCH:
+    case AVRC_PDU_GENERAL_REJECT:
+    case AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS:
+        opcode  = AVRC_OP_BROWSE;
+        break;
+
+    case AVRC_PDU_NEXT_GROUP:
+    case AVRC_PDU_PREV_GROUP: /* pass thru */
+        opcode  = AVRC_OP_PASS_THRU;
+        break;
+
+    default: /* vendor */
+        opcode  = AVRC_OP_VENDOR;
+        break;
+    }
+
+    return opcode;
+}
+
+/*******************************************************************************
+**
+** Function         avrc_is_valid_opcode
+**
+** Description      This function returns the opcode of the given pdu
+**
+** Returns          AVRC_OP_VENDOR, AVRC_OP_PASS_THRU or AVRC_OP_BROWSE
+**
+*******************************************************************************/
+bool    avrc_is_valid_opcode(uint8_t opcode)
+{
+    bool    is_valid = false;
+    switch (opcode)
+    {
+    case AVRC_OP_BROWSE:
+    case AVRC_OP_PASS_THRU:
+    case AVRC_OP_VENDOR:
+        is_valid = true;
+        break;
+    }
+    return is_valid;
+}
+
+#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
+
diff --git a/bt/stack/bnep/bnep_api.cc b/bt/stack/bnep/bnep_api.cc
new file mode 100644
index 0000000..a54ab1e
--- /dev/null
+++ b/bt/stack/bnep/bnep_api.cc
@@ -0,0 +1,744 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2001-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 BNEP API code
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bnep_api.h"
+#include "bnep_int.h"
+
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+/*******************************************************************************
+**
+** Function         BNEP_Init
+**
+** Description      This function initializes the BNEP unit. It should be called
+**                  before accessing any other APIs to initialize the control block
+**
+** Returns          void
+**
+*******************************************************************************/
+void BNEP_Init (void)
+{
+    memset (&bnep_cb, 0, sizeof (tBNEP_CB));
+
+#if defined(BNEP_INITIAL_TRACE_LEVEL)
+    bnep_cb.trace_level = BNEP_INITIAL_TRACE_LEVEL;
+#else
+    bnep_cb.trace_level = BT_TRACE_LEVEL_NONE;    /* No traces */
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function         BNEP_Register
+**
+** Description      This function is called by the upper layer to register
+**                  its callbacks with BNEP
+**
+** Parameters:      p_reg_info - contains all callback function pointers
+**
+**
+** Returns          BNEP_SUCCESS        if registered successfully
+**                  BNEP_FAILURE        if connection state callback is missing
+**
+*******************************************************************************/
+tBNEP_RESULT BNEP_Register (tBNEP_REGISTER *p_reg_info)
+{
+    /* There should be connection state call back registered */
+    if ((!p_reg_info) || (!(p_reg_info->p_conn_state_cb)))
+        return BNEP_SECURITY_FAIL;
+
+    bnep_cb.p_conn_ind_cb       = p_reg_info->p_conn_ind_cb;
+    bnep_cb.p_conn_state_cb     = p_reg_info->p_conn_state_cb;
+    bnep_cb.p_data_ind_cb       = p_reg_info->p_data_ind_cb;
+    bnep_cb.p_data_buf_cb       = p_reg_info->p_data_buf_cb;
+    bnep_cb.p_filter_ind_cb     = p_reg_info->p_filter_ind_cb;
+    bnep_cb.p_mfilter_ind_cb    = p_reg_info->p_mfilter_ind_cb;
+    bnep_cb.p_tx_data_flow_cb   = p_reg_info->p_tx_data_flow_cb;
+
+    if (bnep_register_with_l2cap ())
+        return BNEP_SECURITY_FAIL;
+
+    bnep_cb.profile_registered  = true;
+    return BNEP_SUCCESS;
+}
+
+
+/*******************************************************************************
+**
+** Function         BNEP_Deregister
+**
+** Description      This function is called by the upper layer to de-register
+**                  its callbacks.
+**
+** Parameters:      void
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void BNEP_Deregister (void)
+{
+    /* Clear all the call backs registered */
+    bnep_cb.p_conn_ind_cb       = NULL;
+    bnep_cb.p_conn_state_cb     = NULL;
+    bnep_cb.p_data_ind_cb       = NULL;
+    bnep_cb.p_data_buf_cb       = NULL;
+    bnep_cb.p_filter_ind_cb     = NULL;
+    bnep_cb.p_mfilter_ind_cb    = NULL;
+
+    bnep_cb.profile_registered  = false;
+    L2CA_Deregister (BT_PSM_BNEP);
+}
+
+
+/*******************************************************************************
+**
+** Function         BNEP_Connect
+**
+** Description      This function creates a BNEP connection to a remote
+**                  device.
+**
+** Parameters:      p_rem_addr  - BD_ADDR of the peer
+**                  src_uuid    - source uuid for the connection
+**                  dst_uuid    - destination uuid for the connection
+**                  p_handle    - pointer to return the handle for the connection
+**
+** Returns          BNEP_SUCCESS                if connection started
+**                  BNEP_NO_RESOURCES           if no resources
+**
+*******************************************************************************/
+tBNEP_RESULT BNEP_Connect (BD_ADDR p_rem_bda,
+                           tBT_UUID *src_uuid,
+                           tBT_UUID *dst_uuid,
+                           uint16_t *p_handle)
+{
+    uint16_t        cid;
+    tBNEP_CONN      *p_bcb = bnepu_find_bcb_by_bd_addr (p_rem_bda);
+
+    BNEP_TRACE_API ("BNEP_Connect()  BDA: %02x-%02x-%02x-%02x-%02x-%02x",
+                     p_rem_bda[0], p_rem_bda[1], p_rem_bda[2],
+                     p_rem_bda[3], p_rem_bda[4], p_rem_bda[5]);
+
+    if (!bnep_cb.profile_registered)
+        return BNEP_WRONG_STATE;
+
+    /* Both source and destination UUID lengths should be same */
+    if (src_uuid->len != dst_uuid->len)
+        return BNEP_CONN_FAILED_UUID_SIZE;
+
+    if (!p_bcb)
+    {
+        if ((p_bcb = bnepu_allocate_bcb (p_rem_bda)) == NULL)
+            return (BNEP_NO_RESOURCES);
+    }
+    else if (p_bcb->con_state != BNEP_STATE_CONNECTED)
+            return BNEP_WRONG_STATE;
+    else
+    {
+        /* Backup current UUID values to restore if role change fails */
+        memcpy ((uint8_t *)&(p_bcb->prv_src_uuid), (uint8_t *)&(p_bcb->src_uuid), sizeof (tBT_UUID));
+        memcpy ((uint8_t *)&(p_bcb->prv_dst_uuid), (uint8_t *)&(p_bcb->dst_uuid), sizeof (tBT_UUID));
+    }
+
+    /* We are the originator of this connection */
+    p_bcb->con_flags |= BNEP_FLAGS_IS_ORIG;
+
+    memcpy ((uint8_t *)&(p_bcb->src_uuid), (uint8_t *)src_uuid, sizeof (tBT_UUID));
+    memcpy ((uint8_t *)&(p_bcb->dst_uuid), (uint8_t *)dst_uuid, sizeof (tBT_UUID));
+
+    if (p_bcb->con_state == BNEP_STATE_CONNECTED)
+    {
+        /* Transition to the next appropriate state, waiting for connection confirm. */
+        p_bcb->con_state = BNEP_STATE_SEC_CHECKING;
+
+        BNEP_TRACE_API ("BNEP initiating security procedures for src uuid 0x%x",
+            p_bcb->src_uuid.uu.uuid16);
+
+#if (BNEP_DO_AUTH_FOR_ROLE_SWITCH == TRUE)
+        btm_sec_mx_access_request (p_bcb->rem_bda, BT_PSM_BNEP, true,
+                                   BTM_SEC_PROTO_BNEP,
+                                   bnep_get_uuid32(src_uuid),
+                                   &bnep_sec_check_complete, p_bcb);
+#else
+        bnep_sec_check_complete (p_bcb->rem_bda, p_bcb, BTM_SUCCESS);
+#endif
+
+    }
+    else
+    {
+        /* Transition to the next appropriate state, waiting for connection confirm. */
+        p_bcb->con_state = BNEP_STATE_CONN_START;
+
+        if ((cid = L2CA_ConnectReq (BT_PSM_BNEP, p_bcb->rem_bda)) != 0)
+        {
+            p_bcb->l2cap_cid = cid;
+
+        }
+        else
+        {
+            BNEP_TRACE_ERROR ("BNEP - Originate failed");
+            if (bnep_cb.p_conn_state_cb)
+                (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED, false);
+            bnepu_release_bcb (p_bcb);
+            return BNEP_CONN_FAILED;
+        }
+
+        /* Start timer waiting for connect */
+        alarm_set_on_queue(p_bcb->conn_timer, BNEP_CONN_TIMEOUT_MS,
+                           bnep_conn_timer_timeout, p_bcb,
+                           btu_general_alarm_queue);
+    }
+
+    *p_handle = p_bcb->handle;
+    return (BNEP_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function         BNEP_ConnectResp
+**
+** Description      This function is called in responce to connection indication
+**
+**
+** Parameters:      handle  - handle given in the connection indication
+**                  resp    - responce for the connection indication
+**
+** Returns          BNEP_SUCCESS                if connection started
+**                  BNEP_WRONG_HANDLE           if the connection is not found
+**                  BNEP_WRONG_STATE            if the responce is not expected
+**
+*******************************************************************************/
+tBNEP_RESULT BNEP_ConnectResp (uint16_t handle, tBNEP_RESULT resp)
+{
+    tBNEP_CONN      *p_bcb;
+    uint16_t        resp_code = BNEP_SETUP_CONN_OK;
+
+    if ((!handle) || (handle > BNEP_MAX_CONNECTIONS))
+        return (BNEP_WRONG_HANDLE);
+
+    p_bcb = &(bnep_cb.bcb[handle - 1]);
+
+    if (p_bcb->con_state != BNEP_STATE_CONN_SETUP ||
+        (!(p_bcb->con_flags & BNEP_FLAGS_SETUP_RCVD)))
+        return (BNEP_WRONG_STATE);
+
+    BNEP_TRACE_API ("BNEP_ConnectResp()  for handle %d, responce %d", handle, resp);
+
+    /* Form appropriate responce based on profile responce */
+    if      (resp == BNEP_CONN_FAILED_SRC_UUID)   resp_code = BNEP_SETUP_INVALID_SRC_UUID;
+    else if (resp == BNEP_CONN_FAILED_DST_UUID)   resp_code = BNEP_SETUP_INVALID_DEST_UUID;
+    else if (resp == BNEP_CONN_FAILED_UUID_SIZE)  resp_code = BNEP_SETUP_INVALID_UUID_SIZE;
+    else if (resp == BNEP_SUCCESS)                resp_code = BNEP_SETUP_CONN_OK;
+    else                                          resp_code = BNEP_SETUP_CONN_NOT_ALLOWED;
+
+    bnep_send_conn_responce (p_bcb, resp_code);
+    p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD);
+
+    if (resp == BNEP_SUCCESS)
+        bnep_connected (p_bcb);
+    else if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)
+    {
+        /* Restore the original parameters */
+        p_bcb->con_state = BNEP_STATE_CONNECTED;
+        p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD);
+
+        memcpy ((uint8_t *)&(p_bcb->src_uuid), (uint8_t *)&(p_bcb->prv_src_uuid), sizeof (tBT_UUID));
+        memcpy ((uint8_t *)&(p_bcb->dst_uuid), (uint8_t *)&(p_bcb->prv_dst_uuid), sizeof (tBT_UUID));
+    }
+
+    /* Process remaining part of the setup message (extension headers) */
+    if (p_bcb->p_pending_data)
+    {
+        uint8_t extension_present = true, *p, ext_type;
+        uint16_t rem_len;
+
+        rem_len = p_bcb->p_pending_data->len;
+        p       = (uint8_t *)(p_bcb->p_pending_data + 1) + p_bcb->p_pending_data->offset;
+        while (extension_present && p && rem_len)
+        {
+            ext_type = *p++;
+            extension_present = ext_type >> 7;
+            ext_type &= 0x7F;
+
+            /* if unknown extension present stop processing */
+            if (ext_type)
+                break;
+
+            p = bnep_process_control_packet (p_bcb, p, &rem_len, true);
+        }
+
+        osi_free_and_reset((void **)&p_bcb->p_pending_data);
+    }
+    return (BNEP_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function         BNEP_Disconnect
+**
+** Description      This function is called to close the specified connection.
+**
+** Parameters:      handle   - handle of the connection
+**
+** Returns          BNEP_SUCCESS                if connection is disconnected
+**                  BNEP_WRONG_HANDLE           if no connection is not found
+**
+*******************************************************************************/
+tBNEP_RESULT BNEP_Disconnect (uint16_t handle)
+{
+    tBNEP_CONN      *p_bcb;
+
+    if ((!handle) || (handle > BNEP_MAX_CONNECTIONS))
+        return (BNEP_WRONG_HANDLE);
+
+    p_bcb = &(bnep_cb.bcb[handle - 1]);
+
+    if (p_bcb->con_state == BNEP_STATE_IDLE)
+        return (BNEP_WRONG_HANDLE);
+
+    BNEP_TRACE_API ("BNEP_Disconnect()  for handle %d", handle);
+
+    L2CA_DisconnectReq (p_bcb->l2cap_cid);
+
+    bnepu_release_bcb (p_bcb);
+
+    return (BNEP_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function         BNEP_WriteBuf
+**
+** Description      This function sends data in a GKI buffer on BNEP connection
+**
+** Parameters:      handle       - handle of the connection to write
+**                  p_dest_addr  - BD_ADDR/Ethernet addr of the destination
+**                  p_buf        - pointer to address of buffer with data
+**                  protocol     - protocol type of the packet
+**                  p_src_addr   - (optional) BD_ADDR/ethernet address of the source
+**                                 (should be NULL if it is local BD Addr)
+**                  fw_ext_present - forwarded extensions present
+**
+** Returns:         BNEP_WRONG_HANDLE       - if passed handle is not valid
+**                  BNEP_MTU_EXCEDED        - If the data length is greater than MTU
+**                  BNEP_IGNORE_CMD         - If the packet is filtered out
+**                  BNEP_Q_SIZE_EXCEEDED    - If the Tx Q is full
+**                  BNEP_SUCCESS            - If written successfully
+**
+*******************************************************************************/
+tBNEP_RESULT BNEP_WriteBuf (uint16_t handle,
+                            uint8_t *p_dest_addr,
+                            BT_HDR *p_buf,
+                            uint16_t protocol,
+                            uint8_t *p_src_addr,
+                            bool    fw_ext_present)
+{
+    tBNEP_CONN      *p_bcb;
+    uint8_t         *p_data;
+
+    if ((!handle) || (handle > BNEP_MAX_CONNECTIONS))
+    {
+        osi_free(p_buf);
+        return (BNEP_WRONG_HANDLE);
+    }
+
+    p_bcb = &(bnep_cb.bcb[handle - 1]);
+    /* Check MTU size */
+    if (p_buf->len > BNEP_MTU_SIZE)
+    {
+        BNEP_TRACE_ERROR ("BNEP_Write() length %d exceeded MTU %d", p_buf->len, BNEP_MTU_SIZE);
+        osi_free(p_buf);
+        return (BNEP_MTU_EXCEDED);
+    }
+
+    /* Check if the packet should be filtered out */
+    p_data = (uint8_t *)(p_buf + 1) + p_buf->offset;
+    if (bnep_is_packet_allowed (p_bcb, p_dest_addr, protocol, fw_ext_present, p_data) != BNEP_SUCCESS)
+    {
+        /*
+        ** If packet is filtered and ext headers are present
+        ** drop the data and forward the ext headers
+        */
+        if (fw_ext_present)
+        {
+            uint8_t     ext, length;
+            uint16_t    org_len, new_len;
+            /* parse the extension headers and findout the new packet len */
+            org_len = p_buf->len;
+            new_len = 0;
+            do {
+
+                ext     = *p_data++;
+                length  = *p_data++;
+                p_data += length;
+
+                new_len += (length + 2);
+
+                if (new_len > org_len)
+                {
+                    osi_free(p_buf);
+                    return BNEP_IGNORE_CMD;
+                }
+
+            } while (ext & 0x80);
+
+            if (protocol != BNEP_802_1_P_PROTOCOL)
+                protocol = 0;
+            else
+            {
+                new_len += 4;
+                p_data[2] = 0;
+                p_data[3] = 0;
+            }
+            p_buf->len  = new_len;
+        }
+        else
+        {
+            osi_free(p_buf);
+            return BNEP_IGNORE_CMD;
+        }
+    }
+
+    /* Check transmit queue */
+    if (fixed_queue_length(p_bcb->xmit_q) >= BNEP_MAX_XMITQ_DEPTH)
+    {
+        osi_free(p_buf);
+        return (BNEP_Q_SIZE_EXCEEDED);
+    }
+
+    /* Build the BNEP header */
+    bnepu_build_bnep_hdr (p_bcb, p_buf, protocol, p_src_addr, p_dest_addr, fw_ext_present);
+
+    /* Send the data or queue it up */
+    bnepu_check_send_packet (p_bcb, p_buf);
+
+    return (BNEP_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function         BNEP_Write
+**
+** Description      This function sends data over a BNEP connection
+**
+** Parameters:      handle       - handle of the connection to write
+**                  p_dest_addr  - BD_ADDR/Ethernet addr of the destination
+**                  p_data       - pointer to data start
+**                  protocol     - protocol type of the packet
+**                  p_src_addr   - (optional) BD_ADDR/ethernet address of the source
+**                                 (should be NULL if it is local BD Addr)
+**                  fw_ext_present - forwarded extensions present
+**
+** Returns:         BNEP_WRONG_HANDLE       - if passed handle is not valid
+**                  BNEP_MTU_EXCEDED        - If the data length is greater than MTU
+**                  BNEP_IGNORE_CMD         - If the packet is filtered out
+**                  BNEP_Q_SIZE_EXCEEDED    - If the Tx Q is full
+**                  BNEP_NO_RESOURCES       - If not able to allocate a buffer
+**                  BNEP_SUCCESS            - If written successfully
+**
+*******************************************************************************/
+tBNEP_RESULT  BNEP_Write (uint16_t handle,
+                          uint8_t *p_dest_addr,
+                          uint8_t *p_data,
+                          uint16_t len,
+                          uint16_t protocol,
+                          uint8_t *p_src_addr,
+                          bool    fw_ext_present)
+{
+    tBNEP_CONN   *p_bcb;
+    uint8_t      *p;
+
+    /* Check MTU size. Consider the possibility of having extension headers */
+    if (len > BNEP_MTU_SIZE)
+    {
+        BNEP_TRACE_ERROR ("BNEP_Write() length %d exceeded MTU %d", len, BNEP_MTU_SIZE);
+        return (BNEP_MTU_EXCEDED);
+    }
+
+    if ((!handle) || (handle > BNEP_MAX_CONNECTIONS))
+        return (BNEP_WRONG_HANDLE);
+
+    p_bcb = &(bnep_cb.bcb[handle - 1]);
+
+    /* Check if the packet should be filtered out */
+    if (bnep_is_packet_allowed (p_bcb, p_dest_addr, protocol, fw_ext_present, p_data) != BNEP_SUCCESS)
+    {
+        /*
+        ** If packet is filtered and ext headers are present
+        ** drop the data and forward the ext headers
+        */
+        if (fw_ext_present)
+        {
+            uint8_t     ext, length;
+            uint16_t    org_len, new_len;
+            /* parse the extension headers and findout the new packet len */
+            org_len = len;
+            new_len = 0;
+            p       = p_data;
+            do {
+
+                ext     = *p_data++;
+                length  = *p_data++;
+                p_data += length;
+
+                new_len += (length + 2);
+
+                if (new_len > org_len)
+                    return BNEP_IGNORE_CMD;
+
+            } while (ext & 0x80);
+
+            if (protocol != BNEP_802_1_P_PROTOCOL)
+                protocol = 0;
+            else
+            {
+                new_len += 4;
+                p_data[2] = 0;
+                p_data[3] = 0;
+            }
+            len         = new_len;
+            p_data      = p;
+        }
+        else
+            return BNEP_IGNORE_CMD;
+    }
+
+    /* Check transmit queue */
+    if (fixed_queue_length(p_bcb->xmit_q) >= BNEP_MAX_XMITQ_DEPTH)
+        return (BNEP_Q_SIZE_EXCEEDED);
+
+    /* Get a buffer to copy the data into */
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(BNEP_BUF_SIZE);
+
+    p_buf->len = len;
+    p_buf->offset = BNEP_MINIMUM_OFFSET;
+    p = (uint8_t *)(p_buf + 1) + BNEP_MINIMUM_OFFSET;
+
+    memcpy (p, p_data, len);
+
+    /* Build the BNEP header */
+    bnepu_build_bnep_hdr (p_bcb, p_buf, protocol, p_src_addr, p_dest_addr, fw_ext_present);
+
+    /* Send the data or queue it up */
+    bnepu_check_send_packet (p_bcb, p_buf);
+
+    return (BNEP_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function         BNEP_SetProtocolFilters
+**
+** Description      This function sets the protocol filters on peer device
+**
+** Parameters:      handle        - Handle for the connection
+**                  num_filters   - total number of filter ranges
+**                  p_start_array - Array of beginings of all protocol ranges
+**                  p_end_array   - Array of ends of all protocol ranges
+**
+** Returns          BNEP_WRONG_HANDLE           - if the connection handle is not valid
+**                  BNEP_SET_FILTER_FAIL        - if the connection is in wrong state
+**                  BNEP_TOO_MANY_FILTERS       - if too many filters
+**                  BNEP_SUCCESS                - if request sent successfully
+**
+*******************************************************************************/
+tBNEP_RESULT BNEP_SetProtocolFilters (uint16_t handle,
+                                      uint16_t num_filters,
+                                      uint16_t *p_start_array,
+                                      uint16_t *p_end_array)
+{
+    uint16_t        xx;
+    tBNEP_CONN     *p_bcb;
+
+    if ((!handle) || (handle > BNEP_MAX_CONNECTIONS))
+        return (BNEP_WRONG_HANDLE);
+
+    p_bcb = &(bnep_cb.bcb[handle - 1]);
+
+    /* Check the connection state */
+    if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+        (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
+        return (BNEP_WRONG_STATE);
+
+    /* Validate the parameters */
+    if (num_filters && (!p_start_array || !p_end_array))
+        return (BNEP_SET_FILTER_FAIL);
+
+    if (num_filters > BNEP_MAX_PROT_FILTERS)
+        return (BNEP_TOO_MANY_FILTERS);
+
+    /* Fill the filter values in connnection block */
+    for (xx = 0; xx < num_filters; xx++)
+    {
+        p_bcb->sent_prot_filter_start[xx] = *p_start_array++;
+        p_bcb->sent_prot_filter_end[xx]   = *p_end_array++;
+    }
+
+    p_bcb->sent_num_filters = num_filters;
+
+    bnepu_send_peer_our_filters (p_bcb);
+
+    return (BNEP_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function         BNEP_SetMulticastFilters
+**
+** Description      This function sets the filters for multicast addresses for BNEP.
+**
+** Parameters:      handle        - Handle for the connection
+**                  num_filters   - total number of filter ranges
+**                  p_start_array - Pointer to sequence of beginings of all
+**                                         multicast address ranges
+**                  p_end_array   - Pointer to sequence of ends of all
+**                                         multicast address ranges
+**
+** Returns          BNEP_WRONG_HANDLE           - if the connection handle is not valid
+**                  BNEP_SET_FILTER_FAIL        - if the connection is in wrong state
+**                  BNEP_TOO_MANY_FILTERS       - if too many filters
+**                  BNEP_SUCCESS                - if request sent successfully
+**
+*******************************************************************************/
+tBNEP_RESULT BNEP_SetMulticastFilters (uint16_t handle,
+                                       uint16_t num_filters,
+                                       uint8_t *p_start_array,
+                                       uint8_t *p_end_array)
+{
+    uint16_t        xx;
+    tBNEP_CONN     *p_bcb;
+
+    if ((!handle) || (handle > BNEP_MAX_CONNECTIONS))
+        return (BNEP_WRONG_HANDLE);
+
+    p_bcb = &(bnep_cb.bcb[handle - 1]);
+
+    /* Check the connection state */
+    if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+        (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
+        return (BNEP_WRONG_STATE);
+
+    /* Validate the parameters */
+    if (num_filters && (!p_start_array || !p_end_array))
+        return (BNEP_SET_FILTER_FAIL);
+
+    if (num_filters > BNEP_MAX_MULTI_FILTERS)
+        return (BNEP_TOO_MANY_FILTERS);
+
+    /* Fill the multicast filter values in connnection block */
+    for (xx = 0; xx < num_filters; xx++)
+    {
+        memcpy (p_bcb->sent_mcast_filter_start[xx], p_start_array, BD_ADDR_LEN);
+        memcpy (p_bcb->sent_mcast_filter_end[xx], p_end_array, BD_ADDR_LEN);
+
+        p_start_array += BD_ADDR_LEN;
+        p_end_array   += BD_ADDR_LEN;
+    }
+
+    p_bcb->sent_mcast_filters = num_filters;
+
+    bnepu_send_peer_our_multi_filters (p_bcb);
+
+    return (BNEP_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         BNEP_SetTraceLevel
+**
+** Description      This function sets the trace level for BNEP. If called with
+**                  a value of 0xFF, it simply reads the current trace level.
+**
+** Returns          the new (current) trace level
+**
+*******************************************************************************/
+uint8_t BNEP_SetTraceLevel (uint8_t new_level)
+{
+    if (new_level != 0xFF)
+        bnep_cb.trace_level = new_level;
+
+    return (bnep_cb.trace_level);
+}
+
+
+/*******************************************************************************
+**
+** Function         BNEP_GetStatus
+**
+** Description      This function gets the status information for BNEP connection
+**
+** Returns          BNEP_SUCCESS            - if the status is available
+**                  BNEP_NO_RESOURCES       - if no structure is passed for output
+**                  BNEP_WRONG_HANDLE       - if the handle is invalid
+**                  BNEP_WRONG_STATE        - if not in connected state
+**
+*******************************************************************************/
+tBNEP_RESULT BNEP_GetStatus (uint16_t handle, tBNEP_STATUS *p_status)
+{
+#if (BNEP_SUPPORTS_STATUS_API == TRUE)
+    tBNEP_CONN     *p_bcb;
+
+    if (!p_status)
+        return BNEP_NO_RESOURCES;
+
+    if ((!handle) || (handle > BNEP_MAX_CONNECTIONS))
+        return (BNEP_WRONG_HANDLE);
+
+    p_bcb = &(bnep_cb.bcb[handle - 1]);
+
+    memset (p_status, 0, sizeof (tBNEP_STATUS));
+    if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+        (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
+        return BNEP_WRONG_STATE;
+
+    /* Read the status parameters from the connection control block */
+    p_status->con_status            = BNEP_STATUS_CONNECTED;
+    p_status->l2cap_cid             = p_bcb->l2cap_cid;
+    p_status->rem_mtu_size          = p_bcb->rem_mtu_size;
+    p_status->xmit_q_depth          = fixed_queue_length(p_bcb->xmit_q);
+    p_status->sent_num_filters      = p_bcb->sent_num_filters;
+    p_status->sent_mcast_filters    = p_bcb->sent_mcast_filters;
+    p_status->rcvd_num_filters      = p_bcb->rcvd_num_filters;
+    p_status->rcvd_mcast_filters    = p_bcb->rcvd_mcast_filters;
+
+    memcpy (p_status->rem_bda, p_bcb->rem_bda, BD_ADDR_LEN);
+    memcpy (&(p_status->src_uuid), &(p_bcb->src_uuid), sizeof (tBT_UUID));
+    memcpy (&(p_status->dst_uuid), &(p_bcb->dst_uuid), sizeof (tBT_UUID));
+
+    return BNEP_SUCCESS;
+#else
+    return (BNEP_IGNORE_CMD);
+#endif
+}
+
+
diff --git a/bt/stack/bnep/bnep_int.h b/bt/stack/bnep/bnep_int.h
new file mode 100644
index 0000000..91d3dd1
--- /dev/null
+++ b/bt/stack/bnep/bnep_int.h
@@ -0,0 +1,243 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2001-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 internally used BNEP definitions
+ *
+ ******************************************************************************/
+
+#ifndef  BNEP_INT_H
+#define  BNEP_INT_H
+
+#include "bt_target.h"
+#include "bt_common.h"
+#include "bnep_api.h"
+#include "btm_int.h"
+#include "btu.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* BNEP frame types
+*/
+#define BNEP_FRAME_GENERAL_ETHERNET                 0x00
+#define BNEP_FRAME_CONTROL                          0x01
+#define BNEP_FRAME_COMPRESSED_ETHERNET              0x02
+#define BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY     0x03
+#define BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY    0x04
+
+
+/* BNEP filter control message types
+*/
+#define BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD         0x00
+#define BNEP_SETUP_CONNECTION_REQUEST_MSG           0x01
+#define BNEP_SETUP_CONNECTION_RESPONSE_MSG          0x02
+#define BNEP_FILTER_NET_TYPE_SET_MSG                0x03
+#define BNEP_FILTER_NET_TYPE_RESPONSE_MSG           0x04
+#define BNEP_FILTER_MULTI_ADDR_SET_MSG              0x05
+#define BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG         0x06
+
+
+/* BNEP header extension types
+*/
+#define BNEP_EXTENSION_FILTER_CONTROL   0x00
+
+
+/* BNEP Setup Connection response codes
+*/
+#define BNEP_SETUP_CONN_OK              0x0000
+#define BNEP_SETUP_INVALID_DEST_UUID    0x0001
+#define BNEP_SETUP_INVALID_SRC_UUID     0x0002
+#define BNEP_SETUP_INVALID_UUID_SIZE    0x0003
+#define BNEP_SETUP_CONN_NOT_ALLOWED     0x0004
+
+
+/* BNEP filter control response codes
+*/
+#define BNEP_FILTER_CRL_OK              0x0000
+#define BNEP_FILTER_CRL_UNSUPPORTED     0x0001
+#define BNEP_FILTER_CRL_BAD_RANGE       0x0002
+#define BNEP_FILTER_CRL_MAX_REACHED     0x0003
+#define BNEP_FILTER_CRL_SECURITY_ERR    0x0004
+
+
+/* 802.1p protocol packet will have actual protocol field in side the payload */
+#define BNEP_802_1_P_PROTOCOL           0x8100
+
+/* Timeout definitions.
+*/
+#define BNEP_CONN_TIMEOUT_MS        (20 * 1000)      /* Connection related timeout */
+#define BNEP_HOST_TIMEOUT_MS        (200 * 1000)     /* host responce timeout */
+#define BNEP_FILTER_SET_TIMEOUT_MS  (10 * 1000)
+
+/* Define the Out-Flow default values. */
+#define  BNEP_OFLOW_QOS_FLAG                 0
+#define  BNEP_OFLOW_SERV_TYPE                0
+#define  BNEP_OFLOW_TOKEN_RATE               0
+#define  BNEP_OFLOW_TOKEN_BUCKET_SIZE        0
+#define  BNEP_OFLOW_PEAK_BANDWIDTH           0
+#define  BNEP_OFLOW_LATENCY                  0
+#define  BNEP_OFLOW_DELAY_VARIATION          0
+
+/* Define the In-Flow default values. */
+#define  BNEP_IFLOW_QOS_FLAG                 0
+#define  BNEP_IFLOW_SERV_TYPE                0
+#define  BNEP_IFLOW_TOKEN_RATE               0
+#define  BNEP_IFLOW_TOKEN_BUCKET_SIZE        0
+#define  BNEP_IFLOW_PEAK_BANDWIDTH           0
+#define  BNEP_IFLOW_LATENCY                  0
+#define  BNEP_IFLOW_DELAY_VARIATION          0
+
+#define BNEP_FLUSH_TO                       0xFFFF
+
+#define BNEP_MAX_RETRANSMITS                 3
+
+/* Define the BNEP Connection Control Block
+*/
+typedef struct
+{
+#define BNEP_STATE_IDLE              0
+#define BNEP_STATE_CONN_START        1
+#define BNEP_STATE_CFG_SETUP         2
+#define BNEP_STATE_CONN_SETUP        3
+#define BNEP_STATE_SEC_CHECKING      4
+#define BNEP_STATE_SETUP_RCVD        5
+#define BNEP_STATE_CONNECTED         6
+    uint8_t           con_state;
+
+#define BNEP_FLAGS_IS_ORIG           0x01
+#define BNEP_FLAGS_HIS_CFG_DONE      0x02
+#define BNEP_FLAGS_MY_CFG_DONE       0x04
+#define BNEP_FLAGS_L2CAP_CONGESTED   0x08
+#define BNEP_FLAGS_FILTER_RESP_PEND  0x10
+#define BNEP_FLAGS_MULTI_RESP_PEND   0x20
+#define BNEP_FLAGS_SETUP_RCVD        0x40
+#define BNEP_FLAGS_CONN_COMPLETED    0x80
+    uint8_t           con_flags;
+    BT_HDR            *p_pending_data;
+
+    uint16_t          l2cap_cid;
+    BD_ADDR           rem_bda;
+    uint16_t          rem_mtu_size;
+    alarm_t           *conn_timer;
+    fixed_queue_t     *xmit_q;
+
+    uint16_t          sent_num_filters;
+    uint16_t          sent_prot_filter_start[BNEP_MAX_PROT_FILTERS];
+    uint16_t          sent_prot_filter_end[BNEP_MAX_PROT_FILTERS];
+
+    uint16_t          sent_mcast_filters;
+    BD_ADDR           sent_mcast_filter_start[BNEP_MAX_MULTI_FILTERS];
+    BD_ADDR           sent_mcast_filter_end[BNEP_MAX_MULTI_FILTERS];
+
+    uint16_t          rcvd_num_filters;
+    uint16_t          rcvd_prot_filter_start[BNEP_MAX_PROT_FILTERS];
+    uint16_t          rcvd_prot_filter_end[BNEP_MAX_PROT_FILTERS];
+
+    uint16_t          rcvd_mcast_filters;
+    BD_ADDR           rcvd_mcast_filter_start[BNEP_MAX_MULTI_FILTERS];
+    BD_ADDR           rcvd_mcast_filter_end[BNEP_MAX_MULTI_FILTERS];
+
+    uint16_t          bad_pkts_rcvd;
+    uint8_t           re_transmits;
+    uint16_t          handle;
+    tBT_UUID          prv_src_uuid;
+    tBT_UUID          prv_dst_uuid;
+    tBT_UUID          src_uuid;
+    tBT_UUID          dst_uuid;
+
+} tBNEP_CONN;
+
+
+/*  The main BNEP control block
+*/
+typedef struct
+{
+    tL2CAP_CFG_INFO         l2cap_my_cfg;                   /* My L2CAP config     */
+    tBNEP_CONN              bcb[BNEP_MAX_CONNECTIONS];
+
+    tBNEP_CONNECT_IND_CB    *p_conn_ind_cb;
+    tBNEP_CONN_STATE_CB     *p_conn_state_cb;
+    tBNEP_DATA_IND_CB       *p_data_ind_cb;
+    tBNEP_DATA_BUF_CB       *p_data_buf_cb;
+    tBNEP_FILTER_IND_CB     *p_filter_ind_cb;
+    tBNEP_MFILTER_IND_CB    *p_mfilter_ind_cb;
+    tBNEP_TX_DATA_FLOW_CB   *p_tx_data_flow_cb;
+
+    tL2CAP_APPL_INFO        reg_info;
+
+    bool                    profile_registered;             /* true when we got our BD addr */
+    uint8_t                 trace_level;
+
+} tBNEP_CB;
+
+/* Global BNEP data
+*/
+extern tBNEP_CB bnep_cb;
+
+/* Functions provided by bnep_main.cc
+*/
+extern tBNEP_RESULT bnep_register_with_l2cap (void);
+extern void        bnep_disconnect (tBNEP_CONN *p_bcb, uint16_t reason);
+extern tBNEP_CONN *bnep_conn_originate (uint8_t *p_bd_addr);
+extern void        bnep_conn_timer_timeout(void *data);
+extern void        bnep_connected (tBNEP_CONN *p_bcb);
+
+
+/* Functions provided by bnep_utils.cc
+*/
+extern tBNEP_CONN *bnepu_find_bcb_by_cid (uint16_t cid);
+extern tBNEP_CONN *bnepu_find_bcb_by_bd_addr (uint8_t *p_bda);
+extern tBNEP_CONN *bnepu_allocate_bcb (BD_ADDR p_rem_bda);
+extern void        bnepu_release_bcb (tBNEP_CONN *p_bcb);
+extern void        bnepu_send_peer_our_filters (tBNEP_CONN *p_bcb);
+extern void        bnepu_send_peer_our_multi_filters (tBNEP_CONN *p_bcb);
+extern bool        bnepu_does_dest_support_prot (tBNEP_CONN *p_bcb, uint16_t protocol);
+extern void        bnepu_build_bnep_hdr (tBNEP_CONN *p_bcb, BT_HDR *p_buf, uint16_t protocol,
+                                         uint8_t *p_src_addr, uint8_t *p_dest_addr, bool    ext_bit);
+extern void        test_bnepu_build_bnep_hdr (tBNEP_CONN *p_bcb, BT_HDR *p_buf, uint16_t protocol,
+                                         uint8_t *p_src_addr, uint8_t *p_dest_addr, uint8_t type);
+
+extern tBNEP_CONN *bnepu_get_route_to_dest (uint8_t *p_bda);
+extern void        bnepu_check_send_packet (tBNEP_CONN *p_bcb, BT_HDR *p_buf);
+extern void        bnep_send_command_not_understood (tBNEP_CONN *p_bcb, uint8_t cmd_code);
+extern void        bnepu_process_peer_filter_set (tBNEP_CONN *p_bcb, uint8_t *p_filters, uint16_t len);
+extern void        bnepu_process_peer_filter_rsp (tBNEP_CONN *p_bcb, uint8_t *p_data);
+extern void        bnepu_process_multicast_filter_rsp (tBNEP_CONN *p_bcb, uint8_t *p_data);
+extern void        bnep_send_conn_req (tBNEP_CONN *p_bcb);
+extern void        bnep_send_conn_responce (tBNEP_CONN *p_bcb, uint16_t resp_code);
+extern void        bnep_process_setup_conn_req (tBNEP_CONN *p_bcb, uint8_t *p_setup, uint8_t len);
+extern void        bnep_process_setup_conn_responce (tBNEP_CONN *p_bcb, uint8_t *p_setup);
+extern uint8_t     *bnep_process_control_packet (tBNEP_CONN *p_bcb, uint8_t *p, uint16_t *len,
+                                                        bool    is_ext);
+extern void        bnep_sec_check_complete (BD_ADDR bd_addr, tBT_TRANSPORT trasnport,
+                                                    void *p_ref_data, uint8_t result);
+extern tBNEP_RESULT bnep_is_packet_allowed (tBNEP_CONN *p_bcb, BD_ADDR p_dest_addr, uint16_t protocol,
+                                                    bool    fw_ext_present, uint8_t *p_data);
+extern uint32_t    bnep_get_uuid32 (tBT_UUID *src_uuid);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/bt/stack/bnep/bnep_main.cc b/bt/stack/bnep/bnep_main.cc
new file mode 100644
index 0000000..d7cd02e
--- /dev/null
+++ b/bt/stack/bnep/bnep_main.cc
@@ -0,0 +1,805 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2001-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 main BNEP functions
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "bt_common.h"
+#include "bt_types.h"
+#include "l2cdefs.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+
+#include "l2c_api.h"
+#include "l2cdefs.h"
+
+#include "btu.h"
+#include "btm_api.h"
+
+#include "bnep_api.h"
+#include "bnep_int.h"
+#include "bt_utils.h"
+
+#include "device/include/controller.h"
+#include "osi/include/osi.h"
+
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+/********************************************************************************/
+/*                       G L O B A L    B N E P       D A T A                   */
+/********************************************************************************/
+tBNEP_CB bnep_cb;
+
+const uint16_t bnep_frame_hdr_sizes[] = {14, 1, 2, 8, 8};
+
+/********************************************************************************/
+/*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
+/********************************************************************************/
+static void bnep_connect_ind (BD_ADDR  bd_addr, uint16_t l2cap_cid, uint16_t psm, uint8_t l2cap_id);
+static void bnep_connect_cfm (uint16_t l2cap_cid, uint16_t result);
+static void bnep_config_ind (uint16_t l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void bnep_config_cfm (uint16_t l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void bnep_disconnect_ind (uint16_t l2cap_cid, bool    ack_needed);
+static void bnep_disconnect_cfm (uint16_t l2cap_cid, uint16_t result);
+static void bnep_data_ind (uint16_t l2cap_cid, BT_HDR *p_msg);
+static void bnep_congestion_ind (uint16_t lcid, bool    is_congested);
+
+
+/*******************************************************************************
+**
+** Function         bnep_register_with_l2cap
+**
+** Description      This function registers BNEP PSM with L2CAP
+**
+** Returns          void
+**
+*******************************************************************************/
+tBNEP_RESULT bnep_register_with_l2cap (void)
+{
+    /* Initialize the L2CAP configuration. We only care about MTU and flush */
+    memset(&bnep_cb.l2cap_my_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+    bnep_cb.l2cap_my_cfg.mtu_present            = true;
+    bnep_cb.l2cap_my_cfg.mtu                    = BNEP_MTU_SIZE;
+    bnep_cb.l2cap_my_cfg.flush_to_present       = true;
+    bnep_cb.l2cap_my_cfg.flush_to               = BNEP_FLUSH_TO;
+
+    bnep_cb.reg_info.pL2CA_ConnectInd_Cb        = bnep_connect_ind;
+    bnep_cb.reg_info.pL2CA_ConnectCfm_Cb        = bnep_connect_cfm;
+    bnep_cb.reg_info.pL2CA_ConfigInd_Cb         = bnep_config_ind;
+    bnep_cb.reg_info.pL2CA_ConfigCfm_Cb         = bnep_config_cfm;
+    bnep_cb.reg_info.pL2CA_DisconnectInd_Cb     = bnep_disconnect_ind;
+    bnep_cb.reg_info.pL2CA_DisconnectCfm_Cb     = bnep_disconnect_cfm;
+    bnep_cb.reg_info.pL2CA_DataInd_Cb           = bnep_data_ind;
+    bnep_cb.reg_info.pL2CA_CongestionStatus_Cb  = bnep_congestion_ind;
+
+    /* Now, register with L2CAP */
+    if (!L2CA_Register (BT_PSM_BNEP, &bnep_cb.reg_info))
+    {
+        BNEP_TRACE_ERROR ("BNEP - Registration failed");
+        return BNEP_SECURITY_FAIL;
+    }
+
+    return BNEP_SUCCESS;
+}
+
+
+/*******************************************************************************
+**
+** Function         bnep_connect_ind
+**
+** Description      This function handles an inbound connection indication
+**                  from L2CAP. This is the case where we are acting as a
+**                  server.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bnep_connect_ind (BD_ADDR  bd_addr, uint16_t l2cap_cid,
+                              UNUSED_ATTR uint16_t psm, uint8_t l2cap_id)
+{
+    tBNEP_CONN    *p_bcb = bnepu_find_bcb_by_bd_addr (bd_addr);
+
+    /* If we are not acting as server, or already have a connection, or have */
+    /* no more resources to handle the connection, reject the connection.    */
+    if (!(bnep_cb.profile_registered) || (p_bcb)
+     || ((p_bcb = bnepu_allocate_bcb(bd_addr)) == NULL))
+    {
+        L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_PSM, 0);
+        return;
+    }
+
+    /* Transition to the next appropriate state, waiting for config setup. */
+    p_bcb->con_state = BNEP_STATE_CFG_SETUP;
+
+    /* Save the L2CAP Channel ID. */
+    p_bcb->l2cap_cid = l2cap_cid;
+
+    /* Send response to the L2CAP layer. */
+    L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+
+    /* Send a Configuration Request. */
+    L2CA_ConfigReq (l2cap_cid, &bnep_cb.l2cap_my_cfg);
+
+    /* Start timer waiting for config setup */
+    alarm_set_on_queue(p_bcb->conn_timer, BNEP_CONN_TIMEOUT_MS,
+                       bnep_conn_timer_timeout, p_bcb,
+                       btu_general_alarm_queue);
+
+    BNEP_TRACE_EVENT("BNEP - Rcvd L2CAP conn ind, CID: 0x%x", p_bcb->l2cap_cid);
+
+}
+
+
+/*******************************************************************************
+**
+** Function         bnep_connect_cfm
+**
+** Description      This function handles the connect confirm events
+**                  from L2CAP. This is the case when we are acting as a
+**                  client and have sent a connect request.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bnep_connect_cfm (uint16_t l2cap_cid, uint16_t result)
+{
+    tBNEP_CONN    *p_bcb;
+
+    /* Find CCB based on CID */
+    if ((p_bcb = bnepu_find_bcb_by_cid (l2cap_cid)) == NULL)
+    {
+        BNEP_TRACE_WARNING ("BNEP - Rcvd conn cnf for unknown CID 0x%x", l2cap_cid);
+        return;
+    }
+
+    /* If the connection response contains success status, then */
+    /* Transition to the next state and startup the timer.      */
+    if ((result == L2CAP_CONN_OK) && (p_bcb->con_state == BNEP_STATE_CONN_START))
+    {
+        p_bcb->con_state = BNEP_STATE_CFG_SETUP;
+
+        /* Send a Configuration Request. */
+        L2CA_ConfigReq (l2cap_cid, &bnep_cb.l2cap_my_cfg);
+
+        /* Start timer waiting for config results */
+        alarm_set_on_queue(p_bcb->conn_timer, BNEP_CONN_TIMEOUT_MS,
+                           bnep_conn_timer_timeout, p_bcb,
+                           btu_general_alarm_queue);
+
+        BNEP_TRACE_EVENT ("BNEP - got conn cnf, sent cfg req, CID: 0x%x", p_bcb->l2cap_cid);
+    }
+    else
+    {
+        BNEP_TRACE_WARNING ("BNEP - Rcvd conn cnf with error: 0x%x  CID 0x%x", result, p_bcb->l2cap_cid);
+
+        /* Tell the upper layer, if he has a callback */
+        if (bnep_cb.p_conn_state_cb &&
+            p_bcb->con_flags & BNEP_FLAGS_IS_ORIG)
+        {
+            (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED, false);
+        }
+
+        bnepu_release_bcb (p_bcb);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bnep_config_ind
+**
+** Description      This function processes the L2CAP configuration indication
+**                  event.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bnep_config_ind (uint16_t l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+    tBNEP_CONN    *p_bcb;
+    uint16_t      result, mtu = 0;
+
+    /* Find CCB based on CID */
+    if ((p_bcb = bnepu_find_bcb_by_cid (l2cap_cid)) == NULL)
+    {
+        BNEP_TRACE_WARNING ("BNEP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+        return;
+    }
+
+    BNEP_TRACE_EVENT ("BNEP - Rcvd cfg ind, CID: 0x%x", l2cap_cid);
+
+    /* Remember the remote MTU size */
+    if ((!p_cfg->mtu_present) || (p_cfg->mtu < BNEP_MIN_MTU_SIZE))
+    {
+        mtu                     = p_cfg->mtu;
+        p_cfg->flush_to_present = false;
+        p_cfg->mtu_present      = true;
+        p_cfg->mtu              = BNEP_MIN_MTU_SIZE;
+        p_cfg->result           = result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+    }
+    else
+    {
+        if (p_cfg->mtu > BNEP_MTU_SIZE)
+            p_bcb->rem_mtu_size = BNEP_MTU_SIZE;
+        else
+            p_bcb->rem_mtu_size = p_cfg->mtu;
+
+        /* For now, always accept configuration from the other side */
+        p_cfg->flush_to_present = false;
+        p_cfg->mtu_present      = false;
+        p_cfg->result           = result = L2CAP_CFG_OK;
+    }
+
+    L2CA_ConfigRsp (l2cap_cid, p_cfg);
+
+    if (result != L2CAP_CFG_OK)
+    {
+        BNEP_TRACE_EVENT ("BNEP - Rcvd cfg ind with bad MTU %d, CID: 0x%x", mtu, l2cap_cid);
+        return;
+    }
+
+    p_bcb->con_flags |= BNEP_FLAGS_HIS_CFG_DONE;
+
+    if (p_bcb->con_flags & BNEP_FLAGS_MY_CFG_DONE)
+    {
+        p_bcb->con_state = BNEP_STATE_SEC_CHECKING;
+
+        /* Start timer waiting for setup or response */
+        alarm_set_on_queue(p_bcb->conn_timer, BNEP_HOST_TIMEOUT_MS,
+                           bnep_conn_timer_timeout, p_bcb,
+                           btu_general_alarm_queue);
+
+        if (p_bcb->con_flags & BNEP_FLAGS_IS_ORIG)
+        {
+            btm_sec_mx_access_request (p_bcb->rem_bda, BT_PSM_BNEP, true,
+                                       BTM_SEC_PROTO_BNEP,
+                                       bnep_get_uuid32(&(p_bcb->src_uuid)),
+                                       &bnep_sec_check_complete, p_bcb);
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         bnep_config_cfm
+**
+** Description      This function processes the L2CAP configuration confirmation
+**                  event.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bnep_config_cfm (uint16_t l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+    tBNEP_CONN    *p_bcb;
+
+    BNEP_TRACE_EVENT ("BNEP - Rcvd cfg cfm, CID: 0x%x  Result: %d", l2cap_cid, p_cfg->result);
+
+    /* Find CCB based on CID */
+    if ((p_bcb = bnepu_find_bcb_by_cid (l2cap_cid)) == NULL)
+    {
+        BNEP_TRACE_WARNING ("BNEP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+        return;
+    }
+
+    /* For now, always accept configuration from the other side */
+    if (p_cfg->result == L2CAP_CFG_OK)
+    {
+        p_bcb->con_flags |= BNEP_FLAGS_MY_CFG_DONE;
+
+        if (p_bcb->con_flags & BNEP_FLAGS_HIS_CFG_DONE)
+        {
+            p_bcb->con_state = BNEP_STATE_SEC_CHECKING;
+
+            /* Start timer waiting for setup or response */
+            alarm_set_on_queue(p_bcb->conn_timer, BNEP_HOST_TIMEOUT_MS,
+                               bnep_conn_timer_timeout, p_bcb,
+                               btu_general_alarm_queue);
+
+            if (p_bcb->con_flags & BNEP_FLAGS_IS_ORIG)
+            {
+                btm_sec_mx_access_request (p_bcb->rem_bda, BT_PSM_BNEP, true,
+                                           BTM_SEC_PROTO_BNEP,
+                                           bnep_get_uuid32(&(p_bcb->src_uuid)),
+                                           &bnep_sec_check_complete, p_bcb);
+            }
+        }
+    }
+    else
+    {
+        /* Tell the upper layer, if he has a callback */
+        if ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) && (bnep_cb.p_conn_state_cb))
+        {
+            (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED_CFG, false);
+        }
+
+        L2CA_DisconnectReq (p_bcb->l2cap_cid);
+
+        bnepu_release_bcb (p_bcb);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         bnep_disconnect_ind
+**
+** Description      This function handles a disconnect event from L2CAP. If
+**                  requested to, we ack the disconnect before dropping the CCB
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bnep_disconnect_ind (uint16_t l2cap_cid, bool    ack_needed)
+{
+    tBNEP_CONN    *p_bcb;
+
+    if (ack_needed)
+        L2CA_DisconnectRsp (l2cap_cid);
+
+    /* Find CCB based on CID */
+    if ((p_bcb = bnepu_find_bcb_by_cid (l2cap_cid)) == NULL)
+    {
+        BNEP_TRACE_WARNING ("BNEP - Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
+        return;
+    }
+
+    BNEP_TRACE_EVENT ("BNEP - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
+
+    /* Tell the user if he has a callback */
+    if (p_bcb->con_state == BNEP_STATE_CONNECTED)
+    {
+        if (bnep_cb.p_conn_state_cb)
+            (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_DISCONNECTED, false);
+    }
+    else
+    {
+        if ((bnep_cb.p_conn_state_cb) && ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) ||
+            (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
+            (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED, false);
+    }
+
+    bnepu_release_bcb (p_bcb);
+}
+
+
+
+/*******************************************************************************
+**
+** Function         bnep_disconnect_cfm
+**
+** Description      This function gets the disconnect confirm event from L2CAP
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bnep_disconnect_cfm (uint16_t l2cap_cid, uint16_t result)
+{
+    BNEP_TRACE_EVENT ("BNEP - Rcvd L2CAP disc cfm, CID: 0x%x, Result 0x%x", l2cap_cid, result);
+}
+
+
+
+/*******************************************************************************
+**
+** Function         bnep_congestion_ind
+**
+** Description      This is a callback function called by L2CAP when
+**                  congestion status changes
+**
+*******************************************************************************/
+static void bnep_congestion_ind (uint16_t l2cap_cid, bool    is_congested)
+{
+    tBNEP_CONN    *p_bcb;
+
+    /* Find BCB based on CID */
+    if ((p_bcb = bnepu_find_bcb_by_cid (l2cap_cid)) == NULL)
+    {
+        BNEP_TRACE_WARNING ("BNEP - Rcvd L2CAP cong, unknown CID: 0x%x", l2cap_cid);
+        return;
+    }
+
+    if (is_congested)
+   {
+        p_bcb->con_flags |= BNEP_FLAGS_L2CAP_CONGESTED;
+       if(bnep_cb.p_tx_data_flow_cb)
+       {
+           bnep_cb.p_tx_data_flow_cb(p_bcb->handle, BNEP_TX_FLOW_OFF);
+       }
+   }
+    else
+    {
+        p_bcb->con_flags &= ~BNEP_FLAGS_L2CAP_CONGESTED;
+
+       if(bnep_cb.p_tx_data_flow_cb)
+       {
+           bnep_cb.p_tx_data_flow_cb(p_bcb->handle, BNEP_TX_FLOW_ON);
+       }
+
+        /* While not congested, send as many buffers as we can */
+        while (!(p_bcb->con_flags & BNEP_FLAGS_L2CAP_CONGESTED))
+        {
+            BT_HDR *p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_bcb->xmit_q);
+
+            if (!p_buf)
+                break;
+
+            L2CA_DataWrite (l2cap_cid, p_buf);
+        }
+    }
+}
+
+
+
+/*******************************************************************************
+**
+** Function         bnep_data_ind
+**
+** Description      This function is called when data is received from L2CAP.
+**                  if we are the originator of the connection, we are the SDP
+**                  client, and the received message is queued up for the client.
+**
+**                  If we are the destination of the connection, we are the SDP
+**                  server, so the message is passed to the server processing
+**                  function.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void bnep_data_ind (uint16_t l2cap_cid, BT_HDR *p_buf)
+{
+    tBNEP_CONN    *p_bcb;
+    uint8_t       *p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+    uint16_t      rem_len = p_buf->len;
+    uint8_t       type, ctrl_type, ext_type = 0;
+    bool          extension_present, fw_ext_present;
+    uint16_t      protocol = 0;
+    uint8_t       *p_src_addr, *p_dst_addr;
+
+
+    /* Find CCB based on CID */
+    if ((p_bcb = bnepu_find_bcb_by_cid (l2cap_cid)) == NULL)
+    {
+        BNEP_TRACE_WARNING ("BNEP - Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
+        osi_free(p_buf);
+        return;
+    }
+
+    /* Get the type and extension bits */
+    type = *p++;
+    extension_present = type >> 7;
+    type &= 0x7f;
+    if ((rem_len <= bnep_frame_hdr_sizes[type]) || (rem_len > BNEP_MTU_SIZE))
+    {
+        BNEP_TRACE_EVENT ("BNEP - rcvd frame, bad len: %d  type: 0x%02x", p_buf->len, type);
+        osi_free(p_buf);
+        return;
+    }
+
+    rem_len--;
+
+    if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+        (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)) &&
+        (type != BNEP_FRAME_CONTROL))
+    {
+        BNEP_TRACE_WARNING ("BNEP - Ignored L2CAP data while in state: %d, CID: 0x%x",
+                            p_bcb->con_state, l2cap_cid);
+
+        if (extension_present)
+        {
+            /*
+            ** When there is no connection if a data packet is received
+            ** with unknown control extension headers then those should be processed
+            ** according to complain/ignore law
+            */
+            uint8_t     ext, length;
+            uint16_t    org_len, new_len;
+            /* parse the extension headers and process unknown control headers */
+            org_len = rem_len;
+            new_len = 0;
+            do {
+
+                ext     = *p++;
+                length  = *p++;
+                p += length;
+
+                if ((!(ext & 0x7F)) && (*p > BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG))
+                    bnep_send_command_not_understood (p_bcb, *p);
+
+                new_len += (length + 2);
+
+                if (new_len > org_len)
+                    break;
+
+            } while (ext & 0x80);
+        }
+
+        osi_free(p_buf);
+        return;
+    }
+
+    if (type > BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY)
+    {
+        BNEP_TRACE_EVENT ("BNEP - rcvd frame, unknown type: 0x%02x", type);
+        osi_free(p_buf);
+        return;
+    }
+
+    BNEP_TRACE_DEBUG ("BNEP - rcv frame, type: %d len: %d Ext: %d", type, p_buf->len, extension_present);
+
+    /* Initialize addresses to 'not supplied' */
+    p_src_addr = p_dst_addr = NULL;
+
+    switch (type)
+    {
+    case BNEP_FRAME_GENERAL_ETHERNET:
+        p_dst_addr = p;
+        p += BD_ADDR_LEN;
+        p_src_addr = p;
+        p += BD_ADDR_LEN;
+        BE_STREAM_TO_UINT16 (protocol, p);
+        rem_len -= 14;
+        break;
+
+    case BNEP_FRAME_CONTROL:
+        ctrl_type = *p;
+        p = bnep_process_control_packet (p_bcb, p, &rem_len, false);
+
+        if (ctrl_type == BNEP_SETUP_CONNECTION_REQUEST_MSG &&
+            p_bcb->con_state != BNEP_STATE_CONNECTED &&
+            extension_present && p && rem_len)
+        {
+            p_bcb->p_pending_data = (BT_HDR *)osi_malloc(rem_len + sizeof(BT_HDR));
+            memcpy((uint8_t *)(p_bcb->p_pending_data + 1), p, rem_len);
+            p_bcb->p_pending_data->len    = rem_len;
+            p_bcb->p_pending_data->offset = 0;
+        }
+        else
+        {
+            while (extension_present && p && rem_len)
+            {
+                ext_type = *p++;
+                extension_present = ext_type >> 7;
+                ext_type &= 0x7F;
+
+                /* if unknown extension present stop processing */
+                if (ext_type)
+                    break;
+
+                p = bnep_process_control_packet (p_bcb, p, &rem_len, true);
+            }
+        }
+        osi_free(p_buf);
+        return;
+
+    case BNEP_FRAME_COMPRESSED_ETHERNET:
+        BE_STREAM_TO_UINT16 (protocol, p);
+        rem_len -= 2;
+        break;
+
+    case BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY:
+        p_src_addr = p;
+        p += BD_ADDR_LEN;
+        BE_STREAM_TO_UINT16 (protocol, p);
+        rem_len -= 8;
+        break;
+
+    case BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY:
+        p_dst_addr = p;
+        p += BD_ADDR_LEN;
+        BE_STREAM_TO_UINT16 (protocol, p);
+        rem_len -= 8;
+        break;
+    }
+
+    /* Process the header extension if there is one */
+    while (extension_present && p && rem_len)
+    {
+        ext_type = *p;
+        extension_present = ext_type >> 7;
+        ext_type &= 0x7F;
+
+        /* if unknown extension present stop processing */
+        if (ext_type)
+        {
+            BNEP_TRACE_EVENT ("Data extension type 0x%x found", ext_type);
+            break;
+        }
+
+        p++;
+        rem_len--;
+        p = bnep_process_control_packet (p_bcb, p, &rem_len, true);
+    }
+
+    p_buf->offset += p_buf->len - rem_len;
+    p_buf->len     = rem_len;
+
+    /* Always give the upper layer MAC addresses */
+    if (!p_src_addr)
+        p_src_addr = (uint8_t *) p_bcb->rem_bda;
+
+    if (!p_dst_addr)
+        p_dst_addr = (uint8_t *) controller_get_interface()->get_address();
+
+    /* check whether there are any extensions to be forwarded */
+    if (ext_type)
+        fw_ext_present = true;
+    else
+        fw_ext_present = false;
+
+    if (bnep_cb.p_data_buf_cb)
+    {
+        (*bnep_cb.p_data_buf_cb)(p_bcb->handle, p_src_addr, p_dst_addr, protocol, p_buf, fw_ext_present);
+    }
+    else if (bnep_cb.p_data_ind_cb)
+    {
+        (*bnep_cb.p_data_ind_cb)(p_bcb->handle, p_src_addr, p_dst_addr, protocol, p, rem_len, fw_ext_present);
+        osi_free(p_buf);
+    }
+}
+
+
+
+/*******************************************************************************
+**
+** Function         bnep_conn_timer_timeout
+**
+** Description      This function processes a timeout. If it is a startup
+**                  timeout, we check for reading our BD address. If it
+**                  is an L2CAP timeout, we send a disconnect req to L2CAP.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bnep_conn_timer_timeout(void *data)
+{
+    tBNEP_CONN *p_bcb = (tBNEP_CONN *)data;
+
+    BNEP_TRACE_EVENT ("BNEP - CCB timeout in state: %d  CID: 0x%x flags %x, re_transmit %d",
+                       p_bcb->con_state, p_bcb->l2cap_cid, p_bcb->con_flags, p_bcb->re_transmits);
+
+    if (p_bcb->con_state == BNEP_STATE_CONN_SETUP)
+    {
+        BNEP_TRACE_EVENT ("BNEP - CCB timeout in state: %d  CID: 0x%x",
+                           p_bcb->con_state, p_bcb->l2cap_cid);
+
+        if (!(p_bcb->con_flags & BNEP_FLAGS_IS_ORIG))
+        {
+            L2CA_DisconnectReq (p_bcb->l2cap_cid);
+
+            bnepu_release_bcb (p_bcb);
+            return;
+        }
+
+        if (p_bcb->re_transmits++ != BNEP_MAX_RETRANSMITS)
+        {
+            bnep_send_conn_req (p_bcb);
+            alarm_set_on_queue(p_bcb->conn_timer, BNEP_CONN_TIMEOUT_MS,
+                               bnep_conn_timer_timeout, p_bcb,
+                               btu_general_alarm_queue);
+        }
+        else
+        {
+            L2CA_DisconnectReq (p_bcb->l2cap_cid);
+
+            if ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) && (bnep_cb.p_conn_state_cb))
+                (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED, false);
+
+            bnepu_release_bcb (p_bcb);
+            return;
+        }
+    }
+    else if (p_bcb->con_state != BNEP_STATE_CONNECTED)
+    {
+        BNEP_TRACE_EVENT ("BNEP - CCB timeout in state: %d  CID: 0x%x",
+                           p_bcb->con_state, p_bcb->l2cap_cid);
+
+        L2CA_DisconnectReq (p_bcb->l2cap_cid);
+
+        /* Tell the user if he has a callback */
+        if ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) && (bnep_cb.p_conn_state_cb))
+            (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED, false);
+
+        bnepu_release_bcb (p_bcb);
+    }
+    else if (p_bcb->con_flags & BNEP_FLAGS_FILTER_RESP_PEND)
+    {
+        if (p_bcb->re_transmits++ != BNEP_MAX_RETRANSMITS)
+        {
+            bnepu_send_peer_our_filters (p_bcb);
+            alarm_set_on_queue(p_bcb->conn_timer, BNEP_FILTER_SET_TIMEOUT_MS,
+                               bnep_conn_timer_timeout, p_bcb,
+                               btu_general_alarm_queue);
+        }
+        else
+        {
+            L2CA_DisconnectReq (p_bcb->l2cap_cid);
+
+            /* Tell the user if he has a callback */
+            if (bnep_cb.p_conn_state_cb)
+                (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_SET_FILTER_FAIL, false);
+
+            bnepu_release_bcb (p_bcb);
+            return;
+        }
+    }
+    else if (p_bcb->con_flags & BNEP_FLAGS_MULTI_RESP_PEND)
+    {
+        if (p_bcb->re_transmits++ != BNEP_MAX_RETRANSMITS)
+        {
+            bnepu_send_peer_our_multi_filters (p_bcb);
+            alarm_set_on_queue(p_bcb->conn_timer, BNEP_FILTER_SET_TIMEOUT_MS,
+                               bnep_conn_timer_timeout, p_bcb,
+                               btu_general_alarm_queue);
+        }
+        else
+        {
+            L2CA_DisconnectReq (p_bcb->l2cap_cid);
+
+            /* Tell the user if he has a callback */
+            if (bnep_cb.p_conn_state_cb)
+                (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_SET_FILTER_FAIL, false);
+
+            bnepu_release_bcb (p_bcb);
+            return;
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         bnep_connected
+**
+** Description      This function is called when a connection is established
+**                  (after config).
+**
+** Returns          void
+**
+*******************************************************************************/
+void bnep_connected (tBNEP_CONN *p_bcb)
+{
+    bool        is_role_change;
+
+    if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)
+        is_role_change = true;
+    else
+        is_role_change = false;
+
+    p_bcb->con_state = BNEP_STATE_CONNECTED;
+    p_bcb->con_flags |= BNEP_FLAGS_CONN_COMPLETED;
+    p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD);
+
+    /* Ensure timer is stopped */
+    alarm_cancel(p_bcb->conn_timer);
+    p_bcb->re_transmits = 0;
+
+    /* Tell the upper layer, if he has a callback */
+    if (bnep_cb.p_conn_state_cb)
+        (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_SUCCESS, is_role_change);
+}
diff --git a/bt/stack/bnep/bnep_utils.cc b/bt/stack/bnep/bnep_utils.cc
new file mode 100644
index 0000000..5b8c46c
--- /dev/null
+++ b/bt/stack/bnep/bnep_utils.cc
@@ -0,0 +1,1371 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2001-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 BNEP utility functions
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bnep_int.h"
+#include "btu.h"
+#include "btm_int.h"
+#include "bt_utils.h"
+#include "device/include/controller.h"
+#include "osi/include/osi.h"
+
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+/********************************************************************************/
+/*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
+/********************************************************************************/
+static uint8_t *bnepu_init_hdr (BT_HDR *p_buf, uint16_t hdr_len, uint8_t pkt_type);
+
+void bnepu_process_peer_multicast_filter_set (tBNEP_CONN *p_bcb, uint8_t *p_filters, uint16_t len);
+void bnepu_send_peer_multicast_filter_rsp (tBNEP_CONN *p_bcb, uint16_t response_code);
+
+
+/*******************************************************************************
+**
+** Function         bnepu_find_bcb_by_cid
+**
+** Description      This function searches the bcb table for an entry with the
+**                  passed CID.
+**
+** Returns          the BCB address, or NULL if not found.
+**
+*******************************************************************************/
+tBNEP_CONN *bnepu_find_bcb_by_cid (uint16_t cid)
+{
+    uint16_t        xx;
+    tBNEP_CONN     *p_bcb;
+
+    /* Look through each connection control block */
+    for (xx = 0, p_bcb = bnep_cb.bcb; xx < BNEP_MAX_CONNECTIONS; xx++, p_bcb++)
+    {
+        if ((p_bcb->con_state != BNEP_STATE_IDLE) && (p_bcb->l2cap_cid == cid))
+            return (p_bcb);
+    }
+
+    /* If here, not found */
+    return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         bnepu_find_bcb_by_bd_addr
+**
+** Description      This function searches the BCB table for an entry with the
+**                  passed Bluetooth Address.
+**
+** Returns          the BCB address, or NULL if not found.
+**
+*******************************************************************************/
+tBNEP_CONN *bnepu_find_bcb_by_bd_addr (uint8_t *p_bda)
+{
+    uint16_t        xx;
+    tBNEP_CONN     *p_bcb;
+
+    /* Look through each connection control block */
+    for (xx = 0, p_bcb = bnep_cb.bcb; xx < BNEP_MAX_CONNECTIONS; xx++, p_bcb++)
+    {
+        if (p_bcb->con_state != BNEP_STATE_IDLE)
+        {
+            if (!memcmp ((uint8_t *)(p_bcb->rem_bda), p_bda, BD_ADDR_LEN))
+                return (p_bcb);
+        }
+    }
+
+    /* If here, not found */
+    return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         bnepu_allocate_bcb
+**
+** Description      This function allocates a new BCB.
+**
+** Returns          BCB address, or NULL if none available.
+**
+*******************************************************************************/
+tBNEP_CONN *bnepu_allocate_bcb (BD_ADDR p_rem_bda)
+{
+    uint16_t        xx;
+    tBNEP_CONN     *p_bcb;
+
+    /* Look through each connection control block for a free one */
+    for (xx = 0, p_bcb = bnep_cb.bcb; xx < BNEP_MAX_CONNECTIONS; xx++, p_bcb++)
+    {
+        if (p_bcb->con_state == BNEP_STATE_IDLE)
+        {
+            alarm_free(p_bcb->conn_timer);
+            memset ((uint8_t *)p_bcb, 0, sizeof (tBNEP_CONN));
+            p_bcb->conn_timer = alarm_new("bnep.conn_timer");
+
+            memcpy ((uint8_t *)(p_bcb->rem_bda), (uint8_t *)p_rem_bda, BD_ADDR_LEN);
+            p_bcb->handle = xx + 1;
+            p_bcb->xmit_q = fixed_queue_new(SIZE_MAX);
+
+            return (p_bcb);
+        }
+    }
+
+    /* If here, no free BCB found */
+    return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         bnepu_release_bcb
+**
+** Description      This function releases a BCB.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bnepu_release_bcb (tBNEP_CONN *p_bcb)
+{
+    /* Ensure timer is stopped */
+    alarm_free(p_bcb->conn_timer);
+    p_bcb->conn_timer = NULL;
+
+    /* Drop any response pointer we may be holding */
+    p_bcb->con_state        = BNEP_STATE_IDLE;
+    p_bcb->p_pending_data   = NULL;
+
+    /* Free transmit queue */
+    while (!fixed_queue_is_empty(p_bcb->xmit_q))
+    {
+        osi_free(fixed_queue_try_dequeue(p_bcb->xmit_q));
+    }
+    fixed_queue_free(p_bcb->xmit_q, NULL);
+    p_bcb->xmit_q = NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function         bnep_send_conn_req
+**
+** Description      This function sends a BNEP connection request to peer
+**
+** Returns          void
+**
+*******************************************************************************/
+void bnep_send_conn_req (tBNEP_CONN *p_bcb)
+{
+    BT_HDR  *p_buf = (BT_HDR *)osi_malloc(BNEP_BUF_SIZE);
+    uint8_t *p, *p_start;
+
+    BNEP_TRACE_DEBUG ("%s: sending setup req with dst uuid %x",
+        __func__, p_bcb->dst_uuid.uu.uuid16);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p = p_start = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+    /* Put in BNEP frame type - filter control */
+    UINT8_TO_BE_STREAM (p, BNEP_FRAME_CONTROL);
+
+    /* Put in filter message type - set filters */
+    UINT8_TO_BE_STREAM (p, BNEP_SETUP_CONNECTION_REQUEST_MSG);
+
+    UINT8_TO_BE_STREAM (p, p_bcb->dst_uuid.len);
+
+    if (p_bcb->dst_uuid.len == 2)
+    {
+        UINT16_TO_BE_STREAM (p, p_bcb->dst_uuid.uu.uuid16);
+        UINT16_TO_BE_STREAM (p, p_bcb->src_uuid.uu.uuid16);
+    }
+    else if (p_bcb->dst_uuid.len == 4)
+    {
+        UINT32_TO_BE_STREAM (p, p_bcb->dst_uuid.uu.uuid32);
+        UINT32_TO_BE_STREAM (p, p_bcb->src_uuid.uu.uuid32);
+    }
+    else if (p_bcb->dst_uuid.len == 16)
+    {
+        memcpy (p, p_bcb->dst_uuid.uu.uuid128, p_bcb->dst_uuid.len);
+        p += p_bcb->dst_uuid.len;
+        memcpy (p, p_bcb->src_uuid.uu.uuid128, p_bcb->dst_uuid.len);
+        p += p_bcb->dst_uuid.len;
+    }
+    else
+    {
+        BNEP_TRACE_ERROR ("%s: uuid: %x, invalid length: %x",
+            __func__, p_bcb->dst_uuid.uu.uuid16, p_bcb->dst_uuid.len);
+    }
+
+    p_buf->len = (uint16_t)(p - p_start);
+
+    bnepu_check_send_packet (p_bcb, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         bnep_send_conn_responce
+**
+** Description      This function sends a BNEP setup response to peer
+**
+** Returns          void
+**
+*******************************************************************************/
+void bnep_send_conn_responce (tBNEP_CONN *p_bcb, uint16_t resp_code)
+{
+    BT_HDR  *p_buf = (BT_HDR *)osi_malloc(BNEP_BUF_SIZE);
+    uint8_t *p;
+
+    BNEP_TRACE_EVENT ("BNEP - bnep_send_conn_responce for CID: 0x%x", p_bcb->l2cap_cid);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+    /* Put in BNEP frame type - filter control */
+    UINT8_TO_BE_STREAM (p, BNEP_FRAME_CONTROL);
+
+    /* Put in filter message type - set filters */
+    UINT8_TO_BE_STREAM (p, BNEP_SETUP_CONNECTION_RESPONSE_MSG);
+
+    UINT16_TO_BE_STREAM (p, resp_code);
+
+    p_buf->len = 4;
+
+    bnepu_check_send_packet (p_bcb, p_buf);
+
+}
+
+
+/*******************************************************************************
+**
+** Function         bnepu_send_peer_our_filters
+**
+** Description      This function sends our filters to a peer
+**
+** Returns          void
+**
+*******************************************************************************/
+void bnepu_send_peer_our_filters (tBNEP_CONN *p_bcb)
+{
+    BT_HDR      *p_buf = (BT_HDR *)osi_malloc(BNEP_BUF_SIZE);
+    uint8_t     *p;
+    uint16_t    xx;
+
+    BNEP_TRACE_DEBUG ("BNEP sending peer our filters");
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+    /* Put in BNEP frame type - filter control */
+    UINT8_TO_BE_STREAM (p, BNEP_FRAME_CONTROL);
+
+    /* Put in filter message type - set filters */
+    UINT8_TO_BE_STREAM (p, BNEP_FILTER_NET_TYPE_SET_MSG);
+
+    UINT16_TO_BE_STREAM (p, (4 * p_bcb->sent_num_filters));
+    for (xx = 0; xx < p_bcb->sent_num_filters; xx++)
+    {
+        UINT16_TO_BE_STREAM (p, p_bcb->sent_prot_filter_start[xx]);
+        UINT16_TO_BE_STREAM (p, p_bcb->sent_prot_filter_end[xx]);
+    }
+
+    p_buf->len = 4 + (4 * p_bcb->sent_num_filters);
+
+    bnepu_check_send_packet (p_bcb, p_buf);
+
+    p_bcb->con_flags |= BNEP_FLAGS_FILTER_RESP_PEND;
+
+    /* Start timer waiting for setup response */
+    alarm_set_on_queue(p_bcb->conn_timer, BNEP_FILTER_SET_TIMEOUT_MS,
+                       bnep_conn_timer_timeout, p_bcb,
+                       btu_general_alarm_queue);
+}
+
+
+/*******************************************************************************
+**
+** Function         bnepu_send_peer_our_multi_filters
+**
+** Description      This function sends our multicast filters to a peer
+**
+** Returns          void
+**
+*******************************************************************************/
+void bnepu_send_peer_our_multi_filters (tBNEP_CONN *p_bcb)
+{
+    BT_HDR      *p_buf = (BT_HDR *)osi_malloc(BNEP_BUF_SIZE);
+    uint8_t     *p;
+    uint16_t    xx;
+
+    BNEP_TRACE_DEBUG ("BNEP sending peer our multicast filters");
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+    /* Put in BNEP frame type - filter control */
+    UINT8_TO_BE_STREAM (p, BNEP_FRAME_CONTROL);
+
+    /* Put in filter message type - set filters */
+    UINT8_TO_BE_STREAM (p, BNEP_FILTER_MULTI_ADDR_SET_MSG);
+
+    UINT16_TO_BE_STREAM (p, (2 * BD_ADDR_LEN * p_bcb->sent_mcast_filters));
+    for (xx = 0; xx < p_bcb->sent_mcast_filters; xx++)
+    {
+        memcpy (p, p_bcb->sent_mcast_filter_start[xx], BD_ADDR_LEN);
+        p += BD_ADDR_LEN;
+        memcpy (p, p_bcb->sent_mcast_filter_end[xx], BD_ADDR_LEN);
+        p += BD_ADDR_LEN;
+    }
+
+    p_buf->len = 4 + (2 * BD_ADDR_LEN * p_bcb->sent_mcast_filters);
+
+    bnepu_check_send_packet (p_bcb, p_buf);
+
+    p_bcb->con_flags |= BNEP_FLAGS_MULTI_RESP_PEND;
+
+    /* Start timer waiting for setup response */
+    alarm_set_on_queue(p_bcb->conn_timer, BNEP_FILTER_SET_TIMEOUT_MS,
+                       bnep_conn_timer_timeout, p_bcb,
+                       btu_general_alarm_queue);
+}
+
+
+/*******************************************************************************
+**
+** Function         bnepu_send_peer_filter_rsp
+**
+** Description      This function sends a filter response to a peer
+**
+** Returns          void
+**
+*******************************************************************************/
+void bnepu_send_peer_filter_rsp (tBNEP_CONN *p_bcb, uint16_t response_code)
+{
+    BT_HDR  *p_buf = (BT_HDR *)osi_malloc(BNEP_BUF_SIZE);
+    uint8_t *p;
+
+    BNEP_TRACE_DEBUG ("BNEP sending filter response");
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+    /* Put in BNEP frame type - filter control */
+    UINT8_TO_BE_STREAM (p, BNEP_FRAME_CONTROL);
+
+    /* Put in filter message type - set filters */
+    UINT8_TO_BE_STREAM (p, BNEP_FILTER_NET_TYPE_RESPONSE_MSG);
+
+    UINT16_TO_BE_STREAM (p, response_code);
+
+    p_buf->len = 4;
+
+    bnepu_check_send_packet (p_bcb, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         bnep_send_command_not_understood
+**
+** Description      This function sends a BNEP command not understood message
+**
+** Returns          void
+**
+*******************************************************************************/
+void bnep_send_command_not_understood (tBNEP_CONN *p_bcb, uint8_t cmd_code)
+{
+    BT_HDR  *p_buf = (BT_HDR *)osi_malloc(BNEP_BUF_SIZE);
+    uint8_t *p;
+
+    BNEP_TRACE_EVENT ("BNEP - bnep_send_command_not_understood for CID: 0x%x, cmd 0x%x", p_bcb->l2cap_cid, cmd_code);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+    /* Put in BNEP frame type - filter control */
+    UINT8_TO_BE_STREAM (p, BNEP_FRAME_CONTROL);
+
+    /* Put in filter message type - set filters */
+    UINT8_TO_BE_STREAM (p, BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD);
+
+    UINT8_TO_BE_STREAM (p, cmd_code);
+
+    p_buf->len = 3;
+
+    bnepu_check_send_packet (p_bcb, p_buf);
+
+}
+
+
+/*******************************************************************************
+**
+** Function         bnepu_check_send_packet
+**
+** Description      This function tries to send a packet to L2CAP.
+**                  If L2CAP is flow controlled, it enqueues the
+**                  packet to the transmit queue
+**
+** Returns          void
+**
+*******************************************************************************/
+void bnepu_check_send_packet (tBNEP_CONN *p_bcb, BT_HDR *p_buf)
+{
+    BNEP_TRACE_EVENT ("BNEP - bnepu_check_send_packet for CID: 0x%x", p_bcb->l2cap_cid);
+    if (p_bcb->con_flags & BNEP_FLAGS_L2CAP_CONGESTED)
+    {
+        if (fixed_queue_length(p_bcb->xmit_q) >= BNEP_MAX_XMITQ_DEPTH)
+        {
+            BNEP_TRACE_EVENT ("BNEP - congested, dropping buf, CID: 0x%x", p_bcb->l2cap_cid);
+
+            osi_free(p_buf);
+        }
+        else
+        {
+            fixed_queue_enqueue(p_bcb->xmit_q, p_buf);
+        }
+    }
+    else
+    {
+        L2CA_DataWrite (p_bcb->l2cap_cid, p_buf);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         bnepu_build_bnep_hdr
+**
+** Description      This function builds the BNEP header for a packet
+**                  Extension headers are not sent yet, so there is no
+**                  check for that.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bnepu_build_bnep_hdr (tBNEP_CONN *p_bcb, BT_HDR *p_buf, uint16_t protocol,
+                           uint8_t *p_src_addr, uint8_t *p_dest_addr, bool    fw_ext_present)
+{
+    const controller_t *controller = controller_get_interface();
+    uint8_t  ext_bit, *p = (uint8_t *)NULL;
+    uint8_t  type = BNEP_FRAME_COMPRESSED_ETHERNET;
+
+    ext_bit = fw_ext_present ? 0x80 : 0x00;
+
+    if ((p_src_addr) && (memcmp (p_src_addr, &controller->get_address()->address, BD_ADDR_LEN)))
+        type = BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY;
+
+    if (memcmp (p_dest_addr, p_bcb->rem_bda, BD_ADDR_LEN))
+        type = (type == BNEP_FRAME_COMPRESSED_ETHERNET) ? BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY : BNEP_FRAME_GENERAL_ETHERNET;
+
+    if (!p_src_addr)
+        p_src_addr = (uint8_t *)controller->get_address();
+
+    switch (type)
+    {
+    case BNEP_FRAME_GENERAL_ETHERNET:
+        p = bnepu_init_hdr (p_buf, 15, (uint8_t)(ext_bit | BNEP_FRAME_GENERAL_ETHERNET));
+
+        memcpy (p, p_dest_addr, BD_ADDR_LEN);
+        p += BD_ADDR_LEN;
+
+        memcpy (p, p_src_addr, BD_ADDR_LEN);
+        p += BD_ADDR_LEN;
+        break;
+
+    case BNEP_FRAME_COMPRESSED_ETHERNET:
+        p = bnepu_init_hdr (p_buf, 3, (uint8_t)(ext_bit | BNEP_FRAME_COMPRESSED_ETHERNET));
+        break;
+
+    case BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY:
+        p = bnepu_init_hdr (p_buf, 9, (uint8_t)(ext_bit | BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY));
+
+        memcpy (p, p_src_addr, BD_ADDR_LEN);
+        p += BD_ADDR_LEN;
+        break;
+
+    case BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY:
+        p = bnepu_init_hdr (p_buf, 9, (uint8_t)(ext_bit | BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY));
+
+        memcpy (p, p_dest_addr, BD_ADDR_LEN);
+        p += BD_ADDR_LEN;
+        break;
+    }
+
+    UINT16_TO_BE_STREAM (p, protocol);
+}
+
+
+/*******************************************************************************
+**
+** Function         bnepu_init_hdr
+**
+** Description      This function initializes the BNEP header
+**
+** Returns          pointer to header in buffer
+**
+*******************************************************************************/
+static uint8_t *bnepu_init_hdr (BT_HDR *p_buf, uint16_t hdr_len, uint8_t pkt_type)
+{
+    uint8_t  *p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+    /* See if we need to make space in the buffer */
+    if (p_buf->offset < (hdr_len + L2CAP_MIN_OFFSET))
+    {
+        uint16_t xx, diff = BNEP_MINIMUM_OFFSET - p_buf->offset;
+        p = p + p_buf->len - 1;
+        for (xx = 0; xx < p_buf->len; xx++, p--)
+            p[diff] = *p;
+
+        p_buf->offset = BNEP_MINIMUM_OFFSET;
+        p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+    }
+
+    p_buf->len    += hdr_len;
+    p_buf->offset -= hdr_len;
+    p             -= hdr_len;
+
+    *p++ = pkt_type;
+
+    return (p);
+}
+
+
+/*******************************************************************************
+**
+** Function         bnep_process_setup_conn_req
+**
+** Description      This function processes a peer's setup connection request
+**                  message. The destination UUID is verified and response sent
+**                  Connection open indication will be given to PAN profile
+**
+** Returns          void
+**
+*******************************************************************************/
+void bnep_process_setup_conn_req (tBNEP_CONN *p_bcb, uint8_t *p_setup, uint8_t len)
+{
+    BNEP_TRACE_EVENT ("BNEP - bnep_process_setup_conn_req for CID: 0x%x", p_bcb->l2cap_cid);
+
+    if (p_bcb->con_state != BNEP_STATE_CONN_SETUP &&
+        p_bcb->con_state != BNEP_STATE_SEC_CHECKING &&
+        p_bcb->con_state != BNEP_STATE_CONNECTED)
+    {
+        BNEP_TRACE_ERROR ("BNEP - setup request in bad state %d", p_bcb->con_state);
+        bnep_send_conn_responce (p_bcb, BNEP_SETUP_CONN_NOT_ALLOWED);
+        return;
+    }
+
+    /* Check if we already initiated security check or if waiting for user responce */
+    if (p_bcb->con_flags & BNEP_FLAGS_SETUP_RCVD)
+    {
+        BNEP_TRACE_EVENT ("BNEP - Duplicate Setup message received while doing security check");
+        return;
+    }
+
+    /* Check if peer is the originator */
+    if (p_bcb->con_state != BNEP_STATE_CONNECTED &&
+        (!(p_bcb->con_flags & BNEP_FLAGS_SETUP_RCVD)) &&
+        (p_bcb->con_flags & BNEP_FLAGS_IS_ORIG))
+    {
+        BNEP_TRACE_ERROR ("BNEP - setup request when we are originator", p_bcb->con_state);
+        bnep_send_conn_responce (p_bcb, BNEP_SETUP_CONN_NOT_ALLOWED);
+        return;
+    }
+
+    if (p_bcb->con_state == BNEP_STATE_CONNECTED)
+    {
+        memcpy ((uint8_t *)&(p_bcb->prv_src_uuid), (uint8_t *)&(p_bcb->src_uuid), sizeof (tBT_UUID));
+        memcpy ((uint8_t *)&(p_bcb->prv_dst_uuid), (uint8_t *)&(p_bcb->dst_uuid), sizeof (tBT_UUID));
+    }
+
+    p_bcb->dst_uuid.len = p_bcb->src_uuid.len = len;
+
+    if (p_bcb->dst_uuid.len == 2)
+    {
+        /* because peer initiated connection keep src uuid as dst uuid */
+        BE_STREAM_TO_UINT16 (p_bcb->src_uuid.uu.uuid16, p_setup);
+        BE_STREAM_TO_UINT16 (p_bcb->dst_uuid.uu.uuid16, p_setup);
+
+        /* If nothing has changed don't bother the profile */
+        if (p_bcb->con_state == BNEP_STATE_CONNECTED &&
+            p_bcb->src_uuid.uu.uuid16 == p_bcb->prv_src_uuid.uu.uuid16 &&
+            p_bcb->dst_uuid.uu.uuid16 == p_bcb->prv_dst_uuid.uu.uuid16)
+        {
+            bnep_send_conn_responce (p_bcb, BNEP_SETUP_CONN_OK);
+            return;
+        }
+    }
+    else if (p_bcb->dst_uuid.len == 4)
+    {
+        BE_STREAM_TO_UINT32 (p_bcb->src_uuid.uu.uuid32, p_setup);
+        BE_STREAM_TO_UINT32 (p_bcb->dst_uuid.uu.uuid32, p_setup);
+    }
+    else if (p_bcb->dst_uuid.len == 16)
+    {
+        memcpy (p_bcb->src_uuid.uu.uuid128, p_setup, p_bcb->src_uuid.len);
+        p_setup += p_bcb->src_uuid.len;
+        memcpy (p_bcb->dst_uuid.uu.uuid128, p_setup, p_bcb->dst_uuid.len);
+        p_setup += p_bcb->dst_uuid.len;
+    }
+    else
+    {
+        BNEP_TRACE_ERROR ("BNEP - Bad UID len %d in ConnReq", p_bcb->dst_uuid.len);
+        bnep_send_conn_responce (p_bcb, BNEP_SETUP_INVALID_UUID_SIZE);
+        return;
+    }
+
+    p_bcb->con_state = BNEP_STATE_SEC_CHECKING;
+    p_bcb->con_flags |= BNEP_FLAGS_SETUP_RCVD;
+
+    BNEP_TRACE_EVENT ("BNEP initiating security check for incoming call for uuid 0x%x", p_bcb->src_uuid.uu.uuid16);
+#if (BNEP_DO_AUTH_FOR_ROLE_SWITCH == FALSE)
+    if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)
+        bnep_sec_check_complete (p_bcb->rem_bda, p_bcb, BTM_SUCCESS);
+    else
+#endif
+    btm_sec_mx_access_request (p_bcb->rem_bda, BT_PSM_BNEP, false,
+                               BTM_SEC_PROTO_BNEP, bnep_get_uuid32(&(p_bcb->src_uuid)),
+                               &bnep_sec_check_complete, p_bcb);
+
+    return;
+}
+
+
+/*******************************************************************************
+**
+** Function         bnep_process_setup_conn_responce
+**
+** Description      This function processes a peer's setup connection response
+**                  message. The response code is verified and
+**                  Connection open indication will be given to PAN profile
+**
+** Returns          void
+**
+*******************************************************************************/
+void bnep_process_setup_conn_responce (tBNEP_CONN *p_bcb, uint8_t *p_setup)
+{
+    tBNEP_RESULT    resp;
+    uint16_t        resp_code;
+
+    BNEP_TRACE_DEBUG ("BNEP received setup responce");
+    /* The state should be either SETUP or CONNECTED */
+    if (p_bcb->con_state != BNEP_STATE_CONN_SETUP)
+    {
+        /* Should we disconnect ? */
+        BNEP_TRACE_ERROR ("BNEP - setup response in bad state %d", p_bcb->con_state);
+        return;
+    }
+
+    /* Check if we are the originator */
+    if (!(p_bcb->con_flags & BNEP_FLAGS_IS_ORIG))
+    {
+        BNEP_TRACE_ERROR ("BNEP - setup response when we are not originator", p_bcb->con_state);
+        return;
+    }
+
+    BE_STREAM_TO_UINT16  (resp_code, p_setup);
+
+    switch (resp_code)
+    {
+    case BNEP_SETUP_INVALID_SRC_UUID:
+        resp = BNEP_CONN_FAILED_SRC_UUID;
+        break;
+
+    case BNEP_SETUP_INVALID_DEST_UUID:
+        resp = BNEP_CONN_FAILED_DST_UUID;
+        break;
+
+    case BNEP_SETUP_INVALID_UUID_SIZE:
+        resp = BNEP_CONN_FAILED_UUID_SIZE;
+        break;
+
+    case BNEP_SETUP_CONN_NOT_ALLOWED:
+    default:
+        resp = BNEP_CONN_FAILED;
+        break;
+    }
+
+    /* Check the responce code */
+    if (resp_code != BNEP_SETUP_CONN_OK)
+    {
+        if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)
+        {
+            BNEP_TRACE_EVENT ("BNEP - role change response is %d", resp_code);
+
+            /* Restore the earlier BNEP status */
+            p_bcb->con_state = BNEP_STATE_CONNECTED;
+            p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD);
+            memcpy ((uint8_t *)&(p_bcb->src_uuid), (uint8_t *)&(p_bcb->prv_src_uuid), sizeof (tBT_UUID));
+            memcpy ((uint8_t *)&(p_bcb->dst_uuid), (uint8_t *)&(p_bcb->prv_dst_uuid), sizeof (tBT_UUID));
+
+            /* Ensure timer is stopped */
+            alarm_cancel(p_bcb->conn_timer);
+            p_bcb->re_transmits = 0;
+
+            /* Tell the user if he has a callback */
+            if (bnep_cb.p_conn_state_cb)
+                (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, resp, true);
+
+            return;
+        }
+        else
+        {
+            BNEP_TRACE_ERROR ("BNEP - setup response %d is not OK", resp_code);
+
+            L2CA_DisconnectReq (p_bcb->l2cap_cid);
+
+            /* Tell the user if he has a callback */
+            if ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) && (bnep_cb.p_conn_state_cb))
+                (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, resp, false);
+
+            bnepu_release_bcb (p_bcb);
+            return;
+        }
+    }
+
+    /* Received successful responce */
+    bnep_connected (p_bcb);
+}
+
+
+/*******************************************************************************
+**
+** Function         bnep_process_control_packet
+**
+** Description      This function processes a peer's setup connection request
+**                  message. The destination UUID is verified and response sent
+**                  Connection open indication will be given to PAN profile
+**
+** Returns          void
+**
+*******************************************************************************/
+uint8_t *bnep_process_control_packet (tBNEP_CONN *p_bcb, uint8_t *p, uint16_t *rem_len, bool    is_ext)
+{
+    uint8_t     control_type;
+    bool        bad_pkt = false;
+    uint16_t    len, ext_len = 0;
+
+    if (is_ext)
+    {
+        ext_len = *p++;
+        *rem_len = *rem_len - 1;
+    }
+
+    control_type = *p++;
+    *rem_len = *rem_len - 1;
+
+    BNEP_TRACE_EVENT ("BNEP processing control packet rem_len %d, is_ext %d, ctrl_type %d", *rem_len, is_ext, control_type);
+
+    switch (control_type)
+    {
+    case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
+        BNEP_TRACE_ERROR ("BNEP Received Cmd not understood for ctl pkt type: %d", *p);
+        p++;
+        *rem_len = *rem_len - 1;
+        break;
+
+    case BNEP_SETUP_CONNECTION_REQUEST_MSG:
+        len = *p++;
+        if (*rem_len < ((2 * len) + 1))
+        {
+            bad_pkt = true;
+            BNEP_TRACE_ERROR ("BNEP Received Setup message with bad length");
+            break;
+        }
+        if (!is_ext)
+            bnep_process_setup_conn_req (p_bcb, p, (uint8_t)len);
+        p += (2 * len);
+        *rem_len = *rem_len - (2 * len) - 1;
+        break;
+
+    case BNEP_SETUP_CONNECTION_RESPONSE_MSG:
+        if (!is_ext)
+            bnep_process_setup_conn_responce (p_bcb, p);
+        p += 2;
+        *rem_len = *rem_len - 2;
+        break;
+
+    case BNEP_FILTER_NET_TYPE_SET_MSG:
+        BE_STREAM_TO_UINT16 (len, p);
+        if (*rem_len < (len + 2))
+        {
+            bad_pkt = true;
+            BNEP_TRACE_ERROR ("BNEP Received Filter set message with bad length");
+            break;
+        }
+        bnepu_process_peer_filter_set (p_bcb, p, len);
+        p += len;
+        *rem_len = *rem_len - len - 2;
+        break;
+
+    case BNEP_FILTER_NET_TYPE_RESPONSE_MSG:
+        bnepu_process_peer_filter_rsp (p_bcb, p);
+        p += 2;
+        *rem_len = *rem_len - 2;
+        break;
+
+    case BNEP_FILTER_MULTI_ADDR_SET_MSG:
+        BE_STREAM_TO_UINT16 (len, p);
+        if (*rem_len < (len + 2))
+        {
+            bad_pkt = true;
+            BNEP_TRACE_ERROR ("BNEP Received Multicast Filter Set message with bad length");
+            break;
+        }
+        bnepu_process_peer_multicast_filter_set (p_bcb, p, len);
+        p += len;
+        *rem_len = *rem_len - len - 2;
+        break;
+
+    case BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG:
+        bnepu_process_multicast_filter_rsp (p_bcb, p);
+        p += 2;
+        *rem_len = *rem_len - 2;
+        break;
+
+    default :
+        BNEP_TRACE_ERROR ("BNEP - bad ctl pkt type: %d", control_type);
+        bnep_send_command_not_understood (p_bcb, control_type);
+        if (is_ext)
+        {
+            p += (ext_len - 1);
+            *rem_len -= (ext_len - 1);
+        }
+        break;
+    }
+
+    if (bad_pkt)
+    {
+        BNEP_TRACE_ERROR ("BNEP - bad ctl pkt length: %d", *rem_len);
+        *rem_len = 0;
+        return NULL;
+    }
+
+    return p;
+}
+
+
+/*******************************************************************************
+**
+** Function         bnepu_process_peer_filter_set
+**
+** Description      This function processes a peer's filter control
+**                  'set' message. The filters are stored in the BCB,
+**                  and an appropriate filter response message sent.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bnepu_process_peer_filter_set (tBNEP_CONN *p_bcb, uint8_t *p_filters, uint16_t len)
+{
+    uint16_t    num_filters = 0;
+    uint16_t    xx, resp_code = BNEP_FILTER_CRL_OK;
+    uint16_t    start, end;
+    uint8_t     *p_temp_filters;
+
+    if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+        (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
+    {
+        BNEP_TRACE_DEBUG ("BNEP received filter set from peer when there is no connection");
+        return;
+    }
+
+    BNEP_TRACE_DEBUG ("BNEP received filter set from peer");
+    /* Check for length not a multiple of 4 */
+    if (len & 3)
+    {
+        BNEP_TRACE_EVENT ("BNEP - bad filter len: %d", len);
+        bnepu_send_peer_filter_rsp (p_bcb, BNEP_FILTER_CRL_BAD_RANGE);
+        return;
+    }
+
+    if (len)
+        num_filters = (uint16_t) (len >> 2);
+
+    /* Validate filter values */
+    if (num_filters <= BNEP_MAX_PROT_FILTERS)
+    {
+        p_temp_filters = p_filters;
+        for (xx = 0; xx < num_filters; xx++)
+        {
+            BE_STREAM_TO_UINT16  (start, p_temp_filters);
+            BE_STREAM_TO_UINT16  (end,   p_temp_filters);
+
+            if (start > end)
+            {
+                resp_code = BNEP_FILTER_CRL_BAD_RANGE;
+                break;
+            }
+        }
+    }
+    else
+        resp_code   = BNEP_FILTER_CRL_MAX_REACHED;
+
+    if (resp_code != BNEP_FILTER_CRL_OK)
+    {
+        bnepu_send_peer_filter_rsp (p_bcb, resp_code);
+        return;
+    }
+
+    if (bnep_cb.p_filter_ind_cb)
+        (*bnep_cb.p_filter_ind_cb) (p_bcb->handle, true, 0, len, p_filters);
+
+    p_bcb->rcvd_num_filters = num_filters;
+    for (xx = 0; xx < num_filters; xx++)
+    {
+        BE_STREAM_TO_UINT16  (start, p_filters);
+        BE_STREAM_TO_UINT16  (end,   p_filters);
+
+        p_bcb->rcvd_prot_filter_start[xx] = start;
+        p_bcb->rcvd_prot_filter_end[xx]   = end;
+    }
+
+    bnepu_send_peer_filter_rsp (p_bcb, resp_code);
+}
+
+
+/*******************************************************************************
+**
+** Function         bnepu_process_peer_filter_rsp
+**
+** Description      This function processes a peer's filter control
+**                  'response' message.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bnepu_process_peer_filter_rsp (tBNEP_CONN *p_bcb, uint8_t *p_data)
+{
+    uint16_t        resp_code;
+    tBNEP_RESULT    result;
+
+    BNEP_TRACE_DEBUG ("BNEP received filter responce");
+    /* The state should be  CONNECTED */
+    if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+        (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
+    {
+        BNEP_TRACE_ERROR ("BNEP - filter response in bad state %d", p_bcb->con_state);
+        return;
+    }
+
+    /* Check if we are the originator */
+    if (!(p_bcb->con_flags & BNEP_FLAGS_FILTER_RESP_PEND))
+    {
+        BNEP_TRACE_ERROR ("BNEP - filter response when not expecting");
+        return;
+    }
+
+    /* Ensure timer is stopped */
+    alarm_cancel(p_bcb->conn_timer);
+    p_bcb->con_flags &= ~BNEP_FLAGS_FILTER_RESP_PEND;
+    p_bcb->re_transmits = 0;
+
+    BE_STREAM_TO_UINT16  (resp_code, p_data);
+
+    result = BNEP_SUCCESS;
+    if (resp_code != BNEP_FILTER_CRL_OK)
+        result = BNEP_SET_FILTER_FAIL;
+
+    if (bnep_cb.p_filter_ind_cb)
+        (*bnep_cb.p_filter_ind_cb) (p_bcb->handle, false, result, 0, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         bnepu_process_multicast_filter_rsp
+**
+** Description      This function processes multicast filter control
+**                  'response' message.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bnepu_process_multicast_filter_rsp (tBNEP_CONN *p_bcb, uint8_t *p_data)
+{
+    uint16_t        resp_code;
+    tBNEP_RESULT    result;
+
+    BNEP_TRACE_DEBUG ("BNEP received multicast filter responce");
+    /* The state should be  CONNECTED */
+    if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+        (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
+    {
+        BNEP_TRACE_ERROR ("BNEP - multicast filter response in bad state %d", p_bcb->con_state);
+        return;
+    }
+
+    /* Check if we are the originator */
+    if (!(p_bcb->con_flags & BNEP_FLAGS_MULTI_RESP_PEND))
+    {
+        BNEP_TRACE_ERROR ("BNEP - multicast filter response when not expecting");
+        return;
+    }
+
+    /* Ensure timer is stopped */
+    alarm_cancel(p_bcb->conn_timer);
+    p_bcb->con_flags &= ~BNEP_FLAGS_MULTI_RESP_PEND;
+    p_bcb->re_transmits = 0;
+
+    BE_STREAM_TO_UINT16  (resp_code, p_data);
+
+    result = BNEP_SUCCESS;
+    if (resp_code != BNEP_FILTER_CRL_OK)
+        result = BNEP_SET_FILTER_FAIL;
+
+    if (bnep_cb.p_mfilter_ind_cb)
+        (*bnep_cb.p_mfilter_ind_cb) (p_bcb->handle, false, result, 0, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         bnepu_process_peer_multicast_filter_set
+**
+** Description      This function processes a peer's filter control
+**                  'set' message. The filters are stored in the BCB,
+**                  and an appropriate filter response message sent.
+**
+** Returns          void
+**
+*******************************************************************************/
+void bnepu_process_peer_multicast_filter_set (tBNEP_CONN *p_bcb, uint8_t *p_filters, uint16_t len)
+{
+    uint16_t        resp_code = BNEP_FILTER_CRL_OK;
+    uint16_t        num_filters, xx;
+    uint8_t         *p_temp_filters, null_bda[BD_ADDR_LEN] = {0,0,0,0,0,0};
+
+    if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+        (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
+    {
+        BNEP_TRACE_DEBUG ("BNEP received multicast filter set from peer when there is no connection");
+        return;
+    }
+
+    if (len % 12)
+    {
+        BNEP_TRACE_EVENT ("BNEP - bad filter len: %d", len);
+        bnepu_send_peer_multicast_filter_rsp (p_bcb, BNEP_FILTER_CRL_BAD_RANGE);
+        return;
+    }
+
+    if (len > (BNEP_MAX_MULTI_FILTERS * 2 * BD_ADDR_LEN))
+    {
+        BNEP_TRACE_EVENT ("BNEP - Too many filters");
+        bnepu_send_peer_multicast_filter_rsp (p_bcb, BNEP_FILTER_CRL_MAX_REACHED);
+        return;
+    }
+
+    num_filters = 0;
+    if (len)
+        num_filters = (uint16_t) (len / 12);
+
+    /* Validate filter values */
+    if (num_filters <= BNEP_MAX_MULTI_FILTERS)
+    {
+        p_temp_filters = p_filters;
+        for (xx = 0; xx < num_filters; xx++)
+        {
+            if (memcmp (p_temp_filters, p_temp_filters + BD_ADDR_LEN, BD_ADDR_LEN) > 0)
+            {
+                bnepu_send_peer_multicast_filter_rsp (p_bcb, BNEP_FILTER_CRL_BAD_RANGE);
+                return;
+            }
+
+            p_temp_filters += (BD_ADDR_LEN * 2);
+        }
+    }
+
+    p_bcb->rcvd_mcast_filters = num_filters;
+    for (xx = 0; xx < num_filters; xx++)
+    {
+        memcpy (p_bcb->rcvd_mcast_filter_start[xx], p_filters, BD_ADDR_LEN);
+        memcpy (p_bcb->rcvd_mcast_filter_end[xx], p_filters + BD_ADDR_LEN, BD_ADDR_LEN);
+        p_filters += (BD_ADDR_LEN * 2);
+
+        /* Check if any of the ranges have all zeros as both starting and ending addresses */
+        if ((memcmp (null_bda, p_bcb->rcvd_mcast_filter_start[xx], BD_ADDR_LEN) == 0) &&
+            (memcmp (null_bda, p_bcb->rcvd_mcast_filter_end[xx], BD_ADDR_LEN) == 0))
+        {
+            p_bcb->rcvd_mcast_filters = 0xFFFF;
+            break;
+        }
+    }
+
+    BNEP_TRACE_EVENT ("BNEP multicast filters %d", p_bcb->rcvd_mcast_filters);
+    bnepu_send_peer_multicast_filter_rsp (p_bcb, resp_code);
+
+    if (bnep_cb.p_mfilter_ind_cb)
+        (*bnep_cb.p_mfilter_ind_cb) (p_bcb->handle, true, 0, len, p_filters);
+}
+
+
+/*******************************************************************************
+**
+** Function         bnepu_send_peer_multicast_filter_rsp
+**
+** Description      This function sends a filter response to a peer
+**
+** Returns          void
+**
+*******************************************************************************/
+void bnepu_send_peer_multicast_filter_rsp (tBNEP_CONN *p_bcb, uint16_t response_code)
+{
+    BT_HDR  *p_buf = (BT_HDR *)osi_malloc(BNEP_BUF_SIZE);
+    uint8_t *p;
+
+    BNEP_TRACE_DEBUG ("BNEP sending multicast filter response %d", response_code);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+    /* Put in BNEP frame type - filter control */
+    UINT8_TO_BE_STREAM (p, BNEP_FRAME_CONTROL);
+
+    /* Put in filter message type - set filters */
+    UINT8_TO_BE_STREAM (p, BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG);
+
+    UINT16_TO_BE_STREAM (p, response_code);
+
+    p_buf->len = 4;
+
+    bnepu_check_send_packet (p_bcb, p_buf);
+}
+
+
+
+/*******************************************************************************
+**
+** Function         bnep_sec_check_complete
+**
+** Description      This function is registered with BTM and will be called
+**                  after completing the security procedures
+**
+** Returns          void
+**
+*******************************************************************************/
+void bnep_sec_check_complete (UNUSED_ATTR BD_ADDR bd_addr, UNUSED_ATTR tBT_TRANSPORT trasnport,
+                                    void *p_ref_data, uint8_t result)
+{
+    tBNEP_CONN      *p_bcb = (tBNEP_CONN *)p_ref_data;
+    uint16_t        resp_code = BNEP_SETUP_CONN_OK;
+    bool            is_role_change;
+
+    BNEP_TRACE_EVENT ("BNEP security callback returned result %d", result);
+    if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)
+        is_role_change = true;
+    else
+        is_role_change = false;
+
+    /* check if the port is still waiting for security to complete */
+    if (p_bcb->con_state != BNEP_STATE_SEC_CHECKING)
+    {
+        BNEP_TRACE_ERROR ("BNEP Connection in wrong state %d when security is completed", p_bcb->con_state);
+        return;
+    }
+
+    /* if it is outgoing call and result is FAILURE return security fail error */
+    if (!(p_bcb->con_flags & BNEP_FLAGS_SETUP_RCVD))
+    {
+        if (result != BTM_SUCCESS)
+        {
+            if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)
+            {
+                /* Tell the user that role change is failed because of security */
+                if (bnep_cb.p_conn_state_cb)
+                    (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_SECURITY_FAIL, is_role_change);
+
+                p_bcb->con_state = BNEP_STATE_CONNECTED;
+                memcpy ((uint8_t *)&(p_bcb->src_uuid), (uint8_t *)&(p_bcb->prv_src_uuid), sizeof (tBT_UUID));
+                memcpy ((uint8_t *)&(p_bcb->dst_uuid), (uint8_t *)&(p_bcb->prv_dst_uuid), sizeof (tBT_UUID));
+                return;
+            }
+
+            L2CA_DisconnectReq (p_bcb->l2cap_cid);
+
+            /* Tell the user if he has a callback */
+            if (bnep_cb.p_conn_state_cb)
+                (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_SECURITY_FAIL, is_role_change);
+
+            bnepu_release_bcb (p_bcb);
+            return;
+        }
+
+        /* Transition to the next appropriate state, waiting for connection confirm. */
+        p_bcb->con_state = BNEP_STATE_CONN_SETUP;
+
+        bnep_send_conn_req (p_bcb);
+        alarm_set_on_queue(p_bcb->conn_timer, BNEP_CONN_TIMEOUT_MS,
+                           bnep_conn_timer_timeout, p_bcb,
+                           btu_general_alarm_queue);
+        return;
+    }
+
+    /* it is an incoming call respond appropriately */
+    if (result != BTM_SUCCESS)
+    {
+        bnep_send_conn_responce (p_bcb, BNEP_SETUP_CONN_NOT_ALLOWED);
+        if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)
+        {
+            /* Role change is failed because of security. Revert back to connected state */
+            p_bcb->con_state = BNEP_STATE_CONNECTED;
+            p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD);
+            memcpy ((uint8_t *)&(p_bcb->src_uuid), (uint8_t *)&(p_bcb->prv_src_uuid), sizeof (tBT_UUID));
+            memcpy ((uint8_t *)&(p_bcb->dst_uuid), (uint8_t *)&(p_bcb->prv_dst_uuid), sizeof (tBT_UUID));
+            return;
+        }
+
+        L2CA_DisconnectReq (p_bcb->l2cap_cid);
+
+        bnepu_release_bcb (p_bcb);
+        return;
+    }
+
+    if (bnep_cb.p_conn_ind_cb)
+    {
+        p_bcb->con_state = BNEP_STATE_CONN_SETUP;
+        (*bnep_cb.p_conn_ind_cb) (p_bcb->handle, p_bcb->rem_bda, &p_bcb->dst_uuid, &p_bcb->src_uuid, is_role_change);
+    }
+    else
+    {
+        /* Profile didn't register connection indication call back */
+        bnep_send_conn_responce (p_bcb, resp_code);
+        bnep_connected (p_bcb);
+    }
+
+    return;
+}
+
+
+/*******************************************************************************
+**
+** Function         bnep_is_packet_allowed
+**
+** Description      This function verifies whether the protocol passes through
+**                  the protocol filters set by the peer
+**
+** Returns          BNEP_SUCCESS          - if the protocol is allowed
+**                  BNEP_IGNORE_CMD       - if the protocol is filtered out
+**
+*******************************************************************************/
+tBNEP_RESULT bnep_is_packet_allowed (tBNEP_CONN *p_bcb,
+                                     BD_ADDR p_dest_addr,
+                                     uint16_t protocol,
+                                     bool    fw_ext_present,
+                                     uint8_t *p_data)
+{
+    if (p_bcb->rcvd_num_filters)
+    {
+        uint16_t        i, proto;
+
+        /* Findout the actual protocol to check for the filtering */
+        proto = protocol;
+        if (proto == BNEP_802_1_P_PROTOCOL)
+        {
+            if (fw_ext_present)
+            {
+                uint8_t     len, ext;
+                /* parse the extension headers and findout actual protocol */
+                do {
+
+                    ext     = *p_data++;
+                    len     = *p_data++;
+                    p_data += len;
+
+                } while (ext & 0x80);
+            }
+            p_data += 2;
+            BE_STREAM_TO_UINT16 (proto, p_data);
+        }
+
+        for (i=0; i<p_bcb->rcvd_num_filters; i++)
+        {
+            if ((p_bcb->rcvd_prot_filter_start[i] <= proto) &&
+                (proto <= p_bcb->rcvd_prot_filter_end[i]))
+                break;
+        }
+
+        if (i == p_bcb->rcvd_num_filters)
+        {
+            BNEP_TRACE_DEBUG ("Ignoring protocol 0x%x in BNEP data write", proto);
+            return BNEP_IGNORE_CMD;
+        }
+    }
+
+    /* Ckeck for multicast address filtering */
+    if ((p_dest_addr[0] & 0x01) &&
+        p_bcb->rcvd_mcast_filters)
+    {
+        uint16_t        i;
+
+        /* Check if every multicast should be filtered */
+        if (p_bcb->rcvd_mcast_filters != 0xFFFF)
+        {
+            /* Check if the address is mentioned in the filter range */
+            for (i = 0; i < p_bcb->rcvd_mcast_filters; i++)
+            {
+                if ((memcmp (p_bcb->rcvd_mcast_filter_start[i], p_dest_addr, BD_ADDR_LEN) <= 0) &&
+                    (memcmp (p_bcb->rcvd_mcast_filter_end[i], p_dest_addr, BD_ADDR_LEN) >= 0))
+                    break;
+            }
+        }
+
+        /*
+        ** If every multicast should be filtered or the address is not in the filter range
+        ** drop the packet
+        */
+        if ((p_bcb->rcvd_mcast_filters == 0xFFFF) || (i == p_bcb->rcvd_mcast_filters))
+        {
+            BNEP_TRACE_DEBUG ("Ignoring multicast address %x.%x.%x.%x.%x.%x in BNEP data write",
+                p_dest_addr[0], p_dest_addr[1], p_dest_addr[2],
+                p_dest_addr[3], p_dest_addr[4], p_dest_addr[5]);
+            return BNEP_IGNORE_CMD;
+        }
+    }
+
+    return BNEP_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         bnep_get_uuid32
+**
+** Description      This function returns the 32 bit equivalent of the given UUID
+**
+** Returns          uint32_t        - 32 bit equivalent of the UUID
+**
+*******************************************************************************/
+uint32_t bnep_get_uuid32 (tBT_UUID *src_uuid)
+{
+    uint32_t    result;
+
+    if (src_uuid->len == 2)
+        return ((uint32_t)src_uuid->uu.uuid16);
+    else if (src_uuid->len == 4)
+        return (src_uuid->uu.uuid32 & 0x0000FFFF);
+    else
+    {
+        result = src_uuid->uu.uuid128[2];
+        result = (result << 8) | (src_uuid->uu.uuid128[3]);
+        return result;
+    }
+}
diff --git a/bt/stack/btm/ble_advertiser_hci_interface.cc b/bt/stack/btm/ble_advertiser_hci_interface.cc
new file mode 100644
index 0000000..4b5359e
--- /dev/null
+++ b/bt/stack/btm/ble_advertiser_hci_interface.cc
@@ -0,0 +1,226 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "ble_advertiser_hci_interface.h"
+#include <base/callback.h>
+#include <base/logging.h>
+#include <queue>
+#include <utility>
+#include "btm_api.h"
+#include "btm_ble_api.h"
+
+#define BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN 8
+#define BTM_BLE_MULTI_ADV_ENB_LEN 3
+#define BTM_BLE_MULTI_ADV_SET_PARAM_LEN 24
+#define BTM_BLE_AD_DATA_LEN 31
+#define BTM_BLE_MULTI_ADV_WRITE_DATA_LEN (BTM_BLE_AD_DATA_LEN + 3)
+
+using status_cb = BleAdvertiserHciInterface::status_cb;
+
+namespace {
+class BleAdvertiserHciInterfaceImpl;
+
+BleAdvertiserHciInterfaceImpl *instance = nullptr;
+std::queue<std::pair<int, status_cb>> *pending_ops = nullptr;
+
+void btm_ble_multi_adv_vsc_cmpl_cback(tBTM_VSC_CMPL *p_params) {
+  uint8_t status, subcode;
+  uint8_t *p = p_params->p_param_buf;
+  uint16_t len = p_params->param_len;
+
+  // All multi-adv commands respond with status and inst_id.
+  LOG_ASSERT(len == 2) << "Received bad response length to multi-adv VSC";
+
+  STREAM_TO_UINT8(status, p);
+  STREAM_TO_UINT8(subcode, p);
+
+  VLOG(1) << "subcode = " << +subcode << ", status: " << +status;
+
+  auto pending_op = pending_ops->front();
+  uint8_t opcode = pending_op.first;
+  pending_ops->pop();
+
+  if (opcode != subcode) {
+    LOG(ERROR) << "unexpected VSC cmpl, expect: " << +subcode
+               << " get: " << +opcode;
+    return;
+  }
+
+  pending_op.second.Run(status);
+}
+
+class BleAdvertiserHciInterfaceImpl : public BleAdvertiserHciInterface {
+  void SendVscMultiAdvCmd(uint8_t param_len, uint8_t *param_buf,
+                          status_cb command_complete) {
+    BTM_VendorSpecificCommand(HCI_BLE_MULTI_ADV_OCF, param_len, param_buf,
+                              btm_ble_multi_adv_vsc_cmpl_cback);
+    pending_ops->push(std::make_pair(param_buf[0], command_complete));
+  }
+
+  void ReadInstanceCount(base::Callback<void(uint8_t /* inst_cnt*/)> cb) override {
+    cb.Run(BTM_BleMaxMultiAdvInstanceCount());
+  }
+
+  void SetAdvertisingEventObserver(
+      AdvertisingEventObserver* observer) override {
+    this->advertising_event_observer = observer;
+  }
+
+  void SetParameters(uint32_t adv_int_min, uint32_t adv_int_max,
+                     uint8_t advertising_type, uint8_t own_address_type,
+                     BD_ADDR own_address, uint8_t direct_address_type,
+                     BD_ADDR direct_address, uint8_t channel_map,
+                     uint8_t filter_policy, uint8_t inst_id, uint8_t tx_power,
+                     status_cb command_complete) override {
+    VLOG(1) << __func__;
+    uint8_t param[BTM_BLE_MULTI_ADV_SET_PARAM_LEN];
+    memset(param, 0, BTM_BLE_MULTI_ADV_SET_PARAM_LEN);
+
+    uint8_t *pp = param;
+    UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_SET_PARAM);
+    UINT16_TO_STREAM(pp, adv_int_min);
+    UINT16_TO_STREAM(pp, adv_int_max);
+    UINT8_TO_STREAM(pp, advertising_type);
+    UINT8_TO_STREAM(pp, own_address_type);
+    BDADDR_TO_STREAM(pp, own_address);
+    UINT8_TO_STREAM(pp, direct_address_type);
+    BDADDR_TO_STREAM(pp, direct_address);
+    UINT8_TO_STREAM(pp, channel_map);
+    UINT8_TO_STREAM(pp, filter_policy);
+    UINT8_TO_STREAM(pp, inst_id);
+    UINT8_TO_STREAM(pp, tx_power);
+
+    SendVscMultiAdvCmd(BTM_BLE_MULTI_ADV_SET_PARAM_LEN, param,
+                       command_complete);
+  }
+
+  void SetAdvertisingData(uint8_t data_length, uint8_t *data, uint8_t inst_id,
+                          status_cb command_complete) override {
+    VLOG(1) << __func__;
+    uint8_t param[BTM_BLE_MULTI_ADV_WRITE_DATA_LEN];
+    memset(param, 0, BTM_BLE_MULTI_ADV_WRITE_DATA_LEN);
+
+    uint8_t *pp = param;
+    UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_WRITE_ADV_DATA);
+    UINT8_TO_STREAM(pp, data_length);
+    ARRAY_TO_STREAM(pp, data, data_length);
+    param[BTM_BLE_MULTI_ADV_WRITE_DATA_LEN - 1] = inst_id;
+
+    SendVscMultiAdvCmd((uint8_t)BTM_BLE_MULTI_ADV_WRITE_DATA_LEN, param,
+                       command_complete);
+  }
+
+  void SetScanResponseData(uint8_t scan_response_data_length,
+                           uint8_t *scan_response_data, uint8_t inst_id,
+                           status_cb command_complete) override {
+    VLOG(1) << __func__;
+    uint8_t param[BTM_BLE_MULTI_ADV_WRITE_DATA_LEN];
+    memset(param, 0, BTM_BLE_MULTI_ADV_WRITE_DATA_LEN);
+
+    uint8_t *pp = param;
+    UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_WRITE_SCAN_RSP_DATA);
+    UINT8_TO_STREAM(pp, scan_response_data_length);
+    ARRAY_TO_STREAM(pp, scan_response_data, scan_response_data_length);
+    param[BTM_BLE_MULTI_ADV_WRITE_DATA_LEN - 1] = inst_id;
+
+    SendVscMultiAdvCmd((uint8_t)BTM_BLE_MULTI_ADV_WRITE_DATA_LEN, param,
+                       command_complete);
+  }
+
+  void SetRandomAddress(uint8_t random_address[6], uint8_t inst_id,
+                        status_cb command_complete) override {
+    VLOG(1) << __func__;
+    uint8_t param[BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN];
+    memset(param, 0, BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN);
+
+    uint8_t *pp = param;
+    UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR);
+    BDADDR_TO_STREAM(pp, random_address);
+    UINT8_TO_STREAM(pp, inst_id);
+
+    SendVscMultiAdvCmd((uint8_t)BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN, param,
+                       command_complete);
+  }
+
+  void Enable(uint8_t advertising_enable, uint8_t inst_id,
+              status_cb command_complete) override {
+    VLOG(1) << __func__;
+    uint8_t param[BTM_BLE_MULTI_ADV_ENB_LEN];
+    memset(param, 0, BTM_BLE_MULTI_ADV_ENB_LEN);
+
+    uint8_t *pp = param;
+    UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_ENB);
+    UINT8_TO_STREAM(pp, advertising_enable);
+    UINT8_TO_STREAM(pp, inst_id);
+
+    SendVscMultiAdvCmd((uint8_t)BTM_BLE_MULTI_ADV_ENB_LEN, param,
+                       command_complete);
+  }
+
+ public:
+  static void VendorSpecificEventCback(uint8_t length, uint8_t *p) {
+    VLOG(1) << __func__;
+
+    LOG_ASSERT(p);
+    uint8_t sub_event, adv_inst, change_reason;
+    uint16_t conn_handle;
+
+    STREAM_TO_UINT8(sub_event, p);
+    length--;
+
+    if (sub_event != HCI_VSE_SUBCODE_BLE_MULTI_ADV_ST_CHG || length != 4) {
+      return;
+    }
+
+    STREAM_TO_UINT8(adv_inst, p);
+    STREAM_TO_UINT8(change_reason, p);
+    STREAM_TO_UINT16(conn_handle, p);
+
+    AdvertisingEventObserver* observer =
+        ((BleAdvertiserHciInterfaceImpl*)BleAdvertiserHciInterface::Get())
+            ->advertising_event_observer;
+    if (observer)
+      observer->OnAdvertisingStateChanged(adv_inst, change_reason, conn_handle);
+  }
+
+ private:
+  AdvertisingEventObserver* advertising_event_observer = nullptr;
+};
+}  // namespace
+
+void BleAdvertiserHciInterface::Initialize() {
+  VLOG(1) << __func__;
+  LOG_ASSERT(instance == nullptr) << "Was already initialized.";
+  instance = new BleAdvertiserHciInterfaceImpl();
+  pending_ops = new std::queue<std::pair<int, status_cb>>();
+
+  BTM_RegisterForVSEvents(
+      BleAdvertiserHciInterfaceImpl::VendorSpecificEventCback, true);
+}
+
+BleAdvertiserHciInterface *BleAdvertiserHciInterface::Get() { return instance; }
+
+void BleAdvertiserHciInterface::CleanUp() {
+  VLOG(1) << __func__;
+  BTM_RegisterForVSEvents(
+      BleAdvertiserHciInterfaceImpl::VendorSpecificEventCback, false);
+  delete pending_ops;
+  pending_ops = nullptr;
+  delete instance;
+  instance = nullptr;
+}
diff --git a/bt/stack/btm/ble_advertiser_hci_interface.h b/bt/stack/btm/ble_advertiser_hci_interface.h
new file mode 100644
index 0000000..76d5ea0
--- /dev/null
+++ b/bt/stack/btm/ble_advertiser_hci_interface.h
@@ -0,0 +1,68 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BLE_ADVERTISER_HCI_INTERFACE_H
+#define BLE_ADVERTISER_HCI_INTERFACE_H
+
+#include <base/bind.h>
+#include "stack/include/bt_types.h"
+
+/* This class is an abstraction of HCI commands used for managing
+ * advertisements. Please see VSC HCI SPEC at
+ * https://static.googleusercontent.com/media/source.android.com/en//devices/Android-6.0-Bluetooth-HCI-Reqs.pdf
+ * for more details  */
+class BleAdvertiserHciInterface {
+ public:
+  using status_cb = base::Callback<void(uint8_t /* status */)>;
+
+  static void Initialize();
+  static BleAdvertiserHciInterface *Get();
+  static void CleanUp();
+
+  virtual ~BleAdvertiserHciInterface() = default;
+
+  class AdvertisingEventObserver {
+   public:
+    virtual ~AdvertisingEventObserver() = default;
+    virtual void OnAdvertisingStateChanged(uint8_t inst_id,
+                                           uint8_t state_change_reason,
+                                           uint16_t connection_handle) = 0;
+  };
+
+  virtual void SetAdvertisingEventObserver(
+      AdvertisingEventObserver* observer) = 0;
+  virtual void ReadInstanceCount(base::Callback<void(uint8_t /* inst_cnt*/)> cb) = 0;
+  virtual void SetParameters(uint32_t adv_int_min, uint32_t adv_int_max,
+                             uint8_t advertising_type, uint8_t own_address_type,
+                             BD_ADDR own_address, uint8_t direct_address_type,
+                             BD_ADDR direct_address, uint8_t channel_map,
+                             uint8_t filter_policy, uint8_t inst_id,
+                             uint8_t tx_power, status_cb command_complete) = 0;
+  virtual void SetAdvertisingData(uint8_t data_length, uint8_t *data,
+                                  uint8_t inst_id,
+                                  status_cb command_complete) = 0;
+  virtual void SetScanResponseData(uint8_t scan_response_data_length,
+                                   uint8_t *scan_response_data, uint8_t inst_id,
+                                   status_cb command_complete) = 0;
+  virtual void SetRandomAddress(BD_ADDR random_address, uint8_t inst_id,
+                                status_cb command_complete) = 0;
+  virtual void Enable(uint8_t advertising_enable, uint8_t inst_id,
+                      status_cb command_complete) = 0;
+};
+
+#endif  // BLE_ADVERTISER_HCI_INTERFACE_H
diff --git a/bt/stack/btm/btm_acl.cc b/bt/stack/btm/btm_acl.cc
new file mode 100644
index 0000000..1e4e4a4
--- /dev/null
+++ b/bt/stack/btm/btm_acl.cc
@@ -0,0 +1,2583 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2000-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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+**
+**  Name:          btm_acl.cc
+**
+**  Description:   This file contains functions that handle ACL connections.
+**                 This includes operations such as hold and sniff modes,
+**                 supported packet types.
+**
+**                 This module contains both internal and external (API)
+**                 functions. External (API) functions are distinguishable
+**                 by their names beginning with uppercase BTM.
+**
+**
+******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "bt_types.h"
+#include "bt_target.h"
+#include "device/include/controller.h"
+#include "bt_common.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "l2c_int.h"
+#include "hcidefs.h"
+#include "bt_utils.h"
+#include "osi/include/osi.h"
+
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+static void btm_read_remote_features (uint16_t handle);
+static void btm_read_remote_ext_features (uint16_t handle, uint8_t page_number);
+static void btm_process_remote_ext_features (tACL_CONN *p_acl_cb, uint8_t num_read_pages);
+
+/* 3 seconds timeout waiting for responses */
+#define BTM_DEV_REPLY_TIMEOUT_MS (3 * 1000)
+
+/*******************************************************************************
+**
+** Function         btm_acl_init
+**
+** Description      This function is called at BTM startup to initialize
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_acl_init (void)
+{
+    BTM_TRACE_DEBUG ("btm_acl_init");
+    /* Initialize nonzero defaults */
+    btm_cb.btm_def_link_super_tout = HCI_DEFAULT_INACT_TOUT;
+    btm_cb.acl_disc_reason         = 0xff ;
+}
+
+/*******************************************************************************
+**
+** Function         btm_bda_to_acl
+**
+** Description      This function returns the FIRST acl_db entry for the passed BDA.
+**
+** Parameters      bda : BD address of the remote device
+**                 transport : Physical transport used for ACL connection (BR/EDR or LE)
+**
+** Returns          Returns pointer to the ACL DB for the requested BDA if found.
+**                  NULL if not found.
+**
+*******************************************************************************/
+tACL_CONN *btm_bda_to_acl (const BD_ADDR bda, tBT_TRANSPORT transport)
+{
+    tACL_CONN   *p = &btm_cb.acl_db[0];
+    uint16_t     xx;
+    if (bda)
+    {
+        for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++)
+        {
+            if ((p->in_use) && (!memcmp (p->remote_addr, bda, BD_ADDR_LEN))
+#if (BLE_INCLUDED == TRUE)
+                && p->transport == transport
+#endif
+                )
+            {
+                BTM_TRACE_DEBUG ("btm_bda_to_acl found");
+                return(p);
+            }
+        }
+    }
+
+    /* If here, no BD Addr found */
+    return((tACL_CONN *)NULL);
+}
+
+/*******************************************************************************
+**
+** Function         btm_handle_to_acl_index
+**
+** Description      This function returns the FIRST acl_db entry for the passed hci_handle.
+**
+** Returns          index to the acl_db or MAX_L2CAP_LINKS.
+**
+*******************************************************************************/
+uint8_t btm_handle_to_acl_index (uint16_t hci_handle)
+{
+    tACL_CONN   *p = &btm_cb.acl_db[0];
+    uint8_t     xx;
+    BTM_TRACE_DEBUG ("btm_handle_to_acl_index");
+    for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++)
+    {
+        if ((p->in_use) && (p->hci_handle == hci_handle))
+        {
+            break;
+        }
+    }
+
+    /* If here, no BD Addr found */
+    return(xx);
+}
+
+#if (BLE_PRIVACY_SPT == TRUE)
+/*******************************************************************************
+**
+** Function         btm_ble_get_acl_remote_addr
+**
+** Description      This function reads the active remote address used for the
+**                  connection.
+**
+** Returns          success return true, otherwise false.
+**
+*******************************************************************************/
+#if (BLE_INCLUDED == TRUE)
+bool    btm_ble_get_acl_remote_addr(tBTM_SEC_DEV_REC *p_dev_rec, BD_ADDR conn_addr,
+                                    tBLE_ADDR_TYPE *p_addr_type)
+{
+    bool            st = true;
+
+    if (p_dev_rec == NULL)
+    {
+        BTM_TRACE_ERROR("btm_ble_get_acl_remote_addr can not find device with matching address");
+        return false;
+    }
+
+    switch (p_dev_rec->ble.active_addr_type)
+    {
+    case BTM_BLE_ADDR_PSEUDO:
+        memcpy(conn_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
+        * p_addr_type = p_dev_rec->ble.ble_addr_type;
+        break;
+
+    case BTM_BLE_ADDR_RRA:
+        memcpy(conn_addr, p_dev_rec->ble.cur_rand_addr, BD_ADDR_LEN);
+        * p_addr_type = BLE_ADDR_RANDOM;
+        break;
+
+    case BTM_BLE_ADDR_STATIC:
+        memcpy(conn_addr, p_dev_rec->ble.static_addr, BD_ADDR_LEN);
+        * p_addr_type = p_dev_rec->ble.static_addr_type;
+        break;
+
+    default:
+        BTM_TRACE_ERROR("Unknown active address: %d", p_dev_rec->ble.active_addr_type);
+        st = false;
+        break;
+    }
+
+    return st;
+}
+#else
+bool    btm_ble_get_acl_remote_addr(UNUSED_ATTR tBTM_SEC_DEV_REC *p_dev_rec,
+                                    UNUSED_ATTR BD_ADDR conn_addr,
+                                    UNUSED_ATTR tBLE_ADDR_TYPE *p_addr_type)
+{
+    return false;
+}
+#endif
+#endif
+/*******************************************************************************
+**
+** Function         btm_acl_created
+**
+** Description      This function is called by L2CAP when an ACL connection
+**                  is created.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn,
+                      uint16_t hci_handle, uint8_t link_role, tBT_TRANSPORT transport)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+    tACL_CONN        *p;
+    uint8_t           xx;
+
+    BTM_TRACE_DEBUG ("btm_acl_created hci_handle=%d link_role=%d  transport=%d",
+                      hci_handle,link_role, transport);
+    /* Ensure we don't have duplicates */
+    p = btm_bda_to_acl(bda, transport);
+    if (p != (tACL_CONN *)NULL)
+    {
+        p->hci_handle = hci_handle;
+        p->link_role  = link_role;
+#if (BLE_INCLUDED == TRUE)
+        p->transport = transport;
+#endif
+        BTM_TRACE_DEBUG ("Duplicate btm_acl_created: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+                          bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+        BTM_SetLinkPolicy(p->remote_addr, &btm_cb.btm_def_link_policy);
+        return;
+    }
+
+    /* Allocate acl_db entry */
+    for (xx = 0, p = &btm_cb.acl_db[0]; xx < MAX_L2CAP_LINKS; xx++, p++)
+    {
+        if (!p->in_use)
+        {
+            p->in_use            = true;
+            p->hci_handle        = hci_handle;
+            p->link_role         = link_role;
+            p->link_up_issued    = false;
+            memcpy (p->remote_addr, bda, BD_ADDR_LEN);
+
+#if (BLE_INCLUDED == TRUE)
+            p->transport = transport;
+#if (BLE_PRIVACY_SPT == TRUE)
+            if (transport == BT_TRANSPORT_LE)
+                btm_ble_refresh_local_resolvable_private_addr(bda,
+                                                    btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr);
+#else
+            p->conn_addr_type = BLE_ADDR_PUBLIC;
+            memcpy(p->conn_addr, &controller_get_interface()->get_address()->address, BD_ADDR_LEN);
+
+#endif
+#endif
+            p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+
+            btm_pm_sm_alloc(xx);
+
+
+            if (dc)
+                memcpy (p->remote_dc, dc, DEV_CLASS_LEN);
+
+            if (bdn)
+                memcpy (p->remote_name, bdn, BTM_MAX_REM_BD_NAME_LEN);
+
+            /* if BR/EDR do something more */
+            if (transport == BT_TRANSPORT_BR_EDR)
+            {
+                btsnd_hcic_read_rmt_clk_offset (p->hci_handle);
+                btsnd_hcic_rmt_ver_req (p->hci_handle);
+            }
+            p_dev_rec = btm_find_dev_by_handle (hci_handle);
+
+#if (BLE_INCLUDED == TRUE)
+            if (p_dev_rec )
+            {
+                BTM_TRACE_DEBUG ("device_type=0x%x", p_dev_rec->device_type);
+            }
+#endif
+
+            if (p_dev_rec && !(transport == BT_TRANSPORT_LE))
+            {
+                /* If remote features already known, copy them and continue connection setup */
+                if ((p_dev_rec->num_read_pages) &&
+                    (p_dev_rec->num_read_pages <= (HCI_EXT_FEATURES_PAGE_MAX + 1)))
+                {
+                    memcpy (p->peer_lmp_features, p_dev_rec->features,
+                        (HCI_FEATURE_BYTES_PER_PAGE * p_dev_rec->num_read_pages));
+                    p->num_read_pages = p_dev_rec->num_read_pages;
+
+                    const uint8_t req_pend = (p_dev_rec->sm4 & BTM_SM4_REQ_PEND);
+
+                    /* Store the Peer Security Capabilites (in SM4 and rmt_sec_caps) */
+                    btm_sec_set_peer_sec_caps(p, p_dev_rec);
+
+                    BTM_TRACE_API("%s: pend:%d", __func__, req_pend);
+                    if (req_pend)
+                    {
+                        /* Request for remaining Security Features (if any) */
+                        l2cu_resubmit_pending_sec_req (p_dev_rec->bd_addr);
+                    }
+                    btm_establish_continue (p);
+                    return;
+                }
+            }
+
+#if (BLE_INCLUDED == TRUE)
+            /* If here, features are not known yet */
+            if (p_dev_rec && transport == BT_TRANSPORT_LE)
+            {
+#if (BLE_PRIVACY_SPT == TRUE)
+                btm_ble_get_acl_remote_addr (p_dev_rec, p->active_remote_addr,
+                    &p->active_remote_addr_type);
+#endif
+
+                if (HCI_LE_SLAVE_INIT_FEAT_EXC_SUPPORTED(controller_get_interface()->get_features_ble()->as_array)
+                    || link_role == HCI_ROLE_MASTER)
+                {
+                    btsnd_hcic_ble_read_remote_feat(p->hci_handle);
+                }
+                else
+                {
+                    btm_establish_continue(p);
+                }
+            }
+            else
+#endif
+            {
+                btm_read_remote_features (p->hci_handle);
+            }
+
+            /* read page 1 - on rmt feature event for buffer reasons */
+            return;
+        }
+    }
+}
+
+void btm_acl_update_conn_addr(uint8_t conn_handle, BD_ADDR address) {
+    uint8_t idx = btm_handle_to_acl_index(conn_handle);
+    if (idx != MAX_L2CAP_LINKS) {
+        memcpy(btm_cb.acl_db[idx].conn_addr, address, BD_ADDR_LEN);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_acl_report_role_change
+**
+** Description      This function is called when the local device is deemed
+**                  to be down. It notifies L2CAP of the failure.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_acl_report_role_change (uint8_t hci_status, BD_ADDR bda)
+{
+    tBTM_ROLE_SWITCH_CMPL   ref_data;
+    BTM_TRACE_DEBUG ("btm_acl_report_role_change");
+    if (btm_cb.devcb.p_switch_role_cb
+        && (bda && (0 == memcmp(btm_cb.devcb.switch_role_ref_data.remote_bd_addr, bda, BD_ADDR_LEN))))
+    {
+        memcpy (&ref_data, &btm_cb.devcb.switch_role_ref_data, sizeof(tBTM_ROLE_SWITCH_CMPL));
+        ref_data.hci_status = hci_status;
+        (*btm_cb.devcb.p_switch_role_cb)(&ref_data);
+        memset (&btm_cb.devcb.switch_role_ref_data, 0, sizeof(tBTM_ROLE_SWITCH_CMPL));
+        btm_cb.devcb.p_switch_role_cb = NULL;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_acl_removed
+**
+** Description      This function is called by L2CAP when an ACL connection
+**                  is removed. Since only L2CAP creates ACL links, we use
+**                  the L2CAP link index as our index into the control blocks.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_acl_removed (BD_ADDR bda, tBT_TRANSPORT transport)
+{
+    tACL_CONN   *p;
+    tBTM_BL_EVENT_DATA  evt_data;
+#if (BLE_INCLUDED == TRUE)
+    tBTM_SEC_DEV_REC *p_dev_rec=NULL;
+#endif
+    BTM_TRACE_DEBUG ("btm_acl_removed");
+    p = btm_bda_to_acl(bda, transport);
+    if (p != (tACL_CONN *)NULL)
+    {
+        p->in_use = false;
+
+        /* if the disconnected channel has a pending role switch, clear it now */
+        btm_acl_report_role_change(HCI_ERR_NO_CONNECTION, bda);
+
+        /* Only notify if link up has had a chance to be issued */
+        if (p->link_up_issued)
+        {
+            p->link_up_issued = false;
+
+            /* If anyone cares, tell him database changed */
+            if (btm_cb.p_bl_changed_cb)
+            {
+                evt_data.event = BTM_BL_DISCN_EVT;
+                evt_data.discn.p_bda = bda;
+#if (BLE_INCLUDED == TRUE)
+                evt_data.discn.handle = p->hci_handle;
+                evt_data.discn.transport = p->transport;
+#endif
+                (*btm_cb.p_bl_changed_cb)(&evt_data);
+            }
+
+            btm_acl_update_busy_level (BTM_BLI_ACL_DOWN_EVT);
+        }
+
+#if (BLE_INCLUDED == TRUE)
+
+        BTM_TRACE_DEBUG ("acl hci_handle=%d transport=%d connectable_mode=0x%0x link_role=%d",
+                          p->hci_handle,
+                          p->transport,
+                          btm_cb.ble_ctr_cb.inq_var.connectable_mode,
+                          p->link_role);
+
+        p_dev_rec = btm_find_dev(bda);
+        if ( p_dev_rec)
+        {
+            BTM_TRACE_DEBUG("before update p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags);
+            if (p->transport == BT_TRANSPORT_LE)
+            {
+                BTM_TRACE_DEBUG("LE link down");
+                p_dev_rec->sec_flags &= ~(BTM_SEC_LE_ENCRYPTED | BTM_SEC_ROLE_SWITCHED);
+                if ( (p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_KNOWN) == 0)
+                {
+                    BTM_TRACE_DEBUG("Not Bonded");
+                    p_dev_rec->sec_flags &= ~(BTM_SEC_LE_LINK_KEY_AUTHED | BTM_SEC_LE_AUTHENTICATED);
+                }
+                else
+                {
+                    BTM_TRACE_DEBUG("Bonded");
+                }
+            }
+            else
+            {
+                BTM_TRACE_DEBUG("Bletooth link down");
+                p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED
+                                        | BTM_SEC_ENCRYPTED | BTM_SEC_ROLE_SWITCHED);
+            }
+            BTM_TRACE_DEBUG("after update p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags);
+        }
+        else
+        {
+            BTM_TRACE_ERROR("Device not found");
+
+        }
+#endif
+
+        /* Clear the ACL connection data */
+        memset(p, 0, sizeof(tACL_CONN));
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         btm_acl_device_down
+**
+** Description      This function is called when the local device is deemed
+**                  to be down. It notifies L2CAP of the failure.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_acl_device_down (void)
+{
+    tACL_CONN   *p = &btm_cb.acl_db[0];
+    uint16_t    xx;
+    BTM_TRACE_DEBUG ("btm_acl_device_down");
+    for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++)
+    {
+        if (p->in_use)
+        {
+            BTM_TRACE_DEBUG ("hci_handle=%d HCI_ERR_HW_FAILURE ",p->hci_handle );
+            l2c_link_hci_disc_comp (p->hci_handle, HCI_ERR_HW_FAILURE);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_acl_update_busy_level
+**
+** Description      This function is called to update the busy level of the system
+**                  .
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_acl_update_busy_level (tBTM_BLI_EVENT event)
+{
+    bool    old_inquiry_state = btm_cb.is_inquiry;
+    tBTM_BL_UPDATE_DATA  evt;
+    evt.busy_level_flags = 0;
+    switch (event)
+    {
+        case BTM_BLI_ACL_UP_EVT:
+            BTM_TRACE_DEBUG ("BTM_BLI_ACL_UP_EVT");
+            break;
+        case BTM_BLI_ACL_DOWN_EVT:
+            BTM_TRACE_DEBUG ("BTM_BLI_ACL_DOWN_EVT");
+            break;
+        case BTM_BLI_PAGE_EVT:
+            BTM_TRACE_DEBUG ("BTM_BLI_PAGE_EVT");
+            btm_cb.is_paging = true;
+            evt.busy_level_flags= BTM_BL_PAGING_STARTED;
+            break;
+        case BTM_BLI_PAGE_DONE_EVT:
+            BTM_TRACE_DEBUG ("BTM_BLI_PAGE_DONE_EVT");
+            btm_cb.is_paging = false;
+            evt.busy_level_flags = BTM_BL_PAGING_COMPLETE;
+            break;
+        case BTM_BLI_INQ_EVT:
+            BTM_TRACE_DEBUG ("BTM_BLI_INQ_EVT");
+            btm_cb.is_inquiry = true;
+            evt.busy_level_flags = BTM_BL_INQUIRY_STARTED;
+            break;
+        case BTM_BLI_INQ_CANCEL_EVT:
+            BTM_TRACE_DEBUG ("BTM_BLI_INQ_CANCEL_EVT");
+            btm_cb.is_inquiry = false;
+            evt.busy_level_flags = BTM_BL_INQUIRY_CANCELLED;
+            break;
+        case BTM_BLI_INQ_DONE_EVT:
+            BTM_TRACE_DEBUG ("BTM_BLI_INQ_DONE_EVT");
+            btm_cb.is_inquiry = false;
+            evt.busy_level_flags = BTM_BL_INQUIRY_COMPLETE;
+            break;
+    }
+
+    uint8_t busy_level;
+    if (btm_cb.is_paging || btm_cb.is_inquiry)
+        busy_level = 10;
+    else
+        busy_level = BTM_GetNumAclLinks();
+
+    if ((busy_level != btm_cb.busy_level) ||(old_inquiry_state != btm_cb.is_inquiry))
+    {
+        evt.event         = BTM_BL_UPDATE_EVT;
+        evt.busy_level    = busy_level;
+        btm_cb.busy_level = busy_level;
+        if (btm_cb.p_bl_changed_cb && (btm_cb.bl_evt_mask & BTM_BL_UPDATE_MASK))
+        {
+            (*btm_cb.p_bl_changed_cb)((tBTM_BL_EVENT_DATA *)&evt);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** 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 (BD_ADDR remote_bd_addr, uint8_t *p_role)
+{
+    tACL_CONN   *p;
+    BTM_TRACE_DEBUG ("BTM_GetRole");
+    if ((p = btm_bda_to_acl(remote_bd_addr, BT_TRANSPORT_BR_EDR)) == NULL)
+    {
+        *p_role = BTM_ROLE_UNDEFINED;
+        return(BTM_UNKNOWN_ADDR);
+    }
+
+    /* Get the current role */
+    *p_role = p->link_role;
+    return(BTM_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** 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 couldn't allocate memory to issue command
+**                  BTM_UNKNOWN_ADDR if no active link with bd addr specified
+**                  BTM_MODE_UNSUPPORTED if local device does not support role switching
+**                  BTM_BUSY if the previous command is not completed
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SwitchRole (BD_ADDR remote_bd_addr, uint8_t new_role, tBTM_CMPL_CB *p_cb)
+{
+    tACL_CONN   *p;
+    tBTM_SEC_DEV_REC  *p_dev_rec = NULL;
+#if (BTM_SCO_INCLUDED == TRUE)
+    bool       is_sco_active;
+#endif
+    tBTM_STATUS  status;
+    tBTM_PM_MODE pwr_mode;
+    tBTM_PM_PWR_MD settings;
+    BD_ADDR_PTR  p_bda;
+    BTM_TRACE_API ("BTM_SwitchRole BDA: %02x-%02x-%02x-%02x-%02x-%02x",
+                    remote_bd_addr[0], remote_bd_addr[1], remote_bd_addr[2],
+                    remote_bd_addr[3], remote_bd_addr[4], remote_bd_addr[5]);
+
+    /* Make sure the local device supports switching */
+    if (!controller_get_interface()->supports_master_slave_role_switch())
+        return(BTM_MODE_UNSUPPORTED);
+
+    if (btm_cb.devcb.p_switch_role_cb && p_cb)
+    {
+        p_bda = btm_cb.devcb.switch_role_ref_data.remote_bd_addr;
+        BTM_TRACE_DEBUG ("Role switch on other device is in progress 0x%02x%02x%02x%02x%02x%02x",
+                          p_bda[0], p_bda[1], p_bda[2],
+                          p_bda[3], p_bda[4], p_bda[5]);
+        return(BTM_BUSY);
+    }
+
+    if ((p = btm_bda_to_acl(remote_bd_addr, BT_TRANSPORT_BR_EDR)) == NULL)
+        return(BTM_UNKNOWN_ADDR);
+
+    /* Finished if already in desired role */
+    if (p->link_role == new_role)
+        return(BTM_SUCCESS);
+
+#if (BTM_SCO_INCLUDED == TRUE)
+    /* Check if there is any SCO Active on this BD Address */
+    is_sco_active = btm_is_sco_active_by_bdaddr(remote_bd_addr);
+
+    if (is_sco_active == true)
+        return(BTM_NO_RESOURCES);
+#endif
+
+    /* Ignore role switch request if the previous request was not completed */
+    if (p->switch_role_state != BTM_ACL_SWKEY_STATE_IDLE)
+    {
+        BTM_TRACE_DEBUG ("BTM_SwitchRole busy: %d",
+                          p->switch_role_state);
+        return(BTM_BUSY);
+    }
+
+    if ((status = BTM_ReadPowerMode(p->remote_addr, &pwr_mode)) != BTM_SUCCESS)
+        return(status);
+
+    /* Wake up the link if in sniff or park before attempting switch */
+    if (pwr_mode == BTM_PM_MD_PARK || pwr_mode == BTM_PM_MD_SNIFF)
+    {
+        memset( (void*)&settings, 0, sizeof(settings));
+        settings.mode = BTM_PM_MD_ACTIVE;
+        status = BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p->remote_addr, &settings);
+        if (status != BTM_CMD_STARTED)
+            return(BTM_WRONG_MODE);
+
+        p->switch_role_state = BTM_ACL_SWKEY_STATE_MODE_CHANGE;
+    }
+    /* some devices do not support switch while encryption is on */
+    else
+    {
+        p_dev_rec = btm_find_dev (remote_bd_addr);
+        if ((p_dev_rec != NULL)
+            && ((p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) != 0)
+            && !BTM_EPR_AVAILABLE(p))
+        {
+            /* bypass turning off encryption if change link key is already doing it */
+            if (p->encrypt_state != BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF)
+            {
+                btsnd_hcic_set_conn_encrypt (p->hci_handle, false);
+                p->encrypt_state = BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF;
+            }
+
+            p->switch_role_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF;
+        }
+        else
+        {
+            btsnd_hcic_switch_role (remote_bd_addr, new_role);
+            p->switch_role_state = BTM_ACL_SWKEY_STATE_IN_PROGRESS;
+
+#if (BTM_DISC_DURING_RS == TRUE)
+            if (p_dev_rec)
+                p_dev_rec->rs_disc_pending = BTM_SEC_RS_PENDING;
+#endif
+        }
+    }
+
+    /* Initialize return structure in case request fails */
+    if (p_cb)
+    {
+        memcpy (btm_cb.devcb.switch_role_ref_data.remote_bd_addr, remote_bd_addr,
+                BD_ADDR_LEN);
+        btm_cb.devcb.switch_role_ref_data.role = new_role;
+        /* initialized to an error code */
+        btm_cb.devcb.switch_role_ref_data.hci_status = HCI_ERR_UNSUPPORTED_VALUE;
+        btm_cb.devcb.p_switch_role_cb = p_cb;
+    }
+    return(BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+**
+** Function         btm_acl_encrypt_change
+**
+** Description      This function is when encryption of the connection is
+**                  completed by the LM.  Checks to see if a role switch or
+**                  change of link key was active and initiates or continues
+**                  process if needed.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_acl_encrypt_change (uint16_t handle, uint8_t status, uint8_t encr_enable)
+{
+    tACL_CONN *p;
+    uint8_t   xx;
+    tBTM_SEC_DEV_REC  *p_dev_rec;
+    tBTM_BL_ROLE_CHG_DATA   evt;
+
+    BTM_TRACE_DEBUG ("btm_acl_encrypt_change handle=%d status=%d encr_enabl=%d",
+                      handle, status, encr_enable);
+    xx = btm_handle_to_acl_index(handle);
+    /* don't assume that we can never get a bad hci_handle */
+    if (xx < MAX_L2CAP_LINKS)
+        p = &btm_cb.acl_db[xx];
+    else
+        return;
+
+    /* Process Role Switch if active */
+    if (p->switch_role_state == BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF)
+    {
+        /* if encryption turn off failed we still will try to switch role */
+        if (encr_enable)
+        {
+            p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+            p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+        }
+        else
+        {
+            p->switch_role_state = BTM_ACL_SWKEY_STATE_SWITCHING;
+            p->encrypt_state = BTM_ACL_ENCRYPT_STATE_TEMP_FUNC;
+        }
+
+        btsnd_hcic_switch_role(p->remote_addr, (uint8_t)!p->link_role);
+#if (BTM_DISC_DURING_RS == TRUE)
+        if ((p_dev_rec = btm_find_dev (p->remote_addr)) != NULL)
+            p_dev_rec->rs_disc_pending = BTM_SEC_RS_PENDING;
+#endif
+
+    }
+    /* Finished enabling Encryption after role switch */
+    else if (p->switch_role_state == BTM_ACL_SWKEY_STATE_ENCRYPTION_ON)
+    {
+        p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+        p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+        btm_acl_report_role_change(btm_cb.devcb.switch_role_ref_data.hci_status, p->remote_addr);
+
+        /* if role change event is registered, report it now */
+        if (btm_cb.p_bl_changed_cb && (btm_cb.bl_evt_mask & BTM_BL_ROLE_CHG_MASK))
+        {
+            evt.event       = BTM_BL_ROLE_CHG_EVT;
+            evt.new_role    = btm_cb.devcb.switch_role_ref_data.role;
+            evt.p_bda       = btm_cb.devcb.switch_role_ref_data.remote_bd_addr;
+            evt.hci_status  = btm_cb.devcb.switch_role_ref_data.hci_status;
+            (*btm_cb.p_bl_changed_cb)((tBTM_BL_EVENT_DATA *)&evt);
+
+            BTM_TRACE_DEBUG("Role Switch Event: new_role 0x%02x, HCI Status 0x%02x, rs_st:%d",
+                             evt.new_role, evt.hci_status, p->switch_role_state);
+        }
+
+#if (BTM_DISC_DURING_RS == TRUE)
+        /* If a disconnect is pending, issue it now that role switch has completed */
+        if ((p_dev_rec = btm_find_dev (p->remote_addr)) != NULL)
+        {
+            if (p_dev_rec->rs_disc_pending == BTM_SEC_DISC_PENDING)
+            {
+                BTM_TRACE_WARNING("btm_acl_encrypt_change -> Issuing delayed HCI_Disconnect!!!");
+                btsnd_hcic_disconnect(p_dev_rec->hci_handle, HCI_ERR_PEER_USER);
+            }
+            BTM_TRACE_ERROR("btm_acl_encrypt_change: tBTM_SEC_DEV:0x%x rs_disc_pending=%d",
+                            PTR_TO_UINT(p_dev_rec), p_dev_rec->rs_disc_pending);
+            p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING;     /* reset flag */
+        }
+#endif
+    }
+}
+/*******************************************************************************
+**
+** Function         BTM_SetLinkPolicy
+**
+** Description      Create and send HCI "Write Policy Set" command
+**
+** Returns          status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetLinkPolicy (BD_ADDR remote_bda, uint16_t *settings)
+{
+    tACL_CONN   *p;
+    uint8_t     *localFeatures = BTM_ReadLocalFeatures();
+    BTM_TRACE_DEBUG ("BTM_SetLinkPolicy");
+/*    BTM_TRACE_API ("BTM_SetLinkPolicy: requested settings: 0x%04x", *settings ); */
+
+    /* First, check if hold mode is supported */
+    if (*settings != HCI_DISABLE_ALL_LM_MODES)
+    {
+        if ( (*settings & HCI_ENABLE_MASTER_SLAVE_SWITCH) && (!HCI_SWITCH_SUPPORTED(localFeatures)) )
+        {
+            *settings &= (~HCI_ENABLE_MASTER_SLAVE_SWITCH);
+            BTM_TRACE_API ("BTM_SetLinkPolicy switch not supported (settings: 0x%04x)", *settings );
+        }
+        if ( (*settings & HCI_ENABLE_HOLD_MODE) && (!HCI_HOLD_MODE_SUPPORTED(localFeatures)) )
+        {
+            *settings &= (~HCI_ENABLE_HOLD_MODE);
+            BTM_TRACE_API ("BTM_SetLinkPolicy hold not supported (settings: 0x%04x)", *settings );
+        }
+        if ( (*settings & HCI_ENABLE_SNIFF_MODE) && (!HCI_SNIFF_MODE_SUPPORTED(localFeatures)) )
+        {
+            *settings &= (~HCI_ENABLE_SNIFF_MODE);
+            BTM_TRACE_API ("BTM_SetLinkPolicy sniff not supported (settings: 0x%04x)", *settings );
+        }
+        if ( (*settings & HCI_ENABLE_PARK_MODE) && (!HCI_PARK_MODE_SUPPORTED(localFeatures)) )
+        {
+            *settings &= (~HCI_ENABLE_PARK_MODE);
+            BTM_TRACE_API ("BTM_SetLinkPolicy park not supported (settings: 0x%04x)", *settings );
+        }
+    }
+
+    if ((p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR)) != NULL) {
+        btsnd_hcic_write_policy_set(p->hci_handle, *settings);
+        return BTM_CMD_STARTED;
+    }
+
+    /* If here, no BD Addr found */
+    return(BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    uint8_t *localFeatures = BTM_ReadLocalFeatures();
+
+    BTM_TRACE_DEBUG("BTM_SetDefaultLinkPolicy setting:0x%04x", settings);
+
+    if((settings & HCI_ENABLE_MASTER_SLAVE_SWITCH) && (!HCI_SWITCH_SUPPORTED(localFeatures)))
+    {
+        settings &= ~HCI_ENABLE_MASTER_SLAVE_SWITCH;
+        BTM_TRACE_DEBUG("BTM_SetDefaultLinkPolicy switch not supported (settings: 0x%04x)", settings);
+    }
+    if ((settings & HCI_ENABLE_HOLD_MODE) && (!HCI_HOLD_MODE_SUPPORTED(localFeatures)))
+    {
+        settings &= ~HCI_ENABLE_HOLD_MODE;
+        BTM_TRACE_DEBUG("BTM_SetDefaultLinkPolicy hold not supported (settings: 0x%04x)", settings);
+    }
+    if ((settings & HCI_ENABLE_SNIFF_MODE) && (!HCI_SNIFF_MODE_SUPPORTED(localFeatures)))
+    {
+        settings &= ~HCI_ENABLE_SNIFF_MODE;
+        BTM_TRACE_DEBUG("BTM_SetDefaultLinkPolicy sniff not supported (settings: 0x%04x)", settings);
+    }
+    if ((settings & HCI_ENABLE_PARK_MODE) && (!HCI_PARK_MODE_SUPPORTED(localFeatures)))
+    {
+        settings &= ~HCI_ENABLE_PARK_MODE;
+        BTM_TRACE_DEBUG("BTM_SetDefaultLinkPolicy park not supported (settings: 0x%04x)", settings);
+    }
+    BTM_TRACE_DEBUG("Set DefaultLinkPolicy:0x%04x", settings);
+
+    btm_cb.btm_def_link_policy = settings;
+
+    /* Set the default Link Policy of the controller */
+    btsnd_hcic_write_def_policy_set(settings);
+}
+
+/*******************************************************************************
+**
+** Function         btm_read_remote_version_complete
+**
+** Description      This function is called when the command complete message
+**                  is received from the HCI for the remote version info.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_read_remote_version_complete (uint8_t *p)
+{
+    tACL_CONN        *p_acl_cb = &btm_cb.acl_db[0];
+    uint8_t           status;
+    uint16_t          handle;
+    int               xx;
+    BTM_TRACE_DEBUG ("btm_read_remote_version_complete");
+
+    STREAM_TO_UINT8  (status, p);
+    STREAM_TO_UINT16 (handle, p);
+
+    /* Look up the connection by handle and copy features */
+    for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_acl_cb++)
+    {
+        if ((p_acl_cb->in_use) && (p_acl_cb->hci_handle == handle))
+        {
+            if (status == HCI_SUCCESS)
+            {
+                STREAM_TO_UINT8  (p_acl_cb->lmp_version, p);
+                STREAM_TO_UINT16 (p_acl_cb->manufacturer, p);
+                STREAM_TO_UINT16 (p_acl_cb->lmp_subversion, p);
+            }
+
+#if (BLE_INCLUDED == TRUE)
+            if (p_acl_cb->transport == BT_TRANSPORT_LE)
+                l2cble_notify_le_connection (p_acl_cb->remote_addr);
+#endif  // (defined(BLE_INCLUDED) && (BLE_INCLUDED == true))
+            break;
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         btm_process_remote_ext_features
+**
+** Description      Local function called to process all extended features pages
+**                  read from a remote device.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_process_remote_ext_features (tACL_CONN *p_acl_cb, uint8_t num_read_pages)
+{
+    uint16_t            handle = p_acl_cb->hci_handle;
+    tBTM_SEC_DEV_REC    *p_dev_rec = btm_find_dev_by_handle (handle);
+    uint8_t             page_idx;
+
+    BTM_TRACE_DEBUG ("btm_process_remote_ext_features");
+
+    /* Make sure we have the record to save remote features information */
+    if (p_dev_rec == NULL)
+    {
+        /* Get a new device; might be doing dedicated bonding */
+        p_dev_rec = btm_find_or_alloc_dev (p_acl_cb->remote_addr);
+    }
+
+    p_acl_cb->num_read_pages = num_read_pages;
+    p_dev_rec->num_read_pages = num_read_pages;
+
+    /* Move the pages to placeholder */
+    for (page_idx = 0; page_idx < num_read_pages; page_idx++)
+    {
+        if (page_idx > HCI_EXT_FEATURES_PAGE_MAX)
+        {
+            BTM_TRACE_ERROR("%s: page=%d unexpected", __func__, page_idx);
+            break;
+        }
+        memcpy (p_dev_rec->features[page_idx], p_acl_cb->peer_lmp_features[page_idx],
+                HCI_FEATURE_BYTES_PER_PAGE);
+    }
+
+    const uint8_t req_pend = (p_dev_rec->sm4 & BTM_SM4_REQ_PEND);
+
+    /* Store the Peer Security Capabilites (in SM4 and rmt_sec_caps) */
+    btm_sec_set_peer_sec_caps(p_acl_cb, p_dev_rec);
+
+    BTM_TRACE_API("%s: pend:%d", __func__, req_pend);
+    if (req_pend)
+    {
+        /* Request for remaining Security Features (if any) */
+        l2cu_resubmit_pending_sec_req (p_dev_rec->bd_addr);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         btm_read_remote_features
+**
+** Description      Local function called to send a read remote supported features/
+**                  remote extended features page[0].
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_read_remote_features (uint16_t handle)
+{
+    uint8_t     acl_idx;
+    tACL_CONN   *p_acl_cb;
+
+    BTM_TRACE_DEBUG("btm_read_remote_features() handle: %d", handle);
+
+    if ((acl_idx = btm_handle_to_acl_index(handle)) >= MAX_L2CAP_LINKS)
+    {
+        BTM_TRACE_ERROR("btm_read_remote_features handle=%d invalid", handle);
+        return;
+    }
+
+    p_acl_cb = &btm_cb.acl_db[acl_idx];
+    p_acl_cb->num_read_pages = 0;
+    memset (p_acl_cb->peer_lmp_features, 0, sizeof(p_acl_cb->peer_lmp_features));
+
+    /* first send read remote supported features HCI command */
+    /* because we don't know whether the remote support extended feature command */
+    btsnd_hcic_rmt_features_req (handle);
+}
+
+
+/*******************************************************************************
+**
+** Function         btm_read_remote_ext_features
+**
+** Description      Local function called to send a read remote extended features
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_read_remote_ext_features (uint16_t handle, uint8_t page_number)
+{
+    BTM_TRACE_DEBUG("btm_read_remote_ext_features() handle: %d page: %d", handle, page_number);
+
+    btsnd_hcic_rmt_ext_features(handle, page_number);
+}
+
+
+/*******************************************************************************
+**
+** Function         btm_read_remote_features_complete
+**
+** Description      This function is called when the remote supported features
+**                  complete event is received from the HCI.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_read_remote_features_complete (uint8_t *p)
+{
+    tACL_CONN        *p_acl_cb;
+    uint8_t           status;
+    uint16_t          handle;
+    uint8_t          acl_idx;
+
+    BTM_TRACE_DEBUG ("btm_read_remote_features_complete");
+    STREAM_TO_UINT8  (status, p);
+
+    if (status != HCI_SUCCESS)
+    {
+        BTM_TRACE_ERROR ("btm_read_remote_features_complete failed (status 0x%02x)", status);
+        return;
+    }
+
+        STREAM_TO_UINT16 (handle, p);
+
+    if ((acl_idx = btm_handle_to_acl_index(handle)) >= MAX_L2CAP_LINKS)
+        {
+        BTM_TRACE_ERROR("btm_read_remote_features_complete handle=%d invalid", handle);
+        return;
+                }
+
+    p_acl_cb = &btm_cb.acl_db[acl_idx];
+
+    /* Copy the received features page */
+    STREAM_TO_ARRAY(p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0], p,
+                    HCI_FEATURE_BYTES_PER_PAGE);
+
+    if ((HCI_LMP_EXTENDED_SUPPORTED(p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) &&
+        (controller_get_interface()->supports_reading_remote_extended_features()))
+    {
+        /* if the remote controller has extended features and local controller supports
+        ** HCI_Read_Remote_Extended_Features command then start reading these feature starting
+        ** with extended features page 1 */
+        BTM_TRACE_DEBUG ("Start reading remote extended features");
+        btm_read_remote_ext_features(handle, HCI_EXT_FEATURES_PAGE_1);
+        return;
+    }
+
+    /* Remote controller has no extended features. Process remote controller supported features
+       (features page HCI_EXT_FEATURES_PAGE_0). */
+    btm_process_remote_ext_features (p_acl_cb, 1);
+
+    /* Continue with HCI connection establishment */
+    btm_establish_continue (p_acl_cb);
+}
+
+/*******************************************************************************
+**
+** Function         btm_read_remote_ext_features_complete
+**
+** Description      This function is called when the remote extended features
+**                  complete event is received from the HCI.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_read_remote_ext_features_complete (uint8_t *p)
+{
+    tACL_CONN   *p_acl_cb;
+    uint8_t     page_num, max_page;
+    uint16_t    handle;
+    uint8_t     acl_idx;
+
+    BTM_TRACE_DEBUG ("btm_read_remote_ext_features_complete");
+
+    ++p;
+    STREAM_TO_UINT16 (handle, p);
+    STREAM_TO_UINT8  (page_num, p);
+    STREAM_TO_UINT8  (max_page, p);
+
+    /* Validate parameters */
+    if ((acl_idx = btm_handle_to_acl_index(handle)) >= MAX_L2CAP_LINKS)
+    {
+        BTM_TRACE_ERROR("btm_read_remote_ext_features_complete handle=%d invalid", handle);
+        return;
+    }
+
+    if (max_page > HCI_EXT_FEATURES_PAGE_MAX)
+    {
+        BTM_TRACE_ERROR("btm_read_remote_ext_features_complete page=%d unknown", max_page);
+        return;
+    }
+
+    p_acl_cb = &btm_cb.acl_db[acl_idx];
+
+    /* Copy the received features page */
+    STREAM_TO_ARRAY(p_acl_cb->peer_lmp_features[page_num], p, HCI_FEATURE_BYTES_PER_PAGE);
+
+    /* If there is the next remote features page and
+     * we have space to keep this page data - read this page */
+    if ((page_num < max_page) && (page_num < HCI_EXT_FEATURES_PAGE_MAX))
+    {
+        page_num++;
+        BTM_TRACE_DEBUG("BTM reads next remote extended features page (%d)", page_num);
+        btm_read_remote_ext_features (handle, page_num);
+        return;
+    }
+
+    /* Reading of remote feature pages is complete */
+    BTM_TRACE_DEBUG("BTM reached last remote extended features page (%d)", page_num);
+
+    /* Process the pages */
+    btm_process_remote_ext_features (p_acl_cb, (uint8_t) (page_num + 1));
+
+    /* Continue with HCI connection establishment */
+    btm_establish_continue (p_acl_cb);
+}
+
+/*******************************************************************************
+**
+** Function         btm_read_remote_ext_features_failed
+**
+** Description      This function is called when the remote extended features
+**                  complete event returns a failed status.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_read_remote_ext_features_failed (uint8_t status, uint16_t handle)
+{
+    tACL_CONN   *p_acl_cb;
+    uint8_t     acl_idx;
+
+    BTM_TRACE_WARNING ("btm_read_remote_ext_features_failed (status 0x%02x) for handle %d",
+                         status, handle);
+
+    if ((acl_idx = btm_handle_to_acl_index(handle)) >= MAX_L2CAP_LINKS)
+    {
+        BTM_TRACE_ERROR("btm_read_remote_ext_features_failed handle=%d invalid", handle);
+        return;
+    }
+
+    p_acl_cb = &btm_cb.acl_db[acl_idx];
+
+    /* Process supported features only */
+    btm_process_remote_ext_features (p_acl_cb, 1);
+
+    /* Continue HCI connection establishment */
+    btm_establish_continue (p_acl_cb);
+}
+
+/*******************************************************************************
+**
+** Function         btm_establish_continue
+**
+** Description      This function is called when the command complete message
+**                  is received from the HCI for the read local link policy request.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_establish_continue (tACL_CONN *p_acl_cb)
+{
+        tBTM_BL_EVENT_DATA  evt_data;
+        BTM_TRACE_DEBUG ("btm_establish_continue");
+#if (BTM_BYPASS_EXTRA_ACL_SETUP == FALSE)
+#if (BLE_INCLUDED == TRUE)
+        if (p_acl_cb->transport == BT_TRANSPORT_BR_EDR)
+#endif
+        {
+            /* For now there are a some devices that do not like sending */
+            /* commands events and data at the same time. */
+            /* Set the packet types to the default allowed by the device */
+            btm_set_packet_types (p_acl_cb, btm_cb.btm_acl_pkt_types_supported);
+
+            if (btm_cb.btm_def_link_policy)
+                BTM_SetLinkPolicy (p_acl_cb->remote_addr, &btm_cb.btm_def_link_policy);
+        }
+#endif
+        p_acl_cb->link_up_issued = true;
+
+        /* If anyone cares, tell him database changed */
+        if (btm_cb.p_bl_changed_cb)
+        {
+            evt_data.event = BTM_BL_CONN_EVT;
+            evt_data.conn.p_bda = p_acl_cb->remote_addr;
+            evt_data.conn.p_bdn = p_acl_cb->remote_name;
+            evt_data.conn.p_dc  = p_acl_cb->remote_dc;
+            evt_data.conn.p_features = p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0];
+#if (BLE_INCLUDED == TRUE)
+            evt_data.conn.handle = p_acl_cb->hci_handle;
+            evt_data.conn.transport = p_acl_cb->transport;
+#endif
+
+            (*btm_cb.p_bl_changed_cb)(&evt_data);
+        }
+        btm_acl_update_busy_level (BTM_BLI_ACL_UP_EVT);
+}
+
+
+/*******************************************************************************
+**
+** 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)
+{
+    BTM_TRACE_DEBUG ("BTM_SetDefaultLinkSuperTout");
+    btm_cb.btm_def_link_super_tout = timeout;
+}
+
+/*******************************************************************************
+**
+** Function         BTM_GetLinkSuperTout
+**
+** Description      Read the link supervision timeout value of the connection
+**
+** Returns          status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_GetLinkSuperTout (BD_ADDR remote_bda, uint16_t *p_timeout)
+{
+    tACL_CONN   *p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+
+    BTM_TRACE_DEBUG ("BTM_GetLinkSuperTout");
+    if (p != (tACL_CONN *)NULL)
+    {
+        *p_timeout = p->link_super_tout;
+        return(BTM_SUCCESS);
+    }
+    /* If here, no BD Addr found */
+    return(BTM_UNKNOWN_ADDR);
+}
+
+
+/*******************************************************************************
+**
+** Function         BTM_SetLinkSuperTout
+**
+** Description      Create and send HCI "Write Link Supervision Timeout" command
+**
+** Returns          status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetLinkSuperTout (BD_ADDR remote_bda, uint16_t timeout)
+{
+    tACL_CONN   *p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+
+    BTM_TRACE_DEBUG ("BTM_SetLinkSuperTout");
+    if (p != (tACL_CONN *)NULL)
+    {
+        p->link_super_tout = timeout;
+
+        /* Only send if current role is Master; 2.0 spec requires this */
+        if (p->link_role == BTM_ROLE_MASTER)
+        {
+            btsnd_hcic_write_link_super_tout(LOCAL_BR_EDR_CONTROLLER_ID,
+                                             p->hci_handle, timeout);
+            return(BTM_CMD_STARTED);
+        }
+        else
+            return(BTM_SUCCESS);
+    }
+
+    /* If here, no BD Addr found */
+    return(BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+**
+** 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 (BD_ADDR remote_bda, tBT_TRANSPORT transport)
+{
+    tACL_CONN   *p;
+
+    BTM_TRACE_API ("BTM_IsAclConnectionUp: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+                    remote_bda[0], remote_bda[1], remote_bda[2],
+                    remote_bda[3], remote_bda[4], remote_bda[5]);
+
+    p = btm_bda_to_acl(remote_bda, transport);
+    if (p != (tACL_CONN *)NULL)
+    {
+        return(true);
+    }
+
+    /* If here, no BD Addr found */
+    return(false);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    uint16_t num_acl = 0;
+
+    for (uint16_t i = 0; i < MAX_L2CAP_LINKS; ++i)
+    {
+        if (btm_cb.acl_db[i].in_use)
+            ++num_acl;
+    }
+
+    return num_acl;
+}
+
+/*******************************************************************************
+**
+** Function         btm_get_acl_disc_reason_code
+**
+** Description      This function is called to get the disconnection reason code
+**                  returned by the HCI at disconnection complete event.
+**
+** Returns          true if connection is up, else false.
+**
+*******************************************************************************/
+uint16_t btm_get_acl_disc_reason_code (void)
+{
+    uint8_t res = btm_cb.acl_disc_reason;
+    BTM_TRACE_DEBUG ("btm_get_acl_disc_reason_code");
+    return(res);
+}
+
+
+/*******************************************************************************
+**
+** 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 BD_ADDR remote_bda, tBT_TRANSPORT transport)
+{
+    tACL_CONN   *p;
+    BTM_TRACE_DEBUG ("BTM_GetHCIConnHandle");
+    p = btm_bda_to_acl(remote_bda, transport);
+    if (p != (tACL_CONN *)NULL)
+    {
+        return(p->hci_handle);
+    }
+
+    /* If here, no BD Addr found */
+    return(0xFFFF);
+}
+
+/*******************************************************************************
+**
+** Function         btm_process_clk_off_comp_evt
+**
+** Description      This function is called when clock offset command completes.
+**
+** Input Parms      hci_handle - connection handle associated with the change
+**                  clock offset
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_process_clk_off_comp_evt (uint16_t hci_handle, uint16_t clock_offset)
+{
+    uint8_t    xx;
+    BTM_TRACE_DEBUG ("btm_process_clk_off_comp_evt");
+    /* Look up the connection by handle and set the current mode */
+    if ((xx = btm_handle_to_acl_index(hci_handle)) < MAX_L2CAP_LINKS)
+        btm_cb.acl_db[xx].clock_offset = clock_offset;
+}
+
+/*******************************************************************************
+**
+** Function         btm_acl_role_changed
+**
+** Description      This function is called whan a link's master/slave role change
+**                  event or command status event (with error) is received.
+**                  It updates the link control block, and calls
+**                  the registered callback with status and role (if registered).
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_acl_role_changed (uint8_t hci_status, BD_ADDR bd_addr, uint8_t new_role)
+{
+    uint8_t                 *p_bda = (bd_addr) ? bd_addr :
+                                        btm_cb.devcb.switch_role_ref_data.remote_bd_addr;
+    tACL_CONN               *p = btm_bda_to_acl(p_bda, BT_TRANSPORT_BR_EDR);
+    tBTM_ROLE_SWITCH_CMPL   *p_data = &btm_cb.devcb.switch_role_ref_data;
+    tBTM_SEC_DEV_REC        *p_dev_rec;
+    tBTM_BL_ROLE_CHG_DATA   evt;
+
+    BTM_TRACE_DEBUG ("btm_acl_role_changed");
+    /* Ignore any stray events */
+    if (p == NULL)
+    {
+        /* it could be a failure */
+        if (hci_status != HCI_SUCCESS)
+            btm_acl_report_role_change(hci_status, bd_addr);
+        return;
+    }
+
+    p_data->hci_status = hci_status;
+
+    if (hci_status == HCI_SUCCESS)
+    {
+        p_data->role = new_role;
+        memcpy(p_data->remote_bd_addr, p_bda, BD_ADDR_LEN);
+
+        /* Update cached value */
+        p->link_role = new_role;
+
+        /* Reload LSTO: link supervision timeout is reset in the LM after a role switch */
+        if (new_role == BTM_ROLE_MASTER)
+        {
+            BTM_SetLinkSuperTout (p->remote_addr, p->link_super_tout);
+        }
+    }
+    else
+    {
+        /* so the BTM_BL_ROLE_CHG_EVT uses the old role */
+        new_role = p->link_role;
+    }
+
+    /* Check if any SCO req is pending for role change */
+    btm_sco_chk_pend_rolechange (p->hci_handle);
+
+    /* if switching state is switching we need to turn encryption on */
+    /* if idle, we did not change encryption */
+    if (p->switch_role_state == BTM_ACL_SWKEY_STATE_SWITCHING)
+    {
+        btsnd_hcic_set_conn_encrypt (p->hci_handle, true);
+        p->encrypt_state = BTM_ACL_ENCRYPT_STATE_ENCRYPT_ON;
+        p->switch_role_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_ON;
+        return;
+    }
+
+    /* Set the switch_role_state to IDLE since the reply received from HCI */
+    /* regardless of its result either success or failed. */
+    if (p->switch_role_state == BTM_ACL_SWKEY_STATE_IN_PROGRESS)
+    {
+        p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+        p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+    }
+
+    /* if role switch complete is needed, report it now */
+    btm_acl_report_role_change(hci_status, bd_addr);
+
+    /* if role change event is registered, report it now */
+    if (btm_cb.p_bl_changed_cb && (btm_cb.bl_evt_mask & BTM_BL_ROLE_CHG_MASK))
+    {
+        evt.event       = BTM_BL_ROLE_CHG_EVT;
+        evt.new_role    = new_role;
+        evt.p_bda       = p_bda;
+        evt.hci_status  = hci_status;
+        (*btm_cb.p_bl_changed_cb)((tBTM_BL_EVENT_DATA *)&evt);
+    }
+
+    BTM_TRACE_DEBUG("Role Switch Event: new_role 0x%02x, HCI Status 0x%02x, rs_st:%d",
+                     p_data->role, p_data->hci_status, p->switch_role_state);
+
+#if (BTM_DISC_DURING_RS == TRUE)
+    /* If a disconnect is pending, issue it now that role switch has completed */
+    if ((p_dev_rec = btm_find_dev (p_bda)) != NULL)
+    {
+        if (p_dev_rec->rs_disc_pending == BTM_SEC_DISC_PENDING)
+        {
+            BTM_TRACE_WARNING("btm_acl_role_changed -> Issuing delayed HCI_Disconnect!!!");
+            btsnd_hcic_disconnect(p_dev_rec->hci_handle, HCI_ERR_PEER_USER);
+        }
+        BTM_TRACE_ERROR("tBTM_SEC_DEV:0x%x rs_disc_pending=%d",
+                        PTR_TO_UINT(p_dev_rec), p_dev_rec->rs_disc_pending);
+        p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING;     /* reset flag */
+    }
+
+#endif
+
+}
+
+/*******************************************************************************
+**
+** Function         BTM_AllocateSCN
+**
+** Description      Look through the Server Channel Numbers for a free one.
+**
+** Returns          Allocated SCN number or 0 if none.
+**
+*******************************************************************************/
+
+uint8_t BTM_AllocateSCN(void)
+{
+    uint8_t x;
+    BTM_TRACE_DEBUG ("BTM_AllocateSCN");
+
+    // stack reserves scn 1 for HFP, HSP we still do the correct way
+    for (x = 1; x < BTM_MAX_SCN; x++)
+    {
+        if (!btm_cb.btm_scn[x])
+        {
+            btm_cb.btm_scn[x] = true;
+            return(x+1);
+        }
+    }
+
+    return(0);     /* No free ports */
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    /* Make sure we don't exceed max port range.
+     * Stack reserves scn 1 for HFP, HSP we still do the correct way.
+     */
+    if ( (scn>=BTM_MAX_SCN) || (scn == 1) )
+        return false;
+
+    /* check if this port is available */
+    if (!btm_cb.btm_scn[scn-1])
+    {
+        btm_cb.btm_scn[scn-1] = true;
+        return true;
+    }
+
+    return (false);     /* Port was busy */
+}
+
+/*******************************************************************************
+**
+** Function         BTM_FreeSCN
+**
+** Description      Free the specified SCN.
+**
+** Returns          true or false
+**
+*******************************************************************************/
+bool    BTM_FreeSCN(uint8_t scn)
+{
+    BTM_TRACE_DEBUG ("BTM_FreeSCN ");
+    if (scn <= BTM_MAX_SCN)
+    {
+        btm_cb.btm_scn[scn-1] = false;
+        return(true);
+    }
+    else
+        return(false);      /* Illegal SCN passed in */
+}
+
+/*******************************************************************************
+**
+** Function         btm_set_packet_types
+**
+** Description      This function sets the packet types used for a specific
+**                  ACL connection. It is called internally by btm_acl_created
+**                  or by an application/profile by BTM_SetPacketTypes.
+**
+** Returns          status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS btm_set_packet_types (tACL_CONN *p, uint16_t pkt_types)
+{
+    uint16_t temp_pkt_types;
+    BTM_TRACE_DEBUG ("btm_set_packet_types");
+    /* Save in the ACL control blocks, types that we support */
+    temp_pkt_types = (pkt_types & BTM_ACL_SUPPORTED_PKTS_MASK &
+                      btm_cb.btm_acl_pkt_types_supported);
+
+    /* OR in any exception packet types if at least 2.0 version of spec */
+    temp_pkt_types |= ((pkt_types & BTM_ACL_EXCEPTION_PKTS_MASK) |
+                       (btm_cb.btm_acl_pkt_types_supported & BTM_ACL_EXCEPTION_PKTS_MASK));
+
+    /* Exclude packet types not supported by the peer */
+    btm_acl_chk_peer_pkt_type_support (p, &temp_pkt_types);
+
+    BTM_TRACE_DEBUG ("SetPacketType Mask -> 0x%04x", temp_pkt_types);
+
+    btsnd_hcic_change_conn_type (p->hci_handle, temp_pkt_types);
+    p->pkt_types_mask = temp_pkt_types;
+
+    return(BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+**
+** Function         btm_get_max_packet_size
+**
+** Returns          Returns maximum packet size that can be used for current
+**                  connection, 0 if connection is not established
+**
+*******************************************************************************/
+uint16_t btm_get_max_packet_size (BD_ADDR addr)
+{
+    tACL_CONN   *p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR);
+    uint16_t    pkt_types = 0;
+    uint16_t    pkt_size = 0;
+    BTM_TRACE_DEBUG ("btm_get_max_packet_size");
+    if (p != NULL)
+    {
+        pkt_types = p->pkt_types_mask;
+    }
+    else
+    {
+        /* Special case for when info for the local device is requested */
+        if (memcmp (controller_get_interface()->get_address(), addr, BD_ADDR_LEN) == 0)
+        {
+            pkt_types = btm_cb.btm_acl_pkt_types_supported;
+        }
+    }
+
+    if (pkt_types)
+    {
+        if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_3_DH5))
+            pkt_size = HCI_EDR3_DH5_PACKET_SIZE;
+        else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_2_DH5))
+            pkt_size = HCI_EDR2_DH5_PACKET_SIZE;
+        else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_3_DH3))
+            pkt_size = HCI_EDR3_DH3_PACKET_SIZE;
+        else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DH5)
+            pkt_size = HCI_DH5_PACKET_SIZE;
+        else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_2_DH3))
+            pkt_size = HCI_EDR2_DH3_PACKET_SIZE;
+        else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DM5)
+            pkt_size = HCI_DM5_PACKET_SIZE;
+        else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DH3)
+            pkt_size = HCI_DH3_PACKET_SIZE;
+        else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DM3)
+            pkt_size = HCI_DM3_PACKET_SIZE;
+        else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_3_DH1))
+            pkt_size = HCI_EDR3_DH1_PACKET_SIZE;
+        else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_2_DH1))
+            pkt_size = HCI_EDR2_DH1_PACKET_SIZE;
+        else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DH1)
+            pkt_size = HCI_DH1_PACKET_SIZE;
+        else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DM1)
+            pkt_size = HCI_DM1_PACKET_SIZE;
+    }
+
+   return(pkt_size);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_ReadRemoteVersion
+**
+** Returns          If connected report peer device info
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadRemoteVersion (BD_ADDR addr, uint8_t *lmp_version,
+                                   uint16_t *manufacturer, uint16_t *lmp_sub_version)
+{
+    tACL_CONN        *p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR);
+    BTM_TRACE_DEBUG ("BTM_ReadRemoteVersion");
+    if (p == NULL)
+        return(BTM_UNKNOWN_ADDR);
+
+    if (lmp_version)
+        *lmp_version = p->lmp_version;
+
+    if (manufacturer)
+        *manufacturer = p->manufacturer;
+
+    if (lmp_sub_version)
+        *lmp_sub_version = p->lmp_subversion;
+
+    return(BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_ReadRemoteFeatures
+**
+** Returns          pointer to the remote supported features mask (8 bytes)
+**
+*******************************************************************************/
+uint8_t *BTM_ReadRemoteFeatures (BD_ADDR addr)
+{
+    tACL_CONN        *p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR);
+    BTM_TRACE_DEBUG ("BTM_ReadRemoteFeatures");
+    if (p == NULL)
+    {
+        return(NULL);
+    }
+
+    return(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_ReadRemoteExtendedFeatures
+**
+** Returns          pointer to the remote extended features mask (8 bytes)
+**                  or NULL if bad page
+**
+*******************************************************************************/
+uint8_t *BTM_ReadRemoteExtendedFeatures (BD_ADDR addr, uint8_t page_number)
+{
+    tACL_CONN        *p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR);
+    BTM_TRACE_DEBUG ("BTM_ReadRemoteExtendedFeatures");
+    if (p == NULL)
+    {
+        return(NULL);
+    }
+
+    if (page_number > HCI_EXT_FEATURES_PAGE_MAX)
+    {
+        BTM_TRACE_ERROR("Warning: BTM_ReadRemoteExtendedFeatures page %d unknown", page_number);
+        return NULL;
+    }
+
+    return(p->peer_lmp_features[page_number]);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_ReadNumberRemoteFeaturesPages
+**
+** Returns          number of features pages read from the remote device.
+**
+*******************************************************************************/
+uint8_t BTM_ReadNumberRemoteFeaturesPages (BD_ADDR addr)
+{
+    tACL_CONN        *p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR);
+    BTM_TRACE_DEBUG ("BTM_ReadNumberRemoteFeaturesPages");
+    if (p == NULL)
+    {
+        return(0);
+    }
+
+    return(p->num_read_pages);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_ReadAllRemoteFeatures
+**
+** Returns          pointer to all features of the remote (24 bytes).
+**
+*******************************************************************************/
+uint8_t *BTM_ReadAllRemoteFeatures (BD_ADDR addr)
+{
+    tACL_CONN        *p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR);
+    BTM_TRACE_DEBUG ("BTM_ReadAllRemoteFeatures");
+    if (p == NULL)
+    {
+        return(NULL);
+    }
+
+    return(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    BTM_TRACE_DEBUG ("BTM_RegBusyLevelNotif");
+    if (p_level)
+        *p_level = btm_cb.busy_level;
+
+    btm_cb.bl_evt_mask = evt_mask;
+
+    if (!p_cb)
+        btm_cb.p_bl_changed_cb = NULL;
+    else if (btm_cb.p_bl_changed_cb)
+        return(BTM_BUSY);
+    else
+        btm_cb.p_bl_changed_cb = p_cb;
+
+    return(BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_SetQoS
+**
+** Description      This function is called to setup QoS
+**
+** Returns          status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetQoS (BD_ADDR bd, FLOW_SPEC *p_flow, tBTM_CMPL_CB *p_cb)
+{
+    tACL_CONN   *p = &btm_cb.acl_db[0];
+
+    BTM_TRACE_API ("BTM_SetQoS: BdAddr: %02x%02x%02x%02x%02x%02x",
+                    bd[0], bd[1], bd[2],
+                    bd[3], bd[4], bd[5]);
+
+    /* If someone already waiting on the version, do not allow another */
+    if (btm_cb.devcb.p_qos_setup_cmpl_cb)
+        return(BTM_BUSY);
+
+    if ( (p = btm_bda_to_acl(bd, BT_TRANSPORT_BR_EDR)) != NULL)
+    {
+        btm_cb.devcb.p_qos_setup_cmpl_cb = p_cb;
+        alarm_set_on_queue(btm_cb.devcb.qos_setup_timer,
+                           BTM_DEV_REPLY_TIMEOUT_MS,
+                           btm_qos_setup_timeout, NULL,
+                           btu_general_alarm_queue);
+
+        btsnd_hcic_qos_setup(p->hci_handle, p_flow->qos_flags, p_flow->service_type,
+                                   p_flow->token_rate, p_flow->peak_bandwidth,
+                                   p_flow->latency,p_flow->delay_variation);
+        return(BTM_CMD_STARTED);
+    }
+
+    /* If here, no BD Addr found */
+    return(BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+**
+** Function         btm_qos_setup_timeout
+**
+** Description      Callback when QoS setup times out.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_qos_setup_timeout(UNUSED_ATTR void *data)
+{
+    tBTM_CMPL_CB  *p_cb = btm_cb.devcb.p_qos_setup_cmpl_cb;
+    btm_cb.devcb.p_qos_setup_cmpl_cb = NULL;
+    if (p_cb)
+        (*p_cb)((void *) NULL);
+}
+
+/*******************************************************************************
+**
+** Function         btm_qos_setup_complete
+**
+** Description      This function is called when the command complete message
+**                  is received from the HCI for the qos setup request.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_qos_setup_complete(uint8_t status, uint16_t handle, FLOW_SPEC *p_flow)
+{
+    tBTM_CMPL_CB            *p_cb = btm_cb.devcb.p_qos_setup_cmpl_cb;
+    tBTM_QOS_SETUP_CMPL     qossu;
+
+    BTM_TRACE_DEBUG("%s", __func__);
+    alarm_cancel(btm_cb.devcb.qos_setup_timer);
+    btm_cb.devcb.p_qos_setup_cmpl_cb = NULL;
+
+    /* If there was a registered callback, call it */
+    if (p_cb)
+    {
+        memset(&qossu, 0, sizeof(tBTM_QOS_SETUP_CMPL));
+        qossu.status = status;
+        qossu.handle = handle;
+        if (p_flow != NULL)
+        {
+            qossu.flow.qos_flags = p_flow->qos_flags;
+            qossu.flow.service_type = p_flow->service_type;
+            qossu.flow.token_rate = p_flow->token_rate;
+            qossu.flow.peak_bandwidth = p_flow->peak_bandwidth;
+            qossu.flow.latency = p_flow->latency;
+            qossu.flow.delay_variation = p_flow->delay_variation;
+        }
+        BTM_TRACE_DEBUG ("BTM: p_flow->delay_variation: 0x%02x",
+                          qossu.flow.delay_variation);
+        (*p_cb)(&qossu);
+    }
+}
+
+/*******************************************************************************
+**
+** 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_RESULTS)
+**
+** Returns          BTM_CMD_STARTED if successfully initiated or error code
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadRSSI (const BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb)
+{
+    tACL_CONN   *p;
+    tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+#if (BLE_INCLUDED == TRUE)
+    tBT_DEVICE_TYPE dev_type;
+    tBLE_ADDR_TYPE  addr_type;
+#endif
+    BTM_TRACE_API ("BTM_ReadRSSI: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+                    remote_bda[0], remote_bda[1], remote_bda[2],
+                    remote_bda[3], remote_bda[4], remote_bda[5]);
+
+    /* If someone already waiting on the version, do not allow another */
+    if (btm_cb.devcb.p_rssi_cmpl_cb)
+        return(BTM_BUSY);
+
+#if (BLE_INCLUDED == TRUE)
+    BTM_ReadDevInfo(remote_bda, &dev_type, &addr_type);
+    if (dev_type == BT_DEVICE_TYPE_BLE)
+        transport = BT_TRANSPORT_LE;
+#endif
+
+    p = btm_bda_to_acl(remote_bda, transport);
+    if (p != (tACL_CONN *)NULL)
+    {
+        btm_cb.devcb.p_rssi_cmpl_cb = p_cb;
+        alarm_set_on_queue(btm_cb.devcb.read_rssi_timer,
+                           BTM_DEV_REPLY_TIMEOUT_MS, btm_read_rssi_timeout,
+                           NULL, btu_general_alarm_queue);
+
+        btsnd_hcic_read_rssi (p->hci_handle);
+        return(BTM_CMD_STARTED);
+    }
+
+    /* If here, no BD Addr found */
+    return(BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_ReadLinkQuality
+**
+** Description      This function is called to read the link qulaity.
+**                  The value of the link quality is returned in the callback.
+**                  (tBTM_LINK_QUALITY_RESULTS)
+**
+** Returns          BTM_CMD_STARTED if successfully initiated or error code
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadLinkQuality (BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb)
+{
+    tACL_CONN   *p;
+
+    BTM_TRACE_API ("BTM_ReadLinkQuality: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+                    remote_bda[0], remote_bda[1], remote_bda[2],
+                    remote_bda[3], remote_bda[4], remote_bda[5]);
+
+    /* If someone already waiting on the version, do not allow another */
+    if (btm_cb.devcb.p_link_qual_cmpl_cb)
+        return(BTM_BUSY);
+
+    p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+    if (p != (tACL_CONN *)NULL)
+    {
+        btm_cb.devcb.p_link_qual_cmpl_cb = p_cb;
+        alarm_set_on_queue(btm_cb.devcb.read_link_quality_timer,
+                           BTM_DEV_REPLY_TIMEOUT_MS,
+                           btm_read_link_quality_timeout, NULL,
+                           btu_general_alarm_queue);
+
+        btsnd_hcic_get_link_quality(p->hci_handle);
+        return(BTM_CMD_STARTED);
+    }
+
+    /* If here, no BD Addr found */
+    return(BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_ReadTxPower
+**
+** Description      This function is called to read the current
+**                  TX power of the connection. The tx power level results
+**                  are returned in the callback.
+**                  (tBTM_RSSI_RESULTS)
+**
+** Returns          BTM_CMD_STARTED if successfully initiated or error code
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadTxPower (BD_ADDR remote_bda, tBT_TRANSPORT transport, tBTM_CMPL_CB *p_cb)
+{
+    tACL_CONN   *p;
+#define BTM_READ_RSSI_TYPE_CUR  0x00
+#define BTM_READ_RSSI_TYPE_MAX  0X01
+
+    BTM_TRACE_API ("BTM_ReadTxPower: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+                    remote_bda[0], remote_bda[1], remote_bda[2],
+                    remote_bda[3], remote_bda[4], remote_bda[5]);
+
+    /* If someone already waiting on the version, do not allow another */
+    if (btm_cb.devcb.p_tx_power_cmpl_cb)
+        return(BTM_BUSY);
+
+    p = btm_bda_to_acl(remote_bda, transport);
+    if (p != (tACL_CONN *)NULL)
+    {
+        btm_cb.devcb.p_tx_power_cmpl_cb = p_cb;
+        alarm_set_on_queue(btm_cb.devcb.read_tx_power_timer,
+                       BTM_DEV_REPLY_TIMEOUT_MS,
+                       btm_read_tx_power_timeout, NULL,
+                       btu_general_alarm_queue);
+
+#if (BLE_INCLUDED == TRUE)
+        if (p->transport == BT_TRANSPORT_LE)
+        {
+            memcpy(btm_cb.devcb.read_tx_pwr_addr, remote_bda, BD_ADDR_LEN);
+            btsnd_hcic_ble_read_adv_chnl_tx_power();
+        }
+        else
+#endif
+        {
+            btsnd_hcic_read_tx_power(p->hci_handle, BTM_READ_RSSI_TYPE_CUR);
+        }
+
+        return(BTM_CMD_STARTED);
+    }
+
+    /* If here, no BD Addr found */
+    return (BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+**
+** Function         btm_read_tx_power_timeout
+**
+** Description      Callback when reading the tx power times out.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_read_tx_power_timeout(UNUSED_ATTR void *data)
+{
+    tBTM_CMPL_CB  *p_cb = btm_cb.devcb.p_tx_power_cmpl_cb;
+    btm_cb.devcb.p_tx_power_cmpl_cb = NULL;
+    if (p_cb)
+        (*p_cb)((void *) NULL);
+}
+
+/*******************************************************************************
+**
+** Function         btm_read_tx_power_complete
+**
+** Description      This function is called when the command complete message
+**                  is received from the HCI for the read tx power request.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_read_tx_power_complete(uint8_t *p, bool    is_ble)
+{
+    tBTM_CMPL_CB            *p_cb = btm_cb.devcb.p_tx_power_cmpl_cb;
+    tBTM_TX_POWER_RESULTS   results;
+    uint16_t                 handle;
+    tACL_CONN               *p_acl_cb = &btm_cb.acl_db[0];
+    uint16_t                 index;
+
+    BTM_TRACE_DEBUG("%s", __func__);
+    alarm_cancel(btm_cb.devcb.read_tx_power_timer);
+    btm_cb.devcb.p_tx_power_cmpl_cb = NULL;
+
+    /* If there was a registered callback, call it */
+    if (p_cb)
+    {
+        STREAM_TO_UINT8  (results.hci_status, p);
+
+        if (results.hci_status == HCI_SUCCESS)
+        {
+            results.status = BTM_SUCCESS;
+
+            if (!is_ble)
+            {
+                STREAM_TO_UINT16 (handle, p);
+                STREAM_TO_UINT8 (results.tx_power, p);
+
+                /* Search through the list of active channels for the correct BD Addr */
+                for (index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++)
+                {
+                    if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle))
+                    {
+                        memcpy (results.rem_bda, p_acl_cb->remote_addr, BD_ADDR_LEN);
+                        break;
+                    }
+                }
+            }
+#if (BLE_INCLUDED == TRUE)
+            else
+            {
+                STREAM_TO_UINT8 (results.tx_power, p);
+                memcpy(results.rem_bda, btm_cb.devcb.read_tx_pwr_addr, BD_ADDR_LEN);
+            }
+#endif
+            BTM_TRACE_DEBUG ("BTM TX power Complete: tx_power %d, hci status 0x%02x",
+                                  results.tx_power, results.hci_status);
+        }
+        else
+            results.status = BTM_ERR_PROCESSING;
+
+        (*p_cb)(&results);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_read_rssi_timeout
+**
+** Description      Callback when reading the RSSI times out.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_read_rssi_timeout(UNUSED_ATTR void *data)
+{
+    tBTM_CMPL_CB  *p_cb = btm_cb.devcb.p_rssi_cmpl_cb;
+    btm_cb.devcb.p_rssi_cmpl_cb = NULL;
+    if (p_cb)
+        (*p_cb)((void *) NULL);
+}
+
+/*******************************************************************************
+**
+** Function         btm_read_rssi_complete
+**
+** Description      This function is called when the command complete message
+**                  is received from the HCI for the read rssi request.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_read_rssi_complete (uint8_t *p)
+{
+    tBTM_CMPL_CB            *p_cb = btm_cb.devcb.p_rssi_cmpl_cb;
+    tBTM_RSSI_RESULTS        results;
+    uint16_t                 handle;
+    tACL_CONN               *p_acl_cb = &btm_cb.acl_db[0];
+    uint16_t                 index;
+
+    BTM_TRACE_DEBUG("%s", __func__);
+    alarm_cancel(btm_cb.devcb.read_rssi_timer);
+    btm_cb.devcb.p_rssi_cmpl_cb = NULL;
+
+    /* If there was a registered callback, call it */
+    if (p_cb)
+    {
+        STREAM_TO_UINT8  (results.hci_status, p);
+
+        if (results.hci_status == HCI_SUCCESS)
+        {
+            results.status = BTM_SUCCESS;
+
+            STREAM_TO_UINT16 (handle, p);
+
+            STREAM_TO_UINT8 (results.rssi, p);
+            BTM_TRACE_DEBUG ("BTM RSSI Complete: rssi %d, hci status 0x%02x",
+                              results.rssi, results.hci_status);
+
+            /* Search through the list of active channels for the correct BD Addr */
+            for (index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++)
+            {
+                if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle))
+                {
+                    memcpy (results.rem_bda, p_acl_cb->remote_addr, BD_ADDR_LEN);
+                    break;
+                }
+            }
+        }
+        else
+            results.status = BTM_ERR_PROCESSING;
+
+        (*p_cb)(&results);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_read_link_quality_timeout
+**
+** Description      Callback when reading the link quality times out.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_read_link_quality_timeout(UNUSED_ATTR void *data)
+{
+    tBTM_CMPL_CB  *p_cb = btm_cb.devcb.p_link_qual_cmpl_cb;
+    btm_cb.devcb.p_link_qual_cmpl_cb = NULL;
+    if (p_cb)
+        (*p_cb)((void *) NULL);
+}
+
+/*******************************************************************************
+**
+** Function         btm_read_link_quality_complete
+**
+** Description      This function is called when the command complete message
+**                  is received from the HCI for the read link quality.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_read_link_quality_complete(uint8_t *p)
+{
+    tBTM_CMPL_CB            *p_cb = btm_cb.devcb.p_link_qual_cmpl_cb;
+    tBTM_LINK_QUALITY_RESULTS results;
+    uint16_t                 handle;
+    tACL_CONN               *p_acl_cb = &btm_cb.acl_db[0];
+    uint16_t                 index;
+
+    BTM_TRACE_DEBUG("%s", __func__);
+    alarm_cancel(btm_cb.devcb.read_link_quality_timer);
+    btm_cb.devcb.p_link_qual_cmpl_cb = NULL;
+
+    /* If there was a registered callback, call it */
+    if (p_cb)
+    {
+        STREAM_TO_UINT8  (results.hci_status, p);
+
+        if (results.hci_status == HCI_SUCCESS)
+        {
+            results.status = BTM_SUCCESS;
+
+            STREAM_TO_UINT16 (handle, p);
+
+            STREAM_TO_UINT8 (results.link_quality, p);
+            BTM_TRACE_DEBUG ("BTM Link Quality Complete: Link Quality %d, hci status 0x%02x",
+                              results.link_quality, results.hci_status);
+
+            /* Search through the list of active channels for the correct BD Addr */
+            for (index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++)
+            {
+                if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle))
+                {
+                    memcpy (results.rem_bda, p_acl_cb->remote_addr, BD_ADDR_LEN);
+                    break;
+                }
+            }
+        }
+        else
+            results.status = BTM_ERR_PROCESSING;
+
+        (*p_cb)(&results);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_remove_acl
+**
+** Description      This function is called to disconnect an ACL connection
+**
+** Returns          BTM_SUCCESS if successfully initiated, otherwise BTM_NO_RESOURCES.
+**
+*******************************************************************************/
+tBTM_STATUS btm_remove_acl (BD_ADDR bd_addr, tBT_TRANSPORT transport)
+{
+    uint16_t hci_handle = BTM_GetHCIConnHandle(bd_addr, transport);
+    tBTM_STATUS status = BTM_SUCCESS;
+
+    BTM_TRACE_DEBUG ("btm_remove_acl");
+#if (BTM_DISC_DURING_RS == TRUE)
+    tBTM_SEC_DEV_REC  *p_dev_rec = btm_find_dev (bd_addr);
+
+    /* Role Switch is pending, postpone until completed */
+    if (p_dev_rec && (p_dev_rec->rs_disc_pending == BTM_SEC_RS_PENDING))
+    {
+        p_dev_rec->rs_disc_pending = BTM_SEC_DISC_PENDING;
+    }
+    else    /* otherwise can disconnect right away */
+#endif
+    {
+        if (hci_handle != 0xFFFF && p_dev_rec &&
+             p_dev_rec->sec_state!= BTM_SEC_STATE_DISCONNECTING)
+        {
+            btsnd_hcic_disconnect(hci_handle, HCI_ERR_PEER_USER);
+        }
+        else
+            status = BTM_UNKNOWN_ADDR;
+    }
+
+    return status;
+}
+
+
+/*******************************************************************************
+**
+** 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)
+{
+    BTM_TRACE_DEBUG ("BTM_SetTraceLevel");
+    if (new_level != 0xFF)
+        btm_cb.trace_level = new_level;
+
+    return(btm_cb.trace_level);
+}
+
+/*******************************************************************************
+**
+** Function         btm_cont_rswitch
+**
+** Description      This function is called to continue processing an active
+**                  role switch. It first disables encryption if enabled and
+**                  EPR is not supported
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_cont_rswitch (tACL_CONN *p, tBTM_SEC_DEV_REC *p_dev_rec,
+                                     uint8_t hci_status)
+{
+    BTM_TRACE_DEBUG ("btm_cont_rswitch");
+    /* Check to see if encryption needs to be turned off if pending
+       change of link key or role switch */
+    if (p->switch_role_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE)
+    {
+        /* Must turn off Encryption first if necessary */
+        /* Some devices do not support switch or change of link key while encryption is on */
+        if (p_dev_rec != NULL && ((p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) != 0)
+            && !BTM_EPR_AVAILABLE(p))
+        {
+            btsnd_hcic_set_conn_encrypt(p->hci_handle, false);
+            p->encrypt_state = BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF;
+            if (p->switch_role_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE)
+                p->switch_role_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF;
+        }
+        else    /* Encryption not used or EPR supported, continue with switch
+                   and/or change of link key */
+        {
+            if (p->switch_role_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE)
+            {
+                p->switch_role_state = BTM_ACL_SWKEY_STATE_IN_PROGRESS;
+#if (BTM_DISC_DURING_RS == TRUE)
+                if (p_dev_rec)
+                    p_dev_rec->rs_disc_pending = BTM_SEC_RS_PENDING;
+#endif
+                btsnd_hcic_switch_role(p->remote_addr, (uint8_t)!p->link_role);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_acl_resubmit_page
+**
+** Description      send pending page request
+**
+*******************************************************************************/
+void btm_acl_resubmit_page (void)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec;
+    BT_HDR  *p_buf;
+    uint8_t *pp;
+    BD_ADDR bda;
+    BTM_TRACE_DEBUG ("btm_acl_resubmit_page");
+    /* If there were other page request schedule can start the next one */
+    if ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(btm_cb.page_queue)) != NULL)
+    {
+        /* skip 3 (2 bytes opcode and 1 byte len) to get to the bd_addr
+         * for both create_conn and rmt_name */
+        pp = (uint8_t *)(p_buf + 1) + p_buf->offset + 3;
+
+        STREAM_TO_BDADDR (bda, pp);
+
+        p_dev_rec = btm_find_or_alloc_dev (bda);
+
+        memcpy (btm_cb.connecting_bda, p_dev_rec->bd_addr,   BD_ADDR_LEN);
+        memcpy (btm_cb.connecting_dc,  p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+        btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p_buf);
+    }
+    else
+        btm_cb.paging = false;
+}
+
+/*******************************************************************************
+**
+** Function         btm_acl_reset_paging
+**
+** Description      set paging to false and free the page queue - called at hci_reset
+**
+*******************************************************************************/
+void  btm_acl_reset_paging (void)
+{
+    BT_HDR *p;
+    BTM_TRACE_DEBUG ("btm_acl_reset_paging");
+    /* If we sent reset we are definitely not paging any more */
+    while ((p = (BT_HDR *)fixed_queue_try_dequeue(btm_cb.page_queue)) != NULL)
+        osi_free(p);
+
+    btm_cb.paging = false;
+}
+
+/*******************************************************************************
+**
+** Function         btm_acl_paging
+**
+** Description      send a paging command or queue it in btm_cb
+**
+*******************************************************************************/
+void  btm_acl_paging (BT_HDR *p, BD_ADDR bda)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec;
+
+    BTM_TRACE_DEBUG ("btm_acl_paging discing:%d, paging:%d BDA: %06x%06x",
+                      btm_cb.discing, btm_cb.paging,
+                      (bda[0]<<16) + (bda[1]<<8) + bda[2], (bda[3]<<16) + (bda[4] << 8) + bda[5]);
+    if (btm_cb.discing)
+    {
+        btm_cb.paging = true;
+        fixed_queue_enqueue(btm_cb.page_queue, p);
+    }
+    else
+    {
+        if (!BTM_ACL_IS_CONNECTED (bda))
+        {
+            BTM_TRACE_DEBUG ("connecting_bda: %06x%06x",
+                              (btm_cb.connecting_bda[0]<<16) + (btm_cb.connecting_bda[1]<<8) +
+                               btm_cb.connecting_bda[2],
+                              (btm_cb.connecting_bda[3]<<16) + (btm_cb.connecting_bda[4] << 8) +
+                               btm_cb.connecting_bda[5]);
+            if (btm_cb.paging &&
+                memcmp (bda, btm_cb.connecting_bda, BD_ADDR_LEN) != 0)
+            {
+                fixed_queue_enqueue(btm_cb.page_queue, p);
+            }
+            else
+            {
+                p_dev_rec = btm_find_or_alloc_dev (bda);
+                memcpy (btm_cb.connecting_bda, p_dev_rec->bd_addr,   BD_ADDR_LEN);
+                memcpy (btm_cb.connecting_dc,  p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+                btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+            }
+
+            btm_cb.paging = true;
+        }
+        else /* ACL is already up */
+        {
+            btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_acl_notif_conn_collision
+**
+** Description      Send connection collision event to upper layer if registered
+**
+** Returns          true if sent out to upper layer,
+**                  false if no one needs the notification.
+**
+*******************************************************************************/
+bool     btm_acl_notif_conn_collision (BD_ADDR bda)
+{
+    tBTM_BL_EVENT_DATA  evt_data;
+
+    /* Report possible collision to the upper layer. */
+    if (btm_cb.p_bl_changed_cb)
+    {
+        BTM_TRACE_DEBUG ("btm_acl_notif_conn_collision: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+                          bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+
+        evt_data.event = BTM_BL_COLLISION_EVT;
+        evt_data.conn.p_bda = bda;
+
+#if (BLE_INCLUDED == TRUE)
+        evt_data.conn.transport = BT_TRANSPORT_BR_EDR;
+        evt_data.conn.handle = BTM_INVALID_HCI_HANDLE;
+#endif
+        (*btm_cb.p_bl_changed_cb)(&evt_data);
+        return true;
+    }
+    else
+        return false;
+}
+
+
+/*******************************************************************************
+**
+** Function         btm_acl_chk_peer_pkt_type_support
+**
+** Description      Check if peer supports requested packets
+**
+*******************************************************************************/
+void btm_acl_chk_peer_pkt_type_support (tACL_CONN *p, uint16_t *p_pkt_type)
+{
+    /* 3 and 5 slot packets? */
+    if (!HCI_3_SLOT_PACKETS_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]))
+        *p_pkt_type &= ~(BTM_ACL_PKT_TYPES_MASK_DH3 +BTM_ACL_PKT_TYPES_MASK_DM3);
+
+    if (!HCI_5_SLOT_PACKETS_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]))
+        *p_pkt_type &= ~(BTM_ACL_PKT_TYPES_MASK_DH5 + BTM_ACL_PKT_TYPES_MASK_DM5);
+
+    /* 2 and 3 MPS support? */
+    if (!HCI_EDR_ACL_2MPS_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]))
+        /* Not supported. Add 'not_supported' mask for all 2MPS packet types */
+        *p_pkt_type |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH1 + BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 +
+                            BTM_ACL_PKT_TYPES_MASK_NO_2_DH5);
+
+    if (!HCI_EDR_ACL_3MPS_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]))
+        /* Not supported. Add 'not_supported' mask for all 3MPS packet types */
+        *p_pkt_type |= (BTM_ACL_PKT_TYPES_MASK_NO_3_DH1 + BTM_ACL_PKT_TYPES_MASK_NO_3_DH3 +
+                            BTM_ACL_PKT_TYPES_MASK_NO_3_DH5);
+
+    /* EDR 3 and 5 slot support? */
+    if (HCI_EDR_ACL_2MPS_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])
+     || HCI_EDR_ACL_3MPS_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]))
+    {
+        if (!HCI_3_SLOT_EDR_ACL_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]))
+            /* Not supported. Add 'not_supported' mask for all 3-slot EDR packet types */
+            *p_pkt_type |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 + BTM_ACL_PKT_TYPES_MASK_NO_3_DH3);
+
+        if (!HCI_5_SLOT_EDR_ACL_SUPPORTED(p->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]))
+            /* Not supported. Add 'not_supported' mask for all 5-slot EDR packet types */
+            *p_pkt_type |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH5 + BTM_ACL_PKT_TYPES_MASK_NO_3_DH5);
+    }
+}
diff --git a/bt/stack/btm/btm_ble.cc b/bt/stack/btm/btm_ble.cc
new file mode 100644
index 0000000..a10a68b
--- /dev/null
+++ b/bt/stack/btm/btm_ble.cc
@@ -0,0 +1,2756 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 functions for BLE device control utilities, and LE
+ *  security functions.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btm_ble"
+
+#include "bt_target.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_ble_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "gap_api.h"
+#include "gatt_api.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "smp_api.h"
+
+#if (SMP_INCLUDED == TRUE)
+extern bool    aes_cipher_msg_auth_code(BT_OCTET16 key, uint8_t *input, uint16_t length,
+                                                 uint16_t tlen, uint8_t *p_signature);
+#endif
+
+/*******************************************************************************/
+/* External Function to be called by other modules                             */
+/*******************************************************************************/
+/********************************************************
+**
+** 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 BD_ADDR bd_addr, BD_NAME bd_name, tBT_DEVICE_TYPE dev_type,
+                             tBLE_ADDR_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);
+    if (!p_dev_rec)
+    {
+        p_dev_rec = btm_sec_allocate_dev_rec();
+
+        memcpy(p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN);
+        p_dev_rec->hci_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_BR_EDR);
+        p_dev_rec->ble_hci_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE);
+
+        /* update conn params, use default value for background connection params */
+        p_dev_rec->conn_params.min_conn_int     = BTM_BLE_CONN_PARAM_UNDEF;
+        p_dev_rec->conn_params.max_conn_int     = BTM_BLE_CONN_PARAM_UNDEF;
+        p_dev_rec->conn_params.supervision_tout = BTM_BLE_CONN_PARAM_UNDEF;
+        p_dev_rec->conn_params.slave_latency    = BTM_BLE_CONN_PARAM_UNDEF;
+
+        BTM_TRACE_DEBUG("%s: Device added, handle=0x%x ", __func__, p_dev_rec->ble_hci_handle);
+    }
+
+    memset(p_dev_rec->sec_bd_name, 0, sizeof(tBTM_BD_NAME));
+
+    if (bd_name && bd_name[0])
+    {
+        p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN;
+        strlcpy((char *)p_dev_rec->sec_bd_name,
+                (char *)bd_name, BTM_MAX_REM_BD_NAME_LEN);
+    }
+    p_dev_rec->device_type |= dev_type;
+    p_dev_rec->ble.ble_addr_type = addr_type;
+
+    memcpy(p_dev_rec->ble.pseudo_addr, bd_addr, BD_ADDR_LEN);
+    /* sync up with the Inq Data base*/
+    tBTM_INQ_INFO      *p_info = BTM_InqDbRead(bd_addr);
+    if (p_info)
+    {
+        p_info->results.ble_addr_type = p_dev_rec->ble.ble_addr_type ;
+        p_info->results.device_type = p_dev_rec->device_type;
+        BTM_TRACE_DEBUG("InqDb  device_type =0x%x  addr_type=0x%x",
+                         p_info->results.device_type, p_info->results.ble_addr_type);
+    }
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** 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 (BD_ADDR bd_addr, tBTM_LE_KEY_VALUE *p_le_key, tBTM_LE_KEY_TYPE key_type)
+{
+#if (SMP_INCLUDED == TRUE)
+    tBTM_SEC_DEV_REC  *p_dev_rec;
+    BTM_TRACE_DEBUG ("BTM_SecAddBleKey");
+    p_dev_rec = btm_find_dev (bd_addr);
+    if (!p_dev_rec || !p_le_key ||
+        (key_type != BTM_LE_KEY_PENC && key_type != BTM_LE_KEY_PID &&
+         key_type != BTM_LE_KEY_PCSRK && key_type != BTM_LE_KEY_LENC &&
+         key_type != BTM_LE_KEY_LCSRK && key_type != BTM_LE_KEY_LID))
+    {
+        BTM_TRACE_WARNING ("BTM_SecAddBleKey()  Wrong Type, or No Device record \
+                        for bdaddr: %08x%04x, Type: %d",
+                            (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
+                            (bd_addr[4]<<8)+bd_addr[5], key_type);
+        return(false);
+    }
+
+    BTM_TRACE_DEBUG ("BTM_SecAddLeKey()  BDA: %08x%04x, Type: 0x%02x",
+                      (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
+                      (bd_addr[4]<<8)+bd_addr[5], key_type);
+
+    btm_sec_save_le_key (bd_addr, key_type, p_le_key, false);
+
+#if (BLE_PRIVACY_SPT == TRUE)
+    if (key_type == BTM_LE_KEY_PID || key_type == BTM_LE_KEY_LID)
+        btm_ble_resolving_list_load_dev (p_dev_rec);
+#endif
+
+#endif
+
+    return(true);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    tBTM_DEVCB *p_devcb = &btm_cb.devcb;
+    BTM_TRACE_DEBUG ("%s", __func__);
+    if (p_key != NULL)
+    {
+        switch (key_type)
+        {
+            case BTM_BLE_KEY_TYPE_ID:
+                memcpy(&p_devcb->id_keys, &p_key->id_keys, sizeof(tBTM_BLE_LOCAL_ID_KEYS));
+                break;
+
+            case BTM_BLE_KEY_TYPE_ER:
+                memcpy(p_devcb->ble_encryption_key_value, p_key->er, sizeof(BT_OCTET16));
+                break;
+
+            default:
+                BTM_TRACE_ERROR("unknow local key type: %d", key_type);
+                break;
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTM_GetDeviceEncRoot
+**
+** Description      This function is called to read the local device encryption
+**                  root.
+**
+** Returns          void
+**                  the local device ER is copied into ble_encr_key_value
+**
+*******************************************************************************/
+void BTM_GetDeviceEncRoot (BT_OCTET16 ble_encr_key_value)
+{
+    BTM_TRACE_DEBUG ("%s", __func__);
+    memcpy (ble_encr_key_value, btm_cb.devcb.ble_encryption_key_value, BT_OCTET16_LEN);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_GetDeviceIDRoot
+**
+** Description      This function is called to read the local device identity
+**                  root.
+**
+** Returns          void
+**                  the local device IR is copied into irk
+**
+*******************************************************************************/
+void BTM_GetDeviceIDRoot (BT_OCTET16 irk)
+{
+    BTM_TRACE_DEBUG ("BTM_GetDeviceIDRoot ");
+
+    memcpy (irk, btm_cb.devcb.id_keys.irk, BT_OCTET16_LEN);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_GetDeviceDHK
+**
+** Description      This function is called to read the local device DHK.
+**
+** Returns          void
+**                  the local device DHK is copied into dhk
+**
+*******************************************************************************/
+void BTM_GetDeviceDHK (BT_OCTET16 dhk)
+{
+    BTM_TRACE_DEBUG ("BTM_GetDeviceDHK");
+    memcpy (dhk, btm_cb.devcb.id_keys.dhk, BT_OCTET16_LEN);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_ReadConnectionAddr
+**
+** Description      This function is called to get the local device address information
+**                  .
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTM_ReadConnectionAddr (BD_ADDR remote_bda, BD_ADDR local_conn_addr, tBLE_ADDR_TYPE *p_addr_type)
+{
+    tACL_CONN       *p_acl = btm_bda_to_acl(remote_bda, BT_TRANSPORT_LE);
+
+    if (p_acl == NULL)
+    {
+        BTM_TRACE_ERROR("No connection exist!");
+        return;
+    }
+    memcpy(local_conn_addr, p_acl->conn_addr, BD_ADDR_LEN);
+    * p_addr_type = p_acl->conn_addr_type;
+
+    BTM_TRACE_DEBUG ("BTM_ReadConnectionAddr address type: %d addr: 0x%02x",
+                    p_acl->conn_addr_type, p_acl->conn_addr[0]);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+#if (BLE_INCLUDED == TRUE)
+    uint8_t              xx;
+    tACL_CONN            *p;
+
+    BTM_TRACE_API ("BTM_IsBleConnection: conn_handle: %d", conn_handle);
+
+    xx = btm_handle_to_acl_index (conn_handle);
+    if (xx >= MAX_L2CAP_LINKS)
+        return false;
+
+    p = &btm_cb.acl_db[xx];
+
+    return (p->transport == BT_TRANSPORT_LE);
+#else
+    return false;
+#endif
+}
+
+/*******************************************************************************
+**
+** 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    BTM_ReadRemoteConnectionAddr(BD_ADDR pseudo_addr, BD_ADDR conn_addr,
+                                               tBLE_ADDR_TYPE *p_addr_type)
+{
+ bool            st = true;
+#if (BLE_PRIVACY_SPT == TRUE)
+    tACL_CONN       *p = btm_bda_to_acl (pseudo_addr, BT_TRANSPORT_LE);
+
+    if (p == NULL)
+    {
+        BTM_TRACE_ERROR("BTM_ReadRemoteConnectionAddr can not find connection"
+                        " with matching address");
+        return false;
+    }
+
+    memcpy(conn_addr, p->active_remote_addr, BD_ADDR_LEN);
+    *p_addr_type = p->active_remote_addr_type;
+#else
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(pseudo_addr);
+
+    memcpy(conn_addr, pseudo_addr, BD_ADDR_LEN);
+    if (p_dev_rec != NULL)
+    {
+        *p_addr_type = p_dev_rec->ble.ble_addr_type;
+    }
+#endif
+    return st;
+
+}
+/*******************************************************************************
+**
+** 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(BD_ADDR bd_addr, uint8_t res)
+{
+#if (SMP_INCLUDED == TRUE)
+    tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_REPEATED_ATTEMPTS;
+    BTM_TRACE_DEBUG ("BTM_SecurityGrant");
+    SMP_SecurityGrant(bd_addr, res_smp);
+#endif
+}
+
+/*******************************************************************************
+**
+** 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 BTM_BlePasskeyReply (BD_ADDR bd_addr, uint8_t res, uint32_t passkey)
+{
+#if (SMP_INCLUDED == TRUE)
+    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;
+
+    if (p_dev_rec == NULL)
+    {
+        BTM_TRACE_ERROR("Passkey reply to Unknown device");
+        return;
+    }
+
+    p_dev_rec->sec_flags   |= BTM_SEC_LE_AUTHENTICATED;
+    BTM_TRACE_DEBUG ("BTM_BlePasskeyReply");
+    SMP_PasskeyReply(bd_addr, res_smp, passkey);
+#endif
+}
+
+/*******************************************************************************
+**
+** 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 (BD_ADDR bd_addr, uint8_t 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;
+
+    if (p_dev_rec == NULL)
+    {
+        BTM_TRACE_ERROR("Passkey reply to Unknown device");
+        return;
+    }
+
+    p_dev_rec->sec_flags   |= BTM_SEC_LE_AUTHENTICATED;
+    BTM_TRACE_DEBUG ("%s", __func__);
+    SMP_ConfirmReply(bd_addr, res_smp);
+}
+
+/*******************************************************************************
+**
+** 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 BTM_BleOobDataReply(BD_ADDR bd_addr, uint8_t res, uint8_t len, uint8_t *p_data)
+{
+#if (SMP_INCLUDED == TRUE)
+    tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_OOB_FAIL;
+    tBTM_SEC_DEV_REC  *p_dev_rec = btm_find_dev (bd_addr);
+
+    BTM_TRACE_DEBUG ("%s:", __func__);
+
+    if (p_dev_rec == NULL) {
+        BTM_TRACE_ERROR("%s: Unknown device", __func__);
+        return;
+    }
+
+    p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED;
+    SMP_OobDataReply(bd_addr, res_smp, len, p_data);
+#endif
+}
+
+/*******************************************************************************
+**
+** 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(BD_ADDR bd_addr,
+                                         uint8_t *p_c, uint8_t *p_r)
+{
+#if SMP_INCLUDED == TRUE
+    tBTM_SEC_DEV_REC  *p_dev_rec = btm_find_dev (bd_addr);
+
+    BTM_TRACE_DEBUG ("%s:", __func__);
+
+    if (p_dev_rec == NULL) {
+        BTM_TRACE_ERROR("%s: Unknown device", __func__);
+        return;
+    }
+
+    p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED;
+
+    tSMP_SC_OOB_DATA oob;
+    memset(&oob, 0, sizeof(tSMP_SC_OOB_DATA));
+
+    oob.peer_oob_data.present = true;
+    memcpy(&oob.peer_oob_data.randomizer, p_r, BT_OCTET16_LEN);
+    memcpy(&oob.peer_oob_data.commitment, p_c, BT_OCTET16_LEN);
+    oob.peer_oob_data.addr_rcvd_from.type = p_dev_rec->ble.ble_addr_type;
+    memcpy(&oob.peer_oob_data.addr_rcvd_from.bda, bd_addr, sizeof(BD_ADDR));
+
+    SMP_SecureConnectionOobDataReply((uint8_t*)&oob);
+#endif
+}
+
+/******************************************************************************
+**
+** Function         BTM_BleSetConnScanParams
+**
+** Description      Set scan parameter 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)
+{
+#if (SMP_INCLUDED == TRUE)
+    tBTM_BLE_CB *p_ble_cb = &btm_cb.ble_ctr_cb;
+    bool        new_param = false;
+
+    if (BTM_BLE_ISVALID_PARAM(scan_interval, BTM_BLE_SCAN_INT_MIN, BTM_BLE_SCAN_INT_MAX) &&
+        BTM_BLE_ISVALID_PARAM(scan_window, BTM_BLE_SCAN_WIN_MIN, BTM_BLE_SCAN_WIN_MAX))
+    {
+        if (p_ble_cb->scan_int != scan_interval)
+        {
+            p_ble_cb->scan_int = scan_interval;
+            new_param = true;
+        }
+
+        if (p_ble_cb->scan_win != scan_window)
+        {
+            p_ble_cb->scan_win = scan_window;
+            new_param = true;
+        }
+
+        if (new_param && p_ble_cb->conn_state == BLE_BG_CONN)
+        {
+            btm_ble_suspend_bg_conn();
+        }
+    }
+    else
+    {
+        BTM_TRACE_ERROR("Illegal Connection Scan Parameters");
+    }
+#endif
+}
+
+/********************************************************
+**
+** 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 BTM_BleSetPrefConnParams (BD_ADDR bd_addr,
+                               uint16_t min_conn_int, uint16_t max_conn_int,
+                               uint16_t slave_latency, uint16_t supervision_tout)
+{
+    tBTM_SEC_DEV_REC  *p_dev_rec = btm_find_dev (bd_addr);
+
+    BTM_TRACE_API ("BTM_BleSetPrefConnParams min: %u  max: %u  latency: %u  \
+                    tout: %u",
+                    min_conn_int, max_conn_int, slave_latency, supervision_tout);
+
+    if (BTM_BLE_ISVALID_PARAM(min_conn_int, BTM_BLE_CONN_INT_MIN, BTM_BLE_CONN_INT_MAX) &&
+        BTM_BLE_ISVALID_PARAM(max_conn_int, BTM_BLE_CONN_INT_MIN, BTM_BLE_CONN_INT_MAX) &&
+        BTM_BLE_ISVALID_PARAM(supervision_tout, BTM_BLE_CONN_SUP_TOUT_MIN, BTM_BLE_CONN_SUP_TOUT_MAX) &&
+        (slave_latency <= BTM_BLE_CONN_LATENCY_MAX || slave_latency == BTM_BLE_CONN_PARAM_UNDEF))
+    {
+        if (p_dev_rec)
+        {
+            /* expect conn int and stout and slave latency to be updated all together */
+            if (min_conn_int != BTM_BLE_CONN_PARAM_UNDEF || max_conn_int != BTM_BLE_CONN_PARAM_UNDEF)
+            {
+                if (min_conn_int != BTM_BLE_CONN_PARAM_UNDEF)
+                    p_dev_rec->conn_params.min_conn_int = min_conn_int;
+                else
+                    p_dev_rec->conn_params.min_conn_int = max_conn_int;
+
+                if (max_conn_int != BTM_BLE_CONN_PARAM_UNDEF)
+                    p_dev_rec->conn_params.max_conn_int = max_conn_int;
+                else
+                    p_dev_rec->conn_params.max_conn_int = min_conn_int;
+
+                if (slave_latency != BTM_BLE_CONN_PARAM_UNDEF)
+                    p_dev_rec->conn_params.slave_latency = slave_latency;
+                else
+                    p_dev_rec->conn_params.slave_latency = BTM_BLE_CONN_SLAVE_LATENCY_DEF;
+
+                if (supervision_tout != BTM_BLE_CONN_PARAM_UNDEF)
+                    p_dev_rec->conn_params.supervision_tout = supervision_tout;
+                else
+                    p_dev_rec->conn_params.supervision_tout = BTM_BLE_CONN_TIMEOUT_DEF;
+
+            }
+
+        }
+        else
+        {
+            BTM_TRACE_ERROR("Unknown Device, setting rejected");
+        }
+    }
+    else
+    {
+        BTM_TRACE_ERROR("Illegal Connection Parameters");
+    }
+}
+
+/*******************************************************************************
+**
+** 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 BD_ADDR remote_bda, tBT_DEVICE_TYPE *p_dev_type, tBLE_ADDR_TYPE *p_addr_type)
+{
+    tBTM_SEC_DEV_REC  *p_dev_rec = btm_find_dev (remote_bda);
+    tBTM_INQ_INFO     *p_inq_info = BTM_InqDbRead(remote_bda);
+
+    *p_addr_type = BLE_ADDR_PUBLIC;
+
+    if (!p_dev_rec)
+    {
+        *p_dev_type = BT_DEVICE_TYPE_BREDR;
+        /* Check with the BT manager if details about remote device are known */
+        if (p_inq_info != NULL)
+        {
+            *p_dev_type = p_inq_info->results.device_type ;
+            *p_addr_type = p_inq_info->results.ble_addr_type;
+        } else {
+            /* unknown device, assume BR/EDR */
+            BTM_TRACE_DEBUG ("btm_find_dev_type - unknown device, BR/EDR assumed");
+        }
+    }
+    else /* there is a security device record exisitng */
+    {
+        /* new inquiry result, overwrite device type in security device record */
+        if (p_inq_info)
+        {
+            p_dev_rec->device_type          = p_inq_info->results.device_type;
+            p_dev_rec->ble.ble_addr_type    = p_inq_info->results.ble_addr_type;
+        }
+        if (memcmp(p_dev_rec->bd_addr, remote_bda, BD_ADDR_LEN) == 0 &&
+            memcmp(p_dev_rec->ble.pseudo_addr, remote_bda, BD_ADDR_LEN) == 0)
+        {
+            *p_dev_type = p_dev_rec->device_type;
+            *p_addr_type = p_dev_rec->ble.ble_addr_type;
+        }
+        else if (memcmp(p_dev_rec->ble.pseudo_addr, remote_bda, BD_ADDR_LEN) == 0)
+        {
+            *p_dev_type = BT_DEVICE_TYPE_BLE;
+            *p_addr_type = p_dev_rec->ble.ble_addr_type;
+        }
+        else  /* matching static adddress only */
+        {
+            *p_dev_type = BT_DEVICE_TYPE_BREDR;
+            *p_addr_type = BLE_ADDR_PUBLIC;
+        }
+
+    }
+
+    BTM_TRACE_DEBUG ("btm_find_dev_type - device_type = %d addr_type = %d", *p_dev_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(BD_ADDR remote_bda, tBT_TRANSPORT transport)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(remote_bda);
+
+    /* if no device can be located, return */
+    if (p_dev_rec == NULL)
+        return false;
+
+    if (transport == BT_TRANSPORT_BR_EDR)
+    {
+        if (btm_bda_to_acl(p_dev_rec->bd_addr, transport) != NULL)
+        {
+            memcpy(remote_bda, p_dev_rec->bd_addr, BD_ADDR_LEN);
+            return true;
+        }
+        else if (p_dev_rec->device_type & BT_DEVICE_TYPE_BREDR)
+        {
+            memcpy(remote_bda, p_dev_rec->bd_addr, BD_ADDR_LEN);
+        }
+        else
+            memset(remote_bda, 0, BD_ADDR_LEN);
+        return false;
+    }
+
+    if (transport == BT_TRANSPORT_LE)
+    {
+        memcpy(remote_bda, p_dev_rec->ble.pseudo_addr, BD_ADDR_LEN);
+        if (btm_bda_to_acl(p_dev_rec->ble.pseudo_addr, transport) != NULL)
+            return true;
+        else
+            return false;
+    }
+
+    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 BTM_BleReceiverTest(uint8_t rx_freq, tBTM_CMPL_CB *p_cmd_cmpl_cback)
+{
+     btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
+
+     btsnd_hcic_ble_receiver_test(rx_freq);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+     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);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+     btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
+
+     btsnd_hcic_ble_test_end();
+}
+
+/*******************************************************************************
+** Internal Functions
+*******************************************************************************/
+void btm_ble_test_command_complete(uint8_t *p)
+{
+    tBTM_CMPL_CB   *p_cb = btm_cb.devcb.p_le_test_cmd_cmpl_cb;
+
+    btm_cb.devcb.p_le_test_cmd_cmpl_cb = NULL;
+
+    if (p_cb)
+    {
+        (*p_cb)(p);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTM_UseLeLink
+**
+** Description      This function is to select the underneath physical link to use.
+**
+** Returns          true to use LE, false use BR/EDR.
+**
+*******************************************************************************/
+bool    BTM_UseLeLink (BD_ADDR bd_addr)
+{
+    tACL_CONN         *p;
+    tBT_DEVICE_TYPE     dev_type;
+    tBLE_ADDR_TYPE      addr_type;
+    bool                use_le = false;
+
+    if ((p = btm_bda_to_acl(bd_addr, BT_TRANSPORT_BR_EDR)) != NULL)
+    {
+        return use_le;
+    }
+    else if ((p = btm_bda_to_acl(bd_addr, BT_TRANSPORT_LE)) != NULL)
+    {
+        use_le = true;
+    }
+    else
+    {
+        BTM_ReadDevInfo(bd_addr, &dev_type, &addr_type);
+        use_le = (dev_type == BT_DEVICE_TYPE_BLE);
+    }
+    return use_le;
+}
+
+/*******************************************************************************
+**
+** Function         BTM_SetBleDataLength
+**
+** Description      This function is to set maximum BLE transmission packet size
+**
+** Returns          BTM_SUCCESS if success; otherwise failed.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetBleDataLength(BD_ADDR bd_addr, uint16_t tx_pdu_length)
+{
+    tACL_CONN *p_acl = btm_bda_to_acl(bd_addr, BT_TRANSPORT_LE);
+    BTM_TRACE_DEBUG("%s: tx_pdu_length =%d", __func__, tx_pdu_length);
+
+    if (!controller_get_interface()->supports_ble_packet_extension())
+    {
+        BTM_TRACE_ERROR("%s failed, request not supported", __func__);
+        return BTM_ILLEGAL_VALUE;
+    }
+
+    if (!HCI_LE_DATA_LEN_EXT_SUPPORTED(p_acl->peer_le_features))
+    {
+        BTM_TRACE_ERROR("%s failed, peer does not support request", __func__);
+        return BTM_ILLEGAL_VALUE;
+    }
+
+    if (p_acl != NULL)
+    {
+        if (tx_pdu_length > BTM_BLE_DATA_SIZE_MAX)
+            tx_pdu_length =  BTM_BLE_DATA_SIZE_MAX;
+        else if (tx_pdu_length < BTM_BLE_DATA_SIZE_MIN)
+            tx_pdu_length =  BTM_BLE_DATA_SIZE_MIN;
+
+        /* always set the TxTime to be max, as controller does not care for now */
+        btsnd_hcic_ble_set_data_length(p_acl->hci_handle, tx_pdu_length,
+                                            BTM_BLE_DATA_TX_TIME_MAX);
+
+        return BTM_SUCCESS;
+    }
+    else
+    {
+        BTM_TRACE_ERROR("%s: Wrong mode: no LE link exist or LE not supported",__func__);
+        return BTM_WRONG_MODE;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_determine_security_act
+**
+** Description      This function checks the security of current LE link
+**                  and returns the appropriate action that needs to be
+**                  taken to achieve the required security.
+**
+** Parameter        is_originator - True if outgoing connection
+**                  bdaddr: remote device address
+**                  security_required: Security required for the service.
+**
+** Returns          The appropriate security action required.
+**
+*******************************************************************************/
+tBTM_SEC_ACTION btm_ble_determine_security_act(bool    is_originator, BD_ADDR bdaddr, uint16_t security_required)
+{
+    tBTM_LE_AUTH_REQ auth_req = 0x00;
+
+    if (is_originator)
+    {
+        if ((security_required & BTM_SEC_OUT_FLAGS) == 0 &&
+                (security_required & BTM_SEC_OUT_MITM) == 0)
+        {
+            BTM_TRACE_DEBUG ("%s No security required for outgoing connection", __func__);
+            return BTM_SEC_OK;
+        }
+
+        if (security_required & BTM_SEC_OUT_MITM)
+            auth_req |= BTM_LE_AUTH_REQ_MITM;
+    }
+    else
+    {
+        if ((security_required & BTM_SEC_IN_FLAGS) == 0&& (security_required & BTM_SEC_IN_MITM) == 0)
+        {
+            BTM_TRACE_DEBUG ("%s No security required for incoming connection", __func__);
+            return BTM_SEC_OK;
+        }
+
+        if (security_required & BTM_SEC_IN_MITM)
+            auth_req |= BTM_LE_AUTH_REQ_MITM;
+    }
+
+    tBTM_BLE_SEC_REQ_ACT ble_sec_act;
+    btm_ble_link_sec_check(bdaddr, auth_req, &ble_sec_act);
+
+    BTM_TRACE_DEBUG ("%s ble_sec_act %d", __func__ , ble_sec_act);
+
+    if (ble_sec_act == BTM_BLE_SEC_REQ_ACT_DISCARD)
+        return BTM_SEC_ENC_PENDING;
+
+    if (ble_sec_act == BTM_BLE_SEC_REQ_ACT_NONE)
+        return BTM_SEC_OK;
+
+    uint8_t sec_flag = 0;
+    BTM_GetSecurityFlagsByTransport(bdaddr, &sec_flag, BT_TRANSPORT_LE);
+
+    bool    is_link_encrypted = false;
+    bool    is_key_mitm = false;
+    if (sec_flag & (BTM_SEC_FLAG_ENCRYPTED| BTM_SEC_FLAG_LKEY_KNOWN))
+    {
+        if (sec_flag & BTM_SEC_FLAG_ENCRYPTED)
+            is_link_encrypted = true;
+
+        if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED)
+            is_key_mitm = true;
+    }
+
+    if (auth_req & BTM_LE_AUTH_REQ_MITM)
+    {
+        if (!is_key_mitm)
+        {
+            return BTM_SEC_ENCRYPT_MITM;
+        } else {
+            if (is_link_encrypted)
+                return BTM_SEC_OK;
+            else
+                return BTM_SEC_ENCRYPT;
+        }
+    } else {
+        if (is_link_encrypted)
+            return BTM_SEC_OK;
+        else
+            return BTM_SEC_ENCRYPT_NO_MITM;
+    }
+
+    return BTM_SEC_OK;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_start_sec_check
+**
+** Description      This function is to check and set the security required for
+**                  LE link for LE COC.
+**
+** Parameter        bdaddr: remote device address.
+**                  psm : PSM of the LE COC sevice.
+**                  is_originator: true if outgoing connection.
+**                  p_callback : Pointer to the callback function.
+**                  p_ref_data : Pointer to be returned along with the callback.
+**
+** Returns          true if link already meets the required security; otherwise false.
+**
+*******************************************************************************/
+bool    btm_ble_start_sec_check(BD_ADDR bd_addr, uint16_t psm, bool    is_originator,
+                            tBTM_SEC_CALLBACK *p_callback, void *p_ref_data)
+{
+    /* Find the service record for the PSM */
+    tBTM_SEC_SERV_REC *p_serv_rec = btm_sec_find_first_serv (is_originator, psm);
+
+    /* If there is no application registered with this PSM do not allow connection */
+    if (!p_serv_rec)
+    {
+        BTM_TRACE_WARNING ("%s PSM: %d no application registerd", __func__, psm);
+        (*p_callback) (bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_MODE_UNSUPPORTED);
+        return false;
+    }
+
+    tBTM_SEC_ACTION sec_act = btm_ble_determine_security_act(is_originator,
+                                  bd_addr, p_serv_rec->security_flags);
+
+    tBTM_BLE_SEC_ACT ble_sec_act = BTM_BLE_SEC_NONE;
+    bool    status = false;
+
+    switch (sec_act)
+    {
+        case BTM_SEC_OK:
+            BTM_TRACE_DEBUG ("%s Security met", __func__);
+            p_callback(bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_SUCCESS);
+            status = true;
+            break;
+
+        case BTM_SEC_ENCRYPT:
+            BTM_TRACE_DEBUG ("%s Encryption needs to be done", __func__);
+            ble_sec_act = BTM_BLE_SEC_ENCRYPT;
+            break;
+
+        case BTM_SEC_ENCRYPT_MITM:
+            BTM_TRACE_DEBUG ("%s Pairing with MITM needs to be done", __func__);
+            ble_sec_act = BTM_BLE_SEC_ENCRYPT_MITM;
+            break;
+
+        case BTM_SEC_ENCRYPT_NO_MITM:
+            BTM_TRACE_DEBUG ("%s Pairing with No MITM needs to be done", __func__);
+            ble_sec_act = BTM_BLE_SEC_ENCRYPT_NO_MITM;
+            break;
+
+        case BTM_SEC_ENC_PENDING:
+            BTM_TRACE_DEBUG ("%s Ecryption pending", __func__);
+            break;
+    }
+
+    if (ble_sec_act == BTM_BLE_SEC_NONE)
+        return status;
+
+    tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE);
+    p_lcb->sec_act = sec_act;
+    BTM_SetEncryption(bd_addr, BT_TRANSPORT_LE, p_callback, p_ref_data, ble_sec_act);
+
+    return false;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_rand_enc_complete
+**
+** Description      This function is the callback functions for HCI_Rand command
+**                  and HCI_Encrypt command is completed.
+**                  This message is received from the HCI.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_rand_enc_complete (uint8_t *p, uint16_t op_code, tBTM_RAND_ENC_CB *p_enc_cplt_cback)
+{
+    tBTM_RAND_ENC   params;
+    uint8_t         *p_dest = params.param_buf;
+
+    BTM_TRACE_DEBUG ("btm_ble_rand_enc_complete");
+
+    memset(&params, 0, sizeof(tBTM_RAND_ENC));
+
+    /* If there was a callback address for vcs complete, call it */
+    if (p_enc_cplt_cback && p)
+    {
+        /* Pass paramters to the callback function */
+        STREAM_TO_UINT8(params.status, p); /* command status */
+
+        if (params.status == HCI_SUCCESS)
+        {
+            params.opcode = op_code;
+
+            if (op_code == HCI_BLE_RAND)
+                params.param_len = BT_OCTET8_LEN;
+            else
+                params.param_len = BT_OCTET16_LEN;
+
+            memcpy(p_dest, p, params.param_len);  /* Fetch return info from HCI event message */
+        }
+        if (p_enc_cplt_cback)
+            (*p_enc_cplt_cback)(&params);  /* Call the Encryption complete callback function */
+    }
+}
+
+    #if (SMP_INCLUDED == true)
+
+/*******************************************************************************
+**
+** Function         btm_ble_get_enc_key_type
+**
+** Description      This function is to increment local sign counter
+** Returns         None
+**
+*******************************************************************************/
+void btm_ble_increment_sign_ctr(BD_ADDR bd_addr, bool    is_local )
+{
+    tBTM_SEC_DEV_REC *p_dev_rec;
+
+    BTM_TRACE_DEBUG ("btm_ble_increment_sign_ctr is_local=%d", is_local);
+
+    if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL)
+    {
+        if (is_local)
+            p_dev_rec->ble.keys.local_counter++;
+        else
+            p_dev_rec->ble.keys.counter++;
+        BTM_TRACE_DEBUG ("is_local=%d local sign counter=%d peer sign counter=%d",
+                          is_local,
+                          p_dev_rec->ble.keys.local_counter,
+                          p_dev_rec->ble.keys.counter);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_get_enc_key_type
+**
+** Description      This function is to get the BLE key type that has been exchanged
+**                  in betweem local device and peer device.
+**
+** Returns          p_key_type: output parameter to carry the key type value.
+**
+*******************************************************************************/
+bool    btm_ble_get_enc_key_type(BD_ADDR bd_addr, uint8_t *p_key_types)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec;
+
+    BTM_TRACE_DEBUG ("btm_ble_get_enc_key_type");
+
+    if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL)
+    {
+        *p_key_types = p_dev_rec->ble.key_type;
+        return true;
+    }
+    return false;
+}
+
+/*******************************************************************************
+**
+** Function         btm_get_local_div
+**
+** Description      This function is called to read the local DIV
+**
+** Returns          TURE - if a valid DIV is availavle
+*******************************************************************************/
+bool    btm_get_local_div (BD_ADDR bd_addr, uint16_t *p_div)
+{
+    tBTM_SEC_DEV_REC   *p_dev_rec;
+    bool               status = false;
+    BTM_TRACE_DEBUG ("btm_get_local_div");
+
+    BTM_TRACE_DEBUG("bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+                     bd_addr[0],bd_addr[1],
+                     bd_addr[2],bd_addr[3],
+                     bd_addr[4],bd_addr[5]);
+
+    *p_div = 0;
+    p_dev_rec = btm_find_dev (bd_addr);
+
+    if (p_dev_rec && p_dev_rec->ble.keys.div)
+    {
+        status = true;
+        *p_div = p_dev_rec->ble.keys.div;
+    }
+    BTM_TRACE_DEBUG ("btm_get_local_div status=%d (1-OK) DIV=0x%x", status, *p_div);
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_save_le_key
+**
+** Description      This function is called by the SMP to update
+**                  an  BLE key.  SMP is internal, whereas all the keys shall
+**                  be sent to the application.  The function is also called
+**                  when application passes ble key stored in NVRAM to the btm_sec.
+**                  pass_to_application parameter is false in this case.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sec_save_le_key(BD_ADDR bd_addr, tBTM_LE_KEY_TYPE key_type, tBTM_LE_KEY_VALUE *p_keys,
+                         bool    pass_to_application)
+{
+    tBTM_SEC_DEV_REC *p_rec;
+    tBTM_LE_EVT_DATA    cb_data;
+    uint8_t i;
+
+    BTM_TRACE_DEBUG ("btm_sec_save_le_key key_type=0x%x pass_to_application=%d",key_type, pass_to_application);
+    /* Store the updated key in the device database */
+
+    BTM_TRACE_DEBUG("bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+                     bd_addr[0],bd_addr[1],
+                     bd_addr[2],bd_addr[3],
+                     bd_addr[4],bd_addr[5]);
+
+    if ((p_rec = btm_find_dev (bd_addr)) != NULL && (p_keys || key_type== BTM_LE_KEY_LID))
+    {
+        btm_ble_init_pseudo_addr (p_rec, bd_addr);
+
+        switch (key_type)
+        {
+            case BTM_LE_KEY_PENC:
+                memcpy(p_rec->ble.keys.pltk, p_keys->penc_key.ltk, BT_OCTET16_LEN);
+                memcpy(p_rec->ble.keys.rand, p_keys->penc_key.rand, BT_OCTET8_LEN);
+                p_rec->ble.keys.sec_level = p_keys->penc_key.sec_level;
+                p_rec->ble.keys.ediv = p_keys->penc_key.ediv;
+                p_rec->ble.keys.key_size = p_keys->penc_key.key_size;
+                p_rec->ble.key_type |= BTM_LE_KEY_PENC;
+                p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_KNOWN;
+                if (p_keys->penc_key.sec_level == SMP_SEC_AUTHENTICATED)
+                    p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_AUTHED;
+                else
+                    p_rec->sec_flags &= ~BTM_SEC_LE_LINK_KEY_AUTHED;
+                BTM_TRACE_DEBUG("BTM_LE_KEY_PENC key_type=0x%x sec_flags=0x%x sec_leve=0x%x",
+                                 p_rec->ble.key_type,
+                                 p_rec->sec_flags,
+                                 p_rec->ble.keys.sec_level);
+                break;
+
+            case BTM_LE_KEY_PID:
+                for (i=0; i<BT_OCTET16_LEN; i++)
+                {
+                    p_rec->ble.keys.irk[i] = p_keys->pid_key.irk[i];
+                }
+
+                 //memcpy( p_rec->ble.keys.irk, p_keys->pid_key, BT_OCTET16_LEN); todo will crash the system
+                memcpy(p_rec->ble.static_addr, p_keys->pid_key.static_addr, BD_ADDR_LEN);
+                p_rec->ble.static_addr_type = p_keys->pid_key.addr_type;
+                p_rec->ble.key_type |= BTM_LE_KEY_PID;
+                BTM_TRACE_DEBUG("BTM_LE_KEY_PID key_type=0x%x save peer IRK",  p_rec->ble.key_type);
+                 /* update device record address as static address */
+                memcpy(p_rec->bd_addr, p_keys->pid_key.static_addr, BD_ADDR_LEN);
+                /* combine DUMO device security record if needed */
+                btm_consolidate_dev(p_rec);
+                break;
+
+            case BTM_LE_KEY_PCSRK:
+                memcpy(p_rec->ble.keys.pcsrk, p_keys->pcsrk_key.csrk, BT_OCTET16_LEN);
+                p_rec->ble.keys.srk_sec_level = p_keys->pcsrk_key.sec_level;
+                p_rec->ble.keys.counter  = p_keys->pcsrk_key.counter;
+                p_rec->ble.key_type |= BTM_LE_KEY_PCSRK;
+                p_rec->sec_flags |=  BTM_SEC_LE_LINK_KEY_KNOWN;
+                if ( p_keys->pcsrk_key.sec_level== SMP_SEC_AUTHENTICATED)
+                    p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_AUTHED;
+                else
+                    p_rec->sec_flags &= ~BTM_SEC_LE_LINK_KEY_AUTHED;
+
+                BTM_TRACE_DEBUG("BTM_LE_KEY_PCSRK key_type=0x%x sec_flags=0x%x sec_level=0x%x peer_counter=%d",
+                                 p_rec->ble.key_type,
+                                 p_rec->sec_flags,
+                                 p_rec->ble.keys.srk_sec_level,
+                                 p_rec->ble.keys.counter );
+                break;
+
+            case BTM_LE_KEY_LENC:
+                memcpy(p_rec->ble.keys.lltk, p_keys->lenc_key.ltk, BT_OCTET16_LEN);
+                p_rec->ble.keys.div = p_keys->lenc_key.div; /* update DIV */
+                p_rec->ble.keys.sec_level = p_keys->lenc_key.sec_level;
+                p_rec->ble.keys.key_size = p_keys->lenc_key.key_size;
+                p_rec->ble.key_type |= BTM_LE_KEY_LENC;
+
+                BTM_TRACE_DEBUG("BTM_LE_KEY_LENC key_type=0x%x DIV=0x%x key_size=0x%x sec_level=0x%x",
+                                 p_rec->ble.key_type,
+                                 p_rec->ble.keys.div,
+                                 p_rec->ble.keys.key_size,
+                                 p_rec->ble.keys.sec_level );
+                break;
+
+            case BTM_LE_KEY_LCSRK:/* local CSRK has been delivered */
+                memcpy (p_rec->ble.keys.lcsrk, p_keys->lcsrk_key.csrk, BT_OCTET16_LEN);
+                p_rec->ble.keys.div = p_keys->lcsrk_key.div; /* update DIV */
+                p_rec->ble.keys.local_csrk_sec_level = p_keys->lcsrk_key.sec_level;
+                p_rec->ble.keys.local_counter  = p_keys->lcsrk_key.counter;
+                p_rec->ble.key_type |= BTM_LE_KEY_LCSRK;
+                BTM_TRACE_DEBUG("BTM_LE_KEY_LCSRK key_type=0x%x DIV=0x%x scrk_sec_level=0x%x local_counter=%d",
+                                 p_rec->ble.key_type,
+                                 p_rec->ble.keys.div,
+                                 p_rec->ble.keys.local_csrk_sec_level,
+                                 p_rec->ble.keys.local_counter );
+                break;
+
+            case BTM_LE_KEY_LID:
+               p_rec->ble.key_type |= BTM_LE_KEY_LID;
+               break;
+            default:
+                BTM_TRACE_WARNING("btm_sec_save_le_key (Bad key_type 0x%02x)", key_type);
+                return;
+        }
+
+        BTM_TRACE_DEBUG ("BLE key type 0x%02x updated for BDA: %08x%04x (btm_sec_save_le_key)", key_type,
+                          (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
+                          (bd_addr[4]<<8)+bd_addr[5]);
+
+        /* Notify the application that one of the BLE keys has been updated
+           If link key is in progress, it will get sent later.*/
+        if (pass_to_application && btm_cb.api.p_le_callback)
+        {
+            cb_data.key.p_key_value = p_keys;
+            cb_data.key.key_type = key_type;
+
+            (*btm_cb.api.p_le_callback) (BTM_LE_KEY_EVT, bd_addr, &cb_data);
+        }
+        return;
+    }
+
+    BTM_TRACE_WARNING ("BLE key type 0x%02x called for Unknown BDA or type: %08x%04x !! (btm_sec_save_le_key)", key_type,
+                        (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
+                        (bd_addr[4]<<8)+bd_addr[5]);
+
+    if (p_rec)
+    {
+        BTM_TRACE_DEBUG ("sec_flags=0x%x", p_rec->sec_flags);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_update_sec_key_size
+**
+** Description      update the current lin kencryption key size
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_update_sec_key_size(BD_ADDR bd_addr, uint8_t enc_key_size)
+{
+    tBTM_SEC_DEV_REC *p_rec;
+
+    BTM_TRACE_DEBUG("btm_ble_update_sec_key_size enc_key_size = %d", enc_key_size);
+
+    if ((p_rec = btm_find_dev (bd_addr)) != NULL )
+    {
+        p_rec->enc_key_size = enc_key_size;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_read_sec_key_size
+**
+** Description      update the current lin kencryption key size
+**
+** Returns          void
+**
+*******************************************************************************/
+uint8_t btm_ble_read_sec_key_size(BD_ADDR bd_addr)
+{
+    tBTM_SEC_DEV_REC *p_rec;
+
+    if ((p_rec = btm_find_dev (bd_addr)) != NULL )
+    {
+        return p_rec->enc_key_size;
+    }
+    else
+        return 0;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_link_sec_check
+**
+** Description      Check BLE link security level match.
+**
+** Returns          true: check is OK and the *p_sec_req_act contain the action
+**
+*******************************************************************************/
+void btm_ble_link_sec_check(BD_ADDR bd_addr, tBTM_LE_AUTH_REQ auth_req, tBTM_BLE_SEC_REQ_ACT *p_sec_req_act)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+    uint8_t req_sec_level = BTM_LE_SEC_NONE, cur_sec_level = BTM_LE_SEC_NONE;
+
+    BTM_TRACE_DEBUG ("btm_ble_link_sec_check auth_req =0x%x", auth_req);
+
+    if (p_dev_rec == NULL)
+    {
+        BTM_TRACE_ERROR ("btm_ble_link_sec_check received for unknown device");
+        return;
+    }
+
+    if (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING ||
+        p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING)
+    {
+        /* race condition: discard the security request while master is encrypting the link */
+        *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_DISCARD;
+    }
+    else
+    {
+        req_sec_level = BTM_LE_SEC_UNAUTHENTICATE;
+        if (auth_req & BTM_LE_AUTH_REQ_MITM)
+        {
+            req_sec_level = BTM_LE_SEC_AUTHENTICATED;
+        }
+
+        BTM_TRACE_DEBUG ("dev_rec sec_flags=0x%x", p_dev_rec->sec_flags);
+
+        /* currently encrpted  */
+        if (p_dev_rec->sec_flags & BTM_SEC_LE_ENCRYPTED)
+        {
+            if (p_dev_rec->sec_flags & BTM_SEC_LE_AUTHENTICATED)
+                cur_sec_level = BTM_LE_SEC_AUTHENTICATED;
+            else
+                cur_sec_level = BTM_LE_SEC_UNAUTHENTICATE;
+        }
+        else /* unencrypted link */
+        {
+            /* if bonded, get the key security level */
+            if (p_dev_rec->ble.key_type & BTM_LE_KEY_PENC)
+                cur_sec_level = p_dev_rec->ble.keys.sec_level;
+            else
+                cur_sec_level = BTM_LE_SEC_NONE;
+        }
+
+        if (cur_sec_level >= req_sec_level)
+        {
+            /* To avoid re-encryption on an encrypted link for an equal condition encryption */
+            *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_ENCRYPT;
+        }
+        else
+        {
+            *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_PAIR; /* start the pariring process to upgrade the keys*/
+        }
+    }
+
+    BTM_TRACE_DEBUG("cur_sec_level=%d req_sec_level=%d sec_req_act=%d",
+                     cur_sec_level,
+                     req_sec_level,
+                     *p_sec_req_act);
+
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_set_encryption
+**
+** Description      This function is called to ensure that LE 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.
+**
+** Returns          void
+**                  the local device ER is copied into er
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_set_encryption (BD_ADDR bd_addr, tBTM_BLE_SEC_ACT sec_act, uint8_t link_role)
+{
+    tBTM_STATUS         cmd = BTM_NO_RESOURCES;
+    tBTM_SEC_DEV_REC    *p_rec = btm_find_dev (bd_addr);
+    tBTM_BLE_SEC_REQ_ACT sec_req_act;
+    tBTM_LE_AUTH_REQ    auth_req;
+
+    if (p_rec == NULL)
+    {
+        BTM_TRACE_WARNING ("btm_ble_set_encryption (NULL device record!! sec_act=0x%x", sec_act);
+        return(BTM_WRONG_MODE);
+    }
+
+    BTM_TRACE_DEBUG ("btm_ble_set_encryption sec_act=0x%x role_master=%d", sec_act, p_rec->role_master);
+
+    if (sec_act == BTM_BLE_SEC_ENCRYPT_MITM)
+    {
+        p_rec->security_required |= BTM_SEC_IN_MITM;
+    }
+
+    switch (sec_act)
+    {
+        case BTM_BLE_SEC_ENCRYPT:
+            if (link_role == BTM_ROLE_MASTER)
+            {
+                    /* start link layer encryption using the security info stored */
+                cmd = btm_ble_start_encrypt(bd_addr, false, NULL);
+                break;
+            }
+            /* if salve role then fall through to call SMP_Pair below which will send a
+               sec_request to request the master to encrypt the link */
+        case BTM_BLE_SEC_ENCRYPT_NO_MITM:
+        case BTM_BLE_SEC_ENCRYPT_MITM:
+            auth_req = (sec_act == BTM_BLE_SEC_ENCRYPT_NO_MITM)
+                       ? SMP_AUTH_GEN_BOND : (SMP_AUTH_GEN_BOND | SMP_AUTH_YN_BIT);
+            btm_ble_link_sec_check (bd_addr, auth_req, &sec_req_act);
+            if(sec_req_act == BTM_BLE_SEC_REQ_ACT_NONE || sec_req_act == BTM_BLE_SEC_REQ_ACT_DISCARD)
+            {
+                BTM_TRACE_DEBUG("%s, no action needed. Ignore", __func__);
+                cmd = BTM_SUCCESS;
+                break;
+            }
+            if (link_role == BTM_ROLE_MASTER)
+            {
+
+                if (sec_req_act == BTM_BLE_SEC_REQ_ACT_ENCRYPT)
+                {
+                   cmd = btm_ble_start_encrypt(bd_addr, false, NULL);
+                   break;
+                }
+            }
+
+            if (SMP_Pair(bd_addr) == SMP_STARTED)
+            {
+                cmd = BTM_CMD_STARTED;
+                p_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
+            }
+            break;
+
+        default:
+            cmd = BTM_WRONG_MODE;
+            break;
+    }
+    return cmd;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_ltk_request
+**
+** Description      This function is called when encryption request is received
+**                  on a slave device.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_ltk_request(uint16_t handle, uint8_t rand[8], uint16_t ediv)
+{
+    tBTM_CB *p_cb = &btm_cb;
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle);
+    BT_OCTET8 dummy_stk = {0};
+
+    BTM_TRACE_DEBUG ("btm_ble_ltk_request");
+
+    p_cb->ediv = ediv;
+
+    memcpy(p_cb->enc_rand, rand, BT_OCTET8_LEN);
+
+    if (p_dev_rec != NULL)
+    {
+        if (!smp_proc_ltk_request(p_dev_rec->bd_addr))
+            btm_ble_ltk_request_reply(p_dev_rec->bd_addr, false, dummy_stk);
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_start_encrypt
+**
+** Description      This function is called to start LE encryption.
+**
+**
+** Returns          BTM_SUCCESS if encryption was started successfully
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_start_encrypt(BD_ADDR bda, bool    use_stk, BT_OCTET16 stk)
+{
+    tBTM_CB *p_cb = &btm_cb;
+    tBTM_SEC_DEV_REC    *p_rec = btm_find_dev (bda);
+    BT_OCTET8    dummy_rand = {0};
+
+    BTM_TRACE_DEBUG ("btm_ble_start_encrypt");
+
+    if (!p_rec )
+    {
+        BTM_TRACE_ERROR("Link is not active, can not encrypt!");
+        return BTM_WRONG_MODE;
+    }
+
+    if (p_rec->sec_state == BTM_SEC_STATE_ENCRYPTING)
+    {
+        BTM_TRACE_WARNING("Link Encryption is active, Busy!");
+        return BTM_BUSY;
+    }
+
+    p_cb->enc_handle = p_rec->ble_hci_handle;
+
+    if (use_stk)
+    {
+        btsnd_hcic_ble_start_enc(p_rec->ble_hci_handle, dummy_rand, 0, stk);
+    }
+    else if (p_rec->ble.key_type & BTM_LE_KEY_PENC)
+    {
+        btsnd_hcic_ble_start_enc(p_rec->ble_hci_handle, p_rec->ble.keys.rand,
+                                 p_rec->ble.keys.ediv, p_rec->ble.keys.pltk);
+    }
+    else
+    {
+        BTM_TRACE_ERROR("No key available to encrypt the link");
+        return BTM_NO_RESOURCES;
+    }
+
+    if (p_rec->sec_state == BTM_SEC_STATE_IDLE)
+        p_rec->sec_state = BTM_SEC_STATE_ENCRYPTING;
+
+    return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_link_encrypted
+**
+** Description      This function is called when LE link encrption status is changed.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_link_encrypted(BD_ADDR bd_addr, uint8_t encr_enable)
+{
+    tBTM_SEC_DEV_REC    *p_dev_rec = btm_find_dev (bd_addr);
+    bool                enc_cback;
+
+    if (!p_dev_rec)
+    {
+        BTM_TRACE_WARNING ("btm_ble_link_encrypted (No Device Found!) encr_enable=%d", encr_enable);
+        return;
+    }
+
+    BTM_TRACE_DEBUG ("btm_ble_link_encrypted encr_enable=%d", encr_enable);
+
+    enc_cback = (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING);
+
+    smp_link_encrypted(bd_addr, encr_enable);
+
+    BTM_TRACE_DEBUG(" p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags);
+
+    if (encr_enable && p_dev_rec->enc_key_size == 0)
+        p_dev_rec->enc_key_size = p_dev_rec->ble.keys.key_size;
+
+    p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+    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)
+            btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_PROCESSING, true);
+
+    }
+    /* to notify GATT to send data if any request is pending */
+    gatt_notify_enc_cmpl(p_dev_rec->ble.pseudo_addr);
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_ltk_request_reply
+**
+** Description      This function is called to send a LTK request reply on a slave
+**                  device.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_ltk_request_reply(BD_ADDR bda,  bool    use_stk, BT_OCTET16 stk)
+{
+    tBTM_SEC_DEV_REC    *p_rec = btm_find_dev (bda);
+    tBTM_CB *p_cb = &btm_cb;
+
+    if (p_rec == NULL)
+    {
+        BTM_TRACE_ERROR("btm_ble_ltk_request_reply received for unknown device");
+        return;
+    }
+
+    BTM_TRACE_DEBUG ("btm_ble_ltk_request_reply");
+    p_cb->enc_handle = p_rec->ble_hci_handle;
+    p_cb->key_size = p_rec->ble.keys.key_size;
+
+    BTM_TRACE_ERROR("key size = %d", p_rec->ble.keys.key_size);
+    if (use_stk)
+    {
+        btsnd_hcic_ble_ltk_req_reply(btm_cb.enc_handle, stk);
+    }
+    else /* calculate LTK using peer device  */
+    {
+        if (p_rec->ble.key_type & BTM_LE_KEY_LENC)
+            btsnd_hcic_ble_ltk_req_reply(btm_cb.enc_handle, p_rec->ble.keys.lltk);
+        else
+            btsnd_hcic_ble_ltk_req_neg_reply(btm_cb.enc_handle);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_io_capabilities_req
+**
+** Description      This function is called to handle SMP get IO capability request.
+**
+** Returns          void
+**
+*******************************************************************************/
+uint8_t btm_ble_io_capabilities_req(tBTM_SEC_DEV_REC *p_dev_rec, tBTM_LE_IO_REQ *p_data)
+{
+    uint8_t         callback_rc = BTM_SUCCESS;
+    BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req");
+    if (btm_cb.api.p_le_callback)
+    {
+        /* the callback function implementation may change the IO capability... */
+        callback_rc = (*btm_cb.api.p_le_callback) (BTM_LE_IO_REQ_EVT, p_dev_rec->bd_addr, (tBTM_LE_EVT_DATA *)p_data);
+    }
+    if ((callback_rc == BTM_SUCCESS) || (BTM_OOB_UNKNOWN != p_data->oob_data))
+    {
+#if (BTM_BLE_CONFORMANCE_TESTING == TRUE)
+        if (btm_cb.devcb.keep_rfu_in_auth_req)
+        {
+            BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req keep_rfu_in_auth_req = %u",
+                btm_cb.devcb.keep_rfu_in_auth_req);
+            p_data->auth_req &= BTM_LE_AUTH_REQ_MASK_KEEP_RFU;
+            btm_cb.devcb.keep_rfu_in_auth_req = false;
+        }
+        else
+        {   /* default */
+            p_data->auth_req &= BTM_LE_AUTH_REQ_MASK;
+        }
+#else
+        p_data->auth_req &= BTM_LE_AUTH_REQ_MASK;
+#endif
+
+        BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req 1: p_dev_rec->security_required = %d auth_req:%d",
+                          p_dev_rec->security_required, p_data->auth_req);
+        BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req 2: i_keys=0x%x r_keys=0x%x (bit 0-LTK 1-IRK 2-CSRK)",
+                          p_data->init_keys,
+                          p_data->resp_keys);
+
+        /* if authentication requires MITM protection, put on the mask */
+        if (p_dev_rec->security_required & BTM_SEC_IN_MITM)
+            p_data->auth_req |= BTM_LE_AUTH_REQ_MITM;
+
+        if (!(p_data->auth_req & SMP_AUTH_BOND))
+        {
+            BTM_TRACE_DEBUG("Non bonding: No keys should be exchanged");
+            p_data->init_keys = 0;
+            p_data->resp_keys = 0;
+        }
+
+        BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req 3: auth_req:%d", p_data->auth_req);
+        BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req 4: i_keys=0x%x r_keys=0x%x",
+                          p_data->init_keys,
+                          p_data->resp_keys);
+
+        BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req 5: p_data->io_cap = %d auth_req:%d",
+                          p_data->io_cap, p_data->auth_req);
+
+        /* remove MITM protection requirement if IO cap does not allow it */
+        if ((p_data->io_cap == BTM_IO_CAP_NONE) && p_data->oob_data == SMP_OOB_NONE)
+            p_data->auth_req &= ~BTM_LE_AUTH_REQ_MITM;
+
+        if (!(p_data->auth_req & SMP_SC_SUPPORT_BIT))
+        {
+            /* if Secure Connections are not supported then remove LK derivation,
+            ** and keypress notifications.
+            */
+            BTM_TRACE_DEBUG("%s-SC not supported -> No LK derivation, no keypress notifications",
+                            __func__);
+            p_data->auth_req &= ~SMP_KP_SUPPORT_BIT;
+            p_data->init_keys &= ~SMP_SEC_KEY_TYPE_LK;
+            p_data->resp_keys &= ~SMP_SEC_KEY_TYPE_LK;
+        }
+
+        BTM_TRACE_DEBUG ("btm_ble_io_capabilities_req 6: IO_CAP:%d oob_data:%d auth_req:0x%02x",
+                          p_data->io_cap, p_data->oob_data, p_data->auth_req);
+    }
+    return callback_rc;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_br_keys_req
+**
+** Description      This function is called to handle SMP request for keys sent
+**                  over BR/EDR.
+**
+** Returns          void
+**
+*******************************************************************************/
+uint8_t btm_ble_br_keys_req(tBTM_SEC_DEV_REC *p_dev_rec, tBTM_LE_IO_REQ *p_data)
+{
+    uint8_t         callback_rc = BTM_SUCCESS;
+    BTM_TRACE_DEBUG ("%s", __func__);
+    if (btm_cb.api.p_le_callback)
+    {
+        /* the callback function implementation may change the IO capability... */
+        callback_rc = (*btm_cb.api.p_le_callback) (BTM_LE_IO_REQ_EVT, p_dev_rec->bd_addr,
+                                                  (tBTM_LE_EVT_DATA *)p_data);
+    }
+
+    return callback_rc;
+}
+
+#if (BLE_PRIVACY_SPT == TRUE)
+/*******************************************************************************
+**
+** Function         btm_ble_resolve_random_addr_on_conn_cmpl
+**
+** Description      resolve random address complete on connection complete event.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_ble_resolve_random_addr_on_conn_cmpl(void * p_rec, void *p_data)
+{
+    uint8_t *p = (uint8_t *)p_data;
+    tBTM_SEC_DEV_REC    *match_rec = (tBTM_SEC_DEV_REC *) p_rec;
+    uint8_t     role, bda_type;
+    uint16_t    handle;
+    BD_ADDR     bda;
+    uint16_t    conn_interval, conn_latency, conn_timeout;
+    bool        match = false;
+
+    ++p;
+    STREAM_TO_UINT16   (handle, p);
+    STREAM_TO_UINT8    (role, p);
+    STREAM_TO_UINT8    (bda_type, p);
+    STREAM_TO_BDADDR   (bda, p);
+    STREAM_TO_UINT16   (conn_interval, p);
+    STREAM_TO_UINT16   (conn_latency, p);
+    STREAM_TO_UINT16   (conn_timeout, p);
+
+    handle = HCID_GET_HANDLE (handle);
+
+    BTM_TRACE_EVENT ("%s", __func__);
+
+    if (match_rec)
+    {
+        LOG_INFO(LOG_TAG, "%s matched and resolved random address", __func__);
+        match = true;
+        match_rec->ble.active_addr_type = BTM_BLE_ADDR_RRA;
+        memcpy(match_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN);
+        if (!btm_ble_init_pseudo_addr (match_rec, bda))
+        {
+            /* assign the original address to be the current report address */
+            memcpy(bda, match_rec->ble.pseudo_addr, BD_ADDR_LEN);
+        }
+        else
+        {
+            memcpy(bda, match_rec->bd_addr, BD_ADDR_LEN);
+        }
+    }
+    else
+    {
+        LOG_INFO(LOG_TAG, "%s unable to match and resolve random address", __func__);
+    }
+
+    btm_ble_connected(bda, handle, HCI_ENCRYPT_MODE_DISABLED, role, bda_type, match);
+
+    l2cble_conn_comp (handle, role, bda, bda_type, conn_interval,
+                      conn_latency, conn_timeout);
+
+    return;
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         btm_ble_connected
+**
+** Description      This function is when a LE connection to the peer device is
+**                  establsihed
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_connected (uint8_t *bda, uint16_t handle, uint8_t enc_mode, uint8_t role,
+                        tBLE_ADDR_TYPE addr_type,
+                        UNUSED_ATTR bool addr_matched)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda);
+    tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+
+    BTM_TRACE_EVENT ("btm_ble_connected");
+
+    /* Commenting out trace due to obf/compilation problems.
+    */
+    if (p_dev_rec)
+    {
+        BTM_TRACE_EVENT ("Security Manager: btm_ble_connected :  handle:%d  enc_mode:%d  bda:%x RName:%s",
+                          handle,  enc_mode,
+                          (bda[2]<<24)+(bda[3]<<16)+(bda[4]<<8)+bda[5],
+                          p_dev_rec->sec_bd_name);
+
+        BTM_TRACE_DEBUG ("btm_ble_connected sec_flags=0x%x",p_dev_rec->sec_flags);
+    }
+    else
+    {
+        BTM_TRACE_EVENT ("Security Manager: btm_ble_connected:   handle:%d  enc_mode:%d  bda:%x ",
+                          handle,  enc_mode,
+                          (bda[2]<<24)+(bda[3]<<16)+(bda[4]<<8)+bda[5]);
+    }
+
+    if (!p_dev_rec)
+    {
+        /* There is no device record for new connection.  Allocate one */
+        if ((p_dev_rec = btm_sec_alloc_dev (bda)) == NULL)
+            return;
+    }
+    else    /* Update the timestamp for this device */
+    {
+        p_dev_rec->timestamp = btm_cb.dev_rec_count++;
+    }
+
+    /* update device information */
+    p_dev_rec->device_type |= BT_DEVICE_TYPE_BLE;
+    p_dev_rec->ble_hci_handle = handle;
+    p_dev_rec->ble.ble_addr_type = addr_type;
+    /* update pseudo address */
+    memcpy(p_dev_rec->ble.pseudo_addr, bda, BD_ADDR_LEN);
+
+    p_dev_rec->role_master = false;
+    if (role == HCI_ROLE_MASTER)
+        p_dev_rec->role_master = true;
+
+#if (BLE_PRIVACY_SPT == TRUE)
+    if (!addr_matched)
+        p_dev_rec->ble.active_addr_type = BTM_BLE_ADDR_PSEUDO;
+
+    if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_RANDOM && !addr_matched)
+        memcpy(p_dev_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN);
+#endif
+
+    p_cb->inq_var.directed_conn = BTM_BLE_CONNECT_EVT;
+
+    return;
+}
+
+/*****************************************************************************
+**  Function        btm_ble_conn_complete
+**
+**  Description     LE connection complete.
+**
+******************************************************************************/
+void btm_ble_conn_complete(uint8_t *p,
+                           UNUSED_ATTR uint16_t evt_len, bool    enhanced)
+{
+#if (BLE_PRIVACY_SPT == TRUE)
+    uint8_t     *p_data = p, peer_addr_type;
+    BD_ADDR     local_rpa, peer_rpa;
+#endif
+    uint8_t     role, status, bda_type;
+    uint16_t    handle;
+    BD_ADDR     bda;
+    uint16_t    conn_interval, conn_latency, conn_timeout;
+    bool        match = false;
+
+    STREAM_TO_UINT8   (status, p);
+    STREAM_TO_UINT16   (handle, p);
+    STREAM_TO_UINT8    (role, p);
+    STREAM_TO_UINT8    (bda_type, p);
+    STREAM_TO_BDADDR   (bda, p);
+
+    if (status == 0)
+    {
+#if (BLE_PRIVACY_SPT == TRUE)
+        peer_addr_type = bda_type;
+        match = btm_identity_addr_to_random_pseudo (bda, &bda_type, true);
+
+        if (enhanced)
+        {
+            STREAM_TO_BDADDR   (local_rpa, p);
+            STREAM_TO_BDADDR   (peer_rpa, p);
+        }
+
+        /* possiblly receive connection complete with resolvable random while
+           the device has been paired */
+        if (!match && BTM_BLE_IS_RESOLVE_BDA(bda))
+        {
+            btm_ble_resolve_random_addr(bda, btm_ble_resolve_random_addr_on_conn_cmpl, p_data);
+        }
+        else
+#endif
+        {
+            STREAM_TO_UINT16   (conn_interval, p);
+            STREAM_TO_UINT16   (conn_latency, p);
+            STREAM_TO_UINT16   (conn_timeout, p);
+            handle = HCID_GET_HANDLE (handle);
+
+            btm_ble_connected(bda, handle, HCI_ENCRYPT_MODE_DISABLED, role, bda_type, match);
+
+            l2cble_conn_comp (handle, role, bda, bda_type, conn_interval,
+                              conn_latency, conn_timeout);
+
+#if (BLE_PRIVACY_SPT == TRUE)
+            if (enhanced)
+            {
+                btm_ble_refresh_local_resolvable_private_addr(bda, local_rpa);
+
+                if (peer_addr_type & BLE_ADDR_TYPE_ID_BIT)
+                    btm_ble_refresh_peer_resolvable_private_addr(bda, peer_rpa, BLE_ADDR_RANDOM);
+            }
+#endif
+        }
+    }
+    else
+    {
+        role = HCI_ROLE_UNKNOWN;
+        if (status != HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT)
+        {
+            btm_ble_set_conn_st(BLE_CONN_IDLE);
+#if (BLE_PRIVACY_SPT == TRUE)
+            btm_ble_disable_resolving_list(BTM_BLE_RL_INIT, true);
+#endif
+        }
+        else
+        {
+#if (BLE_PRIVACY_SPT == TRUE)
+            btm_cb.ble_ctr_cb.inq_var.adv_mode  = BTM_BLE_ADV_DISABLE;
+            btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, true);
+#endif
+        }
+    }
+
+    btm_ble_update_mode_operation(role, bda, status);
+}
+
+/*****************************************************************************
+** Function btm_ble_create_ll_conn_complete
+**
+** Description LE connection complete.
+**
+******************************************************************************/
+void btm_ble_create_ll_conn_complete (uint8_t status)
+{
+    if (status != HCI_SUCCESS)
+    {
+        btm_ble_set_conn_st(BLE_CONN_IDLE);
+        btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, NULL, status);
+    }
+}
+/*****************************************************************************
+**  Function        btm_proc_smp_cback
+**
+**  Description     This function is the SMP callback handler.
+**
+******************************************************************************/
+uint8_t btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data)
+{
+    tBTM_SEC_DEV_REC    *p_dev_rec = btm_find_dev (bd_addr);
+    uint8_t res = 0;
+
+    BTM_TRACE_DEBUG ("btm_proc_smp_cback event = %d", event);
+
+    if (p_dev_rec != NULL)
+    {
+        switch (event)
+        {
+            case SMP_IO_CAP_REQ_EVT:
+                btm_ble_io_capabilities_req(p_dev_rec, (tBTM_LE_IO_REQ *)&p_data->io_req);
+                break;
+
+            case SMP_BR_KEYS_REQ_EVT:
+                btm_ble_br_keys_req(p_dev_rec, (tBTM_LE_IO_REQ *)&p_data->io_req);
+                break;
+
+            case SMP_PASSKEY_REQ_EVT:
+            case SMP_PASSKEY_NOTIF_EVT:
+            case SMP_OOB_REQ_EVT:
+            case SMP_NC_REQ_EVT:
+            case SMP_SC_OOB_REQ_EVT:
+                /* fall through */
+                p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED;
+
+            case SMP_SEC_REQUEST_EVT:
+                if (event == SMP_SEC_REQUEST_EVT && btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+                {
+                    BTM_TRACE_DEBUG("%s: Ignoring SMP Security request", __func__);
+                    break;
+                }
+                memcpy (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN);
+                p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
+                btm_cb.pairing_flags |= BTM_PAIR_FLAGS_LE_ACTIVE;
+                /* fall through */
+
+            case SMP_COMPLT_EVT:
+                if (btm_cb.api.p_le_callback)
+                {
+                    /* the callback function implementation may change the IO capability... */
+                    BTM_TRACE_DEBUG ("btm_cb.api.p_le_callback=0x%x", btm_cb.api.p_le_callback );
+                   (*btm_cb.api.p_le_callback) (event, bd_addr, (tBTM_LE_EVT_DATA *)p_data);
+                }
+
+                if (event == SMP_COMPLT_EVT)
+                {
+                    BTM_TRACE_DEBUG ("evt=SMP_COMPLT_EVT before update sec_level=0x%x sec_flags=0x%x", p_data->cmplt.sec_level , p_dev_rec->sec_flags );
+
+                    res = (p_data->cmplt.reason == SMP_SUCCESS) ? BTM_SUCCESS : BTM_ERR_PROCESSING;
+
+                    BTM_TRACE_DEBUG ("after update result=%d sec_level=0x%x sec_flags=0x%x",
+                                      res, p_data->cmplt.sec_level , p_dev_rec->sec_flags );
+
+                    if (p_data->cmplt.is_pair_cancel && btm_cb.api.p_bond_cancel_cmpl_callback )
+                    {
+                        BTM_TRACE_DEBUG ("Pairing Cancel completed");
+                        (*btm_cb.api.p_bond_cancel_cmpl_callback)(BTM_SUCCESS);
+                    }
+#if (BTM_BLE_CONFORMANCE_TESTING == TRUE)
+                    if (res != BTM_SUCCESS)
+                    {
+                        if (!btm_cb.devcb.no_disc_if_pair_fail && p_data->cmplt.reason != SMP_CONN_TOUT)
+                        {
+                            BTM_TRACE_DEBUG ("Pairing failed - prepare to remove ACL");
+                            l2cu_start_post_bond_timer(p_dev_rec->ble_hci_handle);
+                        }
+                        else
+                        {
+                            BTM_TRACE_DEBUG ("Pairing failed - Not Removing ACL");
+                            p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+                        }
+                    }
+#else
+                    if (res != BTM_SUCCESS && p_data->cmplt.reason != SMP_CONN_TOUT)
+                    {
+                        BTM_TRACE_DEBUG ("Pairing failed - prepare to remove ACL");
+                        l2cu_start_post_bond_timer(p_dev_rec->ble_hci_handle);
+                    }
+#endif
+
+                    BTM_TRACE_DEBUG ("btm_cb pairing_state=%x pairing_flags=%x pin_code_len=%x",
+                                      btm_cb.pairing_state,
+                                      btm_cb.pairing_flags,
+                                      btm_cb.pin_code_len  );
+                    BTM_TRACE_DEBUG ("btm_cb.pairing_bda %02x:%02x:%02x:%02x:%02x:%02x",
+                                      btm_cb.pairing_bda[0], btm_cb.pairing_bda[1], btm_cb.pairing_bda[2],
+                                      btm_cb.pairing_bda[3], btm_cb.pairing_bda[4], btm_cb.pairing_bda[5]);
+
+                    /* Reset btm state only if the callback address matches pairing address*/
+                    if(memcmp(bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) == 0)
+                    {
+                        memset (btm_cb.pairing_bda, 0xff, BD_ADDR_LEN);
+                        btm_cb.pairing_state = BTM_PAIR_STATE_IDLE;
+                        btm_cb.pairing_flags = 0;
+                    }
+
+                    if (res == BTM_SUCCESS)
+                    {
+                        p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+#if (BLE_PRIVACY_SPT == TRUE)
+                        /* add all bonded device into resolving list if IRK is available*/
+                        btm_ble_resolving_list_load_dev(p_dev_rec);
+#endif
+                    }
+
+                    btm_sec_dev_rec_cback_event(p_dev_rec, res, true);
+                }
+                break;
+
+            default:
+                BTM_TRACE_DEBUG ("unknown event = %d", event);
+                break;
+
+        }
+    }
+    else
+    {
+        BTM_TRACE_ERROR("btm_proc_smp_cback received for unknown device");
+    }
+
+    return 0;
+}
+
+    #endif  /* SMP_INCLUDED */
+
+/*******************************************************************************
+**
+** 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    BTM_BleDataSignature (BD_ADDR bd_addr, uint8_t *p_text, uint16_t len,
+                              BLE_SIGNATURE signature)
+{
+    tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bd_addr);
+
+    BTM_TRACE_DEBUG ("%s", __func__);
+    bool    ret = false;
+    if (p_rec == NULL)
+    {
+        BTM_TRACE_ERROR("%s-data signing can not be done from unknown device", __func__);
+    }
+    else
+    {
+        uint8_t *p_mac = (uint8_t *)signature;
+        uint8_t *pp;
+        uint8_t *p_buf = (uint8_t *)osi_malloc(len + 4);
+
+        BTM_TRACE_DEBUG("%s-Start to generate Local CSRK", __func__);
+        pp = p_buf;
+        /* prepare plain text */
+        if (p_text) {
+            memcpy(p_buf, p_text, len);
+            pp = (p_buf + len);
+        }
+
+        UINT32_TO_STREAM(pp, p_rec->ble.keys.local_counter);
+        UINT32_TO_STREAM(p_mac, p_rec->ble.keys.local_counter);
+
+        if ((ret = aes_cipher_msg_auth_code(p_rec->ble.keys.lcsrk, p_buf, (uint16_t)(len + 4),
+                                            BTM_CMAC_TLEN_SIZE, p_mac)) == true) {
+            btm_ble_increment_sign_ctr(bd_addr, true);
+        }
+
+        BTM_TRACE_DEBUG("%s p_mac = %d", __func__, p_mac);
+        BTM_TRACE_DEBUG("p_mac[0] = 0x%02x p_mac[1] = 0x%02x p_mac[2] = 0x%02x p_mac[3] = 0x%02x",
+                        *p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3));
+        BTM_TRACE_DEBUG("p_mac[4] = 0x%02x p_mac[5] = 0x%02x p_mac[6] = 0x%02x p_mac[7] = 0x%02x",
+                        *(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7));
+        osi_free(p_buf);
+    }
+    return ret;
+}
+
+/*******************************************************************************
+**
+** 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 (BD_ADDR bd_addr, uint8_t *p_orig, uint16_t len, uint32_t counter,
+                                uint8_t *p_comp)
+{
+    bool    verified = false;
+#if (SMP_INCLUDED == TRUE)
+    tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bd_addr);
+    uint8_t p_mac[BTM_CMAC_TLEN_SIZE];
+
+    if (p_rec == NULL || (p_rec && !(p_rec->ble.key_type & BTM_LE_KEY_PCSRK)))
+    {
+        BTM_TRACE_ERROR("can not verify signature for unknown device");
+    }
+    else if (counter < p_rec->ble.keys.counter)
+    {
+        BTM_TRACE_ERROR("signature received with out dated sign counter");
+    }
+    else if (p_orig == NULL)
+    {
+        BTM_TRACE_ERROR("No signature to verify");
+    }
+    else
+    {
+        BTM_TRACE_DEBUG ("%s rcv_cnt=%d >= expected_cnt=%d", __func__, counter,
+                          p_rec->ble.keys.counter);
+
+        if (aes_cipher_msg_auth_code(p_rec->ble.keys.pcsrk, p_orig, len, BTM_CMAC_TLEN_SIZE, p_mac))
+        {
+            if (memcmp(p_mac, p_comp, BTM_CMAC_TLEN_SIZE) == 0)
+            {
+                btm_ble_increment_sign_ctr(bd_addr, false);
+                verified = true;
+            }
+        }
+    }
+#endif  /* SMP_INCLUDED */
+    return verified;
+}
+
+/*******************************************************************************
+**
+** 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 (BD_ADDR bd_addr, uint8_t *p_le_dev_sec_flags, uint8_t *p_le_key_size)
+{
+#if (BLE_INCLUDED == TRUE)
+    tBTM_SEC_DEV_REC *p_dev_rec;
+    uint16_t dev_rec_sec_flags;
+#endif
+
+    *p_le_dev_sec_flags = 0;
+    *p_le_key_size = 0;
+
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+    if ((p_dev_rec = btm_find_dev (bd_addr)) == NULL)
+    {
+        BTM_TRACE_ERROR ("%s fails", __func__);
+        return (false);
+    }
+
+    if (p_dev_rec->ble_hci_handle == BTM_SEC_INVALID_HANDLE) {
+        BTM_TRACE_ERROR ("%s-this is not LE device", __func__);
+        return (false);
+    }
+
+    dev_rec_sec_flags = p_dev_rec->sec_flags;
+
+    if (dev_rec_sec_flags & BTM_SEC_LE_ENCRYPTED)
+    {
+        /* link is encrypted with LTK or STK */
+        *p_le_key_size = p_dev_rec->enc_key_size;
+        *p_le_dev_sec_flags |= BTM_SEC_LE_LINK_ENCRYPTED;
+
+        *p_le_dev_sec_flags |= (dev_rec_sec_flags & BTM_SEC_LE_AUTHENTICATED)
+            ? BTM_SEC_LE_LINK_PAIRED_WITH_MITM      /* set auth LTK flag */
+            : BTM_SEC_LE_LINK_PAIRED_WITHOUT_MITM;  /* set unauth LTK flag */
+    }
+    else if (p_dev_rec->ble.key_type & BTM_LE_KEY_PENC)
+    {
+        /* link is unencrypted, still LTK is available */
+        *p_le_key_size = p_dev_rec->ble.keys.key_size;
+
+        *p_le_dev_sec_flags |= (dev_rec_sec_flags & BTM_SEC_LE_LINK_KEY_AUTHED)
+            ? BTM_SEC_LE_LINK_PAIRED_WITH_MITM      /* set auth LTK flag */
+            : BTM_SEC_LE_LINK_PAIRED_WITHOUT_MITM;  /* set unauth LTK flag */
+    }
+
+    BTM_TRACE_DEBUG ("%s - le_dev_sec_flags: 0x%02x, le_key_size: %d",
+        __func__, *p_le_dev_sec_flags, *p_le_key_size);
+
+    return true;
+#else
+    return false;
+#endif
+}
+
+/*******************************************************************************
+**
+** 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(BD_ADDR bd_addr)
+{
+#if (BLE_INCLUDED == TRUE)
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+
+    if (p_dev_rec == NULL)
+    {
+        BTM_TRACE_ERROR ("%s device with BDA: %08x%04x is not found",
+                          __func__, (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
+                          (bd_addr[4]<<8)+bd_addr[5]);
+        return false;
+    }
+
+    return (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING ||
+            p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING);
+#else
+    return false;
+#endif
+}
+
+/*******************************************************************************
+**
+** 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.
+**
+*******************************************************************************/
+extern uint8_t BTM_BleGetSupportedKeySize (BD_ADDR bd_addr)
+{
+#if (BLE_INCLUDED == TRUE && L2CAP_LE_COC_INCLUDED == TRUE)
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+    tBTM_LE_IO_REQ dev_io_cfg;
+    uint8_t callback_rc;
+
+    if (!p_dev_rec)
+    {
+        BTM_TRACE_ERROR ("%s device with BDA: %08x%04x is not found",
+                         __func__,(bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
+                          (bd_addr[4]<<8)+bd_addr[5]);
+        return 0;
+    }
+
+    if (btm_cb.api.p_le_callback == NULL)
+    {
+        BTM_TRACE_ERROR ("%s can't access supported key size",__func__);
+        return 0;
+    }
+
+    callback_rc = (*btm_cb.api.p_le_callback) (BTM_LE_IO_REQ_EVT, p_dev_rec->bd_addr,
+                                               (tBTM_LE_EVT_DATA *) &dev_io_cfg);
+
+    if (callback_rc != BTM_SUCCESS)
+    {
+        BTM_TRACE_ERROR ("%s can't access supported key size",__func__);
+        return 0;
+    }
+
+    BTM_TRACE_DEBUG ("%s device supports key size = %d", __func__, dev_io_cfg.max_key_size);
+    return (dev_io_cfg.max_key_size);
+#else
+    return 0;
+#endif
+}
+
+/*******************************************************************************
+**  Utility functions for LE device IR/ER generation
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function         btm_notify_new_key
+**
+** Description      This function is to notify application new keys have been
+**                  generated.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_notify_new_key(uint8_t key_type)
+{
+    tBTM_BLE_LOCAL_KEYS *p_locak_keys = NULL;
+
+    BTM_TRACE_DEBUG ("btm_notify_new_key key_type=%d", key_type);
+
+    if (btm_cb.api.p_le_key_callback)
+    {
+        switch (key_type)
+        {
+            case BTM_BLE_KEY_TYPE_ID:
+                BTM_TRACE_DEBUG ("BTM_BLE_KEY_TYPE_ID");
+                p_locak_keys = (tBTM_BLE_LOCAL_KEYS *)&btm_cb.devcb.id_keys;
+                break;
+
+            case BTM_BLE_KEY_TYPE_ER:
+                BTM_TRACE_DEBUG ("BTM_BLE_KEY_TYPE_ER");
+                p_locak_keys = (tBTM_BLE_LOCAL_KEYS *)&btm_cb.devcb.ble_encryption_key_value;
+                break;
+
+            default:
+                BTM_TRACE_ERROR("unknown key type: %d", key_type);
+                break;
+        }
+        if (p_locak_keys != NULL)
+            (*btm_cb.api.p_le_key_callback) (key_type, p_locak_keys);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_process_er2
+**
+** Description      This function is called when ER is generated, store it in
+**                  local control block.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_ble_process_er2(tBTM_RAND_ENC *p)
+{
+    BTM_TRACE_DEBUG ("btm_ble_process_er2");
+
+    if (p &&p->opcode == HCI_BLE_RAND)
+    {
+        memcpy(&btm_cb.devcb.ble_encryption_key_value[8], p->param_buf, BT_OCTET8_LEN);
+        btm_notify_new_key(BTM_BLE_KEY_TYPE_ER);
+    }
+    else
+    {
+        BTM_TRACE_ERROR("Generating ER2 exception.");
+        memset(&btm_cb.devcb.ble_encryption_key_value, 0, sizeof(BT_OCTET16));
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_process_er
+**
+** Description      This function is called when ER is generated, store it in
+**                  local control block.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_ble_process_er(tBTM_RAND_ENC *p)
+{
+    BTM_TRACE_DEBUG ("btm_ble_process_er");
+
+    if (p &&p->opcode == HCI_BLE_RAND)
+    {
+        memcpy(&btm_cb.devcb.ble_encryption_key_value[0], p->param_buf, BT_OCTET8_LEN);
+
+        btsnd_hcic_ble_rand((void *)btm_ble_process_er2);
+    }
+    else
+    {
+        BTM_TRACE_ERROR("Generating ER1 exception.");
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_process_irk
+**
+** Description      This function is called when IRK is generated, store it in
+**                  local control block.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_ble_process_irk(tSMP_ENC *p)
+{
+    BTM_TRACE_DEBUG ("btm_ble_process_irk");
+    if (p &&p->opcode == HCI_BLE_ENCRYPT)
+    {
+        memcpy(btm_cb.devcb.id_keys.irk, p->param_buf, BT_OCTET16_LEN);
+        btm_notify_new_key(BTM_BLE_KEY_TYPE_ID);
+
+#if (BLE_PRIVACY_SPT == TRUE)
+        /* if privacy is enabled, new RPA should be calculated */
+        if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE)
+        {
+            btm_gen_resolvable_private_addr((void *)btm_gen_resolve_paddr_low);
+        }
+#endif
+    }
+    else
+    {
+        BTM_TRACE_ERROR("Generating IRK exception.");
+    }
+
+    /* proceed generate ER */
+    btsnd_hcic_ble_rand((void *)btm_ble_process_er);
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_process_dhk
+**
+** Description      This function is called when DHK is calculated, store it in
+**                  local control block, and proceed to generate ER, a 128-bits
+**                  random number.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_ble_process_dhk(tSMP_ENC *p)
+{
+#if (SMP_INCLUDED == TRUE)
+    uint8_t btm_ble_irk_pt = 0x01;
+    tSMP_ENC output;
+
+    BTM_TRACE_DEBUG ("btm_ble_process_dhk");
+
+    if (p && p->opcode == HCI_BLE_ENCRYPT)
+    {
+        memcpy(btm_cb.devcb.id_keys.dhk, p->param_buf, BT_OCTET16_LEN);
+        BTM_TRACE_DEBUG("BLE DHK generated.");
+
+        /* IRK = D1(IR, 1) */
+        if (!SMP_Encrypt(btm_cb.devcb.id_keys.ir, BT_OCTET16_LEN, &btm_ble_irk_pt,
+                         1,   &output))
+        {
+            /* reset all identity root related key */
+            memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS));
+        }
+        else
+        {
+            btm_ble_process_irk(&output);
+        }
+    }
+    else
+    {
+        /* reset all identity root related key */
+        memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS));
+    }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_process_ir2
+**
+** Description      This function is called when IR is generated, proceed to calculate
+**                  DHK = Eir({0x03, 0, 0 ...})
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_ble_process_ir2(tBTM_RAND_ENC *p)
+{
+#if (SMP_INCLUDED == TRUE)
+    uint8_t btm_ble_dhk_pt = 0x03;
+    tSMP_ENC output;
+
+    BTM_TRACE_DEBUG ("btm_ble_process_ir2");
+
+    if (p && p->opcode == HCI_BLE_RAND)
+    {
+        /* remembering in control block */
+        memcpy(&btm_cb.devcb.id_keys.ir[8], p->param_buf, BT_OCTET8_LEN);
+        /* generate DHK= Eir({0x03, 0x00, 0x00 ...}) */
+
+        SMP_Encrypt(btm_cb.devcb.id_keys.ir, BT_OCTET16_LEN, &btm_ble_dhk_pt,
+                    1, &output);
+        btm_ble_process_dhk(&output);
+
+        BTM_TRACE_DEBUG("BLE IR generated.");
+    }
+    else
+    {
+        memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS));
+    }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_process_ir
+**
+** Description      This function is called when IR is generated, proceed to calculate
+**                  DHK = Eir({0x02, 0, 0 ...})
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_ble_process_ir(tBTM_RAND_ENC *p)
+{
+    BTM_TRACE_DEBUG ("btm_ble_process_ir");
+
+    if (p && p->opcode == HCI_BLE_RAND)
+    {
+        /* remembering in control block */
+        memcpy(btm_cb.devcb.id_keys.ir, p->param_buf, BT_OCTET8_LEN);
+
+        btsnd_hcic_ble_rand((void *)btm_ble_process_ir2);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_reset_id
+**
+** Description      This function is called to reset LE device identity.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_reset_id( void )
+{
+    BTM_TRACE_DEBUG ("btm_ble_reset_id");
+
+    /* regenrate Identity Root*/
+    btsnd_hcic_ble_rand((void *)btm_ble_process_ir);
+}
+
+    #if BTM_BLE_CONFORMANCE_TESTING == true
+/*******************************************************************************
+**
+** Function         btm_ble_set_no_disc_if_pair_fail
+**
+** Description      This function indicates that whether no disconnect of the ACL
+**                  should be used if pairing failed
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_set_no_disc_if_pair_fail(bool    disable_disc )
+{
+    BTM_TRACE_DEBUG ("btm_ble_set_disc_enable_if_pair_fail disable_disc=%d", disable_disc);
+    btm_cb.devcb.no_disc_if_pair_fail = disable_disc;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_set_test_mac_value
+**
+** Description      This function set test MAC value
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_set_test_mac_value(bool    enable, uint8_t *p_test_mac_val )
+{
+    BTM_TRACE_DEBUG ("btm_ble_set_test_mac_value enable=%d", enable);
+    btm_cb.devcb.enable_test_mac_val = enable;
+    memcpy(btm_cb.devcb.test_mac, p_test_mac_val, BT_OCTET8_LEN);
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_set_test_local_sign_cntr_value
+**
+** Description      This function set test local sign counter value
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_set_test_local_sign_cntr_value(bool    enable, uint32_t test_local_sign_cntr )
+{
+    BTM_TRACE_DEBUG ("btm_ble_set_test_local_sign_cntr_value enable=%d local_sign_cntr=%d",
+                      enable, test_local_sign_cntr);
+    btm_cb.devcb.enable_test_local_sign_cntr = enable;
+    btm_cb.devcb.test_local_sign_cntr =  test_local_sign_cntr;
+}
+
+/*******************************************************************************
+**
+** Function         btm_set_random_address
+**
+** Description      This function set a random address to local controller.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_set_random_address(BD_ADDR random_bda)
+{
+    tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+    bool        adv_mode = btm_cb.ble_ctr_cb.inq_var.adv_mode ;
+
+    BTM_TRACE_DEBUG ("btm_set_random_address");
+
+    if (adv_mode  == BTM_BLE_ADV_ENABLE)
+        btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE);
+
+    memcpy(p_cb->private_addr, random_bda, BD_ADDR_LEN);
+    btsnd_hcic_ble_set_random_addr(p_cb->private_addr);
+
+    if (adv_mode  == BTM_BLE_ADV_ENABLE)
+        btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_ENABLE);
+
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_set_keep_rfu_in_auth_req
+**
+** Description      This function indicates if RFU bits have to be kept as is
+**                  (by default they have to be set to 0 by the sender).
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_set_keep_rfu_in_auth_req(bool    keep_rfu)
+{
+    BTM_TRACE_DEBUG ("btm_ble_set_keep_rfu_in_auth_req keep_rfus=%d", keep_rfu);
+    btm_cb.devcb.keep_rfu_in_auth_req = keep_rfu;
+}
+
+#endif /* BTM_BLE_CONFORMANCE_TESTING */
+
+#endif /* BLE_INCLUDED */
diff --git a/bt/stack/btm/btm_ble_addr.cc b/bt/stack/btm/btm_ble_addr.cc
new file mode 100644
index 0000000..93a1b03
--- /dev/null
+++ b/bt/stack/btm/btm_ble_addr.cc
@@ -0,0 +1,583 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 functions for BLE address management.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_types.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_int.h"
+#include "gap_api.h"
+#include "device/include/controller.h"
+
+#if (BLE_INCLUDED == TRUE)
+#include "btm_ble_int.h"
+#include "smp_api.h"
+
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+/*******************************************************************************
+**
+** Function         btm_gen_resolve_paddr_cmpl
+**
+** Description      This is callback functioin when resolvable private address
+**                  generation is complete.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_gen_resolve_paddr_cmpl(tSMP_ENC *p)
+{
+    tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+    BTM_TRACE_EVENT ("btm_gen_resolve_paddr_cmpl");
+
+    if (p)
+    {
+        /* set hash to be LSB of rpAddress */
+        p_cb->private_addr[5] = p->param_buf[0];
+        p_cb->private_addr[4] = p->param_buf[1];
+        p_cb->private_addr[3] = p->param_buf[2];
+        /* set it to controller */
+        btsnd_hcic_ble_set_random_addr(p_cb->private_addr);
+
+        p_cb->own_addr_type = BLE_ADDR_RANDOM;
+
+        /* start a periodical timer to refresh random addr */
+        period_ms_t interval_ms = BTM_BLE_PRIVATE_ADDR_INT_MS;
+#if (BTM_BLE_CONFORMANCE_TESTING == TRUE)
+        interval_ms = btm_cb.ble_ctr_cb.rpa_tout * 1000;
+#endif
+        alarm_set_on_queue(p_cb->refresh_raddr_timer, interval_ms,
+                           btm_ble_refresh_raddr_timer_timeout, NULL,
+                           btu_general_alarm_queue);
+    }
+    else
+    {
+        /* random address set failure */
+        BTM_TRACE_DEBUG("set random address failed");
+    }
+}
+/*******************************************************************************
+**
+** Function         btm_gen_resolve_paddr_low
+**
+** Description      This function is called when random address has generate the
+**                  random number base for low 3 byte bd address.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_gen_resolve_paddr_low(tBTM_RAND_ENC *p)
+{
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+    tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+    tSMP_ENC    output;
+
+    BTM_TRACE_EVENT ("btm_gen_resolve_paddr_low");
+    if (p)
+    {
+        p->param_buf[2] &= (~BLE_RESOLVE_ADDR_MASK);
+        p->param_buf[2] |= BLE_RESOLVE_ADDR_MSB;
+
+        p_cb->private_addr[2] = p->param_buf[0];
+        p_cb->private_addr[1] = p->param_buf[1];
+        p_cb->private_addr[0] = p->param_buf[2];
+
+        /* encrypt with ur IRK */
+        if (!SMP_Encrypt(btm_cb.devcb.id_keys.irk, BT_OCTET16_LEN, p->param_buf, 3, &output))
+        {
+            btm_gen_resolve_paddr_cmpl(NULL);
+        }
+        else
+        {
+            btm_gen_resolve_paddr_cmpl(&output);
+        }
+    }
+#endif
+}
+/*******************************************************************************
+**
+** Function         btm_gen_resolvable_private_addr
+**
+** Description      This function generate a resolvable private address.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_gen_resolvable_private_addr(void *p_cmd_cplt_cback)
+{
+    BTM_TRACE_EVENT ("%s", __func__);
+    /* generate 3B rand as BD LSB, SRK with it, get BD MSB */
+    btsnd_hcic_ble_rand(p_cmd_cplt_cback);
+}
+/*******************************************************************************
+**
+** Function         btm_gen_non_resolve_paddr_cmpl
+**
+** Description      This is the callback function when non-resolvable private
+**                  function is generated and write to controller.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_gen_non_resolve_paddr_cmpl(tBTM_RAND_ENC *p)
+{
+    tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+    tBTM_BLE_ADDR_CBACK *p_cback = p_cb->p_generate_cback;
+    void    *p_data = p_cb->p;
+    uint8_t *pp;
+    BD_ADDR     static_random;
+
+    BTM_TRACE_EVENT ("btm_gen_non_resolve_paddr_cmpl");
+
+    p_cb->p_generate_cback = NULL;
+    if (p)
+    {
+
+        pp = p->param_buf;
+        STREAM_TO_BDADDR(static_random, pp);
+        /* mask off the 2 MSB */
+        static_random[0] &= BLE_STATIC_PRIVATE_MSB_MASK;
+
+        /* report complete */
+        if (p_cback)
+            (* p_cback)(static_random, p_data);
+    }
+    else
+    {
+        BTM_TRACE_DEBUG("btm_gen_non_resolvable_private_addr failed");
+        if (p_cback)
+            (* p_cback)(NULL, p_data);
+    }
+}
+/*******************************************************************************
+**
+** Function         btm_gen_non_resolvable_private_addr
+**
+** Description      This function generate a non-resolvable private address.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_gen_non_resolvable_private_addr (tBTM_BLE_ADDR_CBACK *p_cback, void *p)
+{
+    tBTM_LE_RANDOM_CB   *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+
+    BTM_TRACE_EVENT ("btm_gen_non_resolvable_private_addr");
+
+    if (p_mgnt_cb->p_generate_cback != NULL)
+        return;
+
+    p_mgnt_cb->p_generate_cback = p_cback;
+    p_mgnt_cb->p                = p;
+    btsnd_hcic_ble_rand((void *)btm_gen_non_resolve_paddr_cmpl);
+}
+
+#if (SMP_INCLUDED == TRUE)
+/*******************************************************************************
+**  Utility functions for Random address resolving
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function         btm_ble_proc_resolve_x
+**
+** Description      This function compares the X with random address 3 MSO bytes
+**                  to find a match.
+**
+** Returns          true on match, false otherwise
+**
+*******************************************************************************/
+static bool    btm_ble_proc_resolve_x(tSMP_ENC *p)
+{
+    tBTM_LE_RANDOM_CB   *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+    uint8_t  comp[3];
+    BTM_TRACE_EVENT ("btm_ble_proc_resolve_x");
+    /* compare the hash with 3 LSB of bd address */
+    comp[0] = p_mgnt_cb->random_bda[5];
+    comp[1] = p_mgnt_cb->random_bda[4];
+    comp[2] = p_mgnt_cb->random_bda[3];
+
+    if (p)
+    {
+        if (!memcmp(p->param_buf, &comp[0], 3))
+        {
+            /* match is found */
+            BTM_TRACE_EVENT ("match is found");
+            return true;
+        }
+    }
+    return false;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_init_pseudo_addr
+**
+** Description      This function is used to initialize pseudo address.
+**                  If pseudo address is not available, use dummy address
+**
+** Returns          true is updated; false otherwise.
+**
+*******************************************************************************/
+bool    btm_ble_init_pseudo_addr (tBTM_SEC_DEV_REC *p_dev_rec, BD_ADDR new_pseudo_addr)
+{
+    BD_ADDR dummy_bda = {0};
+
+    if (memcmp(p_dev_rec->ble.pseudo_addr, dummy_bda, BD_ADDR_LEN) == 0)
+    {
+        memcpy(p_dev_rec->ble.pseudo_addr, new_pseudo_addr, BD_ADDR_LEN);
+        return true;
+    }
+
+    return false;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_addr_resolvable
+**
+** Description      This function checks if a RPA is resolvable by the device key.
+**
+** Returns          true is resolvable; false otherwise.
+**
+*******************************************************************************/
+bool    btm_ble_addr_resolvable (BD_ADDR rpa, tBTM_SEC_DEV_REC *p_dev_rec)
+{
+    bool    rt = false;
+
+    if (!BTM_BLE_IS_RESOLVE_BDA(rpa))
+        return rt;
+
+    uint8_t rand[3];
+    tSMP_ENC output;
+    if ((p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) &&
+        (p_dev_rec->ble.key_type & BTM_LE_KEY_PID))
+    {
+        BTM_TRACE_DEBUG("%s try to resolve", __func__);
+        /* use the 3 MSB of bd address as prand */
+        rand[0] = rpa[2];
+        rand[1] = rpa[1];
+        rand[2] = rpa[0];
+
+        /* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */
+        SMP_Encrypt(p_dev_rec->ble.keys.irk, BT_OCTET16_LEN,
+                    &rand[0], 3, &output);
+
+        rand[0] = rpa[5];
+        rand[1] = rpa[4];
+        rand[2] = rpa[3];
+
+        if (!memcmp(output.param_buf, &rand[0], 3))
+        {
+            btm_ble_init_pseudo_addr (p_dev_rec, rpa);
+            rt = true;
+        }
+    }
+    return rt;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_match_random_bda
+**
+** Description      This function match the random address to the appointed device
+**                  record, starting from calculating IRK. If record index exceed
+**                  the maximum record number, matching failed and send callback.
+**
+** Returns          None.
+**
+*******************************************************************************/
+static bool    btm_ble_match_random_bda(void *data, void *context)
+{
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+    /* use the 3 MSB of bd address as prand */
+
+    tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+    uint8_t rand[3];
+    rand[0] = p_mgnt_cb->random_bda[2];
+    rand[1] = p_mgnt_cb->random_bda[1];
+    rand[2] = p_mgnt_cb->random_bda[0];
+
+    BTM_TRACE_EVENT("%s next iteration", __func__);
+
+    tSMP_ENC output;
+    tBTM_SEC_DEV_REC *p_dev_rec = static_cast<tBTM_SEC_DEV_REC *>(data);
+
+    BTM_TRACE_DEBUG("sec_flags = %02x device_type = %d", p_dev_rec->sec_flags,
+                    p_dev_rec->device_type);
+
+    if (!(p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) ||
+        !(p_dev_rec->ble.key_type & BTM_LE_KEY_PID))
+        return true;
+
+    /* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */
+    SMP_Encrypt(p_dev_rec->ble.keys.irk, BT_OCTET16_LEN,
+                &rand[0], 3, &output);
+    // if it was match, finish iteration, otherwise continue
+    return !btm_ble_proc_resolve_x(&output);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_resolve_random_addr
+**
+** Description      This function is called to resolve a random address.
+**
+** Returns          pointer to the security record of the device whom a random
+**                  address is matched to.
+**
+*******************************************************************************/
+void btm_ble_resolve_random_addr(BD_ADDR random_bda, tBTM_BLE_RESOLVE_CBACK * p_cback, void *p)
+{
+    tBTM_LE_RANDOM_CB   *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+
+    BTM_TRACE_EVENT("%s", __func__);
+    if ( !p_mgnt_cb->busy) {
+        p_mgnt_cb->p = p;
+        p_mgnt_cb->busy = true;
+        memcpy(p_mgnt_cb->random_bda, random_bda, BD_ADDR_LEN);
+        /* start to resolve random address */
+        /* check for next security record */
+
+        list_node_t * n = list_foreach(btm_cb.sec_dev_rec, btm_ble_match_random_bda, NULL);
+        tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+        if (n != NULL)
+            p_dev_rec = static_cast<tBTM_SEC_DEV_REC *>(list_node(n));
+
+        BTM_TRACE_EVENT("%s:  %sresolved", __func__, (p_dev_rec == NULL ? "not " : ""));
+        p_mgnt_cb->busy = false;
+
+        (*p_cback)(p_dev_rec, p);
+    } else {
+        (*p_cback)(NULL, p);
+    }
+}
+#endif
+
+/*******************************************************************************
+**  address mapping between pseudo address and real connection address
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function         btm_find_dev_by_identity_addr
+**
+** Description      find the security record whose LE static address is matching
+**
+*******************************************************************************/
+tBTM_SEC_DEV_REC* btm_find_dev_by_identity_addr(BD_ADDR bd_addr, uint8_t addr_type)
+{
+#if (BLE_PRIVACY_SPT == TRUE)
+    list_node_t *end = list_end(btm_cb.sec_dev_rec);
+    for (list_node_t *node = list_begin(btm_cb.sec_dev_rec); node != end; node = list_next(node)) {
+        tBTM_SEC_DEV_REC *p_dev_rec =
+            static_cast<tBTM_SEC_DEV_REC *>(list_node(node));
+        if (memcmp(p_dev_rec->ble.static_addr, bd_addr, BD_ADDR_LEN) == 0) {
+            if ((p_dev_rec->ble.static_addr_type & (~BLE_ADDR_TYPE_ID_BIT)) !=
+                (addr_type & (~BLE_ADDR_TYPE_ID_BIT)))
+                BTM_TRACE_WARNING("%s find pseudo->random match with diff addr type: %d vs %d",
+                    __func__, p_dev_rec->ble.static_addr_type, addr_type);
+
+            /* found the match */
+            return p_dev_rec;
+        }
+    }
+#endif
+
+    return NULL;
+}
+
+/*******************************************************************************
+**
+** Function         btm_identity_addr_to_random_pseudo
+**
+** Description      This function map a static BD address to a pseudo random address
+**                  in security database.
+**
+*******************************************************************************/
+bool    btm_identity_addr_to_random_pseudo(BD_ADDR bd_addr, uint8_t *p_addr_type, bool    refresh)
+{
+#if (BLE_PRIVACY_SPT == TRUE)
+    tBTM_SEC_DEV_REC    *p_dev_rec = btm_find_dev_by_identity_addr(bd_addr, *p_addr_type);
+
+    BTM_TRACE_EVENT ("%s", __func__);
+    /* evt reported on static address, map static address to random pseudo */
+    if (p_dev_rec != NULL)
+    {
+        /* if RPA offloading is supported, or 4.2 controller, do RPA refresh */
+        if (refresh && controller_get_interface()->get_ble_resolving_list_max_size() != 0)
+            btm_ble_read_resolving_list_entry(p_dev_rec);
+
+        /* assign the original address to be the current report address */
+        if (!btm_ble_init_pseudo_addr (p_dev_rec, bd_addr))
+            memcpy(bd_addr, p_dev_rec->ble.pseudo_addr, BD_ADDR_LEN);
+
+        *p_addr_type = p_dev_rec->ble.ble_addr_type;
+        return true;
+    }
+#endif
+    return false;
+}
+
+/*******************************************************************************
+**
+** Function         btm_random_pseudo_to_identity_addr
+**
+** Description      This function map a random pseudo address to a public address
+**                  random_pseudo is input and output parameter
+**
+*******************************************************************************/
+bool    btm_random_pseudo_to_identity_addr(BD_ADDR random_pseudo, uint8_t *p_static_addr_type)
+{
+#if (BLE_PRIVACY_SPT == TRUE)
+    tBTM_SEC_DEV_REC    *p_dev_rec = btm_find_dev (random_pseudo);
+
+    if (p_dev_rec != NULL)
+    {
+        if (p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT)
+        {
+            * p_static_addr_type = p_dev_rec->ble.static_addr_type;
+            memcpy(random_pseudo, p_dev_rec->ble.static_addr, BD_ADDR_LEN);
+            if (controller_get_interface()->supports_ble_privacy())
+                *p_static_addr_type |= BLE_ADDR_TYPE_ID_BIT;
+            return true;
+        }
+    }
+#endif
+    return false;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_refresh_peer_resolvable_private_addr
+**
+** Description      This function refresh the currently used resolvable remote private address into security
+**                  database and set active connection address.
+**
+*******************************************************************************/
+void btm_ble_refresh_peer_resolvable_private_addr(BD_ADDR pseudo_bda, BD_ADDR rpa,
+                                                  uint8_t rra_type)
+{
+#if (BLE_PRIVACY_SPT == TRUE)
+    uint8_t rra_dummy = false;
+    BD_ADDR dummy_bda = {0};
+
+    if (memcmp(dummy_bda, rpa, BD_ADDR_LEN) == 0)
+        rra_dummy = true;
+
+    /* update security record here, in adv event or connection complete process */
+    tBTM_SEC_DEV_REC *p_sec_rec = btm_find_dev(pseudo_bda);
+    if (p_sec_rec != NULL)
+    {
+        memcpy(p_sec_rec->ble.cur_rand_addr, rpa, BD_ADDR_LEN);
+
+        /* unknown, if dummy address, set to static */
+        if (rra_type == BTM_BLE_ADDR_PSEUDO)
+            p_sec_rec->ble.active_addr_type = rra_dummy ? BTM_BLE_ADDR_STATIC: BTM_BLE_ADDR_RRA;
+        else
+            p_sec_rec->ble.active_addr_type = rra_type;
+    }
+    else
+    {
+        BTM_TRACE_ERROR("No matching known device in record");
+        return;
+    }
+
+    BTM_TRACE_DEBUG("%s: active_addr_type: %d ",
+                    __func__, p_sec_rec->ble.active_addr_type);
+
+    /* connection refresh remote address */
+    tACL_CONN *p_acl = btm_bda_to_acl(p_sec_rec->bd_addr, BT_TRANSPORT_LE);
+    if (p_acl == NULL)
+        p_acl = btm_bda_to_acl(p_sec_rec->ble.pseudo_addr, BT_TRANSPORT_LE);
+
+    if (p_acl != NULL)
+    {
+        if (rra_type == BTM_BLE_ADDR_PSEUDO)
+        {
+            /* use static address, resolvable_private_addr is empty */
+            if (rra_dummy)
+            {
+                p_acl->active_remote_addr_type = p_sec_rec->ble.static_addr_type;
+                memcpy(p_acl->active_remote_addr, p_sec_rec->ble.static_addr, BD_ADDR_LEN);
+            }
+            else
+            {
+                p_acl->active_remote_addr_type = BLE_ADDR_RANDOM;
+                memcpy(p_acl->active_remote_addr, rpa, BD_ADDR_LEN);
+            }
+        }
+        else
+        {
+              p_acl->active_remote_addr_type = rra_type;
+              memcpy(p_acl->active_remote_addr, rpa, BD_ADDR_LEN);
+        }
+
+        BTM_TRACE_DEBUG("p_acl->active_remote_addr_type: %d ", p_acl->active_remote_addr_type);
+        BTM_TRACE_DEBUG("%s conn_addr: %02x:%02x:%02x:%02x:%02x:%02x",
+                __func__,p_acl->active_remote_addr[0], p_acl->active_remote_addr[1],
+                p_acl->active_remote_addr[2], p_acl->active_remote_addr[3],
+                p_acl->active_remote_addr[4], p_acl->active_remote_addr[5]);
+    }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_refresh_local_resolvable_private_addr
+**
+** Description      This function refresh the currently used resolvable private address for the
+**                  active link to the remote device
+**
+*******************************************************************************/
+void btm_ble_refresh_local_resolvable_private_addr(BD_ADDR pseudo_addr,
+                                                   BD_ADDR local_rpa)
+{
+#if (BLE_PRIVACY_SPT == TRUE)
+    tACL_CONN *p = btm_bda_to_acl(pseudo_addr, BT_TRANSPORT_LE);
+    BD_ADDR     dummy_bda = {0};
+
+    if (p != NULL)
+    {
+        if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE)
+        {
+            p->conn_addr_type = BLE_ADDR_RANDOM;
+            if (memcmp(local_rpa, dummy_bda, BD_ADDR_LEN))
+                memcpy(p->conn_addr, local_rpa, BD_ADDR_LEN);
+            else
+                memcpy(p->conn_addr, btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr, BD_ADDR_LEN);
+        }
+        else
+        {
+            p->conn_addr_type = BLE_ADDR_PUBLIC;
+            memcpy(p->conn_addr,&controller_get_interface()->get_address()->address, BD_ADDR_LEN);
+        }
+    }
+#endif
+}
+#endif
+
+
diff --git a/bt/stack/btm/btm_ble_adv_filter.cc b/bt/stack/btm/btm_ble_adv_filter.cc
new file mode 100644
index 0000000..9a23865
--- /dev/null
+++ b/bt/stack/btm/btm_ble_adv_filter.cc
@@ -0,0 +1,1284 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014  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.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btm_ble"
+
+#include <string.h>
+
+#include "bt_target.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_ble_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+
+#define BTM_BLE_ADV_FILT_META_HDR_LENGTH 3
+#define BTM_BLE_ADV_FILT_FEAT_SELN_LEN  13
+#define BTM_BLE_ADV_FILT_TRACK_NUM       2
+
+#define BTM_BLE_PF_SELECT_NONE              0
+
+/* BLE meta vsc header: 1 bytes of sub_code, 1 byte of PCF action */
+#define BTM_BLE_META_HDR_LENGTH     3
+#define BTM_BLE_PF_FEAT_SEL_LEN     18
+#define BTM_BLE_PCF_ENABLE_LEN      2
+
+#define BTM_BLE_META_ADDR_LEN       7
+#define BTM_BLE_META_UUID_LEN       40
+
+#define BTM_BLE_PF_BIT_TO_MASK(x)          (uint16_t)(1 << (x))
+
+tBTM_BLE_ADV_FILTER_CB btm_ble_adv_filt_cb;
+tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+static const BD_ADDR     na_bda= {0};
+
+static uint8_t btm_ble_cs_update_pf_counter(tBTM_BLE_SCAN_COND_OP action,
+                                  uint8_t cond_type, tBLE_BD_ADDR *p_bd_addr, uint8_t num_available);
+
+#define BTM_BLE_SET_SCAN_PF_OPCODE(x, y) (((x)<<4)|(y))
+#define BTM_BLE_GET_SCAN_PF_SUBCODE(x)    ((x) >> 4)
+#define BTM_BLE_GET_SCAN_PF_ACTION(x)    ((x) & 0x0f)
+#define BTM_BLE_INVALID_COUNTER     0xff
+
+/* length of each multi adv sub command */
+#define BTM_BLE_ADV_FILTER_ENB_LEN                       3
+
+/* length of each batch scan command */
+#define BTM_BLE_ADV_FILTER_CLEAR_LEN            3
+#define BTM_BLE_ADV_FILTER_LEN     2
+
+#define BTM_BLE_ADV_FILT_CB_EVT_MASK       0xF0
+#define BTM_BLE_ADV_FILT_SUBCODE_MASK      0x0F
+
+/*******************************************************************************
+**
+** Function         btm_ble_obtain_vsc_details
+**
+** Description      This function obtains the VSC details
+**
+** Parameters
+**
+** Returns          status
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_obtain_vsc_details()
+{
+    tBTM_STATUS st = BTM_SUCCESS;
+
+#if (BLE_VND_INCLUDED == TRUE)
+    BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+    if (0 == cmn_ble_vsc_cb.max_filter)
+    {
+        st = BTM_MODE_UNSUPPORTED;
+        return st;
+    }
+#else
+    cmn_ble_vsc_cb.max_filter = BTM_BLE_MAX_FILTER_COUNTER;
+#endif
+    return st;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_advfilt_enq_op_q
+**
+** Description      enqueue an adv filter operation in q to check command complete
+**                  status
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_advfilt_enq_op_q(uint8_t action, uint8_t ocf, tBTM_BLE_FILT_CB_EVT cb_evt,
+                              tBTM_BLE_REF_VALUE ref, tBTM_BLE_PF_CFG_CBACK *p_cmpl_cback,
+                              tBTM_BLE_PF_PARAM_CBACK  *p_filt_param_cback)
+{
+    btm_ble_adv_filt_cb.op_q.action_ocf[btm_ble_adv_filt_cb.op_q.next_idx] = (action |(ocf << 4));
+    btm_ble_adv_filt_cb.op_q.ref_value[btm_ble_adv_filt_cb.op_q.next_idx] = ref;
+    btm_ble_adv_filt_cb.op_q.cb_evt[btm_ble_adv_filt_cb.op_q.next_idx] = cb_evt;
+    btm_ble_adv_filt_cb.op_q.p_scan_cfg_cback[btm_ble_adv_filt_cb.op_q.next_idx] = p_cmpl_cback;
+    btm_ble_adv_filt_cb.op_q.p_filt_param_cback[btm_ble_adv_filt_cb.op_q.next_idx]
+        = p_filt_param_cback;
+    BTM_TRACE_DEBUG("btm_ble_advfilt_enq_op_q: act_ocf:%d, action:%d, ocf:%d,cb_evt;%d, cback:%x",
+        btm_ble_adv_filt_cb.op_q.action_ocf[btm_ble_adv_filt_cb.op_q.next_idx], action,
+        ocf, cb_evt, p_cmpl_cback);
+    btm_ble_adv_filt_cb.op_q.next_idx = (btm_ble_adv_filt_cb.op_q.next_idx + 1)
+                    % BTM_BLE_PF_TYPE_MAX;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_advfilt_deq_op_q
+**
+** Description      dequeue an adv filter operation from q when command complete
+**                  is received
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_advfilt_deq_op_q(uint8_t *p_action,uint8_t *p_ocf, tBTM_BLE_FILT_CB_EVT *p_cb_evt,
+                              tBTM_BLE_REF_VALUE *p_ref, tBTM_BLE_PF_CFG_CBACK ** p_cmpl_cback,
+                              tBTM_BLE_PF_PARAM_CBACK  **p_filt_param_cback)
+{
+    *p_ocf = (btm_ble_adv_filt_cb.op_q.action_ocf[btm_ble_adv_filt_cb.op_q.pending_idx] >> 4);
+    *p_action = (btm_ble_adv_filt_cb.op_q.action_ocf[btm_ble_adv_filt_cb.op_q.pending_idx]
+                & BTM_BLE_ADV_FILT_SUBCODE_MASK);
+    *p_ref = btm_ble_adv_filt_cb.op_q.ref_value[btm_ble_adv_filt_cb.op_q.pending_idx];
+    *p_cb_evt = btm_ble_adv_filt_cb.op_q.cb_evt[btm_ble_adv_filt_cb.op_q.pending_idx];
+    *p_cmpl_cback = btm_ble_adv_filt_cb.op_q.p_scan_cfg_cback[btm_ble_adv_filt_cb.op_q.pending_idx];
+    *p_filt_param_cback =
+        btm_ble_adv_filt_cb.op_q.p_filt_param_cback[btm_ble_adv_filt_cb.op_q.pending_idx];
+
+    btm_ble_adv_filt_cb.op_q.pending_idx = (btm_ble_adv_filt_cb.op_q.pending_idx + 1)
+        % BTM_BLE_PF_TYPE_MAX;
+    BTM_TRACE_DEBUG("btm_ble_advfilt_deq_op_q: ocf:%d, action:%d, ref_value:%d, cb_evt:%x",
+        *p_ocf,*p_action, *p_ref, *p_cb_evt);
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_condtype_to_ocf
+**
+** Description      Convert cond_type to OCF
+**
+** Returns          Returns ocf value
+**
+*******************************************************************************/
+uint8_t btm_ble_condtype_to_ocf(uint8_t cond_type)
+{
+    uint8_t ocf = 0;
+
+    switch(cond_type)
+    {
+        case BTM_BLE_PF_ADDR_FILTER:
+          ocf = BTM_BLE_META_PF_ADDR;
+          break;
+        case BTM_BLE_PF_SRVC_UUID:
+          ocf = BTM_BLE_META_PF_UUID;
+          break;
+        case BTM_BLE_PF_SRVC_SOL_UUID:
+           ocf = BTM_BLE_META_PF_SOL_UUID;
+           break;
+        case BTM_BLE_PF_LOCAL_NAME:
+           ocf = BTM_BLE_META_PF_LOCAL_NAME;
+           break;
+        case BTM_BLE_PF_MANU_DATA:
+           ocf = BTM_BLE_META_PF_MANU_DATA;
+           break;
+        case BTM_BLE_PF_SRVC_DATA_PATTERN:
+           ocf = BTM_BLE_META_PF_SRVC_DATA;
+           break;
+        case BTM_BLE_PF_TYPE_ALL:
+           ocf = BTM_BLE_META_PF_ALL;
+           break;
+        default:
+           ocf = BTM_BLE_PF_TYPE_MAX;
+           break;
+    }
+    return ocf;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_ocf_to_condtype
+**
+** Description      Convert OCF to cond type
+**
+** Returns          Returns condtype value
+**
+*******************************************************************************/
+uint8_t btm_ble_ocf_to_condtype(uint8_t ocf)
+{
+    uint8_t cond_type = 0;
+
+    switch(ocf)
+    {
+        case BTM_BLE_META_PF_FEAT_SEL:
+           cond_type = BTM_BLE_META_PF_FEAT_SEL;
+           break;
+        case BTM_BLE_META_PF_ADDR:
+          cond_type = BTM_BLE_PF_ADDR_FILTER;
+          break;
+        case BTM_BLE_META_PF_UUID:
+          cond_type = BTM_BLE_PF_SRVC_UUID;
+          break;
+        case BTM_BLE_META_PF_SOL_UUID:
+           cond_type = BTM_BLE_PF_SRVC_SOL_UUID;
+           break;
+        case BTM_BLE_META_PF_LOCAL_NAME:
+           cond_type = BTM_BLE_PF_LOCAL_NAME;
+           break;
+        case BTM_BLE_META_PF_MANU_DATA:
+           cond_type = BTM_BLE_PF_MANU_DATA;
+           break;
+        case BTM_BLE_META_PF_SRVC_DATA:
+           cond_type = BTM_BLE_PF_SRVC_DATA_PATTERN;
+           break;
+        case BTM_BLE_META_PF_ALL:
+           cond_type = BTM_BLE_PF_TYPE_ALL;
+           break;
+        default:
+           cond_type = BTM_BLE_PF_TYPE_MAX;
+           break;
+    }
+    return cond_type;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_scan_pf_cmpl_cback
+**
+** Description      the BTM BLE customer feature VSC complete callback for ADV PF filtering
+**
+** Returns          pointer to the counter if found; NULL otherwise.
+**
+*******************************************************************************/
+void btm_ble_scan_pf_cmpl_cback(tBTM_VSC_CMPL *p_params)
+{
+    uint8_t status = 0;
+    uint8_t *p = p_params->p_param_buf, op_subcode = 0, action = 0xff;
+    uint16_t evt_len = p_params->param_len;
+    uint8_t ocf = BTM_BLE_META_PF_ALL, cond_type = 0;
+    uint8_t num_avail = 0, cb_evt = 0;
+    tBTM_BLE_REF_VALUE ref_value = 0;
+    tBTM_BLE_PF_CFG_CBACK *p_scan_cfg_cback = NULL;
+    tBTM_BLE_PF_PARAM_CBACK *p_filt_param_cback = NULL;
+
+    if (evt_len < 3 || evt_len > 4)
+    {
+      BTM_TRACE_ERROR("%s cannot interpret APCF callback status = %d, length = %d",
+          __func__, status, evt_len);
+        btm_ble_advfilt_deq_op_q(&action, &ocf, &cb_evt, &ref_value, &p_scan_cfg_cback,
+                                 &p_filt_param_cback);
+        return;
+    }
+
+    btm_ble_advfilt_deq_op_q(&action, &ocf, &cb_evt, &ref_value, &p_scan_cfg_cback,
+                             &p_filt_param_cback);
+
+    STREAM_TO_UINT8(status, p);
+    STREAM_TO_UINT8(op_subcode, p);
+    STREAM_TO_UINT8(action, p);
+
+    /* Ignore the event, if it is not the same one expected */
+    if (3 == evt_len)
+    {
+        if(ocf != op_subcode)
+        {
+             BTM_TRACE_ERROR("btm_ble_scan_pf_cmpl_cback:3-Incorrect opcode :%d, %d, %d, %d, %d, %d",
+                                        ocf, op_subcode, action, evt_len, ref_value, status);
+             return;
+        }
+        else
+        {
+            if(NULL != btm_ble_adv_filt_cb.p_filt_stat_cback)
+               btm_ble_adv_filt_cb.p_filt_stat_cback(action, status, ref_value);
+            BTM_TRACE_DEBUG("btm_ble_scan_pf_cmpl_cback enabled/disabled, %d, %d, %d, %d",
+                                         ocf, action, status, ref_value);
+            return;
+        }
+    }
+
+    if (4 == evt_len && ocf != op_subcode)
+    {
+        BTM_TRACE_ERROR("btm_ble_scan_pf_cmpl_cback:4-Incorrect opcode: %d, %d, %d, %d, %d",
+                                ocf, op_subcode, action, status, ref_value);
+        return;
+    }
+
+    STREAM_TO_UINT8(num_avail, p);
+    switch (op_subcode)
+    {
+        case BTM_BLE_META_PF_ADDR:
+        case BTM_BLE_META_PF_UUID:
+        case BTM_BLE_META_PF_SOL_UUID:
+        case BTM_BLE_META_PF_LOCAL_NAME:
+        case BTM_BLE_META_PF_MANU_DATA:
+        case BTM_BLE_META_PF_SRVC_DATA:
+           cond_type = btm_ble_ocf_to_condtype(ocf);
+           BTM_TRACE_DEBUG("btm_ble_scan_pf_cmpl_cback Recd: %d, %d, %d, %d, %d, %d", op_subcode,
+                                        ocf, action, status, ref_value, num_avail);
+           if (HCI_SUCCESS == status)
+           {
+               if (memcmp(&btm_ble_adv_filt_cb.cur_filter_target.bda, &na_bda, BD_ADDR_LEN) == 0)
+                   btm_ble_cs_update_pf_counter(action, cond_type, NULL, num_avail);
+               else
+                   btm_ble_cs_update_pf_counter(action, cond_type,
+                            &btm_ble_adv_filt_cb.cur_filter_target, num_avail);
+           }
+
+           /* send ADV PF operation complete */
+           btm_ble_adv_filt_cb.op_type = 0;
+           break;
+
+        case BTM_BLE_META_PF_FEAT_SEL:
+            BTM_TRACE_DEBUG("btm_ble_scan_pf_cmpl_cback-Feat sel event: %d, %d, %d, %d",
+                                action, status, ref_value, num_avail);
+            break;
+
+        default:
+            BTM_TRACE_ERROR("btm_ble_scan_pf_cmpl_cback: unknown operation: %d", op_subcode);
+            break;
+    }
+
+    switch(cb_evt)
+    {
+        BTM_TRACE_DEBUG("btm_ble_scan_pf_cmpl_cback: calling the cback: %d", cb_evt);
+        case BTM_BLE_FILT_CFG:
+            if(NULL != p_scan_cfg_cback)
+               p_scan_cfg_cback(action, cond_type, num_avail, status, ref_value);
+            break;
+        case BTM_BLE_FILT_ADV_PARAM:
+            if(NULL != p_filt_param_cback)
+               p_filt_param_cback(action, num_avail, ref_value, status);
+            break;
+        default:
+            break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_find_addr_filter_counter
+**
+** Description      find the per bd address ADV payload filter counter by BD_ADDR.
+**
+** Returns          pointer to the counter if found; NULL otherwise.
+**
+*******************************************************************************/
+tBTM_BLE_PF_COUNT* btm_ble_find_addr_filter_counter(tBLE_BD_ADDR *p_le_bda)
+{
+    uint8_t             i;
+    tBTM_BLE_PF_COUNT   *p_addr_filter = &btm_ble_adv_filt_cb.p_addr_filter_count[1];
+
+    if (p_le_bda == NULL)
+        return &btm_ble_adv_filt_cb.p_addr_filter_count[0];
+
+    for (i = 0; i < cmn_ble_vsc_cb.max_filter; i ++, p_addr_filter ++)
+    {
+        if (p_addr_filter->in_use &&
+            memcmp(p_le_bda->bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0)
+        {
+            return p_addr_filter;
+        }
+    }
+    return NULL;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_alloc_addr_filter_counter
+**
+** Description      allocate the per device adv payload filter counter.
+**
+** Returns          pointer to the counter if allocation succeed; NULL otherwise.
+**
+*******************************************************************************/
+tBTM_BLE_PF_COUNT * btm_ble_alloc_addr_filter_counter(BD_ADDR bd_addr)
+{
+    uint8_t             i;
+    tBTM_BLE_PF_COUNT   *p_addr_filter = &btm_ble_adv_filt_cb.p_addr_filter_count[1];
+
+    for (i = 0; i < cmn_ble_vsc_cb.max_filter; i ++, p_addr_filter ++)
+    {
+        if (memcmp(na_bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0)
+        {
+            memcpy(p_addr_filter->bd_addr, bd_addr, BD_ADDR_LEN);
+            p_addr_filter->in_use = true;
+            return p_addr_filter;
+        }
+    }
+    return NULL;
+}
+/*******************************************************************************
+**
+** Function         btm_ble_dealloc_addr_filter_counter
+**
+** Description      de-allocate the per device adv payload filter counter.
+**
+** Returns          true if deallocation succeed; false otherwise.
+**
+*******************************************************************************/
+bool    btm_ble_dealloc_addr_filter_counter(tBLE_BD_ADDR *p_bd_addr, uint8_t filter_type)
+{
+    uint8_t             i;
+    tBTM_BLE_PF_COUNT   *p_addr_filter = &btm_ble_adv_filt_cb.p_addr_filter_count[1];
+    bool                found = false;
+
+    if (BTM_BLE_PF_TYPE_ALL == filter_type && NULL == p_bd_addr)
+        memset(&btm_ble_adv_filt_cb.p_addr_filter_count[0], 0, sizeof(tBTM_BLE_PF_COUNT));
+
+    for (i = 0; i < cmn_ble_vsc_cb.max_filter; i ++, p_addr_filter ++)
+    {
+        if ((p_addr_filter->in_use) && (NULL == p_bd_addr ||
+            (NULL != p_bd_addr &&
+            memcmp(p_bd_addr->bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0)))
+        {
+            found = true;
+            memset(p_addr_filter, 0, sizeof(tBTM_BLE_PF_COUNT));
+
+            if (NULL != p_bd_addr) break;
+        }
+    }
+    return found;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_update_pf_local_name
+**
+** Description      this function update(add,delete or clear) the adv lcoal name filtering condition.
+**
+**
+** Returns          BTM_SUCCESS if sucessful,
+**                  BTM_ILLEGAL_VALUE if paramter is not valid.
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_update_pf_local_name(tBTM_BLE_SCAN_COND_OP action,
+                                         tBTM_BLE_PF_FILT_INDEX filt_index,
+                                         tBTM_BLE_PF_COND_PARAM *p_cond)
+{
+    tBTM_BLE_PF_LOCAL_NAME_COND *p_local_name = (p_cond == NULL) ? NULL : &p_cond->local_name;
+    uint8_t     param[BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_ADV_FILT_META_HDR_LENGTH],
+                *p = param,
+                len = BTM_BLE_ADV_FILT_META_HDR_LENGTH;
+    tBTM_STATUS st = BTM_ILLEGAL_VALUE;
+
+    memset(param, 0, BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_ADV_FILT_META_HDR_LENGTH);
+
+    UINT8_TO_STREAM(p, BTM_BLE_META_PF_LOCAL_NAME);
+    UINT8_TO_STREAM(p, action);
+
+    /* Filter index */
+    UINT8_TO_STREAM(p, filt_index);
+
+    if (BTM_BLE_SCAN_COND_ADD == action ||
+        BTM_BLE_SCAN_COND_DELETE == action)
+    {
+        if (NULL == p_local_name)
+            return st;
+
+        if (p_local_name->data_len > BTM_BLE_PF_STR_LEN_MAX)
+            p_local_name->data_len = BTM_BLE_PF_STR_LEN_MAX;
+
+        ARRAY_TO_STREAM(p, p_local_name->p_data, p_local_name->data_len);
+        len += p_local_name->data_len;
+    }
+
+    /* send local name filter */
+    BTM_VendorSpecificCommand(HCI_BLE_ADV_FILTER_OCF, len, param,
+                              btm_ble_scan_pf_cmpl_cback);
+    memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
+    return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_update_srvc_data_change
+**
+** Description      this function update(add/remove) service data change filter.
+**
+**
+** Returns          BTM_SUCCESS if sucessful,
+**                  BTM_ILLEGAL_VALUE if paramter is not valid.
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_update_srvc_data_change(tBTM_BLE_SCAN_COND_OP action,
+                                       tBTM_BLE_PF_FILT_INDEX filt_index,
+                                       tBTM_BLE_PF_COND_PARAM *p_cond)
+{
+    tBTM_STATUS st = BTM_ILLEGAL_VALUE;
+    tBLE_BD_ADDR   *p_bd_addr = p_cond ? &p_cond->target_addr : NULL;
+    uint8_t         num_avail = (action == BTM_BLE_SCAN_COND_ADD) ? 0 : 1;
+
+    if (btm_ble_cs_update_pf_counter (action, BTM_BLE_PF_SRVC_DATA, p_bd_addr, num_avail)
+                    != BTM_BLE_INVALID_COUNTER)
+        st = BTM_SUCCESS;
+
+    return st;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_update_pf_manu_data
+**
+** Description      this function update(add,delete or clear) the adv manufacturer
+**                  data filtering condition.
+**
+**
+** Returns          BTM_SUCCESS if sucessful,
+**                  BTM_ILLEGAL_VALUE if paramter is not valid.
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_update_pf_manu_data(tBTM_BLE_SCAN_COND_OP action,
+                                        tBTM_BLE_PF_FILT_INDEX filt_index,
+                                        tBTM_BLE_PF_COND_PARAM *p_data,
+                                        tBTM_BLE_PF_COND_TYPE cond_type,
+                                        tBTM_BLE_FILT_CB_EVT cb_evt,
+                                        tBTM_BLE_REF_VALUE ref_value)
+{
+    tBTM_BLE_PF_MANU_COND *p_manu_data = (p_data == NULL) ? NULL : &p_data->manu_data;
+    tBTM_BLE_PF_SRVC_PATTERN_COND *p_srvc_data = (p_data == NULL) ? NULL : &p_data->srvc_data;
+
+    uint8_t param[BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_ADV_FILT_META_HDR_LENGTH],
+          *p = param,
+          len = BTM_BLE_ADV_FILT_META_HDR_LENGTH;
+    tBTM_STATUS st = BTM_ILLEGAL_VALUE;
+
+    if (NULL == p_data)
+        return st;
+
+    memset(param, 0, BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_PF_STR_LEN_MAX
+                    + BTM_BLE_ADV_FILT_META_HDR_LENGTH);
+
+    if (BTM_BLE_PF_SRVC_DATA_PATTERN == cond_type)
+    {
+        UINT8_TO_STREAM(p, BTM_BLE_META_PF_SRVC_DATA);
+    }
+    else
+    {
+        UINT8_TO_STREAM(p, BTM_BLE_META_PF_MANU_DATA);
+    }
+
+    UINT8_TO_STREAM(p, action);
+
+    /* Filter index */
+    UINT8_TO_STREAM(p, filt_index);
+
+    if (BTM_BLE_SCAN_COND_ADD == action || BTM_BLE_SCAN_COND_DELETE == action)
+    {
+        if (BTM_BLE_PF_SRVC_DATA_PATTERN == cond_type)
+        {
+            if (NULL == p_srvc_data)
+                return st;
+            if (p_srvc_data->data_len > (BTM_BLE_PF_STR_LEN_MAX - 2))
+                p_srvc_data->data_len = (BTM_BLE_PF_STR_LEN_MAX - 2);
+
+            if (p_srvc_data->data_len > 0)
+            {
+                ARRAY_TO_STREAM(p, p_srvc_data->p_pattern, p_srvc_data->data_len);
+                len += (p_srvc_data->data_len);
+                ARRAY_TO_STREAM(p, p_srvc_data->p_pattern_mask, p_srvc_data->data_len);
+            }
+
+            len += (p_srvc_data->data_len);
+            BTM_TRACE_DEBUG("Service data length: %d", len);
+        }
+        else
+        {
+            if (NULL == p_manu_data)
+            {
+                BTM_TRACE_ERROR("btm_ble_update_pf_manu_data - No manuf data");
+                return st;
+            }
+            BTM_TRACE_EVENT("btm_ble_update_pf_manu_data length: %d",
+                                    p_manu_data->data_len);
+            if (p_manu_data->data_len > (BTM_BLE_PF_STR_LEN_MAX - 2))
+                p_manu_data->data_len = (BTM_BLE_PF_STR_LEN_MAX - 2);
+
+            UINT16_TO_STREAM(p, p_manu_data->company_id);
+            if (p_manu_data->data_len > 0 && p_manu_data->p_pattern_mask != NULL)
+            {
+                ARRAY_TO_STREAM(p, p_manu_data->p_pattern, p_manu_data->data_len);
+                len += (p_manu_data->data_len + 2);
+            }
+            else
+                len += 2;
+
+            if (p_manu_data->company_id_mask != 0)
+            {
+                UINT16_TO_STREAM (p, p_manu_data->company_id_mask);
+            }
+            else
+            {
+                memset(p, 0xff, 2);
+                p += 2;
+            }
+            len += 2;
+
+            if (p_manu_data->data_len > 0 && p_manu_data->p_pattern_mask != NULL)
+            {
+                ARRAY_TO_STREAM(p, p_manu_data->p_pattern_mask, p_manu_data->data_len);
+                len += (p_manu_data->data_len);
+            }
+
+            BTM_TRACE_DEBUG("Manuf data length: %d", len);
+        }
+    }
+
+    /* send manufacturer*/
+    BTM_VendorSpecificCommand(HCI_BLE_ADV_FILTER_OCF, len, param,
+                              btm_ble_scan_pf_cmpl_cback);
+    memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
+    return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_cs_update_pf_counter
+**
+** Description      this function is to update the adv data payload filter counter
+**
+** Returns          current number of the counter; BTM_BLE_INVALID_COUNTER if
+**                  counter update failed.
+**
+*******************************************************************************/
+uint8_t btm_ble_cs_update_pf_counter(tBTM_BLE_SCAN_COND_OP action,
+                                  uint8_t cond_type, tBLE_BD_ADDR *p_bd_addr,
+                                  uint8_t num_available)
+{
+    tBTM_BLE_PF_COUNT   *p_addr_filter = NULL;
+    uint8_t             *p_counter = NULL;
+
+    btm_ble_obtain_vsc_details();
+
+    if (cond_type > BTM_BLE_PF_TYPE_ALL)
+    {
+        BTM_TRACE_ERROR("unknown PF filter condition type %d", cond_type);
+        return BTM_BLE_INVALID_COUNTER;
+    }
+
+    /* for these three types of filter, always generic */
+    if (BTM_BLE_PF_ADDR_FILTER == cond_type ||
+        BTM_BLE_PF_MANU_DATA == cond_type ||
+        BTM_BLE_PF_LOCAL_NAME == cond_type ||
+        BTM_BLE_PF_SRVC_DATA_PATTERN == cond_type)
+        p_bd_addr = NULL;
+
+    if ((p_addr_filter = btm_ble_find_addr_filter_counter(p_bd_addr)) == NULL &&
+        BTM_BLE_SCAN_COND_ADD == action)
+    {
+        p_addr_filter = btm_ble_alloc_addr_filter_counter(p_bd_addr->bda);
+    }
+
+    if (NULL != p_addr_filter)
+    {
+        /* all filter just cleared */
+        if ((BTM_BLE_PF_TYPE_ALL == cond_type && BTM_BLE_SCAN_COND_CLEAR == action) ||
+            /* or bd address filter been deleted */
+            (BTM_BLE_PF_ADDR_FILTER == cond_type &&
+             (BTM_BLE_SCAN_COND_DELETE == action || BTM_BLE_SCAN_COND_CLEAR == action)))
+        {
+            btm_ble_dealloc_addr_filter_counter(p_bd_addr, cond_type);
+        }
+        /* if not feature selection, update new addition/reduction of the filter counter */
+        else if (cond_type != BTM_BLE_PF_TYPE_ALL)
+        {
+            p_counter = p_addr_filter->pf_counter;
+            if (num_available > 0)
+                p_counter[cond_type] += 1;
+
+            BTM_TRACE_DEBUG("counter = %d, maxfilt = %d, num_avbl=%d",
+                p_counter[cond_type], cmn_ble_vsc_cb.max_filter, num_available);
+            return p_counter[cond_type];
+        }
+    }
+    else
+    {
+        BTM_TRACE_ERROR("no matching filter counter found");
+    }
+    /* no matching filter located and updated */
+    return BTM_BLE_INVALID_COUNTER;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_update_addr_filter
+**
+** Description      this function update(add,delete or clear) the address filter of adv.
+**
+**
+** Returns          BTM_CMD_STARTED if sucessful,
+**                  BTM_ILLEGAL_VALUE if paramter is not valid.
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_update_addr_filter(tBTM_BLE_SCAN_COND_OP action,
+                                       tBTM_BLE_PF_FILT_INDEX filt_index,
+                                       tBTM_BLE_PF_COND_PARAM *p_cond)
+{
+    uint8_t     param[BTM_BLE_META_ADDR_LEN + BTM_BLE_ADV_FILT_META_HDR_LENGTH],
+                * p= param;
+    tBLE_BD_ADDR *p_addr = (p_cond == NULL) ? NULL : &p_cond->target_addr;
+
+    memset(param, 0, BTM_BLE_META_ADDR_LEN + BTM_BLE_ADV_FILT_META_HDR_LENGTH);
+
+    UINT8_TO_STREAM(p, BTM_BLE_META_PF_ADDR);
+    UINT8_TO_STREAM(p, action);
+
+    /* Filter index */
+    UINT8_TO_STREAM(p, filt_index);
+
+    if (BTM_BLE_SCAN_COND_ADD == action ||
+        BTM_BLE_SCAN_COND_DELETE == action)
+    {
+        if (NULL == p_addr)
+            return BTM_ILLEGAL_VALUE;
+
+        BDADDR_TO_STREAM(p, p_addr->bda);
+        UINT8_TO_STREAM(p, p_addr->type);
+    }
+    /* send address filter */
+    BTM_VendorSpecificCommand(HCI_BLE_ADV_FILTER_OCF,
+                              (uint8_t)(BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_META_ADDR_LEN),
+                              param,
+                              btm_ble_scan_pf_cmpl_cback);
+    memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
+    return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_update_uuid_filter
+**
+** Description      this function update(add,delete or clear) service UUID filter.
+**
+**
+** Returns          BTM_CMD_STARTED if sucessful,
+**                  BTM_ILLEGAL_VALUE if paramter is not valid.
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_update_uuid_filter(tBTM_BLE_SCAN_COND_OP action,
+                                       tBTM_BLE_PF_FILT_INDEX filt_index,
+                                       tBTM_BLE_PF_COND_TYPE filter_type,
+                                       tBTM_BLE_PF_COND_PARAM *p_cond,
+                                       tBTM_BLE_FILT_CB_EVT cb_evt,
+                                       tBTM_BLE_REF_VALUE ref_value)
+{
+    uint8_t     param[BTM_BLE_META_UUID_LEN + BTM_BLE_ADV_FILT_META_HDR_LENGTH],
+                * p= param,
+                len = BTM_BLE_ADV_FILT_META_HDR_LENGTH;
+    tBTM_BLE_PF_UUID_COND *p_uuid_cond;
+    uint8_t         evt_type;
+
+    memset(param, 0, BTM_BLE_META_UUID_LEN + BTM_BLE_ADV_FILT_META_HDR_LENGTH);
+
+    if (BTM_BLE_PF_SRVC_UUID == filter_type)
+    {
+        evt_type = BTM_BLE_META_PF_UUID;
+        p_uuid_cond = p_cond ? &p_cond->srvc_uuid : NULL;
+    }
+    else
+    {
+        evt_type = BTM_BLE_META_PF_SOL_UUID;
+        p_uuid_cond = p_cond ? &p_cond->solicitate_uuid : NULL;
+    }
+
+    if (NULL == p_uuid_cond && action != BTM_BLE_SCAN_COND_CLEAR)
+    {
+        BTM_TRACE_ERROR("Illegal param for add/delete UUID filter");
+        return BTM_ILLEGAL_VALUE;
+    }
+
+    /* need to add address filter first, if adding per bda UUID filter without address filter */
+    if (BTM_BLE_SCAN_COND_ADD == action && NULL != p_uuid_cond &&
+        p_uuid_cond->p_target_addr &&
+        btm_ble_find_addr_filter_counter(p_uuid_cond->p_target_addr) == NULL)
+    {
+        UINT8_TO_STREAM(p, BTM_BLE_META_PF_ADDR);
+        UINT8_TO_STREAM(p, action);
+
+        /* Filter index */
+        UINT8_TO_STREAM(p, filt_index);
+
+        BDADDR_TO_STREAM(p, p_uuid_cond->p_target_addr->bda);
+        UINT8_TO_STREAM(p, p_uuid_cond->p_target_addr->type);
+
+        /* send address filter */
+        BTM_VendorSpecificCommand(HCI_BLE_ADV_FILTER_OCF,
+                                  (uint8_t)(BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_META_ADDR_LEN),
+                                  param,
+                                  btm_ble_scan_pf_cmpl_cback);
+        btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_ADDR, cb_evt, ref_value, NULL, NULL);
+        BTM_TRACE_DEBUG("Updated Address filter");
+    }
+
+    p = param;
+    UINT8_TO_STREAM(p, evt_type);
+    UINT8_TO_STREAM(p, action);
+
+    /* Filter index */
+    UINT8_TO_STREAM(p, filt_index);
+
+    if ((BTM_BLE_SCAN_COND_ADD == action ||
+        BTM_BLE_SCAN_COND_DELETE == action) &&
+        NULL != p_uuid_cond)
+    {
+        if (p_uuid_cond->uuid.len == LEN_UUID_16)
+        {
+            UINT16_TO_STREAM(p, p_uuid_cond->uuid.uu.uuid16);
+            len += LEN_UUID_16;
+        }
+        else if (p_uuid_cond->uuid.len == LEN_UUID_32)/*4 bytes */
+        {
+            UINT32_TO_STREAM(p, p_uuid_cond->uuid.uu.uuid32);
+            len += LEN_UUID_32;
+        }
+        else if (p_uuid_cond->uuid.len == LEN_UUID_128)
+        {
+            ARRAY_TO_STREAM (p, p_uuid_cond->uuid.uu.uuid128, LEN_UUID_128);
+            len += LEN_UUID_128;
+        }
+        else
+        {
+            BTM_TRACE_ERROR("illegal UUID length: %d", p_uuid_cond->uuid.len);
+            return BTM_ILLEGAL_VALUE;
+        }
+
+        if (NULL != p_uuid_cond->p_uuid_mask)
+        {
+            if (p_uuid_cond->uuid.len == LEN_UUID_16)
+            {
+                UINT16_TO_STREAM(p, p_uuid_cond->p_uuid_mask->uuid16_mask);
+                len += LEN_UUID_16;
+            }
+            else if (p_uuid_cond->uuid.len == LEN_UUID_32)/*4 bytes */
+            {
+                UINT32_TO_STREAM(p, p_uuid_cond->p_uuid_mask->uuid32_mask);
+                len += LEN_UUID_32;
+            }
+            else if (p_uuid_cond->uuid.len == LEN_UUID_128)
+            {
+                ARRAY_TO_STREAM (p, p_uuid_cond->p_uuid_mask->uuid128_mask, LEN_UUID_128);
+                len += LEN_UUID_128;
+            }
+        }
+        else
+        {
+            memset(p, 0xff, p_uuid_cond->uuid.len);
+            len += p_uuid_cond->uuid.len;
+        }
+        BTM_TRACE_DEBUG("btm_ble_update_uuid_filter : %d, %d, %d, %d", filter_type, evt_type,
+                        p_uuid_cond->uuid.len, len);
+    }
+
+    /* send UUID filter update */
+    BTM_VendorSpecificCommand(HCI_BLE_ADV_FILTER_OCF,
+                              len,
+                              param,
+                              btm_ble_scan_pf_cmpl_cback);
+    if (p_uuid_cond && p_uuid_cond->p_target_addr)
+        memcpy(&btm_ble_adv_filt_cb.cur_filter_target, p_uuid_cond->p_target_addr,
+                sizeof(tBLE_BD_ADDR));
+    else
+        memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
+
+    return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_clear_scan_pf_filter
+**
+** Description      clear all adv payload filter by de-select all the adv pf feature bits
+**
+**
+** Returns          BTM_CMD_STARTED if sucessful,
+**                  BTM_ILLEGAL_VALUE if paramter is not valid.
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_clear_scan_pf_filter(tBTM_BLE_SCAN_COND_OP action,
+                                       tBTM_BLE_PF_FILT_INDEX filt_index,
+                                       tBTM_BLE_PF_COND_PARAM *p_cond,
+                                       tBTM_BLE_PF_CFG_CBACK *p_cmpl_cback,
+                                       tBTM_BLE_FILT_CB_EVT cb_evt,
+                                       tBTM_BLE_REF_VALUE ref_value)
+{
+    tBLE_BD_ADDR *p_target = (p_cond == NULL)? NULL : &p_cond->target_addr;
+    tBTM_BLE_PF_COUNT *p_bda_filter;
+    tBTM_STATUS     st = BTM_WRONG_MODE;
+    uint8_t         param[20], *p;
+
+    if (BTM_BLE_SCAN_COND_CLEAR != action)
+    {
+        BTM_TRACE_ERROR("unable to perform action:%d for generic adv filter type", action);
+        return BTM_ILLEGAL_VALUE;
+    }
+
+    p = param;
+    memset(param, 0, 20);
+
+    p_bda_filter = btm_ble_find_addr_filter_counter(p_target);
+
+    if (NULL == p_bda_filter ||
+        /* not a generic filter */
+        (p_target != NULL && p_bda_filter))
+    {
+        BTM_TRACE_ERROR("Error: Can not clear filter, No PF filter has been configured!");
+        return st;
+    }
+
+    /* clear the general filter entry */
+    if (NULL == p_target)
+    {
+        /* clear manufactuer data filter */
+        st = btm_ble_update_pf_manu_data(BTM_BLE_SCAN_COND_CLEAR, filt_index, NULL,
+                                    BTM_BLE_PF_MANU_DATA, cb_evt, ref_value);
+        if(BTM_CMD_STARTED == st)
+           btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_MANU_DATA, cb_evt,
+                                    ref_value, NULL, NULL);
+
+        /* clear local name filter */
+        st = btm_ble_update_pf_local_name(BTM_BLE_SCAN_COND_CLEAR, filt_index, NULL);
+        if(BTM_CMD_STARTED == st)
+           btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_LOCAL_NAME, cb_evt,
+                                    ref_value, NULL, NULL);
+
+        /* update the counter for service data */
+        st = btm_ble_update_srvc_data_change(BTM_BLE_SCAN_COND_CLEAR, filt_index, NULL);
+
+        /* clear UUID filter */
+        st = btm_ble_update_uuid_filter(BTM_BLE_SCAN_COND_CLEAR, filt_index,
+                                   BTM_BLE_PF_SRVC_UUID, NULL, cb_evt, ref_value);
+        if(BTM_CMD_STARTED == st)
+           btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_UUID, cb_evt, ref_value, NULL, NULL);
+
+        st = btm_ble_update_uuid_filter(BTM_BLE_SCAN_COND_CLEAR, filt_index,
+                                   BTM_BLE_PF_SRVC_SOL_UUID, NULL, cb_evt, ref_value);
+        if(BTM_CMD_STARTED == st)
+           btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_SOL_UUID, cb_evt,
+                                    ref_value, NULL, NULL);
+
+        /* clear service data filter */
+        st = btm_ble_update_pf_manu_data(BTM_BLE_SCAN_COND_CLEAR, filt_index, NULL,
+                                    BTM_BLE_PF_SRVC_DATA_PATTERN, cb_evt, ref_value);
+        if(BTM_CMD_STARTED == st)
+           btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_SRVC_DATA, cb_evt,
+                                    ref_value, NULL, NULL);
+    }
+
+    /* select feature based on control block settings */
+    UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL);
+    UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_CLEAR);
+
+    /* Filter index */
+    UINT8_TO_STREAM(p, filt_index);
+
+    /* set PCF selection */
+    UINT32_TO_STREAM(p, BTM_BLE_PF_SELECT_NONE);
+    /* set logic condition as OR as default */
+    UINT8_TO_STREAM(p, BTM_BLE_PF_LOGIC_OR);
+
+    BTM_VendorSpecificCommand(HCI_BLE_ADV_FILTER_OCF,
+                               (uint8_t)(BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_PF_FEAT_SEL_LEN),
+                                param,
+                                btm_ble_scan_pf_cmpl_cback);
+    if (p_target)
+        memcpy(&btm_ble_adv_filt_cb.cur_filter_target, p_target, sizeof(tBLE_BD_ADDR));
+    else
+        memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
+    return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function         BTM_BleAdvFilterParamSetup
+**
+** Description      This function is called to setup the adv data payload filter
+**                  condition.
+**
+** Parameters       action - Type of action to be performed
+**                       filt_index - Filter index
+**                       p_filt_params - Filter parameters
+**                       p_target - Target device
+**                       p_cmpl_back - Callback pointer
+**                       ref_value - reference value
+**
+** Returns          void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleAdvFilterParamSetup(int action, tBTM_BLE_PF_FILT_INDEX filt_index,
+                                tBTM_BLE_PF_FILT_PARAMS *p_filt_params,
+                                tBLE_BD_ADDR *p_target, tBTM_BLE_PF_PARAM_CBACK *p_cmpl_cback,
+                                tBTM_BLE_REF_VALUE ref_value)
+{
+    tBTM_BLE_PF_COUNT *p_bda_filter = NULL;
+    uint8_t len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_ADV_FILT_FEAT_SELN_LEN +
+                BTM_BLE_ADV_FILT_TRACK_NUM;
+    uint8_t param[len], *p;
+
+    if (BTM_SUCCESS  != btm_ble_obtain_vsc_details())
+        return BTM_WRONG_MODE;
+
+    p = param;
+    memset(param, 0, len);
+    BTM_TRACE_EVENT (" BTM_BleAdvFilterParamSetup");
+
+    if (BTM_BLE_SCAN_COND_ADD == action)
+    {
+        p_bda_filter = btm_ble_find_addr_filter_counter(p_target);
+        if (NULL == p_bda_filter)
+        {
+           BTM_TRACE_ERROR("BD Address not found!");
+           return BTM_WRONG_MODE;
+        }
+
+        BTM_TRACE_DEBUG("BTM_BleAdvFilterParamSetup : Feat mask:%d", p_filt_params->feat_seln);
+        /* select feature based on control block settings */
+        UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL);
+        UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_ADD);
+
+        /* Filter index */
+        UINT8_TO_STREAM(p, filt_index);
+
+        /* set PCF selection */
+        UINT16_TO_STREAM(p, p_filt_params->feat_seln);
+        /* set logic type */
+        UINT16_TO_STREAM(p, p_filt_params->logic_type);
+        /* set logic condition */
+        UINT8_TO_STREAM(p, p_filt_params->filt_logic_type);
+        /* set RSSI high threshold */
+        UINT8_TO_STREAM(p, p_filt_params->rssi_high_thres);
+        /* set delivery mode */
+        UINT8_TO_STREAM(p, p_filt_params->dely_mode);
+
+        if (0x01 == p_filt_params->dely_mode)
+        {
+            /* set onfound timeout */
+            UINT16_TO_STREAM(p, p_filt_params->found_timeout);
+            /* set onfound timeout count*/
+            UINT8_TO_STREAM(p, p_filt_params->found_timeout_cnt);
+            /* set RSSI low threshold */
+            UINT8_TO_STREAM(p, p_filt_params->rssi_low_thres);
+            /* set onlost timeout */
+            UINT16_TO_STREAM(p, p_filt_params->lost_timeout);
+            /* set num_of_track_entries for firmware greater than L-release version */
+            if (cmn_ble_vsc_cb.version_supported > BTM_VSC_CHIP_CAPABILITY_L_VERSION)
+                UINT16_TO_STREAM(p, p_filt_params->num_of_tracking_entries);
+        }
+
+        if (cmn_ble_vsc_cb.version_supported == BTM_VSC_CHIP_CAPABILITY_L_VERSION)
+            len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_ADV_FILT_FEAT_SELN_LEN;
+        else
+            len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_ADV_FILT_FEAT_SELN_LEN +
+                  BTM_BLE_ADV_FILT_TRACK_NUM;
+
+        BTM_VendorSpecificCommand(HCI_BLE_ADV_FILTER_OCF,
+                                  (uint8_t)len,
+                                  param,
+                                  btm_ble_scan_pf_cmpl_cback);
+        btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_FEAT_SEL, BTM_BLE_FILT_ADV_PARAM,
+                                 ref_value, NULL, p_cmpl_cback);
+    }
+    else
+    if (BTM_BLE_SCAN_COND_DELETE == action)
+    {
+        /* select feature based on control block settings */
+        UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL);
+        UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_DELETE);
+        /* Filter index */
+        UINT8_TO_STREAM(p, filt_index);
+
+        BTM_VendorSpecificCommand(HCI_BLE_ADV_FILTER_OCF,
+                                  (uint8_t)(BTM_BLE_ADV_FILT_META_HDR_LENGTH),
+                                  param,
+                                  btm_ble_scan_pf_cmpl_cback);
+        btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_FEAT_SEL,  BTM_BLE_FILT_ADV_PARAM,
+                                 ref_value, NULL, p_cmpl_cback);
+    }
+    else
+    if (BTM_BLE_SCAN_COND_CLEAR == action)
+    {
+        /* Deallocate all filters here */
+        btm_ble_dealloc_addr_filter_counter(NULL, BTM_BLE_PF_TYPE_ALL);
+
+        /* select feature based on control block settings */
+        UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL);
+        UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_CLEAR);
+
+        BTM_VendorSpecificCommand(HCI_BLE_ADV_FILTER_OCF,
+                                  (uint8_t)(BTM_BLE_ADV_FILT_META_HDR_LENGTH-1),
+                                  param,
+                                  btm_ble_scan_pf_cmpl_cback);
+        btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_FEAT_SEL,  BTM_BLE_FILT_ADV_PARAM,
+                                 ref_value, NULL, p_cmpl_cback);
+    }
+    return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function         BTM_BleEnableDisableFilterFeature
+**
+** Description      This function is called to enable / disable the APCF feature
+**
+** Parameters  enable the generic scan condition.
+**                  enable: enable or disable the filter condition
+**                  p_stat_cback - Status callback pointer
+**                  ref_value   - Ref value
+** Returns          void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleEnableDisableFilterFeature(uint8_t enable,
+                                     tBTM_BLE_PF_STATUS_CBACK *p_stat_cback,
+                                     tBTM_BLE_REF_VALUE ref_value)
+{
+    uint8_t         param[20], *p;
+    tBTM_STATUS     st = BTM_WRONG_MODE;
+
+    if (BTM_SUCCESS  != btm_ble_obtain_vsc_details())
+       return st;
+
+    p = param;
+    memset(param, 0, 20);
+
+    /* enable the content filter in controller */
+    p = param;
+    UINT8_TO_STREAM(p, BTM_BLE_META_PF_ENABLE);
+    /* enable adv data payload filtering */
+    UINT8_TO_STREAM(p, enable);
+
+    BTM_VendorSpecificCommand(HCI_BLE_ADV_FILTER_OCF,
+                              BTM_BLE_PCF_ENABLE_LEN, param,
+                              btm_ble_scan_pf_cmpl_cback);
+    btm_ble_adv_filt_cb.p_filt_stat_cback = p_stat_cback;
+    btm_ble_advfilt_enq_op_q(enable, BTM_BLE_META_PF_ENABLE, BTM_BLE_FILT_ENABLE_DISABLE,
+                             ref_value, NULL, NULL);
+    return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function         BTM_BleCfgFilterCondition
+**
+** Description      This function is called to configure the adv data payload filter
+**                  condition.
+**
+** Parameters       action: to read/write/clear
+**                  cond_type: filter condition type.
+**                  filt_index - Filter index
+**                  p_cond: filter condition parameter
+**                  p_cmpl_cback  - Config callback pointer
+**                  ref_value - Reference value
+**
+** Returns          void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleCfgFilterCondition(tBTM_BLE_SCAN_COND_OP action,
+                                      tBTM_BLE_PF_COND_TYPE cond_type,
+                                      tBTM_BLE_PF_FILT_INDEX filt_index,
+                                      tBTM_BLE_PF_COND_PARAM *p_cond,
+                                      tBTM_BLE_PF_CFG_CBACK *p_cmpl_cback,
+                                      tBTM_BLE_REF_VALUE ref_value)
+{
+    tBTM_STATUS     st = BTM_ILLEGAL_VALUE;
+    uint8_t ocf = 0;
+    BTM_TRACE_EVENT (" BTM_BleCfgFilterCondition action:%d, cond_type:%d, index:%d", action,
+                        cond_type, filt_index);
+
+    if (BTM_SUCCESS  != btm_ble_obtain_vsc_details())
+        return st;
+
+    switch (cond_type)
+    {
+        /* write service data filter */
+        case BTM_BLE_PF_SRVC_DATA_PATTERN:
+        /* write manufacturer data filter */
+        case BTM_BLE_PF_MANU_DATA:
+            st = btm_ble_update_pf_manu_data(action, filt_index, p_cond, cond_type, 0, ref_value);
+            break;
+
+        /* write local name filter */
+        case BTM_BLE_PF_LOCAL_NAME:
+            st = btm_ble_update_pf_local_name(action, filt_index, p_cond);
+            break;
+
+        /* filter on advertiser address */
+        case BTM_BLE_PF_ADDR_FILTER:
+            st = btm_ble_update_addr_filter(action, filt_index, p_cond);
+            break;
+
+        /* filter on service/solicitated UUID */
+        case BTM_BLE_PF_SRVC_UUID:
+        case BTM_BLE_PF_SRVC_SOL_UUID:
+            st = btm_ble_update_uuid_filter(action, filt_index, cond_type, p_cond, 0, ref_value);
+            break;
+
+        case BTM_BLE_PF_SRVC_DATA:
+            st = btm_ble_update_srvc_data_change(action, filt_index, p_cond);
+            break;
+
+        case BTM_BLE_PF_TYPE_ALL: /* only used to clear filter */
+            st = btm_ble_clear_scan_pf_filter(action, filt_index, p_cond, p_cmpl_cback,
+                                              0, ref_value);
+            break;
+
+        default:
+            BTM_TRACE_WARNING("condition type [%d] not supported currently.", cond_type);
+            break;
+    }
+
+    if(BTM_CMD_STARTED == st && cond_type != BTM_BLE_PF_TYPE_ALL)
+    {
+       ocf = btm_ble_condtype_to_ocf(cond_type);
+       btm_ble_advfilt_enq_op_q(action, ocf, BTM_BLE_FILT_CFG, ref_value, p_cmpl_cback, NULL);
+    }
+    else
+    if(BTM_CMD_STARTED == st && BTM_BLE_PF_TYPE_ALL == cond_type)
+    {
+       btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_FEAT_SEL, BTM_BLE_FILT_CFG,
+                                ref_value, p_cmpl_cback, NULL);
+    }
+    return st;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_adv_filter_init
+**
+** Description      This function initializes the adv filter control block
+**
+** Parameters
+**
+** Returns          status
+**
+*******************************************************************************/
+void btm_ble_adv_filter_init(void)
+{
+    memset(&btm_ble_adv_filt_cb, 0, sizeof(tBTM_BLE_ADV_FILTER_CB));
+    if (BTM_SUCCESS != btm_ble_obtain_vsc_details())
+       return;
+
+    if (cmn_ble_vsc_cb.max_filter > 0)
+    {
+        btm_ble_adv_filt_cb.p_addr_filter_count =
+            (tBTM_BLE_PF_COUNT*)osi_malloc(sizeof(tBTM_BLE_PF_COUNT) * cmn_ble_vsc_cb.max_filter);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_adv_filter_cleanup
+**
+** Description      This function de-initializes the adv filter control block
+**
+** Parameters
+**
+** Returns          status
+**
+*******************************************************************************/
+void btm_ble_adv_filter_cleanup(void)
+{
+    osi_free_and_reset((void **)&btm_ble_adv_filt_cb.p_addr_filter_count);
+}
+
+#endif
diff --git a/bt/stack/btm/btm_ble_batchscan.cc b/bt/stack/btm/btm_ble_batchscan.cc
new file mode 100644
index 0000000..c61e781
--- /dev/null
+++ b/bt/stack/btm/btm_ble_batchscan.cc
@@ -0,0 +1,896 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 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.
+ *
+ ******************************************************************************/
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+#include "bt_target.h"
+
+#include "btm_ble_api.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btu.h"
+#include "btm_int.h"
+#include "device/include/controller.h"
+#include "hcimsgs.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+tBTM_BLE_BATCH_SCAN_CB ble_batchscan_cb;
+tBTM_BLE_ADV_TRACK_CB ble_advtrack_cb;
+
+
+/* length of each batch scan command */
+#define BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN      4
+#define BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN    12
+#define BTM_BLE_BATCH_SCAN_ENB_DISB_LEN         2
+#define BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN     2
+
+#define BTM_BLE_BATCH_SCAN_CB_EVT_MASK       0xF0
+#define BTM_BLE_BATCH_SCAN_SUBCODE_MASK      0x0F
+
+/*******************************************************************************
+**  Local functions
+*******************************************************************************/
+void btm_ble_batchscan_vsc_cmpl_cback (tBTM_VSC_CMPL *p_params);
+void btm_ble_batchscan_cleanup(void);
+
+/*******************************************************************************
+**
+** Function         btm_ble_batchscan_filter_track_adv_vse_cback
+**
+** Description      VSE callback for batch scan, filter, and tracking events.
+**
+** Returns          None
+**
+*******************************************************************************/
+void btm_ble_batchscan_filter_track_adv_vse_cback(uint8_t len, uint8_t *p)
+{
+    tBTM_BLE_TRACK_ADV_DATA adv_data;
+
+    uint8_t sub_event = 0;
+    tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+    STREAM_TO_UINT8(sub_event, p);
+
+    BTM_TRACE_EVENT("btm_ble_batchscan_filter_track_adv_vse_cback called with event:%x", sub_event);
+    if (HCI_VSE_SUBCODE_BLE_THRESHOLD_SUB_EVT == sub_event &&
+        NULL != ble_batchscan_cb.p_thres_cback)
+    {
+        ble_batchscan_cb.p_thres_cback(ble_batchscan_cb.ref_value);
+        return;
+    }
+
+    if (HCI_VSE_SUBCODE_BLE_TRACKING_SUB_EVT == sub_event && NULL != ble_advtrack_cb.p_track_cback)
+    {
+        if (len < 10)
+            return;
+
+        memset(&adv_data, 0 , sizeof(tBTM_BLE_TRACK_ADV_DATA));
+        BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+        adv_data.client_if = (uint8_t)ble_advtrack_cb.ref_value;
+        if (cmn_ble_vsc_cb.version_supported > BTM_VSC_CHIP_CAPABILITY_L_VERSION)
+        {
+            STREAM_TO_UINT8(adv_data.filt_index, p);
+            STREAM_TO_UINT8(adv_data.advertiser_state, p);
+            STREAM_TO_UINT8(adv_data.advertiser_info_present, p);
+            STREAM_TO_BDADDR(adv_data.bd_addr.address, p);
+            STREAM_TO_UINT8(adv_data.addr_type, p);
+
+            /* Extract the adv info details */
+            if (ADV_INFO_PRESENT == adv_data.advertiser_info_present)
+            {
+                STREAM_TO_UINT8(adv_data.tx_power, p);
+                STREAM_TO_UINT8(adv_data.rssi_value, p);
+                STREAM_TO_UINT16(adv_data.time_stamp, p);
+
+                STREAM_TO_UINT8(adv_data.adv_pkt_len, p);
+                if (adv_data.adv_pkt_len > 0)
+                {
+                    adv_data.p_adv_pkt_data =
+                        static_cast<uint8_t *>(osi_malloc(adv_data.adv_pkt_len));
+                    memcpy(adv_data.p_adv_pkt_data, p, adv_data.adv_pkt_len);
+                }
+
+                STREAM_TO_UINT8(adv_data.scan_rsp_len, p);
+                if (adv_data.scan_rsp_len > 0)
+                {
+                    adv_data.p_scan_rsp_data =
+                        static_cast<uint8_t *>(osi_malloc(adv_data.scan_rsp_len));
+                    memcpy(adv_data.p_scan_rsp_data, p, adv_data.scan_rsp_len);
+                }
+            }
+        }
+        else
+        {
+            /* Based on L-release version */
+            STREAM_TO_UINT8(adv_data.filt_index, p);
+            STREAM_TO_UINT8(adv_data.addr_type, p);
+            STREAM_TO_BDADDR(adv_data.bd_addr.address, p);
+            STREAM_TO_UINT8(adv_data.advertiser_state, p);
+        }
+
+        BTM_TRACE_EVENT("track_adv_vse_cback called: %d, %d, %d", adv_data.filt_index,
+                         adv_data.addr_type, adv_data.advertiser_state);
+
+        // Make sure the device is known
+        BTM_SecAddBleDevice(adv_data.bd_addr.address, NULL, BT_DEVICE_TYPE_BLE, adv_data.addr_type);
+
+        ble_advtrack_cb.p_track_cback(&adv_data);
+        return;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_batchscan_enq_op_q
+**
+** Description      enqueue a batchscan operation in q to check command complete
+**                  status
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_batchscan_enq_op_q(uint8_t opcode, tBTM_BLE_BATCH_SCAN_STATE cur_state,
+                                          uint8_t cb_evt, tBTM_BLE_REF_VALUE ref_value)
+{
+    ble_batchscan_cb.op_q.sub_code[ble_batchscan_cb.op_q.next_idx] = (opcode |(cb_evt << 4));
+    ble_batchscan_cb.op_q.cur_state[ble_batchscan_cb.op_q.next_idx] = cur_state;
+    ble_batchscan_cb.op_q.ref_value[ble_batchscan_cb.op_q.next_idx] = ref_value;
+    BTM_TRACE_DEBUG("btm_ble_batchscan_enq_op_q: subcode:%d, Cur_state:%d, ref_value:%d",
+        ble_batchscan_cb.op_q.sub_code[ble_batchscan_cb.op_q.next_idx],
+        ble_batchscan_cb.op_q.cur_state[ble_batchscan_cb.op_q.next_idx],
+        ble_batchscan_cb.op_q.ref_value[ble_batchscan_cb.op_q.next_idx]);
+    ble_batchscan_cb.op_q.next_idx = (ble_batchscan_cb.op_q.next_idx + 1)
+                                        % BTM_BLE_BATCH_SCAN_MAX;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_batchscan_enq_rep_q
+**
+** Description      enqueue a batchscan report operation in q to check command complete
+**                  status
+**
+** Returns          void
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_batchscan_enq_rep_q(uint8_t report_format, tBTM_BLE_REF_VALUE ref_value)
+{
+    int i = 0;
+    for (i = 0; i < BTM_BLE_BATCH_REP_MAIN_Q_SIZE; i++)
+    {
+        if (report_format == ble_batchscan_cb.main_rep_q.rep_mode[i])
+            return BTM_ILLEGAL_VALUE;
+    }
+
+    ble_batchscan_cb.main_rep_q.rep_mode[ble_batchscan_cb.main_rep_q.next_idx] = report_format;
+    ble_batchscan_cb.main_rep_q.ref_value[ble_batchscan_cb.main_rep_q.next_idx] = ref_value;
+    ble_batchscan_cb.main_rep_q.num_records[ble_batchscan_cb.main_rep_q.next_idx] = 0;
+    ble_batchscan_cb.main_rep_q.data_len[ble_batchscan_cb.main_rep_q.next_idx] = 0;
+    ble_batchscan_cb.main_rep_q.p_data[ble_batchscan_cb.main_rep_q.next_idx] = NULL;
+    BTM_TRACE_DEBUG("btm_ble_batchscan_enq_rep_q: index:%d, rep %d, ref %d",
+            ble_batchscan_cb.main_rep_q.next_idx, report_format, ref_value);
+
+    ble_batchscan_cb.main_rep_q.next_idx = (ble_batchscan_cb.main_rep_q.next_idx + 1)
+                                            % BTM_BLE_BATCH_REP_MAIN_Q_SIZE;
+    return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_batchscan_enq_rep_data
+**
+** Description      setup the data in the main report queue
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_batchscan_enq_rep_data(uint8_t report_format, uint8_t num_records, uint8_t *p_data,
+                                    uint8_t data_len)
+{
+    int index = 0;
+
+    for (index = 0; index < BTM_BLE_BATCH_REP_MAIN_Q_SIZE; index++)
+    {
+        if (report_format == ble_batchscan_cb.main_rep_q.rep_mode[index])
+            break;
+    }
+
+    BTM_TRACE_DEBUG("btm_ble_batchscan_enq_rep_data: index:%d, rep %d, num %d len : %d",
+        index, report_format, num_records, data_len);
+
+    if (index < BTM_BLE_BATCH_REP_MAIN_Q_SIZE && data_len > 0 && num_records > 0)
+    {
+        int len = ble_batchscan_cb.main_rep_q.data_len[index];
+        uint8_t *p_orig_data = ble_batchscan_cb.main_rep_q.p_data[index];
+        uint8_t *p_app_data;
+
+        if (NULL != p_orig_data)
+        {
+            p_app_data = static_cast<uint8_t *>(osi_malloc(len + data_len));
+            memcpy(p_app_data, p_orig_data, len);
+            memcpy(p_app_data+len, p_data, data_len);
+            osi_free(p_orig_data);
+            ble_batchscan_cb.main_rep_q.p_data[index] = p_app_data;
+            ble_batchscan_cb.main_rep_q.num_records[index] += num_records;
+            ble_batchscan_cb.main_rep_q.data_len[index] += data_len;
+        }
+        else
+        {
+            p_app_data = static_cast<uint8_t *>(osi_malloc(data_len));
+            memcpy(p_app_data, p_data, data_len);
+            ble_batchscan_cb.main_rep_q.p_data[index] = p_app_data;
+            ble_batchscan_cb.main_rep_q.num_records[index] = num_records;
+            ble_batchscan_cb.main_rep_q.data_len[index] = data_len;
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_batchscan_deq_rep_q
+**
+** Description      dequeue a batchscan report  in q when command complete
+**                  is received
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_batchscan_deq_rep_data(uint8_t report_format, tBTM_BLE_REF_VALUE *p_ref_value,
+                                 uint8_t *p_num_records, uint8_t **p_data, uint16_t *p_data_len)
+{
+    int index = 0;
+
+    for (index = 0; index < BTM_BLE_BATCH_REP_MAIN_Q_SIZE; index++)
+    {
+        if (report_format == ble_batchscan_cb.main_rep_q.rep_mode[index])
+            break;
+    }
+
+    if (BTM_BLE_BATCH_REP_MAIN_Q_SIZE == index)
+    {
+        BTM_TRACE_ERROR("btm_ble_batchscan_deq_rep_data: rep_format:%d not found", report_format);
+        return;
+    }
+
+    *p_num_records = ble_batchscan_cb.main_rep_q.num_records[index];
+    *p_ref_value = ble_batchscan_cb.main_rep_q.ref_value[index];
+    *p_data = ble_batchscan_cb.main_rep_q.p_data[index];
+    *p_data_len = ble_batchscan_cb.main_rep_q.data_len[index];
+
+    ble_batchscan_cb.main_rep_q.p_data[index] = NULL;
+    ble_batchscan_cb.main_rep_q.data_len[index] = 0;
+    ble_batchscan_cb.main_rep_q.rep_mode[index] = 0;
+    ble_batchscan_cb.main_rep_q.ref_value[index] = 0;
+    ble_batchscan_cb.main_rep_q.num_records[index] = 0;
+
+    BTM_TRACE_DEBUG("btm_ble_batchscan_deq_rep_data: index:%d, rep %d, num %d, data_len %d",
+        index, report_format, *p_num_records, *p_data_len);
+
+    ble_batchscan_cb.main_rep_q.pending_idx = (ble_batchscan_cb.main_rep_q.pending_idx + 1)
+                                            % BTM_BLE_BATCH_SCAN_MAX;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_batchscan_deq_op_q
+**
+** Description      dequeue a batch scan operation from q when command complete
+**                  is received
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_batchscan_deq_op_q(uint8_t *p_opcode,tBTM_BLE_BATCH_SCAN_STATE *cur_state,
+                                          uint8_t *p_cb_evt, tBTM_BLE_REF_VALUE *p_ref)
+{
+    *p_cb_evt = (ble_batchscan_cb.op_q.sub_code[ble_batchscan_cb.op_q.pending_idx] >> 4);
+    *p_opcode = (ble_batchscan_cb.op_q.sub_code[ble_batchscan_cb.op_q.pending_idx]
+                                            & BTM_BLE_BATCH_SCAN_SUBCODE_MASK);
+    *p_ref = ble_batchscan_cb.op_q.ref_value[ble_batchscan_cb.op_q.pending_idx];
+    *cur_state = (ble_batchscan_cb.op_q.cur_state[ble_batchscan_cb.op_q.pending_idx]);
+    ble_batchscan_cb.op_q.pending_idx = (ble_batchscan_cb.op_q.pending_idx + 1)
+                                            % BTM_BLE_BATCH_SCAN_MAX;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_read_batchscan_reports
+**
+** Description      This function reads the reports from controller
+**
+** Parameters       scan_mode - The mode for which the reports are to be read out from the controller
+**                  ref_value - Reference value
+**
+*******************************************************************************/
+void btm_ble_read_batchscan_reports(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
+                                          tBTM_BLE_REF_VALUE ref_value)
+{
+    uint8_t param[BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN], *pp;
+    pp = param;
+
+    memset(param, 0, BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN);
+
+    UINT8_TO_STREAM (pp, BTM_BLE_BATCH_SCAN_READ_RESULTS);
+    UINT8_TO_STREAM (pp, scan_mode);
+
+    BTM_VendorSpecificCommand(HCI_BLE_BATCH_SCAN_OCF,
+            BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN, param, btm_ble_batchscan_vsc_cmpl_cback);
+
+    /* The user needs to be provided scan read reports event */
+    btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_READ_RESULTS, ble_batchscan_cb.cur_state,
+                               BTM_BLE_BATCH_SCAN_READ_REPTS_EVT, ref_value);
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_batchscan_vsc_cmpl_cback
+**
+** Description      Batch scan VSC complete callback
+**
+** Parameters       p_params - VSC completed callback parameters
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_batchscan_vsc_cmpl_cback (tBTM_VSC_CMPL *p_params)
+{
+    uint8_t *p = p_params->p_param_buf;
+    uint16_t len = p_params->param_len;
+    tBTM_BLE_REF_VALUE ref_value = 0;
+
+    uint8_t status = 0, subcode = 0, opcode = 0;
+    uint8_t report_format = 0, num_records = 0, cb_evt = 0;
+    uint16_t data_len = 0;
+    tBTM_BLE_BATCH_SCAN_STATE cur_state = BTM_BLE_SCAN_INVALID_STATE;
+    uint8_t *p_data = NULL;
+
+    if (len < 2)
+    {
+        BTM_TRACE_ERROR("wrong length for btm_ble_batch_scan_vsc_cmpl_cback");
+        btm_ble_batchscan_deq_op_q(&opcode, &cur_state, &cb_evt, &ref_value);
+        return;
+    }
+
+    STREAM_TO_UINT8(status, p);
+    STREAM_TO_UINT8(subcode, p);
+
+    btm_ble_batchscan_deq_op_q(&opcode, &cur_state, &cb_evt, &ref_value);
+
+    BTM_TRACE_DEBUG("btm_ble_batchscan op_code = %02x state = %02x cb_evt = %02x,ref_value=%d",
+        opcode, cur_state, cb_evt, ref_value);
+
+    if (opcode != subcode)
+    {
+        BTM_TRACE_ERROR("Got unexpected VSC cmpl, expected: %d got: %d",subcode,opcode);
+        return;
+    }
+
+    switch (subcode)
+    {
+        case BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE:
+        {
+             if (BTM_SUCCESS == status && BTM_BLE_SCAN_ENABLE_CALLED == cur_state)
+                 ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLED_STATE;
+             else
+             if (BTM_BLE_SCAN_ENABLE_CALLED == cur_state)
+             {
+                 BTM_TRACE_ERROR("SCAN_ENB_DISAB_CUST_FEATURE - Invalid state after enb");
+                 ble_batchscan_cb.cur_state = BTM_BLE_SCAN_INVALID_STATE;
+             }
+
+             BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEAT status = %d, state: %d,evt=%d",
+                                status, ble_batchscan_cb.cur_state, cb_evt);
+
+             if (cb_evt != 0 && NULL != ble_batchscan_cb.p_setup_cback)
+                ble_batchscan_cb.p_setup_cback(cb_evt, ref_value, status);
+             break;
+        }
+
+        case BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM:
+        {
+            BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM status = %d, evt=%d",
+                            status, cb_evt);
+            if (cb_evt != 0 && NULL != ble_batchscan_cb.p_setup_cback)
+                ble_batchscan_cb.p_setup_cback(cb_evt, ref_value, status);
+            break;
+        }
+
+        case BTM_BLE_BATCH_SCAN_SET_PARAMS:
+        {
+            BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_SET_PARAMS status = %d,evt=%d", status, cb_evt);
+
+            if (BTM_BLE_SCAN_DISABLE_CALLED == cur_state)
+            {
+                if (BTM_SUCCESS == status)
+                {
+                    ble_batchscan_cb.cur_state = BTM_BLE_SCAN_DISABLED_STATE;
+                }
+                else
+                {
+                    BTM_TRACE_ERROR("BTM_BLE_BATCH_SCAN_SET_PARAMS - Invalid state after disabled");
+                    ble_batchscan_cb.cur_state = BTM_BLE_SCAN_INVALID_STATE;
+                }
+            }
+
+            if (cb_evt != 0 && NULL != ble_batchscan_cb.p_setup_cback)
+               ble_batchscan_cb.p_setup_cback(cb_evt, ref_value, status);
+            break;
+        }
+
+        case BTM_BLE_BATCH_SCAN_READ_RESULTS:
+        {
+            if (cb_evt != 0 && NULL != ble_batchscan_cb.p_scan_rep_cback)
+            {
+                STREAM_TO_UINT8(report_format,p);
+                STREAM_TO_UINT8(num_records, p);
+                p = (uint8_t *)(p_params->p_param_buf + 4);
+                BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_READ_RESULTS status=%d,len=%d,rec=%d",
+                    status, len-4, num_records);
+
+                if (0 == num_records)
+                {
+                    btm_ble_batchscan_deq_rep_data(report_format, &ref_value, &num_records,
+                                                   &p_data, &data_len);
+                    if (NULL != ble_batchscan_cb.p_scan_rep_cback)
+                        ble_batchscan_cb.p_scan_rep_cback(ref_value,report_format, num_records,
+                                                          data_len, p_data, status);
+                }
+                else
+                {
+                    if ((len-4) > 0)
+                    {
+                        btm_ble_batchscan_enq_rep_data(report_format, num_records, p, len-4);
+                        /* More records could be in the buffer and needs to be pulled out */
+                        btm_ble_read_batchscan_reports(report_format, ref_value);
+                    }
+                }
+            }
+            break;
+        }
+
+        default:
+            break;
+    }
+
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_set_storage_config
+**
+** Description      This function writes the storage configuration in controller
+**
+** Parameters       batch_scan_full_max -Max storage space (in %) allocated to full scanning
+**                  batch_scan_trunc_max -Max storage space (in %) allocated to truncated scanning
+**                  batch_scan_notify_threshold - Setup notification level based on total space
+**
+*******************************************************************************/
+void btm_ble_set_storage_config(uint8_t batch_scan_full_max, uint8_t batch_scan_trunc_max,
+                                       uint8_t batch_scan_notify_threshold)
+{
+    uint8_t param[BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN], *pp;
+
+    pp = param;
+    memset(param, 0, BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN);
+
+    UINT8_TO_STREAM (pp, BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM);
+    UINT8_TO_STREAM (pp, batch_scan_full_max);
+    UINT8_TO_STREAM (pp, batch_scan_trunc_max);
+    UINT8_TO_STREAM (pp, batch_scan_notify_threshold);
+
+    BTM_VendorSpecificCommand(HCI_BLE_BATCH_SCAN_OCF,
+                BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN, param,
+                btm_ble_batchscan_vsc_cmpl_cback);
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_set_batchscan_param
+**
+** Description      This function writes the batch scan params in controller
+**
+** Parameters       scan_mode -Batch scan mode
+**                  scan_interval - Scan interval
+**                  scan_window  - Scan window
+**                  discard_rule -Discard rules
+**                  addr_type - Address type
+**
+*******************************************************************************/
+void btm_ble_set_batchscan_param(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
+                     uint32_t scan_interval, uint32_t scan_window, tBLE_ADDR_TYPE addr_type,
+                     tBTM_BLE_DISCARD_RULE discard_rule)
+{
+    uint8_t scan_param[BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN], *pp_scan;
+
+    pp_scan = scan_param;
+    memset(scan_param, 0, BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN);
+
+    // Override param and decide addr_type based on own addr type
+    // TODO: Remove upper layer parameter?
+    addr_type = btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type;
+
+    UINT8_TO_STREAM (pp_scan, BTM_BLE_BATCH_SCAN_SET_PARAMS);
+    UINT8_TO_STREAM (pp_scan, scan_mode);
+    UINT32_TO_STREAM (pp_scan, scan_window);
+    UINT32_TO_STREAM (pp_scan, scan_interval);
+    UINT8_TO_STREAM (pp_scan, addr_type);
+    UINT8_TO_STREAM (pp_scan, discard_rule);
+
+    BTM_VendorSpecificCommand(HCI_BLE_BATCH_SCAN_OCF,
+            BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN,
+            scan_param, btm_ble_batchscan_vsc_cmpl_cback);
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_enable_disable_batchscan
+**
+** Description      This function enables the customer specific feature in controller
+**
+** Parameters       enable_disable: true - enable, false - disable
+**
+*******************************************************************************/
+void btm_ble_enable_disable_batchscan(bool    should_enable)
+{
+    uint8_t shld_enable = 0x01;
+    uint8_t enable_param[BTM_BLE_BATCH_SCAN_ENB_DISB_LEN], *pp_enable;
+
+    if (!should_enable)
+        shld_enable = 0x00;
+
+    if (should_enable)
+    {
+        pp_enable = enable_param;
+        memset(enable_param, 0, BTM_BLE_BATCH_SCAN_ENB_DISB_LEN);
+
+        UINT8_TO_STREAM (pp_enable, BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE);
+        UINT8_TO_STREAM (pp_enable, shld_enable);
+
+        BTM_VendorSpecificCommand(HCI_BLE_BATCH_SCAN_OCF,
+                 BTM_BLE_BATCH_SCAN_ENB_DISB_LEN, enable_param,
+                 btm_ble_batchscan_vsc_cmpl_cback);
+    }
+    else
+        btm_ble_set_batchscan_param(BTM_BLE_BATCH_SCAN_MODE_DISABLE,
+                   ble_batchscan_cb.scan_interval, ble_batchscan_cb.scan_window,
+                   ble_batchscan_cb.addr_type, ble_batchscan_cb.discard_rule);
+
+    if (should_enable)
+        ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLE_CALLED;
+    else
+        ble_batchscan_cb.cur_state = BTM_BLE_SCAN_DISABLE_CALLED;
+}
+
+/*******************************************************************************
+**
+** Function         BTM_BleSetStorageConfig
+**
+** Description      This function is called to write storage config params.
+**
+** Parameters:      batch_scan_full_max - Max storage space (in %) allocated to full style
+**                  batch_scan_trunc_max - Max storage space (in %) allocated to trunc style
+**                  batch_scan_notify_threshold - Setup notification level based on total space
+**                  p_setup_cback - Setup callback pointer
+**                  p_thres_cback - Threshold callback pointer
+**                  p_rep_cback - Reports callback pointer
+**                  ref_value - Reference value
+**
+** Returns          tBTM_STATUS
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleSetStorageConfig(uint8_t batch_scan_full_max, uint8_t batch_scan_trunc_max,
+                                        uint8_t batch_scan_notify_threshold,
+                                        tBTM_BLE_SCAN_SETUP_CBACK *p_setup_cback,
+                                        tBTM_BLE_SCAN_THRESHOLD_CBACK *p_thres_cback,
+                                        tBTM_BLE_SCAN_REP_CBACK* p_rep_cback,
+                                        tBTM_BLE_REF_VALUE ref_value)
+{
+    tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+
+    BTM_TRACE_EVENT (" BTM_BleSetStorageConfig: %d, %d, %d, %d, %d",
+        ble_batchscan_cb.cur_state, ref_value, batch_scan_full_max, batch_scan_trunc_max,
+        batch_scan_notify_threshold);
+
+    if (!controller_get_interface()->supports_ble())
+        return BTM_ILLEGAL_VALUE;
+
+    BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+    if (0 == cmn_ble_vsc_cb.tot_scan_results_strg)
+    {
+        BTM_TRACE_ERROR("Controller does not support batch scan");
+        return BTM_ERR_PROCESSING;
+    }
+
+    ble_batchscan_cb.p_setup_cback = p_setup_cback;
+    ble_batchscan_cb.p_thres_cback = p_thres_cback;
+    ble_batchscan_cb.p_scan_rep_cback = p_rep_cback;
+    ble_batchscan_cb.ref_value = ref_value;
+
+    if (batch_scan_full_max > BTM_BLE_ADV_SCAN_FULL_MAX ||
+        batch_scan_trunc_max > BTM_BLE_ADV_SCAN_TRUNC_MAX ||
+        batch_scan_notify_threshold > BTM_BLE_ADV_SCAN_THR_MAX)
+    {
+        BTM_TRACE_ERROR("Illegal set storage config params");
+        return BTM_ILLEGAL_VALUE;
+    }
+
+     if (BTM_BLE_SCAN_INVALID_STATE == ble_batchscan_cb.cur_state ||
+         BTM_BLE_SCAN_DISABLED_STATE == ble_batchscan_cb.cur_state ||
+         BTM_BLE_SCAN_DISABLE_CALLED == ble_batchscan_cb.cur_state)
+    {
+        btm_ble_enable_disable_batchscan(true);
+        ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLE_CALLED;
+        btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE,
+                                    BTM_BLE_SCAN_ENABLE_CALLED, 0, ref_value);
+    }
+
+    btm_ble_set_storage_config(batch_scan_full_max, batch_scan_trunc_max,
+                               batch_scan_notify_threshold);
+            /* The user needs to be provided scan config storage event */
+     btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM, ble_batchscan_cb.cur_state,
+                                   BTM_BLE_BATCH_SCAN_CFG_STRG_EVT, ref_value);
+
+    return BTM_CMD_STARTED;
+}
+
+
+/*******************************************************************************
+**
+** Function         BTM_BleEnableBatchScan
+**
+** Description      This function is called to configure and enable batch scanning
+**
+** Parameters:      scan_mode -Batch scan mode
+**                  scan_interval - Scan interval value
+**                  scan_window - Scan window value
+**                  discard_rule - Data discard rule
+**                  ref_value - Reference value
+**
+** Returns          tBTM_STATUS
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleEnableBatchScan(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
+            uint32_t scan_interval, uint32_t scan_window, tBLE_ADDR_TYPE addr_type,
+            tBTM_BLE_DISCARD_RULE discard_rule, tBTM_BLE_REF_VALUE ref_value)
+{
+    tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+    BTM_TRACE_EVENT (" BTM_BleEnableBatchScan: %d, %d, %d, %d, %d, %d",
+        scan_mode, scan_interval, scan_window, addr_type, discard_rule, ref_value);
+
+    if (!controller_get_interface()->supports_ble())
+        return BTM_ILLEGAL_VALUE;
+
+    BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+    if (0 == cmn_ble_vsc_cb.tot_scan_results_strg)
+    {
+        BTM_TRACE_ERROR("Controller does not support batch scan");
+        return BTM_ERR_PROCESSING;
+    }
+
+    BTM_TRACE_DEBUG("BTM_BleEnableBatchScan: %d, %x, %x, %d, %d", scan_mode, scan_interval,
+                                        scan_window, discard_rule, ble_batchscan_cb.cur_state);
+
+    /* Only 16 bits will be used for scan interval and scan window as per agreement with Google */
+    /* So the standard LE range would suffice for scan interval and scan window */
+    if ((BTM_BLE_ISVALID_PARAM(scan_interval, BTM_BLE_SCAN_INT_MIN, BTM_BLE_SCAN_INT_MAX) ||
+        BTM_BLE_ISVALID_PARAM(scan_window, BTM_BLE_SCAN_WIN_MIN, BTM_BLE_SCAN_WIN_MAX))
+        && (BTM_BLE_BATCH_SCAN_MODE_PASS == scan_mode || BTM_BLE_BATCH_SCAN_MODE_ACTI == scan_mode
+        || BTM_BLE_BATCH_SCAN_MODE_PASS_ACTI == scan_mode)
+        && (BTM_BLE_DISCARD_OLD_ITEMS == discard_rule ||
+        BTM_BLE_DISCARD_LOWER_RSSI_ITEMS == discard_rule))
+    {
+        if (BTM_BLE_SCAN_INVALID_STATE == ble_batchscan_cb.cur_state ||
+            BTM_BLE_SCAN_DISABLED_STATE == ble_batchscan_cb.cur_state ||
+            BTM_BLE_SCAN_DISABLE_CALLED == ble_batchscan_cb.cur_state)
+        {
+            btm_ble_enable_disable_batchscan(true);
+            btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE,
+                                       BTM_BLE_SCAN_ENABLE_CALLED, 0, ref_value);
+        }
+
+        ble_batchscan_cb.scan_mode = scan_mode;
+        ble_batchscan_cb.scan_interval = scan_interval;
+        ble_batchscan_cb.scan_window = scan_window;
+        ble_batchscan_cb.addr_type = addr_type;
+        ble_batchscan_cb.discard_rule = discard_rule;
+        /* This command starts batch scanning, if enabled */
+        btm_ble_set_batchscan_param(scan_mode, scan_interval, scan_window, addr_type,
+                    discard_rule);
+
+        /* The user needs to be provided scan enable event */
+        btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_SET_PARAMS, ble_batchscan_cb.cur_state,
+                                   BTM_BLE_BATCH_SCAN_ENABLE_EVT, ref_value);
+    }
+    else
+    {
+        BTM_TRACE_ERROR("Illegal enable scan params");
+        return BTM_ILLEGAL_VALUE;
+    }
+    return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function         BTM_BleDisableBatchScan
+**
+** Description      This function is called to disable batch scanning
+**
+** Parameters:      ref_value - Reference value
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleDisableBatchScan(tBTM_BLE_REF_VALUE ref_value)
+{
+    tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+    BTM_TRACE_EVENT (" BTM_BleDisableBatchScan");
+
+    if (!controller_get_interface()->supports_ble())
+        return BTM_ILLEGAL_VALUE;
+
+    BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+    if (0 == cmn_ble_vsc_cb.tot_scan_results_strg)
+    {
+        BTM_TRACE_ERROR("Controller does not support batch scan");
+        return BTM_ERR_PROCESSING;
+    }
+
+    btm_ble_enable_disable_batchscan(false);
+    /* The user needs to be provided scan disable event */
+    btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_SET_PARAMS,
+                               BTM_BLE_SCAN_DISABLE_CALLED, BTM_BLE_BATCH_SCAN_DISABLE_EVT,
+                               ref_value);
+    return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function         BTM_BleReadScanReports
+**
+** Description      This function is called to start reading batch scan reports
+**
+** Parameters:      scan_mode - Batch scan mode
+**                  ref_value - Reference value
+**
+** Returns          tBTM_STATUS
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleReadScanReports(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
+                                             tBTM_BLE_REF_VALUE ref_value)
+{
+    tBTM_STATUS     status = BTM_NO_RESOURCES;
+    tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+    uint8_t read_scan_mode = 0;
+
+    BTM_TRACE_EVENT (" BTM_BleReadScanReports; %d, %d", scan_mode, ref_value);
+
+    if (!controller_get_interface()->supports_ble())
+        return BTM_ILLEGAL_VALUE;
+
+    BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+    if (0 == cmn_ble_vsc_cb.tot_scan_results_strg)
+    {
+        BTM_TRACE_ERROR("Controller does not support batch scan");
+        return BTM_ERR_PROCESSING;
+    }
+
+    /*  Check if the requested scan mode has already been setup by the user */
+    read_scan_mode = ble_batchscan_cb.scan_mode & BTM_BLE_BATCH_SCAN_MODE_ACTI;
+    if (0 == read_scan_mode)
+        read_scan_mode = ble_batchscan_cb.scan_mode & BTM_BLE_BATCH_SCAN_MODE_PASS;
+
+    /* Check only for modes, as scan reports can be called after disabling batch scan */
+    if (read_scan_mode > 0 && (BTM_BLE_BATCH_SCAN_MODE_PASS == scan_mode ||
+        BTM_BLE_BATCH_SCAN_MODE_ACTI == scan_mode))
+    {
+        status = btm_ble_batchscan_enq_rep_q(scan_mode, ref_value);
+        if (BTM_SUCCESS == status)
+        {
+            btm_ble_read_batchscan_reports(scan_mode, ref_value);
+            status = BTM_CMD_STARTED;
+        }
+    }
+    else
+    {
+        BTM_TRACE_ERROR("Illegal read scan params: %d, %d, %d", read_scan_mode, scan_mode,
+            ble_batchscan_cb.cur_state);
+        return BTM_ILLEGAL_VALUE;
+    }
+    return status;
+}
+
+
+/*******************************************************************************
+**
+** Function         BTM_BleTrackAdvertiser
+**
+** Description      This function is called to setup the callback for tracking advertisers
+**
+** Parameters:      p_track_cback - Tracking callback pointer
+**                  ref_value - Reference value
+**
+** Returns          tBTM_STATUS
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleTrackAdvertiser(tBTM_BLE_TRACK_ADV_CBACK *p_track_cback,
+                                        tBTM_BLE_REF_VALUE ref_value)
+{
+    tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+    BTM_TRACE_EVENT (" BTM_BleTrackAdvertiser");
+    if (!controller_get_interface()->supports_ble())
+        return BTM_ILLEGAL_VALUE;
+
+    BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+    if (0 == cmn_ble_vsc_cb.tot_scan_results_strg)
+    {
+        BTM_TRACE_ERROR("Controller does not support scan storage");
+        return BTM_ERR_PROCESSING;
+    }
+
+    ble_advtrack_cb.p_track_cback = p_track_cback;
+    ble_advtrack_cb.ref_value = ref_value;
+    return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_batchscan_init
+**
+** Description      This function initialize the batch scan control block.
+**
+** Parameters       None
+**
+** Returns          status
+**
+*******************************************************************************/
+void btm_ble_batchscan_init(void)
+{
+    BTM_TRACE_EVENT (" btm_ble_batchscan_init");
+    memset(&ble_batchscan_cb, 0, sizeof(tBTM_BLE_BATCH_SCAN_CB));
+    memset(&ble_advtrack_cb, 0, sizeof(tBTM_BLE_ADV_TRACK_CB));
+    BTM_RegisterForVSEvents(btm_ble_batchscan_filter_track_adv_vse_cback, true);
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_batchscan_cleanup
+**
+** Description      This function cleans the batch scan control block.
+**
+** Parameters       None
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_batchscan_cleanup(void)
+{
+    int index = 0;
+    BTM_TRACE_EVENT (" btm_ble_batchscan_cleanup");
+
+    for (index = 0; index < BTM_BLE_BATCH_REP_MAIN_Q_SIZE; index++)
+        osi_free_and_reset((void **)&ble_batchscan_cb.main_rep_q.p_data[index]);
+
+    memset(&ble_batchscan_cb, 0, sizeof(tBTM_BLE_BATCH_SCAN_CB));
+    memset(&ble_advtrack_cb, 0, sizeof(tBTM_BLE_ADV_TRACK_CB));
+}
+
+#endif
diff --git a/bt/stack/btm/btm_ble_bgconn.cc b/bt/stack/btm/btm_ble_bgconn.cc
new file mode 100644
index 0000000..7e573c4
--- /dev/null
+++ b/bt/stack/btm/btm_ble_bgconn.cc
@@ -0,0 +1,741 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 functions for BLE whitelist operation.
+ *
+ ******************************************************************************/
+
+#include <assert.h>
+#include <string.h>
+#include <unordered_map>
+
+#include "device/include/controller.h"
+#include "osi/include/allocator.h"
+#include "osi/include/osi.h"
+#include "bt_types.h"
+#include "btu.h"
+#include "btm_int.h"
+#include "l2c_int.h"
+#include "hcimsgs.h"
+#include "bt_utils.h"
+
+#ifndef BTM_BLE_SCAN_PARAM_TOUT
+#define BTM_BLE_SCAN_PARAM_TOUT      50    /* 50 seconds */
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+
+static void btm_suspend_wl_activity(tBTM_BLE_WL_STATE wl_state);
+static void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state);
+
+// Unfortunately (for now?) we have to maintain a copy of the device whitelist
+// on the host to determine if a device is pending to be connected or not. This
+// controls whether the host should keep trying to scan for whitelisted
+// peripherals or not.
+// TODO: Move all of this to controller/le/background_list or similar?
+typedef struct background_connection_t {
+  bt_bdaddr_t address;
+} background_connection_t;
+
+struct KeyEqual {
+  bool operator()(const bt_bdaddr_t *x, const bt_bdaddr_t *y) const
+  {
+    return bdaddr_equals(x, y);
+  }
+};
+
+static std::unordered_map<bt_bdaddr_t *, background_connection_t *,
+                          std::hash<bt_bdaddr_t *>, KeyEqual>
+    background_connections;
+
+static void background_connection_add(bt_bdaddr_t *address) {
+  assert(address);
+
+  auto map_iter = background_connections.find(address);
+  if (map_iter == background_connections.end()) {
+    background_connection_t *connection =
+        (background_connection_t *)osi_calloc(sizeof(background_connection_t));
+    connection->address = *address;
+    background_connections[&(connection->address)] = connection;
+  }
+}
+
+static void background_connection_remove(bt_bdaddr_t *address) {
+  background_connections.erase(address);
+}
+
+static void background_connections_clear() {
+  background_connections.clear();
+}
+
+static bool background_connections_pending() {
+  for (const auto &map_el : background_connections) {
+    background_connection_t *connection = map_el.second;
+    const bool connected = BTM_IsAclConnectionUp(connection->address.address, BT_TRANSPORT_LE);
+    if (!connected) {
+      return true;
+    }
+  }
+  return false;
+}
+
+/*******************************************************************************
+**
+** Function         btm_update_scanner_filter_policy
+**
+** Description      This function updates the filter policy of scanner
+*******************************************************************************/
+void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy)
+{
+    tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var;
+
+    uint32_t scan_interval = !p_inq->scan_interval ? BTM_BLE_GAP_DISC_SCAN_INT : p_inq->scan_interval;
+    uint32_t scan_window = !p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window;
+
+    BTM_TRACE_EVENT ("%s", __func__);
+
+    p_inq->sfp = scan_policy;
+    p_inq->scan_type = p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE ? BTM_BLE_SCAN_MODE_ACTI : p_inq->scan_type;
+
+    if (btm_cb.cmn_ble_vsc_cb.extended_scan_support == 0)
+    {
+        btsnd_hcic_ble_set_scan_params(p_inq->scan_type, (uint16_t)scan_interval,
+                                       (uint16_t)scan_window,
+                                       btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+                                       scan_policy);
+    }
+    else
+    {
+        btm_ble_send_extended_scan_params(p_inq->scan_type, scan_interval, scan_window,
+                                          btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+                                          scan_policy);
+    }
+}
+/*******************************************************************************
+**
+** Function         btm_add_dev_to_controller
+**
+** Description      This function load the device into controller white list
+*******************************************************************************/
+bool    btm_add_dev_to_controller (bool    to_add, BD_ADDR bd_addr)
+{
+    tBTM_SEC_DEV_REC    *p_dev_rec = btm_find_dev (bd_addr);
+    bool                started = false;
+    BD_ADDR             dummy_bda = {0};
+
+    if (p_dev_rec != NULL && p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) {
+        if (to_add) {
+            if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC || !BTM_BLE_IS_RESOLVE_BDA(bd_addr)) {
+                btsnd_hcic_ble_add_white_list(p_dev_rec->ble.ble_addr_type, bd_addr);
+                started = true;
+                p_dev_rec->ble.in_controller_list |= BTM_WHITE_LIST_BIT;
+            } else if (memcmp(p_dev_rec->ble.static_addr, bd_addr, BD_ADDR_LEN) != 0 &&
+                memcmp(p_dev_rec->ble.static_addr, dummy_bda, BD_ADDR_LEN) != 0) {
+                btsnd_hcic_ble_add_white_list(p_dev_rec->ble.static_addr_type,
+                                              p_dev_rec->ble.static_addr);
+                started = true;
+                p_dev_rec->ble.in_controller_list |= BTM_WHITE_LIST_BIT;
+            }
+        } else {
+            if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC || !BTM_BLE_IS_RESOLVE_BDA(bd_addr)) {
+                btsnd_hcic_ble_remove_from_white_list(p_dev_rec->ble.ble_addr_type, bd_addr);
+                started = true;
+            }
+
+            if (memcmp(p_dev_rec->ble.static_addr, dummy_bda, BD_ADDR_LEN) != 0 &&
+                memcmp(p_dev_rec->ble.static_addr, bd_addr, BD_ADDR_LEN) != 0) {
+                btsnd_hcic_ble_remove_from_white_list(p_dev_rec->ble.static_addr_type, p_dev_rec->ble.static_addr);
+                started = true;
+            }
+
+            p_dev_rec->ble.in_controller_list &= ~BTM_WHITE_LIST_BIT;
+        }
+    } else {
+        /* not a known device, i.e. attempt to connect to device never seen before */
+        uint8_t addr_type = BTM_IS_PUBLIC_BDA(bd_addr) ? BLE_ADDR_PUBLIC : BLE_ADDR_RANDOM;
+        btsnd_hcic_ble_remove_from_white_list(addr_type, bd_addr);
+        started = true;
+        if (to_add)
+            btsnd_hcic_ble_add_white_list(addr_type, bd_addr);
+    }
+
+    return started;
+
+}
+/*******************************************************************************
+**
+** Function         btm_execute_wl_dev_operation
+**
+** Description      execute the pending whitelist device operation(loading or removing)
+*******************************************************************************/
+bool    btm_execute_wl_dev_operation(void)
+{
+    tBTM_BLE_WL_OP *p_dev_op = btm_cb.ble_ctr_cb.wl_op_q;
+    uint8_t i = 0;
+    bool    rt = true;
+
+    for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM && rt; i ++, p_dev_op ++)
+    {
+        if (p_dev_op->in_use)
+        {
+            rt = btm_add_dev_to_controller(p_dev_op->to_add, p_dev_op->bd_addr);
+            memset(p_dev_op, 0, sizeof(tBTM_BLE_WL_OP));
+        }
+        else
+            break;
+    }
+    return rt;
+}
+/*******************************************************************************
+**
+** Function         btm_enq_wl_dev_operation
+**
+** Description      enqueue the pending whitelist device operation(loading or removing).
+*******************************************************************************/
+void btm_enq_wl_dev_operation(bool    to_add, BD_ADDR bd_addr)
+{
+    tBTM_BLE_WL_OP *p_dev_op = btm_cb.ble_ctr_cb.wl_op_q;
+    uint8_t i = 0;
+
+    for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM; i ++, p_dev_op ++)
+    {
+        if (p_dev_op->in_use && !memcmp(p_dev_op->bd_addr, bd_addr, BD_ADDR_LEN))
+        {
+            p_dev_op->to_add = to_add;
+            return;
+        }
+        else if (!p_dev_op->in_use)
+            break;
+    }
+    if (i != BTM_BLE_MAX_BG_CONN_DEV_NUM)
+    {
+        p_dev_op->in_use = true;
+        p_dev_op->to_add = to_add;
+        memcpy(p_dev_op->bd_addr, bd_addr, BD_ADDR_LEN);
+    }
+    else
+    {
+        BTM_TRACE_ERROR("max pending WL operation reached, discard");
+    }
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         btm_update_dev_to_white_list
+**
+** Description      This function adds or removes a device into/from
+**                  the white list.
+**
+*******************************************************************************/
+bool    btm_update_dev_to_white_list(bool    to_add, BD_ADDR bd_addr)
+{
+    tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+
+    if (to_add && p_cb->white_list_avail_size == 0)
+    {
+        BTM_TRACE_ERROR("%s Whitelist full, unable to add device", __func__);
+        return false;
+    }
+
+    if (to_add)
+        background_connection_add((bt_bdaddr_t*)bd_addr);
+    else
+        background_connection_remove((bt_bdaddr_t*)bd_addr);
+
+    btm_suspend_wl_activity(p_cb->wl_state);
+    btm_enq_wl_dev_operation(to_add, bd_addr);
+    btm_resume_wl_activity(p_cb->wl_state);
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_clear_white_list
+**
+** Description      This function clears the white list.
+**
+*******************************************************************************/
+void btm_ble_clear_white_list (void)
+{
+    BTM_TRACE_EVENT ("btm_ble_clear_white_list");
+    btsnd_hcic_ble_clear_white_list();
+    background_connections_clear();
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_clear_white_list_complete
+**
+** Description      Indicates white list cleared.
+**
+*******************************************************************************/
+void btm_ble_clear_white_list_complete(uint8_t *p_data,
+                                       UNUSED_ATTR uint16_t evt_len)
+{
+    tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+    uint8_t     status;
+
+    BTM_TRACE_EVENT ("btm_ble_clear_white_list_complete");
+    STREAM_TO_UINT8  (status, p_data);
+
+    if (status == HCI_SUCCESS)
+        p_cb->white_list_avail_size = controller_get_interface()->get_ble_white_list_size();
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_white_list_init
+**
+** Description      Initialize white list size
+**
+*******************************************************************************/
+void btm_ble_white_list_init(uint8_t white_list_size)
+{
+    BTM_TRACE_DEBUG("%s white_list_size = %d", __func__, white_list_size);
+    btm_cb.ble_ctr_cb.white_list_avail_size = white_list_size;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_add_2_white_list_complete
+**
+** Description      White list element added
+**
+*******************************************************************************/
+void btm_ble_add_2_white_list_complete(uint8_t status)
+{
+    BTM_TRACE_EVENT("%s status=%d", __func__, status);
+    if (status == HCI_SUCCESS)
+        --btm_cb.ble_ctr_cb.white_list_avail_size;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_remove_from_white_list_complete
+**
+** Description      White list element removal complete
+**
+*******************************************************************************/
+void btm_ble_remove_from_white_list_complete(uint8_t *p,
+                                             UNUSED_ATTR uint16_t evt_len)
+{
+    BTM_TRACE_EVENT ("%s status=%d", __func__, *p);
+    if (*p == HCI_SUCCESS)
+        ++btm_cb.ble_ctr_cb.white_list_avail_size;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_start_auto_conn
+**
+** Description      This function is to start/stop auto connection procedure.
+**
+** Parameters       start: true to start; false to stop.
+**
+** Returns          void
+**
+*******************************************************************************/
+bool    btm_ble_start_auto_conn(bool    start)
+{
+    tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+    BD_ADDR dummy_bda = {0};
+    bool    exec = true;
+    uint16_t scan_int;
+    uint16_t scan_win;
+    uint8_t own_addr_type = p_cb->addr_mgnt_cb.own_addr_type;
+    uint8_t peer_addr_type = BLE_ADDR_PUBLIC;
+
+    if (start)
+    {
+        if (p_cb->conn_state == BLE_CONN_IDLE && background_connections_pending()
+            && btm_ble_topology_check(BTM_BLE_STATE_INIT))
+        {
+            p_cb->wl_state  |= BTM_BLE_WL_INIT;
+
+            btm_execute_wl_dev_operation();
+
+#if (BLE_PRIVACY_SPT == TRUE)
+            btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_INIT);
+#endif
+            scan_int = (p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF) ?
+                                          BTM_BLE_SCAN_SLOW_INT_1 : p_cb->scan_int;
+            scan_win = (p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF) ?
+                                          BTM_BLE_SCAN_SLOW_WIN_1 : p_cb->scan_win;
+
+#if (BLE_PRIVACY_SPT == TRUE)
+            if (btm_cb.ble_ctr_cb.rl_state != BTM_BLE_RL_IDLE
+                    && controller_get_interface()->supports_ble_privacy())
+            {
+                own_addr_type |= BLE_ADDR_TYPE_ID_BIT;
+                peer_addr_type |= BLE_ADDR_TYPE_ID_BIT;
+            }
+#endif
+
+            btsnd_hcic_ble_create_ll_conn(scan_int,  /* uint16_t scan_int      */
+                                          scan_win,    /* uint16_t scan_win      */
+                                          0x01,                   /* uint8_t white_list     */
+                                          peer_addr_type,        /* uint8_t addr_type_peer */
+                                          dummy_bda,              /* BD_ADDR bda_peer     */
+                                          own_addr_type,          /* uint8_t addr_type_own */
+                                          BTM_BLE_CONN_INT_MIN_DEF,   /* uint16_t conn_int_min  */
+                                          BTM_BLE_CONN_INT_MAX_DEF,   /* uint16_t conn_int_max  */
+                                          BTM_BLE_CONN_SLAVE_LATENCY_DEF,  /* uint16_t conn_latency  */
+                                          BTM_BLE_CONN_TIMEOUT_DEF,        /* uint16_t conn_timeout  */
+                                          0,                       /* uint16_t min_len       */
+                                          0);                      /* uint16_t max_len       */
+            btm_ble_set_conn_st (BLE_BG_CONN);
+        }
+        else
+        {
+            exec = false;
+        }
+    }
+    else
+    {
+        if (p_cb->conn_state == BLE_BG_CONN)
+        {
+            btsnd_hcic_ble_create_conn_cancel();
+            btm_ble_set_conn_st (BLE_CONN_CANCEL);
+            p_cb->wl_state &= ~BTM_BLE_WL_INIT;
+        }
+        else
+        {
+            BTM_TRACE_DEBUG("conn_st = %d, not in auto conn state, cannot stop", p_cb->conn_state);
+            exec = false;
+        }
+    }
+    return exec;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_start_select_conn
+**
+** Description      This function is to start/stop selective connection procedure.
+**
+** Parameters       start: true to start; false to stop.
+**                  p_select_cback: callback function to return application
+**                                  selection.
+**
+** Returns          bool   : selective connectino procedure is started.
+**
+*******************************************************************************/
+bool    btm_ble_start_select_conn(bool    start, tBTM_BLE_SEL_CBACK *p_select_cback)
+{
+    tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+    uint32_t scan_int = p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF ? BTM_BLE_SCAN_FAST_INT : p_cb->scan_int;
+    uint32_t scan_win = p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF ? BTM_BLE_SCAN_FAST_WIN : p_cb->scan_win;
+
+    BTM_TRACE_EVENT ("%s", __func__);
+
+    if (start)
+    {
+        if (!BTM_BLE_IS_SCAN_ACTIVE(p_cb->scan_activity))
+        {
+            if (p_select_cback != NULL)
+                btm_cb.ble_ctr_cb.p_select_cback = p_select_cback;
+
+            btm_execute_wl_dev_operation();
+
+            btm_update_scanner_filter_policy(SP_ADV_WL);
+            btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_PASS;
+
+            /* Process advertising packets only from devices in the white list */
+            if (btm_cb.cmn_ble_vsc_cb.extended_scan_support == 0)
+            {
+                /* use passive scan by default */
+                btsnd_hcic_ble_set_scan_params(BTM_BLE_SCAN_MODE_PASS,
+                                               scan_int,
+                                               scan_win,
+                                               p_cb->addr_mgnt_cb.own_addr_type,
+                                               SP_ADV_WL);
+            }
+            else
+            {
+                btm_ble_send_extended_scan_params(BTM_BLE_SCAN_MODE_PASS,
+                                                  scan_int,
+                                                  scan_win,
+                                                  p_cb->addr_mgnt_cb.own_addr_type,
+                                                  SP_ADV_WL);
+            }
+
+            if (!btm_ble_topology_check(BTM_BLE_STATE_PASSIVE_SCAN))
+            {
+                BTM_TRACE_ERROR("peripheral device cannot initiate passive scan for a selective connection");
+                return false;
+            }
+            else if (background_connections_pending())
+            {
+#if (BLE_PRIVACY_SPT == TRUE)
+                btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN);
+#endif
+                btsnd_hcic_ble_set_scan_enable(true, true); /* duplicate filtering enabled */
+
+                 /* mark up inquiry status flag */
+                 p_cb->scan_activity |= BTM_LE_SELECT_CONN_ACTIVE;
+                 p_cb->wl_state |= BTM_BLE_WL_SCAN;
+            }
+        }
+        else
+        {
+            BTM_TRACE_ERROR("scan active, can not start selective connection procedure");
+            return false;
+        }
+    }
+    else /* disable selective connection mode */
+    {
+        p_cb->scan_activity &= ~BTM_LE_SELECT_CONN_ACTIVE;
+        p_cb->p_select_cback = NULL;
+        p_cb->wl_state &= ~BTM_BLE_WL_SCAN;
+
+        /* stop scanning */
+        if (!BTM_BLE_IS_SCAN_ACTIVE(p_cb->scan_activity))
+            btm_ble_stop_scan(); /* duplicate filtering enabled */
+    }
+    return true;
+}
+/*******************************************************************************
+**
+** Function         btm_ble_initiate_select_conn
+**
+** Description      This function is to start/stop selective connection procedure.
+**
+** Parameters       start: true to start; false to stop.
+**                  p_select_cback: callback function to return application
+**                                  selection.
+**
+** Returns          bool   : selective connectino procedure is started.
+**
+*******************************************************************************/
+void btm_ble_initiate_select_conn(BD_ADDR bda)
+{
+    BTM_TRACE_EVENT ("btm_ble_initiate_select_conn");
+
+    /* use direct connection procedure to initiate connection */
+    if (!L2CA_ConnectFixedChnl(L2CAP_ATT_CID, bda))
+    {
+        BTM_TRACE_ERROR("btm_ble_initiate_select_conn failed");
+    }
+}
+/*******************************************************************************
+**
+** Function         btm_ble_suspend_bg_conn
+**
+** Description      This function is to suspend an active background connection
+**                  procedure.
+**
+** Parameters       none.
+**
+** Returns          none.
+**
+*******************************************************************************/
+bool    btm_ble_suspend_bg_conn(void)
+{
+    BTM_TRACE_EVENT ("%s", __func__);
+
+    if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_AUTO)
+        return btm_ble_start_auto_conn(false);
+    else if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_SELECTIVE)
+        return btm_ble_start_select_conn(false, NULL);
+
+    return false;
+}
+/*******************************************************************************
+**
+** Function         btm_suspend_wl_activity
+**
+** Description      This function is to suspend white list related activity
+**
+** Returns          none.
+**
+*******************************************************************************/
+static void btm_suspend_wl_activity(tBTM_BLE_WL_STATE wl_state)
+{
+    if (wl_state & BTM_BLE_WL_INIT)
+    {
+        btm_ble_start_auto_conn(false);
+    }
+    if (wl_state & BTM_BLE_WL_SCAN)
+    {
+        btm_ble_start_select_conn(false, NULL);
+    }
+    if (wl_state & BTM_BLE_WL_ADV)
+    {
+        btm_ble_stop_adv();
+    }
+
+}
+/*******************************************************************************
+**
+** Function         btm_resume_wl_activity
+**
+** Description      This function is to resume white list related activity
+**
+** Returns          none.
+**
+*******************************************************************************/
+static void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state)
+{
+    btm_ble_resume_bg_conn();
+
+    if (wl_state & BTM_BLE_WL_ADV)
+    {
+       btm_ble_start_adv();
+    }
+
+}
+/*******************************************************************************
+**
+** Function         btm_ble_resume_bg_conn
+**
+** Description      This function is to resume a background auto connection
+**                  procedure.
+**
+** Parameters       none.
+**
+** Returns          none.
+**
+*******************************************************************************/
+bool    btm_ble_resume_bg_conn(void)
+{
+    tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+    bool    ret = false;
+
+    if (p_cb->bg_conn_type != BTM_BLE_CONN_NONE)
+    {
+        if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO)
+            ret = btm_ble_start_auto_conn(true);
+
+        if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE)
+            ret = btm_ble_start_select_conn(true, btm_cb.ble_ctr_cb.p_select_cback);
+    }
+
+    return ret;
+}
+/*******************************************************************************
+**
+** Function         btm_ble_get_conn_st
+**
+** Description      This function get BLE connection state
+**
+** Returns          connection state
+**
+*******************************************************************************/
+tBTM_BLE_CONN_ST btm_ble_get_conn_st(void)
+{
+    return btm_cb.ble_ctr_cb.conn_state;
+}
+/*******************************************************************************
+**
+** Function         btm_ble_set_conn_st
+**
+** Description      This function set BLE connection state
+**
+** Returns          None.
+**
+*******************************************************************************/
+void btm_ble_set_conn_st(tBTM_BLE_CONN_ST new_st)
+{
+    btm_cb.ble_ctr_cb.conn_state = new_st;
+
+    if (new_st == BLE_BG_CONN || new_st == BLE_DIR_CONN)
+        btm_ble_set_topology_mask(BTM_BLE_STATE_INIT_BIT);
+    else
+        btm_ble_clear_topology_mask(BTM_BLE_STATE_INIT_BIT);
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_enqueue_direct_conn_req
+**
+** Description      This function enqueue the direct connection request
+**
+** Returns          None.
+**
+*******************************************************************************/
+void btm_ble_enqueue_direct_conn_req(void *p_param)
+{
+    tBTM_BLE_CONN_REQ *p = (tBTM_BLE_CONN_REQ *)osi_malloc(sizeof(tBTM_BLE_CONN_REQ));
+
+    p->p_param = p_param;
+
+    fixed_queue_enqueue(btm_cb.ble_ctr_cb.conn_pending_q, p);
+}
+/*******************************************************************************
+**
+** Function         btm_ble_dequeue_direct_conn_req
+**
+** Description      This function dequeues the direct connection request
+**
+** Returns          None.
+**
+*******************************************************************************/
+void btm_ble_dequeue_direct_conn_req(BD_ADDR rem_bda)
+{
+    if (fixed_queue_is_empty(btm_cb.ble_ctr_cb.conn_pending_q))
+        return;
+
+    list_t *list = fixed_queue_get_list(btm_cb.ble_ctr_cb.conn_pending_q);
+    for (const list_node_t *node = list_begin(list); node != list_end(list);
+            node = list_next(node)) {
+        tBTM_BLE_CONN_REQ *p_req = (tBTM_BLE_CONN_REQ *)list_node(node);
+        tL2C_LCB *p_lcb = (tL2C_LCB *)p_req->p_param;
+        if ((p_lcb == NULL) || (!p_lcb->in_use)) {
+            continue;
+        }
+        //If BD address matches
+        if (!memcmp (rem_bda, p_lcb->remote_bd_addr, BD_ADDR_LEN)) {
+            fixed_queue_try_remove_from_queue(btm_cb.ble_ctr_cb.conn_pending_q, p_req);
+            l2cu_release_lcb((tL2C_LCB *)p_req->p_param);
+            osi_free((void *)p_req);
+            break;
+        }
+    }
+}
+/*******************************************************************************
+**
+** Function         btm_send_pending_direct_conn
+**
+** Description      This function send the pending direct connection request in queue
+**
+** Returns          true if started, false otherwise
+**
+*******************************************************************************/
+bool    btm_send_pending_direct_conn(void)
+{
+    tBTM_BLE_CONN_REQ *p_req;
+    bool        rt = false;
+
+    p_req = (tBTM_BLE_CONN_REQ*)fixed_queue_try_dequeue(btm_cb.ble_ctr_cb.conn_pending_q);
+    if (p_req != NULL) {
+        tL2C_LCB *p_lcb = (tL2C_LCB *)(p_req->p_param);
+        /* Ignore entries that might have been released while queued. */
+        if (p_lcb->in_use)
+            rt = l2cble_init_direct_conn(p_lcb);
+        osi_free(p_req);
+    }
+
+    return rt;
+}
+
+#endif
+
+
diff --git a/bt/stack/btm/btm_ble_cont_energy.cc b/bt/stack/btm/btm_ble_cont_energy.cc
new file mode 100644
index 0000000..99bbf1f
--- /dev/null
+++ b/bt/stack/btm/btm_ble_cont_energy.cc
@@ -0,0 +1,105 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014  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.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_target.h"
+
+#if (BLE_INCLUDED == TRUE)
+#include "bt_types.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_int.h"
+#include "bt_utils.h"
+#include "hcidefs.h"
+#include "btm_ble_api.h"
+
+tBTM_BLE_ENERGY_INFO_CB ble_energy_info_cb;
+
+/*******************************************************************************
+**
+** Function         btm_ble_cont_energy_cmpl_cback
+**
+** Description      Controller VSC complete callback
+**
+** Parameters
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_cont_energy_cmpl_cback (tBTM_VSC_CMPL *p_params)
+{
+    uint8_t *p = p_params->p_param_buf;
+    uint16_t len = p_params->param_len;
+    uint8_t status = 0;
+    uint32_t total_tx_time = 0, total_rx_time = 0, total_idle_time = 0, total_energy_used = 0;
+
+    if (len < 17)
+    {
+        BTM_TRACE_ERROR("wrong length for btm_ble_cont_energy_cmpl_cback");
+        return;
+    }
+
+    STREAM_TO_UINT8(status, p);
+    STREAM_TO_UINT32(total_tx_time, p);
+    STREAM_TO_UINT32(total_rx_time, p);
+    STREAM_TO_UINT32(total_idle_time, p);
+    STREAM_TO_UINT32(total_energy_used, p);
+
+    BTM_TRACE_DEBUG("energy_info status=%d,tx_t=%ld, rx_t=%ld, ener_used=%ld, idle_t=%ld",
+        status, total_tx_time, total_rx_time, total_energy_used, total_idle_time);
+
+    if (NULL != ble_energy_info_cb.p_ener_cback)
+        ble_energy_info_cb.p_ener_cback(total_tx_time, total_rx_time, total_idle_time,
+                          total_energy_used, status);
+
+    return;
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+
+    BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+    BTM_TRACE_EVENT("BTM_BleGetEnergyInfo");
+
+    if (0 == cmn_ble_vsc_cb.energy_support)
+    {
+        BTM_TRACE_ERROR("Controller does not support get energy info");
+        return BTM_ERR_PROCESSING;
+    }
+
+    ble_energy_info_cb.p_ener_cback = p_ener_cback;
+    BTM_VendorSpecificCommand(HCI_BLE_ENERGY_INFO_OCF, 0, NULL,
+                              btm_ble_cont_energy_cmpl_cback);
+    return BTM_CMD_STARTED;
+}
+
+#endif
+
diff --git a/bt/stack/btm/btm_ble_gap.cc b/bt/stack/btm/btm_ble_gap.cc
new file mode 100644
index 0000000..37837be
--- /dev/null
+++ b/bt/stack/btm/btm_ble_gap.cc
@@ -0,0 +1,2945 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2008-2014 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 functions for BLE GAP.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btm_ble"
+
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_ble_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "gap_api.h"
+#include "hcimsgs.h"
+#include "osi/include/osi.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+#include "btm_ble_int.h"
+#include "gatt_int.h"
+#include "gattdefs.h"
+#include "l2c_int.h"
+#include "osi/include/log.h"
+
+#define BTM_BLE_NAME_SHORT                  0x01
+#define BTM_BLE_NAME_CMPL                   0x02
+
+#define BTM_BLE_FILTER_TARGET_UNKNOWN       0xff
+#define BTM_BLE_POLICY_UNKNOWN              0xff
+
+#define BTM_EXT_BLE_RMT_NAME_TIMEOUT_MS     (30 * 1000)
+#define MIN_ADV_LENGTH                       2
+#define BTM_VSC_CHIP_CAPABILITY_RSP_LEN_L_RELEASE 9
+
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+#if (BLE_VND_INCLUDED == TRUE)
+static tBTM_BLE_CTRL_FEATURES_CBACK    *p_ctrl_le_feature_rd_cmpl_cback = NULL;
+#endif
+
+/*******************************************************************************
+**  Local functions
+*******************************************************************************/
+static void btm_ble_update_adv_flag(uint8_t flag);
+static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, uint8_t addr_type, uint8_t evt_type, uint8_t *p);
+static uint8_t btm_set_conn_mode_adv_init_addr(tBTM_BLE_INQ_CB *p_cb,
+                                     BD_ADDR_PTR p_peer_addr_ptr,
+                                     tBLE_ADDR_TYPE *p_peer_addr_type,
+                                     tBLE_ADDR_TYPE *p_own_addr_type);
+static void btm_ble_stop_observe(void);
+static void btm_ble_fast_adv_timer_timeout(void *data);
+static void btm_ble_start_slow_adv(void);
+static void btm_ble_inquiry_timer_gap_limited_discovery_timeout(void *data);
+static void btm_ble_inquiry_timer_timeout(void *data);
+static void btm_ble_observer_timer_timeout(void *data);
+
+
+#define BTM_BLE_INQ_RESULT          0x01
+#define BTM_BLE_OBS_RESULT          0x02
+#define BTM_BLE_SEL_CONN_RESULT     0x04
+
+/* LE states combo bit to check */
+const uint8_t btm_le_state_combo_tbl[BTM_BLE_STATE_MAX][BTM_BLE_STATE_MAX][2] =
+{
+    {/* single state support */
+        {HCI_SUPP_LE_STATES_CONN_ADV_MASK, HCI_SUPP_LE_STATES_CONN_ADV_OFF},  /* conn_adv */
+        {HCI_SUPP_LE_STATES_INIT_MASK, HCI_SUPP_LE_STATES_INIT_OFF}, /* init */
+        {HCI_SUPP_LE_STATES_INIT_MASK, HCI_SUPP_LE_STATES_INIT_OFF}, /* master */
+        {HCI_SUPP_LE_STATES_SLAVE_MASK, HCI_SUPP_LE_STATES_SLAVE_OFF}, /* slave */
+        {0, 0},                   /* todo: lo du dir adv, not covered ? */
+        {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_OFF}, /* hi duty dir adv */
+        {HCI_SUPP_LE_STATES_NON_CONN_ADV_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_OFF},  /* non connectable adv */
+        {HCI_SUPP_LE_STATES_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_PASS_SCAN_OFF},   /*  passive scan */
+        {HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_ACTIVE_SCAN_OFF},  /*   active scan */
+        {HCI_SUPP_LE_STATES_SCAN_ADV_MASK, HCI_SUPP_LE_STATESSCAN_ADV_OFF}   /* scanable adv */
+    },
+    {    /* conn_adv =0 */
+        {0, 0},                                                                           /* conn_adv */
+        {HCI_SUPP_LE_STATES_CONN_ADV_INIT_MASK, HCI_SUPP_LE_STATES_CONN_ADV_INIT_OFF},      /* init: 32 */
+        {HCI_SUPP_LE_STATES_CONN_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_CONN_ADV_MASTER_OFF},  /* master: 35 */
+        {HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_OFF}, /* slave: 38,*/
+        {0, 0},                                                                           /* lo du dir adv */
+        {0, 0},                                                                            /* hi duty dir adv */
+        {0, 0},  /* non connectable adv */
+        {HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_OFF},   /*  passive scan */
+        {HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_OFF},  /*   active scan */
+        {0, 0}   /* scanable adv */
+    },
+    {   /* init */
+        {HCI_SUPP_LE_STATES_CONN_ADV_INIT_MASK, HCI_SUPP_LE_STATES_CONN_ADV_INIT_OFF},      /* conn_adv: 32 */
+        {0, 0},                                                                             /* init */
+        {HCI_SUPP_LE_STATES_INIT_MASTER_MASK, HCI_SUPP_LE_STATES_INIT_MASTER_OFF},          /* master 28 */
+        {HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_MASK, HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_OFF}, /* slave 41 */
+        {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_MASK, HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_OFF} ,/* lo du dir adv 34 */
+        {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_OFF},     /* hi duty dir adv 33 */
+        {HCI_SUPP_LE_STATES_NON_CONN_INIT_MASK, HCI_SUPP_LE_STATES_NON_CONN_INIT_OFF},  /*  non connectable adv */
+        {HCI_SUPP_LE_STATES_PASS_SCAN_INIT_MASK, HCI_SUPP_LE_STATES_PASS_SCAN_INIT_OFF},   /* passive scan */
+        {HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_MASK, HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_OFF},  /*  active scan */
+        {HCI_SUPP_LE_STATES_SCAN_ADV_INIT_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_INIT_OFF}   /* scanable adv */
+
+    },
+    {   /* master */
+        {HCI_SUPP_LE_STATES_CONN_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_CONN_ADV_MASTER_OFF},  /* conn_adv: 35 */
+        {HCI_SUPP_LE_STATES_INIT_MASTER_MASK, HCI_SUPP_LE_STATES_INIT_MASTER_OFF},          /* init 28 */
+        {HCI_SUPP_LE_STATES_INIT_MASTER_MASK, HCI_SUPP_LE_STATES_INIT_MASTER_OFF},          /* master 28 */
+        {HCI_SUPP_LE_STATES_CONN_ADV_INIT_MASK, HCI_SUPP_LE_STATES_CONN_ADV_INIT_OFF},      /* slave: 32 */
+        {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_OFF},  /* lo duty cycle adv 37 */
+        {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_OFF},   /* hi duty cycle adv 36 */
+        {HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_OFF},  /*  non connectable adv */
+        {HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_MASK, HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_OFF},   /*  passive scan */
+        {HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_MASK, HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_OFF},  /*   active scan */
+        {HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_OFF}   /*  scanable adv */
+
+    },
+    { /* slave */
+        {HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_OFF}, /* conn_adv: 38,*/
+        {HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_MASK, HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_OFF}, /* init 41 */
+        {HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_MASK, HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_OFF}, /* master 41 */
+        {HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_OFF},        /* slave: 38,*/
+        {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_OFF},  /* lo duty cycle adv 40 */
+        {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_OFF},   /* hi duty cycle adv 39 */
+        {HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_OFF},  /* non connectable adv */
+        {HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_MASK, HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_OFF},   /* passive scan */
+        {HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_MASK, HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_OFF},  /*  active scan */
+        {HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_OFF}   /* scanable adv */
+
+    },
+    { /* lo duty cycle adv */
+        {0, 0}, /* conn_adv: 38,*/
+        {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_MASK, HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_OFF} ,/* init 34 */
+        {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_OFF}, /* master 37 */
+        {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_OFF}, /* slave: 40 */
+        {0, 0},  /* lo duty cycle adv 40 */
+        {0, 0},   /* hi duty cycle adv 39 */
+        {0, 0},  /*  non connectable adv */
+        {0, 0},   /* TODO: passive scan, not covered? */
+        {0, 0},  /* TODO:  active scan, not covered? */
+        {0, 0}   /*  scanable adv */
+    },
+    { /* hi duty cycle adv */
+        {0, 0}, /* conn_adv: 38,*/
+        {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_OFF}, /* init 33 */
+        {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_OFF}, /* master 36 */
+        {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_OFF},   /* slave: 39*/
+        {0, 0},  /* lo duty cycle adv 40 */
+        {0, 0},   /* hi duty cycle adv 39 */
+        {0, 0},  /* non connectable adv */
+        {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_OFF},   /* passive scan */
+        {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_OFF},  /* active scan */
+        {0, 0}   /* scanable adv */
+    },
+    { /* non connectable adv */
+        {0, 0}, /* conn_adv: */
+        {HCI_SUPP_LE_STATES_NON_CONN_INIT_MASK, HCI_SUPP_LE_STATES_NON_CONN_INIT_OFF}, /* init  */
+        {HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_OFF}, /* master  */
+        {HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_OFF},   /* slave: */
+        {0, 0},  /* lo duty cycle adv */
+        {0, 0},   /* hi duty cycle adv */
+        {0, 0},  /* non connectable adv */
+        {HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_OFF},   /* passive scan */
+        {HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_OFF},  /*  active scan */
+        {0, 0}   /* scanable adv */
+    },
+    { /* passive scan */
+        {HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_OFF}, /* conn_adv: */
+        {HCI_SUPP_LE_STATES_PASS_SCAN_INIT_MASK, HCI_SUPP_LE_STATES_PASS_SCAN_INIT_OFF}, /* init  */
+        {HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_MASK, HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_OFF}, /* master  */
+        {HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_MASK, HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_OFF},   /* slave: */
+        {0, 0},  /* lo duty cycle adv */
+        {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_OFF},   /* hi duty cycle adv */
+        {HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_OFF},  /*  non connectable adv */
+        {0, 0},   /* passive scan */
+        {0, 0},  /* active scan */
+         {HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_OFF}   /* scanable adv */
+    },
+    { /* active scan */
+        {HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_OFF}, /* conn_adv: */
+        {HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_MASK, HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_OFF}, /* init  */
+        {HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_MASK, HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_OFF}, /* master  */
+        {HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_MASK, HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_OFF},   /* slave: */
+        {0, 0},  /* lo duty cycle adv */
+        {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_OFF},   /* hi duty cycle adv */
+        {HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_OFF},  /*  non connectable adv */
+        {0, 0},   /* TODO: passive scan */
+        {0, 0},  /* TODO:  active scan */
+        {HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_OFF}   /*  scanable adv */
+    },
+    { /* scanable adv */
+        {0, 0}, /* conn_adv: */
+        {HCI_SUPP_LE_STATES_SCAN_ADV_INIT_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_INIT_OFF}, /* init  */
+        {HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_OFF}, /* master  */
+        {HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_OFF},   /* slave: */
+        {0, 0},  /* lo duty cycle adv */
+        {0, 0},   /* hi duty cycle adv */
+        {0, 0},  /* non connectable adv */
+        {HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_OFF},   /*  passive scan */
+        {HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_MASK, HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_OFF},  /*  active scan */
+        {0, 0}   /* scanable adv */
+    }
+
+};
+/* check LE combo state supported */
+#define BTM_LE_STATES_SUPPORTED(x, y, z)      ((x)[(z)] & (y))
+
+/*******************************************************************************
+**
+** 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)
+{
+    tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+    tBLE_ADDR_TYPE   init_addr_type = BLE_ADDR_PUBLIC;
+    BD_ADDR          p_addr_ptr= {0};
+    uint8_t          adv_mode = p_cb->adv_mode;
+
+    BTM_TRACE_EVENT ("BTM_BleUpdateAdvFilterPolicy");
+
+    if (!controller_get_interface()->supports_ble())
+        return;
+
+    if (p_cb->afp != adv_policy)
+    {
+        p_cb->afp = adv_policy;
+
+        /* if adv active, stop and restart */
+        btm_ble_stop_adv ();
+
+        if (p_cb->connectable_mode & BTM_BLE_CONNECTABLE)
+            p_cb->evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &init_addr_type,
+                                                              &p_cb->adv_addr_type);
+
+        btsnd_hcic_ble_write_adv_params((uint16_t)(p_cb->adv_interval_min ? p_cb->adv_interval_min :
+                                        BTM_BLE_GAP_ADV_SLOW_INT),
+                                        (uint16_t)(p_cb->adv_interval_max ? p_cb->adv_interval_max :
+                                        BTM_BLE_GAP_ADV_SLOW_INT),
+                                        p_cb->evt_type,
+                                        p_cb->adv_addr_type,
+                                        init_addr_type,
+                                        p_addr_ptr,
+                                        p_cb->adv_chnl_map,
+                                        p_cb->afp);
+
+        if (adv_mode == BTM_BLE_ADV_ENABLE)
+            btm_ble_start_adv ();
+
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_send_extended_scan_params
+**
+** Description      This function sends out the extended scan parameters command to the controller
+**
+** Parameters       scan_type - Scan type
+**                  scan_int - Scan interval
+**                  scan_win - Scan window
+**                  addr_type_own - Own address type
+**                  scan_filter_policy - Scan filter policy
+**
+*******************************************************************************/
+void btm_ble_send_extended_scan_params(uint8_t scan_type, uint32_t scan_int,
+                                          uint32_t scan_win, uint8_t addr_type_own,
+                                          uint8_t scan_filter_policy)
+{
+    uint8_t scan_param[HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_SCAN_PARAM];
+    uint8_t *pp_scan = scan_param;
+
+    memset(scan_param, 0, HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_SCAN_PARAM);
+
+    UINT8_TO_STREAM(pp_scan, scan_type);
+    UINT32_TO_STREAM(pp_scan, scan_int);
+    UINT32_TO_STREAM(pp_scan, scan_win);
+    UINT8_TO_STREAM(pp_scan, addr_type_own);
+    UINT8_TO_STREAM(pp_scan, scan_filter_policy);
+
+    BTM_TRACE_DEBUG("%s, %d, %d", __func__, scan_int, scan_win);
+    BTM_VendorSpecificCommand(HCI_BLE_EXTENDED_SCAN_PARAMS_OCF,
+         HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_SCAN_PARAM, scan_param, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_BleObserve
+**
+** Description      This procedure keep the device listening for advertising
+**                  events from a broadcast device.
+**
+** Parameters       start: start or stop observe.
+**                  white_list: use white list in observer mode or not.
+**
+** Returns          void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleObserve(bool    start, uint8_t duration,
+                           tBTM_INQ_RESULTS_CB *p_results_cb, tBTM_CMPL_CB *p_cmpl_cb)
+{
+    tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var;
+    tBTM_STATUS status = BTM_WRONG_MODE;
+
+    uint32_t scan_interval = !p_inq->scan_interval ? BTM_BLE_GAP_DISC_SCAN_INT : p_inq->scan_interval;
+    uint32_t scan_window = !p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window;
+
+    BTM_TRACE_EVENT ("%s : scan_type:%d, %d, %d", __func__, btm_cb.btm_inq_vars.scan_type,
+                      p_inq->scan_interval, p_inq->scan_window);
+
+    if (!controller_get_interface()->supports_ble())
+        return BTM_ILLEGAL_VALUE;
+
+    if (start)
+    {
+        /* shared inquiry database, do not allow observe if any inquiry is active */
+        if (BTM_BLE_IS_OBS_ACTIVE(btm_cb.ble_ctr_cb.scan_activity))
+        {
+            BTM_TRACE_ERROR("%s Observe Already Active", __func__);
+            return status;
+        }
+
+        btm_cb.ble_ctr_cb.p_obs_results_cb = p_results_cb;
+        btm_cb.ble_ctr_cb.p_obs_cmpl_cb = p_cmpl_cb;
+        status = BTM_CMD_STARTED;
+
+        /* scan is not started */
+        if (!BTM_BLE_IS_SCAN_ACTIVE(btm_cb.ble_ctr_cb.scan_activity))
+        {
+            /* allow config of scan type */
+            p_inq->scan_type = (p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE) ?
+                                                    BTM_BLE_SCAN_MODE_ACTI: p_inq->scan_type;
+            /* assume observe always not using white list */
+            #if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == true)
+                /* enable resolving list */
+                btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN);
+            #endif
+
+            if (btm_cb.cmn_ble_vsc_cb.extended_scan_support == 0)
+            {
+                btsnd_hcic_ble_set_scan_params(p_inq->scan_type, (uint16_t)scan_interval,
+                                               (uint16_t)scan_window,
+                                               btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+                                               BTM_BLE_DEFAULT_SFP);
+            }
+            else
+            {
+                btm_ble_send_extended_scan_params(p_inq->scan_type, scan_interval, scan_window,
+                                                  btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+                                                  BTM_BLE_DEFAULT_SFP);
+            }
+
+            p_inq->scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE;
+            status = btm_ble_start_scan();
+        }
+
+        if (status == BTM_CMD_STARTED)
+        {
+            btm_cb.ble_ctr_cb.scan_activity |= BTM_LE_OBSERVE_ACTIVE;
+            if (duration != 0) {
+                /* start observer timer */
+                period_ms_t duration_ms = duration * 1000;
+                alarm_set_on_queue(btm_cb.ble_ctr_cb.observer_timer,
+                                   duration_ms, btm_ble_observer_timer_timeout,
+                                   NULL, btu_general_alarm_queue);
+            }
+        }
+    }
+    else if (BTM_BLE_IS_OBS_ACTIVE(btm_cb.ble_ctr_cb.scan_activity))
+    {
+        status = BTM_CMD_STARTED;
+        btm_ble_stop_observe();
+    }
+    else
+    {
+        BTM_TRACE_ERROR("%s Observe not active", __func__);
+    }
+
+    return status;
+
+}
+
+#if (BLE_VND_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function         btm_vsc_brcm_features_complete
+**
+** Description      Command Complete callback for HCI_BLE_VENDOR_CAP_OCF
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_ble_vendor_capability_vsc_cmpl_cback (tBTM_VSC_CMPL *p_vcs_cplt_params)
+{
+    uint8_t status = 0xFF;
+    uint8_t *p;
+
+    BTM_TRACE_DEBUG("%s", __func__);
+
+    /* Check status of command complete event */
+    if ((p_vcs_cplt_params->opcode == HCI_BLE_VENDOR_CAP_OCF) &&
+        (p_vcs_cplt_params->param_len > 0))
+    {
+        p = p_vcs_cplt_params->p_param_buf;
+        STREAM_TO_UINT8(status, p);
+    }
+
+    if (status == HCI_SUCCESS)
+    {
+        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);
+        STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.max_irk_list_sz, p);
+        STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.filter_support, p);
+        STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.max_filter, p);
+        STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.energy_support, p);
+
+        if (p_vcs_cplt_params->param_len > BTM_VSC_CHIP_CAPABILITY_RSP_LEN_L_RELEASE)
+        {
+            STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.version_supported, p);
+        }
+        else
+        {
+            btm_cb.cmn_ble_vsc_cb.version_supported = BTM_VSC_CHIP_CAPABILITY_L_VERSION;
+        }
+
+        if (btm_cb.cmn_ble_vsc_cb.version_supported >= BTM_VSC_CHIP_CAPABILITY_M_VERSION)
+        {
+            STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.total_trackable_advertisers, p);
+            STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.extended_scan_support, p);
+            STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.debug_logging_supported, p);
+        }
+        btm_cb.cmn_ble_vsc_cb.values_read = true;
+    }
+
+    BTM_TRACE_DEBUG("%s: stat=%d, irk=%d, ADV ins:%d, rpa=%d, ener=%d, ext_scan=%d",
+         __func__, status, btm_cb.cmn_ble_vsc_cb.max_irk_list_sz,
+         btm_cb.cmn_ble_vsc_cb.adv_inst_max, btm_cb.cmn_ble_vsc_cb.rpa_offloading,
+         btm_cb.cmn_ble_vsc_cb.energy_support, btm_cb.cmn_ble_vsc_cb.extended_scan_support);
+
+    if (BTM_BleMaxMultiAdvInstanceCount() > 0)
+        btm_ble_multi_adv_init();
+
+    if (btm_cb.cmn_ble_vsc_cb.max_filter > 0)
+        btm_ble_adv_filter_init();
+
+#if (BLE_PRIVACY_SPT == TRUE)
+    /* VS capability included and non-4.2 device */
+    if (btm_cb.cmn_ble_vsc_cb.max_irk_list_sz > 0 &&
+        controller_get_interface()->get_ble_resolving_list_max_size() == 0)
+        btm_ble_resolving_list_init(btm_cb.cmn_ble_vsc_cb.max_irk_list_sz);
+#endif  /* (BLE_PRIVACY_SPT == TRUE) */
+
+    if (btm_cb.cmn_ble_vsc_cb.tot_scan_results_strg > 0)
+        btm_ble_batchscan_init();
+
+    if (p_ctrl_le_feature_rd_cmpl_cback != NULL)
+        p_ctrl_le_feature_rd_cmpl_cback(status);
+}
+#endif  /* (BLE_VND_INCLUDED == TRUE) */
+
+/*******************************************************************************
+**
+** Function         BTM_BleGetVendorCapabilities
+**
+** Description      This function reads local LE features
+**
+** Parameters       p_cmn_vsc_cb : Locala LE capability structure
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void BTM_BleGetVendorCapabilities(tBTM_BLE_VSC_CB *p_cmn_vsc_cb)
+{
+    BTM_TRACE_DEBUG("BTM_BleGetVendorCapabilities");
+
+    if (NULL != p_cmn_vsc_cb)
+    {
+        *p_cmn_vsc_cb = btm_cb.cmn_ble_vsc_cb;
+    }
+}
+
+/******************************************************************************
+**
+** Function         BTM_BleReadControllerFeatures
+**
+** Description      Reads BLE specific controller features
+**
+** Parameters:      tBTM_BLE_CTRL_FEATURES_CBACK : Callback to notify when features are read
+**
+** Returns          void
+**
+*******************************************************************************/
+#if (BLE_VND_INCLUDED == TRUE)
+extern void BTM_BleReadControllerFeatures(tBTM_BLE_CTRL_FEATURES_CBACK  *p_vsc_cback)
+{
+    if (true == btm_cb.cmn_ble_vsc_cb.values_read)
+        return;
+
+    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_ble_vendor_capability_vsc_cmpl_cback);
+}
+#else
+extern void BTM_BleReadControllerFeatures(UNUSED_ATTR tBTM_BLE_CTRL_FEATURES_CBACK  *p_vsc_cback)
+{
+}
+#endif
+
+/*******************************************************************************
+**
+** 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)
+{
+
+#if (BLE_PRIVACY_SPT == TRUE)
+    btm_cb.ble_ctr_cb.mixed_mode = mixed_on;
+
+    /* TODO: send VSC to enabled mixed mode */
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         BTM_BleConfigPrivacy
+**
+** Description      This function is called to enable or disable the privacy in
+**                   LE channel of the local device.
+**
+** Parameters       privacy_mode:  privacy mode on or off.
+**
+** Returns          bool    privacy mode set success; otherwise failed.
+**
+*******************************************************************************/
+bool    BTM_BleConfigPrivacy(bool    privacy_mode)
+{
+#if (BLE_PRIVACY_SPT == TRUE)
+    tBTM_BLE_CB  *p_cb = &btm_cb.ble_ctr_cb;
+
+    BTM_TRACE_EVENT ("%s", __func__);
+
+    /* if LE is not supported, return error */
+    if (!controller_get_interface()->supports_ble())
+        return false;
+
+    uint8_t addr_resolution = 0;
+    if(!privacy_mode)/* if privacy disabled, always use public address */
+    {
+        p_cb->addr_mgnt_cb.own_addr_type = BLE_ADDR_PUBLIC;
+        p_cb->privacy_mode = BTM_PRIVACY_NONE;
+    }
+    else /* privacy is turned on*/
+    {
+        /* always set host random address, used when privacy 1.1 or priavcy 1.2 is disabled */
+        p_cb->addr_mgnt_cb.own_addr_type = BLE_ADDR_RANDOM;
+        btm_gen_resolvable_private_addr((void *)btm_gen_resolve_paddr_low);
+
+        /* 4.2 controller only allow privacy 1.2 or mixed mode, resolvable private address in controller */
+        if (controller_get_interface()->supports_ble_privacy())
+        {
+            addr_resolution = 1;
+            /* check vendor specific capability */
+            p_cb->privacy_mode = btm_cb.ble_ctr_cb.mixed_mode ? BTM_PRIVACY_MIXED : BTM_PRIVACY_1_2;
+        }
+        else  /* 4.1/4.0 controller */
+            p_cb->privacy_mode = BTM_PRIVACY_1_1;
+    }
+
+    GAP_BleAttrDBUpdate (GATT_UUID_GAP_CENTRAL_ADDR_RESOL, (tGAP_BLE_ATTR_VALUE *)&addr_resolution);
+
+    return true;
+#else
+    return false;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function          BTM_BleMaxMultiAdvInstanceCount
+**
+** Description        Returns max number of multi adv instances supported by controller
+**
+** Returns          Max multi adv instance count
+**
+*******************************************************************************/
+extern uint8_t BTM_BleMaxMultiAdvInstanceCount(void)
+{
+    return btm_cb.cmn_ble_vsc_cb.adv_inst_max < BTM_BLE_MULTI_ADV_MAX ?
+        btm_cb.cmn_ble_vsc_cb.adv_inst_max : BTM_BLE_MULTI_ADV_MAX;
+}
+
+#if (BLE_PRIVACY_SPT == TRUE)
+/*******************************************************************************
+**
+** Function         btm_ble_resolve_random_addr_on_adv
+**
+** Description      resolve random address complete callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_ble_resolve_random_addr_on_adv(void * p_rec, void *p)
+{
+    tBTM_SEC_DEV_REC    *match_rec = (tBTM_SEC_DEV_REC *) p_rec;
+    uint8_t     addr_type = BLE_ADDR_RANDOM;
+    BD_ADDR     bda;
+    uint8_t     *pp = (uint8_t *)p + 1;
+    uint8_t         evt_type;
+
+    BTM_TRACE_EVENT ("btm_ble_resolve_random_addr_on_adv ");
+
+    STREAM_TO_UINT8    (evt_type, pp);
+    STREAM_TO_UINT8    (addr_type, pp);
+    STREAM_TO_BDADDR   (bda, pp);
+
+    if (match_rec)
+    {
+        BTM_TRACE_DEBUG("Random match");
+        match_rec->ble.active_addr_type = BTM_BLE_ADDR_RRA;
+        memcpy(match_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN);
+
+        if (btm_ble_init_pseudo_addr(match_rec, bda))
+        {
+            memcpy(bda, match_rec->bd_addr, BD_ADDR_LEN);
+        } else {
+            // Assign the original address to be the current report address
+            memcpy(bda, match_rec->ble.pseudo_addr, BD_ADDR_LEN);
+        }
+    }
+
+    btm_ble_process_adv_pkt_cont(bda, addr_type, evt_type, pp);
+
+    return;
+}
+#endif
+
+/*******************************************************************************
+**
+** 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)
+{
+#if (BLE_PRIVACY_SPT == TRUE)
+    return (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE);
+#else
+    return false;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         BTM_BleSetBgConnType
+**
+** Description      This function is called to set BLE connectable mode for a
+**                  peripheral device.
+**
+** Parameters       bg_conn_type: it can be auto connection, or selective connection.
+**                  p_select_cback: callback function when selective connection procedure
+**                              is being used.
+**
+** Returns          void
+**
+*******************************************************************************/
+bool    BTM_BleSetBgConnType(tBTM_BLE_CONN_TYPE   bg_conn_type,
+                             tBTM_BLE_SEL_CBACK   *p_select_cback)
+{
+    bool    started = true;
+
+    BTM_TRACE_EVENT ("BTM_BleSetBgConnType ");
+    if (!controller_get_interface()->supports_ble())
+        return false;
+
+    if (btm_cb.ble_ctr_cb.bg_conn_type != bg_conn_type)
+    {
+        switch (bg_conn_type)
+        {
+            case BTM_BLE_CONN_AUTO:
+                btm_ble_start_auto_conn(true);
+                break;
+
+            case BTM_BLE_CONN_SELECTIVE:
+                if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_AUTO)
+                {
+                    btm_ble_start_auto_conn(false);
+                }
+                btm_ble_start_select_conn(true, p_select_cback);
+                break;
+
+            case BTM_BLE_CONN_NONE:
+                if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_AUTO)
+                {
+                    btm_ble_start_auto_conn(false);
+                }
+                else if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_SELECTIVE)
+                {
+                    btm_ble_start_select_conn(false, NULL);
+                }
+                started = true;
+                break;
+
+            default:
+                BTM_TRACE_ERROR("invalid bg connection type : %d ", bg_conn_type);
+                started = false;
+                break;
+        }
+
+        if (started)
+            btm_cb.ble_ctr_cb.bg_conn_type = bg_conn_type;
+    }
+    return started;
+}
+
+/*******************************************************************************
+**
+** Function         BTM_BleClearBgConnDev
+**
+** Description      This function is called to clear the whitelist,
+**                  end any pending whitelist connections,
+*                   and reset the local bg device list.
+**
+** Parameters       void
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTM_BleClearBgConnDev(void)
+{
+    btm_ble_start_auto_conn(false);
+    btm_ble_clear_white_list();
+    gatt_reset_bgdev_list();
+}
+
+/*******************************************************************************
+**
+** Function         BTM_BleUpdateBgConnDev
+**
+** Description      This function is called to add or remove a device into/from
+**                  background connection procedure. The background connection
+*                   procedure is decided by the background connection type, it can be
+*                   auto connection, or selective connection.
+**
+** Parameters       add_remove: true to add; false to remove.
+**                  remote_bda: device address to add/remove.
+**
+** Returns          void
+**
+*******************************************************************************/
+bool    BTM_BleUpdateBgConnDev(bool    add_remove, BD_ADDR   remote_bda)
+{
+    BTM_TRACE_EVENT("%s() add=%d", __func__, add_remove);
+    return btm_update_dev_to_white_list(add_remove, remote_bda);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_BleSetConnectableMode
+**
+** Description      This function is called to set BLE connectable mode for a
+**                  peripheral device.
+**
+** Parameters       conn_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)
+{
+    tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+    BTM_TRACE_EVENT ("%s connectable_mode = %d ", __func__, connectable_mode);
+    if (!controller_get_interface()->supports_ble())
+        return BTM_ILLEGAL_VALUE;
+
+    p_cb->directed_conn = connectable_mode;
+    return btm_ble_set_connectability( p_cb->connectable_mode);
+}
+
+#if (BLE_PRIVACY_SPT == TRUE)
+static bool is_resolving_list_bit_set(void *data, void *context)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = static_cast<tBTM_SEC_DEV_REC *>(data);
+
+    if ((p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) != 0)
+        return false;
+
+    return true;
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         btm_set_conn_mode_adv_init_addr
+**
+** Description      set initator address type and local address type based on adv
+**                  mode.
+**
+**
+*******************************************************************************/
+static uint8_t btm_set_conn_mode_adv_init_addr(tBTM_BLE_INQ_CB *p_cb,
+                                     BD_ADDR_PTR p_peer_addr_ptr,
+                                     tBLE_ADDR_TYPE *p_peer_addr_type,
+                                     tBLE_ADDR_TYPE *p_own_addr_type)
+{
+    uint8_t evt_type;
+#if (BLE_PRIVACY_SPT == TRUE)
+    tBTM_SEC_DEV_REC *p_dev_rec;
+#endif
+
+    evt_type = (p_cb->connectable_mode == BTM_BLE_NON_CONNECTABLE) ? \
+                ((p_cb->scan_rsp) ? BTM_BLE_DISCOVER_EVT : BTM_BLE_NON_CONNECT_EVT )\
+                : BTM_BLE_CONNECT_EVT;
+
+    if (evt_type == BTM_BLE_CONNECT_EVT)
+    {
+        evt_type = p_cb->directed_conn;
+
+        if ( p_cb->directed_conn == BTM_BLE_CONNECT_DIR_EVT ||
+             p_cb->directed_conn == BTM_BLE_CONNECT_LO_DUTY_DIR_EVT)
+        {
+
+#if (BLE_PRIVACY_SPT == TRUE)
+            /* for privacy 1.2, convert peer address as static, own address set as ID addr */
+            if (btm_cb.ble_ctr_cb.privacy_mode ==  BTM_PRIVACY_1_2 ||
+                btm_cb.ble_ctr_cb.privacy_mode ==  BTM_PRIVACY_MIXED)
+            {
+                /* only do so for bonded device */
+                 if ((p_dev_rec = btm_find_or_alloc_dev (p_cb->direct_bda.bda)) != NULL &&
+                      p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT)
+                 {
+                     btm_ble_enable_resolving_list(BTM_BLE_RL_ADV);
+                     memcpy(p_peer_addr_ptr, p_dev_rec->ble.static_addr, BD_ADDR_LEN);
+                     *p_peer_addr_type = p_dev_rec->ble.static_addr_type;
+                     *p_own_addr_type = BLE_ADDR_RANDOM_ID;
+                     return evt_type;
+                 }
+                 /* otherwise fall though as normal directed adv */
+                 else
+                 {
+                    btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, true);
+                 }
+            }
+#endif
+            /* direct adv mode does not have privacy, if privacy is not enabled  */
+            *p_peer_addr_type  = p_cb->direct_bda.type;
+            memcpy(p_peer_addr_ptr, p_cb->direct_bda.bda, BD_ADDR_LEN);
+            return evt_type;
+        }
+    }
+
+    /* undirect adv mode or non-connectable mode*/
+#if (BLE_PRIVACY_SPT == TRUE)
+    /* when privacy 1.2 privacy only mode is used, or mixed mode */
+    if ((btm_cb.ble_ctr_cb.privacy_mode ==  BTM_PRIVACY_1_2 && p_cb->afp != AP_SCAN_CONN_ALL) ||
+        btm_cb.ble_ctr_cb.privacy_mode ==  BTM_PRIVACY_MIXED)
+    {
+        list_node_t *n = list_foreach(btm_cb.sec_dev_rec, is_resolving_list_bit_set, NULL);
+        if (n) {
+            /* if enhanced privacy is required, set Identity address and matching IRK peer */
+            tBTM_SEC_DEV_REC *p_dev_rec =
+                static_cast<tBTM_SEC_DEV_REC *>(list_node(n));
+            memcpy(p_peer_addr_ptr, p_dev_rec->ble.static_addr, BD_ADDR_LEN);
+            *p_peer_addr_type = p_dev_rec->ble.static_addr_type;
+
+            *p_own_addr_type = BLE_ADDR_RANDOM_ID;
+        } else {
+            /* resolving list is empty, not enabled */
+            *p_own_addr_type = BLE_ADDR_RANDOM;
+        }
+    }
+    /* privacy 1.1, or privacy 1.2, general discoverable/connectable mode, disable privacy in */
+    /* controller fall back to host based privacy */
+    else if (btm_cb.ble_ctr_cb.privacy_mode !=  BTM_PRIVACY_NONE)
+    {
+        *p_own_addr_type = BLE_ADDR_RANDOM;
+    }
+#endif
+
+    /* if no privacy,do not set any peer address,*/
+    /* local address type go by global privacy setting */
+    return evt_type;
+}
+
+/*******************************************************************************
+**
+** Function         BTM_BleSetAdvParams
+**
+** Description      This function is called to set advertising parameters.
+**
+** Parameters       adv_int_min: minimum advertising interval
+**                  adv_int_max: maximum advertising interval
+**                  p_dir_bda: connectable direct initiator's LE device address
+**                  chnl_map: advertising channel map.
+**
+** Returns          void
+**
+*******************************************************************************/
+tBTM_STATUS BTM_BleSetAdvParams(uint16_t adv_int_min, uint16_t adv_int_max,
+                                tBLE_BD_ADDR *p_dir_bda,
+                                tBTM_BLE_ADV_CHNL_MAP chnl_map)
+{
+    tBTM_LE_RANDOM_CB *p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+    tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+    tBTM_STATUS status = BTM_SUCCESS;
+    BD_ADDR     p_addr_ptr =  {0};
+    tBLE_ADDR_TYPE   init_addr_type = BLE_ADDR_PUBLIC;
+    tBLE_ADDR_TYPE   own_addr_type = p_addr_cb->own_addr_type;
+    uint8_t          adv_mode = p_cb->adv_mode;
+
+    BTM_TRACE_EVENT ("BTM_BleSetAdvParams");
+
+    if (!controller_get_interface()->supports_ble())
+        return BTM_ILLEGAL_VALUE;
+
+    if (!BTM_BLE_ISVALID_PARAM(adv_int_min, BTM_BLE_ADV_INT_MIN, BTM_BLE_ADV_INT_MAX) ||
+        !BTM_BLE_ISVALID_PARAM(adv_int_max, BTM_BLE_ADV_INT_MIN, BTM_BLE_ADV_INT_MAX))
+    {
+        return BTM_ILLEGAL_VALUE;
+    }
+
+    p_cb->adv_interval_min = adv_int_min;
+    p_cb->adv_interval_max = adv_int_max;
+    p_cb->adv_chnl_map = chnl_map;
+
+    if (p_dir_bda)
+    {
+        memcpy(&p_cb->direct_bda, p_dir_bda, sizeof(tBLE_BD_ADDR));
+    }
+
+    BTM_TRACE_EVENT ("update params for an active adv");
+
+    btm_ble_stop_adv();
+
+    p_cb->evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &init_addr_type,
+                                                     &own_addr_type);
+
+    /* update adv params */
+    btsnd_hcic_ble_write_adv_params (p_cb->adv_interval_min,
+                                     p_cb->adv_interval_max,
+                                     p_cb->evt_type,
+                                     own_addr_type,
+                                     init_addr_type,
+                                     p_addr_ptr,
+                                     p_cb->adv_chnl_map,
+                                     p_cb->afp);
+
+    if (adv_mode == BTM_BLE_ADV_ENABLE)
+        btm_ble_start_adv();
+
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         BTM_BleReadAdvParams
+**
+** Description      This function is called to set advertising parameters.
+**
+** Parameters       adv_int_min: minimum advertising interval
+**                  adv_int_max: maximum advertising interval
+**                  p_dir_bda: connectable direct initiator's LE device address
+**                  chnl_map: advertising channel map.
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTM_BleReadAdvParams (uint16_t *adv_int_min, uint16_t *adv_int_max,
+                           tBLE_BD_ADDR *p_dir_bda, tBTM_BLE_ADV_CHNL_MAP *p_chnl_map)
+{
+    tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+    BTM_TRACE_EVENT ("BTM_BleReadAdvParams ");
+    if (!controller_get_interface()->supports_ble())
+        return ;
+
+    *adv_int_min = p_cb->adv_interval_min;
+    *adv_int_max = p_cb->adv_interval_max;
+    *p_chnl_map = p_cb->adv_chnl_map;
+
+    if (p_dir_bda != NULL)
+    {
+        memcpy(p_dir_bda, &p_cb->direct_bda, sizeof(tBLE_BD_ADDR));
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTM_BleSetScanParams
+**
+** Description      This function is called to set scan parameters.
+**
+** Parameters       client_if - Client IF
+**                  scan_interval - Scan interval
+**                  scan_window - Scan window
+**                  scan_mode -    Scan mode
+**                  scan_setup_status_cback - Scan param setup status callback
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTM_BleSetScanParams(tGATT_IF client_if, uint32_t scan_interval, uint32_t scan_window,
+                          tBLE_SCAN_MODE scan_mode,
+                          tBLE_SCAN_PARAM_SETUP_CBACK scan_setup_status_cback)
+{
+    tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+    uint32_t max_scan_interval;
+    uint32_t max_scan_window;
+
+    BTM_TRACE_EVENT ("%s", __func__);
+    if (!controller_get_interface()->supports_ble())
+        return;
+
+    /* If not supporting extended scan support, use the older range for checking */
+    if (btm_cb.cmn_ble_vsc_cb.extended_scan_support == 0)
+    {
+        max_scan_interval = BTM_BLE_SCAN_INT_MAX;
+        max_scan_window = BTM_BLE_SCAN_WIN_MAX;
+    }
+    else
+    {
+        /* If supporting extended scan support, use the new extended range for checking */
+        max_scan_interval = BTM_BLE_EXT_SCAN_INT_MAX;
+        max_scan_window = BTM_BLE_EXT_SCAN_WIN_MAX;
+    }
+
+    if (BTM_BLE_ISVALID_PARAM(scan_interval, BTM_BLE_SCAN_INT_MIN, max_scan_interval) &&
+        BTM_BLE_ISVALID_PARAM(scan_window, BTM_BLE_SCAN_WIN_MIN, max_scan_window) &&
+       (scan_mode == BTM_BLE_SCAN_MODE_ACTI || scan_mode == BTM_BLE_SCAN_MODE_PASS))
+    {
+        p_cb->scan_type = scan_mode;
+        p_cb->scan_interval = scan_interval;
+        p_cb->scan_window = scan_window;
+
+        if (scan_setup_status_cback != NULL)
+            scan_setup_status_cback(client_if, BTM_SUCCESS);
+    }
+    else
+    {
+        if (scan_setup_status_cback != NULL)
+            scan_setup_status_cback(client_if, BTM_ILLEGAL_VALUE);
+
+        BTM_TRACE_ERROR("Illegal params: scan_interval = %d scan_window = %d",
+                        scan_interval, scan_window);
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         BTM_BleWriteScanRsp
+**
+** Description      This function is called to write LE scan response.
+**
+** Parameters:      p_scan_rsp: scan response information.
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTM_BleWriteScanRsp(uint8_t* data, uint8_t length,
+                         tBTM_BLE_ADV_DATA_CMPL_CBACK *p_adv_data_cback)
+{
+    BTM_TRACE_EVENT ("%s: length: %d", __func__, length);
+    if (!controller_get_interface()->supports_ble()) {
+        p_adv_data_cback(BTM_ILLEGAL_VALUE);
+        return;
+    }
+
+    btsnd_hcic_ble_set_scan_rsp_data(length, data);
+
+    if (length != 0)
+        btm_cb.ble_ctr_cb.inq_var.scan_rsp = true;
+    else
+        btm_cb.ble_ctr_cb.inq_var.scan_rsp = false;
+
+    p_adv_data_cback(BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_BleWriteAdvData
+**
+** Description      This function is called to write advertising data.
+**
+** Parameters:       None.
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTM_BleWriteAdvData(uint8_t* data, uint8_t length,
+                         tBTM_BLE_ADV_DATA_CMPL_CBACK *p_adv_data_cback)
+{
+    //TODO(jpawlowski) : delete btm_cb.ble_ctr_cb.inq_var.adv_data ??
+    BTM_TRACE_EVENT ("BTM_BleWriteAdvData ");
+
+    if (!controller_get_interface()->supports_ble()) {
+        p_adv_data_cback(BTM_ILLEGAL_VALUE);
+        return;
+    }
+
+    //TODO(jpawlowski): fill flags, old code had them empty always.
+
+    btsnd_hcic_ble_set_adv_data(length, data);
+    p_adv_data_cback(BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_CheckAdvData
+**
+** Description      This function is called to get ADV data for a specific type.
+**
+** Parameters       p_adv - pointer of ADV data
+**                  type   - finding ADV data type
+**                  p_length - return the length of ADV data not including type
+**
+** Returns          pointer of ADV data
+**
+*******************************************************************************/
+uint8_t *BTM_CheckAdvData( uint8_t *p_adv, uint8_t type, uint8_t *p_length)
+{
+    uint8_t *p = p_adv;
+    uint8_t length;
+    uint8_t adv_type;
+    BTM_TRACE_API("%s: type=0x%02x", __func__, type);
+
+    STREAM_TO_UINT8(length, p);
+
+    while ( length && (p - p_adv <= BTM_BLE_CACHE_ADV_DATA_MAX))
+    {
+        STREAM_TO_UINT8(adv_type, p);
+
+        if ( adv_type == type )
+        {
+            /* length doesn't include itself */
+            *p_length = length - 1; /* minus the length of type */
+            return p;
+        }
+        p += length - 1; /* skip the length of data */
+        STREAM_TO_UINT8(length, p);
+    }
+
+    *p_length = 0;
+    return NULL;
+}
+
+/*******************************************************************************
+**
+** 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()
+{
+    BTM_TRACE_API("%s", __func__);
+
+    return (btm_cb.ble_ctr_cb.inq_var.discoverable_mode);
+}
+
+/*******************************************************************************
+**
+** 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()
+{
+    BTM_TRACE_API ("%s", __func__);
+
+    return (btm_cb.ble_ctr_cb.inq_var.connectable_mode);
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_select_adv_interval
+**
+** Description      select adv interval based on device mode
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_select_adv_interval(tBTM_BLE_INQ_CB *p_cb, uint8_t evt_type, uint16_t *p_adv_int_min, uint16_t *p_adv_int_max)
+{
+    if (p_cb->adv_interval_min && p_cb->adv_interval_max)
+    {
+        *p_adv_int_min = p_cb->adv_interval_min;
+        *p_adv_int_max = p_cb->adv_interval_max;
+    }
+    else
+    {
+        switch (evt_type)
+        {
+        case BTM_BLE_CONNECT_EVT:
+        case BTM_BLE_CONNECT_LO_DUTY_DIR_EVT:
+            *p_adv_int_min = *p_adv_int_max = BTM_BLE_GAP_ADV_FAST_INT_1;
+            break;
+
+        case BTM_BLE_NON_CONNECT_EVT:
+        case BTM_BLE_DISCOVER_EVT:
+            *p_adv_int_min = *p_adv_int_max = BTM_BLE_GAP_ADV_FAST_INT_2;
+            break;
+
+        /* connectable directed event */
+        case BTM_BLE_CONNECT_DIR_EVT:
+            *p_adv_int_min = BTM_BLE_GAP_ADV_DIR_MIN_INT;
+            *p_adv_int_max = BTM_BLE_GAP_ADV_DIR_MAX_INT;
+            break;
+
+        default:
+            *p_adv_int_min = *p_adv_int_max = BTM_BLE_GAP_ADV_SLOW_INT;
+            break;
+        }
+    }
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_update_dmt_flag_bits
+**
+** Description      Obtain updated adv flag value based on connect and discoverability mode.
+**                  Also, setup DMT support value in the flag based on whether the controller
+**                  supports both LE and BR/EDR.
+**
+** Parameters:      flag_value (Input / Output) - flag value
+**                  connect_mode (Input) - Connect mode value
+**                  disc_mode (Input) - discoverability mode
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_update_dmt_flag_bits(uint8_t *adv_flag_value, const uint16_t connect_mode,
+                                   const uint16_t disc_mode)
+{
+    /* BR/EDR non-discoverable , non-connectable */
+    if ((disc_mode & BTM_DISCOVERABLE_MASK) == 0 &&
+        (connect_mode & BTM_CONNECTABLE_MASK) == 0)
+        *adv_flag_value |= BTM_BLE_BREDR_NOT_SPT;
+    else
+        *adv_flag_value &= ~BTM_BLE_BREDR_NOT_SPT;
+
+    /* if local controller support, mark both controller and host support in flag */
+    if (controller_get_interface()->supports_simultaneous_le_bredr())
+        *adv_flag_value |= (BTM_BLE_DMT_CONTROLLER_SPT|BTM_BLE_DMT_HOST_SPT);
+    else
+        *adv_flag_value &= ~(BTM_BLE_DMT_CONTROLLER_SPT|BTM_BLE_DMT_HOST_SPT);
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_set_adv_flag
+**
+** Description      Set adv flag in adv data.
+**
+** Parameters:      connect_mode (Input)- Connect mode value
+**                  disc_mode (Input) - discoverability mode
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_set_adv_flag(uint16_t connect_mode, uint16_t disc_mode)
+{
+    uint8_t flag = 0, old_flag = 0;
+    tBTM_BLE_LOCAL_ADV_DATA *p_adv_data = &btm_cb.ble_ctr_cb.inq_var.adv_data;
+
+    if (p_adv_data->p_flags != NULL)
+        flag = old_flag = *(p_adv_data->p_flags);
+
+    btm_ble_update_dmt_flag_bits (&flag, connect_mode, disc_mode);
+
+    LOG_DEBUG(LOG_TAG, "disc_mode %04x", disc_mode);
+    /* update discoverable flag */
+    if (disc_mode & BTM_BLE_LIMITED_DISCOVERABLE)
+    {
+        flag &= ~BTM_BLE_GEN_DISC_FLAG;
+        flag |= BTM_BLE_LIMIT_DISC_FLAG;
+    }
+    else if (disc_mode & BTM_BLE_GENERAL_DISCOVERABLE)
+    {
+        flag |= BTM_BLE_GEN_DISC_FLAG;
+        flag &= ~BTM_BLE_LIMIT_DISC_FLAG;
+    }
+    else /* remove all discoverable flags */
+    {
+        flag &= ~(BTM_BLE_LIMIT_DISC_FLAG|BTM_BLE_GEN_DISC_FLAG);
+    }
+
+    if (flag != old_flag)
+    {
+        btm_ble_update_adv_flag(flag);
+    }
+}
+/*******************************************************************************
+**
+** Function         btm_ble_set_discoverability
+**
+** Description      This function is called to set BLE discoverable mode.
+**
+** Parameters:      combined_mode: discoverability mode.
+**
+** Returns          BTM_SUCCESS is status set successfully; otherwise failure.
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_set_discoverability(uint16_t combined_mode)
+{
+    tBTM_LE_RANDOM_CB   *p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+    tBTM_BLE_INQ_CB     *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+    uint16_t            mode = (combined_mode &  BTM_BLE_DISCOVERABLE_MASK);
+    uint8_t             new_mode = BTM_BLE_ADV_ENABLE;
+    uint8_t             evt_type;
+    tBTM_STATUS         status = BTM_SUCCESS;
+    BD_ADDR             p_addr_ptr= {0};
+    tBLE_ADDR_TYPE      init_addr_type = BLE_ADDR_PUBLIC,
+                        own_addr_type = p_addr_cb->own_addr_type;
+    uint16_t            adv_int_min, adv_int_max;
+
+    BTM_TRACE_EVENT ("%s mode=0x%0x combined_mode=0x%x", __func__, mode, combined_mode);
+
+    /*** Check mode parameter ***/
+    if (mode > BTM_BLE_MAX_DISCOVERABLE)
+        return(BTM_ILLEGAL_VALUE);
+
+    p_cb->discoverable_mode = mode;
+
+    evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &init_addr_type, &own_addr_type);
+
+    if (p_cb->connectable_mode == BTM_BLE_NON_CONNECTABLE && mode == BTM_BLE_NON_DISCOVERABLE)
+        new_mode = BTM_BLE_ADV_DISABLE;
+
+    btm_ble_select_adv_interval(p_cb, evt_type, &adv_int_min, &adv_int_max);
+
+    alarm_cancel(p_cb->fast_adv_timer);
+
+    /* update adv params if start advertising */
+    BTM_TRACE_EVENT ("evt_type=0x%x p-cb->evt_type=0x%x ", evt_type, p_cb->evt_type);
+
+    if (new_mode == BTM_BLE_ADV_ENABLE)
+    {
+        btm_ble_set_adv_flag (btm_cb.btm_inq_vars.connectable_mode, combined_mode);
+
+        if (evt_type != p_cb->evt_type ||p_cb->adv_addr_type != own_addr_type
+            || !p_cb->fast_adv_on)
+        {
+            btm_ble_stop_adv();
+
+            /* update adv params */
+            btsnd_hcic_ble_write_adv_params(adv_int_min, adv_int_max, evt_type,
+                                            own_addr_type, init_addr_type,
+                                            p_addr_ptr, p_cb->adv_chnl_map,
+                                            p_cb->afp);
+            p_cb->evt_type = evt_type;
+            p_cb->adv_addr_type = own_addr_type;
+        }
+    }
+
+    if (status == BTM_SUCCESS && p_cb->adv_mode != new_mode)
+    {
+        if (new_mode == BTM_BLE_ADV_ENABLE)
+            status = btm_ble_start_adv();
+        else
+            status = btm_ble_stop_adv();
+    }
+
+    if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE)
+    {
+        p_cb->fast_adv_on = true;
+        /* start initial GAP mode adv timer */
+        alarm_set_on_queue(p_cb->fast_adv_timer,
+                           BTM_BLE_GAP_FAST_ADV_TIMEOUT_MS,
+                           btm_ble_fast_adv_timer_timeout, NULL,
+                           btu_general_alarm_queue);
+    }
+    else
+    {
+#if (BLE_PRIVACY_SPT == TRUE)
+        btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, true);
+#endif
+    }
+
+    /* set up stop advertising timer */
+    if (status == BTM_SUCCESS && mode == BTM_BLE_LIMITED_DISCOVERABLE)
+    {
+        BTM_TRACE_EVENT("start timer for limited disc mode duration=%d ms",
+                        BTM_BLE_GAP_LIM_TIMEOUT_MS);
+        /* start Tgap(lim_timeout) */
+        alarm_set_on_queue(p_cb->inquiry_timer, BTM_BLE_GAP_LIM_TIMEOUT_MS,
+                           btm_ble_inquiry_timer_gap_limited_discovery_timeout,
+                           NULL, btu_general_alarm_queue);
+    }
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_set_connectability
+**
+** Description      This function is called to set BLE connectability mode.
+**
+** Parameters:      combined_mode: connectability mode.
+**
+** Returns          BTM_SUCCESS is status set successfully; otherwise failure.
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_set_connectability(uint16_t combined_mode)
+{
+    tBTM_LE_RANDOM_CB       *p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+    tBTM_BLE_INQ_CB         *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+    uint16_t                mode = (combined_mode & BTM_BLE_CONNECTABLE_MASK);
+    uint8_t                 new_mode = BTM_BLE_ADV_ENABLE;
+    uint8_t                 evt_type;
+    tBTM_STATUS             status = BTM_SUCCESS;
+    BD_ADDR                 p_addr_ptr =  {0};
+    tBLE_ADDR_TYPE          peer_addr_type = BLE_ADDR_PUBLIC,
+                            own_addr_type = p_addr_cb->own_addr_type;
+    uint16_t                adv_int_min, adv_int_max;
+
+    BTM_TRACE_EVENT ("%s mode=0x%0x combined_mode=0x%x", __func__, mode, combined_mode);
+
+    /*** Check mode parameter ***/
+    if (mode > BTM_BLE_MAX_CONNECTABLE)
+        return(BTM_ILLEGAL_VALUE);
+
+    p_cb->connectable_mode = mode;
+
+    evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &peer_addr_type, &own_addr_type);
+
+    if (mode == BTM_BLE_NON_CONNECTABLE && p_cb->discoverable_mode == BTM_BLE_NON_DISCOVERABLE)
+        new_mode = BTM_BLE_ADV_DISABLE;
+
+    btm_ble_select_adv_interval(p_cb, evt_type, &adv_int_min, &adv_int_max);
+
+    alarm_cancel(p_cb->fast_adv_timer);
+    /* update adv params if needed */
+    if (new_mode == BTM_BLE_ADV_ENABLE)
+    {
+        btm_ble_set_adv_flag (combined_mode, btm_cb.btm_inq_vars.discoverable_mode);
+        if (p_cb->evt_type != evt_type || p_cb->adv_addr_type != p_addr_cb->own_addr_type
+            || !p_cb->fast_adv_on)
+        {
+            btm_ble_stop_adv();
+
+            btsnd_hcic_ble_write_adv_params(adv_int_min, adv_int_max, evt_type,
+                                            own_addr_type, peer_addr_type,
+                                            p_addr_ptr, p_cb->adv_chnl_map,
+                                            p_cb->afp);
+            p_cb->evt_type = evt_type;
+            p_cb->adv_addr_type = own_addr_type;
+        }
+    }
+
+    /* update advertising mode */
+    if (status == BTM_SUCCESS && new_mode != p_cb->adv_mode)
+    {
+        if (new_mode == BTM_BLE_ADV_ENABLE)
+            status = btm_ble_start_adv();
+        else
+            status = btm_ble_stop_adv();
+    }
+
+    if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE)
+    {
+        p_cb->fast_adv_on = true;
+        /* start initial GAP mode adv timer */
+        alarm_set_on_queue(p_cb->fast_adv_timer,
+                           BTM_BLE_GAP_FAST_ADV_TIMEOUT_MS,
+                           btm_ble_fast_adv_timer_timeout, NULL,
+                           btu_general_alarm_queue);
+    }
+    else
+    {
+#if (BLE_PRIVACY_SPT == TRUE)
+        btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, true);
+#endif
+    }
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_start_inquiry
+**
+** Description      This function is called to start BLE inquiry procedure.
+**                  If the duration is zero, the periodic inquiry mode is cancelled.
+**
+** Parameters:      mode - GENERAL or LIMITED inquiry
+**                  p_inq_params - pointer to the BLE inquiry parameter.
+**                  p_results_cb - callback returning pointer to results (tBTM_INQ_RESULTS)
+**                  p_cmpl_cb - callback indicating the end of an inquiry
+**
+**
+**
+** Returns          BTM_CMD_STARTED if successfully started
+**                  BTM_NO_RESOURCES if could not allocate a message buffer
+**                  BTM_BUSY - if an inquiry is already active
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_start_inquiry (uint8_t mode, uint8_t duration)
+{
+    tBTM_STATUS status = BTM_CMD_STARTED;
+    tBTM_BLE_CB *p_ble_cb = &btm_cb.ble_ctr_cb;
+    tBTM_INQUIRY_VAR_ST      *p_inq = &btm_cb.btm_inq_vars;
+
+    BTM_TRACE_DEBUG("btm_ble_start_inquiry: mode = %02x inq_active = 0x%02x", mode, btm_cb.btm_inq_vars.inq_active);
+
+    /* if selective connection is active, or inquiry is already active, reject it */
+    if (BTM_BLE_IS_INQ_ACTIVE(p_ble_cb->scan_activity) ||
+        BTM_BLE_IS_SEL_CONN_ACTIVE (p_ble_cb->scan_activity))
+    {
+        BTM_TRACE_ERROR("LE Inquiry is active, can not start inquiry");
+        return(BTM_BUSY);
+    }
+
+    if (!BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity))
+    {
+        btsnd_hcic_ble_set_scan_params(BTM_BLE_SCAN_MODE_ACTI,
+                                        BTM_BLE_LOW_LATENCY_SCAN_INT,
+                                        BTM_BLE_LOW_LATENCY_SCAN_WIN,
+                                        btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+                                        SP_ADV_ALL);
+#if (BLE_PRIVACY_SPT == TRUE)
+        /* enable IRK list */
+        btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN);
+#endif
+        p_ble_cb->inq_var.scan_duplicate_filter  = BTM_BLE_DUPLICATE_DISABLE;
+        status = btm_ble_start_scan();
+    }
+    else if ((p_ble_cb->inq_var.scan_interval != BTM_BLE_LOW_LATENCY_SCAN_INT) ||
+            (p_ble_cb->inq_var.scan_window != BTM_BLE_LOW_LATENCY_SCAN_WIN)) {
+        BTM_TRACE_DEBUG("%s, restart LE scan with low latency scan params", __func__);
+        btsnd_hcic_ble_set_scan_enable(BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
+        btsnd_hcic_ble_set_scan_params(BTM_BLE_SCAN_MODE_ACTI,
+                                        BTM_BLE_LOW_LATENCY_SCAN_INT,
+                                        BTM_BLE_LOW_LATENCY_SCAN_WIN,
+                                        btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
+                                        SP_ADV_ALL);
+        btsnd_hcic_ble_set_scan_enable(BTM_BLE_SCAN_ENABLE, BTM_BLE_DUPLICATE_DISABLE);
+    }
+
+    if (status == BTM_CMD_STARTED)
+    {
+        p_inq->inq_active |= mode;
+        p_ble_cb->scan_activity |= mode;
+
+        BTM_TRACE_DEBUG("btm_ble_start_inquiry inq_active = 0x%02x", p_inq->inq_active);
+
+        if (duration != 0) {
+            /* start inquiry timer */
+            period_ms_t duration_ms = duration * 1000;
+            alarm_set_on_queue(p_ble_cb->inq_var.inquiry_timer,
+                               duration_ms, btm_ble_inquiry_timer_timeout,
+                               NULL, btu_general_alarm_queue);
+        }
+    }
+
+    return status;
+
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_read_remote_name_cmpl
+**
+** Description      This function is called when BLE remote name is received.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_read_remote_name_cmpl(bool    status, BD_ADDR bda, uint16_t length, char *p_name)
+{
+    uint8_t hci_status = HCI_SUCCESS;
+    BD_NAME bd_name;
+
+    memset(bd_name, 0, (BD_NAME_LEN + 1));
+    if (length > BD_NAME_LEN)
+    {
+        length = BD_NAME_LEN;
+    }
+    memcpy((uint8_t*)bd_name, p_name, length);
+
+    if ((!status) || (length==0))
+    {
+        hci_status = HCI_ERR_HOST_TIMEOUT;
+    }
+
+    btm_process_remote_name(bda, bd_name, length +1, hci_status);
+    btm_sec_rmt_name_request_complete (bda, (uint8_t *)p_name, hci_status);
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_read_remote_name
+**
+** Description      This function read remote LE device name using GATT read
+**                  procedure.
+**
+** Parameters:       None.
+**
+** Returns          void
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_read_remote_name(BD_ADDR remote_bda, tBTM_INQ_INFO *p_cur, tBTM_CMPL_CB *p_cb)
+{
+    tBTM_INQUIRY_VAR_ST      *p_inq = &btm_cb.btm_inq_vars;
+
+    if (!controller_get_interface()->supports_ble())
+        return BTM_ERR_PROCESSING;
+
+    if (p_cur &&
+        p_cur->results.ble_evt_type != BTM_BLE_EVT_CONN_ADV &&
+        p_cur->results.ble_evt_type != BTM_BLE_EVT_CONN_DIR_ADV)
+    {
+        BTM_TRACE_DEBUG("name request to non-connectable device failed.");
+        return BTM_ERR_PROCESSING;
+    }
+
+    /* read remote device name using GATT procedure */
+    if (p_inq->remname_active)
+        return BTM_BUSY;
+
+    if (!GAP_BleReadPeerDevName(remote_bda, btm_ble_read_remote_name_cmpl))
+        return BTM_BUSY;
+
+    p_inq->p_remname_cmpl_cb = p_cb;
+    p_inq->remname_active = true;
+
+    memcpy(p_inq->remname_bda, remote_bda, BD_ADDR_LEN);
+
+    alarm_set_on_queue(p_inq->remote_name_timer,
+                       BTM_EXT_BLE_RMT_NAME_TIMEOUT_MS,
+                       btm_inq_remote_name_timer_timeout, NULL,
+                       btu_general_alarm_queue);
+
+    return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_cancel_remote_name
+**
+** Description      This function cancel read remote LE device name.
+**
+** Parameters:       None.
+**
+** Returns          void
+**
+*******************************************************************************/
+bool    btm_ble_cancel_remote_name(BD_ADDR remote_bda)
+{
+    tBTM_INQUIRY_VAR_ST      *p_inq = &btm_cb.btm_inq_vars;
+    bool        status;
+
+    status = GAP_BleCancelReadPeerDevName(remote_bda);
+
+    p_inq->remname_active = false;
+    memset(p_inq->remname_bda, 0, BD_ADDR_LEN);
+    alarm_cancel(p_inq->remote_name_timer);
+
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_update_adv_flag
+**
+** Description      This function update the limited discoverable flag in the adv
+**                  data.
+**
+** Parameters:       None.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_ble_update_adv_flag(uint8_t flag)
+{
+    tBTM_BLE_LOCAL_ADV_DATA *p_adv_data = &btm_cb.ble_ctr_cb.inq_var.adv_data;
+    uint8_t *p;
+
+    BTM_TRACE_DEBUG ("btm_ble_update_adv_flag new=0x%x", flag);
+
+    if (p_adv_data->p_flags != NULL)
+    {
+        BTM_TRACE_DEBUG ("btm_ble_update_adv_flag old=0x%x",   *p_adv_data->p_flags);
+        *p_adv_data->p_flags = flag;
+    }
+    else /* no FLAGS in ADV data*/
+    {
+        p = (p_adv_data->p_pad == NULL) ? p_adv_data->ad_data : p_adv_data->p_pad;
+        /* need 3 bytes space to stuff in the flags, if not */
+        /* erase all written data, just for flags */
+        if ((BTM_BLE_AD_DATA_LEN - (p - p_adv_data->ad_data)) < 3)
+        {
+            p = p_adv_data->p_pad = p_adv_data->ad_data;
+            memset(p_adv_data->ad_data, 0, BTM_BLE_AD_DATA_LEN);
+        }
+
+        *p++ = 2;
+        *p++ = BTM_BLE_AD_TYPE_FLAG;
+        p_adv_data->p_flags = p;
+        *p++ = flag;
+        p_adv_data->p_pad = p;
+    }
+
+    btsnd_hcic_ble_set_adv_data((uint8_t)(p_adv_data->p_pad - p_adv_data->ad_data),
+                                p_adv_data->ad_data);
+    p_adv_data->data_mask |= BTM_BLE_AD_BIT_FLAGS;
+
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_cache_adv_data
+**
+** Description      Update advertising cache data.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_cache_adv_data(UNUSED_ATTR tBTM_INQ_RESULTS *p_cur, uint8_t data_len,
+                            uint8_t *p, uint8_t evt_type)
+{
+    tBTM_BLE_INQ_CB     *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
+    uint8_t *p_cache;
+    uint8_t length;
+
+    /* cache adv report/scan response data */
+    if (evt_type != BTM_BLE_SCAN_RSP_EVT)
+    {
+        p_le_inq_cb->adv_len = 0;
+        memset(p_le_inq_cb->adv_data_cache, 0, BTM_BLE_CACHE_ADV_DATA_MAX);
+    }
+
+    if (data_len > 0)
+    {
+        p_cache = &p_le_inq_cb->adv_data_cache[p_le_inq_cb->adv_len];
+        STREAM_TO_UINT8(length, p);
+        while ( length && ((p_le_inq_cb->adv_len + length + 1) <= BTM_BLE_CACHE_ADV_DATA_MAX))
+        {
+            /* copy from the length byte & data into cache */
+            memcpy(p_cache, p-1, length+1);
+            /* advance the cache pointer past data */
+            p_cache += length+1;
+            /* increment cache length */
+            p_le_inq_cb->adv_len += length+1;
+            /* skip the length of data */
+            p += length;
+            STREAM_TO_UINT8(length, p);
+        }
+    }
+
+    /* parse service UUID from adv packet and save it in inq db eir_uuid */
+    /* TODO */
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_is_discoverable
+**
+** Description      check ADV flag to make sure device is discoverable and match
+**                  the search condition
+**
+** Parameters
+**
+** Returns          void
+**
+*******************************************************************************/
+uint8_t btm_ble_is_discoverable(BD_ADDR bda, uint8_t evt_type,
+                                UNUSED_ATTR uint8_t *p)
+{
+    uint8_t             *p_flag, flag = 0, rt = 0;
+    uint8_t              data_len;
+    tBTM_INQ_PARMS      *p_cond = &btm_cb.btm_inq_vars.inqparms;
+    tBTM_BLE_INQ_CB     *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+    /* for observer, always "discoverable */
+    if (BTM_BLE_IS_OBS_ACTIVE(btm_cb.ble_ctr_cb.scan_activity))
+        rt |= BTM_BLE_OBS_RESULT;
+
+    if (BTM_BLE_IS_SEL_CONN_ACTIVE(btm_cb.ble_ctr_cb.scan_activity) &&
+        (evt_type == BTM_BLE_CONNECT_EVT || evt_type == BTM_BLE_CONNECT_DIR_EVT))
+        rt |= BTM_BLE_SEL_CONN_RESULT;
+
+    /* does not match filter condition */
+    if (p_cond->filter_cond_type == BTM_FILTER_COND_BD_ADDR &&
+        memcmp(bda, p_cond->filter_cond.bdaddr_cond, BD_ADDR_LEN) != 0)
+    {
+        BTM_TRACE_DEBUG("BD ADDR does not meet filter condition");
+        return rt;
+    }
+
+    if (p_le_inq_cb->adv_len != 0)
+    {
+        if ((p_flag = BTM_CheckAdvData(p_le_inq_cb->adv_data_cache,
+            BTM_BLE_AD_TYPE_FLAG, &data_len)) != NULL)
+        {
+            flag = * p_flag;
+
+            if ((btm_cb.btm_inq_vars.inq_active & BTM_BLE_GENERAL_INQUIRY) &&
+                (flag & (BTM_BLE_LIMIT_DISC_FLAG|BTM_BLE_GEN_DISC_FLAG)) != 0)
+            {
+                BTM_TRACE_DEBUG("Find Generable Discoverable device");
+                rt |= BTM_BLE_INQ_RESULT;
+            }
+
+            else if (btm_cb.btm_inq_vars.inq_active & BTM_BLE_LIMITED_INQUIRY &&
+                     (flag & BTM_BLE_LIMIT_DISC_FLAG) != 0)
+            {
+                BTM_TRACE_DEBUG("Find limited discoverable device");
+                rt |= BTM_BLE_INQ_RESULT;
+            }
+        }
+    }
+    return rt;
+}
+
+static void btm_ble_appearance_to_cod(uint16_t appearance, uint8_t *dev_class)
+{
+    dev_class[0] = 0;
+
+    switch (appearance)
+    {
+        case BTM_BLE_APPEARANCE_GENERIC_PHONE:
+            dev_class[1] = BTM_COD_MAJOR_PHONE;
+            dev_class[2] = BTM_COD_MINOR_UNCLASSIFIED;
+            break;
+        case BTM_BLE_APPEARANCE_GENERIC_COMPUTER:
+            dev_class[1] = BTM_COD_MAJOR_COMPUTER;
+            dev_class[2] = BTM_COD_MINOR_UNCLASSIFIED;
+            break;
+        case BTM_BLE_APPEARANCE_GENERIC_REMOTE:
+            dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+            dev_class[2] = BTM_COD_MINOR_REMOTE_CONTROL;
+            break;
+        case BTM_BLE_APPEARANCE_GENERIC_THERMOMETER:
+        case BTM_BLE_APPEARANCE_THERMOMETER_EAR:
+            dev_class[1] = BTM_COD_MAJOR_HEALTH;
+            dev_class[2] = BTM_COD_MINOR_THERMOMETER;
+            break;
+        case BTM_BLE_APPEARANCE_GENERIC_HEART_RATE:
+        case BTM_BLE_APPEARANCE_HEART_RATE_BELT:
+            dev_class[1] = BTM_COD_MAJOR_HEALTH;
+            dev_class[2] = BTM_COD_MINOR_HEART_PULSE_MONITOR;
+            break;
+        case BTM_BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE:
+        case BTM_BLE_APPEARANCE_BLOOD_PRESSURE_ARM:
+        case BTM_BLE_APPEARANCE_BLOOD_PRESSURE_WRIST:
+            dev_class[1] = BTM_COD_MAJOR_HEALTH;
+            dev_class[2] = BTM_COD_MINOR_BLOOD_MONITOR;
+            break;
+        case BTM_BLE_APPEARANCE_GENERIC_PULSE_OXIMETER:
+        case BTM_BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP:
+        case BTM_BLE_APPEARANCE_PULSE_OXIMETER_WRIST:
+            dev_class[1] = BTM_COD_MAJOR_HEALTH;
+            dev_class[2] = BTM_COD_MINOR_PULSE_OXIMETER;
+            break;
+        case BTM_BLE_APPEARANCE_GENERIC_GLUCOSE:
+            dev_class[1] = BTM_COD_MAJOR_HEALTH;
+            dev_class[2] = BTM_COD_MINOR_GLUCOSE_METER;
+            break;
+        case BTM_BLE_APPEARANCE_GENERIC_WEIGHT:
+            dev_class[1] = BTM_COD_MAJOR_HEALTH;
+            dev_class[2] = BTM_COD_MINOR_WEIGHING_SCALE;
+            break;
+        case BTM_BLE_APPEARANCE_GENERIC_WALKING:
+        case BTM_BLE_APPEARANCE_WALKING_IN_SHOE:
+        case BTM_BLE_APPEARANCE_WALKING_ON_SHOE:
+        case BTM_BLE_APPEARANCE_WALKING_ON_HIP:
+            dev_class[1] = BTM_COD_MAJOR_HEALTH;
+            dev_class[2] = BTM_COD_MINOR_STEP_COUNTER;
+            break;
+        case BTM_BLE_APPEARANCE_GENERIC_WATCH:
+        case BTM_BLE_APPEARANCE_SPORTS_WATCH:
+            dev_class[1] = BTM_COD_MAJOR_WEARABLE;
+            dev_class[2] = BTM_COD_MINOR_WRIST_WATCH;
+            break;
+        case BTM_BLE_APPEARANCE_GENERIC_EYEGLASSES:
+            dev_class[1] = BTM_COD_MAJOR_WEARABLE;
+            dev_class[2] = BTM_COD_MINOR_GLASSES;
+            break;
+        case BTM_BLE_APPEARANCE_GENERIC_DISPLAY:
+            dev_class[1] = BTM_COD_MAJOR_IMAGING;
+            dev_class[2] = BTM_COD_MINOR_DISPLAY;
+            break;
+        case BTM_BLE_APPEARANCE_GENERIC_MEDIA_PLAYER:
+            dev_class[1] = BTM_COD_MAJOR_AUDIO;
+            dev_class[2] = BTM_COD_MINOR_UNCLASSIFIED;
+            break;
+        case BTM_BLE_APPEARANCE_GENERIC_BARCODE_SCANNER:
+        case BTM_BLE_APPEARANCE_HID_BARCODE_SCANNER:
+        case BTM_BLE_APPEARANCE_GENERIC_HID:
+            dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+            dev_class[2] = BTM_COD_MINOR_UNCLASSIFIED;
+            break;
+        case BTM_BLE_APPEARANCE_HID_KEYBOARD:
+            dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+            dev_class[2] = BTM_COD_MINOR_KEYBOARD;
+            break;
+        case BTM_BLE_APPEARANCE_HID_MOUSE:
+            dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+            dev_class[2] = BTM_COD_MINOR_POINTING;
+            break;
+        case BTM_BLE_APPEARANCE_HID_JOYSTICK:
+            dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+            dev_class[2] = BTM_COD_MINOR_JOYSTICK;
+            break;
+        case BTM_BLE_APPEARANCE_HID_GAMEPAD:
+            dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+            dev_class[2] = BTM_COD_MINOR_GAMEPAD;
+            break;
+        case BTM_BLE_APPEARANCE_HID_DIGITIZER_TABLET:
+            dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+            dev_class[2] = BTM_COD_MINOR_DIGITIZING_TABLET;
+            break;
+        case BTM_BLE_APPEARANCE_HID_CARD_READER:
+            dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+            dev_class[2] = BTM_COD_MINOR_CARD_READER;
+            break;
+        case BTM_BLE_APPEARANCE_HID_DIGITAL_PEN:
+            dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+            dev_class[2] = BTM_COD_MINOR_DIGITAL_PAN;
+            break;
+        case BTM_BLE_APPEARANCE_UKNOWN:
+        case BTM_BLE_APPEARANCE_GENERIC_CLOCK:
+        case BTM_BLE_APPEARANCE_GENERIC_TAG:
+        case BTM_BLE_APPEARANCE_GENERIC_KEYRING:
+        case BTM_BLE_APPEARANCE_GENERIC_CYCLING:
+        case BTM_BLE_APPEARANCE_CYCLING_COMPUTER:
+        case BTM_BLE_APPEARANCE_CYCLING_SPEED:
+        case BTM_BLE_APPEARANCE_CYCLING_CADENCE:
+        case BTM_BLE_APPEARANCE_CYCLING_POWER:
+        case BTM_BLE_APPEARANCE_CYCLING_SPEED_CADENCE:
+        case BTM_BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS:
+        case BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION:
+        case BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_AND_NAV:
+        case BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD:
+        case BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD_AND_NAV:
+        default:
+            dev_class[1] = BTM_COD_MAJOR_UNCLASSIFIED;
+            dev_class[2] = BTM_COD_MINOR_UNCLASSIFIED;
+    };
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_update_inq_result
+**
+** Description      Update adv packet information into inquiry result.
+**
+** Parameters
+**
+** Returns          void
+**
+*******************************************************************************/
+bool    btm_ble_update_inq_result(tINQ_DB_ENT *p_i, uint8_t addr_type, uint8_t evt_type, uint8_t *p)
+{
+    bool                to_report = true;
+    tBTM_INQ_RESULTS     *p_cur = &p_i->inq_info.results;
+    uint8_t             len;
+    uint8_t             *p_flag;
+    tBTM_INQUIRY_VAR_ST  *p_inq = &btm_cb.btm_inq_vars;
+    uint8_t              data_len, rssi;
+    tBTM_BLE_INQ_CB     *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
+    uint8_t *p1;
+    uint8_t             *p_uuid16;
+
+    STREAM_TO_UINT8    (data_len, p);
+
+    if (data_len > BTM_BLE_ADV_DATA_LEN_MAX)
+    {
+        BTM_TRACE_WARNING("EIR data too long %d. discard", data_len);
+        return false;
+    }
+    btm_ble_cache_adv_data(p_cur, data_len, p, evt_type);
+
+    p1 = (p + data_len);
+    STREAM_TO_UINT8 (rssi, p1);
+
+    /* Save the info */
+    p_cur->inq_result_type = BTM_INQ_RESULT_BLE;
+    p_cur->ble_addr_type    = addr_type;
+    p_cur->rssi = rssi;
+
+    /* active scan, always wait until get scan_rsp to report the result */
+    if ((btm_cb.ble_ctr_cb.inq_var.scan_type == BTM_BLE_SCAN_MODE_ACTI &&
+         (evt_type == BTM_BLE_CONNECT_EVT || evt_type == BTM_BLE_DISCOVER_EVT)))
+    {
+        BTM_TRACE_DEBUG("btm_ble_update_inq_result scan_rsp=false, to_report=false,\
+                              scan_type_active=%d", btm_cb.ble_ctr_cb.inq_var.scan_type);
+        p_i->scan_rsp = false;
+        to_report = false;
+    }
+    else
+        p_i->scan_rsp = true;
+
+    if (p_i->inq_count != p_inq->inq_counter)
+        p_cur->device_type = BT_DEVICE_TYPE_BLE;
+    else
+        p_cur->device_type |= BT_DEVICE_TYPE_BLE;
+
+    if (evt_type != BTM_BLE_SCAN_RSP_EVT)
+        p_cur->ble_evt_type     = evt_type;
+
+    p_i->inq_count = p_inq->inq_counter;   /* Mark entry for current inquiry */
+
+    if (p_le_inq_cb->adv_len != 0)
+    {
+        if ((p_flag = BTM_CheckAdvData(p_le_inq_cb->adv_data_cache, BTM_BLE_AD_TYPE_FLAG, &len)) != NULL)
+            p_cur->flag = * p_flag;
+    }
+
+    if (p_le_inq_cb->adv_len != 0)
+    {
+        /* Check to see the BLE device has the Appearance UUID in the advertising data.  If it does
+         * then try to convert the appearance value to a class of device value Bluedroid can use.
+         * Otherwise fall back to trying to infer if it is a HID device based on the service class.
+         */
+        p_uuid16 = BTM_CheckAdvData(p_le_inq_cb->adv_data_cache, BTM_BLE_AD_TYPE_APPEARANCE, &len);
+        if (p_uuid16 && len == 2)
+        {
+            btm_ble_appearance_to_cod((uint16_t)p_uuid16[0] | (p_uuid16[1] << 8), p_cur->dev_class);
+        }
+        else
+        {
+            if ((p_uuid16 = BTM_CheckAdvData(p_le_inq_cb->adv_data_cache,
+                                             BTM_BLE_AD_TYPE_16SRV_CMPL, &len)) != NULL)
+            {
+                uint8_t i;
+                for (i = 0; i + 2 <= len; i = i + 2)
+                {
+                    /* if this BLE device support HID over LE, set HID Major in class of device */
+                    if ((p_uuid16[i] | (p_uuid16[i+1] << 8)) == UUID_SERVCLASS_LE_HID)
+                    {
+                        p_cur->dev_class[0] = 0;
+                        p_cur->dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+                        p_cur->dev_class[2] = 0;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    /* if BR/EDR not supported is not set, assume is a DUMO device */
+    if ((p_cur->flag & BTM_BLE_BREDR_NOT_SPT) == 0 &&
+         evt_type != BTM_BLE_CONNECT_DIR_EVT)
+    {
+        if (p_cur->ble_addr_type != BLE_ADDR_RANDOM)
+        {
+            BTM_TRACE_DEBUG("BR/EDR NOT support bit not set, treat as DUMO");
+            p_cur->device_type |= BT_DEVICE_TYPE_DUMO;
+        } else {
+            BTM_TRACE_DEBUG("Random address, treating device as LE only");
+        }
+    }
+    else
+    {
+        BTM_TRACE_DEBUG("BR/EDR NOT SUPPORT bit set, LE only device");
+    }
+
+    return to_report;
+
+}
+
+/*******************************************************************************
+**
+** Function         btm_clear_all_pending_le_entry
+**
+** Description      This function is called to clear all LE pending entry in
+**                  inquiry database.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_clear_all_pending_le_entry(void)
+{
+    uint16_t     xx;
+    tINQ_DB_ENT  *p_ent = btm_cb.btm_inq_vars.inq_db;
+
+    for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++)
+    {
+        /* mark all pending LE entry as unused if an LE only device has scan response outstanding */
+        if ((p_ent->in_use) &&
+            (p_ent->inq_info.results.device_type == BT_DEVICE_TYPE_BLE) &&
+             !p_ent->scan_rsp)
+            p_ent->in_use = false;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_send_sel_conn_callback
+**
+** Description      send selection connection request callback.
+**
+** Parameters
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_send_sel_conn_callback(BD_ADDR remote_bda, uint8_t evt_type, uint8_t *p_data,
+                                UNUSED_ATTR uint8_t addr_type)
+{
+    uint8_t data_len, len;
+    uint8_t *p_dev_name, remname[31] = {0};
+
+    if (btm_cb.ble_ctr_cb.p_select_cback == NULL ||
+        /* non-connectable device */
+        (evt_type != BTM_BLE_EVT_CONN_ADV && evt_type != BTM_BLE_EVT_CONN_DIR_ADV))
+        return;
+
+    STREAM_TO_UINT8    (data_len, p_data);
+
+    /* get the device name if exist in ADV data */
+    if (data_len != 0)
+    {
+        p_dev_name = BTM_CheckAdvData(p_data, BTM_BLE_AD_TYPE_NAME_CMPL, &len);
+
+        if (p_dev_name == NULL)
+            p_dev_name = BTM_CheckAdvData(p_data, BTM_BLE_AD_TYPE_NAME_SHORT, &len);
+
+        if (p_dev_name)
+            memcpy(remname, p_dev_name, len);
+    }
+    /* allow connection */
+    if ((* btm_cb.ble_ctr_cb.p_select_cback)(remote_bda, remname))
+    {
+        /* terminate selective connection, initiate connection */
+        btm_ble_initiate_select_conn(remote_bda);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_process_adv_pkt
+**
+** Description      This function is called when adv packet report events are
+**                  received from the device. It updates the inquiry database.
+**                  If the inquiry database is full, the oldest entry is discarded.
+**
+** Parameters
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_process_adv_pkt (uint8_t *p_data)
+{
+    BD_ADDR             bda;
+    uint8_t             evt_type = 0, *p = p_data;
+    uint8_t             addr_type = 0;
+    uint8_t             num_reports;
+    uint8_t             data_len;
+#if (BLE_PRIVACY_SPT == TRUE)
+    bool                match = false;
+#endif
+
+    /* Only process the results if the inquiry is still active */
+    if (!BTM_BLE_IS_SCAN_ACTIVE(btm_cb.ble_ctr_cb.scan_activity))
+        return;
+
+    /* Extract the number of reports in this event. */
+    STREAM_TO_UINT8(num_reports, p);
+
+    while (num_reports--)
+    {
+        /* Extract inquiry results */
+        STREAM_TO_UINT8    (evt_type, p);
+        STREAM_TO_UINT8    (addr_type, p);
+        STREAM_TO_BDADDR   (bda, p);
+
+#if (BLE_PRIVACY_SPT == TRUE)
+        /* map address to security record */
+        match = btm_identity_addr_to_random_pseudo(bda, &addr_type, false);
+
+        BTM_TRACE_DEBUG("btm_ble_process_adv_pkt:bda= %0x:%0x:%0x:%0x:%0x:%0x",
+                                     bda[0],bda[1],bda[2],bda[3],bda[4],bda[5]);
+        /* always do RRA resolution on host */
+        if (!match && BTM_BLE_IS_RESOLVE_BDA(bda))
+        {
+            btm_ble_resolve_random_addr(bda, btm_ble_resolve_random_addr_on_adv, p_data);
+        }
+        else
+#endif
+            btm_ble_process_adv_pkt_cont(bda, addr_type, evt_type, p);
+
+        STREAM_TO_UINT8(data_len, p);
+
+        /* Advance to the next event data_len + rssi byte */
+        p += data_len + 1;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_process_adv_pkt_cont
+**
+** Description      This function is called after random address resolution is
+**                  done, and proceed to process adv packet.
+**
+** Parameters
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, uint8_t addr_type, uint8_t evt_type, uint8_t *p)
+{
+    tINQ_DB_ENT          *p_i;
+    tBTM_INQUIRY_VAR_ST  *p_inq = &btm_cb.btm_inq_vars;
+    tBTM_INQ_RESULTS_CB  *p_inq_results_cb = p_inq->p_inq_results_cb;
+    tBTM_INQ_RESULTS_CB  *p_obs_results_cb = btm_cb.ble_ctr_cb.p_obs_results_cb;
+    tBTM_BLE_INQ_CB      *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
+    bool        update = true;
+    uint8_t     result = 0;
+
+    p_i = btm_inq_db_find (bda);
+
+    /* Check if this address has already been processed for this inquiry */
+    if (btm_inq_find_bdaddr(bda))
+    {
+        /* never been report as an LE device */
+        if (p_i &&
+            (!(p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BLE) ||
+              /* scan repsonse to be updated */
+              (!p_i->scan_rsp)))
+        {
+            update = true;
+        }
+        else if (BTM_BLE_IS_OBS_ACTIVE(btm_cb.ble_ctr_cb.scan_activity))
+        {
+            update = false;
+        }
+        else
+        {
+            /* if yes, skip it */
+            return; /* assumption: one result per event */
+        }
+    }
+    /* If existing entry, use that, else get  a new one (possibly reusing the oldest) */
+    if (p_i == NULL)
+    {
+        if ((p_i = btm_inq_db_new (bda)) != NULL)
+        {
+            p_inq->inq_cmpl_info.num_resp++;
+        }
+        else
+            return;
+    }
+    else if (p_i->inq_count != p_inq->inq_counter) /* first time seen in this inquiry */
+    {
+        p_inq->inq_cmpl_info.num_resp++;
+    }
+    /* update the LE device information in inquiry database */
+    if (!btm_ble_update_inq_result(p_i, addr_type, evt_type, p))
+        return;
+
+    if ((result = btm_ble_is_discoverable(bda, evt_type, p)) == 0)
+    {
+      LOG_WARN(LOG_TAG, "%s device is no longer discoverable so discarding advertising packet pkt",
+          __func__);
+        return;
+    }
+    if (!update)
+        result &= ~BTM_BLE_INQ_RESULT;
+    /* If the number of responses found and limited, issue a cancel inquiry */
+    if (p_inq->inqparms.max_resps &&
+        p_inq->inq_cmpl_info.num_resp == p_inq->inqparms.max_resps)
+    {
+        /* new device */
+        if (p_i == NULL ||
+            /* assume a DUMO device, BR/EDR inquiry is always active */
+            (p_i &&
+            (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE &&
+             p_i->scan_rsp))
+        {
+            BTM_TRACE_WARNING("INQ RES: Extra Response Received...cancelling inquiry..");
+
+            /* if is non-periodic inquiry active, cancel now */
+            if ((p_inq->inq_active & BTM_BR_INQ_ACTIVE_MASK) != 0 &&
+                (p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) == 0)
+                btsnd_hcic_inq_cancel();
+
+            btm_ble_stop_inquiry();
+
+            btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT);
+        }
+    }
+    /* background connection in selective connection mode */
+    if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_SELECTIVE)
+    {
+        if (result & BTM_BLE_SEL_CONN_RESULT)
+            btm_send_sel_conn_callback(bda, evt_type, p, addr_type);
+        else
+        {
+            BTM_TRACE_DEBUG("None LE device, can not initiate selective connection");
+        }
+    }
+    else
+    {
+        if (p_inq_results_cb && (result & BTM_BLE_INQ_RESULT))
+        {
+            (p_inq_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
+        }
+        if (p_obs_results_cb && (result & BTM_BLE_OBS_RESULT))
+        {
+            (p_obs_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_start_scan
+**
+** Description      Start the BLE scan.
+**
+** Returns          void
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_start_scan(void)
+{
+    tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var;
+
+    /* start scan, disable duplicate filtering */
+    btsnd_hcic_ble_set_scan_enable(BTM_BLE_SCAN_ENABLE, p_inq->scan_duplicate_filter);
+
+    if (p_inq->scan_type == BTM_BLE_SCAN_MODE_ACTI)
+        btm_ble_set_topology_mask(BTM_BLE_STATE_ACTIVE_SCAN_BIT);
+    else
+        btm_ble_set_topology_mask(BTM_BLE_STATE_PASSIVE_SCAN_BIT);
+
+    return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_stop_scan
+**
+** Description      Stop the BLE scan.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_stop_scan(void)
+{
+    BTM_TRACE_EVENT ("btm_ble_stop_scan ");
+
+    /* Clear the inquiry callback if set */
+    btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE;
+
+    /* stop discovery now */
+    btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
+
+    btm_update_scanner_filter_policy(SP_ADV_ALL);
+
+    btm_cb.ble_ctr_cb.wl_state &= ~BTM_BLE_WL_SCAN;
+}
+/*******************************************************************************
+**
+** Function         btm_ble_stop_inquiry
+**
+** Description      Stop the BLE Inquiry.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_stop_inquiry(void)
+{
+    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+    tBTM_BLE_CB *p_ble_cb = &btm_cb.ble_ctr_cb;
+
+    alarm_cancel(p_ble_cb->inq_var.inquiry_timer);
+
+    p_ble_cb->scan_activity &=  ~BTM_BLE_INQUIRY_MASK;
+
+    /* If no more scan activity, stop LE scan now */
+    if (!BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity))
+        btm_ble_stop_scan();
+    else if((p_ble_cb->inq_var.scan_interval != BTM_BLE_LOW_LATENCY_SCAN_INT) ||
+            (p_ble_cb->inq_var.scan_window != BTM_BLE_LOW_LATENCY_SCAN_WIN))
+    {
+        BTM_TRACE_DEBUG("%s: setting default params for ongoing observe", __func__);
+        btm_ble_stop_scan();
+        btm_ble_start_scan();
+    }
+
+    /* If we have a callback registered for inquiry complete, call it */
+    BTM_TRACE_DEBUG ("BTM Inq Compl Callback: status 0x%02x, num results %d",
+                      p_inq->inq_cmpl_info.status, p_inq->inq_cmpl_info.num_resp);
+
+    btm_process_inq_complete(HCI_SUCCESS, (uint8_t)(p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK));
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_stop_observe
+**
+** Description      Stop the BLE Observe.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_ble_stop_observe(void)
+{
+    tBTM_BLE_CB *p_ble_cb = & btm_cb.ble_ctr_cb;
+    tBTM_CMPL_CB *p_obs_cb = p_ble_cb->p_obs_cmpl_cb;
+
+    alarm_cancel(p_ble_cb->observer_timer);
+
+    p_ble_cb->scan_activity &= ~BTM_LE_OBSERVE_ACTIVE;
+
+    p_ble_cb->p_obs_results_cb = NULL;
+    p_ble_cb->p_obs_cmpl_cb = NULL;
+
+    if (!BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity))
+        btm_ble_stop_scan();
+
+    if (p_obs_cb)
+        (p_obs_cb)((tBTM_INQUIRY_CMPL *) &btm_cb.btm_inq_vars.inq_cmpl_info);
+}
+/*******************************************************************************
+**
+** Function         btm_ble_adv_states_operation
+**
+** Description      Set or clear adv states in topology mask
+**
+** Returns          operation status. true if sucessful, false otherwise.
+**
+*******************************************************************************/
+typedef bool    (BTM_TOPOLOGY_FUNC_PTR)(tBTM_BLE_STATE_MASK);
+static bool    btm_ble_adv_states_operation(BTM_TOPOLOGY_FUNC_PTR *p_handler, uint8_t adv_evt)
+{
+    bool    rt = false;
+
+    switch (adv_evt)
+    {
+    case BTM_BLE_CONNECT_EVT:
+        rt  = (*p_handler)(BTM_BLE_STATE_CONN_ADV_BIT);
+        break;
+
+    case  BTM_BLE_NON_CONNECT_EVT:
+        rt  = (*p_handler) (BTM_BLE_STATE_NON_CONN_ADV_BIT);
+        break;
+    case BTM_BLE_CONNECT_DIR_EVT:
+        rt  =  (*p_handler) (BTM_BLE_STATE_HI_DUTY_DIR_ADV_BIT);
+        break;
+
+    case BTM_BLE_DISCOVER_EVT:
+        rt  =  (*p_handler) (BTM_BLE_STATE_SCAN_ADV_BIT);
+        break;
+
+    case BTM_BLE_CONNECT_LO_DUTY_DIR_EVT:
+        rt = (*p_handler) (BTM_BLE_STATE_LO_DUTY_DIR_ADV_BIT);
+        break;
+
+    default:
+        BTM_TRACE_ERROR("unknown adv event : %d", adv_evt);
+        break;
+    }
+
+    return rt;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_start_adv
+**
+** Description      start the BLE advertising.
+**
+** Returns          void
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_start_adv(void)
+{
+    tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+    if (!btm_ble_adv_states_operation (btm_ble_topology_check, p_cb->evt_type))
+        return BTM_WRONG_MODE;
+
+#if (BLE_PRIVACY_SPT == TRUE)
+    /* To relax resolving list,  always have resolving list enabled, unless directed adv */
+    if (p_cb->evt_type != BTM_BLE_CONNECT_LO_DUTY_DIR_EVT &&
+        p_cb->evt_type != BTM_BLE_CONNECT_DIR_EVT)
+        /* enable resolving list is desired */
+        btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_ADV);
+#endif
+    if (p_cb->afp != AP_SCAN_CONN_ALL)
+    {
+        btm_execute_wl_dev_operation();
+        btm_cb.ble_ctr_cb.wl_state |= BTM_BLE_WL_ADV;
+    }
+
+    btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_ENABLE);
+    p_cb->adv_mode = BTM_BLE_ADV_ENABLE;
+    btm_ble_adv_states_operation(btm_ble_set_topology_mask, p_cb->evt_type);
+    return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_stop_adv
+**
+** Description      Stop the BLE advertising.
+**
+** Returns          void
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_stop_adv(void)
+{
+    tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+    if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE)
+    {
+        btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE);
+
+        p_cb->fast_adv_on = false;
+        p_cb->adv_mode = BTM_BLE_ADV_DISABLE;
+        btm_cb.ble_ctr_cb.wl_state &= ~BTM_BLE_WL_ADV;
+
+        /* clear all adv states */
+        btm_ble_clear_topology_mask (BTM_BLE_STATE_ALL_ADV_MASK);
+    }
+    return BTM_SUCCESS;
+}
+
+static void btm_ble_fast_adv_timer_timeout(UNUSED_ATTR void *data)
+{
+    /* fast adv is completed, fall back to slow adv interval */
+    btm_ble_start_slow_adv();
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_start_slow_adv
+**
+** Description      Restart adv with slow adv interval
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_ble_start_slow_adv(void)
+{
+    tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+    if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE)
+    {
+        tBTM_LE_RANDOM_CB *p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+        BD_ADDR p_addr_ptr = {0};
+        tBLE_ADDR_TYPE init_addr_type = BLE_ADDR_PUBLIC;
+        tBLE_ADDR_TYPE own_addr_type = p_addr_cb->own_addr_type;
+
+        btm_ble_stop_adv();
+
+        p_cb->evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &init_addr_type,
+                                                         &own_addr_type);
+
+        /* slow adv mode never goes into directed adv */
+        btsnd_hcic_ble_write_adv_params (BTM_BLE_GAP_ADV_SLOW_INT, BTM_BLE_GAP_ADV_SLOW_INT,
+                                         p_cb->evt_type, own_addr_type,
+                                         init_addr_type, p_addr_ptr,
+                                         p_cb->adv_chnl_map, p_cb->afp);
+
+        btm_ble_start_adv();
+    }
+}
+
+static void btm_ble_inquiry_timer_gap_limited_discovery_timeout(UNUSED_ATTR void *data)
+{
+    /* lim_timeout expired, limited discovery should exit now */
+    btm_cb.btm_inq_vars.discoverable_mode &= ~BTM_BLE_LIMITED_DISCOVERABLE;
+    btm_ble_set_adv_flag(btm_cb.btm_inq_vars.connectable_mode,
+                         btm_cb.btm_inq_vars.discoverable_mode);
+}
+
+static void btm_ble_inquiry_timer_timeout(UNUSED_ATTR void *data)
+{
+    btm_ble_stop_inquiry();
+}
+
+static void btm_ble_observer_timer_timeout(UNUSED_ATTR void *data)
+{
+    btm_ble_stop_observe();
+}
+
+void btm_ble_refresh_raddr_timer_timeout(UNUSED_ATTR void *data)
+{
+    if (btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type == BLE_ADDR_RANDOM) {
+        /* refresh the random addr */
+        btm_gen_resolvable_private_addr((void *)btm_gen_resolve_paddr_low);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_read_remote_features_complete
+**
+** Description      This function is called when the command complete message
+**                  is received from the HCI for the read LE remote feature supported
+**                  complete event.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_read_remote_features_complete(uint8_t *p)
+{
+    tACL_CONN        *p_acl_cb = &btm_cb.acl_db[0];
+    uint16_t          handle;
+    uint8_t           status;
+    int               xx;
+
+    BTM_TRACE_EVENT ("btm_ble_read_remote_features_complete ");
+
+    STREAM_TO_UINT8(status, p);
+
+    // if LE read remote feature failed for HCI_ERR_CONN_FAILED_ESTABLISHMENT,
+    // expect disconnect complete to be received
+    if (status != HCI_ERR_CONN_FAILED_ESTABLISHMENT)
+    {
+        STREAM_TO_UINT16 (handle, p);
+
+        /* Look up the connection by handle and copy features */
+        for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_acl_cb++)
+        {
+            if ((p_acl_cb->in_use) && (p_acl_cb->hci_handle == handle))
+            {
+                STREAM_TO_ARRAY(p_acl_cb->peer_le_features, p, BD_FEATURES_LEN);
+                btsnd_hcic_rmt_ver_req (p_acl_cb->hci_handle);
+                break;
+            }
+        }
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_write_adv_enable_complete
+**
+** Description      This function process the write adv enable command complete.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_write_adv_enable_complete(uint8_t * p)
+{
+    tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+    /* if write adv enable/disbale not succeed */
+    if (*p != HCI_SUCCESS)
+    {
+        /* toggle back the adv mode */
+        p_cb->adv_mode = !p_cb->adv_mode;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_dir_adv_tout
+**
+** Description      when directed adv time out
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_dir_adv_tout(void)
+{
+    btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
+
+    /* make device fall back into undirected adv mode by default */
+    btm_cb.ble_ctr_cb.inq_var.directed_conn = false;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_set_topology_mask
+**
+** Description      set BLE topology mask
+**
+** Returns          true is request is allowed, false otherwise.
+**
+*******************************************************************************/
+bool    btm_ble_set_topology_mask(tBTM_BLE_STATE_MASK request_state_mask)
+{
+    request_state_mask &= BTM_BLE_STATE_ALL_MASK;
+    btm_cb.ble_ctr_cb.cur_states |= (request_state_mask & BTM_BLE_STATE_ALL_MASK);
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_clear_topology_mask
+**
+** Description      Clear BLE topology bit mask
+**
+** Returns          true is request is allowed, false otherwise.
+**
+*******************************************************************************/
+bool    btm_ble_clear_topology_mask (tBTM_BLE_STATE_MASK request_state_mask)
+{
+    request_state_mask &= BTM_BLE_STATE_ALL_MASK;
+    btm_cb.ble_ctr_cb.cur_states &= ~request_state_mask;
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_update_link_topology_mask
+**
+** Description      This function update the link topology mask
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_update_link_topology_mask(uint8_t link_role, bool    increase)
+{
+    btm_ble_clear_topology_mask (BTM_BLE_STATE_ALL_CONN_MASK);
+
+    if (increase)
+        btm_cb.ble_ctr_cb.link_count[link_role]++;
+    else if (btm_cb.ble_ctr_cb.link_count[link_role] > 0)
+        btm_cb.ble_ctr_cb.link_count[link_role]--;
+
+    if (btm_cb.ble_ctr_cb.link_count[HCI_ROLE_MASTER])
+        btm_ble_set_topology_mask (BTM_BLE_STATE_MASTER_BIT);
+
+    if (btm_cb.ble_ctr_cb.link_count[HCI_ROLE_SLAVE])
+        btm_ble_set_topology_mask(BTM_BLE_STATE_SLAVE_BIT);
+
+    if (link_role == HCI_ROLE_SLAVE && increase)
+    {
+        btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
+        /* make device fall back into undirected adv mode by default */
+        btm_cb.ble_ctr_cb.inq_var.directed_conn = BTM_BLE_CONNECT_EVT;
+        /* clear all adv states */
+        btm_ble_clear_topology_mask(BTM_BLE_STATE_ALL_ADV_MASK);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_update_mode_operation
+**
+** Description      This function update the GAP role operation when a link status
+**                  is updated.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_update_mode_operation(uint8_t link_role, BD_ADDR bd_addr, uint8_t status)
+{
+    if (status == HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT)
+    {
+        btm_cb.ble_ctr_cb.inq_var.adv_mode  = BTM_BLE_ADV_DISABLE;
+        /* make device fall back into undirected adv mode by default */
+        btm_cb.ble_ctr_cb.inq_var.directed_conn = BTM_BLE_CONNECT_EVT;
+        /* clear all adv states */
+        btm_ble_clear_topology_mask (BTM_BLE_STATE_ALL_ADV_MASK);
+    }
+
+    if (btm_cb.ble_ctr_cb.inq_var.connectable_mode == BTM_BLE_CONNECTABLE)
+    {
+        btm_ble_set_connectability(btm_cb.btm_inq_vars.connectable_mode |
+                                   btm_cb.ble_ctr_cb.inq_var.connectable_mode);
+    }
+
+    /* when no connection is attempted, and controller is not rejecting last request
+       due to resource limitation, start next direct connection or background connection
+       now in order */
+    if (btm_ble_get_conn_st() == BLE_CONN_IDLE && status != HCI_ERR_HOST_REJECT_RESOURCES &&
+        !btm_send_pending_direct_conn())
+    {
+         btm_ble_resume_bg_conn();
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_init
+**
+** Description      Initialize the control block variable values.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_init(void)
+{
+    tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+
+    BTM_TRACE_DEBUG("%s", __func__);
+
+    alarm_free(p_cb->observer_timer);
+    alarm_free(p_cb->inq_var.fast_adv_timer);
+    memset(p_cb, 0, sizeof(tBTM_BLE_CB));
+    memset(&(btm_cb.cmn_ble_vsc_cb), 0 , sizeof(tBTM_BLE_VSC_CB));
+    btm_cb.cmn_ble_vsc_cb.values_read = false;
+
+    p_cb->observer_timer = alarm_new("btm_ble.observer_timer");
+    p_cb->cur_states       = 0;
+    p_cb->conn_pending_q = fixed_queue_new(SIZE_MAX);
+
+    p_cb->inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
+    p_cb->inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE;
+    p_cb->inq_var.adv_chnl_map = BTM_BLE_DEFAULT_ADV_CHNL_MAP;
+    p_cb->inq_var.afp = BTM_BLE_DEFAULT_AFP;
+    p_cb->inq_var.sfp = BTM_BLE_DEFAULT_SFP;
+    p_cb->inq_var.connectable_mode = BTM_BLE_NON_CONNECTABLE;
+    p_cb->inq_var.discoverable_mode = BTM_BLE_NON_DISCOVERABLE;
+    p_cb->inq_var.fast_adv_timer = alarm_new("btm_ble_inq.fast_adv_timer");
+    p_cb->inq_var.inquiry_timer = alarm_new("btm_ble_inq.inquiry_timer");
+
+    /* for background connection, reset connection params to be undefined */
+    p_cb->scan_int = p_cb->scan_win = BTM_BLE_SCAN_PARAM_UNDEF;
+
+    p_cb->inq_var.evt_type = BTM_BLE_NON_CONNECT_EVT;
+
+    p_cb->addr_mgnt_cb.refresh_raddr_timer =
+        alarm_new("btm_ble_addr.refresh_raddr_timer");
+
+#if (BLE_VND_INCLUDED == FALSE)
+    btm_ble_adv_filter_init();
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_topology_check
+**
+** Description      check to see requested state is supported. One state check at
+**                  a time is supported
+**
+** Returns          true is request is allowed, false otherwise.
+**
+*******************************************************************************/
+bool    btm_ble_topology_check(tBTM_BLE_STATE_MASK request_state_mask)
+{
+    bool    rt = false;
+
+    uint8_t state_offset = 0;
+    uint16_t cur_states = btm_cb.ble_ctr_cb.cur_states;
+    uint8_t mask, offset;
+    uint8_t request_state = 0;
+
+    /* check only one bit is set and within valid range */
+    if (request_state_mask == BTM_BLE_STATE_INVALID ||
+        request_state_mask > BTM_BLE_STATE_SCAN_ADV_BIT ||
+        (request_state_mask & (request_state_mask -1 )) != 0)
+    {
+        BTM_TRACE_ERROR("illegal state requested: %d", request_state_mask);
+        return rt;
+    }
+
+    while (request_state_mask)
+    {
+        request_state_mask >>= 1;
+        request_state ++;
+    }
+
+    /* check if the requested state is supported or not */
+    mask = btm_le_state_combo_tbl[0][request_state - 1][0];
+    offset = btm_le_state_combo_tbl[0][request_state-1][1];
+
+    const uint8_t *ble_supported_states = controller_get_interface()->get_ble_supported_states();
+
+    if (!BTM_LE_STATES_SUPPORTED(ble_supported_states, mask, offset))
+    {
+        BTM_TRACE_ERROR("state requested not supported: %d", request_state);
+        return rt;
+    }
+
+    rt = true;
+    /* make sure currently active states are all supported in conjunction with the requested
+       state. If the bit in table is not set, the combination is not supported */
+    while (cur_states != 0)
+    {
+        if (cur_states & 0x01)
+        {
+            mask = btm_le_state_combo_tbl[request_state][state_offset][0];
+            offset = btm_le_state_combo_tbl[request_state][state_offset][1];
+
+            if (mask != 0 && offset != 0)
+            {
+                if (!BTM_LE_STATES_SUPPORTED(ble_supported_states, mask, offset))
+                {
+                    rt = false;
+                    break;
+                }
+            }
+        }
+        cur_states >>= 1;
+        state_offset ++;
+    }
+    return rt;
+}
+
+#endif  /* BLE_INCLUDED */
diff --git a/bt/stack/btm/btm_ble_int.h b/bt/stack/btm/btm_ble_int.h
new file mode 100644
index 0000000..03b263f
--- /dev/null
+++ b/bt/stack/btm/btm_ble_int.h
@@ -0,0 +1,178 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 main Bluetooth Manager (BTM) internal
+ *  definitions.
+ *
+ ******************************************************************************/
+
+#ifndef BTM_BLE_INT_H
+#define BTM_BLE_INT_H
+
+#include "bt_target.h"
+#include "bt_common.h"
+#include "hcidefs.h"
+#include "btm_ble_api.h"
+#include "btm_int.h"
+
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+#include "smp_api.h"
+#endif
+
+#include "btm_ble_int_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void btm_ble_refresh_raddr_timer_timeout(void *data);
+extern void btm_ble_process_adv_pkt (uint8_t *p);
+extern void btm_ble_proc_scan_rsp_rpt (uint8_t *p);
+extern tBTM_STATUS btm_ble_read_remote_name(BD_ADDR remote_bda, tBTM_INQ_INFO *p_cur, tBTM_CMPL_CB *p_cb);
+extern bool    btm_ble_cancel_remote_name(BD_ADDR remote_bda);
+
+extern tBTM_STATUS btm_ble_set_discoverability(uint16_t combined_mode);
+extern tBTM_STATUS btm_ble_set_connectability(uint16_t combined_mode);
+extern tBTM_STATUS btm_ble_start_inquiry (uint8_t mode, uint8_t duration);
+extern void btm_ble_stop_scan(void);
+extern void btm_clear_all_pending_le_entry(void);
+
+extern void btm_ble_stop_scan();
+extern void btm_ble_send_extended_scan_params(uint8_t scan_type, uint32_t scan_int,
+                                                 uint32_t scan_win, uint8_t addr_type_own,
+                                                 uint8_t scan_filter_policy);
+extern void btm_ble_stop_inquiry(void);
+extern void btm_ble_init (void);
+extern void btm_ble_connected (uint8_t *bda, uint16_t handle, uint8_t enc_mode, uint8_t role, tBLE_ADDR_TYPE addr_type, bool    addr_matched);
+extern void btm_ble_read_remote_features_complete(uint8_t *p);
+extern void btm_ble_write_adv_enable_complete(uint8_t * p);
+extern void btm_ble_conn_complete(uint8_t *p, uint16_t evt_len, bool    enhanced);
+extern void btm_read_ble_local_supported_states_complete(uint8_t *p, uint16_t evt_len);
+extern tBTM_BLE_CONN_ST btm_ble_get_conn_st(void);
+extern void btm_ble_set_conn_st(tBTM_BLE_CONN_ST new_st);
+extern tBTM_STATUS btm_ble_start_adv(void);
+extern tBTM_STATUS btm_ble_stop_adv(void);
+extern tBTM_STATUS btm_ble_start_scan(void);
+extern void btm_ble_create_ll_conn_complete (uint8_t status);
+
+/* LE security function from btm_sec.cc */
+#if (SMP_INCLUDED == TRUE)
+extern void btm_ble_link_sec_check(BD_ADDR bd_addr, tBTM_LE_AUTH_REQ auth_req, tBTM_BLE_SEC_REQ_ACT *p_sec_req_act);
+extern void btm_ble_ltk_request_reply(BD_ADDR bda,  bool    use_stk, BT_OCTET16 stk);
+extern uint8_t btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data);
+extern tBTM_STATUS btm_ble_set_encryption (BD_ADDR bd_addr, tBTM_BLE_SEC_ACT sec_act, uint8_t link_role);
+extern void btm_ble_ltk_request(uint16_t handle, uint8_t rand[8], uint16_t ediv);
+extern tBTM_STATUS btm_ble_start_encrypt(BD_ADDR bda, bool    use_stk, BT_OCTET16 stk);
+extern void btm_ble_link_encrypted(BD_ADDR bd_addr, uint8_t encr_enable);
+#endif
+
+/* LE device management functions */
+extern void btm_ble_reset_id( void );
+
+/* security related functions */
+extern void btm_ble_increment_sign_ctr(BD_ADDR bd_addr, bool    is_local );
+extern bool    btm_get_local_div (BD_ADDR bd_addr, uint16_t *p_div);
+extern bool    btm_ble_get_enc_key_type(BD_ADDR bd_addr, uint8_t *p_key_types);
+
+extern void btm_ble_test_command_complete(uint8_t *p);
+extern void btm_ble_rand_enc_complete (uint8_t *p, uint16_t op_code, tBTM_RAND_ENC_CB *p_enc_cplt_cback);
+
+extern void btm_sec_save_le_key(BD_ADDR bd_addr, tBTM_LE_KEY_TYPE key_type, tBTM_LE_KEY_VALUE *p_keys, bool    pass_to_application);
+extern void btm_ble_update_sec_key_size(BD_ADDR bd_addr, uint8_t enc_key_size);
+extern uint8_t btm_ble_read_sec_key_size(BD_ADDR bd_addr);
+
+/* white list function */
+extern bool    btm_update_dev_to_white_list(bool    to_add, BD_ADDR bd_addr);
+extern void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy);
+extern void btm_update_adv_filter_policy(tBTM_BLE_AFP adv_policy);
+extern void btm_ble_clear_white_list (void);
+extern void btm_read_white_list_size_complete(uint8_t *p, uint16_t evt_len);
+extern void btm_ble_add_2_white_list_complete(uint8_t status);
+extern void btm_ble_remove_from_white_list_complete(uint8_t *p, uint16_t evt_len);
+extern void btm_ble_clear_white_list_complete(uint8_t *p, uint16_t evt_len);
+extern void btm_ble_white_list_init(uint8_t white_list_size);
+
+/* background connection function */
+extern bool    btm_ble_suspend_bg_conn(void);
+extern bool    btm_ble_resume_bg_conn(void);
+extern void btm_ble_initiate_select_conn(BD_ADDR bda);
+extern bool    btm_ble_start_auto_conn(bool    start);
+extern bool    btm_ble_start_select_conn(bool    start,tBTM_BLE_SEL_CBACK   *p_select_cback);
+extern bool    btm_ble_renew_bg_conn_params(bool    add, BD_ADDR bd_addr);
+extern void btm_write_dir_conn_wl(BD_ADDR target_addr);
+extern void btm_ble_update_mode_operation(uint8_t link_role, BD_ADDR bda, uint8_t status);
+extern bool    btm_execute_wl_dev_operation(void);
+extern void btm_ble_update_link_topology_mask(uint8_t role, bool    increase);
+
+/* direct connection utility */
+extern bool    btm_send_pending_direct_conn(void);
+extern void btm_ble_enqueue_direct_conn_req(void *p_param);
+extern void btm_ble_dequeue_direct_conn_req(BD_ADDR rem_bda);
+
+/* BLE address management */
+extern void btm_gen_resolvable_private_addr (void *p_cmd_cplt_cback);
+extern void btm_gen_non_resolvable_private_addr (tBTM_BLE_ADDR_CBACK *p_cback, void *p);
+extern void btm_ble_resolve_random_addr(BD_ADDR random_bda, tBTM_BLE_RESOLVE_CBACK * p_cback, void *p);
+extern void btm_gen_resolve_paddr_low(tBTM_RAND_ENC *p);
+
+/*  privacy function */
+#if (BLE_PRIVACY_SPT == TRUE)
+/* BLE address mapping with CS feature */
+extern bool    btm_identity_addr_to_random_pseudo(BD_ADDR bd_addr, uint8_t *p_addr_type, bool    refresh);
+extern bool    btm_random_pseudo_to_identity_addr(BD_ADDR random_pseudo, uint8_t *p_static_addr_type);
+extern void btm_ble_refresh_peer_resolvable_private_addr(BD_ADDR pseudo_bda, BD_ADDR rra, uint8_t rra_type);
+extern void btm_ble_refresh_local_resolvable_private_addr(BD_ADDR pseudo_addr, BD_ADDR local_rpa);
+extern void btm_ble_read_resolving_list_entry_complete(uint8_t *p, uint16_t evt_len) ;
+extern void btm_ble_remove_resolving_list_entry_complete(uint8_t *p, uint16_t evt_len);
+extern void btm_ble_add_resolving_list_entry_complete(uint8_t *p, uint16_t evt_len);
+extern void btm_ble_clear_resolving_list_complete(uint8_t *p, uint16_t evt_len);
+extern void btm_read_ble_resolving_list_size_complete (uint8_t *p, uint16_t evt_len);
+extern void btm_ble_enable_resolving_list(uint8_t);
+extern bool    btm_ble_disable_resolving_list(uint8_t rl_mask, bool    to_resume);
+extern void btm_ble_enable_resolving_list_for_platform (uint8_t rl_mask);
+extern void btm_ble_resolving_list_init(uint8_t max_irk_list_sz);
+extern void btm_ble_resolving_list_cleanup(void);
+#endif
+
+extern void btm_ble_multi_adv_init(void);
+extern void* btm_ble_multi_adv_get_ref(uint8_t inst_id);
+extern void btm_ble_multi_adv_cleanup(void);
+extern void btm_ble_batchscan_init(void);
+extern void btm_ble_batchscan_cleanup(void);
+extern void btm_ble_adv_filter_init(void);
+extern void btm_ble_adv_filter_cleanup(void);
+extern bool    btm_ble_topology_check(tBTM_BLE_STATE_MASK request);
+extern bool    btm_ble_clear_topology_mask(tBTM_BLE_STATE_MASK request_state);
+extern bool    btm_ble_set_topology_mask(tBTM_BLE_STATE_MASK request_state);
+
+#if (BTM_BLE_CONFORMANCE_TESTING == TRUE)
+extern void btm_ble_set_no_disc_if_pair_fail (bool    disble_disc);
+extern void btm_ble_set_test_mac_value (bool    enable, uint8_t *p_test_mac_val);
+extern void btm_ble_set_test_local_sign_cntr_value(bool    enable, uint32_t test_local_sign_cntr);
+extern void btm_set_random_address(BD_ADDR random_bda);
+extern void btm_ble_set_keep_rfu_in_auth_req(bool    keep_rfu);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bt/stack/btm/btm_ble_int_types.h b/bt/stack/btm/btm_ble_int_types.h
new file mode 100644
index 0000000..cb16b03
--- /dev/null
+++ b/bt/stack/btm/btm_ble_int_types.h
@@ -0,0 +1,339 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTM_BLE_INT_TYPES_H
+#define BTM_BLE_INT_TYPES_H
+
+#include "osi/include/alarm.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* scanning enable status */
+#define BTM_BLE_SCAN_ENABLE      0x01
+#define BTM_BLE_SCAN_DISABLE     0x00
+
+/* advertising enable status */
+#define BTM_BLE_ADV_ENABLE     0x01
+#define BTM_BLE_ADV_DISABLE    0x00
+
+/* use the high 4 bits unused by inquiry mode */
+#define BTM_BLE_SELECT_SCAN     0x20
+#define BTM_BLE_NAME_REQUEST    0x40
+#define BTM_BLE_OBSERVE         0x80
+
+#define BTM_BLE_MAX_WL_ENTRY        1
+#define BTM_BLE_AD_DATA_LEN         31
+
+#define BTM_BLE_ENC_MASK    0x03
+
+#define BTM_BLE_DUPLICATE_ENABLE        1
+#define BTM_BLE_DUPLICATE_DISABLE       0
+
+#define BTM_BLE_GAP_DISC_SCAN_INT      18         /* Interval(scan_int) = 11.25 ms= 0x0010 * 0.625 ms */
+#define BTM_BLE_GAP_DISC_SCAN_WIN      18         /* scan_window = 11.25 ms= 0x0010 * 0.625 ms */
+#define BTM_BLE_GAP_ADV_INT            512        /* Tgap(gen_disc) = 1.28 s= 512 * 0.625 ms */
+#define BTM_BLE_GAP_LIM_TIMEOUT_MS     (180 * 1000) /* Tgap(lim_timeout) = 180s max */
+#define BTM_BLE_LOW_LATENCY_SCAN_INT   8000       /* Interval(scan_int) = 5s= 8000 * 0.625 ms */
+#define BTM_BLE_LOW_LATENCY_SCAN_WIN   8000       /* scan_window = 5s= 8000 * 0.625 ms */
+
+
+#define BTM_BLE_GAP_ADV_FAST_INT_1         48         /* TGAP(adv_fast_interval1) = 30(used) ~ 60 ms  = 48 *0.625 */
+#define BTM_BLE_GAP_ADV_FAST_INT_2         160         /* TGAP(adv_fast_interval2) = 100(used) ~ 150 ms = 160 * 0.625 ms */
+#define BTM_BLE_GAP_ADV_SLOW_INT           2048         /* Tgap(adv_slow_interval) = 1.28 s= 512 * 0.625 ms */
+#define BTM_BLE_GAP_ADV_DIR_MAX_INT        800         /* Tgap(dir_conn_adv_int_max) = 500 ms = 800 * 0.625 ms */
+#define BTM_BLE_GAP_ADV_DIR_MIN_INT        400         /* Tgap(dir_conn_adv_int_min) = 250 ms = 400 * 0.625 ms */
+
+#define BTM_BLE_GAP_FAST_ADV_TIMEOUT_MS    (30 * 1000)
+
+#define BTM_BLE_SEC_REQ_ACT_NONE           0
+#define BTM_BLE_SEC_REQ_ACT_ENCRYPT        1 /* encrypt the link using current key or key refresh */
+#define BTM_BLE_SEC_REQ_ACT_PAIR           2
+#define BTM_BLE_SEC_REQ_ACT_DISCARD        3 /* discard the sec request while encryption is started but not completed */
+typedef uint8_t tBTM_BLE_SEC_REQ_ACT;
+
+#define BLE_STATIC_PRIVATE_MSB_MASK          0x3f
+#define BLE_RESOLVE_ADDR_MSB                 0x40   /*  most significant bit, bit7, bit6 is 01 to be resolvable random */
+#define BLE_RESOLVE_ADDR_MASK                0xc0   /* bit 6, and bit7 */
+#define BTM_BLE_IS_RESOLVE_BDA(x)           (((x)[0] & BLE_RESOLVE_ADDR_MASK) == BLE_RESOLVE_ADDR_MSB)
+
+#define BLE_PUBLIC_ADDR_MSB_MASK            0xC0
+#define BLE_PUBLIC_ADDR_MSB                 0x80   /*  most significant bit, bit7, bit6 is 10 to be public address*/
+#define BTM_IS_PUBLIC_BDA(x)               (((x)[0]  & BLE_PUBLIC_ADDR_MSB_MASK) == BLE_PUBLIC_ADDR_MSB)
+
+/* LE scan activity bit mask, continue with LE inquiry bits */
+#define BTM_LE_SELECT_CONN_ACTIVE      0x40     /* selection connection is in progress */
+#define BTM_LE_OBSERVE_ACTIVE          0x80     /* observe is in progress */
+
+/* BLE scan activity mask checking */
+#define BTM_BLE_IS_SCAN_ACTIVE(x)   ((x) & BTM_BLE_SCAN_ACTIVE_MASK)
+#define BTM_BLE_IS_INQ_ACTIVE(x)   ((x) & BTM_BLE_INQUIRY_MASK)
+#define BTM_BLE_IS_OBS_ACTIVE(x)   ((x) & BTM_LE_OBSERVE_ACTIVE)
+#define BTM_BLE_IS_SEL_CONN_ACTIVE(x)   ((x) & BTM_LE_SELECT_CONN_ACTIVE)
+
+/* BLE ADDR type ID bit */
+#define BLE_ADDR_TYPE_ID_BIT 0x02
+
+#define BTM_VSC_CHIP_CAPABILITY_L_VERSION 55
+#define BTM_VSC_CHIP_CAPABILITY_M_VERSION 95
+
+typedef struct
+{
+    uint16_t            data_mask;
+    uint8_t             *p_flags;
+    uint8_t             ad_data[BTM_BLE_AD_DATA_LEN];
+    uint8_t             *p_pad;
+}tBTM_BLE_LOCAL_ADV_DATA;
+
+typedef struct
+{
+    uint32_t        inq_count;          /* Used for determining if a response has already been      */
+                                        /* received for the current inquiry operation. (We do not   */
+                                        /* want to flood the caller with multiple responses from    */
+                                        /* the same device.                                         */
+    bool            scan_rsp;
+    tBLE_BD_ADDR    le_bda;
+} tINQ_LE_BDADDR;
+
+#define BTM_BLE_ADV_DATA_LEN_MAX        31
+#define BTM_BLE_CACHE_ADV_DATA_MAX      62
+
+#define BTM_BLE_ISVALID_PARAM(x, min, max)  (((x) >= (min) && (x) <= (max)) || ((x) == BTM_BLE_CONN_PARAM_UNDEF))
+
+/* 15 minutes minimum for random address refreshing */
+#define BTM_BLE_PRIVATE_ADDR_INT_MS     (15 * 60 * 1000)
+
+typedef struct
+{
+    uint16_t discoverable_mode;
+    uint16_t connectable_mode;
+    uint32_t scan_window;
+    uint32_t scan_interval;
+    uint8_t scan_type; /* current scan type: active or passive */
+    uint8_t scan_duplicate_filter; /* duplicate filter enabled for scan */
+    uint16_t adv_interval_min;
+    uint16_t adv_interval_max;
+    tBTM_BLE_AFP afp; /* advertising filter policy */
+    tBTM_BLE_SFP sfp; /* scanning filter policy */
+
+    tBLE_ADDR_TYPE adv_addr_type;
+    uint8_t evt_type;
+    uint8_t adv_mode;
+    tBLE_BD_ADDR direct_bda;
+    tBTM_BLE_EVT directed_conn;
+    bool    fast_adv_on;
+    alarm_t *fast_adv_timer;
+
+    uint8_t adv_len;
+    uint8_t adv_data_cache[BTM_BLE_CACHE_ADV_DATA_MAX];
+
+    /* inquiry BD addr database */
+    uint8_t num_bd_entries;
+    uint8_t max_bd_entries;
+    tBTM_BLE_LOCAL_ADV_DATA adv_data;
+    tBTM_BLE_ADV_CHNL_MAP adv_chnl_map;
+
+    alarm_t *inquiry_timer;
+    bool    scan_rsp;
+    uint8_t state; /* Current state that the inquiry process is in */
+    int8_t tx_power;
+} tBTM_BLE_INQ_CB;
+
+
+/* random address resolving complete callback */
+typedef void (tBTM_BLE_RESOLVE_CBACK) (void * match_rec, void *p);
+
+typedef void (tBTM_BLE_ADDR_CBACK) (BD_ADDR_PTR static_random, void *p);
+
+/* random address management control block */
+typedef struct
+{
+    tBLE_ADDR_TYPE              own_addr_type;         /* local device LE address type */
+    BD_ADDR                     private_addr;
+    BD_ADDR                     random_bda;
+    bool                        busy;
+    tBTM_BLE_ADDR_CBACK         *p_generate_cback;
+    void                        *p;
+    alarm_t                     *refresh_raddr_timer;
+} tBTM_LE_RANDOM_CB;
+
+#define BTM_BLE_MAX_BG_CONN_DEV_NUM    10
+
+typedef struct
+{
+    uint16_t            min_conn_int;
+    uint16_t            max_conn_int;
+    uint16_t            slave_latency;
+    uint16_t            supervision_tout;
+
+}tBTM_LE_CONN_PRAMS;
+
+
+typedef struct
+{
+    BD_ADDR     bd_addr;
+    uint8_t     attr;
+    bool        is_connected;
+    bool        in_use;
+}tBTM_LE_BG_CONN_DEV;
+
+  /* white list using state as a bit mask */
+#define BTM_BLE_WL_IDLE         0
+#define BTM_BLE_WL_INIT         1
+#define BTM_BLE_WL_SCAN         2
+#define BTM_BLE_WL_ADV          4
+typedef uint8_t tBTM_BLE_WL_STATE;
+
+/* resolving list using state as a bit mask */
+#define BTM_BLE_RL_IDLE         0
+#define BTM_BLE_RL_INIT         1
+#define BTM_BLE_RL_SCAN         2
+#define BTM_BLE_RL_ADV          4
+typedef uint8_t tBTM_BLE_RL_STATE;
+
+/* BLE connection state */
+#define BLE_CONN_IDLE    0
+#define BLE_DIR_CONN     1
+#define BLE_BG_CONN      2
+#define BLE_CONN_CANCEL  3
+typedef uint8_t tBTM_BLE_CONN_ST;
+
+typedef struct
+{
+    void    *p_param;
+}tBTM_BLE_CONN_REQ;
+
+/* LE state request */
+#define BTM_BLE_STATE_INVALID               0
+#define BTM_BLE_STATE_CONN_ADV              1
+#define BTM_BLE_STATE_INIT                  2
+#define BTM_BLE_STATE_MASTER                3
+#define BTM_BLE_STATE_SLAVE                 4
+#define BTM_BLE_STATE_LO_DUTY_DIR_ADV       5
+#define BTM_BLE_STATE_HI_DUTY_DIR_ADV       6
+#define BTM_BLE_STATE_NON_CONN_ADV          7
+#define BTM_BLE_STATE_PASSIVE_SCAN          8
+#define BTM_BLE_STATE_ACTIVE_SCAN           9
+#define BTM_BLE_STATE_SCAN_ADV              10
+#define BTM_BLE_STATE_MAX                   11
+typedef uint8_t tBTM_BLE_STATE;
+
+#define BTM_BLE_STATE_CONN_ADV_BIT          0x0001
+#define BTM_BLE_STATE_INIT_BIT              0x0002
+#define BTM_BLE_STATE_MASTER_BIT            0x0004
+#define BTM_BLE_STATE_SLAVE_BIT             0x0008
+#define BTM_BLE_STATE_LO_DUTY_DIR_ADV_BIT   0x0010
+#define BTM_BLE_STATE_HI_DUTY_DIR_ADV_BIT   0x0020
+#define BTM_BLE_STATE_NON_CONN_ADV_BIT      0x0040
+#define BTM_BLE_STATE_PASSIVE_SCAN_BIT      0x0080
+#define BTM_BLE_STATE_ACTIVE_SCAN_BIT       0x0100
+#define BTM_BLE_STATE_SCAN_ADV_BIT          0x0200
+typedef uint16_t tBTM_BLE_STATE_MASK;
+
+#define BTM_BLE_STATE_ALL_MASK              0x03ff
+#define BTM_BLE_STATE_ALL_ADV_MASK          (BTM_BLE_STATE_CONN_ADV_BIT|BTM_BLE_STATE_LO_DUTY_DIR_ADV_BIT|BTM_BLE_STATE_HI_DUTY_DIR_ADV_BIT|BTM_BLE_STATE_SCAN_ADV_BIT)
+#define BTM_BLE_STATE_ALL_SCAN_MASK         (BTM_BLE_STATE_PASSIVE_SCAN_BIT|BTM_BLE_STATE_ACTIVE_SCAN_BIT)
+#define BTM_BLE_STATE_ALL_CONN_MASK         (BTM_BLE_STATE_MASTER_BIT|BTM_BLE_STATE_SLAVE_BIT)
+
+#ifndef BTM_LE_RESOLVING_LIST_MAX
+#define BTM_LE_RESOLVING_LIST_MAX     0x20
+#endif
+
+typedef struct
+{
+    BD_ADDR         *resolve_q_random_pseudo;
+    uint8_t         *resolve_q_action;
+    uint8_t         q_next;
+    uint8_t         q_pending;
+} tBTM_BLE_RESOLVE_Q;
+
+typedef struct
+{
+    bool        in_use;
+    bool        to_add;
+    BD_ADDR     bd_addr;
+    uint8_t     attr;
+}tBTM_BLE_WL_OP;
+
+/* BLE privacy mode */
+#define BTM_PRIVACY_NONE    0              /* BLE no privacy */
+#define BTM_PRIVACY_1_1     1              /* BLE privacy 1.1, do not support privacy 1.0 */
+#define BTM_PRIVACY_1_2     2              /* BLE privacy 1.2 */
+#define BTM_PRIVACY_MIXED   3              /* BLE privacy mixed mode, broadcom propietary mode */
+typedef uint8_t tBTM_PRIVACY_MODE;
+
+/* data length change event callback */
+typedef void (tBTM_DATA_LENGTH_CHANGE_CBACK) (uint16_t max_tx_length, uint16_t max_rx_length);
+
+/* Define BLE Device Management control structure
+*/
+typedef struct
+{
+    uint8_t scan_activity;         /* LE scan activity mask */
+
+    /*****************************************************
+    **      BLE Inquiry
+    *****************************************************/
+    tBTM_BLE_INQ_CB inq_var;
+
+    /* observer callback and timer */
+    tBTM_INQ_RESULTS_CB *p_obs_results_cb;
+    tBTM_CMPL_CB *p_obs_cmpl_cb;
+    alarm_t *observer_timer;
+
+    /* background connection procedure cb value */
+    tBTM_BLE_CONN_TYPE bg_conn_type;
+    uint32_t scan_int;
+    uint32_t scan_win;
+    tBTM_BLE_SEL_CBACK *p_select_cback;
+
+    /* white list information */
+    uint8_t white_list_avail_size;
+    tBTM_BLE_WL_STATE wl_state;
+
+    fixed_queue_t *conn_pending_q;
+    tBTM_BLE_CONN_ST conn_state;
+
+    /* random address management control block */
+    tBTM_LE_RANDOM_CB addr_mgnt_cb;
+
+    bool    enabled;
+
+#if (BLE_PRIVACY_SPT == TRUE)
+    bool    mixed_mode; /* privacy 1.2 mixed mode is on or not */
+    tBTM_PRIVACY_MODE privacy_mode; /* privacy mode */
+    uint8_t resolving_list_avail_size; /* resolving list available size */
+    tBTM_BLE_RESOLVE_Q resolving_list_pend_q; /* Resolving list queue */
+    tBTM_BLE_RL_STATE suspended_rl_state; /* Suspended resolving list state */
+    uint8_t *irk_list_mask; /* IRK list availability mask, up to max entry bits */
+    tBTM_BLE_RL_STATE rl_state; /* Resolving list state */
+#endif
+
+    tBTM_BLE_WL_OP wl_op_q[BTM_BLE_MAX_BG_CONN_DEV_NUM];
+
+    /* current BLE link state */
+    tBTM_BLE_STATE_MASK cur_states; /* bit mask of tBTM_BLE_STATE */
+    uint8_t link_count[2]; /* total link count master and slave*/
+} tBTM_BLE_CB;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BTM_BLE_INT_TYPES_H
diff --git a/bt/stack/btm/btm_ble_multi_adv.cc b/bt/stack/btm/btm_ble_multi_adv.cc
new file mode 100644
index 0000000..76500ec
--- /dev/null
+++ b/bt/stack/btm/btm_ble_multi_adv.cc
@@ -0,0 +1,469 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014  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.
+ *
+ ******************************************************************************/
+
+#include <base/bind.h>
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+#include <string.h>
+#include <queue>
+#include <vector>
+
+#include "bt_target.h"
+#include "device/include/controller.h"
+#include "osi/include/alarm.h"
+
+#if (BLE_INCLUDED == TRUE)
+#include "ble_advertiser.h"
+#include "ble_advertiser_hci_interface.h"
+#include "btm_int_types.h"
+
+using base::Bind;
+using multiadv_cb = base::Callback<void(uint8_t /* status */)>;
+
+struct AdvertisingInstance {
+  uint8_t inst_id;
+  bool in_use;
+  uint8_t adv_evt;
+  BD_ADDR rpa;
+  alarm_t *adv_raddr_timer;
+  int8_t tx_power;
+  int timeout_s;
+  MultiAdvCb timeout_cb;
+  alarm_t *timeout_timer;
+  AdvertisingInstance(int inst_id)
+      : inst_id(inst_id),
+        in_use(false),
+        adv_evt(0),
+        rpa{0},
+        tx_power(0),
+        timeout_s(0),
+        timeout_cb(),
+        timeout_timer(nullptr) {
+    adv_raddr_timer = alarm_new_periodic("btm_ble.adv_raddr_timer");
+  }
+
+  ~AdvertisingInstance() {
+    alarm_free(adv_raddr_timer);
+    if (timeout_timer) alarm_free(timeout_timer);
+  }
+};
+
+/************************************************************************************
+**  Externs
+************************************************************************************/
+extern fixed_queue_t *btu_general_alarm_queue;
+
+void DoNothing(uint8_t) {}
+
+std::queue<base::Callback<void(tBTM_RAND_ENC *p)>> *rand_gen_inst_id = nullptr;
+
+/* RPA generation completion callback for each adv instance. Will continue write
+ * the new RPA into controller. */
+void btm_ble_multi_adv_gen_rpa_cmpl(tBTM_RAND_ENC *p) {
+  /* Retrieve the index of adv instance from stored Q */
+  base::Callback<void(tBTM_RAND_ENC * p)> cb = rand_gen_inst_id->front();
+  rand_gen_inst_id->pop();
+  cb.Run(p);
+}
+
+void btm_ble_adv_raddr_timer_timeout(void *data);
+
+class BleAdvertisingManagerImpl
+    : public BleAdvertisingManager,
+      public BleAdvertiserHciInterface::AdvertisingEventObserver {
+ public:
+  BleAdvertisingManagerImpl(BleAdvertiserHciInterface *interface) {
+    this->hci_interface = interface;
+    hci_interface->ReadInstanceCount(base::Bind(
+        &BleAdvertisingManagerImpl::ReadInstanceCountCb, base::Unretained(this)));
+  }
+
+  ~BleAdvertisingManagerImpl() { adv_inst.clear(); }
+
+  void ReadInstanceCountCb(uint8_t instance_count) {
+    this->inst_count = instance_count;
+    adv_inst.reserve(inst_count);
+    /* Initialize adv instance indices and IDs. */
+    for (uint8_t i = 0; i < inst_count; i++) {
+      adv_inst.emplace_back(i + 1);
+    }
+  }
+
+  void OnRpaGenerationComplete(uint8_t inst_id, tBTM_RAND_ENC *p) {
+#if (SMP_INCLUDED == TRUE)
+    AdvertisingInstance *p_inst = &adv_inst[inst_id - 1];
+
+    LOG(INFO) << "inst_id = " << +p_inst->inst_id;
+
+    if (!p) return;
+
+    p->param_buf[2] &= (~BLE_RESOLVE_ADDR_MASK);
+    p->param_buf[2] |= BLE_RESOLVE_ADDR_MSB;
+
+    p_inst->rpa[2] = p->param_buf[0];
+    p_inst->rpa[1] = p->param_buf[1];
+    p_inst->rpa[0] = p->param_buf[2];
+
+    BT_OCTET16 irk;
+    BTM_GetDeviceIDRoot(irk);
+    tSMP_ENC output;
+
+    if (!SMP_Encrypt(irk, BT_OCTET16_LEN, p->param_buf, 3, &output))
+      LOG_ASSERT(false) << "SMP_Encrypt failed";
+
+    /* set hash to be LSB of rpAddress */
+    p_inst->rpa[5] = output.param_buf[0];
+    p_inst->rpa[4] = output.param_buf[1];
+    p_inst->rpa[3] = output.param_buf[2];
+
+    if (p_inst->inst_id != BTM_BLE_MULTI_ADV_DEFAULT_STD &&
+        p_inst->inst_id < inst_count) {
+      /* set it to controller */
+      GetHciInterface()->SetRandomAddress(p_inst->rpa, p_inst->inst_id,
+                                          Bind(DoNothing));
+    }
+#endif
+  }
+
+  void ConfigureRpa(uint8_t inst_id) {
+    if (rand_gen_inst_id == nullptr)
+      rand_gen_inst_id =
+          new std::queue<base::Callback<void(tBTM_RAND_ENC * p)>>();
+
+    rand_gen_inst_id->push(
+        Bind(&BleAdvertisingManagerImpl::OnRpaGenerationComplete,
+             base::Unretained(this), inst_id));
+    btm_gen_resolvable_private_addr((void *)btm_ble_multi_adv_gen_rpa_cmpl);
+  }
+
+  void RegisterAdvertiser(
+      base::Callback<void(uint8_t /* inst_id */, uint8_t /* status */)> cb)
+      override {
+    if (inst_count == 0) {
+      LOG(ERROR) << "multi adv not supported";
+      cb.Run(0xFF, BTM_BLE_MULTI_ADV_FAILURE);
+      return;
+    }
+
+    AdvertisingInstance *p_inst = &adv_inst[0];
+    for (uint8_t i = 0; i < inst_count - 1;
+         i++, p_inst++) {
+      if (!p_inst->in_use) {
+        p_inst->in_use = TRUE;
+
+#if (BLE_PRIVACY_SPT == TRUE)
+        // configure the address, and set up periodic timer to update it.
+        ConfigureRpa(p_inst->inst_id);
+
+        if (BTM_BleLocalPrivacyEnabled()) {
+          alarm_set_on_queue(
+              p_inst->adv_raddr_timer, BTM_BLE_PRIVATE_ADDR_INT_MS,
+              btm_ble_adv_raddr_timer_timeout, p_inst, btu_general_alarm_queue);
+        }
+#endif
+
+        cb.Run(p_inst->inst_id, BTM_BLE_MULTI_ADV_SUCCESS);
+        return;
+      }
+    }
+
+    LOG(INFO) << "no free advertiser instance";
+    cb.Run(0xFF, BTM_BLE_MULTI_ADV_FAILURE);
+  }
+
+  void EnableWithTimerCb(uint8_t inst_id, int timeout_s, MultiAdvCb timeout_cb,
+                         uint8_t status) {
+    AdvertisingInstance *p_inst = &adv_inst[inst_id - 1];
+    p_inst->timeout_s = timeout_s;
+    p_inst->timeout_cb = std::move(timeout_cb);
+
+    p_inst->timeout_timer = alarm_new("btm_ble.adv_timeout");
+    alarm_set_on_queue(p_inst->timeout_timer, p_inst->timeout_s * 1000, nullptr,
+                       p_inst, btu_general_alarm_queue);
+  }
+
+  void Enable(uint8_t inst_id, bool enable, MultiAdvCb cb, int timeout_s,
+              MultiAdvCb timeout_cb) {
+    AdvertisingInstance *p_inst = &adv_inst[inst_id - 1];
+
+    VLOG(1) << __func__ << " inst_id: " << +inst_id << ", enable: " << enable;
+    if (inst_count == 0) {
+      LOG(ERROR) << "multi adv not supported";
+      return;
+    }
+
+    if (!p_inst || !p_inst->in_use) {
+      LOG(ERROR) << "Invalid or no active instance";
+      cb.Run(BTM_BLE_MULTI_ADV_FAILURE);
+      return;
+    }
+
+    if (enable && timeout_s) {
+      GetHciInterface()->Enable(
+          enable, p_inst->inst_id,
+          Bind(&BleAdvertisingManagerImpl::EnableWithTimerCb,
+               base::Unretained(this), inst_id, timeout_s, timeout_cb));
+    } else {
+      if (p_inst->timeout_timer) {
+        alarm_cancel(p_inst->timeout_timer);
+        alarm_free(p_inst->timeout_timer);
+        p_inst->timeout_timer = nullptr;
+      }
+
+      GetHciInterface()->Enable(enable, p_inst->inst_id, cb);
+    }
+  }
+
+  void SetParameters(uint8_t inst_id, tBTM_BLE_ADV_PARAMS *p_params,
+                     MultiAdvCb cb) override {
+    AdvertisingInstance *p_inst = &adv_inst[inst_id - 1];
+
+    VLOG(1) << __func__ << " inst_id:" << +inst_id;
+
+    if (inst_count == 0) {
+      LOG(ERROR) << "multi adv not supported";
+      return;
+    }
+
+    if (inst_id > inst_count || inst_id < 0 ||
+        inst_id == BTM_BLE_MULTI_ADV_DEFAULT_STD) {
+      LOG(ERROR) << "bad instance id " << +inst_id;
+      return;
+    }
+
+    if (!p_inst->in_use) {
+      LOG(ERROR) << "adv instance not in use" << +inst_id;
+      cb.Run(BTM_BLE_MULTI_ADV_FAILURE);
+      return;
+    }
+
+    // TODO: disable only if was enabled, currently no use scenario needs that,
+    // we always set parameters before enabling
+    // GetHciInterface()->Enable(false, inst_id, Bind(DoNothing));
+
+    uint8_t own_address_type = BLE_ADDR_PUBLIC;
+    BD_ADDR own_address;
+
+#if (BLE_PRIVACY_SPT == TRUE)
+    if (BTM_BleLocalPrivacyEnabled()) {
+      own_address_type = BLE_ADDR_RANDOM;
+      memcpy(own_address, p_inst->rpa, BD_ADDR_LEN);
+    } else {
+#else
+    {
+#endif
+      memcpy(own_address, controller_get_interface()->get_address()->address,
+             BD_ADDR_LEN);
+    }
+
+    BD_ADDR dummy = {0, 0, 0, 0, 0, 0};
+
+    p_inst->adv_evt = p_params->adv_type;
+    p_inst->tx_power = p_params->tx_power;
+
+    GetHciInterface()->SetParameters(
+        p_params->adv_int_min, p_params->adv_int_max, p_params->adv_type,
+        own_address_type, own_address, 0, dummy, p_params->channel_map,
+        p_params->adv_filter_policy, p_inst->inst_id, p_inst->tx_power, cb);
+
+    // TODO: re-enable only if it was enabled, properly call
+    // SetParamsCallback
+    // currently no use scenario needs that
+    // GetHciInterface()->Enable(true, inst_id, BTM_BleUpdateAdvInstParamCb);
+  }
+
+  void SetData(uint8_t inst_id, bool is_scan_rsp, std::vector<uint8_t> data,
+               MultiAdvCb cb) override {
+    AdvertisingInstance *p_inst = &adv_inst[inst_id - 1];
+
+    VLOG(1) << "inst_id = " << +inst_id << ", is_scan_rsp = " << is_scan_rsp;
+
+    if (inst_count == 0) {
+      LOG(ERROR) << "multi adv not supported";
+      return;
+    }
+
+    if (!is_scan_rsp && p_inst->adv_evt != BTM_BLE_NON_CONNECT_EVT) {
+      uint8_t flags_val = BTM_GENERAL_DISCOVERABLE;
+
+      if (p_inst->timeout_s) flags_val = BTM_LIMITED_DISCOVERABLE;
+
+      std::vector<uint8_t> flags;
+      flags.push_back(2); // length
+      flags.push_back(HCI_EIR_FLAGS_TYPE);
+      flags.push_back(flags_val);
+
+      data.insert(data.begin(), flags.begin(), flags.end());
+    }
+
+    // Find and fill TX Power with the correct value
+    if (data.size()) {
+      size_t i = 0;
+      while (i < data.size()) {
+        uint8_t type = data[i + 1];
+        if (type == HCI_EIR_TX_POWER_LEVEL_TYPE) {
+          int8_t tx_power = adv_inst[inst_id - 1].tx_power;
+          data[i + 2] = tx_power;
+        }
+        i += data[i] + 1;
+      }
+    }
+
+    if (inst_id > inst_count || inst_id < 0 ||
+        inst_id == BTM_BLE_MULTI_ADV_DEFAULT_STD) {
+      LOG(ERROR) << "bad instance id " << +inst_id;
+      return;
+    }
+
+    VLOG(1) << "data is: " << base::HexEncode(data.data(), data.size());
+
+    if (is_scan_rsp) {
+      GetHciInterface()->SetScanResponseData(data.size(), data.data(), inst_id,
+                                             cb);
+    } else {
+      GetHciInterface()->SetAdvertisingData(data.size(), data.data(), inst_id,
+                                            cb);
+    }
+  }
+
+  void Unregister(uint8_t inst_id) override {
+    AdvertisingInstance *p_inst = &adv_inst[inst_id - 1];
+
+    VLOG(1) << __func__ << " inst_id: " << +inst_id;
+
+    if (inst_count == 0) {
+      LOG(ERROR) << "multi adv not supported";
+      return;
+    }
+
+    if (inst_id > inst_count || inst_id < 0 ||
+        inst_id == BTM_BLE_MULTI_ADV_DEFAULT_STD) {
+      LOG(ERROR) << "bad instance id " << +inst_id;
+      return;
+    }
+
+    // TODO(jpawlowski): only disable when enabled or enabling
+    GetHciInterface()->Enable(false, inst_id, Bind(DoNothing));
+
+    alarm_cancel(p_inst->adv_raddr_timer);
+    p_inst->in_use = false;
+  }
+
+  void OnAdvertisingStateChanged(uint8_t inst_id, uint8_t reason,
+                                 uint16_t conn_handle) override {
+    AdvertisingInstance *p_inst = &adv_inst[inst_id - 1];
+    VLOG(1) << __func__ << " inst_id: 0x" << std::hex << inst_id
+            << ", reason: 0x" << std::hex << reason << ", conn_handle: 0x"
+            << std::hex << conn_handle;
+
+#if (BLE_PRIVACY_SPT == TRUE)
+    if (BTM_BleLocalPrivacyEnabled() && inst_id <= BTM_BLE_MULTI_ADV_MAX &&
+        inst_id != BTM_BLE_MULTI_ADV_DEFAULT_STD) {
+      btm_acl_update_conn_addr(conn_handle, p_inst->rpa);
+    }
+#endif
+
+    if (inst_id < inst_count &&
+        inst_id != BTM_BLE_MULTI_ADV_DEFAULT_STD) {
+      VLOG(1) << "reneabling advertising";
+
+      if (p_inst->in_use == true) {
+        // TODO(jpawlowski): we don't really allow to do directed advertising
+        // right now. This should probably be removed, check with Andre.
+        if (p_inst->adv_evt != BTM_BLE_CONNECT_DIR_EVT) {
+          GetHciInterface()->Enable(true, inst_id, Bind(DoNothing));
+        } else {
+          /* mark directed adv as disabled if adv has been stopped */
+          p_inst->in_use = false;
+        }
+      }
+    } else if (inst_id == BTM_BLE_MULTI_ADV_DEFAULT_STD) {
+      /* re-enable connectibility */
+      uint16_t conn_mode = BTM_ReadConnectability(nullptr, nullptr);
+      if (conn_mode == BTM_BLE_CONNECTABLE) {
+        btm_ble_set_connectability(conn_mode);
+      }
+    }
+  }
+
+ private:
+  BleAdvertiserHciInterface *GetHciInterface() { return hci_interface; }
+
+  BleAdvertiserHciInterface *hci_interface = nullptr;
+  std::vector<AdvertisingInstance> adv_inst;
+  uint8_t inst_count;
+};
+
+namespace {
+BleAdvertisingManager *instance;
+}
+
+void BleAdvertisingManager::Initialize(BleAdvertiserHciInterface *interface) {
+  instance = new BleAdvertisingManagerImpl(interface);
+}
+
+BleAdvertisingManager *BleAdvertisingManager::Get() {
+  CHECK(instance);
+  return instance;
+};
+
+void BleAdvertisingManager::CleanUp() {
+  delete instance;
+  instance = nullptr;
+};
+
+void btm_ble_adv_raddr_timer_timeout(void *data) {
+  ((BleAdvertisingManagerImpl *)BleAdvertisingManager::Get())
+      ->ConfigureRpa(((AdvertisingInstance *)data)->inst_id);
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_multi_adv_init
+**
+** Description      This function initialize the multi adv control block.
+**
+** Parameters       None
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_multi_adv_init() {
+  BleAdvertiserHciInterface::Initialize();
+  BleAdvertisingManager::Initialize(
+      BleAdvertiserHciInterface::Get());
+  BleAdvertiserHciInterface::Get()->SetAdvertisingEventObserver(
+      (BleAdvertisingManagerImpl*)BleAdvertisingManager::Get());
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_multi_adv_cleanup
+**
+** Description      This function cleans up multi adv control block.
+**
+** Parameters
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_multi_adv_cleanup(void) {
+  BleAdvertisingManager::CleanUp();
+  BleAdvertiserHciInterface::CleanUp();
+}
+
+#endif
diff --git a/bt/stack/btm/btm_ble_privacy.cc b/bt/stack/btm/btm_ble_privacy.cc
new file mode 100644
index 0000000..a9a5c16
--- /dev/null
+++ b/bt/stack/btm/btm_ble_privacy.cc
@@ -0,0 +1,1011 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 functions for BLE controller based privacy.
+ *
+ ******************************************************************************/
+#include <string.h>
+#include "bt_target.h"
+
+#if (BLE_INCLUDED == TRUE && BLE_PRIVACY_SPT == TRUE)
+#include "bt_types.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "vendor_hcidefs.h"
+#include "btm_int.h"
+#include "device/include/controller.h"
+
+/* RPA offload VSC specifics */
+#define BTM_BLE_META_IRK_ENABLE         0x01
+#define BTM_BLE_META_ADD_IRK_ENTRY      0x02
+#define BTM_BLE_META_REMOVE_IRK_ENTRY   0x03
+#define BTM_BLE_META_CLEAR_IRK_LIST     0x04
+#define BTM_BLE_META_READ_IRK_ENTRY     0x05
+#define BTM_BLE_META_CS_RESOLVE_ADDR    0x00000001
+#define BTM_BLE_IRK_ENABLE_LEN          2
+
+#define BTM_BLE_META_ADD_IRK_LEN        24
+#define BTM_BLE_META_REMOVE_IRK_LEN     8
+#define BTM_BLE_META_CLEAR_IRK_LEN      1
+#define BTM_BLE_META_READ_IRK_LEN       2
+#define BTM_BLE_META_ADD_WL_ATTR_LEN    9
+
+/*******************************************************************************
+**         Functions implemented controller based privacy using Resolving List
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function         btm_ble_enq_resolving_list_pending
+**
+** Description      add target address into resolving pending operation queue
+**
+** Parameters       target_bda: target device address
+**                  add_entry: true for add entry, false for remove entry
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_enq_resolving_list_pending(BD_ADDR pseudo_bda, uint8_t op_code)
+{
+    tBTM_BLE_RESOLVE_Q *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
+
+    memcpy(p_q->resolve_q_random_pseudo[p_q->q_next], pseudo_bda, BD_ADDR_LEN);
+    p_q->resolve_q_action[p_q->q_next] = op_code;
+    p_q->q_next ++;
+    p_q->q_next %= controller_get_interface()->get_ble_resolving_list_max_size();
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_brcm_find_resolving_pending_entry
+**
+** Description      check to see if the action is in pending list
+**
+** Parameters       true: action pending;
+**                  false: new action
+**
+** Returns          void
+**
+*******************************************************************************/
+bool    btm_ble_brcm_find_resolving_pending_entry(BD_ADDR pseudo_addr, uint8_t action)
+{
+    tBTM_BLE_RESOLVE_Q *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
+
+    for (uint8_t i = p_q->q_pending; i != p_q->q_next;)
+    {
+        if (memcmp(p_q->resolve_q_random_pseudo[i], pseudo_addr, BD_ADDR_LEN) == 0 &&
+            action == p_q->resolve_q_action[i])
+            return true;
+
+        i ++;
+        i %= controller_get_interface()->get_ble_resolving_list_max_size();
+    }
+    return false;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_deq_resolving_pending
+**
+** Description      dequeue target address from resolving pending operation queue
+**
+** Parameters       pseudo_addr: pseudo_addr device address
+**
+** Returns          void
+**
+*******************************************************************************/
+bool    btm_ble_deq_resolving_pending(BD_ADDR pseudo_addr)
+{
+    tBTM_BLE_RESOLVE_Q *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
+
+    if (p_q->q_next != p_q->q_pending)
+    {
+        memcpy(pseudo_addr, p_q->resolve_q_random_pseudo[p_q->q_pending], BD_ADDR_LEN);
+        memset(p_q->resolve_q_random_pseudo[p_q->q_pending], 0, BD_ADDR_LEN);
+        p_q->q_pending ++;
+        p_q->q_pending %= controller_get_interface()->get_ble_resolving_list_max_size();
+        return true;
+    }
+
+    return false;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_clear_irk_index
+**
+** Description      clear IRK list index mask for availability
+**
+** Returns          none
+**
+*******************************************************************************/
+void btm_ble_clear_irk_index(uint8_t index)
+{
+    uint8_t byte;
+    uint8_t bit;
+
+    if (index < controller_get_interface()->get_ble_resolving_list_max_size())
+    {
+         byte = index / 8;
+         bit = index % 8;
+         btm_cb.ble_ctr_cb.irk_list_mask[byte] &= (~(1 << bit));
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_find_irk_index
+**
+** Description      find the first available IRK list index
+**
+** Returns          index from 0 ~ max (127 default)
+**
+*******************************************************************************/
+uint8_t btm_ble_find_irk_index(void)
+{
+    uint8_t i = 0;
+    uint8_t byte;
+    uint8_t bit;
+
+    while (i < controller_get_interface()->get_ble_resolving_list_max_size())
+    {
+        byte = i / 8;
+        bit = i % 8;
+
+        if ((btm_cb.ble_ctr_cb.irk_list_mask[byte] & (1 << bit)) == 0)
+        {
+            btm_cb.ble_ctr_cb.irk_list_mask[byte] |= (1 << bit);
+            return i;
+        }
+        i++;
+    }
+
+    BTM_TRACE_ERROR ("%s failed, list full", __func__);
+    return i;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_update_resolving_list
+**
+** Description      update resolving list entry in host maintained record
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_update_resolving_list(BD_ADDR pseudo_bda, bool    add)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(pseudo_bda);
+    if (p_dev_rec == NULL)
+        return;
+
+    if (add)
+    {
+        p_dev_rec->ble.in_controller_list |= BTM_RESOLVING_LIST_BIT;
+        if (!controller_get_interface()->supports_ble_privacy())
+            p_dev_rec->ble.resolving_list_index = btm_ble_find_irk_index();
+    }
+    else
+    {
+        p_dev_rec->ble.in_controller_list &= ~BTM_RESOLVING_LIST_BIT;
+        if (!controller_get_interface()->supports_ble_privacy())
+        {
+           /* clear IRK list index mask */
+           btm_ble_clear_irk_index(p_dev_rec->ble.resolving_list_index);
+           p_dev_rec->ble.resolving_list_index = 0;
+        }
+    }
+}
+
+bool clear_resolving_list_bit(void *data, void *context)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = static_cast<tBTM_SEC_DEV_REC *>(data);
+    p_dev_rec->ble.in_controller_list &= ~BTM_RESOLVING_LIST_BIT;
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_clear_resolving_list_complete
+**
+** Description      This function is called when command complete for
+**                  clear resolving list
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_clear_resolving_list_complete(uint8_t *p, uint16_t evt_len)
+{
+    uint8_t status = 0;
+    STREAM_TO_UINT8(status, p);
+
+    BTM_TRACE_DEBUG("%s status=%d", __func__, status);
+
+    if (status == HCI_SUCCESS)
+    {
+        if (evt_len >= 3)
+        {
+            /* VSC complete has one extra byte for op code and list size, skip it here */
+            p ++;
+
+            /* updated the available list size, and current list size */
+            uint8_t irk_list_sz_max = 0;
+            STREAM_TO_UINT8(irk_list_sz_max, p);
+
+            if (controller_get_interface()->get_ble_resolving_list_max_size() == 0)
+                btm_ble_resolving_list_init(irk_list_sz_max);
+
+            uint8_t irk_mask_size = (irk_list_sz_max % 8) ?
+                            (irk_list_sz_max / 8 + 1) : (irk_list_sz_max / 8);
+            memset(btm_cb.ble_ctr_cb.irk_list_mask, 0, irk_mask_size);
+        }
+
+        btm_cb.ble_ctr_cb.resolving_list_avail_size =
+            controller_get_interface()->get_ble_resolving_list_max_size();
+
+        BTM_TRACE_DEBUG("%s resolving_list_avail_size=%d",
+                        __func__, btm_cb.ble_ctr_cb.resolving_list_avail_size);
+
+        list_foreach(btm_cb.sec_dev_rec, clear_resolving_list_bit, NULL);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_add_resolving_list_entry_complete
+**
+** Description      This function is called when command complete for
+**                  add resolving list entry
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_add_resolving_list_entry_complete(uint8_t *p, uint16_t evt_len)
+{
+    uint8_t status;
+    STREAM_TO_UINT8(status, p);
+
+    BTM_TRACE_DEBUG("%s status = %d", __func__, status);
+
+    BD_ADDR pseudo_bda;
+    if (!btm_ble_deq_resolving_pending(pseudo_bda))
+    {
+        BTM_TRACE_DEBUG("no pending resolving list operation");
+        return;
+    }
+
+    if (status == HCI_SUCCESS)
+    {
+        /* privacy 1.2 command complete does not have these extra byte */
+        if (evt_len > 2)
+        {
+            /* VSC complete has one extra byte for op code, skip it here */
+            p ++;
+            STREAM_TO_UINT8(btm_cb.ble_ctr_cb.resolving_list_avail_size, p);
+        }
+        else
+            btm_cb.ble_ctr_cb.resolving_list_avail_size --;
+    }
+    else if (status == HCI_ERR_MEMORY_FULL) /* BT_ERROR_CODE_MEMORY_CAPACITY_EXCEEDED  */
+    {
+        btm_cb.ble_ctr_cb.resolving_list_avail_size = 0;
+        BTM_TRACE_DEBUG("%s Resolving list Full ", __func__);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_remove_resolving_list_entry_complete
+**
+** Description      This function is called when command complete for
+**                  remove resolving list entry
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_remove_resolving_list_entry_complete(uint8_t *p, uint16_t evt_len)
+{
+    BD_ADDR pseudo_bda;
+    uint8_t status;
+
+    STREAM_TO_UINT8(status, p);
+
+    BTM_TRACE_DEBUG("%s status = %d", __func__, status);
+
+    if (!btm_ble_deq_resolving_pending(pseudo_bda))
+    {
+        BTM_TRACE_ERROR("%s no pending resolving list operation", __func__);
+        return;
+    }
+
+    if (status == HCI_SUCCESS)
+    {
+        /* proprietary: spec does not have these extra bytes */
+        if (evt_len > 2)
+        {
+            p ++; /* skip opcode */
+            STREAM_TO_UINT8(btm_cb.ble_ctr_cb.resolving_list_avail_size, p);
+        }
+        else
+            btm_cb.ble_ctr_cb.resolving_list_avail_size++;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_read_resolving_list_entry_complete
+**
+** Description      This function is called when command complete for
+**                  remove resolving list entry
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_read_resolving_list_entry_complete(uint8_t *p, uint16_t evt_len)
+{
+    uint8_t         status, rra_type = BTM_BLE_ADDR_PSEUDO;
+    BD_ADDR         rra, pseudo_bda;
+
+    STREAM_TO_UINT8  (status, p);
+
+    BTM_TRACE_DEBUG("%s status = %d", __func__, status);
+
+    if (!btm_ble_deq_resolving_pending(pseudo_bda))
+    {
+        BTM_TRACE_ERROR("no pending resolving list operation");
+        return;
+    }
+
+    if (status == HCI_SUCCESS)
+    {
+        /* proprietary spec has extra bytes */
+        if (evt_len > 8)
+        {
+            p += (2 + 16 + 1 + 6); /* skip subcode, index, IRK value, address type, identity addr type */
+            STREAM_TO_BDADDR(rra, p);
+
+            BTM_TRACE_ERROR("%s peer_addr: %02x:%02x:%02x:%02x:%02x:%02x",
+                            __func__, rra[0], rra[1], rra[2], rra[3], rra[4], rra[5]);
+        }
+        else
+        {
+           STREAM_TO_BDADDR(rra, p);
+        }
+        btm_ble_refresh_peer_resolvable_private_addr(pseudo_bda, rra, rra_type);
+   }
+}
+/*******************************************************************************
+                VSC that implement controller based privacy
+********************************************************************************/
+/*******************************************************************************
+**
+** Function         btm_ble_resolving_list_vsc_op_cmpl
+**
+** Description      IRK operation VSC complete handler
+**
+** Parameters
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_resolving_list_vsc_op_cmpl (tBTM_VSC_CMPL *p_params)
+{
+    uint8_t *p = p_params->p_param_buf, op_subcode;
+    uint16_t evt_len = p_params->param_len;
+
+    op_subcode   = *(p + 1);
+
+    BTM_TRACE_DEBUG("%s op_subcode = %d", __func__, op_subcode);
+
+    if (op_subcode == BTM_BLE_META_CLEAR_IRK_LIST)
+    {
+        btm_ble_clear_resolving_list_complete(p, evt_len);
+    }
+    else if (op_subcode == BTM_BLE_META_ADD_IRK_ENTRY)
+    {
+       btm_ble_add_resolving_list_entry_complete(p, evt_len);
+    }
+    else if (op_subcode == BTM_BLE_META_REMOVE_IRK_ENTRY)
+    {
+        btm_ble_remove_resolving_list_entry_complete(p, evt_len);
+    }
+    else if (op_subcode == BTM_BLE_META_READ_IRK_ENTRY)
+    {
+         btm_ble_read_resolving_list_entry_complete(p, evt_len);
+    }
+    else if (op_subcode == BTM_BLE_META_IRK_ENABLE)
+    {
+        /* RPA offloading enable/disabled */
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_remove_resolving_list_entry
+**
+** Description      This function to remove an IRK entry from the list
+**
+** Parameters       ble_addr_type: address type
+**                  ble_addr: LE adddress
+**
+** Returns          status
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_remove_resolving_list_entry(tBTM_SEC_DEV_REC *p_dev_rec)
+{
+    /* if controller does not support RPA offloading or privacy 1.2, skip */
+    if (controller_get_interface()->get_ble_resolving_list_max_size() == 0)
+        return BTM_WRONG_MODE;
+
+    if (controller_get_interface()->supports_ble_privacy())
+    {
+        btsnd_hcic_ble_rm_device_resolving_list(p_dev_rec->ble.static_addr_type,
+                                                p_dev_rec->ble.static_addr);
+    }
+    else
+    {
+        uint8_t param[20]= {0};
+        uint8_t *p = param;
+
+        UINT8_TO_STREAM(p, BTM_BLE_META_REMOVE_IRK_ENTRY);
+        UINT8_TO_STREAM(p, p_dev_rec->ble.static_addr_type);
+        BDADDR_TO_STREAM(p, p_dev_rec->ble.static_addr);
+
+        BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC,
+                                       BTM_BLE_META_REMOVE_IRK_LEN,
+                                       param,
+                                       btm_ble_resolving_list_vsc_op_cmpl);
+    }
+
+    btm_ble_enq_resolving_list_pending( p_dev_rec->bd_addr, BTM_BLE_META_REMOVE_IRK_ENTRY);
+    return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_clear_resolving_list
+**
+** Description      This function clears the resolving  list
+**
+** Parameters       None.
+**
+*******************************************************************************/
+void btm_ble_clear_resolving_list(void)
+{
+
+    if (controller_get_interface()->supports_ble_privacy())
+    {
+        btsnd_hcic_ble_clear_resolving_list();
+    }
+    else
+    {
+        uint8_t param[20] = {0};
+        uint8_t *p = param;
+
+        UINT8_TO_STREAM(p, BTM_BLE_META_CLEAR_IRK_LIST);
+        BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC,
+                                  BTM_BLE_META_CLEAR_IRK_LEN,
+                                  param,
+                                  btm_ble_resolving_list_vsc_op_cmpl);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_read_resolving_list_entry
+**
+** Description      This function read an IRK entry by index
+**
+** Parameters       entry index.
+**
+** Returns          status
+**
+*******************************************************************************/
+tBTM_STATUS btm_ble_read_resolving_list_entry(tBTM_SEC_DEV_REC *p_dev_rec)
+{
+    if (!(p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT))
+        return BTM_WRONG_MODE;
+
+    if (controller_get_interface()->supports_ble_privacy())
+    {
+        btsnd_hcic_ble_read_resolvable_addr_peer(p_dev_rec->ble.static_addr_type,
+                                                     p_dev_rec->ble.static_addr);
+    }
+    else
+    {
+        uint8_t param[20] = {0};
+        uint8_t *p = param;
+
+        UINT8_TO_STREAM(p, BTM_BLE_META_READ_IRK_ENTRY);
+        UINT8_TO_STREAM(p, p_dev_rec->ble.resolving_list_index);
+
+        BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC,
+                                  BTM_BLE_META_READ_IRK_LEN,
+                                  param,
+                                  btm_ble_resolving_list_vsc_op_cmpl);
+    }
+
+    btm_ble_enq_resolving_list_pending(p_dev_rec->bd_addr,
+                                       BTM_BLE_META_READ_IRK_ENTRY);
+
+    return BTM_CMD_STARTED;
+}
+
+
+/*******************************************************************************
+**
+** Function         btm_ble_suspend_resolving_list_activity
+**
+** Description      This function suspends all resolving list activity, including
+**                  scan, initiating, and advertising, if resolving list is being
+**                  enabled.
+**
+** Parameters
+**
+** Returns          true if suspended; false otherwise
+**
+*******************************************************************************/
+bool    btm_ble_suspend_resolving_list_activity(void)
+{
+    tBTM_BLE_CB *p_ble_cb = &btm_cb.ble_ctr_cb;
+
+    /* if resolving list is not enabled, do not need to terminate any activity */
+    /* if asking for stop all activity */
+    /* if already suspended */
+    if (p_ble_cb->suspended_rl_state != BTM_BLE_RL_IDLE)
+        return true;
+
+    /* direct connection active, wait until it completed */
+    if (btm_ble_get_conn_st() == BLE_DIR_CONN)
+    {
+        BTM_TRACE_ERROR("resolving list can not be edited, EnQ now");
+        return false;
+    }
+
+    p_ble_cb->suspended_rl_state = BTM_BLE_RL_IDLE;
+
+    if (p_ble_cb->inq_var.adv_mode == BTM_BLE_ADV_ENABLE)
+    {
+        btm_ble_stop_adv();
+        p_ble_cb->suspended_rl_state |= BTM_BLE_RL_ADV;
+    }
+
+    if (BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity))
+    {
+        btm_ble_stop_scan();
+        p_ble_cb->suspended_rl_state |= BTM_BLE_RL_SCAN;
+    }
+
+    if (btm_ble_suspend_bg_conn())
+        p_ble_cb->suspended_rl_state |= BTM_BLE_RL_INIT;
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_resume_resolving_list_activity
+**
+** Description      This function resumes the resolving list activity, including
+**                  scanning, initiating, and advertising, if any of these
+**                  activities has been suspended earlier.
+**
+** Returns          none
+**
+*******************************************************************************/
+void btm_ble_resume_resolving_list_activity(void)
+{
+    tBTM_BLE_CB *p_ble_cb = &btm_cb.ble_ctr_cb;
+
+    if (p_ble_cb->suspended_rl_state & BTM_BLE_RL_ADV)
+        btm_ble_start_adv();
+
+    if (p_ble_cb->suspended_rl_state & BTM_BLE_RL_SCAN)
+        btm_ble_start_scan();
+
+    if  (p_ble_cb->suspended_rl_state & BTM_BLE_RL_INIT)
+        btm_ble_resume_bg_conn();
+
+    p_ble_cb->suspended_rl_state = BTM_BLE_RL_IDLE;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_vendor_enable_irk_feature
+**
+** Description      This function is called to enable or disable the RRA
+**                  offloading feature.
+**
+** Parameters       enable: enable or disable the RRA offloading feature
+**
+*******************************************************************************/
+void btm_ble_vendor_enable_irk_feature(bool enable)
+{
+    uint8_t         param[20], *p;
+
+    p = param;
+    memset(param, 0, 20);
+
+    /* select feature based on control block settings */
+    UINT8_TO_STREAM(p, BTM_BLE_META_IRK_ENABLE);
+    UINT8_TO_STREAM(p, enable ? 0x01 : 0x00);
+
+    BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC, BTM_BLE_IRK_ENABLE_LEN,
+                              param, btm_ble_resolving_list_vsc_op_cmpl);
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_exe_disable_resolving_list
+**
+** Description      execute resolving list disable
+**
+** Returns          none
+**
+*******************************************************************************/
+bool    btm_ble_exe_disable_resolving_list(void)
+{
+    if (!btm_ble_suspend_resolving_list_activity())
+        return false;
+
+    if (!controller_get_interface()->supports_ble_privacy())
+        btm_ble_vendor_enable_irk_feature(false);
+    else
+        btsnd_hcic_ble_set_addr_resolution_enable(false);
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_exe_enable_resolving_list
+**
+** Description      enable LE resolve address list
+**
+** Returns          none
+**
+*******************************************************************************/
+void btm_ble_exe_enable_resolving_list(void)
+{
+    if (!btm_ble_suspend_resolving_list_activity())
+        return;
+
+    if (!controller_get_interface()->supports_ble_privacy())
+        btm_ble_vendor_enable_irk_feature(true);
+    else
+        btsnd_hcic_ble_set_addr_resolution_enable(true);
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_disable_resolving_list
+**
+** Description      Disable LE Address resolution
+**
+** Returns          none
+**
+*******************************************************************************/
+bool    btm_ble_disable_resolving_list(uint8_t rl_mask, bool    to_resume )
+{
+    uint8_t rl_state = btm_cb.ble_ctr_cb.rl_state;
+
+    /* if controller does not support RPA offloading or privacy 1.2, skip */
+    if (controller_get_interface()->get_ble_resolving_list_max_size()== 0)
+        return false;
+
+    btm_cb.ble_ctr_cb.rl_state &= ~rl_mask;
+
+    if (rl_state != BTM_BLE_RL_IDLE && btm_cb.ble_ctr_cb.rl_state == BTM_BLE_RL_IDLE)
+    {
+        if (btm_ble_exe_disable_resolving_list())
+        {
+            if (to_resume)
+                btm_ble_resume_resolving_list_activity();
+
+            return true;
+        }
+        else
+            return false;
+    }
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_resolving_list_load_dev
+**
+** Description      This function add a device which is using RPA into white list
+**
+** Parameters       pointer to device security record
+**
+** Returns          true if device added, otherwise falase.
+**
+*******************************************************************************/
+bool    btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC *p_dev_rec)
+{
+    bool    rt = false;
+    uint8_t rl_mask = btm_cb.ble_ctr_cb.rl_state;
+
+    BTM_TRACE_DEBUG("%s btm_cb.ble_ctr_cb.privacy_mode = %d", __func__,
+                                btm_cb.ble_ctr_cb.privacy_mode);
+
+    /* if controller does not support RPA offloading or privacy 1.2, skip */
+    if (controller_get_interface()->get_ble_resolving_list_max_size() == 0)
+        return false;
+
+    BTM_TRACE_DEBUG("%s btm_cb.ble_ctr_cb.privacy_mode = %d",
+                    __func__, btm_cb.ble_ctr_cb.privacy_mode);
+
+    /* only add RPA enabled device into resolving list */
+    if (p_dev_rec != NULL && /* RPA is being used and PID is known */
+       ((p_dev_rec->ble.key_type & BTM_LE_KEY_PID) != 0 ||
+       (p_dev_rec->ble.key_type & BTM_LE_KEY_LID) != 0))
+    {
+        if (!(p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) &&
+            btm_ble_brcm_find_resolving_pending_entry(p_dev_rec->bd_addr,
+                                                      BTM_BLE_META_ADD_IRK_ENTRY) == false)
+        {
+            if (btm_cb.ble_ctr_cb.resolving_list_avail_size > 0)
+            {
+                if (rl_mask)
+                {
+                    if (!btm_ble_disable_resolving_list (rl_mask, false))
+                        return false;
+                }
+
+                btm_ble_update_resolving_list(p_dev_rec->bd_addr, true);
+                if (controller_get_interface()->supports_ble_privacy())
+                {
+                    BD_ADDR dummy_bda = {0};
+                    uint8_t *peer_irk = p_dev_rec->ble.keys.irk;
+                    uint8_t *local_irk = btm_cb.devcb.id_keys.irk;
+
+                    if (memcmp(p_dev_rec->ble.static_addr, dummy_bda, BD_ADDR_LEN) == 0)
+                    {
+                        memcpy(p_dev_rec->ble.static_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
+                        p_dev_rec->ble.static_addr_type = p_dev_rec->ble.ble_addr_type;
+                    }
+
+                    BTM_TRACE_DEBUG("%s:adding device to controller resolving list", __func__);
+                    // use identical IRK for now
+                    btsnd_hcic_ble_add_device_resolving_list(p_dev_rec->ble.static_addr_type,
+                              p_dev_rec->ble.static_addr, peer_irk, local_irk);
+                }
+                else
+                {
+                    uint8_t param[40] = {0};
+                    uint8_t *p = param;
+
+                    UINT8_TO_STREAM(p, BTM_BLE_META_ADD_IRK_ENTRY);
+                    ARRAY_TO_STREAM(p, p_dev_rec->ble.keys.irk, BT_OCTET16_LEN);
+                    UINT8_TO_STREAM(p, p_dev_rec->ble.static_addr_type);
+                    BDADDR_TO_STREAM(p,p_dev_rec->ble.static_addr);
+
+                    BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC,
+                                              BTM_BLE_META_ADD_IRK_LEN,
+                                              param,
+                                              btm_ble_resolving_list_vsc_op_cmpl);
+                }
+
+                rt = true;
+                btm_ble_enq_resolving_list_pending(p_dev_rec->bd_addr,
+                                                  BTM_BLE_META_ADD_IRK_ENTRY);
+
+                /* if resolving list has been turned on, re-enable it */
+                if (rl_mask)
+                    btm_ble_enable_resolving_list(rl_mask);
+                else
+                    btm_ble_enable_resolving_list(BTM_BLE_RL_INIT);
+            }
+        }
+        else
+        {
+            BTM_TRACE_ERROR("Device already in Resolving list");
+            rt = true;
+        }
+    }
+    else
+    {
+        BTM_TRACE_DEBUG("Device not a RPA enabled device");
+    }
+    return rt;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_resolving_list_remove_dev
+**
+** Description      This function removes the device from resolving list
+**
+** Parameters
+**
+** Returns          status
+**
+*******************************************************************************/
+void btm_ble_resolving_list_remove_dev(tBTM_SEC_DEV_REC *p_dev_rec)
+{
+    uint8_t rl_mask = btm_cb.ble_ctr_cb.rl_state;
+
+    BTM_TRACE_EVENT ("%s", __func__);
+    if (rl_mask)
+    {
+        if (!btm_ble_disable_resolving_list (rl_mask, false))
+             return;
+    }
+
+    if ((p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) &&
+        btm_ble_brcm_find_resolving_pending_entry(p_dev_rec->bd_addr,
+                                                  BTM_BLE_META_REMOVE_IRK_ENTRY) == false)
+    {
+        btm_ble_update_resolving_list( p_dev_rec->bd_addr, false);
+        btm_ble_remove_resolving_list_entry(p_dev_rec);
+    }
+    else
+    {
+        BTM_TRACE_DEBUG("Device not in resolving list");
+    }
+
+    /* if resolving list has been turned on, re-enable it */
+    if (rl_mask)
+        btm_ble_enable_resolving_list(rl_mask);
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_enable_resolving_list
+**
+** Description      enable LE resolve address list
+**
+** Returns          none
+**
+*******************************************************************************/
+void btm_ble_enable_resolving_list(uint8_t rl_mask)
+{
+    uint8_t rl_state = btm_cb.ble_ctr_cb.rl_state;
+
+    btm_cb.ble_ctr_cb.rl_state |= rl_mask;
+    if (rl_state == BTM_BLE_RL_IDLE &&
+        btm_cb.ble_ctr_cb.rl_state != BTM_BLE_RL_IDLE &&
+        controller_get_interface()->get_ble_resolving_list_max_size() != 0)
+    {
+        btm_ble_exe_enable_resolving_list();
+        btm_ble_resume_resolving_list_activity();
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_resolving_list_empty
+**
+** Description      check to see if resoving list is empty or not
+**
+** Returns          true: empty; false non-empty
+**
+*******************************************************************************/
+bool    btm_ble_resolving_list_empty(void)
+{
+    return (controller_get_interface()->get_ble_resolving_list_max_size() ==
+            btm_cb.ble_ctr_cb.resolving_list_avail_size);
+}
+
+
+bool is_on_resolving_list(void *data, void *context)
+{
+    tBTM_SEC_DEV_REC *p_dev = static_cast<tBTM_SEC_DEV_REC *>(data);
+    if ((p_dev->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) &&
+        (p_dev->ble.in_controller_list & BTM_WHITE_LIST_BIT))
+        return false;
+
+    return true;
+}
+
+
+/*******************************************************************************
+**
+** Function         btm_ble_enable_resolving_list_for_platform
+**
+** Description      enable/disable resolving list feature depending on if any
+**                  resolving list is empty and whitelist is involoved in the
+**                  operation.
+**
+** Returns          none
+**
+*******************************************************************************/
+void btm_ble_enable_resolving_list_for_platform (uint8_t rl_mask)
+{
+    /* if controller does not support, skip */
+    if (controller_get_interface()->get_ble_resolving_list_max_size() == 0)
+        return;
+
+    if (btm_cb.ble_ctr_cb.wl_state == BTM_BLE_WL_IDLE)
+    {
+        if (controller_get_interface()->get_ble_resolving_list_max_size() >
+                                        btm_cb.ble_ctr_cb.resolving_list_avail_size)
+            btm_ble_enable_resolving_list(rl_mask);
+        else
+            btm_ble_disable_resolving_list(rl_mask, true);
+        return;
+    }
+
+    list_node_t *n = list_foreach(btm_cb.sec_dev_rec, is_on_resolving_list, NULL);
+    if (n)
+        btm_ble_enable_resolving_list(rl_mask);
+    else
+        btm_ble_disable_resolving_list(rl_mask, true);
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_resolving_list_init
+**
+** Description      Initialize resolving list in host stack
+**
+** Parameters       Max resolving list size
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_resolving_list_init(uint8_t max_irk_list_sz)
+{
+    tBTM_BLE_RESOLVE_Q *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
+    uint8_t irk_mask_size =  (max_irk_list_sz % 8) ?
+                           (max_irk_list_sz/8 + 1) : (max_irk_list_sz/8);
+
+    if (max_irk_list_sz > 0)
+    {
+        p_q->resolve_q_random_pseudo = (BD_ADDR *)osi_malloc(sizeof(BD_ADDR) * max_irk_list_sz);
+        p_q->resolve_q_action = (uint8_t *)osi_malloc(max_irk_list_sz);
+
+        /* RPA offloading feature */
+        if (btm_cb.ble_ctr_cb.irk_list_mask == NULL)
+            btm_cb.ble_ctr_cb.irk_list_mask = (uint8_t *)osi_malloc(irk_mask_size);
+
+        BTM_TRACE_DEBUG ("%s max_irk_list_sz = %d", __func__, max_irk_list_sz);
+    }
+
+    controller_get_interface()->set_ble_resolving_list_max_size(max_irk_list_sz);
+    btm_ble_clear_resolving_list();
+    btm_cb.ble_ctr_cb.resolving_list_avail_size = max_irk_list_sz;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_resolving_list_cleanup
+**
+** Description      Cleanup resolving list dynamic memory
+**
+** Parameters
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_ble_resolving_list_cleanup(void)
+{
+    tBTM_BLE_RESOLVE_Q *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
+
+    osi_free_and_reset((void **)&p_q->resolve_q_random_pseudo);
+    osi_free_and_reset((void **)&p_q->resolve_q_action);
+
+    controller_get_interface()->set_ble_resolving_list_max_size(0);
+
+    osi_free_and_reset((void **)&btm_cb.ble_ctr_cb.irk_list_mask);
+}
+#endif
diff --git a/bt/stack/btm/btm_dev.cc b/bt/stack/btm/btm_dev.cc
new file mode 100644
index 0000000..bb27685
--- /dev/null
+++ b/bt/stack/btm/btm_dev.cc
@@ -0,0 +1,634 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 functions for the Bluetooth Device Manager
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "bt_types.h"
+#include "device/include/controller.h"
+#include "bt_common.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "hcidefs.h"
+#include "l2c_api.h"
+
+/*******************************************************************************
+**
+** 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.
+**
+** Parameters:      bd_addr          - BD address of the peer
+**                  dev_class        - Device Class
+**                  bd_name          - Name of the peer device.  NULL if unknown.
+**                  features         - Remote device's features (up to 3 pages). NULL if not known
+**                  trusted_mask     - Bitwise OR of services that do not
+**                                     require authorization. (array of uint32_t)
+**                  link_key         - Connection link key. NULL if unknown.
+**
+** Returns          true if added OK, else false
+**
+*******************************************************************************/
+bool    BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name,
+                          uint8_t *features, uint32_t trusted_mask[],
+                          LINK_KEY link_key, uint8_t key_type, tBTM_IO_CAP io_cap,
+                          uint8_t pin_length)
+{
+    BTM_TRACE_API("%s: link key type:%x", __func__, key_type);
+
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+    if (!p_dev_rec)
+    {
+        p_dev_rec = btm_sec_allocate_dev_rec();
+
+        memcpy (p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN);
+        p_dev_rec->hci_handle = BTM_GetHCIConnHandle (bd_addr, BT_TRANSPORT_BR_EDR);
+
+#if (BLE_INCLUDED == TRUE)
+        /* use default value for background connection params */
+        /* update conn params, use default value for background connection params */
+        memset(&p_dev_rec->conn_params, 0xff, sizeof(tBTM_LE_CONN_PRAMS));
+#endif
+    } else {
+        /* "Bump" timestamp for existing record */
+        p_dev_rec->timestamp = btm_cb.dev_rec_count++;
+
+        /* TODO(eisenbach):
+         * Small refactor, but leaving original logic for now.
+         * On the surface, this does not make any sense at all. Why change the
+         * bond state for an existing device here? This logic should be verified
+         * as part of a larger refactor.
+         */
+        p_dev_rec->bond_type = BOND_TYPE_UNKNOWN;
+    }
+
+    if (dev_class)
+        memcpy (p_dev_rec->dev_class, dev_class, DEV_CLASS_LEN);
+
+    memset(p_dev_rec->sec_bd_name, 0, sizeof(tBTM_BD_NAME));
+
+    if (bd_name && bd_name[0])
+    {
+        p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN;
+        strlcpy ((char *)p_dev_rec->sec_bd_name,
+                 (char *)bd_name, BTM_MAX_REM_BD_NAME_LEN);
+    }
+
+    p_dev_rec->num_read_pages = 0;
+    if (features)
+    {
+        bool found = false;
+        memcpy (p_dev_rec->features, features, sizeof (p_dev_rec->features));
+        for (int i = HCI_EXT_FEATURES_PAGE_MAX; !found && i >= 0; i--)
+        {
+            for (int j = 0; j < HCI_FEATURE_BYTES_PER_PAGE; j++)
+            {
+                if (p_dev_rec->features[i][j] != 0)
+                {
+                    found = true;
+                    p_dev_rec->num_read_pages = i + 1;
+                    break;
+                }
+            }
+        }
+    } else {
+        memset (p_dev_rec->features, 0, sizeof (p_dev_rec->features));
+    }
+
+    BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);
+
+    if (link_key)
+    {
+        BTM_TRACE_EVENT ("%s: BDA: %02x:%02x:%02x:%02x:%02x:%02x", __func__,
+                          bd_addr[0], bd_addr[1], bd_addr[2],
+                          bd_addr[3], bd_addr[4], bd_addr[5]);
+        p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN;
+        memcpy (p_dev_rec->link_key, link_key, LINK_KEY_LEN);
+        p_dev_rec->link_key_type = key_type;
+        p_dev_rec->pin_code_length = pin_length;
+
+        if (pin_length >= 16 ||
+            key_type == BTM_LKEY_TYPE_AUTH_COMB ||
+            key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) {
+            // Set the flag if the link key was made by using either a 16 digit
+            // pin or MITM.
+            p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED | BTM_SEC_LINK_KEY_AUTHED;
+        }
+    }
+
+#if (BTIF_MIXED_MODE_INCLUDED == TRUE)
+    if (key_type  < BTM_MAX_PRE_SM4_LKEY_TYPE)
+        p_dev_rec->sm4 = BTM_SM4_KNOWN;
+    else
+        p_dev_rec->sm4 = BTM_SM4_TRUE;
+#endif
+
+    p_dev_rec->rmt_io_caps = io_cap;
+    p_dev_rec->device_type |= BT_DEVICE_TYPE_BREDR;
+
+    return true;
+}
+
+
+/*******************************************************************************
+**
+** Function         BTM_SecDeleteDevice
+**
+** Description      Free resources associated with the device.
+**
+** Parameters:      bd_addr          - BD address of the peer
+**
+** Returns          true if removed OK, false if not found or ACL link is active
+**
+*******************************************************************************/
+bool    BTM_SecDeleteDevice (BD_ADDR bd_addr)
+{
+    if (BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE) ||
+        BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_BR_EDR))
+    {
+        BTM_TRACE_WARNING("%s FAILED: Cannot Delete when connection is active", __func__);
+        return false;
+    }
+
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bd_addr);
+    if (p_dev_rec != NULL)
+    {
+        btm_sec_free_dev(p_dev_rec);
+        /* Tell controller to get rid of the link key, if it has one stored */
+        BTM_DeleteStoredLinkKey (p_dev_rec->bd_addr, NULL);
+    }
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         BTM_SecClearSecurityFlags
+**
+** Description      Reset the security flags (mark as not-paired) for a given
+**                  remove device.
+**
+*******************************************************************************/
+extern void BTM_SecClearSecurityFlags (BD_ADDR bd_addr)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bd_addr);
+    if (p_dev_rec == NULL)
+        return;
+
+    p_dev_rec->sec_flags = 0;
+    p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+    p_dev_rec->sm4 = BTM_SM4_UNKNOWN;
+}
+
+/*******************************************************************************
+**
+** 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 (BD_ADDR bd_addr)
+{
+    char *p_name = NULL;
+    tBTM_SEC_DEV_REC *p_srec;
+
+    if ((p_srec = btm_find_dev(bd_addr)) != NULL)
+        p_name = (char *)p_srec->sec_bd_name;
+
+    return(p_name);
+}
+
+bool is_bd_addr_equal(void *data, void *context)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = static_cast<tBTM_SEC_DEV_REC *>(data);
+    BD_ADDR *bd_addr = static_cast<BD_ADDR *>(context);
+
+    if (!memcmp(p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN))
+        return false;
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_alloc_dev
+**
+** Description      Look for the record in the device database for the record
+**                  with specified address
+**
+** Returns          Pointer to the record or NULL
+**
+*******************************************************************************/
+tBTM_SEC_DEV_REC *btm_sec_alloc_dev (BD_ADDR bd_addr)
+{
+    tBTM_INQ_INFO    *p_inq_info;
+    BTM_TRACE_EVENT ("btm_sec_alloc_dev");
+
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_sec_allocate_dev_rec();
+
+    /* Check with the BT manager if details about remote device are known */
+    /* outgoing connection */
+    if ((p_inq_info = BTM_InqDbRead(bd_addr)) != NULL)
+    {
+        memcpy (p_dev_rec->dev_class, p_inq_info->results.dev_class, DEV_CLASS_LEN);
+
+#if (BLE_INCLUDED == TRUE)
+        p_dev_rec->device_type = p_inq_info->results.device_type;
+        p_dev_rec->ble.ble_addr_type = p_inq_info->results.ble_addr_type;
+#endif
+    }
+    else if (!memcmp (bd_addr, btm_cb.connecting_bda, BD_ADDR_LEN))
+            memcpy (p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN);
+
+#if (BLE_INCLUDED == TRUE)
+    /* update conn params, use default value for background connection params */
+    memset(&p_dev_rec->conn_params, 0xff, sizeof(tBTM_LE_CONN_PRAMS));
+#endif
+
+    memcpy (p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN);
+
+#if (BLE_INCLUDED == TRUE)
+    p_dev_rec->ble_hci_handle = BTM_GetHCIConnHandle (bd_addr, BT_TRANSPORT_LE);
+#endif
+    p_dev_rec->hci_handle = BTM_GetHCIConnHandle (bd_addr, BT_TRANSPORT_BR_EDR);
+
+    return(p_dev_rec);
+}
+
+
+/*******************************************************************************
+**
+** Function         btm_sec_free_dev
+**
+** Description      Mark device record as not used
+**
+*******************************************************************************/
+void btm_sec_free_dev (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+#if (BLE_INCLUDED == TRUE)
+    /* Clear out any saved BLE keys */
+    btm_sec_clear_ble_keys (p_dev_rec);
+#endif
+    list_remove(btm_cb.sec_dev_rec, p_dev_rec);
+}
+
+/*******************************************************************************
+**
+** Function         btm_dev_support_switch
+**
+** Description      This function is called by the L2CAP to check if remote
+**                  device supports role switch
+**
+** Parameters:      bd_addr       - Address of the peer device
+**
+** Returns          true if device is known and role switch is supported
+**
+*******************************************************************************/
+bool    btm_dev_support_switch (BD_ADDR bd_addr)
+{
+    tBTM_SEC_DEV_REC  *p_dev_rec;
+    uint8_t xx;
+    bool    feature_empty = true;
+
+#if (BTM_SCO_INCLUDED == TRUE)
+    /* Role switch is not allowed if a SCO is up */
+    if (btm_is_sco_active_by_bdaddr(bd_addr))
+        return(false);
+#endif
+    p_dev_rec = btm_find_dev (bd_addr);
+    if (p_dev_rec && controller_get_interface()->supports_master_slave_role_switch())
+    {
+        if (HCI_SWITCH_SUPPORTED(p_dev_rec->features[HCI_EXT_FEATURES_PAGE_0]))
+        {
+            BTM_TRACE_DEBUG("btm_dev_support_switch return true (feature found)");
+            return (true);
+        }
+
+        /* If the feature field is all zero, we never received them */
+        for (xx = 0 ; xx < BD_FEATURES_LEN ; xx++)
+        {
+            if (p_dev_rec->features[HCI_EXT_FEATURES_PAGE_0][xx] != 0x00)
+            {
+                feature_empty = false; /* at least one is != 0 */
+                break;
+            }
+        }
+
+        /* If we don't know peer's capabilities, assume it supports Role-switch */
+        if (feature_empty)
+        {
+            BTM_TRACE_DEBUG("btm_dev_support_switch return true (feature empty)");
+            return (true);
+        }
+    }
+
+    BTM_TRACE_DEBUG("btm_dev_support_switch return false");
+    return(false);
+}
+
+bool is_handle_equal(void *data, void *context)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = static_cast<tBTM_SEC_DEV_REC *>(data);
+    uint16_t *handle = static_cast<uint16_t *>(context);
+
+    if (p_dev_rec->hci_handle == *handle
+#if (BLE_INCLUDED == TRUE)
+     || p_dev_rec->ble_hci_handle == *handle
+#endif
+     )
+        return false;
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         btm_find_dev_by_handle
+**
+** Description      Look for the record in the device database for the record
+**                  with specified handle
+**
+** Returns          Pointer to the record or NULL
+**
+*******************************************************************************/
+tBTM_SEC_DEV_REC *btm_find_dev_by_handle (uint16_t handle)
+{
+    list_node_t *n = list_foreach(btm_cb.sec_dev_rec, is_handle_equal, &handle);
+    if (n)
+        return static_cast<tBTM_SEC_DEV_REC *>(list_node(n));
+
+    return NULL;
+}
+
+bool is_address_equal(void *data, void *context)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = static_cast<tBTM_SEC_DEV_REC *>(data);
+    BD_ADDR *bd_addr = static_cast<BD_ADDR *>(context);
+
+    if (!memcmp (p_dev_rec->bd_addr, *bd_addr, BD_ADDR_LEN))
+        return false;
+#if (BLE_INCLUDED == TRUE)
+    // If a LE random address is looking for device record
+    if (!memcmp(p_dev_rec->ble.pseudo_addr, *bd_addr, BD_ADDR_LEN))
+        return false;
+
+    if (btm_ble_addr_resolvable(*bd_addr, p_dev_rec))
+        return false;
+#endif
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         btm_find_dev
+**
+** Description      Look for the record in the device database for the record
+**                  with specified BD address
+**
+** Returns          Pointer to the record or NULL
+**
+*******************************************************************************/
+tBTM_SEC_DEV_REC *btm_find_dev(const BD_ADDR bd_addr)
+{
+    if (!bd_addr)
+        return NULL;
+
+    list_node_t *n = list_foreach(btm_cb.sec_dev_rec, is_address_equal, (void*)bd_addr);
+    if (n)
+        return static_cast<tBTM_SEC_DEV_REC *>(list_node(n));
+
+    return NULL;
+}
+
+/*******************************************************************************
+**
+** Function         btm_consolidate_dev
+5**
+** Description      combine security records if identified as same peer
+**
+** Returns          none
+**
+*******************************************************************************/
+void btm_consolidate_dev(tBTM_SEC_DEV_REC *p_target_rec)
+{
+#if (BLE_INCLUDED == TRUE)
+    tBTM_SEC_DEV_REC temp_rec = *p_target_rec;
+
+    BTM_TRACE_DEBUG("%s", __func__);
+
+    list_node_t *end = list_end(btm_cb.sec_dev_rec);
+    for (list_node_t *node = list_begin(btm_cb.sec_dev_rec); node != end; node = list_next(node)) {
+        tBTM_SEC_DEV_REC *p_dev_rec =
+            static_cast<tBTM_SEC_DEV_REC *>(list_node(node));
+
+        if (p_target_rec == p_dev_rec)
+            continue;
+
+        if (!memcmp (p_dev_rec->bd_addr, p_target_rec->bd_addr, BD_ADDR_LEN))
+        {
+            memcpy(p_target_rec, p_dev_rec, sizeof(tBTM_SEC_DEV_REC));
+            p_target_rec->ble = temp_rec.ble;
+            p_target_rec->ble_hci_handle = temp_rec.ble_hci_handle;
+            p_target_rec->enc_key_size = temp_rec.enc_key_size;
+            p_target_rec->conn_params = temp_rec.conn_params;
+            p_target_rec->device_type |= temp_rec.device_type;
+            p_target_rec->sec_flags |= temp_rec.sec_flags;
+
+            p_target_rec->new_encryption_key_is_p256 = temp_rec.new_encryption_key_is_p256;
+            p_target_rec->no_smp_on_br = temp_rec.no_smp_on_br;
+            p_target_rec->bond_type = temp_rec.bond_type;
+
+            /* remove the combined record */
+            list_remove(btm_cb.sec_dev_rec, p_dev_rec);
+            break;
+        }
+
+        /* an RPA device entry is a duplicate of the target record */
+        if (btm_ble_addr_resolvable(p_dev_rec->bd_addr, p_target_rec))
+        {
+            if (memcmp(p_target_rec->ble.pseudo_addr, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0)
+            {
+                p_target_rec->ble.ble_addr_type = p_dev_rec->ble.ble_addr_type;
+                p_target_rec->device_type |= p_dev_rec->device_type;
+
+                /* remove the combined record */
+                list_remove(btm_cb.sec_dev_rec, p_dev_rec);
+            }
+            break;
+        }
+    }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btm_find_or_alloc_dev
+**
+** Description      Look for the record in the device database for the record
+**                  with specified BD address
+**
+** Returns          Pointer to the record or NULL
+**
+*******************************************************************************/
+tBTM_SEC_DEV_REC *btm_find_or_alloc_dev (BD_ADDR bd_addr)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec;
+    BTM_TRACE_EVENT ("btm_find_or_alloc_dev");
+    if ((p_dev_rec = btm_find_dev (bd_addr)) == NULL)
+    {
+
+        /* Allocate a new device record or reuse the oldest one */
+        p_dev_rec = btm_sec_alloc_dev (bd_addr);
+    }
+    return(p_dev_rec);
+}
+
+/*******************************************************************************
+**
+** Function         btm_find_oldest_dev_rec
+**
+** Description      Locates the oldest device in use. It first looks for
+**                  the oldest non-paired device.  If all devices are paired it
+**                  returns the oldest paired device.
+**
+** Returns          Pointer to the record or NULL
+**
+*******************************************************************************/
+static tBTM_SEC_DEV_REC* btm_find_oldest_dev_rec (void)
+{
+    tBTM_SEC_DEV_REC *p_oldest = NULL;
+    uint32_t ts_oldest = 0xFFFFFFFF;
+    tBTM_SEC_DEV_REC *p_oldest_paired = NULL;
+    uint32_t ts_oldest_paired = 0xFFFFFFFF;
+
+    list_node_t *end = list_end(btm_cb.sec_dev_rec);
+    for (list_node_t *node = list_begin(btm_cb.sec_dev_rec); node != end; node = list_next(node)) {
+        tBTM_SEC_DEV_REC *p_dev_rec =
+            static_cast<tBTM_SEC_DEV_REC *>(list_node(node));
+
+        if ((p_dev_rec->sec_flags & (BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LE_LINK_KEY_KNOWN)) == 0) {
+            // Device is not paired
+            if (p_dev_rec->timestamp < ts_oldest) {
+                p_oldest = p_dev_rec;
+                ts_oldest = p_dev_rec->timestamp;
+            }
+        } else {
+            // Paired device
+            if (p_dev_rec->timestamp < ts_oldest_paired) {
+                p_oldest_paired = p_dev_rec;
+                ts_oldest_paired = p_dev_rec->timestamp;
+            }
+        }
+    }
+
+    // If we did not find any non-paired devices, use the oldest paired one...
+    if (ts_oldest == 0xFFFFFFFF)
+        p_oldest = p_oldest_paired;
+
+    return p_oldest;
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_allocate_dev_rec
+**
+** Description      Attempts to allocate a new device record. If we have
+**                  exceeded the maximum number of allowable records to
+**                  allocate, the oldest record will be deleted to make room
+**                  for the new record.
+**
+** Returns          Pointer to the newly allocated record
+**
+*******************************************************************************/
+tBTM_SEC_DEV_REC* btm_sec_allocate_dev_rec(void)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = NULL;
+
+    if (list_length(btm_cb.sec_dev_rec) > BTM_SEC_MAX_DEVICE_RECORDS)
+    {
+        p_dev_rec = btm_find_oldest_dev_rec();
+        list_remove(btm_cb.sec_dev_rec, p_dev_rec);
+    }
+
+    p_dev_rec =
+        static_cast<tBTM_SEC_DEV_REC *>(osi_calloc(sizeof(tBTM_SEC_DEV_REC)));
+    list_append(btm_cb.sec_dev_rec, p_dev_rec);
+
+    // Initialize defaults
+    p_dev_rec->sec_flags = BTM_SEC_IN_USE;
+    p_dev_rec->bond_type = BOND_TYPE_UNKNOWN;
+    p_dev_rec->timestamp = btm_cb.dev_rec_count++;
+
+    return p_dev_rec;
+}
+
+/*******************************************************************************
+**
+** Function         btm_get_bond_type_dev
+**
+** Description      Get the bond type for a device in the device database
+**                  with specified BD address
+**
+** Returns          The device bond type if known, otherwise BOND_TYPE_UNKNOWN
+**
+*******************************************************************************/
+tBTM_BOND_TYPE btm_get_bond_type_dev(BD_ADDR bd_addr)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bd_addr);
+
+    if (p_dev_rec == NULL)
+        return BOND_TYPE_UNKNOWN;
+
+    return p_dev_rec->bond_type;
+}
+
+/*******************************************************************************
+**
+** Function         btm_set_bond_type_dev
+**
+** Description      Set the bond type for a device in the device database
+**                  with specified BD address
+**
+** Returns          true on success, otherwise false
+**
+*******************************************************************************/
+bool    btm_set_bond_type_dev(BD_ADDR bd_addr, tBTM_BOND_TYPE bond_type)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bd_addr);
+
+    if (p_dev_rec == NULL)
+        return false;
+
+    p_dev_rec->bond_type = bond_type;
+    return true;
+}
diff --git a/bt/stack/btm/btm_devctl.cc b/bt/stack/btm/btm_devctl.cc
new file mode 100644
index 0000000..d3aaeb1
--- /dev/null
+++ b/bt/stack/btm/btm_devctl.cc
@@ -0,0 +1,929 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 functions that handle BTM interface functions for the
+ *  Bluetooth device including Rest, HCI buffer size and others
+ *
+ ******************************************************************************/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "hci_layer.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+#include "btcore/include/module.h"
+#include "osi/include/osi.h"
+#include "osi/include/thread.h"
+
+#if (BLE_INCLUDED == TRUE)
+#include "gatt_int.h"
+#endif /* BLE_INCLUDED */
+
+extern fixed_queue_t *btu_general_alarm_queue;
+extern thread_t *bt_workqueue_thread;
+
+/********************************************************************************/
+/*                 L O C A L    D A T A    D E F I N I T I O N S                */
+/********************************************************************************/
+
+#ifndef BTM_DEV_RESET_TIMEOUT
+#define BTM_DEV_RESET_TIMEOUT   4
+#endif
+
+// TODO: Reevaluate this value in the context of timers with ms granularity
+#define BTM_DEV_NAME_REPLY_TIMEOUT_MS (2 * 1000) /* 2 seconds for name reply */
+
+#define BTM_INFO_TIMEOUT        5   /* 5 seconds for info response */
+
+/********************************************************************************/
+/*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
+/********************************************************************************/
+
+static void btm_decode_ext_features_page (uint8_t page_number, const BD_FEATURES p_features);
+
+/*******************************************************************************
+**
+** Function         btm_dev_init
+**
+** Description      This function is on the BTM startup
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_dev_init (void)
+{
+    /* Initialize nonzero defaults */
+    memset(btm_cb.cfg.bd_name, 0, sizeof(tBTM_LOC_BD_NAME));
+
+    btm_cb.devcb.read_local_name_timer =
+        alarm_new("btm.read_local_name_timer");
+    btm_cb.devcb.read_rssi_timer = alarm_new("btm.read_rssi_timer");
+    btm_cb.devcb.read_link_quality_timer =
+        alarm_new("btm.read_link_quality_timer");
+    btm_cb.devcb.read_inq_tx_power_timer =
+        alarm_new("btm.read_inq_tx_power_timer");
+    btm_cb.devcb.qos_setup_timer = alarm_new("btm.qos_setup_timer");
+    btm_cb.devcb.read_tx_power_timer = alarm_new("btm.read_tx_power_timer");
+
+    btm_cb.btm_acl_pkt_types_supported = BTM_ACL_PKT_TYPES_MASK_DH1 + BTM_ACL_PKT_TYPES_MASK_DM1 +
+                                         BTM_ACL_PKT_TYPES_MASK_DH3 + BTM_ACL_PKT_TYPES_MASK_DM3 +
+                                         BTM_ACL_PKT_TYPES_MASK_DH5 + BTM_ACL_PKT_TYPES_MASK_DM5;
+
+    btm_cb.btm_sco_pkt_types_supported = 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;
+}
+
+
+/*******************************************************************************
+**
+** Function         btm_db_reset
+**
+** Description      This function is called by BTM_DeviceReset and clears out any
+**                  pending callbacks for inquiries, discoveries, other pending
+**                  functions that may be in progress.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_db_reset (void)
+{
+    tBTM_CMPL_CB    *p_cb;
+    tBTM_STATUS      status = BTM_DEV_RESET;
+
+    btm_inq_db_reset();
+
+    if (btm_cb.devcb.p_rln_cmpl_cb)
+    {
+        p_cb = btm_cb.devcb.p_rln_cmpl_cb;
+        btm_cb.devcb.p_rln_cmpl_cb = NULL;
+
+        if (p_cb)
+            (*p_cb)((void *) NULL);
+    }
+
+    if (btm_cb.devcb.p_rssi_cmpl_cb)
+    {
+        p_cb = btm_cb.devcb.p_rssi_cmpl_cb;
+        btm_cb.devcb.p_rssi_cmpl_cb = NULL;
+
+        if (p_cb)
+            (*p_cb)((tBTM_RSSI_RESULTS *) &status);
+    }
+}
+
+bool set_sec_state_idle(void *data, void *context)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = static_cast<tBTM_SEC_DEV_REC *>(data);
+    p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+    return true;
+}
+
+static void reset_complete(void *result) {
+  assert(result == FUTURE_SUCCESS);
+  const controller_t *controller = controller_get_interface();
+
+  /* Tell L2CAP that all connections are gone */
+  l2cu_device_reset ();
+
+  /* Clear current security state */
+  list_foreach(btm_cb.sec_dev_rec, set_sec_state_idle, NULL);
+
+  /* After the reset controller should restore all parameters to defaults. */
+  btm_cb.btm_inq_vars.inq_counter       = 1;
+  btm_cb.btm_inq_vars.inq_scan_window   = HCI_DEF_INQUIRYSCAN_WINDOW;
+  btm_cb.btm_inq_vars.inq_scan_period   = HCI_DEF_INQUIRYSCAN_INTERVAL;
+  btm_cb.btm_inq_vars.inq_scan_type     = HCI_DEF_SCAN_TYPE;
+
+  btm_cb.btm_inq_vars.page_scan_window  = HCI_DEF_PAGESCAN_WINDOW;
+  btm_cb.btm_inq_vars.page_scan_period  = HCI_DEF_PAGESCAN_INTERVAL;
+  btm_cb.btm_inq_vars.page_scan_type    = HCI_DEF_SCAN_TYPE;
+
+#if (BLE_INCLUDED == TRUE)
+  btm_cb.ble_ctr_cb.conn_state = BLE_CONN_IDLE;
+  btm_cb.ble_ctr_cb.bg_conn_type = BTM_BLE_CONN_NONE;
+  btm_cb.ble_ctr_cb.p_select_cback = NULL;
+  gatt_reset_bgdev_list();
+#endif
+
+  btm_pm_reset();
+
+  l2c_link_processs_num_bufs(controller->get_acl_buffer_count_classic());
+#if (BLE_INCLUDED == TRUE)
+
+#if (BLE_PRIVACY_SPT == TRUE)
+  /* Set up the BLE privacy settings */
+  if (controller->supports_ble() && controller->supports_ble_privacy() &&
+      controller->get_ble_resolving_list_max_size() > 0) {
+      btm_ble_resolving_list_init(controller->get_ble_resolving_list_max_size());
+      /* set the default random private address timeout */
+      btsnd_hcic_ble_set_rand_priv_addr_timeout(BTM_BLE_PRIVATE_ADDR_INT_MS / 1000);
+  }
+#endif
+
+  if (controller->supports_ble()) {
+    btm_ble_white_list_init(controller->get_ble_white_list_size());
+    l2c_link_processs_ble_num_bufs(controller->get_acl_buffer_count_ble());
+  }
+#endif
+
+  BTM_SetPinType (btm_cb.cfg.pin_type, btm_cb.cfg.pin_code, btm_cb.cfg.pin_code_len);
+
+  for (int i = 0; i <= controller->get_last_features_classic_index(); i++) {
+    btm_decode_ext_features_page(i, controller->get_features_classic(i)->as_array);
+  }
+
+  btm_report_device_status(BTM_DEV_STATUS_UP);
+}
+
+// TODO(zachoverflow): remove this function
+void BTM_DeviceReset (UNUSED_ATTR tBTM_CMPL_CB *p_cb) {
+  /* Flush all ACL connections */
+  btm_acl_device_down();
+
+  /* Clear the callback, so application would not hang on reset */
+  btm_db_reset();
+
+  module_start_up_callbacked_wrapper(
+    get_module(CONTROLLER_MODULE),
+    bt_workqueue_thread,
+    reset_complete
+  );
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    return controller_get_interface()->get_is_ready();
+}
+
+/*******************************************************************************
+**
+** Function         btm_read_local_name_timeout
+**
+** Description      Callback when reading the local name times out.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_read_local_name_timeout(UNUSED_ATTR void *data)
+{
+    tBTM_CMPL_CB  *p_cb = btm_cb.devcb.p_rln_cmpl_cb;
+    btm_cb.devcb.p_rln_cmpl_cb = NULL;
+    if (p_cb)
+        (*p_cb)((void *) NULL);
+}
+
+/*******************************************************************************
+**
+** Function         btm_decode_ext_features_page
+**
+** Description      This function is decodes a features page.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_decode_ext_features_page (uint8_t page_number, const uint8_t *p_features)
+{
+    BTM_TRACE_DEBUG ("btm_decode_ext_features_page page: %d", page_number);
+    switch (page_number)
+    {
+    /* Extended (Legacy) Page 0 */
+    case HCI_EXT_FEATURES_PAGE_0:
+
+        /* Create ACL supported packet types mask */
+        btm_cb.btm_acl_pkt_types_supported = (BTM_ACL_PKT_TYPES_MASK_DH1 +
+                                              BTM_ACL_PKT_TYPES_MASK_DM1);
+
+        if (HCI_3_SLOT_PACKETS_SUPPORTED(p_features))
+            btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_DH3 +
+                                                   BTM_ACL_PKT_TYPES_MASK_DM3);
+
+        if (HCI_5_SLOT_PACKETS_SUPPORTED(p_features))
+            btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_DH5 +
+                                                   BTM_ACL_PKT_TYPES_MASK_DM5);
+
+        /* Add in EDR related ACL types */
+        if (!HCI_EDR_ACL_2MPS_SUPPORTED(p_features))
+        {
+            btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH1 +
+                                                   BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 +
+                                                   BTM_ACL_PKT_TYPES_MASK_NO_2_DH5);
+        }
+
+        if (!HCI_EDR_ACL_3MPS_SUPPORTED(p_features))
+        {
+            btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_NO_3_DH1 +
+                                                   BTM_ACL_PKT_TYPES_MASK_NO_3_DH3 +
+                                                   BTM_ACL_PKT_TYPES_MASK_NO_3_DH5);
+        }
+
+        /* Check to see if 3 and 5 slot packets are available */
+        if (HCI_EDR_ACL_2MPS_SUPPORTED(p_features) ||
+            HCI_EDR_ACL_3MPS_SUPPORTED(p_features))
+        {
+            if (!HCI_3_SLOT_EDR_ACL_SUPPORTED(p_features))
+                btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 +
+                                                       BTM_ACL_PKT_TYPES_MASK_NO_3_DH3);
+
+            if (!HCI_5_SLOT_EDR_ACL_SUPPORTED(p_features))
+                btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH5 +
+                                                       BTM_ACL_PKT_TYPES_MASK_NO_3_DH5);
+        }
+
+        BTM_TRACE_DEBUG("Local supported ACL packet types: 0x%04x",
+                         btm_cb.btm_acl_pkt_types_supported);
+
+        /* Create (e)SCO supported packet types mask */
+        btm_cb.btm_sco_pkt_types_supported = 0;
+#if (BTM_SCO_INCLUDED == TRUE)
+        btm_cb.sco_cb.esco_supported = false;
+#endif
+        if (HCI_SCO_LINK_SUPPORTED(p_features))
+        {
+            btm_cb.btm_sco_pkt_types_supported = BTM_SCO_PKT_TYPES_MASK_HV1;
+
+            if (HCI_HV2_PACKETS_SUPPORTED(p_features))
+                btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_HV2;
+
+            if (HCI_HV3_PACKETS_SUPPORTED(p_features))
+                btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_HV3;
+        }
+
+        if (HCI_ESCO_EV3_SUPPORTED(p_features))
+            btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_EV3;
+
+        if (HCI_ESCO_EV4_SUPPORTED(p_features))
+            btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_EV4;
+
+        if (HCI_ESCO_EV5_SUPPORTED(p_features))
+            btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_EV5;
+#if (BTM_SCO_INCLUDED == TRUE)
+        if (btm_cb.btm_sco_pkt_types_supported & BTM_ESCO_LINK_ONLY_MASK)
+        {
+            btm_cb.sco_cb.esco_supported = true;
+
+            /* Add in EDR related eSCO types */
+            if (HCI_EDR_ESCO_2MPS_SUPPORTED(p_features))
+            {
+                if (!HCI_3_SLOT_EDR_ESCO_SUPPORTED(p_features))
+                    btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_NO_2_EV5;
+            }
+            else
+            {
+                btm_cb.btm_sco_pkt_types_supported |= (BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 +
+                                                       BTM_SCO_PKT_TYPES_MASK_NO_2_EV5);
+            }
+
+            if (HCI_EDR_ESCO_3MPS_SUPPORTED(p_features))
+            {
+                if (!HCI_3_SLOT_EDR_ESCO_SUPPORTED(p_features))
+                    btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_NO_3_EV5;
+            }
+            else
+            {
+                btm_cb.btm_sco_pkt_types_supported |= (BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 +
+                                                       BTM_SCO_PKT_TYPES_MASK_NO_3_EV5);
+            }
+        }
+#endif
+
+        BTM_TRACE_DEBUG("Local supported SCO packet types: 0x%04x",
+                         btm_cb.btm_sco_pkt_types_supported);
+
+        /* Create Default Policy Settings */
+        if (HCI_SWITCH_SUPPORTED(p_features))
+            btm_cb.btm_def_link_policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+        else
+            btm_cb.btm_def_link_policy &= ~HCI_ENABLE_MASTER_SLAVE_SWITCH;
+
+        if (HCI_HOLD_MODE_SUPPORTED(p_features))
+            btm_cb.btm_def_link_policy |= HCI_ENABLE_HOLD_MODE;
+        else
+            btm_cb.btm_def_link_policy &= ~HCI_ENABLE_HOLD_MODE;
+
+        if (HCI_SNIFF_MODE_SUPPORTED(p_features))
+            btm_cb.btm_def_link_policy |= HCI_ENABLE_SNIFF_MODE;
+        else
+            btm_cb.btm_def_link_policy &= ~HCI_ENABLE_SNIFF_MODE;
+
+        if (HCI_PARK_MODE_SUPPORTED(p_features))
+            btm_cb.btm_def_link_policy |= HCI_ENABLE_PARK_MODE;
+        else
+            btm_cb.btm_def_link_policy &= ~HCI_ENABLE_PARK_MODE;
+
+        btm_sec_dev_reset ();
+
+        if (HCI_LMP_INQ_RSSI_SUPPORTED(p_features))
+        {
+            if (HCI_EXT_INQ_RSP_SUPPORTED(p_features))
+                BTM_SetInquiryMode (BTM_INQ_RESULT_EXTENDED);
+            else
+                BTM_SetInquiryMode (BTM_INQ_RESULT_WITH_RSSI);
+        }
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+        if( HCI_NON_FLUSHABLE_PB_SUPPORTED(p_features))
+            l2cu_set_non_flushable_pbf(true);
+        else
+            l2cu_set_non_flushable_pbf(false);
+#endif
+        BTM_SetPageScanType (BTM_DEFAULT_SCAN_TYPE);
+        BTM_SetInquiryScanType (BTM_DEFAULT_SCAN_TYPE);
+
+        break;
+
+    /* Extended Page 1 */
+    case HCI_EXT_FEATURES_PAGE_1:
+        /* Nothing to do for page 1 */
+        break;
+
+    /* Extended Page 2 */
+    case HCI_EXT_FEATURES_PAGE_2:
+        /* Nothing to do for page 2 */
+        break;
+
+    default:
+        BTM_TRACE_ERROR("btm_decode_ext_features_page page=%d unknown", page_number);
+        break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTM_SetLocalDeviceName
+**
+** Description      This function is called to set the local device name.
+**
+** Returns          status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetLocalDeviceName (char *p_name)
+{
+    uint8_t  *p;
+
+    if (!p_name || !p_name[0] || (strlen ((char *)p_name) > BD_NAME_LEN))
+        return (BTM_ILLEGAL_VALUE);
+
+    if (!controller_get_interface()->get_is_ready())
+        return (BTM_DEV_RESET);
+    /* Save the device name if local storage is enabled */
+    p = (uint8_t *)btm_cb.cfg.bd_name;
+    if (p != (uint8_t *)p_name)
+        strlcpy(btm_cb.cfg.bd_name, p_name, BTM_MAX_LOC_BD_NAME_LEN);
+
+    btsnd_hcic_change_name(p);
+    return (BTM_CMD_STARTED);
+}
+
+
+
+/*******************************************************************************
+**
+** 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)
+{
+    *p_name = btm_cb.cfg.bd_name;
+    return(BTM_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** 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)
+{
+    /* Check if rln already in progress */
+    if (btm_cb.devcb.p_rln_cmpl_cb)
+        return(BTM_NO_RESOURCES);
+
+    /* Save callback */
+    btm_cb.devcb.p_rln_cmpl_cb = p_rln_cmpl_cback;
+
+    btsnd_hcic_read_name();
+    alarm_set_on_queue(btm_cb.devcb.read_local_name_timer,
+                       BTM_DEV_NAME_REPLY_TIMEOUT_MS,
+                       btm_read_local_name_timeout, NULL,
+                       btu_general_alarm_queue);
+
+    return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function         btm_read_local_name_complete
+**
+** Description      This function is called when local name read complete.
+**                  message is received from the HCI.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_read_local_name_complete (uint8_t *p,
+                                   UNUSED_ATTR uint16_t evt_len)
+{
+    tBTM_CMPL_CB   *p_cb = btm_cb.devcb.p_rln_cmpl_cb;
+    uint8_t         status;
+
+    alarm_cancel(btm_cb.devcb.read_local_name_timer);
+
+    /* If there was a callback address for read local name, call it */
+    btm_cb.devcb.p_rln_cmpl_cb = NULL;
+
+    if (p_cb)
+    {
+        STREAM_TO_UINT8  (status, p);
+
+        if (status == HCI_SUCCESS)
+            (*p_cb)(p);
+        else
+            (*p_cb)(NULL);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTM_SetDeviceClass
+**
+** Description      This function is called to set the local device class
+**
+** Returns          status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetDeviceClass (DEV_CLASS dev_class)
+{
+    if(!memcmp (btm_cb.devcb.dev_class, dev_class, DEV_CLASS_LEN))
+        return(BTM_SUCCESS);
+
+    memcpy (btm_cb.devcb.dev_class, dev_class, DEV_CLASS_LEN);
+
+    if (!controller_get_interface()->get_is_ready())
+        return (BTM_DEV_RESET);
+
+    btsnd_hcic_write_dev_class(dev_class);
+
+    return (BTM_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** 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)
+{
+    return ((uint8_t *)btm_cb.devcb.dev_class);
+}
+
+
+/*******************************************************************************
+**
+** Function         BTM_ReadLocalFeatures
+**
+** Description      This function is called to read the local features
+**
+** Returns          pointer to the local features string
+**
+*******************************************************************************/
+// TODO(zachoverflow): get rid of this function
+uint8_t *BTM_ReadLocalFeatures (void)
+{
+    // Discarding const modifier for now, until this function dies
+    return (uint8_t *)controller_get_interface()->get_features_classic(0)->as_array;
+}
+
+/*******************************************************************************
+**
+** Function         BTM_RegisterForDeviceStatusNotif
+**
+** Description      This function is called to register for device status
+**                  change notifications.
+**
+**                  If one registration is already there calling function should
+**                  save the pointer to the function that is return and
+**                  call it when processing of the event is complete
+**
+** Returns          status of the operation
+**
+*******************************************************************************/
+tBTM_DEV_STATUS_CB *BTM_RegisterForDeviceStatusNotif (tBTM_DEV_STATUS_CB *p_cb)
+{
+    tBTM_DEV_STATUS_CB *p_prev = btm_cb.devcb.p_dev_status_cb;
+
+    btm_cb.devcb.p_dev_status_cb = p_cb;
+    return (p_prev);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_VendorSpecificCommand
+**
+** Description      Send a vendor specific HCI command to the controller.
+**
+** Notes
+**      Opcode will be OR'd with HCI_GRP_VENDOR_SPECIFIC.
+**
+*******************************************************************************/
+void BTM_VendorSpecificCommand(uint16_t opcode, uint8_t param_len,
+                                      uint8_t *p_param_buf, tBTM_VSC_CMPL_CB *p_cb)
+{
+    /* Allocate a buffer to hold HCI command plus the callback function */
+    void *p_buf = osi_malloc(sizeof(BT_HDR) + sizeof(tBTM_CMPL_CB *) +
+                             param_len + HCIC_PREAMBLE_SIZE);
+
+    BTM_TRACE_EVENT("BTM: %s: Opcode: 0x%04X, ParamLen: %i.", __func__,
+                    opcode, param_len);
+
+    /* Send the HCI command (opcode will be OR'd with HCI_GRP_VENDOR_SPECIFIC) */
+    btsnd_hcic_vendor_spec_cmd(p_buf, opcode, param_len, p_param_buf, (void *)p_cb);
+}
+
+
+/*******************************************************************************
+**
+** Function         btm_vsc_complete
+**
+** Description      This function is called when local HCI Vendor Specific
+**                  Command complete message is received from the HCI.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_vsc_complete (uint8_t *p, uint16_t opcode, uint16_t evt_len,
+                       tBTM_CMPL_CB *p_vsc_cplt_cback)
+{
+    tBTM_VSC_CMPL   vcs_cplt_params;
+
+    /* If there was a callback address for vcs complete, call it */
+    if (p_vsc_cplt_cback)
+    {
+        /* Pass paramters to the callback function */
+        vcs_cplt_params.opcode = opcode;        /* Number of bytes in return info */
+        vcs_cplt_params.param_len = evt_len;    /* Number of bytes in return info */
+        vcs_cplt_params.p_param_buf = p;
+        (*p_vsc_cplt_cback)(&vcs_cplt_params);  /* Call the VSC complete callback function */
+    }
+}
+
+/*******************************************************************************
+**
+** 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;
+**                  if is_register=false, then 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)
+{
+    tBTM_STATUS retval = BTM_SUCCESS;
+    uint8_t i, free_idx = BTM_MAX_VSE_CALLBACKS;
+
+    /* See if callback is already registered */
+    for (i=0; i<BTM_MAX_VSE_CALLBACKS; i++)
+    {
+        if (btm_cb.devcb.p_vend_spec_cb[i] == NULL)
+        {
+            /* Found a free slot. Store index */
+            free_idx = i;
+        }
+        else if (btm_cb.devcb.p_vend_spec_cb[i] == p_cb)
+        {
+            /* Found callback in lookup table. If deregistering, clear the entry. */
+            if (is_register == false)
+            {
+                btm_cb.devcb.p_vend_spec_cb[i] = NULL;
+                BTM_TRACE_EVENT("BTM Deregister For VSEvents is successfully");
+            }
+            return (BTM_SUCCESS);
+        }
+    }
+
+    /* Didn't find callback. Add callback to free slot if registering */
+    if (is_register)
+    {
+        if (free_idx < BTM_MAX_VSE_CALLBACKS)
+        {
+            btm_cb.devcb.p_vend_spec_cb[free_idx] = p_cb;
+            BTM_TRACE_EVENT("BTM Register For VSEvents is successfully");
+        }
+        else
+        {
+            /* No free entries available */
+            BTM_TRACE_ERROR ("BTM_RegisterForVSEvents: too many callbacks registered");
+
+            retval = BTM_NO_RESOURCES;
+        }
+    }
+
+    return (retval);
+}
+
+/*******************************************************************************
+**
+** Function         btm_vendor_specific_evt
+**
+** Description      Process event HCI_VENDOR_SPECIFIC_EVT
+**
+**                  Note: Some controllers do not send command complete, so
+**                  the callback and busy flag are cleared here also.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_vendor_specific_evt (uint8_t *p, uint8_t evt_len)
+{
+    uint8_t i;
+
+    BTM_TRACE_DEBUG ("BTM Event: Vendor Specific event from controller");
+
+    for (i=0; i<BTM_MAX_VSE_CALLBACKS; i++)
+    {
+        if (btm_cb.devcb.p_vend_spec_cb[i])
+            (*btm_cb.devcb.p_vend_spec_cb[i])(evt_len, p);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         BTM_WritePageTimeout
+**
+** Description      Send HCI Write Page Timeout.
+**
+*******************************************************************************/
+void BTM_WritePageTimeout(uint16_t timeout)
+{
+    BTM_TRACE_EVENT ("BTM: BTM_WritePageTimeout: Timeout: %d.", timeout);
+
+    /* Send the HCI command */
+    btsnd_hcic_write_page_tout(timeout);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_WriteVoiceSettings
+**
+** Description      Send HCI Write Voice Settings command.
+**                  See hcidefs.h for settings bitmask values.
+**
+*******************************************************************************/
+void BTM_WriteVoiceSettings(uint16_t settings)
+{
+    BTM_TRACE_EVENT ("BTM: BTM_WriteVoiceSettings: Settings: 0x%04x.", settings);
+
+    /* Send the HCI command */
+    btsnd_hcic_write_voice_settings((uint16_t)(settings & 0x03ff));
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    uint8_t cond;
+
+    BTM_TRACE_EVENT ("BTM: BTM_EnableTestMode");
+
+    /* set auto accept connection as this is needed during test mode */
+    /* Allocate a buffer to hold HCI command */
+    cond = HCI_DO_AUTO_ACCEPT_CONNECT;
+    btsnd_hcic_set_event_filter(HCI_FILTER_CONNECTION_SETUP,
+                                HCI_FILTER_COND_NEW_DEVICE,
+                                &cond, sizeof(cond));
+
+    /* put device to connectable mode */
+    if (BTM_SetConnectability(BTM_CONNECTABLE, BTM_DEFAULT_CONN_WINDOW,
+                              BTM_DEFAULT_CONN_INTERVAL) != BTM_SUCCESS) {
+        return BTM_NO_RESOURCES;
+    }
+
+    /* put device to discoverable mode */
+    if (BTM_SetDiscoverability(BTM_GENERAL_DISCOVERABLE,
+                               BTM_DEFAULT_DISC_WINDOW,
+                               BTM_DEFAULT_DISC_INTERVAL) != BTM_SUCCESS) {
+        return BTM_NO_RESOURCES;
+    }
+
+    /* mask off all of event from controller */
+    hci_layer_get_interface()->transmit_command(
+      hci_packet_factory_get_interface()->make_set_event_mask((const bt_event_mask_t *)("\x00\x00\x00\x00\x00\x00\x00\x00")),
+      NULL,
+      NULL,
+      NULL);
+
+    /* Send the HCI command */
+    btsnd_hcic_enable_test_mode();
+    return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** 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(BD_ADDR bd_addr, tBTM_CMPL_CB *p_cb)
+{
+    BD_ADDR local_bd_addr;
+    bool    delete_all_flag = false;
+
+    /* Check if the previous command is completed */
+    if (btm_cb.devcb.p_stored_link_key_cmpl_cb)
+        return (BTM_BUSY);
+
+    if (!bd_addr)
+    {
+        /* This is to delete all link keys */
+        delete_all_flag = true;
+
+        /* We don't care the BD address. Just pass a non zero pointer */
+        bd_addr = local_bd_addr;
+    }
+
+    BTM_TRACE_EVENT ("BTM: BTM_DeleteStoredLinkKey: delete_all_flag: %s",
+                        delete_all_flag ? "true" : "false");
+
+    /* Send the HCI command */
+    btm_cb.devcb.p_stored_link_key_cmpl_cb = p_cb;
+    btsnd_hcic_delete_stored_key(bd_addr, delete_all_flag);
+    return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         btm_delete_stored_link_key_complete
+**
+** Description      This function is called when the command complete message
+**                  is received from the HCI for the delete stored link key command.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_delete_stored_link_key_complete (uint8_t *p)
+{
+    tBTM_CMPL_CB         *p_cb = btm_cb.devcb.p_stored_link_key_cmpl_cb;
+    tBTM_DELETE_STORED_LINK_KEY_COMPLETE  result;
+
+    /* If there was a callback registered for read stored link key, call it */
+    btm_cb.devcb.p_stored_link_key_cmpl_cb = NULL;
+
+    if (p_cb)
+    {
+        /* Set the call back event to indicate command complete */
+        result.event = BTM_CB_EVT_DELETE_STORED_LINK_KEYS;
+
+        /* Extract the result fields from the HCI event */
+        STREAM_TO_UINT8  (result.status, p);
+        STREAM_TO_UINT16 (result.num_keys, p);
+
+        /* Call the call back and pass the result */
+        (*p_cb)(&result);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_report_device_status
+**
+** Description      This function is called when there is a change in the device
+**                  status. This function will report the new device status to
+**                  the application
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_report_device_status (tBTM_DEV_STATUS status)
+{
+    tBTM_DEV_STATUS_CB *p_cb = btm_cb.devcb.p_dev_status_cb;
+
+    /* Call the call back to pass the device status to application */
+    if (p_cb)
+        (*p_cb)(status);
+}
+
+
diff --git a/bt/stack/btm/btm_inq.cc b/bt/stack/btm/btm_inq.cc
new file mode 100644
index 0000000..e52b62f
--- /dev/null
+++ b/bt/stack/btm/btm_inq.cc
@@ -0,0 +1,2928 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-2014 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 functions that handle inquiries. These include
+ *  setting discoverable mode, controlling the mode of the Baseband, and
+ *  maintaining a small database of inquiry responses, with API for people
+ *  to browse it.
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "device/include/controller.h"
+#include "osi/include/osi.h"
+#include "osi/include/time.h"
+
+#include "bt_types.h"
+#include "bt_common.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "hcidefs.h"
+
+/* 3 second timeout waiting for responses */
+#define BTM_INQ_REPLY_TIMEOUT_MS (3 * 1000)
+
+/* TRUE to enable DEBUG traces for btm_inq */
+#ifndef BTM_INQ_DEBUG
+#define BTM_INQ_DEBUG FALSE
+#endif
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+/********************************************************************************/
+/*                 L O C A L    D A T A    D E F I N I T I O N S                */
+/********************************************************************************/
+static const LAP general_inq_lap = {0x9e,0x8b,0x33};
+static const LAP limited_inq_lap = {0x9e,0x8b,0x00};
+
+const uint16_t BTM_EIR_UUID_LKUP_TBL[BTM_EIR_MAX_SERVICES] =
+{
+    UUID_SERVCLASS_SERVICE_DISCOVERY_SERVER,
+/*    UUID_SERVCLASS_BROWSE_GROUP_DESCRIPTOR,   */
+/*    UUID_SERVCLASS_PUBLIC_BROWSE_GROUP,       */
+    UUID_SERVCLASS_SERIAL_PORT,
+    UUID_SERVCLASS_LAN_ACCESS_USING_PPP,
+    UUID_SERVCLASS_DIALUP_NETWORKING,
+    UUID_SERVCLASS_IRMC_SYNC,
+    UUID_SERVCLASS_OBEX_OBJECT_PUSH,
+    UUID_SERVCLASS_OBEX_FILE_TRANSFER,
+    UUID_SERVCLASS_IRMC_SYNC_COMMAND,
+    UUID_SERVCLASS_HEADSET,
+    UUID_SERVCLASS_CORDLESS_TELEPHONY,
+    UUID_SERVCLASS_AUDIO_SOURCE,
+    UUID_SERVCLASS_AUDIO_SINK,
+    UUID_SERVCLASS_AV_REM_CTRL_TARGET,
+/*    UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION,    */
+    UUID_SERVCLASS_AV_REMOTE_CONTROL,
+/*    UUID_SERVCLASS_VIDEO_CONFERENCING,        */
+    UUID_SERVCLASS_INTERCOM,
+    UUID_SERVCLASS_FAX,
+    UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY,
+/*    UUID_SERVCLASS_WAP,                       */
+/*    UUID_SERVCLASS_WAP_CLIENT,                */
+    UUID_SERVCLASS_PANU,
+    UUID_SERVCLASS_NAP,
+    UUID_SERVCLASS_GN,
+    UUID_SERVCLASS_DIRECT_PRINTING,
+/*    UUID_SERVCLASS_REFERENCE_PRINTING,        */
+    UUID_SERVCLASS_IMAGING,
+    UUID_SERVCLASS_IMAGING_RESPONDER,
+    UUID_SERVCLASS_IMAGING_AUTO_ARCHIVE,
+    UUID_SERVCLASS_IMAGING_REF_OBJECTS,
+    UUID_SERVCLASS_HF_HANDSFREE,
+    UUID_SERVCLASS_AG_HANDSFREE,
+    UUID_SERVCLASS_DIR_PRT_REF_OBJ_SERVICE,
+/*    UUID_SERVCLASS_REFLECTED_UI,              */
+    UUID_SERVCLASS_BASIC_PRINTING,
+    UUID_SERVCLASS_PRINTING_STATUS,
+    UUID_SERVCLASS_HUMAN_INTERFACE,
+    UUID_SERVCLASS_CABLE_REPLACEMENT,
+    UUID_SERVCLASS_HCRP_PRINT,
+    UUID_SERVCLASS_HCRP_SCAN,
+/*    UUID_SERVCLASS_COMMON_ISDN_ACCESS,        */
+/*    UUID_SERVCLASS_VIDEO_CONFERENCING_GW,     */
+/*    UUID_SERVCLASS_UDI_MT,                    */
+/*    UUID_SERVCLASS_UDI_TA,                    */
+/*    UUID_SERVCLASS_VCP,                       */
+    UUID_SERVCLASS_SAP,
+    UUID_SERVCLASS_PBAP_PCE,
+    UUID_SERVCLASS_PBAP_PSE,
+    UUID_SERVCLASS_PHONE_ACCESS,
+    UUID_SERVCLASS_HEADSET_HS,
+    UUID_SERVCLASS_PNP_INFORMATION,
+/*    UUID_SERVCLASS_GENERIC_NETWORKING,        */
+/*    UUID_SERVCLASS_GENERIC_FILETRANSFER,      */
+/*    UUID_SERVCLASS_GENERIC_AUDIO,             */
+/*    UUID_SERVCLASS_GENERIC_TELEPHONY,         */
+/*    UUID_SERVCLASS_UPNP_SERVICE,              */
+/*    UUID_SERVCLASS_UPNP_IP_SERVICE,           */
+/*    UUID_SERVCLASS_ESDP_UPNP_IP_PAN,          */
+/*    UUID_SERVCLASS_ESDP_UPNP_IP_LAP,          */
+/*    UUID_SERVCLASS_ESDP_UPNP_IP_L2CAP,        */
+    UUID_SERVCLASS_VIDEO_SOURCE,
+    UUID_SERVCLASS_VIDEO_SINK,
+/*    UUID_SERVCLASS_VIDEO_DISTRIBUTION         */
+    UUID_SERVCLASS_MESSAGE_ACCESS,
+    UUID_SERVCLASS_MESSAGE_NOTIFICATION,
+    UUID_SERVCLASS_HDP_SOURCE,
+    UUID_SERVCLASS_HDP_SINK
+};
+
+/********************************************************************************/
+/*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
+/********************************************************************************/
+static void         btm_initiate_inquiry (tBTM_INQUIRY_VAR_ST *p_inq);
+static tBTM_STATUS  btm_set_inq_event_filter (uint8_t filter_cond_type, tBTM_INQ_FILT_COND *p_filt_cond);
+static void         btm_clr_inq_result_flt (void);
+
+static uint8_t      btm_convert_uuid_to_eir_service( uint16_t uuid16 );
+static void         btm_set_eir_uuid( uint8_t *p_eir, tBTM_INQ_RESULTS *p_results );
+static uint8_t     *btm_eir_get_uuid_list( uint8_t *p_eir, uint8_t uuid_size,
+                                           uint8_t *p_num_uuid, uint8_t *p_uuid_list_type );
+static uint16_t     btm_convert_uuid_to_uuid16( uint8_t *p_uuid, uint8_t uuid_size );
+
+/*******************************************************************************
+**
+** 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)
+{
+    uint8_t      scan_mode = 0;
+    uint16_t     service_class;
+    uint8_t     *p_cod;
+    uint8_t      major, minor;
+    DEV_CLASS    cod;
+    LAP          temp_lap[2];
+    bool         is_limited;
+    bool         cod_limited;
+
+    BTM_TRACE_API ("BTM_SetDiscoverability");
+#if (BLE_INCLUDED == TRUE && BLE_INCLUDED == TRUE)
+    if (controller_get_interface()->supports_ble())
+    {
+        if (btm_ble_set_discoverability((uint16_t)(inq_mode))
+                            == BTM_SUCCESS)
+        {
+            btm_cb.btm_inq_vars.discoverable_mode &= (~BTM_BLE_DISCOVERABLE_MASK);
+            btm_cb.btm_inq_vars.discoverable_mode |= (inq_mode & BTM_BLE_DISCOVERABLE_MASK);
+        }
+    }
+    inq_mode &= ~BTM_BLE_DISCOVERABLE_MASK;
+#endif
+
+    /*** Check mode parameter ***/
+    if (inq_mode > BTM_MAX_DISCOVERABLE)
+        return (BTM_ILLEGAL_VALUE);
+
+    /* Make sure the controller is active */
+    if (!controller_get_interface()->get_is_ready())
+        return (BTM_DEV_RESET);
+
+    /* If the window and/or interval is '0', set to default values */
+    if (!window)
+        window = BTM_DEFAULT_DISC_WINDOW;
+
+    if (!interval)
+        interval = BTM_DEFAULT_DISC_INTERVAL;
+
+    BTM_TRACE_API ("BTM_SetDiscoverability: mode %d [NonDisc-0, Lim-1, Gen-2], window 0x%04x, interval 0x%04x",
+                        inq_mode, window, interval);
+
+    /*** Check for valid window and interval parameters ***/
+    /*** Only check window and duration if mode is connectable ***/
+    if (inq_mode != BTM_NON_DISCOVERABLE)
+    {
+        /* window must be less than or equal to interval */
+        if (window < HCI_MIN_INQUIRYSCAN_WINDOW     ||
+            window > HCI_MAX_INQUIRYSCAN_WINDOW     ||
+            interval < HCI_MIN_INQUIRYSCAN_INTERVAL ||
+            interval > HCI_MAX_INQUIRYSCAN_INTERVAL ||
+            window > interval)
+        {
+            return (BTM_ILLEGAL_VALUE);
+        }
+    }
+
+    /* Set the IAC if needed */
+    if (inq_mode != BTM_NON_DISCOVERABLE)
+    {
+        if (inq_mode & BTM_LIMITED_DISCOVERABLE)
+        {
+            /* Use the GIAC and LIAC codes for limited discoverable mode */
+            memcpy (temp_lap[0], limited_inq_lap, LAP_LEN);
+            memcpy (temp_lap[1], general_inq_lap, LAP_LEN);
+
+            btsnd_hcic_write_cur_iac_lap(2, (LAP * const) temp_lap);
+        }
+        else
+        {
+            btsnd_hcic_write_cur_iac_lap(1, (LAP * const) &general_inq_lap);
+        }
+
+        scan_mode |= HCI_INQUIRY_SCAN_ENABLED;
+    }
+
+    /* Send down the inquiry scan window and period if changed */
+    if ((window != btm_cb.btm_inq_vars.inq_scan_window) ||
+        (interval != btm_cb.btm_inq_vars.inq_scan_period))
+    {
+        btsnd_hcic_write_inqscan_cfg(interval, window);
+        btm_cb.btm_inq_vars.inq_scan_window = window;
+        btm_cb.btm_inq_vars.inq_scan_period = interval;
+    }
+
+    if (btm_cb.btm_inq_vars.connectable_mode & BTM_CONNECTABLE_MASK)
+        scan_mode |= HCI_PAGE_SCAN_ENABLED;
+
+    btsnd_hcic_write_scan_enable (scan_mode);
+    btm_cb.btm_inq_vars.discoverable_mode &= (~BTM_DISCOVERABLE_MASK);
+    btm_cb.btm_inq_vars.discoverable_mode |= inq_mode;
+
+    /* Change the service class bit if mode has changed */
+    p_cod = BTM_ReadDeviceClass();
+    BTM_COD_SERVICE_CLASS(service_class, p_cod);
+    is_limited = (inq_mode & BTM_LIMITED_DISCOVERABLE) ? true : false;
+    cod_limited = (service_class & BTM_COD_SERVICE_LMTD_DISCOVER) ? true : false;
+    if (is_limited ^ cod_limited)
+    {
+        BTM_COD_MINOR_CLASS(minor, p_cod );
+        BTM_COD_MAJOR_CLASS(major, p_cod );
+        if (is_limited)
+            service_class |= BTM_COD_SERVICE_LMTD_DISCOVER;
+        else
+            service_class &= ~BTM_COD_SERVICE_LMTD_DISCOVER;
+
+        FIELDS_TO_COD(cod, minor, major, service_class);
+        (void) BTM_SetDeviceClass (cod);
+    }
+
+    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 BTM_SetInquiryScanType (uint16_t scan_type)
+{
+
+    BTM_TRACE_API ("BTM_SetInquiryScanType");
+    if (scan_type != BTM_SCAN_TYPE_STANDARD && scan_type != BTM_SCAN_TYPE_INTERLACED)
+        return (BTM_ILLEGAL_VALUE);
+
+    /* whatever app wants if device is not 1.2 scan type should be STANDARD */
+    if (!controller_get_interface()->supports_interlaced_inquiry_scan())
+     return (BTM_MODE_UNSUPPORTED);
+
+    /* Check for scan type if configuration has been changed */
+    if (scan_type != btm_cb.btm_inq_vars.inq_scan_type)
+    {
+        if (BTM_IsDeviceUp())
+        {
+            btsnd_hcic_write_inqscan_type((uint8_t)scan_type);
+            btm_cb.btm_inq_vars.inq_scan_type = scan_type;
+        }
+        else return (BTM_WRONG_MODE);
+    }
+    return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** 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 BTM_SetPageScanType (uint16_t scan_type)
+{
+    BTM_TRACE_API ("BTM_SetPageScanType");
+    if (scan_type != BTM_SCAN_TYPE_STANDARD && scan_type != BTM_SCAN_TYPE_INTERLACED)
+        return (BTM_ILLEGAL_VALUE);
+
+    /* whatever app wants if device is not 1.2 scan type should be STANDARD */
+    if (!controller_get_interface()->supports_interlaced_inquiry_scan())
+     return (BTM_MODE_UNSUPPORTED);
+
+    /* Check for scan type if configuration has been changed */
+    if (scan_type != btm_cb.btm_inq_vars.page_scan_type)
+    {
+        if (BTM_IsDeviceUp())
+        {
+            btsnd_hcic_write_pagescan_type ((uint8_t)scan_type);
+            btm_cb.btm_inq_vars.page_scan_type  = scan_type;
+        }
+        else return (BTM_WRONG_MODE);
+    }
+    return (BTM_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** 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 BTM_SetInquiryMode (uint8_t mode)
+{
+    const controller_t *controller = controller_get_interface();
+    BTM_TRACE_API ("BTM_SetInquiryMode");
+    if (mode == BTM_INQ_RESULT_STANDARD)
+    {
+        /* mandatory mode */
+    }
+    else if (mode == BTM_INQ_RESULT_WITH_RSSI)
+    {
+        if (!controller->supports_rssi_with_inquiry_results())
+            return (BTM_MODE_UNSUPPORTED);
+    }
+    else if (mode == BTM_INQ_RESULT_EXTENDED)
+    {
+        if (!controller->supports_extended_inquiry_response())
+            return (BTM_MODE_UNSUPPORTED);
+    }
+    else
+        return (BTM_ILLEGAL_VALUE);
+
+    if (!BTM_IsDeviceUp())
+        return (BTM_WRONG_MODE);
+
+    btsnd_hcic_write_inquiry_mode(mode);
+
+    return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    BTM_TRACE_API ("BTM_ReadDiscoverability");
+    if (p_window)
+        *p_window = btm_cb.btm_inq_vars.inq_scan_window;
+
+    if (p_interval)
+        *p_interval = btm_cb.btm_inq_vars.inq_scan_period;
+
+    return (btm_cb.btm_inq_vars.discoverable_mode);
+}
+
+
+/*******************************************************************************
+**
+** 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 BTM_SetPeriodicInquiryMode (tBTM_INQ_PARMS *p_inqparms, uint16_t max_delay,
+                                        uint16_t min_delay, tBTM_INQ_RESULTS_CB *p_results_cb)
+{
+    tBTM_STATUS  status;
+    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+    BTM_TRACE_API ("BTM_SetPeriodicInquiryMode: mode: %d, dur: %d, rsps: %d, flt: %d, min: %d, max: %d",
+        p_inqparms->mode, p_inqparms->duration, p_inqparms->max_resps,
+        p_inqparms->filter_cond_type, min_delay, max_delay);
+
+    /*** Make sure the device is ready ***/
+    if (!BTM_IsDeviceUp())
+        return (BTM_WRONG_MODE);
+
+    /* Only one active inquiry is allowed in this implementation.
+       Also do not allow an inquiry if the inquiry filter is being updated */
+    if (p_inq->inq_active || p_inq->inqfilt_active)
+        return (BTM_BUSY);
+
+    /* If illegal parameters return false */
+    if (p_inqparms->mode != BTM_GENERAL_INQUIRY &&
+        p_inqparms->mode != BTM_LIMITED_INQUIRY)
+        return (BTM_ILLEGAL_VALUE);
+
+    /* Verify the parameters for this command */
+    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)
+ /*       max_delay > BTM_PER_INQ_MAX_MAX_PERIOD)*/
+ /*  BTM_PER_INQ_MAX_MAX_PERIOD set to 1's in all bits. Condition resulting in false always*/
+    {
+        return (BTM_ILLEGAL_VALUE);
+    }
+
+    /* Save the inquiry parameters to be used upon the completion of setting/clearing the inquiry filter */
+    p_inq->inqparms = *p_inqparms;
+    p_inq->per_min_delay = min_delay;
+    p_inq->per_max_delay = max_delay;
+    p_inq->inq_cmpl_info.num_resp = 0;         /* Clear the results counter */
+    p_inq->p_inq_results_cb = p_results_cb;
+
+    p_inq->inq_active = (uint8_t)((p_inqparms->mode == BTM_LIMITED_INQUIRY) ?
+                            (BTM_LIMITED_INQUIRY_ACTIVE | BTM_PERIODIC_INQUIRY_ACTIVE) :
+                            (BTM_GENERAL_INQUIRY_ACTIVE | BTM_PERIODIC_INQUIRY_ACTIVE));
+
+    /* If a filter is specified, then save it for later and clear the current filter.
+       The setting of the filter is done upon completion of clearing of the previous
+       filter.
+    */
+    if (p_inqparms->filter_cond_type != BTM_CLR_INQUIRY_FILTER)
+    {
+        p_inq->state = BTM_INQ_CLR_FILT_STATE;
+        p_inqparms->filter_cond_type = BTM_CLR_INQUIRY_FILTER;
+    }
+    else    /* The filter is not being used so simply clear it; the inquiry can start after this operation */
+        p_inq->state = BTM_INQ_SET_FILT_STATE;
+
+    /* Before beginning the inquiry the current filter must be cleared, so initiate the command */
+    if ((status = btm_set_inq_event_filter (p_inqparms->filter_cond_type, &p_inqparms->filter_cond)) != BTM_CMD_STARTED)
+    {
+        /* If set filter command is not succesful reset the state */
+        p_inq->p_inq_results_cb = NULL;
+        p_inq->state = BTM_INQ_INACTIVE_STATE;
+
+    }
+
+    return (status);
+}
+
+
+/*******************************************************************************
+**
+** 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)
+{
+    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+    tBTM_STATUS          status = BTM_SUCCESS;
+    BTM_TRACE_API ("BTM_CancelPeriodicInquiry called");
+
+    /*** Make sure the device is ready ***/
+    if (!BTM_IsDeviceUp())
+        return (BTM_WRONG_MODE);
+
+    /* Only cancel if one is active */
+    if (btm_cb.btm_inq_vars.inq_active & BTM_PERIODIC_INQUIRY_ACTIVE)
+    {
+        btm_cb.btm_inq_vars.inq_active = BTM_INQUIRY_INACTIVE;
+        btm_cb.btm_inq_vars.p_inq_results_cb = (tBTM_INQ_RESULTS_CB *) NULL;
+
+        btsnd_hcic_exit_per_inq();
+
+        /* If the event filter is in progress, mark it so that the processing of the return
+           event will be ignored */
+        if(p_inq->inqfilt_active)
+            p_inq->pending_filt_complete_event++;
+
+        p_inq->inqfilt_active = false;
+        p_inq->inq_counter++;
+    }
+
+    return (status);
+}
+
+
+/*******************************************************************************
+**
+** Function         BTM_SetConnectability
+**
+** Description      This function is called to set the device into or out of
+**                  connectable mode. Discoverable mode means page scans 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)
+{
+    uint8_t  scan_mode = 0;
+    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+    BTM_TRACE_API ("BTM_SetConnectability");
+
+#if (BLE_INCLUDED == TRUE && BLE_INCLUDED == TRUE)
+    if (controller_get_interface()->supports_ble())
+    {
+        if (btm_ble_set_connectability(page_mode) != BTM_SUCCESS)
+        {
+            return BTM_NO_RESOURCES;
+        }
+        p_inq->connectable_mode &= (~BTM_BLE_CONNECTABLE_MASK);
+        p_inq->connectable_mode |= (page_mode & BTM_BLE_CONNECTABLE_MASK);
+    }
+    page_mode &= ~BTM_BLE_CONNECTABLE_MASK;
+#endif
+
+    /*** Check mode parameter ***/
+    if (page_mode != BTM_NON_CONNECTABLE && page_mode != BTM_CONNECTABLE)
+        return (BTM_ILLEGAL_VALUE);
+
+    /* Make sure the controller is active */
+    if (!controller_get_interface()->get_is_ready())
+        return (BTM_DEV_RESET);
+
+    /* If the window and/or interval is '0', set to default values */
+    if (!window)
+        window = BTM_DEFAULT_CONN_WINDOW;
+
+    if (!interval)
+        interval = BTM_DEFAULT_CONN_INTERVAL;
+
+    BTM_TRACE_API ("BTM_SetConnectability: mode %d [NonConn-0, Conn-1], window 0x%04x, interval 0x%04x",
+                        page_mode, window, interval);
+
+    /*** Check for valid window and interval parameters ***/
+    /*** Only check window and duration if mode is connectable ***/
+    if (page_mode == BTM_CONNECTABLE)
+    {
+        /* window must be less than or equal to interval */
+        if (window < HCI_MIN_PAGESCAN_WINDOW     ||
+            window > HCI_MAX_PAGESCAN_WINDOW     ||
+            interval < HCI_MIN_PAGESCAN_INTERVAL ||
+            interval > HCI_MAX_PAGESCAN_INTERVAL ||
+            window > interval)
+        {
+            return (BTM_ILLEGAL_VALUE);
+        }
+
+        scan_mode |= HCI_PAGE_SCAN_ENABLED;
+    }
+
+    if ((window != p_inq->page_scan_window) ||
+        (interval != p_inq->page_scan_period))
+    {
+        p_inq->page_scan_window = window;
+        p_inq->page_scan_period = interval;
+        btsnd_hcic_write_pagescan_cfg(interval, window);
+    }
+
+    /* Keep the inquiry scan as previouosly set */
+    if (p_inq->discoverable_mode & BTM_DISCOVERABLE_MASK)
+        scan_mode |= HCI_INQUIRY_SCAN_ENABLED;
+
+    btsnd_hcic_write_scan_enable (scan_mode);
+    p_inq->connectable_mode &= (~BTM_CONNECTABLE_MASK);
+    p_inq->connectable_mode |= page_mode;
+    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 BTM_ReadConnectability (uint16_t *p_window, uint16_t *p_interval)
+{
+    BTM_TRACE_API ("BTM_ReadConnectability");
+    if (p_window)
+        *p_window = btm_cb.btm_inq_vars.page_scan_window;
+
+    if (p_interval)
+        *p_interval = btm_cb.btm_inq_vars.page_scan_period;
+
+    return (btm_cb.btm_inq_vars.connectable_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 BTM_IsInquiryActive (void)
+{
+    BTM_TRACE_API ("BTM_IsInquiryActive");
+
+    return(btm_cb.btm_inq_vars.inq_active);
+}
+
+
+
+/*******************************************************************************
+**
+** 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)
+{
+    tBTM_STATUS           status = BTM_SUCCESS;
+    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+    uint8_t active_mode=p_inq->inq_active;
+#endif
+    BTM_TRACE_API ("BTM_CancelInquiry called");
+
+    /*** Make sure the device is ready ***/
+    if (!BTM_IsDeviceUp())
+        return (BTM_WRONG_MODE);
+
+    /* Only cancel if not in periodic mode, otherwise the caller should call BTM_CancelPeriodicMode */
+    if ((p_inq->inq_active &BTM_INQUIRY_ACTIVE_MASK) != 0 &&
+        (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE)))
+    {
+        p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+        p_inq->state = BTM_INQ_INACTIVE_STATE;
+        p_inq->p_inq_results_cb = (tBTM_INQ_RESULTS_CB *) NULL; /* Do not notify caller anymore */
+        p_inq->p_inq_cmpl_cb = (tBTM_CMPL_CB *) NULL;    /* Do not notify caller anymore */
+
+        /* If the event filter is in progress, mark it so that the processing of the return
+            event will be ignored */
+        if (p_inq->inqfilt_active)
+        {
+            p_inq->inqfilt_active = false;
+            p_inq->pending_filt_complete_event++;
+        }
+         /* Initiate the cancel inquiry */
+        else
+        {
+            if (((p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK) != 0)
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+            &&(active_mode & BTM_BR_INQUIRY_MASK)
+#endif
+            )
+            {
+                btsnd_hcic_inq_cancel();
+            }
+#if (BLE_INCLUDED == TRUE)
+            if (((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0)
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+            &&(active_mode & BTM_BLE_INQ_ACTIVE_MASK)
+#endif
+            )
+                btm_ble_stop_inquiry();
+#endif
+        }
+
+        /* Do not send the BUSY_LEVEL event yet. Wait for the cancel_complete event
+         * and then send the BUSY_LEVEL event
+         * btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT);
+         */
+
+         p_inq->inq_counter++;
+         btm_clr_inq_result_flt();
+    }
+
+    return (status);
+}
+
+
+/*******************************************************************************
+**
+** 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 BTM_StartInquiry (tBTM_INQ_PARMS *p_inqparms, tBTM_INQ_RESULTS_CB *p_results_cb,
+                              tBTM_CMPL_CB *p_cmpl_cb)
+{
+    tBTM_STATUS  status = BTM_CMD_STARTED;
+    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+    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);
+
+    /* Only one active inquiry is allowed in this implementation.
+       Also do not allow an inquiry if the inquiry filter is being updated */
+    if (p_inq->inq_active || p_inq->inqfilt_active)
+    {
+#if (BLE_INCLUDED == TRUE)
+        /*check if LE observe is already running*/
+        if(p_inq->scan_type==INQ_LE_OBSERVE && p_inq->p_inq_ble_results_cb!=NULL)
+        {
+            BTM_TRACE_API("BTM_StartInquiry: LE observe in progress");
+            p_inq->scan_type = INQ_GENERAL;
+            p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+            btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE;
+            btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
+        }
+        else
+#endif
+        {
+            return (BTM_BUSY);
+            BTM_TRACE_API("BTM_StartInquiry: return BUSY");
+        }
+    }
+    else
+        p_inq->scan_type = INQ_GENERAL;
+
+        /*** Make sure the device is ready ***/
+    if (!BTM_IsDeviceUp())
+        return (BTM_WRONG_MODE);
+
+    if ((p_inqparms->mode & BTM_BR_INQUIRY_MASK)!= BTM_GENERAL_INQUIRY &&
+        (p_inqparms->mode & BTM_BR_INQUIRY_MASK)!= BTM_LIMITED_INQUIRY
+#if (BLE_INCLUDED == TRUE)
+        && (p_inqparms->mode & BTM_BLE_INQUIRY_MASK)!= BTM_BLE_GENERAL_INQUIRY
+        && (p_inqparms->mode & BTM_BLE_INQUIRY_MASK)!= BTM_BLE_LIMITED_INQUIRY
+#endif
+        )
+        return (BTM_ILLEGAL_VALUE);
+
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+        if(p_inq->next_state==BTM_FINISH)
+            return BTM_ILLEGAL_VALUE;
+#endif
+
+
+    /* Save the inquiry parameters to be used upon the completion of setting/clearing the inquiry filter */
+    p_inq->inqparms = *p_inqparms;
+
+    /* Initialize the inquiry variables */
+    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_TRACE_DEBUG("BTM_StartInquiry: p_inq->inq_active = 0x%02x", p_inq->inq_active);
+
+/* interleave scan minimal conditions */
+#if (BLE_INCLUDED == TRUE && BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+
+    /* check if both modes are present */
+    if((p_inqparms->mode & BTM_BLE_INQUIRY_MASK) && (p_inqparms->mode & BTM_BR_INQUIRY_MASK))
+    {
+        BTM_TRACE_API("BTM:Interleave Inquiry Mode Set");
+        p_inqparms->duration=p_inqparms->intl_duration[p_inq->next_state];
+        p_inq->inqparms.duration=p_inqparms->duration;
+    }
+    else
+    {
+        BTM_TRACE_API("BTM:Single Mode: No interleaving, Mode:0x%02x", p_inqparms->mode);
+        p_inq->next_state=BTM_NO_INTERLEAVING;
+    }
+#endif
+
+
+
+/* start LE inquiry here if requested */
+#if (BLE_INCLUDED == TRUE)
+    if ((p_inqparms->mode & BTM_BLE_INQUIRY_MASK)
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+        &&(p_inq->next_state==BTM_BLE_ONE || p_inq->next_state==BTM_BLE_TWO ||
+           p_inq->next_state==BTM_NO_INTERLEAVING)
+#endif
+        )
+
+    {
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+        p_inq->inq_active = (p_inqparms->mode & BTM_BLE_INQUIRY_MASK);
+        BTM_TRACE_API("BTM:Starting LE Scan with duration %d and activeMode:0x%02x",
+                       p_inqparms->duration, (p_inqparms->mode & BTM_BLE_INQUIRY_MASK));
+#endif
+        if (!controller_get_interface()->supports_ble())
+        {
+            p_inq->inqparms.mode &= ~ BTM_BLE_INQUIRY_MASK;
+            status = BTM_ILLEGAL_VALUE;
+        }
+        /* BLE for now does not support filter condition for inquiry */
+        else if ((status = btm_ble_start_inquiry((uint8_t)(p_inqparms->mode & BTM_BLE_INQUIRY_MASK),
+                                            p_inqparms->duration)) != BTM_CMD_STARTED)
+        {
+            BTM_TRACE_ERROR("Err Starting LE Inquiry.");
+            p_inq->inqparms.mode &= ~ BTM_BLE_INQUIRY_MASK;
+        }
+#if (BTA_HOST_INTERLEAVE_SEARCH == FALSE)
+        p_inqparms->mode &= ~BTM_BLE_INQUIRY_MASK;
+#endif
+
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+        if(p_inq->next_state==BTM_NO_INTERLEAVING)
+        {
+            p_inq->next_state=BTM_FINISH;
+        }
+        else
+        {
+            BTM_TRACE_API("BTM:Interleaving: started LE scan, Advancing to next state: %d",
+                           p_inq->next_state+1);
+            p_inq->next_state+=1;
+        }
+        /* reset next_state if status <> BTM_Started */
+        if(status!=BTM_CMD_STARTED)
+            p_inq->next_state=BTM_BR_ONE;
+
+        /* if interleave scan..return here */
+        return status;
+#endif
+
+
+        BTM_TRACE_DEBUG("BTM_StartInquiry: mode = %02x", p_inqparms->mode);
+    }
+#endif /* end of BLE_INCLUDED */
+
+    /* we're done with this routine if BR/EDR inquiry is not desired. */
+    if ((p_inqparms->mode & BTM_BR_INQUIRY_MASK) == BTM_INQUIRY_NONE)
+        return status;
+
+    /* BR/EDR inquiry portion */
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+    if((p_inq->next_state==BTM_BR_ONE || p_inq->next_state==BTM_BR_TWO ||
+        p_inq->next_state==BTM_NO_INTERLEAVING ))
+    {
+        p_inq->inq_active = (p_inqparms->mode & BTM_BR_INQUIRY_MASK);
+#endif
+    /* If a filter is specified, then save it for later and clear the current filter.
+       The setting of the filter is done upon completion of clearing of the previous
+       filter.
+    */
+    switch (p_inqparms->filter_cond_type)
+    {
+    case BTM_CLR_INQUIRY_FILTER:
+        p_inq->state = BTM_INQ_SET_FILT_STATE;
+        break;
+
+    case BTM_FILTER_COND_DEVICE_CLASS:
+    case BTM_FILTER_COND_BD_ADDR:
+        /* The filter is not being used so simply clear it;
+            the inquiry can start after this operation */
+        p_inq->state = BTM_INQ_CLR_FILT_STATE;
+        p_inqparms->filter_cond_type = BTM_CLR_INQUIRY_FILTER;
+        /* =============>>>> adding LE filtering here ????? */
+        break;
+
+    default:
+        return (BTM_ILLEGAL_VALUE);
+    }
+
+    /* Before beginning the inquiry the current filter must be cleared, so initiate the command */
+    if ((status = btm_set_inq_event_filter (p_inqparms->filter_cond_type,
+                                            &p_inqparms->filter_cond)) != BTM_CMD_STARTED)
+        p_inq->state = BTM_INQ_INACTIVE_STATE;
+
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+        if (p_inq->next_state==BTM_NO_INTERLEAVING)
+            p_inq->next_state=BTM_FINISH;
+        else
+        {
+            BTM_TRACE_API("BTM:Interleaving: Started BTM inq, Advancing to next state: %d",
+                           p_inq->next_state+1);
+            p_inq->next_state+=1;
+        }
+     }
+     if (status!=BTM_CMD_STARTED)
+     {
+         /* Some error beginning the scan process.
+            Reset the next_state parameter.. Do we need to reset the inq_active also?
+         */
+        BTM_TRACE_API("BTM:Interleaving: Error in Starting inquiry, status: 0x%02x", status);
+        p_inq->next_state=BTM_BR_ONE;
+     }
+#endif
+
+
+    return (status);
+}
+
+
+/*******************************************************************************
+**
+** 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  BTM_ReadRemoteDeviceName (BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb
+                                                ,tBT_TRANSPORT transport)
+{
+    tBTM_INQ_INFO   *p_cur = NULL;
+    tINQ_DB_ENT     *p_i;
+
+    BTM_TRACE_API ("BTM_ReadRemoteDeviceName: bd addr [%02x%02x%02x%02x%02x%02x]",
+               remote_bda[0], remote_bda[1], remote_bda[2],
+               remote_bda[3], remote_bda[4], remote_bda[5]);
+
+    /* Use the remote device's clock offset if it is in the local inquiry database */
+    if ((p_i = btm_inq_db_find (remote_bda)) != NULL)
+    {
+        p_cur = &p_i->inq_info;
+        if ((p_cur->results.ble_evt_type == BTM_BLE_EVT_NON_CONN_ADV) &&
+            (p_cur->results.device_type != BT_DEVICE_TYPE_BREDR))
+        {/* Non-connectable LE device: do not request its name! */
+          return BTM_ERR_PROCESSING;
+        }
+    }
+    BTM_TRACE_API ("no device found in inquiry db");
+
+#if (BLE_INCLUDED == TRUE)
+    if (transport == BT_TRANSPORT_LE)
+    {
+        return btm_ble_read_remote_name(remote_bda, p_cur, p_cb);
+    }
+    else
+#endif
+
+    return (btm_initiate_rem_name (remote_bda, p_cur, BTM_RMT_NAME_EXT,
+                                   BTM_EXT_RMT_NAME_TIMEOUT_MS, p_cb));
+}
+
+/*******************************************************************************
+**
+** 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  BTM_CancelRemoteDeviceName (void)
+{
+    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+    BTM_TRACE_API ("BTM_CancelRemoteDeviceName()");
+
+    /* Make sure there is not already one in progress */
+    if (p_inq->remname_active)
+    {
+#if (BLE_INCLUDED == TRUE)
+        if (BTM_UseLeLink(p_inq->remname_bda))
+        {
+            if (btm_ble_cancel_remote_name(p_inq->remname_bda))
+                return (BTM_CMD_STARTED);
+            else
+                return (BTM_UNKNOWN_ADDR);
+        }
+        else
+#endif
+        btsnd_hcic_rmt_name_req_cancel(p_inq->remname_bda);
+        return (BTM_CMD_STARTED);
+    }
+    else
+        return (BTM_WRONG_MODE);
+}
+
+/*******************************************************************************
+**
+** 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 BD_ADDR p_bda)
+{
+    BTM_TRACE_API ("BTM_InqDbRead: bd addr [%02x%02x%02x%02x%02x%02x]",
+               p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]);
+
+    tINQ_DB_ENT *p_ent = btm_inq_db_find(p_bda);
+    if (!p_ent)
+      return NULL;
+
+    return &p_ent->inq_info;
+}
+
+
+/*******************************************************************************
+**
+** 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)
+{
+    uint16_t     xx;
+    tINQ_DB_ENT  *p_ent = btm_cb.btm_inq_vars.inq_db;
+
+    for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++)
+    {
+        if (p_ent->in_use)
+            return (&p_ent->inq_info);
+    }
+
+    /* If here, no used entry found */
+    return ((tBTM_INQ_INFO *)NULL);
+}
+
+
+/*******************************************************************************
+**
+** 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)
+{
+    tINQ_DB_ENT  *p_ent;
+    uint16_t      inx;
+
+    if (p_cur)
+    {
+        p_ent = (tINQ_DB_ENT *) ((uint8_t *)p_cur - offsetof (tINQ_DB_ENT, inq_info));
+        inx = (uint16_t)((p_ent - btm_cb.btm_inq_vars.inq_db) + 1);
+
+        for (p_ent = &btm_cb.btm_inq_vars.inq_db[inx]; inx < BTM_INQ_DB_SIZE; inx++, p_ent++)
+        {
+            if (p_ent->in_use)
+                return (&p_ent->inq_info);
+        }
+
+        /* If here, more entries found */
+        return ((tBTM_INQ_INFO *)NULL);
+    }
+    else
+        return (BTM_InqDbFirst());
+}
+
+
+/*******************************************************************************
+**
+** 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 (BD_ADDR p_bda)
+{
+    tBTM_INQUIRY_VAR_ST     *p_inq = &btm_cb.btm_inq_vars;
+
+    /* If an inquiry or remote name is in progress return busy */
+    if (p_inq->inq_active != BTM_INQUIRY_INACTIVE ||
+        p_inq->inqfilt_active)
+        return (BTM_BUSY);
+
+    btm_clr_inq_db(p_bda);
+
+    return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    if (btm_cb.devcb.p_inq_tx_power_cmpl_cb)
+        return (BTM_BUSY);
+
+    btm_cb.devcb.p_inq_tx_power_cmpl_cb = p_cb;
+    alarm_set_on_queue(btm_cb.devcb.read_inq_tx_power_timer,
+                       BTM_INQ_REPLY_TIMEOUT_MS,
+                       btm_read_inq_tx_power_timeout, NULL,
+                       btu_general_alarm_queue);
+
+    btsnd_hcic_read_inq_tx_power();
+    return (BTM_CMD_STARTED);
+}
+
+/*********************************************************************************
+**********************************************************************************
+**                                                                              **
+**                      BTM Internal Inquiry Functions                          **
+**                                                                              **
+**********************************************************************************
+*********************************************************************************/
+/*******************************************************************************
+**
+** Function         btm_inq_db_reset
+**
+** Description      This function is called at at reset to clear the inquiry
+**                  database & pending callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_inq_db_reset (void)
+{
+    tBTM_REMOTE_DEV_NAME     rem_name;
+    tBTM_INQUIRY_VAR_ST     *p_inq = &btm_cb.btm_inq_vars;
+    uint8_t                  num_responses;
+    uint8_t                  temp_inq_active;
+    tBTM_STATUS              status;
+
+    /* If an inquiry or periodic inquiry is active, reset the mode to inactive */
+    if (p_inq->inq_active != BTM_INQUIRY_INACTIVE)
+    {
+        temp_inq_active = p_inq->inq_active;    /* Save so state can change BEFORE
+                                                       callback is called */
+        p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+
+        /* If not a periodic inquiry, the complete callback must be called to notify caller */
+        if (temp_inq_active == BTM_LIMITED_INQUIRY_ACTIVE ||
+            temp_inq_active == BTM_GENERAL_INQUIRY_ACTIVE)
+        {
+            if (p_inq->p_inq_cmpl_cb)
+            {
+                num_responses = 0;
+                (*p_inq->p_inq_cmpl_cb)(&num_responses);
+            }
+        }
+    }
+
+    /* Cancel a remote name request if active, and notify the caller (if waiting) */
+    if (p_inq->remname_active )
+    {
+        alarm_cancel(p_inq->remote_name_timer);
+        p_inq->remname_active = false;
+        memset(p_inq->remname_bda, 0, BD_ADDR_LEN);
+
+        if (p_inq->p_remname_cmpl_cb)
+        {
+            rem_name.status = BTM_DEV_RESET;
+
+            (*p_inq->p_remname_cmpl_cb)(&rem_name);
+            p_inq->p_remname_cmpl_cb = NULL;
+        }
+    }
+
+    /* Cancel an inquiry filter request if active, and notify the caller (if waiting) */
+    if (p_inq->inqfilt_active)
+    {
+        p_inq->inqfilt_active = false;
+
+        if (p_inq->p_inqfilter_cmpl_cb)
+        {
+            status = BTM_DEV_RESET;
+            (*p_inq->p_inqfilter_cmpl_cb)(&status);
+        }
+    }
+
+    p_inq->state = BTM_INQ_INACTIVE_STATE;
+    p_inq->pending_filt_complete_event = 0;
+    p_inq->p_inq_results_cb = NULL;
+    btm_clr_inq_db(NULL);   /* Clear out all the entries in the database */
+    btm_clr_inq_result_flt();
+
+    p_inq->discoverable_mode = BTM_NON_DISCOVERABLE;
+    p_inq->connectable_mode  = BTM_NON_CONNECTABLE;
+    p_inq->page_scan_type    = BTM_SCAN_TYPE_STANDARD;
+    p_inq->inq_scan_type     = BTM_SCAN_TYPE_STANDARD;
+
+#if (BLE_INCLUDED == TRUE)
+    p_inq->discoverable_mode |= BTM_BLE_NON_DISCOVERABLE;
+    p_inq->connectable_mode  |= BTM_BLE_NON_CONNECTABLE;
+#endif
+    return;
+}
+
+
+/*********************************************************************************
+**
+** Function         btm_inq_db_init
+**
+** Description      This function is called at startup to initialize the inquiry
+**                  database.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_inq_db_init (void)
+{
+    alarm_free(btm_cb.btm_inq_vars.remote_name_timer);
+    btm_cb.btm_inq_vars.remote_name_timer =
+        alarm_new("btm_inq.remote_name_timer");
+    btm_cb.btm_inq_vars.no_inc_ssp = BTM_NO_SSP_ON_INQUIRY;
+}
+
+/*********************************************************************************
+**
+** Function         btm_inq_stop_on_ssp
+**
+** Description      This function is called on incoming SSP
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_inq_stop_on_ssp(void)
+{
+    uint8_t normal_active = (BTM_GENERAL_INQUIRY_ACTIVE|BTM_LIMITED_INQUIRY_ACTIVE);
+
+#if (BTM_INQ_DEBUG == TRUE)
+    BTM_TRACE_DEBUG ("btm_inq_stop_on_ssp: no_inc_ssp=%d inq_active:0x%x state:%d inqfilt_active:%d",
+        btm_cb.btm_inq_vars.no_inc_ssp, btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+    if (btm_cb.btm_inq_vars.no_inc_ssp)
+    {
+        if (btm_cb.btm_inq_vars.state == BTM_INQ_ACTIVE_STATE)
+        {
+            if (btm_cb.btm_inq_vars.inq_active & BTM_PERIODIC_INQUIRY_ACTIVE)
+            {
+                BTM_CancelPeriodicInquiry();
+            }
+            else if (btm_cb.btm_inq_vars.inq_active & normal_active)
+            {
+                /* can not call BTM_CancelInquiry() here. We need to report inquiry complete evt */
+                btsnd_hcic_inq_cancel();
+            }
+        }
+        /* do not allow inquiry to start */
+        btm_cb.btm_inq_vars.inq_active |= BTM_SSP_INQUIRY_ACTIVE;
+    }
+}
+
+/*********************************************************************************
+**
+** Function         btm_inq_clear_ssp
+**
+** Description      This function is called when pairing_state becomes idle
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_inq_clear_ssp(void)
+{
+    btm_cb.btm_inq_vars.inq_active &= ~BTM_SSP_INQUIRY_ACTIVE;
+}
+
+/*********************************************************************************
+**
+** Function         btm_clr_inq_db
+**
+** 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          void
+**
+*******************************************************************************/
+void btm_clr_inq_db (BD_ADDR p_bda)
+{
+    tBTM_INQUIRY_VAR_ST     *p_inq = &btm_cb.btm_inq_vars;
+    tINQ_DB_ENT             *p_ent = p_inq->inq_db;
+    uint16_t                 xx;
+
+#if (BTM_INQ_DEBUG == TRUE)
+    BTM_TRACE_DEBUG ("btm_clr_inq_db: inq_active:0x%x state:%d",
+        btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state);
+#endif
+    for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++)
+    {
+        if (p_ent->in_use)
+        {
+            /* If this is the specified BD_ADDR or clearing all devices */
+            if (p_bda == NULL ||
+                (!memcmp (p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN)))
+            {
+                p_ent->in_use = false;
+            }
+        }
+    }
+#if (BTM_INQ_DEBUG == TRUE)
+    BTM_TRACE_DEBUG ("inq_active:0x%x state:%d",
+        btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function         btm_clr_inq_result_flt
+**
+** Description      This function looks through the bdaddr database for a match
+**                  based on Bluetooth Device Address
+**
+** Returns          true if found, else false (new entry)
+**
+*******************************************************************************/
+static void btm_clr_inq_result_flt (void)
+{
+    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+    osi_free_and_reset((void **)&p_inq->p_bd_db);
+    p_inq->num_bd_entries = 0;
+    p_inq->max_bd_entries = 0;
+}
+
+/*******************************************************************************
+**
+** Function         btm_inq_find_bdaddr
+**
+** Description      This function looks through the bdaddr database for a match
+**                  based on Bluetooth Device Address
+**
+** Returns          true if found, else false (new entry)
+**
+*******************************************************************************/
+bool    btm_inq_find_bdaddr (BD_ADDR p_bda)
+{
+    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+    tINQ_BDADDR         *p_db = &p_inq->p_bd_db[0];
+    uint16_t     xx;
+
+    /* Don't bother searching, database doesn't exist or periodic mode */
+    if ((p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) || !p_db)
+        return (false);
+
+    for (xx = 0; xx < p_inq->num_bd_entries; xx++, p_db++)
+    {
+        if (!memcmp(p_db->bd_addr, p_bda, BD_ADDR_LEN)
+            && p_db->inq_count == p_inq->inq_counter)
+            return (true);
+    }
+
+    if (xx < p_inq->max_bd_entries)
+    {
+        p_db->inq_count = p_inq->inq_counter;
+        memcpy(p_db->bd_addr, p_bda, BD_ADDR_LEN);
+        p_inq->num_bd_entries++;
+    }
+
+    /* If here, New Entry */
+    return (false);
+}
+
+/*******************************************************************************
+**
+** Function         btm_inq_db_find
+**
+** Description      This function looks through the inquiry database for a match
+**                  based on Bluetooth Device Address
+**
+** Returns          pointer to entry, or NULL if not found
+**
+*******************************************************************************/
+tINQ_DB_ENT *btm_inq_db_find (const BD_ADDR p_bda)
+{
+    uint16_t     xx;
+    tINQ_DB_ENT  *p_ent = btm_cb.btm_inq_vars.inq_db;
+
+    for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++)
+    {
+        if ((p_ent->in_use) && (!memcmp (p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN)))
+            return (p_ent);
+    }
+
+    /* If here, not found */
+    return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         btm_inq_db_new
+**
+** Description      This function looks through the inquiry database for an unused
+**                  entry. If no entry is free, it allocates the oldest entry.
+**
+** Returns          pointer to entry
+**
+*******************************************************************************/
+tINQ_DB_ENT *btm_inq_db_new (BD_ADDR p_bda)
+{
+    uint16_t     xx;
+    tINQ_DB_ENT  *p_ent = btm_cb.btm_inq_vars.inq_db;
+    tINQ_DB_ENT  *p_old = btm_cb.btm_inq_vars.inq_db;
+    uint32_t     ot = 0xFFFFFFFF;
+
+    for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++)
+    {
+        if (!p_ent->in_use)
+        {
+            memset (p_ent, 0, sizeof (tINQ_DB_ENT));
+            memcpy (p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN);
+            p_ent->in_use = true;
+
+            return (p_ent);
+        }
+
+        if (p_ent->time_of_resp < ot)
+        {
+            p_old = p_ent;
+            ot    = p_ent->time_of_resp;
+        }
+    }
+
+    /* If here, no free entry found. Return the oldest. */
+
+    memset (p_old, 0, sizeof (tINQ_DB_ENT));
+    memcpy (p_old->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN);
+    p_old->in_use = true;
+
+    return (p_old);
+}
+
+
+/*******************************************************************************
+**
+** Function         btm_set_inq_event_filter
+**
+** Description      This function is called to set the inquiry event filter.
+**                  It is called by either internally, or by the external API function
+**                  (BTM_SetInqEventFilter).  It is used internally as part of the
+**                  inquiry processing.
+**
+** Input Params:
+**                  filter_cond_type - this is the type of inquiry filter to apply:
+**                          BTM_FILTER_COND_DEVICE_CLASS,
+**                          BTM_FILTER_COND_BD_ADDR, or
+**                          BTM_CLR_INQUIRY_FILTER
+**
+**                  p_filt_cond - this is either a BD_ADDR or DEV_CLASS depending on the
+**                          filter_cond_type  (See section 4.7.3 of Core Spec 1.0b).
+**
+** Returns          BTM_CMD_STARTED if successfully initiated
+**                  BTM_NO_RESOURCES if couldn't get a memory pool buffer
+**                  BTM_ILLEGAL_VALUE if a bad parameter was detected
+**
+*******************************************************************************/
+static tBTM_STATUS btm_set_inq_event_filter (uint8_t filter_cond_type,
+                                             tBTM_INQ_FILT_COND *p_filt_cond)
+{
+    uint8_t  condition_length = DEV_CLASS_LEN * 2;
+    uint8_t  condition_buf[DEV_CLASS_LEN * 2];
+    uint8_t *p_cond = condition_buf;                    /* points to the condition to pass to HCI */
+
+#if (BTM_INQ_DEBUG == TRUE)
+    BTM_TRACE_DEBUG ("btm_set_inq_event_filter: filter type %d [Clear-0, COD-1, BDADDR-2]",
+        filter_cond_type);
+    BTM_TRACE_DEBUG ("                       condition [%02x%02x%02x %02x%02x%02x]",
+               p_filt_cond->bdaddr_cond[0], p_filt_cond->bdaddr_cond[1], p_filt_cond->bdaddr_cond[2],
+               p_filt_cond->bdaddr_cond[3], p_filt_cond->bdaddr_cond[4], p_filt_cond->bdaddr_cond[5]);
+#endif
+
+    /* Load the correct filter condition to pass to the lower layer */
+    switch (filter_cond_type)
+    {
+    case BTM_FILTER_COND_DEVICE_CLASS:
+        /* copy the device class and device class fields into contiguous memory to send to HCI */
+        memcpy (condition_buf, p_filt_cond->cod_cond.dev_class, DEV_CLASS_LEN);
+        memcpy (&condition_buf[DEV_CLASS_LEN],
+                p_filt_cond->cod_cond.dev_class_mask, DEV_CLASS_LEN);
+
+        /* condition length should already be set as the default */
+        break;
+
+    case BTM_FILTER_COND_BD_ADDR:
+        p_cond = p_filt_cond->bdaddr_cond;
+
+        /* condition length should already be set as the default */
+        break;
+
+    case BTM_CLR_INQUIRY_FILTER:
+        condition_length = 0;
+        break;
+
+    default:
+        return (BTM_ILLEGAL_VALUE);     /* Bad parameter was passed in */
+    }
+
+    btm_cb.btm_inq_vars.inqfilt_active = true;
+
+    /* Filter the inquiry results for the specified condition type and value */
+    btsnd_hcic_set_event_filter(HCI_FILTER_INQUIRY_RESULT, filter_cond_type,
+                                p_cond, condition_length);
+    return (BTM_CMD_STARTED);
+}
+
+
+/*******************************************************************************
+**
+** Function         btm_event_filter_complete
+**
+** Description      This function is called when a set event filter has completed.
+**                  Note: This routine currently only handles inquiry filters.
+**                      Connection filters are ignored for now.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_event_filter_complete (uint8_t *p)
+{
+    uint8_t          hci_status;
+    tBTM_STATUS      status;
+    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+    tBTM_CMPL_CB   *p_cb = p_inq->p_inqfilter_cmpl_cb;
+
+#if (BTM_INQ_DEBUG == TRUE)
+    BTM_TRACE_DEBUG ("btm_event_filter_complete: inq_active:0x%x state:%d inqfilt_active:%d",
+        btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+    /* If the filter complete event is from an old or cancelled request, ignore it */
+    if(p_inq->pending_filt_complete_event)
+    {
+        p_inq->pending_filt_complete_event--;
+        return;
+    }
+
+    /* Only process the inquiry filter; Ignore the connection filter until it
+       is used by the upper layers */
+    if (p_inq->inqfilt_active == true )
+    {
+        /* Extract the returned status from the buffer */
+        STREAM_TO_UINT8 (hci_status, p);
+        if (hci_status != HCI_SUCCESS)
+        {
+            /* If standalone operation, return the error status; if embedded in the inquiry, continue the inquiry */
+            BTM_TRACE_WARNING ("BTM Warning: Set Event Filter Failed (HCI returned 0x%x)", hci_status);
+            status = BTM_ERR_PROCESSING;
+        }
+        else
+            status = BTM_SUCCESS;
+
+        /* If the set filter was initiated externally (via BTM_SetInqEventFilter), call the
+           callback function to notify the initiator that it has completed */
+        if (p_inq->state == BTM_INQ_INACTIVE_STATE)
+        {
+            p_inq->inqfilt_active = false;
+            if (p_cb)
+                (*p_cb) (&status);
+        }
+        else    /* An inquiry is active (the set filter command was internally generated),
+                   process the next state of the process (Set a new filter or start the inquiry). */
+        {
+            if(status != BTM_SUCCESS)
+            {
+                /* Process the inquiry complete (Error Status) */
+                btm_process_inq_complete (BTM_ERR_PROCESSING, (uint8_t)(p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK));
+
+                /* btm_process_inq_complete() does not restore the following settings on periodic inquiry */
+                p_inq->inqfilt_active = false;
+                p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+                p_inq->state = BTM_INQ_INACTIVE_STATE;
+
+                return;
+            }
+
+            /* Check to see if a new filter needs to be set up */
+            if (p_inq->state == BTM_INQ_CLR_FILT_STATE)
+            {
+                if ((status = btm_set_inq_event_filter (p_inq->inqparms.filter_cond_type, &p_inq->inqparms.filter_cond)) == BTM_CMD_STARTED)
+                {
+                    p_inq->state = BTM_INQ_SET_FILT_STATE;
+                }
+                else    /* Error setting the filter: Call the initiator's callback function to indicate a failure */
+                {
+                    p_inq->inqfilt_active = false;
+
+                    /* Process the inquiry complete (Error Status) */
+                    btm_process_inq_complete (BTM_ERR_PROCESSING, (uint8_t)(p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK));
+                }
+            }
+            else    /* Initiate the Inquiry or Periodic Inquiry */
+            {
+                p_inq->state = BTM_INQ_ACTIVE_STATE;
+                p_inq->inqfilt_active = false;
+                btm_initiate_inquiry (p_inq);
+            }
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         btm_initiate_inquiry
+**
+** Description      This function is called to start an inquiry or periodic inquiry
+**                  upon completion of the setting and/or clearing of the inquiry filter.
+**
+** Inputs:          p_inq (btm_cb.btm_inq_vars) - pointer to saved 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)
+**
+** Returns          If an error occurs the initiator's callback is called with the error status.
+**
+*******************************************************************************/
+static void btm_initiate_inquiry (tBTM_INQUIRY_VAR_ST *p_inq)
+{
+    const LAP       *lap;
+    tBTM_INQ_PARMS  *p_inqparms = &p_inq->inqparms;
+
+#if (BTM_INQ_DEBUG == TRUE)
+    BTM_TRACE_DEBUG ("btm_initiate_inquiry: inq_active:0x%x state:%d inqfilt_active:%d",
+        btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+    btm_acl_update_busy_level (BTM_BLI_INQ_EVT);
+
+    if (p_inq->inq_active & BTM_SSP_INQUIRY_ACTIVE)
+    {
+        btm_process_inq_complete (BTM_NO_RESOURCES, (uint8_t)(p_inqparms->mode & BTM_BR_INQUIRY_MASK));
+        return;
+    }
+
+    /* Make sure the number of responses doesn't overflow the database configuration */
+    p_inqparms->max_resps = (uint8_t)((p_inqparms->max_resps <= BTM_INQ_DB_SIZE) ? p_inqparms->max_resps : BTM_INQ_DB_SIZE);
+
+    lap = (p_inq->inq_active & BTM_LIMITED_INQUIRY_ACTIVE) ? &limited_inq_lap : &general_inq_lap;
+
+    if (p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE)
+    {
+        btsnd_hcic_per_inq_mode (p_inq->per_max_delay,
+                                 p_inq->per_min_delay,
+                                 *lap, p_inqparms->duration,
+                                 p_inqparms->max_resps);
+    }
+    else
+    {
+        btm_clr_inq_result_flt();
+
+        /* Allocate memory to hold bd_addrs responding */
+        p_inq->p_bd_db = (tINQ_BDADDR *)osi_calloc(BT_DEFAULT_BUFFER_SIZE);
+        p_inq->max_bd_entries = (uint16_t)(BT_DEFAULT_BUFFER_SIZE / sizeof(tINQ_BDADDR));
+
+        btsnd_hcic_inquiry(*lap, p_inqparms->duration, 0);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_process_inq_results
+**
+** Description      This function is called when inquiry results are received from
+**                  the device. It updates the inquiry database. If the inquiry
+**                  database is full, the oldest entry is discarded.
+**
+** Parameters       inq_res_mode - BTM_INQ_RESULT_STANDARD
+**                                 BTM_INQ_RESULT_WITH_RSSI
+**                                 BTM_INQ_RESULT_EXTENDED
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_process_inq_results (uint8_t *p, uint8_t inq_res_mode)
+{
+    uint8_t          num_resp, xx;
+    BD_ADDR          bda;
+    tINQ_DB_ENT     *p_i;
+    tBTM_INQ_RESULTS *p_cur=NULL;
+    bool             is_new = true;
+    bool             update = false;
+    int8_t           i_rssi;
+    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+    tBTM_INQ_RESULTS_CB *p_inq_results_cb = p_inq->p_inq_results_cb;
+    uint8_t          page_scan_rep_mode = 0;
+    uint8_t          page_scan_per_mode = 0;
+    uint8_t          page_scan_mode = 0;
+    uint8_t          rssi = 0;
+    DEV_CLASS        dc;
+    uint16_t         clock_offset;
+    uint8_t          *p_eir_data = NULL;
+
+#if (BTM_INQ_DEBUG == TRUE)
+    BTM_TRACE_DEBUG ("btm_process_inq_results inq_active:0x%x state:%d inqfilt_active:%d",
+        btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+    /* Only process the results if the BR inquiry is still active */
+    if (!(p_inq->inq_active & BTM_BR_INQ_ACTIVE_MASK))
+        return;
+
+    STREAM_TO_UINT8 (num_resp, p);
+
+    if (inq_res_mode == BTM_INQ_RESULT_EXTENDED && (num_resp > 1)) {
+        BTM_TRACE_ERROR ("btm_process_inq_results() extended results (%d) > 1",
+                         num_resp);
+        return;
+    }
+
+    for (xx = 0; xx < num_resp; xx++)
+    {
+        update = false;
+        /* Extract inquiry results */
+        STREAM_TO_BDADDR   (bda, p);
+        STREAM_TO_UINT8    (page_scan_rep_mode, p);
+        STREAM_TO_UINT8    (page_scan_per_mode, p);
+
+        if (inq_res_mode == BTM_INQ_RESULT_STANDARD)
+        {
+            STREAM_TO_UINT8(page_scan_mode, p);
+        }
+
+        STREAM_TO_DEVCLASS (dc, p);
+        STREAM_TO_UINT16   (clock_offset, p);
+        if (inq_res_mode != BTM_INQ_RESULT_STANDARD)
+        {
+            STREAM_TO_UINT8(rssi, p);
+        }
+
+        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
+           responses could be processed which can confuse some apps
+        */
+        if (p_inq->inqparms.max_resps &&
+            p_inq->inq_cmpl_info.num_resp >= p_inq->inqparms.max_resps
+#if (BLE_INCLUDED == TRUE)
+            /* new device response */
+            && ( p_i == NULL ||
+                /* exisiting device with BR/EDR info */
+                (p_i && (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) != 0)
+               )
+#endif
+
+            )
+        {
+/*            BTM_TRACE_WARNING("INQ RES: Extra Response Received...ignoring"); */
+            return;
+        }
+
+        /* 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]);*/
+             /* By default suppose no update needed */
+            i_rssi = (int8_t)rssi;
+
+            /* If this new RSSI is higher than the last one */
+            if(p_inq->inqparms.report_dup && (rssi != 0) &&
+               p_i && (i_rssi > p_i->inq_info.results.rssi || p_i->inq_info.results.rssi == 0
+#if (BLE_INCLUDED == TRUE)
+               /* BR/EDR inquiry information update */
+                       || (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) != 0
+#endif
+                       ))
+            {
+                p_cur = &p_i->inq_info.results;
+                BTM_TRACE_DEBUG("update RSSI new:%d, old:%d", i_rssi, p_cur->rssi);
+                p_cur->rssi = i_rssi;
+                update = true;
+            }
+            /* If we received a second Extended Inq Event for an already */
+            /* discovered device, this is because for the first one EIR was not received */
+            else if ((inq_res_mode == BTM_INQ_RESULT_EXTENDED) && (p_i))
+            {
+                p_cur = &p_i->inq_info.results;
+                update = true;
+            }
+            /* If no update needed continue with next response (if any) */
+            else
+                continue;
+        }
+
+        /* If existing entry, use that, else get a new one (possibly reusing the oldest) */
+        if (p_i == NULL)
+        {
+            p_i = btm_inq_db_new (bda);
+            is_new = true;
+        }
+
+        /* If an entry for the device already exists, overwrite it ONLY if it is from
+           a previous inquiry. (Ignore it if it is a duplicate response from the same
+           inquiry.
+        */
+        else if (p_i->inq_count == p_inq->inq_counter
+#if (BLE_INCLUDED == TRUE)
+            && (p_i->inq_info.results.device_type == BT_DEVICE_TYPE_BREDR)
+#endif
+            )
+            is_new = false;
+
+        /* keep updating RSSI to have latest value */
+        if( inq_res_mode != BTM_INQ_RESULT_STANDARD )
+            p_i->inq_info.results.rssi = (int8_t)rssi;
+        else
+            p_i->inq_info.results.rssi = BTM_INQ_RES_IGNORE_RSSI;
+
+        if (is_new == true)
+        {
+            /* Save the info */
+            p_cur = &p_i->inq_info.results;
+            p_cur->page_scan_rep_mode = page_scan_rep_mode;
+            p_cur->page_scan_per_mode = page_scan_per_mode;
+            p_cur->page_scan_mode     = page_scan_mode;
+            p_cur->dev_class[0]       = dc[0];
+            p_cur->dev_class[1]       = dc[1];
+            p_cur->dev_class[2]       = dc[2];
+            p_cur->clock_offset       = clock_offset  | BTM_CLOCK_OFFSET_VALID;
+
+            p_i->time_of_resp = time_get_os_boottime_ms();
+
+            if (p_i->inq_count != p_inq->inq_counter)
+                p_inq->inq_cmpl_info.num_resp++;       /* A new response was found */
+
+#if (BLE_INCLUDED == TRUE)
+            p_cur->inq_result_type    = BTM_INQ_RESULT_BR;
+            if (p_i->inq_count != p_inq->inq_counter)
+            {
+                p_cur->device_type  = BT_DEVICE_TYPE_BREDR;
+                p_i->scan_rsp       = false;
+            }
+            else
+                p_cur->device_type    |= BT_DEVICE_TYPE_BREDR;
+#endif
+                p_i->inq_count = p_inq->inq_counter;   /* Mark entry for current inquiry */
+
+            /* If the number of responses found and not unlimited, issue a cancel inquiry */
+            if (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) &&
+                p_inq->inqparms.max_resps &&
+                p_inq->inq_cmpl_info.num_resp == p_inq->inqparms.max_resps
+#if (BLE_INCLUDED == TRUE)
+                /* BLE scanning is active and received adv */
+                && ((((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0) &&
+                     p_cur->device_type == BT_DEVICE_TYPE_DUMO && p_i->scan_rsp) ||
+                    (p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) == 0)
+#endif
+                )
+            {
+/*                BTM_TRACE_DEBUG("BTMINQ: Found devices, cancelling inquiry..."); */
+                btsnd_hcic_inq_cancel();
+
+#if (BLE_INCLUDED == TRUE)
+                if ((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0)
+                    btm_ble_stop_inquiry();
+#endif
+                btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT);
+            }
+            /* Initialize flag to false. This flag is set/used by application */
+            p_i->inq_info.appl_knows_rem_name = false;
+        }
+
+        if (is_new || update)
+        {
+            if( inq_res_mode == BTM_INQ_RESULT_EXTENDED )
+            {
+                memset( p_cur->eir_uuid, 0,
+                        BTM_EIR_SERVICE_ARRAY_SIZE * (BTM_EIR_ARRAY_BITS/8));
+                /* set bit map of UUID list from received EIR */
+                btm_set_eir_uuid( p, p_cur );
+                p_eir_data = p;
+            }
+            else
+                p_eir_data = NULL;
+
+            /* If a callback is registered, call it with the results */
+            if (p_inq_results_cb)
+                (p_inq_results_cb)((tBTM_INQ_RESULTS *) p_cur, p_eir_data);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_sort_inq_result
+**
+** Description      This function is called when inquiry complete is received
+**                  from the device to sort inquiry results based on rssi.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sort_inq_result(void)
+{
+    uint8_t xx, yy, num_resp;
+    tINQ_DB_ENT *p_ent  = btm_cb.btm_inq_vars.inq_db;
+    tINQ_DB_ENT *p_next = btm_cb.btm_inq_vars.inq_db+1;
+    int size;
+    tINQ_DB_ENT *p_tmp = (tINQ_DB_ENT *)osi_malloc(sizeof(tINQ_DB_ENT));
+
+    num_resp = (btm_cb.btm_inq_vars.inq_cmpl_info.num_resp<BTM_INQ_DB_SIZE)?
+                btm_cb.btm_inq_vars.inq_cmpl_info.num_resp: BTM_INQ_DB_SIZE;
+
+    size = sizeof(tINQ_DB_ENT);
+    for (xx = 0; xx < num_resp-1; xx++, p_ent++) {
+        for (yy = xx+1, p_next = p_ent+1; yy < num_resp; yy++, p_next++) {
+            if (p_ent->inq_info.results.rssi < p_next->inq_info.results.rssi) {
+                memcpy(p_tmp, p_next, size);
+                memcpy(p_next, p_ent,  size);
+                memcpy(p_ent, p_tmp,  size);
+            }
+        }
+    }
+
+    osi_free(p_tmp);
+}
+
+/*******************************************************************************
+**
+** Function         btm_process_inq_complete
+**
+** Description      This function is called when inquiry complete is received
+**                  from the device.  Call the callback if not in periodic inquiry
+**                  mode AND it is not NULL (The caller wants the event).
+**
+**                  The callback pass back the status and the number of responses
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_process_inq_complete (uint8_t status, uint8_t mode)
+{
+    tBTM_CMPL_CB        *p_inq_cb = btm_cb.btm_inq_vars.p_inq_cmpl_cb;
+    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+    /* inquiry inactive case happens when inquiry is cancelled.
+       Make mode 0 for no further inquiries from the current inquiry process
+    */
+    if(status!=HCI_SUCCESS || p_inq->next_state==BTM_FINISH || !p_inq->inq_active)
+    {
+        /* re-initialize for next inquiry request */
+        p_inq->next_state=BTM_BR_ONE;
+        /* make the mode 0 here */
+        p_inq->inqparms.mode &= ~(p_inq->inqparms.mode);
+
+    }
+#endif
+
+#if (BTA_HOST_INTERLEAVE_SEARCH == FALSE)
+    p_inq->inqparms.mode &= ~(mode);
+#endif
+
+    if(p_inq->scan_type == INQ_LE_OBSERVE && !p_inq->inq_active)
+    {
+        /*end of LE observe*/
+        p_inq->p_inq_ble_results_cb = (tBTM_INQ_RESULTS_CB *) NULL;
+        p_inq->p_inq_ble_cmpl_cb = (tBTM_CMPL_CB *) NULL;
+        p_inq->scan_type=INQ_NONE;
+    }
+
+
+#if (BTM_INQ_DEBUG == TRUE)
+    BTM_TRACE_DEBUG ("btm_process_inq_complete inq_active:0x%x state:%d inqfilt_active:%d",
+        btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+    btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT);
+    /* Ignore any stray or late complete messages if the inquiry is not active */
+    if (p_inq->inq_active)
+    {
+        p_inq->inq_cmpl_info.status = (tBTM_STATUS)((status == HCI_SUCCESS) ? BTM_SUCCESS : BTM_ERR_PROCESSING);
+
+        /* Notify caller that the inquiry has completed; (periodic inquiries do not send completion events */
+        if (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) && p_inq->inqparms.mode == 0)
+        {
+#if (BLE_INCLUDED == TRUE)
+            btm_clear_all_pending_le_entry();
+#endif
+            p_inq->state = BTM_INQ_INACTIVE_STATE;
+
+            /* Increment so the start of a next inquiry has a new count */
+            p_inq->inq_counter++;
+
+            btm_clr_inq_result_flt();
+
+            if((p_inq->inq_cmpl_info.status == BTM_SUCCESS) &&
+                controller_get_interface()->supports_rssi_with_inquiry_results())
+            {
+                btm_sort_inq_result();
+            }
+
+            /* Clear the results callback if set */
+            p_inq->p_inq_results_cb = (tBTM_INQ_RESULTS_CB *) NULL;
+            p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+            p_inq->p_inq_cmpl_cb = (tBTM_CMPL_CB *) NULL;
+
+            /* If we have a callback registered for inquiry complete, call it */
+            BTM_TRACE_DEBUG ("BTM Inq Compl Callback: status 0x%02x, num results %d",
+                        p_inq->inq_cmpl_info.status, p_inq->inq_cmpl_info.num_resp);
+
+            if (p_inq_cb)
+                (p_inq_cb)((tBTM_INQUIRY_CMPL *) &p_inq->inq_cmpl_info);
+        }
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+        if(p_inq->inqparms.mode != 0 && !(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE))
+        {
+            /* make inquiry inactive for next iteration */
+            p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+            /* call the inquiry again */
+            BTM_StartInquiry(&p_inq->inqparms,p_inq->p_inq_results_cb,p_inq->p_inq_cmpl_cb);
+        }
+#endif
+    }
+    if(p_inq->inqparms.mode == 0 && p_inq->scan_type == INQ_GENERAL)//this inquiry is complete
+    {
+        p_inq->scan_type = INQ_NONE;
+#if (BLE_INCLUDED == TRUE)
+        /* check if the LE observe is pending */
+        if(p_inq->p_inq_ble_results_cb != NULL)
+        {
+            BTM_TRACE_DEBUG("BTM Inq Compl: resuming a pending LE scan");
+            BTM_BleObserve(1,0, p_inq->p_inq_ble_results_cb, p_inq->p_inq_ble_cmpl_cb);
+        }
+#endif
+    }
+#if (BTM_INQ_DEBUG == TRUE)
+    BTM_TRACE_DEBUG ("inq_active:0x%x state:%d inqfilt_active:%d",
+        btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btm_process_cancel_complete
+**
+** Description      This function is called when inquiry cancel complete is received
+**                  from the device.This function will also call the btm_process_inq_complete
+**                  This function is needed to differentiate a cancel_cmpl_evt from the
+**                  inq_cmpl_evt
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_process_cancel_complete(uint8_t status, uint8_t mode)
+{
+     btm_acl_update_busy_level (BTM_BLI_INQ_CANCEL_EVT);
+     btm_process_inq_complete(status, mode);
+}
+/*******************************************************************************
+**
+** Function         btm_initiate_rem_name
+**
+** Description      This function looks initiates a remote name request.  It is called
+**                  either by GAP or by the API call BTM_ReadRemoteDeviceName.
+**
+** Input Params:    p_cur         - pointer to an inquiry result structure (NULL if nonexistent)
+**                  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 sent to HCI.
+**                  BTM_BUSY if already in progress
+**                  BTM_NO_RESOURCES if could not allocate resources to start the command
+**                  BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+tBTM_STATUS  btm_initiate_rem_name (BD_ADDR remote_bda, tBTM_INQ_INFO *p_cur,
+                                    uint8_t origin, period_ms_t timeout_ms,
+                                    tBTM_CMPL_CB *p_cb)
+{
+    tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
+
+    /*** Make sure the device is ready ***/
+    if (!BTM_IsDeviceUp())
+        return (BTM_WRONG_MODE);
+
+
+    if (origin == BTM_RMT_NAME_SEC)
+    {
+        btsnd_hcic_rmt_name_req(remote_bda, HCI_PAGE_SCAN_REP_MODE_R1,
+                                HCI_MANDATARY_PAGE_SCAN_MODE, 0);
+        return BTM_CMD_STARTED;
+    }
+    /* Make sure there are no two remote name requests from external API in progress */
+    else if (origin == BTM_RMT_NAME_EXT)
+    {
+        if (p_inq->remname_active)
+        {
+            return (BTM_BUSY);
+        }
+        else
+        {
+            /* If there is no remote name request running,call the callback function and start timer */
+            p_inq->p_remname_cmpl_cb = p_cb;
+            memcpy(p_inq->remname_bda, remote_bda, BD_ADDR_LEN);
+
+            alarm_set_on_queue(p_inq->remote_name_timer, timeout_ms,
+                               btm_inq_remote_name_timer_timeout, NULL,
+                               btu_general_alarm_queue);
+
+            /* If the database entry exists for the device, use its clock offset */
+            if (p_cur)
+            {
+                btsnd_hcic_rmt_name_req(remote_bda,
+                                        p_cur->results.page_scan_rep_mode,
+                                        p_cur->results.page_scan_mode,
+                                        (uint16_t)(p_cur->results.clock_offset |
+                                                 BTM_CLOCK_OFFSET_VALID));
+            }
+            else /* Otherwise use defaults and mark the clock offset as invalid */
+            {
+                btsnd_hcic_rmt_name_req(remote_bda, HCI_PAGE_SCAN_REP_MODE_R1,
+                                        HCI_MANDATARY_PAGE_SCAN_MODE, 0);
+            }
+
+            p_inq->remname_active = true;
+            return BTM_CMD_STARTED;
+        }
+    }
+    else
+    {
+        return BTM_ILLEGAL_VALUE;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_process_remote_name
+**
+** Description      This function is called when a remote name is received from
+**                  the device. If remote names are cached, it updates the inquiry
+**                  database.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_process_remote_name (BD_ADDR bda, BD_NAME bdn, uint16_t evt_len, uint8_t hci_status)
+{
+    tBTM_REMOTE_DEV_NAME    rem_name;
+    tBTM_INQUIRY_VAR_ST    *p_inq = &btm_cb.btm_inq_vars;
+    tBTM_CMPL_CB           *p_cb = p_inq->p_remname_cmpl_cb;
+    uint8_t                *p_n1;
+
+    uint16_t               temp_evt_len;
+
+    if (bda != NULL)
+    {
+        BTM_TRACE_EVENT("BDA %02x:%02x:%02x:%02x:%02x:%02x",bda[0], bda[1],
+                 bda[2], bda[3],
+                 bda[4], bda[5]);
+    }
+
+    BTM_TRACE_EVENT("Inquire BDA %02x:%02x:%02x:%02x:%02x:%02x",p_inq->remname_bda[0], p_inq->remname_bda[1],
+             p_inq->remname_bda[2], p_inq->remname_bda[3],
+             p_inq->remname_bda[4], p_inq->remname_bda[5]);
+
+
+
+    /* If the inquire BDA and remote DBA are the same, then stop the timer and set the active to false */
+    if ((p_inq->remname_active ==true)&&
+        (((bda != NULL) &&
+        (memcmp(bda, p_inq->remname_bda,BD_ADDR_LEN)==0)) || bda == NULL))
+
+    {
+#if (BLE_INCLUDED == TRUE)
+        if (BTM_UseLeLink(p_inq->remname_bda))
+        {
+            if (hci_status == HCI_ERR_UNSPECIFIED)
+                btm_ble_cancel_remote_name(p_inq->remname_bda);
+        }
+#endif
+        alarm_cancel(p_inq->remote_name_timer);
+        p_inq->remname_active = false;
+         /* Clean up and return the status if the command was not successful */
+         /* Note: If part of the inquiry, the name is not stored, and the    */
+         /*       inquiry complete callback is called.                       */
+
+        if (hci_status == HCI_SUCCESS)
+        {
+            /* Copy the name from the data stream into the return structure */
+            /* Note that even if it is not being returned, it is used as a  */
+            /*      temporary buffer.                                       */
+            p_n1 = (uint8_t *)rem_name.remote_bd_name;
+            rem_name.length = (evt_len < BD_NAME_LEN) ? evt_len : BD_NAME_LEN;
+            rem_name.remote_bd_name[rem_name.length] = 0;
+            rem_name.status = BTM_SUCCESS;
+            temp_evt_len = rem_name.length;
+
+            while (temp_evt_len > 0)
+            {
+                *p_n1++ = *bdn++;
+                temp_evt_len--;
+            }
+            rem_name.remote_bd_name[rem_name.length] = 0;
+        }
+
+
+        /* If processing a stand alone remote name then report the error in the callback */
+        else
+        {
+            rem_name.status = BTM_BAD_VALUE_RET;
+            rem_name.length = 0;
+            rem_name.remote_bd_name[0] = 0;
+        }
+        /* Reset the remote BAD to zero and call callback if possible */
+        memset(p_inq->remname_bda, 0, BD_ADDR_LEN);
+
+        p_inq->p_remname_cmpl_cb = NULL;
+        if (p_cb)
+            (p_cb)((tBTM_REMOTE_DEV_NAME *)&rem_name);
+    }
+}
+
+void btm_inq_remote_name_timer_timeout(UNUSED_ATTR void *data)
+{
+    btm_inq_rmt_name_failed();
+}
+
+/*******************************************************************************
+**
+** Function         btm_inq_rmt_name_failed
+**
+** Description      This function is if timeout expires while getting remote
+**                  name.  This is done for devices that incorrectly do not
+**                  report operation failure
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_inq_rmt_name_failed (void)
+{
+    BTM_TRACE_ERROR ("btm_inq_rmt_name_failed()  remname_active=%d", btm_cb.btm_inq_vars.remname_active);
+
+    if (btm_cb.btm_inq_vars.remname_active)
+        btm_process_remote_name (btm_cb.btm_inq_vars.remname_bda, NULL, 0, HCI_ERR_UNSPECIFIED);
+    else
+        btm_process_remote_name (NULL, NULL, 0, HCI_ERR_UNSPECIFIED);
+
+    btm_sec_rmt_name_request_complete (NULL, NULL, HCI_ERR_UNSPECIFIED);
+}
+
+/*******************************************************************************
+**
+** Function         btm_read_inq_tx_power_timeout
+**
+** Description      Callback when reading the inquiry tx power times out.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_read_inq_tx_power_timeout(UNUSED_ATTR void *data)
+{
+    tBTM_CMPL_CB  *p_cb = btm_cb.devcb.p_inq_tx_power_cmpl_cb;
+    btm_cb.devcb.p_inq_tx_power_cmpl_cb = NULL;
+    if (p_cb)
+        (*p_cb)((void *) NULL);
+}
+
+/*******************************************************************************
+**
+** Function         btm_read_inq_tx_power_complete
+**
+** Description      read inquiry tx power level complete callback function.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_read_inq_tx_power_complete(uint8_t *p)
+{
+    tBTM_CMPL_CB                *p_cb = btm_cb.devcb.p_inq_tx_power_cmpl_cb;
+    tBTM_INQ_TXPWR_RESULTS        results;
+
+    BTM_TRACE_DEBUG("%s", __func__);
+    alarm_cancel(btm_cb.devcb.read_inq_tx_power_timer);
+    btm_cb.devcb.p_inq_tx_power_cmpl_cb = NULL;
+
+    /* If there was a registered callback, call it */
+    if (p_cb)
+    {
+        STREAM_TO_UINT8  (results.hci_status, p);
+
+        if (results.hci_status == HCI_SUCCESS)
+        {
+            results.status = BTM_SUCCESS;
+
+            STREAM_TO_UINT8 (results.tx_power, p);
+            BTM_TRACE_EVENT ("BTM INQ TX POWER Complete: tx_power %d, hci status 0x%02x",
+                              results.tx_power, results.hci_status);
+        }
+        else
+            results.status = BTM_ERR_PROCESSING;
+
+        (*p_cb)(&results);
+    }
+
+}
+/*******************************************************************************
+**
+** 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 )
+{
+    if (controller_get_interface()->supports_extended_inquiry_response())
+    {
+        BTM_TRACE_API("Write Extended Inquiry Response to controller");
+        btsnd_hcic_write_ext_inquiry_response (p_buff, BTM_EIR_DEFAULT_FEC_REQUIRED);
+        return BTM_SUCCESS;
+    }
+    else
+    {
+        osi_free(p_buff);
+        return BTM_MODE_UNSUPPORTED;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTM_CheckEirData
+**
+** Description      This function is called to get EIR data from significant part.
+**
+** Parameters       p_eir - pointer of EIR significant part
+**                  type   - finding EIR data type
+**                  p_length - return the length of EIR data not including type
+**
+** Returns          pointer of EIR data
+**
+*******************************************************************************/
+uint8_t *BTM_CheckEirData( uint8_t *p_eir, uint8_t type, uint8_t *p_length )
+{
+    uint8_t *p = p_eir;
+    uint8_t length;
+    uint8_t eir_type;
+    BTM_TRACE_API("BTM_CheckEirData type=0x%02X", type);
+
+    STREAM_TO_UINT8(length, p);
+    while( length && (p - p_eir <= HCI_EXT_INQ_RESPONSE_LEN))
+    {
+        STREAM_TO_UINT8(eir_type, p);
+        if( eir_type == type )
+        {
+            /* length doesn't include itself */
+            *p_length = length - 1; /* minus the length of type */
+            return p;
+        }
+        p += length - 1; /* skip the length of data */
+        STREAM_TO_UINT8(length, p);
+    }
+
+    *p_length = 0;
+    return NULL;
+}
+
+/*******************************************************************************
+**
+** Function         btm_convert_uuid_to_eir_service
+**
+** Description      This function is called to get the bit position of UUID.
+**
+** Parameters       uuid16 - UUID 16-bit
+**
+** Returns          BTM EIR service ID if found
+**                  BTM_EIR_MAX_SERVICES - if not found
+**
+*******************************************************************************/
+static uint8_t btm_convert_uuid_to_eir_service( uint16_t uuid16 )
+{
+    uint8_t xx;
+
+    for( xx = 0; xx < BTM_EIR_MAX_SERVICES; xx++ )
+    {
+        if( uuid16 == BTM_EIR_UUID_LKUP_TBL[xx])
+        {
+            return xx;
+        }
+    }
+    return BTM_EIR_MAX_SERVICES;
+}
+
+/*******************************************************************************
+**
+** 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( uint32_t *p_eir_uuid, uint16_t uuid16 )
+{
+    uint8_t service_id;
+
+    service_id = btm_convert_uuid_to_eir_service(uuid16);
+    if( service_id < BTM_EIR_MAX_SERVICES )
+        return( BTM_EIR_HAS_SERVICE( p_eir_uuid, service_id ));
+    else
+        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 BTM_HasInquiryEirService( tBTM_INQ_RESULTS *p_results, uint16_t uuid16 )
+{
+    if( BTM_HasEirService( p_results->eir_uuid, uuid16 ))
+    {
+        return BTM_EIR_FOUND;
+    }
+    else if( p_results->eir_complete_list )
+    {
+        return BTM_EIR_NOT_FOUND;
+    }
+    else
+        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 BTM_AddEirService( uint32_t *p_eir_uuid, uint16_t uuid16 )
+{
+    uint8_t service_id;
+
+    service_id = btm_convert_uuid_to_eir_service(uuid16);
+    if( service_id < BTM_EIR_MAX_SERVICES )
+        BTM_EIR_SET_SERVICE( p_eir_uuid, service_id );
+}
+
+/*******************************************************************************
+**
+** 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 BTM_RemoveEirService( uint32_t *p_eir_uuid, uint16_t uuid16 )
+{
+    uint8_t service_id;
+
+    service_id = btm_convert_uuid_to_eir_service(uuid16);
+    if( service_id < BTM_EIR_MAX_SERVICES )
+        BTM_EIR_CLR_SERVICE( p_eir_uuid, service_id );
+}
+
+/*******************************************************************************
+**
+** 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 BTM_GetEirSupportedServices( uint32_t *p_eir_uuid,    uint8_t **p,
+                                   uint8_t max_num_uuid16, uint8_t *p_num_uuid16)
+{
+    uint8_t service_index;
+
+    *p_num_uuid16 = 0;
+
+    for(service_index = 0; service_index < BTM_EIR_MAX_SERVICES; service_index++)
+    {
+        if( BTM_EIR_HAS_SERVICE( p_eir_uuid, service_index ))
+        {
+            if( *p_num_uuid16 < max_num_uuid16 )
+            {
+                UINT16_TO_STREAM(*p, BTM_EIR_UUID_LKUP_TBL[service_index]);
+                (*p_num_uuid16)++;
+            }
+            /* if max number of UUIDs are stored and found one more */
+            else
+            {
+                return BTM_EIR_MORE_16BITS_UUID_TYPE;
+            }
+        }
+    }
+    return BTM_EIR_COMPLETE_16BITS_UUID_TYPE;
+}
+
+/*******************************************************************************
+**
+** Function         BTM_GetEirUuidList
+**
+** Description      This function parses EIR and returns UUID list.
+**
+** Parameters       p_eir - EIR
+**                  uuid_size - LEN_UUID_16, LEN_UUID_32, LEN_UUID_128
+**                  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 BTM_GetEirUuidList( uint8_t *p_eir, uint8_t uuid_size, uint8_t *p_num_uuid,
+                            uint8_t *p_uuid_list, uint8_t max_num_uuid)
+{
+    uint8_t *p_uuid_data;
+    uint8_t type;
+    uint8_t yy, xx;
+    uint16_t *p_uuid16 = (uint16_t *)p_uuid_list;
+    uint32_t *p_uuid32 = (uint32_t *)p_uuid_list;
+    char    buff[LEN_UUID_128 * 2 + 1];
+
+    p_uuid_data = btm_eir_get_uuid_list( p_eir, uuid_size, p_num_uuid, &type );
+    if( p_uuid_data == NULL )
+    {
+        return 0x00;
+    }
+
+    if( *p_num_uuid > max_num_uuid )
+    {
+        BTM_TRACE_WARNING("BTM_GetEirUuidList number of uuid in EIR = %d, size of uuid list = %d",
+                           *p_num_uuid, max_num_uuid );
+        *p_num_uuid = max_num_uuid;
+    }
+
+    BTM_TRACE_DEBUG("BTM_GetEirUuidList type = %02X, number of uuid = %d", type, *p_num_uuid );
+
+    if( uuid_size == LEN_UUID_16 )
+    {
+        for( yy = 0; yy < *p_num_uuid; yy++ )
+        {
+            STREAM_TO_UINT16(*(p_uuid16 + yy), p_uuid_data);
+            BTM_TRACE_DEBUG("                     0x%04X", *(p_uuid16 + yy));
+        }
+    }
+    else if( uuid_size == LEN_UUID_32 )
+    {
+        for( yy = 0; yy < *p_num_uuid; yy++ )
+        {
+            STREAM_TO_UINT32(*(p_uuid32 + yy), p_uuid_data);
+            BTM_TRACE_DEBUG("                     0x%08X", *(p_uuid32 + yy));
+        }
+    }
+    else if( uuid_size == LEN_UUID_128 )
+    {
+        for( yy = 0; yy < *p_num_uuid; yy++ )
+        {
+            STREAM_TO_ARRAY16(p_uuid_list + yy * LEN_UUID_128, p_uuid_data);
+            for( xx = 0; xx < LEN_UUID_128; xx++ )
+                snprintf(buff + xx*2, sizeof(buff) - xx*2, "%02X",
+                         *(p_uuid_list + yy * LEN_UUID_128 + xx));
+            BTM_TRACE_DEBUG("                     0x%s", buff);
+        }
+    }
+
+    return type;
+}
+
+
+/*******************************************************************************
+**
+** Function         btm_eir_get_uuid_list
+**
+** Description      This function searches UUID list in EIR.
+**
+** Parameters       p_eir - address of EIR
+**                  uuid_size - size of UUID to find
+**                  p_num_uuid - number of UUIDs found
+**                  p_uuid_list_type - EIR data type
+**
+** Returns          NULL - if UUID list with uuid_size is not found
+**                  beginning of UUID list in EIR - otherwise
+**
+*******************************************************************************/
+static uint8_t *btm_eir_get_uuid_list( uint8_t *p_eir, uint8_t uuid_size,
+                                     uint8_t *p_num_uuid, uint8_t *p_uuid_list_type )
+{
+    uint8_t *p_uuid_data;
+    uint8_t complete_type, more_type;
+    uint8_t uuid_len;
+
+    switch( uuid_size )
+    {
+    case LEN_UUID_16:
+        complete_type = BTM_EIR_COMPLETE_16BITS_UUID_TYPE;
+        more_type     = BTM_EIR_MORE_16BITS_UUID_TYPE;
+        break;
+    case LEN_UUID_32:
+        complete_type = BTM_EIR_COMPLETE_32BITS_UUID_TYPE;
+        more_type     = BTM_EIR_MORE_32BITS_UUID_TYPE;
+        break;
+    case LEN_UUID_128:
+        complete_type = BTM_EIR_COMPLETE_128BITS_UUID_TYPE;
+        more_type     = BTM_EIR_MORE_128BITS_UUID_TYPE;
+        break;
+    default:
+        *p_num_uuid = 0;
+        return NULL;
+        break;
+    }
+
+    p_uuid_data = BTM_CheckEirData( p_eir, complete_type, &uuid_len );
+    if(p_uuid_data == NULL)
+    {
+        p_uuid_data = BTM_CheckEirData( p_eir, more_type, &uuid_len );
+        *p_uuid_list_type = more_type;
+    }
+    else
+    {
+        *p_uuid_list_type = complete_type;
+    }
+
+    *p_num_uuid = uuid_len / uuid_size;
+    return p_uuid_data;
+}
+
+/*******************************************************************************
+**
+** Function         btm_convert_uuid_to_uuid16
+**
+** Description      This function converts UUID to UUID 16-bit.
+**
+** Parameters       p_uuid - address of UUID
+**                  uuid_size - size of UUID
+**
+** Returns          0 - if UUID cannot be converted to UUID 16-bit
+**                  UUID 16-bit - otherwise
+**
+*******************************************************************************/
+static uint16_t btm_convert_uuid_to_uuid16( uint8_t *p_uuid, uint8_t uuid_size )
+{
+    static const uint8_t base_uuid[LEN_UUID_128] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
+                                                   0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+    uint16_t uuid16 = 0;
+    uint32_t uuid32;
+    bool    is_base_uuid;
+    uint8_t xx;
+
+    switch (uuid_size)
+    {
+    case LEN_UUID_16:
+        STREAM_TO_UINT16 (uuid16, p_uuid);
+        break;
+    case LEN_UUID_32:
+        STREAM_TO_UINT32 (uuid32, p_uuid);
+        if (uuid32 < 0x10000)
+            uuid16 = (uint16_t) uuid32;
+        break;
+    case LEN_UUID_128:
+        /* See if we can compress his UUID down to 16 or 32bit UUIDs */
+        is_base_uuid = true;
+        for (xx = 0; xx < LEN_UUID_128 - 4; xx++)
+        {
+            if (p_uuid[xx] != base_uuid[xx])
+            {
+                is_base_uuid = false;
+                break;
+            }
+        }
+        if (is_base_uuid)
+        {
+            if ((p_uuid[LEN_UUID_128 - 1] == 0) && (p_uuid[LEN_UUID_128 - 2] == 0))
+            {
+                p_uuid += (LEN_UUID_128 - 4);
+                STREAM_TO_UINT16(uuid16, p_uuid);
+            }
+        }
+        break;
+    default:
+        BTM_TRACE_WARNING("btm_convert_uuid_to_uuid16 invalid uuid size");
+        break;
+    }
+
+    return( uuid16);
+}
+
+/*******************************************************************************
+**
+** Function         btm_set_eir_uuid
+**
+** Description      This function is called to store received UUID into inquiry result.
+**
+** Parameters       p_eir - pointer of EIR significant part
+**                  p_results - pointer of inquiry result
+**
+** Returns          None
+**
+*******************************************************************************/
+void btm_set_eir_uuid( uint8_t *p_eir, tBTM_INQ_RESULTS *p_results )
+{
+    uint8_t *p_uuid_data;
+    uint8_t num_uuid;
+    uint16_t uuid16;
+    uint8_t yy;
+    uint8_t type = BTM_EIR_MORE_16BITS_UUID_TYPE;
+
+    p_uuid_data = btm_eir_get_uuid_list( p_eir, LEN_UUID_16, &num_uuid, &type );
+
+    if(type == BTM_EIR_COMPLETE_16BITS_UUID_TYPE)
+    {
+        p_results->eir_complete_list = true;
+    }
+    else
+    {
+        p_results->eir_complete_list = false;
+    }
+
+    BTM_TRACE_API("btm_set_eir_uuid eir_complete_list=0x%02X", p_results->eir_complete_list);
+
+    if( p_uuid_data )
+    {
+        for( yy = 0; yy < num_uuid; yy++ )
+        {
+            STREAM_TO_UINT16(uuid16, p_uuid_data);
+            BTM_AddEirService( p_results->eir_uuid, uuid16 );
+        }
+    }
+
+    p_uuid_data = btm_eir_get_uuid_list( p_eir, LEN_UUID_32, &num_uuid, &type );
+    if( p_uuid_data )
+    {
+        for( yy = 0; yy < num_uuid; yy++ )
+        {
+            uuid16 = btm_convert_uuid_to_uuid16( p_uuid_data, LEN_UUID_32 );
+            p_uuid_data += LEN_UUID_32;
+            if( uuid16 )
+                BTM_AddEirService( p_results->eir_uuid, uuid16 );
+        }
+    }
+
+    p_uuid_data = btm_eir_get_uuid_list( p_eir, LEN_UUID_128, &num_uuid, &type );
+    if( p_uuid_data )
+    {
+        for( yy = 0; yy < num_uuid; yy++ )
+        {
+            uuid16 = btm_convert_uuid_to_uuid16( p_uuid_data, LEN_UUID_128 );
+            p_uuid_data += LEN_UUID_128;
+            if( uuid16 )
+                BTM_AddEirService( p_results->eir_uuid, uuid16 );
+        }
+    }
+}
diff --git a/bt/stack/btm/btm_int.h b/bt/stack/btm/btm_int.h
new file mode 100644
index 0000000..bdf12c0
--- /dev/null
+++ b/bt/stack/btm/btm_int.h
@@ -0,0 +1,276 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 main Bluetooth Manager (BTM) internal
+ *  definitions.
+ *
+ ******************************************************************************/
+#ifndef BTM_INT_H
+#define BTM_INT_H
+
+#include "bt_target.h"
+#include "bt_common.h"
+#include "hcidefs.h"
+
+#include "rfcdefs.h"
+#include "osi/include/alarm.h"
+#include "osi/include/list.h"
+#include "osi/include/fixed_queue.h"
+
+#include "btm_api.h"
+
+#if (BLE_INCLUDED == TRUE)
+#include "btm_ble_int.h"
+#if (SMP_INCLUDED == TRUE)
+#include "smp_api.h"
+#endif
+#endif
+
+#include "btm_int_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern tBTM_CB btm_cb;
+
+/* Internal functions provided by btm_main.cc
+********************************************
+*/
+extern void         btm_init (void);
+
+/* Internal functions provided by btm_inq.cc
+*******************************************
+*/
+extern tBTM_STATUS  btm_initiate_rem_name(BD_ADDR remote_bda,
+                                          tBTM_INQ_INFO *p_cur,
+                                          uint8_t origin, period_ms_t timeout_ms,
+                                          tBTM_CMPL_CB *p_cb);
+
+extern void         btm_process_remote_name (BD_ADDR bda, BD_NAME name, uint16_t evt_len,
+                                             uint8_t hci_status);
+extern void         btm_inq_rmt_name_failed(void);
+extern void         btm_inq_remote_name_timer_timeout(void *data);
+
+/* Inquiry related functions */
+extern void         btm_clr_inq_db (BD_ADDR p_bda);
+extern void         btm_inq_db_init (void);
+extern void         btm_process_inq_results (uint8_t *p, uint8_t inq_res_mode);
+extern void         btm_process_inq_complete (uint8_t status, uint8_t mode);
+extern void         btm_process_cancel_complete(uint8_t status, uint8_t mode);
+extern void         btm_event_filter_complete (uint8_t *p);
+extern void         btm_inq_stop_on_ssp(void);
+extern void         btm_inq_clear_ssp(void);
+extern tINQ_DB_ENT *btm_inq_db_find (const BD_ADDR p_bda);
+extern bool         btm_inq_find_bdaddr (BD_ADDR p_bda);
+
+extern bool    btm_lookup_eir(BD_ADDR_PTR p_rem_addr);
+
+/* Internal functions provided by btm_acl.cc
+********************************************
+*/
+extern void         btm_acl_init (void);
+extern void         btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn,
+                                     uint16_t hci_handle, uint8_t link_role, tBT_TRANSPORT transport);
+extern void         btm_acl_removed (BD_ADDR bda, tBT_TRANSPORT transport);
+extern void         btm_acl_device_down (void);
+extern void         btm_acl_update_busy_level (tBTM_BLI_EVENT event);
+
+extern void         btm_cont_rswitch (tACL_CONN *p,
+                                      tBTM_SEC_DEV_REC *p_dev_rec,
+                                      uint8_t hci_status);
+
+extern uint8_t      btm_handle_to_acl_index (uint16_t hci_handle);
+extern void         btm_read_link_policy_complete (uint8_t *p);
+
+extern void         btm_read_rssi_timeout(void *data);
+extern void         btm_read_rssi_complete(uint8_t *p);
+
+extern void         btm_read_tx_power_timeout(void *data);
+extern void         btm_read_tx_power_complete(uint8_t *p, bool    is_ble);
+
+extern void         btm_read_link_quality_timeout(void *data);
+extern void         btm_read_link_quality_complete(uint8_t *p);
+
+extern tBTM_STATUS  btm_set_packet_types (tACL_CONN *p, uint16_t pkt_types);
+extern void         btm_process_clk_off_comp_evt (uint16_t hci_handle, uint16_t clock_offset);
+extern void         btm_acl_role_changed (uint8_t hci_status, BD_ADDR bd_addr, uint8_t new_role);
+extern void         btm_acl_encrypt_change (uint16_t handle, uint8_t status, uint8_t encr_enable);
+extern uint16_t     btm_get_acl_disc_reason_code (void);
+extern tBTM_STATUS  btm_remove_acl (BD_ADDR bd_addr, tBT_TRANSPORT transport);
+extern void         btm_read_remote_features_complete (uint8_t *p);
+extern void         btm_read_remote_ext_features_complete (uint8_t *p);
+extern void         btm_read_remote_ext_features_failed (uint8_t status, uint16_t handle);
+extern void         btm_read_remote_version_complete (uint8_t *p);
+extern void         btm_establish_continue (tACL_CONN *p_acl_cb);
+
+extern void         btm_acl_chk_peer_pkt_type_support (tACL_CONN *p, uint16_t *p_pkt_type);
+/* Read maximum data packet that can be sent over current connection */
+extern uint16_t btm_get_max_packet_size (BD_ADDR addr);
+extern tACL_CONN *btm_bda_to_acl (const BD_ADDR bda, tBT_TRANSPORT transport);
+extern bool       btm_acl_notif_conn_collision (BD_ADDR bda);
+extern void btm_acl_update_conn_addr(uint8_t conn_handle, BD_ADDR address);
+
+extern void btm_pm_reset(void);
+extern void btm_pm_sm_alloc(uint8_t ind);
+extern void btm_pm_proc_cmd_status(uint8_t status);
+extern void btm_pm_proc_mode_change (uint8_t hci_status, uint16_t hci_handle, uint8_t mode,
+                                     uint16_t interval);
+extern void btm_pm_proc_ssr_evt (uint8_t *p, uint16_t evt_len);
+extern tBTM_STATUS btm_read_power_mode_state (BD_ADDR remote_bda,
+                                                      tBTM_PM_STATE *pmState);
+#if (BTM_SCO_INCLUDED == TRUE)
+extern void btm_sco_chk_pend_unpark (uint8_t hci_status, uint16_t hci_handle);
+#else
+#define btm_sco_chk_pend_unpark(hci_status, hci_handle)
+#endif /* BTM_SCO_INCLUDED */
+
+extern void btm_qos_setup_timeout(void *data);
+extern void btm_qos_setup_complete(uint8_t status, uint16_t handle,
+                                   FLOW_SPEC *p_flow);
+
+
+/* Internal functions provided by btm_sco.cc
+********************************************
+*/
+extern void btm_sco_init (void);
+extern void btm_sco_connected (uint8_t hci_status, BD_ADDR bda, uint16_t hci_handle,
+                               tBTM_ESCO_DATA *p_esco_data);
+extern void btm_esco_proc_conn_chg (uint8_t status, uint16_t handle, uint8_t tx_interval,
+                                    uint8_t retrans_window, uint16_t rx_pkt_len,
+                                    uint16_t tx_pkt_len);
+extern void btm_sco_conn_req (BD_ADDR bda,  DEV_CLASS dev_class, uint8_t link_type);
+extern void btm_sco_removed (uint16_t hci_handle, uint8_t reason);
+extern void btm_sco_acl_removed (BD_ADDR bda);
+extern void btm_route_sco_data (BT_HDR *p_msg);
+extern bool    btm_is_sco_active (uint16_t handle);
+extern void btm_remove_sco_links (BD_ADDR bda);
+extern bool    btm_is_sco_active_by_bdaddr (BD_ADDR remote_bda);
+
+extern tBTM_SCO_TYPE btm_read_def_esco_mode (tBTM_ESCO_PARAMS *p_parms);
+extern uint16_t btm_find_scb_by_handle (uint16_t handle);
+extern void btm_sco_flush_sco_data(uint16_t sco_inx);
+
+/* Internal functions provided by btm_devctl.cc
+**********************************************
+*/
+extern void btm_dev_init(void);
+extern void btm_read_local_name_timeout(void *data);
+extern void btm_read_local_name_complete(uint8_t *p, uint16_t evt_len);
+
+#if (BLE_INCLUDED == TRUE)
+extern void btm_ble_add_2_white_list_complete(uint8_t status);
+extern void btm_ble_remove_from_white_list_complete(uint8_t *p, uint16_t evt_len);
+extern void btm_ble_clear_white_list_complete(uint8_t *p, uint16_t evt_len);
+extern bool    btm_ble_addr_resolvable(BD_ADDR rpa, tBTM_SEC_DEV_REC *p_dev_rec);
+extern tBTM_STATUS btm_ble_read_resolving_list_entry(tBTM_SEC_DEV_REC *p_dev_rec);
+extern bool    btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC *p_dev_rec);
+extern void btm_ble_resolving_list_remove_dev(tBTM_SEC_DEV_REC *p_dev_rec);
+#endif  /* BLE_INCLUDED */
+
+/* Vendor Specific Command complete evt handler */
+extern void btm_vsc_complete (uint8_t *p, uint16_t cc_opcode, uint16_t evt_len,
+                              tBTM_CMPL_CB *p_vsc_cplt_cback);
+extern void btm_inq_db_reset (void);
+extern void btm_vendor_specific_evt (uint8_t *p, uint8_t evt_len);
+extern void btm_delete_stored_link_key_complete (uint8_t *p);
+extern void btm_report_device_status (tBTM_DEV_STATUS status);
+
+
+/* Internal functions provided by btm_dev.cc
+**********************************************
+*/
+extern bool    btm_dev_support_switch (BD_ADDR bd_addr);
+
+extern tBTM_SEC_DEV_REC  *btm_sec_allocate_dev_rec(void);
+extern tBTM_SEC_DEV_REC  *btm_sec_alloc_dev (BD_ADDR bd_addr);
+extern void               btm_sec_free_dev (tBTM_SEC_DEV_REC *p_dev_rec);
+extern tBTM_SEC_DEV_REC  *btm_find_dev (const BD_ADDR bd_addr);
+extern tBTM_SEC_DEV_REC  *btm_find_or_alloc_dev (BD_ADDR bd_addr);
+extern tBTM_SEC_DEV_REC  *btm_find_dev_by_handle (uint16_t handle);
+extern tBTM_BOND_TYPE     btm_get_bond_type_dev(BD_ADDR bd_addr);
+extern bool               btm_set_bond_type_dev(BD_ADDR bd_addr,
+                                                tBTM_BOND_TYPE bond_type);
+
+/* Internal functions provided by btm_sec.cc
+**********************************************
+*/
+extern bool    btm_dev_support_switch (BD_ADDR bd_addr);
+extern tBTM_STATUS  btm_sec_l2cap_access_req (BD_ADDR bd_addr, uint16_t psm,
+                                       uint16_t handle, CONNECTION_TYPE conn_type,
+                                       tBTM_SEC_CALLBACK *p_callback, void *p_ref_data);
+extern tBTM_STATUS  btm_sec_mx_access_request (BD_ADDR bd_addr, uint16_t psm, bool    is_originator,
+                                        uint32_t mx_proto_id, uint32_t mx_chan_id,
+                                        tBTM_SEC_CALLBACK *p_callback, void *p_ref_data);
+extern void  btm_sec_conn_req (uint8_t *bda, uint8_t *dc);
+extern void btm_create_conn_cancel_complete (uint8_t *p);
+
+extern void  btm_read_inq_tx_power_timeout(void *data);
+extern void  btm_read_inq_tx_power_complete(uint8_t *p);
+
+extern void  btm_sec_init (uint8_t sec_mode);
+extern void  btm_sec_dev_reset (void);
+extern void  btm_sec_abort_access_req (BD_ADDR bd_addr);
+extern void  btm_sec_auth_complete (uint16_t handle, uint8_t status);
+extern void  btm_sec_encrypt_change (uint16_t handle, uint8_t status, uint8_t encr_enable);
+extern void  btm_sec_connected (uint8_t *bda, uint16_t handle, uint8_t status, uint8_t enc_mode);
+extern tBTM_STATUS btm_sec_disconnect (uint16_t handle, uint8_t reason);
+extern void  btm_sec_disconnected (uint16_t handle, uint8_t reason);
+extern void  btm_sec_rmt_name_request_complete (uint8_t *bd_addr, uint8_t *bd_name, uint8_t status);
+extern void  btm_sec_rmt_host_support_feat_evt (uint8_t *p);
+extern void  btm_io_capabilities_req (uint8_t *p);
+extern void  btm_io_capabilities_rsp (uint8_t *p);
+extern void  btm_proc_sp_req_evt (tBTM_SP_EVT event, uint8_t *p);
+extern void  btm_keypress_notif_evt (uint8_t *p);
+extern void  btm_simple_pair_complete (uint8_t *p);
+extern void  btm_sec_link_key_notification (uint8_t *p_bda, uint8_t *p_link_key, uint8_t key_type);
+extern void  btm_sec_link_key_request (uint8_t *p_bda);
+extern void  btm_sec_pin_code_request (uint8_t *p_bda);
+extern void  btm_sec_update_clock_offset (uint16_t handle, uint16_t clock_offset);
+extern void  btm_sec_dev_rec_cback_event (tBTM_SEC_DEV_REC *p_dev_rec, uint8_t res, bool    is_le_trasnport);
+extern void btm_sec_set_peer_sec_caps (tACL_CONN *p_acl_cb, tBTM_SEC_DEV_REC *p_dev_rec);
+
+#if (BLE_INCLUDED == TRUE)
+extern void  btm_sec_clear_ble_keys (tBTM_SEC_DEV_REC  *p_dev_rec);
+extern bool    btm_sec_is_a_bonded_dev (BD_ADDR bda);
+extern void btm_consolidate_dev(tBTM_SEC_DEV_REC *p_target_rec);
+extern bool    btm_sec_is_le_capable_dev (BD_ADDR bda);
+extern bool    btm_ble_init_pseudo_addr (tBTM_SEC_DEV_REC *p_dev_rec, BD_ADDR new_pseudo_addr);
+extern tBTM_SEC_SERV_REC *btm_sec_find_first_serv (CONNECTION_TYPE conn_type, uint16_t psm);
+extern bool    btm_ble_start_sec_check(BD_ADDR bd_addr, uint16_t psm, bool    is_originator,
+                            tBTM_SEC_CALLBACK *p_callback, void *p_ref_data);
+#endif /* BLE_INCLUDED */
+
+extern tINQ_DB_ENT *btm_inq_db_new (BD_ADDR p_bda);
+
+extern void  btm_rem_oob_req (uint8_t *p);
+extern void  btm_read_local_oob_complete (uint8_t *p);
+
+extern void  btm_acl_resubmit_page (void);
+extern void  btm_acl_reset_paging (void);
+extern void  btm_acl_paging (BT_HDR *p, BD_ADDR dest);
+extern uint8_t btm_sec_clr_service_by_psm (uint16_t psm);
+extern void  btm_sec_clr_temp_auth_service (BD_ADDR bda);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bt/stack/btm/btm_int_types.h b/bt/stack/btm/btm_int_types.h
new file mode 100644
index 0000000..6c61d41
--- /dev/null
+++ b/bt/stack/btm/btm_int_types.h
@@ -0,0 +1,888 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+#ifndef BTM_INT_TYPES_H
+#define BTM_INT_TYPES_H
+
+#include "btm_api_types.h"
+#include "btm_ble_api_types.h"
+#include "hcidefs.h"
+#include "btm_ble_int_types.h"
+#include "osi/include/alarm.h"
+#include "osi/include/list.h"
+#include "rfcdefs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef char tBTM_LOC_BD_NAME[BTM_MAX_LOC_BD_NAME_LEN + 1];
+
+#define  BTM_ACL_IS_CONNECTED(bda)   (btm_bda_to_acl (bda, BT_TRANSPORT_BR_EDR) != NULL)
+
+/* Definitions for Server Channel Number (SCN) management
+*/
+#define BTM_MAX_SCN      PORT_MAX_RFC_PORTS
+
+/* Define masks for supported and exception 2.0 ACL packet types
+*/
+#define BTM_ACL_SUPPORTED_PKTS_MASK      (HCI_PKT_TYPES_MASK_DM1        | \
+                                          HCI_PKT_TYPES_MASK_DH1        | \
+                                          HCI_PKT_TYPES_MASK_DM3        | \
+                                          HCI_PKT_TYPES_MASK_DH3        | \
+                                          HCI_PKT_TYPES_MASK_DM5        | \
+                                          HCI_PKT_TYPES_MASK_DH5)
+
+#define BTM_ACL_EXCEPTION_PKTS_MASK      (HCI_PKT_TYPES_MASK_NO_2_DH1   | \
+                                          HCI_PKT_TYPES_MASK_NO_3_DH1   | \
+                                          HCI_PKT_TYPES_MASK_NO_2_DH3   | \
+                                          HCI_PKT_TYPES_MASK_NO_3_DH3   | \
+                                          HCI_PKT_TYPES_MASK_NO_2_DH5   | \
+                                          HCI_PKT_TYPES_MASK_NO_3_DH5)
+
+#define BTM_EPR_AVAILABLE(p) ((HCI_ATOMIC_ENCRYPT_SUPPORTED((p)->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]) && \
+                               HCI_ATOMIC_ENCRYPT_SUPPORTED(controller_get_interface()->get_features_classic(0)->as_array)) \
+                               ? true : false)
+
+#define BTM_IS_BRCM_CONTROLLER() (controller_get_interface()->get_bt_version()->manufacturer == LMP_COMPID_BROADCOM)
+
+/* Define the ACL Management control structure
+*/
+typedef struct
+{
+    uint16_t        hci_handle;
+    uint16_t        pkt_types_mask;
+    uint16_t        clock_offset;
+    BD_ADDR         remote_addr;
+    DEV_CLASS       remote_dc;
+    BD_NAME         remote_name;
+
+    uint16_t        manufacturer;
+    uint16_t        lmp_subversion;
+    uint16_t        link_super_tout;
+    BD_FEATURES     peer_lmp_features[HCI_EXT_FEATURES_PAGE_MAX + 1];    /* Peer LMP Extended features mask table for the device */
+    uint8_t         num_read_pages;
+    uint8_t         lmp_version;
+
+    bool            in_use;
+    uint8_t         link_role;
+    bool            link_up_issued;     /* True if busy_level link up has been issued */
+
+#define BTM_ACL_SWKEY_STATE_IDLE                0
+#define BTM_ACL_SWKEY_STATE_MODE_CHANGE         1
+#define BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF      2
+#define BTM_ACL_SWKEY_STATE_SWITCHING           3
+#define BTM_ACL_SWKEY_STATE_ENCRYPTION_ON       4
+#define BTM_ACL_SWKEY_STATE_IN_PROGRESS         5
+    uint8_t         switch_role_state;
+
+#define BTM_ACL_ENCRYPT_STATE_IDLE              0
+#define BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF       1   /* encryption turning off */
+#define BTM_ACL_ENCRYPT_STATE_TEMP_FUNC         2   /* temporarily off for change link key or role switch */
+#define BTM_ACL_ENCRYPT_STATE_ENCRYPT_ON        3   /* encryption turning on */
+    uint8_t         encrypt_state;                  /* overall BTM encryption state */
+
+#if (BLE_INCLUDED == TRUE)
+    tBT_TRANSPORT   transport;
+    BD_ADDR         conn_addr;              /* local device address used for this connection */
+    uint8_t         conn_addr_type;         /* local device address type for this connection */
+    BD_ADDR         active_remote_addr;     /* remote address used on this connection */
+    uint8_t         active_remote_addr_type;         /* local device address type for this connection */
+    BD_FEATURES     peer_le_features;       /* Peer LE Used features mask for the device */
+
+#endif
+
+} tACL_CONN;
+
+/* Define the Device Management control structure
+*/
+typedef struct
+{
+    tBTM_DEV_STATUS_CB  *p_dev_status_cb;   /* Device status change callback        */
+    tBTM_VS_EVT_CB      *p_vend_spec_cb[BTM_MAX_VSE_CALLBACKS];     /* Register for vendor specific events  */
+
+    tBTM_CMPL_CB        *p_stored_link_key_cmpl_cb;   /* Read/Write/Delete stored link key    */
+
+    alarm_t             *read_local_name_timer; /* Read local name timer */
+    tBTM_CMPL_CB        *p_rln_cmpl_cb;     /* Callback function to be called when  */
+                                            /* read local name function complete    */
+    alarm_t             *read_rssi_timer;   /* Read RSSI timer */
+    tBTM_CMPL_CB        *p_rssi_cmpl_cb;    /* Callback function to be called when  */
+                                            /* read RSSI function completes */
+    alarm_t             *read_link_quality_timer;
+    tBTM_CMPL_CB        *p_link_qual_cmpl_cb; /* Callback function to be called when  */
+                                            /* read link quality function completes */
+
+    alarm_t             *read_inq_tx_power_timer;
+    tBTM_CMPL_CB        *p_inq_tx_power_cmpl_cb; /* Callback function to be called when  */
+                                            /* read inq tx power function completes  */
+
+    alarm_t             *qos_setup_timer;   /* QoS setup timer */
+    tBTM_CMPL_CB        *p_qos_setup_cmpl_cb; /* Callback function to be called when  */
+                                            /* qos setup function completes         */
+
+    tBTM_ROLE_SWITCH_CMPL switch_role_ref_data;
+    tBTM_CMPL_CB        *p_switch_role_cb;  /* Callback function to be called when  */
+                                            /* requested switch role is completed   */
+
+    alarm_t             *read_tx_power_timer; /* Read tx power timer */
+    tBTM_CMPL_CB        *p_tx_power_cmpl_cb;/* Callback function to be called       */
+
+    DEV_CLASS            dev_class;         /* Local device class                   */
+
+#if (BLE_INCLUDED == TRUE)
+
+    tBTM_CMPL_CB        *p_le_test_cmd_cmpl_cb;   /* Callback function to be called when
+                                                  LE test mode command has been sent successfully */
+
+    BD_ADDR                 read_tx_pwr_addr;   /* read TX power target address     */
+
+#define BTM_LE_SUPPORT_STATE_SIZE   8
+uint8_t                 le_supported_states[BTM_LE_SUPPORT_STATE_SIZE];
+
+tBTM_BLE_LOCAL_ID_KEYS id_keys; /* local BLE ID keys */
+BT_OCTET16 ble_encryption_key_value; /* BLE encryption key */
+
+#if (BTM_BLE_CONFORMANCE_TESTING == TRUE)
+    bool                    no_disc_if_pair_fail;
+    bool                    enable_test_mac_val;
+    BT_OCTET8               test_mac;
+    bool                    enable_test_local_sign_cntr;
+    uint32_t                test_local_sign_cntr;
+#endif
+
+#endif  /* BLE_INCLUDED */
+
+    tBTM_IO_CAP          loc_io_caps;       /* IO capability of the local device */
+    tBTM_AUTH_REQ        loc_auth_req;      /* the auth_req flag  */
+    bool                 secure_connections_only;    /* Rejects service level 0 connections if */
+                                                     /* itself or peer device doesn't support */
+                                                     /* secure connections */
+} tBTM_DEVCB;
+
+
+/* Define the structures and constants used for inquiry
+*/
+
+/* Definitions of limits for inquiries */
+#define BTM_PER_INQ_MIN_MAX_PERIOD      HCI_PER_INQ_MIN_MAX_PERIOD
+#define BTM_PER_INQ_MAX_MAX_PERIOD      HCI_PER_INQ_MAX_MAX_PERIOD
+#define BTM_PER_INQ_MIN_MIN_PERIOD      HCI_PER_INQ_MIN_MIN_PERIOD
+#define BTM_PER_INQ_MAX_MIN_PERIOD      HCI_PER_INQ_MAX_MIN_PERIOD
+#define BTM_MAX_INQUIRY_LENGTH          HCI_MAX_INQUIRY_LENGTH
+#define BTM_MIN_INQUIRY_LEN             0x01
+
+#define BTM_MIN_INQ_TX_POWER    (-70)
+#define BTM_MAX_INQ_TX_POWER    20
+
+typedef struct
+{
+    uint32_t        inq_count;          /* Used for determining if a response has already been      */
+                                        /* received for the current inquiry operation. (We do not   */
+                                        /* want to flood the caller with multiple responses from    */
+                                        /* the same device.                                         */
+    BD_ADDR         bd_addr;
+} tINQ_BDADDR;
+
+typedef struct
+{
+    uint32_t        time_of_resp;
+    uint32_t        inq_count;          /* "timestamps" the entry with a particular inquiry count   */
+                                        /* Used for determining if a response has already been      */
+                                        /* received for the current inquiry operation. (We do not   */
+                                        /* want to flood the caller with multiple responses from    */
+                                        /* the same device.                                         */
+    tBTM_INQ_INFO   inq_info;
+    bool            in_use;
+
+#if (BLE_INCLUDED == TRUE)
+    bool            scan_rsp;
+#endif
+} tINQ_DB_ENT;
+
+
+enum
+{
+    INQ_NONE,
+    INQ_LE_OBSERVE,
+    INQ_GENERAL
+};
+typedef uint8_t tBTM_INQ_TYPE;
+
+typedef struct
+{
+    tBTM_CMPL_CB *p_remname_cmpl_cb;
+
+#define BTM_EXT_RMT_NAME_TIMEOUT_MS (40 * 1000) /* 40 seconds */
+
+
+    alarm_t         *remote_name_timer;
+
+    uint16_t         discoverable_mode;
+    uint16_t         connectable_mode;
+    uint16_t         page_scan_window;
+    uint16_t         page_scan_period;
+    uint16_t         inq_scan_window;
+    uint16_t         inq_scan_period;
+    uint16_t         inq_scan_type;
+    uint16_t         page_scan_type;        /* current page scan type */
+    tBTM_INQ_TYPE    scan_type;
+
+    BD_ADDR          remname_bda;           /* Name of bd addr for active remote name request */
+#define BTM_RMT_NAME_INACTIVE       0
+#define BTM_RMT_NAME_EXT            0x1     /* Initiated through API */
+#define BTM_RMT_NAME_SEC            0x2     /* Initiated internally by security manager */
+#define BTM_RMT_NAME_INQ            0x4     /* Remote name initiated internally by inquiry */
+    bool             remname_active;        /* State of a remote name request by external API */
+
+    tBTM_CMPL_CB    *p_inq_cmpl_cb;
+    tBTM_INQ_RESULTS_CB *p_inq_results_cb;
+    tBTM_CMPL_CB    *p_inq_ble_cmpl_cb;     /*completion callback exclusively for LE Observe*/
+    tBTM_INQ_RESULTS_CB *p_inq_ble_results_cb;/*results callback exclusively for LE observe*/
+    tBTM_CMPL_CB    *p_inqfilter_cmpl_cb;   /* Called (if not NULL) after inquiry filter completed */
+    uint32_t         inq_counter;           /* Counter incremented each time an inquiry completes */
+                                            /* Used for determining whether or not duplicate devices */
+                                            /* have responded to the same inquiry */
+    tINQ_BDADDR     *p_bd_db;               /* Pointer to memory that holds bdaddrs */
+    uint16_t         num_bd_entries;        /* Number of entries in database */
+    uint16_t         max_bd_entries;        /* Maximum number of entries that can be stored */
+    tINQ_DB_ENT      inq_db[BTM_INQ_DB_SIZE];
+    tBTM_INQ_PARMS   inqparms;              /* Contains the parameters for the current inquiry */
+    tBTM_INQUIRY_CMPL inq_cmpl_info;        /* Status and number of responses from the last inquiry */
+
+    uint16_t         per_min_delay;         /* Current periodic minimum delay */
+    uint16_t         per_max_delay;         /* Current periodic maximum delay */
+    bool             inqfilt_active;
+    uint8_t          pending_filt_complete_event; /* to take care of btm_event_filter_complete corresponding to */
+                                                  /* inquiry that has been cancelled*/
+    uint8_t          inqfilt_type;          /* Contains the inquiry filter type (BD ADDR, COD, or Clear) */
+
+#define BTM_INQ_INACTIVE_STATE      0
+#define BTM_INQ_CLR_FILT_STATE      1   /* Currently clearing the inquiry filter preceeding the inquiry request */
+                                        /* (bypassed if filtering is not used)                                  */
+#define BTM_INQ_SET_FILT_STATE      2   /* Sets the new filter (or turns off filtering) in this state */
+#define BTM_INQ_ACTIVE_STATE        3   /* Actual inquiry or periodic inquiry is in progress */
+#define BTM_INQ_REMNAME_STATE       4   /* Remote name requests are active  */
+
+    uint8_t          state;             /* Current state that the inquiry process is in */
+    uint8_t          inq_active;        /* Bit Mask indicating type of inquiry is active */
+    bool             no_inc_ssp;        /* true, to stop inquiry on incoming SSP */
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+    btm_inq_state    next_state;        /*interleaving state to determine next mode to be inquired*/
+#endif
+} tBTM_INQUIRY_VAR_ST;
+
+/* The MSB of the clock offset field indicates that the offset is valid if true */
+#define BTM_CLOCK_OFFSET_VALID      0x8000
+
+/* Define the structures needed by security management
+*/
+
+#define BTM_SEC_INVALID_HANDLE  0xFFFF
+
+typedef uint8_t *BTM_BD_NAME_PTR;                        /* Pointer to Device name */
+
+/* Security callback is called by this unit when security
+**   procedures are completed.  Parameters are
+**              BD Address of remote
+**              Result of the operation
+*/
+typedef tBTM_SEC_CBACK tBTM_SEC_CALLBACK;
+
+typedef void (tBTM_SCO_IND_CBACK) (uint16_t sco_inx) ;
+
+/* MACROs to convert from SCO packet types mask to ESCO and back */
+#define BTM_SCO_PKT_TYPE_MASK   (   HCI_PKT_TYPES_MASK_HV1      \
+                                 |  HCI_PKT_TYPES_MASK_HV2      \
+                                 |  HCI_PKT_TYPES_MASK_HV3)
+
+/* Mask defining only the SCO types of an esco packet type */
+#define BTM_ESCO_PKT_TYPE_MASK  (   HCI_ESCO_PKT_TYPES_MASK_HV1 \
+                                 |  HCI_ESCO_PKT_TYPES_MASK_HV2 \
+                                 |  HCI_ESCO_PKT_TYPES_MASK_HV3)
+
+#define BTM_SCO_2_ESCO(scotype)  ((uint16_t)(((scotype) & BTM_SCO_PKT_TYPE_MASK) >> 5))
+#define BTM_ESCO_2_SCO(escotype) ((uint16_t)(((escotype) & BTM_ESCO_PKT_TYPE_MASK) << 5))
+
+/* Define masks for supported and exception 2.0 SCO packet types
+*/
+#define BTM_SCO_SUPPORTED_PKTS_MASK      (HCI_ESCO_PKT_TYPES_MASK_HV1       | \
+                                          HCI_ESCO_PKT_TYPES_MASK_HV2       | \
+                                          HCI_ESCO_PKT_TYPES_MASK_HV3       | \
+                                          HCI_ESCO_PKT_TYPES_MASK_EV3       | \
+                                          HCI_ESCO_PKT_TYPES_MASK_EV4       | \
+                                          HCI_ESCO_PKT_TYPES_MASK_EV5)
+
+#define BTM_SCO_EXCEPTION_PKTS_MASK      (HCI_ESCO_PKT_TYPES_MASK_NO_2_EV3  | \
+                                          HCI_ESCO_PKT_TYPES_MASK_NO_3_EV3  | \
+                                          HCI_ESCO_PKT_TYPES_MASK_NO_2_EV5  | \
+                                          HCI_ESCO_PKT_TYPES_MASK_NO_3_EV5)
+
+
+#define BTM_SCO_ROUTE_UNKNOWN       0xff
+
+/* Define the structure that contains (e)SCO data */
+typedef struct
+{
+    tBTM_ESCO_CBACK    *p_esco_cback;   /* Callback for eSCO events     */
+    tBTM_ESCO_PARAMS    setup;
+    tBTM_ESCO_DATA      data;           /* Connection complete information */
+    uint8_t             hci_status;
+} tBTM_ESCO_INFO;
+
+/* Define the structure used for SCO Management
+*/
+typedef struct
+{
+    tBTM_ESCO_INFO   esco;              /* Current settings             */
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+    fixed_queue_t   *xmit_data_q;       /* SCO data transmitting queue  */
+#endif
+    tBTM_SCO_CB     *p_conn_cb;         /* Callback for when connected  */
+    tBTM_SCO_CB     *p_disc_cb;         /* Callback for when disconnect */
+    uint16_t         state;             /* The state of the SCO link    */
+    uint16_t         hci_handle;        /* HCI Handle                   */
+    bool             is_orig;           /* true if the originator       */
+    bool             rem_bd_known;      /* true if remote BD addr known */
+
+} tSCO_CONN;
+
+/* SCO Management control block */
+typedef struct
+{
+    tBTM_SCO_IND_CBACK  *app_sco_ind_cb;
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+    tBTM_SCO_DATA_CB     *p_data_cb;        /* Callback for SCO data over HCI */
+    uint32_t             xmit_window_size; /* Total SCO window in bytes  */
+#endif
+    tSCO_CONN            sco_db[BTM_MAX_SCO_LINKS];
+    tBTM_ESCO_PARAMS     def_esco_parms;
+    BD_ADDR              xfer_addr;
+    uint16_t             sco_disc_reason;
+    bool                 esco_supported;    /* true if 1.2 cntlr AND supports eSCO links */
+    tBTM_SCO_TYPE        desired_sco_mode;
+    tBTM_SCO_TYPE        xfer_sco_type;
+    tBTM_SCO_PCM_PARAM   sco_pcm_param;
+    tBTM_SCO_CODEC_TYPE  codec_in_use;      /* None, CVSD, MSBC, etc. */
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+    tBTM_SCO_ROUTE_TYPE  sco_path;
+#endif
+
+} tSCO_CB;
+
+
+#if (BTM_SCO_INCLUDED == TRUE)
+extern void     btm_set_sco_ind_cback( tBTM_SCO_IND_CBACK *sco_ind_cb );
+extern void     btm_accept_sco_link(uint16_t sco_inx, tBTM_ESCO_PARAMS *p_setup,
+                                    tBTM_SCO_CB *p_conn_cb, tBTM_SCO_CB *p_disc_cb);
+extern void     btm_reject_sco_link(uint16_t sco_inx );
+extern void btm_sco_chk_pend_rolechange (uint16_t hci_handle);
+extern void btm_sco_disc_chk_pend_for_modechange (uint16_t hci_handle);
+
+#else
+#define btm_accept_sco_link(sco_inx, p_setup, p_conn_cb, p_disc_cb)
+#define btm_reject_sco_link(sco_inx)
+#define btm_set_sco_ind_cback(sco_ind_cb)
+#define btm_sco_chk_pend_rolechange(hci_handle)
+#endif  /* BTM_SCO_INCLUDED */
+
+/*
+** Define structure for Security Service Record.
+** A record exists for each service registered with the Security Manager
+*/
+#define BTM_SEC_OUT_FLAGS   (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHORIZE)
+#define BTM_SEC_IN_FLAGS    (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHORIZE)
+
+#define BTM_SEC_OUT_LEVEL4_FLAGS   (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT | \
+                                    BTM_SEC_OUT_MITM | BTM_SEC_MODE4_LEVEL4)
+
+#define BTM_SEC_IN_LEVEL4_FLAGS    (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT | \
+                                    BTM_SEC_IN_MITM | BTM_SEC_MODE4_LEVEL4)
+typedef struct
+{
+    uint32_t        mx_proto_id;        /* Service runs over this multiplexer protocol */
+    uint32_t        orig_mx_chan_id;    /* Channel on the multiplexer protocol    */
+    uint32_t        term_mx_chan_id;    /* Channel on the multiplexer protocol    */
+    uint16_t        psm;                /* L2CAP PSM value */
+    uint16_t        security_flags;     /* Bitmap of required security features */
+    uint8_t         service_id;         /* Passed in authorization callback */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+    uint16_t        ucd_security_flags; /* Bitmap of required security features for UCD */
+#endif
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+    uint8_t         orig_service_name[BTM_SEC_SERVICE_NAME_LEN + 1];
+    uint8_t         term_service_name[BTM_SEC_SERVICE_NAME_LEN + 1];
+#endif
+} tBTM_SEC_SERV_REC;
+
+#if (BLE_INCLUDED == TRUE)
+/* LE Security information of device in Slave Role */
+typedef struct
+{
+    BT_OCTET16          irk;            /* peer diverified identity root */
+    BT_OCTET16          pltk;           /* peer long term key */
+    BT_OCTET16          pcsrk;          /* peer SRK peer device used to secured sign local data  */
+
+    BT_OCTET16          lltk;           /* local long term key */
+    BT_OCTET16          lcsrk;          /* local SRK peer device used to secured sign local data  */
+
+    BT_OCTET8           rand;           /* random vector for LTK generation */
+    uint16_t            ediv;           /* LTK diversifier of this slave device */
+    uint16_t            div;            /* local DIV  to generate local LTK=d1(ER,DIV,0) and CSRK=d1(ER,DIV,1)  */
+    uint8_t             sec_level;      /* local pairing security level */
+    uint8_t             key_size;       /* key size of the LTK delivered to peer device */
+    uint8_t             srk_sec_level;  /* security property of peer SRK for this device */
+    uint8_t             local_csrk_sec_level;  /* security property of local CSRK for this device */
+
+    uint32_t            counter;        /* peer sign counter for verifying rcv signed cmd */
+    uint32_t            local_counter;  /* local sign counter for sending signed write cmd*/
+}tBTM_SEC_BLE_KEYS;
+
+typedef struct
+{
+    BD_ADDR pseudo_addr; /* LE pseudo address of the device if different from device address  */
+    tBLE_ADDR_TYPE      ble_addr_type;  /* LE device type: public or random address */
+    tBLE_ADDR_TYPE      static_addr_type;   /* static address type */
+    BD_ADDR             static_addr;    /* static address */
+
+#define BTM_WHITE_LIST_BIT          0x01
+#define BTM_RESOLVING_LIST_BIT      0x02
+    uint8_t             in_controller_list;   /* in controller resolving list or not */
+    uint8_t             resolving_list_index;
+#if (BLE_PRIVACY_SPT == TRUE)
+    BD_ADDR             cur_rand_addr;  /* current random address */
+
+#define BTM_BLE_ADDR_PSEUDO         0   /* address index device record */
+#define BTM_BLE_ADDR_RRA            1   /* cur_rand_addr */
+#define BTM_BLE_ADDR_STATIC         2   /* static_addr  */
+    uint8_t             active_addr_type;
+#endif
+
+#if (SMP_INCLUDED == TRUE)
+    tBTM_LE_KEY_TYPE    key_type;       /* bit mask of valid key types in record */
+    tBTM_SEC_BLE_KEYS   keys;           /* LE device security info in slave rode */
+#endif
+} tBTM_SEC_BLE;
+
+
+#endif  /* BLE_INCLUDED */
+
+/* Peering bond type */
+enum
+{
+    BOND_TYPE_UNKNOWN,
+    BOND_TYPE_PERSISTENT,
+    BOND_TYPE_TEMPORARY
+};
+typedef uint8_t tBTM_BOND_TYPE;
+
+/*
+** Define structure for Security Device Record.
+** A record exists for each device authenticated with this device
+*/
+typedef struct
+{
+    tBTM_SEC_SERV_REC   *p_cur_service;
+    tBTM_SEC_CALLBACK   *p_callback;
+    void                *p_ref_data;
+    uint32_t             timestamp;         /* Timestamp of the last connection   */
+    uint32_t             trusted_mask[BTM_SEC_SERVICE_ARRAY_SIZE];  /* Bitwise OR of trusted services     */
+    uint16_t             hci_handle;        /* Handle to connection when exists   */
+    uint16_t             clock_offset;      /* Latest known clock offset          */
+    BD_ADDR              bd_addr;           /* BD_ADDR of the device              */
+    DEV_CLASS            dev_class;         /* DEV_CLASS of the device            */
+    LINK_KEY             link_key;          /* Device link key                    */
+    uint8_t              pin_code_length;   /* Length of the pin_code used for paring */
+
+#define BTM_SEC_AUTHORIZED      BTM_SEC_FLAG_AUTHORIZED     /* 0x01 */
+#define BTM_SEC_AUTHENTICATED   BTM_SEC_FLAG_AUTHENTICATED  /* 0x02 */
+#define BTM_SEC_ENCRYPTED       BTM_SEC_FLAG_ENCRYPTED      /* 0x04 */
+#define BTM_SEC_NAME_KNOWN      0x08
+#define BTM_SEC_LINK_KEY_KNOWN  BTM_SEC_FLAG_LKEY_KNOWN /* 0x10 */
+#define BTM_SEC_LINK_KEY_AUTHED BTM_SEC_FLAG_LKEY_AUTHED    /* 0x20 */
+#define BTM_SEC_ROLE_SWITCHED   0x40
+#define BTM_SEC_IN_USE          0x80
+    /* LE link security flag */
+#define BTM_SEC_LE_AUTHENTICATED   0x0200   /* LE link is encrypted after pairing with MITM */
+#define BTM_SEC_LE_ENCRYPTED       0x0400   /* LE link is encrypted */
+#define BTM_SEC_LE_NAME_KNOWN      0x0800   /* not used */
+#define BTM_SEC_LE_LINK_KEY_KNOWN  0x1000   /* bonded with peer (peer LTK and/or SRK is saved) */
+#define BTM_SEC_LE_LINK_KEY_AUTHED 0x2000   /* pairing is done with MITM */
+#define BTM_SEC_16_DIGIT_PIN_AUTHED 0x4000   /* pairing is done with 16 digit pin */
+
+    uint16_t         sec_flags;          /* Current device security state      */
+
+    tBTM_BD_NAME    sec_bd_name;        /* User friendly name of the device. (may be truncated to save space in dev_rec table) */
+    BD_FEATURES     features[HCI_EXT_FEATURES_PAGE_MAX + 1];           /* Features supported by the device */
+    uint8_t         num_read_pages;
+
+#define BTM_SEC_STATE_IDLE               0
+#define BTM_SEC_STATE_AUTHENTICATING     1
+#define BTM_SEC_STATE_ENCRYPTING         2
+#define BTM_SEC_STATE_GETTING_NAME       3
+#define BTM_SEC_STATE_AUTHORIZING        4
+#define BTM_SEC_STATE_SWITCHING_ROLE     5
+#define BTM_SEC_STATE_DISCONNECTING      6 /* disconnecting BR/EDR */
+#define BTM_SEC_STATE_DELAY_FOR_ENC      7 /* delay to check for encryption to work around */
+                                           /* controller problems */
+#define BTM_SEC_STATE_DISCONNECTING_BLE  8 /* disconnecting BLE */
+#define BTM_SEC_STATE_DISCONNECTING_BOTH 9 /* disconnecting BR/EDR and BLE */
+
+    uint8_t     sec_state;              /* Operating state                    */
+    bool        is_originator;          /* true if device is originating connection */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+    bool        is_ucd;                 /* true if device is sending or receiving UCD */
+                                        /* if incoming security failed, received UCD will be discarded */
+#endif
+    bool        role_master;            /* true if current mode is master     */
+    uint16_t    security_required;      /* Security required for connection   */
+    bool        link_key_not_sent;      /* link key notification has not been sent waiting for name */
+    uint8_t     link_key_type;          /* Type of key used in pairing   */
+    bool        link_key_changed;       /* Changed link key during current connection */
+
+#define BTM_MAX_PRE_SM4_LKEY_TYPE   BTM_LKEY_TYPE_REMOTE_UNIT /* the link key type used by legacy pairing */
+
+#define BTM_SM4_UNKNOWN     0x00
+#define BTM_SM4_KNOWN       0x10
+#define BTM_SM4_TRUE        0x11
+#define BTM_SM4_REQ_PEND    0x08        /* set this bit when getting remote features */
+#define BTM_SM4_UPGRADE     0x04        /* set this bit when upgrading link key */
+#define BTM_SM4_RETRY       0x02        /* set this bit to retry on HCI_ERR_KEY_MISSING or HCI_ERR_LMP_ERR_TRANS_COLLISION */
+#define BTM_SM4_DD_ACP      0x20        /* set this bit to indicate peer initiated dedicated bonding */
+#define BTM_SM4_CONN_PEND   0x40        /* set this bit to indicate accepting acl conn; to be cleared on btm_acl_created */
+    uint8_t     sm4;                    /* BTM_SM4_TRUE, if the peer supports SM4 */
+    tBTM_IO_CAP rmt_io_caps;            /* IO capability of the peer device */
+    tBTM_AUTH_REQ rmt_auth_req;         /* the auth_req flag as in the IO caps rsp evt */
+    bool        remote_supports_secure_connections;
+    bool        remote_features_needed; /* set to true if the local device is in */
+                                        /* "Secure Connections Only" mode and it receives */
+                                        /* HCI_IO_CAPABILITY_REQUEST_EVT from the peer before */
+                                        /* it knows peer's support for Secure Connections */
+
+    uint16_t            ble_hci_handle;         /* use in DUMO connection */
+    uint8_t             enc_key_size;           /* current link encryption key size */
+    tBT_DEVICE_TYPE     device_type;
+    bool                new_encryption_key_is_p256; /* Set to true when the newly generated LK
+                                                    ** is generated from P-256.
+                                                    ** Link encrypted with such LK can be used
+                                                    ** for SM over BR/EDR.
+                                                    */
+    bool    no_smp_on_br;       /* if set to true then SMP on BR/EDR doesn't */
+                                /* work, i.e. link keys crosspairing */
+                                /* SC BR/EDR->SC LE doesn't happen */
+    tBTM_BOND_TYPE bond_type;   /* peering bond type */
+
+#if (BLE_INCLUDED == TRUE)
+    tBTM_SEC_BLE        ble;
+    tBTM_LE_CONN_PRAMS  conn_params;
+#endif
+
+#if (BTM_DISC_DURING_RS == TRUE)
+#define BTM_SEC_RS_NOT_PENDING          0           /* Role Switch not in progress */
+#define BTM_SEC_RS_PENDING              1           /* Role Switch in progress */
+#define BTM_SEC_DISC_PENDING            2           /* Disconnect is pending */
+    uint8_t         rs_disc_pending;
+#endif
+#define BTM_SEC_NO_LAST_SERVICE_ID      0
+    uint8_t         last_author_service_id;         /* ID of last serviced authorized: Reset after each l2cap connection */
+
+} tBTM_SEC_DEV_REC;
+
+#define BTM_SEC_IS_SM4(sm) ((bool   )(BTM_SM4_TRUE == ((sm)&BTM_SM4_TRUE)))
+#define BTM_SEC_IS_SM4_LEGACY(sm) ((bool   )(BTM_SM4_KNOWN == ((sm)&BTM_SM4_TRUE)))
+#define BTM_SEC_IS_SM4_UNKNOWN(sm) ((bool   )(BTM_SM4_UNKNOWN == ((sm)&BTM_SM4_TRUE)))
+
+#define BTM_SEC_LE_MASK    (BTM_SEC_LE_AUTHENTICATED|BTM_SEC_LE_ENCRYPTED|BTM_SEC_LE_LINK_KEY_KNOWN|BTM_SEC_LE_LINK_KEY_AUTHED)
+
+/*
+** Define device configuration structure
+*/
+typedef struct
+{
+    tBTM_LOC_BD_NAME bd_name;                    /* local Bluetooth device name */
+    bool             pin_type;                   /* true if PIN type is fixed */
+    uint8_t          pin_code_len;               /* Bonding information */
+    PIN_CODE         pin_code;                   /* PIN CODE if pin type is fixed */
+    bool             connectable;                /* If true page scan should be enabled */
+    uint8_t          def_inq_scan_mode;          /* ??? limited/general/none */
+} tBTM_CFG;
+
+enum
+{
+    BTM_PM_ST_ACTIVE  = BTM_PM_STS_ACTIVE,
+    BTM_PM_ST_HOLD    = BTM_PM_STS_HOLD,
+    BTM_PM_ST_SNIFF   = BTM_PM_STS_SNIFF,
+    BTM_PM_ST_PARK    = BTM_PM_STS_PARK,
+    BTM_PM_ST_PENDING = BTM_PM_STS_PENDING,
+    BTM_PM_ST_INVALID = 0xFF
+};
+typedef uint8_t tBTM_PM_STATE;
+
+enum
+{
+    BTM_PM_SET_MODE_EVT,    /* Set power mode API is called. */
+    BTM_PM_UPDATE_EVT,
+    BTM_PM_RD_MODE_EVT     /* Read power mode API is called. */
+};
+typedef uint8_t tBTM_PM_EVENT;
+
+typedef struct
+{
+    uint16_t        event;
+    uint16_t        len;
+    uint8_t         link_ind;
+} tBTM_PM_MSG_DATA;
+
+typedef struct
+{
+    uint8_t hci_status;
+    uint8_t mode;
+    uint16_t interval;
+} tBTM_PM_MD_CHG_DATA;
+
+typedef struct
+{
+    uint8_t        pm_id;      /* the entity that calls SetPowerMode API */
+    tBTM_PM_PWR_MD *p_pmd;
+} tBTM_PM_SET_MD_DATA;
+
+typedef struct
+{
+    void        *p_data;
+    uint8_t      link_ind;
+} tBTM_PM_SM_DATA;
+
+typedef struct
+{
+    tBTM_PM_PWR_MD req_mode[BTM_MAX_PM_RECORDS+1]; /* the desired mode and parameters of the connection*/
+    tBTM_PM_PWR_MD set_mode;  /* the mode and parameters sent down to the host controller. */
+    uint16_t       interval;  /* the interval from last mode change event. */
+#if (BTM_SSR_INCLUDED == TRUE)
+    uint16_t       max_lat;   /* stored SSR maximum latency */
+    uint16_t       min_rmt_to;/* stored SSR minimum remote timeout */
+    uint16_t       min_loc_to;/* stored SSR minimum local timeout */
+#endif
+    tBTM_PM_STATE  state;     /* contains the current mode of the connection */
+    bool           chg_ind;   /* a request change indication */
+} tBTM_PM_MCB;
+
+#define BTM_PM_REC_NOT_USED 0
+typedef struct
+{
+    tBTM_PM_STATUS_CBACK *cback;/* to notify the registered party of mode change event */
+    uint8_t               mask; /* registered request mask. 0, if this entry is not used */
+} tBTM_PM_RCB;
+
+enum
+{
+    BTM_BLI_ACL_UP_EVT,
+    BTM_BLI_ACL_DOWN_EVT,
+    BTM_BLI_PAGE_EVT,
+    BTM_BLI_PAGE_DONE_EVT,
+    BTM_BLI_INQ_EVT,
+    BTM_BLI_INQ_CANCEL_EVT,
+    BTM_BLI_INQ_DONE_EVT
+};
+typedef uint8_t tBTM_BLI_EVENT;
+
+/* Pairing State */
+enum
+{
+    BTM_PAIR_STATE_IDLE,                        /* Idle                                         */
+    BTM_PAIR_STATE_GET_REM_NAME,                /* Getting the remote name (to check for SM4)   */
+    BTM_PAIR_STATE_WAIT_PIN_REQ,                /* Started authentication, waiting for PIN req (PIN is pre-fetched) */
+    BTM_PAIR_STATE_WAIT_LOCAL_PIN,              /* Waiting for local PIN code                   */
+    BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM,        /* Waiting user 'yes' to numeric confirmation   */
+    BTM_PAIR_STATE_KEY_ENTRY,                   /* Key entry state (we are a keyboard)          */
+    BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP,          /* Waiting for local response to peer OOB data  */
+    BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS,           /* Waiting for local IO capabilities and OOB data */
+    BTM_PAIR_STATE_INCOMING_SSP,                /* Incoming SSP (got peer IO caps when idle)    */
+    BTM_PAIR_STATE_WAIT_AUTH_COMPLETE,          /* All done, waiting authentication cpmplete    */
+    BTM_PAIR_STATE_WAIT_DISCONNECT              /* Waiting to disconnect the ACL                */
+};
+typedef uint8_t tBTM_PAIRING_STATE;
+
+#define BTM_PAIR_FLAGS_WE_STARTED_DD    0x01    /* We want to do dedicated bonding              */
+#define BTM_PAIR_FLAGS_PEER_STARTED_DD  0x02    /* Peer initiated dedicated bonding             */
+#define BTM_PAIR_FLAGS_DISC_WHEN_DONE   0x04    /* Disconnect when done     */
+#define BTM_PAIR_FLAGS_PIN_REQD         0x08    /* set this bit when pin_callback is called     */
+#define BTM_PAIR_FLAGS_PRE_FETCH_PIN    0x10    /* set this bit when pre-fetch pin     */
+#define BTM_PAIR_FLAGS_REJECTED_CONNECT 0x20    /* set this bit when rejected incoming connection  */
+#define BTM_PAIR_FLAGS_WE_CANCEL_DD     0x40    /* set this bit when cancelling a bonding procedure */
+#define BTM_PAIR_FLAGS_LE_ACTIVE        0x80    /* use this bit when SMP pairing is active */
+
+
+typedef struct
+{
+    bool                is_mux;
+    BD_ADDR             bd_addr;
+    uint16_t            psm;
+    bool                is_orig;
+    tBTM_SEC_CALLBACK   *p_callback;
+    void                *p_ref_data;
+    uint32_t            mx_proto_id;
+    uint32_t            mx_chan_id;
+    tBT_TRANSPORT       transport;
+    tBTM_BLE_SEC_ACT    sec_act;
+} tBTM_SEC_QUEUE_ENTRY;
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+
+#define CONN_ORIENT_TERM                0x00    /* incoming connection oriented */
+#define CONN_ORIENT_ORIG                0x01    /* outgoing connection oriented */
+#define CONNLESS_TERM                   0x02    /* incoming connectionless      */
+#define CONNLESS_ORIG                   0x03    /* outgoing connectionless      */
+#define CONNECTION_TYPE_ORIG_MASK       0x01    /* mask for direction           */
+#define CONNECTION_TYPE_CONNLESS_MASK   0x02    /* mask for connectionless or not */
+typedef uint8_t CONNECTION_TYPE;
+
+#else
+
+#define CONN_ORIENT_TERM                false
+#define CONN_ORIENT_ORIG                true
+typedef bool    CONNECTION_TYPE;
+
+#endif /* (L2CAP_UCD_INCLUDED == TRUE) */
+
+/* Define a structure to hold all the BTM data
+*/
+
+#define BTM_STATE_BUFFER_SIZE  5                  /* size of state buffer */
+
+typedef struct
+{
+    tBTM_CFG    cfg;                        /* Device configuration */
+
+    /****************************************************
+    **      ACL Management
+    ****************************************************/
+    tACL_CONN   acl_db[MAX_L2CAP_LINKS];
+    uint8_t     btm_scn[BTM_MAX_SCN];        /* current SCNs: true if SCN is in use */
+    uint16_t    btm_def_link_policy;
+    uint16_t    btm_def_link_super_tout;
+
+    tBTM_BL_EVENT_MASK     bl_evt_mask;
+    tBTM_BL_CHANGE_CB     *p_bl_changed_cb;    /* Callback for when Busy Level changed */
+
+    /****************************************************
+    **      Power Management
+    ****************************************************/
+    tBTM_PM_MCB pm_mode_db[MAX_L2CAP_LINKS];   /* per ACL link */
+    tBTM_PM_RCB pm_reg_db[BTM_MAX_PM_RECORDS+1]; /* per application/module */
+    uint8_t     pm_pend_link;  /* the index of acl_db, which has a pending PM cmd */
+    uint8_t     pm_pend_id;    /* the id pf the module, which has a pending PM cmd */
+
+    /*****************************************************
+    **      Device control
+    *****************************************************/
+    tBTM_DEVCB  devcb;
+
+    /*****************************************************
+    **      BLE Device controllers
+    *****************************************************/
+#if (BLE_INCLUDED == TRUE)
+    tBTM_BLE_CB             ble_ctr_cb;
+
+    uint16_t                enc_handle;
+    BT_OCTET8               enc_rand;   /* received rand value from LTK request*/
+    uint16_t                ediv;       /* received ediv value from LTK request */
+    uint8_t                 key_size;
+    tBTM_BLE_VSC_CB         cmn_ble_vsc_cb;
+#endif
+
+                                            /* Packet types supported by the local device */
+    uint16_t    btm_acl_pkt_types_supported;
+    uint16_t    btm_sco_pkt_types_supported;
+
+
+    /*****************************************************
+    **      Inquiry
+    *****************************************************/
+    tBTM_INQUIRY_VAR_ST     btm_inq_vars;
+
+    /*****************************************************
+    **      SCO Management
+    *****************************************************/
+#if (BTM_SCO_INCLUDED == TRUE)
+    tSCO_CB             sco_cb;
+#endif
+
+    /*****************************************************
+    **      Security Management
+    *****************************************************/
+    tBTM_APPL_INFO          api;
+
+#define BTM_SEC_MAX_RMT_NAME_CALLBACKS  2
+    tBTM_RMT_NAME_CALLBACK  *p_rmt_name_callback[BTM_SEC_MAX_RMT_NAME_CALLBACKS];
+
+    tBTM_SEC_DEV_REC        *p_collided_dev_rec;
+    alarm_t                 *sec_collision_timer;
+    uint32_t                 collision_start_time;
+    uint32_t                 max_collision_delay;
+    uint32_t                 dev_rec_count;      /* Counter used for device record timestamp */
+    uint8_t                  security_mode;
+    bool                     pairing_disabled;
+    bool                     connect_only_paired;
+    bool                     security_mode_changed;  /* mode changed during bonding */
+    bool                     pin_type_changed;       /* pin type changed during bonding */
+    bool                     sec_req_pending;       /*   true if a request is pending */
+
+    uint8_t                  pin_code_len;  /* for legacy devices */
+    PIN_CODE                 pin_code;      /* for legacy devices */
+    tBTM_PAIRING_STATE       pairing_state; /* The current pairing state    */
+    uint8_t                  pairing_flags; /* The current pairing flags    */
+    BD_ADDR                  pairing_bda;   /* The device currently pairing */
+    alarm_t                 *pairing_timer; /* Timer for pairing process    */
+    uint16_t                 disc_handle;   /* for legacy devices */
+    uint8_t                  disc_reason;   /* for legacy devices */
+    tBTM_SEC_SERV_REC        sec_serv_rec[BTM_SEC_MAX_SERVICE_RECORDS];
+    list_t                  *sec_dev_rec;   /* list of tBTM_SEC_DEV_REC */
+    tBTM_SEC_SERV_REC       *p_out_serv;
+    tBTM_MKEY_CALLBACK      *mkey_cback;
+
+    BD_ADDR                  connecting_bda;
+    DEV_CLASS                connecting_dc;
+
+    uint8_t                 acl_disc_reason;
+    uint8_t                 trace_level;
+    uint8_t                 busy_level; /* the current busy level */
+    bool                    is_paging;  /* true, if paging is in progess */
+    bool                    is_inquiry; /* true, if inquiry is in progess */
+    fixed_queue_t          *page_queue;
+    bool                    paging;
+    bool                    discing;
+    fixed_queue_t          *sec_pending_q;  /* pending sequrity requests in tBTM_SEC_QUEUE_ENTRY format */
+
+#if (BT_TRACE_VERBOSE == FALSE)
+    char state_temp_buffer[BTM_STATE_BUFFER_SIZE];
+#endif
+} tBTM_CB;
+
+/* security action for L2CAP COC channels */
+#define BTM_SEC_OK                1
+#define BTM_SEC_ENCRYPT           2    /* encrypt the link with current key */
+#define BTM_SEC_ENCRYPT_NO_MITM   3    /* unauthenticated encryption or better */
+#define BTM_SEC_ENCRYPT_MITM      4    /* authenticated encryption */
+#define BTM_SEC_ENC_PENDING       5    /* wait for link encryption pending */
+
+typedef uint8_t tBTM_SEC_ACTION;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BTM_INT_TYPES_H
\ No newline at end of file
diff --git a/bt/stack/btm/btm_main.cc b/bt/stack/btm/btm_main.cc
new file mode 100644
index 0000000..7430e2a
--- /dev/null
+++ b/bt/stack/btm/btm_main.cc
@@ -0,0 +1,78 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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 definition of the btm control block.
+ *
+ ******************************************************************************/
+
+#include "bt_types.h"
+#include "bt_target.h"
+#include <string.h>
+#include "btm_int.h"
+#include "stack_config.h"
+
+/* Global BTM control block structure
+*/
+tBTM_CB  btm_cb;
+
+/*******************************************************************************
+**
+** Function         btm_init
+**
+** Description      This function is called at BTM startup to allocate the
+**                  control block (if using dynamic memory), and initializes the
+**                  tracing level.  It then initializes the various components of
+**                  btm.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_init (void)
+{
+    /* All fields are cleared; nonzero fields are reinitialized in appropriate function */
+    memset(&btm_cb, 0, sizeof(tBTM_CB));
+    btm_cb.page_queue = fixed_queue_new(SIZE_MAX);
+    btm_cb.sec_pending_q = fixed_queue_new(SIZE_MAX);
+    btm_cb.sec_collision_timer = alarm_new("btm.sec_collision_timer");
+    btm_cb.pairing_timer = alarm_new("btm.pairing_timer");
+
+#if defined(BTM_INITIAL_TRACE_LEVEL)
+    btm_cb.trace_level = BTM_INITIAL_TRACE_LEVEL;
+#else
+    btm_cb.trace_level = BT_TRACE_LEVEL_NONE;    /* No traces */
+#endif
+    /* Initialize BTM component structures */
+    btm_inq_db_init();                  /* Inquiry Database and Structures */
+    btm_acl_init();                     /* ACL Database and Structures */
+    /* Security Manager Database and Structures */
+    if (stack_config_get_interface()->get_pts_secure_only_mode())
+        btm_sec_init(BTM_SEC_MODE_SC);
+    else
+        btm_sec_init(BTM_SEC_MODE_SP);
+#if (BTM_SCO_INCLUDED == TRUE)
+    btm_sco_init();                     /* SCO Database and Structures (If included) */
+#endif
+
+    btm_cb.sec_dev_rec = list_new(osi_free);
+
+    btm_dev_init();                     /* Device Manager Structures & HCI_Reset */
+}
+
+
diff --git a/bt/stack/btm/btm_pm.cc b/bt/stack/btm/btm_pm.cc
new file mode 100644
index 0000000..312baf6
--- /dev/null
+++ b/bt/stack/btm/btm_pm.cc
@@ -0,0 +1,1028 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2000-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 functions that manages ACL link modes.
+ *  This includes operations such as active, hold,
+ *  park and sniff modes.
+ *
+ *  This module contains both internal and external (API)
+ *  functions. External (API) functions are distinguishable
+ *  by their names beginning with uppercase BTM.
+ *
+ *****************************************************************************/
+
+#define LOG_TAG "bt_btm_pm"
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "bt_common.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+/*****************************************************************************/
+/*      to handle different modes                                            */
+/*****************************************************************************/
+#define BTM_PM_STORED_MASK      0x80 /* set this mask if the command is stored */
+#define BTM_PM_NUM_SET_MODES    3 /* only hold, sniff & park */
+
+/* Usage:  (ptr_features[ offset ] & mask )?true:false */
+/* offset to supported feature */
+const uint8_t btm_pm_mode_off[BTM_PM_NUM_SET_MODES] = {0,    0,    1};
+/* mask to supported feature */
+const uint8_t btm_pm_mode_msk[BTM_PM_NUM_SET_MODES] = {0x40, 0x80, 0x01};
+
+#define BTM_PM_GET_MD1      1
+#define BTM_PM_GET_MD2      2
+#define BTM_PM_GET_COMP     3
+
+const uint8_t btm_pm_md_comp_matrix[BTM_PM_NUM_SET_MODES*BTM_PM_NUM_SET_MODES] =
+{
+    BTM_PM_GET_COMP,
+    BTM_PM_GET_MD2,
+    BTM_PM_GET_MD2,
+
+    BTM_PM_GET_MD1,
+    BTM_PM_GET_COMP,
+    BTM_PM_GET_MD1,
+
+    BTM_PM_GET_MD1,
+    BTM_PM_GET_MD2,
+    BTM_PM_GET_COMP
+};
+
+/* function prototype */
+static int btm_pm_find_acl_ind(BD_ADDR remote_bda);
+static tBTM_STATUS btm_pm_snd_md_req( uint8_t pm_id, int link_ind, tBTM_PM_PWR_MD *p_mode );
+static const char *mode_to_string(tBTM_PM_MODE mode);
+
+/*
+#ifdef BTM_PM_DEBUG
+#undef BTM_PM_DEBUG
+#define BTM_PM_DEBUG    true
+#endif
+*/
+
+#if (BTM_PM_DEBUG == TRUE)
+const char * btm_pm_state_str[] =
+{
+    "pm_active_state",
+    "pm_hold_state",
+    "pm_sniff_state",
+    "pm_park_state",
+    "pm_pend_state"
+};
+
+const char * btm_pm_event_str[] =
+{
+    "pm_set_mode_event",
+    "pm_hci_sts_event",
+    "pm_mod_chg_event",
+    "pm_update_event"
+};
+
+const char * btm_pm_action_str[] =
+{
+    "pm_set_mode_action",
+    "pm_update_db_action",
+    "pm_mod_chg_action",
+    "pm_hci_sts_action",
+    "pm_update_action"
+};
+#endif  // BTM_PM_DEBUG
+
+/*****************************************************************************/
+/*                     P U B L I C  F U N C T I O N S                        */
+/*****************************************************************************/
+/*******************************************************************************
+**
+** 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)
+{
+    int xx;
+
+    /* de-register */
+    if(mask & BTM_PM_DEREG)
+    {
+        if(*p_pm_id >= BTM_MAX_PM_RECORDS)
+            return BTM_ILLEGAL_VALUE;
+        btm_cb.pm_reg_db[*p_pm_id].mask = BTM_PM_REC_NOT_USED;
+        return BTM_SUCCESS;
+    }
+
+    for(xx=0; xx<BTM_MAX_PM_RECORDS; xx++)
+    {
+        /* find an unused entry */
+        if(btm_cb.pm_reg_db[xx].mask == BTM_PM_REC_NOT_USED)
+        {
+            /* if register for notification, should provide callback routine */
+            if(mask & BTM_PM_REG_NOTIF)
+            {
+                if(p_cb == NULL)
+                    return BTM_ILLEGAL_VALUE;
+                btm_cb.pm_reg_db[xx].cback = p_cb;
+            }
+            btm_cb.pm_reg_db[xx].mask = mask;
+            *p_pm_id = xx;
+            return BTM_SUCCESS;
+        }
+    }
+
+    return BTM_NO_RESOURCES;
+}
+
+/*******************************************************************************
+**
+** 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, BD_ADDR remote_bda, tBTM_PM_PWR_MD *p_mode)
+{
+    uint8_t             *p_features;
+    int               ind, acl_ind;
+    tBTM_PM_MCB *p_cb = NULL;   /* per ACL link */
+    tBTM_PM_MODE        mode;
+    int                 temp_pm_id;
+
+    if(pm_id >= BTM_MAX_PM_RECORDS)
+        pm_id = BTM_PM_SET_ONLY_ID;
+
+    if(p_mode == NULL)
+        return BTM_ILLEGAL_VALUE;
+
+    BTM_TRACE_API( "BTM_SetPowerMode: pm_id %d BDA: %08x mode:0x%x", pm_id,
+                   (remote_bda[2]<<24)+(remote_bda[3]<<16)+(remote_bda[4]<<8)+remote_bda[5], p_mode->mode);
+
+    /* take out the force bit */
+    mode = p_mode->mode & ~BTM_PM_MD_FORCE;
+
+    acl_ind = btm_pm_find_acl_ind(remote_bda);
+    if(acl_ind == MAX_L2CAP_LINKS)
+        return (BTM_UNKNOWN_ADDR);
+
+    p_cb = &(btm_cb.pm_mode_db[acl_ind]);
+
+    if(mode != BTM_PM_MD_ACTIVE)
+    {
+        /* check if the requested mode is supported */
+        ind = mode - BTM_PM_MD_HOLD; /* make it base 0 */
+        p_features = BTM_ReadLocalFeatures();
+        if( !(p_features[ btm_pm_mode_off[ind] ] & btm_pm_mode_msk[ind] ) )
+            return BTM_MODE_UNSUPPORTED;
+    }
+
+    if(mode == p_cb->state) /* the requested mode is current mode */
+    {
+        /* already in the requested mode and the current interval has less latency than the max */
+        if( (mode == BTM_PM_MD_ACTIVE) ||
+            ((p_mode->mode & BTM_PM_MD_FORCE) && (p_mode->max >= p_cb->interval) && (p_mode->min <= p_cb->interval)) ||
+            ((p_mode->mode & BTM_PM_MD_FORCE)==0 && (p_mode->max >= p_cb->interval)) )
+        {
+            BTM_TRACE_DEBUG( "BTM_SetPowerMode: mode:0x%x interval %d max:%d, min:%d", p_mode->mode, p_cb->interval, p_mode->max, p_mode->min);
+            return BTM_SUCCESS;
+        }
+    }
+
+    temp_pm_id = pm_id;
+    if(pm_id == BTM_PM_SET_ONLY_ID)
+        temp_pm_id = BTM_MAX_PM_RECORDS;
+
+    /* update mode database */
+    if( ((pm_id != BTM_PM_SET_ONLY_ID) &&
+         (btm_cb.pm_reg_db[pm_id].mask & BTM_PM_REG_SET))
+       || ((pm_id == BTM_PM_SET_ONLY_ID) && (btm_cb.pm_pend_link != MAX_L2CAP_LINKS)) )
+    {
+#if (BTM_PM_DEBUG == TRUE)
+    BTM_TRACE_DEBUG( "BTM_SetPowerMode: Saving cmd acl_ind %d temp_pm_id %d", acl_ind,temp_pm_id);
+#endif  // BTM_PM_DEBUG
+        /* Make sure mask is set to BTM_PM_REG_SET */
+        btm_cb.pm_reg_db[temp_pm_id].mask |= BTM_PM_REG_SET;
+        *(&p_cb->req_mode[temp_pm_id]) = *((tBTM_PM_PWR_MD *)p_mode);
+        p_cb->chg_ind = true;
+    }
+
+#if (BTM_PM_DEBUG == TRUE)
+    BTM_TRACE_DEBUG( "btm_pm state:0x%x, pm_pend_link: %d", p_cb->state, btm_cb.pm_pend_link);
+#endif  // BTM_PM_DEBUG
+    /* if mode == hold or pending, return */
+    if( (p_cb->state == BTM_PM_STS_HOLD) ||
+        (p_cb->state ==  BTM_PM_STS_PENDING) ||
+        (btm_cb.pm_pend_link != MAX_L2CAP_LINKS) ) /* command pending */
+    {
+        if(acl_ind != btm_cb.pm_pend_link)
+        {
+            /* set the stored mask */
+            p_cb->state |= BTM_PM_STORED_MASK;
+            BTM_TRACE_DEBUG( "btm_pm state stored:%d",acl_ind);
+        }
+        return BTM_CMD_STORED;
+    }
+
+    return btm_pm_snd_md_req(pm_id, acl_ind, 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 (BD_ADDR remote_bda, tBTM_PM_MODE *p_mode)
+{
+    int acl_ind;
+
+    if( (acl_ind = btm_pm_find_acl_ind(remote_bda)) == MAX_L2CAP_LINKS)
+        return (BTM_UNKNOWN_ADDR);
+
+    *p_mode = btm_cb.pm_mode_db[acl_ind].state;
+    return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         btm_read_power_mode_state
+**
+** Description      This returns the current pm state for a specific
+**                  ACL connection.
+**
+** Input Param      remote_bda - device address of desired ACL connection
+**
+** Output Param     pmState - address where the current  pm state is copied into.
+**                          BTM_PM_ST_ACTIVE
+**                          BTM_PM_ST_HOLD
+**                          BTM_PM_ST_SNIFF
+**                          BTM_PM_ST_PARK
+**                          BTM_PM_ST_PENDING
+**                          (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_read_power_mode_state (BD_ADDR remote_bda, tBTM_PM_STATE *pmState)
+{
+    int acl_ind = btm_pm_find_acl_ind(remote_bda);
+
+    if( acl_ind == MAX_L2CAP_LINKS)
+        return (BTM_UNKNOWN_ADDR);
+
+    *pmState = btm_cb.pm_mode_db[acl_ind].state;
+    return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** 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 (BD_ADDR remote_bda, uint16_t max_lat,
+                              uint16_t min_rmt_to, uint16_t min_loc_to)
+{
+#if (BTM_SSR_INCLUDED == TRUE)
+    int acl_ind;
+    tBTM_PM_MCB *p_cb;
+
+    if( (acl_ind = btm_pm_find_acl_ind(remote_bda)) == MAX_L2CAP_LINKS)
+        return (BTM_UNKNOWN_ADDR);
+
+    if(BTM_PM_STS_ACTIVE == btm_cb.pm_mode_db[acl_ind].state ||
+        BTM_PM_STS_SNIFF == btm_cb.pm_mode_db[acl_ind].state)
+    {
+        btsnd_hcic_sniff_sub_rate(btm_cb.acl_db[acl_ind].hci_handle, max_lat,
+                                  min_rmt_to, min_loc_to);
+        return BTM_SUCCESS;
+    }
+    p_cb = &btm_cb.pm_mode_db[acl_ind];
+    p_cb->max_lat       = max_lat;
+    p_cb->min_rmt_to    = min_rmt_to;
+    p_cb->min_loc_to    = min_loc_to;
+    return BTM_CMD_STORED;
+#else
+    return BTM_ILLEGAL_ACTION;
+#endif  // BTM_SSR_INCLUDED
+}
+
+/*******************************************************************************
+**
+** Function         btm_pm_reset
+**
+** Description      as a part of the BTM reset process.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_pm_reset(void)
+{
+    int xx;
+    tBTM_PM_STATUS_CBACK *cb = NULL;
+
+    /* clear the pending request for application */
+    if( (btm_cb.pm_pend_id != BTM_PM_SET_ONLY_ID) &&
+        (btm_cb.pm_reg_db[btm_cb.pm_pend_id].mask & BTM_PM_REG_NOTIF) )
+    {
+        cb = btm_cb.pm_reg_db[btm_cb.pm_pend_id].cback;
+    }
+
+    /* clear the register record */
+    for(xx=0; xx<BTM_MAX_PM_RECORDS; xx++)
+    {
+        btm_cb.pm_reg_db[xx].mask = BTM_PM_REC_NOT_USED;
+    }
+
+    if(cb != NULL && btm_cb.pm_pend_link < MAX_L2CAP_LINKS)
+        (*cb)(btm_cb.acl_db[btm_cb.pm_pend_link].remote_addr, BTM_PM_STS_ERROR, BTM_DEV_RESET, 0);
+
+    /* no command pending */
+    btm_cb.pm_pend_link = MAX_L2CAP_LINKS;
+}
+
+/*******************************************************************************
+**
+** Function         btm_pm_sm_alloc
+**
+** Description      This function initializes the control block of an ACL link.
+**                  It is called when an ACL connection is created.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_pm_sm_alloc(uint8_t ind)
+{
+    tBTM_PM_MCB *p_db = &btm_cb.pm_mode_db[ind];   /* per ACL link */
+    memset (p_db, 0, sizeof(tBTM_PM_MCB));
+    p_db->state = BTM_PM_ST_ACTIVE;
+#if (BTM_PM_DEBUG == TRUE)
+    BTM_TRACE_DEBUG( "btm_pm_sm_alloc ind:%d st:%d", ind, p_db->state);
+#endif  // BTM_PM_DEBUG
+}
+
+/*******************************************************************************
+**
+** Function         btm_pm_find_acl_ind
+**
+** Description      This function initializes the control block of an ACL link.
+**                  It is called when an ACL connection is created.
+**
+** Returns          void
+**
+*******************************************************************************/
+static int btm_pm_find_acl_ind(BD_ADDR remote_bda)
+{
+    tACL_CONN   *p = &btm_cb.acl_db[0];
+    uint8_t xx;
+
+    for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++)
+    {
+        if ((p->in_use) && (!memcmp (p->remote_addr, remote_bda, BD_ADDR_LEN))
+#if (BLE_INCLUDED == TRUE)
+            && p->transport == BT_TRANSPORT_BR_EDR
+#endif  // BLE_INCLUDED
+            )
+        {
+#if (BTM_PM_DEBUG == TRUE)
+            BTM_TRACE_DEBUG( "btm_pm_find_acl_ind ind:%d, st:%d", xx, btm_cb.pm_mode_db[xx].state);
+#endif  // BTM_PM_DEBUG
+            break;
+        }
+    }
+    return xx;
+}
+
+/*******************************************************************************
+**
+** Function     btm_pm_compare_modes
+** Description  get the "more active" mode of the 2
+** Returns      void
+**
+*******************************************************************************/
+static tBTM_PM_PWR_MD * btm_pm_compare_modes(tBTM_PM_PWR_MD *p_md1, tBTM_PM_PWR_MD *p_md2, tBTM_PM_PWR_MD *p_res)
+{
+    uint8_t res;
+
+    if(p_md1 == NULL)
+    {
+        *p_res = *p_md2;
+        p_res->mode &= ~BTM_PM_MD_FORCE;
+
+        return p_md2;
+    }
+
+    if(p_md2->mode == BTM_PM_MD_ACTIVE || p_md1->mode == BTM_PM_MD_ACTIVE)
+    {
+        return NULL;
+    }
+
+    /* check if force bit is involved */
+    if(p_md1->mode & BTM_PM_MD_FORCE)
+    {
+        *p_res = *p_md1;
+        p_res->mode &= ~BTM_PM_MD_FORCE;
+        return p_res;
+    }
+
+    if(p_md2->mode & BTM_PM_MD_FORCE)
+    {
+        *p_res = *p_md2;
+        p_res->mode &= ~BTM_PM_MD_FORCE;
+        return p_res;
+    }
+
+    res = (p_md1->mode - 1) * BTM_PM_NUM_SET_MODES + (p_md2->mode - 1);
+    res = btm_pm_md_comp_matrix[res];
+    switch(res)
+    {
+    case BTM_PM_GET_MD1:
+        *p_res = *p_md1;
+        return p_md1;
+
+    case BTM_PM_GET_MD2:
+        *p_res = *p_md2;
+        return p_md2;
+
+    case BTM_PM_GET_COMP:
+        p_res->mode = p_md1->mode;
+        /* min of the two */
+        p_res->max  = (p_md1->max < p_md2->max)? (p_md1->max) : (p_md2->max);
+        /* max of the two */
+        p_res->min  = (p_md1->min > p_md2->min)? (p_md1->min) : (p_md2->min);
+
+        /* the intersection is NULL */
+        if( p_res->max < p_res->min)
+            return NULL;
+
+        if(p_res->mode == BTM_PM_MD_SNIFF)
+        {
+            /* max of the two */
+            p_res->attempt  = (p_md1->attempt > p_md2->attempt)? (p_md1->attempt) : (p_md2->attempt);
+            p_res->timeout  = (p_md1->timeout > p_md2->timeout)? (p_md1->timeout) : (p_md2->timeout);
+        }
+        return p_res;
+    }
+    return NULL;
+}
+
+/*******************************************************************************
+**
+** Function     btm_pm_get_set_mode
+** Description  get the resulting mode from the registered parties, then compare it
+**              with the requested mode, if the command is from an unregistered party.
+** Returns      void
+**
+*******************************************************************************/
+static tBTM_PM_MODE btm_pm_get_set_mode(uint8_t pm_id, tBTM_PM_MCB *p_cb, tBTM_PM_PWR_MD *p_mode, tBTM_PM_PWR_MD *p_res)
+{
+    int   xx, loop_max;
+    tBTM_PM_PWR_MD *p_md = NULL;
+
+    if(p_mode != NULL && p_mode->mode & BTM_PM_MD_FORCE)
+    {
+        *p_res = *p_mode;
+        p_res->mode &= ~BTM_PM_MD_FORCE;
+        return p_res->mode;
+    }
+
+    if(!p_mode)
+        loop_max = BTM_MAX_PM_RECORDS+1;
+    else
+        loop_max = BTM_MAX_PM_RECORDS;
+
+    for( xx=0; xx<loop_max; xx++)
+    {
+        /* g through all the registered "set" parties */
+        if(btm_cb.pm_reg_db[xx].mask & BTM_PM_REG_SET)
+        {
+            if(p_cb->req_mode[xx].mode == BTM_PM_MD_ACTIVE)
+            {
+                /* if at least one registered (SET) party says ACTIVE, stay active */
+                return BTM_PM_MD_ACTIVE;
+            }
+            else
+            {
+                /* if registered parties give conflicting information, stay active */
+                if( (btm_pm_compare_modes(p_md, &p_cb->req_mode[xx], p_res)) == NULL)
+                    return BTM_PM_MD_ACTIVE;
+                p_md = p_res;
+            }
+        }
+    }
+
+    /* if the resulting mode is NULL(nobody registers SET), use the requested mode */
+    if(p_md == NULL)
+    {
+        if(p_mode)
+            *p_res = *((tBTM_PM_PWR_MD *)p_mode);
+        else /* p_mode is NULL when btm_pm_snd_md_req is called from btm_pm_proc_mode_change */
+            return BTM_PM_MD_ACTIVE;
+    }
+    else
+    {
+        /* if the command is from unregistered party,
+           compare the resulting mode from registered party*/
+        if( (pm_id == BTM_PM_SET_ONLY_ID) &&
+            ((btm_pm_compare_modes(p_mode, p_md, p_res)) == NULL) )
+            return BTM_PM_MD_ACTIVE;
+    }
+
+    return p_res->mode;
+}
+
+/*******************************************************************************
+**
+** Function     btm_pm_snd_md_req
+** Description  get the resulting mode and send the resuest to host controller
+** Returns      tBTM_STATUS
+**, bool    *p_chg_ind
+*******************************************************************************/
+static tBTM_STATUS btm_pm_snd_md_req(uint8_t pm_id, int link_ind, tBTM_PM_PWR_MD *p_mode)
+{
+    tBTM_PM_PWR_MD  md_res;
+    tBTM_PM_MODE    mode;
+    tBTM_PM_MCB *p_cb = &btm_cb.pm_mode_db[link_ind];
+    bool         chg_ind = false;
+
+    mode = btm_pm_get_set_mode(pm_id, p_cb, p_mode, &md_res);
+    md_res.mode = mode;
+
+#if (BTM_PM_DEBUG == TRUE)
+    BTM_TRACE_DEBUG( "btm_pm_snd_md_req link_ind:%d, mode: %d",
+        link_ind, mode);
+#endif  // BTM_PM_DEBUG
+
+    if( p_cb->state == mode)
+    {
+        /* already in the resulting mode */
+        if( (mode == BTM_PM_MD_ACTIVE) ||
+            ((md_res.max >= p_cb->interval) && (md_res.min <= p_cb->interval)) )
+            return BTM_CMD_STORED;
+        /* Otherwise, needs to wake, then sleep */
+        chg_ind = true;
+    }
+    p_cb->chg_ind = chg_ind;
+
+     /* cannot go directly from current mode to resulting mode. */
+    if( mode != BTM_PM_MD_ACTIVE && p_cb->state != BTM_PM_MD_ACTIVE)
+        p_cb->chg_ind = true; /* needs to wake, then sleep */
+
+    if(p_cb->chg_ind == true) /* needs to wake first */
+        md_res.mode = BTM_PM_MD_ACTIVE;
+#if (BTM_SSR_INCLUDED == TRUE)
+    else if(BTM_PM_MD_SNIFF == md_res.mode && p_cb->max_lat)
+    {
+        btsnd_hcic_sniff_sub_rate(btm_cb.acl_db[link_ind].hci_handle, p_cb->max_lat,
+                                  p_cb->min_rmt_to, p_cb->min_loc_to);
+        p_cb->max_lat = 0;
+    }
+#endif  // BTM_SSR_INCLUDED
+    /* Default is failure */
+    btm_cb.pm_pend_link = MAX_L2CAP_LINKS;
+
+    /* send the appropriate HCI command */
+    btm_cb.pm_pend_id   = pm_id;
+
+#if (BTM_PM_DEBUG == TRUE)
+    BTM_TRACE_DEBUG("btm_pm_snd_md_req state:0x%x, link_ind: %d", p_cb->state, link_ind);
+#endif  // BTM_PM_DEBUG
+
+    BTM_TRACE_DEBUG("%s switching from %s to %s.", __func__,
+                    mode_to_string(p_cb->state), mode_to_string(md_res.mode));
+    switch(md_res.mode)
+    {
+    case BTM_PM_MD_ACTIVE:
+        switch(p_cb->state)
+        {
+        case BTM_PM_MD_SNIFF:
+            btsnd_hcic_exit_sniff_mode(btm_cb.acl_db[link_ind].hci_handle);
+            btm_cb.pm_pend_link = link_ind;
+            break;
+        case BTM_PM_MD_PARK:
+            btsnd_hcic_exit_park_mode(btm_cb.acl_db[link_ind].hci_handle);
+            btm_cb.pm_pend_link = link_ind;
+            break;
+        default:
+            /* Failure btm_cb.pm_pend_link = MAX_L2CAP_LINKS */
+            break;
+        }
+        break;
+
+    case BTM_PM_MD_HOLD:
+        btsnd_hcic_hold_mode(btm_cb.acl_db[link_ind].hci_handle,
+                             md_res.max, md_res.min);
+        btm_cb.pm_pend_link = link_ind;
+        break;
+
+    case BTM_PM_MD_SNIFF:
+        btsnd_hcic_sniff_mode(btm_cb.acl_db[link_ind].hci_handle,
+                              md_res.max, md_res.min, md_res.attempt,
+                              md_res.timeout);
+        btm_cb.pm_pend_link = link_ind;
+        break;
+
+    case BTM_PM_MD_PARK:
+        btsnd_hcic_park_mode(btm_cb.acl_db[link_ind].hci_handle,
+                             md_res.max, md_res.min);
+        btm_cb.pm_pend_link = link_ind;
+        break;
+    default:
+        /* Failure btm_cb.pm_pend_link = MAX_L2CAP_LINKS */
+        break;
+    }
+
+    if(btm_cb.pm_pend_link == MAX_L2CAP_LINKS)
+    {
+        /* the command was not sent */
+#if (BTM_PM_DEBUG == TRUE)
+        BTM_TRACE_DEBUG( "pm_pend_link: %d",btm_cb.pm_pend_link);
+#endif  // BTM_PM_DEBUG
+        return (BTM_NO_RESOURCES);
+    }
+
+    return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function         btm_pm_check_stored
+**
+** Description      This function is called when an HCI command status event occurs
+**                  to check if there's any PM command issued while waiting for
+**                  HCI command status.
+**
+** Returns          none.
+**
+*******************************************************************************/
+static void btm_pm_check_stored(void)
+{
+    int     xx;
+    for(xx=0; xx<MAX_L2CAP_LINKS; xx++)
+    {
+        if(btm_cb.pm_mode_db[xx].state & BTM_PM_STORED_MASK)
+        {
+            btm_cb.pm_mode_db[xx].state &= ~BTM_PM_STORED_MASK;
+            BTM_TRACE_DEBUG( "btm_pm_check_stored :%d", xx);
+            btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, xx, NULL);
+            break;
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_pm_proc_cmd_status
+**
+** Description      This function is called when an HCI command status event occurs
+**                  for power manager related commands.
+**
+** Input Parms      status - status of the event (HCI_SUCCESS if no errors)
+**
+** Returns          none.
+**
+*******************************************************************************/
+void btm_pm_proc_cmd_status(uint8_t status)
+{
+    tBTM_PM_MCB     *p_cb;
+    tBTM_PM_STATUS  pm_status;
+
+    if(btm_cb.pm_pend_link >= MAX_L2CAP_LINKS)
+        return;
+
+    p_cb = &btm_cb.pm_mode_db[btm_cb.pm_pend_link];
+
+    if(status == HCI_SUCCESS)
+    {
+        p_cb->state = BTM_PM_ST_PENDING;
+        pm_status = BTM_PM_STS_PENDING;
+#if (BTM_PM_DEBUG == TRUE)
+        BTM_TRACE_DEBUG( "btm_pm_proc_cmd_status new state:0x%x", p_cb->state);
+#endif // BTM_PM_DEBUG
+    }
+    else /* the command was not successfull. Stay in the same state */
+    {
+        pm_status = BTM_PM_STS_ERROR;
+    }
+
+    /* notify the caller is appropriate */
+    if( (btm_cb.pm_pend_id != BTM_PM_SET_ONLY_ID) &&
+        (btm_cb.pm_reg_db[btm_cb.pm_pend_id].mask & BTM_PM_REG_NOTIF) )
+    {
+        (*btm_cb.pm_reg_db[btm_cb.pm_pend_id].cback)(btm_cb.acl_db[btm_cb.pm_pend_link].remote_addr, pm_status, 0, status);
+    }
+
+    /* no pending cmd now */
+#if (BTM_PM_DEBUG == TRUE)
+    BTM_TRACE_DEBUG( "btm_pm_proc_cmd_status state:0x%x, pm_pend_link: %d(new: %d)",
+        p_cb->state, btm_cb.pm_pend_link, MAX_L2CAP_LINKS);
+#endif  // BTM_PM_DEBUG
+    btm_cb.pm_pend_link = MAX_L2CAP_LINKS;
+
+    btm_pm_check_stored();
+}
+
+/*******************************************************************************
+**
+** Function         btm_process_mode_change
+**
+** Description      This function is called when an HCI mode change event occurs.
+**
+** Input Parms      hci_status - status of the event (HCI_SUCCESS if no errors)
+**                  hci_handle - connection handle associated with the change
+**                  mode - HCI_MODE_ACTIVE, HCI_MODE_HOLD, HCI_MODE_SNIFF, or HCI_MODE_PARK
+**                  interval - number of baseband slots (meaning depends on mode)
+**
+** Returns          none.
+**
+*******************************************************************************/
+void btm_pm_proc_mode_change (uint8_t hci_status, uint16_t hci_handle, uint8_t mode, uint16_t interval)
+{
+    tACL_CONN   *p;
+    tBTM_PM_MCB *p_cb = NULL;
+    int xx, yy, zz;
+    tBTM_PM_STATE  old_state;
+    tL2C_LCB        *p_lcb;
+
+    /* get the index to acl_db */
+    if ((xx = btm_handle_to_acl_index(hci_handle)) >= MAX_L2CAP_LINKS)
+        return;
+
+    p = &btm_cb.acl_db[xx];
+
+    /* update control block */
+    p_cb = &(btm_cb.pm_mode_db[xx]);
+    old_state       = p_cb->state;
+    p_cb->state     = mode;
+    p_cb->interval  = interval;
+
+    BTM_TRACE_DEBUG("%s switched from %s to %s.", __func__,
+                    mode_to_string(old_state), mode_to_string(p_cb->state));
+
+    if ((p_lcb = l2cu_find_lcb_by_bd_addr(p->remote_addr, BT_TRANSPORT_BR_EDR)) != NULL)
+    {
+        if ((p_cb->state == BTM_PM_ST_ACTIVE) || (p_cb->state == BTM_PM_ST_SNIFF))
+        {
+            /* There might be any pending packets due to SNIFF or PENDING state */
+            /* Trigger L2C to start transmission of the pending packets. */
+            BTM_TRACE_DEBUG("btm mode change to active; check l2c_link for outgoing packets");
+            l2c_link_check_send_pkts(p_lcb, NULL, NULL);
+        }
+    }
+
+    /* notify registered parties */
+    for(yy=0; yy<=BTM_MAX_PM_RECORDS; yy++)
+    {
+        /* set req_mode  HOLD mode->ACTIVE */
+        if( (mode == BTM_PM_MD_ACTIVE) && (p_cb->req_mode[yy].mode == BTM_PM_MD_HOLD) )
+            p_cb->req_mode[yy].mode = BTM_PM_MD_ACTIVE;
+    }
+
+    /* new request has been made. - post a message to BTU task */
+    if(old_state & BTM_PM_STORED_MASK)
+    {
+#if (BTM_PM_DEBUG == TRUE)
+        BTM_TRACE_DEBUG( "btm_pm_proc_mode_change: Sending stored req:%d", xx);
+#endif  // BTM_PM_DEBUG
+        btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, xx, NULL);
+    }
+    else
+    {
+        for(zz=0; zz<MAX_L2CAP_LINKS; zz++)
+        {
+            if(btm_cb.pm_mode_db[zz].chg_ind == true)
+            {
+#if (BTM_PM_DEBUG == TRUE)
+                BTM_TRACE_DEBUG( "btm_pm_proc_mode_change: Sending PM req :%d", zz);
+#endif   // BTM_PM_DEBUG
+                btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, zz, NULL);
+                break;
+            }
+        }
+    }
+
+    /* notify registered parties */
+    for(yy=0; yy<BTM_MAX_PM_RECORDS; yy++)
+    {
+        if(btm_cb.pm_reg_db[yy].mask & BTM_PM_REG_NOTIF)
+        {
+            (*btm_cb.pm_reg_db[yy].cback)( p->remote_addr, mode, interval, hci_status);
+        }
+    }
+#if (BTM_SCO_INCLUDED == TRUE)
+    /*check if sco disconnect  is waiting for the mode change */
+    btm_sco_disc_chk_pend_for_modechange(hci_handle);
+#endif
+
+    /* If mode change was because of an active role switch or change link key */
+    btm_cont_rswitch(p, btm_find_dev(p->remote_addr), hci_status);
+}
+
+/*******************************************************************************
+**
+** Function         btm_pm_proc_ssr_evt
+**
+** Description      This function is called when an HCI sniff subrating event occurs.
+**
+** Returns          none.
+**
+*******************************************************************************/
+#if (BTM_SSR_INCLUDED == TRUE)
+void btm_pm_proc_ssr_evt (uint8_t *p,
+                          UNUSED_ATTR uint16_t evt_len)
+{
+    uint8_t     status;
+    uint16_t    handle;
+    uint16_t    max_rx_lat;
+    int         xx, yy;
+    tBTM_PM_MCB *p_cb;
+    tACL_CONN   *p_acl=NULL;
+    uint16_t    use_ssr = true;
+
+    STREAM_TO_UINT8 (status, p);
+
+    STREAM_TO_UINT16 (handle, p);
+    /* get the index to acl_db */
+    if ((xx = btm_handle_to_acl_index(handle)) >= MAX_L2CAP_LINKS)
+        return;
+
+    p += 2;
+    STREAM_TO_UINT16 (max_rx_lat, p);
+    p_cb = &(btm_cb.pm_mode_db[xx]);
+
+    p_acl = &btm_cb.acl_db[xx];
+    if(p_cb->interval == max_rx_lat)
+    {
+        /* using legacy sniff */
+        use_ssr = false;
+    }
+
+    /* notify registered parties */
+    for(yy=0; yy<BTM_MAX_PM_RECORDS; yy++)
+    {
+        if(btm_cb.pm_reg_db[yy].mask & BTM_PM_REG_NOTIF)
+        {
+            if( p_acl)
+            {
+                (*btm_cb.pm_reg_db[yy].cback)( p_acl->remote_addr, BTM_PM_STS_SSR, use_ssr, status);
+            }
+        }
+    }
+}
+#endif  // BTM_SSR_INCLUDED
+
+/*******************************************************************************
+**
+** Function         btm_pm_device_in_active_or_sniff_mode
+**
+** Description      This function is called to check if in active or sniff mode
+**
+** Returns          true, if in active or sniff mode
+**
+*******************************************************************************/
+bool    btm_pm_device_in_active_or_sniff_mode(void)
+{
+    /* The active state is the highest state-includes connected device and sniff mode*/
+
+    /* Covers active and sniff modes */
+    if (BTM_GetNumAclLinks() > 0)
+    {
+        BTM_TRACE_DEBUG("%s - ACL links: %d", __func__, BTM_GetNumAclLinks());
+        return true;
+    }
+
+#if (BLE_INCLUDED == TRUE)
+    /* Check BLE states */
+    if (btm_ble_get_conn_st() != BLE_CONN_IDLE)
+    {
+        BTM_TRACE_DEBUG("%s - BLE state: %x", __func__, btm_ble_get_conn_st());
+        return true;
+    }
+#endif
+
+    return false;
+}
+
+/*******************************************************************************
+**
+** Function         btm_pm_device_in_scan_state
+**
+** Description      This function is called to check if in paging, inquiry or connecting mode
+**
+** Returns          true, if in paging, inquiry or connecting mode
+**
+*******************************************************************************/
+bool    btm_pm_device_in_scan_state(void)
+{
+    /* Scan state-paging, inquiry, and trying to connect */
+
+    /* Check for paging */
+    if (btm_cb.is_paging || (!fixed_queue_is_empty(btm_cb.page_queue)) ||
+       BTM_BL_PAGING_STARTED == btm_cb.busy_level)
+    {
+       BTM_TRACE_DEBUG("btm_pm_device_in_scan_state- paging");
+       return true;
+    }
+
+    /* Check for inquiry */
+    if ((btm_cb.btm_inq_vars.inq_active & (BTM_BR_INQ_ACTIVE_MASK | BTM_BLE_INQ_ACTIVE_MASK)) != 0)
+    {
+        BTM_TRACE_DEBUG("btm_pm_device_in_scan_state- Inq active");
+        return true;
+    }
+
+    return false;
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    if (true == btm_pm_device_in_active_or_sniff_mode())
+       return BTM_CONTRL_ACTIVE;
+    else
+    if (true == btm_pm_device_in_scan_state())
+       return BTM_CONTRL_SCAN;
+    else
+       return BTM_CONTRL_IDLE;
+}
+
+static const char *mode_to_string(tBTM_PM_MODE mode) {
+  switch (mode) {
+    case BTM_PM_MD_ACTIVE: return "ACTIVE";
+    case BTM_PM_MD_SNIFF:  return "SNIFF";
+    case BTM_PM_MD_PARK:   return "PARK";
+    case BTM_PM_MD_HOLD:   return "HOLD";
+    default:               return "UNKNOWN";
+  }
+}
diff --git a/bt/stack/btm/btm_sco.cc b/bt/stack/btm/btm_sco.cc
new file mode 100644
index 0000000..73049db
--- /dev/null
+++ b/bt/stack/btm/btm_sco.cc
@@ -0,0 +1,1793 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2000-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 functions that handle SCO connections. This includes
+ *  operations such as connect, disconnect, change supported packet types.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_types.h"
+#include "bt_target.h"
+#include "bt_common.h"
+#include "bt_types.h"
+#include "hcimsgs.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "hcidefs.h"
+#include "bt_utils.h"
+#include "device/include/controller.h"
+#include "osi/include/osi.h"
+
+
+#if (BTM_SCO_INCLUDED == TRUE)
+
+/********************************************************************************/
+/*                 L O C A L    D A T A    D E F I N I T I O N S                */
+/********************************************************************************/
+
+#define SCO_ST_UNUSED           0
+#define SCO_ST_LISTENING        1
+#define SCO_ST_W4_CONN_RSP      2
+#define SCO_ST_CONNECTING       3
+#define SCO_ST_CONNECTED        4
+#define SCO_ST_DISCONNECTING    5
+#define SCO_ST_PEND_UNPARK      6
+#define SCO_ST_PEND_ROLECHANGE  7
+#define SCO_ST_PEND_MODECHANGE  8
+
+/********************************************************************************/
+/*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
+/********************************************************************************/
+
+static const tBTM_ESCO_PARAMS btm_esco_defaults =
+{
+    BTM_64KBITS_RATE,               /* TX Bandwidth (64 kbits/sec)              */
+    BTM_64KBITS_RATE,               /* RX Bandwidth (64 kbits/sec)              */
+    0x000c,                         /* 12 ms (HS/HF can use EV3, 2-EV3, 3-EV3)  */
+    0x0060,                         /* Inp Linear, Air CVSD, 2s Comp, 16bit     */
+    (BTM_SCO_PKT_TYPES_MASK_HV1 +   /* Packet Types                             */
+     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_ESCO_RETRANS_QUALITY         /* Retransmission Effort */
+};
+
+/*******************************************************************************
+**
+** Function         btm_sco_flush_sco_data
+**
+** Description      This function is called to flush the SCO data for this channel.
+**
+** Returns          void
+**
+*******************************************************************************/
+#if (BTM_SCO_HCI_INCLUDED == TRUE && BTM_MAX_SCO_LINKS>0)
+void btm_sco_flush_sco_data(uint16_t sco_inx)
+{
+    tSCO_CONN   *p ;
+    BT_HDR      *p_buf;
+
+    if (sco_inx < BTM_MAX_SCO_LINKS)
+    {
+        p = &btm_cb.sco_cb.sco_db[sco_inx];
+        while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p->xmit_data_q)) != NULL)
+            osi_free(p_buf);
+        }
+    }
+}
+#else
+void btm_sco_flush_sco_data(UNUSED_ATTR uint16_t sco_inx)
+{
+}
+#endif
+/*******************************************************************************
+**
+** Function         btm_sco_init
+**
+** Description      This function is called at BTM startup to initialize
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sco_init (void)
+{
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+    for (int i = 0; i < BTM_MAX_SCO_LINKS; i++)
+        btm_cb.sco_cb.sco_db[i].xmit_data_q = fixed_queue_new(SIZE_MAX);
+#endif
+
+    /* Initialize nonzero defaults */
+    btm_cb.sco_cb.sco_disc_reason  = BTM_INVALID_SCO_DISC_REASON;
+
+    btm_cb.sco_cb.def_esco_parms = btm_esco_defaults; /* Initialize with defaults */
+    btm_cb.sco_cb.desired_sco_mode = BTM_DEFAULT_SCO_MODE;
+}
+
+/*******************************************************************************
+**
+** Function         btm_esco_conn_rsp
+**
+** 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 default values 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
+**
+*******************************************************************************/
+static void btm_esco_conn_rsp (uint16_t sco_inx, uint8_t hci_status, BD_ADDR bda,
+                               tBTM_ESCO_PARAMS *p_parms)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    tSCO_CONN        *p_sco = NULL;
+    tBTM_ESCO_PARAMS *p_setup;
+    uint16_t          temp_pkt_types;
+
+    if (sco_inx < BTM_MAX_SCO_LINKS)
+        p_sco = &btm_cb.sco_cb.sco_db[sco_inx];
+
+    /* Reject the connect request if refused by caller or wrong state */
+    if (hci_status != HCI_SUCCESS || p_sco == NULL)
+    {
+        if (p_sco)
+        {
+            p_sco->state = (p_sco->state == SCO_ST_W4_CONN_RSP) ? SCO_ST_LISTENING
+                                                                : SCO_ST_UNUSED;
+        }
+
+        if (!btm_cb.sco_cb.esco_supported)
+        {
+            btsnd_hcic_reject_conn(bda, hci_status);
+        }
+        else
+        {
+            btsnd_hcic_reject_esco_conn(bda, hci_status);
+        }
+    }
+    else    /* Connection is being accepted */
+    {
+        p_sco->state = SCO_ST_CONNECTING;
+        p_setup = &p_sco->esco.setup;
+        /* If parameters not specified use the default */
+        if (p_parms)
+            *p_setup = *p_parms;
+        else /* Use the last setup passed thru BTM_SetEscoMode (or defaults) */
+        {
+            *p_setup = btm_cb.sco_cb.def_esco_parms;
+        }
+
+        temp_pkt_types = (p_setup->packet_types &
+                          BTM_SCO_SUPPORTED_PKTS_MASK &
+                          btm_cb.btm_sco_pkt_types_supported);
+
+        /* Make sure at least one eSCO packet type is sent, else might confuse peer */
+        /* Taking this out to confirm with BQB tests
+        ** Real application would like to include this though, as many devices
+        ** do not retry with SCO only if an eSCO connection fails.
+        if (!(temp_pkt_types & BTM_ESCO_LINK_ONLY_MASK))
+        {
+            temp_pkt_types |= BTM_SCO_PKT_TYPES_MASK_EV3;
+        }
+        */
+        /* If SCO request, remove eSCO packet types (conformance) */
+        if (p_sco->esco.data.link_type == BTM_LINK_TYPE_SCO)
+        {
+            temp_pkt_types &= BTM_SCO_LINK_ONLY_MASK;
+            temp_pkt_types |= BTM_SCO_EXCEPTION_PKTS_MASK;
+        }
+        else
+        {
+            /* OR in any exception packet types */
+            temp_pkt_types |= ((p_setup->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
+                (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
+        }
+
+        btsnd_hcic_accept_esco_conn(bda, p_setup->tx_bw, p_setup->rx_bw,
+                                    p_setup->max_latency, p_setup->voice_contfmt,
+                                    p_setup->retrans_effort, temp_pkt_types);
+        p_setup->packet_types = temp_pkt_types;
+    }
+#endif
+}
+
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function         btm_sco_check_send_pkts
+**
+** Description      This function is called to check if it can send packets
+**                  to the Host Controller.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sco_check_send_pkts (uint16_t sco_inx)
+{
+    tSCO_CB  *p_cb = &btm_cb.sco_cb;
+    tSCO_CONN   *p_ccb = &p_cb->sco_db[sco_inx];
+
+    /* If there is data to send, send it now */
+    BT_HDR  *p_buf;
+    while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->xmit_data_q)) != NULL)
+    {
+#if (BTM_SCO_HCI_DEBUG == TRUE)
+        BTM_TRACE_DEBUG("btm: [%d] buf in xmit_data_q",
+                        fixed_queue_length(p_ccb->xmit_data_q) + 1);
+#endif
+
+        HCI_SCO_DATA_TO_LOWER(p_buf);
+    }
+}
+#endif /* BTM_SCO_HCI_INCLUDED == TRUE */
+
+/*******************************************************************************
+**
+** Function         btm_route_sco_data
+**
+** Description      Route received SCO data.
+**
+** Returns          void
+**
+*******************************************************************************/
+void  btm_route_sco_data(BT_HDR *p_msg)
+{
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+    uint16_t    sco_inx, handle;
+    uint8_t     *p = (uint8_t *)(p_msg + 1) + p_msg->offset;
+    uint8_t     pkt_size = 0;
+    uint8_t     pkt_status = 0;
+
+    /* Extract Packet_Status_Flag and handle */
+    STREAM_TO_UINT16 (handle, p);
+    pkt_status = HCID_GET_EVENT(handle);
+    handle   = HCID_GET_HANDLE (handle);
+
+    STREAM_TO_UINT8 (pkt_size, p);
+
+    if ((sco_inx = btm_find_scb_by_handle(handle)) != BTM_MAX_SCO_LINKS )
+    {
+        /* send data callback */
+        if (!btm_cb.sco_cb.p_data_cb )
+            /* if no data callback registered,  just free the buffer  */
+            osi_free(p_msg);
+        else
+        {
+            (*btm_cb.sco_cb.p_data_cb)(sco_inx, p_msg, (tBTM_SCO_DATA_FLAG) pkt_status);
+        }
+    }
+    else /* no mapping handle SCO connection is active, free the buffer */
+    {
+        osi_free(p_msg);
+    }
+#else
+    osi_free(p_msg);
+#endif
+}
+
+/*******************************************************************************
+**
+** 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.
+**
+**
+*******************************************************************************/
+#if (BTM_SCO_HCI_INCLUDED == TRUE && BTM_MAX_SCO_LINKS > 0)
+tBTM_STATUS BTM_WriteScoData (uint16_t sco_inx, BT_HDR *p_buf)
+{
+    tSCO_CONN   *p_ccb = &btm_cb.sco_cb.sco_db[sco_inx];
+    uint8_t *p;
+    tBTM_STATUS     status = BTM_SUCCESS;
+
+    if (sco_inx < BTM_MAX_SCO_LINKS && btm_cb.sco_cb.p_data_cb &&
+        p_ccb->state == SCO_ST_CONNECTED)
+    {
+        /* Ensure we have enough space in the buffer for the SCO and HCI headers */
+        if (p_buf->offset < HCI_SCO_PREAMBLE_SIZE)
+        {
+            BTM_TRACE_ERROR ("BTM SCO - cannot send buffer, offset: %d", p_buf->offset);
+            osi_free(p_buf);
+            status = BTM_ILLEGAL_VALUE;
+        }
+        else    /* write HCI header */
+        {
+            /* Step back 3 bytes to add the headers */
+            p_buf->offset -= HCI_SCO_PREAMBLE_SIZE;
+            /* Set the pointer to the beginning of the data */
+            p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+            /* add HCI handle */
+            UINT16_TO_STREAM (p, p_ccb->hci_handle);
+            /* only sent the first BTM_SCO_DATA_SIZE_MAX bytes data if more than max,
+               and set warning status */
+            if (p_buf->len > BTM_SCO_DATA_SIZE_MAX)
+            {
+                p_buf->len = BTM_SCO_DATA_SIZE_MAX;
+                status = BTM_SCO_BAD_LENGTH;
+            }
+
+            UINT8_TO_STREAM (p, (uint8_t)p_buf->len);
+            p_buf->len += HCI_SCO_PREAMBLE_SIZE;
+
+            fixed_queue_enqueue(p_ccb->xmit_data_q, p_buf);
+
+            btm_sco_check_send_pkts (sco_inx);
+        }
+    }
+    else
+    {
+        osi_free(p_buf);
+
+        BTM_TRACE_WARNING ("BTM_WriteScoData, invalid sco index: %d at state [%d]",
+            sco_inx, btm_cb.sco_cb.sco_db[sco_inx].state);
+        status = BTM_UNKNOWN_ADDR;
+    }
+
+    return (status);
+
+}
+#else
+tBTM_STATUS BTM_WriteScoData(UNUSED_ATTR uint16_t sco_inx,
+                             UNUSED_ATTR BT_HDR *p_buf)
+{
+    return (BTM_NO_RESOURCES);
+}
+#endif
+
+#if (BTM_MAX_SCO_LINKS>0)
+/*******************************************************************************
+**
+** Function         btm_send_connect_request
+**
+** Description      This function is called to respond to SCO connect indications
+**
+** Returns          void
+**
+*******************************************************************************/
+static tBTM_STATUS btm_send_connect_request(uint16_t acl_handle,
+                                            tBTM_ESCO_PARAMS *p_setup)
+{
+    uint16_t temp_pkt_types;
+    uint8_t xx;
+    tACL_CONN *p_acl;
+
+    /* Send connect request depending on version of spec */
+    if (!btm_cb.sco_cb.esco_supported)
+    {
+        btsnd_hcic_add_SCO_conn(acl_handle, BTM_ESCO_2_SCO(p_setup->packet_types));
+    }
+    else
+    {
+        temp_pkt_types = (p_setup->packet_types & BTM_SCO_SUPPORTED_PKTS_MASK &
+                             btm_cb.btm_sco_pkt_types_supported);
+
+        /* OR in any exception packet types */
+        temp_pkt_types |= ((p_setup->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
+            (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
+
+        /* Finally, remove EDR eSCO if the remote device doesn't support it */
+        /* UPF25:  Only SCO was brought up in this case */
+        btm_handle_to_acl_index(acl_handle);
+        if ((xx = btm_handle_to_acl_index(acl_handle)) < MAX_L2CAP_LINKS)
+        {
+            p_acl = &btm_cb.acl_db[xx];
+            if (!HCI_EDR_ESCO_2MPS_SUPPORTED(p_acl->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]))
+            {
+
+                BTM_TRACE_WARNING("BTM Remote does not support 2-EDR eSCO");
+                temp_pkt_types |= (HCI_ESCO_PKT_TYPES_MASK_NO_2_EV3 |
+                                   HCI_ESCO_PKT_TYPES_MASK_NO_2_EV5);
+            }
+            if (!HCI_EDR_ESCO_3MPS_SUPPORTED(p_acl->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0]))
+            {
+
+                BTM_TRACE_WARNING("BTM Remote does not support 3-EDR eSCO");
+                temp_pkt_types |= (HCI_ESCO_PKT_TYPES_MASK_NO_3_EV3 |
+                                   HCI_ESCO_PKT_TYPES_MASK_NO_3_EV5);
+            }
+
+             /* Check to see if BR/EDR Secure Connections is being used
+             ** If so, we cannot use SCO-only packet types (HFP 1.7)
+             */
+            if (BTM_BothEndsSupportSecureConnections(p_acl->remote_addr))
+            {
+                temp_pkt_types &= ~(BTM_SCO_PKT_TYPE_MASK);
+                BTM_TRACE_DEBUG("%s: SCO Conn: pkt_types after removing SCO (0x%04x)", __func__,
+                                 temp_pkt_types);
+
+                /* Return error if no packet types left */
+                if (temp_pkt_types == 0)
+                {
+                    BTM_TRACE_ERROR("%s: SCO Conn (BR/EDR SC): No packet types available",
+                                    __func__);
+                    return (BTM_WRONG_MODE);
+                }
+            }
+            else
+            {
+                BTM_TRACE_DEBUG("%s: SCO Conn(BR/EDR SC):local or peer does not support BR/EDR SC",
+                                __func__);
+            }
+        }
+
+
+        BTM_TRACE_API("      txbw 0x%x, rxbw 0x%x, lat 0x%x, voice 0x%x, retrans 0x%02x, pkt 0x%04x",
+            p_setup->tx_bw, p_setup->rx_bw,
+            p_setup->max_latency, p_setup->voice_contfmt,
+            p_setup->retrans_effort, temp_pkt_types);
+
+        btsnd_hcic_setup_esco_conn(acl_handle,
+                                   p_setup->tx_bw,
+                                   p_setup->rx_bw,
+                                   p_setup->max_latency,
+                                   p_setup->voice_contfmt,
+                                   p_setup->retrans_effort,
+                                   temp_pkt_types);
+        p_setup->packet_types = temp_pkt_types;
+    }
+
+    return (BTM_CMD_STARTED);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         btm_set_sco_ind_cback
+**
+** Description      This function is called to register for TCS SCO connect
+**                  indications.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_set_sco_ind_cback( tBTM_SCO_IND_CBACK *sco_ind_cb )
+{
+    btm_cb.sco_cb.app_sco_ind_cb = sco_ind_cb;
+}
+
+/*******************************************************************************
+**
+** Function         btm_accept_sco_link
+**
+** Description      This function is called to respond to TCS SCO connect
+**                  indications
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_accept_sco_link(uint16_t sco_inx, tBTM_ESCO_PARAMS *p_setup,
+                         tBTM_SCO_CB *p_conn_cb, tBTM_SCO_CB *p_disc_cb)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    tSCO_CONN        *p_sco;
+
+    if (sco_inx >= BTM_MAX_SCO_LINKS)
+    {
+        BTM_TRACE_ERROR("btm_accept_sco_link: Invalid sco_inx(%d)", sco_inx);
+        return;
+    }
+
+    /* Link role is ignored in for this message */
+    p_sco = &btm_cb.sco_cb.sco_db[sco_inx];
+    p_sco->p_conn_cb = p_conn_cb;
+    p_sco->p_disc_cb = p_disc_cb;
+    p_sco->esco.data.link_type = BTM_LINK_TYPE_ESCO; /* Accept with all supported types */
+
+    BTM_TRACE_DEBUG("TCS accept SCO: Packet Types 0x%04x", p_setup->packet_types);
+
+    btm_esco_conn_rsp(sco_inx, HCI_SUCCESS, p_sco->esco.data.bd_addr, p_setup);
+#else
+    btm_reject_sco_link(sco_inx);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btm_reject_sco_link
+**
+** Description      This function is called to respond to SCO connect indications
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_reject_sco_link( uint16_t sco_inx )
+{
+    btm_esco_conn_rsp(sco_inx, HCI_ERR_HOST_REJECT_RESOURCES,
+                      btm_cb.sco_cb.sco_db[sco_inx].esco.data.bd_addr, NULL);
+}
+
+/*******************************************************************************
+**
+** 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.
+**
+**                  NOTE:  If BTM_IGNORE_SCO_PKT_TYPE is passed in the pkt_types
+**                      parameter the default packet types is used.
+**
+** 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 (BD_ADDR 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)
+{
+#if (BTM_MAX_SCO_LINKS > 0)
+    tBTM_ESCO_PARAMS *p_setup;
+    tSCO_CONN        *p = &btm_cb.sco_cb.sco_db[0];
+    uint16_t          xx;
+    uint16_t          acl_handle = 0;
+    uint16_t          temp_pkt_types;
+    tACL_CONN        *p_acl;
+
+#if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
+    tBTM_PM_PWR_MD    pm;
+    tBTM_PM_STATE     state;
+#else
+    uint8_t           mode;
+#endif  // BTM_SCO_WAKE_PARKED_LINK
+
+    *p_sco_inx = BTM_INVALID_SCO_INDEX;
+
+    /* If originating, ensure that there is an ACL connection to the BD Address */
+    if (is_orig)
+    {
+        if ((!remote_bda) || ((acl_handle = BTM_GetHCIConnHandle (remote_bda, BT_TRANSPORT_BR_EDR)) == 0xFFFF))
+            return (BTM_UNKNOWN_ADDR);
+    }
+
+    if (remote_bda)
+    {
+        /* If any SCO is being established to the remote BD address, refuse this */
+        for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+        {
+            if (((p->state == SCO_ST_CONNECTING) || (p->state == SCO_ST_LISTENING)
+                || (p->state == SCO_ST_PEND_UNPARK))
+                && (!memcmp (p->esco.data.bd_addr, remote_bda, BD_ADDR_LEN)))
+            {
+                return (BTM_BUSY);
+            }
+        }
+    }
+    else
+    {
+        /* Support only 1 wildcard BD address at a time */
+        for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+        {
+            if ((p->state == SCO_ST_LISTENING) && (!p->rem_bd_known))
+                return (BTM_BUSY);
+        }
+    }
+
+    /* Now, try to find an unused control block, and kick off the SCO establishment */
+    for (xx = 0, p = &btm_cb.sco_cb.sco_db[0]; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+    {
+        if (p->state == SCO_ST_UNUSED)
+        {
+            if (remote_bda)
+            {
+                if (is_orig)
+                {
+                    /* can not create SCO link if in park mode */
+#if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
+                    if ((btm_read_power_mode_state(p->esco.data.bd_addr, &state) == BTM_SUCCESS))
+                    {
+                        if (state == BTM_PM_ST_SNIFF || state == BTM_PM_ST_PARK ||
+                            state == BTM_PM_ST_PENDING)
+                        {
+                            BTM_TRACE_DEBUG("%s In sniff, park or pend mode: %d", __func__, state);
+                            memset( (void*)&pm, 0, sizeof(pm));
+                            pm.mode = BTM_PM_MD_ACTIVE;
+                            BTM_SetPowerMode(BTM_PM_SET_ONLY_ID, remote_bda, &pm);
+                            p->state = SCO_ST_PEND_UNPARK;
+                        }
+                    }
+#else  // BTM_SCO_WAKE_PARKED_LINK
+                    if( (BTM_ReadPowerMode(remote_bda, &mode) == BTM_SUCCESS) && (mode == BTM_PM_MD_PARK) )
+                        return (BTM_WRONG_MODE);
+#endif  // BTM_SCO_WAKE_PARKED_LINK
+                }
+                memcpy (p->esco.data.bd_addr, remote_bda, BD_ADDR_LEN);
+                p->rem_bd_known = true;
+            }
+            else
+                p->rem_bd_known = false;
+
+            /* Link role is ignored in for this message */
+            if (pkt_types == BTM_IGNORE_SCO_PKT_TYPE)
+                pkt_types = btm_cb.sco_cb.def_esco_parms.packet_types;
+
+            p_setup = &p->esco.setup;
+            *p_setup = btm_cb.sco_cb.def_esco_parms;
+            p_setup->packet_types = (btm_cb.sco_cb.desired_sco_mode == BTM_LINK_TYPE_SCO)
+                ? (pkt_types & BTM_SCO_LINK_ONLY_MASK) : pkt_types;
+
+            temp_pkt_types = (p_setup->packet_types & BTM_SCO_SUPPORTED_PKTS_MASK &
+                             btm_cb.btm_sco_pkt_types_supported);
+
+            /* OR in any exception packet types */
+            if (controller_get_interface()->get_bt_version()->hci_version >= HCI_PROTO_VERSION_2_0)
+            {
+                temp_pkt_types |= ((p_setup->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
+                    (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
+            }
+            else    /* Only using SCO packet types; turn off EDR also */
+            {
+                temp_pkt_types |= BTM_SCO_EXCEPTION_PKTS_MASK;
+            }
+
+            p_setup->packet_types = temp_pkt_types;
+            p->p_conn_cb  = p_conn_cb;
+            p->p_disc_cb  = p_disc_cb;
+            p->hci_handle = BTM_INVALID_HCI_HANDLE;
+            p->is_orig = is_orig;
+
+            if( p->state != SCO_ST_PEND_UNPARK )
+            {
+                if (is_orig)
+                {
+                    /* If role change is in progress, do not proceed with SCO setup
+                     * Wait till role change is complete */
+                    p_acl = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+                    if (p_acl && p_acl->switch_role_state != BTM_ACL_SWKEY_STATE_IDLE)
+                    {
+                        BTM_TRACE_API("Role Change is in progress for ACL handle 0x%04x",acl_handle);
+                        p->state = SCO_ST_PEND_ROLECHANGE;
+
+                    }
+                }
+            }
+
+            if( p->state != SCO_ST_PEND_UNPARK && p->state != SCO_ST_PEND_ROLECHANGE )
+            {
+                if (is_orig)
+                {
+                    BTM_TRACE_API("BTM_CreateSco -> (e)SCO Link for ACL handle 0x%04x, Desired Type %d",
+                                    acl_handle, btm_cb.sco_cb.desired_sco_mode);
+
+                    if ((btm_send_connect_request(acl_handle, p_setup)) != BTM_CMD_STARTED)
+                        return (BTM_NO_RESOURCES);
+
+                    p->state = SCO_ST_CONNECTING;
+                }
+                else
+                    p->state = SCO_ST_LISTENING;
+            }
+
+            *p_sco_inx = xx;
+
+            return (BTM_CMD_STARTED);
+        }
+    }
+
+#endif
+    /* If here, all SCO blocks in use */
+    return (BTM_NO_RESOURCES);
+}
+
+#if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
+/*******************************************************************************
+**
+** Function         btm_sco_chk_pend_unpark
+**
+** Description      This function is called by BTIF when there is a mode change
+**                  event to see if there are SCO commands waiting for the unpark.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sco_chk_pend_unpark (uint8_t hci_status, uint16_t hci_handle)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    uint16_t    xx;
+    uint16_t    acl_handle;
+    tSCO_CONN   *p = &btm_cb.sco_cb.sco_db[0];
+
+    for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+    {
+        if ((p->state == SCO_ST_PEND_UNPARK) &&
+            ((acl_handle = BTM_GetHCIConnHandle (p->esco.data.bd_addr, BT_TRANSPORT_BR_EDR)) == hci_handle))
+
+        {
+            BTM_TRACE_API("btm_sco_chk_pend_unpark -> (e)SCO Link for ACL handle 0x%04x, Desired Type %d, hci_status 0x%02x",
+                                    acl_handle, btm_cb.sco_cb.desired_sco_mode, hci_status);
+
+            if ((btm_send_connect_request(acl_handle, &p->esco.setup)) == BTM_CMD_STARTED)
+                p->state = SCO_ST_CONNECTING;
+        }
+    }
+#endif  // BTM_MAX_SCO_LINKS
+}
+#endif  // BTM_SCO_WAKE_PARKED_LINK
+
+/*******************************************************************************
+**
+** Function         btm_sco_chk_pend_rolechange
+**
+** Description      This function is called by BTIF when there is a role change
+**                  event to see if there are SCO commands waiting for the role change.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sco_chk_pend_rolechange (uint16_t hci_handle)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    uint16_t    xx;
+    uint16_t    acl_handle;
+    tSCO_CONN   *p = &btm_cb.sco_cb.sco_db[0];
+
+    for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+    {
+        if ((p->state == SCO_ST_PEND_ROLECHANGE) &&
+            ((acl_handle = BTM_GetHCIConnHandle (p->esco.data.bd_addr, BT_TRANSPORT_BR_EDR)) == hci_handle))
+
+        {
+            BTM_TRACE_API("btm_sco_chk_pend_rolechange -> (e)SCO Link for ACL handle 0x%04x", acl_handle);
+
+            if ((btm_send_connect_request(acl_handle, &p->esco.setup)) == BTM_CMD_STARTED)
+                p->state = SCO_ST_CONNECTING;
+        }
+    }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function        btm_sco_disc_chk_pend_for_modechange
+**
+** Description     This function is called by btm when there is a mode change
+**                 event to see if there are SCO  disconnect commands waiting for the mode change.
+**
+** Returns         void
+**
+*******************************************************************************/
+void btm_sco_disc_chk_pend_for_modechange (uint16_t hci_handle)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    tSCO_CONN   *p = &btm_cb.sco_cb.sco_db[0];
+
+    BTM_TRACE_DEBUG("%s: hci_handle 0x%04x, p->state 0x%02x", __func__,
+                     hci_handle, p->state);
+
+    for (uint16_t xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+    {
+        if ((p->state == SCO_ST_PEND_MODECHANGE) &&
+            (BTM_GetHCIConnHandle (p->esco.data.bd_addr, BT_TRANSPORT_BR_EDR)) == hci_handle)
+
+        {
+            BTM_TRACE_DEBUG("%s: SCO Link handle 0x%04x", __func__, p->hci_handle);
+            BTM_RemoveSco(xx);
+        }
+    }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btm_sco_conn_req
+**
+** Description      This function is called by BTIF when an SCO connection
+**                  request is received from a remote.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sco_conn_req (BD_ADDR bda,  DEV_CLASS dev_class, uint8_t link_type)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    tSCO_CB     *p_sco = &btm_cb.sco_cb;
+    tSCO_CONN   *p = &p_sco->sco_db[0];
+    uint16_t    xx;
+    tBTM_ESCO_CONN_REQ_EVT_DATA evt_data;
+
+    for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+    {
+        /*
+         * If the sco state is in the SCO_ST_CONNECTING state, we still need
+         * to return accept sco to avoid race conditon for sco creation
+         */
+        int rem_bd_matches = p->rem_bd_known &&
+          !memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN);
+        if (((p->state == SCO_ST_CONNECTING) && rem_bd_matches) ||
+            ((p->state == SCO_ST_LISTENING) && (rem_bd_matches || !p->rem_bd_known)))
+        {
+            /* If this guy was a wildcard, he is not one any more */
+            p->rem_bd_known = true;
+            p->esco.data.link_type = link_type;
+            p->state = SCO_ST_W4_CONN_RSP;
+            memcpy (p->esco.data.bd_addr, bda, BD_ADDR_LEN);
+
+            /* If no callback, auto-accept the connection if packet types match */
+            if (!p->esco.p_esco_cback)
+            {
+                /* If requesting eSCO reject if default parameters are SCO only */
+                if ((link_type == BTM_LINK_TYPE_ESCO
+                    && !(p_sco->def_esco_parms.packet_types & BTM_ESCO_LINK_ONLY_MASK)
+                    && ((p_sco->def_esco_parms.packet_types & BTM_SCO_EXCEPTION_PKTS_MASK)
+                       == BTM_SCO_EXCEPTION_PKTS_MASK))
+
+                    /* Reject request if SCO is desired but no SCO packets delected */
+                    || (link_type == BTM_LINK_TYPE_SCO
+                    && !(p_sco->def_esco_parms.packet_types & BTM_SCO_LINK_ONLY_MASK)))
+                {
+                    btm_esco_conn_rsp(xx, HCI_ERR_HOST_REJECT_RESOURCES, bda, NULL);
+                }
+                else    /* Accept the request */
+                {
+                    btm_esco_conn_rsp(xx, HCI_SUCCESS, bda, NULL);
+                }
+            }
+            else    /* Notify upper layer of connect indication */
+            {
+                memcpy(evt_data.bd_addr, bda, BD_ADDR_LEN);
+                memcpy(evt_data.dev_class, dev_class, DEV_CLASS_LEN);
+                evt_data.link_type = link_type;
+                evt_data.sco_inx = xx;
+                p->esco.p_esco_cback(BTM_ESCO_CONN_REQ_EVT, (tBTM_ESCO_EVT_DATA *)&evt_data);
+            }
+
+            return;
+        }
+    }
+
+    /* TCS usage */
+    if (btm_cb.sco_cb.app_sco_ind_cb)
+    {
+        /* Now, try to find an unused control block */
+        for (xx = 0, p = &btm_cb.sco_cb.sco_db[0]; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+        {
+            if (p->state == SCO_ST_UNUSED)
+            {
+                p->is_orig = false;
+                p->state = SCO_ST_LISTENING;
+
+                p->esco.data.link_type = link_type;
+                memcpy (p->esco.data.bd_addr, bda, BD_ADDR_LEN);
+                p->rem_bd_known = true;
+                break;
+            }
+        }
+        if( xx < BTM_MAX_SCO_LINKS)
+        {
+            btm_cb.sco_cb.app_sco_ind_cb(xx);
+            return;
+        }
+    }
+
+#endif
+    /* If here, no one wants the SCO connection. Reject it */
+    BTM_TRACE_WARNING("btm_sco_conn_req: No one wants this SCO connection; rejecting it");
+    btm_esco_conn_rsp(BTM_MAX_SCO_LINKS, HCI_ERR_HOST_REJECT_RESOURCES, bda, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sco_connected
+**
+** Description      This function is called by BTIF when an (e)SCO connection
+**                  is connected.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sco_connected (uint8_t hci_status, BD_ADDR bda, uint16_t hci_handle,
+                        tBTM_ESCO_DATA *p_esco_data)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    tSCO_CONN   *p = &btm_cb.sco_cb.sco_db[0];
+    uint16_t    xx;
+    bool        spt = false;
+    tBTM_CHG_ESCO_PARAMS parms;
+#endif
+
+    btm_cb.sco_cb.sco_disc_reason = hci_status;
+
+#if (BTM_MAX_SCO_LINKS>0)
+    for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+    {
+        if (((p->state == SCO_ST_CONNECTING) ||
+             (p->state == SCO_ST_LISTENING)  ||
+             (p->state == SCO_ST_W4_CONN_RSP))
+         && (p->rem_bd_known)
+         && (!bda || !memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN)))
+        {
+            if (hci_status != HCI_SUCCESS)
+            {
+                /* Report the error if originator, otherwise remain in Listen mode */
+                if (p->is_orig)
+                {
+                    /* If role switch is pending, we need try again after role switch is complete */
+                    if(hci_status == HCI_ERR_ROLE_SWITCH_PENDING)
+                    {
+                        BTM_TRACE_API("Role Change pending for HCI handle 0x%04x",hci_handle);
+                        p->state = SCO_ST_PEND_ROLECHANGE;
+                    }
+                    /* avoid calling disconnect callback because of sco creation race */
+                    else if (hci_status != HCI_ERR_LMP_ERR_TRANS_COLLISION)
+                    {
+                        p->state = SCO_ST_UNUSED;
+                        (*p->p_disc_cb)(xx);
+                    }
+                }
+                else
+                {
+                    /* Notify the upper layer that incoming sco connection has failed. */
+                    if (p->state == SCO_ST_CONNECTING)
+                    {
+                        p->state = SCO_ST_UNUSED;
+                        (*p->p_disc_cb)(xx);
+                    }
+                    else
+                        p->state = SCO_ST_LISTENING;
+                }
+
+                return;
+            }
+
+            if (p->state == SCO_ST_LISTENING)
+                spt = true;
+
+            p->state = SCO_ST_CONNECTED;
+            p->hci_handle = hci_handle;
+
+            if (!btm_cb.sco_cb.esco_supported)
+            {
+                p->esco.data.link_type = BTM_LINK_TYPE_SCO;
+                if (spt)
+                {
+                    parms.packet_types = p->esco.setup.packet_types;
+                    /* Keep the other parameters the same for SCO */
+                    parms.max_latency = p->esco.setup.max_latency;
+                    parms.retrans_effort = p->esco.setup.retrans_effort;
+
+                    BTM_ChangeEScoLinkParms(xx, &parms);
+                }
+            }
+            else
+            {
+                if (p_esco_data)
+                    p->esco.data = *p_esco_data;
+            }
+
+            (*p->p_conn_cb)(xx);
+
+            return;
+        }
+    }
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function         btm_find_scb_by_handle
+**
+** Description      Look through all active SCO connection for a match based on the
+**                  HCI handle.
+**
+** Returns          index to matched SCO connection CB, or BTM_MAX_SCO_LINKS if
+**                  no match.
+**
+*******************************************************************************/
+uint16_t btm_find_scb_by_handle (uint16_t handle)
+{
+    int         xx;
+    tSCO_CONN    *p = &btm_cb.sco_cb.sco_db[0];
+
+    for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+    {
+        if ((p->state == SCO_ST_CONNECTED) && (p->hci_handle == handle))
+        {
+            return (xx);
+        }
+    }
+
+    /* If here, no match found */
+    return (xx);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_RemoveSco
+**
+** Description      This function is called to remove a specific SCO connection.
+**
+** Returns          status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_RemoveSco (uint16_t sco_inx)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    tSCO_CONN   *p = &btm_cb.sco_cb.sco_db[sco_inx];
+    uint16_t     tempstate;
+    tBTM_PM_STATE   state = BTM_PM_ST_INVALID;
+
+    BTM_TRACE_DEBUG("%s", __func__);
+
+    /* Validity check */
+    if ((sco_inx >= BTM_MAX_SCO_LINKS) || (p->state == SCO_ST_UNUSED))
+        return (BTM_UNKNOWN_ADDR);
+
+    /* If no HCI handle, simply drop the connection and return */
+    if (p->hci_handle == BTM_INVALID_HCI_HANDLE || p->state == SCO_ST_PEND_UNPARK)
+    {
+        p->hci_handle = BTM_INVALID_HCI_HANDLE;
+        p->state = SCO_ST_UNUSED;
+        p->esco.p_esco_cback = NULL;    /* Deregister the eSCO event callback */
+        return (BTM_SUCCESS);
+    }
+
+    if ((btm_read_power_mode_state(p->esco.data.bd_addr, &state) == BTM_SUCCESS)
+        && state == BTM_PM_ST_PENDING)
+    {
+        BTM_TRACE_DEBUG("%s: BTM_PM_ST_PENDING for ACL mapped with SCO Link 0x%04x",
+                          __func__, p->hci_handle);
+        p->state = SCO_ST_PEND_MODECHANGE;
+        return (BTM_CMD_STARTED);
+    }
+
+    tempstate = p->state;
+    p->state = SCO_ST_DISCONNECTING;
+
+    btsnd_hcic_disconnect(p->hci_handle, HCI_ERR_PEER_USER);
+
+    return (BTM_CMD_STARTED);
+#else
+    return (BTM_NO_RESOURCES);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btm_remove_sco_links
+**
+** Description      This function is called to remove all sco links for an ACL link.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_remove_sco_links (BD_ADDR bda)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    tSCO_CONN   *p = &btm_cb.sco_cb.sco_db[0];
+    uint16_t     xx;
+
+    for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+    {
+        if (p->rem_bd_known && (!memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN)))
+        {
+            BTM_RemoveSco(xx);
+        }
+    }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btm_sco_removed
+**
+** Description      This function is called by BTIF when an SCO connection
+**                  is removed.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sco_removed (uint16_t hci_handle, uint8_t reason)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    tSCO_CONN   *p = &btm_cb.sco_cb.sco_db[0];
+    uint16_t    xx;
+#endif
+
+    btm_cb.sco_cb.sco_disc_reason = reason;
+
+#if (BTM_MAX_SCO_LINKS>0)
+    p = &btm_cb.sco_cb.sco_db[0];
+    for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+    {
+        if ((p->state != SCO_ST_UNUSED) && (p->state != SCO_ST_LISTENING) && (p->hci_handle == hci_handle))
+        {
+            btm_sco_flush_sco_data(xx);
+
+            p->state = SCO_ST_UNUSED;
+            p->hci_handle = BTM_INVALID_HCI_HANDLE;
+            p->rem_bd_known = false;
+            p->esco.p_esco_cback = NULL;    /* Deregister eSCO callback */
+            (*p->p_disc_cb)(xx);
+
+            return;
+        }
+    }
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function         btm_sco_acl_removed
+**
+** Description      This function is called when an ACL connection is
+**                  removed. If the BD address is NULL, it is assumed that
+**                  the local device is down, and all SCO links are removed.
+**                  If a specific BD address is passed, only SCO connections
+**                  to that BD address are removed.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sco_acl_removed (BD_ADDR bda)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    tSCO_CONN   *p = &btm_cb.sco_cb.sco_db[0];
+    uint16_t    xx;
+
+    for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+    {
+        if (p->state != SCO_ST_UNUSED)
+        {
+            if ((!bda) || (!memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN) && p->rem_bd_known))
+            {
+                btm_sco_flush_sco_data(xx);
+
+                p->state = SCO_ST_UNUSED;
+                p->esco.p_esco_cback = NULL;    /* Deregister eSCO callback */
+                (*p->p_disc_cb)(xx);
+            }
+        }
+    }
+#endif
+}
+
+
+/*******************************************************************************
+**
+** 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_PKT_TYPES_MASK_NO_2_EV3
+**                  BTM_SCO_PKT_TYPES_MASK_NO_3_EV3
+**                  BTM_SCO_PKT_TYPES_MASK_NO_2_EV5
+**                  BTM_SCO_PKT_TYPES_MASK_NO_3_EV5
+**
+**                  BTM_SCO_LINK_ALL_MASK   - enables all supported types
+**
+** Returns          status of the operation
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetScoPacketTypes (uint16_t sco_inx, uint16_t pkt_types)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    tBTM_CHG_ESCO_PARAMS parms;
+    tSCO_CONN           *p;
+
+    /* Validity check */
+    if (sco_inx >= BTM_MAX_SCO_LINKS)
+        return (BTM_UNKNOWN_ADDR);
+
+    p = &btm_cb.sco_cb.sco_db[sco_inx];
+    parms.packet_types = pkt_types;
+
+    /* Keep the other parameters the same for SCO */
+    parms.max_latency = p->esco.setup.max_latency;
+    parms.retrans_effort = p->esco.setup.retrans_effort;
+
+    return (BTM_ChangeEScoLinkParms(sco_inx, &parms));
+#else
+    return (BTM_UNKNOWN_ADDR);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function         BTM_ReadScoPacketTypes
+**
+** Description      This function is read the packet types used for a specific
+**                  SCO connection.
+**
+** Returns          Packet types supported for the connection
+**                  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
+**                  BTM_SCO_PKT_TYPES_MASK_NO_2_EV3
+**                  BTM_SCO_PKT_TYPES_MASK_NO_3_EV3
+**                  BTM_SCO_PKT_TYPES_MASK_NO_2_EV5
+**                  BTM_SCO_PKT_TYPES_MASK_NO_3_EV5
+**
+*******************************************************************************/
+uint16_t BTM_ReadScoPacketTypes (uint16_t sco_inx)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    tSCO_CONN *p = &btm_cb.sco_cb.sco_db[sco_inx];
+
+    /* Validity check */
+    if ((sco_inx < BTM_MAX_SCO_LINKS) && (p->state == SCO_ST_CONNECTED))
+        return (p->esco.setup.packet_types);
+    else
+        return (0);
+#else
+    return (0);
+#endif
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    uint16_t res = btm_cb.sco_cb.sco_disc_reason;
+    btm_cb.sco_cb.sco_disc_reason = BTM_INVALID_SCO_DISC_REASON;
+    return (res);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_ReadDeviceScoPacketTypes
+**
+** Description      This function is read the SCO packet types that
+**                  the device supports.
+**
+** Returns          Packet types supported by the device.
+**                  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
+**                  BTM_SCO_PKT_TYPES_MASK_NO_2_EV3
+**                  BTM_SCO_PKT_TYPES_MASK_NO_3_EV3
+**                  BTM_SCO_PKT_TYPES_MASK_NO_2_EV5
+**                  BTM_SCO_PKT_TYPES_MASK_NO_3_EV5
+**
+*******************************************************************************/
+uint16_t BTM_ReadDeviceScoPacketTypes (void)
+{
+    return (btm_cb.btm_sco_pkt_types_supported);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_ReadScoHandle
+**
+** Description      This function is used to read 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)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    tSCO_CONN   *p = &btm_cb.sco_cb.sco_db[sco_inx];
+
+    /* Validity check */
+    if ((sco_inx < BTM_MAX_SCO_LINKS) && (p->state == SCO_ST_CONNECTED))
+        return (p->hci_handle);
+    else
+        return (BTM_INVALID_HCI_HANDLE);
+#else
+    return (BTM_INVALID_HCI_HANDLE);
+#endif
+}
+
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+uint8_t *BTM_ReadScoBdAddr (uint16_t sco_inx)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    tSCO_CONN   *p = &btm_cb.sco_cb.sco_db[sco_inx];
+
+    /* Validity check */
+    if ((sco_inx < BTM_MAX_SCO_LINKS) && (p->rem_bd_known))
+        return (p->esco.data.bd_addr);
+    else
+        return (NULL);
+#else
+    return (NULL);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         BTM_SetEScoMode
+**
+** Description      This function sets up the negotiated parameters for SCO or
+**                  eSCO, and sets as the default mode used for outgoing calls to
+**                  BTM_CreateSco.  It does not change any currently active (e)SCO links.
+**                  Note:  Incoming (e)SCO connections will always use packet types
+**                      supported by the controller.  If eSCO is not desired the
+**                      feature should be disabled in the controller's feature mask.
+**
+** Returns          BTM_SUCCESS if the successful.
+**                  BTM_BUSY if there are one or more active (e)SCO links.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetEScoMode (tBTM_SCO_TYPE sco_mode, tBTM_ESCO_PARAMS *p_parms)
+{
+    tSCO_CB          *p_esco = &btm_cb.sco_cb;
+    tBTM_ESCO_PARAMS *p_def = &p_esco->def_esco_parms;
+
+    if (p_esco->esco_supported)
+    {
+        if (p_parms)
+        {
+            if (sco_mode == BTM_LINK_TYPE_ESCO)
+                *p_def = *p_parms;  /* Save as the default parameters */
+            else    /* Load only the SCO packet types */
+            {
+                p_def->packet_types = p_parms->packet_types;
+                p_def->tx_bw            = BTM_64KBITS_RATE;
+                p_def->rx_bw            = BTM_64KBITS_RATE;
+                p_def->max_latency      = 0x000a;
+                p_def->voice_contfmt    = 0x0060;
+                p_def->retrans_effort   = 0;
+
+                /* OR in any exception packet types */
+                p_def->packet_types |= BTM_SCO_EXCEPTION_PKTS_MASK;
+            }
+        }
+        p_esco->desired_sco_mode = sco_mode;
+        BTM_TRACE_API("BTM_SetEScoMode -> mode %d",  sco_mode);
+    }
+    else
+    {
+        p_esco->desired_sco_mode = BTM_LINK_TYPE_SCO;
+        p_def->packet_types &= BTM_SCO_LINK_ONLY_MASK;
+        p_def->retrans_effort = 0;
+        BTM_TRACE_API("BTM_SetEScoMode -> mode SCO (eSCO not supported)");
+    }
+
+    BTM_TRACE_DEBUG("    txbw 0x%08x, rxbw 0x%08x, max_lat 0x%04x, voice 0x%04x, pkt 0x%04x, rtx effort 0x%02x",
+                     p_def->tx_bw, p_def->rx_bw, p_def->max_latency,
+                     p_def->voice_contfmt, p_def->packet_types,
+                     p_def->retrans_effort);
+
+    return (BTM_SUCCESS);
+}
+
+
+
+/*******************************************************************************
+**
+** 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
+**                  BTM_MODE_UNSUPPORTED if controller version is not BT1.2 or
+**                          later or does not support eSCO.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_RegForEScoEvts (uint16_t sco_inx, tBTM_ESCO_CBACK *p_esco_cback)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    if (!btm_cb.sco_cb.esco_supported)
+    {
+        btm_cb.sco_cb.sco_db[sco_inx].esco.p_esco_cback = NULL;
+        return (BTM_MODE_UNSUPPORTED);
+    }
+
+    if (sco_inx < BTM_MAX_SCO_LINKS &&
+        btm_cb.sco_cb.sco_db[sco_inx].state != SCO_ST_UNUSED)
+    {
+        btm_cb.sco_cb.sco_db[sco_inx].esco.p_esco_cback = p_esco_cback;
+        return (BTM_SUCCESS);
+    }
+    return (BTM_ILLEGAL_VALUE);
+#else
+    return (BTM_MODE_UNSUPPORTED);
+#endif
+}
+
+/*******************************************************************************
+**
+** 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.
+**
+** Returns          BTM_SUCCESS if returned data is valid connection.
+**                  BTM_WRONG_MODE if no connection with a peer device or bad sco_inx.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ReadEScoLinkParms (uint16_t sco_inx, tBTM_ESCO_DATA *p_parms)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    uint8_t index;
+
+    BTM_TRACE_API("BTM_ReadEScoLinkParms -> sco_inx 0x%04x", sco_inx);
+
+    if (sco_inx < BTM_MAX_SCO_LINKS &&
+        btm_cb.sco_cb.sco_db[sco_inx].state >= SCO_ST_CONNECTED)
+    {
+        *p_parms = btm_cb.sco_cb.sco_db[sco_inx].esco.data;
+        return (BTM_SUCCESS);
+    }
+
+    if (sco_inx == BTM_FIRST_ACTIVE_SCO_INDEX)
+    {
+        for (index = 0; index < BTM_MAX_SCO_LINKS; index++)
+        {
+            if (btm_cb.sco_cb.sco_db[index].state >= SCO_ST_CONNECTED)
+            {
+                BTM_TRACE_API("BTM_ReadEScoLinkParms the first active SCO index is %d",index);
+                *p_parms = btm_cb.sco_cb.sco_db[index].esco.data;
+                return (BTM_SUCCESS);
+            }
+        }
+    }
+
+#endif
+
+    BTM_TRACE_API("BTM_ReadEScoLinkParms cannot find the SCO index!");
+    memset(p_parms, 0, sizeof(tBTM_ESCO_DATA));
+    return (BTM_WRONG_MODE);
+}
+
+/*******************************************************************************
+**
+** 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.
+**
+**                  Note: If called over a SCO link (including 1.1 controller),
+**                        a change packet type request is sent out instead.
+**
+** Returns          BTM_CMD_STARTED if command is successfully initiated.
+**                  BTM_NO_RESOURCES - not enough resources to initiate command.
+**                  BTM_WRONG_MODE if no connection with a peer device or bad sco_inx.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_ChangeEScoLinkParms (uint16_t sco_inx, tBTM_CHG_ESCO_PARAMS *p_parms)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    tBTM_ESCO_PARAMS *p_setup;
+    tSCO_CONN        *p_sco;
+    uint16_t          temp_pkt_types;
+
+    /* Make sure sco handle is valid and on an active link */
+    if (sco_inx >= BTM_MAX_SCO_LINKS ||
+        btm_cb.sco_cb.sco_db[sco_inx].state != SCO_ST_CONNECTED)
+        return (BTM_WRONG_MODE);
+
+    p_sco = &btm_cb.sco_cb.sco_db[sco_inx];
+    p_setup = &p_sco->esco.setup;
+
+    /* If SCO connection OR eSCO not supported just send change packet types */
+    if (p_sco->esco.data.link_type == BTM_LINK_TYPE_SCO ||
+        !btm_cb.sco_cb.esco_supported)
+    {
+        p_setup->packet_types = p_parms->packet_types &
+            (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_LINK_ONLY_MASK);
+
+
+        BTM_TRACE_API("BTM_ChangeEScoLinkParms -> SCO Link for handle 0x%04x, pkt 0x%04x",
+                         p_sco->hci_handle, p_setup->packet_types);
+
+        btsnd_hcic_change_conn_type(p_sco->hci_handle,
+                                    BTM_ESCO_2_SCO(p_setup->packet_types));
+    }
+    else
+    {
+        temp_pkt_types = (p_parms->packet_types & BTM_SCO_SUPPORTED_PKTS_MASK &
+                             btm_cb.btm_sco_pkt_types_supported);
+
+        /* OR in any exception packet types */
+        temp_pkt_types |= ((p_parms->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
+            (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
+
+        BTM_TRACE_API("BTM_ChangeEScoLinkParms -> eSCO Link for handle 0x%04x", p_sco->hci_handle);
+        BTM_TRACE_API("      txbw 0x%x, rxbw 0x%x, lat 0x%x, voice 0x%x, retrans 0x%02x, pkt 0x%04x",
+                         p_setup->tx_bw, p_setup->rx_bw, p_parms->max_latency,
+                         p_setup->voice_contfmt, p_parms->retrans_effort, temp_pkt_types);
+
+        /* When changing an existing link, only change latency, retrans, and pkts */
+        btsnd_hcic_setup_esco_conn(p_sco->hci_handle, p_setup->tx_bw,
+                                   p_setup->rx_bw, p_parms->max_latency,
+                                   p_setup->voice_contfmt,
+                                   p_parms->retrans_effort,
+                                   temp_pkt_types);
+        p_parms->packet_types = temp_pkt_types;
+    }
+
+    return (BTM_CMD_STARTED);
+#else
+    return (BTM_WRONG_MODE);
+#endif
+}
+
+/*******************************************************************************
+**
+** 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, tBTM_ESCO_PARAMS *p_parms)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    if (sco_inx < BTM_MAX_SCO_LINKS &&
+        btm_cb.sco_cb.sco_db[sco_inx].state == SCO_ST_W4_CONN_RSP)
+    {
+        btm_esco_conn_rsp(sco_inx, hci_status,
+                          btm_cb.sco_cb.sco_db[sco_inx].esco.data.bd_addr,
+                          p_parms);
+    }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btm_read_def_esco_mode
+**
+** Description      This function copies the current default esco settings into
+**                  the return buffer.
+**
+** Returns          tBTM_SCO_TYPE
+**
+*******************************************************************************/
+tBTM_SCO_TYPE btm_read_def_esco_mode (tBTM_ESCO_PARAMS *p_parms)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    *p_parms = btm_cb.sco_cb.def_esco_parms;
+    return btm_cb.sco_cb.desired_sco_mode;
+#else
+    return BTM_LINK_TYPE_SCO;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btm_esco_proc_conn_chg
+**
+** Description      This function is called by BTIF when an SCO connection
+**                  is changed.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_esco_proc_conn_chg (uint8_t status, uint16_t handle, uint8_t tx_interval,
+                             uint8_t retrans_window, uint16_t rx_pkt_len,
+                             uint16_t tx_pkt_len)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    tSCO_CONN               *p = &btm_cb.sco_cb.sco_db[0];
+    tBTM_CHG_ESCO_EVT_DATA   data;
+    uint16_t                 xx;
+
+    BTM_TRACE_EVENT("btm_esco_proc_conn_chg -> handle 0x%04x, status 0x%02x",
+                      handle, status);
+
+    for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+    {
+        if (p->state == SCO_ST_CONNECTED && handle == p->hci_handle)
+        {
+            /* If upper layer wants notification */
+            if (p->esco.p_esco_cback)
+            {
+                memcpy(data.bd_addr, p->esco.data.bd_addr, BD_ADDR_LEN);
+                data.hci_status = status;
+                data.sco_inx = xx;
+                data.rx_pkt_len = p->esco.data.rx_pkt_len = rx_pkt_len;
+                data.tx_pkt_len = p->esco.data.tx_pkt_len = tx_pkt_len;
+                data.tx_interval = p->esco.data.tx_interval = tx_interval;
+                data.retrans_window = p->esco.data.retrans_window = retrans_window;
+
+                (*p->esco.p_esco_cback)(BTM_ESCO_CHG_EVT,
+                                        (tBTM_ESCO_EVT_DATA *)&data);
+            }
+            return;
+        }
+    }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btm_is_sco_active
+**
+** Description      This function is called to see if a SCO handle is already in
+**                  use.
+**
+** Returns          bool
+**
+*******************************************************************************/
+bool    btm_is_sco_active (uint16_t handle)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    uint16_t   xx;
+    tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+
+    for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+    {
+        if (handle == p->hci_handle && p->state == SCO_ST_CONNECTED)
+            return (true);
+    }
+#endif
+    return (false);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_GetNumScoLinks
+**
+** Description      This function returns the number of active sco links.
+**
+** Returns          uint8_t
+**
+*******************************************************************************/
+uint8_t BTM_GetNumScoLinks (void)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+    uint16_t   xx;
+    uint8_t    num_scos = 0;
+
+    for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+    {
+        switch (p->state)
+        {
+        case SCO_ST_W4_CONN_RSP:
+        case SCO_ST_CONNECTING:
+        case SCO_ST_CONNECTED:
+        case SCO_ST_DISCONNECTING:
+        case SCO_ST_PEND_UNPARK:
+            num_scos++;
+        }
+    }
+    return (num_scos);
+#else
+    return (0);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function         btm_is_sco_active_by_bdaddr
+**
+** Description      This function is called to see if a SCO active to a bd address.
+**
+** Returns          bool
+**
+*******************************************************************************/
+bool    btm_is_sco_active_by_bdaddr (BD_ADDR remote_bda)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    uint8_t xx;
+    tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
+
+    /* If any SCO is being established to the remote BD address, refuse this */
+    for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+    {
+        if ((!memcmp (p->esco.data.bd_addr, remote_bda, BD_ADDR_LEN)) && (p->state == SCO_ST_CONNECTED))
+        {
+            return (true);
+        }
+    }
+#endif
+    return (false);
+}
+#else   /* SCO_EXCLUDED == TRUE (Link in stubs) */
+
+tBTM_STATUS BTM_CreateSco (BD_ADDR 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) {return (BTM_NO_RESOURCES);}
+tBTM_STATUS BTM_RemoveSco (uint16_t sco_inx) {return (BTM_NO_RESOURCES);}
+tBTM_STATUS BTM_SetScoPacketTypes (uint16_t sco_inx, uint16_t pkt_types) {return (BTM_NO_RESOURCES);}
+uint16_t BTM_ReadScoPacketTypes (uint16_t sco_inx) {return (0);}
+uint16_t BTM_ReadDeviceScoPacketTypes (void) {return (0);}
+uint16_t BTM_ReadScoHandle (uint16_t sco_inx) {return (BTM_INVALID_HCI_HANDLE);}
+uint8_t *BTM_ReadScoBdAddr(uint16_t sco_inx) {return((uint8_t *) NULL);}
+uint16_t BTM_ReadScoDiscReason (void) {return (BTM_INVALID_SCO_DISC_REASON);}
+tBTM_STATUS BTM_SetEScoMode (tBTM_SCO_TYPE sco_mode, tBTM_ESCO_PARAMS *p_parms) {return (BTM_MODE_UNSUPPORTED);}
+tBTM_STATUS BTM_RegForEScoEvts (uint16_t sco_inx, tBTM_ESCO_CBACK *p_esco_cback) { return (BTM_ILLEGAL_VALUE);}
+tBTM_STATUS BTM_ReadEScoLinkParms (uint16_t sco_inx, tBTM_ESCO_DATA *p_parms) { return (BTM_MODE_UNSUPPORTED);}
+tBTM_STATUS BTM_ChangeEScoLinkParms (uint16_t sco_inx, tBTM_CHG_ESCO_PARAMS *p_parms) { return (BTM_MODE_UNSUPPORTED);}
+void BTM_EScoConnRsp (uint16_t sco_inx, uint8_t hci_status, tBTM_ESCO_PARAMS *p_parms) {}
+uint8_t BTM_GetNumScoLinks (void)  {return (0);}
+
+#endif /* If SCO is being used */
diff --git a/bt/stack/btm/btm_sec.cc b/bt/stack/btm/btm_sec.cc
new file mode 100644
index 0000000..cc48e7d
--- /dev/null
+++ b/bt/stack/btm/btm_sec.cc
@@ -0,0 +1,6299 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 functions for the Bluetooth Security Manager
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btm_sec"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "device/include/controller.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/time.h"
+
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+
+#if (BLE_INCLUDED == TRUE)
+    #include "gatt_int.h"
+#endif
+
+#define BTM_SEC_MAX_COLLISION_DELAY     (5000)
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+#ifdef APPL_AUTH_WRITE_EXCEPTION
+bool    (APPL_AUTH_WRITE_EXCEPTION)(BD_ADDR bd_addr);
+#endif
+
+/********************************************************************************
+**              L O C A L    F U N C T I O N     P R O T O T Y P E S            *
+*********************************************************************************/
+tBTM_SEC_SERV_REC *btm_sec_find_first_serv (bool    is_originator, uint16_t psm);
+static tBTM_SEC_SERV_REC *btm_sec_find_next_serv (tBTM_SEC_SERV_REC *p_cur);
+static tBTM_SEC_SERV_REC *btm_sec_find_mx_serv (uint8_t is_originator, uint16_t psm,
+                                                uint32_t mx_proto_id,
+                                                uint32_t mx_chan_id);
+
+static tBTM_STATUS btm_sec_execute_procedure (tBTM_SEC_DEV_REC *p_dev_rec);
+static bool     btm_sec_start_get_name (tBTM_SEC_DEV_REC *p_dev_rec);
+static void     btm_sec_start_authentication (tBTM_SEC_DEV_REC *p_dev_rec);
+static void     btm_sec_start_encryption (tBTM_SEC_DEV_REC *p_dev_rec);
+static void     btm_sec_collision_timeout(void *data);
+static void     btm_restore_mode(void);
+static void     btm_sec_pairing_timeout(void *data);
+static tBTM_STATUS btm_sec_dd_create_conn (tBTM_SEC_DEV_REC *p_dev_rec);
+static void     btm_sec_change_pairing_state (tBTM_PAIRING_STATE new_state);
+
+static char     *btm_pair_state_descr (tBTM_PAIRING_STATE state);
+
+static void     btm_sec_check_pending_reqs(void);
+static bool     btm_sec_queue_mx_request (BD_ADDR bd_addr,  uint16_t psm,  bool    is_orig,
+                                          uint32_t mx_proto_id, uint32_t mx_chan_id,
+                                          tBTM_SEC_CALLBACK *p_callback, void *p_ref_data);
+static void     btm_sec_bond_cancel_complete (void);
+static void     btm_send_link_key_notif (tBTM_SEC_DEV_REC *p_dev_rec);
+static bool     btm_sec_check_prefetch_pin (tBTM_SEC_DEV_REC  *p_dev_rec);
+
+static uint8_t  btm_sec_start_authorization (tBTM_SEC_DEV_REC *p_dev_rec);
+bool            btm_sec_are_all_trusted(uint32_t p_mask[]);
+
+static tBTM_STATUS btm_sec_send_hci_disconnect (tBTM_SEC_DEV_REC *p_dev_rec, uint8_t reason, uint16_t conn_handle);
+uint8_t         btm_sec_start_role_switch (tBTM_SEC_DEV_REC *p_dev_rec);
+tBTM_SEC_DEV_REC *btm_sec_find_dev_by_sec_state (uint8_t state);
+
+static bool     btm_sec_set_security_level ( CONNECTION_TYPE conn_type, 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);
+
+static bool    btm_dev_authenticated(tBTM_SEC_DEV_REC *p_dev_rec);
+static bool    btm_dev_encrypted(tBTM_SEC_DEV_REC *p_dev_rec);
+static bool    btm_dev_authorized(tBTM_SEC_DEV_REC *p_dev_rec);
+static bool    btm_serv_trusted(tBTM_SEC_DEV_REC *p_dev_rec, tBTM_SEC_SERV_REC *p_serv_rec);
+static bool    btm_sec_is_serv_level0 (uint16_t psm);
+static uint16_t btm_sec_set_serv_level4_flags (uint16_t cur_security, bool    is_originator);
+
+static bool    btm_sec_queue_encrypt_request  (BD_ADDR bd_addr, tBT_TRANSPORT transport,
+                                         tBTM_SEC_CALLBACK *p_callback, void *p_ref_data,
+                                         tBTM_BLE_SEC_ACT sec_act);
+static void btm_sec_check_pending_enc_req (tBTM_SEC_DEV_REC  *p_dev_rec, tBT_TRANSPORT transport,
+                                            uint8_t encr_enable);
+
+static bool    btm_sec_use_smp_br_chnl(tBTM_SEC_DEV_REC *p_dev_rec);
+static bool    btm_sec_is_master(tBTM_SEC_DEV_REC *p_dev_rec);
+
+/* true - authenticated link key is possible */
+static const bool    btm_sec_io_map [BTM_IO_CAP_MAX][BTM_IO_CAP_MAX] =
+{
+    /*   OUT,    IO,     IN,     NONE */
+/* OUT  */ {false,  false,  true,   false},
+/* IO   */ {false,  true,   true,   false},
+/* IN   */ {true,   true,   true,   false},
+/* NONE */ {false,  false,  false,  false}
+};
+/*  BTM_IO_CAP_OUT      0   DisplayOnly */
+/*  BTM_IO_CAP_IO       1   DisplayYesNo */
+/*  BTM_IO_CAP_IN       2   KeyboardOnly */
+/*  BTM_IO_CAP_NONE     3   NoInputNoOutput */
+
+/*******************************************************************************
+**
+** Function         btm_dev_authenticated
+**
+** Description      check device is authenticated
+**
+** Returns          bool    true or false
+**
+*******************************************************************************/
+static bool    btm_dev_authenticated (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+    if(p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)
+    {
+        return(true);
+    }
+    return(false);
+}
+
+/*******************************************************************************
+**
+** Function         btm_dev_encrypted
+**
+** Description      check device is encrypted
+**
+** Returns          bool    true or false
+**
+*******************************************************************************/
+static bool    btm_dev_encrypted (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+    if(p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED)
+    {
+        return(true);
+    }
+    return(false);
+}
+
+/*******************************************************************************
+**
+** Function         btm_dev_authorized
+**
+** Description      check device is authorized
+**
+** Returns          bool    true or false
+**
+*******************************************************************************/
+static bool    btm_dev_authorized (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+    if(p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED)
+    {
+        return(true);
+    }
+    return(false);
+}
+
+/*******************************************************************************
+**
+** Function         btm_dev_16_digit_authenticated
+**
+** Description      check device is authenticated by using 16 digit pin or MITM
+**
+** Returns          bool    true or false
+**
+*******************************************************************************/
+static bool    btm_dev_16_digit_authenticated(tBTM_SEC_DEV_REC *p_dev_rec)
+{
+    // BTM_SEC_16_DIGIT_PIN_AUTHED is set if MITM or 16 digit pin is used
+    if(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED)
+    {
+        return(true);
+    }
+    return(false);
+}
+
+/*******************************************************************************
+**
+** Function         btm_serv_trusted
+**
+** Description      check service is trusted
+**
+** Returns          bool    true or false
+**
+*******************************************************************************/
+static bool    btm_serv_trusted(tBTM_SEC_DEV_REC *p_dev_rec, tBTM_SEC_SERV_REC *p_serv_rec)
+{
+    if(BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask, p_serv_rec->service_id))
+    {
+        return(true);
+    }
+    return(false);
+}
+
+/*******************************************************************************
+**
+** 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(tBTM_APPL_INFO *p_cb_info)
+{
+#if (BLE_INCLUDED == TRUE)
+    BT_OCTET16      temp_value = {0};
+#endif
+
+    BTM_TRACE_EVENT("%s application registered", __func__);
+
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+    LOG_INFO(LOG_TAG, "%s p_cb_info->p_le_callback == 0x%p", __func__, p_cb_info->p_le_callback);
+    if (p_cb_info->p_le_callback)
+    {
+#if (SMP_INCLUDED == TRUE)
+      BTM_TRACE_EVENT("%s SMP_Register( btm_proc_smp_cback )", __func__);
+      SMP_Register(btm_proc_smp_cback);
+#endif
+      /* if no IR is loaded, need to regenerate all the keys */
+      if (memcmp(btm_cb.devcb.id_keys.ir, &temp_value, sizeof(BT_OCTET16)) == 0)
+      {
+        btm_ble_reset_id();
+      }
+    }
+    else
+    {
+      LOG_WARN(LOG_TAG, "%s p_cb_info->p_le_callback == NULL", __func__);
+    }
+#endif /* (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE) */
+
+    btm_cb.api = *p_cb_info;
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+     LOG_INFO(LOG_TAG, "%s btm_cb.api.p_le_callback = 0x%p ", __func__, btm_cb.api.p_le_callback);
+#endif
+    BTM_TRACE_EVENT("%s application registered", __func__);
+    return(true);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_SecRegisterLinkKeyNotificationCallback
+**
+** Description      Application manager calls this function to register for
+**                  link key notification.  When there is nobody registered
+**                  we should avoid changing link key
+**
+** Returns          true if registered OK, else false
+**
+*******************************************************************************/
+bool    BTM_SecRegisterLinkKeyNotificationCallback (tBTM_LINK_KEY_CALLBACK *p_callback)
+{
+    btm_cb.api.p_link_key_callback = p_callback;
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         BTM_SecAddRmtNameNotifyCallback
+**
+** Description      Any profile can register to be notified when name of the
+**                  remote device is resolved.
+**
+** Returns          true if registered OK, else false
+**
+*******************************************************************************/
+bool     BTM_SecAddRmtNameNotifyCallback (tBTM_RMT_NAME_CALLBACK *p_callback)
+{
+    int i;
+
+    for (i = 0; i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++)
+    {
+        if (btm_cb.p_rmt_name_callback[i] == NULL)
+        {
+            btm_cb.p_rmt_name_callback[i] = p_callback;
+            return(true);
+        }
+    }
+
+    return(false);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_SecDeleteRmtNameNotifyCallback
+**
+** Description      Any 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)
+{
+    int i;
+
+    for (i = 0; i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++)
+    {
+        if (btm_cb.p_rmt_name_callback[i] == p_callback)
+        {
+            btm_cb.p_rmt_name_callback[i] = NULL;
+            return(true);
+        }
+    }
+
+    return(false);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_GetSecurityFlags
+**
+** Description      Get security flags for the device
+**
+** Returns          bool    true or false is device found
+**
+*******************************************************************************/
+bool    BTM_GetSecurityFlags (BD_ADDR bd_addr, uint8_t * p_sec_flags)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec;
+
+    if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL)
+    {
+        *p_sec_flags = (uint8_t) p_dev_rec->sec_flags;
+        return(true);
+    }
+    BTM_TRACE_ERROR ("BTM_GetSecurityFlags false");
+    return(false);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_GetSecurityFlagsByTransport
+**
+** Description      Get security flags for the device on a particular transport
+**
+** Returns          bool    true or false is device found
+**
+*******************************************************************************/
+bool    BTM_GetSecurityFlagsByTransport (BD_ADDR bd_addr, uint8_t * p_sec_flags,
+                                                tBT_TRANSPORT transport)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec;
+
+    if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL)
+    {
+        if (transport == BT_TRANSPORT_BR_EDR)
+            *p_sec_flags = (uint8_t) p_dev_rec->sec_flags;
+        else
+            *p_sec_flags = (uint8_t) (p_dev_rec->sec_flags >> 8);
+
+        return(true);
+    }
+    BTM_TRACE_ERROR ("BTM_GetSecurityFlags false");
+    return(false);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    BTM_TRACE_API ("BTM_SetPinType: pin type %d [variable-0, fixed-1], code %s, length %d",
+                    pin_type, (char *) pin_code, pin_code_len);
+
+    /* If device is not up security mode will be set as a part of startup */
+    if ( (btm_cb.cfg.pin_type != pin_type)
+         && controller_get_interface()->get_is_ready() )
+    {
+        btsnd_hcic_write_pin_type (pin_type);
+    }
+
+    btm_cb.cfg.pin_type     = pin_type;
+    btm_cb.cfg.pin_code_len = pin_code_len;
+    memcpy (btm_cb.cfg.pin_code, pin_code, 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)
+{
+    BTM_TRACE_API ("BTM_SetPairableMode()  allow_pairing: %u   connect_only_paired: %u", allow_pairing, connect_only_paired);
+
+    btm_cb.pairing_disabled    = !allow_pairing;
+    btm_cb.connect_only_paired = 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) whether or not the device
+**                  true means that the device should treat Mode 4 Level 0 services as
+**                  services of other levels. (Secure_connections_only_mode)
+**                  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)
+{
+    BTM_TRACE_API("%s: Mode : %u", __func__,
+                   secure_connections_only_mode);
+
+    btm_cb.devcb.secure_connections_only = secure_connections_only_mode;
+    btm_cb.security_mode = BTM_SEC_MODE_SC;
+}
+#define BTM_NO_AVAIL_SEC_SERVICES   ((uint16_t) 0xffff)
+
+/*******************************************************************************
+**
+** Function         BTM_SetSecurityLevel
+**
+** Description      Register service security level with Security Manager
+**
+** Parameters:      is_originator - true if originating the connection, false if not
+**                  p_name      - Name of the service relevant only if
+**                                authorization will show this name to user. ignored
+**                                if BTM_SEC_SERVICE_NAME_LEN is 0.
+**                  service_id  - service ID for the service passed to authorization callback
+**                  sec_level   - bit mask of the security features
+**                  psm         - L2CAP PSM
+**                  mx_proto_id - protocol ID of multiplexing proto below
+**                  mx_chan_id  - channel ID of multiplexing proto below
+**
+** 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)
+{
+#if (L2CAP_UCD_INCLUDED == TRUE)
+    CONNECTION_TYPE conn_type;
+
+    if (is_originator)
+        conn_type = CONN_ORIENT_ORIG;
+    else
+        conn_type = CONN_ORIENT_TERM;
+
+    return(btm_sec_set_security_level (conn_type, p_name, service_id,
+                                       sec_level, psm, mx_proto_id, mx_chan_id));
+#else
+    return(btm_sec_set_security_level (is_originator, p_name, service_id,
+                                       sec_level, psm, mx_proto_id, mx_chan_id));
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_set_security_level
+**
+** Description      Register service security level with Security Manager
+**
+** Parameters:      conn_type   - true if originating the connection, false if not
+**                  p_name      - Name of the service relevant only if
+**                                authorization will show this name to user. ignored
+**                                if BTM_SEC_SERVICE_NAME_LEN is 0.
+**                  service_id  - service ID for the service passed to authorization callback
+**                  sec_level   - bit mask of the security features
+**                  psm         - L2CAP PSM
+**                  mx_proto_id - protocol ID of multiplexing proto below
+**                  mx_chan_id  - channel ID of multiplexing proto below
+**
+** Returns          true if registered OK, else false
+**
+*******************************************************************************/
+static bool    btm_sec_set_security_level (CONNECTION_TYPE conn_type, 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)
+{
+    tBTM_SEC_SERV_REC   *p_srec;
+    uint16_t             index;
+    uint16_t             first_unused_record = BTM_NO_AVAIL_SEC_SERVICES;
+    bool                 record_allocated = false;
+    bool                 is_originator;
+#if (L2CAP_UCD_INCLUDED == TRUE)
+    bool                 is_ucd;
+
+    if (conn_type & CONNECTION_TYPE_ORIG_MASK)
+        is_originator = true;
+    else
+        is_originator = false;
+
+    if (conn_type & CONNECTION_TYPE_CONNLESS_MASK )
+    {
+        is_ucd = true;
+    }
+    else
+    {
+        is_ucd = false;
+    }
+#else
+    is_originator = conn_type;
+#endif
+
+    BTM_TRACE_API("%s : sec: 0x%x", __func__, sec_level);
+
+    /* See if the record can be reused (same service name, psm, mx_proto_id,
+       service_id, and mx_chan_id), or obtain the next unused record */
+
+    p_srec = &btm_cb.sec_serv_rec[0];
+
+    for (index = 0; index < BTM_SEC_MAX_SERVICE_RECORDS; index++, p_srec++)
+    {
+        /* Check if there is already a record for this service */
+        if (p_srec->security_flags & BTM_SEC_IN_USE)
+        {
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+            if (p_srec->psm == psm                  &&
+                p_srec->mx_proto_id == mx_proto_id  &&
+                service_id == p_srec->service_id    &&
+                p_name                              &&
+                (!strncmp (p_name, (char *) p_srec->orig_service_name,
+                           BTM_SEC_SERVICE_NAME_LEN) ||
+                 !strncmp (p_name, (char *) p_srec->term_service_name,
+                           BTM_SEC_SERVICE_NAME_LEN)))
+#else
+            if (p_srec->psm == psm                  &&
+                p_srec->mx_proto_id == mx_proto_id  &&
+                service_id == p_srec->service_id)
+#endif
+            {
+                record_allocated = true;
+                break;
+            }
+        }
+        /* Mark the first available service record */
+        else if (!record_allocated)
+        {
+            memset (p_srec, 0, sizeof(tBTM_SEC_SERV_REC));
+            record_allocated = true;
+            first_unused_record = index;
+        }
+    }
+
+    if (!record_allocated)
+    {
+        BTM_TRACE_WARNING("BTM_SEC_REG: Out of Service Records (%d)",  BTM_SEC_MAX_SERVICE_RECORDS);
+        return(record_allocated);
+    }
+
+    /* Process the request if service record is valid */
+    /* If a duplicate service wasn't found, use the first available */
+    if (index >= BTM_SEC_MAX_SERVICE_RECORDS)
+    {
+        index = first_unused_record;
+        p_srec = &btm_cb.sec_serv_rec[index];
+    }
+
+    p_srec->psm         = psm;
+    p_srec->service_id  = service_id;
+    p_srec->mx_proto_id = mx_proto_id;
+
+    if (is_originator)
+    {
+        p_srec->orig_mx_chan_id = mx_chan_id;
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+        strlcpy ((char *)p_srec->orig_service_name, p_name, BTM_SEC_SERVICE_NAME_LEN + 1);
+#endif
+        /* clear out the old setting, just in case it exists */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+        if ( is_ucd )
+        {
+            p_srec->ucd_security_flags &=
+            ~(BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_ENCRYPT    | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM |
+              BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE);
+        }
+        else
+#endif
+        {
+            p_srec->security_flags &=
+            ~(BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_ENCRYPT    | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM |
+              BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE);
+        }
+
+        /* Parameter validation.  Originator should not set requirements for incoming connections */
+        sec_level &= ~(BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE
+                | BTM_SEC_IN_MITM | BTM_SEC_IN_MIN_16_DIGIT_PIN );
+
+        if (btm_cb.security_mode == BTM_SEC_MODE_SP ||
+            btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG ||
+            btm_cb.security_mode == BTM_SEC_MODE_SC)
+        {
+            if (sec_level & BTM_SEC_OUT_AUTHENTICATE)
+                sec_level |= BTM_SEC_OUT_MITM;
+        }
+
+        /* Make sure the authenticate bit is set, when encrypt bit is set */
+        if (sec_level & BTM_SEC_OUT_ENCRYPT)
+            sec_level |= BTM_SEC_OUT_AUTHENTICATE;
+
+        /* outgoing connections usually set the security level right before
+         * the connection is initiated.
+         * set it to be the outgoing service */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+        if ( is_ucd == false )
+#endif
+        {
+            btm_cb.p_out_serv = p_srec;
+        }
+    }
+    else
+    {
+        p_srec->term_mx_chan_id = mx_chan_id;
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+        strlcpy ((char *)p_srec->term_service_name, p_name, BTM_SEC_SERVICE_NAME_LEN + 1);
+#endif
+        /* clear out the old setting, just in case it exists */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+        if ( is_ucd )
+        {
+            p_srec->ucd_security_flags &=
+            ~(BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT     | BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_MITM |
+              BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE
+              | BTM_SEC_IN_MIN_16_DIGIT_PIN);
+        }
+        else
+#endif
+        {
+            p_srec->security_flags &=
+            ~(BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT     | BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_MITM |
+              BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE
+              | BTM_SEC_IN_MIN_16_DIGIT_PIN);
+        }
+
+        /* Parameter validation.  Acceptor should not set requirements for outgoing connections */
+        sec_level &= ~(BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM);
+
+        if (btm_cb.security_mode == BTM_SEC_MODE_SP ||
+            btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG ||
+            btm_cb.security_mode == BTM_SEC_MODE_SC)
+        {
+            if (sec_level & BTM_SEC_IN_AUTHENTICATE)
+                sec_level |= BTM_SEC_IN_MITM;
+        }
+
+        /* Make sure the authenticate bit is set, when encrypt bit is set */
+        if (sec_level & BTM_SEC_IN_ENCRYPT)
+            sec_level |= BTM_SEC_IN_AUTHENTICATE;
+    }
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+    if ( is_ucd )
+    {
+        p_srec->security_flags     |= (uint16_t)(BTM_SEC_IN_USE);
+        p_srec->ucd_security_flags |= (uint16_t)(sec_level | BTM_SEC_IN_USE);
+    }
+    else
+    {
+        p_srec->security_flags |= (uint16_t)(sec_level | BTM_SEC_IN_USE);
+    }
+
+    BTM_TRACE_API("BTM_SEC_REG[%d]: id %d, conn_type 0x%x, psm 0x%04x, proto_id %d, chan_id %d",
+                   index, service_id, conn_type, psm, mx_proto_id, mx_chan_id);
+
+    BTM_TRACE_API("               : security_flags: 0x%04x, ucd_security_flags: 0x%04x",
+                   p_srec->security_flags, p_srec->ucd_security_flags);
+
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+    BTM_TRACE_API("               : service name [%s] (up to %d chars saved)",
+                   p_name, BTM_SEC_SERVICE_NAME_LEN);
+#endif
+#else
+    p_srec->security_flags |= (uint16_t)(sec_level | BTM_SEC_IN_USE);
+
+    BTM_TRACE_API("BTM_SEC_REG[%d]: id %d, is_orig %d, psm 0x%04x, proto_id %d, chan_id %d",
+                   index, service_id, is_originator, psm, mx_proto_id, mx_chan_id);
+
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+    BTM_TRACE_API("               : sec: 0x%x, service name [%s] (up to %d chars saved)",
+                   p_srec->security_flags, p_name, BTM_SEC_SERVICE_NAME_LEN);
+#endif
+#endif
+
+    return(record_allocated);
+}
+
+/*******************************************************************************
+**
+** 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.
+**
+**                  Note: Unpredictable results may occur if a service is cleared
+**                      that is still in use by an application/profile.
+**
+** Parameters       Service ID - Id of the service to remove. ('0' removes all service
+**                          records (except SDP).
+**
+** Returns          Number of records that were freed.
+**
+*******************************************************************************/
+uint8_t BTM_SecClrService (uint8_t service_id)
+{
+    tBTM_SEC_SERV_REC   *p_srec = &btm_cb.sec_serv_rec[0];
+    uint8_t num_freed = 0;
+    int     i;
+
+    for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_srec++)
+    {
+        /* Delete services with specified name (if in use and not SDP) */
+        if ((p_srec->security_flags & BTM_SEC_IN_USE) && (p_srec->psm != BT_PSM_SDP) &&
+            (!service_id || (service_id == p_srec->service_id)))
+        {
+            BTM_TRACE_API("BTM_SEC_CLR[%d]: id %d", i, service_id);
+            p_srec->security_flags = 0;
+#if (L2CAP_UCD_INCLUDED == TRUE)
+            p_srec->ucd_security_flags = 0;
+#endif
+            num_freed++;
+        }
+    }
+
+    return(num_freed);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_clr_service_by_psm
+**
+** Description      Removes specified service record from the security database.
+**                  All service records with the specified psm are removed.
+**                  Typically used by L2CAP to free up the service record used
+**                  by dynamic PSM clients when the channel is closed.
+**                  The given psm must be a virtual psm.
+**
+** Parameters       Service ID - Id of the service to remove. ('0' removes all service
+**                          records (except SDP).
+**
+** Returns          Number of records that were freed.
+**
+*******************************************************************************/
+uint8_t btm_sec_clr_service_by_psm (uint16_t psm)
+{
+    tBTM_SEC_SERV_REC   *p_srec = &btm_cb.sec_serv_rec[0];
+    uint8_t num_freed = 0;
+    int     i;
+
+    for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_srec++)
+    {
+        /* Delete services with specified name (if in use and not SDP) */
+        if ((p_srec->security_flags & BTM_SEC_IN_USE) && (p_srec->psm == psm) )
+        {
+            BTM_TRACE_API("BTM_SEC_CLR[%d]: id %d ", i, p_srec->service_id);
+            p_srec->security_flags = 0;
+            num_freed++;
+        }
+    }
+    BTM_TRACE_API("btm_sec_clr_service_by_psm psm:0x%x num_freed:%d", psm, num_freed);
+
+    return(num_freed);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_clr_temp_auth_service
+**
+** Description      Removes specified device record's temporary authorization
+**                  flag from the security database.
+**
+** Parameters       Device address to be cleared
+**
+** Returns          void.
+**
+*******************************************************************************/
+void btm_sec_clr_temp_auth_service (BD_ADDR bda)
+{
+    tBTM_SEC_DEV_REC   *p_dev_rec;
+
+    if ((p_dev_rec = btm_find_dev (bda)) == NULL)
+    {
+        BTM_TRACE_WARNING ("btm_sec_clr_temp_auth_service() - no dev CB");
+        return;
+    }
+
+    /* Reset the temporary authorized flag so that next time (untrusted) service is accessed autorization will take place */
+    if (p_dev_rec->last_author_service_id != BTM_SEC_NO_LAST_SERVICE_ID && p_dev_rec->p_cur_service)
+    {
+        BTM_TRACE_DEBUG ("btm_sec_clr_auth_service_by_psm [clearing device: %02x:%02x:%02x:%02x:%02x:%02x]",
+                    bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+
+        p_dev_rec->last_author_service_id = BTM_SEC_NO_LAST_SERVICE_ID;
+    }
+}
+
+/*******************************************************************************
+**
+** 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)
+**
+*******************************************************************************/
+void BTM_PINCodeReply (BD_ADDR bd_addr, uint8_t res, uint8_t pin_len, uint8_t *p_pin, uint32_t trusted_mask[])
+{
+    tBTM_SEC_DEV_REC *p_dev_rec;
+
+    BTM_TRACE_API ("BTM_PINCodeReply(): PairState: %s   PairFlags: 0x%02x  PinLen:%d  Result:%d",
+                    btm_pair_state_descr(btm_cb.pairing_state), btm_cb.pairing_flags, pin_len, res);
+
+    /* If timeout already expired or has been canceled, ignore the reply */
+    if (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_PIN)
+    {
+        BTM_TRACE_WARNING ("BTM_PINCodeReply() - Wrong State: %d", btm_cb.pairing_state);
+        return;
+    }
+
+    if (memcmp (bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) != 0)
+    {
+        BTM_TRACE_ERROR ("BTM_PINCodeReply() - Wrong BD Addr");
+        return;
+    }
+
+    if ((p_dev_rec = btm_find_dev (bd_addr)) == NULL)
+    {
+        BTM_TRACE_ERROR ("BTM_PINCodeReply() - no dev CB");
+        return;
+    }
+
+    if ( (pin_len > PIN_CODE_LEN) || (pin_len == 0) || (p_pin == NULL) )
+        res = BTM_ILLEGAL_VALUE;
+
+    if (res != BTM_SUCCESS)
+    {
+        /* if peer started dd OR we started dd and pre-fetch pin was not used send negative reply */
+        if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_PEER_STARTED_DD) ||
+            ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) &&
+            (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE)) )
+        {
+            /* use BTM_PAIR_STATE_WAIT_AUTH_COMPLETE to report authentication failed event */
+            btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+            btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+
+            btsnd_hcic_pin_code_neg_reply (bd_addr);
+        }
+        else
+        {
+            p_dev_rec->security_required = BTM_SEC_NONE;
+            btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+        }
+        return;
+    }
+    if (trusted_mask)
+        BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);
+    p_dev_rec->sec_flags   |= BTM_SEC_LINK_KEY_AUTHED;
+    p_dev_rec->pin_code_length = pin_len;
+    if (pin_len >= 16) {
+        p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
+    }
+
+    if ( (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+         &&  (p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE)
+         &&  (btm_cb.security_mode_changed == false) )
+    {
+        /* This is start of the dedicated bonding if local device is 2.0 */
+        btm_cb.pin_code_len = pin_len;
+        memcpy (btm_cb.pin_code, p_pin, pin_len);
+
+        btm_cb.security_mode_changed = true;
+#ifdef APPL_AUTH_WRITE_EXCEPTION
+        if(!(APPL_AUTH_WRITE_EXCEPTION)(p_dev_rec->bd_addr))
+#endif
+        btsnd_hcic_write_auth_enable (true);
+
+        btm_cb.acl_disc_reason = 0xff ;
+
+        /* if we rejected incoming connection request, we have to wait HCI_Connection_Complete event */
+        /*  before originating  */
+        if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT)
+        {
+            BTM_TRACE_WARNING ("BTM_PINCodeReply(): waiting HCI_Connection_Complete after rejected incoming connection");
+            /* we change state little bit early so btm_sec_connected() will originate connection */
+            /*   when existing ACL link is down completely */
+            btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ);
+        }
+        /* if we already accepted incoming connection from pairing device */
+        else if (p_dev_rec->sm4 & BTM_SM4_CONN_PEND)
+        {
+            BTM_TRACE_WARNING ("BTM_PINCodeReply(): link is connecting so wait pin code request from peer");
+            btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ);
+        }
+        else if (btm_sec_dd_create_conn(p_dev_rec) != BTM_CMD_STARTED)
+        {
+            btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+            p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_AUTHED;
+
+            if (btm_cb.api.p_auth_complete_callback)
+                (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,  p_dev_rec->dev_class,
+                                                    p_dev_rec->sec_bd_name, HCI_ERR_AUTH_FAILURE);
+        }
+        return;
+    }
+
+    btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+    btm_cb.acl_disc_reason = HCI_SUCCESS;
+
+    btsnd_hcic_pin_code_req_reply (bd_addr, pin_len, p_pin);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_bond_by_transport
+**
+** Description      this is the bond function that will start either SSP or SMP.
+**
+** 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)
+**
+**  Note: After 2.1 parameters are not used and preserved here not to change API
+*******************************************************************************/
+tBTM_STATUS btm_sec_bond_by_transport (BD_ADDR bd_addr, tBT_TRANSPORT transport,
+                                       uint8_t pin_len, uint8_t *p_pin, uint32_t trusted_mask[])
+{
+    tBTM_SEC_DEV_REC *p_dev_rec;
+    tBTM_STATUS      status;
+    uint8_t          *p_features;
+    uint8_t          ii;
+    tACL_CONN        *p= btm_bda_to_acl(bd_addr, transport);
+    BTM_TRACE_API ("btm_sec_bond_by_transport BDA: %02x:%02x:%02x:%02x:%02x:%02x",
+                    bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+
+    BTM_TRACE_DEBUG("btm_sec_bond_by_transport: Transport used %d" , transport);
+
+    /* Other security process is in progress */
+    if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+    {
+        BTM_TRACE_ERROR ("BTM_SecBond: already busy in state: %s", btm_pair_state_descr(btm_cb.pairing_state));
+        return(BTM_WRONG_MODE);
+    }
+
+    if ((p_dev_rec = btm_find_or_alloc_dev (bd_addr)) == NULL)
+    {
+        return(BTM_NO_RESOURCES);
+    }
+
+    if (!controller_get_interface()->get_is_ready())
+    {
+        BTM_TRACE_ERROR ("%s controller module is not ready", __func__);
+        return(BTM_NO_RESOURCES);
+    }
+
+    BTM_TRACE_DEBUG ("before update sec_flags=0x%x", p_dev_rec->sec_flags);
+
+    /* Finished if connection is active and already paired */
+    if ( ((p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE) && transport == BT_TRANSPORT_BR_EDR
+         &&  (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))
+#if (BLE_INCLUDED == TRUE)
+        ||((p_dev_rec->ble_hci_handle != BTM_SEC_INVALID_HANDLE) && transport == BT_TRANSPORT_LE
+         &&  (p_dev_rec->sec_flags & BTM_SEC_LE_AUTHENTICATED))
+#endif
+
+         )
+    {
+        BTM_TRACE_WARNING("BTM_SecBond -> Already Paired");
+        return(BTM_SUCCESS);
+    }
+
+    /* Tell controller to get rid of the link key if it has one stored */
+    if ((BTM_DeleteStoredLinkKey (bd_addr, NULL)) != BTM_SUCCESS)
+        return(BTM_NO_RESOURCES);
+
+    /* Save the PIN code if we got a valid one */
+    if (p_pin && (pin_len <= PIN_CODE_LEN) && (pin_len != 0))
+    {
+        btm_cb.pin_code_len = pin_len;
+        p_dev_rec->pin_code_length = pin_len;
+        memcpy (btm_cb.pin_code, p_pin, PIN_CODE_LEN);
+    }
+
+    memcpy (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN);
+
+    btm_cb.pairing_flags = BTM_PAIR_FLAGS_WE_STARTED_DD;
+
+    p_dev_rec->security_required = BTM_SEC_OUT_AUTHENTICATE;
+    p_dev_rec->is_originator     = true;
+    if (trusted_mask)
+        BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);
+
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+    if (transport == BT_TRANSPORT_LE)
+    {
+        btm_ble_init_pseudo_addr (p_dev_rec, bd_addr);
+        p_dev_rec->sec_flags &= ~ BTM_SEC_LE_MASK;
+
+        if (SMP_Pair(bd_addr) == SMP_STARTED)
+        {
+            btm_cb.pairing_flags |= BTM_PAIR_FLAGS_LE_ACTIVE;
+            p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
+            btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+            return BTM_CMD_STARTED;
+        }
+
+        btm_cb.pairing_flags = 0;
+        return(BTM_NO_RESOURCES);
+    }
+#endif
+
+    p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED
+                                  | BTM_SEC_ROLE_SWITCHED  | BTM_SEC_LINK_KEY_AUTHED);
+
+    BTM_TRACE_DEBUG ("after update sec_flags=0x%x", p_dev_rec->sec_flags);
+    if (!controller_get_interface()->supports_simple_pairing())
+    {
+        /* The special case when we authenticate keyboard.  Set pin type to fixed */
+        /* It would be probably better to do it from the application, but it is */
+        /* complicated */
+        if (((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) == BTM_COD_MAJOR_PERIPHERAL)
+            && (p_dev_rec->dev_class[2] & BTM_COD_MINOR_KEYBOARD)
+            && (btm_cb.cfg.pin_type != HCI_PIN_TYPE_FIXED))
+        {
+            btm_cb.pin_type_changed = true;
+            btsnd_hcic_write_pin_type (HCI_PIN_TYPE_FIXED);
+        }
+    }
+
+    for (ii = 0; ii <= HCI_EXT_FEATURES_PAGE_MAX; ii++)
+    {
+        p_features = p_dev_rec->features[ii];
+        BTM_TRACE_EVENT("  remote_features page[%1d] = %02x-%02x-%02x-%02x",
+                         ii, p_features[0], p_features[1], p_features[2], p_features[3]);
+        BTM_TRACE_EVENT("                              %02x-%02x-%02x-%02x",
+                             p_features[4], p_features[5], p_features[6], p_features[7]);
+    }
+
+    BTM_TRACE_EVENT ("BTM_SecBond: Remote sm4: 0x%x  HCI Handle: 0x%04x", p_dev_rec->sm4, p_dev_rec->hci_handle);
+
+#if (BTM_SEC_FORCE_RNR_FOR_DBOND == TRUE)
+    p_dev_rec->sec_flags &= ~BTM_SEC_NAME_KNOWN;
+#endif
+
+    /* If connection already exists... */
+    if (p && p->hci_handle != BTM_SEC_INVALID_HANDLE)
+    {
+        btm_sec_start_authentication(p_dev_rec);
+
+        btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ);
+
+        /* Mark lcb as bonding */
+        l2cu_update_lcb_4_bonding (bd_addr, true);
+        return(BTM_CMD_STARTED);
+    }
+
+    BTM_TRACE_DEBUG ("sec mode: %d sm4:x%x", btm_cb.security_mode, p_dev_rec->sm4);
+    if (!controller_get_interface()->supports_simple_pairing()
+        || (p_dev_rec->sm4 == BTM_SM4_KNOWN))
+    {
+        if ( btm_sec_check_prefetch_pin (p_dev_rec) )
+            return (BTM_CMD_STARTED);
+    }
+    if ((btm_cb.security_mode == BTM_SEC_MODE_SP ||
+         btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG ||
+         btm_cb.security_mode == BTM_SEC_MODE_SC) &&
+         BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4))
+    {
+        /* local is 2.1 and peer is unknown */
+        if ((p_dev_rec->sm4 & BTM_SM4_CONN_PEND) == 0)
+        {
+            /* we are not accepting connection request from peer
+             * -> RNR (to learn if peer is 2.1)
+             * RNR when no ACL causes HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT */
+            btm_sec_change_pairing_state (BTM_PAIR_STATE_GET_REM_NAME);
+            BTM_ReadRemoteDeviceName(bd_addr, NULL, BT_TRANSPORT_BR_EDR);
+        }
+        else
+        {
+            /* We are accepting connection request from peer */
+            btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ);
+        }
+        BTM_TRACE_DEBUG ("State:%s sm4: 0x%x sec_state:%d",
+            btm_pair_state_descr (btm_cb.pairing_state), p_dev_rec->sm4, p_dev_rec->sec_state);
+        return BTM_CMD_STARTED;
+    }
+
+    /* both local and peer are 2.1  */
+    status = btm_sec_dd_create_conn(p_dev_rec);
+
+    if (status != BTM_CMD_STARTED)
+    {
+        btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+    }
+
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         BTM_SecBondByTransport
+**
+** Description      This function is called to perform bonding with peer device.
+**                  If the connection is already up, but not secure, pairing
+**                  is attempted.  If already paired BTM_SUCCESS is returned.
+**
+** Parameters:      bd_addr      - Address of the device to bond
+**                  transport    - doing SSP over BR/EDR or SMP over LE
+**                  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)
+**
+**  Note: After 2.1 parameters are not used and preserved here not to change API
+*******************************************************************************/
+tBTM_STATUS BTM_SecBondByTransport (BD_ADDR bd_addr, tBT_TRANSPORT transport,
+                                    uint8_t pin_len, uint8_t *p_pin, uint32_t trusted_mask[])
+{
+#if (SMP_INCLUDED == TRUE)
+    tBT_DEVICE_TYPE     dev_type;
+    tBLE_ADDR_TYPE      addr_type;
+
+    BTM_ReadDevInfo(bd_addr, &dev_type, &addr_type);
+    /* LE device, do SMP pairing */
+    if ((transport == BT_TRANSPORT_LE && (dev_type & BT_DEVICE_TYPE_BLE) == 0) ||
+        (transport == BT_TRANSPORT_BR_EDR && (dev_type & BT_DEVICE_TYPE_BREDR) == 0))
+    {
+        return BTM_ILLEGAL_ACTION;
+    }
+#endif
+    return btm_sec_bond_by_transport(bd_addr, transport, pin_len, p_pin, trusted_mask);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_SecBond
+**
+** Description      This function is called to perform bonding with peer device.
+**                  If the connection is already up, but not secure, pairing
+**                  is attempted.  If already paired BTM_SUCCESS is returned.
+**
+** 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)
+**
+**  Note: After 2.1 parameters are not used and preserved here not to change API
+*******************************************************************************/
+tBTM_STATUS BTM_SecBond (BD_ADDR bd_addr, uint8_t pin_len, uint8_t *p_pin, uint32_t trusted_mask[])
+{
+    tBT_TRANSPORT   transport = BT_TRANSPORT_BR_EDR;
+#if (BLE_INCLUDED == TRUE)
+    if (BTM_UseLeLink(bd_addr))
+        transport = BT_TRANSPORT_LE;
+#endif
+    return btm_sec_bond_by_transport(bd_addr, transport, pin_len, p_pin, trusted_mask);
+}
+/*******************************************************************************
+**
+** Function         BTM_SecBondCancel
+**
+** Description      This function is called to cancel ongoing bonding process
+**                  with peer device.
+**
+** Parameters:      bd_addr      - Address of the peer device
+**                         transport    - false for BR/EDR link; true for LE link
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SecBondCancel (BD_ADDR bd_addr)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec;
+
+    BTM_TRACE_API ("BTM_SecBondCancel()  State: %s flags:0x%x",
+                    btm_pair_state_descr (btm_cb.pairing_state), btm_cb.pairing_flags);
+
+    if (((p_dev_rec = btm_find_dev (bd_addr)) == NULL)
+        ||  (memcmp (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN) != 0) )
+        return BTM_UNKNOWN_ADDR;
+
+#if (SMP_INCLUDED == TRUE)
+    if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_LE_ACTIVE)
+    {
+        if (p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING)
+        {
+            BTM_TRACE_DEBUG ("Cancel LE pairing");
+            if (SMP_PairCancel(bd_addr))
+            {
+                return BTM_CMD_STARTED;
+            }
+        }
+        return BTM_WRONG_MODE;
+    }
+
+#endif
+    BTM_TRACE_DEBUG ("hci_handle:0x%x sec_state:%d", p_dev_rec->hci_handle, p_dev_rec->sec_state );
+    if (BTM_PAIR_STATE_WAIT_LOCAL_PIN == btm_cb.pairing_state &&
+        BTM_PAIR_FLAGS_WE_STARTED_DD & btm_cb.pairing_flags)
+    {
+        /* pre-fetching pin for dedicated bonding */
+        btm_sec_bond_cancel_complete();
+        return BTM_SUCCESS;
+    }
+
+    /* If this BDA is in a bonding procedure */
+    if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+         &&  (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD))
+    {
+        /* If the HCI link is up */
+        if (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE)
+        {
+            /* If some other thread disconnecting, we do not send second command */
+            if ((p_dev_rec->sec_state == BTM_SEC_STATE_DISCONNECTING) ||
+                (p_dev_rec->sec_state == BTM_SEC_STATE_DISCONNECTING_BOTH))
+                return(BTM_CMD_STARTED);
+
+            /* If the HCI link was set up by Bonding process */
+            if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE)
+                return btm_sec_send_hci_disconnect(p_dev_rec, HCI_ERR_PEER_USER, p_dev_rec->hci_handle);
+            else
+                l2cu_update_lcb_4_bonding(bd_addr, false);
+
+            return BTM_NOT_AUTHORIZED;
+        }
+        else /*HCI link is not up */
+        {
+            /* If the HCI link creation was started by Bonding process */
+            if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE)
+            {
+                btsnd_hcic_create_conn_cancel(bd_addr);
+                return BTM_CMD_STARTED;
+            }
+            if (btm_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME)
+            {
+                BTM_CancelRemoteDeviceName();
+                btm_cb.pairing_flags |= BTM_PAIR_FLAGS_WE_CANCEL_DD;
+                return BTM_CMD_STARTED;
+            }
+            return BTM_NOT_AUTHORIZED;
+        }
+    }
+
+    return BTM_WRONG_MODE;
+}
+
+/*******************************************************************************
+**
+** 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
+**
+** Parameters:      bd_addr      - Address of the device
+**                  link_key     - Link Key is copied into this array
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SecGetDeviceLinkKey (BD_ADDR bd_addr, LINK_KEY link_key)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec;
+
+    if (((p_dev_rec = btm_find_dev (bd_addr)) != NULL)
+        && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN))
+    {
+        memcpy (link_key, p_dev_rec->link_key, LINK_KEY_LEN);
+        return(BTM_SUCCESS);
+    }
+    return(BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+**
+** 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 (BD_ADDR bd_addr)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+
+    if ((p_dev_rec != NULL) && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN))
+    {
+        return p_dev_rec->link_key_type;
+    }
+    return BTM_LKEY_TYPE_IGNORE;
+}
+
+/*******************************************************************************
+**
+** 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 (BD_ADDR bd_addr, tBT_TRANSPORT transport, tBTM_SEC_CBACK *p_callback,
+                               void *p_ref_data, tBTM_BLE_SEC_ACT sec_act)
+{
+    tBTM_STATUS rc = 0;
+
+    tBTM_SEC_DEV_REC  *p_dev_rec = btm_find_dev (bd_addr);
+    if (!p_dev_rec ||
+        (transport == BT_TRANSPORT_BR_EDR && p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE)
+#if (BLE_INCLUDED == TRUE)
+        || (transport == BT_TRANSPORT_LE && p_dev_rec->ble_hci_handle == BTM_SEC_INVALID_HANDLE)
+#endif
+        )
+    {
+        /* Connection should be up and runnning */
+        BTM_TRACE_WARNING ("Security Manager: BTM_SetEncryption not connected");
+
+        if (p_callback)
+            (*p_callback) (bd_addr, transport, p_ref_data, BTM_WRONG_MODE);
+
+        return(BTM_WRONG_MODE);
+    }
+
+    if (transport == BT_TRANSPORT_BR_EDR &&
+         (p_dev_rec->sec_flags &  BTM_SEC_ENCRYPTED))
+    {
+        BTM_TRACE_EVENT ("Security Manager: BTM_SetEncryption already encrypted");
+
+        if (p_callback)
+            (*p_callback) (bd_addr, transport, p_ref_data, BTM_SUCCESS);
+
+        return(BTM_SUCCESS);
+    }
+
+    /* enqueue security request if security is active */
+    if (p_dev_rec->p_callback || (p_dev_rec->sec_state != BTM_SEC_STATE_IDLE))
+    {
+        BTM_TRACE_WARNING ("Security Manager: BTM_SetEncryption busy, enqueue request");
+
+        if (btm_sec_queue_encrypt_request(bd_addr, transport, p_callback, p_ref_data, sec_act))
+        {
+            return BTM_CMD_STARTED;
+        }
+        else
+        {
+            if (p_callback)
+                (*p_callback) (bd_addr, transport, p_ref_data, BTM_NO_RESOURCES);
+            return BTM_NO_RESOURCES;
+        }
+    }
+
+    p_dev_rec->p_callback        = p_callback;
+    p_dev_rec->p_ref_data        = p_ref_data;
+    p_dev_rec->security_required |= (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT);
+    p_dev_rec->is_originator     = false;
+
+    BTM_TRACE_API ("Security Manager: BTM_SetEncryption Handle:%d State:%d Flags:0x%x Required:0x%x",
+                    p_dev_rec->hci_handle, p_dev_rec->sec_state, p_dev_rec->sec_flags,
+                    p_dev_rec->security_required);
+
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+    if (transport == BT_TRANSPORT_LE)
+    {
+        tACL_CONN *p = btm_bda_to_acl(bd_addr, transport);
+        if (p)
+        {
+           rc = btm_ble_set_encryption(bd_addr, sec_act, p->link_role);
+        }
+        else
+        {
+            rc = BTM_WRONG_MODE;
+            BTM_TRACE_WARNING("%s: cannot call btm_ble_set_encryption, p is NULL", __func__);
+        }
+    }
+    else
+#endif
+        rc = btm_sec_execute_procedure (p_dev_rec);
+
+    if (rc != BTM_CMD_STARTED && rc != BTM_BUSY)
+    {
+        if (p_callback)
+        {
+            p_dev_rec->p_callback = NULL;
+            (*p_callback) (bd_addr, transport, p_dev_rec->p_ref_data, rc);
+        }
+    }
+
+    return(rc);
+}
+
+/*******************************************************************************
+ * disconnect the ACL link, if it's not done yet.
+*******************************************************************************/
+static tBTM_STATUS btm_sec_send_hci_disconnect (tBTM_SEC_DEV_REC *p_dev_rec, uint8_t reason, uint16_t conn_handle)
+{
+    uint8_t     old_state = p_dev_rec->sec_state;
+    tBTM_STATUS status = BTM_CMD_STARTED;
+
+    BTM_TRACE_EVENT ("btm_sec_send_hci_disconnect:  handle:0x%x, reason=0x%x",
+                      conn_handle, reason);
+
+    /* send HCI_Disconnect on a transport only once */
+    switch (old_state)
+    {
+        case BTM_SEC_STATE_DISCONNECTING:
+            if (conn_handle == p_dev_rec->hci_handle)
+                return status;
+
+            p_dev_rec->sec_state = BTM_SEC_STATE_DISCONNECTING_BOTH;
+            break;
+
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+        case BTM_SEC_STATE_DISCONNECTING_BLE:
+            if (conn_handle == p_dev_rec->ble_hci_handle)
+                return status;
+
+            p_dev_rec->sec_state = BTM_SEC_STATE_DISCONNECTING_BOTH;
+            break;
+
+        case BTM_SEC_STATE_DISCONNECTING_BOTH:
+            return status;
+#endif
+
+        default:
+            p_dev_rec->sec_state = (conn_handle == p_dev_rec->hci_handle) ?
+                    BTM_SEC_STATE_DISCONNECTING : BTM_SEC_STATE_DISCONNECTING_BLE;
+
+            break;
+    }
+
+    /* If a role switch is in progress, delay the HCI Disconnect to avoid controller problem */
+    if (p_dev_rec->rs_disc_pending == BTM_SEC_RS_PENDING && p_dev_rec->hci_handle == conn_handle)
+    {
+        BTM_TRACE_DEBUG("RS in progress - Set DISC Pending flag in btm_sec_send_hci_disconnect to delay disconnect");
+              p_dev_rec->rs_disc_pending = BTM_SEC_DISC_PENDING;
+        status = BTM_SUCCESS;
+    }
+    /* Tear down the HCI link */
+    else
+    {
+        btsnd_hcic_disconnect(conn_handle, reason);
+    }
+
+    return status;
+}
+
+/*******************************************************************************
+**
+** 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, BD_ADDR bd_addr)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec;
+
+    BTM_TRACE_EVENT ("BTM_ConfirmReqReply() State: %s  Res: %u",
+                      btm_pair_state_descr(btm_cb.pairing_state), res);
+
+    /* If timeout already expired or has been canceled, ignore the reply */
+    if ( (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM)
+         ||  (memcmp (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN) != 0) )
+        return;
+
+    btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+
+    if ( (res == BTM_SUCCESS) || (res == BTM_SUCCESS_NO_SECURITY) )
+    {
+        btm_cb.acl_disc_reason = HCI_SUCCESS;
+
+        if (res == BTM_SUCCESS)
+        {
+            if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL) {
+                p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED;
+                p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
+            }
+        }
+
+        btsnd_hcic_user_conf_reply (bd_addr, true);
+    }
+    else
+    {
+        /* Report authentication failed event from state BTM_PAIR_STATE_WAIT_AUTH_COMPLETE */
+        btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+        btsnd_hcic_user_conf_reply (bd_addr, false);
+    }
+}
+
+/*******************************************************************************
+**
+** 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
+**                  BTM_MIN_PASSKEY_VAL(0) - BTM_MAX_PASSKEY_VAL(999999(0xF423F)).
+**
+*******************************************************************************/
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+void BTM_PasskeyReqReply(tBTM_STATUS res, BD_ADDR bd_addr, uint32_t passkey)
+{
+    BTM_TRACE_API ("BTM_PasskeyReqReply: State: %s  res:%d",
+                    btm_pair_state_descr(btm_cb.pairing_state), res);
+
+    if ( (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE)
+         ||  (memcmp (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN) != 0) )
+    {
+        return;
+    }
+
+    /* If timeout already expired or has been canceled, ignore the reply */
+    if ( (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_AUTH_COMPLETE) && (res != BTM_SUCCESS) )
+    {
+        tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+        if (p_dev_rec != NULL)
+        {
+            btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+
+            if (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE)
+                btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_AUTH_FAILURE, p_dev_rec->hci_handle);
+            else
+                BTM_SecBondCancel(bd_addr);
+
+            p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_AUTHED | BTM_SEC_LINK_KEY_KNOWN);
+
+            btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+            return;
+        }
+    }
+    else if (btm_cb.pairing_state != BTM_PAIR_STATE_KEY_ENTRY)
+        return;
+
+    if (passkey > BTM_MAX_PASSKEY_VAL)
+        res = BTM_ILLEGAL_VALUE;
+
+    btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+
+    if (res != BTM_SUCCESS)
+    {
+        /* use BTM_PAIR_STATE_WAIT_AUTH_COMPLETE to report authentication failed event */
+        btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+        btsnd_hcic_user_passkey_neg_reply (bd_addr);
+    } else {
+        btm_cb.acl_disc_reason = HCI_SUCCESS;
+        btsnd_hcic_user_passkey_reply (bd_addr, passkey);
+    }
+}
+#endif
+
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+void BTM_SendKeypressNotif(BD_ADDR bd_addr, tBTM_SP_KEY_TYPE type)
+{
+    /* This API only make sense between PASSKEY_REQ and SP complete */
+    if (btm_cb.pairing_state == BTM_PAIR_STATE_KEY_ENTRY)
+        btsnd_hcic_send_keypress_notif(bd_addr, type);
+}
+#endif
+
+/*******************************************************************************
+**
+** 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(BD_ADDR bd_addr, tBTM_IO_CAP io_cap, tBTM_OOB_DATA oob, tBTM_AUTH_REQ auth_req)
+{
+    BTM_TRACE_EVENT ("BTM_IoCapRsp: state: %s  oob: %d io_cap: %d",
+                      btm_pair_state_descr(btm_cb.pairing_state), oob, io_cap);
+
+    if ( (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS)
+         ||  (memcmp (btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN) != 0) )
+        return;
+
+    if (oob < BTM_OOB_UNKNOWN && io_cap < BTM_IO_CAP_MAX)
+    {
+        btm_cb.devcb.loc_auth_req   = auth_req;
+        btm_cb.devcb.loc_io_caps    = io_cap;
+
+        if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+            auth_req = (BTM_AUTH_DD_BOND | (auth_req&BTM_AUTH_YN_BIT));
+
+        btsnd_hcic_io_cap_req_reply (bd_addr, io_cap, oob, auth_req);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         BTM_ReadLocalOobData
+**
+** Description      This function is called to read the local OOB data from
+**                  LM
+**
+*******************************************************************************/
+void BTM_ReadLocalOobData(void)
+{
+    btsnd_hcic_read_local_oob_data();
+}
+
+/*******************************************************************************
+**
+** 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, BD_ADDR bd_addr, BT_OCTET16 c, BT_OCTET16 r)
+{
+    BTM_TRACE_EVENT ("%s() - State: %s res: %d", __func__,
+                      btm_pair_state_descr(btm_cb.pairing_state), res);
+
+    /* If timeout already expired or has been canceled, ignore the reply */
+    if (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP)
+        return;
+
+    btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+
+    if (res != BTM_SUCCESS)
+    {
+        /* use BTM_PAIR_STATE_WAIT_AUTH_COMPLETE to report authentication failed event */
+        btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+        btsnd_hcic_rem_oob_neg_reply (bd_addr);
+    } else {
+        btm_cb.acl_disc_reason = HCI_SUCCESS;
+        btsnd_hcic_rem_oob_reply (bd_addr, c, 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, BT_OCTET16 c,
+                        BT_OCTET16 r, uint8_t name_len)
+{
+    uint8_t *p = p_data;
+    uint16_t len = 0;
+    uint16_t name_size;
+    uint8_t name_type = BTM_EIR_SHORTENED_LOCAL_NAME_TYPE;
+
+    if (p_data && max_len >= BTM_OOB_MANDATORY_SIZE)
+    {
+        /* add mandatory part */
+        UINT16_TO_STREAM(p, len);
+        BDADDR_TO_STREAM(p, controller_get_interface()->get_address()->address);
+
+        len = BTM_OOB_MANDATORY_SIZE;
+        max_len -= len;
+
+        /* now optional part */
+
+        /* add Hash C */
+        uint16_t delta = BTM_OOB_HASH_C_SIZE + 2;
+        if (max_len >= delta)
+        {
+            *p++ = BTM_OOB_HASH_C_SIZE + 1;
+            *p++ = BTM_EIR_OOB_SSP_HASH_C_TYPE;
+            ARRAY_TO_STREAM(p, c, BTM_OOB_HASH_C_SIZE);
+            len     += delta;
+            max_len -= delta;
+        }
+
+        /* add Rand R */
+        delta = BTM_OOB_RAND_R_SIZE + 2;
+        if (max_len >= delta)
+        {
+            *p++ = BTM_OOB_RAND_R_SIZE + 1;
+            *p++ = BTM_EIR_OOB_SSP_RAND_R_TYPE;
+            ARRAY_TO_STREAM(p, r, BTM_OOB_RAND_R_SIZE);
+            len     += delta;
+            max_len -= delta;
+        }
+
+        /* add class of device */
+        delta = BTM_OOB_COD_SIZE + 2;
+        if (max_len >= delta)
+        {
+            *p++ = BTM_OOB_COD_SIZE + 1;
+            *p++ = BTM_EIR_OOB_COD_TYPE;
+            DEVCLASS_TO_STREAM(p, btm_cb.devcb.dev_class);
+            len     += delta;
+            max_len -= delta;
+        }
+        name_size = name_len;
+        if (name_size > strlen(btm_cb.cfg.bd_name))
+        {
+            name_type = BTM_EIR_COMPLETE_LOCAL_NAME_TYPE;
+            name_size = (uint16_t)strlen(btm_cb.cfg.bd_name);
+        }
+        delta = name_size + 2;
+        if (max_len >= delta)
+        {
+            *p++ = name_size + 1;
+            *p++ = name_type;
+            ARRAY_TO_STREAM (p, btm_cb.cfg.bd_name, name_size);
+            len     += delta;
+            max_len -= delta;
+        }
+        /* update len */
+        p = p_data;
+        UINT16_TO_STREAM(p, len);
+    }
+    return 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(BD_ADDR bd_addr)
+{
+    return ((controller_get_interface()->supports_secure_connections()) &&
+            (BTM_PeerSupportsSecureConnections(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(BD_ADDR bd_addr)
+{
+    tBTM_SEC_DEV_REC    *p_dev_rec;
+
+    if ((p_dev_rec = btm_find_dev(bd_addr)) == NULL)
+    {
+        BTM_TRACE_WARNING("%s: unknown BDA: %08x%04x", __func__,
+            (bd_addr[0]<<24) + (bd_addr[1]<<16) + (bd_addr[2]<<8) + bd_addr[3],
+            (bd_addr[4]<< 8) + bd_addr[5]);
+        return false;
+    }
+
+    return (p_dev_rec->remote_supports_secure_connections);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    uint8_t *p = p_data;
+    uint16_t max_len;
+    uint8_t len, type;
+    uint8_t *p_ret = NULL;
+    uint8_t ret_len = 0;
+
+    if (p_data)
+    {
+        STREAM_TO_UINT16(max_len, p);
+        if (max_len >= BTM_OOB_MANDATORY_SIZE)
+        {
+            if (BTM_EIR_OOB_BD_ADDR_TYPE == eir_tag)
+            {
+                p_ret = p; /* the location for bd_addr */
+                ret_len = BTM_OOB_BD_ADDR_SIZE;
+            }
+            else
+            {
+                p += BD_ADDR_LEN;
+                max_len -= BTM_OOB_MANDATORY_SIZE;
+                /* now the optional data in EIR format */
+                while (max_len > 0)
+                {
+                    len     = *p++; /* tag data len + 1 */
+                    type    = *p++;
+                    if (eir_tag == type)
+                    {
+                        p_ret = p;
+                        ret_len = len - 1;
+                        break;
+                    }
+                    /* the data size of this tag is len + 1 (tag data len + 2) */
+                    if (max_len > len)
+                    {
+                        max_len -= len;
+                        max_len--;
+                        len--;
+                        p += len;
+                    }
+                    else
+                        max_len = 0;
+                }
+            }
+        }
+    }
+
+    if (p_len)
+        *p_len = ret_len;
+
+    return p_ret;
+}
+
+/*******************************************************************************
+**
+** Function         BTM_SetOutService
+**
+** Description      This function is called to set the service for
+**                  outgoing connections.
+**
+**                  If the profile/application calls BTM_SetSecurityLevel
+**                  before initiating a connection, this function does not
+**                  need to be called.
+**
+** Returns          void
+**
+*******************************************************************************/
+void BTM_SetOutService(BD_ADDR bd_addr, uint8_t service_id, uint32_t mx_chan_id)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec;
+    tBTM_SEC_SERV_REC *p_serv_rec = &btm_cb.sec_serv_rec[0];
+
+    btm_cb.p_out_serv = p_serv_rec;
+    p_dev_rec = btm_find_dev (bd_addr);
+
+    for (int i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++)
+    {
+        if ((p_serv_rec->security_flags & BTM_SEC_IN_USE)
+            && (p_serv_rec->service_id == service_id)
+            && (p_serv_rec->orig_mx_chan_id == mx_chan_id))
+        {
+            BTM_TRACE_API("BTM_SetOutService p_out_serv id %d, psm 0x%04x, proto_id %d, chan_id %d",
+                           p_serv_rec->service_id, p_serv_rec->psm, p_serv_rec->mx_proto_id, p_serv_rec->orig_mx_chan_id);
+            btm_cb.p_out_serv = p_serv_rec;
+            if (p_dev_rec)
+                p_dev_rec->p_cur_service = p_serv_rec;
+            break;
+        }
+    }
+}
+
+/************************************************************************
+**              I N T E R N A L     F U N C T I O N S
+*************************************************************************/
+/*******************************************************************************
+**
+** Function         btm_sec_is_upgrade_possible
+**
+** Description      This function returns true if the existing link key
+**                  can be upgraded or if the link key does not exist.
+**
+** Returns          bool
+**
+*******************************************************************************/
+static bool    btm_sec_is_upgrade_possible(tBTM_SEC_DEV_REC  *p_dev_rec, bool    is_originator)
+{
+    uint16_t            mtm_check = is_originator ? BTM_SEC_OUT_MITM : BTM_SEC_IN_MITM;
+    bool                is_possible = true;
+
+    if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)
+    {
+        is_possible = false;
+        if(p_dev_rec->p_cur_service)
+        {
+            BTM_TRACE_DEBUG ("%s() id: %d, link_key_typet: %d, rmt_io_caps: %d, chk flags: 0x%x, flags: 0x%x",
+                          __func__, p_dev_rec->p_cur_service->service_id, p_dev_rec->link_key_type,
+                          p_dev_rec->rmt_io_caps, mtm_check, p_dev_rec->p_cur_service->security_flags);
+        }
+        else
+        {
+            BTM_TRACE_DEBUG ("%s() link_key_typet: %d, rmt_io_caps: %d, chk flags: 0x%x",
+                          __func__, p_dev_rec->link_key_type, p_dev_rec->rmt_io_caps, mtm_check);
+        }
+        /* Already have a link key to the connected peer. Is the link key secure enough?
+        ** Is a link key upgrade even possible?
+        */
+        if ((p_dev_rec->security_required & mtm_check)    /* needs MITM */
+            && ((p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB) ||
+                (p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256))
+                                                          /* has unauthenticated
+                                                          link key */
+            && (p_dev_rec->rmt_io_caps < BTM_IO_CAP_MAX)  /* a valid peer IO cap */
+            && (btm_sec_io_map[p_dev_rec->rmt_io_caps][btm_cb.devcb.loc_io_caps]))
+                                                          /* authenticated
+                                                          link key is possible */
+        {
+            /* upgrade is possible: check if the application wants the upgrade.
+             * If the application is configured to use a global MITM flag,
+             * it probably would not want to upgrade the link key based on the security level database */
+            is_possible = true;
+        }
+    }
+    BTM_TRACE_DEBUG ("%s() is_possible: %d sec_flags: 0x%x", __func__, is_possible, p_dev_rec->sec_flags);
+    return is_possible;
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_check_upgrade
+**
+** Description      This function is called to check if the existing link key
+**                  needs to be upgraded.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_sec_check_upgrade(tBTM_SEC_DEV_REC  *p_dev_rec, bool    is_originator)
+{
+
+    BTM_TRACE_DEBUG ("%s()", __func__);
+
+    /* Only check if link key already exists */
+    if (!(p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN))
+        return;
+
+    if (btm_sec_is_upgrade_possible (p_dev_rec, is_originator) == true)
+    {
+        BTM_TRACE_DEBUG ("need upgrade!! sec_flags:0x%x", p_dev_rec->sec_flags);
+        /* upgrade is possible: check if the application wants the upgrade.
+         * If the application is configured to use a global MITM flag,
+         * it probably would not want to upgrade the link key based on the security level database */
+        tBTM_SP_UPGRADE evt_data;
+        memcpy (evt_data.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
+        evt_data.upgrade = true;
+        if (btm_cb.api.p_sp_callback)
+            (*btm_cb.api.p_sp_callback) (BTM_SP_UPGRADE_EVT, (tBTM_SP_EVT_DATA *)&evt_data);
+
+        BTM_TRACE_DEBUG ("evt_data.upgrade:0x%x", evt_data.upgrade);
+        if (evt_data.upgrade)
+        {
+            /* if the application confirms the upgrade, set the upgrade bit */
+            p_dev_rec->sm4 |= BTM_SM4_UPGRADE;
+
+            /* Clear the link key known to go through authentication/pairing again */
+            p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED);
+            p_dev_rec->sec_flags &= ~BTM_SEC_AUTHENTICATED;
+            BTM_TRACE_DEBUG ("sec_flags:0x%x", p_dev_rec->sec_flags);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_l2cap_access_req
+**
+** Description      This function is called by the L2CAP to grant permission to
+**                  establish L2CAP connection to or from the peer device.
+**
+** Parameters:      bd_addr       - Address of the peer device
+**                  psm           - L2CAP PSM
+**                  is_originator - true if protocol above L2CAP originates
+**                                  connection
+**                  p_callback    - Pointer to callback function called if
+**                                  this function returns PENDING after required
+**                                  procedures are complete. MUST NOT BE NULL.
+**
+** Returns          tBTM_STATUS
+**
+*******************************************************************************/
+tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, uint16_t psm, uint16_t handle,
+                                      CONNECTION_TYPE conn_type,
+                                      tBTM_SEC_CALLBACK *p_callback,
+                                      void *p_ref_data)
+{
+    tBTM_SEC_DEV_REC  *p_dev_rec;
+    tBTM_SEC_SERV_REC *p_serv_rec;
+    uint16_t       security_required;
+    uint16_t       old_security_required;
+    bool          old_is_originator;
+    tBTM_STATUS   rc = BTM_SUCCESS;
+    bool          chk_acp_auth_done = false;
+    bool    is_originator;
+    tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR; /* should check PSM range in LE connection oriented L2CAP connection */
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+    if (conn_type & CONNECTION_TYPE_ORIG_MASK)
+        is_originator = true;
+    else
+        is_originator = false;
+
+    BTM_TRACE_DEBUG ("%s() conn_type: 0x%x, 0x%x", __func__, conn_type, p_ref_data);
+#else
+    is_originator = conn_type;
+
+    BTM_TRACE_DEBUG ("%s() is_originator:%d, 0x%x", __func__, is_originator, p_ref_data);
+#endif
+
+    /* Find or get oldest record */
+    p_dev_rec = btm_find_or_alloc_dev (bd_addr);
+
+    p_dev_rec->hci_handle = handle;
+
+    /* Find the service record for the PSM */
+    p_serv_rec = btm_sec_find_first_serv (conn_type, psm);
+
+    /* If there is no application registered with this PSM do not allow connection */
+    if (!p_serv_rec)
+    {
+        BTM_TRACE_WARNING ("%s() PSM: %d no application registerd", __func__, psm);
+        (*p_callback) (bd_addr, transport, p_ref_data, BTM_MODE_UNSUPPORTED);
+        return(BTM_MODE_UNSUPPORTED);
+    }
+
+    /* Services level0 by default have no security */
+    if ((btm_sec_is_serv_level0(psm)) && (!btm_cb.devcb.secure_connections_only))
+    {
+        (*p_callback) (bd_addr,transport, p_ref_data, BTM_SUCCESS_NO_SECURITY);
+        return(BTM_SUCCESS);
+    }
+#if (L2CAP_UCD_INCLUDED == TRUE)
+    if ( conn_type & CONNECTION_TYPE_CONNLESS_MASK )
+    {
+        if (btm_cb.security_mode == BTM_SEC_MODE_SC)
+        {
+            security_required = btm_sec_set_serv_level4_flags (p_serv_rec->ucd_security_flags,
+                                                               is_originator);
+        }
+        else
+        {
+            security_required = p_serv_rec->ucd_security_flags;
+        }
+
+        rc = BTM_CMD_STARTED;
+        if (is_originator)
+        {
+            if (((security_required & BTM_SEC_OUT_FLAGS) == 0) ||
+                ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_AUTHENTICATE) && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))) ||
+                ((((security_required & BTM_SEC_OUT_FLAGS) == (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) && (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))) ||
+                ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_FLAGS) && (p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED))) )
+            {
+                rc = BTM_SUCCESS;
+            }
+        }
+        else
+        {
+            if (((security_required & BTM_SEC_IN_FLAGS) == 0) ||
+                ((((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_AUTHENTICATE) && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))) ||
+                ((((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) && (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))) ||
+                ((((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_FLAGS) && (p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED))) )
+            {
+                // Check for 16 digits (or MITM)
+                if (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == 0) ||
+                    (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == BTM_SEC_IN_MIN_16_DIGIT_PIN) &&
+                     btm_dev_16_digit_authenticated(p_dev_rec))) {
+                    rc = BTM_SUCCESS;
+                }
+            }
+        }
+
+        if ((rc == BTM_SUCCESS) && (security_required & BTM_SEC_MODE4_LEVEL4) &&
+            (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256))
+        {
+            rc = BTM_CMD_STARTED;
+        }
+
+        if (rc == BTM_SUCCESS)
+        {
+            if (p_callback)
+                (*p_callback) (bd_addr, transport, (void *)p_ref_data, BTM_SUCCESS);
+
+            return(BTM_SUCCESS);
+        }
+    }
+    else
+#endif
+    {
+        if (btm_cb.security_mode == BTM_SEC_MODE_SC)
+        {
+            security_required = btm_sec_set_serv_level4_flags (p_serv_rec->security_flags,
+                                                                is_originator);
+        }
+        else
+        {
+            security_required = p_serv_rec->security_flags;
+        }
+    }
+
+    BTM_TRACE_DEBUG("%s: security_required 0x%04x, is_originator 0x%02x, psm  0x%04x",
+                    __func__, security_required, is_originator, psm);
+
+    if ((!is_originator) && (security_required & BTM_SEC_MODE4_LEVEL4))
+    {
+        bool    local_supports_sc = controller_get_interface()->supports_secure_connections();
+        /* acceptor receives L2CAP Channel Connect Request for Secure Connections Only service */
+        if (!(local_supports_sc) || !(p_dev_rec->remote_supports_secure_connections))
+        {
+            BTM_TRACE_DEBUG("%s: SC only service, local_support_for_sc %d",
+                            "rmt_support_for_sc : %d -> fail pairing", __func__,
+                            local_supports_sc,
+                            p_dev_rec->remote_supports_secure_connections);
+            if (p_callback)
+                (*p_callback) (bd_addr, transport, (void *)p_ref_data,
+                                                    BTM_MODE4_LEVEL4_NOT_SUPPORTED);
+
+            return (BTM_MODE4_LEVEL4_NOT_SUPPORTED);
+        }
+    }
+
+    /* there are some devices (moto KRZR) which connects to several services at the same time */
+    /* we will process one after another */
+    if ( (p_dev_rec->p_callback) || (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) )
+    {
+        BTM_TRACE_EVENT ("%s() - busy - PSM:%d delayed  state: %s mode:%d, sm4:0x%x", __func__,
+                          psm, btm_pair_state_descr(btm_cb.pairing_state), btm_cb.security_mode, p_dev_rec->sm4);
+        BTM_TRACE_EVENT ("security_flags:x%x, sec_flags:x%x", security_required, p_dev_rec->sec_flags);
+        rc = BTM_CMD_STARTED;
+        if ((btm_cb.security_mode == BTM_SEC_MODE_UNDEFINED ||
+             btm_cb.security_mode == BTM_SEC_MODE_NONE ||
+             btm_cb.security_mode == BTM_SEC_MODE_SERVICE ||
+             btm_cb.security_mode == BTM_SEC_MODE_LINK) ||
+            (BTM_SM4_KNOWN == p_dev_rec->sm4) || (BTM_SEC_IS_SM4(p_dev_rec->sm4) &&
+            (btm_sec_is_upgrade_possible(p_dev_rec, is_originator) == false)))
+        {
+            /* legacy mode - local is legacy or local is lisbon/peer is legacy
+             * or SM4 with no possibility of link key upgrade */
+            if (is_originator)
+            {
+                if (((security_required & BTM_SEC_OUT_FLAGS) == 0) ||
+                    ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_AUTHENTICATE) && btm_dev_authenticated(p_dev_rec))) ||
+                    ((((security_required & BTM_SEC_OUT_FLAGS) == (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) && btm_dev_encrypted(p_dev_rec))) ||
+                    ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_FLAGS) && btm_dev_authorized(p_dev_rec)  && btm_dev_encrypted(p_dev_rec))) )
+                {
+                    rc = BTM_SUCCESS;
+                }
+            }
+            else
+            {
+                if (((security_required & BTM_SEC_IN_FLAGS) == 0) ||
+                (((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_AUTHENTICATE) && btm_dev_authenticated(p_dev_rec)) ||
+                (((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) && btm_dev_encrypted(p_dev_rec)) ||
+                (((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_AUTHORIZE) && (btm_dev_authorized(p_dev_rec)||btm_serv_trusted(p_dev_rec, p_serv_rec))) ||
+                (((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_AUTHORIZE)) && ((btm_dev_authorized(p_dev_rec)||btm_serv_trusted(p_dev_rec, p_serv_rec)) && btm_dev_authenticated(p_dev_rec))) ||
+                (((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHORIZE)) && ((btm_dev_authorized(p_dev_rec)||btm_serv_trusted(p_dev_rec, p_serv_rec)) && btm_dev_encrypted(p_dev_rec))) ||
+                (((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_FLAGS)  && btm_dev_encrypted(p_dev_rec) && (btm_dev_authorized(p_dev_rec)||btm_serv_trusted(p_dev_rec, p_serv_rec))))
+                {
+                    // Check for 16 digits (or MITM)
+                    if (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == 0) ||
+                       (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == BTM_SEC_IN_MIN_16_DIGIT_PIN) && btm_dev_16_digit_authenticated(p_dev_rec))) {
+                        rc = BTM_SUCCESS;
+                    }
+                }
+            }
+
+            if ((rc == BTM_SUCCESS) && (security_required & BTM_SEC_MODE4_LEVEL4) &&
+                (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256))
+            {
+                rc = BTM_CMD_STARTED;
+            }
+
+            if (rc == BTM_SUCCESS)
+            {
+                if (p_callback)
+                    (*p_callback) (bd_addr, transport, (void *)p_ref_data, BTM_SUCCESS);
+                return(BTM_SUCCESS);
+            }
+        }
+
+        btm_cb.sec_req_pending = true;
+        return(BTM_CMD_STARTED);
+    }
+
+    /* Save pointer to service record */
+    p_dev_rec->p_cur_service = p_serv_rec;
+
+    /* Modify security_required in btm_sec_l2cap_access_req for Lisbon */
+    if (btm_cb.security_mode == BTM_SEC_MODE_SP ||
+        btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG ||
+        btm_cb.security_mode == BTM_SEC_MODE_SC)
+    {
+        if (BTM_SEC_IS_SM4(p_dev_rec->sm4))
+        {
+            if (is_originator)
+            {
+                /* SM4 to SM4 -> always authenticate & encrypt */
+                security_required |= (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT);
+            }
+            else /* acceptor */
+            {
+                /* SM4 to SM4: the acceptor needs to make sure the authentication is already done */
+                chk_acp_auth_done = true;
+                /* SM4 to SM4 -> always authenticate & encrypt */
+                security_required |= (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT);
+           }
+        }
+        else if (!(BTM_SM4_KNOWN & p_dev_rec->sm4))
+        {
+            /* the remote features are not known yet */
+            BTM_TRACE_DEBUG("%s: (%s) remote features unknown!!sec_flags:0x%02x", __func__,
+                            (is_originator) ? "initiator" : "acceptor", p_dev_rec->sec_flags);
+
+            p_dev_rec->sm4 |= BTM_SM4_REQ_PEND;
+            return (BTM_CMD_STARTED);
+        }
+    }
+
+    BTM_TRACE_DEBUG ("%s()  sm4:0x%x, sec_flags:0x%x, security_required:0x%x chk:%d", __func__,
+                      p_dev_rec->sm4, p_dev_rec->sec_flags, security_required, chk_acp_auth_done);
+
+    old_security_required        = p_dev_rec->security_required;
+    old_is_originator            = p_dev_rec->is_originator;
+    p_dev_rec->security_required = security_required;
+    p_dev_rec->p_ref_data        = p_ref_data;
+    p_dev_rec->is_originator     = is_originator;
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+    if ( conn_type & CONNECTION_TYPE_CONNLESS_MASK )
+        p_dev_rec->is_ucd = true;
+    else
+        p_dev_rec->is_ucd = false;
+#endif
+
+    /* If there are multiple service records used through the same PSM */
+    /* leave security decision for the multiplexor on the top */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+    if (((btm_sec_find_next_serv (p_serv_rec)) != NULL)
+        &&(!( conn_type & CONNECTION_TYPE_CONNLESS_MASK ))) /* if not UCD */
+#else
+    if ((btm_sec_find_next_serv (p_serv_rec)) != NULL)
+#endif
+    {
+        BTM_TRACE_DEBUG ("no next_serv sm4:0x%x, chk:%d", p_dev_rec->sm4, chk_acp_auth_done);
+        if (!BTM_SEC_IS_SM4(p_dev_rec->sm4))
+        {
+            BTM_TRACE_EVENT ("Security Manager: l2cap_access_req PSM:%d postponed for multiplexer", psm);
+            /* pre-Lisbon: restore the old settings */
+            p_dev_rec->security_required = old_security_required;
+            p_dev_rec->is_originator     = old_is_originator;
+
+            (*p_callback) (bd_addr, transport, p_ref_data, BTM_SUCCESS);
+
+            return(BTM_SUCCESS);
+        }
+    }
+
+    /* if the originator is using dynamic PSM in legacy mode, do not start any security process now
+     * The layer above L2CAP needs to carry out the security requirement after L2CAP connect
+     * response is received */
+    if (is_originator &&
+        ((btm_cb.security_mode == BTM_SEC_MODE_UNDEFINED ||
+          btm_cb.security_mode == BTM_SEC_MODE_NONE ||
+          btm_cb.security_mode == BTM_SEC_MODE_SERVICE ||
+          btm_cb.security_mode == BTM_SEC_MODE_LINK) ||
+         !BTM_SEC_IS_SM4(p_dev_rec->sm4)) && (psm >= 0x1001))
+    {
+        BTM_TRACE_EVENT ("dynamic PSM:0x%x in legacy mode - postponed for upper layer", psm);
+        /* restore the old settings */
+        p_dev_rec->security_required = old_security_required;
+        p_dev_rec->is_originator     = old_is_originator;
+
+        (*p_callback) (bd_addr, transport, p_ref_data, BTM_SUCCESS);
+
+        return(BTM_SUCCESS);
+    }
+
+    if (chk_acp_auth_done)
+    {
+        BTM_TRACE_DEBUG ("(SM4 to SM4) btm_sec_l2cap_access_req rspd. authenticated: x%x, enc: x%x",
+                          (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED), (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED));
+        /* SM4, but we do not know for sure which level of security we need.
+         * as long as we have a link key, it's OK */
+        if ((0 == (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))
+            ||(0 == (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED)))
+        {
+            rc = BTM_DELAY_CHECK;
+            /*
+            2046 may report HCI_Encryption_Change and L2C Connection Request out of sequence
+            because of data path issues. Delay this disconnect a little bit
+            */
+            LOG_INFO(LOG_TAG, "%s peer should have initiated security process by now (SM4 to SM4)", __func__);
+            p_dev_rec->p_callback        = p_callback;
+            p_dev_rec->sec_state         = BTM_SEC_STATE_DELAY_FOR_ENC;
+            (*p_callback) (bd_addr, transport, p_ref_data, rc);
+
+            return BTM_SUCCESS;
+        }
+    }
+
+    p_dev_rec->p_callback        = p_callback;
+
+    if (p_dev_rec->last_author_service_id == BTM_SEC_NO_LAST_SERVICE_ID
+        || p_dev_rec->last_author_service_id != p_dev_rec->p_cur_service->service_id)
+    {
+        /* Although authentication and encryption are per connection
+        ** authorization is per access request.  For example when serial connection
+        ** is up and authorized and client requests to read file (access to other
+        ** scn), we need to request user's permission again.
+        */
+        p_dev_rec->sec_flags &= ~BTM_SEC_AUTHORIZED;
+    }
+
+    if (BTM_SEC_IS_SM4(p_dev_rec->sm4))
+    {
+        if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) &&
+            (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256))
+        {
+            /* BTM_LKEY_TYPE_AUTH_COMB_P_256 is the only acceptable key in this case */
+            if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) != 0)
+            {
+                p_dev_rec->sm4 |= BTM_SM4_UPGRADE;
+            }
+            p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED |
+                                      BTM_SEC_AUTHENTICATED);
+            BTM_TRACE_DEBUG ("%s: sec_flags:0x%x", __func__, p_dev_rec->sec_flags);
+        }
+        else
+        {
+            /* If we already have a link key to the connected peer, is it secure enough? */
+            btm_sec_check_upgrade(p_dev_rec, is_originator);
+        }
+    }
+
+    BTM_TRACE_EVENT ("%s() PSM:%d Handle:%d State:%d Flags: 0x%x Required: 0x%x Service ID:%d",
+           __func__, psm, handle, p_dev_rec->sec_state, p_dev_rec->sec_flags,
+           p_dev_rec->security_required, p_dev_rec->p_cur_service->service_id);
+
+    if ((rc = btm_sec_execute_procedure (p_dev_rec)) != BTM_CMD_STARTED)
+    {
+        p_dev_rec->p_callback = NULL;
+        (*p_callback) (bd_addr, transport, p_dev_rec->p_ref_data, (uint8_t)rc);
+    }
+
+    return(rc);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_mx_access_request
+**
+** Description      This function is called by all Multiplexing Protocols during
+**                  establishing connection to or from peer device to grant
+**                  permission to establish application connection.
+**
+** Parameters:      bd_addr       - Address of the peer device
+**                  psm           - L2CAP PSM
+**                  is_originator - true if protocol above L2CAP originates
+**                                  connection
+**                  mx_proto_id   - protocol ID of the multiplexer
+**                  mx_chan_id    - multiplexer channel to reach application
+**                  p_callback    - Pointer to callback function called if
+**                                  this function returns PENDING after required
+**                                  procedures are completed
+**                  p_ref_data    - Pointer to any reference data needed by the
+**                                  the callback function.
+**
+** Returns          BTM_CMD_STARTED
+**
+*******************************************************************************/
+tBTM_STATUS btm_sec_mx_access_request (BD_ADDR bd_addr, uint16_t psm, bool    is_originator,
+                                       uint32_t mx_proto_id, uint32_t mx_chan_id,
+                                       tBTM_SEC_CALLBACK *p_callback, void *p_ref_data)
+{
+    tBTM_SEC_DEV_REC  *p_dev_rec;
+    tBTM_SEC_SERV_REC *p_serv_rec;
+    tBTM_STATUS        rc;
+    uint16_t           security_required;
+    bool    transport   = false;/* should check PSM range in LE connection oriented L2CAP connection */
+
+    BTM_TRACE_DEBUG ("%s() is_originator: %d", __func__, is_originator);
+    /* Find or get oldest record */
+    p_dev_rec = btm_find_or_alloc_dev (bd_addr);
+
+    /* Find the service record for the PSM */
+    p_serv_rec = btm_sec_find_mx_serv (is_originator, psm, mx_proto_id, mx_chan_id);
+
+    /* If there is no application registered with this PSM do not allow connection */
+    if (!p_serv_rec)
+    {
+        if (p_callback)
+            (*p_callback) (bd_addr, transport, p_ref_data, BTM_MODE_UNSUPPORTED);
+
+        BTM_TRACE_ERROR ("Security Manager: MX service not found PSM:%d Proto:%d SCN:%d",
+                          psm, mx_proto_id, mx_chan_id);
+        return BTM_NO_RESOURCES;
+    }
+
+    if ((btm_cb.security_mode == BTM_SEC_MODE_SC) && (!btm_sec_is_serv_level0(psm)))
+    {
+        security_required = btm_sec_set_serv_level4_flags (p_serv_rec->security_flags,
+                                                           is_originator);
+    }
+    else
+    {
+        security_required = p_serv_rec->security_flags;
+    }
+
+    /* there are some devices (moto phone) which connects to several services at the same time */
+    /* we will process one after another */
+    if ( (p_dev_rec->p_callback) || (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) )
+    {
+        BTM_TRACE_EVENT ("%s() service PSM:%d Proto:%d SCN:%d delayed  state: %s", __func__,
+                          psm, mx_proto_id, mx_chan_id, btm_pair_state_descr(btm_cb.pairing_state));
+
+        rc = BTM_CMD_STARTED;
+
+        if ((btm_cb.security_mode == BTM_SEC_MODE_UNDEFINED ||
+             btm_cb.security_mode == BTM_SEC_MODE_NONE ||
+             btm_cb.security_mode == BTM_SEC_MODE_SERVICE ||
+             btm_cb.security_mode == BTM_SEC_MODE_LINK) ||
+            (BTM_SM4_KNOWN == p_dev_rec->sm4) || (BTM_SEC_IS_SM4(p_dev_rec->sm4) &&
+            (btm_sec_is_upgrade_possible(p_dev_rec, is_originator) == false)))
+        {
+            /* legacy mode - local is legacy or local is lisbon/peer is legacy
+             * or SM4 with no possibility of link key upgrade */
+            if (is_originator)
+            {
+                if (((security_required & BTM_SEC_OUT_FLAGS) == 0) ||
+                    ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_AUTHENTICATE) && btm_dev_authenticated(p_dev_rec))) ||
+                    ((((security_required & BTM_SEC_OUT_FLAGS) == (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) && btm_dev_encrypted(p_dev_rec)))
+                    )
+                {
+                    rc = BTM_SUCCESS;
+                }
+            }
+            else
+            {
+                if (((security_required & BTM_SEC_IN_FLAGS) == 0) ||
+                    ((((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_AUTHENTICATE) && btm_dev_authenticated(p_dev_rec))) ||
+                    (((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_AUTHORIZE) && (btm_dev_authorized(p_dev_rec)||btm_serv_trusted(p_dev_rec, p_serv_rec))) ||
+                    (((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_AUTHENTICATE)) && ((btm_dev_authorized(p_dev_rec)||btm_serv_trusted(p_dev_rec, p_serv_rec)) && btm_dev_authenticated(p_dev_rec))) ||
+                    (((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT)) && ((btm_dev_authorized(p_dev_rec)||btm_serv_trusted(p_dev_rec, p_serv_rec))&& btm_dev_encrypted(p_dev_rec))) ||
+                    ((((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) && btm_dev_encrypted(p_dev_rec)))
+                    )
+                {
+                    // Check for 16 digits (or MITM)
+                    if (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == 0) ||
+                       (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == BTM_SEC_IN_MIN_16_DIGIT_PIN) && btm_dev_16_digit_authenticated(p_dev_rec))) {
+                        rc = BTM_SUCCESS;
+                    }
+                }
+            }
+            if ((rc == BTM_SUCCESS) && (security_required & BTM_SEC_MODE4_LEVEL4) &&
+                (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256))
+            {
+                rc = BTM_CMD_STARTED;
+            }
+        }
+
+        if (rc == BTM_SUCCESS)
+        {
+            BTM_TRACE_EVENT("%s: allow to bypass, checking authorization", __func__);
+            /* the security in BTM_SEC_IN_FLAGS is fullfilled so far, check the requirements in */
+            /* btm_sec_execute_procedure */
+            if ((is_originator && (p_serv_rec->security_flags & BTM_SEC_OUT_AUTHORIZE)) ||
+                (!is_originator && (p_serv_rec->security_flags & BTM_SEC_IN_AUTHORIZE)))
+            {
+                BTM_TRACE_EVENT("%s: still need authorization", __func__);
+                rc = BTM_CMD_STARTED;
+            }
+        }
+
+        /* Check whether there is a pending security procedure, if so we should always queue */
+        /* the new security request */
+        if (p_dev_rec->sec_state != BTM_SEC_STATE_IDLE)
+        {
+            BTM_TRACE_EVENT("%s: There is a pending security procedure", __func__);
+            rc = BTM_CMD_STARTED;
+        }
+        if (rc == BTM_CMD_STARTED)
+        {
+            BTM_TRACE_EVENT("%s: call btm_sec_queue_mx_request", __func__);
+            btm_sec_queue_mx_request (bd_addr, psm,  is_originator, mx_proto_id,
+                                      mx_chan_id, p_callback, p_ref_data);
+        }
+        else /* rc == BTM_SUCCESS */
+        {
+            /* access granted */
+             if (p_callback)
+            {
+                (*p_callback) (bd_addr, transport, p_ref_data, (uint8_t)rc);
+            }
+        }
+
+        BTM_TRACE_EVENT("%s: return with rc = 0x%02x in delayed state %s", __func__, rc,
+                          btm_pair_state_descr(btm_cb.pairing_state));
+        return rc;
+    }
+
+    if ((!is_originator) && ((security_required & BTM_SEC_MODE4_LEVEL4) ||
+        (btm_cb.security_mode == BTM_SEC_MODE_SC)))
+    {
+        bool    local_supports_sc = controller_get_interface()->supports_secure_connections();
+        /* acceptor receives service connection establishment Request for */
+        /* Secure Connections Only service */
+        if (!(local_supports_sc) || !(p_dev_rec->remote_supports_secure_connections))
+        {
+            BTM_TRACE_DEBUG("%s: SC only service,local_support_for_sc %d,",
+                            "remote_support_for_sc %d: fail pairing",__func__,
+                            local_supports_sc, p_dev_rec->remote_supports_secure_connections);
+
+            if (p_callback)
+                (*p_callback) (bd_addr, transport, (void *)p_ref_data,
+                               BTM_MODE4_LEVEL4_NOT_SUPPORTED);
+
+            return (BTM_MODE4_LEVEL4_NOT_SUPPORTED);
+        }
+    }
+
+    p_dev_rec->p_cur_service     = p_serv_rec;
+    p_dev_rec->security_required = security_required;
+
+    if (btm_cb.security_mode == BTM_SEC_MODE_SP ||
+        btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG ||
+        btm_cb.security_mode == BTM_SEC_MODE_SC)
+    {
+        if (BTM_SEC_IS_SM4(p_dev_rec->sm4))
+        {
+            if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) &&
+                (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256))
+            {
+                /* BTM_LKEY_TYPE_AUTH_COMB_P_256 is the only acceptable key in this case */
+                if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) != 0)
+                {
+                    p_dev_rec->sm4 |= BTM_SM4_UPGRADE;
+                }
+
+                p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED |
+                                          BTM_SEC_AUTHENTICATED);
+                BTM_TRACE_DEBUG("%s: sec_flags:0x%x", __func__, p_dev_rec->sec_flags);
+            }
+            else
+            {
+                /* If we already have a link key, check if that link key is good enough */
+                btm_sec_check_upgrade(p_dev_rec, is_originator);
+            }
+        }
+    }
+
+    p_dev_rec->is_originator     = is_originator;
+    p_dev_rec->p_callback        = p_callback;
+    p_dev_rec->p_ref_data        = p_ref_data;
+
+    /* Although authentication and encryption are per connection */
+    /* authorization is per access request.  For example when serial connection */
+    /* is up and authorized and client requests to read file (access to other */
+    /* scn, we need to request user's permission again. */
+    p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED);
+
+    BTM_TRACE_EVENT ("%s() proto_id:%d chan_id:%d State:%d Flags:0x%x Required:0x%x Service ID:%d",
+                      __func__, mx_proto_id, mx_chan_id, p_dev_rec->sec_state, p_dev_rec->sec_flags,
+                      p_dev_rec->security_required, p_dev_rec->p_cur_service->service_id);
+
+    if ((rc = btm_sec_execute_procedure (p_dev_rec)) != BTM_CMD_STARTED)
+    {
+        if (p_callback)
+        {
+            p_dev_rec->p_callback = NULL;
+            (*p_callback) (bd_addr,transport, p_ref_data, (uint8_t)rc);
+        }
+    }
+
+    return rc;
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_conn_req
+**
+** Description      This function is when the peer device is requesting
+**                  connection
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sec_conn_req (uint8_t *bda, uint8_t *dc)
+{
+    tBTM_SEC_DEV_REC  *p_dev_rec = btm_find_dev (bda);
+
+    /* Some device may request a connection before we are done with the HCI_Reset sequence */
+    if (!controller_get_interface()->get_is_ready())
+    {
+        BTM_TRACE_EVENT ("Security Manager: connect request when device not ready");
+        btsnd_hcic_reject_conn (bda, HCI_ERR_HOST_REJECT_DEVICE);
+        return;
+    }
+
+    /* Security guys wants us not to allow connection from not paired devices */
+
+    /* Check if connection is allowed for only paired devices */
+    if (btm_cb.connect_only_paired)
+    {
+        if (!p_dev_rec || !(p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED))
+        {
+            BTM_TRACE_EVENT ("Security Manager: connect request from non-paired device");
+            btsnd_hcic_reject_conn (bda, HCI_ERR_HOST_REJECT_DEVICE);
+            return;
+        }
+    }
+
+#if (BTM_ALLOW_CONN_IF_NONDISCOVER == FALSE)
+    /* If non-discoverable, only allow known devices to connect */
+    if (btm_cb.btm_inq_vars.discoverable_mode == BTM_NON_DISCOVERABLE)
+    {
+        if (!p_dev_rec)
+        {
+            BTM_TRACE_EVENT ("Security Manager: connect request from not paired device");
+            btsnd_hcic_reject_conn (bda, HCI_ERR_HOST_REJECT_DEVICE);
+            return;
+        }
+    }
+#endif
+
+    if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+        &&(btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+        &&(!memcmp (btm_cb.pairing_bda, bda, BD_ADDR_LEN)))
+    {
+        BTM_TRACE_EVENT ("Security Manager: reject connect request from bonding device");
+
+        /* incoming connection from bonding device is rejected */
+        btm_cb.pairing_flags |= BTM_PAIR_FLAGS_REJECTED_CONNECT;
+        btsnd_hcic_reject_conn (bda, HCI_ERR_HOST_REJECT_DEVICE);
+        return;
+    }
+
+    /* Host is not interested or approved connection.  Save BDA and DC and */
+    /* pass request to L2CAP */
+    memcpy (btm_cb.connecting_bda, bda, BD_ADDR_LEN);
+    memcpy (btm_cb.connecting_dc,  dc,  DEV_CLASS_LEN);
+
+    if (l2c_link_hci_conn_req (bda))
+    {
+        if (!p_dev_rec)
+        {
+            /* accept the connection -> allocate a device record */
+            p_dev_rec = btm_sec_alloc_dev (bda);
+        }
+        if (p_dev_rec)
+        {
+            p_dev_rec->sm4 |= BTM_SM4_CONN_PEND;
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_bond_cancel_complete
+**
+** Description      This function is called to report bond cancel complete
+**                  event.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_sec_bond_cancel_complete (void)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec;
+
+    if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) ||
+        (BTM_PAIR_STATE_WAIT_LOCAL_PIN == btm_cb.pairing_state &&
+         BTM_PAIR_FLAGS_WE_STARTED_DD & btm_cb.pairing_flags) ||
+         (btm_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME &&
+          BTM_PAIR_FLAGS_WE_CANCEL_DD & btm_cb.pairing_flags))
+    {
+        /* for dedicated bonding in legacy mode, authentication happens at "link level"
+         * btm_sec_connected is called with failed status.
+         * In theory, the code that handles is_pairing_device/true should clean out security related code.
+         * However, this function may clean out the security related flags and btm_sec_connected would not know
+         * this function also needs to do proper clean up.
+         */
+        if ((p_dev_rec = btm_find_dev (btm_cb.pairing_bda)) != NULL)
+            p_dev_rec->security_required = BTM_SEC_NONE;
+        btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+
+        /* Notify application that the cancel succeeded */
+        if (btm_cb.api.p_bond_cancel_cmpl_callback)
+            btm_cb.api.p_bond_cancel_cmpl_callback(BTM_SUCCESS);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_create_conn_cancel_complete
+**
+** Description      This function is called when the command complete message
+**                  is received from the HCI for the create connection cancel
+**                  command.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_create_conn_cancel_complete (uint8_t *p)
+{
+    uint8_t     status;
+
+    STREAM_TO_UINT8 (status, p);
+    BTM_TRACE_EVENT ("btm_create_conn_cancel_complete(): in State: %s  status:%d",
+                      btm_pair_state_descr(btm_cb.pairing_state), status);
+
+    /* if the create conn cancel cmd was issued by the bond cancel,
+    ** the application needs to be notified that bond cancel succeeded
+    */
+    switch (status)
+    {
+        case HCI_SUCCESS:
+            btm_sec_bond_cancel_complete();
+            break;
+        case HCI_ERR_CONNECTION_EXISTS:
+        case HCI_ERR_NO_CONNECTION:
+        default:
+            /* Notify application of the error */
+            if (btm_cb.api.p_bond_cancel_cmpl_callback)
+                btm_cb.api.p_bond_cancel_cmpl_callback(BTM_ERR_PROCESSING);
+            break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_check_pending_reqs
+**
+** Description      This function is called at the end of the security procedure
+**                  to let L2CAP and RFCOMM know to re-submit any pending requests
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sec_check_pending_reqs (void)
+{
+    if (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE)
+    {
+        /* First, resubmit L2CAP requests */
+        if (btm_cb.sec_req_pending)
+        {
+            btm_cb.sec_req_pending = false;
+            l2cu_resubmit_pending_sec_req (NULL);
+        }
+
+        /* Now, re-submit anything in the mux queue */
+        fixed_queue_t *bq = btm_cb.sec_pending_q;
+
+        btm_cb.sec_pending_q = fixed_queue_new(SIZE_MAX);
+
+        tBTM_SEC_QUEUE_ENTRY *p_e;
+        while ((p_e = (tBTM_SEC_QUEUE_ENTRY *)fixed_queue_try_dequeue(bq)) != NULL)
+        {
+            /* Check that the ACL is still up before starting security procedures */
+            if (btm_bda_to_acl(p_e->bd_addr, p_e->transport) != NULL)
+            {
+                if (p_e->psm != 0)
+                {
+                    BTM_TRACE_EVENT("%s PSM:0x%04x Is_Orig:%u mx_proto_id:%u mx_chan_id:%u",
+                                    __func__, p_e->psm, p_e->is_orig,
+                                    p_e->mx_proto_id, p_e->mx_chan_id);
+
+                    btm_sec_mx_access_request (p_e->bd_addr, p_e->psm, p_e->is_orig,
+                                           p_e->mx_proto_id, p_e->mx_chan_id,
+                                           p_e->p_callback, p_e->p_ref_data);
+                }
+                else
+                {
+                    BTM_SetEncryption(p_e->bd_addr, p_e->transport, p_e->p_callback,
+                                      p_e->p_ref_data, p_e->sec_act);
+                }
+            }
+
+            osi_free(p_e);
+        }
+        fixed_queue_free(bq, NULL);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_init
+**
+** Description      This function is on the SEC startup
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sec_init (uint8_t sec_mode)
+{
+    btm_cb.security_mode = sec_mode;
+    memset (btm_cb.pairing_bda, 0xff, BD_ADDR_LEN);
+    btm_cb.max_collision_delay = BTM_SEC_MAX_COLLISION_DELAY;
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_device_down
+**
+** Description      This function should be called when device is disabled or
+**                  turned off
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sec_device_down (void)
+{
+    BTM_TRACE_EVENT ("%s() State: %s", __func__, btm_pair_state_descr(btm_cb.pairing_state));
+    btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_dev_reset
+**
+** Description      This function should be called after device reset
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sec_dev_reset (void)
+{
+    if (controller_get_interface()->supports_simple_pairing())
+    {
+        /* set the default IO capabilities */
+        btm_cb.devcb.loc_io_caps = BTM_LOCAL_IO_CAPS;
+        /* add mx service to use no security */
+        BTM_SetSecurityLevel(false, "RFC_MUX", BTM_SEC_SERVICE_RFC_MUX,
+                             BTM_SEC_NONE, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, 0);
+    }
+    else
+    {
+        btm_cb.security_mode = BTM_SEC_MODE_SERVICE;
+    }
+
+    BTM_TRACE_DEBUG ("btm_sec_dev_reset sec mode: %d", btm_cb.security_mode);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_abort_access_req
+**
+** Description      This function is called by the L2CAP or RFCOMM to abort
+**                  the pending operation.
+**
+** Parameters:      bd_addr       - Address of the peer device
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sec_abort_access_req (BD_ADDR bd_addr)
+{
+    tBTM_SEC_DEV_REC  *p_dev_rec = btm_find_dev (bd_addr);
+
+    if (!p_dev_rec)
+        return;
+
+    if ((p_dev_rec->sec_state != BTM_SEC_STATE_AUTHORIZING)
+        && (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHENTICATING))
+        return;
+
+    p_dev_rec->sec_state  = BTM_SEC_STATE_IDLE;
+    p_dev_rec->p_callback = NULL;
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_dd_create_conn
+**
+** Description      This function is called to create the ACL connection for
+**                  the dedicated boding process
+**
+** Returns          void
+**
+*******************************************************************************/
+static tBTM_STATUS btm_sec_dd_create_conn (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+    tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR);
+    if (p_lcb && (p_lcb->link_state == LST_CONNECTED || p_lcb->link_state == LST_CONNECTING))
+    {
+       BTM_TRACE_WARNING("%s Connection already exists", __func__);
+       btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ);
+       return BTM_CMD_STARTED;
+    }
+
+    /* Make sure an L2cap link control block is available */
+    if (!p_lcb && (p_lcb = l2cu_allocate_lcb (p_dev_rec->bd_addr, true, BT_TRANSPORT_BR_EDR)) == NULL)
+    {
+        BTM_TRACE_WARNING ("Security Manager: failed allocate LCB [%02x%02x%02x%02x%02x%02x]",
+                            p_dev_rec->bd_addr[0], p_dev_rec->bd_addr[1], p_dev_rec->bd_addr[2],
+                            p_dev_rec->bd_addr[3], p_dev_rec->bd_addr[4], p_dev_rec->bd_addr[5]);
+
+        return(BTM_NO_RESOURCES);
+    }
+
+    /* set up the control block to indicated dedicated bonding */
+    btm_cb.pairing_flags |= BTM_PAIR_FLAGS_DISC_WHEN_DONE;
+
+    if (l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR) == false)
+    {
+        BTM_TRACE_WARNING ("Security Manager: failed create  [%02x%02x%02x%02x%02x%02x]",
+                            p_dev_rec->bd_addr[0], p_dev_rec->bd_addr[1], p_dev_rec->bd_addr[2],
+                            p_dev_rec->bd_addr[3], p_dev_rec->bd_addr[4], p_dev_rec->bd_addr[5]);
+
+        l2cu_release_lcb(p_lcb);
+        return(BTM_NO_RESOURCES);
+    }
+
+    btm_acl_update_busy_level (BTM_BLI_PAGE_EVT);
+
+    BTM_TRACE_DEBUG ("Security Manager: btm_sec_dd_create_conn [%02x%02x%02x%02x%02x%02x]",
+                      p_dev_rec->bd_addr[0], p_dev_rec->bd_addr[1], p_dev_rec->bd_addr[2],
+                      p_dev_rec->bd_addr[3], p_dev_rec->bd_addr[4], p_dev_rec->bd_addr[5]);
+
+    btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_PIN_REQ);
+
+    return(BTM_CMD_STARTED);
+}
+
+
+bool is_state_getting_name(void *data, void *context)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = static_cast<tBTM_SEC_DEV_REC *>(data);
+
+    if (p_dev_rec->sec_state == BTM_SEC_STATE_GETTING_NAME) {
+        return false;
+    }
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_rmt_name_request_complete
+*
+** Description      This function is called when remote name was obtained from
+**                  the peer device
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sec_rmt_name_request_complete (uint8_t *p_bd_addr, uint8_t *p_bd_name, uint8_t status)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec;
+    int              i;
+    DEV_CLASS        dev_class;
+    uint8_t          old_sec_state;
+
+    BTM_TRACE_EVENT ("btm_sec_rmt_name_request_complete");
+    if (((p_bd_addr == NULL) && !BTM_ACL_IS_CONNECTED(btm_cb.connecting_bda))
+        || ((p_bd_addr != NULL) && !BTM_ACL_IS_CONNECTED(p_bd_addr)))
+    {
+        btm_acl_resubmit_page();
+    }
+
+    /* If remote name request failed, p_bd_addr is null and we need to search */
+    /* based on state assuming that we are doing 1 at a time */
+    if (p_bd_addr)
+        p_dev_rec = btm_find_dev (p_bd_addr);
+    else
+    {
+        list_node_t *node = list_foreach(btm_cb.sec_dev_rec, is_state_getting_name, NULL);
+        if (node != NULL) {
+            p_dev_rec = static_cast<tBTM_SEC_DEV_REC *>(list_node(node));
+            p_bd_addr = p_dev_rec->bd_addr;
+        } else {
+            p_dev_rec = NULL;
+        }
+    }
+
+    /* Commenting out trace due to obf/compilation problems.
+    */
+    if (!p_bd_name)
+        p_bd_name = (uint8_t *)"";
+
+    if (p_dev_rec)
+    {
+        BTM_TRACE_EVENT ("%s PairState: %s  RemName: %s  status: %d State:%d  p_dev_rec: 0x%08x ", __func__,
+                          btm_pair_state_descr (btm_cb.pairing_state), p_bd_name,
+                          status, p_dev_rec->sec_state, p_dev_rec);
+    } else {
+        BTM_TRACE_EVENT ("%s PairState: %s  RemName: %s  status: %d", __func__,
+                          btm_pair_state_descr (btm_cb.pairing_state), p_bd_name,
+                          status);
+    }
+
+    if (p_dev_rec)
+    {
+        old_sec_state = p_dev_rec->sec_state;
+        if (status == HCI_SUCCESS)
+        {
+            strlcpy((char *)p_dev_rec->sec_bd_name, (char *)p_bd_name, BTM_MAX_REM_BD_NAME_LEN);
+            p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN;
+            BTM_TRACE_EVENT ("setting BTM_SEC_NAME_KNOWN sec_flags:0x%x", p_dev_rec->sec_flags);
+        }
+        else
+        {
+            /* Notify all clients waiting for name to be resolved even if it failed so clients can continue */
+            p_dev_rec->sec_bd_name[0] = 0;
+        }
+
+        if (p_dev_rec->sec_state == BTM_SEC_STATE_GETTING_NAME)
+            p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+
+        /* Notify all clients waiting for name to be resolved */
+        for (i = 0;i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++)
+        {
+            if (btm_cb.p_rmt_name_callback[i] && p_bd_addr)
+                (*btm_cb.p_rmt_name_callback[i])(p_bd_addr, p_dev_rec->dev_class,
+                                                 p_dev_rec->sec_bd_name);
+        }
+    } else {
+        dev_class[0] = 0;
+        dev_class[1] = 0;
+        dev_class[2] = 0;
+
+        /* Notify all clients waiting for name to be resolved even if not found so clients can continue */
+        for (i = 0;i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++)
+        {
+            if (btm_cb.p_rmt_name_callback[i] && p_bd_addr)
+                (*btm_cb.p_rmt_name_callback[i])(p_bd_addr, dev_class, (uint8_t *)"");
+        }
+
+        return;
+    }
+
+    /* If we were delaying asking UI for a PIN because name was not resolved, ask now */
+    if ( (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_LOCAL_PIN) && p_bd_addr
+         &&  (memcmp (btm_cb.pairing_bda, p_bd_addr, BD_ADDR_LEN) == 0) )
+    {
+        BTM_TRACE_EVENT ("%s() delayed pin now being requested flags:0x%x, (p_pin_callback=0x%p)",
+            __func__, btm_cb.pairing_flags, btm_cb.api.p_pin_callback);
+
+        if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_PIN_REQD) == 0 && btm_cb.api.p_pin_callback)
+        {
+            BTM_TRACE_EVENT ("%s() calling pin_callback", __func__);
+            btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD;
+            (*btm_cb.api.p_pin_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class, p_bd_name,
+                    (p_dev_rec->p_cur_service==NULL) ? false
+                     : (p_dev_rec->p_cur_service->security_flags & BTM_SEC_IN_MIN_16_DIGIT_PIN));
+        }
+
+        /* Set the same state again to force the timer to be restarted */
+        btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_LOCAL_PIN);
+        return;
+    }
+
+    /* Check if we were delaying bonding because name was not resolved */
+    if ( btm_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME)
+    {
+        if (p_bd_addr && memcmp (btm_cb.pairing_bda, p_bd_addr, BD_ADDR_LEN) == 0)
+        {
+            BTM_TRACE_EVENT ("%s() continue bonding sm4: 0x%04x, status:0x%x", __func__, p_dev_rec->sm4, status);
+            if(btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_CANCEL_DD)
+            {
+                btm_sec_bond_cancel_complete();
+                return;
+            }
+
+            if (status != HCI_SUCCESS)
+            {
+                btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+
+                if (btm_cb.api.p_auth_complete_callback)
+                    (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,  p_dev_rec->dev_class,
+                                                            p_dev_rec->sec_bd_name, status);
+                return;
+            }
+
+            /* if peer is very old legacy devices, HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT is not reported */
+            if (BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4))
+            {
+                /* set the KNOWN flag only if BTM_PAIR_FLAGS_REJECTED_CONNECT is not set.*/
+                /* If it is set, there may be a race condition */
+                BTM_TRACE_DEBUG ("%s IS_SM4_UNKNOWN Flags:0x%04x", __func__,
+                                   btm_cb.pairing_flags);
+                if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT) == 0)
+                    p_dev_rec->sm4 |= BTM_SM4_KNOWN;
+            }
+
+            BTM_TRACE_DEBUG("%s, SM4 Value: %x, Legacy:%d,IS SM4:%d, Unknown:%d",__func__,
+                p_dev_rec->sm4, BTM_SEC_IS_SM4_LEGACY(p_dev_rec->sm4),
+                BTM_SEC_IS_SM4(p_dev_rec->sm4),BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4));
+
+            /* BT 2.1 or carkit, bring up the connection to force the peer to request PIN.
+            ** Else prefetch (btm_sec_check_prefetch_pin will do the prefetching if needed)
+            */
+            if ((p_dev_rec->sm4 != BTM_SM4_KNOWN) || !btm_sec_check_prefetch_pin(p_dev_rec))
+            {
+                /* if we rejected incoming connection request, we have to wait HCI_Connection_Complete event */
+                /*  before originating  */
+                if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT)
+                {
+                    BTM_TRACE_WARNING ("%s: waiting HCI_Connection_Complete after rejecting connection", __func__);
+                }
+                /* Both we and the peer are 2.1 - continue to create connection */
+                else if (btm_sec_dd_create_conn(p_dev_rec) != BTM_CMD_STARTED)
+                {
+                    BTM_TRACE_WARNING ("%s: failed to start connection", __func__);
+
+                    btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+
+                    if (btm_cb.api.p_auth_complete_callback)
+                    (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,  p_dev_rec->dev_class,
+                                                            p_dev_rec->sec_bd_name, HCI_ERR_MEMORY_FULL);
+                }
+            }
+            return;
+        } else {
+            BTM_TRACE_WARNING ("%s: wrong BDA, retry with pairing BDA", __func__);
+            BTM_ReadRemoteDeviceName (btm_cb.pairing_bda, NULL, BT_TRANSPORT_BR_EDR);
+            return;
+        }
+    }
+
+    /* check if we were delaying link_key_callback because name was not resolved */
+    if (p_dev_rec->link_key_not_sent)
+    {
+        /* If HCI connection complete has not arrived, wait for it */
+        if (p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE)
+            return;
+
+        p_dev_rec->link_key_not_sent = false;
+        btm_send_link_key_notif(p_dev_rec);
+
+        /* If its not us who perform authentication, we should tell stackserver */
+        /* that some authentication has been completed                          */
+        /* This is required when different entities receive link notification and auth complete */
+        if (!(p_dev_rec->security_required & BTM_SEC_OUT_AUTHENTICATE))
+        {
+            if (btm_cb.api.p_auth_complete_callback)
+                (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+                                                        p_dev_rec->dev_class,
+                                                        p_dev_rec->sec_bd_name, HCI_SUCCESS);
+
+        }
+    }
+
+    /* If this is a bonding procedure can disconnect the link now */
+    if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+        && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))
+    {
+        BTM_TRACE_WARNING ("btm_sec_rmt_name_request_complete (none/ce)");
+        p_dev_rec->security_required &= ~(BTM_SEC_OUT_AUTHENTICATE);
+        l2cu_start_post_bond_timer(p_dev_rec->hci_handle);
+        return;
+    }
+
+    if (old_sec_state != BTM_SEC_STATE_GETTING_NAME)
+        return;
+
+    /* If get name failed, notify the waiting layer */
+    if (status != HCI_SUCCESS)
+    {
+        btm_sec_dev_rec_cback_event  (p_dev_rec, BTM_ERR_PROCESSING, false);
+        return;
+    }
+
+    if (p_dev_rec->sm4 & BTM_SM4_REQ_PEND)
+    {
+        BTM_TRACE_EVENT ("waiting for remote features!!");
+        return;
+    }
+
+    /* Remote Name succeeded, execute the next security procedure, if any */
+    status = (uint8_t)btm_sec_execute_procedure (p_dev_rec);
+
+    /* If result is pending reply from the user or from the device is pending */
+    if (status == BTM_CMD_STARTED)
+        return;
+
+    /* There is no next procedure or start of procedure failed, notify the waiting layer */
+    btm_sec_dev_rec_cback_event  (p_dev_rec, status, false);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_rmt_host_support_feat_evt
+**
+** Description      This function is called when the
+**                  HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT is received
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sec_rmt_host_support_feat_evt (uint8_t *p)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec;
+    BD_ADDR         bd_addr;        /* peer address */
+    BD_FEATURES     features;
+
+    STREAM_TO_BDADDR (bd_addr, p);
+    p_dev_rec = btm_find_or_alloc_dev (bd_addr);
+
+    BTM_TRACE_EVENT ("btm_sec_rmt_host_support_feat_evt  sm4: 0x%x  p[0]: 0x%x", p_dev_rec->sm4, p[0]);
+
+    if (BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4))
+    {
+        p_dev_rec->sm4 = BTM_SM4_KNOWN;
+        STREAM_TO_ARRAY(features, p, HCI_FEATURE_BYTES_PER_PAGE);
+        if (HCI_SSP_HOST_SUPPORTED(features))
+        {
+            p_dev_rec->sm4 = BTM_SM4_TRUE;
+        }
+        BTM_TRACE_EVENT ("btm_sec_rmt_host_support_feat_evt sm4: 0x%x features[0]: 0x%x", p_dev_rec->sm4, features[0]);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_io_capabilities_req
+**
+** Description      This function is called when LM request for the IO
+**                  capability of the local device and
+**                  if the OOB data is present for the device in the event
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_io_capabilities_req (uint8_t *p)
+{
+    tBTM_SP_IO_REQ  evt_data;
+    uint8_t         err_code = 0;
+    tBTM_SEC_DEV_REC *p_dev_rec;
+    bool            is_orig = true;
+    uint8_t         callback_rc = BTM_SUCCESS;
+
+    STREAM_TO_BDADDR (evt_data.bd_addr, p);
+
+    /* setup the default response according to compile options */
+    /* assume that the local IO capability does not change
+     * loc_io_caps is initialized with the default value */
+    evt_data.io_cap = btm_cb.devcb.loc_io_caps;
+    evt_data.oob_data = BTM_OOB_NONE;
+    evt_data.auth_req = BTM_DEFAULT_AUTH_REQ;
+
+    BTM_TRACE_EVENT("%s: State: %s", __func__, btm_pair_state_descr(btm_cb.pairing_state));
+
+    p_dev_rec = btm_find_or_alloc_dev (evt_data.bd_addr);
+
+    BTM_TRACE_DEBUG("%s:Security mode: %d, Num Read Remote Feat pages: %d", __func__,
+                      btm_cb.security_mode, p_dev_rec->num_read_pages);
+
+    if ((btm_cb.security_mode == BTM_SEC_MODE_SC) && (p_dev_rec->num_read_pages == 0))
+    {
+        BTM_TRACE_EVENT("%s: Device security mode is SC only.",
+                         "To continue need to know remote features.", __func__);
+
+        p_dev_rec->remote_features_needed = true;
+        return;
+    }
+
+    p_dev_rec->sm4 |= BTM_SM4_TRUE;
+
+    BTM_TRACE_EVENT("%s: State: %s  Flags: 0x%04x  p_cur_service: 0x%08x",
+                     __func__, btm_pair_state_descr(btm_cb.pairing_state),
+                     btm_cb.pairing_flags, p_dev_rec->p_cur_service);
+
+    if (p_dev_rec->p_cur_service)
+    {
+        BTM_TRACE_EVENT("%s: cur_service psm: 0x%04x, security_flags: 0x%04x",
+                         __func__, p_dev_rec->p_cur_service->psm,
+                         p_dev_rec->p_cur_service->security_flags);
+    }
+
+    switch (btm_cb.pairing_state)
+    {
+        /* initiator connecting */
+        case BTM_PAIR_STATE_IDLE:
+            //TODO: Handle Idle pairing state
+            //security_required = p_dev_rec->security_required;
+            break;
+
+        /* received IO capability response already->acceptor */
+        case BTM_PAIR_STATE_INCOMING_SSP:
+            is_orig = false;
+
+            if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_PEER_STARTED_DD)
+            {
+                /* acceptor in dedicated bonding */
+                evt_data.auth_req = BTM_DEFAULT_DD_AUTH_REQ;
+            }
+            break;
+
+        /* initiator, at this point it is expected to be dedicated bonding
+        initiated by local device */
+        case BTM_PAIR_STATE_WAIT_PIN_REQ:
+            if (!memcmp (evt_data.bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN))
+            {
+                evt_data.auth_req = BTM_DEFAULT_DD_AUTH_REQ;
+            }
+            else
+            {
+                err_code = HCI_ERR_HOST_BUSY_PAIRING;
+            }
+            break;
+
+        /* any other state is unexpected */
+        default:
+            err_code = HCI_ERR_HOST_BUSY_PAIRING;
+            BTM_TRACE_ERROR("%s: Unexpected Pairing state received %d", __func__,
+                             btm_cb.pairing_state);
+            break;
+    }
+
+    if (btm_cb.pairing_disabled)
+    {
+        /* pairing is not allowed */
+        BTM_TRACE_DEBUG("%s: Pairing is not allowed -> fail pairing.", __func__);
+        err_code = HCI_ERR_PAIRING_NOT_ALLOWED;
+    }
+    else if (btm_cb.security_mode == BTM_SEC_MODE_SC)
+    {
+        bool    local_supports_sc = controller_get_interface()->supports_secure_connections();
+        /* device in Secure Connections Only mode */
+        if (!(local_supports_sc) || !(p_dev_rec->remote_supports_secure_connections))
+        {
+            BTM_TRACE_DEBUG("%s: SC only service, local_support_for_sc %d,",
+                            " remote_support_for_sc 0x%02x -> fail pairing", __func__,
+                            local_supports_sc, p_dev_rec->remote_supports_secure_connections);
+
+            err_code = HCI_ERR_PAIRING_NOT_ALLOWED;
+        }
+    }
+
+    if (err_code != 0)
+    {
+/* coverity[uninit_use_in_call]
+Event uninit_use_in_call: Using uninitialized element of array "evt_data.bd_addr" in call to function "memcmp"
+False-positive: evt_data.bd_addr is set at the beginning with:     STREAM_TO_BDADDR (evt_data.bd_addr, p);
+*/
+        btsnd_hcic_io_cap_req_neg_reply(evt_data.bd_addr, err_code);
+        return;
+    }
+
+    evt_data.is_orig = is_orig;
+
+    if (is_orig)
+    {
+        /* local device initiated the pairing non-bonding -> use p_cur_service */
+        if (!(btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) &&
+            p_dev_rec->p_cur_service &&
+            (p_dev_rec->p_cur_service->security_flags & BTM_SEC_OUT_AUTHENTICATE))
+        {
+            if (btm_cb.security_mode == BTM_SEC_MODE_SC)
+            {
+                /* SC only mode device requires MITM protection */
+                evt_data.auth_req = BTM_AUTH_SP_YES;
+            }
+            else
+            {
+                evt_data.auth_req = (p_dev_rec->p_cur_service->security_flags &
+                                     BTM_SEC_OUT_MITM)? BTM_AUTH_SP_YES : BTM_AUTH_SP_NO;
+            }
+        }
+    }
+
+    /* Notify L2CAP to increase timeout */
+    l2c_pin_code_request (evt_data.bd_addr);
+
+    memcpy (btm_cb.pairing_bda, evt_data.bd_addr, BD_ADDR_LEN);
+
+/* coverity[uninit_use_in_call]
+Event uninit_use_in_call: Using uninitialized element of array "evt_data.bd_addr" in call to function "memcmp"
+False-positive: False-positive: evt_data.bd_addr is set at the beginning with:     STREAM_TO_BDADDR (evt_data.bd_addr, p);
+*/
+    if (!memcmp (evt_data.bd_addr, btm_cb.connecting_bda, BD_ADDR_LEN))
+        memcpy (p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN);
+
+    btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS);
+
+    callback_rc = BTM_SUCCESS;
+    if (p_dev_rec->sm4 & BTM_SM4_UPGRADE)
+    {
+        p_dev_rec->sm4 &= ~BTM_SM4_UPGRADE;
+
+        /* link key upgrade: always use SPGB_YES - assuming we want to save the link key */
+        evt_data.auth_req = BTM_AUTH_SPGB_YES;
+    }
+    else if (btm_cb.api.p_sp_callback)
+    {
+        /* the callback function implementation may change the IO capability... */
+        callback_rc = (*btm_cb.api.p_sp_callback) (BTM_SP_IO_REQ_EVT, (tBTM_SP_EVT_DATA *)&evt_data);
+    }
+
+    if ((callback_rc == BTM_SUCCESS) || (BTM_OOB_UNKNOWN != evt_data.oob_data))
+    {
+        if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD))
+        {
+            evt_data.auth_req = (BTM_AUTH_DD_BOND | (evt_data.auth_req & BTM_AUTH_YN_BIT));
+        }
+
+        if (btm_cb.security_mode == BTM_SEC_MODE_SC)
+        {
+            /* At this moment we know that both sides are SC capable, device in */
+            /* SC only mode requires MITM for any service so let's set MITM bit */
+            evt_data.auth_req |= BTM_AUTH_YN_BIT;
+            BTM_TRACE_DEBUG("%s: for device in \"SC only\" mode set auth_req to 0x%02x",
+                             __func__, evt_data.auth_req);
+        }
+
+        /* if the user does not indicate "reply later" by setting the oob_data to unknown */
+        /* send the response right now. Save the current IO capability in the control block */
+        btm_cb.devcb.loc_auth_req   = evt_data.auth_req;
+        btm_cb.devcb.loc_io_caps    = evt_data.io_cap;
+
+        BTM_TRACE_EVENT("%s: State: %s  IO_CAP:%d oob_data:%d auth_req:%d",
+                         __func__, btm_pair_state_descr(btm_cb.pairing_state), evt_data.io_cap,
+                         evt_data.oob_data, evt_data.auth_req);
+
+        btsnd_hcic_io_cap_req_reply(evt_data.bd_addr, evt_data.io_cap,
+                                    evt_data.oob_data, evt_data.auth_req);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_io_capabilities_rsp
+**
+** Description      This function is called when the IO capability of the
+**                  specified device is received
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_io_capabilities_rsp (uint8_t *p)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec;
+    tBTM_SP_IO_RSP evt_data;
+
+    STREAM_TO_BDADDR (evt_data.bd_addr, p);
+    STREAM_TO_UINT8 (evt_data.io_cap, p);
+    STREAM_TO_UINT8 (evt_data.oob_data, p);
+    STREAM_TO_UINT8 (evt_data.auth_req, p);
+
+    /* Allocate a new device record or reuse the oldest one */
+    p_dev_rec = btm_find_or_alloc_dev (evt_data.bd_addr);
+
+    /* If no security is in progress, this indicates incoming security */
+    if (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE)
+    {
+        memcpy (btm_cb.pairing_bda, evt_data.bd_addr, BD_ADDR_LEN);
+
+        btm_sec_change_pairing_state (BTM_PAIR_STATE_INCOMING_SSP);
+
+        /* Make sure we reset the trusted mask to help against attacks */
+        BTM_SEC_CLR_TRUSTED_DEVICE(p_dev_rec->trusted_mask);
+
+        /* work around for FW bug */
+        btm_inq_stop_on_ssp();
+    }
+
+    /* Notify L2CAP to increase timeout */
+    l2c_pin_code_request (evt_data.bd_addr);
+
+    /* We must have a device record here.
+     * Use the connecting device's CoD for the connection */
+/* coverity[uninit_use_in_call]
+Event uninit_use_in_call: Using uninitialized element of array "evt_data.bd_addr" in call to function "memcmp"
+FALSE-POSITIVE error from Coverity test-tool. evt_data.bd_addr is set at the beginning with:     STREAM_TO_BDADDR (evt_data.bd_addr, p);
+*/
+    if (!memcmp (evt_data.bd_addr, btm_cb.connecting_bda, BD_ADDR_LEN))
+        memcpy (p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN);
+
+    /* peer sets dedicated bonding bit and we did not initiate dedicated bonding */
+    if (btm_cb.pairing_state == BTM_PAIR_STATE_INCOMING_SSP /* peer initiated bonding */
+        && (evt_data.auth_req & BTM_AUTH_DD_BOND) )            /* and dedicated bonding bit is set */
+    {
+        btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PEER_STARTED_DD;
+    }
+
+    /* save the IO capability in the device record */
+    p_dev_rec->rmt_io_caps  = evt_data.io_cap;
+    p_dev_rec->rmt_auth_req = evt_data.auth_req;
+
+    if (btm_cb.api.p_sp_callback)
+        (*btm_cb.api.p_sp_callback) (BTM_SP_IO_RSP_EVT, (tBTM_SP_EVT_DATA *)&evt_data);
+}
+
+/*******************************************************************************
+**
+** Function         btm_proc_sp_req_evt
+**
+** Description      This function is called to process/report
+**                  HCI_USER_CONFIRMATION_REQUEST_EVT
+**                  or HCI_USER_PASSKEY_REQUEST_EVT
+**                  or HCI_USER_PASSKEY_NOTIFY_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_proc_sp_req_evt (tBTM_SP_EVT event, uint8_t *p)
+{
+    tBTM_STATUS status = BTM_ERR_PROCESSING;
+    tBTM_SP_EVT_DATA evt_data;
+    uint8_t             *p_bda = evt_data.cfm_req.bd_addr;
+    tBTM_SEC_DEV_REC *p_dev_rec;
+
+    /* All events start with bd_addr */
+    STREAM_TO_BDADDR (p_bda, p);
+
+    BTM_TRACE_EVENT ("btm_proc_sp_req_evt() BDA: %08x%04x event: 0x%x, State: %s",
+                      (p_bda[0]<<24) + (p_bda[1]<<16) + (p_bda[2]<<8) + p_bda[3], (p_bda[4] << 8) + p_bda[5],
+                      event, btm_pair_state_descr(btm_cb.pairing_state));
+
+    if ( ((p_dev_rec = btm_find_dev (p_bda)) != NULL)
+         &&  (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+         &&  (memcmp (btm_cb.pairing_bda, p_bda, BD_ADDR_LEN) == 0) )
+    {
+        memcpy (evt_data.cfm_req.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
+        memcpy (evt_data.cfm_req.dev_class, p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+        strlcpy((char *)evt_data.cfm_req.bd_name, (char *)p_dev_rec->sec_bd_name, BTM_MAX_REM_BD_NAME_LEN);
+
+        switch (event)
+        {
+            case BTM_SP_CFM_REQ_EVT:
+                /* Numeric confirmation. Need user to conf the passkey */
+                btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM);
+
+                /* The device record must be allocated in the "IO cap exchange" step */
+                STREAM_TO_UINT32 (evt_data.cfm_req.num_val, p);
+
+                evt_data.cfm_req.just_works = true;
+
+                /* process user confirm req in association with the auth_req param */
+#if (BTM_LOCAL_IO_CAPS == BTM_IO_CAP_IO)
+                if ( (p_dev_rec->rmt_io_caps == BTM_IO_CAP_IO)
+                     &&  (btm_cb.devcb.loc_io_caps == BTM_IO_CAP_IO)
+                     &&  ((p_dev_rec->rmt_auth_req & BTM_AUTH_SP_YES) || (btm_cb.devcb.loc_auth_req & BTM_AUTH_SP_YES)) )
+                {
+                    /* Both devices are DisplayYesNo and one or both devices want to authenticate
+                       -> use authenticated link key */
+                    evt_data.cfm_req.just_works = false;
+                }
+#endif
+                BTM_TRACE_DEBUG ("btm_proc_sp_req_evt()  just_works:%d, io loc:%d, rmt:%d, auth loc:%d, rmt:%d",
+                                  evt_data.cfm_req.just_works, btm_cb.devcb.loc_io_caps, p_dev_rec->rmt_io_caps,
+                                  btm_cb.devcb.loc_auth_req, p_dev_rec->rmt_auth_req);
+
+                evt_data.cfm_req.loc_auth_req   = btm_cb.devcb.loc_auth_req;
+                evt_data.cfm_req.rmt_auth_req   = p_dev_rec->rmt_auth_req;
+                evt_data.cfm_req.loc_io_caps    = btm_cb.devcb.loc_io_caps;
+                evt_data.cfm_req.rmt_io_caps    = p_dev_rec->rmt_io_caps;
+                break;
+
+            case BTM_SP_KEY_NOTIF_EVT:
+                /* Passkey notification (other side is a keyboard) */
+                STREAM_TO_UINT32 (evt_data.key_notif.passkey, p);
+
+                BTM_TRACE_DEBUG ("BTM_SP_KEY_NOTIF_EVT:  passkey: %u", evt_data.key_notif.passkey);
+
+                btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+                break;
+
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+            case BTM_SP_KEY_REQ_EVT:
+                /* HCI_USER_PASSKEY_REQUEST_EVT */
+                btm_sec_change_pairing_state (BTM_PAIR_STATE_KEY_ENTRY);
+                break;
+#endif
+        }
+
+        if (btm_cb.api.p_sp_callback)
+        {
+            status = (*btm_cb.api.p_sp_callback) (event, (tBTM_SP_EVT_DATA *)&evt_data);
+            if (status != BTM_NOT_AUTHORIZED)
+            {
+                return;
+            }
+            /* else BTM_NOT_AUTHORIZED means when the app wants to reject the req right now */
+        }
+        else if ( (event == BTM_SP_CFM_REQ_EVT) && (evt_data.cfm_req.just_works == true) )
+        {
+            /* automatically reply with just works if no sp_cback */
+            status = BTM_SUCCESS;
+        }
+
+        if (event == BTM_SP_CFM_REQ_EVT)
+        {
+            BTM_TRACE_DEBUG ("calling BTM_ConfirmReqReply with status: %d", status);
+            BTM_ConfirmReqReply (status, p_bda);
+        }
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+        else if (event == BTM_SP_KEY_REQ_EVT)
+        {
+            BTM_PasskeyReqReply(status, p_bda, 0);
+        }
+#endif
+        return;
+    }
+
+    /* Something bad. we can only fail this connection */
+    btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+
+    if (BTM_SP_CFM_REQ_EVT == event)
+    {
+        btsnd_hcic_user_conf_reply (p_bda, false);
+    }
+    else if (BTM_SP_KEY_NOTIF_EVT == event)
+    {
+        /* do nothing -> it very unlikely to happen.
+        This event is most likely to be received by a HID host when it first connects to a HID device.
+        Usually the Host initiated the connection in this case.
+        On Mobile platforms, if there's a security process happening,
+        the host probably can not initiate another connection.
+        BTW (PC) is another story.  */
+        if (NULL != (p_dev_rec = btm_find_dev (p_bda)) )
+        {
+            btm_sec_disconnect (p_dev_rec->hci_handle, HCI_ERR_AUTH_FAILURE);
+        }
+    }
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+    else
+    {
+        btsnd_hcic_user_passkey_neg_reply(p_bda);
+    }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btm_keypress_notif_evt
+**
+** Description      This function is called when a key press notification is
+**                  received
+**
+** Returns          void
+**
+*******************************************************************************/
+void  btm_keypress_notif_evt (uint8_t *p)
+{
+    tBTM_SP_KEYPRESS    evt_data;
+    uint8_t *p_bda;
+
+    /* parse & report BTM_SP_KEYPRESS_EVT */
+    if (btm_cb.api.p_sp_callback)
+    {
+        p_bda = evt_data.bd_addr;
+
+        STREAM_TO_BDADDR (p_bda, p);
+        evt_data.notif_type = *p;
+
+        (*btm_cb.api.p_sp_callback) (BTM_SP_KEYPRESS_EVT, (tBTM_SP_EVT_DATA *)&evt_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_simple_pair_complete
+**
+** Description      This function is called when simple pairing process is
+**                  complete
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_simple_pair_complete (uint8_t *p)
+{
+    tBTM_SP_COMPLT  evt_data;
+    tBTM_SEC_DEV_REC *p_dev_rec;
+    uint8_t         status;
+    bool            disc = false;
+
+    status = *p++;
+    STREAM_TO_BDADDR (evt_data.bd_addr, p);
+
+    if ((p_dev_rec = btm_find_dev (evt_data.bd_addr)) == NULL)
+    {
+        BTM_TRACE_ERROR ("btm_simple_pair_complete() with unknown BDA: %08x%04x",
+                          (evt_data.bd_addr[0]<<24) + (evt_data.bd_addr[1]<<16) + (evt_data.bd_addr[2]<<8) + evt_data.bd_addr[3],
+                          (evt_data.bd_addr[4] << 8) + evt_data.bd_addr[5]);
+        return;
+    }
+
+    BTM_TRACE_EVENT ("btm_simple_pair_complete()  Pair State: %s  Status:%d  sec_state: %u",
+                      btm_pair_state_descr(btm_cb.pairing_state),  status, p_dev_rec->sec_state);
+
+    evt_data.status = BTM_ERR_PROCESSING;
+    if (status == HCI_SUCCESS)
+    {
+        evt_data.status = BTM_SUCCESS;
+        p_dev_rec->sec_flags |= BTM_SEC_AUTHENTICATED;
+    }
+    else
+    {
+        if (status == HCI_ERR_PAIRING_NOT_ALLOWED)
+        {
+            /* The test spec wants the peer device to get this failure code. */
+            btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_DISCONNECT);
+
+            /* Change the timer to 1 second */
+            alarm_set_on_queue(btm_cb.pairing_timer, BT_1SEC_TIMEOUT_MS,
+                               btm_sec_pairing_timeout, NULL,
+                               btu_general_alarm_queue);
+        }
+        else if (memcmp (btm_cb.pairing_bda, evt_data.bd_addr, BD_ADDR_LEN) == 0)
+        {
+            /* stop the timer */
+            alarm_cancel(btm_cb.pairing_timer);
+
+            if (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHENTICATING)
+            {
+                /* the initiating side: will receive auth complete event. disconnect ACL at that time */
+                disc = true;
+            }
+        }
+        else
+            disc = true;
+    }
+
+    /* Let the pairing state stay active, p_auth_complete_callback will report the failure */
+    memcpy (evt_data.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
+    memcpy (evt_data.dev_class, p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+    if (btm_cb.api.p_sp_callback)
+        (*btm_cb.api.p_sp_callback) (BTM_SP_COMPLT_EVT, (tBTM_SP_EVT_DATA *)&evt_data);
+
+    if (disc)
+    {
+        /* simple pairing failed */
+        /* Avoid sending disconnect on HCI_ERR_PEER_USER */
+        if ((status != HCI_ERR_PEER_USER) && (status != HCI_ERR_CONN_CAUSE_LOCAL_HOST))
+        {
+            btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_AUTH_FAILURE, p_dev_rec->hci_handle);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_rem_oob_req
+**
+** Description      This function is called to process/report
+**                  HCI_REMOTE_OOB_DATA_REQUEST_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_rem_oob_req (uint8_t *p)
+{
+    uint8_t *p_bda;
+    tBTM_SP_RMT_OOB  evt_data;
+    tBTM_SEC_DEV_REC *p_dev_rec;
+    BT_OCTET16      c;
+    BT_OCTET16      r;
+
+    p_bda = evt_data.bd_addr;
+
+    STREAM_TO_BDADDR (p_bda, p);
+
+    BTM_TRACE_EVENT ("btm_rem_oob_req() BDA: %02x:%02x:%02x:%02x:%02x:%02x",
+                      p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]);
+
+    if ( (NULL != (p_dev_rec = btm_find_dev (p_bda))) &&
+         btm_cb.api.p_sp_callback)
+    {
+        memcpy (evt_data.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
+        memcpy (evt_data.dev_class, p_dev_rec->dev_class, DEV_CLASS_LEN);
+        strlcpy((char *)evt_data.bd_name, (char *)p_dev_rec->sec_bd_name, BTM_MAX_REM_BD_NAME_LEN);
+
+        btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP);
+        if ((*btm_cb.api.p_sp_callback) (BTM_SP_RMT_OOB_EVT, (tBTM_SP_EVT_DATA *)&evt_data) == BTM_NOT_AUTHORIZED)
+        {
+            BTM_RemoteOobDataReply(true, p_bda, c, r);
+        }
+        return;
+    }
+
+    /* something bad. we can only fail this connection */
+    btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+    btsnd_hcic_rem_oob_neg_reply (p_bda);
+}
+
+/*******************************************************************************
+**
+** Function         btm_read_local_oob_complete
+**
+** Description      This function is called when read local oob data is
+**                  completed by the LM
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_read_local_oob_complete (uint8_t *p)
+{
+    tBTM_SP_LOC_OOB evt_data;
+    uint8_t         status = *p++;
+
+    BTM_TRACE_EVENT ("btm_read_local_oob_complete:%d", status);
+    if (status == HCI_SUCCESS)
+    {
+        evt_data.status = BTM_SUCCESS;
+        STREAM_TO_ARRAY16(evt_data.c, p);
+        STREAM_TO_ARRAY16(evt_data.r, p);
+    }
+    else
+        evt_data.status = BTM_ERR_PROCESSING;
+
+    if (btm_cb.api.p_sp_callback)
+        (*btm_cb.api.p_sp_callback) (BTM_SP_LOC_OOB_EVT, (tBTM_SP_EVT_DATA *)&evt_data);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_auth_collision
+**
+** Description      This function is called when authentication or encryption
+**                  needs to be retried at a later time.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_sec_auth_collision (uint16_t handle)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec;
+
+    if (!btm_cb.collision_start_time)
+        btm_cb.collision_start_time = time_get_os_boottime_ms();
+
+    if ((time_get_os_boottime_ms() - btm_cb.collision_start_time) < btm_cb.max_collision_delay)
+    {
+        if (handle == BTM_SEC_INVALID_HANDLE)
+        {
+            if ((p_dev_rec = btm_sec_find_dev_by_sec_state (BTM_SEC_STATE_AUTHENTICATING)) == NULL)
+                p_dev_rec = btm_sec_find_dev_by_sec_state (BTM_SEC_STATE_ENCRYPTING);
+        }
+        else
+            p_dev_rec = btm_find_dev_by_handle (handle);
+
+        if (p_dev_rec != NULL)
+        {
+            BTM_TRACE_DEBUG ("btm_sec_auth_collision: state %d (retrying in a moment...)", p_dev_rec->sec_state);
+            /* We will restart authentication after timeout */
+            if (p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING || p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING)
+                p_dev_rec->sec_state = 0;
+
+            btm_cb.p_collided_dev_rec = p_dev_rec;
+            alarm_set_on_queue(btm_cb.sec_collision_timer, BT_1SEC_TIMEOUT_MS,
+                               btm_sec_collision_timeout, NULL,
+                               btu_general_alarm_queue);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_auth_complete
+**
+** Description      This function is when authentication of the connection is
+**                  completed by the LM
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sec_auth_complete (uint16_t handle, uint8_t status)
+{
+    uint8_t          old_sm4;
+    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;
+
+    if (p_dev_rec)
+    {
+        BTM_TRACE_EVENT ("Security Manager: auth_complete PairState: %s  handle:%u  status:%d  dev->sec_state: %u  Bda:%08x, RName:%s",
+                          btm_pair_state_descr (btm_cb.pairing_state),
+                          handle, status,
+                          p_dev_rec->sec_state,
+                          (p_dev_rec->bd_addr[2]<<24)+(p_dev_rec->bd_addr[3]<<16)+(p_dev_rec->bd_addr[4]<<8)+p_dev_rec->bd_addr[5],
+                          p_dev_rec->sec_bd_name);
+    }
+    else
+    {
+        BTM_TRACE_EVENT ("Security Manager: auth_complete PairState: %s  handle:%u  status:%d",
+                          btm_pair_state_descr (btm_cb.pairing_state),
+                          handle, status);
+    }
+
+    /* For transaction collision we need to wait and repeat.  There is no need */
+    /* for random timeout because only slave should receive the result */
+    if ((status == HCI_ERR_LMP_ERR_TRANS_COLLISION) || (status == HCI_ERR_DIFF_TRANSACTION_COLLISION))
+    {
+        btm_sec_auth_collision(handle);
+        return;
+    }
+    btm_cb.collision_start_time = 0;
+
+    btm_restore_mode();
+
+    /* Check if connection was made just to do bonding.  If we authenticate
+       the connection that is up, this is the last event received.
+    */
+    if (p_dev_rec
+        && (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+        && !(btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE))
+    {
+        p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
+
+        l2cu_start_post_bond_timer (p_dev_rec->hci_handle);
+    }
+
+    if (!p_dev_rec)
+        return;
+
+    /* keep the old sm4 flag and clear the retry bit in control block */
+    old_sm4 = p_dev_rec->sm4;
+    p_dev_rec->sm4 &= ~BTM_SM4_RETRY;
+
+    if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+         &&  (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+         &&  (memcmp (p_dev_rec->bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) == 0) )
+        are_bonding = true;
+
+    if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+          &&  (memcmp (p_dev_rec->bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) == 0) )
+        btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+
+    if (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHENTICATING)
+    {
+        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,
+                                                    p_dev_rec->dev_class,
+                                                    p_dev_rec->sec_bd_name, status);
+        }
+        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)
+    {
+        /* report the suthentication status */
+        if ((old_state != BTM_PAIR_STATE_IDLE) || (status != HCI_SUCCESS))
+            (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+                                                    p_dev_rec->dev_class,
+                                                    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;
+
+        if (status != HCI_SUCCESS)
+        {
+            if(((status != HCI_ERR_PEER_USER) && (status != HCI_ERR_CONN_CAUSE_LOCAL_HOST)))
+                btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_PEER_USER, p_dev_rec->hci_handle);
+        }
+        else
+        {
+            BTM_TRACE_DEBUG ("TRYING TO DECIDE IF CAN USE SMP_BR_CHNL");
+            if (p_dev_rec->new_encryption_key_is_p256 && (btm_sec_use_smp_br_chnl(p_dev_rec))
+                /* no LE keys are available, do deriving */
+                 && (!(p_dev_rec->sec_flags &BTM_SEC_LE_LINK_KEY_KNOWN) ||
+                /* or BR key is higher security than existing LE keys */
+                 (!(p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_AUTHED) &&
+                 (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED))))
+            {
+                BTM_TRACE_DEBUG ("link encrypted afer dedic bonding can use SMP_BR_CHNL");
+
+                if (btm_sec_is_master(p_dev_rec))
+                {
+                    // Encryption is required to start SM over BR/EDR
+                    // indicate that this is encryption after authentication
+                    BTM_SetEncryption(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR, NULL, NULL, 0);
+                }
+            }
+            l2cu_start_post_bond_timer (p_dev_rec->hci_handle);
+        }
+
+        return;
+    }
+
+    /* If authentication failed, notify the waiting layer */
+    if (status != HCI_SUCCESS)
+    {
+        if ((old_sm4 & BTM_SM4_RETRY) == 0)
+        {
+            /* allow retry only once */
+            if (status == HCI_ERR_LMP_ERR_TRANS_COLLISION)
+            {
+                /* not retried yet. set the retry bit */
+                p_dev_rec->sm4 |= BTM_SM4_RETRY;
+                BTM_TRACE_DEBUG ("Collision retry sm4:x%x sec_flags:0x%x", p_dev_rec->sm4, p_dev_rec->sec_flags);
+            }
+            /* this retry for missing key is for Lisbon or later only.
+             * Legacy device do not need this. the controller will drive the retry automatically */
+            else if (HCI_ERR_KEY_MISSING == status && BTM_SEC_IS_SM4(p_dev_rec->sm4))
+            {
+                /* not retried yet. set the retry bit */
+                p_dev_rec->sm4 |= BTM_SM4_RETRY;
+                p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_KNOWN;
+                BTM_TRACE_DEBUG ("Retry for missing key sm4:x%x sec_flags:0x%x", p_dev_rec->sm4, p_dev_rec->sec_flags);
+
+                /* With BRCM controller, we do not need to delete the stored link key in controller.
+                If the stack may sit on top of other controller, we may need this
+                BTM_DeleteStoredLinkKey (bd_addr, NULL); */
+            }
+
+            if (p_dev_rec->sm4 & BTM_SM4_RETRY)
+            {
+                btm_sec_execute_procedure (p_dev_rec);
+                return;
+            }
+        }
+
+        btm_sec_dev_rec_cback_event (p_dev_rec, BTM_ERR_PROCESSING, false);
+
+        if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE)
+        {
+            btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_AUTH_FAILURE, p_dev_rec->hci_handle);
+        }
+        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) {
+        // If we have MITM protection we have a higher level of security than
+        // provided by 16 digits PIN
+        p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
+    }
+
+    /* Authentication succeeded, execute the next security procedure, if any */
+    status = btm_sec_execute_procedure (p_dev_rec);
+
+    /* If there is no next procedure, or procedure failed to start, notify the caller */
+    if (status != BTM_CMD_STARTED)
+        btm_sec_dev_rec_cback_event (p_dev_rec, status, false);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_encrypt_change
+**
+** Description      This function is when encryption of the connection is
+**                  completed by the LM
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sec_encrypt_change (uint16_t handle, uint8_t status, uint8_t encr_enable)
+{
+    tBTM_SEC_DEV_REC  *p_dev_rec = btm_find_dev_by_handle (handle);
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+    tACL_CONN       *p_acl = NULL;
+    uint8_t         acl_idx = btm_handle_to_acl_index(handle);
+#endif
+    BTM_TRACE_EVENT ("Security Manager: encrypt_change status:%d State:%d, encr_enable = %d",
+                      status, (p_dev_rec) ? p_dev_rec->sec_state : 0, encr_enable);
+    BTM_TRACE_DEBUG ("before update p_dev_rec->sec_flags=0x%x", (p_dev_rec) ? p_dev_rec->sec_flags : 0 );
+
+    /* For transaction collision we need to wait and repeat.  There is no need */
+    /* for random timeout because only slave should receive the result */
+    if ((status == HCI_ERR_LMP_ERR_TRANS_COLLISION) ||
+        (status == HCI_ERR_DIFF_TRANSACTION_COLLISION))
+    {
+        btm_sec_auth_collision(handle);
+        return;
+    }
+    btm_cb.collision_start_time = 0;
+
+    if (!p_dev_rec)
+        return;
+
+    if ((status == HCI_SUCCESS) && encr_enable)
+    {
+        if (p_dev_rec->hci_handle == handle) {
+            p_dev_rec->sec_flags |= (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED);
+            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) {
+                p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
+            }
+        }
+        else
+        {
+            p_dev_rec->sec_flags |= (BTM_SEC_LE_AUTHENTICATED | BTM_SEC_LE_ENCRYPTED);
+        }
+    }
+
+    /* It is possible that we decrypted the link to perform role switch */
+    /* mark link not to be encrypted, so that when we execute security next time it will kick in again */
+    if ((status == HCI_SUCCESS) && !encr_enable)
+    {
+        if (p_dev_rec->hci_handle == handle)
+            p_dev_rec->sec_flags &= ~BTM_SEC_ENCRYPTED;
+        else
+            p_dev_rec->sec_flags &= ~BTM_SEC_LE_ENCRYPTED;
+    }
+
+    BTM_TRACE_DEBUG ("after update p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags );
+
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+    if (acl_idx != MAX_L2CAP_LINKS)
+        p_acl = &btm_cb.acl_db[acl_idx];
+
+    if (p_acl != NULL)
+        btm_sec_check_pending_enc_req(p_dev_rec, p_acl->transport, encr_enable);
+
+    if (p_acl && p_acl->transport == BT_TRANSPORT_LE)
+    {
+        if (status == HCI_ERR_KEY_MISSING || status == HCI_ERR_AUTH_FAILURE ||
+            status == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE)
+        {
+            p_dev_rec->sec_flags &= ~ (BTM_SEC_LE_LINK_KEY_KNOWN);
+            p_dev_rec->ble.key_type = BTM_LE_KEY_NONE;
+        }
+        btm_ble_link_encrypted(p_dev_rec->ble.pseudo_addr, encr_enable);
+        return;
+    }
+    else
+    {
+        /* BR/EDR connection, update the encryption key size to be 16 as always */
+        p_dev_rec->enc_key_size = 16;
+    }
+
+     BTM_TRACE_DEBUG ("in %s new_encr_key_256 is %d",
+                       __func__, p_dev_rec->new_encryption_key_is_p256);
+
+    if ((status == HCI_SUCCESS) && encr_enable && (p_dev_rec->hci_handle == handle))
+    {
+        /* if BR key is temporary no need for LE LTK derivation */
+        bool derive_ltk = true;
+        if(p_dev_rec->rmt_auth_req == BTM_AUTH_SP_NO && btm_cb.devcb.loc_auth_req == BTM_AUTH_SP_NO)
+        {
+            derive_ltk = false;
+            BTM_TRACE_DEBUG("%s: BR key is temporary, skip derivation of LE LTK", __func__);
+        }
+        if (p_dev_rec->new_encryption_key_is_p256)
+        {
+            if (btm_sec_use_smp_br_chnl(p_dev_rec) &&
+                btm_sec_is_master(p_dev_rec) &&
+                /* if LE key is not known, do deriving */
+                (!(p_dev_rec->sec_flags &BTM_SEC_LE_LINK_KEY_KNOWN) ||
+                /* or BR key is higher security than existing LE keys */
+                 (!(p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_AUTHED)
+                 && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED))) && derive_ltk)
+            {
+                /* BR/EDR is encrypted with LK that can be used to derive LE LTK */
+                p_dev_rec->new_encryption_key_is_p256 = false;
+
+                if (p_dev_rec->no_smp_on_br)
+                {
+                    BTM_TRACE_DEBUG ("%s NO SM over BR/EDR", __func__);
+                }
+                else
+                {
+                    BTM_TRACE_DEBUG ("%s start SM over BR/EDR", __func__);
+                    SMP_BR_PairWith(p_dev_rec->bd_addr);
+                }
+            }
+        }
+        else
+        {
+            // BR/EDR is successfully encrypted. Correct LK type if needed
+            // (BR/EDR LK derived from LE LTK was used for encryption)
+            if ((encr_enable == 1)  && /* encryption is ON for SSP */
+                /* LK type is for BR/EDR SC */
+                (p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256 ||
+                 p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256))
+            {
+                if (p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256)
+                    p_dev_rec->link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB;
+                else /* BTM_LKEY_TYPE_AUTH_COMB_P_256 */
+                    p_dev_rec->link_key_type = BTM_LKEY_TYPE_AUTH_COMB;
+
+                BTM_TRACE_DEBUG("updated link key type to %d", p_dev_rec->link_key_type);
+                btm_send_link_key_notif(p_dev_rec);
+            }
+        }
+    }
+#else
+    btm_sec_check_pending_enc_req (p_dev_rec, BT_TRANSPORT_BR_EDR, encr_enable);
+#endif /* BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE */
+
+    /* If this encryption was started by peer do not need to do anything */
+    if (p_dev_rec->sec_state != BTM_SEC_STATE_ENCRYPTING)
+    {
+        if (BTM_SEC_STATE_DELAY_FOR_ENC == p_dev_rec->sec_state)
+        {
+            p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+            p_dev_rec->p_callback = NULL;
+            l2cu_resubmit_pending_sec_req (p_dev_rec->bd_addr);
+        }
+        return;
+    }
+
+    p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+    /* If encryption setup failed, notify the waiting layer */
+    if (status != HCI_SUCCESS)
+    {
+        btm_sec_dev_rec_cback_event (p_dev_rec, BTM_ERR_PROCESSING, false);
+        return;
+    }
+
+    /* Encryption setup succeeded, execute the next security procedure, if any */
+    status = (uint8_t)btm_sec_execute_procedure (p_dev_rec);
+    /* If there is no next procedure, or procedure failed to start, notify the caller */
+    if (status != BTM_CMD_STARTED)
+        btm_sec_dev_rec_cback_event (p_dev_rec, status, false);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_connect_after_reject_timeout
+**
+** Description      Connection for bonding could not start because of the collision
+**                  Initiate outgoing connection
+**
+** Returns          Pointer to the TLE struct
+**
+*******************************************************************************/
+static void btm_sec_connect_after_reject_timeout(UNUSED_ATTR void *data)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_cb.p_collided_dev_rec;
+
+    BTM_TRACE_EVENT("%s", __func__);
+    btm_cb.p_collided_dev_rec = 0;
+
+    if (btm_sec_dd_create_conn(p_dev_rec) != BTM_CMD_STARTED)
+    {
+        BTM_TRACE_WARNING("Security Manager: %s: failed to start connection",
+                          __func__);
+
+        btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+
+        if (btm_cb.api.p_auth_complete_callback)
+        (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,  p_dev_rec->dev_class,
+                                                p_dev_rec->sec_bd_name, HCI_ERR_MEMORY_FULL);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_connected
+**
+** Description      This function is when a connection to the peer device is
+**                  establsihed
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sec_connected (uint8_t *bda, uint16_t handle, uint8_t status, uint8_t enc_mode)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda);
+    uint8_t          res;
+    bool             is_pairing_device = false;
+    tACL_CONN        *p_acl_cb;
+    uint8_t          bit_shift = 0;
+
+    btm_acl_resubmit_page();
+
+    if (p_dev_rec)
+    {
+        BTM_TRACE_EVENT ("Security Manager: btm_sec_connected in state: %s  handle:%d status:%d enc_mode:%d  bda:%x RName:%s",
+                          btm_pair_state_descr(btm_cb.pairing_state), handle, status, enc_mode,
+                          (bda[2]<<24)+(bda[3]<<16)+(bda[4]<<8)+bda[5],
+                          p_dev_rec->sec_bd_name);
+    }
+    else
+    {
+        BTM_TRACE_EVENT ("Security Manager: btm_sec_connected in state: %s  handle:%d status:%d enc_mode:%d  bda:%x ",
+                          btm_pair_state_descr(btm_cb.pairing_state), handle, status, enc_mode,
+                          (bda[2]<<24)+(bda[3]<<16)+(bda[4]<<8)+bda[5]);
+    }
+
+    if (!p_dev_rec)
+    {
+        /* There is no device record for new connection.  Allocate one */
+        if (status == HCI_SUCCESS)
+        {
+            p_dev_rec = btm_sec_alloc_dev (bda);
+        }
+        else
+        {
+            /* If the device matches with stored paring address
+             * reset the paring state to idle */
+            if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
+                (memcmp (btm_cb.pairing_bda, bda, BD_ADDR_LEN) == 0))
+            {
+                btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+            }
+
+            /* can not find the device record and the status is error,
+             * just ignore it */
+            return;
+        }
+    }
+    else    /* Update the timestamp for this device */
+    {
+
+#if (BLE_INCLUDED == TRUE)
+        bit_shift = (handle == p_dev_rec->ble_hci_handle) ? 8 :0;
+#endif
+        p_dev_rec->timestamp = btm_cb.dev_rec_count++;
+        if (p_dev_rec->sm4 & BTM_SM4_CONN_PEND)
+        {
+            /* tell L2CAP it's a bonding connection. */
+            if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+                 &&  (memcmp (btm_cb.pairing_bda, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0)
+                 &&  (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) )
+            {
+                /* if incoming connection failed while pairing, then try to connect and continue */
+                /* Motorola S9 disconnects without asking pin code */
+                if ((status != HCI_SUCCESS)&&(btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_PIN_REQ))
+                {
+                    BTM_TRACE_WARNING ("Security Manager: btm_sec_connected: incoming connection failed without asking PIN");
+
+                    p_dev_rec->sm4 &= ~BTM_SM4_CONN_PEND;
+                    if (p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN)
+                    {
+                        /* Start timer with 0 to initiate connection with new LCB */
+                        /* because L2CAP will delete current LCB with this event  */
+                        btm_cb.p_collided_dev_rec = p_dev_rec;
+                        alarm_set_on_queue(btm_cb.sec_collision_timer, 0,
+                                           btm_sec_connect_after_reject_timeout,
+                                           NULL, btu_general_alarm_queue);
+                    }
+                    else
+                    {
+                        btm_sec_change_pairing_state (BTM_PAIR_STATE_GET_REM_NAME);
+                        BTM_ReadRemoteDeviceName(p_dev_rec->bd_addr, NULL, BT_TRANSPORT_BR_EDR);
+                    }
+#if (BTM_DISC_DURING_RS == TRUE)
+                    p_dev_rec->rs_disc_pending   = BTM_SEC_RS_NOT_PENDING;     /* reset flag */
+#endif
+                    return;
+                }
+                else
+                {
+                    l2cu_update_lcb_4_bonding(p_dev_rec->bd_addr, true);
+                }
+            }
+            /* always clear the pending flag */
+            p_dev_rec->sm4 &= ~BTM_SM4_CONN_PEND;
+        }
+    }
+
+#if (BLE_INCLUDED == TRUE)
+    p_dev_rec->device_type |= BT_DEVICE_TYPE_BREDR;
+#endif
+
+#if (BTM_DISC_DURING_RS == TRUE)
+    p_dev_rec->rs_disc_pending   = BTM_SEC_RS_NOT_PENDING;     /* reset flag */
+#endif
+
+    p_dev_rec->rs_disc_pending   = BTM_SEC_RS_NOT_PENDING;     /* reset flag */
+
+    if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+         && (memcmp (btm_cb.pairing_bda, bda, BD_ADDR_LEN) == 0) )
+    {
+        /* if we rejected incoming connection from bonding device */
+        if ((status == HCI_ERR_HOST_REJECT_DEVICE)
+            &&(btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT))
+        {
+            BTM_TRACE_WARNING ("Security Manager: btm_sec_connected: HCI_Conn_Comp Flags:0x%04x, sm4: 0x%x",
+                btm_cb.pairing_flags, p_dev_rec->sm4);
+
+            btm_cb.pairing_flags &= ~BTM_PAIR_FLAGS_REJECTED_CONNECT;
+            if (BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4))
+            {
+                /* Try again: RNR when no ACL causes HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT */
+                btm_sec_change_pairing_state (BTM_PAIR_STATE_GET_REM_NAME);
+                BTM_ReadRemoteDeviceName(bda, NULL, BT_TRANSPORT_BR_EDR);
+                return;
+            }
+
+            /* if we already have pin code */
+            if (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_PIN)
+            {
+                /* Start timer with 0 to initiate connection with new LCB */
+                /* because L2CAP will delete current LCB with this event  */
+                btm_cb.p_collided_dev_rec = p_dev_rec;
+                alarm_set_on_queue(btm_cb.sec_collision_timer, 0,
+                                   btm_sec_connect_after_reject_timeout,
+                                   NULL, btu_general_alarm_queue);
+            }
+
+            return;
+        }
+        /* wait for incoming connection without resetting pairing state */
+        else if (status == HCI_ERR_CONNECTION_EXISTS)
+        {
+            BTM_TRACE_WARNING ("Security Manager: btm_sec_connected: Wait for incoming connection");
+            return;
+        }
+
+        is_pairing_device = true;
+    }
+
+    /* If connection was made to do bonding restore link security if changed */
+    btm_restore_mode();
+
+    /* if connection fails during pin request, notify application */
+    if (status != HCI_SUCCESS)
+    {
+        /* If connection failed because of during pairing, need to tell user */
+        if (is_pairing_device)
+        {
+            p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
+            p_dev_rec->sec_flags &= ~((BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED) << bit_shift);
+            BTM_TRACE_DEBUG ("security_required:%x ", p_dev_rec->security_required );
+
+            btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+
+            /* We need to notify host that the key is not known any more */
+            if (btm_cb.api.p_auth_complete_callback)
+            {
+                (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+                                                        p_dev_rec->dev_class,
+                                                        p_dev_rec->sec_bd_name, status);
+            }
+        }
+ /*
+     Do not send authentication failure, if following conditions hold good
+      1.  BTM Sec Pairing state is idle
+      2.  Link key for the remote device is present.
+      3.  Remote is SSP capable.
+  */
+        else if  ((p_dev_rec->link_key_type  <= BTM_LKEY_TYPE_REMOTE_UNIT) &&
+                 (((status == HCI_ERR_AUTH_FAILURE)                      ||
+                 (status == HCI_ERR_KEY_MISSING)                         ||
+                 (status == HCI_ERR_HOST_REJECT_SECURITY)                ||
+                 (status == HCI_ERR_PAIRING_NOT_ALLOWED)                 ||
+                 (status == HCI_ERR_UNIT_KEY_USED)                       ||
+                 (status == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) ||
+                 (status == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE)           ||
+                 (status == HCI_ERR_REPEATED_ATTEMPTS))))
+        {
+            p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
+            p_dev_rec->sec_flags &= ~ (BTM_SEC_LE_LINK_KEY_KNOWN << bit_shift);
+
+#ifdef BRCM_NOT_4_BTE
+            /* If we rejected pairing, pass this special result code */
+            if (btm_cb.acl_disc_reason == HCI_ERR_HOST_REJECT_SECURITY)
+            {
+                status = HCI_ERR_HOST_REJECT_SECURITY;
+            }
+#endif
+
+            /* We need to notify host that the key is not known any more */
+            if (btm_cb.api.p_auth_complete_callback)
+            {
+                (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+                                                        p_dev_rec->dev_class,
+                                                        p_dev_rec->sec_bd_name, status);
+            }
+        }
+
+        if (status == HCI_ERR_CONNECTION_TOUT || status == HCI_ERR_LMP_RESPONSE_TIMEOUT  ||
+            status == HCI_ERR_UNSPECIFIED     || status == HCI_ERR_PAGE_TIMEOUT)
+            btm_sec_dev_rec_cback_event (p_dev_rec, BTM_DEVICE_TIMEOUT, false);
+        else
+            btm_sec_dev_rec_cback_event (p_dev_rec, BTM_ERR_PROCESSING, false);
+
+        return;
+    }
+
+    /* If initiated dedicated bonding, return the link key now, and initiate disconnect */
+    /* If dedicated bonding, and we now have a link key, we are all done */
+    if ( is_pairing_device
+         && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) )
+    {
+        if (p_dev_rec->link_key_not_sent)
+        {
+            p_dev_rec->link_key_not_sent = false;
+            btm_send_link_key_notif(p_dev_rec);
+        }
+
+        p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
+
+        /* remember flag before it is initialized */
+        if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+            res = true;
+        else
+            res = false;
+
+        if (btm_cb.api.p_auth_complete_callback)
+            (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+                                                    p_dev_rec->dev_class,
+                                                    p_dev_rec->sec_bd_name, HCI_SUCCESS);
+
+        btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+
+        if ( res )
+        {
+            /* Let l2cap start bond timer */
+            l2cu_update_lcb_4_bonding (p_dev_rec->bd_addr, true);
+        }
+
+        return;
+    }
+
+    p_dev_rec->hci_handle = handle;
+
+    /* role may not be correct here, it will be updated by l2cap, but we need to */
+    /* notify btm_acl that link is up, so starting of rmt name request will not */
+    /* set paging flag up */
+    p_acl_cb = btm_bda_to_acl(bda, BT_TRANSPORT_BR_EDR);
+    if (p_acl_cb)
+    {
+        /* whatever is in btm_establish_continue() without reporting the BTM_BL_CONN_EVT event */
+#if (BTM_BYPASS_EXTRA_ACL_SETUP == FALSE)
+        /* For now there are a some devices that do not like sending */
+        /* commands events and data at the same time. */
+        /* Set the packet types to the default allowed by the device */
+        btm_set_packet_types (p_acl_cb, btm_cb.btm_acl_pkt_types_supported);
+
+        if (btm_cb.btm_def_link_policy)
+            BTM_SetLinkPolicy (p_acl_cb->remote_addr, &btm_cb.btm_def_link_policy);
+#endif
+    }
+    btm_acl_created (bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name, handle, HCI_ROLE_SLAVE, BT_TRANSPORT_BR_EDR);
+
+    /* Initialize security flags.  We need to do that because some            */
+    /* authorization complete could have come after the connection is dropped */
+    /* and that would set wrong flag that link has been authorized already    */
+    p_dev_rec->sec_flags &= ~((BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED |
+                              BTM_SEC_ENCRYPTED | BTM_SEC_ROLE_SWITCHED) << bit_shift);
+
+    if (enc_mode != HCI_ENCRYPT_MODE_DISABLED)
+        p_dev_rec->sec_flags |= ((BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED) << bit_shift);
+
+    if (btm_cb.security_mode == BTM_SEC_MODE_LINK)
+        p_dev_rec->sec_flags |= (BTM_SEC_AUTHENTICATED << bit_shift);
+
+    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) {
+        p_dev_rec->sec_flags |= (BTM_SEC_16_DIGIT_PIN_AUTHED << bit_shift);
+    }
+
+    p_dev_rec->link_key_changed = false;
+
+    /* After connection is established we perform security if we do not know */
+    /* the name, or if we are originator because some procedure can have */
+    /* been scheduled while connection was down */
+    BTM_TRACE_DEBUG ("is_originator:%d ", p_dev_rec->is_originator);
+    if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) || p_dev_rec->is_originator)
+    {
+        if ((res = btm_sec_execute_procedure (p_dev_rec)) != BTM_CMD_STARTED)
+            btm_sec_dev_rec_cback_event (p_dev_rec, res, false);
+    }
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_disconnect
+**
+** Description      This function is called to disconnect HCI link
+**
+** Returns          btm status
+**
+*******************************************************************************/
+tBTM_STATUS btm_sec_disconnect (uint16_t handle, uint8_t reason)
+{
+    tBTM_SEC_DEV_REC  *p_dev_rec = btm_find_dev_by_handle (handle);
+
+    /* In some weird race condition we may not have a record */
+    if (!p_dev_rec)
+    {
+        btsnd_hcic_disconnect (handle, reason);
+        return(BTM_SUCCESS);
+    }
+
+    /* If we are in the process of bonding we need to tell client that auth failed */
+    if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+         &&  (memcmp (btm_cb.pairing_bda, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0)
+         &&  (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) )
+    {
+        /* we are currently doing bonding.  Link will be disconnected when done */
+        btm_cb.pairing_flags |= BTM_PAIR_FLAGS_DISC_WHEN_DONE;
+        return(BTM_BUSY);
+    }
+
+    return(btm_sec_send_hci_disconnect(p_dev_rec, reason, handle));
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_disconnected
+**
+** Description      This function is when a connection to the peer device is
+**                  dropped
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sec_disconnected (uint16_t handle, uint8_t reason)
+{
+    tBTM_SEC_DEV_REC  *p_dev_rec = btm_find_dev_by_handle (handle);
+    uint8_t           old_pairing_flags = btm_cb.pairing_flags;
+    int               result = HCI_ERR_AUTH_FAILURE;
+    tBTM_SEC_CALLBACK   *p_callback = NULL;
+    tBT_TRANSPORT      transport = BT_TRANSPORT_BR_EDR;
+
+    /* If page was delayed for disc complete, can do it now */
+    btm_cb.discing = false;
+
+    btm_acl_resubmit_page();
+
+    if (!p_dev_rec)
+        return;
+
+    transport  = (handle == p_dev_rec->hci_handle) ? BT_TRANSPORT_BR_EDR: BT_TRANSPORT_LE;
+
+    p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING;     /* reset flag */
+
+#if (BTM_DISC_DURING_RS == TRUE)
+    LOG_INFO(LOG_TAG, "%s clearing pending flag handle:%d reason:%d", __func__, handle, reason);
+    p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING;     /* reset flag */
+#endif
+
+    /* clear unused flags */
+    p_dev_rec->sm4 &= BTM_SM4_TRUE;
+
+    uint8_t *bd_addr = (uint8_t *)p_dev_rec->bd_addr;
+    BTM_TRACE_EVENT("%s sec_req:x%x state:%s reason:%d bd_addr:%02x:%02x:%02x:%02x:%02x:%02x"
+            "  remote_name:%s", __func__, p_dev_rec->security_required, btm_pair_state_descr(btm_cb.pairing_state),
+            reason, bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5], p_dev_rec->sec_bd_name);
+
+    BTM_TRACE_EVENT("%s before update sec_flags=0x%x", __func__, p_dev_rec->sec_flags);
+
+    /* If we are in the process of bonding we need to tell client that auth failed */
+    if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+         && (memcmp (btm_cb.pairing_bda, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0))
+    {
+        btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+        p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_KNOWN;
+        if (btm_cb.api.p_auth_complete_callback)
+        {
+            /* If the disconnection reason is REPEATED_ATTEMPTS,
+               send this error message to complete callback function
+               to display the error message of Repeated attempts.
+               All others, send HCI_ERR_AUTH_FAILURE. */
+            if (reason == HCI_ERR_REPEATED_ATTEMPTS)
+            {
+                result = HCI_ERR_REPEATED_ATTEMPTS;
+            }
+            else if (old_pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+            {
+                result = HCI_ERR_HOST_REJECT_SECURITY;
+            }
+            (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,     p_dev_rec->dev_class,
+                                                    p_dev_rec->sec_bd_name, result);
+        }
+    }
+
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+    btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, p_dev_rec->bd_addr, HCI_SUCCESS);
+    /* see sec_flags processing in btm_acl_removed */
+
+    if (transport == BT_TRANSPORT_LE)
+    {
+        p_dev_rec->ble_hci_handle = BTM_SEC_INVALID_HANDLE;
+        p_dev_rec->sec_flags &= ~(BTM_SEC_LE_AUTHENTICATED|BTM_SEC_LE_ENCRYPTED);
+        p_dev_rec->enc_key_size = 0;
+    }
+    else
+#endif
+    {
+        p_dev_rec->hci_handle = BTM_SEC_INVALID_HANDLE;
+        p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED
+                | BTM_SEC_ROLE_SWITCHED | BTM_SEC_16_DIGIT_PIN_AUTHED);
+    }
+
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+    if (p_dev_rec->sec_state == BTM_SEC_STATE_DISCONNECTING_BOTH)
+    {
+        p_dev_rec->sec_state = (transport == BT_TRANSPORT_LE) ?
+                                BTM_SEC_STATE_DISCONNECTING : BTM_SEC_STATE_DISCONNECTING_BLE;
+        return;
+    }
+#endif
+    p_dev_rec->sec_state  = BTM_SEC_STATE_IDLE;
+    p_dev_rec->security_required = BTM_SEC_NONE;
+
+    p_callback = p_dev_rec->p_callback;
+
+    /* if security is pending, send callback to clean up the security state */
+    if(p_callback)
+    {
+        p_dev_rec->p_callback = NULL; /* when the peer device time out the authentication before
+                                         we do, this call back must be reset here */
+        (*p_callback) (p_dev_rec->bd_addr, transport, p_dev_rec->p_ref_data, BTM_ERR_PROCESSING);
+    }
+
+    BTM_TRACE_EVENT("%s after update sec_flags=0x%x", __func__, p_dev_rec->sec_flags);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_link_key_notification
+**
+** Description      This function is called when a new connection link key is
+**                  generated
+**
+** Returns          Pointer to the record or NULL
+**
+*******************************************************************************/
+void btm_sec_link_key_notification (uint8_t *p_bda, uint8_t *p_link_key, uint8_t key_type)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (p_bda);
+    bool            we_are_bonding = false;
+    bool            ltk_derived_lk  = false;
+
+    BTM_TRACE_EVENT ("btm_sec_link_key_notification()  BDA:%04x%08x, TYPE: %d",
+                      (p_bda[0]<<8)+p_bda[1], (p_bda[2]<<24)+(p_bda[3]<<16)+(p_bda[4]<<8)+p_bda[5],
+                      key_type);
+
+    if ((key_type >= BTM_LTK_DERIVED_LKEY_OFFSET + BTM_LKEY_TYPE_COMBINATION) &&
+        (key_type <= BTM_LTK_DERIVED_LKEY_OFFSET + BTM_LKEY_TYPE_AUTH_COMB_P_256))
+    {
+        ltk_derived_lk = true;
+        key_type -= BTM_LTK_DERIVED_LKEY_OFFSET;
+    }
+    /* If connection was made to do bonding restore link security if changed */
+    btm_restore_mode();
+
+    if (key_type != BTM_LKEY_TYPE_CHANGED_COMB)
+        p_dev_rec->link_key_type = key_type;
+
+    p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN;
+
+    /*
+     * Until this point in time, we do not know if MITM was enabled, hence we
+     * add the extended security flag here.
+     */
+    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) {
+        p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
+    }
+
+#if (BLE_INCLUDED == TRUE)
+    /* BR/EDR connection, update the encryption key size to be 16 as always */
+    p_dev_rec->enc_key_size = 16;
+#endif
+    memcpy (p_dev_rec->link_key, p_link_key, LINK_KEY_LEN);
+
+    if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+         && (memcmp (btm_cb.pairing_bda, p_bda, BD_ADDR_LEN) == 0) )
+    {
+        if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+            we_are_bonding = true;
+        else
+            btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+    }
+
+    /* save LTK derived LK no matter what */
+    if (ltk_derived_lk)
+    {
+        if (btm_cb.api.p_link_key_callback)
+        {
+                BTM_TRACE_DEBUG ("%s() Save LTK derived LK (key_type = %d)",
+                                  __func__, p_dev_rec->link_key_type);
+                (*btm_cb.api.p_link_key_callback) (p_bda, p_dev_rec->dev_class,
+                                                   p_dev_rec->sec_bd_name,
+                                                   p_link_key, p_dev_rec->link_key_type);
+        }
+    }
+    else
+    {
+        if ((p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256) ||
+            (p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256))
+        {
+             p_dev_rec->new_encryption_key_is_p256 = true;
+             BTM_TRACE_DEBUG ("%s set new_encr_key_256 to %d",
+                               __func__, p_dev_rec->new_encryption_key_is_p256);
+        }
+    }
+
+    /* If name is not known at this point delay calling callback until the name is   */
+    /* resolved. Unless it is a HID Device and we really need to send all link keys. */
+    if ((!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN)
+        &&  ((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) != BTM_COD_MAJOR_PERIPHERAL))
+        && !ltk_derived_lk)
+    {
+        BTM_TRACE_EVENT ("btm_sec_link_key_notification()  Delayed BDA: %08x%04x Type:%d",
+                          (p_bda[0]<<24) + (p_bda[1]<<16) + (p_bda[2]<<8) + p_bda[3],
+                          (p_bda[4] << 8) + p_bda[5], key_type);
+
+        p_dev_rec->link_key_not_sent = true;
+
+        /* If it is for bonding nothing else will follow, so we need to start name resolution */
+        if (we_are_bonding)
+        {
+            btsnd_hcic_rmt_name_req(p_bda, HCI_PAGE_SCAN_REP_MODE_R1, HCI_MANDATARY_PAGE_SCAN_MODE, 0);
+        }
+
+        BTM_TRACE_EVENT ("rmt_io_caps:%d, sec_flags:x%x, dev_class[1]:x%02x", p_dev_rec->rmt_io_caps, p_dev_rec->sec_flags, p_dev_rec->dev_class[1])
+        return;
+    }
+
+    /* If its not us who perform authentication, we should tell stackserver */
+    /* that some authentication has been completed                          */
+    /* This is required when different entities receive link notification and auth complete */
+    if (!(p_dev_rec->security_required & BTM_SEC_OUT_AUTHENTICATE)
+        /* for derived key, always send authentication callback for BR channel */
+         || ltk_derived_lk)
+    {
+        if (btm_cb.api.p_auth_complete_callback)
+            (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
+                                                    p_dev_rec->sec_bd_name, HCI_SUCCESS);
+    }
+
+    /* We will save link key only if the user authorized it - BTE report link key in all cases */
+#ifdef BRCM_NONE_BTE
+    if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED)
+#endif
+    {
+        if (btm_cb.api.p_link_key_callback)
+        {
+            if (ltk_derived_lk)
+            {
+                BTM_TRACE_DEBUG ("btm_sec_link_key_notification()  LTK derived LK is saved already"
+                                    " (key_type = %d)", p_dev_rec->link_key_type);
+            }
+            else
+            {
+                (*btm_cb.api.p_link_key_callback) (p_bda, p_dev_rec->dev_class,
+                                                   p_dev_rec->sec_bd_name,
+                                                   p_link_key, p_dev_rec->link_key_type);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_link_key_request
+**
+** Description      This function is called when controller requests link key
+**
+** Returns          Pointer to the record or NULL
+**
+*******************************************************************************/
+void btm_sec_link_key_request (uint8_t *p_bda)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (p_bda);
+
+    BTM_TRACE_EVENT ("btm_sec_link_key_request()  BDA: %02x:%02x:%02x:%02x:%02x:%02x",
+                      p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]);
+
+    if( (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_PIN_REQ) &&
+        (btm_cb.collision_start_time != 0) &&
+        (memcmp (btm_cb.p_collided_dev_rec->bd_addr, p_bda, BD_ADDR_LEN) == 0) )
+    {
+        BTM_TRACE_EVENT ("btm_sec_link_key_request() rejecting link key req "
+            "State: %d START_TIMEOUT : %d",
+             btm_cb.pairing_state, btm_cb.collision_start_time);
+        btsnd_hcic_link_key_neg_reply (p_bda);
+        return;
+    }
+    if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)
+    {
+        btsnd_hcic_link_key_req_reply (p_bda, p_dev_rec->link_key);
+        return;
+    }
+
+    /* Notify L2CAP to increase timeout */
+    l2c_pin_code_request (p_bda);
+
+    /* The link key is not in the database and it is not known to the manager */
+    btsnd_hcic_link_key_neg_reply (p_bda);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_pairing_timeout
+**
+** Description      This function is called when host does not provide PIN
+**                  within requested time
+**
+** Returns          Pointer to the TLE struct
+**
+*******************************************************************************/
+static void btm_sec_pairing_timeout(UNUSED_ATTR void *data)
+{
+    tBTM_CB *p_cb = &btm_cb;
+    tBTM_SEC_DEV_REC *p_dev_rec;
+#if (BTM_LOCAL_IO_CAPS == BTM_IO_CAP_NONE)
+    tBTM_AUTH_REQ   auth_req = BTM_AUTH_AP_NO;
+#else
+    tBTM_AUTH_REQ   auth_req = BTM_AUTH_AP_YES;
+#endif
+    uint8_t name[2];
+
+/* Coverity: FALSE-POSITIVE error from Coverity tool. Please do NOT remove following comment. */
+/* coverity[UNUSED_VALUE] pointer p_dev_rec is actually used several times... This is a Coverity false-positive, i.e. a fake issue.
+*/
+    p_dev_rec = btm_find_dev (p_cb->pairing_bda);
+
+    BTM_TRACE_EVENT ("%s  State: %s   Flags: %u", __func__,
+                      btm_pair_state_descr(p_cb->pairing_state), p_cb->pairing_flags);
+
+    switch (p_cb->pairing_state)
+    {
+        case BTM_PAIR_STATE_WAIT_PIN_REQ:
+            btm_sec_bond_cancel_complete();
+            break;
+
+        case BTM_PAIR_STATE_WAIT_LOCAL_PIN:
+            if ( (btm_cb.pairing_flags & BTM_PAIR_FLAGS_PRE_FETCH_PIN) == 0)
+                btsnd_hcic_pin_code_neg_reply (p_cb->pairing_bda);
+            btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+            /* We need to notify the UI that no longer need the PIN */
+            if (btm_cb.api.p_auth_complete_callback)
+            {
+                if (p_dev_rec == NULL)
+                {
+                    name[0] = 0;
+                    (*btm_cb.api.p_auth_complete_callback) (p_cb->pairing_bda,
+                                                            NULL,
+                                                            name, HCI_ERR_CONNECTION_TOUT);
+                }
+                else
+                    (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+                                                            p_dev_rec->dev_class,
+                                                            p_dev_rec->sec_bd_name, HCI_ERR_CONNECTION_TOUT);
+            }
+            break;
+
+        case BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM:
+            btsnd_hcic_user_conf_reply (p_cb->pairing_bda, false);
+            /* btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); */
+            break;
+
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+        case BTM_PAIR_STATE_KEY_ENTRY:
+            btsnd_hcic_user_passkey_neg_reply(p_cb->pairing_bda);
+            /* btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); */
+            break;
+#endif /* !BTM_IO_CAP_NONE */
+
+        case BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS:
+            if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+                auth_req |= BTM_AUTH_DD_BOND;
+
+            btsnd_hcic_io_cap_req_reply (p_cb->pairing_bda, btm_cb.devcb.loc_io_caps,
+                                         BTM_OOB_NONE, auth_req);
+            btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+            break;
+
+        case BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP:
+            btsnd_hcic_rem_oob_neg_reply (p_cb->pairing_bda);
+            btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+            break;
+
+        case BTM_PAIR_STATE_WAIT_DISCONNECT:
+            /* simple pairing failed. Started a 1-sec timer at simple pairing complete.
+             * now it's time to tear down the ACL link*/
+            if (p_dev_rec == NULL)
+            {
+                BTM_TRACE_ERROR("%s BTM_PAIR_STATE_WAIT_DISCONNECT unknown BDA: %08x%04x",
+                                __func__,
+                                (p_cb->pairing_bda[0]<<24) + (p_cb->pairing_bda[1]<<16) + (p_cb->pairing_bda[2]<<8) + p_cb->pairing_bda[3],
+                                (p_cb->pairing_bda[4] << 8) + p_cb->pairing_bda[5]);
+                break;
+            }
+            btm_sec_send_hci_disconnect (p_dev_rec, HCI_ERR_AUTH_FAILURE, p_dev_rec->hci_handle);
+            btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+            break;
+
+        case BTM_PAIR_STATE_WAIT_AUTH_COMPLETE:
+        case BTM_PAIR_STATE_GET_REM_NAME:
+            /* We need to notify the UI that timeout has happened while waiting for authentication*/
+            btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+            if (btm_cb.api.p_auth_complete_callback)
+            {
+                if (p_dev_rec == NULL)
+                {
+                    name[0] = 0;
+                    (*btm_cb.api.p_auth_complete_callback) (p_cb->pairing_bda,
+                                                            NULL,
+                                                            name, HCI_ERR_CONNECTION_TOUT);
+                }
+                else
+                    (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
+                                                            p_dev_rec->dev_class,
+                                                            p_dev_rec->sec_bd_name, HCI_ERR_CONNECTION_TOUT);
+            }
+            break;
+
+        default:
+            BTM_TRACE_WARNING("%s not processed state: %s", __func__,
+                              btm_pair_state_descr(btm_cb.pairing_state));
+            btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
+            break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_pin_code_request
+**
+** Description      This function is called when controller requests PIN code
+**
+** Returns          Pointer to the record or NULL
+**
+*******************************************************************************/
+void btm_sec_pin_code_request (uint8_t *p_bda)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec;
+    tBTM_CB          *p_cb = &btm_cb;
+
+    BTM_TRACE_EVENT ("btm_sec_pin_code_request()  State: %s, BDA:%04x%08x",
+                      btm_pair_state_descr(btm_cb.pairing_state),
+                      (p_bda[0]<<8)+p_bda[1], (p_bda[2]<<24)+(p_bda[3]<<16)+(p_bda[4]<<8)+p_bda[5] );
+
+    if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
+    {
+        if ( (memcmp (p_bda, btm_cb.pairing_bda, BD_ADDR_LEN) == 0)  &&
+             (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_AUTH_COMPLETE) )
+        {
+             btsnd_hcic_pin_code_neg_reply (p_bda);
+             return;
+        }
+        else if ((btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_PIN_REQ)
+                 || memcmp (p_bda, btm_cb.pairing_bda, BD_ADDR_LEN) != 0)
+        {
+            BTM_TRACE_WARNING ("btm_sec_pin_code_request() rejected - state: %s",
+                                btm_pair_state_descr(btm_cb.pairing_state));
+            btsnd_hcic_pin_code_neg_reply (p_bda);
+            return;
+        }
+    }
+
+    p_dev_rec = btm_find_or_alloc_dev (p_bda);
+    /* received PIN code request. must be non-sm4 */
+    p_dev_rec->sm4 = BTM_SM4_KNOWN;
+
+    if (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE)
+    {
+        memcpy (btm_cb.pairing_bda, p_bda, BD_ADDR_LEN);
+
+        btm_cb.pairing_flags = BTM_PAIR_FLAGS_PEER_STARTED_DD;
+        /* Make sure we reset the trusted mask to help against attacks */
+        BTM_SEC_CLR_TRUSTED_DEVICE(p_dev_rec->trusted_mask);
+    }
+
+    if (!p_cb->pairing_disabled && (p_cb->cfg.pin_type == HCI_PIN_TYPE_FIXED))
+    {
+        BTM_TRACE_EVENT ("btm_sec_pin_code_request fixed pin replying");
+        btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+        btsnd_hcic_pin_code_req_reply (p_bda, p_cb->cfg.pin_code_len, p_cb->cfg.pin_code);
+        return;
+    }
+
+    /* Use the connecting device's CoD for the connection */
+    if ( (!memcmp (p_bda, p_cb->connecting_bda, BD_ADDR_LEN))
+         &&  (p_cb->connecting_dc[0] || p_cb->connecting_dc[1] || p_cb->connecting_dc[2]) )
+        memcpy (p_dev_rec->dev_class, p_cb->connecting_dc, DEV_CLASS_LEN);
+
+    /* We could have started connection after asking user for the PIN code */
+    if (btm_cb.pin_code_len != 0)
+    {
+        BTM_TRACE_EVENT ("btm_sec_pin_code_request bonding sending reply");
+        btsnd_hcic_pin_code_req_reply (p_bda, btm_cb.pin_code_len, p_cb->pin_code);
+
+        /* Mark that we forwarded received from the user PIN code */
+        btm_cb.pin_code_len = 0;
+
+        /* We can change mode back right away, that other connection being established */
+        /* is not forced to be secure - found a FW issue, so we can not do this
+        btm_restore_mode(); */
+
+        btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+    }
+
+    /* If pairing disabled OR (no PIN callback and not bonding) */
+    /* OR we could not allocate entry in the database reject pairing request */
+    else if (p_cb->pairing_disabled
+             || (p_cb->api.p_pin_callback == NULL)
+
+             /* OR Microsoft keyboard can for some reason try to establish connection */
+             /*  the only thing we can do here is to shut it up.  Normally we will be originator */
+             /*  for keyboard bonding */
+             || (!p_dev_rec->is_originator
+                 && ((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) == BTM_COD_MAJOR_PERIPHERAL)
+                 &&  (p_dev_rec->dev_class[2] & BTM_COD_MINOR_KEYBOARD)) )
+    {
+        BTM_TRACE_WARNING("btm_sec_pin_code_request(): Pairing disabled:%d; PIN callback:%x, Dev Rec:%x!",
+                           p_cb->pairing_disabled, p_cb->api.p_pin_callback, p_dev_rec);
+
+        btsnd_hcic_pin_code_neg_reply (p_bda);
+    }
+    /* Notify upper layer of PIN request and start expiration timer */
+    else
+    {
+        btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_LOCAL_PIN);
+        /* Pin code request can not come at the same time as connection request */
+        memcpy (p_cb->connecting_bda, p_bda, BD_ADDR_LEN);
+        memcpy (p_cb->connecting_dc,  p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+        /* Check if the name is known */
+        /* Even if name is not known we might not be able to get one */
+        /* this is the case when we are already getting something from the */
+        /* device, so HCI level is flow controlled */
+        /* Also cannot send remote name request while paging, i.e. connection is not completed */
+        if (p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN)
+        {
+            BTM_TRACE_EVENT ("btm_sec_pin_code_request going for callback");
+
+            btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD;
+            if (p_cb->api.p_pin_callback) {
+                (*p_cb->api.p_pin_callback) (p_bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name,
+                        (p_dev_rec->p_cur_service == NULL) ? false
+                                : (p_dev_rec->p_cur_service->security_flags
+                                   & BTM_SEC_IN_MIN_16_DIGIT_PIN));
+            }
+        }
+        else
+        {
+            BTM_TRACE_EVENT ("btm_sec_pin_code_request going for remote name");
+
+            /* We received PIN code request for the device with unknown name */
+            /* it is not user friendly just to ask for the PIN without name */
+            /* try to get name at first */
+            btsnd_hcic_rmt_name_req(p_dev_rec->bd_addr,
+                                    HCI_PAGE_SCAN_REP_MODE_R1,
+                                    HCI_MANDATARY_PAGE_SCAN_MODE, 0);
+        }
+    }
+
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_update_clock_offset
+**
+** Description      This function is called to update clock offset
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sec_update_clock_offset (uint16_t handle, uint16_t clock_offset)
+{
+    tBTM_SEC_DEV_REC  *p_dev_rec;
+    tBTM_INQ_INFO     *p_inq_info;
+
+    if ((p_dev_rec = btm_find_dev_by_handle (handle)) == NULL)
+        return;
+
+    p_dev_rec->clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID;
+
+    if ((p_inq_info = BTM_InqDbRead(p_dev_rec->bd_addr)) == NULL)
+        return;
+
+    p_inq_info->results.clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID;
+}
+
+/******************************************************************
+** S T A T I C     F U N C T I O N S
+*******************************************************************/
+
+/*******************************************************************************
+**
+** Function         btm_sec_execute_procedure
+**
+** Description      This function is called to start required security
+**                  procedure.  There is a case when multiplexing protocol
+**                  calls this function on the originating side, connection to
+**                  the peer will not be established.  This function in this
+**                  case performs only authorization.
+**
+** Returns          BTM_SUCCESS     - permission is granted
+**                  BTM_CMD_STARTED - in process
+**                  BTM_NO_RESOURCES  - permission declined
+**
+*******************************************************************************/
+static tBTM_STATUS btm_sec_execute_procedure (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+    BTM_TRACE_EVENT ("btm_sec_execute_procedure: Required:0x%x Flags:0x%x State:%d",
+                      p_dev_rec->security_required, p_dev_rec->sec_flags, p_dev_rec->sec_state);
+
+    /* There is a chance that we are getting name.  Wait until done. */
+    if (p_dev_rec->sec_state != 0)
+        return(BTM_CMD_STARTED);
+
+    /* If any security is required, get the name first */
+    if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN)
+        && (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE))
+    {
+        BTM_TRACE_EVENT ("Security Manager: Start get name");
+        if (!btm_sec_start_get_name (p_dev_rec))
+        {
+            return(BTM_NO_RESOURCES);
+        }
+        return(BTM_CMD_STARTED);
+    }
+
+    /* If connection is not authenticated and authentication is required */
+    /* start authentication and return PENDING to the caller */
+    if ((((!(p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))
+        && (( p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_OUT_AUTHENTICATE))
+            || (!p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_IN_AUTHENTICATE))))
+        || (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED)
+            && (!p_dev_rec->is_originator
+                    && (p_dev_rec->security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN))))
+        && (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE))
+    {
+        /*
+         * We rely on BTM_SEC_16_DIGIT_PIN_AUTHED being set if MITM is in use,
+         * as 16 DIGIT is only needed if MITM is not used. Unfortunately, the
+         * BTM_SEC_AUTHENTICATED is used for both MITM and non-MITM
+         * authenticated connections, hence we cannot distinguish here.
+         */
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+        /* if incoming UCD packet, discard it */
+        if ( !p_dev_rec->is_originator && (p_dev_rec->is_ucd == true ))
+            return(BTM_FAILED_ON_SECURITY);
+#endif
+
+        BTM_TRACE_EVENT ("Security Manager: Start authentication");
+
+        /*
+         * If we do have a link-key, but we end up here because we need an
+         * upgrade, then clear the link-key known and authenticated flag before
+         * restarting authentication.
+         * WARNING: If the controller has link-key, it is optional and
+         * recommended for the controller to send a Link_Key_Request.
+         * In case we need an upgrade, the only alternative would be to delete
+         * the existing link-key. That could lead to very bad user experience
+         * or even IOP issues, if a reconnect causes a new connection that
+         * requires an upgrade.
+         */
+        if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)
+                && (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED)
+                    && (!p_dev_rec->is_originator && (p_dev_rec->security_required
+                            & BTM_SEC_IN_MIN_16_DIGIT_PIN)))) {
+            p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED
+                    | BTM_SEC_AUTHENTICATED);
+        }
+
+        btm_sec_start_authentication(p_dev_rec);
+        return(BTM_CMD_STARTED);
+    }
+
+    /* If connection is not encrypted and encryption is required */
+    /* start encryption and return PENDING to the caller */
+    if (!(p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED)
+        && (( p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_OUT_ENCRYPT))
+            || (!p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_IN_ENCRYPT)))
+        && (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE))
+    {
+#if (L2CAP_UCD_INCLUDED == TRUE)
+        /* if incoming UCD packet, discard it */
+        if ( !p_dev_rec->is_originator && (p_dev_rec->is_ucd == true ))
+            return(BTM_FAILED_ON_SECURITY);
+#endif
+
+        BTM_TRACE_EVENT ("Security Manager: Start encryption");
+
+        btm_sec_start_encryption(p_dev_rec);
+        return(BTM_CMD_STARTED);
+    }
+
+    if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) &&
+        (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256))
+    {
+        BTM_TRACE_EVENT("%s: Security Manager: SC only service, but link key type is 0x%02x -",
+                        "security failure", __func__, p_dev_rec->link_key_type);
+        return (BTM_FAILED_ON_SECURITY);
+    }
+
+    /* If connection is not authorized and authorization is required */
+    /* start authorization and return PENDING to the caller */
+    if (!(p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED)
+        && (( p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_OUT_AUTHORIZE))
+            || (!p_dev_rec->is_originator && (p_dev_rec->security_required & BTM_SEC_IN_AUTHORIZE))))
+    {
+        BTM_TRACE_EVENT ("service id:%d, is trusted:%d",
+                          p_dev_rec->p_cur_service->service_id,
+                          (BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask,
+                                                      p_dev_rec->p_cur_service->service_id)));
+        if ((btm_sec_are_all_trusted(p_dev_rec->trusted_mask) == false) &&
+            (p_dev_rec->p_cur_service->service_id < BTM_SEC_MAX_SERVICES) &&
+            (BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask,
+                                        p_dev_rec->p_cur_service->service_id) == false))
+        {
+            BTM_TRACE_EVENT ("Security Manager: Start authorization");
+            return(btm_sec_start_authorization (p_dev_rec));
+        }
+    }
+
+    /* All required  security procedures already established */
+    p_dev_rec->security_required &= ~(BTM_SEC_OUT_AUTHORIZE | BTM_SEC_IN_AUTHORIZE |
+                                      BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_IN_AUTHENTICATE |
+                                      BTM_SEC_OUT_ENCRYPT | BTM_SEC_IN_ENCRYPT |
+                                      BTM_SEC_FORCE_MASTER | BTM_SEC_ATTEMPT_MASTER |
+                                      BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE);
+
+    BTM_TRACE_EVENT ("Security Manager: trusted:0x%04x%04x", p_dev_rec->trusted_mask[1], p_dev_rec->trusted_mask[0]);
+    BTM_TRACE_EVENT ("Security Manager: access granted");
+
+    return(BTM_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_start_get_name
+**
+** Description      This function is called to start get name procedure
+**
+** Returns          true if started
+**
+*******************************************************************************/
+static bool    btm_sec_start_get_name (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+    uint8_t tempstate = p_dev_rec->sec_state;
+
+    p_dev_rec->sec_state = BTM_SEC_STATE_GETTING_NAME;
+
+    /* Device should be connected, no need to provide correct page params */
+    /* 0 and NULL are as timeout and callback params because they are not used in security get name case */
+    if ((btm_initiate_rem_name (p_dev_rec->bd_addr, NULL, BTM_RMT_NAME_SEC,
+                                0, NULL)) != BTM_CMD_STARTED)
+    {
+        p_dev_rec->sec_state = tempstate;
+        return(false);
+    }
+
+    return(true);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_start_authentication
+**
+** Description      This function is called to start authentication
+**
+*******************************************************************************/
+static void btm_sec_start_authentication(tBTM_SEC_DEV_REC *p_dev_rec)
+{
+    p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
+    btsnd_hcic_auth_request(p_dev_rec->hci_handle);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_start_encryption
+**
+** Description      This function is called to start encryption
+**
+*******************************************************************************/
+static void btm_sec_start_encryption(tBTM_SEC_DEV_REC *p_dev_rec)
+{
+    btsnd_hcic_set_conn_encrypt(p_dev_rec->hci_handle, true);
+    p_dev_rec->sec_state = BTM_SEC_STATE_ENCRYPTING;
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_start_authorization
+**
+** Description      This function is called to start authorization
+**
+** Returns          true if started
+**
+*******************************************************************************/
+static uint8_t btm_sec_start_authorization (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+    uint8_t  result;
+    uint8_t *p_service_name = NULL;
+    uint8_t  service_id;
+
+    if ((p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN)
+        || (p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE))
+    {
+        if (!btm_cb.api.p_authorize_callback)
+            return(BTM_MODE_UNSUPPORTED);
+
+        if (p_dev_rec->p_cur_service)
+        {
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+            if (p_dev_rec->is_originator)
+                p_service_name = p_dev_rec->p_cur_service->orig_service_name;
+            else
+                p_service_name = p_dev_rec->p_cur_service->term_service_name;
+#endif
+            service_id = p_dev_rec->p_cur_service->service_id;
+        }
+        else
+            service_id = 0;
+
+        /* Send authorization request if not already sent during this service connection */
+        if (p_dev_rec->last_author_service_id == BTM_SEC_NO_LAST_SERVICE_ID
+            || p_dev_rec->last_author_service_id != service_id)
+        {
+            p_dev_rec->sec_state = BTM_SEC_STATE_AUTHORIZING;
+            result = (*btm_cb.api.p_authorize_callback) (p_dev_rec->bd_addr,
+                                                     p_dev_rec->dev_class,
+                                                     p_dev_rec->sec_bd_name,
+                                                     p_service_name,
+                                                     service_id,
+                                                     p_dev_rec->is_originator);
+        }
+
+        else    /* Already authorized once for this L2CAP bringup */
+        {
+            BTM_TRACE_DEBUG ("btm_sec_start_authorization: (Ignoring extra Authorization prompt for service %d)", service_id);
+            return (BTM_SUCCESS);
+        }
+
+        if (result == BTM_SUCCESS)
+        {
+            p_dev_rec->sec_flags |= BTM_SEC_AUTHORIZED;
+
+            /* Save the currently authorized service in case we are asked again by another multiplexer layer */
+            if (!p_dev_rec->is_originator)
+                p_dev_rec->last_author_service_id = service_id;
+
+            p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+        }
+        return(result);
+    }
+    btm_sec_start_get_name (p_dev_rec);
+    return(BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_are_all_trusted
+**
+** Description      This function is called check if all services are trusted
+**
+** Returns          true if all are trusted, otherwise false
+**
+*******************************************************************************/
+bool    btm_sec_are_all_trusted(uint32_t p_mask[])
+{
+    uint32_t trusted_inx;
+    for (trusted_inx = 0; trusted_inx < BTM_SEC_SERVICE_ARRAY_SIZE; trusted_inx++)
+    {
+        if (p_mask[trusted_inx] != BTM_SEC_TRUST_ALL)
+            return(false);
+    }
+
+    return(true);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_find_first_serv
+**
+** Description      Look for the first record in the service database
+**                  with specified PSM
+**
+** Returns          Pointer to the record or NULL
+**
+*******************************************************************************/
+tBTM_SEC_SERV_REC *btm_sec_find_first_serv (CONNECTION_TYPE conn_type, uint16_t psm)
+{
+    tBTM_SEC_SERV_REC *p_serv_rec = &btm_cb.sec_serv_rec[0];
+    int i;
+    bool    is_originator;
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+
+    if ( conn_type & CONNECTION_TYPE_ORIG_MASK )
+        is_originator = true;
+    else
+        is_originator = false;
+#else
+    is_originator = conn_type;
+#endif
+
+    if (is_originator && btm_cb.p_out_serv && btm_cb.p_out_serv->psm == psm)
+    {
+        /* If this is outgoing connection and the PSM matches p_out_serv,
+         * use it as the current service */
+        return btm_cb.p_out_serv;
+    }
+
+    /* otherwise, just find the first record with the specified PSM */
+    for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++)
+    {
+        if ( (p_serv_rec->security_flags & BTM_SEC_IN_USE) && (p_serv_rec->psm == psm) )
+            return(p_serv_rec);
+    }
+    return(NULL);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_find_next_serv
+**
+** Description      Look for the next record in the service database
+**                  with specified PSM
+**
+** Returns          Pointer to the record or NULL
+**
+*******************************************************************************/
+static tBTM_SEC_SERV_REC *btm_sec_find_next_serv (tBTM_SEC_SERV_REC *p_cur)
+{
+    tBTM_SEC_SERV_REC *p_serv_rec   = &btm_cb.sec_serv_rec[0];
+    int               i;
+
+    for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++)
+    {
+        if ((p_serv_rec->security_flags & BTM_SEC_IN_USE)
+            && (p_serv_rec->psm == p_cur->psm) )
+        {
+            if (p_cur != p_serv_rec)
+            {
+                return(p_serv_rec);
+            }
+        }
+    }
+    return(NULL);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_find_mx_serv
+**
+** Description      Look for the record in the service database with specified
+**                  PSM and multiplexor channel information
+**
+** Returns          Pointer to the record or NULL
+**
+*******************************************************************************/
+static tBTM_SEC_SERV_REC *btm_sec_find_mx_serv (uint8_t is_originator, uint16_t psm,
+                                                uint32_t mx_proto_id, uint32_t mx_chan_id)
+{
+    tBTM_SEC_SERV_REC *p_out_serv = btm_cb.p_out_serv;
+    tBTM_SEC_SERV_REC *p_serv_rec = &btm_cb.sec_serv_rec[0];
+    int i;
+
+    BTM_TRACE_DEBUG ("%s()", __func__);
+    if (is_originator && p_out_serv && p_out_serv->psm == psm
+        && p_out_serv->mx_proto_id == mx_proto_id
+        && p_out_serv->orig_mx_chan_id == mx_chan_id)
+    {
+        /* If this is outgoing connection and the parameters match p_out_serv,
+         * use it as the current service */
+        return btm_cb.p_out_serv;
+    }
+
+    /* otherwise, the old way */
+    for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++)
+    {
+        if ((p_serv_rec->security_flags & BTM_SEC_IN_USE)
+            && (p_serv_rec->psm == psm)
+            && (p_serv_rec->mx_proto_id == mx_proto_id)
+            && (( is_originator && (p_serv_rec->orig_mx_chan_id  == mx_chan_id))
+                || (!is_originator && (p_serv_rec->term_mx_chan_id  == mx_chan_id))))
+        {
+            return(p_serv_rec);
+        }
+    }
+    return(NULL);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_collision_timeout
+**
+** Description      Encryption could not start because of the collision
+**                  try to do it again
+**
+** Returns          Pointer to the TLE struct
+**
+*******************************************************************************/
+static void btm_sec_collision_timeout(UNUSED_ATTR void *data)
+{
+    BTM_TRACE_EVENT ("%s()", __func__);
+
+    tBTM_STATUS status = btm_sec_execute_procedure (btm_cb.p_collided_dev_rec);
+
+    /* If result is pending reply from the user or from the device is pending */
+    if (status != BTM_CMD_STARTED)
+    {
+        /* There is no next procedure or start of procedure failed, notify the waiting layer */
+        btm_sec_dev_rec_cback_event (btm_cb.p_collided_dev_rec, status, false);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_link_key_request
+**
+** Description      This function is called when controller requests link key
+**
+** Returns          Pointer to the record or NULL
+**
+*******************************************************************************/
+static void btm_send_link_key_notif (tBTM_SEC_DEV_REC *p_dev_rec)
+{
+    if (btm_cb.api.p_link_key_callback)
+        (*btm_cb.api.p_link_key_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
+                                           p_dev_rec->sec_bd_name, p_dev_rec->link_key,
+                                           p_dev_rec->link_key_type);
+}
+
+/*******************************************************************************
+**
+** Function         BTM_ReadTrustedMask
+**
+** Description      Get trusted mask for the peer device
+**
+** Parameters:      bd_addr   - Address of the device
+**
+** Returns          NULL, if the device record is not found.
+**                  otherwise, the trusted mask
+**
+*******************************************************************************/
+uint32_t * BTM_ReadTrustedMask (BD_ADDR bd_addr)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
+    if (p_dev_rec != NULL)
+        return(p_dev_rec->trusted_mask);
+    return NULL;
+}
+
+/*******************************************************************************
+**
+** Function         btm_restore_mode
+**
+** Description      This function returns the security mode to previous setting
+**                  if it was changed during bonding.
+**
+**
+** Parameters:      void
+**
+*******************************************************************************/
+static void btm_restore_mode(void)
+{
+    if (btm_cb.security_mode_changed)
+    {
+        btm_cb.security_mode_changed = false;
+        BTM_TRACE_DEBUG("%s() Auth enable -> %d", __func__, (btm_cb.security_mode == BTM_SEC_MODE_LINK));
+        btsnd_hcic_write_auth_enable ((uint8_t)(btm_cb.security_mode == BTM_SEC_MODE_LINK));
+    }
+
+    if (btm_cb.pin_type_changed)
+    {
+        btm_cb.pin_type_changed = false;
+        btsnd_hcic_write_pin_type (btm_cb.cfg.pin_type);
+    }
+}
+
+
+bool is_sec_state_equal(void *data, void *context)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = static_cast<tBTM_SEC_DEV_REC *>(data);
+    uint8_t *state = static_cast<uint8_t *>(context);
+
+    if (p_dev_rec->sec_state == *state)
+        return false;
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_find_dev_by_sec_state
+**
+** Description      Look for the record in the device database for the device
+**                  which is being authenticated or encrypted
+**
+** Returns          Pointer to the record or NULL
+**
+*******************************************************************************/
+tBTM_SEC_DEV_REC *btm_sec_find_dev_by_sec_state (uint8_t state)
+{
+    list_node_t *n = list_foreach(btm_cb.sec_dev_rec, is_sec_state_equal, &state);
+    if (n)
+        return static_cast<tBTM_SEC_DEV_REC *>(list_node(n));
+
+    return NULL;
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_change_pairing_state
+**
+** Description      This function is called to change pairing state
+**
+*******************************************************************************/
+static void btm_sec_change_pairing_state (tBTM_PAIRING_STATE new_state)
+{
+    tBTM_PAIRING_STATE  old_state = btm_cb.pairing_state;
+
+    BTM_TRACE_EVENT ("%s()  Old: %s", __func__, btm_pair_state_descr(btm_cb.pairing_state));
+    BTM_TRACE_EVENT ("%s()  New: %s pairing_flags:0x%x", __func__,
+            btm_pair_state_descr(new_state), btm_cb.pairing_flags);
+
+    btm_cb.pairing_state = new_state;
+
+    if (new_state == BTM_PAIR_STATE_IDLE)
+    {
+        alarm_cancel(btm_cb.pairing_timer);
+
+        btm_cb.pairing_flags = 0;
+        btm_cb.pin_code_len  = 0;
+
+        /* Make sure the the lcb shows we are not bonding */
+        l2cu_update_lcb_4_bonding (btm_cb.pairing_bda, false);
+
+        btm_restore_mode();
+        btm_sec_check_pending_reqs();
+        btm_inq_clear_ssp();
+
+        memset (btm_cb.pairing_bda, 0xFF, BD_ADDR_LEN);
+    }
+    else
+    {
+        /* If transitioning out of idle, mark the lcb as bonding */
+        if (old_state == BTM_PAIR_STATE_IDLE)
+            l2cu_update_lcb_4_bonding (btm_cb.pairing_bda, true);
+
+        alarm_set_on_queue(btm_cb.pairing_timer,
+                           BTM_SEC_TIMEOUT_VALUE * 1000,
+                           btm_sec_pairing_timeout, NULL,
+                           btu_general_alarm_queue);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_pair_state_descr
+**
+** Description      Return state description for tracing
+**
+*******************************************************************************/
+static char *btm_pair_state_descr (tBTM_PAIRING_STATE state)
+{
+#if (BT_TRACE_VERBOSE == TRUE)
+    switch (state)
+    {
+        case BTM_PAIR_STATE_IDLE:                   return("IDLE");
+        case BTM_PAIR_STATE_GET_REM_NAME:           return("GET_REM_NAME");
+        case BTM_PAIR_STATE_WAIT_PIN_REQ:           return("WAIT_PIN_REQ");
+        case BTM_PAIR_STATE_WAIT_LOCAL_PIN:         return("WAIT_LOCAL_PIN");
+        case BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM:   return("WAIT_NUM_CONFIRM");
+        case BTM_PAIR_STATE_KEY_ENTRY:              return("KEY_ENTRY");
+        case BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP:     return("WAIT_LOCAL_OOB_RSP");
+        case BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS:      return("WAIT_LOCAL_IOCAPS");
+        case BTM_PAIR_STATE_INCOMING_SSP:           return("INCOMING_SSP");
+        case BTM_PAIR_STATE_WAIT_AUTH_COMPLETE:     return("WAIT_AUTH_COMPLETE");
+        case BTM_PAIR_STATE_WAIT_DISCONNECT:        return("WAIT_DISCONNECT");
+    }
+
+    return("???");
+#else
+    snprintf(btm_cb.state_temp_buffer, sizeof(btm_cb.state_temp_buffer),
+        "%hhu", state);
+
+    return(btm_cb.state_temp_buffer);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_dev_rec_cback_event
+**
+** Description      This function calls the callback function with the given
+**                  result and clear the callback function.
+**
+** Parameters:      void
+**
+*******************************************************************************/
+void btm_sec_dev_rec_cback_event (tBTM_SEC_DEV_REC *p_dev_rec, uint8_t res, bool    is_le_transport)
+{
+    tBTM_SEC_CALLBACK   *p_callback = p_dev_rec->p_callback;
+
+    if (p_dev_rec->p_callback)
+    {
+        p_dev_rec->p_callback = NULL;
+
+#if (BLE_INCLUDED == TRUE)
+        if (is_le_transport)
+           (*p_callback) (p_dev_rec->ble.pseudo_addr, BT_TRANSPORT_LE, p_dev_rec->p_ref_data, res);
+        else
+#endif
+           (*p_callback) (p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR, p_dev_rec->p_ref_data, res);
+    }
+
+    btm_sec_check_pending_reqs();
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_queue_mx_request
+**
+** Description      Return state description for tracing
+**
+*******************************************************************************/
+static bool    btm_sec_queue_mx_request (BD_ADDR bd_addr,  uint16_t psm,  bool    is_orig,
+                                         uint32_t mx_proto_id, uint32_t mx_chan_id,
+                                         tBTM_SEC_CALLBACK *p_callback, void *p_ref_data)
+{
+    tBTM_SEC_QUEUE_ENTRY *p_e = (tBTM_SEC_QUEUE_ENTRY *)osi_malloc(sizeof(tBTM_SEC_QUEUE_ENTRY));
+
+    p_e->psm            = psm;
+    p_e->is_orig        = is_orig;
+    p_e->p_callback     = p_callback;
+    p_e->p_ref_data     = p_ref_data;
+    p_e->mx_proto_id    = mx_proto_id;
+    p_e->mx_chan_id     = mx_chan_id;
+    p_e->transport      = BT_TRANSPORT_BR_EDR;
+    p_e->sec_act        = 0;
+
+    memcpy(p_e->bd_addr, bd_addr, BD_ADDR_LEN);
+
+    BTM_TRACE_EVENT("%s() PSM: 0x%04x  Is_Orig: %u  mx_proto_id: %u  mx_chan_id: %u",
+                     __func__, psm, is_orig, mx_proto_id, mx_chan_id);
+
+    fixed_queue_enqueue(btm_cb.sec_pending_q, p_e);
+
+    return true;
+}
+
+static bool    btm_sec_check_prefetch_pin (tBTM_SEC_DEV_REC  *p_dev_rec)
+{
+    uint8_t major = (uint8_t)(p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK);
+    uint8_t minor = (uint8_t)(p_dev_rec->dev_class[2] & BTM_COD_MINOR_CLASS_MASK);
+    bool    rv = false;
+
+    if ((major == BTM_COD_MAJOR_AUDIO)
+        &&  ((minor == BTM_COD_MINOR_CONFM_HANDSFREE) || (minor == BTM_COD_MINOR_CAR_AUDIO)) )
+    {
+        BTM_TRACE_EVENT ("%s() Skipping pre-fetch PIN for carkit COD Major: 0x%02x Minor: 0x%02x",
+            __func__, major, minor);
+
+        if (btm_cb.security_mode_changed == false)
+        {
+            btm_cb.security_mode_changed = true;
+#ifdef APPL_AUTH_WRITE_EXCEPTION
+            if(!(APPL_AUTH_WRITE_EXCEPTION)(p_dev_rec->bd_addr))
+#endif
+                btsnd_hcic_write_auth_enable (true);
+        }
+    }
+    else
+    {
+        btm_sec_change_pairing_state (BTM_PAIR_STATE_WAIT_LOCAL_PIN);
+
+        /* If we got a PIN, use that, else try to get one */
+        if (btm_cb.pin_code_len)
+        {
+            BTM_PINCodeReply (p_dev_rec->bd_addr, BTM_SUCCESS, btm_cb.pin_code_len, btm_cb.pin_code, p_dev_rec->trusted_mask);
+        }
+        else
+        {
+            /* pin was not supplied - pre-fetch pin code now */
+            if (btm_cb.api.p_pin_callback && ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_PIN_REQD) == 0))
+            {
+                BTM_TRACE_DEBUG("%s() PIN code callback called", __func__);
+                if (btm_bda_to_acl(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR) == NULL)
+                btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD;
+                (btm_cb.api.p_pin_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
+                        p_dev_rec->sec_bd_name, (p_dev_rec->p_cur_service == NULL) ? false
+                                : (p_dev_rec->p_cur_service->security_flags
+                                   & BTM_SEC_IN_MIN_16_DIGIT_PIN));
+            }
+        }
+
+        rv = true;
+    }
+
+    return rv;
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_auth_payload_tout
+**
+** Description      Processes the HCI Autheniticated Payload Timeout Event
+**                  indicating that a packet containing a valid MIC on the
+**                  connection handle was not received within the programmed
+**                  timeout value. (Spec Default is 30 secs, but can be
+**                  changed via the BTM_SecSetAuthPayloadTimeout() function.
+**
+*******************************************************************************/
+void btm_sec_auth_payload_tout (uint8_t *p, uint16_t hci_evt_len)
+{
+    uint16_t handle;
+
+    STREAM_TO_UINT16 (handle, p);
+    handle = HCID_GET_HANDLE (handle);
+
+    /* Will be exposed to upper layers in the future if/when determined necessary */
+    BTM_TRACE_ERROR ("%s on handle 0x%02x", __func__, handle);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_queue_encrypt_request
+**
+** Description      encqueue encryption request when device has active security
+**                  process pending.
+**
+*******************************************************************************/
+static bool    btm_sec_queue_encrypt_request (BD_ADDR bd_addr, tBT_TRANSPORT transport,
+                                         tBTM_SEC_CALLBACK *p_callback, void *p_ref_data,
+                                         tBTM_BLE_SEC_ACT sec_act)
+{
+    tBTM_SEC_QUEUE_ENTRY *p_e =
+        (tBTM_SEC_QUEUE_ENTRY *)osi_malloc(sizeof(tBTM_SEC_QUEUE_ENTRY) + 1);
+
+    p_e->psm        = 0;  /* if PSM 0, encryption request */
+    p_e->p_callback = p_callback;
+    p_e->p_ref_data = p_ref_data;
+    p_e->transport  = transport;
+    p_e->sec_act    = sec_act;
+    memcpy(p_e->bd_addr, bd_addr, BD_ADDR_LEN);
+    fixed_queue_enqueue(btm_cb.sec_pending_q, p_e);
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_set_peer_sec_caps
+**
+** Description      This function is called to set sm4 and rmt_sec_caps fields
+**                  based on the available peer device features.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sec_set_peer_sec_caps(tACL_CONN *p_acl_cb, tBTM_SEC_DEV_REC *p_dev_rec)
+{
+    BD_ADDR     rem_bd_addr;
+    uint8_t     *p_rem_bd_addr;
+
+    if ((btm_cb.security_mode == BTM_SEC_MODE_SP ||
+         btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG ||
+         btm_cb.security_mode == BTM_SEC_MODE_SC) &&
+        HCI_SSP_HOST_SUPPORTED(p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_1]))
+    {
+        p_dev_rec->sm4 = BTM_SM4_TRUE;
+        p_dev_rec->remote_supports_secure_connections =
+            (HCI_SC_HOST_SUPPORTED(p_acl_cb->peer_lmp_features[HCI_EXT_FEATURES_PAGE_1]));
+    }
+    else
+    {
+        p_dev_rec->sm4 = BTM_SM4_KNOWN;
+        p_dev_rec->remote_supports_secure_connections = false;
+    }
+
+    BTM_TRACE_API("%s: sm4: 0x%02x, rmt_support_for_secure_connections %d", __func__,
+                  p_dev_rec->sm4, p_dev_rec->remote_supports_secure_connections);
+
+    if (p_dev_rec->remote_features_needed)
+    {
+        BTM_TRACE_EVENT("%s: Now device in SC Only mode, waiting for peer remote features!",
+                        __func__);
+        p_rem_bd_addr = (uint8_t*) rem_bd_addr;
+        BDADDR_TO_STREAM(p_rem_bd_addr, p_dev_rec->bd_addr);
+        p_rem_bd_addr = (uint8_t*) rem_bd_addr;
+        btm_io_capabilities_req(p_rem_bd_addr);
+        p_dev_rec->remote_features_needed = false;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_is_serv_level0
+**
+** Description      This function is called to check if the service corresponding
+**                  to PSM is security mode 4 level 0 service.
+**
+** Returns          true if the service is security mode 4 level 0 service
+**
+*******************************************************************************/
+static bool    btm_sec_is_serv_level0(uint16_t psm)
+{
+    if (psm == BT_PSM_SDP)
+    {
+        BTM_TRACE_DEBUG("%s: PSM: 0x%04x -> mode 4 level 0 service", __func__, psm);
+        return true;
+    }
+    return false;
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_check_pending_enc_req
+**
+** Description      This function is called to send pending encryption callback if
+**                  waiting
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btm_sec_check_pending_enc_req (tBTM_SEC_DEV_REC  *p_dev_rec, tBT_TRANSPORT transport,
+                                            uint8_t encr_enable)
+{
+    if (fixed_queue_is_empty(btm_cb.sec_pending_q))
+        return;
+
+    uint8_t res = encr_enable ? BTM_SUCCESS : BTM_ERR_PROCESSING;
+    list_t *list = fixed_queue_get_list(btm_cb.sec_pending_q);
+    for (const list_node_t *node = list_begin(list); node != list_end(list); ) {
+        tBTM_SEC_QUEUE_ENTRY *p_e = (tBTM_SEC_QUEUE_ENTRY *)list_node(node);
+        node = list_next(node);
+
+        if (memcmp(p_e->bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0 && p_e->psm == 0
+#if (BLE_INCLUDED == TRUE)
+            && p_e->transport == transport
+#endif
+            )
+        {
+            if (encr_enable == 0 || transport == BT_TRANSPORT_BR_EDR
+#if (BLE_INCLUDED == TRUE)
+                || p_e->sec_act == BTM_BLE_SEC_ENCRYPT
+                || p_e->sec_act == BTM_BLE_SEC_ENCRYPT_NO_MITM
+                || (p_e->sec_act == BTM_BLE_SEC_ENCRYPT_MITM && p_dev_rec->sec_flags
+                    & BTM_SEC_LE_AUTHENTICATED)
+#endif
+               )
+            {
+                if (p_e->p_callback)
+                    (*p_e->p_callback) (p_dev_rec->bd_addr, transport, p_e->p_ref_data, res);
+                fixed_queue_try_remove_from_queue(btm_cb.sec_pending_q, (void *)p_e);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_set_serv_level4_flags
+**
+** Description      This function is called to set security mode 4 level 4 flags.
+**
+** Returns          service security requirements updated to include secure
+**                  connections only mode.
+**
+*******************************************************************************/
+static uint16_t btm_sec_set_serv_level4_flags(uint16_t cur_security, bool    is_originator)
+{
+    uint16_t sec_level4_flags = is_originator ? BTM_SEC_OUT_LEVEL4_FLAGS : BTM_SEC_IN_LEVEL4_FLAGS;
+
+    return cur_security | sec_level4_flags;
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_clear_ble_keys
+**
+** Description      This function is called to clear out the BLE keys.
+**                  Typically when devices are removed in BTM_SecDeleteDevice,
+**                  or when a new BT Link key is generated.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btm_sec_clear_ble_keys (tBTM_SEC_DEV_REC  *p_dev_rec)
+{
+
+    BTM_TRACE_DEBUG ("%s() Clearing BLE Keys", __func__);
+#if (SMP_INCLUDED == TRUE)
+    p_dev_rec->ble.key_type = BTM_LE_KEY_NONE;
+    memset (&p_dev_rec->ble.keys, 0, sizeof(tBTM_SEC_BLE_KEYS));
+
+#if (BLE_PRIVACY_SPT == TRUE)
+    btm_ble_resolving_list_remove_dev(p_dev_rec);
+#endif
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_is_a_bonded_dev
+**
+** Description       Is the specified device is a bonded device
+**
+** Returns          true - dev is bonded
+**
+*******************************************************************************/
+bool    btm_sec_is_a_bonded_dev (BD_ADDR bda)
+{
+
+    tBTM_SEC_DEV_REC *p_dev_rec= btm_find_dev (bda);
+    bool    is_bonded= false;
+
+    if (p_dev_rec &&
+#if (SMP_INCLUDED == TRUE)
+        ((p_dev_rec->ble.key_type && (p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_KNOWN))||
+#else
+        (
+#endif
+         (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)))
+    {
+        is_bonded = true;
+    }
+    BTM_TRACE_DEBUG ("%s() is_bonded=%d", __func__, is_bonded);
+    return(is_bonded);
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_is_le_capable_dev
+**
+** Description       Is the specified device is dual mode or LE only device
+**
+** Returns          true - dev is a dual mode
+**
+*******************************************************************************/
+bool    btm_sec_is_le_capable_dev (BD_ADDR bda)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec= btm_find_dev (bda);
+    bool    le_capable = false;
+
+#if (BLE_INCLUDED == TRUE)
+    if (p_dev_rec && (p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE)
+        le_capable  = true;
+#endif
+    return le_capable;
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_use_smp_br_chnl
+**
+** Description      The function checks if SMP BR connection can be used with
+**                  the peer.
+**                  Is called when authentication for dedicated bonding is
+**                  successfully completed.
+**
+** Returns          true - if SMP BR connection can be used (the link key is
+**                         generated from P-256 and the peer supports Security
+**                         Manager over BR).
+**
+*******************************************************************************/
+static bool    btm_sec_use_smp_br_chnl(tBTM_SEC_DEV_REC *p_dev_rec)
+{
+    uint32_t ext_feat;
+    uint8_t chnl_mask[L2CAP_FIXED_CHNL_ARRAY_SIZE];
+
+    BTM_TRACE_DEBUG ("%s() link_key_type = 0x%x", __func__,
+                      p_dev_rec->link_key_type);
+
+    if ((p_dev_rec->link_key_type != BTM_LKEY_TYPE_UNAUTH_COMB_P_256) &&
+        (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256))
+         return false;
+
+    if (!L2CA_GetPeerFeatures (p_dev_rec->bd_addr, &ext_feat, chnl_mask))
+        return false;
+
+    if (!(chnl_mask[0] & L2CAP_FIXED_CHNL_SMP_BR_BIT))
+        return false;
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         btm_sec_is_master
+**
+** Description      The function checks if the device is BR/EDR master after
+**                  pairing is completed.
+**
+** Returns          true - if the device is master.
+**
+*******************************************************************************/
+static bool    btm_sec_is_master(tBTM_SEC_DEV_REC *p_dev_rec)
+{
+    tACL_CONN *p= btm_bda_to_acl(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR);
+    return (p && (p->link_role == BTM_ROLE_MASTER));
+}
+
diff --git a/bt/stack/btu/btu_hcif.cc b/bt/stack/btu/btu_hcif.cc
new file mode 100644
index 0000000..8b2d567
--- /dev/null
+++ b/bt/stack/btu/btu_hcif.cc
@@ -0,0 +1,1710 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 functions that interface with the HCI transport. On
+ *  the receive side, it routes events to the appropriate handler, e.g.
+ *  L2CAP, ScoMgr. On the transmit side, it manages the command
+ *  transmission.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btu_hcif"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "device/include/controller.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "bt_common.h"
+#include "hci_layer.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+
+// TODO(zachoverflow): remove this horrible hack
+#include "btu.h"
+extern fixed_queue_t *btu_hci_msg_queue;
+
+extern void btm_process_cancel_complete(uint8_t status, uint8_t mode);
+extern void btm_ble_test_command_complete(uint8_t *p);
+
+/********************************************************************************/
+/*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
+/********************************************************************************/
+static void btu_hcif_inquiry_comp_evt (uint8_t *p);
+static void btu_hcif_inquiry_result_evt (uint8_t *p);
+static void btu_hcif_inquiry_rssi_result_evt (uint8_t *p);
+static void btu_hcif_extended_inquiry_result_evt (uint8_t *p);
+
+static void btu_hcif_connection_comp_evt (uint8_t *p);
+static void btu_hcif_connection_request_evt (uint8_t *p);
+static void btu_hcif_disconnection_comp_evt (uint8_t *p);
+static void btu_hcif_authentication_comp_evt (uint8_t *p);
+static void btu_hcif_rmt_name_request_comp_evt (uint8_t *p, uint16_t evt_len);
+static void btu_hcif_encryption_change_evt (uint8_t *p);
+static void btu_hcif_read_rmt_features_comp_evt (uint8_t *p);
+static void btu_hcif_read_rmt_ext_features_comp_evt (uint8_t *p);
+static void btu_hcif_read_rmt_version_comp_evt (uint8_t *p);
+static void btu_hcif_qos_setup_comp_evt (uint8_t *p);
+static void btu_hcif_command_complete_evt (BT_HDR *response, void *context);
+static void btu_hcif_command_status_evt (uint8_t status, BT_HDR *command, void *context);
+static void btu_hcif_hardware_error_evt (uint8_t *p);
+static void btu_hcif_flush_occured_evt (void);
+static void btu_hcif_role_change_evt (uint8_t *p);
+static void btu_hcif_num_compl_data_pkts_evt (uint8_t *p);
+static void btu_hcif_mode_change_evt (uint8_t *p);
+static void btu_hcif_pin_code_request_evt (uint8_t *p);
+static void btu_hcif_link_key_request_evt (uint8_t *p);
+static void btu_hcif_link_key_notification_evt (uint8_t *p);
+static void btu_hcif_loopback_command_evt (void);
+static void btu_hcif_data_buf_overflow_evt (void);
+static void btu_hcif_max_slots_changed_evt (void);
+static void btu_hcif_read_clock_off_comp_evt (uint8_t *p);
+static void btu_hcif_conn_pkt_type_change_evt (void);
+static void btu_hcif_qos_violation_evt (uint8_t *p);
+static void btu_hcif_page_scan_mode_change_evt (void);
+static void btu_hcif_page_scan_rep_mode_chng_evt (void);
+static void btu_hcif_esco_connection_comp_evt(uint8_t *p);
+static void btu_hcif_esco_connection_chg_evt(uint8_t *p);
+
+/* Simple Pairing Events */
+static void btu_hcif_host_support_evt (uint8_t *p);
+static void btu_hcif_io_cap_request_evt (uint8_t *p);
+static void btu_hcif_io_cap_response_evt (uint8_t *p);
+static void btu_hcif_user_conf_request_evt (uint8_t *p);
+static void btu_hcif_user_passkey_request_evt (uint8_t *p);
+static void btu_hcif_user_passkey_notif_evt (uint8_t *p);
+static void btu_hcif_keypress_notif_evt (uint8_t *p);
+static void btu_hcif_rem_oob_request_evt (uint8_t *p);
+
+static void btu_hcif_simple_pair_complete_evt (uint8_t *p);
+    #if L2CAP_NON_FLUSHABLE_PB_INCLUDED == true
+static void btu_hcif_enhanced_flush_complete_evt (void);
+    #endif
+
+    #if (BTM_SSR_INCLUDED == true)
+static void btu_hcif_ssr_evt (uint8_t *p, uint16_t evt_len);
+    #endif /* BTM_SSR_INCLUDED == TRUE */
+
+    #if BLE_INCLUDED == true
+static void btu_ble_ll_conn_complete_evt (uint8_t *p, uint16_t evt_len);
+static void btu_ble_process_adv_pkt (uint8_t *p);
+static void btu_ble_read_remote_feat_evt (uint8_t *p);
+static void btu_ble_ll_conn_param_upd_evt (uint8_t *p, uint16_t evt_len);
+static void btu_ble_proc_ltk_req (uint8_t *p);
+static void btu_hcif_encryption_key_refresh_cmpl_evt (uint8_t *p);
+static void btu_ble_data_length_change_evt (uint8_t *p, uint16_t evt_len);
+#if (BLE_LLT_INCLUDED == TRUE)
+static void btu_ble_rc_param_req_evt(uint8_t *p);
+#endif
+#if (BLE_PRIVACY_SPT == TRUE)
+static void btu_ble_proc_enhanced_conn_cmpl (uint8_t *p, uint16_t evt_len);
+#endif
+
+    #endif
+
+/*******************************************************************************
+**
+** Function         btu_hcif_process_event
+**
+** Description      This function is called when an event is received from
+**                  the Host Controller.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btu_hcif_process_event (UNUSED_ATTR uint8_t controller_id, BT_HDR *p_msg)
+{
+    uint8_t *p = (uint8_t *)(p_msg + 1) + p_msg->offset;
+    uint8_t hci_evt_code, hci_evt_len;
+#if (BLE_INCLUDED == TRUE)
+    uint8_t ble_sub_code;
+#endif
+    STREAM_TO_UINT8  (hci_evt_code, p);
+    STREAM_TO_UINT8  (hci_evt_len, p);
+
+    switch (hci_evt_code)
+    {
+        case HCI_INQUIRY_COMP_EVT:
+            btu_hcif_inquiry_comp_evt (p);
+            break;
+        case HCI_INQUIRY_RESULT_EVT:
+            btu_hcif_inquiry_result_evt (p);
+            break;
+        case HCI_INQUIRY_RSSI_RESULT_EVT:
+            btu_hcif_inquiry_rssi_result_evt (p);
+            break;
+        case HCI_EXTENDED_INQUIRY_RESULT_EVT:
+            btu_hcif_extended_inquiry_result_evt (p);
+            break;
+        case HCI_CONNECTION_COMP_EVT:
+            btu_hcif_connection_comp_evt (p);
+            break;
+        case HCI_CONNECTION_REQUEST_EVT:
+            btu_hcif_connection_request_evt (p);
+            break;
+        case HCI_DISCONNECTION_COMP_EVT:
+            btu_hcif_disconnection_comp_evt (p);
+            break;
+        case HCI_AUTHENTICATION_COMP_EVT:
+            btu_hcif_authentication_comp_evt (p);
+            break;
+        case HCI_RMT_NAME_REQUEST_COMP_EVT:
+            btu_hcif_rmt_name_request_comp_evt (p, hci_evt_len);
+            break;
+        case HCI_ENCRYPTION_CHANGE_EVT:
+            btu_hcif_encryption_change_evt (p);
+            break;
+#if (BLE_INCLUDED == TRUE)
+        case HCI_ENCRYPTION_KEY_REFRESH_COMP_EVT:
+            btu_hcif_encryption_key_refresh_cmpl_evt(p);
+            break;
+#endif
+        case HCI_READ_RMT_FEATURES_COMP_EVT:
+            btu_hcif_read_rmt_features_comp_evt (p);
+            break;
+        case HCI_READ_RMT_EXT_FEATURES_COMP_EVT:
+            btu_hcif_read_rmt_ext_features_comp_evt (p);
+            break;
+        case HCI_READ_RMT_VERSION_COMP_EVT:
+            btu_hcif_read_rmt_version_comp_evt (p);
+            break;
+        case HCI_QOS_SETUP_COMP_EVT:
+            btu_hcif_qos_setup_comp_evt (p);
+            break;
+        case HCI_COMMAND_COMPLETE_EVT:
+            LOG_ERROR(LOG_TAG, "%s should not have received a command complete event. "
+                  "Someone didn't go through the hci transmit_command function.", __func__);
+            break;
+        case HCI_COMMAND_STATUS_EVT:
+            LOG_ERROR(LOG_TAG, "%s should not have received a command status event. "
+                  "Someone didn't go through the hci transmit_command function.", __func__);
+            break;
+        case HCI_HARDWARE_ERROR_EVT:
+            btu_hcif_hardware_error_evt (p);
+            break;
+        case HCI_FLUSH_OCCURED_EVT:
+            btu_hcif_flush_occured_evt ();
+            break;
+        case HCI_ROLE_CHANGE_EVT:
+            btu_hcif_role_change_evt (p);
+            break;
+        case HCI_NUM_COMPL_DATA_PKTS_EVT:
+            btu_hcif_num_compl_data_pkts_evt (p);
+            break;
+        case HCI_MODE_CHANGE_EVT:
+            btu_hcif_mode_change_evt (p);
+            break;
+        case HCI_PIN_CODE_REQUEST_EVT:
+            btu_hcif_pin_code_request_evt (p);
+            break;
+        case HCI_LINK_KEY_REQUEST_EVT:
+            btu_hcif_link_key_request_evt (p);
+            break;
+        case HCI_LINK_KEY_NOTIFICATION_EVT:
+            btu_hcif_link_key_notification_evt (p);
+            break;
+        case HCI_LOOPBACK_COMMAND_EVT:
+            btu_hcif_loopback_command_evt ();
+            break;
+        case HCI_DATA_BUF_OVERFLOW_EVT:
+            btu_hcif_data_buf_overflow_evt ();
+            break;
+        case HCI_MAX_SLOTS_CHANGED_EVT:
+            btu_hcif_max_slots_changed_evt ();
+            break;
+        case HCI_READ_CLOCK_OFF_COMP_EVT:
+            btu_hcif_read_clock_off_comp_evt (p);
+            break;
+        case HCI_CONN_PKT_TYPE_CHANGE_EVT:
+            btu_hcif_conn_pkt_type_change_evt ();
+            break;
+        case HCI_QOS_VIOLATION_EVT:
+            btu_hcif_qos_violation_evt (p);
+            break;
+        case HCI_PAGE_SCAN_MODE_CHANGE_EVT:
+            btu_hcif_page_scan_mode_change_evt ();
+            break;
+        case HCI_PAGE_SCAN_REP_MODE_CHNG_EVT:
+            btu_hcif_page_scan_rep_mode_chng_evt ();
+            break;
+        case HCI_ESCO_CONNECTION_COMP_EVT:
+            btu_hcif_esco_connection_comp_evt (p);
+            break;
+        case HCI_ESCO_CONNECTION_CHANGED_EVT:
+            btu_hcif_esco_connection_chg_evt (p);
+            break;
+#if (BTM_SSR_INCLUDED == TRUE)
+        case HCI_SNIFF_SUB_RATE_EVT:
+            btu_hcif_ssr_evt (p, hci_evt_len);
+            break;
+#endif  /* BTM_SSR_INCLUDED == TRUE */
+        case HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT:
+            btu_hcif_host_support_evt (p);
+            break;
+        case HCI_IO_CAPABILITY_REQUEST_EVT:
+            btu_hcif_io_cap_request_evt (p);
+            break;
+        case HCI_IO_CAPABILITY_RESPONSE_EVT:
+            btu_hcif_io_cap_response_evt (p);
+            break;
+        case HCI_USER_CONFIRMATION_REQUEST_EVT:
+            btu_hcif_user_conf_request_evt (p);
+            break;
+        case HCI_USER_PASSKEY_REQUEST_EVT:
+            btu_hcif_user_passkey_request_evt (p);
+            break;
+        case HCI_REMOTE_OOB_DATA_REQUEST_EVT:
+            btu_hcif_rem_oob_request_evt (p);
+            break;
+        case HCI_SIMPLE_PAIRING_COMPLETE_EVT:
+            btu_hcif_simple_pair_complete_evt (p);
+            break;
+        case HCI_USER_PASSKEY_NOTIFY_EVT:
+            btu_hcif_user_passkey_notif_evt (p);
+            break;
+        case HCI_KEYPRESS_NOTIFY_EVT:
+            btu_hcif_keypress_notif_evt (p);
+            break;
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+        case HCI_ENHANCED_FLUSH_COMPLETE_EVT:
+            btu_hcif_enhanced_flush_complete_evt ();
+            break;
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+        case HCI_BLE_EVENT:
+            STREAM_TO_UINT8  (ble_sub_code, p);
+
+            HCI_TRACE_EVENT("BLE HCI(id=%d) event = 0x%02x)", hci_evt_code,  ble_sub_code);
+
+            switch (ble_sub_code)
+            {
+                case HCI_BLE_ADV_PKT_RPT_EVT: /* result of inquiry */
+                    btu_ble_process_adv_pkt(p);
+                    break;
+                case HCI_BLE_CONN_COMPLETE_EVT:
+                    btu_ble_ll_conn_complete_evt(p, hci_evt_len);
+                    break;
+                case HCI_BLE_LL_CONN_PARAM_UPD_EVT:
+                    btu_ble_ll_conn_param_upd_evt(p, hci_evt_len);
+                    break;
+                case HCI_BLE_READ_REMOTE_FEAT_CMPL_EVT:
+                    btu_ble_read_remote_feat_evt(p);
+                    break;
+                case HCI_BLE_LTK_REQ_EVT: /* received only at slave device */
+                    btu_ble_proc_ltk_req(p);
+                    break;
+#if (BLE_PRIVACY_SPT == TRUE)
+                case HCI_BLE_ENHANCED_CONN_COMPLETE_EVT:
+                    btu_ble_proc_enhanced_conn_cmpl(p, hci_evt_len);
+                    break;
+#endif
+#if (BLE_LLT_INCLUDED == TRUE)
+               case HCI_BLE_RC_PARAM_REQ_EVT:
+                    btu_ble_rc_param_req_evt(p);
+                    break;
+#endif
+               case HCI_BLE_DATA_LENGTH_CHANGE_EVT:
+                    btu_ble_data_length_change_evt(p, hci_evt_len);
+                    break;
+            }
+            break;
+#endif /* BLE_INCLUDED */
+        case HCI_VENDOR_SPECIFIC_EVT:
+                btm_vendor_specific_evt (p, hci_evt_len);
+            break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_send_cmd
+**
+** Description      This function is called to send commands to the Host Controller.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btu_hcif_send_cmd (UNUSED_ATTR uint8_t controller_id, BT_HDR *p_buf)
+{
+    if (!p_buf)
+      return;
+
+    uint16_t opcode;
+    uint8_t *stream = p_buf->data + p_buf->offset;
+    void * vsc_callback = NULL;
+
+    STREAM_TO_UINT16(opcode, stream);
+
+    // Eww...horrible hackery here
+    /* If command was a VSC, then extract command_complete callback */
+    if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC
+#if (BLE_INCLUDED == TRUE)
+        || (opcode == HCI_BLE_RAND)
+        || (opcode == HCI_BLE_ENCRYPT)
+#endif
+       ) {
+        vsc_callback = *((void **)(p_buf + 1));
+    }
+
+    hci_layer_get_interface()->transmit_command(
+      p_buf,
+      btu_hcif_command_complete_evt,
+      btu_hcif_command_status_evt,
+      vsc_callback);
+
+#if (HCILP_INCLUDED == TRUE)
+    btu_check_bt_sleep ();
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_inquiry_comp_evt
+**
+** Description      Process event HCI_INQUIRY_COMP_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_inquiry_comp_evt (uint8_t *p)
+{
+    uint8_t status;
+
+    STREAM_TO_UINT8    (status, p);
+
+    /* Tell inquiry processing that we are done */
+    btm_process_inq_complete(status, BTM_BR_INQUIRY_MASK);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_inquiry_result_evt
+**
+** Description      Process event HCI_INQUIRY_RESULT_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_inquiry_result_evt (uint8_t *p)
+{
+    /* Store results in the cache */
+    btm_process_inq_results (p, BTM_INQ_RESULT_STANDARD);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_inquiry_rssi_result_evt
+**
+** Description      Process event HCI_INQUIRY_RSSI_RESULT_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_inquiry_rssi_result_evt (uint8_t *p)
+{
+    /* Store results in the cache */
+    btm_process_inq_results (p, BTM_INQ_RESULT_WITH_RSSI);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_extended_inquiry_result_evt
+**
+** Description      Process event HCI_EXTENDED_INQUIRY_RESULT_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_extended_inquiry_result_evt (uint8_t *p)
+{
+    /* Store results in the cache */
+    btm_process_inq_results (p, BTM_INQ_RESULT_EXTENDED);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_connection_comp_evt
+**
+** Description      Process event HCI_CONNECTION_COMP_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_connection_comp_evt (uint8_t *p)
+{
+    uint8_t     status;
+    uint16_t    handle;
+    BD_ADDR     bda;
+    uint8_t     link_type;
+    uint8_t     enc_mode;
+#if (BTM_SCO_INCLUDED == TRUE)
+    tBTM_ESCO_DATA  esco_data;
+#endif
+
+    STREAM_TO_UINT8    (status, p);
+    STREAM_TO_UINT16   (handle, p);
+    STREAM_TO_BDADDR   (bda, p);
+    STREAM_TO_UINT8    (link_type, p);
+    STREAM_TO_UINT8    (enc_mode, p);
+
+    handle = HCID_GET_HANDLE (handle);
+
+    if (link_type == HCI_LINK_TYPE_ACL)
+    {
+        btm_sec_connected (bda, handle, status, enc_mode);
+
+        l2c_link_hci_conn_comp (status, handle, bda);
+    }
+#if (BTM_SCO_INCLUDED == TRUE)
+    else
+    {
+        memset(&esco_data, 0, sizeof(tBTM_ESCO_DATA));
+        /* esco_data.link_type = HCI_LINK_TYPE_SCO; already zero */
+        memcpy (esco_data.bd_addr, bda, BD_ADDR_LEN);
+        btm_sco_connected (status, bda, handle, &esco_data);
+    }
+#endif /* BTM_SCO_INCLUDED */
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_connection_request_evt
+**
+** Description      Process event HCI_CONNECTION_REQUEST_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_connection_request_evt (uint8_t *p)
+{
+    BD_ADDR     bda;
+    DEV_CLASS   dc;
+    uint8_t     link_type;
+
+    STREAM_TO_BDADDR   (bda, p);
+    STREAM_TO_DEVCLASS (dc, p);
+    STREAM_TO_UINT8    (link_type, p);
+
+    /* Pass request to security manager to check connect filters before */
+    /* passing request to l2cap */
+    if (link_type == HCI_LINK_TYPE_ACL)
+    {
+        btm_sec_conn_req (bda, dc);
+    }
+#if (BTM_SCO_INCLUDED == TRUE)
+    else
+    {
+        btm_sco_conn_req (bda, dc, link_type);
+    }
+#endif /* BTM_SCO_INCLUDED */
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_disconnection_comp_evt
+**
+** Description      Process event HCI_DISCONNECTION_COMP_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_disconnection_comp_evt (uint8_t *p)
+{
+    uint16_t handle;
+    uint8_t reason;
+
+    ++p;
+    STREAM_TO_UINT16 (handle, p);
+    STREAM_TO_UINT8  (reason, p);
+
+    handle = HCID_GET_HANDLE (handle);
+
+#if (BTM_SCO_INCLUDED == TRUE)
+    /* If L2CAP doesn't know about it, send it to SCO */
+    if (!l2c_link_hci_disc_comp (handle, reason))
+        btm_sco_removed (handle, reason);
+#else
+    l2c_link_hci_disc_comp (handle, reason);
+#endif /* BTM_SCO_INCLUDED */
+
+    /* Notify security manager */
+    btm_sec_disconnected (handle, reason);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_authentication_comp_evt
+**
+** Description      Process event HCI_AUTHENTICATION_COMP_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_authentication_comp_evt (uint8_t *p)
+{
+    uint8_t status;
+    uint16_t handle;
+
+    STREAM_TO_UINT8  (status, p);
+    STREAM_TO_UINT16 (handle, p);
+
+    btm_sec_auth_complete (handle, status);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_rmt_name_request_comp_evt
+**
+** Description      Process event HCI_RMT_NAME_REQUEST_COMP_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_rmt_name_request_comp_evt (uint8_t *p, uint16_t evt_len)
+{
+    uint8_t status;
+    BD_ADDR bd_addr;
+
+    STREAM_TO_UINT8 (status, p);
+    STREAM_TO_BDADDR (bd_addr, p);
+
+    evt_len -= (1 + BD_ADDR_LEN);
+
+    btm_process_remote_name (bd_addr, p, evt_len, status);
+
+    btm_sec_rmt_name_request_complete (bd_addr, p, status);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_encryption_change_evt
+**
+** Description      Process event HCI_ENCRYPTION_CHANGE_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_encryption_change_evt (uint8_t *p)
+{
+    uint8_t status;
+    uint16_t handle;
+    uint8_t encr_enable;
+
+    STREAM_TO_UINT8  (status, p);
+    STREAM_TO_UINT16 (handle, p);
+    STREAM_TO_UINT8  (encr_enable, p);
+
+    btm_acl_encrypt_change (handle, status, encr_enable);
+    btm_sec_encrypt_change (handle, status, encr_enable);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_read_rmt_features_comp_evt
+**
+** Description      Process event HCI_READ_RMT_FEATURES_COMP_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_read_rmt_features_comp_evt (uint8_t *p)
+{
+    btm_read_remote_features_complete(p);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_read_rmt_ext_features_comp_evt
+**
+** Description      Process event HCI_READ_RMT_EXT_FEATURES_COMP_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_read_rmt_ext_features_comp_evt (uint8_t *p)
+{
+    uint8_t *p_cur = p;
+    uint8_t status;
+    uint16_t handle;
+
+    STREAM_TO_UINT8 (status, p_cur);
+
+    if (status == HCI_SUCCESS)
+        btm_read_remote_ext_features_complete(p);
+    else
+    {
+        STREAM_TO_UINT16 (handle, p_cur);
+        btm_read_remote_ext_features_failed(status, handle);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_read_rmt_version_comp_evt
+**
+** Description      Process event HCI_READ_RMT_VERSION_COMP_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_read_rmt_version_comp_evt (uint8_t *p)
+{
+    btm_read_remote_version_complete (p);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_qos_setup_comp_evt
+**
+** Description      Process event HCI_QOS_SETUP_COMP_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_qos_setup_comp_evt (uint8_t *p)
+{
+    uint8_t status;
+    uint16_t handle;
+    FLOW_SPEC flow;
+
+    STREAM_TO_UINT8 (status, p);
+    STREAM_TO_UINT16 (handle, p);
+    STREAM_TO_UINT8 (flow.qos_flags, p);
+    STREAM_TO_UINT8 (flow.service_type, p);
+    STREAM_TO_UINT32 (flow.token_rate, p);
+    STREAM_TO_UINT32 (flow.peak_bandwidth, p);
+    STREAM_TO_UINT32 (flow.latency, p);
+    STREAM_TO_UINT32 (flow.delay_variation, p);
+
+    btm_qos_setup_complete(status, handle, &flow);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_esco_connection_comp_evt
+**
+** Description      Process event HCI_ESCO_CONNECTION_COMP_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_esco_connection_comp_evt (uint8_t *p)
+{
+#if (BTM_SCO_INCLUDED == TRUE)
+    tBTM_ESCO_DATA  data;
+    uint16_t        handle;
+    BD_ADDR         bda;
+    uint8_t         status;
+
+    STREAM_TO_UINT8 (status, p);
+    STREAM_TO_UINT16 (handle, p);
+    STREAM_TO_BDADDR (bda, p);
+
+    STREAM_TO_UINT8 (data.link_type, p);
+    STREAM_TO_UINT8 (data.tx_interval, p);
+    STREAM_TO_UINT8 (data.retrans_window, p);
+    STREAM_TO_UINT16 (data.rx_pkt_len, p);
+    STREAM_TO_UINT16 (data.tx_pkt_len, p);
+    STREAM_TO_UINT8 (data.air_mode, p);
+
+    memcpy (data.bd_addr, bda, BD_ADDR_LEN);
+    btm_sco_connected (status, bda, handle, &data);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_esco_connection_chg_evt
+**
+** Description      Process event HCI_ESCO_CONNECTION_CHANGED_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_esco_connection_chg_evt (uint8_t *p)
+{
+#if (BTM_SCO_INCLUDED == TRUE)
+    uint16_t handle;
+    uint16_t tx_pkt_len;
+    uint16_t rx_pkt_len;
+    uint8_t status;
+    uint8_t tx_interval;
+    uint8_t retrans_window;
+
+    STREAM_TO_UINT8 (status, p);
+    STREAM_TO_UINT16 (handle, p);
+
+    STREAM_TO_UINT8 (tx_interval, p);
+    STREAM_TO_UINT8 (retrans_window, p);
+    STREAM_TO_UINT16 (rx_pkt_len, p);
+    STREAM_TO_UINT16 (tx_pkt_len, p);
+
+    btm_esco_proc_conn_chg (status, handle, tx_interval, retrans_window,
+                            rx_pkt_len, tx_pkt_len);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_hdl_command_complete
+**
+** Description      Handle command complete event
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_hdl_command_complete (uint16_t opcode, uint8_t *p, uint16_t evt_len,
+                                           void *p_cplt_cback)
+{
+    switch (opcode)
+    {
+        case HCI_INQUIRY_CANCEL:
+            /* Tell inquiry processing that we are done */
+            btm_process_cancel_complete(HCI_SUCCESS, BTM_BR_INQUIRY_MASK);
+            break;
+        case HCI_SET_EVENT_FILTER:
+            btm_event_filter_complete (p);
+            break;
+
+        case HCI_DELETE_STORED_LINK_KEY:
+            btm_delete_stored_link_key_complete (p);
+            break;
+
+        case HCI_READ_LOCAL_NAME:
+            btm_read_local_name_complete (p, evt_len);
+            break;
+
+        case HCI_GET_LINK_QUALITY:
+            btm_read_link_quality_complete (p);
+            break;
+
+        case HCI_READ_RSSI:
+            btm_read_rssi_complete (p);
+            break;
+
+        case HCI_READ_TRANSMIT_POWER_LEVEL:
+            btm_read_tx_power_complete(p, false);
+            break;
+
+        case HCI_CREATE_CONNECTION_CANCEL:
+            btm_create_conn_cancel_complete(p);
+            break;
+
+        case HCI_READ_LOCAL_OOB_DATA:
+            btm_read_local_oob_complete(p);
+            break;
+
+        case HCI_READ_INQ_TX_POWER_LEVEL:
+            btm_read_inq_tx_power_complete(p);
+            break;
+
+#if (BLE_INCLUDED == TRUE)
+/* BLE Commands sComplete*/
+        case HCI_BLE_ADD_WHITE_LIST:
+            btm_ble_add_2_white_list_complete(*p);
+            break;
+
+        case HCI_BLE_CLEAR_WHITE_LIST:
+            btm_ble_clear_white_list_complete(p, evt_len);
+            break;
+
+        case HCI_BLE_REMOVE_WHITE_LIST:
+            btm_ble_remove_from_white_list_complete(p, evt_len);
+            break;
+
+        case HCI_BLE_RAND:
+        case HCI_BLE_ENCRYPT:
+            btm_ble_rand_enc_complete (p, opcode, (tBTM_RAND_ENC_CB *)p_cplt_cback);
+            break;
+
+        case HCI_BLE_READ_ADV_CHNL_TX_POWER:
+            btm_read_tx_power_complete(p, true);
+            break;
+
+        case HCI_BLE_WRITE_ADV_ENABLE:
+            btm_ble_write_adv_enable_complete(p);
+            break;
+
+        case HCI_BLE_CREATE_LL_CONN:
+            btm_ble_create_ll_conn_complete(*p);
+            break;
+
+        case HCI_BLE_TRANSMITTER_TEST:
+        case HCI_BLE_RECEIVER_TEST:
+        case HCI_BLE_TEST_END:
+            btm_ble_test_command_complete(p);
+            break;
+
+#if (BLE_PRIVACY_SPT == TRUE)
+        case HCI_BLE_ADD_DEV_RESOLVING_LIST:
+            btm_ble_add_resolving_list_entry_complete(p, evt_len);
+            break;
+
+        case HCI_BLE_RM_DEV_RESOLVING_LIST:
+            btm_ble_remove_resolving_list_entry_complete(p, evt_len);
+            break;
+
+        case HCI_BLE_CLEAR_RESOLVING_LIST:
+            btm_ble_clear_resolving_list_complete(p, evt_len);
+            break;
+
+        case HCI_BLE_READ_RESOLVABLE_ADDR_PEER:
+             btm_ble_read_resolving_list_entry_complete(p, evt_len);
+             break;
+
+        case HCI_BLE_READ_RESOLVABLE_ADDR_LOCAL:
+        case HCI_BLE_SET_ADDR_RESOLUTION_ENABLE:
+        case HCI_BLE_SET_RAND_PRIV_ADDR_TIMOUT:
+            break;
+#endif
+#endif /* (BLE_INCLUDED == TRUE) */
+
+        default:
+            if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC)
+                btm_vsc_complete (p, opcode, evt_len, (tBTM_CMPL_CB *)p_cplt_cback);
+            break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_command_complete_evt
+**
+** Description      Process event HCI_COMMAND_COMPLETE_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_command_complete_evt_on_task(BT_HDR *event)
+{
+    command_complete_hack_t *hack = (command_complete_hack_t *)&event->data[0];
+
+    command_opcode_t opcode;
+    uint8_t *stream = hack->response->data + hack->response->offset + 3; // 2 to skip the event headers, 1 to skip the command credits
+    STREAM_TO_UINT16(opcode, stream);
+
+    btu_hcif_hdl_command_complete(
+      opcode,
+      stream,
+      hack->response->len - 5, // 3 for the command complete headers, 2 for the event headers
+      hack->context);
+
+    osi_free(hack->response);
+    osi_free(event);
+}
+
+static void btu_hcif_command_complete_evt(BT_HDR *response, void *context)
+{
+    BT_HDR *event =
+      static_cast<BT_HDR *>(osi_calloc(sizeof(BT_HDR) + sizeof(command_complete_hack_t)));
+    command_complete_hack_t *hack = (command_complete_hack_t *)&event->data[0];
+
+    hack->callback = btu_hcif_command_complete_evt_on_task;
+    hack->response = response;
+    hack->context = context;
+
+    event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK;
+
+    fixed_queue_enqueue(btu_hci_msg_queue, event);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_hdl_command_status
+**
+** Description      Handle a command status event
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_hdl_command_status (uint16_t opcode, uint8_t status, uint8_t *p_cmd,
+                                         void *p_vsc_status_cback)
+{
+    BD_ADDR         bd_addr;
+    uint16_t        handle;
+#if (BTM_SCO_INCLUDED == TRUE)
+    tBTM_ESCO_DATA  esco_data;
+#endif
+
+    switch (opcode)
+    {
+        case HCI_EXIT_SNIFF_MODE:
+        case HCI_EXIT_PARK_MODE:
+#if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
+            if (status != HCI_SUCCESS)
+            {
+                /* Allow SCO initiation to continue if waiting for change mode event */
+                if (p_cmd != NULL)
+                {
+                    p_cmd++;    /* bypass length field */
+                    STREAM_TO_UINT16 (handle, p_cmd);
+                    btm_sco_chk_pend_unpark (status, handle);
+                }
+            }
+#endif
+            /* Case Falls Through */
+
+        case HCI_HOLD_MODE:
+        case HCI_SNIFF_MODE:
+        case HCI_PARK_MODE:
+            btm_pm_proc_cmd_status(status);
+            break;
+
+        default:
+            /* If command failed to start, we may need to tell BTM */
+            if (status != HCI_SUCCESS)
+            {
+                switch (opcode)
+                {
+                    case HCI_INQUIRY:
+                        /* Tell inquiry processing that we are done */
+                        btm_process_inq_complete(status, BTM_BR_INQUIRY_MASK);
+                        break;
+
+                    case HCI_RMT_NAME_REQUEST:
+                        /* Tell inquiry processing that we are done */
+                        btm_process_remote_name (NULL, NULL, 0, status);
+
+                        btm_sec_rmt_name_request_complete (NULL, NULL, status);
+                        break;
+
+                    case HCI_QOS_SETUP_COMP_EVT:
+                        /* Tell qos setup that we are done */
+                        btm_qos_setup_complete(status,0,NULL);
+                        break;
+
+                    case HCI_SWITCH_ROLE:
+                        /* Tell BTM that the command failed */
+                        /* read bd addr out of stored command */
+                        if (p_cmd != NULL)
+                        {
+                            p_cmd++;
+                            STREAM_TO_BDADDR (bd_addr, p_cmd);
+                            btm_acl_role_changed(status, bd_addr, BTM_ROLE_UNDEFINED);
+                        }
+                        else
+                            btm_acl_role_changed(status, NULL, BTM_ROLE_UNDEFINED);
+                        l2c_link_role_changed (NULL, BTM_ROLE_UNDEFINED, HCI_ERR_COMMAND_DISALLOWED);
+                        break;
+
+                    case HCI_CREATE_CONNECTION:
+                        /* read bd addr out of stored command */
+                        if (p_cmd != NULL)
+                        {
+                            p_cmd++;
+                            STREAM_TO_BDADDR (bd_addr, p_cmd);
+                            btm_sec_connected (bd_addr, HCI_INVALID_HANDLE, status, 0);
+                            l2c_link_hci_conn_comp (status, HCI_INVALID_HANDLE, bd_addr);
+                        }
+                        break;
+
+                    case HCI_READ_RMT_EXT_FEATURES:
+                        if (p_cmd != NULL)
+                        {
+                            p_cmd++; /* skip command length */
+                            STREAM_TO_UINT16 (handle, p_cmd);
+                        }
+                        else
+                            handle = HCI_INVALID_HANDLE;
+
+                        btm_read_remote_ext_features_failed(status, handle);
+                        break;
+
+                    case HCI_AUTHENTICATION_REQUESTED:
+                        /* Device refused to start authentication.  That should be treated as authentication failure. */
+                        btm_sec_auth_complete (BTM_INVALID_HCI_HANDLE, status);
+                        break;
+
+                    case HCI_SET_CONN_ENCRYPTION:
+                        /* Device refused to start encryption.  That should be treated as encryption failure. */
+                        btm_sec_encrypt_change (BTM_INVALID_HCI_HANDLE, status, false);
+                        break;
+
+#if (BLE_INCLUDED == TRUE)
+                    case HCI_BLE_CREATE_LL_CONN:
+                        btm_ble_create_ll_conn_complete(status);
+                        break;
+#endif
+
+#if (BTM_SCO_INCLUDED == TRUE)
+                    case HCI_SETUP_ESCO_CONNECTION:
+                        /* read handle out of stored command */
+                        if (p_cmd != NULL)
+                        {
+                            p_cmd++;
+                            STREAM_TO_UINT16 (handle, p_cmd);
+
+                            /* Determine if initial connection failed or is a change of setup */
+                            if (btm_is_sco_active(handle))
+                                btm_esco_proc_conn_chg (status, handle, 0, 0, 0, 0);
+                            else
+                                btm_sco_connected (status, NULL, handle, &esco_data);
+                        }
+                        break;
+#endif
+
+/* This is commented out until an upper layer cares about returning event
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+            case HCI_ENHANCED_FLUSH:
+                break;
+#endif
+*/
+                    default:
+                        if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC)
+                            btm_vsc_complete (&status, opcode, 1, (tBTM_CMPL_CB *)p_vsc_status_cback);
+                        break;
+                }
+
+            }
+            else
+            {
+                if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC)
+                    btm_vsc_complete (&status, opcode, 1, (tBTM_CMPL_CB *)p_vsc_status_cback);
+            }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_command_status_evt
+**
+** Description      Process event HCI_COMMAND_STATUS_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_command_status_evt_on_task(BT_HDR *event)
+{
+    command_status_hack_t *hack = (command_status_hack_t *)&event->data[0];
+
+    command_opcode_t opcode;
+    uint8_t *stream = hack->command->data + hack->command->offset;
+    STREAM_TO_UINT16(opcode, stream);
+
+    btu_hcif_hdl_command_status(
+      opcode,
+      hack->status,
+      stream,
+      hack->context);
+
+    osi_free(hack->command);
+    osi_free(event);
+}
+
+static void btu_hcif_command_status_evt(uint8_t status, BT_HDR *command, void *context)
+{
+    BT_HDR *event =
+        static_cast<BT_HDR *>(osi_calloc(sizeof(BT_HDR) + sizeof(command_status_hack_t)));
+    command_status_hack_t *hack = (command_status_hack_t *)&event->data[0];
+
+    hack->callback = btu_hcif_command_status_evt_on_task;
+    hack->status = status;
+    hack->command = command;
+    hack->context = context;
+
+    event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK;
+
+    fixed_queue_enqueue(btu_hci_msg_queue, event);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_hardware_error_evt
+**
+** Description      Process event HCI_HARDWARE_ERROR_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_hardware_error_evt (uint8_t *p)
+{
+    HCI_TRACE_ERROR("Ctlr H/w error event - code:0x%x", *p);
+
+    /* If anyone wants device status notifications, give him one. */
+    btm_report_device_status (BTM_DEV_STATUS_DOWN);
+
+    /* Reset the controller */
+    if (BTM_IsDeviceUp())
+        BTM_DeviceReset (NULL);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_flush_occured_evt
+**
+** Description      Process event HCI_FLUSH_OCCURED_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_flush_occured_evt (void)
+{
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_role_change_evt
+**
+** Description      Process event HCI_ROLE_CHANGE_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_role_change_evt (uint8_t *p)
+{
+    uint8_t     status;
+    BD_ADDR     bda;
+    uint8_t     role;
+
+    STREAM_TO_UINT8 (status, p);
+    STREAM_TO_BDADDR (bda, p);
+    STREAM_TO_UINT8  (role, p);
+
+    l2c_link_role_changed (bda, role, status);
+    btm_acl_role_changed(status, bda, role);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_num_compl_data_pkts_evt
+**
+** Description      Process event HCI_NUM_COMPL_DATA_PKTS_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_num_compl_data_pkts_evt (uint8_t *p)
+{
+    /* Process for L2CAP and SCO */
+    l2c_link_process_num_completed_pkts (p);
+
+    /* Send on to SCO */
+    /*?? No SCO for now */
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_mode_change_evt
+**
+** Description      Process event HCI_MODE_CHANGE_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_mode_change_evt (uint8_t *p)
+{
+    uint8_t     status;
+    uint16_t    handle;
+    uint8_t     current_mode;
+    uint16_t    interval;
+
+    STREAM_TO_UINT8 (status, p);
+
+    STREAM_TO_UINT16 (handle, p);
+    STREAM_TO_UINT8 (current_mode, p);
+    STREAM_TO_UINT16 (interval, p);
+#if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
+    btm_sco_chk_pend_unpark (status, handle);
+#endif
+    btm_pm_proc_mode_change (status, handle, current_mode, interval);
+
+#if (HID_DEV_INCLUDED == TRUE && HID_DEV_PM_INCLUDED == TRUE)
+    hidd_pm_proc_mode_change( status, current_mode, interval ) ;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_ssr_evt
+**
+** Description      Process event HCI_SNIFF_SUB_RATE_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+    #if (BTM_SSR_INCLUDED == true)
+static void btu_hcif_ssr_evt (uint8_t *p, uint16_t evt_len)
+{
+    btm_pm_proc_ssr_evt(p, evt_len);
+}
+    #endif
+
+/*******************************************************************************
+**
+** Function         btu_hcif_pin_code_request_evt
+**
+** Description      Process event HCI_PIN_CODE_REQUEST_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_pin_code_request_evt (uint8_t *p)
+{
+    BD_ADDR  bda;
+
+    STREAM_TO_BDADDR (bda, p);
+
+    /* Tell L2CAP that there was a PIN code request,  */
+    /* it may need to stretch timeouts                */
+    l2c_pin_code_request (bda);
+
+    btm_sec_pin_code_request (bda);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_link_key_request_evt
+**
+** Description      Process event HCI_LINK_KEY_REQUEST_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_link_key_request_evt (uint8_t *p)
+{
+    BD_ADDR  bda;
+
+    STREAM_TO_BDADDR (bda, p);
+    btm_sec_link_key_request (bda);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_link_key_notification_evt
+**
+** Description      Process event HCI_LINK_KEY_NOTIFICATION_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_link_key_notification_evt (uint8_t *p)
+{
+    BD_ADDR  bda;
+    LINK_KEY key;
+    uint8_t  key_type;
+
+    STREAM_TO_BDADDR (bda, p);
+    STREAM_TO_ARRAY16 (key, p);
+    STREAM_TO_UINT8 (key_type, p);
+
+    btm_sec_link_key_notification (bda, key, key_type);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_loopback_command_evt
+**
+** Description      Process event HCI_LOOPBACK_COMMAND_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_loopback_command_evt (void)
+{
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_data_buf_overflow_evt
+**
+** Description      Process event HCI_DATA_BUF_OVERFLOW_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_data_buf_overflow_evt (void)
+{
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_max_slots_changed_evt
+**
+** Description      Process event HCI_MAX_SLOTS_CHANGED_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_max_slots_changed_evt (void)
+{
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_read_clock_off_comp_evt
+**
+** Description      Process event HCI_READ_CLOCK_OFF_COMP_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_read_clock_off_comp_evt (uint8_t *p)
+{
+    uint8_t     status;
+    uint16_t    handle;
+    uint16_t    clock_offset;
+
+    STREAM_TO_UINT8  (status, p);
+
+    /* If failed to get clock offset just drop the result */
+    if (status != HCI_SUCCESS)
+        return;
+
+    STREAM_TO_UINT16 (handle, p);
+    STREAM_TO_UINT16 (clock_offset, p);
+
+    handle = HCID_GET_HANDLE (handle);
+
+    btm_process_clk_off_comp_evt (handle, clock_offset);
+    btm_sec_update_clock_offset (handle, clock_offset);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_conn_pkt_type_change_evt
+**
+** Description      Process event HCI_CONN_PKT_TYPE_CHANGE_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_conn_pkt_type_change_evt (void)
+{
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_qos_violation_evt
+**
+** Description      Process event HCI_QOS_VIOLATION_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_qos_violation_evt (uint8_t *p)
+{
+    uint16_t handle;
+
+    STREAM_TO_UINT16 (handle, p);
+
+    handle = HCID_GET_HANDLE (handle);
+
+    l2c_link_hci_qos_violation (handle);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_page_scan_mode_change_evt
+**
+** Description      Process event HCI_PAGE_SCAN_MODE_CHANGE_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_page_scan_mode_change_evt (void)
+{
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_page_scan_rep_mode_chng_evt
+**
+** Description      Process event HCI_PAGE_SCAN_REP_MODE_CHNG_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_page_scan_rep_mode_chng_evt (void)
+{
+}
+
+/**********************************************
+** Simple Pairing Events
+***********************************************/
+
+/*******************************************************************************
+**
+** Function         btu_hcif_host_support_evt
+**
+** Description      Process event HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_host_support_evt (uint8_t *p)
+{
+    btm_sec_rmt_host_support_feat_evt(p);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_io_cap_request_evt
+**
+** Description      Process event HCI_IO_CAPABILITY_REQUEST_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_io_cap_request_evt (uint8_t *p)
+{
+    btm_io_capabilities_req(p);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_io_cap_response_evt
+**
+** Description      Process event HCI_IO_CAPABILITY_RESPONSE_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_io_cap_response_evt (uint8_t *p)
+{
+    btm_io_capabilities_rsp(p);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_user_conf_request_evt
+**
+** Description      Process event HCI_USER_CONFIRMATION_REQUEST_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_user_conf_request_evt (uint8_t *p)
+{
+    btm_proc_sp_req_evt(BTM_SP_CFM_REQ_EVT, p);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_user_passkey_request_evt
+**
+** Description      Process event HCI_USER_PASSKEY_REQUEST_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_user_passkey_request_evt (uint8_t *p)
+{
+    btm_proc_sp_req_evt(BTM_SP_KEY_REQ_EVT, p);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_user_passkey_notif_evt
+**
+** Description      Process event HCI_USER_PASSKEY_NOTIFY_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_user_passkey_notif_evt (uint8_t *p)
+{
+    btm_proc_sp_req_evt(BTM_SP_KEY_NOTIF_EVT, p);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_keypress_notif_evt
+**
+** Description      Process event HCI_KEYPRESS_NOTIFY_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_keypress_notif_evt (uint8_t *p)
+{
+    btm_keypress_notif_evt(p);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_rem_oob_request_evt
+**
+** Description      Process event HCI_REMOTE_OOB_DATA_REQUEST_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_rem_oob_request_evt (uint8_t *p)
+{
+    btm_rem_oob_req(p);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_simple_pair_complete_evt
+**
+** Description      Process event HCI_SIMPLE_PAIRING_COMPLETE_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+static void btu_hcif_simple_pair_complete_evt (uint8_t *p)
+{
+    btm_simple_pair_complete(p);
+}
+
+/*******************************************************************************
+**
+** Function         btu_hcif_enhanced_flush_complete_evt
+**
+** Description      Process event HCI_ENHANCED_FLUSH_COMPLETE_EVT
+**
+** Returns          void
+**
+*******************************************************************************/
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+static void btu_hcif_enhanced_flush_complete_evt (void)
+{
+/* This is empty until an upper layer cares about returning event */
+}
+#endif
+/**********************************************
+** End of Simple Pairing Events
+***********************************************/
+
+/**********************************************
+** BLE Events
+***********************************************/
+#if (BLE_INCLUDED == TRUE)
+static void btu_hcif_encryption_key_refresh_cmpl_evt (uint8_t *p)
+{
+    uint8_t status;
+    uint8_t enc_enable = 0;
+    uint16_t handle;
+
+    STREAM_TO_UINT8  (status, p);
+    STREAM_TO_UINT16 (handle, p);
+
+    if (status == HCI_SUCCESS) enc_enable = 1;
+
+    btm_sec_encrypt_change (handle, status, enc_enable);
+}
+
+static void btu_ble_process_adv_pkt (uint8_t *p)
+{
+    HCI_TRACE_EVENT("btu_ble_process_adv_pkt");
+
+    btm_ble_process_adv_pkt(p);
+}
+
+static void btu_ble_ll_conn_complete_evt ( uint8_t *p, uint16_t evt_len)
+{
+    btm_ble_conn_complete(p, evt_len, false);
+}
+#if (BLE_PRIVACY_SPT == TRUE)
+static void btu_ble_proc_enhanced_conn_cmpl( uint8_t *p, uint16_t evt_len)
+{
+    btm_ble_conn_complete(p, evt_len, true);
+}
+#endif
+static void btu_ble_ll_conn_param_upd_evt (uint8_t *p, uint16_t evt_len)
+{
+    /* LE connection update has completed successfully as a master. */
+    /* We can enable the update request if the result is a success. */
+    /* extract the HCI handle first */
+    uint8_t status;
+    uint16_t handle;
+    uint16_t interval;
+    uint16_t latency;
+    uint16_t timeout;
+
+    STREAM_TO_UINT8(status, p);
+    STREAM_TO_UINT16(handle, p);
+    STREAM_TO_UINT16(interval, p);
+    STREAM_TO_UINT16(latency, p);
+    STREAM_TO_UINT16(timeout, p);
+
+    l2cble_process_conn_update_evt(handle, status, interval, latency, timeout);
+}
+
+static void btu_ble_read_remote_feat_evt (uint8_t *p)
+{
+    btm_ble_read_remote_features_complete(p);
+}
+
+static void btu_ble_proc_ltk_req (uint8_t *p)
+{
+    uint16_t ediv, handle;
+    uint8_t *pp;
+
+    STREAM_TO_UINT16(handle, p);
+    pp = p + 8;
+    STREAM_TO_UINT16(ediv, pp);
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+    btm_ble_ltk_request(handle, p, ediv);
+#endif
+    /* This is empty until an upper layer cares about returning event */
+}
+
+static void btu_ble_data_length_change_evt(uint8_t *p, uint16_t evt_len)
+{
+    uint16_t handle;
+    uint16_t tx_data_len;
+    uint16_t rx_data_len;
+
+    if (!controller_get_interface()->supports_ble_packet_extension())
+    {
+        HCI_TRACE_WARNING("%s, request not supported", __func__);
+        return;
+    }
+
+    STREAM_TO_UINT16(handle, p);
+    STREAM_TO_UINT16(tx_data_len, p);
+    p += 2; /* Skip the TxTimer */
+    STREAM_TO_UINT16(rx_data_len, p);
+
+    l2cble_process_data_length_change_event(handle, tx_data_len, rx_data_len);
+}
+
+/**********************************************
+** End of BLE Events Handler
+***********************************************/
+#if (BLE_LLT_INCLUDED == TRUE)
+static void btu_ble_rc_param_req_evt(uint8_t *p)
+{
+    uint16_t handle;
+    uint16_t int_min, int_max, latency, timeout;
+
+    STREAM_TO_UINT16(handle, p);
+    STREAM_TO_UINT16(int_min, p);
+    STREAM_TO_UINT16(int_max, p);
+    STREAM_TO_UINT16(latency, p);
+    STREAM_TO_UINT16(timeout, p);
+
+    l2cble_process_rc_param_request_evt(handle, int_min, int_max, latency, timeout);
+}
+#endif /* BLE_LLT_INCLUDED */
+
+#endif /* BLE_INCLUDED */
+
diff --git a/bt/stack/btu/btu_init.cc b/bt/stack/btu/btu_init.cc
new file mode 100644
index 0000000..5373e99
--- /dev/null
+++ b/bt/stack/btu/btu_init.cc
@@ -0,0 +1,171 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2000-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.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_task"
+
+#include <assert.h>
+#include <pthread.h>
+#include <string.h>
+
+#include "bt_target.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "l2c_int.h"
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/log.h"
+#include "osi/include/thread.h"
+#include "sdpint.h"
+
+#if (BLE_INCLUDED == TRUE)
+#include "gatt_api.h"
+#include "gatt_int.h"
+#if (SMP_INCLUDED == TRUE)
+#include "smp_int.h"
+#endif
+#endif
+
+// Increase BTU task thread priority to avoid pre-emption
+// of audio realated tasks.
+#define BTU_TASK_THREAD_PRIORITY (-19)
+
+extern fixed_queue_t *btif_msg_queue;
+
+// Communication queue from bta thread to bt_workqueue.
+fixed_queue_t *btu_bta_msg_queue;
+
+// Communication queue from hci thread to bt_workqueue.
+extern fixed_queue_t *btu_hci_msg_queue;
+
+// General timer queue.
+fixed_queue_t *btu_general_alarm_queue;
+
+thread_t *bt_workqueue_thread;
+static const char *BT_WORKQUEUE_NAME = "bt_workqueue";
+
+extern void PLATFORM_DisableHciTransport(uint8_t bDisable);
+/*****************************************************************************
+**                          V A R I A B L E S                                *
+******************************************************************************/
+// TODO(cmanton) Move this out of this file
+const BD_ADDR   BT_BD_ANY = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+void btu_task_start_up(void *context);
+void btu_task_shut_down(void *context);
+
+/*****************************************************************************
+**
+** Function         btu_init_core
+**
+** Description      Initialize control block memory for each core component.
+**
+**
+** Returns          void
+**
+******************************************************************************/
+void btu_init_core(void)
+{
+    /* Initialize the mandatory core stack components */
+    btm_init();
+
+    l2c_init();
+
+    sdp_init();
+
+#if (BLE_INCLUDED == TRUE)
+    gatt_init();
+#if (SMP_INCLUDED == TRUE)
+    SMP_Init();
+#endif
+    btm_ble_init();
+#endif
+}
+
+/*****************************************************************************
+**
+** Function         btu_free_core
+**
+** Description      Releases control block memory for each core component.
+**
+**
+** Returns          void
+**
+******************************************************************************/
+void btu_free_core(void)
+{
+      /* Free the mandatory core stack components */
+      l2c_free();
+
+#if (BLE_INCLUDED == TRUE)
+      gatt_free();
+#endif
+}
+
+/*****************************************************************************
+**
+** Function         BTU_StartUp
+**
+** Description      Initializes the BTU control block.
+**
+**                  NOTE: Must be called before creating any tasks
+**                      (RPC, BTU, HCIT, APPL, etc.)
+**
+** Returns          void
+**
+******************************************************************************/
+void BTU_StartUp(void)
+{
+    btu_trace_level = HCI_INITIAL_TRACE_LEVEL;
+
+    btu_bta_msg_queue = fixed_queue_new(SIZE_MAX);
+    if (btu_bta_msg_queue == NULL)
+        goto error_exit;
+
+    btu_general_alarm_queue = fixed_queue_new(SIZE_MAX);
+    if (btu_general_alarm_queue == NULL)
+        goto error_exit;
+
+    bt_workqueue_thread = thread_new(BT_WORKQUEUE_NAME);
+    if (bt_workqueue_thread == NULL)
+        goto error_exit;
+
+    thread_set_priority(bt_workqueue_thread, BTU_TASK_THREAD_PRIORITY);
+
+    // Continue startup on bt workqueue thread.
+    thread_post(bt_workqueue_thread, btu_task_start_up, NULL);
+    return;
+
+  error_exit:;
+    LOG_ERROR(LOG_TAG, "%s Unable to allocate resources for bt_workqueue", __func__);
+    BTU_ShutDown();
+}
+
+void BTU_ShutDown(void) {
+  btu_task_shut_down(NULL);
+
+  fixed_queue_free(btu_bta_msg_queue, NULL);
+  btu_bta_msg_queue = NULL;
+
+  fixed_queue_free(btu_general_alarm_queue, NULL);
+  btu_general_alarm_queue = NULL;
+
+  thread_free(bt_workqueue_thread);
+
+  bt_workqueue_thread = NULL;
+}
diff --git a/bt/stack/btu/btu_task.cc b/bt/stack/btu/btu_task.cc
new file mode 100644
index 0000000..fc015ae
--- /dev/null
+++ b/bt/stack/btu/btu_task.cc
@@ -0,0 +1,235 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btu_task"
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_target.h"
+#include "bt_trace.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btcore/include/module.h"
+#include "bte.h"
+#include "btif_common.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "gap_int.h"
+#include "bt_common.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/future.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/thread.h"
+#include "port_api.h"
+#include "port_ext.h"
+#include "sdpint.h"
+
+#if (BNEP_INCLUDED == TRUE)
+#include "bnep_int.h"
+#endif
+
+#if (PAN_INCLUDED == TRUE)
+#include "pan_int.h"
+#endif
+
+#if (HID_HOST_INCLUDED == TRUE)
+#include "hidh_int.h"
+#endif
+
+#if (AVDT_INCLUDED == TRUE)
+#include "avdt_int.h"
+#else
+extern void avdt_rcv_sync_info (BT_HDR *p_buf); /* this is for hci_test */
+#endif
+
+#if (MCA_INCLUDED == TRUE)
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mca_int.h"
+#endif
+
+#include "bta_sys.h"
+
+#if (BLE_INCLUDED == TRUE)
+#include "gatt_int.h"
+#if (SMP_INCLUDED == TRUE)
+#include "smp_int.h"
+#endif
+#include "btm_ble_int.h"
+#endif
+
+
+
+/* Define BTU storage area
+*/
+uint8_t btu_trace_level = HCI_INITIAL_TRACE_LEVEL;
+
+// Communication queue between btu_task and bta.
+extern fixed_queue_t *btu_bta_msg_queue;
+
+// Communication queue between btu_task and hci.
+extern fixed_queue_t *btu_hci_msg_queue;
+
+// General timer queue.
+extern fixed_queue_t *btu_general_alarm_queue;
+
+extern fixed_queue_t *event_queue;
+extern fixed_queue_t *btif_msg_queue;
+
+extern thread_t *bt_workqueue_thread;
+
+static void btu_hci_msg_process(BT_HDR *p_msg);
+
+void btu_hci_msg_ready(fixed_queue_t *queue, UNUSED_ATTR void *context) {
+    BT_HDR *p_msg = (BT_HDR *)fixed_queue_dequeue(queue);
+    btu_hci_msg_process(p_msg);
+}
+
+void btu_bta_msg_ready(fixed_queue_t *queue, UNUSED_ATTR void *context) {
+    BT_HDR *p_msg = (BT_HDR *)fixed_queue_dequeue(queue);
+    bta_sys_event(p_msg);
+}
+
+static void btu_hci_msg_process(BT_HDR *p_msg) {
+    /* Determine the input message type. */
+    switch (p_msg->event & BT_EVT_MASK)
+    {
+        case BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK: // TODO(zachoverflow): remove this
+            ((post_to_task_hack_t *)(&p_msg->data[0]))->callback(p_msg);
+#if (HCILP_INCLUDED == TRUE)
+            /* If the host receives events which it doesn't responsd to, */
+            /* it should start an idle timer to enter sleep mode.        */
+            btu_check_bt_sleep ();
+#endif
+            break;
+        case BT_EVT_TO_BTU_HCI_ACL:
+            /* All Acl Data goes to L2CAP */
+            l2c_rcv_acl_data (p_msg);
+            break;
+
+        case BT_EVT_TO_BTU_L2C_SEG_XMIT:
+            /* L2CAP segment transmit complete */
+            l2c_link_segments_xmitted (p_msg);
+            break;
+
+        case BT_EVT_TO_BTU_HCI_SCO:
+#if (BTM_SCO_INCLUDED == TRUE)
+            btm_route_sco_data (p_msg);
+            break;
+#endif
+
+        case BT_EVT_TO_BTU_HCI_EVT:
+            btu_hcif_process_event ((uint8_t)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
+            osi_free(p_msg);
+
+#if (HCILP_INCLUDED == TRUE)
+            /* If host receives events which it doesn't response to, */
+            /* host should start idle timer to enter sleep mode.     */
+            btu_check_bt_sleep ();
+#endif
+            break;
+
+        case BT_EVT_TO_BTU_HCI_CMD:
+            btu_hcif_send_cmd ((uint8_t)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
+            break;
+
+        default:
+            osi_free(p_msg);
+            break;
+    }
+}
+
+void btu_task_start_up(UNUSED_ATTR void *context) {
+  BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API,
+      "btu_task pending for preload complete event");
+
+  LOG_INFO(LOG_TAG, "Bluetooth chip preload is complete");
+
+  BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API,
+      "btu_task received preload complete event");
+
+  /* Initialize the mandatory core stack control blocks
+     (BTU, BTM, L2CAP, and SDP)
+   */
+  btu_init_core();
+
+  /* Initialize any optional stack components */
+  BTE_InitStack();
+
+  bta_sys_init();
+
+  /* Initialise platform trace levels at this point as BTE_InitStack() and bta_sys_init()
+   * reset the control blocks and preset the trace level with XXX_INITIAL_TRACE_LEVEL
+   */
+  module_init(get_module(BTE_LOGMSG_MODULE));
+
+  // Inform the bt jni thread initialization is ok.
+  btif_transfer_context(btif_init_ok, 0, NULL, 0, NULL);
+
+  fixed_queue_register_dequeue(btu_bta_msg_queue,
+      thread_get_reactor(bt_workqueue_thread),
+      btu_bta_msg_ready,
+      NULL);
+
+  fixed_queue_register_dequeue(btu_hci_msg_queue,
+      thread_get_reactor(bt_workqueue_thread),
+      btu_hci_msg_ready,
+      NULL);
+
+  alarm_register_processing_queue(btu_general_alarm_queue, bt_workqueue_thread);
+}
+
+void btu_task_shut_down(UNUSED_ATTR void *context) {
+  fixed_queue_unregister_dequeue(btu_bta_msg_queue);
+  fixed_queue_unregister_dequeue(btu_hci_msg_queue);
+  alarm_unregister_processing_queue(btu_general_alarm_queue);
+
+  module_clean_up(get_module(BTE_LOGMSG_MODULE));
+
+  bta_sys_free();
+  btu_free_core();
+}
+
+#if (HCILP_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function         btu_check_bt_sleep
+**
+** Description      This function is called to check if controller can go to sleep.
+**
+** Returns          void
+**
+*******************************************************************************/
+void btu_check_bt_sleep (void)
+{
+    // TODO(zachoverflow) take pending commands into account?
+    if (l2cb.controller_xmit_window == l2cb.num_lm_acl_bufs)
+    {
+        bte_main_lpm_allow_bt_device_sleep();
+    }
+}
+#endif
diff --git a/bt/stack/gap/gap_api.cc b/bt/stack/gap/gap_api.cc
new file mode 100644
index 0000000..aaa1ae6
--- /dev/null
+++ b/bt/stack/gap/gap_api.cc
@@ -0,0 +1,75 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "gap_int.h"
+
+tGAP_CB  gap_cb;
+
+/*******************************************************************************
+**
+** Function         GAP_SetTraceLevel
+**
+** Description      This function sets the trace level for GAP.  If called with
+**                  a value of 0xFF, it simply returns the current trace level.
+**
+** Returns          The new or current trace level
+**
+*******************************************************************************/
+uint8_t GAP_SetTraceLevel (uint8_t new_level)
+{
+    if (new_level != 0xFF)
+        gap_cb.trace_level = new_level;
+
+    return (gap_cb.trace_level);
+}
+
+/*******************************************************************************
+**
+** Function         GAP_Init
+**
+** Description      Initializes the control blocks used by GAP.
+**
+**                  This routine should not be called except once per
+**                      stack invocation.
+**
+** Returns          Nothing
+**
+*******************************************************************************/
+void GAP_Init(void)
+{
+    memset (&gap_cb, 0, sizeof (tGAP_CB));
+
+#if defined(GAP_INITIAL_TRACE_LEVEL)
+    gap_cb.trace_level = GAP_INITIAL_TRACE_LEVEL;
+#else
+    gap_cb.trace_level = BT_TRACE_LEVEL_NONE;    /* No traces */
+#endif
+
+#if (GAP_CONN_INCLUDED == TRUE)
+    gap_conn_init();
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+    gap_attr_db_init();
+#endif
+}
+
diff --git a/bt/stack/gap/gap_ble.cc b/bt/stack/gap/gap_ble.cc
new file mode 100644
index 0000000..50f3a54
--- /dev/null
+++ b/bt/stack/gap/gap_ble.cc
@@ -0,0 +1,795 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+#include "bt_target.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+#include "bt_utils.h"
+#include <string.h>
+#include "gap_int.h"
+#include "gap_api.h"
+#include "gattdefs.h"
+#include "gatt_api.h"
+#include "gatt_int.h"
+#include "btm_int.h"
+#include "hcimsgs.h"
+#include "btcore/include/uuid.h"
+#include "osi/include/osi.h"
+
+#define GAP_CHAR_ICON_SIZE          2
+#define GAP_CHAR_DEV_NAME_SIZE      248
+#define GAP_MAX_NUM_INC_SVR       0
+#define GAP_MAX_ATTR_NUM          (2 * GAP_MAX_CHAR_NUM + GAP_MAX_NUM_INC_SVR + 1)
+#define GAP_MAX_CHAR_VALUE_SIZE   (30 + GAP_CHAR_DEV_NAME_SIZE)
+
+
+#ifndef GAP_ATTR_DB_SIZE
+#define GAP_ATTR_DB_SIZE      GATT_DB_MEM_SIZE(GAP_MAX_NUM_INC_SVR, GAP_MAX_CHAR_NUM, GAP_MAX_CHAR_VALUE_SIZE)
+#endif
+
+static void gap_ble_s_attr_request_cback (uint16_t conn_id, uint32_t trans_id, tGATTS_REQ_TYPE op_code, tGATTS_DATA *p_data);
+
+/* client connection callback */
+static void  gap_ble_c_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, uint16_t conn_id, bool connected,
+                                      tGATT_DISCONN_REASON reason, tGATT_TRANSPORT transport);
+static void  gap_ble_c_cmpl_cback (uint16_t conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data);
+
+static tGATT_CBACK gap_cback =
+{
+    gap_ble_c_connect_cback,
+    gap_ble_c_cmpl_cback,
+    NULL,
+    NULL,
+    gap_ble_s_attr_request_cback,
+    NULL,
+    NULL
+};
+
+
+
+/*******************************************************************************
+**
+** Function         gap_find_clcb_by_bd_addr
+**
+** Description      The function searches all LCB with macthing bd address
+**
+** Returns          total number of clcb found.
+**
+*******************************************************************************/
+tGAP_CLCB *gap_find_clcb_by_bd_addr(BD_ADDR bda)
+{
+    uint8_t i_clcb;
+    tGAP_CLCB    *p_clcb = NULL;
+
+    for (i_clcb = 0, p_clcb= gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++)
+    {
+        if (p_clcb->in_use && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN))
+        {
+            return p_clcb;
+        }
+    }
+
+    return NULL;
+}
+
+/*******************************************************************************
+**
+** Function         gap_ble_find_clcb_by_conn_id
+**
+** Description      The function searches all LCB with macthing connection ID
+**
+** Returns          total number of clcb found.
+**
+*******************************************************************************/
+tGAP_CLCB *gap_ble_find_clcb_by_conn_id(uint16_t conn_id)
+{
+    uint8_t i_clcb;
+    tGAP_CLCB    *p_clcb = NULL;
+
+    for (i_clcb = 0, p_clcb= gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++)
+    {
+        if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id)
+        {
+            return p_clcb;
+        }
+    }
+
+    return p_clcb;
+}
+
+/*******************************************************************************
+**
+** Function         gap_clcb_alloc
+**
+** Description      The function allocates a GAP  connection link control block
+**
+** Returns           NULL if not found. Otherwise pointer to the connection link block.
+**
+*******************************************************************************/
+tGAP_CLCB *gap_clcb_alloc (BD_ADDR bda)
+{
+    uint8_t       i_clcb = 0;
+    tGAP_CLCB    *p_clcb = NULL;
+
+    for (i_clcb = 0, p_clcb= gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++)
+    {
+        if (!p_clcb->in_use)
+        {
+            fixed_queue_free(p_clcb->pending_req_q, NULL);
+            memset(p_clcb, 0, sizeof(tGAP_CLCB));
+            p_clcb->in_use = true;
+            memcpy (p_clcb->bda, bda, BD_ADDR_LEN);
+            p_clcb->pending_req_q = fixed_queue_new(SIZE_MAX);
+            break;
+        }
+    }
+    return p_clcb;
+}
+
+/*******************************************************************************
+**
+** Function         gap_ble_dealloc_clcb
+**
+** Description      The function clean up the pending request queue in GAP
+**
+** Returns          none
+**
+*******************************************************************************/
+void gap_ble_dealloc_clcb(tGAP_CLCB *p_clcb)
+{
+    tGAP_BLE_REQ    *p_q;
+
+    while ((p_q = (tGAP_BLE_REQ *)fixed_queue_try_dequeue(p_clcb->pending_req_q)) != NULL)
+    {
+         /* send callback to all pending requests if being removed*/
+         if (p_q->p_cback != NULL)
+            (*p_q->p_cback)(false, p_clcb->bda, 0, NULL);
+
+         osi_free(p_q);
+    }
+    fixed_queue_free(p_clcb->pending_req_q, NULL);
+
+    memset(p_clcb, 0, sizeof(tGAP_CLCB));
+}
+
+/*******************************************************************************
+**
+** Function         gap_ble_enqueue_request
+**
+** Description      The function enqueue a GAP client request
+**
+** Returns           true is successul; false otherwise
+**
+*******************************************************************************/
+bool    gap_ble_enqueue_request (tGAP_CLCB *p_clcb, uint16_t uuid, tGAP_BLE_CMPL_CBACK *p_cback)
+{
+    tGAP_BLE_REQ *p_q = (tGAP_BLE_REQ *)osi_malloc(sizeof(tGAP_BLE_REQ));
+
+    p_q->p_cback = p_cback;
+    p_q->uuid = uuid;
+    fixed_queue_enqueue(p_clcb->pending_req_q, p_q);
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         gap_ble_dequeue_request
+**
+** Description      The function dequeue a GAP client request if any
+**
+** Returns           true is successul; false otherwise
+**
+*******************************************************************************/
+bool    gap_ble_dequeue_request (tGAP_CLCB *p_clcb, uint16_t * p_uuid, tGAP_BLE_CMPL_CBACK **p_cback)
+{
+    tGAP_BLE_REQ *p_q = (tGAP_BLE_REQ *)fixed_queue_try_dequeue(p_clcb->pending_req_q);;
+
+    if (p_q != NULL)
+    {
+        *p_cback    = p_q->p_cback;
+        *p_uuid     = p_q->uuid;
+        osi_free(p_q);
+        return true;
+    }
+
+    return false;
+}
+
+/*******************************************************************************
+**   GAP Attributes Database Request callback
+*******************************************************************************/
+tGATT_STATUS gap_read_attr_value (uint16_t handle, tGATT_VALUE *p_value, bool    is_long)
+{
+    tGAP_ATTR   *p_db_attr = gap_cb.gatt_attr;
+    uint8_t     *p = p_value->value, i;
+    uint16_t    offset = p_value->offset;
+    uint8_t     *p_dev_name = NULL;
+
+    for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++)
+    {
+        if (handle == p_db_attr->handle)
+        {
+            if (p_db_attr->uuid != GATT_UUID_GAP_DEVICE_NAME &&
+                is_long == true)
+                return GATT_NOT_LONG;
+
+            switch (p_db_attr->uuid)
+            {
+                case GATT_UUID_GAP_DEVICE_NAME:
+                    BTM_ReadLocalDeviceName((char **)&p_dev_name);
+                    if (strlen ((char *)p_dev_name) > GATT_MAX_ATTR_LEN)
+                        p_value->len = GATT_MAX_ATTR_LEN;
+                    else
+                        p_value->len = (uint16_t)strlen ((char *)p_dev_name);
+
+                    if (offset > p_value->len)
+                        return GATT_INVALID_OFFSET;
+                    else
+                    {
+                        p_value->len -= offset;
+                        p_dev_name += offset;
+                        ARRAY_TO_STREAM(p, p_dev_name, p_value->len);
+                        GAP_TRACE_EVENT("GATT_UUID_GAP_DEVICE_NAME len=0x%04x", p_value->len);
+                    }
+                    break;
+
+                case GATT_UUID_GAP_ICON:
+                    UINT16_TO_STREAM(p, p_db_attr->attr_value.icon);
+                    p_value->len = 2;
+                    break;
+
+                case GATT_UUID_GAP_PREF_CONN_PARAM:
+                    UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.int_min); /* int_min */
+                    UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.int_max); /* int_max */
+                    UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.latency); /* latency */
+                    UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.sp_tout);  /* sp_tout */
+                    p_value->len =8;
+                    break;
+
+                /* address resolution */
+                case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
+                    UINT8_TO_STREAM(p, p_db_attr->attr_value.addr_resolution);
+                    p_value->len =1;
+                    break;
+            }
+            return GATT_SUCCESS;
+        }
+    }
+    return GATT_NOT_FOUND;
+}
+
+/*******************************************************************************
+**   GAP Attributes Database Read/Read Blob Request process
+*******************************************************************************/
+tGATT_STATUS gap_proc_read (UNUSED_ATTR tGATTS_REQ_TYPE type, tGATT_READ_REQ *p_data,
+                            tGATTS_RSP *p_rsp)
+{
+    tGATT_STATUS    status = GATT_NO_RESOURCES;
+
+    if (p_data->is_long)
+        p_rsp->attr_value.offset = p_data->offset;
+
+    p_rsp->attr_value.handle = p_data->handle;
+
+    status = gap_read_attr_value(p_data->handle, &p_rsp->attr_value, p_data->is_long);
+
+    return status;
+}
+
+/******************************************************************************
+**
+** Function         gap_proc_write_req
+**
+** Description      GAP ATT server process a write request.
+**
+** Returns          void.
+**
+*******************************************************************************/
+uint8_t gap_proc_write_req(UNUSED_ATTR tGATTS_REQ_TYPE type, tGATT_WRITE_REQ *p_data)
+{
+    tGAP_ATTR   *p_db_attr = gap_cb.gatt_attr;
+    uint8_t i;
+
+    for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++)
+    {
+        if (p_data-> handle == p_db_attr->handle)
+        {
+                return GATT_WRITE_NOT_PERMIT;
+        }
+    }
+    return GATT_NOT_FOUND;
+
+}
+
+/******************************************************************************
+**
+** Function         gap_ble_s_attr_request_cback
+**
+** Description      GAP ATT server attribute access request callback.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void gap_ble_s_attr_request_cback (uint16_t conn_id, uint32_t trans_id,
+                                   tGATTS_REQ_TYPE type, tGATTS_DATA *p_data)
+{
+    uint8_t     status = GATT_INVALID_PDU;
+    tGATTS_RSP  rsp_msg;
+    bool        ignore = false;
+
+    GAP_TRACE_EVENT("gap_ble_s_attr_request_cback : recv type (0x%02x)", type);
+
+    memset(&rsp_msg, 0, sizeof(tGATTS_RSP));
+
+    switch (type)
+    {
+        case GATTS_REQ_TYPE_READ_CHARACTERISTIC:
+        case GATTS_REQ_TYPE_READ_DESCRIPTOR:
+            status = gap_proc_read(type, &p_data->read_req, &rsp_msg);
+            break;
+
+        case GATTS_REQ_TYPE_WRITE_CHARACTERISTIC:
+        case GATTS_REQ_TYPE_WRITE_DESCRIPTOR:
+            if (!p_data->write_req.need_rsp)
+                ignore = true;
+
+            status = gap_proc_write_req(type, &p_data->write_req);
+            break;
+
+        case GATTS_REQ_TYPE_WRITE_EXEC:
+            ignore = true;
+            GAP_TRACE_EVENT("Ignore GATTS_REQ_TYPE_WRITE_EXEC"  );
+            break;
+
+        case GATTS_REQ_TYPE_MTU:
+            GAP_TRACE_EVENT("Get MTU exchange new mtu size: %d", p_data->mtu);
+            ignore = true;
+            break;
+
+        default:
+            GAP_TRACE_EVENT("Unknown/unexpected LE GAP ATT request: 0x%02x", type);
+            break;
+    }
+
+    if (!ignore)
+        GATTS_SendRsp (conn_id, trans_id, status, &rsp_msg);
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_att_db_init
+**
+** Description      GAP ATT database initalization.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void gap_attr_db_init(void)
+{
+    tBT_UUID        app_uuid = {LEN_UUID_128,{0}};
+    uint16_t        service_handle;
+
+    /* Fill our internal UUID with a fixed pattern 0x82 */
+    memset (&app_uuid.uu.uuid128, 0x82, LEN_UUID_128);
+    memset(gap_cb.gatt_attr, 0, sizeof(tGAP_ATTR) *GAP_MAX_CHAR_NUM);
+
+    gap_cb.gatt_if = GATT_Register(&app_uuid, &gap_cback);
+
+    GATT_StartIf(gap_cb.gatt_if);
+
+    bt_uuid_t svc_uuid, name_uuid, icon_uuid, pref_uuid, addr_res_uuid;
+    uuid_128_from_16(&svc_uuid, UUID_SERVCLASS_GAP_SERVER);
+    uuid_128_from_16(&name_uuid, GATT_UUID_GAP_DEVICE_NAME);
+    uuid_128_from_16(&icon_uuid, GATT_UUID_GAP_ICON);
+    uuid_128_from_16(&pref_uuid, GATT_UUID_GAP_PREF_CONN_PARAM);
+    uuid_128_from_16(&addr_res_uuid, 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, .properties = GATT_CHAR_PROP_BIT_READ, .permissions = GATT_PERM_READ},
+        {.type = BTGATT_DB_CHARACTERISTIC, .uuid = icon_uuid, .properties = GATT_CHAR_PROP_BIT_READ, .permissions = GATT_PERM_READ},
+        {.type = BTGATT_DB_CHARACTERISTIC, .uuid = addr_res_uuid, .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 = pref_uuid, .properties = GATT_CHAR_PROP_BIT_READ, .permissions = GATT_PERM_READ}
+#endif
+    };
+
+    /* Add a GAP service */
+    GATTS_AddService(gap_cb.gatt_if, service, sizeof(service)/sizeof(btgatt_db_element_t));
+    service_handle = service[0].attribute_handle;
+
+    GAP_TRACE_EVENT("%s: service_handle = %d",__func__, service_handle);
+
+    gap_cb.gatt_attr[0].uuid = GATT_UUID_GAP_DEVICE_NAME;
+    gap_cb.gatt_attr[0].handle = service[1].attribute_handle;
+
+    gap_cb.gatt_attr[1].uuid = GATT_UUID_GAP_ICON;
+    gap_cb.gatt_attr[1].handle = service[2].attribute_handle;
+
+    gap_cb.gatt_attr[2].uuid = GATT_UUID_GAP_CENTRAL_ADDR_RESOL;
+    gap_cb.gatt_attr[2].handle = service[3].attribute_handle;
+    gap_cb.gatt_attr[2].attr_value.addr_resolution = 0;
+
+#if (BTM_PERIPHERAL_ENABLED == TRUE)     /*  Only needed for peripheral testing */
+
+    gap_cb.gatt_attr[3].uuid = GATT_UUID_GAP_PREF_CONN_PARAM;
+    gap_cb.gatt_attr[3].attr_value.conn_param.int_max = GAP_PREFER_CONN_INT_MAX; /* 6 */
+    gap_cb.gatt_attr[3].attr_value.conn_param.int_min = GAP_PREFER_CONN_INT_MIN; /* 0 */
+    gap_cb.gatt_attr[3].attr_value.conn_param.latency = GAP_PREFER_CONN_LATENCY; /* 0 */
+    gap_cb.gatt_attr[3].attr_value.conn_param.sp_tout = GAP_PREFER_CONN_SP_TOUT; /* 2000 */
+    gap_cb.gatt_attr[3].handle = service[4].attribute_handle;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         GAP_BleAttrDBUpdate
+**
+** Description      GAP ATT database update.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void GAP_BleAttrDBUpdate(uint16_t attr_uuid, tGAP_BLE_ATTR_VALUE *p_value)
+{
+    tGAP_ATTR  *p_db_attr = gap_cb.gatt_attr;
+    uint8_t     i = 0;
+
+    GAP_TRACE_EVENT("GAP_BleAttrDBUpdate attr_uuid=0x%04x", attr_uuid);
+
+    for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++)
+    {
+        if (p_db_attr->uuid == attr_uuid)
+        {
+            GAP_TRACE_EVENT("Found attr_uuid=0x%04x", attr_uuid);
+
+            switch (attr_uuid)
+            {
+            case GATT_UUID_GAP_ICON:
+                p_db_attr->attr_value.icon  =  p_value->icon;
+                break;
+
+            case GATT_UUID_GAP_PREF_CONN_PARAM:
+                memcpy((void *)&p_db_attr->attr_value.conn_param,
+                       (const void *)&p_value->conn_param, sizeof(tGAP_BLE_PREF_PARAM));
+                break;
+
+            case GATT_UUID_GAP_DEVICE_NAME:
+                BTM_SetLocalDeviceName((char *)p_value->p_dev_name);
+                break;
+
+            case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
+                p_db_attr->attr_value.addr_resolution = p_value->addr_resolution;
+                break;
+
+            }
+            break;
+        }
+    }
+
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         gap_ble_send_cl_read_request
+**
+** Description      utility function to send a read request for a GAP charactersitic
+**
+** Returns          true if read started, else false if GAP is busy
+**
+*******************************************************************************/
+bool    gap_ble_send_cl_read_request(tGAP_CLCB *p_clcb)
+{
+    tGATT_READ_PARAM        param;
+    uint16_t                uuid = 0;
+    bool                    started = false;
+
+    if (gap_ble_dequeue_request(p_clcb, &uuid, &p_clcb->p_cback))
+    {
+        memset(&param, 0, sizeof(tGATT_READ_PARAM));
+
+        param.service.uuid.len       = LEN_UUID_16;
+        param.service.uuid.uu.uuid16 = uuid;
+        param.service.s_handle       = 1;
+        param.service.e_handle       = 0xFFFF;
+        param.service.auth_req       = 0;
+
+        if (GATTC_Read(p_clcb->conn_id, GATT_READ_BY_TYPE, &param) == GATT_SUCCESS)
+        {
+            p_clcb->cl_op_uuid = uuid;
+            started = true;
+        }
+    }
+
+    return started;
+}
+
+/*******************************************************************************
+**
+** Function         gap_ble_cl_op_cmpl
+**
+** Description      GAP client operation complete callback
+**
+** Returns          void
+**
+*******************************************************************************/
+void gap_ble_cl_op_cmpl(tGAP_CLCB *p_clcb, bool    status, uint16_t len, uint8_t *p_name)
+{
+    tGAP_BLE_CMPL_CBACK *p_cback = p_clcb->p_cback;
+    uint16_t                op = p_clcb->cl_op_uuid;
+
+    GAP_TRACE_EVENT("gap_ble_cl_op_cmpl status: %d", status);
+
+    p_clcb->cl_op_uuid = 0;
+    p_clcb->p_cback=NULL;
+
+    if (p_cback && op)
+    {
+        GAP_TRACE_EVENT("calling gap_ble_cl_op_cmpl");
+        (* p_cback)(status, p_clcb->bda, len, (char *)p_name);
+    }
+
+    /* if no further activity is requested in callback, drop the link */
+    if (p_clcb->connected)
+    {
+        if (!gap_ble_send_cl_read_request(p_clcb))
+        {
+            GATT_Disconnect(p_clcb->conn_id);
+            gap_ble_dealloc_clcb(p_clcb);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gap_ble_c_connect_cback
+**
+** Description      Client connection callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gap_ble_c_connect_cback (UNUSED_ATTR tGATT_IF gatt_if, BD_ADDR bda,
+                                     uint16_t conn_id,
+                                     bool    connected, tGATT_DISCONN_REASON reason,
+                                     UNUSED_ATTR tGATT_TRANSPORT transport)
+{
+    tGAP_CLCB   *p_clcb = gap_find_clcb_by_bd_addr (bda);
+
+    if (p_clcb != NULL)
+    {
+        if (connected)
+        {
+            p_clcb->conn_id = conn_id;
+            p_clcb->connected = true;
+            /* start operation is pending */
+            gap_ble_send_cl_read_request(p_clcb);
+        }
+        else
+        {
+            p_clcb->connected = false;
+            gap_ble_cl_op_cmpl(p_clcb, false, 0, NULL);
+            /* clean up clcb */
+            gap_ble_dealloc_clcb(p_clcb);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gap_ble_c_cmpl_cback
+**
+** Description      Client operation complete callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gap_ble_c_cmpl_cback (uint16_t conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data)
+
+{
+    tGAP_CLCB   *p_clcb = gap_ble_find_clcb_by_conn_id(conn_id);
+    uint16_t    op_type;
+    uint16_t    min, max, latency, tout;
+    uint16_t    len;
+    uint8_t     *pp;
+
+    if (p_clcb == NULL)
+        return;
+
+    op_type = p_clcb->cl_op_uuid;
+
+    GAP_TRACE_EVENT ("gap_ble_c_cmpl_cback() - op_code: 0x%02x  status: 0x%02x  read_type: 0x%04x", op, status, op_type);
+    /* Currently we only issue read commands */
+    if (op != GATTC_OPTYPE_READ)
+        return;
+
+    if (status != GATT_SUCCESS)
+    {
+        gap_ble_cl_op_cmpl(p_clcb, false, 0, NULL);
+        return;
+    }
+
+    pp = p_data->att_value.value;
+
+    switch (op_type)
+    {
+        case GATT_UUID_GAP_PREF_CONN_PARAM:
+            GAP_TRACE_EVENT ("GATT_UUID_GAP_PREF_CONN_PARAM");
+            /* Extract the peripheral preferred connection parameters and save them */
+
+            STREAM_TO_UINT16 (min, pp);
+            STREAM_TO_UINT16 (max, pp);
+            STREAM_TO_UINT16 (latency, pp);
+            STREAM_TO_UINT16 (tout, pp);
+
+            BTM_BleSetPrefConnParams (p_clcb->bda, min, max, latency, tout);
+            /* release the connection here */
+            gap_ble_cl_op_cmpl(p_clcb, true, 0, NULL);
+            break;
+
+        case GATT_UUID_GAP_DEVICE_NAME:
+            GAP_TRACE_EVENT ("GATT_UUID_GAP_DEVICE_NAME");
+            len = (uint16_t)strlen((char *)pp);
+            if (len > GAP_CHAR_DEV_NAME_SIZE)
+                len = GAP_CHAR_DEV_NAME_SIZE;
+            gap_ble_cl_op_cmpl(p_clcb, true, len, pp);
+            break;
+
+        case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
+            gap_ble_cl_op_cmpl(p_clcb, true, 1, pp);
+            break;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         gap_ble_accept_cl_operation
+**
+** Description      Start a process to read peer address resolution capability
+**
+** Returns          true if request accepted
+**
+*******************************************************************************/
+bool    gap_ble_accept_cl_operation(BD_ADDR peer_bda, uint16_t uuid, tGAP_BLE_CMPL_CBACK *p_cback)
+{
+    tGAP_CLCB *p_clcb;
+    bool    started = false;
+
+    if (p_cback == NULL && uuid != GATT_UUID_GAP_PREF_CONN_PARAM)
+        return(started);
+
+    if ((p_clcb = gap_find_clcb_by_bd_addr (peer_bda)) == NULL)
+    {
+        if ((p_clcb = gap_clcb_alloc(peer_bda)) == NULL)
+        {
+            GAP_TRACE_ERROR("gap_ble_accept_cl_operation max connection reached");
+            return started;
+        }
+    }
+
+    GAP_TRACE_EVENT ("%s() - BDA: %08x%04x  cl_op_uuid: 0x%04x",
+                      __func__,
+                      (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3],
+                      (peer_bda[4]<<8)+peer_bda[5], uuid);
+
+    if (GATT_GetConnIdIfConnected(gap_cb.gatt_if, peer_bda, &p_clcb->conn_id, BT_TRANSPORT_LE))
+        p_clcb->connected = true;
+
+    /* hold the link here */
+    if (!GATT_Connect(gap_cb.gatt_if, p_clcb->bda, true, BT_TRANSPORT_LE, false))
+        return started;
+
+    /* enqueue the request */
+    gap_ble_enqueue_request(p_clcb, uuid, p_cback);
+
+    if (p_clcb->connected && p_clcb->cl_op_uuid == 0)
+        started = gap_ble_send_cl_read_request(p_clcb);
+    else /* wait for connection up or pending operation to finish */
+        started = true;
+
+   return started;
+}
+/*******************************************************************************
+**
+** Function         GAP_BleReadPeerPrefConnParams
+**
+** Description      Start a process to read a connected peripheral's preferred
+**                  connection parameters
+**
+** Returns          true if read started, else false if GAP is busy
+**
+*******************************************************************************/
+bool    GAP_BleReadPeerPrefConnParams (BD_ADDR peer_bda)
+{
+    return gap_ble_accept_cl_operation (peer_bda, GATT_UUID_GAP_PREF_CONN_PARAM, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         GAP_BleReadPeerDevName
+**
+** Description      Start a process to read a connected peripheral's device name.
+**
+** Returns          true if request accepted
+**
+*******************************************************************************/
+bool    GAP_BleReadPeerDevName (BD_ADDR peer_bda, tGAP_BLE_CMPL_CBACK *p_cback)
+{
+    return gap_ble_accept_cl_operation (peer_bda, GATT_UUID_GAP_DEVICE_NAME, p_cback);
+}
+
+/*******************************************************************************
+**
+** Function         GAP_BleReadPeerAddressResolutionCap
+**
+** Description      Start a process to read peer address resolution capability
+**
+** Returns          true if request accepted
+**
+*******************************************************************************/
+bool    GAP_BleReadPeerAddressResolutionCap (BD_ADDR peer_bda, tGAP_BLE_CMPL_CBACK *p_cback)
+{
+    return gap_ble_accept_cl_operation(peer_bda, GATT_UUID_GAP_CENTRAL_ADDR_RESOL, p_cback);
+}
+
+/*******************************************************************************
+**
+** Function         GAP_BleCancelReadPeerDevName
+**
+** Description      Cancel reading a peripheral's device name.
+**
+** Returns          true if request accepted
+**
+*******************************************************************************/
+bool    GAP_BleCancelReadPeerDevName (BD_ADDR peer_bda)
+{
+    tGAP_CLCB *p_clcb = gap_find_clcb_by_bd_addr (peer_bda);
+
+    GAP_TRACE_EVENT ("GAP_BleCancelReadPeerDevName() - BDA: %08x%04x  cl_op_uuid: 0x%04x",
+                      (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3],
+                      (peer_bda[4]<<8)+peer_bda[5], (p_clcb == NULL)? 0 : p_clcb->cl_op_uuid);
+
+    if (p_clcb == NULL)
+    {
+        GAP_TRACE_ERROR ("Cannot cancel current op is not get dev name");
+        return false;
+    }
+
+    if (!p_clcb->connected)
+    {
+        if (!GATT_CancelConnect(gap_cb.gatt_if, peer_bda, true))
+        {
+            GAP_TRACE_ERROR ("Cannot cancel where No connection id");
+            return false;
+        }
+    }
+
+    gap_ble_cl_op_cmpl(p_clcb, false, 0, NULL);
+
+    return(true);
+}
+
+#endif  /* BLE_INCLUDED */
+
+
+
+
+
diff --git a/bt/stack/gap/gap_conn.cc b/bt/stack/gap/gap_conn.cc
new file mode 100644
index 0000000..b63fca7
--- /dev/null
+++ b/bt/stack/gap/gap_conn.cc
@@ -0,0 +1,1234 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+
+
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "btu.h"
+#include "gap_int.h"
+#include "l2cdefs.h"
+#include "l2c_int.h"
+#include <string.h>
+#include "osi/include/mutex.h"
+#include "osi/include/osi.h"
+#if (GAP_CONN_INCLUDED == TRUE)
+#include "btm_int.h"
+
+/********************************************************************************/
+/*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
+/********************************************************************************/
+static void gap_connect_ind (BD_ADDR  bd_addr, uint16_t l2cap_cid, uint16_t psm, uint8_t l2cap_id);
+static void gap_connect_cfm (uint16_t l2cap_cid, uint16_t result);
+static void gap_config_ind (uint16_t l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void gap_config_cfm (uint16_t l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void gap_disconnect_ind (uint16_t l2cap_cid, bool    ack_needed);
+static void gap_data_ind (uint16_t l2cap_cid, BT_HDR *p_msg);
+static void gap_congestion_ind (uint16_t lcid, bool    is_congested);
+static void gap_tx_complete_ind (uint16_t l2cap_cid, uint16_t sdu_sent);
+
+static tGAP_CCB *gap_find_ccb_by_cid (uint16_t cid);
+static tGAP_CCB *gap_find_ccb_by_handle (uint16_t handle);
+static tGAP_CCB *gap_allocate_ccb (void);
+static void      gap_release_ccb (tGAP_CCB *p_ccb);
+static void      gap_checks_con_flags (tGAP_CCB *p_ccb);
+
+/*******************************************************************************
+**
+** Function         gap_conn_init
+**
+** Description      This function is called to initialize GAP connection management
+**
+** Returns          void
+**
+*******************************************************************************/
+void gap_conn_init (void)
+{
+#if (AMP_INCLUDED == TRUE)
+    gap_cb.conn.reg_info.pAMP_ConnectInd_Cb         = gap_connect_ind;
+    gap_cb.conn.reg_info.pAMP_ConnectCfm_Cb         = gap_connect_cfm;
+    gap_cb.conn.reg_info.pAMP_ConnectPnd_Cb         = NULL;
+    gap_cb.conn.reg_info.pAMP_ConfigInd_Cb          = gap_config_ind;
+    gap_cb.conn.reg_info.pAMP_ConfigCfm_Cb          = gap_config_cfm;
+    gap_cb.conn.reg_info.pAMP_DisconnectInd_Cb      = gap_disconnect_ind;
+    gap_cb.conn.reg_info.pAMP_DisconnectCfm_Cb      = NULL;
+    gap_cb.conn.reg_info.pAMP_QoSViolationInd_Cb    = NULL;
+    gap_cb.conn.reg_info.pAMP_DataInd_Cb            = gap_data_ind;
+    gap_cb.conn.reg_info.pAMP_CongestionStatus_Cb   = gap_congestion_ind;
+    gap_cb.conn.reg_info.pAMP_TxComplete_Cb         = NULL;
+    gap_cb.conn.reg_info.pAMP_MoveInd_Cb            = NULL;
+    gap_cb.conn.reg_info.pAMP_MoveRsp_Cb            = NULL;
+    gap_cb.conn.reg_info.pAMP_MoveCfm_Cb            = NULL; //gap_move_cfm
+    gap_cb.conn.reg_info.pAMP_MoveCfmRsp_Cb         = NULL; //gap_move_cfm_rsp
+
+#else
+    gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb       = gap_connect_ind;
+    gap_cb.conn.reg_info.pL2CA_ConnectCfm_Cb       = gap_connect_cfm;
+    gap_cb.conn.reg_info.pL2CA_ConnectPnd_Cb       = NULL;
+    gap_cb.conn.reg_info.pL2CA_ConfigInd_Cb        = gap_config_ind;
+    gap_cb.conn.reg_info.pL2CA_ConfigCfm_Cb        = gap_config_cfm;
+    gap_cb.conn.reg_info.pL2CA_DisconnectInd_Cb    = gap_disconnect_ind;
+    gap_cb.conn.reg_info.pL2CA_DisconnectCfm_Cb    = NULL;
+    gap_cb.conn.reg_info.pL2CA_QoSViolationInd_Cb  = NULL;
+    gap_cb.conn.reg_info.pL2CA_DataInd_Cb          = gap_data_ind;
+    gap_cb.conn.reg_info.pL2CA_CongestionStatus_Cb = gap_congestion_ind;
+    gap_cb.conn.reg_info.pL2CA_TxComplete_Cb       = gap_tx_complete_ind;
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function         GAP_ConnOpen
+**
+** Description      This function is called to open an L2CAP connection.
+**
+** Parameters:      is_server   - If true, the connection is not created
+**                                but put into a "listen" mode waiting for
+**                                the remote side to connect.
+**
+**                  service_id  - Unique service ID from
+**                                BTM_SEC_SERVICE_FIRST_EMPTY (6)
+**                                to BTM_SEC_MAX_SERVICE_RECORDS (32)
+**
+**                  p_rem_bda   - Pointer to remote BD Address.
+**                                If a server, and we don't care about the
+**                                remote BD Address, then NULL should be passed.
+**
+**                  psm         - the PSM used for the connection
+**
+**                  p_config    - Optional pointer to configuration structure.
+**                                If NULL, the default GAP configuration will
+**                                be used.
+**
+**                  security    - security flags
+**                  chan_mode_mask - (GAP_FCR_CHAN_OPT_BASIC, GAP_FCR_CHAN_OPT_ERTM,
+**                                    GAP_FCR_CHAN_OPT_STREAM)
+**
+**                  p_cb        - Pointer to callback function for events.
+**
+** Returns          handle of the connection if successful, else GAP_INVALID_HANDLE
+**
+*******************************************************************************/
+uint16_t GAP_ConnOpen(const char *p_serv_name, uint8_t service_id, bool is_server,
+                     BD_ADDR p_rem_bda, uint16_t psm, tL2CAP_CFG_INFO *p_cfg,
+                     tL2CAP_ERTM_INFO *ertm_info, uint16_t security, uint8_t chan_mode_mask,
+                     tGAP_CONN_CALLBACK *p_cb, tBT_TRANSPORT transport)
+{
+    tGAP_CCB    *p_ccb;
+    uint16_t     cid;
+
+    GAP_TRACE_EVENT ("GAP_CONN - Open Request");
+
+    /* Allocate a new CCB. Return if none available. */
+    if ((p_ccb = gap_allocate_ccb()) == NULL)
+        return (GAP_INVALID_HANDLE);
+
+    /* update the transport */
+    p_ccb->transport = transport;
+
+    /* If caller specified a BD address, save it */
+    if (p_rem_bda)
+    {
+        /* the bd addr is not BT_BD_ANY, then a bd address was specified */
+        if (memcmp (p_rem_bda, BT_BD_ANY, BD_ADDR_LEN))
+            p_ccb->rem_addr_specified = true;
+
+        memcpy (&p_ccb->rem_dev_address[0], p_rem_bda, BD_ADDR_LEN);
+    }
+    else if (!is_server)
+    {
+        /* remore addr is not specified and is not a server -> bad */
+        return (GAP_INVALID_HANDLE);
+    }
+
+    /* A client MUST have specified a bd addr to connect with */
+    if (!p_ccb->rem_addr_specified && !is_server)
+    {
+        gap_release_ccb (p_ccb);
+        GAP_TRACE_ERROR ("GAP ERROR: Client must specify a remote BD ADDR to connect to!");
+        return (GAP_INVALID_HANDLE);
+    }
+
+    /* Check if configuration was specified */
+    if (p_cfg)
+        p_ccb->cfg = *p_cfg;
+
+    /* Configure L2CAP COC, if transport is LE */
+    if (transport == BT_TRANSPORT_LE)
+    {
+        p_ccb->local_coc_cfg.credits = L2CAP_LE_DEFAULT_CREDIT;
+        p_ccb->local_coc_cfg.mtu = p_cfg->mtu;
+        p_ccb->local_coc_cfg.mps = L2CAP_LE_DEFAULT_MPS;
+    }
+
+    p_ccb->p_callback     = p_cb;
+
+    /* If originator, use a dynamic PSM */
+#if (AMP_INCLUDED == TRUE)
+    if (!is_server)
+        gap_cb.conn.reg_info.pAMP_ConnectInd_Cb  = NULL;
+    else
+        gap_cb.conn.reg_info.pAMP_ConnectInd_Cb  = gap_connect_ind;
+#else
+    if (!is_server)
+        gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = NULL;
+    else
+        gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = gap_connect_ind;
+#endif
+
+    /* Register the PSM with L2CAP */
+    if (transport == BT_TRANSPORT_BR_EDR)
+    {
+        p_ccb->psm = L2CA_REGISTER (psm, &gap_cb.conn.reg_info,
+                    AMP_AUTOSWITCH_ALLOWED|AMP_USE_AMP_IF_POSSIBLE);
+        if (p_ccb->psm == 0)
+        {
+            GAP_TRACE_ERROR ("%s: Failure registering PSM 0x%04x", __func__, psm);
+            gap_release_ccb (p_ccb);
+            return (GAP_INVALID_HANDLE);
+        }
+    }
+
+    if (transport == BT_TRANSPORT_LE)
+    {
+        p_ccb->psm = L2CA_REGISTER_COC (psm, &gap_cb.conn.reg_info,
+                    AMP_AUTOSWITCH_ALLOWED|AMP_USE_AMP_IF_POSSIBLE);
+        if (p_ccb->psm == 0)
+        {
+            GAP_TRACE_ERROR ("%s: Failure registering PSM 0x%04x", __func__, psm);
+            gap_release_ccb (p_ccb);
+            return (GAP_INVALID_HANDLE);
+        }
+    }
+
+    /* Register with Security Manager for the specific security level */
+    p_ccb->service_id = service_id;
+    if (!BTM_SetSecurityLevel ((uint8_t)!is_server, p_serv_name,
+                p_ccb->service_id, security, p_ccb->psm, 0, 0))
+    {
+        GAP_TRACE_ERROR ("GAP_CONN - Security Error");
+        gap_release_ccb (p_ccb);
+        return (GAP_INVALID_HANDLE);
+    }
+
+    /* Fill in eL2CAP parameter data */
+    if( p_ccb->cfg.fcr_present )
+    {
+        if(ertm_info == NULL) {
+            p_ccb->ertm_info.preferred_mode = p_ccb->cfg.fcr.mode;
+            p_ccb->ertm_info.user_rx_buf_size = GAP_DATA_BUF_SIZE;
+            p_ccb->ertm_info.user_tx_buf_size = GAP_DATA_BUF_SIZE;
+            p_ccb->ertm_info.fcr_rx_buf_size = L2CAP_INVALID_ERM_BUF_SIZE;
+            p_ccb->ertm_info.fcr_tx_buf_size = L2CAP_INVALID_ERM_BUF_SIZE;
+        } else {
+            p_ccb->ertm_info = *ertm_info;
+        }
+    }
+
+    /* optional FCR channel modes */
+    if(ertm_info != NULL) {
+        p_ccb->ertm_info.allowed_modes =
+            (chan_mode_mask) ? chan_mode_mask : (uint8_t)L2CAP_FCR_CHAN_OPT_BASIC;
+    }
+
+    if (is_server)
+    {
+        p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE; /* assume btm/l2cap would handle it */
+        p_ccb->con_state = GAP_CCB_STATE_LISTENING;
+        return (p_ccb->gap_handle);
+    }
+    else
+    {
+        /* We are the originator of this connection */
+        p_ccb->con_flags = GAP_CCB_FLAGS_IS_ORIG;
+
+        /* Transition to the next appropriate state, waiting for connection confirm. */
+        p_ccb->con_state = GAP_CCB_STATE_CONN_SETUP;
+
+        /* mark security done flag, when security is not required */
+        if ((security & (BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT) ) == 0)
+            p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE;
+
+        /* Check if L2CAP started the connection process */
+        if (p_rem_bda && (transport == BT_TRANSPORT_BR_EDR))
+        {
+            cid = L2CA_CONNECT_REQ (p_ccb->psm, p_rem_bda, &p_ccb->ertm_info);
+            if (cid != 0)
+            {
+                p_ccb->connection_id = cid;
+                return (p_ccb->gap_handle);
+            }
+        }
+
+        if (p_rem_bda && (transport == BT_TRANSPORT_LE))
+        {
+            cid = L2CA_CONNECT_COC_REQ (p_ccb->psm, p_rem_bda, &p_ccb->local_coc_cfg);
+            if (cid != 0)
+            {
+                p_ccb->connection_id = cid;
+                return (p_ccb->gap_handle);
+            }
+        }
+
+        gap_release_ccb (p_ccb);
+        return (GAP_INVALID_HANDLE);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         GAP_ConnClose
+**
+** Description      This function is called to close a connection.
+**
+** Parameters:      handle      - Handle of the connection returned by GAP_ConnOpen
+**
+** Returns          BT_PASS             - closed OK
+**                  GAP_ERR_BAD_HANDLE  - invalid handle
+**
+*******************************************************************************/
+uint16_t GAP_ConnClose (uint16_t gap_handle)
+{
+    tGAP_CCB    *p_ccb = gap_find_ccb_by_handle (gap_handle);
+
+    GAP_TRACE_EVENT ("GAP_CONN - close  handle: 0x%x", gap_handle);
+
+    if (p_ccb)
+    {
+        /* Check if we have a connection ID */
+        if (p_ccb->con_state != GAP_CCB_STATE_LISTENING)
+            L2CA_DISCONNECT_REQ (p_ccb->connection_id);
+
+        gap_release_ccb (p_ccb);
+
+        return (BT_PASS);
+    }
+
+    return (GAP_ERR_BAD_HANDLE);
+}
+
+
+
+/*******************************************************************************
+**
+** Function         GAP_ConnReadData
+**
+** Description      Normally not GKI aware application will call this function
+**                  after receiving GAP_EVT_RXDATA event.
+**
+** Parameters:      handle      - Handle of the connection returned in the Open
+**                  p_data      - Data area
+**                  max_len     - Byte count requested
+**                  p_len       - Byte count received
+**
+** Returns          BT_PASS             - data read
+**                  GAP_ERR_BAD_HANDLE  - invalid handle
+**                  GAP_NO_DATA_AVAIL   - no data available
+**
+*******************************************************************************/
+uint16_t GAP_ConnReadData (uint16_t gap_handle, uint8_t *p_data, uint16_t max_len, uint16_t *p_len)
+{
+    tGAP_CCB    *p_ccb = gap_find_ccb_by_handle (gap_handle);
+    uint16_t    copy_len;
+
+    if (!p_ccb)
+        return (GAP_ERR_BAD_HANDLE);
+
+    *p_len = 0;
+
+    if (fixed_queue_is_empty(p_ccb->rx_queue))
+        return (GAP_NO_DATA_AVAIL);
+
+    mutex_global_lock();
+
+    while (max_len)
+    {
+        BT_HDR *p_buf =
+            static_cast<BT_HDR *>(fixed_queue_try_peek_first(p_ccb->rx_queue));
+        if (p_buf == NULL)
+            break;
+
+        copy_len = (p_buf->len > max_len)?max_len:p_buf->len;
+        max_len -= copy_len;
+        *p_len  += copy_len;
+        if (p_data)
+        {
+            memcpy (p_data, (uint8_t *)(p_buf + 1) + p_buf->offset, copy_len);
+            p_data += copy_len;
+        }
+
+        if (p_buf->len > copy_len)
+        {
+            p_buf->offset += copy_len;
+            p_buf->len    -= copy_len;
+            break;
+        }
+        osi_free(fixed_queue_try_dequeue(p_ccb->rx_queue));
+    }
+
+    p_ccb->rx_queue_size -= *p_len;
+
+    mutex_global_unlock();
+
+    GAP_TRACE_EVENT ("GAP_ConnReadData - rx_queue_size left=%d, *p_len=%d",
+                                       p_ccb->rx_queue_size, *p_len);
+
+    return (BT_PASS);
+}
+
+/*******************************************************************************
+**
+** Function         GAP_GetRxQueueCnt
+**
+** Description      This function return number of bytes on the rx queue.
+**
+** Parameters:      handle     - Handle returned in the GAP_ConnOpen
+**                  p_rx_queue_count - Pointer to return queue count in.
+**
+**
+*******************************************************************************/
+int GAP_GetRxQueueCnt (uint16_t handle, uint32_t *p_rx_queue_count)
+{
+    tGAP_CCB    *p_ccb;
+    int         rc = BT_PASS;
+
+    /* Check that handle is valid */
+    if (handle < GAP_MAX_CONNECTIONS)
+    {
+        p_ccb = &gap_cb.conn.ccb_pool[handle];
+
+        if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED)
+        {
+            *p_rx_queue_count = p_ccb->rx_queue_size;
+        }
+        else
+            rc = GAP_INVALID_HANDLE;
+    }
+    else
+        rc = GAP_INVALID_HANDLE;
+
+    GAP_TRACE_EVENT ("GAP_GetRxQueueCnt - rc = 0x%04x, rx_queue_count=%d",
+                                       rc , *p_rx_queue_count);
+
+    return (rc);
+}
+
+/*******************************************************************************
+**
+** Function         GAP_ConnBTRead
+**
+** Description      Bluetooth aware applications will call this function after receiving
+**                  GAP_EVT_RXDATA event.
+**
+** Parameters:      handle      - Handle of the connection returned in the Open
+**                  pp_buf      - pointer to address of buffer with data,
+**
+** Returns          BT_PASS             - data read
+**                  GAP_ERR_BAD_HANDLE  - invalid handle
+**                  GAP_NO_DATA_AVAIL   - no data available
+**
+*******************************************************************************/
+uint16_t GAP_ConnBTRead (uint16_t gap_handle, BT_HDR **pp_buf)
+{
+    tGAP_CCB    *p_ccb = gap_find_ccb_by_handle (gap_handle);
+    BT_HDR      *p_buf;
+
+    if (!p_ccb)
+        return (GAP_ERR_BAD_HANDLE);
+
+    p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->rx_queue);
+
+    if (p_buf)
+    {
+        *pp_buf = p_buf;
+
+        p_ccb->rx_queue_size -= p_buf->len;
+        return (BT_PASS);
+    }
+    else
+    {
+        *pp_buf = NULL;
+        return (GAP_NO_DATA_AVAIL);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         GAP_ConnWriteData
+**
+** Description      Normally not GKI aware application will call this function
+**                  to send data to the connection.
+**
+** Parameters:      handle      - Handle of the connection returned in the Open
+**                  p_data      - Data area
+**                  max_len     - Byte count requested
+**                  p_len       - Byte count received
+**
+** Returns          BT_PASS                 - data read
+**                  GAP_ERR_BAD_HANDLE      - invalid handle
+**                  GAP_ERR_BAD_STATE       - connection not established
+**                  GAP_CONGESTION          - system is congested
+**
+*******************************************************************************/
+uint16_t GAP_ConnWriteData (uint16_t gap_handle, uint8_t *p_data, uint16_t max_len, uint16_t *p_len)
+{
+    tGAP_CCB    *p_ccb = gap_find_ccb_by_handle (gap_handle);
+    BT_HDR     *p_buf;
+
+    *p_len = 0;
+
+    if (!p_ccb)
+        return (GAP_ERR_BAD_HANDLE);
+
+    if (p_ccb->con_state != GAP_CCB_STATE_CONNECTED)
+        return (GAP_ERR_BAD_STATE);
+
+    while (max_len)
+    {
+        if (p_ccb->cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
+            p_buf = (BT_HDR *)osi_malloc(L2CAP_FCR_ERTM_BUF_SIZE);
+        else
+            p_buf = (BT_HDR *)osi_malloc(GAP_DATA_BUF_SIZE);
+
+        p_buf->offset = L2CAP_MIN_OFFSET;
+        p_buf->len = (p_ccb->rem_mtu_size < max_len) ? p_ccb->rem_mtu_size : max_len;
+        p_buf->event = BT_EVT_TO_BTU_SP_DATA;
+
+        memcpy ((uint8_t *)(p_buf + 1) + p_buf->offset, p_data, p_buf->len);
+
+        *p_len  += p_buf->len;
+        max_len -= p_buf->len;
+        p_data  += p_buf->len;
+
+        GAP_TRACE_EVENT ("GAP_WriteData %d bytes", p_buf->len);
+
+        fixed_queue_enqueue(p_ccb->tx_queue, p_buf);
+    }
+
+    if (p_ccb->is_congested)
+    {
+        return (BT_PASS);
+    }
+
+    /* Send the buffer through L2CAP */
+    while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->tx_queue)) != NULL)
+    {
+        uint8_t status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf);
+
+        if (status == L2CAP_DW_CONGESTED)
+        {
+            p_ccb->is_congested = true;
+            break;
+        }
+        else if (status != L2CAP_DW_SUCCESS)
+            return (GAP_ERR_BAD_STATE);
+    }
+
+    return (BT_PASS);
+}
+
+
+/*******************************************************************************
+**
+** Function         GAP_ConnReconfig
+**
+** Description      Applications can call this function to reconfigure the connection.
+**
+** Parameters:      handle      - Handle of the connection
+**                  p_cfg       - Pointer to new configuration
+**
+** Returns          BT_PASS                 - config process started
+**                  GAP_ERR_BAD_HANDLE      - invalid handle
+**
+*******************************************************************************/
+uint16_t GAP_ConnReconfig (uint16_t gap_handle, tL2CAP_CFG_INFO *p_cfg)
+{
+    tGAP_CCB    *p_ccb = gap_find_ccb_by_handle (gap_handle);
+
+    if (!p_ccb)
+        return (GAP_ERR_BAD_HANDLE);
+
+    p_ccb->cfg = *p_cfg;
+
+    if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED)
+        L2CA_CONFIG_REQ (p_ccb->connection_id, p_cfg);
+
+    return (BT_PASS);
+}
+
+
+
+/*******************************************************************************
+**
+** Function         GAP_ConnSetIdleTimeout
+**
+** 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.
+**
+** Parameters:      handle      - Handle of the connection
+**                  timeout     - in secs
+**                                0 = immediate disconnect when last channel is removed
+**                                0xFFFF = no idle timeout
+**
+** Returns          BT_PASS                 - config process started
+**                  GAP_ERR_BAD_HANDLE      - invalid handle
+**
+*******************************************************************************/
+uint16_t GAP_ConnSetIdleTimeout (uint16_t gap_handle, uint16_t timeout)
+{
+    tGAP_CCB    *p_ccb;
+
+    if ((p_ccb = gap_find_ccb_by_handle (gap_handle)) == NULL)
+        return (GAP_ERR_BAD_HANDLE);
+
+    if (L2CA_SetIdleTimeout (p_ccb->connection_id, timeout, false))
+        return (BT_PASS);
+    else
+        return (GAP_ERR_BAD_HANDLE);
+}
+
+
+
+/*******************************************************************************
+**
+** Function         GAP_ConnGetRemoteAddr
+**
+** Description      This function is called to get the remote BD address
+**                  of a connection.
+**
+** Parameters:      handle      - Handle of the connection returned by GAP_ConnOpen
+**
+** Returns          BT_PASS             - closed OK
+**                  GAP_ERR_BAD_HANDLE  - invalid handle
+**
+*******************************************************************************/
+uint8_t *GAP_ConnGetRemoteAddr (uint16_t gap_handle)
+{
+    tGAP_CCB    *p_ccb = gap_find_ccb_by_handle (gap_handle);
+
+    GAP_TRACE_EVENT ("GAP_ConnGetRemoteAddr gap_handle = %d", gap_handle);
+
+    if ((p_ccb) && (p_ccb->con_state > GAP_CCB_STATE_LISTENING))
+    {
+        GAP_TRACE_EVENT("GAP_ConnGetRemoteAddr bda :0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", \
+                         p_ccb->rem_dev_address[0],p_ccb->rem_dev_address[1],p_ccb->rem_dev_address[2],
+                         p_ccb->rem_dev_address[3],p_ccb->rem_dev_address[4],p_ccb->rem_dev_address[5]);
+        return (p_ccb->rem_dev_address);
+    }
+    else
+    {
+        GAP_TRACE_EVENT ("GAP_ConnGetRemoteAddr return Error ");
+        return (NULL);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         GAP_ConnGetRemMtuSize
+**
+** Description      Returns the remote device's MTU size
+**
+** Parameters:      handle      - Handle of the connection
+**
+** Returns          uint16_t    - maximum size buffer that can be transmitted to the peer
+**
+*******************************************************************************/
+uint16_t GAP_ConnGetRemMtuSize (uint16_t gap_handle)
+{
+    tGAP_CCB    *p_ccb;
+
+    if ((p_ccb = gap_find_ccb_by_handle (gap_handle)) == NULL)
+        return (0);
+
+    return (p_ccb->rem_mtu_size);
+}
+
+/*******************************************************************************
+**
+** Function         GAP_ConnGetL2CAPCid
+**
+** Description      Returns the L2CAP channel id
+**
+** Parameters:      handle      - Handle of the connection
+**
+** Returns          uint16_t    - The L2CAP channel id
+**                  0, if error
+**
+*******************************************************************************/
+uint16_t GAP_ConnGetL2CAPCid (uint16_t gap_handle)
+{
+    tGAP_CCB    *p_ccb;
+
+    if ((p_ccb = gap_find_ccb_by_handle (gap_handle)) == NULL)
+        return (0);
+
+    return (p_ccb->connection_id);
+}
+
+/*******************************************************************************
+**
+** Function         gap_tx_connect_ind
+**
+** Description      Sends out GAP_EVT_TX_EMPTY when transmission has been
+**                  completed.
+**
+** Returns          void
+**
+*******************************************************************************/
+void gap_tx_complete_ind (uint16_t l2cap_cid, uint16_t sdu_sent)
+{
+    tGAP_CCB *p_ccb = gap_find_ccb_by_cid (l2cap_cid);
+    if (p_ccb == NULL)
+        return;
+
+    if ((p_ccb->con_state == GAP_CCB_STATE_CONNECTED) && (sdu_sent == 0xFFFF))
+    {
+        GAP_TRACE_EVENT("%s: GAP_EVT_TX_EMPTY", __func__);
+        p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_TX_EMPTY);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gap_connect_ind
+**
+** Description      This function handles an inbound connection indication
+**                  from L2CAP. This is the case where we are acting as a
+**                  server.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gap_connect_ind (BD_ADDR  bd_addr, uint16_t l2cap_cid, uint16_t psm, uint8_t l2cap_id)
+{
+    uint16_t     xx;
+    tGAP_CCB     *p_ccb;
+
+    /* See if we have a CCB listening for the connection */
+    for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++)
+    {
+        if ((p_ccb->con_state == GAP_CCB_STATE_LISTENING)
+         && (p_ccb->psm == psm)
+         && ((p_ccb->rem_addr_specified == false)
+           || (!memcmp (bd_addr, p_ccb->rem_dev_address, BD_ADDR_LEN))))
+            break;
+    }
+
+    if (xx == GAP_MAX_CONNECTIONS)
+    {
+        GAP_TRACE_WARNING("*******");
+        GAP_TRACE_WARNING("WARNING: GAP Conn Indication for Unexpected Bd Addr...Disconnecting");
+        GAP_TRACE_WARNING("*******");
+
+        /* Disconnect because it is an unexpected connection */
+        L2CA_DISCONNECT_REQ (l2cap_cid);
+        return;
+    }
+
+    /* Transition to the next appropriate state, waiting for config setup. */
+    if (p_ccb->transport == BT_TRANSPORT_BR_EDR)
+        p_ccb->con_state = GAP_CCB_STATE_CFG_SETUP;
+
+    /* Save the BD Address and Channel ID. */
+    memcpy (&p_ccb->rem_dev_address[0], bd_addr, BD_ADDR_LEN);
+    p_ccb->connection_id = l2cap_cid;
+
+    /* Send response to the L2CAP layer. */
+    if (p_ccb->transport == BT_TRANSPORT_BR_EDR)
+        L2CA_CONNECT_RSP (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK, &p_ccb->ertm_info);
+
+    if (p_ccb->transport == BT_TRANSPORT_LE)
+    {
+        L2CA_CONNECT_COC_RSP (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK, &p_ccb->local_coc_cfg);
+
+        /* get the remote coc configuration */
+        L2CA_GET_PEER_COC_CONFIG(l2cap_cid, &p_ccb->peer_coc_cfg);
+        p_ccb->rem_mtu_size = p_ccb->peer_coc_cfg.mtu;
+
+        /* configuration is not required for LE COC */
+        p_ccb->con_flags |= GAP_CCB_FLAGS_HIS_CFG_DONE;
+        p_ccb->con_flags |= GAP_CCB_FLAGS_MY_CFG_DONE;
+        gap_checks_con_flags (p_ccb);
+    }
+
+    GAP_TRACE_EVENT("GAP_CONN - Rcvd L2CAP conn ind, CID: 0x%x", p_ccb->connection_id);
+
+    /* Send a Configuration Request. */
+    if (p_ccb->transport == BT_TRANSPORT_BR_EDR)
+        L2CA_CONFIG_REQ (l2cap_cid, &p_ccb->cfg);
+}
+
+/*******************************************************************************
+**
+** Function         gap_checks_con_flags
+**
+** Description      This function processes the L2CAP configuration indication
+**                  event.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gap_checks_con_flags (tGAP_CCB    *p_ccb)
+{
+    GAP_TRACE_EVENT ("gap_checks_con_flags conn_flags:0x%x, ", p_ccb->con_flags);
+    /* if all the required con_flags are set, report the OPEN event now */
+    if ((p_ccb->con_flags & GAP_CCB_FLAGS_CONN_DONE) == GAP_CCB_FLAGS_CONN_DONE)
+    {
+        p_ccb->con_state = GAP_CCB_STATE_CONNECTED;
+
+        p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_OPENED);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gap_sec_check_complete
+**
+** Description      The function called when Security Manager finishes
+**                  verification of the service side connection
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gap_sec_check_complete (UNUSED_ATTR BD_ADDR bd_addr, UNUSED_ATTR tBT_TRANSPORT transport, void *p_ref_data,
+                                    uint8_t res)
+{
+    tGAP_CCB *p_ccb = (tGAP_CCB *)p_ref_data;
+
+    GAP_TRACE_EVENT ("gap_sec_check_complete conn_state:%d, conn_flags:0x%x, status:%d",
+        p_ccb->con_state, p_ccb->con_flags, res);
+    if (p_ccb->con_state == GAP_CCB_STATE_IDLE)
+        return;
+
+    if (res == BTM_SUCCESS)
+    {
+        p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE;
+        gap_checks_con_flags (p_ccb);
+    }
+    else
+    {
+        /* security failed - disconnect the channel */
+        L2CA_DISCONNECT_REQ (p_ccb->connection_id);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gap_connect_cfm
+**
+** Description      This function handles the connect confirm events
+**                  from L2CAP. This is the case when we are acting as a
+**                  client and have sent a connect request.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gap_connect_cfm (uint16_t l2cap_cid, uint16_t result)
+{
+    tGAP_CCB    *p_ccb;
+
+    /* Find CCB based on CID */
+    if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL)
+        return;
+
+    /* initiate security process, if needed */
+    if ( (p_ccb->con_flags & GAP_CCB_FLAGS_SEC_DONE) == 0 && p_ccb->transport != BT_TRANSPORT_LE)
+    {
+        btm_sec_mx_access_request (p_ccb->rem_dev_address, p_ccb->psm, true,
+                                   0, 0, &gap_sec_check_complete, p_ccb);
+    }
+
+    /* If the connection response contains success status, then */
+    /* Transition to the next state and startup the timer.      */
+    if ((result == L2CAP_CONN_OK) && (p_ccb->con_state == GAP_CCB_STATE_CONN_SETUP))
+    {
+        if (p_ccb->transport == BT_TRANSPORT_BR_EDR)
+        {
+            p_ccb->con_state = GAP_CCB_STATE_CFG_SETUP;
+
+            /* Send a Configuration Request. */
+            L2CA_CONFIG_REQ (l2cap_cid, &p_ccb->cfg);
+        }
+
+        if (p_ccb->transport == BT_TRANSPORT_LE)
+        {
+            /* get the remote coc configuration */
+            L2CA_GET_PEER_COC_CONFIG(l2cap_cid, &p_ccb->peer_coc_cfg);
+            p_ccb->rem_mtu_size = p_ccb->peer_coc_cfg.mtu;
+
+            /* configuration is not required for LE COC */
+            p_ccb->con_flags |= GAP_CCB_FLAGS_HIS_CFG_DONE;
+            p_ccb->con_flags |= GAP_CCB_FLAGS_MY_CFG_DONE;
+            p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE;
+            gap_checks_con_flags (p_ccb);
+        }
+    }
+    else
+    {
+        /* Tell the user if he has a callback */
+        if (p_ccb->p_callback)
+            (*p_ccb->p_callback) (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
+
+        gap_release_ccb (p_ccb);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gap_config_ind
+**
+** Description      This function processes the L2CAP configuration indication
+**                  event.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gap_config_ind (uint16_t l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+    tGAP_CCB    *p_ccb;
+    uint16_t    local_mtu_size;
+
+    /* Find CCB based on CID */
+    if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL)
+        return;
+
+    /* Remember the remote MTU size */
+
+    if (p_ccb->cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
+    {
+        local_mtu_size = p_ccb->ertm_info.user_tx_buf_size
+                       - sizeof(BT_HDR) - L2CAP_MIN_OFFSET;
+    }
+    else
+        local_mtu_size = L2CAP_MTU_SIZE;
+
+    if ((!p_cfg->mtu_present)||(p_cfg->mtu > local_mtu_size))
+    {
+        p_ccb->rem_mtu_size = local_mtu_size;
+    }
+    else
+        p_ccb->rem_mtu_size = p_cfg->mtu;
+
+    /* For now, always accept configuration from the other side */
+    p_cfg->flush_to_present = false;
+    p_cfg->mtu_present      = false;
+    p_cfg->result           = L2CAP_CFG_OK;
+    p_cfg->fcs_present      = false;
+
+    L2CA_CONFIG_RSP (l2cap_cid, p_cfg);
+
+    p_ccb->con_flags |= GAP_CCB_FLAGS_HIS_CFG_DONE;
+
+    gap_checks_con_flags (p_ccb);
+}
+
+
+/*******************************************************************************
+**
+** Function         gap_config_cfm
+**
+** Description      This function processes the L2CAP configuration confirmation
+**                  event.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gap_config_cfm (uint16_t l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+    tGAP_CCB    *p_ccb;
+
+    /* Find CCB based on CID */
+    if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL)
+        return;
+
+    if (p_cfg->result == L2CAP_CFG_OK)
+    {
+        p_ccb->con_flags |= GAP_CCB_FLAGS_MY_CFG_DONE;
+
+
+        if (p_ccb->cfg.fcr_present)
+            p_ccb->cfg.fcr.mode = p_cfg->fcr.mode;
+        else
+            p_ccb->cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+
+        gap_checks_con_flags (p_ccb);
+    }
+    else
+    {
+        p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
+        gap_release_ccb (p_ccb);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         gap_disconnect_ind
+**
+** Description      This function handles a disconnect event from L2CAP. If
+**                  requested to, we ack the disconnect before dropping the CCB
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gap_disconnect_ind (uint16_t l2cap_cid, bool    ack_needed)
+{
+    tGAP_CCB    *p_ccb;
+
+    GAP_TRACE_EVENT ("GAP_CONN - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
+
+    /* Find CCB based on CID */
+    if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL)
+        return;
+
+    if (ack_needed)
+        L2CA_DISCONNECT_RSP (l2cap_cid);
+
+    p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
+    gap_release_ccb (p_ccb);
+}
+
+
+/*******************************************************************************
+**
+** Function         gap_data_ind
+**
+** Description      This function is called when data is received from L2CAP.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gap_data_ind (uint16_t l2cap_cid, BT_HDR *p_msg)
+{
+    tGAP_CCB    *p_ccb;
+
+    /* Find CCB based on CID */
+    if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL)
+    {
+        osi_free(p_msg);
+        return;
+    }
+
+    if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED)
+    {
+        fixed_queue_enqueue(p_ccb->rx_queue, p_msg);
+
+        p_ccb->rx_queue_size += p_msg->len;
+        /*
+        GAP_TRACE_EVENT ("gap_data_ind - rx_queue_size=%d, msg len=%d",
+                                       p_ccb->rx_queue_size, p_msg->len);
+         */
+
+        p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_DATA_AVAIL);
+    }
+    else
+    {
+        osi_free(p_msg);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         gap_congestion_ind
+**
+** Description      This is a callback function called by L2CAP when
+**                  data L2CAP congestion status changes
+**
+*******************************************************************************/
+static void gap_congestion_ind (uint16_t lcid, bool    is_congested)
+{
+    tGAP_CCB    *p_ccb;
+    uint16_t     event;
+    BT_HDR      *p_buf;
+    uint8_t      status;
+
+    GAP_TRACE_EVENT ("GAP_CONN - Rcvd L2CAP Is Congested (%d), CID: 0x%x",
+                      is_congested, lcid);
+
+    /* Find CCB based on CID */
+    if ((p_ccb = gap_find_ccb_by_cid (lcid)) == NULL)
+        return;
+
+    p_ccb->is_congested = is_congested;
+
+    event = (is_congested) ? GAP_EVT_CONN_CONGESTED : GAP_EVT_CONN_UNCONGESTED;
+    p_ccb->p_callback (p_ccb->gap_handle, event);
+
+    if (!is_congested)
+    {
+        while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->tx_queue)) != NULL)
+        {
+            status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf);
+
+            if (status == L2CAP_DW_CONGESTED)
+            {
+                p_ccb->is_congested = true;
+                break;
+            }
+            else if (status != L2CAP_DW_SUCCESS)
+                break;
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         gap_find_ccb_by_cid
+**
+** Description      This function searches the CCB table for an entry with the
+**                  passed CID.
+**
+** Returns          the CCB address, or NULL if not found.
+**
+*******************************************************************************/
+static tGAP_CCB *gap_find_ccb_by_cid (uint16_t cid)
+{
+    uint16_t     xx;
+    tGAP_CCB     *p_ccb;
+
+    /* Look through each connection control block */
+    for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++)
+    {
+        if ((p_ccb->con_state != GAP_CCB_STATE_IDLE) && (p_ccb->connection_id == cid))
+            return (p_ccb);
+    }
+
+    /* If here, not found */
+    return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         gap_find_ccb_by_handle
+**
+** Description      This function searches the CCB table for an entry with the
+**                  passed handle.
+**
+** Returns          the CCB address, or NULL if not found.
+**
+*******************************************************************************/
+static tGAP_CCB *gap_find_ccb_by_handle (uint16_t handle)
+{
+    tGAP_CCB     *p_ccb;
+
+    /* Check that handle is valid */
+    if (handle < GAP_MAX_CONNECTIONS)
+    {
+        p_ccb = &gap_cb.conn.ccb_pool[handle];
+
+        if (p_ccb->con_state != GAP_CCB_STATE_IDLE)
+            return (p_ccb);
+    }
+
+    /* If here, handle points to invalid connection */
+    return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         gap_allocate_ccb
+**
+** Description      This function allocates a new CCB.
+**
+** Returns          CCB address, or NULL if none available.
+**
+*******************************************************************************/
+static tGAP_CCB *gap_allocate_ccb (void)
+{
+    uint16_t     xx;
+    tGAP_CCB     *p_ccb;
+
+    /* Look through each connection control block for a free one */
+    for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++)
+    {
+        if (p_ccb->con_state == GAP_CCB_STATE_IDLE)
+        {
+            memset (p_ccb, 0, sizeof (tGAP_CCB));
+            p_ccb->tx_queue = fixed_queue_new(SIZE_MAX);
+            p_ccb->rx_queue = fixed_queue_new(SIZE_MAX);
+
+            p_ccb->gap_handle   = xx;
+            p_ccb->rem_mtu_size = L2CAP_MTU_SIZE;
+
+            return (p_ccb);
+        }
+    }
+
+    /* If here, no free CCB found */
+    return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         gap_release_ccb
+**
+** Description      This function releases a CCB.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gap_release_ccb (tGAP_CCB *p_ccb)
+{
+    uint16_t     xx;
+    uint16_t    psm = p_ccb->psm;
+    uint8_t     service_id = p_ccb->service_id;
+
+    /* Drop any buffers we may be holding */
+    p_ccb->rx_queue_size = 0;
+
+    while (!fixed_queue_is_empty(p_ccb->rx_queue))
+        osi_free(fixed_queue_try_dequeue(p_ccb->rx_queue));
+    fixed_queue_free(p_ccb->rx_queue, NULL);
+    p_ccb->rx_queue = NULL;
+
+    while (!fixed_queue_is_empty(p_ccb->tx_queue))
+        osi_free(fixed_queue_try_dequeue(p_ccb->tx_queue));
+    fixed_queue_free(p_ccb->tx_queue, NULL);
+    p_ccb->tx_queue = NULL;
+
+    p_ccb->con_state = GAP_CCB_STATE_IDLE;
+
+    /* If no-one else is using the PSM, deregister from L2CAP */
+    for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++)
+    {
+        if ((p_ccb->con_state != GAP_CCB_STATE_IDLE) && (p_ccb->psm == psm))
+            return;
+    }
+
+    /* Free the security record for this PSM */
+    BTM_SecClrService(service_id);
+    if (p_ccb->transport == BT_TRANSPORT_BR_EDR)
+        L2CA_DEREGISTER (psm);
+
+    if(p_ccb->transport == BT_TRANSPORT_LE)
+        L2CA_DEREGISTER_COC (psm);
+}
+
+#endif  /* GAP_CONN_INCLUDED */
diff --git a/bt/stack/gap/gap_int.h b/bt/stack/gap/gap_int.h
new file mode 100644
index 0000000..4d34db0
--- /dev/null
+++ b/bt/stack/gap/gap_int.h
@@ -0,0 +1,166 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+
+
+#ifndef GAP_INT_H
+#define GAP_INT_H
+
+#include "bt_target.h"
+#include "osi/include/fixed_queue.h"
+#include "gap_api.h"
+#include "bt_common.h"
+#include "gatt_api.h"
+#define GAP_MAX_BLOCKS 2        /* Concurrent GAP commands pending at a time*/
+/* Define the Generic Access Profile control structure */
+typedef struct
+{
+    void          *p_data;      /* Pointer to any data returned in callback */
+    tGAP_CALLBACK *gap_cback;   /* Pointer to users callback function */
+    tGAP_CALLBACK *gap_inq_rslt_cback; /* Used for inquiry results */
+    uint16_t       event;       /* Passed back in the callback */
+    uint8_t        index;       /* Index of this control block and callback */
+    bool           in_use;      /* True when structure is allocated */
+} tGAP_INFO;
+
+/* Define the control block for the FindAddrByName operation (Only 1 active at a time) */
+typedef struct
+{
+    tGAP_CALLBACK           *p_cback;
+    tBTM_INQ_INFO           *p_cur_inq; /* Pointer to the current inquiry database entry */
+    tGAP_FINDADDR_RESULTS    results;
+    bool                     in_use;
+} tGAP_FINDADDR_CB;
+
+/* Define the GAP Connection Control Block.
+*/
+typedef struct
+{
+#define GAP_CCB_STATE_IDLE              0
+#define GAP_CCB_STATE_LISTENING         1
+#define GAP_CCB_STATE_CONN_SETUP        2
+#define GAP_CCB_STATE_CFG_SETUP         3
+#define GAP_CCB_STATE_WAIT_SEC          4
+#define GAP_CCB_STATE_CONNECTED         5
+    uint8_t           con_state;
+
+#define GAP_CCB_FLAGS_IS_ORIG           0x01
+#define GAP_CCB_FLAGS_HIS_CFG_DONE      0x02
+#define GAP_CCB_FLAGS_MY_CFG_DONE       0x04
+#define GAP_CCB_FLAGS_SEC_DONE          0x08
+#define GAP_CCB_FLAGS_CONN_DONE         0x0E
+    uint8_t           con_flags;
+
+    uint8_t           service_id;           /* Used by BTM                          */
+    uint16_t          gap_handle;           /* GAP handle                           */
+    uint16_t          connection_id;        /* L2CAP CID                            */
+    bool              rem_addr_specified;
+    uint8_t           chan_mode_mask;       /* Supported channel modes (FCR)        */
+    BD_ADDR           rem_dev_address;
+    uint16_t          psm;
+    uint16_t          rem_mtu_size;
+
+    bool              is_congested;
+    fixed_queue_t     *tx_queue;            /* Queue of buffers waiting to be sent  */
+    fixed_queue_t     *rx_queue;            /* Queue of buffers waiting to be read  */
+
+    uint32_t          rx_queue_size;        /* Total data count in rx_queue         */
+
+    tGAP_CONN_CALLBACK *p_callback;         /* Users callback function              */
+
+    tL2CAP_CFG_INFO   cfg;                  /* Configuration                        */
+    tL2CAP_ERTM_INFO  ertm_info;            /* Pools and modes for ertm */
+    tBT_TRANSPORT     transport;            /* Transport channel BR/EDR or BLE */
+    tL2CAP_LE_CFG_INFO local_coc_cfg;       /* local configuration for LE Coc */
+    tL2CAP_LE_CFG_INFO peer_coc_cfg;        /* local configuration for LE Coc */
+} tGAP_CCB;
+
+typedef struct
+{
+#if (AMP_INCLUDED == TRUE)
+    tAMP_APPL_INFO    reg_info;
+#else
+    tL2CAP_APPL_INFO  reg_info;                     /* L2CAP Registration info */
+#endif
+    tGAP_CCB    ccb_pool[GAP_MAX_CONNECTIONS];
+} tGAP_CONN;
+
+
+#if (BLE_INCLUDED == TRUE)
+#define GAP_MAX_CHAR_NUM          4
+
+typedef struct
+{
+    uint16_t                handle;
+    uint16_t                uuid;
+    tGAP_BLE_ATTR_VALUE     attr_value;
+}tGAP_ATTR;
+#endif
+/**********************************************************************
+** M A I N   C O N T R O L   B L O C K
+***********************************************************************/
+
+#define GAP_MAX_CL GATT_CL_MAX_LCB
+
+typedef struct
+{
+    uint16_t uuid;
+    tGAP_BLE_CMPL_CBACK *p_cback;
+} tGAP_BLE_REQ;
+
+typedef struct
+{
+    BD_ADDR                 bda;
+    tGAP_BLE_CMPL_CBACK     *p_cback;
+    uint16_t                conn_id;
+    uint16_t                cl_op_uuid;
+    bool                    in_use;
+    bool                    connected;
+    fixed_queue_t           *pending_req_q;
+
+}tGAP_CLCB;
+
+typedef struct
+{
+    tGAP_INFO        blk[GAP_MAX_BLOCKS];
+    tBTM_CMPL_CB    *btm_cback[GAP_MAX_BLOCKS];
+    uint8_t          trace_level;
+    tGAP_FINDADDR_CB findaddr_cb;   /* Contains the control block for finding a device addr */
+    tBTM_INQ_INFO   *cur_inqptr;
+
+#if (GAP_CONN_INCLUDED == TRUE)
+    tGAP_CONN        conn;
+#endif
+
+    /* LE GAP attribute database */
+#if (BLE_INCLUDED == TRUE)
+    tGAP_ATTR               gatt_attr[GAP_MAX_CHAR_NUM];
+    tGAP_CLCB               clcb[GAP_MAX_CL]; /* connection link*/
+    tGATT_IF                gatt_if;
+#endif
+} tGAP_CB;
+
+
+extern tGAP_CB  gap_cb;
+#if (GAP_CONN_INCLUDED == TRUE)
+    extern void gap_conn_init(void);
+#endif
+#if (BLE_INCLUDED == TRUE)
+    extern void gap_attr_db_init(void);
+#endif
+
+#endif
diff --git a/bt/stack/gap/gap_utils.cc b/bt/stack/gap/gap_utils.cc
new file mode 100644
index 0000000..afdcf65
--- /dev/null
+++ b/bt/stack/gap/gap_utils.cc
@@ -0,0 +1,142 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "gap_int.h"
+
+/*******************************************************************************
+**
+** Function         gap_allocate_cb
+**
+** Description      Look through the GAP Control Blocks for a free one.
+**
+** Returns          Pointer to the control block or NULL if not found
+**
+*******************************************************************************/
+tGAP_INFO *gap_allocate_cb (void)
+{
+    tGAP_INFO     *p_cb = &gap_cb.blk[0];
+    uint8_t      x;
+
+    for (x = 0; x < GAP_MAX_BLOCKS; x++, p_cb++)
+    {
+        if (!p_cb->in_use)
+        {
+            memset (p_cb, 0, sizeof (tGAP_INFO));
+
+            p_cb->in_use = true;
+            p_cb->index = x;
+            p_cb->p_data = (void *)NULL;
+            return (p_cb);
+        }
+    }
+
+    /* If here, no free control blocks found */
+    return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         gap_free_cb
+**
+** Description      Release GAP control block.
+**
+** Returns          Pointer to the control block or NULL if not found
+**
+*******************************************************************************/
+void gap_free_cb (tGAP_INFO *p_cb)
+{
+    if (p_cb)
+    {
+        p_cb->gap_cback = NULL;
+        p_cb->in_use = false;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         gap_is_service_busy
+**
+** Description      Look through the GAP Control Blocks that are in use
+**                  and check to see if the event waiting for is the command
+**                  requested.
+**
+** Returns          true if already in use
+**                  false if not busy
+**
+*******************************************************************************/
+bool    gap_is_service_busy (uint16_t request)
+{
+    tGAP_INFO   *p_cb = &gap_cb.blk[0];
+    uint8_t      x;
+
+    for (x = 0; x < GAP_MAX_BLOCKS; x++, p_cb++)
+    {
+        if (p_cb->in_use && p_cb->event == request)
+            return (true);
+    }
+
+    /* If here, service is not busy */
+    return (false);
+}
+
+
+/*******************************************************************************
+**
+** Function         gap_convert_btm_status
+**
+** Description      Converts a BTM error status into a GAP error status
+**
+**
+** Returns          GAP_UNKNOWN_BTM_STATUS is returned if not recognized
+**
+*******************************************************************************/
+uint16_t gap_convert_btm_status (tBTM_STATUS btm_status)
+{
+    switch (btm_status)
+    {
+    case BTM_SUCCESS:
+        return (BT_PASS);
+
+    case BTM_CMD_STARTED:
+        return (GAP_CMD_INITIATED);
+
+    case BTM_BUSY:
+        return (GAP_ERR_BUSY);
+
+    case BTM_MODE_UNSUPPORTED:
+    case BTM_ILLEGAL_VALUE:
+        return (GAP_ERR_ILL_PARM);
+
+    case BTM_WRONG_MODE:
+        return (GAP_DEVICE_NOT_UP);
+
+    case BTM_UNKNOWN_ADDR:
+        return (GAP_BAD_BD_ADDR);
+
+    case BTM_DEVICE_TIMEOUT:
+        return (GAP_ERR_TIMEOUT);
+
+    default:
+        return (GAP_ERR_PROCESSING);
+    }
+}
diff --git a/bt/stack/gatt/att_protocol.cc b/bt/stack/gatt/att_protocol.cc
new file mode 100644
index 0000000..bef0982
--- /dev/null
+++ b/bt/stack/gatt/att_protocol.cc
@@ -0,0 +1,606 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2008-2014 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 ATT protocol functions
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+#include "gatt_int.h"
+#include "l2c_api.h"
+
+#define GATT_HDR_FIND_TYPE_VALUE_LEN    21
+#define GATT_OP_CODE_SIZE   1
+#define GATT_START_END_HANDLE_SIZE    4
+
+/**********************************************************************
+**   ATT protocl message building utility                              *
+***********************************************************************/
+/*******************************************************************************
+**
+** Function         attp_build_mtu_exec_cmd
+**
+** Description      Build a exchange MTU request
+**
+** Returns          None.
+**
+*******************************************************************************/
+BT_HDR *attp_build_mtu_cmd(uint8_t op_code, uint16_t rx_mtu)
+{
+    uint8_t *p;
+    BT_HDR *p_buf =
+        (BT_HDR *)osi_malloc(sizeof(BT_HDR) + GATT_HDR_SIZE + L2CAP_MIN_OFFSET);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+    UINT8_TO_STREAM(p, op_code);
+    UINT16_TO_STREAM(p, rx_mtu);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_buf->len = GATT_HDR_SIZE; /* opcode + 2 bytes mtu */
+
+    return p_buf;
+}
+/*******************************************************************************
+**
+** Function         attp_build_exec_write_cmd
+**
+** Description      Build a execute write request or response.
+**
+** Returns          None.
+**
+*******************************************************************************/
+BT_HDR *attp_build_exec_write_cmd (uint8_t op_code, uint8_t flag)
+{
+    BT_HDR      *p_buf = (BT_HDR *)osi_malloc(GATT_DATA_BUF_SIZE);
+    uint8_t     *p;
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_buf->len = GATT_OP_CODE_SIZE;
+
+    UINT8_TO_STREAM(p, op_code);
+
+    if (op_code == GATT_REQ_EXEC_WRITE) {
+        flag &= GATT_PREP_WRITE_EXEC;
+        UINT8_TO_STREAM (p, flag);
+        p_buf->len += 1;
+    }
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function         attp_build_err_cmd
+**
+** Description      Build a exchange MTU request
+**
+** Returns          None.
+**
+*******************************************************************************/
+BT_HDR *attp_build_err_cmd(uint8_t cmd_code, uint16_t err_handle, uint8_t reason)
+{
+    uint8_t *p;
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + 5);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+    UINT8_TO_STREAM(p, GATT_RSP_ERROR);
+    UINT8_TO_STREAM(p, cmd_code);
+    UINT16_TO_STREAM(p, err_handle);
+    UINT8_TO_STREAM(p, reason);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    /* GATT_HDR_SIZE (1B ERR_RSP op code+ 2B handle) + 1B cmd_op_code  + 1B status */
+    p_buf->len = GATT_HDR_SIZE + 1 + 1;
+
+    return p_buf;
+}
+/*******************************************************************************
+**
+** Function         attp_build_browse_cmd
+**
+** Description      Build a read information request or read by type request
+**
+** Returns          None.
+**
+*******************************************************************************/
+BT_HDR *attp_build_browse_cmd(uint8_t op_code, uint16_t s_hdl, uint16_t e_hdl, tBT_UUID uuid)
+{
+    const size_t payload_size = (GATT_OP_CODE_SIZE) + (GATT_START_END_HANDLE_SIZE) + (LEN_UUID_128);
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET);
+
+    uint8_t *p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+    /* Describe the built message location and size */
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_buf->len = GATT_OP_CODE_SIZE + 4;
+
+    UINT8_TO_STREAM(p, op_code);
+    UINT16_TO_STREAM(p, s_hdl);
+    UINT16_TO_STREAM(p, e_hdl);
+    p_buf->len += gatt_build_uuid_to_stream(&p, uuid);
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function         attp_build_read_handles_cmd
+**
+** Description      Build a read by type and value request.
+**
+** Returns          pointer to the command buffer.
+**
+*******************************************************************************/
+BT_HDR *attp_build_read_by_type_value_cmd (uint16_t payload_size, tGATT_FIND_TYPE_VALUE *p_value_type)
+{
+    uint8_t *p;
+    uint16_t len = p_value_type->value_len;
+    BT_HDR *p_buf =
+        (BT_HDR *)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_buf->len = 5; /* opcode + s_handle + e_handle */
+
+    UINT8_TO_STREAM(p, GATT_REQ_FIND_TYPE_VALUE);
+    UINT16_TO_STREAM(p, p_value_type->s_handle);
+    UINT16_TO_STREAM(p, p_value_type->e_handle);
+
+    p_buf->len += gatt_build_uuid_to_stream(&p, p_value_type->uuid);
+
+    if (p_value_type->value_len +  p_buf->len > payload_size)
+        len = payload_size - p_buf->len;
+
+    memcpy(p, p_value_type->value, len);
+    p_buf->len += len;
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function         attp_build_read_multi_cmd
+**
+** Description      Build a read multiple request
+**
+** Returns          None.
+**
+*******************************************************************************/
+BT_HDR *attp_build_read_multi_cmd(uint16_t payload_size, uint16_t num_handle, uint16_t *p_handle)
+{
+    uint8_t *p, i = 0;
+    BT_HDR *p_buf =
+        (BT_HDR *)osi_malloc(sizeof(BT_HDR) + num_handle * 2 + 1 + L2CAP_MIN_OFFSET);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_buf->len = 1;
+
+    UINT8_TO_STREAM(p, GATT_REQ_READ_MULTI);
+
+    for (i = 0; i < num_handle && p_buf->len + 2 <= payload_size; i ++) {
+      UINT16_TO_STREAM (p, *(p_handle + i));
+      p_buf->len += 2;
+    }
+
+    return p_buf;
+}
+/*******************************************************************************
+**
+** Function         attp_build_handle_cmd
+**
+** Description      Build a read /read blob request
+**
+** Returns          None.
+**
+*******************************************************************************/
+BT_HDR *attp_build_handle_cmd(uint8_t op_code, uint16_t handle, uint16_t offset)
+{
+    uint8_t *p;
+    BT_HDR *p_buf =
+        (BT_HDR *)osi_malloc(sizeof(BT_HDR) + 5 + L2CAP_MIN_OFFSET);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+    p_buf->offset = L2CAP_MIN_OFFSET;
+
+    UINT8_TO_STREAM(p, op_code);
+    p_buf->len  = 1;
+
+    UINT16_TO_STREAM(p, handle);
+    p_buf->len += 2;
+
+    if (op_code == GATT_REQ_READ_BLOB) {
+        UINT16_TO_STREAM (p, offset);
+        p_buf->len += 2;
+    }
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function         attp_build_opcode_cmd
+**
+** Description      Build a  request/response with opcode only.
+**
+** Returns          None.
+**
+*******************************************************************************/
+BT_HDR *attp_build_opcode_cmd(uint8_t op_code)
+{
+    uint8_t *p;
+    BT_HDR *p_buf =
+        (BT_HDR *)osi_malloc(sizeof(BT_HDR) + 1 + L2CAP_MIN_OFFSET);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+    p_buf->offset = L2CAP_MIN_OFFSET;
+
+    UINT8_TO_STREAM(p, op_code);
+    p_buf->len  = 1;
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function         attp_build_value_cmd
+**
+** Description      Build a attribute value request
+**
+** Returns          None.
+**
+*******************************************************************************/
+BT_HDR *attp_build_value_cmd (uint16_t payload_size, uint8_t op_code, uint16_t handle,
+                              uint16_t offset, uint16_t len, uint8_t *p_data)
+{
+    uint8_t *p, *pp, pair_len, *p_pair_len;
+    BT_HDR *p_buf =
+        (BT_HDR *)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET);
+
+    p = pp = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+    UINT8_TO_STREAM(p, op_code);
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_buf->len = 1;
+
+    if (op_code == GATT_RSP_READ_BY_TYPE) {
+        p_pair_len = p;
+        pair_len = len + 2;
+        UINT8_TO_STREAM (p, pair_len);
+        p_buf->len += 1;
+    }
+    if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ) {
+        UINT16_TO_STREAM (p, handle);
+        p_buf->len += 2;
+    }
+
+    if (op_code == GATT_REQ_PREPARE_WRITE ||op_code == GATT_RSP_PREPARE_WRITE) {
+        UINT16_TO_STREAM (p, offset);
+        p_buf->len += 2;
+    }
+
+    if (len > 0 && p_data != NULL) {
+        /* ensure data not exceed MTU size */
+        if (payload_size - p_buf->len < len) {
+            len = payload_size - p_buf->len;
+            /* update handle value pair length */
+            if (op_code == GATT_RSP_READ_BY_TYPE)
+                *p_pair_len = (len + 2);
+
+            GATT_TRACE_WARNING("attribute value too long, to be truncated to %d", len);
+        }
+
+        ARRAY_TO_STREAM(p, p_data, len);
+        p_buf->len += len;
+    }
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function         attp_send_msg_to_l2cap
+**
+** Description      Send message to L2CAP.
+**
+*******************************************************************************/
+tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB *p_tcb, BT_HDR *p_toL2CAP)
+{
+    uint16_t    l2cap_ret;
+
+
+    if (p_tcb->att_lcid == L2CAP_ATT_CID)
+        l2cap_ret = L2CA_SendFixedChnlData (L2CAP_ATT_CID, p_tcb->peer_bda, p_toL2CAP);
+    else
+        l2cap_ret = (uint16_t) L2CA_DataWrite (p_tcb->att_lcid, p_toL2CAP);
+
+    if (l2cap_ret == L2CAP_DW_FAILED)
+    {
+        GATT_TRACE_ERROR("ATT   failed to pass msg:0x%0x to L2CAP",
+            *((uint8_t *)(p_toL2CAP + 1) + p_toL2CAP->offset));
+        return GATT_INTERNAL_ERROR;
+    }
+    else if (l2cap_ret == L2CAP_DW_CONGESTED)
+    {
+        GATT_TRACE_DEBUG("ATT congested, message accepted");
+        return GATT_CONGESTED;
+    }
+    return GATT_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         attp_build_sr_msg
+**
+** Description      Build ATT Server PDUs.
+**
+*******************************************************************************/
+BT_HDR *attp_build_sr_msg(tGATT_TCB *p_tcb, uint8_t op_code, tGATT_SR_MSG *p_msg)
+{
+    BT_HDR          *p_cmd = NULL;
+    uint16_t        offset = 0;
+
+    switch (op_code)
+    {
+    case GATT_RSP_READ_BLOB:
+    case GATT_RSP_PREPARE_WRITE:
+        GATT_TRACE_EVENT ("ATT_RSP_READ_BLOB/GATT_RSP_PREPARE_WRITE: len = %d offset = %d",
+                    p_msg->attr_value.len, p_msg->attr_value.offset);
+        offset = p_msg->attr_value.offset;
+/* Coverity: [FALSE-POSITIVE error] intended fall through */
+/* Missing break statement between cases in switch statement */
+        /* fall through */
+    case GATT_RSP_READ_BY_TYPE:
+    case GATT_RSP_READ:
+    case GATT_HANDLE_VALUE_NOTIF:
+    case GATT_HANDLE_VALUE_IND:
+        p_cmd = attp_build_value_cmd(p_tcb->payload_size,
+                                     op_code,
+                                     p_msg->attr_value.handle,
+                                     offset,
+                                     p_msg->attr_value.len,
+                                     p_msg->attr_value.value);
+        break;
+
+    case GATT_RSP_WRITE:
+        p_cmd = attp_build_opcode_cmd(op_code);
+        break;
+
+    case GATT_RSP_ERROR:
+        p_cmd = attp_build_err_cmd(p_msg->error.cmd_code, p_msg->error.handle, p_msg->error.reason);
+        break;
+
+    case GATT_RSP_EXEC_WRITE:
+        p_cmd = attp_build_exec_write_cmd(op_code, 0);
+        break;
+
+    case GATT_RSP_MTU:
+        p_cmd = attp_build_mtu_cmd(op_code, p_msg->mtu);
+        break;
+
+    default:
+        GATT_TRACE_DEBUG("attp_build_sr_msg: unknown op code = %d", op_code);
+        break;
+    }
+
+    if (!p_cmd)
+        GATT_TRACE_ERROR("No resources");
+
+    return p_cmd;
+}
+
+/*******************************************************************************
+**
+** Function         attp_send_sr_msg
+**
+** Description      This function sends the server response or indication message
+**                  to client.
+**
+** Parameter        p_tcb: pointer to the connecton control block.
+**                  p_msg: pointer to message parameters structure.
+**
+** Returns          GATT_SUCCESS if sucessfully sent; otherwise error code.
+**
+**
+*******************************************************************************/
+tGATT_STATUS attp_send_sr_msg (tGATT_TCB *p_tcb, BT_HDR *p_msg)
+{
+    tGATT_STATUS     cmd_sent = GATT_NO_RESOURCES;
+
+    if (p_tcb != NULL)
+    {
+        if (p_msg != NULL)
+        {
+            p_msg->offset = L2CAP_MIN_OFFSET;
+            cmd_sent = attp_send_msg_to_l2cap (p_tcb, p_msg);
+        }
+    }
+    return cmd_sent;
+}
+
+/*******************************************************************************
+**
+** Function         attp_cl_send_cmd
+**
+** Description      Send a ATT command or enqueue it.
+**
+** Returns          GATT_SUCCESS if command sent
+**                  GATT_CONGESTED if command sent but channel congested
+**                  GATT_CMD_STARTED if command queue up in GATT
+**                  GATT_ERROR if command sending failure
+**
+*******************************************************************************/
+tGATT_STATUS attp_cl_send_cmd(tGATT_TCB *p_tcb, uint16_t clcb_idx, uint8_t cmd_code, BT_HDR *p_cmd)
+{
+    tGATT_STATUS att_ret = GATT_SUCCESS;
+
+    if (p_tcb != NULL)
+    {
+        cmd_code &= ~GATT_AUTH_SIGN_MASK;
+
+        /* no pending request or value confirmation */
+        if (p_tcb->pending_cl_req == p_tcb->next_slot_inq ||
+            cmd_code == GATT_HANDLE_VALUE_CONF)
+        {
+            att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd);
+            if (att_ret == GATT_CONGESTED || att_ret == GATT_SUCCESS)
+            {
+                /* do not enq cmd if handle value confirmation or set request */
+                if (cmd_code != GATT_HANDLE_VALUE_CONF && cmd_code != GATT_CMD_WRITE)
+                {
+                    gatt_start_rsp_timer (clcb_idx);
+                    gatt_cmd_enq(p_tcb, clcb_idx, false, cmd_code, NULL);
+                }
+            }
+            else
+                att_ret = GATT_INTERNAL_ERROR;
+        }
+        else
+        {
+            att_ret = GATT_CMD_STARTED;
+            gatt_cmd_enq(p_tcb, clcb_idx, true, cmd_code, p_cmd);
+        }
+    }
+    else
+        att_ret = GATT_ERROR;
+
+    return att_ret;
+}
+/*******************************************************************************
+**
+** Function         attp_send_cl_msg
+**
+** Description      This function sends the client request or confirmation message
+**                  to server.
+**
+** Parameter        p_tcb: pointer to the connectino control block.
+**                  clcb_idx: clcb index
+**                  op_code: message op code.
+**                  p_msg: pointer to message parameters structure.
+**
+** Returns          GATT_SUCCESS if sucessfully sent; otherwise error code.
+**
+**
+*******************************************************************************/
+tGATT_STATUS attp_send_cl_msg (tGATT_TCB *p_tcb, uint16_t clcb_idx, uint8_t op_code, tGATT_CL_MSG *p_msg)
+{
+    tGATT_STATUS     status = GATT_NO_RESOURCES;
+    BT_HDR          *p_cmd = NULL;
+    uint16_t        offset = 0, handle;
+
+    if (p_tcb != NULL)
+    {
+        switch (op_code)
+        {
+        case GATT_REQ_MTU:
+            if (p_msg->mtu <= GATT_MAX_MTU_SIZE)
+            {
+                p_tcb->payload_size = p_msg->mtu;
+                p_cmd = attp_build_mtu_cmd(GATT_REQ_MTU, p_msg->mtu);
+            }
+            else
+                status = GATT_ILLEGAL_PARAMETER;
+            break;
+
+        case GATT_REQ_FIND_INFO:
+        case GATT_REQ_READ_BY_TYPE:
+        case GATT_REQ_READ_BY_GRP_TYPE:
+            if (GATT_HANDLE_IS_VALID (p_msg->browse.s_handle) &&
+                GATT_HANDLE_IS_VALID (p_msg->browse.e_handle)  &&
+                p_msg->browse.s_handle <= p_msg->browse.e_handle)
+            {
+                p_cmd = attp_build_browse_cmd(op_code,
+                                            p_msg->browse.s_handle,
+                                            p_msg->browse.e_handle,
+                                            p_msg->browse.uuid);
+            }
+            else
+                status = GATT_ILLEGAL_PARAMETER;
+            break;
+
+        case GATT_REQ_READ_BLOB:
+            offset = p_msg->read_blob.offset;
+            /* fall through */
+        case GATT_REQ_READ:
+            handle = (op_code == GATT_REQ_READ) ? p_msg->handle: p_msg->read_blob.handle;
+            /*  handle checking */
+            if (GATT_HANDLE_IS_VALID (handle))
+            {
+                p_cmd = attp_build_handle_cmd(op_code, handle, offset);
+            }
+            else
+                status = GATT_ILLEGAL_PARAMETER;
+            break;
+
+        case GATT_HANDLE_VALUE_CONF:
+            p_cmd = attp_build_opcode_cmd(op_code);
+            break;
+
+        case GATT_REQ_PREPARE_WRITE:
+            offset = p_msg->attr_value.offset;
+            /* fall through */
+        case GATT_REQ_WRITE:
+        case GATT_CMD_WRITE:
+        case GATT_SIGN_CMD_WRITE:
+            if (GATT_HANDLE_IS_VALID (p_msg->attr_value.handle))
+            {
+                p_cmd = attp_build_value_cmd (p_tcb->payload_size,
+                                              op_code, p_msg->attr_value.handle,
+                                              offset,
+                                              p_msg->attr_value.len,
+                                              p_msg->attr_value.value);
+            }
+            else
+                status = GATT_ILLEGAL_PARAMETER;
+            break;
+
+        case GATT_REQ_EXEC_WRITE:
+            p_cmd = attp_build_exec_write_cmd(op_code, p_msg->exec_write);
+            break;
+
+        case GATT_REQ_FIND_TYPE_VALUE:
+            p_cmd = attp_build_read_by_type_value_cmd(p_tcb->payload_size, &p_msg->find_type_value);
+            break;
+
+        case GATT_REQ_READ_MULTI:
+            p_cmd = attp_build_read_multi_cmd(p_tcb->payload_size,
+                                              p_msg->read_multi.num_handles,
+                                              p_msg->read_multi.handles);
+            break;
+
+        default:
+            break;
+        }
+
+        if (p_cmd != NULL)
+            status = attp_cl_send_cmd(p_tcb, clcb_idx, op_code, p_cmd);
+
+    }
+    else
+    {
+        GATT_TRACE_ERROR("Peer device not connected");
+    }
+
+    return status;
+}
+#endif
diff --git a/bt/stack/gatt/gatt_api.cc b/bt/stack/gatt/gatt_api.cc
new file mode 100644
index 0000000..a6c191c
--- /dev/null
+++ b/bt/stack/gatt/gatt_api.cc
@@ -0,0 +1,1463 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 GATT interface functions
+ *
+ ******************************************************************************/
+#include "bt_target.h"
+
+
+#if (BTA_GATT_INCLUDED == TRUE)
+
+#include "bt_common.h"
+#include <stdio.h>
+#include <string.h>
+#include "gatt_api.h"
+#include "gatt_int.h"
+#include "l2c_api.h"
+#include "btm_int.h"
+
+/*******************************************************************************
+**
+** Function         GATT_SetTraceLevel
+**
+** Description      This function sets the trace level.  If called with
+**                  a value of 0xFF, it simply returns the current trace level.
+**
+**                  Input Parameters:
+**                      level:  The level to set the GATT tracing to:
+**                      0xff-returns the current setting.
+**                      0-turns off tracing.
+**                      >= 1-Errors.
+**                      >= 2-Warnings.
+**                      >= 3-APIs.
+**                      >= 4-Events.
+**                      >= 5-Debug.
+**
+** Returns          The new or current trace level
+**
+*******************************************************************************/
+uint8_t GATT_SetTraceLevel (uint8_t new_level)
+{
+    if (new_level != 0xFF)
+        gatt_cb.trace_level = new_level;
+
+    return(gatt_cb.trace_level);
+}
+
+/*****************************************************************************
+**
+**                  GATT SERVER API
+**
+******************************************************************************/
+/*******************************************************************************
+**
+** Function         GATTS_AddHandleRange
+**
+** Description      This function add the allocated handles range for the specifed
+**                  application UUID, service UUID and service instance
+**
+** Parameter        p_hndl_range:   pointer to allocated handles information
+**
+** Returns          true if handle range is added sucessfully; otherwise false.
+**
+*******************************************************************************/
+
+bool    GATTS_AddHandleRange(tGATTS_HNDL_RANGE *p_hndl_range)
+{
+    tGATT_HDL_LIST_ELEM *p_buf;
+    bool    status= false;
+
+    if ((p_buf = gatt_alloc_hdl_buffer()) != NULL)
+    {
+        p_buf->asgn_range = *p_hndl_range;
+        status  = gatt_add_an_item_to_list(&gatt_cb.hdl_list_info, p_buf);
+    }
+    return status;
+}
+
+
+/*******************************************************************************
+**
+** Function         GATTS_NVRegister
+**
+** Description      Application manager calls this function to register for
+**                  NV save callback function.  There can be one and only one
+**                  NV save callback function.
+**
+** Parameter        p_cb_info : callback informaiton
+**
+** Returns          true if registered OK, else false
+**
+*******************************************************************************/
+bool     GATTS_NVRegister (tGATT_APPL_INFO *p_cb_info)
+{
+    bool    status= false;
+    if (p_cb_info)
+    {
+        gatt_cb.cb_info = *p_cb_info;
+        status = true;
+        gatt_init_srv_chg();
+    }
+
+    return status;
+}
+
+static uint8_t BASE_UUID[16] = {0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
+                                0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static int uuidType(unsigned char* p_uuid)
+{
+    if (memcmp(p_uuid, BASE_UUID, 12) != 0)
+        return LEN_UUID_128;
+    if (memcmp(p_uuid + 14, BASE_UUID + 14, 2) != 0)
+        return LEN_UUID_32;
+
+    return LEN_UUID_16;
+}
+
+/*******************************************************************************
+ * BTIF -> BTA conversion functions
+ *******************************************************************************/
+
+static void btif_to_bta_uuid(tBT_UUID *p_dest, bt_uuid_t *p_src)
+{
+    char *p_byte = (char*)p_src;
+    int i = 0;
+
+    p_dest->len = uuidType(p_src->uu);
+
+    switch (p_dest->len)
+    {
+        case LEN_UUID_16:
+            p_dest->uu.uuid16 = (p_src->uu[13] << 8) + p_src->uu[12];
+            break;
+
+        case LEN_UUID_32:
+            p_dest->uu.uuid32  = (p_src->uu[15] << 24) + (p_src->uu[14] << 16)
+                               + (p_src->uu[13] <<  8) + p_src->uu[12];
+            break;
+
+        case LEN_UUID_128:
+            for(i = 0; i != 16; ++i)
+                p_dest->uu.uuid128[i] = p_byte[i];
+            break;
+
+        default:
+            GATT_TRACE_ERROR("%s: Unknown UUID length %d!", __func__, p_dest->len);
+            break;
+    }
+}
+
+void uuid_128_from_16(bt_uuid_t *uuid, uint16_t uuid16) {
+  memcpy(uuid, &BASE_UUID, sizeof(bt_uuid_t));
+
+  uuid->uu[13] = (uint8_t)((0xFF00 & uuid16)>>8);
+  uuid->uu[12] = (uint8_t)(0x00FF & uuid16);
+}
+
+
+static uint16_t compute_service_size(btgatt_db_element_t *service, int count) {
+    int db_size = 0;
+    btgatt_db_element_t *el = service;
+
+    for (int i = 0; i<count; i++, el++)
+        if (el->type == BTGATT_DB_PRIMARY_SERVICE ||
+            el->type == BTGATT_DB_SECONDARY_SERVICE ||
+            el->type == BTGATT_DB_DESCRIPTOR ||
+            el->type == BTGATT_DB_INCLUDED_SERVICE)
+            db_size += 1;
+        else if (el->type == BTGATT_DB_CHARACTERISTIC)
+            db_size += 2;
+        else
+            GATT_TRACE_ERROR("%s: Unknown element type: %d", __func__, el->type);
+
+    return db_size;
+}
+/*******************************************************************************
+**
+** Function         GATTS_AddService
+**
+** Description      This function is called to add GATT service.
+**
+** Parameter        gatt_if : application if
+**                  service : pseudo-representation of service and it's content
+**                  count   : size of service
+**
+** Returns          on success GATT_SERVICE_STARTED is returned, and
+**                  attribute_handle field inside service elements are filled.
+**                  on error error status is returned.
+**
+*******************************************************************************/
+uint16_t GATTS_AddService(tGATT_IF gatt_if, btgatt_db_element_t *service, int count) {
+    tGATT_HDL_LIST_INFO     *p_list_info= &gatt_cb.hdl_list_info;
+    tGATT_HDL_LIST_ELEM     *p_list=NULL;
+    uint16_t                s_hdl=0;
+    bool                    save_hdl=false;
+    tGATT_REG              *p_reg = gatt_get_regcb(gatt_if);
+    tBT_UUID     *p_app_uuid128;
+
+    bool is_pri = (service->type == BTGATT_DB_PRIMARY_SERVICE) ? true : false;
+    tBT_UUID svc_uuid;
+    btif_to_bta_uuid(&svc_uuid, &service->uuid);
+
+    GATT_TRACE_API("%s", __func__);
+
+    if (p_reg == NULL)
+    {
+        GATT_TRACE_ERROR ("Inavlid gatt_if=%d", gatt_if);
+        return GATT_INTERNAL_ERROR;
+    }
+
+    p_app_uuid128 = &p_reg->app_uuid128;
+
+    uint16_t num_handles = compute_service_size(service, count);
+
+    if ( (svc_uuid.len == LEN_UUID_16) && (svc_uuid.uu.uuid16 == UUID_SERVCLASS_GATT_SERVER)) {
+            s_hdl=  gatt_cb.hdl_cfg.gatt_start_hdl;
+    } else if ((svc_uuid.len == LEN_UUID_16) && (svc_uuid.uu.uuid16 == UUID_SERVCLASS_GAP_SERVER)) {
+            s_hdl= gatt_cb.hdl_cfg.gap_start_hdl;
+    } else {
+        p_list = p_list_info->p_first;
+
+        if (p_list)
+            s_hdl = p_list->asgn_range.e_handle + 1;
+
+        if (s_hdl < gatt_cb.hdl_cfg.app_start_hdl)
+            s_hdl = gatt_cb.hdl_cfg.app_start_hdl;
+
+        save_hdl = true;
+    }
+
+    /* check for space */
+    if (num_handles > (0xFFFF - s_hdl + 1)) {
+        GATT_TRACE_ERROR ("GATTS_ReserveHandles: no handles, s_hdl: %u  needed: %u", s_hdl, num_handles);
+        return GATT_INTERNAL_ERROR;
+    }
+
+    if ( (p_list = gatt_alloc_hdl_buffer()) == NULL) {
+        /* No free entry */
+        GATT_TRACE_ERROR ("GATTS_ReserveHandles: no free handle blocks");
+        return GATT_INTERNAL_ERROR;
+    }
+
+    p_list->asgn_range.app_uuid128 = *p_app_uuid128;
+    p_list->asgn_range.svc_uuid    = svc_uuid;
+    p_list->asgn_range.s_handle    = s_hdl;
+    p_list->asgn_range.e_handle    = s_hdl+num_handles-1;
+    p_list->asgn_range.is_primary  = is_pri;
+
+    gatt_add_an_item_to_list(p_list_info, p_list);
+
+    if (save_hdl) {
+        if (gatt_cb.cb_info.p_nv_save_callback)
+            (*gatt_cb.cb_info.p_nv_save_callback)(true, &p_list->asgn_range);
+    }
+
+    if (!gatts_init_service_db(&p_list->svc_db, &svc_uuid, is_pri, s_hdl , num_handles))
+    {
+        GATT_TRACE_ERROR ("GATTS_ReserveHandles: service DB initialization failed");
+        if (p_list)
+        {
+            gatt_remove_an_item_from_list(p_list_info, p_list);
+            gatt_free_hdl_buffer(p_list);
+        }
+
+        return GATT_INTERNAL_ERROR;
+    }
+
+    GATT_TRACE_DEBUG ("%d: handles needed:%u s_hdl=%u e_hdl=%u %s[%x] is_primary=%d", __func__,
+                       num_handles, p_list->asgn_range.s_handle , p_list->asgn_range.e_handle,
+                       ((p_list->asgn_range.svc_uuid.len == 2) ? "uuid16": "uuid128" ),
+                       p_list->asgn_range.svc_uuid.uu.uuid16,
+                       p_list->asgn_range.is_primary);
+
+    service->attribute_handle = s_hdl;
+
+    btgatt_db_element_t *el = service +1;
+    for (int i = 0; i<count-1; i++, el++) {
+        tBT_UUID uuid;
+        btif_to_bta_uuid(&uuid, &el->uuid);
+
+        if (el->type == BTGATT_DB_CHARACTERISTIC) {
+            /* data validity checking */
+            if (((el->properties & GATT_CHAR_PROP_BIT_AUTH) && !(el->permissions & GATT_WRITE_SIGNED_PERM)) ||
+                ((el->permissions & GATT_WRITE_SIGNED_PERM) && !(el->properties & GATT_CHAR_PROP_BIT_AUTH)) ) {
+                GATT_TRACE_DEBUG("Invalid configuration property=0x%02x perm=0x%04x ", el->properties, el->permissions);
+                return GATT_INTERNAL_ERROR;
+            }
+
+            el->attribute_handle = gatts_add_characteristic(&p_list->svc_db, el->permissions, el->properties, &uuid);
+        } else if (el->type == BTGATT_DB_DESCRIPTOR) {
+            el->attribute_handle = gatts_add_char_descr(&p_list->svc_db, el->permissions, &uuid);
+        } else if (el->type == BTGATT_DB_INCLUDED_SERVICE) {
+            tGATT_HDL_LIST_ELEM  *p_incl_decl;
+            if ((p_incl_decl = gatt_find_hdl_buffer_by_handle(el->attribute_handle)) == NULL) {
+                GATT_TRACE_DEBUG("Included Service not created");
+                return GATT_INTERNAL_ERROR;
+            }
+
+            el->attribute_handle = gatts_add_included_service(&p_list->svc_db,
+                                              p_incl_decl->asgn_range.s_handle,
+                                              p_incl_decl->asgn_range.e_handle,
+                                              p_incl_decl->asgn_range.svc_uuid);
+        }
+    }
+
+    tGATT_SR_REG *p_sreg;
+    uint8_t       i_sreg;
+    tBT_UUID     *p_uuid;
+
+    GATT_TRACE_API("%s: service parsed correctly, now starting", __func__);
+
+    /*this is a new application servoce start */
+    if ((i_sreg = gatt_sr_alloc_rcb(p_list)) ==  GATT_MAX_SR_PROFILES) {
+        GATT_TRACE_ERROR ("%s: no free server registration block", __func__);
+        return GATT_NO_RESOURCES;
+    }
+
+    p_sreg = &gatt_cb.sr_reg[i_sreg];
+    p_sreg->gatt_if = gatt_if;
+
+    if (p_sreg->type == GATT_UUID_PRI_SERVICE) {
+        p_uuid = gatts_get_service_uuid(p_sreg->p_db);
+        p_sreg->sdp_handle = gatt_add_sdp_record(p_uuid, p_sreg->s_hdl, p_sreg->e_hdl);
+    }
+
+    gatts_update_srv_list_elem(i_sreg, p_sreg->s_hdl,
+                               p_list->asgn_range.is_primary);
+
+    gatt_add_a_srv_to_list(&gatt_cb.srv_list_info, &gatt_cb.srv_list[i_sreg]);
+
+    GATT_TRACE_DEBUG("%s: allocated i_sreg=%d ",__func__, i_sreg);
+    GATT_TRACE_DEBUG("%s: s_hdl=%d e_hdl=%d type=0x%x sdp_hdl=0x%x", __func__,
+                       p_sreg->s_hdl,p_sreg->e_hdl,
+                       p_sreg->type,
+                       p_sreg->sdp_handle);
+
+    gatt_proc_srv_chg();
+
+    return GATT_SERVICE_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function         GATTS_DeleteService
+**
+** Description      This function is called to delete a service.
+**
+** Parameter        gatt_if       : application interface
+**                  p_svc_uuid    : service UUID
+**                  start_handle  : start handle of the service
+**
+** Returns          true if operation succeed, false if handle block was not found.
+**
+*******************************************************************************/
+bool    GATTS_DeleteService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid, uint16_t svc_inst)
+{
+
+    tGATT_HDL_LIST_INFO             *p_list_info= &gatt_cb.hdl_list_info;
+    tGATT_HDL_LIST_ELEM             *p_list=NULL;
+    uint8_t                           i_sreg;
+    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
+    tBT_UUID *p_app_uuid128;
+
+    GATT_TRACE_DEBUG ("GATTS_DeleteService");
+
+    if (p_reg == NULL)
+    {
+        GATT_TRACE_ERROR ("Applicaiton not foud");
+        return false;
+    }
+    p_app_uuid128 = &p_reg->app_uuid128;
+
+    if ((p_list = gatt_find_hdl_buffer_by_app_id(p_app_uuid128, p_svc_uuid, svc_inst)) == NULL)
+    {
+        GATT_TRACE_ERROR ("No Service found");
+        return false;
+    }
+
+    gatt_proc_srv_chg();
+
+    if ((i_sreg = gatt_sr_find_i_rcb_by_app_id (p_app_uuid128,
+                                                p_svc_uuid,
+                                                svc_inst)) != GATT_MAX_SR_PROFILES)
+    {
+        GATTS_StopService(gatt_cb.sr_reg[i_sreg].s_hdl);
+    }
+
+    GATT_TRACE_DEBUG ("released handles s_hdl=%u e_hdl=%u",
+                       p_list->asgn_range.s_handle , p_list->asgn_range.e_handle  );
+
+    if ( (p_list->asgn_range.s_handle >= gatt_cb.hdl_cfg.app_start_hdl)
+         && gatt_cb.cb_info.p_nv_save_callback)
+        (*gatt_cb.cb_info.p_nv_save_callback)(false, &p_list->asgn_range);
+
+    gatt_remove_an_item_from_list(p_list_info, p_list);
+    gatt_free_hdl_buffer(p_list);
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         GATTS_StopService
+**
+** Description      This function is called to stop a service
+**
+** Parameter         service_handle : this is the start handle of a service
+**
+** Returns          None.
+**
+*******************************************************************************/
+void GATTS_StopService (uint16_t service_handle)
+{
+    uint8_t         ii = gatt_sr_find_i_rcb_by_handle(service_handle);
+
+    GATT_TRACE_API("GATTS_StopService %u", service_handle);
+
+    /* Index 0 is reserved for GATT, and is never stopped */
+    if ( (ii > 0) && (ii < GATT_MAX_SR_PROFILES) && (gatt_cb.sr_reg[ii].in_use) )
+    {
+        if (gatt_cb.sr_reg[ii].sdp_handle)
+        {
+            SDP_DeleteRecord(gatt_cb.sr_reg[ii].sdp_handle);
+        }
+        gatt_remove_a_srv_from_list(&gatt_cb.srv_list_info, &gatt_cb.srv_list[ii]);
+        gatt_cb.srv_list[ii].in_use = false;
+        memset (&gatt_cb.sr_reg[ii], 0, sizeof(tGATT_SR_REG));
+    }
+    else
+    {
+        GATT_TRACE_ERROR("GATTS_StopService service_handle: %u is not in use", service_handle);
+    }
+}
+/*******************************************************************************
+**
+** Function         GATTs_HandleValueIndication
+**
+** Description      This function sends a handle value indication to a client.
+**
+** Parameter        conn_id: connection identifier.
+**                  attr_handle: Attribute handle of this handle value indication.
+**                  val_len: Length of the indicated attribute value.
+**                  p_val: Pointer to the indicated attribute value data.
+**
+** Returns          GATT_SUCCESS if sucessfully sent or queued; otherwise error code.
+**
+*******************************************************************************/
+tGATT_STATUS GATTS_HandleValueIndication (uint16_t conn_id,  uint16_t attr_handle, uint16_t val_len, uint8_t *p_val)
+{
+    tGATT_STATUS    cmd_status = GATT_NO_RESOURCES;
+
+    tGATT_VALUE      indication;
+    BT_HDR          *p_msg;
+    tGATT_VALUE     *p_buf;
+    tGATT_IF         gatt_if = GATT_GET_GATT_IF(conn_id);
+    uint8_t         tcb_idx = GATT_GET_TCB_IDX(conn_id);
+    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
+    tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+
+
+    GATT_TRACE_API ("GATTS_HandleValueIndication");
+    if ( (p_reg == NULL) || (p_tcb == NULL))
+    {
+        GATT_TRACE_ERROR ("GATTS_HandleValueIndication Unknown  conn_id: %u ", conn_id);
+        return(tGATT_STATUS) GATT_INVALID_CONN_ID;
+    }
+
+    if (! GATT_HANDLE_IS_VALID (attr_handle))
+        return GATT_ILLEGAL_PARAMETER;
+
+    indication.conn_id  = conn_id;
+    indication.handle   = attr_handle;
+    indication.len      = val_len;
+    memcpy (indication.value, p_val, val_len);
+    indication.auth_req = GATT_AUTH_REQ_NONE;
+
+    if (GATT_HANDLE_IS_VALID(p_tcb->indicate_handle))
+    {
+        GATT_TRACE_DEBUG ("Add a pending indication");
+        if ((p_buf = gatt_add_pending_ind(p_tcb, &indication)) !=NULL)
+        {
+            cmd_status = GATT_SUCCESS;
+        }
+        else
+        {
+            cmd_status = GATT_NO_RESOURCES;
+        }
+    }
+    else
+    {
+
+        if ( (p_msg = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_IND, (tGATT_SR_MSG *)&indication)) != NULL)
+        {
+            cmd_status = attp_send_sr_msg (p_tcb, p_msg);
+
+            if (cmd_status == GATT_SUCCESS || cmd_status == GATT_CONGESTED)
+            {
+                p_tcb->indicate_handle = indication.handle;
+                gatt_start_conf_timer(p_tcb);
+            }
+        }
+    }
+    return cmd_status;
+}
+
+/*******************************************************************************
+**
+** Function         GATTS_HandleValueNotification
+**
+** Description      This function sends a handle value notification to a client.
+**
+** Parameter        conn_id: connection identifier.
+**                  attr_handle: Attribute handle of this handle value indication.
+**                  val_len: Length of the indicated attribute value.
+**                  p_val: Pointer to the indicated attribute value data.
+**
+** Returns          GATT_SUCCESS if sucessfully sent; otherwise error code.
+**
+*******************************************************************************/
+tGATT_STATUS GATTS_HandleValueNotification (uint16_t conn_id, uint16_t attr_handle,
+                                            uint16_t val_len, uint8_t *p_val)
+{
+    tGATT_STATUS    cmd_sent = GATT_ILLEGAL_PARAMETER;
+    BT_HDR          *p_buf;
+    tGATT_VALUE     notif;
+    tGATT_IF         gatt_if = GATT_GET_GATT_IF(conn_id);
+    uint8_t         tcb_idx = GATT_GET_TCB_IDX(conn_id);
+    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
+    tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+
+    GATT_TRACE_API ("GATTS_HandleValueNotification");
+
+    if ( (p_reg == NULL) || (p_tcb == NULL))
+    {
+        GATT_TRACE_ERROR ("GATTS_HandleValueNotification Unknown  conn_id: %u ", conn_id);
+        return(tGATT_STATUS) GATT_INVALID_CONN_ID;
+    }
+
+    if (GATT_HANDLE_IS_VALID (attr_handle))
+    {
+        notif.handle    = attr_handle;
+        notif.len       = val_len;
+        memcpy (notif.value, p_val, val_len);
+        notif.auth_req = GATT_AUTH_REQ_NONE;;
+
+        if ((p_buf = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_NOTIF, (tGATT_SR_MSG *)&notif))
+                   != NULL)
+        {
+            cmd_sent = attp_send_sr_msg (p_tcb, p_buf);
+        }
+        else
+            cmd_sent = GATT_NO_RESOURCES;
+    }
+    return cmd_sent;
+}
+
+/*******************************************************************************
+**
+** Function         GATTS_SendRsp
+**
+** Description      This function sends the server response to client.
+**
+** Parameter        conn_id: connection identifier.
+**                  trans_id: transaction id
+**                  status: response status
+**                  p_msg: pointer to message parameters structure.
+**
+** Returns          GATT_SUCCESS if sucessfully sent; otherwise error code.
+**
+*******************************************************************************/
+tGATT_STATUS GATTS_SendRsp (uint16_t conn_id,  uint32_t trans_id,
+                            tGATT_STATUS status, tGATTS_RSP *p_msg)
+{
+    tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER;
+    tGATT_IF         gatt_if = GATT_GET_GATT_IF(conn_id);
+    uint8_t         tcb_idx = GATT_GET_TCB_IDX(conn_id);
+    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
+    tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+
+    GATT_TRACE_API ("GATTS_SendRsp: conn_id: %u  trans_id: %u  Status: 0x%04x",
+                     conn_id, trans_id, status);
+
+    if ( (p_reg == NULL) || (p_tcb == NULL))
+    {
+        GATT_TRACE_ERROR ("GATTS_SendRsp Unknown  conn_id: %u ", conn_id);
+        return(tGATT_STATUS) GATT_INVALID_CONN_ID;
+    }
+
+    if (p_tcb->sr_cmd.trans_id != trans_id)
+    {
+        GATT_TRACE_ERROR ("GATTS_SendRsp conn_id: %u  waiting for op_code = %02x",
+                           conn_id, p_tcb->sr_cmd.op_code);
+
+        return(GATT_WRONG_STATE);
+    }
+    /* Process App response */
+    cmd_sent = gatt_sr_process_app_rsp (p_tcb,  gatt_if, trans_id, p_tcb->sr_cmd.op_code, status, p_msg);
+
+    return cmd_sent;
+}
+
+/*******************************************************************************/
+/* GATT Profile Srvr Functions */
+/*******************************************************************************/
+
+/*******************************************************************************/
+/*                                                                             */
+/*                   GATT CLIENT APIs                                          */
+/*                                                                             */
+/*******************************************************************************/
+
+
+/*******************************************************************************
+**
+** Function         GATTC_ConfigureMTU
+**
+** Description      This function is called to configure the ATT MTU size.
+**
+** Parameters       conn_id: connection identifier.
+**                  mtu    - attribute MTU size..
+**
+** Returns          GATT_SUCCESS if command started successfully.
+**
+*******************************************************************************/
+tGATT_STATUS GATTC_ConfigureMTU (uint16_t conn_id, uint16_t mtu)
+{
+    uint8_t         ret = GATT_NO_RESOURCES;
+    tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
+    uint8_t         tcb_idx = GATT_GET_TCB_IDX(conn_id);
+    tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
+
+    tGATT_CLCB    *p_clcb;
+
+    GATT_TRACE_API ("GATTC_ConfigureMTU conn_id=%d mtu=%d", conn_id, mtu );
+
+    /* Validate that the link is BLE, not BR/EDR */
+    if (p_tcb->transport != BT_TRANSPORT_LE)
+    {
+        return GATT_ERROR;
+    }
+
+    if ( (p_tcb == NULL) || (p_reg==NULL) || (mtu < GATT_DEF_BLE_MTU_SIZE) || (mtu > GATT_MAX_MTU_SIZE))
+    {
+        return GATT_ILLEGAL_PARAMETER;
+    }
+
+    if (gatt_is_clcb_allocated(conn_id))
+    {
+        GATT_TRACE_ERROR("GATTC_ConfigureMTU GATT_BUSY conn_id = %d", conn_id);
+        return GATT_BUSY;
+    }
+
+    if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL)
+    {
+        p_clcb->p_tcb->payload_size = mtu;
+        p_clcb->operation = GATTC_OPTYPE_CONFIG;
+
+        ret = attp_send_cl_msg (p_clcb->p_tcb, p_clcb->clcb_idx, GATT_REQ_MTU, (tGATT_CL_MSG *)&mtu);
+    }
+
+    return ret;
+}
+
+/*******************************************************************************
+**
+** Function         GATTC_Discover
+**
+** Description      This function is called to do a discovery procedure on ATT server.
+**
+** Parameters       conn_id: connection identifier.
+**                  disc_type:discovery type.
+**                  p_param: parameters of discovery requirement.
+**
+** Returns          GATT_SUCCESS if command received/sent successfully.
+**
+*******************************************************************************/
+tGATT_STATUS GATTC_Discover (uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+                             tGATT_DISC_PARAM *p_param)
+{
+    tGATT_STATUS    status = GATT_SUCCESS;
+    tGATT_CLCB      *p_clcb;
+    tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
+    uint8_t         tcb_idx = GATT_GET_TCB_IDX(conn_id);
+    tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
+
+
+    GATT_TRACE_API ("GATTC_Discover conn_id=%d disc_type=%d",conn_id, disc_type);
+
+    if ( (p_tcb == NULL) || (p_reg==NULL) ||(p_param == NULL) ||
+         (disc_type >= GATT_DISC_MAX))
+    {
+        GATT_TRACE_ERROR("GATTC_Discover Illegal param: disc_type %d conn_id = %d", disc_type, conn_id);
+        return GATT_ILLEGAL_PARAMETER;
+    }
+
+
+    if (gatt_is_clcb_allocated(conn_id))
+    {
+        GATT_TRACE_ERROR("GATTC_Discover GATT_BUSY conn_id = %d", conn_id);
+        return GATT_BUSY;
+    }
+
+
+    if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
+    {
+        if (!GATT_HANDLE_IS_VALID(p_param->s_handle) ||
+            !GATT_HANDLE_IS_VALID(p_param->e_handle) ||
+            /* search by type does not have a valid UUID param */
+            (disc_type == GATT_DISC_SRVC_BY_UUID &&
+             p_param->service.len == 0))
+        {
+            gatt_clcb_dealloc(p_clcb);
+            return GATT_ILLEGAL_PARAMETER;
+        }
+
+        p_clcb->operation  = GATTC_OPTYPE_DISCOVERY;
+        p_clcb->op_subtype = disc_type;
+        p_clcb->s_handle   = p_param->s_handle;
+        p_clcb->e_handle   = p_param->e_handle;
+        p_clcb->uuid       = p_param->service;
+
+        gatt_act_discovery(p_clcb);
+    }
+    else
+    {
+        status = GATT_NO_RESOURCES;
+    }
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         GATTC_Read
+**
+** Description      This function is called to read the value of an attribute from
+**                  the server.
+**
+** Parameters       conn_id: connection identifier.
+**                  type    - attribute read type.
+**                  p_read  - read operation parameters.
+**
+** Returns          GATT_SUCCESS if command started successfully.
+**
+*******************************************************************************/
+tGATT_STATUS GATTC_Read (uint16_t conn_id, tGATT_READ_TYPE type, tGATT_READ_PARAM *p_read)
+{
+    tGATT_STATUS status = GATT_SUCCESS;
+    tGATT_CLCB          *p_clcb;
+    tGATT_IF            gatt_if=GATT_GET_GATT_IF(conn_id);
+    uint8_t             tcb_idx = GATT_GET_TCB_IDX(conn_id);
+    tGATT_TCB           *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+    tGATT_REG           *p_reg = gatt_get_regcb(gatt_if);
+
+
+    GATT_TRACE_API ("GATTC_Read conn_id=%d type=%d", conn_id, type);
+
+    if ( (p_tcb == NULL) || (p_reg==NULL) || (p_read == NULL) || ((type >= GATT_READ_MAX) || (type == 0)))
+    {
+        GATT_TRACE_ERROR("GATT_Read Illegal param: conn_id %d, type 0%d,", conn_id, type);
+        return GATT_ILLEGAL_PARAMETER;
+    }
+
+    if (gatt_is_clcb_allocated(conn_id))
+    {
+        GATT_TRACE_ERROR("GATTC_Read GATT_BUSY conn_id = %d", conn_id);
+        return GATT_BUSY;
+    }
+
+    if ( (p_clcb = gatt_clcb_alloc(conn_id)) != NULL  )
+    {
+        p_clcb->operation = GATTC_OPTYPE_READ;
+        p_clcb->op_subtype = type;
+        p_clcb->auth_req = p_read->by_handle.auth_req;
+        p_clcb->counter = 0;
+
+        switch (type)
+        {
+            case GATT_READ_BY_TYPE:
+            case GATT_READ_CHAR_VALUE:
+                p_clcb->s_handle = p_read->service.s_handle;
+                p_clcb->e_handle = p_read->service.e_handle;
+                memcpy(&p_clcb->uuid, &p_read->service.uuid, sizeof(tBT_UUID));
+                break;
+            case GATT_READ_MULTIPLE:
+            {
+                p_clcb->s_handle = 0;
+                /* copy multiple handles in CB */
+                tGATT_READ_MULTI *p_read_multi =
+                    (tGATT_READ_MULTI *)osi_malloc(sizeof(tGATT_READ_MULTI));
+                p_clcb->p_attr_buf = (uint8_t*)p_read_multi;
+                memcpy(p_read_multi, &p_read->read_multiple, sizeof(tGATT_READ_MULTI));
+                break;
+            }
+            case GATT_READ_BY_HANDLE:
+            case GATT_READ_PARTIAL:
+                memset(&p_clcb->uuid, 0, sizeof(tBT_UUID));
+                p_clcb->s_handle = p_read->by_handle.handle;
+
+                if (type == GATT_READ_PARTIAL)
+                {
+                    p_clcb->counter = p_read->partial.offset;
+                }
+
+                break;
+            default:
+                break;
+        }
+        /* start security check */
+        if (gatt_security_check_start(p_clcb) == false)
+        {
+            status = GATT_NO_RESOURCES;
+            gatt_clcb_dealloc(p_clcb);
+        }
+    }
+    else
+    {
+        status = GATT_NO_RESOURCES;
+    }
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         GATTC_Write
+**
+** Description      This function is called to write the value of an attribute to
+**                  the server.
+**
+** Parameters       conn_id: connection identifier.
+**                  type    - attribute write type.
+**                  p_write  - write operation parameters.
+**
+** Returns          GATT_SUCCESS if command started successfully.
+**
+*******************************************************************************/
+tGATT_STATUS GATTC_Write (uint16_t conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE *p_write)
+{
+    tGATT_STATUS status = GATT_SUCCESS;
+    tGATT_CLCB      *p_clcb;
+    tGATT_VALUE     *p;
+    tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
+    uint8_t         tcb_idx = GATT_GET_TCB_IDX(conn_id);
+    tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
+
+    if ( (p_tcb == NULL) || (p_reg==NULL) || (p_write == NULL) ||
+         ((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) && (type != GATT_WRITE_NO_RSP)) )
+    {
+        GATT_TRACE_ERROR("GATT_Write Illegal param: conn_id %d, type 0%d,", conn_id, type);
+        return GATT_ILLEGAL_PARAMETER;
+    }
+
+    if (gatt_is_clcb_allocated(conn_id))
+    {
+        GATT_TRACE_ERROR("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
+        return GATT_BUSY;
+    }
+
+    if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
+    {
+        p_clcb->operation  = GATTC_OPTYPE_WRITE;
+        p_clcb->op_subtype = type;
+        p_clcb->auth_req = p_write->auth_req;
+
+        p_clcb->p_attr_buf = (uint8_t *)osi_malloc(sizeof(tGATT_VALUE));
+        memcpy(p_clcb->p_attr_buf, (void *)p_write, sizeof(tGATT_VALUE));
+
+        p = (tGATT_VALUE *)p_clcb->p_attr_buf;
+        if (type == GATT_WRITE_PREPARE) {
+            p_clcb->start_offset = p_write->offset;
+            p->offset = 0;
+        }
+
+        if (gatt_security_check_start(p_clcb) == false) {
+            status = GATT_NO_RESOURCES;
+        }
+
+        if (status == GATT_NO_RESOURCES)
+            gatt_clcb_dealloc(p_clcb);
+    } else {
+        status = GATT_NO_RESOURCES;
+    }
+    return status;
+}
+
+
+/*******************************************************************************
+**
+** Function         GATTC_ExecuteWrite
+**
+** Description      This function is called to send an Execute write request to
+**                  the server.
+**
+** Parameters       conn_id: connection identifier.
+**                  is_execute - to execute or cancel the prepare write requet(s)
+**
+** Returns          GATT_SUCCESS if command started successfully.
+**
+*******************************************************************************/
+tGATT_STATUS GATTC_ExecuteWrite (uint16_t conn_id, bool    is_execute)
+{
+    tGATT_STATUS status = GATT_SUCCESS;
+    tGATT_CLCB      *p_clcb;
+    tGATT_EXEC_FLAG flag;
+    tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
+    uint8_t         tcb_idx = GATT_GET_TCB_IDX(conn_id);
+    tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
+
+    GATT_TRACE_API ("GATTC_ExecuteWrite conn_id=%d is_execute=%d", conn_id, is_execute);
+
+    if ( (p_tcb == NULL) || (p_reg==NULL) )
+    {
+        GATT_TRACE_ERROR("GATTC_ExecuteWrite Illegal param: conn_id %d", conn_id);
+        return GATT_ILLEGAL_PARAMETER;
+    }
+
+    if (gatt_is_clcb_allocated(conn_id))
+    {
+        GATT_TRACE_ERROR("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
+        return GATT_BUSY;
+    }
+
+    if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL)
+    {
+        p_clcb->operation  = GATTC_OPTYPE_EXE_WRITE;
+        flag = is_execute ? GATT_PREP_WRITE_EXEC : GATT_PREP_WRITE_CANCEL;
+        gatt_send_queue_write_cancel (p_clcb->p_tcb, p_clcb, flag);
+    }
+    else
+    {
+        GATT_TRACE_ERROR("Unable to allocate client CB for conn_id %d ", conn_id);
+        status = GATT_NO_RESOURCES;
+    }
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         GATTC_SendHandleValueConfirm
+**
+** Description      This function is called to send a handle value confirmation
+**                  as response to a handle value notification from server.
+**
+** Parameters       conn_id: connection identifier.
+**                  handle: the handle of the attribute confirmation.
+**
+** Returns          GATT_SUCCESS if command started successfully.
+**
+*******************************************************************************/
+tGATT_STATUS GATTC_SendHandleValueConfirm (uint16_t conn_id, uint16_t handle)
+{
+    tGATT_STATUS    ret = GATT_ILLEGAL_PARAMETER;
+    tGATT_TCB     *p_tcb=gatt_get_tcb_by_idx(GATT_GET_TCB_IDX(conn_id));
+
+    GATT_TRACE_API ("GATTC_SendHandleValueConfirm conn_id=%d handle=0x%x", conn_id, handle);
+
+    if (p_tcb)
+    {
+        if (p_tcb->ind_count > 0 )
+        {
+            alarm_cancel(p_tcb->ind_ack_timer);
+
+            GATT_TRACE_DEBUG ("notif_count=%d ", p_tcb->ind_count);
+            /* send confirmation now */
+            ret = attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, (tGATT_CL_MSG *)&handle);
+
+            p_tcb->ind_count = 0;
+
+        }
+        else
+        {
+            GATT_TRACE_DEBUG ("GATTC_SendHandleValueConfirm - conn_id: %u - ignored not waiting for indicaiton ack", conn_id);
+            ret = GATT_SUCCESS;
+        }
+    }
+    else
+    {
+        GATT_TRACE_ERROR ("GATTC_SendHandleValueConfirm - Unknown conn_id: %u", conn_id);
+    }
+    return ret;
+}
+
+
+/*******************************************************************************/
+/*                                                                             */
+/*                   GATT  APIs                                                */
+/*                                                                             */
+/*******************************************************************************/
+/*******************************************************************************
+**
+** Function         GATT_SetIdleTimeout
+**
+** Description      This function (common to both client and server) sets the idle
+**                  timeout for a tansport connection
+**
+** Parameter        bd_addr:   target device bd address.
+**                  idle_tout: timeout value in seconds.
+**
+** Returns          void
+**
+*******************************************************************************/
+void GATT_SetIdleTimeout (BD_ADDR bd_addr, uint16_t idle_tout, tBT_TRANSPORT transport)
+{
+    tGATT_TCB       *p_tcb;
+    bool            status = false;
+
+    if ((p_tcb = gatt_find_tcb_by_addr (bd_addr, transport)) != NULL)
+    {
+        if (p_tcb->att_lcid == L2CAP_ATT_CID)
+        {
+            status = L2CA_SetFixedChannelTout (bd_addr, L2CAP_ATT_CID, idle_tout);
+
+            if (idle_tout == GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP)
+                L2CA_SetIdleTimeoutByBdAddr(p_tcb->peer_bda,
+                                            GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP, BT_TRANSPORT_LE);
+        }
+        else
+        {
+            status = L2CA_SetIdleTimeout (p_tcb->att_lcid, idle_tout, false);
+        }
+    }
+
+    GATT_TRACE_API ("GATT_SetIdleTimeout idle_tout=%d status=%d(1-OK 0-not performed)",
+                    idle_tout, status);
+}
+
+
+/*******************************************************************************
+**
+** Function         GATT_Register
+**
+** Description      This function is called to register an  application
+**                  with GATT
+**
+** Parameter        p_app_uuid128: Application UUID
+**                  p_cb_info: callback functions.
+**
+** Returns          0 for error, otherwise the index of the client registered with GATT
+**
+*******************************************************************************/
+tGATT_IF GATT_Register (tBT_UUID *p_app_uuid128, tGATT_CBACK *p_cb_info)
+{
+    tGATT_REG    *p_reg;
+    uint8_t      i_gatt_if=0;
+    tGATT_IF     gatt_if=0;
+
+    GATT_TRACE_API("%s", __func__);
+    gatt_dbg_display_uuid(*p_app_uuid128);
+
+    for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++)
+    {
+        if (p_reg->in_use  && !memcmp(p_app_uuid128->uu.uuid128, p_reg->app_uuid128.uu.uuid128, LEN_UUID_128))
+        {
+            GATT_TRACE_ERROR("application already registered.");
+            return 0;
+        }
+    }
+
+    for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++)
+    {
+        if (!p_reg->in_use)
+        {
+            memset(p_reg, 0 , sizeof(tGATT_REG));
+            i_gatt_if++;              /* one based number */
+            p_reg->app_uuid128 =  *p_app_uuid128;
+            gatt_if            =
+            p_reg->gatt_if     = (tGATT_IF)i_gatt_if;
+            p_reg->app_cb      = *p_cb_info;
+            p_reg->in_use      = true;
+
+            GATT_TRACE_API("%s: allocated gatt_if=%d", __func__, gatt_if);
+            return gatt_if;
+        }
+    }
+
+    GATT_TRACE_ERROR("%s: can't Register GATT client, MAX client %d reached!",
+                     __func__, GATT_MAX_APPS);
+    return 0;
+}
+
+
+/*******************************************************************************
+**
+** Function         GATT_Deregister
+**
+** Description      This function deregistered the application from GATT.
+**
+** Parameters       gatt_if: applicaiton interface.
+**
+** Returns          None.
+**
+*******************************************************************************/
+void GATT_Deregister (tGATT_IF gatt_if)
+{
+    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
+    tGATT_TCB       *p_tcb;
+    tGATT_CLCB       *p_clcb;
+    uint8_t         i, ii, j;
+    tGATT_SR_REG    *p_sreg;
+
+    GATT_TRACE_API ("GATT_Deregister gatt_if=%d", gatt_if);
+    /* Index 0 is GAP and is never deregistered */
+    if ( (gatt_if == 0) || (p_reg == NULL) )
+    {
+        GATT_TRACE_ERROR ("GATT_Deregister with invalid gatt_if: %u", gatt_if);
+        return;
+    }
+
+    /* stop all services  */
+    /* todo an applcaiton can not be deregistered if its services is also used by other application
+      deregisteration need to bed performed in an orderly fashion
+      no check for now */
+
+    for (ii = 0, p_sreg = gatt_cb.sr_reg; ii < GATT_MAX_SR_PROFILES; ii++, p_sreg++)
+    {
+        if (p_sreg->in_use && (p_sreg->gatt_if == gatt_if))
+        {
+            GATTS_StopService(p_sreg->s_hdl);
+        }
+    }
+
+    /* free all services db buffers if owned by this application */
+    gatt_free_srvc_db_buffer_app_id(&p_reg->app_uuid128);
+
+    /* When an application deregisters, check remove the link associated with the app */
+
+    for (i=0, p_tcb = gatt_cb.tcb; i < GATT_MAX_PHY_CHANNEL; i++, p_tcb++)
+    {
+        if (p_tcb->in_use)
+        {
+            if (gatt_get_ch_state(p_tcb) != GATT_CH_CLOSE)
+            {
+                gatt_update_app_use_link_flag(gatt_if, p_tcb,  false, true);
+            }
+
+            for (j = 0, p_clcb= &gatt_cb.clcb[j]; j < GATT_CL_MAX_LCB; j++, p_clcb++)
+            {
+                if (p_clcb->in_use &&
+                    (p_clcb->p_reg->gatt_if == gatt_if) &&
+                    (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx))
+                {
+                    alarm_cancel(p_clcb->gatt_rsp_timer_ent);
+                    gatt_clcb_dealloc (p_clcb);
+                    break;
+                }
+            }
+        }
+    }
+
+    gatt_deregister_bgdev_list(gatt_if);
+    /* update the listen mode */
+    GATT_Listen(false);
+
+    memset (p_reg, 0, sizeof(tGATT_REG));
+}
+
+
+/*******************************************************************************
+**
+** Function         GATT_StartIf
+**
+** Description      This function is called after registration to start receiving
+**                  callbacks for registered interface.  Function may call back
+**                  with connection status and queued notifications
+**
+** Parameter        gatt_if: applicaiton interface.
+**
+** Returns          None.
+**
+*******************************************************************************/
+void GATT_StartIf (tGATT_IF gatt_if)
+{
+    tGATT_REG   *p_reg;
+    tGATT_TCB   *p_tcb;
+    BD_ADDR     bda;
+    uint8_t     start_idx, found_idx;
+    uint16_t    conn_id;
+    tGATT_TRANSPORT transport ;
+
+    GATT_TRACE_API ("GATT_StartIf gatt_if=%d", gatt_if);
+    if ((p_reg = gatt_get_regcb(gatt_if)) != NULL)
+    {
+        start_idx = 0;
+        while (gatt_find_the_connected_bda(start_idx, bda, &found_idx, &transport))
+        {
+            p_tcb = gatt_find_tcb_by_addr(bda, transport);
+            if (p_reg->app_cb.p_conn_cb && p_tcb)
+            {
+                conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
+                (*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, true, 0, transport);
+            }
+            start_idx = ++found_idx;
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         GATT_Connect
+**
+** Description      This function initiate a connecttion to a remote device on GATT
+**                  channel.
+**
+** Parameters       gatt_if: applicaiton interface
+**                  bd_addr: peer device address.
+**                  is_direct: is a direct conenection or a background auto connection
+**
+** Returns          true if connection started; false if connection start failure.
+**
+*******************************************************************************/
+bool GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, bool is_direct,
+                      tBT_TRANSPORT transport, bool opportunistic)
+{
+    tGATT_REG    *p_reg;
+    bool    status = false;
+
+    GATT_TRACE_API ("GATT_Connect gatt_if=%d", gatt_if);
+
+    /* Make sure app is registered */
+    if ((p_reg = gatt_get_regcb(gatt_if)) == NULL)
+    {
+        GATT_TRACE_ERROR("GATT_Connect - gatt_if =%d is not registered", gatt_if);
+        return(false);
+    }
+
+    if (is_direct)
+        status = gatt_act_connect (p_reg, bd_addr, transport, opportunistic);
+    else
+    {
+        if (transport == BT_TRANSPORT_LE)
+        status = gatt_update_auto_connect_dev(gatt_if,true, bd_addr);
+        else
+        {
+            GATT_TRACE_ERROR("Unsupported transport for background connection");
+        }
+    }
+
+    return status;
+
+}
+
+/*******************************************************************************
+**
+** Function         GATT_CancelConnect
+**
+** Description      This function terminate the connection initaition to a remote
+**                  device on GATT channel.
+**
+** Parameters       gatt_if: client interface. If 0 used as unconditionally disconnect,
+**                          typically used for direct connection cancellation.
+**                  bd_addr: peer device address.
+**
+** Returns          true if connection started; false if connection start failure.
+**
+*******************************************************************************/
+bool    GATT_CancelConnect (tGATT_IF gatt_if, BD_ADDR bd_addr, bool    is_direct){
+    tGATT_REG     *p_reg;
+    tGATT_TCB     *p_tcb;
+    bool          status = true;
+    tGATT_IF      temp_gatt_if;
+    uint8_t       start_idx, found_idx;
+
+    GATT_TRACE_API ("GATT_CancelConnect gatt_if=%d", gatt_if);
+
+    if ((gatt_if != 0) && ((p_reg = gatt_get_regcb(gatt_if)) == NULL))
+    {
+        GATT_TRACE_ERROR("GATT_CancelConnect - gatt_if =%d is not registered", gatt_if);
+        return(false);
+    }
+
+    if (is_direct)
+    {
+        if (!gatt_if)
+        {
+            GATT_TRACE_DEBUG("GATT_CancelConnect - unconditional");
+            start_idx = 0;
+            /* only LE connection can be cancelled */
+            p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
+            if (p_tcb && gatt_num_apps_hold_link(p_tcb))
+            {
+                while (status && gatt_find_app_hold_link(p_tcb, start_idx, &found_idx, &temp_gatt_if))
+                {
+                    status = gatt_cancel_open(temp_gatt_if, bd_addr);
+                    start_idx = ++found_idx;
+                }
+            }
+            else
+            {
+                GATT_TRACE_ERROR("GATT_CancelConnect - no app found");
+                status = false;
+            }
+        }
+        else
+        {
+            status = gatt_cancel_open(gatt_if, bd_addr);
+        }
+    }
+    else
+    {
+        if (!gatt_if)
+        {
+            if (gatt_get_num_apps_for_bg_dev(bd_addr))
+            {
+                while (gatt_find_app_for_bg_dev(bd_addr, &temp_gatt_if))
+                    gatt_remove_bg_dev_for_app(temp_gatt_if, bd_addr);
+            }
+            else
+            {
+                GATT_TRACE_ERROR("GATT_CancelConnect -no app associated with the bg device for unconditional removal");
+                status = false;
+            }
+        }
+        else
+        {
+            status = gatt_remove_bg_dev_for_app(gatt_if, bd_addr);
+        }
+    }
+
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         GATT_Disconnect
+**
+** Description      This function disconnect the GATT channel for this registered
+**                  application.
+**
+** Parameters       conn_id: connection identifier.
+**
+** Returns          GATT_SUCCESS if disconnected.
+**
+*******************************************************************************/
+tGATT_STATUS GATT_Disconnect (uint16_t conn_id)
+{
+    tGATT_STATUS    ret = GATT_ILLEGAL_PARAMETER;
+    tGATT_TCB       *p_tcb=NULL;
+    tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
+    uint8_t        tcb_idx = GATT_GET_TCB_IDX(conn_id);
+
+    GATT_TRACE_API ("GATT_Disconnect conn_id=%d ", conn_id);
+
+    p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+
+    if (p_tcb)
+    {
+        gatt_update_app_use_link_flag(gatt_if, p_tcb, false, true);
+        ret = GATT_SUCCESS;
+    }
+    return ret;
+}
+
+
+/*******************************************************************************
+**
+** Function         GATT_GetConnectionInfor
+**
+** Description      This function use conn_id to find its associated BD address and applciation
+**                  interface
+**
+** Parameters        conn_id: connection id  (input)
+**                   p_gatt_if: applicaiton interface (output)
+**                   bd_addr: peer device address. (output)
+**
+** Returns          true the ligical link information is found for conn_id
+**
+*******************************************************************************/
+bool    GATT_GetConnectionInfor(uint16_t conn_id, tGATT_IF *p_gatt_if, BD_ADDR bd_addr,
+                                tBT_TRANSPORT *p_transport)
+{
+
+    tGATT_IF        gatt_if = GATT_GET_GATT_IF(conn_id);
+    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
+    uint8_t         tcb_idx = GATT_GET_TCB_IDX(conn_id);
+    tGATT_TCB       *p_tcb= gatt_get_tcb_by_idx(tcb_idx);
+    bool            status=false;
+
+    GATT_TRACE_API ("GATT_GetConnectionInfor conn_id=%d", conn_id);
+
+    if (p_tcb && p_reg )
+    {
+        memcpy(bd_addr, p_tcb->peer_bda, BD_ADDR_LEN);
+        *p_gatt_if = gatt_if;
+        *p_transport = p_tcb->transport;
+        status = true;
+    }
+    return status;
+}
+
+
+/*******************************************************************************
+**
+** Function         GATT_GetConnIdIfConnected
+**
+** Description      This function find the conn_id if the logical link for BD address
+**                  and applciation interface is connected
+**
+** Parameters        gatt_if: applicaiton interface (input)
+**                   bd_addr: peer device address. (input)
+**                   p_conn_id: connection id  (output)
+**                   transport: transport option
+**
+** Returns          true the logical link is connected
+**
+*******************************************************************************/
+bool    GATT_GetConnIdIfConnected(tGATT_IF gatt_if, BD_ADDR bd_addr, uint16_t *p_conn_id,
+                                  tBT_TRANSPORT transport)
+{
+    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
+    tGATT_TCB       *p_tcb= gatt_find_tcb_by_addr(bd_addr, transport);
+    bool            status=false;
+
+    if (p_reg && p_tcb && (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) )
+    {
+        *p_conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
+        status = true;
+    }
+
+    GATT_TRACE_API ("GATT_GetConnIdIfConnected status=%d", status);
+    return status;
+}
+
+
+/*******************************************************************************
+**
+** Function         GATT_Listen
+**
+** Description      This function start or stop LE advertisement and listen for
+**                  connection.
+**
+** Parameters       start: start or stop listening.
+**
+*******************************************************************************/
+void GATT_Listen(bool start)
+{
+    GATT_TRACE_API("GATT_Listen start=%d", start);
+    gatt_update_listen_mode(start ? GATT_LISTEN_TO_ALL : GATT_LISTEN_TO_NONE);
+}
+
+#endif
+
diff --git a/bt/stack/gatt/gatt_attr.cc b/bt/stack/gatt/gatt_attr.cc
new file mode 100644
index 0000000..d3733a6
--- /dev/null
+++ b/bt/stack/gatt/gatt_attr.cc
@@ -0,0 +1,472 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 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 main GATT server attributes access request
+ *  handling functions.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+#include "bt_utils.h"
+
+#include "gatt_api.h"
+#include "gatt_int.h"
+#include "btcore/include/uuid.h"
+#include "osi/include/osi.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+#define GATTP_MAX_NUM_INC_SVR       0
+#define GATTP_MAX_CHAR_NUM          2
+#define GATTP_MAX_ATTR_NUM          (GATTP_MAX_CHAR_NUM * 2 + GATTP_MAX_NUM_INC_SVR + 1)
+#define GATTP_MAX_CHAR_VALUE_SIZE   50
+
+#ifndef GATTP_ATTR_DB_SIZE
+#define GATTP_ATTR_DB_SIZE      GATT_DB_MEM_SIZE(GATTP_MAX_NUM_INC_SVR, GATTP_MAX_CHAR_NUM, GATTP_MAX_CHAR_VALUE_SIZE)
+#endif
+
+static void gatt_request_cback(uint16_t conn_id, uint32_t trans_id, uint8_t op_code, tGATTS_DATA *p_data);
+static void gatt_connect_cback(UNUSED_ATTR tGATT_IF gatt_if, BD_ADDR bda,
+			       uint16_t conn_id, bool    connected,
+              tGATT_DISCONN_REASON reason, tBT_TRANSPORT transport);
+static void gatt_disc_res_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_RES *p_data);
+static void gatt_disc_cmpl_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status);
+static void gatt_cl_op_cmpl_cback(UNUSED_ATTR uint16_t conn_id, UNUSED_ATTR tGATTC_OPTYPE op, UNUSED_ATTR tGATT_STATUS status,
+              UNUSED_ATTR tGATT_CL_COMPLETE *p_data);
+
+static void gatt_cl_start_config_ccc(tGATT_PROFILE_CLCB *p_clcb);
+
+
+static tGATT_CBACK gatt_profile_cback =
+{
+    gatt_connect_cback,
+    gatt_cl_op_cmpl_cback,
+    gatt_disc_res_cback,
+    gatt_disc_cmpl_cback,
+    gatt_request_cback,
+    NULL,
+    NULL
+} ;
+
+/*******************************************************************************
+**
+** Function         gatt_profile_find_conn_id_by_bd_addr
+**
+** Description      Find the connection ID by remote address
+**
+** Returns          Connection ID
+**
+*******************************************************************************/
+uint16_t gatt_profile_find_conn_id_by_bd_addr(BD_ADDR remote_bda)
+{
+    uint16_t conn_id = GATT_INVALID_CONN_ID;
+    GATT_GetConnIdIfConnected (gatt_cb.gatt_if, remote_bda, &conn_id, BT_TRANSPORT_LE);
+    return conn_id;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_profile_find_clcb_by_conn_id
+**
+** Description      find clcb by Connection ID
+**
+** Returns          Pointer to the found link conenction control block.
+**
+*******************************************************************************/
+static tGATT_PROFILE_CLCB *gatt_profile_find_clcb_by_conn_id(uint16_t conn_id)
+{
+    uint8_t i_clcb;
+    tGATT_PROFILE_CLCB    *p_clcb = NULL;
+
+    for (i_clcb = 0, p_clcb= gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS; i_clcb++, p_clcb++)
+    {
+        if (p_clcb->in_use && p_clcb->conn_id == conn_id)
+            return p_clcb;
+    }
+
+    return NULL;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_profile_find_clcb_by_bd_addr
+**
+** Description      The function searches all LCBs with macthing bd address.
+**
+** Returns          Pointer to the found link conenction control block.
+**
+*******************************************************************************/
+static tGATT_PROFILE_CLCB *gatt_profile_find_clcb_by_bd_addr(BD_ADDR bda, tBT_TRANSPORT transport)
+{
+    uint8_t i_clcb;
+    tGATT_PROFILE_CLCB    *p_clcb = NULL;
+
+    for (i_clcb = 0, p_clcb= gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS; i_clcb++, p_clcb++)
+    {
+        if (p_clcb->in_use && p_clcb->transport == transport &&
+            p_clcb->connected && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN))
+            return p_clcb;
+    }
+
+    return NULL;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_profile_clcb_alloc
+**
+** Description      The function allocates a GATT profile  connection link control block
+**
+** Returns           NULL if not found. Otherwise pointer to the connection link block.
+**
+*******************************************************************************/
+tGATT_PROFILE_CLCB *gatt_profile_clcb_alloc (uint16_t conn_id, BD_ADDR bda, tBT_TRANSPORT tranport)
+{
+    uint8_t                 i_clcb = 0;
+    tGATT_PROFILE_CLCB      *p_clcb = NULL;
+
+    for (i_clcb = 0, p_clcb= gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS; i_clcb++, p_clcb++)
+    {
+        if (!p_clcb->in_use)
+        {
+            p_clcb->in_use      = true;
+            p_clcb->conn_id     = conn_id;
+            p_clcb->connected   = true;
+            p_clcb->transport   = tranport;
+            memcpy (p_clcb->bda, bda, BD_ADDR_LEN);
+            break;
+        }
+    }
+    if(i_clcb < GATT_MAX_APPS)
+        return p_clcb;
+
+    return NULL;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_profile_clcb_dealloc
+**
+** Description      The function deallocates a GATT profile  connection link control block
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_profile_clcb_dealloc (tGATT_PROFILE_CLCB *p_clcb)
+{
+    memset(p_clcb, 0, sizeof(tGATT_PROFILE_CLCB));
+}
+
+/*******************************************************************************
+**
+** Function         gatt_request_cback
+**
+** Description      GATT profile attribute access request callback.
+**
+** Returns          void.
+**
+*******************************************************************************/
+static void gatt_request_cback (uint16_t conn_id, uint32_t trans_id, tGATTS_REQ_TYPE type,
+                                        tGATTS_DATA *p_data)
+{
+    uint8_t     status = GATT_INVALID_PDU;
+    tGATTS_RSP   rsp_msg ;
+    bool        ignore = false;
+
+    memset(&rsp_msg, 0, sizeof(tGATTS_RSP));
+
+    switch (type)
+    {
+        case GATTS_REQ_TYPE_READ_CHARACTERISTIC:
+        case GATTS_REQ_TYPE_READ_DESCRIPTOR:
+            status = GATT_READ_NOT_PERMIT;
+            break;
+
+        case GATTS_REQ_TYPE_WRITE_CHARACTERISTIC:
+        case GATTS_REQ_TYPE_WRITE_DESCRIPTOR:
+            status = GATT_WRITE_NOT_PERMIT;
+            break;
+
+        case GATTS_REQ_TYPE_WRITE_EXEC:
+        case GATT_CMD_WRITE:
+            ignore = true;
+            GATT_TRACE_EVENT("Ignore GATT_REQ_EXEC_WRITE/WRITE_CMD" );
+            break;
+
+        case GATTS_REQ_TYPE_MTU:
+            GATT_TRACE_EVENT("Get MTU exchange new mtu size: %d", p_data->mtu);
+            ignore = true;
+            break;
+
+        default:
+            GATT_TRACE_EVENT("Unknown/unexpected LE GAP ATT request: 0x%02x", type);
+            break;
+    }
+
+    if (!ignore)
+        GATTS_SendRsp (conn_id, trans_id, status, &rsp_msg);
+
+}
+
+/*******************************************************************************
+**
+** Function         gatt_connect_cback
+**
+** Description      Gatt profile connection callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gatt_connect_cback (UNUSED_ATTR tGATT_IF gatt_if, BD_ADDR bda,
+                                uint16_t conn_id,
+                                        bool    connected, tGATT_DISCONN_REASON reason,
+                                        tBT_TRANSPORT transport)
+{
+    GATT_TRACE_EVENT ("%s: from %08x%04x connected:%d conn_id=%d reason = 0x%04x", __FUNCTION__,
+                       (bda[0]<<24)+(bda[1]<<16)+(bda[2]<<8)+bda[3],
+                       (bda[4]<<8)+bda[5], connected, conn_id, reason);
+
+    tGATT_PROFILE_CLCB *p_clcb = gatt_profile_find_clcb_by_bd_addr(bda, transport);
+    if (p_clcb == NULL)
+        return;
+
+    if (connected)
+    {
+        p_clcb->conn_id = conn_id;
+        p_clcb->connected = true;
+
+        if (p_clcb->ccc_stage == GATT_SVC_CHANGED_CONNECTING)
+        {
+            p_clcb->ccc_stage ++;
+            gatt_cl_start_config_ccc(p_clcb);
+        }
+    } else {
+        gatt_profile_clcb_dealloc(p_clcb);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_profile_db_init
+**
+** Description      Initializa the GATT profile attribute database.
+**
+*******************************************************************************/
+void gatt_profile_db_init (void)
+{
+    tBT_UUID          app_uuid = {LEN_UUID_128, {0}};
+    uint16_t          service_handle = 0;
+
+    /* Fill our internal UUID with a fixed pattern 0x81 */
+    memset (&app_uuid.uu.uuid128, 0x81, LEN_UUID_128);
+
+    /* Create a GATT profile service */
+    gatt_cb.gatt_if = GATT_Register(&app_uuid, &gatt_profile_cback);
+    GATT_StartIf(gatt_cb.gatt_if);
+
+    bt_uuid_t service_uuid;
+    uuid_128_from_16(&service_uuid, UUID_SERVCLASS_GATT_SERVER);
+
+    bt_uuid_t char_uuid;
+    uuid_128_from_16(&char_uuid, 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}
+    };
+
+    GATTS_AddService(gatt_cb.gatt_if, service, sizeof(service)/sizeof(btgatt_db_element_t));
+
+    service_handle = service[0].attribute_handle;
+    gatt_cb.handle_of_h_r = service[1].attribute_handle;
+
+    GATT_TRACE_ERROR("gatt_profile_db_init:  gatt_if=%d", gatt_cb.gatt_if);
+}
+
+/*******************************************************************************
+**
+** Function         gatt_disc_res_cback
+**
+** Description      Gatt profile discovery result callback
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gatt_disc_res_cback (uint16_t conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_RES *p_data)
+{
+    tGATT_PROFILE_CLCB *p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id);
+
+    if (p_clcb == NULL)
+        return;
+
+    switch (disc_type)
+    {
+    case GATT_DISC_SRVC_BY_UUID:/* stage 1 */
+        p_clcb->e_handle = p_data->value.group_value.e_handle;
+        p_clcb->ccc_result ++;
+        break;
+
+    case GATT_DISC_CHAR:/* stage 2 */
+        p_clcb->s_handle = p_data->value.dclr_value.val_handle;
+        p_clcb->ccc_result ++;
+        break;
+
+    case GATT_DISC_CHAR_DSCPT: /* stage 3 */
+        if (p_data->type.uu.uuid16 == GATT_UUID_CHAR_CLIENT_CONFIG)
+        {
+            p_clcb->s_handle = p_data->handle;
+            p_clcb->ccc_result ++;
+        }
+        break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_disc_cmpl_cback
+**
+** Description      Gatt profile discovery complete callback
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gatt_disc_cmpl_cback (uint16_t conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status)
+{
+    tGATT_PROFILE_CLCB *p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id);
+
+    if (p_clcb == NULL)
+        return;
+
+    if (status == GATT_SUCCESS && p_clcb->ccc_result > 0)
+    {
+        p_clcb->ccc_result = 0;
+        p_clcb->ccc_stage ++;
+        gatt_cl_start_config_ccc(p_clcb);
+    } else {
+        GATT_TRACE_ERROR("%s() - Unable to register for service changed indication", __func__);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_cl_op_cmpl_cback
+**
+** Description      Gatt profile client operation complete callback
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gatt_cl_op_cmpl_cback (UNUSED_ATTR uint16_t conn_id, UNUSED_ATTR tGATTC_OPTYPE op,
+                                   UNUSED_ATTR tGATT_STATUS status,
+                                   UNUSED_ATTR tGATT_CL_COMPLETE *p_data)
+{
+}
+
+/*******************************************************************************
+**
+** Function         gatt_cl_start_config_ccc
+**
+** Description      Gatt profile start configure service change CCC
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gatt_cl_start_config_ccc(tGATT_PROFILE_CLCB *p_clcb)
+{
+    tGATT_DISC_PARAM    srvc_disc_param;
+    tGATT_VALUE         ccc_value;
+
+    GATT_TRACE_DEBUG("%s() - stage: %d", __func__, p_clcb->ccc_stage);
+
+    memset (&srvc_disc_param, 0 , sizeof(tGATT_DISC_PARAM));
+    memset (&ccc_value, 0 , sizeof(tGATT_VALUE));
+
+    switch(p_clcb->ccc_stage)
+    {
+    case GATT_SVC_CHANGED_SERVICE: /* discover GATT service */
+        srvc_disc_param.s_handle = 1;
+        srvc_disc_param.e_handle = 0xffff;
+        srvc_disc_param.service.len = 2;
+        srvc_disc_param.service.uu.uuid16 = UUID_SERVCLASS_GATT_SERVER;
+        GATTC_Discover(p_clcb->conn_id, GATT_DISC_SRVC_BY_UUID, &srvc_disc_param);
+        break;
+
+    case GATT_SVC_CHANGED_CHARACTERISTIC: /* discover service change char */
+        srvc_disc_param.s_handle = 1;
+        srvc_disc_param.e_handle = p_clcb->e_handle;
+        srvc_disc_param.service.len = 2;
+        srvc_disc_param.service.uu.uuid16 = GATT_UUID_GATT_SRV_CHGD;
+        GATTC_Discover(p_clcb->conn_id, GATT_DISC_CHAR, &srvc_disc_param);
+        break;
+
+    case GATT_SVC_CHANGED_DESCRIPTOR: /* discover service change ccc */
+        srvc_disc_param.s_handle = p_clcb->s_handle;
+        srvc_disc_param.e_handle = p_clcb->e_handle;
+        GATTC_Discover(p_clcb->conn_id, GATT_DISC_CHAR_DSCPT, &srvc_disc_param);
+        break;
+
+    case GATT_SVC_CHANGED_CONFIGURE_CCCD: /* write ccc */
+        ccc_value.handle = p_clcb->s_handle;
+        ccc_value.len = 2;
+        ccc_value.value[0] = GATT_CLT_CONFIG_INDICATION;
+        GATTC_Write(p_clcb->conn_id, GATT_WRITE, &ccc_value);
+        break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         GATT_ConfigServiceChangeCCC
+**
+** Description      Configure service change indication on remote device
+**
+** Returns          none
+**
+*******************************************************************************/
+void GATT_ConfigServiceChangeCCC (BD_ADDR remote_bda, bool    enable, tBT_TRANSPORT transport)
+{
+    tGATT_PROFILE_CLCB   *p_clcb = gatt_profile_find_clcb_by_bd_addr (remote_bda, transport);
+
+    if (p_clcb == NULL)
+        p_clcb = gatt_profile_clcb_alloc (0, remote_bda, transport);
+
+    if (p_clcb == NULL)
+        return;
+
+    if (GATT_GetConnIdIfConnected (gatt_cb.gatt_if, remote_bda, &p_clcb->conn_id, transport))
+    {
+        p_clcb->connected = true;
+    }
+    /* hold the link here */
+    GATT_Connect(gatt_cb.gatt_if, remote_bda, true, transport, true);
+    p_clcb->ccc_stage = GATT_SVC_CHANGED_CONNECTING;
+
+    if (!p_clcb->connected)
+    {
+        /* wait for connection */
+        return;
+    }
+
+    p_clcb->ccc_stage ++;
+    gatt_cl_start_config_ccc(p_clcb);
+}
+
+#endif  /* BLE_INCLUDED */
diff --git a/bt/stack/gatt/gatt_auth.cc b/bt/stack/gatt/gatt_auth.cc
new file mode 100644
index 0000000..034b253
--- /dev/null
+++ b/bt/stack/gatt/gatt_auth.cc
@@ -0,0 +1,534 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 GATT authentication handling functions
+ *
+ ******************************************************************************/
+#include "bt_target.h"
+#include "bt_utils.h"
+
+#if (BLE_INCLUDED == TRUE)
+#include <string.h>
+#include "bt_common.h"
+
+#include "gatt_int.h"
+#include "gatt_api.h"
+#include "btm_int.h"
+#include "osi/include/osi.h"
+
+/*******************************************************************************
+**
+** Function         gatt_sign_data
+**
+** Description      This function sign the data for write command.
+**
+** Returns          true if encrypted, otherwise false.
+**
+*******************************************************************************/
+static bool    gatt_sign_data (tGATT_CLCB *p_clcb)
+{
+    tGATT_VALUE         *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
+    uint8_t             *p_data = NULL, *p;
+    uint16_t            payload_size = p_clcb->p_tcb->payload_size;
+    bool                status = false;
+    uint8_t              *p_signature;
+
+    /* do not need to mark channel securoty activity for data signing */
+    gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_OK);
+
+    p_data = (uint8_t *)osi_malloc(p_attr->len + 3); /* 3 = 2 byte handle + opcode */
+
+    p = p_data;
+    UINT8_TO_STREAM(p, GATT_SIGN_CMD_WRITE);
+    UINT16_TO_STREAM(p, p_attr->handle);
+    ARRAY_TO_STREAM(p, p_attr->value, p_attr->len);
+
+    /* sign data length should be attribulte value length plus 2B handle + 1B op code */
+    if ((payload_size - GATT_AUTH_SIGN_LEN - 3) < p_attr->len)
+        p_attr->len = payload_size - GATT_AUTH_SIGN_LEN - 3;
+
+    p_signature = p_attr->value + p_attr->len;
+    if (BTM_BleDataSignature(p_clcb->p_tcb->peer_bda,
+                             p_data,
+                             (uint16_t)(p_attr->len + 3), /* 3 = 2 byte handle + opcode */
+                             p_signature)) {
+        p_attr->len += BTM_BLE_AUTH_SIGN_LEN;
+        gatt_set_ch_state(p_clcb->p_tcb, GATT_CH_OPEN);
+        gatt_act_write(p_clcb, GATT_SEC_SIGN_DATA);
+    } else {
+        gatt_end_operation(p_clcb, GATT_INTERNAL_ERROR, NULL);
+    }
+
+    osi_free(p_data);
+
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_verify_signature
+**
+** Description      This function start to verify the sign data when receiving
+**                  the data from peer device.
+**
+** Returns
+**
+*******************************************************************************/
+void gatt_verify_signature(tGATT_TCB *p_tcb, BT_HDR *p_buf)
+{
+    uint16_t cmd_len;
+    uint8_t op_code;
+    uint8_t *p, *p_orig = (uint8_t *)(p_buf + 1) + p_buf->offset;
+    uint32_t counter;
+
+    if (p_buf->len < GATT_AUTH_SIGN_LEN + 4) {
+        GATT_TRACE_ERROR("%s: Data length %u less than expected %u",
+                         __func__, p_buf->len, GATT_AUTH_SIGN_LEN + 4);
+        return;
+    }
+    cmd_len = p_buf->len - GATT_AUTH_SIGN_LEN + 4;
+    p =  p_orig + cmd_len - 4;
+    STREAM_TO_UINT32(counter, p);
+
+    if (BTM_BleVerifySignature(p_tcb->peer_bda, p_orig, cmd_len, counter, p))
+    {
+        STREAM_TO_UINT8(op_code, p_orig);
+        gatt_server_handle_client_req (p_tcb, op_code, (uint16_t)(p_buf->len - 1), p_orig);
+    }
+    else
+    {
+        /* if this is a bad signature, assume from attacker, ignore it  */
+        GATT_TRACE_ERROR("Signature Verification Failed, data ignored");
+    }
+
+    return;
+}
+/*******************************************************************************
+**
+** Function         gatt_sec_check_complete
+**
+** Description      security check complete and proceed to data sending action.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void gatt_sec_check_complete(bool    sec_check_ok, tGATT_CLCB   *p_clcb, uint8_t sec_act)
+{
+    if (p_clcb && p_clcb->p_tcb &&
+        fixed_queue_is_empty(p_clcb->p_tcb->pending_enc_clcb)) {
+        gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_NONE);
+    }
+
+    if (!sec_check_ok)
+    {
+        gatt_end_operation(p_clcb, GATT_AUTH_FAIL, NULL);
+    }
+    else if (p_clcb->operation == GATTC_OPTYPE_WRITE)
+    {
+        gatt_act_write(p_clcb, sec_act);
+    }
+    else if (p_clcb->operation == GATTC_OPTYPE_READ)
+    {
+        gatt_act_read(p_clcb, p_clcb->counter);
+    }
+}
+/*******************************************************************************
+**
+** Function         gatt_enc_cmpl_cback
+**
+** Description      link encryption complete callback.
+**
+** Returns
+**
+*******************************************************************************/
+void gatt_enc_cmpl_cback(BD_ADDR bd_addr, tBT_TRANSPORT transport,
+                         UNUSED_ATTR void *p_ref_data, tBTM_STATUS result)
+{
+    tGATT_TCB   *p_tcb;
+    uint8_t     sec_flag;
+    bool        status = false;
+
+    GATT_TRACE_DEBUG("gatt_enc_cmpl_cback");
+    if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, transport)) != NULL)
+    {
+        if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING)
+            return;
+
+        tGATT_PENDING_ENC_CLCB *p_buf =
+            (tGATT_PENDING_ENC_CLCB *)fixed_queue_try_dequeue(p_tcb->pending_enc_clcb);
+        if (p_buf != NULL)
+        {
+            if (result == BTM_SUCCESS)
+            {
+                if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENCRYPT_MITM )
+                {
+                    BTM_GetSecurityFlagsByTransport(bd_addr, &sec_flag, transport);
+
+                    if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED)
+                    {
+                        status = true;
+                    }
+                }
+                else
+                {
+                    status = true;
+                }
+            }
+            gatt_sec_check_complete(status, p_buf->p_clcb, p_tcb->sec_act);
+            osi_free(p_buf);
+            /* start all other pending operation in queue */
+            for (size_t count = fixed_queue_length(p_tcb->pending_enc_clcb);
+                 count > 0; count--)
+            {
+                p_buf = (tGATT_PENDING_ENC_CLCB *)fixed_queue_try_dequeue(p_tcb->pending_enc_clcb);
+                if (p_buf != NULL)
+                {
+                    gatt_security_check_start(p_buf->p_clcb);
+                    osi_free(p_buf);
+                }
+                else
+                    break;
+            }
+        }
+        else
+        {
+            GATT_TRACE_ERROR("Unknown operation encryption completed");
+        }
+    }
+    else
+    {
+        GATT_TRACE_ERROR("enc callback for unknown bd_addr");
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_notify_enc_cmpl
+**
+** Description      link encryption complete notification for all encryption process
+**                  initiated outside GATT.
+**
+** Returns
+**
+*******************************************************************************/
+void gatt_notify_enc_cmpl(BD_ADDR bd_addr)
+{
+    tGATT_TCB   *p_tcb;
+    uint8_t      i = 0;
+
+    if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE)) != NULL)
+    {
+        for (i = 0; i < GATT_MAX_APPS; i++)
+        {
+            if (gatt_cb.cl_rcb[i].in_use && gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb)
+            {
+                (*gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb)(gatt_cb.cl_rcb[i].gatt_if, bd_addr);
+            }
+        }
+
+        if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING)
+        {
+            gatt_set_sec_act(p_tcb, GATT_SEC_NONE);
+
+            size_t count = fixed_queue_length(p_tcb->pending_enc_clcb);
+            for (; count > 0; count--)
+            {
+                tGATT_PENDING_ENC_CLCB *p_buf =
+                    (tGATT_PENDING_ENC_CLCB *)fixed_queue_try_dequeue(p_tcb->pending_enc_clcb);
+                if (p_buf != NULL)
+                {
+                    gatt_security_check_start(p_buf->p_clcb);
+                    osi_free(p_buf);
+                }
+                else
+                    break;
+            }
+        }
+    }
+    else
+    {
+        GATT_TRACE_DEBUG("notify GATT for encryption completion of unknown device");
+    }
+    return;
+}
+/*******************************************************************************
+**
+** Function         gatt_set_sec_act
+**
+** Description      This function set the sec_act in clcb
+**
+** Returns          none
+**
+*******************************************************************************/
+void gatt_set_sec_act(tGATT_TCB *p_tcb, tGATT_SEC_ACTION sec_act)
+{
+    if (p_tcb)
+    {
+        p_tcb->sec_act = sec_act;
+    }
+}
+/*******************************************************************************
+**
+** Function         gatt_get_sec_act
+**
+** Description      This function get the sec_act in clcb
+**
+** Returns          none
+**
+*******************************************************************************/
+tGATT_SEC_ACTION gatt_get_sec_act(tGATT_TCB *p_tcb)
+{
+    tGATT_SEC_ACTION sec_act = GATT_SEC_NONE;
+    if (p_tcb)
+    {
+        sec_act = p_tcb->sec_act;
+    }
+    return sec_act;
+}
+/*******************************************************************************
+**
+** Function         gatt_determine_sec_act
+**
+** Description      This routine determine the security action based on auth_request and
+**                  current link status
+**
+** Returns          tGATT_SEC_ACTION security action
+**
+*******************************************************************************/
+tGATT_SEC_ACTION gatt_determine_sec_act(tGATT_CLCB *p_clcb )
+{
+    tGATT_SEC_ACTION    act = GATT_SEC_OK;
+    uint8_t             sec_flag;
+    tGATT_TCB           *p_tcb = p_clcb->p_tcb;
+    tGATT_AUTH_REQ      auth_req = p_clcb->auth_req;
+    bool                is_link_encrypted= false;
+    bool                is_link_key_known=false;
+    bool                is_key_mitm=false;
+    uint8_t             key_type;
+    tBTM_BLE_SEC_REQ_ACT    sec_act = BTM_LE_SEC_NONE;
+
+    if (auth_req == GATT_AUTH_REQ_NONE )
+        return act;
+
+    BTM_GetSecurityFlagsByTransport(p_tcb->peer_bda, &sec_flag, p_clcb->p_tcb->transport);
+
+    btm_ble_link_sec_check(p_tcb->peer_bda, auth_req, &sec_act);
+
+    /* if a encryption is pending, need to wait */
+    if (sec_act == BTM_BLE_SEC_REQ_ACT_DISCARD &&
+        auth_req != GATT_AUTH_REQ_NONE)
+        return GATT_SEC_ENC_PENDING;
+
+    if (sec_flag & (BTM_SEC_FLAG_ENCRYPTED| BTM_SEC_FLAG_LKEY_KNOWN))
+    {
+        if (sec_flag & BTM_SEC_FLAG_ENCRYPTED)
+            is_link_encrypted = true;
+
+        is_link_key_known = true;
+
+        if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED)
+            is_key_mitm = true;
+    }
+
+    /* first check link key upgrade required or not */
+    switch (auth_req)
+    {
+        case GATT_AUTH_REQ_MITM:
+        case GATT_AUTH_REQ_SIGNED_MITM:
+            if (!is_key_mitm)
+                act = GATT_SEC_ENCRYPT_MITM;
+            break;
+
+        case GATT_AUTH_REQ_NO_MITM:
+        case GATT_AUTH_REQ_SIGNED_NO_MITM:
+            if (!is_link_key_known)
+                act = GATT_SEC_ENCRYPT_NO_MITM;
+            break;
+        default:
+            break;
+    }
+
+    /* now check link needs to be encrypted or not if the link key upgrade is not required */
+    if (act == GATT_SEC_OK)
+    {
+        if (p_tcb->transport == BT_TRANSPORT_LE &&
+            (p_clcb->operation == GATTC_OPTYPE_WRITE) &&
+            (p_clcb->op_subtype == GATT_WRITE_NO_RSP))
+        {
+            /* this is a write command request
+               check data signing required or not */
+            if (!is_link_encrypted)
+            {
+                btm_ble_get_enc_key_type(p_tcb->peer_bda, &key_type);
+
+                if ( (key_type & BTM_LE_KEY_LCSRK) &&
+                     ((auth_req == GATT_AUTH_REQ_SIGNED_NO_MITM) ||
+                      (auth_req == GATT_AUTH_REQ_SIGNED_MITM)))
+                {
+                    act = GATT_SEC_SIGN_DATA;
+                }
+                else
+                {
+                    act = GATT_SEC_ENCRYPT;
+                }
+            }
+        }
+        else
+        {
+            if (!is_link_encrypted)
+            {
+                act = GATT_SEC_ENCRYPT;
+            }
+        }
+
+    }
+
+    return  act ;
+
+}
+
+
+
+/*******************************************************************************
+**
+** Function         gatt_get_link_encrypt_status
+**
+** Description      This routine get the encryption status of the specified link
+**
+**
+** Returns          tGATT_STATUS link encryption status
+**
+*******************************************************************************/
+tGATT_STATUS gatt_get_link_encrypt_status(tGATT_TCB *p_tcb)
+{
+    tGATT_STATUS    encrypt_status = GATT_NOT_ENCRYPTED;
+    uint8_t         sec_flag=0;
+
+    BTM_GetSecurityFlagsByTransport(p_tcb->peer_bda, &sec_flag, p_tcb->transport);
+
+    if ((sec_flag & BTM_SEC_FLAG_ENCRYPTED) && (sec_flag & BTM_SEC_FLAG_LKEY_KNOWN))
+    {
+        encrypt_status = GATT_ENCRYPED_NO_MITM;
+        if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED)
+            encrypt_status = GATT_ENCRYPED_MITM;
+    }
+
+    GATT_TRACE_DEBUG("gatt_get_link_encrypt_status status=0x%x",encrypt_status);
+    return  encrypt_status ;
+}
+
+
+/*******************************************************************************
+**
+** Function          gatt_convert_sec_action
+**
+** Description      Convert GATT security action enum into equivalent BTM BLE security action enum
+**
+** Returns          bool    true - conversation is successful
+**
+*******************************************************************************/
+static bool    gatt_convert_sec_action(tGATT_SEC_ACTION gatt_sec_act, tBTM_BLE_SEC_ACT *p_btm_sec_act )
+{
+    bool    status = true;
+    switch (gatt_sec_act)
+    {
+        case GATT_SEC_ENCRYPT:
+            *p_btm_sec_act = BTM_BLE_SEC_ENCRYPT;
+            break;
+        case GATT_SEC_ENCRYPT_NO_MITM:
+            *p_btm_sec_act = BTM_BLE_SEC_ENCRYPT_NO_MITM;
+            break;
+        case GATT_SEC_ENCRYPT_MITM:
+            *p_btm_sec_act = BTM_BLE_SEC_ENCRYPT_MITM;
+            break;
+        default:
+            status = false;
+            break;
+    }
+
+    return status;
+}
+/*******************************************************************************
+**
+** Function         gatt_check_enc_req
+**
+** Description      check link security.
+**
+** Returns          true if encrypted, otherwise false.
+**
+*******************************************************************************/
+bool    gatt_security_check_start(tGATT_CLCB *p_clcb)
+{
+    tGATT_TCB           *p_tcb = p_clcb->p_tcb;
+    tGATT_SEC_ACTION    gatt_sec_act;
+    tBTM_BLE_SEC_ACT    btm_ble_sec_act;
+    bool                status = true;
+    tBTM_STATUS         btm_status;
+    tGATT_SEC_ACTION    sec_act_old =  gatt_get_sec_act(p_tcb);
+
+    gatt_sec_act = gatt_determine_sec_act(p_clcb);
+
+    if (sec_act_old == GATT_SEC_NONE)
+        gatt_set_sec_act(p_tcb, gatt_sec_act);
+
+    switch (gatt_sec_act )
+    {
+        case GATT_SEC_SIGN_DATA:
+            GATT_TRACE_DEBUG("gatt_security_check_start: Do data signing");
+            gatt_sign_data(p_clcb);
+            break;
+        case GATT_SEC_ENCRYPT:
+        case GATT_SEC_ENCRYPT_NO_MITM:
+        case GATT_SEC_ENCRYPT_MITM:
+            if (sec_act_old < GATT_SEC_ENCRYPT)
+            {
+                GATT_TRACE_DEBUG("gatt_security_check_start: Encrypt now or key upgreade first");
+                gatt_convert_sec_action(gatt_sec_act, &btm_ble_sec_act);
+                btm_status = BTM_SetEncryption(p_tcb->peer_bda, p_tcb->transport,
+                                               gatt_enc_cmpl_cback, NULL, btm_ble_sec_act);
+                if ( (btm_status != BTM_SUCCESS) && (btm_status != BTM_CMD_STARTED))
+                {
+                    GATT_TRACE_ERROR("gatt_security_check_start BTM_SetEncryption failed btm_status=%d", btm_status);
+                    status = false;
+                }
+            }
+            if (status)
+                gatt_add_pending_enc_channel_clcb (p_tcb, p_clcb);
+            break;
+        case GATT_SEC_ENC_PENDING:
+            gatt_add_pending_enc_channel_clcb (p_tcb, p_clcb);
+            /* wait for link encrypotion to finish */
+            break;
+        default:
+            gatt_sec_check_complete(true, p_clcb, gatt_sec_act);
+            break;
+    }
+
+    if (status == false)
+    {
+        gatt_set_sec_act(p_tcb, GATT_SEC_NONE);
+        gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
+    }
+
+    return status;
+}
+
+
+#endif  /* BLE_INCLUDED */
diff --git a/bt/stack/gatt/gatt_cl.cc b/bt/stack/gatt/gatt_cl.cc
new file mode 100644
index 0000000..b522dfd
--- /dev/null
+++ b/bt/stack/gatt/gatt_cl.cc
@@ -0,0 +1,1252 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 main GATT client functions
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+#include <string.h>
+#include "bt_utils.h"
+#include "bt_common.h"
+#include "gatt_int.h"
+#include "l2c_int.h"
+#include "osi/include/osi.h"
+
+#define GATT_WRITE_LONG_HDR_SIZE    5 /* 1 opcode + 2 handle + 2 offset */
+#define GATT_READ_CHAR_VALUE_HDL    (GATT_READ_CHAR_VALUE | 0x80)
+#define GATT_READ_INC_SRV_UUID128   (GATT_DISC_INC_SRVC   | 0x90)
+
+#define GATT_PREP_WRITE_RSP_MIN_LEN 4
+#define GATT_NOTIFICATION_MIN_LEN 2
+#define GATT_WRITE_RSP_MIN_LEN  2
+#define GATT_INFO_RSP_MIN_LEN   1
+#define GATT_MTU_RSP_MIN_LEN    2
+#define GATT_READ_BY_TYPE_RSP_MIN_LEN    1
+
+/********************************************************************************
+**                       G L O B A L      G A T T       D A T A                 *
+*********************************************************************************/
+void gatt_send_prepare_write(tGATT_TCB  *p_tcb, tGATT_CLCB *p_clcb);
+
+uint8_t disc_type_to_att_opcode[GATT_DISC_MAX] =
+{
+    0,
+    GATT_REQ_READ_BY_GRP_TYPE,     /*  GATT_DISC_SRVC_ALL = 1, */
+    GATT_REQ_FIND_TYPE_VALUE,      /*  GATT_DISC_SRVC_BY_UUID,  */
+    GATT_REQ_READ_BY_TYPE,         /*  GATT_DISC_INC_SRVC,      */
+    GATT_REQ_READ_BY_TYPE,         /*  GATT_DISC_CHAR,          */
+    GATT_REQ_FIND_INFO             /*  GATT_DISC_CHAR_DSCPT,    */
+};
+
+uint16_t disc_type_to_uuid[GATT_DISC_MAX] =
+{
+    0,                  /* reserved */
+    GATT_UUID_PRI_SERVICE, /* <service> DISC_SRVC_ALL */
+    GATT_UUID_PRI_SERVICE, /* <service> for DISC_SERVC_BY_UUID */
+    GATT_UUID_INCLUDE_SERVICE, /* <include_service> for DISC_INC_SRVC */
+    GATT_UUID_CHAR_DECLARE,   /* <characteristic> for DISC_CHAR */
+    0                   /* no type filtering for DISC_CHAR_DSCPT */
+};
+
+
+/*******************************************************************************
+**
+** Function         gatt_act_discovery
+**
+** Description      GATT discovery operation.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void gatt_act_discovery(tGATT_CLCB *p_clcb)
+{
+    uint8_t     op_code = disc_type_to_att_opcode[p_clcb->op_subtype];
+    tGATT_CL_MSG   cl_req;
+    tGATT_STATUS    st;
+
+    if (p_clcb->s_handle <= p_clcb->e_handle && p_clcb->s_handle != 0)
+    {
+        memset(&cl_req, 0, sizeof(tGATT_CL_MSG));
+
+        cl_req.browse.s_handle = p_clcb->s_handle;
+        cl_req.browse.e_handle = p_clcb->e_handle;
+
+        if (disc_type_to_uuid[p_clcb->op_subtype] != 0)
+        {
+            cl_req.browse.uuid.len = 2;
+            cl_req.browse.uuid.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
+        }
+
+        if (p_clcb->op_subtype == GATT_DISC_SRVC_BY_UUID) /* fill in the FindByTypeValue request info*/
+        {
+            cl_req.find_type_value.uuid.len = 2;
+            cl_req.find_type_value.uuid.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
+            cl_req.find_type_value.s_handle = p_clcb->s_handle;
+            cl_req.find_type_value.e_handle = p_clcb->e_handle;
+            cl_req.find_type_value.value_len = p_clcb->uuid.len;
+            /* if service type is 32 bits UUID, convert it now */
+            if (p_clcb->uuid.len == LEN_UUID_32)
+            {
+                cl_req.find_type_value.value_len = LEN_UUID_128;
+                gatt_convert_uuid32_to_uuid128(cl_req.find_type_value.value, p_clcb->uuid.uu.uuid32);
+            }
+            else
+            memcpy (cl_req.find_type_value.value,  &p_clcb->uuid.uu, p_clcb->uuid.len);
+        }
+
+        st = attp_send_cl_msg(p_clcb->p_tcb, p_clcb->clcb_idx, op_code, &cl_req);
+
+        if (st !=  GATT_SUCCESS && st != GATT_CMD_STARTED)
+        {
+            gatt_end_operation(p_clcb, GATT_ERROR, NULL);
+        }
+    }
+    else /* end of handle range */
+        gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         gatt_act_read
+**
+** Description      GATT read operation.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void gatt_act_read (tGATT_CLCB *p_clcb, uint16_t offset)
+{
+    tGATT_TCB  *p_tcb = p_clcb->p_tcb;
+    uint8_t rt = GATT_INTERNAL_ERROR;
+    tGATT_CL_MSG  msg;
+    uint8_t      op_code = 0;
+
+    memset (&msg, 0, sizeof(tGATT_CL_MSG));
+
+    switch (p_clcb->op_subtype)
+    {
+        case GATT_READ_CHAR_VALUE:
+        case GATT_READ_BY_TYPE:
+            op_code = GATT_REQ_READ_BY_TYPE;
+            msg.browse.s_handle = p_clcb->s_handle;
+            msg.browse.e_handle = p_clcb->e_handle;
+            if (p_clcb->op_subtype == GATT_READ_BY_TYPE)
+                memcpy(&msg.browse.uuid, &p_clcb->uuid, sizeof(tBT_UUID));
+            else
+            {
+                msg.browse.uuid.len = LEN_UUID_16;
+                msg.browse.uuid.uu.uuid16 = GATT_UUID_CHAR_DECLARE;
+            }
+            break;
+
+        case GATT_READ_CHAR_VALUE_HDL:
+        case GATT_READ_BY_HANDLE:
+            if (!p_clcb->counter)
+            {
+                op_code = GATT_REQ_READ;
+                msg.handle = p_clcb->s_handle;
+            }
+            else
+            {
+                if (!p_clcb->first_read_blob_after_read)
+                    p_clcb->first_read_blob_after_read = true;
+                else
+                    p_clcb->first_read_blob_after_read = false;
+
+                GATT_TRACE_DEBUG("gatt_act_read first_read_blob_after_read=%d",
+                                  p_clcb->first_read_blob_after_read);
+                op_code = GATT_REQ_READ_BLOB;
+                msg.read_blob.offset = offset;
+                msg.read_blob.handle = p_clcb->s_handle;
+            }
+            p_clcb->op_subtype &= ~ 0x80;
+            break;
+
+        case GATT_READ_PARTIAL:
+            op_code = GATT_REQ_READ_BLOB;
+            msg.read_blob.handle = p_clcb->s_handle;
+            msg.read_blob.offset = offset;
+            break;
+
+        case GATT_READ_MULTIPLE:
+            op_code = GATT_REQ_READ_MULTI;
+            memcpy (&msg.read_multi, p_clcb->p_attr_buf, sizeof(tGATT_READ_MULTI));
+            break;
+
+        case GATT_READ_INC_SRV_UUID128:
+            op_code = GATT_REQ_READ;
+            msg.handle = p_clcb->s_handle;
+            p_clcb->op_subtype &= ~ 0x90;
+            break;
+
+        default:
+            GATT_TRACE_ERROR("Unknown read type: %d", p_clcb->op_subtype);
+            break;
+    }
+
+    if (op_code != 0)
+        rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, op_code, &msg);
+
+    if ( op_code == 0 || (rt != GATT_SUCCESS && rt != GATT_CMD_STARTED))
+    {
+        gatt_end_operation(p_clcb, rt, NULL);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_act_write
+**
+** Description      GATT write operation.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void gatt_act_write (tGATT_CLCB *p_clcb, uint8_t sec_act)
+{
+    tGATT_TCB           *p_tcb = p_clcb->p_tcb;
+    uint8_t             rt = GATT_SUCCESS, op_code = 0;
+    tGATT_VALUE         *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
+
+    if (p_attr)
+    {
+        switch (p_clcb->op_subtype)
+        {
+            case GATT_WRITE_NO_RSP:
+                p_clcb->s_handle = p_attr->handle;
+                op_code = (sec_act == GATT_SEC_SIGN_DATA) ? GATT_SIGN_CMD_WRITE : GATT_CMD_WRITE;
+                rt = gatt_send_write_msg(p_tcb,
+                                         p_clcb->clcb_idx,
+                                         op_code,
+                                         p_attr->handle,
+                                         p_attr->len,
+                                         0,
+                                         p_attr->value);
+                break;
+
+            case GATT_WRITE:
+                if (p_attr->len <= (p_tcb->payload_size - GATT_HDR_SIZE))
+                {
+                    p_clcb->s_handle = p_attr->handle;
+
+                    rt = gatt_send_write_msg(p_tcb,
+                                             p_clcb->clcb_idx,
+                                             GATT_REQ_WRITE,
+                                             p_attr->handle,
+                                             p_attr->len,
+                                             0,
+                                             p_attr->value);
+                }
+                else /* prepare write for long attribute */
+                {
+                    gatt_send_prepare_write(p_tcb, p_clcb);
+                }
+                break;
+
+            case GATT_WRITE_PREPARE:
+                gatt_send_prepare_write(p_tcb, p_clcb);
+                break;
+
+            default:
+                rt = GATT_INTERNAL_ERROR;
+                GATT_TRACE_ERROR("Unknown write type: %d", p_clcb->op_subtype);
+                break;
+        }
+    }
+    else
+        rt = GATT_INTERNAL_ERROR;
+
+    if ((rt != GATT_SUCCESS  && rt != GATT_CMD_STARTED && rt != GATT_CONGESTED)
+        || (rt != GATT_CMD_STARTED && p_clcb->op_subtype == GATT_WRITE_NO_RSP))
+    {
+        if (rt != GATT_SUCCESS)
+        {
+            GATT_TRACE_ERROR("gatt_act_write() failed op_code=0x%x rt=%d", op_code, rt);
+        }
+        gatt_end_operation(p_clcb, rt, NULL);
+    }
+}
+/*******************************************************************************
+**
+** Function         gatt_send_queue_write_cancel
+**
+** Description      send queue write cancel
+**
+** Returns          void.
+**
+*******************************************************************************/
+void gatt_send_queue_write_cancel (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, tGATT_EXEC_FLAG flag)
+{
+    uint8_t     rt ;
+
+    GATT_TRACE_DEBUG("gatt_send_queue_write_cancel ");
+
+    rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, GATT_REQ_EXEC_WRITE, (tGATT_CL_MSG *)&flag);
+
+    if (rt != GATT_SUCCESS)
+    {
+        gatt_end_operation(p_clcb, rt, NULL);
+    }
+}
+/*******************************************************************************
+**
+** Function         gatt_check_write_long_terminate
+**
+** Description      To terminate write long or not.
+**
+** Returns          true: write long is terminated; false keep sending.
+**
+*******************************************************************************/
+bool    gatt_check_write_long_terminate(tGATT_TCB  *p_tcb, tGATT_CLCB *p_clcb, tGATT_VALUE *p_rsp_value)
+{
+    tGATT_VALUE         *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
+    bool                exec = false;
+    tGATT_EXEC_FLAG     flag = GATT_PREP_WRITE_EXEC;
+
+    GATT_TRACE_DEBUG("gatt_check_write_long_terminate ");
+    /* check the first write response status */
+    if (p_rsp_value != NULL)
+    {
+        if (p_rsp_value->handle != p_attr->handle ||
+            p_rsp_value->len != p_clcb->counter ||
+            memcmp(p_rsp_value->value, p_attr->value + p_attr->offset, p_rsp_value->len))
+        {
+            /* data does not match    */
+            p_clcb->status = GATT_ERROR;
+            flag = GATT_PREP_WRITE_CANCEL;
+            exec = true;
+        }
+        else /* response checking is good */
+        {
+            p_clcb->status = GATT_SUCCESS;
+            /* update write offset and check if end of attribute value */
+            if ((p_attr->offset += p_rsp_value->len) >= p_attr->len)
+                exec = true;
+        }
+    }
+    if (exec)
+    {
+        gatt_send_queue_write_cancel (p_tcb, p_clcb, flag);
+        return true;
+    }
+    return false;
+}
+/*******************************************************************************
+**
+** Function         gatt_send_prepare_write
+**
+** Description      Send prepare write.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void gatt_send_prepare_write(tGATT_TCB  *p_tcb, tGATT_CLCB *p_clcb)
+{
+    tGATT_VALUE  *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
+    uint16_t to_send, offset;
+    uint8_t rt = GATT_SUCCESS;
+    uint8_t type = p_clcb->op_subtype;
+
+    GATT_TRACE_DEBUG("gatt_send_prepare_write type=0x%x", type );
+    to_send = p_attr->len - p_attr->offset;
+
+    if (to_send > (p_tcb->payload_size - GATT_WRITE_LONG_HDR_SIZE)) /* 2 = uint16_t offset bytes  */
+        to_send = p_tcb->payload_size - GATT_WRITE_LONG_HDR_SIZE;
+
+    p_clcb->s_handle = p_attr->handle;
+
+    offset = p_attr->offset;
+    if (type == GATT_WRITE_PREPARE)
+    {
+        offset += p_clcb->start_offset;
+    }
+
+    GATT_TRACE_DEBUG("offset =0x%x len=%d", offset, to_send );
+
+    rt = gatt_send_write_msg(p_tcb,
+                             p_clcb->clcb_idx,
+                             GATT_REQ_PREPARE_WRITE,
+                             p_attr->handle,
+                             to_send,                           /* length */
+                             offset,                            /* used as offset */
+                             p_attr->value + p_attr->offset);   /* data */
+
+    /* remember the write long attribute length */
+    p_clcb->counter = to_send;
+
+    if (rt != GATT_SUCCESS && rt != GATT_CMD_STARTED)
+    {
+        gatt_end_operation(p_clcb, rt, NULL);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         gatt_process_find_type_value_rsp
+**
+** Description      This function is called to handle find by type value response.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_process_find_type_value_rsp (UNUSED_ATTR tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb,
+				       uint16_t len, uint8_t *p_data)
+{
+    tGATT_DISC_RES      result;
+    uint8_t             *p = p_data;
+
+    GATT_TRACE_DEBUG("gatt_process_find_type_value_rsp ");
+    /* unexpected response */
+    if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY || p_clcb->op_subtype != GATT_DISC_SRVC_BY_UUID)
+        return;
+
+    memset (&result, 0, sizeof(tGATT_DISC_RES));
+    result.type.len = 2;
+    result.type.uu.uuid16 = GATT_UUID_PRI_SERVICE;
+
+    /* returns a series of handle ranges */
+    while (len >= 4)
+    {
+        STREAM_TO_UINT16 (result.handle, p);
+        STREAM_TO_UINT16 (result.value.group_value.e_handle, p);
+        memcpy (&result.value.group_value.service_type,  &p_clcb->uuid, sizeof(tBT_UUID));
+
+        len -= 4;
+
+        if (p_clcb->p_reg->app_cb.p_disc_res_cb)
+            (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);
+    }
+
+    /* last handle  + 1 */
+    p_clcb->s_handle = (result.value.group_value.e_handle == 0) ? 0 : (result.value.group_value.e_handle + 1);
+    /* initiate another request */
+    gatt_act_discovery(p_clcb) ;
+}
+/*******************************************************************************
+**
+** Function         gatt_process_read_info_rsp
+**
+** Description      This function is called to handle the read information
+**                  response.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_process_read_info_rsp(UNUSED_ATTR tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UNUSED_ATTR uint8_t op_code,
+                                uint16_t len, uint8_t *p_data)
+{
+    tGATT_DISC_RES  result;
+    uint8_t *p = p_data, uuid_len = 0, type;
+
+    if (len < GATT_INFO_RSP_MIN_LEN)
+    {
+        GATT_TRACE_ERROR("invalid Info Response PDU received, discard.");
+        gatt_end_operation(p_clcb, GATT_INVALID_PDU, NULL);
+        return;
+    }
+    /* unexpected response */
+    if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY || p_clcb->op_subtype != GATT_DISC_CHAR_DSCPT)
+        return;
+
+    STREAM_TO_UINT8(type, p);
+    len -= 1;
+
+    if (type == GATT_INFO_TYPE_PAIR_16)
+        uuid_len = LEN_UUID_16;
+    else if (type == GATT_INFO_TYPE_PAIR_128)
+        uuid_len = LEN_UUID_128;
+
+    while (len >= uuid_len + 2)
+    {
+        STREAM_TO_UINT16 (result.handle, p);
+
+        if (uuid_len > 0)
+        {
+            if (!gatt_parse_uuid_from_cmd(&result.type, uuid_len, &p))
+                break;
+        }
+        else
+            memcpy (&result.type, &p_clcb->uuid, sizeof(tBT_UUID));
+
+        len -= (uuid_len + 2);
+
+        if (p_clcb->p_reg->app_cb.p_disc_res_cb)
+            (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);
+    }
+
+    p_clcb->s_handle = (result.handle == 0) ? 0 :(result.handle + 1);
+    /* initiate another request */
+    gatt_act_discovery(p_clcb) ;
+}
+/*******************************************************************************
+**
+** Function         gatt_proc_disc_error_rsp
+**
+** Description      This function process the read by type response and send another
+**                  request if needed.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void gatt_proc_disc_error_rsp(UNUSED_ATTR tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb,
+                              uint8_t opcode,
+                              UNUSED_ATTR uint16_t handle, uint8_t reason)
+{
+    tGATT_STATUS    status = (tGATT_STATUS) reason;
+
+    GATT_TRACE_DEBUG("gatt_proc_disc_error_rsp reason: %02x cmd_code %04x", reason, opcode);
+
+    switch (opcode)
+    {
+        case GATT_REQ_READ_BY_GRP_TYPE:
+        case GATT_REQ_FIND_TYPE_VALUE:
+        case GATT_REQ_READ_BY_TYPE:
+        case GATT_REQ_FIND_INFO:
+            if (reason == GATT_NOT_FOUND)
+            {
+                status = GATT_SUCCESS;
+                GATT_TRACE_DEBUG("Discovery completed");
+            }
+            break;
+        default:
+            GATT_TRACE_ERROR("Incorrect discovery opcode %04x",   opcode);
+            break;
+    }
+
+    gatt_end_operation(p_clcb, status, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         gatt_process_error_rsp
+**
+** Description      This function is called to handle the error response
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_process_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UNUSED_ATTR uint8_t op_code,
+                            UNUSED_ATTR uint16_t len, uint8_t *p_data)
+{
+    uint8_t opcode, reason, * p= p_data;
+    uint16_t handle;
+    tGATT_VALUE  *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
+
+    GATT_TRACE_DEBUG("gatt_process_error_rsp ");
+    STREAM_TO_UINT8(opcode, p);
+    STREAM_TO_UINT16(handle, p);
+    STREAM_TO_UINT8(reason, p);
+
+    if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY)
+    {
+        gatt_proc_disc_error_rsp(p_tcb, p_clcb, opcode, handle, reason);
+    }
+    else
+    {
+        if ( (p_clcb->operation == GATTC_OPTYPE_WRITE) &&
+             (p_clcb->op_subtype == GATT_WRITE) &&
+             (opcode == GATT_REQ_PREPARE_WRITE) &&
+             (p_attr) &&
+             (handle == p_attr->handle)  )
+        {
+            p_clcb->status = reason;
+            gatt_send_queue_write_cancel(p_tcb, p_clcb, GATT_PREP_WRITE_CANCEL);
+        }
+        else if ((p_clcb->operation == GATTC_OPTYPE_READ) &&
+                 ((p_clcb->op_subtype == GATT_READ_CHAR_VALUE_HDL) ||
+                  (p_clcb->op_subtype == GATT_READ_BY_HANDLE)) &&
+                 (opcode == GATT_REQ_READ_BLOB) &&
+                 p_clcb->first_read_blob_after_read &&
+                 (reason == GATT_NOT_LONG))
+        {
+            gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p_clcb->p_attr_buf);
+        }
+        else
+            gatt_end_operation(p_clcb, reason, NULL);
+    }
+}
+/*******************************************************************************
+**
+** Function         gatt_process_prep_write_rsp
+**
+** Description      This function is called to handle the read response
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_process_prep_write_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, uint8_t op_code,
+                                  uint16_t len, uint8_t *p_data)
+{
+    uint8_t *p = p_data;
+
+    tGATT_VALUE value = {
+        .conn_id = p_clcb->conn_id,
+        .auth_req = GATT_AUTH_REQ_NONE,
+    };
+
+    GATT_TRACE_ERROR("value resp op_code = %s len = %d", gatt_dbg_op_name(op_code), len);
+
+    if (len < GATT_PREP_WRITE_RSP_MIN_LEN)
+    {
+        GATT_TRACE_ERROR("illegal prepare write response length, discard");
+        gatt_end_operation(p_clcb, GATT_INVALID_PDU, &value);
+        return;
+    }
+
+    STREAM_TO_UINT16 (value.handle, p);
+    STREAM_TO_UINT16 (value.offset, p);
+
+    value.len = len - 4;
+
+    memcpy (value.value, p, value.len);
+
+    if (p_clcb->op_subtype == GATT_WRITE_PREPARE)
+    {
+        p_clcb->status = GATT_SUCCESS;
+        /* application should verify handle offset
+           and value are matched or not */
+
+        gatt_end_operation(p_clcb, p_clcb->status, &value);
+    }
+    else if (p_clcb->op_subtype == GATT_WRITE )
+    {
+        if (!gatt_check_write_long_terminate(p_tcb, p_clcb, &value))
+            gatt_send_prepare_write(p_tcb, p_clcb);
+    }
+
+}
+/*******************************************************************************
+**
+** Function         gatt_process_notification
+**
+** Description      This function is called to handle the handle value indication
+**                  or handle value notification.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_process_notification(tGATT_TCB *p_tcb, uint8_t op_code,
+                               uint16_t len, uint8_t *p_data)
+{
+    tGATT_VALUE     value;
+    tGATT_REG       *p_reg;
+    uint16_t        conn_id;
+    tGATT_STATUS    encrypt_status;
+    uint8_t         *p= p_data, i,
+    event = (op_code == GATT_HANDLE_VALUE_NOTIF) ? GATTC_OPTYPE_NOTIFICATION : GATTC_OPTYPE_INDICATION;
+
+    GATT_TRACE_DEBUG("gatt_process_notification ");
+
+    if (len < GATT_NOTIFICATION_MIN_LEN)
+    {
+        GATT_TRACE_ERROR("illegal notification PDU length, discard");
+        return;
+    }
+
+    memset(&value, 0, sizeof(value));
+    STREAM_TO_UINT16(value.handle, p);
+    value.len = len - 2;
+    memcpy (value.value, p, value.len);
+
+    if (!GATT_HANDLE_IS_VALID(value.handle))
+    {
+        /* illegal handle, send ack now */
+        if (op_code == GATT_HANDLE_VALUE_IND)
+            attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
+        return;
+    }
+
+    if (event == GATTC_OPTYPE_INDICATION)
+    {
+        if (p_tcb->ind_count)
+        {
+            /* this is an error case that receiving an indication but we
+               still has an indication not being acked yet.
+               For now, just log the error reset the counter.
+               Later we need to disconnect the link unconditionally.
+            */
+            GATT_TRACE_ERROR("gatt_process_notification rcv Ind. but ind_count=%d (will reset ind_count)",  p_tcb->ind_count);
+        }
+        p_tcb->ind_count = 0;
+    }
+
+    /* should notify all registered client with the handle value notificaion/indication
+       Note: need to do the indication count and start timer first then do callback
+     */
+
+    for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++)
+    {
+        if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb && (event == GATTC_OPTYPE_INDICATION))
+            p_tcb->ind_count++;
+    }
+
+    if (event == GATTC_OPTYPE_INDICATION)
+    {
+        /* start a timer for app confirmation */
+        if (p_tcb->ind_count > 0)
+            gatt_start_ind_ack_timer(p_tcb);
+        else /* no app to indicate, or invalid handle */
+            attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
+    }
+
+    encrypt_status = gatt_get_link_encrypt_status(p_tcb);
+    for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++)
+    {
+        if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb)
+        {
+            conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
+            (*p_reg->app_cb.p_cmpl_cb) (conn_id, event, encrypt_status, (tGATT_CL_COMPLETE *)&value);
+        }
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         gatt_process_read_by_type_rsp
+**
+** Description      This function is called to handle the read by type response.
+**                  read by type can be used for discovery, or read by type or
+**                  read characteristic value.
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, uint8_t op_code,
+                                    uint16_t len, uint8_t *p_data)
+{
+    tGATT_DISC_RES      result;
+    tGATT_DISC_VALUE    record_value;
+    uint8_t             *p = p_data, value_len, handle_len = 2;
+    uint16_t            handle = 0;
+
+    /* discovery procedure and no callback function registered */
+    if (((!p_clcb->p_reg) || (!p_clcb->p_reg->app_cb.p_disc_res_cb)) && (p_clcb->operation == GATTC_OPTYPE_DISCOVERY))
+        return;
+
+    if (len < GATT_READ_BY_TYPE_RSP_MIN_LEN)
+    {
+        GATT_TRACE_ERROR("Illegal ReadByType/ReadByGroupType Response length, discard");
+        gatt_end_operation(p_clcb, GATT_INVALID_PDU, NULL);
+        return;
+    }
+
+    STREAM_TO_UINT8(value_len, p);
+
+    if ((value_len > (p_tcb->payload_size - 2)) || (value_len > (len-1))  )
+    {
+        /* this is an error case that server's response containing a value length which is larger than MTU-2
+           or value_len > message total length -1 */
+        GATT_TRACE_ERROR("gatt_process_read_by_type_rsp: Discard response op_code=%d vale_len=%d > (MTU-2=%d or msg_len-1=%d)",
+                          op_code, value_len, (p_tcb->payload_size - 2), (len-1));
+        gatt_end_operation(p_clcb, GATT_ERROR, NULL);
+        return;
+    }
+
+    if (op_code == GATT_RSP_READ_BY_GRP_TYPE)
+        handle_len = 4;
+
+    value_len -= handle_len; /* substract the handle pairs bytes */
+    len -= 1;
+
+    while (len >= (handle_len + value_len))
+    {
+        STREAM_TO_UINT16(handle, p);
+
+        if (!GATT_HANDLE_IS_VALID(handle))
+        {
+            gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
+            return;
+        }
+
+        memset(&result, 0, sizeof(tGATT_DISC_RES));
+        memset(&record_value, 0, sizeof(tGATT_DISC_VALUE));
+
+        result.handle = handle;
+        result.type.len = 2;
+        result.type.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
+
+        /* discover all services */
+        if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
+            p_clcb->op_subtype == GATT_DISC_SRVC_ALL &&
+            op_code == GATT_RSP_READ_BY_GRP_TYPE)
+        {
+            STREAM_TO_UINT16(handle, p);
+
+            if (!GATT_HANDLE_IS_VALID(handle))
+            {
+                gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
+                return;
+            }
+            else
+            {
+                record_value.group_value.e_handle = handle;
+                if (!gatt_parse_uuid_from_cmd(&record_value.group_value.service_type, value_len, &p))
+                {
+                    GATT_TRACE_ERROR("discover all service response parsing failure");
+                    break;
+                }
+            }
+        }
+        /* discover included service */
+        else if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->op_subtype == GATT_DISC_INC_SRVC)
+        {
+            STREAM_TO_UINT16(record_value.incl_service.s_handle, p);
+            STREAM_TO_UINT16(record_value.incl_service.e_handle, p);
+
+            if (!GATT_HANDLE_IS_VALID(record_value.incl_service.s_handle) ||
+                !GATT_HANDLE_IS_VALID(record_value.incl_service.e_handle))
+            {
+                gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
+                return;
+            }
+
+            if(value_len == 6)
+            {
+                STREAM_TO_UINT16(record_value.incl_service.service_type.uu.uuid16, p);
+                record_value.incl_service.service_type.len = LEN_UUID_16;
+            }
+            else if (value_len == 4)
+            {
+                p_clcb->s_handle = record_value.incl_service.s_handle;
+                p_clcb->read_uuid128.wait_for_read_rsp = true;
+                p_clcb->read_uuid128.next_disc_start_hdl = handle + 1;
+                memcpy(&p_clcb->read_uuid128.result, &result, sizeof(result));
+                memcpy(&p_clcb->read_uuid128.result.value, &record_value, sizeof (result.value));
+                p_clcb->op_subtype |= 0x90;
+                gatt_act_read(p_clcb, 0);
+                return;
+            }
+            else
+            {
+               GATT_TRACE_ERROR("gatt_process_read_by_type_rsp INCL_SRVC failed with invalid data value_len=%d", value_len);
+               gatt_end_operation(p_clcb, GATT_INVALID_PDU, (void *)p);
+               return;
+            }
+        }
+        /* read by type */
+        else if (p_clcb->operation == GATTC_OPTYPE_READ && p_clcb->op_subtype == GATT_READ_BY_TYPE)
+        {
+            p_clcb->counter = len - 2;
+            p_clcb->s_handle = handle;
+            if ( p_clcb->counter == (p_clcb->p_tcb->payload_size -4))
+            {
+                p_clcb->op_subtype = GATT_READ_BY_HANDLE;
+                if (!p_clcb->p_attr_buf)
+                    p_clcb->p_attr_buf = (uint8_t *)osi_malloc(GATT_MAX_ATTR_LEN);
+                if (p_clcb->counter <= GATT_MAX_ATTR_LEN) {
+                    memcpy(p_clcb->p_attr_buf, p, p_clcb->counter);
+                    gatt_act_read(p_clcb, p_clcb->counter);
+                } else {
+                    gatt_end_operation(p_clcb, GATT_INTERNAL_ERROR, (void *)p);
+                }
+            }
+            else
+            {
+                 gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p);
+            }
+            return;
+        }
+        else /* discover characterisitic */
+        {
+            STREAM_TO_UINT8 (record_value.dclr_value.char_prop, p);
+            STREAM_TO_UINT16(record_value.dclr_value.val_handle, p);
+            if (!GATT_HANDLE_IS_VALID(record_value.dclr_value.val_handle))
+            {
+                gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
+                return;
+            }
+            if (!gatt_parse_uuid_from_cmd(&record_value.dclr_value.char_uuid, (uint16_t)(value_len - 3), &p))
+            {
+                gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
+                /* invalid format, and skip the result */
+                return;
+            }
+
+            /* UUID not matching */
+            if (!gatt_uuid_compare(record_value.dclr_value.char_uuid, p_clcb->uuid))
+            {
+                len -= (value_len + 2);
+                continue; /* skip the result, and look for next one */
+            }
+            else if (p_clcb->operation == GATTC_OPTYPE_READ)
+            /* UUID match for read characteristic value */
+            {
+                /* only read the first matching UUID characteristic value, and
+                  discard the rest results */
+                p_clcb->s_handle = record_value.dclr_value.val_handle;
+                p_clcb->op_subtype |= 0x80;
+                gatt_act_read(p_clcb, 0);
+                return;
+            }
+        }
+        len -= (value_len + handle_len);
+
+        /* result is (handle, 16bits UUID) pairs */
+        memcpy (&result.value, &record_value, sizeof (result.value));
+
+        /* send callback if is discover procedure */
+        if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->p_reg->app_cb.p_disc_res_cb)
+            (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);
+    }
+
+    p_clcb->s_handle = (handle == 0) ? 0 : (handle + 1);
+
+    if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY)
+    {
+        /* initiate another request */
+        gatt_act_discovery(p_clcb) ;
+    }
+    else /* read characteristic value */
+    {
+        gatt_act_read(p_clcb, 0);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_process_read_rsp
+**
+** Description      This function is called to handle the read BLOB response
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_process_read_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb,  UNUSED_ATTR uint8_t op_code,
+                           uint16_t len, uint8_t *p_data)
+{
+    uint16_t    offset = p_clcb->counter;
+    uint8_t     * p= p_data;
+
+    if (p_clcb->operation == GATTC_OPTYPE_READ)
+    {
+        if (p_clcb->op_subtype != GATT_READ_BY_HANDLE)
+        {
+            p_clcb->counter = len;
+            gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p);
+        }
+        else
+        {
+
+            /* allocate GKI buffer holding up long attribute value  */
+            if (!p_clcb->p_attr_buf)
+                p_clcb->p_attr_buf = (uint8_t *)osi_malloc(GATT_MAX_ATTR_LEN);
+
+            /* copy attrobute value into cb buffer  */
+            if (offset < GATT_MAX_ATTR_LEN) {
+                if ((len + offset) > GATT_MAX_ATTR_LEN)
+                    len = GATT_MAX_ATTR_LEN - offset;
+
+                p_clcb->counter += len;
+
+                memcpy(p_clcb->p_attr_buf + offset, p, len);
+
+                /* send next request if needed  */
+
+                if (len == (p_tcb->payload_size - 1) && /* full packet for read or read blob rsp */
+                    len + offset < GATT_MAX_ATTR_LEN)
+                {
+                    GATT_TRACE_DEBUG("full pkt issue read blob for remianing bytes old offset=%d len=%d new offset=%d",
+                                      offset, len, p_clcb->counter);
+                    gatt_act_read(p_clcb, p_clcb->counter);
+                }
+                else /* end of request, send callback */
+                {
+                    gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p_clcb->p_attr_buf);
+                }
+            }
+            else /* exception, should not happen */
+            {
+                GATT_TRACE_ERROR("attr offset = %d p_attr_buf = %d ", offset, p_clcb->p_attr_buf);
+                gatt_end_operation(p_clcb, GATT_NO_RESOURCES, (void *)p_clcb->p_attr_buf);
+            }
+        }
+    }
+    else
+    {
+        if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
+            p_clcb->op_subtype == GATT_DISC_INC_SRVC &&
+            p_clcb->read_uuid128.wait_for_read_rsp )
+        {
+            p_clcb->s_handle = p_clcb->read_uuid128.next_disc_start_hdl;
+            p_clcb->read_uuid128.wait_for_read_rsp = false;
+            if (len == LEN_UUID_128)
+            {
+
+                memcpy(p_clcb->read_uuid128.result.value.incl_service.service_type.uu.uuid128, p, len);
+                p_clcb->read_uuid128.result.value.incl_service.service_type.len = LEN_UUID_128;
+                if ( p_clcb->p_reg->app_cb.p_disc_res_cb)
+                    (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &p_clcb->read_uuid128.result);
+                gatt_act_discovery(p_clcb) ;
+            }
+            else
+            {
+                gatt_end_operation(p_clcb, GATT_INVALID_PDU, (void *)p);
+            }
+        }
+    }
+
+}
+
+
+/*******************************************************************************
+**
+** Function         gatt_process_handle_rsp
+**
+** Description      This function is called to handle the write response
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_process_handle_rsp(tGATT_CLCB *p_clcb)
+{
+    gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
+}
+/*******************************************************************************
+**
+** Function         gatt_process_mtu_rsp
+**
+** Description      This function is called to process the configure MTU response.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_process_mtu_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, uint16_t len, uint8_t *p_data)
+{
+    uint16_t mtu;
+    tGATT_STATUS    status = GATT_SUCCESS;
+
+    if (len < GATT_MTU_RSP_MIN_LEN)
+    {
+        GATT_TRACE_ERROR("invalid MTU response PDU received, discard.");
+        status = GATT_INVALID_PDU;
+    }
+    else
+    {
+    STREAM_TO_UINT16(mtu, p_data);
+
+    if (mtu < p_tcb->payload_size && mtu >= GATT_DEF_BLE_MTU_SIZE)
+        p_tcb->payload_size = mtu;
+    }
+
+    l2cble_set_fixed_channel_tx_data_length(p_tcb->peer_bda, L2CAP_ATT_CID, p_tcb->payload_size);
+    gatt_end_operation(p_clcb, status, NULL);
+}
+/*******************************************************************************
+**
+** Function         gatt_cmd_to_rsp_code
+**
+** Description      The function convert a ATT command op code into the corresponding
+**                  response code assume no error occurs.
+**
+** Returns          response code.
+**
+*******************************************************************************/
+uint8_t gatt_cmd_to_rsp_code (uint8_t cmd_code)
+{
+    uint8_t rsp_code  = 0;
+
+    if (cmd_code > 1 && cmd_code != GATT_CMD_WRITE)
+    {
+        rsp_code = cmd_code + 1;
+    }
+    return rsp_code;
+}
+/*******************************************************************************
+**
+** Function         gatt_cl_send_next_cmd_inq
+**
+** Description      Find next command in queue and sent to server
+**
+** Returns          true if command sent, otherwise false.
+**
+*******************************************************************************/
+bool    gatt_cl_send_next_cmd_inq(tGATT_TCB *p_tcb)
+{
+    tGATT_CMD_Q  *p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
+    bool        sent = false;
+    uint8_t     rsp_code;
+    tGATT_CLCB   *p_clcb = NULL;
+    tGATT_STATUS att_ret = GATT_SUCCESS;
+
+    while (!sent &&
+           p_tcb->pending_cl_req != p_tcb->next_slot_inq &&
+           p_cmd->to_send && p_cmd->p_cmd != NULL)
+    {
+        att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd->p_cmd);
+
+        if (att_ret == GATT_SUCCESS || att_ret == GATT_CONGESTED)
+        {
+            sent = true;
+            p_cmd->to_send = false;
+            p_cmd->p_cmd = NULL;
+
+            /* dequeue the request if is write command or sign write */
+            if (p_cmd->op_code != GATT_CMD_WRITE && p_cmd->op_code != GATT_SIGN_CMD_WRITE)
+            {
+                gatt_start_rsp_timer (p_cmd->clcb_idx);
+            }
+            else
+            {
+                p_clcb = gatt_cmd_dequeue(p_tcb, &rsp_code);
+
+                /* if no ack needed, keep sending */
+                if (att_ret == GATT_SUCCESS)
+                    sent = false;
+
+                p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
+                /* send command complete callback here */
+                gatt_end_operation(p_clcb, att_ret, NULL);
+            }
+        }
+        else
+        {
+            GATT_TRACE_ERROR("gatt_cl_send_next_cmd_inq: L2CAP sent error");
+
+            memset(p_cmd, 0, sizeof(tGATT_CMD_Q));
+            p_tcb->pending_cl_req ++;
+            p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
+        }
+
+    }
+    return sent;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_client_handle_server_rsp
+**
+** Description      This function is called to handle the server response to
+**                  client.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_client_handle_server_rsp (tGATT_TCB *p_tcb, uint8_t op_code,
+                                    uint16_t len, uint8_t *p_data)
+{
+    tGATT_CLCB   *p_clcb = NULL;
+    uint8_t      rsp_code;
+
+    if (op_code != GATT_HANDLE_VALUE_IND && op_code != GATT_HANDLE_VALUE_NOTIF)
+    {
+        p_clcb = gatt_cmd_dequeue(p_tcb, &rsp_code);
+
+        rsp_code = gatt_cmd_to_rsp_code(rsp_code);
+
+        if (p_clcb == NULL || (rsp_code != op_code && op_code != GATT_RSP_ERROR))
+        {
+            GATT_TRACE_WARNING ("ATT - Ignore wrong response. Receives (%02x) \
+                                Request(%02x) Ignored", op_code, rsp_code);
+
+            return;
+        }
+        else
+        {
+            alarm_cancel(p_clcb->gatt_rsp_timer_ent);
+            p_clcb->retry_count = 0;
+        }
+    }
+    /* the size of the message may not be bigger than the local max PDU size*/
+    /* The message has to be smaller than the agreed MTU, len does not count op_code */
+    if (len >= p_tcb->payload_size)
+    {
+        GATT_TRACE_ERROR("invalid response/indicate pkt size: %d, PDU size: %d", len + 1, p_tcb->payload_size);
+        if (op_code != GATT_HANDLE_VALUE_NOTIF &&
+            op_code != GATT_HANDLE_VALUE_IND)
+            gatt_end_operation(p_clcb, GATT_ERROR, NULL);
+    }
+    else
+    {
+        switch (op_code)
+        {
+            case GATT_RSP_ERROR:
+                gatt_process_error_rsp(p_tcb, p_clcb, op_code, len, p_data);
+                break;
+
+            case GATT_RSP_MTU:       /* 2 bytes mtu */
+                gatt_process_mtu_rsp(p_tcb, p_clcb, len ,p_data);
+                break;
+
+            case GATT_RSP_FIND_INFO:
+                gatt_process_read_info_rsp(p_tcb, p_clcb, op_code, len, p_data);
+                break;
+
+            case GATT_RSP_READ_BY_TYPE:
+            case GATT_RSP_READ_BY_GRP_TYPE:
+                gatt_process_read_by_type_rsp(p_tcb, p_clcb, op_code, len, p_data);
+                break;
+
+            case GATT_RSP_READ:
+            case GATT_RSP_READ_BLOB:
+            case GATT_RSP_READ_MULTI:
+                gatt_process_read_rsp(p_tcb, p_clcb, op_code, len, p_data);
+                break;
+
+            case GATT_RSP_FIND_TYPE_VALUE: /* disc service with UUID */
+                gatt_process_find_type_value_rsp(p_tcb, p_clcb, len, p_data);
+                break;
+
+            case GATT_RSP_WRITE:
+                gatt_process_handle_rsp(p_clcb);
+                break;
+
+            case GATT_RSP_PREPARE_WRITE:
+                gatt_process_prep_write_rsp(p_tcb, p_clcb, op_code, len, p_data);
+                break;
+
+            case GATT_RSP_EXEC_WRITE:
+                gatt_end_operation(p_clcb, p_clcb->status, NULL);
+                break;
+
+            case GATT_HANDLE_VALUE_NOTIF:
+            case GATT_HANDLE_VALUE_IND:
+                gatt_process_notification(p_tcb, op_code, len, p_data);
+                break;
+
+            default:
+                GATT_TRACE_ERROR("Unknown opcode = %d", op_code);
+                break;
+        }
+    }
+
+    if (op_code != GATT_HANDLE_VALUE_IND && op_code != GATT_HANDLE_VALUE_NOTIF)
+    {
+        gatt_cl_send_next_cmd_inq(p_tcb);
+    }
+
+    return;
+}
+
+#endif  /* BLE_INCLUDED */
diff --git a/bt/stack/gatt/gatt_db.cc b/bt/stack/gatt/gatt_db.cc
new file mode 100644
index 0000000..18dc08d
--- /dev/null
+++ b/bt/stack/gatt/gatt_db.cc
@@ -0,0 +1,1188 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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 GATT database building and query functions
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+#include "bt_trace.h"
+#include "bt_utils.h"
+
+#include <stdio.h>
+#include <string.h>
+#include "gatt_int.h"
+#include "l2c_api.h"
+#include "btm_int.h"
+#include "osi/include/osi.h"
+
+/********************************************************************************
+**              L O C A L    F U N C T I O N     P R O T O T Y P E S            *
+*********************************************************************************/
+static bool allocate_svc_db_buf(tGATT_SVC_DB *p_db);
+static void *allocate_attr_in_db(tGATT_SVC_DB *p_db, tBT_UUID *p_uuid, tGATT_PERM perm);
+static bool deallocate_attr_in_db(tGATT_SVC_DB *p_db, void *p_attr);
+static bool copy_extra_byte_in_db(tGATT_SVC_DB *p_db, void **p_dst, uint16_t len);
+
+static bool gatts_db_add_service_declaration(tGATT_SVC_DB *p_db, tBT_UUID *p_service, bool is_pri);
+static tGATT_STATUS gatts_send_app_read_request(tGATT_TCB *p_tcb, uint8_t op_code,
+                                                uint16_t handle, uint16_t offset, uint32_t trans_id,
+                                                bt_gatt_db_attribute_type_t gatt_type);
+
+/*******************************************************************************
+**
+** Function         gatts_init_service_db
+**
+** Description      This function initialize a memory space to be a service database.
+**
+** Parameter        p_db: database pointer.
+**                  len: size of the memory space.
+**
+** Returns          Status of te operation.
+**
+*******************************************************************************/
+bool    gatts_init_service_db (tGATT_SVC_DB *p_db, tBT_UUID *p_service,  bool    is_pri,
+                               uint16_t s_hdl, uint16_t num_handle)
+{
+    p_db->svc_buffer = fixed_queue_new(SIZE_MAX);
+
+    if (!allocate_svc_db_buf(p_db))
+    {
+        GATT_TRACE_ERROR("gatts_init_service_db failed, no resources");
+        return false;
+    }
+
+    GATT_TRACE_DEBUG("gatts_init_service_db");
+    GATT_TRACE_DEBUG("s_hdl = %d num_handle = %d", s_hdl, num_handle );
+
+    /* update service database information */
+    p_db->next_handle   = s_hdl;
+    p_db->end_handle    = s_hdl + num_handle;
+
+    return gatts_db_add_service_declaration(p_db, p_service, is_pri);
+}
+
+/*******************************************************************************
+**
+** Function         gatts_init_service_db
+**
+** Description      This function initialize a memory space to be a service database.
+**
+** Parameter        p_db: database pointer.
+**                  len: size of the memory space.
+**
+** Returns          Status of te operation.
+**
+*******************************************************************************/
+tBT_UUID * gatts_get_service_uuid (tGATT_SVC_DB *p_db)
+{
+    if (!p_db || !p_db->p_attr_list)
+    {
+        GATT_TRACE_ERROR("service DB empty");
+
+        return NULL;
+    }
+    else
+    {
+        return &((tGATT_ATTR *)p_db->p_attr_list)->p_value->uuid;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatts_check_attr_readability
+**
+** Description      check attribute readability
+**
+** Returns          status of operation.
+**
+*******************************************************************************/
+static tGATT_STATUS gatts_check_attr_readability(tGATT_ATTR *p_attr,
+                                                 UNUSED_ATTR uint16_t offset,
+                                                 bool    read_long,
+                                                 tGATT_SEC_FLAG sec_flag,
+                                                 uint8_t key_size)
+{
+    uint16_t        min_key_size;
+    tGATT_PERM      perm = p_attr->permission;
+
+    min_key_size = (((perm & GATT_ENCRYPT_KEY_SIZE_MASK) >> 12));
+    if (min_key_size != 0 )
+    {
+        min_key_size +=6;
+    }
+
+    if (!(perm & GATT_READ_ALLOWED))
+    {
+        GATT_TRACE_ERROR("%s: GATT_READ_NOT_PERMIT", __func__);
+        return GATT_READ_NOT_PERMIT;
+    }
+
+    if ((perm & GATT_READ_AUTH_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED) &&
+        !(sec_flag & BTM_SEC_FLAG_ENCRYPTED))
+    {
+        GATT_TRACE_ERROR("%s: GATT_INSUF_AUTHENTICATION", __func__);
+        return GATT_INSUF_AUTHENTICATION;
+    }
+
+    if ((perm & GATT_READ_MITM_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_AUTHED))
+    {
+        GATT_TRACE_ERROR("%s: GATT_INSUF_AUTHENTICATION: MITM Required", __func__);
+        return GATT_INSUF_AUTHENTICATION;
+    }
+
+    if ((perm & GATT_READ_ENCRYPTED_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_ENCRYPTED))
+    {
+        GATT_TRACE_ERROR("%s: GATT_INSUF_ENCRYPTION", __func__);
+        return GATT_INSUF_ENCRYPTION;
+    }
+
+    if ( (perm & GATT_READ_ENCRYPTED_REQUIRED) && (sec_flag & GATT_SEC_FLAG_ENCRYPTED) && (key_size < min_key_size))
+    {
+        GATT_TRACE_ERROR("%s: GATT_INSUF_KEY_SIZE", __func__);
+        return GATT_INSUF_KEY_SIZE;
+    }
+
+
+    if (read_long && p_attr->uuid.len == LEN_UUID_16)
+    {
+        switch (p_attr->uuid.uu.uuid16)
+        {
+            case GATT_UUID_PRI_SERVICE:
+            case GATT_UUID_SEC_SERVICE:
+            case GATT_UUID_CHAR_DECLARE:
+            case GATT_UUID_INCLUDE_SERVICE:
+            case GATT_UUID_CHAR_EXT_PROP:
+            case GATT_UUID_CHAR_CLIENT_CONFIG:
+            case GATT_UUID_CHAR_SRVR_CONFIG:
+            case GATT_UUID_CHAR_PRESENT_FORMAT:
+                GATT_TRACE_ERROR("%s: GATT_NOT_LONG", __func__);
+                return GATT_NOT_LONG;
+
+            default:
+                break;
+        }
+    }
+
+    return GATT_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         read_attr_value
+**
+** Description      Utility function to read an attribute value.
+**
+** Parameter        p_attr: pointer to the attribute to read.
+**                  offset: read offset.
+**                  p_value: output parameter to carry out the attribute value.
+**                  p_len: output parameter to carry out the attribute length.
+**                  read_long: this is a read blob request.
+**                  mtu: MTU
+**                  sec_flag: current link security status.
+**                  key_size: encryption key size.
+**
+** Returns          status of operation.
+**
+*******************************************************************************/
+static tGATT_STATUS read_attr_value (void *p_attr,
+                                     uint16_t offset,
+                                     uint8_t **p_data,
+                                     bool    read_long,
+                                     uint16_t mtu,
+                                     uint16_t *p_len,
+                                     tGATT_SEC_FLAG sec_flag,
+                                     uint8_t key_size)
+{
+    uint16_t        len = 0, uuid16 = 0;
+    uint8_t         *p = *p_data;
+    tGATT_STATUS    status;
+    tGATT_ATTR    *p_attr16  = (tGATT_ATTR  *)p_attr;
+
+    GATT_TRACE_DEBUG("read_attr_value uuid=0x%04x perm=0x%02x sec_flag=0x%x offset=%d read_long=%d",
+                      p_attr16->uuid,
+                      p_attr16->permission,
+                      sec_flag,
+                      offset,
+                      read_long);
+
+    status = gatts_check_attr_readability((tGATT_ATTR *)p_attr, offset, read_long, sec_flag, key_size);
+
+    if (status != GATT_SUCCESS)
+        return status;
+
+    if (p_attr16->uuid.len == LEN_UUID_16)
+        uuid16 = p_attr16->uuid.uu.uuid16;
+
+    status = GATT_NO_RESOURCES;
+
+    if (uuid16 == GATT_UUID_PRI_SERVICE || uuid16 == GATT_UUID_SEC_SERVICE)
+    {
+        len = p_attr16->p_value->uuid.len;
+        if (mtu >= p_attr16->p_value->uuid.len)
+        {
+            gatt_build_uuid_to_stream(&p, p_attr16->p_value->uuid);
+            status = GATT_SUCCESS;
+        }
+    }
+    else if (uuid16 == GATT_UUID_CHAR_DECLARE)
+    {
+        len = (((tGATT_ATTR *)(p_attr16->p_next))->uuid.len == LEN_UUID_16) ? 5 :19;
+
+        if (mtu >= len)
+        {
+            UINT8_TO_STREAM(p, p_attr16->p_value->char_decl.property);
+            UINT16_TO_STREAM(p, p_attr16->p_value->char_decl.char_val_handle);
+
+            if (((tGATT_ATTR *)(p_attr16->p_next))->uuid.len == LEN_UUID_16)
+            {
+                UINT16_TO_STREAM(p, ((tGATT_ATTR *)(p_attr16->p_next))->uuid.uu.uuid16);
+            }
+            /* convert a 32bits UUID to 128 bits */
+            else if (((tGATT_ATTR *)(p_attr16->p_next))->uuid.len == LEN_UUID_32)
+            {
+                gatt_convert_uuid32_to_uuid128 (p, ((tGATT_ATTR *)(p_attr16->p_next))->uuid.uu.uuid32);
+                p += LEN_UUID_128;
+            }
+            else
+            {
+                ARRAY_TO_STREAM (p, ((tGATT_ATTR *)(p_attr16->p_next))->uuid.uu.uuid128, LEN_UUID_128);
+            }
+            status = GATT_SUCCESS;
+        }
+
+    }
+    else if (uuid16 == GATT_UUID_INCLUDE_SERVICE)
+    {
+        if (p_attr16->p_value->incl_handle.service_type.len == LEN_UUID_16)
+            len = 6;
+        else
+            len = 4;
+
+        if (mtu >= len)
+        {
+            UINT16_TO_STREAM(p, p_attr16->p_value->incl_handle.s_handle);
+            UINT16_TO_STREAM(p, p_attr16->p_value->incl_handle.e_handle);
+
+            if (p_attr16->p_value->incl_handle.service_type.len == LEN_UUID_16)
+            {
+                UINT16_TO_STREAM(p, p_attr16->p_value->incl_handle.service_type.uu.uuid16);
+            }
+            status = GATT_SUCCESS;
+        }
+    }
+    else /* characteristic description or characteristic value */
+    {
+        status = GATT_PENDING;
+    }
+
+    *p_len = len;
+    *p_data = p;
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         gatts_db_read_attr_value_by_type
+**
+** Description      Query attribute value by attribute type.
+**
+** Parameter        p_db: pointer to the attribute database.
+**                  p_rsp: Read By type response data.
+**                  s_handle: starting handle of the range we are looking for.
+**                  e_handle: ending handle of the range we are looking for.
+**                  type: Attribute type.
+**                  mtu: MTU.
+**                  sec_flag: current link security status.
+**                  key_size: encryption key size.
+**
+** Returns          Status of the operation.
+**
+*******************************************************************************/
+tGATT_STATUS gatts_db_read_attr_value_by_type (tGATT_TCB   *p_tcb,
+                                               tGATT_SVC_DB    *p_db,
+                                               uint8_t      op_code,
+                                               BT_HDR      *p_rsp,
+                                               uint16_t     s_handle,
+                                               uint16_t     e_handle,
+                                               tBT_UUID     type,
+                                               uint16_t    *p_len,
+                                               tGATT_SEC_FLAG sec_flag,
+                                               uint8_t      key_size,
+                                               uint32_t     trans_id,
+                                               uint16_t     *p_cur_handle)
+{
+    tGATT_STATUS status = GATT_NOT_FOUND;
+    tGATT_ATTR  *p_attr;
+    uint16_t    len = 0;
+    uint8_t     *p = (uint8_t *)(p_rsp + 1) + p_rsp->len + L2CAP_MIN_OFFSET;
+    tBT_UUID    attr_uuid;
+
+    if (p_db && p_db->p_attr_list)
+    {
+        p_attr = (tGATT_ATTR *)p_db->p_attr_list;
+
+        while (p_attr && p_attr->handle <= e_handle)
+        {
+            attr_uuid = p_attr->uuid;
+
+            if (p_attr->handle >= s_handle && gatt_uuid_compare(type, attr_uuid))
+            {
+                if (*p_len <= 2)
+                {
+                    status = GATT_NO_RESOURCES;
+                    break;
+                }
+
+                UINT16_TO_STREAM (p, p_attr->handle);
+
+                status = read_attr_value ((void *)p_attr, 0, &p, false, (uint16_t)(*p_len -2), &len, sec_flag, key_size);
+
+                if (status == GATT_PENDING)
+                {
+                    status = gatts_send_app_read_request(p_tcb, op_code, p_attr->handle, 0,
+                                                         trans_id, p_attr->gatt_type);
+
+                    /* one callback at a time */
+                    break;
+                }
+                else if (status == GATT_SUCCESS)
+                {
+                    if (p_rsp->offset == 0)
+                        p_rsp->offset = len + 2;
+
+                    if (p_rsp->offset == len + 2)
+                    {
+                        p_rsp->len += (len  + 2);
+                        *p_len -= (len + 2);
+                    }
+                    else
+                    {
+                        GATT_TRACE_ERROR("format mismatch");
+                        status = GATT_NO_RESOURCES;
+                        break;
+                    }
+                }
+                else
+                {
+                    *p_cur_handle = p_attr->handle;
+                    break;
+                }
+            }
+            p_attr = (tGATT_ATTR *)p_attr->p_next;
+        }
+    }
+
+#if (BLE_DELAY_REQUEST_ENC == TRUE)
+    uint8_t flag = 0;
+    if (BTM_GetSecurityFlags(p_tcb->peer_bda, &flag))
+    {
+        if ((p_tcb->att_lcid == L2CAP_ATT_CID) && (status == GATT_PENDING) &&
+            (type.uu.uuid16 == GATT_UUID_GAP_DEVICE_NAME))
+        {
+            if ((flag & (BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_FLAG_ENCRYPTED)) ==
+                 BTM_SEC_LINK_KEY_KNOWN)
+            {
+                tACL_CONN *p = btm_bda_to_acl(p_tcb->peer_bda, BT_TRANSPORT_LE);
+                if ((p != NULL) && (p->link_role == BTM_ROLE_MASTER))
+                    btm_ble_set_encryption(p_tcb->peer_bda, BTM_BLE_SEC_ENCRYPT, p->link_role);
+            }
+        }
+    }
+#endif
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         gatts_add_included_service
+**
+** Description      This function adds an included service into a database.
+**
+** Parameter        p_db: database pointer.
+**                  inc_srvc_type: included service type.
+**
+** Returns          Status of the operation.
+**
+*******************************************************************************/
+uint16_t gatts_add_included_service (tGATT_SVC_DB *p_db, uint16_t s_handle, uint16_t e_handle,
+                                   tBT_UUID service)
+{
+    tGATT_ATTR      *p_attr;
+    tBT_UUID         uuid = {LEN_UUID_16, {GATT_UUID_INCLUDE_SERVICE}};
+
+    GATT_TRACE_DEBUG("gatts_add_included_service: s_hdl = 0x%04x e_hdl = 0x%04x uuid = 0x%04x",
+                      s_handle, e_handle, service.uu.uuid16);
+
+    if (service.len == 0 || s_handle == 0 || e_handle == 0)
+    {
+        GATT_TRACE_ERROR("gatts_add_included_service Illegal Params.");
+        return 0;
+    }
+
+    if ((p_attr = (tGATT_ATTR *) allocate_attr_in_db(p_db, &uuid, GATT_PERM_READ)) != NULL)
+    {
+        if (copy_extra_byte_in_db(p_db, (void **)&p_attr->p_value, sizeof(tGATT_INCL_SRVC)))
+        {
+            p_attr->p_value->incl_handle.s_handle = s_handle;
+            p_attr->p_value->incl_handle.e_handle = e_handle;
+            memcpy(&p_attr->p_value->incl_handle.service_type, &service, sizeof(tBT_UUID));
+
+            return p_attr->handle;
+        }
+        else
+        {
+            deallocate_attr_in_db(p_db, p_attr);
+        }
+    }
+
+    return 0;
+}
+
+/*******************************************************************************
+**
+** Function         gatts_add_characteristic
+**
+** Description      This function add a characteristics and its descriptor into
+**                  a servce identified by the service database pointer.
+**
+** Parameter        p_db: database pointer.
+**                  perm: permission (authentication and key size requirements)
+**                  property: property of the characteristic.
+**                  p_char: characteristic value information.
+**
+** Returns          Status of te operation.
+**
+*******************************************************************************/
+uint16_t gatts_add_characteristic (tGATT_SVC_DB *p_db, tGATT_PERM perm,
+                                 tGATT_CHAR_PROP property,
+                                 tBT_UUID * p_char_uuid)
+{
+    tGATT_ATTR     *p_char_decl, *p_char_val;
+    tBT_UUID        uuid = {LEN_UUID_16, {GATT_UUID_CHAR_DECLARE}};
+
+    GATT_TRACE_DEBUG("%s: perm=0x%0x property=0x%0x", __func__, perm, property);
+
+    if ((p_char_decl = (tGATT_ATTR *)allocate_attr_in_db(p_db, &uuid, GATT_PERM_READ)) != NULL)
+    {
+        if (!copy_extra_byte_in_db(p_db, (void **)&p_char_decl->p_value, sizeof(tGATT_CHAR_DECL)))
+        {
+            deallocate_attr_in_db(p_db, p_char_decl);
+            return 0;
+        }
+
+        p_char_val = (tGATT_ATTR *)allocate_attr_in_db(p_db, p_char_uuid, perm);
+
+        if (p_char_val == NULL)
+        {
+            deallocate_attr_in_db(p_db, p_char_decl);
+            return 0;
+        }
+
+        p_char_decl->p_value->char_decl.property = property;
+        p_char_decl->p_value->char_decl.char_val_handle  = p_char_val->handle;
+
+        p_char_val->gatt_type = BTGATT_DB_CHARACTERISTIC;
+        p_char_val->p_value = NULL;
+
+        return p_char_val->handle;
+    }
+
+    return 0;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_convertchar_descr_type
+**
+** Description      This function convert a char descript UUID into descriptor type.
+**
+** Returns          descriptor type.
+**
+*******************************************************************************/
+uint8_t gatt_convertchar_descr_type(tBT_UUID *p_descr_uuid)
+{
+    tBT_UUID std_descr = {LEN_UUID_16, {GATT_UUID_CHAR_EXT_PROP}};
+
+    if (gatt_uuid_compare(std_descr, * p_descr_uuid))
+        return GATT_DESCR_EXT_DSCPTOR;
+
+    std_descr.uu.uuid16 ++;
+    if (gatt_uuid_compare(std_descr,  * p_descr_uuid))
+        return GATT_DESCR_USER_DSCPTOR;
+
+    std_descr.uu.uuid16 ++;
+    if (gatt_uuid_compare(std_descr,  * p_descr_uuid))
+        return GATT_DESCR_CLT_CONFIG;
+
+    std_descr.uu.uuid16 ++;
+    if (gatt_uuid_compare(std_descr,  * p_descr_uuid))
+        return GATT_DESCR_SVR_CONFIG;
+
+    std_descr.uu.uuid16 ++;
+    if (gatt_uuid_compare(std_descr,  * p_descr_uuid))
+        return GATT_DESCR_PRES_FORMAT;
+
+    std_descr.uu.uuid16 ++;
+    if (gatt_uuid_compare(std_descr,  * p_descr_uuid))
+        return GATT_DESCR_AGGR_FORMAT;
+
+    std_descr.uu.uuid16 ++;
+    if (gatt_uuid_compare(std_descr,  * p_descr_uuid))
+        return GATT_DESCR_VALID_RANGE;
+
+
+    return GATT_DESCR_UNKNOWN;
+}
+
+/*******************************************************************************
+**
+** Function         gatts_add_char_descr
+**
+** Description      This function add a characteristics descriptor.
+**
+** Parameter        p_db: database pointer.
+**                  perm: characteristic descriptor permission type.
+**                  char_dscp_tpye: the characteristic descriptor masks.
+**                  p_dscp_params: characteristic descriptors values.
+**
+** Returns          Status of the operation.
+**
+*******************************************************************************/
+uint16_t gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm,
+                             tBT_UUID *     p_descr_uuid)
+{
+    tGATT_ATTR    *p_char_dscptr;
+
+    GATT_TRACE_DEBUG("gatts_add_char_descr uuid=0x%04x", p_descr_uuid->uu.uuid16);
+
+    /* Add characteristic descriptors */
+    if ((p_char_dscptr = (tGATT_ATTR *)allocate_attr_in_db(p_db,
+                                                             p_descr_uuid,
+                                                             perm))
+        == NULL)
+    {
+        GATT_TRACE_DEBUG("gatts_add_char_descr Fail for adding char descriptors.");
+        return 0;
+    }
+    else
+    {
+        p_char_dscptr->gatt_type = BTGATT_DB_DESCRIPTOR;
+        return p_char_dscptr->handle;
+    }
+}
+
+/*******************************************************************************/
+/* Service Attribute Database Query Utility Functions */
+/*******************************************************************************/
+/*******************************************************************************
+**
+** Function         gatts_read_attr_value_by_handle
+**
+** Description      Query attribute value by attribute handle.
+**
+** Parameter        p_db: pointer to the attribute database.
+**                  handle: Attribute handle to read.
+**                  offset: Read offset.
+**                  p_value: output parameter to carry out the attribute value.
+**                  p_len: output parameter as attribute length read.
+**                  read_long: this is a read blob request.
+**                  mtu: MTU.
+**                  sec_flag: current link security status.
+**                  key_size: encryption key size
+**
+** Returns          Status of operation.
+**
+*******************************************************************************/
+tGATT_STATUS gatts_read_attr_value_by_handle(tGATT_TCB *p_tcb,
+                                             tGATT_SVC_DB *p_db,
+                                             uint8_t op_code,
+                                             uint16_t handle, uint16_t offset,
+                                             uint8_t *p_value, uint16_t *p_len,
+                                             uint16_t mtu,
+                                             tGATT_SEC_FLAG sec_flag,
+                                             uint8_t key_size,
+                                             uint32_t trans_id)
+{
+    tGATT_STATUS status = GATT_NOT_FOUND;
+    tGATT_ATTR  *p_attr;
+    uint8_t     *pp = p_value;
+
+    if (p_db && p_db->p_attr_list)
+    {
+        p_attr = (tGATT_ATTR *)p_db->p_attr_list;
+
+        while (p_attr && handle >= p_attr->handle)
+        {
+            if (p_attr->handle == handle)
+            {
+                status = read_attr_value (p_attr, offset, &pp,
+                                          (bool   )(op_code == GATT_REQ_READ_BLOB),
+                                          mtu, p_len, sec_flag, key_size);
+
+                if (status == GATT_PENDING)
+                {
+                    status = gatts_send_app_read_request(p_tcb, op_code, p_attr->handle, offset,
+                                                         trans_id, p_attr->gatt_type);
+                }
+                break;
+            }
+            p_attr = (tGATT_ATTR *)p_attr->p_next;
+        }
+    }
+
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         gatts_read_attr_perm_check
+**
+** Description      Check attribute readability.
+**
+** Parameter        p_db: pointer to the attribute database.
+**                  handle: Attribute handle to read.
+**                  offset: Read offset.
+**                  p_value: output parameter to carry out the attribute value.
+**                  p_len: output parameter as attribute length read.
+**                  read_long: this is a read blob request.
+**                  mtu: MTU.
+**                  sec_flag: current link security status.
+**                  key_size: encryption key size
+**
+** Returns          Status of operation.
+**
+*******************************************************************************/
+tGATT_STATUS gatts_read_attr_perm_check(tGATT_SVC_DB *p_db,
+                                        bool    is_long,
+                                        uint16_t handle,
+                                        tGATT_SEC_FLAG sec_flag,
+                                        uint8_t key_size)
+{
+    tGATT_STATUS status = GATT_NOT_FOUND;
+    tGATT_ATTR  *p_attr;
+
+    if (p_db && p_db->p_attr_list)
+    {
+        p_attr = (tGATT_ATTR *)p_db->p_attr_list;
+
+        while (p_attr && handle >= p_attr->handle)
+        {
+            if (p_attr->handle == handle)
+            {
+                status = gatts_check_attr_readability (p_attr, 0,
+                                                       is_long,
+                                                       sec_flag, key_size);
+                break;
+            }
+            p_attr = (tGATT_ATTR *) p_attr->p_next;
+        }
+    }
+
+    return status;
+}
+/*******************************************************************************
+**
+** Function         gatts_write_attr_perm_check
+**
+** Description      Write attribute value into database.
+**
+** Parameter        p_db: pointer to the attribute database.
+**                  op_code:op code of this write.
+**                  handle: handle of the attribute to write.
+**                  offset: Write offset if write op code is write blob.
+**                  p_data: Attribute value to write.
+**                  len: attribute data length.
+**                  sec_flag: current link security status.
+**                  key_size: encryption key size
+**
+** Returns          Status of the operation.
+**
+*******************************************************************************/
+tGATT_STATUS gatts_write_attr_perm_check (tGATT_SVC_DB *p_db, uint8_t op_code,
+                                          uint16_t handle, uint16_t offset, uint8_t *p_data,
+                                          uint16_t len, tGATT_SEC_FLAG sec_flag, uint8_t key_size)
+{
+    tGATT_STATUS    status = GATT_NOT_FOUND;
+    tGATT_ATTR    *p_attr;
+    uint16_t        max_size = 0;
+    tGATT_PERM      perm;
+    uint16_t        min_key_size;
+
+    GATT_TRACE_DEBUG( "%s: op_code=0x%0x handle=0x%04x offset=%d len=%d sec_flag=0x%0x key_size=%d",
+                       __func__, op_code, handle, offset, len, sec_flag, key_size);
+
+    if (p_db != NULL)
+    {
+        p_attr = (tGATT_ATTR *) p_db->p_attr_list;
+
+        while (p_attr != NULL)
+        {
+            if (p_attr->handle == handle)
+            {
+                perm = p_attr->permission;
+                min_key_size = (((perm & GATT_ENCRYPT_KEY_SIZE_MASK) >> 12));
+                if (min_key_size != 0 )
+                {
+                    min_key_size +=6;
+                }
+                GATT_TRACE_DEBUG( "%s: p_attr->permission =0x%04x min_key_size==0x%04x",
+                                   __func__, p_attr->permission, min_key_size);
+
+                if ((op_code == GATT_CMD_WRITE || op_code == GATT_REQ_WRITE)
+                    && (perm & GATT_WRITE_SIGNED_PERM))
+                {
+                    /* use the rules for the mixed security see section 10.2.3*/
+                    /* use security mode 1 level 2 when the following condition follows */
+                    /* LE security mode 2 level 1 and LE security mode 1 level 2 */
+                    if ((perm & GATT_PERM_WRITE_SIGNED) && (perm & GATT_PERM_WRITE_ENCRYPTED))
+                    {
+                        perm = GATT_PERM_WRITE_ENCRYPTED;
+                    }
+                    /* use security mode 1 level 3 when the following condition follows */
+                    /* LE security mode 2 level 2 and security mode 1 and LE */
+                    else if (((perm & GATT_PERM_WRITE_SIGNED_MITM) && (perm & GATT_PERM_WRITE_ENCRYPTED)) ||
+                              /* LE security mode 2 and security mode 1 level 3 */
+                             ((perm & GATT_WRITE_SIGNED_PERM) && (perm & GATT_PERM_WRITE_ENC_MITM)))
+                    {
+                        perm = GATT_PERM_WRITE_ENC_MITM;
+                    }
+                }
+
+                if ((op_code == GATT_SIGN_CMD_WRITE) && !(perm & GATT_WRITE_SIGNED_PERM))
+                {
+                    status = GATT_WRITE_NOT_PERMIT;
+                    GATT_TRACE_DEBUG( "%s: sign cmd write not allowed", __func__);
+                }
+                 if ((op_code == GATT_SIGN_CMD_WRITE) && (sec_flag & GATT_SEC_FLAG_ENCRYPTED))
+                {
+                    status = GATT_INVALID_PDU;
+                    GATT_TRACE_ERROR( "%s: Error!! sign cmd write sent on a encypted link", __func__);
+                }
+                else if (!(perm & GATT_WRITE_ALLOWED))
+                {
+                    status = GATT_WRITE_NOT_PERMIT;
+                    GATT_TRACE_ERROR( "%s: GATT_WRITE_NOT_PERMIT", __func__);
+                }
+                /* require authentication, but not been authenticated */
+                else if ((perm & GATT_WRITE_AUTH_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED))
+                {
+                    status = GATT_INSUF_AUTHENTICATION;
+                    GATT_TRACE_ERROR( "%s: GATT_INSUF_AUTHENTICATION", __func__);
+                }
+                else if ((perm & GATT_WRITE_MITM_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_AUTHED))
+                {
+                    status = GATT_INSUF_AUTHENTICATION;
+                    GATT_TRACE_ERROR( "%s: GATT_INSUF_AUTHENTICATION: MITM required", __func__);
+                }
+                else if ((perm & GATT_WRITE_ENCRYPTED_PERM ) && !(sec_flag & GATT_SEC_FLAG_ENCRYPTED))
+                {
+                    status = GATT_INSUF_ENCRYPTION;
+                    GATT_TRACE_ERROR( "%s: GATT_INSUF_ENCRYPTION", __func__);
+                }
+                else if ((perm & GATT_WRITE_ENCRYPTED_PERM ) && (sec_flag & GATT_SEC_FLAG_ENCRYPTED) && (key_size < min_key_size))
+                {
+                    status = GATT_INSUF_KEY_SIZE;
+                    GATT_TRACE_ERROR( "%s: GATT_INSUF_KEY_SIZE", __func__);
+                }
+                /* LE security mode 2 attribute  */
+                else if (perm & GATT_WRITE_SIGNED_PERM && op_code != GATT_SIGN_CMD_WRITE && !(sec_flag & GATT_SEC_FLAG_ENCRYPTED)
+                    &&  (perm & GATT_WRITE_ALLOWED) == 0)
+                {
+                    status = GATT_INSUF_AUTHENTICATION;
+                    GATT_TRACE_ERROR( "%s: GATT_INSUF_AUTHENTICATION: LE security mode 2 required", __func__);
+                }
+                else /* writable: must be char value declaration or char descritpors */
+                {
+                    if(p_attr->uuid.len == LEN_UUID_16)
+                    {
+                    switch (p_attr->uuid.uu.uuid16)
+                    {
+                        case GATT_UUID_CHAR_PRESENT_FORMAT:/* should be readable only */
+                        case GATT_UUID_CHAR_EXT_PROP:/* should be readable only */
+                        case GATT_UUID_CHAR_AGG_FORMAT: /* should be readable only */
+                        case GATT_UUID_CHAR_VALID_RANGE:
+                            status = GATT_WRITE_NOT_PERMIT;
+                            break;
+
+                        case GATT_UUID_CHAR_CLIENT_CONFIG:
+                            /* fall through */
+                        case GATT_UUID_CHAR_SRVR_CONFIG:
+                            max_size = 2;
+                            /* fall through */
+                        case GATT_UUID_CHAR_DESCRIPTION:
+                        default: /* any other must be character value declaration */
+                            status = GATT_SUCCESS;
+                            break;
+                        }
+                    }
+                    else if (p_attr->uuid.len == LEN_UUID_128 ||
+				              p_attr->uuid.len == LEN_UUID_32)
+                    {
+                         status = GATT_SUCCESS;
+                    }
+                    else
+                    {
+                        status = GATT_INVALID_PDU;
+                    }
+
+                    if (p_data == NULL && len  > 0)
+                    {
+                        status = GATT_INVALID_PDU;
+                    }
+                    /* these attribute does not allow write blob */
+                    else if ( (p_attr->uuid.len == LEN_UUID_16) &&
+                              (p_attr->uuid.uu.uuid16 == GATT_UUID_CHAR_CLIENT_CONFIG ||
+                               p_attr->uuid.uu.uuid16 == GATT_UUID_CHAR_SRVR_CONFIG) )
+                    {
+                        if (op_code == GATT_REQ_PREPARE_WRITE && offset != 0) /* does not allow write blob */
+                        {
+                            status = GATT_NOT_LONG;
+                            GATT_TRACE_ERROR( "%s: GATT_NOT_LONG", __func__);
+                        }
+                        else if (len != max_size)    /* data does not match the required format */
+                        {
+                            status = GATT_INVALID_ATTR_LEN;
+                            GATT_TRACE_ERROR( "%s: GATT_INVALID_PDU", __func__);
+                        }
+                        else
+                        {
+                            status = GATT_SUCCESS;
+                        }
+                    }
+                }
+                break;
+            }
+            else
+                p_attr = (tGATT_ATTR *)p_attr->p_next;
+        }
+    }
+
+    return status;
+}
+
+static void uuid_to_str(const tBT_UUID bt_uuid, char *str_buf, size_t buf_len)
+{
+    if (bt_uuid.len == LEN_UUID_16) {
+        snprintf(str_buf, buf_len, "0x%04x", bt_uuid.uu.uuid16);
+    } else if (bt_uuid.len == LEN_UUID_32) {
+        snprintf(str_buf, buf_len, "0x%08x", bt_uuid.uu.uuid32);
+    } else if (bt_uuid.len == LEN_UUID_128)
+    {
+        int x = snprintf(str_buf, buf_len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-",
+                bt_uuid.uu.uuid128[15], bt_uuid.uu.uuid128[14],
+                bt_uuid.uu.uuid128[13], bt_uuid.uu.uuid128[12],
+                bt_uuid.uu.uuid128[11], bt_uuid.uu.uuid128[10],
+                bt_uuid.uu.uuid128[9], bt_uuid.uu.uuid128[8]);
+        snprintf(&str_buf[x], buf_len - x, "%02x%02x-%02x%02x%02x%02x%02x%02x",
+                bt_uuid.uu.uuid128[7], bt_uuid.uu.uuid128[6],
+                bt_uuid.uu.uuid128[5], bt_uuid.uu.uuid128[4],
+                bt_uuid.uu.uuid128[3], bt_uuid.uu.uuid128[2],
+                bt_uuid.uu.uuid128[1], bt_uuid.uu.uuid128[0]);
+    }
+    else
+        snprintf(str_buf, buf_len, "Unknown (len=%d)", bt_uuid.len);
+}
+
+/*******************************************************************************
+**
+** Function         allocate_attr_in_db
+**
+** Description      Allocate a memory space for a new attribute, and link this
+**                  attribute into the database attribute list.
+**
+**
+** Parameter        p_db    : database pointer.
+**                  p_uuid:     pointer to attribute UUID
+**                  service : type of attribute to be added.
+**
+** Returns          pointer to the newly allocated attribute.
+**
+*******************************************************************************/
+static void *allocate_attr_in_db(tGATT_SVC_DB *p_db, tBT_UUID *p_uuid, tGATT_PERM perm)
+{
+    if (p_uuid == NULL) {
+        GATT_TRACE_ERROR("illegal UUID");
+        return NULL;
+    }
+
+    if (p_db->end_handle <= p_db->next_handle) {
+        GATT_TRACE_DEBUG("handle space full. handle_max = %d next_handle = %d",
+                          p_db->end_handle, p_db->next_handle);
+        return NULL;
+    }
+
+    uint16_t len = sizeof(tGATT_ATTR);
+    if (p_db->mem_free < len) {
+        if (!allocate_svc_db_buf(p_db)) {
+            GATT_TRACE_ERROR("allocate_attr_in_db failed, no resources");
+            return NULL;
+        }
+    }
+    memset(p_db->p_free_mem, 0, len);
+
+    tGATT_ATTR    *p_attr = (tGATT_ATTR *) p_db->p_free_mem;
+    p_db->p_free_mem += len;
+    p_db->mem_free -= len;
+
+    p_attr->handle = p_db->next_handle++;
+    p_attr->uuid = *p_uuid;
+    p_attr->permission = perm;
+    p_attr->p_next = NULL;
+
+    /* link the attribute record into the end of DB */
+    if (p_db->p_attr_list == NULL)
+        p_db->p_attr_list = p_attr;
+    else
+    {
+        tGATT_ATTR *p_last = (tGATT_ATTR *)p_db->p_attr_list;
+
+        while (p_last != NULL && p_last->p_next != NULL)
+            p_last = (tGATT_ATTR *)p_last->p_next;
+
+        p_last->p_next = p_attr;
+    }
+
+    char uuid_str[37];
+    uuid_to_str(p_attr->uuid, uuid_str, sizeof(uuid_str));
+    GATT_TRACE_ERROR("=====> handle = [0x%04x] uuid = [%s] perm=0x%02x ",
+                     p_attr->handle, uuid_str, p_attr->permission);
+
+    return(void *)p_attr;
+}
+
+/*******************************************************************************
+**
+** Function         deallocate_attr_in_db
+**
+** Description      Free an attribute within the database.
+**
+** Parameter        p_db: database pointer.
+**                  p_attr: pointer to the attribute record to be freed.
+**
+** Returns          bool   : success
+**
+*******************************************************************************/
+static bool    deallocate_attr_in_db(tGATT_SVC_DB *p_db, void *p_attr)
+{
+    tGATT_ATTR  *p_cur, *p_next;
+    bool        found = false;
+
+    if (p_db->p_attr_list == NULL)
+        return found;
+
+    p_cur   = (tGATT_ATTR *) p_db->p_attr_list;
+    p_next  = (tGATT_ATTR *) p_cur->p_next;
+
+    for (; p_cur != NULL && p_next != NULL;
+        p_cur = p_next, p_next = (tGATT_ATTR *)p_next->p_next)
+    {
+        if (p_next == p_attr)
+        {
+            p_cur->p_next = p_next->p_next;
+            found = true;
+        }
+    }
+    if (p_cur == p_attr && p_cur == p_db->p_attr_list)
+    {
+        p_db->p_attr_list = p_cur->p_next;
+        found = true;
+    }
+    /* else attr not found */
+    if ( found)
+        p_db->next_handle --;
+
+    return found;
+}
+
+/*******************************************************************************
+**
+** Function         copy_extra_byte_in_db
+**
+** Description      Utility function to allocate extra bytes memory in DB and copy
+**                  the value from a source place.
+**
+**
+** Parameter        p_db: database pointer.
+**                  p_dst: destination data pointer.
+**                  p_src: source data pointer.
+**                  len: data length to be copied.
+**
+** Returns          None.
+**
+*******************************************************************************/
+static bool    copy_extra_byte_in_db(tGATT_SVC_DB *p_db, void **p_dst, uint16_t len)
+{
+    uint8_t *p = (uint8_t *)*p_dst;
+
+    if (p_db->mem_free < len)
+    {
+        if (!allocate_svc_db_buf(p_db))
+        {
+            GATT_TRACE_ERROR("copy_extra_byte_in_db failed, no resources");
+            return false;
+        }
+    }
+
+    p = p_db->p_free_mem;
+    p_db->p_free_mem += len;
+    p_db->mem_free -= len;
+    memset((void *)p, 0, len);
+    *p_dst = (void *)p;
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         allocate_svc_db_buf
+**
+** Description      Utility function to allocate extra buffer for service database.
+**
+** Returns          true if allocation succeed, otherwise false.
+**
+*******************************************************************************/
+static bool    allocate_svc_db_buf(tGATT_SVC_DB *p_db)
+{
+    BT_HDR *p_buf = (BT_HDR *)osi_calloc(GATT_DB_BUF_SIZE);
+
+    GATT_TRACE_DEBUG("%s allocating extra buffer", __func__);
+
+    p_db->p_free_mem = (uint8_t *) p_buf;
+    p_db->mem_free = GATT_DB_BUF_SIZE;
+
+    fixed_queue_enqueue(p_db->svc_buffer, p_buf);
+
+    return true;
+
+}
+
+/*******************************************************************************
+**
+** Function         gatts_send_app_read_request
+**
+** Description      Send application read request callback
+**
+** Returns          status of operation.
+**
+*******************************************************************************/
+static tGATT_STATUS gatts_send_app_read_request(tGATT_TCB *p_tcb, uint8_t op_code,
+                                                uint16_t handle, uint16_t offset, uint32_t trans_id,
+                                                bt_gatt_db_attribute_type_t gatt_type)
+{
+    tGATTS_DATA   sr_data;
+    uint8_t     i_rcb;
+    tGATT_SR_REG *p_sreg;
+    uint16_t conn_id;
+
+    i_rcb = gatt_sr_find_i_rcb_by_handle(handle);
+    p_sreg = &gatt_cb.sr_reg[i_rcb];
+    conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_sreg->gatt_if);
+
+    if (trans_id == 0)
+    {
+        trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle);
+        gatt_sr_update_cback_cnt(p_tcb, p_sreg->gatt_if, true, true);
+    }
+
+    if (trans_id != 0 )
+    {
+        memset(&sr_data, 0, sizeof(tGATTS_DATA));
+
+        sr_data.read_req.handle = handle;
+        sr_data.read_req.is_long = (bool)(op_code == GATT_REQ_READ_BLOB);
+        sr_data.read_req.offset = offset;
+
+        uint8_t opcode;
+        if (gatt_type == BTGATT_DB_DESCRIPTOR) {
+            opcode = GATTS_REQ_TYPE_READ_DESCRIPTOR;
+        } else if (gatt_type == BTGATT_DB_CHARACTERISTIC) {
+            opcode = GATTS_REQ_TYPE_READ_CHARACTERISTIC;
+        } else {
+            GATT_TRACE_ERROR("%s: Attempt to read attribute that's not tied with"
+                             " characteristic or descriptor value.", __func__);
+            return GATT_ERROR;
+        }
+
+        gatt_sr_send_req_callback(conn_id,
+                                  trans_id, opcode, &sr_data);
+        return(tGATT_STATUS) GATT_PENDING;
+    }
+    else
+        return(tGATT_STATUS) GATT_BUSY; /* max pending command, application error */
+
+}
+
+/*******************************************************************************
+**
+** Function         gatts_db_add_service_declaration
+**
+** Description      Update a service database service declaration record.
+**
+** Parameter        p_db: database pointer.
+**                  service: UUID of the service.
+**
+** Returns          void
+**
+*******************************************************************************/
+static bool gatts_db_add_service_declaration(tGATT_SVC_DB *p_db, tBT_UUID *p_service, bool is_pri)
+{
+    tGATT_ATTR  *p_attr;
+    tBT_UUID    uuid = {LEN_UUID_16, {0}};
+    bool        rt = false;
+
+    GATT_TRACE_DEBUG( "add_service_declaration");
+
+    if (is_pri)
+        uuid.uu.uuid16 = GATT_UUID_PRI_SERVICE;
+    else
+        uuid.uu.uuid16 = GATT_UUID_SEC_SERVICE;
+
+    /* add service declration record */
+    if ((p_attr = (tGATT_ATTR *)(allocate_attr_in_db(p_db, &uuid, GATT_PERM_READ))) != NULL)
+    {
+        if (copy_extra_byte_in_db (p_db, (void **)&p_attr->p_value, sizeof(tBT_UUID)))
+        {
+            if (p_service->len == LEN_UUID_16)
+            {
+                p_attr->p_value->uuid.len = LEN_UUID_16;
+                p_attr->p_value->uuid.uu.uuid16 = p_service->uu.uuid16;
+            }
+            else if (p_service->len == LEN_UUID_32)
+            {
+                p_attr->p_value->uuid.len = LEN_UUID_128;
+                gatt_convert_uuid32_to_uuid128(p_attr->p_value->uuid.uu.uuid128, p_service->uu.uuid32);
+            }
+            else
+            {
+                p_attr->p_value->uuid.len = LEN_UUID_128;
+                memcpy(p_attr->p_value->uuid.uu.uuid128, p_service->uu.uuid128, LEN_UUID_128);
+            }
+            rt = true;
+        }
+
+    }
+    return rt;
+}
+
+#endif /* BLE_INCLUDED */
diff --git a/bt/stack/gatt/gatt_int.h b/bt/stack/gatt/gatt_int.h
new file mode 100644
index 0000000..ba1fe8f
--- /dev/null
+++ b/bt/stack/gatt/gatt_int.h
@@ -0,0 +1,647 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+
+#ifndef  GATT_INT_H
+#define  GATT_INT_H
+
+#include "bt_target.h"
+
+#include "osi/include/fixed_queue.h"
+#include "bt_trace.h"
+#include "gatt_api.h"
+#include "btm_ble_api.h"
+#include "btu.h"
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GATT_CREATE_CONN_ID(tcb_idx, gatt_if)  ((uint16_t) ((((uint8_t)(tcb_idx) ) << 8) | ((uint8_t) (gatt_if))))
+#define GATT_GET_TCB_IDX(conn_id)  ((uint8_t) (((uint16_t) (conn_id)) >> 8))
+#define GATT_GET_GATT_IF(conn_id)  ((tGATT_IF)((uint8_t) (conn_id)))
+
+#define GATT_GET_SR_REG_PTR(index) (&gatt_cb.sr_reg[(uint8_t) (index)]);
+#define GATT_TRANS_ID_MAX                   0x0fffffff      /* 4 MSB is reserved */
+
+/* security action for GATT write and read request */
+#define GATT_SEC_NONE              0
+#define GATT_SEC_OK                1
+#define GATT_SEC_SIGN_DATA         2   /* compute the signature for the write cmd */
+#define GATT_SEC_ENCRYPT           3    /* encrypt the link with current key */
+#define GATT_SEC_ENCRYPT_NO_MITM   4    /* unauthenticated encryption or better */
+#define GATT_SEC_ENCRYPT_MITM      5    /* authenticated encryption */
+#define GATT_SEC_ENC_PENDING       6   /* wait for link encryption pending */
+typedef uint8_t tGATT_SEC_ACTION;
+
+
+#define GATT_ATTR_OP_SPT_MTU               (0x00000001 << 0)
+#define GATT_ATTR_OP_SPT_FIND_INFO         (0x00000001 << 1)
+#define GATT_ATTR_OP_SPT_FIND_BY_TYPE      (0x00000001 << 2)
+#define GATT_ATTR_OP_SPT_READ_BY_TYPE      (0x00000001 << 3)
+#define GATT_ATTR_OP_SPT_READ              (0x00000001 << 4)
+#define GATT_ATTR_OP_SPT_MULT_READ         (0x00000001 << 5)
+#define GATT_ATTR_OP_SPT_READ_BLOB         (0x00000001 << 6)
+#define GATT_ATTR_OP_SPT_READ_BY_GRP_TYPE  (0x00000001 << 7)
+#define GATT_ATTR_OP_SPT_WRITE             (0x00000001 << 8)
+#define GATT_ATTR_OP_SPT_WRITE_CMD         (0x00000001 << 9)
+#define GATT_ATTR_OP_SPT_PREP_WRITE        (0x00000001 << 10)
+#define GATT_ATTR_OP_SPT_EXE_WRITE         (0x00000001 << 11)
+#define GATT_ATTR_OP_SPT_HDL_VALUE_CONF    (0x00000001 << 12)
+#define GATT_ATTR_OP_SP_SIGN_WRITE        (0x00000001 << 13)
+
+#define GATT_INDEX_INVALID  0xff
+
+#define GATT_PENDING_REQ_NONE    0
+
+
+#define GATT_WRITE_CMD_MASK  0xc0  /*0x1100-0000*/
+#define GATT_AUTH_SIGN_MASK  0x80  /*0x1000-0000*/
+#define GATT_AUTH_SIGN_LEN   12
+
+#define GATT_HDR_SIZE           3 /* 1B opcode + 2B handle */
+
+/* wait for ATT cmd response timeout value */
+#define GATT_WAIT_FOR_RSP_TIMEOUT_MS      (30 * 1000)
+#define GATT_WAIT_FOR_DISC_RSP_TIMEOUT_MS (5 * 1000)
+#define GATT_REQ_RETRY_LIMIT         2
+
+/* characteristic descriptor type */
+#define GATT_DESCR_EXT_DSCPTOR   1    /* Characteristic Extended Properties */
+#define GATT_DESCR_USER_DSCPTOR  2    /* Characteristic User Description    */
+#define GATT_DESCR_CLT_CONFIG    3    /* Client Characteristic Configuration */
+#define GATT_DESCR_SVR_CONFIG    4    /* Server Characteristic Configuration */
+#define GATT_DESCR_PRES_FORMAT   5    /* Characteristic Presentation Format */
+#define GATT_DESCR_AGGR_FORMAT   6    /* Characteristic Aggregate Format */
+#define GATT_DESCR_VALID_RANGE   7    /* Characteristic Valid Range */
+#define GATT_DESCR_UNKNOWN       0xff
+
+#define GATT_SEC_FLAG_LKEY_UNAUTHED     BTM_SEC_FLAG_LKEY_KNOWN
+#define GATT_SEC_FLAG_LKEY_AUTHED       BTM_SEC_FLAG_LKEY_AUTHED
+#define GATT_SEC_FLAG_ENCRYPTED         BTM_SEC_FLAG_ENCRYPTED
+typedef uint8_t tGATT_SEC_FLAG;
+
+/* Find Information Response Type
+*/
+#define GATT_INFO_TYPE_PAIR_16      0x01
+#define GATT_INFO_TYPE_PAIR_128     0x02
+
+/*  GATT client FIND_TYPE_VALUE_Request data */
+typedef struct
+{
+    tBT_UUID        uuid;           /* type of attribute to be found */
+    uint16_t        s_handle;       /* starting handle */
+    uint16_t        e_handle;       /* ending handle */
+    uint16_t        value_len;      /* length of the attribute value */
+    uint8_t         value[GATT_MAX_MTU_SIZE];       /* pointer to the attribute value to be found */
+} tGATT_FIND_TYPE_VALUE;
+
+/* client request message to ATT protocol
+*/
+typedef union
+{
+    tGATT_READ_BY_TYPE      browse;     /* read by type request */
+    tGATT_FIND_TYPE_VALUE   find_type_value;/* find by type value */
+    tGATT_READ_MULTI        read_multi;   /* read multiple request */
+    tGATT_READ_PARTIAL      read_blob;    /* read blob */
+    tGATT_VALUE             attr_value;   /* write request */
+                                          /* prepare write */
+    /* write blob */
+    uint16_t                handle;        /* read,  handle value confirmation */
+    uint16_t                mtu;
+    tGATT_EXEC_FLAG         exec_write;    /* execute write */
+}tGATT_CL_MSG;
+
+/* error response strucutre */
+typedef struct
+{
+    uint16_t handle;
+    uint8_t cmd_code;
+    uint8_t reason;
+}tGATT_ERROR;
+
+/* server response message to ATT protocol
+*/
+typedef union
+{
+    /* data type            member          event   */
+    tGATT_VALUE             attr_value;     /* READ, HANDLE_VALUE_IND, PREPARE_WRITE */
+                                            /* READ_BLOB, READ_BY_TYPE */
+    tGATT_ERROR             error;          /* ERROR_RSP */
+    uint16_t                handle;         /* WRITE, WRITE_BLOB */
+    uint16_t                mtu;            /* exchange MTU request */
+} tGATT_SR_MSG;
+
+/* Characteristic declaration attribute value
+*/
+typedef struct
+{
+    tGATT_CHAR_PROP             property;
+    uint16_t                    char_val_handle;
+} tGATT_CHAR_DECL;
+
+/* attribute value maintained in the server database
+*/
+typedef union
+{
+    tBT_UUID                uuid;               /* service declaration */
+    tGATT_CHAR_DECL         char_decl;          /* characteristic declaration */
+    tGATT_INCL_SRVC         incl_handle;        /* included service */
+
+} tGATT_ATTR_VALUE;
+
+/* Attribute UUID type
+*/
+#define GATT_ATTR_UUID_TYPE_16      0
+#define GATT_ATTR_UUID_TYPE_128     1
+#define GATT_ATTR_UUID_TYPE_32      2
+typedef uint8_t tGATT_ATTR_UUID_TYPE;
+
+/* 16 bits UUID Attribute in server database
+*/
+typedef struct
+{
+    void                                *p_next;  /* pointer to the next attribute,
+                                                    either tGATT_ATTR16 or tGATT_ATTR128 */
+    tGATT_ATTR_VALUE                    *p_value;
+    tGATT_PERM                          permission;
+    uint16_t                            handle;
+    tBT_UUID                            uuid;
+    bt_gatt_db_attribute_type_t         gatt_type;
+} tGATT_ATTR;
+
+/* Service Database definition
+*/
+typedef struct
+{
+    void            *p_attr_list;               /* pointer to the first attribute,
+                                                  either tGATT_ATTR16 or tGATT_ATTR128 */
+    uint8_t         *p_free_mem;                /* Pointer to free memory       */
+    fixed_queue_t   *svc_buffer;                /* buffer queue used for service database */
+    uint32_t        mem_free;                   /* Memory still available       */
+    uint16_t        end_handle;                 /* Last handle number           */
+    uint16_t        next_handle;                /* Next usable handle value     */
+} tGATT_SVC_DB;
+
+/* Data Structure used for GATT server                                        */
+/* A GATT registration record consists of a handle, and 1 or more attributes  */
+/* A service registration information record consists of beginning and ending */
+/* attribute handle, service UUID and a set of GATT server callback.          */
+typedef struct
+{
+    tGATT_SVC_DB    *p_db;      /* pointer to the service database */
+    tBT_UUID        app_uuid;           /* applicatino UUID */
+    uint32_t        sdp_handle; /* primamry service SDP handle */
+    uint16_t        type;       /* service type UUID, primary or secondary */
+    uint16_t        s_hdl;      /* service starting handle */
+    uint16_t        e_hdl;      /* service ending handle */
+    tGATT_IF        gatt_if;    /* this service is belong to which application */
+    bool            in_use;
+} tGATT_SR_REG;
+
+#define GATT_LISTEN_TO_ALL  0xff
+#define GATT_LISTEN_TO_NONE 0
+
+/* Data Structure used for GATT server */
+/* An GATT registration record consists of a handle, and 1 or more attributes */
+/* A service registration information record consists of beginning and ending */
+/* attribute handle, service UUID and a set of GATT server callback.          */
+
+typedef struct
+{
+    tBT_UUID     app_uuid128;
+    tGATT_CBACK  app_cb;
+    tGATT_IF     gatt_if; /* one based */
+    bool         in_use;
+    uint8_t      listening; /* if adv for all has been enabled */
+} tGATT_REG;
+
+
+
+
+/* command queue for each connection */
+typedef struct
+{
+    BT_HDR      *p_cmd;
+    uint16_t    clcb_idx;
+    uint8_t     op_code;
+    bool        to_send;
+}tGATT_CMD_Q;
+
+
+#if GATT_MAX_SR_PROFILES <= 8
+typedef uint8_t tGATT_APP_MASK;
+#elif GATT_MAX_SR_PROFILES <= 16
+typedef uint16_t tGATT_APP_MASK;
+#elif GATT_MAX_SR_PROFILES <= 32
+typedef uint32_t tGATT_APP_MASK;
+#endif
+
+/* command details for each connection */
+typedef struct
+{
+    BT_HDR          *p_rsp_msg;
+    uint32_t         trans_id;
+    tGATT_READ_MULTI multi_req;
+    fixed_queue_t   *multi_rsp_q;
+    uint16_t         handle;
+    uint8_t          op_code;
+    uint8_t          status;
+    uint8_t          cback_cnt[GATT_MAX_APPS];
+} tGATT_SR_CMD;
+
+#define     GATT_CH_CLOSE               0
+#define     GATT_CH_CLOSING             1
+#define     GATT_CH_CONN                2
+#define     GATT_CH_CFG                 3
+#define     GATT_CH_OPEN                4
+
+typedef uint8_t tGATT_CH_STATE;
+
+#define GATT_GATT_START_HANDLE  1
+#define GATT_GAP_START_HANDLE   20
+#define GATT_APP_START_HANDLE   40
+
+typedef struct hdl_cfg
+{
+    uint16_t             gatt_start_hdl;
+    uint16_t             gap_start_hdl;
+    uint16_t             app_start_hdl;
+}tGATT_HDL_CFG;
+
+typedef struct hdl_list_elem
+{
+    struct              hdl_list_elem *p_next;
+    struct              hdl_list_elem *p_prev;
+    tGATTS_HNDL_RANGE   asgn_range; /* assigned handle range */
+    tGATT_SVC_DB        svc_db;
+    bool                in_use;
+}tGATT_HDL_LIST_ELEM;
+
+typedef struct
+{
+    tGATT_HDL_LIST_ELEM  *p_first;
+    tGATT_HDL_LIST_ELEM  *p_last;
+    uint16_t             count;
+}tGATT_HDL_LIST_INFO;
+
+
+typedef struct srv_list_elem
+{
+    struct              srv_list_elem *p_next;
+    struct              srv_list_elem *p_prev;
+    uint16_t            s_hdl;
+    uint8_t             i_sreg;
+    bool                in_use;
+    bool                is_primary;
+}tGATT_SRV_LIST_ELEM;
+
+
+typedef struct
+{
+    tGATT_SRV_LIST_ELEM  *p_last_primary;
+    tGATT_SRV_LIST_ELEM  *p_first;
+    tGATT_SRV_LIST_ELEM  *p_last;
+    uint16_t             count;
+}tGATT_SRV_LIST_INFO;
+
+typedef struct
+{
+    fixed_queue_t   *pending_enc_clcb;   /* pending encryption channel q */
+    tGATT_SEC_ACTION sec_act;
+    BD_ADDR         peer_bda;
+    tBT_TRANSPORT   transport;
+    uint32_t        trans_id;
+
+    uint16_t        att_lcid;           /* L2CAP channel ID for ATT */
+    uint16_t        payload_size;
+
+    tGATT_CH_STATE  ch_state;
+    uint8_t         ch_flags;
+
+    tGATT_IF        app_hold_link[GATT_MAX_APPS];
+
+    /* server needs */
+    /* server response data */
+    tGATT_SR_CMD    sr_cmd;
+    uint16_t        indicate_handle;
+    fixed_queue_t   *pending_ind_q;
+
+    alarm_t         *conf_timer;         /* peer confirm to indication timer */
+
+    uint8_t         prep_cnt[GATT_MAX_APPS];
+    uint8_t         ind_count;
+
+    tGATT_CMD_Q     cl_cmd_q[GATT_CL_MAX_LCB];
+    alarm_t         *ind_ack_timer;   /* local app confirm to indication timer */
+    uint8_t         pending_cl_req;
+    uint8_t         next_slot_inq;    /* index of next available slot in queue */
+
+    bool            in_use;
+    uint8_t         tcb_idx;
+} tGATT_TCB;
+
+
+/* logic channel */
+typedef struct
+{
+    uint16_t                next_disc_start_hdl;   /* starting handle for the next inc srvv discovery */
+    tGATT_DISC_RES          result;
+    bool                    wait_for_read_rsp;
+} tGATT_READ_INC_UUID128;
+typedef struct
+{
+    tGATT_TCB               *p_tcb;         /* associated TCB of this CLCB */
+    tGATT_REG               *p_reg;        /* owner of this CLCB */
+    uint8_t                 sccb_idx;
+    uint8_t                 *p_attr_buf;    /* attribute buffer for read multiple, prepare write */
+    tBT_UUID                uuid;
+    uint16_t                conn_id;        /* connection handle */
+    uint16_t                clcb_idx;
+    uint16_t                s_handle;       /* starting handle of the active request */
+    uint16_t                e_handle;       /* ending handle of the active request */
+    uint16_t                counter;        /* used as offset, attribute length, num of prepare write */
+    uint16_t                start_offset;
+    tGATT_AUTH_REQ          auth_req;       /* authentication requirement */
+    uint8_t                 operation;      /* one logic channel can have one operation active */
+    uint8_t                 op_subtype;     /* operation subtype */
+    uint8_t                 status;         /* operation status */
+    bool                    first_read_blob_after_read;
+    tGATT_READ_INC_UUID128  read_uuid128;
+    bool                    in_use;
+    alarm_t                 *gatt_rsp_timer_ent;  /* peer response timer */
+    uint8_t                 retry_count;
+
+} tGATT_CLCB;
+
+typedef struct
+{
+    tGATT_CLCB  *p_clcb;
+}tGATT_PENDING_ENC_CLCB;
+
+typedef struct
+{
+    uint16_t                clcb_idx;
+    bool                    in_use;
+} tGATT_SCCB;
+
+typedef struct
+{
+    uint16_t    handle;
+    uint16_t    uuid;
+    uint32_t    service_change;
+}tGATT_SVC_CHG;
+
+typedef struct
+{
+    tGATT_IF        gatt_if[GATT_MAX_APPS];
+    BD_ADDR         remote_bda;
+    bool            in_use;
+}tGATT_BG_CONN_DEV;
+
+#define GATT_SVC_CHANGED_CONNECTING        1   /* wait for connection */
+#define GATT_SVC_CHANGED_SERVICE           2   /* GATT service discovery */
+#define GATT_SVC_CHANGED_CHARACTERISTIC    3   /* service change char discovery */
+#define GATT_SVC_CHANGED_DESCRIPTOR        4   /* service change CCC discoery */
+#define GATT_SVC_CHANGED_CONFIGURE_CCCD    5   /* config CCC */
+
+typedef struct
+{
+    uint16_t conn_id;
+    bool    in_use;
+    bool    connected;
+    BD_ADDR bda;
+    tBT_TRANSPORT   transport;
+
+    /* GATT service change CCC related variables */
+    uint8_t     ccc_stage;
+    uint8_t     ccc_result;
+    uint16_t    s_handle;
+    uint16_t    e_handle;
+}tGATT_PROFILE_CLCB;
+
+typedef struct
+{
+    tGATT_TCB           tcb[GATT_MAX_PHY_CHANNEL];
+    fixed_queue_t       *sign_op_queue;
+
+    tGATT_SR_REG        sr_reg[GATT_MAX_SR_PROFILES];
+    uint16_t            next_handle;    /* next available handle */
+    tGATT_SVC_CHG       gattp_attr;     /* GATT profile attribute service change */
+    tGATT_IF            gatt_if;
+    tGATT_HDL_LIST_INFO hdl_list_info;
+    tGATT_HDL_LIST_ELEM hdl_list[GATT_MAX_SR_PROFILES];
+    tGATT_SRV_LIST_INFO srv_list_info;
+    tGATT_SRV_LIST_ELEM srv_list[GATT_MAX_SR_PROFILES];
+
+    fixed_queue_t       *srv_chg_clt_q; /* service change clients queue */
+    tGATT_REG           cl_rcb[GATT_MAX_APPS];
+    tGATT_CLCB          clcb[GATT_CL_MAX_LCB];  /* connection link control block*/
+    tGATT_SCCB          sccb[GATT_MAX_SCCB];    /* sign complete callback function GATT_MAX_SCCB <= GATT_CL_MAX_LCB */
+    uint8_t             trace_level;
+    uint16_t            def_mtu_size;
+
+#if (GATT_CONFORMANCE_TESTING == TRUE)
+    bool                enable_err_rsp;
+    uint8_t             req_op_code;
+    uint8_t             err_status;
+    uint16_t            handle;
+#endif
+
+    tGATT_PROFILE_CLCB  profile_clcb[GATT_MAX_APPS];
+    uint16_t            handle_of_h_r;          /* Handle of the handles reused characteristic value */
+
+    tGATT_APPL_INFO       cb_info;
+
+
+
+    tGATT_HDL_CFG           hdl_cfg;
+    tGATT_BG_CONN_DEV       bgconn_dev[GATT_MAX_BG_CONN_DEV];
+
+} tGATT_CB;
+
+
+#define GATT_SIZE_OF_SRV_CHG_HNDL_RANGE 4
+
+/* Global GATT data */
+extern tGATT_CB gatt_cb;
+
+#if (GATT_CONFORMANCE_TESTING == TRUE)
+extern void gatt_set_err_rsp(bool    enable, uint8_t req_op_code, uint8_t err_status);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+/* from gatt_main.cc */
+extern bool gatt_disconnect (tGATT_TCB *p_tcb);
+extern bool gatt_act_connect (tGATT_REG *p_reg, BD_ADDR bd_addr, tBT_TRANSPORT transport, bool opportunistic);
+extern bool gatt_connect (BD_ADDR rem_bda,  tGATT_TCB *p_tcb, tBT_TRANSPORT transport);
+extern void gatt_data_process (tGATT_TCB *p_tcb, BT_HDR *p_buf);
+extern void gatt_update_app_use_link_flag ( tGATT_IF gatt_if, tGATT_TCB *p_tcb, bool    is_add, bool    check_acl_link);
+
+extern void gatt_profile_db_init(void);
+extern void gatt_set_ch_state(tGATT_TCB *p_tcb, tGATT_CH_STATE ch_state);
+extern tGATT_CH_STATE gatt_get_ch_state(tGATT_TCB *p_tcb);
+extern void gatt_init_srv_chg(void);
+extern void gatt_proc_srv_chg (void);
+extern void gatt_send_srv_chg_ind (BD_ADDR peer_bda);
+extern void gatt_chk_srv_chg(tGATTS_SRV_CHG *p_srv_chg_clt);
+extern void gatt_add_a_bonded_dev_for_srv_chg (BD_ADDR bda);
+
+/* from gatt_attr.cc */
+extern uint16_t gatt_profile_find_conn_id_by_bd_addr(BD_ADDR bda);
+
+
+/* Functions provided by att_protocol.cc */
+extern tGATT_STATUS attp_send_cl_msg (tGATT_TCB *p_tcb, uint16_t clcb_idx, uint8_t op_code, tGATT_CL_MSG *p_msg);
+extern BT_HDR *attp_build_sr_msg(tGATT_TCB *p_tcb, uint8_t op_code, tGATT_SR_MSG *p_msg);
+extern tGATT_STATUS attp_send_sr_msg (tGATT_TCB *p_tcb, BT_HDR *p_msg);
+extern tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB *p_tcb, BT_HDR *p_toL2CAP);
+
+/* utility functions */
+extern uint8_t * gatt_dbg_op_name(uint8_t op_code);
+extern uint32_t gatt_add_sdp_record (tBT_UUID *p_uuid, uint16_t start_hdl, uint16_t end_hdl);
+extern bool    gatt_parse_uuid_from_cmd(tBT_UUID *p_uuid, uint16_t len, uint8_t **p_data);
+extern uint8_t gatt_build_uuid_to_stream(uint8_t **p_dst, tBT_UUID uuid);
+extern bool    gatt_uuid_compare(tBT_UUID src, tBT_UUID tar);
+extern void gatt_convert_uuid32_to_uuid128(uint8_t uuid_128[LEN_UUID_128], uint32_t uuid_32);
+extern void gatt_sr_get_sec_info(BD_ADDR rem_bda, tBT_TRANSPORT transport, uint8_t *p_sec_flag, uint8_t *p_key_size);
+extern void gatt_start_rsp_timer(uint16_t clcb_idx);
+extern void gatt_start_conf_timer(tGATT_TCB    *p_tcb);
+extern void gatt_rsp_timeout(void *data);
+extern void gatt_indication_confirmation_timeout(void *data);
+extern void gatt_ind_ack_timeout(void *data);
+extern void gatt_start_ind_ack_timer(tGATT_TCB *p_tcb);
+extern tGATT_STATUS gatt_send_error_rsp(tGATT_TCB *p_tcb, uint8_t err_code, uint8_t op_code, uint16_t handle, bool    deq);
+extern void gatt_dbg_display_uuid(tBT_UUID bt_uuid);
+extern tGATT_PENDING_ENC_CLCB* gatt_add_pending_enc_channel_clcb(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb );
+
+extern bool    gatt_is_srv_chg_ind_pending (tGATT_TCB *p_tcb);
+extern tGATTS_SRV_CHG *gatt_is_bda_in_the_srv_chg_clt_list (BD_ADDR bda);
+
+extern bool    gatt_find_the_connected_bda(uint8_t start_idx, BD_ADDR bda, uint8_t *p_found_idx, tBT_TRANSPORT *p_transport);
+extern void gatt_set_srv_chg(void);
+extern void gatt_delete_dev_from_srv_chg_clt_list(BD_ADDR bd_addr);
+extern tGATT_VALUE *gatt_add_pending_ind(tGATT_TCB  *p_tcb, tGATT_VALUE *p_ind);
+extern void gatt_free_srvc_db_buffer_app_id(tBT_UUID *p_app_id);
+extern void gatt_update_listen_mode(int listening);
+extern bool    gatt_cl_send_next_cmd_inq(tGATT_TCB *p_tcb);
+
+/* reserved handle list */
+extern tGATT_HDL_LIST_ELEM *gatt_find_hdl_buffer_by_app_id (tBT_UUID *p_app_uuid128, tBT_UUID *p_svc_uuid, uint16_t svc_inst);
+extern tGATT_HDL_LIST_ELEM *gatt_find_hdl_buffer_by_handle(uint16_t handle);
+extern tGATT_HDL_LIST_ELEM *gatt_alloc_hdl_buffer(void);
+extern void gatt_free_hdl_buffer(tGATT_HDL_LIST_ELEM *p);
+extern bool    gatt_is_last_attribute(tGATT_SRV_LIST_INFO *p_list, tGATT_SRV_LIST_ELEM *p_start, tBT_UUID value);
+extern void gatt_update_last_pri_srv_info(tGATT_SRV_LIST_INFO *p_list);
+extern bool    gatt_add_a_srv_to_list(tGATT_SRV_LIST_INFO *p_list, tGATT_SRV_LIST_ELEM *p_new);
+extern bool    gatt_remove_a_srv_from_list(tGATT_SRV_LIST_INFO *p_list, tGATT_SRV_LIST_ELEM *p_remove);
+extern bool    gatt_add_an_item_to_list(tGATT_HDL_LIST_INFO *p_list, tGATT_HDL_LIST_ELEM *p_new);
+extern bool    gatt_remove_an_item_from_list(tGATT_HDL_LIST_INFO *p_list, tGATT_HDL_LIST_ELEM *p_remove);
+extern tGATTS_SRV_CHG *gatt_add_srv_chg_clt(tGATTS_SRV_CHG *p_srv_chg);
+
+/* for background connection */
+extern bool    gatt_update_auto_connect_dev (tGATT_IF gatt_if, bool    add, BD_ADDR bd_addr);
+extern bool    gatt_is_bg_dev_for_app(tGATT_BG_CONN_DEV *p_dev, tGATT_IF gatt_if);
+extern bool    gatt_remove_bg_dev_for_app(tGATT_IF gatt_if, BD_ADDR bd_addr);
+extern uint8_t gatt_get_num_apps_for_bg_dev(BD_ADDR bd_addr);
+extern bool    gatt_find_app_for_bg_dev(BD_ADDR bd_addr, tGATT_IF *p_gatt_if);
+extern tGATT_BG_CONN_DEV * gatt_find_bg_dev(BD_ADDR remote_bda);
+extern void gatt_deregister_bgdev_list(tGATT_IF gatt_if);
+
+/* server function */
+extern uint8_t gatt_sr_find_i_rcb_by_handle(uint16_t handle);
+extern uint8_t gatt_sr_find_i_rcb_by_app_id(tBT_UUID *p_app_uuid128, tBT_UUID *p_svc_uuid, uint16_t svc_inst);
+extern uint8_t gatt_sr_alloc_rcb(tGATT_HDL_LIST_ELEM *p_list);
+extern tGATT_STATUS gatt_sr_process_app_rsp (tGATT_TCB *p_tcb, tGATT_IF gatt_if, uint32_t trans_id, uint8_t op_code, tGATT_STATUS status, tGATTS_RSP *p_msg);
+extern void gatt_server_handle_client_req (tGATT_TCB *p_tcb, uint8_t op_code,
+                                           uint16_t len, uint8_t *p_data);
+extern void gatt_sr_send_req_callback(uint16_t conn_id,  uint32_t trans_id,
+                                      uint8_t op_code, tGATTS_DATA *p_req_data);
+extern uint32_t gatt_sr_enqueue_cmd (tGATT_TCB *p_tcb, uint8_t op_code, uint16_t handle);
+extern bool    gatt_cancel_open(tGATT_IF gatt_if, BD_ADDR bda);
+
+/*   */
+
+extern tGATT_REG *gatt_get_regcb (tGATT_IF gatt_if);
+extern bool    gatt_is_clcb_allocated (uint16_t conn_id);
+extern tGATT_CLCB *gatt_clcb_alloc (uint16_t conn_id);
+extern void gatt_clcb_dealloc (tGATT_CLCB *p_clcb);
+
+extern void gatt_sr_copy_prep_cnt_to_cback_cnt(tGATT_TCB *p_tcb );
+extern bool    gatt_sr_is_cback_cnt_zero(tGATT_TCB *p_tcb );
+extern bool    gatt_sr_is_prep_cnt_zero(tGATT_TCB *p_tcb );
+extern void gatt_sr_reset_cback_cnt(tGATT_TCB *p_tcb );
+extern void gatt_sr_reset_prep_cnt(tGATT_TCB *p_tcb );
+extern void gatt_sr_update_cback_cnt(tGATT_TCB *p_tcb, tGATT_IF gatt_if, bool    is_inc, bool    is_reset_first);
+extern void gatt_sr_update_prep_cnt(tGATT_TCB *p_tcb, tGATT_IF gatt_if, bool    is_inc, bool    is_reset_first);
+
+extern bool    gatt_find_app_hold_link(tGATT_TCB *p_tcb, uint8_t start_idx, uint8_t *p_found_idx, tGATT_IF *p_gatt_if);
+extern uint8_t gatt_num_apps_hold_link(tGATT_TCB *p_tcb);
+extern uint8_t gatt_num_clcb_by_bd_addr(BD_ADDR bda);
+extern tGATT_TCB * gatt_find_tcb_by_cid(uint16_t lcid);
+extern tGATT_TCB * gatt_allocate_tcb_by_bdaddr(BD_ADDR bda, tBT_TRANSPORT transport);
+extern tGATT_TCB * gatt_get_tcb_by_idx(uint8_t tcb_idx);
+extern tGATT_TCB * gatt_find_tcb_by_addr(BD_ADDR bda, tBT_TRANSPORT transport);
+extern bool    gatt_send_ble_burst_data (BD_ADDR remote_bda,  BT_HDR *p_buf);
+
+/* GATT client functions */
+extern void gatt_dequeue_sr_cmd (tGATT_TCB *p_tcb);
+extern uint8_t gatt_send_write_msg(tGATT_TCB *p_tcb, uint16_t clcb_idx, uint8_t op_code, uint16_t handle,
+                                 uint16_t len, uint16_t offset, uint8_t *p_data);
+extern void gatt_cleanup_upon_disc(BD_ADDR bda, uint16_t reason, tBT_TRANSPORT transport);
+extern void gatt_end_operation(tGATT_CLCB *p_clcb, tGATT_STATUS status, void *p_data);
+
+extern void gatt_act_discovery(tGATT_CLCB *p_clcb);
+extern void gatt_act_read(tGATT_CLCB *p_clcb, uint16_t offset);
+extern void gatt_act_write(tGATT_CLCB *p_clcb, uint8_t sec_act);
+extern uint8_t gatt_act_send_browse(tGATT_TCB *p_tcb, uint16_t index, uint8_t op, uint16_t s_handle, uint16_t e_handle,
+                                  tBT_UUID uuid);
+extern tGATT_CLCB *gatt_cmd_dequeue(tGATT_TCB *p_tcb, uint8_t *p_opcode);
+extern bool    gatt_cmd_enq(tGATT_TCB *p_tcb, uint16_t clcb_idx, bool    to_send, uint8_t op_code, BT_HDR *p_buf);
+extern void gatt_client_handle_server_rsp (tGATT_TCB *p_tcb, uint8_t op_code,
+                                           uint16_t len, uint8_t *p_data);
+extern void gatt_send_queue_write_cancel (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, tGATT_EXEC_FLAG flag);
+
+/* gatt_auth.cc */
+extern bool    gatt_security_check_start(tGATT_CLCB *p_clcb);
+extern void gatt_verify_signature(tGATT_TCB *p_tcb, BT_HDR *p_buf);
+extern tGATT_SEC_ACTION gatt_determine_sec_act(tGATT_CLCB *p_clcb );
+extern tGATT_STATUS gatt_get_link_encrypt_status(tGATT_TCB *p_tcb);
+extern tGATT_SEC_ACTION gatt_get_sec_act(tGATT_TCB *p_tcb);
+extern void gatt_set_sec_act(tGATT_TCB *p_tcb, tGATT_SEC_ACTION sec_act);
+
+/* gatt_db.cc */
+extern bool    gatts_init_service_db (tGATT_SVC_DB *p_db, tBT_UUID *p_service, bool    is_pri, uint16_t s_hdl, uint16_t num_handle);
+extern uint16_t gatts_add_included_service (tGATT_SVC_DB *p_db, uint16_t s_handle, uint16_t e_handle, tBT_UUID service);
+extern uint16_t gatts_add_characteristic (tGATT_SVC_DB *p_db, tGATT_PERM perm, tGATT_CHAR_PROP property, tBT_UUID *p_char_uuid);
+extern uint16_t gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm, tBT_UUID *p_dscp_uuid);
+extern tGATT_STATUS gatts_db_read_attr_value_by_type (tGATT_TCB *p_tcb, tGATT_SVC_DB *p_db, uint8_t op_code, BT_HDR *p_rsp, uint16_t s_handle,
+                                                      uint16_t e_handle, tBT_UUID type, uint16_t *p_len, tGATT_SEC_FLAG sec_flag, uint8_t key_size,uint32_t trans_id, uint16_t *p_cur_handle);
+extern tGATT_STATUS gatts_read_attr_value_by_handle(tGATT_TCB *p_tcb,tGATT_SVC_DB *p_db, uint8_t op_code, uint16_t handle, uint16_t offset,
+                                                    uint8_t *p_value, uint16_t *p_len, uint16_t mtu,tGATT_SEC_FLAG sec_flag,uint8_t key_size,uint32_t trans_id);
+extern tGATT_STATUS gatts_write_attr_perm_check (tGATT_SVC_DB *p_db, uint8_t op_code,uint16_t handle, uint16_t offset, uint8_t *p_data,
+                                                 uint16_t len, tGATT_SEC_FLAG sec_flag, uint8_t key_size);
+extern tGATT_STATUS gatts_read_attr_perm_check(tGATT_SVC_DB *p_db, bool    is_long, uint16_t handle, tGATT_SEC_FLAG sec_flag,uint8_t key_size);
+extern void gatts_update_srv_list_elem(uint8_t i_sreg, uint16_t handle, bool    is_primary);
+extern tBT_UUID * gatts_get_service_uuid (tGATT_SVC_DB *p_db);
+
+#endif
diff --git a/bt/stack/gatt/gatt_main.cc b/bt/stack/gatt/gatt_main.cc
new file mode 100644
index 0000000..f904e68
--- /dev/null
+++ b/bt/stack/gatt/gatt_main.cc
@@ -0,0 +1,1233 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 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 main ATT functions
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+#include "bt_common.h"
+#include "gatt_int.h"
+#include "l2c_api.h"
+#include "btm_int.h"
+#include "btm_ble_int.h"
+#include "bt_utils.h"
+#include "osi/include/osi.h"
+
+/* Configuration flags. */
+#define GATT_L2C_CFG_IND_DONE   (1<<0)
+#define GATT_L2C_CFG_CFM_DONE   (1<<1)
+
+/* minimum GATT MTU size over BR/EDR link
+*/
+#define GATT_MIN_BR_MTU_SIZE       48
+
+/********************************************************************************/
+/*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
+/********************************************************************************/
+static void gatt_le_connect_cback (uint16_t chan, BD_ADDR bd_addr, bool    connected,
+        uint16_t reason, tBT_TRANSPORT transport);
+static void gatt_le_data_ind (uint16_t chan, BD_ADDR bd_addr, BT_HDR *p_buf);
+static void gatt_le_cong_cback(BD_ADDR remote_bda, bool    congest);
+
+static void gatt_l2cif_connect_ind_cback (BD_ADDR  bd_addr, uint16_t l2cap_cid,
+        uint16_t psm, uint8_t l2cap_id);
+static void gatt_l2cif_connect_cfm_cback (uint16_t l2cap_cid, uint16_t result);
+static void gatt_l2cif_config_ind_cback (uint16_t l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void gatt_l2cif_config_cfm_cback (uint16_t l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void gatt_l2cif_disconnect_ind_cback (uint16_t l2cap_cid, bool    ack_needed);
+static void gatt_l2cif_disconnect_cfm_cback (uint16_t l2cap_cid, uint16_t result);
+static void gatt_l2cif_data_ind_cback (uint16_t l2cap_cid, BT_HDR *p_msg);
+static void gatt_send_conn_cback (tGATT_TCB *p_tcb);
+static void gatt_l2cif_congest_cback (uint16_t cid, bool    congested);
+
+static const tL2CAP_APPL_INFO dyn_info =
+{
+    gatt_l2cif_connect_ind_cback,
+    gatt_l2cif_connect_cfm_cback,
+    NULL,
+    gatt_l2cif_config_ind_cback,
+    gatt_l2cif_config_cfm_cback,
+    gatt_l2cif_disconnect_ind_cback,
+    gatt_l2cif_disconnect_cfm_cback,
+    NULL,
+    gatt_l2cif_data_ind_cback,
+    gatt_l2cif_congest_cback,
+    NULL
+} ;
+
+tGATT_CB gatt_cb;
+
+/*******************************************************************************
+**
+** Function         gatt_init
+**
+** Description      This function is enable the GATT profile on the device.
+**                  It clears out the control blocks, and registers with L2CAP.
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_init (void)
+{
+    tL2CAP_FIXED_CHNL_REG  fixed_reg;
+
+    GATT_TRACE_DEBUG("gatt_init()");
+
+    memset (&gatt_cb, 0, sizeof(tGATT_CB));
+    memset (&fixed_reg, 0, sizeof(tL2CAP_FIXED_CHNL_REG));
+
+#if defined(GATT_INITIAL_TRACE_LEVEL)
+    gatt_cb.trace_level = GATT_INITIAL_TRACE_LEVEL;
+#else
+    gatt_cb.trace_level = BT_TRACE_LEVEL_NONE;    /* No traces */
+#endif
+    gatt_cb.def_mtu_size = GATT_DEF_BLE_MTU_SIZE;
+    gatt_cb.sign_op_queue = fixed_queue_new(SIZE_MAX);
+    gatt_cb.srv_chg_clt_q = fixed_queue_new(SIZE_MAX);
+    /* First, register fixed L2CAP channel for ATT over BLE */
+    fixed_reg.fixed_chnl_opts.mode         = L2CAP_FCR_BASIC_MODE;
+    fixed_reg.fixed_chnl_opts.max_transmit = 0xFF;
+    fixed_reg.fixed_chnl_opts.rtrans_tout  = 2000;
+    fixed_reg.fixed_chnl_opts.mon_tout     = 12000;
+    fixed_reg.fixed_chnl_opts.mps          = 670;
+    fixed_reg.fixed_chnl_opts.tx_win_sz    = 1;
+
+    fixed_reg.pL2CA_FixedConn_Cb = gatt_le_connect_cback;
+    fixed_reg.pL2CA_FixedData_Cb = gatt_le_data_ind;
+    fixed_reg.pL2CA_FixedCong_Cb = gatt_le_cong_cback;      /* congestion callback */
+    fixed_reg.default_idle_tout  = 0xffff;                  /* 0xffff default idle timeout */
+
+    L2CA_RegisterFixedChannel (L2CAP_ATT_CID, &fixed_reg);
+
+    /* Now, register with L2CAP for ATT PSM over BR/EDR */
+    if (!L2CA_Register (BT_PSM_ATT, (tL2CAP_APPL_INFO *) &dyn_info))
+    {
+        GATT_TRACE_ERROR ("ATT Dynamic Registration failed");
+    }
+
+    BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_ATT, BTM_SEC_NONE, BT_PSM_ATT, 0, 0);
+    BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_ATT, BTM_SEC_NONE, BT_PSM_ATT, 0, 0);
+
+    gatt_cb.hdl_cfg.gatt_start_hdl = GATT_GATT_START_HANDLE;
+    gatt_cb.hdl_cfg.gap_start_hdl  = GATT_GAP_START_HANDLE;
+    gatt_cb.hdl_cfg.app_start_hdl  = GATT_APP_START_HANDLE;
+    gatt_profile_db_init();
+
+}
+
+
+/*******************************************************************************
+**
+** Function         gatt_free
+**
+** Description      This function frees resources used by the GATT profile.
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_free(void)
+{
+    int i;
+    GATT_TRACE_DEBUG("gatt_free()");
+
+    fixed_queue_free(gatt_cb.sign_op_queue, NULL);
+    gatt_cb.sign_op_queue = NULL;
+    fixed_queue_free(gatt_cb.srv_chg_clt_q, NULL);
+    gatt_cb.srv_chg_clt_q = NULL;
+    for (i = 0; i < GATT_MAX_PHY_CHANNEL; i++)
+    {
+        fixed_queue_free(gatt_cb.tcb[i].pending_enc_clcb, NULL);
+        gatt_cb.tcb[i].pending_enc_clcb = NULL;
+
+        fixed_queue_free(gatt_cb.tcb[i].pending_ind_q, NULL);
+        gatt_cb.tcb[i].pending_ind_q = NULL;
+
+        alarm_free(gatt_cb.tcb[i].conf_timer);
+        gatt_cb.tcb[i].conf_timer = NULL;
+
+        alarm_free(gatt_cb.tcb[i].ind_ack_timer);
+        gatt_cb.tcb[i].ind_ack_timer = NULL;
+
+        fixed_queue_free(gatt_cb.tcb[i].sr_cmd.multi_rsp_q, NULL);
+        gatt_cb.tcb[i].sr_cmd.multi_rsp_q = NULL;
+    }
+    for (i = 0; i < GATT_MAX_SR_PROFILES; i++)
+    {
+        gatt_free_hdl_buffer(&gatt_cb.hdl_list[i]);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_connect
+**
+** Description      This function is called to initiate a connection to a peer device.
+**
+** Parameter        rem_bda: remote device address to connect to.
+**
+** Returns          true if connection is started, otherwise return false.
+**
+*******************************************************************************/
+bool    gatt_connect (BD_ADDR rem_bda, tGATT_TCB *p_tcb, tBT_TRANSPORT transport)
+{
+    bool                gatt_ret = false;
+
+    if (gatt_get_ch_state(p_tcb) != GATT_CH_OPEN)
+        gatt_set_ch_state(p_tcb, GATT_CH_CONN);
+
+    if (transport == BT_TRANSPORT_LE)
+    {
+        p_tcb->att_lcid = L2CAP_ATT_CID;
+        gatt_ret = L2CA_ConnectFixedChnl (L2CAP_ATT_CID, rem_bda);
+    }
+    else
+    {
+        if ((p_tcb->att_lcid = L2CA_ConnectReq(BT_PSM_ATT, rem_bda)) != 0)
+            gatt_ret = true;
+    }
+
+    return gatt_ret;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_disconnect
+**
+** Description      This function is called to disconnect to an ATT device.
+**
+** Parameter        p_tcb: pointer to the TCB to disconnect.
+**
+** Returns          true: if connection found and to be disconnected; otherwise
+**                  return false.
+**
+*******************************************************************************/
+bool    gatt_disconnect (tGATT_TCB *p_tcb)
+{
+    bool                ret = false;
+    tGATT_CH_STATE      ch_state;
+
+    GATT_TRACE_EVENT ("%s", __func__);
+
+    if (p_tcb != NULL)
+    {
+        ret = true;
+        if ( (ch_state = gatt_get_ch_state(p_tcb)) != GATT_CH_CLOSING )
+        {
+            if (p_tcb->att_lcid == L2CAP_ATT_CID)
+            {
+                if (ch_state == GATT_CH_OPEN)
+                {
+                    /* only LCB exist between remote device and local */
+                    ret = L2CA_RemoveFixedChnl (L2CAP_ATT_CID, p_tcb->peer_bda);
+                }
+                else
+                {
+                    ret = L2CA_CancelBleConnectReq (p_tcb->peer_bda);
+                    if (!ret)
+                        gatt_set_ch_state(p_tcb, GATT_CH_CLOSE);
+                }
+                gatt_set_ch_state(p_tcb, GATT_CH_CLOSING);
+            }
+            else
+            {
+                if ((ch_state == GATT_CH_OPEN) || (ch_state == GATT_CH_CFG))
+                    ret = L2CA_DisconnectReq(p_tcb->att_lcid);
+                else
+                    GATT_TRACE_DEBUG ("%s gatt_disconnect channel not opened", __func__);
+            }
+        }
+        else
+        {
+            GATT_TRACE_DEBUG ("%s already in closing state", __func__);
+        }
+    }
+
+    return ret;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_update_app_hold_link_status
+**
+** Description      Update the application use link status
+**
+** Returns          true if any modifications are made, false otherwise.
+**
+*******************************************************************************/
+bool    gatt_update_app_hold_link_status(tGATT_IF gatt_if, tGATT_TCB *p_tcb, bool    is_add)
+{
+    for (int i=0; i<GATT_MAX_APPS; i++) {
+        if (p_tcb->app_hold_link[i] == 0 && is_add) {
+            p_tcb->app_hold_link[i] = gatt_if;
+            GATT_TRACE_DEBUG("%s: added gatt_if=%d idx=%d ", __func__, gatt_if, i);
+            return true;
+        } else if (p_tcb->app_hold_link[i] == gatt_if && !is_add) {
+            p_tcb->app_hold_link[i] = 0;
+            GATT_TRACE_DEBUG("%s: removed gatt_if=%d idx=%d", __func__, gatt_if, i);
+            return true;
+        }
+    }
+
+    GATT_TRACE_DEBUG("%s: gatt_if=%d not found; is_add=%d", __func__, gatt_if, is_add);
+    return false;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_update_app_use_link_flag
+**
+** Description      Update the application use link flag and optional to check the acl link
+**                  if the link is up then set the idle time out accordingly
+**
+** Returns          void.
+**
+*******************************************************************************/
+void gatt_update_app_use_link_flag(tGATT_IF gatt_if, tGATT_TCB *p_tcb, bool    is_add,
+                                   bool    check_acl_link)
+{
+    GATT_TRACE_DEBUG("%s: is_add=%d chk_link=%d", __func__, is_add, check_acl_link);
+
+    if (!p_tcb)
+        return;
+
+    // If we make no modification, i.e. kill app that was never connected to a device,
+    // skip updating the device state.
+    if (!gatt_update_app_hold_link_status(gatt_if, p_tcb, is_add))
+        return;
+
+    if (!check_acl_link ||
+            p_tcb->att_lcid != L2CAP_ATT_CID || /* only update link idle timer for fixed channel */
+            (BTM_GetHCIConnHandle(p_tcb->peer_bda, p_tcb->transport) == GATT_INVALID_ACL_HANDLE)) {
+        return;
+    }
+
+    if (is_add) {
+        GATT_TRACE_DEBUG("%s: disable link idle timer", __func__);
+        /* acl link is connected disable the idle timeout */
+        GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT, p_tcb->transport);
+    } else {
+        if (!gatt_num_apps_hold_link(p_tcb)) {
+            /* acl link is connected but no application needs to use the link
+               so set the timeout value to GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP seconds */
+            GATT_TRACE_DEBUG("%s: start link idle timer =%d sec", __func__,
+                             GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP);
+            GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP,
+                                p_tcb->transport);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_act_connect
+**
+** Description      GATT connection initiation.
+**
+** Returns          void.
+**
+*******************************************************************************/
+bool gatt_act_connect (tGATT_REG *p_reg, BD_ADDR bd_addr,
+                          tBT_TRANSPORT transport, bool opportunistic)
+{
+    bool        ret = false;
+    tGATT_TCB   *p_tcb;
+    uint8_t     st;
+
+    if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, transport)) != NULL)
+    {
+        ret = true;
+        st = gatt_get_ch_state(p_tcb);
+
+        /* before link down, another app try to open a GATT connection */
+        if(st == GATT_CH_OPEN &&  gatt_num_apps_hold_link(p_tcb) == 0 &&
+            transport == BT_TRANSPORT_LE )
+        {
+            if (!gatt_connect(bd_addr,  p_tcb, transport))
+                ret = false;
+        }
+        else if(st == GATT_CH_CLOSING)
+        {
+            /* need to complete the closing first */
+            ret = false;
+        }
+    }
+    else
+    {
+        if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, transport)) != NULL)
+        {
+            if (!gatt_connect(bd_addr,  p_tcb, transport))
+            {
+                GATT_TRACE_ERROR("gatt_connect failed");
+                fixed_queue_free(p_tcb->pending_enc_clcb, NULL);
+                fixed_queue_free(p_tcb->pending_ind_q, NULL);
+                memset(p_tcb, 0, sizeof(tGATT_TCB));
+            }
+            else
+                ret = true;
+        }
+        else
+        {
+            ret = 0;
+            GATT_TRACE_ERROR("Max TCB for gatt_if [%d] reached.", p_reg->gatt_if);
+        }
+    }
+
+    if (ret)
+    {
+        if (!opportunistic)
+            gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, true, false);
+        else
+            GATT_TRACE_DEBUG("%s: connection is opportunistic, not updating app usage",
+                            __func__);
+    }
+
+    return ret;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_le_connect_cback
+**
+** Description      This callback function is called by L2CAP to indicate that
+**                  the ATT fixed channel for LE is
+**                      connected (conn = true)/disconnected (conn = false).
+**
+*******************************************************************************/
+static void gatt_le_connect_cback (uint16_t chan, BD_ADDR bd_addr, bool    connected,
+                                   uint16_t reason, tBT_TRANSPORT transport)
+{
+
+    tGATT_TCB       *p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
+    bool                    check_srv_chg = false;
+    tGATTS_SRV_CHG          *p_srv_chg_clt=NULL;
+
+    /* ignore all fixed channel connect/disconnect on BR/EDR link for GATT */
+    if (transport == BT_TRANSPORT_BR_EDR)
+        return;
+
+    GATT_TRACE_DEBUG ("GATT   ATT protocol channel with BDA: %08x%04x is %s",
+                       (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
+                       (bd_addr[4]<<8)+bd_addr[5], (connected) ? "connected" : "disconnected");
+
+    if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(bd_addr)) != NULL)
+    {
+        check_srv_chg = true;
+    }
+    else
+    {
+        if (btm_sec_is_a_bonded_dev(bd_addr))
+            gatt_add_a_bonded_dev_for_srv_chg(bd_addr);
+    }
+
+    if (connected)
+    {
+        /* do we have a channel initiating a connection? */
+        if (p_tcb)
+        {
+            /* we are initiating connection */
+            if ( gatt_get_ch_state(p_tcb) == GATT_CH_CONN)
+            {
+                /* send callback */
+                gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
+                p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;
+
+                gatt_send_conn_cback(p_tcb);
+            }
+            if (check_srv_chg)
+                gatt_chk_srv_chg (p_srv_chg_clt);
+        }
+        /* this is incoming connection or background connection callback */
+
+        else
+        {
+            if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, BT_TRANSPORT_LE)) != NULL)
+            {
+                p_tcb->att_lcid = L2CAP_ATT_CID;
+
+                gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
+
+                p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;
+
+                gatt_send_conn_cback (p_tcb);
+                if (check_srv_chg)
+                {
+                    gatt_chk_srv_chg (p_srv_chg_clt);
+                }
+            }
+            else
+            {
+                GATT_TRACE_ERROR("CCB max out, no rsources");
+            }
+        }
+    }
+    else
+    {
+        gatt_cleanup_upon_disc(bd_addr, reason, transport);
+        GATT_TRACE_DEBUG ("ATT disconnected");
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_channel_congestion
+**
+** Description      This function is called to process the congestion callback
+**                  from lcb
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gatt_channel_congestion(tGATT_TCB *p_tcb, bool    congested)
+{
+    uint8_t i = 0;
+    tGATT_REG *p_reg=NULL;
+    uint16_t conn_id;
+
+    /* if uncongested, check to see if there is any more pending data */
+    if (p_tcb != NULL && congested == false)
+    {
+        gatt_cl_send_next_cmd_inq(p_tcb);
+    }
+    /* notifying all applications for the connection up event */
+    for (i = 0, p_reg = gatt_cb.cl_rcb ; i < GATT_MAX_APPS; i++, p_reg++)
+    {
+        if (p_reg->in_use)
+        {
+            if (p_reg->app_cb.p_congestion_cb)
+            {
+                conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
+                (*p_reg->app_cb.p_congestion_cb)(conn_id, congested);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_le_cong_cback
+**
+** Description      This function is called when GATT fixed channel is congested
+**                  or uncongested.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gatt_le_cong_cback(BD_ADDR remote_bda, bool    congested)
+{
+    tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(remote_bda, BT_TRANSPORT_LE);
+
+    /* if uncongested, check to see if there is any more pending data */
+    if (p_tcb != NULL)
+    {
+        gatt_channel_congestion(p_tcb, congested);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_le_data_ind
+**
+** Description      This function is called when data is received from L2CAP.
+**                  if we are the originator of the connection, we are the ATT
+**                  client, and the received message is queued up for the client.
+**
+**                  If we are the destination of the connection, we are the ATT
+**                  server, so the message is passed to the server processing
+**                  function.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gatt_le_data_ind (uint16_t chan, BD_ADDR bd_addr, BT_HDR *p_buf)
+{
+    tGATT_TCB    *p_tcb;
+
+    /* Find CCB based on bd addr */
+    if ((p_tcb = gatt_find_tcb_by_addr (bd_addr, BT_TRANSPORT_LE)) != NULL &&
+        gatt_get_ch_state(p_tcb) >= GATT_CH_OPEN)
+    {
+        gatt_data_process(p_tcb, p_buf);
+    }
+    else
+    {
+        osi_free(p_buf);
+
+        if (p_tcb != NULL)
+        {
+            GATT_TRACE_WARNING ("ATT - Ignored L2CAP data while in state: %d",
+                                 gatt_get_ch_state(p_tcb));
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_l2cif_connect_ind
+**
+** Description      This function handles an inbound connection indication
+**                  from L2CAP. This is the case where we are acting as a
+**                  server.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gatt_l2cif_connect_ind_cback (BD_ADDR  bd_addr, uint16_t lcid,
+                                          UNUSED_ATTR uint16_t psm, uint8_t id)
+{
+    /* do we already have a control channel for this peer? */
+    uint8_t     result = L2CAP_CONN_OK;
+    tL2CAP_CFG_INFO cfg;
+    tGATT_TCB       *p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_BR_EDR);
+
+    GATT_TRACE_ERROR("Connection indication cid = %d", lcid);
+    /* new connection ? */
+    if (p_tcb == NULL)
+    {
+        /* allocate tcb */
+        if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, BT_TRANSPORT_BR_EDR)) == NULL)
+        {
+            /* no tcb available, reject L2CAP connection */
+            result = L2CAP_CONN_NO_RESOURCES;
+        }
+        else
+            p_tcb->att_lcid = lcid;
+
+    }
+    else /* existing connection , reject it */
+    {
+        result = L2CAP_CONN_NO_RESOURCES;
+    }
+
+    /* Send L2CAP connect rsp */
+    L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
+
+    /* if result ok, proceed with connection */
+    if (result == L2CAP_CONN_OK)
+    {
+        /* transition to configuration state */
+        gatt_set_ch_state(p_tcb, GATT_CH_CFG);
+
+        /* Send L2CAP config req */
+        memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+        cfg.mtu_present = true;
+        cfg.mtu = GATT_MAX_MTU_SIZE;
+
+        L2CA_ConfigReq(lcid, &cfg);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_l2c_connect_cfm_cback
+**
+** Description      This is the L2CAP connect confirm callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gatt_l2cif_connect_cfm_cback(uint16_t lcid, uint16_t result)
+{
+    tGATT_TCB       *p_tcb;
+    tL2CAP_CFG_INFO cfg;
+
+    /* look up clcb for this channel */
+    if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
+    {
+        GATT_TRACE_DEBUG("gatt_l2c_connect_cfm_cback result: %d ch_state: %d, lcid:0x%x", result, gatt_get_ch_state(p_tcb), p_tcb->att_lcid);
+
+        /* if in correct state */
+        if (gatt_get_ch_state(p_tcb) == GATT_CH_CONN)
+        {
+            /* if result successful */
+            if (result == L2CAP_CONN_OK)
+            {
+                /* set channel state */
+                gatt_set_ch_state(p_tcb, GATT_CH_CFG);
+
+                /* Send L2CAP config req */
+                memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+                cfg.mtu_present = true;
+                cfg.mtu = GATT_MAX_MTU_SIZE;
+                L2CA_ConfigReq(lcid, &cfg);
+            }
+            /* else initiating connection failure */
+            else
+            {
+                gatt_cleanup_upon_disc(p_tcb->peer_bda, result, GATT_TRANSPORT_BR_EDR);
+            }
+        }
+        else /* wrong state, disconnect it */
+        {
+            if (result == L2CAP_CONN_OK)
+            {
+                /* just in case the peer also accepts our connection - Send L2CAP disconnect req */
+                L2CA_DisconnectReq(lcid);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_l2cif_config_cfm_cback
+**
+** Description      This is the L2CAP config confirm callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_l2cif_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+    tGATT_TCB       *p_tcb;
+    tGATTS_SRV_CHG  *p_srv_chg_clt=NULL;
+
+    /* look up clcb for this channel */
+    if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
+    {
+        /* if in correct state */
+        if ( gatt_get_ch_state(p_tcb) == GATT_CH_CFG)
+        {
+            /* if result successful */
+            if (p_cfg->result == L2CAP_CFG_OK)
+            {
+                /* update flags */
+                p_tcb->ch_flags |= GATT_L2C_CFG_CFM_DONE;
+
+                /* if configuration complete */
+                if (p_tcb->ch_flags & GATT_L2C_CFG_IND_DONE)
+                {
+                    gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
+
+                    if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda)) != NULL)
+                    {
+                        gatt_chk_srv_chg(p_srv_chg_clt);
+                    }
+                    else
+                    {
+                        if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
+                            gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
+                    }
+
+                    /* send callback */
+                    gatt_send_conn_cback(p_tcb);
+                }
+            }
+            /* else failure */
+            else
+            {
+                /* Send L2CAP disconnect req */
+                L2CA_DisconnectReq(lcid);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_l2cif_config_ind_cback
+**
+** Description      This is the L2CAP config indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_l2cif_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+    tGATT_TCB       *p_tcb;
+    tGATTS_SRV_CHG  *p_srv_chg_clt=NULL;
+    /* look up clcb for this channel */
+    if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
+    {
+        /* GATT uses the smaller of our MTU and peer's MTU  */
+        if ( p_cfg->mtu_present &&
+             (p_cfg->mtu >= GATT_MIN_BR_MTU_SIZE && p_cfg->mtu < L2CAP_DEFAULT_MTU))
+            p_tcb->payload_size = p_cfg->mtu;
+        else
+            p_tcb->payload_size = L2CAP_DEFAULT_MTU;
+
+        /* send L2CAP configure response */
+        memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+        p_cfg->result = L2CAP_CFG_OK;
+        L2CA_ConfigRsp(lcid, p_cfg);
+
+        /* if first config ind */
+        if ((p_tcb->ch_flags & GATT_L2C_CFG_IND_DONE) == 0)
+        {
+            /* update flags */
+            p_tcb->ch_flags |= GATT_L2C_CFG_IND_DONE;
+
+            /* if configuration complete */
+            if (p_tcb->ch_flags & GATT_L2C_CFG_CFM_DONE)
+            {
+                gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
+                if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda)) != NULL)
+                {
+                    gatt_chk_srv_chg(p_srv_chg_clt);
+                }
+                else
+                {
+                    if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
+                        gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
+                }
+
+                /* send callback */
+                gatt_send_conn_cback(p_tcb);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_l2cif_disconnect_ind_cback
+**
+** Description      This is the L2CAP disconnect indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_l2cif_disconnect_ind_cback(uint16_t lcid, bool    ack_needed)
+{
+    tGATT_TCB       *p_tcb;
+    uint16_t        reason;
+
+    /* look up clcb for this channel */
+    if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
+    {
+        if (ack_needed)
+        {
+            /* send L2CAP disconnect response */
+            L2CA_DisconnectRsp(lcid);
+        }
+        if (gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda) == NULL)
+        {
+            if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
+                gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
+        }
+        /* if ACL link is still up, no reason is logged, l2cap is disconnect from peer */
+        if ((reason = L2CA_GetDisconnectReason(p_tcb->peer_bda, p_tcb->transport)) == 0)
+            reason = GATT_CONN_TERMINATE_PEER_USER;
+
+        /* send disconnect callback */
+        gatt_cleanup_upon_disc(p_tcb->peer_bda, reason, GATT_TRANSPORT_BR_EDR);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_l2cif_disconnect_cfm_cback
+**
+** Description      This is the L2CAP disconnect confirm callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gatt_l2cif_disconnect_cfm_cback(uint16_t lcid,
+                                            UNUSED_ATTR uint16_t result)
+{
+    tGATT_TCB       *p_tcb;
+    uint16_t        reason;
+
+    /* look up clcb for this channel */
+    if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
+    {
+        /* If the device is not in the service changed client list, add it... */
+        if (gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda) == NULL)
+        {
+            if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
+                gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
+        }
+
+        /* send disconnect callback */
+        /* if ACL link is still up, no reason is logged, l2cap is disconnect from peer */
+        if ((reason = L2CA_GetDisconnectReason(p_tcb->peer_bda, p_tcb->transport)) == 0)
+            reason = GATT_CONN_TERMINATE_LOCAL_HOST;
+
+        gatt_cleanup_upon_disc(p_tcb->peer_bda, reason, GATT_TRANSPORT_BR_EDR);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_l2cif_data_ind_cback
+**
+** Description      This is the L2CAP data indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gatt_l2cif_data_ind_cback(uint16_t lcid, BT_HDR *p_buf)
+{
+    tGATT_TCB       *p_tcb;
+
+    /* look up clcb for this channel */
+    if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL &&
+        gatt_get_ch_state(p_tcb) == GATT_CH_OPEN)
+    {
+        /* process the data */
+        gatt_data_process(p_tcb, p_buf);
+    }
+    else /* prevent buffer leak */
+        osi_free(p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         gatt_l2cif_congest_cback
+**
+** Description      L2CAP congestion callback
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gatt_l2cif_congest_cback (uint16_t lcid, bool    congested)
+{
+    tGATT_TCB *p_tcb = gatt_find_tcb_by_cid(lcid);
+
+    if (p_tcb != NULL)
+    {
+        gatt_channel_congestion(p_tcb, congested);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_send_conn_cback
+**
+** Description      Callback used to notify layer above about a connection.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gatt_send_conn_cback(tGATT_TCB *p_tcb)
+{
+    uint8_t             i;
+    tGATT_REG           *p_reg;
+    tGATT_BG_CONN_DEV   *p_bg_dev=NULL;
+    uint16_t            conn_id;
+
+    p_bg_dev = gatt_find_bg_dev(p_tcb->peer_bda);
+
+    /* notifying all applications for the connection up event */
+    for (i = 0,  p_reg = gatt_cb.cl_rcb ; i < GATT_MAX_APPS; i++, p_reg++)
+    {
+        if (p_reg->in_use)
+        {
+            if (p_bg_dev && gatt_is_bg_dev_for_app(p_bg_dev, p_reg->gatt_if))
+                gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, true, true);
+
+            if (p_reg->app_cb.p_conn_cb)
+            {
+                conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
+                (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, p_tcb->peer_bda, conn_id,
+                                          true, 0, p_tcb->transport);
+            }
+        }
+    }
+
+
+    if (gatt_num_apps_hold_link(p_tcb) &&  p_tcb->att_lcid == L2CAP_ATT_CID )
+    {
+        /* disable idle timeout if one or more clients are holding the link disable the idle timer */
+        GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT, p_tcb->transport);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_le_data_ind
+**
+** Description      This function is called when data is received from L2CAP.
+**                  if we are the originator of the connection, we are the ATT
+**                  client, and the received message is queued up for the client.
+**
+**                  If we are the destination of the connection, we are the ATT
+**                  server, so the message is passed to the server processing
+**                  function.
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_data_process (tGATT_TCB *p_tcb, BT_HDR *p_buf)
+{
+    uint8_t *p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+    uint8_t op_code, pseudo_op_code;
+    uint16_t msg_len;
+
+    if (p_buf->len > 0)
+    {
+        msg_len = p_buf->len - 1;
+        STREAM_TO_UINT8(op_code, p);
+
+        /* remove the two MSBs associated with sign write and write cmd */
+        pseudo_op_code = op_code & (~GATT_WRITE_CMD_MASK);
+
+        if (pseudo_op_code < GATT_OP_CODE_MAX)
+        {
+            if (op_code == GATT_SIGN_CMD_WRITE)
+            {
+                gatt_verify_signature(p_tcb, p_buf);
+            }
+            else
+            {
+                /* message from client */
+                if ((op_code % 2) == 0)
+                    gatt_server_handle_client_req (p_tcb, op_code, msg_len, p);
+                else
+                    gatt_client_handle_server_rsp (p_tcb, op_code, msg_len, p);
+            }
+        }
+        else
+        {
+            GATT_TRACE_ERROR ("ATT - Rcvd L2CAP data, unknown cmd: 0x%x", op_code);
+        }
+    }
+    else
+    {
+        GATT_TRACE_ERROR ("invalid data length, ignore");
+    }
+
+    osi_free(p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         gatt_add_a_bonded_dev_for_srv_chg
+**
+** Description      Add a bonded dev to the service changed client list
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_add_a_bonded_dev_for_srv_chg (BD_ADDR bda)
+{
+    tGATTS_SRV_CHG_REQ req;
+    tGATTS_SRV_CHG srv_chg_clt;
+
+    memcpy(srv_chg_clt.bda, bda, BD_ADDR_LEN);
+    srv_chg_clt.srv_changed = false;
+    if (gatt_add_srv_chg_clt(&srv_chg_clt) != NULL)
+    {
+        memcpy(req.srv_chg.bda, bda, BD_ADDR_LEN);
+        req.srv_chg.srv_changed = false;
+        if (gatt_cb.cb_info.p_srv_chg_callback)
+            (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_ADD_CLIENT, &req, NULL);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_send_srv_chg_ind
+**
+** Description      This function is called to send a service chnaged indication to
+**                  the specified bd address
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_send_srv_chg_ind (BD_ADDR peer_bda)
+{
+    uint8_t handle_range[GATT_SIZE_OF_SRV_CHG_HNDL_RANGE];
+    uint8_t *p = handle_range;
+    uint16_t conn_id;
+
+    GATT_TRACE_DEBUG("gatt_send_srv_chg_ind");
+
+    if (gatt_cb.handle_of_h_r)
+    {
+        if ((conn_id = gatt_profile_find_conn_id_by_bd_addr(peer_bda)) != GATT_INVALID_CONN_ID)
+        {
+            UINT16_TO_STREAM (p, 1);
+            UINT16_TO_STREAM (p, 0xFFFF);
+            GATTS_HandleValueIndication (conn_id,
+                                         gatt_cb.handle_of_h_r,
+                                         GATT_SIZE_OF_SRV_CHG_HNDL_RANGE,
+                                         handle_range);
+        }
+        else
+        {
+            GATT_TRACE_ERROR("Unable to find conn_id for  %08x%04x ",
+                              (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3],
+                              (peer_bda[4]<<8)+peer_bda[5] );
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_chk_srv_chg
+**
+** Description      Check sending service chnaged Indication is required or not
+**                  if required then send the Indication
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_chk_srv_chg(tGATTS_SRV_CHG *p_srv_chg_clt)
+{
+    GATT_TRACE_DEBUG("gatt_chk_srv_chg srv_changed=%d", p_srv_chg_clt->srv_changed );
+
+    if (p_srv_chg_clt->srv_changed)
+    {
+        gatt_send_srv_chg_ind(p_srv_chg_clt->bda);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_init_srv_chg
+**
+** Description      This function is used to initialize the service changed
+**                  attribute value
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_init_srv_chg (void)
+{
+    tGATTS_SRV_CHG_REQ req;
+    tGATTS_SRV_CHG_RSP rsp;
+    bool    status;
+    uint8_t num_clients,i;
+    tGATTS_SRV_CHG  srv_chg_clt;
+
+    GATT_TRACE_DEBUG("gatt_init_srv_chg");
+    if (gatt_cb.cb_info.p_srv_chg_callback)
+    {
+        status = (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_READ_NUM_CLENTS, NULL, &rsp);
+
+        if (status && rsp.num_clients)
+        {
+            GATT_TRACE_DEBUG("gatt_init_srv_chg num_srv_chg_clt_clients=%d", rsp.num_clients);
+            num_clients = rsp.num_clients;
+            i = 1; /* use one based index */
+            while ((i <= num_clients) && status)
+            {
+                req.client_read_index = i;
+                if ((status = (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_READ_CLENT, &req, &rsp)) == true)
+                {
+                    memcpy(&srv_chg_clt, &rsp.srv_chg ,sizeof(tGATTS_SRV_CHG));
+                    if (gatt_add_srv_chg_clt(&srv_chg_clt) == NULL)
+                    {
+                        GATT_TRACE_ERROR("Unable to add a service change client");
+                        status = false;
+                    }
+                }
+                i++;
+            }
+        }
+    }
+    else
+    {
+        GATT_TRACE_DEBUG("gatt_init_srv_chg callback not registered yet");
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_proc_srv_chg
+**
+** Description      This function is process the service changed request
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_proc_srv_chg (void)
+{
+    uint8_t             start_idx, found_idx;
+    BD_ADDR             bda;
+    bool                srv_chg_ind_pending=false;
+    tGATT_TCB           *p_tcb;
+    tBT_TRANSPORT      transport;
+
+    GATT_TRACE_DEBUG ("gatt_proc_srv_chg");
+
+    if (gatt_cb.cb_info.p_srv_chg_callback && gatt_cb.handle_of_h_r)
+    {
+        gatt_set_srv_chg();
+        start_idx =0;
+        while (gatt_find_the_connected_bda(start_idx, bda, &found_idx, &transport))
+        {
+            p_tcb = &gatt_cb.tcb[found_idx];;
+            srv_chg_ind_pending  = gatt_is_srv_chg_ind_pending(p_tcb);
+
+            if (!srv_chg_ind_pending)
+            {
+                gatt_send_srv_chg_ind(bda);
+            }
+            else
+            {
+                GATT_TRACE_DEBUG ("discard srv chg - already has one in the queue");
+            }
+            start_idx = ++found_idx;
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_set_ch_state
+**
+** Description      This function set the ch_state in tcb
+**
+** Returns          none
+**
+*******************************************************************************/
+void gatt_set_ch_state(tGATT_TCB *p_tcb, tGATT_CH_STATE ch_state)
+{
+    if (p_tcb)
+    {
+        GATT_TRACE_DEBUG ("gatt_set_ch_state: old=%d new=%d", p_tcb->ch_state, ch_state);
+        p_tcb->ch_state = ch_state;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_get_ch_state
+**
+** Description      This function get the ch_state in tcb
+**
+** Returns          none
+**
+*******************************************************************************/
+tGATT_CH_STATE gatt_get_ch_state(tGATT_TCB *p_tcb)
+{
+    tGATT_CH_STATE ch_state = GATT_CH_CLOSE;
+    if (p_tcb)
+    {
+        GATT_TRACE_DEBUG ("gatt_get_ch_state: ch_state=%d", p_tcb->ch_state);
+        ch_state = p_tcb->ch_state;
+    }
+    return ch_state;
+}
+
+#endif /* BLE_INCLUDED */
diff --git a/bt/stack/gatt/gatt_sr.cc b/bt/stack/gatt/gatt_sr.cc
new file mode 100644
index 0000000..a4aa238
--- /dev/null
+++ b/bt/stack/gatt/gatt_sr.cc
@@ -0,0 +1,1484 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 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 GATT server functions
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "osi/include/osi.h"
+
+#if (BLE_INCLUDED == TRUE)
+#include <string.h>
+#include "gatt_int.h"
+#include "l2c_api.h"
+#include "l2c_int.h"
+#define GATT_MTU_REQ_MIN_LEN        2
+
+
+/*******************************************************************************
+**
+** Function         gatt_sr_enqueue_cmd
+**
+** Description      This function enqueue the request from client which needs a
+**                  application response, and update the transaction ID.
+**
+** Returns          void
+**
+*******************************************************************************/
+uint32_t gatt_sr_enqueue_cmd (tGATT_TCB *p_tcb, uint8_t op_code, uint16_t handle)
+{
+    tGATT_SR_CMD   *p_cmd = &p_tcb->sr_cmd;
+    uint32_t        trans_id = 0;
+
+    if ( (p_cmd->op_code == 0) ||
+         (op_code == GATT_HANDLE_VALUE_CONF)) /* no pending request */
+    {
+        if (op_code == GATT_CMD_WRITE ||
+            op_code == GATT_SIGN_CMD_WRITE  ||
+            op_code == GATT_REQ_MTU ||
+            op_code == GATT_HANDLE_VALUE_CONF)
+        {
+            trans_id = ++p_tcb->trans_id;
+        }
+        else
+        {
+            p_cmd->trans_id   = ++p_tcb->trans_id;
+            p_cmd->op_code    = op_code;
+            p_cmd->handle     = handle;
+            p_cmd->status     = GATT_NOT_FOUND;
+            p_tcb->trans_id %= GATT_TRANS_ID_MAX;
+            trans_id = p_cmd->trans_id;
+        }
+    }
+
+    return trans_id;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_sr_cmd_empty
+**
+** Description      This function check the server command queue is empty or not.
+**
+** Returns          true if empty, false if there is pending command.
+**
+*******************************************************************************/
+bool    gatt_sr_cmd_empty (tGATT_TCB *p_tcb)
+{
+    return(p_tcb->sr_cmd.op_code == 0);
+}
+
+/*******************************************************************************
+**
+** Function         gatt_dequeue_sr_cmd
+**
+** Description      This function dequeue the request from command queue.
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_dequeue_sr_cmd (tGATT_TCB *p_tcb)
+{
+    /* Double check in case any buffers are queued */
+    GATT_TRACE_DEBUG("gatt_dequeue_sr_cmd" );
+    if (p_tcb->sr_cmd.p_rsp_msg)
+        GATT_TRACE_ERROR("free p_tcb->sr_cmd.p_rsp_msg = %d", p_tcb->sr_cmd.p_rsp_msg);
+    osi_free_and_reset((void **)&p_tcb->sr_cmd.p_rsp_msg);
+
+    while (!fixed_queue_is_empty(p_tcb->sr_cmd.multi_rsp_q))
+        osi_free(fixed_queue_try_dequeue(p_tcb->sr_cmd.multi_rsp_q));
+    fixed_queue_free(p_tcb->sr_cmd.multi_rsp_q, NULL);
+    memset( &p_tcb->sr_cmd, 0, sizeof(tGATT_SR_CMD));
+}
+
+/*******************************************************************************
+**
+** Function         process_read_multi_rsp
+**
+** Description      This function check the read multiple response.
+**
+** Returns          bool    if all replies have been received
+**
+*******************************************************************************/
+static bool    process_read_multi_rsp (tGATT_SR_CMD *p_cmd, tGATT_STATUS status,
+                                       tGATTS_RSP *p_msg, uint16_t mtu)
+{
+    uint16_t        ii, total_len, len;
+    uint8_t         *p;
+    bool            is_overflow = false;
+
+    GATT_TRACE_DEBUG ("%s status=%d mtu=%d", __func__, status, mtu);
+
+    if (p_cmd->multi_rsp_q == NULL)
+        p_cmd->multi_rsp_q = fixed_queue_new(SIZE_MAX);
+
+    /* Enqueue the response */
+    BT_HDR  *p_buf = (BT_HDR *)osi_malloc(sizeof(tGATTS_RSP));
+    memcpy((void *)p_buf, (const void *)p_msg, sizeof(tGATTS_RSP));
+    fixed_queue_enqueue(p_cmd->multi_rsp_q, p_buf);
+
+    p_cmd->status = status;
+    if (status == GATT_SUCCESS)
+    {
+        GATT_TRACE_DEBUG("Multi read count=%d num_hdls=%d",
+                         fixed_queue_length(p_cmd->multi_rsp_q),
+                         p_cmd->multi_req.num_handles);
+        /* Wait till we get all the responses */
+        if (fixed_queue_length(p_cmd->multi_rsp_q) == p_cmd->multi_req.num_handles)
+        {
+            len = sizeof(BT_HDR) + L2CAP_MIN_OFFSET + mtu;
+            p_buf = (BT_HDR *)osi_calloc(len);
+            p_buf->offset = L2CAP_MIN_OFFSET;
+            p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+            /* First byte in the response is the opcode */
+            *p++ = GATT_RSP_READ_MULTI;
+            p_buf->len = 1;
+
+            /* Now walk through the buffers puting the data into the response in order */
+            list_t *list = NULL;
+            const list_node_t *node = NULL;
+            if (! fixed_queue_is_empty(p_cmd->multi_rsp_q))
+                list = fixed_queue_get_list(p_cmd->multi_rsp_q);
+            for (ii = 0; ii < p_cmd->multi_req.num_handles; ii++)
+            {
+                tGATTS_RSP *p_rsp = NULL;
+
+                if (list != NULL) {
+                    if (ii == 0)
+                        node = list_begin(list);
+                    else
+                        node = list_next(node);
+                    if (node != list_end(list))
+                        p_rsp = (tGATTS_RSP *)list_node(node);
+                }
+
+                if (p_rsp != NULL)
+                {
+
+                    total_len = (p_buf->len + p_rsp->attr_value.len);
+
+                    if (total_len >  mtu)
+                    {
+                        /* just send the partial response for the overflow case */
+                        len = p_rsp->attr_value.len - (total_len - mtu);
+                        is_overflow = true;
+                        GATT_TRACE_DEBUG ("multi read overflow available len=%d val_len=%d", len, p_rsp->attr_value.len );
+                    }
+                    else
+                    {
+                        len = p_rsp->attr_value.len;
+                    }
+
+                    if (p_rsp->attr_value.handle == p_cmd->multi_req.handles[ii])
+                    {
+                        memcpy (p, p_rsp->attr_value.value, len);
+                        if (!is_overflow)
+                            p += len;
+                        p_buf->len += len;
+                    }
+                    else
+                    {
+                        p_cmd->status        = GATT_NOT_FOUND;
+                        break;
+                    }
+
+                    if (is_overflow)
+                        break;
+
+                }
+                else
+                {
+                    p_cmd->status        = GATT_NOT_FOUND;
+                    break;
+                }
+
+            } /* loop through all handles*/
+
+
+            /* Sanity check on the buffer length */
+            if (p_buf->len == 0)
+            {
+                GATT_TRACE_ERROR("process_read_multi_rsp - nothing found!!");
+                p_cmd->status = GATT_NOT_FOUND;
+                osi_free(p_buf);
+                GATT_TRACE_DEBUG("osi_free(p_buf)");
+            }
+            else if (p_cmd->p_rsp_msg != NULL)
+            {
+                osi_free(p_buf);
+            }
+            else
+            {
+                p_cmd->p_rsp_msg = p_buf;
+            }
+
+            return(true);
+        }
+    }
+    else    /* any handle read exception occurs, return error */
+    {
+        return(true);
+    }
+
+    /* If here, still waiting */
+    return(false);
+}
+
+/*******************************************************************************
+**
+** Function         gatt_sr_process_app_rsp
+**
+** Description      This function checks whether the response message from application
+**                  match any pending request or not.
+**
+** Returns          void
+**
+*******************************************************************************/
+tGATT_STATUS gatt_sr_process_app_rsp (tGATT_TCB *p_tcb, tGATT_IF gatt_if,
+                                      UNUSED_ATTR uint32_t trans_id, uint8_t op_code,
+                                      tGATT_STATUS status, tGATTS_RSP *p_msg)
+{
+    tGATT_STATUS    ret_code = GATT_SUCCESS;
+
+    GATT_TRACE_DEBUG("gatt_sr_process_app_rsp gatt_if=%d", gatt_if);
+
+    gatt_sr_update_cback_cnt(p_tcb, gatt_if, false, false);
+
+    if (op_code == GATT_REQ_READ_MULTI)
+    {
+        /* If no error and still waiting, just return */
+        if (!process_read_multi_rsp (&p_tcb->sr_cmd, status, p_msg, p_tcb->payload_size))
+            return(GATT_SUCCESS);
+    }
+    else
+    {
+        if (op_code == GATT_REQ_PREPARE_WRITE && status == GATT_SUCCESS)
+            gatt_sr_update_prep_cnt(p_tcb, gatt_if, true, false);
+
+        if (op_code == GATT_REQ_EXEC_WRITE && status != GATT_SUCCESS)
+            gatt_sr_reset_cback_cnt(p_tcb);
+
+        p_tcb->sr_cmd.status = status;
+
+        if (gatt_sr_is_cback_cnt_zero(p_tcb)
+            && status == GATT_SUCCESS)
+        {
+            if (p_tcb->sr_cmd.p_rsp_msg == NULL)
+            {
+                p_tcb->sr_cmd.p_rsp_msg = attp_build_sr_msg (p_tcb, (uint8_t)(op_code + 1), (tGATT_SR_MSG *)p_msg);
+            }
+            else
+            {
+                GATT_TRACE_ERROR("Exception!!! already has respond message");
+            }
+        }
+    }
+    if (gatt_sr_is_cback_cnt_zero(p_tcb))
+    {
+        if ( (p_tcb->sr_cmd.status == GATT_SUCCESS) && (p_tcb->sr_cmd.p_rsp_msg) )
+        {
+            ret_code = attp_send_sr_msg (p_tcb, p_tcb->sr_cmd.p_rsp_msg);
+            p_tcb->sr_cmd.p_rsp_msg = NULL;
+        }
+        else
+        {
+            ret_code = gatt_send_error_rsp (p_tcb, status, op_code, p_tcb->sr_cmd.handle, false);
+        }
+
+        gatt_dequeue_sr_cmd(p_tcb);
+    }
+
+    GATT_TRACE_DEBUG("gatt_sr_process_app_rsp ret_code=%d", ret_code);
+
+    return ret_code;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_process_exec_write_req
+**
+** Description      This function is called to process the execute write request
+**                  from client.
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_process_exec_write_req (tGATT_TCB *p_tcb, uint8_t op_code,
+                                  UNUSED_ATTR uint16_t len, uint8_t *p_data)
+{
+    uint8_t *p = p_data, flag, i = 0;
+    uint32_t trans_id = 0;
+    tGATT_IF gatt_if;
+    uint16_t conn_id;
+
+#if (GATT_CONFORMANCE_TESTING == TRUE)
+    if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code)
+    {
+        GATT_TRACE_DEBUG("Conformance tst: forced err rspv for Execute Write: error status=%d",
+        gatt_cb.err_status);
+
+        gatt_send_error_rsp (p_tcb, gatt_cb.err_status, gatt_cb.req_op_code, gatt_cb.handle, false);
+
+        return;
+    }
+#endif
+
+    STREAM_TO_UINT8(flag, p);
+
+    /* mask the flag */
+    flag &= GATT_PREP_WRITE_EXEC;
+
+
+    /* no prep write is queued */
+    if (!gatt_sr_is_prep_cnt_zero(p_tcb))
+    {
+        trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, 0);
+        gatt_sr_copy_prep_cnt_to_cback_cnt(p_tcb);
+
+        for (i=0; i<GATT_MAX_APPS; i++)
+        {
+            if (p_tcb->prep_cnt[i])
+            {
+                gatt_if = (tGATT_IF) (i+1);
+                conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
+                gatt_sr_send_req_callback(conn_id,
+                                          trans_id,
+                                          GATTS_REQ_TYPE_WRITE_EXEC,
+                                          (tGATTS_DATA *)&flag);
+                p_tcb->prep_cnt[i]= 0;
+            }
+        }
+    }
+    else /* nothing needs to be executed , send response now */
+    {
+        GATT_TRACE_ERROR("gatt_process_exec_write_req: no prepare write pending");
+        gatt_send_error_rsp(p_tcb, GATT_ERROR, GATT_REQ_EXEC_WRITE, 0, false);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_process_read_multi_req
+**
+** Description      This function is called to process the read multiple request
+**                  from client.
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_process_read_multi_req (tGATT_TCB *p_tcb, uint8_t op_code, uint16_t len, uint8_t *p_data)
+{
+    uint32_t        trans_id;
+    uint16_t        handle = 0, ll = len;
+    uint8_t         *p = p_data, i_rcb;
+    tGATT_STATUS    err = GATT_SUCCESS;
+    uint8_t         sec_flag, key_size;
+
+    GATT_TRACE_DEBUG("gatt_process_read_multi_req" );
+    p_tcb->sr_cmd.multi_req.num_handles = 0;
+
+    gatt_sr_get_sec_info(p_tcb->peer_bda,
+                         p_tcb->transport,
+                         &sec_flag,
+                         &key_size);
+
+#if (GATT_CONFORMANCE_TESTING == TRUE)
+    if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code)
+    {
+        GATT_TRACE_DEBUG("Conformance tst: forced err rspvofr ReadMultiple: error status=%d", gatt_cb.err_status);
+
+        STREAM_TO_UINT16(handle, p);
+
+        gatt_send_error_rsp (p_tcb, gatt_cb.err_status, gatt_cb.req_op_code, handle, false);
+
+        return;
+    }
+#endif
+
+    while (ll >= 2 && p_tcb->sr_cmd.multi_req.num_handles < GATT_MAX_READ_MULTI_HANDLES)
+    {
+        STREAM_TO_UINT16(handle, p);
+
+        if ((i_rcb = gatt_sr_find_i_rcb_by_handle(handle)) < GATT_MAX_SR_PROFILES)
+        {
+            p_tcb->sr_cmd.multi_req.handles[p_tcb->sr_cmd.multi_req.num_handles++] = handle;
+
+            /* check read permission */
+            if ((err = gatts_read_attr_perm_check(   gatt_cb.sr_reg[i_rcb].p_db,
+                                                     false,
+                                                     handle,
+                                                     sec_flag,
+                                                     key_size))
+                != GATT_SUCCESS)
+            {
+                GATT_TRACE_DEBUG("read permission denied : 0x%02x", err);
+                break;
+            }
+        }
+        else
+        {
+            /* invalid handle */
+            err = GATT_INVALID_HANDLE;
+            break;
+        }
+        ll -= 2;
+    }
+
+    if (ll != 0)
+    {
+        GATT_TRACE_ERROR("max attribute handle reached in ReadMultiple Request.");
+    }
+
+    if (p_tcb->sr_cmd.multi_req.num_handles == 0)
+        err = GATT_INVALID_HANDLE;
+
+    if (err == GATT_SUCCESS)
+    {
+        if ((trans_id = gatt_sr_enqueue_cmd (p_tcb, op_code, p_tcb->sr_cmd.multi_req.handles[0])) != 0)
+        {
+            gatt_sr_reset_cback_cnt(p_tcb); /* read multiple use multi_rsp_q's count*/
+
+            for (ll = 0; ll < p_tcb->sr_cmd.multi_req.num_handles; ll ++) {
+                tGATTS_RSP *p_msg = (tGATTS_RSP *)osi_calloc(sizeof(tGATTS_RSP));
+                handle = p_tcb->sr_cmd.multi_req.handles[ll];
+                i_rcb = gatt_sr_find_i_rcb_by_handle(handle);
+
+                p_msg->attr_value.handle = handle;
+                err = gatts_read_attr_value_by_handle(p_tcb,
+                                                      gatt_cb.sr_reg[i_rcb].p_db,
+                                                      op_code,
+                                                      handle,
+                                                      0,
+                                                      p_msg->attr_value.value,
+                                                      &p_msg->attr_value.len,
+                                                      GATT_MAX_ATTR_LEN,
+                                                      sec_flag,
+                                                      key_size,
+                                                      trans_id);
+
+                if (err == GATT_SUCCESS) {
+                    gatt_sr_process_app_rsp(p_tcb, gatt_cb.sr_reg[i_rcb].gatt_if ,trans_id, op_code, GATT_SUCCESS, p_msg);
+                }
+                /* either not using or done using the buffer, release it now */
+                osi_free(p_msg);
+            }
+        }
+        else
+            err = GATT_NO_RESOURCES;
+    }
+
+    /* in theroy BUSY is not possible(should already been checked), protected check */
+    if (err != GATT_SUCCESS && err != GATT_PENDING && err != GATT_BUSY)
+        gatt_send_error_rsp(p_tcb, err, op_code, handle, false);
+}
+
+/*******************************************************************************
+**
+** Function         gatt_build_primary_service_rsp
+**
+** Description      Primamry service request processed internally. Theretically
+**                  only deal with ReadByTypeVAlue and ReadByGroupType.
+**
+** Returns          void
+**
+*******************************************************************************/
+static tGATT_STATUS gatt_build_primary_service_rsp (BT_HDR *p_msg, tGATT_TCB *p_tcb,
+                                                    uint8_t op_code, uint16_t s_hdl,
+                                                    uint16_t e_hdl,
+                                                    UNUSED_ATTR uint8_t *p_data, tBT_UUID value)
+{
+    tGATT_STATUS    status = GATT_NOT_FOUND;
+    uint8_t         handle_len =4, *p ;
+    tGATT_SR_REG    *p_rcb;
+    tGATT_SRV_LIST_INFO *p_list= &gatt_cb.srv_list_info;
+    tGATT_SRV_LIST_ELEM  *p_srv=NULL;
+    tBT_UUID       *p_uuid;
+
+    p = (uint8_t *)(p_msg + 1) + L2CAP_MIN_OFFSET;
+
+    p_srv = p_list->p_first;
+
+    while (p_srv)
+    {
+        p_rcb = GATT_GET_SR_REG_PTR(p_srv->i_sreg);
+
+        if (p_rcb->in_use &&
+            p_rcb->s_hdl >= s_hdl &&
+            p_rcb->s_hdl <= e_hdl &&
+            p_rcb->type == GATT_UUID_PRI_SERVICE)
+        {
+            if ((p_uuid = gatts_get_service_uuid (p_rcb->p_db)) != NULL)
+            {
+                if (op_code == GATT_REQ_READ_BY_GRP_TYPE)
+                    handle_len = 4 + p_uuid->len;
+
+                /* get the length byte in the repsonse */
+                if (p_msg->offset ==0)
+                {
+                    *p ++ = op_code + 1;
+                    p_msg->len ++;
+                    p_msg->offset = handle_len;
+
+                    if (op_code == GATT_REQ_READ_BY_GRP_TYPE)
+                    {
+                        *p ++ =  (uint8_t)p_msg->offset; /* length byte */
+                        p_msg->len ++;
+                    }
+                }
+
+                if (p_msg->len + p_msg->offset <= p_tcb->payload_size &&
+                    handle_len == p_msg->offset)
+                {
+                    if (op_code != GATT_REQ_FIND_TYPE_VALUE ||
+                        gatt_uuid_compare(value, *p_uuid))
+                    {
+                        UINT16_TO_STREAM(p, p_rcb->s_hdl);
+
+                        if (p_list->p_last_primary == p_srv &&
+                            p_list->p_last_primary == p_list->p_last)
+                        {
+                            GATT_TRACE_DEBUG("Use 0xFFFF for the last primary attribute");
+                            UINT16_TO_STREAM(p, 0xFFFF); /* see GATT ERRATA 4065, 4063, ATT ERRATA 4062 */
+                        }
+                        else
+                        {
+                            UINT16_TO_STREAM(p, p_rcb->e_hdl);
+                        }
+
+                        if (op_code == GATT_REQ_READ_BY_GRP_TYPE)
+                            gatt_build_uuid_to_stream(&p, *p_uuid);
+
+                        status = GATT_SUCCESS;
+                        p_msg->len += p_msg->offset;
+                    }
+                }
+                else
+                    break;
+            }
+        }
+        p_srv = p_srv->p_next;
+    }
+    p_msg->offset = L2CAP_MIN_OFFSET;
+
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_build_find_info_rsp
+**
+** Description      fill the find information response information in the given
+**                  buffer.
+**
+** Returns          true: if data filled sucessfully.
+**                  false: packet full, or format mismatch.
+**
+*******************************************************************************/
+static tGATT_STATUS gatt_build_find_info_rsp(tGATT_SR_REG *p_rcb, BT_HDR *p_msg, uint16_t *p_len,
+                                             uint16_t s_hdl, uint16_t e_hdl)
+{
+    tGATT_STATUS        status = GATT_NOT_FOUND;
+    uint8_t             *p;
+    uint16_t            len = *p_len;
+    tGATT_ATTR        *p_attr = NULL;
+    uint8_t             info_pair_len[2] = {4, 18};
+
+    if (!p_rcb->p_db || !p_rcb->p_db->p_attr_list)
+        return status;
+
+    /* check the attribute database */
+    p_attr = (tGATT_ATTR *) p_rcb->p_db->p_attr_list;
+
+    p = (uint8_t *)(p_msg + 1) + L2CAP_MIN_OFFSET + p_msg->len;
+
+    while (p_attr)
+    {
+        if (p_attr->handle > e_hdl)
+        {
+            break;
+        }
+
+        if (p_attr->handle >= s_hdl)
+        {
+            if (p_msg->offset == 0)
+                p_msg->offset = (p_attr->uuid.len == LEN_UUID_16) ? GATT_INFO_TYPE_PAIR_16 : GATT_INFO_TYPE_PAIR_128;
+
+            if (len >= info_pair_len[p_msg->offset - 1])
+            {
+                if (p_msg->offset == GATT_INFO_TYPE_PAIR_16 && p_attr->uuid.len == LEN_UUID_16)
+                {
+                    UINT16_TO_STREAM(p, p_attr->handle);
+                    UINT16_TO_STREAM(p, p_attr->uuid.uu.uuid16);
+                }
+                else if (p_msg->offset == GATT_INFO_TYPE_PAIR_128 && p_attr->uuid.len == LEN_UUID_128  )
+                {
+                    UINT16_TO_STREAM(p, p_attr->handle);
+                    ARRAY_TO_STREAM (p, p_attr->uuid.uu.uuid128, LEN_UUID_128);
+                }
+                else if (p_msg->offset == GATT_INFO_TYPE_PAIR_128 && p_attr->uuid.len == LEN_UUID_32)
+                {
+                    UINT16_TO_STREAM(p, p_attr->handle);
+                    gatt_convert_uuid32_to_uuid128(p, p_attr->uuid.uu.uuid32);
+                    p += LEN_UUID_128;
+                }
+                else
+                {
+                    GATT_TRACE_ERROR("format mismatch");
+                    status = GATT_NO_RESOURCES;
+                    break;
+                    /* format mismatch */
+                }
+                p_msg->len += info_pair_len[p_msg->offset - 1];
+                len -= info_pair_len[p_msg->offset - 1];
+                status = GATT_SUCCESS;
+
+            }
+            else
+            {
+                status = GATT_NO_RESOURCES;
+                break;
+            }
+        }
+        p_attr = (tGATT_ATTR *)p_attr->p_next;
+    }
+
+    *p_len = len;
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         gatts_internal_read_by_type_req
+**
+** Description      check to see if the ReadByType request can be handled internally.
+**
+** Returns          void
+**
+*******************************************************************************/
+static tGATT_STATUS gatts_validate_packet_format(uint8_t op_code, uint16_t *p_len,
+                                                 uint8_t **p_data, tBT_UUID *p_uuid_filter,
+                                                 uint16_t *p_s_hdl, uint16_t *p_e_hdl)
+{
+    tGATT_STATUS    reason = GATT_SUCCESS;
+    uint16_t        uuid_len, s_hdl = 0, e_hdl = 0;
+    uint16_t        len = *p_len;
+    uint8_t         *p = *p_data;
+
+    if (len >= 4)
+    {
+        /* obtain starting handle, and ending handle */
+        STREAM_TO_UINT16(s_hdl, p);
+        STREAM_TO_UINT16(e_hdl, p);
+        len -= 4;
+
+        if (s_hdl > e_hdl || !GATT_HANDLE_IS_VALID(s_hdl) || !GATT_HANDLE_IS_VALID(e_hdl))
+        {
+            reason = GATT_INVALID_HANDLE;
+        }
+        /* for these PDUs, uuid filter must present */
+        else if (op_code == GATT_REQ_READ_BY_GRP_TYPE ||
+                 op_code == GATT_REQ_FIND_TYPE_VALUE ||
+                 op_code == GATT_REQ_READ_BY_TYPE)
+        {
+            if (len >= 2 && p_uuid_filter != NULL)
+            {
+                uuid_len = (op_code == GATT_REQ_FIND_TYPE_VALUE) ? 2 : len;
+
+                /* parse uuid now */
+                if (gatt_parse_uuid_from_cmd (p_uuid_filter, uuid_len, &p) == false ||
+                    p_uuid_filter->len == 0)
+                {
+                    GATT_TRACE_DEBUG("UUID filter does not exsit");
+                    reason = GATT_INVALID_PDU;
+                }
+                else
+                    len -= p_uuid_filter->len;
+            }
+            else
+                reason = GATT_INVALID_PDU;
+        }
+    }
+    else
+        reason = GATT_INVALID_PDU;
+
+    *p_data     = p;
+    *p_len      = len;
+    *p_s_hdl    = s_hdl;
+    *p_e_hdl    = e_hdl;
+
+    return reason;
+}
+
+/*******************************************************************************
+**
+** Function         gatts_process_primary_service_req
+**
+** Description      process ReadByGroupType/ReadByTypeValue request, for discover
+**                  all primary services or discover primary service by UUID request.
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatts_process_primary_service_req(tGATT_TCB *p_tcb, uint8_t op_code, uint16_t len, uint8_t *p_data)
+{
+    uint8_t         reason = GATT_INVALID_PDU;
+    uint16_t        s_hdl = 0, e_hdl = 0;
+    tBT_UUID        uuid, value, primary_service = {LEN_UUID_16, {GATT_UUID_PRI_SERVICE}};
+    BT_HDR          *p_msg = NULL;
+    uint16_t        msg_len = (uint16_t)(sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET);
+
+    memset (&value, 0, sizeof(tBT_UUID));
+    reason = gatts_validate_packet_format(op_code, &len, &p_data, &uuid, &s_hdl, &e_hdl);
+
+    if (reason == GATT_SUCCESS)
+    {
+        if (gatt_uuid_compare(uuid, primary_service))
+        {
+            if (op_code == GATT_REQ_FIND_TYPE_VALUE)
+            {
+                if (gatt_parse_uuid_from_cmd(&value, len, &p_data) == false)
+                    reason = GATT_INVALID_PDU;
+            }
+
+            if (reason == GATT_SUCCESS) {
+                p_msg = (BT_HDR *)osi_calloc(msg_len);
+                reason = gatt_build_primary_service_rsp (p_msg, p_tcb, op_code,
+                                                         s_hdl, e_hdl, p_data,
+                                                         value);
+            }
+        }
+        else
+        {
+            if (op_code == GATT_REQ_READ_BY_GRP_TYPE)
+            {
+                reason = GATT_UNSUPPORT_GRP_TYPE;
+                GATT_TRACE_DEBUG("unexpected ReadByGrpType Group: 0x%04x", uuid.uu.uuid16);
+            }
+            else
+            {
+                /* we do not support ReadByTypeValue with any non-primamry_service type */
+                reason = GATT_NOT_FOUND;
+                GATT_TRACE_DEBUG("unexpected ReadByTypeValue type: 0x%04x", uuid.uu.uuid16);
+            }
+        }
+    }
+
+    if (reason != GATT_SUCCESS)
+    {
+        osi_free(p_msg);
+        gatt_send_error_rsp (p_tcb, reason, op_code, s_hdl, false);
+    }
+    else
+        attp_send_sr_msg(p_tcb, p_msg);
+
+}
+
+/*******************************************************************************
+**
+** Function         gatts_process_find_info
+**
+** Description      process find information request, for discover character
+**                  descriptors.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gatts_process_find_info(tGATT_TCB *p_tcb, uint8_t op_code, uint16_t len, uint8_t *p_data)
+{
+    uint8_t         reason = GATT_INVALID_PDU, *p;
+    uint16_t        s_hdl = 0, e_hdl = 0, buf_len;
+    BT_HDR          *p_msg = NULL;
+    tGATT_SR_REG    *p_rcb;
+    tGATT_SRV_LIST_INFO *p_list= &gatt_cb.srv_list_info;
+    tGATT_SRV_LIST_ELEM  *p_srv=NULL;
+
+    reason = gatts_validate_packet_format(op_code, &len, &p_data, NULL, &s_hdl, &e_hdl);
+
+    if (reason == GATT_SUCCESS)
+    {
+        buf_len = (uint16_t)(sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET);
+
+        p_msg = (BT_HDR *)osi_calloc(buf_len);
+        reason = GATT_NOT_FOUND;
+
+        p = (uint8_t *)(p_msg + 1) + L2CAP_MIN_OFFSET;
+        *p ++ = op_code + 1;
+        p_msg->len = 2;
+
+        buf_len = p_tcb->payload_size - 2;
+
+        p_srv = p_list->p_first;
+
+        while (p_srv) {
+            p_rcb = GATT_GET_SR_REG_PTR(p_srv->i_sreg);
+
+            if (p_rcb->in_use && !(p_rcb->s_hdl > e_hdl ||
+                                   p_rcb->e_hdl < s_hdl)) {
+                reason = gatt_build_find_info_rsp(p_rcb, p_msg, &buf_len,
+                                                  s_hdl, e_hdl);
+                if (reason == GATT_NO_RESOURCES) {
+                    reason = GATT_SUCCESS;
+                    break;
+                }
+            }
+            p_srv = p_srv->p_next;
+        }
+        *p = (uint8_t)p_msg->offset;
+
+        p_msg->offset = L2CAP_MIN_OFFSET;
+    }
+
+    if (reason != GATT_SUCCESS)
+    {
+        osi_free(p_msg);
+        gatt_send_error_rsp (p_tcb, reason, op_code, s_hdl, false);
+    }
+    else
+        attp_send_sr_msg(p_tcb, p_msg);
+
+}
+
+/*******************************************************************************
+**
+** Function         gatts_process_mtu_req
+**
+** Description      This function is called to process excahnge MTU request.
+**                  Only used on LE.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gatts_process_mtu_req (tGATT_TCB *p_tcb, uint16_t len, uint8_t *p_data)
+{
+    uint16_t      mtu = 0;
+    uint8_t       *p = p_data, i;
+    BT_HDR        *p_buf;
+    uint16_t conn_id;
+
+    /* BR/EDR conenction, send error response */
+    if (p_tcb->att_lcid != L2CAP_ATT_CID)
+    {
+        gatt_send_error_rsp (p_tcb, GATT_REQ_NOT_SUPPORTED, GATT_REQ_MTU, 0, false);
+    }
+    else if (len < GATT_MTU_REQ_MIN_LEN)
+    {
+        GATT_TRACE_ERROR("invalid MTU request PDU received.");
+        gatt_send_error_rsp (p_tcb, GATT_INVALID_PDU, GATT_REQ_MTU, 0, false);
+    }
+    else
+    {
+        STREAM_TO_UINT16 (mtu, p);
+        /* mtu must be greater than default MTU which is 23/48 */
+        if (mtu < GATT_DEF_BLE_MTU_SIZE)
+            p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;
+        else if (mtu > GATT_MAX_MTU_SIZE)
+            p_tcb->payload_size = GATT_MAX_MTU_SIZE;
+        else
+            p_tcb->payload_size = mtu;
+
+        GATT_TRACE_ERROR("MTU request PDU with MTU size %d", p_tcb->payload_size);
+
+        l2cble_set_fixed_channel_tx_data_length(p_tcb->peer_bda, L2CAP_ATT_CID, p_tcb->payload_size);
+
+        if ((p_buf = attp_build_sr_msg(p_tcb, GATT_RSP_MTU, (tGATT_SR_MSG *) &p_tcb->payload_size)) != NULL)
+        {
+            attp_send_sr_msg (p_tcb, p_buf);
+
+            /* Notify all registered applicaiton with new MTU size. Us a transaction ID */
+            /* of 0, as no response is allowed from applcations                    */
+
+            for (i = 0; i < GATT_MAX_APPS; i ++)
+            {
+                if (gatt_cb.cl_rcb[i].in_use )
+                {
+                    conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_cb.cl_rcb[i].gatt_if);
+                    gatt_sr_send_req_callback(conn_id, 0, GATTS_REQ_TYPE_MTU,
+                                              (tGATTS_DATA *)&p_tcb->payload_size);
+                }
+            }
+
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatts_process_read_by_type_req
+**
+** Description      process Read By type request.
+**                  This PDU can be used to perform:
+**                  - read characteristic value
+**                  - read characteristic descriptor value
+**                  - discover characteristic
+**                  - discover characteristic by UUID
+**                  - relationship discovery
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatts_process_read_by_type_req(tGATT_TCB *p_tcb, uint8_t op_code, uint16_t len, uint8_t *p_data)
+{
+    tBT_UUID            uuid;
+    tGATT_SR_REG        *p_rcb;
+    size_t              msg_len = sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET;
+    uint16_t            buf_len, s_hdl, e_hdl, err_hdl = 0;
+    BT_HDR              *p_msg = NULL;
+    tGATT_STATUS        reason, ret;
+    uint8_t             *p;
+    uint8_t             sec_flag, key_size;
+    tGATT_SRV_LIST_INFO *p_list= &gatt_cb.srv_list_info;
+    tGATT_SRV_LIST_ELEM  *p_srv=NULL;
+
+    reason = gatts_validate_packet_format(op_code, &len, &p_data, &uuid, &s_hdl, &e_hdl);
+
+#if (GATT_CONFORMANCE_TESTING == TRUE)
+    if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code)
+    {
+        GATT_TRACE_DEBUG("Conformance tst: forced err rsp for ReadByType: error status=%d", gatt_cb.err_status);
+
+        gatt_send_error_rsp (p_tcb, gatt_cb.err_status, gatt_cb.req_op_code, s_hdl, false);
+
+        return;
+    }
+#endif
+
+    if (reason == GATT_SUCCESS)
+    {
+        p_msg = (BT_HDR *)osi_calloc(msg_len);
+        p = (uint8_t *)(p_msg + 1) + L2CAP_MIN_OFFSET;
+
+        *p ++ = op_code + 1;
+        /* reserve length byte */
+        p_msg->len = 2;
+        buf_len = p_tcb->payload_size - 2;
+
+        reason = GATT_NOT_FOUND;
+
+        p_srv = p_list->p_first;
+
+        while (p_srv) {
+            p_rcb = GATT_GET_SR_REG_PTR(p_srv->i_sreg);
+
+            if (p_rcb->in_use && !(p_rcb->s_hdl > e_hdl ||
+                                   p_rcb->e_hdl < s_hdl)) {
+                gatt_sr_get_sec_info(p_tcb->peer_bda, p_tcb->transport,
+                                     &sec_flag, &key_size);
+
+                ret = gatts_db_read_attr_value_by_type(p_tcb,
+                                                       p_rcb->p_db,
+                                                       op_code,
+                                                       p_msg,
+                                                       s_hdl,
+                                                       e_hdl,
+                                                       uuid,
+                                                       &buf_len,
+                                                       sec_flag,
+                                                       key_size,
+                                                       0,
+                                                       &err_hdl);
+                if (ret != GATT_NOT_FOUND) {
+                    reason = ret;
+
+                    if (ret == GATT_NO_RESOURCES)
+                        reason = GATT_SUCCESS;
+                }
+                if (ret != GATT_SUCCESS && ret != GATT_NOT_FOUND) {
+                    s_hdl = err_hdl;
+                    break;
+                }
+            }
+            p_srv = p_srv->p_next;
+        }
+        *p = (uint8_t)p_msg->offset;
+        p_msg->offset = L2CAP_MIN_OFFSET;
+    }
+    if (reason != GATT_SUCCESS)
+    {
+        osi_free(p_msg);
+
+        /* in theroy BUSY is not possible(should already been checked), protected check */
+        if (reason != GATT_PENDING && reason != GATT_BUSY)
+            gatt_send_error_rsp (p_tcb, reason, op_code, s_hdl, false);
+    }
+    else
+        attp_send_sr_msg(p_tcb, p_msg);
+
+}
+
+/*******************************************************************************
+**
+** Function         gatts_process_write_req
+**
+** Description      This function is called to process the write request
+**                  from client.
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatts_process_write_req (tGATT_TCB *p_tcb, uint8_t i_rcb, uint16_t handle,
+                              uint8_t op_code, uint16_t len, uint8_t *p_data,
+                              bt_gatt_db_attribute_type_t gatt_type)
+{
+    tGATTS_DATA     sr_data;
+    uint32_t        trans_id;
+    tGATT_STATUS    status;
+    uint8_t         sec_flag, key_size, *p = p_data;
+    tGATT_SR_REG    *p_sreg;
+    uint16_t        conn_id;
+
+    memset(&sr_data, 0, sizeof(tGATTS_DATA));
+
+    switch (op_code)
+    {
+        case GATT_REQ_PREPARE_WRITE:
+            if (len < 2) {
+                GATT_TRACE_ERROR("%s: Prepare write request was invalid - missing offset, sending error response", __func__);
+                gatt_send_error_rsp(p_tcb, GATT_INVALID_PDU, op_code, handle, false);
+                return;
+            }
+            sr_data.write_req.is_prep = true;
+            STREAM_TO_UINT16(sr_data.write_req.offset, p);
+            len -= 2;
+            /* fall through */
+        case GATT_SIGN_CMD_WRITE:
+            if (op_code == GATT_SIGN_CMD_WRITE)
+            {
+                GATT_TRACE_DEBUG("Write CMD with data sigining" );
+                len -= GATT_AUTH_SIGN_LEN;
+            }
+            /* fall through */
+        case GATT_CMD_WRITE:
+        case GATT_REQ_WRITE:
+            if (op_code == GATT_REQ_WRITE || op_code == GATT_REQ_PREPARE_WRITE)
+                sr_data.write_req.need_rsp = true;
+            sr_data.write_req.handle = handle;
+            sr_data.write_req.len = len;
+            if (len != 0 && p != NULL)
+            {
+                memcpy (sr_data.write_req.value, p, len);
+            }
+            break;
+    }
+
+    gatt_sr_get_sec_info(p_tcb->peer_bda,
+                         p_tcb->transport,
+                         &sec_flag,
+                         &key_size);
+
+    status = gatts_write_attr_perm_check (gatt_cb.sr_reg[i_rcb].p_db,
+                                          op_code,
+                                          handle,
+                                          sr_data.write_req.offset,
+                                          p,
+                                          len,
+                                          sec_flag,
+                                          key_size);
+
+    if (status == GATT_SUCCESS)
+    {
+        if ((trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle)) != 0)
+        {
+            p_sreg = &gatt_cb.sr_reg[i_rcb];
+            conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_sreg->gatt_if);
+
+            uint8_t opcode = 0;
+            if (gatt_type == BTGATT_DB_DESCRIPTOR) {
+                opcode = GATTS_REQ_TYPE_WRITE_DESCRIPTOR;
+            } else if (gatt_type == BTGATT_DB_CHARACTERISTIC) {
+                opcode = GATTS_REQ_TYPE_WRITE_CHARACTERISTIC;
+            } else {
+                GATT_TRACE_ERROR("%s: Attempt to write attribute that's not tied with"
+                                 " characteristic or descriptor value.", __func__);
+                status = GATT_ERROR;
+            }
+
+            if (opcode) {
+                gatt_sr_send_req_callback(conn_id, trans_id, opcode, &sr_data);
+                status = GATT_PENDING;
+            }
+        }
+        else
+        {
+            GATT_TRACE_ERROR("max pending command, send error");
+            status = GATT_BUSY; /* max pending command, application error */
+        }
+    }
+
+    /* in theroy BUSY is not possible(should already been checked), protected check */
+    if (status != GATT_PENDING && status != GATT_BUSY &&
+        (op_code == GATT_REQ_PREPARE_WRITE || op_code == GATT_REQ_WRITE))
+    {
+        gatt_send_error_rsp (p_tcb, status, op_code, handle, false);
+    }
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         gatts_process_read_req
+**
+** Description      This function is called to process the read request
+**                  from client.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gatts_process_read_req(tGATT_TCB *p_tcb, tGATT_SR_REG *p_rcb, uint8_t op_code,
+                                   uint16_t handle,
+                                   UNUSED_ATTR uint16_t len, uint8_t *p_data)
+{
+    size_t          buf_len = sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET;
+    tGATT_STATUS    reason;
+    uint8_t         sec_flag, key_size, *p;
+    uint16_t        offset = 0, value_len = 0;
+    BT_HDR          *p_msg = (BT_HDR *)osi_calloc(buf_len);
+
+    if (op_code == GATT_REQ_READ_BLOB)
+        STREAM_TO_UINT16(offset, p_data);
+
+    p = (uint8_t *)(p_msg + 1) + L2CAP_MIN_OFFSET;
+    *p ++ = op_code + 1;
+    p_msg->len = 1;
+    buf_len = p_tcb->payload_size - 1;
+
+    gatt_sr_get_sec_info(p_tcb->peer_bda, p_tcb->transport, &sec_flag,
+                         &key_size);
+
+    reason = gatts_read_attr_value_by_handle(p_tcb,
+                                             p_rcb->p_db,
+                                             op_code,
+                                             handle,
+                                             offset,
+                                             p,
+                                             &value_len,
+                                             (uint16_t)buf_len,
+                                             sec_flag,
+                                             key_size,
+                                             0);
+
+    p_msg->len += value_len;
+
+    if (reason != GATT_SUCCESS)
+    {
+        osi_free(p_msg);
+
+        /* in theroy BUSY is not possible(should already been checked), protected check */
+        if (reason != GATT_PENDING && reason != GATT_BUSY)
+            gatt_send_error_rsp (p_tcb, reason, op_code, handle, false);
+    }
+    else
+        attp_send_sr_msg(p_tcb, p_msg);
+
+}
+
+/*******************************************************************************
+**
+** Function         gatts_process_attribute_req
+**
+** Description      This function is called to process the per attribute handle request
+**                  from client.
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatts_process_attribute_req (tGATT_TCB *p_tcb, uint8_t op_code,
+                                  uint16_t len, uint8_t *p_data)
+{
+    uint16_t        handle = 0;
+    uint8_t         *p = p_data, i;
+    tGATT_SR_REG    *p_rcb = gatt_cb.sr_reg;
+    tGATT_STATUS    status = GATT_INVALID_HANDLE;
+    tGATT_ATTR    *p_attr;
+
+    if (len < 2)
+    {
+        GATT_TRACE_ERROR("Illegal PDU length, discard request");
+        status = GATT_INVALID_PDU;
+    }
+    else
+    {
+        STREAM_TO_UINT16(handle, p);
+        len -= 2;
+    }
+
+#if (GATT_CONFORMANCE_TESTING == TRUE)
+    gatt_cb.handle = handle;
+    if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code)
+    {
+        GATT_TRACE_DEBUG("Conformance tst: forced err rsp: error status=%d", gatt_cb.err_status);
+
+        gatt_send_error_rsp (p_tcb, gatt_cb.err_status, gatt_cb.req_op_code, handle, false);
+
+        return;
+    }
+#endif
+
+    if (GATT_HANDLE_IS_VALID(handle))
+    {
+        for (i = 0; i < GATT_MAX_SR_PROFILES; i ++, p_rcb ++)
+        {
+            if (p_rcb->in_use && p_rcb->s_hdl <= handle && p_rcb->e_hdl >= handle)
+            {
+                p_attr = (tGATT_ATTR *)p_rcb->p_db->p_attr_list;
+
+                while (p_attr)
+                {
+                    if (p_attr->handle == handle)
+                    {
+                        switch (op_code)
+                        {
+                            case GATT_REQ_READ: /* read char/char descriptor value */
+                            case GATT_REQ_READ_BLOB:
+                                gatts_process_read_req(p_tcb, p_rcb, op_code, handle, len, p);
+                                break;
+
+                            case GATT_REQ_WRITE: /* write char/char descriptor value */
+                            case GATT_CMD_WRITE:
+                            case GATT_SIGN_CMD_WRITE:
+                            case GATT_REQ_PREPARE_WRITE:
+                                gatts_process_write_req(p_tcb, i, handle, op_code, len, p,
+                                                        p_attr->gatt_type);
+                                break;
+                            default:
+                                break;
+                        }
+                        status = GATT_SUCCESS;
+                        break;
+                    }
+                    p_attr = (tGATT_ATTR *)p_attr->p_next;
+                }
+                break;
+            }
+        }
+    }
+
+    if (status != GATT_SUCCESS && op_code != GATT_CMD_WRITE && op_code != GATT_SIGN_CMD_WRITE)
+        gatt_send_error_rsp (p_tcb, status, op_code, handle, false);
+}
+
+/*******************************************************************************
+**
+** Function         gatts_proc_srv_chg_ind_ack
+**
+** Description      This function process the service changed indicaiton ACK
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gatts_proc_srv_chg_ind_ack(tGATT_TCB *p_tcb )
+{
+    tGATTS_SRV_CHG_REQ  req;
+    tGATTS_SRV_CHG      *p_buf = NULL;
+
+    GATT_TRACE_DEBUG("gatts_proc_srv_chg_ind_ack");
+
+    if ((p_buf = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda)) != NULL)
+    {
+        GATT_TRACE_DEBUG("NV update set srv chg = false");
+        p_buf->srv_changed = false;
+        memcpy(&req.srv_chg, p_buf, sizeof(tGATTS_SRV_CHG));
+        if (gatt_cb.cb_info.p_srv_chg_callback)
+            (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_UPDATE_CLIENT,&req, NULL);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatts_chk_pending_ind
+**
+** Description      This function check any pending indication needs to be sent if
+**                  there is a pending indication then sent the indication
+**
+** Returns          void
+**
+*******************************************************************************/
+static void gatts_chk_pending_ind(tGATT_TCB *p_tcb )
+{
+    GATT_TRACE_DEBUG("%s", __func__);
+
+    tGATT_VALUE *p_buf = (tGATT_VALUE *)fixed_queue_try_peek_first(p_tcb->pending_ind_q);
+    if (p_buf != NULL)
+    {
+        GATTS_HandleValueIndication(p_buf->conn_id,
+                                    p_buf->handle,
+                                    p_buf->len,
+                                    p_buf->value);
+        osi_free(fixed_queue_try_remove_from_queue(p_tcb->pending_ind_q,
+                                                      p_buf));
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatts_proc_ind_ack
+**
+** Description      This function process the Indication ack
+**
+** Returns          true continue to process the indication ack by the aaplication
+**                  if the ACk is not a Service Changed Indication Ack
+**
+*******************************************************************************/
+static bool    gatts_proc_ind_ack(tGATT_TCB *p_tcb, uint16_t ack_handle)
+{
+    bool    continue_processing = true;
+
+    GATT_TRACE_DEBUG ("gatts_proc_ind_ack ack handle=%d", ack_handle);
+
+    if (ack_handle == gatt_cb.handle_of_h_r)
+    {
+        gatts_proc_srv_chg_ind_ack(p_tcb);
+        /* there is no need to inform the application since srv chg is handled internally by GATT */
+        continue_processing = false;
+    }
+
+    gatts_chk_pending_ind(p_tcb);
+    return continue_processing;
+}
+
+/*******************************************************************************
+**
+** Function         gatts_process_value_conf
+**
+** Description      This function is called to process the handle value confirmation.
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatts_process_value_conf(tGATT_TCB *p_tcb, uint8_t op_code)
+{
+    uint16_t        handle = p_tcb->indicate_handle;
+    uint32_t        trans_id;
+    uint8_t         i;
+    tGATT_SR_REG    *p_rcb = gatt_cb.sr_reg;
+    bool            continue_processing;
+    uint16_t        conn_id;
+
+    alarm_cancel(p_tcb->conf_timer);
+    if (GATT_HANDLE_IS_VALID(handle))
+    {
+        p_tcb->indicate_handle = 0;
+        continue_processing = gatts_proc_ind_ack(p_tcb, handle);
+
+        if (continue_processing)
+        {
+            for (i = 0; i < GATT_MAX_SR_PROFILES; i ++, p_rcb ++)
+            {
+                if (p_rcb->in_use && p_rcb->s_hdl <= handle && p_rcb->e_hdl >= handle)
+                {
+                    trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle);
+                    conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_rcb->gatt_if);
+                    gatt_sr_send_req_callback(conn_id,
+                                              trans_id, GATTS_REQ_TYPE_CONF, (tGATTS_DATA *)&handle);
+                }
+            }
+        }
+    }
+    else
+    {
+        GATT_TRACE_ERROR("unexpected handle value confirmation");
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_server_handle_client_req
+**
+** Description      This function is called to handle the client requests to
+**                  server.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_server_handle_client_req (tGATT_TCB *p_tcb, uint8_t op_code,
+                                    uint16_t len, uint8_t *p_data)
+{
+    /* there is pending command, discard this one */
+    if (!gatt_sr_cmd_empty(p_tcb) && op_code != GATT_HANDLE_VALUE_CONF)
+        return;
+
+    /* the size of the message may not be bigger than the local max PDU size*/
+    /* The message has to be smaller than the agreed MTU, len does not include op code */
+    if (len >= p_tcb->payload_size)
+    {
+        GATT_TRACE_ERROR("server receive invalid PDU size:%d pdu size:%d", len + 1, p_tcb->payload_size );
+        /* for invalid request expecting response, send it now */
+        if (op_code != GATT_CMD_WRITE &&
+            op_code != GATT_SIGN_CMD_WRITE &&
+            op_code != GATT_HANDLE_VALUE_CONF)
+        {
+            gatt_send_error_rsp (p_tcb, GATT_INVALID_PDU, op_code, 0, false);
+        }
+        /* otherwise, ignore the pkt */
+    }
+    else
+    {
+        switch (op_code)
+        {
+            case GATT_REQ_READ_BY_GRP_TYPE: /* discover primary services */
+            case GATT_REQ_FIND_TYPE_VALUE: /* discover service by UUID */
+                gatts_process_primary_service_req (p_tcb, op_code, len, p_data);
+                break;
+
+            case GATT_REQ_FIND_INFO:/* discover char descrptor */
+                gatts_process_find_info(p_tcb, op_code, len, p_data);
+                break;
+
+            case GATT_REQ_READ_BY_TYPE: /* read characteristic value, char descriptor value */
+                /* discover characteristic, discover char by UUID */
+                gatts_process_read_by_type_req(p_tcb, op_code, len, p_data);
+                break;
+
+
+            case GATT_REQ_READ: /* read char/char descriptor value */
+            case GATT_REQ_READ_BLOB:
+            case GATT_REQ_WRITE: /* write char/char descriptor value */
+            case GATT_CMD_WRITE:
+            case GATT_SIGN_CMD_WRITE:
+            case GATT_REQ_PREPARE_WRITE:
+                gatts_process_attribute_req (p_tcb, op_code, len, p_data);
+                break;
+
+            case GATT_HANDLE_VALUE_CONF:
+                gatts_process_value_conf (p_tcb, op_code);
+                break;
+
+            case GATT_REQ_MTU:
+                gatts_process_mtu_req (p_tcb, len, p_data);
+                break;
+
+            case GATT_REQ_EXEC_WRITE:
+                gatt_process_exec_write_req (p_tcb, op_code, len, p_data);
+                break;
+
+            case GATT_REQ_READ_MULTI:
+                gatt_process_read_multi_req (p_tcb, op_code, len, p_data);
+                break;
+
+            default:
+                break;
+        }
+    }
+}
+
+#endif /* BLE_INCLUDED */
diff --git a/bt/stack/gatt/gatt_utils.cc b/bt/stack/gatt/gatt_utils.cc
new file mode 100644
index 0000000..cfa86b7
--- /dev/null
+++ b/bt/stack/gatt/gatt_utils.cc
@@ -0,0 +1,2718 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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 GATT utility functions
+ *
+ ******************************************************************************/
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "osi/include/osi.h"
+
+#if (BLE_INCLUDED == TRUE)
+    #include <string.h>
+    #include "stdio.h"
+    #include "bt_common.h"
+
+    #include "l2cdefs.h"
+    #include "gatt_int.h"
+    #include "gatt_api.h"
+    #include "gattdefs.h"
+    #include "sdp_api.h"
+    #include "btm_int.h"
+/* check if [x, y] and [a, b] have overlapping range */
+    #define GATT_VALIDATE_HANDLE_RANGE(x, y, a, b)   ((y) >= (a) && (x) <= (b))
+
+    #define GATT_GET_NEXT_VALID_HANDLE(x)    (((x)/10 + 1) * 10)
+
+const char * const op_code_name[] =
+{
+    "UNKNOWN",
+    "ATT_RSP_ERROR",
+    "ATT_REQ_MTU",
+    "ATT_RSP_MTU",
+    "ATT_REQ_READ_INFO",
+    "ATT_RSP_READ_INFO",
+    "ATT_REQ_FIND_TYPE_VALUE",
+    "ATT_RSP_FIND_TYPE_VALUE",
+    "ATT_REQ_READ_BY_TYPE",
+    "ATT_RSP_READ_BY_TYPE",
+    "ATT_REQ_READ",
+    "ATT_RSP_READ",
+    "ATT_REQ_READ_BLOB",
+    "ATT_RSP_READ_BLOB",
+    "GATT_REQ_READ_MULTI",
+    "GATT_RSP_READ_MULTI",
+    "GATT_REQ_READ_BY_GRP_TYPE",
+    "GATT_RSP_READ_BY_GRP_TYPE",
+    "ATT_REQ_WRITE",
+    "ATT_RSP_WRITE",
+    "ATT_CMD_WRITE",
+    "ATT_SIGN_CMD_WRITE",
+    "ATT_REQ_PREPARE_WRITE",
+    "ATT_RSP_PREPARE_WRITE",
+    "ATT_REQ_EXEC_WRITE",
+    "ATT_RSP_EXEC_WRITE",
+    "Reserved",
+    "ATT_HANDLE_VALUE_NOTIF",
+    "Reserved",
+    "ATT_HANDLE_VALUE_IND",
+    "ATT_HANDLE_VALUE_CONF",
+    "ATT_OP_CODE_MAX"
+};
+
+static const uint8_t base_uuid[LEN_UUID_128] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
+    0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+/*******************************************************************************
+**
+** Function         gatt_free_pending_ind
+**
+** Description    Free all pending indications
+**
+** Returns       None
+**
+*******************************************************************************/
+void gatt_free_pending_ind(tGATT_TCB *p_tcb)
+{
+    GATT_TRACE_DEBUG("%s", __func__);
+
+    if (p_tcb->pending_ind_q == NULL)
+        return;
+
+    /* release all queued indications */
+    while (!fixed_queue_is_empty(p_tcb->pending_ind_q))
+        osi_free(fixed_queue_try_dequeue(p_tcb->pending_ind_q));
+    fixed_queue_free(p_tcb->pending_ind_q, NULL);
+    p_tcb->pending_ind_q = NULL;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_free_pending_enc_queue
+**
+** Description       Free all buffers in pending encyption queue
+**
+** Returns       None
+**
+*******************************************************************************/
+void gatt_free_pending_enc_queue(tGATT_TCB *p_tcb)
+{
+    GATT_TRACE_DEBUG("%s", __func__);
+
+    if (p_tcb->pending_enc_clcb == NULL)
+        return;
+
+    /* release all queued indications */
+    while (!fixed_queue_is_empty(p_tcb->pending_enc_clcb))
+        osi_free(fixed_queue_try_dequeue(p_tcb->pending_enc_clcb));
+    fixed_queue_free(p_tcb->pending_enc_clcb, NULL);
+    p_tcb->pending_enc_clcb = NULL;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_delete_dev_from_srv_chg_clt_list
+**
+** Description    Delete a device from the service changed client lit
+**
+** Returns       None
+**
+*******************************************************************************/
+void gatt_delete_dev_from_srv_chg_clt_list(BD_ADDR bd_addr)
+{
+    GATT_TRACE_DEBUG("gatt_delete_dev_from_srv_chg_clt_list");
+
+    tGATTS_SRV_CHG *p_buf = gatt_is_bda_in_the_srv_chg_clt_list(bd_addr);
+    if (p_buf != NULL)
+    {
+        if (gatt_cb.cb_info.p_srv_chg_callback)
+        {
+            /* delete from NV */
+            tGATTS_SRV_CHG_REQ req;
+            memcpy(req.srv_chg.bda, bd_addr, BD_ADDR_LEN);
+            (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_REMOVE_CLIENT,&req, NULL);
+        }
+        osi_free(fixed_queue_try_remove_from_queue(gatt_cb.srv_chg_clt_q,
+                                                      p_buf));
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_set_srv_chg
+**
+** Description      Set the service changed flag to true
+**
+** Returns        None
+**
+*******************************************************************************/
+void gatt_set_srv_chg(void)
+{
+    GATT_TRACE_DEBUG ("gatt_set_srv_chg");
+
+    if (fixed_queue_is_empty(gatt_cb.srv_chg_clt_q))
+        return;
+
+    list_t *list = fixed_queue_get_list(gatt_cb.srv_chg_clt_q);
+    for (const list_node_t *node = list_begin(list); node != list_end(list);
+         node = list_next(node)) {
+        GATT_TRACE_DEBUG ("found a srv_chg clt");
+
+        tGATTS_SRV_CHG *p_buf = (tGATTS_SRV_CHG *)list_node(node);
+        if (!p_buf->srv_changed)
+        {
+            GATT_TRACE_DEBUG("set srv_changed to true");
+            p_buf->srv_changed = true;
+            tGATTS_SRV_CHG_REQ req;
+            memcpy(&req.srv_chg, p_buf, sizeof(tGATTS_SRV_CHG));
+            if (gatt_cb.cb_info.p_srv_chg_callback)
+                (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_UPDATE_CLIENT,&req, NULL);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function     gatt_add_pending_ind
+**
+** Description  Add a pending indication
+**
+** Returns    Pointer to the current pending indication buffer, NULL no buffer available
+**
+*******************************************************************************/
+tGATT_VALUE *gatt_add_pending_ind(tGATT_TCB  *p_tcb, tGATT_VALUE *p_ind)
+{
+    tGATT_VALUE *p_buf = (tGATT_VALUE *)osi_malloc(sizeof(tGATT_VALUE));
+
+    GATT_TRACE_DEBUG("%s", __func__);
+    GATT_TRACE_DEBUG("enqueue a pending indication");
+
+    memcpy(p_buf, p_ind, sizeof(tGATT_VALUE));
+    fixed_queue_enqueue(p_tcb->pending_ind_q, p_buf);
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function     gatt_add_srv_chg_clt
+**
+** Description  Add a service chnage client to the service change client queue
+**
+** Returns    Pointer to the service change client buffer; Null no buffer available
+**
+*******************************************************************************/
+tGATTS_SRV_CHG *gatt_add_srv_chg_clt(tGATTS_SRV_CHG *p_srv_chg)
+{
+    tGATTS_SRV_CHG *p_buf = (tGATTS_SRV_CHG *)osi_malloc(sizeof(tGATTS_SRV_CHG));
+
+    GATT_TRACE_DEBUG("%s", __func__);
+    GATT_TRACE_DEBUG("enqueue a srv chg client");
+
+    memcpy(p_buf, p_srv_chg, sizeof(tGATTS_SRV_CHG));
+    fixed_queue_enqueue(gatt_cb.srv_chg_clt_q, p_buf);
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function     gatt_alloc_hdl_buffer
+**
+** Description  Allocate a handle buufer
+**
+** Returns    Pointer to the allocated buffer, NULL no buffer available
+**
+*******************************************************************************/
+tGATT_HDL_LIST_ELEM *gatt_alloc_hdl_buffer(void)
+{
+    uint8_t i;
+    tGATT_CB    *p_cb = &gatt_cb;
+    tGATT_HDL_LIST_ELEM * p_elem= &p_cb->hdl_list[0];
+
+    for (i = 0; i < GATT_MAX_SR_PROFILES; i++, p_elem++)
+    {
+        if (!p_cb->hdl_list[i].in_use)
+        {
+            memset(p_elem, 0, sizeof(tGATT_HDL_LIST_ELEM));
+            p_elem->in_use = true;
+            p_elem->svc_db.svc_buffer = fixed_queue_new(SIZE_MAX);
+            return p_elem;
+        }
+    }
+
+    return NULL;
+}
+
+/*******************************************************************************
+**
+** Function     gatt_find_hdl_buffer_by_handle
+**
+** Description  Find handle range buffer by service handle.
+**
+** Returns    Pointer to the buffer, NULL no buffer available
+**
+*******************************************************************************/
+tGATT_HDL_LIST_ELEM *gatt_find_hdl_buffer_by_handle(uint16_t handle)
+{
+    tGATT_HDL_LIST_INFO *p_list_info= &gatt_cb.hdl_list_info;
+    tGATT_HDL_LIST_ELEM      *p_list = NULL;
+
+    p_list = p_list_info->p_first;
+
+    while (p_list != NULL)
+    {
+        if (p_list->in_use && p_list->asgn_range.s_handle == handle)
+        {
+            return(p_list);
+        }
+        p_list = p_list->p_next;
+    }
+    return NULL;
+}
+/*******************************************************************************
+**
+** Function     gatt_find_hdl_buffer_by_app_id
+**
+** Description  Find handle range buffer by app ID, service and service instance ID.
+**
+** Returns    Pointer to the buffer, NULL no buffer available
+**
+*******************************************************************************/
+tGATT_HDL_LIST_ELEM *gatt_find_hdl_buffer_by_app_id (tBT_UUID *p_app_uuid128,
+                                                     tBT_UUID *p_svc_uuid,
+                                                     uint16_t start_handle)
+{
+    tGATT_HDL_LIST_INFO *p_list_info= &gatt_cb.hdl_list_info;
+    tGATT_HDL_LIST_ELEM      *p_list = NULL;
+
+    p_list = p_list_info->p_first;
+
+    while (p_list != NULL)
+    {
+        if ( gatt_uuid_compare (*p_app_uuid128, p_list->asgn_range.app_uuid128)
+             &&  gatt_uuid_compare (*p_svc_uuid,    p_list->asgn_range.svc_uuid)
+             &&  (start_handle == p_list->asgn_range.s_handle) )
+        {
+            GATT_TRACE_DEBUG ("Already allocated handles for this service before!!");
+            return(p_list);
+        }
+        p_list = p_list->p_next;
+    }
+    return NULL;
+}
+/*******************************************************************************
+**
+** Function         gatt_free_hdl_buffer
+**
+** Description     free a handle buffer
+**
+** Returns       None
+**
+*******************************************************************************/
+void gatt_free_hdl_buffer(tGATT_HDL_LIST_ELEM *p)
+{
+
+    if (p)
+    {
+        while (!fixed_queue_is_empty(p->svc_db.svc_buffer))
+            osi_free(fixed_queue_try_dequeue(p->svc_db.svc_buffer));
+        fixed_queue_free(p->svc_db.svc_buffer, NULL);
+        memset(p, 0, sizeof(tGATT_HDL_LIST_ELEM));
+    }
+}
+/*******************************************************************************
+**
+** Function         gatt_free_srvc_db_buffer_app_id
+**
+** Description      free the service attribute database buffers by the owner of the
+**                  service app ID.
+**
+** Returns       None
+**
+*******************************************************************************/
+void gatt_free_srvc_db_buffer_app_id(tBT_UUID *p_app_id)
+{
+    tGATT_HDL_LIST_ELEM *p_elem =  &gatt_cb.hdl_list[0];
+    uint8_t i;
+
+    for (i = 0; i < GATT_MAX_SR_PROFILES; i ++, p_elem ++)
+    {
+        if (memcmp(p_app_id, &p_elem->asgn_range.app_uuid128, sizeof(tBT_UUID)) == 0)
+        {
+            while (!fixed_queue_is_empty(p_elem->svc_db.svc_buffer))
+                osi_free(fixed_queue_try_dequeue(p_elem->svc_db.svc_buffer));
+            fixed_queue_free(p_elem->svc_db.svc_buffer, NULL);
+            p_elem->svc_db.svc_buffer = NULL;
+
+            p_elem->svc_db.mem_free = 0;
+            p_elem->svc_db.p_attr_list = p_elem->svc_db.p_free_mem = NULL;
+        }
+    }
+}
+/*******************************************************************************
+**
+** Function         gatt_is_last_attribute
+**
+** Description     Check this is the last attribute of the specified value or not
+**
+** Returns       true - yes this is the last attribute
+**
+*******************************************************************************/
+bool    gatt_is_last_attribute(tGATT_SRV_LIST_INFO *p_list, tGATT_SRV_LIST_ELEM *p_start, tBT_UUID value)
+{
+    tGATT_SRV_LIST_ELEM *p_srv= p_start->p_next;
+    bool                 is_last_attribute = true;
+    tGATT_SR_REG        *p_rcb = NULL;
+    tBT_UUID            *p_svc_uuid;
+
+    p_list->p_last_primary = NULL;
+
+    while (p_srv)
+    {
+        p_rcb = GATT_GET_SR_REG_PTR(p_srv->i_sreg);
+
+        p_svc_uuid = gatts_get_service_uuid (p_rcb->p_db);
+
+        if (gatt_uuid_compare(value, *p_svc_uuid))
+        {
+            is_last_attribute = false;
+            break;
+
+        }
+        p_srv = p_srv->p_next;
+    }
+
+    return is_last_attribute;
+
+}
+
+/*******************************************************************************
+**
+** Function         gatt_update_last_pri_srv_info
+**
+** Description     Update the the last primary info for the service list info
+**
+** Returns       None
+**
+*******************************************************************************/
+void gatt_update_last_pri_srv_info(tGATT_SRV_LIST_INFO *p_list)
+{
+    tGATT_SRV_LIST_ELEM *p_srv= p_list->p_first;
+
+    p_list->p_last_primary = NULL;
+
+    while (p_srv)
+    {
+        if (p_srv->is_primary)
+        {
+            p_list->p_last_primary = p_srv;
+        }
+        p_srv = p_srv->p_next;
+    }
+
+}
+/*******************************************************************************
+**
+** Function         gatts_update_srv_list_elem
+**
+** Description      update an element in the service list.
+**
+** Returns          None.
+**
+*******************************************************************************/
+void gatts_update_srv_list_elem(uint8_t i_sreg,
+                                UNUSED_ATTR uint16_t handle, bool    is_primary)
+{
+    gatt_cb.srv_list[i_sreg].in_use         = true;
+    gatt_cb.srv_list[i_sreg].i_sreg    = i_sreg;
+    gatt_cb.srv_list[i_sreg].s_hdl          = gatt_cb.sr_reg[i_sreg].s_hdl;
+    gatt_cb.srv_list[i_sreg].is_primary     = is_primary;
+
+    return;
+}
+/*******************************************************************************
+**
+** Function  gatt_add_a_srv_to_list
+**
+** Description  add an service to the list in ascending
+**              order of the start handle
+**
+** Returns   bool    true-if add is successful
+**
+*******************************************************************************/
+bool    gatt_add_a_srv_to_list(tGATT_SRV_LIST_INFO *p_list, tGATT_SRV_LIST_ELEM *p_new)
+{
+    tGATT_SRV_LIST_ELEM *p_old;
+
+    if (!p_new)
+    {
+        GATT_TRACE_DEBUG("p_new==NULL");
+        return false;
+    }
+
+    if (!p_list->p_first)
+    {
+        /* this is an empty list */
+        p_list->p_first =
+        p_list->p_last  = p_new;
+        p_new->p_next   =
+        p_new->p_prev   = NULL;
+    }
+    else
+    {
+        p_old = p_list->p_first;
+        while (1)
+        {
+            if (p_old == NULL)
+            {
+                p_list->p_last->p_next      = p_new;
+                p_new->p_prev               = p_list->p_last;
+                p_new->p_next               = NULL;
+                p_list->p_last              = p_new;
+                break;
+            }
+            else
+            {
+                if (p_new->s_hdl <  p_old->s_hdl)
+                {
+                    /* if not the first in list */
+                    if (p_old->p_prev != NULL)
+                        p_old->p_prev->p_next   = p_new;
+                    else
+                        p_list->p_first = p_new;
+
+                    p_new->p_prev           = p_old->p_prev;
+                    p_new->p_next           = p_old;
+                    p_old->p_prev           = p_new;
+                    break;
+                }
+            }
+            p_old = p_old->p_next;
+        }
+    }
+    p_list->count++;
+
+    gatt_update_last_pri_srv_info(p_list);
+    return true;
+
+}
+
+/*******************************************************************************
+**
+** Function  gatt_remove_a_srv_from_list
+**
+** Description  Remove a service from the list
+**
+** Returns   bool    true-if remove is successful
+**
+*******************************************************************************/
+bool    gatt_remove_a_srv_from_list(tGATT_SRV_LIST_INFO *p_list, tGATT_SRV_LIST_ELEM *p_remove)
+{
+    if (!p_remove || !p_list->p_first)
+    {
+        GATT_TRACE_DEBUG("p_remove==NULL || p_list->p_first==NULL");
+        return false;
+    }
+
+    if (p_remove->p_prev == NULL)
+    {
+        p_list->p_first             = p_remove->p_next;
+        if (p_remove->p_next)
+            p_remove->p_next->p_prev    = NULL;
+    }
+    else if (p_remove->p_next == NULL)
+    {
+        p_list->p_last              = p_remove->p_prev;
+        p_remove->p_prev->p_next    = NULL;
+    }
+    else
+    {
+        p_remove->p_next->p_prev = p_remove->p_prev;
+        p_remove->p_prev->p_next = p_remove->p_next;
+    }
+    p_list->count--;
+    gatt_update_last_pri_srv_info(p_list);
+    return true;
+
+}
+
+/*******************************************************************************
+**
+** Function  gatt_add_an_item_to_list
+**
+** Description  add an service handle range to the list in decending
+**              order of the start handle
+**
+** Returns   bool    true-if add is successful
+**
+*******************************************************************************/
+bool    gatt_add_an_item_to_list(tGATT_HDL_LIST_INFO *p_list, tGATT_HDL_LIST_ELEM *p_new)
+{
+    tGATT_HDL_LIST_ELEM *p_old;
+    if (!p_new)
+    {
+        GATT_TRACE_DEBUG("p_new==NULL");
+        return false;
+    }
+
+    if (!p_list->p_first)
+    {
+        /* this is an empty list */
+        p_list->p_first =
+        p_list->p_last  = p_new;
+        p_new->p_next   =
+        p_new->p_prev   = NULL;
+    }
+    else
+    {
+        p_old = p_list->p_first;
+        while (1)
+        {
+            if (p_old == NULL)
+            {
+                p_list->p_last->p_next      = p_new;
+                p_new->p_prev               = p_list->p_last;
+                p_new->p_next               = NULL;
+                p_list->p_last              = p_new;
+
+                break;
+
+            }
+            else
+            {
+                if (p_new->asgn_range.s_handle >  p_old->asgn_range.s_handle)
+                {
+                    if (p_old == p_list->p_first)
+                        p_list->p_first = p_new;
+
+                    p_new->p_prev    = p_old->p_prev;
+                    p_new->p_next    = p_old;
+
+
+                    p_old->p_prev    = p_new;
+                    break;
+                }
+            }
+            p_old = p_old->p_next;
+        }
+    }
+    p_list->count++;
+    return true;
+
+}
+
+/*******************************************************************************
+**
+** Function  gatt_remove_an_item_from_list
+**
+** Description  Remove an service handle range from the list
+**
+** Returns   bool    true-if remove is successful
+**
+*******************************************************************************/
+bool    gatt_remove_an_item_from_list(tGATT_HDL_LIST_INFO *p_list, tGATT_HDL_LIST_ELEM *p_remove)
+{
+    if (!p_remove || !p_list->p_first)
+    {
+        GATT_TRACE_DEBUG("p_remove==NULL || p_list->p_first==NULL");
+        return false;
+    }
+
+    if (p_remove->p_prev == NULL)
+    {
+        p_list->p_first             = p_remove->p_next;
+        if (p_remove->p_next)
+            p_remove->p_next->p_prev    = NULL;
+    }
+    else if (p_remove->p_next == NULL)
+    {
+        p_list->p_last              = p_remove->p_prev;
+        p_remove->p_prev->p_next    = NULL;
+    }
+    else
+    {
+        p_remove->p_next->p_prev = p_remove->p_prev;
+        p_remove->p_prev->p_next = p_remove->p_next;
+    }
+    p_list->count--;
+    return true;
+
+}
+
+/*******************************************************************************
+**
+** Function         gatt_find_the_connected_bda
+**
+** Description      This function find the connected bda
+**
+** Returns           true if found
+**
+*******************************************************************************/
+bool    gatt_find_the_connected_bda(uint8_t start_idx, BD_ADDR bda, uint8_t *p_found_idx,
+                                    tBT_TRANSPORT *p_transport)
+{
+    uint8_t i;
+    bool    found = false;
+    GATT_TRACE_DEBUG("gatt_find_the_connected_bda start_idx=%d",start_idx);
+
+    for (i = start_idx ; i < GATT_MAX_PHY_CHANNEL; i ++)
+    {
+        if (gatt_cb.tcb[i].in_use && gatt_cb.tcb[i].ch_state == GATT_CH_OPEN)
+        {
+            memcpy( bda, gatt_cb.tcb[i].peer_bda, BD_ADDR_LEN);
+            *p_found_idx = i;
+            *p_transport = gatt_cb.tcb[i].transport;
+            found = true;
+            GATT_TRACE_DEBUG("gatt_find_the_connected_bda bda :%02x-%02x-%02x-%02x-%02x-%02x",
+                              bda[0],  bda[1], bda[2],  bda[3], bda[4],  bda[5]);
+            break;
+        }
+    }
+    GATT_TRACE_DEBUG("gatt_find_the_connected_bda found=%d found_idx=%d", found, i);
+    return found;
+}
+
+
+
+/*******************************************************************************
+**
+** Function         gatt_is_srv_chg_ind_pending
+**
+** Description      Check whether a service chnaged is in the indication pending queue
+**                  or waiting for an Ack already
+**
+** Returns         bool
+**
+*******************************************************************************/
+bool    gatt_is_srv_chg_ind_pending (tGATT_TCB *p_tcb)
+{
+    bool    srv_chg_ind_pending = false;
+
+    GATT_TRACE_DEBUG("gatt_is_srv_chg_ind_pending is_queue_empty=%d",
+                     fixed_queue_is_empty(p_tcb->pending_ind_q));
+
+    if (p_tcb->indicate_handle == gatt_cb.handle_of_h_r)
+    {
+        srv_chg_ind_pending = true;
+    }
+    else if (! fixed_queue_is_empty(p_tcb->pending_ind_q))
+    {
+        list_t *list = fixed_queue_get_list(p_tcb->pending_ind_q);
+        for (const list_node_t *node = list_begin(list);
+             node != list_end(list);
+             node = list_next(node)) {
+            tGATT_VALUE *p_buf = (tGATT_VALUE *)list_node(node);
+            if (p_buf->handle == gatt_cb.handle_of_h_r)
+            {
+                srv_chg_ind_pending = true;
+                break;
+            }
+        }
+    }
+
+    GATT_TRACE_DEBUG("srv_chg_ind_pending = %d", srv_chg_ind_pending);
+    return srv_chg_ind_pending;
+}
+
+
+/*******************************************************************************
+**
+** Function         gatt_is_bda_in_the_srv_chg_clt_list
+**
+** Description      This function check the specified bda is in the srv chg clinet list or not
+**
+** Returns         pointer to the found elemenet otherwise NULL
+**
+*******************************************************************************/
+tGATTS_SRV_CHG *gatt_is_bda_in_the_srv_chg_clt_list (BD_ADDR bda)
+{
+    tGATTS_SRV_CHG *p_buf = NULL;
+
+    GATT_TRACE_DEBUG("gatt_is_bda_in_the_srv_chg_clt_list :%02x-%02x-%02x-%02x-%02x-%02x",
+                      bda[0],  bda[1], bda[2],  bda[3], bda[4],  bda[5]);
+
+    if (fixed_queue_is_empty(gatt_cb.srv_chg_clt_q))
+        return NULL;
+
+    list_t *list = fixed_queue_get_list(gatt_cb.srv_chg_clt_q);
+    for (const list_node_t *node = list_begin(list); node != list_end(list);
+         node = list_next(node)) {
+        tGATTS_SRV_CHG *p_buf = (tGATTS_SRV_CHG *)list_node(node);
+        if (!memcmp( bda, p_buf->bda, BD_ADDR_LEN))
+        {
+            GATT_TRACE_DEBUG("bda is in the srv chg clt list");
+            break;
+        }
+    }
+
+    return p_buf;
+}
+
+
+/*******************************************************************************
+**
+** Function         gatt_is_bda_connected
+**
+** Description
+**
+** Returns           GATT_INDEX_INVALID if not found. Otherwise index to the tcb.
+**
+*******************************************************************************/
+bool    gatt_is_bda_connected(BD_ADDR bda)
+{
+    uint8_t i = 0;
+    bool    connected=false;
+
+    for ( i=0; i < GATT_MAX_PHY_CHANNEL; i ++)
+    {
+        if (gatt_cb.tcb[i].in_use &&
+            !memcmp(gatt_cb.tcb[i].peer_bda, bda, BD_ADDR_LEN))
+        {
+            connected = true;
+            break;
+        }
+    }
+    return connected;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_find_i_tcb_by_addr
+**
+** Description      The function searches for an empty tcb entry, and return the index.
+**
+** Returns           GATT_INDEX_INVALID if not found. Otherwise index to the tcb.
+**
+*******************************************************************************/
+uint8_t gatt_find_i_tcb_by_addr(BD_ADDR bda, tBT_TRANSPORT transport)
+{
+    uint8_t i = 0;
+
+    for ( ; i < GATT_MAX_PHY_CHANNEL; i ++)
+    {
+        if (!memcmp(gatt_cb.tcb[i].peer_bda, bda, BD_ADDR_LEN) &&
+            gatt_cb.tcb[i].transport == transport)
+        {
+            return i;
+        }
+    }
+    return GATT_INDEX_INVALID;
+}
+
+
+/*******************************************************************************
+**
+** Function         gatt_get_tcb_by_idx
+**
+** Description      The function get TCB using the TCB index
+**
+** Returns           NULL if not found. Otherwise index to the tcb.
+**
+*******************************************************************************/
+tGATT_TCB * gatt_get_tcb_by_idx(uint8_t tcb_idx)
+{
+    tGATT_TCB   *p_tcb = NULL;
+
+    if ( (tcb_idx < GATT_MAX_PHY_CHANNEL) && gatt_cb.tcb[tcb_idx].in_use)
+        p_tcb = &gatt_cb.tcb[tcb_idx];
+
+    return p_tcb;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_find_tcb_by_addr
+**
+** Description      The function searches for an empty tcb entry, and return pointer.
+**
+** Returns           NULL if not found. Otherwise index to the tcb.
+**
+*******************************************************************************/
+tGATT_TCB * gatt_find_tcb_by_addr(BD_ADDR bda, tBT_TRANSPORT transport)
+{
+    tGATT_TCB   *p_tcb = NULL;
+    uint8_t i = 0;
+
+    if ((i = gatt_find_i_tcb_by_addr(bda, transport)) != GATT_INDEX_INVALID)
+        p_tcb = &gatt_cb.tcb[i];
+
+    return p_tcb;
+}
+/*******************************************************************************
+**
+** Function         gatt_find_i_tcb_free
+**
+** Description      The function searches for an empty tcb entry, and return the index.
+**
+** Returns           GATT_INDEX_INVALID if not found. Otherwise index to the tcb.
+**
+*******************************************************************************/
+uint8_t gatt_find_i_tcb_free(void)
+{
+    uint8_t i = 0, j = GATT_INDEX_INVALID;
+
+    for (i = 0; i < GATT_MAX_PHY_CHANNEL; i ++)
+    {
+        if (!gatt_cb.tcb[i].in_use)
+        {
+            j = i;
+            break;
+        }
+    }
+    return j;
+}
+/*******************************************************************************
+**
+** Function         gatt_allocate_tcb_by_bdaddr
+**
+** Description      The function locate or allocate new tcb entry for matching bda.
+**
+** Returns           GATT_INDEX_INVALID if not found. Otherwise index to the tcb.
+**
+*******************************************************************************/
+tGATT_TCB * gatt_allocate_tcb_by_bdaddr(BD_ADDR bda, tBT_TRANSPORT transport)
+{
+    uint8_t i = 0;
+    bool    allocated = false;
+    tGATT_TCB    *p_tcb = NULL;
+
+    /* search for existing tcb with matching bda    */
+    i = gatt_find_i_tcb_by_addr(bda, transport);
+    /* find free tcb */
+    if (i == GATT_INDEX_INVALID)
+    {
+        i = gatt_find_i_tcb_free();
+        allocated = true;
+    }
+    if (i != GATT_INDEX_INVALID)
+    {
+        p_tcb = &gatt_cb.tcb[i];
+
+        if (allocated)
+        {
+            memset(p_tcb, 0, sizeof(tGATT_TCB));
+            p_tcb->pending_enc_clcb = fixed_queue_new(SIZE_MAX);
+            p_tcb->pending_ind_q = fixed_queue_new(SIZE_MAX);
+            p_tcb->conf_timer = alarm_new("gatt.conf_timer");
+            p_tcb->ind_ack_timer = alarm_new("gatt.ind_ack_timer");
+            p_tcb->in_use = true;
+            p_tcb->tcb_idx = i;
+            p_tcb->transport = transport;
+        }
+        memcpy(p_tcb->peer_bda, bda, BD_ADDR_LEN);
+    }
+    return p_tcb;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_convert_uuid16_to_uuid128
+**
+** Description      Convert a 16 bits UUID to be an standard 128 bits one.
+**
+** Returns          true if two uuid match; false otherwise.
+**
+*******************************************************************************/
+void gatt_convert_uuid16_to_uuid128(uint8_t uuid_128[LEN_UUID_128], uint16_t uuid_16)
+{
+    uint8_t *p = &uuid_128[LEN_UUID_128 - 4];
+
+    memcpy (uuid_128, base_uuid, LEN_UUID_128);
+
+    UINT16_TO_STREAM(p, uuid_16);
+}
+
+/*******************************************************************************
+**
+** Function         gatt_convert_uuid32_to_uuid128
+**
+** Description      Convert a 32 bits UUID to be an standard 128 bits one.
+**
+** Returns          true if two uuid match; false otherwise.
+**
+*******************************************************************************/
+void gatt_convert_uuid32_to_uuid128(uint8_t uuid_128[LEN_UUID_128], uint32_t uuid_32)
+{
+    uint8_t *p = &uuid_128[LEN_UUID_128 - 4];
+
+    memcpy (uuid_128, base_uuid, LEN_UUID_128);
+
+    UINT32_TO_STREAM(p, uuid_32);
+}
+/*******************************************************************************
+**
+** Function         gatt_uuid_compare
+**
+** Description      Compare two UUID to see if they are the same.
+**
+** Returns          true if two uuid match; false otherwise.
+**
+*******************************************************************************/
+bool    gatt_uuid_compare (tBT_UUID src, tBT_UUID tar)
+{
+    uint8_t su[LEN_UUID_128], tu[LEN_UUID_128];
+    uint8_t *ps, *pt;
+
+    /* any of the UUID is unspecified */
+    if (src.len == 0 || tar.len == 0)
+    {
+        return true;
+    }
+
+    /* If both are 16-bit, we can do a simple compare */
+    if (src.len == LEN_UUID_16 && tar.len == LEN_UUID_16)
+    {
+        return src.uu.uuid16 == tar.uu.uuid16;
+    }
+
+    /* If both are 32-bit, we can do a simple compare */
+    if (src.len == LEN_UUID_32 && tar.len == LEN_UUID_32)
+    {
+        return src.uu.uuid32 == tar.uu.uuid32;
+    }
+
+    /* One or both of the UUIDs is 128-bit */
+    if (src.len == LEN_UUID_16)
+    {
+        /* convert a 16 bits UUID to 128 bits value */
+        gatt_convert_uuid16_to_uuid128(su, src.uu.uuid16);
+        ps = su;
+    }
+    else if (src.len == LEN_UUID_32)
+    {
+        gatt_convert_uuid32_to_uuid128(su, src.uu.uuid32);
+        ps = su;
+    }
+    else
+        ps = src.uu.uuid128;
+
+    if (tar.len == LEN_UUID_16)
+    {
+        /* convert a 16 bits UUID to 128 bits value */
+        gatt_convert_uuid16_to_uuid128(tu, tar.uu.uuid16);
+        pt = tu;
+    }
+    else if (tar.len == LEN_UUID_32)
+    {
+        /* convert a 32 bits UUID to 128 bits value */
+        gatt_convert_uuid32_to_uuid128(tu, tar.uu.uuid32);
+        pt = tu;
+    }
+    else
+        pt = tar.uu.uuid128;
+
+    return(memcmp(ps, pt, LEN_UUID_128) == 0);
+}
+
+/*******************************************************************************
+**
+** Function         gatt_build_uuid_to_stream
+**
+** Description      Add UUID into stream.
+**
+** Returns          UUID length.
+**
+*******************************************************************************/
+uint8_t gatt_build_uuid_to_stream(uint8_t **p_dst, tBT_UUID uuid)
+{
+    uint8_t *p = *p_dst;
+    uint8_t len = 0;
+
+    if (uuid.len == LEN_UUID_16)
+    {
+        UINT16_TO_STREAM (p, uuid.uu.uuid16);
+        len = LEN_UUID_16;
+    }
+    else if (uuid.len == LEN_UUID_32) /* always convert 32 bits into 128 bits as alwats */
+    {
+        gatt_convert_uuid32_to_uuid128(p, uuid.uu.uuid32);
+        p += LEN_UUID_128;
+        len = LEN_UUID_128;
+    }
+    else if (uuid.len == LEN_UUID_128)
+    {
+        ARRAY_TO_STREAM (p, uuid.uu.uuid128, LEN_UUID_128);
+        len = LEN_UUID_128;
+    }
+
+    *p_dst = p;
+    return len;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_parse_uuid_from_cmd
+**
+** Description      Convert a 128 bits UUID into a 16 bits UUID.
+**
+** Returns          true if command sent, otherwise false.
+**
+*******************************************************************************/
+bool    gatt_parse_uuid_from_cmd(tBT_UUID *p_uuid_rec, uint16_t uuid_size, uint8_t **p_data)
+{
+    bool    is_base_uuid, ret = true;
+    uint8_t xx;
+    uint8_t *p_uuid = *p_data;
+
+    memset(p_uuid_rec, 0, sizeof(tBT_UUID));
+
+    switch (uuid_size)
+    {
+        case LEN_UUID_16:
+            p_uuid_rec->len = uuid_size;
+            STREAM_TO_UINT16 (p_uuid_rec->uu.uuid16, p_uuid);
+            *p_data += LEN_UUID_16;
+            break;
+
+        case LEN_UUID_128:
+            /* See if we can compress his UUID down to 16 or 32bit UUIDs */
+            is_base_uuid = true;
+            for (xx = 0; xx < LEN_UUID_128 - 4; xx++)
+            {
+                if (p_uuid[xx] != base_uuid[xx])
+                {
+                    is_base_uuid = false;
+                    break;
+                }
+            }
+            if (is_base_uuid)
+            {
+                if ((p_uuid[LEN_UUID_128 - 1] == 0) && (p_uuid[LEN_UUID_128 - 2] == 0))
+                {
+                    p_uuid += (LEN_UUID_128 - 4);
+                    p_uuid_rec->len = LEN_UUID_16;
+                    STREAM_TO_UINT16(p_uuid_rec->uu.uuid16, p_uuid);
+                }
+                else
+                {
+                    p_uuid += (LEN_UUID_128 - LEN_UUID_32);
+                    p_uuid_rec->len = LEN_UUID_32;
+                    STREAM_TO_UINT32(p_uuid_rec->uu.uuid32, p_uuid);
+                }
+            }
+            if (!is_base_uuid)
+            {
+                p_uuid_rec->len = LEN_UUID_128;
+                memcpy(p_uuid_rec->uu.uuid128, p_uuid, LEN_UUID_128);
+            }
+            *p_data += LEN_UUID_128;
+            break;
+
+        /* do not allow 32 bits UUID in ATT PDU now */
+        case LEN_UUID_32:
+            GATT_TRACE_ERROR("DO NOT ALLOW 32 BITS UUID IN ATT PDU");
+            return false;
+        case 0:
+        default:
+            if (uuid_size != 0) ret = false;
+            GATT_TRACE_WARNING("gatt_parse_uuid_from_cmd invalid uuid size");
+            break;
+    }
+
+    return( ret);
+}
+
+/*******************************************************************************
+**
+** Function         gatt_start_rsp_timer
+**
+** Description      Start a wait_for_response timer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_start_rsp_timer(uint16_t clcb_idx)
+{
+    tGATT_CLCB *p_clcb = &gatt_cb.clcb[clcb_idx];
+    period_ms_t timeout_ms = GATT_WAIT_FOR_RSP_TIMEOUT_MS;
+
+    if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
+        p_clcb->op_subtype == GATT_DISC_SRVC_ALL) {
+        timeout_ms = GATT_WAIT_FOR_DISC_RSP_TIMEOUT_MS;
+    }
+
+    // TODO: The tGATT_CLCB memory and state management needs cleanup,
+    // and then the timers can be allocated elsewhere.
+    if (p_clcb->gatt_rsp_timer_ent == NULL) {
+        p_clcb->gatt_rsp_timer_ent = alarm_new("gatt.gatt_rsp_timer_ent");
+    }
+    alarm_set_on_queue(p_clcb->gatt_rsp_timer_ent, timeout_ms,
+                       gatt_rsp_timeout, p_clcb, btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+**
+** Function         gatt_start_conf_timer
+**
+** Description      Start a wait_for_confirmation timer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_start_conf_timer(tGATT_TCB *p_tcb)
+{
+    alarm_set_on_queue(p_tcb->conf_timer, GATT_WAIT_FOR_RSP_TIMEOUT_MS,
+                       gatt_indication_confirmation_timeout, p_tcb,
+                       btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+**
+** Function         gatt_start_ind_ack_timer
+**
+** Description      start the application ack timer
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_start_ind_ack_timer(tGATT_TCB *p_tcb)
+{
+    /* start notification cache timer */
+    alarm_set_on_queue(p_tcb->ind_ack_timer, GATT_WAIT_FOR_RSP_TIMEOUT_MS,
+                       gatt_ind_ack_timeout, p_tcb, btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+**
+** Function         gatt_rsp_timeout
+**
+** Description      Called when GATT wait for ATT command response timer expires
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_rsp_timeout(void *data)
+{
+    tGATT_CLCB *p_clcb = (tGATT_CLCB *)data;
+
+    if (p_clcb == NULL || p_clcb->p_tcb == NULL)
+    {
+        GATT_TRACE_WARNING("%s clcb is already deleted", __func__);
+        return;
+    }
+    if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
+        p_clcb->op_subtype == GATT_DISC_SRVC_ALL &&
+        p_clcb->retry_count < GATT_REQ_RETRY_LIMIT)
+    {
+        uint8_t rsp_code;
+        GATT_TRACE_WARNING("%s retry discovery primary service", __func__);
+        if (p_clcb != gatt_cmd_dequeue(p_clcb->p_tcb, &rsp_code))
+        {
+            GATT_TRACE_ERROR("%s command queue out of sync, disconnect",
+                             __func__);
+        }
+        else
+        {
+            p_clcb->retry_count++;
+            gatt_act_discovery(p_clcb);
+            return;
+        }
+    }
+
+    GATT_TRACE_WARNING("%s disconnecting...", __func__);
+    gatt_disconnect (p_clcb->p_tcb);
+}
+
+/*******************************************************************************
+**
+** Function         gatt_indication_confirmation_timeout
+**
+** Description      Called when the indication confirmation timer expires
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_indication_confirmation_timeout(void *data)
+{
+    tGATT_TCB *p_tcb = (tGATT_TCB *)data;
+
+    GATT_TRACE_WARNING("%s disconnecting...", __func__);
+    gatt_disconnect(p_tcb);
+}
+
+/*******************************************************************************
+**
+** Function         gatt_ind_ack_timeout
+**
+** Description      Called when GATT wait for ATT handle confirmation timeout
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_ind_ack_timeout(void *data)
+{
+    tGATT_TCB *p_tcb = (tGATT_TCB *)data;
+
+    GATT_TRACE_WARNING("%s send ack now", __func__);
+
+    if (p_tcb != NULL)
+        p_tcb->ind_count = 0;
+
+    attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
+}
+/*******************************************************************************
+**
+** Function         gatt_sr_find_i_rcb_by_handle
+**
+** Description      The function searches for a service that owns a specific handle.
+**
+** Returns          GATT_MAX_SR_PROFILES if not found. Otherwise index of th eservice.
+**
+*******************************************************************************/
+uint8_t gatt_sr_find_i_rcb_by_handle(uint16_t handle)
+{
+    uint8_t i_rcb = 0;
+
+    for ( ; i_rcb < GATT_MAX_SR_PROFILES; i_rcb++)
+    {
+        if (gatt_cb.sr_reg[i_rcb].in_use &&
+            gatt_cb.sr_reg[i_rcb].s_hdl <= handle &&
+            gatt_cb.sr_reg[i_rcb].e_hdl >= handle )
+        {
+            break;
+        }
+    }
+    return i_rcb;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_sr_find_i_rcb_by_handle
+**
+** Description      The function searches for a service that owns a specific handle.
+**
+** Returns          0 if not found. Otherwise index of th eservice.
+**
+*******************************************************************************/
+uint8_t gatt_sr_find_i_rcb_by_app_id(tBT_UUID *p_app_uuid128, tBT_UUID *p_svc_uuid, uint16_t start_handle)
+{
+    uint8_t         i_rcb = 0;
+    tGATT_SR_REG    *p_sreg;
+    tBT_UUID        *p_this_uuid;
+
+    for (i_rcb = 0, p_sreg = gatt_cb.sr_reg; i_rcb < GATT_MAX_SR_PROFILES; i_rcb++, p_sreg++)
+    {
+        if ( p_sreg->in_use )
+        {
+            p_this_uuid = gatts_get_service_uuid (p_sreg->p_db);
+
+            if (p_this_uuid &&
+                gatt_uuid_compare (*p_app_uuid128, p_sreg->app_uuid ) &&
+                gatt_uuid_compare (*p_svc_uuid, *p_this_uuid) &&
+                (start_handle == p_sreg->s_hdl))
+            {
+                GATT_TRACE_ERROR ("Active Service Found ");
+                gatt_dbg_display_uuid(*p_svc_uuid);
+
+                break;
+            }
+        }
+    }
+    return i_rcb;
+}
+/*******************************************************************************
+**
+** Function         gatt_sr_find_i_rcb_by_handle
+**
+** Description      The function searches for a service that owns a specific handle.
+**
+** Returns          0 if not found. Otherwise index of th eservice.
+**
+*******************************************************************************/
+uint8_t gatt_sr_alloc_rcb(tGATT_HDL_LIST_ELEM *p_list )
+{
+    uint8_t ii = 0;
+    tGATT_SR_REG    *p_sreg = NULL;
+
+    /*this is a new application servoce start */
+    for (ii = 0, p_sreg = gatt_cb.sr_reg; ii < GATT_MAX_SR_PROFILES; ii++, p_sreg++)
+    {
+        if (!p_sreg->in_use)
+        {
+            memset (p_sreg, 0, sizeof(tGATT_SR_REG));
+
+            p_sreg->in_use = true;
+            memcpy (&p_sreg->app_uuid, &p_list->asgn_range.app_uuid128, sizeof(tBT_UUID));
+
+            p_sreg->type                = p_list->asgn_range.is_primary ? GATT_UUID_PRI_SERVICE: GATT_UUID_SEC_SERVICE;
+            p_sreg->s_hdl               = p_list->asgn_range.s_handle;
+            p_sreg->e_hdl               = p_list->asgn_range.e_handle;
+            p_sreg->p_db                = &p_list->svc_db;
+
+            GATT_TRACE_DEBUG("total buffer in db [%d]",
+                             fixed_queue_length(p_sreg->p_db->svc_buffer));
+            break;
+        }
+    }
+
+    return ii;
+}
+/*******************************************************************************
+**
+** Function         gatt_sr_get_sec_info
+**
+** Description      Get the security flag and key size information for the peer
+**                  device.
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_sr_get_sec_info(BD_ADDR rem_bda, tBT_TRANSPORT transport, uint8_t *p_sec_flag, uint8_t *p_key_size)
+{
+    uint8_t         sec_flag = 0;
+
+    BTM_GetSecurityFlagsByTransport(rem_bda, &sec_flag, transport);
+
+    sec_flag &= (GATT_SEC_FLAG_LKEY_UNAUTHED | GATT_SEC_FLAG_LKEY_AUTHED | GATT_SEC_FLAG_ENCRYPTED);
+
+    *p_key_size = btm_ble_read_sec_key_size(rem_bda);
+    *p_sec_flag = sec_flag;
+}
+/*******************************************************************************
+**
+** Function         gatt_sr_send_req_callback
+**
+** Description
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_sr_send_req_callback(uint16_t conn_id,
+                               uint32_t trans_id,
+                               tGATTS_REQ_TYPE type, tGATTS_DATA *p_data)
+{
+    tGATT_IF        gatt_if = GATT_GET_GATT_IF(conn_id);
+    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
+
+    if (!p_reg )
+    {
+        GATT_TRACE_ERROR ("p_reg not found discard request");
+        return;
+    }
+
+    if ( p_reg->in_use &&
+         p_reg->app_cb.p_req_cb)
+    {
+        (*p_reg->app_cb.p_req_cb)(conn_id, trans_id, type, p_data);
+    }
+    else
+    {
+        GATT_TRACE_WARNING("Call back not found for application conn_id=%d", conn_id);
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         gatt_send_error_rsp
+**
+** Description      This function sends an error response.
+**
+** Returns          void
+**
+*******************************************************************************/
+tGATT_STATUS gatt_send_error_rsp (tGATT_TCB *p_tcb, uint8_t err_code, uint8_t op_code,
+                                  uint16_t handle, bool    deq)
+{
+    tGATT_ERROR      error;
+    tGATT_STATUS     status;
+    BT_HDR           *p_buf;
+
+    error.cmd_code = op_code;
+    error.reason = err_code;
+    error.handle =handle;
+
+    if ((p_buf = attp_build_sr_msg(p_tcb, GATT_RSP_ERROR, (tGATT_SR_MSG *)&error)) != NULL)
+    {
+        status = attp_send_sr_msg (p_tcb, p_buf);
+    }
+    else
+        status = GATT_INSUF_RESOURCE;
+
+    if (deq)
+        gatt_dequeue_sr_cmd(p_tcb);
+
+    return status;
+}
+
+
+/*******************************************************************************
+**
+** Function         gatt_add_sdp_record
+**
+** Description      This function add a SDP record for a GATT primary service
+**
+** Returns          0 if error else sdp handle for the record.
+**
+*******************************************************************************/
+uint32_t gatt_add_sdp_record (tBT_UUID *p_uuid, uint16_t start_hdl, uint16_t end_hdl)
+{
+    tSDP_PROTOCOL_ELEM  proto_elem_list[2];
+    uint32_t            sdp_handle;
+    uint16_t            list = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+    uint8_t             buff[60];
+    uint8_t             *p = buff;
+
+    GATT_TRACE_DEBUG("gatt_add_sdp_record s_hdl=0x%x  s_hdl=0x%x",start_hdl, end_hdl);
+
+    if ((sdp_handle = SDP_CreateRecord()) == 0)
+        return 0;
+
+    switch (p_uuid->len)
+    {
+        case LEN_UUID_16:
+            SDP_AddServiceClassIdList(sdp_handle, 1, &p_uuid->uu.uuid16);
+            break;
+
+        case LEN_UUID_32:
+            UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_FOUR_BYTES);
+            UINT32_TO_BE_STREAM (p, p_uuid->uu.uuid32);
+            SDP_AddAttribute (sdp_handle, ATTR_ID_SERVICE_CLASS_ID_LIST, DATA_ELE_SEQ_DESC_TYPE,
+                              (uint32_t) (p - buff), buff);
+            break;
+
+        case LEN_UUID_128:
+            UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_SIXTEEN_BYTES);
+            ARRAY_TO_BE_STREAM_REVERSE (p, p_uuid->uu.uuid128, LEN_UUID_128);
+            SDP_AddAttribute (sdp_handle, ATTR_ID_SERVICE_CLASS_ID_LIST, DATA_ELE_SEQ_DESC_TYPE,
+                              (uint32_t) (p - buff), buff);
+            break;
+
+        default:
+            GATT_TRACE_ERROR("inavlid UUID len=%d", p_uuid->len);
+            SDP_DeleteRecord(sdp_handle);
+            return 0;
+            break;
+    }
+
+    /*** Fill out the protocol element sequence for SDP ***/
+    proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+    proto_elem_list[0].num_params    = 1;
+    proto_elem_list[0].params[0]     = BT_PSM_ATT;
+    proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_ATT;
+    proto_elem_list[1].num_params    = 2;
+    proto_elem_list[1].params[0]     = start_hdl;
+    proto_elem_list[1].params[1]     = end_hdl;
+
+    SDP_AddProtocolList(sdp_handle, 2, proto_elem_list);
+
+    /* Make the service browseable */
+    SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &list);
+
+    return(sdp_handle);
+}
+
+
+    #if GATT_CONFORMANCE_TESTING == true
+/*******************************************************************************
+**
+** Function         gatt_set_err_rsp
+**
+** Description      This function is called to set the test confirm value
+**
+** Returns          void
+**
+*******************************************************************************/
+void gatt_set_err_rsp(bool    enable, uint8_t req_op_code, uint8_t err_status)
+{
+    GATT_TRACE_DEBUG("gatt_set_err_rsp enable=%d op_code=%d, err_status=%d", enable, req_op_code, err_status);
+    gatt_cb.enable_err_rsp  = enable;
+    gatt_cb.req_op_code     = req_op_code;
+    gatt_cb.err_status      = err_status;
+}
+    #endif
+
+
+
+/*******************************************************************************
+**
+** Function         gatt_get_regcb
+**
+** Description      The function returns the registration control block.
+**
+** Returns          pointer to the registration control block or NULL
+**
+*******************************************************************************/
+tGATT_REG *gatt_get_regcb (tGATT_IF gatt_if)
+{
+    uint8_t         ii = (uint8_t)gatt_if;
+    tGATT_REG       *p_reg = NULL;
+
+    if (ii < 1 || ii > GATT_MAX_APPS) {
+        GATT_TRACE_WARNING("gatt_if out of range [ = %d]", ii);
+        return NULL;
+    }
+
+    // Index for cl_rcb is always 1 less than gatt_if.
+    p_reg = &gatt_cb.cl_rcb[ii - 1];
+
+    if (!p_reg->in_use) {
+        GATT_TRACE_WARNING("gatt_if found but not in use.");
+        return NULL;
+    }
+
+    return p_reg;
+}
+
+
+/*******************************************************************************
+**
+** Function         gatt_is_clcb_allocated
+**
+** Description      The function check clcb for conn_id is allocated or not
+**
+** Returns           True already allocated
+**
+*******************************************************************************/
+
+bool    gatt_is_clcb_allocated (uint16_t conn_id)
+{
+    uint8_t       i = 0;
+    bool          is_allocated= false;
+
+    for (i = 0; i < GATT_CL_MAX_LCB; i++)
+    {
+        if (gatt_cb.clcb[i].in_use && (gatt_cb.clcb[i].conn_id == conn_id))
+        {
+            is_allocated = true;
+            break;
+        }
+    }
+
+    return is_allocated;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_clcb_alloc
+**
+** Description      The function allocates a GATT  connection link control block
+**
+** Returns           NULL if not found. Otherwise pointer to the connection link block.
+**
+*******************************************************************************/
+tGATT_CLCB *gatt_clcb_alloc (uint16_t conn_id)
+{
+    uint8_t         i = 0;
+    tGATT_CLCB      *p_clcb = NULL;
+    tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
+    uint8_t         tcb_idx = GATT_GET_TCB_IDX(conn_id);
+    tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
+
+    for (i = 0; i < GATT_CL_MAX_LCB; i++)
+    {
+        if (!gatt_cb.clcb[i].in_use)
+        {
+            p_clcb = &gatt_cb.clcb[i];
+
+            p_clcb->in_use      = true;
+            p_clcb->conn_id     = conn_id;
+            p_clcb->clcb_idx    = i;
+            p_clcb->p_reg       = p_reg;
+            p_clcb->p_tcb       = p_tcb;
+            break;
+        }
+    }
+    return p_clcb;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_clcb_dealloc
+**
+** Description      The function de allocates a GATT  connection link control block
+**
+** Returns         None
+**
+*******************************************************************************/
+void gatt_clcb_dealloc (tGATT_CLCB *p_clcb)
+{
+    if (p_clcb && p_clcb->in_use)
+    {
+        alarm_free(p_clcb->gatt_rsp_timer_ent);
+        memset(p_clcb, 0, sizeof(tGATT_CLCB));
+    }
+}
+
+
+
+/*******************************************************************************
+**
+** Function         gatt_find_tcb_by_cid
+**
+** Description      The function searches for an empty entry
+**                   in registration info table for GATT client
+**
+** Returns           NULL if not found. Otherwise pointer to the rcb.
+**
+*******************************************************************************/
+tGATT_TCB * gatt_find_tcb_by_cid (uint16_t lcid)
+{
+    uint16_t     xx = 0;
+    tGATT_TCB    *p_tcb = NULL;
+
+    for (xx = 0; xx < GATT_MAX_PHY_CHANNEL; xx++)
+    {
+        if (gatt_cb.tcb[xx].in_use && gatt_cb.tcb[xx].att_lcid == lcid)
+        {
+            p_tcb = &gatt_cb.tcb[xx];
+            break;
+        }
+    }
+    return p_tcb;
+}
+
+
+/*******************************************************************************
+**
+** Function         gatt_num_apps_hold_link
+**
+** Description      The function find the number of applcaitions is holding the link
+**
+** Returns          total number of applications holding this acl link.
+**
+*******************************************************************************/
+uint8_t gatt_num_apps_hold_link(tGATT_TCB *p_tcb)
+{
+    uint8_t i, num = 0;
+
+    for (i = 0; i < GATT_MAX_APPS; i ++)
+    {
+        if (p_tcb->app_hold_link[i])
+            num ++;
+    }
+
+    GATT_TRACE_DEBUG("gatt_num_apps_hold_link   num=%d",  num);
+    return num;
+}
+
+
+/*******************************************************************************
+**
+** Function         gatt_num_clcb_by_bd_addr
+**
+** Description      The function searches all LCB with macthing bd address
+**
+** Returns          total number of clcb found.
+**
+*******************************************************************************/
+uint8_t gatt_num_clcb_by_bd_addr(BD_ADDR bda)
+{
+    uint8_t i, num = 0;
+
+    for (i = 0; i < GATT_CL_MAX_LCB; i ++)
+    {
+        if (gatt_cb.clcb[i].in_use && memcmp(gatt_cb.clcb[i].p_tcb->peer_bda, bda, BD_ADDR_LEN) == 0)
+            num ++;
+    }
+    return num;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_sr_update_cback_cnt
+**
+** Description      The function searches all LCB with macthing bd address
+**
+** Returns          total number of clcb found.
+**
+*******************************************************************************/
+void gatt_sr_copy_prep_cnt_to_cback_cnt(tGATT_TCB *p_tcb )
+{
+    uint8_t i;
+
+    if (p_tcb)
+    {
+        for (i = 0; i < GATT_MAX_APPS; i ++)
+        {
+            if (p_tcb->prep_cnt[i])
+            {
+                p_tcb->sr_cmd.cback_cnt[i]=1;
+            }
+        }
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         gatt_sr_is_cback_cnt_zero
+**
+** Description      The function searches all LCB with macthing bd address
+**
+** Returns          True if thetotal application callback count is zero
+**
+*******************************************************************************/
+bool    gatt_sr_is_cback_cnt_zero(tGATT_TCB *p_tcb )
+{
+    bool    status = true;
+    uint8_t i;
+
+    if (p_tcb)
+    {
+        for (i = 0; i < GATT_MAX_APPS; i ++)
+        {
+            if (p_tcb->sr_cmd.cback_cnt[i])
+            {
+                status = false;
+                break;
+            }
+        }
+    }
+    else
+    {
+        status = false;
+    }
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_sr_is_prep_cnt_zero
+**
+** Description      Check the prepare write request count is zero or not
+**
+** Returns          True no prepare write request
+**
+*******************************************************************************/
+bool    gatt_sr_is_prep_cnt_zero(tGATT_TCB *p_tcb)
+{
+    bool    status = true;
+    uint8_t i;
+
+    if (p_tcb)
+    {
+        for (i = 0; i < GATT_MAX_APPS; i ++)
+        {
+            if (p_tcb->prep_cnt[i])
+            {
+                status = false;
+                break;
+            }
+        }
+    }
+    else
+    {
+        status = false;
+    }
+    return status;
+}
+
+
+/*******************************************************************************
+**
+** Function         gatt_sr_reset_cback_cnt
+**
+** Description      Reset the application callback count to zero
+**
+** Returns         None
+**
+*******************************************************************************/
+void gatt_sr_reset_cback_cnt(tGATT_TCB *p_tcb )
+{
+    uint8_t i;
+
+    if (p_tcb)
+    {
+        for (i = 0; i < GATT_MAX_APPS; i ++)
+        {
+            p_tcb->sr_cmd.cback_cnt[i]=0;
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         gatt_sr_reset_prep_cnt
+**
+** Description     Reset the prep write count to zero
+**
+** Returns        None
+**
+*******************************************************************************/
+void gatt_sr_reset_prep_cnt(tGATT_TCB *p_tcb )
+{
+    uint8_t i;
+    if (p_tcb)
+    {
+        for (i = 0; i < GATT_MAX_APPS; i ++)
+        {
+            p_tcb->prep_cnt[i]=0;
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         gatt_sr_update_cback_cnt
+**
+** Description    Update the teh applicaiton callback count
+**
+** Returns           None
+**
+*******************************************************************************/
+void gatt_sr_update_cback_cnt(tGATT_TCB *p_tcb, tGATT_IF gatt_if, bool    is_inc, bool    is_reset_first)
+{
+
+    uint8_t idx = ((uint8_t) gatt_if) - 1 ;
+
+    if (p_tcb)
+    {
+        if (is_reset_first)
+        {
+            gatt_sr_reset_cback_cnt(p_tcb);
+        }
+        if (is_inc)
+        {
+            p_tcb->sr_cmd.cback_cnt[idx]++;
+        }
+        else
+        {
+            if ( p_tcb->sr_cmd.cback_cnt[idx])
+            {
+                p_tcb->sr_cmd.cback_cnt[idx]--;
+            }
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         gatt_sr_update_prep_cnt
+**
+** Description    Update the teh prepare write request count
+**
+** Returns           None
+**
+*******************************************************************************/
+void gatt_sr_update_prep_cnt(tGATT_TCB *p_tcb, tGATT_IF gatt_if, bool    is_inc, bool    is_reset_first)
+{
+    uint8_t idx = ((uint8_t) gatt_if) - 1 ;
+
+    GATT_TRACE_DEBUG("gatt_sr_update_prep_cnt tcb idx=%d gatt_if=%d is_inc=%d is_reset_first=%d",
+                      p_tcb->tcb_idx, gatt_if, is_inc, is_reset_first);
+
+    if (p_tcb)
+    {
+        if (is_reset_first)
+        {
+            gatt_sr_reset_prep_cnt(p_tcb);
+        }
+        if (is_inc)
+        {
+            p_tcb->prep_cnt[idx]++;
+        }
+        else
+        {
+            if (p_tcb->prep_cnt[idx])
+            {
+                p_tcb->prep_cnt[idx]--;
+            }
+        }
+    }
+}
+/*******************************************************************************
+**
+** Function         gatt_cancel_open
+**
+** Description      Cancel open request
+**
+** Returns         Boolean
+**
+*******************************************************************************/
+bool    gatt_cancel_open(tGATT_IF gatt_if, BD_ADDR bda)
+{
+    tGATT_TCB *p_tcb=NULL;
+    bool    status= true;
+
+    p_tcb = gatt_find_tcb_by_addr(bda, BT_TRANSPORT_LE);
+
+    if (p_tcb)
+    {
+        if (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN)
+        {
+            GATT_TRACE_ERROR("GATT_CancelConnect - link connected Too late to cancel");
+            status = false;
+        }
+        else
+        {
+            gatt_update_app_use_link_flag(gatt_if, p_tcb, false, false);
+            if (!gatt_num_apps_hold_link(p_tcb))
+            {
+                gatt_disconnect(p_tcb);
+            }
+        }
+    }
+
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_find_app_hold_link
+**
+** Description      find the applicaiton that is holding the specified link
+**
+** Returns         Boolean
+**
+*******************************************************************************/
+bool    gatt_find_app_hold_link(tGATT_TCB *p_tcb, uint8_t start_idx, uint8_t *p_found_idx, tGATT_IF *p_gatt_if)
+{
+    uint8_t i;
+    bool    found= false;
+
+    for (i = start_idx; i < GATT_MAX_APPS; i ++)
+    {
+        if (p_tcb->app_hold_link[i])
+        {
+            *p_gatt_if = gatt_cb.clcb[i].p_reg->gatt_if;
+            *p_found_idx = i;
+            found = true;
+            break;
+        }
+    }
+    return found;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_cmd_enq
+**
+** Description      Enqueue this command.
+**
+** Returns          None.
+**
+*******************************************************************************/
+bool    gatt_cmd_enq(tGATT_TCB *p_tcb, uint16_t clcb_idx, bool    to_send, uint8_t op_code, BT_HDR *p_buf)
+{
+    tGATT_CMD_Q  *p_cmd = &p_tcb->cl_cmd_q[p_tcb->next_slot_inq];
+
+    p_cmd->to_send = to_send; /* waiting to be sent */
+    p_cmd->op_code  = op_code;
+    p_cmd->p_cmd    = p_buf;
+    p_cmd->clcb_idx = clcb_idx;
+
+    if (!to_send)
+    {
+        p_tcb->pending_cl_req = p_tcb->next_slot_inq;
+    }
+
+    p_tcb->next_slot_inq ++;
+    p_tcb->next_slot_inq %= GATT_CL_MAX_LCB;
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_cmd_dequeue
+**
+** Description      dequeue the command in the client CCB command queue.
+**
+** Returns          total number of clcb found.
+**
+*******************************************************************************/
+tGATT_CLCB * gatt_cmd_dequeue(tGATT_TCB *p_tcb, uint8_t *p_op_code)
+{
+    tGATT_CMD_Q  *p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
+    tGATT_CLCB *p_clcb = NULL;
+
+    if (p_tcb->pending_cl_req != p_tcb->next_slot_inq)
+    {
+        p_clcb = &gatt_cb.clcb[p_cmd->clcb_idx];
+
+        *p_op_code = p_cmd->op_code;
+
+        p_tcb->pending_cl_req ++;
+        p_tcb->pending_cl_req %= GATT_CL_MAX_LCB;
+    }
+
+    return p_clcb;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_send_write_msg
+**
+** Description      This real function send out the ATT message for write.
+**
+** Returns          status code
+**
+*******************************************************************************/
+uint8_t gatt_send_write_msg (tGATT_TCB *p_tcb, uint16_t clcb_idx, uint8_t op_code,
+                           uint16_t handle, uint16_t len,
+                           uint16_t offset, uint8_t *p_data)
+{
+    tGATT_CL_MSG     msg;
+
+    msg.attr_value.handle = handle;
+    msg.attr_value.len = len;
+    msg.attr_value.offset = offset;
+
+    memcpy (msg.attr_value.value, p_data, len);
+
+    /* write by handle */
+    return attp_send_cl_msg(p_tcb, clcb_idx, op_code, &msg);
+}
+
+/*******************************************************************************
+**
+** Function         gatt_act_send_browse
+**
+** Description      This function ends a browse command request, including read
+**                  information request and read by type request.
+**
+** Returns          status code
+**
+*******************************************************************************/
+uint8_t gatt_act_send_browse(tGATT_TCB *p_tcb, uint16_t index, uint8_t op, uint16_t s_handle,
+                           uint16_t e_handle, tBT_UUID uuid)
+{
+    tGATT_CL_MSG     msg;
+
+    msg.browse.s_handle = s_handle;
+    msg.browse.e_handle   = e_handle;
+    memcpy(&msg.browse.uuid, &uuid, sizeof(tBT_UUID));
+
+    /* write by handle */
+    return attp_send_cl_msg(p_tcb, index, op, &msg);
+}
+
+/*******************************************************************************
+**
+** Function         gatt_end_operation
+**
+** Description      This function ends a discovery, send callback and finalize
+**                  some control value.
+**
+** Returns          16 bits uuid.
+**
+*******************************************************************************/
+void gatt_end_operation(tGATT_CLCB *p_clcb, tGATT_STATUS status, void *p_data)
+{
+    tGATT_CL_COMPLETE   cb_data;
+    tGATT_CMPL_CBACK    *p_cmpl_cb = (p_clcb->p_reg) ? p_clcb->p_reg->app_cb.p_cmpl_cb : NULL;
+    uint8_t             op = p_clcb->operation, disc_type=GATT_DISC_MAX;
+    tGATT_DISC_CMPL_CB  *p_disc_cmpl_cb = (p_clcb->p_reg) ? p_clcb->p_reg->app_cb.p_disc_cmpl_cb : NULL;
+    uint16_t            conn_id;
+    uint8_t             operation;
+
+    GATT_TRACE_DEBUG ("gatt_end_operation status=%d op=%d subtype=%d",
+                       status, p_clcb->operation, p_clcb->op_subtype);
+    memset(&cb_data.att_value, 0, sizeof(tGATT_VALUE));
+
+    if (p_cmpl_cb != NULL && p_clcb->operation != 0)
+    {
+        if (p_clcb->operation == GATTC_OPTYPE_READ)
+        {
+            cb_data.att_value.handle   = p_clcb->s_handle;
+            cb_data.att_value.len      = p_clcb->counter;
+
+            if (p_data && p_clcb->counter)
+                memcpy (cb_data.att_value.value, p_data, cb_data.att_value.len);
+        }
+
+        if (p_clcb->operation == GATTC_OPTYPE_WRITE)
+        {
+            memset(&cb_data.att_value, 0, sizeof(tGATT_VALUE));
+            cb_data.handle           =
+            cb_data.att_value.handle = p_clcb->s_handle;
+            if (p_clcb->op_subtype == GATT_WRITE_PREPARE)
+            {
+                if (p_data)
+                {
+                    cb_data.att_value = *((tGATT_VALUE *) p_data);
+                }
+                else
+                {
+                    GATT_TRACE_DEBUG("Rcv Prepare write rsp but no data");
+                }
+            }
+        }
+
+        if (p_clcb->operation == GATTC_OPTYPE_CONFIG)
+            cb_data.mtu = p_clcb->p_tcb->payload_size;
+
+        if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY)
+        {
+            disc_type = p_clcb->op_subtype;
+        }
+    }
+
+    osi_free_and_reset((void **)&p_clcb->p_attr_buf);
+
+    operation =  p_clcb->operation;
+    conn_id = p_clcb->conn_id;
+    alarm_cancel(p_clcb->gatt_rsp_timer_ent);
+
+    gatt_clcb_dealloc(p_clcb);
+
+    if (p_disc_cmpl_cb && (op == GATTC_OPTYPE_DISCOVERY))
+        (*p_disc_cmpl_cb)(conn_id, disc_type, status);
+    else if (p_cmpl_cb && op)
+        (*p_cmpl_cb)(conn_id, op, status, &cb_data);
+    else
+        GATT_TRACE_WARNING ("gatt_end_operation not sent out op=%d p_disc_cmpl_cb:%p p_cmpl_cb:%p",
+                             operation, p_disc_cmpl_cb, p_cmpl_cb);
+}
+
+/*******************************************************************************
+**
+** Function         gatt_cleanup_upon_disc
+**
+** Description      This function cleans up the control blocks when L2CAP channel
+**                  disconnect.
+**
+** Returns          16 bits uuid.
+**
+*******************************************************************************/
+void gatt_cleanup_upon_disc(BD_ADDR bda, uint16_t reason, tBT_TRANSPORT transport)
+{
+    tGATT_TCB       *p_tcb = NULL;
+    tGATT_CLCB      *p_clcb;
+    uint8_t         i;
+    uint16_t        conn_id;
+    tGATT_REG        *p_reg=NULL;
+
+
+    GATT_TRACE_DEBUG ("gatt_cleanup_upon_disc ");
+
+    if ((p_tcb = gatt_find_tcb_by_addr(bda, transport)) != NULL)
+    {
+        GATT_TRACE_DEBUG ("found p_tcb ");
+        gatt_set_ch_state(p_tcb, GATT_CH_CLOSE);
+        for (i = 0; i < GATT_CL_MAX_LCB; i ++)
+        {
+            p_clcb = &gatt_cb.clcb[i];
+            if (p_clcb->in_use && p_clcb->p_tcb == p_tcb)
+            {
+                alarm_cancel(p_clcb->gatt_rsp_timer_ent);
+                GATT_TRACE_DEBUG ("found p_clcb conn_id=%d clcb_idx=%d", p_clcb->conn_id, p_clcb->clcb_idx);
+                if (p_clcb->operation != GATTC_OPTYPE_NONE)
+                    gatt_end_operation(p_clcb, GATT_ERROR, NULL);
+
+                gatt_clcb_dealloc(p_clcb);
+
+            }
+        }
+
+        alarm_free(p_tcb->ind_ack_timer);
+        p_tcb->ind_ack_timer = NULL;
+        alarm_free(p_tcb->conf_timer);
+        p_tcb->conf_timer = NULL;
+        gatt_free_pending_ind(p_tcb);
+        gatt_free_pending_enc_queue(p_tcb);
+        fixed_queue_free(p_tcb->sr_cmd.multi_rsp_q, NULL);
+        p_tcb->sr_cmd.multi_rsp_q = NULL;
+
+        for (i = 0; i < GATT_MAX_APPS; i ++)
+        {
+            p_reg = &gatt_cb.cl_rcb[i];
+            if (p_reg->in_use && p_reg->app_cb.p_conn_cb)
+            {
+                conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
+                GATT_TRACE_DEBUG ("found p_reg tcb_idx=%d gatt_if=%d  conn_id=0x%x", p_tcb->tcb_idx, p_reg->gatt_if, conn_id);
+                (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if,  bda, conn_id, false, reason, transport);
+            }
+        }
+        memset(p_tcb, 0, sizeof(tGATT_TCB));
+
+    }
+    GATT_TRACE_DEBUG ("exit gatt_cleanup_upon_disc ");
+}
+/*******************************************************************************
+**
+** Function         gatt_dbg_req_op_name
+**
+** Description      Get op code description name, for debug information.
+**
+** Returns          uint8_t *: name of the operation.
+**
+*******************************************************************************/
+uint8_t * gatt_dbg_op_name(uint8_t op_code)
+{
+    uint8_t pseduo_op_code_idx = op_code & (~GATT_WRITE_CMD_MASK);
+
+    if (op_code == GATT_CMD_WRITE )
+    {
+        pseduo_op_code_idx = 0x14; /* just an index to op_code_name */
+
+    }
+
+    if (op_code == GATT_SIGN_CMD_WRITE)
+    {
+        pseduo_op_code_idx = 0x15; /* just an index to op_code_name */
+    }
+
+    if (pseduo_op_code_idx <= GATT_OP_CODE_MAX)
+        return(uint8_t*) op_code_name[pseduo_op_code_idx];
+    else
+        return(uint8_t *)"Op Code Exceed Max";
+}
+
+/*******************************************************************************
+**
+** Function         gatt_dbg_display_uuid
+**
+** Description      Disaplay the UUID
+**
+** Returns          None
+**
+*******************************************************************************/
+void gatt_dbg_display_uuid(tBT_UUID bt_uuid)
+{
+    char str_buf[50];
+
+    if (bt_uuid.len == LEN_UUID_16)
+    {
+        snprintf(str_buf, sizeof(str_buf), "0x%04x", bt_uuid.uu.uuid16);
+    }
+    else if (bt_uuid.len == LEN_UUID_32)
+    {
+        snprintf(str_buf, sizeof(str_buf), "0x%08x", (unsigned int)bt_uuid.uu.uuid32);
+    }
+    else if (bt_uuid.len == LEN_UUID_128)
+    {
+        int x = snprintf(str_buf, sizeof(str_buf),
+                      "0x%02x%02x%02x%02x%02x%02x%02x%02x",
+                      bt_uuid.uu.uuid128[15], bt_uuid.uu.uuid128[14],
+                      bt_uuid.uu.uuid128[13], bt_uuid.uu.uuid128[12],
+                      bt_uuid.uu.uuid128[11], bt_uuid.uu.uuid128[10],
+                      bt_uuid.uu.uuid128[9], bt_uuid.uu.uuid128[8]);
+        snprintf(&str_buf[x], sizeof(str_buf) - x,
+                 "%02x%02x%02x%02x%02x%02x%02x%02x",
+                 bt_uuid.uu.uuid128[7], bt_uuid.uu.uuid128[6],
+                 bt_uuid.uu.uuid128[5], bt_uuid.uu.uuid128[4],
+                 bt_uuid.uu.uuid128[3], bt_uuid.uu.uuid128[2],
+                 bt_uuid.uu.uuid128[1], bt_uuid.uu.uuid128[0]);
+    }
+    else
+        strlcpy(str_buf, "Unknown UUID 0", sizeof(str_buf));
+
+    GATT_TRACE_DEBUG ("UUID=[%s]", str_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         gatt_is_bg_dev_for_app
+**
+** Description      find is this one of the background devices for the application
+**
+** Returns          true this is one of the background devices for the  application
+**
+*******************************************************************************/
+bool    gatt_is_bg_dev_for_app(tGATT_BG_CONN_DEV *p_dev, tGATT_IF gatt_if)
+{
+    uint8_t i;
+
+    for (i = 0; i < GATT_MAX_APPS; i ++ )
+    {
+        if (p_dev->in_use && (p_dev->gatt_if[i] == gatt_if))
+        {
+            return true;
+        }
+    }
+    return false;
+}
+/*******************************************************************************
+**
+** Function         gatt_find_bg_dev
+**
+** Description      find background connection device from the list.
+**
+** Returns          pointer to the device record
+**
+*******************************************************************************/
+tGATT_BG_CONN_DEV * gatt_find_bg_dev(BD_ADDR remote_bda)
+{
+    tGATT_BG_CONN_DEV    *p_dev_list = &gatt_cb.bgconn_dev[0];
+    uint8_t i;
+
+    for (i = 0; i < GATT_MAX_BG_CONN_DEV; i ++, p_dev_list ++)
+    {
+        if (p_dev_list->in_use && !memcmp(p_dev_list->remote_bda, remote_bda, BD_ADDR_LEN))
+        {
+            return p_dev_list;
+        }
+    }
+    return NULL;
+}
+/*******************************************************************************
+**
+** Function         gatt_alloc_bg_dev
+**
+** Description      allocate a background connection device record
+**
+** Returns          pointer to the device record
+**
+*******************************************************************************/
+tGATT_BG_CONN_DEV * gatt_alloc_bg_dev(BD_ADDR remote_bda)
+{
+    tGATT_BG_CONN_DEV    *p_dev_list = &gatt_cb.bgconn_dev[0];
+    uint8_t i;
+
+    for (i = 0; i < GATT_MAX_BG_CONN_DEV; i ++, p_dev_list ++)
+    {
+        if (!p_dev_list->in_use)
+        {
+            p_dev_list->in_use = true;
+            memcpy(p_dev_list->remote_bda, remote_bda, BD_ADDR_LEN);
+
+            return p_dev_list;
+        }
+    }
+    return NULL;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_add_bg_dev_list
+**
+** Description      add/remove device from the back ground connection device list
+**
+** Returns          true if device added to the list; false failed
+**
+*******************************************************************************/
+bool    gatt_add_bg_dev_list(tGATT_REG *p_reg,  BD_ADDR bd_addr)
+{
+    tGATT_IF gatt_if =  p_reg->gatt_if;
+    tGATT_BG_CONN_DEV   *p_dev = NULL;
+    uint8_t     i;
+    bool         ret = false;
+
+    if ((p_dev = gatt_find_bg_dev(bd_addr)) == NULL)
+    {
+        p_dev = gatt_alloc_bg_dev(bd_addr);
+    }
+
+    if (p_dev)
+    {
+        for (i = 0; i < GATT_MAX_APPS; i ++)
+        {
+            if (p_dev->gatt_if[i] == gatt_if)
+            {
+                GATT_TRACE_ERROR("device already in iniator white list");
+                return true;
+            }
+            else if (p_dev->gatt_if[i] == 0)
+            {
+                p_dev->gatt_if[i] = gatt_if;
+                if (i == 0)
+                    ret = BTM_BleUpdateBgConnDev(true, bd_addr);
+                else
+                    ret = true;
+                break;
+            }
+        }
+    }
+    else
+    {
+        GATT_TRACE_ERROR("no device record available");
+    }
+
+    return ret;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_remove_bg_dev_for_app
+**
+** Description      Remove the application interface for the specified background device
+**
+** Returns          Boolean
+**
+*******************************************************************************/
+bool    gatt_remove_bg_dev_for_app(tGATT_IF gatt_if, BD_ADDR bd_addr)
+{
+    tGATT_TCB    *p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
+    bool          status;
+
+    if (p_tcb)
+        gatt_update_app_use_link_flag(gatt_if, p_tcb, false, false);
+    status = gatt_update_auto_connect_dev(gatt_if, false, bd_addr);
+    return status;
+}
+
+
+/*******************************************************************************
+**
+** Function         gatt_get_num_apps_for_bg_dev
+**
+** Description      Gte the number of applciations for the specified background device
+**
+** Returns          uint8_t total number fo applications
+**
+*******************************************************************************/
+uint8_t gatt_get_num_apps_for_bg_dev(BD_ADDR bd_addr)
+{
+    tGATT_BG_CONN_DEV   *p_dev = NULL;
+    uint8_t i;
+    uint8_t cnt = 0;
+
+    if ((p_dev = gatt_find_bg_dev(bd_addr)) != NULL)
+    {
+        for (i = 0; i < GATT_MAX_APPS; i ++)
+        {
+            if (p_dev->gatt_if[i])
+                cnt++;
+        }
+    }
+    return cnt;
+}
+
+/*******************************************************************************
+**
+** Function         gatt_find_app_for_bg_dev
+**
+** Description      find the application interface for the specified background device
+**
+** Returns          Boolean
+**
+*******************************************************************************/
+bool    gatt_find_app_for_bg_dev(BD_ADDR bd_addr, tGATT_IF *p_gatt_if)
+{
+    tGATT_BG_CONN_DEV   *p_dev = NULL;
+    uint8_t i;
+    bool    ret = false;
+
+    if ((p_dev = gatt_find_bg_dev(bd_addr)) == NULL)
+    {
+        return ret;
+    }
+
+    for (i = 0; i < GATT_MAX_APPS; i ++)
+    {
+        if (p_dev->gatt_if[i] != 0 )
+        {
+            *p_gatt_if = p_dev->gatt_if[i];
+            ret = true;
+            break;
+        }
+    }
+    return ret;
+}
+
+
+/*******************************************************************************
+**
+** Function         gatt_remove_bg_dev_from_list
+**
+** Description      add/remove device from the back ground connection device list or
+**                  listening to advertising list.
+**
+** Returns          pointer to the device record
+**
+*******************************************************************************/
+bool    gatt_remove_bg_dev_from_list(tGATT_REG *p_reg, BD_ADDR bd_addr)
+{
+    tGATT_IF gatt_if = p_reg->gatt_if;
+    tGATT_BG_CONN_DEV   *p_dev = NULL;
+    uint8_t i, j;
+    bool    ret = false;
+
+    if ((p_dev = gatt_find_bg_dev(bd_addr)) == NULL)
+    {
+        return ret;
+    }
+
+    for (i = 0; i < GATT_MAX_APPS && (p_dev->gatt_if[i] > 0); i ++)
+    {
+        if (p_dev->gatt_if[i] == gatt_if)
+        {
+            p_dev->gatt_if[i] = 0;
+            /* move all element behind one forward */
+            for (j = i + 1; j < GATT_MAX_APPS; j ++)
+                p_dev->gatt_if[j - 1] = p_dev->gatt_if[j];
+
+            if (p_dev->gatt_if[0] == 0)
+                ret = BTM_BleUpdateBgConnDev(false, p_dev->remote_bda);
+            else
+                ret = true;
+
+            break;
+        }
+    }
+
+    if (i != GATT_MAX_APPS && p_dev->gatt_if[0] == 0)
+    {
+        memset(p_dev, 0, sizeof(tGATT_BG_CONN_DEV));
+    }
+
+    return ret;
+}
+/*******************************************************************************
+**
+** Function         gatt_deregister_bgdev_list
+**
+** Description      deregister all related back ground connetion device.
+**
+** Returns          pointer to the device record
+**
+*******************************************************************************/
+void gatt_deregister_bgdev_list(tGATT_IF gatt_if)
+{
+    tGATT_BG_CONN_DEV    *p_dev_list = &gatt_cb.bgconn_dev[0];
+    uint8_t i , j, k;
+
+    /* update the BG conn device list */
+    for (i = 0 ; i <GATT_MAX_BG_CONN_DEV; i ++, p_dev_list ++ )
+    {
+        if (p_dev_list->in_use)
+        {
+            for (j = 0; j < GATT_MAX_APPS; j ++)
+            {
+                if (p_dev_list->gatt_if[j] == 0)
+                    break;
+
+                if (p_dev_list->gatt_if[j] == gatt_if)
+                {
+                    for (k = j + 1; k < GATT_MAX_APPS; k ++)
+                        p_dev_list->gatt_if[k - 1] = p_dev_list->gatt_if[k];
+
+                    if (p_dev_list->gatt_if[0] == 0)
+                        BTM_BleUpdateBgConnDev(false, p_dev_list->remote_bda);
+                }
+            }
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         gatt_reset_bgdev_list
+**
+** Description      reset bg device list
+**
+** Returns          pointer to the device record
+**
+*******************************************************************************/
+void gatt_reset_bgdev_list(void)
+{
+    memset(&gatt_cb.bgconn_dev, 0 , sizeof(tGATT_BG_CONN_DEV)*GATT_MAX_BG_CONN_DEV);
+
+}
+/*******************************************************************************
+**
+** Function         gatt_update_auto_connect_dev
+**
+** Description      This function add or remove a device for background connection
+**                  procedure.
+**
+** Parameters       gatt_if: Application ID.
+**                  add: add peer device
+**                  bd_addr: peer device address.
+**
+** Returns          true if connection started; false if connection start failure.
+**
+*******************************************************************************/
+bool    gatt_update_auto_connect_dev (tGATT_IF gatt_if, bool    add, BD_ADDR bd_addr)
+{
+    bool            ret = false;
+    tGATT_REG        *p_reg;
+    tGATT_TCB       *p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
+
+    GATT_TRACE_API ("gatt_update_auto_connect_dev ");
+    /* Make sure app is registered */
+    if ((p_reg = gatt_get_regcb(gatt_if)) == NULL)
+    {
+        GATT_TRACE_ERROR("gatt_update_auto_connect_dev - gatt_if is not registered", gatt_if);
+        return(false);
+    }
+
+    if (add)
+    {
+        ret = gatt_add_bg_dev_list(p_reg, bd_addr);
+
+        if (ret && p_tcb != NULL)
+        {
+            /* if a connected device, update the link holding number */
+            gatt_update_app_use_link_flag(gatt_if, p_tcb, true, true);
+        }
+    }
+    else
+    {
+        ret = gatt_remove_bg_dev_from_list(p_reg, bd_addr);
+    }
+    return ret;
+}
+
+
+
+/*******************************************************************************
+**
+** Function     gatt_add_pending_new_srv_start
+**
+** Description  Add a pending new srv start to the new service start queue
+**
+** Returns    Pointer to the new service start buffer, NULL no buffer available
+**
+*******************************************************************************/
+tGATT_PENDING_ENC_CLCB* gatt_add_pending_enc_channel_clcb(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb)
+{
+    tGATT_PENDING_ENC_CLCB *p_buf =
+        (tGATT_PENDING_ENC_CLCB *)osi_malloc(sizeof(tGATT_PENDING_ENC_CLCB));
+
+    GATT_TRACE_DEBUG ("%s", __func__);
+    GATT_TRACE_DEBUG("enqueue a new pending encryption channel clcb");
+
+    p_buf->p_clcb = p_clcb;
+    fixed_queue_enqueue(p_tcb->pending_enc_clcb, p_buf);
+
+    return p_buf;
+}
+/*******************************************************************************
+**
+** Function     gatt_update_listen_mode
+**
+** Description  update peripheral role listening mode
+**
+** Returns    Pointer to the new service start buffer, NULL no buffer available
+**
+*******************************************************************************/
+void gatt_update_listen_mode(int listening)
+{
+    uint16_t        connectability, window, interval;
+
+    connectability = BTM_ReadConnectability(&window, &interval);
+
+    if (listening != GATT_LISTEN_TO_NONE)
+    {
+        connectability |= BTM_BLE_CONNECTABLE;
+    }
+    else
+    {
+        if ((connectability & BTM_BLE_CONNECTABLE) == 0)
+        connectability &= ~BTM_BLE_CONNECTABLE;
+    }
+    /* turning on the adv now */
+    btm_ble_set_connectability(connectability);
+}
+#endif
+
+
diff --git a/bt/stack/hcic/hciblecmds.cc b/bt/stack/hcic/hciblecmds.cc
new file mode 100644
index 0000000..49978e0
--- /dev/null
+++ b/bt/stack/hcic/hciblecmds.cc
@@ -0,0 +1,733 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 function of the HCIC unit to format and send HCI
+ *  commands.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+#include "bt_common.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "hcidefs.h"
+#include "btu.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#if (BLE_INCLUDED == TRUE)
+
+void btsnd_hcic_ble_set_local_used_feat (uint8_t feat_set[8])
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_USED_FEAT_CMD;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_WRITE_LOCAL_SPT_FEAT);
+    ARRAY_TO_STREAM (pp, feat_set, HCIC_PARAM_SIZE_SET_USED_FEAT_CMD);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_ble_set_random_addr (BD_ADDR random_bda)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_WRITE_RANDOM_ADDR);
+    UINT8_TO_STREAM  (pp,  HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD);
+
+    BDADDR_TO_STREAM (pp, random_bda);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_ble_write_adv_params (uint16_t adv_int_min, uint16_t adv_int_max,
+                                       uint8_t adv_type, uint8_t addr_type_own,
+                                       uint8_t addr_type_dir, BD_ADDR direct_bda,
+                                       uint8_t channel_map, uint8_t adv_filter_policy)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS ;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_WRITE_ADV_PARAMS);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS );
+
+    UINT16_TO_STREAM (pp, adv_int_min);
+    UINT16_TO_STREAM (pp, adv_int_max);
+    UINT8_TO_STREAM (pp, adv_type);
+    UINT8_TO_STREAM (pp, addr_type_own);
+    UINT8_TO_STREAM (pp, addr_type_dir);
+    BDADDR_TO_STREAM (pp, direct_bda);
+    UINT8_TO_STREAM (pp, channel_map);
+    UINT8_TO_STREAM (pp, adv_filter_policy);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+void btsnd_hcic_ble_read_adv_chnl_tx_power (void)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_READ_ADV_CHNL_TX_POWER);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+
+}
+
+void btsnd_hcic_ble_set_adv_data (uint8_t data_len, uint8_t *p_data)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_WRITE_ADV_DATA);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1);
+
+    memset(pp, 0, HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA);
+
+    if (p_data != NULL && data_len > 0)
+    {
+        if (data_len > HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA)
+            data_len = HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA;
+
+        UINT8_TO_STREAM (pp, data_len);
+
+        ARRAY_TO_STREAM (pp, p_data, data_len);
+    }
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+
+}
+void btsnd_hcic_ble_set_scan_rsp_data (uint8_t data_len, uint8_t *p_scan_rsp)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP + 1;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_WRITE_SCAN_RSP_DATA);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP + 1);
+
+    memset(pp, 0, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP);
+
+    if (p_scan_rsp != NULL && data_len > 0)
+    {
+
+        if (data_len > HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP )
+            data_len = HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP;
+
+        UINT8_TO_STREAM (pp, data_len);
+
+        ARRAY_TO_STREAM (pp, p_scan_rsp, data_len);
+    }
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+
+}
+
+void btsnd_hcic_ble_set_adv_enable (uint8_t adv_enable)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_ADV_ENABLE;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_WRITE_ADV_ENABLE);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_WRITE_ADV_ENABLE);
+
+    UINT8_TO_STREAM (pp, adv_enable);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+void btsnd_hcic_ble_set_scan_params (uint8_t scan_type,
+                                          uint16_t scan_int, uint16_t scan_win,
+                                          uint8_t addr_type_own, uint8_t scan_filter_policy)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_SCAN_PARAM;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_WRITE_SCAN_PARAMS);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_PARAM);
+
+    UINT8_TO_STREAM (pp, scan_type);
+    UINT16_TO_STREAM (pp, scan_int);
+    UINT16_TO_STREAM (pp, scan_win);
+    UINT8_TO_STREAM (pp, addr_type_own);
+    UINT8_TO_STREAM (pp, scan_filter_policy);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_ble_set_scan_enable (uint8_t scan_enable, uint8_t duplicate)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_WRITE_SCAN_ENABLE);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE);
+
+    UINT8_TO_STREAM (pp, scan_enable);
+    UINT8_TO_STREAM (pp, duplicate);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+/* link layer connection management commands */
+void btsnd_hcic_ble_create_ll_conn (uint16_t scan_int, uint16_t scan_win,
+                                       uint8_t init_filter_policy,
+                                       uint8_t addr_type_peer, BD_ADDR bda_peer,
+                                       uint8_t addr_type_own,
+                                       uint16_t conn_int_min, uint16_t conn_int_max,
+                                       uint16_t conn_latency, uint16_t conn_timeout,
+                                       uint16_t min_ce_len, uint16_t max_ce_len)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_CREATE_LL_CONN;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_CREATE_LL_CONN);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_BLE_CREATE_LL_CONN);
+
+    UINT16_TO_STREAM (pp, scan_int);
+    UINT16_TO_STREAM (pp, scan_win);
+    UINT8_TO_STREAM (pp, init_filter_policy);
+
+    UINT8_TO_STREAM (pp, addr_type_peer);
+    BDADDR_TO_STREAM (pp, bda_peer);
+    UINT8_TO_STREAM (pp, addr_type_own);
+
+    UINT16_TO_STREAM (pp, conn_int_min);
+    UINT16_TO_STREAM (pp, conn_int_max);
+    UINT16_TO_STREAM (pp, conn_latency);
+    UINT16_TO_STREAM (pp, conn_timeout);
+
+    UINT16_TO_STREAM (pp, min_ce_len);
+    UINT16_TO_STREAM (pp, max_ce_len);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_ble_create_conn_cancel (void)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_CREATE_CONN_CANCEL;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_CREATE_CONN_CANCEL);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_BLE_CREATE_CONN_CANCEL);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_ble_clear_white_list (void)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CLEAR_WHITE_LIST;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_CLEAR_WHITE_LIST);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_CLEAR_WHITE_LIST);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_ble_add_white_list (uint8_t addr_type, BD_ADDR bda)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ADD_WHITE_LIST;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_ADD_WHITE_LIST);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_ADD_WHITE_LIST);
+
+    UINT8_TO_STREAM (pp, addr_type);
+    BDADDR_TO_STREAM (pp, bda);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_ble_remove_from_white_list (uint8_t addr_type, BD_ADDR bda)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_REMOVE_WHITE_LIST;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_REMOVE_WHITE_LIST);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_REMOVE_WHITE_LIST);
+
+    UINT8_TO_STREAM (pp, addr_type);
+    BDADDR_TO_STREAM (pp, bda);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_ble_upd_ll_conn_params (uint16_t handle,
+                                           uint16_t conn_int_min, uint16_t conn_int_max,
+                                           uint16_t conn_latency, uint16_t conn_timeout,
+                                           uint16_t min_ce_len, uint16_t max_ce_len)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_UPD_LL_CONN_PARAMS;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_UPD_LL_CONN_PARAMS);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_BLE_UPD_LL_CONN_PARAMS);
+
+    UINT16_TO_STREAM (pp, handle);
+
+    UINT16_TO_STREAM (pp, conn_int_min);
+    UINT16_TO_STREAM (pp, conn_int_max);
+    UINT16_TO_STREAM (pp, conn_latency);
+    UINT16_TO_STREAM (pp, conn_timeout);
+    UINT16_TO_STREAM (pp, min_ce_len);
+    UINT16_TO_STREAM (pp, max_ce_len);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_ble_set_host_chnl_class (uint8_t chnl_map[HCIC_BLE_CHNL_MAP_SIZE])
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_HOST_CHNL_CLASS;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_SET_HOST_CHNL_CLASS);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_SET_HOST_CHNL_CLASS);
+
+    ARRAY_TO_STREAM (pp, chnl_map, HCIC_BLE_CHNL_MAP_SIZE);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_ble_read_chnl_map (uint16_t handle)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CHNL_MAP;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_READ_CHNL_MAP);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_READ_CHNL_MAP);
+
+    UINT16_TO_STREAM (pp, handle);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_ble_read_remote_feat (uint16_t handle)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_READ_REMOTE_FEAT;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_READ_REMOTE_FEAT);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_BLE_READ_REMOTE_FEAT);
+
+    UINT16_TO_STREAM (pp, handle);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+/* security management commands */
+void btsnd_hcic_ble_encrypt (uint8_t *key, uint8_t key_len,
+                                uint8_t *plain_text, uint8_t pt_len,
+                                void *p_cmd_cplt_cback)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_ENCRYPT;
+    p->offset = sizeof(void *);
+
+    *((void **)pp) = p_cmd_cplt_cback;  /* Store command complete callback in buffer */
+    pp += sizeof(void *);               /* Skip over callback pointer */
+
+
+    UINT16_TO_STREAM (pp, HCI_BLE_ENCRYPT);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_BLE_ENCRYPT);
+
+    memset(pp, 0, HCIC_PARAM_SIZE_BLE_ENCRYPT);
+
+    if (key_len > HCIC_BLE_ENCRYT_KEY_SIZE) key_len = HCIC_BLE_ENCRYT_KEY_SIZE;
+    if (pt_len > HCIC_BLE_ENCRYT_KEY_SIZE) pt_len = HCIC_BLE_ENCRYT_KEY_SIZE;
+
+    ARRAY_TO_STREAM (pp, key, key_len);
+    pp += (HCIC_BLE_ENCRYT_KEY_SIZE - key_len);
+    ARRAY_TO_STREAM (pp, plain_text, pt_len);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_ble_rand (void *p_cmd_cplt_cback)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_RAND;
+    p->offset = sizeof(void *);
+
+    *((void **)pp) = p_cmd_cplt_cback;  /* Store command complete callback in buffer */
+    pp += sizeof(void *);               /* Skip over callback pointer */
+
+    UINT16_TO_STREAM (pp, HCI_BLE_RAND);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_BLE_RAND);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_ble_start_enc (uint16_t handle, uint8_t rand[HCIC_BLE_RAND_DI_SIZE],
+                                uint16_t ediv, uint8_t ltk[HCIC_BLE_ENCRYT_KEY_SIZE])
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_START_ENC;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_START_ENC);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_BLE_START_ENC);
+
+    UINT16_TO_STREAM (pp, handle);
+    ARRAY_TO_STREAM (pp, rand, HCIC_BLE_RAND_DI_SIZE);
+    UINT16_TO_STREAM (pp, ediv);
+    ARRAY_TO_STREAM (pp, ltk, HCIC_BLE_ENCRYT_KEY_SIZE);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_ble_ltk_req_reply (uint16_t handle, uint8_t ltk[HCIC_BLE_ENCRYT_KEY_SIZE])
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_LTK_REQ_REPLY;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_LTK_REQ_REPLY);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_LTK_REQ_REPLY);
+
+    UINT16_TO_STREAM (pp, handle);
+    ARRAY_TO_STREAM (pp, ltk, HCIC_BLE_ENCRYT_KEY_SIZE);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_ble_ltk_req_neg_reply (uint16_t handle)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_LTK_REQ_NEG_REPLY;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_LTK_REQ_NEG_REPLY);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_LTK_REQ_NEG_REPLY);
+
+    UINT16_TO_STREAM (pp, handle);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_ble_receiver_test(uint8_t rx_freq)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_RECEIVER_TEST);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+    UINT8_TO_STREAM (pp, rx_freq);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_ble_transmitter_test(uint8_t tx_freq, uint8_t test_data_len, uint8_t payload)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM3;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_TRANSMITTER_TEST);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_WRITE_PARAM3);
+
+    UINT8_TO_STREAM (pp, tx_freq);
+    UINT8_TO_STREAM (pp, test_data_len);
+    UINT8_TO_STREAM (pp, payload);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_ble_test_end(void)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_TEST_END);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_ble_read_host_supported (void)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_READ_LE_HOST_SUPPORT);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_READ_CMD);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+#if (BLE_LLT_INCLUDED == TRUE)
+
+void btsnd_hcic_ble_rc_param_req_reply(  uint16_t handle,
+                                            uint16_t conn_int_min, uint16_t conn_int_max,
+                                            uint16_t conn_latency, uint16_t conn_timeout,
+                                            uint16_t min_ce_len, uint16_t max_ce_len  )
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_RC_PARAM_REQ_REPLY;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_RC_PARAM_REQ_REPLY);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_BLE_RC_PARAM_REQ_REPLY);
+
+    UINT16_TO_STREAM (pp, handle);
+    UINT16_TO_STREAM (pp, conn_int_min);
+    UINT16_TO_STREAM (pp, conn_int_max);
+    UINT16_TO_STREAM (pp, conn_latency);
+    UINT16_TO_STREAM (pp, conn_timeout);
+    UINT16_TO_STREAM (pp, min_ce_len);
+    UINT16_TO_STREAM (pp, max_ce_len);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_ble_rc_param_req_neg_reply(uint16_t handle, uint8_t reason)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_RC_PARAM_REQ_NEG_REPLY;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_RC_PARAM_REQ_NEG_REPLY);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_BLE_RC_PARAM_REQ_NEG_REPLY);
+
+    UINT16_TO_STREAM (pp, handle);
+    UINT8_TO_STREAM (pp, reason);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+#endif
+
+void btsnd_hcic_ble_add_device_resolving_list (uint8_t addr_type_peer, BD_ADDR bda_peer,
+    uint8_t irk_peer[HCIC_BLE_IRK_SIZE],
+    uint8_t irk_local[HCIC_BLE_IRK_SIZE])
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_ADD_DEV_RESOLVING_LIST;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_ADD_DEV_RESOLVING_LIST);
+    UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_ADD_DEV_RESOLVING_LIST);
+    UINT8_TO_STREAM (pp, addr_type_peer);
+    BDADDR_TO_STREAM (pp, bda_peer);
+    ARRAY_TO_STREAM (pp, irk_peer, HCIC_BLE_ENCRYT_KEY_SIZE);
+    ARRAY_TO_STREAM (pp, irk_local, HCIC_BLE_ENCRYT_KEY_SIZE);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+
+}
+
+void btsnd_hcic_ble_rm_device_resolving_list (uint8_t addr_type_peer, BD_ADDR bda_peer)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_RM_DEV_RESOLVING_LIST;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_RM_DEV_RESOLVING_LIST);
+    UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_RM_DEV_RESOLVING_LIST);
+    UINT8_TO_STREAM (pp, addr_type_peer);
+    BDADDR_TO_STREAM (pp, bda_peer);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+
+}
+
+void btsnd_hcic_ble_clear_resolving_list (void)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_CLEAR_RESOLVING_LIST;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_CLEAR_RESOLVING_LIST);
+    UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_CLEAR_RESOLVING_LIST);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+
+}
+
+void btsnd_hcic_ble_read_resolvable_addr_peer (uint8_t addr_type_peer, BD_ADDR bda_peer)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_PEER;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_READ_RESOLVABLE_ADDR_PEER);
+    UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_PEER);
+    UINT8_TO_STREAM (pp, addr_type_peer);
+    BDADDR_TO_STREAM (pp, bda_peer);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+
+}
+
+void btsnd_hcic_ble_read_resolvable_addr_local (uint8_t addr_type_peer, BD_ADDR bda_peer)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_LOCAL;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_READ_RESOLVABLE_ADDR_LOCAL);
+    UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_LOCAL);
+    UINT8_TO_STREAM (pp, addr_type_peer);
+    BDADDR_TO_STREAM (pp, bda_peer);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+
+}
+
+void btsnd_hcic_ble_set_addr_resolution_enable (uint8_t addr_resolution_enable)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_SET_ADDR_RESOLUTION_ENABLE;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_SET_ADDR_RESOLUTION_ENABLE);
+    UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_SET_ADDR_RESOLUTION_ENABLE);
+    UINT8_TO_STREAM (pp, addr_resolution_enable);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+
+}
+
+void btsnd_hcic_ble_set_rand_priv_addr_timeout (uint16_t rpa_timout)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_SET_RAND_PRIV_ADDR_TIMOUT;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_BLE_SET_RAND_PRIV_ADDR_TIMOUT);
+    UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_SET_RAND_PRIV_ADDR_TIMOUT);
+    UINT16_TO_STREAM (pp, rpa_timout);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+
+}
+
+void btsnd_hcic_ble_set_data_length(uint16_t conn_handle, uint16_t tx_octets, uint16_t tx_time)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_SET_DATA_LENGTH;
+    p->offset = 0;
+
+    UINT16_TO_STREAM(pp, HCI_BLE_SET_DATA_LENGTH);
+    UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_SET_DATA_LENGTH);
+
+    UINT16_TO_STREAM(pp, conn_handle);
+    UINT16_TO_STREAM(pp, tx_octets);
+    UINT16_TO_STREAM(pp, tx_time);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+#endif
+
diff --git a/bt/stack/hcic/hcicmds.cc b/bt/stack/hcic/hcicmds.cc
new file mode 100644
index 0000000..6d8159c
--- /dev/null
+++ b/bt/stack/hcic/hcicmds.cc
@@ -0,0 +1,1376 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 function of the HCIC unit to format and send HCI
+ *  commands.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+#include "bt_common.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "hcidefs.h"
+#include "btu.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#include "btm_int.h"    /* Included for UIPC_* macro definitions */
+
+void btsnd_hcic_inquiry(const LAP inq_lap, uint8_t duration, uint8_t response_cnt)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_INQUIRY;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_INQUIRY);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_INQUIRY);
+
+    LAP_TO_STREAM   (pp, inq_lap);
+    UINT8_TO_STREAM (pp, duration);
+    UINT8_TO_STREAM (pp, response_cnt);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_inq_cancel(void)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_INQ_CANCEL;
+    p->offset = 0;
+    UINT16_TO_STREAM (pp, HCI_INQUIRY_CANCEL);
+    UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_INQ_CANCEL);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_per_inq_mode (uint16_t max_period, uint16_t min_period,
+                                 const LAP inq_lap, uint8_t duration, uint8_t response_cnt)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_PER_INQ_MODE;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_PERIODIC_INQUIRY_MODE);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_PER_INQ_MODE);
+
+    UINT16_TO_STREAM (pp, max_period);
+    UINT16_TO_STREAM (pp, min_period);
+    LAP_TO_STREAM    (pp, inq_lap);
+    UINT8_TO_STREAM  (pp, duration);
+    UINT8_TO_STREAM  (pp, response_cnt);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_exit_per_inq (void)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_EXIT_PER_INQ;
+    p->offset = 0;
+    UINT16_TO_STREAM (pp, HCI_EXIT_PERIODIC_INQUIRY_MODE);
+    UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_EXIT_PER_INQ);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+
+void btsnd_hcic_create_conn(BD_ADDR dest, uint16_t packet_types,
+                               uint8_t page_scan_rep_mode, uint8_t page_scan_mode,
+                               uint16_t clock_offset, uint8_t allow_switch)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+#ifndef BT_10A
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CREATE_CONN;
+#else
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CREATE_CONN - 1;
+#endif
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_CREATE_CONNECTION);
+#ifndef BT_10A
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_CREATE_CONN);
+#else
+    UINT8_TO_STREAM  (pp, (HCIC_PARAM_SIZE_CREATE_CONN - 1));
+#endif
+    BDADDR_TO_STREAM (pp, dest);
+    UINT16_TO_STREAM (pp, packet_types);
+    UINT8_TO_STREAM  (pp, page_scan_rep_mode);
+    UINT8_TO_STREAM  (pp, page_scan_mode);
+    UINT16_TO_STREAM (pp, clock_offset);
+#if !defined (BT_10A)
+    UINT8_TO_STREAM  (pp, allow_switch);
+#endif
+    btm_acl_paging (p, dest);
+}
+
+void btsnd_hcic_disconnect (uint16_t handle, uint8_t reason)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_DISCONNECT;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_DISCONNECT);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_DISCONNECT);
+    UINT16_TO_STREAM (pp, handle);
+    UINT8_TO_STREAM  (pp, reason);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+#if (BTM_SCO_INCLUDED == TRUE)
+void btsnd_hcic_add_SCO_conn (uint16_t handle, uint16_t packet_types)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ADD_SCO_CONN;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_ADD_SCO_CONNECTION);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_ADD_SCO_CONN);
+
+    UINT16_TO_STREAM (pp, handle);
+    UINT16_TO_STREAM (pp, packet_types);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+#endif /* BTM_SCO_INCLUDED */
+
+void btsnd_hcic_create_conn_cancel(BD_ADDR dest)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CREATE_CONN_CANCEL;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_CREATE_CONNECTION_CANCEL);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_CREATE_CONN_CANCEL);
+
+    BDADDR_TO_STREAM (pp, dest);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_accept_conn (BD_ADDR dest, uint8_t role)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ACCEPT_CONN;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_ACCEPT_CONNECTION_REQUEST);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_ACCEPT_CONN);
+    BDADDR_TO_STREAM (pp, dest);
+    UINT8_TO_STREAM  (pp, role);
+
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_reject_conn (BD_ADDR dest, uint8_t reason)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_REJECT_CONN;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_REJECT_CONNECTION_REQUEST);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_REJECT_CONN);
+
+    BDADDR_TO_STREAM (pp, dest);
+    UINT8_TO_STREAM (pp, reason);
+
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_link_key_req_reply (BD_ADDR bd_addr, LINK_KEY link_key)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_LINK_KEY_REQ_REPLY;
+    p->offset = 0;
+
+    UINT16_TO_STREAM  (pp, HCI_LINK_KEY_REQUEST_REPLY);
+    UINT8_TO_STREAM   (pp, HCIC_PARAM_SIZE_LINK_KEY_REQ_REPLY);
+
+    BDADDR_TO_STREAM  (pp, bd_addr);
+    ARRAY16_TO_STREAM (pp, link_key);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_link_key_neg_reply (BD_ADDR bd_addr)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_LINK_KEY_NEG_REPLY;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_LINK_KEY_REQUEST_NEG_REPLY);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_LINK_KEY_NEG_REPLY);
+
+    BDADDR_TO_STREAM (pp, bd_addr);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_pin_code_req_reply (BD_ADDR bd_addr, uint8_t pin_code_len,
+                                    PIN_CODE pin_code)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+    int i;
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_PIN_CODE_REQ_REPLY;
+    p->offset = 0;
+
+    UINT16_TO_STREAM  (pp, HCI_PIN_CODE_REQUEST_REPLY);
+    UINT8_TO_STREAM   (pp, HCIC_PARAM_SIZE_PIN_CODE_REQ_REPLY);
+
+    BDADDR_TO_STREAM  (pp, bd_addr);
+    UINT8_TO_STREAM   (pp, pin_code_len);
+
+    for (i = 0; i < pin_code_len; i++)
+        *pp++ = *pin_code++;
+
+    for (; i < PIN_CODE_LEN; i++)
+        *pp++ = 0;
+
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_pin_code_neg_reply (BD_ADDR bd_addr)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_PIN_CODE_NEG_REPLY;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_PIN_CODE_REQUEST_NEG_REPLY);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_PIN_CODE_NEG_REPLY);
+
+    BDADDR_TO_STREAM (pp, bd_addr);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_change_conn_type (uint16_t handle, uint16_t packet_types)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CHANGE_CONN_TYPE;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_CHANGE_CONN_PACKET_TYPE);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_CHANGE_CONN_TYPE);
+
+    UINT16_TO_STREAM (pp, handle);
+    UINT16_TO_STREAM (pp, packet_types);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_auth_request (uint16_t handle)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_AUTHENTICATION_REQUESTED);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+    UINT16_TO_STREAM (pp, handle);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_set_conn_encrypt (uint16_t handle, bool    enable)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_CONN_ENCRYPT;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_SET_CONN_ENCRYPTION);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_SET_CONN_ENCRYPT);
+
+    UINT16_TO_STREAM (pp, handle);
+    UINT8_TO_STREAM  (pp, enable);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_rmt_name_req (BD_ADDR bd_addr, uint8_t page_scan_rep_mode,
+                                 uint8_t page_scan_mode, uint16_t clock_offset)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_RMT_NAME_REQ;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_RMT_NAME_REQUEST);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_RMT_NAME_REQ);
+
+    BDADDR_TO_STREAM (pp, bd_addr);
+    UINT8_TO_STREAM  (pp, page_scan_rep_mode);
+    UINT8_TO_STREAM  (pp, page_scan_mode);
+    UINT16_TO_STREAM (pp, clock_offset);
+
+    btm_acl_paging (p, bd_addr);
+}
+
+void btsnd_hcic_rmt_name_req_cancel (BD_ADDR bd_addr)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_RMT_NAME_REQ_CANCEL;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_RMT_NAME_REQUEST_CANCEL);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_RMT_NAME_REQ_CANCEL);
+
+    BDADDR_TO_STREAM (pp, bd_addr);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_rmt_features_req (uint16_t handle)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_READ_RMT_FEATURES);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+    UINT16_TO_STREAM (pp, handle);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_rmt_ext_features (uint16_t handle, uint8_t page_num)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_RMT_EXT_FEATURES;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_READ_RMT_EXT_FEATURES);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_RMT_EXT_FEATURES);
+
+    UINT16_TO_STREAM (pp, handle);
+    UINT8_TO_STREAM (pp, page_num);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_rmt_ver_req (uint16_t handle)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_READ_RMT_VERSION_INFO);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+    UINT16_TO_STREAM (pp, handle);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_read_rmt_clk_offset (uint16_t handle)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_READ_RMT_CLOCK_OFFSET);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+    UINT16_TO_STREAM (pp, handle);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_read_lmp_handle (uint16_t handle)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_READ_LMP_HANDLE);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+    UINT16_TO_STREAM (pp, handle);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_setup_esco_conn (uint16_t handle, uint32_t tx_bw,
+                                    uint32_t rx_bw, uint16_t max_latency, uint16_t voice,
+                                    uint8_t retrans_effort, uint16_t packet_types)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SETUP_ESCO;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_SETUP_ESCO_CONNECTION);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_SETUP_ESCO);
+
+    UINT16_TO_STREAM (pp, handle);
+    UINT32_TO_STREAM (pp, tx_bw);
+    UINT32_TO_STREAM (pp, rx_bw);
+    UINT16_TO_STREAM (pp, max_latency);
+    UINT16_TO_STREAM (pp, voice);
+    UINT8_TO_STREAM  (pp, retrans_effort);
+    UINT16_TO_STREAM (pp, packet_types);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_accept_esco_conn (BD_ADDR bd_addr, uint32_t tx_bw,
+                                     uint32_t rx_bw, uint16_t max_latency,
+                                     uint16_t content_fmt, uint8_t retrans_effort,
+                                     uint16_t packet_types)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ACCEPT_ESCO;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_ACCEPT_ESCO_CONNECTION);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_ACCEPT_ESCO);
+
+    BDADDR_TO_STREAM (pp, bd_addr);
+    UINT32_TO_STREAM (pp, tx_bw);
+    UINT32_TO_STREAM (pp, rx_bw);
+    UINT16_TO_STREAM (pp, max_latency);
+    UINT16_TO_STREAM (pp, content_fmt);
+    UINT8_TO_STREAM  (pp, retrans_effort);
+    UINT16_TO_STREAM (pp, packet_types);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_reject_esco_conn (BD_ADDR bd_addr, uint8_t reason)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_REJECT_ESCO;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_REJECT_ESCO_CONNECTION);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_REJECT_ESCO);
+
+    BDADDR_TO_STREAM (pp, bd_addr);
+    UINT8_TO_STREAM  (pp, reason);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_hold_mode (uint16_t handle, uint16_t max_hold_period,
+                              uint16_t min_hold_period)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_HOLD_MODE;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_HOLD_MODE);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_HOLD_MODE);
+
+    UINT16_TO_STREAM (pp, handle);
+    UINT16_TO_STREAM (pp, max_hold_period);
+    UINT16_TO_STREAM (pp, min_hold_period);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_sniff_mode (uint16_t handle, uint16_t max_sniff_period,
+                               uint16_t min_sniff_period, uint16_t sniff_attempt,
+                               uint16_t sniff_timeout)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SNIFF_MODE;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_SNIFF_MODE);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_SNIFF_MODE);
+
+    UINT16_TO_STREAM (pp, handle);
+    UINT16_TO_STREAM (pp, max_sniff_period);
+    UINT16_TO_STREAM (pp, min_sniff_period);
+    UINT16_TO_STREAM (pp, sniff_attempt);
+    UINT16_TO_STREAM (pp, sniff_timeout);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_exit_sniff_mode (uint16_t handle)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_EXIT_SNIFF_MODE);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+    UINT16_TO_STREAM (pp, handle);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_park_mode (uint16_t handle, uint16_t beacon_max_interval,
+                              uint16_t beacon_min_interval)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_PARK_MODE;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_PARK_MODE);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_PARK_MODE);
+
+    UINT16_TO_STREAM (pp, handle);
+    UINT16_TO_STREAM (pp, beacon_max_interval);
+    UINT16_TO_STREAM (pp, beacon_min_interval);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_exit_park_mode (uint16_t handle)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_EXIT_PARK_MODE);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+    UINT16_TO_STREAM (pp, handle);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_qos_setup (uint16_t handle, uint8_t flags, uint8_t service_type,
+                              uint32_t token_rate, uint32_t peak, uint32_t latency,
+                              uint32_t delay_var)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_QOS_SETUP;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_QOS_SETUP);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_QOS_SETUP);
+
+    UINT16_TO_STREAM (pp, handle);
+    UINT8_TO_STREAM  (pp, flags);
+    UINT8_TO_STREAM  (pp, service_type);
+    UINT32_TO_STREAM (pp, token_rate);
+    UINT32_TO_STREAM (pp, peak);
+    UINT32_TO_STREAM (pp, latency);
+    UINT32_TO_STREAM (pp, delay_var);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_switch_role (BD_ADDR bd_addr, uint8_t role)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SWITCH_ROLE;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_SWITCH_ROLE);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_SWITCH_ROLE);
+
+    BDADDR_TO_STREAM (pp, bd_addr);
+    UINT8_TO_STREAM  (pp, role);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_write_policy_set (uint16_t handle, uint16_t settings)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_POLICY_SET;
+    p->offset = 0;
+    UINT16_TO_STREAM (pp, HCI_WRITE_POLICY_SETTINGS);
+    UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_POLICY_SET);
+
+    UINT16_TO_STREAM (pp, handle);
+    UINT16_TO_STREAM (pp, settings);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_write_def_policy_set (uint16_t settings)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_DEF_POLICY_SET;
+    p->offset = 0;
+    UINT16_TO_STREAM (pp, HCI_WRITE_DEF_POLICY_SETTINGS);
+    UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_DEF_POLICY_SET);
+
+    UINT16_TO_STREAM (pp, settings);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_set_event_filter (uint8_t filt_type, uint8_t filt_cond_type,
+                                     uint8_t *filt_cond, uint8_t filt_cond_len)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_SET_EVENT_FILTER);
+
+    if (filt_type)
+    {
+        p->len = (uint16_t)(HCIC_PREAMBLE_SIZE + 2 + filt_cond_len);
+        UINT8_TO_STREAM (pp, (uint8_t)(2 + filt_cond_len));
+
+        UINT8_TO_STREAM (pp, filt_type);
+        UINT8_TO_STREAM (pp, filt_cond_type);
+
+        if (filt_cond_type == HCI_FILTER_COND_DEVICE_CLASS)
+        {
+            DEVCLASS_TO_STREAM (pp, filt_cond);
+            filt_cond += DEV_CLASS_LEN;
+            DEVCLASS_TO_STREAM (pp, filt_cond);
+            filt_cond += DEV_CLASS_LEN;
+
+            filt_cond_len -= (2 * DEV_CLASS_LEN);
+        }
+        else if (filt_cond_type == HCI_FILTER_COND_BD_ADDR)
+        {
+            BDADDR_TO_STREAM (pp, filt_cond);
+            filt_cond += BD_ADDR_LEN;
+
+            filt_cond_len -= BD_ADDR_LEN;
+        }
+
+        if (filt_cond_len)
+            ARRAY_TO_STREAM (pp, filt_cond, filt_cond_len);
+    }
+    else
+    {
+        p->len = (uint16_t)(HCIC_PREAMBLE_SIZE + 1);
+        UINT8_TO_STREAM (pp, 1);
+
+        UINT8_TO_STREAM (pp, filt_type);
+    }
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_write_pin_type (uint8_t type)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_WRITE_PIN_TYPE);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+    UINT8_TO_STREAM (pp, type);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_delete_stored_key (BD_ADDR bd_addr, bool    delete_all_flag)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_DELETE_STORED_KEY;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_DELETE_STORED_LINK_KEY);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_DELETE_STORED_KEY);
+
+    BDADDR_TO_STREAM (pp, bd_addr);
+    UINT8_TO_STREAM  (pp, delete_all_flag);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_change_name (BD_NAME name)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+    uint16_t len = strlen((char *)name) + 1;
+
+    memset(pp, 0, HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CHANGE_NAME);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CHANGE_NAME;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_CHANGE_LOCAL_NAME);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_CHANGE_NAME);
+
+    if (len > HCIC_PARAM_SIZE_CHANGE_NAME)
+        len = HCIC_PARAM_SIZE_CHANGE_NAME;
+
+    ARRAY_TO_STREAM (pp, name, len);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_read_name (void)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_READ_LOCAL_NAME);
+    UINT8_TO_STREAM  (pp,  HCIC_PARAM_SIZE_READ_CMD);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_write_page_tout (uint16_t timeout)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM2;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_WRITE_PAGE_TOUT);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_WRITE_PARAM2);
+
+    UINT16_TO_STREAM  (pp, timeout);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_write_scan_enable (uint8_t flag)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_WRITE_SCAN_ENABLE);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+    UINT8_TO_STREAM  (pp, flag);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_write_pagescan_cfg(uint16_t interval, uint16_t window)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PAGESCAN_CFG;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_WRITE_PAGESCAN_CFG);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_WRITE_PAGESCAN_CFG);
+
+    UINT16_TO_STREAM (pp, interval);
+    UINT16_TO_STREAM (pp, window);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_write_inqscan_cfg(uint16_t interval, uint16_t window)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_INQSCAN_CFG;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_WRITE_INQUIRYSCAN_CFG);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_WRITE_INQSCAN_CFG);
+
+    UINT16_TO_STREAM (pp, interval);
+    UINT16_TO_STREAM (pp, window);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_write_auth_enable (uint8_t flag)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_WRITE_AUTHENTICATION_ENABLE);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+    UINT8_TO_STREAM (pp, flag);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_write_dev_class(DEV_CLASS dev_class)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM3;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_WRITE_CLASS_OF_DEVICE);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_WRITE_PARAM3);
+
+    DEVCLASS_TO_STREAM (pp, dev_class);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_write_voice_settings(uint16_t flags)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM2;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_WRITE_VOICE_SETTINGS);
+    UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM2);
+
+    UINT16_TO_STREAM (pp, flags);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_write_auto_flush_tout (uint16_t handle, uint16_t tout)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_AUTO_FLUSH_TOUT;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_WRITE_AUTO_FLUSH_TOUT);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_WRITE_AUTO_FLUSH_TOUT);
+
+    UINT16_TO_STREAM (pp, handle);
+    UINT16_TO_STREAM (pp, tout);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_read_tx_power (uint16_t handle, uint8_t type)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_TX_POWER;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_READ_TRANSMIT_POWER_LEVEL);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_READ_TX_POWER);
+
+    UINT16_TO_STREAM (pp, handle);
+    UINT8_TO_STREAM  (pp, type);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_host_num_xmitted_pkts (uint8_t num_handles, uint16_t *handle,
+                                          uint16_t *num_pkts)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + 1 + (num_handles * 4);
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_HOST_NUM_PACKETS_DONE);
+    UINT8_TO_STREAM  (pp, p->len - HCIC_PREAMBLE_SIZE);
+
+    UINT8_TO_STREAM (pp, num_handles);
+
+    for (int i = 0; i < num_handles; i++) {
+        UINT16_TO_STREAM(pp, handle[i]);
+        UINT16_TO_STREAM(pp, num_pkts[i]);
+    }
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_write_link_super_tout (uint8_t local_controller_id, uint16_t handle, uint16_t timeout)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_LINK_SUPER_TOUT;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_WRITE_LINK_SUPER_TOUT);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_WRITE_LINK_SUPER_TOUT);
+
+    UINT16_TO_STREAM (pp, handle);
+    UINT16_TO_STREAM (pp, timeout);
+
+    btu_hcif_send_cmd (local_controller_id,  p);
+}
+
+void btsnd_hcic_write_cur_iac_lap (uint8_t num_cur_iac, LAP * const iac_lap)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + 1 + (LAP_LEN * num_cur_iac);
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_WRITE_CURRENT_IAC_LAP);
+    UINT8_TO_STREAM  (pp, p->len - HCIC_PREAMBLE_SIZE);
+
+    UINT8_TO_STREAM (pp, num_cur_iac);
+
+    for (int i = 0; i < num_cur_iac; i++)
+        LAP_TO_STREAM (pp, iac_lap[i]);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+/******************************************
+**    Lisbon Features
+*******************************************/
+#if (BTM_SSR_INCLUDED == TRUE)
+
+void btsnd_hcic_sniff_sub_rate(uint16_t handle, uint16_t max_lat,
+                                  uint16_t min_remote_lat, uint16_t min_local_lat)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SNIFF_SUB_RATE;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_SNIFF_SUB_RATE);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_SNIFF_SUB_RATE);
+
+    UINT16_TO_STREAM  (pp, handle);
+    UINT16_TO_STREAM  (pp, max_lat);
+    UINT16_TO_STREAM  (pp, min_remote_lat);
+    UINT16_TO_STREAM  (pp, min_local_lat);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+#endif /* BTM_SSR_INCLUDED */
+
+/**** Extended Inquiry Response Commands ****/
+void btsnd_hcic_write_ext_inquiry_response (void *buffer, uint8_t fec_req)
+{
+    BT_HDR *p = (BT_HDR *)buffer;
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_EXT_INQ_RESP;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_WRITE_EXT_INQ_RESPONSE);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_EXT_INQ_RESP);
+
+    UINT8_TO_STREAM (pp, fec_req);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_io_cap_req_reply (BD_ADDR bd_addr, uint8_t capability,
+                                uint8_t oob_present, uint8_t auth_req)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_IO_CAP_RESP;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_IO_CAPABILITY_REQUEST_REPLY);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_IO_CAP_RESP);
+
+    BDADDR_TO_STREAM (pp, bd_addr);
+    UINT8_TO_STREAM  (pp, capability);
+    UINT8_TO_STREAM  (pp, oob_present);
+    UINT8_TO_STREAM  (pp, auth_req);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_io_cap_req_neg_reply (BD_ADDR bd_addr, uint8_t err_code)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_IO_CAP_NEG_REPLY;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_IO_CAP_REQ_NEG_REPLY);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_IO_CAP_NEG_REPLY);
+
+    BDADDR_TO_STREAM (pp, bd_addr);
+    UINT8_TO_STREAM  (pp, err_code);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_read_local_oob_data (void)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_R_LOCAL_OOB;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_READ_LOCAL_OOB_DATA);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_R_LOCAL_OOB);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_user_conf_reply (BD_ADDR bd_addr, bool    is_yes)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_UCONF_REPLY;
+    p->offset = 0;
+
+    if (!is_yes)
+    {
+        /* Negative reply */
+        UINT16_TO_STREAM (pp, HCI_USER_CONF_VALUE_NEG_REPLY);
+    }
+    else
+    {
+        /* Confirmation */
+        UINT16_TO_STREAM (pp, HCI_USER_CONF_REQUEST_REPLY);
+    }
+
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_UCONF_REPLY);
+
+    BDADDR_TO_STREAM (pp, bd_addr);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_user_passkey_reply (BD_ADDR bd_addr, uint32_t value)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_U_PKEY_REPLY;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_USER_PASSKEY_REQ_REPLY);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_U_PKEY_REPLY);
+
+    BDADDR_TO_STREAM (pp, bd_addr);
+    UINT32_TO_STREAM (pp, value);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_user_passkey_neg_reply (BD_ADDR bd_addr)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_U_PKEY_NEG_REPLY;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_USER_PASSKEY_REQ_NEG_REPLY);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_U_PKEY_NEG_REPLY);
+
+    BDADDR_TO_STREAM (pp, bd_addr);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_rem_oob_reply (BD_ADDR bd_addr, uint8_t *p_c, uint8_t *p_r)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_REM_OOB_REPLY;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_REM_OOB_DATA_REQ_REPLY);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_REM_OOB_REPLY);
+
+    BDADDR_TO_STREAM (pp, bd_addr);
+    ARRAY16_TO_STREAM (pp, p_c);
+    ARRAY16_TO_STREAM (pp, p_r);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_rem_oob_neg_reply (BD_ADDR bd_addr)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_REM_OOB_NEG_REPLY;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_REM_OOB_DATA_REQ_NEG_REPLY);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_REM_OOB_NEG_REPLY);
+
+    BDADDR_TO_STREAM (pp, bd_addr);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+
+void btsnd_hcic_read_inq_tx_power (void)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_R_TX_POWER;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_READ_INQ_TX_POWER_LEVEL);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_R_TX_POWER);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_send_keypress_notif (BD_ADDR bd_addr, uint8_t notif)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SEND_KEYPRESS_NOTIF;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_SEND_KEYPRESS_NOTIF);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_SEND_KEYPRESS_NOTIF);
+
+    BDADDR_TO_STREAM (pp, bd_addr);
+    UINT8_TO_STREAM (pp, notif);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+/**** end of Simple Pairing Commands ****/
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+void btsnd_hcic_enhanced_flush (uint16_t handle, uint8_t packet_type)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ENHANCED_FLUSH;
+    p->offset = 0;
+    UINT16_TO_STREAM (pp, HCI_ENHANCED_FLUSH);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_ENHANCED_FLUSH);
+
+    UINT16_TO_STREAM (pp, handle);
+    UINT8_TO_STREAM  (pp, packet_type);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+#endif
+
+/*************************
+** End of Lisbon Commands
+**************************/
+
+void btsnd_hcic_get_link_quality (uint16_t handle)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_GET_LINK_QUALITY);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+    UINT16_TO_STREAM (pp, handle);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_read_rssi (uint16_t handle)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_READ_RSSI);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+    UINT16_TO_STREAM (pp, handle);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_enable_test_mode (void)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_ENABLE_DEV_UNDER_TEST_MODE);
+    UINT8_TO_STREAM  (pp,  HCIC_PARAM_SIZE_READ_CMD);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_write_inqscan_type (uint8_t type)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_WRITE_INQSCAN_TYPE);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+    UINT8_TO_STREAM  (pp, type);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_write_inquiry_mode (uint8_t mode)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_WRITE_INQUIRY_MODE);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+    UINT8_TO_STREAM  (pp, mode);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+void btsnd_hcic_write_pagescan_type (uint8_t type)
+{
+    BT_HDR *p = (BT_HDR *)osi_malloc(HCI_CMD_BUF_SIZE);
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+    p->offset = 0;
+
+    UINT16_TO_STREAM (pp, HCI_WRITE_PAGESCAN_TYPE);
+    UINT8_TO_STREAM  (pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+    UINT8_TO_STREAM  (pp, type);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
+
+/* Must have room to store BT_HDR + max VSC length + callback pointer */
+#if (HCI_CMD_BUF_SIZE < 268)
+#error "HCI_CMD_BUF_SIZE must be larger than 268"
+#endif
+
+void btsnd_hcic_vendor_spec_cmd (void *buffer, uint16_t opcode, uint8_t len,
+                                 uint8_t *p_data, void *p_cmd_cplt_cback)
+{
+    BT_HDR *p = (BT_HDR *)buffer;
+    uint8_t *pp = (uint8_t *)(p + 1);
+
+    p->len    = HCIC_PREAMBLE_SIZE + len;
+    p->offset = sizeof(void *);
+
+    *((void **)pp) = p_cmd_cplt_cback;  /* Store command complete callback in buffer */
+    pp += sizeof(void *);               /* Skip over callback pointer */
+
+    UINT16_TO_STREAM (pp, HCI_GRP_VENDOR_SPECIFIC | opcode);
+    UINT8_TO_STREAM  (pp, len);
+    ARRAY_TO_STREAM  (pp, p_data, len);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID,  p);
+}
diff --git a/bt/stack/hid/hid_conn.h b/bt/stack/hid/hid_conn.h
new file mode 100644
index 0000000..49a6ebd
--- /dev/null
+++ b/bt/stack/hid/hid_conn.h
@@ -0,0 +1,69 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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 HID connection internal definitions
+ *
+ ******************************************************************************/
+
+#ifndef HID_CONN_H
+#define HID_CONN_H
+
+#include "osi/include/alarm.h"
+
+/* Define the HID Connection Block
+*/
+typedef struct hid_conn
+{
+#define HID_CONN_STATE_UNUSED           (0)
+#define HID_CONN_STATE_CONNECTING_CTRL  (1)
+#define HID_CONN_STATE_CONNECTING_INTR  (2)
+#define HID_CONN_STATE_CONFIG           (3)
+#define HID_CONN_STATE_CONNECTED        (4)
+#define HID_CONN_STATE_DISCONNECTING    (5)
+#define HID_CONN_STATE_SECURITY         (6)
+
+    uint8_t           conn_state;
+
+#define HID_CONN_FLAGS_IS_ORIG              (0x01)
+#define HID_CONN_FLAGS_HIS_CTRL_CFG_DONE    (0x02)
+#define HID_CONN_FLAGS_MY_CTRL_CFG_DONE     (0x04)
+#define HID_CONN_FLAGS_HIS_INTR_CFG_DONE    (0x08)
+#define HID_CONN_FLAGS_MY_INTR_CFG_DONE     (0x10)
+#define HID_CONN_FLAGS_ALL_CONFIGURED       (0x1E)        /* All the config done */
+#define HID_CONN_FLAGS_CONGESTED            (0x20)
+#define HID_CONN_FLAGS_INACTIVE             (0x40)
+
+    uint8_t           conn_flags;
+
+    uint8_t           ctrl_id;
+    uint16_t          ctrl_cid;
+    uint16_t          intr_cid;
+    uint16_t          rem_mtu_size;
+    uint16_t          disc_reason;                       /* Reason for disconnecting (for HID_HDEV_EVT_CLOSE) */
+    alarm_t           *process_repage_timer;
+} tHID_CONN;
+
+#define HID_SEC_CHN   1
+#define HID_NOSEC_CHN 2
+
+#define HIDD_SEC_CHN    3
+#define HIDD_NOSEC_CHN  4
+
+#endif
diff --git a/bt/stack/hid/hidh_api.cc b/bt/stack/hid/hidh_api.cc
new file mode 100644
index 0000000..bc4d77f
--- /dev/null
+++ b/bt/stack/hid/hidh_api.cc
@@ -0,0 +1,597 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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 HID HOST API entry points
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "bt_common.h"
+#include "bt_types.h"
+#include "hiddefs.h"
+#include "hidh_api.h"
+#include "hidh_int.h"
+#include "btm_api.h"
+#include "btu.h"
+#include "btm_int.h"
+
+tHID_HOST_CTB hh_cb;
+
+static void hidh_search_callback (uint16_t sdp_result);
+
+/*******************************************************************************
+**
+** Function         HID_HostGetSDPRecord
+**
+** Description      This function reads the device SDP record
+**
+** Returns          tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_HostGetSDPRecord ( BD_ADDR addr, tSDP_DISCOVERY_DB *p_db, uint32_t db_len,
+                                   tHID_HOST_SDP_CALLBACK *sdp_cback )
+{
+    tSDP_UUID   uuid_list;
+
+    if( hh_cb.sdp_busy )
+        return HID_ERR_SDP_BUSY;
+
+    uuid_list.len = 2;
+    uuid_list.uu.uuid16 = UUID_SERVCLASS_HUMAN_INTERFACE;
+
+    hh_cb.p_sdp_db = p_db;
+    SDP_InitDiscoveryDb (p_db, db_len, 1, &uuid_list, 0, NULL);
+
+    if (SDP_ServiceSearchRequest (addr, p_db, hidh_search_callback))
+    {
+        hh_cb.sdp_cback = sdp_cback ;
+        hh_cb.sdp_busy = true;
+        return HID_SUCCESS;
+    }
+    else
+        return HID_ERR_NO_RESOURCES;
+}
+
+void hidh_get_str_attr( tSDP_DISC_REC *p_rec, uint16_t attr_id, uint16_t max_len, char *str )
+{
+    tSDP_DISC_ATTR          *p_attr;
+    uint16_t                name_len;
+
+    if ((p_attr = SDP_FindAttributeInRec(p_rec, attr_id)) != NULL)
+    {
+        if((name_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type)) < max_len )
+        {
+            memcpy( str, (char *) p_attr->attr_value.v.array, name_len );
+            str[name_len] = '\0';
+        }
+        else
+        {
+            memcpy( str, (char *) p_attr->attr_value.v.array, max_len-1 );
+            str[max_len-1] = '\0';
+        }
+    }
+    else
+        str[0] = '\0';
+}
+
+
+static void hidh_search_callback (uint16_t sdp_result)
+{
+    tSDP_DISCOVERY_DB       *p_db = hh_cb.p_sdp_db;
+    tSDP_DISC_REC           *p_rec;
+    tSDP_DISC_ATTR          *p_attr, *p_subattr1, *p_subattr2, *p_repdesc;
+    tBT_UUID                hid_uuid;
+    tHID_DEV_SDP_INFO       *p_nvi = &hh_cb.sdp_rec;
+    uint16_t                attr_mask = 0;
+
+    hid_uuid.len       = LEN_UUID_16;
+    hid_uuid.uu.uuid16 = UUID_SERVCLASS_HUMAN_INTERFACE;
+
+    hh_cb.sdp_busy = false;
+
+    if (sdp_result != SDP_SUCCESS)
+    {
+        hh_cb.sdp_cback(sdp_result, 0, NULL);
+        return;
+    }
+
+    if ((p_rec = SDP_FindServiceUUIDInDb (p_db, &hid_uuid, NULL)) == NULL)
+    {
+        hh_cb.sdp_cback(HID_SDP_NO_SERV_UUID, 0, NULL);
+        return;
+    }
+
+    memset (&hh_cb.sdp_rec, 0, sizeof( tHID_DEV_SDP_INFO ));
+
+    /* First, verify the mandatory fields we care about */
+    if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_DESCRIPTOR_LIST)) == NULL)
+     || (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE)
+     || ((p_subattr1 = p_attr->attr_value.v.p_sub_attr) == NULL)
+     || (SDP_DISC_ATTR_TYPE(p_subattr1->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE)
+     || ((p_subattr2 = p_subattr1->attr_value.v.p_sub_attr) == NULL)
+     || ((p_repdesc = p_subattr2->p_next_attr) == NULL)
+     || (SDP_DISC_ATTR_TYPE(p_repdesc->attr_len_type) != TEXT_STR_DESC_TYPE))
+    {
+        hh_cb.sdp_cback(HID_SDP_MANDATORY_MISSING, 0, NULL);
+        return;
+    }
+
+    if ((p_nvi->dscp_info.dl_len = SDP_DISC_ATTR_LEN(p_repdesc->attr_len_type)) != 0)
+        p_nvi->dscp_info.dsc_list = (uint8_t *) &p_repdesc->attr_value;
+
+    if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_VIRTUAL_CABLE)) != NULL) &&
+        (p_attr->attr_value.v.u8) )
+    {
+        attr_mask |= HID_VIRTUAL_CABLE;
+    }
+
+    if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_RECONNECT_INITIATE)) != NULL) &&
+        (p_attr->attr_value.v.u8) )
+    {
+        attr_mask |= HID_RECONN_INIT;
+    }
+
+    if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_NORMALLY_CONNECTABLE)) != NULL) &&
+        (p_attr->attr_value.v.u8) )
+    {
+        attr_mask |= HID_NORMALLY_CONNECTABLE;
+    }
+
+    if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_SDP_DISABLE)) != NULL)&&
+        (p_attr->attr_value.v.u8) )
+    {
+        attr_mask |= HID_SDP_DISABLE;
+    }
+
+    if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_BATTERY_POWER)) != NULL)&&
+        (p_attr->attr_value.v.u8) )
+    {
+        attr_mask |= HID_BATTERY_POWER;
+    }
+
+    if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_REMOTE_WAKE)) != NULL)&&
+        (p_attr->attr_value.v.u8) )
+    {
+        attr_mask |= HID_REMOTE_WAKE;
+    }
+
+    hidh_get_str_attr( p_rec, ATTR_ID_SERVICE_NAME, HID_MAX_SVC_NAME_LEN, p_nvi->svc_name );
+    hidh_get_str_attr( p_rec, ATTR_ID_SERVICE_DESCRIPTION, HID_MAX_SVC_DESCR_LEN, p_nvi->svc_descr );
+    hidh_get_str_attr( p_rec, ATTR_ID_PROVIDER_NAME, HID_MAX_PROV_NAME_LEN, p_nvi->prov_name );
+
+    if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_DEVICE_RELNUM)) != NULL))
+    {
+        p_nvi->rel_num = p_attr->attr_value.v.u16;
+    }
+
+    if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_COUNTRY_CODE)) != NULL))
+    {
+        p_nvi->ctry_code = p_attr->attr_value.v.u8;
+    }
+
+    if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_DEVICE_SUBCLASS)) != NULL))
+    {
+        p_nvi->sub_class = p_attr->attr_value.v.u8;
+    }
+
+    if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_PARSER_VERSION)) != NULL))
+    {
+        p_nvi->hpars_ver = p_attr->attr_value.v.u16;
+    }
+
+    if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_LINK_SUPERVISION_TO)) != NULL))
+    {
+        attr_mask |= HID_SUP_TOUT_AVLBL;
+        p_nvi->sup_timeout = p_attr->attr_value.v.u16;
+    }
+
+    if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_SSR_HOST_MAX_LAT)) != NULL))
+    {
+        attr_mask |= HID_SSR_MAX_LATENCY;
+        p_nvi->ssr_max_latency = p_attr->attr_value.v.u16;
+    }
+    else
+        p_nvi->ssr_max_latency = HID_SSR_PARAM_INVALID;
+
+    if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_SSR_HOST_MIN_TOUT)) != NULL))
+    {
+        attr_mask |= HID_SSR_MIN_TOUT;
+        p_nvi->ssr_min_tout = p_attr->attr_value.v.u16;
+    }
+    else
+        p_nvi->ssr_min_tout = HID_SSR_PARAM_INVALID;
+
+    hh_cb.sdp_rec.p_sdp_layer_rec = p_rec;
+    hh_cb.sdp_cback(SDP_SUCCESS, attr_mask, &hh_cb.sdp_rec);
+}
+
+
+/*******************************************************************************
+**
+** Function         HID_HostInit
+**
+** Description      This function initializes the control block and trace variable
+**
+** Returns          void
+**
+*******************************************************************************/
+void HID_HostInit (void)
+{
+    memset(&hh_cb, 0, sizeof(tHID_HOST_CTB));
+
+    for (size_t i = 0; i < HID_HOST_MAX_DEVICES; i++) {
+        hh_cb.devices[i].conn.process_repage_timer =
+          alarm_new("hid_devices_conn.process_repage_timer");
+    }
+
+#if defined(HID_INITIAL_TRACE_LEVEL)
+    hh_cb.trace_level = HID_INITIAL_TRACE_LEVEL;
+#else
+    hh_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         HID_HostSetTraceLevel
+**
+** Description      This function sets the trace level for HID Host. If called with
+**                  a value of 0xFF, it simply reads the current trace level.
+**
+** Returns          the new (current) trace level
+**
+*******************************************************************************/
+uint8_t HID_HostSetTraceLevel (uint8_t new_level)
+{
+    if (new_level != 0xFF)
+        hh_cb.trace_level = new_level;
+
+    return (hh_cb.trace_level);
+}
+
+/*******************************************************************************
+**
+** Function         HID_HostRegister
+**
+** Description      This function registers HID-Host with lower layers
+**
+** Returns          tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_HostRegister (tHID_HOST_DEV_CALLBACK *dev_cback)
+{
+    tHID_STATUS st;
+
+    if( hh_cb.reg_flag )
+        return HID_ERR_ALREADY_REGISTERED;
+
+    if( dev_cback == NULL )
+        return HID_ERR_INVALID_PARAM;
+
+    /* Register with L2CAP */
+    if( (st = hidh_conn_reg()) != HID_SUCCESS )
+    {
+        return st;
+    }
+
+    hh_cb.callback = dev_cback ;
+    hh_cb.reg_flag = true;
+
+    return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         HID_HostDeregister
+**
+** Description      This function is called when the host is about power down.
+**
+** Returns          tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_HostDeregister(void)
+{
+    uint8_t i;
+
+    if( !hh_cb.reg_flag )
+        return (HID_ERR_NOT_REGISTERED);
+
+    for( i=0; i<HID_HOST_MAX_DEVICES; i++ )
+    {
+        HID_HostRemoveDev( i ) ;
+    }
+
+    hidh_conn_dereg();
+    hh_cb.reg_flag = false;
+
+    return (HID_SUCCESS) ;
+}
+
+/*******************************************************************************
+**
+** Function         HID_HostAddDev
+**
+** Description      This is called so HID-host may manage this device.
+**
+** Returns          tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_HostAddDev ( BD_ADDR addr, uint16_t attr_mask, uint8_t *handle )
+{
+    int i;
+    /* Find an entry for this device in hh_cb.devices array */
+    if( !hh_cb.reg_flag )
+        return (HID_ERR_NOT_REGISTERED);
+
+    for( i=0; i<HID_HOST_MAX_DEVICES; i++)
+    {
+        if((hh_cb.devices[i].in_use) &&
+           (!memcmp(addr, hh_cb.devices[i].addr, BD_ADDR_LEN)))
+            break;
+    }
+
+    if (i== HID_HOST_MAX_DEVICES )
+    {
+        for( i=0; i<HID_HOST_MAX_DEVICES; i++)
+        {
+            if( !hh_cb.devices[i].in_use)
+                break;
+        }
+    }
+
+    if( i==HID_HOST_MAX_DEVICES )
+        return HID_ERR_NO_RESOURCES;
+
+    if (!hh_cb.devices[i].in_use)
+    {
+        hh_cb.devices[i].in_use = true;
+        memcpy( hh_cb.devices[i].addr, addr, sizeof( BD_ADDR ) ) ;
+        hh_cb.devices[i].state = HID_DEV_NO_CONN;
+        hh_cb.devices[i].conn_tries = 0 ;
+    }
+
+    if (attr_mask != HID_ATTR_MASK_IGNORE)
+        hh_cb.devices[i].attr_mask = attr_mask;
+
+    *handle = i;
+
+    return (HID_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function         HID_HostRemoveDev
+**
+** Description      This removes the device from list devices that host has to manage.
+**
+** Returns          tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS HID_HostRemoveDev ( uint8_t dev_handle )
+{
+    if( !hh_cb.reg_flag )
+        return (HID_ERR_NOT_REGISTERED);
+
+    if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) )
+        return HID_ERR_INVALID_PARAM;
+
+    HID_HostCloseDev( dev_handle ) ;
+    hh_cb.devices[dev_handle].in_use = false;
+    hh_cb.devices[dev_handle].conn.conn_state = HID_CONN_STATE_UNUSED;
+    hh_cb.devices[dev_handle].conn.ctrl_cid = hh_cb.devices[dev_handle].conn.intr_cid = 0;
+    hh_cb.devices[dev_handle].attr_mask = 0;
+    return HID_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function         HID_HostOpenDev
+**
+** Description      This function is called when the user wants to initiate a
+**                  connection attempt to a device.
+**
+** Returns          void
+**
+*******************************************************************************/
+tHID_STATUS HID_HostOpenDev ( uint8_t dev_handle )
+{
+    if( !hh_cb.reg_flag )
+        return (HID_ERR_NOT_REGISTERED);
+
+    if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) )
+        return HID_ERR_INVALID_PARAM;
+
+    if( hh_cb.devices[dev_handle].state != HID_DEV_NO_CONN )
+        return HID_ERR_ALREADY_CONN;
+
+    hh_cb.devices[dev_handle].conn_tries = 1;
+    return hidh_conn_initiate( dev_handle );
+}
+
+/*******************************************************************************
+**
+** Function         HID_HostWriteDev
+**
+** Description      This function is called when the host has a report to send.
+**
+**                  report_id: is only used on GET_REPORT transaction if is specified.
+**                              only valid when it's a non-zero value.
+**
+** Returns          void
+**
+*******************************************************************************/
+tHID_STATUS HID_HostWriteDev( uint8_t dev_handle, uint8_t t_type,
+                              uint8_t param, uint16_t data, uint8_t report_id, BT_HDR *pbuf  )
+{
+    tHID_STATUS status = HID_SUCCESS;
+
+    if( !hh_cb.reg_flag )
+    {
+        HIDH_TRACE_ERROR("HID_ERR_NOT_REGISTERED");
+        status = HID_ERR_NOT_REGISTERED;
+    }
+
+    if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) )
+    {
+        HIDH_TRACE_ERROR("HID_ERR_INVALID_PARAM");
+        status = HID_ERR_INVALID_PARAM;
+    }
+
+    else if( hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED )
+    {
+        HIDH_TRACE_ERROR("HID_ERR_NO_CONNECTION dev_handle %d", dev_handle);
+        status = HID_ERR_NO_CONNECTION;
+    }
+
+    if (status != HID_SUCCESS)
+        osi_free(pbuf);
+    else
+        status = hidh_conn_snd_data(dev_handle, t_type, param, data, report_id, pbuf);
+
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         HID_HostCloseDev
+**
+** Description      This function disconnects the device.
+**
+** Returns          void
+**
+*******************************************************************************/
+tHID_STATUS HID_HostCloseDev( uint8_t dev_handle )
+{
+    if( !hh_cb.reg_flag )
+        return (HID_ERR_NOT_REGISTERED);
+
+    if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) )
+        return HID_ERR_INVALID_PARAM;
+
+    if( hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED )
+        return HID_ERR_NO_CONNECTION;
+
+    alarm_cancel(hh_cb.devices[dev_handle].conn.process_repage_timer);
+    hh_cb.devices[dev_handle].conn_tries = HID_HOST_MAX_CONN_RETRY+1;
+    return hidh_conn_disconnect( dev_handle );
+}
+
+tHID_STATUS HID_HostSetSecurityLevel(const char serv_name[], uint8_t sec_lvl )
+{
+    if (!BTM_SetSecurityLevel (false, serv_name, BTM_SEC_SERVICE_HIDH_SEC_CTRL,
+                               sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HID_SEC_CHN))
+    {
+        HIDH_TRACE_ERROR ("Security Registration 1 failed");
+        return (HID_ERR_NO_RESOURCES);
+    }
+
+    if (!BTM_SetSecurityLevel (true, serv_name, BTM_SEC_SERVICE_HIDH_SEC_CTRL,
+                               sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HID_SEC_CHN))
+    {
+        HIDH_TRACE_ERROR ("Security Registration 2 failed");
+        return (HID_ERR_NO_RESOURCES);
+    }
+
+    if (!BTM_SetSecurityLevel (false, serv_name, BTM_SEC_SERVICE_HIDH_NOSEC_CTRL,
+                               BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HID_NOSEC_CHN))
+    {
+        HIDH_TRACE_ERROR ("Security Registration 3 failed");
+        return (HID_ERR_NO_RESOURCES);
+    }
+
+    if (!BTM_SetSecurityLevel (true, serv_name, BTM_SEC_SERVICE_HIDH_NOSEC_CTRL,
+                               BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HID_NOSEC_CHN))
+    {
+        HIDH_TRACE_ERROR ("Security Registration 4 failed");
+        return (HID_ERR_NO_RESOURCES);
+    }
+
+    if (!BTM_SetSecurityLevel (true, serv_name, BTM_SEC_SERVICE_HIDH_INTR,
+                               BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID, 0))
+    {
+        HIDH_TRACE_ERROR ("Security Registration 5 failed");
+        return (HID_ERR_NO_RESOURCES);
+    }
+
+    if (!BTM_SetSecurityLevel (false, serv_name, BTM_SEC_SERVICE_HIDH_INTR,
+                               BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID, 0))
+    {
+        HIDH_TRACE_ERROR ("Security Registration 6 failed");
+        return (HID_ERR_NO_RESOURCES);
+    }
+
+    return( HID_SUCCESS );
+}
+
+/******************************************************************************
+**
+** Function         hid_known_hid_device
+**
+** Description      check if this device is  of type HID Device
+**
+** Returns          true if device is HID Device else false
+**
+*******************************************************************************/
+bool    hid_known_hid_device (BD_ADDR bd_addr)
+{
+    uint8_t i;
+    tBTM_INQ_INFO *p_inq_info = BTM_InqDbRead(bd_addr);
+
+     if ( !hh_cb.reg_flag )
+        return false;
+
+    /* First  check for class of device , if Inq DB has information about this device*/
+    if (p_inq_info != NULL)
+    {
+        /* Check if remote major device class is of type BTM_COD_MAJOR_PERIPHERAL */
+        if ((p_inq_info->results.dev_class[1] & BTM_COD_MAJOR_CLASS_MASK)
+            == BTM_COD_MAJOR_PERIPHERAL )
+        {
+            HIDH_TRACE_DEBUG("hid_known_hid_device:dev found in InqDB & COD matches HID dev");
+            return true;
+        }
+    }
+    else
+    {
+        /* Look for this device in security device DB */
+        tBTM_SEC_DEV_REC  *p_dev_rec = btm_find_dev (bd_addr);
+        if ((p_dev_rec != NULL) &&
+            ((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) == BTM_COD_MAJOR_PERIPHERAL ))
+        {
+            HIDH_TRACE_DEBUG("hid_known_hid_device:dev found in SecDevDB & COD matches HID dev");
+            return true;
+        }
+    }
+
+    /* Find an entry for this device in hh_cb.devices array */
+     for ( i=0; i<HID_HOST_MAX_DEVICES; i++)
+     {
+         if ((hh_cb.devices[i].in_use) &&
+            (memcmp(bd_addr, hh_cb.devices[i].addr, BD_ADDR_LEN) == 0))
+             return true;
+     }
+    /* Check if this device is marked as HID Device in IOP Dev */
+    HIDH_TRACE_DEBUG("hid_known_hid_device:remote is not HID device");
+    return false;
+}
diff --git a/bt/stack/hid/hidh_conn.cc b/bt/stack/hid/hidh_conn.cc
new file mode 100644
index 0000000..dc03c67
--- /dev/null
+++ b/bt/stack/hid/hidh_conn.cc
@@ -0,0 +1,1109 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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 connection interface functions
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+
+#include "bt_common.h"
+#include "bt_types.h"
+
+#include "l2cdefs.h"
+#include "l2c_api.h"
+
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+
+#include "hiddefs.h"
+
+#include "hidh_api.h"
+#include "hidh_int.h"
+#include "bt_utils.h"
+
+#include "osi/include/osi.h"
+
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+static uint8_t find_conn_by_cid (uint16_t cid);
+static void hidh_conn_retry (uint8_t dhandle);
+
+/********************************************************************************/
+/*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
+/********************************************************************************/
+static void hidh_l2cif_connect_ind (BD_ADDR  bd_addr, uint16_t l2cap_cid,
+                                    uint16_t psm, uint8_t l2cap_id);
+static void hidh_l2cif_connect_cfm (uint16_t l2cap_cid, uint16_t result);
+static void hidh_l2cif_config_ind (uint16_t l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void hidh_l2cif_config_cfm (uint16_t l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void hidh_l2cif_disconnect_ind (uint16_t l2cap_cid, bool    ack_needed);
+static void hidh_l2cif_data_ind (uint16_t l2cap_cid, BT_HDR *p_msg);
+static void hidh_l2cif_disconnect_cfm (uint16_t l2cap_cid, uint16_t result);
+static void hidh_l2cif_cong_ind (uint16_t l2cap_cid, bool    congested);
+
+static const tL2CAP_APPL_INFO hst_reg_info =
+{
+    hidh_l2cif_connect_ind,
+    hidh_l2cif_connect_cfm,
+    NULL,
+    hidh_l2cif_config_ind,
+    hidh_l2cif_config_cfm,
+    hidh_l2cif_disconnect_ind,
+    hidh_l2cif_disconnect_cfm,
+    NULL,
+    hidh_l2cif_data_ind,
+    hidh_l2cif_cong_ind,
+    NULL                        /* tL2CA_TX_COMPLETE_CB */
+};
+
+/*******************************************************************************
+**
+** Function         hidh_l2cif_reg
+**
+** Description      This function initializes the SDP unit.
+**
+** Returns          void
+**
+*******************************************************************************/
+tHID_STATUS hidh_conn_reg (void)
+{
+    int xx;
+
+    /* Initialize the L2CAP configuration. We only care about MTU and flush */
+    memset(&hh_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+    hh_cb.l2cap_cfg.mtu_present          = true;
+    hh_cb.l2cap_cfg.mtu                  = HID_HOST_MTU;
+    hh_cb.l2cap_cfg.flush_to_present     = true;
+    hh_cb.l2cap_cfg.flush_to             = HID_HOST_FLUSH_TO;
+
+    /* Now, register with L2CAP */
+    if (!L2CA_Register (HID_PSM_CONTROL, (tL2CAP_APPL_INFO *) &hst_reg_info))
+    {
+        HIDH_TRACE_ERROR ("HID-Host Control Registration failed");
+        return (HID_ERR_L2CAP_FAILED) ;
+    }
+    if (!L2CA_Register (HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO *) &hst_reg_info))
+    {
+        L2CA_Deregister( HID_PSM_CONTROL ) ;
+        HIDH_TRACE_ERROR ("HID-Host Interrupt Registration failed");
+        return (HID_ERR_L2CAP_FAILED) ;
+    }
+
+    for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++)
+    {
+        hh_cb.devices[xx].in_use = false ;
+        hh_cb.devices[xx].conn.conn_state = HID_CONN_STATE_UNUSED;
+    }
+
+    return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         hidh_conn_disconnect
+**
+** Description      This function disconnects a connection.
+**
+** Returns          true if disconnect started, false if already disconnected
+**
+*******************************************************************************/
+tHID_STATUS hidh_conn_disconnect (uint8_t dhandle)
+{
+    tHID_CONN *p_hcon = &hh_cb.devices[dhandle].conn;
+
+    HIDH_TRACE_EVENT ("HID-Host disconnect");
+
+    if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0))
+    {
+        p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
+
+        /* Set l2cap idle timeout to 0 (so ACL link is disconnected
+         * immediately after last channel is closed) */
+        L2CA_SetIdleTimeoutByBdAddr(hh_cb.devices[dhandle].addr, 0, BT_TRANSPORT_BR_EDR);
+        /* Disconnect both interrupt and control channels */
+        if (p_hcon->intr_cid)
+            L2CA_DisconnectReq (p_hcon->intr_cid);
+        else if (p_hcon->ctrl_cid)
+            L2CA_DisconnectReq (p_hcon->ctrl_cid);
+    }
+    else
+    {
+        p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+    }
+
+    return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         hidh_sec_check_complete_term
+**
+** Description      HID security check complete callback function.
+**
+** Returns          Send L2CA_ConnectRsp OK if secutiry check succeed; otherwise
+**                  send security block L2C connection response.
+**
+*******************************************************************************/
+void hidh_sec_check_complete_term (UNUSED_ATTR BD_ADDR bd_addr, UNUSED_ATTR tBT_TRANSPORT transport, void *p_ref_data,
+                                   uint8_t res)
+{
+    tHID_HOST_DEV_CTB *p_dev= (tHID_HOST_DEV_CTB *) p_ref_data;
+
+    if( res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
+    {
+        p_dev->conn.disc_reason = HID_SUCCESS;  /* Authentication passed. Reset disc_reason (from HID_ERR_AUTH_FAILED) */
+
+        p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_INTR;
+
+        /* Send response to the L2CAP layer. */
+        L2CA_ConnectRsp (p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+
+        /* Send a Configuration Request. */
+        L2CA_ConfigReq (p_dev->conn.ctrl_cid, &hh_cb.l2cap_cfg);
+
+    }
+    /* security check fail */
+    else if (res != BTM_SUCCESS)
+    {
+        p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED;      /* Save reason for disconnecting */
+        p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
+        L2CA_ConnectRsp (p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid, L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         hidh_l2cif_connect_ind
+**
+** Description      This function handles an inbound connection indication
+**                  from L2CAP. This is the case where we are acting as a
+**                  server.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void hidh_l2cif_connect_ind (BD_ADDR  bd_addr, uint16_t l2cap_cid, uint16_t psm, uint8_t l2cap_id)
+{
+    tHID_CONN    *p_hcon;
+    bool         bAccept = true;
+    uint8_t      i = HID_HOST_MAX_DEVICES;
+    tHID_HOST_DEV_CTB *p_dev;
+
+    HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP conn ind, PSM: 0x%04x  CID 0x%x", psm, l2cap_cid);
+
+    /* always add incoming connection device into HID database by default */
+    if (HID_HostAddDev(bd_addr, HID_SEC_REQUIRED, &i) != HID_SUCCESS)
+    {
+        L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_SECURITY_BLOCK, 0);
+        return;
+    }
+
+    p_hcon = &hh_cb.devices[i].conn;
+    p_dev  = &hh_cb.devices[i];
+
+    /* Check we are in the correct state for this */
+    if (psm == HID_PSM_INTERRUPT)
+    {
+        if (p_hcon->ctrl_cid == 0)
+        {
+            HIDH_TRACE_WARNING ("HID-Host Rcvd INTR L2CAP conn ind, but no CTL channel");
+            bAccept = false;
+        }
+        if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)
+        {
+            HIDH_TRACE_WARNING ("HID-Host Rcvd INTR L2CAP conn ind, wrong state: %d",
+                                 p_hcon->conn_state);
+            bAccept = false;
+        }
+    }
+    else /* CTRL channel */
+    {
+#if (HID_HOST_ACPT_NEW_CONN == TRUE)
+        p_hcon->ctrl_cid = p_hcon->intr_cid = 0;
+        p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+#else
+        if (p_hcon->conn_state != HID_CONN_STATE_UNUSED)
+        {
+            HIDH_TRACE_WARNING ("HID-Host - Rcvd CTL L2CAP conn ind, wrong state: %d",
+                                 p_hcon->conn_state);
+            bAccept = false;
+        }
+#endif
+    }
+
+    if (!bAccept)
+    {
+        L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_RESOURCES, 0);
+        return;
+    }
+
+    if (psm == HID_PSM_CONTROL)
+    {
+        p_hcon->conn_flags = 0;
+        p_hcon->ctrl_cid   = l2cap_cid;
+        p_hcon->ctrl_id    = l2cap_id;
+        p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;  /* In case disconnection occurs before security is completed, then set CLOSE_EVT reason code to 'connection failure' */
+
+        p_hcon->conn_state = HID_CONN_STATE_SECURITY;
+        if(btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
+            false, BTM_SEC_PROTO_HID,
+            (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
+            &hidh_sec_check_complete_term, p_dev) == BTM_CMD_STARTED)
+        {
+            L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
+        }
+
+        return;
+    }
+
+    /* Transition to the next appropriate state, configuration */
+    p_hcon->conn_state = HID_CONN_STATE_CONFIG;
+    p_hcon->intr_cid   = l2cap_cid;
+
+    /* Send response to the L2CAP layer. */
+    L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+
+    /* Send a Configuration Request. */
+    L2CA_ConfigReq (l2cap_cid, &hh_cb.l2cap_cfg);
+
+    HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP conn ind, sent config req, PSM: 0x%04x  CID 0x%x",
+                       psm, l2cap_cid);
+}
+
+void hidh_process_repage_timer_timeout(void *data)
+{
+  uint8_t dhandle = PTR_TO_UINT(data);
+  hidh_try_repage(dhandle);
+}
+
+/*******************************************************************************
+**
+** Function         hidh_try_repage
+**
+** Description      This function processes timeout (to page device).
+**
+** Returns          void
+**
+*******************************************************************************/
+void hidh_try_repage(uint8_t dhandle)
+{
+    tHID_HOST_DEV_CTB *device;
+
+    hidh_conn_initiate(dhandle);
+
+    device = &hh_cb.devices[dhandle];
+    device->conn_tries++;
+
+    hh_cb.callback(dhandle, device->addr, HID_HDEV_EVT_RETRYING,
+                   device->conn_tries, NULL ) ;
+}
+
+/*******************************************************************************
+**
+** Function         hidh_sec_check_complete_orig
+**
+** Description      This function checks to see if security procedures are being
+**                  carried out or not..
+**
+** Returns          void
+**
+*******************************************************************************/
+void hidh_sec_check_complete_orig (UNUSED_ATTR BD_ADDR bd_addr, UNUSED_ATTR tBT_TRANSPORT transport, void *p_ref_data,
+                                   uint8_t res)
+{
+    tHID_HOST_DEV_CTB *p_dev = (tHID_HOST_DEV_CTB *) p_ref_data;
+    uint8_t dhandle;
+
+    // TODO(armansito): This kind of math to determine a device handle is way
+    // too dirty and unnecessary. Why can't |p_dev| store it's handle?
+    dhandle = (PTR_TO_UINT(p_dev) - PTR_TO_UINT(&(hh_cb.devices[0])))/ sizeof(tHID_HOST_DEV_CTB);
+    if( res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
+    {
+        HIDH_TRACE_EVENT ("HID-Host Originator security pass.");
+        p_dev->conn.disc_reason = HID_SUCCESS;  /* Authentication passed. Reset disc_reason (from HID_ERR_AUTH_FAILED) */
+
+        /* Transition to the next appropriate state, configuration */
+        p_dev->conn.conn_state = HID_CONN_STATE_CONFIG;
+        L2CA_ConfigReq (p_dev->conn.ctrl_cid, &hh_cb.l2cap_cfg);
+        HIDH_TRACE_EVENT ("HID-Host Got Control conn cnf, sent cfg req, CID: 0x%x", p_dev->conn.ctrl_cid);
+
+    }
+
+    if( res != BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
+    {
+#if (HID_HOST_MAX_CONN_RETRY > 0)
+        if( res == BTM_DEVICE_TIMEOUT )
+        {
+            if( p_dev->conn_tries <= HID_HOST_MAX_CONN_RETRY )
+            {
+                hidh_conn_retry (dhandle);
+                return;
+            }
+        }
+#endif
+        p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED;      /* Save reason for disconnecting */
+        hidh_conn_disconnect(dhandle);
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         hidh_l2cif_connect_cfm
+**
+** Description      This function handles the connect confirm events
+**                  from L2CAP. This is the case when we are acting as a
+**                  client and have sent a connect request.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void hidh_l2cif_connect_cfm (uint16_t l2cap_cid, uint16_t result)
+{
+    uint8_t dhandle;
+    tHID_CONN    *p_hcon = NULL;
+    uint32_t reason;
+    tHID_HOST_DEV_CTB *p_dev = NULL;
+
+    /* Find CCB based on CID, and verify we are in a state to accept this message */
+    if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
+    {
+        p_dev = &hh_cb.devices[dhandle];
+        p_hcon = &hh_cb.devices[dhandle].conn;
+    }
+
+    if ((p_hcon == NULL)
+     || (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG))
+     || ((l2cap_cid == p_hcon->ctrl_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL))
+     || ((l2cap_cid == p_hcon->intr_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)
+     && (p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING)))
+    {
+        HIDH_TRACE_WARNING ("HID-Host Rcvd unexpected conn cnf, CID 0x%x ", l2cap_cid);
+        return;
+    }
+
+    if (result != L2CAP_CONN_OK)
+    {
+        if (l2cap_cid == p_hcon->ctrl_cid)
+            p_hcon->ctrl_cid = 0;
+        else
+            p_hcon->intr_cid = 0;
+
+        hidh_conn_disconnect(dhandle);
+
+#if (HID_HOST_MAX_CONN_RETRY > 0)
+        if( (hh_cb.devices[dhandle].conn_tries <= HID_HOST_MAX_CONN_RETRY) &&
+            (result == HCI_ERR_CONNECTION_TOUT || result == HCI_ERR_UNSPECIFIED ||
+             result == HCI_ERR_PAGE_TIMEOUT) )
+        {
+            hidh_conn_retry(dhandle);
+        }
+        else
+#endif
+        {
+            reason = HID_L2CAP_CONN_FAIL | (uint32_t) result ;
+            hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
+        }
+        return;
+    }
+    /* receive Control Channel connect confirmation */
+    if (l2cap_cid == p_hcon->ctrl_cid)
+    {
+        /* check security requirement */
+        p_hcon->conn_state = HID_CONN_STATE_SECURITY;
+        p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;  /* In case disconnection occurs before security is completed, then set CLOSE_EVT reason code to "connection failure" */
+
+        btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
+            true, BTM_SEC_PROTO_HID,
+            (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
+            &hidh_sec_check_complete_orig, p_dev);
+    }
+    else
+    {
+        p_hcon->conn_state = HID_CONN_STATE_CONFIG;
+        /* Send a Configuration Request. */
+        L2CA_ConfigReq (l2cap_cid, &hh_cb.l2cap_cfg);
+        HIDH_TRACE_EVENT ("HID-Host got Interrupt conn cnf, sent cfg req, CID: 0x%x", l2cap_cid);
+    }
+
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         hidh_l2cif_config_ind
+**
+** Description      This function processes the L2CAP configuration indication
+**                  event.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void hidh_l2cif_config_ind (uint16_t l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+    uint8_t dhandle;
+    tHID_CONN    *p_hcon = NULL;
+    uint32_t reason;
+
+    /* Find CCB based on CID */
+    if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
+    {
+        p_hcon = &hh_cb.devices[dhandle].conn;
+    }
+
+    if (p_hcon == NULL)
+    {
+        HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+        return;
+    }
+
+    HIDH_TRACE_EVENT ("HID-Host Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
+
+    /* Remember the remote MTU size */
+    if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_HOST_MTU))
+        p_hcon->rem_mtu_size = HID_HOST_MTU;
+    else
+        p_hcon->rem_mtu_size = p_cfg->mtu;
+
+    /* For now, always accept configuration from the other side */
+    p_cfg->flush_to_present = false;
+    p_cfg->mtu_present      = false;
+    p_cfg->result           = L2CAP_CFG_OK;
+
+    L2CA_ConfigRsp (l2cap_cid, p_cfg);
+
+    if (l2cap_cid == p_hcon->ctrl_cid)
+    {
+        p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE;
+        if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
+           (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE))
+        {
+            /* Connect interrupt channel */
+            p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;	/* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */
+            if ((p_hcon->intr_cid = L2CA_ConnectReq (HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr)) == 0)
+            {
+                HIDH_TRACE_WARNING ("HID-Host INTR Originate failed");
+                reason = HID_L2CAP_REQ_FAIL ;
+                p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+                hidh_conn_disconnect (dhandle);
+                hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
+                return;
+            }
+            else
+            {
+                /* Transition to the next appropriate state, waiting for connection confirm on interrupt channel. */
+                p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
+            }
+        }
+    }
+    else
+        p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_INTR_CFG_DONE;
+
+    /* If all configuration is complete, change state and tell management we are up */
+    if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == HID_CONN_FLAGS_ALL_CONFIGURED)
+     && (p_hcon->conn_state == HID_CONN_STATE_CONFIG))
+    {
+        p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
+        /* Reset disconnect reason to success, as connection successful */
+        p_hcon->disc_reason = HID_SUCCESS;
+
+        hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
+        hh_cb.callback( dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0, NULL ) ;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         hidh_l2cif_config_cfm
+**
+** Description      This function processes the L2CAP configuration confirmation
+**                  event.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void hidh_l2cif_config_cfm (uint16_t l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+    uint8_t dhandle;
+    tHID_CONN    *p_hcon = NULL;
+    uint32_t reason;
+
+    HIDH_TRACE_EVENT ("HID-Host Rcvd cfg cfm, CID: 0x%x  Result: %d", l2cap_cid, p_cfg->result);
+
+    /* Find CCB based on CID */
+    if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
+        p_hcon = &hh_cb.devices[dhandle].conn;
+
+    if (p_hcon == NULL)
+    {
+        HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+        return;
+    }
+
+    /* If configuration failed, disconnect the channel(s) */
+    if (p_cfg->result != L2CAP_CFG_OK)
+    {
+        hidh_conn_disconnect (dhandle);
+        reason = HID_L2CAP_CFG_FAIL | (uint32_t) p_cfg->result ;
+        hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
+        return;
+    }
+
+    if (l2cap_cid == p_hcon->ctrl_cid)
+    {
+        p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE;
+        if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
+           (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE))
+        {
+            /* Connect interrupt channel */
+            p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;  /* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */
+            if ((p_hcon->intr_cid = L2CA_ConnectReq (HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr)) == 0)
+            {
+                HIDH_TRACE_WARNING ("HID-Host INTR Originate failed");
+                reason = HID_L2CAP_REQ_FAIL ;
+                p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+                hidh_conn_disconnect (dhandle);
+                hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
+                return;
+            }
+            else
+            {
+                /* Transition to the next appropriate state, waiting for connection confirm on interrupt channel. */
+                p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
+            }
+        }
+    }
+    else
+        p_hcon->conn_flags |= HID_CONN_FLAGS_MY_INTR_CFG_DONE;
+
+    /* If all configuration is complete, change state and tell management we are up */
+    if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == HID_CONN_FLAGS_ALL_CONFIGURED)
+     && (p_hcon->conn_state == HID_CONN_STATE_CONFIG))
+    {
+        p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
+        /* Reset disconnect reason to success, as connection successful */
+        p_hcon->disc_reason = HID_SUCCESS;
+
+        hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
+        hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0, NULL ) ;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         hidh_l2cif_disconnect_ind
+**
+** Description      This function handles a disconnect event from L2CAP. If
+**                  requested to, we ack the disconnect before dropping the CCB
+**
+** Returns          void
+**
+*******************************************************************************/
+static void hidh_l2cif_disconnect_ind (uint16_t l2cap_cid, bool    ack_needed)
+{
+    uint8_t dhandle;
+    tHID_CONN    *p_hcon = NULL;
+    uint16_t disc_res = HCI_SUCCESS;
+    uint16_t hid_close_evt_reason;
+
+    /* Find CCB based on CID */
+    if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
+        p_hcon = &hh_cb.devices[dhandle].conn;
+
+    if (p_hcon == NULL)
+    {
+        HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
+        return;
+    }
+
+    if (ack_needed)
+        L2CA_DisconnectRsp (l2cap_cid);
+
+    HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
+
+    p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
+
+    if (l2cap_cid == p_hcon->ctrl_cid)
+        p_hcon->ctrl_cid = 0;
+    else
+        p_hcon->intr_cid = 0;
+
+    if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0))
+    {
+        hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
+        p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+
+        if( !ack_needed )
+            disc_res = btm_get_acl_disc_reason_code();
+
+#if (HID_HOST_MAX_CONN_RETRY > 0)
+        if( (disc_res == HCI_ERR_CONNECTION_TOUT || disc_res == HCI_ERR_UNSPECIFIED) &&
+            (!(hh_cb.devices[dhandle].attr_mask & HID_RECONN_INIT)) &&
+            (hh_cb.devices[dhandle].attr_mask & HID_NORMALLY_CONNECTABLE))
+        {
+            hh_cb.devices[dhandle].conn_tries = 0;
+            period_ms_t interval_ms = HID_HOST_REPAGE_WIN * 1000;
+            alarm_set_on_queue(hh_cb.devices[dhandle].conn.process_repage_timer,
+                               interval_ms, hidh_process_repage_timer_timeout,
+                               UINT_TO_PTR(dhandle), btu_general_alarm_queue);
+            hh_cb.callback( dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, disc_res, NULL);
+        }
+        else
+#endif
+        {
+            /* Set reason code for HID_HDEV_EVT_CLOSE */
+            hid_close_evt_reason = p_hcon->disc_reason;
+
+            /* If we got baseband sent HCI_DISCONNECT_COMPLETE_EVT due to security failure, then set reason to HID_ERR_AUTH_FAILED */
+            if ((disc_res == HCI_ERR_AUTH_FAILURE)                        ||
+                (disc_res == HCI_ERR_KEY_MISSING)                         ||
+                (disc_res == HCI_ERR_HOST_REJECT_SECURITY)                ||
+                (disc_res == HCI_ERR_PAIRING_NOT_ALLOWED)                 ||
+                (disc_res == HCI_ERR_UNIT_KEY_USED)                       ||
+                (disc_res == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) ||
+                (disc_res == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE)           ||
+                (disc_res == HCI_ERR_REPEATED_ATTEMPTS))
+            {
+                hid_close_evt_reason = HID_ERR_AUTH_FAILED;
+            }
+
+            hh_cb.callback( dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, hid_close_evt_reason, NULL ) ;
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         hidh_l2cif_disconnect_cfm
+**
+** Description      This function handles a disconnect confirm event from L2CAP.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void hidh_l2cif_disconnect_cfm (uint16_t l2cap_cid,
+                                       UNUSED_ATTR uint16_t result)
+{
+    uint8_t dhandle;
+    tHID_CONN    *p_hcon = NULL;
+
+    /* Find CCB based on CID */
+    if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
+        p_hcon = &hh_cb.devices[dhandle].conn;
+
+    if (p_hcon == NULL)
+    {
+        HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP disc cfm, unknown CID: 0x%x", l2cap_cid);
+        return;
+    }
+
+    HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid);
+
+    if (l2cap_cid == p_hcon->ctrl_cid)
+        p_hcon->ctrl_cid = 0;
+    else
+    {
+        p_hcon->intr_cid = 0;
+        if (p_hcon->ctrl_cid)
+        {
+            HIDH_TRACE_EVENT ("HID-Host Initiating L2CAP Ctrl disconnection");
+            L2CA_DisconnectReq (p_hcon->ctrl_cid);
+        }
+    }
+
+    if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0))
+    {
+        hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
+        p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+        hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, p_hcon->disc_reason, NULL ) ;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         hidh_l2cif_cong_ind
+**
+** Description      This function handles a congestion status event from L2CAP.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void hidh_l2cif_cong_ind (uint16_t l2cap_cid, bool    congested)
+{
+    uint8_t dhandle;
+    tHID_CONN    *p_hcon = NULL;
+
+    /* Find CCB based on CID */
+    if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
+        p_hcon = &hh_cb.devices[dhandle].conn;
+
+    if (p_hcon == NULL)
+    {
+        HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP congestion status, unknown CID: 0x%x", l2cap_cid);
+        return;
+    }
+
+    HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP congestion status, CID: 0x%x  Cong: %d", l2cap_cid, congested);
+
+    if (congested)
+        p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
+    else
+    {
+        p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
+
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         hidh_l2cif_data_ind
+**
+** Description      This function is called when data is received from L2CAP.
+**                  if we are the originator of the connection, we are the SDP
+**                  client, and the received message is queued up for the client.
+**
+**                  If we are the destination of the connection, we are the SDP
+**                  server, so the message is passed to the server processing
+**                  function.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void hidh_l2cif_data_ind (uint16_t l2cap_cid, BT_HDR *p_msg)
+{
+    uint8_t         *p_data = (uint8_t *)(p_msg + 1) + p_msg->offset;
+    uint8_t         ttype, param, rep_type, evt;
+    uint8_t dhandle;
+    tHID_CONN    *p_hcon = NULL;
+
+    HIDH_TRACE_DEBUG ("HID-Host hidh_l2cif_data_ind [l2cap_cid=0x%04x]", l2cap_cid);
+
+    /* Find CCB based on CID */
+     if ((dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES)
+        p_hcon = &hh_cb.devices[dhandle].conn;
+
+    if (p_hcon == NULL)
+    {
+        HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
+        osi_free(p_msg);
+        return;
+    }
+
+
+    ttype    = HID_GET_TRANS_FROM_HDR(*p_data);
+    param    = HID_GET_PARAM_FROM_HDR(*p_data);
+    rep_type = param & HID_PAR_REP_TYPE_MASK;
+    p_data++;
+
+    /* Get rid of the data type */
+    p_msg->len--;
+    p_msg->offset++;
+
+    switch (ttype)
+    {
+    case HID_TRANS_HANDSHAKE:
+        hh_cb.callback(dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_HANDSHAKE, param, NULL);
+        osi_free(p_msg);
+        break;
+
+    case HID_TRANS_CONTROL:
+        switch (param)
+        {
+        case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
+            hidh_conn_disconnect( dhandle ) ;
+            /* Device is unplugging from us. Tell USB */
+            hh_cb.callback(dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_VC_UNPLUG, 0, NULL);
+            break;
+
+        default:
+            break;
+        }
+        osi_free(p_msg);
+        break;
+
+
+    case HID_TRANS_DATA:
+        evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid) ?
+                    HID_HDEV_EVT_INTR_DATA : HID_HDEV_EVT_CTRL_DATA;
+        hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type, p_msg);
+        break;
+
+    case HID_TRANS_DATAC:
+        evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid) ?
+                    HID_HDEV_EVT_INTR_DATC : HID_HDEV_EVT_CTRL_DATC;
+        hh_cb.callback(dhandle,  hh_cb.devices[dhandle].addr, evt, rep_type, p_msg);
+        break;
+
+    default:
+        osi_free(p_msg);
+        break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         hidh_conn_snd_data
+**
+** Description      This function is sends out data.
+**
+** Returns          tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS hidh_conn_snd_data (uint8_t dhandle, uint8_t trans_type, uint8_t param,
+                                uint16_t data, uint8_t report_id, BT_HDR *buf)
+{
+    tHID_CONN   *p_hcon = &hh_cb.devices[dhandle].conn;
+    BT_HDR      *p_buf;
+    uint8_t     *p_out;
+    uint16_t    bytes_copied;
+    bool        seg_req = false;
+    uint16_t    data_size;
+    uint16_t    cid;
+    uint16_t    buf_size;
+    uint8_t     use_data = 0 ;
+    bool        blank_datc = false;
+
+    if (!BTM_IsAclConnectionUp(hh_cb.devices[dhandle].addr, BT_TRANSPORT_BR_EDR))
+    {
+        osi_free(buf);
+        return HID_ERR_NO_CONNECTION;
+    }
+
+    if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED)
+    {
+        osi_free(buf);
+        return HID_ERR_CONGESTED;
+    }
+
+    switch( trans_type )
+    {
+    case HID_TRANS_CONTROL:
+    case HID_TRANS_GET_REPORT:
+    case HID_TRANS_SET_REPORT:
+    case HID_TRANS_GET_PROTOCOL:
+    case HID_TRANS_SET_PROTOCOL:
+    case HID_TRANS_GET_IDLE:
+    case HID_TRANS_SET_IDLE:
+        cid = p_hcon->ctrl_cid;
+        buf_size = HID_CONTROL_BUF_SIZE;
+        break;
+    case HID_TRANS_DATA:
+        cid = p_hcon->intr_cid;
+        buf_size = HID_INTERRUPT_BUF_SIZE;
+        break;
+    default:
+        return (HID_ERR_INVALID_PARAM) ;
+    }
+
+    if( trans_type == HID_TRANS_SET_IDLE )
+        use_data = 1;
+    else if( (trans_type == HID_TRANS_GET_REPORT) && (param & 0x08) )
+        use_data = 2;
+
+    do
+    {
+        if ( buf == NULL || blank_datc )
+        {
+            p_buf = (BT_HDR *)osi_malloc(buf_size);
+
+            p_buf->offset = L2CAP_MIN_OFFSET;
+            seg_req = false;
+            data_size = 0;
+            bytes_copied = 0;
+            blank_datc = false;
+        }
+        else if ( (buf->len > (p_hcon->rem_mtu_size - 1)))
+        {
+            p_buf = (BT_HDR *)osi_malloc(buf_size);
+
+            p_buf->offset = L2CAP_MIN_OFFSET;
+            seg_req = true;
+            data_size = buf->len;
+            bytes_copied = p_hcon->rem_mtu_size - 1;
+        }
+        else
+        {
+            p_buf = buf ;
+            p_buf->offset -= 1;
+            seg_req = false;
+            data_size = buf->len;
+            bytes_copied = buf->len;
+        }
+
+        p_out         = (uint8_t *)(p_buf + 1) + p_buf->offset;
+        *p_out++      = HID_BUILD_HDR(trans_type, param);
+
+        /* If report ID required for this device */
+        if( (trans_type == HID_TRANS_GET_REPORT) && (report_id != 0) )
+        {
+            *p_out = report_id;
+            data_size = bytes_copied = 1;
+        }
+
+
+        if (seg_req)
+        {
+            memcpy (p_out, (((uint8_t *)(buf+1)) + buf->offset), bytes_copied);
+            buf->offset += bytes_copied;
+            buf->len -= bytes_copied;
+        }
+        else if( use_data == 1)
+        {
+            *(p_out+bytes_copied) = data & 0xff;
+        }
+        else if( use_data == 2 )
+        {
+            *(p_out+bytes_copied) = data & 0xff;
+            *(p_out+bytes_copied+1) = (data >> 8) & 0xff ;
+        }
+
+        p_buf->len   = bytes_copied + 1 + use_data;
+        data_size    -= bytes_copied;
+
+        /* Send the buffer through L2CAP */
+        if ((p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) || (!L2CA_DataWrite (cid, p_buf)))
+            return (HID_ERR_CONGESTED);
+
+        if (data_size)
+            trans_type = HID_TRANS_DATAC;
+        else if( bytes_copied == (p_hcon->rem_mtu_size - 1) )
+        {
+            trans_type = HID_TRANS_DATAC;
+            blank_datc = true;
+        }
+
+    } while ((data_size != 0) || blank_datc ) ;
+
+    return (HID_SUCCESS);
+}
+/*******************************************************************************
+**
+** Function         hidh_conn_initiate
+**
+** Description      This function is called by the management to create a connection.
+**
+** Returns          void
+**
+*******************************************************************************/
+tHID_STATUS hidh_conn_initiate (uint8_t dhandle)
+{
+    uint8_t service_id = BTM_SEC_SERVICE_HIDH_NOSEC_CTRL;
+    uint32_t mx_chan_id = HID_NOSEC_CHN;
+
+    tHID_HOST_DEV_CTB *p_dev = &hh_cb.devices[dhandle];
+
+    if( p_dev->conn.conn_state != HID_CONN_STATE_UNUSED )
+        return( HID_ERR_CONN_IN_PROCESS );
+
+    p_dev->conn.ctrl_cid = 0;
+    p_dev->conn.intr_cid = 0;
+    p_dev->conn.disc_reason = HID_L2CAP_CONN_FAIL;  /* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */
+
+    /* We are the originator of this connection */
+    p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG;
+
+    if(p_dev->attr_mask & HID_SEC_REQUIRED)
+    {
+        service_id = BTM_SEC_SERVICE_HIDH_SEC_CTRL;
+        mx_chan_id = HID_SEC_CHN;
+    }
+    BTM_SetOutService (p_dev->addr, service_id, mx_chan_id);
+
+    /* Check if L2CAP started the connection process */
+    if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq (HID_PSM_CONTROL, p_dev->addr)) == 0)
+    {
+        HIDH_TRACE_WARNING ("HID-Host Originate failed");
+        hh_cb.callback( dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
+                                HID_ERR_L2CAP_FAILED, NULL ) ;
+    }
+    else
+    {
+        /* Transition to the next appropriate state, waiting for connection confirm on control channel. */
+        p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
+    }
+
+    return( HID_SUCCESS );
+}
+
+
+/*******************************************************************************
+**
+** Function         find_conn_by_cid
+**
+** Description      This function finds a connection control block based on CID
+**
+** Returns          address of control block, or NULL if not found
+**
+*******************************************************************************/
+static uint8_t find_conn_by_cid (uint16_t cid)
+{
+    uint8_t    xx;
+
+    for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++)
+    {
+        if ((hh_cb.devices[xx].in_use) && (hh_cb.devices[xx].conn.conn_state != HID_CONN_STATE_UNUSED)
+            && ((hh_cb.devices[xx].conn.ctrl_cid == cid) || (hh_cb.devices[xx].conn.intr_cid == cid)))
+            break;
+    }
+
+    return (xx);
+}
+
+void hidh_conn_dereg( void )
+{
+    L2CA_Deregister (HID_PSM_CONTROL);
+    L2CA_Deregister (HID_PSM_INTERRUPT);
+}
+
+/*******************************************************************************
+**
+** Function         hidh_conn_retry
+**
+** Description      This function is called to retry a failed connection.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void hidh_conn_retry(  uint8_t dhandle )
+{
+    tHID_HOST_DEV_CTB *p_dev = &hh_cb.devices[dhandle];
+
+    p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
+#if (HID_HOST_REPAGE_WIN > 0)
+    period_ms_t interval_ms = HID_HOST_REPAGE_WIN * 1000;
+    alarm_set_on_queue(p_dev->conn.process_repage_timer,
+                       interval_ms, hidh_process_repage_timer_timeout,
+                       UINT_TO_PTR(dhandle), btu_general_alarm_queue);
+#else
+    hidh_try_repage(dhandle);
+#endif
+}
diff --git a/bt/stack/hid/hidh_int.h b/bt/stack/hid/hidh_int.h
new file mode 100644
index 0000000..6034ac0
--- /dev/null
+++ b/bt/stack/hid/hidh_int.h
@@ -0,0 +1,88 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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 HID HOST internal definitions
+ *
+ ******************************************************************************/
+
+#ifndef HIDH_INT_H
+#define HIDH_INT_H
+
+#include "hidh_api.h"
+#include "hid_conn.h"
+#include "l2c_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+    HID_DEV_NO_CONN,
+    HID_DEV_CONNECTED
+};
+
+typedef struct per_device_ctb
+{
+    bool           in_use;
+    BD_ADDR        addr;  /* BD-Addr of the host device */
+    uint16_t       attr_mask; /* 0x01- virtual_cable; 0x02- normally_connectable; 0x03- reconn_initiate;
+    			                 0x04- sdp_disable; */
+    uint8_t        state;  /* Device state if in HOST-KNOWN mode */
+    uint8_t        conn_substate;
+    uint8_t        conn_tries; /* Remembers to the number of connection attempts while CONNECTING */
+
+    tHID_CONN      conn; /* L2CAP channel info */
+} tHID_HOST_DEV_CTB;
+
+typedef struct host_ctb
+{
+    tHID_HOST_DEV_CTB       devices[HID_HOST_MAX_DEVICES];
+    tHID_HOST_DEV_CALLBACK  *callback;             /* Application callbacks */
+    tL2CAP_CFG_INFO         l2cap_cfg;
+
+#define MAX_SERVICE_DB_SIZE    4000
+
+    bool                    sdp_busy;
+    tHID_HOST_SDP_CALLBACK  *sdp_cback;
+    tSDP_DISCOVERY_DB       *p_sdp_db;
+    tHID_DEV_SDP_INFO       sdp_rec;
+    bool                    reg_flag;
+    uint8_t                 trace_level;
+} tHID_HOST_CTB;
+
+extern tHID_STATUS hidh_conn_snd_data(uint8_t dhandle, uint8_t trans_type, uint8_t param, \
+                                      uint16_t data,uint8_t rpt_id, BT_HDR *buf);
+extern tHID_STATUS hidh_conn_reg (void);
+extern void hidh_conn_dereg( void );
+extern tHID_STATUS hidh_conn_disconnect (uint8_t dhandle);
+extern tHID_STATUS hidh_conn_initiate (uint8_t dhandle);
+extern void hidh_process_repage_timer_timeout(void *data);
+extern void hidh_try_repage(uint8_t dhandle);
+
+/******************************************************************************
+** Main Control Block
+*******************************************************************************/
+extern tHID_HOST_CTB  hh_cb;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bt/stack/include/a2dp_api.h b/bt/stack/include/a2dp_api.h
new file mode 100644
index 0000000..8f16bf6
--- /dev/null
+++ b/bt/stack/include/a2dp_api.h
@@ -0,0 +1,623 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2000-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Interface to A2DP Application Programming Interface
+ *
+ ******************************************************************************/
+#ifndef A2DP_API_H
+#define A2DP_API_H
+
+#include <stddef.h>
+
+#include "avdt_api.h"
+#include "osi/include/time.h"
+#include "sdp_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+**  constants
+*****************************************************************************/
+
+//
+// |MAX_PCM_FRAME_NUM_PER_TICK| controls how many buffers we can hold in
+// the A2DP buffer queues during temporary link congestion.
+//
+#ifndef MAX_PCM_FRAME_NUM_PER_TICK
+#define MAX_PCM_FRAME_NUM_PER_TICK 14
+#endif
+
+/* Profile supported features */
+#define A2DP_SUPF_PLAYER 0x0001
+#define A2DP_SUPF_MIC 0x0002
+#define A2DP_SUPF_TUNER 0x0004
+#define A2DP_SUPF_MIXER 0x0008
+
+#define A2DP_SUPF_HEADPHONE 0x0001
+#define A2DP_SUPF_SPEAKER 0x0002
+#define A2DP_SUPF_RECORDER 0x0004
+#define A2DP_SUPF_AMP 0x0008
+
+/* AV Media Codec Type (Audio Codec ID) */
+#define A2DP_MEDIA_CT_SBC 0x00 /* SBC media codec type */
+#define A2DP_MEDIA_CT_NON_A2DP \
+  0xFF /* Non-A2DP media codec type (vendor-specific codec) */
+
+typedef uint8_t tA2DP_CODEC_TYPE; /* A2DP Codec type: A2DP_MEDIA_CT_* */
+
+#define A2DP_SUCCESS 0           /* Success */
+#define A2DP_FAIL 0x0A           /* Failed */
+#define A2DP_BUSY 0x0B           /* A2DP_FindService is already in progress */
+#define A2DP_INVALID_PARAMS 0x0C /* bad parameters */
+#define A2DP_WRONG_CODEC 0x0D    /* wrong codec info */
+#define A2DP_BAD_CODEC_TYPE 0xC1 /* Media Codec Type is not valid  */
+#define A2DP_NS_CODEC_TYPE 0xC2  /* Media Codec Type is not supported */
+#define A2DP_BAD_SAMP_FREQ                                             \
+  0xC3 /* Sampling Frequency is not valid or multiple values have been \
+          selected  */
+#define A2DP_NS_SAMP_FREQ 0xC4 /* Sampling Frequency is not supported  */
+#define A2DP_BAD_CH_MODE \
+  0xC5 /* Channel Mode is not valid or multiple values have been selected  */
+#define A2DP_NS_CH_MODE 0xC6 /* Channel Mode is not supported */
+#define A2DP_BAD_SUBBANDS \
+  0xC7 /* None or multiple values have been selected for Number of Subbands */
+#define A2DP_NS_SUBBANDS 0xC8 /* Number of Subbands is not supported */
+#define A2DP_BAD_ALLOC_METHOD \
+  0xC9 /* None or multiple values have been selected for Allocation Method */
+#define A2DP_NS_ALLOC_METHOD 0xCA /* Allocation Method is not supported */
+#define A2DP_BAD_MIN_BITPOOL 0xCB /* Minimum Bitpool Value is not valid */
+#define A2DP_NS_MIN_BITPOOL 0xCC  /* Minimum Bitpool Value is not supported */
+#define A2DP_BAD_MAX_BITPOOL 0xCD /* Maximum Bitpool Value is not valid */
+#define A2DP_NS_MAX_BITPOOL 0xCE  /* Maximum Bitpool Value is not supported */
+#define A2DP_BAD_LAYER \
+  0xCF /* None or multiple values have been selected for Layer */
+#define A2DP_NS_LAYER 0xD0 /* Layer is not supported */
+#define A2DP_NS_CRC 0xD1   /* CRC is not supported */
+#define A2DP_NS_MPF 0xD2   /* MPF-2 is not supported */
+#define A2DP_NS_VBR 0xD3   /* VBR is not supported */
+#define A2DP_BAD_BIT_RATE \
+  0xD4 /* None or multiple values have been selected for Bit Rate */
+#define A2DP_NS_BIT_RATE 0xD5 /* Bit Rate is not supported */
+#define A2DP_BAD_OBJ_TYPE                                                   \
+  0xD6 /* Either 1) Object type is not valid (b3-b0) or 2) None or multiple \
+          values have been selected for Object Type */
+#define A2DP_NS_OBJ_TYPE 0xD7 /* Object type is not supported */
+#define A2DP_BAD_CHANNEL \
+  0xD8 /* None or multiple values have been selected for Channels */
+#define A2DP_NS_CHANNEL 0xD9 /* Channels is not supported */
+#define A2DP_BAD_BLOCK_LEN \
+  0xDD /* None or multiple values have been selected for Block Length */
+#define A2DP_BAD_CP_TYPE 0xE0 /* The requested CP Type is not supported. */
+#define A2DP_BAD_CP_FORMAT                                            \
+  0xE1 /* The format of Content Protection Service Capability/Content \
+          Protection Scheme Dependent Data is not correct. */
+
+typedef uint8_t tA2DP_STATUS;
+
+/* the return values from A2DP_BitsSet() */
+#define A2DP_SET_ONE_BIT 1   /* one and only one bit is set */
+#define A2DP_SET_ZERO_BIT 0  /* all bits clear */
+#define A2DP_SET_MULTL_BIT 2 /* multiple bits are set */
+
+/*****************************************************************************
+**  type definitions
+*****************************************************************************/
+
+/* This data type is used in A2DP_FindService() to initialize the SDP database
+ * to hold the result service search. */
+typedef struct {
+  uint32_t db_len;   /* Length, in bytes, of the discovery database */
+  uint16_t num_attr; /* The number of attributes in p_attrs */
+  uint16_t* p_attrs; /* The attributes filter. If NULL, A2DP API sets the
+                      * attribute filter
+                      * to be ATTR_ID_SERVICE_CLASS_ID_LIST,
+                      * ATTR_ID_BT_PROFILE_DESC_LIST,
+                      * ATTR_ID_SUPPORTED_FEATURES, ATTR_ID_SERVICE_NAME and
+                      * ATTR_ID_PROVIDER_NAME.
+                      * If not NULL, the input is taken as the filter. */
+} tA2DP_SDP_DB_PARAMS;
+
+/* This data type is used in tA2DP_FIND_CBACK to report the result of the SDP
+ * discovery process. */
+typedef struct {
+  uint16_t service_len;  /* Length, in bytes, of the service name */
+  uint16_t provider_len; /* Length, in bytes, of the provider name */
+  char* p_service_name;  /* Pointer the service name.  This character string may
+                          * not be null terminated.
+                          * Use the service_len parameter to safely copy this
+                          * string */
+  char* p_provider_name; /* Pointer the provider name.  This character string
+                          * may not be null terminated.
+                          * Use the provider_len parameter to safely copy this
+                          * string */
+  uint16_t features;     /* Profile supported features */
+  uint16_t avdt_version; /* AVDTP protocol version */
+} tA2DP_Service;
+
+/* This is the callback to notify the result of the SDP discovery process. */
+typedef void(tA2DP_FIND_CBACK)(bool found, tA2DP_Service* p_service);
+
+/*
+ * Enum values for each supported codec per SEP.
+ * There should be a separate entry for each codec that is supported
+ * for encoding (SRC), and for decoding purpose (SINK).
+ */
+typedef enum {
+  A2DP_CODEC_SEP_INDEX_SOURCE_MIN = 0,
+  A2DP_CODEC_SEP_INDEX_SOURCE_SBC = 0,
+  /* Add an entry for each new source codec here */
+  A2DP_CODEC_SEP_INDEX_SOURCE_MAX,
+
+  A2DP_CODEC_SEP_INDEX_SINK_MIN = A2DP_CODEC_SEP_INDEX_SOURCE_MAX,
+  A2DP_CODEC_SEP_INDEX_SINK_SBC = A2DP_CODEC_SEP_INDEX_SINK_MIN,
+  /* Add an entry for each new sink codec here */
+  A2DP_CODEC_SEP_INDEX_SINK_MAX,
+
+  A2DP_CODEC_SEP_INDEX_MIN = A2DP_CODEC_SEP_INDEX_SOURCE_MIN,
+  A2DP_CODEC_SEP_INDEX_MAX = A2DP_CODEC_SEP_INDEX_SINK_MAX
+} tA2DP_CODEC_SEP_INDEX;
+
+/**
+ * Structure used to configure the A2DP feeding.
+ */
+typedef struct {
+  uint32_t sampling_freq; /* 44100, 48000 etc */
+  uint8_t num_channel;    /* 1 for mono or 2 stereo */
+  uint8_t bit_per_sample; /* Number of bits per sample (8, 16) */
+} tA2DP_FEEDING_PARAMS;
+
+/**
+ * Structure used to initialize the A2DP encoder.
+ */
+typedef struct {
+  uint32_t SamplingFreq;    /* 16k, 32k, 44.1k, 48k, etc. */
+  uint8_t ChannelMode;      /* mono, dual, stereo or joint stereo */
+  uint8_t NumOfSubBands;    /* 4 or 8 */
+  uint8_t NumOfBlocks;      /* 4, 8, 12 or 16 */
+  uint8_t AllocationMethod; /* loudness or SNR */
+  uint16_t MtuSize;         /* peer mtu size */
+} tA2DP_ENCODER_INIT_PARAMS;
+
+/**
+ * Structure used to update the A2DP encoder.
+ */
+typedef struct {
+  uint16_t MinMtuSize; /* Minimum peer mtu size */
+  uint8_t MaxBitPool;  /* Maximum peer bitpool */
+  uint8_t MinBitPool;  /* Minimum peer bitpool */
+} tA2DP_ENCODER_UPDATE_PARAMS;
+
+// Prototype for a callback to read audio data for encoding.
+// |p_buf| is the buffer to store the data. |len| is the number of octets to
+// read.
+// Returns the number of octets read.
+typedef uint32_t (*a2dp_source_read_callback_t)(uint8_t* p_buf, uint32_t len);
+
+// Prototype for a callback to enqueue A2DP Source packets for transmission.
+// |p_buf| is the buffer with the audio data to enqueue. The callback is
+// responsible for freeing |p_buf|.
+// |frames_n| is the number of audio frames in |p_buf| - it is used for
+// statistics purpose.
+// Returns true if the packet was enqueued, otherwise false.
+typedef bool (*a2dp_source_enqueue_callback_t)(BT_HDR* p_buf, size_t frames_n);
+
+//
+// A2DP encoder callbacks interface.
+//
+typedef struct {
+  // Initialize the A2DP encoder.
+  // If |is_peer_edr| is true, the A2DP peer device supports EDR.
+  // If |peer_supports_3mbps| is true, the A2DP peer device supports 3Mbps
+  // EDR.
+  // The encoder initialization parameters are in |p_init_params|.
+  // |enqueue_callback} is the callback for enqueueing the encoded audio
+  // data.
+  void (*encoder_init)(bool is_peer_edr, bool peer_supports_3mbps,
+                       const tA2DP_ENCODER_INIT_PARAMS* p_init_params,
+                       a2dp_source_read_callback_t read_callback,
+                       a2dp_source_enqueue_callback_t enqueue_callback);
+
+  // Update the A2DP encoder.
+  // The encoder update parameters are in |p_update_params|.
+  void (*encoder_update)(const tA2DP_ENCODER_UPDATE_PARAMS* p_update_params);
+
+  // Cleanup the A2DP encoder.
+  void (*encoder_cleanup)(void);
+
+  // Initialize the feeding for the A2DP encoder.
+  // The feeding initialization parameters are in |p_feeding_params|.
+  void (*feeding_init)(const tA2DP_FEEDING_PARAMS* p_feeding_params);
+
+  // Reset the feeding for the A2DP encoder.
+  void (*feeding_reset)(void);
+
+  // Flush the feeding for the A2DP encoder.
+  void (*feeding_flush)(void);
+
+  // Get the A2DP encoder interval (in milliseconds).
+  period_ms_t (*get_encoder_interval_ms)(void);
+
+  // Prepare and send A2DP encoded frames.
+  // |timestamp_us| is the current timestamp (in microseconds).
+  void (*send_frames)(uint64_t timestamp_us);
+
+  // Dump codec-related statistics.
+  // |fd| is the file descriptor to use to dump the statistics information
+  // in user-friendly test format.
+  void (*debug_codec_dump)(int fd);
+} tA2DP_ENCODER_INTERFACE;
+
+/*****************************************************************************
+**  external function declarations
+*****************************************************************************/
+/******************************************************************************
+**
+** Function         A2DP_AddRecord
+**
+** Description      This function is called by a server application to add
+**                  SRC or SNK information to an SDP record.  Prior to
+**                  calling this function the application must call
+**                  SDP_CreateRecord() to create an SDP record.
+**
+**                  Input Parameters:
+**                      service_uuid:  Indicates SRC or SNK.
+**
+**                      p_service_name:  Pointer to a null-terminated character
+**                      string containing the service name.
+**
+**                      p_provider_name:  Pointer to a null-terminated character
+**                      string containing the provider name.
+**
+**                      features:  Profile supported features.
+**
+**                      sdp_handle:  SDP handle returned by SDP_CreateRecord().
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          A2DP_SUCCESS if function execution succeeded,
+**                  A2DP_INVALID_PARAMS if bad parameters are given.
+**                  A2DP_FAIL if function execution failed.
+**
+******************************************************************************/
+extern tA2DP_STATUS A2DP_AddRecord(uint16_t service_uuid, char* p_service_name,
+                                   char* p_provider_name, uint16_t features,
+                                   uint32_t sdp_handle);
+
+/******************************************************************************
+**
+** Function         A2DP_FindService
+**
+** Description      This function is called by a client application to
+**                  perform service discovery and retrieve SRC or SNK SDP
+**                  record information from a server.  Information is
+**                  returned for the first service record found on the
+**                  server that matches the service UUID.  The callback
+**                  function will be executed when service discovery is
+**                  complete.  There can only be one outstanding call to
+**                  A2DP_FindService() at a time; the application must wait
+**                  for the callback before it makes another call to
+**                  the function.
+**
+**                  Input Parameters:
+**                      service_uuid:  Indicates SRC or SNK.
+**
+**                      bd_addr:  BD address of the peer device.
+**
+**                      p_db:  Pointer to the information to initialize
+**                             the discovery database.
+**
+**                      p_cback:  Pointer to the A2DP_FindService()
+**                      callback function.
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          A2DP_SUCCESS if function execution succeeded,
+**                  A2DP_INVALID_PARAMS if bad parameters are given.
+**                  A2DP_BUSY if discovery is already in progress.
+**                  A2DP_FAIL if function execution failed.
+**
+******************************************************************************/
+extern tA2DP_STATUS A2DP_FindService(uint16_t service_uuid, BD_ADDR bd_addr,
+                                     tA2DP_SDP_DB_PARAMS* p_db,
+                                     tA2DP_FIND_CBACK* p_cback);
+
+/******************************************************************************
+**
+** Function         A2DP_SetTraceLevel
+**
+** Description      Sets the trace level for A2D. If 0xff is passed, the
+**                  current trace level is returned.
+**
+**                  Input Parameters:
+**                      new_level:  The level to set the A2DP tracing to:
+**                      0xff-returns the current setting.
+**                      0-turns off tracing.
+**                      >= 1-Errors.
+**                      >= 2-Warnings.
+**                      >= 3-APIs.
+**                      >= 4-Events.
+**                      >= 5-Debug.
+**
+** Returns          The new trace level or current trace level if
+**                  the input parameter is 0xff.
+**
+******************************************************************************/
+extern uint8_t A2DP_SetTraceLevel(uint8_t new_level);
+
+/******************************************************************************
+** Function         A2DP_BitsSet
+**
+** Description      Check the given num for the number of bits set
+** Returns          A2DP_SET_ONE_BIT, if one and only one bit is set
+**                  A2DP_SET_ZERO_BIT, if all bits clear
+**                  A2DP_SET_MULTL_BIT, if multiple bits are set
+******************************************************************************/
+extern uint8_t A2DP_BitsSet(uint8_t num);
+
+// Initializes the A2DP control block.
+void A2DP_Init(void);
+
+// Gets the A2DP codec type.
+// |p_codec_info| contains information about the codec capabilities.
+tA2DP_CODEC_TYPE A2DP_GetCodecType(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid A2DP Source codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid codec,
+// otherwise false.
+bool A2DP_IsSourceCodecValid(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid A2DP Sink codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid codec,
+// otherwise false.
+bool A2DP_IsSinkCodecValid(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid peer A2DP Source
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid codec,
+// otherwise false.
+bool A2DP_IsPeerSourceCodecValid(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid peer A2DP Sink codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid codec,
+// otherwise false.
+bool A2DP_IsPeerSinkCodecValid(const uint8_t* p_codec_info);
+
+// Checks whether an A2DP Source codec is supported.
+// |p_codec_info| contains information about the codec capabilities.
+// Returns true if the A2DP Source codec is supported, otherwise false.
+bool A2DP_IsSourceCodecSupported(const uint8_t* p_codec_info);
+
+// Checks whether an A2DP Sink codec is supported.
+// |p_codec_info| contains information about the codec capabilities.
+// Returns true if the A2DP Sink codec is supported, otherwise false.
+bool A2DP_IsSinkCodecSupported(const uint8_t* p_codec_info);
+
+// Checks whether an A2DP Source codec for a peer Source device is supported.
+// |p_codec_info| contains information about the codec capabilities of the
+// peer device.
+// Returns true if the A2DP Source codec for a peer Source device is supported,
+// otherwise false.
+bool A2DP_IsPeerSourceCodecSupported(const uint8_t* p_codec_info);
+
+// Initialize state with the default A2DP codec.
+// The initialized state with the codec capabilities is stored in
+// |p_codec_info|.
+void A2DP_InitDefaultCodec(uint8_t* p_codec_info);
+
+// Sets A2DB source codec state based on the Source codec index
+// |source_codec_sep_index| and the feeding information from
+// |p_feeding_params|.
+// The state with the codec capabilities is stored in |p_codec_info|.
+// Returns true on success, otherwise false.
+// |source_codec_sep_index| should be in the range
+// [A2DP_CODEC_SEP_INDEX_SOURCE_MIN, A2DP_CODEC_SEP_INDEX_SOURCE_MAX),
+// otherwise the return value is false.
+bool A2DP_SetSourceCodec(tA2DP_CODEC_SEP_INDEX source_codec_sep_index,
+                         const tA2DP_FEEDING_PARAMS* p_feeding_params,
+                         uint8_t* p_codec_info);
+
+// Builds A2DP preferred Sink capability from Source capability.
+// |p_src_cap| is the Source capability to use.
+// |p_pref_cfg| is the result Sink capability to store.
+// Returns |A2DP_SUCCESS| on success, otherwise the corresponding A2DP error
+// status code.
+tA2DP_STATUS A2DP_BuildSrc2SinkConfig(const uint8_t* p_src_cap,
+                                      uint8_t* p_pref_cfg);
+
+// Builds A2DP Sink codec config from Source codec config and Sink codec
+// capability.
+// |p_src_config| is the A2DP Source codec config to use.
+// |p_sink_cap| is the A2DP Sink codec capability to use.
+// The result is stored in |p_result_sink_config|.
+// Returns |A2DP_SUCCESS| on success, otherwise the corresponding A2DP error
+// status code.
+tA2DP_STATUS A2DP_BuildSinkConfig(const uint8_t* p_src_config,
+                                  const uint8_t* p_sink_cap,
+                                  uint8_t* p_result_sink_config);
+
+// Checks whether the A2DP data packets should contain RTP header.
+// |content_protection_enabled| is true if Content Protection is
+// enabled. |p_codec_info| contains information about the codec capabilities.
+// Returns true if the A2DP data packets should contain RTP header, otherwise
+// false.
+bool A2DP_UsesRtpHeader(bool content_protection_enabled,
+                        const uint8_t* p_codec_info);
+
+// Gets the A2DP codec name for a given |codec_sep_index|.
+const char* A2DP_CodecSepIndexStr(tA2DP_CODEC_SEP_INDEX codec_sep_index);
+
+// Initializes A2DP codec-specific information into |tAVDT_CFG| configuration
+// entry pointed by |p_cfg|. The selected codec is defined by
+// |codec_sep_index|.
+// Returns true on success, otherwise false.
+bool A2DP_InitCodecConfig(tA2DP_CODEC_SEP_INDEX codec_sep_index,
+                          tAVDT_CFG* p_cfg);
+
+// Gets the |AVDT_MEDIA_TYPE_*| media type from the codec capability
+// in |p_codec_info|.
+uint8_t A2DP_GetMediaType(const uint8_t* p_codec_info);
+
+// Gets the A2DP codec name for a given |p_codec_info|.
+const char* A2DP_CodecName(const uint8_t* p_codec_info);
+
+// Checks whether two A2DP codecs |p_codec_info_a| and |p_codec_info_b| have
+// the same type.
+// Returns true if the two codecs have the same type, otherwise false.
+// If the codec type is not recognized, the return value is false.
+bool A2DP_CodecTypeEquals(const uint8_t* p_codec_info_a,
+                          const uint8_t* p_codec_info_b);
+
+// Checks whether two A2DP codecs p_codec_info_a| and |p_codec_info_b| are
+// exactly the same.
+// Returns true if the two codecs are exactly the same, otherwise false.
+// If the codec type is not recognized, the return value is false.
+bool A2DP_CodecEquals(const uint8_t* p_codec_info_a,
+                      const uint8_t* p_codec_info_b);
+
+// Checks whether two A2DP codecs |p_codec_info_a| and |p_codec_info_b|
+// are different, and A2DP requires reconfiguration.
+// Returns true if the two codecs are different and A2DP requires
+// reconfiguration, otherwise false.
+// If the codec type is not recognized, the return value is true.
+bool A2DP_CodecRequiresReconfig(const uint8_t* p_codec_info_a,
+                                const uint8_t* p_codec_info_b);
+
+// Checks if a codec config |p_codec_config| matches a codec capabilities
+// |p_codec_caps|.
+// Returns true if the codec config is supported, otherwise false.
+bool A2DP_CodecConfigMatchesCapabilities(const uint8_t* p_codec_config,
+                                         const uint8_t* p_codec_caps);
+
+// Gets the track sampling frequency value for the A2DP codec.
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the track sampling frequency on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackFrequency(const uint8_t* p_codec_info);
+
+// Gets the channel count for the A2DP codec.
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the channel count on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackChannelCount(const uint8_t* p_codec_info);
+
+// Gets the number of subbands for the A2DP codec.
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the number of subbands on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetNumberOfSubbands(const uint8_t* p_codec_info);
+
+// Gets the number of blocks for the A2DP codec.
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the number of blocks on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetNumberOfBlocks(const uint8_t* p_codec_info);
+
+// Gets the allocation method code for the A2DP codec.
+// The actual value is codec-specific.
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the allocation method code on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetAllocationMethodCode(const uint8_t* p_codec_info);
+
+// Gets the channel mode code for the A2DP codec.
+// The actual value is codec-specific.
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the channel mode code on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetChannelModeCode(const uint8_t* p_codec_info);
+
+// Gets the sampling frequency code for the A2DP codec.
+// The actual value is codec-specific.
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the sampling frequency code on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetSamplingFrequencyCode(const uint8_t* p_codec_info);
+
+// Gets the minimum bitpool for the A2DP codec.
+// The actual value is codec-specific.
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the minimum bitpool on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetMinBitpool(const uint8_t* p_codec_info);
+
+// Gets the maximum bitpool for the A2DP codec.
+// The actual value is codec-specific.
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the maximum bitpool on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetMaxBitpool(const uint8_t* p_codec_info);
+
+// Gets the channel type for the A2DP Sink codec:
+// 1 for mono, or 3 for dual/stereo/joint.
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the channel type on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetSinkTrackChannelType(const uint8_t* p_codec_info);
+
+// Computes the number of frames to process in a time window for the A2DP
+// Sink codec. |time_interval_ms| is the time interval (in milliseconds).
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the number of frames to process on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetSinkFramesCountToProcess(uint64_t time_interval_ms,
+                                     const uint8_t* p_codec_info);
+
+// Gets the A2DP audio data timestamp from an audio packet.
+// |p_codec_info| contains the codec information.
+// |p_data| contains the audio data.
+// The timestamp is stored in |p_timestamp|.
+// Returns true on success, otherwise false.
+bool A2DP_GetPacketTimestamp(const uint8_t* p_codec_info, const uint8_t* p_data,
+                             uint32_t* p_timestamp);
+
+// Builds A2DP codec header for audio data.
+// |p_codec_info| contains the codec information.
+// |p_buf| contains the audio data.
+// |frames_per_packet| is the number of frames in this packet.
+// Returns true on success, otherwise false.
+bool A2DP_BuildCodecHeader(const uint8_t* p_codec_info, BT_HDR* p_buf,
+                           uint16_t frames_per_packet);
+
+// Gets the A2DP encoder interface that can be used to encode and prepare
+// A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP encoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterface(
+    const uint8_t* p_codec_info);
+
+// Adjusts the A2DP codec, based on local support and Bluetooth specification.
+// |p_codec_info| contains the codec information to adjust.
+// Returns true if |p_codec_info| is valid and supported, otherwise false.
+bool A2DP_AdjustCodec(uint8_t* p_codec_info);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* A2DP_API_H */
diff --git a/bt/stack/include/a2dp_sbc.h b/bt/stack/include/a2dp_sbc.h
new file mode 100644
index 0000000..2548132
--- /dev/null
+++ b/bt/stack/include/a2dp_sbc.h
@@ -0,0 +1,318 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2000-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Interface to low complexity subband codec (SBC)
+ *
+ ******************************************************************************/
+#ifndef A2DP_SBC_H
+#define A2DP_SBC_H
+
+#include "a2dp_api.h"
+#include "avdt_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+/* the length of the SBC Media Payload header. */
+#define A2DP_SBC_MPL_HDR_LEN 1
+
+/* the LOSC of SBC media codec capabilitiy */
+#define A2DP_SBC_INFO_LEN 6
+
+/* for Codec Specific Information Element */
+#define A2DP_SBC_IE_SAMP_FREQ_MSK 0xF0 /* b7-b4 sampling frequency */
+#define A2DP_SBC_IE_SAMP_FREQ_16 0x80  /* b7:16  kHz */
+#define A2DP_SBC_IE_SAMP_FREQ_32 0x40  /* b6:32  kHz */
+#define A2DP_SBC_IE_SAMP_FREQ_44 0x20  /* b5:44.1kHz */
+#define A2DP_SBC_IE_SAMP_FREQ_48 0x10  /* b4:48  kHz */
+
+#define A2DP_SBC_IE_CH_MD_MSK 0x0F    /* b3-b0 channel mode */
+#define A2DP_SBC_IE_CH_MD_MONO 0x08   /* b3: mono */
+#define A2DP_SBC_IE_CH_MD_DUAL 0x04   /* b2: dual */
+#define A2DP_SBC_IE_CH_MD_STEREO 0x02 /* b1: stereo */
+#define A2DP_SBC_IE_CH_MD_JOINT 0x01  /* b0: joint stereo */
+
+#define A2DP_SBC_IE_BLOCKS_MSK 0xF0 /* b7-b4 number of blocks */
+#define A2DP_SBC_IE_BLOCKS_4 0x80   /* 4 blocks */
+#define A2DP_SBC_IE_BLOCKS_8 0x40   /* 8 blocks */
+#define A2DP_SBC_IE_BLOCKS_12 0x20  /* 12blocks */
+#define A2DP_SBC_IE_BLOCKS_16 0x10  /* 16blocks */
+
+#define A2DP_SBC_IE_SUBBAND_MSK 0x0C /* b3-b2 number of subbands */
+#define A2DP_SBC_IE_SUBBAND_4 0x08   /* b3: 4 */
+#define A2DP_SBC_IE_SUBBAND_8 0x04   /* b2: 8 */
+
+#define A2DP_SBC_IE_ALLOC_MD_MSK 0x03 /* b1-b0 allocation mode */
+#define A2DP_SBC_IE_ALLOC_MD_S 0x02   /* b1: SNR */
+#define A2DP_SBC_IE_ALLOC_MD_L 0x01   /* b0: loundess */
+
+#define A2DP_SBC_IE_MIN_BITPOOL 2
+#define A2DP_SBC_IE_MAX_BITPOOL 250
+
+/* for media payload header */
+#define A2DP_SBC_HDR_F_MSK 0x80
+#define A2DP_SBC_HDR_S_MSK 0x40
+#define A2DP_SBC_HDR_L_MSK 0x20
+#define A2DP_SBC_HDR_NUM_MSK 0x0F
+
+/*****************************************************************************
+**  Type Definitions
+*****************************************************************************/
+
+/*****************************************************************************
+**  External Function Declarations
+*****************************************************************************/
+
+// Gets the A2DP SBC Source codec name.
+const char* A2DP_CodecSepIndexStrSbc(void);
+
+// Gets the A2DP SBC Sink codec name.
+const char* A2DP_CodecSepIndexStrSbcSink(void);
+
+// Initializes A2DP SBC Source codec information into |tAVDT_CFG| configuration
+// entry pointed by |p_cfg|.
+bool A2DP_InitCodecConfigSbc(tAVDT_CFG* p_cfg);
+
+// Initializes A2DP SBC Sink codec information into |tAVDT_CFG| configuration
+// entry pointed by |p_cfg|.
+bool A2DP_InitCodecConfigSbcSink(tAVDT_CFG* p_cfg);
+
+// Checks whether the codec capabilities contain a valid A2DP SBC Source codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid SBC codec,
+// otherwise false.
+bool A2DP_IsSourceCodecValidSbc(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid A2DP SBC Sink codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid SBC codec,
+// otherwise false.
+bool A2DP_IsSinkCodecValidSbc(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid peer A2DP SBC Source
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid SBC codec,
+// otherwise false.
+bool A2DP_IsPeerSourceCodecValidSbc(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid peer A2DP SBC Sink
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid SBC codec,
+// otherwise false.
+bool A2DP_IsPeerSinkCodecValidSbc(const uint8_t* p_codec_info);
+
+// Checks whether A2DP SBC Source codec is supported.
+// |p_codec_info| contains information about the codec capabilities.
+// Returns true if the A2DP SBC Source codec is supported, otherwise false.
+bool A2DP_IsSourceCodecSupportedSbc(const uint8_t* p_codec_info);
+
+// Checks whether A2DP SBC Sink codec is supported.
+// |p_codec_info| contains information about the codec capabilities.
+// Returns true if the A2DP SBC Sink codec is supported, otherwise false.
+bool A2DP_IsSinkCodecSupportedSbc(const uint8_t* p_codec_info);
+
+// Checks whether an A2DP SBC Source codec for a peer Source device is
+// supported.
+// |p_codec_info| contains information about the codec capabilities of the
+// peer device.
+// Returns true if the A2DP SBC Source codec for a peer Source device is
+// supported, otherwise false.
+bool A2DP_IsPeerSourceCodecSupportedSbc(const uint8_t* p_codec_info);
+
+// Initialize state with the default A2DP SBC codec.
+// The initialized state with the codec capabilities is stored in
+// |p_codec_info|.
+void A2DP_InitDefaultCodecSbc(uint8_t* p_codec_info);
+
+// Sets A2DB SBC Source codec state based on the feeding information from
+// |p_feeding_params|.
+// The state with the codec capabilities is stored in |p_codec_info|.
+// Returns true on success, otherwise false.
+bool A2DP_SetSourceCodecSbc(const tA2DP_FEEDING_PARAMS* p_feeding_params,
+                            uint8_t* p_codec_info);
+
+// Builds A2DP preferred SBC Sink capability from SBC Source capability.
+// |p_src_cap| is the Source capability to use.
+// |p_pref_cfg| is the result Sink capability to store.
+// Returns |A2DP_SUCCESS| on success, otherwise the corresponding A2DP error
+// status code.
+tA2DP_STATUS A2DP_BuildSrc2SinkConfigSbc(const uint8_t* p_src_cap,
+                                         uint8_t* p_pref_cfg);
+
+// Builds A2DP SBC Sink codec config from SBC Source codec config and SBC Sink
+// codec capability.
+// |p_src_config| is the A2DP SBC Source codec config to use.
+// |p_sink_cap| is the A2DP SBC Sink codec capability to use.
+// The result is stored in |p_result_sink_config|.
+// Returns |A2DP_SUCCESS| on success, otherwise the corresponding A2DP error
+// status code.
+tA2DP_STATUS A2DP_BuildSinkConfigSbc(const uint8_t* p_src_config,
+                                     const uint8_t* p_sink_cap,
+                                     uint8_t* p_result_sink_config);
+
+// Gets the A2DP SBC codec name for a given |p_codec_info|.
+const char* A2DP_CodecNameSbc(const uint8_t* p_codec_info);
+
+// Checks whether two A2DP SBC codecs |p_codec_info_a| and |p_codec_info_b|
+// have the same type.
+// Returns true if the two codecs have the same type, otherwise false.
+bool A2DP_CodecTypeEqualsSbc(const uint8_t* p_codec_info_a,
+                             const uint8_t* p_codec_info_b);
+
+// Checks whether two A2DP SBC codecs |p_codec_info_a| and |p_codec_info_b|
+// are exactly the same.
+// Returns true if the two codecs are exactly the same, otherwise false.
+// If the codec type is not SBC, the return value is false.
+bool A2DP_CodecEqualsSbc(const uint8_t* p_codec_info_a,
+                         const uint8_t* p_codec_info_b);
+
+// Checks whether two A2DP SBC codecs |p_codec_info_a| and |p_codec_info_b|
+// are different, and A2DP requires reconfiguration.
+// Returns true if the two codecs are different and A2DP requires
+// reconfiguration, otherwise false.
+// If the codec type is not SBC, the return value is true.
+bool A2DP_CodecRequiresReconfigSbc(const uint8_t* p_codec_info_a,
+                                   const uint8_t* p_codec_info_b);
+
+// Checks if an A2DP SBC codec config |p_codec_config| matches an A2DP SBC
+// codec capabilities |p_codec_caps|.
+// Returns true if the codec config is supported, otherwise false.
+bool A2DP_CodecConfigMatchesCapabilitiesSbc(const uint8_t* p_codec_config,
+                                            const uint8_t* p_codec_caps);
+
+// Gets the track sampling frequency value for the A2DP SBC codec.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the track sampling frequency on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackFrequencySbc(const uint8_t* p_codec_info);
+
+// Gets the channel count for the A2DP SBC codec.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the channel count on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackChannelCountSbc(const uint8_t* p_codec_info);
+
+// Gets the number of subbands for the A2DP SBC codec.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the number of subbands on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetNumberOfSubbandsSbc(const uint8_t* p_codec_info);
+
+// Gets the number of blocks for the A2DP SBC codec.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the number of blocks on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetNumberOfBlocksSbc(const uint8_t* p_codec_info);
+
+// Gets the allocation method code for the A2DP SBC codec.
+// The actual value is codec-specific.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the allocation method code on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetAllocationMethodCodeSbc(const uint8_t* p_codec_info);
+
+// Gets the channel mode code for the A2DP SBC codec.
+// The actual value is codec-specific.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the channel mode code on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetChannelModeCodeSbc(const uint8_t* p_codec_info);
+
+// Gets the sampling frequency code for the A2DP SBC codec.
+// The actual value is codec-specific.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the sampling frequency code on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetSamplingFrequencyCodeSbc(const uint8_t* p_codec_info);
+
+// Gets the minimum bitpool for the A2DP SBC codec.
+// The actual value is codec-specific.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the minimum bitpool on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetMinBitpoolSbc(const uint8_t* p_codec_info);
+
+// Gets the maximum bitpool for the A2DP SBC codec.
+// The actual value is codec-specific.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the maximum bitpool on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetMaxBitpoolSbc(const uint8_t* p_codec_info);
+
+// Gets the channel type for the A2DP SBC Sink codec:
+// 1 for mono, or 3 for dual/stereo/joint.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the channel type on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetSinkTrackChannelTypeSbc(const uint8_t* p_codec_info);
+
+// Computes the number of frames to process in a time window for the A2DP
+// SBC sink codec. |time_interval_ms| is the time interval (in milliseconds).
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the number of frames to process on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetSinkFramesCountToProcessSbc(uint64_t time_interval_ms,
+                                        const uint8_t* p_codec_info);
+
+// Gets the A2DP SBC audio data timestamp from an audio packet.
+// |p_codec_info| contains the codec information.
+// |p_data| contains the audio data.
+// The timestamp is stored in |p_timestamp|.
+// Returns true on success, otherwise false.
+bool A2DP_GetPacketTimestampSbc(const uint8_t* p_codec_info,
+                                const uint8_t* p_data, uint32_t* p_timestamp);
+
+// Builds A2DP SBC codec header for audio data.
+// |p_codec_info| contains the codec information.
+// |p_buf| contains the audio data.
+// |frames_per_packet| is the number of frames in this packet.
+// Returns true on success, otherwise false.
+bool A2DP_BuildCodecHeaderSbc(const uint8_t* p_codec_info, BT_HDR* p_buf,
+                              uint16_t frames_per_packet);
+
+// Decodes and displays SBC codec info (for debugging).
+// |p_codec_info| is a pointer to the SBC codec_info to decode and display.
+void A2DP_DumpCodecInfoSbc(const uint8_t* p_codec_info);
+
+// Gets the A2DP SBC encoder interface that can be used to encode and prepare
+// A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP SBC encoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterfaceSbc(
+    const uint8_t* p_codec_info);
+
+// Adjusts the A2DP SBC codec, based on local support and Bluetooth
+// specification.
+// |p_codec_info| contains the codec information to adjust.
+// Returns true if |p_codec_info| is valid and supported, otherwise false.
+bool A2DP_AdjustCodecSbc(uint8_t* p_codec_info);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* A2DP_SBC_H */
diff --git a/bt/stack/include/a2dp_sbc_encoder.h b/bt/stack/include/a2dp_sbc_encoder.h
new file mode 100644
index 0000000..5272215
--- /dev/null
+++ b/bt/stack/include/a2dp_sbc_encoder.h
@@ -0,0 +1,78 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+//
+// Interface to the A2DP SBC Encoder
+//
+
+#ifndef A2DP_SBC_ENCODER_H
+#define A2DP_SBC_ENCODER_H
+
+#include "a2dp_api.h"
+#include "osi/include/time.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Initialize the A2DP SBC encoder.
+// If |is_peer_edr| is true, the A2DP peer device supports EDR.
+// If |peer_supports_3mbps| is true, the A2DP peer device supports 3Mbps EDR.
+// The encoder initialization parameters are in |p_init_params|.
+// |enqueue_callback} is the callback for enqueueing the encoded audio data.
+void a2dp_sbc_encoder_init(bool is_peer_edr, bool peer_supports_3mbps,
+                           const tA2DP_ENCODER_INIT_PARAMS* p_init_params,
+                           a2dp_source_read_callback_t read_callback,
+                           a2dp_source_enqueue_callback_t enqueue_callback);
+
+// Update the A2DP SBC encoder.
+// The encoder update parameters are in |p_update_params|.
+void a2dp_sbc_encoder_update(
+    const tA2DP_ENCODER_UPDATE_PARAMS* p_update_params);
+
+// Cleanup the A2DP SBC encoder.
+void a2dp_sbc_encoder_cleanup(void);
+
+// Initialize the feeding for the A2DP SBC encoder.
+// The feeding initialization parameters are in |p_feeding_params|.
+void a2dp_sbc_feeding_init(const tA2DP_FEEDING_PARAMS* p_feeding_params);
+
+// Reset the feeding for the A2DP SBC encoder.
+void a2dp_sbc_feeding_reset(void);
+
+// Flush the feeding for the A2DP SBC encoder.
+void a2dp_sbc_feeding_flush(void);
+
+// Get the A2DP SBC encoder interval (in milliseconds).
+period_ms_t a2dp_sbc_get_encoder_interval_ms(void);
+
+// Prepare and send A2DP SBC encoded frames.
+// |timestamp_us| is the current timestamp (in microseconds).
+void a2dp_sbc_send_frames(uint64_t timestamp_us);
+
+// Dump SBC codec-related statistics.
+// |fd| is the file descriptor to use to dump the statistics information
+// in user-friendly test format.
+void a2dp_sbc_debug_codec_dump(int fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // A2DP_SBC_ENCODER_H
diff --git a/bt/stack/include/a2dp_sbc_up_sample.h b/bt/stack/include/a2dp_sbc_up_sample.h
new file mode 100644
index 0000000..946a6d4
--- /dev/null
+++ b/bt/stack/include/a2dp_sbc_up_sample.h
@@ -0,0 +1,171 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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 is the interface to utility functions for dealing with SBC data
+ *  frames and codec capabilities.
+ *
+ ******************************************************************************/
+#ifndef A2DP_SBC_UP_SAMPLE_H
+#define A2DP_SBC_UP_SAMPLE_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+**
+** Function         a2dp_sbc_init_up_sample
+**
+** Description      initialize the up sample
+**
+**                  src_sps: samples per second (source audio data)
+**                  dst_sps: samples per second (converted audio data)
+**                  bits: number of bits per pcm sample
+**                  n_channels: number of channels (i.e. mono(1), stereo(2)...)
+**
+** Returns          none
+**
+*******************************************************************************/
+void a2dp_sbc_init_up_sample(uint32_t src_sps, uint32_t dst_sps, uint8_t bits,
+                             uint8_t n_channels);
+
+/*******************************************************************************
+**
+** Function         a2dp_sbc_up_sample
+**
+** Description      Given the source (p_src) audio data and
+**                  source speed (src_sps, samples per second),
+**                  This function converts it to audio data in the desired
+**                  format
+**
+**                  p_src: the data buffer that holds the source audio data
+**                  p_dst: the data buffer to hold the converted audio data
+**                  src_samples: The number of source samples (number of bytes)
+**                  dst_samples: The size of p_dst (number of bytes)
+**
+** Note:            An AE reported an issue with this function.
+**                  When called with a2dp_sbc_up_sample(src, uint8_array_dst..)
+**                  the byte before uint8_array_dst may get overwritten.
+**                  Using uint16_array_dst avoids the problem.
+**                  This issue is related to endian-ness and is hard to resolve
+**                  in a generic manner.
+** **************** Please use uint16 array as dst.
+**
+** Returns          The number of bytes used in p_dst
+**                  The number of bytes used in p_src (in *p_ret)
+**
+*******************************************************************************/
+int a2dp_sbc_up_sample(void* p_src, void* p_dst, uint32_t src_samples,
+                       uint32_t dst_samples, uint32_t* p_ret);
+
+/*******************************************************************************
+**
+** Function         a2dp_sbc_up_sample_16s (16bits-stereo)
+**
+** Description      Given the source (p_src) audio data and
+**                  source speed (src_sps, samples per second),
+**                  This function converts it to audio data in the desired
+**                  format
+**
+**                  p_src: the data buffer that holds the source audio data
+**                  p_dst: the data buffer to hold the converted audio data
+**                  src_samples: The number of source samples (in uint of 4
+**                               bytes)
+**                  dst_samples: The size of p_dst (in uint of 4 bytes)
+**
+** Returns          The number of bytes used in p_dst
+**                  The number of bytes used in p_src (in *p_ret)
+**
+*******************************************************************************/
+int a2dp_sbc_up_sample_16s(void* p_src, void* p_dst, uint32_t src_samples,
+                           uint32_t dst_samples, uint32_t* p_ret);
+
+/*******************************************************************************
+**
+** Function         a2dp_sbc_up_sample_16m (16bits-mono)
+**
+** Description      Given the source (p_src) audio data and
+**                  source speed (src_sps, samples per second),
+**                  This function converts it to audio data in the desired
+**                  format
+**
+**                  p_src: the data buffer that holds the source audio data
+**                  p_dst: the data buffer to hold the converted audio data
+**                  src_samples: The number of source samples (in uint of 2
+**                               bytes)
+**                  dst_samples: The size of p_dst (in uint of 2 bytes)
+**
+** Returns          The number of bytes used in p_dst
+**                  The number of bytes used in p_src (in *p_ret)
+**
+*******************************************************************************/
+int a2dp_sbc_up_sample_16m(void* p_src, void* p_dst, uint32_t src_samples,
+                           uint32_t dst_samples, uint32_t* p_ret);
+
+/*******************************************************************************
+**
+** Function         a2dp_sbc_up_sample_8s (8bits-stereo)
+**
+** Description      Given the source (p_src) audio data and
+**                  source speed (src_sps, samples per second),
+**                  This function converts it to audio data in the desired
+**                  format
+**
+**                  p_src: the data buffer that holds the source audio data
+**                  p_dst: the data buffer to hold the converted audio data
+**                  src_samples: The number of source samples (in uint of 2
+**                               bytes)
+**                  dst_samples: The size of p_dst (in uint of 2 bytes)
+**
+** Returns          The number of bytes used in p_dst
+**                  The number of bytes used in p_src (in *p_ret)
+**
+*******************************************************************************/
+int a2dp_sbc_up_sample_8s(void* p_src, void* p_dst, uint32_t src_samples,
+                          uint32_t dst_samples, uint32_t* p_ret);
+
+/*******************************************************************************
+**
+** Function         a2dp_sbc_up_sample_8m (8bits-mono)
+**
+** Description      Given the source (p_src) audio data and
+**                  source speed (src_sps, samples per second),
+**                  This function converts it to audio data in the desired
+**                  format
+**
+**                  p_src: the data buffer that holds the source audio data
+**                  p_dst: the data buffer to hold the converted audio data
+**                  src_samples: The number of source samples (number of bytes)
+**                  dst_samples: The size of p_dst (number of bytes)
+**
+** Returns          The number of bytes used in p_dst
+**                  The number of bytes used in p_src (in *p_ret)
+**
+*******************************************************************************/
+int a2dp_sbc_up_sample_8m(void* p_src, void* p_dst, uint32_t src_samples,
+                          uint32_t dst_samples, uint32_t* p_ret);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* A2DP_SBC_UP_SAMPLE_H */
diff --git a/bt/stack/include/a2dp_vendor.h b/bt/stack/include/a2dp_vendor.h
new file mode 100644
index 0000000..b4f67dc
--- /dev/null
+++ b/bt/stack/include/a2dp_vendor.h
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Vendor Specific A2DP Codecs Support
+ */
+
+#ifndef A2DP_VENDOR_H
+#define A2DP_VENDOR_H
+
+#include <stdbool.h>
+#include "a2dp_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Offset for A2DP vendor codec */
+#define A2DP_VENDOR_CODEC_START_IDX 3
+
+/* Offset for Vendor ID for A2DP vendor codec */
+#define A2DP_VENDOR_CODEC_VENDOR_ID_START_IDX A2DP_VENDOR_CODEC_START_IDX
+
+/* Offset for Codec ID for A2DP vendor codec */
+#define A2DP_VENDOR_CODEC_CODEC_ID_START_IDX \
+  (A2DP_VENDOR_CODEC_VENDOR_ID_START_IDX + sizeof(uint32_t))
+
+// Gets the A2DP vendor codec name for a given |codec_sep_index|.
+const char* A2DP_VendorCodecSepIndexStr(tA2DP_CODEC_SEP_INDEX codec_sep_index);
+
+// Initializes A2DP vendor codec-specific information into |tAVDT_CFG|
+// configuration entry pointed by |p_cfg|. The selected codec is defined by
+// |codec_sep_index|.
+// Returns true on success, otherwise false.
+bool A2DP_VendorInitCodecConfig(tA2DP_CODEC_SEP_INDEX codec_sep_index,
+                                tAVDT_CFG* p_cfg);
+
+// Checks whether the codec capabilities contain a valid A2DP vendor-specific
+// Source codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid
+// vendor-specific codec, otherwise false.
+bool A2DP_IsVendorSourceCodecValid(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid A2DP vendor-specific
+// Sink codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid
+// vendor-specific codec, otherwise false.
+bool A2DP_IsVendorSinkCodecValid(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid peer A2DP
+// vendor-specific Source codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid
+// vendor-specific codec, otherwise false.
+bool A2DP_IsVendorPeerSourceCodecValid(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid peer A2DP
+// vendor-specific Sink codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid
+// vendor-specific codec, otherwise false.
+bool A2DP_IsVendorPeerSinkCodecValid(const uint8_t* p_codec_info);
+
+// Checks whether a vendor-specific A2DP Source codec is supported.
+// |p_codec_info| contains information about the codec capabilities.
+// Returns true if the vendor-specific A2DP Source codec is supported,
+// otherwise false.
+bool A2DP_IsVendorSourceCodecSupported(const uint8_t* p_codec_info);
+
+// Checks whether a vendor-specific A2DP Sink codec is supported.
+// |p_codec_info| contains information about the codec capabilities.
+// Returns true if the vendor-specific A2DP Sink codec is supported,
+// otherwise false.
+bool A2DP_IsVendorSinkCodecSupported(const uint8_t* p_codec_info);
+
+// Checks whether a vendor-specific A2DP Source codec for a peer Source device
+// is supported.
+// |p_codec_info| contains information about the codec capabilities of the
+// peer device.
+// Returns true if the vendor-specific A2DP Source codec for a peer Source
+// device is supported, otherwise false.
+bool A2DP_IsVendorPeerSourceCodecSupported(const uint8_t* p_codec_info);
+
+// Sets A2DB vendor-specific Source codec state based on the Source codec index
+// |source_codec_sep_index| and the feeding information from
+// |p_feeding_params|.
+// The state with the codec capabilities is stored in |p_codec_info|.
+// Returns true on success, otherwise false.
+// |source_codec_sep_index| should be in the range
+// [A2DP_CODEC_SEP_INDEX_SOURCE_MIN, A2DP_CODEC_SEP_INDEX_SOURCE_MAX),
+// otherwise the return value is false.
+bool A2DP_VendorSetSourceCodec(tA2DP_CODEC_SEP_INDEX source_codec_sep_index,
+                               const tA2DP_FEEDING_PARAMS* p_feeding_params,
+                               uint8_t* p_codec_info);
+
+// Builds a vendor-specific A2DP preferred Sink capability from a vendor
+// Source capability.
+// |p_src_cap| is the Source capability to use.
+// |p_pref_cfg| is the result Sink capability to store.
+// Returns |A2DP_SUCCESS| on success, otherwise the corresponding A2DP error
+// status code.
+tA2DP_STATUS A2DP_VendorBuildSrc2SinkConfig(const uint8_t* p_src_cap,
+                                            uint8_t* p_pref_cfg);
+
+// Builds a vendor-specific A2DP Sink codec config from a vendor-specific
+// Source codec config and Sink codec capability.
+// |p_src_config| is the A2DP vendor-specific Source codec config to use.
+// |p_sink_cap| is the A2DP vendor-specific Sink codec capability to use.
+// The result is stored in |p_result_sink_config|.
+// Returns |A2DP_SUCCESS| on success, otherwise the corresponding A2DP error
+// status code.
+tA2DP_STATUS A2DP_VendorBuildSinkConfig(const uint8_t* p_src_config,
+                                        const uint8_t* p_sink_cap,
+                                        uint8_t* p_result_sink_config);
+
+// Gets the Vendor ID for the vendor-specific A2DP codec.
+// |p_codec_info| contains information about the codec capabilities.
+// Returns the Vendor ID for the vendor-specific A2DP codec.
+uint32_t A2DP_VendorCodecGetVendorId(const uint8_t* p_codec_info);
+
+// Gets the Codec ID for the vendor-specific A2DP codec.
+// |p_codec_info| contains information about the codec capabilities.
+// Returns the Codec ID for the vendor-specific A2DP codec.
+uint16_t A2DP_VendorCodecGetCodecId(const uint8_t* p_codec_info);
+
+// Checks whether the A2DP vendor-specific data packets should contain RTP
+// header. |content_protection_enabled| is true if Content Protection is
+// enabled. |p_codec_info| contains information about the codec capabilities.
+// Returns true if the A2DP vendor-specific data packets should contain RTP
+// header, otherwise false.
+bool A2DP_VendorUsesRtpHeader(bool content_protection_enabled,
+                              const uint8_t* p_codec_info);
+
+// Gets the A2DP vendor-specific codec name for a given |p_codec_info|.
+const char* A2DP_VendorCodecName(const uint8_t* p_codec_info);
+
+// Checks whether two A2DP vendor-specific codecs |p_codec_info_a| and
+// |p_codec_info_b| have the same type.
+// Returns true if the two codecs have the same type, otherwise false.
+// If the codec type is not recognized, the return value is false.
+bool A2DP_VendorCodecTypeEquals(const uint8_t* p_codec_info_a,
+                                const uint8_t* p_codec_info_b);
+
+// Checks whether two A2DP vendor-specific codecs |p_codec_info_a| and
+// |p_codec_info_b| are exactly the same.
+// Returns true if the two codecs are exactly the same, otherwise false.
+// If the codec type is not recognized, the return value is false.
+bool A2DP_VendorCodecEquals(const uint8_t* p_codec_info_a,
+                            const uint8_t* p_codec_info_b);
+
+// Checks whether two A2DP vendor-specific codecs |p_codec_info_a| and
+// |p_codec_info_b| are different, and A2DP requires reconfiguration.
+// Returns true if the two codecs are different and A2DP requires
+// reconfiguration, otherwise false.
+// If the codec type is not recognized, the return value is true.
+bool A2DP_VendorCodecRequiresReconfig(const uint8_t* p_codec_info_a,
+                                      const uint8_t* p_codec_info_b);
+
+// Checks if an A2DP vendor-specific codec config |p_codec_config| matches
+// an A2DP vendor-specific codec capabilities |p_codec_caps|.
+// Returns true if the codec config is supported, otherwise false.
+bool A2DP_VendorCodecConfigMatchesCapabilities(const uint8_t* p_codec_config,
+                                               const uint8_t* p_codec_caps);
+
+// Gets the track sampling frequency value for the A2DP vendor-specific codec.
+// |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
+// Returns the track sampling frequency on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackFrequency(const uint8_t* p_codec_info);
+
+// Gets the channel count for the A2DP vendor-specific codec.
+// |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
+// Returns the channel count on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackChannelCount(const uint8_t* p_codec_info);
+
+// Gets the number of subbands for the A2DP vendor-specific codec.
+// |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
+// Returns the number of subbands on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetNumberOfSubbands(const uint8_t* p_codec_info);
+
+// Gets the number of blocks for the A2DP vendor-specific codec.
+// |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
+// Returns the number of blocks on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetNumberOfBlocks(const uint8_t* p_codec_info);
+
+// Gets the allocation method code for the A2DP vendor-specific codec.
+// The actual value is codec-specific.
+// |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
+// Returns the allocation method code on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetAllocationMethodCode(const uint8_t* p_codec_info);
+
+// Gets the channel mode code for the A2DP vendor-specific codec.
+// The actual value is codec-specific.
+// |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
+// Returns the channel mode code on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetChannelModeCode(const uint8_t* p_codec_info);
+
+// Gets the sampling frequency code for the A2DP vendor-specific codec.
+// The actual value is codec-specific.
+// |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
+// Returns the sampling frequency code on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetSamplingFrequencyCode(const uint8_t* p_codec_info);
+
+// Gets the minimum bitpool for the A2DP vendor-specific codec.
+// The actual value is codec-specific.
+// |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
+// Returns the minimum bitpool on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetMinBitpool(const uint8_t* p_codec_info);
+
+// Gets the maximum bitpool for the A2DP vendor-specific codec.
+// The actual value is codec-specific.
+// |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
+// Returns the maximum bitpool on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetMaxBitpool(const uint8_t* p_codec_info);
+
+// Gets the channel type for the A2DP vendor-specific Sink codec:
+// 1 for mono, or 3 for dual/stereo/joint.
+// |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
+// Returns the channel type on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetSinkTrackChannelType(const uint8_t* p_codec_info);
+
+// Computes the number of frames to process in a time window for the A2DP
+// vendor-specific Sink codec. |time_interval_ms| is the time interval
+// (in milliseconds).
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the number of frames to process on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetSinkFramesCountToProcess(uint64_t time_interval_ms,
+                                           const uint8_t* p_codec_info);
+
+// Gets the A2DP codec-specific audio data timestamp from an audio packet.
+// |p_codec_info| contains the codec information.
+// |p_data| contains the audio data.
+// The timestamp is stored in |p_timestamp|.
+// Returns true on success, otherwise false.
+bool A2DP_VendorGetPacketTimestamp(const uint8_t* p_codec_info,
+                                   const uint8_t* p_data,
+                                   uint32_t* p_timestamp);
+
+// Builds A2DP vendor-specific codec header for audio data.
+// |p_codec_info| contains the codec information.
+// |p_buf| contains the audio data.
+// |frames_per_packet| is the number of frames in this packet.
+// Returns true on success, otherwise false.
+bool A2DP_VendorBuildCodecHeader(const uint8_t* p_codec_info, BT_HDR* p_buf,
+                                 uint16_t frames_per_packet);
+
+// Gets the A2DP vendor encoder interface that can be used to encode and
+// prepare A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP vendor encoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterface(
+    const uint8_t* p_codec_info);
+
+// Adjusts the A2DP vendor-specific codec, based on local support and Bluetooth
+// specification.
+// |p_codec_info| contains the codec information to adjust.
+// Returns true if |p_codec_info| is valid and supported, otherwise false.
+bool A2DP_VendorAdjustCodec(uint8_t* p_codec_info);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* A2DP_VENDOR_H */
diff --git a/bt/stack/include/avct_api.h b/bt/stack/include/avct_api.h
new file mode 100644
index 0000000..f16228f
--- /dev/null
+++ b/bt/stack/include/avct_api.h
@@ -0,0 +1,279 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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 interface file contains the interface to the Audio Video Control
+ *  Transport Protocol (AVCTP).
+ *
+ ******************************************************************************/
+#ifndef AVCT_API_H
+#define AVCT_API_H
+
+#include "bt_types.h"
+#include "bt_target.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+/* API function return value result codes. */
+#define AVCT_SUCCESS                0       /* Function successful */
+#define AVCT_NO_RESOURCES           1       /* Not enough resources */
+#define AVCT_BAD_HANDLE             2       /* Bad handle */
+#define AVCT_PID_IN_USE             3       /* PID already in use */
+#define AVCT_NOT_OPEN               4       /* Connection not open */
+
+/* PSM for AVCT. */
+#define AVCT_PSM                    0x0017
+#define AVCT_BR_PSM                 0x001B
+
+/* Protocol revision numbers */
+#define AVCT_REV_1_0                0x0100
+#define AVCT_REV_1_2                0x0102
+#define AVCT_REV_1_3                0x0103
+#define AVCT_REV_1_4                0x0104
+
+/* the layer_specific settings */
+#define AVCT_DATA_CTRL              0x0001    /* for the control channel */
+#define AVCT_DATA_BROWSE            0x0002    /* for the browsing channel */
+#define AVCT_DATA_PARTIAL           0x0100    /* Only have room for a partial message */
+
+#define AVCT_MIN_CONTROL_MTU        48  /* Per the AVRC spec, minimum MTU for the control channel */
+#define AVCT_MIN_BROWSE_MTU         335 /* Per the AVRC spec, minimum MTU for the browsing channel */
+
+/* Message offset.  The number of bytes needed by the protocol stack for the
+** protocol headers of an AVCTP message packet.
+*/
+#define AVCT_MSG_OFFSET             15
+#define AVCT_BROWSE_OFFSET          17 /* the default offset for browsing channel */
+
+/* Connection role. */
+#define AVCT_INT                    0       /* Initiator connection */
+#define AVCT_ACP                    1       /* Acceptor connection */
+
+/* Control role. */
+#define AVCT_TARGET                 1       /* target  */
+#define AVCT_CONTROL                2       /* controller  */
+#define AVCT_PASSIVE                4       /* If conflict, allow the other side to succeed  */
+
+/* Command/Response indicator. */
+#define AVCT_CMD                    0       /* Command message */
+#define AVCT_RSP                    2       /* Response message */
+#define AVCT_REJ                    3       /* Message rejected */
+
+/* Control callback events. */
+#define AVCT_CONNECT_CFM_EVT        0       /* Connection confirm */
+#define AVCT_CONNECT_IND_EVT        1       /* Connection indication */
+#define AVCT_DISCONNECT_CFM_EVT     2       /* Disconnect confirm */
+#define AVCT_DISCONNECT_IND_EVT     3       /* Disconnect indication */
+#define AVCT_CONG_IND_EVT           4       /* Congestion indication */
+#define AVCT_UNCONG_IND_EVT         5       /* Uncongestion indication */
+#define AVCT_BROWSE_CONN_CFM_EVT    6       /* Browse Connection confirm */
+#define AVCT_BROWSE_CONN_IND_EVT    7       /* Browse Connection indication */
+#define AVCT_BROWSE_DISCONN_CFM_EVT 8       /* Browse Disconnect confirm */
+#define AVCT_BROWSE_DISCONN_IND_EVT 9       /* Browse Disconnect indication */
+#define AVCT_BROWSE_CONG_IND_EVT    10      /* Congestion indication */
+#define AVCT_BROWSE_UNCONG_IND_EVT  11      /* Uncongestion indication */
+
+
+/* General purpose failure result code for callback events. */
+#define AVCT_RESULT_FAIL            5
+
+/*****************************************************************************
+**  Type Definitions
+*****************************************************************************/
+
+/* Control callback function. */
+typedef void (tAVCT_CTRL_CBACK)(uint8_t handle, uint8_t event, uint16_t result,
+                                BD_ADDR peer_addr);
+
+/* Message callback function */
+/* p_pkt->layer_specific is AVCT_DATA_CTRL or AVCT_DATA_BROWSE */
+typedef void (tAVCT_MSG_CBACK)(uint8_t handle, uint8_t label, uint8_t cr,
+                               BT_HDR *p_pkt);
+
+/* Structure used by AVCT_CreateConn. */
+typedef struct {
+    tAVCT_CTRL_CBACK    *p_ctrl_cback;      /* Control callback */
+    tAVCT_MSG_CBACK     *p_msg_cback;       /* Message callback */
+    uint16_t            pid;                /* Profile ID */
+    uint8_t             role;               /* Initiator/acceptor role */
+    uint8_t             control;        /* Control role (Control/Target) */
+} tAVCT_CC;
+
+/*****************************************************************************
+**  External Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function         AVCT_Register
+**
+** Description      This is the system level registration function for the
+**                  AVCTP protocol.  This function initializes AVCTP and
+**                  prepares the protocol stack for its use.  This function
+**                  must be called once by the system or platform using AVCTP
+**                  before the other functions of the API an be used.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void AVCT_Register(uint16_t mtu, uint16_t mtu_br, uint8_t sec_mask);
+
+/*******************************************************************************
+**
+** Function         AVCT_Deregister
+**
+** Description      This function is called to deregister use AVCTP protocol.
+**                  It is called when AVCTP is no longer being used by any
+**                  application in the system.  Before this function can be
+**                  called, all connections must be removed with
+**                  AVCT_RemoveConn().
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void AVCT_Deregister(void);
+
+/*******************************************************************************
+**
+** Function         AVCT_CreateConn
+**
+** Description      Create an AVCTP connection.  There are two types of
+**                  connections, initiator and acceptor, as determined by
+**                  the p_cc->role parameter.  When this function is called to
+**                  create an initiator connection, an AVCTP connection to
+**                  the peer device is initiated if one does not already exist.
+**                  If an acceptor connection is created, the connection waits
+**                  passively for an incoming AVCTP connection from a peer device.
+**
+**
+** Returns          AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVCT_CreateConn(uint8_t *p_handle, tAVCT_CC *p_cc,
+                              BD_ADDR peer_addr);
+
+/*******************************************************************************
+**
+** Function         AVCT_RemoveConn
+**
+** Description      Remove an AVCTP connection.  This function is called when
+**                  the application is no longer using a connection.  If this
+**                  is the last connection to a peer the L2CAP channel for AVCTP
+**                  will be closed.
+**
+**
+** Returns          AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVCT_RemoveConn(uint8_t handle);
+
+/*******************************************************************************
+**
+** Function         AVCT_CreateBrowse
+**
+** Description      Create an AVCTP connection.  There are two types of
+**                  connections, initiator and acceptor, as determined by
+**                  the p_cc->role parameter.  When this function is called to
+**                  create an initiator connection, an AVCTP connection to
+**                  the peer device is initiated if one does not already exist.
+**                  If an acceptor connection is created, the connection waits
+**                  passively for an incoming AVCTP connection from a peer device.
+**
+**
+** Returns          AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVCT_CreateBrowse(uint8_t handle, uint8_t role);
+
+/*******************************************************************************
+**
+** Function         AVCT_RemoveBrowse
+**
+** Description      Remove an AVCTP connection.  This function is called when
+**                  the application is no longer using a connection.  If this
+**                  is the last connection to a peer the L2CAP channel for AVCTP
+**                  will be closed.
+**
+**
+** Returns          AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVCT_RemoveBrowse(uint8_t handle);
+
+/*******************************************************************************
+**
+** Function         AVCT_GetBrowseMtu
+**
+** Description      Get the peer_mtu for the AVCTP Browse channel of the given
+**                  connection.
+**
+** Returns          the peer browsing channel MTU.
+**
+*******************************************************************************/
+extern uint16_t AVCT_GetBrowseMtu (uint8_t handle);
+
+/*******************************************************************************
+**
+** Function         AVCT_GetPeerMtu
+**
+** Description      Get the peer_mtu for the AVCTP channel of the given
+**                  connection.
+**
+** Returns          the peer MTU size.
+**
+*******************************************************************************/
+extern uint16_t AVCT_GetPeerMtu (uint8_t handle);
+
+/*******************************************************************************
+**
+** Function         AVCT_MsgReq
+**
+** Description      Send an AVCTP message to a peer device.  In calling
+**                  AVCT_MsgReq(), the application should keep track of the
+**                  congestion state of AVCTP as communicated with events
+**                  AVCT_CONG_IND_EVT and AVCT_UNCONG_IND_EVT.   If the
+**                  application calls AVCT_MsgReq() when AVCTP is congested
+**                  the message may be discarded.  The application may make its
+**                  first call to AVCT_MsgReq() after it receives an
+**                  AVCT_CONNECT_CFM_EVT or AVCT_CONNECT_IND_EVT on control channel or
+**                  AVCT_BROWSE_CONN_CFM_EVT or AVCT_BROWSE_CONN_IND_EVT on browsing channel.
+**
+**                  p_msg->layer_specific must be set to
+**                  AVCT_DATA_CTRL for control channel traffic;
+**                  AVCT_DATA_BROWSE for for browse channel traffic.
+**
+** Returns          AVCT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVCT_MsgReq(uint8_t handle, uint8_t label, uint8_t cr, BT_HDR *p_msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* AVCT_API_H */
diff --git a/bt/stack/include/avdt_api.h b/bt/stack/include/avdt_api.h
new file mode 100644
index 0000000..b4f6365
--- /dev/null
+++ b/bt/stack/include/avdt_api.h
@@ -0,0 +1,904 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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 interface file contains the interface to the Audio Video
+ *  Distribution Transport Protocol (AVDTP).
+ *
+ ******************************************************************************/
+#ifndef AVDT_API_H
+#define AVDT_API_H
+
+#include "bt_types.h"
+#include "bt_target.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+#ifndef AVDT_VERSION
+#define AVDT_VERSION                0x0102
+#endif
+#define AVDT_VERSION_SYNC           0x0103
+
+/* Maximum size in bytes of the codec capabilities information element. */
+#define AVDT_CODEC_SIZE             20
+
+/* API function return value result codes. */
+#define AVDT_SUCCESS                0       /* Function successful */
+#define AVDT_BAD_PARAMS             1       /* Invalid parameters */
+#define AVDT_NO_RESOURCES           2       /* Not enough resources */
+#define AVDT_BAD_HANDLE             3       /* Bad handle */
+#define AVDT_BUSY                   4       /* A procedure is already in progress */
+#define AVDT_WRITE_FAIL             5       /* Write failed */
+
+/* The index to access the codec type in codec_info[]. */
+#define AVDT_CODEC_TYPE_INDEX       2
+
+/* The size in bytes of a Adaptation Layer header. */
+#define AVDT_AL_HDR_SIZE         3
+
+/* The size in bytes of a media packet header. */
+#define AVDT_MEDIA_HDR_SIZE         12
+
+/* The handle is used when reporting MULTI_AV specific events */
+#define AVDT_MULTI_AV_HANDLE        0xFF
+
+/* The number of bytes needed by the protocol stack for the protocol headers
+** of a media packet.  This is the size of the media packet header, the
+** L2CAP packet header and HCI header.
+*/
+#define AVDT_MEDIA_OFFSET           23
+
+/* The marker bit is used by the application to mark significant events such
+** as frame boundaries in the data stream.  This constant is used to check or
+** set the marker bit in the m_pt parameter of an AVDT_WriteReq()
+** or AVDT_DATA_IND_EVT.
+*/
+#define AVDT_MARKER_SET             0x80
+
+/* SEP Type.  This indicates the stream endpoint type. */
+#define AVDT_TSEP_SRC               0       /* Source SEP */
+#define AVDT_TSEP_SNK               1       /* Sink SEP */
+#define AVDT_TSEP_INVALID           3       /* Invalid SEP */
+
+/* initiator/acceptor role for adaption */
+#define AVDT_INT                0       /* initiator */
+#define AVDT_ACP                1       /* acceptor */
+
+/* Media Type of the stream endpoint */
+/* The value does not include the reserved 4-bit LSBs field */
+#define AVDT_MEDIA_TYPE_AUDIO   0       /* Audio SEP */
+#define AVDT_MEDIA_TYPE_VIDEO   1       /* Video SEP */
+#define AVDT_MEDIA_TYPE_MULTI   2       /* Multimedia SEP */
+
+/* for reporting packets */
+#define AVDT_RTCP_PT_SR         200     /* the packet type - SR (Sender Report) */
+#define AVDT_RTCP_PT_RR         201     /* the packet type - RR (Receiver Report) */
+#define AVDT_RTCP_PT_SDES       202     /* the packet type - SDES (Source Description) */
+typedef uint8_t AVDT_REPORT_TYPE;
+
+#define AVDT_RTCP_SDES_CNAME    1       /* SDES item CNAME */
+#ifndef AVDT_MAX_CNAME_SIZE
+#define AVDT_MAX_CNAME_SIZE     28
+#endif
+
+/* Protocol service capabilities.  This indicates the protocol service
+** capabilities of a stream endpoint.  This value is a mask.
+** Multiple values can be combined with a bitwise OR.
+*/
+#define AVDT_PSC_TRANS              (1<<1)  /* Media transport */
+#define AVDT_PSC_REPORT             (1<<2)  /* Reporting */
+#define AVDT_PSC_RECOV              (1<<3)  /* Recovery */
+#define AVDT_PSC_HDRCMP             (1<<5)  /* Header compression */
+#define AVDT_PSC_MUX                (1<<6)  /* Multiplexing */
+#define AVDT_PSC_DELAY_RPT          (1<<8)  /* Delay Report */
+
+/* Recovery type.  This indicates the recovery type. */
+#define AVDT_RECOV_RFC2733          1       /* RFC2733 recovery */
+
+/* Header compression capabilities.  This indicates the header compression
+** capabilities.  This value is a mask.  Multiple values can be combined
+** with a bitwise OR.
+*/
+#define AVDT_HDRCMP_MEDIA           (1<<5)  /* Available for media packets */
+#define AVDT_HDRCMP_RECOV           (1<<6)  /* Available for recovery packets */
+#define AVDT_HDRCMP_BACKCH          (1<<7)  /* Back channel supported */
+
+/* Multiplexing capabilities mask. */
+#define AVDT_MUX_FRAG               (1<<7)  /* Allow Adaptation Layer Fragmentation */
+
+/* Application service category. This indicates the application
+** service category.
+*/
+#define AVDT_ASC_PROTECT            4       /* Content protection */
+#define AVDT_ASC_CODEC              7       /* Codec */
+
+/* the content protection IDs assigned by BT SIG */
+#define AVDT_CP_SCMS_T_ID     0x0002
+#define AVDT_CP_DTCP_ID       0x0001
+
+#define AVDT_CP_LOSC                  2
+#define AVDT_CP_INFO_LEN              3
+
+#define AVDT_CP_SCMS_COPY_MASK        3
+#define AVDT_CP_SCMS_COPY_FREE        2
+#define AVDT_CP_SCMS_COPY_ONCE        1
+#define AVDT_CP_SCMS_COPY_NEVER       0
+
+/* Error codes.  The following are error codes defined in the AVDTP and GAVDP
+** specifications.  These error codes communicate protocol errors between
+** AVDTP and the application.  More detailed descriptions of the error codes
+** and their appropriate use can be found in the AVDTP and GAVDP specifications.
+** These error codes are unrelated to the result values returned by the
+** AVDTP API functions.
+*/
+#define AVDT_ERR_HEADER             0x01    /* Bad packet header format */
+#define AVDT_ERR_LENGTH             0x11    /* Bad packet length */
+#define AVDT_ERR_SEID               0x12    /* Invalid SEID */
+#define AVDT_ERR_IN_USE             0x13    /* The SEP is in use */
+#define AVDT_ERR_NOT_IN_USE         0x14    /* The SEP is not in use */
+#define AVDT_ERR_CATEGORY           0x17    /* Bad service category */
+#define AVDT_ERR_PAYLOAD            0x18    /* Bad payload format */
+#define AVDT_ERR_NSC                0x19    /* Requested command not supported */
+#define AVDT_ERR_INVALID_CAP        0x1A    /* Reconfigure attempted invalid capabilities */
+#define AVDT_ERR_RECOV_TYPE         0x22    /* Requested recovery type not defined */
+#define AVDT_ERR_MEDIA_TRANS        0x23    /* Media transport capability not correct */
+#define AVDT_ERR_RECOV_FMT          0x25    /* Recovery service capability not correct */
+#define AVDT_ERR_ROHC_FMT           0x26    /* Header compression service capability not correct */
+#define AVDT_ERR_CP_FMT             0x27    /* Content protection service capability not correct */
+#define AVDT_ERR_MUX_FMT            0x28    /* Multiplexing service capability not correct */
+#define AVDT_ERR_UNSUP_CFG          0x29    /* Configuration not supported */
+#define AVDT_ERR_BAD_STATE          0x31    /* Message cannot be processed in this state */
+#define AVDT_ERR_REPORT_FMT         0x65    /* Report service capability not correct */
+#define AVDT_ERR_SERVICE            0x80    /* Invalid service category */
+#define AVDT_ERR_RESOURCE           0x81    /* Insufficient resources */
+#define AVDT_ERR_INVALID_MCT        0xC1    /* Invalid Media Codec Type */
+#define AVDT_ERR_UNSUP_MCT          0xC2    /* Unsupported Media Codec Type */
+#define AVDT_ERR_INVALID_LEVEL      0xC3    /* Invalid Level */
+#define AVDT_ERR_UNSUP_LEVEL        0xC4    /* Unsupported Level */
+#define AVDT_ERR_INVALID_CP         0xE0    /* Invalid Content Protection Type */
+#define AVDT_ERR_INVALID_FORMAT     0xE1    /* Invalid Content Protection format */
+
+/* Additional error codes.  This indicates error codes used by AVDTP
+** in addition to the ones defined in the specifications.
+*/
+#define AVDT_ERR_CONNECT            0x07    /* Connection failed. */
+#define AVDT_ERR_TIMEOUT            0x08    /* Response timeout. */
+
+/* Control callback events. */
+#define AVDT_DISCOVER_CFM_EVT       0       /* Discover confirm */
+#define AVDT_GETCAP_CFM_EVT         1       /* Get capabilities confirm */
+#define AVDT_OPEN_CFM_EVT           2       /* Open confirm */
+#define AVDT_OPEN_IND_EVT           3       /* Open indication */
+#define AVDT_CONFIG_IND_EVT         4       /* Configuration indication */
+#define AVDT_START_CFM_EVT          5       /* Start confirm */
+#define AVDT_START_IND_EVT          6       /* Start indication */
+#define AVDT_SUSPEND_CFM_EVT        7       /* Suspend confirm */
+#define AVDT_SUSPEND_IND_EVT        8       /* Suspend indication */
+#define AVDT_CLOSE_CFM_EVT          9       /* Close confirm */
+#define AVDT_CLOSE_IND_EVT          10      /* Close indication */
+#define AVDT_RECONFIG_CFM_EVT       11      /* Reconfiguration confirm */
+#define AVDT_RECONFIG_IND_EVT       12      /* Reconfiguration indication */
+#define AVDT_SECURITY_CFM_EVT       13      /* Security confirm */
+#define AVDT_SECURITY_IND_EVT       14      /* Security indication */
+#define AVDT_WRITE_CFM_EVT          15      /* Write confirm */
+#define AVDT_CONNECT_IND_EVT        16      /* Signaling channel connected */
+#define AVDT_DISCONNECT_IND_EVT     17      /* Signaling channel disconnected */
+#define AVDT_REPORT_CONN_EVT        18      /* Reporting channel connected */
+#define AVDT_REPORT_DISCONN_EVT     19      /* Reporting channel disconnected */
+#define AVDT_DELAY_REPORT_EVT       20      /* Delay report received */
+#define AVDT_DELAY_REPORT_CFM_EVT   21      /* Delay report response received */
+
+#define AVDT_MAX_EVT                (AVDT_DELAY_REPORT_CFM_EVT)
+
+/* PSM for AVDT */
+#define AVDT_PSM                    0x0019
+
+/* Nonsupported protocol command messages.  This value is used in tAVDT_CS */
+#define AVDT_NSC_SUSPEND            0x01    /* Suspend command not supported */
+#define AVDT_NSC_RECONFIG           0x02    /* Reconfigure command not supported */
+#define AVDT_NSC_SECURITY           0x04    /* Security command not supported */
+
+/*****************************************************************************
+**  Type Definitions
+*****************************************************************************/
+
+typedef struct
+{
+    uint32_t ntp_sec;        /* NTP time: seconds relative to 0h UTC on 1 January 1900 */
+    uint32_t ntp_frac;       /* NTP time: the fractional part */
+    uint32_t rtp_time;       /* timestamp in RTP header */
+    uint32_t pkt_count;      /* sender's packet count: since starting transmission
+                             * up until the time this SR packet was generated. */
+    uint32_t octet_count;    /* sender's octet count: same comment */
+} tAVDT_SENDER_INFO;
+
+typedef struct
+{
+    uint8_t frag_lost;      /* fraction lost since last RR */
+    uint32_t packet_lost;    /* cumulative number of packets lost since the beginning */
+    uint32_t seq_num_rcvd;   /* extended highest sequence number received */
+    uint32_t jitter;         /* interarrival jitter */
+    uint32_t lsr;            /* last SR timestamp */
+    uint32_t dlsr;           /* delay since last SR */
+} tAVDT_REPORT_BLK;
+
+typedef union
+{
+    tAVDT_SENDER_INFO   sr;
+    tAVDT_REPORT_BLK    rr;
+    uint8_t             cname[AVDT_MAX_CNAME_SIZE + 1];
+} tAVDT_REPORT_DATA;
+
+/* This structure contains parameters which are set at registration. */
+typedef struct {
+    uint16_t    ctrl_mtu;   /* L2CAP MTU of the AVDTP signaling channel */
+    uint8_t     ret_tout;   /* AVDTP signaling retransmission timeout */
+    uint8_t     sig_tout;   /* AVDTP signaling message timeout */
+    uint8_t     idle_tout;  /* AVDTP idle signaling channel timeout */
+    uint8_t     sec_mask;   /* Security mask for BTM_SetSecurityLevel() */
+} tAVDT_REG;
+
+/* This structure contains the SEP information.  This information is
+** transferred during the discovery procedure.
+*/
+typedef struct {
+    bool        in_use;         /* true if stream is currently in use */
+    uint8_t     seid;           /* Stream endpoint identifier */
+    uint8_t     media_type;     /* Media type: AVDT_MEDIA_TYPE_* */
+    uint8_t     tsep;           /* SEP type */
+} tAVDT_SEP_INFO;
+
+/* This structure contains the SEP configuration. */
+typedef struct {
+    uint8_t codec_info[AVDT_CODEC_SIZE];        /* Codec capabilities array */
+    uint8_t protect_info[AVDT_PROTECT_SIZE];    /* Content protection capabilities */
+    uint8_t num_codec;                          /* Number of media codec information elements */
+    uint8_t num_protect;                        /* Number of content protection information elements */
+    uint16_t psc_mask;                           /* Protocol service capabilities mask */
+    uint8_t recov_type;                         /* Recovery type */
+    uint8_t recov_mrws;                         /* Maximum recovery window size */
+    uint8_t recov_mnmp;                         /* Recovery maximum number of media packets */
+    uint8_t hdrcmp_mask;                        /* Header compression capabilities */
+} tAVDT_CFG;
+
+/* Header structure for callback event parameters. */
+typedef struct {
+    uint8_t         err_code;           /* Zero if operation succeeded; nonzero if operation failed */
+    uint8_t         err_param;          /* Error parameter included for some events */
+    uint8_t         label;              /* Transaction label */
+    uint8_t         seid;               /* For internal use only */
+    uint8_t         sig_id;             /* For internal use only */
+    uint8_t         ccb_idx;            /* For internal use only */
+} tAVDT_EVT_HDR;
+
+/* This data structure is associated with the AVDT_GETCAP_CFM_EVT,
+** AVDT_RECONFIG_IND_EVT, and AVDT_RECONFIG_CFM_EVT.
+*/
+typedef struct {
+    tAVDT_EVT_HDR   hdr;                /* Event header */
+    tAVDT_CFG       *p_cfg;             /* Pointer to configuration for this SEP */
+} tAVDT_CONFIG;
+
+/* This data structure is associated with the AVDT_CONFIG_IND_EVT. */
+typedef struct {
+    tAVDT_EVT_HDR   hdr;                /* Event header */
+    tAVDT_CFG       *p_cfg;             /* Pointer to configuration for this SEP */
+    uint8_t         int_seid;           /* Stream endpoint ID of stream initiating the operation */
+} tAVDT_SETCONFIG;
+
+/* This data structure is associated with the AVDT_OPEN_IND_EVT and AVDT_OPEN_CFM_EVT. */
+typedef struct {
+    tAVDT_EVT_HDR   hdr;                /* Event header */
+    uint16_t        peer_mtu;           /* Transport channel L2CAP MTU of the peer */
+    uint16_t        lcid;               /* L2CAP LCID for media channel */
+} tAVDT_OPEN;
+
+/* This data structure is associated with the AVDT_SECURITY_IND_EVT
+** and AVDT_SECURITY_CFM_EVT.
+*/
+typedef struct {
+    tAVDT_EVT_HDR   hdr;                /* Event header */
+    uint8_t         *p_data;            /* Pointer to security data */
+    uint16_t        len;                /* Length in bytes of the security data */
+} tAVDT_SECURITY;
+
+/* This data structure is associated with the AVDT_DISCOVER_CFM_EVT. */
+typedef struct {
+    tAVDT_EVT_HDR   hdr;                /* Event header */
+    tAVDT_SEP_INFO  *p_sep_info;        /* Pointer to SEP information */
+    uint8_t         num_seps;           /* Number of stream endpoints */
+} tAVDT_DISCOVER;
+
+/* This data structure is associated with the AVDT_DELAY_REPORT_EVT. */
+typedef struct {
+    tAVDT_EVT_HDR   hdr;                /* Event header */
+    uint16_t        delay;              /* Delay value */
+} tAVDT_DELAY_RPT;
+
+/* Union of all control callback event data structures */
+typedef union {
+    tAVDT_EVT_HDR       hdr;
+    tAVDT_DISCOVER      discover_cfm;
+    tAVDT_CONFIG        getcap_cfm;
+    tAVDT_OPEN          open_cfm;
+    tAVDT_OPEN          open_ind;
+    tAVDT_SETCONFIG     config_ind;
+    tAVDT_EVT_HDR       start_cfm;
+    tAVDT_EVT_HDR       suspend_cfm;
+    tAVDT_EVT_HDR       close_cfm;
+    tAVDT_CONFIG        reconfig_cfm;
+    tAVDT_CONFIG        reconfig_ind;
+    tAVDT_SECURITY      security_cfm;
+    tAVDT_SECURITY      security_ind;
+    tAVDT_EVT_HDR       connect_ind;
+    tAVDT_EVT_HDR       disconnect_ind;
+    tAVDT_EVT_HDR       report_conn;
+    tAVDT_DELAY_RPT     delay_rpt_cmd;
+} tAVDT_CTRL;
+
+/* This is the control callback function.  This function passes control events
+** to the application.  This function is required for all registered stream
+** endpoints and for the AVDT_DiscoverReq() and AVDT_GetCapReq() functions.
+**
+*/
+typedef void (tAVDT_CTRL_CBACK)(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+                                tAVDT_CTRL *p_data);
+
+/* This is the data callback function.  It is executed when AVDTP has a media
+** packet ready for the application.  This function is required for SNK
+** endpoints and not applicable for SRC endpoints.
+*/
+typedef void (tAVDT_SINK_DATA_CBACK)(uint8_t handle, BT_HDR *p_pkt,
+                                     uint32_t time_stamp, uint8_t m_pt);
+
+#if (AVDT_REPORTING == TRUE)
+/* This is the report callback function.  It is executed when AVDTP has a reporting
+** packet ready for the application.  This function is required for streams
+** created with AVDT_PSC_REPORT.
+*/
+typedef void (tAVDT_REPORT_CBACK)(uint8_t handle, AVDT_REPORT_TYPE type,
+                                tAVDT_REPORT_DATA *p_data);
+#endif
+
+typedef uint16_t (tAVDT_GETCAP_REQ) (BD_ADDR bd_addr, uint8_t seid, tAVDT_CFG *p_cfg, tAVDT_CTRL_CBACK *p_cback);
+
+/* This structure contains information required when a stream is created.
+** It is passed to the AVDT_CreateStream() function.
+*/
+typedef struct {
+    tAVDT_CFG           cfg;            /* SEP configuration */
+    tAVDT_CTRL_CBACK    *p_ctrl_cback;  /* Control callback function */
+    tAVDT_SINK_DATA_CBACK *p_sink_data_cback; /* Sink data callback function */
+#if (AVDT_REPORTING == TRUE)
+    tAVDT_REPORT_CBACK  *p_report_cback;/* Report callback function. */
+#endif
+    uint16_t            mtu;            /* The L2CAP MTU of the transport channel */
+    uint16_t            flush_to;       /* The L2CAP flush timeout of the transport channel */
+    uint8_t             tsep;           /* SEP type */
+    uint8_t             media_type;     /* Media type: AVDT_MEDIA_TYPE_* */
+    uint16_t            nsc_mask;       /* Nonsupported protocol command messages */
+} tAVDT_CS;
+
+/* AVDT data option mask is used in the write request */
+#define AVDT_DATA_OPT_NONE      0x00         /* No option still add RTP header */
+#define AVDT_DATA_OPT_NO_RTP   (0x01 << 0)   /* Skip adding RTP header */
+
+typedef uint8_t tAVDT_DATA_OPT_MASK;
+
+
+
+/*****************************************************************************
+**  External Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function         AVDT_Register
+**
+** Description      This is the system level registration function for the
+**                  AVDTP protocol.  This function initializes AVDTP and
+**                  prepares the protocol stack for its use.  This function
+**                  must be called once by the system or platform using AVDTP
+**                  before the other functions of the API an be used.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void AVDT_Register(tAVDT_REG *p_reg, tAVDT_CTRL_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function         AVDT_Deregister
+**
+** Description      This function is called to deregister use AVDTP protocol.
+**                  It is called when AVDTP is no longer being used by any
+**                  application in the system.  Before this function can be
+**                  called, all streams must be removed with AVDT_RemoveStream().
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void AVDT_Deregister(void);
+
+/*******************************************************************************
+**
+** Function         AVDT_AbortReq
+**
+** Description      Trigger Abort request to pass AVDTP Abort related mandatory
+**                  PTS Test case.
+**
+** Returns          void.
+**
+*******************************************************************************/
+extern void AVDT_AbortReq(uint8_t handle);
+
+/*******************************************************************************
+**
+** Function         AVDT_CreateStream
+**
+** Description      Create a stream endpoint.  After a stream endpoint is
+**                  created an application can initiate a connection between
+**                  this endpoint and an endpoint on a peer device.  In
+**                  addition, a peer device can discover, get the capabilities,
+**                  and connect to this endpoint.
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVDT_CreateStream(uint8_t *p_handle, tAVDT_CS *p_cs);
+
+/*******************************************************************************
+**
+** Function         AVDT_RemoveStream
+**
+** Description      Remove a stream endpoint.  This function is called when
+**                  the application is no longer using a stream endpoint.
+**                  If this function is called when the endpoint is connected
+**                  the connection is closed and then the stream endpoint
+**                  is removed.
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVDT_RemoveStream(uint8_t handle);
+
+/*******************************************************************************
+**
+** Function         AVDT_DiscoverReq
+**
+** Description      This function initiates a connection to the AVDTP service
+**                  on the peer device, if not already present, and discovers
+**                  the stream endpoints on the peer device.  (Please note
+**                  that AVDTP discovery is unrelated to SDP discovery).
+**                  This function can be called at any time regardless of whether
+**                  there is an AVDTP connection to the peer device.
+**
+**                  When discovery is complete, an AVDT_DISCOVER_CFM_EVT
+**                  is sent to the application via its callback function.
+**                  The application must not call AVDT_GetCapReq() or
+**                  AVDT_DiscoverReq() again to the same device until
+**                  discovery is complete.
+**
+**                  The memory addressed by sep_info is allocated by the
+**                  application.  This memory is written to by AVDTP as part
+**                  of the discovery procedure.  This memory must remain
+**                  accessible until the application receives the
+**                  AVDT_DISCOVER_CFM_EVT.
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVDT_DiscoverReq(BD_ADDR bd_addr, tAVDT_SEP_INFO *p_sep_info,
+                               uint8_t max_seps, tAVDT_CTRL_CBACK *p_cback);
+
+
+/*******************************************************************************
+**
+** Function         AVDT_GetCapReq
+**
+** Description      This function initiates a connection to the AVDTP service
+**                  on the peer device, if not already present, and gets the
+**                  capabilities of a stream endpoint on the peer device.
+**                  This function can be called at any time regardless of
+**                  whether there is an AVDTP connection to the peer device.
+**
+**                  When the procedure is complete, an AVDT_GETCAP_CFM_EVT is
+**                  sent to the application via its callback function.  The
+**                  application must not call AVDT_GetCapReq() or
+**                  AVDT_DiscoverReq() again until the procedure is complete.
+**
+**                  The memory pointed to by p_cfg is allocated by the
+**                  application.  This memory is written to by AVDTP as part
+**                  of the get capabilities procedure.  This memory must
+**                  remain accessible until the application receives
+**                  the AVDT_GETCAP_CFM_EVT.
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVDT_GetCapReq(BD_ADDR bd_addr, uint8_t seid, tAVDT_CFG *p_cfg,
+                             tAVDT_CTRL_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function         AVDT_GetAllCapReq
+**
+** Description      This function initiates a connection to the AVDTP service
+**                  on the peer device, if not already present, and gets the
+**                  capabilities of a stream endpoint on the peer device.
+**                  This function can be called at any time regardless of
+**                  whether there is an AVDTP connection to the peer device.
+**
+**                  When the procedure is complete, an AVDT_GETCAP_CFM_EVT is
+**                  sent to the application via its callback function.  The
+**                  application must not call AVDT_GetCapReq() or
+**                  AVDT_DiscoverReq() again until the procedure is complete.
+**
+**                  The memory pointed to by p_cfg is allocated by the
+**                  application.  This memory is written to by AVDTP as part
+**                  of the get capabilities procedure.  This memory must
+**                  remain accessible until the application receives
+**                  the AVDT_GETCAP_CFM_EVT.
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVDT_GetAllCapReq(BD_ADDR bd_addr, uint8_t seid, tAVDT_CFG *p_cfg,
+                                tAVDT_CTRL_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function         AVDT_DelayReport
+**
+** Description      This functions sends a Delay Report to the peer device
+**                  that is associated with a particular SEID.
+**                  This function is called by SNK device.
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVDT_DelayReport(uint8_t handle, uint8_t seid, uint16_t delay);
+
+/*******************************************************************************
+**
+** Function         AVDT_OpenReq
+**
+** Description      This function initiates a connection to the AVDTP service
+**                  on the peer device, if not already present, and connects
+**                  to a stream endpoint on a peer device.  When the connection
+**                  is completed, an AVDT_OPEN_CFM_EVT is sent to the
+**                  application via the control callback function for this handle.
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVDT_OpenReq(uint8_t handle, BD_ADDR bd_addr, uint8_t seid,
+                           tAVDT_CFG *p_cfg);
+
+
+/*******************************************************************************
+**
+** Function         AVDT_ConfigRsp
+**
+** Description      Respond to a configure request from the peer device.  This
+**                  function must be called if the application receives an
+**                  AVDT_CONFIG_IND_EVT through its control callback.
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVDT_ConfigRsp(uint8_t handle, uint8_t label, uint8_t error_code,
+                             uint8_t category);
+
+/*******************************************************************************
+**
+** Function         AVDT_StartReq
+**
+** Description      Start one or more stream endpoints.  This initiates the
+**                  transfer of media packets for the streams.  All stream
+**                  endpoints must previously be opened.  When the streams
+**                  are started, an AVDT_START_CFM_EVT is sent to the
+**                  application via the control callback function for each stream.
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVDT_StartReq(uint8_t *p_handles, uint8_t num_handles);
+
+/*******************************************************************************
+**
+** Function         AVDT_SuspendReq
+**
+** Description      Suspend one or more stream endpoints. This suspends the
+**                  transfer of media packets for the streams.  All stream
+**                  endpoints must previously be open and started.  When the
+**                  streams are suspended, an AVDT_SUSPEND_CFM_EVT is sent to
+**                  the application via the control callback function for
+**                  each stream.
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVDT_SuspendReq(uint8_t *p_handles, uint8_t num_handles);
+
+/*******************************************************************************
+**
+** Function         AVDT_CloseReq
+**
+** Description      Close a stream endpoint.  This stops the transfer of media
+**                  packets and closes the transport channel associated with
+**                  this stream endpoint.  When the stream is closed, an
+**                  AVDT_CLOSE_CFM_EVT is sent to the application via the
+**                  control callback function for this handle.
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVDT_CloseReq(uint8_t handle);
+
+/*******************************************************************************
+**
+** Function         AVDT_ReconfigReq
+**
+** Description      Reconfigure a stream endpoint.  This allows the application
+**                  to change the codec or content protection capabilities of
+**                  a stream endpoint after it has been opened.  This function
+**                  can only be called if the stream is opened but not started
+**                  or if the stream has been suspended.  When the procedure
+**                  is completed, an AVDT_RECONFIG_CFM_EVT is sent to the
+**                  application via the control callback function for this handle.
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVDT_ReconfigReq(uint8_t handle, tAVDT_CFG *p_cfg);
+
+/*******************************************************************************
+**
+** Function         AVDT_ReconfigRsp
+**
+** Description      Respond to a reconfigure request from the peer device.
+**                  This function must be called if the application receives
+**                  an AVDT_RECONFIG_IND_EVT through its control callback.
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVDT_ReconfigRsp(uint8_t handle, uint8_t label, uint8_t error_code,
+                               uint8_t category);
+
+/*******************************************************************************
+**
+** Function         AVDT_SecurityReq
+**
+** Description      Send a security request to the peer device.  When the
+**                  security procedure is completed, an AVDT_SECURITY_CFM_EVT
+**                  is sent to the application via the control callback function
+**                  for this handle.  (Please note that AVDTP security procedures
+**                  are unrelated to Bluetooth link level security.)
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVDT_SecurityReq(uint8_t handle, uint8_t *p_data, uint16_t len);
+
+/*******************************************************************************
+**
+** Function         AVDT_SecurityRsp
+**
+** Description      Respond to a security request from the peer device.
+**                  This function must be called if the application receives
+**                  an AVDT_SECURITY_IND_EVT through its control callback.
+**                  (Please note that AVDTP security procedures are unrelated
+**                  to Bluetooth link level security.)
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVDT_SecurityRsp(uint8_t handle, uint8_t label, uint8_t error_code,
+                               uint8_t *p_data, uint16_t len);
+
+/*******************************************************************************
+**
+** Function         AVDT_WriteReq
+**
+** Description      Send a media packet to the peer device.  The stream must
+**                  be started before this function is called.  Also, this
+**                  function can only be called if the stream is a SRC.
+**
+**                  When AVDTP has sent the media packet and is ready for the
+**                  next packet, an AVDT_WRITE_CFM_EVT is sent to the
+**                  application via the control callback.  The application must
+**                  wait for the AVDT_WRITE_CFM_EVT before it makes the next
+**                  call to AVDT_WriteReq().  If the applications calls
+**                  AVDT_WriteReq() before it receives the event the packet
+**                  will not be sent.  The application may make its first call
+**                  to AVDT_WriteReq() after it receives an AVDT_START_CFM_EVT
+**                  or AVDT_START_IND_EVT.
+**
+**                  The application passes the packet using the BT_HDR structure.
+**                  This structure is described in section 2.1.  The offset
+**                  field must be equal to or greater than AVDT_MEDIA_OFFSET.
+**                  This allows enough space in the buffer for the L2CAP and
+**                  AVDTP headers.
+**
+**                  The memory pointed to by p_pkt must be a GKI buffer
+**                  allocated by the application.  This buffer will be freed
+**                  by the protocol stack; the application must not free
+**                  this buffer.
+**
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVDT_WriteReq(uint8_t handle, BT_HDR *p_pkt, uint32_t time_stamp,
+                            uint8_t m_pt);
+/*******************************************************************************
+**
+** Function         AVDT_WriteReqOpt
+**
+** Description      Send a media packet to the peer device.  The stream must
+**                  be started before this function is called.  Also, this
+**                  function can only be called if the stream is a SRC
+**
+**                  When AVDTP has sent the media packet and is ready for the
+**                  next packet, an AVDT_WRITE_CFM_EVT is sent to the
+**                  application via the control callback.  The application must
+**                  wait for the AVDT_WRITE_CFM_EVT before it makes the next
+**                  call to AVDT_WriteReq().  If the applications calls
+**                  AVDT_WriteReq() before it receives the event the packet
+**                  will not be sent.  The application may make its first call
+**                  to AVDT_WriteReq() after it receives an AVDT_START_CFM_EVT
+**                  or AVDT_START_IND_EVT.
+**
+**                  The application passes the packet using the BT_HDR structure
+**                  This structure is described in section 2.1.  The offset
+**                  field must be equal to or greater than AVDT_MEDIA_OFFSET
+**                  (if NO_RTP is specified, L2CAP_MIN_OFFSET can be used)
+**                  This allows enough space in the buffer for the L2CAP and
+**                  AVDTP headers.
+**
+**                  The memory pointed to by p_pkt must be a GKI buffer
+**                  allocated by the application.  This buffer will be freed
+**                  by the protocol stack; the application must not free
+**                  this buffer.
+**
+**                  The opt parameter allows passing specific options like:
+**                  - NO_RTP : do not add the RTP header to buffer
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVDT_WriteReqOpt(uint8_t handle, BT_HDR *p_pkt, uint32_t time_stamp,
+                               uint8_t m_pt, tAVDT_DATA_OPT_MASK opt);
+
+/*******************************************************************************
+**
+** Function         AVDT_ConnectReq
+**
+** Description      This function initiates an AVDTP signaling connection
+**                  to the peer device.  When the connection is completed, an
+**                  AVDT_CONNECT_IND_EVT is sent to the application via its
+**                  control callback function.  If the connection attempt fails
+**                  an AVDT_DISCONNECT_IND_EVT is sent.  The security mask
+**                  parameter overrides the outgoing security mask set in
+**                  AVDT_Register().
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVDT_ConnectReq(BD_ADDR bd_addr, uint8_t sec_mask,
+                              tAVDT_CTRL_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function         AVDT_DisconnectReq
+**
+** Description      This function disconnect an AVDTP signaling connection
+**                  to the peer device.  When disconnected an
+**                  AVDT_DISCONNECT_IND_EVT is sent to the application via its
+**                  control callback function.
+**
+** Returns          AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVDT_DisconnectReq(BD_ADDR bd_addr, tAVDT_CTRL_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function         AVDT_GetL2CapChannel
+**
+** Description      Get the L2CAP CID used by the handle.
+**
+** Returns          CID if successful, otherwise 0.
+**
+*******************************************************************************/
+extern uint16_t AVDT_GetL2CapChannel(uint8_t handle);
+
+/*******************************************************************************
+**
+** Function         AVDT_GetSignalChannel
+**
+** Description      Get the L2CAP CID used by the signal channel of the given handle.
+**
+** Returns          CID if successful, otherwise 0.
+**
+*******************************************************************************/
+extern uint16_t AVDT_GetSignalChannel(uint8_t handle, BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function         AVDT_SendReport
+**
+** Description
+**
+**
+**
+** Returns
+**
+*******************************************************************************/
+extern uint16_t AVDT_SendReport(uint8_t handle, AVDT_REPORT_TYPE type,
+                              tAVDT_REPORT_DATA *p_data);
+
+/******************************************************************************
+**
+** Function         AVDT_SetTraceLevel
+**
+** Description      Sets the trace level for AVDT. If 0xff is passed, the
+**                  current trace level is returned.
+**
+**                  Input Parameters:
+**                      new_level:  The level to set the AVDT tracing to:
+**                      0xff-returns the current setting.
+**                      0-turns off tracing.
+**                      >= 1-Errors.
+**                      >= 2-Warnings.
+**                      >= 3-APIs.
+**                      >= 4-Events.
+**                      >= 5-Debug.
+**
+** Returns          The new trace level or current trace level if
+**                  the input parameter is 0xff.
+**
+******************************************************************************/
+extern uint8_t AVDT_SetTraceLevel (uint8_t new_level);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* AVDT_API_H */
diff --git a/bt/stack/include/avdtc_api.h b/bt/stack/include/avdtc_api.h
new file mode 100644
index 0000000..82591c5
--- /dev/null
+++ b/bt/stack/include/avdtc_api.h
@@ -0,0 +1,229 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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 interface file contains the interface AVDTP conformance API.  These
+ *  additional API functions and callback events are provided for
+ *  conformance testing purposes only.  They are not intended to be used by
+ *  an application.
+ *
+ ******************************************************************************/
+#ifndef AVDT_CAPI_H
+#define AVDT_CAPI_H
+
+#include "avdt_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* start AVDTC events here to distinguish from AVDT events */
+#define AVDTC_EVT_BEGIN             0x80
+
+#define AVDTC_DISCOVER_IND_EVT      (0 + AVDTC_EVT_BEGIN)   /* Discover indication */
+#define AVDTC_GETCAP_IND_EVT        (1 + AVDTC_EVT_BEGIN)   /* Get capabilities indication */
+#define AVDTC_SETCONFIG_CFM_EVT     (2 + AVDTC_EVT_BEGIN)   /* Set configuration confirm */
+#define AVDTC_GETCONFIG_IND_EVT     (3 + AVDTC_EVT_BEGIN)   /* Get configuration indication */
+#define AVDTC_GETCONFIG_CFM_EVT     (4 + AVDTC_EVT_BEGIN)   /* Get configuration confirm */
+#define AVDTC_OPEN_IND_EVT          (5 + AVDTC_EVT_BEGIN)   /* Open indication */
+#define AVDTC_START_IND_EVT         (6 + AVDTC_EVT_BEGIN)   /* Start indication */
+#define AVDTC_CLOSE_IND_EVT         (7 + AVDTC_EVT_BEGIN)   /* Close indication */
+#define AVDTC_SUSPEND_IND_EVT       (8 + AVDTC_EVT_BEGIN)   /* Suspend indication */
+#define AVDTC_ABORT_IND_EVT         (9 + AVDTC_EVT_BEGIN)   /* Abort indication */
+#define AVDTC_ABORT_CFM_EVT         (10 + AVDTC_EVT_BEGIN)  /* Abort confirm */
+
+typedef struct {
+    tAVDT_EVT_HDR   hdr;                        /* Event header */
+    uint8_t         seid_list[AVDT_NUM_SEPS];   /* Array of SEID values */
+    uint8_t         num_seps;                   /* Number of values in array */
+} tAVDT_MULTI;
+
+/* Union of all control callback event data structures */
+typedef union {
+    tAVDT_EVT_HDR       hdr;
+    tAVDT_CONFIG        getconfig_cfm;
+    tAVDT_MULTI         start_ind;
+    tAVDT_MULTI         suspend_ind;
+} tAVDTC_CTRL;
+
+typedef void tAVDTC_CTRL_CBACK(uint8_t handle, BD_ADDR bd_addr, uint8_t event, tAVDTC_CTRL *p_data);
+
+/*******************************************************************************
+**
+** Function         AVDTC_Init
+**
+** Description      This function is called to begin using the conformance API.
+**                  It must be called after AVDT_Register() and before any
+**                  other API or conformance API functions are called.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void AVDTC_Init(tAVDTC_CTRL_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function         AVDTC_DiscoverRsp
+**
+** Description      Send a discover response.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void AVDTC_DiscoverRsp(BD_ADDR bd_addr, uint8_t label,
+                              tAVDT_SEP_INFO sep_info[], uint8_t num_seps);
+
+/*******************************************************************************
+**
+** Function         AVDTC_GetCapRsp
+**
+** Description     Send a get capabilities response.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void AVDTC_GetCapRsp(BD_ADDR bd_addr, uint8_t label, tAVDT_CFG *p_cap);
+
+/*******************************************************************************
+**
+** Function         AVDTC_GetAllCapRsp
+**
+** Description     Send a get all capabilities response.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void AVDTC_GetAllCapRsp(BD_ADDR bd_addr, uint8_t label, tAVDT_CFG *p_cap);
+
+/*******************************************************************************
+**
+** Function         AVDTC_GetConfigReq
+**
+** Description      Send a get configuration request.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void AVDTC_GetConfigReq(uint8_t handle);
+
+/*******************************************************************************
+**
+** Function         AVDTC_GetConfigRsp
+**
+** Description      Send a get configuration response.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void AVDTC_GetConfigRsp(uint8_t handle, uint8_t label, tAVDT_CFG *p_cfg);
+
+/*******************************************************************************
+**
+** Function         AVDTC_OpenReq
+**
+** Description      Send an open request.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void AVDTC_OpenReq(uint8_t handle);
+
+/*******************************************************************************
+**
+** Function         AVDTC_OpenRsp
+**
+** Description      Send an open response.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void AVDTC_OpenRsp(uint8_t handle, uint8_t label);
+
+/*******************************************************************************
+**
+** Function         AVDTC_StartRsp
+**
+** Description      Send a start response.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void AVDTC_StartRsp(uint8_t *p_handles, uint8_t num_handles, uint8_t label);
+
+/*******************************************************************************
+**
+** Function         AVDTC_CloseRsp
+**
+** Description      Send a close response.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void AVDTC_CloseRsp(uint8_t handle, uint8_t label);
+
+/*******************************************************************************
+**
+** Function         AVDTC_SuspendRsp
+**
+** Description      Send a suspend response.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void AVDTC_SuspendRsp(uint8_t *p_handles, uint8_t num_handles, uint8_t label);
+
+/*******************************************************************************
+**
+** Function         AVDTC_AbortReq
+**
+** Description      Send an abort request.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void AVDTC_AbortReq(uint8_t handle);
+
+/*******************************************************************************
+**
+** Function         AVDTC_AbortRsp
+**
+** Description      Send an abort response.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void AVDTC_AbortRsp(uint8_t handle, uint8_t label);
+
+/*******************************************************************************
+**
+** Function         AVDTC_Rej
+**
+** Description      Send a reject message.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void AVDTC_Rej(uint8_t handle, BD_ADDR bd_addr, uint8_t cmd, uint8_t label,
+                      uint8_t err_code, uint8_t err_param);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVDT_CAPI_H */
diff --git a/bt/stack/include/avrc_api.h b/bt/stack/include/avrc_api.h
new file mode 100644
index 0000000..06a6dc7
--- /dev/null
+++ b/bt/stack/include/avrc_api.h
@@ -0,0 +1,680 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2006-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  nterface to AVRCP Application Programming Interface
+ *
+ ******************************************************************************/
+#ifndef AVRC_API_H
+#define AVRC_API_H
+#include "bt_target.h"
+#include "avct_api.h"
+#include "sdp_api.h"
+#include "avrc_defs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+**  constants
+*****************************************************************************/
+
+/* API function return value result codes. */
+#define AVRC_SUCCESS        AVCT_SUCCESS        /* 0 Function successful */
+#define AVRC_NO_RESOURCES   AVCT_NO_RESOURCES   /* 1 Not enough resources */
+#define AVRC_BAD_HANDLE     AVCT_BAD_HANDLE     /* 2 Bad handle */
+#define AVRC_PID_IN_USE     AVCT_PID_IN_USE     /* 3 PID already in use */
+#define AVRC_NOT_OPEN       AVCT_NOT_OPEN       /* 4 Connection not open */
+#define AVRC_MSG_TOO_BIG    5                   /* 5 the message length exceed the MTU of the browsing channel */
+#define AVRC_FAIL           0x10                /* 0x10 generic failure */
+#define AVRC_BAD_PARAM      0x11                /* 0x11 bad parameter   */
+
+/* Control role - same as AVCT_TARGET/AVCT_CONTROL */
+#define AVRC_CT_TARGET      1                   /* target  */
+#define AVRC_CT_CONTROL     2                   /* controller  */
+#define AVRC_CT_PASSIVE     4                   /* If conflict, allow the other side to succeed  */
+
+/* Connection role */
+#define AVRC_CONN_INT       AVCT_INT            /* initiator */
+#define AVRC_CONN_ACP       AVCT_ACP            /* Acceptor  */
+
+
+/* AVRC CTRL events */
+/* AVRC_OPEN_IND_EVT event is sent when the connection is successfully opened.
+ * This eventis sent in response to an AVRC_Open(). */
+#define AVRC_OPEN_IND_EVT       0
+
+/* AVRC_CLOSE_IND_EVT event is sent when a connection is closed.
+ * This event can result from a call to AVRC_Close() or when the peer closes
+ * the connection.  It is also sent when a connection attempted through
+ * AVRC_Open() fails. */
+#define AVRC_CLOSE_IND_EVT      1
+
+/* AVRC_CONG_IND_EVT event indicates that AVCTP is congested and cannot send
+ * any more messages. */
+#define AVRC_CONG_IND_EVT       2
+
+/* AVRC_UNCONG_IND_EVT event indicates that AVCTP is uncongested and ready to
+ * send messages. */
+#define AVRC_UNCONG_IND_EVT     3
+
+ /* AVRC_BROWSE_OPEN_IND_EVT event is sent when the browse channel is successfully opened.
+ * This eventis sent in response to an AVRC_Open() or AVRC_OpenBrowse() . */
+#define AVRC_BROWSE_OPEN_IND_EVT       4
+
+/* AVRC_BROWSE_CLOSE_IND_EVT event is sent when a browse channel is closed.
+ * This event can result from a call to AVRC_Close(), AVRC_CloseBrowse() or when the peer closes
+ * the connection.  It is also sent when a connection attempted through
+ * AVRC_OpenBrowse() fails. */
+#define AVRC_BROWSE_CLOSE_IND_EVT      5
+
+/* AVRC_BROWSE_CONG_IND_EVT event indicates that AVCTP browse channel is congested and cannot send
+ * any more messages. */
+#define AVRC_BROWSE_CONG_IND_EVT       6
+
+/* AVRC_BROWSE_UNCONG_IND_EVT event indicates that AVCTP browse channel is uncongested and ready to
+ * send messages. */
+#define AVRC_BROWSE_UNCONG_IND_EVT     7
+
+/* AVRC_CMD_TIMEOUT_EVT event indicates timeout waiting for AVRC command response from the peer */
+#define AVRC_CMD_TIMEOUT_EVT           8
+
+/* Supported categories */
+#define AVRC_SUPF_CT_CAT1               0x0001      /* Category 1 */
+#define AVRC_SUPF_CT_CAT2               0x0002      /* Category 2 */
+#define AVRC_SUPF_CT_CAT3               0x0004      /* Category 3 */
+#define AVRC_SUPF_CT_CAT4               0x0008      /* Category 4 */
+#define AVRC_SUPF_CT_APP_SETTINGS       0x0010      /* Player Application Settings */
+#define AVRC_SUPF_CT_GROUP_NAVI         0x0020      /* Group Navigation */
+#define AVRC_SUPF_CT_BROWSE             0x0040      /* Browsing */
+#define AVRC_SUPF_CT_COVER_ART_GET_IMAGE_PROP   0x0080  /* Cover Art, get image property */
+#define AVRC_SUPF_CT_COVER_ART_GET_IMAGE        0x0100  /* Cover Art, get image */
+#define AVRC_SUPF_CT_COVER_ART_GET_THUMBNAIL    0x0200  /* Cover Art, get Linked Thumbnail */
+
+#define AVRC_SUPF_TG_CAT1               0x0001      /* Category 1 */
+#define AVRC_SUPF_TG_CAT2               0x0002      /* Category 2 */
+#define AVRC_SUPF_TG_CAT3               0x0004      /* Category 3 */
+#define AVRC_SUPF_TG_CAT4               0x0008      /* Category 4 */
+#define AVRC_SUPF_TG_APP_SETTINGS       0x0010      /* Player Application Settings */
+#define AVRC_SUPF_TG_GROUP_NAVI         0x0020      /* Group Navigation */
+#define AVRC_SUPF_TG_BROWSE             0x0040      /* Browsing */
+#define AVRC_SUPF_TG_MULTI_PLAYER       0x0080      /* Muliple Media Player */
+#define AVRC_SUPF_TG_PLAYER_COVER_ART   0x0100      /* Cover Art */
+
+#define AVRC_META_SUCCESS               AVRC_SUCCESS
+#define AVRC_META_FAIL                  AVRC_FAIL
+#define AVRC_METADATA_CMD               0x0000
+#define AVRC_METADATA_RESP              0x0001
+
+
+
+/*****************************************************************************
+**  data type definitions
+*****************************************************************************/
+
+/* This data type is used in AVRC_FindService() to initialize the SDP database
+ * to hold the result service search. */
+typedef struct
+{
+    uint32_t            db_len;  /* Length, in bytes, of the discovery database */
+    tSDP_DISCOVERY_DB  *p_db;    /* Pointer to the discovery database */
+    uint16_t            num_attr;/* The number of attributes in p_attrs */
+    uint16_t           *p_attrs; /* The attributes filter. If NULL, AVRCP API sets the attribute filter
+                                  * to be ATTR_ID_SERVICE_CLASS_ID_LIST, ATTR_ID_BT_PROFILE_DESC_LIST,
+                                  * ATTR_ID_SUPPORTED_FEATURES, ATTR_ID_SERVICE_NAME and ATTR_ID_PROVIDER_NAME.
+                                  * If not NULL, the input is taken as the filter. */
+} tAVRC_SDP_DB_PARAMS;
+
+/* This callback function returns service discovery information to the
+ * application after the AVRC_FindService() API function is called.  The
+ * implementation of this callback function must copy the p_service_name
+ * and p_provider_name parameters passed to it as they are not guaranteed
+ * to remain after the callback function exits. */
+typedef void (tAVRC_FIND_CBACK) (uint16_t status);
+
+
+/* This is the control callback function.  This function passes events
+ * listed in Table 20 to the application. */
+typedef void (tAVRC_CTRL_CBACK) (uint8_t handle, uint8_t event, uint16_t result,
+             BD_ADDR peer_addr);
+
+
+/* This is the message callback function.  It is executed when AVCTP has
+ * a message packet ready for the application.  The implementation of this
+ * callback function must copy the tAVRC_MSG structure passed to it as it
+ * is not guaranteed to remain after the callback function exits. */
+typedef void (tAVRC_MSG_CBACK) (uint8_t handle, uint8_t label, uint8_t opcode,
+             tAVRC_MSG *p_msg);
+
+typedef struct
+{
+    tAVRC_CTRL_CBACK    *p_ctrl_cback;  /* pointer to application control callback */
+    tAVRC_MSG_CBACK     *p_msg_cback;   /* pointer to application message callback */
+    uint32_t            company_id;     /* the company ID  */
+    uint8_t             conn;           /* Connection role (Initiator/acceptor) */
+    uint8_t             control;        /* Control role (Control/Target) */
+} tAVRC_CONN_CB;
+
+typedef struct {
+    uint8_t handle;
+    uint8_t label;
+    uint8_t msg_mask;
+} tAVRC_PARAM;
+
+
+/*****************************************************************************
+**  external function declarations
+*****************************************************************************/
+
+/******************************************************************************
+**
+** Function         AVRC_AddRecord
+**
+** Description      This function is called to build an AVRCP SDP record.
+**                  Prior to calling this function the application must
+**                  call SDP_CreateRecord() to create an SDP record.
+**
+**                  Input Parameters:
+**                      service_uuid:  Indicates TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET)
+**                                            or CT(UUID_SERVCLASS_AV_REMOTE_CONTROL)
+**
+**                      p_service_name:  Pointer to a null-terminated character
+**                      string containing the service name.
+**                      If service name is not used set this to NULL.
+**
+**                      p_provider_name:  Pointer to a null-terminated character
+**                      string containing the provider name.
+**                      If provider name is not used set this to NULL.
+**
+**                      categories:  Supported categories.
+**
+**                      sdp_handle:  SDP handle returned by SDP_CreateRecord().
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_NO_RESOURCES if not enough resources to build the SDP record.
+**
+******************************************************************************/
+extern uint16_t AVRC_AddRecord(uint16_t service_uuid,
+                               const char *p_service_name,
+                               const char *p_provider_name,
+                               uint16_t categories, uint32_t sdp_handle,
+                               bool browse_supported,
+                               uint16_t profile_version);
+
+/******************************************************************************
+**
+** Function         AVRC_FindService
+**
+** Description      This function is called by the application to perform service
+**                  discovery and retrieve AVRCP SDP record information from a
+**                  peer device.  Information is returned for the first service
+**                  record found on the server that matches the service UUID.
+**                  The callback function will be executed when service discovery
+**                  is complete.  There can only be one outstanding call to
+**                  AVRC_FindService() at a time; the application must wait for
+**                  the callback before it makes another call to the function.
+**                  The application is responsible for allocating memory for the
+**                  discovery database.  It is recommended that the size of the
+**                  discovery database be at least 300 bytes.  The application
+**                  can deallocate the memory after the callback function has
+**                  executed.
+**
+**                  Input Parameters:
+**                      service_uuid: Indicates TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET)
+**                                           or CT(UUID_SERVCLASS_AV_REMOTE_CONTROL)
+**
+**                      bd_addr:  BD address of the peer device.
+**
+**                      p_db:  SDP discovery database parameters.
+**
+**                      p_cback:  Pointer to the callback function.
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_PARAMS if discovery database parameters are invalid.
+**                  AVRC_NO_RESOURCES if there are not enough resources to
+**                                    perform the service search.
+**
+******************************************************************************/
+extern uint16_t AVRC_FindService(uint16_t service_uuid, BD_ADDR bd_addr,
+                               tAVRC_SDP_DB_PARAMS *p_db, tAVRC_FIND_CBACK *p_cback);
+
+/******************************************************************************
+**
+** Function         AVRC_Open
+**
+** Description      This function is called to open a connection to AVCTP.
+**                  The connection can be either an initiator or acceptor, as
+**                  determined by the p_ccb->stream parameter.
+**                  The connection can be a target, a controller or for both role,
+**                  as determined by the p_ccb->control parameter.
+**                  By definition, a target connection is an acceptor connection
+**                  that waits for an incoming AVCTP connection from the peer.
+**                  The connection remains available to the application until
+**                  the application closes it by calling AVRC_Close().  The
+**                  application does not need to reopen the connection after an
+**                  AVRC_CLOSE_IND_EVT is received.
+**
+**                  Input Parameters:
+**                      p_ccb->company_id: Company Identifier.
+**
+**                      p_ccb->p_ctrl_cback:  Pointer to control callback function.
+**
+**                      p_ccb->p_msg_cback:  Pointer to message callback function.
+**
+**                      p_ccb->conn: AVCTP connection role.  This is set to
+**                      AVCTP_INT for initiator connections and AVCTP_ACP
+**                      for acceptor connections.
+**
+**                      p_ccb->control: Control role.  This is set to
+**                      AVRC_CT_TARGET for target connections, AVRC_CT_CONTROL
+**                      for control connections or (AVRC_CT_TARGET|AVRC_CT_CONTROL)
+**                      for connections that support both roles.
+**
+**                      peer_addr: BD address of peer device.  This value is
+**                      only used for initiator connections; for acceptor
+**                      connections it can be set to NULL.
+**
+**                  Output Parameters:
+**                      p_handle: Pointer to handle.  This parameter is only
+**                                valid if AVRC_SUCCESS is returned.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_NO_RESOURCES if there are not enough resources to open
+**                  the connection.
+**
+******************************************************************************/
+extern uint16_t AVRC_Open(uint8_t *p_handle, tAVRC_CONN_CB *p_ccb,
+                        BD_ADDR_PTR peer_addr);
+
+/******************************************************************************
+**
+** Function         AVRC_Close
+**
+** Description      Close a connection opened with AVRC_Open().
+**                  This function is called when the
+**                  application is no longer using a connection.
+**
+**                  Input Parameters:
+**                      handle: Handle of this connection.
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+extern uint16_t AVRC_Close(uint8_t handle);
+
+/******************************************************************************
+**
+** Function         AVRC_OpenBrowse
+**
+** Description      This function is called to open a browsing connection to AVCTP.
+**                  The connection can be either an initiator or acceptor, as
+**                  determined by the conn_role.
+**                  The handle is returned by a previous call to AVRC_Open.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_NO_RESOURCES if there are not enough resources to open
+**                  the connection.
+**
+******************************************************************************/
+extern uint16_t AVRC_OpenBrowse(uint8_t handle, uint8_t conn_role);
+
+/******************************************************************************
+**
+** Function         AVRC_CloseBrowse
+**
+** Description      Close a connection opened with AVRC_OpenBrowse().
+**                  This function is called when the
+**                  application is no longer using a connection.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+extern uint16_t AVRC_CloseBrowse(uint8_t handle);
+
+/******************************************************************************
+**
+** Function         AVRC_MsgReq
+**
+** Description      This function is used to send the AVRCP byte stream in p_pkt
+**                  down to AVCTP.
+**
+**                  It is expected that p_pkt->offset is at least AVCT_MSG_OFFSET
+**                  p_pkt->layer_specific is AVCT_DATA_CTRL or AVCT_DATA_BROWSE
+**                  p_pkt->event is AVRC_OP_VENDOR, AVRC_OP_PASS_THRU or AVRC_OP_BROWSING
+**                  The above BT_HDR settings are set by the AVRC_Bld* functions.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+extern uint16_t AVRC_MsgReq (uint8_t handle, uint8_t label, uint8_t ctype, BT_HDR *p_pkt);
+
+/******************************************************************************
+**
+** Function         AVRC_UnitCmd
+**
+** Description      Send a UNIT INFO command to the peer device.  This
+**                  function can only be called for controller role connections.
+**                  Any response message from the peer is passed back through
+**                  the tAVRC_MSG_CBACK callback function.
+**
+**                  Input Parameters:
+**                      handle: Handle of this connection.
+**
+**                      label: Transaction label.
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+extern uint16_t AVRC_UnitCmd(uint8_t handle, uint8_t label);
+
+/******************************************************************************
+**
+** Function         AVRC_SubCmd
+**
+** Description      Send a SUBUNIT INFO command to the peer device.  This
+**                  function can only be called for controller role connections.
+**                  Any response message from the peer is passed back through
+**                  the tAVRC_MSG_CBACK callback function.
+**
+**                  Input Parameters:
+**                      handle: Handle of this connection.
+**
+**                      label: Transaction label.
+**
+**                      page: Specifies which part of the subunit type table
+**                      is requested.  For AVRCP it is typically zero.
+**                      Value range is 0-7.
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+extern uint16_t AVRC_SubCmd(uint8_t handle, uint8_t label, uint8_t page);
+
+
+/******************************************************************************
+**
+** Function         AVRC_PassCmd
+**
+** Description      Send a PASS THROUGH command to the peer device.  This
+**                  function can only be called for controller role connections.
+**                  Any response message from the peer is passed back through
+**                  the tAVRC_MSG_CBACK callback function.
+**
+**                  Input Parameters:
+**                      handle: Handle of this connection.
+**
+**                      label: Transaction label.
+**
+**                      p_msg: Pointer to PASS THROUGH message structure.
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+extern uint16_t AVRC_PassCmd(uint8_t handle, uint8_t label, tAVRC_MSG_PASS *p_msg);
+
+/******************************************************************************
+**
+** Function         AVRC_PassRsp
+**
+** Description      Send a PASS THROUGH response to the peer device.  This
+**                  function can only be called for target role connections.
+**                  This function must be called when a PASS THROUGH command
+**                  message is received from the peer through the
+**                  tAVRC_MSG_CBACK callback function.
+**
+**                  Input Parameters:
+**                      handle: Handle of this connection.
+**
+**                      label: Transaction label.  Must be the same value as
+**                      passed with the command message in the callback function.
+**
+**                      p_msg: Pointer to PASS THROUGH message structure.
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+extern uint16_t AVRC_PassRsp(uint8_t handle, uint8_t label, tAVRC_MSG_PASS *p_msg);
+
+
+/******************************************************************************
+**
+** Function         AVRC_VendorCmd
+**
+** Description      Send a VENDOR DEPENDENT command to the peer device.  This
+**                  function can only be called for controller role connections.
+**                  Any response message from the peer is passed back through
+**                  the tAVRC_MSG_CBACK callback function.
+**
+**                  Input Parameters:
+**                      handle: Handle of this connection.
+**
+**                      label: Transaction label.
+**
+**                      p_msg: Pointer to VENDOR DEPENDENT message structure.
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+extern uint16_t AVRC_VendorCmd(uint8_t handle, uint8_t label, tAVRC_MSG_VENDOR *p_msg);
+
+
+/******************************************************************************
+**
+** Function         AVRC_VendorRsp
+**
+** Description      Send a VENDOR DEPENDENT response to the peer device.  This
+**                  function can only be called for target role connections.
+**                  This function must be called when a VENDOR DEPENDENT
+**                  command message is received from the peer through the
+**                  tAVRC_MSG_CBACK callback function.
+**
+**                  Input Parameters:
+**                      handle: Handle of this connection.
+**
+**                      label: Transaction label.  Must be the same value as
+**                      passed with the command message in the callback function.
+**
+**                      p_msg: Pointer to VENDOR DEPENDENT message structure.
+**
+**                  Output Parameters:
+**                      None.
+**
+** Returns          AVRC_SUCCESS if successful.
+**                  AVRC_BAD_HANDLE if handle is invalid.
+**
+******************************************************************************/
+extern uint16_t AVRC_VendorRsp(uint8_t handle, uint8_t label, tAVRC_MSG_VENDOR *p_msg);
+
+
+/******************************************************************************
+**
+** Function         AVRC_SetTraceLevel
+**
+** Description      Sets the trace level for AVRC. If 0xff is passed, the
+**                  current trace level is returned.
+**
+**                  Input Parameters:
+**                      new_level:  The level to set the AVRC tracing to:
+**                      0xff-returns the current setting.
+**                      0-turns off tracing.
+**                      >= 1-Errors.
+**                      >= 2-Warnings.
+**                      >= 3-APIs.
+**                      >= 4-Events.
+**                      >= 5-Debug.
+**
+** Returns          The new trace level or current trace level if
+**                  the input parameter is 0xff.
+**
+******************************************************************************/
+extern uint8_t AVRC_SetTraceLevel (uint8_t new_level);
+
+/*******************************************************************************
+**
+** Function         AVRC_Init
+**
+** Description      This function is called at stack startup to allocate the
+**                  control block (if using dynamic memory), and initializes the
+**                  control block and tracing level.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void AVRC_Init(void);
+
+/*******************************************************************************
+**
+** Function         AVRC_Ctrl_ParsCommand
+**
+** Description      This function is used to parse cmds received for CTRL
+**                  Currently it is for SetAbsVolume and Volume Change Notification..
+**
+** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+**                  Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+extern tAVRC_STS AVRC_Ctrl_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result);
+
+/*******************************************************************************
+**
+** Function         AVRC_ParsCommand
+**
+** Description      This function is used to parse the received command.
+**
+** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+**                  Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+extern tAVRC_STS AVRC_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result,
+                                   uint8_t *p_buf, uint16_t buf_len);
+
+/*******************************************************************************
+**
+** Function         AVRC_ParsResponse
+**
+** Description      This function is used to parse the received response.
+**
+** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+**                  Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+extern tAVRC_STS AVRC_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result,
+                                    uint8_t *p_buf, uint16_t buf_len);
+
+/*******************************************************************************
+**
+** Function         AVRC_Ctrl_ParsResponse
+**
+** Description      This function is a parse response for AVRCP Controller.
+**
+** Returns          AVRC_STS_NO_ERROR, if the message in p_data is parsed successfully.
+**                  Otherwise, the error code defined by AVRCP 1.4
+**
+*******************************************************************************/
+extern tAVRC_STS AVRC_Ctrl_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result,
+   uint8_t *p_buf, uint16_t* buf_len);
+
+/*******************************************************************************
+**
+** Function         AVRC_BldCommand
+**
+** Description      This function builds the given AVRCP command to the given
+**                  GKI buffer
+**
+** Returns          AVRC_STS_NO_ERROR, if the command is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+extern tAVRC_STS AVRC_BldCommand( tAVRC_COMMAND *p_cmd, BT_HDR **pp_pkt);
+
+/*******************************************************************************
+**
+** Function         AVRC_BldResponse
+**
+** Description      This function builds the given AVRCP response to the given
+**                  GKI buffer
+**
+** Returns          AVRC_STS_NO_ERROR, if the response is built successfully
+**                  Otherwise, the error code.
+**
+*******************************************************************************/
+extern tAVRC_STS AVRC_BldResponse( uint8_t handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt);
+
+/**************************************************************************
+**
+** Function         AVRC_IsValidAvcType
+**
+** Description      Check if correct AVC type is specified
+**
+** Returns          returns true if it is valid
+**
+**
+*******************************************************************************/
+extern bool    AVRC_IsValidAvcType(uint8_t pdu_id, uint8_t avc_type);
+
+/*******************************************************************************
+**
+** Function         AVRC_IsValidPlayerAttr
+**
+** Description      Check if the given attrib value is a valid one
+**
+**
+** Returns          returns true if it is valid
+**
+*******************************************************************************/
+extern bool    AVRC_IsValidPlayerAttr(uint8_t attr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVRC_API_H */
diff --git a/bt/stack/include/avrc_defs.h b/bt/stack/include/avrc_defs.h
new file mode 100644
index 0000000..f865054
--- /dev/null
+++ b/bt/stack/include/avrc_defs.h
@@ -0,0 +1,1453 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2006-2016 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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  AVRCP definition and data types
+ *
+ ******************************************************************************/
+#ifndef _AVRC_DEFS_H
+#define _AVRC_DEFS_H
+
+#include "stack/include/bt_types.h"
+
+/*****************************************************************************
+**  constants
+*****************************************************************************/
+
+/* Profile revision numbers */
+#define AVRC_REV_1_0        0x0100
+#define AVRC_REV_1_3        0x0103
+#define AVRC_REV_1_4        0x0104
+#define AVRC_REV_1_5        0x0105
+#define AVRC_REV_1_6        0x0106
+
+#define AVRC_PACKET_LEN             512 /* Per the spec, you must support 512 byte RC packets */
+
+#define AVRC_MIN_CONTROL_MTU        48  /* Per the spec, minimum MTU for the control channel */
+#define AVRC_MIN_BROWSE_MTU         335 /* Per the spec, minimum MTU for the browsing channel */
+
+#define AVRC_META_PDU_OFFSET        4
+#define AVRC_SUB_TYPE_LEN           4
+#define AVRC_UID_SIZE               8
+#define AVRC_FEATURE_MASK_SIZE      16
+
+/* command type codes */
+#define AVRC_CMD_CTRL       0   /* Instruct a target to perform an operation */
+#define AVRC_CMD_STATUS     1   /* Check a device's current status */
+#define AVRC_CMD_SPEC_INQ   2   /* Check whether a target supports a particular
+                                   control command; all operands are included */
+#define AVRC_CMD_NOTIF      3   /* Used for receiving notification of a change in a device's state */
+#define AVRC_CMD_GEN_INQ    4   /* Check whether a target supports a particular
+                                   control command; operands are not included */
+
+/* response type codes */
+#define AVRC_RSP_NOT_IMPL   8   /* The target does not implement the command specified
+                                   by the opcode and operand,
+                                   or doesn't implement the specified subunit */
+#define AVRC_RSP_ACCEPT     9   /* The target executed or is executing the command */
+#define AVRC_RSP_REJ        10  /* The target implements the command specified by the
+                                   opcode but cannot respond because the current state
+                                   of the target doesn't allow it */
+#define AVRC_RSP_IN_TRANS   11  /* The target implements the status command but it is
+                                   in a state of transition; the status command may
+                                   be retried at a future time */
+#define AVRC_RSP_IMPL_STBL  12  /* For specific inquiry or general inquiy commands,
+                                   the target implements the command; for status
+                                   commands, the target returns stable and includes
+                                   the status results */
+#define AVRC_RSP_CHANGED    13  /* The response frame contains a notification that the
+                                   target device's state has changed */
+#define AVRC_RSP_INTERIM    15  /* For control commands, the target has accepted the
+                                   request but cannot return information within 100
+                                   milliseconds; for notify commands, the target accepted
+                                   the command, and will notify the controller of a change
+                                   of target state at a future time */
+
+/* subunit type */
+#define AVRC_SUB_MONITOR    0x00    /* Monitor */
+#define AVRC_SUB_AUDIO      0x01    /* Audio */
+#define AVRC_SUB_PRINTER    0x02    /* Printer */
+#define AVRC_SUB_DISC       0x03    /* Disc */
+#define AVRC_SUB_TAPE       0x04    /* Tape recorder/player */
+#define AVRC_SUB_TUNER      0x05    /* Tuner */
+#define AVRC_SUB_CA         0x06    /* CA */
+#define AVRC_SUB_CAMERA     0x07    /* Camera */
+#define AVRC_SUB_PANEL      0x09    /* Panel */
+#define AVRC_SUB_BB         0x0A    /* Bulletin Board */
+#define AVRC_SUB_CAM_STOR   0x0B    /* Camera Storage */
+#define AVRC_SUB_VENDOR     0x1C    /* Vendor unique */
+#define AVRC_SUB_EXT        0x1E    /* Subunit type extended to next byte */
+#define AVRC_SUB_UNIT       0x1F    /* Unit */
+
+/* opcodes - defined by 1394ta */
+#define AVRC_OP_UNIT_INFO   0x30    /* Report unit information */
+#define AVRC_OP_SUB_INFO    0x31    /* Report subunit information */
+#define AVRC_OP_VENDOR      0x00    /* Vendor-dependent commands */
+#define AVRC_OP_PASS_THRU   0x7C    /* panel subunit opcode */
+/* opcodes 80-9F and E0-FF are not used by 1394ta.Sneak one for the browsing channel */
+#define AVRC_OP_BROWSE      0xFF    /* Browsing */
+#define AVRC_OP_INVALID     0xFE    /* invalid one */
+
+/* Company ID's
+*/
+#define AVRC_CO_BLUETOOTH_SIG   0x00FFFFFF
+#define AVRC_CO_WIDCOMM         0x00000361
+#define AVRC_CO_BROADCOM        0x00001018
+#define AVRC_CO_GOOGLE          0x00DAA119
+#define AVRC_CO_METADATA        0x00001958  /* Unique COMPANY ID for Metadata messages */
+
+/* State flag for Passthrough commands
+*/
+#define AVRC_STATE_PRESS    0
+#define AVRC_STATE_RELEASE  1
+
+/* Operation ID list for Passthrough commands
+*/
+#define AVRC_ID_SELECT      0x00    /* select */
+#define AVRC_ID_UP          0x01    /* up */
+#define AVRC_ID_DOWN        0x02    /* down */
+#define AVRC_ID_LEFT        0x03    /* left */
+#define AVRC_ID_RIGHT       0x04    /* right */
+#define AVRC_ID_RIGHT_UP    0x05    /* right-up */
+#define AVRC_ID_RIGHT_DOWN  0x06    /* right-down */
+#define AVRC_ID_LEFT_UP     0x07    /* left-up */
+#define AVRC_ID_LEFT_DOWN   0x08    /* left-down */
+#define AVRC_ID_ROOT_MENU   0x09    /* root menu */
+#define AVRC_ID_SETUP_MENU  0x0A    /* setup menu */
+#define AVRC_ID_CONT_MENU   0x0B    /* contents menu */
+#define AVRC_ID_FAV_MENU    0x0C    /* favorite menu */
+#define AVRC_ID_EXIT        0x0D    /* exit */
+#define AVRC_ID_0           0x20    /* 0 */
+#define AVRC_ID_1           0x21    /* 1 */
+#define AVRC_ID_2           0x22    /* 2 */
+#define AVRC_ID_3           0x23    /* 3 */
+#define AVRC_ID_4           0x24    /* 4 */
+#define AVRC_ID_5           0x25    /* 5 */
+#define AVRC_ID_6           0x26    /* 6 */
+#define AVRC_ID_7           0x27    /* 7 */
+#define AVRC_ID_8           0x28    /* 8 */
+#define AVRC_ID_9           0x29    /* 9 */
+#define AVRC_ID_DOT         0x2A    /* dot */
+#define AVRC_ID_ENTER       0x2B    /* enter */
+#define AVRC_ID_CLEAR       0x2C    /* clear */
+#define AVRC_ID_CHAN_UP     0x30    /* channel up */
+#define AVRC_ID_CHAN_DOWN   0x31    /* channel down */
+#define AVRC_ID_PREV_CHAN   0x32    /* previous channel */
+#define AVRC_ID_SOUND_SEL   0x33    /* sound select */
+#define AVRC_ID_INPUT_SEL   0x34    /* input select */
+#define AVRC_ID_DISP_INFO   0x35    /* display information */
+#define AVRC_ID_HELP        0x36    /* help */
+#define AVRC_ID_PAGE_UP     0x37    /* page up */
+#define AVRC_ID_PAGE_DOWN   0x38    /* page down */
+#define AVRC_ID_POWER       0x40    /* power */
+#define AVRC_ID_VOL_UP      0x41    /* volume up */
+#define AVRC_ID_VOL_DOWN    0x42    /* volume down */
+#define AVRC_ID_MUTE        0x43    /* mute */
+#define AVRC_ID_PLAY        0x44    /* play */
+#define AVRC_ID_STOP        0x45    /* stop */
+#define AVRC_ID_PAUSE       0x46    /* pause */
+#define AVRC_ID_RECORD      0x47    /* record */
+#define AVRC_ID_REWIND      0x48    /* rewind */
+#define AVRC_ID_FAST_FOR    0x49    /* fast forward */
+#define AVRC_ID_EJECT       0x4A    /* eject */
+#define AVRC_ID_FORWARD     0x4B    /* forward */
+#define AVRC_ID_BACKWARD    0x4C    /* backward */
+#define AVRC_ID_ANGLE       0x50    /* angle */
+#define AVRC_ID_SUBPICT     0x51    /* subpicture */
+#define AVRC_ID_F1          0x71    /* F1 */
+#define AVRC_ID_F2          0x72    /* F2 */
+#define AVRC_ID_F3          0x73    /* F3 */
+#define AVRC_ID_F4          0x74    /* F4 */
+#define AVRC_ID_F5          0x75    /* F5 */
+#define AVRC_ID_VENDOR      0x7E    /* vendor unique */
+#define AVRC_KEYPRESSED_RELEASE 0x80
+
+/*****************************************************************************
+**  Metadata transfer definitions
+*****************************************************************************/
+
+/* Define the Metadata Packet types
+*/
+#define AVRC_PKT_SINGLE           0
+#define AVRC_PKT_START            1
+#define AVRC_PKT_CONTINUE         2
+#define AVRC_PKT_END              3
+#define AVRC_PKT_TYPE_MASK        3
+
+/* Define the PDUs carried in the vendor dependant data
+*/
+#define AVRC_PDU_GET_CAPABILITIES               0x10
+#define AVRC_PDU_LIST_PLAYER_APP_ATTR           0x11
+#define AVRC_PDU_LIST_PLAYER_APP_VALUES         0x12
+#define AVRC_PDU_GET_CUR_PLAYER_APP_VALUE       0x13
+#define AVRC_PDU_SET_PLAYER_APP_VALUE           0x14
+#define AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT       0x15
+#define AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT      0x16
+#define AVRC_PDU_INFORM_DISPLAY_CHARSET         0x17
+#define AVRC_PDU_INFORM_BATTERY_STAT_OF_CT      0x18
+#define AVRC_PDU_GET_ELEMENT_ATTR               0x20
+#define AVRC_PDU_GET_PLAY_STATUS                0x30
+#define AVRC_PDU_REGISTER_NOTIFICATION          0x31
+#define AVRC_PDU_REQUEST_CONTINUATION_RSP       0x40
+#define AVRC_PDU_ABORT_CONTINUATION_RSP         0x41
+/* added in 1.4 */
+#define AVRC_PDU_SET_ABSOLUTE_VOLUME            0x50
+#define AVRC_PDU_SET_ADDRESSED_PLAYER           0x60
+#define AVRC_PDU_SET_BROWSED_PLAYER             0x70
+#define AVRC_PDU_GET_FOLDER_ITEMS               0x71
+#define AVRC_PDU_CHANGE_PATH                    0x72
+#define AVRC_PDU_GET_ITEM_ATTRIBUTES            0x73
+#define AVRC_PDU_PLAY_ITEM                      0x74
+#define AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS         0x75        /* Added in post 1.5 */
+#define AVRC_PDU_SEARCH                         0x80
+#define AVRC_PDU_ADD_TO_NOW_PLAYING             0x90
+#define AVRC_PDU_GENERAL_REJECT                 0xA0
+
+/* Define the vendor unique id carried in the pass through data
+*/
+#define AVRC_PDU_NEXT_GROUP                     0x00
+#define AVRC_PDU_PREV_GROUP                     0x01
+/* the only pass through vendor unique commands defined by AVRC is the group navigation commands
+ * The len for vendor unique data is 5 */
+#define AVRC_PASS_THRU_GROUP_LEN                5
+
+#define AVRC_PDU_INVALID                        0xff
+/* 6.15.3 error status code for general reject */
+#define AVRC_STS_BAD_CMD        0x00    /* Invalid command, sent if TG received a PDU that it did not understand. */
+#define AVRC_STS_BAD_PARAM      0x01    /* Invalid parameter, sent if the TG received a PDU with a parameter ID that it did not understand. Sent if there is only one parameter ID in the PDU. */
+#define AVRC_STS_NOT_FOUND      0x02    /* Specified parameter not found., sent if the parameter ID is understood, but content is wrong or corrupted. */
+#define AVRC_STS_INTERNAL_ERR   0x03    /* Internal Error, sent if there are error conditions not covered by a more specific error code. */
+#define AVRC_STS_NO_ERROR       0x04    /* Operation completed without error.  This is the status that should be returned if the operation was successful. */
+#define AVRC_STS_UID_CHANGED    0x05    /* UID Changed - The UIDs on the device have changed */
+/* #define AVRC_STS_GEN_ERROR      0x06    Unknown Error - this is changed to "reserved" */
+#define AVRC_STS_BAD_DIR        0x07    /* Invalid Direction - The Direction parameter is invalid - Change Path*/
+#define AVRC_STS_NOT_DIR        0x08    /* Not a Directory - The UID provided does not refer to a folder item  Change Path*/
+#define AVRC_STS_NOT_EXIST      0x09    /* Does Not Exist - The UID provided does not refer to any item    Change Path, PlayItem, AddToNowPlaying, GetItemAttributes*/
+#define AVRC_STS_BAD_SCOPE      0x0a    /* Invalid Scope - The scope parameter is invalid  GetFolderItems, PlayItem, AddToNowPlayer, GetItemAttributes, */
+#define AVRC_STS_BAD_RANGE      0x0b    /* Range Out of Bounds - The start of range provided is not valid  GetFolderItems*/
+#define AVRC_STS_UID_IS_DIR     0x0c    /* UID is a Directory - The UID provided refers to a directory, which cannot be handled by this media player   PlayItem, AddToNowPlaying */
+#define AVRC_STS_IN_USE         0x0d    /* Media in Use - The media is not able to be used for this operation at this time PlayItem, AddToNowPlaying */
+#define AVRC_STS_NOW_LIST_FULL  0x0e    /* Now Playing List Full - No more items can be added to the Now Playing List  AddToNowPlaying*/
+#define AVRC_STS_SEARCH_NOT_SUP 0x0f    /* Search Not Supported - The Browsed Media Player does not support search Search */
+#define AVRC_STS_SEARCH_BUSY    0x10    /* Search in Progress - A search operation is already in progress  Search*/
+#define AVRC_STS_BAD_PLAYER_ID  0x11    /* Invalid Player Id - The specified Player Id does not refer to a valid player    SetAddressedPlayer, SetBrowsedPlayer*/
+#define AVRC_STS_PLAYER_N_BR    0x12    /* Player Not Browsable - The Player Id supplied refers to a Media Player which does not support browsing. SetBrowsedPlayer */
+#define AVRC_STS_PLAYER_N_ADDR  0x13    /* Player Not Addressed.  The Player Id supplied refers to a player which is not currently addressed, and the command is not able to be performed if the player is not set as addressed.   Search, SetBrowsedPlayer*/
+#define AVRC_STS_BAD_SEARCH_RES 0x14    /* No valid Search Results - The Search result list does not contain valid entries, e.g. after being invalidated due to change of browsed player   GetFolderItems */
+#define AVRC_STS_NO_AVAL_PLAYER 0x15    /* No available players ALL */
+#define AVRC_STS_ADDR_PLAYER_CHG 0x16   /* Addressed Player Changed - Register Notification */
+typedef uint8_t tAVRC_STS;
+
+/* Define the Capability IDs
+*/
+#define AVRC_CAP_COMPANY_ID                     0x02
+#define AVRC_CAP_EVENTS_SUPPORTED               0x03
+#define AVRC_COMPANY_ID_LEN                     3
+#define AVRC_CAPABILITY_OFFSET                  2
+
+/* Define the Player Application Settings IDs
+*/
+#define AVRC_PLAYER_SETTING_EQUALIZER           0x01
+#define AVRC_PLAYER_SETTING_REPEAT              0x02
+#define AVRC_PLAYER_SETTING_SHUFFLE             0x03
+#define AVRC_PLAYER_SETTING_SCAN                0x04
+#define AVRC_PLAYER_SETTING_LOW_MENU_EXT        0x80
+#define AVRC_PLAYER_SETTING_HIGH_MENU_EXT       0xff
+
+/* Define the possible values of the Player Application Settings
+*/
+#define AVRC_PLAYER_VAL_OFF                     0x01
+#define AVRC_PLAYER_VAL_ON                      0x02
+#define AVRC_PLAYER_VAL_SINGLE_REPEAT           0x02
+#define AVRC_PLAYER_VAL_ALL_REPEAT              0x03
+#define AVRC_PLAYER_VAL_GROUP_REPEAT            0x04
+#define AVRC_PLAYER_VAL_ALL_SHUFFLE             0x02
+#define AVRC_PLAYER_VAL_GROUP_SHUFFLE           0x03
+#define AVRC_PLAYER_VAL_ALL_SCAN                0x02
+#define AVRC_PLAYER_VAL_GROUP_SCAN              0x03
+
+/* Define the possible values of Battery Status PDU
+*/
+#define AVRC_BATTERY_STATUS_NORMAL              0x00
+#define AVRC_BATTERY_STATUS_WARNING             0x01
+#define AVRC_BATTERY_STATUS_CRITICAL            0x02
+#define AVRC_BATTERY_STATUS_EXTERNAL            0x03
+#define AVRC_BATTERY_STATUS_FULL_CHARGE         0x04
+typedef uint8_t tAVRC_BATTERY_STATUS;
+
+/* Define character set */
+#define AVRC_CHAR_SET_SIZE                      2
+
+/* Define the Media Attribute IDs
+*/
+#define AVRC_MEDIA_ATTR_ID_TITLE                 0x00000001
+#define AVRC_MEDIA_ATTR_ID_ARTIST                0x00000002
+#define AVRC_MEDIA_ATTR_ID_ALBUM                 0x00000003
+#define AVRC_MEDIA_ATTR_ID_TRACK_NUM             0x00000004
+#define AVRC_MEDIA_ATTR_ID_NUM_TRACKS            0x00000005
+#define AVRC_MEDIA_ATTR_ID_GENRE                 0x00000006
+#define AVRC_MEDIA_ATTR_ID_PLAYING_TIME          0x00000007        /* in miliseconds */
+#define AVRC_MAX_NUM_MEDIA_ATTR_ID               7
+
+/* Define the possible values of play state
+*/
+#define AVRC_PLAYSTATE_RESP_MSG_SIZE            9
+#define AVRC_PLAYSTATE_STOPPED                  0x00    /* Stopped */
+#define AVRC_PLAYSTATE_PLAYING                  0x01    /* Playing */
+#define AVRC_PLAYSTATE_PAUSED                   0x02    /* Paused  */
+#define AVRC_PLAYSTATE_FWD_SEEK                 0x03    /* Fwd Seek*/
+#define AVRC_PLAYSTATE_REV_SEEK                 0x04    /* Rev Seek*/
+#define AVRC_PLAYSTATE_ERROR                    0xFF    /* Error   */
+typedef uint8_t tAVRC_PLAYSTATE;
+
+/* Define the events that can be registered for notifications
+*/
+#define AVRC_EVT_PLAY_STATUS_CHANGE             0x01
+#define AVRC_EVT_TRACK_CHANGE                   0x02
+#define AVRC_EVT_TRACK_REACHED_END              0x03
+#define AVRC_EVT_TRACK_REACHED_START            0x04
+#define AVRC_EVT_PLAY_POS_CHANGED               0x05
+#define AVRC_EVT_BATTERY_STATUS_CHANGE          0x06
+#define AVRC_EVT_SYSTEM_STATUS_CHANGE           0x07
+#define AVRC_EVT_APP_SETTING_CHANGE             0x08
+/* added in AVRCP 1.4 */
+#define AVRC_EVT_NOW_PLAYING_CHANGE             0x09
+#define AVRC_EVT_AVAL_PLAYERS_CHANGE            0x0a
+#define AVRC_EVT_ADDR_PLAYER_CHANGE             0x0b
+#define AVRC_EVT_UIDS_CHANGE                    0x0c
+#define AVRC_EVT_VOLUME_CHANGE                  0x0d
+
+/* the number of events that can be registered for notifications */
+#define AVRC_NUM_NOTIF_EVENTS                   0x0d
+
+#define AVRC_EVT_MSG_LEN_1                      0x01
+#define AVRC_EVT_MSG_LEN_2                      0x02
+#define AVRC_EVT_MSG_LEN_5                      0x05
+#define AVRC_EVT_MSG_LEN_9                      0x09
+
+#define AVRC_MAX_VOLUME                         0x7F
+
+/* Define the possible values of system status
+*/
+#define AVRC_SYSTEMSTATE_PWR_ON                 0x00
+#define AVRC_SYSTEMSTATE_PWR_OFF                0x01
+#define AVRC_SYSTEMSTATE_PWR_UNPLUGGED          0x02
+typedef uint8_t tAVRC_SYSTEMSTATE;
+
+/* the frequently used character set ids */
+#define AVRC_CHARSET_ID_ASCII                  ((uint16_t) 0x0003) /* ASCII */
+#define AVRC_CHARSET_ID_UTF8                   ((uint16_t) 0x006a) /* UTF-8 */
+#define AVRC_CHARSET_ID_UTF16                  ((uint16_t) 0x03f7) /* 1015 */
+#define AVRC_CHARSET_ID_UTF32                  ((uint16_t) 0x03f9) /* 1017 */
+
+/*****************************************************************************
+**  Advanced Control
+*****************************************************************************/
+#define AVRC_ITEM_PLAYER            0x01
+#define AVRC_ITEM_FOLDER            0x02
+#define AVRC_ITEM_MEDIA             0x03
+
+#define AVRC_SCOPE_PLAYER_LIST      0x00  /* Media Player Item - Contains all available media players */
+#define AVRC_SCOPE_FILE_SYSTEM      0x01  /* Folder Item, Media Element Item
+                                             - The virtual filesystem containing the media content of the browsed player */
+#define AVRC_SCOPE_SEARCH           0x02  /* Media Element Item  The results of a search operation on the browsed player */
+#define AVRC_SCOPE_NOW_PLAYING      0x03  /* Media Element Item  The Now Playing list (or queue) of the addressed player */
+
+#define AVRC_FOLDER_ITEM_COUNT_NONE 0xFF
+
+/* folder type */
+#define AVRC_FOLDER_TYPE_MIXED      0x00
+#define AVRC_FOLDER_TYPE_TITLES     0x01
+#define AVRC_FOLDER_TYPE_ALNUMS     0x02
+#define AVRC_FOLDER_TYPE_ARTISTS    0x03
+#define AVRC_FOLDER_TYPE_GENRES     0x04
+#define AVRC_FOLDER_TYPE_PLAYLISTS  0x05
+#define AVRC_FOLDER_TYPE_YEARS      0x06
+
+/* major player type */
+#define AVRC_MJ_TYPE_AUDIO          0x01  /* Audio */
+#define AVRC_MJ_TYPE_VIDEO          0x02  /* Video */
+#define AVRC_MJ_TYPE_BC_AUDIO       0x04  /* Broadcasting Audio */
+#define AVRC_MJ_TYPE_BC_VIDEO       0x08  /* Broadcasting Video */
+#define AVRC_MJ_TYPE_INVALID        0xF0
+
+/* player sub type */
+#define AVRC_SUB_TYPE_NONE          0x00
+#define AVRC_SUB_TYPE_AUDIO_BOOK    0x01  /* Audio Book */
+#define AVRC_SUB_TYPE_PODCAST       0x02  /* Podcast */
+#define AVRC_SUB_TYPE_INVALID       0xFC
+
+/* media item - media type */
+#define AVRC_MEDIA_TYPE_AUDIO       0x00
+#define AVRC_MEDIA_TYPE_VIDEO       0x01
+
+#define AVRC_DIR_UP                 0x00  /* Folder Up */
+#define AVRC_DIR_DOWN               0x01  /* Folder Down */
+
+#define AVRC_UID_SIZE               8
+typedef uint8_t tAVRC_UID[AVRC_UID_SIZE];
+
+/*****************************************************************************
+**  player attribute - supported features
+*****************************************************************************/
+#define AVRC_PF_SELECT_BIT_NO           0
+#define AVRC_PF_SELECT_MASK             0x01
+#define AVRC_PF_SELECT_OFF              0
+#define AVRC_PF_SELECT_SUPPORTED(x)     ((x)[AVRC_PF_SELECT_OFF] & AVRC_PF_SELECT_MASK)
+
+#define AVRC_PF_UP_BIT_NO               1
+#define AVRC_PF_UP_MASK                 0x02
+#define AVRC_PF_UP_OFF                  0
+#define AVRC_PF_UP_SUPPORTED(x)         ((x)[AVRC_PF_UP_OFF] & AVRC_PF_UP_MASK)
+
+#define AVRC_PF_DOWN_BIT_NO             2
+#define AVRC_PF_DOWN_MASK               0x04
+#define AVRC_PF_DOWN_OFF                0
+#define AVRC_PF_DOWN_SUPPORTED(x)       ((x)[AVRC_PF_DOWN_OFF] & AVRC_PF_DOWN_MASK)
+
+#define AVRC_PF_LEFT_BIT_NO             3
+#define AVRC_PF_LEFT_MASK               0x08
+#define AVRC_PF_LEFT_OFF                0
+#define AVRC_PF_LEFT_SUPPORTED(x)       ((x)[AVRC_PF_LEFT_OFF] & AVRC_PF_LEFT_MASK)
+
+#define AVRC_PF_RIGHT_BIT_NO            4
+#define AVRC_PF_RIGHT_MASK              0x10
+#define AVRC_PF_RIGHT_OFF               0
+#define AVRC_PF_RIGHT_SUPPORTED(x)      ((x)[AVRC_PF_RIGHT_OFF] & AVRC_PF_RIGHT_MASK)
+
+#define AVRC_PF_RIGHTUP_BIT_NO          5
+#define AVRC_PF_RIGHTUP_MASK            0x20
+#define AVRC_PF_RIGHTUP_OFF             0
+#define AVRC_PF_RIGHTUP_SUPPORTED(x)    ((x)[AVRC_PF_RIGHTUP_OFF] & AVRC_PF_RIGHTUP_MASK)
+
+#define AVRC_PF_RIGHTDOWN_BIT_NO        6
+#define AVRC_PF_RIGHTDOWN_MASK          0x40
+#define AVRC_PF_RIGHTDOWN_OFF           0
+#define AVRC_PF_RIGHTDOWN_SUPPORTED(x)  ((x)[AVRC_PF_RIGHTDOWN_OFF] & AVRC_PF_RIGHTDOWN_MASK)
+
+#define AVRC_PF_LEFTUP_BIT_NO           7
+#define AVRC_PF_LEFTUP_MASK             0x80
+#define AVRC_PF_LEFTUP_OFF              0
+#define AVRC_PF_LEFTUP_SUPPORTED(x)     ((x)[AVRC_PF_LEFTUP_OFF] & AVRC_PF_LEFTUP_MASK)
+
+#define AVRC_PF_LEFTDOWN_BIT_NO         8
+#define AVRC_PF_LEFTDOWN_MASK           0x01
+#define AVRC_PF_LEFTDOWN_OFF            1
+#define AVRC_PF_LEFTDOWN_SUPPORTED(x)   ((x)[AVRC_PF_LEFTDOWN_OFF] & AVRC_PF_LEFTDOWN_MASK)
+
+#define AVRC_PF_ROOT_MENU_BIT_NO        9
+#define AVRC_PF_ROOT_MENU_MASK          0x02
+#define AVRC_PF_ROOT_MENU_OFF           1
+#define AVRC_PF_ROOT_MENU_SUPPORTED(x)  ((x)[AVRC_PF_ROOT_MENU_OFF] & AVRC_PF_ROOT_MENU_MASK)
+
+#define AVRC_PF_SETUP_MENU_BIT_NO       10
+#define AVRC_PF_SETUP_MENU_MASK         0x04
+#define AVRC_PF_SETUP_MENU_OFF          1
+#define AVRC_PF_SETUP_MENU_SUPPORTED(x) ((x)[AVRC_PF_SETUP_MENU_OFF] & AVRC_PF_SETUP_MENU_MASK)
+
+#define AVRC_PF_CONTENTS_MENU_BIT_NO    11
+#define AVRC_PF_CONTENTS_MENU_MASK      0x08
+#define AVRC_PF_CONTENTS_MENU_OFF       1
+#define AVRC_PF_CONTENTS_MENU_SUPPORTED(x)  ((x)[AVRC_PF_CONTENTS_MENU_OFF] & AVRC_PF_CONTENTS_MENU_MASK)
+
+#define AVRC_PF_FAVORITE_MENU_BIT_NO    12
+#define AVRC_PF_FAVORITE_MENU_MASK      0x10
+#define AVRC_PF_FAVORITE_MENU_OFF       1
+#define AVRC_PF_FAVORITE_MENU_SUPPORTED(x)  ((x)[AVRC_PF_FAVORITE_MENU_OFF] & AVRC_PF_FAVORITE_MENU_MASK)
+
+#define AVRC_PF_EXIT_BIT_NO             13
+#define AVRC_PF_EXIT_MASK               0x20
+#define AVRC_PF_EXIT_OFF                1
+#define AVRC_PF_EXIT_SUPPORTED(x)       ((x)[AVRC_PF_EXIT_OFF] & AVRC_PF_EXIT_MASK)
+
+#define AVRC_PF_0_BIT_NO                14
+#define AVRC_PF_0_MASK                  0x40
+#define AVRC_PF_0_OFF                   1
+#define AVRC_PF_0_SUPPORTED(x)          ((x)[AVRC_PF_0_OFF] & AVRC_PF_0_MASK)
+
+#define AVRC_PF_1_BIT_NO                15
+#define AVRC_PF_1_MASK                  0x80
+#define AVRC_PF_1_OFF                   1
+#define AVRC_PF_1_SUPPORTED(x)          ((x)[AVRC_PF_1_OFF] & AVRC_PF_1_MASK)
+
+#define AVRC_PF_2_BIT_NO                16
+#define AVRC_PF_2_MASK                  0x01
+#define AVRC_PF_2_OFF                   2
+#define AVRC_PF_2_SUPPORTED(x)          ((x)[AVRC_PF_2_OFF] & AVRC_PF_2_MASK)
+
+#define AVRC_PF_3_BIT_NO                17
+#define AVRC_PF_3_MASK                  0x02
+#define AVRC_PF_3_OFF                   2
+#define AVRC_PF_3_SUPPORTED(x)          ((x)[AVRC_PF_3_OFF] & AVRC_PF_3_MASK)
+
+#define AVRC_PF_4_BIT_NO                18
+#define AVRC_PF_4_MASK                  0x04
+#define AVRC_PF_4_OFF                   2
+#define AVRC_PF_4_SUPPORTED(x)          ((x)[AVRC_PF_4_OFF] & AVRC_PF_4_MASK)
+
+#define AVRC_PF_5_BIT_NO                19
+#define AVRC_PF_5_MASK                  0x08
+#define AVRC_PF_5_OFF                   2
+#define AVRC_PF_5_SUPPORTED(x)          ((x)[AVRC_PF_5_OFF] & AVRC_PF_5_MASK)
+
+#define AVRC_PF_6_BIT_NO                20
+#define AVRC_PF_6_MASK                  0x10
+#define AVRC_PF_6_OFF                   2
+#define AVRC_PF_6_SUPPORTED(x)          ((x)[AVRC_PF_6_OFF] & AVRC_PF_6_MASK)
+
+#define AVRC_PF_7_BIT_NO                21
+#define AVRC_PF_7_MASK                  0x20
+#define AVRC_PF_7_OFF                   2
+#define AVRC_PF_7_SUPPORTED(x)          ((x)[AVRC_PF_7_OFF] & AVRC_PF_7_MASK)
+
+#define AVRC_PF_8_BIT_NO                22
+#define AVRC_PF_8_MASK                  0x40
+#define AVRC_PF_8_OFF                   2
+#define AVRC_PF_8_SUPPORTED(x)          ((x)[AVRC_PF_8_OFF] & AVRC_PF_8_MASK)
+
+#define AVRC_PF_9_BIT_NO                23
+#define AVRC_PF_9_MASK                  0x80
+#define AVRC_PF_9_OFF                   2
+#define AVRC_PF_9_SUPPORTED(x)          ((x)[AVRC_PF_9_OFF] & AVRC_PF_9_MASK)
+
+#define AVRC_PF_DOT_BIT_NO              24
+#define AVRC_PF_DOT_MASK                0x01
+#define AVRC_PF_DOT_OFF                 3
+#define AVRC_PF_DOT_SUPPORTED(x)        ((x)[AVRC_PF_DOT_OFF] & AVRC_PF_DOT_MASK)
+
+#define AVRC_PF_ENTER_BIT_NO            25
+#define AVRC_PF_ENTER_MASK              0x02
+#define AVRC_PF_ENTER_OFF               3
+#define AVRC_PF_ENTER_SUPPORTED(x)      ((x)[AVRC_PF_ENTER_OFF] & AVRC_PF_ENTER_MASK)
+
+#define AVRC_PF_CLEAR_BIT_NO            26
+#define AVRC_PF_CLEAR_MASK              0x04
+#define AVRC_PF_CLEAR_OFF               3
+#define AVRC_PF_CLEAR_SUPPORTED(x)      ((x)[AVRC_PF_CLEAR_OFF] & AVRC_PF_CLEAR_MASK)
+
+#define AVRC_PF_CHNL_UP_BIT_NO          27
+#define AVRC_PF_CHNL_UP_MASK            0x08
+#define AVRC_PF_CHNL_UP_OFF             3
+#define AVRC_PF_CHNL_UP_SUPPORTED(x)    ((x)[AVRC_PF_CHNL_UP_OFF] & AVRC_PF_CHNL_UP_MASK)
+
+#define AVRC_PF_CHNL_DOWN_BIT_NO        28
+#define AVRC_PF_CHNL_DOWN_MASK          0x10
+#define AVRC_PF_CHNL_DOWN_OFF           3
+#define AVRC_PF_CHNL_DOWN_SUPPORTED(x)  ((x)[AVRC_PF_CHNL_DOWN_OFF] & AVRC_PF_CHNL_DOWN_MASK)
+
+#define AVRC_PF_PREV_CHNL_BIT_NO        29
+#define AVRC_PF_PREV_CHNL_MASK          0x20
+#define AVRC_PF_PREV_CHNL_OFF           3
+#define AVRC_PF_PREV_CHNL_SUPPORTED(x)  ((x)[AVRC_PF_PREV_CHNL_OFF] & AVRC_PF_PREV_CHNL_MASK)
+
+#define AVRC_PF_SOUND_SEL_BIT_NO        30
+#define AVRC_PF_SOUND_SEL_MASK          0x40
+#define AVRC_PF_SOUND_SEL_OFF           3
+#define AVRC_PF_SOUND_SEL_SUPPORTED(x)  ((x)[AVRC_PF_SOUND_SEL_OFF] & AVRC_PF_SOUND_SEL_MASK)
+
+#define AVRC_PF_INPUT_SEL_BIT_NO        31
+#define AVRC_PF_INPUT_SEL_MASK          0x80
+#define AVRC_PF_INPUT_SEL_OFF           3
+#define AVRC_PF_INPUT_SEL_SUPPORTED(x)  ((x)[AVRC_PF_INPUT_SEL_OFF] & AVRC_PF_INPUT_SEL_MASK)
+
+#define AVRC_PF_DISP_INFO_BIT_NO        32
+#define AVRC_PF_DISP_INFO_MASK          0x01
+#define AVRC_PF_DISP_INFO_OFF           4
+#define AVRC_PF_DISP_INFO_SUPPORTED(x)  ((x)[AVRC_PF_DISP_INFO_OFF] & AVRC_PF_DISP_INFO_MASK)
+
+#define AVRC_PF_HELP_BIT_NO             33
+#define AVRC_PF_HELP_MASK               0x02
+#define AVRC_PF_HELP_OFF                4
+#define AVRC_PF_HELP_SUPPORTED(x)       ((x)[AVRC_PF_HELP_OFF] & AVRC_PF_HELP_MASK)
+
+#define AVRC_PF_PAGE_UP_BIT_NO          34
+#define AVRC_PF_PAGE_UP_MASK            0x04
+#define AVRC_PF_PAGE_UP_OFF             4
+#define AVRC_PF_PAGE_UP_SUPPORTED(x)    ((x)[AVRC_PF_PAGE_UP_OFF] & AVRC_PF_PAGE_UP_MASK)
+
+#define AVRC_PF_PAGE_DOWN_BIT_NO        35
+#define AVRC_PF_PAGE_DOWN_MASK          0x08
+#define AVRC_PF_PAGE_DOWN_OFF           4
+#define AVRC_PF_PAGE_DOWN_SUPPORTED(x)  ((x)[AVRC_PF_PAGE_DOWN_OFF] & AVRC_PF_PAGE_DOWN_MASK)
+
+#define AVRC_PF_POWER_BIT_NO            36
+#define AVRC_PF_POWER_MASK              0x10
+#define AVRC_PF_POWER_OFF               4
+#define AVRC_PF_POWER_SUPPORTED(x)      ((x)[AVRC_PF_POWER_OFF] & AVRC_PF_POWER_MASK)
+
+#define AVRC_PF_VOL_UP_BIT_NO           37
+#define AVRC_PF_VOL_UP_MASK             0x20
+#define AVRC_PF_VOL_UP_OFF              4
+#define AVRC_PF_VOL_UP_SUPPORTED(x)     ((x)[AVRC_PF_VOL_UP_OFF] & AVRC_PF_VOL_UP_MASK)
+
+#define AVRC_PF_VOL_DOWN_BIT_NO         38
+#define AVRC_PF_VOL_DOWN_MASK           0x40
+#define AVRC_PF_VOL_DOWN_OFF            4
+#define AVRC_PF_VOL_DOWN_SUPPORTED(x)   ((x)[AVRC_PF_VOL_DOWN_OFF] & AVRC_PF_VOL_DOWN_MASK)
+
+#define AVRC_PF_MUTE_BIT_NO             39
+#define AVRC_PF_MUTE_MASK               0x80
+#define AVRC_PF_MUTE_OFF                4
+#define AVRC_PF_MUTE_SUPPORTED(x)       ((x)[AVRC_PF_MUTE_OFF] & AVRC_PF_MUTE_MASK)
+
+#define AVRC_PF_PLAY_BIT_NO             40
+#define AVRC_PF_PLAY_MASK               0x01
+#define AVRC_PF_PLAY_OFF                5
+#define AVRC_PF_PLAY_SUPPORTED(x)       ((x)[AVRC_PF_PLAY_OFF] & AVRC_PF_PLAY_MASK)
+
+#define AVRC_PF_STOP_BIT_NO             41
+#define AVRC_PF_STOP_MASK               0x02
+#define AVRC_PF_STOP_OFF                5
+#define AVRC_PF_STOP_SUPPORTED(x)       ((x)[AVRC_PF_STOP_OFF] & AVRC_PF_STOP_MASK)
+
+#define AVRC_PF_PAUSE_BIT_NO            42
+#define AVRC_PF_PAUSE_MASK              0x04
+#define AVRC_PF_PAUSE_OFF               5
+#define AVRC_PF_PAUSE_SUPPORTED(x)      ((x)[AVRC_PF_PAUSE_OFF] & AVRC_PF_PAUSE_MASK)
+
+#define AVRC_PF_RECORD_BIT_NO           43
+#define AVRC_PF_RECORD_MASK             0x08
+#define AVRC_PF_RECORD_OFF              5
+#define AVRC_PF_RECORD_SUPPORTED(x)     ((x)[AVRC_PF_RECORD_OFF] & AVRC_PF_RECORD_MASK)
+
+#define AVRC_PF_REWIND_BIT_NO           44
+#define AVRC_PF_REWIND_MASK             0x10
+#define AVRC_PF_REWIND_OFF              5
+#define AVRC_PF_REWIND_SUPPORTED(x)     ((x)[AVRC_PF_REWIND_OFF] & AVRC_PF_REWIND_MASK)
+
+#define AVRC_PF_FAST_FWD_BIT_NO         45
+#define AVRC_PF_FAST_FWD_MASK           0x20
+#define AVRC_PF_FAST_FWD_OFF            5
+#define AVRC_PF_FAST_FWD_SUPPORTED(x)   ((x)[AVRC_PF_FAST_FWD_OFF] & AVRC_PF_FAST_FWD_MASK)
+
+#define AVRC_PF_EJECT_BIT_NO            46
+#define AVRC_PF_EJECT_MASK              0x40
+#define AVRC_PF_EJECT_OFF               5
+#define AVRC_PF_EJECT_SUPPORTED(x)      ((x)[AVRC_PF_EJECT_OFF] & AVRC_PF_EJECT_MASK)
+
+#define AVRC_PF_FORWARD_BIT_NO          47
+#define AVRC_PF_FORWARD_MASK            0x80
+#define AVRC_PF_FORWARD_OFF             5
+#define AVRC_PF_FORWARD_SUPPORTED(x)    ((x)[AVRC_PF_FORWARD_OFF] & AVRC_PF_FORWARD_MASK)
+
+#define AVRC_PF_BACKWARD_BIT_NO         48
+#define AVRC_PF_BACKWARD_MASK           0x01
+#define AVRC_PF_BACKWARD_OFF            6
+#define AVRC_PF_BACKWARD_SUPPORTED(x)   ((x)[AVRC_PF_BACKWARD_OFF] & AVRC_PF_BACKWARD_MASK)
+
+#define AVRC_PF_ANGLE_BIT_NO            49
+#define AVRC_PF_ANGLE_MASK              0x02
+#define AVRC_PF_ANGLE_OFF               6
+#define AVRC_PF_ANGLE_SUPPORTED(x)      ((x)[AVRC_PF_ANGLE_OFF] & AVRC_PF_ANGLE_MASK)
+
+#define AVRC_PF_SUBPICTURE_BIT_NO       50
+#define AVRC_PF_SUBPICTURE_MASK         0x04
+#define AVRC_PF_SUBPICTURE_OFF          6
+#define AVRC_PF_SUBPICTURE_SUPPORTED(x) ((x)[AVRC_PF_SUBPICTURE_OFF] & AVRC_PF_SUBPICTURE_MASK)
+
+#define AVRC_PF_F1_BIT_NO               51
+#define AVRC_PF_F1_MASK                 0x08
+#define AVRC_PF_F1_OFF                  6
+#define AVRC_PF_F1_SUPPORTED(x)         ((x)[AVRC_PF_F1_OFF] & AVRC_PF_F1_MASK)
+
+#define AVRC_PF_F2_BIT_NO               52
+#define AVRC_PF_F2_MASK                 0x10
+#define AVRC_PF_F2_OFF                  6
+#define AVRC_PF_F2_SUPPORTED(x)         ((x)[AVRC_PF_F2_OFF] & AVRC_PF_F2_MASK)
+
+#define AVRC_PF_F3_BIT_NO               53
+#define AVRC_PF_F3_MASK                 0x20
+#define AVRC_PF_F3_OFF                  6
+#define AVRC_PF_F3_SUPPORTED(x)         ((x)[AVRC_PF_F3_OFF] & AVRC_PF_F3_MASK)
+
+#define AVRC_PF_F4_BIT_NO               54
+#define AVRC_PF_F4_MASK                 0x40
+#define AVRC_PF_F4_OFF                  6
+#define AVRC_PF_F4_SUPPORTED(x)         ((x)[AVRC_PF_F4_OFF] & AVRC_PF_F4_MASK)
+
+#define AVRC_PF_F5_BIT_NO               55
+#define AVRC_PF_F5_MASK                 0x80
+#define AVRC_PF_F5_OFF                  6
+#define AVRC_PF_F5_SUPPORTED(x)         ((x)[AVRC_PF_F5_OFF] & AVRC_PF_F5_MASK)
+
+/* Vendor unique. This PASSTHROUGH command is supported. */
+#define AVRC_PF_VENDOR_BIT_NO           56
+#define AVRC_PF_VENDOR_MASK             0x01
+#define AVRC_PF_VENDOR_OFF              7
+#define AVRC_PF_VENDOR_SUPPORTED(x)     ((x)[AVRC_PF_VENDOR_OFF] & AVRC_PF_VENDOR_MASK)
+
+/* Basic Group Navigation.  This overrules the SDP entry as it is set per player.7 */
+#define AVRC_PF_GROUP_NAVI_BIT_NO       57
+#define AVRC_PF_GROUP_NAVI_MASK         0x02
+#define AVRC_PF_GROUP_NAVI_OFF          7
+#define AVRC_PF_GROUP_NAVI_SUPPORTED(x) ((x)[AVRC_PF_GROUP_NAVI_OFF] & AVRC_PF_GROUP_NAVI_MASK)
+
+/* Advanced Control Player.  This bit is set if the player supports at least AVRCP 1.4. */
+#define AVRC_PF_ADV_CTRL_BIT_NO         58
+#define AVRC_PF_ADV_CTRL_MASK           0x04
+#define AVRC_PF_ADV_CTRL_OFF            7
+#define AVRC_PF_ADV_CTRL_SUPPORTED(x)   ((x)[AVRC_PF_ADV_CTRL_OFF] & AVRC_PF_ADV_CTRL_MASK)
+
+/* Browsing.  This bit is set if the player supports browsing. */
+#define AVRC_PF_BROWSE_BIT_NO           59
+#define AVRC_PF_BROWSE_MASK             0x08
+#define AVRC_PF_BROWSE_OFF              7
+#define AVRC_PF_BROWSE_SUPPORTED(x)     ((x)[AVRC_PF_BROWSE_OFF] & AVRC_PF_BROWSE_MASK)
+
+/* Searching. This bit is set if the player supports searching. */
+#define AVRC_PF_SEARCH_BIT_NO           60
+#define AVRC_PF_SEARCH_MASK             0x10
+#define AVRC_PF_SEARCH_OFF              7
+#define AVRC_PF_SEARCH_SUPPORTED(x)     ((x)[AVRC_PF_SEARCH_OFF] & AVRC_PF_SEARCH_MASK)
+
+/* AddToNowPlaying.  This bit is set if the player supports the AddToNowPlaying command. */
+#define AVRC_PF_ADD2NOWPLAY_BIT_NO      61
+#define AVRC_PF_ADD2NOWPLAY_MASK        0x20
+#define AVRC_PF_ADD2NOWPLAY_OFF         7
+#define AVRC_PF_ADD2NOWPLAY_SUPPORTED(x) ((x)[AVRC_PF_ADD2NOWPLAY_OFF] & AVRC_PF_ADD2NOWPLAY_MASK)
+
+/* UIDs unique in player browse tree.  This bit is set if the player is able to maintain unique UIDs across the player browse tree. */
+#define AVRC_PF_UID_UNIQUE_BIT_NO       62
+#define AVRC_PF_UID_UNIQUE_MASK         0x40
+#define AVRC_PF_UID_UNIQUE_OFF          7
+#define AVRC_PF_UID_UNIQUE_SUPPORTED(x) ((x)[AVRC_PF_UID_UNIQUE_OFF] & AVRC_PF_UID_UNIQUE_MASK)
+
+/* OnlyBrowsableWhenAddressed.  This bit is set if the player is only able to be browsed when it is set as the Addressed Player. */
+#define AVRC_PF_BR_WH_ADDR_BIT_NO       63
+#define AVRC_PF_BR_WH_ADDR_MASK         0x80
+#define AVRC_PF_BR_WH_ADDR_OFF          7
+#define AVRC_PF_BR_WH_ADDR_SUPPORTED(x) ((x)[AVRC_PF_BR_WH_ADDR_OFF] & AVRC_PF_BR_WH_ADDR_MASK)
+
+/* OnlySearchableWhenAddressed.  This bit is set if the player is only able to be searched when it is set as the Addressed player. */
+#define AVRC_PF_SEARCH_WH_ADDR_BIT_NO   64
+#define AVRC_PF_SEARCH_WH_ADDR_MASK     0x01
+#define AVRC_PF_SEARCH_WH_ADDR_OFF      8
+#define AVRC_PF_SEARCH_WH_ADDR_SUPPORTED(x) ((x)[AVRC_PF_SEARCH_WH_ADDR_OFF] & AVRC_PF_SEARCH_WH_ADDR_MASK)
+
+/* NowPlaying.  This bit is set if the player supports the NowPlaying folder.  Note that for all players that support browsing this bit shall be set */
+#define AVRC_PF_NOW_PLAY_BIT_NO         65
+#define AVRC_PF_NOW_PLAY_MASK           0x02
+#define AVRC_PF_NOW_PLAY_OFF            8
+#define AVRC_PF_NOW_PLAY_SUPPORTED(x)   ((x)[AVRC_PF_NOW_PLAY_OFF] & AVRC_PF_NOW_PLAY_MASK)
+
+/* UIDPersistency.  This bit is set if the Player is able to persist UID values between AVRCP Browse Reconnect */
+#define AVRC_PF_UID_PERSIST_BIT_NO      66
+#define AVRC_PF_UID_PERSIST_MASK        0x04
+#define AVRC_PF_UID_PERSIST_OFF         8
+#define AVRC_PF_UID_PERSIST_SUPPORTED(x) ((x)[AVRC_PF_UID_PERSIST_OFF] & AVRC_PF_UID_PERSIST_MASK)
+
+/* NumberOfItems. This bit is set if player supports the GetTotalNumberOfItems browsing command. */
+#define AVRC_PF_GET_NUM_OF_ITEMS_BIT_NO    67
+#define AVRC_PF_GET_NUM_OF_ITEMS_MASK      0x08
+#define AVRC_PF_GET_NUM_OF_ITEMS_OFF       8
+#define AVRC_PF_GET_NUM_OF_ITEMS_SUPPORTED(x) ((x)[AVRC_PF_GET_NUM_OF_ITEMS_OFF] & AVRC_PF_GET_NUM_OF_ITEMS_MASK)
+
+/*****************************************************************************
+**  data type definitions
+*****************************************************************************/
+
+/*
+This structure contains the header parameters of an AV/C message.
+*/
+typedef struct
+{
+    uint8_t ctype;          /* Command type.  */
+    uint8_t subunit_type;   /* Subunit type. */
+    uint8_t subunit_id;     /* Subunit ID.  This value is typically ignored in AVRCP,
+                             * except for VENDOR DEPENDENT messages when the value is
+                             * vendor-dependent.  Value range is 0-7. */
+    uint8_t opcode;         /* Op Code (passthrough, vendor, etc) */
+} tAVRC_HDR;
+
+/* This structure contains a UNIT INFO message. */
+typedef struct
+{
+    tAVRC_HDR   hdr;        /* Message header. */
+    uint32_t    company_id; /* Company identifier. */
+    uint8_t     unit_type;  /* Unit type.  Uses the same values as subunit type. */
+    uint8_t     unit;       /* This value is vendor dependent and typically zero.  */
+} tAVRC_MSG_UNIT;
+
+/* This structure contains a SUBUNIT INFO message. */
+typedef struct
+{
+    tAVRC_HDR   hdr;        /* Message header. */
+    uint8_t     subunit_type[AVRC_SUB_TYPE_LEN];
+                            /* Array containing subunit type values.  */
+    bool        panel;      /* true if the panel subunit type is in the
+                             * subunit_type array, false otherwise. */
+    uint8_t     page;       /* Specifies which part of the subunit type table is
+                             * returned.  For AVRCP it is typically zero.
+                             * Value range is 0-7. */
+} tAVRC_MSG_SUB;
+
+/* This structure contains a VENDOR DEPENDENT message. */
+typedef struct
+{
+    tAVRC_HDR   hdr;        /* Message header. */
+    uint32_t    company_id; /* Company identifier. */
+    uint8_t    *p_vendor_data;/* Pointer to vendor dependent data. */
+    uint16_t    vendor_len; /* Length in bytes of vendor dependent data. */
+} tAVRC_MSG_VENDOR;
+
+/* PASS THROUGH message structure */
+typedef struct
+{
+    tAVRC_HDR   hdr;        /* hdr.ctype Unused.
+                             * hdr.subunit_type Unused.
+                             * hdr.subunit_id Unused. */
+    uint8_t     op_id;      /* Operation ID.  */
+    uint8_t     state;      /* Keypress state.  */
+    uint8_t    *p_pass_data;/* Pointer to data.  This parameter is only valid
+                             * when the op_id is AVRC_ID_VENDOR.*/
+    uint8_t     pass_len;   /* Length in bytes of data. This parameter is only
+                             * valid when the op_id is AVRC_ID_VENDOR.*/
+} tAVRC_MSG_PASS;
+
+/* Command/Response indicator. */
+#define AVRC_CMD            AVCT_CMD    /* Command message */
+#define AVRC_RSP            AVCT_RSP    /* Response message */
+
+/* Browsing channel message structure */
+typedef struct
+{
+    tAVRC_HDR   hdr;            /* hdr.ctype AVRC_CMD or AVRC_RSP.
+                                 * hdr.subunit_type Unused.
+                                 * hdr.subunit_id Unused. */
+    uint8_t    *p_browse_data;  /* Pointer to data.  */
+    uint16_t    browse_len;     /* Length in bytes of data. */
+    BT_HDR     *p_browse_pkt;   /* The GKI buffer received. Set to NULL, if the callback function wants to keep the buffer */
+} tAVRC_MSG_BROWSE;
+
+/* This is a union of all message type structures. */
+typedef union
+{
+    tAVRC_HDR           hdr;    /* Message header. */
+    tAVRC_MSG_UNIT      unit;   /* UNIT INFO message. */
+    tAVRC_MSG_SUB       sub;    /* SUBUNIT INFO message. */
+    tAVRC_MSG_VENDOR    vendor; /* VENDOR DEPENDENT message. */
+    tAVRC_MSG_PASS      pass;   /* PASS THROUGH message. */
+    tAVRC_MSG_BROWSE    browse; /* messages thru browsing channel */
+} tAVRC_MSG;
+
+/* macros */
+#define AVRC_IS_VALID_CAP_ID(a)           ((((a) == AVRC_CAP_COMPANY_ID) || ((a) == AVRC_CAP_EVENTS_SUPPORTED)) ? true : false)
+
+#define AVRC_IS_VALID_EVENT_ID(a)           ((((a) >= AVRC_EVT_PLAY_STATUS_CHANGE) && \
+                                              ((a) <= AVRC_EVT_VOLUME_CHANGE)) ? true : false)
+
+#define AVRC_IS_VALID_ATTRIBUTE(a)          ((((((a) > 0) && (a) <= AVRC_PLAYER_SETTING_SCAN)) || \
+                                              ((a) >= AVRC_PLAYER_SETTING_LOW_MENU_EXT)) ? true : false)
+
+#define AVRC_IS_VALID_MEDIA_ATTRIBUTE(a)    (((a) >= AVRC_MEDIA_ATTR_ID_TITLE) && \
+                                             ((a) <= AVRC_MEDIA_ATTR_ID_PLAYING_TIME) ? true : false)
+
+#define AVRC_IS_VALID_BATTERY_STATUS(a)    (((a) <= AVRC_BATTERY_STATUS_FULL_CHARGE) ? true : false)
+
+#define AVRC_IS_VALID_SYSTEM_STATUS(a)    (((a) <= AVRC_SYSTEMSTATE_PWR_UNPLUGGED) ? true : false)
+
+#define AVRC_IS_VALID_GROUP(a)    (((a) <= AVRC_PDU_PREV_GROUP) ? true : false)
+
+/* Company ID is 24-bit integer We can not use the macros in bt_types.h */
+#define AVRC_CO_ID_TO_BE_STREAM(p, u32) {*(p)++ = (uint8_t)((u32) >> 16); *(p)++ = (uint8_t)((u32) >> 8); *(p)++ = (uint8_t)(u32); }
+#define AVRC_BE_STREAM_TO_CO_ID(u32, p) {(u32) = (((uint32_t)(*((p) + 2))) + (((uint32_t)(*((p) + 1))) << 8) + (((uint32_t)(*(p))) << 16)); (p) += 3;}
+
+/*****************************************************************************
+**  data type definitions
+*****************************************************************************/
+#define AVRC_MAX_APP_ATTR_SIZE      16
+#define AVRC_MAX_CHARSET_SIZE       16
+#define AVRC_MAX_ELEM_ATTR_SIZE     8
+
+/*****************************************************************************
+**  Metadata transfer Building/Parsing definitions
+*****************************************************************************/
+
+typedef struct {
+    uint16_t            charset_id;
+    uint16_t            str_len;
+    uint8_t             *p_str;
+} tAVRC_FULL_NAME;
+
+typedef struct {
+    uint16_t            str_len;
+    uint8_t             *p_str;
+} tAVRC_NAME;
+
+#ifndef AVRC_CAP_MAX_NUM_COMP_ID
+#define AVRC_CAP_MAX_NUM_COMP_ID    4
+#endif
+
+#ifndef AVRC_CAP_MAX_NUM_EVT_ID
+#define AVRC_CAP_MAX_NUM_EVT_ID     16
+#endif
+
+typedef union
+{
+    uint32_t company_id[AVRC_CAP_MAX_NUM_COMP_ID];
+    uint8_t event_id[AVRC_CAP_MAX_NUM_EVT_ID];
+} tAVRC_CAPS_PARAM;
+
+typedef struct
+{
+    uint8_t attr_id;
+    uint8_t attr_val;
+} tAVRC_APP_SETTING;
+
+typedef struct
+{
+    uint8_t attr_id;
+    uint16_t charset_id;
+    uint8_t str_len;
+    uint8_t *p_str;
+} tAVRC_APP_SETTING_TEXT;
+
+typedef uint8_t tAVRC_FEATURE_MASK[AVRC_FEATURE_MASK_SIZE];
+
+typedef struct
+{
+    uint16_t            player_id;      /* A unique identifier for this media player.*/
+    uint8_t             major_type;     /* Use AVRC_MJ_TYPE_AUDIO, AVRC_MJ_TYPE_VIDEO, AVRC_MJ_TYPE_BC_AUDIO, or AVRC_MJ_TYPE_BC_VIDEO.*/
+    uint32_t            sub_type;       /* Use AVRC_SUB_TYPE_NONE, AVRC_SUB_TYPE_AUDIO_BOOK, or AVRC_SUB_TYPE_PODCAST*/
+    uint8_t             play_status;    /* Use AVRC_PLAYSTATE_STOPPED, AVRC_PLAYSTATE_PLAYING, AVRC_PLAYSTATE_PAUSED, AVRC_PLAYSTATE_FWD_SEEK,
+                                            AVRC_PLAYSTATE_REV_SEEK, or AVRC_PLAYSTATE_ERROR*/
+    tAVRC_FEATURE_MASK  features;       /* Supported feature bit mask*/
+    tAVRC_FULL_NAME     name;           /* The player name, name length and character set id.*/
+} tAVRC_ITEM_PLAYER;
+
+typedef struct
+{
+    tAVRC_UID           uid;            /* The uid of this folder */
+    uint8_t             type;           /* Use AVRC_FOLDER_TYPE_MIXED, AVRC_FOLDER_TYPE_TITLES,
+                                           AVRC_FOLDER_TYPE_ALNUMS, AVRC_FOLDER_TYPE_ARTISTS, AVRC_FOLDER_TYPE_GENRES,
+                                           AVRC_FOLDER_TYPE_PLAYLISTS, or AVRC_FOLDER_TYPE_YEARS.*/
+    bool                playable;       /* true, if the folder can be played. */
+    tAVRC_FULL_NAME     name;           /* The folder name, name length and character set id. */
+} tAVRC_ITEM_FOLDER;
+
+typedef struct
+{
+    uint32_t            attr_id;        /* Use AVRC_MEDIA_ATTR_ID_TITLE, AVRC_MEDIA_ATTR_ID_ARTIST, AVRC_MEDIA_ATTR_ID_ALBUM,
+                                           AVRC_MEDIA_ATTR_ID_TRACK_NUM, AVRC_MEDIA_ATTR_ID_NUM_TRACKS,
+                                           AVRC_MEDIA_ATTR_ID_GENRE, AVRC_MEDIA_ATTR_ID_PLAYING_TIME */
+    tAVRC_FULL_NAME     name;           /* The attribute value, value length and character set id. */
+} tAVRC_ATTR_ENTRY;
+
+typedef struct
+{
+    tAVRC_UID           uid;            /* The uid of this media element item */
+    uint8_t             type;           /* Use AVRC_MEDIA_TYPE_AUDIO or AVRC_MEDIA_TYPE_VIDEO. */
+    tAVRC_FULL_NAME     name;           /* The media name, name length and character set id. */
+    uint8_t             attr_count;     /* The number of attributes in p_attr_list */
+    tAVRC_ATTR_ENTRY*   p_attr_list;    /* Attribute entry list. */
+} tAVRC_ITEM_MEDIA;
+
+typedef struct
+{
+    uint8_t                 item_type;  /* AVRC_ITEM_PLAYER, AVRC_ITEM_FOLDER, or AVRC_ITEM_MEDIA */
+    union
+    {
+        tAVRC_ITEM_PLAYER   player;     /* The properties of a media player item.*/
+        tAVRC_ITEM_FOLDER   folder;     /* The properties of a folder item.*/
+        tAVRC_ITEM_MEDIA    media;      /* The properties of a media item.*/
+    } u;
+} tAVRC_ITEM;
+
+/* GetCapability */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    uint8_t     capability_id;
+} tAVRC_GET_CAPS_CMD;
+
+/* ListPlayerAppValues */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    uint8_t     attr_id;
+} tAVRC_LIST_APP_VALUES_CMD;
+
+/* GetCurAppValue */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    uint8_t     num_attr;
+    uint8_t     attrs[AVRC_MAX_APP_ATTR_SIZE];
+} tAVRC_GET_CUR_APP_VALUE_CMD;
+
+/* SetAppValue */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    uint8_t     num_val;
+    tAVRC_APP_SETTING   *p_vals;
+} tAVRC_SET_APP_VALUE_CMD;
+
+/* GetAppAttrTxt */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    uint8_t     num_attr;
+    uint8_t     attrs[AVRC_MAX_APP_ATTR_SIZE];
+} tAVRC_GET_APP_ATTR_TXT_CMD;
+
+/* GetAppValueTxt */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    uint8_t     attr_id;
+    uint8_t     num_val;
+    uint8_t     vals[AVRC_MAX_APP_ATTR_SIZE];
+} tAVRC_GET_APP_VAL_TXT_CMD;
+
+/* InformCharset */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    uint8_t     num_id;
+    uint16_t    charsets[AVRC_MAX_CHARSET_SIZE];
+} tAVRC_INFORM_CHARSET_CMD;
+
+/* InformBatteryStatus */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    uint8_t     battery_status;
+} tAVRC_BATTERY_STATUS_CMD;
+
+/* GetElemAttrs */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    uint8_t     num_attr;
+    uint32_t    attrs[AVRC_MAX_ELEM_ATTR_SIZE];
+} tAVRC_GET_ELEM_ATTRS_CMD;
+
+/* RegNotify */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    uint8_t     event_id;
+    uint32_t    param;
+} tAVRC_REG_NOTIF_CMD;
+
+/* SetAddrPlayer */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    uint16_t    player_id;
+} tAVRC_SET_ADDR_PLAYER_CMD;
+
+/* SetBrowsedPlayer */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    uint16_t    player_id;
+} tAVRC_SET_BR_PLAYER_CMD;
+
+/* SetAbsVolume */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    uint8_t     volume;
+} tAVRC_SET_VOLUME_CMD;
+
+/* GetFolderItems */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    uint8_t     scope;
+    uint32_t    start_item;
+    uint32_t    end_item;
+    uint8_t     attr_count;
+    uint32_t    *p_attr_list;
+} tAVRC_GET_ITEMS_CMD;
+
+/* ChangePath */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    uint16_t    uid_counter;
+    uint8_t     direction;
+    tAVRC_UID   folder_uid;
+} tAVRC_CHG_PATH_CMD;
+
+/* GetItemAttrs */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    uint8_t     scope;
+    tAVRC_UID   uid;
+    uint16_t    uid_counter;
+    uint8_t     attr_count;
+    uint32_t    *p_attr_list;
+} tAVRC_GET_ATTRS_CMD;
+
+/* Search */
+typedef struct
+{
+    uint8_t         pdu;
+    tAVRC_STS       status;
+    uint8_t         opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    tAVRC_FULL_NAME string;
+} tAVRC_SEARCH_CMD;
+
+/* PlayItem */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    uint8_t     scope;
+    tAVRC_UID   uid;
+    uint16_t    uid_counter;
+} tAVRC_PLAY_ITEM_CMD;
+
+/* AddToNowPlaying */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    uint8_t     scope;
+    tAVRC_UID   uid;
+    uint16_t    uid_counter;
+} tAVRC_ADD_TO_PLAY_CMD;
+
+/* GetTotalNumOfItems */
+typedef struct
+{
+    uint8_t       pdu;
+    tAVRC_STS     status;
+    uint8_t       opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    uint8_t       scope;
+} tAVRC_GET_NUM_OF_ITEMS_CMD;
+
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+} tAVRC_CMD;
+
+/* Continue and Abort */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+    uint8_t     target_pdu;
+} tAVRC_NEXT_CMD;
+
+typedef union
+{
+    uint8_t                     pdu;
+    tAVRC_CMD                   cmd;
+    tAVRC_GET_CAPS_CMD          get_caps;               /* GetCapability */
+    tAVRC_CMD                   list_app_attr;          /* ListPlayerAppAttr */
+    tAVRC_LIST_APP_VALUES_CMD   list_app_values;        /* ListPlayerAppValues */
+    tAVRC_GET_CUR_APP_VALUE_CMD get_cur_app_val;        /* GetCurAppValue */
+    tAVRC_SET_APP_VALUE_CMD     set_app_val;            /* SetAppValue */
+    tAVRC_GET_APP_ATTR_TXT_CMD  get_app_attr_txt;       /* GetAppAttrTxt */
+    tAVRC_GET_APP_VAL_TXT_CMD   get_app_val_txt;        /* GetAppValueTxt */
+    tAVRC_INFORM_CHARSET_CMD    inform_charset;         /* InformCharset */
+    tAVRC_BATTERY_STATUS_CMD    inform_battery_status;  /* InformBatteryStatus */
+    tAVRC_GET_ELEM_ATTRS_CMD    get_elem_attrs;         /* GetElemAttrs */
+    tAVRC_CMD                   get_play_status;        /* GetPlayStatus */
+    tAVRC_REG_NOTIF_CMD         reg_notif;              /* RegNotify */
+    tAVRC_NEXT_CMD              continu;                /* Continue */
+    tAVRC_NEXT_CMD              abort;                  /* Abort */
+
+    tAVRC_SET_ADDR_PLAYER_CMD   addr_player;            /* SetAddrPlayer */
+    tAVRC_SET_VOLUME_CMD        volume;                 /* SetAbsVolume */
+    tAVRC_SET_BR_PLAYER_CMD     br_player;              /* SetBrowsedPlayer */
+    tAVRC_GET_ITEMS_CMD         get_items;              /* GetFolderItems */
+    tAVRC_CHG_PATH_CMD          chg_path;               /* ChangePath */
+    tAVRC_GET_ATTRS_CMD         get_attrs;              /* GetItemAttrs */
+    tAVRC_SEARCH_CMD            search;                 /* Search */
+    tAVRC_PLAY_ITEM_CMD         play_item;              /* PlayItem */
+    tAVRC_ADD_TO_PLAY_CMD       add_to_play;            /* AddToNowPlaying */
+    tAVRC_GET_NUM_OF_ITEMS_CMD  get_num_of_items;       /* GetTotalNumOfItems */
+} tAVRC_COMMAND;
+
+/* GetCapability */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+    uint8_t     capability_id;
+    uint8_t     count;
+    tAVRC_CAPS_PARAM param;
+} tAVRC_GET_CAPS_RSP;
+
+/* ListPlayerAppAttr */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+    uint8_t     num_attr;
+    uint8_t     attrs[AVRC_MAX_APP_ATTR_SIZE];
+} tAVRC_LIST_APP_ATTR_RSP;
+
+/* ListPlayerAppValues */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+    uint8_t     num_val;
+    uint8_t     vals[AVRC_MAX_APP_ATTR_SIZE];
+} tAVRC_LIST_APP_VALUES_RSP;
+
+/* GetCurAppValue */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+    uint8_t     num_val;
+    tAVRC_APP_SETTING   *p_vals;
+} tAVRC_GET_CUR_APP_VALUE_RSP;
+
+/* GetAppAttrTxt */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+    uint8_t     num_attr;
+    tAVRC_APP_SETTING_TEXT   *p_attrs;
+} tAVRC_GET_APP_ATTR_TXT_RSP;
+
+/* GetElemAttrs */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+    uint8_t     num_attr;
+    tAVRC_ATTR_ENTRY   *p_attrs;
+} tAVRC_GET_ELEM_ATTRS_RSP;
+
+/* GetPlayStatus */
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+    uint32_t    song_len;
+    uint32_t    song_pos;
+    uint8_t     play_status;
+} tAVRC_GET_PLAY_STATUS_RSP;
+
+/* notification event parameter for AddressedPlayer change */
+typedef struct
+{
+    uint16_t            player_id;
+    uint16_t            uid_counter;
+} tAVRC_ADDR_PLAYER_PARAM;
+
+#ifndef AVRC_MAX_APP_SETTINGS
+#define AVRC_MAX_APP_SETTINGS    8
+#endif
+
+/* notification event parameter for Player Application setting change */
+typedef struct
+{
+    uint8_t             num_attr;
+    uint8_t             attr_id[AVRC_MAX_APP_SETTINGS];
+    uint8_t             attr_value[AVRC_MAX_APP_SETTINGS];
+} tAVRC_PLAYER_APP_PARAM;
+
+typedef union
+{
+    tAVRC_PLAYSTATE         play_status;
+    tAVRC_UID               track;
+    uint32_t                play_pos;
+    tAVRC_BATTERY_STATUS    battery_status;
+    tAVRC_SYSTEMSTATE       system_status;
+    tAVRC_PLAYER_APP_PARAM  player_setting;
+    tAVRC_ADDR_PLAYER_PARAM addr_player;
+    uint16_t                uid_counter;
+    uint8_t                 volume;
+} tAVRC_NOTIF_RSP_PARAM;
+
+/* RegNotify */
+typedef struct
+{
+    uint8_t                 pdu;
+    tAVRC_STS               status;
+    uint8_t                 opcode;         /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+    uint8_t                 event_id;
+    tAVRC_NOTIF_RSP_PARAM   param;
+} tAVRC_REG_NOTIF_RSP;
+
+/* SetAbsVolume */
+typedef struct
+{
+    uint8_t             pdu;
+    tAVRC_STS           status;
+    uint8_t             opcode;         /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+    uint8_t             volume;
+} tAVRC_SET_VOLUME_RSP;
+
+/* SetBrowsedPlayer */
+typedef struct
+{
+    uint8_t             pdu;
+    tAVRC_STS           status;
+    uint8_t             opcode;         /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+    uint16_t            uid_counter;
+    uint32_t            num_items;
+    uint16_t            charset_id;
+    uint8_t             folder_depth;
+    tAVRC_NAME          *p_folders;
+} tAVRC_SET_BR_PLAYER_RSP;
+
+/* GetFolderItems */
+typedef struct
+{
+    uint8_t             pdu;
+    tAVRC_STS           status;
+    uint8_t             opcode;         /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+    uint16_t            uid_counter;
+    uint16_t            item_count;
+    tAVRC_ITEM          *p_item_list;
+} tAVRC_GET_ITEMS_RSP;
+
+/* ChangePath */
+typedef struct
+{
+    uint8_t             pdu;
+    tAVRC_STS           status;
+    uint8_t             opcode;         /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+    uint32_t            num_items;
+} tAVRC_CHG_PATH_RSP;
+
+/* GetItemAttrs */
+typedef struct
+{
+    uint8_t             pdu;
+    tAVRC_STS           status;
+    uint8_t             opcode;         /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+    uint8_t             attr_count;
+    tAVRC_ATTR_ENTRY    *p_attr_list;
+} tAVRC_GET_ATTRS_RSP;
+
+/* Get Total Number of Items */
+typedef struct
+{
+    uint8_t               pdu;
+    tAVRC_STS           status;
+    uint8_t               opcode;         /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+    uint16_t              uid_counter;
+    uint32_t              num_items;
+} tAVRC_GET_NUM_OF_ITEMS_RSP;
+
+/* Search */
+typedef struct
+{
+    uint8_t             pdu;
+    tAVRC_STS           status;
+    uint8_t             opcode;         /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+    uint16_t            uid_counter;
+    uint32_t            num_items;
+} tAVRC_SEARCH_RSP;
+
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+    uint8_t     target_pdu;
+} tAVRC_NEXT_RSP;
+
+typedef struct
+{
+    uint8_t     pdu;
+    tAVRC_STS   status;
+    uint8_t     opcode;         /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse user. invalid one to generate according to pdu) */
+} tAVRC_RSP;
+
+typedef union
+{
+    uint8_t                         pdu;
+    tAVRC_RSP                       rsp;
+    tAVRC_GET_CAPS_RSP              get_caps;               /* GetCapability */
+    tAVRC_LIST_APP_ATTR_RSP         list_app_attr;          /* ListPlayerAppAttr */
+    tAVRC_LIST_APP_VALUES_RSP       list_app_values;        /* ListPlayerAppValues */
+    tAVRC_GET_CUR_APP_VALUE_RSP     get_cur_app_val;        /* GetCurAppValue */
+    tAVRC_RSP                       set_app_val;            /* SetAppValue */
+    tAVRC_GET_APP_ATTR_TXT_RSP      get_app_attr_txt;       /* GetAppAttrTxt */
+    tAVRC_GET_APP_ATTR_TXT_RSP      get_app_val_txt;        /* GetAppValueTxt */
+    tAVRC_RSP                       inform_charset;         /* InformCharset */
+    tAVRC_RSP                       inform_battery_status;  /* InformBatteryStatus */
+    tAVRC_GET_ELEM_ATTRS_RSP        get_elem_attrs;         /* GetElemAttrs */
+    tAVRC_GET_PLAY_STATUS_RSP       get_play_status;        /* GetPlayStatus */
+    tAVRC_REG_NOTIF_RSP             reg_notif;              /* RegNotify */
+    tAVRC_NEXT_RSP                  continu;                /* Continue */
+    tAVRC_NEXT_RSP                  abort;                  /* Abort */
+
+    tAVRC_RSP                       addr_player;            /* SetAddrPlayer */
+    tAVRC_SET_VOLUME_RSP            volume;                 /* SetAbsVolume */
+    tAVRC_SET_BR_PLAYER_RSP         br_player;              /* SetBrowsedPlayer */
+    tAVRC_GET_ITEMS_RSP             get_items;              /* GetFolderItems */
+    tAVRC_CHG_PATH_RSP              chg_path;               /* ChangePath */
+    tAVRC_GET_ATTRS_RSP             get_attrs;              /* GetItemAttrs */
+    tAVRC_GET_NUM_OF_ITEMS_RSP      get_num_of_items;       /* GetTotalNumberOfItems */
+    tAVRC_SEARCH_RSP                search;                 /* Search */
+    tAVRC_RSP                       play_item;              /* PlayItem */
+    tAVRC_RSP                       add_to_play;            /* AddToNowPlaying */
+} tAVRC_RESPONSE;
+
+#endif
diff --git a/bt/stack/include/ble_advertiser.h b/bt/stack/include/ble_advertiser.h
new file mode 100644
index 0000000..90bff2b
--- /dev/null
+++ b/bt/stack/include/ble_advertiser.h
@@ -0,0 +1,93 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BLE_ADVERTISER_H
+#define BLE_ADVERTISER_H
+
+#include <base/bind.h>
+#include <vector>
+#include "btm_ble_api.h"
+
+#define BTM_BLE_MULTI_ADV_DEFAULT_STD 0
+
+#define BTM_BLE_MULTI_ADV_SUCCESS 0
+#define BTM_BLE_MULTI_ADV_FAILURE 1
+
+using MultiAdvCb = base::Callback<void(uint8_t /* status */)>;
+
+extern "C" {
+// methods we must have defined
+tBTM_STATUS btm_ble_set_connectability(uint16_t combined_mode);
+void btm_ble_update_dmt_flag_bits(uint8_t *flag_value,
+                                  const uint16_t connect_mode,
+                                  const uint16_t disc_mode);
+void btm_gen_resolvable_private_addr(void *p_cmd_cplt_cback);
+void btm_acl_update_conn_addr(uint8_t conn_handle, BD_ADDR address);
+void GATT_Listen(bool start);
+
+// methods we expose to c code:
+void btm_ble_multi_adv_cleanup(void);
+void btm_ble_multi_adv_init();
+}
+
+typedef struct {
+  uint16_t adv_int_min;
+  uint16_t adv_int_max;
+  uint8_t adv_type;
+  tBTM_BLE_ADV_CHNL_MAP channel_map;
+  tBTM_BLE_AFP adv_filter_policy;
+  tBTM_BLE_ADV_TX_POWER tx_power;
+} tBTM_BLE_ADV_PARAMS;
+
+class BleAdvertiserHciInterface;
+
+class BleAdvertisingManager {
+ public:
+  virtual ~BleAdvertisingManager() = default;
+
+  static void Initialize(BleAdvertiserHciInterface *interface);
+  static void CleanUp();
+  static BleAdvertisingManager *Get();
+
+  /* Register an advertising instance, status will be returned in |cb|
+  * callback, with assigned id, if operation succeeds. Instance is freed when
+  * advertising is disabled by calling |BTM_BleDisableAdvInstance|, or when any
+  * of the operations fails. */
+  virtual void RegisterAdvertiser(
+      base::Callback<void(uint8_t /* inst_id */, uint8_t /* status */)>) = 0;
+
+  /* This function enables/disables an advertising instance. Operation status is
+   * returned in |cb| */
+  virtual void Enable(uint8_t inst_id, bool enable, MultiAdvCb cb, int timeout_s,
+                    MultiAdvCb timeout_cb) = 0;
+
+  /* This function update a Multi-ADV instance with the specififed adv
+   * parameters. */
+  virtual void SetParameters(uint8_t inst_id, tBTM_BLE_ADV_PARAMS *p_params,
+                             MultiAdvCb cb) = 0;
+
+  /* This function configure a Multi-ADV instance with the specified adv data or
+   * scan response data.*/
+  virtual void SetData(uint8_t inst_id, bool is_scan_rsp,
+                       std::vector<uint8_t> data, MultiAdvCb cb) = 0;
+
+  /*  This function disable a Multi-ADV instance */
+  virtual void Unregister(uint8_t inst_id) = 0;
+};
+
+#endif  // BLE_ADVERTISER_H
diff --git a/bt/stack/include/bnep_api.h b/bt/stack/include/bnep_api.h
new file mode 100644
index 0000000..41e4906
--- /dev/null
+++ b/bt/stack/include/bnep_api.h
@@ -0,0 +1,464 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2001-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 interface file contains the interface to the Bluetooth Network
+ *  Encapsilation Protocol (BNEP).
+ *
+ ******************************************************************************/
+#ifndef BNEP_API_H
+#define BNEP_API_H
+
+#include "l2c_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+/* Define the minimum offset needed in a GKI buffer for
+** sending BNEP packets. Note, we are currently not sending
+** extension headers, but may in the future, so allow
+** space for them
+*/
+#define BNEP_MINIMUM_OFFSET        (15 + L2CAP_MIN_OFFSET)
+#define BNEP_INVALID_HANDLE         0xFFFF
+
+/*****************************************************************************
+**  Type Definitions
+*****************************************************************************/
+
+/* Define the result codes from BNEP
+*/
+enum
+{
+    BNEP_SUCCESS,                       /* Success                           */
+    BNEP_CONN_DISCONNECTED,             /* Connection terminated   */
+    BNEP_NO_RESOURCES,                  /* No resources                      */
+    BNEP_MTU_EXCEDED,                   /* Attempt to write long data        */
+    BNEP_INVALID_OFFSET,                /* Insufficient offset in GKI buffer */
+    BNEP_CONN_FAILED,                   /* Connection failed                 */
+    BNEP_CONN_FAILED_CFG,               /* Connection failed cos of config   */
+    BNEP_CONN_FAILED_SRC_UUID,          /* Connection failed wrong source UUID   */
+    BNEP_CONN_FAILED_DST_UUID,          /* Connection failed wrong destination UUID   */
+    BNEP_CONN_FAILED_UUID_SIZE,         /* Connection failed wrong size UUID   */
+    BNEP_Q_SIZE_EXCEEDED,               /* Too many buffers to dest          */
+    BNEP_TOO_MANY_FILTERS,              /* Too many local filters specified  */
+    BNEP_SET_FILTER_FAIL,               /* Set Filter failed  */
+    BNEP_WRONG_HANDLE,                  /* Wrong handle for the connection  */
+    BNEP_WRONG_STATE,                   /* Connection is in wrong state */
+    BNEP_SECURITY_FAIL,                 /* Failed because of security */
+    BNEP_IGNORE_CMD,                    /* To ignore the rcvd command */
+    BNEP_TX_FLOW_ON,                    /* tx data flow enabled */
+    BNEP_TX_FLOW_OFF                    /* tx data flow disabled */
+
+}; typedef uint8_t tBNEP_RESULT;
+
+
+/***************************
+**  Callback Functions
+****************************/
+
+/* Connection state change callback prototype. Parameters are
+**              Connection handle
+**              BD Address of remote
+**              Connection state change result
+**                  BNEP_SUCCESS indicates connection is success
+**                  All values are used to indicate the reason for failure
+**              Flag to indicate if it is just a role change
+*/
+typedef void (tBNEP_CONN_STATE_CB) (uint16_t handle,
+                                    BD_ADDR rem_bda,
+                                    tBNEP_RESULT result,
+                                    bool    is_role_change);
+
+
+
+
+/* Connection indication callback prototype. Parameters are
+**              BD Address of remote, remote UUID and local UUID
+**              and flag to indicate role change and handle to the connection
+**              When BNEP calls this function profile should
+**              use BNEP_ConnectResp call to accept or reject the request
+*/
+typedef void (tBNEP_CONNECT_IND_CB) (uint16_t handle,
+                                     BD_ADDR bd_addr,
+                                     tBT_UUID *remote_uuid,
+                                     tBT_UUID *local_uuid,
+                                     bool    is_role_change);
+
+
+
+/* Data buffer received indication callback prototype. Parameters are
+**              Handle to the connection
+**              Source BD/Ethernet Address
+**              Dest BD/Ethernet address
+**              Protocol
+**              Pointer to the buffer
+**              Flag to indicate whether extension headers to be forwarded are present
+*/
+typedef void (tBNEP_DATA_BUF_CB) (uint16_t handle,
+                                  uint8_t *src,
+                                  uint8_t *dst,
+                                  uint16_t protocol,
+                                  BT_HDR *p_buf,
+                                  bool    fw_ext_present);
+
+
+/* Data received indication callback prototype. Parameters are
+**              Handle to the connection
+**              Source BD/Ethernet Address
+**              Dest BD/Ethernet address
+**              Protocol
+**              Pointer to the beginning of the data
+**              Length of data
+**              Flag to indicate whether extension headers to be forwarded are present
+*/
+typedef void (tBNEP_DATA_IND_CB) (uint16_t handle,
+                                  uint8_t *src,
+                                  uint8_t *dst,
+                                  uint16_t protocol,
+                                  uint8_t *p_data,
+                                  uint16_t len,
+                                  bool    fw_ext_present);
+
+/* Flow control callback for TX data. Parameters are
+**              Handle to the connection
+**              Event  flow status
+*/
+typedef void (tBNEP_TX_DATA_FLOW_CB) (uint16_t handle,
+                                      tBNEP_RESULT  event);
+
+/* Filters received indication callback prototype. Parameters are
+**              Handle to the connection
+**              true if the cb is called for indication
+**              Ignore this if it is indication, otherwise it is the result
+**                      for the filter set operation performed by the local
+**                      device
+**              Number of protocol filters present
+**              Pointer to the filters start. Filters are present in pairs
+**                      of start of the range and end of the range.
+**                      They will be present in big endian order. First
+**                      two bytes will be starting of the first range and
+**                      next two bytes will be ending of the range.
+*/
+typedef void (tBNEP_FILTER_IND_CB) (uint16_t handle,
+                                    bool    indication,
+                                    tBNEP_RESULT result,
+                                    uint16_t num_filters,
+                                    uint8_t *p_filters);
+
+
+
+/* Multicast Filters received indication callback prototype. Parameters are
+**              Handle to the connection
+**              true if the cb is called for indication
+**              Ignore this if it is indication, otherwise it is the result
+**                      for the filter set operation performed by the local
+**                      device
+**              Number of multicast filters present
+**              Pointer to the filters start. Filters are present in pairs
+**                      of start of the range and end of the range.
+**                      First six bytes will be starting of the first range and
+**                      next six bytes will be ending of the range.
+*/
+typedef void (tBNEP_MFILTER_IND_CB) (uint16_t handle,
+                                     bool    indication,
+                                     tBNEP_RESULT result,
+                                     uint16_t num_mfilters,
+                                     uint8_t *p_mfilters);
+
+/* This is the structure used by profile to register with BNEP */
+typedef struct
+{
+    tBNEP_CONNECT_IND_CB    *p_conn_ind_cb;     /* To indicate the conn request */
+    tBNEP_CONN_STATE_CB     *p_conn_state_cb;   /* To indicate conn state change */
+    tBNEP_DATA_IND_CB       *p_data_ind_cb;     /* To pass the data received */
+    tBNEP_DATA_BUF_CB       *p_data_buf_cb;     /* To pass the data buffer received */
+    tBNEP_TX_DATA_FLOW_CB   *p_tx_data_flow_cb; /* data flow callback */
+    tBNEP_FILTER_IND_CB     *p_filter_ind_cb;   /* To indicate that peer set protocol filters */
+    tBNEP_MFILTER_IND_CB    *p_mfilter_ind_cb;  /* To indicate that peer set mcast filters */
+
+} tBNEP_REGISTER;
+
+
+
+/* This is the structure used by profile to get the status of BNEP */
+typedef struct
+{
+#define BNEP_STATUS_FAILE            0
+#define BNEP_STATUS_CONNECTED        1
+    uint8_t           con_status;
+
+    uint16_t          l2cap_cid;
+    BD_ADDR           rem_bda;
+    uint16_t          rem_mtu_size;
+    uint16_t          xmit_q_depth;
+
+    uint16_t          sent_num_filters;
+    uint16_t          sent_mcast_filters;
+    uint16_t          rcvd_num_filters;
+    uint16_t          rcvd_mcast_filters;
+    tBT_UUID          src_uuid;
+    tBT_UUID          dst_uuid;
+
+} tBNEP_STATUS;
+
+
+
+/*****************************************************************************
+**  External Function Declarations
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function         BNEP_Register
+**
+** Description      This function is called by the upper layer to register
+**                  its callbacks with BNEP
+**
+** Parameters:      p_reg_info - contains all callback function pointers
+**
+**
+** Returns          BNEP_SUCCESS        if registered successfully
+**                  BNEP_FAILURE        if connection state callback is missing
+**
+*******************************************************************************/
+extern tBNEP_RESULT BNEP_Register (tBNEP_REGISTER *p_reg_info);
+
+/*******************************************************************************
+**
+** Function         BNEP_Deregister
+**
+** Description      This function is called by the upper layer to de-register
+**                  its callbacks.
+**
+** Parameters:      void
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void BNEP_Deregister (void);
+
+
+/*******************************************************************************
+**
+** Function         BNEP_Connect
+**
+** Description      This function creates a BNEP connection to a remote
+**                  device.
+**
+** Parameters:      p_rem_addr  - BD_ADDR of the peer
+**                  src_uuid    - source uuid for the connection
+**                  dst_uuid    - destination uuid for the connection
+**                  p_handle    - pointer to return the handle for the connection
+**
+** Returns          BNEP_SUCCESS                if connection started
+**                  BNEP_NO_RESOURCES           if no resources
+**
+*******************************************************************************/
+extern tBNEP_RESULT BNEP_Connect (BD_ADDR p_rem_bda,
+                                  tBT_UUID *src_uuid,
+                                  tBT_UUID *dst_uuid,
+                                  uint16_t *p_handle);
+
+/*******************************************************************************
+**
+** Function         BNEP_ConnectResp
+**
+** Description      This function is called in responce to connection indication
+**
+**
+** Parameters:      handle  - handle given in the connection indication
+**                  resp    - responce for the connection indication
+**
+** Returns          BNEP_SUCCESS                if connection started
+**                  BNEP_WRONG_HANDLE           if the connection is not found
+**                  BNEP_WRONG_STATE            if the responce is not expected
+**
+*******************************************************************************/
+extern tBNEP_RESULT BNEP_ConnectResp (uint16_t handle, tBNEP_RESULT resp);
+
+/*******************************************************************************
+**
+** Function         BNEP_Disconnect
+**
+** Description      This function is called to close the specified connection.
+**
+** Parameters:      handle   - handle of the connection
+**
+** Returns          BNEP_SUCCESS                if connection is disconnected
+**                  BNEP_WRONG_HANDLE           if no connection is not found
+**
+*******************************************************************************/
+extern tBNEP_RESULT BNEP_Disconnect (uint16_t handle);
+
+/*******************************************************************************
+**
+** Function         BNEP_WriteBuf
+**
+** Description      This function sends data in a GKI buffer on BNEP connection
+**
+** Parameters:      handle       - handle of the connection to write
+**                  p_dest_addr  - BD_ADDR/Ethernet addr of the destination
+**                  p_buf        - pointer to address of buffer with data
+**                  protocol     - protocol type of the packet
+**                  p_src_addr   - (optional) BD_ADDR/ethernet address of the source
+**                                 (should be NULL if it is local BD Addr)
+**                  fw_ext_present - forwarded extensions present
+**
+** Returns:         BNEP_WRONG_HANDLE       - if passed handle is not valid
+**                  BNEP_MTU_EXCEDED        - If the data length is greater than MTU
+**                  BNEP_IGNORE_CMD         - If the packet is filtered out
+**                  BNEP_Q_SIZE_EXCEEDED    - If the Tx Q is full
+**                  BNEP_SUCCESS            - If written successfully
+**
+*******************************************************************************/
+extern tBNEP_RESULT BNEP_WriteBuf (uint16_t handle,
+                                   uint8_t *p_dest_addr,
+                                   BT_HDR *p_buf,
+                                   uint16_t protocol,
+                                   uint8_t *p_src_addr,
+                                   bool    fw_ext_present);
+
+/*******************************************************************************
+**
+** Function         BNEP_Write
+**
+** Description      This function sends data over a BNEP connection
+**
+** Parameters:      handle       - handle of the connection to write
+**                  p_dest_addr  - BD_ADDR/Ethernet addr of the destination
+**                  p_data       - pointer to data start
+**                  protocol     - protocol type of the packet
+**                  p_src_addr   - (optional) BD_ADDR/ethernet address of the source
+**                                 (should be NULL if it is local BD Addr)
+**                  fw_ext_present - forwarded extensions present
+**
+** Returns:         BNEP_WRONG_HANDLE       - if passed handle is not valid
+**                  BNEP_MTU_EXCEDED        - If the data length is greater than MTU
+**                  BNEP_IGNORE_CMD         - If the packet is filtered out
+**                  BNEP_Q_SIZE_EXCEEDED    - If the Tx Q is full
+**                  BNEP_NO_RESOURCES       - If not able to allocate a buffer
+**                  BNEP_SUCCESS            - If written successfully
+**
+*******************************************************************************/
+extern tBNEP_RESULT  BNEP_Write (uint16_t handle,
+                                 uint8_t *p_dest_addr,
+                                 uint8_t *p_data,
+                                 uint16_t len,
+                                 uint16_t protocol,
+                                 uint8_t *p_src_addr,
+                                 bool    fw_ext_present);
+
+/*******************************************************************************
+**
+** Function         BNEP_SetProtocolFilters
+**
+** Description      This function sets the protocol filters on peer device
+**
+** Parameters:      handle        - Handle for the connection
+**                  num_filters   - total number of filter ranges
+**                  p_start_array - Array of beginings of all protocol ranges
+**                  p_end_array   - Array of ends of all protocol ranges
+**
+** Returns          BNEP_WRONG_HANDLE           - if the connection handle is not valid
+**                  BNEP_SET_FILTER_FAIL        - if the connection is in wrong state
+**                  BNEP_TOO_MANY_FILTERS       - if too many filters
+**                  BNEP_SUCCESS                - if request sent successfully
+**
+*******************************************************************************/
+extern tBNEP_RESULT BNEP_SetProtocolFilters (uint16_t handle,
+                                             uint16_t num_filters,
+                                             uint16_t *p_start_array,
+                                             uint16_t *p_end_array);
+
+/*******************************************************************************
+**
+** Function         BNEP_SetMulticastFilters
+**
+** Description      This function sets the filters for multicast addresses for BNEP.
+**
+** Parameters:      handle        - Handle for the connection
+**                  num_filters   - total number of filter ranges
+**                  p_start_array - Pointer to sequence of beginings of all
+**                                         multicast address ranges
+**                  p_end_array   - Pointer to sequence of ends of all
+**                                         multicast address ranges
+**
+** Returns          BNEP_WRONG_HANDLE           - if the connection handle is not valid
+**                  BNEP_SET_FILTER_FAIL        - if the connection is in wrong state
+**                  BNEP_TOO_MANY_FILTERS       - if too many filters
+**                  BNEP_SUCCESS                - if request sent successfully
+**
+*******************************************************************************/
+extern tBNEP_RESULT BNEP_SetMulticastFilters (uint16_t handle,
+                                              uint16_t num_filters,
+                                              uint8_t *p_start_array,
+                                              uint8_t *p_end_array);
+
+/*******************************************************************************
+**
+** Function         BNEP_SetTraceLevel
+**
+** Description      This function sets the trace level for BNEP. If called with
+**                  a value of 0xFF, it simply reads the current trace level.
+**
+** Returns          the new (current) trace level
+**
+*******************************************************************************/
+extern uint8_t BNEP_SetTraceLevel (uint8_t new_level);
+
+/*******************************************************************************
+**
+** Function         BNEP_Init
+**
+** Description      This function initializes the BNEP unit. It should be called
+**                  before accessing any other APIs to initialize the control block
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void BNEP_Init (void);
+
+/*******************************************************************************
+**
+** Function         BNEP_GetStatus
+**
+** Description      This function gets the status information for BNEP connection
+**
+** Returns          BNEP_SUCCESS            - if the status is available
+**                  BNEP_NO_RESOURCES       - if no structure is passed for output
+**                  BNEP_WRONG_HANDLE       - if the handle is invalid
+**                  BNEP_WRONG_STATE        - if not in connected state
+**
+*******************************************************************************/
+extern tBNEP_RESULT BNEP_GetStatus (uint16_t handle, tBNEP_STATUS *p_status);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/bt/stack/include/bt_types.h b/bt/stack/include/bt_types.h
new file mode 100644
index 0000000..2b5e176
--- /dev/null
+++ b/bt/stack/include/bt_types.h
@@ -0,0 +1,784 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+
+#ifndef BT_TYPES_H
+#define BT_TYPES_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifndef FALSE
+#  define FALSE false
+#endif
+
+#ifndef TRUE
+#  define TRUE true
+#endif
+
+#ifdef __arm
+#  define PACKED  __packed
+#  define INLINE  __inline
+#else
+#  define PACKED
+#  define INLINE
+#endif
+
+/* READ WELL !!
+**
+** This section defines global events. These are events that cross layers.
+** Any event that passes between layers MUST be one of these events. Tasks
+** can use their own events internally, but a FUNDAMENTAL design issue is
+** that global events MUST be one of these events defined below.
+**
+** The convention used is the the event name contains the layer that the
+** event is going to.
+*/
+#define BT_EVT_MASK                 0xFF00
+#define BT_SUB_EVT_MASK             0x00FF
+                                                /* To Bluetooth Upper Layers        */
+                                                /************************************/
+#define BT_EVT_TO_BTU_L2C_EVT       0x0900      /* L2CAP event */
+#define BT_EVT_TO_BTU_HCI_EVT       0x1000      /* HCI Event                        */
+#define BT_EVT_TO_BTU_HCI_BR_EDR_EVT (0x0000 | BT_EVT_TO_BTU_HCI_EVT)      /* event from BR/EDR controller */
+#define BT_EVT_TO_BTU_HCI_AMP1_EVT   (0x0001 | BT_EVT_TO_BTU_HCI_EVT)      /* event from local AMP 1 controller */
+#define BT_EVT_TO_BTU_HCI_AMP2_EVT   (0x0002 | BT_EVT_TO_BTU_HCI_EVT)      /* event from local AMP 2 controller */
+#define BT_EVT_TO_BTU_HCI_AMP3_EVT   (0x0003 | BT_EVT_TO_BTU_HCI_EVT)      /* event from local AMP 3 controller */
+
+#define BT_EVT_TO_BTU_HCI_ACL       0x1100      /* ACL Data from HCI                */
+#define BT_EVT_TO_BTU_HCI_SCO       0x1200      /* SCO Data from HCI                */
+#define BT_EVT_TO_BTU_HCIT_ERR      0x1300      /* HCI Transport Error              */
+
+#define BT_EVT_TO_BTU_SP_EVT        0x1400      /* Serial Port Event                */
+#define BT_EVT_TO_BTU_SP_DATA       0x1500      /* Serial Port Data                 */
+
+#define BT_EVT_TO_BTU_HCI_CMD       0x1600      /* HCI command from upper layer     */
+
+
+#define BT_EVT_TO_BTU_L2C_SEG_XMIT  0x1900      /* L2CAP segment(s) transmitted     */
+
+#define BT_EVT_PROXY_INCOMING_MSG   0x1A00      /* BlueStackTester event: incoming message from target */
+
+#define BT_EVT_BTSIM                0x1B00      /* Insight BTSIM event */
+#define BT_EVT_BTISE                0x1C00      /* Insight Script Engine event */
+
+                                                /* To LM                            */
+                                                /************************************/
+#define BT_EVT_TO_LM_HCI_CMD        0x2000      /* HCI Command                      */
+#define BT_EVT_TO_LM_HCI_ACL        0x2100      /* HCI ACL Data                     */
+#define BT_EVT_TO_LM_HCI_SCO        0x2200      /* HCI SCO Data                     */
+#define BT_EVT_TO_LM_HCIT_ERR       0x2300      /* HCI Transport Error              */
+#define BT_EVT_TO_LM_LC_EVT         0x2400      /* LC event                         */
+#define BT_EVT_TO_LM_LC_LMP         0x2500      /* LC Received LMP command frame    */
+#define BT_EVT_TO_LM_LC_ACL         0x2600      /* LC Received ACL data             */
+#define BT_EVT_TO_LM_LC_SCO         0x2700      /* LC Received SCO data  (not used) */
+#define BT_EVT_TO_LM_LC_ACL_TX      0x2800      /* LMP data transmit complete       */
+#define BT_EVT_TO_LM_LC_LMPC_TX     0x2900      /* LMP Command transmit complete    */
+#define BT_EVT_TO_LM_LOCAL_ACL_LB   0x2a00      /* Data to be locally loopbacked    */
+#define BT_EVT_TO_LM_HCI_ACL_ACK    0x2b00      /* HCI ACL Data ack      (not used) */
+#define BT_EVT_TO_LM_DIAG           0x2c00      /* LM Diagnostics commands          */
+
+
+#define BT_EVT_TO_BTM_CMDS          0x2f00
+#define BT_EVT_TO_BTM_PM_MDCHG_EVT (0x0001 | BT_EVT_TO_BTM_CMDS)
+
+#define BT_EVT_TO_TCS_CMDS          0x3000
+
+#define BT_EVT_TO_CTP_CMDS          0x3300
+
+/* ftp events */
+#define BT_EVT_TO_FTP_SRVR_CMDS     0x3600
+#define BT_EVT_TO_FTP_CLNT_CMDS     0x3700
+
+#define BT_EVT_TO_BTU_SAP           0x3800       /* SIM Access Profile events */
+
+/* opp events */
+#define BT_EVT_TO_OPP_SRVR_CMDS     0x3900
+#define BT_EVT_TO_OPP_CLNT_CMDS     0x3a00
+
+/* gap events */
+#define BT_EVT_TO_GAP_MSG           0x3b00
+
+/* for NFC                          */
+                                                /************************************/
+#define BT_EVT_TO_NFC_NCI           0x4000      /* NCI Command, Notification or Data*/
+#define BT_EVT_TO_NFC_INIT          0x4100      /* Initialization message */
+#define BT_EVT_TO_NCI_LP            0x4200      /* Low power */
+#define BT_EVT_TO_NFC_ERR           0x4300      /* Error notification to NFC Task */
+
+#define BT_EVT_TO_NFCCSIM_NCI       0x4a00      /* events to NFCC simulation (NCI packets) */
+
+/* HCISU Events */
+
+#define BT_EVT_HCISU                0x5000
+
+#define BT_EVT_TO_HCISU_RECONFIG_EVT            (0x0001 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_UPDATE_BAUDRATE_EVT     (0x0002 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_LP_ENABLE_EVT           (0x0003 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_LP_DISABLE_EVT          (0x0004 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_LP_APP_SLEEPING_EVT     (0x0005 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_LP_ALLOW_BT_SLEEP_EVT   (0x0006 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_LP_WAKEUP_HOST_EVT      (0x0007 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_LP_RCV_H4IBSS_EVT       (0x0008 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_H5_RESET_EVT            (0x0009 | BT_EVT_HCISU)
+#define BT_EVT_HCISU_START_QUICK_TIMER          (0x000a | BT_EVT_HCISU)
+
+#define BT_EVT_DATA_TO_AMP_1        0x5100
+#define BT_EVT_DATA_TO_AMP_15       0x5f00
+
+/* HSP Events */
+
+#define BT_EVT_BTU_HSP2             0x6000
+
+#define BT_EVT_TO_BTU_HSP2_EVT     (0x0001 | BT_EVT_BTU_HSP2)
+
+/* BPP Events */
+#define BT_EVT_TO_BPP_PR_CMDS       0x6100      /* Printer Events */
+#define BT_EVT_TO_BPP_SND_CMDS      0x6200      /* BPP Sender Events */
+
+/* BIP Events */
+#define BT_EVT_TO_BIP_CMDS          0x6300
+
+/* HCRP Events */
+
+#define BT_EVT_BTU_HCRP             0x7000
+
+#define BT_EVT_TO_BTU_HCRP_EVT     (0x0001 | BT_EVT_BTU_HCRP)
+#define BT_EVT_TO_BTU_HCRPM_EVT    (0x0002 | BT_EVT_BTU_HCRP)
+
+
+#define BT_EVT_BTU_HFP              0x8000
+#define BT_EVT_TO_BTU_HFP_EVT      (0x0001 | BT_EVT_BTU_HFP)
+
+#define BT_EVT_BTU_IPC_EVT          0x9000
+#define BT_EVT_BTU_IPC_LOGMSG_EVT  (0x0000 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_ACL_EVT     (0x0001 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_BTU_EVT     (0x0002 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_L2C_EVT     (0x0003 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_L2C_MSG_EVT (0x0004 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_BTM_EVT     (0x0005 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_AVDT_EVT    (0x0006 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_SLIP_EVT    (0x0007 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_MGMT_EVT    (0x0008 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_BTTRC_EVT   (0x0009 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_BURST_EVT   (0x000A | BT_EVT_BTU_IPC_EVT)
+
+
+/* BTIF Events */
+#define BT_EVT_BTIF                 0xA000
+#define BT_EVT_CONTEXT_SWITCH_EVT  (0x0001 | BT_EVT_BTIF)
+
+/* Define the header of each buffer used in the Bluetooth stack.
+*/
+typedef struct
+{
+    uint16_t          event;
+    uint16_t          len;
+    uint16_t          offset;
+    uint16_t          layer_specific;
+    uint8_t           data[];
+} BT_HDR;
+
+#define BT_HDR_SIZE (sizeof (BT_HDR))
+
+#define BT_PSM_SDP                      0x0001
+#define BT_PSM_RFCOMM                   0x0003
+#define BT_PSM_TCS                      0x0005
+#define BT_PSM_CTP                      0x0007
+#define BT_PSM_BNEP                     0x000F
+#define BT_PSM_HIDC                     0x0011
+#define BT_PSM_HIDI                     0x0013
+#define BT_PSM_UPNP                     0x0015
+#define BT_PSM_AVCTP                    0x0017
+#define BT_PSM_AVDTP                    0x0019
+#define BT_PSM_AVCTP_13                 0x001B /* Advanced Control - Browsing */
+#define BT_PSM_UDI_CP                   0x001D /* Unrestricted Digital Information Profile C-Plane  */
+#define BT_PSM_ATT                      0x001F /* Attribute Protocol  */
+
+/* These macros extract the HCI opcodes from a buffer
+*/
+#define HCI_GET_CMD_HDR_OPCODE(p)    (uint16_t)((*((uint8_t *)((p) + 1) + (p)->offset) + \
+                                              (*((uint8_t *)((p) + 1) + (p)->offset + 1) << 8)))
+#define HCI_GET_CMD_HDR_PARAM_LEN(p) (uint8_t)  (*((uint8_t *)((p) + 1) + (p)->offset + 2))
+
+#define HCI_GET_EVT_HDR_OPCODE(p)    (uint8_t)(*((uint8_t *)((p) + 1) + (p)->offset))
+#define HCI_GET_EVT_HDR_PARAM_LEN(p) (uint8_t)  (*((uint8_t *)((p) + 1) + (p)->offset + 1))
+
+
+/********************************************************************************
+** Macros to get and put bytes to and from a stream (Little Endian format).
+*/
+#define UINT64_TO_BE_STREAM(p, u64) {*(p)++ = (uint8_t)((u64) >> 56);  *(p)++ = (uint8_t)((u64) >> 48); *(p)++ = (uint8_t)((u64) >> 40); *(p)++ = (uint8_t)((u64) >> 32); \
+                                     *(p)++ = (uint8_t)((u64) >> 24);  *(p)++ = (uint8_t)((u64) >> 16); *(p)++ = (uint8_t)((u64) >> 8); *(p)++ = (uint8_t)(u64); }
+#define UINT32_TO_STREAM(p, u32) {*(p)++ = (uint8_t)(u32); *(p)++ = (uint8_t)((u32) >> 8); *(p)++ = (uint8_t)((u32) >> 16); *(p)++ = (uint8_t)((u32) >> 24);}
+#define UINT24_TO_STREAM(p, u24) {*(p)++ = (uint8_t)(u24); *(p)++ = (uint8_t)((u24) >> 8); *(p)++ = (uint8_t)((u24) >> 16);}
+#define UINT16_TO_STREAM(p, u16) {*(p)++ = (uint8_t)(u16); *(p)++ = (uint8_t)((u16) >> 8);}
+#define UINT8_TO_STREAM(p, u8)   {*(p)++ = (uint8_t)(u8);}
+#define INT8_TO_STREAM(p, u8)    {*(p)++ = (int8_t)(u8);}
+#define ARRAY32_TO_STREAM(p, a)  {int ijk; for (ijk = 0; ijk < 32;           ijk++) *(p)++ = (uint8_t) (a)[31 - ijk];}
+#define ARRAY16_TO_STREAM(p, a)  {int ijk; for (ijk = 0; ijk < 16;           ijk++) *(p)++ = (uint8_t) (a)[15 - ijk];}
+#define ARRAY8_TO_STREAM(p, a)   {int ijk; for (ijk = 0; ijk < 8;            ijk++) *(p)++ = (uint8_t) (a)[7 - ijk];}
+#define BDADDR_TO_STREAM(p, a)   {int ijk; for (ijk = 0; ijk < BD_ADDR_LEN;  ijk++) *(p)++ = (uint8_t) (a)[BD_ADDR_LEN - 1 - ijk];}
+#define LAP_TO_STREAM(p, a)      {int ijk; for (ijk = 0; ijk < LAP_LEN;      ijk++) *(p)++ = (uint8_t) (a)[LAP_LEN - 1 - ijk];}
+#define DEVCLASS_TO_STREAM(p, a) {int ijk; for (ijk = 0; ijk < DEV_CLASS_LEN;ijk++) *(p)++ = (uint8_t) (a)[DEV_CLASS_LEN - 1 - ijk];}
+#define ARRAY_TO_STREAM(p, a, len) {int ijk; for (ijk = 0; ijk < (len);        ijk++) *(p)++ = (uint8_t) (a)[ijk];}
+#define REVERSE_ARRAY_TO_STREAM(p, a, len)  {int ijk; for (ijk = 0; ijk < (len); ijk++) *(p)++ = (uint8_t) (a)[(len) - 1 - ijk];}
+
+#define STREAM_TO_UINT8(u8, p)   {(u8) = (uint8_t)(*(p)); (p) += 1;}
+#define STREAM_TO_UINT16(u16, p) {(u16) = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); (p) += 2;}
+#define STREAM_TO_UINT24(u32, p) {(u32) = (((uint32_t)(*(p))) + ((((uint32_t)(*((p) + 1)))) << 8) + ((((uint32_t)(*((p) + 2)))) << 16) ); (p) += 3;}
+#define STREAM_TO_UINT32(u32, p) {(u32) = (((uint32_t)(*(p))) + ((((uint32_t)(*((p) + 1)))) << 8) + ((((uint32_t)(*((p) + 2)))) << 16) + ((((uint32_t)(*((p) + 3)))) << 24)); (p) += 4;}
+#define STREAM_TO_BDADDR(a, p)   {int ijk; uint8_t *pbda = (uint8_t *)(a) + BD_ADDR_LEN - 1; for (ijk = 0; ijk < BD_ADDR_LEN; ijk++) *pbda-- = *(p)++;}
+#define STREAM_TO_ARRAY32(a, p)  {int ijk; uint8_t *_pa = (uint8_t *)(a) + 31; for (ijk = 0; ijk < 32; ijk++) *_pa-- = *(p)++;}
+#define STREAM_TO_ARRAY16(a, p)  {int ijk; uint8_t *_pa = (uint8_t *)(a) + 15; for (ijk = 0; ijk < 16; ijk++) *_pa-- = *(p)++;}
+#define STREAM_TO_ARRAY8(a, p)   {int ijk; uint8_t *_pa = (uint8_t *)(a) + 7; for (ijk = 0; ijk < 8; ijk++) *_pa-- = *(p)++;}
+#define STREAM_TO_DEVCLASS(a, p) {int ijk; uint8_t *_pa = (uint8_t *)(a) + DEV_CLASS_LEN - 1; for (ijk = 0; ijk < DEV_CLASS_LEN; ijk++) *_pa-- = *(p)++;}
+#define STREAM_TO_LAP(a, p)      {int ijk; uint8_t *plap = (uint8_t *)(a) + LAP_LEN - 1; for (ijk = 0; ijk < LAP_LEN; ijk++) *plap-- = *(p)++;}
+#define STREAM_TO_ARRAY(a, p, len) {int ijk; for (ijk = 0; ijk < (len); ijk++) ((uint8_t *) (a))[ijk] = *(p)++;}
+#define REVERSE_STREAM_TO_ARRAY(a, p, len) {int ijk; uint8_t *_pa = (uint8_t *)(a) + (len) - 1; for (ijk = 0; ijk < (len); ijk++) *_pa-- = *(p)++;}
+
+#define STREAM_SKIP_UINT8(p)  do { (p) += 1; } while (0)
+#define STREAM_SKIP_UINT16(p) do { (p) += 2; } while (0)
+
+/********************************************************************************
+** Macros to get and put bytes to and from a field (Little Endian format).
+** These are the same as to stream, except the pointer is not incremented.
+*/
+#define UINT32_TO_FIELD(p, u32) {*(uint8_t *)(p) = (uint8_t)(u32); *((uint8_t *)(p)+1) = (uint8_t)((u32) >> 8); *((uint8_t *)(p)+2) = (uint8_t)((u32) >> 16); *((uint8_t *)(p)+3) = (uint8_t)((u32) >> 24);}
+#define UINT24_TO_FIELD(p, u24) {*(uint8_t *)(p) = (uint8_t)(u24); *((uint8_t *)(p)+1) = (uint8_t)((u24) >> 8); *((uint8_t *)(p)+2) = (uint8_t)((u24) >> 16);}
+#define UINT16_TO_FIELD(p, u16) {*(uint8_t *)(p) = (uint8_t)(u16); *((uint8_t *)(p)+1) = (uint8_t)((u16) >> 8);}
+#define UINT8_TO_FIELD(p, u8)   {*(uint8_t *)(p) = (uint8_t)(u8);}
+
+
+/********************************************************************************
+** Macros to get and put bytes to and from a stream (Big Endian format)
+*/
+#define UINT32_TO_BE_STREAM(p, u32) {*(p)++ = (uint8_t)((u32) >> 24);  *(p)++ = (uint8_t)((u32) >> 16); *(p)++ = (uint8_t)((u32) >> 8); *(p)++ = (uint8_t)(u32); }
+#define UINT24_TO_BE_STREAM(p, u24) {*(p)++ = (uint8_t)((u24) >> 16); *(p)++ = (uint8_t)((u24) >> 8); *(p)++ = (uint8_t)(u24);}
+#define UINT16_TO_BE_STREAM(p, u16) {*(p)++ = (uint8_t)((u16) >> 8); *(p)++ = (uint8_t)(u16);}
+#define UINT8_TO_BE_STREAM(p, u8)   {*(p)++ = (uint8_t)(u8);}
+#define ARRAY_TO_BE_STREAM(p, a, len) {int ijk; for (ijk = 0; ijk < (len); ijk++) *(p)++ = (uint8_t) (a)[ijk];}
+#define ARRAY_TO_BE_STREAM_REVERSE(p, a, len) {int ijk; for (ijk = 0; ijk < (len); ijk++) *(p)++ = (uint8_t) (a)[(len) - ijk - 1];}
+
+#define BE_STREAM_TO_UINT8(u8, p)   {(u8) = (uint8_t)(*(p)); (p) += 1;}
+#define BE_STREAM_TO_UINT16(u16, p) {(u16) = (uint16_t)(((uint16_t)(*(p)) << 8) + (uint16_t)(*((p) + 1))); (p) += 2;}
+#define BE_STREAM_TO_UINT24(u32, p) {(u32) = (((uint32_t)(*((p) + 2))) + ((uint32_t)(*((p) + 1)) << 8) + ((uint32_t)(*(p)) << 16)); (p) += 3;}
+#define BE_STREAM_TO_UINT32(u32, p) {(u32) = ((uint32_t)(*((p) + 3)) + ((uint32_t)(*((p) + 2)) << 8) + ((uint32_t)(*((p) + 1)) << 16) + ((uint32_t)(*(p)) << 24)); (p) += 4;}
+#define BE_STREAM_TO_UINT64(u64, p) {(u64) = ((uint64_t)(*((p) + 7)) + ((uint64_t)(*((p) + 6)) << 8) + \
+                                    ((uint64_t)(*((p) + 5)) << 16) + ((uint64_t)(*((p) + 4)) << 24) + \
+                                    ((uint64_t)(*((p) + 3)) << 32) + ((uint64_t)(*((p) + 2)) << 40) + \
+                                    ((uint64_t)(*((p) + 1)) << 48) + ((uint64_t)(*(p)) << 56)); \
+                                    (p) += 8;}
+#define BE_STREAM_TO_ARRAY(p, a, len) {int ijk; for (ijk = 0; ijk < (len); ijk++) ((uint8_t *) (a))[ijk] = *(p)++;}
+
+
+/********************************************************************************
+** Macros to get and put bytes to and from a field (Big Endian format).
+** These are the same as to stream, except the pointer is not incremented.
+*/
+#define UINT32_TO_BE_FIELD(p, u32) {*(uint8_t *)(p) = (uint8_t)((u32) >> 24);  *((uint8_t *)(p)+1) = (uint8_t)((u32) >> 16); *((uint8_t *)(p)+2) = (uint8_t)((u32) >> 8); *((uint8_t *)(p)+3) = (uint8_t)(u32); }
+#define UINT24_TO_BE_FIELD(p, u24) {*(uint8_t *)(p) = (uint8_t)((u24) >> 16); *((uint8_t *)(p)+1) = (uint8_t)((u24) >> 8); *((uint8_t *)(p)+2) = (uint8_t)(u24);}
+#define UINT16_TO_BE_FIELD(p, u16) {*(uint8_t *)(p) = (uint8_t)((u16) >> 8); *((uint8_t *)(p)+1) = (uint8_t)(u16);}
+#define UINT8_TO_BE_FIELD(p, u8)   {*(uint8_t *)(p) = (uint8_t)(u8);}
+
+
+/* Common Bluetooth field definitions */
+#define BD_ADDR_LEN     6                   /* Device address length */
+typedef uint8_t BD_ADDR[BD_ADDR_LEN];         /* Device address */
+typedef uint8_t *BD_ADDR_PTR;                 /* Pointer to Device Address */
+
+#define AMP_KEY_TYPE_GAMP       0
+#define AMP_KEY_TYPE_WIFI       1
+#define AMP_KEY_TYPE_UWB        2
+typedef uint8_t tAMP_KEY_TYPE;
+
+#define BT_OCTET8_LEN    8
+typedef uint8_t BT_OCTET8[BT_OCTET8_LEN];   /* octet array: size 16 */
+
+#define LINK_KEY_LEN    16
+typedef uint8_t LINK_KEY[LINK_KEY_LEN];       /* Link Key */
+
+#define AMP_LINK_KEY_LEN        32
+typedef uint8_t AMP_LINK_KEY[AMP_LINK_KEY_LEN];   /* Dedicated AMP and GAMP Link Keys */
+
+#define BT_OCTET16_LEN    16
+typedef uint8_t BT_OCTET16[BT_OCTET16_LEN];   /* octet array: size 16 */
+
+#define PIN_CODE_LEN    16
+typedef uint8_t PIN_CODE[PIN_CODE_LEN];       /* Pin Code (upto 128 bits) MSB is 0 */
+typedef uint8_t *PIN_CODE_PTR;                /* Pointer to Pin Code */
+
+#define BT_OCTET32_LEN    32
+typedef uint8_t BT_OCTET32[BT_OCTET32_LEN];   /* octet array: size 32 */
+
+#define DEV_CLASS_LEN   3
+typedef uint8_t DEV_CLASS[DEV_CLASS_LEN];     /* Device class */
+typedef uint8_t *DEV_CLASS_PTR;               /* Pointer to Device class */
+
+#define EXT_INQ_RESP_LEN   3
+typedef uint8_t EXT_INQ_RESP[EXT_INQ_RESP_LEN];/* Extended Inquiry Response */
+typedef uint8_t *EXT_INQ_RESP_PTR;             /* Pointer to Extended Inquiry Response */
+
+#define BD_NAME_LEN     248
+typedef uint8_t BD_NAME[BD_NAME_LEN + 1];         /* Device name */
+typedef uint8_t *BD_NAME_PTR;                 /* Pointer to Device name */
+
+#define BD_FEATURES_LEN 8
+typedef uint8_t BD_FEATURES[BD_FEATURES_LEN]; /* LMP features supported by device */
+
+#define BT_EVENT_MASK_LEN  8
+typedef uint8_t BT_EVENT_MASK[BT_EVENT_MASK_LEN];   /* Event Mask */
+
+#define LAP_LEN         3
+typedef uint8_t LAP[LAP_LEN];                 /* IAC as passed to Inquiry (LAP) */
+typedef uint8_t INQ_LAP[LAP_LEN];             /* IAC as passed to Inquiry (LAP) */
+
+#define RAND_NUM_LEN    16
+typedef uint8_t RAND_NUM[RAND_NUM_LEN];
+
+#define ACO_LEN         12
+typedef uint8_t ACO[ACO_LEN];                 /* Authenticated ciphering offset */
+
+#define COF_LEN         12
+typedef uint8_t COF[COF_LEN];                 /* ciphering offset number */
+
+typedef struct {
+    uint8_t             qos_flags;          /* TBD */
+    uint8_t             service_type;       /* see below */
+    uint32_t            token_rate;         /* bytes/second */
+    uint32_t            token_bucket_size;  /* bytes */
+    uint32_t            peak_bandwidth;     /* bytes/second */
+    uint32_t            latency;            /* microseconds */
+    uint32_t            delay_variation;    /* microseconds */
+} FLOW_SPEC;
+
+/* Values for service_type */
+#define NO_TRAFFIC      0
+#define BEST_EFFORT     1
+#define GUARANTEED      2
+
+/* Service class of the CoD */
+#define SERV_CLASS_NETWORKING               (1 << 1)
+#define SERV_CLASS_RENDERING                (1 << 2)
+#define SERV_CLASS_CAPTURING                (1 << 3)
+#define SERV_CLASS_OBJECT_TRANSFER          (1 << 4)
+#define SERV_CLASS_OBJECT_AUDIO             (1 << 5)
+#define SERV_CLASS_OBJECT_TELEPHONY         (1 << 6)
+#define SERV_CLASS_OBJECT_INFORMATION       (1 << 7)
+
+/* Second byte */
+#define SERV_CLASS_LIMITED_DISC_MODE        (0x20)
+
+/* Field size definitions. Note that byte lengths are rounded up. */
+#define ACCESS_CODE_BIT_LEN             72
+#define ACCESS_CODE_BYTE_LEN            9
+#define SHORTENED_ACCESS_CODE_BIT_LEN   68
+
+typedef uint8_t ACCESS_CODE[ACCESS_CODE_BYTE_LEN];
+
+#define SYNTH_TX                1           /* want synth code to TRANSMIT at this freq */
+#define SYNTH_RX                2           /* want synth code to RECEIVE at this freq */
+
+#define SYNC_REPS 1             /* repeats of sync word transmitted to start of burst */
+
+#define BT_1SEC_TIMEOUT_MS              (1 * 1000)      /* 1 second */
+
+/* Maximum UUID size - 16 bytes, and structure to hold any type of UUID. */
+#define MAX_UUID_SIZE              16
+typedef struct
+{
+#define LEN_UUID_16     2
+#define LEN_UUID_32     4
+#define LEN_UUID_128    16
+
+    uint16_t        len;
+
+    union
+    {
+        uint16_t    uuid16;
+        uint32_t    uuid32;
+        uint8_t     uuid128[MAX_UUID_SIZE];
+    } uu;
+
+} tBT_UUID;
+
+#define BT_EIR_FLAGS_TYPE                       0x01
+#define BT_EIR_MORE_16BITS_UUID_TYPE            0x02
+#define BT_EIR_COMPLETE_16BITS_UUID_TYPE        0x03
+#define BT_EIR_MORE_32BITS_UUID_TYPE            0x04
+#define BT_EIR_COMPLETE_32BITS_UUID_TYPE        0x05
+#define BT_EIR_MORE_128BITS_UUID_TYPE           0x06
+#define BT_EIR_COMPLETE_128BITS_UUID_TYPE       0x07
+#define BT_EIR_SHORTENED_LOCAL_NAME_TYPE        0x08
+#define BT_EIR_COMPLETE_LOCAL_NAME_TYPE         0x09
+#define BT_EIR_TX_POWER_LEVEL_TYPE              0x0A
+#define BT_EIR_OOB_BD_ADDR_TYPE                 0x0C
+#define BT_EIR_OOB_COD_TYPE                     0x0D
+#define BT_EIR_OOB_SSP_HASH_C_TYPE              0x0E
+#define BT_EIR_OOB_SSP_RAND_R_TYPE              0x0F
+#define BT_EIR_SERVICE_DATA_TYPE                0x16
+#define BT_EIR_SERVICE_DATA_16BITS_UUID_TYPE    0x16
+#define BT_EIR_SERVICE_DATA_32BITS_UUID_TYPE    0x20
+#define BT_EIR_SERVICE_DATA_128BITS_UUID_TYPE   0x21
+#define BT_EIR_MANUFACTURER_SPECIFIC_TYPE       0xFF
+
+#define BT_OOB_COD_SIZE            3
+#define BT_OOB_HASH_C_SIZE         16
+#define BT_OOB_RAND_R_SIZE         16
+
+/* Broadcom proprietary UUIDs and reserved PSMs
+**
+** The lowest 4 bytes byte of the UUID or GUID depends on the feature. Typically,
+** the value of those bytes will be the PSM or SCN, but it is up to the features.
+*/
+#define BRCM_PROPRIETARY_UUID_BASE  0xDA, 0x23, 0x41, 0x02, 0xA3, 0xBB, 0xC1, 0x71, 0xBA, 0x09, 0x6f, 0x21
+#define BRCM_PROPRIETARY_GUID_BASE  0xda23, 0x4102, 0xa3, 0xbb, 0xc1, 0x71, 0xba, 0x09, 0x6f, 0x21
+
+/* We will not allocate a PSM in the reserved range to 3rd party apps
+*/
+#define BRCM_RESERVED_PSM_START	    0x5AE1
+#define BRCM_RESERVED_PSM_END	    0x5AFF
+
+#define BRCM_UTILITY_SERVICE_PSM    0x5AE1
+#define BRCM_MATCHER_PSM            0x5AE3
+
+/* Connection statistics
+*/
+
+/* Structure to hold connection stats */
+#ifndef BT_CONN_STATS_DEFINED
+#define BT_CONN_STATS_DEFINED
+
+/* These bits are used in the bIsConnected field */
+#define BT_CONNECTED_USING_BREDR   1
+#define BT_CONNECTED_USING_AMP     2
+
+typedef struct
+{
+    uint32_t is_connected;
+    int32_t  rssi;
+    uint32_t bytes_sent;
+    uint32_t bytes_rcvd;
+    uint32_t duration;
+} tBT_CONN_STATS;
+
+#endif
+
+
+/*****************************************************************************
+**                          Low Energy definitions
+**
+** Address types
+*/
+#define BLE_ADDR_PUBLIC         0x00
+#define BLE_ADDR_RANDOM         0x01
+#define BLE_ADDR_PUBLIC_ID      0x02
+#define BLE_ADDR_RANDOM_ID      0x03
+typedef uint8_t tBLE_ADDR_TYPE;
+#define BLE_ADDR_TYPE_MASK      (BLE_ADDR_RANDOM | BLE_ADDR_PUBLIC)
+
+#define BT_TRANSPORT_INVALID   0
+#define BT_TRANSPORT_BR_EDR    1
+#define BT_TRANSPORT_LE        2
+typedef uint8_t tBT_TRANSPORT;
+
+#define BLE_ADDR_IS_STATIC(x)   (((x)[0] & 0xC0) == 0xC0)
+
+typedef struct
+{
+    tBLE_ADDR_TYPE      type;
+    BD_ADDR             bda;
+} tBLE_BD_ADDR;
+
+/* Device Types
+*/
+#define BT_DEVICE_TYPE_BREDR   0x01
+#define BT_DEVICE_TYPE_BLE     0x02
+#define BT_DEVICE_TYPE_DUMO    0x03
+typedef uint8_t tBT_DEVICE_TYPE;
+/*****************************************************************************/
+
+
+/* Define trace levels */
+#define BT_TRACE_LEVEL_NONE    0          /* No trace messages to be generated    */
+#define BT_TRACE_LEVEL_ERROR   1          /* Error condition trace messages       */
+#define BT_TRACE_LEVEL_WARNING 2          /* Warning condition trace messages     */
+#define BT_TRACE_LEVEL_API     3          /* API traces                           */
+#define BT_TRACE_LEVEL_EVENT   4          /* Debug messages for events            */
+#define BT_TRACE_LEVEL_DEBUG   5          /* Full debug messages                  */
+#define BT_TRACE_LEVEL_VERBOSE 6          /* Verbose debug messages               */
+
+#define MAX_TRACE_LEVEL        6
+
+
+/* Define New Trace Type Definition */
+/* TRACE_CTRL_TYPE                  0x^^000000*/
+#define TRACE_CTRL_MASK             0xff000000
+#define TRACE_GET_CTRL(x)           ((((uint32_t)(x)) & TRACE_CTRL_MASK) >> 24)
+
+#define TRACE_CTRL_GENERAL          0x00000000
+#define TRACE_CTRL_STR_RESOURCE     0x01000000
+#define TRACE_CTRL_SEQ_FLOW         0x02000000
+#define TRACE_CTRL_MAX_NUM          3
+
+/* LAYER SPECIFIC                   0x00^^0000*/
+#define TRACE_LAYER_MASK            0x00ff0000
+#define TRACE_GET_LAYER(x)          ((((uint32_t)(x)) & TRACE_LAYER_MASK) >> 16)
+
+#define TRACE_LAYER_NONE            0x00000000
+#define TRACE_LAYER_USB             0x00010000
+#define TRACE_LAYER_SERIAL          0x00020000
+#define TRACE_LAYER_SOCKET          0x00030000
+#define TRACE_LAYER_RS232           0x00040000
+#define TRACE_LAYER_TRANS_MAX_NUM   5
+#define TRACE_LAYER_TRANS_ALL       0x007f0000
+#define TRACE_LAYER_LC              0x00050000
+#define TRACE_LAYER_LM              0x00060000
+#define TRACE_LAYER_HCI             0x00070000
+#define TRACE_LAYER_L2CAP           0x00080000
+#define TRACE_LAYER_RFCOMM          0x00090000
+#define TRACE_LAYER_SDP             0x000a0000
+#define TRACE_LAYER_TCS             0x000b0000
+#define TRACE_LAYER_OBEX            0x000c0000
+#define TRACE_LAYER_BTM             0x000d0000
+#define TRACE_LAYER_GAP             0x000e0000
+#define TRACE_LAYER_ICP             0x00110000
+#define TRACE_LAYER_HSP2            0x00120000
+#define TRACE_LAYER_SPP             0x00130000
+#define TRACE_LAYER_CTP             0x00140000
+#define TRACE_LAYER_BPP             0x00150000
+#define TRACE_LAYER_HCRP            0x00160000
+#define TRACE_LAYER_FTP             0x00170000
+#define TRACE_LAYER_OPP             0x00180000
+#define TRACE_LAYER_BTU             0x00190000
+#define TRACE_LAYER_GKI             0x001a0000          /* OBSOLETED */
+#define TRACE_LAYER_BNEP            0x001b0000
+#define TRACE_LAYER_PAN             0x001c0000
+#define TRACE_LAYER_HFP             0x001d0000
+#define TRACE_LAYER_HID             0x001e0000
+#define TRACE_LAYER_BIP             0x001f0000
+#define TRACE_LAYER_AVP             0x00200000
+#define TRACE_LAYER_A2DP            0x00210000
+#define TRACE_LAYER_SAP             0x00220000
+#define TRACE_LAYER_AMP             0x00230000
+#define TRACE_LAYER_MCA             0x00240000
+#define TRACE_LAYER_ATT             0x00250000
+#define TRACE_LAYER_SMP             0x00260000
+#define TRACE_LAYER_NFC             0x00270000
+#define TRACE_LAYER_NCI             0x00280000
+#define TRACE_LAYER_LLCP            0x00290000
+#define TRACE_LAYER_NDEF            0x002a0000
+#define TRACE_LAYER_RW              0x002b0000
+#define TRACE_LAYER_CE              0x002c0000
+#define TRACE_LAYER_P2P             0x002d0000
+#define TRACE_LAYER_SNEP            0x002e0000
+#define TRACE_LAYER_CHO             0x002f0000
+#define TRACE_LAYER_NFA             0x00300000
+
+#define TRACE_LAYER_MAX_NUM         0x0031
+
+
+/* TRACE_ORIGINATOR                 0x0000^^00*/
+#define TRACE_ORG_MASK              0x0000ff00
+#define TRACE_GET_ORG(x)            ((((uint32_t)(x)) & TRACE_ORG_MASK) >> 8)
+
+#define TRACE_ORG_STACK             0x00000000
+#define TRACE_ORG_HCI_TRANS         0x00000100
+#define TRACE_ORG_PROTO_DISP        0x00000200
+#define TRACE_ORG_RPC               0x00000300
+#define TRACE_ORG_GKI               0x00000400  /* OBSOLETED */
+#define TRACE_ORG_APPL              0x00000500
+#define TRACE_ORG_SCR_WRAPPER       0x00000600
+#define TRACE_ORG_SCR_ENGINE        0x00000700
+#define TRACE_ORG_USER_SCR          0x00000800
+#define TRACE_ORG_TESTER            0x00000900
+#define TRACE_ORG_MAX_NUM           10          /* 32-bit mask; must be < 32 */
+#define TRACE_LITE_ORG_MAX_NUM		6
+#define TRACE_ORG_ALL               0x03ff
+#define TRACE_ORG_RPC_TRANS         0x04
+
+#define TRACE_ORG_REG               0x00000909
+#define TRACE_ORG_REG_SUCCESS       0x0000090a
+
+/* TRACE_TYPE                       0x000000^^*/
+#define TRACE_TYPE_MASK             0x000000ff
+#define TRACE_GET_TYPE(x)           (((uint32_t)(x)) & TRACE_TYPE_MASK)
+
+#define TRACE_TYPE_ERROR            0x00000000
+#define TRACE_TYPE_WARNING          0x00000001
+#define TRACE_TYPE_API              0x00000002
+#define TRACE_TYPE_EVENT            0x00000003
+#define TRACE_TYPE_DEBUG            0x00000004
+#define TRACE_TYPE_STACK_ONLY_MAX   TRACE_TYPE_DEBUG
+#define TRACE_TYPE_TX               0x00000005
+#define TRACE_TYPE_RX               0x00000006
+#define TRACE_TYPE_DEBUG_ASSERT     0x00000007
+#define TRACE_TYPE_GENERIC          0x00000008
+#define TRACE_TYPE_REG              0x00000009
+#define TRACE_TYPE_REG_SUCCESS      0x0000000a
+#define TRACE_TYPE_CMD_TX           0x0000000b
+#define TRACE_TYPE_EVT_TX           0x0000000c
+#define TRACE_TYPE_ACL_TX           0x0000000d
+#define TRACE_TYPE_CMD_RX           0x0000000e
+#define TRACE_TYPE_EVT_RX           0x0000000f
+#define TRACE_TYPE_ACL_RX           0x00000010
+#define TRACE_TYPE_TARGET_TRACE     0x00000011
+#define TRACE_TYPE_SCO_TX           0x00000012
+#define TRACE_TYPE_SCO_RX           0x00000013
+
+
+#define TRACE_TYPE_MAX_NUM          20
+#define TRACE_TYPE_ALL              0xffff
+
+/* Define color for script type */
+#define SCR_COLOR_DEFAULT       0
+#define SCR_COLOR_TYPE_COMMENT  1
+#define SCR_COLOR_TYPE_COMMAND  2
+#define SCR_COLOR_TYPE_EVENT    3
+#define SCR_COLOR_TYPE_SELECT   4
+
+/* Define protocol trace flag values */
+#define SCR_PROTO_TRACE_HCI_SUMMARY 0x00000001
+#define SCR_PROTO_TRACE_HCI_DATA    0x00000002
+#define SCR_PROTO_TRACE_L2CAP       0x00000004
+#define SCR_PROTO_TRACE_RFCOMM      0x00000008
+#define SCR_PROTO_TRACE_SDP         0x00000010
+#define SCR_PROTO_TRACE_TCS         0x00000020
+#define SCR_PROTO_TRACE_OBEX        0x00000040
+#define SCR_PROTO_TRACE_OAPP        0x00000080 /* OBEX Application Profile */
+#define SCR_PROTO_TRACE_AMP         0x00000100
+#define SCR_PROTO_TRACE_BNEP        0x00000200
+#define SCR_PROTO_TRACE_AVP         0x00000400
+#define SCR_PROTO_TRACE_MCA         0x00000800
+#define SCR_PROTO_TRACE_ATT         0x00001000
+#define SCR_PROTO_TRACE_SMP         0x00002000
+#define SCR_PROTO_TRACE_NCI         0x00004000
+#define SCR_PROTO_TRACE_LLCP        0x00008000
+#define SCR_PROTO_TRACE_NDEF        0x00010000
+#define SCR_PROTO_TRACE_RW          0x00020000
+#define SCR_PROTO_TRACE_CE          0x00040000
+#define SCR_PROTO_TRACE_SNEP        0x00080000
+#define SCR_PROTO_TRACE_CHO         0x00100000
+#define SCR_PROTO_TRACE_ALL         0x001fffff
+#define SCR_PROTO_TRACE_HCI_LOGGING_VSE 0x0800 /* Brcm vs event for logmsg and protocol traces */
+
+#define MAX_SCRIPT_TYPE             5
+
+#define TCS_PSM_INTERCOM        5
+#define TCS_PSM_CORDLESS        7
+#define BT_PSM_BNEP             0x000F
+/* Define PSMs HID uses */
+#define HID_PSM_CONTROL         0x0011
+#define HID_PSM_INTERRUPT       0x0013
+
+/* Define a function for logging */
+typedef void (BT_LOG_FUNC) (int trace_type, const char *fmt_str, ...);
+
+/* bd addr length and type */
+#ifndef BD_ADDR_LEN
+#define BD_ADDR_LEN     6
+typedef uint8_t BD_ADDR[BD_ADDR_LEN];
+#endif
+
+// From bd.c
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+/* global constant for "any" bd addr */
+static const BD_ADDR bd_addr_any = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+static const BD_ADDR bd_addr_null= {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/*****************************************************************************
+**  Functions
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function         bdcpy
+**
+** Description      Copy bd addr b to a.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static inline void bdcpy(BD_ADDR a, const BD_ADDR b)
+{
+    int i;
+
+    for (i = BD_ADDR_LEN; i != 0; i--)
+    {
+        *a++ = *b++;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         bdcmp
+**
+** Description      Compare bd addr b to a.
+**
+**
+** Returns          Zero if b==a, nonzero otherwise (like memcmp).
+**
+*******************************************************************************/
+static inline int bdcmp(const BD_ADDR a, const BD_ADDR b)
+{
+    int i;
+
+    for (i = BD_ADDR_LEN; i != 0; i--)
+    {
+        if (*a++ != *b++)
+        {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+/*******************************************************************************
+**
+** Function         bdcmpany
+**
+** Description      Compare bd addr to "any" bd addr.
+**
+**
+** Returns          Zero if a equals bd_addr_any.
+**
+*******************************************************************************/
+static inline int bdcmpany(const BD_ADDR a)
+{
+    return bdcmp(a, bd_addr_any);
+}
+
+/*******************************************************************************
+**
+** Function         bdsetany
+**
+** Description      Set bd addr to "any" bd addr.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static inline void bdsetany(BD_ADDR a)
+{
+    bdcpy(a, bd_addr_any);
+}
+#endif
diff --git a/bt/stack/include/btm_api.h b/bt/stack/include/btm_api.h
new file mode 100644
index 0000000..82a6c80
--- /dev/null
+++ b/bt/stack/include/btm_api.h
@@ -0,0 +1,2097 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 Bluetooth Manager (BTM) API function external
+ *  definitions.
+ *
+ ******************************************************************************/
+#ifndef BTM_API_H
+#define BTM_API_H
+
+#include "bt_target.h"
+#include "sdp_api.h"
+#include "hcidefs.h"
+
+#include "smp_api.h"
+
+#include "btm_api_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+**  DEVICE CONTROL and COMMON
+*****************************************************************************/
+
+/*****************************************************************************
+**  EXTERNAL FUNCTION DECLARATIONS
+*****************************************************************************/
+
+/*****************************************************************************
+**  DEVICE CONTROL and COMMON FUNCTIONS
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern 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;
+**                  if is_register=false, then the function will be deregistered.
+**
+** Returns          BTM_SUCCESS if successful,
+**                  BTM_BUSY if maximum number of callbacks have already been
+**                           registered.
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern uint8_t BTM_AllocateSCN(void);
+
+/*******************************************************************************
+**
+** Function         BTM_TryAllocateSCN
+**
+** Description      Try to allocate a fixed server channel
+**
+** Returns          Returns true if server channel was available
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern uint8_t BTM_SetTraceLevel (uint8_t new_level);
+
+
+/*******************************************************************************
+**
+** Function         BTM_WritePageTimeout
+**
+** Description      Send HCI Wite Page Timeout.
+**
+*******************************************************************************/
+extern void BTM_WritePageTimeout(uint16_t timeout);
+
+/*******************************************************************************
+**
+** Function         BTM_WriteVoiceSettings
+**
+** Description      Send HCI Write Voice Settings command.
+**                  See hcidefs.h for settings bitmask values.
+**
+*******************************************************************************/
+extern 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.
+**
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern 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      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
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern 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 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.
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+
+extern 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 could not allocate resources to start the command
+**                  BTM_WRONG_MODE if the device is not up.
+**
+*******************************************************************************/
+extern tBTM_STATUS  BTM_ReadRemoteDeviceName (BD_ADDR 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 could not allocate resources to start the command
+**                  BTM_WRONG_MODE if there is not an active remote name request.
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_ReadRemoteVersion (BD_ADDR 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
+**
+*******************************************************************************/
+extern uint8_t *BTM_ReadRemoteFeatures (BD_ADDR 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
+**
+*******************************************************************************/
+extern uint8_t *BTM_ReadRemoteExtendedFeatures (BD_ADDR 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
+**
+*******************************************************************************/
+extern uint8_t BTM_ReadNumberRemoteFeaturesPages (BD_ADDR addr);
+
+/*******************************************************************************
+**
+** Function         BTM_ReadAllRemoteFeatures
+**
+** Description      This function is called to read all 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).
+**
+*******************************************************************************/
+extern uint8_t *BTM_ReadAllRemoteFeatures (BD_ADDR 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
+**
+*******************************************************************************/
+extern tBTM_INQ_INFO *BTM_InqDbRead (const BD_ADDR 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
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern tBTM_STATUS  BTM_ClearInqDb (BD_ADDR 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
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_ReadInquiryRspTxPower (tBTM_CMPL_CB *p_cb);
+
+/*******************************************************************************
+**
+** Function         BTM_StartDiscovery
+**
+** Description      This function is called by an application (or profile)
+**                  when it wants to trigger an service discovery using the
+**                  BTM's discovery database.
+**
+** Returns          tBTM_STATUS
+**                      BTM_CMD_STARTED if the discovery was initiated
+**                      BTM_BUSY if one is already in progress
+**                      BTM_UNKNOWN_ADDR if no addresses are in the INQ DB
+**                      BTM_ERR_PROCESSING if err initiating the command
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_StartDiscovery (tBTM_CMPL_CB *p_cmpl_cb,
+                                       BD_ADDR_PTR p_rem_addr);
+
+
+/*******************************************************************************
+**
+** Function         BTM_FindAttribute
+**
+** Description      This function is called by an application (or profile)
+**                  when it wants to see if an attribute exists in the BTM
+**                  discovery database.
+**
+** Returns          Pointer to matching record, or NULL
+**
+*******************************************************************************/
+extern tSDP_DISC_REC *BTM_FindAttribute (uint16_t attr_id,
+                                         tSDP_DISC_REC *p_start_rec);
+
+
+/*******************************************************************************
+**
+** Function         BTM_FindService
+**
+** Description      This function is called by an application (or profile)
+**                  when it wants to see if a service exists in the BTM
+**                  discovery database.
+**
+** Returns          Pointer to matching record, or NULL
+**
+*******************************************************************************/
+extern tSDP_DISC_REC *BTM_FindService (uint16_t service_uuid,
+                                       tSDP_DISC_REC *p_start_rec);
+
+
+/*******************************************************************************
+**
+** Function         BTM_SetDiscoveryParams
+**
+** Description      This function is called to set the BTM default discovery parameters.
+**                  These UUID and attribute filters are used during the call to
+**                  BTM_StartDiscovery.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void BTM_SetDiscoveryParams (uint16_t num_uuid, tSDP_UUID *p_uuid_list,
+                                    uint16_t num_attr, uint16_t *p_attr_list);
+
+
+/*****************************************************************************
+**  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
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_SetLinkPolicy (BD_ADDR 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_SetLinkSuperTout (BD_ADDR remote_bda,
+                                         uint16_t timeout);
+/*******************************************************************************
+**
+** Function         BTM_GetLinkSuperTout
+**
+** Description      Read the link supervision timeout value of the connection
+**
+** Returns          status of the operation
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_GetLinkSuperTout (BD_ADDR 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.
+**
+*******************************************************************************/
+extern bool    BTM_IsAclConnectionUp (BD_ADDR 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
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_GetRole (BD_ADDR 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 couldn't allocate memory to issue command
+**                  BTM_UNKNOWN_ADDR if no active link with bd addr specified
+**                  BTM_MODE_UNSUPPORTED if local device does not support role switching
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_SwitchRole (BD_ADDR 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_RESULTS)
+**
+** Returns          BTM_CMD_STARTED if command issued to controller.
+**                  BTM_NO_RESOURCES if couldn't allocate memory to issue command
+**                  BTM_UNKNOWN_ADDR if no active link with bd addr specified
+**                  BTM_BUSY if command is already in progress
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_ReadRSSI (const BD_ADDR 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_RESULTS)
+**
+** Returns          BTM_CMD_STARTED if command issued to controller.
+**                  BTM_NO_RESOURCES if couldn't allocate memory to issue command
+**                  BTM_UNKNOWN_ADDR if no active link with bd addr specified
+**                  BTM_BUSY if command is already in progress
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_ReadTxPower (BD_ADDR 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_RESULTS)
+**
+** Returns          BTM_CMD_STARTED if command issued to controller.
+**                  BTM_NO_RESOURCES if couldn't allocate memory to issue command
+**                  BTM_UNKNOWN_ADDR if no active link with bd addr specified
+**                  BTM_BUSY if command is already in progress
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_ReadLinkQuality (BD_ADDR 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_SetQoS(BD_ADDR 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.
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_CreateSco (BD_ADDR 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern uint16_t BTM_ReadDeviceScoPacketTypes (void);
+
+
+/*******************************************************************************
+**
+** Function         BTM_ReadScoHandle
+**
+** Description      This function is used to read the HCI handle used for a specific
+**                  SCO connection,
+**
+** Returns          handle for the connection, or 0xFFFF if invalid SCO index.
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern uint8_t *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.
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_SetEScoMode (tBTM_SCO_TYPE sco_mode,
+                                    tBTM_ESCO_PARAMS *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.
+**
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern void BTM_EScoConnRsp (uint16_t sco_inx, uint8_t hci_status,
+                             tBTM_ESCO_PARAMS *p_parms);
+
+/*******************************************************************************
+**
+** Function         BTM_GetNumScoLinks
+**
+** Description      This function returns the number of active SCO links.
+**
+** Returns          uint8_t
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern bool    BTM_SecRegister (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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern bool    BTM_GetSecurityFlags (BD_ADDR 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
+**
+*******************************************************************************/
+extern bool    BTM_GetSecurityFlagsByTransport (BD_ADDR 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
+**
+*******************************************************************************/
+extern uint32_t * BTM_ReadTrustedMask (BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function         BTM_SetPinType
+**
+** Description      Set PIN type for the device.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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
+**                  nad again for acceptors of connections.
+**
+** Returns          true if registered OK, else false
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern void BTM_SetOutService(BD_ADDR 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.
+**                          records (except SDP).
+**
+** Returns          Number of records that were freed.
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern bool    BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class,
+                                 BD_NAME bd_name, uint8_t *features,
+                                 uint32_t trusted_mask[], LINK_KEY link_key,
+                                 uint8_t key_type, tBTM_IO_CAP io_cap, uint8_t pin_length);
+
+
+/*******************************************************************************
+**
+** Function         BTM_SecDeleteDevice
+**
+** Description      Free resources associated with the device.
+**
+** Returns          true if rmoved OK, false if not found
+**
+*******************************************************************************/
+extern bool    BTM_SecDeleteDevice (BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function         BTM_SecClearSecurityFlags
+**
+** Description      Reset the security flags (mark as not-paired) for a given
+**                  remove device.
+**
+*******************************************************************************/
+extern void BTM_SecClearSecurityFlags (BD_ADDR 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
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_SecGetDeviceLinkKey (BD_ADDR bd_addr,
+                                            LINK_KEY 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.
+**
+*******************************************************************************/
+extern tBTM_LINK_KEY_TYPE BTM_SecGetDeviceLinkKeyType (BD_ADDR 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
+**
+*******************************************************************************/
+extern void BTM_PINCodeReply (BD_ADDR 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
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_SecBond (BD_ADDR bd_addr,
+                                uint8_t pin_len, uint8_t *p_pin,
+                                uint32_t trusted_mask[]);
+
+/*******************************************************************************
+**
+** Function         BTM_SecBondByTransport
+**
+** Description      This function is called to 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
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_SecBondByTransport (BD_ADDR 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
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_SecBondCancel (BD_ADDR 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.
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_SetEncryption (BD_ADDR 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
+**
+*******************************************************************************/
+extern void BTM_ConfirmReqReply(tBTM_STATUS res, BD_ADDR 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).
+**
+*******************************************************************************/
+extern void BTM_PasskeyReqReply(tBTM_STATUS res, BD_ADDR 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
+**
+*******************************************************************************/
+extern void BTM_SendKeypressNotif(BD_ADDR 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.
+**
+*******************************************************************************/
+extern void BTM_IoCapRsp(BD_ADDR 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
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern void BTM_RemoteOobDataReply(tBTM_STATUS res, BD_ADDR bd_addr,
+                                   BT_OCTET16 c, BT_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.
+**
+*******************************************************************************/
+extern uint16_t BTM_BuildOobData(uint8_t *p_data, uint16_t max_len, BT_OCTET16 c,
+                               BT_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.
+**
+*******************************************************************************/
+extern bool    BTM_BothEndsSupportSecureConnections(BD_ADDR 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.
+**
+*******************************************************************************/
+extern bool    BTM_PeerSupportsSecureConnections(BD_ADDR 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.
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern char *BTM_SecReadDevName (BD_ADDR 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_SetPowerMode (uint8_t pm_id, BD_ADDR remote_bda,
+                                     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
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_ReadPowerMode (BD_ADDR 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
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_SetSsrParams (BD_ADDR 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.
+**
+*******************************************************************************/
+extern uint16_t BTM_GetHCIConnHandle (const BD_ADDR 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
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_DeleteStoredLinkKey(BD_ADDR 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
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_WriteEIR( BT_HDR * p_buff );
+
+/*******************************************************************************
+**
+** Function         BTM_CheckEirData
+**
+** Description      This function is called to get EIR data from significant part.
+**
+** Parameters       p_eir - pointer of EIR significant part
+**                  type   - finding EIR data type
+**                  p_length - return the length of EIR data
+**
+** Returns          pointer of EIR data
+**
+*******************************************************************************/
+extern uint8_t *BTM_CheckEirData( uint8_t *p_eir, uint8_t type, uint8_t *p_length );
+
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+extern bool    BTM_HasEirService( uint32_t *p_eir_uuid, uint16_t uuid16 );
+
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+extern 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 bit map of UUID list.
+**
+** Parameters       p_eir_uuid - bit mask of UUID list for EIR
+**                  uuid16 - UUID 16-bit
+**
+** Returns          None
+**
+*******************************************************************************/
+extern void BTM_AddEirService( uint32_t *p_eir_uuid, uint16_t uuid16 );
+
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+extern 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 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
+**
+*******************************************************************************/
+extern 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
+**                  uuid_size - LEN_UUID_16, LEN_UUID_32, LEN_UUID_128
+**                  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
+**
+*******************************************************************************/
+extern uint8_t BTM_GetEirUuidList( uint8_t *p_eir, 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, PCM parameter maintained in
+**                               the control block will be used; otherwise update
+**                               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 cmpl event.
+**
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_ConfigScoPath (tBTM_SCO_ROUTE_TYPE 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.
+**
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_WriteScoData (uint16_t sco_inx, BT_HDR *p_buf);
+
+/*******************************************************************************
+**
+** Function         BTM_SetARCMode
+**
+** Description      Send Audio Routing Control command.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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)
+**
+*******************************************************************************/
+extern tBTM_CONTRL_STATE BTM_PM_ReadControllerState(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTM_API_H */
diff --git a/bt/stack/include/btm_api_types.h b/bt/stack/include/btm_api_types.h
new file mode 100644
index 0000000..88ddcb7
--- /dev/null
+++ b/bt/stack/include/btm_api_types.h
@@ -0,0 +1,1884 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTM_API_TYPES_H
+#define BTM_API_TYPES_H
+
+#include "bt_target.h"
+#include "smp_api_types.h"
+#include "hcidefs.h"
+
+/* Maximum number of bytes allowed for vendor specific command parameters */
+#define BTM_MAX_VENDOR_SPECIFIC_LEN  HCI_COMMAND_SIZE
+
+/* BTM application return status codes */
+enum
+{
+    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 */
+};
+
+typedef uint8_t tBTM_STATUS;
+
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+typedef enum
+{
+    BTM_BR_ONE,                         /*0 First state or BR/EDR scan 1*/
+    BTM_BLE_ONE,                        /*1BLE scan 1*/
+    BTM_BR_TWO,                         /*2 BR/EDR scan 2*/
+    BTM_BLE_TWO,                        /*3 BLE scan 2*/
+    BTM_FINISH,                         /*4 End of Interleave Scan, or normal scan*/
+    BTM_NO_INTERLEAVING                 /*5 No Interleaving*/
+}btm_inq_state;
+#endif
+
+
+
+/*************************
+**  Device Control Types
+**************************/
+#define BTM_DEVICE_ROLE_BR      0x01
+#define BTM_DEVICE_ROLE_DUAL    0x02
+#define BTM_MAX_DEVICE_ROLE     BTM_DEVICE_ROLE_DUAL
+typedef uint8_t tBTM_DEVICE_ROLE;
+
+/* Device name of peer (may be truncated to save space in BTM database) */
+typedef uint8_t tBTM_BD_NAME[BTM_MAX_REM_BD_NAME_LEN + 1];
+
+/* Structure returned with local version information */
+typedef struct
+{
+    uint8_t     hci_version;
+    uint16_t    hci_revision;
+    uint8_t     lmp_version;
+    uint16_t    manufacturer;
+    uint16_t    lmp_subversion;
+} tBTM_VERSION_INFO;
+
+/* Structure returned with Vendor Specific Command complete callback */
+typedef struct
+{
+    uint16_t opcode;
+    uint16_t param_len;
+    uint8_t  *p_param_buf;
+} tBTM_VSC_CMPL;
+
+#define  BTM_VSC_CMPL_DATA_SIZE  (BTM_MAX_VENDOR_SPECIFIC_LEN + sizeof(tBTM_VSC_CMPL))
+/**************************************************
+**  Device Control and General Callback Functions
+***************************************************/
+/* Callback function for when device status changes. Appl must poll for
+** what the new state is (BTM_IsDeviceUp). The event occurs whenever the stack
+** has detected that the controller status has changed. This asynchronous event
+** is enabled/disabled by calling BTM_RegisterForDeviceStatusNotif().
+*/
+enum
+{
+    BTM_DEV_STATUS_UP,
+    BTM_DEV_STATUS_DOWN,
+    BTM_DEV_STATUS_CMD_TOUT
+};
+
+typedef uint8_t tBTM_DEV_STATUS;
+
+
+typedef void (tBTM_DEV_STATUS_CB) (tBTM_DEV_STATUS status);
+
+
+/* Callback function for when a vendor specific event occurs. The length and
+** array of returned parameter bytes are included. This asynchronous event
+** is enabled/disabled by calling BTM_RegisterForVSEvents().
+*/
+typedef void (tBTM_VS_EVT_CB) (uint8_t len, uint8_t *p);
+
+
+/* General callback function for notifying an application that a synchronous
+** BTM function is complete. The pointer contains the address of any returned data.
+*/
+typedef void (tBTM_CMPL_CB) (void *p1);
+
+/* VSC callback function for notifying an application that a synchronous
+** BTM function is complete. The pointer contains the address of any returned data.
+*/
+typedef void (tBTM_VSC_CMPL_CB) (tBTM_VSC_CMPL *p1);
+
+/* Callback for apps to check connection and inquiry filters.
+** Parameters are the BD Address of remote and the Dev Class of remote.
+** If the app returns none zero, the connection or inquiry result will be dropped.
+*/
+typedef uint8_t (tBTM_FILTER_CB) (BD_ADDR bd_addr, DEV_CLASS dc);
+
+/*****************************************************************************
+**  DEVICE DISCOVERY - Inquiry, Remote Name, Discovery, Class of Device
+*****************************************************************************/
+/*******************************
+**  Device Discovery Constants
+********************************/
+/* Discoverable modes */
+#define BTM_NON_DISCOVERABLE        0
+#define BTM_LIMITED_DISCOVERABLE    1
+#define BTM_GENERAL_DISCOVERABLE    2
+#define BTM_DISCOVERABLE_MASK       (BTM_LIMITED_DISCOVERABLE|BTM_GENERAL_DISCOVERABLE)
+#define BTM_MAX_DISCOVERABLE        BTM_GENERAL_DISCOVERABLE
+/* high byte for BLE Discoverable modes */
+#define BTM_BLE_NON_DISCOVERABLE        0x0000
+#define BTM_BLE_LIMITED_DISCOVERABLE    0x0100
+#define BTM_BLE_GENERAL_DISCOVERABLE    0x0200
+#define BTM_BLE_MAX_DISCOVERABLE        BTM_BLE_GENERAL_DISCOVERABLE
+#define BTM_BLE_DISCOVERABLE_MASK       (BTM_BLE_NON_DISCOVERABLE|BTM_BLE_LIMITED_DISCOVERABLE|BTM_BLE_GENERAL_DISCOVERABLE)
+
+/* Connectable modes */
+#define BTM_NON_CONNECTABLE         0
+#define BTM_CONNECTABLE             1
+#define BTM_CONNECTABLE_MASK        (BTM_NON_CONNECTABLE | BTM_CONNECTABLE)
+/* high byte for BLE Connectable modes */
+#define BTM_BLE_NON_CONNECTABLE      0x0000
+#define BTM_BLE_CONNECTABLE          0x0100
+#define BTM_BLE_MAX_CONNECTABLE      BTM_BLE_CONNECTABLE
+#define BTM_BLE_CONNECTABLE_MASK    (BTM_BLE_NON_CONNECTABLE | BTM_BLE_CONNECTABLE)
+
+/* Inquiry modes
+ * Note: These modes are associated with the inquiry active values (BTM_*ACTIVE) */
+#define BTM_INQUIRY_NONE            0
+#define BTM_GENERAL_INQUIRY         0x01
+#define BTM_LIMITED_INQUIRY         0x02
+#define BTM_BR_INQUIRY_MASK         (BTM_GENERAL_INQUIRY | BTM_LIMITED_INQUIRY)
+
+/* high byte of inquiry mode for BLE inquiry mode */
+#define BTM_BLE_INQUIRY_NONE         0x00
+#define BTM_BLE_GENERAL_INQUIRY      0x10
+#define BTM_BLE_LIMITED_INQUIRY      0x20
+#define BTM_BLE_INQUIRY_MASK         (BTM_BLE_GENERAL_INQUIRY|BTM_BLE_LIMITED_INQUIRY)
+
+/* BTM_IsInquiryActive return values (Bit Mask)
+ * Note: These bit masks are associated with the inquiry modes (BTM_*_INQUIRY) */
+#define BTM_INQUIRY_INACTIVE        0x0     /* no inquiry in progress */
+#define BTM_GENERAL_INQUIRY_ACTIVE  BTM_GENERAL_INQUIRY     /* a general inquiry is in progress */
+#define BTM_LIMITED_INQUIRY_ACTIVE  BTM_LIMITED_INQUIRY     /* a limited inquiry is in progress */
+#define BTM_PERIODIC_INQUIRY_ACTIVE 0x8     /* a periodic inquiry is active */
+#define BTM_SSP_INQUIRY_ACTIVE      0x4     /* SSP is active, so inquiry is disallowed (work around for FW bug) */
+#define BTM_LE_GENERAL_INQUIRY_ACTIVE  BTM_BLE_GENERAL_INQUIRY     /* a general inquiry is in progress */
+#define BTM_LE_LIMITED_INQUIRY_ACTIVE  BTM_BLE_LIMITED_INQUIRY      /* a limited inquiry is in progress */
+
+/* inquiry activity mask */
+#define BTM_BR_INQ_ACTIVE_MASK        (BTM_GENERAL_INQUIRY_ACTIVE|BTM_LIMITED_INQUIRY_ACTIVE|BTM_PERIODIC_INQUIRY_ACTIVE) /* BR/EDR inquiry activity mask */
+#define BTM_BLE_SCAN_ACTIVE_MASK      0xF0     /* LE scan activity mask */
+#define BTM_BLE_INQ_ACTIVE_MASK       (BTM_LE_GENERAL_INQUIRY_ACTIVE|BTM_LE_LIMITED_INQUIRY_ACTIVE) /* LE inquiry activity mask*/
+#define BTM_INQUIRY_ACTIVE_MASK       (BTM_BR_INQ_ACTIVE_MASK | BTM_BLE_INQ_ACTIVE_MASK) /* inquiry activity mask */
+
+/* Define scan types */
+#define BTM_SCAN_TYPE_STANDARD      0
+#define BTM_SCAN_TYPE_INTERLACED    1       /* 1.2 devices only */
+
+/* Define inquiry results mode */
+#define BTM_INQ_RESULT_STANDARD     0
+#define BTM_INQ_RESULT_WITH_RSSI    1
+#define BTM_INQ_RESULT_EXTENDED     2
+
+#define BTM_INQ_RES_IGNORE_RSSI     0x7f    /* RSSI value not supplied (ignore it) */
+
+/* Inquiry Filter Condition types (see tBTM_INQ_PARMS) */
+#define BTM_CLR_INQUIRY_FILTER          0                   /* Inquiry Filtering is turned off */
+#define BTM_FILTER_COND_DEVICE_CLASS    HCI_FILTER_COND_DEVICE_CLASS /* Filter on device class */
+#define BTM_FILTER_COND_BD_ADDR         HCI_FILTER_COND_BD_ADDR /* Filter on device addr */
+
+/* State of the remote name retrieval during inquiry operations.
+** Used in the tBTM_INQ_INFO structure, and returned in the
+** BTM_InqDbRead, BTM_InqDbFirst, and BTM_InqDbNext functions.
+** The name field is valid when the state returned is
+** BTM_INQ_RMT_NAME_DONE */
+#define BTM_INQ_RMT_NAME_EMPTY      0
+#define BTM_INQ_RMT_NAME_PENDING    1
+#define BTM_INQ_RMT_NAME_DONE       2
+#define BTM_INQ_RMT_NAME_FAILED     3
+
+/*********************************
+ *** Class of Device constants ***
+ *********************************/
+#define BTM_FORMAT_TYPE_1   0x00
+
+/****************************
+** minor device class field
+*****************************/
+
+/* 0x00 is used as unclassified for all minor device classes */
+#define BTM_COD_MINOR_UNCLASSIFIED          0x00
+
+/* minor device class field for Computer Major Class */
+/* #define BTM_COD_MINOR_UNCLASSIFIED       0x00    */
+#define BTM_COD_MINOR_DESKTOP_WORKSTATION   0x04
+#define BTM_COD_MINOR_SERVER_COMPUTER       0x08
+#define BTM_COD_MINOR_LAPTOP                0x0C
+#define BTM_COD_MINOR_HANDHELD_PC_PDA       0x10    /* clam shell */
+#define BTM_COD_MINOR_PALM_SIZE_PC_PDA      0x14
+#define BTM_COD_MINOR_WEARABLE_COMPUTER     0x18    /* watch sized */
+
+/* minor device class field for Phone Major Class */
+/* #define BTM_COD_MINOR_UNCLASSIFIED       0x00    */
+#define BTM_COD_MINOR_CELLULAR              0x04
+#define BTM_COD_MINOR_CORDLESS              0x08
+#define BTM_COD_MINOR_SMART_PHONE           0x0C
+#define BTM_COD_MINOR_WIRED_MDM_V_GTWY      0x10 /* wired modem or voice gatway */
+#define BTM_COD_MINOR_ISDN_ACCESS           0x14
+
+/* minor device class field for LAN Access Point Major Class */
+/* Load Factor Field bit 5-7 */
+#define BTM_COD_MINOR_FULLY_AVAILABLE       0x00
+#define BTM_COD_MINOR_1_17_UTILIZED         0x20
+#define BTM_COD_MINOR_17_33_UTILIZED        0x40
+#define BTM_COD_MINOR_33_50_UTILIZED        0x60
+#define BTM_COD_MINOR_50_67_UTILIZED        0x80
+#define BTM_COD_MINOR_67_83_UTILIZED        0xA0
+#define BTM_COD_MINOR_83_99_UTILIZED        0xC0
+#define BTM_COD_MINOR_NO_SERVICE_AVAILABLE  0xE0
+/* sub-Field bit 2-4 */
+/* #define BTM_COD_MINOR_UNCLASSIFIED       0x00    */
+
+/* minor device class field for Audio/Video Major Class */
+/* #define BTM_COD_MINOR_UNCLASSIFIED       0x00    */
+#define BTM_COD_MINOR_CONFM_HEADSET         0x04
+#define BTM_COD_MINOR_CONFM_HANDSFREE       0x08
+#define BTM_COD_MINOR_MICROPHONE            0x10
+#define BTM_COD_MINOR_LOUDSPEAKER           0x14
+#define BTM_COD_MINOR_HEADPHONES            0x18
+#define BTM_COD_MINOR_PORTABLE_AUDIO        0x1C
+#define BTM_COD_MINOR_CAR_AUDIO             0x20
+#define BTM_COD_MINOR_SET_TOP_BOX           0x24
+#define BTM_COD_MINOR_HIFI_AUDIO            0x28
+#define BTM_COD_MINOR_VCR                   0x2C
+#define BTM_COD_MINOR_VIDEO_CAMERA          0x30
+#define BTM_COD_MINOR_CAMCORDER             0x34
+#define BTM_COD_MINOR_VIDEO_MONITOR         0x38
+#define BTM_COD_MINOR_VIDDISP_LDSPKR        0x3C
+#define BTM_COD_MINOR_VIDEO_CONFERENCING    0x40
+#define BTM_COD_MINOR_GAMING_TOY            0x48
+
+/* minor device class field for Peripheral Major Class */
+/* Bits 6-7 independently specify mouse, keyboard, or combo mouse/keyboard */
+#define BTM_COD_MINOR_KEYBOARD              0x40
+#define BTM_COD_MINOR_POINTING              0x80
+#define BTM_COD_MINOR_COMBO                 0xC0
+/* Bits 2-5 OR'd with selection from bits 6-7 */
+/* #define BTM_COD_MINOR_UNCLASSIFIED       0x00    */
+#define BTM_COD_MINOR_JOYSTICK              0x04
+#define BTM_COD_MINOR_GAMEPAD               0x08
+#define BTM_COD_MINOR_REMOTE_CONTROL        0x0C
+#define BTM_COD_MINOR_SENSING_DEVICE        0x10
+#define BTM_COD_MINOR_DIGITIZING_TABLET     0x14
+#define BTM_COD_MINOR_CARD_READER           0x18    /* e.g. SIM card reader */
+#define BTM_COD_MINOR_DIGITAL_PAN           0x1C
+#define BTM_COD_MINOR_HAND_SCANNER          0x20
+#define BTM_COD_MINOR_HAND_GESTURAL_INPUT   0x24
+
+/* minor device class field for Imaging Major Class */
+/* Bits 5-7 independently specify display, camera, scanner, or printer */
+#define BTM_COD_MINOR_DISPLAY               0x10
+#define BTM_COD_MINOR_CAMERA                0x20
+#define BTM_COD_MINOR_SCANNER               0x40
+#define BTM_COD_MINOR_PRINTER               0x80
+/* Bits 2-3 Reserved */
+/* #define BTM_COD_MINOR_UNCLASSIFIED       0x00    */
+
+/* minor device class field for Wearable Major Class */
+/* Bits 2-7 meaningful    */
+#define BTM_COD_MINOR_WRIST_WATCH           0x04
+#define BTM_COD_MINOR_PAGER                 0x08
+#define BTM_COD_MINOR_JACKET                0x0C
+#define BTM_COD_MINOR_HELMET                0x10
+#define BTM_COD_MINOR_GLASSES               0x14
+
+/* minor device class field for Toy Major Class */
+/* Bits 2-7 meaningful    */
+#define BTM_COD_MINOR_ROBOT                 0x04
+#define BTM_COD_MINOR_VEHICLE               0x08
+#define BTM_COD_MINOR_DOLL_ACTION_FIGURE    0x0C
+#define BTM_COD_MINOR_CONTROLLER            0x10
+#define BTM_COD_MINOR_GAME                  0x14
+
+/* minor device class field for Health Major Class */
+/* Bits 2-7 meaningful    */
+#define BTM_COD_MINOR_BLOOD_MONITOR         0x04
+#define BTM_COD_MINOR_THERMOMETER           0x08
+#define BTM_COD_MINOR_WEIGHING_SCALE        0x0C
+#define BTM_COD_MINOR_GLUCOSE_METER         0x10
+#define BTM_COD_MINOR_PULSE_OXIMETER        0x14
+#define BTM_COD_MINOR_HEART_PULSE_MONITOR   0x18
+#define BTM_COD_MINOR_HEALTH_DATA_DISPLAY   0x1C
+#define BTM_COD_MINOR_STEP_COUNTER          0x20
+#define BTM_COD_MINOR_BODY_COM_ANALYZER     0x24
+#define BTM_COD_MINOR_PEAK_FLOW_MONITOR     0x28
+#define BTM_COD_MINOR_MEDICATION_MONITOR    0x2C
+#define BTM_COD_MINOR_KNEE_PROSTHESIS       0x30
+#define BTM_COD_MINOR_ANKLE_PROSTHESIS      0x34
+
+
+/***************************
+** major device class field
+****************************/
+#define BTM_COD_MAJOR_MISCELLANEOUS         0x00
+#define BTM_COD_MAJOR_COMPUTER              0x01
+#define BTM_COD_MAJOR_PHONE                 0x02
+#define BTM_COD_MAJOR_LAN_ACCESS_PT         0x03
+#define BTM_COD_MAJOR_AUDIO                 0x04
+#define BTM_COD_MAJOR_PERIPHERAL            0x05
+#define BTM_COD_MAJOR_IMAGING               0x06
+#define BTM_COD_MAJOR_WEARABLE              0x07
+#define BTM_COD_MAJOR_TOY                   0x08
+#define BTM_COD_MAJOR_HEALTH                0x09
+#define BTM_COD_MAJOR_UNCLASSIFIED          0x1F
+
+/***************************
+** service class fields
+****************************/
+#define BTM_COD_SERVICE_LMTD_DISCOVER       0x0020
+#define BTM_COD_SERVICE_POSITIONING         0x0100
+#define BTM_COD_SERVICE_NETWORKING          0x0200
+#define BTM_COD_SERVICE_RENDERING           0x0400
+#define BTM_COD_SERVICE_CAPTURING           0x0800
+#define BTM_COD_SERVICE_OBJ_TRANSFER        0x1000
+#define BTM_COD_SERVICE_AUDIO               0x2000
+#define BTM_COD_SERVICE_TELEPHONY           0x4000
+#define BTM_COD_SERVICE_INFORMATION         0x8000
+
+/* class of device field macros */
+#define BTM_COD_FORMAT_TYPE(u8, pd)         {(u8)  = (pd)[2]&0x03;}
+#define BTM_COD_MINOR_CLASS(u8, pd)         {(u8)  = (pd)[2]&0xFC;}
+#define BTM_COD_MAJOR_CLASS(u8, pd)         {(u8)  = (pd)[1]&0x1F;}
+#define BTM_COD_SERVICE_CLASS(u16, pd)      {(u16) = (pd)[0]; (u16)<<=8; (u16) += (pd)[1]&0xE0;}
+
+/* to set the fields (assumes that format type is always 0) */
+#define FIELDS_TO_COD(pd, mn, mj, sv) {(pd)[2] = mn; (pd)[1] =                  \
+                                       (mj)+ ((sv)&BTM_COD_SERVICE_CLASS_LO_B); \
+                                       (pd)[0] = (sv) >> 8;}
+
+/* the COD masks */
+#define BTM_COD_FORMAT_TYPE_MASK      0x03
+#define BTM_COD_MINOR_CLASS_MASK      0xFC
+#define BTM_COD_MAJOR_CLASS_MASK      0x1F
+#define BTM_COD_SERVICE_CLASS_LO_B    0x00E0
+#define BTM_COD_SERVICE_CLASS_MASK    0xFFE0
+
+
+/* BTM service definitions
+** Used for storing EIR data to bit mask
+*/
+enum
+{
+    BTM_EIR_UUID_SERVCLASS_SERVICE_DISCOVERY_SERVER,
+/*    BTM_EIR_UUID_SERVCLASS_BROWSE_GROUP_DESCRIPTOR,   */
+/*    BTM_EIR_UUID_SERVCLASS_PUBLIC_BROWSE_GROUP,       */
+    BTM_EIR_UUID_SERVCLASS_SERIAL_PORT,
+    BTM_EIR_UUID_SERVCLASS_LAN_ACCESS_USING_PPP,
+    BTM_EIR_UUID_SERVCLASS_DIALUP_NETWORKING,
+    BTM_EIR_UUID_SERVCLASS_IRMC_SYNC,
+    BTM_EIR_UUID_SERVCLASS_OBEX_OBJECT_PUSH,
+    BTM_EIR_UUID_SERVCLASS_OBEX_FILE_TRANSFER,
+    BTM_EIR_UUID_SERVCLASS_IRMC_SYNC_COMMAND,
+    BTM_EIR_UUID_SERVCLASS_HEADSET,
+    BTM_EIR_UUID_SERVCLASS_CORDLESS_TELEPHONY,
+    BTM_EIR_UUID_SERVCLASS_AUDIO_SOURCE,
+    BTM_EIR_UUID_SERVCLASS_AUDIO_SINK,
+    BTM_EIR_UUID_SERVCLASS_AV_REM_CTRL_TARGET,
+/*    BTM_EIR_UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION,    */
+    BTM_EIR_UUID_SERVCLASS_AV_REMOTE_CONTROL,
+/*    BTM_EIR_UUID_SERVCLASS_VIDEO_CONFERENCING,        */
+    BTM_EIR_UUID_SERVCLASS_INTERCOM,
+    BTM_EIR_UUID_SERVCLASS_FAX,
+    BTM_EIR_UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY,
+/*    BTM_EIR_UUID_SERVCLASS_WAP,                       */
+/*    BTM_EIR_UUID_SERVCLASS_WAP_CLIENT,                */
+    BTM_EIR_UUID_SERVCLASS_PANU,
+    BTM_EIR_UUID_SERVCLASS_NAP,
+    BTM_EIR_UUID_SERVCLASS_GN,
+    BTM_EIR_UUID_SERVCLASS_DIRECT_PRINTING,
+/*    BTM_EIR_UUID_SERVCLASS_REFERENCE_PRINTING,        */
+    BTM_EIR_UUID_SERVCLASS_IMAGING,
+    BTM_EIR_UUID_SERVCLASS_IMAGING_RESPONDER,
+    BTM_EIR_UUID_SERVCLASS_IMAGING_AUTO_ARCHIVE,
+    BTM_EIR_UUID_SERVCLASS_IMAGING_REF_OBJECTS,
+    BTM_EIR_UUID_SERVCLASS_HF_HANDSFREE,
+    BTM_EIR_UUID_SERVCLASS_AG_HANDSFREE,
+    BTM_EIR_UUID_SERVCLASS_DIR_PRT_REF_OBJ_SERVICE,
+/*    BTM_EIR_UUID_SERVCLASS_REFLECTED_UI,              */
+    BTM_EIR_UUID_SERVCLASS_BASIC_PRINTING,
+    BTM_EIR_UUID_SERVCLASS_PRINTING_STATUS,
+    BTM_EIR_UUID_SERVCLASS_HUMAN_INTERFACE,
+    BTM_EIR_UUID_SERVCLASS_CABLE_REPLACEMENT,
+    BTM_EIR_UUID_SERVCLASS_HCRP_PRINT,
+    BTM_EIR_UUID_SERVCLASS_HCRP_SCAN,
+/*    BTM_EIR_UUID_SERVCLASS_COMMON_ISDN_ACCESS,        */
+/*    BTM_EIR_UUID_SERVCLASS_VIDEO_CONFERENCING_GW,     */
+/*    BTM_EIR_UUID_SERVCLASS_UDI_MT,                    */
+/*    BTM_EIR_UUID_SERVCLASS_UDI_TA,                    */
+/*    BTM_EIR_UUID_SERVCLASS_VCP,                       */
+    BTM_EIR_UUID_SERVCLASS_SAP,
+    BTM_EIR_UUID_SERVCLASS_PBAP_PCE,
+    BTM_EIR_UUID_SERVCLASS_PBAP_PSE,
+/*    BTM_EIR_UUID_SERVCLASS_TE_PHONE_ACCESS,           */
+/*    BTM_EIR_UUID_SERVCLASS_ME_PHONE_ACCESS,           */
+    BTM_EIR_UUID_SERVCLASS_PHONE_ACCESS,
+    BTM_EIR_UUID_SERVCLASS_HEADSET_HS,
+    BTM_EIR_UUID_SERVCLASS_PNP_INFORMATION,
+/*    BTM_EIR_UUID_SERVCLASS_GENERIC_NETWORKING,        */
+/*    BTM_EIR_UUID_SERVCLASS_GENERIC_FILETRANSFER,      */
+/*    BTM_EIR_UUID_SERVCLASS_GENERIC_AUDIO,             */
+/*    BTM_EIR_UUID_SERVCLASS_GENERIC_TELEPHONY,         */
+/*    BTM_EIR_UUID_SERVCLASS_UPNP_SERVICE,              */
+/*    BTM_EIR_UUID_SERVCLASS_UPNP_IP_SERVICE,           */
+/*    BTM_EIR_UUID_SERVCLASS_ESDP_UPNP_IP_PAN,          */
+/*    BTM_EIR_UUID_SERVCLASS_ESDP_UPNP_IP_LAP,          */
+/*    BTM_EIR_UUID_SERVCLASS_ESDP_UPNP_IP_L2CAP,        */
+    BTM_EIR_UUID_SERVCLASS_VIDEO_SOURCE,
+    BTM_EIR_UUID_SERVCLASS_VIDEO_SINK,
+/*    BTM_EIR_UUID_SERVCLASS_VIDEO_DISTRIBUTION         */
+/*    BTM_EIR_UUID_SERVCLASS_HDP_PROFILE                */
+    BTM_EIR_UUID_SERVCLASS_MESSAGE_ACCESS,
+    BTM_EIR_UUID_SERVCLASS_MESSAGE_NOTIFICATION,
+    BTM_EIR_UUID_SERVCLASS_HDP_SOURCE,
+    BTM_EIR_UUID_SERVCLASS_HDP_SINK,
+    BTM_EIR_MAX_SERVICES
+};
+
+/* search result in EIR of inquiry database */
+#define BTM_EIR_FOUND           0
+#define BTM_EIR_NOT_FOUND       1
+#define BTM_EIR_UNKNOWN         2
+
+typedef uint8_t tBTM_EIR_SEARCH_RESULT;
+
+#define BTM_EIR_FLAGS_TYPE                  HCI_EIR_FLAGS_TYPE                  /* 0x01 */
+#define BTM_EIR_MORE_16BITS_UUID_TYPE       HCI_EIR_MORE_16BITS_UUID_TYPE       /* 0x02 */
+#define BTM_EIR_COMPLETE_16BITS_UUID_TYPE   HCI_EIR_COMPLETE_16BITS_UUID_TYPE   /* 0x03 */
+#define BTM_EIR_MORE_32BITS_UUID_TYPE       HCI_EIR_MORE_32BITS_UUID_TYPE       /* 0x04 */
+#define BTM_EIR_COMPLETE_32BITS_UUID_TYPE   HCI_EIR_COMPLETE_32BITS_UUID_TYPE   /* 0x05 */
+#define BTM_EIR_MORE_128BITS_UUID_TYPE      HCI_EIR_MORE_128BITS_UUID_TYPE      /* 0x06 */
+#define BTM_EIR_COMPLETE_128BITS_UUID_TYPE  HCI_EIR_COMPLETE_128BITS_UUID_TYPE  /* 0x07 */
+#define BTM_EIR_SHORTENED_LOCAL_NAME_TYPE   HCI_EIR_SHORTENED_LOCAL_NAME_TYPE   /* 0x08 */
+#define BTM_EIR_COMPLETE_LOCAL_NAME_TYPE    HCI_EIR_COMPLETE_LOCAL_NAME_TYPE    /* 0x09 */
+#define BTM_EIR_TX_POWER_LEVEL_TYPE         HCI_EIR_TX_POWER_LEVEL_TYPE         /* 0x0A */
+#define BTM_EIR_MANUFACTURER_SPECIFIC_TYPE  HCI_EIR_MANUFACTURER_SPECIFIC_TYPE  /* 0xFF */
+
+/* the following EIR tags are defined to OOB, not regular EIR data */
+#define BTM_EIR_OOB_BD_ADDR_TYPE            HCI_EIR_OOB_BD_ADDR_TYPE    /* 6 bytes */
+#define BTM_EIR_OOB_COD_TYPE                HCI_EIR_OOB_COD_TYPE        /* 3 bytes */
+#define BTM_EIR_OOB_SSP_HASH_C_TYPE         HCI_EIR_OOB_SSP_HASH_C_TYPE /* 16 bytes */
+#define BTM_EIR_OOB_SSP_RAND_R_TYPE         HCI_EIR_OOB_SSP_RAND_R_TYPE /* 16 bytes */
+
+#define BTM_OOB_MANDATORY_SIZE      8   /* include 2 bytes length & 6 bytes bd_addr */
+#define BTM_OOB_DATA_LEN_SIZE       2
+#define BTM_OOB_BD_ADDR_SIZE        6
+#define BTM_OOB_COD_SIZE            BT_OOB_COD_SIZE
+#define BTM_OOB_HASH_C_SIZE         BT_OOB_HASH_C_SIZE
+#define BTM_OOB_RAND_R_SIZE         BT_OOB_RAND_R_SIZE
+
+#define BTM_BLE_SEC_NONE                0
+#define BTM_BLE_SEC_ENCRYPT             1 /* encrypt the link using current key */
+#define BTM_BLE_SEC_ENCRYPT_NO_MITM     2
+#define BTM_BLE_SEC_ENCRYPT_MITM        3
+typedef uint8_t tBTM_BLE_SEC_ACT;
+
+/************************************************************************************************
+** BTM Services MACROS handle array of uint32_t bits for more than 32 services
+*************************************************************************************************/
+/* Determine the number of uint32_t's necessary for services */
+#define BTM_EIR_ARRAY_BITS          32          /* Number of bits in each array element */
+#define BTM_EIR_SERVICE_ARRAY_SIZE  (((uint32_t)BTM_EIR_MAX_SERVICES / BTM_EIR_ARRAY_BITS) + \
+                                    (((uint32_t)BTM_EIR_MAX_SERVICES % BTM_EIR_ARRAY_BITS) ? 1 : 0))
+
+/* MACRO to set the service bit mask in a bit stream */
+#define BTM_EIR_SET_SERVICE(p, service)  (((uint32_t *)(p))[(((uint32_t)(service)) / BTM_EIR_ARRAY_BITS)] |=  \
+                                    ((uint32_t)1 << (((uint32_t)(service)) % BTM_EIR_ARRAY_BITS)))
+
+
+/* MACRO to clear the service bit mask in a bit stream */
+#define BTM_EIR_CLR_SERVICE(p, service)  (((uint32_t *)(p))[(((uint32_t)(service)) / BTM_EIR_ARRAY_BITS)] &=  \
+                                    ~((uint32_t)1 << (((uint32_t)(service)) % BTM_EIR_ARRAY_BITS)))
+
+/* MACRO to check the service bit mask in a bit stream */
+#define BTM_EIR_HAS_SERVICE(p, service)  ((((uint32_t *)(p))[(((uint32_t)(service)) / BTM_EIR_ARRAY_BITS)] &  \
+                                    ((uint32_t)1 << (((uint32_t)(service)) % BTM_EIR_ARRAY_BITS))) >> (((uint32_t)(service)) % BTM_EIR_ARRAY_BITS))
+
+/* start of EIR in HCI buffer, 4 bytes = HCI Command(2) + Length(1) + FEC_Req(1) */
+#define BTM_HCI_EIR_OFFSET          (BT_HDR_SIZE + 4)
+
+/***************************
+**  Device Discovery Types
+****************************/
+/* Definitions of the parameters passed to BTM_StartInquiry and
+** BTM_SetPeriodicInquiryMode.
+*/
+typedef struct              /* contains the two device class condition fields */
+{
+    DEV_CLASS       dev_class;
+    DEV_CLASS       dev_class_mask;
+} tBTM_COD_COND;
+
+
+typedef union               /* contains the inquiry filter condition */
+{
+    BD_ADDR         bdaddr_cond;
+    tBTM_COD_COND   cod_cond;
+} tBTM_INQ_FILT_COND;
+
+
+typedef struct              /* contains the parameters passed to the inquiry functions */
+{
+    uint8_t mode;                       /* general or limited */
+    uint8_t duration;                   /* duration of the inquiry (1.28 sec increments) */
+    uint8_t max_resps;                  /* maximum number of responses to return */
+    bool    report_dup;                 /* report duplicated inquiry response with higher RSSI value */
+    uint8_t filter_cond_type;           /* new devices, BD ADDR, COD, or No filtering */
+    tBTM_INQ_FILT_COND  filter_cond;    /* filter value based on filter cond type */
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+    uint8_t intl_duration[4];              /*duration array storing the interleave scan's time portions*/
+#endif
+} tBTM_INQ_PARMS;
+
+#define BTM_INQ_RESULT_BR       0x01
+#define BTM_INQ_RESULT_BLE      0x02
+
+#if (BLE_INCLUDED == TRUE)
+#define BTM_BLE_EVT_CONN_ADV        0x00
+#define BTM_BLE_EVT_CONN_DIR_ADV    0x01
+#define BTM_BLE_EVT_DISC_ADV        0x02
+#define BTM_BLE_EVT_NON_CONN_ADV    0x03
+#define BTM_BLE_EVT_SCAN_RSP        0x04
+typedef uint8_t tBTM_BLE_EVT_TYPE;
+#endif
+
+/* These are the fields returned in each device's response to the inquiry.  It
+** is returned in the results callback if registered.
+*/
+typedef struct
+{
+    uint16_t    clock_offset;
+    BD_ADDR     remote_bd_addr;
+    DEV_CLASS   dev_class;
+    uint8_t     page_scan_rep_mode;
+    uint8_t     page_scan_per_mode;
+    uint8_t     page_scan_mode;
+    int8_t      rssi;       /* Set to BTM_INQ_RES_IGNORE_RSSI if  not valid */
+    uint32_t    eir_uuid[BTM_EIR_SERVICE_ARRAY_SIZE];
+    bool        eir_complete_list;
+#if (BLE_INCLUDED == TRUE)
+    tBT_DEVICE_TYPE         device_type;
+    uint8_t     inq_result_type;
+    uint8_t     ble_addr_type;
+    tBTM_BLE_EVT_TYPE       ble_evt_type;
+    uint8_t                 flag;
+#endif
+} tBTM_INQ_RESULTS;
+
+
+/* This is the inquiry response information held in its database by BTM, and available
+** to applications via BTM_InqDbRead, BTM_InqDbFirst, and BTM_InqDbNext.
+*/
+typedef struct
+{
+    tBTM_INQ_RESULTS    results;
+
+    bool                appl_knows_rem_name;    /* set by application if it knows the remote name of the peer device.
+                                                   This is later used by application to determine if remote name request is
+                                                   required to be done. Having the flag here avoid duplicate store of inquiry results */
+#if (BLE_INCLUDED == TRUE)
+    uint16_t        remote_name_len;
+    tBTM_BD_NAME    remote_name;
+    uint8_t         remote_name_state;
+    uint8_t         remote_name_type;
+#endif
+
+} tBTM_INQ_INFO;
+
+
+/* Structure returned with inquiry complete callback */
+typedef struct
+{
+    tBTM_STATUS status;
+    uint8_t     num_resp;       /* Number of results from the current inquiry */
+} tBTM_INQUIRY_CMPL;
+
+
+/* Structure returned with remote name  request */
+typedef struct
+{
+    uint16_t    status;
+    BD_ADDR     bd_addr;
+    uint16_t    length;
+    BD_NAME     remote_bd_name;
+} tBTM_REMOTE_DEV_NAME;
+
+typedef struct
+{
+    uint8_t pcm_intf_rate;  /* PCM interface rate: 0: 128kbps, 1: 256 kbps;
+                                2:512 bps; 3: 1024kbps; 4: 2048kbps */
+    uint8_t frame_type;     /* frame type: 0: short; 1: long */
+    uint8_t sync_mode;      /* sync mode: 0: slave; 1: master */
+    uint8_t clock_mode;     /* clock mode: 0: slave; 1: master */
+
+}tBTM_SCO_PCM_PARAM;
+
+/****************************************
+**  Device Discovery Callback Functions
+*****************************************/
+/* Callback function for asynchronous notifications when the BTM inquiry DB
+** changes. First param is inquiry database, second is if added to or removed
+** from the inquiry database.
+*/
+typedef void (tBTM_INQ_DB_CHANGE_CB) (void *p1, bool    is_new);
+
+/* Callback function for notifications when the BTM gets inquiry response.
+** First param is inquiry results database, second is pointer of EIR.
+*/
+typedef void (tBTM_INQ_RESULTS_CB) (tBTM_INQ_RESULTS *p_inq_results, uint8_t *p_eir);
+
+/*****************************************************************************
+**  ACL CHANNEL MANAGEMENT
+*****************************************************************************/
+/******************
+**  ACL Constants
+*******************/
+
+/* ACL modes */
+#define BTM_ACL_MODE_NORMAL     HCI_MODE_ACTIVE
+#define BTM_ACL_MODE_HOLD       HCI_MODE_HOLD
+#define BTM_ACL_MODE_SNIFF      HCI_MODE_SNIFF
+#define BTM_ACL_MODE_PARK       HCI_MODE_PARK
+
+/* Returned with structure in role switch callback (tBTM_ROLE_SWITCH_CMPL) */
+#define BTM_ROLE_MASTER         HCI_ROLE_MASTER
+#define BTM_ROLE_SLAVE          HCI_ROLE_SLAVE
+#define BTM_ROLE_UNDEFINED      0xff     /* undefined value (error status) */
+
+/* ACL Packet Types */
+#define BTM_ACL_PKT_TYPES_MASK_DM1      HCI_PKT_TYPES_MASK_DM1
+#define BTM_ACL_PKT_TYPES_MASK_DH1      HCI_PKT_TYPES_MASK_DH1
+#define BTM_ACL_PKT_TYPES_MASK_DM3      HCI_PKT_TYPES_MASK_DM3
+#define BTM_ACL_PKT_TYPES_MASK_DH3      HCI_PKT_TYPES_MASK_DH3
+#define BTM_ACL_PKT_TYPES_MASK_DM5      HCI_PKT_TYPES_MASK_DM5
+#define BTM_ACL_PKT_TYPES_MASK_DH5      HCI_PKT_TYPES_MASK_DH5
+#define BTM_ACL_PKT_TYPES_MASK_NO_2_DH1 HCI_PKT_TYPES_MASK_NO_2_DH1
+#define BTM_ACL_PKT_TYPES_MASK_NO_3_DH1 HCI_PKT_TYPES_MASK_NO_3_DH1
+#define BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 HCI_PKT_TYPES_MASK_NO_2_DH3
+#define BTM_ACL_PKT_TYPES_MASK_NO_3_DH3 HCI_PKT_TYPES_MASK_NO_3_DH3
+#define BTM_ACL_PKT_TYPES_MASK_NO_2_DH5 HCI_PKT_TYPES_MASK_NO_2_DH5
+#define BTM_ACL_PKT_TYPES_MASK_NO_3_DH5 HCI_PKT_TYPES_MASK_NO_3_DH5
+
+/***************
+**  ACL Types
+****************/
+
+/* Structure returned with Role Switch information (in tBTM_CMPL_CB callback function)
+** in response to BTM_SwitchRole call.
+*/
+typedef struct
+{
+    uint8_t hci_status;     /* HCI status returned with the event */
+    uint8_t role;           /* BTM_ROLE_MASTER or BTM_ROLE_SLAVE */
+    BD_ADDR remote_bd_addr; /* Remote BD addr involved with the switch */
+} tBTM_ROLE_SWITCH_CMPL;
+
+/* Structure returned with QoS information (in tBTM_CMPL_CB callback function)
+** in response to BTM_SetQoS call.
+*/
+typedef struct
+{
+    FLOW_SPEC flow;
+    uint16_t handle;
+    uint8_t status;
+} tBTM_QOS_SETUP_CMPL;
+
+
+/* Structure returned with read RSSI event (in tBTM_CMPL_CB callback function)
+** in response to BTM_ReadRSSI call.
+*/
+typedef struct
+{
+    tBTM_STATUS status;
+    uint8_t     hci_status;
+    int8_t      rssi;
+    BD_ADDR     rem_bda;
+} tBTM_RSSI_RESULTS;
+
+/* Structure returned with read current TX power event (in tBTM_CMPL_CB callback function)
+** in response to BTM_ReadTxPower call.
+*/
+typedef struct
+{
+    tBTM_STATUS status;
+    uint8_t     hci_status;
+    int8_t      tx_power;
+    BD_ADDR     rem_bda;
+} tBTM_TX_POWER_RESULTS;
+
+/* Structure returned with read link quality event (in tBTM_CMPL_CB callback function)
+** in response to BTM_ReadLinkQuality call.
+*/
+typedef struct
+{
+    tBTM_STATUS status;
+    uint8_t     hci_status;
+    uint8_t     link_quality;
+    BD_ADDR     rem_bda;
+} tBTM_LINK_QUALITY_RESULTS;
+
+/* Structure returned with read inq tx power quality event (in tBTM_CMPL_CB callback function)
+** in response to BTM_ReadInquiryRspTxPower call.
+*/
+typedef struct
+{
+    tBTM_STATUS status;
+    uint8_t     hci_status;
+    int8_t      tx_power;
+} tBTM_INQ_TXPWR_RESULTS;
+
+enum
+{
+    BTM_BL_CONN_EVT,
+    BTM_BL_DISCN_EVT,
+    BTM_BL_UPDATE_EVT,
+    BTM_BL_ROLE_CHG_EVT,
+    BTM_BL_COLLISION_EVT
+};
+typedef uint8_t tBTM_BL_EVENT;
+typedef uint16_t tBTM_BL_EVENT_MASK;
+
+#define BTM_BL_CONN_MASK        0x0001
+#define BTM_BL_DISCN_MASK       0x0002
+#define BTM_BL_UPDATE_MASK      0x0004
+#define BTM_BL_ROLE_CHG_MASK    0x0008
+
+/* Device features mask definitions */
+#define BTM_FEATURE_BYTES_PER_PAGE  HCI_FEATURE_BYTES_PER_PAGE
+#define BTM_EXT_FEATURES_PAGE_MAX   HCI_EXT_FEATURES_PAGE_MAX
+
+/* the data type associated with BTM_BL_CONN_EVT */
+typedef struct
+{
+    tBTM_BL_EVENT   event;      /* The event reported. */
+    BD_ADDR_PTR     p_bda;      /* The address of the newly connected device */
+    DEV_CLASS_PTR   p_dc;       /* The device class */
+    BD_NAME_PTR     p_bdn;      /* The device name */
+    uint8_t        *p_features; /* pointer to the remote device's features page[0] (supported features page) */
+#if (BLE_INCLUDED == TRUE)
+    uint16_t        handle;     /* connection handle */
+    tBT_TRANSPORT   transport; /* link is LE or not */
+#endif
+} tBTM_BL_CONN_DATA;
+
+/* the data type associated with BTM_BL_DISCN_EVT */
+typedef struct
+{
+    tBTM_BL_EVENT   event;  /* The event reported. */
+    BD_ADDR_PTR     p_bda;  /* The address of the disconnected device */
+#if (BLE_INCLUDED == TRUE)
+    uint16_t        handle; /* disconnected connection handle */
+    tBT_TRANSPORT   transport; /* link is LE link or not */
+#endif
+} tBTM_BL_DISCN_DATA;
+
+/* Busy-Level shall have the inquiry_paging mask set when
+ * inquiry/paging is in progress, Else the number of ACL links */
+#define BTM_BL_INQUIRY_PAGING_MASK 0x10
+#define BTM_BL_INQUIRY_STARTED   (BTM_BL_INQUIRY_PAGING_MASK | 0x1)
+#define BTM_BL_INQUIRY_CANCELLED (BTM_BL_INQUIRY_PAGING_MASK | 0x2)
+#define BTM_BL_INQUIRY_COMPLETE  (BTM_BL_INQUIRY_PAGING_MASK | 0x3)
+#define BTM_BL_PAGING_STARTED    (BTM_BL_INQUIRY_PAGING_MASK | 0x4)
+#define BTM_BL_PAGING_COMPLETE   (BTM_BL_INQUIRY_PAGING_MASK | 0x5)
+/* the data type associated with BTM_BL_UPDATE_EVT */
+typedef struct
+{
+    tBTM_BL_EVENT   event;  /* The event reported. */
+    uint8_t         busy_level;/* when paging or inquiring, level is 10.
+                                * Otherwise, the number of ACL links. */
+    uint8_t         busy_level_flags; /* Notifies actual inquiry/page activities */
+} tBTM_BL_UPDATE_DATA;
+
+/* the data type associated with BTM_BL_ROLE_CHG_EVT */
+typedef struct
+{
+    tBTM_BL_EVENT   event;      /* The event reported. */
+    BD_ADDR_PTR     p_bda;      /* The address of the peer connected device */
+    uint8_t         new_role;
+    uint8_t         hci_status; /* HCI status returned with the event */
+} tBTM_BL_ROLE_CHG_DATA;
+
+typedef union
+{
+    tBTM_BL_EVENT           event;  /* The event reported. */
+    tBTM_BL_CONN_DATA       conn;   /* The data associated with BTM_BL_CONN_EVT */
+    tBTM_BL_DISCN_DATA      discn;  /* The data associated with BTM_BL_DISCN_EVT */
+    tBTM_BL_UPDATE_DATA     update; /* The data associated with BTM_BL_UPDATE_EVT */
+    tBTM_BL_ROLE_CHG_DATA   role_chg;/*The data associated with BTM_BL_ROLE_CHG_EVT */
+} tBTM_BL_EVENT_DATA;
+
+/* Callback function for notifications when the BTM busy level
+** changes.
+*/
+typedef void (tBTM_BL_CHANGE_CB) (tBTM_BL_EVENT_DATA *p_data);
+
+/***************************
+**  ACL Callback Functions
+****************************/
+/* Callback function for notifications when the BTM ACL connection DB
+** changes. First param is BD address, second is if added or removed.
+** Registered through BTM_AclRegisterForChanges call.
+*/
+#if (BLE_INCLUDED == TRUE)
+typedef void (tBTM_ACL_DB_CHANGE_CB) (BD_ADDR p_bda, DEV_CLASS p_dc,
+                                      BD_NAME p_bdn, uint8_t *features,
+                                      bool    is_new, uint16_t handle,
+                                      tBT_TRANSPORT transport);
+#else
+typedef void (tBTM_ACL_DB_CHANGE_CB) (BD_ADDR p_bda, DEV_CLASS p_dc,
+                                      BD_NAME p_bdn, uint8_t *features,
+                                      bool    is_new);
+#endif
+/*****************************************************************************
+**  SCO CHANNEL MANAGEMENT
+*****************************************************************************/
+/******************
+**  SCO Constants
+*******************/
+
+/* Define an invalid SCO index and an invalid HCI handle */
+#define BTM_INVALID_SCO_INDEX       0xFFFF
+#define BTM_INVALID_HCI_HANDLE      0xFFFF
+
+/* Define an invalid SCO disconnect reason */
+#define BTM_INVALID_SCO_DISC_REASON 0xFFFF
+
+/* Define first active SCO index */
+#define BTM_FIRST_ACTIVE_SCO_INDEX  BTM_MAX_SCO_LINKS
+
+/* Define SCO packet types used in APIs */
+#define BTM_SCO_PKT_TYPES_MASK_HV1  HCI_ESCO_PKT_TYPES_MASK_HV1
+#define BTM_SCO_PKT_TYPES_MASK_HV2  HCI_ESCO_PKT_TYPES_MASK_HV2
+#define BTM_SCO_PKT_TYPES_MASK_HV3  HCI_ESCO_PKT_TYPES_MASK_HV3
+#define BTM_SCO_PKT_TYPES_MASK_EV3  HCI_ESCO_PKT_TYPES_MASK_EV3
+#define BTM_SCO_PKT_TYPES_MASK_EV4  HCI_ESCO_PKT_TYPES_MASK_EV4
+#define BTM_SCO_PKT_TYPES_MASK_EV5  HCI_ESCO_PKT_TYPES_MASK_EV5
+#define BTM_SCO_PKT_TYPES_MASK_NO_2_EV3  HCI_ESCO_PKT_TYPES_MASK_NO_2_EV3
+#define BTM_SCO_PKT_TYPES_MASK_NO_3_EV3  HCI_ESCO_PKT_TYPES_MASK_NO_3_EV3
+#define BTM_SCO_PKT_TYPES_MASK_NO_2_EV5  HCI_ESCO_PKT_TYPES_MASK_NO_2_EV5
+#define BTM_SCO_PKT_TYPES_MASK_NO_3_EV5  HCI_ESCO_PKT_TYPES_MASK_NO_3_EV5
+
+#define BTM_SCO_LINK_ONLY_MASK  (BTM_SCO_PKT_TYPES_MASK_HV1 | \
+                                 BTM_SCO_PKT_TYPES_MASK_HV2 | \
+                                 BTM_SCO_PKT_TYPES_MASK_HV3)
+
+#define BTM_ESCO_LINK_ONLY_MASK (BTM_SCO_PKT_TYPES_MASK_EV3 | \
+                                 BTM_SCO_PKT_TYPES_MASK_EV4 | \
+                                 BTM_SCO_PKT_TYPES_MASK_EV5)
+
+#define BTM_SCO_LINK_ALL_PKT_MASK   (BTM_SCO_LINK_ONLY_MASK     | \
+                                     BTM_ESCO_LINK_ONLY_MASK)
+
+#define BTM_VALID_SCO_ALL_PKT_TYPE HCI_VALID_SCO_ALL_PKT_TYPE
+
+/* Passed in BTM_CreateSco if the packet type parameter should be ignored */
+#define BTM_IGNORE_SCO_PKT_TYPE     0
+
+/***************
+**  SCO Types
+****************/
+#define BTM_LINK_TYPE_SCO           HCI_LINK_TYPE_SCO
+#define BTM_LINK_TYPE_ESCO          HCI_LINK_TYPE_ESCO
+typedef uint8_t tBTM_SCO_TYPE;
+
+
+/*******************
+** SCO Routing Path
+********************/
+#define BTM_SCO_ROUTE_PCM           HCI_BRCM_SCO_ROUTE_PCM
+#define BTM_SCO_ROUTE_HCI           HCI_BRCM_SCO_ROUTE_HCI
+typedef uint8_t tBTM_SCO_ROUTE_TYPE;
+
+
+/*******************
+** SCO Codec Types
+********************/
+// TODO(google) This should use common definitions
+// in hci/include/hci_audio.h
+#define BTM_SCO_CODEC_NONE          0x0000
+#define BTM_SCO_CODEC_CVSD          0x0001
+#define BTM_SCO_CODEC_MSBC          0x0002
+typedef uint16_t tBTM_SCO_CODEC_TYPE;
+
+
+
+/*******************
+** SCO Air Mode Types
+********************/
+#define BTM_SCO_AIR_MODE_U_LAW          0
+#define BTM_SCO_AIR_MODE_A_LAW          1
+#define BTM_SCO_AIR_MODE_CVSD           2
+#define BTM_SCO_AIR_MODE_TRANSPNT       3
+typedef uint8_t tBTM_SCO_AIR_MODE_TYPE;
+
+/*******************
+** SCO Voice Settings
+********************/
+#define BTM_VOICE_SETTING_CVSD  ((uint16_t)  (HCI_INP_CODING_LINEAR          |   \
+                                            HCI_INP_DATA_FMT_2S_COMPLEMENT |   \
+                                            HCI_INP_SAMPLE_SIZE_16BIT      |   \
+                                            HCI_AIR_CODING_FORMAT_CVSD))
+
+#define BTM_VOICE_SETTING_TRANS ((uint16_t)  (HCI_INP_CODING_LINEAR          |   \
+                                            HCI_INP_DATA_FMT_2S_COMPLEMENT |   \
+                                            HCI_INP_SAMPLE_SIZE_16BIT      |   \
+                                            HCI_AIR_CODING_FORMAT_TRANSPNT))
+
+/*******************
+** SCO Data Status
+********************/
+enum
+{
+    BTM_SCO_DATA_CORRECT,
+    BTM_SCO_DATA_PAR_ERR,
+    BTM_SCO_DATA_NONE,
+    BTM_SCO_DATA_PAR_LOST
+};
+typedef uint8_t tBTM_SCO_DATA_FLAG;
+
+/***************************
+**  SCO Callback Functions
+****************************/
+typedef void (tBTM_SCO_CB) (uint16_t sco_inx);
+typedef void (tBTM_SCO_DATA_CB) (uint16_t sco_inx, BT_HDR *p_data, tBTM_SCO_DATA_FLAG status);
+
+/******************
+**  eSCO Constants
+*******************/
+#define BTM_64KBITS_RATE            0x00001f40  /* 64 kbits/sec data rate */
+
+/* Retransmission effort */
+#define BTM_ESCO_RETRANS_OFF        0
+#define BTM_ESCO_RETRANS_POWER      1
+#define BTM_ESCO_RETRANS_QUALITY    2
+#define BTM_ESCO_RETRANS_DONTCARE   0xff
+
+/* Max Latency Don't Care */
+#define BTM_ESCO_MAX_LAT_DONTCARE   0xffff
+
+/***************
+**  eSCO Types
+****************/
+/* tBTM_ESCO_CBACK event types */
+#define BTM_ESCO_CHG_EVT        1
+#define BTM_ESCO_CONN_REQ_EVT   2
+typedef uint8_t tBTM_ESCO_EVT;
+
+/* Passed into BTM_SetEScoMode() */
+typedef struct
+{
+    uint32_t tx_bw;
+    uint32_t rx_bw;
+    uint16_t max_latency;
+    uint16_t voice_contfmt;  /* Voice Settings or Content Format */
+    uint16_t packet_types;
+    uint8_t  retrans_effort;
+} tBTM_ESCO_PARAMS;
+
+typedef struct
+{
+    uint16_t max_latency;
+    uint16_t packet_types;
+    uint8_t  retrans_effort;
+} tBTM_CHG_ESCO_PARAMS;
+
+/* Returned by BTM_ReadEScoLinkParms() */
+typedef struct
+{
+    uint16_t rx_pkt_len;
+    uint16_t tx_pkt_len;
+    BD_ADDR bd_addr;
+    uint8_t link_type;  /* BTM_LINK_TYPE_SCO or BTM_LINK_TYPE_ESCO */
+    uint8_t tx_interval;
+    uint8_t retrans_window;
+    uint8_t air_mode;
+} tBTM_ESCO_DATA;
+
+typedef struct
+{
+    uint16_t sco_inx;
+    uint16_t rx_pkt_len;
+    uint16_t tx_pkt_len;
+    BD_ADDR bd_addr;
+    uint8_t hci_status;
+    uint8_t tx_interval;
+    uint8_t retrans_window;
+} tBTM_CHG_ESCO_EVT_DATA;
+
+typedef struct
+{
+    uint16_t      sco_inx;
+    BD_ADDR       bd_addr;
+    DEV_CLASS     dev_class;
+    tBTM_SCO_TYPE link_type;
+} tBTM_ESCO_CONN_REQ_EVT_DATA;
+
+typedef union
+{
+    tBTM_CHG_ESCO_EVT_DATA      chg_evt;
+    tBTM_ESCO_CONN_REQ_EVT_DATA conn_evt;
+} tBTM_ESCO_EVT_DATA;
+
+/***************************
+**  eSCO Callback Functions
+****************************/
+typedef void (tBTM_ESCO_CBACK) (tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA *p_data);
+
+
+/*****************************************************************************
+**  SECURITY MANAGEMENT
+*****************************************************************************/
+/*******************************
+**  Security Manager Constants
+********************************/
+
+/* Security Mode (BTM_SetSecurityMode) */
+#define BTM_SEC_MODE_UNDEFINED      0
+#define BTM_SEC_MODE_NONE           1
+#define BTM_SEC_MODE_SERVICE        2
+#define BTM_SEC_MODE_LINK           3
+#define BTM_SEC_MODE_SP             4
+#define BTM_SEC_MODE_SP_DEBUG       5
+#define BTM_SEC_MODE_SC             6
+
+/* Maximum Number of BTM Security Modes */
+#define BTM_SEC_MODES_MAX           7
+
+/* Security Service Levels [bit mask] (BTM_SetSecurityLevel)
+** Encryption should not be used without authentication
+*/
+#define BTM_SEC_NONE               0x0000 /* Nothing required */
+#define BTM_SEC_IN_AUTHORIZE       0x0001 /* Inbound call requires authorization */
+#define BTM_SEC_IN_AUTHENTICATE    0x0002 /* Inbound call requires authentication */
+#define BTM_SEC_IN_ENCRYPT         0x0004 /* Inbound call requires encryption */
+#define BTM_SEC_OUT_AUTHORIZE      0x0008 /* Outbound call requires authorization */
+#define BTM_SEC_OUT_AUTHENTICATE   0x0010 /* Outbound call requires authentication */
+#define BTM_SEC_OUT_ENCRYPT        0x0020 /* Outbound call requires encryption */
+#define BTM_SEC_MODE4_LEVEL4       0x0040 /* Secure Connections Only Mode */
+#define BTM_SEC_FORCE_MASTER       0x0100 /* Need to switch connection to be master */
+#define BTM_SEC_ATTEMPT_MASTER     0x0200 /* Try to switch connection to be master */
+#define BTM_SEC_FORCE_SLAVE        0x0400 /* Need to switch connection to be master */
+#define BTM_SEC_ATTEMPT_SLAVE      0x0800 /* Try to switch connection to be slave */
+#define BTM_SEC_IN_MITM            0x1000 /* inbound Do man in the middle protection */
+#define BTM_SEC_OUT_MITM           0x2000 /* outbound Do man in the middle protection */
+#define BTM_SEC_IN_MIN_16_DIGIT_PIN 0x4000 /* enforce a minimum of 16 digit for sec mode 2 */
+
+/* Security Flags [bit mask] (BTM_GetSecurityFlags)
+*/
+#define BTM_SEC_FLAG_AUTHORIZED     0x01
+#define BTM_SEC_FLAG_AUTHENTICATED  0x02
+#define BTM_SEC_FLAG_ENCRYPTED      0x04
+#define BTM_SEC_FLAG_LKEY_KNOWN     0x10
+#define BTM_SEC_FLAG_LKEY_AUTHED    0x20
+
+/* PIN types */
+#define BTM_PIN_TYPE_VARIABLE       HCI_PIN_TYPE_VARIABLE
+#define BTM_PIN_TYPE_FIXED          HCI_PIN_TYPE_FIXED
+
+/* Link Key types used to generate the new link key.
+** returned in link key notification callback function
+*/
+#define BTM_LKEY_TYPE_COMBINATION   HCI_LKEY_TYPE_COMBINATION
+#define BTM_LKEY_TYPE_LOCAL_UNIT    HCI_LKEY_TYPE_LOCAL_UNIT
+#define BTM_LKEY_TYPE_REMOTE_UNIT   HCI_LKEY_TYPE_REMOTE_UNIT
+#define BTM_LKEY_TYPE_DEBUG_COMB    HCI_LKEY_TYPE_DEBUG_COMB
+#define BTM_LKEY_TYPE_UNAUTH_COMB   HCI_LKEY_TYPE_UNAUTH_COMB
+#define BTM_LKEY_TYPE_AUTH_COMB     HCI_LKEY_TYPE_AUTH_COMB
+#define BTM_LKEY_TYPE_CHANGED_COMB  HCI_LKEY_TYPE_CHANGED_COMB
+
+#define BTM_LKEY_TYPE_UNAUTH_COMB_P_256 HCI_LKEY_TYPE_UNAUTH_COMB_P_256
+#define BTM_LKEY_TYPE_AUTH_COMB_P_256   HCI_LKEY_TYPE_AUTH_COMB_P_256
+
+#define BTM_LTK_DERIVED_LKEY_OFFSET 0x20    /* "easy" requirements for LK derived from LTK */
+#define BTM_LKEY_TYPE_IGNORE        0xff    /* used when event is response from
+                                               hci return link keys request */
+
+typedef uint8_t tBTM_LINK_KEY_TYPE;
+
+/* Protocol level security (BTM_SetSecurityLevel) */
+#define BTM_SEC_PROTO_L2CAP         0
+#define BTM_SEC_PROTO_SDP           1
+#define BTM_SEC_PROTO_TCS           2
+#define BTM_SEC_PROTO_RFCOMM        3
+#define BTM_SEC_PROTO_OBEX          4
+#define BTM_SEC_PROTO_BNEP          5
+#define BTM_SEC_PROTO_HID           6   /* HID      */
+#define BTM_SEC_PROTO_AVDT          7
+#define BTM_SEC_PROTO_MCA           8
+
+/* Determine the number of uint32_t's necessary for security services */
+#define BTM_SEC_ARRAY_BITS          32          /* Number of bits in each array element */
+#define BTM_SEC_SERVICE_ARRAY_SIZE  (((uint32_t)BTM_SEC_MAX_SERVICES / BTM_SEC_ARRAY_BITS) + \
+                                    (((uint32_t)BTM_SEC_MAX_SERVICES % BTM_SEC_ARRAY_BITS) ? 1 : 0))
+
+/* Security service definitions (BTM_SetSecurityLevel)
+** Used for Authorization APIs
+*/
+#define BTM_SEC_SERVICE_SDP_SERVER      0
+#define BTM_SEC_SERVICE_SERIAL_PORT     1
+#define BTM_SEC_SERVICE_LAN_ACCESS      2
+#define BTM_SEC_SERVICE_DUN             3
+#define BTM_SEC_SERVICE_IRMC_SYNC       4
+#define BTM_SEC_SERVICE_IRMC_SYNC_CMD   5
+#define BTM_SEC_SERVICE_OBEX            6
+#define BTM_SEC_SERVICE_OBEX_FTP        7
+#define BTM_SEC_SERVICE_HEADSET         8
+#define BTM_SEC_SERVICE_CORDLESS        9
+#define BTM_SEC_SERVICE_INTERCOM        10
+#define BTM_SEC_SERVICE_FAX             11
+#define BTM_SEC_SERVICE_HEADSET_AG      12
+#define BTM_SEC_SERVICE_PNP_INFO        13
+#define BTM_SEC_SERVICE_GEN_NET         14
+#define BTM_SEC_SERVICE_GEN_FILE        15
+#define BTM_SEC_SERVICE_GEN_AUDIO       16
+#define BTM_SEC_SERVICE_GEN_TEL         17
+#define BTM_SEC_SERVICE_CTP_DATA        18
+#define BTM_SEC_SERVICE_HCRP_CTRL       19
+#define BTM_SEC_SERVICE_HCRP_DATA       20
+#define BTM_SEC_SERVICE_HCRP_NOTIF      21
+#define BTM_SEC_SERVICE_BPP_JOB         22
+#define BTM_SEC_SERVICE_BPP_STATUS      23
+#define BTM_SEC_SERVICE_BPP_REF         24
+#define BTM_SEC_SERVICE_BNEP_PANU       25
+#define BTM_SEC_SERVICE_BNEP_GN         26
+#define BTM_SEC_SERVICE_BNEP_NAP        27
+#define BTM_SEC_SERVICE_HF_HANDSFREE    28
+#define BTM_SEC_SERVICE_AG_HANDSFREE    29
+#define BTM_SEC_SERVICE_TE_PHONE_ACCESS 30
+#define BTM_SEC_SERVICE_ME_PHONE_ACCESS 31
+
+#define BTM_SEC_SERVICE_HIDH_SEC_CTRL   32
+#define BTM_SEC_SERVICE_HIDH_NOSEC_CTRL 33
+#define BTM_SEC_SERVICE_HIDH_INTR       34
+#define BTM_SEC_SERVICE_BIP             35
+#define BTM_SEC_SERVICE_BIP_REF         36
+#define BTM_SEC_SERVICE_AVDTP           37
+#define BTM_SEC_SERVICE_AVDTP_NOSEC     38
+#define BTM_SEC_SERVICE_AVCTP           39
+#define BTM_SEC_SERVICE_SAP             40
+#define BTM_SEC_SERVICE_PBAP            41
+#define BTM_SEC_SERVICE_RFC_MUX         42
+#define BTM_SEC_SERVICE_AVCTP_BROWSE    43
+#define BTM_SEC_SERVICE_MAP             44
+#define BTM_SEC_SERVICE_MAP_NOTIF       45
+#define BTM_SEC_SERVICE_MCAP_CTRL       46
+#define BTM_SEC_SERVICE_MCAP_DATA       47
+#define BTM_SEC_SERVICE_HDP_SNK         48
+#define BTM_SEC_SERVICE_HDP_SRC         49
+#define BTM_SEC_SERVICE_ATT             50
+
+/* Update these as services are added */
+#define BTM_SEC_SERVICE_FIRST_EMPTY     51
+
+#ifndef BTM_SEC_MAX_SERVICES
+#define BTM_SEC_MAX_SERVICES            75
+#endif
+
+/************************************************************************************************
+** Security Services MACROS handle array of uint32_t bits for more than 32 trusted services
+*************************************************************************************************/
+/* MACRO to set the security service bit mask in a bit stream */
+#define BTM_SEC_SET_SERVICE(p, service)  (((uint32_t *)(p))[(((uint32_t)(service)) / BTM_SEC_ARRAY_BITS)] |=  \
+                                    ((uint32_t)1 << (((uint32_t)(service)) % BTM_SEC_ARRAY_BITS)))
+
+
+/* MACRO to clear the security service bit mask in a bit stream */
+#define BTM_SEC_CLR_SERVICE(p, service)  (((uint32_t *)(p))[(((uint32_t)(service)) / BTM_SEC_ARRAY_BITS)] &=  \
+                                    ~((uint32_t)1 << (((uint32_t)(service)) % BTM_SEC_ARRAY_BITS)))
+
+/* MACRO to check the security service bit mask in a bit stream (Returns true or false) */
+#define BTM_SEC_IS_SERVICE_TRUSTED(p, service)    (((((uint32_t *)(p))[(((uint32_t)(service)) / BTM_SEC_ARRAY_BITS)]) &   \
+                                        (uint32_t)(((uint32_t)1 << (((uint32_t)(service)) % BTM_SEC_ARRAY_BITS)))) ? true : false)
+
+/* MACRO to copy two trusted device bitmask */
+#define BTM_SEC_COPY_TRUSTED_DEVICE(p_src, p_dst)   {uint32_t trst; for (trst = 0; trst < BTM_SEC_SERVICE_ARRAY_SIZE; trst++) \
+                                                        ((uint32_t *)(p_dst))[trst] = ((uint32_t *)(p_src))[trst];}
+
+/* MACRO to clear two trusted device bitmask */
+#define BTM_SEC_CLR_TRUSTED_DEVICE(p_dst)   {uint32_t trst; for (trst = 0; trst < BTM_SEC_SERVICE_ARRAY_SIZE; trst++) \
+                                                        ((uint32_t *)(p_dst))[trst] = 0;}
+
+/* Following bits can be provided by host in the trusted_mask array */
+/* 0..31 bits of mask[0] (Least Significant Word) */
+#define BTM_SEC_TRUST_SDP_SERVER        (1 << BTM_SEC_SERVICE_SDP_SERVER)
+#define BTM_SEC_TRUST_SERIAL_PORT       (1 << BTM_SEC_SERVICE_SERIAL_PORT)
+#define BTM_SEC_TRUST_LAN_ACCESS        (1 << BTM_SEC_SERVICE_LAN_ACCESS)
+#define BTM_SEC_TRUST_DUN               (1 << BTM_SEC_SERVICE_DUN)
+#define BTM_SEC_TRUST_IRMC_SYNC         (1 << BTM_SEC_SERVICE_IRMC_SYNC)
+#define BTM_SEC_TRUST_IRMC_SYNC_CMD     (1 << BTM_SEC_SERVICE_IRMC_SYNC_CMD)
+#define BTM_SEC_TRUST_OBEX              (1 << BTM_SEC_SERVICE_OBEX)
+#define BTM_SEC_TRUST_OBEX_FTP          (1 << BTM_SEC_SERVICE_OBEX_FTP)
+#define BTM_SEC_TRUST_HEADSET           (1 << BTM_SEC_SERVICE_HEADSET)
+#define BTM_SEC_TRUST_CORDLESS          (1 << BTM_SEC_SERVICE_CORDLESS)
+#define BTM_SEC_TRUST_INTERCOM          (1 << BTM_SEC_SERVICE_INTERCOM)
+#define BTM_SEC_TRUST_FAX               (1 << BTM_SEC_SERVICE_FAX)
+#define BTM_SEC_TRUST_HEADSET_AG        (1 << BTM_SEC_SERVICE_HEADSET_AG)
+#define BTM_SEC_TRUST_PNP_INFO          (1 << BTM_SEC_SERVICE_PNP_INFO)
+#define BTM_SEC_TRUST_GEN_NET           (1 << BTM_SEC_SERVICE_GEN_NET)
+#define BTM_SEC_TRUST_GEN_FILE          (1 << BTM_SEC_SERVICE_GEN_FILE)
+#define BTM_SEC_TRUST_GEN_AUDIO         (1 << BTM_SEC_SERVICE_GEN_AUDIO)
+#define BTM_SEC_TRUST_GEN_TEL           (1 << BTM_SEC_SERVICE_GEN_TEL)
+#define BTM_SEC_TRUST_CTP_DATA          (1 << BTM_SEC_SERVICE_CTP_DATA)
+#define BTM_SEC_TRUST_HCRP_CTRL         (1 << BTM_SEC_SERVICE_HCRP_CTRL)
+#define BTM_SEC_TRUST_HCRP_DATA         (1 << BTM_SEC_SERVICE_HCRP_DATA)
+#define BTM_SEC_TRUST_HCRP_NOTIF        (1 << BTM_SEC_SERVICE_HCRP_NOTIF)
+#define BTM_SEC_TRUST_BPP_JOB           (1 << BTM_SEC_SERVICE_JOB)
+#define BTM_SEC_TRUST_BPP_STATUS        (1 << BTM_SEC_SERVICE_STATUS)
+#define BTM_SEC_TRUST_BPP_REF           (1 << BTM_SEC_SERVICE_REF)
+#define BTM_SEC_TRUST_BNEP_PANU         (1 << BTM_SEC_SERVICE_BNEP_PANU)
+#define BTM_SEC_TRUST_BNEP_GN           (1 << BTM_SEC_SERVICE_BNEP_GN)
+#define BTM_SEC_TRUST_BNEP_NAP          (1 << BTM_SEC_SERVICE_BNEP_NAP)
+#define BTM_SEC_TRUST_HFP_HF            (1 << BTM_SEC_SERVICE_HF_HANDSFREE)
+#define BTM_SEC_TRUST_HFP_AG            (1 << BTM_SEC_SERVICE_AG_HANDSFREE)
+#define BTM_SEC_TRUST_TE_PHONE_ACCESS   (1 << BTM_SEC_SERVICE_TE_PHONE_ACCESS)
+#define BTM_SEC_TRUST_ME_PHONE_ACCESS   (1 << BTM_SEC_SERVICE_ME_PHONE_ACCESS)
+
+/* 0..31 bits of mask[1] (Most Significant Word) */
+#define BTM_SEC_TRUST_HIDH_CTRL         (1 << (BTM_SEC_SERVICE_HIDH_SEC_CTRL - 32))
+#define BTM_SEC_TRUST_HIDH_NOSEC_CTRL   (1 << (BTM_SEC_SERVICE_HIDH_NOSEC_CTRL - 32))
+#define BTM_SEC_TRUST_HIDH_INTR         (1 << (BTM_SEC_SERVICE_HIDH_INTR - 32))
+#define BTM_SEC_TRUST_BIP               (1 << (BTM_SEC_SERVICE_BIP - 32))
+#define BTM_SEC_TRUST_BIP_REF           (1 << (BTM_SEC_SERVICE_BIP_REF - 32))
+#define BTM_SEC_TRUST_AVDTP             (1 << (BTM_SEC_SERVICE_AVDTP - 32))
+#define BTM_SEC_TRUST_AVDTP_NOSEC       (1 << (BTM_SEC_SERVICE_AVDTP_NOSEC - 32))
+#define BTM_SEC_TRUST_AVCTP             (1 << (BTM_SEC_SERVICE_AVCTP - 32))
+#define BTM_SEC_TRUST_SAP               (1 << (BTM_SEC_SERVICE_SAP - 32))
+#define BTM_SEC_TRUST_PBAP              (1 << (BTM_SEC_SERVICE_PBAP - 32))
+#define BTM_SEC_TRUST_RFC_MUX           (1 << (BTM_SEC_SERVICE_RFC_MUX - 32))
+#define BTM_SEC_TRUST_AVCTP_BROWSE      (1 << (BTM_SEC_SERVICE_AVCTP_BROWSE - 32))
+#define BTM_SEC_TRUST_MAP               (1 << (BTM_SEC_SERVICE_MAP - 32))
+#define BTM_SEC_TRUST_MAP_NOTIF         (1 << (BTM_SEC_SERVICE_MAP_NOTIF - 32))
+#define BTM_SEC_TRUST_MCAP_CTRL         (1 << (BTM_SEC_SERVICE_MCAP_CTRL - 32))
+#define BTM_SEC_TRUST_MCAP_DATA         (1 << (BTM_SEC_SERVICE_MCAP_DATA - 32))
+#define BTM_SEC_TRUST_HDP_SNK           (1 << (BTM_SEC_SERVICE_HDP_SNK - 32))
+#define BTM_SEC_TRUST_HDP_SRC           (1 << (BTM_SEC_SERVICE_HDP_SRC - 32))
+
+#define BTM_SEC_TRUST_ALL               0xFFFFFFFF  /* for each array element */
+
+/****************************************
+**  Security Manager Callback Functions
+*****************************************/
+/* Authorize device for service.  Parameters are
+**              BD Address of remote
+**              Device Class of remote
+**              BD Name of remote
+**              Service name
+**              Service Id (NULL - unknown service or unused
+**                                 [BTM_SEC_SERVICE_NAME_LEN set to 0])
+**              Is originator of the connection
+**              Result of the operation
+*/
+typedef uint8_t (tBTM_AUTHORIZE_CALLBACK) (BD_ADDR bd_addr, DEV_CLASS dev_class,
+                                         tBTM_BD_NAME bd_name, uint8_t *service_name,
+                                         uint8_t service_id, bool    is_originator);
+
+/* Get PIN for the connection.  Parameters are
+**              BD Address of remote
+**              Device Class of remote
+**              BD Name of remote
+**              Flag indicating the minimum pin code length to be 16 digits
+*/
+typedef uint8_t (tBTM_PIN_CALLBACK) (BD_ADDR bd_addr, DEV_CLASS dev_class,
+                                   tBTM_BD_NAME bd_name, bool    min_16_digit);
+
+/* New Link Key for the connection.  Parameters are
+**              BD Address of remote
+**              Link Key
+**              Key Type: Combination, Local Unit, or Remote Unit
+*/
+typedef uint8_t (tBTM_LINK_KEY_CALLBACK) (BD_ADDR bd_addr, DEV_CLASS dev_class,
+                                        tBTM_BD_NAME bd_name, uint8_t *key,
+                                        uint8_t key_type);
+
+
+/* Remote Name Resolved.  Parameters are
+**              BD Address of remote
+**              BD Name of remote
+*/
+typedef void (tBTM_RMT_NAME_CALLBACK) (BD_ADDR bd_addr, DEV_CLASS dc,
+                                       tBTM_BD_NAME bd_name);
+
+
+/* Authentication complete for the connection.  Parameters are
+**              BD Address of remote
+**              Device Class of remote
+**              BD Name of remote
+**
+*/
+typedef uint8_t (tBTM_AUTH_COMPLETE_CALLBACK) (BD_ADDR bd_addr, DEV_CLASS dev_class,
+                                             tBTM_BD_NAME bd_name, int result);
+
+enum
+{
+    BTM_SP_IO_REQ_EVT,      /* received IO_CAPABILITY_REQUEST event */
+    BTM_SP_IO_RSP_EVT,      /* received IO_CAPABILITY_RESPONSE event */
+    BTM_SP_CFM_REQ_EVT,     /* received USER_CONFIRMATION_REQUEST event */
+    BTM_SP_KEY_NOTIF_EVT,   /* received USER_PASSKEY_NOTIFY event */
+    BTM_SP_KEY_REQ_EVT,     /* received USER_PASSKEY_REQUEST event */
+    BTM_SP_KEYPRESS_EVT,    /* received KEYPRESS_NOTIFY event */
+    BTM_SP_LOC_OOB_EVT,     /* received result for READ_LOCAL_OOB_DATA command */
+    BTM_SP_RMT_OOB_EVT,     /* received REMOTE_OOB_DATA_REQUEST event */
+    BTM_SP_COMPLT_EVT,      /* received SIMPLE_PAIRING_COMPLETE event */
+    BTM_SP_UPGRADE_EVT      /* check if the application wants to upgrade the link key */
+};
+typedef uint8_t tBTM_SP_EVT;
+
+#define BTM_IO_CAP_OUT      0   /* DisplayOnly */
+#define BTM_IO_CAP_IO       1   /* DisplayYesNo */
+#define BTM_IO_CAP_IN       2   /* KeyboardOnly */
+#define BTM_IO_CAP_NONE     3   /* NoInputNoOutput */
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+#define BTM_IO_CAP_KBDISP   4   /* Keyboard display */
+#define BTM_IO_CAP_MAX      5
+#else
+#define BTM_IO_CAP_MAX      4
+#endif
+
+typedef uint8_t tBTM_IO_CAP;
+
+#define BTM_MAX_PASSKEY_VAL (999999)
+#define BTM_MIN_PASSKEY_VAL (0)
+
+#define BTM_AUTH_SP_NO      0   /* MITM Protection Not Required - Single Profile/non-bonding
+                                Numeric comparison with automatic accept allowed */
+#define BTM_AUTH_SP_YES     1   /* MITM Protection Required - Single Profile/non-bonding
+                                Use IO Capabilities to determine authentication procedure */
+#define BTM_AUTH_AP_NO      2   /* MITM Protection Not Required - All Profiles/dedicated bonding
+                                Numeric comparison with automatic accept allowed */
+#define BTM_AUTH_AP_YES     3   /* MITM Protection Required - All Profiles/dedicated bonding
+                                Use IO Capabilities to determine authentication procedure */
+#define BTM_AUTH_SPGB_NO    4   /* MITM Protection Not Required - Single Profiles/general bonding
+                                Numeric comparison with automatic accept allowed */
+#define BTM_AUTH_SPGB_YES   5   /* MITM Protection Required - Single Profiles/general bonding
+                                Use IO Capabilities to determine authentication procedure */
+#define BTM_AUTH_DD_BOND    2   /* this bit is ORed to the BTM_AUTH_SP_* when IO exchange for dedicated bonding */
+#define BTM_AUTH_GB_BIT     4   /* the genernal bonding bit */
+#define BTM_AUTH_BONDS      6   /* the general/dedicated bonding bits  */
+#define BTM_AUTH_YN_BIT     1   /* this is the Yes or No bit  */
+
+#define BTM_BLE_INITIATOR_KEY_SIZE 15
+#define BTM_BLE_RESPONDER_KEY_SIZE 15
+#define BTM_BLE_MAX_KEY_SIZE       16
+
+typedef uint8_t tBTM_AUTH_REQ;
+
+enum
+{
+    BTM_OOB_NONE,
+    BTM_OOB_PRESENT,
+    BTM_OOB_UNKNOWN
+};
+typedef uint8_t tBTM_OOB_DATA;
+
+/* data type for BTM_SP_IO_REQ_EVT */
+typedef struct
+{
+    BD_ADDR         bd_addr;        /* peer address */
+    tBTM_IO_CAP     io_cap;         /* local IO capabilities */
+    tBTM_OOB_DATA   oob_data;       /* OOB data present (locally) for the peer device */
+    tBTM_AUTH_REQ   auth_req;       /* Authentication required (for local device) */
+    bool            is_orig;        /* true, if local device initiated the SP process */
+} tBTM_SP_IO_REQ;
+
+/* data type for BTM_SP_IO_RSP_EVT */
+typedef struct
+{
+    BD_ADDR         bd_addr;        /* peer address */
+    tBTM_IO_CAP     io_cap;         /* peer IO capabilities */
+    tBTM_OOB_DATA   oob_data;       /* OOB data present at peer device for the local device */
+    tBTM_AUTH_REQ   auth_req;       /* Authentication required for peer device */
+} tBTM_SP_IO_RSP;
+
+/* data type for BTM_SP_CFM_REQ_EVT */
+typedef struct
+{
+    BD_ADDR         bd_addr;        /* peer address */
+    DEV_CLASS       dev_class;      /* peer CoD */
+    tBTM_BD_NAME    bd_name;        /* peer device name */
+    uint32_t        num_val;        /* the numeric value for comparison. If just_works, do not show this number to UI */
+    bool            just_works;     /* true, if "Just Works" association model */
+    tBTM_AUTH_REQ   loc_auth_req;   /* Authentication required for local device */
+    tBTM_AUTH_REQ   rmt_auth_req;   /* Authentication required for peer device */
+    tBTM_IO_CAP     loc_io_caps;    /* IO Capabilities of the local device */
+    tBTM_IO_CAP     rmt_io_caps;    /* IO Capabilities of the remot device */
+} tBTM_SP_CFM_REQ;
+
+/* data type for BTM_SP_KEY_REQ_EVT */
+typedef struct
+{
+    BD_ADDR         bd_addr;        /* peer address */
+    DEV_CLASS       dev_class;      /* peer CoD */
+    tBTM_BD_NAME    bd_name;        /* peer device name */
+} tBTM_SP_KEY_REQ;
+
+/* data type for BTM_SP_KEY_NOTIF_EVT */
+typedef struct
+{
+    BD_ADDR         bd_addr;        /* peer address */
+    DEV_CLASS       dev_class;      /* peer CoD */
+    tBTM_BD_NAME    bd_name;        /* peer device name */
+    uint32_t        passkey;        /* passkey */
+} tBTM_SP_KEY_NOTIF;
+
+enum
+{
+    BTM_SP_KEY_STARTED,         /* 0 - passkey entry started */
+    BTM_SP_KEY_ENTERED,         /* 1 - passkey digit entered */
+    BTM_SP_KEY_ERASED,          /* 2 - passkey digit erased */
+    BTM_SP_KEY_CLEARED,         /* 3 - passkey cleared */
+    BTM_SP_KEY_COMPLT,          /* 4 - passkey entry completed */
+    BTM_SP_KEY_OUT_OF_RANGE     /* 5 - out of range */
+};
+typedef uint8_t tBTM_SP_KEY_TYPE;
+
+/* data type for BTM_SP_KEYPRESS_EVT */
+typedef struct
+{
+    BD_ADDR             bd_addr;        /* peer address */
+    tBTM_SP_KEY_TYPE   notif_type;
+} tBTM_SP_KEYPRESS;
+
+/* data type for BTM_SP_LOC_OOB_EVT */
+typedef struct
+{
+    tBTM_STATUS     status;         /* */
+    BT_OCTET16      c;              /* Simple Pairing Hash C */
+    BT_OCTET16      r;              /* Simple Pairing Randomnizer R */
+} tBTM_SP_LOC_OOB;
+
+/* data type for BTM_SP_RMT_OOB_EVT */
+typedef struct
+{
+    BD_ADDR         bd_addr;        /* peer address */
+    DEV_CLASS       dev_class;      /* peer CoD */
+    tBTM_BD_NAME    bd_name;        /* peer device name */
+} tBTM_SP_RMT_OOB;
+
+
+/* data type for BTM_SP_COMPLT_EVT */
+typedef struct
+{
+    BD_ADDR         bd_addr;        /* peer address */
+    DEV_CLASS       dev_class;      /* peer CoD */
+    tBTM_BD_NAME    bd_name;        /* peer device name */
+    tBTM_STATUS     status;         /* status of the simple pairing process */
+} tBTM_SP_COMPLT;
+
+/* data type for BTM_SP_UPGRADE_EVT */
+typedef struct
+{
+    BD_ADDR         bd_addr;        /* peer address */
+    bool            upgrade;        /* true, to upgrade the link key */
+} tBTM_SP_UPGRADE;
+
+typedef union
+{
+    tBTM_SP_IO_REQ      io_req;     /* BTM_SP_IO_REQ_EVT      */
+    tBTM_SP_IO_RSP      io_rsp;     /* BTM_SP_IO_RSP_EVT      */
+    tBTM_SP_CFM_REQ     cfm_req;    /* BTM_SP_CFM_REQ_EVT     */
+    tBTM_SP_KEY_NOTIF   key_notif;  /* BTM_SP_KEY_NOTIF_EVT   */
+    tBTM_SP_KEY_REQ     key_req;    /* BTM_SP_KEY_REQ_EVT     */
+    tBTM_SP_KEYPRESS    key_press;  /* BTM_SP_KEYPRESS_EVT    */
+    tBTM_SP_LOC_OOB     loc_oob;    /* BTM_SP_LOC_OOB_EVT     */
+    tBTM_SP_RMT_OOB     rmt_oob;    /* BTM_SP_RMT_OOB_EVT     */
+    tBTM_SP_COMPLT      complt;     /* BTM_SP_COMPLT_EVT      */
+    tBTM_SP_UPGRADE     upgrade;    /* BTM_SP_UPGRADE_EVT      */
+} tBTM_SP_EVT_DATA;
+
+/* Simple Pairing Events.  Called by the stack when Simple Pairing related
+** events occur.
+*/
+typedef uint8_t (tBTM_SP_CALLBACK) (tBTM_SP_EVT event, tBTM_SP_EVT_DATA *p_data);
+
+
+typedef void (tBTM_MKEY_CALLBACK) (BD_ADDR bd_addr, uint8_t status, uint8_t key_flag) ;
+
+/* Encryption enabled/disabled complete: Optionally passed with BTM_SetEncryption.
+** Parameters are
+**              BD Address of remote
+**              optional data passed in by BTM_SetEncryption
+**              tBTM_STATUS - result of the operation
+*/
+typedef void (tBTM_SEC_CBACK) (BD_ADDR bd_addr, tBT_TRANSPORT trasnport,
+                                void *p_ref_data, tBTM_STATUS result);
+
+/* Bond Cancel complete. Parameters are
+**              Result of the cancel operation
+**
+*/
+typedef void (tBTM_BOND_CANCEL_CMPL_CALLBACK) (tBTM_STATUS result);
+
+/* LE related event and data structure
+*/
+#define BTM_LE_IO_REQ_EVT       SMP_IO_CAP_REQ_EVT     /* received IO_CAPABILITY_REQUEST event */
+#define BTM_LE_SEC_REQUEST_EVT  SMP_SEC_REQUEST_EVT    /* security request event */
+#define BTM_LE_KEY_NOTIF_EVT    SMP_PASSKEY_NOTIF_EVT  /* received USER_PASSKEY_NOTIFY event */
+#define BTM_LE_KEY_REQ_EVT      SMP_PASSKEY_REQ_EVT    /* received USER_PASSKEY_REQUEST event */
+#define BTM_LE_OOB_REQ_EVT      SMP_OOB_REQ_EVT        /* OOB data request event */
+#define BTM_LE_NC_REQ_EVT       SMP_NC_REQ_EVT          /* Numeric Comparison request event */
+#define BTM_LE_PR_KEYPR_NOT_EVT SMP_PEER_KEYPR_NOT_EVT /* Peer keypress notification recd event */
+/* SC OOB request event (both local and peer OOB data) can be expected in response */
+#define BTM_LE_SC_OOB_REQ_EVT   SMP_SC_OOB_REQ_EVT
+/* SC OOB local data set is created (as result of SMP_CrLocScOobData(...)) */
+#define BTM_LE_SC_LOC_OOB_EVT   SMP_SC_LOC_OOB_DATA_UP_EVT
+#define BTM_LE_BR_KEYS_REQ_EVT  SMP_BR_KEYS_REQ_EVT     /* SMP over BR keys request event */
+#define BTM_LE_COMPLT_EVT       SMP_COMPLT_EVT         /* SMP complete event */
+#define BTM_LE_LAST_FROM_SMP    BTM_LE_BR_KEYS_REQ_EVT
+#define BTM_LE_KEY_EVT          (BTM_LE_LAST_FROM_SMP + 1) /* KEY update event */
+typedef uint8_t tBTM_LE_EVT;
+
+#define BTM_LE_KEY_NONE           0
+#define BTM_LE_KEY_PENC      SMP_SEC_KEY_TYPE_ENC        /* encryption information of peer device */
+#define BTM_LE_KEY_PID       SMP_SEC_KEY_TYPE_ID         /* identity key of the peer device */
+#define BTM_LE_KEY_PCSRK     SMP_SEC_KEY_TYPE_CSRK      /* peer SRK */
+#define BTM_LE_KEY_PLK       SMP_SEC_KEY_TYPE_LK
+#define BTM_LE_KEY_LLK       (SMP_SEC_KEY_TYPE_LK << 4)
+#define BTM_LE_KEY_LENC      (SMP_SEC_KEY_TYPE_ENC << 4)  /* master role security information:div */
+#define BTM_LE_KEY_LID       (SMP_SEC_KEY_TYPE_ID << 4)   /* master device ID key */
+#define BTM_LE_KEY_LCSRK     (SMP_SEC_KEY_TYPE_CSRK << 4) /* local CSRK has been deliver to peer */
+typedef uint8_t tBTM_LE_KEY_TYPE;
+
+#define BTM_LE_AUTH_REQ_NO_BOND SMP_AUTH_NO_BOND   /* 0 */
+#define BTM_LE_AUTH_REQ_BOND    SMP_AUTH_GEN_BOND  /* 1 << 0 */
+#define BTM_LE_AUTH_REQ_MITM    SMP_AUTH_YN_BIT    /* 1 << 2 */
+typedef uint8_t tBTM_LE_AUTH_REQ;
+#define BTM_LE_SC_SUPPORT_BIT           SMP_SC_SUPPORT_BIT     /* (1 << 3) */
+#define BTM_LE_KP_SUPPORT_BIT           SMP_KP_SUPPORT_BIT     /* (1 << 4) */
+
+#define BTM_LE_AUTH_REQ_SC_ONLY         SMP_AUTH_SC_ENC_ONLY    /* 1 << 3 */
+#define BTM_LE_AUTH_REQ_SC_BOND         SMP_AUTH_SC_GB          /* 1001 */
+#define BTM_LE_AUTH_REQ_SC_MITM         SMP_AUTH_SC_MITM_NB     /* 1100 */
+#define BTM_LE_AUTH_REQ_SC_MITM_BOND    SMP_AUTH_SC_MITM_GB     /* 1101 */
+#define BTM_LE_AUTH_REQ_MASK            SMP_AUTH_MASK           /* 0x1D */
+
+/* LE security level */
+#define BTM_LE_SEC_NONE             SMP_SEC_NONE
+#define BTM_LE_SEC_UNAUTHENTICATE   SMP_SEC_UNAUTHENTICATE      /* 1 */
+#define BTM_LE_SEC_AUTHENTICATED    SMP_SEC_AUTHENTICATED       /* 4 */
+typedef uint8_t tBTM_LE_SEC;
+
+
+typedef struct
+{
+    tBTM_IO_CAP         io_cap;         /* local IO capabilities */
+    uint8_t             oob_data;       /* OOB data present (locally) for the peer device */
+    tBTM_LE_AUTH_REQ    auth_req;       /* Authentication request (for local device) contain bonding and MITM info */
+    uint8_t             max_key_size;   /* max encryption key size */
+    tBTM_LE_KEY_TYPE    init_keys;      /* keys to be distributed, bit mask */
+    tBTM_LE_KEY_TYPE    resp_keys;      /* keys to be distributed, bit mask */
+} tBTM_LE_IO_REQ;
+
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+/* data type for tBTM_LE_COMPLT */
+typedef struct
+{
+    uint8_t reason;
+    uint8_t sec_level;
+    bool    is_pair_cancel;
+    bool    smp_over_br;
+}tBTM_LE_COMPLT;
+#endif
+
+/* BLE encryption keys */
+typedef struct
+{
+    BT_OCTET16  ltk;
+    BT_OCTET8   rand;
+    uint16_t    ediv;
+    uint8_t     sec_level;
+    uint8_t     key_size;
+}tBTM_LE_PENC_KEYS;
+
+/* BLE CSRK keys */
+typedef struct
+{
+    uint32_t        counter;
+    BT_OCTET16      csrk;
+    uint8_t         sec_level;
+}tBTM_LE_PCSRK_KEYS;
+
+/* BLE Encryption reproduction keys */
+typedef struct
+{
+    BT_OCTET16  ltk;
+    uint16_t    div;
+    uint8_t     key_size;
+    uint8_t     sec_level;
+}tBTM_LE_LENC_KEYS;
+
+/* BLE SRK keys */
+typedef struct
+{
+    uint32_t        counter;
+    uint16_t        div;
+    uint8_t         sec_level;
+    BT_OCTET16      csrk;
+}tBTM_LE_LCSRK_KEYS;
+
+typedef struct
+{
+    BT_OCTET16          irk;
+    tBLE_ADDR_TYPE      addr_type;
+    BD_ADDR             static_addr;
+}tBTM_LE_PID_KEYS;
+
+typedef union
+{
+    tBTM_LE_PENC_KEYS   penc_key;       /* received peer encryption key */
+    tBTM_LE_PCSRK_KEYS  pcsrk_key;      /* received peer device SRK */
+    tBTM_LE_PID_KEYS    pid_key;        /* peer device ID key */
+    tBTM_LE_LENC_KEYS   lenc_key;       /* local encryption reproduction keys LTK = = d1(ER,DIV,0)*/
+    tBTM_LE_LCSRK_KEYS   lcsrk_key;     /* local device CSRK = d1(ER,DIV,1)*/
+}tBTM_LE_KEY_VALUE;
+
+typedef struct
+{
+    tBTM_LE_KEY_TYPE        key_type;
+    tBTM_LE_KEY_VALUE       *p_key_value;
+}tBTM_LE_KEY;
+
+typedef union
+{
+    tBTM_LE_IO_REQ      io_req;     /* BTM_LE_IO_REQ_EVT      */
+    uint32_t            key_notif;  /* BTM_LE_KEY_NOTIF_EVT   */
+                                    /* BTM_LE_NC_REQ_EVT */
+                                    /* no callback data for BTM_LE_KEY_REQ_EVT */
+                                    /* and BTM_LE_OOB_REQ_EVT  */
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+    tBTM_LE_COMPLT      complt;     /* BTM_LE_COMPLT_EVT      */
+    tSMP_OOB_DATA_TYPE  req_oob_type;
+#endif
+    tBTM_LE_KEY         key;
+} tBTM_LE_EVT_DATA;
+
+/* Simple Pairing Events.  Called by the stack when Simple Pairing related
+** events occur.
+*/
+typedef uint8_t (tBTM_LE_CALLBACK) (tBTM_LE_EVT event, BD_ADDR bda, tBTM_LE_EVT_DATA *p_data);
+
+#define BTM_BLE_KEY_TYPE_ID         1
+#define BTM_BLE_KEY_TYPE_ER         2
+#define BTM_BLE_KEY_TYPE_COUNTER    3  //tobe obsolete
+
+typedef struct
+{
+    BT_OCTET16       ir;
+    BT_OCTET16       irk;
+    BT_OCTET16       dhk;
+
+}tBTM_BLE_LOCAL_ID_KEYS;
+
+typedef union
+{
+    tBTM_BLE_LOCAL_ID_KEYS  id_keys;
+    BT_OCTET16              er;
+}tBTM_BLE_LOCAL_KEYS;
+
+
+/* New LE identity key for local device.
+*/
+typedef void (tBTM_LE_KEY_CALLBACK) (uint8_t key_type, tBTM_BLE_LOCAL_KEYS *p_key);
+
+
+/***************************
+**  Security Manager Types
+****************************/
+/* Structure that applications use to register with BTM_SecRegister */
+typedef struct
+{
+    tBTM_AUTHORIZE_CALLBACK     *p_authorize_callback;
+    tBTM_PIN_CALLBACK           *p_pin_callback;
+    tBTM_LINK_KEY_CALLBACK      *p_link_key_callback;
+    tBTM_AUTH_COMPLETE_CALLBACK *p_auth_complete_callback;
+    tBTM_BOND_CANCEL_CMPL_CALLBACK *p_bond_cancel_cmpl_callback;
+    tBTM_SP_CALLBACK            *p_sp_callback;
+#if (BLE_INCLUDED == TRUE)
+#if (SMP_INCLUDED == TRUE)
+    tBTM_LE_CALLBACK            *p_le_callback;
+#endif
+    tBTM_LE_KEY_CALLBACK        *p_le_key_callback;
+#endif
+} tBTM_APPL_INFO;
+
+/* Callback function for when a link supervision timeout event occurs.
+** This asynchronous event is enabled/disabled by calling BTM_RegForLstoEvt().
+*/
+typedef void (tBTM_LSTO_CBACK) (BD_ADDR remote_bda, uint16_t timeout);
+
+/*****************************************************************************
+**  POWER MANAGEMENT
+*****************************************************************************/
+/****************************
+**  Power Manager Constants
+*****************************/
+/* BTM Power manager status codes */
+enum
+{
+    BTM_PM_STS_ACTIVE = HCI_MODE_ACTIVE,
+    BTM_PM_STS_HOLD   = HCI_MODE_HOLD,
+    BTM_PM_STS_SNIFF  = HCI_MODE_SNIFF,
+    BTM_PM_STS_PARK   = HCI_MODE_PARK,
+    BTM_PM_STS_SSR,     /* report the SSR parameters in HCI_SNIFF_SUB_RATE_EVT */
+    BTM_PM_STS_PENDING,   /* when waiting for status from controller */
+    BTM_PM_STS_ERROR   /* when HCI command status returns error */
+};
+typedef uint8_t tBTM_PM_STATUS;
+
+/* BTM Power manager modes */
+enum
+{
+    BTM_PM_MD_ACTIVE = BTM_PM_STS_ACTIVE,
+    BTM_PM_MD_HOLD   = BTM_PM_STS_HOLD,
+    BTM_PM_MD_SNIFF  = BTM_PM_STS_SNIFF,
+    BTM_PM_MD_PARK   = BTM_PM_STS_PARK,
+    BTM_PM_MD_FORCE  = 0x10 /* OR this to force ACL link to a certain mode */
+};
+typedef uint8_t tBTM_PM_MODE;
+
+#define BTM_PM_SET_ONLY_ID  0x80
+
+/* Operation codes */
+#define BTM_PM_REG_SET      1 /* The module wants to set the desired power mode */
+#define BTM_PM_REG_NOTIF    2 /* The module wants to receive mode change event */
+#define BTM_PM_DEREG        4 /* The module does not want to involve with PM anymore */
+
+/************************
+**  Power Manager Types
+*************************/
+typedef struct
+{
+    uint16_t        max;
+    uint16_t        min;
+    uint16_t        attempt;
+    uint16_t        timeout;
+    tBTM_PM_MODE    mode;
+} tBTM_PM_PWR_MD;
+
+/*************************************
+**  Power Manager Callback Functions
+**************************************/
+typedef void (tBTM_PM_STATUS_CBACK) (BD_ADDR p_bda, tBTM_PM_STATUS status,
+                                     uint16_t value, uint8_t hci_status);
+
+
+/************************
+**  Stored Linkkey Types
+*************************/
+#define BTM_CB_EVT_DELETE_STORED_LINK_KEYS  4
+
+typedef struct
+{
+    uint8_t        event;
+    uint8_t        status;
+    uint16_t       num_keys;
+
+} tBTM_DELETE_STORED_LINK_KEY_COMPLETE;
+
+/* MIP evnets, callbacks    */
+enum
+{
+    BTM_MIP_MODE_CHG_EVT,
+    BTM_MIP_DISCONNECT_EVT,
+    BTM_MIP_PKTS_COMPL_EVT,
+    BTM_MIP_RXDATA_EVT
+};
+typedef uint8_t tBTM_MIP_EVT;
+
+typedef struct
+{
+    tBTM_MIP_EVT    event;
+    BD_ADDR         bd_addr;
+    uint16_t        mip_id;
+} tBTM_MIP_MODE_CHANGE;
+
+typedef struct
+{
+    tBTM_MIP_EVT    event;
+    uint16_t        mip_id;
+    uint8_t         disc_reason;
+} tBTM_MIP_CONN_TIMEOUT;
+
+#define BTM_MIP_MAX_RX_LEN  17
+
+typedef struct
+{
+    tBTM_MIP_EVT    event;
+    uint16_t        mip_id;
+    uint8_t         rx_len;
+    uint8_t         rx_data[BTM_MIP_MAX_RX_LEN];
+} tBTM_MIP_RXDATA;
+
+typedef struct
+{
+    tBTM_MIP_EVT    event;
+    BD_ADDR         bd_addr;
+    uint8_t         data[11];       /* data[0] shows Vender-specific device type */
+} tBTM_MIP_EIR_HANDSHAKE;
+
+typedef struct
+{
+    tBTM_MIP_EVT    event;
+    uint16_t        num_sent;       /* Number of packets completed at the controller */
+} tBTM_MIP_PKTS_COMPL;
+
+typedef union
+{
+    tBTM_MIP_EVT            event;
+    tBTM_MIP_MODE_CHANGE    mod_chg;
+    tBTM_MIP_CONN_TIMEOUT   conn_tmo;
+    tBTM_MIP_EIR_HANDSHAKE  eir;
+    tBTM_MIP_PKTS_COMPL     completed;
+    tBTM_MIP_RXDATA         rxdata;
+} tBTM_MIP_EVENT_DATA;
+
+/* MIP event callback function  */
+typedef void (tBTM_MIP_EVENTS_CB) (tBTM_MIP_EVT event, tBTM_MIP_EVENT_DATA data);
+
+/* MIP Device query callback function  */
+typedef bool    (tBTM_MIP_QUERY_CB) (BD_ADDR dev_addr, uint8_t *p_mode, LINK_KEY link_key);
+
+#define BTM_CONTRL_ACTIVE  1       /* ACL link on, SCO link ongoing, sniff mode */
+#define BTM_CONTRL_SCAN    2       /* Scan state - paging/inquiry/trying to connect*/
+#define BTM_CONTRL_IDLE    3       /* Idle state - page scan, LE advt, inquiry scan */
+
+typedef uint8_t tBTM_CONTRL_STATE;
+
+#endif // BTM_API_TYPES_H
\ No newline at end of file
diff --git a/bt/stack/include/btm_ble_api.h b/bt/stack/include/btm_ble_api.h
new file mode 100644
index 0000000..38deb46
--- /dev/null
+++ b/bt/stack/include/btm_ble_api.h
@@ -0,0 +1,936 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 Bluetooth Manager (BTM) API function external
+ *  definitions.
+ *
+ ******************************************************************************/
+#ifndef BTM_BLE_API_H
+#define BTM_BLE_API_H
+
+#include "btm_api.h"
+#include "bt_common.h"
+#include "osi/include/alarm.h"
+#include <hardware/bt_common_types.h>
+#include "btm_ble_api_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+tBTM_BLE_SCAN_SETUP_CBACK bta_ble_scan_setup_cb;
+
+/*****************************************************************************
+**  EXTERNAL FUNCTION DECLARATIONS
+*****************************************************************************/
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+extern bool    BTM_SecAddBleDevice (const BD_ADDR 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
+**
+*******************************************************************************/
+extern bool    BTM_SecAddBleKey (BD_ADDR bd_addr, tBTM_LE_KEY_VALUE *p_le_key,
+                                 tBTM_LE_KEY_TYPE key_type);
+
+/*******************************************************************************
+**
+** Function         BTM_BleSetAdvParams
+**
+** Description      This function is called to set advertising parameters.
+**
+** Parameters:       None.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_BleSetAdvParams(uint16_t adv_int_min, uint16_t adv_int_max,
+                                       tBLE_BD_ADDR *p_dir_bda, tBTM_BLE_ADV_CHNL_MAP chnl_map);
+
+/*******************************************************************************
+**
+** Function         BTM_BleWriteAdvData
+**
+** Description      This function is called to write advertising data.
+**
+** Parameters:       None.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void BTM_BleWriteAdvData(uint8_t* data, uint8_t length,
+                                tBTM_BLE_ADV_DATA_CMPL_CBACK *p_adv_data_cback);
+
+/*******************************************************************************
+**
+** Function         BTM_BleSetAdvParams
+**
+** Description      This function is called to set advertising parameters.
+**
+** Parameters       adv_int_min: minimum advertising interval
+**                  adv_int_max: maximum advertising interval
+**                  p_dir_bda: connectable direct initiator's LE device address
+**                  chnl_map: advertising channel map.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void BTM_BleReadAdvParams (uint16_t *adv_int_min, uint16_t *adv_int_max,
+                                  tBLE_BD_ADDR *p_dir_bda, tBTM_BLE_ADV_CHNL_MAP *p_chnl_map);
+
+/*******************************************************************************
+**
+** Function         BTM_BleObtainVendorCapabilities
+**
+** Description      This function is called to obatin vendor capabilties
+**
+** Parameters       p_cmn_vsc_cb - Returns the vednor capabilities
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void BTM_BleObtainVendorCapabilities(tBTM_BLE_VSC_CB *p_cmn_vsc_cb);
+
+/*******************************************************************************
+**
+** Function         BTM_BleSetScanParams
+**
+** Description      This function is called to set Scan parameters.
+**
+** Parameters       client_if - Client IF value
+**                  scan_interval - Scan interval
+**                  scan_window - Scan window
+**                  scan_type - Scan type
+**                  scan_setup_status_cback - Scan setup status callback
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void BTM_BleSetScanParams(tGATT_IF client_if, uint32_t scan_interval,
+                                 uint32_t scan_window, tBLE_SCAN_MODE scan_type,
+                                 tBLE_SCAN_PARAM_SETUP_CBACK scan_setup_status_cback);
+
+/*******************************************************************************
+**
+** Function         BTM_BleGetVendorCapabilities
+**
+** Description      This function reads local LE features
+**
+** Parameters       p_cmn_vsc_cb : Locala LE capability structure
+**
+** Returns          void
+**
+*******************************************************************************/
+extern 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
+                    tBTM_BLE_SCAN_SETUP_CBACK *p_setup_cback - Setup callback
+                    tBTM_BLE_SCAN_THRESHOLD_CBACK *p_thres_cback -Threshold callback
+                    void *p_ref - Reference value
+**
+** Returns          tBTM_STATUS
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_BleSetStorageConfig(uint8_t batch_scan_full_max,
+                                        uint8_t batch_scan_trunc_max,
+                                        uint8_t batch_scan_notify_threshold,
+                                        tBTM_BLE_SCAN_SETUP_CBACK *p_setup_cback,
+                                        tBTM_BLE_SCAN_THRESHOLD_CBACK *p_thres_cback,
+                                        tBTM_BLE_SCAN_REP_CBACK* p_cback,
+                                        tBTM_BLE_REF_VALUE ref_value);
+
+/*******************************************************************************
+**
+** Function         BTM_BleEnableBatchScan
+**
+** Description      This function is called to enable batch scan
+**
+** Parameters       tBTM_BLE_BATCH_SCAN_MODE scan_mode - Batch scan mode
+                    uint32_t scan_interval -Scan interval
+                    uint32_t scan_window - Scan window value
+                    tBLE_ADDR_TYPE addr_type - Address type
+                    tBTM_BLE_DISCARD_RULE discard_rule - Data discard rules
+**
+** Returns          tBTM_STATUS
+**
+*******************************************************************************/
+extern tBTM_STATUS 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,
+                                        tBTM_BLE_REF_VALUE ref_value);
+
+/*******************************************************************************
+**
+** Function         BTM_BleDisableBatchScan
+**
+** Description      This function is called to disable batch scanning
+**
+** Parameters       void
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_BleDisableBatchScan(tBTM_BLE_REF_VALUE ref_value);
+
+/*******************************************************************************
+**
+** Function         BTM_BleReadScanReports
+**
+** Description      This function is called to read batch scan reports
+**
+** Parameters       tBLE_SCAN_MODE scan_mode - Scan mode report to be read out
+                    tBTM_BLE_SCAN_REP_CBACK* p_cback - Reports callback
+**
+** Returns          tBTM_STATUS
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_BleReadScanReports(tBLE_SCAN_MODE scan_mode,
+                                                  tBTM_BLE_REF_VALUE ref_value);
+
+/*******************************************************************************
+**
+** Function         BTM_BleTrackAdvertiser
+**
+** Description      This function is called to read batch scan reports
+**
+** Parameters       p_track_cback - Tracking callback
+**                  ref_value - Reference value
+**
+** Returns          tBTM_STATUS
+**
+*******************************************************************************/
+extern tBTM_STATUS 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_BleObserve(bool    start, uint8_t duration,
+                                  tBTM_INQ_RESULTS_CB *p_results_cb, tBTM_CMPL_CB *p_cmpl_cb);
+
+
+/*******************************************************************************
+**
+** Function         BTM_GetDeviceIDRoot
+**
+** Description      This function is called to read the local device identity
+**                  root.
+**
+** Returns          void
+**                  the local device ER is copied into er
+**
+*******************************************************************************/
+extern void BTM_GetDeviceIDRoot (BT_OCTET16 ir);
+
+/*******************************************************************************
+**
+** Function         BTM_GetDeviceEncRoot
+**
+** Description      This function is called to read the local device encryption
+**                  root.
+**
+** Returns          void
+**                  the local device ER is copied into er
+**
+*******************************************************************************/
+extern void BTM_GetDeviceEncRoot (BT_OCTET16 er);
+
+/*******************************************************************************
+**
+** Function         BTM_GetDeviceDHK
+**
+** Description      This function is called to read the local device DHK.
+**
+** Returns          void
+**                  the local device DHK is copied into dhk
+**
+*******************************************************************************/
+extern void BTM_GetDeviceDHK (BT_OCTET16 dhk);
+
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+extern void BTM_SecurityGrant(BD_ADDR 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)).
+**
+*******************************************************************************/
+extern void BTM_BlePasskeyReply (BD_ADDR 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
+**
+*******************************************************************************/
+extern void BTM_BleConfirmReply (BD_ADDR 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.
+**
+*******************************************************************************/
+extern void BTM_BleOobDataReply(BD_ADDR 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.
+**
+*******************************************************************************/
+extern void BTM_BleSecureConnectionOobDataReply(BD_ADDR 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.
+**
+*******************************************************************************/
+extern bool    BTM_BleDataSignature (BD_ADDR 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.
+**
+*******************************************************************************/
+extern bool    BTM_BleVerifySignature (BD_ADDR bd_addr, uint8_t *p_orig,
+                                       uint16_t len, uint32_t counter,
+                                       uint8_t *p_comp);
+
+/*******************************************************************************
+**
+** Function         BTM_ReadConnectionAddr
+**
+** Description      This function is called to set the local device random address
+**                  .
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void BTM_ReadConnectionAddr (BD_ADDR remote_bda, BD_ADDR local_conn_addr,
+                                            tBLE_ADDR_TYPE *p_addr_type);
+
+
+
+/*******************************************************************************
+**
+** Function         BTM_ReadRemoteConnectionAddr
+**
+** Description      This function is read the remote device address currently used
+**                  .
+**
+** Returns          void
+**
+*******************************************************************************/
+extern bool    BTM_ReadRemoteConnectionAddr(BD_ADDR pseudo_addr,
+                                                    BD_ADDR 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.
+**
+*******************************************************************************/
+extern void BTM_BleLoadLocalKeys(uint8_t key_type, tBTM_BLE_LOCAL_KEYS *p_key);
+
+
+/*******************************************************************************
+**
+** Function         BTM_BleSetBgConnType
+**
+** Description      This function is called to set BLE background connection
+**                  procedure type. It can be auto connection, or selective connection.
+**
+** Parameters       conn_type: it can be auto connection, or selective connection.
+**                  p_select_cback: callback function when selective connection procedure
+**                              is being used.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern bool    BTM_BleSetBgConnType(tBTM_BLE_CONN_TYPE   conn_type,
+                                    tBTM_BLE_SEL_CBACK   *p_select_cback);
+
+/*******************************************************************************
+**
+** Function         BTM_BleUpdateBgConnDev
+**
+** Description      This function is called to add or remove a device into/from
+**                  background connection procedure. The background connection
+*                   procedure is decided by the background connection type, it can be
+*                   auto connection, or selective connection.
+**
+** Parameters       add_remove: true to add; false to remove.
+**                  remote_bda: device address to add/remove.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern bool    BTM_BleUpdateBgConnDev(bool    add_remove, BD_ADDR   remote_bda);
+
+/*******************************************************************************
+**
+** Function         BTM_BleClearBgConnDev
+**
+** Description      This function is called to clear the whitelist,
+**                  end any pending whitelist connections,
+**                  and reset the local bg device list.
+**
+** Parameters       void
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void BTM_BleClearBgConnDev(void);
+
+/********************************************************
+**
+** 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
+**
+*******************************************************************************/
+extern  void BTM_BleSetPrefConnParams (BD_ADDR 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
+**
+*******************************************************************************/
+extern  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
+**
+*******************************************************************************/
+extern void BTM_BleReadControllerFeatures(tBTM_BLE_CTRL_FEATURES_CBACK  *p_vsc_cback);
+
+/*******************************************************************************
+**
+** Function         BTM_CheckAdvData
+**
+** Description      This function is called to get ADV data for a specific type.
+**
+** Parameters       p_adv - pointer of ADV data
+**                  type   - finding ADV data type
+**                  p_length - return the length of ADV data not including type
+**
+** Returns          pointer of ADV data
+**
+*******************************************************************************/
+extern  uint8_t *BTM_CheckAdvData( uint8_t *p_adv, uint8_t type, uint8_t *p_length);
+
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern void BTM_ReadDevInfo (const BD_ADDR 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
+**
+*******************************************************************************/
+extern bool    BTM_ReadConnectedTransportAddress(BD_ADDR 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.
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern void BTM_BleEnableMixedPrivacyMode(bool    mixed_on);
+
+/*******************************************************************************
+**
+** Function          BTM_BleMaxMultiAdvInstanceCount
+**
+** Description        Returns max number of multi adv instances  supported by controller
+**
+** Returns          Max multi adv instance count
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern void BTM_BleTurnOnPrivacyOnRemote(BD_ADDR 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
+*******************************************************************************/
+extern 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      This function is to select the underneath physical link to use.
+**
+** Returns          true to use LE, false use BR/EDR.
+**
+*******************************************************************************/
+extern bool    BTM_UseLeLink (BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function         BTM_BleStackEnable
+**
+** Description      Enable/Disable BLE functionality on stack regarless controller
+**                  capability.
+**
+** Parameters:      enable: true to enable, false to disable.
+**
+** Returns          true if added OK, else false
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern bool    BTM_GetLeSecurityState (BD_ADDR 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.
+**
+*******************************************************************************/
+extern bool    BTM_BleSecurityProcedureIsRunning (BD_ADDR 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.
+**
+*******************************************************************************/
+extern uint8_t BTM_BleGetSupportedKeySize (BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function         BTM_BleAdvFilterParamSetup
+**
+** Description      This function is called to setup the adv data payload filter
+**                  condition.
+**
+** Parameters       p_target: enabble the filter condition on a target device; if NULL
+**                            enable the generic scan condition.
+**                  enable: enable or disable the filter condition
+**
+** Returns          void
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_BleAdvFilterParamSetup(int action,
+                                tBTM_BLE_PF_FILT_INDEX filt_index,
+                                tBTM_BLE_PF_FILT_PARAMS *p_filt_params,
+                                tBLE_BD_ADDR *p_target, tBTM_BLE_PF_PARAM_CBACK *p_cmpl_cback,
+                                tBTM_BLE_REF_VALUE ref_value);
+
+/*******************************************************************************
+**
+** Function         BTM_BleCfgFilterCondition
+**
+** Description      This function is called to configure the adv data payload filter
+**                  condition.
+**
+** Parameters       action: to read/write/clear
+**                  cond_type: filter condition type.
+**                  p_cond: filter condition paramter
+**
+** Returns          tBTM_STATUS
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_BleCfgFilterCondition(tBTM_BLE_SCAN_COND_OP action,
+                                      tBTM_BLE_PF_COND_TYPE cond_type,
+                                      tBTM_BLE_PF_FILT_INDEX filt_index,
+                                      tBTM_BLE_PF_COND_PARAM *p_cond,
+                                      tBTM_BLE_PF_CFG_CBACK *p_cmpl_cback,
+                                      tBTM_BLE_REF_VALUE ref_value);
+
+/*******************************************************************************
+**
+** Function         BTM_BleEnableDisableFilterFeature
+**
+** Description      This function is called to enable or disable the APCF feature
+**
+** Parameters       enable - true - enables the APCF, false - disables the APCF
+**                       ref_value - Ref value
+**
+** Returns          tBTM_STATUS
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_BleEnableDisableFilterFeature(uint8_t enable,
+                                               tBTM_BLE_PF_STATUS_CBACK *p_stat_cback,
+                                               tBTM_BLE_REF_VALUE ref_value);
+
+/*******************************************************************************
+**
+** Function         BTM_BleGetEnergyInfo
+**
+** Description      This function obtains the energy info
+**
+** Parameters       p_ener_cback - Callback pointer
+**
+** Returns          status
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_BleGetEnergyInfo(tBTM_BLE_ENERGY_INFO_CBACK *p_ener_cback);
+
+/*******************************************************************************
+**
+** Function         BTM_SetBleDataLength
+**
+** Description      This function is called to set maximum BLE transmission packet size
+**
+** Returns          BTM_SUCCESS if success; otherwise failed.
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_SetBleDataLength(BD_ADDR bd_addr, uint16_t tx_pdu_length);
+
+extern void btm_ble_multi_adv_cleanup(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bt/stack/include/btm_ble_api_types.h b/bt/stack/include/btm_ble_api_types.h
new file mode 100644
index 0000000..164b73c
--- /dev/null
+++ b/bt/stack/include/btm_ble_api_types.h
@@ -0,0 +1,701 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTM_BLE_API_TYPES_H
+#define BTM_BLE_API_TYPES_H
+
+#include <hardware/bt_common_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CHNL_MAP_LEN    5
+typedef uint8_t tBTM_BLE_CHNL_MAP[CHNL_MAP_LEN];
+
+/* 0x00-0x04 only used for set advertising parameter command */
+#define BTM_BLE_CONNECT_EVT     0x00   /* 0x00-0x04 only used for set advertising
+                                            parameter command */
+#define BTM_BLE_CONNECT_DIR_EVT 0x01   /* Connectable directed advertising */
+#define BTM_BLE_DISCOVER_EVT    0x02  /* Scannable undirected advertising */
+#define BTM_BLE_NON_CONNECT_EVT 0x03  /* Non connectable undirected advertising */
+#define BTM_BLE_CONNECT_LO_DUTY_DIR_EVT 0x04        /* Connectable low duty
+                                                       cycle directed advertising  */
+    /* 0x00 - 0x05 can be received on adv event type */
+#define BTM_BLE_SCAN_RSP_EVT    0x04
+#define BTM_BLE_SCAN_REQ_EVT    0x05
+#define BTM_BLE_UNKNOWN_EVT     0xff
+
+#define BTM_BLE_UNKNOWN_EVT     0xff
+
+typedef uint8_t tBTM_BLE_EVT;
+typedef uint8_t tBTM_BLE_CONN_MODE;
+
+typedef uint32_t tBTM_BLE_REF_VALUE;
+
+#define BTM_BLE_SCAN_MODE_PASS      0
+#define BTM_BLE_SCAN_MODE_ACTI      1
+#define BTM_BLE_SCAN_MODE_NONE      0xff
+typedef uint8_t tBLE_SCAN_MODE;
+
+#define BTM_BLE_BATCH_SCAN_MODE_DISABLE 0
+#define BTM_BLE_BATCH_SCAN_MODE_PASS  1
+#define BTM_BLE_BATCH_SCAN_MODE_ACTI  2
+#define BTM_BLE_BATCH_SCAN_MODE_PASS_ACTI 3
+
+typedef uint8_t tBTM_BLE_BATCH_SCAN_MODE;
+
+/* advertising channel map */
+#define BTM_BLE_ADV_CHNL_37    (0x01 << 0)
+#define BTM_BLE_ADV_CHNL_38    (0x01 << 1)
+#define BTM_BLE_ADV_CHNL_39    (0x01 << 2)
+typedef uint8_t tBTM_BLE_ADV_CHNL_MAP;
+
+/*d efault advertising channel map */
+#ifndef BTM_BLE_DEFAULT_ADV_CHNL_MAP
+#define BTM_BLE_DEFAULT_ADV_CHNL_MAP   (BTM_BLE_ADV_CHNL_37| BTM_BLE_ADV_CHNL_38| BTM_BLE_ADV_CHNL_39)
+#endif
+
+/* advertising filter policy */
+#define AP_SCAN_CONN_ALL           0x00        /* default */
+#define AP_SCAN_WL_CONN_ALL        0x01
+#define AP_SCAN_ALL_CONN_WL        0x02
+#define AP_SCAN_CONN_WL            0x03
+#define AP_SCAN_CONN_POLICY_MAX    0x04
+typedef uint8_t tBTM_BLE_AFP;
+
+/* default advertising filter policy */
+#ifndef BTM_BLE_DEFAULT_AFP
+#define BTM_BLE_DEFAULT_AFP   AP_SCAN_CONN_ALL
+#endif
+
+/* scanning filter policy */
+#define SP_ADV_ALL     0x00     /* 0: accept adv packet from all, directed adv pkt not directed */
+                                /* to local device is ignored */
+#define SP_ADV_WL      0x01     /* 1: accept adv packet from device in white list, directed adv */
+                                /* packet not directed to local device is ignored */
+#define SP_ADV_ALL_RPA_DIR_ADV 0x02  /* 2: accept adv packet from all, directed adv pkt */
+                                     /* not directed to me is ignored except direct adv with RPA */
+#define SP_ADV_WL_RPA_DIR_ADV  0x03  /* 3: accept adv packet from device in white list, directed */
+                                     /* adv pkt not directed to me is ignored except direct adv */
+                                     /* with RPA */
+typedef uint8_t tBTM_BLE_SFP;
+
+#ifndef BTM_BLE_DEFAULT_SFP
+#define BTM_BLE_DEFAULT_SFP   SP_ADV_ALL
+#endif
+
+/* adv parameter boundary values */
+#define BTM_BLE_ADV_INT_MIN            0x0020
+#define BTM_BLE_ADV_INT_MAX            0x4000
+
+/* Full scan boundary values */
+#define BTM_BLE_ADV_SCAN_FULL_MIN      0x00
+#define BTM_BLE_ADV_SCAN_FULL_MAX      0x64
+
+/* Partial scan boundary values */
+#define BTM_BLE_ADV_SCAN_TRUNC_MIN      BTM_BLE_ADV_SCAN_FULL_MIN
+#define BTM_BLE_ADV_SCAN_TRUNC_MAX      BTM_BLE_ADV_SCAN_FULL_MAX
+
+/* Threshold values */
+#define BTM_BLE_ADV_SCAN_THR_MIN        BTM_BLE_ADV_SCAN_FULL_MIN
+#define BTM_BLE_ADV_SCAN_THR_MAX        BTM_BLE_ADV_SCAN_FULL_MAX
+
+/* connection parameter boundary values */
+#define BTM_BLE_SCAN_INT_MIN            0x0004
+#define BTM_BLE_SCAN_INT_MAX            0x4000
+#define BTM_BLE_SCAN_WIN_MIN            0x0004
+#define BTM_BLE_SCAN_WIN_MAX            0x4000
+#define BTM_BLE_EXT_SCAN_INT_MAX        0x00FFFFFF
+#define BTM_BLE_EXT_SCAN_WIN_MAX        0xFFFF
+#define BTM_BLE_CONN_INT_MIN            0x0006
+#define BTM_BLE_CONN_INT_MAX            0x0C80
+#define BTM_BLE_CONN_LATENCY_MAX        500
+#define BTM_BLE_CONN_SUP_TOUT_MIN       0x000A
+#define BTM_BLE_CONN_SUP_TOUT_MAX       0x0C80
+#define BTM_BLE_CONN_PARAM_UNDEF        0xffff      /* use this value when a specific value not to be overwritten */
+#define BTM_BLE_SCAN_PARAM_UNDEF        0xffffffff
+
+/* default connection parameters if not configured, use GAP recommend value for auto/selective connection */
+/* default scan interval */
+#ifndef BTM_BLE_SCAN_FAST_INT
+#define BTM_BLE_SCAN_FAST_INT    96    /* 30 ~ 60 ms (use 60)  = 96 *0.625 */
+#endif
+/* default scan window for background connection, applicable for auto connection or selective conenction */
+#ifndef BTM_BLE_SCAN_FAST_WIN
+#define BTM_BLE_SCAN_FAST_WIN   48      /* 30 ms = 48 *0.625 */
+#endif
+
+/* default scan paramter used in reduced power cycle (background scanning) */
+#ifndef BTM_BLE_SCAN_SLOW_INT_1
+#define BTM_BLE_SCAN_SLOW_INT_1    2048    /* 1.28 s   = 2048 *0.625 */
+#endif
+#ifndef BTM_BLE_SCAN_SLOW_WIN_1
+#define BTM_BLE_SCAN_SLOW_WIN_1   48      /* 30 ms = 48 *0.625 */
+#endif
+
+/* default scan paramter used in reduced power cycle (background scanning) */
+#ifndef BTM_BLE_SCAN_SLOW_INT_2
+#define BTM_BLE_SCAN_SLOW_INT_2    4096    /* 2.56 s   = 4096 *0.625 */
+#endif
+#ifndef BTM_BLE_SCAN_SLOW_WIN_2
+#define BTM_BLE_SCAN_SLOW_WIN_2   36      /* 22.5 ms = 36 *0.625 */
+#endif
+
+/* default connection interval min */
+#ifndef BTM_BLE_CONN_INT_MIN_DEF
+#define BTM_BLE_CONN_INT_MIN_DEF     24      /* recommended min: 30ms  = 24 * 1.25 */
+#endif
+
+/* default connectino interval max */
+#ifndef BTM_BLE_CONN_INT_MAX_DEF
+#define BTM_BLE_CONN_INT_MAX_DEF     40      /* recommended max: 50 ms = 56 * 1.25 */
+#endif
+
+/* default slave latency */
+#ifndef BTM_BLE_CONN_SLAVE_LATENCY_DEF
+#define BTM_BLE_CONN_SLAVE_LATENCY_DEF  0      /* 0 */
+#endif
+
+/* default supervision timeout */
+#ifndef BTM_BLE_CONN_TIMEOUT_DEF
+#define BTM_BLE_CONN_TIMEOUT_DEF    2000
+#endif
+
+/* minimum supervision timeout */
+#ifndef BTM_BLE_CONN_TIMEOUT_MIN_DEF
+#define BTM_BLE_CONN_TIMEOUT_MIN_DEF    100
+#endif
+
+/* minimum acceptable connection interval */
+#ifndef BTM_BLE_CONN_INT_MIN_LIMIT
+#define BTM_BLE_CONN_INT_MIN_LIMIT     0x0009
+#endif
+
+#define BTM_BLE_DIR_CONN_FALLBACK_UNDIR         1
+#define BTM_BLE_DIR_CONN_FALLBACK_NO_ADV        2
+
+#ifndef BTM_BLE_DIR_CONN_FALLBACK
+#define BTM_BLE_DIR_CONN_FALLBACK   BTM_BLE_DIR_CONN_FALLBACK_UNDIR
+#endif
+
+#define BTM_CMAC_TLEN_SIZE          8                   /* 64 bits */
+#define BTM_BLE_AUTH_SIGN_LEN       12                   /* BLE data signature length 8 Bytes + 4 bytes counter*/
+typedef uint8_t BLE_SIGNATURE[BTM_BLE_AUTH_SIGN_LEN];         /* Device address */
+
+#ifndef BTM_BLE_HOST_SUPPORT
+#define BTM_BLE_HOST_SUPPORT        0x01
+#endif
+
+#ifndef BTM_BLE_SIMULTANEOUS_HOST
+#define BTM_BLE_SIMULTANEOUS_HOST   0x01
+#endif
+
+/* Appearance Values Reported with BTM_BLE_AD_TYPE_APPEARANCE */
+#define BTM_BLE_APPEARANCE_UKNOWN                  0x0000
+#define BTM_BLE_APPEARANCE_GENERIC_PHONE           0x0040
+#define BTM_BLE_APPEARANCE_GENERIC_COMPUTER        0x0080
+#define BTM_BLE_APPEARANCE_GENERIC_WATCH           0x00C0
+#define BTM_BLE_APPEARANCE_SPORTS_WATCH            0x00C1
+#define BTM_BLE_APPEARANCE_GENERIC_CLOCK           0x0100
+#define BTM_BLE_APPEARANCE_GENERIC_DISPLAY         0x0140
+#define BTM_BLE_APPEARANCE_GENERIC_REMOTE          0x0180
+#define BTM_BLE_APPEARANCE_GENERIC_EYEGLASSES      0x01C0
+#define BTM_BLE_APPEARANCE_GENERIC_TAG             0x0200
+#define BTM_BLE_APPEARANCE_GENERIC_KEYRING         0x0240
+#define BTM_BLE_APPEARANCE_GENERIC_MEDIA_PLAYER    0x0280
+#define BTM_BLE_APPEARANCE_GENERIC_BARCODE_SCANNER 0x02C0
+#define BTM_BLE_APPEARANCE_GENERIC_THERMOMETER     0x0300
+#define BTM_BLE_APPEARANCE_THERMOMETER_EAR         0x0301
+#define BTM_BLE_APPEARANCE_GENERIC_HEART_RATE      0x0340
+#define BTM_BLE_APPEARANCE_HEART_RATE_BELT         0x0341
+#define BTM_BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE  0x0380
+#define BTM_BLE_APPEARANCE_BLOOD_PRESSURE_ARM      0x0381
+#define BTM_BLE_APPEARANCE_BLOOD_PRESSURE_WRIST    0x0382
+#define BTM_BLE_APPEARANCE_GENERIC_HID             0x03C0
+#define BTM_BLE_APPEARANCE_HID_KEYBOARD            0x03C1
+#define BTM_BLE_APPEARANCE_HID_MOUSE               0x03C2
+#define BTM_BLE_APPEARANCE_HID_JOYSTICK            0x03C3
+#define BTM_BLE_APPEARANCE_HID_GAMEPAD             0x03C4
+#define BTM_BLE_APPEARANCE_HID_DIGITIZER_TABLET    0x03C5
+#define BTM_BLE_APPEARANCE_HID_CARD_READER         0x03C6
+#define BTM_BLE_APPEARANCE_HID_DIGITAL_PEN         0x03C7
+#define BTM_BLE_APPEARANCE_HID_BARCODE_SCANNER     0x03C8
+#define BTM_BLE_APPEARANCE_GENERIC_GLUCOSE         0x0400
+#define BTM_BLE_APPEARANCE_GENERIC_WALKING         0x0440
+#define BTM_BLE_APPEARANCE_WALKING_IN_SHOE         0x0441
+#define BTM_BLE_APPEARANCE_WALKING_ON_SHOE         0x0442
+#define BTM_BLE_APPEARANCE_WALKING_ON_HIP          0x0443
+#define BTM_BLE_APPEARANCE_GENERIC_CYCLING         0x0480
+#define BTM_BLE_APPEARANCE_CYCLING_COMPUTER        0x0481
+#define BTM_BLE_APPEARANCE_CYCLING_SPEED           0x0482
+#define BTM_BLE_APPEARANCE_CYCLING_CADENCE         0x0483
+#define BTM_BLE_APPEARANCE_CYCLING_POWER           0x0484
+#define BTM_BLE_APPEARANCE_CYCLING_SPEED_CADENCE   0x0485
+#define BTM_BLE_APPEARANCE_GENERIC_PULSE_OXIMETER  0x0C40
+#define BTM_BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP 0x0C41
+#define BTM_BLE_APPEARANCE_PULSE_OXIMETER_WRIST    0x0C42
+#define BTM_BLE_APPEARANCE_GENERIC_WEIGHT          0x0C80
+#define BTM_BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS  0x1440
+#define BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION 0x1441
+#define BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_AND_NAV     0x1442
+#define BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD         0x1443
+#define BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD_AND_NAV 0x1444
+
+
+/* Structure returned with Rand/Encrypt complete callback */
+typedef struct
+{
+    uint8_t status;
+    uint8_t param_len;
+    uint16_t opcode;
+    uint8_t param_buf[BT_OCTET16_LEN];
+} tBTM_RAND_ENC;
+
+/* General callback function for notifying an application that a synchronous
+** BTM function is complete. The pointer contains the address of any returned data.
+*/
+typedef void (tBTM_RAND_ENC_CB) (tBTM_RAND_ENC *p1);
+
+#define BTM_BLE_FILTER_TARGET_SCANNER       0x01
+#define BTM_BLE_FILTER_TARGET_ADVR          0x00
+
+#define BTM_BLE_POLICY_BLACK_ALL            0x00    /* relevant to both */
+#define BTM_BLE_POLICY_ALLOW_SCAN           0x01    /* relevant to advertiser */
+#define BTM_BLE_POLICY_ALLOW_CONN           0x02    /* relevant to advertiser */
+#define BTM_BLE_POLICY_WHITE_ALL            0x03    /* relevant to both */
+
+/* ADV data flag bit definition used for BTM_BLE_AD_TYPE_FLAG */
+#define BTM_BLE_LIMIT_DISC_FLAG         (0x01 << 0)
+#define BTM_BLE_GEN_DISC_FLAG           (0x01 << 1)
+#define BTM_BLE_BREDR_NOT_SPT           (0x01 << 2)
+/* 4.1 spec adv flag for simultaneous BR/EDR+LE connection support */
+#define BTM_BLE_DMT_CONTROLLER_SPT      (0x01 << 3)
+#define BTM_BLE_DMT_HOST_SPT            (0x01 << 4)
+#define BTM_BLE_NON_LIMIT_DISC_FLAG     (0x00 )         /* lowest bit unset */
+#define BTM_BLE_ADV_FLAG_MASK           (BTM_BLE_LIMIT_DISC_FLAG | BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG)
+#define BTM_BLE_LIMIT_DISC_MASK         (BTM_BLE_LIMIT_DISC_FLAG )
+
+//TODO(jpawlowski): this should be removed with code that depend on it.
+#define BTM_BLE_AD_BIT_FLAGS           (0x00000001 << 1)
+
+#define BTM_BLE_AD_TYPE_FLAG            HCI_EIR_FLAGS_TYPE                  /* 0x01 */
+#define BTM_BLE_AD_TYPE_16SRV_CMPL      HCI_EIR_COMPLETE_16BITS_UUID_TYPE   /* 0x03 */
+#define BTM_BLE_AD_TYPE_NAME_SHORT      HCI_EIR_SHORTENED_LOCAL_NAME_TYPE       /* 0x08 */
+#define BTM_BLE_AD_TYPE_NAME_CMPL       HCI_EIR_COMPLETE_LOCAL_NAME_TYPE        /* 0x09 */
+
+#define BTM_BLE_AD_TYPE_APPEARANCE      0x19
+
+/*  Security settings used with L2CAP LE COC */
+#define BTM_SEC_LE_LINK_ENCRYPTED           0x01
+#define BTM_SEC_LE_LINK_PAIRED_WITHOUT_MITM 0x02
+#define BTM_SEC_LE_LINK_PAIRED_WITH_MITM    0x04
+
+/*  Min/max Preferred  number of payload octets that the local Controller
+    should include in a single Link Layer Data Channel PDU. */
+#define BTM_BLE_DATA_SIZE_MAX     0x00fb
+#define BTM_BLE_DATA_SIZE_MIN     0x001b
+
+/*  Preferred maximum number of microseconds that the local Controller
+    should use to transmit a single Link Layer Data Channel PDU. */
+#define BTM_BLE_DATA_TX_TIME_MIN     0x0148
+#define BTM_BLE_DATA_TX_TIME_MAX     0x0848
+
+/* adv tx power level */
+#define BTM_BLE_ADV_TX_POWER_MIN        0           /* minimum tx power */
+#define BTM_BLE_ADV_TX_POWER_LOW        1           /* low tx power     */
+#define BTM_BLE_ADV_TX_POWER_MID        2           /* middle tx power  */
+#define BTM_BLE_ADV_TX_POWER_UPPER      3           /* upper tx power   */
+#define BTM_BLE_ADV_TX_POWER_MAX        4           /* maximum tx power */
+typedef uint8_t tBTM_BLE_ADV_TX_POWER;
+
+/* adv tx power in dBm */
+typedef struct
+{
+    uint8_t adv_inst_max;         /* max adv instance supported in controller */
+    uint8_t rpa_offloading;
+    uint16_t tot_scan_results_strg;
+    uint8_t max_irk_list_sz;
+    uint8_t filter_support;
+    uint8_t max_filter;
+    uint8_t energy_support;
+    bool    values_read;
+    uint16_t version_supported;
+    uint16_t total_trackable_advertisers;
+    uint8_t extended_scan_support;
+    uint8_t debug_logging_supported;
+}tBTM_BLE_VSC_CB;
+
+typedef void (tBTM_BLE_ADV_DATA_CMPL_CBACK) (tBTM_STATUS status);
+
+#ifndef BTM_BLE_MULTI_ADV_MAX
+#define BTM_BLE_MULTI_ADV_MAX   16 /* controller returned adv_inst_max should be less
+                                      than this number */
+#endif
+
+typedef uint8_t tGATT_IF;
+
+typedef void (tBTM_BLE_SCAN_THRESHOLD_CBACK)(tBTM_BLE_REF_VALUE ref_value);
+typedef void (tBTM_BLE_SCAN_REP_CBACK)(tBTM_BLE_REF_VALUE ref_value, uint8_t report_format,
+                                       uint8_t num_records, uint16_t total_len,
+                                       uint8_t* p_rep_data, uint8_t status);
+typedef void (tBTM_BLE_SCAN_SETUP_CBACK)(uint8_t evt, tBTM_BLE_REF_VALUE ref_value, uint8_t status);
+
+#ifndef BTM_BLE_BATCH_SCAN_MAX
+#define BTM_BLE_BATCH_SCAN_MAX   5
+#endif
+
+#ifndef BTM_BLE_BATCH_REP_MAIN_Q_SIZE
+#define BTM_BLE_BATCH_REP_MAIN_Q_SIZE  2
+#endif
+
+typedef enum
+{
+    BTM_BLE_SCAN_INVALID_STATE=0,
+    BTM_BLE_SCAN_ENABLE_CALLED=1,
+    BTM_BLE_SCAN_ENABLED_STATE=2,
+    BTM_BLE_SCAN_DISABLE_CALLED=3,
+    BTM_BLE_SCAN_DISABLED_STATE=4
+}tBTM_BLE_BATCH_SCAN_STATE;
+
+enum
+{
+    BTM_BLE_DISCARD_OLD_ITEMS,
+    BTM_BLE_DISCARD_LOWER_RSSI_ITEMS
+};
+typedef uint8_t tBTM_BLE_DISCARD_RULE;
+
+typedef struct
+{
+    uint8_t sub_code[BTM_BLE_BATCH_SCAN_MAX];
+    tBTM_BLE_BATCH_SCAN_STATE cur_state[BTM_BLE_BATCH_SCAN_MAX];
+    tBTM_BLE_REF_VALUE        ref_value[BTM_BLE_BATCH_SCAN_MAX];
+    uint8_t pending_idx;
+    uint8_t next_idx;
+}tBTM_BLE_BATCH_SCAN_OPQ;
+
+typedef struct
+{
+    uint8_t rep_mode[BTM_BLE_BATCH_REP_MAIN_Q_SIZE];
+    tBTM_BLE_REF_VALUE  ref_value[BTM_BLE_BATCH_REP_MAIN_Q_SIZE];
+    uint8_t num_records[BTM_BLE_BATCH_REP_MAIN_Q_SIZE];
+    uint16_t data_len[BTM_BLE_BATCH_REP_MAIN_Q_SIZE];
+    uint8_t *p_data[BTM_BLE_BATCH_REP_MAIN_Q_SIZE];
+    uint8_t pending_idx;
+    uint8_t next_idx;
+}tBTM_BLE_BATCH_SCAN_REP_Q;
+
+typedef struct
+{
+    tBTM_BLE_BATCH_SCAN_STATE      cur_state;
+    tBTM_BLE_BATCH_SCAN_MODE scan_mode;
+    uint32_t                scan_interval;
+    uint32_t                scan_window;
+    tBLE_ADDR_TYPE          addr_type;
+    tBTM_BLE_DISCARD_RULE   discard_rule;
+    tBTM_BLE_BATCH_SCAN_OPQ  op_q;
+    tBTM_BLE_BATCH_SCAN_REP_Q main_rep_q;
+    tBTM_BLE_SCAN_SETUP_CBACK     *p_setup_cback;
+    tBTM_BLE_SCAN_THRESHOLD_CBACK *p_thres_cback;
+    tBTM_BLE_SCAN_REP_CBACK       *p_scan_rep_cback;
+    tBTM_BLE_REF_VALUE             ref_value;
+}tBTM_BLE_BATCH_SCAN_CB;
+
+/* filter selection bit index  */
+#define BTM_BLE_PF_ADDR_FILTER          0
+#define BTM_BLE_PF_SRVC_DATA            1
+#define BTM_BLE_PF_SRVC_UUID            2
+#define BTM_BLE_PF_SRVC_SOL_UUID        3
+#define BTM_BLE_PF_LOCAL_NAME           4
+#define BTM_BLE_PF_MANU_DATA            5
+#define BTM_BLE_PF_SRVC_DATA_PATTERN    6
+#define BTM_BLE_PF_TYPE_ALL             7  /* when passed in payload filter type all, only clear action is applicable */
+#define BTM_BLE_PF_TYPE_MAX             8
+
+/* max number of filter spot for different filter type */
+#ifndef BTM_BLE_MAX_UUID_FILTER
+#define BTM_BLE_MAX_UUID_FILTER     8
+#endif
+#ifndef BTM_BLE_MAX_ADDR_FILTER
+#define BTM_BLE_MAX_ADDR_FILTER     8
+#endif
+#ifndef BTM_BLE_PF_STR_COND_MAX
+#define BTM_BLE_PF_STR_COND_MAX     4   /* apply to manu data , or local name */
+#endif
+#ifndef BTM_BLE_PF_STR_LEN_MAX
+#define BTM_BLE_PF_STR_LEN_MAX      29  /* match for first 29 bytes */
+#endif
+
+typedef uint8_t tBTM_BLE_PF_COND_TYPE;
+
+#define BTM_BLE_PF_LOGIC_OR              0
+#define BTM_BLE_PF_LOGIC_AND             1
+typedef uint8_t tBTM_BLE_PF_LOGIC_TYPE;
+
+#define BTM_BLE_PF_ENABLE       1
+#define BTM_BLE_PF_CONFIG       2
+typedef uint8_t tBTM_BLE_PF_ACTION;
+
+typedef uint8_t tBTM_BLE_PF_FILT_INDEX;
+
+typedef uint8_t tBTM_BLE_PF_AVBL_SPACE;
+
+#define BTM_BLE_PF_BRDCAST_ADDR_FILT  1
+#define BTM_BLE_PF_SERV_DATA_CHG_FILT 2
+#define BTM_BLE_PF_SERV_UUID          4
+#define BTM_BLE_PF_SERV_SOLC_UUID     8
+#define BTM_BLE_PF_LOC_NAME_CHECK    16
+#define BTM_BLE_PF_MANUF_NAME_CHECK  32
+#define BTM_BLE_PF_SERV_DATA_CHECK   64
+typedef uint16_t tBTM_BLE_PF_FEAT_SEL;
+
+#define BTM_BLE_PF_LIST_LOGIC_OR   1
+#define BTM_BLE_PF_LIST_LOGIC_AND  2
+typedef uint16_t tBTM_BLE_PF_LIST_LOGIC_TYPE;
+
+#define BTM_BLE_PF_FILT_LOGIC_OR   0
+#define BTM_BLE_PF_FILT_LOGIC_AND  1
+typedef uint16_t tBTM_BLE_PF_FILT_LOGIC_TYPE;
+
+typedef uint8_t tBTM_BLE_PF_RSSI_THRESHOLD;
+typedef uint8_t tBTM_BLE_PF_DELIVERY_MODE;
+typedef uint16_t tBTM_BLE_PF_TIMEOUT;
+typedef uint8_t tBTM_BLE_PF_TIMEOUT_CNT;
+typedef uint16_t tBTM_BLE_PF_ADV_TRACK_ENTRIES;
+
+typedef struct
+{
+    tBTM_BLE_PF_FEAT_SEL feat_seln;
+    tBTM_BLE_PF_LIST_LOGIC_TYPE logic_type;
+    tBTM_BLE_PF_FILT_LOGIC_TYPE filt_logic_type;
+    tBTM_BLE_PF_RSSI_THRESHOLD  rssi_high_thres;
+    tBTM_BLE_PF_RSSI_THRESHOLD  rssi_low_thres;
+    tBTM_BLE_PF_DELIVERY_MODE dely_mode;
+    tBTM_BLE_PF_TIMEOUT found_timeout;
+    tBTM_BLE_PF_TIMEOUT lost_timeout;
+    tBTM_BLE_PF_TIMEOUT_CNT found_timeout_cnt;
+    tBTM_BLE_PF_ADV_TRACK_ENTRIES num_of_tracking_entries;
+}tBTM_BLE_PF_FILT_PARAMS;
+
+enum
+{
+    BTM_BLE_SCAN_COND_ADD,
+    BTM_BLE_SCAN_COND_DELETE,
+    BTM_BLE_SCAN_COND_CLEAR = 2
+};
+typedef uint8_t tBTM_BLE_SCAN_COND_OP;
+
+enum
+{
+    BTM_BLE_FILT_ENABLE_DISABLE = 1,
+    BTM_BLE_FILT_CFG            = 2,
+    BTM_BLE_FILT_ADV_PARAM      = 3
+};
+
+typedef uint8_t tBTM_BLE_FILT_CB_EVT;
+
+/* BLE adv payload filtering config complete callback */
+typedef void (tBTM_BLE_PF_CFG_CBACK)(tBTM_BLE_PF_ACTION action, tBTM_BLE_SCAN_COND_OP cfg_op,
+                                     tBTM_BLE_PF_AVBL_SPACE avbl_space, tBTM_STATUS status,
+                                     tBTM_BLE_REF_VALUE ref_value);
+
+typedef void (tBTM_BLE_PF_CMPL_CBACK) (tBTM_BLE_PF_CFG_CBACK);
+
+/* BLE adv payload filtering status setup complete callback */
+typedef void (tBTM_BLE_PF_STATUS_CBACK) (uint8_t action, tBTM_STATUS status,
+                                        tBTM_BLE_REF_VALUE ref_value);
+
+/* BLE adv payload filtering param setup complete callback */
+typedef void (tBTM_BLE_PF_PARAM_CBACK) (tBTM_BLE_PF_ACTION action_type,
+                                        tBTM_BLE_PF_AVBL_SPACE avbl_space,
+                                        tBTM_BLE_REF_VALUE ref_value, tBTM_STATUS status);
+
+typedef union
+{
+      uint16_t            uuid16_mask;
+      uint32_t            uuid32_mask;
+      uint8_t             uuid128_mask[LEN_UUID_128];
+}tBTM_BLE_PF_COND_MASK;
+
+typedef struct
+{
+    tBLE_BD_ADDR            *p_target_addr;     /* target address, if NULL, generic UUID filter */
+    tBT_UUID                uuid;           /* UUID condition */
+    tBTM_BLE_PF_LOGIC_TYPE  cond_logic;    /* AND/OR */
+    tBTM_BLE_PF_COND_MASK   *p_uuid_mask;           /* UUID mask */
+}tBTM_BLE_PF_UUID_COND;
+
+typedef struct
+{
+    uint8_t                 data_len;       /* <= 20 bytes */
+    uint8_t                 *p_data;
+}tBTM_BLE_PF_LOCAL_NAME_COND;
+
+typedef struct
+{
+    uint16_t                company_id;     /* company ID */
+    uint8_t                 data_len;       /* <= 20 bytes */
+    uint8_t                 *p_pattern;
+    uint16_t                company_id_mask; /* UUID value mask */
+    uint8_t                 *p_pattern_mask; /* Manufacturer data matching mask,
+                                                same length as data pattern,
+                                                set to all 0xff, match exact data */
+}tBTM_BLE_PF_MANU_COND;
+
+typedef struct
+{
+    uint16_t                uuid;     /* service ID */
+    uint8_t                 data_len;       /* <= 20 bytes */
+    uint8_t                 *p_pattern;
+    uint8_t                 *p_pattern_mask; /* Service data matching mask, same length as data pattern,
+                                                set to all 0xff, match exact data */
+}tBTM_BLE_PF_SRVC_PATTERN_COND;
+
+
+typedef union
+{
+    tBLE_BD_ADDR                            target_addr;
+    tBTM_BLE_PF_LOCAL_NAME_COND             local_name; /* lcoal name filtering */
+    tBTM_BLE_PF_MANU_COND                   manu_data;  /* manufactuer data filtering */
+    tBTM_BLE_PF_UUID_COND                   srvc_uuid;  /* service UUID filtering */
+    tBTM_BLE_PF_UUID_COND                   solicitate_uuid;   /* solicitated service UUID filtering */
+    tBTM_BLE_PF_SRVC_PATTERN_COND           srvc_data;      /* service data pattern */
+}tBTM_BLE_PF_COND_PARAM;
+
+typedef struct
+{
+    uint8_t action_ocf[BTM_BLE_PF_TYPE_MAX];
+    tBTM_BLE_REF_VALUE  ref_value[BTM_BLE_PF_TYPE_MAX];
+    tBTM_BLE_PF_PARAM_CBACK  *p_filt_param_cback[BTM_BLE_PF_TYPE_MAX];
+    tBTM_BLE_PF_CFG_CBACK *p_scan_cfg_cback[BTM_BLE_PF_TYPE_MAX];
+    uint8_t cb_evt[BTM_BLE_PF_TYPE_MAX];
+    uint8_t pending_idx;
+    uint8_t next_idx;
+}tBTM_BLE_ADV_FILTER_ADV_OPQ;
+
+#define BTM_BLE_MAX_FILTER_COUNTER  (BTM_BLE_MAX_ADDR_FILTER + 1) /* per device filter + one generic filter indexed by 0 */
+
+#ifndef BTM_CS_IRK_LIST_MAX
+#define BTM_CS_IRK_LIST_MAX 0x20
+#endif
+
+typedef struct
+{
+    bool       in_use;
+    BD_ADDR    bd_addr;
+    uint8_t    pf_counter[BTM_BLE_PF_TYPE_MAX]; /* number of filter indexed by tBTM_BLE_PF_COND_TYPE */
+}tBTM_BLE_PF_COUNT;
+
+typedef struct
+{
+    bool                enable;
+    uint8_t             op_type;
+    tBTM_BLE_PF_COUNT   *p_addr_filter_count; /* per BDA filter array */
+    tBLE_BD_ADDR        cur_filter_target;
+    tBTM_BLE_PF_STATUS_CBACK *p_filt_stat_cback;
+    tBTM_BLE_ADV_FILTER_ADV_OPQ  op_q;
+}tBTM_BLE_ADV_FILTER_CB;
+
+/* Sub codes */
+#define BTM_BLE_META_PF_ENABLE          0x00
+#define BTM_BLE_META_PF_FEAT_SEL        0x01
+#define BTM_BLE_META_PF_ADDR            0x02
+#define BTM_BLE_META_PF_UUID            0x03
+#define BTM_BLE_META_PF_SOL_UUID        0x04
+#define BTM_BLE_META_PF_LOCAL_NAME      0x05
+#define BTM_BLE_META_PF_MANU_DATA       0x06
+#define BTM_BLE_META_PF_SRVC_DATA       0x07
+#define BTM_BLE_META_PF_ALL             0x08
+
+typedef uint8_t BTM_BLE_ADV_STATE;
+typedef uint8_t BTM_BLE_ADV_INFO_PRESENT;
+typedef uint8_t BTM_BLE_RSSI_VALUE;
+typedef uint16_t BTM_BLE_ADV_INFO_TIMESTAMP;
+
+enum
+{
+    BTM_BLE_CONN_NONE,
+    BTM_BLE_CONN_AUTO,
+    BTM_BLE_CONN_SELECTIVE
+};
+typedef uint8_t tBTM_BLE_CONN_TYPE;
+
+#define ADV_INFO_PRESENT        0x00
+#define NO_ADV_INFO_PRESENT     0x01
+
+typedef btgatt_track_adv_info_t tBTM_BLE_TRACK_ADV_DATA;
+
+typedef void (tBTM_BLE_TRACK_ADV_CBACK)(tBTM_BLE_TRACK_ADV_DATA *p_track_adv_data);
+
+typedef uint8_t tBTM_BLE_TRACK_ADV_EVT;
+
+typedef struct
+{
+    tBTM_BLE_REF_VALUE             ref_value;
+    tBTM_BLE_TRACK_ADV_CBACK *p_track_cback;
+}tBTM_BLE_ADV_TRACK_CB;
+
+enum
+{
+    BTM_BLE_TRACK_ADV_ADD,
+    BTM_BLE_TRACK_ADV_REMOVE
+};
+
+typedef uint8_t tBTM_BLE_TRACK_ADV_ACTION;
+
+#define BTM_BLE_BATCH_SCAN_ENABLE_EVT     1
+#define BTM_BLE_BATCH_SCAN_CFG_STRG_EVT   2
+#define BTM_BLE_BATCH_SCAN_READ_REPTS_EVT 3
+#define BTM_BLE_BATCH_SCAN_THR_EVT        4
+#define BTM_BLE_BATCH_SCAN_PARAM_EVT      5
+#define BTM_BLE_BATCH_SCAN_DISABLE_EVT    6
+
+typedef uint8_t tBTM_BLE_BATCH_SCAN_EVT;
+
+typedef uint32_t tBTM_BLE_TX_TIME_MS;
+typedef uint32_t tBTM_BLE_RX_TIME_MS;
+typedef uint32_t tBTM_BLE_IDLE_TIME_MS;
+typedef uint32_t tBTM_BLE_ENERGY_USED;
+
+typedef void (tBTM_BLE_ENERGY_INFO_CBACK)(tBTM_BLE_TX_TIME_MS tx_time, tBTM_BLE_RX_TIME_MS rx_time,
+                                          tBTM_BLE_IDLE_TIME_MS idle_time,
+                                          tBTM_BLE_ENERGY_USED  energy_used,
+                                          tBTM_STATUS status);
+
+typedef struct
+{
+    tBTM_BLE_ENERGY_INFO_CBACK *p_ener_cback;
+}tBTM_BLE_ENERGY_INFO_CB;
+
+typedef bool    (tBTM_BLE_SEL_CBACK)(BD_ADDR random_bda,     uint8_t *p_remote_name);
+typedef void (tBTM_BLE_CTRL_FEATURES_CBACK)(tBTM_STATUS status);
+
+/* callback function for SMP signing algorithm, signed data in little endian order with tlen bits long */
+typedef void (tBTM_BLE_SIGN_CBACK)(void *p_ref_data, uint8_t *p_signing_data);
+typedef void (tBTM_BLE_VERIFY_CBACK)(void *p_ref_data, bool    match);
+/* random address set complete callback */
+typedef void (tBTM_BLE_RANDOM_SET_CBACK) (BD_ADDR random_bda);
+
+typedef void (tBTM_BLE_SCAN_REQ_CBACK)(BD_ADDR remote_bda, tBLE_ADDR_TYPE addr_type, uint8_t adv_evt);
+typedef void (*tBLE_SCAN_PARAM_SETUP_CBACK)(tGATT_IF client_if, tBTM_STATUS status);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BTM_BLE_API_TYPES_H
diff --git a/bt/stack/include/btu.h b/bt/stack/include/btu.h
new file mode 100644
index 0000000..dc53b83
--- /dev/null
+++ b/bt/stack/include/btu.h
@@ -0,0 +1,89 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 main Bluetooth Upper Layer definitions. The Broadcom
+ *  implementations of L2CAP RFCOMM, SDP and the BTIf run as one GKI task. The
+ *  btu_task switches between them.
+ *
+ ******************************************************************************/
+
+#ifndef BTU_H
+#define BTU_H
+
+#include "bt_target.h"
+#include "bt_common.h"
+#include "osi/include/alarm.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// HACK(zachoverflow): temporary dark magic
+#define BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK 0x1700 // didn't look used in bt_types...here goes nothing
+typedef struct {
+  void (*callback)(BT_HDR *);
+} post_to_task_hack_t;
+
+typedef struct {
+  void (*callback)(BT_HDR *);
+  BT_HDR *response;
+  void *context;
+} command_complete_hack_t;
+
+typedef struct {
+  void (*callback)(BT_HDR *);
+  uint8_t status;
+  BT_HDR *command;
+  void *context;
+} command_status_hack_t;
+
+/* Global BTU data */
+extern uint8_t btu_trace_level;
+
+extern const BD_ADDR        BT_BD_ANY;
+
+/* Functions provided by btu_task.cc
+************************************
+*/
+
+#if (HCILP_INCLUDED == TRUE)
+extern void btu_check_bt_sleep (void);
+#endif
+
+/* Functions provided by btu_hcif.cc
+************************************
+*/
+extern void  btu_hcif_process_event (uint8_t controller_id, BT_HDR *p_buf);
+extern void  btu_hcif_send_cmd (uint8_t controller_id, BT_HDR *p_msg);
+
+/* Functions provided by btu_init.cc
+************************************
+*/
+extern void  btu_init_core(void);
+extern void  btu_free_core(void);
+
+void BTU_StartUp(void);
+void BTU_ShutDown(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bt/stack/include/gap_api.h b/bt/stack/include/gap_api.h
new file mode 100644
index 0000000..22087b7
--- /dev/null
+++ b/bt/stack/include/gap_api.h
@@ -0,0 +1,389 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+
+#ifndef GAP_API_H
+#define GAP_API_H
+
+#include "profiles_api.h"
+#include "btm_api.h"
+#include "l2c_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+/*** GAP Error and Status Codes ***/
+#define GAP_UNSUPPORTED     (GAP_ERR_GRP + 0x01)    /* Unsupported call */
+#define GAP_EOINQDB         (GAP_ERR_GRP + 0x02)    /* End of inquiry database marker */
+#define GAP_ERR_BUSY        (GAP_ERR_GRP + 0x03)    /* The requested function was busy */
+#define GAP_ERR_NO_CTRL_BLK (GAP_ERR_GRP + 0x04)    /* No control blocks available */
+#define GAP_ERR_STARTING_CMD (GAP_ERR_GRP + 0x05)   /* Error occurred while initiating the command */
+#define GAP_NO_BDADDR_REC   (GAP_ERR_GRP + 0x06)    /* No Inquiry DB record for BD_ADDR */
+#define GAP_ERR_ILL_MODE    (GAP_ERR_GRP + 0x07)    /* An illegal mode parameter was detected */
+#define GAP_ERR_ILL_INQ_TIME (GAP_ERR_GRP + 0x08)   /* An illegal time parameter was detected */
+#define GAP_ERR_ILL_PARM     (GAP_ERR_GRP + 0x09)   /* An illegal parameter was detected */
+#define GAP_ERR_REM_NAME    (GAP_ERR_GRP + 0x0a)    /* Error starting the remote device name request */
+#define GAP_CMD_INITIATED   (GAP_ERR_GRP + 0x0b)    /* The GAP command was started (result pending) */
+#define GAP_DEVICE_NOT_UP   (GAP_ERR_GRP + 0x0c)    /* The device was not up; the request was not executed */
+#define GAP_BAD_BD_ADDR     (GAP_ERR_GRP + 0x0d)    /* The bd addr passed in was not found or invalid */
+
+#define GAP_ERR_BAD_HANDLE  (GAP_ERR_GRP + 0x0e)    /* Bad GAP handle                       */
+#define GAP_ERR_BUF_OFFSET  (GAP_ERR_GRP + 0x0f)    /* Buffer offset invalid                */
+#define GAP_ERR_BAD_STATE   (GAP_ERR_GRP + 0x10)    /* Connection is in invalid state       */
+#define GAP_NO_DATA_AVAIL   (GAP_ERR_GRP + 0x11)    /* No data available                    */
+#define GAP_ERR_CONGESTED   (GAP_ERR_GRP + 0x12)    /* BT stack is congested                */
+#define GAP_ERR_SECURITY    (GAP_ERR_GRP + 0x13)    /* Security failed                      */
+
+#define GAP_ERR_PROCESSING  (GAP_ERR_GRP + 0x14)    /* General error processing BTM request */
+#define GAP_ERR_TIMEOUT     (GAP_ERR_GRP + 0x15)    /* Timeout occurred while processing cmd */
+#define GAP_EVT_CONN_OPENED         0x0100
+#define GAP_EVT_CONN_CLOSED         0x0101
+#define GAP_EVT_CONN_DATA_AVAIL     0x0102
+#define GAP_EVT_CONN_CONGESTED      0x0103
+#define GAP_EVT_CONN_UNCONGESTED    0x0104
+#define GAP_EVT_TX_EMPTY            0x0105
+
+/* Values for 'chan_mode_mask' field */
+/* GAP_ConnOpen() - optional channels to negotiate */
+#define GAP_FCR_CHAN_OPT_BASIC      L2CAP_FCR_CHAN_OPT_BASIC
+#define GAP_FCR_CHAN_OPT_ERTM       L2CAP_FCR_CHAN_OPT_ERTM
+#define GAP_FCR_CHAN_OPT_STREAM     L2CAP_FCR_CHAN_OPT_STREAM
+/*** used in connection variables and functions ***/
+#define GAP_INVALID_HANDLE      0xFFFF
+
+/* This is used to change the criteria for AMP  */
+#define GAP_PROTOCOL_ID         (UUID_PROTOCOL_UDP)
+
+
+#ifndef  GAP_PREFER_CONN_INT_MAX
+#define  GAP_PREFER_CONN_INT_MAX         BTM_BLE_CONN_INT_MIN
+#endif
+
+#ifndef  GAP_PREFER_CONN_INT_MIN
+#define  GAP_PREFER_CONN_INT_MIN         BTM_BLE_CONN_INT_MIN
+#endif
+
+#ifndef  GAP_PREFER_CONN_LATENCY
+#define  GAP_PREFER_CONN_LATENCY         0
+#endif
+
+#ifndef  GAP_PREFER_CONN_SP_TOUT
+#define  GAP_PREFER_CONN_SP_TOUT         2000
+#endif
+
+/*****************************************************************************
+**  Type Definitions
+*****************************************************************************/
+/*
+** Callback function for connection services
+*/
+typedef void (tGAP_CONN_CALLBACK) (uint16_t gap_handle, uint16_t event);
+
+/*
+** Define the callback function prototypes.  Parameters are specific
+** to each event and are described below
+*/
+typedef void (tGAP_CALLBACK) (uint16_t event, void *p_data);
+
+
+/* Definition of the GAP_FindAddrByName results structure */
+typedef struct
+{
+    uint16_t     status;
+    BD_ADDR      bd_addr;
+    tBTM_BD_NAME devname;
+} tGAP_FINDADDR_RESULTS;
+
+typedef struct
+{
+    uint16_t    int_min;
+    uint16_t    int_max;
+    uint16_t    latency;
+    uint16_t    sp_tout;
+}tGAP_BLE_PREF_PARAM;
+
+typedef union
+{
+    tGAP_BLE_PREF_PARAM     conn_param;
+    BD_ADDR                 reconn_bda;
+    uint16_t                icon;
+    uint8_t                 *p_dev_name;
+    uint8_t                 addr_resolution;
+
+}tGAP_BLE_ATTR_VALUE;
+
+typedef void (tGAP_BLE_CMPL_CBACK)(bool    status, BD_ADDR addr, uint16_t length, char *p_name);
+
+
+/*****************************************************************************
+**  External Function Declarations
+*****************************************************************************/
+
+/*** Functions for L2CAP connection interface ***/
+
+/*******************************************************************************
+**
+** Function         GAP_ConnOpen
+**
+** Description      This function is called to open a generic L2CAP connection.
+**
+** Returns          handle of the connection if successful, else GAP_INVALID_HANDLE
+**
+*******************************************************************************/
+extern uint16_t GAP_ConnOpen(const char *p_serv_name, uint8_t service_id, bool is_server,
+                                    BD_ADDR p_rem_bda, uint16_t psm, tL2CAP_CFG_INFO *p_cfg,
+                                    tL2CAP_ERTM_INFO *ertm_info,
+                                    uint16_t security, uint8_t chan_mode_mask,
+                                    tGAP_CONN_CALLBACK *p_cb, tBT_TRANSPORT transport);
+
+/*******************************************************************************
+**
+** Function         GAP_ConnClose
+**
+** Description      This function is called to close a connection.
+**
+** Returns          BT_PASS             - closed OK
+**                  GAP_ERR_BAD_HANDLE  - invalid handle
+**
+*******************************************************************************/
+extern uint16_t GAP_ConnClose (uint16_t gap_handle);
+
+/*******************************************************************************
+**
+** Function         GAP_ConnReadData
+**
+** Description      GKI buffer unaware application will call this function
+**                  after receiving GAP_EVT_RXDATA event. A data copy is made
+**                  into the receive buffer parameter.
+**
+** Returns          BT_PASS             - data read
+**                  GAP_ERR_BAD_HANDLE  - invalid handle
+**                  GAP_NO_DATA_AVAIL   - no data available
+**
+*******************************************************************************/
+extern uint16_t GAP_ConnReadData (uint16_t gap_handle, uint8_t *p_data,
+                                        uint16_t max_len, uint16_t *p_len);
+
+/*******************************************************************************
+**
+** Function         GAP_GetRxQueueCnt
+**
+** Description      This function return number of bytes on the rx queue.
+**
+** Parameters:      handle     - Handle returned in the GAP_ConnOpen
+**                  p_rx_queue_count - Pointer to return queue count in.
+**
+**
+*******************************************************************************/
+extern int GAP_GetRxQueueCnt (uint16_t handle, uint32_t *p_rx_queue_count);
+
+/*******************************************************************************
+**
+** Function         GAP_ConnBTRead
+**
+** Description      GKI buffer aware applications will call this function after
+**                  receiving an GAP_EVT_RXDATA event to process the incoming
+**                  data buffer.
+**
+** Returns          BT_PASS             - data read
+**                  GAP_ERR_BAD_HANDLE  - invalid handle
+**                  GAP_NO_DATA_AVAIL   - no data available
+**
+*******************************************************************************/
+extern uint16_t GAP_ConnBTRead (uint16_t gap_handle, BT_HDR **pp_buf);
+
+/*******************************************************************************
+**
+** Function         GAP_ConnWriteData
+**
+** Description      GKI buffer unaware application will call this function
+**                  to send data to the connection. A data copy is made into a GKI
+**                  buffer.
+**
+** Returns          BT_PASS                 - data read
+**                  GAP_ERR_BAD_HANDLE      - invalid handle
+**                  GAP_ERR_BAD_STATE       - connection not established
+**                  GAP_CONGESTION          - system is congested
+**
+*******************************************************************************/
+extern uint16_t GAP_ConnWriteData (uint16_t gap_handle, uint8_t *p_data,
+                                         uint16_t max_len, uint16_t *p_len);
+
+/*******************************************************************************
+**
+** Function         GAP_ConnReconfig
+**
+** Description      Applications can call this function to reconfigure the connection.
+**
+** Returns          BT_PASS                 - config process started
+**                  GAP_ERR_BAD_HANDLE      - invalid handle
+**
+*******************************************************************************/
+extern uint16_t GAP_ConnReconfig (uint16_t gap_handle, tL2CAP_CFG_INFO *p_cfg);
+
+/*******************************************************************************
+**
+** Function         GAP_ConnSetIdleTimeout
+**
+** 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          BT_PASS                 - config process started
+**                  GAP_ERR_BAD_HANDLE      - invalid handle
+**
+*******************************************************************************/
+extern uint16_t GAP_ConnSetIdleTimeout (uint16_t gap_handle, uint16_t timeout);
+
+/*******************************************************************************
+**
+** Function         GAP_ConnGetRemoteAddr
+**
+** Description      This function is called to get the remote BD address
+**                  of a connection.
+**
+** Returns          BT_PASS             - closed OK
+**                  GAP_ERR_BAD_HANDLE  - invalid handle
+**
+*******************************************************************************/
+extern uint8_t *GAP_ConnGetRemoteAddr (uint16_t gap_handle);
+
+/*******************************************************************************
+**
+** Function         GAP_ConnGetRemMtuSize
+**
+** Description      Returns the remote device's MTU size.
+**
+** Returns          uint16_t - maximum size buffer that can be transmitted to the peer
+**
+*******************************************************************************/
+extern uint16_t GAP_ConnGetRemMtuSize (uint16_t gap_handle);
+
+/*******************************************************************************
+**
+** Function         GAP_ConnGetL2CAPCid
+**
+** Description      Returns the L2CAP channel id
+**
+** Parameters:      handle      - Handle of the connection
+**
+** Returns          uint16_t    - The L2CAP channel id
+**                  0, if error
+**
+*******************************************************************************/
+extern uint16_t GAP_ConnGetL2CAPCid (uint16_t gap_handle);
+
+/*******************************************************************************
+**
+** Function         GAP_SetTraceLevel
+**
+** Description      This function sets the trace level for GAP.  If called with
+**                  a value of 0xFF, it simply returns the current trace level.
+**
+** Returns          The new or current trace level
+**
+*******************************************************************************/
+extern uint8_t GAP_SetTraceLevel (uint8_t new_level);
+
+/*******************************************************************************
+**
+** Function         GAP_Init
+**
+** Description      Initializes the control blocks used by GAP.
+**                  This routine should not be called except once per
+**                      stack invocation.
+**
+** Returns          Nothing
+**
+*******************************************************************************/
+extern void GAP_Init(void);
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function         GAP_BleAttrDBUpdate
+**
+** Description      update GAP local BLE attribute database.
+**
+** Returns          Nothing
+**
+*******************************************************************************/
+extern void GAP_BleAttrDBUpdate(uint16_t attr_uuid, tGAP_BLE_ATTR_VALUE *p_value);
+
+
+/*******************************************************************************
+**
+** Function         GAP_BleReadPeerPrefConnParams
+**
+** Description      Start a process to read a connected peripheral's preferred
+**                  connection parameters
+**
+** Returns          true if read started, else false if GAP is busy
+**
+*******************************************************************************/
+extern bool    GAP_BleReadPeerPrefConnParams (BD_ADDR peer_bda);
+
+/*******************************************************************************
+**
+** Function         GAP_BleReadPeerDevName
+**
+** Description      Start a process to read a connected peripheral's device name.
+**
+** Returns          true if request accepted
+**
+*******************************************************************************/
+extern bool    GAP_BleReadPeerDevName (BD_ADDR peer_bda, tGAP_BLE_CMPL_CBACK *p_cback);
+
+
+/*******************************************************************************
+**
+** Function         GAP_BleReadPeerAddressResolutionCap
+**
+** Description      Start a process to read peer address resolution capability
+**
+** Returns          true if request accepted
+**
+*******************************************************************************/
+extern bool    GAP_BleReadPeerAddressResolutionCap (BD_ADDR peer_bda,
+                                                    tGAP_BLE_CMPL_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function         GAP_BleCancelReadPeerDevName
+**
+** Description      Cancel reading a peripheral's device name.
+**
+** Returns          true if request accepted
+**
+*******************************************************************************/
+extern bool    GAP_BleCancelReadPeerDevName (BD_ADDR peer_bda);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* GAP_API_H */
diff --git a/bt/stack/include/gatt_api.h b/bt/stack/include/gatt_api.h
new file mode 100644
index 0000000..89404e0
--- /dev/null
+++ b/bt/stack/include/gatt_api.h
@@ -0,0 +1,1122 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+#ifndef GATT_API_H
+#define GATT_API_H
+
+#include "bt_target.h"
+#include "gattdefs.h"
+#include "btm_ble_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+/* Success code and error codes */
+#define  GATT_SUCCESS                        0x00
+#define  GATT_INVALID_HANDLE                 0x01
+#define  GATT_READ_NOT_PERMIT                0x02
+#define  GATT_WRITE_NOT_PERMIT               0x03
+#define  GATT_INVALID_PDU                    0x04
+#define  GATT_INSUF_AUTHENTICATION           0x05
+#define  GATT_REQ_NOT_SUPPORTED              0x06
+#define  GATT_INVALID_OFFSET                 0x07
+#define  GATT_INSUF_AUTHORIZATION            0x08
+#define  GATT_PREPARE_Q_FULL                 0x09
+#define  GATT_NOT_FOUND                      0x0a
+#define  GATT_NOT_LONG                       0x0b
+#define  GATT_INSUF_KEY_SIZE                 0x0c
+#define  GATT_INVALID_ATTR_LEN               0x0d
+#define  GATT_ERR_UNLIKELY                   0x0e
+#define  GATT_INSUF_ENCRYPTION               0x0f
+#define  GATT_UNSUPPORT_GRP_TYPE             0x10
+#define  GATT_INSUF_RESOURCE                 0x11
+
+
+#define  GATT_ILLEGAL_PARAMETER              0x87
+#define  GATT_NO_RESOURCES                   0x80
+#define  GATT_INTERNAL_ERROR                 0x81
+#define  GATT_WRONG_STATE                    0x82
+#define  GATT_DB_FULL                        0x83
+#define  GATT_BUSY                           0x84
+#define  GATT_ERROR                          0x85
+#define  GATT_CMD_STARTED                    0x86
+#define  GATT_PENDING                        0x88
+#define  GATT_AUTH_FAIL                      0x89
+#define  GATT_MORE                           0x8a
+#define  GATT_INVALID_CFG                    0x8b
+#define  GATT_SERVICE_STARTED                0x8c
+#define  GATT_ENCRYPED_MITM                  GATT_SUCCESS
+#define  GATT_ENCRYPED_NO_MITM               0x8d
+#define  GATT_NOT_ENCRYPTED                  0x8e
+#define  GATT_CONGESTED                      0x8f
+
+                                             /* 0xE0 ~ 0xFC reserved for future use */
+#define  GATT_CCC_CFG_ERR                    0xFD /* Client Characteristic Configuration Descriptor Improperly Configured */
+#define  GATT_PRC_IN_PROGRESS                0xFE /* Procedure Already in progress */
+#define  GATT_OUT_OF_RANGE                   0xFF /* Attribute value out of range */
+typedef uint8_t tGATT_STATUS;
+
+
+#define  GATT_RSP_ERROR                      0x01
+#define  GATT_REQ_MTU                        0x02
+#define  GATT_RSP_MTU                        0x03
+#define  GATT_REQ_FIND_INFO                  0x04
+#define  GATT_RSP_FIND_INFO                  0x05
+#define  GATT_REQ_FIND_TYPE_VALUE            0x06
+#define  GATT_RSP_FIND_TYPE_VALUE            0x07
+#define  GATT_REQ_READ_BY_TYPE               0x08
+#define  GATT_RSP_READ_BY_TYPE               0x09
+#define  GATT_REQ_READ                       0x0A
+#define  GATT_RSP_READ                       0x0B
+#define  GATT_REQ_READ_BLOB                  0x0C
+#define  GATT_RSP_READ_BLOB                  0x0D
+#define  GATT_REQ_READ_MULTI                 0x0E
+#define  GATT_RSP_READ_MULTI                 0x0F
+#define  GATT_REQ_READ_BY_GRP_TYPE           0x10
+#define  GATT_RSP_READ_BY_GRP_TYPE           0x11
+#define  GATT_REQ_WRITE                      0x12 /*                 0001-0010 (write)*/
+#define  GATT_RSP_WRITE                      0x13
+#define  GATT_CMD_WRITE                      0x52 /* changed in V4.0 01001-0010(write cmd)*/
+#define  GATT_REQ_PREPARE_WRITE              0x16
+#define  GATT_RSP_PREPARE_WRITE              0x17
+#define  GATT_REQ_EXEC_WRITE                 0x18
+#define  GATT_RSP_EXEC_WRITE                 0x19
+#define  GATT_HANDLE_VALUE_NOTIF             0x1B
+#define  GATT_HANDLE_VALUE_IND               0x1D
+#define  GATT_HANDLE_VALUE_CONF              0x1E
+#define  GATT_SIGN_CMD_WRITE                 0xD2 /* changed in V4.0 1101-0010 (signed write)  see write cmd above*/
+#define  GATT_OP_CODE_MAX                    (GATT_HANDLE_VALUE_CONF + 1) /* 0x1E = 30 + 1 = 31*/
+
+
+#define  GATT_HANDLE_IS_VALID(x) ((x) != 0)
+
+#define GATT_CONN_UNKNOWN                   0
+#define GATT_CONN_L2C_FAILURE               1                               /* general L2cap failure  */
+#define GATT_CONN_TIMEOUT                   HCI_ERR_CONNECTION_TOUT         /* 0x08 connection timeout  */
+#define GATT_CONN_TERMINATE_PEER_USER       HCI_ERR_PEER_USER               /* 0x13 connection terminate by peer user  */
+#define GATT_CONN_TERMINATE_LOCAL_HOST      HCI_ERR_CONN_CAUSE_LOCAL_HOST   /* 0x16 connectionterminated by local host  */
+#define GATT_CONN_FAIL_ESTABLISH            HCI_ERR_CONN_FAILED_ESTABLISHMENT/* 0x03E connection fail to establish  */
+#define GATT_CONN_LMP_TIMEOUT               HCI_ERR_LMP_RESPONSE_TIMEOUT     /* 0x22 connection fail for LMP response tout */
+#define GATT_CONN_CANCEL                    L2CAP_CONN_CANCEL                /* 0x0100 L2CAP connection cancelled  */
+typedef uint16_t tGATT_DISCONN_REASON;
+
+/* MAX GATT MTU size
+*/
+#ifndef GATT_MAX_MTU_SIZE
+    #define GATT_MAX_MTU_SIZE     517
+#endif
+
+/* max legth of an attribute value
+*/
+#ifndef GATT_MAX_ATTR_LEN
+    #define GATT_MAX_ATTR_LEN     600
+#endif
+
+/* default GATT MTU size over LE link
+*/
+#define GATT_DEF_BLE_MTU_SIZE       23
+
+/* invalid connection ID
+*/
+#define GATT_INVALID_CONN_ID        0xFFFF
+
+#ifndef GATT_CL_MAX_LCB
+    #define GATT_CL_MAX_LCB     22
+#endif
+
+#ifndef GATT_MAX_SCCB
+    #define GATT_MAX_SCCB       10
+#endif
+
+
+/* GATT notification caching timer, default to be three seconds
+*/
+#ifndef GATTC_NOTIF_TIMEOUT
+    #define GATTC_NOTIF_TIMEOUT   3
+#endif
+
+/*****************************************************************************
+** GATT Structure Definition
+*****************************************************************************/
+
+/* Attribute permissions
+*/
+#define GATT_PERM_READ              (1 << 0) /* bit 0 */
+#define GATT_PERM_READ_ENCRYPTED    (1 << 1) /* bit 1 */
+#define GATT_PERM_READ_ENC_MITM     (1 << 2) /* bit 2 */
+#define GATT_PERM_WRITE             (1 << 4) /* bit 4 */
+#define GATT_PERM_WRITE_ENCRYPTED   (1 << 5) /* bit 5 */
+#define GATT_PERM_WRITE_ENC_MITM    (1 << 6) /* bit 6 */
+#define GATT_PERM_WRITE_SIGNED      (1 << 7) /* bit 7 */
+#define GATT_PERM_WRITE_SIGNED_MITM (1 << 8) /* bit 8 */
+typedef uint16_t tGATT_PERM;
+
+#define GATT_ENCRYPT_KEY_SIZE_MASK  (0xF000) /* the MS nibble of tGATT_PERM; key size 7=0; size 16=9 */
+
+#define GATT_READ_ALLOWED           (GATT_PERM_READ | GATT_PERM_READ_ENCRYPTED | GATT_PERM_READ_ENC_MITM)
+#define GATT_READ_AUTH_REQUIRED     (GATT_PERM_READ_ENCRYPTED)
+#define GATT_READ_MITM_REQUIRED     (GATT_PERM_READ_ENC_MITM)
+#define GATT_READ_ENCRYPTED_REQUIRED   (GATT_PERM_READ_ENCRYPTED | GATT_PERM_READ_ENC_MITM)
+
+
+#define GATT_WRITE_ALLOWED          (GATT_PERM_WRITE | GATT_PERM_WRITE_ENCRYPTED | GATT_PERM_WRITE_ENC_MITM | \
+                                     GATT_PERM_WRITE_SIGNED | GATT_PERM_WRITE_SIGNED_MITM)
+
+#define GATT_WRITE_AUTH_REQUIRED    (GATT_PERM_WRITE_ENCRYPTED | GATT_PERM_WRITE_SIGNED)
+
+#define GATT_WRITE_MITM_REQUIRED    (GATT_PERM_WRITE_ENC_MITM | GATT_PERM_WRITE_SIGNED_MITM)
+
+#define GATT_WRITE_ENCRYPTED_PERM   (GATT_PERM_WRITE_ENCRYPTED | GATT_PERM_WRITE_ENC_MITM)
+
+#define GATT_WRITE_SIGNED_PERM      (GATT_PERM_WRITE_SIGNED | GATT_PERM_WRITE_SIGNED_MITM)
+
+
+/* Characteristic properties
+*/
+#define GATT_CHAR_PROP_BIT_BROADCAST    (1 << 0)
+#define GATT_CHAR_PROP_BIT_READ         (1 << 1)
+#define GATT_CHAR_PROP_BIT_WRITE_NR     (1 << 2)
+#define GATT_CHAR_PROP_BIT_WRITE        (1 << 3)
+#define GATT_CHAR_PROP_BIT_NOTIFY       (1 << 4)
+#define GATT_CHAR_PROP_BIT_INDICATE     (1 << 5)
+#define GATT_CHAR_PROP_BIT_AUTH         (1 << 6)
+#define GATT_CHAR_PROP_BIT_EXT_PROP     (1 << 7)
+typedef uint8_t tGATT_CHAR_PROP;
+
+
+/* Format of the value of a characteristic. enumeration type
+*/
+enum
+{
+    GATT_FORMAT_RES,            /* rfu */
+    GATT_FORMAT_BOOL,           /* 0x01 boolean */
+    GATT_FORMAT_2BITS,           /* 0x02 2 bit */
+    GATT_FORMAT_NIBBLE,         /* 0x03 nibble */
+    GATT_FORMAT_UINT8,          /* 0x04 uint8 */
+    GATT_FORMAT_UINT12,         /* 0x05 uint12 */
+    GATT_FORMAT_UINT16,         /* 0x06 uint16 */
+    GATT_FORMAT_UINT24,         /* 0x07 uint24 */
+    GATT_FORMAT_UINT32,         /* 0x08 uint32 */
+    GATT_FORMAT_UINT48,         /* 0x09 uint48 */
+    GATT_FORMAT_UINT64,         /* 0x0a uint64 */
+    GATT_FORMAT_UINT128,        /* 0x0B uint128 */
+    GATT_FORMAT_SINT8,          /* 0x0C signed 8 bit integer */
+    GATT_FORMAT_SINT12,         /* 0x0D signed 12 bit integer */
+    GATT_FORMAT_SINT16,         /* 0x0E signed 16 bit integer */
+    GATT_FORMAT_SINT24,         /* 0x0F signed 24 bit integer */
+    GATT_FORMAT_SINT32,         /* 0x10 signed 32 bit integer */
+    GATT_FORMAT_SINT48,         /* 0x11 signed 48 bit integer */
+    GATT_FORMAT_SINT64,         /* 0x12 signed 64 bit integer */
+    GATT_FORMAT_SINT128,        /* 0x13 signed 128 bit integer */
+    GATT_FORMAT_FLOAT32,        /* 0x14 float 32 */
+    GATT_FORMAT_FLOAT64,        /* 0x15 float 64*/
+    GATT_FORMAT_SFLOAT,         /* 0x16 IEEE-11073 16 bit SFLOAT */
+    GATT_FORMAT_FLOAT,          /* 0x17 IEEE-11073 32 bit SFLOAT */
+    GATT_FORMAT_DUINT16,        /* 0x18 IEEE-20601 format */
+    GATT_FORMAT_UTF8S,          /* 0x19 UTF-8 string */
+    GATT_FORMAT_UTF16S,         /* 0x1a UTF-16 string */
+    GATT_FORMAT_STRUCT,         /* 0x1b Opaque structure*/
+    GATT_FORMAT_MAX             /* 0x1c or above reserved */
+};
+typedef uint8_t tGATT_FORMAT;
+
+/* Characteristic Presentation Format Descriptor value
+*/
+typedef struct
+{
+    uint16_t            unit;       /* as UUIUD defined by SIG */
+    uint16_t            descr;       /* as UUID as defined by SIG */
+    tGATT_FORMAT        format;
+    int8_t              exp;
+    uint8_t             name_spc;   /* The name space of the description */
+} tGATT_CHAR_PRES;
+
+/* Characteristic Report reference Descriptor format
+*/
+typedef struct
+{
+    uint8_t            rpt_id;       /* report ID */
+    uint8_t            rpt_type;       /* report type */
+} tGATT_CHAR_RPT_REF;
+
+
+#define GATT_VALID_RANGE_MAX_SIZE       16
+typedef struct
+{
+    uint8_t                 format;
+    uint16_t                len;
+    uint8_t                 lower_range[GATT_VALID_RANGE_MAX_SIZE]; /* in little endian format */
+    uint8_t                 upper_range[GATT_VALID_RANGE_MAX_SIZE];
+} tGATT_VALID_RANGE;
+
+/* Characteristic Aggregate Format attribute value
+*/
+#define GATT_AGGR_HANDLE_NUM_MAX        10
+typedef struct
+{
+    uint8_t                 num_handle;
+    uint16_t                handle_list[GATT_AGGR_HANDLE_NUM_MAX];
+} tGATT_CHAR_AGGRE;
+
+/* Characteristic descriptor: Extended Properties value
+*/
+#define GATT_CHAR_BIT_REL_WRITE    0x0001       /* permits reliable writes of the Characteristic Value */
+#define GATT_CHAR_BIT_WRITE_AUX    0x0002       /* permits writes to the characteristic descriptor */
+
+
+/* characteristic descriptor: client configuration value
+*/
+#define GATT_CLT_CONFIG_NONE               0x0000
+#define GATT_CLT_CONFIG_NOTIFICATION       0x0001
+#define GATT_CLT_CONFIG_INDICATION         0x0002
+typedef uint16_t tGATT_CLT_CHAR_CONFIG;
+
+
+/* characteristic descriptor: server configuration value
+*/
+#define GATT_SVR_CONFIG_NONE                     0x0000
+#define GATT_SVR_CONFIG_BROADCAST                0x0001
+typedef uint16_t tGATT_SVR_CHAR_CONFIG;
+
+/* Characteristic descriptor: Extended Properties value
+*/
+#define GATT_CHAR_BIT_REL_WRITE    0x0001       /* permits reliable writes of the Characteristic Value */
+#define GATT_CHAR_BIT_WRITE_AUX    0x0002       /* permits writes to the characteristic descriptor */
+
+/* authentication requirement
+*/
+#define GATT_AUTH_REQ_NONE              0
+#define GATT_AUTH_REQ_NO_MITM           1   /* unauthenticated encryption */
+#define GATT_AUTH_REQ_MITM              2   /* authenticated encryption */
+#define GATT_AUTH_REQ_SIGNED_NO_MITM    3
+#define GATT_AUTH_REQ_SIGNED_MITM       4
+typedef uint8_t tGATT_AUTH_REQ;
+
+/* Attribute Value structure
+*/
+typedef struct
+{
+    uint16_t        conn_id;
+    uint16_t        handle;     /* attribute handle */
+    uint16_t        offset;     /* attribute value offset, if no offfset is needed for the command, ignore it */
+    uint16_t        len;        /* length of attribute value */
+    tGATT_AUTH_REQ  auth_req;   /*  authentication request */
+    uint8_t         value[GATT_MAX_ATTR_LEN];  /* the actual attribute value */
+} tGATT_VALUE;
+
+/* Union of the event data which is used in the server respond API to carry the server response information
+*/
+typedef union
+{
+    /* data type            member          event   */
+    tGATT_VALUE             attr_value;     /* READ, HANDLE_VALUE_IND, PREPARE_WRITE */
+                                            /* READ_BLOB, READ_BY_TYPE */
+    uint16_t                handle;         /* WRITE, WRITE_BLOB */
+
+} tGATTS_RSP;
+
+/* Transports for the primary service  */
+#define GATT_TRANSPORT_LE           BT_TRANSPORT_LE
+#define GATT_TRANSPORT_BR_EDR       BT_TRANSPORT_BR_EDR
+#define GATT_TRANSPORT_LE_BR_EDR    (BT_TRANSPORT_LE|BT_TRANSPORT_BR_EDR)
+typedef uint8_t tGATT_TRANSPORT;
+
+#define GATT_PREP_WRITE_CANCEL   0x00
+#define GATT_PREP_WRITE_EXEC     0x01
+typedef uint8_t tGATT_EXEC_FLAG;
+
+/* read request always based on UUID */
+typedef struct
+{
+    uint16_t      handle;
+    uint16_t      offset;
+    bool          is_long;
+    bt_gatt_db_attribute_type_t gatt_type; /* are we writing characteristic or descriptor */
+} tGATT_READ_REQ;
+
+/* write request data */
+typedef struct
+{
+    uint16_t        handle;     /* attribute handle */
+    uint16_t        offset;     /* attribute value offset, if no offfset is needed for the command, ignore it */
+    uint16_t        len;        /* length of attribute value */
+    uint8_t         value[GATT_MAX_ATTR_LEN];  /* the actual attribute value */
+    bool            need_rsp;   /* need write response */
+    bool            is_prep;    /* is prepare write */
+    bt_gatt_db_attribute_type_t gatt_type; /* are we writing characteristic or descriptor */
+} tGATT_WRITE_REQ;
+
+/* callback data for server access request from client */
+typedef union
+{
+    tGATT_READ_REQ         read_req;       /* read request, read by Type, read blob */
+
+    tGATT_WRITE_REQ        write_req;    /* write */
+                                         /* prepare write */
+                                         /* write blob */
+    uint16_t               handle;       /* handle value confirmation */
+    uint16_t               mtu;          /* MTU exchange request */
+    tGATT_EXEC_FLAG        exec_write;    /* execute write */
+} tGATTS_DATA;
+
+typedef uint8_t tGATT_SERV_IF;               /* GATT Service Interface */
+
+enum
+{
+    GATTS_REQ_TYPE_READ_CHARACTERISTIC = 1, /* Char read request */
+    GATTS_REQ_TYPE_READ_DESCRIPTOR,         /* Desc read request */
+    GATTS_REQ_TYPE_WRITE_CHARACTERISTIC,    /* Char write request */
+    GATTS_REQ_TYPE_WRITE_DESCRIPTOR,        /* Desc write request */
+    GATTS_REQ_TYPE_WRITE_EXEC,      /* Execute write */
+    GATTS_REQ_TYPE_MTU,             /* MTU exchange information */
+    GATTS_REQ_TYPE_CONF             /* handle value confirmation */
+};
+typedef uint8_t tGATTS_REQ_TYPE;
+
+
+
+/* Client Used Data Structure
+*/
+/* definition of different discovery types */
+enum
+{
+    GATT_DISC_SRVC_ALL = 1,     /* discover all services */
+    GATT_DISC_SRVC_BY_UUID,     /* discover service of a special type */
+    GATT_DISC_INC_SRVC,         /* discover the included service within a service */
+    GATT_DISC_CHAR,             /* discover characteristics of a service with/without type requirement */
+    GATT_DISC_CHAR_DSCPT,       /* discover characteristic descriptors of a character */
+    GATT_DISC_MAX               /* maximnun discover type */
+};
+typedef uint8_t tGATT_DISC_TYPE;
+
+/* Discover parameters of different discovery types
+*/
+typedef struct
+{
+    tBT_UUID    service;
+    uint16_t    s_handle;
+    uint16_t    e_handle;
+}tGATT_DISC_PARAM;
+
+/* GATT read type enumeration
+*/
+enum
+{
+    GATT_READ_BY_TYPE =        1,
+    GATT_READ_BY_HANDLE,
+    GATT_READ_MULTIPLE,
+    GATT_READ_CHAR_VALUE,
+    GATT_READ_PARTIAL,
+    GATT_READ_MAX
+};
+typedef uint8_t tGATT_READ_TYPE;
+
+/* Read By Type Request (GATT_READ_BY_TYPE) Data
+*/
+typedef struct
+{
+    tGATT_AUTH_REQ      auth_req;
+    uint16_t            s_handle;
+    uint16_t            e_handle;
+    tBT_UUID            uuid;
+} tGATT_READ_BY_TYPE;
+
+/*   GATT_READ_MULTIPLE request data
+*/
+#define GATT_MAX_READ_MULTI_HANDLES      10           /* Max attributes to read in one request */
+typedef struct
+{
+    tGATT_AUTH_REQ          auth_req;
+    uint16_t                num_handles;                            /* number of handles to read */
+    uint16_t                handles[GATT_MAX_READ_MULTI_HANDLES];   /* handles list to be read */
+} tGATT_READ_MULTI;
+
+/*   Read By Handle Request (GATT_READ_BY_HANDLE) data */
+typedef struct
+{
+    tGATT_AUTH_REQ         auth_req;
+    uint16_t               handle;
+} tGATT_READ_BY_HANDLE;
+
+/*   READ_BT_HANDLE_Request data */
+typedef struct
+{
+    tGATT_AUTH_REQ         auth_req;
+    uint16_t               handle;
+    uint16_t               offset;
+} tGATT_READ_PARTIAL;
+
+/* Read Request Data
+*/
+typedef union
+{
+    tGATT_READ_BY_TYPE   service;
+    tGATT_READ_BY_TYPE   char_type;        /* characterisitc type */
+    tGATT_READ_MULTI     read_multiple;
+    tGATT_READ_BY_HANDLE by_handle;
+    tGATT_READ_PARTIAL   partial;
+} tGATT_READ_PARAM;
+
+/* GATT write type enumeration */
+enum
+{
+    GATT_WRITE_NO_RSP = 1,
+    GATT_WRITE ,
+    GATT_WRITE_PREPARE
+};
+typedef uint8_t tGATT_WRITE_TYPE;
+
+/* Client Operation Complete Callback Data
+*/
+typedef union
+{
+    tGATT_VALUE          att_value;
+    uint16_t             mtu;
+    uint16_t             handle;
+} tGATT_CL_COMPLETE;
+
+/* GATT client operation type, used in client callback function
+*/
+#define GATTC_OPTYPE_NONE                 0
+#define GATTC_OPTYPE_DISCOVERY            1
+#define GATTC_OPTYPE_READ                 2
+#define GATTC_OPTYPE_WRITE                3
+#define GATTC_OPTYPE_EXE_WRITE            4
+#define GATTC_OPTYPE_CONFIG               5
+#define GATTC_OPTYPE_NOTIFICATION         6
+#define GATTC_OPTYPE_INDICATION           7
+typedef uint8_t tGATTC_OPTYPE;
+
+/* characteristic declaration
+*/
+typedef struct
+{
+    tGATT_CHAR_PROP       char_prop;   /* characterisitc properties */
+    uint16_t              val_handle;  /* characteristic value attribute handle */
+    tBT_UUID              char_uuid;   /* characteristic UUID type */
+} tGATT_CHAR_DCLR_VAL;
+
+/* primary service group data
+*/
+typedef struct
+{
+    uint16_t        e_handle;       /* ending handle of the group */
+    tBT_UUID        service_type;   /* group type */
+} tGATT_GROUP_VALUE;
+
+
+/* included service attribute value
+*/
+typedef struct
+{
+    tBT_UUID    service_type;       /* included service UUID */
+    uint16_t    s_handle;           /* starting handle */
+    uint16_t    e_handle;           /* ending handle */
+} tGATT_INCL_SRVC;
+
+typedef union
+{
+    tGATT_INCL_SRVC     incl_service;  /* include service value */
+    tGATT_GROUP_VALUE   group_value;   /* Service UUID type.
+                                          This field is used with GATT_DISC_SRVC_ALL
+                                          or GATT_DISC_SRVC_BY_UUID
+                                          type of discovery result callback. */
+
+    uint16_t            handle;        /* When used with GATT_DISC_INC_SRVC type discovery result,
+                                          it is the included service starting handle.*/
+
+    tGATT_CHAR_DCLR_VAL dclr_value;    /* Characteristic declaration value.
+                                          This field is used with GATT_DISC_CHAR type discovery.*/
+} tGATT_DISC_VALUE;
+
+/* discover result record
+*/
+typedef struct
+{
+    tBT_UUID            type;
+    uint16_t            handle;
+    tGATT_DISC_VALUE    value;
+} tGATT_DISC_RES;
+
+
+#define GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP    1 /* start a idle timer for this duration
+                                                 when no application need to use the link */
+
+#define GATT_LINK_NO_IDLE_TIMEOUT            0xFFFF
+
+#define GATT_INVALID_ACL_HANDLE              0xFFFF
+/* discover result callback function */
+typedef void (tGATT_DISC_RES_CB) (uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+                                    tGATT_DISC_RES *p_data);
+
+/* discover complete callback function */
+typedef void (tGATT_DISC_CMPL_CB) (uint16_t conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status);
+
+/* Define a callback function for when read/write/disc/config operation is completed. */
+typedef void (tGATT_CMPL_CBACK) (uint16_t conn_id, tGATTC_OPTYPE op, tGATT_STATUS status,
+                tGATT_CL_COMPLETE *p_data);
+
+/* Define a callback function when an initialized connection is established. */
+typedef void (tGATT_CONN_CBACK) (tGATT_IF gatt_if, BD_ADDR bda, uint16_t conn_id, bool    connected,
+                                    tGATT_DISCONN_REASON reason, tBT_TRANSPORT transport);
+
+/* attribute request callback for ATT server */
+typedef void  (tGATT_REQ_CBACK )(uint16_t conn_id, uint32_t trans_id, tGATTS_REQ_TYPE type,
+                                tGATTS_DATA *p_data);
+
+/* channel congestion/uncongestion callback */
+typedef void (tGATT_CONGESTION_CBACK )(uint16_t conn_id, bool    congested);
+
+/* Define a callback function when encryption is established. */
+typedef void (tGATT_ENC_CMPL_CB)(tGATT_IF gatt_if, BD_ADDR bda);
+
+
+/* Define the structure that applications use to register with
+** GATT. This structure includes callback functions. All functions
+** MUST be provided.
+*/
+typedef struct
+{
+    tGATT_CONN_CBACK                *p_conn_cb;
+    tGATT_CMPL_CBACK                *p_cmpl_cb;
+    tGATT_DISC_RES_CB               *p_disc_res_cb;
+    tGATT_DISC_CMPL_CB              *p_disc_cmpl_cb;
+    tGATT_REQ_CBACK                 *p_req_cb;
+    tGATT_ENC_CMPL_CB               *p_enc_cmpl_cb;
+    tGATT_CONGESTION_CBACK          *p_congestion_cb;
+} tGATT_CBACK;
+
+/***********************  Start Handle Management Definitions   **********************
+*/
+
+
+typedef struct
+{
+    tBT_UUID app_uuid128;
+    tBT_UUID svc_uuid;
+    uint16_t s_handle;
+    uint16_t e_handle;
+    bool     is_primary;      /* primary service or secondary */
+} tGATTS_HNDL_RANGE;
+
+
+
+#define GATTS_SRV_CHG_CMD_ADD_CLIENT       1
+#define GATTS_SRV_CHG_CMD_UPDATE_CLIENT    2
+#define GATTS_SRV_CHG_CMD_REMOVE_CLIENT    3
+#define GATTS_SRV_CHG_CMD_READ_NUM_CLENTS  4
+#define GATTS_SRV_CHG_CMD_READ_CLENT       5
+typedef uint8_t tGATTS_SRV_CHG_CMD;
+
+typedef struct
+{
+    BD_ADDR         bda;
+    bool            srv_changed;
+} tGATTS_SRV_CHG;
+
+
+typedef union
+{
+    tGATTS_SRV_CHG  srv_chg;
+    uint8_t         client_read_index; /* only used for sequential reading client srv chg info */
+} tGATTS_SRV_CHG_REQ;
+
+typedef union
+{
+    tGATTS_SRV_CHG srv_chg;
+    uint8_t num_clients;
+} tGATTS_SRV_CHG_RSP;
+
+/* Attibute server handle ranges NV storage callback functions
+*/
+typedef void  (tGATTS_NV_SAVE_CBACK)(bool    is_saved, tGATTS_HNDL_RANGE *p_hndl_range);
+typedef bool     (tGATTS_NV_SRV_CHG_CBACK)(tGATTS_SRV_CHG_CMD cmd, tGATTS_SRV_CHG_REQ *p_req,
+                                            tGATTS_SRV_CHG_RSP *p_rsp);
+
+typedef struct
+{
+    tGATTS_NV_SAVE_CBACK       *p_nv_save_callback;
+    tGATTS_NV_SRV_CHG_CBACK    *p_srv_chg_callback;
+} tGATT_APPL_INFO;
+
+/*
+***********************  End Handle Management Definitions   **********************/
+
+/*****************************************************************************
+**  External Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function         GATT_SetTraceLevel
+**
+** Description      This function sets the trace level.  If called with
+**                  a value of 0xFF, it simply returns the current trace level.
+**
+** Returns          The new or current trace level
+**
+*******************************************************************************/
+extern uint8_t GATT_SetTraceLevel (uint8_t new_level);
+
+
+/*******************************************************************************/
+/* GATT Profile API Functions */
+/*******************************************************************************/
+/* GATT Profile Server Functions */
+/*******************************************************************************/
+/*******************************************************************************
+**
+** Function         GATTS_AddHandleRange
+**
+** Description      This function add the allocated handles range for the specifed
+**                  application UUID, service UUID and service instance
+**
+** Parameter        p_hndl_range:   pointer to allocated handles information
+**
+** Returns          true if handle range is added sucessfully; otherwise false.
+**
+*******************************************************************************/
+
+extern bool    GATTS_AddHandleRange(tGATTS_HNDL_RANGE *p_hndl_range);
+
+/*******************************************************************************
+**
+** Function         GATTS_NVRegister
+**
+** Description      Application manager calls this function to register for
+**                  NV save callback function.  There can be one and only one
+**                  NV save callback function.
+**
+** Parameter        p_cb_info : callback informaiton
+**
+** Returns          true if registered OK, else false
+**
+*******************************************************************************/
+extern bool     GATTS_NVRegister (tGATT_APPL_INFO *p_cb_info);
+
+/* Converts 16bit uuid to bt_uuid_t that can be used when adding
+ * service/characteristic/descriptor with GATTS_AddService */
+void uuid_128_from_16(bt_uuid_t *uuid, uint16_t uuid16);
+
+/*******************************************************************************
+**
+** Function         BTA_GATTS_AddService
+**
+** Description      Add a service. When service is ready, a callback
+**                  event BTA_GATTS_ADD_SRVC_EVT is called to report status
+**                  and handles to the profile.
+**
+** Parameters       server_if: server interface.
+**                  service: pointer array describing service.
+**                  count: number of elements in service array.
+**
+** Returns          on success GATT_SERVICE_STARTED is returned, and
+**                  attribute_handle field inside service elements are filled.
+**                  on error error status is returned.
+**
+*******************************************************************************/
+extern uint16_t GATTS_AddService(tGATT_IF gatt_if, btgatt_db_element_t *service, int count);
+
+/*******************************************************************************
+**
+** Function         GATTS_DeleteService
+**
+** Description      This function is called to delete a service.
+**
+** Parameter        gatt_if       : application interface
+**                  p_svc_uuid    : service UUID
+**                  svc_inst      : instance of the service inside the application
+**
+** Returns          true if operation succeed, false if handle block was not found.
+**
+*******************************************************************************/
+extern bool GATTS_DeleteService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid, uint16_t svc_inst);
+
+
+/*******************************************************************************
+**
+** Function         GATTS_StopService
+**
+** Description      This function is called to stop a service
+**
+** Parameter         service_handle : this is the start handle of a service
+**
+** Returns          None.
+**
+*******************************************************************************/
+extern void GATTS_StopService (uint16_t service_handle);
+
+
+/*******************************************************************************
+**
+** Function         GATTs_HandleValueIndication
+**
+** Description      This function sends a handle value indication to a client.
+**
+** Parameter        conn_id: connection identifier.
+**                  attr_handle: Attribute handle of this handle value indication.
+**                  val_len: Length of the indicated attribute value.
+**                  p_val: Pointer to the indicated attribute value data.
+**
+** Returns          GATT_SUCCESS if sucessfully sent or queued; otherwise error code.
+**
+*******************************************************************************/
+extern  tGATT_STATUS GATTS_HandleValueIndication (uint16_t conn_id,
+                                                  uint16_t attr_handle,
+                                                  uint16_t val_len, uint8_t *p_val);
+
+/*******************************************************************************
+**
+** Function         GATTS_HandleValueNotification
+**
+** Description      This function sends a handle value notification to a client.
+**
+** Parameter       conn_id: connection identifier.
+**                  attr_handle: Attribute handle of this handle value indication.
+**                  val_len: Length of the indicated attribute value.
+**                  p_val: Pointer to the indicated attribute value data.
+**
+** Returns          GATT_SUCCESS if sucessfully sent; otherwise error code.
+**
+*******************************************************************************/
+extern  tGATT_STATUS GATTS_HandleValueNotification (uint16_t conn_id, uint16_t attr_handle,
+                                                    uint16_t val_len, uint8_t *p_val);
+
+
+/*******************************************************************************
+**
+** Function         GATTS_SendRsp
+**
+** Description      This function sends the server response to client.
+**
+** Parameter        conn_id: connection identifier.
+**                  trans_id: transaction id
+**                  status: response status
+**                  p_msg: pointer to message parameters structure.
+**
+** Returns          GATT_SUCCESS if sucessfully sent; otherwise error code.
+**
+*******************************************************************************/
+extern  tGATT_STATUS GATTS_SendRsp (uint16_t conn_id,  uint32_t trans_id,
+                                    tGATT_STATUS status, tGATTS_RSP *p_msg);
+
+
+/*******************************************************************************/
+/* GATT Profile Client Functions */
+/*******************************************************************************/
+
+/*******************************************************************************
+**
+** Function         GATTC_ConfigureMTU
+**
+** Description      This function is called to configure the ATT MTU size for
+**                  a connection on an LE transport.
+**
+** Parameters       conn_id: connection identifier.
+**                  mtu    - attribute MTU size..
+**
+** Returns          GATT_SUCCESS if command started successfully.
+**
+*******************************************************************************/
+extern tGATT_STATUS GATTC_ConfigureMTU (uint16_t conn_id, uint16_t mtu);
+
+/*******************************************************************************
+**
+** Function         GATTC_Discover
+**
+** Description      This function is called to do a discovery procedure on ATT server.
+**
+** Parameters       conn_id: connection identifier.
+**                  disc_type:discovery type.
+**                  p_param: parameters of discovery requirement.
+**
+** Returns          GATT_SUCCESS if command received/sent successfully.
+**
+*******************************************************************************/
+extern tGATT_STATUS GATTC_Discover (uint16_t conn_id,
+                                    tGATT_DISC_TYPE disc_type,
+                                    tGATT_DISC_PARAM *p_param );
+/*******************************************************************************
+**
+** Function         GATTC_Read
+**
+** Description      This function is called to read the value of an attribute from
+**                  the server.
+**
+** Parameters       conn_id: connection identifier.
+**                  type    - attribute read type.
+**                  p_read  - read operation parameters.
+**
+** Returns          GATT_SUCCESS if command started successfully.
+**
+*******************************************************************************/
+extern tGATT_STATUS GATTC_Read (uint16_t conn_id, tGATT_READ_TYPE type,
+                                tGATT_READ_PARAM *p_read);
+
+/*******************************************************************************
+**
+** Function         GATTC_Write
+**
+** Description      This function is called to read the value of an attribute from
+**                  the server.
+**
+** Parameters       conn_id: connection identifier.
+**                  type    - attribute write type.
+**                  p_write  - write operation parameters.
+**
+** Returns          GATT_SUCCESS if command started successfully.
+**
+*******************************************************************************/
+extern tGATT_STATUS GATTC_Write (uint16_t conn_id, tGATT_WRITE_TYPE type,
+                                 tGATT_VALUE *p_write);
+
+
+/*******************************************************************************
+**
+** Function         GATTC_ExecuteWrite
+**
+** Description      This function is called to send an Execute write request to
+**                  the server.
+**
+** Parameters       conn_id: connection identifier.
+**                  is_execute - to execute or cancel the prepare write requet(s)
+**
+** Returns          GATT_SUCCESS if command started successfully.
+**
+*******************************************************************************/
+extern tGATT_STATUS GATTC_ExecuteWrite (uint16_t conn_id, bool    is_execute);
+
+/*******************************************************************************
+**
+** Function         GATTC_SendHandleValueConfirm
+**
+** Description      This function is called to send a handle value confirmation
+**                  as response to a handle value notification from server.
+**
+** Parameters       conn_id: connection identifier.
+**                  handle: the handle of the attribute confirmation.
+**
+** Returns          GATT_SUCCESS if command started successfully.
+**
+*******************************************************************************/
+extern tGATT_STATUS GATTC_SendHandleValueConfirm (uint16_t conn_id, uint16_t handle);
+
+
+/*******************************************************************************
+**
+** Function         GATT_SetIdleTimeout
+**
+** Description      This function (common to both client and server) sets the idle
+**                  timeout for a tansport connection
+**
+** Parameter        bd_addr:   target device bd address.
+**                  idle_tout: timeout value in seconds.
+**                  transport: trasnport option.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void GATT_SetIdleTimeout (BD_ADDR bd_addr, uint16_t idle_tout,
+                                 tGATT_TRANSPORT transport);
+
+
+/*******************************************************************************
+**
+** Function         GATT_Register
+**
+** Description      This function is called to register an  application
+**                  with GATT
+**
+** Parameter        p_app_uuid128: Application UUID
+**                  p_cb_info: callback functions.
+**
+** Returns          0 for error, otherwise the index of the client registered with GATT
+**
+*******************************************************************************/
+extern  tGATT_IF GATT_Register (tBT_UUID *p_app_uuid128, tGATT_CBACK *p_cb_info);
+
+/*******************************************************************************
+**
+** Function         GATT_Deregister
+**
+** Description      This function deregistered the application from GATT.
+**
+** Parameters       gatt_if: applicaiton interface.
+**
+** Returns          None.
+**
+*******************************************************************************/
+extern void GATT_Deregister (tGATT_IF gatt_if);
+
+/*******************************************************************************
+**
+** Function         GATT_StartIf
+**
+** Description      This function is called after registration to start receiving
+**                  callbacks for registered interface.  Function may call back
+**                  with connection status and queued notifications
+**
+** Parameter        gatt_if: applicaiton interface.
+**
+** Returns          None
+**
+*******************************************************************************/
+extern  void GATT_StartIf (tGATT_IF gatt_if);
+
+/*******************************************************************************
+**
+** Function         GATT_Connect
+**
+** Description      This function initiate a connecttion to a remote device on GATT
+**                  channel.
+**
+** Parameters       gatt_if: applicaiton interface
+**                  bd_addr: peer device address.
+**                  is_direct: is a direct connection or a background auto connection
+**                  transport : Physical transport for GATT connection (BR/EDR or LE)
+**                  opportunistic: will not keep device connected if other apps
+**                      disconnect, will not update connected apps counter, when
+**                      disconnected won't cause physical disconnection.
+**
+** Returns          true if connection started; false if connection start failure.
+**
+*******************************************************************************/
+extern bool GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr,
+                             bool is_direct, tBT_TRANSPORT transport,
+                             bool opportunistic);
+
+
+/*******************************************************************************
+**
+** Function         GATT_CancelConnect
+**
+** Description      This function terminate the connection initaition to a remote
+**                  device on GATT channel.
+**
+** Parameters       gatt_if: client interface. If 0 used as unconditionally disconnect,
+**                          typically used for direct connection cancellation.
+**                  bd_addr: peer device address.
+**                  is_direct: is a direct conenection or a background auto connection
+**
+** Returns          true if connection started; false if connection start failure.
+**
+*******************************************************************************/
+extern bool    GATT_CancelConnect (tGATT_IF gatt_if, BD_ADDR bd_addr,
+                                   bool    is_direct);
+
+/*******************************************************************************
+**
+** Function         GATT_Disconnect
+**
+** Description      This function disconnect the GATT channel for this registered
+**                  application.
+**
+** Parameters       conn_id: connection identifier.
+**
+** Returns          GATT_SUCCESS if disconnected.
+**
+*******************************************************************************/
+extern tGATT_STATUS GATT_Disconnect (uint16_t conn_id);
+
+
+
+/*******************************************************************************
+**
+** Function         GATT_GetConnectionInfor
+**
+** Description      This function use conn_id to find its associated BD address and applciation
+**                  interface
+**
+** Parameters        conn_id: connection id  (input)
+**                   p_gatt_if: applicaiton interface (output)
+**                   bd_addr: peer device address. (output)
+**                   transport :  physical transport of the GATT connection (BR/EDR or LE)
+**
+** Returns          true the ligical link information is found for conn_id
+**
+*******************************************************************************/
+extern bool    GATT_GetConnectionInfor(uint16_t conn_id, tGATT_IF *p_gatt_if,
+                                       BD_ADDR bd_addr, tBT_TRANSPORT *p_transport);
+
+
+/*******************************************************************************
+**
+** Function         GATT_GetConnIdIfConnected
+**
+** Description      This function find the conn_id if the logical link for BD address
+**                  and applciation interface is connected
+**
+** Parameters        gatt_if: applicaiton interface (input)
+**                   bd_addr: peer device address. (input)
+**                   p_conn_id: connection id  (output)
+**                   transport :  physical transport of the GATT connection (BR/EDR or LE)
+**
+** Returns          true the ligical link is connected
+**
+*******************************************************************************/
+extern bool    GATT_GetConnIdIfConnected(tGATT_IF gatt_if, BD_ADDR bd_addr,
+                                         uint16_t *p_conn_id, tBT_TRANSPORT transport);
+
+
+/*******************************************************************************
+**
+** Function         GATT_Listen
+**
+** Description      This function start or stop LE advertisement and listen for
+**                  connection.
+**
+** Parameters       start: is a direct conenection or a background auto connection
+**
+**
+*******************************************************************************/
+extern void GATT_Listen(bool start);
+
+/*******************************************************************************
+**
+** Function         GATT_ConfigServiceChangeCCC
+**
+** Description      Configure service change indication on remote device
+**
+** Returns          None.
+**
+*******************************************************************************/
+extern void GATT_ConfigServiceChangeCCC (BD_ADDR remote_bda, bool    enable,
+                                                    tBT_TRANSPORT transport);
+
+// Enables the GATT profile on the device.
+// It clears out the control blocks, and registers with L2CAP.
+extern void gatt_init(void);
+
+// Frees resources used by the GATT profile.
+extern void gatt_free(void);
+
+// Link encryption complete notification for all encryption process
+// initiated outside GATT.
+extern void gatt_notify_enc_cmpl(BD_ADDR bd_addr);
+
+// Reset bg device list.
+extern void gatt_reset_bgdev_list(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* GATT_API_H */
diff --git a/bt/stack/include/gattdefs.h b/bt/stack/include/gattdefs.h
new file mode 100644
index 0000000..3edfa8b
--- /dev/null
+++ b/bt/stack/include/gattdefs.h
@@ -0,0 +1,124 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 internally used ATT definitions
+ *
+ ******************************************************************************/
+
+#ifndef  _GATTDEFS_H
+#define  _GATTDEFS_H
+
+#define GATT_ILLEGAL_UUID            0
+
+/* GATT attribute types
+*/
+#define GATT_UUID_PRI_SERVICE           0x2800
+#define GATT_UUID_SEC_SERVICE           0x2801
+#define GATT_UUID_INCLUDE_SERVICE       0x2802
+#define GATT_UUID_CHAR_DECLARE          0x2803      /*  Characteristic Declaration*/
+
+#define GATT_UUID_CHAR_EXT_PROP         0x2900      /*	Characteristic Extended Properties */
+#define GATT_UUID_CHAR_DESCRIPTION      0x2901      /*  Characteristic User Description*/
+#define GATT_UUID_CHAR_CLIENT_CONFIG    0x2902      /*  Client Characteristic Configuration */
+#define GATT_UUID_CHAR_SRVR_CONFIG      0x2903      /*  Server Characteristic Configuration */
+#define GATT_UUID_CHAR_PRESENT_FORMAT   0x2904      /*  Characteristic Presentation Format*/
+#define GATT_UUID_CHAR_AGG_FORMAT       0x2905      /*  Characteristic Aggregate Format*/
+#define GATT_UUID_CHAR_VALID_RANGE       0x2906      /*  Characteristic Valid Range */
+#define GATT_UUID_EXT_RPT_REF_DESCR     0x2907
+#define GATT_UUID_RPT_REF_DESCR         0x2908
+
+
+/* GAP Profile Attributes
+*/
+#define GATT_UUID_GAP_DEVICE_NAME        0x2A00
+#define GATT_UUID_GAP_ICON               0x2A01
+#define GATT_UUID_GAP_PREF_CONN_PARAM    0x2A04
+#define GATT_UUID_GAP_CENTRAL_ADDR_RESOL 0x2AA6
+
+/* Attribute Profile Attribute UUID */
+#define GATT_UUID_GATT_SRV_CHGD          0x2A05
+/* Attribute Protocol Test */
+
+/* Link Loss Service */
+#define GATT_UUID_ALERT_LEVEL           0x2A06      /* Alert Level */
+#define GATT_UUID_TX_POWER_LEVEL        0x2A07      /* TX power level */
+
+/* Time Profile */
+/* Current Time Service */
+#define GATT_UUID_CURRENT_TIME          0x2A2B      /* Current Time */
+#define GATT_UUID_LOCAL_TIME_INFO       0x2A0F      /* Local time info */
+#define GATT_UUID_REF_TIME_INFO         0x2A14      /* reference time information */
+
+/* NwA Profile */
+#define GATT_UUID_NW_STATUS             0x2A18      /* network availability status */
+#define GATT_UUID_NW_TRIGGER            0x2A1A      /* Network availability trigger */
+
+/* phone alert */
+#define GATT_UUID_ALERT_STATUS          0x2A3F    /* alert status */
+#define GATT_UUID_RINGER_CP             0x2A40    /* ringer control point */
+#define GATT_UUID_RINGER_SETTING        0x2A41    /* ringer setting */
+
+/* Glucose Service */
+#define GATT_UUID_GM_MEASUREMENT        0x2A18
+#define GATT_UUID_GM_CONTEXT            0x2A34
+#define GATT_UUID_GM_CONTROL_POINT      0x2A52
+#define GATT_UUID_GM_FEATURE            0x2A51
+
+/* device infor characteristic */
+#define GATT_UUID_SYSTEM_ID             0x2A23
+#define GATT_UUID_MODEL_NUMBER_STR      0x2A24
+#define GATT_UUID_SERIAL_NUMBER_STR     0x2A25
+#define GATT_UUID_FW_VERSION_STR        0x2A26
+#define GATT_UUID_HW_VERSION_STR        0x2A27
+#define GATT_UUID_SW_VERSION_STR        0x2A28
+#define GATT_UUID_MANU_NAME             0x2A29
+#define GATT_UUID_IEEE_DATA             0x2A2A
+#define GATT_UUID_PNP_ID                0x2A50
+
+/* HID characteristics */
+#define GATT_UUID_HID_INFORMATION       0x2A4A
+#define GATT_UUID_HID_REPORT_MAP        0x2A4B
+#define GATT_UUID_HID_CONTROL_POINT     0x2A4C
+#define GATT_UUID_HID_REPORT            0x2A4D
+#define GATT_UUID_HID_PROTO_MODE        0x2A4E
+#define GATT_UUID_HID_BT_KB_INPUT       0x2A22
+#define GATT_UUID_HID_BT_KB_OUTPUT      0x2A32
+#define GATT_UUID_HID_BT_MOUSE_INPUT    0x2A33
+
+/* Battery Service char */
+#define GATT_UUID_BATTERY_LEVEL         0x2A19
+
+#define GATT_UUID_SC_CONTROL_POINT      0x2A55
+#define GATT_UUID_SENSOR_LOCATION       0x2A5D
+
+/* RUNNERS SPEED AND CADENCE SERVICE      */
+#define GATT_UUID_RSC_MEASUREMENT       0x2A53
+#define GATT_UUID_RSC_FEATURE           0x2A54
+
+/* CYCLING SPEED AND CADENCE SERVICE      */
+#define GATT_UUID_CSC_MEASUREMENT       0x2A5B
+#define GATT_UUID_CSC_FEATURE           0x2A5C
+
+
+/* Scan Parameter charatceristics */
+#define GATT_UUID_SCAN_INT_WINDOW       0x2A4F
+#define GATT_UUID_SCAN_REFRESH          0x2A31
+
+#endif
diff --git a/bt/stack/include/hcidefs.h b/bt/stack/include/hcidefs.h
new file mode 100644
index 0000000..c064501
--- /dev/null
+++ b/bt/stack/include/hcidefs.h
@@ -0,0 +1,2598 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-2014 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.
+ *
+ ******************************************************************************/
+
+#ifndef HCIDEFS_H
+#define HCIDEFS_H
+
+#define HCI_PROTO_VERSION     0x01      /* Version for BT spec 1.1          */
+#define HCI_PROTO_VERSION_1_2 0x02      /* Version for BT spec 1.2          */
+#define HCI_PROTO_VERSION_2_0 0x03      /* Version for BT spec 2.0          */
+#define HCI_PROTO_VERSION_2_1 0x04      /* Version for BT spec 2.1 [Lisbon] */
+#define HCI_PROTO_VERSION_3_0 0x05      /* Version for BT spec 3.0          */
+#define HCI_PROTO_VERSION_4_0 0x06      /* Version for BT spec 4.0          */
+#define HCI_PROTO_VERSION_4_1 0x07      /* Version for BT spec 4.1          */
+#define HCI_PROTO_VERSION_4_2 0x08      /* Version for BT spec 4.2          */
+
+/*
+**  Definitions for HCI groups
+*/
+#define HCI_GRP_LINK_CONTROL_CMDS       (0x01 << 10)            /* 0x0400 */
+#define HCI_GRP_LINK_POLICY_CMDS        (0x02 << 10)            /* 0x0800 */
+#define HCI_GRP_HOST_CONT_BASEBAND_CMDS (0x03 << 10)            /* 0x0C00 */
+#define HCI_GRP_INFORMATIONAL_PARAMS    (0x04 << 10)            /* 0x1000 */
+#define HCI_GRP_STATUS_PARAMS           (0x05 << 10)            /* 0x1400 */
+#define HCI_GRP_TESTING_CMDS            (0x06 << 10)            /* 0x1800 */
+
+#define HCI_GRP_VENDOR_SPECIFIC         (0x3F << 10)            /* 0xFC00 */
+
+/* Group occupies high 6 bits of the HCI command rest is opcode itself */
+#define HCI_OGF(p)  (uint8_t)((0xFC00 & (p)) >> 10)
+#define HCI_OCF(p)  ( 0x3FF & (p))
+
+/*
+**  Definitions for Link Control Commands
+*/
+/* Following opcode is used only in command complete event for flow control */
+#define HCI_COMMAND_NONE                0x0000
+
+/* Commands of HCI_GRP_LINK_CONTROL_CMDS group */
+#define HCI_INQUIRY                     (0x0001 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_INQUIRY_CANCEL              (0x0002 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_PERIODIC_INQUIRY_MODE       (0x0003 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_EXIT_PERIODIC_INQUIRY_MODE  (0x0004 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CREATE_CONNECTION           (0x0005 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_DISCONNECT                  (0x0006 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ADD_SCO_CONNECTION          (0x0007 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CREATE_CONNECTION_CANCEL    (0x0008 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ACCEPT_CONNECTION_REQUEST   (0x0009 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_REJECT_CONNECTION_REQUEST   (0x000A | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_LINK_KEY_REQUEST_REPLY      (0x000B | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_LINK_KEY_REQUEST_NEG_REPLY  (0x000C | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_PIN_CODE_REQUEST_REPLY      (0x000D | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_PIN_CODE_REQUEST_NEG_REPLY  (0x000E | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CHANGE_CONN_PACKET_TYPE     (0x000F | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_AUTHENTICATION_REQUESTED    (0x0011 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_SET_CONN_ENCRYPTION         (0x0013 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CHANGE_CONN_LINK_KEY        (0x0015 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_MASTER_LINK_KEY             (0x0017 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_RMT_NAME_REQUEST            (0x0019 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_RMT_NAME_REQUEST_CANCEL     (0x001A | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_RMT_FEATURES           (0x001B | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_RMT_EXT_FEATURES       (0x001C | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_RMT_VERSION_INFO       (0x001D | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_RMT_CLOCK_OFFSET       (0x001F | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_LMP_HANDLE             (0x0020 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_SETUP_ESCO_CONNECTION       (0x0028 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ACCEPT_ESCO_CONNECTION      (0x0029 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_REJECT_ESCO_CONNECTION      (0x002A | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_IO_CAPABILITY_REQUEST_REPLY (0x002B | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_USER_CONF_REQUEST_REPLY     (0x002C | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_USER_CONF_VALUE_NEG_REPLY   (0x002D | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_USER_PASSKEY_REQ_REPLY      (0x002E | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_USER_PASSKEY_REQ_NEG_REPLY  (0x002F | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_REM_OOB_DATA_REQ_REPLY      (0x0030 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_REM_OOB_DATA_REQ_NEG_REPLY  (0x0033 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_IO_CAP_REQ_NEG_REPLY        (0x0034 | HCI_GRP_LINK_CONTROL_CMDS)
+
+/* AMP HCI */
+#define HCI_CREATE_PHYSICAL_LINK        (0x0035 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ACCEPT_PHYSICAL_LINK        (0x0036 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_DISCONNECT_PHYSICAL_LINK    (0x0037 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CREATE_LOGICAL_LINK         (0x0038 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ACCEPT_LOGICAL_LINK         (0x0039 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_DISCONNECT_LOGICAL_LINK     (0x003A | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_LOGICAL_LINK_CANCEL         (0x003B | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_FLOW_SPEC_MODIFY            (0x003C | HCI_GRP_LINK_CONTROL_CMDS)
+
+#define HCI_ENH_SETUP_ESCO_CONNECTION   (0x003D | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ENH_ACCEPT_ESCO_CONNECTION  (0x003E | HCI_GRP_LINK_CONTROL_CMDS)
+
+/* ConnectionLess Broadcast */
+#define HCI_TRUNCATED_PAGE              (0x003F | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_TRUNCATED_PAGE_CANCEL       (0x0040 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_SET_CLB                     (0x0041 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_RECEIVE_CLB                 (0x0042 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_START_SYNC_TRAIN            (0x0043 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_RECEIVE_SYNC_TRAIN          (0x0044 | HCI_GRP_LINK_CONTROL_CMDS)
+
+#define HCI_LINK_CTRL_CMDS_FIRST        HCI_INQUIRY
+#define HCI_LINK_CTRL_CMDS_LAST         HCI_RECEIVE_SYNC_TRAIN
+
+/* Commands of HCI_GRP_LINK_POLICY_CMDS */
+#define HCI_HOLD_MODE                   (0x0001 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_SNIFF_MODE                  (0x0003 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_EXIT_SNIFF_MODE             (0x0004 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_PARK_MODE                   (0x0005 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_EXIT_PARK_MODE              (0x0006 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_QOS_SETUP                   (0x0007 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_ROLE_DISCOVERY              (0x0009 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_SWITCH_ROLE                 (0x000B | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_READ_POLICY_SETTINGS        (0x000C | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_WRITE_POLICY_SETTINGS       (0x000D | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_READ_DEF_POLICY_SETTINGS    (0x000E | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_WRITE_DEF_POLICY_SETTINGS   (0x000F | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_FLOW_SPECIFICATION          (0x0010 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_SNIFF_SUB_RATE              (0x0011 | HCI_GRP_LINK_POLICY_CMDS)
+
+#define HCI_LINK_POLICY_CMDS_FIRST      HCI_HOLD_MODE
+#define HCI_LINK_POLICY_CMDS_LAST       HCI_SNIFF_SUB_RATE
+
+
+/* Commands of HCI_GRP_HOST_CONT_BASEBAND_CMDS */
+#define HCI_SET_EVENT_MASK              (0x0001 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_RESET                       (0x0003 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_EVENT_FILTER            (0x0005 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_FLUSH                       (0x0008 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PIN_TYPE               (0x0009 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PIN_TYPE              (0x000A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_CREATE_NEW_UNIT_KEY         (0x000B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_GET_MWS_TRANS_LAYER_CFG     (0x000C | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_STORED_LINK_KEY        (0x000D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_STORED_LINK_KEY       (0x0011 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_DELETE_STORED_LINK_KEY      (0x0012 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_CHANGE_LOCAL_NAME           (0x0013 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_LOCAL_NAME             (0x0014 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_CONN_ACCEPT_TOUT       (0x0015 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_CONN_ACCEPT_TOUT      (0x0016 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGE_TOUT              (0x0017 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGE_TOUT             (0x0018 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_SCAN_ENABLE            (0x0019 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_SCAN_ENABLE           (0x001A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGESCAN_CFG           (0x001B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGESCAN_CFG          (0x001C | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_INQUIRYSCAN_CFG        (0x001D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_INQUIRYSCAN_CFG       (0x001E | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_AUTHENTICATION_ENABLE  (0x001F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_AUTHENTICATION_ENABLE (0x0020 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_ENCRYPTION_MODE        (0x0021 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_ENCRYPTION_MODE       (0x0022 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_CLASS_OF_DEVICE        (0x0023 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_CLASS_OF_DEVICE       (0x0024 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_VOICE_SETTINGS         (0x0025 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_VOICE_SETTINGS        (0x0026 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_AUTO_FLUSH_TOUT        (0x0027 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_AUTO_FLUSH_TOUT       (0x0028 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_NUM_BCAST_REXMITS      (0x0029 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_NUM_BCAST_REXMITS     (0x002A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_HOLD_MODE_ACTIVITY     (0x002B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_HOLD_MODE_ACTIVITY    (0x002C | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_TRANSMIT_POWER_LEVEL   (0x002D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_SCO_FLOW_CTRL_ENABLE   (0x002E | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_SCO_FLOW_CTRL_ENABLE  (0x002F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_HC_TO_HOST_FLOW_CTRL    (0x0031 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_HOST_BUFFER_SIZE            (0x0033 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_HOST_NUM_PACKETS_DONE       (0x0035 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_LINK_SUPER_TOUT        (0x0036 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_LINK_SUPER_TOUT       (0x0037 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_NUM_SUPPORTED_IAC      (0x0038 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_CURRENT_IAC_LAP        (0x0039 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_CURRENT_IAC_LAP       (0x003A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGESCAN_PERIOD_MODE   (0x003B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGESCAN_PERIOD_MODE  (0x003C | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGESCAN_MODE          (0x003D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGESCAN_MODE         (0x003E | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_AFH_CHANNELS            (0x003F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+
+#define HCI_READ_INQSCAN_TYPE           (0x0042 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_INQSCAN_TYPE          (0x0043 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_INQUIRY_MODE           (0x0044 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_INQUIRY_MODE          (0x0045 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGESCAN_TYPE          (0x0046 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGESCAN_TYPE         (0x0047 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_AFH_ASSESSMENT_MODE    (0x0048 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_AFH_ASSESSMENT_MODE   (0x0049 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_EXT_INQ_RESPONSE       (0x0051 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_EXT_INQ_RESPONSE      (0x0052 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_REFRESH_ENCRYPTION_KEY      (0x0053 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_SIMPLE_PAIRING_MODE    (0x0055 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_SIMPLE_PAIRING_MODE   (0x0056 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_LOCAL_OOB_DATA         (0x0057 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_INQ_TX_POWER_LEVEL     (0x0058 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_INQ_TX_POWER_LEVEL    (0x0059 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_ERRONEOUS_DATA_RPT     (0x005A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_ERRONEOUS_DATA_RPT    (0x005B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_ENHANCED_FLUSH              (0x005F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SEND_KEYPRESS_NOTIF         (0x0060 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+
+
+/* AMP HCI */
+#define HCI_READ_LOGICAL_LINK_ACCEPT_TIMEOUT  (0x0061 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT (0x0062 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_EVENT_MASK_PAGE_2             (0x0063 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_LOCATION_DATA                (0x0064 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_LOCATION_DATA               (0x0065 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_FLOW_CONTROL_MODE            (0x0066 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_FLOW_CONTROL_MODE           (0x0067 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_BE_FLUSH_TOUT                (0x0069 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_BE_FLUSH_TOUT               (0x006A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SHORT_RANGE_MODE                  (0x006B | HCI_GRP_HOST_CONT_BASEBAND_CMDS) /* 802.11 only */
+#define HCI_READ_LE_HOST_SUPPORT              (0x006C | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_LE_HOST_SUPPORT             (0x006D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+
+
+/* MWS coexistence */
+#define HCI_SET_MWS_CHANNEL_PARAMETERS          (0x006E | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_EXTERNAL_FRAME_CONFIGURATION    (0x006F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_MWS_SIGNALING                   (0x0070 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_MWS_TRANSPORT_LAYER             (0x0071 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_MWS_SCAN_FREQUENCY_TABLE        (0x0072 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_MWS_PATTERN_CONFIGURATION       (0x0073 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+
+/* Connectionless Broadcast */
+#define HCI_SET_RESERVED_LT_ADDR                (0x0074 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_DELETE_RESERVED_LT_ADDR             (0x0075 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_CLB_DATA                      (0x0076 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_SYNC_TRAIN_PARAM               (0x0077 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_SYNC_TRAIN_PARAM              (0x0078 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+
+#define HCI_READ_SECURE_CONNS_SUPPORT           (0x0079 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_SECURE_CONNS_SUPPORT          (0x007A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_CONT_BASEBAND_CMDS_FIRST    HCI_SET_EVENT_MASK
+#define HCI_CONT_BASEBAND_CMDS_LAST     HCI_READ_SYNC_TRAIN_PARAM
+
+
+/* Commands of HCI_GRP_INFORMATIONAL_PARAMS group */
+#define HCI_READ_LOCAL_VERSION_INFO     (0x0001 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_LOCAL_SUPPORTED_CMDS   (0x0002 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_LOCAL_FEATURES         (0x0003 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_LOCAL_EXT_FEATURES     (0x0004 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_BUFFER_SIZE            (0x0005 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_COUNTRY_CODE           (0x0007 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_BD_ADDR                (0x0009 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_DATA_BLOCK_SIZE        (0x000A | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_LOCAL_SUPPORTED_CODECS (0x000B | HCI_GRP_INFORMATIONAL_PARAMS)
+
+#define HCI_INFORMATIONAL_CMDS_FIRST    HCI_READ_LOCAL_VERSION_INFO
+#define HCI_INFORMATIONAL_CMDS_LAST     HCI_READ_LOCAL_SUPPORTED_CODECS
+
+
+/* Commands of HCI_GRP_STATUS_PARAMS group */
+#define HCI_READ_FAILED_CONTACT_COUNT   (0x0001 | HCI_GRP_STATUS_PARAMS)
+#define HCI_RESET_FAILED_CONTACT_COUNT  (0x0002 | HCI_GRP_STATUS_PARAMS)
+#define HCI_GET_LINK_QUALITY            (0x0003 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_RSSI                   (0x0005 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_AFH_CH_MAP             (0x0006 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_CLOCK                  (0x0007 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_ENCR_KEY_SIZE          (0x0008 | HCI_GRP_STATUS_PARAMS)
+
+/* AMP HCI */
+#define HCI_READ_LOCAL_AMP_INFO         (0x0009 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_LOCAL_AMP_ASSOC        (0x000A | HCI_GRP_STATUS_PARAMS)
+#define HCI_WRITE_REMOTE_AMP_ASSOC      (0x000B | HCI_GRP_STATUS_PARAMS)
+
+#define HCI_STATUS_PARAMS_CMDS_FIRST    HCI_READ_FAILED_CONTACT_COUNT
+#define HCI_STATUS_PARAMS_CMDS_LAST     HCI_WRITE_REMOTE_AMP_ASSOC
+
+/* Commands of HCI_GRP_TESTING_CMDS group */
+#define HCI_READ_LOOPBACK_MODE          (0x0001 | HCI_GRP_TESTING_CMDS)
+#define HCI_WRITE_LOOPBACK_MODE         (0x0002 | HCI_GRP_TESTING_CMDS)
+#define HCI_ENABLE_DEV_UNDER_TEST_MODE  (0x0003 | HCI_GRP_TESTING_CMDS)
+#define HCI_WRITE_SIMP_PAIR_DEBUG_MODE  (0x0004 | HCI_GRP_TESTING_CMDS)
+
+/* AMP HCI */
+#define HCI_ENABLE_AMP_RCVR_REPORTS     (0x0007 | HCI_GRP_TESTING_CMDS)
+#define HCI_AMP_TEST_END                (0x0008 | HCI_GRP_TESTING_CMDS)
+#define HCI_AMP_TEST                    (0x0009 | HCI_GRP_TESTING_CMDS)
+
+#define HCI_TESTING_CMDS_FIRST          HCI_READ_LOOPBACK_MODE
+#define HCI_TESTING_CMDS_LAST           HCI_AMP_TEST
+
+#define HCI_VENDOR_CMDS_FIRST           0x0001
+#define HCI_VENDOR_CMDS_LAST            0xFFFF
+#define HCI_VSC_MULTI_AV_HANDLE         0x0AAA
+#define HCI_VSC_BURST_MODE_HANDLE       0x0BBB
+
+/* BLE HCI */
+#define HCI_GRP_BLE_CMDS                (0x08 << 10)
+/* Commands of BLE Controller setup and configuration */
+#define HCI_BLE_SET_EVENT_MASK          (0x0001 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_BUFFER_SIZE        (0x0002 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_LOCAL_SPT_FEAT     (0x0003 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_LOCAL_SPT_FEAT    (0x0004 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_RANDOM_ADDR       (0x0005 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_ADV_PARAMS        (0x0006 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_ADV_CHNL_TX_POWER  (0x0007 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_ADV_DATA          (0x0008 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_SCAN_RSP_DATA     (0x0009 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_ADV_ENABLE        (0x000A | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_SCAN_PARAMS       (0x000B | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_SCAN_ENABLE       (0x000C | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_CREATE_LL_CONN          (0x000D | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_CREATE_CONN_CANCEL      (0x000E | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_WHITE_LIST_SIZE    (0x000F | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_CLEAR_WHITE_LIST        (0x0010 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_ADD_WHITE_LIST          (0x0011 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_REMOVE_WHITE_LIST       (0x0012 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_UPD_LL_CONN_PARAMS      (0x0013 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_SET_HOST_CHNL_CLASS     (0x0014 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_CHNL_MAP           (0x0015 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_REMOTE_FEAT        (0x0016 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_ENCRYPT                 (0x0017 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_RAND                    (0x0018 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_START_ENC               (0x0019 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_LTK_REQ_REPLY           (0x001A | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_LTK_REQ_NEG_REPLY       (0x001B | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_SUPPORTED_STATES   (0x001C | HCI_GRP_BLE_CMDS)
+                            /*0x001D, 0x001E and 0x001F are reserved*/
+#define HCI_BLE_RECEIVER_TEST           (0x001D | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_TRANSMITTER_TEST        (0x001E | HCI_GRP_BLE_CMDS)
+/* BLE TEST COMMANDS */
+#define HCI_BLE_TEST_END                (0x001F | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_RC_PARAM_REQ_REPLY      (0x0020 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_RC_PARAM_REQ_NEG_REPLY  (0x0021 | HCI_GRP_BLE_CMDS)
+
+#define HCI_BLE_SET_DATA_LENGTH             (0x0022 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_DEFAULT_DATA_LENGTH    (0x0023 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_DEFAULT_DATA_LENGTH   (0x0024 | HCI_GRP_BLE_CMDS)
+
+#define HCI_BLE_ADD_DEV_RESOLVING_LIST      (0x0027 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_RM_DEV_RESOLVING_LIST       (0x0028 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_CLEAR_RESOLVING_LIST        (0x0029 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_RESOLVING_LIST_SIZE    (0x002A | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_RESOLVABLE_ADDR_PEER   (0x002B | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_RESOLVABLE_ADDR_LOCAL  (0x002C | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_SET_ADDR_RESOLUTION_ENABLE  (0x002D | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_SET_RAND_PRIV_ADDR_TIMOUT   (0x002E | HCI_GRP_BLE_CMDS)
+
+/* LE Get Vendor Capabilities Command OCF */
+#define HCI_BLE_VENDOR_CAP_OCF    (0x0153 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Multi adv OCF */
+#define HCI_BLE_MULTI_ADV_OCF     (0x0154 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Batch scan OCF */
+#define HCI_BLE_BATCH_SCAN_OCF    (0x0156 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* ADV filter OCF */
+#define HCI_BLE_ADV_FILTER_OCF    (0x0157 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Tracking OCF */
+#define HCI_BLE_TRACK_ADV_OCF     (0x0158 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Energy info OCF */
+#define HCI_BLE_ENERGY_INFO_OCF   (0x0159 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Extended BLE Scan parameters OCF */
+#define HCI_BLE_EXTENDED_SCAN_PARAMS_OCF  (0x015A | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Controller debug info OCF */
+#define HCI_CONTROLLER_DEBUG_INFO_OCF     (0x015B | HCI_GRP_VENDOR_SPECIFIC)
+
+/* subcode for multi adv feature */
+#define BTM_BLE_MULTI_ADV_SET_PARAM                     0x01
+#define BTM_BLE_MULTI_ADV_WRITE_ADV_DATA                0x02
+#define BTM_BLE_MULTI_ADV_WRITE_SCAN_RSP_DATA           0x03
+#define BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR               0x04
+#define BTM_BLE_MULTI_ADV_ENB                           0x05
+
+/* multi adv VSE subcode */
+#define HCI_VSE_SUBCODE_BLE_MULTI_ADV_ST_CHG       0x55 /* multi adv instance state change */
+
+/* subcode for batch scan feature */
+#define BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE      0x01
+#define BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM           0x02
+#define BTM_BLE_BATCH_SCAN_SET_PARAMS                  0x03
+#define BTM_BLE_BATCH_SCAN_READ_RESULTS                0x04
+
+/* batch scan VSE subcode */
+#define HCI_VSE_SUBCODE_BLE_THRESHOLD_SUB_EVT      0x54 /* Threshold event */
+
+/* tracking sub event */
+#define HCI_VSE_SUBCODE_BLE_TRACKING_SUB_EVT       0x56 /* Tracking event */
+
+/* LE supported states definition */
+#define HCI_LE_ADV_STATE          0x00000001
+#define HCI_LE_SCAN_STATE         0x00000002
+#define HCI_LE_INIT_STATE         0x00000004
+#define HCI_LE_CONN_SL_STATE      0x00000008
+#define HCI_LE_ADV_SCAN_STATE     0x00000010
+#define HCI_LE_ADV_INIT_STATE     0x00000020
+#define HCI_LE_ADV_MA_STATE       0x00000040
+#define HCI_LE_ADV_SL_STATE       0x00000080
+#define HCI_LE_SCAN_INIT_STATE    0x00000100
+#define HCI_LE_SCAN_MA_STATE      0x00000200
+#define HCI_LE_SCAN_SL_STATE      0x00000400
+#define HCI_LE_INIT_MA_STATE      0x00000800
+
+/* LE Supported States */
+/* Non Connectable Adv state is supported. 0x0000000000000001 */
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_MASK          0x01
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_OFF           0
+#define HCI_LE_STATES_NON_CONN_ADV_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_NON_CONN_ADV_OFF] & HCI_SUPP_LE_STATES_NON_CONN_ADV_MASK)
+
+/*Scanneable Connectable Adv state  is supported. 0x0000000000000002 */
+#define HCI_SUPP_LE_STATES_SCAN_ADV_MASK          0x02
+#define HCI_SUPP_LE_STATESSCAN_ADV_OFF           0
+#define HCI_LE_STATES_SCAN_ADV_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATESSCAN_ADV_OFF] & HCI_SUPP_LE_STATES_SCAN_ADV_MASK)
+
+/* Connectable Adv state is supported. 0x0000000000000004 */
+#define HCI_SUPP_LE_STATES_CONN_ADV_MASK          0x04
+#define HCI_SUPP_LE_STATES_CONN_ADV_OFF           0
+#define HCI_LE_STATES_CONN_ADV_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_CONN_ADV_OFF] & HCI_SUPP_LE_STATES_CONN_ADV_MASK)
+
+/* Hi duty Cycle Directed Adv state is supported. 0x0000000000000008 */
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASK          0x08
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_OFF           0
+#define HCI_LE_STATES_HI_DUTY_DIR_ADV_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_OFF] & HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASK)
+
+/* Passive Scan state is supported. 0x0000000000000010 */
+#define HCI_SUPP_LE_STATES_PASS_SCAN_MASK          0x10
+#define HCI_SUPP_LE_STATES_PASS_SCAN_OFF           0
+#define HCI_LE_STATES_PASS_SCAN_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_PASS_SCAN_OFF] & HCI_SUPP_LE_STATES_PASS_SCAN_MASK)
+
+/* Active Scan state is supported. 0x0000000000000020 */
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASK          0x20
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_OFF           0
+#define HCI_LE_STATES_ACTIVE_SCAN_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_ACTIVE_SCAN_OFF] & HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASK)
+
+/* Initiating state is supported. 0x0000000000000040 (or connection state in master role is also supported) */
+#define HCI_SUPP_LE_STATES_INIT_MASK          0x40
+#define HCI_SUPP_LE_STATES_INIT_OFF           0
+#define HCI_LE_STATES_INIT_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_INIT_OFF] & HCI_SUPP_LE_STATES_INIT_MASK)
+
+/*connection state in slave  role is also supported. 0x0000000000000080 */
+#define HCI_SUPP_LE_STATES_SLAVE_MASK          0x80
+#define HCI_SUPP_LE_STATES_SLAVE_OFF           0
+#define HCI_LE_STATES_SLAVE_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_SLAVE_OFF] & HCI_SUPP_LE_STATES_SLAVE_MASK)
+
+/* Non Connectable Adv state and Passive Scanning State combination is supported. 0x0000000000000100 */
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_MASK          0x01
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_OFF           1
+#define HCI_LE_STATES_NON_CONN_ADV_PASS_SCAN_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_OFF] & HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_MASK)
+
+/*Scannable Adv state and Passive Scanning State combination is supported. 0x0000000000000200 */
+#define HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_MASK          0x02
+#define HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_OFF           1
+#define HCI_LE_STATES_SCAN_ADV_PASS_SCAN_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_OFF] & HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_MASK)
+
+/*Connectable Adv state and Passive Scanning State combination is supported. 0x0000000000000400 */
+#define HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_MASK          0x04
+#define HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_OFF           1
+#define HCI_LE_STATES_CONN_ADV_PASS_SCAN_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_OFF] & HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_MASK)
+
+/*High Duty Cycl Directed ADv and Passive Scanning State combination is supported. 0x0000000000000800 */
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_MASK          0x08
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_OFF           1
+#define HCI_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_MASK] & HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_OFF)
+
+/*Non Connectable Adv state and Passive Scanning State combination is supported. 0x0000000000001000 */
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_MASK          0x10
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_OFF           1
+#define HCI_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_OFF] & HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_MASK)
+
+/*Scannable Adv state and Active Scanning State combination is supported. 0x0000000000002000 */
+#define HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_MASK          0x20
+#define HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_OFF           1
+#define HCI_LE_STATES_SCAN_ADV_ACTIVE_SCAN_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_OFF] & HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_MASK)
+
+/*Connectable Adv state and Active Scanning State combination is supported. 0x0000000000004000 */
+#define HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_MASK          0x40
+#define HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_OFF           1
+#define HCI_LE_STATES_CONN_ADV_ACTIVE_SCAN_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_OFF] & HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_MASK)
+
+/*High Duty Cycl Directed ADv and ACtive Scanning State combination is supported. 0x0000000000008000 */
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_MASK          0x80
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_OFF           1
+#define HCI_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_MASK] & HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_OFF)
+
+/*Non-Connectable Adv state and Initiating State combination is supported. 0x0000000000010000 */
+#define HCI_SUPP_LE_STATES_NON_CONN_INIT_MASK          0x01
+#define HCI_SUPP_LE_STATES_NON_CONN_INIT_OFF           2
+#define HCI_LE_STATES_NON_CONN_INIT_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_NON_CONN_INIT_OFF] & HCI_SUPP_LE_STATES_NON_CONN_INIT_MASK)
+
+/* Scannable Adv state and Initiating State combination is supported. 0x0000000000020000 */
+#define HCI_SUPP_LE_STATES_SCAN_ADV_INIT_MASK          0x02
+#define HCI_SUPP_LE_STATES_SCAN_ADV_INIT_OFF           2
+#define HCI_LE_STATES_SCAN_ADV_INIT_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_SCAN_ADV_INIT_OFF] & HCI_SUPP_LE_STATES_SCAN_ADV_INIT_MASK)
+
+/* Non-Connectable Adv state and Master Role combination is supported. 0x0000000000040000 */
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_MASK          0x04
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_OFF           2
+#define HCI_LE_STATES_NON_CONN_ADV_MASTER_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_OFF] & HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_MASK)
+
+/*Scannable Adv state and Master Role combination is supported. 0x0000000000040000 */
+#define HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_MASK          0x08
+#define HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_OFF           2
+#define HCI_LE_STATES_SCAN_ADV_MASTER_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_OFF] & HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_MASK)
+
+/* Non-Connectable Adv and Slave Role combination is supported. 0x000000000100000 */
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_MASK          0x10
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_OFF           2
+#define HCI_LE_STATES_NON_CONN_ADV_SLAVE_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_OFF] & HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_MASK)
+
+/*Scannable Adv and Slave Role combination is supported. 0x000000000200000 */
+#define HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_MASK          0x20
+#define HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_OFF           2
+#define HCI_LE_STATES_SCAN_ADV_SLAVE_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_OFF] & HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_MASK)
+
+/*Passive Scan and Initiating State combination is supported. 0x000000000400000 */
+#define HCI_SUPP_LE_STATES_PASS_SCAN_INIT_MASK          0x40
+#define HCI_SUPP_LE_STATES_PASS_SCAN_INIT_OFF           2
+#define HCI_LE_STATES_PASS_SCAN_INIT_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_PASS_SCAN_INIT_OFF] & HCI_SUPP_LE_STATES_PASS_SCAN_INIT_MASK)
+
+/*Active Scan and Initiating State combination is supported. 0x000000000800000 */
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_MASK          0x80
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_OFF           2
+#define HCI_LE_STATES_ACTIVE_SCAN_INIT_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_OFF] & HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_MASK)
+
+/*Passive Scan and Master Role combination is supported. 0x000000001000000 */
+#define HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_MASK          0x01
+#define HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_OFF           3
+#define HCI_LE_STATES_PASS_SCAN_MASTER_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_OFF] & HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_MASK)
+
+/*Active Scan and Master Role combination is supported. 0x000000002000000 */
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_MASK          0x02
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_OFF           3
+#define HCI_LE_STATES_ACTIVE_SCAN_MASTER_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_OFF] & HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_MASK)
+
+/*Passive Scan and Slave Role combination is supported. 0x000000004000000 */
+#define HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_MASK          0x04
+#define HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_OFF           3
+#define HCI_LE_STATES_PASS_SCAN_SLAVE_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_OFF] & HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_MASK)
+
+/*Active Scan and Slave Role combination is supported. 0x000000008000000 */
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_MASK          0x08
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_OFF           3
+#define HCI_LE_STATES_ACTIVE_SCAN_SLAVE_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_OFF] & HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_MASK)
+
+/*Link Layer Topology Added States Combo */
+/*Initiating State and Master Role combination supported.
+  Master Role and Master Role combination is also supported. 0x0000000010000000 */
+#define HCI_SUPP_LE_STATES_INIT_MASTER_MASK          0x10
+#define HCI_SUPP_LE_STATES_INIT_MASTER_OFF           3
+#define HCI_LE_STATES_INIT_MASTER_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_INIT_MASTER_OFF] & HCI_SUPP_LE_STATES_INIT_MASTER_MASK)
+
+/*Low Duty Cycle Directed Advertising State . 0x0000000020000000 */
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASK          0x20
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_OFF           3
+#define HCI_LE_STATES_LOW_DUTY_DIR_ADV_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_LOW_DUTY_DIR_ADV_OFF] & HCI_SUPP_LE_STATES_LOW_DUTY_DIR_ADV_MASK)
+
+/*Low Duty Cycle Directed Advertising State and Passive scan combination. 0x0000000040000000 */
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_MASK          0x40
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_OFF           3
+#define HCI_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_OFF] & HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_MASK)
+
+/*Low Duty Cycle Directed Advertising State and Active scan combination . 0x0000000080000000 */
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_MASK          0x80
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_OFF           3
+#define HCI_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_OFF] & HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_MASK)
+
+/* Connectable Advertising State and Initiating State combination supported. 0x0000000100000000 */
+#define HCI_SUPP_LE_STATES_CONN_ADV_INIT_MASK          0x01
+#define HCI_SUPP_LE_STATES_CONN_ADV_INIT_OFF           4
+#define HCI_LE_STATES_CONN_ADV_INIT_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_CONN_ADV_INIT_OFF] & HCI_SUPP_LE_STATES_CONN_ADV_INIT_MASK)
+
+/* High Duty Cycle Directed Advertising State and Initiating State combination supported. */
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_MASK          0x02
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_OFF           4
+#define HCI_LE_STATES_HI_DUTY_DIR_ADV_INIT_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_OFF] & HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_MASK)
+
+/* Low Duty Cycle Directed Advertising State and Initiating State combination supported.*/
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_MASK          0x04
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_OFF           4
+#define HCI_LE_STATES_LO_DUTY_DIR_ADV_INIT_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_OFF] & HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_MASK)
+
+/* Connectable Advertising State and Master Role combination supported.*/
+#define HCI_SUPP_LE_STATES_CONN_ADV_MASTER_MASK          0x08
+#define HCI_SUPP_LE_STATES_CONN_ADV_MASTER_OFF           4
+#define HCI_LE_STATES_CONN_ADV_MASTER_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_CONN_ADV_MASTER_OFF] & HCI_SUPP_LE_STATES_CONN_ADV_MASTER_MASK)
+
+/* High Duty Cycle Directed Advertising State and Master Role combination supported.*/
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_MASK          0x10
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_OFF           4
+#define HCI_LE_STATES_HI_DUTY_DIR_ADV_MASTER_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_OFF] & HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_MASK)
+
+/* Low Duty Cycle Directed Advertising State and Master Role combination supported.*/
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_MASK          0x20
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_OFF           4
+#define HCI_LE_STATES_LO_DUTY_DIR_ADV_MASTER_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_OFF] & HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_MASK)
+
+/* Connectable Advertising State and Slave Role combination supported. */
+#define HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_MASK          0x40
+#define HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_OFF           4
+#define HCI_LE_STATES_CONN_ADV_SLAVE_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_OFF] & HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_MASK)
+
+/* High Duty Cycle Directed Advertising State and slave Role combination supported.*/
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_MASK          0x80
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_OFF           4
+#define HCI_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_OFF] & HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_MASK)
+
+/* Low Duty Cycle Directed Advertising State and slave Role combination supported.*/
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_MASK          0x01
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_OFF           5
+#define HCI_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_OFF] & HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_MASK)
+
+/* Initiating State and Slave Role combination supported.
+   Master Role and Slave Role combination also supported.
+ */
+#define HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_MASK          0x02
+#define HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_OFF           5
+#define HCI_LE_STATES_INIT_MASTER_SLAVE_SUPPORTED(x)      ((x)[HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_OFF] & HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_MASK)
+
+/*
+**  Definitions for HCI Events
+*/
+#define HCI_INQUIRY_COMP_EVT                0x01
+#define HCI_INQUIRY_RESULT_EVT              0x02
+#define HCI_CONNECTION_COMP_EVT             0x03
+#define HCI_CONNECTION_REQUEST_EVT          0x04
+#define HCI_DISCONNECTION_COMP_EVT          0x05
+#define HCI_AUTHENTICATION_COMP_EVT         0x06
+#define HCI_RMT_NAME_REQUEST_COMP_EVT       0x07
+#define HCI_ENCRYPTION_CHANGE_EVT           0x08
+#define HCI_CHANGE_CONN_LINK_KEY_EVT        0x09
+#define HCI_MASTER_LINK_KEY_COMP_EVT        0x0A
+#define HCI_READ_RMT_FEATURES_COMP_EVT      0x0B
+#define HCI_READ_RMT_VERSION_COMP_EVT       0x0C
+#define HCI_QOS_SETUP_COMP_EVT              0x0D
+#define HCI_COMMAND_COMPLETE_EVT            0x0E
+#define HCI_COMMAND_STATUS_EVT              0x0F
+#define HCI_HARDWARE_ERROR_EVT              0x10
+#define HCI_FLUSH_OCCURED_EVT               0x11
+#define HCI_ROLE_CHANGE_EVT                 0x12
+#define HCI_NUM_COMPL_DATA_PKTS_EVT         0x13
+#define HCI_MODE_CHANGE_EVT                 0x14
+#define HCI_RETURN_LINK_KEYS_EVT            0x15
+#define HCI_PIN_CODE_REQUEST_EVT            0x16
+#define HCI_LINK_KEY_REQUEST_EVT            0x17
+#define HCI_LINK_KEY_NOTIFICATION_EVT       0x18
+#define HCI_LOOPBACK_COMMAND_EVT            0x19
+#define HCI_DATA_BUF_OVERFLOW_EVT           0x1A
+#define HCI_MAX_SLOTS_CHANGED_EVT           0x1B
+#define HCI_READ_CLOCK_OFF_COMP_EVT         0x1C
+#define HCI_CONN_PKT_TYPE_CHANGE_EVT        0x1D
+#define HCI_QOS_VIOLATION_EVT               0x1E
+#define HCI_PAGE_SCAN_MODE_CHANGE_EVT       0x1F
+#define HCI_PAGE_SCAN_REP_MODE_CHNG_EVT     0x20
+#define HCI_FLOW_SPECIFICATION_COMP_EVT     0x21
+#define HCI_INQUIRY_RSSI_RESULT_EVT         0x22
+#define HCI_READ_RMT_EXT_FEATURES_COMP_EVT  0x23
+#define HCI_ESCO_CONNECTION_COMP_EVT        0x2C
+#define HCI_ESCO_CONNECTION_CHANGED_EVT     0x2D
+#define HCI_SNIFF_SUB_RATE_EVT              0x2E
+#define HCI_EXTENDED_INQUIRY_RESULT_EVT     0x2F
+#define HCI_ENCRYPTION_KEY_REFRESH_COMP_EVT 0x30
+#define HCI_IO_CAPABILITY_REQUEST_EVT       0x31
+#define HCI_IO_CAPABILITY_RESPONSE_EVT      0x32
+#define HCI_USER_CONFIRMATION_REQUEST_EVT   0x33
+#define HCI_USER_PASSKEY_REQUEST_EVT        0x34
+#define HCI_REMOTE_OOB_DATA_REQUEST_EVT     0x35
+#define HCI_SIMPLE_PAIRING_COMPLETE_EVT     0x36
+#define HCI_LINK_SUPER_TOUT_CHANGED_EVT     0x38
+#define HCI_ENHANCED_FLUSH_COMPLETE_EVT     0x39
+#define HCI_USER_PASSKEY_NOTIFY_EVT         0x3B
+#define HCI_KEYPRESS_NOTIFY_EVT             0x3C
+#define HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT    0x3D
+
+/*#define HCI_GENERIC_AMP_LINK_KEY_NOTIF_EVT  0x3E Removed from spec */
+#define HCI_PHYSICAL_LINK_COMP_EVT          0x40
+#define HCI_CHANNEL_SELECTED_EVT            0x41
+#define HCI_DISC_PHYSICAL_LINK_COMP_EVT     0x42
+#define HCI_PHY_LINK_LOSS_EARLY_WARNING_EVT 0x43
+#define HCI_PHY_LINK_RECOVERY_EVT           0x44
+#define HCI_LOGICAL_LINK_COMP_EVT           0x45
+#define HCI_DISC_LOGICAL_LINK_COMP_EVT      0x46
+#define HCI_FLOW_SPEC_MODIFY_COMP_EVT       0x47
+#define HCI_NUM_COMPL_DATA_BLOCKS_EVT       0x48
+#define HCI_SHORT_RANGE_MODE_COMPLETE_EVT   0x4C
+#define HCI_AMP_STATUS_CHANGE_EVT           0x4D
+#define HCI_SET_TRIGGERED_CLOCK_CAPTURE_EVT 0x4E
+
+/* ULP HCI Event */
+#define HCI_BLE_EVENT                       0x3e
+/* ULP Event sub code */
+#define HCI_BLE_CONN_COMPLETE_EVT           0x01
+#define HCI_BLE_ADV_PKT_RPT_EVT             0x02
+#define HCI_BLE_LL_CONN_PARAM_UPD_EVT       0x03
+#define HCI_BLE_READ_REMOTE_FEAT_CMPL_EVT   0x04
+#define HCI_BLE_LTK_REQ_EVT                 0x05
+#define HCI_BLE_RC_PARAM_REQ_EVT            0x06
+#define HCI_BLE_DATA_LENGTH_CHANGE_EVT      0x07
+#define HCI_BLE_ENHANCED_CONN_COMPLETE_EVT  0x0a
+#define HCI_BLE_DIRECT_ADV_EVT              0x0b
+
+/* Definitions for LE Channel Map */
+#define HCI_BLE_CHNL_MAP_SIZE               5
+
+#define HCI_VENDOR_SPECIFIC_EVT         0xFF  /* Vendor specific events */
+#define HCI_NAP_TRACE_EVT               0xFF  /* was define 0xFE, 0xFD, change to 0xFF
+                                                 because conflict w/ TCI_EVT and per
+                                                 specification compliant */
+
+/*
+**  Defentions for HCI Error Codes that are past in the events
+*/
+#define HCI_SUCCESS                                     0x00
+#define HCI_PENDING                                     0x00
+#define HCI_ERR_ILLEGAL_COMMAND                         0x01
+#define HCI_ERR_NO_CONNECTION                           0x02
+#define HCI_ERR_HW_FAILURE                              0x03
+#define HCI_ERR_PAGE_TIMEOUT                            0x04
+#define HCI_ERR_AUTH_FAILURE                            0x05
+#define HCI_ERR_KEY_MISSING                             0x06
+#define HCI_ERR_MEMORY_FULL                             0x07
+#define HCI_ERR_CONNECTION_TOUT                         0x08
+#define HCI_ERR_MAX_NUM_OF_CONNECTIONS                  0x09
+#define HCI_ERR_MAX_NUM_OF_SCOS                         0x0A
+#define HCI_ERR_CONNECTION_EXISTS                       0x0B
+#define HCI_ERR_COMMAND_DISALLOWED                      0x0C
+#define HCI_ERR_HOST_REJECT_RESOURCES                   0x0D
+#define HCI_ERR_HOST_REJECT_SECURITY                    0x0E
+#define HCI_ERR_HOST_REJECT_DEVICE                      0x0F
+#define HCI_ERR_HOST_TIMEOUT                            0x10
+#define HCI_ERR_UNSUPPORTED_VALUE                       0x11
+#define HCI_ERR_ILLEGAL_PARAMETER_FMT                   0x12
+#define HCI_ERR_PEER_USER                               0x13
+#define HCI_ERR_PEER_LOW_RESOURCES                      0x14
+#define HCI_ERR_PEER_POWER_OFF                          0x15
+#define HCI_ERR_CONN_CAUSE_LOCAL_HOST                   0x16
+#define HCI_ERR_REPEATED_ATTEMPTS                       0x17
+#define HCI_ERR_PAIRING_NOT_ALLOWED                     0x18
+#define HCI_ERR_UNKNOWN_LMP_PDU                         0x19
+#define HCI_ERR_UNSUPPORTED_REM_FEATURE                 0x1A
+#define HCI_ERR_SCO_OFFSET_REJECTED                     0x1B
+#define HCI_ERR_SCO_INTERVAL_REJECTED                   0x1C
+#define HCI_ERR_SCO_AIR_MODE                            0x1D
+#define HCI_ERR_INVALID_LMP_PARAM                       0x1E
+#define HCI_ERR_UNSPECIFIED                             0x1F
+#define HCI_ERR_UNSUPPORTED_LMP_FEATURE                 0x20
+#define HCI_ERR_ROLE_CHANGE_NOT_ALLOWED                 0x21
+#define HCI_ERR_LMP_RESPONSE_TIMEOUT                    0x22
+#define HCI_ERR_LMP_ERR_TRANS_COLLISION                 0x23
+#define HCI_ERR_LMP_PDU_NOT_ALLOWED                     0x24
+#define HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE               0x25
+#define HCI_ERR_UNIT_KEY_USED                           0x26
+#define HCI_ERR_QOS_NOT_SUPPORTED                       0x27
+#define HCI_ERR_INSTANT_PASSED                          0x28
+#define HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED     0x29
+#define HCI_ERR_DIFF_TRANSACTION_COLLISION              0x2A
+#define HCI_ERR_UNDEFINED_0x2B                          0x2B
+#define HCI_ERR_QOS_UNACCEPTABLE_PARAM                  0x2C
+#define HCI_ERR_QOS_REJECTED                            0x2D
+#define HCI_ERR_CHAN_CLASSIF_NOT_SUPPORTED              0x2E
+#define HCI_ERR_INSUFFCIENT_SECURITY                    0x2F
+#define HCI_ERR_PARAM_OUT_OF_RANGE                      0x30
+#define HCI_ERR_UNDEFINED_0x31                          0x31
+#define HCI_ERR_ROLE_SWITCH_PENDING                     0x32
+#define HCI_ERR_UNDEFINED_0x33                          0x33
+#define HCI_ERR_RESERVED_SLOT_VIOLATION                 0x34
+#define HCI_ERR_ROLE_SWITCH_FAILED                      0x35
+#define HCI_ERR_INQ_RSP_DATA_TOO_LARGE                  0x36
+#define HCI_ERR_SIMPLE_PAIRING_NOT_SUPPORTED            0x37
+#define HCI_ERR_HOST_BUSY_PAIRING                       0x38
+#define HCI_ERR_REJ_NO_SUITABLE_CHANNEL                 0x39
+#define HCI_ERR_CONTROLLER_BUSY                         0x3A
+#define HCI_ERR_UNACCEPT_CONN_INTERVAL                  0x3B
+#define HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT            0x3C
+#define HCI_ERR_CONN_TOUT_DUE_TO_MIC_FAILURE            0x3D
+#define HCI_ERR_CONN_FAILED_ESTABLISHMENT               0x3E
+#define HCI_ERR_MAC_CONNECTION_FAILED                   0x3F
+
+/* ConnectionLess Broadcast errors */
+#define HCI_ERR_LT_ADDR_ALREADY_IN_USE                  0x40
+#define HCI_ERR_LT_ADDR_NOT_ALLOCATED                   0x41
+#define HCI_ERR_CLB_NOT_ENABLED                         0x42
+#define HCI_ERR_CLB_DATA_TOO_BIG                        0x43
+
+#define HCI_ERR_MAX_ERR                                 0x43
+
+#define HCI_HINT_TO_RECREATE_AMP_PHYS_LINK              0xFF
+
+/*
+** Definitions for HCI enable event
+*/
+#define HCI_INQUIRY_COMPLETE_EV(p)          (*((uint32_t *)(p)) & 0x00000001)
+#define HCI_INQUIRY_RESULT_EV(p)            (*((uint32_t *)(p)) & 0x00000002)
+#define HCI_CONNECTION_COMPLETE_EV(p)       (*((uint32_t *)(p)) & 0x00000004)
+#define HCI_CONNECTION_REQUEST_EV(p)        (*((uint32_t *)(p)) & 0x00000008)
+#define HCI_DISCONNECTION_COMPLETE_EV(p)    (*((uint32_t *)(p)) & 0x00000010)
+#define HCI_AUTHENTICATION_COMPLETE_EV(p)   (*((uint32_t *)(p)) & 0x00000020)
+#define HCI_RMT_NAME_REQUEST_COMPL_EV(p)    (*((uint32_t *)(p)) & 0x00000040)
+#define HCI_CHANGE_CONN_ENCRPT_ENABLE_EV(p) (*((uint32_t *)(p)) & 0x00000080)
+#define HCI_CHANGE_CONN_LINK_KEY_EV(p)      (*((uint32_t *)(p)) & 0x00000100)
+#define HCI_MASTER_LINK_KEY_COMPLETE_EV(p)  (*((uint32_t *)(p)) & 0x00000200)
+#define HCI_READ_RMT_FEATURES_COMPL_EV(p)   (*((uint32_t *)(p)) & 0x00000400)
+#define HCI_READ_RMT_VERSION_COMPL_EV(p)    (*((uint32_t *)(p)) & 0x00000800)
+#define HCI_QOS_SETUP_COMPLETE_EV(p)        (*((uint32_t *)(p)) & 0x00001000)
+#define HCI_COMMAND_COMPLETE_EV(p)          (*((uint32_t *)(p)) & 0x00002000)
+#define HCI_COMMAND_STATUS_EV(p)            (*((uint32_t *)(p)) & 0x00004000)
+#define HCI_HARDWARE_ERROR_EV(p)            (*((uint32_t *)(p)) & 0x00008000)
+#define HCI_FLASH_OCCURED_EV(p)             (*((uint32_t *)(p)) & 0x00010000)
+#define HCI_ROLE_CHANGE_EV(p)               (*((uint32_t *)(p)) & 0x00020000)
+#define HCI_NUM_COMPLETED_PKTS_EV(p)        (*((uint32_t *)(p)) & 0x00040000)
+#define HCI_MODE_CHANGE_EV(p)               (*((uint32_t *)(p)) & 0x00080000)
+#define HCI_RETURN_LINK_KEYS_EV(p)          (*((uint32_t *)(p)) & 0x00100000)
+#define HCI_PIN_CODE_REQUEST_EV(p)          (*((uint32_t *)(p)) & 0x00200000)
+#define HCI_LINK_KEY_REQUEST_EV(p)          (*((uint32_t *)(p)) & 0x00400000)
+#define HCI_LINK_KEY_NOTIFICATION_EV(p)     (*((uint32_t *)(p)) & 0x00800000)
+#define HCI_LOOPBACK_COMMAND_EV(p)          (*((uint32_t *)(p)) & 0x01000000)
+#define HCI_DATA_BUF_OVERFLOW_EV(p)         (*((uint32_t *)(p)) & 0x02000000)
+#define HCI_MAX_SLOTS_CHANGE_EV(p)          (*((uint32_t *)(p)) & 0x04000000)
+#define HCI_READ_CLOCK_OFFSET_COMP_EV(p)    (*((uint32_t *)(p)) & 0x08000000)
+#define HCI_CONN_PKT_TYPE_CHANGED_EV(p)     (*((uint32_t *)(p)) & 0x10000000)
+#define HCI_QOS_VIOLATION_EV(p)             (*((uint32_t *)(p)) & 0x20000000)
+#define HCI_PAGE_SCAN_MODE_CHANGED_EV(p)    (*((uint32_t *)(p)) & 0x40000000)
+#define HCI_PAGE_SCAN_REP_MODE_CHNG_EV(p)   (*((uint32_t *)(p)) & 0x80000000)
+
+/* the default event mask for 2.1+EDR (Lisbon) does not include Lisbon events */
+#define HCI_DEFAULT_EVENT_MASK_0            0xFFFFFFFF
+#define HCI_DEFAULT_EVENT_MASK_1            0x00001FFF
+
+/* the event mask for 2.0 + EDR and later (includes Lisbon events) */
+#define HCI_LISBON_EVENT_MASK_0             0xFFFFFFFF
+#define HCI_LISBON_EVENT_MASK_1             0x1DBFFFFF
+#define HCI_LISBON_EVENT_MASK           {0x0D, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
+#define HCI_LISBON_EVENT_MASK_EXT       {0x1D, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
+#define HCI_DUMO_EVENT_MASK_EXT         {0x3D, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
+/*  0x00001FFF FFFFFFFF Default - no Lisbon events
+    0x00000800 00000000 Synchronous Connection Complete Event
+    0x00001000 00000000 Synchronous Connection Changed Event
+    0x00002000 00000000 Sniff Subrate Event
+    0x00004000 00000000 Extended Inquiry Result Event
+    0x00008000 00000000 Encryption Key Refresh Complete Event
+    0x00010000 00000000 IO Capability Request Event
+    0x00020000 00000000 IO Capability Response Event
+    0x00040000 00000000 User Confirmation Request Event
+    0x00080000 00000000 User Passkey Request Event
+    0x00100000 00000000 Remote OOB Data Request Event
+    0x00200000 00000000 Simple Pairing Complete Event
+    0x00400000 00000000 Generic AMP Link Key Notification Event
+    0x00800000 00000000 Link Supervision Timeout Changed Event
+    0x01000000 00000000 Enhanced Flush Complete Event
+    0x04000000 00000000 User Passkey Notification Event
+    0x08000000 00000000 Keypress Notification Event
+    0x10000000 00000000 Remote Host Supported Features Notification Event
+    0x20000000 00000000 LE Meta Event
+ */
+
+
+/* the event mask for AMP controllers */
+#define HCI_AMP_EVENT_MASK_3_0               "\x00\x00\x00\x00\x00\x00\x3F\xFF"
+
+/*  0x0000000000000000 No events specified (default)
+    0x0000000000000001 Physical Link Complete Event
+    0x0000000000000002 Channel Selected Event
+    0x0000000000000004 Disconnection Physical Link Event
+    0x0000000000000008 Physical Link Loss Early Warning Event
+    0x0000000000000010 Physical Link Recovery Event
+    0x0000000000000020 Logical Link Complete Event
+    0x0000000000000040 Disconnection Logical Link Complete Event
+    0x0000000000000080 Flow Spec Modify Complete Event
+    0x0000000000000100 Number of Completed Data Blocks Event
+    0x0000000000000200 AMP Start Test Event
+    0x0000000000000400 AMP Test End Event
+    0x0000000000000800 AMP Receiver Report Event
+    0x0000000000001000 Short Range Mode Change Complete Event
+    0x0000000000002000 AMP Status Change Event
+*/
+
+/* the event mask page 2 (CLB + CSA4) for BR/EDR controller */
+#define HCI_PAGE_2_EVENT_MASK                  "\x00\x00\x00\x00\x00\x7F\xC0\x00"
+/*  0x0000000000004000 Triggered Clock Capture Event
+    0x0000000000008000 Sync Train Complete Event
+    0x0000000000010000 Sync Train Received Event
+    0x0000000000020000 Connectionless Broadcast Receive Event
+    0x0000000000040000 Connectionless Broadcast Timeout Event
+    0x0000000000080000 Truncated Page Complete Event
+    0x0000000000100000 Salve Page Response Timeout Event
+    0x0000000000200000 Connectionless Broadcast Channel Map Change Event
+    0x0000000000400000 Inquiry Response Notification Event
+*/
+#if (BLE_PRIVACY_SPT == TRUE)
+/* BLE event mask */
+#define HCI_BLE_EVENT_MASK_DEF               "\x00\x00\x00\x00\x00\x00\x07\xff"
+#else
+#define HCI_BLE_EVENT_MASK_DEF              "\x00\x00\x00\x00\x00\x00\x00\x7f"
+#endif
+/*
+** Definitions for packet type masks (BT1.2 and BT2.0 definitions)
+*/
+#define HCI_PKT_TYPES_MASK_NO_2_DH1         0x0002
+#define HCI_PKT_TYPES_MASK_NO_3_DH1         0x0004
+#define HCI_PKT_TYPES_MASK_DM1              0x0008
+#define HCI_PKT_TYPES_MASK_DH1              0x0010
+#define HCI_PKT_TYPES_MASK_HV1              0x0020
+#define HCI_PKT_TYPES_MASK_HV2              0x0040
+#define HCI_PKT_TYPES_MASK_HV3              0x0080
+#define HCI_PKT_TYPES_MASK_NO_2_DH3         0x0100
+#define HCI_PKT_TYPES_MASK_NO_3_DH3         0x0200
+#define HCI_PKT_TYPES_MASK_DM3              0x0400
+#define HCI_PKT_TYPES_MASK_DH3              0x0800
+#define HCI_PKT_TYPES_MASK_NO_2_DH5         0x1000
+#define HCI_PKT_TYPES_MASK_NO_3_DH5         0x2000
+#define HCI_PKT_TYPES_MASK_DM5              0x4000
+#define HCI_PKT_TYPES_MASK_DH5              0x8000
+
+/* Packet type should be one of valid but at least one should be specified */
+#define HCI_VALID_SCO_PKT_TYPE(t) (((((t) & ~(HCI_PKT_TYPES_MASK_HV1       \
+                                           |  HCI_PKT_TYPES_MASK_HV2       \
+                                           |  HCI_PKT_TYPES_MASK_HV3)) == 0)) \
+                                    && ((t) != 0))
+
+
+
+
+
+/* Packet type should not be invalid and at least one should be specified */
+#define HCI_VALID_ACL_PKT_TYPE(t) (((((t) & ~(HCI_PKT_TYPES_MASK_DM1        \
+                                           |  HCI_PKT_TYPES_MASK_DH1        \
+                                           |  HCI_PKT_TYPES_MASK_DM3        \
+                                           |  HCI_PKT_TYPES_MASK_DH3        \
+                                           |  HCI_PKT_TYPES_MASK_DM5        \
+                                           |  HCI_PKT_TYPES_MASK_DH5        \
+                                           |  HCI_PKT_TYPES_MASK_NO_2_DH1   \
+                                           |  HCI_PKT_TYPES_MASK_NO_3_DH1   \
+                                           |  HCI_PKT_TYPES_MASK_NO_2_DH3   \
+                                           |  HCI_PKT_TYPES_MASK_NO_3_DH3   \
+                                           |  HCI_PKT_TYPES_MASK_NO_2_DH5   \
+                                           |  HCI_PKT_TYPES_MASK_NO_3_DH5  )) == 0)) \
+                                    && (((t) &  (HCI_PKT_TYPES_MASK_DM1        \
+                                              |  HCI_PKT_TYPES_MASK_DH1        \
+                                              |  HCI_PKT_TYPES_MASK_DM3        \
+                                              |  HCI_PKT_TYPES_MASK_DH3        \
+                                              |  HCI_PKT_TYPES_MASK_DM5        \
+                                              |  HCI_PKT_TYPES_MASK_DH5)) != 0))
+
+/*
+** Definitions for eSCO packet type masks (BT1.2 and BT2.0 definitions)
+*/
+#define HCI_ESCO_PKT_TYPES_MASK_HV1         0x0001
+#define HCI_ESCO_PKT_TYPES_MASK_HV2         0x0002
+#define HCI_ESCO_PKT_TYPES_MASK_HV3         0x0004
+#define HCI_ESCO_PKT_TYPES_MASK_EV3         0x0008
+#define HCI_ESCO_PKT_TYPES_MASK_EV4         0x0010
+#define HCI_ESCO_PKT_TYPES_MASK_EV5         0x0020
+#define HCI_ESCO_PKT_TYPES_MASK_NO_2_EV3    0x0040
+#define HCI_ESCO_PKT_TYPES_MASK_NO_3_EV3    0x0080
+#define HCI_ESCO_PKT_TYPES_MASK_NO_2_EV5    0x0100
+#define HCI_ESCO_PKT_TYPES_MASK_NO_3_EV5    0x0200
+
+/* Packet type should be one of valid but at least one should be specified for 1.2 */
+#define HCI_VALID_ESCO_PKT_TYPE(t) (((((t) & ~(HCI_ESCO_PKT_TYPES_MASK_EV3       \
+                                           |   HCI_ESCO_PKT_TYPES_MASK_EV4       \
+                                           |   HCI_ESCO_PKT_TYPES_MASK_EV5)) == 0)) \
+                                    && ((t) != 0))/* Packet type should be one of valid but at least one should be specified */
+
+#define HCI_VALID_ESCO_SCOPKT_TYPE(t) (((((t) & ~(HCI_ESCO_PKT_TYPES_MASK_HV1       \
+                                           |      HCI_ESCO_PKT_TYPES_MASK_HV2       \
+                                           |      HCI_ESCO_PKT_TYPES_MASK_HV3)) == 0)) \
+                                    && ((t) != 0))
+
+#define HCI_VALID_SCO_ALL_PKT_TYPE(t) (((((t) & ~(HCI_ESCO_PKT_TYPES_MASK_HV1       \
+                                           |      HCI_ESCO_PKT_TYPES_MASK_HV2       \
+                                           |      HCI_ESCO_PKT_TYPES_MASK_HV3       \
+                                           |      HCI_ESCO_PKT_TYPES_MASK_EV3       \
+                                           |      HCI_ESCO_PKT_TYPES_MASK_EV4       \
+                                           |      HCI_ESCO_PKT_TYPES_MASK_EV5)) == 0)) \
+                                    && ((t) != 0))
+
+/*
+** Define parameters to allow role switch during create connection
+*/
+#define HCI_CR_CONN_NOT_ALLOW_SWITCH    0x00
+#define HCI_CR_CONN_ALLOW_SWITCH        0x01
+
+/*
+** Hold Mode command destination
+*/
+#define HOLD_MODE_DEST_LOCAL_DEVICE     0x00
+#define HOLD_MODE_DEST_RMT_DEVICE       0x01
+
+/*
+**  Definitions for different HCI parameters
+*/
+#define HCI_PER_INQ_MIN_MAX_PERIOD      0x0003
+#define HCI_PER_INQ_MAX_MAX_PERIOD      0xFFFF
+#define HCI_PER_INQ_MIN_MIN_PERIOD      0x0002
+#define HCI_PER_INQ_MAX_MIN_PERIOD      0xFFFE
+
+#define HCI_MAX_INQUIRY_LENGTH          0x30
+
+#define HCI_MIN_INQ_LAP                 0x9E8B00
+#define HCI_MAX_INQ_LAP                 0x9E8B3F
+
+/* HCI role defenitions */
+#define HCI_ROLE_MASTER                 0x00
+#define HCI_ROLE_SLAVE                  0x01
+#define HCI_ROLE_UNKNOWN                0xff
+
+/* HCI mode defenitions */
+#define HCI_MODE_ACTIVE                 0x00
+#define HCI_MODE_HOLD                   0x01
+#define HCI_MODE_SNIFF                  0x02
+#define HCI_MODE_PARK                   0x03
+
+/* HCI Flow Control Mode defenitions */
+#define HCI_PACKET_BASED_FC_MODE        0x00
+#define HCI_BLOCK_BASED_FC_MODE         0x01
+
+/* Define Packet types as requested by the Host */
+#define HCI_ACL_PKT_TYPE_NONE           0x0000
+#define HCI_ACL_PKT_TYPE_DM1            0x0008
+#define HCI_ACL_PKT_TYPE_DH1            0x0010
+#define HCI_ACL_PKT_TYPE_AUX1           0x0200
+#define HCI_ACL_PKT_TYPE_DM3            0x0400
+#define HCI_ACL_PKT_TYPE_DH3            0x0800
+#define HCI_ACL_PKT_TYPE_DM5            0x4000
+#define HCI_ACL_PKT_TYPE_DH5            0x8000
+
+/* Define key type in the Master Link Key command */
+#define HCI_USE_SEMI_PERMANENT_KEY      0x00
+#define HCI_USE_TEMPORARY_KEY           0x01
+
+/* Page scan period modes */
+#define HCI_PAGE_SCAN_REP_MODE_R0       0x00
+#define HCI_PAGE_SCAN_REP_MODE_R1       0x01
+#define HCI_PAGE_SCAN_REP_MODE_R2       0x02
+
+/* Define limits for page scan repetition modes */
+#define HCI_PAGE_SCAN_R1_LIMIT          0x0800
+#define HCI_PAGE_SCAN_R2_LIMIT          0x1000
+
+/* Page scan period modes */
+#define HCI_PAGE_SCAN_PER_MODE_P0       0x00
+#define HCI_PAGE_SCAN_PER_MODE_P1       0x01
+#define HCI_PAGE_SCAN_PER_MODE_P2       0x02
+
+/* Page scan modes */
+#define HCI_MANDATARY_PAGE_SCAN_MODE    0x00
+#define HCI_OPTIONAL_PAGE_SCAN_MODE1    0x01
+#define HCI_OPTIONAL_PAGE_SCAN_MODE2    0x02
+#define HCI_OPTIONAL_PAGE_SCAN_MODE3    0x03
+
+/* Page and inquiry scan types */
+#define HCI_SCAN_TYPE_STANDARD          0x00
+#define HCI_SCAN_TYPE_INTERLACED        0x01       /* 1.2 devices or later */
+#define HCI_DEF_SCAN_TYPE               HCI_SCAN_TYPE_STANDARD
+
+/* Definitions for quality of service service types */
+#define HCI_SERVICE_NO_TRAFFIC          0x00
+#define HCI_SERVICE_BEST_EFFORT         0x01
+#define HCI_SERVICE_GUARANTEED          0x02
+
+#define HCI_QOS_LATENCY_DO_NOT_CARE     0xFFFFFFFF
+#define HCI_QOS_DELAY_DO_NOT_CARE       0xFFFFFFFF
+
+/* Definitions for Flow Specification */
+#define HCI_FLOW_SPEC_LATENCY_DO_NOT_CARE 0xFFFFFFFF
+
+/* Definitions for AFH Channel Map */
+#define HCI_AFH_CHANNEL_MAP_LEN         10
+
+/* Definitions for Extended Inquiry Response */
+#define HCI_EXT_INQ_RESPONSE_LEN        240
+#define HCI_EIR_FLAGS_TYPE                       BT_EIR_FLAGS_TYPE
+#define HCI_EIR_MORE_16BITS_UUID_TYPE            BT_EIR_MORE_16BITS_UUID_TYPE
+#define HCI_EIR_COMPLETE_16BITS_UUID_TYPE        BT_EIR_COMPLETE_16BITS_UUID_TYPE
+#define HCI_EIR_MORE_32BITS_UUID_TYPE            BT_EIR_MORE_32BITS_UUID_TYPE
+#define HCI_EIR_COMPLETE_32BITS_UUID_TYPE        BT_EIR_COMPLETE_32BITS_UUID_TYPE
+#define HCI_EIR_MORE_128BITS_UUID_TYPE           BT_EIR_MORE_128BITS_UUID_TYPE
+#define HCI_EIR_COMPLETE_128BITS_UUID_TYPE       BT_EIR_COMPLETE_128BITS_UUID_TYPE
+#define HCI_EIR_SHORTENED_LOCAL_NAME_TYPE        BT_EIR_SHORTENED_LOCAL_NAME_TYPE
+#define HCI_EIR_COMPLETE_LOCAL_NAME_TYPE         BT_EIR_COMPLETE_LOCAL_NAME_TYPE
+#define HCI_EIR_TX_POWER_LEVEL_TYPE              BT_EIR_TX_POWER_LEVEL_TYPE
+#define HCI_EIR_MANUFACTURER_SPECIFIC_TYPE       BT_EIR_MANUFACTURER_SPECIFIC_TYPE
+#define HCI_EIR_SERVICE_DATA_TYPE                BT_EIR_SERVICE_DATA_TYPE
+#define HCI_EIR_SERVICE_DATA_16BITS_UUID_TYPE    BT_EIR_SERVICE_DATA_16BITS_UUID_TYPE
+#define HCI_EIR_SERVICE_DATA_32BITS_UUID_TYPE    BT_EIR_SERVICE_DATA_32BITS_UUID_TYPE
+#define HCI_EIR_SERVICE_DATA_128BITS_UUID_TYPE   BT_EIR_SERVICE_DATA_128BITS_UUID_TYPE
+#define HCI_EIR_OOB_BD_ADDR_TYPE                 BT_EIR_OOB_BD_ADDR_TYPE
+#define HCI_EIR_OOB_COD_TYPE                     BT_EIR_OOB_COD_TYPE
+#define HCI_EIR_OOB_SSP_HASH_C_TYPE              BT_EIR_OOB_SSP_HASH_C_TYPE
+#define HCI_EIR_OOB_SSP_RAND_R_TYPE              BT_EIR_OOB_SSP_RAND_R_TYPE
+
+/* Definitions for Write Simple Pairing Mode */
+#define HCI_SP_MODE_UNDEFINED           0x00
+#define HCI_SP_MODE_ENABLED             0x01
+
+/* Definitions for Write Simple Pairing Debug Mode */
+#define HCI_SPD_MODE_DISABLED           0x00
+#define HCI_SPD_MODE_ENABLED            0x01
+
+/* Definitions for Write Secure Connections Host Support */
+#define HCI_SC_MODE_DISABLED            0x00
+#define HCI_SC_MODE_ENABLED             0x01
+
+/* Definitions for IO Capability Response/Command */
+#define HCI_IO_CAP_DISPLAY_ONLY         0x00
+#define HCI_IO_CAP_DISPLAY_YESNO        0x01
+#define HCI_IO_CAP_KEYBOARD_ONLY        0x02
+#define HCI_IO_CAP_NO_IO                0x03
+
+#define HCI_OOB_AUTH_DATA_NOT_PRESENT   0x00
+#define HCI_OOB_REM_AUTH_DATA_PRESENT   0x01
+
+#define HCI_MITM_PROTECT_NOT_REQUIRED  0x00
+#define HCI_MITM_PROTECT_REQUIRED      0x01
+
+
+/* Policy settings status */
+#define HCI_DISABLE_ALL_LM_MODES        0x0000
+#define HCI_ENABLE_MASTER_SLAVE_SWITCH  0x0001
+#define HCI_ENABLE_HOLD_MODE            0x0002
+#define HCI_ENABLE_SNIFF_MODE           0x0004
+#define HCI_ENABLE_PARK_MODE            0x0008
+
+/* By default allow switch, because host can not allow that */
+/* that until he created the connection */
+#define HCI_DEFAULT_POLICY_SETTINGS     HCI_DISABLE_ALL_LM_MODES
+
+/* Filters that are sent in set filter command */
+#define HCI_FILTER_TYPE_CLEAR_ALL       0x00
+#define HCI_FILTER_INQUIRY_RESULT       0x01
+#define HCI_FILTER_CONNECTION_SETUP     0x02
+
+#define HCI_FILTER_COND_NEW_DEVICE      0x00
+#define HCI_FILTER_COND_DEVICE_CLASS    0x01
+#define HCI_FILTER_COND_BD_ADDR         0x02
+
+#define HCI_DO_NOT_AUTO_ACCEPT_CONNECT  1
+#define HCI_DO_AUTO_ACCEPT_CONNECT      2   /* role switch disabled */
+#define HCI_DO_AUTO_ACCEPT_CONNECT_RS   3   /* role switch enabled (1.1 errata 1115) */
+
+/* Auto accept flags */
+#define HCI_AUTO_ACCEPT_OFF             0x00
+#define HCI_AUTO_ACCEPT_ACL_CONNECTIONS 0x01
+#define HCI_AUTO_ACCEPT_SCO_CONNECTIONS 0x02
+
+/* PIN type */
+#define HCI_PIN_TYPE_VARIABLE           0
+#define HCI_PIN_TYPE_FIXED              1
+
+/* Loopback Modes */
+#define HCI_LOOPBACK_MODE_DISABLED      0
+#define HCI_LOOPBACK_MODE_LOCAL         1
+#define HCI_LOOPBACK_MODE_REMOTE        2
+
+#define SLOTS_PER_10MS                  16      /* 0.625 ms slots in a 10 ms tick */
+
+/* Maximum connection accept timeout in 0.625msec */
+#define HCI_MAX_CONN_ACCEPT_TOUT        0xB540  /* 29 sec */
+#define HCI_DEF_CONN_ACCEPT_TOUT        0x1F40  /* 5 sec */
+
+/* Page timeout is used in LC only and LC is counting down slots not using OS */
+#define HCI_DEFAULT_PAGE_TOUT           0x2000  /* 5.12 sec (in slots) */
+
+/* Scan enable flags */
+#define HCI_NO_SCAN_ENABLED             0x00
+#define HCI_INQUIRY_SCAN_ENABLED        0x01
+#define HCI_PAGE_SCAN_ENABLED           0x02
+
+/* Pagescan timer definitions in 0.625 ms */
+#define HCI_MIN_PAGESCAN_INTERVAL       0x12    /* 11.25 ms */
+#define HCI_MAX_PAGESCAN_INTERVAL       0x1000  /* 2.56 sec */
+#define HCI_DEF_PAGESCAN_INTERVAL       0x0800  /* 1.28 sec */
+
+/* Parameter for pagescan window is passed to LC and is kept in slots */
+#define HCI_MIN_PAGESCAN_WINDOW         0x11    /* 10.625 ms */
+#define HCI_MAX_PAGESCAN_WINDOW         0x1000  /* 2.56  sec */
+#define HCI_DEF_PAGESCAN_WINDOW         0x12    /* 11.25 ms  */
+
+/* Inquiryscan timer definitions in 0.625 ms */
+#define HCI_MIN_INQUIRYSCAN_INTERVAL    0x12    /* 11.25 ms */
+#define HCI_MAX_INQUIRYSCAN_INTERVAL    0x1000  /* 2.56 sec */
+#define HCI_DEF_INQUIRYSCAN_INTERVAL    0x1000  /* 2.56 sec */
+
+/* Parameter for inquiryscan window is passed to LC and is kept in slots */
+#define HCI_MIN_INQUIRYSCAN_WINDOW      0x11    /* 10.625 ms */
+#define HCI_MAX_INQUIRYSCAN_WINDOW      0x1000  /* 2.56 sec */
+#define HCI_DEF_INQUIRYSCAN_WINDOW      0x12    /* 11.25 ms */
+
+/* Encryption modes */
+#define HCI_ENCRYPT_MODE_DISABLED       0x00
+#define HCI_ENCRYPT_MODE_POINT_TO_POINT 0x01
+#define HCI_ENCRYPT_MODE_ALL            0x02
+
+/* Voice settings */
+#define HCI_INP_CODING_LINEAR           0x0000 /* 0000000000 */
+#define HCI_INP_CODING_U_LAW            0x0100 /* 0100000000 */
+#define HCI_INP_CODING_A_LAW            0x0200 /* 1000000000 */
+#define HCI_INP_CODING_MASK             0x0300 /* 1100000000 */
+
+#define HCI_INP_DATA_FMT_1S_COMPLEMENT  0x0000 /* 0000000000 */
+#define HCI_INP_DATA_FMT_2S_COMPLEMENT  0x0040 /* 0001000000 */
+#define HCI_INP_DATA_FMT_SIGN_MAGNITUDE 0x0080 /* 0010000000 */
+#define HCI_INP_DATA_FMT_UNSIGNED       0x00c0 /* 0011000000 */
+#define HCI_INP_DATA_FMT_MASK           0x00c0 /* 0011000000 */
+
+#define HCI_INP_SAMPLE_SIZE_8BIT        0x0000 /* 0000000000 */
+#define HCI_INP_SAMPLE_SIZE_16BIT       0x0020 /* 0000100000 */
+#define HCI_INP_SAMPLE_SIZE_MASK        0x0020 /* 0000100000 */
+
+#define HCI_INP_LINEAR_PCM_BIT_POS_MASK 0x001c /* 0000011100 */
+#define HCI_INP_LINEAR_PCM_BIT_POS_OFFS 2
+
+#define HCI_AIR_CODING_FORMAT_CVSD      0x0000 /* 0000000000 */
+#define HCI_AIR_CODING_FORMAT_U_LAW     0x0001 /* 0000000001 */
+#define HCI_AIR_CODING_FORMAT_A_LAW     0x0002 /* 0000000010 */
+#define HCI_AIR_CODING_FORMAT_TRANSPNT  0x0003 /* 0000000011 */
+#define HCI_AIR_CODING_FORMAT_MASK      0x0003 /* 0000000011 */
+
+/* default                                        0001100000 */
+#define HCI_DEFAULT_VOICE_SETTINGS    (HCI_INP_CODING_LINEAR \
+                                     | HCI_INP_DATA_FMT_2S_COMPLEMENT \
+                                     | HCI_INP_SAMPLE_SIZE_16BIT \
+                                     | HCI_AIR_CODING_FORMAT_CVSD)
+
+#define HCI_CVSD_SUPPORTED(x)       (((x) & HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_CVSD)
+#define HCI_U_LAW_SUPPORTED(x)      (((x) & HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_U_LAW)
+#define HCI_A_LAW_SUPPORTED(x)      (((x) & HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_A_LAW)
+#define HCI_TRANSPNT_SUPPORTED(x)   (((x) & HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_TRANSPNT)
+
+/* Retransmit timer definitions in 0.625 */
+#define HCI_MAX_AUTO_FLUSH_TOUT         0x07FF
+#define HCI_DEFAULT_AUTO_FLUSH_TOUT     0       /* No auto flush */
+
+/* Broadcast retransmitions */
+#define HCI_DEFAULT_NUM_BCAST_RETRAN    1
+
+/* Define broadcast data types as passed in the hci data packet */
+#define HCI_DATA_POINT_TO_POINT         0x00
+#define HCI_DATA_ACTIVE_BCAST           0x01
+#define HCI_DATA_PICONET_BCAST          0x02
+
+/* Hold mode activity */
+#define HCI_MAINTAIN_CUR_POWER_STATE    0x00
+#define HCI_SUSPEND_PAGE_SCAN           0x01
+#define HCI_SUSPEND_INQUIRY_SCAN        0x02
+#define HCI_SUSPEND_PERIODIC_INQUIRIES  0x04
+
+/* Default Link Supervision timeoout */
+#define HCI_DEFAULT_INACT_TOUT          0x7D00  /* BR/EDR (20 seconds) */
+#define HCI_DEFAULT_AMP_INACT_TOUT      0x3E80  /* AMP    (10 seconds) */
+
+/* Read transmit power level parameter */
+#define HCI_READ_CURRENT                0x00
+#define HCI_READ_MAXIMUM                0x01
+
+/* Link types for connection complete event */
+#define HCI_LINK_TYPE_SCO               0x00
+#define HCI_LINK_TYPE_ACL               0x01
+#define HCI_LINK_TYPE_ESCO              0x02
+
+/* Link Key Notification Event (Key Type) definitions */
+#define HCI_LKEY_TYPE_COMBINATION       0x00
+#define HCI_LKEY_TYPE_LOCAL_UNIT        0x01
+#define HCI_LKEY_TYPE_REMOTE_UNIT       0x02
+#define HCI_LKEY_TYPE_DEBUG_COMB        0x03
+#define HCI_LKEY_TYPE_UNAUTH_COMB       0x04
+#define HCI_LKEY_TYPE_AUTH_COMB         0x05
+#define HCI_LKEY_TYPE_CHANGED_COMB      0x06
+#define HCI_LKEY_TYPE_UNAUTH_COMB_P_256 0x07
+#define HCI_LKEY_TYPE_AUTH_COMB_P_256   0x08
+
+/* Internal definitions - not used over HCI */
+#define HCI_LKEY_TYPE_AMP_WIFI          0x80
+#define HCI_LKEY_TYPE_AMP_UWB           0x81
+#define HCI_LKEY_TYPE_UNKNOWN           0xff
+
+/* Read Local Version HCI Version return values (Command Complete Event) */
+#define HCI_VERSION_1_0B                0x00
+#define HCI_VERSION_1_1                 0x01
+
+/* Define an invalid value for a handle */
+#define HCI_INVALID_HANDLE              0xFFFF
+
+/* Define max ammount of data in the HCI command */
+#define HCI_COMMAND_SIZE        255
+
+/* Define the preamble length for all HCI Commands.
+** This is 2-bytes for opcode and 1 byte for length
+*/
+#define HCIC_PREAMBLE_SIZE      3
+
+/* Define the preamble length for all HCI Events
+** This is 1-byte for opcode and 1 byte for length
+*/
+#define HCIE_PREAMBLE_SIZE      2
+#define HCI_SCO_PREAMBLE_SIZE   3
+#define HCI_DATA_PREAMBLE_SIZE  4
+
+/* local Bluetooth controller id for AMP HCI */
+#define LOCAL_BR_EDR_CONTROLLER_ID      0
+
+/* controller id types for AMP HCI */
+#define HCI_CONTROLLER_TYPE_BR_EDR      0
+#define HCI_CONTROLLER_TYPE_802_11      1
+#define HCI_CONTROLLER_TYPE_ECMA        2
+#define HCI_MAX_CONTROLLER_TYPES        3
+
+/*  ConnectionLess Broadcast */
+#define HCI_CLB_DISABLE                 0x00
+#define HCI_CLB_ENABLE                  0x01
+
+/* ConnectionLess Broadcast Data fragment */
+#define HCI_CLB_FRAGMENT_CONT           0x00
+#define HCI_CLB_FRAGMENT_START          0x01
+#define HCI_CLB_FRAGMENT_END            0x02
+#define HCI_CLB_FRAGMENT_SINGLE         0x03
+
+/* AMP Controller Status codes
+*/
+#define HCI_AMP_CTRLR_PHYSICALLY_DOWN   0
+#define HCI_AMP_CTRLR_USABLE_BY_BT      1
+#define HCI_AMP_CTRLR_UNUSABLE_FOR_BT   2
+#define HCI_AMP_CTRLR_LOW_CAP_FOR_BT    3
+#define HCI_AMP_CTRLR_MED_CAP_FOR_BT    4
+#define HCI_AMP_CTRLR_HIGH_CAP_FOR_BT   5
+#define HCI_AMP_CTRLR_FULL_CAP_FOR_BT   6
+
+#define HCI_MAX_AMP_STATUS_TYPES        7
+
+
+/* Define the extended flow specification fields used by AMP */
+typedef struct
+{
+    uint8_t     id;
+    uint8_t     stype;
+    uint16_t    max_sdu_size;
+    uint32_t    sdu_inter_time;
+    uint32_t    access_latency;
+    uint32_t    flush_timeout;
+} tHCI_EXT_FLOW_SPEC;
+
+
+/* HCI message type definitions (for H4 messages) */
+#define HCIT_TYPE_COMMAND   1
+#define HCIT_TYPE_ACL_DATA  2
+#define HCIT_TYPE_SCO_DATA  3
+#define HCIT_TYPE_EVENT     4
+#define HCIT_TYPE_LM_DIAG   7
+#define HCIT_TYPE_NFC       16
+
+#define HCIT_LM_DIAG_LENGTH 63
+
+/* Parameter information for HCI_BRCM_SET_ACL_PRIORITY */
+#define HCI_BRCM_ACL_PRIORITY_PARAM_SIZE    3
+#define HCI_BRCM_ACL_PRIORITY_LOW           0x00
+#define HCI_BRCM_ACL_PRIORITY_HIGH          0xFF
+#define HCI_BRCM_SET_ACL_PRIORITY           (0x0057 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Define values for LMP Test Control parameters
+** Test Scenario, Hopping Mode, Power Control Mode
+*/
+#define LMP_TESTCTL_TESTSC_PAUSE        0
+#define LMP_TESTCTL_TESTSC_TXTEST_0     1
+#define LMP_TESTCTL_TESTSC_TXTEST_1     2
+#define LMP_TESTCTL_TESTSC_TXTEST_1010  3
+#define LMP_TESTCTL_TESTSC_PSRND_BITSEQ 4
+#define LMP_TESTCTL_TESTSC_CLOSEDLB_ACL 5
+#define LMP_TESTCTL_TESTSC_CLOSEDLB_SCO 6
+#define LMP_TESTCTL_TESTSC_ACL_NOWHIT   7
+#define LMP_TESTCTL_TESTSC_SCO_NOWHIT   8
+#define LMP_TESTCTL_TESTSC_TXTEST_11110000  9
+#define LMP_TESTCTL_TESTSC_EXITTESTMODE 255
+
+#define LMP_TESTCTL_HOPMOD_RXTX1FREQ    0
+#define LMP_TESTCTL_HOPMOD_HOP_EURUSA   1
+#define LMP_TESTCTL_HOPMOD_HOP_JAPAN    2
+#define LMP_TESTCTL_HOPMOD_HOP_FRANCE   3
+#define LMP_TESTCTL_HOPMOD_HOP_SPAIN    4
+#define LMP_TESTCTL_HOPMOD_REDUCED_HOP  5
+
+#define LMP_TESTCTL_POWCTL_FIXEDTX_OP   0
+#define LMP_TESTCTL_POWCTL_ADAPTIVE     1
+
+// TODO(zachoverflow): remove this once broadcom specific hacks are removed
+#define LMP_COMPID_BROADCOM             15
+
+/*
+** Define the packet types in the packet header, and a couple extra
+*/
+#define PKT_TYPE_NULL   0x00
+#define PKT_TYPE_POLL   0x01
+#define PKT_TYPE_FHS    0x02
+#define PKT_TYPE_DM1    0x03
+
+#define PKT_TYPE_DH1    0x04
+#define PKT_TYPE_HV1    0x05
+#define PKT_TYPE_HV2    0x06
+#define PKT_TYPE_HV3    0x07
+#define PKT_TYPE_DV     0x08
+#define PKT_TYPE_AUX1   0x09
+
+#define PKT_TYPE_DM3    0x0a
+#define PKT_TYPE_DH3    0x0b
+
+#define PKT_TYPE_DM5    0x0e
+#define PKT_TYPE_DH5    0x0f
+
+
+#define PKT_TYPE_ID     0x10        /* Internally used packet types */
+#define PKT_TYPE_BAD    0x11
+#define PKT_TYPE_NONE   0x12
+
+/*
+** Define packet size
+*/
+#define HCI_DM1_PACKET_SIZE         17
+#define HCI_DH1_PACKET_SIZE         27
+#define HCI_DM3_PACKET_SIZE         121
+#define HCI_DH3_PACKET_SIZE         183
+#define HCI_DM5_PACKET_SIZE         224
+#define HCI_DH5_PACKET_SIZE         339
+#define HCI_AUX1_PACKET_SIZE        29
+#define HCI_HV1_PACKET_SIZE         10
+#define HCI_HV2_PACKET_SIZE         20
+#define HCI_HV3_PACKET_SIZE         30
+#define HCI_DV_PACKET_SIZE          9
+#define HCI_EDR2_DH1_PACKET_SIZE    54
+#define HCI_EDR2_DH3_PACKET_SIZE    367
+#define HCI_EDR2_DH5_PACKET_SIZE    679
+#define HCI_EDR3_DH1_PACKET_SIZE    83
+#define HCI_EDR3_DH3_PACKET_SIZE    552
+#define HCI_EDR3_DH5_PACKET_SIZE    1021
+
+/* Feature Pages */
+#define HCI_EXT_FEATURES_PAGE_0     0       /* Extended Feature Page 0 (regular features) */
+#define HCI_EXT_FEATURES_PAGE_1     1       /* Extended Feature Page 1 */
+#define HCI_EXT_FEATURES_PAGE_2     2       /* Extended Feature Page 2 */
+#define HCI_EXT_FEATURES_PAGE_MAX   HCI_EXT_FEATURES_PAGE_2
+
+#define HCI_FEATURE_BYTES_PER_PAGE      8
+
+#define HCI_FEATURES_KNOWN(x) (((x)[0] | (x)[1] | (x)[2] | (x)[3] | (x)[4] | (x)[5] | (x)[6] | (x)[7]) != 0)
+
+/*
+**   LMP features encoding - page 0
+*/
+#define HCI_FEATURE_3_SLOT_PACKETS_MASK 0x01
+#define HCI_FEATURE_3_SLOT_PACKETS_OFF  0
+#define HCI_3_SLOT_PACKETS_SUPPORTED(x) ((x)[HCI_FEATURE_3_SLOT_PACKETS_OFF] & HCI_FEATURE_3_SLOT_PACKETS_MASK)
+
+#define HCI_FEATURE_5_SLOT_PACKETS_MASK 0x02
+#define HCI_FEATURE_5_SLOT_PACKETS_OFF  0
+#define HCI_5_SLOT_PACKETS_SUPPORTED(x) ((x)[HCI_FEATURE_5_SLOT_PACKETS_OFF] & HCI_FEATURE_5_SLOT_PACKETS_MASK)
+
+#define HCI_FEATURE_ENCRYPTION_MASK     0x04
+#define HCI_FEATURE_ENCRYPTION_OFF      0
+#define HCI_ENCRYPTION_SUPPORTED(x)     ((x)[HCI_FEATURE_ENCRYPTION_OFF] & HCI_FEATURE_ENCRYPTION_MASK)
+
+#define HCI_FEATURE_SLOT_OFFSET_MASK    0x08
+#define HCI_FEATURE_SLOT_OFFSET_OFF     0
+#define HCI_SLOT_OFFSET_SUPPORTED(x)    ((x)[HCI_FEATURE_SLOT_OFFSET_OFF] & HCI_FEATURE_SLOT_OFFSET_MASK)
+
+#define HCI_FEATURE_TIMING_ACC_MASK     0x10
+#define HCI_FEATURE_TIMING_ACC_OFF      0
+#define HCI_TIMING_ACC_SUPPORTED(x)     ((x)[HCI_FEATURE_TIMING_ACC_OFF] & HCI_FEATURE_TIMING_ACC_MASK)
+
+#define HCI_FEATURE_SWITCH_MASK         0x20
+#define HCI_FEATURE_SWITCH_OFF          0
+#define HCI_SWITCH_SUPPORTED(x)         ((x)[HCI_FEATURE_SWITCH_OFF] & HCI_FEATURE_SWITCH_MASK)
+
+#define HCI_FEATURE_HOLD_MODE_MASK      0x40
+#define HCI_FEATURE_HOLD_MODE_OFF       0
+#define HCI_HOLD_MODE_SUPPORTED(x)      ((x)[HCI_FEATURE_HOLD_MODE_OFF] & HCI_FEATURE_HOLD_MODE_MASK)
+
+#define HCI_FEATURE_SNIFF_MODE_MASK     0x80
+#define HCI_FEATURE_SNIFF_MODE_OFF      0
+#define HCI_SNIFF_MODE_SUPPORTED(x)      ((x)[HCI_FEATURE_SNIFF_MODE_OFF] & HCI_FEATURE_SNIFF_MODE_MASK)
+
+#define HCI_FEATURE_PARK_MODE_MASK      0x01
+#define HCI_FEATURE_PARK_MODE_OFF       1
+#define HCI_PARK_MODE_SUPPORTED(x)      ((x)[HCI_FEATURE_PARK_MODE_OFF] & HCI_FEATURE_PARK_MODE_MASK)
+
+#define HCI_FEATURE_RSSI_MASK           0x02
+#define HCI_FEATURE_RSSI_OFF            1
+#define HCI_RSSI_SUPPORTED(x)           ((x)[HCI_FEATURE_RSSI_OFF] & HCI_FEATURE_RSSI_MASK)
+
+#define HCI_FEATURE_CQM_DATA_RATE_MASK  0x04
+#define HCI_FEATURE_CQM_DATA_RATE_OFF   1
+#define HCI_CQM_DATA_RATE_SUPPORTED(x)  ((x)[HCI_FEATURE_CQM_DATA_RATE_OFF] & HCI_FEATURE_CQM_DATA_RATE_MASK)
+
+#define HCI_FEATURE_SCO_LINK_MASK       0x08
+#define HCI_FEATURE_SCO_LINK_OFF        1
+#define HCI_SCO_LINK_SUPPORTED(x)       ((x)[HCI_FEATURE_SCO_LINK_OFF] & HCI_FEATURE_SCO_LINK_MASK)
+
+#define HCI_FEATURE_HV2_PACKETS_MASK    0x10
+#define HCI_FEATURE_HV2_PACKETS_OFF     1
+#define HCI_HV2_PACKETS_SUPPORTED(x)    ((x)[HCI_FEATURE_HV2_PACKETS_OFF] & HCI_FEATURE_HV2_PACKETS_MASK)
+
+#define HCI_FEATURE_HV3_PACKETS_MASK    0x20
+#define HCI_FEATURE_HV3_PACKETS_OFF     1
+#define HCI_HV3_PACKETS_SUPPORTED(x)    ((x)[HCI_FEATURE_HV3_PACKETS_OFF] & HCI_FEATURE_HV3_PACKETS_MASK)
+
+#define HCI_FEATURE_U_LAW_MASK          0x40
+#define HCI_FEATURE_U_LAW_OFF           1
+#define HCI_LMP_U_LAW_SUPPORTED(x)      ((x)[HCI_FEATURE_U_LAW_OFF] & HCI_FEATURE_U_LAW_MASK)
+
+#define HCI_FEATURE_A_LAW_MASK          0x80
+#define HCI_FEATURE_A_LAW_OFF           1
+#define HCI_LMP_A_LAW_SUPPORTED(x)      ((x)[HCI_FEATURE_A_LAW_OFF] & HCI_FEATURE_A_LAW_MASK)
+
+#define HCI_FEATURE_CVSD_MASK           0x01
+#define HCI_FEATURE_CVSD_OFF            2
+#define HCI_LMP_CVSD_SUPPORTED(x)       ((x)[HCI_FEATURE_CVSD_OFF] & HCI_FEATURE_CVSD_MASK)
+
+#define HCI_FEATURE_PAGING_SCHEME_MASK  0x02
+#define HCI_FEATURE_PAGING_SCHEME_OFF   2
+#define HCI_PAGING_SCHEME_SUPPORTED(x) ((x)[HCI_FEATURE_PAGING_SCHEME_OFF] & HCI_FEATURE_PAGING_SCHEME_MASK)
+
+#define HCI_FEATURE_POWER_CTRL_MASK     0x04
+#define HCI_FEATURE_POWER_CTRL_OFF      2
+#define HCI_POWER_CTRL_SUPPORTED(x)     ((x)[HCI_FEATURE_POWER_CTRL_OFF] & HCI_FEATURE_POWER_CTRL_MASK)
+
+#define HCI_FEATURE_TRANSPNT_MASK       0x08
+#define HCI_FEATURE_TRANSPNT_OFF        2
+#define HCI_LMP_TRANSPNT_SUPPORTED(x)   ((x)[HCI_FEATURE_TRANSPNT_OFF] & HCI_FEATURE_TRANSPNT_MASK)
+
+#define HCI_FEATURE_FLOW_CTRL_LAG_MASK  0x70
+#define HCI_FEATURE_FLOW_CTRL_LAG_OFF   2
+#define HCI_FLOW_CTRL_LAG_VALUE(x)      (((x)[HCI_FEATURE_FLOW_CTRL_LAG_OFF] & HCI_FEATURE_FLOW_CTRL_LAG_MASK) >> 4)
+
+#define HCI_FEATURE_BROADCAST_ENC_MASK  0x80
+#define HCI_FEATURE_BROADCAST_ENC_OFF   2
+#define HCI_LMP_BCAST_ENC_SUPPORTED(x)  ((x)[HCI_FEATURE_BROADCAST_ENC_OFF] & HCI_FEATURE_BROADCAST_ENC_MASK)
+
+#define HCI_FEATURE_SCATTER_MODE_MASK   0x01
+#define HCI_FEATURE_SCATTER_MODE_OFF    3
+#define HCI_LMP_SCATTER_MODE_SUPPORTED(x) ((x)[HCI_FEATURE_SCATTER_MODE_OFF] & HCI_FEATURE_SCATTER_MODE_MASK)
+
+#define HCI_FEATURE_EDR_ACL_2MPS_MASK   0x02
+#define HCI_FEATURE_EDR_ACL_2MPS_OFF    3
+#define HCI_EDR_ACL_2MPS_SUPPORTED(x)   ((x)[HCI_FEATURE_EDR_ACL_2MPS_OFF] & HCI_FEATURE_EDR_ACL_2MPS_MASK)
+
+#define HCI_FEATURE_EDR_ACL_3MPS_MASK   0x04
+#define HCI_FEATURE_EDR_ACL_3MPS_OFF    3
+#define HCI_EDR_ACL_3MPS_SUPPORTED(x)   ((x)[HCI_FEATURE_EDR_ACL_3MPS_OFF] & HCI_FEATURE_EDR_ACL_3MPS_MASK)
+
+#define HCI_FEATURE_ENHANCED_INQ_MASK   0x08
+#define HCI_FEATURE_ENHANCED_INQ_OFF    3
+#define HCI_ENHANCED_INQ_SUPPORTED(x)   ((x)[HCI_FEATURE_ENHANCED_INQ_OFF] & HCI_FEATURE_ENHANCED_INQ_MASK)
+
+#define HCI_FEATURE_INTERLACED_INQ_SCAN_MASK   0x10
+#define HCI_FEATURE_INTERLACED_INQ_SCAN_OFF    3
+#define HCI_LMP_INTERLACED_INQ_SCAN_SUPPORTED(x) ((x)[HCI_FEATURE_INTERLACED_INQ_SCAN_OFF] & HCI_FEATURE_INTERLACED_INQ_SCAN_MASK)
+
+#define HCI_FEATURE_INTERLACED_PAGE_SCAN_MASK  0x20
+#define HCI_FEATURE_INTERLACED_PAGE_SCAN_OFF   3
+#define HCI_LMP_INTERLACED_PAGE_SCAN_SUPPORTED(x) ((x)[HCI_FEATURE_INTERLACED_PAGE_SCAN_OFF] & HCI_FEATURE_INTERLACED_PAGE_SCAN_MASK)
+
+#define HCI_FEATURE_INQ_RSSI_MASK       0x40
+#define HCI_FEATURE_INQ_RSSI_OFF        3
+#define HCI_LMP_INQ_RSSI_SUPPORTED(x)   ((x)[HCI_FEATURE_INQ_RSSI_OFF] & HCI_FEATURE_INQ_RSSI_MASK)
+
+#define HCI_FEATURE_ESCO_EV3_MASK       0x80
+#define HCI_FEATURE_ESCO_EV3_OFF        3
+#define HCI_ESCO_EV3_SUPPORTED(x)       ((x)[HCI_FEATURE_ESCO_EV3_OFF] & HCI_FEATURE_ESCO_EV3_MASK)
+
+#define HCI_FEATURE_ESCO_EV4_MASK       0x01
+#define HCI_FEATURE_ESCO_EV4_OFF        4
+#define HCI_ESCO_EV4_SUPPORTED(x)       ((x)[HCI_FEATURE_ESCO_EV4_OFF] & HCI_FEATURE_ESCO_EV4_MASK)
+
+#define HCI_FEATURE_ESCO_EV5_MASK       0x02
+#define HCI_FEATURE_ESCO_EV5_OFF        4
+#define HCI_ESCO_EV5_SUPPORTED(x)       ((x)[HCI_FEATURE_ESCO_EV5_OFF] & HCI_FEATURE_ESCO_EV5_MASK)
+
+#define HCI_FEATURE_ABSENCE_MASKS_MASK  0x04
+#define HCI_FEATURE_ABSENCE_MASKS_OFF   4
+#define HCI_LMP_ABSENCE_MASKS_SUPPORTED(x) ((x)[HCI_FEATURE_ABSENCE_MASKS_OFF] & HCI_FEATURE_ABSENCE_MASKS_MASK)
+
+#define HCI_FEATURE_AFH_CAP_SLAVE_MASK  0x08
+#define HCI_FEATURE_AFH_CAP_SLAVE_OFF   4
+#define HCI_LMP_AFH_CAP_SLAVE_SUPPORTED(x) ((x)[HCI_FEATURE_AFH_CAP_SLAVE_OFF] & HCI_FEATURE_AFH_CAP_SLAVE_MASK)
+
+#define HCI_FEATURE_AFH_CLASS_SLAVE_MASK 0x10
+#define HCI_FEATURE_AFH_CLASS_SLAVE_OFF  4
+#define HCI_LMP_AFH_CLASS_SLAVE_SUPPORTED(x) ((x)[HCI_FEATURE_AFH_CLASS_SLAVE_OFF] & HCI_FEATURE_AFH_CLASS_SLAVE_MASK)
+
+#define HCI_FEATURE_BREDR_NOT_SPT_MASK     0x20
+#define HCI_FEATURE_BREDR_NOT_SPT_OFF      4
+#define HCI_BREDR_NOT_SPT_SUPPORTED(x) ((x)[HCI_FEATURE_BREDR_NOT_SPT_OFF] & HCI_FEATURE_BREDR_NOT_SPT_MASK)
+
+#define HCI_FEATURE_LE_SPT_MASK      0x40
+#define HCI_FEATURE_LE_SPT_OFF       4
+#define HCI_LE_SPT_SUPPORTED(x)  ((x)[HCI_FEATURE_LE_SPT_OFF] & HCI_FEATURE_LE_SPT_MASK)
+
+#define HCI_FEATURE_3_SLOT_EDR_ACL_MASK 0x80
+#define HCI_FEATURE_3_SLOT_EDR_ACL_OFF  4
+#define HCI_3_SLOT_EDR_ACL_SUPPORTED(x) ((x)[HCI_FEATURE_3_SLOT_EDR_ACL_OFF] & HCI_FEATURE_3_SLOT_EDR_ACL_MASK)
+
+#define HCI_FEATURE_5_SLOT_EDR_ACL_MASK 0x01
+#define HCI_FEATURE_5_SLOT_EDR_ACL_OFF  5
+#define HCI_5_SLOT_EDR_ACL_SUPPORTED(x) ((x)[HCI_FEATURE_5_SLOT_EDR_ACL_OFF] & HCI_FEATURE_5_SLOT_EDR_ACL_MASK)
+
+#define HCI_FEATURE_SNIFF_SUB_RATE_MASK 0x02
+#define HCI_FEATURE_SNIFF_SUB_RATE_OFF  5
+#define HCI_SNIFF_SUB_RATE_SUPPORTED(x) ((x)[HCI_FEATURE_SNIFF_SUB_RATE_OFF] & HCI_FEATURE_SNIFF_SUB_RATE_MASK)
+
+#define HCI_FEATURE_ATOMIC_ENCRYPT_MASK 0x04
+#define HCI_FEATURE_ATOMIC_ENCRYPT_OFF  5
+#define HCI_ATOMIC_ENCRYPT_SUPPORTED(x) ((x)[HCI_FEATURE_ATOMIC_ENCRYPT_OFF] & HCI_FEATURE_ATOMIC_ENCRYPT_MASK)
+
+#define HCI_FEATURE_AFH_CAP_MASTR_MASK  0x08
+#define HCI_FEATURE_AFH_CAP_MASTR_OFF   5
+#define HCI_LMP_AFH_CAP_MASTR_SUPPORTED(x) ((x)[HCI_FEATURE_AFH_CAP_MASTR_OFF] & HCI_FEATURE_AFH_CAP_MASTR_MASK)
+
+#define HCI_FEATURE_AFH_CLASS_MASTR_MASK 0x10
+#define HCI_FEATURE_AFH_CLASS_MASTR_OFF  5
+#define HCI_LMP_AFH_CLASS_MASTR_SUPPORTED(x) ((x)[HCI_FEATURE_AFH_CLASS_MASTR_OFF] & HCI_FEATURE_AFH_CLASS_MASTR_MASK)
+
+#define HCI_FEATURE_EDR_ESCO_2MPS_MASK  0x20
+#define HCI_FEATURE_EDR_ESCO_2MPS_OFF   5
+#define HCI_EDR_ESCO_2MPS_SUPPORTED(x)  ((x)[HCI_FEATURE_EDR_ESCO_2MPS_OFF] & HCI_FEATURE_EDR_ESCO_2MPS_MASK)
+
+#define HCI_FEATURE_EDR_ESCO_3MPS_MASK  0x40
+#define HCI_FEATURE_EDR_ESCO_3MPS_OFF   5
+#define HCI_EDR_ESCO_3MPS_SUPPORTED(x)  ((x)[HCI_FEATURE_EDR_ESCO_3MPS_OFF] & HCI_FEATURE_EDR_ESCO_3MPS_MASK)
+
+#define HCI_FEATURE_3_SLOT_EDR_ESCO_MASK 0x80
+#define HCI_FEATURE_3_SLOT_EDR_ESCO_OFF  5
+#define HCI_3_SLOT_EDR_ESCO_SUPPORTED(x) ((x)[HCI_FEATURE_3_SLOT_EDR_ESCO_OFF] & HCI_FEATURE_3_SLOT_EDR_ESCO_MASK)
+
+#define HCI_FEATURE_EXT_INQ_RSP_MASK    0x01
+#define HCI_FEATURE_EXT_INQ_RSP_OFF     6
+#define HCI_EXT_INQ_RSP_SUPPORTED(x)    ((x)[HCI_FEATURE_EXT_INQ_RSP_OFF] & HCI_FEATURE_EXT_INQ_RSP_MASK)
+
+#if 1 /* TOKYO spec definition */
+#define HCI_FEATURE_SIMUL_LE_BREDR_MASK 0x02
+#define HCI_FEATURE_SIMUL_LE_BREDR_OFF  6
+#define HCI_SIMUL_LE_BREDR_SUPPORTED(x) ((x)[HCI_FEATURE_SIMUL_LE_BREDR_OFF] & HCI_FEATURE_SIMUL_LE_BREDR_MASK)
+
+#else
+#define HCI_FEATURE_ANUM_PIN_AWARE_MASK 0x02
+#define HCI_FEATURE_ANUM_PIN_AWARE_OFF  6
+#define HCI_ANUM_PIN_AWARE_SUPPORTED(x) ((x)[HCI_FEATURE_ANUM_PIN_AWARE_OFF] & HCI_FEATURE_ANUM_PIN_AWARE_MASK)
+#endif
+
+#define HCI_FEATURE_ANUM_PIN_CAP_MASK   0x04
+#define HCI_FEATURE_ANUM_PIN_CAP_OFF    6
+#define HCI_ANUM_PIN_CAP_SUPPORTED(x)   ((x)[HCI_FEATURE_ANUM_PIN_CAP_OFF] & HCI_FEATURE_ANUM_PIN_CAP_MASK)
+
+#define HCI_FEATURE_SIMPLE_PAIRING_MASK 0x08
+#define HCI_FEATURE_SIMPLE_PAIRING_OFF  6
+#define HCI_SIMPLE_PAIRING_SUPPORTED(x) ((x)[HCI_FEATURE_SIMPLE_PAIRING_OFF] & HCI_FEATURE_SIMPLE_PAIRING_MASK)
+
+#define HCI_FEATURE_ENCAP_PDU_MASK      0x10
+#define HCI_FEATURE_ENCAP_PDU_OFF       6
+#define HCI_ENCAP_PDU_SUPPORTED(x)      ((x)[HCI_FEATURE_ENCAP_PDU_OFF] & HCI_FEATURE_ENCAP_PDU_MASK)
+
+#define HCI_FEATURE_ERROR_DATA_MASK     0x20
+#define HCI_FEATURE_ERROR_DATA_OFF      6
+#define HCI_ERROR_DATA_SUPPORTED(x)     ((x)[HCI_FEATURE_ERROR_DATA_OFF] & HCI_FEATURE_ERROR_DATA_MASK)
+
+#define HCI_FEATURE_NON_FLUSHABLE_PB_MASK      0x40
+#define HCI_FEATURE_NON_FLUSHABLE_PB_OFF       6
+
+/* This feature is causing frequent link drops when doing call switch with certain av/hfp headsets */
+#define HCI_NON_FLUSHABLE_PB_SUPPORTED(x)      (0)//((x)[HCI_FEATURE_NON_FLUSHABLE_PB_OFF] & HCI_FEATURE_NON_FLUSHABLE_PB_MASK)
+
+#define HCI_FEATURE_LINK_SUP_TO_EVT_MASK 0x01
+#define HCI_FEATURE_LINK_SUP_TO_EVT_OFF  7
+#define HCI_LINK_SUP_TO_EVT_SUPPORTED(x) ((x)[HCI_FEATURE_LINK_SUP_TO_EVT_OFF] & HCI_FEATURE_LINK_SUP_TO_EVT_MASK)
+
+#define HCI_FEATURE_INQ_RESP_TX_MASK     0x02
+#define HCI_FEATURE_INQ_RESP_TX_OFF      7
+#define HCI_INQ_RESP_TX_SUPPORTED(x)     ((x)[HCI_FEATURE_INQ_RESP_TX_OFF] & HCI_FEATURE_INQ_RESP_TX_MASK)
+
+#define HCI_FEATURE_EXTENDED_MASK       0x80
+#define HCI_FEATURE_EXTENDED_OFF        7
+#define HCI_LMP_EXTENDED_SUPPORTED(x)   ((x)[HCI_FEATURE_EXTENDED_OFF] & HCI_FEATURE_EXTENDED_MASK)
+
+/*
+**   LMP features encoding - page 1
+*/
+#define HCI_EXT_FEATURE_SSP_HOST_MASK 0x01
+#define HCI_EXT_FEATURE_SSP_HOST_OFF  0
+#define HCI_SSP_HOST_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_SSP_HOST_OFF] & HCI_EXT_FEATURE_SSP_HOST_MASK)
+
+#define HCI_EXT_FEATURE_LE_HOST_MASK 0x02
+#define HCI_EXT_FEATURE_LE_HOST_OFF  0
+#define HCI_LE_HOST_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_LE_HOST_OFF] & HCI_EXT_FEATURE_LE_HOST_MASK)
+
+#define HCI_EXT_FEATURE_SIMUL_DUMO_HOST_MASK 0x04
+#define HCI_EXT_FEATURE_SIMUL_DUMO_HOST_OFF  0
+#define HCI_SIMUL_DUMO_HOST_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_SIMUL_DUMO_HOST_OFF] & HCI_EXT_FEATURE_SIMUL_DUMO_HOST_MASK)
+
+#define HCI_EXT_FEATURE_SC_HOST_MASK 0x08
+#define HCI_EXT_FEATURE_SC_HOST_OFF  0
+#define HCI_SC_HOST_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_SC_HOST_OFF] & HCI_EXT_FEATURE_SC_HOST_MASK)
+
+/*
+**   LMP features encoding - page 2
+*/
+#define HCI_EXT_FEATURE_CSB_MASTER_MASK         0x01
+#define HCI_EXT_FEATURE_CSB_MASTER_OFF          0
+#define HCI_CSB_MASTER_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_CSB_MASTER_OFF] & HCI_EXT_FEATURE_CSB_MASTER_MASK)
+
+#define HCI_EXT_FEATURE_CSB_SLAVE_MASK          0x02
+#define HCI_EXT_FEATURE_CSB_SLAVE_OFF           0
+#define HCI_CSB_SLAVE_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_CSB_SLAVE_OFF] & HCI_EXT_FEATURE_CSB_SLAVE_MASK)
+
+#define HCI_EXT_FEATURE_SYNC_TRAIN_MASTER_MASK  0x04
+#define HCI_EXT_FEATURE_SYNC_TRAIN_MASTER_OFF   0
+#define HCI_SYNC_TRAIN_MASTER_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_SYNC_TRAIN_MASTER_OFF] & HCI_EXT_FEATURE_SYNC_TRAIN_MASTER_MASK)
+
+#define HCI_EXT_FEATURE_SYNC_SCAN_SLAVE_MASK    0x08
+#define HCI_EXT_FEATURE_SYNC_SCAN_SLAVE_OFF     0
+#define HCI_SYNC_SCAN_SLAVE_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_SYNC_SCAN_SLAVE_OFF] & HCI_EXT_FEATURE_SYNC_SCAN_SLAVE_MASK)
+
+#define HCI_EXT_FEATURE_INQ_RESP_NOTIF_MASK     0x10
+#define HCI_EXT_FEATURE_INQ_RESP_NOTIF_OFF      0
+#define HCI_INQ_RESP_NOTIF_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_INQ_RESP_NOTIF_OFF] & HCI_EXT_FEATURE_INQ_RESP_NOTIF_MASK)
+
+#define HCI_EXT_FEATURE_SC_CTRLR_MASK           0x01
+#define HCI_EXT_FEATURE_SC_CTRLR_OFF            1
+#define HCI_SC_CTRLR_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_SC_CTRLR_OFF] & HCI_EXT_FEATURE_SC_CTRLR_MASK)
+
+#define HCI_EXT_FEATURE_PING_MASK               0x02
+#define HCI_EXT_FEATURE_PING_OFF                1
+#define HCI_PING_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_PING_OFF] & HCI_EXT_FEATURE_PING_MASK)
+
+/*
+**   LE features encoding - page 0 (the only page for now)
+*/
+/* LE Encryption */
+#define HCI_LE_FEATURE_LE_ENCRYPTION_MASK       0x01
+#define HCI_LE_FEATURE_LE_ENCRYPTION_OFF        0
+#define HCI_LE_ENCRYPTION_SUPPORTED(x) ((x)[HCI_LE_FEATURE_LE_ENCRYPTION_OFF] & HCI_LE_FEATURE_LE_ENCRYPTION_MASK)
+
+/* Connection Parameters Request Procedure */
+#define HCI_LE_FEATURE_CONN_PARAM_REQ_MASK       0x02
+#define HCI_LE_FEATURE_CONN_PARAM_REQ_OFF        0
+#define HCI_LE_CONN_PARAM_REQ_SUPPORTED(x) ((x)[HCI_LE_FEATURE_CONN_PARAM_REQ_OFF] & HCI_LE_FEATURE_CONN_PARAM_REQ_MASK)
+
+/* Extended Reject Indication */
+#define HCI_LE_FEATURE_EXT_REJ_IND_MASK       0x04
+#define HCI_LE_FEATURE_EXT_REJ_IND_OFF        0
+#define HCI_LE_EXT_REJ_IND_SUPPORTED(x) ((x)[HCI_LE_FEATURE_EXT_REJ_IND_OFF] & HCI_LE_FEATURE_EXT_REJ_IND_MASK)
+
+/* Slave-initiated Features Exchange */
+#define HCI_LE_FEATURE_SLAVE_INIT_FEAT_EXC_MASK       0x08
+#define HCI_LE_FEATURE_SLAVE_INIT_FEAT_EXC_OFF        0
+#define HCI_LE_SLAVE_INIT_FEAT_EXC_SUPPORTED(x) ((x)[HCI_LE_FEATURE_SLAVE_INIT_FEAT_EXC_OFF] & HCI_LE_FEATURE_SLAVE_INIT_FEAT_EXC_MASK)
+
+/* Enhanced privacy Feature: bit 6 */
+#define HCI_LE_FEATURE_ENHANCED_PRIVACY_MASK       0x40
+#define HCI_LE_FEATURE_ENHANCED_PRIVACY_OFF        0
+#define HCI_LE_ENHANCED_PRIVACY_SUPPORTED(x) ((x)[HCI_LE_FEATURE_ENHANCED_PRIVACY_OFF] & HCI_LE_FEATURE_ENHANCED_PRIVACY_MASK)
+
+/* Extended scanner filter policy : 7 */
+#define HCI_LE_FEATURE_EXT_SCAN_FILTER_POLICY_MASK       0x80
+#define HCI_LE_FEATURE_EXT_SCAN_FILTER_POLICY_OFF        0
+#define HCI_LE_EXT_SCAN_FILTER_POLICY_SUPPORTED(x) ((x)[HCI_LE_FEATURE_EXT_SCAN_FILTER_POLICY_OFF] & HCI_LE_FEATURE_EXT_SCAN_FILTER_POLICY_MASK)
+
+/* Slave-initiated Features Exchange */
+#define HCI_LE_FEATURE_DATA_LEN_EXT_MASK       0x20
+#define HCI_LE_FEATURE_DATA_LEN_EXT_OFF        0
+#define HCI_LE_DATA_LEN_EXT_SUPPORTED(x) ((x)[HCI_LE_FEATURE_DATA_LEN_EXT_OFF] & HCI_LE_FEATURE_DATA_LEN_EXT_MASK)
+
+/*
+**   Local Supported Commands encoding
+*/
+#define HCI_NUM_SUPP_COMMANDS_BYTES           64
+
+/* Supported Commands Byte 0 */
+#define HCI_SUPP_COMMANDS_INQUIRY_MASK 0x01
+#define HCI_SUPP_COMMANDS_INQUIRY_OFF  0
+#define HCI_INQUIRY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_INQUIRY_OFF] & HCI_SUPP_COMMANDS_INQUIRY_MASK)
+
+#define HCI_SUPP_COMMANDS_INQUIRY_CANCEL_MASK 0x02
+#define HCI_SUPP_COMMANDS_INQUIRY_CANCEL_OFF  0
+#define HCI_INQUIRY_CANCEL_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_INQUIRY_CANCEL_OFF] & HCI_SUPP_COMMANDS_INQUIRY_CANCEL_MASK)
+
+#define HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_MASK     0x04
+#define HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_OFF      0
+#define HCI_PERIODIC_INQUIRY_SUPPORTED(x)     ((x)[HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_OFF] & HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_MASK)
+
+#define HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_MASK    0x08
+#define HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_OFF     0
+#define HCI_EXIT_PERIODIC_INQUIRY_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_OFF] & HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_MASK)
+
+#define HCI_SUPP_COMMANDS_CREATE_CONN_MASK     0x10
+#define HCI_SUPP_COMMANDS_CREATE_CONN_OFF      0
+#define HCI_CREATE_CONN_SUPPORTED(x)     ((x)[HCI_SUPP_COMMANDS_CREATE_CONN_OFF] & HCI_SUPP_COMMANDS_CREATE_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_DISCONNECT_MASK         0x20
+#define HCI_SUPP_COMMANDS_DISCONNECT_OFF          0
+#define HCI_DISCONNECT_SUPPORTED(x)         ((x)[HCI_SUPP_COMMANDS_DISCONNECT_OFF] & HCI_SUPP_COMMANDS_DISCONNECT_MASK)
+
+#define HCI_SUPP_COMMANDS_ADD_SCO_CONN_MASK      0x40
+#define HCI_SUPP_COMMANDS_ADD_SCO_CONN_OFF       0
+#define HCI_ADD_SCO_CONN_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_ADD_SCO_CONN_OFF] & HCI_SUPP_COMMANDS_ADD_SCO_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_MASK     0x80
+#define HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_OFF      0
+#define HCI_CANCEL_CREATE_CONN_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_OFF] & HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_MASK      0x01
+#define HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_OFF       1
+#define HCI_ACCEPT_CONN_REQUEST_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_OFF] & HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_MASK           0x02
+#define HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_OFF            1
+#define HCI_REJECT_CONN_REQUEST_SUPPORTED(x)           ((x)[HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_OFF] & HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_MASK  0x04
+#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_OFF   1
+#define HCI_LINK_KEY_REQUEST_REPLY_SUPPORTED(x)  ((x)[HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_MASK       0x08
+#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_OFF        1
+#define HCI_LINK_KEY_REQUEST_NEG_REPLY_SUPPORTED(x)       ((x)[HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_MASK    0x10
+#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_OFF     1
+#define HCI_PIN_CODE_REQUEST_REPLY_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_MASK    0x20
+#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_OFF     1
+#define HCI_PIN_CODE_REQUEST_NEG_REPLY_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_MASK          0x40
+#define HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_OFF           1
+#define HCI_CHANGE_CONN_PKT_TYPE_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_OFF] & HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_AUTH_REQUEST_MASK          0x80
+#define HCI_SUPP_COMMANDS_AUTH_REQUEST_OFF           1
+#define HCI_AUTH_REQUEST_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_AUTH_REQUEST_OFF] & HCI_SUPP_COMMANDS_AUTH_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_MASK      0x01
+#define HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_OFF       2
+#define HCI_SET_CONN_ENCRYPTION_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_OFF] & HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_MASK)
+
+#define HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_MASK           0x02
+#define HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_OFF            2
+#define HCI_CHANGE_CONN_LINK_KEY_SUPPORTED(x)           ((x)[HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_MASTER_LINK_KEY_MASK  0x04
+#define HCI_SUPP_COMMANDS_MASTER_LINK_KEY_OFF   2
+#define HCI_MASTER_LINK_KEY_SUPPORTED(x)  ((x)[HCI_SUPP_COMMANDS_MASTER_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_MASTER_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_MASK       0x08
+#define HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_OFF        2
+#define HCI_REMOTE_NAME_REQUEST_SUPPORTED(x)       ((x)[HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_OFF] & HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_MASK    0x10
+#define HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_OFF     2
+#define HCI_CANCEL_REMOTE_NAME_REQUEST_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_OFF] & HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_MASK    0x20
+#define HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_OFF     2
+#define HCI_READ_REMOTE_SUPP_FEATURES_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_OFF] & HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_MASK          0x40
+#define HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_OFF           2
+#define HCI_READ_REMOTE_EXT_FEATURES_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_OFF] & HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_MASK          0x80
+#define HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_OFF           2
+#define HCI_READ_REMOTE_VER_INFO_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_OFF] & HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_MASK           0x01
+#define HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_OFF            3
+#define HCI_READ_CLOCK_OFFSET_SUPPORTED(x)       ((x)[HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_OFF] & HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LMP_HANDLE_MASK  0x02
+#define HCI_SUPP_COMMANDS_READ_LMP_HANDLE_OFF   3
+#define HCI_READ_LMP_HANDLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LMP_HANDLE_OFF] & HCI_SUPP_COMMANDS_READ_LMP_HANDLE_MASK)
+
+#define HCI_SUPP_COMMANDS_HOLD_MODE_CMD_MASK           0x02
+#define HCI_SUPP_COMMANDS_HOLD_MODE_CMD_OFF            4
+#define HCI_HOLD_MODE_CMD_SUPPORTED(x)           ((x)[HCI_SUPP_COMMANDS_HOLD_MODE_CMD_OFF] & HCI_SUPP_COMMANDS_HOLD_MODE_CMD_MASK)
+
+#define HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_MASK  0x04
+#define HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_OFF   4
+#define HCI_SNIFF_MODE_CMD_SUPPORTED(x)  ((x)[HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_OFF] & HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_MASK)
+
+#define HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_MASK       0x08
+#define HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_OFF        4
+#define HCI_EXIT_SNIFF_MODE_SUPPORTED(x)       ((x)[HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_OFF] & HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_PARK_STATE_MASK    0x10
+#define HCI_SUPP_COMMANDS_PARK_STATE_OFF     4
+#define HCI_PARK_STATE_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_PARK_STATE_OFF] & HCI_SUPP_COMMANDS_PARK_STATE_MASK)
+
+#define HCI_SUPP_COMMANDS_EXIT_PARK_STATE_MASK    0x20
+#define HCI_SUPP_COMMANDS_EXIT_PARK_STATE_OFF     4
+#define HCI_EXIT_PARK_STATE_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_EXIT_PARK_STATE_OFF] & HCI_SUPP_COMMANDS_EXIT_PARK_STATE_MASK)
+
+#define HCI_SUPP_COMMANDS_QOS_SETUP_MASK          0x40
+#define HCI_SUPP_COMMANDS_QOS_SETUP_OFF           4
+#define HCI_QOS_SETUP_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_QOS_SETUP_OFF] & HCI_SUPP_COMMANDS_QOS_SETUP_MASK)
+
+#define HCI_SUPP_COMMANDS_ROLE_DISCOVERY_MASK          0x80
+#define HCI_SUPP_COMMANDS_ROLE_DISCOVERY_OFF           4
+#define HCI_ROLE_DISCOVERY_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_ROLE_DISCOVERY_OFF] & HCI_SUPP_COMMANDS_ROLE_DISCOVERY_MASK)
+
+#define HCI_SUPP_COMMANDS_SWITCH_ROLE_MASK      0x01
+#define HCI_SUPP_COMMANDS_SWITCH_ROLE_OFF       5
+#define HCI_SWITCH_ROLE_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_SWITCH_ROLE_OFF] & HCI_SUPP_COMMANDS_SWITCH_ROLE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_MASK           0x02
+#define HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_OFF            5
+#define HCI_READ_LINK_POLICY_SET_SUPPORTED(x)           ((x)[HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_OFF] & HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_MASK  0x04
+#define HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_OFF   5
+#define HCI_WRITE_LINK_POLICY_SET_SUPPORTED(x)  ((x)[HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_OFF] & HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_MASK       0x08
+#define HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_OFF        5
+#define HCI_READ_DEF_LINK_POLICY_SET_SUPPORTED(x)       ((x)[HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_OFF] & HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_MASK    0x10
+#define HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_OFF     5
+#define HCI_WRITE_DEF_LINK_POLICY_SET_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_OFF] & HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_MASK)
+
+#define HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_MASK    0x20
+#define HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_OFF     5
+#define HCI_FLOW_SPECIFICATION_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_OFF] & HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_MASK          0x40
+#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_OFF           5
+#define HCI_SET_EVENT_MASK_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_SET_EVENT_MASK_OFF] & HCI_SUPP_COMMANDS_SET_EVENT_MASK_MASK)
+
+#define HCI_SUPP_COMMANDS_RESET_MASK          0x80
+#define HCI_SUPP_COMMANDS_RESET_OFF           5
+#define HCI_RESET_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_RESET_OFF] & HCI_SUPP_COMMANDS_RESET_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_EVENT_FILTER_MASK      0x01
+#define HCI_SUPP_COMMANDS_SET_EVENT_FILTER_OFF       6
+#define HCI_SET_EVENT_FILTER_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_SET_EVENT_FILTER_OFF] & HCI_SUPP_COMMANDS_SET_EVENT_FILTER_MASK)
+
+#define HCI_SUPP_COMMANDS_FLUSH_MASK           0x02
+#define HCI_SUPP_COMMANDS_FLUSH_OFF            6
+#define HCI_FLUSH_SUPPORTED(x)           ((x)[HCI_SUPP_COMMANDS_FLUSH_OFF] & HCI_SUPP_COMMANDS_FLUSH_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PIN_TYPE_MASK  0x04
+#define HCI_SUPP_COMMANDS_READ_PIN_TYPE_OFF   6
+#define HCI_READ_PIN_TYPE_SUPPORTED(x)  ((x)[HCI_SUPP_COMMANDS_READ_PIN_TYPE_OFF] & HCI_SUPP_COMMANDS_READ_PIN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_MASK       0x08
+#define HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_OFF        6
+#define HCI_WRITE_PIN_TYPE_SUPPORTED(x)       ((x)[HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_OFF] & HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_MASK    0x10
+#define HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_OFF     6
+#define HCI_CREATE_NEW_UNIT_KEY_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_OFF] & HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_MASK    0x20
+#define HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_OFF     6
+#define HCI_READ_STORED_LINK_KEY_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_MASK          0x40
+#define HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_OFF           6
+#define HCI_WRITE_STORED_LINK_KEY_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_MASK          0x80
+#define HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_OFF           6
+#define HCI_DELETE_STORED_LINK_KEY_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_MASK      0x01
+#define HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_OFF       7
+#define HCI_WRITE_LOCAL_NAME_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_OFF] & HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_NAME_MASK           0x02
+#define HCI_SUPP_COMMANDS_READ_LOCAL_NAME_OFF            7
+#define HCI_READ_LOCAL_NAME_SUPPORTED(x)           ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_NAME_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_NAME_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_MASK  0x04
+#define HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_OFF   7
+#define HCI_READ_CONN_ACCEPT_TOUT_SUPPORTED(x)  ((x)[HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_MASK       0x08
+#define HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_OFF        7
+#define HCI_WRITE_CONN_ACCEPT_TOUT_SUPPORTED(x)       ((x)[HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_TOUT_MASK    0x10
+#define HCI_SUPP_COMMANDS_READ_PAGE_TOUT_OFF     7
+#define HCI_READ_PAGE_TOUT_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_READ_PAGE_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_MASK    0x20
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_OFF     7
+#define HCI_WRITE_PAGE_TOUT_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_MASK          0x40
+#define HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_OFF           7
+#define HCI_READ_SCAN_ENABLE_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_OFF] & HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_MASK          0x80
+#define HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_OFF           7
+#define HCI_WRITE_SCAN_ENABLE_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_OFF] & HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_MASK      0x01
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_OFF       8
+#define HCI_READ_PAGE_SCAN_ACTIVITY_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_MASK           0x02
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_OFF            8
+#define HCI_WRITE_PAGE_SCAN_ACTIVITY_SUPPORTED(x)           ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_MASK  0x04
+#define HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_OFF   8
+#define HCI_READ_INQURIY_SCAN_ACTIVITY_SUPPORTED(x)  ((x)[HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_MASK       0x08
+#define HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_OFF        8
+#define HCI_WRITE_INQURIY_SCAN_ACTIVITY_SUPPORTED(x)       ((x)[HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_MASK    0x10
+#define HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_OFF     8
+#define HCI_READ_AUTH_ENABLE_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_OFF] & HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_MASK    0x20
+#define HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_OFF     8
+#define HCI_WRITE_AUTH_ENABLE_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_OFF] & HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_MASK          0x40
+#define HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_OFF           8
+#define HCI_READ_ENCRYPT_ENABLE_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_OFF] & HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_MASK          0x80
+#define HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_OFF           8
+#define HCI_WRITE_ENCRYPT_ENABLE_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_OFF] & HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_MASK      0x01
+#define HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_OFF       9
+#define HCI_READ_CLASS_DEVICE_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_OFF] & HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_MASK           0x02
+#define HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_OFF            9
+#define HCI_WRITE_CLASS_DEVICE_SUPPORTED(x)           ((x)[HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_OFF] & HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_VOICE_SETTING_MASK  0x04
+#define HCI_SUPP_COMMANDS_READ_VOICE_SETTING_OFF   9
+#define HCI_READ_VOICE_SETTING_SUPPORTED(x)  ((x)[HCI_SUPP_COMMANDS_READ_VOICE_SETTING_OFF] & HCI_SUPP_COMMANDS_READ_VOICE_SETTING_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_MASK       0x08
+#define HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_OFF        9
+#define HCI_WRITE_VOICE_SETTING_SUPPORTED(x)       ((x)[HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_OFF] & HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_MASK    0x10
+#define HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_OFF     9
+#define HCI_READ_AUTO_FLUSH_TOUT_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_MASK    0x20
+#define HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_OFF     9
+#define HCI_WRITE_AUTO_FLUSH_TOUT_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_MASK          0x40
+#define HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_OFF           9
+#define HCI_READ_NUM_BROAD_RETRANS_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_OFF] & HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_MASK          0x80
+#define HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_OFF           9
+#define HCI_WRITE_NUM_BROAD_RETRANS_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_OFF] & HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_MASK      0x01
+#define HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_OFF       10
+#define HCI_READ_HOLD_MODE_ACTIVITY_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_MASK           0x02
+#define HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_OFF            10
+#define HCI_WRITE_HOLD_MODE_ACTIVITY_SUPPORTED(x)           ((x)[HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_MASK  0x04
+#define HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_OFF   10
+#define HCI_READ_TRANS_PWR_LEVEL_SUPPORTED(x)  ((x)[HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_OFF] & HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_MASK       0x08
+#define HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_OFF        10
+#define HCI_READ_SYNCH_FLOW_CTRL_ENABLE_SUPPORTED(x)       ((x)[HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_OFF] & HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_MASK    0x10
+#define HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_OFF     10
+#define HCI_WRITE_SYNCH_FLOW_CTRL_ENABLE_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_OFF] & HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_MASK    0x20
+#define HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_OFF     10
+#define HCI_SET_HOST_CTRLR_TO_HOST_FC_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_OFF] & HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_MASK)
+
+#define HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_MASK          0x40
+#define HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_OFF           10
+#define HCI_HOST_BUFFER_SIZE_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_OFF] & HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_MASK)
+
+#define HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_MASK          0x80
+#define HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_OFF           10
+#define HCI_HOST_NUM_COMPLETED_PKTS_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_OFF] & HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_MASK      0x01
+#define HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_OFF       11
+#define HCI_READ_LINK_SUP_TOUT_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_MASK           0x02
+#define HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_OFF            11
+#define HCI_WRITE_LINK_SUP_TOUT_SUPPORTED(x)           ((x)[HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_MASK  0x04
+#define HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_OFF   11
+#define HCI_READ_NUM_SUPP_IAC_SUPPORTED(x)  ((x)[HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_OFF] & HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_MASK       0x08
+#define HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_OFF        11
+#define HCI_READ_CURRENT_IAC_LAP_SUPPORTED(x)       ((x)[HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_OFF] & HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_MASK    0x10
+#define HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_OFF     11
+#define HCI_WRITE_CURRENT_IAC_LAP_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_OFF] & HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_MASK    0x20
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_OFF     11
+#define HCI_READ_PAGE_SCAN_PER_MODE_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_MASK          0x40
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_OFF           11
+#define HCI_WRITE_PAGE_SCAN_PER_MODE_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_MASK          0x80
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_OFF           11
+#define HCI_READ_PAGE_SCAN_MODE_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_MASK      0x01
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_OFF       12
+#define HCI_WRITE_PAGE_SCAN_MODE_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_MASK           0x02
+#define HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_OFF            12
+#define HCI_SET_AFH_CHNL_CLASS_SUPPORTED(x)           ((x)[HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_OFF] & HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_MASK    0x10
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_OFF     12
+#define HCI_READ_INQUIRY_SCAN_TYPE_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_OFF] & HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_MASK    0x20
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_OFF     12
+#define HCI_WRITE_INQUIRY_SCAN_TYPE_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_OFF] & HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_MASK          0x40
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_OFF           12
+#define HCI_READ_INQUIRY_MODE_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_OFF] & HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_MASK          0x80
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_OFF           12
+#define HCI_WRITE_INQUIRY_MODE_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_MASK      0x01
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_OFF       13
+#define HCI_READ_PAGE_SCAN_TYPE_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_MASK           0x02
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_OFF            13
+#define HCI_WRITE_PAGE_SCAN_TYPE_SUPPORTED(x)           ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_MASK  0x04
+#define HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_OFF   13
+#define HCI_READ_AFH_CHNL_ASSESS_MODE_SUPPORTED(x)  ((x)[HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_OFF] & HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_MASK       0x08
+#define HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_OFF        13
+#define HCI_WRITE_AFH_CHNL_ASSESS_MODE_SUPPORTED(x)       ((x)[HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_MASK       0x08
+#define HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_OFF        14
+#define HCI_READ_LOCAL_VER_INFO_SUPPORTED(x)       ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_MASK       0x10
+#define HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_OFF        14
+#define HCI_READ_LOCAL_SUP_CMDS_SUPPORTED(x)       ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_MASK    0x20
+#define HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_OFF     14
+#define HCI_READ_LOCAL_SUPP_FEATURES_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_MASK          0x40
+#define HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_OFF           14
+#define HCI_READ_LOCAL_EXT_FEATURES_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_MASK          0x80
+#define HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_OFF           14
+#define HCI_READ_BUFFER_SIZE_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_OFF] & HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_MASK      0x01
+#define HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_OFF       15
+#define HCI_READ_COUNTRY_CODE_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_OFF] & HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_BD_ADDR_MASK           0x02
+#define HCI_SUPP_COMMANDS_READ_BD_ADDR_OFF            15
+#define HCI_READ_BD_ADDR_SUPPORTED(x)           ((x)[HCI_SUPP_COMMANDS_READ_BD_ADDR_OFF] & HCI_SUPP_COMMANDS_READ_BD_ADDR_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_MASK  0x04
+#define HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_OFF   15
+#define HCI_READ_FAIL_CONTACT_CNTR_SUPPORTED(x)  ((x)[HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_OFF] & HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_MASK)
+
+#define HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_MASK       0x08
+#define HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_OFF        15
+#define HCI_RESET_FAIL_CONTACT_CNTR_SUPPORTED(x)       ((x)[HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_OFF] & HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_MASK)
+
+#define HCI_SUPP_COMMANDS_GET_LINK_QUALITY_MASK    0x10
+#define HCI_SUPP_COMMANDS_GET_LINK_QUALITY_OFF     15
+#define HCI_GET_LINK_QUALITY_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_GET_LINK_QUALITY_OFF] & HCI_SUPP_COMMANDS_GET_LINK_QUALITY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_RSSI_MASK    0x20
+#define HCI_SUPP_COMMANDS_READ_RSSI_OFF     15
+#define HCI_READ_RSSI_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_READ_RSSI_OFF] & HCI_SUPP_COMMANDS_READ_RSSI_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_MASK          0x40
+#define HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_OFF           15
+#define HCI_READ_AFH_CH_MAP_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_OFF] & HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_BD_CLOCK_MASK          0x80
+#define HCI_SUPP_COMMANDS_READ_BD_CLOCK_OFF           15
+#define HCI_READ_BD_CLOCK_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_READ_BD_CLOCK_OFF] & HCI_SUPP_COMMANDS_READ_BD_CLOCK_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_MASK      0x01
+#define HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_OFF       16
+#define HCI_READ_LOOPBACK_MODE_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_OFF] & HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_MASK           0x02
+#define HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_OFF            16
+#define HCI_WRITE_LOOPBACK_MODE_SUPPORTED(x)           ((x)[HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_MASK  0x04
+#define HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_OFF   16
+#define HCI_ENABLE_DEV_UNDER_TEST_SUPPORTED(x)  ((x)[HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_OFF] & HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_MASK)
+
+#define HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_MASK       0x08
+#define HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_OFF        16
+#define HCI_SETUP_SYNCH_CONN_SUPPORTED(x)       ((x)[HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_MASK    0x10
+#define HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_OFF     16
+#define HCI_ACCEPT_SYNCH_CONN_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_MASK    0x20
+#define HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_OFF     16
+#define HCI_REJECT_SYNCH_CONN_SUPPORTED(x)    ((x)[HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_MASK   0x01
+#define HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_OFF    17
+#define HCI_READ_EXT_INQUIRY_RESP_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_OFF] & HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_MASK  0x02
+#define HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_OFF   17
+#define HCI_WRITE_EXT_INQUIRY_RESP_SUPPORTED(x)  ((x)[HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_OFF] & HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_MASK)
+
+#define HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_MASK   0x04
+#define HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_OFF    17
+#define HCI_REFRESH_ENCRYPTION_KEY_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_OFF] & HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_MASK)
+
+/* Octet 17, bit 3 is reserved */
+
+#define HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_MASK       0x10
+#define HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_OFF        17
+#define HCI_SNIFF_SUB_RATE_CMD_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_OFF] & HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_MASK   0x20
+#define HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_OFF    17
+#define HCI_READ_SIMPLE_PAIRING_MODE_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_OFF] & HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_MASK   0x40
+#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_OFF    17
+#define HCI_WRITE_SIMPLE_PAIRING_MODE_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_MASK   0x80
+#define HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_OFF    17
+#define HCI_READ_LOCAL_OOB_DATA_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_MASK   0x01
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_OFF    18
+#define HCI_READ_INQUIRY_RESPONSE_TX_POWER_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_OFF] & HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_MASK   0x02
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_OFF    18
+#define HCI_WRITE_INQUIRY_RESPONSE_TX_POWER_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_OFF] & HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK   0x04
+#define HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF    18
+#define HCI_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF] & HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK   0x08
+#define HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF    18
+#define HCI_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF] & HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK)
+
+#define HCI_SUPP_COMMANDS_IO_CAPABILITY_REQUEST_REPLY_MASK   0x80
+#define HCI_SUPP_COMMANDS_IO_CAPABILITY_REQUEST_REPLY_OFF    18
+#define HCI_IO_CAPABILITY_REQUEST_REPLY_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_IO_CAPABILITY_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_IO_CAPABILITY_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_MASK   0x01
+#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_OFF    19
+#define HCI_USER_CONFIRMATION_REQUEST_REPLY_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_MASK   0x02
+#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_OFF    19
+#define HCI_USER_CONFIRMATION_REQUEST_NEG_REPLY_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_MASK   0x04
+#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_OFF    19
+#define HCI_USER_PASSKEY_REQUEST_REPLY_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_MASK   0x08
+#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_OFF    19
+#define HCI_USER_PASSKEY_REQUEST_NEG_REPLY_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_MASK   0x10
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_OFF    19
+#define HCI_REMOTE_OOB_DATA_REQUEST_REPLY_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_MASK       0x20
+#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_OFF        19
+#define HCI_WRITE_SIMPLE_PAIRING_DBG_MODE_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_ENHANCED_FLUSH_MASK   0x40
+#define HCI_SUPP_COMMANDS_ENHANCED_FLUSH_OFF    19
+#define HCI_ENHANCED_FLUSH_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_ENHANCED_FLUSH_OFF] & HCI_SUPP_COMMANDS_ENHANCED_FLUSH_MASK)
+
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_MASK       0x80
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_OFF        19
+#define HCI_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_MASK)
+
+/* Supported Commands (Byte 20) */
+#define HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_MASK       0x04
+#define HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_OFF        20
+#define HCI_SEND_NOTIF_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_OFF] & HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_MASK)
+
+#define HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_MASK      0x08
+#define HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_OFF       20
+#define HCI_IO_CAP_REQ_NEG_REPLY_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_ENCR_KEY_SIZE_MASK      0x10
+#define HCI_SUPP_COMMANDS_READ_ENCR_KEY_SIZE_OFF       20
+#define HCI_READ_ENCR_KEY_SIZE_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_READ_ENCR_KEY_SIZE_OFF] & HCI_SUPP_COMMANDS_READ_ENCR_KEY_SIZE_MASK)
+
+/* Supported Commands (Byte 21) */
+#define HCI_SUPP_COMMANDS_CREATE_PHYSICAL_LINK_MASK   0x01
+#define HCI_SUPP_COMMANDS_CREATE_PHYSICAL_LINK_OFF    21
+#define HCI_CREATE_PHYSICAL_LINK_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_CREATE_PHYSICAL_LINK_OFF] & HCI_SUPP_COMMANDS_CREATE_PHYSICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_ACCEPT_PHYSICAL_LINK_MASK   0x02
+#define HCI_SUPP_COMMANDS_ACCEPT_PHYSICAL_LINK_OFF    21
+#define HCI_ACCEPT_PHYSICAL_LINK_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_ACCEPT_PHYSICAL_LINK_OFF] & HCI_SUPP_COMMANDS_ACCEPT_PHYSICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_DISCONNECT_PHYSICAL_LINK_MASK   0x04
+#define HCI_SUPP_COMMANDS_DISCONNECT_PHYSICAL_LINK_OFF    21
+#define HCI_DISCONNECT_PHYSICAL_LINK_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_DISCONNECT_PHYSICAL_LINK_OFF] & HCI_SUPP_COMMANDS_DISCONNECT_PHYSICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_CREATE_LOGICAL_LINK_MASK   0x08
+#define HCI_SUPP_COMMANDS_CREATE_LOGICAL_LINK_OFF    21
+#define HCI_CREATE_LOGICAL_LINK_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_CREATE_LOGICAL_LINK_OFF] & HCI_SUPP_COMMANDS_CREATE_LOGICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_ACCEPT_LOGICAL_LINK_MASK   0x10
+#define HCI_SUPP_COMMANDS_ACCEPT_LOGICAL_LINK_OFF    21
+#define HCI_ACCEPT_LOGICAL_LINK_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_ACCEPT_LOGICAL_LINK_OFF] & HCI_SUPP_COMMANDS_ACCEPT_LOGICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_DISCONNECT_LOGICAL_LINK_MASK   0x20
+#define HCI_SUPP_COMMANDS_DISCONNECT_LOGICAL_LINK_OFF    21
+#define HCI_DISCONNECT_LOGICAL_LINK_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_DISCONNECT_LOGICAL_LINK_OFF] & HCI_SUPP_COMMANDS_DISCONNECT_LOGICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_LOGICAL_LINK_CANCEL_MASK   0x40
+#define HCI_SUPP_COMMANDS_LOGICAL_LINK_CANCEL_OFF    21
+#define HCI_LOGICAL_LINK_CANCEL_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_LOGICAL_LINK_CANCEL_OFF] & HCI_SUPP_COMMANDS_LOGICAL_LINK_CANCEL_MASK)
+
+#define HCI_SUPP_COMMANDS_FLOW_SPEC_MODIFY_MASK       0x80
+#define HCI_SUPP_COMMANDS_FLOW_SPEC_MODIFY_OFF        21
+#define HCI_FLOW_SPEC_MODIFY_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_FLOW_SPEC_MODIFY_OFF] & HCI_SUPP_COMMANDS_FLOW_SPEC_MODIFY_MASK)
+
+/* Supported Commands (Byte 22) */
+#define HCI_SUPP_COMMANDS_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_MASK   0x01
+#define HCI_SUPP_COMMANDS_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_OFF    22
+#define HCI_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_OFF] & HCI_SUPP_COMMANDS_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_MASK   0x02
+#define HCI_SUPP_COMMANDS_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_OFF    22
+#define HCI_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_PAGE_2_MASK   0x04
+#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_PAGE_2_OFF    22
+#define HCI_SET_EVENT_MASK_PAGE_2_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_SET_EVENT_MASK_PAGE_2_OFF] & HCI_SUPP_COMMANDS_SET_EVENT_MASK_PAGE_2_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCATION_DATA_MASK   0x08
+#define HCI_SUPP_COMMANDS_READ_LOCATION_DATA_OFF    22
+#define HCI_READ_LOCATION_DATA_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_READ_LOCATION_DATA_OFF] & HCI_SUPP_COMMANDS_READ_LOCATION_DATA_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LOCATION_DATA_MASK   0x10
+#define HCI_SUPP_COMMANDS_WRITE_LOCATION_DATA_OFF    22
+#define HCI_WRITE_LOCATION_DATA_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_WRITE_LOCATION_DATA_OFF] & HCI_SUPP_COMMANDS_WRITE_LOCATION_DATA_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_AMP_INFO_MASK   0x20
+#define HCI_SUPP_COMMANDS_READ_LOCAL_AMP_INFO_OFF    22
+#define HCI_READ_LOCAL_AMP_INFO_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_AMP_INFO_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_AMP_INFO_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_AMP_ASSOC_MASK   0x40
+#define HCI_SUPP_COMMANDS_READ_LOCAL_AMP_ASSOC_OFF    22
+#define HCI_READ_LOCAL_AMP_ASSOC_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_AMP_ASSOC_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_AMP_ASSOC_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_REMOTE_AMP_ASSOC_MASK   0x80
+#define HCI_SUPP_COMMANDS_WRITE_REMOTE_AMP_ASSOC_OFF    22
+#define HCI_WRITE_REMOTE_AMP_ASSOC_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_WRITE_REMOTE_AMP_ASSOC_OFF] & HCI_SUPP_COMMANDS_WRITE_REMOTE_AMP_ASSOC_MASK)
+
+/* Supported Commands (Byte 23) */
+#define HCI_SUPP_COMMANDS_READ_FLOW_CONTROL_MODE_MASK   0x01
+#define HCI_SUPP_COMMANDS_READ_FLOW_CONTROL_MODE_OFF    23
+#define HCI_READ_FLOW_CONTROL_MODE_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_READ_FLOW_CONTROL_MODE_OFF] & HCI_SUPP_COMMANDS_READ_FLOW_CONTROL_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_FLOW_CONTROL_MODE_MASK   0x02
+#define HCI_SUPP_COMMANDS_WRITE_FLOW_CONTROL_MODE_OFF    23
+#define HCI_WRITE_FLOW_CONTROL_MODE_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_WRITE_FLOW_CONTROL_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_FLOW_CONTROL_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_DATA_BLOCK_SIZE_MASK   0x04
+#define HCI_SUPP_COMMANDS_READ_DATA_BLOCK_SIZE_OFF    23
+#define HCI_READ_DATA_BLOCK_SIZE_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_READ_DATA_BLOCK_SIZE_OFF] & HCI_SUPP_COMMANDS_READ_DATA_BLOCK_SIZE_MASK)
+
+#define HCI_SUPP_COMMANDS_ENABLE_AMP_RCVR_REPORTS_MASK   0x20
+#define HCI_SUPP_COMMANDS_ENABLE_AMP_RCVR_REPORTS_OFF    23
+#define HCI_ENABLE_AMP_RCVR_REPORTS_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_ENABLE_AMP_RCVR_REPORTS_OFF] & HCI_SUPP_COMMANDS_ENABLE_AMP_RCVR_REPORTS_MASK)
+
+#define HCI_SUPP_COMMANDS_AMP_TEST_END_MASK   0x40
+#define HCI_SUPP_COMMANDS_AMP_TEST_END_OFF    23
+#define HCI_AMP_TEST_END_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_AMP_TEST_END_OFF] & HCI_SUPP_COMMANDS_AMP_TEST_END_MASK)
+
+#define HCI_SUPP_COMMANDS_AMP_TEST_MASK   0x80
+#define HCI_SUPP_COMMANDS_AMP_TEST_OFF    23
+#define HCI_AMP_TEST_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_AMP_TEST_OFF] & HCI_SUPP_COMMANDS_AMP_TEST_MASK)
+
+/* Supported Commands (Byte 24) */
+#define HCI_SUPP_COMMANDS_READ_TRANSMIT_POWER_LEVEL_MASK   0x01
+#define HCI_SUPP_COMMANDS_READ_TRANSMIT_POWER_LEVEL_OFF    24
+#define HCI_READ_TRANSMIT_POWER_LEVEL_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_READ_TRANSMIT_POWER_LEVEL_OFF] & HCI_SUPP_COMMANDS_READ_TRANSMIT_POWER_LEVEL_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_BE_FLUSH_TOUT_MASK   0x04
+#define HCI_SUPP_COMMANDS_READ_BE_FLUSH_TOUT_OFF    24
+#define HCI_READ_BE_FLUSH_TOUT_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_READ_BE_FLUSH_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_BE_FLUSH_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_BE_FLUSH_TOUT_MASK   0x08
+#define HCI_SUPP_COMMANDS_WRITE_BE_FLUSH_TOUT_OFF    24
+#define HCI_WRITE_BE_FLUSH_TOUT_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_WRITE_BE_FLUSH_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_BE_FLUSH_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_SHORT_RANGE_MODE_MASK   0x10
+#define HCI_SUPP_COMMANDS_SHORT_RANGE_MODE_OFF    24
+#define HCI_SHORT_RANGE_MODE_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_SHORT_RANGE_MODE_OFF] & HCI_SUPP_COMMANDS_SHORT_RANGE_MODE_MASK)
+
+/* LE commands TBD
+** Supported Commands (Byte 24 continued)
+** Supported Commands (Byte 25)
+** Supported Commands (Byte 26)
+** Supported Commands (Byte 27)
+** Supported Commands (Byte 28)
+*/
+
+/* Supported Commands (Byte 29) */
+#define HCI_SUPP_COMMANDS_ENH_SETUP_SYNCH_CONN_MASK     0x08
+#define HCI_SUPP_COMMANDS_ENH_SETUP_SYNCH_CONN_OFF      29
+#define HCI_READ_ENH_SETUP_SYNCH_CONN_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_ENH_SETUP_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_ENH_SETUP_SYNCH_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_ENH_ACCEPT_SYNCH_CONN_MASK    0x10
+#define HCI_SUPP_COMMANDS_ENH_ACCEPT_SYNCH_CONN_OFF     29
+#define HCI_READ_ENH_ACCEPT_SYNCH_CONN_SUPPORTED(x)     ((x)[HCI_SUPP_COMMANDS_ENH_ACCEPT_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_ENH_ACCEPT_SYNCH_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_CODECS_MASK        0x20
+#define HCI_SUPP_COMMANDS_READ_LOCAL_CODECS_OFF         29
+#define HCI_READ_LOCAL_CODECS_SUPPORTED(x)              ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_CODECS_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_CODECS_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_MWS_CHANN_PARAM_MASK      0x40
+#define HCI_SUPP_COMMANDS_SET_MWS_CHANN_PARAM_OFF       29
+#define HCI_SET_MWS_CHANNEL_PARAMETERS_SUPPORTED(x)     ((x)[HCI_SUPP_COMMANDS_SET_MWS_CHANN_PARAM_OFF] & HCI_SUPP_COMMANDS_SET_MWS_CHANN_PARAM_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_EXT_FRAME_CONF_MASK       0x80
+#define HCI_SUPP_COMMANDS_SET_EXT_FRAME_CONF_OFF        29
+#define HCI_SET_EXTERNAL_FRAME_CONFIGURATION_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_SET_EXT_FRAME_CONF_OFF] & HCI_SUPP_COMMANDS_SET_EXT_FRAME_CONF_MASK)
+
+
+/* Supported Commands (Byte 30) */
+#define HCI_SUPP_COMMANDS_SET_MWS_SIGNALING_MASK     0x01
+#define HCI_SUPP_COMMANDS_SET_MWS_SIGNALING_OFF      30
+#define HCI_SET_MWS_SIGNALING_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_SET_MWS_SIGNALING_OFF] & HCI_SUPP_COMMANDS_SET_MWS_SIGNALING_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_MWS_TRANS_LAYER_MASK   0x02
+#define HCI_SUPP_COMMANDS_SET_MWS_TRANS_LAYER_OFF    30
+#define HCI_SET_MWS_TRANSPORT_LAYER_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_SET_MWS_TRANS_LAYER_OFF] & HCI_SUPP_COMMANDS_SET_MWS_TRANS_LAYER_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_MWS_SCAN_FREQ_TABLE_MASK   0x04
+#define HCI_SUPP_COMMANDS_SET_MWS_SCAN_FREQ_TABLE_OFF    30
+#define HCI_SET_MWS_SCAN_FREQUENCY_TABLE_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_SET_MWS_SCAN_FREQ_TABLE_OFF] & HCI_SUPP_COMMANDS_SET_MWS_SCAN_FREQ_TABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_GET_TRANS_LAYER_CONF_MASK      0x08
+#define HCI_SUPP_COMMANDS_GET_TRANS_LAYER_CONF_OFF    30
+#define HCI_GET_MWS_TRANS_LAYER_CFG_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_GET_TRANS_LAYER_CONF_OFF] & HCI_SUPP_COMMANDS_GET_TRANS_LAYER_CONF_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_MWS_PATTERN_CONF_MASK      0x10
+#define HCI_SUPP_COMMANDS_SET_MWS_PATTERN_CONF_OFF       30
+#define HCI_SET_MWS_PATTERN_CONFIGURATION_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_SET_MWS_PATTERN_CONF_OFF] & HCI_SUPP_COMMANDS_SET_MWS_PATTERN_CONF_MASK)
+
+/* Supported Commands (Byte 30 bit 5) */
+#define HCI_SUPP_COMMANDS_SET_TRIG_CLK_CAP_MASK         0x20
+#define HCI_SUPP_COMMANDS_SET_TRIG_CLK_CAP_OFF          30
+#define HCI_SET_TRIG_CLK_CAP_SUPPORTED(x)               ((x)[HCI_SUPP_COMMANDS_SET_TRIG_CLK_CAP_OFF] & HCI_SUPP_COMMANDS_SET_TRIG_CLK_CAP_MASK)
+
+
+/* Supported Commands (Byte 30 bit 6-7) */
+#define HCI_SUPP_COMMANDS_TRUNCATED_PAGE             0x06
+#define HCI_SUPP_COMMANDS_TRUNCATED_PAGE_OFF         30
+#define HCI_TRUNCATED_PAGE_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_TRUNCATED_PAGE_OFF] & HCI_SUPP_COMMANDS_TRUNCATED_PAGE)
+
+#define HCI_SUPP_COMMANDS_TRUNCATED_PAGE_CANCEL             0x07
+#define HCI_SUPP_COMMANDS_TRUNCATED_PAGE_CANCEL_OFF         30
+#define HCI_TRUNCATED_PAGE_CANCEL_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_TRUNCATED_PAGE_CANCEL_OFF] & HCI_SUPP_COMMANDS_TRUNCATED_PAGE_CANCEL)
+
+/* Supported Commands (Byte 31 bit 6-7) */
+#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST             0x00
+#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_OFF         31
+#define HCI_SET_CONLESS_SLAVE_BRCST_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_OFF] & HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST)
+
+#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_RECEIVE             0x01
+#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_RECEIVE_OFF         31
+#define HCI_SET_CONLESS_SLAVE_BRCST_RECEIVE_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_RECEIVE_OFF] & HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_RECEIVE)
+
+#define HCI_SUPP_COMMANDS_START_SYNC_TRAIN             0x02
+#define HCI_SUPP_COMMANDS_START_SYNC_TRAIN_OFF         31
+#define HCI_START_SYNC_TRAIN_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_START_SYNC_TRAIN_OFF] & HCI_SUPP_COMMANDS_START_SYNC_TRAIN)
+
+#define HCI_SUPP_COMMANDS_RECEIVE_SYNC_TRAIN             0x03
+#define HCI_SUPP_COMMANDS_RECEIVE_SYNC_TRAIN_OFF         31
+#define HCI_RECEIVE_SYNC_TRAIN_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_RECEIVE_SYNC_TRAIN_OFF] & HCI_SUPP_COMMANDS_RECEIVE_SYNC_TRAIN)
+
+#define HCI_SUPP_COMMANDS_SET_RESERVED_LT_ADDR             0x04
+#define HCI_SUPP_COMMANDS_SET_RESERVED_LT_ADDR_OFF         31
+#define HCI_SET_RESERVED_LT_ADDR_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_SET_RESERVED_LT_ADDR_OFF] & HCI_SUPP_COMMANDS_SET_RESERVED_LT_ADDR)
+
+#define HCI_SUPP_COMMANDS_DELETE_RESERVED_LT_ADDR             0x05
+#define HCI_SUPP_COMMANDS_DELETE_RESERVED_LT_ADDR_OFF         31
+#define HCI_DELETE_RESERVED_LT_ADDR_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_DELETE_RESERVED_LT_ADDR_OFF] & HCI_SUPP_COMMANDS_DELETE_RESERVED_LT_ADDR)
+
+#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_DATA             0x06
+#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_DATA_OFF         31
+#define HCI_SET_CONLESS_SLAVE_BRCST_DATA_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_DATA_OFF] & HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_DATA)
+
+#define HCI_SUPP_COMMANDS_READ_SYNC_TRAIN_PARAM             0x07
+#define HCI_SUPP_COMMANDS_READ_SYNC_TRAIN_PARAM_OFF         31
+#define HCI_READ_SYNC_TRAIN_PARAM_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_READ_SYNC_TRAIN_PARAM_OFF] & HCI_SUPP_COMMANDS_READ_SYNC_TRAIN_PARAM)
+
+/* Supported Commands (Byte 32 bit 0) */
+#define HCI_SUPP_COMMANDS_WRITE_SYNC_TRAIN_PARAM             0x00
+#define HCI_SUPP_COMMANDS_WRITE_SYNC_TRAIN_PARAM_OFF         32
+#define HCI_WRITE_SYNC_TRAIN_PARAM_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_WRITE_SYNC_TRAIN_PARAM_OFF] & HCI_SUPP_COMMANDS_WRITE_SYNC_TRAIN_PARAM)
+
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_MASK   0x02
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_OFF    32
+#define HCI_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_SECURE_CONNS_SUPPORT_MASK    0x04
+#define HCI_SUPP_COMMANDS_READ_SECURE_CONNS_SUPPORT_OFF     32
+#define HCI_READ_SECURE_CONNS_SUPPORT_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_READ_SECURE_CONNS_SUPPORT_OFF] & HCI_SUPP_COMMANDS_READ_SECURE_CONNS_SUPPORT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SECURE_CONNS_SUPPORT_MASK   0x08
+#define HCI_SUPP_COMMANDS_WRITE_SECURE_CONNS_SUPPORT_OFF    32
+#define HCI_WRITE_SECURE_CONNS_SUPPORT_SUPPORTED(x)  ((x)[HCI_SUPP_COMMANDS_WRITE_SECURE_CONNS_SUPPORT_OFF] & HCI_SUPP_COMMANDS_WRITE_SECURE_CONNS_SUPPORT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AUTHENT_PAYLOAD_TOUT_MASK    0x10
+#define HCI_SUPP_COMMANDS_READ_AUTHENT_PAYLOAD_TOUT_OFF     32
+#define HCI_READ_AUTHENT_PAYLOAD_TOUT_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_READ_AUTHENT_PAYLOAD_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_AUTHENT_PAYLOAD_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_AUTHENT_PAYLOAD_TOUT_MASK   0x20
+#define HCI_SUPP_COMMANDS_WRITE_AUTHENT_PAYLOAD_TOUT_OFF    32
+#define HCI_WRITE_AUTHENT_PAYLOAD_TOUT_SUPPORTED(x)  ((x)[HCI_SUPP_COMMANDS_WRITE_AUTHENT_PAYLOAD_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_AUTHENT_PAYLOAD_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_OOB_EXTENDED_DATA_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_LOCAL_OOB_EXTENDED_DATA_OFF  32
+#define HCI_READ_LOCAL_OOB_EXTENDED_DATA_SUPPORTED(x)   ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_OOB_EXTENDED_DATA_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_OOB_EXTENDED_DATA_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SECURE_CONNECTIONS_TEST_MODE_MASK   0x80
+#define HCI_SUPP_COMMANDS_WRITE_SECURE_CONNECTIONS_TEST_MODE_OFF    32
+#define HCI_WRITE_SECURE_CONNECTIONS_TEST_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_SECURE_CONNECTIONS_TEST_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_SECURE_CONNECTIONS_TEST_MODE_MASK)
+
+/* supported LE remote control connection parameter request reply */
+#define HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_RPY_MASK          0x10
+#define HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_RPY_OFF           33
+#define HCI_LE_RC_CONN_PARAM_UPD_RPY_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_RPY_OFF] & HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_RPY_MASK)
+
+#define HCI_SUPP_COMMANDS_RLE_RC_CONN_PARAM_UPD_NEG_RPY_MASK          0x20
+#define HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_NEG_RPY_OFF           33
+#define HCI_LE_RC_CONN_PARAM_UPD_NEG_RPY_SUPPORTED(x)      ((x)[HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_NEG_RPY_OFF] & HCI_SUPP_COMMANDS_RLE_RC_CONN_PARAM_UPD_NEG_RPY_MASK)
+
+#endif
+
diff --git a/bt/stack/include/hcimsgs.h b/bt/stack/include/hcimsgs.h
new file mode 100644
index 0000000..c9b86ab
--- /dev/null
+++ b/bt/stack/include/hcimsgs.h
@@ -0,0 +1,819 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+
+#ifndef HCIMSGS_H
+#define HCIMSGS_H
+
+#include "bt_target.h"
+#include "hcidefs.h"
+#include "bt_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void bte_main_hci_send(BT_HDR *p_msg, uint16_t event);
+void bte_main_lpm_allow_bt_device_sleep(void);
+
+/* Message by message.... */
+
+extern void btsnd_hcic_inquiry(const LAP inq_lap, uint8_t duration,
+                                  uint8_t response_cnt);
+
+#define HCIC_PARAM_SIZE_INQUIRY 5
+
+
+#define HCIC_INQ_INQ_LAP_OFF    0
+#define HCIC_INQ_DUR_OFF        3
+#define HCIC_INQ_RSP_CNT_OFF    4
+                                                                    /* Inquiry */
+
+                                                                    /* Inquiry Cancel */
+extern void btsnd_hcic_inq_cancel(void);
+
+#define HCIC_PARAM_SIZE_INQ_CANCEL   0
+
+                                                                    /* Periodic Inquiry Mode */
+extern void btsnd_hcic_per_inq_mode(uint16_t max_period, uint16_t min_period,
+                                       const LAP inq_lap, uint8_t duration,
+                                       uint8_t response_cnt);
+
+#define HCIC_PARAM_SIZE_PER_INQ_MODE    9
+
+#define HCI_PER_INQ_MAX_INTRVL_OFF  0
+#define HCI_PER_INQ_MIN_INTRVL_OFF  2
+#define HCI_PER_INQ_INQ_LAP_OFF     4
+#define HCI_PER_INQ_DURATION_OFF    7
+#define HCI_PER_INQ_RSP_CNT_OFF     8
+                                                                    /* Periodic Inquiry Mode */
+
+                                                                    /* Exit Periodic Inquiry Mode */
+extern void btsnd_hcic_exit_per_inq(void);
+
+#define HCIC_PARAM_SIZE_EXIT_PER_INQ   0
+                                                                    /* Create Connection */
+extern void btsnd_hcic_create_conn(BD_ADDR dest, uint16_t packet_types,
+                                      uint8_t page_scan_rep_mode,
+                                      uint8_t page_scan_mode,
+                                      uint16_t clock_offset,
+                                      uint8_t allow_switch);
+
+#define HCIC_PARAM_SIZE_CREATE_CONN  13
+
+#define HCIC_CR_CONN_BD_ADDR_OFF        0
+#define HCIC_CR_CONN_PKT_TYPES_OFF      6
+#define HCIC_CR_CONN_REP_MODE_OFF       8
+#define HCIC_CR_CONN_PAGE_SCAN_MODE_OFF 9
+#define HCIC_CR_CONN_CLK_OFF_OFF        10
+#define HCIC_CR_CONN_ALLOW_SWITCH_OFF   12
+                                                                    /* Create Connection */
+
+                                                                    /* Disconnect */
+extern void btsnd_hcic_disconnect(uint16_t handle, uint8_t reason);
+
+#define HCIC_PARAM_SIZE_DISCONNECT 3
+
+#define HCI_DISC_HANDLE_OFF             0
+#define HCI_DISC_REASON_OFF             2
+                                                                    /* Disconnect */
+
+#if (BTM_SCO_INCLUDED == TRUE)
+                                                                    /* Add SCO Connection */
+extern void btsnd_hcic_add_SCO_conn (uint16_t handle, uint16_t packet_types);
+#endif /* BTM_SCO_INCLUDED */
+
+#define HCIC_PARAM_SIZE_ADD_SCO_CONN    4
+
+#define HCI_ADD_SCO_HANDLE_OFF          0
+#define HCI_ADD_SCO_PACKET_TYPES_OFF    2
+                                                                    /* Add SCO Connection */
+
+                                                                    /* Create Connection Cancel */
+extern void btsnd_hcic_create_conn_cancel(BD_ADDR dest);
+
+#define HCIC_PARAM_SIZE_CREATE_CONN_CANCEL  6
+
+#define HCIC_CR_CONN_CANCEL_BD_ADDR_OFF     0
+                                                                    /* Create Connection Cancel */
+
+                                                                    /* Accept Connection Request */
+extern void btsnd_hcic_accept_conn (BD_ADDR bd_addr, uint8_t role);
+
+#define HCIC_PARAM_SIZE_ACCEPT_CONN     7
+
+#define HCI_ACC_CONN_BD_ADDR_OFF        0
+#define HCI_ACC_CONN_ROLE_OFF           6
+                                                                    /* Accept Connection Request */
+
+                                                                    /* Reject Connection Request */
+extern void btsnd_hcic_reject_conn (BD_ADDR bd_addr, uint8_t reason);
+
+#define HCIC_PARAM_SIZE_REJECT_CONN      7
+
+#define HCI_REJ_CONN_BD_ADDR_OFF        0
+#define HCI_REJ_CONN_REASON_OFF         6
+                                                                    /* Reject Connection Request */
+
+                                                                    /* Link Key Request Reply */
+extern void btsnd_hcic_link_key_req_reply (BD_ADDR bd_addr,
+                                              LINK_KEY link_key);
+
+#define HCIC_PARAM_SIZE_LINK_KEY_REQ_REPLY   22
+
+#define HCI_LINK_KEY_REPLY_BD_ADDR_OFF  0
+#define HCI_LINK_KEY_REPLY_LINK_KEY_OFF 6
+                                                                    /* Link Key Request Reply  */
+
+                                                                    /* Link Key Request Neg Reply */
+extern void btsnd_hcic_link_key_neg_reply (BD_ADDR bd_addr);
+
+#define HCIC_PARAM_SIZE_LINK_KEY_NEG_REPLY   6
+
+#define HCI_LINK_KEY_NEG_REP_BD_ADR_OFF 0
+                                                                    /* Link Key Request Neg Reply  */
+
+                                                                    /* PIN Code Request Reply */
+extern void btsnd_hcic_pin_code_req_reply (BD_ADDR bd_addr,
+                                              uint8_t pin_code_len,
+                                              PIN_CODE pin_code);
+
+#define HCIC_PARAM_SIZE_PIN_CODE_REQ_REPLY   23
+
+#define HCI_PIN_CODE_REPLY_BD_ADDR_OFF  0
+#define HCI_PIN_CODE_REPLY_PIN_LEN_OFF  6
+#define HCI_PIN_CODE_REPLY_PIN_CODE_OFF 7
+                                                                    /* PIN Code Request Reply  */
+
+                                                                    /* Link Key Request Neg Reply */
+extern void btsnd_hcic_pin_code_neg_reply (BD_ADDR bd_addr);
+
+#define HCIC_PARAM_SIZE_PIN_CODE_NEG_REPLY   6
+
+#define HCI_PIN_CODE_NEG_REP_BD_ADR_OFF 0
+                                                                    /* Link Key Request Neg Reply  */
+
+                                                                    /* Change Connection Type */
+extern void btsnd_hcic_change_conn_type (uint16_t handle, uint16_t packet_types);
+
+#define HCIC_PARAM_SIZE_CHANGE_CONN_TYPE     4
+
+#define HCI_CHNG_PKT_TYPE_HANDLE_OFF    0
+#define HCI_CHNG_PKT_TYPE_PKT_TYPE_OFF  2
+                                                                    /* Change Connection Type */
+
+#define HCIC_PARAM_SIZE_CMD_HANDLE      2
+
+#define HCI_CMD_HANDLE_HANDLE_OFF       0
+
+extern void btsnd_hcic_auth_request (uint16_t handle);     /* Authentication Request */
+
+                                                                    /* Set Connection Encryption */
+extern void btsnd_hcic_set_conn_encrypt (uint16_t handle, bool    enable);
+#define HCIC_PARAM_SIZE_SET_CONN_ENCRYPT     3
+
+
+#define HCI_SET_ENCRYPT_HANDLE_OFF      0
+#define HCI_SET_ENCRYPT_ENABLE_OFF      2
+                                                                    /* Set Connection Encryption */
+
+                                                                    /* Remote Name Request */
+extern void btsnd_hcic_rmt_name_req (BD_ADDR bd_addr,
+                                        uint8_t page_scan_rep_mode,
+                                        uint8_t page_scan_mode,
+                                        uint16_t clock_offset);
+
+#define HCIC_PARAM_SIZE_RMT_NAME_REQ   10
+
+#define HCI_RMT_NAME_BD_ADDR_OFF        0
+#define HCI_RMT_NAME_REP_MODE_OFF       6
+#define HCI_RMT_NAME_PAGE_SCAN_MODE_OFF 7
+#define HCI_RMT_NAME_CLK_OFF_OFF        8
+                                                                    /* Remote Name Request */
+
+                                                                    /* Remote Name Request Cancel */
+extern void btsnd_hcic_rmt_name_req_cancel(BD_ADDR bd_addr);
+
+#define HCIC_PARAM_SIZE_RMT_NAME_REQ_CANCEL   6
+
+#define HCI_RMT_NAME_CANCEL_BD_ADDR_OFF       0
+                                                                    /* Remote Name Request Cancel */
+
+extern void btsnd_hcic_rmt_features_req(uint16_t handle);      /* Remote Features Request */
+
+                                                                    /* Remote Extended Features */
+extern void btsnd_hcic_rmt_ext_features(uint16_t handle, uint8_t page_num);
+
+#define HCIC_PARAM_SIZE_RMT_EXT_FEATURES   3
+
+#define HCI_RMT_EXT_FEATURES_HANDLE_OFF    0
+#define HCI_RMT_EXT_FEATURES_PAGE_NUM_OFF  2
+                                                                    /* Remote Extended Features */
+
+
+extern void btsnd_hcic_rmt_ver_req(uint16_t handle);           /* Remote Version Info Request */
+extern void btsnd_hcic_read_rmt_clk_offset(uint16_t handle);   /* Remote Clock Offset */
+extern void btsnd_hcic_read_lmp_handle(uint16_t handle);       /* Remote LMP Handle */
+
+extern void btsnd_hcic_setup_esco_conn (uint16_t handle,
+                                           uint32_t tx_bw, uint32_t rx_bw,
+                                           uint16_t max_latency, uint16_t voice,
+                                           uint8_t retrans_effort,
+                                           uint16_t packet_types);
+#define HCIC_PARAM_SIZE_SETUP_ESCO      17
+
+#define HCI_SETUP_ESCO_HANDLE_OFF       0
+#define HCI_SETUP_ESCO_TX_BW_OFF        2
+#define HCI_SETUP_ESCO_RX_BW_OFF        6
+#define HCI_SETUP_ESCO_MAX_LAT_OFF      10
+#define HCI_SETUP_ESCO_VOICE_OFF        12
+#define HCI_SETUP_ESCO_RETRAN_EFF_OFF   14
+#define HCI_SETUP_ESCO_PKT_TYPES_OFF    15
+
+
+extern void btsnd_hcic_accept_esco_conn (BD_ADDR bd_addr,
+                                            uint32_t tx_bw, uint32_t rx_bw,
+                                            uint16_t max_latency,
+                                            uint16_t content_fmt,
+                                            uint8_t retrans_effort,
+                                            uint16_t packet_types);
+#define HCIC_PARAM_SIZE_ACCEPT_ESCO     21
+
+#define HCI_ACCEPT_ESCO_BDADDR_OFF      0
+#define HCI_ACCEPT_ESCO_TX_BW_OFF       6
+#define HCI_ACCEPT_ESCO_RX_BW_OFF       10
+#define HCI_ACCEPT_ESCO_MAX_LAT_OFF     14
+#define HCI_ACCEPT_ESCO_VOICE_OFF       16
+#define HCI_ACCEPT_ESCO_RETRAN_EFF_OFF  18
+#define HCI_ACCEPT_ESCO_PKT_TYPES_OFF   19
+
+
+extern void btsnd_hcic_reject_esco_conn (BD_ADDR bd_addr, uint8_t reason);
+#define HCIC_PARAM_SIZE_REJECT_ESCO     7
+
+#define HCI_REJECT_ESCO_BDADDR_OFF      0
+#define HCI_REJECT_ESCO_REASON_OFF      6
+
+/* Hold Mode */
+extern void btsnd_hcic_hold_mode(uint16_t handle, uint16_t max_hold_period,
+                                    uint16_t min_hold_period);
+
+#define HCIC_PARAM_SIZE_HOLD_MODE       6
+
+#define HCI_HOLD_MODE_HANDLE_OFF        0
+#define HCI_HOLD_MODE_MAX_PER_OFF       2
+#define HCI_HOLD_MODE_MIN_PER_OFF       4
+                                                                    /* Hold Mode */
+
+                                                                    /* Sniff Mode */
+extern void btsnd_hcic_sniff_mode(uint16_t handle,
+                                     uint16_t max_sniff_period,
+                                     uint16_t min_sniff_period,
+                                     uint16_t sniff_attempt,
+                                     uint16_t sniff_timeout);
+
+#define HCIC_PARAM_SIZE_SNIFF_MODE      10
+
+
+#define HCI_SNIFF_MODE_HANDLE_OFF       0
+#define HCI_SNIFF_MODE_MAX_PER_OFF      2
+#define HCI_SNIFF_MODE_MIN_PER_OFF      4
+#define HCI_SNIFF_MODE_ATTEMPT_OFF      6
+#define HCI_SNIFF_MODE_TIMEOUT_OFF      8
+                                                                    /* Sniff Mode */
+
+extern void btsnd_hcic_exit_sniff_mode(uint16_t handle);       /* Exit Sniff Mode */
+
+                                                                    /* Park Mode */
+extern void btsnd_hcic_park_mode (uint16_t handle,
+                                     uint16_t beacon_max_interval,
+                                     uint16_t beacon_min_interval);
+
+#define HCIC_PARAM_SIZE_PARK_MODE       6
+
+#define HCI_PARK_MODE_HANDLE_OFF        0
+#define HCI_PARK_MODE_MAX_PER_OFF       2
+#define HCI_PARK_MODE_MIN_PER_OFF       4
+                                                                    /* Park Mode */
+
+extern void btsnd_hcic_exit_park_mode(uint16_t handle);  /* Exit Park Mode */
+
+                                                                    /* QoS Setup */
+extern void btsnd_hcic_qos_setup (uint16_t handle, uint8_t flags,
+                                     uint8_t service_type,
+                                     uint32_t token_rate, uint32_t peak,
+                                     uint32_t latency, uint32_t delay_var);
+
+#define HCIC_PARAM_SIZE_QOS_SETUP       20
+
+#define HCI_QOS_HANDLE_OFF              0
+#define HCI_QOS_FLAGS_OFF               2
+#define HCI_QOS_SERVICE_TYPE_OFF        3
+#define HCI_QOS_TOKEN_RATE_OFF          4
+#define HCI_QOS_PEAK_BANDWIDTH_OFF      8
+#define HCI_QOS_LATENCY_OFF             12
+#define HCI_QOS_DELAY_VAR_OFF           16
+                                                                    /* QoS Setup */
+
+                                                                    /* Switch Role Request */
+extern void btsnd_hcic_switch_role (BD_ADDR bd_addr, uint8_t role);
+
+#define HCIC_PARAM_SIZE_SWITCH_ROLE  7
+
+#define HCI_SWITCH_BD_ADDR_OFF          0
+#define HCI_SWITCH_ROLE_OFF             6
+                                                                    /* Switch Role Request */
+
+                                                                    /* Write Policy Settings */
+extern void btsnd_hcic_write_policy_set(uint16_t handle, uint16_t settings);
+
+#define HCIC_PARAM_SIZE_WRITE_POLICY_SET     4
+
+#define HCI_WRITE_POLICY_HANDLE_OFF          0
+#define HCI_WRITE_POLICY_SETTINGS_OFF        2
+                                                                    /* Write Policy Settings */
+
+                                                                    /* Write Default Policy Settings */
+extern void btsnd_hcic_write_def_policy_set(uint16_t settings);
+
+#define HCIC_PARAM_SIZE_WRITE_DEF_POLICY_SET     2
+
+#define HCI_WRITE_DEF_POLICY_SETTINGS_OFF        0
+                                                                    /* Write Default Policy Settings */
+
+/******************************************
+**    Lisbon Features
+*******************************************/
+#if (BTM_SSR_INCLUDED == TRUE)
+                                                                    /* Sniff Subrating */
+extern void btsnd_hcic_sniff_sub_rate(uint16_t handle, uint16_t max_lat,
+                                         uint16_t min_remote_lat,
+                                         uint16_t min_local_lat);
+
+#define HCIC_PARAM_SIZE_SNIFF_SUB_RATE             8
+
+#define HCI_SNIFF_SUB_RATE_HANDLE_OFF              0
+#define HCI_SNIFF_SUB_RATE_MAX_LAT_OFF             2
+#define HCI_SNIFF_SUB_RATE_MIN_REM_LAT_OFF         4
+#define HCI_SNIFF_SUB_RATE_MIN_LOC_LAT_OFF         6
+                                                                    /* Sniff Subrating */
+
+#else   /* BTM_SSR_INCLUDED == FALSE */
+
+#define btsnd_hcic_sniff_sub_rate(handle, max_lat, min_remote_lat, min_local_lat) false
+
+#endif  /* BTM_SSR_INCLUDED */
+
+                                                                    /* Extended Inquiry Response */
+extern void btsnd_hcic_write_ext_inquiry_response(void *buffer, uint8_t fec_req);
+
+#define HCIC_PARAM_SIZE_EXT_INQ_RESP        241
+
+#define HCIC_EXT_INQ_RESP_FEC_OFF     0
+#define HCIC_EXT_INQ_RESP_RESPONSE    1
+                                                                   /* IO Capabilities Response */
+extern void btsnd_hcic_io_cap_req_reply (BD_ADDR bd_addr, uint8_t capability,
+                                            uint8_t oob_present, uint8_t auth_req);
+
+#define HCIC_PARAM_SIZE_IO_CAP_RESP     9
+
+#define HCI_IO_CAP_BD_ADDR_OFF          0
+#define HCI_IO_CAPABILITY_OFF           6
+#define HCI_IO_CAP_OOB_DATA_OFF         7
+#define HCI_IO_CAP_AUTH_REQ_OFF         8
+
+                                                                    /* IO Capabilities Req Neg Reply */
+extern void btsnd_hcic_io_cap_req_neg_reply (BD_ADDR bd_addr, uint8_t err_code);
+
+#define HCIC_PARAM_SIZE_IO_CAP_NEG_REPLY 7
+
+#define HCI_IO_CAP_NR_BD_ADDR_OFF        0
+#define HCI_IO_CAP_NR_ERR_CODE           6
+
+                                                         /* Read Local OOB Data */
+extern void btsnd_hcic_read_local_oob_data (void);
+
+#define HCIC_PARAM_SIZE_R_LOCAL_OOB     0
+
+
+extern void btsnd_hcic_user_conf_reply (BD_ADDR bd_addr, bool    is_yes);
+
+#define HCIC_PARAM_SIZE_UCONF_REPLY     6
+
+#define HCI_USER_CONF_BD_ADDR_OFF       0
+
+
+extern void btsnd_hcic_user_passkey_reply (BD_ADDR bd_addr, uint32_t value);
+
+#define HCIC_PARAM_SIZE_U_PKEY_REPLY    10
+
+#define HCI_USER_PASSKEY_BD_ADDR_OFF    0
+#define HCI_USER_PASSKEY_VALUE_OFF      6
+
+
+extern void btsnd_hcic_user_passkey_neg_reply (BD_ADDR bd_addr);
+
+#define HCIC_PARAM_SIZE_U_PKEY_NEG_REPLY 6
+
+#define HCI_USER_PASSKEY_NEG_BD_ADDR_OFF 0
+
+                                                            /* Remote OOB Data Request Reply */
+extern void btsnd_hcic_rem_oob_reply (BD_ADDR bd_addr, uint8_t *p_c,
+                                         uint8_t *p_r);
+
+#define HCIC_PARAM_SIZE_REM_OOB_REPLY   38
+
+#define HCI_REM_OOB_DATA_BD_ADDR_OFF    0
+#define HCI_REM_OOB_DATA_C_OFF          6
+#define HCI_REM_OOB_DATA_R_OFF          22
+
+                                                            /* Remote OOB Data Request Negative Reply */
+extern void btsnd_hcic_rem_oob_neg_reply (BD_ADDR bd_addr);
+
+#define HCIC_PARAM_SIZE_REM_OOB_NEG_REPLY   6
+
+#define HCI_REM_OOB_DATA_NEG_BD_ADDR_OFF    0
+
+                                                            /* Read Tx Power Level */
+extern void btsnd_hcic_read_inq_tx_power (void);
+
+#define HCIC_PARAM_SIZE_R_TX_POWER      0
+
+                                                            /* Read Default Erroneous Data Reporting */
+extern void btsnd_hcic_read_default_erroneous_data_rpt (void);
+
+#define HCIC_PARAM_SIZE_R_ERR_DATA_RPT      0
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+extern void btsnd_hcic_enhanced_flush (uint16_t handle, uint8_t packet_type);
+
+#define HCIC_PARAM_SIZE_ENHANCED_FLUSH  3
+#endif
+
+
+extern void btsnd_hcic_send_keypress_notif (BD_ADDR bd_addr, uint8_t notif);
+
+#define HCIC_PARAM_SIZE_SEND_KEYPRESS_NOTIF    7
+
+#define HCI_SEND_KEYPRESS_NOTIF_BD_ADDR_OFF    0
+#define HCI_SEND_KEYPRESS_NOTIF_NOTIF_OFF      6
+
+/**** end of Simple Pairing Commands ****/
+
+                                                                    /* Store Current Settings */
+#define MAX_FILT_COND   (sizeof (BD_ADDR) + 1)
+
+extern void btsnd_hcic_set_event_filter(uint8_t filt_type,
+                                           uint8_t filt_cond_type,
+                                           uint8_t *filt_cond,
+                                           uint8_t filt_cond_len);
+
+#define HCIC_PARAM_SIZE_SET_EVT_FILTER  9
+
+#define HCI_FILT_COND_FILT_TYPE_OFF     0
+#define HCI_FILT_COND_COND_TYPE_OFF     1
+#define HCI_FILT_COND_FILT_OFF          2
+                                                                    /* Set Event Filter */
+
+                                                                /* Delete Stored Key */
+extern void btsnd_hcic_delete_stored_key (BD_ADDR bd_addr, bool    delete_all_flag);
+
+#define HCIC_PARAM_SIZE_DELETE_STORED_KEY        7
+
+#define HCI_DELETE_KEY_BD_ADDR_OFF      0
+#define HCI_DELETE_KEY_ALL_FLAG_OFF     6
+                                                                /* Delete Stored Key */
+
+                                                                /* Change Local Name */
+extern void btsnd_hcic_change_name(BD_NAME name);
+
+#define HCIC_PARAM_SIZE_CHANGE_NAME     BD_NAME_LEN
+
+#define HCI_CHANGE_NAME_NAME_OFF        0
+                                                                /* Change Local Name */
+
+
+#define HCIC_PARAM_SIZE_READ_CMD     0
+
+#define HCIC_PARAM_SIZE_WRITE_PARAM1     1
+
+#define HCIC_WRITE_PARAM1_PARAM_OFF      0
+
+#define HCIC_PARAM_SIZE_WRITE_PARAM2     2
+
+#define HCIC_WRITE_PARAM2_PARAM_OFF      0
+
+#define HCIC_PARAM_SIZE_WRITE_PARAM3     3
+
+#define HCIC_WRITE_PARAM3_PARAM_OFF      0
+
+#define HCIC_PARAM_SIZE_SET_AFH_CHANNELS    10
+
+extern void btsnd_hcic_write_pin_type(uint8_t type);                   /* Write PIN Type */
+extern void btsnd_hcic_write_auto_accept(uint8_t flag);                /* Write Auto Accept */
+extern void btsnd_hcic_read_name (void);                             /* Read Local Name */
+extern void btsnd_hcic_write_page_tout(uint16_t timeout);              /* Write Page Timout */
+extern void btsnd_hcic_write_scan_enable(uint8_t flag);                /* Write Scan Enable */
+extern void btsnd_hcic_write_pagescan_cfg(uint16_t interval,
+                                             uint16_t window);            /* Write Page Scan Activity */
+
+#define HCIC_PARAM_SIZE_WRITE_PAGESCAN_CFG  4
+
+#define HCI_SCAN_CFG_INTERVAL_OFF       0
+#define HCI_SCAN_CFG_WINDOW_OFF         2
+                                                                /* Write Page Scan Activity */
+
+                                                                /* Write Inquiry Scan Activity */
+extern void btsnd_hcic_write_inqscan_cfg(uint16_t interval, uint16_t window);
+
+#define HCIC_PARAM_SIZE_WRITE_INQSCAN_CFG    4
+
+#define HCI_SCAN_CFG_INTERVAL_OFF       0
+#define HCI_SCAN_CFG_WINDOW_OFF         2
+                                                                /* Write Inquiry Scan Activity */
+
+extern void btsnd_hcic_write_auth_enable(uint8_t flag);                 /* Write Authentication Enable */
+extern void btsnd_hcic_write_dev_class(DEV_CLASS dev);                /* Write Class of Device */
+extern void btsnd_hcic_write_voice_settings(uint16_t flags);            /* Write Voice Settings */
+
+/* Host Controller to Host flow control */
+#define HCI_HOST_FLOW_CTRL_OFF          0
+#define HCI_HOST_FLOW_CTRL_ACL_ON       1
+#define HCI_HOST_FLOW_CTRL_SCO_ON       2
+#define HCI_HOST_FLOW_CTRL_BOTH_ON      3
+
+extern void btsnd_hcic_write_auto_flush_tout(uint16_t handle,
+                                                uint16_t timeout);    /* Write Retransmit Timout */
+
+#define HCIC_PARAM_SIZE_WRITE_AUTO_FLUSH_TOUT    4
+
+#define HCI_FLUSH_TOUT_HANDLE_OFF       0
+#define HCI_FLUSH_TOUT_TOUT_OFF         2
+
+extern void btsnd_hcic_read_tx_power(uint16_t handle, uint8_t type);     /* Read Tx Power */
+
+#define HCIC_PARAM_SIZE_READ_TX_POWER    3
+
+#define HCI_READ_TX_POWER_HANDLE_OFF    0
+#define HCI_READ_TX_POWER_TYPE_OFF      2
+
+/* Read transmit power level parameter */
+#define HCI_READ_CURRENT                0x00
+#define HCI_READ_MAXIMUM                0x01
+
+extern void btsnd_hcic_host_num_xmitted_pkts (uint8_t num_handles,
+                                                 uint16_t *handle,
+                                                 uint16_t *num_pkts);         /* Set Host Buffer Size */
+
+#define HCIC_PARAM_SIZE_NUM_PKTS_DONE_SIZE    sizeof(btmsg_hcic_num_pkts_done_t)
+
+#define MAX_DATA_HANDLES        10
+
+#define HCI_PKTS_DONE_NUM_HANDLES_OFF   0
+#define HCI_PKTS_DONE_HANDLE_OFF        1
+#define HCI_PKTS_DONE_NUM_PKTS_OFF      3
+
+                                                                /* Write Link Supervision Timeout */
+extern void btsnd_hcic_write_link_super_tout(uint8_t local_controller_id, uint16_t handle, uint16_t timeout);
+
+#define HCIC_PARAM_SIZE_WRITE_LINK_SUPER_TOUT        4
+
+#define HCI_LINK_SUPER_TOUT_HANDLE_OFF  0
+#define HCI_LINK_SUPER_TOUT_TOUT_OFF    2
+                                                                /* Write Link Supervision Timeout */
+
+extern void btsnd_hcic_write_cur_iac_lap (uint8_t num_cur_iac,
+                                             LAP * const iac_lap);  /* Write Current IAC LAP */
+
+#define MAX_IAC_LAPS    0x40
+
+#define HCI_WRITE_IAC_LAP_NUM_OFF       0
+#define HCI_WRITE_IAC_LAP_LAP_OFF       1
+                                                                /* Write Current IAC LAP */
+
+extern void btsnd_hcic_get_link_quality (uint16_t handle);            /* Get Link Quality */
+extern void btsnd_hcic_read_rssi (uint16_t handle);                   /* Read RSSI */
+extern void btsnd_hcic_enable_test_mode (void);                     /* Enable Device Under Test Mode */
+extern void btsnd_hcic_write_pagescan_type(uint8_t type);             /* Write Page Scan Type */
+extern void btsnd_hcic_write_inqscan_type(uint8_t type);              /* Write Inquiry Scan Type */
+extern void btsnd_hcic_write_inquiry_mode(uint8_t type);              /* Write Inquiry Mode */
+
+#define HCI_DATA_HANDLE_MASK 0x0FFF
+
+#define HCID_GET_HANDLE_EVENT(p)  (uint16_t)((*((uint8_t *)((p) + 1) + (p)->offset) + \
+                                           (*((uint8_t *)((p) + 1) + (p)->offset + 1) << 8)))
+
+#define HCID_GET_HANDLE(u16) (uint16_t)((u16) & HCI_DATA_HANDLE_MASK)
+
+#define HCI_DATA_EVENT_MASK   3
+#define HCI_DATA_EVENT_OFFSET 12
+#define HCID_GET_EVENT(u16)   (uint8_t)(((u16) >> HCI_DATA_EVENT_OFFSET) & HCI_DATA_EVENT_MASK)
+
+#define HCI_DATA_BCAST_MASK   3
+#define HCI_DATA_BCAST_OFFSET 10
+#define HCID_GET_BCAST(u16)   (uint8_t)(((u16) >> HCI_DATA_BCAST_OFFSET) & HCI_DATA_BCAST_MASK)
+
+#define HCID_GET_ACL_LEN(p)     (uint16_t)((*((uint8_t *)((p) + 1) + (p)->offset + 2) + \
+                                         (*((uint8_t *)((p) + 1) + (p)->offset + 3) << 8)))
+
+#define HCID_HEADER_SIZE      4
+
+#define HCID_GET_SCO_LEN(p)  (*((uint8_t *)((p) + 1) + (p)->offset + 2))
+
+extern void btsnd_hcic_vendor_spec_cmd (void *buffer, uint16_t opcode,
+                                        uint8_t len, uint8_t *p_data,
+                                        void *p_cmd_cplt_cback);
+
+#if (BLE_INCLUDED == TRUE)
+/********************************************************************************
+** BLE Commands
+**      Note: "local_controller_id" is for transport, not counted in HCI message size
+*********************************************************************************/
+#define HCIC_BLE_RAND_DI_SIZE                   8
+#define HCIC_BLE_ENCRYT_KEY_SIZE                16
+#define HCIC_BLE_IRK_SIZE                       16
+
+#define HCIC_PARAM_SIZE_SET_USED_FEAT_CMD       8
+#define HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD    6
+#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS    15
+#define HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP      31
+#define HCIC_PARAM_SIZE_WRITE_ADV_ENABLE        1
+#define HCIC_PARAM_SIZE_BLE_WRITE_SCAN_PARAM    7
+#define HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE   2
+#define HCIC_PARAM_SIZE_BLE_CREATE_LL_CONN      25
+#define HCIC_PARAM_SIZE_BLE_CREATE_CONN_CANCEL  0
+#define HCIC_PARAM_SIZE_CLEAR_WHITE_LIST        0
+#define HCIC_PARAM_SIZE_ADD_WHITE_LIST          7
+#define HCIC_PARAM_SIZE_REMOVE_WHITE_LIST       7
+#define HCIC_PARAM_SIZE_BLE_UPD_LL_CONN_PARAMS  14
+#define HCIC_PARAM_SIZE_SET_HOST_CHNL_CLASS     5
+#define HCIC_PARAM_SIZE_READ_CHNL_MAP         2
+#define HCIC_PARAM_SIZE_BLE_READ_REMOTE_FEAT    2
+#define HCIC_PARAM_SIZE_BLE_ENCRYPT             32
+#define HCIC_PARAM_SIZE_BLE_RAND                0
+#define HCIC_PARAM_SIZE_WRITE_LE_HOST_SUPPORTED 2
+
+#define HCIC_BLE_RAND_DI_SIZE                   8
+#define HCIC_BLE_ENCRYT_KEY_SIZE                16
+#define HCIC_PARAM_SIZE_BLE_START_ENC           (4 + HCIC_BLE_RAND_DI_SIZE + HCIC_BLE_ENCRYT_KEY_SIZE)
+#define HCIC_PARAM_SIZE_LTK_REQ_REPLY           (2 + HCIC_BLE_ENCRYT_KEY_SIZE)
+#define HCIC_PARAM_SIZE_LTK_REQ_NEG_REPLY       2
+#define HCIC_BLE_CHNL_MAP_SIZE                  5
+#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA      31
+
+#define HCIC_PARAM_SIZE_BLE_ADD_DEV_RESOLVING_LIST      (7 + HCIC_BLE_IRK_SIZE * 2)
+#define HCIC_PARAM_SIZE_BLE_RM_DEV_RESOLVING_LIST       7
+#define HCIC_PARAM_SIZE_BLE_CLEAR_RESOLVING_LIST        0
+#define HCIC_PARAM_SIZE_BLE_READ_RESOLVING_LIST_SIZE    0
+#define HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_PEER   7
+#define HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_LOCAL  7
+#define HCIC_PARAM_SIZE_BLE_SET_ADDR_RESOLUTION_ENABLE  1
+#define HCIC_PARAM_SIZE_BLE_SET_RAND_PRIV_ADDR_TIMOUT   2
+#define HCIC_PARAM_SIZE_BLE_SET_DATA_LENGTH             6
+#define HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_SCAN_PARAM  11
+
+/* ULP HCI command */
+extern void btsnd_hcic_ble_set_evt_mask (BT_EVENT_MASK event_mask);
+
+extern void btsnd_hcic_ble_read_buffer_size (void);
+
+extern void btsnd_hcic_ble_read_local_spt_feat (void);
+
+extern void btsnd_hcic_ble_set_local_used_feat (uint8_t feat_set[8]);
+
+extern void btsnd_hcic_ble_set_random_addr (BD_ADDR random_addr);
+
+extern void btsnd_hcic_ble_write_adv_params (uint16_t adv_int_min, uint16_t adv_int_max,
+                                                uint8_t adv_type, uint8_t addr_type_own,
+                                                uint8_t addr_type_dir, BD_ADDR direct_bda,
+                                                uint8_t channel_map, uint8_t adv_filter_policy);
+
+extern void btsnd_hcic_ble_read_adv_chnl_tx_power (void);
+
+extern void btsnd_hcic_ble_set_adv_data (uint8_t data_len, uint8_t *p_data);
+
+extern void btsnd_hcic_ble_set_scan_rsp_data (uint8_t data_len, uint8_t *p_scan_rsp);
+
+extern void btsnd_hcic_ble_set_adv_enable (uint8_t adv_enable);
+
+extern void btsnd_hcic_ble_set_scan_params (uint8_t scan_type,
+                                               uint16_t scan_int, uint16_t scan_win,
+                                               uint8_t addr_type, uint8_t scan_filter_policy);
+
+extern void btsnd_hcic_ble_set_scan_enable (uint8_t scan_enable, uint8_t duplicate);
+
+extern void btsnd_hcic_ble_create_ll_conn (uint16_t scan_int, uint16_t scan_win,
+                                              uint8_t init_filter_policy, uint8_t addr_type_peer, BD_ADDR bda_peer, uint8_t addr_type_own,
+                                              uint16_t conn_int_min, uint16_t conn_int_max, uint16_t conn_latency, uint16_t conn_timeout,
+                                              uint16_t min_ce_len, uint16_t max_ce_len);
+
+extern void btsnd_hcic_ble_create_conn_cancel (void);
+
+extern void btsnd_hcic_ble_read_white_list_size (void);
+
+extern void btsnd_hcic_ble_clear_white_list (void);
+
+extern void btsnd_hcic_ble_add_white_list (uint8_t addr_type, BD_ADDR bda);
+
+extern void btsnd_hcic_ble_remove_from_white_list (uint8_t addr_type, BD_ADDR bda);
+
+extern void btsnd_hcic_ble_upd_ll_conn_params (uint16_t handle, uint16_t conn_int_min, uint16_t conn_int_max,
+                                                  uint16_t conn_latency, uint16_t conn_timeout, uint16_t min_len, uint16_t max_len);
+
+extern void btsnd_hcic_ble_set_host_chnl_class (uint8_t chnl_map[HCIC_BLE_CHNL_MAP_SIZE]);
+
+extern void btsnd_hcic_ble_read_chnl_map (uint16_t handle);
+
+extern void btsnd_hcic_ble_read_remote_feat ( uint16_t handle);
+
+extern void btsnd_hcic_ble_encrypt (uint8_t* key, uint8_t key_len, uint8_t* plain_text, uint8_t pt_len, void *p_cmd_cplt_cback);
+
+extern void btsnd_hcic_ble_rand (void *p_cmd_cplt_cback);
+
+extern void btsnd_hcic_ble_start_enc ( uint16_t handle,
+                                          uint8_t rand[HCIC_BLE_RAND_DI_SIZE],
+                                          uint16_t ediv, uint8_t ltk[HCIC_BLE_ENCRYT_KEY_SIZE]);
+
+extern void btsnd_hcic_ble_ltk_req_reply (uint16_t handle, uint8_t ltk[HCIC_BLE_ENCRYT_KEY_SIZE]);
+
+extern void btsnd_hcic_ble_ltk_req_neg_reply (uint16_t handle);
+
+extern void btsnd_hcic_ble_read_supported_states (void);
+
+extern void btsnd_hcic_ble_write_host_supported (uint8_t le_host_spt, uint8_t simul_le_host_spt);
+
+extern void btsnd_hcic_ble_read_host_supported (void);
+
+extern void btsnd_hcic_ble_receiver_test(uint8_t rx_freq);
+
+extern void btsnd_hcic_ble_transmitter_test(uint8_t tx_freq, uint8_t test_data_len,
+                                               uint8_t payload);
+extern void btsnd_hcic_ble_test_end(void);
+
+#if (BLE_LLT_INCLUDED == TRUE)
+
+#define HCIC_PARAM_SIZE_BLE_RC_PARAM_REQ_REPLY           14
+extern void btsnd_hcic_ble_rc_param_req_reply(uint16_t handle,
+                                                 uint16_t conn_int_min, uint16_t conn_int_max,
+                                                 uint16_t conn_latency, uint16_t conn_timeout,
+                                                 uint16_t min_ce_len, uint16_t max_ce_len);
+
+#define HCIC_PARAM_SIZE_BLE_RC_PARAM_REQ_NEG_REPLY       3
+extern void btsnd_hcic_ble_rc_param_req_neg_reply(uint16_t handle, uint8_t reason);
+
+#endif /* BLE_LLT_INCLUDED */
+
+extern void btsnd_hcic_ble_set_data_length(uint16_t conn_handle, uint16_t tx_octets,
+                                                      uint16_t tx_time);
+
+extern void btsnd_hcic_ble_add_device_resolving_list (uint8_t addr_type_peer,
+                                                               BD_ADDR bda_peer,
+                                                               uint8_t irk_peer[HCIC_BLE_IRK_SIZE],
+                                                               uint8_t irk_local[HCIC_BLE_IRK_SIZE]);
+
+extern void btsnd_hcic_ble_rm_device_resolving_list (uint8_t addr_type_peer,
+                                                                BD_ADDR bda_peer);
+
+extern void btsnd_hcic_ble_clear_resolving_list (void);
+
+extern void btsnd_hcic_ble_read_resolvable_addr_peer (uint8_t addr_type_peer,
+                                                                 BD_ADDR bda_peer);
+
+extern void btsnd_hcic_ble_read_resolvable_addr_local (uint8_t addr_type_peer,
+                                                                 BD_ADDR bda_peer);
+
+extern void btsnd_hcic_ble_set_addr_resolution_enable (uint8_t addr_resolution_enable);
+
+extern void btsnd_hcic_ble_set_rand_priv_addr_timeout (uint16_t rpa_timout);
+
+#endif /* BLE_INCLUDED */
+
+extern void btsnd_hcic_read_authenticated_payload_tout(uint16_t handle);
+
+extern void btsnd_hcic_write_authenticated_payload_tout(uint16_t handle,
+                                                                   uint16_t timeout);
+
+#define HCIC_PARAM_SIZE_WRITE_AUTHENT_PAYLOAD_TOUT  4
+
+#define HCI__WRITE_AUTHENT_PAYLOAD_TOUT_HANDLE_OFF  0
+#define HCI__WRITE_AUTHENT_PAYLOAD_TOUT_TOUT_OFF    2
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bt/stack/include/hiddefs.h b/bt/stack/include/hiddefs.h
new file mode 100644
index 0000000..705fcce
--- /dev/null
+++ b/bt/stack/include/hiddefs.h
@@ -0,0 +1,159 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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 HID protocol definitions
+ *
+ ******************************************************************************/
+
+#ifndef HIDDEFS_H
+#define HIDDEFS_H
+
+#include "sdp_api.h"
+/*
+** tHID_STATUS: HID result codes, returned by HID and device and host functions.
+*/
+enum
+{
+   HID_SUCCESS,
+   HID_ERR_NOT_REGISTERED,
+   HID_ERR_ALREADY_REGISTERED,
+   HID_ERR_NO_RESOURCES,
+   HID_ERR_NO_CONNECTION,
+   HID_ERR_INVALID_PARAM,
+   HID_ERR_UNSUPPORTED,
+   HID_ERR_UNKNOWN_COMMAND,
+   HID_ERR_CONGESTED,
+   HID_ERR_CONN_IN_PROCESS,
+   HID_ERR_ALREADY_CONN,
+   HID_ERR_DISCONNECTING,
+   HID_ERR_SET_CONNABLE_FAIL,
+   /* Device specific error codes */
+   HID_ERR_HOST_UNKNOWN,
+   HID_ERR_L2CAP_FAILED,
+   HID_ERR_AUTH_FAILED,
+   HID_ERR_SDP_BUSY,
+   HID_ERR_GATT,
+
+   HID_ERR_INVALID = 0xFF
+};
+
+typedef uint8_t tHID_STATUS;
+
+#define    HID_L2CAP_CONN_FAIL (0x0100) /* Connection Attempt was made but failed */
+#define    HID_L2CAP_REQ_FAIL  (0x0200)  /* L2CAP_ConnectReq API failed */
+#define    HID_L2CAP_CFG_FAIL  (0x0400) /* L2CAP Configuration was rejected by peer */
+
+
+
+/* Define the HID transaction types
+*/
+#define HID_TRANS_HANDSHAKE     (0)
+#define HID_TRANS_CONTROL       (1)
+#define HID_TRANS_GET_REPORT    (4)
+#define HID_TRANS_SET_REPORT    (5)
+#define HID_TRANS_GET_PROTOCOL  (6)
+#define HID_TRANS_SET_PROTOCOL  (7)
+#define HID_TRANS_GET_IDLE      (8)
+#define HID_TRANS_SET_IDLE      (9)
+#define HID_TRANS_DATA          (10)
+#define HID_TRANS_DATAC         (11)
+
+#define HID_GET_TRANS_FROM_HDR(x) (((x) >> 4) & 0x0f)
+#define HID_GET_PARAM_FROM_HDR(x) ((x) & 0x0f)
+#define HID_BUILD_HDR(t,p)  (uint8_t)(((t) << 4) | ((p) & 0x0f))
+
+
+/* Parameters for Handshake
+*/
+#define HID_PAR_HANDSHAKE_RSP_SUCCESS               (0)
+#define HID_PAR_HANDSHAKE_RSP_NOT_READY             (1)
+#define HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID    (2)
+#define HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ   (3)
+#define HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM     (4)
+#define HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN           (14)
+#define HID_PAR_HANDSHAKE_RSP_ERR_FATAL             (15)
+
+
+/* Parameters for Control
+*/
+#define HID_PAR_CONTROL_NOP                         (0)
+#define HID_PAR_CONTROL_HARD_RESET                  (1)
+#define HID_PAR_CONTROL_SOFT_RESET                  (2)
+#define HID_PAR_CONTROL_SUSPEND                     (3)
+#define HID_PAR_CONTROL_EXIT_SUSPEND                (4)
+#define HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG        (5)
+
+
+/* Different report types in get, set, data
+*/
+#define HID_PAR_REP_TYPE_MASK                       (0x03)
+#define HID_PAR_REP_TYPE_OTHER                      (0x00)
+#define HID_PAR_REP_TYPE_INPUT                      (0x01)
+#define HID_PAR_REP_TYPE_OUTPUT                     (0x02)
+#define HID_PAR_REP_TYPE_FEATURE                    (0x03)
+
+/* Parameters for Get Report
+*/
+
+/* Buffer size in two bytes after Report ID */
+#define HID_PAR_GET_REP_BUFSIZE_FOLLOWS             (0x08)
+
+
+/* Parameters for Protocol Type
+*/
+#define HID_PAR_PROTOCOL_MASK                       (0x01)
+#define HID_PAR_PROTOCOL_REPORT                     (0x01)
+#define HID_PAR_PROTOCOL_BOOT_MODE                  (0x00)
+
+#define HID_PAR_REP_TYPE_MASK                       (0x03)
+
+/* Descriptor types in the SDP record
+*/
+#define HID_SDP_DESCRIPTOR_REPORT                   (0x22)
+#define HID_SDP_DESCRIPTOR_PHYSICAL                 (0x23)
+
+typedef struct desc_info
+{
+    uint16_t dl_len;
+    uint8_t *dsc_list;
+} tHID_DEV_DSCP_INFO;
+
+#define HID_SSR_PARAM_INVALID    0xffff
+
+typedef struct sdp_info
+{
+    char svc_name[HID_MAX_SVC_NAME_LEN];   /*Service Name */
+    char svc_descr[HID_MAX_SVC_DESCR_LEN]; /*Service Description*/
+    char prov_name[HID_MAX_PROV_NAME_LEN]; /*Provider Name.*/
+    uint16_t  rel_num;    /*Release Number */
+    uint16_t  hpars_ver;  /*HID Parser Version.*/
+    uint16_t  ssr_max_latency; /* HIDSSRHostMaxLatency value, if HID_SSR_PARAM_INVALID not used*/
+    uint16_t  ssr_min_tout; /* HIDSSRHostMinTimeout value, if HID_SSR_PARAM_INVALID not used* */
+    uint8_t   sub_class;    /*Device Subclass.*/
+    uint8_t   ctry_code;     /*Country Code.*/
+    uint16_t  sup_timeout;/* Supervisory Timeout */
+
+    tHID_DEV_DSCP_INFO  dscp_info;   /* Descriptor list and Report list to be set in the SDP record.
+                                       This parameter is used if HID_DEV_USE_GLB_SDP_REC is set to false.*/
+    tSDP_DISC_REC       *p_sdp_layer_rec;
+} tHID_DEV_SDP_INFO;
+
+#endif
+
diff --git a/bt/stack/include/hidh_api.h b/bt/stack/include/hidh_api.h
new file mode 100644
index 0000000..01d7678
--- /dev/null
+++ b/bt/stack/include/hidh_api.h
@@ -0,0 +1,236 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2002-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.
+ *
+ ******************************************************************************/
+#ifndef HIDH_API_H
+#define HIDH_API_H
+
+#include "hiddefs.h"
+#include "sdp_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+enum {
+    HID_SDP_NO_SERV_UUID = (SDP_ILLEGAL_PARAMETER+1),
+    HID_SDP_MANDATORY_MISSING
+};
+
+/* Attributes mask values to be used in HID_HostAddDev API */
+#define HID_VIRTUAL_CABLE        0x0001
+#define HID_NORMALLY_CONNECTABLE 0x0002
+#define HID_RECONN_INIT          0x0004
+#define HID_SDP_DISABLE          0x0008
+#define HID_BATTERY_POWER        0x0010
+#define HID_REMOTE_WAKE          0x0020
+#define HID_SUP_TOUT_AVLBL       0x0040
+#define HID_SSR_MAX_LATENCY      0x0080
+#define HID_SSR_MIN_TOUT         0x0100
+
+#define HID_SEC_REQUIRED         0x8000
+#define HID_ATTR_MASK_IGNORE     0
+
+
+/*****************************************************************************
+**  Type Definitions
+*****************************************************************************/
+
+typedef void (tHID_HOST_SDP_CALLBACK) (uint16_t result, uint16_t attr_mask,
+                                       tHID_DEV_SDP_INFO *sdp_rec );
+
+/* HID-HOST returns the events in the following table to the application via tHID_HOST_DEV_CALLBACK
+HID_HDEV_EVT_OPEN   Connected to device with Interrupt and Control Channels in OPEN state.
+                                                        Data = NA
+HID_HDEV_EVT_CLOSE  Connection with device is closed.   Data=reason code.
+HID_HDEV_EVT_RETRYING   Lost connection is being re-connected.
+                                                        Data=Retrial number
+HID_HDEV_EVT_IN_REPORT  Device sent an input report     Data=Report Type pdata= pointer to BT_HDR
+                                                        (GKI buffer having report data.)
+HID_HDEV_EVT_HANDSHAKE  Device sent SET_REPORT          Data=Result-code pdata=NA.
+HID_HDEV_EVT_VC_UNPLUG  Device sent Virtual Unplug      Data=NA. pdata=NA.
+*/
+
+enum
+{
+    HID_HDEV_EVT_OPEN,
+    HID_HDEV_EVT_CLOSE,
+    HID_HDEV_EVT_RETRYING,
+    HID_HDEV_EVT_INTR_DATA,
+    HID_HDEV_EVT_INTR_DATC,
+    HID_HDEV_EVT_CTRL_DATA,
+    HID_HDEV_EVT_CTRL_DATC,
+    HID_HDEV_EVT_HANDSHAKE,
+    HID_HDEV_EVT_VC_UNPLUG
+};
+typedef void (tHID_HOST_DEV_CALLBACK) (uint8_t dev_handle,
+                                       BD_ADDR addr,
+                                       uint8_t event, /* Event from HID-DEVICE. */
+                                       uint32_t data, /* Integer data corresponding to the event.*/
+                                       BT_HDR *p_buf ); /* Pointer data corresponding to the event. */
+
+
+/*****************************************************************************
+**  External Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function         HID_HostGetSDPRecord
+**
+** Description      This function reads the device SDP record.
+**
+** Returns          tHID_STATUS
+**
+*******************************************************************************/
+extern tHID_STATUS HID_HostGetSDPRecord (BD_ADDR addr,
+                                         tSDP_DISCOVERY_DB *p_db,
+                                         uint32_t db_len,
+                                         tHID_HOST_SDP_CALLBACK *sdp_cback );
+
+/*******************************************************************************
+**
+** Function         HID_HostRegister
+**
+** Description      This function registers HID-Host with lower layers.
+**
+** Returns          tHID_STATUS
+**
+*******************************************************************************/
+extern tHID_STATUS HID_HostRegister (tHID_HOST_DEV_CALLBACK *dev_cback);
+
+/*******************************************************************************
+**
+** Function         HID_HostDeregister
+**
+** Description      This function is called when the host is about power down.
+**
+** Returns          tHID_STATUS
+**
+*******************************************************************************/
+extern tHID_STATUS HID_HostDeregister(void);
+
+/*******************************************************************************
+**
+** Function         HID_HostAddDev
+**
+** Description      This is called so HID-host may manage this device.
+**
+** Returns          tHID_STATUS
+**
+*******************************************************************************/
+extern tHID_STATUS HID_HostAddDev (BD_ADDR addr, uint16_t attr_mask,
+                                   uint8_t *handle );
+
+/*******************************************************************************
+**
+** Function         HID_HostRemoveDev
+**
+** Description      This removes the device from list devices that host has to manage.
+**
+** Returns          tHID_STATUS
+**
+*******************************************************************************/
+extern tHID_STATUS HID_HostRemoveDev (uint8_t dev_handle );
+
+/*******************************************************************************
+**
+** Function         HID_HostOpenDev
+**
+** Description      This function is called when the user wants to initiate a
+**                  connection attempt to a device.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern tHID_STATUS HID_HostOpenDev (uint8_t dev_handle );
+
+/*******************************************************************************
+**
+** Function         HID_HostWriteDev
+**
+** Description      This function is called when the host has a report to send.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern tHID_STATUS HID_HostWriteDev(uint8_t dev_handle, uint8_t t_type,
+                                    uint8_t param, uint16_t data,
+                                    uint8_t report_id, BT_HDR *pbuf);
+
+/*******************************************************************************
+**
+** Function         HID_HostCloseDev
+**
+** Description      This function disconnects the device.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern tHID_STATUS HID_HostCloseDev(uint8_t dev_handle );
+
+/*******************************************************************************
+** Function         HID_HostInit
+**
+** Description      This function initializes the control block and trace variable
+**
+** Returns          void
+*******************************************************************************/
+extern void HID_HostInit(void);
+
+/*******************************************************************************
+** Function        HID_HostSetSecurityLevel
+**
+** Description     This function sets the security level for the devices which
+**                 are marked by application as requiring security
+**
+** Returns         tHID_STATUS
+*******************************************************************************/
+extern tHID_STATUS HID_HostSetSecurityLevel(const char serv_name[], uint8_t sec_lvl );
+
+/*******************************************************************************
+**
+** Function         hid_known_hid_device
+**
+** Description      This function checks if this device is  of type HID Device
+**
+** Returns          true if device exists else false
+**
+*******************************************************************************/
+bool    hid_known_hid_device (BD_ADDR bd_addr);
+
+
+/*******************************************************************************
+**
+** Function         HID_HostSetTraceLevel
+**
+** Description      This function sets the trace level for HID Host. If called with
+**                  a value of 0xFF, it simply reads the current trace level.
+**
+** Returns          the new (current) trace level
+**
+*******************************************************************************/
+extern uint8_t HID_HostSetTraceLevel (uint8_t new_level);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* HIDH_API_H */
diff --git a/bt/stack/include/l2c_api.h b/bt/stack/include/l2c_api.h
new file mode 100644
index 0000000..033af10
--- /dev/null
+++ b/bt/stack/include/l2c_api.h
@@ -0,0 +1,1239 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 L2CAP API definitions
+ *
+ ******************************************************************************/
+#ifndef L2C_API_H
+#define L2C_API_H
+
+#include <stdbool.h>
+
+#include "bt_target.h"
+#include "l2cdefs.h"
+#include "hcidefs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+/* Define the minimum offset that L2CAP needs in a buffer. This is made up of
+** HCI type(1), len(2), handle(2), L2CAP len(2) and CID(2) => 9
+*/
+#define L2CAP_MIN_OFFSET    13     /* plus control(2), SDU length(2) */
+
+#define L2CAP_LCC_SDU_LENGTH    2
+#define L2CAP_LCC_OFFSET        (L2CAP_MIN_OFFSET + L2CAP_LCC_SDU_LENGTH)  /* plus SDU length(2) */
+
+/* ping result codes */
+#define L2CAP_PING_RESULT_OK        0       /* Ping reply received OK     */
+#define L2CAP_PING_RESULT_NO_LINK   1       /* Link could not be setup    */
+#define L2CAP_PING_RESULT_NO_RESP   2       /* Remote L2CAP did not reply */
+
+/* result code for L2CA_DataWrite() */
+#define L2CAP_DW_FAILED        false
+#define L2CAP_DW_SUCCESS       true
+#define L2CAP_DW_CONGESTED     2
+
+/* Values for priority parameter to L2CA_SetAclPriority */
+#define L2CAP_PRIORITY_NORMAL       0
+#define L2CAP_PRIORITY_HIGH         1
+
+/* Values for priority parameter to L2CA_SetTxPriority */
+#define L2CAP_CHNL_PRIORITY_HIGH    0
+#define L2CAP_CHNL_PRIORITY_MEDIUM  1
+#define L2CAP_CHNL_PRIORITY_LOW     2
+
+typedef uint8_t tL2CAP_CHNL_PRIORITY;
+
+/* Values for Tx/Rx data rate parameter to L2CA_SetChnlDataRate */
+#define L2CAP_CHNL_DATA_RATE_HIGH       3
+#define L2CAP_CHNL_DATA_RATE_MEDIUM     2
+#define L2CAP_CHNL_DATA_RATE_LOW        1
+#define L2CAP_CHNL_DATA_RATE_NO_TRAFFIC 0
+
+typedef uint8_t tL2CAP_CHNL_DATA_RATE;
+
+/* Data Packet Flags  (bits 2-15 are reserved) */
+/* layer specific 14-15 bits are used for FCR SAR */
+#define L2CAP_FLUSHABLE_MASK        0x0003
+#define L2CAP_FLUSHABLE_CH_BASED    0x0000
+#define L2CAP_FLUSHABLE_PKT         0x0001
+#define L2CAP_NON_FLUSHABLE_PKT     0x0002
+
+
+/* L2CA_FlushChannel num_to_flush definitions */
+#define L2CAP_FLUSH_CHANS_ALL       0xffff
+#define L2CAP_FLUSH_CHANS_GET       0x0000
+
+
+/* special CID for Multi-AV for reporting congestion */
+#define L2CAP_MULTI_AV_CID          0
+
+/* length of the HCI header block */
+/* HCI header(4) + SNK count(1) + FCR bits(1) + AV data length(2) */
+#define L2CAP_MULTI_AV_HCI_HDR_LEN	8
+
+/* length of padding for 4 bytes align */
+#define L2CAP_MULTI_AV_PADDING_LEN  2
+
+/* length of the HCI header block with padding for FCR */
+/* HCI header(4) + SNK count(1) + FCR bits(1) + AV data length(2) + padding(2) */
+#define L2CAP_MULTI_AV_HCI_HDR_LEN_WITH_PADDING	10
+
+/* length of the L2CAP header block */
+/* HCI header(4) + L2CAP header(4) + padding(4) or control word(2) + FCS(2) */
+#define L2CAP_MULTI_AV_L2C_HDR_LEN	12
+
+/* definition used for L2CA_SetDesireRole */
+#define L2CAP_ROLE_SLAVE            HCI_ROLE_SLAVE
+#define L2CAP_ROLE_MASTER           HCI_ROLE_MASTER
+#define L2CAP_ROLE_ALLOW_SWITCH     0x80    /* set this bit to allow switch at create conn */
+#define L2CAP_ROLE_DISALLOW_SWITCH  0x40    /* set this bit to disallow switch at create conn */
+#define L2CAP_ROLE_CHECK_SWITCH     0xC0
+
+
+/* Values for 'allowed_modes' field passed in structure tL2CAP_ERTM_INFO
+*/
+#define L2CAP_FCR_CHAN_OPT_BASIC    (1 << L2CAP_FCR_BASIC_MODE)
+#define L2CAP_FCR_CHAN_OPT_ERTM     (1 << L2CAP_FCR_ERTM_MODE)
+#define L2CAP_FCR_CHAN_OPT_STREAM   (1 << L2CAP_FCR_STREAM_MODE)
+
+#define L2CAP_FCR_CHAN_OPT_ALL_MASK (L2CAP_FCR_CHAN_OPT_BASIC | L2CAP_FCR_CHAN_OPT_ERTM | L2CAP_FCR_CHAN_OPT_STREAM)
+
+/* Validity check for PSM.  PSM values must be odd.  Also, all PSM values must
+** be assigned such that the least significant bit of the most sigificant
+** octet equals zero.
+*/
+#define L2C_INVALID_PSM(psm)       (((psm) & 0x0101) != 0x0001)
+#define L2C_IS_VALID_PSM(psm)      (((psm) & 0x0101) == 0x0001)
+#define L2C_IS_VALID_LE_PSM(psm)   (((psm) > 0x0000) && ((psm) < 0x0100))
+
+/*****************************************************************************
+**  Type Definitions
+*****************************************************************************/
+
+typedef struct
+{
+#define L2CAP_FCR_BASIC_MODE    0x00
+#define L2CAP_FCR_ERTM_MODE     0x03
+#define L2CAP_FCR_STREAM_MODE   0x04
+#define L2CAP_FCR_LE_COC_MODE   0x05
+
+    uint8_t mode;
+
+    uint8_t tx_win_sz;
+    uint8_t max_transmit;
+    uint16_t rtrans_tout;
+    uint16_t mon_tout;
+    uint16_t mps;
+} tL2CAP_FCR_OPTS;
+
+/* Define a structure to hold the configuration parameters. Since the
+** parameters are optional, for each parameter there is a boolean to
+** use to signify its presence or absence.
+*/
+typedef struct
+{
+    uint16_t    result;                 /* Only used in confirm messages */
+    bool        mtu_present;
+    uint16_t    mtu;
+    bool        qos_present;
+    FLOW_SPEC   qos;
+    bool        flush_to_present;
+    uint16_t    flush_to;
+    bool        fcr_present;
+    tL2CAP_FCR_OPTS fcr;
+    bool        fcs_present;            /* Optionally bypasses FCS checks */
+    uint8_t     fcs;                    /* '0' if desire is to bypass FCS, otherwise '1' */
+    bool                  ext_flow_spec_present;
+    tHCI_EXT_FLOW_SPEC    ext_flow_spec;
+    uint16_t    flags;                  /* bit 0: 0-no continuation, 1-continuation */
+} tL2CAP_CFG_INFO;
+
+/* Define a structure to hold the configuration parameter for LE L2CAP connection
+** oriented channels.
+*/
+typedef struct
+{
+    uint16_t mtu;
+    uint16_t mps;
+    uint16_t credits;
+} tL2CAP_LE_CFG_INFO;
+
+/* L2CAP channel configured field bitmap */
+#define L2CAP_CH_CFG_MASK_MTU           0x0001
+#define L2CAP_CH_CFG_MASK_QOS           0x0002
+#define L2CAP_CH_CFG_MASK_FLUSH_TO      0x0004
+#define L2CAP_CH_CFG_MASK_FCR           0x0008
+#define L2CAP_CH_CFG_MASK_FCS           0x0010
+#define L2CAP_CH_CFG_MASK_EXT_FLOW_SPEC 0x0020
+
+typedef uint16_t tL2CAP_CH_CFG_BITS;
+
+/*********************************
+**  Callback Functions Prototypes
+**********************************/
+
+/* Connection indication callback prototype. Parameters are
+**              BD Address of remote
+**              Local CID assigned to the connection
+**              PSM that the remote wants to connect to
+**              Identifier that the remote sent
+*/
+typedef void (tL2CA_CONNECT_IND_CB) (BD_ADDR, uint16_t, uint16_t, uint8_t);
+
+
+/* Connection confirmation callback prototype. Parameters are
+**              Local CID
+**              Result - 0 = connected, non-zero means failure reason
+*/
+typedef void (tL2CA_CONNECT_CFM_CB) (uint16_t, uint16_t);
+
+
+/* Connection pending callback prototype. Parameters are
+**              Local CID
+*/
+typedef void (tL2CA_CONNECT_PND_CB) (uint16_t);
+
+
+/* Configuration indication callback prototype. Parameters are
+**              Local CID assigned to the connection
+**              Pointer to configuration info
+*/
+typedef void (tL2CA_CONFIG_IND_CB) (uint16_t, tL2CAP_CFG_INFO *);
+
+
+/* Configuration confirm callback prototype. Parameters are
+**              Local CID assigned to the connection
+**              Pointer to configuration info
+*/
+typedef void (tL2CA_CONFIG_CFM_CB) (uint16_t, tL2CAP_CFG_INFO *);
+
+
+/* Disconnect indication callback prototype. Parameters are
+**              Local CID
+**              Boolean whether upper layer should ack this
+*/
+typedef void (tL2CA_DISCONNECT_IND_CB) (uint16_t, bool   );
+
+
+/* Disconnect confirm callback prototype. Parameters are
+**              Local CID
+**              Result
+*/
+typedef void (tL2CA_DISCONNECT_CFM_CB) (uint16_t, uint16_t);
+
+
+/* QOS Violation indication callback prototype. Parameters are
+**              BD Address of violating device
+*/
+typedef void (tL2CA_QOS_VIOLATION_IND_CB) (BD_ADDR);
+
+
+/* Data received indication callback prototype. Parameters are
+**              Local CID
+**              Address of buffer
+*/
+typedef void (tL2CA_DATA_IND_CB) (uint16_t, BT_HDR *);
+
+
+/* Echo response callback prototype. Note that this is not included in the
+** registration information, but is passed to L2CAP as part of the API to
+** actually send an echo request. Parameters are
+**              Result
+*/
+typedef void (tL2CA_ECHO_RSP_CB) (uint16_t);
+
+
+/* Callback function prototype to pass broadcom specific echo response  */
+/* to the upper layer                                                   */
+typedef void (tL2CA_ECHO_DATA_CB) (BD_ADDR, uint16_t, uint8_t *);
+
+
+/* Congestion status callback protype. This callback is optional. If
+** an application tries to send data when the transmit queue is full,
+** the data will anyways be dropped. The parameter is:
+**              Local CID
+**              true if congested, false if uncongested
+*/
+typedef void (tL2CA_CONGESTION_STATUS_CB) (uint16_t, bool   );
+
+/* Callback prototype for number of packets completed events.
+** This callback notifies the application when Number of Completed Packets
+** event has been received.
+** This callback is originally designed for 3DG devices.
+** The parameter is:
+**          peer BD_ADDR
+*/
+typedef void (tL2CA_NOCP_CB) (BD_ADDR);
+
+/* Transmit complete callback protype. This callback is optional. If
+** set, L2CAP will call it when packets are sent or flushed. If the
+** count is 0xFFFF, it means all packets are sent for that CID (eRTM
+** mode only). The parameters are:
+**              Local CID
+**              Number of SDUs sent or dropped
+*/
+typedef void (tL2CA_TX_COMPLETE_CB) (uint16_t, uint16_t);
+
+/* Define the structure that applications use to register with
+** L2CAP. This structure includes callback functions. All functions
+** MUST be provided, with the exception of the "connect pending"
+** callback and "congestion status" callback.
+*/
+typedef struct
+{
+    tL2CA_CONNECT_IND_CB        *pL2CA_ConnectInd_Cb;
+    tL2CA_CONNECT_CFM_CB        *pL2CA_ConnectCfm_Cb;
+    tL2CA_CONNECT_PND_CB        *pL2CA_ConnectPnd_Cb;
+    tL2CA_CONFIG_IND_CB         *pL2CA_ConfigInd_Cb;
+    tL2CA_CONFIG_CFM_CB         *pL2CA_ConfigCfm_Cb;
+    tL2CA_DISCONNECT_IND_CB     *pL2CA_DisconnectInd_Cb;
+    tL2CA_DISCONNECT_CFM_CB     *pL2CA_DisconnectCfm_Cb;
+    tL2CA_QOS_VIOLATION_IND_CB  *pL2CA_QoSViolationInd_Cb;
+    tL2CA_DATA_IND_CB           *pL2CA_DataInd_Cb;
+    tL2CA_CONGESTION_STATUS_CB  *pL2CA_CongestionStatus_Cb;
+    tL2CA_TX_COMPLETE_CB        *pL2CA_TxComplete_Cb;
+
+} tL2CAP_APPL_INFO;
+
+/* Define the structure that applications use to create or accept
+** connections with enhanced retransmission mode.
+*/
+typedef struct
+{
+    uint8_t     preferred_mode;
+    uint8_t     allowed_modes;
+    uint16_t    user_rx_buf_size;
+    uint16_t    user_tx_buf_size;
+    uint16_t    fcr_rx_buf_size;
+    uint16_t    fcr_tx_buf_size;
+
+} tL2CAP_ERTM_INFO;
+
+#define L2CA_REGISTER(a,b,c)              L2CA_Register(a,(tL2CAP_APPL_INFO *)(b))
+#define L2CA_DEREGISTER(a)                L2CA_Deregister(a)
+#define L2CA_CONNECT_REQ(a,b,c)           L2CA_ErtmConnectReq(a,b,c)
+#define L2CA_CONNECT_RSP(a,b,c,d,e,f)     L2CA_ErtmConnectRsp(a,b,c,d,e,f)
+#define L2CA_CONFIG_REQ(a,b)              L2CA_ConfigReq(a,b)
+#define L2CA_CONFIG_RSP(a,b)              L2CA_ConfigRsp(a,b)
+#define L2CA_DISCONNECT_REQ(a)            L2CA_DisconnectReq(a)
+#define L2CA_DISCONNECT_RSP(a)            L2CA_DisconnectRsp(a)
+#define L2CA_DATA_WRITE(a, b)             L2CA_DataWrite(a, b)
+#define L2CA_REGISTER_COC(a,b,c)          L2CA_RegisterLECoc(a,(tL2CAP_APPL_INFO *)(b))
+#define L2CA_DEREGISTER_COC(a)            L2CA_DeregisterLECoc(a)
+#define L2CA_CONNECT_COC_REQ(a,b,c)       L2CA_ConnectLECocReq(a,b,c)
+#define L2CA_CONNECT_COC_RSP(a,b,c,d,e,f) L2CA_ConnectLECocRsp(a,b,c,d,e,f)
+#define L2CA_GET_PEER_COC_CONFIG(a, b)    L2CA_GetPeerLECocConfig(a, b)
+
+/*****************************************************************************
+**  External Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** 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().
+**
+*******************************************************************************/
+extern uint16_t L2CA_Register (uint16_t psm, tL2CAP_APPL_INFO *p_cb_info);
+
+/*******************************************************************************
+**
+** Function         L2CA_Deregister
+**
+** Description      Other layers call this function to deregister for L2CAP
+**                  services.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern uint16_t L2CA_AllocatePSM(void);
+
+/*******************************************************************************
+**
+** 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 function
+**                  will be invoked when connection establishes or fails.
+**
+** Returns          the CID of the connection, or 0 if it failed to start
+**
+*******************************************************************************/
+extern uint16_t L2CA_ConnectReq (uint16_t psm, BD_ADDR 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
+**
+*******************************************************************************/
+extern bool    L2CA_ConnectRsp (BD_ADDR 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 function
+**                  will be invoked when connection establishes or fails.
+**
+** Returns          the CID of the connection, or 0 if it failed to start
+**
+*******************************************************************************/
+extern uint16_t L2CA_ErtmConnectReq (uint16_t psm, BD_ADDR 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().
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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 function
+**                  will be invoked when connection establishes or fails.
+**
+** Returns          the CID of the connection, or 0 if it failed to start
+**
+*******************************************************************************/
+extern uint16_t L2CA_ConnectLECocReq (uint16_t psm, BD_ADDR 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 an connect
+**                  indication callback.
+**
+** Returns          true for success, false for failure
+**
+*******************************************************************************/
+extern bool    L2CA_ConnectLECocRsp (BD_ADDR 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern bool     L2CA_ErtmConnectRsp (BD_ADDR 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern bool    L2CA_DisconnectReq (uint16_t cid);
+
+/*******************************************************************************
+**
+** Function         L2CA_DisconnectRsp
+**
+** Description      Higher layers call this function to acknowledge the
+**                  disconnection of a channel.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern bool    L2CA_Ping (BD_ADDR 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.
+**
+*******************************************************************************/
+extern bool     L2CA_Echo (BD_ADDR 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
+**
+*******************************************************************************/
+extern 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 = BT_BD_ANY,
+**                  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.
+*******************************************************************************/
+extern bool    L2CA_SetIdleTimeoutByBdAddr(BD_ADDR 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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.
+**
+*******************************************************************************/
+extern uint16_t L2CA_LocalLoopbackReq (uint16_t psm, uint16_t handle, BD_ADDR 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern bool    L2CA_SetAclPriority (BD_ADDR 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern bool    L2CA_RegForNoCPEvt(tL2CA_NOCP_CB *p_cb, BD_ADDR p_bda);
+
+/*******************************************************************************
+**
+** Function         L2CA_SetChnlDataRate
+**
+** Description      Sets the tx/rx data rate for a channel.
+**
+** Returns          true if a valid channel, else false
+**
+*******************************************************************************/
+extern 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_AUTO_FLUSH_TOUT (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.
+*******************************************************************************/
+extern bool    L2CA_SetFlushTimeout (BD_ADDR 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern bool    L2CA_GetPeerFeatures (BD_ADDR 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
+**
+*******************************************************************************/
+extern bool    L2CA_GetBDAddrbyHandle (uint16_t handle, BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+**  Function         L2CA_GetChnlFcrMode
+**
+**  Description      Get the channel FCR mode
+**
+**  Parameters:      Local CID
+**
+**  Return value:    Channel mode
+**
+*******************************************************************************/
+extern uint8_t L2CA_GetChnlFcrMode (uint16_t lcid);
+
+
+/*******************************************************************************
+**
+**                      UCD callback prototypes
+**
+*******************************************************************************/
+
+/* UCD discovery. Parameters are
+**      BD Address of remote
+**      Data Type
+**      Data
+*/
+#define L2CAP_UCD_INFO_TYPE_RECEPTION   0x01
+#define L2CAP_UCD_INFO_TYPE_MTU         0x02
+
+typedef void (tL2CA_UCD_DISCOVER_CB) (BD_ADDR, uint8_t, uint32_t);
+
+/* UCD data received. Parameters are
+**      BD Address of remote
+**      Pointer to buffer with data
+*/
+typedef void (tL2CA_UCD_DATA_CB) (BD_ADDR, BT_HDR *);
+
+/* Congestion status callback protype. This callback is optional. If
+** an application tries to send data when the transmit queue is full,
+** the data will anyways be dropped. The parameter is:
+**              remote BD_ADDR
+**              true if congested, false if uncongested
+*/
+typedef void (tL2CA_UCD_CONGESTION_STATUS_CB) (BD_ADDR, bool   );
+
+/* UCD registration info (the callback addresses and PSM)
+*/
+typedef struct
+{
+    tL2CA_UCD_DISCOVER_CB           *pL2CA_UCD_Discover_Cb;
+    tL2CA_UCD_DATA_CB               *pL2CA_UCD_Data_Cb;
+    tL2CA_UCD_CONGESTION_STATUS_CB  *pL2CA_UCD_Congestion_Status_Cb;
+} tL2CAP_UCD_CB_INFO;
+
+/*******************************************************************************
+**
+**  Function        L2CA_UcdRegister
+**
+**  Description     Register PSM on UCD.
+**
+**  Parameters:     tL2CAP_UCD_CB_INFO
+**
+**  Return value:   true if successs
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern bool    L2CA_UcdDiscover ( uint16_t psm, BD_ADDR 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
+**
+*******************************************************************************/
+extern uint16_t L2CA_UcdDataWrite (uint16_t psm, BD_ADDR 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
+**
+*******************************************************************************/
+extern bool    L2CA_UcdSetIdleTimeout ( BD_ADDR 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
+**
+*******************************************************************************/
+extern bool    L2CA_UCDSetTxPriority ( BD_ADDR rem_bda, tL2CAP_CHNL_PRIORITY priority );
+
+
+/*******************************************************************************
+**
+**                      Fixed Channel callback prototypes
+**
+*******************************************************************************/
+
+/* Fixed channel connected and disconnected. Parameters are
+**      channel
+**      BD Address of remote
+**      true if channel is connected, false if disconnected
+**      Reason for connection failure
+**      transport : physical transport, BR/EDR or LE
+*/
+typedef void (tL2CA_FIXED_CHNL_CB) (uint16_t, BD_ADDR, bool   , uint16_t, tBT_TRANSPORT);
+
+/* Signalling data received. Parameters are
+**      channel
+**      BD Address of remote
+**      Pointer to buffer with data
+*/
+typedef void (tL2CA_FIXED_DATA_CB) (uint16_t, BD_ADDR, BT_HDR *);
+
+/* Congestion status callback protype. This callback is optional. If
+** an application tries to send data when the transmit queue is full,
+** the data will anyways be dropped. The parameter is:
+**      remote BD_ADDR
+**      true if congested, false if uncongested
+*/
+typedef void (tL2CA_FIXED_CONGESTION_STATUS_CB) (BD_ADDR, bool   );
+
+/* Fixed channel registration info (the callback addresses and channel config)
+*/
+typedef struct
+{
+    tL2CA_FIXED_CHNL_CB    *pL2CA_FixedConn_Cb;
+    tL2CA_FIXED_DATA_CB    *pL2CA_FixedData_Cb;
+    tL2CA_FIXED_CONGESTION_STATUS_CB *pL2CA_FixedCong_Cb;
+    tL2CAP_FCR_OPTS         fixed_chnl_opts;
+
+    uint16_t                default_idle_tout;
+    tL2CA_TX_COMPLETE_CB    *pL2CA_FixedTxComplete_Cb; /* fixed channel tx complete callback */
+} tL2CAP_FIXED_CHNL_REG;
+
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+/*******************************************************************************
+**
+**  Function        L2CA_RegisterFixedChannel
+**
+**  Description     Register a fixed channel.
+**
+**  Parameters:     Fixed Channel #
+**                  Channel Callbacks and config
+**
+**  Return value:   true if registered OK
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern bool    L2CA_ConnectFixedChnl (uint16_t fixed_cid, BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+**  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
+**
+*******************************************************************************/
+extern uint16_t L2CA_SendFixedChnlData (uint16_t fixed_cid, BD_ADDR 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
+**
+*******************************************************************************/
+extern bool    L2CA_RemoveFixedChnl (uint16_t fixed_cid, BD_ADDR 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 = BT_BD_ANY,
+**                  then the idle timeouts for all active l2cap links will be
+**                  changed.
+**
+** Returns          true if command succeeded, false if failed
+**
+*******************************************************************************/
+extern bool    L2CA_SetFixedChannelTout (BD_ADDR rem_bda, uint16_t fixed_cid, uint16_t idle_tout);
+
+#endif /* (L2CAP_NUM_FIXED_CHNLS > 0) */
+
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+extern 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
+**
+*******************************************************************************/
+extern bool    L2CA_GetConnectionConfig(uint16_t lcid, uint16_t *mtu, uint16_t *rcid, uint16_t *handle);
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+**  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
+**
+*******************************************************************************/
+extern bool    L2CA_CancelBleConnectReq (BD_ADDR rem_bda);
+
+/*******************************************************************************
+**
+**  Function        L2CA_UpdateBleConnParams
+**
+**  Description     Update BLE connection parameters.
+**
+**  Parameters:     BD Address of remote
+**
+**  Return value:   true if update started
+**
+*******************************************************************************/
+extern bool    L2CA_UpdateBleConnParams (BD_ADDR rem_bdRa, uint16_t min_int,
+                                         uint16_t max_int, uint16_t latency, uint16_t timeout);
+
+/*******************************************************************************
+**
+**  Function        L2CA_EnableUpdateBleConnParams
+**
+**  Description     Update BLE connection parameters.
+**
+**  Parameters:     BD Address of remote
+**                  enable flag
+**
+**  Return value:   true if update started
+**
+*******************************************************************************/
+extern bool    L2CA_EnableUpdateBleConnParams (BD_ADDR rem_bda, bool    enable);
+
+/*******************************************************************************
+**
+** Function         L2CA_GetBleConnRole
+**
+** Description      This function returns the connection role.
+**
+** Returns          link role.
+**
+*******************************************************************************/
+extern uint8_t L2CA_GetBleConnRole (BD_ADDR 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
+**
+*******************************************************************************/
+extern uint16_t L2CA_GetDisconnectReason (BD_ADDR remote_bda, tBT_TRANSPORT transport);
+
+#endif /* (BLE_INCLUDED == TRUE) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* L2C_API_H */
diff --git a/bt/stack/include/l2cap_client.h b/bt/stack/include/l2cap_client.h
new file mode 100644
index 0000000..b995d5e
--- /dev/null
+++ b/bt/stack/include/l2cap_client.h
@@ -0,0 +1,74 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <hardware/bluetooth.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef struct buffer_t buffer_t;
+typedef struct l2cap_client_t l2cap_client_t;
+
+typedef struct {
+  void (*connected)(l2cap_client_t *client, void *context);
+  void (*disconnected)(l2cap_client_t *client, void *context);
+  void (*read_ready)(l2cap_client_t *client, buffer_t *packet, void *context);
+  void (*write_ready)(l2cap_client_t *client, void *context);
+} l2cap_client_callbacks_t;
+
+// Returns a new buffer with enough space for |size| bytes of L2CAP payload.
+// |size| must be greater than zero. This function returns NULL if the buffer
+// could not be allocated. The returned buffer must be freed with |buffer_free|
+// when it is no longer needed.
+buffer_t *l2cap_buffer_new(size_t size);
+
+// Creates and returns a new L2CAP client object. |callbacks| must not be NULL and
+// must specify a set of functions that should be called back when events occur
+// on the L2CAP connection. |context| may be NULL and will be passed as the argument
+// to all callbacks in |l2cap_client_callbacks_t|. The returned object must be freed
+// with |l2cap_client_free|.
+l2cap_client_t *l2cap_client_new(const l2cap_client_callbacks_t *callbacks, void *context);
+
+// Frees the L2CAP client object allocated with |l2cap_client_new|. |client| may be NULL.
+void l2cap_client_free(l2cap_client_t *client);
+
+// Attempts to connect the |client| to a peer device specified by |remote_bdaddr|
+// using the |psm| protocol specifier. This function returns true if the connect
+// operation could be started and will indicate completion with either a 'connected'
+// callback (success) or a 'disconnected' callback (failure).
+//
+// This function must not be called while a connect operation is in progress or
+// while |l2cap_client_is_connected|. |client| and |remote_bdaddr| must not be NULL.
+// |psm| must be greater than zero.
+bool l2cap_client_connect(l2cap_client_t *client, const bt_bdaddr_t *remote_bdaddr, uint16_t psm);
+
+// Disconnects a connected |client|. This function is asynchronous and idempotent. It
+// will indicate completion with a 'disconnected' callback. |client| must not be NULL.
+void l2cap_client_disconnect(l2cap_client_t *client);
+
+// Returns true if |client| is connected and is ready to accept data written to it.
+// |client| must not be NULL.
+bool l2cap_client_is_connected(const l2cap_client_t *client);
+
+// Writes data contained in |packet| to a connected |client|. This function returns
+// true if the packet was successfully queued for delivery, false if the client cannot
+// accept more data at this time. If this function returns false, the caller must wait
+// for the 'write_ready' callback to write additional data to the client. Neither
+// |client| nor |packet| may be NULL.
+bool l2cap_client_write(l2cap_client_t *client, buffer_t *packet);
diff --git a/bt/stack/include/l2cdefs.h b/bt/stack/include/l2cdefs.h
new file mode 100644
index 0000000..4037dc7
--- /dev/null
+++ b/bt/stack/include/l2cdefs.h
@@ -0,0 +1,334 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+
+#ifndef L2CDEFS_H
+#define L2CDEFS_H
+
+/* L2CAP command codes
+*/
+#define L2CAP_CMD_REJECT                    0x01
+#define L2CAP_CMD_CONN_REQ                  0x02
+#define L2CAP_CMD_CONN_RSP                  0x03
+#define L2CAP_CMD_CONFIG_REQ                0x04
+#define L2CAP_CMD_CONFIG_RSP                0x05
+#define L2CAP_CMD_DISC_REQ                  0x06
+#define L2CAP_CMD_DISC_RSP                  0x07
+#define L2CAP_CMD_ECHO_REQ                  0x08
+#define L2CAP_CMD_ECHO_RSP                  0x09
+#define L2CAP_CMD_INFO_REQ                  0x0A
+#define L2CAP_CMD_INFO_RSP                  0x0B
+#define L2CAP_CMD_AMP_CONN_REQ              0x0C
+#define L2CAP_CMD_AMP_CONN_RSP              0x0D
+#define L2CAP_CMD_AMP_MOVE_REQ              0x0E
+#define L2CAP_CMD_AMP_MOVE_RSP              0x0F
+#define L2CAP_CMD_AMP_MOVE_CFM              0x10
+#define L2CAP_CMD_AMP_MOVE_CFM_RSP          0x11
+#define L2CAP_CMD_BLE_UPDATE_REQ            0x12
+#define L2CAP_CMD_BLE_UPDATE_RSP            0x13
+#define L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ 0x14
+#define L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES 0x15
+#define L2CAP_CMD_BLE_FLOW_CTRL_CREDIT      0x16
+
+/* Define some packet and header lengths
+*/
+#define L2CAP_PKT_OVERHEAD      4           /* Length and CID                       */
+#define L2CAP_CMD_OVERHEAD      4           /* Cmd code, Id and length              */
+#define L2CAP_CMD_REJECT_LEN    2           /* Reason (data is optional)            */
+#define L2CAP_CONN_REQ_LEN      4           /* PSM and source CID                   */
+#define L2CAP_CONN_RSP_LEN      8           /* Dest CID, source CID, reason, status */
+#define L2CAP_CONFIG_REQ_LEN    4           /* Dest CID, flags (data is optional)   */
+#define L2CAP_CONFIG_RSP_LEN    6           /* Dest CID, flags, result,data optional*/
+#define L2CAP_DISC_REQ_LEN      4           /* Dest CID, source CID                 */
+#define L2CAP_DISC_RSP_LEN      4           /* Dest CID, source CID                 */
+#define L2CAP_ECHO_REQ_LEN      0           /* Data is optional                     */
+#define L2CAP_ECHO_RSP_LEN      0           /* Data is optional                     */
+#define L2CAP_INFO_REQ_LEN      2           /* Info type                            */
+#define L2CAP_INFO_RSP_LEN      4           /* Info type, result (data is optional) */
+#define L2CAP_UCD_OVERHEAD      2           /* Additional connectionless packet overhead */
+
+#define L2CAP_AMP_CONN_REQ_LEN  5           /* PSM, CID, and remote controller ID   */
+#define L2CAP_AMP_MOVE_REQ_LEN  3           /* CID and remote controller ID         */
+#define L2CAP_AMP_MOVE_RSP_LEN  4           /* CID and result                       */
+#define L2CAP_AMP_MOVE_CFM_LEN  4           /* CID and result                       */
+#define L2CAP_AMP_MOVE_CFM_RSP_LEN  2       /* CID                                  */
+
+#define L2CAP_CMD_BLE_UPD_REQ_LEN   8       /* Min and max interval, latency, tout  */
+#define L2CAP_CMD_BLE_UPD_RSP_LEN   2       /* Result                               */
+
+#define L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ_LEN 10 /* LE_PSM, SCID, MTU, MPS, Init Credit */
+#define L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES_LEN 10 /* DCID, MTU, MPS, Init credit, Result */
+#define L2CAP_CMD_BLE_FLOW_CTRL_CREDIT_LEN      4  /* CID, Credit */
+
+/* Define the packet boundary flags
+*/
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+#define L2CAP_PKT_START_FLUSHABLE       2
+#define L2CAP_PKT_START_NON_FLUSHABLE   0
+#endif
+#define L2CAP_COMPLETE_AMP_PKT          3       /* complete L2CAP packet on AMP HCI */
+#define L2CAP_PKT_START                 2
+#define L2CAP_PKT_CONTINUE              1
+#define L2CAP_MASK_FLAG            0x0FFF
+#define L2CAP_PKT_TYPE_SHIFT            12
+#define L2CAP_PKT_TYPE_MASK             3
+
+
+/* Define the L2CAP connection result codes
+*/
+#define L2CAP_CONN_OK                0
+#define L2CAP_CONN_PENDING           1
+#define L2CAP_CONN_NO_PSM            2
+#define L2CAP_CONN_SECURITY_BLOCK    3
+#define L2CAP_CONN_NO_RESOURCES      4
+#define L2CAP_CONN_BAD_CTLR_ID       5              /* AMP related */
+#define L2CAP_CONN_TIMEOUT           0xEEEE
+#define L2CAP_CONN_AMP_FAILED        254
+#define L2CAP_CONN_NO_LINK           255        /* Add a couple of our own for internal use */
+#define L2CAP_CONN_CANCEL            256        /* L2CAP connection cancelled */
+
+/* Define the LE L2CAP connection result codes
+*/
+#define L2CAP_LE_CONN_OK                        0
+#define L2CAP_LE_NO_PSM                         2
+#define L2CAP_LE_NO_RESOURCES                   4
+#define L2CAP_LE_INSUFFICIENT_AUTHENTICATION    5
+#define L2CAP_LE_INSUFFICIENT_AUTHORIZATION     6
+#define L2CAP_LE_INSUFFICIENT_ENCRYP_KEY_SIZE   7
+#define L2CAP_LE_INSUFFICIENT_ENCRYP            8
+#define L2CAP_LE_INVALID_SOURCE_CID             9   /* We don't like peer device response */
+
+/* Define L2CAP Move Channel Response result codes
+*/
+#define L2CAP_MOVE_OK                   0
+#define L2CAP_MOVE_PENDING              1
+#define L2CAP_MOVE_CTRL_ID_NOT_SUPPORT  2
+#define L2CAP_MOVE_SAME_CTRLR_ID        3
+#define L2CAP_MOVE_CONFIG_NOT_SUPPORTED 4
+#define L2CAP_MOVE_CHAN_COLLISION       5
+#define L2CAP_MOVE_NOT_ALLOWED          6
+
+
+/* Define L2CAP Move Channel Confirmation result codes
+*/
+#define L2CAP_MOVE_CFM_OK               0
+#define L2CAP_MOVE_CFM_REFUSED          1
+
+
+/* Define the L2CAP command reject reason codes
+*/
+#define L2CAP_CMD_REJ_NOT_UNDERSTOOD    0
+#define L2CAP_CMD_REJ_MTU_EXCEEDED      1
+#define L2CAP_CMD_REJ_INVALID_CID       2
+
+
+/* L2CAP Predefined CIDs
+*/
+#define L2CAP_SIGNALLING_CID            1
+#define L2CAP_CONNECTIONLESS_CID        2
+#define L2CAP_AMP_CID                   3
+#define L2CAP_ATT_CID                   4
+#define L2CAP_BLE_SIGNALLING_CID        5
+#define L2CAP_SMP_CID                   6
+#define L2CAP_SMP_BR_CID                7
+#define L2CAP_AMP_TEST_CID              0x003F
+#define L2CAP_BASE_APPL_CID             0x0040
+#define L2CAP_BLE_CONN_MAX_CID          0x007F
+
+/* Fixed Channels mask bits */
+
+/* Signal channel supported (Mandatory) */
+#define L2CAP_FIXED_CHNL_SIG_BIT     (1 << L2CAP_SIGNALLING_CID)
+
+/* Connectionless reception */
+#define L2CAP_FIXED_CHNL_CNCTLESS_BIT (1 << L2CAP_CONNECTIONLESS_CID)
+
+/* AMP Manager supported */
+#define L2CAP_FIXED_CHNL_AMP_BIT      (1 << L2CAP_AMP_CID)
+
+/* Attribute protocol supported */
+#define L2CAP_FIXED_CHNL_ATT_BIT      (1 << L2CAP_ATT_CID)
+
+/* BLE Signalling supported */
+#define L2CAP_FIXED_CHNL_BLE_SIG_BIT  (1 << L2CAP_BLE_SIGNALLING_CID)
+
+/* BLE Security Mgr supported */
+#define L2CAP_FIXED_CHNL_SMP_BIT      (1 << L2CAP_SMP_CID)
+
+/* Security Mgr over BR supported */
+#define L2CAP_FIXED_CHNL_SMP_BR_BIT   (1 << L2CAP_SMP_BR_CID)
+
+
+
+/* Define the L2CAP configuration result codes
+*/
+#define L2CAP_CFG_OK                    0
+#define L2CAP_CFG_UNACCEPTABLE_PARAMS   1
+#define L2CAP_CFG_FAILED_NO_REASON      2
+#define L2CAP_CFG_UNKNOWN_OPTIONS       3
+#define L2CAP_CFG_PENDING               4
+#define L2CAP_CFG_FLOW_SPEC_REJECTED    5
+
+
+/* Define the L2CAP configuration option types
+*/
+#define L2CAP_CFG_TYPE_MTU              0x01
+#define L2CAP_CFG_TYPE_FLUSH_TOUT       0x02
+#define L2CAP_CFG_TYPE_QOS              0x03
+#define L2CAP_CFG_TYPE_FCR              0x04
+#define L2CAP_CFG_TYPE_FCS              0x05
+#define L2CAP_CFG_TYPE_EXT_FLOW         0x06
+#define L2CAP_CFG_TYPE_EXT_WIN_SIZE     0x07
+
+#define L2CAP_CFG_MTU_OPTION_LEN        2           /* MTU option length    */
+#define L2CAP_CFG_FLUSH_OPTION_LEN      2           /* Flush option len     */
+#define L2CAP_CFG_QOS_OPTION_LEN        22          /* QOS option length    */
+#define L2CAP_CFG_FCR_OPTION_LEN        9           /* FCR option length    */
+#define L2CAP_CFG_FCS_OPTION_LEN        1           /* FCR option length    */
+#define L2CAP_CFG_EXT_FLOW_OPTION_LEN   16          /* Extended Flow Spec   */
+#define L2CAP_CFG_EXT_WIN_SIZE_LEN      2           /* Ext window size length */
+#define L2CAP_CFG_OPTION_OVERHEAD       2           /* Type and length      */
+
+/* Configuration Cmd/Rsp Flags mask
+*/
+#define L2CAP_CFG_FLAGS_MASK_CONT       0x0001      /* Flags mask: Continuation */
+
+/* FCS Check Option values
+*/
+#define L2CAP_CFG_FCS_BYPASS            0       /* Bypass the FCS in streaming or ERTM modes */
+#define L2CAP_CFG_FCS_USE               1       /* Use the FCS in streaming or ERTM modes [default] */
+
+/* Default values for configuration
+*/
+#define L2CAP_NO_AUTOMATIC_FLUSH        0xFFFF
+#define L2CAP_NO_RETRANSMISSION         0x0001
+
+#define L2CAP_DEFAULT_MTU               (672)
+#define L2CAP_DEFAULT_FLUSH_TO          L2CAP_NO_AUTOMATIC_FLUSH
+#define L2CAP_DEFAULT_SERV_TYPE         1
+#define L2CAP_DEFAULT_TOKEN_RATE        0
+#define L2CAP_DEFAULT_BUCKET_SIZE       0
+#define L2CAP_DEFAULT_PEAK_BANDWIDTH    0
+#define L2CAP_DEFAULT_LATENCY           0xFFFFFFFF
+#define L2CAP_DEFAULT_DELAY             0xFFFFFFFF
+#define L2CAP_DEFAULT_FCS               L2CAP_CFG_FCS_USE
+
+
+/* Define the L2CAP disconnect result codes
+*/
+#define L2CAP_DISC_OK                   0
+#define L2CAP_DISC_TIMEOUT              0xEEEE
+
+/* Define the L2CAP info resp result codes
+*/
+#define L2CAP_INFO_RESP_RESULT_SUCCESS          0
+#define L2CAP_INFO_RESP_RESULT_NOT_SUPPORTED    1
+
+/* Define the info-type fields of information request & response
+*/
+#define L2CAP_CONNLESS_MTU_INFO_TYPE      0x0001
+#define L2CAP_EXTENDED_FEATURES_INFO_TYPE 0x0002    /* Used in Information Req/Response */
+#define L2CAP_FIXED_CHANNELS_INFO_TYPE    0x0003    /* Used in AMP                      */
+
+#define L2CAP_CONNLESS_MTU_INFO_SIZE           2    /* Connectionless MTU size          */
+#define L2CAP_EXTENDED_FEATURES_ARRAY_SIZE     4    /* Extended features array size     */
+#define L2CAP_FIXED_CHNL_ARRAY_SIZE            8    /* Fixed channel array size         */
+
+/* Extended features mask bits
+*/
+#define L2CAP_EXTFEA_RTRANS         0x00000001    /* Retransmission Mode (Not Supported)    */
+#define L2CAP_EXTFEA_FC             0x00000002    /* Flow Control Mode   (Not Supported)    */
+#define L2CAP_EXTFEA_QOS            0x00000004
+#define L2CAP_EXTFEA_ENH_RETRANS    0x00000008    /* Enhanced retransmission mode           */
+#define L2CAP_EXTFEA_STREAM_MODE    0x00000010    /* Streaming Mode                         */
+#define L2CAP_EXTFEA_NO_CRC         0x00000020    /* Optional FCS (if set No FCS desired)   */
+#define L2CAP_EXTFEA_EXT_FLOW_SPEC  0x00000040    /* Extended flow spec                     */
+#define L2CAP_EXTFEA_FIXED_CHNLS    0x00000080    /* Fixed channels                         */
+#define L2CAP_EXTFEA_EXT_WINDOW     0x00000100    /* Extended Window Size                   */
+#define L2CAP_EXTFEA_UCD_RECEPTION  0x00000200    /* Unicast Connectionless Data Reception  */
+
+/* Mask for locally supported features used in Information Response (default to none) */
+#ifndef L2CAP_EXTFEA_SUPPORTED_MASK
+#define L2CAP_EXTFEA_SUPPORTED_MASK 0
+#endif
+
+/* Mask for LE supported features used in Information Response (default to none) */
+#ifndef L2CAP_BLE_EXTFEA_MASK
+#define L2CAP_BLE_EXTFEA_MASK 0
+#endif
+
+/* Define a value that tells L2CAP to use the default HCI ACL buffer size */
+#define L2CAP_INVALID_ERM_BUF_SIZE      0
+/* Define a value that tells L2CAP to use the default MPS */
+#define L2CAP_DEFAULT_ERM_MPS           0x0000
+
+#define L2CAP_FCR_OVERHEAD         2   /* Control word                 */
+#define L2CAP_FCS_LEN              2   /* FCS takes 2 bytes */
+#define L2CAP_SDU_LEN_OVERHEAD     2   /* SDU length field is 2 bytes */
+#define L2CAP_SDU_LEN_OFFSET       2   /* SDU length offset is 2 bytes */
+#define L2CAP_EXT_CONTROL_OVERHEAD 4   /* Extended Control Field       */
+#define L2CAP_MAX_HEADER_FCS       (L2CAP_PKT_OVERHEAD + L2CAP_EXT_CONTROL_OVERHEAD + L2CAP_SDU_LEN_OVERHEAD + L2CAP_FCS_LEN)
+                                   /* length(2), channel(2), control(4), SDU length(2) FCS(2) */
+
+/* To optimize this, it must be a multiplum of the L2CAP PDU length AND match the 3DH5 air
+ * including the l2cap headers in each packet - to match the latter - the -5 is added
+ * Changed it to  8087 to have same value between BTIF and L2cap layers
+ */
+#define L2CAP_MAX_SDU_LENGTH     (8080 + 26 - (L2CAP_MIN_OFFSET + 6))
+#define L2CAP_MAX_BUF_SIZE      (10240 + 24)
+
+/* Part of L2CAP_MIN_OFFSET that is not part of L2CAP
+*/
+#define L2CAP_OFFSET_WO_L2HDR  (L2CAP_MIN_OFFSET-(L2CAP_PKT_OVERHEAD+L2CAP_FCR_OVERHEAD))
+
+/* SAR bits in the control word
+*/
+#define L2CAP_FCR_UNSEG_SDU    0x0000   /* Control word to begin with for unsegmented PDU*/
+#define L2CAP_FCR_START_SDU    0x4000   /* ...for Starting PDU of a semented SDU */
+#define L2CAP_FCR_END_SDU      0x8000   /* ...for ending PDU of a segmented SDU */
+#define L2CAP_FCR_CONT_SDU     0xc000   /* ...for continuation PDU of a segmented SDU */
+
+/* Supervisory frame types
+*/
+#define L2CAP_FCR_SUP_RR        0x0000   /* Supervisory frame - RR                          */
+#define L2CAP_FCR_SUP_REJ       0x0001   /* Supervisory frame - REJ                         */
+#define L2CAP_FCR_SUP_RNR       0x0002   /* Supervisory frame - RNR                         */
+#define L2CAP_FCR_SUP_SREJ      0x0003   /* Supervisory frame - SREJ                        */
+
+#define L2CAP_FCR_SAR_BITS           0xC000    /* Mask to get the SAR bits from control word */
+#define L2CAP_FCR_SAR_BITS_SHIFT     14        /* Bits to shift right to get the SAR bits from ctrl-word */
+
+#define L2CAP_FCR_S_FRAME_BIT         0x0001   /* Mask to check if a PDU is S-frame */
+#define L2CAP_FCR_REQ_SEQ_BITS        0x3F00   /* Mask to get the req-seq from control word */
+#define L2CAP_FCR_REQ_SEQ_BITS_SHIFT  8        /* Bits to shift right to get the req-seq from ctrl-word */
+#define L2CAP_FCR_TX_SEQ_BITS         0x007E   /* Mask on get the tx-seq from control word */
+#define L2CAP_FCR_TX_SEQ_BITS_SHIFT   1        /* Bits to shift right to get the tx-seq from ctrl-word */
+
+#define L2CAP_FCR_F_BIT               0x0080   /* F-bit in the control word (Sup and I frames)  */
+#define L2CAP_FCR_P_BIT               0x0010   /* P-bit in the control word (Sup frames only)   */
+
+#define L2CAP_FCR_F_BIT_SHIFT         7
+#define L2CAP_FCR_P_BIT_SHIFT         4
+
+#define L2CAP_FCR_SEG_BITS            0xC000   /* Mask to get the segmentation bits from ctrl-word */
+#define L2CAP_FCR_SUP_SHIFT           2        /* Bits to shift right to get the S-bits from ctrl-word */
+#define L2CAP_FCR_SUP_BITS            0x000C   /* Mask to get the supervisory bits from ctrl-word */
+
+#define L2CAP_FCR_INIT_CRC            0   /* Initial state of the CRC register */
+#define L2CAP_FCR_SEQ_MODULO          0x3F     /* Mask for sequence numbers (range 0 - 63) */
+
+#endif
diff --git a/bt/stack/include/mca_api.h b/bt/stack/include/mca_api.h
new file mode 100644
index 0000000..5cd82e4
--- /dev/null
+++ b/bt/stack/include/mca_api.h
@@ -0,0 +1,503 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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 interface file contains the interface to the Multi-Channel
+ *  Adaptation Protocol (MCAP).
+ *
+ ******************************************************************************/
+#ifndef MCA_API_H
+#define MCA_API_H
+
+#include "bt_target.h"
+#include "l2c_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* move the following to bt_target.h or other place later */
+#define MCA_NUM_TC_TBL  ((MCA_NUM_REGS)*(MCA_NUM_LINKS)*(MCA_NUM_MDLS+1))
+#define MCA_NUM_CCBS	((MCA_NUM_REGS)*(MCA_NUM_LINKS))    /* Number of control channel control blocks	*/
+#define MCA_NUM_DCBS	((MCA_NUM_REGS)*(MCA_NUM_LINKS)*(MCA_NUM_MDLS)) /* Number of data channel control blocks */
+
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+/* API function return value result codes. */
+#define MCA_SUCCESS                0       /* Function successful */
+#define MCA_BAD_PARAMS             1       /* Invalid parameters */
+#define MCA_NO_RESOURCES           2       /* Not enough resources */
+#define MCA_BAD_HANDLE             3       /* Bad handle */
+#define MCA_BUSY                   4       /* A procedure is already in progress */
+#define MCA_WRITE_FAIL             5       /* Write failed */
+#define MCA_BAD_MDL_ID             6       /* MDL ID is not valid for the current API */
+typedef uint8_t tMCA_RESULT;
+
+/* MDEP data type.  */
+#define MCA_TDEP_ECHO              0       /* MDEP for echo test  */
+#define MCA_TDEP_DATA              1       /* MDEP for normal data */
+
+/* Control callback events. */
+#define MCA_ERROR_RSP_EVT           0       /* error response */
+#define MCA_CREATE_IND_EVT          1       /* create mdl indication */
+#define MCA_CREATE_CFM_EVT          2       /* create mdl confirm */
+#define MCA_RECONNECT_IND_EVT       3       /* reconnect mdl indication */
+#define MCA_RECONNECT_CFM_EVT       4       /* reconnect mdl confirm */
+#define MCA_ABORT_IND_EVT           5       /* abort mdl indication */
+#define MCA_ABORT_CFM_EVT           6       /* abort mdl confirm */
+#define MCA_DELETE_IND_EVT          7       /* delete mdl indication */
+#define MCA_DELETE_CFM_EVT          8       /* delete mdl confirm */
+
+#define MCA_SYNC_CAP_IND_EVT        0x11   /* request sync capabilities & requirements */
+#define MCA_SYNC_CAP_CFM_EVT        0x12   /* indicate completion */
+#define MCA_SYNC_SET_IND_EVT        0x13   /* request to set the time-stamp clock */
+#define MCA_SYNC_SET_CFM_EVT        0x14   /* indicate completion */
+#define MCA_SYNC_INFO_IND_EVT       0x15   /* update of the actual time-stamp clock instant from the sync slave */
+
+#define MCA_CONNECT_IND_EVT         0x20    /* Control channel connected */
+#define MCA_DISCONNECT_IND_EVT      0x21    /* Control channel disconnected */
+#define MCA_OPEN_IND_EVT            0x22    /* Data channel open indication */
+#define MCA_OPEN_CFM_EVT            0x23    /* Data channel open confirm */
+#define MCA_CLOSE_IND_EVT           0x24    /* Data channel close indication */
+#define MCA_CLOSE_CFM_EVT           0x25    /* Data channel close confirm */
+#define MCA_CONG_CHG_EVT            0x26    /* congestion change event */
+#define MCA_RSP_TOUT_IND_EVT        0x27    /* Control channel message response timeout */
+/*****************************************************************************
+**  Type Definitions
+*****************************************************************************/
+typedef uint8_t tMCA_HANDLE; /* the handle for registration. 1 based index to rcb */
+typedef uint8_t tMCA_CL;     /* the handle for a control channel; reported at MCA_CONNECT_IND_EVT */
+typedef uint8_t tMCA_DEP;    /* the handle for MCA_CreateDep. This is also the local mdep_id */
+typedef uint16_t tMCA_DL;     /* the handle for the data channel. This is reported at MCA_OPEN_CFM_EVT or MCA_OPEN_IND_EVT */
+
+/* This is the data callback function.  It is executed when MCAP has a data
+** packet ready for the application.
+*/
+typedef void (tMCA_DATA_CBACK)(tMCA_DL mdl, BT_HDR *p_pkt);
+
+
+/* This structure contains parameters which are set at registration. */
+typedef struct {
+    uint32_t    rsp_tout;   /* MCAP signaling response timeout */
+    uint16_t    ctrl_psm;   /* L2CAP PSM for the MCAP control channel */
+    uint16_t    data_psm;   /* L2CAP PSM for the MCAP data channel */
+    uint16_t    sec_mask;   /* Security mask for BTM_SetSecurityLevel() */
+} tMCA_REG;
+
+/* This structure contains parameters to create a MDEP. */
+typedef struct {
+    uint8_t         type;       /* MCA_TDEP_DATA, or MCA_TDEP_ECHO. a regiatration may have only one MCA_TDEP_ECHO MDEP */
+    uint8_t         max_mdl;    /* The maximum number of MDLs for this MDEP (max is MCA_NUM_MDLS) */
+    tMCA_DATA_CBACK *p_data_cback;  /* Data callback function */
+} tMCA_CS;
+
+#define MCA_FCS_NONE        0       /* fcs_present=false */
+#define MCA_FCS_BYPASS      0x10    /* fcs_present=true, fcs=L2CAP_CFG_FCS_BYPASS */
+#define MCA_FCS_USE         0x11    /* fcs_present=true, fcs=L2CAP_CFG_FCS_USE */
+#define MCA_FCS_PRESNT_MASK 0x10    /* fcs_present=true */
+#define MCA_FCS_USE_MASK    0x01    /* mask for fcs */
+typedef uint8_t tMCA_FCS_OPT;
+
+/* This structure contains L2CAP configuration parameters for the channel. */
+typedef struct {
+    tL2CAP_FCR_OPTS fcr_opt;
+    uint16_t        user_rx_buf_size;
+    uint16_t        user_tx_buf_size;
+    uint16_t        fcr_rx_buf_size;
+    uint16_t        fcr_tx_buf_size;
+    tMCA_FCS_OPT    fcs;
+    uint16_t        data_mtu;   /* L2CAP MTU of the MCAP data channel */
+} tMCA_CHNL_CFG;
+
+
+/* Header structure for callback event parameters. */
+typedef struct {
+    uint16_t        mdl_id;     /* The associated MDL ID */
+    uint8_t         op_code;    /* The op (request/response) code */
+} tMCA_EVT_HDR;
+
+/* Response Header structure for callback event parameters. */
+typedef struct {
+    uint16_t        mdl_id;     /* The associated MDL ID */
+    uint8_t         op_code;    /* The op (request/response) code */
+    uint8_t         rsp_code;   /* The response code */
+} tMCA_RSP_EVT;
+
+/* This data structure is associated with the MCA_CREATE_IND_EVT. */
+typedef struct {
+    uint16_t        mdl_id;     /* The associated MDL ID */
+    uint8_t         op_code;    /* The op (request/response) code */
+    uint8_t         dep_id;     /* MDEP ID */
+    uint8_t         cfg;        /* The configuration to negotiate */
+} tMCA_CREATE_IND;
+
+/* This data structure is associated with the MCA_CREATE_CFM_EVT. */
+typedef struct {
+    uint16_t        mdl_id;     /* The associated MDL ID */
+    uint8_t         op_code;    /* The op (request/response) code */
+    uint8_t         rsp_code;   /* The response code. */
+    uint8_t         cfg;        /* The configuration to negotiate */
+} tMCA_CREATE_CFM;
+
+/* This data structure is associated with MCA_CONNECT_IND_EVT. */
+typedef struct {
+    BD_ADDR         bd_addr;    /* The peer address */
+    uint16_t        mtu;        /* peer mtu */
+} tMCA_CONNECT_IND;
+
+/* This data structure is associated with MCA_DISCONNECT_IND_EVT. */
+typedef struct {
+    BD_ADDR         bd_addr;    /* The peer address */
+    uint16_t        reason;     /* disconnect reason given by L2CAP */
+} tMCA_DISCONNECT_IND;
+
+/* This data structure is associated with MCA_OPEN_IND_EVT, and MCA_OPEN_CFM_EVT. */
+typedef struct {
+    uint16_t        mdl_id;     /* The associated MDL ID */
+    tMCA_DL         mdl;        /* The handle for the data channel */
+    uint16_t        mtu;        /* peer mtu */
+} tMCA_DL_OPEN;
+
+/* This data structure is associated with MCA_CLOSE_IND_EVT and MCA_CLOSE_CFM_EVT. */
+typedef struct {
+    uint16_t        mdl_id;     /* The associated MDL ID */
+    tMCA_DL         mdl;        /* The handle for the data channel */
+    uint16_t        reason;     /* disconnect reason given by L2CAP */
+} tMCA_DL_CLOSE;
+
+/* This data structure is associated with MCA_CONG_CHG_EVT. */
+typedef struct {
+    uint16_t        mdl_id;     /* N/A - This is a place holder */
+    tMCA_DL	        mdl;        /* The handle for the data channel */
+    bool            cong;       /* true, if the channel is congested */
+} tMCA_CONG_CHG;
+
+/* Union of all control callback event data structures */
+typedef union {
+    tMCA_EVT_HDR        hdr;
+    tMCA_RSP_EVT        rsp;
+    tMCA_CREATE_IND     create_ind;
+    tMCA_CREATE_CFM     create_cfm;
+    tMCA_EVT_HDR        reconnect_ind;
+    tMCA_RSP_EVT        reconnect_cfm;
+    tMCA_EVT_HDR        abort_ind;
+    tMCA_RSP_EVT        abort_cfm;
+    tMCA_EVT_HDR        delete_ind;
+    tMCA_RSP_EVT        delete_cfm;
+    tMCA_CONNECT_IND    connect_ind;
+    tMCA_DISCONNECT_IND disconnect_ind;
+    tMCA_DL_OPEN        open_ind;
+    tMCA_DL_OPEN        open_cfm;
+    tMCA_DL_CLOSE       close_ind;
+    tMCA_DL_CLOSE       close_cfm;
+    tMCA_CONG_CHG       cong_chg;
+} tMCA_CTRL;
+
+/* This is the control callback function.  This function passes control events
+** to the application.
+*/
+typedef void (tMCA_CTRL_CBACK)(tMCA_HANDLE handle, tMCA_CL mcl, uint8_t event,
+                                tMCA_CTRL *p_data);
+
+
+/*******************************************************************************
+**
+** Function         MCA_Init
+**
+** Description      Initialize MCAP internal control blocks.
+**                  This function is called at stack start up.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void MCA_Init(void);
+
+/*******************************************************************************
+**
+** Function         MCA_SetTraceLevel
+**
+** Description      This function sets the debug trace level for MCA.
+**                  If 0xff is passed, the current trace level is returned.
+**
+**                  Input Parameters:
+**                      level:  The level to set the MCA tracing to:
+**                      0xff-returns the current setting.
+**                      0-turns off tracing.
+**                      >= 1-Errors.
+**                      >= 2-Warnings.
+**                      >= 3-APIs.
+**                      >= 4-Events.
+**                      >= 5-Debug.
+**
+** Returns          The new trace level or current trace level if
+**                  the input parameter is 0xff.
+**
+*******************************************************************************/
+extern uint8_t MCA_SetTraceLevel (uint8_t level);
+
+/*******************************************************************************
+**
+** Function         MCA_Register
+**
+** Description      This function registers an MCAP implementation.
+**                  It is assumed that the control channel PSM and data channel
+**                  PSM are not used by any other instances of the stack.
+**                  If the given p_reg->ctrl_psm is 0, this handle is INT only.
+**
+** Returns          0, if failed. Otherwise, the MCA handle.
+**
+*******************************************************************************/
+extern tMCA_HANDLE MCA_Register(tMCA_REG *p_reg, tMCA_CTRL_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function         MCA_Deregister
+**
+** Description      This function is called to deregister an MCAP implementation.
+**                  Before this function can be called, all control and data
+**                  channels must be removed with MCA_DisconnectReq and MCA_CloseReq.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void MCA_Deregister(tMCA_HANDLE handle);
+
+/*******************************************************************************
+**
+** Function         MCA_CreateDep
+**
+** Description      Create a data endpoint.  If the MDEP is created successfully,
+**                  the MDEP ID is returned in *p_dep. After a data endpoint is
+**                  created, an application can initiate a connection between this
+**                  endpoint and an endpoint on a peer device.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern tMCA_RESULT MCA_CreateDep(tMCA_HANDLE handle, tMCA_DEP *p_dep, tMCA_CS *p_cs);
+
+/*******************************************************************************
+**
+** Function         MCA_DeleteDep
+**
+** Description      Delete a data endpoint.  This function is called when
+**                  the implementation is no longer using a data endpoint.
+**                  If this function is called when the endpoint is connected
+**                  the connection is closed and the data endpoint
+**                  is removed.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern tMCA_RESULT MCA_DeleteDep(tMCA_HANDLE handle, tMCA_DEP dep);
+
+/*******************************************************************************
+**
+** Function         MCA_ConnectReq
+**
+** Description      This function initiates an MCAP control channel connection
+**                  to the peer device.  When the connection is completed, an
+**                  MCA_CONNECT_IND_EVT is reported to the application via its
+**                  control callback function.
+**                  This control channel is identified by tMCA_CL.
+**                  If the connection attempt fails, an MCA_DISCONNECT_IND_EVT is
+**                  reported. The security mask parameter overrides the outgoing
+**                  security mask set in MCA_Register().
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern tMCA_RESULT MCA_ConnectReq(tMCA_HANDLE handle, BD_ADDR bd_addr,
+                                  uint16_t ctrl_psm,
+                                  uint16_t sec_mask);
+
+/*******************************************************************************
+**
+** Function         MCA_DisconnectReq
+**
+** Description      This function disconnect an MCAP control channel
+**                  to the peer device.
+**                  If associated data channel exists, they are disconnected.
+**                  When the MCL is disconnected an MCA_DISCONNECT_IND_EVT is
+**                  reported to the application via its control callback function.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern tMCA_RESULT MCA_DisconnectReq(tMCA_CL mcl);
+
+/*******************************************************************************
+**
+** Function         MCA_CreateMdl
+**
+** Description      This function sends a CREATE_MDL request to the peer device.
+**                  When the response is received, a MCA_CREATE_CFM_EVT is reported
+**                  with the given MDL ID.
+**                  If the response is successful, a data channel is open
+**                  with the given p_chnl_cfg
+**                  When the data channel is open successfully, a MCA_OPEN_CFM_EVT
+**                  is reported. This data channel is identified as tMCA_DL.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern tMCA_RESULT MCA_CreateMdl(tMCA_CL mcl, tMCA_DEP dep, uint16_t data_psm,
+                                 uint16_t mdl_id, uint8_t peer_dep_id,
+                                 uint8_t cfg, const tMCA_CHNL_CFG *p_chnl_cfg);
+
+/*******************************************************************************
+**
+** Function         MCA_CreateMdlRsp
+**
+** Description      This function sends a CREATE_MDL response to the peer device
+**                  in response to a received MCA_CREATE_IND_EVT.
+**                  If the rsp_code is successful, a data channel is open
+**                  with the given p_chnl_cfg
+**                  When the data channel is open successfully, a MCA_OPEN_IND_EVT
+**                  is reported. This data channel is identified as tMCA_DL.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern tMCA_RESULT MCA_CreateMdlRsp(tMCA_CL mcl, tMCA_DEP dep,
+                                    uint16_t mdl_id, uint8_t cfg, uint8_t rsp_code,
+                                    const tMCA_CHNL_CFG *p_chnl_cfg);
+
+/*******************************************************************************
+**
+** Function         MCA_CloseReq
+**
+** Description      Close a data channel.  When the channel is closed, an
+**                  MCA_CLOSE_CFM_EVT is sent to the application via the
+**                  control callback function for this handle.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern tMCA_RESULT MCA_CloseReq(tMCA_DL mdl);
+
+/*******************************************************************************
+**
+** Function         MCA_ReconnectMdl
+**
+** Description      This function sends a RECONNECT_MDL request to the peer device.
+**                  When the response is received, a MCA_RECONNECT_CFM_EVT is reported.
+**                  If the response is successful, a data channel is open.
+**                  When the data channel is open successfully, a MCA_OPEN_CFM_EVT
+**                  is reported.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern tMCA_RESULT MCA_ReconnectMdl(tMCA_CL mcl, tMCA_DEP dep, uint16_t data_psm,
+                                    uint16_t mdl_id, const tMCA_CHNL_CFG *p_chnl_cfg);
+
+/*******************************************************************************
+**
+** Function         MCA_ReconnectMdlRsp
+**
+** Description      This function sends a RECONNECT_MDL response to the peer device
+**                  in response to a MCA_RECONNECT_IND_EVT event.
+**                  If the response is successful, a data channel is open.
+**                  When the data channel is open successfully, a MCA_OPEN_IND_EVT
+**                  is reported.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern tMCA_RESULT MCA_ReconnectMdlRsp(tMCA_CL mcl, tMCA_DEP dep,
+                                       uint16_t mdl_id, uint8_t rsp_code,
+                                       const tMCA_CHNL_CFG *p_chnl_cfg);
+
+/*******************************************************************************
+**
+** Function         MCA_DataChnlCfg
+**
+** Description      This function initiates a data channel connection toward the
+**                  connected peer device.
+**                  When the data channel is open successfully, a MCA_OPEN_CFM_EVT
+**                  is reported. This data channel is identified as tMCA_DL.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern tMCA_RESULT MCA_DataChnlCfg(tMCA_CL mcl, const tMCA_CHNL_CFG *p_chnl_cfg);
+
+/*******************************************************************************
+**
+** Function         MCA_Abort
+**
+** Description      This function sends a ABORT_MDL request to the peer device.
+**                  When the response is received, a MCA_ABORT_CFM_EVT is reported.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern tMCA_RESULT MCA_Abort(tMCA_CL mcl);
+
+/*******************************************************************************
+**
+** Function         MCA_Delete
+**
+** Description      This function sends a DELETE_MDL request to the peer device.
+**                  When the response is received, a MCA_DELETE_CFM_EVT is reported.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern tMCA_RESULT MCA_Delete(tMCA_CL mcl, uint16_t mdl_id);
+
+/*******************************************************************************
+**
+** Function         MCA_WriteReq
+**
+** Description      Send a data packet to the peer device.
+**
+**                  The application passes the packet using the BT_HDR structure.
+**                  The offset field must be equal to or greater than L2CAP_MIN_OFFSET.
+**                  This allows enough space in the buffer for the L2CAP header.
+**
+**                  The memory pointed to by p_pkt must be a GKI buffer
+**                  allocated by the application.  This buffer will be freed
+**                  by the protocol stack; the application must not free
+**                  this buffer.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern tMCA_RESULT MCA_WriteReq(tMCA_DL mdl, BT_HDR *p_pkt);
+
+/*******************************************************************************
+**
+** Function         MCA_GetL2CapChannel
+**
+** Description      Get the L2CAP CID used by the given data channel handle.
+**
+** Returns          L2CAP channel ID if successful, otherwise 0.
+**
+*******************************************************************************/
+extern uint16_t MCA_GetL2CapChannel (tMCA_DL mdl);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MCA_API_H */
diff --git a/bt/stack/include/mca_defs.h b/bt/stack/include/mca_defs.h
new file mode 100644
index 0000000..cca7fe0
--- /dev/null
+++ b/bt/stack/include/mca_defs.h
@@ -0,0 +1,87 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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 contains constants definitions and other information from the MCAP
+ *  specification.
+ *
+ ******************************************************************************/
+#ifndef MCA_DEFS_H
+#define MCA_DEFS_H
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+#define MCA_MIN_MTU                 48
+
+/* standard op codes */
+#define MCA_OP_ERROR_RSP            0x00   /* invalid opcode response */
+#define MCA_OP_MDL_CREATE_REQ       0x01   /* create an MDL, wait for an associated data channel connection */
+#define MCA_OP_MDL_CREATE_RSP       0x02   /* response to above request */
+#define MCA_OP_MDL_RECONNECT_REQ    0x03   /* req to prepare to rvc a data channel conn associated with a prev MDL */
+#define MCA_OP_MDL_RECONNECT_RSP    0x04   /* response to above request */
+#define MCA_OP_MDL_ABORT_REQ        0x05   /* stop waiting for a data channel connection */
+#define MCA_OP_MDL_ABORT_RSP        0x06   /* response to above request */
+#define MCA_OP_MDL_DELETE_REQ       0x07   /* delete an MDL */
+#define MCA_OP_MDL_DELETE_RSP       0x08   /* response to above request */
+#define MCA_NUM_STANDARD_OPCODE     (1+MCA_OP_MDL_DELETE_RSP)
+
+/* clock synchronization op codes */
+#define MCA_OP_SYNC_CAP_REQ         0x11   /* request sync capabilities & requirements */
+#define MCA_OP_SYNC_CAP_RSP         0x12   /* indicate completion */
+#define MCA_OP_SYNC_SET_REQ         0x13   /* request to set the time-stamp clock */
+#define MCA_OP_SYNC_SET_RSP         0x14   /* indicate completion */
+#define MCA_OP_SYNC_INFO_IND        0x15   /* update of the actual time-stamp clock instant from the sync slave */
+
+#define MCA_FIRST_SYNC_OP          MCA_OP_SYNC_CAP_REQ
+#define MCA_LAST_SYNC_OP           MCA_OP_SYNC_INFO_IND
+
+/* response code */
+#define MCA_RSP_SUCCESS     0x00    /* The corresponding request was received and processed successfully. */
+#define MCA_RSP_BAD_OPCODE  0x01    /* The Op Code received is not valid (i.e. neither a Standard Op Code nor a Clock Synchronization Protocol Op Code). */
+#define MCA_RSP_BAD_PARAM   0x02    /* One or more of the values in the received request is invalid. */
+/* MCA_RSP_BAD_PARAM shall be used when:
+- The request length is invalid
+- Some of the parameters have invalid values and none of the other defined Response Codes are more appropriate.
+*/
+#define MCA_RSP_BAD_MDEP    0x03    /* The MDEP ID referenced does not exist on this device. */
+#define MCA_RSP_MDEP_BUSY   0x04    /* The requested MDEP currently has as many active MDLs as it can manage simultaneously. */
+#define MCA_RSP_BAD_MDL     0x05    /* The MDL ID referenced is invalid. */
+/* MCA_RSP_BAD_MDL shall be used when:
+- A reserved or invalid value for MDL ID was used.
+- The MDL ID referenced is not available (was never created, has been deleted, or was otherwise lost),
+- The MDL ID referenced in the Abort request is not the same value that was used to initiate the PENDING state
+*/
+#define MCA_RSP_MDL_BUSY    0x06    /* The device is temporarily unable to complete the request. This is intended for reasons not related to the physical sensor (e.g. communication resources unavailable). */
+#define MCA_RSP_BAD_OP      0x07    /* The received request is invalid in the current state. */
+/* MCA_RSP_BAD_OP is used when
+- Abort request was received while not in the PENDING state.
+- Create, Reconnect, or Delete request was received while in the PENDING state.
+- A response is received when a request is expected
+*/
+#define MCA_RSP_NO_RESOURCE 0x08    /* The device is temporarily unable to complete the request. This is intended for reasons relating to the physical sensor (e.g. hardware fault, low battery), or when processing resources are temporarily committed to other processes. */
+#define MCA_RSP_ERROR       0x09    /* An internal error other than those listed in this table was encountered while processing the request. */
+#define MCA_RSP_NO_SUPPORT  0x0A    /* The Op Code that was used in this request is not supported. */
+#define MCA_RSP_CFG_REJ     0x0B    /* A configuration required by a MD_CREATE_MDL or MD_RECONNECT_MDL operation has been rejected. */
+
+#define MCA_MAX_MDEP_ID     0x7F    /* the valid range for MDEP ID is 1-0x7F */
+#define MCA_IS_VALID_MDL_ID(xxx)    (((xxx)>0) && ((xxx)<=0xFEFF))
+#define MCA_ALL_MDL_ID      0xFFFF
+
+#endif /* MCA_DEFS_H */
diff --git a/bt/stack/include/pan_api.h b/bt/stack/include/pan_api.h
new file mode 100644
index 0000000..a7c7b53
--- /dev/null
+++ b/bt/stack/include/pan_api.h
@@ -0,0 +1,459 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2001-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 PAN API definitions
+ *
+ ******************************************************************************/
+#ifndef PAN_API_H
+#define PAN_API_H
+
+#include "bnep_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+/* Define the minimum offset needed in a GKI buffer for
+** sending PAN packets. Note, we are currently not sending
+** extension headers, but may in the future, so allow
+** space for them
+*/
+#define PAN_MINIMUM_OFFSET          BNEP_MINIMUM_OFFSET
+
+
+/*
+** The handle is passed from BNEP to PAN. The same handle is used
+** between PAN and application as well
+*/
+#define PAN_INVALID_HANDLE          BNEP_INVALID_HANDLE
+
+/* Bit map for PAN roles */
+#define PAN_ROLE_CLIENT         0x01     /* PANU role */
+#define PAN_ROLE_GN_SERVER      0x02     /* GN role */
+#define PAN_ROLE_NAP_SERVER     0x04     /* NAP role */
+
+/* Bitmap to indicate the usage of the Data */
+#define PAN_DATA_TO_HOST        0x01
+#define PAN_DATA_TO_LAN         0x02
+
+
+/*****************************************************************************
+**  Type Definitions
+*****************************************************************************/
+
+/* Define the result codes from PAN */
+enum
+{
+    PAN_SUCCESS,                                                /* Success                           */
+    PAN_DISCONNECTED            = BNEP_CONN_DISCONNECTED,       /* Connection terminated   */
+    PAN_CONN_FAILED             = BNEP_CONN_FAILED,             /* Connection failed                 */
+    PAN_NO_RESOURCES            = BNEP_NO_RESOURCES,            /* No resources                      */
+    PAN_MTU_EXCEDED             = BNEP_MTU_EXCEDED,             /* Attempt to write long data        */
+    PAN_INVALID_OFFSET          = BNEP_INVALID_OFFSET,          /* Insufficient offset in GKI buffer */
+    PAN_CONN_FAILED_CFG         = BNEP_CONN_FAILED_CFG,         /* Connection failed cos of config   */
+    PAN_INVALID_SRC_ROLE        = BNEP_CONN_FAILED_SRC_UUID,    /* Connection failed wrong source UUID   */
+    PAN_INVALID_DST_ROLE        = BNEP_CONN_FAILED_DST_UUID,    /* Connection failed wrong destination UUID   */
+    PAN_CONN_FAILED_UUID_SIZE   = BNEP_CONN_FAILED_UUID_SIZE,   /* Connection failed wrong size UUID   */
+    PAN_Q_SIZE_EXCEEDED         = BNEP_Q_SIZE_EXCEEDED,         /* Too many buffers to dest          */
+    PAN_TOO_MANY_FILTERS        = BNEP_TOO_MANY_FILTERS,        /* Too many local filters specified  */
+    PAN_SET_FILTER_FAIL         = BNEP_SET_FILTER_FAIL,         /* Set Filter failed  */
+    PAN_WRONG_HANDLE            = BNEP_WRONG_HANDLE,            /* Wrong handle for the connection  */
+    PAN_WRONG_STATE             = BNEP_WRONG_STATE,             /* Connection is in wrong state */
+    PAN_SECURITY_FAIL           = BNEP_SECURITY_FAIL,           /* Failed because of security */
+    PAN_IGNORE_CMD              = BNEP_IGNORE_CMD,              /* To ignore the rcvd command */
+    PAN_TX_FLOW_ON              = BNEP_TX_FLOW_ON,              /* tx data flow enabled */
+    PAN_TX_FLOW_OFF	            = BNEP_TX_FLOW_OFF,             /* tx data flow disabled */
+    PAN_FAILURE                                                 /* Failure                      */
+
+};
+typedef uint8_t tPAN_RESULT;
+
+
+/*****************************************************************
+**       Callback Function Prototypes
+*****************************************************************/
+
+/* This is call back function used to report connection status
+**      to the application. The second parameter true means
+**      to create the bridge and false means to remove it.
+*/
+typedef void (tPAN_CONN_STATE_CB) (uint16_t handle, BD_ADDR bd_addr, tPAN_RESULT state, bool    is_role_change,
+                                        uint8_t src_role, uint8_t dst_role);
+
+
+/* This is call back function used to create bridge for the
+**      Connected device. The parameter "state" indicates
+**      whether to create the bridge or remove it. true means
+**      to create the bridge and false means to remove it.
+*/
+typedef void (tPAN_BRIDGE_REQ_CB) (BD_ADDR bd_addr, bool    state);
+
+
+/* Data received indication callback prototype. Parameters are
+**              Source BD/Ethernet Address
+**              Dest BD/Ethernet address
+**              Protocol
+**              Address of buffer (or data if non-GKI)
+**              Length of data (non-GKI)
+**              ext is flag to indicate whether it has aby extension headers
+**              Flag used to indicate to forward on LAN
+**                      false - Use it for internal stack
+**                      true  - Send it across the ethernet as well
+*/
+typedef void (tPAN_DATA_IND_CB) (uint16_t handle,
+                                 BD_ADDR src,
+                                 BD_ADDR dst,
+                                 uint16_t protocol,
+                                 uint8_t *p_data,
+                                 uint16_t len,
+                                 bool    ext,
+                                 bool    forward);
+
+
+/* Data buffer received indication callback prototype. Parameters are
+**              Source BD/Ethernet Address
+**              Dest BD/Ethernet address
+**              Protocol
+**              pointer to the data buffer
+**              ext is flag to indicate whether it has aby extension headers
+**              Flag used to indicate to forward on LAN
+**                      false - Use it for internal stack
+**                      true  - Send it across the ethernet as well
+*/
+typedef void (tPAN_DATA_BUF_IND_CB) (uint16_t handle,
+                                     BD_ADDR src,
+                                     BD_ADDR dst,
+                                     uint16_t protocol,
+                                     BT_HDR *p_buf,
+                                     bool    ext,
+                                     bool    forward);
+
+
+/* Flow control callback for TX data. Parameters are
+**              Handle to the connection
+**              Event  flow status
+*/
+typedef void (tPAN_TX_DATA_FLOW_CB) (uint16_t handle,
+                                     tPAN_RESULT  event);
+
+/* Filters received indication callback prototype. Parameters are
+**              Handle to the connection
+**              true if the cb is called for indication
+**              Ignore this if it is indication, otherwise it is the result
+**                      for the filter set operation performed by the local
+**                      device
+**              Number of protocol filters present
+**              Pointer to the filters start. Filters are present in pairs
+**                      of start of the range and end of the range.
+**                      They will be present in big endian order. First
+**                      two bytes will be starting of the first range and
+**                      next two bytes will be ending of the range.
+*/
+typedef void (tPAN_FILTER_IND_CB) (uint16_t handle,
+                                   bool    indication,
+                                   tBNEP_RESULT result,
+                                   uint16_t num_filters,
+                                   uint8_t *p_filters);
+
+
+
+/* Multicast Filters received indication callback prototype. Parameters are
+**              Handle to the connection
+**              true if the cb is called for indication
+**              Ignore this if it is indication, otherwise it is the result
+**                      for the filter set operation performed by the local
+**                      device
+**              Number of multicast filters present
+**              Pointer to the filters start. Filters are present in pairs
+**                      of start of the range and end of the range.
+**                      First six bytes will be starting of the first range and
+**                      next six bytes will be ending of the range.
+*/
+typedef void (tPAN_MFILTER_IND_CB) (uint16_t handle,
+                                    bool    indication,
+                                    tBNEP_RESULT result,
+                                    uint16_t num_mfilters,
+                                    uint8_t *p_mfilters);
+
+
+
+
+/* This structure is used to register with PAN profile
+** It is passed as a parameter to PAN_Register call.
+*/
+typedef struct
+{
+    tPAN_CONN_STATE_CB          *pan_conn_state_cb;     /* Connection state callback */
+    tPAN_BRIDGE_REQ_CB          *pan_bridge_req_cb;     /* Bridge request callback */
+    tPAN_DATA_IND_CB            *pan_data_ind_cb;       /* Data indication callback */
+    tPAN_DATA_BUF_IND_CB        *pan_data_buf_ind_cb;   /* Data buffer indication callback */
+    tPAN_FILTER_IND_CB          *pan_pfilt_ind_cb;      /* protocol filter indication callback */
+    tPAN_MFILTER_IND_CB         *pan_mfilt_ind_cb;      /* multicast filter indication callback */
+    tPAN_TX_DATA_FLOW_CB        *pan_tx_data_flow_cb;   /* data flow callback */
+    char                        *user_service_name;     /* Service name for PANU role */
+    char                        *gn_service_name;       /* Service name for GN role */
+    char                        *nap_service_name;      /* Service name for NAP role */
+
+} tPAN_REGISTER;
+
+
+/*****************************************************************************
+**  External Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function         PAN_Register
+**
+** Description      This function is called by the application to register
+**                  its callbacks with PAN profile. The application then
+**                  should set the PAN role explicitly.
+**
+** Parameters:      p_register - contains all callback function pointers
+**
+**
+** Returns          none
+**
+*******************************************************************************/
+extern void PAN_Register (tPAN_REGISTER *p_register);
+
+
+/*******************************************************************************
+**
+** Function         PAN_Deregister
+**
+** Description      This function is called by the application to de-register
+**                  its callbacks with PAN profile. This will make the PAN to
+**                  become inactive. This will deregister PAN services from SDP
+**                  and close all active connections
+**
+** Returns          none
+**
+*******************************************************************************/
+extern void PAN_Deregister (void);
+
+/*******************************************************************************
+**
+** Function         PAN_SetRole
+**
+** Description      This function is called by the application to set the PAN
+**                  profile role. This should be called after PAN_Register.
+**                  This can be called any time to change the PAN role
+**
+** Parameters:      role        - is bit map of roles to be active
+**                                      PAN_ROLE_CLIENT is for PANU role
+**                                      PAN_ROLE_GN_SERVER is for GN role
+**                                      PAN_ROLE_NAP_SERVER is for NAP role
+**                  sec_mask    - Security mask for different roles
+**                                      It is array of uint8_t. The byte represent the
+**                                      security for roles PANU, GN and NAP in order
+**                  p_user_name - Service name for PANU role
+**                  p_gn_name   - Service name for GN role
+**                  p_nap_name  - Service name for NAP role
+**                                      Can be NULL if user wants it to be default
+**
+** Returns          PAN_SUCCESS     - if the role is set successfully
+**                  PAN_FAILURE     - if the role is not valid
+**
+*******************************************************************************/
+extern tPAN_RESULT PAN_SetRole (uint8_t role,
+                                uint8_t *sec_mask,
+                                const char *p_user_name,
+                                const char *p_gn_name,
+                                const char *p_nap_name);
+
+/*******************************************************************************
+**
+** Function         PAN_Connect
+**
+** Description      This function is called by the application to initiate a
+**                  connection to the remote device
+**
+** Parameters:      rem_bda     - BD Addr of the remote device
+**                  src_role    - Role of the local device for the connection
+**                  dst_role    - Role of the remote device for the connection
+**                                      PAN_ROLE_CLIENT is for PANU role
+**                                      PAN_ROLE_GN_SERVER is for GN role
+**                                      PAN_ROLE_NAP_SERVER is for NAP role
+**                  *handle     - Pointer for returning Handle to the connection
+**
+** Returns          PAN_SUCCESS      - if the connection is initiated successfully
+**                  PAN_NO_RESOURCES - resources are not sufficent
+**                  PAN_FAILURE      - if the connection cannot be initiated
+**                                           this can be because of the combination of
+**                                           src and dst roles may not be valid or
+**                                           allowed at that point of time
+**
+*******************************************************************************/
+extern tPAN_RESULT PAN_Connect (BD_ADDR rem_bda, uint8_t src_role, uint8_t dst_role, uint16_t *handle);
+
+/*******************************************************************************
+**
+** Function         PAN_Disconnect
+**
+** Description      This is used to disconnect the connection
+**
+** Parameters:      handle           - handle for the connection
+**
+** Returns          PAN_SUCCESS      - if the connection is closed successfully
+**                  PAN_FAILURE      - if the connection is not found or
+**                                           there is an error in disconnecting
+**
+*******************************************************************************/
+extern tPAN_RESULT PAN_Disconnect (uint16_t handle);
+
+/*******************************************************************************
+**
+** Function         PAN_Write
+**
+** Description      This sends data over the PAN connections. If this is called
+**                  on GN or NAP side and the packet is multicast or broadcast
+**                  it will be sent on all the links. Otherwise the correct link
+**                  is found based on the destination address and forwarded on it
+**                  If the return value is not PAN_SUCCESS the application should
+**                  take care of releasing the message buffer
+**
+** Parameters:      dst      - MAC or BD Addr of the destination device
+**                  src      - MAC or BD Addr of the source who sent this packet
+**                  protocol - protocol of the ethernet packet like IP or ARP
+**                  p_data   - pointer to the data
+**                  len      - length of the data
+**                  ext      - to indicate that extension headers present
+**
+** Returns          PAN_SUCCESS       - if the data is sent successfully
+**                  PAN_FAILURE       - if the connection is not found or
+**                                           there is an error in sending data
+**
+*******************************************************************************/
+extern tPAN_RESULT PAN_Write (uint16_t handle,
+                              BD_ADDR dst,
+                              BD_ADDR src,
+                              uint16_t protocol,
+                              uint8_t *p_data,
+                              uint16_t len,
+                              bool    ext);
+
+/*******************************************************************************
+**
+** Function         PAN_WriteBuf
+**
+** Description      This sends data over the PAN connections. If this is called
+**                  on GN or NAP side and the packet is multicast or broadcast
+**                  it will be sent on all the links. Otherwise the correct link
+**                  is found based on the destination address and forwarded on it
+**                  If the return value is not PAN_SUCCESS the application should
+**                  take care of releasing the message buffer
+**
+** Parameters:      dst      - MAC or BD Addr of the destination device
+**                  src      - MAC or BD Addr of the source who sent this packet
+**                  protocol - protocol of the ethernet packet like IP or ARP
+**                  p_buf    - pointer to the data buffer
+**                  ext      - to indicate that extension headers present
+**
+** Returns          PAN_SUCCESS       - if the data is sent successfully
+**                  PAN_FAILURE       - if the connection is not found or
+**                                           there is an error in sending data
+**
+*******************************************************************************/
+extern tPAN_RESULT PAN_WriteBuf (uint16_t handle,
+                                 BD_ADDR dst,
+                                 BD_ADDR src,
+                                 uint16_t protocol,
+                                 BT_HDR *p_buf,
+                                 bool    ext);
+
+/*******************************************************************************
+**
+** Function         PAN_SetProtocolFilters
+**
+** Description      This function is used to set protocol filters on the peer
+**
+** Parameters:      handle      - handle for the connection
+**                  num_filters - number of protocol filter ranges
+**                  start       - array of starting protocol numbers
+**                  end         - array of ending protocol numbers
+**
+**
+** Returns          PAN_SUCCESS        if protocol filters are set successfully
+**                  PAN_FAILURE        if connection not found or error in setting
+**
+*******************************************************************************/
+extern tPAN_RESULT PAN_SetProtocolFilters (uint16_t handle,
+                                           uint16_t num_filters,
+                                           uint16_t *p_start_array,
+                                           uint16_t *p_end_array);
+
+/*******************************************************************************
+**
+** Function         PAN_SetMulticastFilters
+**
+** Description      This function is used to set multicast filters on the peer
+**
+** Parameters:      handle      - handle for the connection
+**                  num_filters - number of multicast filter ranges
+**                  p_start_array - Pointer to sequence of beginings of all
+**                                         multicast address ranges
+**                  p_end_array   - Pointer to sequence of ends of all
+**                                         multicast address ranges
+**
+**
+** Returns          PAN_SUCCESS        if multicast filters are set successfully
+**                  PAN_FAILURE        if connection not found or error in setting
+**
+*******************************************************************************/
+extern tBNEP_RESULT PAN_SetMulticastFilters (uint16_t handle,
+                                             uint16_t num_mcast_filters,
+                                             uint8_t *p_start_array,
+                                             uint8_t *p_end_array);
+
+/*******************************************************************************
+**
+** Function         PAN_SetTraceLevel
+**
+** Description      This function sets the trace level for PAN. If called with
+**                  a value of 0xFF, it simply reads the current trace level.
+**
+** Returns          the new (current) trace level
+**
+*******************************************************************************/
+extern uint8_t PAN_SetTraceLevel (uint8_t new_level);
+
+/*******************************************************************************
+**
+** Function         PAN_Init
+**
+** Description      This function initializes the PAN unit. It should be called
+**                  before accessing any other APIs to initialize the control
+**                  block.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void PAN_Init (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* PAN_API_H */
diff --git a/bt/stack/include/port_api.h b/bt/stack/include/port_api.h
new file mode 100644
index 0000000..88dd162
--- /dev/null
+++ b/bt/stack/include/port_api.h
@@ -0,0 +1,673 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 PORT API definitions
+ *
+ ******************************************************************************/
+#ifndef PORT_API_H
+#define PORT_API_H
+
+#include "bt_target.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+**  Constants and Types
+*****************************************************************************/
+
+/*
+** Define port settings structure send from the application in the
+** set settings request, or to the application in the set settings indication.
+*/
+typedef struct
+{
+
+#define PORT_BAUD_RATE_2400       0x00
+#define PORT_BAUD_RATE_4800       0x01
+#define PORT_BAUD_RATE_7200       0x02
+#define PORT_BAUD_RATE_9600       0x03
+#define PORT_BAUD_RATE_19200      0x04
+#define PORT_BAUD_RATE_38400      0x05
+#define PORT_BAUD_RATE_57600      0x06
+#define PORT_BAUD_RATE_115200     0x07
+#define PORT_BAUD_RATE_230400     0x08
+
+    uint8_t baud_rate;
+
+#define PORT_5_BITS               0x00
+#define PORT_6_BITS               0x01
+#define PORT_7_BITS               0x02
+#define PORT_8_BITS               0x03
+
+    uint8_t byte_size;
+
+#define PORT_ONESTOPBIT           0x00
+#define PORT_ONE5STOPBITS         0x01
+    uint8_t stop_bits;
+
+#define PORT_PARITY_NO            0x00
+#define PORT_PARITY_YES           0x01
+    uint8_t parity;
+
+#define PORT_ODD_PARITY           0x00
+#define PORT_EVEN_PARITY          0x01
+#define PORT_MARK_PARITY          0x02
+#define PORT_SPACE_PARITY         0x03
+
+    uint8_t parity_type;
+
+#define PORT_FC_OFF               0x00
+#define PORT_FC_XONXOFF_ON_INPUT  0x01
+#define PORT_FC_XONXOFF_ON_OUTPUT 0x02
+#define PORT_FC_CTS_ON_INPUT      0x04
+#define PORT_FC_CTS_ON_OUTPUT     0x08
+#define PORT_FC_DSR_ON_INPUT      0x10
+#define PORT_FC_DSR_ON_OUTPUT     0x20
+
+    uint8_t fc_type;
+
+    uint8_t rx_char1;
+
+#define PORT_XON_DC1              0x11
+    uint8_t xon_char;
+
+#define PORT_XOFF_DC3             0x13
+    uint8_t xoff_char;
+
+} tPORT_STATE;
+
+
+/*
+** Define the callback function prototypes.  Parameters are specific
+** to each event and are described bellow
+*/
+typedef int  (tPORT_DATA_CALLBACK) (uint16_t port_handle, void *p_data, uint16_t len);
+
+#define DATA_CO_CALLBACK_TYPE_INCOMING          1
+#define DATA_CO_CALLBACK_TYPE_OUTGOING_SIZE     2
+#define DATA_CO_CALLBACK_TYPE_OUTGOING          3
+typedef int  (tPORT_DATA_CO_CALLBACK) (uint16_t port_handle, uint8_t* p_buf, uint16_t len, int type);
+
+typedef void (tPORT_CALLBACK) (uint32_t code, uint16_t port_handle);
+
+/*
+** Define events that registered application can receive in the callback
+*/
+
+#define PORT_EV_RXCHAR  0x00000001   /* Any Character received */
+#define PORT_EV_RXFLAG  0x00000002   /* Received certain character */
+#define PORT_EV_TXEMPTY 0x00000004   /* Transmitt Queue Empty */
+#define PORT_EV_CTS     0x00000008   /* CTS changed state */
+#define PORT_EV_DSR     0x00000010   /* DSR changed state */
+#define PORT_EV_RLSD    0x00000020   /* RLSD changed state */
+#define PORT_EV_BREAK   0x00000040   /* BREAK received */
+#define PORT_EV_ERR     0x00000080   /* Line status error occurred */
+#define PORT_EV_RING    0x00000100   /* Ring signal detected */
+#define PORT_EV_CTSS    0x00000400   /* CTS state */
+#define PORT_EV_DSRS    0x00000800   /* DSR state */
+#define PORT_EV_RLSDS   0x00001000   /* RLSD state */
+#define PORT_EV_OVERRUN 0x00002000   /* receiver buffer overrun */
+#define PORT_EV_TXCHAR  0x00004000   /* Any character transmitted */
+
+#define PORT_EV_CONNECTED    0x00000200  /* RFCOMM connection established */
+#define PORT_EV_CONNECT_ERR  0x00008000  /* Was not able to establish connection */
+                                     /* or disconnected */
+#define PORT_EV_FC      0x00010000   /* data flow enabled flag changed by remote */
+#define PORT_EV_FCS     0x00020000   /* data flow enable status true = enabled */
+
+/*
+** To register for events application should provide bitmask with
+** corresponding bit set
+*/
+
+#define PORT_MASK_ALL             (PORT_EV_RXCHAR | PORT_EV_TXEMPTY | PORT_EV_CTS | \
+                                   PORT_EV_DSR | PORT_EV_RLSD | PORT_EV_BREAK | \
+                                   PORT_EV_ERR | PORT_EV_RING | PORT_EV_CONNECT_ERR | \
+                                   PORT_EV_DSRS | PORT_EV_CTSS | PORT_EV_RLSDS | \
+                                   PORT_EV_RXFLAG | PORT_EV_TXCHAR | PORT_EV_OVERRUN | \
+                                   PORT_EV_FC | PORT_EV_FCS | PORT_EV_CONNECTED)
+
+
+/*
+** Define port result codes
+*/
+#define PORT_SUCCESS                0
+
+#define PORT_ERR_BASE               0
+
+#define PORT_UNKNOWN_ERROR          (PORT_ERR_BASE + 1)
+#define PORT_ALREADY_OPENED         (PORT_ERR_BASE + 2)
+#define PORT_CMD_PENDING            (PORT_ERR_BASE + 3)
+#define PORT_APP_NOT_REGISTERED     (PORT_ERR_BASE + 4)
+#define PORT_NO_MEM                 (PORT_ERR_BASE + 5)
+#define PORT_NO_RESOURCES           (PORT_ERR_BASE + 6)
+#define PORT_BAD_BD_ADDR            (PORT_ERR_BASE + 7)
+#define PORT_BAD_HANDLE             (PORT_ERR_BASE + 9)
+#define PORT_NOT_OPENED             (PORT_ERR_BASE + 10)
+#define PORT_LINE_ERR               (PORT_ERR_BASE + 11)
+#define PORT_START_FAILED           (PORT_ERR_BASE + 12)
+#define PORT_PAR_NEG_FAILED         (PORT_ERR_BASE + 13)
+#define PORT_PORT_NEG_FAILED        (PORT_ERR_BASE + 14)
+#define PORT_SEC_FAILED             (PORT_ERR_BASE + 15)
+#define PORT_PEER_CONNECTION_FAILED (PORT_ERR_BASE + 16)
+#define PORT_PEER_FAILED            (PORT_ERR_BASE + 17)
+#define PORT_PEER_TIMEOUT           (PORT_ERR_BASE + 18)
+#define PORT_CLOSED                 (PORT_ERR_BASE + 19)
+#define PORT_TX_FULL                (PORT_ERR_BASE + 20)
+#define PORT_LOCAL_CLOSED           (PORT_ERR_BASE + 21)
+#define PORT_LOCAL_TIMEOUT          (PORT_ERR_BASE + 22)
+#define PORT_TX_QUEUE_DISABLED      (PORT_ERR_BASE + 23)
+#define PORT_PAGE_TIMEOUT           (PORT_ERR_BASE + 24)
+#define PORT_INVALID_SCN            (PORT_ERR_BASE + 25)
+
+#define PORT_ERR_MAX                (PORT_ERR_BASE + 26)
+
+/*****************************************************************************
+**  External Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function         RFCOMM_CreateConnection
+**
+** Description      RFCOMM_CreateConnection function is used from the application
+**                  to establish serial port connection to the peer device,
+**                  or allow RFCOMM to accept a connection from the peer
+**                  application.
+**
+** Parameters:      scn          - Service Channel Number as registered with
+**                                 the SDP (server) or obtained using SDP from
+**                                 the peer device (client).
+**                  is_server    - true if requesting application is a server
+**                  mtu          - Maximum frame size the application can accept
+**                  bd_addr      - BD_ADDR of the peer (client)
+**                  mask         - specifies events to be enabled.  A value
+**                                 of zero disables all events.
+**                  p_handle     - OUT pointer to the handle.
+**                  p_mgmt_cb    - pointer to callback function to receive
+**                                 connection up/down events.
+** Notes:
+**
+** Server can call this function with the same scn parameter multiple times if
+** it is ready to accept multiple simulteneous connections.
+**
+** DLCI for the connection is (scn * 2 + 1) if client originates connection on
+** existing none initiator multiplexer channel.  Otherwise it is (scn * 2).
+** For the server DLCI can be changed later if client will be calling it using
+** (scn * 2 + 1) dlci.
+**
+*******************************************************************************/
+extern int RFCOMM_CreateConnection (uint16_t uuid, uint8_t scn,
+                                            bool    is_server, uint16_t mtu,
+                                            BD_ADDR bd_addr, uint16_t *p_handle,
+                                            tPORT_CALLBACK *p_mgmt_cb);
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_RemoveConnection
+**
+** Description      This function is called to close the specified connection.
+**
+** Parameters:      handle     - Handle of the port returned in the Open
+**
+*******************************************************************************/
+extern int RFCOMM_RemoveConnection (uint16_t handle);
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_RemoveServer
+**
+** Description      This function is called to close the server port.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**
+*******************************************************************************/
+extern int RFCOMM_RemoveServer (uint16_t handle);
+
+
+/*******************************************************************************
+**
+** Function         PORT_SetEventCallback
+**
+** Description      Set event callback the specified connection.
+**
+** Parameters:      handle       - Handle of the port returned in the Open
+**                  p_callback   - address of the callback function which should
+**                                 be called from the RFCOMM when an event
+**                                 specified in the mask occurs.
+**
+*******************************************************************************/
+extern int PORT_SetEventCallback (uint16_t port_handle,
+                                  tPORT_CALLBACK *p_port_cb);
+
+/*******************************************************************************
+**
+** Function         PORT_ClearKeepHandleFlag
+**
+** Description      This function is called to clear the keep handle flag
+**                  which will cause not to keep the port handle open when closed
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**
+*******************************************************************************/
+int PORT_ClearKeepHandleFlag (uint16_t port_handle);
+
+/*******************************************************************************
+**
+** Function         PORT_SetEventCallback
+**
+** Description      Set event data callback the specified connection.
+**
+** Parameters:      handle       - Handle of the port returned in the Open
+**                  p_callback   - address of the callback function which should
+**                                 be called from the RFCOMM when a data
+**                                 packet is received.
+**
+*******************************************************************************/
+extern int PORT_SetDataCallback (uint16_t port_handle,
+                                 tPORT_DATA_CALLBACK *p_cb);
+
+extern int PORT_SetDataCOCallback (uint16_t port_handle, tPORT_DATA_CO_CALLBACK *p_port_cb);
+/*******************************************************************************
+**
+** Function         PORT_SetEventMask
+**
+** Description      This function is called to close the specified connection.
+**
+** Parameters:      handle - Handle of the port returned in the Open
+**                  mask   - specifies events to be enabled.  A value
+**                           of zero disables all events.
+**
+*******************************************************************************/
+extern int PORT_SetEventMask (uint16_t port_handle, uint32_t mask);
+
+
+/*******************************************************************************
+**
+** Function         PORT_CheckConnection
+**
+** Description      This function returns PORT_SUCCESS if connection referenced
+**                  by handle is up and running
+**
+** Parameters:      handle     - Handle of the port returned in the Open
+**                  bd_addr    - OUT bd_addr of the peer
+**                  p_lcid     - OUT L2CAP's LCID
+**
+*******************************************************************************/
+extern int PORT_CheckConnection (uint16_t handle, BD_ADDR bd_addr,
+                                 uint16_t *p_lcid);
+
+/*******************************************************************************
+**
+** Function         PORT_IsOpening
+**
+** Description      This function returns true if there is any RFCOMM connection
+**                  opening in process.
+**
+** Parameters:      true if any connection opening is found
+**                  bd_addr    - bd_addr of the peer
+**
+*******************************************************************************/
+extern bool    PORT_IsOpening (BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function         PORT_SetState
+**
+** Description      This function configures connection according to the
+**                  specifications in the tPORT_STATE structure.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  p_settings - Pointer to a tPORT_STATE structure containing
+**                               configuration information for the connection.
+**
+*******************************************************************************/
+extern int PORT_SetState (uint16_t handle, tPORT_STATE *p_settings);
+
+/*******************************************************************************
+**
+** Function         PORT_GetRxQueueCnt
+**
+** Description      This function return number of buffers on the rx queue.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  p_rx_queue_count - Pointer to return queue count in.
+**
+*******************************************************************************/
+extern int PORT_GetRxQueueCnt (uint16_t handle, uint16_t *p_rx_queue_count);
+
+/*******************************************************************************
+**
+** Function         PORT_GetState
+**
+** Description      This function is called to fill tPORT_STATE structure
+**                  with the current control settings for the port
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  p_settings - Pointer to a tPORT_STATE structure in which
+**                               configuration information is returned.
+**
+*******************************************************************************/
+extern int PORT_GetState (uint16_t handle, tPORT_STATE *p_settings);
+
+
+/*******************************************************************************
+**
+** Function         PORT_Control
+**
+** Description      This function directs a specified connection to pass control
+**                  control information to the peer device.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  signal     - specify the function to be passed
+**
+*******************************************************************************/
+#define PORT_SET_DTRDSR         0x01
+#define PORT_CLR_DTRDSR         0x02
+#define PORT_SET_CTSRTS         0x03
+#define PORT_CLR_CTSRTS         0x04
+#define PORT_SET_RI             0x05        /* DCE only */
+#define PORT_CLR_RI             0x06        /* DCE only */
+#define PORT_SET_DCD            0x07        /* DCE only */
+#define PORT_CLR_DCD            0x08        /* DCE only */
+#define PORT_BREAK              0x09        /* Break event */
+
+extern int PORT_Control (uint16_t handle, uint8_t signal);
+
+
+/*******************************************************************************
+**
+** Function         PORT_FlowControl
+**
+** Description      This function directs a specified connection to pass
+**                  flow control message to the peer device.  Enable flag passed
+**                  shows if port can accept more data.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  enable     - enables data flow
+**
+*******************************************************************************/
+extern int PORT_FlowControl (uint16_t handle, bool    enable);
+
+/*******************************************************************************
+**
+** Function         PORT_FlowControl_MaxCredit
+**
+** Description      This function directs a specified connection to pass
+**                  flow control message to the peer device.  Enable flag passed
+**                  shows if port can accept more data. It also sends max credit
+**                  when data flow enabled
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  enable     - enables data flow
+**
+*******************************************************************************/
+extern int PORT_FlowControl_MaxCredit(uint16_t handle, bool enable);
+
+/*******************************************************************************
+**
+** Function         PORT_GetModemStatus
+**
+** Description      This function retrieves modem control signals.  Normally
+**                  application will call this function after a callback
+**                  function is called with notification that one of signals
+**                  has been changed.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                               callback.
+**                  p_signal   - specify the pointer to control signals info
+**
+*******************************************************************************/
+#define PORT_DTRDSR_ON          0x01
+#define PORT_CTSRTS_ON          0x02
+#define PORT_RING_ON            0x04
+#define PORT_DCD_ON             0x08
+
+/*
+** Define default initial local modem signals state set after connection established
+*/
+#define PORT_OBEX_DEFAULT_SIGNAL_STATE  (PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON)
+#define PORT_SPP_DEFAULT_SIGNAL_STATE   (PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON)
+#define PORT_PPP_DEFAULT_SIGNAL_STATE   (PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON)
+#define PORT_DUN_DEFAULT_SIGNAL_STATE   (PORT_DTRDSR_ON | PORT_CTSRTS_ON)
+
+extern int PORT_GetModemStatus (uint16_t handle, uint8_t *p_control_signal);
+
+
+/*******************************************************************************
+**
+** Function         PORT_ClearError
+**
+** Description      This function retreives information about a communications
+**                  error and reports current status of a connection.  The
+**                  function should be called when an error occures to clear
+**                  the connection error flag and to enable additional read
+**                  and write operations.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  p_errors   - pointer of the variable to receive error codes
+**                  p_status   - pointer to the tPORT_STATUS structur to receive
+**                               connection status
+**
+*******************************************************************************/
+
+#define PORT_ERR_BREAK      0x01    /* Break condition occured on the peer device */
+#define PORT_ERR_OVERRUN    0x02    /* Overrun is reported by peer device */
+#define PORT_ERR_FRAME      0x04    /* Framing error reported by peer device */
+#define PORT_ERR_RXOVER     0x08    /* Input queue overflow occured */
+#define PORT_ERR_TXFULL     0x10    /* Output queue overflow occured */
+
+typedef struct
+{
+#define PORT_FLAG_CTS_HOLD  0x01    /* Tx is waiting for CTS signal */
+#define PORT_FLAG_DSR_HOLD  0x02    /* Tx is waiting for DSR signal */
+#define PORT_FLAG_RLSD_HOLD 0x04    /* Tx is waiting for RLSD signal */
+
+    uint16_t flags;
+    uint16_t in_queue_size;          /* Number of bytes in the input queue */
+    uint16_t out_queue_size;         /* Number of bytes in the output queue */
+    uint16_t mtu_size;               /* peer MTU size */
+} tPORT_STATUS;
+
+
+extern int PORT_ClearError (uint16_t handle, uint16_t *p_errors,
+                            tPORT_STATUS *p_status);
+
+
+/*******************************************************************************
+**
+** Function         PORT_SendError
+**
+** Description      This function send a communications error to the peer device
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  errors     - receive error codes
+**
+*******************************************************************************/
+extern int PORT_SendError (uint16_t handle, uint8_t errors);
+
+
+/*******************************************************************************
+**
+** Function         PORT_GetQueueStatus
+**
+** Description      This function reports current status of a connection.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  p_status   - pointer to the tPORT_STATUS structur to receive
+**                               connection status
+**
+*******************************************************************************/
+extern int PORT_GetQueueStatus (uint16_t handle, tPORT_STATUS *p_status);
+
+
+/*******************************************************************************
+**
+** Function         PORT_Purge
+**
+** Description      This function discards all the data from the output or
+**                  input queues of the specified connection.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  purge_flags - specify the action to take.
+**
+*******************************************************************************/
+#define PORT_PURGE_TXCLEAR  0x01
+#define PORT_PURGE_RXCLEAR  0x02
+
+extern int PORT_Purge (uint16_t handle, uint8_t purge_flags);
+
+
+/*******************************************************************************
+**
+** Function         PORT_Read
+**
+** Description      This function returns the pointer to the buffer received
+**                  from the peer device.  Normally application will call this
+**                  function after receiving PORT_EVT_RXCHAR event.
+**                  Application calling this function is responsible to free
+**                  buffer returned.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                                callback.
+**                  pp_buf      - pointer to address of buffer with data,
+**
+*******************************************************************************/
+extern int PORT_Read (uint16_t handle, BT_HDR **pp_buf);
+
+
+/*******************************************************************************
+**
+** Function         PORT_ReadData
+**
+** Description      Normally application will call this function after receiving
+**                  PORT_EVT_RXCHAR event.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                                callback.
+**                  p_data      - Data area
+**                  max_len     - Byte count requested
+**                  p_len       - Byte count received
+**
+*******************************************************************************/
+extern int PORT_ReadData (uint16_t handle, char *p_data, uint16_t max_len,
+                          uint16_t *p_len);
+
+
+/*******************************************************************************
+**
+** Function         PORT_Write
+**
+** Description      This function to send BT buffer to the peer device.
+**                  Application should not free the buffer.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  p_buf       - pointer to the buffer with data,
+**
+*******************************************************************************/
+extern int PORT_Write (uint16_t handle, BT_HDR *p_buf);
+
+
+/*******************************************************************************
+**
+** Function         PORT_WriteData
+**
+** Description      This function is called from the legacy application to
+**                  send data.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  p_data      - Data area
+**                  max_len     - Byte count to write
+**                  p_len       - Bytes written
+**
+*******************************************************************************/
+extern int PORT_WriteData (uint16_t handle, const char *p_data,
+                           uint16_t max_len, uint16_t *p_len);
+
+/*******************************************************************************
+**
+** Function         PORT_WriteDataCO
+**
+** Description      Normally not GKI aware application will call this function
+**                  to send data to the port by callout functions.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**
+*******************************************************************************/
+extern int PORT_WriteDataCO (uint16_t handle, int* p_len);
+
+/*******************************************************************************
+**
+** Function         PORT_Test
+**
+** Description      Application can call this function to send RFCOMM Test frame
+**
+** Parameters:      handle      - Handle returned in the RFCOMM_CreateConnection
+**                  p_data      - Data area
+**                  max_len     - Byte count requested
+**
+*******************************************************************************/
+extern int PORT_Test (uint16_t handle, uint8_t *p_data, uint16_t len);
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_Init
+**
+** Description      This function is called to initialize RFCOMM layer
+**
+*******************************************************************************/
+extern void RFCOMM_Init (void);
+
+
+/*******************************************************************************
+**
+** Function         PORT_SetTraceLevel
+**
+** Description      This function sets the trace level for RFCOMM. If called with
+**                  a value of 0xFF, it simply reads the current trace level.
+**
+** Returns          the new (current) trace level
+**
+*******************************************************************************/
+extern uint8_t PORT_SetTraceLevel (uint8_t new_level);
+
+
+/*******************************************************************************
+**
+** Function         PORT_GetResultString
+**
+** Description      This function returns the human-readable string for a given
+**                  result code.
+**
+** Returns          a pointer to the human-readable string for the given
+**                  result. Note that the string returned must not be freed.
+**
+*******************************************************************************/
+extern const char *PORT_GetResultString (const uint8_t result_code);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* PORT_API_H */
diff --git a/bt/stack/include/port_ext.h b/bt/stack/include/port_ext.h
new file mode 100644
index 0000000..b940e4e
--- /dev/null
+++ b/bt/stack/include/port_ext.h
@@ -0,0 +1,32 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 external definitions of Port Emulation entity unit
+ *
+ ******************************************************************************/
+
+#ifndef PORTEXT_H
+#define PORTEXT_H
+
+#include "bt_common.h"
+
+extern void rfcomm_port_timer_timeout(void *data);
+extern void rfcomm_mcb_timer_timeout(void *data);
+#endif
diff --git a/bt/stack/include/profiles_api.h b/bt/stack/include/profiles_api.h
new file mode 100644
index 0000000..bb8a6ec
--- /dev/null
+++ b/bt/stack/include/profiles_api.h
@@ -0,0 +1,71 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-2013 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.
+ *
+ ******************************************************************************/
+
+#ifndef PROFILES_API_H
+#define PROFILES_API_H
+
+#include "bt_target.h"
+#include "btm_api.h"
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+#define BT_PASS         0   /* Used for general successful function returns */
+
+/*** Port entity passes back 8 bit errors; will use upper byte offset ***/
+#define PORT_ERR_GRP    0x0000          /* base offset for port entity */
+#define GAP_ERR_GRP     0x0100          /* base offset for GAP profile */
+#define SPP_ERR_GRP     0x0200          /* base offset for serial port profile */
+#define HCRP_ERR_GRP    0x0300          /* base offset for HCRP */
+#define HCRPM_ERR_GRP   0x0400          /* base offset for HCRPM */
+
+/* #define HSP2_ERR_GRP 0x0F00 */
+
+/* security level definitions (tBT_SECURITY) */
+#define BT_USE_DEF_SECURITY         0
+#define BT_SEC_MODE_NONE            BTM_SEC_MODE_NONE
+#define BT_SEC_MODE_SERVICE         BTM_SEC_MODE_SERVICE
+#define BT_SEC_MODE_LINK            BTM_SEC_MODE_LINK
+
+/* security mask definitions (tBT_SECURITY) */
+/* The following definitions are OR'd together to form the security requirements */
+#define BT_SEC_IN_AUTHORIZE         BTM_SEC_IN_AUTHORIZE         /* Inbound call requires authorization */
+#define BT_SEC_IN_AUTHENTICATE      BTM_SEC_IN_AUTHENTICATE      /* Inbound call requires authentication */
+#define BT_SEC_IN_ENCRYPT           BTM_SEC_IN_ENCRYPT           /* Inbound call requires encryption */
+#define BT_SEC_OUT_AUTHORIZE        BTM_SEC_OUT_AUTHORIZE        /* Outbound call requires authorization */
+#define BT_SEC_OUT_AUTHENTICATE     BTM_SEC_OUT_AUTHENTICATE     /* Outbound call requires authentication */
+#define BT_SEC_OUT_ENCRYPT          BTM_SEC_OUT_ENCRYPT          /* Outbound call requires encryption */
+
+
+/*****************************************************************************
+**  Type Definitions
+*****************************************************************************/
+
+/*
+** Security Definitions
+**      This following definitions are used to indicate the security
+**      requirements for a service.
+*/
+typedef struct
+{
+    uint8_t level;
+    uint8_t mask;
+} tBT_SECURITY;
+
+#endif  /* PROFILES_API_H */
+
diff --git a/bt/stack/include/rfcdefs.h b/bt/stack/include/rfcdefs.h
new file mode 100644
index 0000000..d23b76c
--- /dev/null
+++ b/bt/stack/include/rfcdefs.h
@@ -0,0 +1,248 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 definitions for the RFCOMM protocol
+ *
+ ****************************************************************************/
+
+#ifndef RFCDEFS_H
+#define RFCDEFS_H
+
+#define PORT_MAX_RFC_PORTS              31
+
+/*
+**  If nothing is negotiated MTU should be 127
+*/
+#define RFCOMM_DEFAULT_MTU              127
+
+/*
+** Define used by RFCOMM TS frame types
+*/
+#define RFCOMM_SABME                    0x2F
+#define RFCOMM_UA                       0x63
+#define RFCOMM_DM                       0x0F
+#define RFCOMM_DISC                     0x43
+#define RFCOMM_UIH                      0xEF
+
+/*
+** Defenitions for the TS control frames
+*/
+#define RFCOMM_CTRL_FRAME_LEN           3
+#define RFCOMM_MIN_OFFSET               5 /* ctrl 2 , len 1 or 2 bytes, credit 1 byte */
+#define RFCOMM_DATA_OVERHEAD            (RFCOMM_MIN_OFFSET + 1)  /* add 1 for checksum */
+
+#define RFCOMM_EA                       1
+#define RFCOMM_EA_MASK                  0x01
+#define RFCOMM_CR_MASK                  0x02
+#define RFCOMM_SHIFT_CR                 1
+#define RFCOMM_SHIFT_DLCI               2
+#define RFCOMM_SHIFT_DLCI2              6
+#define RFCOMM_PF                       0x10
+#define RFCOMM_PF_MASK                  0x10
+#define RFCOMM_PF_OFFSET                4
+#define RFCOMM_SHIFT_LENGTH1            1
+#define RFCOMM_SHIFT_LENGTH2            7
+#define RFCOMM_SHIFT_MX_CTRL_TYPE       2
+
+#define RFCOMM_INITIATOR_CMD            1
+#define RFCOMM_INITIATOR_RSP            0
+#define RFCOMM_RESPONDER_CMD            0
+#define RFCOMM_RESPONDER_RSP            1
+
+#define RFCOMM_PARSE_CTRL_FIELD(ea, cr, dlci, p_data)       \
+{                                                           \
+    (ea) = *(p_data) & RFCOMM_EA;                           \
+    (cr) = (*(p_data) & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR; \
+    (dlci) = *(p_data)++ >> RFCOMM_SHIFT_DLCI;              \
+    if (!(ea)) (dlci) += *(p_data)++ << RFCOMM_SHIFT_DLCI2; \
+}
+
+#define RFCOMM_FORMAT_CTRL_FIELD(p_data, ea, cr, dlci) \
+    (*(p_data)++ = (ea) | (cr) | ((dlci) << RFCOMM_SHIFT_DLCI))
+
+#define RFCOMM_PARSE_TYPE_FIELD(type, pf, p_data)               \
+{                                                               \
+    (type) = *(p_data) & ~RFCOMM_PF_MASK;                       \
+    (pf)   = (*(p_data)++ & RFCOMM_PF_MASK) >> RFCOMM_PF_OFFSET;\
+}
+
+#define RFCOMM_FORMAT_TYPE_FIELD(p_data, type, pf)                    \
+    *(p_data)++ = ((type) | ((pf) << RFCOMM_PF_OFFSET))               \
+{                                                                     \
+    (type) = *(p_data) & ~RFCOMM_PF_MASK;                             \
+    (pf)   = (*(p_data)++ & RFCOMM_PF_MASK) >> RFCOMM_PF_OFFSET;      \
+}
+
+#define RFCOMM_PARSE_LEN_FIELD(ea, length, p_data)                \
+{                                                                 \
+    (ea) = (*(p_data) & RFCOMM_EA);                               \
+    (length) = (*(p_data)++ >> RFCOMM_SHIFT_LENGTH1);             \
+    if (!(ea)) (length) += (*(p_data)++ << RFCOMM_SHIFT_LENGTH2); \
+}
+
+#define RFCOMM_FRAME_IS_CMD(initiator, cr)                  \
+    (( (initiator) && !(cr)) || (!(initiator) &&  (cr)))
+
+#define RFCOMM_FRAME_IS_RSP(initiator, cr)                  \
+    (( (initiator) &&  (cr)) || (!(initiator) && !(cr)))
+
+#define RFCOMM_CR(initiator, is_command)                    \
+    (( ( (initiator) &&  (is_command))                      \
+    || (!(initiator) && !(is_command))) << 1)
+
+#define RFCOMM_I_CR(is_command) ((is_command) ? 0x02 : 0x00)
+
+#define RFCOMM_MAX_DLCI             61
+
+#define RFCOMM_VALID_DLCI(dlci)                             \
+    (((dlci) == 0) || (((dlci) >= 2) && ((dlci) <= RFCOMM_MAX_DLCI)))
+
+
+/* Port Negotiation (PN) */
+#define RFCOMM_PN_DLCI_MASK         0x3F
+
+#define RFCOMM_PN_FRAM_TYPE_UIH     0x00
+#define RFCOMM_PN_FRAME_TYPE_MASK   0x0F
+
+#define RFCOMM_PN_CONV_LAYER_MASK   0xF0
+#define RFCOMM_PN_CONV_LAYER_TYPE_1 0
+#define RFCOMM_PN_CONV_LAYER_CBFC_I 0xF0
+#define RFCOMM_PN_CONV_LAYER_CBFC_R 0xE0
+
+#define RFCOMM_PN_PRIORITY_MASK     0x3F
+#define RFCOMM_PN_PRIORITY_0        0
+
+#define RFCOMM_PN_K_MASK            0x07
+
+#define RFCOMM_T1_DSEC              0 /* None negotiable in RFCOMM */
+#define RFCOMM_N2                   0 /* Number of retransmissions */
+#define RFCOMM_K                    0 /* Window size */
+#define RFCOMM_K_MAX                7 /* Max value of K for credit based flow control */
+
+#define RFCOMM_MSC_FC               0x02          /* Flow control*/
+#define RFCOMM_MSC_RTC              0x04          /* Ready to communicate*/
+#define RFCOMM_MSC_RTR              0x08          /* Ready to receive*/
+#define RFCOMM_MSC_IC               0x40          /* Incomming call indicator*/
+#define RFCOMM_MSC_DV               0x80          /* Data Valid*/
+
+#define RFCOMM_MSC_SHIFT_BREAK          4
+#define RFCOMM_MSC_BREAK_MASK           0xF0
+#define RFCOMM_MSC_BREAK_PRESENT_MASK   0x02
+
+#define RFCOMM_BAUD_RATE_2400           0x00
+#define RFCOMM_BAUD_RATE_4800           0x01
+#define RFCOMM_BAUD_RATE_7200           0x02
+#define RFCOMM_BAUD_RATE_9600           0x03
+#define RFCOMM_BAUD_RATE_19200          0x04
+#define RFCOMM_BAUD_RATE_38400          0x05
+#define RFCOMM_BAUD_RATE_57600          0x06
+#define RFCOMM_BAUD_RATE_115200         0x07
+#define RFCOMM_BAUD_RATE_230400         0x08
+
+#define RFCOMM_5_BITS                   0x00
+#define RFCOMM_6_BITS                   0x01
+#define RFCOMM_7_BITS                   0x02
+#define RFCOMM_8_BITS                   0x03
+
+#define RFCOMM_RPN_BITS_MASK            0x03
+#define RFCOMM_RPN_BITS_SHIFT           0
+
+#define RFCOMM_ONESTOPBIT               0x00
+#define RFCOMM_ONE5STOPBITS             0x01
+
+#define RFCOMM_RPN_STOP_BITS_MASK       0x01
+#define RFCOMM_RPN_STOP_BITS_SHIFT      2
+
+#define RFCOMM_PARITY_NO                0x00
+#define RFCOMM_PARITY_YES               0x01
+#define RFCOMM_RPN_PARITY_MASK          0x01
+#define RFCOMM_RPN_PARITY_SHIFT         3
+
+#define RFCOMM_ODD_PARITY               0x00
+#define RFCOMM_EVEN_PARITY              0x01
+#define RFCOMM_MARK_PARITY              0x02
+#define RFCOMM_SPACE_PARITY             0x03
+
+#define RFCOMM_RPN_PARITY_TYPE_MASK     0x03
+#define RFCOMM_RPN_PARITY_TYPE_SHIFT    4
+
+#define RFCOMM_FC_OFF                   0x00
+#define RFCOMM_FC_XONXOFF_ON_INPUT      0x01
+#define RFCOMM_FC_XONXOFF_ON_OUTPUT     0x02
+#define RFCOMM_FC_RTR_ON_INPUT          0x04
+#define RFCOMM_FC_RTR_ON_OUTPUT         0x08
+#define RFCOMM_FC_RTC_ON_INPUT          0x10
+#define RFCOMM_FC_RTC_ON_OUTPUT         0x20
+#define RFCOMM_FC_MASK                  0x3F
+
+#define RFCOMM_RPN_PM_BIT_RATE          0x0001
+#define RFCOMM_RPN_PM_DATA_BITS         0x0002
+#define RFCOMM_RPN_PM_STOP_BITS         0x0004
+#define RFCOMM_RPN_PM_PARITY            0x0008
+#define RFCOMM_RPN_PM_PARITY_TYPE       0x0010
+#define RFCOMM_RPN_PM_XON_CHAR          0x0020
+#define RFCOMM_RPN_PM_XOFF_CHAR         0x0040
+#define RFCOMM_RPN_PM_XONXOFF_ON_INPUT  0x0100
+#define RFCOMM_RPN_PM_XONXOFF_ON_OUTPUT 0x0200
+#define RFCOMM_RPN_PM_RTR_ON_INPUT      0x0400
+#define RFCOMM_RPN_PM_RTR_ON_OUTPUT     0x0800
+#define RFCOMM_RPN_PM_RTC_ON_INPUT      0x1000
+#define RFCOMM_RPN_PM_RTC_ON_OUTPUT     0x2000
+#define RFCOMM_RPN_PM_MASK              0x3F7F
+
+#define RFCOMM_RLS_ERROR                0x01
+#define RFCOMM_RLS_OVERRUN              0x02
+#define RFCOMM_RLS_PARITY               0x04
+#define RFCOMM_RLS_FRAMING              0x08
+
+/* Multiplexor channel uses DLCI 0 */
+#define RFCOMM_MX_DLCI                  0
+
+/*
+** Define RFCOMM Multiplexer message types
+*/
+#define RFCOMM_MX_PN                    0x80
+#define RFCOMM_MX_PN_LEN                8
+
+#define RFCOMM_MX_CLD                   0xC0
+#define RFCOMM_MX_CLD_LEN               0
+
+#define RFCOMM_MX_TEST                  0x20
+
+#define RFCOMM_MX_FCON                  0xA0
+#define RFCOMM_MX_FCON_LEN              0
+
+#define RFCOMM_MX_FCOFF                 0x60
+#define RFCOMM_MX_FCOFF_LEN             0
+
+#define RFCOMM_MX_MSC                   0xE0
+#define RFCOMM_MX_MSC_LEN_NO_BREAK      2
+#define RFCOMM_MX_MSC_LEN_WITH_BREAK    3
+
+#define RFCOMM_MX_NSC                   0x10
+#define RFCOMM_MX_NSC_LEN               1
+
+#define RFCOMM_MX_RPN                   0x90
+#define RFCOMM_MX_RPN_REQ_LEN           1
+#define RFCOMM_MX_RPN_LEN               8
+
+#define RFCOMM_MX_RLS                   0x50
+#define RFCOMM_MX_RLS_LEN               2
+#endif
diff --git a/bt/stack/include/sdp_api.h b/bt/stack/include/sdp_api.h
new file mode 100644
index 0000000..f58d834
--- /dev/null
+++ b/bt/stack/include/sdp_api.h
@@ -0,0 +1,692 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+#ifndef SDP_API_H
+#define SDP_API_H
+
+#include "bt_target.h"
+#include "sdpdefs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+**  Constants
+*****************************************************************************/
+
+/* Success code and error codes */
+#define  SDP_SUCCESS                        0x0000
+#define  SDP_INVALID_VERSION                0x0001
+#define  SDP_INVALID_SERV_REC_HDL           0x0002
+#define  SDP_INVALID_REQ_SYNTAX             0x0003
+#define  SDP_INVALID_PDU_SIZE               0x0004
+#define  SDP_INVALID_CONT_STATE             0x0005
+#define  SDP_NO_RESOURCES                   0x0006
+#define  SDP_DI_REG_FAILED                  0x0007
+#define  SDP_DI_DISC_FAILED                 0x0008
+#define  SDP_NO_DI_RECORD_FOUND             0x0009
+#define  SDP_ERR_ATTR_NOT_PRESENT           0x000A
+#define  SDP_ILLEGAL_PARAMETER              0x000B
+
+#define  SDP_NO_RECS_MATCH                  0xFFF0
+#define  SDP_CONN_FAILED                    0xFFF1
+#define  SDP_CFG_FAILED                     0xFFF2
+#define  SDP_GENERIC_ERROR                  0xFFF3
+#define  SDP_DB_FULL                        0xFFF4
+#define  SDP_INVALID_PDU                    0xFFF5
+#define  SDP_SECURITY_ERR                   0xFFF6
+#define  SDP_CONN_REJECTED                  0xFFF7
+#define  SDP_CANCEL                         0xFFF8
+
+/* Define the PSM that SDP uses */
+#define SDP_PSM     0x0001
+
+/* Legacy #define to avoid code changes - SDP UUID is same as BT UUID */
+#define tSDP_UUID   tBT_UUID
+
+/* Masks for attr_value field of tSDP_DISC_ATTR */
+#define SDP_DISC_ATTR_LEN_MASK          0x0FFF
+#define SDP_DISC_ATTR_TYPE(len_type)    ((len_type) >> 12)
+#define SDP_DISC_ATTR_LEN(len_type)     ((len_type) & SDP_DISC_ATTR_LEN_MASK)
+
+/* Maximum number of protocol list items (list_elem in tSDP_PROTOCOL_ELEM) */
+#define SDP_MAX_LIST_ELEMS      3
+
+
+/*****************************************************************************
+**  Type Definitions
+*****************************************************************************/
+
+/* Define a callback function for when discovery is complete. */
+typedef void (tSDP_DISC_CMPL_CB) (uint16_t result);
+typedef void (tSDP_DISC_CMPL_CB2) (uint16_t result, void* user_data);
+
+typedef struct
+{
+    BD_ADDR         peer_addr;
+    uint16_t        peer_mtu;
+} tSDP_DR_OPEN;
+
+typedef struct
+{
+    uint8_t         *p_data;
+    uint16_t        data_len;
+} tSDP_DR_DATA;
+
+typedef union
+{
+    tSDP_DR_OPEN    open;
+    tSDP_DR_DATA    data;
+} tSDP_DATA;
+
+/* Define a callback function for when discovery result is received. */
+typedef void (tSDP_DISC_RES_CB) (uint16_t event, tSDP_DATA *p_data);
+
+/* Define a structure to hold the discovered service information. */
+typedef struct
+{
+    union
+    {
+        uint8_t     u8;                         /* 8-bit integer            */
+        uint16_t    u16;                        /* 16-bit integer           */
+        uint32_t    u32;                        /* 32-bit integer           */
+        uint8_t     array[4];                   /* Variable length field    */
+        struct t_sdp_disc_attr *p_sub_attr;     /* Addr of first sub-attr (list)*/
+    } v;
+
+} tSDP_DISC_ATVAL;
+
+typedef struct t_sdp_disc_attr
+{
+    struct t_sdp_disc_attr *p_next_attr;        /* Addr of next linked attr     */
+    uint16_t                attr_id;            /* Attribute ID                 */
+    uint16_t                attr_len_type;      /* Length and type fields       */
+    tSDP_DISC_ATVAL         attr_value;         /* Variable length entry data   */
+} tSDP_DISC_ATTR;
+
+typedef struct t_sdp_disc_rec
+{
+    tSDP_DISC_ATTR          *p_first_attr;      /* First attribute of record    */
+    struct t_sdp_disc_rec   *p_next_rec;        /* Addr of next linked record   */
+    uint32_t                time_read;          /* The time the record was read */
+    BD_ADDR                 remote_bd_addr;     /* Remote BD address            */
+} tSDP_DISC_REC;
+
+typedef struct
+{
+    uint32_t        mem_size;                   /* Memory size of the DB        */
+    uint32_t        mem_free;                   /* Memory still available       */
+    tSDP_DISC_REC   *p_first_rec;               /* Addr of first record in DB   */
+    uint16_t        num_uuid_filters;           /* Number of UUIds to filter    */
+    tSDP_UUID       uuid_filters[SDP_MAX_UUID_FILTERS]; /* UUIDs to filter      */
+    uint16_t        num_attr_filters;           /* Number of attribute filters  */
+    uint16_t        attr_filters[SDP_MAX_ATTR_FILTERS]; /* Attributes to filter */
+    uint8_t         *p_free_mem;                /* Pointer to free memory       */
+#if (SDP_RAW_DATA_INCLUDED == TRUE)
+    uint8_t         *raw_data;                  /* Received record from server. allocated/released by client  */
+    uint32_t        raw_size;                   /* size of raw_data */
+    uint32_t        raw_used;                   /* length of raw_data used */
+#endif
+}tSDP_DISCOVERY_DB;
+
+/* This structure is used to add protocol lists and find protocol elements */
+typedef struct
+{
+    uint16_t    protocol_uuid;
+    uint16_t    num_params;
+    uint16_t    params[SDP_MAX_PROTOCOL_PARAMS];
+} tSDP_PROTOCOL_ELEM;
+
+typedef struct
+{
+    uint16_t            num_elems;
+    tSDP_PROTOCOL_ELEM  list_elem[SDP_MAX_LIST_ELEMS];
+} tSDP_PROTO_LIST_ELEM;
+
+/* Device Identification (DI) data structure
+*/
+/* Used to set the DI record */
+typedef struct t_sdp_di_record
+{
+    uint16_t     vendor;
+    uint16_t     vendor_id_source;
+    uint16_t     product;
+    uint16_t     version;
+    bool         primary_record;
+    char         client_executable_url[SDP_MAX_ATTR_LEN];   /* optional */
+    char         service_description[SDP_MAX_ATTR_LEN];     /* optional */
+    char         documentation_url[SDP_MAX_ATTR_LEN];       /* optional */
+}tSDP_DI_RECORD;
+
+/* Used to get the DI record */
+typedef struct t_sdp_di_get_record
+{
+    uint16_t        spec_id;
+    tSDP_DI_RECORD  rec;
+}tSDP_DI_GET_RECORD;
+
+/* API into the SDP layer for service discovery. */
+
+/*******************************************************************************
+**
+** Function         SDP_InitDiscoveryDb
+**
+** Description      This function is called to initialize a discovery database.
+**
+** Returns          true if successful, false if one or more parameters are bad
+**
+*******************************************************************************/
+bool    SDP_InitDiscoveryDb (tSDP_DISCOVERY_DB *p_db, uint32_t len,
+                                    uint16_t num_uuid,
+                                    tSDP_UUID *p_uuid_list,
+                                    uint16_t num_attr,
+                                    uint16_t *p_attr_list);
+
+/*******************************************************************************
+**
+** Function         SDP_CancelServiceSearch
+**
+** Description      This function cancels an active query to an SDP server.
+**
+** Returns          true if discovery cancelled, false if a matching activity is not found.
+**
+*******************************************************************************/
+bool    SDP_CancelServiceSearch (tSDP_DISCOVERY_DB *p_db);
+
+/*******************************************************************************
+**
+** Function         SDP_ServiceSearchRequest
+**
+** Description      This function queries an SDP server for information.
+**
+** Returns          true if discovery started, false if failed.
+**
+*******************************************************************************/
+bool    SDP_ServiceSearchRequest (uint8_t *p_bd_addr,
+                                         tSDP_DISCOVERY_DB *p_db,
+                                         tSDP_DISC_CMPL_CB *p_cb);
+
+
+/*******************************************************************************
+**
+** Function         SDP_ServiceSearchAttributeRequest
+**
+** Description      This function queries an SDP server for information.
+**
+**                  The difference between this API function and the function
+**                  SDP_ServiceSearchRequest is that this one does a
+**                  combined ServiceSearchAttributeRequest SDP function.
+**
+** Returns          true if discovery started, false if failed.
+**
+*******************************************************************************/
+bool    SDP_ServiceSearchAttributeRequest (uint8_t *p_bd_addr,
+                                                  tSDP_DISCOVERY_DB *p_db,
+                                                  tSDP_DISC_CMPL_CB *p_cb);
+
+/*******************************************************************************
+**
+** Function         SDP_ServiceSearchAttributeRequest2
+**
+** Description      This function queries an SDP server for information.
+**
+**                  The difference between this API function and the function
+**                  SDP_ServiceSearchRequest is that this one does a
+**                  combined ServiceSearchAttributeRequest SDP function with the
+**                  user data piggyback
+**
+** Returns          true if discovery started, false if failed.
+**
+*******************************************************************************/
+bool    SDP_ServiceSearchAttributeRequest2 (uint8_t *p_bd_addr,
+                                                   tSDP_DISCOVERY_DB *p_db,
+                                                   tSDP_DISC_CMPL_CB2 *p_cb, void * user_data);
+
+/* API of utilities to find data in the local discovery database */
+
+/*******************************************************************************
+**
+** Function         SDP_FindAttributeInDb
+**
+** Description      This function queries an SDP database for a specific attribute.
+**                  If the p_start_rec pointer is NULL, it looks from the beginning
+**                  of the database, else it continues from the next record after
+**                  p_start_rec.
+**
+** Returns          Pointer to matching record, or NULL
+**
+*******************************************************************************/
+tSDP_DISC_REC *SDP_FindAttributeInDb (tSDP_DISCOVERY_DB *p_db,
+                                             uint16_t attr_id,
+                                             tSDP_DISC_REC *p_start_rec);
+
+
+/*******************************************************************************
+**
+** Function         SDP_FindAttributeInRec
+**
+** Description      This function searches an SDP discovery record for a
+**                  specific attribute.
+**
+** Returns          Pointer to matching attribute entry, or NULL
+**
+*******************************************************************************/
+tSDP_DISC_ATTR *SDP_FindAttributeInRec (tSDP_DISC_REC *p_rec,
+                                               uint16_t attr_id);
+
+
+/*******************************************************************************
+**
+** Function         SDP_FindServiceInDb
+**
+** Description      This function queries an SDP database for a specific service.
+**                  If the p_start_rec pointer is NULL, it looks from the beginning
+**                  of the database, else it continues from the next record after
+**                  p_start_rec.
+**
+** Returns          Pointer to record containing service class, or NULL
+**
+*******************************************************************************/
+tSDP_DISC_REC *SDP_FindServiceInDb (tSDP_DISCOVERY_DB *p_db,
+                                           uint16_t service_uuid,
+                                           tSDP_DISC_REC *p_start_rec);
+
+
+/*******************************************************************************
+**
+** Function         SDP_FindServiceUUIDInDb
+**
+** Description      This function queries an SDP database for a specific service.
+**                  If the p_start_rec pointer is NULL, it looks from the beginning
+**                  of the database, else it continues from the next record after
+**                  p_start_rec.
+**
+** NOTE             the only difference between this function and the previous
+**                  function "SDP_FindServiceInDb()" is that this function takes
+**                  a tBT_UUID input.
+**
+** Returns          Pointer to record containing service class, or NULL
+**
+*******************************************************************************/
+tSDP_DISC_REC *SDP_FindServiceUUIDInDb (tSDP_DISCOVERY_DB *p_db,
+                                               tBT_UUID *p_uuid,
+                                               tSDP_DISC_REC *p_start_rec);
+
+/*******************************************************************************
+**
+** Function         SDP_FindServiceUUIDInRec_128bit
+**
+** Description      This function is called to read the 128-bit service UUID within a record
+**                  if there is any.
+**
+** Parameters:      p_rec      - pointer to a SDP record.
+**                  p_uuid     - output parameter to save the UUID found.
+**
+** Returns          true if found, otherwise false.
+**
+*******************************************************************************/
+bool    SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC *p_rec, tBT_UUID * p_uuid);
+
+/*******************************************************************************
+**
+** Function         SDP_FindServiceInDb_128bit
+**
+** Description      This function queries an SDP database for a specific service.
+**                  If the p_start_rec pointer is NULL, it looks from the beginning
+**                  of the database, else it continues from the next record after
+**                  p_start_rec.
+**
+** Returns          Pointer to record containing service class, or NULL
+**
+*******************************************************************************/
+tSDP_DISC_REC *SDP_FindServiceInDb_128bit(tSDP_DISCOVERY_DB *p_db,
+                                                 tSDP_DISC_REC *p_start_rec);
+
+/*******************************************************************************
+**
+** Function         SDP_FindProtocolListElemInRec
+**
+** Description      This function looks at a specific discovery record for a
+**                  protocol list element.
+**
+** Returns          true if found, false if not
+**                  If found, the passed protocol list element is filled in.
+**
+*******************************************************************************/
+bool    SDP_FindProtocolListElemInRec (tSDP_DISC_REC *p_rec,
+                                              uint16_t layer_uuid,
+                                              tSDP_PROTOCOL_ELEM *p_elem);
+
+
+/*******************************************************************************
+**
+** Function         SDP_FindAddProtoListsElemInRec
+**
+** Description      This function looks at a specific discovery record for a
+**                  protocol list element.
+**
+** Returns          true if found, false if not
+**                  If found, the passed protocol list element is filled in.
+**
+*******************************************************************************/
+bool    SDP_FindAddProtoListsElemInRec (tSDP_DISC_REC *p_rec,
+                                               uint16_t layer_uuid,
+                                               tSDP_PROTOCOL_ELEM *p_elem);
+
+
+/*******************************************************************************
+**
+** Function         SDP_FindProfileVersionInRec
+**
+** Description      This function looks at a specific discovery record for the
+**                  Profile list descriptor, and pulls out the version number.
+**                  The version number consists of an 8-bit major version and
+**                  an 8-bit minor version.
+**
+** Returns          true if found, false if not
+**                  If found, the major and minor version numbers that were passed
+**                  in are filled in.
+**
+*******************************************************************************/
+bool    SDP_FindProfileVersionInRec (tSDP_DISC_REC *p_rec,
+                                            uint16_t profile_uuid,
+                                            uint16_t *p_version);
+
+
+/* API into SDP for local service database updates */
+
+/*******************************************************************************
+**
+** Function         SDP_CreateRecord
+**
+** Description      This function is called to create a record in the database.
+**                  This would be through the SDP database maintenance API. The
+**                  record is created empty, teh application should then call
+**                  "add_attribute" to add the record's attributes.
+**
+** Returns          Record handle if OK, else 0.
+**
+*******************************************************************************/
+uint32_t SDP_CreateRecord (void);
+
+
+/*******************************************************************************
+**
+** Function         SDP_DeleteRecord
+**
+** Description      This function is called to add a record (or all records)
+**                  from the database. This would be through the SDP database
+**                  maintenance API.
+**
+**                  If a record handle of 0 is passed, all records are deleted.
+**
+** Returns          true if succeeded, else false
+**
+*******************************************************************************/
+bool    SDP_DeleteRecord (uint32_t handle);
+
+
+/*******************************************************************************
+**
+** Function         SDP_ReadRecord
+**
+** Description      This function is called to get the raw data of the record
+**                  with the given handle from the database.
+**
+** Returns          -1, if the record is not found.
+**                  Otherwise, the offset (0 or 1) to start of data in p_data.
+**
+**                  The size of data copied into p_data is in *p_data_len.
+**
+*******************************************************************************/
+int32_t SDP_ReadRecord(uint32_t handle, uint8_t *p_data, int32_t *p_data_len);
+
+/*******************************************************************************
+**
+** Function         SDP_AddAttribute
+**
+** Description      This function is called to add an attribute to a record.
+**                  This would be through the SDP database maintenance API.
+**                  If the attribute already exists in the record, it is replaced
+**                  with the new value.
+**
+** NOTE             Attribute values must be passed as a Big Endian stream.
+**
+** Returns          true if added OK, else false
+**
+*******************************************************************************/
+bool    SDP_AddAttribute (uint32_t handle, uint16_t attr_id,
+                                 uint8_t attr_type, uint32_t attr_len,
+                                 uint8_t *p_val);
+
+
+/*******************************************************************************
+**
+** Function         SDP_AddSequence
+**
+** Description      This function is called to add a sequence to a record.
+**                  This would be through the SDP database maintenance API.
+**                  If the sequence already exists in the record, it is replaced
+**                  with the new sequence.
+**
+** NOTE             Element values must be passed as a Big Endian stream.
+**
+** Returns          true if added OK, else false
+**
+*******************************************************************************/
+bool    SDP_AddSequence (uint32_t handle,  uint16_t attr_id,
+                                uint16_t num_elem, uint8_t type[],
+                                uint8_t len[], uint8_t *p_val[]);
+
+
+/*******************************************************************************
+**
+** Function         SDP_AddUuidSequence
+**
+** Description      This function is called to add a UUID sequence to a record.
+**                  This would be through the SDP database maintenance API.
+**                  If the sequence already exists in the record, it is replaced
+**                  with the new sequence.
+**
+** Returns          true if added OK, else false
+**
+*******************************************************************************/
+bool    SDP_AddUuidSequence (uint32_t handle,  uint16_t attr_id,
+                                    uint16_t num_uuids, uint16_t *p_uuids);
+
+
+/*******************************************************************************
+**
+** Function         SDP_AddProtocolList
+**
+** Description      This function is called to add a protocol descriptor list to
+**                  a record. This would be through the SDP database maintenance API.
+**                  If the protocol list already exists in the record, it is replaced
+**                  with the new list.
+**
+** Returns          true if added OK, else false
+**
+*******************************************************************************/
+bool    SDP_AddProtocolList (uint32_t handle, uint16_t num_elem,
+                                    tSDP_PROTOCOL_ELEM *p_elem_list);
+
+
+/*******************************************************************************
+**
+** Function         SDP_AddAdditionProtoLists
+**
+** Description      This function is called to add a protocol descriptor list to
+**                  a record. This would be through the SDP database maintenance API.
+**                  If the protocol list already exists in the record, it is replaced
+**                  with the new list.
+**
+** Returns          true if added OK, else false
+**
+*******************************************************************************/
+bool    SDP_AddAdditionProtoLists (uint32_t handle, uint16_t num_elem,
+                                          tSDP_PROTO_LIST_ELEM *p_proto_list);
+
+
+/*******************************************************************************
+**
+** Function         SDP_AddProfileDescriptorList
+**
+** Description      This function is called to add a profile descriptor list to
+**                  a record. This would be through the SDP database maintenance API.
+**                  If the version already exists in the record, it is replaced
+**                  with the new one.
+**
+** Returns          true if added OK, else false
+**
+*******************************************************************************/
+bool    SDP_AddProfileDescriptorList (uint32_t handle,
+                                             uint16_t profile_uuid,
+                                             uint16_t version);
+
+/*******************************************************************************
+**
+** Function         SDP_AddLanguageBaseAttrIDList
+**
+** Description      This function is called to add a language base attr list to
+**                  a record. This would be through the SDP database maintenance API.
+**                  If the version already exists in the record, it is replaced
+**                  with the new one.
+**
+** Returns          true if added OK, else false
+**
+*******************************************************************************/
+bool    SDP_AddLanguageBaseAttrIDList (uint32_t handle,
+                                              uint16_t lang, uint16_t char_enc,
+                                              uint16_t base_id);
+
+/*******************************************************************************
+**
+** Function         SDP_AddServiceClassIdList
+**
+** Description      This function is called to add a service list to a record.
+**                  This would be through the SDP database maintenance API.
+**                  If the service list already exists in the record, it is replaced
+**                  with the new list.
+**
+** Returns          true if added OK, else false
+**
+*******************************************************************************/
+bool    SDP_AddServiceClassIdList (uint32_t handle,
+                                          uint16_t num_services,
+                                          uint16_t *p_service_uuids);
+
+/*******************************************************************************
+**
+** Function         SDP_DeleteAttribute
+**
+** Description      This function is called to delete an attribute from a record.
+**                  This would be through the SDP database maintenance API.
+**
+** Returns          true if deleted OK, else false if not found
+**
+*******************************************************************************/
+bool    SDP_DeleteAttribute (uint32_t handle, uint16_t attr_id);
+
+/* Device Identification APIs */
+
+/*******************************************************************************
+**
+** Function         SDP_SetLocalDiRecord
+**
+** Description      This function adds a DI record to the local SDP database.
+**
+** Returns          Returns SDP_SUCCESS if record added successfully, else error
+**
+*******************************************************************************/
+uint16_t SDP_SetLocalDiRecord (tSDP_DI_RECORD *device_info,
+                                    uint32_t *p_handle);
+
+/*******************************************************************************
+**
+** Function         SDP_DiDiscover
+**
+** Description      This function queries a remote device for DI information.
+**
+** Returns          SDP_SUCCESS if query started successfully, else error
+**
+*******************************************************************************/
+uint16_t SDP_DiDiscover (BD_ADDR remote_device,
+                              tSDP_DISCOVERY_DB *p_db, uint32_t len,
+                              tSDP_DISC_CMPL_CB *p_cb);
+
+/*******************************************************************************
+**
+** Function         SDP_GetNumDiRecords
+**
+** Description      Searches specified database for DI records
+**
+** Returns          number of DI records found
+**
+*******************************************************************************/
+uint8_t SDP_GetNumDiRecords (tSDP_DISCOVERY_DB *p_db);
+
+/*******************************************************************************
+**
+** Function         SDP_GetDiRecord
+**
+** Description      This function retrieves a remote device's DI record from
+**                  the specified database.
+**
+** Returns          SDP_SUCCESS if record retrieved, else error
+**
+*******************************************************************************/
+uint16_t SDP_GetDiRecord (uint8_t getRecordIndex,
+                               tSDP_DI_GET_RECORD *device_info,
+                               tSDP_DISCOVERY_DB *p_db);
+
+/*******************************************************************************
+**
+** Function         SDP_SetTraceLevel
+**
+** Description      This function sets the trace level for SDP. If called with
+**                  a value of 0xFF, it simply reads the current trace level.
+**
+** Returns          the new (current) trace level
+**
+*******************************************************************************/
+uint8_t SDP_SetTraceLevel (uint8_t new_level);
+
+/*******************************************************************************
+**
+** Function         SDP_FindServiceUUIDInRec
+**
+** Description      This function is called to read the service UUID within a record
+**                  if there is any.
+**
+** Parameters:      p_rec      - pointer to a SDP record.
+**
+** Returns          true if found, otherwise false.
+**
+*******************************************************************************/
+bool    SDP_FindServiceUUIDInRec(tSDP_DISC_REC *p_rec, tBT_UUID *p_uuid);
+
+// Converts UUID-16 to UUID-128 by including the base UUID.
+// |uuid16| is the 2-byte UUID to convert.
+// The result with the expanded 128-bit UUID is stored in |p_uuid128|.
+void sdpu_uuid16_to_uuid128(uint16_t uuid16, uint8_t* p_uuid128);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* SDP_API_H */
diff --git a/bt/stack/include/sdpdefs.h b/bt/stack/include/sdpdefs.h
new file mode 100644
index 0000000..07dfa5e
--- /dev/null
+++ b/bt/stack/include/sdpdefs.h
@@ -0,0 +1,330 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 definitions for the SDP API
+ *
+ ******************************************************************************/
+
+#ifndef SDP_DEFS_H
+#define SDP_DEFS_H
+
+/* Define the service attribute IDs.
+*/
+#define  ATTR_ID_SERVICE_RECORD_HDL             0x0000
+#define  ATTR_ID_SERVICE_CLASS_ID_LIST          0x0001
+#define  ATTR_ID_SERVICE_RECORD_STATE           0x0002
+#define  ATTR_ID_SERVICE_ID                     0x0003
+#define  ATTR_ID_PROTOCOL_DESC_LIST             0x0004
+#define  ATTR_ID_BROWSE_GROUP_LIST              0x0005
+#define  ATTR_ID_LANGUAGE_BASE_ATTR_ID_LIST     0x0006
+#define  ATTR_ID_SERVICE_INFO_TIME_TO_LIVE      0x0007
+#define  ATTR_ID_SERVICE_AVAILABILITY           0x0008
+#define  ATTR_ID_BT_PROFILE_DESC_LIST           0x0009
+#define  ATTR_ID_DOCUMENTATION_URL              0x000A
+#define  ATTR_ID_CLIENT_EXE_URL                 0x000B
+#define  ATTR_ID_ICON_URL                       0x000C
+#define  ATTR_ID_ADDITION_PROTO_DESC_LISTS      0x000D
+
+#define  LANGUAGE_BASE_ID                       0x0100
+#define  ATTR_ID_SERVICE_NAME                   (LANGUAGE_BASE_ID + 0x0000)
+#define  ATTR_ID_SERVICE_DESCRIPTION            (LANGUAGE_BASE_ID + 0x0001)
+#define  ATTR_ID_PROVIDER_NAME                  (LANGUAGE_BASE_ID + 0x0002)
+
+/* Device Identification (DI)
+*/
+#define ATTR_ID_SPECIFICATION_ID                0x0200
+#define ATTR_ID_VENDOR_ID                       0x0201
+#define ATTR_ID_PRODUCT_ID                      0x0202
+#define ATTR_ID_PRODUCT_VERSION                 0x0203
+#define ATTR_ID_PRIMARY_RECORD                  0x0204
+#define ATTR_ID_VENDOR_ID_SOURCE                0x0205
+
+#define BLUETOOTH_DI_SPECIFICATION              0x0103  /* 1.3 */
+#define DI_VENDOR_ID_DEFAULT                    0xFFFF
+#define DI_VENDOR_ID_SOURCE_BTSIG               0x0001
+#define DI_VENDOR_ID_SOURCE_USBIF               0x0002
+
+
+#define  ATTR_ID_IP_SUBNET                      0x0200 /* PAN Profile (***) */
+#define  ATTR_ID_VERSION_NUMBER_LIST            0x0200
+#define  ATTR_ID_GOEP_L2CAP_PSM                 0x0200
+#define  ATTR_ID_GROUP_ID                       0x0200
+#define  ATTR_ID_SERVICE_DATABASE_STATE         0x0201
+#define  ATTR_ID_SERVICE_VERSION                0x0300
+#define  ATTR_ID_HCRP_1284ID                    0x0300
+
+#define  ATTR_ID_SUPPORTED_DATA_STORES          0x0301
+#define  ATTR_ID_NETWORK                        0x0301
+#define  ATTR_ID_EXTERNAL_NETWORK               0x0301
+#define  ATTR_ID_FAX_CLASS_1_SUPPORT            0x0302
+#define  ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL    0x0302
+#define  ATTR_ID_DEVICE_NAME                    0x0302
+#define  ATTR_ID_SUPPORTED_FORMATS_LIST         0x0303
+#define  ATTR_ID_FAX_CLASS_2_0_SUPPORT          0x0303
+#define  ATTR_ID_FAX_CLASS_2_SUPPORT            0x0304
+#define  ATTR_ID_FRIENDLY_NAME                  0x0304
+#define  ATTR_ID_AUDIO_FEEDBACK_SUPPORT         0x0305
+#define  ATTR_ID_NETWORK_ADDRESS                0x0306
+#define  ATTR_ID_DEVICE_LOCATION                0x0306
+#define  ATTR_ID_WAP_GATEWAY                    0x0307
+#define  ATTR_ID_HOME_PAGE_URL                  0x0308
+#define  ATTR_ID_WAP_STACK_TYPE                 0x0309
+#define  ATTR_ID_IMG_SUPPORTED_CAPABILITIES     0x0310 /* Imaging Profile */
+#define  ATTR_ID_SUPPORTED_FEATURES             0x0311 /* HFP, BIP */
+#define  ATTR_ID_IMG_SUPPORTED_FUNCTIONS        0x0312 /* Imaging Profile */
+#define  ATTR_ID_IMG_TOT_DATA_CAPABILITY        0x0313 /* Imaging Profile */
+#define  ATTR_ID_SUPPORTED_REPOSITORIES         0x0314 /* Phone book access Profile */
+#define  ATTR_ID_MAS_INSTANCE_ID                0x0315 /* MAP profile */
+#define  ATTR_ID_SUPPORTED_MSG_TYPE             0x0316 /* MAP profile */
+#define  ATTR_ID_MAP_SUPPORTED_FEATURES         0x0317 /* MAP profile */
+#define  ATTR_ID_PBAP_SUPPORTED_FEATURES        0x0317 /* PBAP profile */
+
+
+/* These values are for the BPP profile */
+#define ATTR_ID_DOCUMENT_FORMATS_SUPPORTED      0x0350
+#define ATTR_ID_CHARACTER_REPERTOIRES_SUPPORTED 0x0352
+#define ATTR_ID_XHTML_IMAGE_FORMATS_SUPPORTED   0x0354
+#define ATTR_ID_COLOR_SUPPORTED                 0x0356
+#define ATTR_ID_1284ID                          0x0358
+#define ATTR_ID_PRINTER_NAME                    0x035A
+#define ATTR_ID_PRINTER_LOCATION                0x035C
+#define ATTR_ID_DUPLEX_SUPPORTED                0x035E
+#define ATTR_ID_MEDIA_TYPES_SUPPORTED           0x0360
+#define ATTR_ID_MAX_MEDIA_WIDTH                 0x0362
+#define ATTR_ID_MAX_MEDIA_LENGTH                0x0364
+#define ATTR_ID_ENHANCED_LAYOUT_SUPPORTED       0x0366
+#define ATTR_ID_RUI_FORMATS_SUPPORTED           0x0368
+#define ATTR_ID_RUI_REF_PRINTING_SUPPORTED      0x0370  /* Boolean */
+#define ATTR_ID_RUI_DIRECT_PRINTING_SUPPORTED   0x0372  /* Boolean */
+#define ATTR_ID_REF_PRINTING_TOP_URL            0x0374
+#define ATTR_ID_DIRECT_PRINTING_TOP_URL         0x0376
+#define ATTR_ID_PRINTER_ADMIN_RUI_TOP_URL       0x0378
+#define ATTR_ID_BPP_DEVICE_NAME                 0x037A
+
+/* These values are for the PAN profile */
+#define  ATTR_ID_SECURITY_DESCRIPTION           0x030A
+#define  ATTR_ID_NET_ACCESS_TYPE                0x030B
+#define  ATTR_ID_MAX_NET_ACCESS_RATE            0x030C
+#define  ATTR_ID_IPV4_SUBNET                    0x030D
+#define  ATTR_ID_IPV6_SUBNET                    0x030E
+#define  ATTR_ID_PAN_SECURITY                   0x0400
+
+/* These values are for HID profile */
+#define  ATTR_ID_HID_DEVICE_RELNUM          0x0200
+#define  ATTR_ID_HID_PARSER_VERSION         0x0201
+#define  ATTR_ID_HID_DEVICE_SUBCLASS        0x0202
+#define  ATTR_ID_HID_COUNTRY_CODE           0x0203
+#define  ATTR_ID_HID_VIRTUAL_CABLE          0x0204
+#define  ATTR_ID_HID_RECONNECT_INITIATE     0x0205
+#define  ATTR_ID_HID_DESCRIPTOR_LIST        0x0206
+#define  ATTR_ID_HID_LANGUAGE_ID_BASE       0x0207
+#define  ATTR_ID_HID_SDP_DISABLE            0x0208
+#define  ATTR_ID_HID_BATTERY_POWER          0x0209
+#define  ATTR_ID_HID_REMOTE_WAKE            0x020A
+#define  ATTR_ID_HID_PROFILE_VERSION        0x020B
+#define  ATTR_ID_HID_LINK_SUPERVISION_TO    0x020C
+#define  ATTR_ID_HID_NORMALLY_CONNECTABLE   0x020D
+#define  ATTR_ID_HID_BOOT_DEVICE            0x020E
+#define  ATTR_ID_HID_SSR_HOST_MAX_LAT       0x020F
+#define  ATTR_ID_HID_SSR_HOST_MIN_TOUT      0x0210
+
+/* These values are for the HDP profile */
+#define  ATTR_ID_HDP_SUP_FEAT_LIST          0x0200  /* Supported features list */
+#define  ATTR_ID_HDP_DATA_EXCH_SPEC         0x0301  /* Data exchange specification */
+#define  ATTR_ID_HDP_MCAP_SUP_PROC          0x0302  /* MCAP supported procedures */
+
+/* Define common 16-bit protocol UUIDs
+*/
+#define UUID_PROTOCOL_SDP                    0x0001
+#define UUID_PROTOCOL_UDP                    0x0002
+#define UUID_PROTOCOL_RFCOMM                 0x0003
+#define UUID_PROTOCOL_TCP                    0x0004
+#define UUID_PROTOCOL_TCS_BIN                0x0005
+#define UUID_PROTOCOL_TCS_AT                 0x0006
+#define UUID_PROTOCOL_OBEX                   0x0008
+#define UUID_PROTOCOL_IP                     0x0009
+#define UUID_PROTOCOL_FTP                    0x000A
+#define UUID_PROTOCOL_HTTP                   0x000C
+#define UUID_PROTOCOL_WSP                    0x000E
+#define UUID_PROTOCOL_BNEP                   0x000F
+#define UUID_PROTOCOL_UPNP                   0x0010
+#define UUID_PROTOCOL_HIDP                   0x0011
+#define UUID_PROTOCOL_HCRP_CTRL              0x0012
+#define UUID_PROTOCOL_HCRP_DATA              0x0014
+#define UUID_PROTOCOL_HCRP_NOTIF             0x0016
+#define UUID_PROTOCOL_AVCTP                  0x0017
+#define UUID_PROTOCOL_AVDTP                  0x0019
+#define UUID_PROTOCOL_CMTP                   0x001B
+#define UUID_PROTOCOL_UDI                    0x001D
+#define UUID_PROTOCOL_MCAP_CTRL              0x001E
+#define UUID_PROTOCOL_MCAP_DATA              0x001F
+#define UUID_PROTOCOL_L2CAP                  0x0100
+#define UUID_PROTOCOL_ATT                    0x0007
+
+/* Define common 16-bit service class UUIDs
+*/
+#define UUID_SERVCLASS_SERVICE_DISCOVERY_SERVER 0X1000
+#define UUID_SERVCLASS_BROWSE_GROUP_DESCRIPTOR  0X1001
+#define UUID_SERVCLASS_PUBLIC_BROWSE_GROUP      0X1002
+#define UUID_SERVCLASS_SERIAL_PORT              0X1101
+#define UUID_SERVCLASS_LAN_ACCESS_USING_PPP     0X1102
+#define UUID_SERVCLASS_DIALUP_NETWORKING        0X1103
+#define UUID_SERVCLASS_IRMC_SYNC                0X1104
+#define UUID_SERVCLASS_OBEX_OBJECT_PUSH         0X1105
+#define UUID_SERVCLASS_OBEX_FILE_TRANSFER       0X1106
+#define UUID_SERVCLASS_IRMC_SYNC_COMMAND        0X1107
+#define UUID_SERVCLASS_HEADSET                  0X1108
+#define UUID_SERVCLASS_CORDLESS_TELEPHONY       0X1109
+#define UUID_SERVCLASS_AUDIO_SOURCE             0X110A
+#define UUID_SERVCLASS_AUDIO_SINK               0X110B
+#define UUID_SERVCLASS_AV_REM_CTRL_TARGET       0X110C  /* Audio/Video Control profile */
+#define UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION   0X110D  /* Advanced Audio Distribution profile */
+#define UUID_SERVCLASS_AV_REMOTE_CONTROL        0X110E  /* Audio/Video Control profile */
+#define UUID_SERVCLASS_AV_REM_CTRL_CONTROL      0X110F  /* Audio/Video Control profile */
+#define UUID_SERVCLASS_INTERCOM                 0X1110
+#define UUID_SERVCLASS_FAX                      0X1111
+#define UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY    0X1112
+#define UUID_SERVCLASS_WAP                      0X1113
+#define UUID_SERVCLASS_WAP_CLIENT               0X1114
+#define UUID_SERVCLASS_PANU                     0X1115  /* PAN profile */
+#define UUID_SERVCLASS_NAP                      0X1116  /* PAN profile */
+#define UUID_SERVCLASS_GN                       0X1117  /* PAN profile */
+#define UUID_SERVCLASS_DIRECT_PRINTING          0X1118  /* BPP profile */
+#define UUID_SERVCLASS_REFERENCE_PRINTING       0X1119  /* BPP profile */
+#define UUID_SERVCLASS_IMAGING                  0X111A  /* Imaging profile */
+#define UUID_SERVCLASS_IMAGING_RESPONDER        0X111B  /* Imaging profile */
+#define UUID_SERVCLASS_IMAGING_AUTO_ARCHIVE     0X111C  /* Imaging profile */
+#define UUID_SERVCLASS_IMAGING_REF_OBJECTS      0X111D  /* Imaging profile */
+#define UUID_SERVCLASS_HF_HANDSFREE             0X111E  /* Handsfree profile */
+#define UUID_SERVCLASS_AG_HANDSFREE             0X111F  /* Handsfree profile */
+#define UUID_SERVCLASS_DIR_PRT_REF_OBJ_SERVICE  0X1120  /* BPP profile */
+#define UUID_SERVCLASS_REFLECTED_UI             0X1121  /* BPP profile */
+#define UUID_SERVCLASS_BASIC_PRINTING           0X1122  /* BPP profile */
+#define UUID_SERVCLASS_PRINTING_STATUS          0X1123  /* BPP profile */
+#define UUID_SERVCLASS_HUMAN_INTERFACE          0X1124  /* HID profile */
+#define UUID_SERVCLASS_CABLE_REPLACEMENT        0X1125  /* HCRP profile */
+#define UUID_SERVCLASS_HCRP_PRINT               0X1126  /* HCRP profile */
+#define UUID_SERVCLASS_HCRP_SCAN                0X1127  /* HCRP profile */
+#define UUID_SERVCLASS_COMMON_ISDN_ACCESS       0X1128  /* CAPI Message Transport Protocol*/
+#define UUID_SERVCLASS_VIDEO_CONFERENCING_GW    0X1129  /* Video Conferencing profile */
+#define UUID_SERVCLASS_UDI_MT                   0X112A  /* Unrestricted Digital Information profile */
+#define UUID_SERVCLASS_UDI_TA                   0X112B  /* Unrestricted Digital Information profile */
+#define UUID_SERVCLASS_VCP                      0X112C  /* Video Conferencing profile */
+#define UUID_SERVCLASS_SAP                      0X112D  /* SIM Access profile */
+#define UUID_SERVCLASS_PBAP_PCE                 0X112E  /* Phonebook Access - PCE */
+#define UUID_SERVCLASS_PBAP_PSE                 0X112F  /* Phonebook Access - PSE */
+#define UUID_SERVCLASS_PHONE_ACCESS             0x1130
+#define UUID_SERVCLASS_HEADSET_HS               0x1131  /* Headset - HS, from HSP v1.2 */
+#define UUID_SERVCLASS_PNP_INFORMATION          0X1200  /* Device Identification */
+#define UUID_SERVCLASS_GENERIC_NETWORKING       0X1201
+#define UUID_SERVCLASS_GENERIC_FILETRANSFER     0X1202
+#define UUID_SERVCLASS_GENERIC_AUDIO            0X1203
+#define UUID_SERVCLASS_GENERIC_TELEPHONY        0X1204
+#define UUID_SERVCLASS_UPNP_SERVICE             0X1205  /* UPNP_Service [ESDP] */
+#define UUID_SERVCLASS_UPNP_IP_SERVICE          0X1206  /* UPNP_IP_Service [ESDP] */
+#define UUID_SERVCLASS_ESDP_UPNP_IP_PAN         0X1300  /* UPNP_IP_PAN [ESDP] */
+#define UUID_SERVCLASS_ESDP_UPNP_IP_LAP         0X1301  /* UPNP_IP_LAP [ESDP] */
+#define UUID_SERVCLASS_ESDP_UPNP_IP_L2CAP       0X1302  /* UPNP_L2CAP [ESDP] */
+#define UUID_SERVCLASS_VIDEO_SOURCE             0X1303  /* Video Distribution Profile (VDP) */
+#define UUID_SERVCLASS_VIDEO_SINK               0X1304  /* Video Distribution Profile (VDP) */
+#define UUID_SERVCLASS_VIDEO_DISTRIBUTION       0X1305  /* Video Distribution Profile (VDP) */
+#define UUID_SERVCLASS_HDP_PROFILE              0X1400  /* Health Device profile (HDP) */
+#define UUID_SERVCLASS_HDP_SOURCE               0X1401  /* Health Device profile (HDP) */
+#define UUID_SERVCLASS_HDP_SINK                 0X1402  /* Health Device profile (HDP) */
+#define UUID_SERVCLASS_MAP_PROFILE              0X1134  /* MAP profile UUID */
+#define UUID_SERVCLASS_MESSAGE_ACCESS           0X1132  /* Message Access Service UUID */
+#define UUID_SERVCLASS_MESSAGE_NOTIFICATION     0X1133  /* Message Notification Service UUID */
+
+#define UUID_SERVCLASS_GAP_SERVER               0x1800
+#define UUID_SERVCLASS_GATT_SERVER              0x1801
+#define UUID_SERVCLASS_IMMEDIATE_ALERT          0x1802      /* immediate alert */
+#define UUID_SERVCLASS_LINKLOSS                 0x1803      /* Link Loss Alert */
+#define UUID_SERVCLASS_TX_POWER                 0x1804      /* TX power */
+#define UUID_SERVCLASS_CURRENT_TIME             0x1805      /* Link Loss Alert */
+#define UUID_SERVCLASS_DST_CHG                  0x1806      /* DST Time change */
+#define UUID_SERVCLASS_REF_TIME_UPD             0x1807      /* reference time update */
+#define UUID_SERVCLASS_THERMOMETER              0x1809      /* Thermometer UUID */
+#define UUID_SERVCLASS_DEVICE_INFO              0x180A      /* device info service */
+#define UUID_SERVCLASS_NWA                      0x180B      /* Network availability */
+#define UUID_SERVCLASS_HEART_RATE               0x180D      /* Heart Rate service */
+#define UUID_SERVCLASS_PHALERT                  0x180E      /* phone alert service */
+#define UUID_SERVCLASS_BATTERY                  0x180F     /* battery service */
+#define UUID_SERVCLASS_BPM                      0x1810      /*  blood pressure service */
+#define UUID_SERVCLASS_ALERT_NOTIFICATION       0x1811      /* alert notification service */
+#define UUID_SERVCLASS_LE_HID                   0x1812     /*  HID over LE */
+#define UUID_SERVCLASS_SCAN_PARAM               0x1813      /* Scan Parameter service */
+#define UUID_SERVCLASS_GLUCOSE                  0x1808      /* Glucose Meter Service */
+#define UUID_SERVCLASS_RSC                      0x1814      /* RUNNERS SPEED AND CADENCE SERVICE      */
+#define UUID_SERVCLASS_CSC                      0x1816      /* Cycling SPEED AND CADENCE SERVICE      */
+
+#define UUID_SERVCLASS_TEST_SERVER              0x9000      /* Test Group UUID */
+
+#if (BTM_WBS_INCLUDED == TRUE)
+#define UUID_CODEC_CVSD                         0x0001   /* CVSD */
+#define UUID_CODEC_MSBC                         0x0002   /* mSBC */
+#endif
+
+#define UUID_HF_IND_ENHANCED_DRIVER_SAFETY      0x0001   /* Assigned number for Enhanced Safety */
+#define UUID_HF_IND_BATTERY_LEVEL_STATUS        0x0002   /* Assigned number for Battery Status */
+
+/* Define all the 'Descriptor Type' values.
+*/
+#define  NULL_DESC_TYPE                     0
+#define  UINT_DESC_TYPE                     1
+#define  TWO_COMP_INT_DESC_TYPE             2
+#define  UUID_DESC_TYPE                     3
+#define  TEXT_STR_DESC_TYPE                 4
+#define  BOOLEAN_DESC_TYPE                  5
+#define  DATA_ELE_SEQ_DESC_TYPE             6
+#define  DATA_ELE_ALT_DESC_TYPE             7
+#define  URL_DESC_TYPE                      8
+
+/* Define all the "Descriptor Size" values.
+*/
+#define  SIZE_ONE_BYTE                0
+#define  SIZE_TWO_BYTES               1
+#define  SIZE_FOUR_BYTES              2
+#define  SIZE_EIGHT_BYTES             3
+#define  SIZE_SIXTEEN_BYTES           4
+#define  SIZE_IN_NEXT_BYTE            5
+#define  SIZE_IN_NEXT_WORD            6
+#define  SIZE_IN_NEXT_LONG            7
+
+/* Language Encoding Constants */
+#define LANG_ID_CODE_ENGLISH            ((uint16_t) 0x656e)   /* "en" */
+#define LANG_ID_CHAR_ENCODE_UTF8        ((uint16_t) 0x006a)   /* UTF-8 */
+
+/* Constants used for display purposes only.  These define ovelapping attribute values */
+#define  ATTR_ID_VERS_OR_GRP_OR_DRELNUM_OR_IPSUB_OR_SPECID  0x0200
+#define  ATTR_ID_VEND_ID_OR_SERVICE_DB_STATE_OR_PARSE_VER   0x0201
+#define  ATTR_ID_PROD_ID_OR_HID_DEV_SUBCLASS                0x0202
+#define  ATTR_ID_PROD_VER_OR_HID_COUNTRY_CODE               0x0203
+#define  ATTR_ID_PRIMARY_REC_OR_HID_VIRTUAL_CABLE           0x0204
+#define  ATTR_ID_DI_VENDOR_ID_SOURCE_OR_HID_INIT_RECONNECT  0x0205
+#define  ATTR_ID_SERV_VERS_OR_1284ID                        0x0300
+#define  ATTR_ID_DATA_STORES_OR_NETWORK                     0x0301
+#define  ATTR_ID_FAX_1_OR_AUD_VOL_OR_DEV_NAME               0x0302
+#define  ATTR_ID_FORMATS_OR_FAX_2_0                         0x0303
+#define  ATTR_ID_FAX_CLASS_2_OR_FRIENDLY_NAME               0x0304
+#define  ATTR_ID_NETADDRESS_OR_DEVLOCATION                  0x0306
+
+#endif
+
+
diff --git a/bt/stack/include/smp_api.h b/bt/stack/include/smp_api.h
new file mode 100644
index 0000000..fc843fb
--- /dev/null
+++ b/bt/stack/include/smp_api.h
@@ -0,0 +1,248 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 SMP API function external definitions.
+ *
+ ******************************************************************************/
+#ifndef SMP_API_H
+#define SMP_API_H
+
+#include "bt_target.h"
+#include "smp_api_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+**  External Function Declarations
+*****************************************************************************/
+/* API of SMP */
+
+/*******************************************************************************
+**
+** Function         SMP_Init
+**
+** Description      This function initializes the SMP unit.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void SMP_Init(void);
+
+/*******************************************************************************
+**
+** Function         SMP_SetTraceLevel
+**
+** Description      This function sets the trace level for SMP.  If called with
+**                  a value of 0xFF, it simply returns the current trace level.
+**
+** Returns          The new or current trace level
+**
+*******************************************************************************/
+extern uint8_t SMP_SetTraceLevel (uint8_t new_level);
+
+/*******************************************************************************
+**
+** Function         SMP_Register
+**
+** Description      This function register for the SMP service callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern bool    SMP_Register (tSMP_CALLBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function         SMP_Pair
+**
+** Description      This function is called to start a SMP pairing.
+**
+** Returns          SMP_STARTED if bond started, else otherwise exception.
+**
+*******************************************************************************/
+extern tSMP_STATUS SMP_Pair (BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function         SMP_BR_PairWith
+**
+** Description      This function is called to start a SMP pairing over BR/EDR.
+**
+** Returns          SMP_STARTED if pairing started, otherwise reason for failure.
+**
+*******************************************************************************/
+extern tSMP_STATUS SMP_BR_PairWith (BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function         SMP_PairCancel
+**
+** Description      This function is called to cancel a SMP pairing.
+**
+** Returns          true - pairing cancelled
+**
+*******************************************************************************/
+extern  bool    SMP_PairCancel (BD_ADDR bd_addr);
+
+/*******************************************************************************
+**
+** Function         SMP_SecurityGrant
+**
+** Description      This function is called to grant security process.
+**
+** Parameters       bd_addr - peer device bd address.
+**                  res     - result of the operation SMP_SUCCESS if success.
+**                            Otherwise, SMP_REPEATED_ATTEMPTS is too many attempts.
+**
+** Returns          None
+**
+*******************************************************************************/
+extern void SMP_SecurityGrant(BD_ADDR bd_addr, uint8_t res);
+
+/*******************************************************************************
+**
+** Function         SMP_PasskeyReply
+**
+** Description      This function is called after Security Manager submitted
+**                  Passkey request to the application.
+**
+** Parameters:      bd_addr      - Address of the device for which PIN 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)).
+**
+*******************************************************************************/
+extern void SMP_PasskeyReply (BD_ADDR bd_addr, uint8_t res, uint32_t passkey);
+
+/*******************************************************************************
+**
+** Function         SMP_ConfirmReply
+**
+** 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 SMP_SUCCESS if success
+**
+*******************************************************************************/
+extern void SMP_ConfirmReply (BD_ADDR bd_addr, uint8_t res);
+
+/*******************************************************************************
+**
+** Function         SMP_OobDataReply
+**
+** Description      This function is called to provide the OOB data for
+**                  SMP in response to SMP_OOB_REQ_EVT
+**
+** Parameters:      bd_addr     - Address of the peer device
+**                  res         - result of the operation SMP_SUCCESS if success
+**                  p_data      - SM Randomizer  C.
+**
+*******************************************************************************/
+extern void SMP_OobDataReply(BD_ADDR bd_addr, tSMP_STATUS res, uint8_t len,
+                             uint8_t *p_data);
+
+/*******************************************************************************
+**
+** Function         SMP_SecureConnectionOobDataReply
+**
+** Description      This function is called to provide the SC OOB data for
+**                  SMP in response to SMP_SC_OOB_REQ_EVT
+**
+** Parameters:      p_data      - pointer to the data
+**
+*******************************************************************************/
+extern void SMP_SecureConnectionOobDataReply(uint8_t *p_data);
+
+/*******************************************************************************
+**
+** Function         SMP_Encrypt
+**
+** Description      This function is called to encrypt the data with the specified
+**                  key
+**
+** Parameters:      key                 - Pointer to key key[0] conatins the MSB
+**                  key_len             - key length
+**                  plain_text          - Pointer to data to be encrypted
+**                                        plain_text[0] conatins the MSB
+**                  pt_len              - plain text length
+**                  p_out               - pointer to the encrypted outputs
+**
+**  Returns         Boolean - true: encryption is successful
+*******************************************************************************/
+extern bool    SMP_Encrypt (uint8_t *key, uint8_t key_len,
+                            uint8_t *plain_text, uint8_t pt_len,
+                            tSMP_ENC *p_out);
+
+/*******************************************************************************
+**
+** Function         SMP_KeypressNotification
+**
+** Description      This function is called to notify SM about Keypress Notification.
+**
+** Parameters:      bd_addr      - Address of the device to send keypress
+**                                 notification to
+**                  value        - keypress notification parameter value
+**
+*******************************************************************************/
+extern void SMP_KeypressNotification (BD_ADDR bd_addr, uint8_t value);
+
+/*******************************************************************************
+**
+** Function         SMP_CreateLocalSecureConnectionsOobData
+**
+** Description      This function is called to start creation of local SC OOB
+**                  data set (tSMP_LOC_OOB_DATA).
+**
+** Parameters:      bd_addr      - Address of the device to send OOB data block
+**                                 to.
+**
+**  Returns         Boolean - true: creation of local SC OOB data set started.
+*******************************************************************************/
+extern bool SMP_CreateLocalSecureConnectionsOobData(tBLE_BD_ADDR *addr_to_send_to);
+
+#if (SMP_INCLUDED == TRUE)
+// Called when LTK request is received from controller.
+extern bool smp_proc_ltk_request(BD_ADDR bda);
+
+// Called when link is encrypted and notified to slave device.
+// Proceed to send LTK, DIV and ER to master if bonding the devices.
+extern void smp_link_encrypted(BD_ADDR bda, uint8_t encr_enable);
+#endif /* SMP_INCLUDED == TRUE */
+
+//
+// The AES-CMAC Generation Function with tlen implemented.
+// |key| - CMAC key in little endian order, expect SRK when used by SMP.
+// |input| - text to be signed in little endian byte order.
+// |length| - length of the input in byte.
+// |tlen| - lenth of mac desired
+// |p_signature| - data pointer to where signed data to be stored, tlen long.
+// Returns false if out of resources, true in other cases.
+//
+bool aes_cipher_msg_auth_code(BT_OCTET16 key, uint8_t *input, uint16_t length,
+                              uint16_t tlen, uint8_t *p_signature);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* SMP_API_H */
diff --git a/bt/stack/include/smp_api_types.h b/bt/stack/include/smp_api_types.h
new file mode 100644
index 0000000..41ccc8b
--- /dev/null
+++ b/bt/stack/include/smp_api_types.h
@@ -0,0 +1,299 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+
+#ifndef SMP_API_TYPES_H
+#define SMP_API_TYPES_H
+
+#include "bt_target.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SMP_PIN_CODE_LEN_MAX    PIN_CODE_LEN
+#define SMP_PIN_CODE_LEN_MIN    6
+
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+/* SMP command code */
+#define SMP_OPCODE_PAIRING_REQ            0x01
+#define SMP_OPCODE_PAIRING_RSP            0x02
+#define SMP_OPCODE_CONFIRM                0x03
+#define SMP_OPCODE_RAND                   0x04
+#define SMP_OPCODE_PAIRING_FAILED         0x05
+#define SMP_OPCODE_ENCRYPT_INFO           0x06
+#define SMP_OPCODE_MASTER_ID              0x07
+#define SMP_OPCODE_IDENTITY_INFO          0x08
+#define SMP_OPCODE_ID_ADDR                0x09
+#define SMP_OPCODE_SIGN_INFO              0x0A
+#define SMP_OPCODE_SEC_REQ                0x0B
+#define SMP_OPCODE_PAIR_PUBLIC_KEY        0x0C
+#define SMP_OPCODE_PAIR_DHKEY_CHECK       0x0D
+#define SMP_OPCODE_PAIR_KEYPR_NOTIF       0x0E
+#define SMP_OPCODE_MAX                    SMP_OPCODE_PAIR_KEYPR_NOTIF
+#define SMP_OPCODE_MIN                    SMP_OPCODE_PAIRING_REQ
+#define SMP_OPCODE_PAIR_COMMITM           0x0F
+#endif
+
+/* SMP event type */
+#define SMP_IO_CAP_REQ_EVT      1       /* IO capability request event */
+#define SMP_SEC_REQUEST_EVT     2       /* SMP pairing request */
+#define SMP_PASSKEY_NOTIF_EVT   3       /* passkey notification event */
+#define SMP_PASSKEY_REQ_EVT     4       /* passkey request event */
+#define SMP_OOB_REQ_EVT         5       /* OOB request event */
+#define SMP_NC_REQ_EVT          6       /* Numeric Comparison request event */
+#define SMP_COMPLT_EVT          7       /* SMP complete event */
+#define SMP_PEER_KEYPR_NOT_EVT  8       /* Peer keypress notification received event */
+#define SMP_SC_OOB_REQ_EVT      9       /* SC OOB request event (both local and peer OOB data */
+                                        /* can be expected in response) */
+#define SMP_SC_LOC_OOB_DATA_UP_EVT  10  /* SC OOB local data set is created */
+                                        /* (as result of SMP_CrLocScOobData(...)) */
+#define SMP_BR_KEYS_REQ_EVT     12      /* SMP over BR keys request event */
+typedef uint8_t tSMP_EVT;
+
+
+/* pairing failure reason code */
+#define SMP_PASSKEY_ENTRY_FAIL      0x01
+#define SMP_OOB_FAIL                0x02
+#define SMP_PAIR_AUTH_FAIL          0x03
+#define SMP_CONFIRM_VALUE_ERR       0x04
+#define SMP_PAIR_NOT_SUPPORT        0x05
+#define SMP_ENC_KEY_SIZE            0x06
+#define SMP_INVALID_CMD             0x07
+#define SMP_PAIR_FAIL_UNKNOWN       0x08
+#define SMP_REPEATED_ATTEMPTS       0x09
+#define SMP_INVALID_PARAMETERS      0x0A
+#define SMP_DHKEY_CHK_FAIL          0x0B
+#define SMP_NUMERIC_COMPAR_FAIL     0x0C
+#define SMP_BR_PARING_IN_PROGR      0x0D
+#define SMP_XTRANS_DERIVE_NOT_ALLOW 0x0E
+#define SMP_MAX_FAIL_RSN_PER_SPEC   SMP_XTRANS_DERIVE_NOT_ALLOW
+
+/* self defined error code */
+#define SMP_PAIR_INTERNAL_ERR       (SMP_MAX_FAIL_RSN_PER_SPEC + 0x01) /* 0x0F */
+
+/* Unknown IO capability, unable to decide association model */
+#define SMP_UNKNOWN_IO_CAP          (SMP_MAX_FAIL_RSN_PER_SPEC + 0x02) /* 0x10 */
+
+#define SMP_INIT_FAIL               (SMP_MAX_FAIL_RSN_PER_SPEC + 0x03) /* 0x11 */
+#define SMP_CONFIRM_FAIL            (SMP_MAX_FAIL_RSN_PER_SPEC + 0x04) /* 0x12 */
+#define SMP_BUSY                    (SMP_MAX_FAIL_RSN_PER_SPEC + 0x05) /* 0x13 */
+#define SMP_ENC_FAIL                (SMP_MAX_FAIL_RSN_PER_SPEC + 0x06) /* 0x14 */
+#define SMP_STARTED                 (SMP_MAX_FAIL_RSN_PER_SPEC + 0x07) /* 0x15 */
+#define SMP_RSP_TIMEOUT             (SMP_MAX_FAIL_RSN_PER_SPEC + 0x08) /* 0x16 */
+#define SMP_DIV_NOT_AVAIL           (SMP_MAX_FAIL_RSN_PER_SPEC + 0x09) /* 0x17 */
+
+/* Unspecified failure reason */
+#define SMP_FAIL                    (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0A) /* 0x18 */
+
+#define SMP_CONN_TOUT               (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0B) /* 0x19 */
+#define SMP_SUCCESS                 0
+
+typedef uint8_t tSMP_STATUS;
+
+
+/* Device IO capability */
+#define SMP_IO_CAP_OUT      BTM_IO_CAP_OUT   /* DisplayOnly */
+#define SMP_IO_CAP_IO       BTM_IO_CAP_IO   /* DisplayYesNo */
+#define SMP_IO_CAP_IN       BTM_IO_CAP_IN   /* KeyboardOnly */
+#define SMP_IO_CAP_NONE     BTM_IO_CAP_NONE   /* NoInputNoOutput */
+#define SMP_IO_CAP_KBDISP   BTM_IO_CAP_KBDISP   /* Keyboard Display */
+#define SMP_IO_CAP_MAX      BTM_IO_CAP_MAX
+typedef uint8_t tSMP_IO_CAP;
+
+#ifndef SMP_DEFAULT_IO_CAPS
+    #define SMP_DEFAULT_IO_CAPS     SMP_IO_CAP_KBDISP
+#endif
+
+/* OOB data present or not */
+enum
+{
+    SMP_OOB_NONE,
+    SMP_OOB_PRESENT,
+    SMP_OOB_UNKNOWN
+};
+typedef uint8_t tSMP_OOB_FLAG;
+
+/* type of OOB data required from application */
+enum
+{
+    SMP_OOB_INVALID_TYPE,
+    SMP_OOB_PEER,
+    SMP_OOB_LOCAL,
+    SMP_OOB_BOTH
+};
+typedef uint8_t tSMP_OOB_DATA_TYPE;
+
+#define SMP_AUTH_NO_BOND        0x00
+#define SMP_AUTH_GEN_BOND       0x01 //todo sdh change GEN_BOND to BOND
+
+/* SMP Authentication requirement */
+#define SMP_AUTH_YN_BIT         (1 << 2)
+#define SMP_SC_SUPPORT_BIT      (1 << 3)
+#define SMP_KP_SUPPORT_BIT      (1 << 4)
+
+#define SMP_AUTH_MASK    (SMP_AUTH_GEN_BOND|SMP_AUTH_YN_BIT|SMP_SC_SUPPORT_BIT|SMP_KP_SUPPORT_BIT)
+
+#define SMP_AUTH_BOND           SMP_AUTH_GEN_BOND
+
+/* no MITM, No Bonding, encryption only */
+#define SMP_AUTH_NB_ENC_ONLY    0x00 //(SMP_AUTH_MASK | BTM_AUTH_SP_NO)
+
+/* MITM, No Bonding, Use IO Capability to determine authentication procedure */
+#define SMP_AUTH_NB_IOCAP       (SMP_AUTH_NO_BOND | SMP_AUTH_YN_BIT)
+
+/* No MITM, General Bonding, Encryption only */
+#define SMP_AUTH_GB_ENC_ONLY    (SMP_AUTH_GEN_BOND )
+
+/* MITM, General Bonding, Use IO Capability to determine authentication procedure */
+#define SMP_AUTH_GB_IOCAP       (SMP_AUTH_GEN_BOND | SMP_AUTH_YN_BIT)
+
+/* Secure Connections, no MITM, no Bonding */
+#define SMP_AUTH_SC_ENC_ONLY    (SMP_SC_SUPPORT_BIT)
+
+/* Secure Connections, no MITM, Bonding */
+#define SMP_AUTH_SC_GB          (SMP_SC_SUPPORT_BIT | SMP_AUTH_GEN_BOND)
+
+/* Secure Connections, MITM, no Bonding */
+#define SMP_AUTH_SC_MITM_NB     (SMP_SC_SUPPORT_BIT | SMP_AUTH_YN_BIT | SMP_AUTH_NO_BOND)
+
+/* Secure Connections, MITM, Bonding */
+#define SMP_AUTH_SC_MITM_GB     (SMP_SC_SUPPORT_BIT | SMP_AUTH_YN_BIT | SMP_AUTH_GEN_BOND)
+
+ /* All AuthReq RFU bits are set to 1 - NOTE: reserved bit in Bonding_Flags is not set */
+#define SMP_AUTH_ALL_RFU_SET    0xF8
+
+typedef uint8_t tSMP_AUTH_REQ;
+
+#define SMP_SEC_NONE                 0
+#define SMP_SEC_UNAUTHENTICATE      (1 << 0)
+#define SMP_SEC_AUTHENTICATED       (1 << 2)
+typedef uint8_t tSMP_SEC_LEVEL;
+
+/* Maximum Encryption Key Size range */
+#define SMP_ENCR_KEY_SIZE_MIN       7
+#define SMP_ENCR_KEY_SIZE_MAX       16
+
+/* SMP key types */
+#define SMP_SEC_KEY_TYPE_ENC                (1 << 0)    /* encryption key */
+#define SMP_SEC_KEY_TYPE_ID                 (1 << 1)    /* identity key */
+#define SMP_SEC_KEY_TYPE_CSRK               (1 << 2)    /* slave CSRK */
+#define SMP_SEC_KEY_TYPE_LK                 (1 << 3)    /* BR/EDR link key */
+typedef uint8_t tSMP_KEYS;
+
+#define SMP_BR_SEC_DEFAULT_KEY   (SMP_SEC_KEY_TYPE_ENC | SMP_SEC_KEY_TYPE_ID | \
+                                  SMP_SEC_KEY_TYPE_CSRK)
+
+/* default security key distribution value */
+#define SMP_SEC_DEFAULT_KEY      (SMP_SEC_KEY_TYPE_ENC | SMP_SEC_KEY_TYPE_ID | \
+                                  SMP_SEC_KEY_TYPE_CSRK | SMP_SEC_KEY_TYPE_LK)
+
+#define SMP_SC_KEY_STARTED      0   /* passkey entry started */
+#define SMP_SC_KEY_ENTERED      1   /* passkey digit entered */
+#define SMP_SC_KEY_ERASED       2   /* passkey digit erased */
+#define SMP_SC_KEY_CLEARED      3   /* passkey cleared */
+#define SMP_SC_KEY_COMPLT       4   /* passkey entry completed */
+#define SMP_SC_KEY_OUT_OF_RANGE 5   /* out of range */
+typedef uint8_t tSMP_SC_KEY_TYPE;
+
+/* data type for BTM_SP_IO_REQ_EVT */
+typedef struct
+{
+    tSMP_IO_CAP     io_cap;         /* local IO capabilities */
+    tSMP_OOB_FLAG   oob_data;       /* OOB data present (locally) for the peer device */
+    tSMP_AUTH_REQ   auth_req;       /* Authentication required (for local device) */
+    uint8_t         max_key_size;   /* max encryption key size */
+    tSMP_KEYS       init_keys;      /* initiator keys to be distributed */
+    tSMP_KEYS       resp_keys;      /* responder keys */
+} tSMP_IO_REQ;
+
+typedef struct
+{
+    tSMP_STATUS reason;
+    tSMP_SEC_LEVEL sec_level;
+    bool    is_pair_cancel;
+    bool    smp_over_br;
+} tSMP_CMPL;
+
+typedef struct
+{
+    BT_OCTET32  x;
+    BT_OCTET32  y;
+} tSMP_PUBLIC_KEY;
+
+/* the data associated with the info sent to the peer via OOB interface */
+typedef struct
+{
+    bool            present;
+    BT_OCTET16      randomizer;
+    BT_OCTET16      commitment;
+
+    tBLE_BD_ADDR    addr_sent_to;
+    BT_OCTET32      private_key_used;   /* is used to calculate: */
+                    /* publ_key_used = P-256(private_key_used, curve_p256.G) - send it to the */
+                    /* other side */
+                    /* dhkey = P-256(private_key_used, publ key rcvd from the other side) */
+    tSMP_PUBLIC_KEY publ_key_used; /* P-256(private_key_used, curve_p256.G) */
+} tSMP_LOC_OOB_DATA;
+
+/* the data associated with the info received from the peer via OOB interface */
+typedef struct
+{
+    bool            present;
+    BT_OCTET16      randomizer;
+    BT_OCTET16      commitment;
+    tBLE_BD_ADDR    addr_rcvd_from;
+} tSMP_PEER_OOB_DATA;
+
+typedef struct
+{
+    tSMP_LOC_OOB_DATA   loc_oob_data;
+    tSMP_PEER_OOB_DATA  peer_oob_data;
+} tSMP_SC_OOB_DATA;
+
+
+typedef union
+{
+    uint32_t        passkey;
+    tSMP_IO_REQ     io_req;     /* IO request */
+    tSMP_CMPL       cmplt;
+    tSMP_OOB_DATA_TYPE  req_oob_type;
+    tSMP_LOC_OOB_DATA   loc_oob_data;
+}tSMP_EVT_DATA;
+
+
+/* AES Encryption output */
+typedef struct
+{
+    uint8_t  status;
+    uint8_t  param_len;
+    uint16_t opcode;
+    uint8_t  param_buf[BT_OCTET16_LEN];
+} tSMP_ENC;
+
+/* Security Manager events - Called by the stack when Security Manager related events occur.*/
+typedef uint8_t (tSMP_CALLBACK) (tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data);
+
+/* callback function for CMAC algorithm
+*/
+typedef void (tCMAC_CMPL_CBACK)(uint8_t *p_mac, uint16_t tlen, uint32_t sign_counter);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SMP_API_TYPES_H
\ No newline at end of file
diff --git a/bt/stack/include/srvc_api.h b/bt/stack/include/srvc_api.h
new file mode 100644
index 0000000..2988a29
--- /dev/null
+++ b/bt/stack/include/srvc_api.h
@@ -0,0 +1,217 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-2013 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.
+ *
+ ******************************************************************************/
+
+#ifndef SRVC_DIS_API_H
+#define SRVC_DIS_API_H
+
+#include "bt_target.h"
+#include "gatt_api.h"
+#include "gattdefs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DIS_SUCCESS             GATT_SUCCESS
+#define DIS_ILLEGAL_PARAM       GATT_ILLEGAL_PARAMETER
+#define DIS_NO_RESOURCES        GATT_NO_RESOURCES
+typedef uint8_t tDIS_STATUS;
+
+
+/*****************************************************************************
+**  Data structure for DIS
+*****************************************************************************/
+
+#define DIS_ATTR_SYS_ID_BIT         0x0001
+#define DIS_ATTR_MODEL_NUM_BIT      0x0002
+#define DIS_ATTR_SERIAL_NUM_BIT     0x0004
+#define DIS_ATTR_FW_NUM_BIT         0x0008
+#define DIS_ATTR_HW_NUM_BIT         0x0010
+#define DIS_ATTR_SW_NUM_BIT         0x0020
+#define DIS_ATTR_MANU_NAME_BIT      0x0040
+#define DIS_ATTR_IEEE_DATA_BIT      0x0080
+#define DIS_ATTR_PNP_ID_BIT         0x0100
+typedef uint16_t tDIS_ATTR_MASK;
+
+#define DIS_ATTR_ALL_MASK           0xffff
+
+typedef tDIS_ATTR_MASK tDIS_ATTR_BIT ;
+
+typedef struct
+{
+    uint16_t    len;
+    uint8_t     *p_data;
+}tDIS_STRING;
+
+typedef struct
+{
+    uint16_t     vendor_id;
+    uint16_t     product_id;
+    uint16_t     product_version;
+    uint8_t      vendor_id_src;
+
+}tDIS_PNP_ID;
+
+typedef union
+{
+    uint64_t            system_id;
+    tDIS_PNP_ID         pnp_id;
+    tDIS_STRING         data_str;
+}tDIS_ATTR;
+
+#define DIS_MAX_STRING_DATA     7
+
+typedef struct
+{
+    uint16_t                attr_mask;
+    uint64_t                system_id;
+    tDIS_PNP_ID             pnp_id;
+    uint8_t                 *data_string[DIS_MAX_STRING_DATA];
+}tDIS_VALUE;
+
+
+typedef void (tDIS_READ_CBACK)(BD_ADDR addr, tDIS_VALUE *p_dis_value);
+
+/*****************************************************************************
+**  Data structure used by Battery Service
+*****************************************************************************/
+typedef struct
+{
+    BD_ADDR remote_bda;
+    bool    need_rsp;
+    uint16_t clt_cfg;
+}tBA_WRITE_DATA;
+
+#define BA_READ_CLT_CFG_REQ     1
+#define BA_READ_PRE_FMT_REQ     2
+#define BA_READ_RPT_REF_REQ     3
+#define BA_READ_LEVEL_REQ       4
+#define BA_WRITE_CLT_CFG_REQ    5
+
+typedef void (tBA_CBACK)(uint8_t app_id, uint8_t event, tBA_WRITE_DATA *p_data);
+
+#define BA_LEVEL_NOTIFY         0x01
+#define BA_LEVEL_PRE_FMT        0x02
+#define BA_LEVEL_RPT_REF        0x04
+typedef uint8_t tBA_LEVEL_DESCR;
+
+typedef struct
+{
+    bool            is_pri;
+    tBA_LEVEL_DESCR     ba_level_descr;
+    tGATT_TRANSPORT transport;
+    tBA_CBACK       *p_cback;
+
+}tBA_REG_INFO;
+
+typedef union
+{
+    uint8_t     ba_level;
+    uint16_t    clt_cfg;
+    tGATT_CHAR_RPT_REF  rpt_ref;
+    tGATT_CHAR_PRES     pres_fmt;
+}tBA_RSP_DATA;
+
+/*****************************************************************************
+**  External Function Declarations
+*****************************************************************************/
+/*****************************************************************************
+**  Service Engine API
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function         srvc_eng_init
+**
+** Description      Initializa the GATT Service engine, register a GATT application
+**                  as for a central service management.
+**
+*******************************************************************************/
+extern tGATT_STATUS srvc_eng_init (void);
+
+
+/*****************************************************************************
+**  DIS Server Function
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function         DIS_SrInit
+**
+** Description      Initializa the Device Information Service Server.
+**
+*******************************************************************************/
+extern tDIS_STATUS DIS_SrInit (tDIS_ATTR_MASK dis_attr_mask);
+/*******************************************************************************
+**
+** Function         DIS_SrUpdate
+**
+** Description      Update the DIS server attribute values
+**
+*******************************************************************************/
+extern tDIS_STATUS DIS_SrUpdate(tDIS_ATTR_BIT dis_attr_bit, tDIS_ATTR *p_info);
+/*****************************************************************************
+**  DIS Client Function
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function         DIS_ReadDISInfo
+**
+** Description      Read remote device DIS information.
+**
+** Returns          void
+**
+*******************************************************************************/
+extern bool    DIS_ReadDISInfo(BD_ADDR peer_bda, tDIS_READ_CBACK *p_cback,
+                               tDIS_ATTR_MASK mask);
+
+/*******************************************************************************
+**      BATTERY SERVICE API
+*******************************************************************************/
+/*******************************************************************************
+**
+** Function         Battery_Instantiate
+**
+** Description      Instantiate a Battery service
+**
+*******************************************************************************/
+extern uint16_t Battery_Instantiate (uint8_t app_id, tBA_REG_INFO *p_reg_info);
+
+/*******************************************************************************
+**
+** Function         Battery_Rsp
+**
+** Description      Respond to a battery service request
+**
+*******************************************************************************/
+extern void Battery_Rsp (uint8_t app_id, tGATT_STATUS st, uint8_t event, tBA_RSP_DATA *p_rsp);
+/*******************************************************************************
+**
+** Function         Battery_Notify
+**
+** Description      Send battery level notification
+**
+*******************************************************************************/
+extern void Battery_Notify (uint8_t app_id, BD_ADDR remote_bda, uint8_t battery_level);
+
+
+#ifdef __cplusplus
+
+}
+#endif
+
+#endif
diff --git a/bt/stack/l2cap/l2c_api.cc b/bt/stack/l2cap/l2c_api.cc
new file mode 100644
index 0000000..3248781
--- /dev/null
+++ b/bt/stack/l2cap/l2c_api.cc
@@ -0,0 +1,2304 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 L2CAP API code
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_l2cap"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_types.h"
+#include "btm_api.h"
+#include "btu.h"
+#include "bt_common.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+#include "l2cdefs.h"
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+/*******************************************************************************
+**
+** 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(),
+**                  L2CA_ErtmConnectReq() and L2CA_Deregister()
+**
+*******************************************************************************/
+uint16_t L2CA_Register (uint16_t psm, tL2CAP_APPL_INFO *p_cb_info)
+{
+    tL2C_RCB    *p_rcb;
+    uint16_t    vpsm = psm;
+
+    L2CAP_TRACE_API ("L2CAP - L2CA_Register() called for PSM: 0x%04x", psm);
+
+    /* Verify that the required callback info has been filled in
+    **      Note:  Connection callbacks are required but not checked
+    **             for here because it is possible to be only a client
+    **             or only a server.
+    */
+    if ((!p_cb_info->pL2CA_ConfigCfm_Cb)
+     || (!p_cb_info->pL2CA_ConfigInd_Cb)
+     || (!p_cb_info->pL2CA_DataInd_Cb)
+     || (!p_cb_info->pL2CA_DisconnectInd_Cb))
+    {
+        L2CAP_TRACE_ERROR ("L2CAP - no cb registering PSM: 0x%04x", psm);
+        return (0);
+    }
+
+    /* Verify PSM is valid */
+    if (L2C_INVALID_PSM(psm))
+    {
+        L2CAP_TRACE_ERROR ("L2CAP - invalid PSM value, PSM: 0x%04x", psm);
+        return (0);
+    }
+
+    /* Check if this is a registration for an outgoing-only connection to */
+    /* a dynamic PSM. If so, allocate a "virtual" PSM for the app to use. */
+    if ( (psm >= 0x1001) && (p_cb_info->pL2CA_ConnectInd_Cb == NULL) )
+    {
+        for (vpsm = 0x1002; vpsm < 0x8000; vpsm += 2)
+        {
+            if ((p_rcb = l2cu_find_rcb_by_psm (vpsm)) == NULL)
+                break;
+        }
+
+        L2CAP_TRACE_API ("L2CA_Register - Real PSM: 0x%04x  Virtual PSM: 0x%04x", psm, vpsm);
+    }
+
+    /* If registration block already there, just overwrite it */
+    if ((p_rcb = l2cu_find_rcb_by_psm (vpsm)) == NULL)
+    {
+        if ((p_rcb = l2cu_allocate_rcb (vpsm)) == NULL)
+        {
+            L2CAP_TRACE_WARNING ("L2CAP - no RCB available, PSM: 0x%04x  vPSM: 0x%04x", psm, vpsm);
+            return (0);
+        }
+    }
+
+    p_rcb->api      = *p_cb_info;
+    p_rcb->real_psm = psm;
+
+    return (vpsm);
+}
+
+/*******************************************************************************
+**
+** Function         L2CA_Deregister
+**
+** Description      Other layers call this function to de-register for L2CAP
+**                  services.
+**
+** Returns          void
+**
+*******************************************************************************/
+void L2CA_Deregister (uint16_t psm)
+{
+    tL2C_RCB    *p_rcb;
+    tL2C_CCB    *p_ccb;
+    tL2C_LCB    *p_lcb;
+    int         ii;
+
+    L2CAP_TRACE_API ("L2CAP - L2CA_Deregister() called for PSM: 0x%04x", psm);
+
+    if ((p_rcb = l2cu_find_rcb_by_psm (psm)) != NULL)
+    {
+        p_lcb = &l2cb.lcb_pool[0];
+        for (ii = 0; ii < MAX_L2CAP_LINKS; ii++, p_lcb++)
+        {
+            if (p_lcb->in_use)
+            {
+                if (((p_ccb = p_lcb->ccb_queue.p_first_ccb) == NULL)
+                 || (p_lcb->link_state == LST_DISCONNECTING))
+                    continue;
+
+                if ((p_ccb->in_use) &&
+                    ((p_ccb->chnl_state == CST_W4_L2CAP_DISCONNECT_RSP) ||
+                     (p_ccb->chnl_state == CST_W4_L2CA_DISCONNECT_RSP)))
+                    continue;
+
+                if (p_ccb->p_rcb == p_rcb)
+                    l2c_csm_execute (p_ccb, L2CEVT_L2CA_DISCONNECT_REQ, NULL);
+            }
+        }
+        l2cu_release_rcb (p_rcb);
+    }
+    else
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - PSM: 0x%04x not found for deregistration", 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)
+{
+    bool    done = false;
+    uint16_t psm = l2cb.dyn_psm;
+
+    L2CAP_TRACE_API( "L2CA_AllocatePSM");
+    while (!done)
+    {
+        psm += 2;
+        if (psm > 0xfeff)
+        {
+            psm = 0x1001;
+        }
+        else if (psm & 0x0100)
+        {
+            /* the upper byte must be even */
+            psm += 0x0100;
+        }
+
+        /* if psm is in range of reserved BRCM Aware features */
+        if ((BRCM_RESERVED_PSM_START <= psm)&&(psm <= BRCM_RESERVED_PSM_END))
+            continue;
+
+        /* make sure the newlly allocated psm is not used right now */
+        if ((l2cu_find_rcb_by_psm (psm)) == NULL)
+            done = true;
+    }
+    l2cb.dyn_psm = psm;
+
+    return(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 function
+**                  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, BD_ADDR p_bd_addr)
+{
+    return L2CA_ErtmConnectReq (psm, p_bd_addr, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         L2CA_ErtmConnectReq
+**
+** 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 function
+**                  will be invoked when connection establishes or fails.
+**
+**  Parameters:       PSM: L2CAP PSM for the connection
+**                    BD address of the peer
+**                   Enhaced retransmission mode configurations
+
+** Returns          the CID of the connection, or 0 if it failed to start
+**
+*******************************************************************************/
+uint16_t L2CA_ErtmConnectReq (uint16_t psm, BD_ADDR p_bd_addr, tL2CAP_ERTM_INFO *p_ertm_info)
+{
+    tL2C_LCB        *p_lcb;
+    tL2C_CCB        *p_ccb;
+    tL2C_RCB        *p_rcb;
+
+    L2CAP_TRACE_API ("L2CA_ErtmConnectReq()  PSM: 0x%04x  BDA: %08x%04x  p_ertm_info: 0x%08x allowed:0x%x preferred:%d", psm,
+                      (p_bd_addr[0]<<24)+(p_bd_addr[1]<<16)+(p_bd_addr[2]<<8)+p_bd_addr[3],
+                      (p_bd_addr[4]<<8)+p_bd_addr[5], p_ertm_info,
+                      (p_ertm_info) ? p_ertm_info->allowed_modes : 0,
+                      (p_ertm_info) ? p_ertm_info->preferred_mode : 0);
+
+    /* Fail if we have not established communications with the controller */
+    if (!BTM_IsDeviceUp())
+    {
+        L2CAP_TRACE_WARNING ("L2CAP connect req - BTU not ready");
+        return (0);
+    }
+    /* Fail if the PSM is not registered */
+    if ((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no RCB for L2CA_conn_req, PSM: 0x%04x", psm);
+        return (0);
+    }
+
+    /* First, see if we already have a link to the remote */
+    /* assume all ERTM l2cap connection is going over BR/EDR for now */
+    if ((p_lcb = l2cu_find_lcb_by_bd_addr (p_bd_addr, BT_TRANSPORT_BR_EDR)) == NULL)
+    {
+        /* No link. Get an LCB and start link establishment */
+        if ( ((p_lcb = l2cu_allocate_lcb (p_bd_addr, false, BT_TRANSPORT_BR_EDR)) == NULL)
+             /* currently use BR/EDR for ERTM mode l2cap connection */
+         ||  (l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR) == false) )
+        {
+            L2CAP_TRACE_WARNING ("L2CAP - conn not started for PSM: 0x%04x  p_lcb: 0x%08x", psm, p_lcb);
+            return (0);
+        }
+    }
+
+    /* Allocate a channel control block */
+    if ((p_ccb = l2cu_allocate_ccb (p_lcb, 0)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_conn_req, PSM: 0x%04x", psm);
+        return (0);
+    }
+
+    /* Save registration info */
+    p_ccb->p_rcb = p_rcb;
+
+    if (p_ertm_info)
+    {
+        p_ccb->ertm_info  = *p_ertm_info;
+
+        /* Replace default indicators with the actual default pool */
+        if (p_ccb->ertm_info.fcr_rx_buf_size == L2CAP_INVALID_ERM_BUF_SIZE)
+            p_ccb->ertm_info.fcr_rx_buf_size = L2CAP_FCR_RX_BUF_SIZE;
+
+        if (p_ccb->ertm_info.fcr_tx_buf_size == L2CAP_INVALID_ERM_BUF_SIZE)
+            p_ccb->ertm_info.fcr_tx_buf_size = L2CAP_FCR_TX_BUF_SIZE;
+
+        if (p_ccb->ertm_info.user_rx_buf_size == L2CAP_INVALID_ERM_BUF_SIZE)
+            p_ccb->ertm_info.user_rx_buf_size = L2CAP_USER_RX_BUF_SIZE;
+
+        if (p_ccb->ertm_info.user_tx_buf_size == L2CAP_INVALID_ERM_BUF_SIZE)
+            p_ccb->ertm_info.user_tx_buf_size = L2CAP_USER_TX_BUF_SIZE;
+
+        p_ccb->max_rx_mtu = p_ertm_info->user_rx_buf_size -
+            (L2CAP_MIN_OFFSET + L2CAP_SDU_LEN_OFFSET + L2CAP_FCS_LEN);
+    }
+
+    /* If link is up, start the L2CAP connection */
+    if (p_lcb->link_state == LST_CONNECTED)
+    {
+        l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONNECT_REQ, NULL);
+    }
+
+    /* If link is disconnecting, save link info to retry after disconnect
+     * Possible Race condition when a reconnect occurs
+     * on the channel during a disconnect of link. This
+     * ccb will be automatically retried after link disconnect
+     * arrives
+     */
+    else if (p_lcb->link_state == LST_DISCONNECTING)
+    {
+        L2CAP_TRACE_DEBUG ("L2CAP API - link disconnecting: RETRY LATER");
+
+        /* Save ccb so it can be started after disconnect is finished */
+        p_lcb->p_pending_ccb = p_ccb;
+    }
+
+    L2CAP_TRACE_API ("L2CAP - L2CA_conn_req(psm: 0x%04x) returned CID: 0x%04x", psm, p_ccb->local_cid);
+
+    /* Return the local CID as our handle */
+    return (p_ccb->local_cid);
+}
+
+/*******************************************************************************
+**
+** 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 L2CA_DeregisterLECoc()
+**
+*******************************************************************************/
+uint16_t L2CA_RegisterLECoc(uint16_t psm, tL2CAP_APPL_INFO *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
+    **      Note:  Connection callbacks are required but not checked
+    **             for here because it is possible to be only a client
+    **             or only a server.
+    */
+    if ((!p_cb_info->pL2CA_DataInd_Cb)
+     || (!p_cb_info->pL2CA_DisconnectInd_Cb))
+    {
+        L2CAP_TRACE_ERROR("%s No cb registering BLE PSM: 0x%04x", __func__, psm);
+        return 0;
+    }
+
+    /* Verify PSM is valid */
+    if (!L2C_IS_VALID_LE_PSM(psm))
+    {
+        L2CAP_TRACE_ERROR("%s Invalid BLE PSM value, PSM: 0x%04x", __func__, psm);
+        return 0;
+    }
+
+    tL2C_RCB    *p_rcb;
+    uint16_t    vpsm = psm;
+
+    /* Check if this is a registration for an outgoing-only connection to */
+    /* a dynamic PSM. If so, allocate a "virtual" PSM for the app to use. */
+    if ((psm >= 0x0080) && (p_cb_info->pL2CA_ConnectInd_Cb == NULL))
+    {
+        for (vpsm = 0x0080; vpsm < 0x0100; vpsm++)
+        {
+            p_rcb = l2cu_find_ble_rcb_by_psm(vpsm);
+            if (p_rcb == NULL)
+                break;
+        }
+
+        L2CAP_TRACE_API("%s Real PSM: 0x%04x  Virtual PSM: 0x%04x", __func__, psm, vpsm);
+    }
+
+    /* If registration block already there, just overwrite it */
+    p_rcb = l2cu_find_ble_rcb_by_psm(vpsm);
+    if (p_rcb == NULL)
+    {
+        p_rcb = l2cu_allocate_ble_rcb(vpsm);
+        if (p_rcb == NULL)
+        {
+            L2CAP_TRACE_WARNING("%s No BLE RCB available, PSM: 0x%04x  vPSM: 0x%04x",
+                  __func__, psm, vpsm);
+            return 0;
+        }
+    }
+
+    p_rcb->api      = *p_cb_info;
+    p_rcb->real_psm = psm;
+
+    return vpsm;
+}
+
+/*******************************************************************************
+**
+** Function         L2CA_DeregisterLECoc
+**
+** Description      Other layers call this function to de-register for L2CAP
+**                  Connection Oriented Channel.
+**
+** Returns          void
+**
+*******************************************************************************/
+void L2CA_DeregisterLECoc(uint16_t psm)
+{
+    L2CAP_TRACE_API("%s called for PSM: 0x%04x", __func__, psm);
+
+    tL2C_RCB *p_rcb = l2cu_find_ble_rcb_by_psm(psm);
+    if (p_rcb == NULL)
+    {
+        L2CAP_TRACE_WARNING("%s PSM: 0x%04x not found for deregistration", psm);
+        return;
+    }
+
+    tL2C_LCB *p_lcb = &l2cb.lcb_pool[0];
+    for (int i = 0; i < MAX_L2CAP_LINKS; i++, p_lcb++)
+    {
+        if (!p_lcb->in_use || p_lcb->transport != BT_TRANSPORT_LE)
+            continue;
+
+        tL2C_CCB *p_ccb = p_lcb->ccb_queue.p_first_ccb;
+        if ((p_ccb == NULL) || (p_lcb->link_state == LST_DISCONNECTING))
+            continue;
+
+        if (p_ccb->in_use &&
+           (p_ccb->chnl_state == CST_W4_L2CAP_DISCONNECT_RSP ||
+            p_ccb->chnl_state == CST_W4_L2CA_DISCONNECT_RSP))
+            continue;
+
+        if (p_ccb->p_rcb == p_rcb)
+            l2c_csm_execute(p_ccb, L2CEVT_L2CA_DISCONNECT_REQ, NULL);
+    }
+
+    l2cu_release_rcb (p_rcb);
+}
+
+/*******************************************************************************
+**
+** Function         L2CA_ConnectLECocReq
+**
+** 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 function
+**                  will be invoked when connection establishes or fails.
+**
+**  Parameters:     PSM: L2CAP PSM for the connection
+**                  BD address of the peer
+**                  Local Coc configurations
+
+** Returns          the CID of the connection, or 0 if it failed to start
+**
+*******************************************************************************/
+uint16_t L2CA_ConnectLECocReq(uint16_t psm, BD_ADDR p_bd_addr, tL2CAP_LE_CFG_INFO *p_cfg)
+{
+    L2CAP_TRACE_API("%s PSM: 0x%04x BDA: %02x:%02x:%02x:%02x:%02x:%02x", __func__, psm,
+        p_bd_addr[0], p_bd_addr[1], p_bd_addr[2], p_bd_addr[3], p_bd_addr[4], p_bd_addr[5]);
+
+    /* Fail if we have not established communications with the controller */
+    if (!BTM_IsDeviceUp())
+    {
+        L2CAP_TRACE_WARNING("%s BTU not ready", __func__);
+        return 0;
+    }
+
+    /* Fail if the PSM is not registered */
+    tL2C_RCB *p_rcb = l2cu_find_ble_rcb_by_psm(psm);
+    if (p_rcb == NULL)
+    {
+        L2CAP_TRACE_WARNING("%s No BLE RCB, PSM: 0x%04x", __func__, psm);
+        return 0;
+    }
+
+    /* First, see if we already have a le link to the remote */
+    tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(p_bd_addr, BT_TRANSPORT_LE);
+    if (p_lcb == NULL)
+    {
+        /* No link. Get an LCB and start link establishment */
+        p_lcb = l2cu_allocate_lcb(p_bd_addr, false, BT_TRANSPORT_LE);
+        if ((p_lcb == NULL)
+             /* currently use BR/EDR for ERTM mode l2cap connection */
+         || (l2cu_create_conn(p_lcb, BT_TRANSPORT_LE) == false) )
+        {
+            L2CAP_TRACE_WARNING("%s conn not started for PSM: 0x%04x  p_lcb: 0x%08x",
+                __func__, psm, p_lcb);
+            return 0;
+        }
+    }
+
+    /* Allocate a channel control block */
+    tL2C_CCB *p_ccb = l2cu_allocate_ccb(p_lcb, 0);
+    if (p_ccb == NULL)
+    {
+        L2CAP_TRACE_WARNING("%s no CCB, PSM: 0x%04x", __func__, psm);
+        return 0;
+    }
+
+    /* Save registration info */
+    p_ccb->p_rcb = p_rcb;
+
+    /* Save the configuration */
+    if (p_cfg)
+        memcpy(&p_ccb->local_conn_cfg, p_cfg, sizeof(tL2CAP_LE_CFG_INFO));
+
+    /* If link is up, start the L2CAP connection */
+    if (p_lcb->link_state == LST_CONNECTED)
+    {
+        if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
+        {
+            L2CAP_TRACE_DEBUG("%s LE Link is up", __func__);
+            l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_REQ, NULL);
+        }
+    }
+
+    /* If link is disconnecting, save link info to retry after disconnect
+     * Possible Race condition when a reconnect occurs
+     * on the channel during a disconnect of link. This
+     * ccb will be automatically retried after link disconnect
+     * arrives
+     */
+    else if (p_lcb->link_state == LST_DISCONNECTING)
+    {
+        L2CAP_TRACE_DEBUG("%s link disconnecting: RETRY LATER", __func__);
+
+        /* Save ccb so it can be started after disconnect is finished */
+        p_lcb->p_pending_ccb = p_ccb;
+    }
+
+    L2CAP_TRACE_API("%s(psm: 0x%04x) returned CID: 0x%04x", __func__, psm, p_ccb->local_cid);
+
+    /* Return the local CID as our handle */
+    return p_ccb->local_cid;
+}
+
+/*******************************************************************************
+**
+** Function         L2CA_ConnectLECocRsp
+**
+** Description      Higher layers call this function to accept an incoming
+**                  L2CAP COC connection, for which they had gotten an connect
+**                  indication callback.
+**
+** Returns          true for success, false for failure
+**
+*******************************************************************************/
+bool    L2CA_ConnectLECocRsp (BD_ADDR p_bd_addr, uint8_t id, uint16_t lcid, uint16_t result,
+                             uint16_t status, tL2CAP_LE_CFG_INFO *p_cfg)
+{
+    L2CAP_TRACE_API("%s CID: 0x%04x Result: %d Status: %d BDA: %02x:%02x:%02x:%02x:%02x:%02x",
+        __func__, lcid, result, status,
+        p_bd_addr[0], p_bd_addr[1], p_bd_addr[2], p_bd_addr[3], p_bd_addr[4], p_bd_addr[5]);
+
+
+    /* First, find the link control block */
+    tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(p_bd_addr, BT_TRANSPORT_LE);
+    if (p_lcb == NULL)
+    {
+        /* No link. Get an LCB and start link establishment */
+        L2CAP_TRACE_WARNING("%s no LCB", __func__);
+        return false;
+    }
+
+    /* Now, find the channel control block */
+    tL2C_CCB *p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
+    if (p_ccb == NULL)
+    {
+        L2CAP_TRACE_WARNING("%s no CCB", __func__);
+        return false;
+    }
+
+    /* The IDs must match */
+    if (p_ccb->remote_id != id)
+    {
+        L2CAP_TRACE_WARNING("%s bad id. Expected: %d  Got: %d", __func__, p_ccb->remote_id, id);
+        return false;
+    }
+
+    if (p_cfg)
+        memcpy(&p_ccb->local_conn_cfg, p_cfg, sizeof(tL2CAP_LE_CFG_INFO));
+
+    if (result == L2CAP_CONN_OK)
+        l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONNECT_RSP, NULL);
+    else
+    {
+        tL2C_CONN_INFO conn_info;
+        memcpy(conn_info.bd_addr, p_bd_addr, BD_ADDR_LEN);
+        conn_info.l2cap_result = result;
+        conn_info.l2cap_status = status;
+        l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_RSP_NEG, &conn_info);
+    }
+
+    return true;
+}
+
+/*******************************************************************************
+**
+**  Function         L2CA_GetPeerLECocConfig
+**
+**  Description      Get a peers configuration for LE Connection Oriented Channel.
+**
+**  Parameters:      local channel id
+**                   Pointers to peers configuration storage area
+**
+**  Return value:    true if peer is connected
+**
+*******************************************************************************/
+bool    L2CA_GetPeerLECocConfig (uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg)
+{
+    L2CAP_TRACE_API ("%s CID: 0x%04x", __func__, lcid);
+
+    tL2C_CCB *p_ccb = l2cu_find_ccb_by_cid(NULL, lcid);
+    if (p_ccb == NULL)
+    {
+        L2CAP_TRACE_ERROR("%s No CCB for CID:0x%04x", __func__, lcid);
+        return false;
+    }
+
+    if (peer_cfg != NULL)
+        memcpy(peer_cfg, &p_ccb->peer_conn_cfg, sizeof(tL2CAP_LE_CFG_INFO));
+
+    return true;
+}
+
+bool L2CA_SetConnectionCallbacks(uint16_t local_cid, const tL2CAP_APPL_INFO *callbacks) {
+  assert(callbacks != NULL);
+  assert(callbacks->pL2CA_ConnectInd_Cb == NULL);
+  assert(callbacks->pL2CA_ConnectCfm_Cb != NULL);
+  assert(callbacks->pL2CA_ConfigInd_Cb != NULL);
+  assert(callbacks->pL2CA_ConfigCfm_Cb != NULL);
+  assert(callbacks->pL2CA_DisconnectInd_Cb != NULL);
+  assert(callbacks->pL2CA_DisconnectCfm_Cb != NULL);
+  assert(callbacks->pL2CA_CongestionStatus_Cb != NULL);
+  assert(callbacks->pL2CA_DataInd_Cb != NULL);
+  assert(callbacks->pL2CA_TxComplete_Cb != NULL);
+
+  tL2C_CCB *channel_control_block = l2cu_find_ccb_by_cid(NULL, local_cid);
+  if (!channel_control_block) {
+    LOG_ERROR(LOG_TAG, "%s no channel control block found for L2CAP LCID=0x%04x.", __func__, local_cid);
+    return false;
+  }
+
+  // We're making a connection-specific registration control block so we check if
+  // we already have a private one allocated to us on the heap. If not, we make a
+  // new allocation, mark it as heap-allocated, and inherit the fields from the old
+  // control block.
+  tL2C_RCB *registration_control_block = channel_control_block->p_rcb;
+  if (!channel_control_block->should_free_rcb) {
+    registration_control_block = (tL2C_RCB *)osi_calloc(sizeof(tL2C_RCB));
+
+    *registration_control_block = *channel_control_block->p_rcb;
+    channel_control_block->p_rcb = registration_control_block;
+    channel_control_block->should_free_rcb = true;
+  }
+
+  registration_control_block->api = *callbacks;
+  return true;
+}
+
+/*******************************************************************************
+**
+** 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 (BD_ADDR p_bd_addr, uint8_t id, uint16_t lcid,
+                              uint16_t result, uint16_t status)
+{
+    return L2CA_ErtmConnectRsp (p_bd_addr, id, lcid, result, status, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         L2CA_ErtmConnectRsp
+**
+** 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_ErtmConnectRsp (BD_ADDR p_bd_addr, uint8_t id, uint16_t lcid, uint16_t result,
+                             uint16_t status, tL2CAP_ERTM_INFO *p_ertm_info)
+{
+    tL2C_LCB        *p_lcb;
+    tL2C_CCB        *p_ccb;
+
+    L2CAP_TRACE_API ("L2CA_ErtmConnectRsp()  CID: 0x%04x  Result: %d  Status: %d  BDA: %08x%04x  p_ertm_info:0x%08x",
+                      lcid, result, status,
+                      (p_bd_addr[0]<<24)+(p_bd_addr[1]<<16)+(p_bd_addr[2]<<8)+p_bd_addr[3],
+                      (p_bd_addr[4]<<8)+p_bd_addr[5], p_ertm_info);
+
+    /* First, find the link control block */
+    if ((p_lcb = l2cu_find_lcb_by_bd_addr (p_bd_addr, BT_TRANSPORT_BR_EDR)) == NULL)
+    {
+        /* No link. Get an LCB and start link establishment */
+        L2CAP_TRACE_WARNING ("L2CAP - no LCB for L2CA_conn_rsp");
+        return (false);
+    }
+
+    /* Now, find the channel control block */
+    if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_conn_rsp");
+        return (false);
+    }
+
+    /* The IDs must match */
+    if (p_ccb->remote_id != id)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - bad id in L2CA_conn_rsp. Exp: %d  Got: %d", p_ccb->remote_id, id);
+        return (false);
+    }
+
+    if (p_ertm_info)
+    {
+        p_ccb->ertm_info  = *p_ertm_info;
+
+        /* Replace default indicators with the actual default pool */
+        if (p_ccb->ertm_info.fcr_rx_buf_size == L2CAP_INVALID_ERM_BUF_SIZE)
+            p_ccb->ertm_info.fcr_rx_buf_size = L2CAP_FCR_RX_BUF_SIZE;
+
+        if (p_ccb->ertm_info.fcr_tx_buf_size == L2CAP_INVALID_ERM_BUF_SIZE)
+            p_ccb->ertm_info.fcr_tx_buf_size = L2CAP_FCR_TX_BUF_SIZE;
+
+        if (p_ccb->ertm_info.user_rx_buf_size == L2CAP_INVALID_ERM_BUF_SIZE)
+            p_ccb->ertm_info.user_rx_buf_size = L2CAP_USER_RX_BUF_SIZE;
+
+        if (p_ccb->ertm_info.user_tx_buf_size == L2CAP_INVALID_ERM_BUF_SIZE)
+            p_ccb->ertm_info.user_tx_buf_size = L2CAP_USER_TX_BUF_SIZE;
+
+        p_ccb->max_rx_mtu = p_ertm_info->user_rx_buf_size -
+            (L2CAP_MIN_OFFSET + L2CAP_SDU_LEN_OFFSET + L2CAP_FCS_LEN);
+    }
+
+    if (result == L2CAP_CONN_OK)
+    {
+        l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONNECT_RSP, NULL);
+    }
+    else
+    {
+        tL2C_CONN_INFO   conn_info;
+
+        conn_info.l2cap_result = result;
+        conn_info.l2cap_status = status;
+
+        if (result == L2CAP_CONN_PENDING)
+            l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONNECT_RSP, &conn_info);
+        else
+            l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONNECT_RSP_NEG, &conn_info);
+    }
+
+    return (true);
+}
+
+/*******************************************************************************
+**
+** Function         L2CA_ConfigReq
+**
+** Description      Higher layers call this function to send configuration.
+**
+**                  Note:  The FCR options of p_cfg are not used.
+**
+** Returns          true if configuration sent, else false
+**
+*******************************************************************************/
+bool    L2CA_ConfigReq (uint16_t cid, tL2CAP_CFG_INFO *p_cfg)
+{
+    tL2C_CCB        *p_ccb;
+
+    L2CAP_TRACE_API ("L2CA_ConfigReq()  CID 0x%04x: fcr_present:%d (mode %d) mtu_present:%d (%d)",
+        cid, p_cfg->fcr_present, p_cfg->fcr.mode, p_cfg->mtu_present, p_cfg->mtu);
+
+    /* Find the channel control block. We don't know the link it is on. */
+    if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_cfg_req, CID: %d", cid);
+        return (false);
+    }
+
+    /* We need to have at least one mode type common with the peer */
+    if (!l2c_fcr_adj_our_req_options(p_ccb, p_cfg))
+        return (false);
+
+    /* Don't adjust FCR options if not used */
+    if ((!p_cfg->fcr_present)||(p_cfg->fcr.mode == L2CAP_FCR_BASIC_MODE))
+    {
+        /* FCR and FCS options are not used in basic mode */
+        p_cfg->fcs_present = false;
+        p_cfg->ext_flow_spec_present = false;
+
+        if ( (p_cfg->mtu_present) && (p_cfg->mtu > L2CAP_MTU_SIZE) )
+        {
+            L2CAP_TRACE_WARNING ("L2CAP - adjust MTU: %u too large", p_cfg->mtu);
+            p_cfg->mtu = L2CAP_MTU_SIZE;
+        }
+    }
+
+    /* Save the adjusted configuration in case it needs to be used for renegotiation */
+    p_ccb->our_cfg = *p_cfg;
+
+    l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONFIG_REQ, p_cfg);
+
+    return (true);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    tL2C_CCB        *p_ccb;
+
+    L2CAP_TRACE_API ("L2CA_ConfigRsp()  CID: 0x%04x  Result: %d MTU present:%d Flush TO:%d FCR:%d FCS:%d",
+        cid, p_cfg->result, p_cfg->mtu_present, p_cfg->flush_to_present, p_cfg->fcr_present, p_cfg->fcs_present);
+
+    /* Find the channel control block. We don't know the link it is on. */
+    if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_cfg_rsp, CID: %d", cid);
+        return (false);
+    }
+
+    if ( (p_cfg->result == L2CAP_CFG_OK) || (p_cfg->result == L2CAP_CFG_PENDING) )
+        l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONFIG_RSP, p_cfg);
+    else
+    {
+        p_cfg->fcr_present = false; /* FCR options already negotiated before this point */
+
+        /* Clear out any cached options that are being returned as an error (excluding FCR) */
+        if (p_cfg->mtu_present)
+            p_ccb->peer_cfg.mtu_present = false;
+        if (p_cfg->flush_to_present)
+            p_ccb->peer_cfg.flush_to_present = false;
+        if (p_cfg->qos_present)
+            p_ccb->peer_cfg.qos_present = false;
+
+        l2c_csm_execute (p_ccb, L2CEVT_L2CA_CONFIG_RSP_NEG, p_cfg);
+    }
+
+    return (true);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    tL2C_CCB        *p_ccb;
+
+    L2CAP_TRACE_API ("L2CA_DisconnectReq()  CID: 0x%04x", cid);
+
+    /* Find the channel control block. We don't know the link it is on. */
+    if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_disc_req, CID: %d", cid);
+        return (false);
+    }
+
+    l2c_csm_execute (p_ccb, L2CEVT_L2CA_DISCONNECT_REQ, NULL);
+
+    return (true);
+}
+
+/*******************************************************************************
+**
+** Function         L2CA_DisconnectRsp
+**
+** Description      Higher layers call this function to acknowledge the
+**                  disconnection of a channel.
+**
+** Returns          void
+**
+*******************************************************************************/
+bool    L2CA_DisconnectRsp (uint16_t cid)
+{
+    tL2C_CCB        *p_ccb;
+
+    L2CAP_TRACE_API ("L2CA_DisconnectRsp()  CID: 0x%04x", cid);
+
+    /* Find the channel control block. We don't know the link it is on. */
+    if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_disc_rsp, CID: %d", cid);
+        return (false);
+    }
+
+    l2c_csm_execute (p_ccb, L2CEVT_L2CA_DISCONNECT_RSP, NULL);
+
+    return (true);
+}
+
+/*******************************************************************************
+**
+** 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 (BD_ADDR p_bd_addr, tL2CA_ECHO_RSP_CB *p_callback)
+{
+    tL2C_LCB        *p_lcb;
+
+    L2CAP_TRACE_API ("L2CA_Ping()  BDA: %02x-%02x-%02x-%02x-%02x-%02x",
+                      p_bd_addr[0], p_bd_addr[1], p_bd_addr[2], p_bd_addr[3], p_bd_addr[4], p_bd_addr[5]);
+
+    /* Fail if we have not established communications with the controller */
+    if (!BTM_IsDeviceUp())
+        return (false);
+
+    /* First, see if we already have a link to the remote */
+    if ((p_lcb = l2cu_find_lcb_by_bd_addr (p_bd_addr, BT_TRANSPORT_BR_EDR)) == NULL)
+    {
+        /* No link. Get an LCB and start link establishment */
+        if ((p_lcb = l2cu_allocate_lcb (p_bd_addr, false, BT_TRANSPORT_BR_EDR)) == NULL)
+        {
+            L2CAP_TRACE_WARNING ("L2CAP - no LCB for L2CA_ping");
+            return (false);
+        }
+        if (l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR) == false)
+        {
+            return (false);
+        }
+
+        p_lcb->p_echo_rsp_cb = p_callback;
+
+        return (true);
+    }
+
+    /* We only allow 1 ping outstanding at a time */
+    if (p_lcb->p_echo_rsp_cb != NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - rejected second L2CA_ping");
+        return (false);
+    }
+
+    /* Have a link control block. If link is disconnecting, tell user to retry later */
+    if (p_lcb->link_state == LST_DISCONNECTING)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - L2CA_ping rejected - link disconnecting");
+        return (false);
+    }
+
+    /* Save address of callback */
+    p_lcb->p_echo_rsp_cb = p_callback;
+
+    if (p_lcb->link_state == LST_CONNECTED)
+    {
+        l2cu_adj_id(p_lcb, L2CAP_ADJ_BRCM_ID);  /* Make sure not using Broadcom ID */
+        l2cu_send_peer_echo_req (p_lcb, NULL, 0);
+        alarm_set_on_queue(p_lcb->l2c_lcb_timer,
+                           L2CAP_ECHO_RSP_TIMEOUT_MS,
+                           l2c_lcb_timer_timeout, p_lcb,
+                           btu_general_alarm_queue);
+    }
+
+    return (true);
+}
+
+/*******************************************************************************
+**
+** 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 (BD_ADDR p_bd_addr, BT_HDR *p_data, tL2CA_ECHO_DATA_CB *p_callback)
+{
+    tL2C_LCB    *p_lcb;
+    uint8_t     *pp;
+
+    L2CAP_TRACE_API ("L2CA_Echo() BDA: %08X%04X",
+            ((p_bd_addr[0] << 24) + (p_bd_addr[1] << 16) + (p_bd_addr[2] <<  8) + (p_bd_addr[3])),
+            ((p_bd_addr[4] <<  8) + (p_bd_addr[5])));
+
+    /* Fail if we have not established communications with the controller */
+    if (!BTM_IsDeviceUp())
+        return (false);
+
+    if ((memcmp(BT_BD_ANY, p_bd_addr, BD_ADDR_LEN) == 0) && (p_data == NULL))
+    {
+        /* Only register callback without sending message. */
+        l2cb.p_echo_data_cb = p_callback;
+        return true;
+    }
+
+    /* We assume the upper layer will call this function only when the link is established. */
+    if ((p_lcb = l2cu_find_lcb_by_bd_addr (p_bd_addr, BT_TRANSPORT_BR_EDR)) == NULL)
+    {
+        L2CAP_TRACE_ERROR ("L2CA_Echo ERROR : link not established");
+        return false;
+    }
+
+    if (p_lcb->link_state != LST_CONNECTED)
+    {
+        L2CAP_TRACE_ERROR ("L2CA_Echo ERROR : link is not connected");
+        return false;
+    }
+
+    /* Save address of callback */
+    l2cb.p_echo_data_cb = p_callback;
+
+    /* Set the pointer to the beginning of the data */
+    pp = (uint8_t *)(p_data + 1) + p_data->offset;
+    l2cu_adj_id(p_lcb, L2CAP_ADJ_BRCM_ID);  /* Make sure not using Broadcom ID */
+    l2cu_send_peer_echo_req (p_lcb, pp, p_data->len);
+
+    return (true);
+
+}
+
+bool L2CA_GetIdentifiers(uint16_t lcid, uint16_t *rcid, uint16_t *handle) {
+  tL2C_CCB *control_block = l2cu_find_ccb_by_cid(NULL, lcid);
+  if (!control_block)
+    return false;
+
+  if (rcid)
+    *rcid = control_block->remote_cid;
+  if (handle)
+    *handle = control_block->p_lcb->handle;
+
+  return true;
+}
+
+/*******************************************************************************
+**
+** 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
+**
+** NOTE             This timeout takes effect after at least 1 channel has been
+**                  established and removed. L2CAP maintains its own timer from
+**                  whan a connection is established till the first channel is
+**                  set up.
+*******************************************************************************/
+bool    L2CA_SetIdleTimeout (uint16_t cid, uint16_t timeout, bool    is_global)
+{
+    tL2C_CCB        *p_ccb;
+    tL2C_LCB        *p_lcb;
+
+    if (is_global)
+    {
+        l2cb.idle_timeout = timeout;
+    }
+    else
+    {
+        /* Find the channel control block. We don't know the link it is on. */
+        if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+        {
+            L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_SetIdleTimeout, CID: %d", cid);
+            return (false);
+        }
+
+        p_lcb = p_ccb->p_lcb;
+
+        if ((p_lcb) && (p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTED))
+            p_lcb->idle_timeout = timeout;
+        else
+            return (false);
+    }
+
+    return (true);
+}
+
+/*******************************************************************************
+**
+** 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 = BT_BD_ANY,
+**                  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(BD_ADDR bd_addr, uint16_t timeout, tBT_TRANSPORT transport)
+{
+    tL2C_LCB        *p_lcb;
+
+    if (memcmp (BT_BD_ANY, bd_addr, BD_ADDR_LEN))
+    {
+        p_lcb = l2cu_find_lcb_by_bd_addr( bd_addr, transport);
+        if ((p_lcb) && (p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTED))
+        {
+            p_lcb->idle_timeout = timeout;
+
+            if (!p_lcb->ccb_queue.p_first_ccb)
+                l2cu_no_dynamic_ccbs (p_lcb);
+        }
+        else
+            return false;
+    }
+    else
+    {
+        int         xx;
+        tL2C_LCB    *p_lcb = &l2cb.lcb_pool[0];
+
+        for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
+        {
+            if ((p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTED))
+            {
+                p_lcb->idle_timeout = timeout;
+
+                if (!p_lcb->ccb_queue.p_first_ccb)
+                    l2cu_no_dynamic_ccbs (p_lcb);
+            }
+        }
+    }
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** 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 new_level)
+{
+    if (new_level != 0xFF)
+        l2cb.l2cap_trace_level = new_level;
+
+    return (l2cb.l2cap_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)
+{
+    L2CAP_TRACE_API ("L2CA_SetDesireRole() new:x%x, disallow_switch:%d",
+        new_role, l2cb.disallow_switch);
+
+    if (L2CAP_ROLE_CHECK_SWITCH != (L2CAP_ROLE_CHECK_SWITCH & new_role))
+    {
+        /* do not process the allow_switch when both bits are set */
+        if (new_role & L2CAP_ROLE_ALLOW_SWITCH)
+        {
+            l2cb.disallow_switch = false;
+        }
+        if (new_role & L2CAP_ROLE_DISALLOW_SWITCH)
+        {
+            l2cb.disallow_switch = true;
+        }
+    }
+
+    if (new_role == HCI_ROLE_MASTER || new_role == HCI_ROLE_SLAVE)
+        l2cb.desire_role = new_role;
+
+    return (l2cb.desire_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, BD_ADDR p_bd_addr)
+{
+    tL2C_LCB        *p_lcb;
+    tL2C_CCB        *p_ccb;
+    tL2C_RCB        *p_rcb;
+
+    L2CAP_TRACE_API ("L2CA_LocalLoopbackReq()  PSM: %d  Handle: 0x%04x", psm, handle);
+
+    /* Fail if we have not established communications with the controller */
+    if (!BTM_IsDeviceUp())
+    {
+        L2CAP_TRACE_WARNING ("L2CAP loop req - BTU not ready");
+        return (0);
+    }
+
+    /* Fail if the PSM is not registered */
+    if ((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no RCB for L2CA_conn_req, PSM: %d", psm);
+        return (0);
+    }
+
+    if ((p_lcb = l2cu_allocate_lcb (p_bd_addr, false, BT_TRANSPORT_BR_EDR)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no LCB for L2CA_conn_req");
+        return (0);
+    }
+
+    p_lcb->link_state = LST_CONNECTED;
+    p_lcb->handle     = handle;
+
+    /* Allocate a channel control block */
+    if ((p_ccb = l2cu_allocate_ccb (p_lcb, 0)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_conn_req");
+        return (0);
+    }
+
+    /* Save registration info */
+    p_ccb->p_rcb        = p_rcb;
+    p_ccb->chnl_state   = CST_OPEN;
+    p_ccb->remote_cid   = p_ccb->local_cid;
+    p_ccb->config_done  = CFG_DONE_MASK;
+
+    /* Return the local CID as our handle */
+    return (p_ccb->local_cid);
+}
+
+/*******************************************************************************
+**
+** Function         L2CA_SetAclPriority
+**
+** Description      Sets the transmission priority for a 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 (BD_ADDR bd_addr, uint8_t priority)
+{
+    L2CAP_TRACE_API ("L2CA_SetAclPriority()  bdaddr: %02x%02x%02x%02x%04x, priority:%d",
+                    bd_addr[0], bd_addr[1], bd_addr[2],
+                    bd_addr[3], (bd_addr[4] << 8) + bd_addr[5], priority);
+
+    return (l2cu_set_acl_priority(bd_addr, priority, false));
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    tL2C_CCB  *p_ccb;
+    bool      on_off = !data_enabled;
+
+    L2CAP_TRACE_API ("L2CA_FlowControl(%d)  CID: 0x%04x", on_off, cid);
+
+    /* Find the channel control block. We don't know the link it is on. */
+    if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_FlowControl, CID: 0x%04x  data_enabled: %d", cid, data_enabled);
+        return (false);
+    }
+
+    if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_ERTM_MODE)
+    {
+        L2CAP_TRACE_EVENT ("L2CA_FlowControl()  invalid mode:%d", p_ccb->peer_cfg.fcr.mode);
+        return (false);
+    }
+    if (p_ccb->fcrb.local_busy != on_off)
+    {
+        p_ccb->fcrb.local_busy = on_off;
+
+        if ( (p_ccb->chnl_state == CST_OPEN) && (!p_ccb->fcrb.wait_ack) )
+        {
+            if (on_off)
+                l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, 0);
+            else
+                l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_P_BIT);
+        }
+    }
+
+    return (true);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    tL2C_CCB        *p_ccb;
+
+    L2CAP_TRACE_API ("L2CA_SendTestSFrame()  CID: 0x%04x  Type: 0x%02x  back_track: %u", cid, sup_type, back_track);
+
+    /* Find the channel control block. We don't know the link it is on. */
+    if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_SendTestSFrame, CID: %d", cid);
+        return (false);
+    }
+
+    if ( (p_ccb->chnl_state != CST_OPEN) || (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_ERTM_MODE) )
+        return (false);
+
+    p_ccb->fcrb.next_seq_expected -= back_track;
+
+    l2c_fcr_send_S_frame (p_ccb, (uint16_t)(sup_type & 3), (uint16_t)(sup_type & (L2CAP_FCR_P_BIT | L2CAP_FCR_F_BIT)));
+
+    return (true);
+}
+
+/*******************************************************************************
+**
+** Function         L2CA_SetTxPriority
+**
+** Description      Sets the transmission priority for a channel.
+**
+** Returns          true if a valid channel, else false
+**
+*******************************************************************************/
+bool    L2CA_SetTxPriority (uint16_t cid, tL2CAP_CHNL_PRIORITY priority)
+{
+    tL2C_CCB        *p_ccb;
+
+    L2CAP_TRACE_API ("L2CA_SetTxPriority()  CID: 0x%04x, priority:%d", cid, priority);
+
+    /* Find the channel control block. We don't know the link it is on. */
+    if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_SetTxPriority, CID: %d", cid);
+        return (false);
+    }
+
+    /* it will update the order of CCB in LCB by priority and update round robin service variables */
+    l2cu_change_pri_ccb (p_ccb, priority);
+
+    return (true);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    tL2C_CCB        *p_ccb;
+
+    L2CAP_TRACE_API ("L2CA_SetChnlDataRate()  CID: 0x%04x, tx:%d, rx:%d", cid, tx, rx);
+
+    /* Find the channel control block. We don't know the link it is on. */
+    if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_SetChnlDataRate, CID: %d", cid);
+        return (false);
+    }
+
+    p_ccb->tx_data_rate = tx;
+    p_ccb->rx_data_rate = rx;
+
+    /* Adjust channel buffer allocation */
+    l2c_link_adjust_chnl_allocation ();
+
+    return(true);
+}
+
+/*******************************************************************************
+**
+** 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_AUTO_FLUSH_TOUT (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 (BD_ADDR bd_addr, uint16_t flush_tout)
+{
+    tL2C_LCB    *p_lcb;
+    uint16_t    hci_flush_to;
+    uint32_t    temp;
+
+    /* no automatic flush (infinite timeout) */
+    if (flush_tout == 0x0000)
+    {
+        hci_flush_to = flush_tout;
+        flush_tout   = L2CAP_NO_AUTOMATIC_FLUSH;
+    }
+    /* no retransmission */
+    else if (flush_tout == L2CAP_NO_RETRANSMISSION)
+    {
+        /* not mandatory range for controller */
+        /* Packet is flushed before getting any ACK/NACK */
+        /* To do this, flush timeout should be 1 baseband slot */
+        hci_flush_to = flush_tout;
+    }
+    /* no automatic flush (infinite timeout) */
+    else if (flush_tout == L2CAP_NO_AUTOMATIC_FLUSH)
+    {
+        hci_flush_to = 0x0000;
+    }
+    else
+    {
+        /* convert L2CAP flush_to to 0.625 ms units, with round */
+        temp = (((uint32_t)flush_tout * 8) + 3) / 5;
+
+        /* if L2CAP flush_to within range of HCI, set HCI flush timeout */
+        if (temp > HCI_MAX_AUTO_FLUSH_TOUT)
+        {
+            L2CAP_TRACE_WARNING("WARNING L2CA_SetFlushTimeout timeout(0x%x) is out of range", flush_tout);
+            return false;
+        }
+        else
+        {
+            hci_flush_to = (uint16_t)temp;
+        }
+    }
+
+    if (memcmp (BT_BD_ANY, bd_addr, BD_ADDR_LEN))
+    {
+        p_lcb = l2cu_find_lcb_by_bd_addr (bd_addr, BT_TRANSPORT_BR_EDR);
+
+        if ((p_lcb) && (p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTED))
+        {
+            if (p_lcb->link_flush_tout != flush_tout)
+            {
+                p_lcb->link_flush_tout = flush_tout;
+
+                L2CAP_TRACE_API ("L2CA_SetFlushTimeout 0x%04x ms for bd_addr [...;%02x%02x%02x]",
+                                  flush_tout, bd_addr[3], bd_addr[4], bd_addr[5]);
+
+                btsnd_hcic_write_auto_flush_tout(p_lcb->handle, hci_flush_to);
+            }
+        }
+        else
+        {
+            L2CAP_TRACE_WARNING ("WARNING L2CA_SetFlushTimeout No lcb for bd_addr [...;%02x%02x%02x]",
+                                  bd_addr[3], bd_addr[4], bd_addr[5]);
+            return (false);
+        }
+    }
+    else
+    {
+        int   xx;
+        p_lcb = &l2cb.lcb_pool[0];
+
+        for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
+        {
+            if ((p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTED))
+            {
+                if (p_lcb->link_flush_tout != flush_tout)
+                {
+                    p_lcb->link_flush_tout = flush_tout;
+
+                    L2CAP_TRACE_API ("L2CA_SetFlushTimeout 0x%04x ms for bd_addr [...;%02x%02x%02x]",
+                                      flush_tout, p_lcb->remote_bd_addr[3],
+                                      p_lcb->remote_bd_addr[4], p_lcb->remote_bd_addr[5]);
+
+                    btsnd_hcic_write_auto_flush_tout(p_lcb->handle, hci_flush_to);
+                }
+            }
+        }
+    }
+
+    return (true);
+}
+
+/*******************************************************************************
+**
+**  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 (BD_ADDR bd_addr, uint32_t *p_ext_feat, uint8_t *p_chnl_mask)
+{
+    tL2C_LCB        *p_lcb;
+
+    /* We must already have a link to the remote */
+    if ((p_lcb = l2cu_find_lcb_by_bd_addr (bd_addr, BT_TRANSPORT_BR_EDR)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CA_GetPeerFeatures() No BDA: %08x%04x",
+                              (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
+                              (bd_addr[4]<<8)+bd_addr[5]);
+        return (false);
+    }
+
+    L2CAP_TRACE_API ("L2CA_GetPeerFeatures() BDA: %08x%04x  ExtFea: 0x%08x  Chnl_Mask[0]: 0x%02x",
+                      (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
+                      (bd_addr[4]<<8)+bd_addr[5], p_lcb->peer_ext_fea, p_lcb->peer_chnl_mask[0]);
+
+    *p_ext_feat = p_lcb->peer_ext_fea;
+
+    memcpy (p_chnl_mask, p_lcb->peer_chnl_mask, L2CAP_FIXED_CHNL_ARRAY_SIZE);
+
+    return (true);
+}
+
+/*******************************************************************************
+**
+**  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, BD_ADDR bd_addr)
+{
+    tL2C_LCB *p_lcb = NULL;
+    bool    found_dev = false;
+
+    p_lcb = l2cu_find_lcb_by_handle (handle);
+    if (p_lcb)
+    {
+        found_dev = true;
+        memcpy (bd_addr, p_lcb->remote_bd_addr, BD_ADDR_LEN);
+    }
+
+    return found_dev;
+}
+
+/*******************************************************************************
+**
+**  Function         L2CA_GetChnlFcrMode
+**
+**  Description      Get the channel FCR mode
+**
+**  Parameters:      Local CID
+**
+**  Return value:    Channel mode
+**
+*******************************************************************************/
+uint8_t L2CA_GetChnlFcrMode (uint16_t lcid)
+{
+    tL2C_CCB    *p_ccb = l2cu_find_ccb_by_cid (NULL, lcid);
+
+    if (p_ccb)
+    {
+        L2CAP_TRACE_API ("L2CA_GetChnlFcrMode() returns mode %d", p_ccb->peer_cfg.fcr.mode);
+        return (p_ccb->peer_cfg.fcr.mode);
+    }
+
+    L2CAP_TRACE_API ("L2CA_GetChnlFcrMode() returns mode L2CAP_FCR_BASIC_MODE");
+    return (L2CAP_FCR_BASIC_MODE);
+}
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+/*******************************************************************************
+**
+**  Function        L2CA_RegisterFixedChannel
+**
+**  Description     Register a fixed channel.
+**
+**  Parameters:     Fixed Channel #
+**                  Channel Callbacks and config
+**
+**  Return value:   -
+**
+*******************************************************************************/
+bool     L2CA_RegisterFixedChannel (uint16_t fixed_cid, tL2CAP_FIXED_CHNL_REG *p_freg)
+{
+    if ( (fixed_cid < L2CAP_FIRST_FIXED_CHNL) || (fixed_cid > L2CAP_LAST_FIXED_CHNL) )
+    {
+        L2CAP_TRACE_ERROR ("L2CA_RegisterFixedChannel()  Invalid CID: 0x%04x", fixed_cid);
+
+        return (false);
+    }
+
+    l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL] = *p_freg;
+    return (true);
+}
+
+/*******************************************************************************
+**
+**  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, BD_ADDR rem_bda)
+{
+    tL2C_LCB *p_lcb;
+    tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+
+    L2CAP_TRACE_API  ("%s() CID: 0x%04x  BDA: %08x%04x", __func__, fixed_cid,
+          (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]);
+
+    // Check CID is valid and registered
+    if ( (fixed_cid < L2CAP_FIRST_FIXED_CHNL) || (fixed_cid > L2CAP_LAST_FIXED_CHNL)
+     ||  (l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb == NULL) )
+    {
+        L2CAP_TRACE_ERROR ("%s() Invalid CID: 0x%04x", __func__, fixed_cid);
+        return (false);
+    }
+
+    // Fail if BT is not yet up
+    if (!BTM_IsDeviceUp())
+    {
+        L2CAP_TRACE_WARNING ("%s(0x%04x) - BTU not ready", __func__, fixed_cid);
+        return (false);
+    }
+
+#if (BLE_INCLUDED == TRUE)
+    if (fixed_cid >= L2CAP_ATT_CID && fixed_cid <= L2CAP_SMP_CID)
+        transport = BT_TRANSPORT_LE;
+#endif
+
+    tL2C_BLE_FIXED_CHNLS_MASK peer_channel_mask;
+
+    // If we already have a link to the remote, check if it supports that CID
+    if ((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, transport)) != NULL)
+    {
+        // Fixed channels are mandatory on LE transports so ignore the received
+        // channel mask and use the locally cached LE channel mask.
+
+#if (BLE_INCLUDED == TRUE)
+        if (transport == BT_TRANSPORT_LE)
+            peer_channel_mask = l2cb.l2c_ble_fixed_chnls_mask;
+        else
+#endif
+            peer_channel_mask = p_lcb->peer_chnl_mask[0];
+
+        // Check for supported channel
+        if (!(peer_channel_mask & (1 << fixed_cid)))
+        {
+            L2CAP_TRACE_EVENT  ("%s() CID:0x%04x  BDA: %08x%04x not supported", __func__,
+                fixed_cid,(rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3],
+                (rem_bda[4]<<8)+rem_bda[5]);
+            return false;
+        }
+
+        // Get a CCB and link the lcb to it
+        if (!l2cu_initialize_fixed_ccb (p_lcb, fixed_cid,
+            &l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
+        {
+            L2CAP_TRACE_WARNING ("%s(0x%04x) - LCB but no CCB", __func__, fixed_cid);
+            return false;
+        }
+
+        // racing with disconnecting, queue the connection request
+        if (p_lcb->link_state == LST_DISCONNECTING)
+        {
+            L2CAP_TRACE_DEBUG ("$s() - link disconnecting: RETRY LATER", __func__);
+            /* Save ccb so it can be started after disconnect is finished */
+            p_lcb->p_pending_ccb = p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL];
+            return true;
+        }
+
+#if (BLE_INCLUDED == TRUE)
+        (*l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedConn_Cb)
+        (fixed_cid,p_lcb->remote_bd_addr, true, 0, p_lcb->transport);
+#else
+        (*l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedConn_Cb)
+        (fixed_cid, p_lcb->remote_bd_addr, true, 0, BT_TRANSPORT_BR_EDR);
+#endif
+        return true;
+    }
+
+    // No link. Get an LCB and start link establishment
+    if ((p_lcb = l2cu_allocate_lcb (rem_bda, false, transport)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("%s(0x%04x) - no LCB", __func__, fixed_cid);
+        return false;
+    }
+
+    // Get a CCB and link the lcb to it
+    if (!l2cu_initialize_fixed_ccb (p_lcb, fixed_cid,
+        &l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
+    {
+        p_lcb->disc_reason = L2CAP_CONN_NO_RESOURCES;
+        L2CAP_TRACE_WARNING ("%s(0x%04x) - no CCB", __func__, fixed_cid);
+        l2cu_release_lcb (p_lcb);
+        return false;
+    }
+
+    if (!l2cu_create_conn(p_lcb, transport))
+    {
+        L2CAP_TRACE_WARNING ("%s() - create_conn failed", __func__);
+        l2cu_release_lcb (p_lcb);
+        return false;
+    }
+    return true;
+}
+
+/*******************************************************************************
+**
+**  Function        L2CA_SendFixedChnlData
+**
+**  Description     Write data on a fixed 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, BD_ADDR rem_bda, BT_HDR *p_buf)
+{
+    tL2C_LCB        *p_lcb;
+    tBT_TRANSPORT   transport = BT_TRANSPORT_BR_EDR;
+
+    L2CAP_TRACE_API ("L2CA_SendFixedChnlData()  CID: 0x%04x  BDA: %08x%04x", fixed_cid,
+                     (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]);
+
+#if (BLE_INCLUDED == TRUE)
+    if (fixed_cid >= L2CAP_ATT_CID && fixed_cid <= L2CAP_SMP_CID)
+        transport = BT_TRANSPORT_LE;
+#endif
+
+    // Check CID is valid and registered
+    if ( (fixed_cid < L2CAP_FIRST_FIXED_CHNL) || (fixed_cid > L2CAP_LAST_FIXED_CHNL)
+     ||  (l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb == NULL) )
+    {
+        L2CAP_TRACE_ERROR ("L2CA_SendFixedChnlData()  Invalid CID: 0x%04x", fixed_cid);
+        osi_free(p_buf);
+        return (L2CAP_DW_FAILED);
+    }
+
+    // Fail if BT is not yet up
+    if (!BTM_IsDeviceUp())
+    {
+        L2CAP_TRACE_WARNING ("L2CA_SendFixedChnlData(0x%04x) - BTU not ready", fixed_cid);
+        osi_free(p_buf);
+        return (L2CAP_DW_FAILED);
+    }
+
+    // We need to have a link up
+    if ((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, transport)) == NULL ||
+        /* if link is disconnecting, also report data sending failure */
+        p_lcb->link_state == LST_DISCONNECTING)
+    {
+        L2CAP_TRACE_WARNING ("L2CA_SendFixedChnlData(0x%04x) - no LCB", fixed_cid);
+        osi_free(p_buf);
+        return (L2CAP_DW_FAILED);
+    }
+
+    tL2C_BLE_FIXED_CHNLS_MASK peer_channel_mask;
+
+    // Select peer channels mask to use depending on transport
+#if (BLE_INCLUDED == TRUE)
+    if (transport == BT_TRANSPORT_LE)
+        peer_channel_mask = l2cb.l2c_ble_fixed_chnls_mask;
+    else
+#endif
+        peer_channel_mask = p_lcb->peer_chnl_mask[0];
+
+    if ((peer_channel_mask & (1 << fixed_cid)) == 0)
+    {
+        L2CAP_TRACE_WARNING ("L2CA_SendFixedChnlData() - peer does not support fixed chnl: 0x%04x", fixed_cid);
+        osi_free(p_buf);
+        return (L2CAP_DW_FAILED);
+    }
+
+    p_buf->event = 0;
+    p_buf->layer_specific = L2CAP_FLUSHABLE_CH_BASED;
+
+    if (!p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL])
+    {
+        if (!l2cu_initialize_fixed_ccb (p_lcb, fixed_cid, &l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
+        {
+            L2CAP_TRACE_WARNING ("L2CA_SendFixedChnlData() - no CCB for chnl: 0x%4x", fixed_cid);
+            osi_free(p_buf);
+            return (L2CAP_DW_FAILED);
+        }
+    }
+
+    // If already congested, do not accept any more packets
+    if (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->cong_sent)
+    {
+        L2CAP_TRACE_ERROR ("L2CAP - CID: 0x%04x cannot send, already congested \
+            xmit_hold_q.count: %u buff_quota: %u", fixed_cid,
+            fixed_queue_length(p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->xmit_hold_q),
+            p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->buff_quota);
+        osi_free(p_buf);
+        return (L2CAP_DW_FAILED);
+    }
+
+    l2c_enqueue_peer_data (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL], p_buf);
+
+    l2c_link_check_send_pkts (p_lcb, NULL, NULL);
+
+    // If there is no dynamic CCB on the link, restart the idle timer each time something is sent
+    if (p_lcb->in_use && p_lcb->link_state == LST_CONNECTED && !p_lcb->ccb_queue.p_first_ccb)
+    {
+        l2cu_no_dynamic_ccbs (p_lcb);
+    }
+
+    if (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->cong_sent)
+        return (L2CAP_DW_CONGESTED);
+
+    return (L2CAP_DW_SUCCESS);
+}
+
+/*******************************************************************************
+**
+**  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, BD_ADDR rem_bda)
+{
+    tL2C_LCB    *p_lcb;
+    tL2C_CCB    *p_ccb;
+    tBT_TRANSPORT   transport = BT_TRANSPORT_BR_EDR;
+
+    /* Check CID is valid and registered */
+    if ( (fixed_cid < L2CAP_FIRST_FIXED_CHNL) || (fixed_cid > L2CAP_LAST_FIXED_CHNL)
+     ||  (l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb == NULL) )
+    {
+        L2CAP_TRACE_ERROR ("L2CA_RemoveFixedChnl()  Invalid CID: 0x%04x", fixed_cid);
+        return (false);
+    }
+
+#if (BLE_INCLUDED == TRUE)
+    if (fixed_cid >= L2CAP_ATT_CID && fixed_cid <= L2CAP_SMP_CID)
+        transport = BT_TRANSPORT_LE;
+#endif
+
+    /* Is a fixed channel connected to the remote BDA ?*/
+    p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, transport);
+
+    if ( ((p_lcb) == NULL) || (!p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]) )
+    {
+        L2CAP_TRACE_WARNING ("L2CA_RemoveFixedChnl()  CID: 0x%04x  BDA: %08x%04x not connected", fixed_cid,
+                             (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]);
+        return (false);
+    }
+
+    L2CAP_TRACE_API ("L2CA_RemoveFixedChnl()  CID: 0x%04x  BDA: %08x%04x", fixed_cid,
+                      (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]);
+
+    /* Release the CCB, starting an inactivity timeout on the LCB if no other CCBs exist */
+    p_ccb = p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL];
+
+    p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL] = NULL;
+    p_lcb->disc_reason = HCI_ERR_CONN_CAUSE_LOCAL_HOST;
+
+#if (BLE_INCLUDED == TRUE)
+    // Retain the link for a few more seconds after SMP pairing is done, since the Android
+    // platform always does service discovery after pairing is complete. This will avoid
+    // the link down (pairing is complete) and an immediate re-connection for service
+    // discovery.
+    // Some devices do not do auto advertising when link is dropped, thus fail the second
+    // connection and service discovery.
+    if ((fixed_cid == L2CAP_ATT_CID ) && !p_lcb->ccb_queue.p_first_ccb)
+        p_lcb->idle_timeout = 0;
+#endif
+
+    l2cu_release_ccb (p_ccb);
+
+    return (true);
+}
+
+/*******************************************************************************
+**
+** 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 = BT_BD_ANY,
+**                  then the idle timeouts for all active l2cap links will be
+**                  changed.
+**
+** Returns          true if command succeeded, false if failed
+**
+*******************************************************************************/
+bool    L2CA_SetFixedChannelTout (BD_ADDR rem_bda, uint16_t fixed_cid, uint16_t idle_tout)
+{
+    tL2C_LCB        *p_lcb;
+    tBT_TRANSPORT   transport = BT_TRANSPORT_BR_EDR;
+
+#if (BLE_INCLUDED == TRUE)
+    if (fixed_cid >= L2CAP_ATT_CID && fixed_cid <= L2CAP_SMP_CID)
+        transport = BT_TRANSPORT_LE;
+#endif
+
+    /* Is a fixed channel connected to the remote BDA ?*/
+    p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, transport);
+    if ( ((p_lcb) == NULL) || (!p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]) )
+    {
+        L2CAP_TRACE_WARNING ("L2CA_SetFixedChannelTout()  CID: 0x%04x  BDA: %08x%04x not connected", fixed_cid,
+                             (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]);
+        return (false);
+    }
+
+    p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->fixed_chnl_idle_tout = idle_tout;
+
+    if (p_lcb->in_use && p_lcb->link_state == LST_CONNECTED && !p_lcb->ccb_queue.p_first_ccb)
+    {
+        /* If there are no dynamic CCBs, (re)start the idle timer in case we changed it */
+        l2cu_no_dynamic_ccbs (p_lcb);
+    }
+
+    return true;
+}
+
+#endif /* #if (L2CAP_NUM_FIXED_CHNLS > 0) */
+
+/*******************************************************************************
+**
+** 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)
+{
+    tL2C_CCB    *p_ccb;
+
+    L2CAP_TRACE_API ("L2CA_GetCurrentConfig()  CID: 0x%04x", lcid);
+
+    p_ccb = l2cu_find_ccb_by_cid(NULL, lcid);
+
+    if (p_ccb)
+    {
+        *pp_our_cfg  = &(p_ccb->our_cfg);
+
+        /* convert valid config items into bitmap */
+        *p_our_cfg_bits = 0;
+        if (p_ccb->our_cfg.mtu_present)
+            *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_MTU;
+        if (p_ccb->our_cfg.qos_present)
+            *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_QOS;
+        if (p_ccb->our_cfg.flush_to_present)
+            *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_FLUSH_TO;
+        if (p_ccb->our_cfg.fcr_present)
+            *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_FCR;
+        if (p_ccb->our_cfg.fcs_present)
+            *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_FCS;
+        if (p_ccb->our_cfg.ext_flow_spec_present)
+            *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_EXT_FLOW_SPEC;
+
+        *pp_peer_cfg = &(p_ccb->peer_cfg);
+        *p_peer_cfg_bits = p_ccb->peer_cfg_bits;
+
+        return true;
+    }
+    else
+    {
+        L2CAP_TRACE_ERROR ("No CCB for CID:0x%04x", lcid);
+        return false;
+    }
+}
+
+/*******************************************************************************
+**
+** Function      L2CA_GetConnectionConfig
+**
+** Description  This function returns configurations of L2CAP channel
+**              pp_l2c_ccb : pointer to this channels L2CAP ccb data.
+**
+** Returns      true if successful
+**
+*******************************************************************************/
+bool    L2CA_GetConnectionConfig(uint16_t lcid, uint16_t *mtu, uint16_t *rcid, uint16_t *handle)
+{
+    tL2C_CCB *p_ccb = l2cu_find_ccb_by_cid(NULL, lcid);;
+
+    L2CAP_TRACE_API ("%s CID: 0x%04x", __func__, lcid);
+
+    if (p_ccb)
+    {
+        *mtu = L2CAP_MTU_SIZE;
+        if (p_ccb->our_cfg.mtu_present)
+            *mtu = p_ccb->our_cfg.mtu;
+
+        *rcid  = p_ccb->remote_cid;
+        *handle= p_ccb->p_lcb->handle;
+        return true;
+    }
+
+    L2CAP_TRACE_ERROR ("%s No CCB for CID:0x%04x", __func__, lcid);
+    return false;
+}
+
+/*******************************************************************************
+**
+** 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          true if registered OK, else false
+**
+*******************************************************************************/
+bool    L2CA_RegForNoCPEvt(tL2CA_NOCP_CB *p_cb, BD_ADDR p_bda)
+{
+    tL2C_LCB        *p_lcb;
+
+    /* Find the link that is associated with this remote bdaddr */
+    p_lcb = l2cu_find_lcb_by_bd_addr (p_bda, BT_TRANSPORT_BR_EDR);
+
+    /* If no link for this handle, nothing to do. */
+    if (!p_lcb)
+        return false;
+
+    p_lcb->p_nocp_cb = p_cb;
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    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);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+#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. */
+    if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_SetChnlFlushability, CID: %d", cid);
+        return (false);
+    }
+
+    p_ccb->is_flushable = is_flushable;
+
+    L2CAP_TRACE_API ("L2CA_SetChnlFlushability()  CID: 0x%04x  is_flushable: %d", cid, is_flushable);
+
+#endif
+
+    return (true);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    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);
+}
+
+/*******************************************************************************
+**
+** 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)
+{
+    tL2C_CCB        *p_ccb;
+    tL2C_LCB        *p_lcb;
+    uint16_t        num_left = 0,
+                    num_flushed1 = 0,
+                    num_flushed2 = 0;
+
+    p_ccb = l2cu_find_ccb_by_cid(NULL, lcid);
+
+    if ( !p_ccb || ((p_lcb = p_ccb->p_lcb) == NULL) )
+    {
+        L2CAP_TRACE_WARNING ("L2CA_FlushChannel()  abnormally returning 0  CID: 0x%04x", lcid);
+        return (0);
+    }
+
+    if (num_to_flush != L2CAP_FLUSH_CHANS_GET)
+    {
+        L2CAP_TRACE_API ("L2CA_FlushChannel (FLUSH)  CID: 0x%04x  NumToFlush: %d  QC: %u  pFirst: 0x%08x",
+                         lcid, num_to_flush,
+                         fixed_queue_length(p_ccb->xmit_hold_q),
+                         fixed_queue_try_peek_first(p_ccb->xmit_hold_q));
+    }
+    else
+    {
+        L2CAP_TRACE_API ("L2CA_FlushChannel (QUERY)  CID: 0x%04x", lcid);
+    }
+
+    /* Cannot flush eRTM buffers once they have a sequence number */
+    if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_ERTM_MODE)
+    {
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+        if (num_to_flush != L2CAP_FLUSH_CHANS_GET)
+        {
+            /* If the controller supports enhanced flush, flush the data queued at the controller */
+            if ( (HCI_NON_FLUSHABLE_PB_SUPPORTED(BTM_ReadLocalFeatures ()))
+             && (BTM_GetNumScoLinks() == 0) )
+            {
+                if ( l2cb.is_flush_active == false )
+                {
+                    l2cb.is_flush_active = true;
+
+                    /* The only packet type defined - 0 - Automatically-Flushable Only */
+                    btsnd_hcic_enhanced_flush (p_lcb->handle, 0);
+                }
+            }
+        }
+#endif
+
+        // Iterate though list and flush the amount requested from
+        // the transmit data queue that satisfy the layer and event conditions.
+        for (const list_node_t *node = list_begin(p_lcb->link_xmit_data_q);
+            (num_to_flush > 0) && node != list_end(p_lcb->link_xmit_data_q);) {
+          BT_HDR *p_buf = (BT_HDR *)list_node(node);
+          node = list_next(node);
+          if ((p_buf->layer_specific == 0) && (p_buf->event == lcid)) {
+            num_to_flush--;
+            num_flushed1++;
+
+            list_remove(p_lcb->link_xmit_data_q, p_buf);
+            osi_free(p_buf);
+          }
+        }
+    }
+
+    /* If needed, flush buffers in the CCB xmit hold queue */
+    while ( (num_to_flush != 0) && (!fixed_queue_is_empty(p_ccb->xmit_hold_q)))
+    {
+        BT_HDR *p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->xmit_hold_q);
+        osi_free(p_buf);
+        num_to_flush--;
+        num_flushed2++;
+    }
+
+    /* If app needs to track all packets, call him */
+    if ( (p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_TxComplete_Cb) && (num_flushed2) )
+        (*p_ccb->p_rcb->api.pL2CA_TxComplete_Cb)(p_ccb->local_cid, num_flushed2);
+
+    /* Now count how many are left */
+    for (const list_node_t *node = list_begin(p_lcb->link_xmit_data_q);
+        node != list_end(p_lcb->link_xmit_data_q);
+        node = list_next(node)) {
+
+      BT_HDR *p_buf = (BT_HDR *)list_node(node);
+      if (p_buf->event == lcid)
+        num_left++;
+    }
+
+    /* Add in the number in the CCB xmit queue */
+    num_left += fixed_queue_length(p_ccb->xmit_hold_q);
+
+    /* Return the local number of buffers left for the CID */
+    L2CAP_TRACE_DEBUG ("L2CA_FlushChannel()  flushed: %u + %u,  num_left: %u", num_flushed1, num_flushed2, num_left);
+
+    /* If we were congested, and now we are not, tell the app */
+    l2cu_check_channel_congestion (p_ccb);
+
+    return (num_left);
+}
+
diff --git a/bt/stack/l2cap/l2c_ble.cc b/bt/stack/l2cap/l2c_ble.cc
new file mode 100644
index 0000000..94bb6d9
--- /dev/null
+++ b/bt/stack/l2cap/l2c_ble.cc
@@ -0,0 +1,1515 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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 functions relating to BLE management.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "l2cdefs.h"
+#include "l2c_int.h"
+#include "btu.h"
+#include "btm_int.h"
+#include "hcimsgs.h"
+#include "device/include/controller.h"
+#include "stack_config.h"
+#include "osi/include/osi.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+static void l2cble_start_conn_update (tL2C_LCB *p_lcb);
+
+/*******************************************************************************
+**
+**  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 (BD_ADDR rem_bda)
+{
+    tL2C_LCB *p_lcb;
+
+    /* There can be only one BLE connection request outstanding at a time */
+    if (btm_ble_get_conn_st() == BLE_CONN_IDLE)
+    {
+        L2CAP_TRACE_WARNING ("%s - no connection pending", __func__);
+        return(false);
+    }
+
+    if (memcmp (rem_bda, l2cb.ble_connecting_bda, BD_ADDR_LEN))
+    {
+        L2CAP_TRACE_WARNING ("%s - different  BDA Connecting: %08x%04x  Cancel: %08x%04x", __func__,
+                              (l2cb.ble_connecting_bda[0]<<24)+(l2cb.ble_connecting_bda[1]<<16)+(l2cb.ble_connecting_bda[2]<<8)+l2cb.ble_connecting_bda[3],
+                              (l2cb.ble_connecting_bda[4]<<8)+l2cb.ble_connecting_bda[5],
+                              (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]);
+        btm_ble_dequeue_direct_conn_req(rem_bda);
+        return(false);
+    }
+
+    btsnd_hcic_ble_create_conn_cancel();
+
+    p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_LE);
+    /* Do not remove lcb if an LE link is already up as a peripheral */
+    if (p_lcb != NULL &&
+        !(p_lcb->link_role == HCI_ROLE_SLAVE && btm_bda_to_acl(rem_bda, BT_TRANSPORT_LE) != NULL))
+    {
+        p_lcb->disc_reason = L2CAP_CONN_CANCEL;
+        l2cu_release_lcb (p_lcb);
+    }
+    /* update state to be cancel, wait for connection cancel complete */
+    btm_ble_set_conn_st (BLE_CONN_CANCEL);
+
+    return(true);
+}
+
+/*******************************************************************************
+**
+**  Function        L2CA_UpdateBleConnParams
+**
+**  Description     Update BLE connection parameters.
+**
+**  Parameters:     BD Address of remote
+**
+**  Return value:   true if update started
+**
+*******************************************************************************/
+bool    L2CA_UpdateBleConnParams (BD_ADDR rem_bda, uint16_t min_int, uint16_t max_int,
+                                            uint16_t latency, uint16_t timeout)
+{
+    tL2C_LCB            *p_lcb;
+    tACL_CONN           *p_acl_cb = btm_bda_to_acl(rem_bda, BT_TRANSPORT_LE);
+
+    /* See if we have a link control block for the remote device */
+    p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_LE);
+
+    /* If we don't have one, create one and accept the connection. */
+    if (!p_lcb || !p_acl_cb)
+    {
+        L2CAP_TRACE_WARNING ("L2CA_UpdateBleConnParams - unknown BD_ADDR %08x%04x",
+                              (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3],
+                              (rem_bda[4]<<8)+rem_bda[5]);
+        return(false);
+    }
+
+    if (p_lcb->transport != BT_TRANSPORT_LE)
+    {
+        L2CAP_TRACE_WARNING ("L2CA_UpdateBleConnParams - BD_ADDR %08x%04x not LE",
+                              (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3],
+                              (rem_bda[4]<<8)+rem_bda[5]);
+        return(false);
+    }
+
+    p_lcb->min_interval = min_int;
+    p_lcb->max_interval = max_int;
+    p_lcb->latency = latency;
+    p_lcb->timeout = timeout;
+    p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM;
+
+    l2cble_start_conn_update(p_lcb);
+
+    return(true);
+}
+
+
+/*******************************************************************************
+**
+**  Function        L2CA_EnableUpdateBleConnParams
+**
+**  Description     Enable or disable update based on the request from the peer
+**
+**  Parameters:     BD Address of remote
+**
+**  Return value:   true if update started
+**
+*******************************************************************************/
+bool    L2CA_EnableUpdateBleConnParams (BD_ADDR rem_bda, bool    enable)
+{
+    if (stack_config_get_interface()->get_pts_conn_updates_disabled())
+        return false;
+
+    tL2C_LCB            *p_lcb;
+
+    /* See if we have a link control block for the remote device */
+    p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_LE);
+
+    if (!p_lcb)
+    {
+        L2CAP_TRACE_WARNING ("L2CA_EnableUpdateBleConnParams - unknown BD_ADDR %08x%04x",
+            (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3],
+            (rem_bda[4]<<8)+rem_bda[5]);
+        return (false);
+    }
+
+    L2CAP_TRACE_API ("%s - BD_ADDR %08x%04x enable %d current upd state 0x%02x",__func__,
+        (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3],
+        (rem_bda[4]<<8)+rem_bda[5], enable, p_lcb->conn_update_mask);
+
+    if (p_lcb->transport != BT_TRANSPORT_LE)
+    {
+        L2CAP_TRACE_WARNING ("%s - BD_ADDR %08x%04x not LE (link role %d)", __func__,
+                              (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3],
+                              (rem_bda[4]<<8)+rem_bda[5], p_lcb->link_role);
+        return (false);
+    }
+
+    if (enable)
+        p_lcb->conn_update_mask &= ~L2C_BLE_CONN_UPDATE_DISABLE;
+    else
+        p_lcb->conn_update_mask |= L2C_BLE_CONN_UPDATE_DISABLE;
+
+    l2cble_start_conn_update(p_lcb);
+
+    return (true);
+}
+
+
+/*******************************************************************************
+**
+** Function         L2CA_GetBleConnRole
+**
+** Description      This function returns the connection role.
+**
+** Returns          link role.
+**
+*******************************************************************************/
+uint8_t L2CA_GetBleConnRole (BD_ADDR bd_addr)
+{
+    uint8_t     role = HCI_ROLE_UNKNOWN;
+
+    tL2C_LCB *p_lcb;
+
+    if ((p_lcb = l2cu_find_lcb_by_bd_addr (bd_addr, BT_TRANSPORT_LE)) != NULL)
+        role = p_lcb->link_role;
+
+    return role;
+}
+/*******************************************************************************
+**
+** Function         L2CA_GetDisconnectReason
+**
+** Description      This function returns the disconnect reason code.
+**
+** Returns          disconnect reason
+**
+*******************************************************************************/
+uint16_t L2CA_GetDisconnectReason (BD_ADDR remote_bda, tBT_TRANSPORT transport)
+{
+    tL2C_LCB            *p_lcb;
+    uint16_t            reason = 0;
+
+    if ((p_lcb = l2cu_find_lcb_by_bd_addr (remote_bda, transport)) != NULL)
+        reason = p_lcb->disc_reason;
+
+    L2CAP_TRACE_DEBUG ("L2CA_GetDisconnectReason=%d ",reason);
+
+    return reason;
+}
+
+void l2cble_use_preferred_conn_params(BD_ADDR bda) {
+    tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr (bda, BT_TRANSPORT_LE);
+    tBTM_SEC_DEV_REC    *p_dev_rec = btm_find_or_alloc_dev (bda);
+
+    /* If there are any preferred connection parameters, set them now */
+    if ( (p_dev_rec->conn_params.min_conn_int     >= BTM_BLE_CONN_INT_MIN ) &&
+         (p_dev_rec->conn_params.min_conn_int     <= BTM_BLE_CONN_INT_MAX ) &&
+         (p_dev_rec->conn_params.max_conn_int     >= BTM_BLE_CONN_INT_MIN ) &&
+         (p_dev_rec->conn_params.max_conn_int     <= BTM_BLE_CONN_INT_MAX ) &&
+         (p_dev_rec->conn_params.slave_latency    <= BTM_BLE_CONN_LATENCY_MAX ) &&
+         (p_dev_rec->conn_params.supervision_tout >= BTM_BLE_CONN_SUP_TOUT_MIN) &&
+         (p_dev_rec->conn_params.supervision_tout <= BTM_BLE_CONN_SUP_TOUT_MAX) &&
+         ((p_lcb->min_interval < p_dev_rec->conn_params.min_conn_int &&
+          p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ||
+          (p_lcb->min_interval > p_dev_rec->conn_params.max_conn_int) ||
+          (p_lcb->latency > p_dev_rec->conn_params.slave_latency) ||
+          (p_lcb->timeout > p_dev_rec->conn_params.supervision_tout)))
+    {
+        L2CAP_TRACE_DEBUG ("%s: HANDLE=%d min_conn_int=%d max_conn_int=%d slave_latency=%d supervision_tout=%d", __func__,
+                            p_lcb->handle, p_dev_rec->conn_params.min_conn_int, p_dev_rec->conn_params.max_conn_int,
+                            p_dev_rec->conn_params.slave_latency, p_dev_rec->conn_params.supervision_tout);
+
+        p_lcb->min_interval = p_dev_rec->conn_params.min_conn_int;
+        p_lcb->max_interval = p_dev_rec->conn_params.max_conn_int;
+        p_lcb->timeout      = p_dev_rec->conn_params.supervision_tout;
+        p_lcb->latency      = p_dev_rec->conn_params.slave_latency;
+
+        btsnd_hcic_ble_upd_ll_conn_params (p_lcb->handle,
+                                           p_dev_rec->conn_params.min_conn_int,
+                                           p_dev_rec->conn_params.max_conn_int,
+                                           p_dev_rec->conn_params.slave_latency,
+                                           p_dev_rec->conn_params.supervision_tout,
+                                           0, 0);
+    }
+}
+
+/*******************************************************************************
+**
+** Function l2cble_notify_le_connection
+**
+** Description This function notifiy the l2cap connection to the app layer
+**
+** Returns none
+**
+*******************************************************************************/
+void l2cble_notify_le_connection (BD_ADDR bda)
+{
+    tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr (bda, BT_TRANSPORT_LE);
+    tACL_CONN *p_acl = btm_bda_to_acl(bda, BT_TRANSPORT_LE) ;
+    tL2C_CCB *p_ccb;
+
+    if (p_lcb != NULL && p_acl != NULL && p_lcb->link_state != LST_CONNECTED)
+    {
+        /* update link status */
+        btm_establish_continue(p_acl);
+        /* update l2cap link status and send callback */
+        p_lcb->link_state = LST_CONNECTED;
+        l2cu_process_fixed_chnl_resp (p_lcb);
+    }
+
+    if (p_lcb != NULL) {
+        /* For all channels, send the event through their FSMs */
+        for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
+        {
+            if (p_ccb->chnl_state == CST_CLOSED)
+                l2c_csm_execute (p_ccb, L2CEVT_LP_CONNECT_CFM, NULL);
+        }
+    }
+
+    l2cble_use_preferred_conn_params(bda);
+}
+
+/*******************************************************************************
+**
+** Function         l2cble_scanner_conn_comp
+**
+** Description      This function is called when an HCI Connection Complete
+**                  event is received while we are a scanner (so we are master).
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cble_scanner_conn_comp (uint16_t handle, BD_ADDR bda, tBLE_ADDR_TYPE type,
+                               uint16_t conn_interval, uint16_t conn_latency, uint16_t conn_timeout)
+{
+    tL2C_LCB            *p_lcb;
+    tBTM_SEC_DEV_REC    *p_dev_rec = btm_find_or_alloc_dev (bda);
+
+    L2CAP_TRACE_DEBUG ("l2cble_scanner_conn_comp: HANDLE=%d addr_type=%d conn_interval=%d slave_latency=%d supervision_tout=%d",
+                        handle,  type, conn_interval, conn_latency, conn_timeout);
+
+    l2cb.is_ble_connecting = false;
+
+    /* See if we have a link control block for the remote device */
+    p_lcb = l2cu_find_lcb_by_bd_addr (bda, BT_TRANSPORT_LE);
+
+    /* If we don't have one, create one. this is auto connection complete. */
+    if (!p_lcb)
+    {
+        p_lcb = l2cu_allocate_lcb (bda, false, BT_TRANSPORT_LE);
+        if (!p_lcb)
+        {
+            btm_sec_disconnect (handle, HCI_ERR_NO_CONNECTION);
+            L2CAP_TRACE_ERROR ("l2cble_scanner_conn_comp - failed to allocate LCB");
+            return;
+        }
+        else
+        {
+            if (!l2cu_initialize_fixed_ccb (p_lcb, L2CAP_ATT_CID, &l2cb.fixed_reg[L2CAP_ATT_CID - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
+            {
+                btm_sec_disconnect (handle, HCI_ERR_NO_CONNECTION);
+                L2CAP_TRACE_WARNING ("l2cble_scanner_conn_comp - LCB but no CCB");
+                return ;
+            }
+        }
+    }
+    else if (p_lcb->link_state != LST_CONNECTING)
+    {
+        L2CAP_TRACE_ERROR ("L2CAP got BLE scanner conn_comp in bad state: %d", p_lcb->link_state);
+        return;
+    }
+    alarm_cancel(p_lcb->l2c_lcb_timer);
+
+    /* Save the handle */
+    p_lcb->handle = handle;
+
+    /* Connected OK. Change state to connected, we were scanning so we are master */
+    p_lcb->link_role  = HCI_ROLE_MASTER;
+    p_lcb->transport  = BT_TRANSPORT_LE;
+
+    /* update link parameter, set slave link as non-spec default upon link up */
+    p_lcb->min_interval =  p_lcb->max_interval = conn_interval;
+    p_lcb->timeout      =  conn_timeout;
+    p_lcb->latency      =  conn_latency;
+    p_lcb->conn_update_mask = L2C_BLE_NOT_DEFAULT_PARAM;
+
+    /* Tell BTM Acl management about the link */
+    btm_acl_created (bda, NULL, p_dev_rec->sec_bd_name, handle, p_lcb->link_role, BT_TRANSPORT_LE);
+
+    p_lcb->peer_chnl_mask[0] = L2CAP_FIXED_CHNL_ATT_BIT | L2CAP_FIXED_CHNL_BLE_SIG_BIT | L2CAP_FIXED_CHNL_SMP_BIT;
+
+    btm_ble_set_conn_st(BLE_CONN_IDLE);
+
+#if (BLE_PRIVACY_SPT == TRUE)
+    btm_ble_disable_resolving_list(BTM_BLE_RL_INIT, true);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function         l2cble_advertiser_conn_comp
+**
+** Description      This function is called when an HCI Connection Complete
+**                  event is received while we are an advertiser (so we are slave).
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cble_advertiser_conn_comp (uint16_t handle, BD_ADDR bda, UNUSED_ATTR tBLE_ADDR_TYPE type,
+                                  UNUSED_ATTR uint16_t conn_interval, UNUSED_ATTR uint16_t conn_latency,
+                                  UNUSED_ATTR uint16_t conn_timeout)
+{
+    tL2C_LCB            *p_lcb;
+    tBTM_SEC_DEV_REC    *p_dev_rec;
+
+    /* See if we have a link control block for the remote device */
+    p_lcb = l2cu_find_lcb_by_bd_addr (bda, BT_TRANSPORT_LE);
+
+    /* If we don't have one, create one and accept the connection. */
+    if (!p_lcb)
+    {
+        p_lcb = l2cu_allocate_lcb (bda, false, BT_TRANSPORT_LE);
+        if (!p_lcb)
+        {
+            btm_sec_disconnect (handle, HCI_ERR_NO_CONNECTION);
+            L2CAP_TRACE_ERROR ("l2cble_advertiser_conn_comp - failed to allocate LCB");
+            return;
+        }
+        else
+        {
+            if (!l2cu_initialize_fixed_ccb (p_lcb, L2CAP_ATT_CID, &l2cb.fixed_reg[L2CAP_ATT_CID - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
+            {
+                btm_sec_disconnect (handle, HCI_ERR_NO_CONNECTION);
+                L2CAP_TRACE_WARNING ("l2cble_scanner_conn_comp - LCB but no CCB");
+                return ;
+            }
+        }
+    }
+
+    /* Save the handle */
+    p_lcb->handle = handle;
+
+    /* Connected OK. Change state to connected, we were advertising, so we are slave */
+    p_lcb->link_role  = HCI_ROLE_SLAVE;
+    p_lcb->transport  = BT_TRANSPORT_LE;
+
+    /* update link parameter, set slave link as non-spec default upon link up */
+    p_lcb->min_interval = p_lcb->max_interval = conn_interval;
+    p_lcb->timeout      =  conn_timeout;
+    p_lcb->latency      =  conn_latency;
+    p_lcb->conn_update_mask = L2C_BLE_NOT_DEFAULT_PARAM;
+
+    /* Tell BTM Acl management about the link */
+    p_dev_rec = btm_find_or_alloc_dev (bda);
+
+    btm_acl_created (bda, NULL, p_dev_rec->sec_bd_name, handle, p_lcb->link_role, BT_TRANSPORT_LE);
+
+#if (BLE_PRIVACY_SPT == TRUE)
+    btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, true);
+#endif
+
+    p_lcb->peer_chnl_mask[0] = L2CAP_FIXED_CHNL_ATT_BIT | L2CAP_FIXED_CHNL_BLE_SIG_BIT | L2CAP_FIXED_CHNL_SMP_BIT;
+
+    if (!HCI_LE_SLAVE_INIT_FEAT_EXC_SUPPORTED(controller_get_interface()->get_features_ble()->as_array))
+    {
+        p_lcb->link_state = LST_CONNECTED;
+        l2cu_process_fixed_chnl_resp (p_lcb);
+    }
+
+    /* when adv and initiating are both active, cancel the direct connection */
+    if (l2cb.is_ble_connecting && memcmp(bda, l2cb.ble_connecting_bda, BD_ADDR_LEN) == 0)
+    {
+        L2CA_CancelBleConnectReq(bda);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2cble_conn_comp
+**
+** Description      This function is called when an HCI Connection Complete
+**                  event is received.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cble_conn_comp(uint16_t handle, uint8_t role, BD_ADDR bda, tBLE_ADDR_TYPE type,
+                      uint16_t conn_interval, uint16_t conn_latency, uint16_t conn_timeout)
+{
+    btm_ble_update_link_topology_mask(role, true);
+
+    if (role == HCI_ROLE_MASTER)
+    {
+        l2cble_scanner_conn_comp(handle, bda, type, conn_interval, conn_latency, conn_timeout);
+    }
+    else
+    {
+        l2cble_advertiser_conn_comp(handle, bda, type, conn_interval, conn_latency, conn_timeout);
+    }
+}
+
+/*******************************************************************************
+**
+**  Function        l2cble_start_conn_update
+**
+**  Description     start BLE connection parameter update process based on status
+**
+**  Parameters:     lcb : l2cap link control block
+**
+**  Return value:   none
+**
+*******************************************************************************/
+static void l2cble_start_conn_update (tL2C_LCB *p_lcb)
+{
+    uint16_t min_conn_int, max_conn_int, slave_latency, supervision_tout;
+    tACL_CONN *p_acl_cb = btm_bda_to_acl(p_lcb->remote_bd_addr, BT_TRANSPORT_LE);
+
+    // TODO(armansito): The return value of this call wasn't being used but the
+    // logic of this function might be depending on its side effects. We should
+    // verify if this call is needed at all and remove it otherwise.
+    btm_find_or_alloc_dev(p_lcb->remote_bd_addr);
+
+    if (p_lcb->conn_update_mask & L2C_BLE_UPDATE_PENDING) return;
+
+    if (p_lcb->conn_update_mask & L2C_BLE_CONN_UPDATE_DISABLE)
+    {
+        /* application requests to disable parameters update.
+           If parameters are already updated, lets set them
+           up to what has been requested during connection establishement */
+        if (p_lcb->conn_update_mask & L2C_BLE_NOT_DEFAULT_PARAM &&
+            /* current connection interval is greater than default min */
+            p_lcb->min_interval > BTM_BLE_CONN_INT_MIN)
+        {
+            /* use 7.5 ms as fast connection parameter, 0 slave latency */
+            min_conn_int = max_conn_int = BTM_BLE_CONN_INT_MIN;
+            slave_latency = BTM_BLE_CONN_SLAVE_LATENCY_DEF;
+            supervision_tout = BTM_BLE_CONN_TIMEOUT_DEF;
+
+            /* if both side 4.1, or we are master device, send HCI command */
+            if (p_lcb->link_role == HCI_ROLE_MASTER
+#if (BLE_LLT_INCLUDED == TRUE)
+                || (HCI_LE_CONN_PARAM_REQ_SUPPORTED(controller_get_interface()->get_features_ble()->as_array) &&
+                    HCI_LE_CONN_PARAM_REQ_SUPPORTED(p_acl_cb->peer_le_features))
+#endif
+                 )
+            {
+                btsnd_hcic_ble_upd_ll_conn_params(p_lcb->handle, min_conn_int, max_conn_int,
+                                                  slave_latency, supervision_tout, 0, 0);
+                p_lcb->conn_update_mask |= L2C_BLE_UPDATE_PENDING;
+            }
+            else
+            {
+                l2cu_send_peer_ble_par_req (p_lcb, min_conn_int, max_conn_int, slave_latency, supervision_tout);
+            }
+            p_lcb->conn_update_mask &= ~L2C_BLE_NOT_DEFAULT_PARAM;
+            p_lcb->conn_update_mask |=  L2C_BLE_NEW_CONN_PARAM;
+         }
+    }
+    else
+    {
+        /* application allows to do update, if we were delaying one do it now */
+        if (p_lcb->conn_update_mask & L2C_BLE_NEW_CONN_PARAM)
+        {
+             /* if both side 4.1, or we are master device, send HCI command */
+            if (p_lcb->link_role == HCI_ROLE_MASTER
+#if (BLE_LLT_INCLUDED == TRUE)
+                || (HCI_LE_CONN_PARAM_REQ_SUPPORTED(controller_get_interface()->get_features_ble()->as_array) &&
+                    HCI_LE_CONN_PARAM_REQ_SUPPORTED(p_acl_cb->peer_le_features))
+#endif
+                 )
+            {
+                btsnd_hcic_ble_upd_ll_conn_params(p_lcb->handle, p_lcb->min_interval,
+                    p_lcb->max_interval, p_lcb->latency, p_lcb->timeout, 0, 0);
+                p_lcb->conn_update_mask |= L2C_BLE_UPDATE_PENDING;
+            }
+            else
+            {
+                l2cu_send_peer_ble_par_req (p_lcb, p_lcb->min_interval, p_lcb->max_interval,
+                                            p_lcb->latency, p_lcb->timeout);
+            }
+            p_lcb->conn_update_mask &= ~L2C_BLE_NEW_CONN_PARAM;
+            p_lcb->conn_update_mask |= L2C_BLE_NOT_DEFAULT_PARAM;
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2cble_process_conn_update_evt
+**
+** Description      This function enables the connection update request from remote
+**                  after a successful connection update response is received.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cble_process_conn_update_evt (uint16_t handle, uint8_t status,
+                  uint16_t interval, uint16_t latency, uint16_t timeout)
+{
+    L2CAP_TRACE_DEBUG("%s", __func__);
+
+    /* See if we have a link control block for the remote device */
+    tL2C_LCB *p_lcb = l2cu_find_lcb_by_handle(handle);
+    if (!p_lcb)
+    {
+        L2CAP_TRACE_WARNING("%s: Invalid handle: %d", __func__, handle);
+        return;
+    }
+
+    p_lcb->conn_update_mask &= ~L2C_BLE_UPDATE_PENDING;
+
+    if (status != HCI_SUCCESS)
+    {
+        L2CAP_TRACE_WARNING("%s: Error status: %d", __func__, status);
+    }
+
+    l2cble_start_conn_update(p_lcb);
+
+    L2CAP_TRACE_DEBUG("%s: conn_update_mask=%d", __func__, p_lcb->conn_update_mask);
+}
+
+/*******************************************************************************
+**
+** Function         l2cble_process_sig_cmd
+**
+** Description      This function is called when a signalling packet is received
+**                  on the BLE signalling CID
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, uint8_t *p, uint16_t pkt_len)
+{
+    uint8_t         *p_pkt_end;
+    uint8_t         cmd_code, id;
+    uint16_t        cmd_len;
+    uint16_t        min_interval, max_interval, latency, timeout;
+    tL2C_CONN_INFO  con_info;
+    uint16_t        lcid = 0, rcid = 0, mtu = 0, mps = 0, initial_credit = 0;
+    tL2C_CCB        *p_ccb = NULL, *temp_p_ccb = NULL;
+    tL2C_RCB        *p_rcb;
+    uint16_t        credit;
+    p_pkt_end = p + pkt_len;
+
+    STREAM_TO_UINT8  (cmd_code, p);
+    STREAM_TO_UINT8  (id, p);
+    STREAM_TO_UINT16 (cmd_len, p);
+
+    /* Check command length does not exceed packet length */
+    if ((p + cmd_len) > p_pkt_end)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - LE - format error, pkt_len: %d  cmd_len: %d  code: %d", pkt_len, cmd_len, cmd_code);
+        return;
+    }
+
+    switch (cmd_code)
+    {
+        case L2CAP_CMD_REJECT:
+            p += 2;
+            break;
+
+        case L2CAP_CMD_ECHO_REQ:
+        case L2CAP_CMD_ECHO_RSP:
+        case L2CAP_CMD_INFO_RSP:
+        case L2CAP_CMD_INFO_REQ:
+            l2cu_send_peer_cmd_reject (p_lcb, L2CAP_CMD_REJ_NOT_UNDERSTOOD, id, 0, 0);
+            break;
+
+        case L2CAP_CMD_BLE_UPDATE_REQ:
+            STREAM_TO_UINT16 (min_interval, p); /* 0x0006 - 0x0C80 */
+            STREAM_TO_UINT16 (max_interval, p); /* 0x0006 - 0x0C80 */
+            STREAM_TO_UINT16 (latency, p);  /* 0x0000 - 0x03E8 */
+            STREAM_TO_UINT16 (timeout, p);  /* 0x000A - 0x0C80 */
+            /* If we are a master, the slave wants to update the parameters */
+            if (p_lcb->link_role == HCI_ROLE_MASTER)
+            {
+                if (min_interval < BTM_BLE_CONN_INT_MIN_LIMIT)
+                    min_interval = BTM_BLE_CONN_INT_MIN_LIMIT;
+
+                // While this could result in connection parameters that fall
+                // outside fo the range requested, this will allow the connection
+                // to remain established.
+                // In other words, this is a workaround for certain peripherals.
+                if (max_interval < BTM_BLE_CONN_INT_MIN_LIMIT)
+                    max_interval = BTM_BLE_CONN_INT_MIN_LIMIT;
+
+                if (min_interval < BTM_BLE_CONN_INT_MIN || min_interval > BTM_BLE_CONN_INT_MAX ||
+                    max_interval < BTM_BLE_CONN_INT_MIN || max_interval > BTM_BLE_CONN_INT_MAX ||
+                    latency  > BTM_BLE_CONN_LATENCY_MAX ||
+                    /*(timeout >= max_interval && latency > (timeout * 10/(max_interval * 1.25) - 1)) ||*/
+                    timeout < BTM_BLE_CONN_SUP_TOUT_MIN || timeout > BTM_BLE_CONN_SUP_TOUT_MAX ||
+                    max_interval < min_interval)
+                {
+                    l2cu_send_peer_ble_par_rsp (p_lcb, L2CAP_CFG_UNACCEPTABLE_PARAMS, id);
+                }
+                else
+                {
+
+                    l2cu_send_peer_ble_par_rsp (p_lcb, L2CAP_CFG_OK, id);
+
+                     p_lcb->min_interval = min_interval;
+                     p_lcb->max_interval = max_interval;
+                     p_lcb->latency = latency;
+                     p_lcb->timeout = timeout;
+                     p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM;
+
+                     l2cble_start_conn_update(p_lcb);
+                }
+            }
+            else
+                l2cu_send_peer_cmd_reject (p_lcb, L2CAP_CMD_REJ_NOT_UNDERSTOOD, id, 0, 0);
+            break;
+
+        case L2CAP_CMD_BLE_UPDATE_RSP:
+            p += 2;
+            break;
+
+        case L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ:
+            STREAM_TO_UINT16 (con_info.psm, p);
+            STREAM_TO_UINT16 (rcid, p);
+            STREAM_TO_UINT16 (mtu, p);
+            STREAM_TO_UINT16 (mps, p);
+            STREAM_TO_UINT16 (initial_credit, p);
+
+            L2CAP_TRACE_DEBUG ("Recv L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ with "
+                    "mtu = %d, "
+                    "mps = %d, "
+                    "initial credit = %d", mtu, mps, initial_credit);
+
+            if ((p_rcb = l2cu_find_ble_rcb_by_psm (con_info.psm)) == NULL)
+            {
+                L2CAP_TRACE_WARNING ("L2CAP - rcvd conn req for unknown PSM: 0x%04x", con_info.psm);
+                l2cu_reject_ble_connection (p_lcb, id, L2CAP_LE_NO_PSM);
+                break;
+            }
+            else
+            {
+                if (!p_rcb->api.pL2CA_ConnectInd_Cb)
+                {
+                    L2CAP_TRACE_WARNING ("L2CAP - rcvd conn req for outgoing-only connection PSM: %d", con_info.psm);
+                    l2cu_reject_ble_connection (p_lcb, id, L2CAP_CONN_NO_PSM);
+                    break;
+                }
+            }
+
+            /* Allocate a ccb for this.*/
+            if ((p_ccb = l2cu_allocate_ccb (p_lcb, 0)) == NULL)
+            {
+                L2CAP_TRACE_ERROR ("L2CAP - unable to allocate CCB");
+                l2cu_reject_ble_connection (p_lcb, id, L2CAP_CONN_NO_RESOURCES);
+                break;
+            }
+
+            /* validate the parameters */
+            if (mtu < L2CAP_LE_MIN_MTU || mps < L2CAP_LE_MIN_MPS || mps > L2CAP_LE_MAX_MPS)
+            {
+                L2CAP_TRACE_ERROR ("L2CAP don't like the params");
+                l2cu_reject_ble_connection (p_lcb, id, L2CAP_CONN_NO_RESOURCES);
+                break;
+            }
+
+            p_ccb->remote_id = id;
+            p_ccb->p_rcb = p_rcb;
+            p_ccb->remote_cid = rcid;
+
+            p_ccb->peer_conn_cfg.mtu = mtu;
+            p_ccb->peer_conn_cfg.mps = mps;
+            p_ccb->peer_conn_cfg.credits = initial_credit;
+
+            p_ccb->tx_mps = mps;
+            p_ccb->ble_sdu = NULL;
+            p_ccb->ble_sdu_length = 0;
+            p_ccb->is_first_seg = true;
+            p_ccb->peer_cfg.fcr.mode = L2CAP_FCR_LE_COC_MODE;
+
+            l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_REQ, &con_info);
+            break;
+
+        case L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES:
+            L2CAP_TRACE_DEBUG ("Recv L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES");
+            /* For all channels, see whose identifier matches this id */
+            for (temp_p_ccb = p_lcb->ccb_queue.p_first_ccb; temp_p_ccb; temp_p_ccb = temp_p_ccb->p_next_ccb)
+            {
+                if (temp_p_ccb->local_id == id)
+                {
+                    p_ccb = temp_p_ccb;
+                    break;
+                }
+            }
+            if (p_ccb)
+            {
+                L2CAP_TRACE_DEBUG ("I remember the connection req");
+                STREAM_TO_UINT16 (p_ccb->remote_cid, p);
+                STREAM_TO_UINT16 (p_ccb->peer_conn_cfg.mtu, p);
+                STREAM_TO_UINT16 (p_ccb->peer_conn_cfg.mps, p);
+                STREAM_TO_UINT16 (p_ccb->peer_conn_cfg.credits, p);
+                STREAM_TO_UINT16 (con_info.l2cap_result, p);
+                con_info.remote_cid = p_ccb->remote_cid;
+
+                L2CAP_TRACE_DEBUG ("remote_cid = %d, "
+                        "mtu = %d, "
+                        "mps = %d, "
+                        "initial_credit = %d, "
+                        "con_info.l2cap_result = %d",
+                        p_ccb->remote_cid, p_ccb->peer_conn_cfg.mtu, p_ccb->peer_conn_cfg.mps,
+                        p_ccb->peer_conn_cfg.credits, con_info.l2cap_result);
+
+                /* validate the parameters */
+                if (p_ccb->peer_conn_cfg.mtu < L2CAP_LE_MIN_MTU ||
+                        p_ccb->peer_conn_cfg.mps < L2CAP_LE_MIN_MPS ||
+                        p_ccb->peer_conn_cfg.mps > L2CAP_LE_MAX_MPS)
+                {
+                    L2CAP_TRACE_ERROR ("L2CAP don't like the params");
+                    con_info.l2cap_result = L2CAP_LE_NO_RESOURCES;
+                    l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info);
+                    break;
+                }
+
+                p_ccb->tx_mps = p_ccb->peer_conn_cfg.mps;
+                p_ccb->ble_sdu = NULL;
+                p_ccb->ble_sdu_length = 0;
+                p_ccb->is_first_seg = true;
+                p_ccb->peer_cfg.fcr.mode = L2CAP_FCR_LE_COC_MODE;
+
+                if (con_info.l2cap_result == L2CAP_LE_CONN_OK)
+                    l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP, &con_info);
+                else
+                    l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info);
+            }
+            else
+            {
+                L2CAP_TRACE_DEBUG ("I DO NOT remember the connection req");
+                con_info.l2cap_result = L2CAP_LE_INVALID_SOURCE_CID;
+                l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info);
+            }
+            break;
+
+        case L2CAP_CMD_BLE_FLOW_CTRL_CREDIT:
+            STREAM_TO_UINT16(lcid, p);
+            if((p_ccb = l2cu_find_ccb_by_remote_cid(p_lcb, lcid)) == NULL)
+            {
+                L2CAP_TRACE_DEBUG ("%s Credit received for unknown channel id %d", __func__, lcid);
+                break;
+            }
+
+            STREAM_TO_UINT16(credit ,p);
+            l2c_csm_execute(p_ccb, L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT, &credit);
+            L2CAP_TRACE_DEBUG ("%s Credit received", __func__);
+            break;
+
+        case L2CAP_CMD_DISC_REQ:
+            STREAM_TO_UINT16 (lcid, p);
+            STREAM_TO_UINT16 (rcid, p);
+
+            if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL)
+            {
+                if (p_ccb->remote_cid == rcid)
+                {
+                    p_ccb->remote_id = id;
+                    l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DISCONNECT_REQ, NULL);
+                }
+            }
+            else
+                l2cu_send_peer_disc_rsp (p_lcb, id, lcid, rcid);
+
+            break;
+
+         case L2CAP_CMD_DISC_RSP:
+            STREAM_TO_UINT16 (rcid, p);
+            STREAM_TO_UINT16 (lcid, p);
+
+            if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL)
+            {
+                if ((p_ccb->remote_cid == rcid) && (p_ccb->local_id == id))
+                    l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DISCONNECT_RSP, NULL);
+            }
+            break;
+
+        default:
+            L2CAP_TRACE_WARNING ("L2CAP - LE - unknown cmd code: %d", cmd_code);
+            l2cu_send_peer_cmd_reject (p_lcb, L2CAP_CMD_REJ_NOT_UNDERSTOOD, id, 0, 0);
+            break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2cble_init_direct_conn
+**
+** Description      This function is to initate a direct connection
+**
+** Returns          true connection initiated, false otherwise.
+**
+*******************************************************************************/
+bool    l2cble_init_direct_conn (tL2C_LCB *p_lcb)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (p_lcb->remote_bd_addr);
+    tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
+    uint16_t scan_int;
+    uint16_t scan_win;
+    BD_ADDR peer_addr;
+    uint8_t peer_addr_type = BLE_ADDR_PUBLIC;
+    uint8_t own_addr_type = BLE_ADDR_PUBLIC;
+
+    /* There can be only one BLE connection request outstanding at a time */
+    if (p_dev_rec == NULL)
+    {
+        L2CAP_TRACE_WARNING ("unknown device, can not initate connection");
+        return(false);
+    }
+
+    scan_int = (p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF) ? BTM_BLE_SCAN_FAST_INT : p_cb->scan_int;
+    scan_win = (p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF) ? BTM_BLE_SCAN_FAST_WIN : p_cb->scan_win;
+
+    peer_addr_type = p_lcb->ble_addr_type;
+    memcpy(peer_addr, p_lcb->remote_bd_addr, BD_ADDR_LEN);
+
+#if (BLE_PRIVACY_SPT == TRUE)
+    own_addr_type = btm_cb.ble_ctr_cb.privacy_mode ? BLE_ADDR_RANDOM : BLE_ADDR_PUBLIC;
+    if (p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT)
+    {
+        if (btm_cb.ble_ctr_cb.privacy_mode >=  BTM_PRIVACY_1_2)
+            own_addr_type |= BLE_ADDR_TYPE_ID_BIT;
+
+        btm_ble_enable_resolving_list(BTM_BLE_RL_INIT);
+        btm_random_pseudo_to_identity_addr(peer_addr, &peer_addr_type);
+    } else {
+        btm_ble_disable_resolving_list(BTM_BLE_RL_INIT, true);
+
+        // If we have a current RPA, use that instead.
+        if (!bdaddr_is_empty((const bt_bdaddr_t *)p_dev_rec->ble.cur_rand_addr)) {
+            memcpy(peer_addr, p_dev_rec->ble.cur_rand_addr, BD_ADDR_LEN);
+        }
+    }
+#endif
+
+    if (!btm_ble_topology_check(BTM_BLE_STATE_INIT))
+    {
+        l2cu_release_lcb (p_lcb);
+        L2CAP_TRACE_ERROR("initate direct connection fail, topology limitation");
+        return false;
+    }
+
+    btsnd_hcic_ble_create_ll_conn(scan_int,/* uint16_t scan_int      */
+                                  scan_win, /* uint16_t scan_win      */
+                                  false,                   /* uint8_t white_list     */
+                                  peer_addr_type,          /* uint8_t addr_type_peer */
+                                  peer_addr,               /* BD_ADDR bda_peer     */
+                                  own_addr_type,         /* uint8_t addr_type_own  */
+        (uint16_t) ((p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ?
+        p_dev_rec->conn_params.min_conn_int : BTM_BLE_CONN_INT_MIN_DEF),  /* uint16_t conn_int_min  */
+        (uint16_t) ((p_dev_rec->conn_params.max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ?
+        p_dev_rec->conn_params.max_conn_int : BTM_BLE_CONN_INT_MAX_DEF),  /* uint16_t conn_int_max  */
+        (uint16_t) ((p_dev_rec->conn_params.slave_latency != BTM_BLE_CONN_PARAM_UNDEF) ?
+        p_dev_rec->conn_params.slave_latency : BTM_BLE_CONN_SLAVE_LATENCY_DEF), /* uint16_t conn_latency  */
+        (uint16_t) ((p_dev_rec->conn_params.supervision_tout != BTM_BLE_CONN_PARAM_UNDEF) ?
+        p_dev_rec->conn_params.supervision_tout : BTM_BLE_CONN_TIMEOUT_DEF), /* conn_timeout */
+                                  0,                       /* uint16_t min_len       */
+                                  0);                      /* uint16_t max_len       */
+
+    p_lcb->link_state = LST_CONNECTING;
+    l2cb.is_ble_connecting = true;
+    memcpy (l2cb.ble_connecting_bda, p_lcb->remote_bd_addr, BD_ADDR_LEN);
+    alarm_set_on_queue(p_lcb->l2c_lcb_timer,
+                       L2CAP_BLE_LINK_CONNECT_TIMEOUT_MS,
+                       l2c_lcb_timer_timeout, p_lcb,
+                       btu_general_alarm_queue);
+    btm_ble_set_conn_st (BLE_DIR_CONN);
+
+    return (true);
+}
+
+/*******************************************************************************
+**
+** Function         l2cble_create_conn
+**
+** Description      This function initiates an acl connection via HCI
+**
+** Returns          true if successful, false if connection not started.
+**
+*******************************************************************************/
+bool    l2cble_create_conn (tL2C_LCB *p_lcb)
+{
+    tBTM_BLE_CONN_ST     conn_st = btm_ble_get_conn_st();
+    bool            rt = false;
+
+    /* There can be only one BLE connection request outstanding at a time */
+    if (conn_st == BLE_CONN_IDLE)
+    {
+        rt = l2cble_init_direct_conn(p_lcb);
+    }
+    else
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - LE - cannot start new connection at conn st: %d", conn_st);
+
+        btm_ble_enqueue_direct_conn_req(p_lcb);
+
+        if (conn_st == BLE_BG_CONN)
+            btm_ble_suspend_bg_conn();
+
+        rt = true;
+    }
+    return rt;
+}
+
+/*******************************************************************************
+**
+** Function         l2c_link_processs_ble_num_bufs
+**
+** Description      This function is called when a "controller buffer size"
+**                  event is first received from the controller. It updates
+**                  the L2CAP values.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2c_link_processs_ble_num_bufs (uint16_t num_lm_ble_bufs)
+{
+    if (num_lm_ble_bufs == 0)
+    {
+        num_lm_ble_bufs = L2C_DEF_NUM_BLE_BUF_SHARED;
+        l2cb.num_lm_acl_bufs -= L2C_DEF_NUM_BLE_BUF_SHARED;
+    }
+
+    l2cb.num_lm_ble_bufs = l2cb.controller_le_xmit_window = num_lm_ble_bufs;
+}
+
+/*******************************************************************************
+**
+** Function         l2c_ble_link_adjust_allocation
+**
+** Description      This function is called when a link is created or removed
+**                  to calculate the amount of packets each link may send to
+**                  the HCI without an ack coming back.
+**
+**                  Currently, this is a simple allocation, dividing the
+**                  number of Controller Packets by the number of links. In
+**                  the future, QOS configuration should be examined.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2c_ble_link_adjust_allocation (void)
+{
+    uint16_t    qq, yy, qq_remainder;
+    tL2C_LCB    *p_lcb;
+    uint16_t    hi_quota, low_quota;
+    uint16_t    num_lowpri_links = 0;
+    uint16_t    num_hipri_links  = 0;
+    uint16_t    controller_xmit_quota = l2cb.num_lm_ble_bufs;
+    uint16_t    high_pri_link_quota = L2CAP_HIGH_PRI_MIN_XMIT_QUOTA_A;
+
+    /* If no links active, reset buffer quotas and controller buffers */
+    if (l2cb.num_ble_links_active == 0)
+    {
+        l2cb.controller_le_xmit_window = l2cb.num_lm_ble_bufs;
+        l2cb.ble_round_robin_quota = l2cb.ble_round_robin_unacked = 0;
+        return;
+    }
+
+    /* First, count the links */
+    for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++)
+    {
+        if (p_lcb->in_use && p_lcb->transport == BT_TRANSPORT_LE)
+        {
+            if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)
+                num_hipri_links++;
+            else
+                num_lowpri_links++;
+        }
+    }
+
+    /* now adjust high priority link quota */
+    low_quota = num_lowpri_links ? 1 : 0;
+    while ( (num_hipri_links * high_pri_link_quota + low_quota) > controller_xmit_quota )
+        high_pri_link_quota--;
+
+
+    /* Work out the xmit quota and buffer quota high and low priorities */
+    hi_quota  = num_hipri_links * high_pri_link_quota;
+    low_quota = (hi_quota < controller_xmit_quota) ? controller_xmit_quota - hi_quota : 1;
+
+    /* Work out and save the HCI xmit quota for each low priority link */
+
+    /* If each low priority link cannot have at least one buffer */
+    if (num_lowpri_links > low_quota)
+    {
+        l2cb.ble_round_robin_quota = low_quota;
+        qq = qq_remainder = 0;
+    }
+    /* If each low priority link can have at least one buffer */
+    else if (num_lowpri_links > 0)
+    {
+        l2cb.ble_round_robin_quota = 0;
+        l2cb.ble_round_robin_unacked = 0;
+        qq = low_quota / num_lowpri_links;
+        qq_remainder = low_quota % num_lowpri_links;
+    }
+    /* If no low priority link */
+    else
+    {
+        l2cb.ble_round_robin_quota = 0;
+        l2cb.ble_round_robin_unacked = 0;
+        qq = qq_remainder = 0;
+    }
+    L2CAP_TRACE_EVENT ("l2c_ble_link_adjust_allocation  num_hipri: %u  num_lowpri: %u  low_quota: %u  round_robin_quota: %u  qq: %u",
+                        num_hipri_links, num_lowpri_links, low_quota,
+                        l2cb.ble_round_robin_quota, qq);
+
+    /* Now, assign the quotas to each link */
+    for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++)
+    {
+        if (p_lcb->in_use && p_lcb->transport == BT_TRANSPORT_LE)
+        {
+            if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)
+            {
+                p_lcb->link_xmit_quota   = high_pri_link_quota;
+            }
+            else
+            {
+                /* Safety check in case we switched to round-robin with something outstanding */
+                /* if sent_not_acked is added into round_robin_unacked then don't add it again */
+                /* l2cap keeps updating sent_not_acked for exiting from round robin */
+                if (( p_lcb->link_xmit_quota > 0 )&&( qq == 0 ))
+                    l2cb.ble_round_robin_unacked += p_lcb->sent_not_acked;
+
+                p_lcb->link_xmit_quota   = qq;
+                if (qq_remainder > 0)
+                {
+                    p_lcb->link_xmit_quota++;
+                    qq_remainder--;
+                }
+            }
+
+            L2CAP_TRACE_EVENT("l2c_ble_link_adjust_allocation LCB %d   Priority: %d  XmitQuota: %d",
+                                yy, p_lcb->acl_priority, p_lcb->link_xmit_quota);
+
+            L2CAP_TRACE_EVENT("        SentNotAcked: %d  RRUnacked: %d",
+                                p_lcb->sent_not_acked, l2cb.round_robin_unacked);
+
+            /* There is a special case where we have readjusted the link quotas and  */
+            /* this link may have sent anything but some other link sent packets so  */
+            /* so we may need a timer to kick off this link's transmissions.         */
+            if ( (p_lcb->link_state == LST_CONNECTED)
+              && (!list_is_empty(p_lcb->link_xmit_data_q))
+                 && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota) ) {
+                alarm_set_on_queue(p_lcb->l2c_lcb_timer,
+                                   L2CAP_LINK_FLOW_CONTROL_TIMEOUT_MS,
+                                   l2c_lcb_timer_timeout, p_lcb,
+                                   btu_general_alarm_queue);
+            }
+        }
+    }
+}
+
+#if (BLE_LLT_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function         l2cble_process_rc_param_request_evt
+**
+** Description      process LE Remote Connection Parameter Request Event.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cble_process_rc_param_request_evt(uint16_t handle, uint16_t int_min, uint16_t int_max,
+                                     uint16_t latency, uint16_t timeout)
+{
+    tL2C_LCB    *p_lcb = l2cu_find_lcb_by_handle (handle);
+
+    if (p_lcb != NULL)
+    {
+        p_lcb->min_interval = int_min;
+        p_lcb->max_interval = int_max;
+        p_lcb->latency = latency;
+        p_lcb->timeout = timeout;
+
+        /* if update is enabled, always accept connection parameter update */
+        if ((p_lcb->conn_update_mask & L2C_BLE_CONN_UPDATE_DISABLE) == 0)
+        {
+            btsnd_hcic_ble_rc_param_req_reply(handle, int_min, int_max, latency, timeout, 0, 0);
+        }
+        else
+        {
+            L2CAP_TRACE_EVENT ("L2CAP - LE - update currently disabled");
+            p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM;
+            btsnd_hcic_ble_rc_param_req_neg_reply (handle,HCI_ERR_UNACCEPT_CONN_INTERVAL);
+        }
+
+    }
+    else
+    {
+        L2CAP_TRACE_WARNING("No link to update connection parameter")
+    }
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         l2cble_update_data_length
+**
+** Description      This function update link tx data length if applicable
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cble_update_data_length(tL2C_LCB *p_lcb)
+{
+    uint16_t tx_mtu = 0;
+    uint16_t i = 0;
+
+    L2CAP_TRACE_DEBUG("%s", __func__);
+
+    /* See if we have a link control block for the connection */
+    if (p_lcb == NULL)
+        return;
+
+    for (i = 0; i < L2CAP_NUM_FIXED_CHNLS; i++)
+    {
+        if (i + L2CAP_FIRST_FIXED_CHNL != L2CAP_BLE_SIGNALLING_CID)
+        {
+            if ((p_lcb->p_fixed_ccbs[i] != NULL) &&
+                    (tx_mtu < (p_lcb->p_fixed_ccbs[i]->tx_data_len + L2CAP_PKT_OVERHEAD)))
+                tx_mtu = p_lcb->p_fixed_ccbs[i]->tx_data_len + L2CAP_PKT_OVERHEAD;
+        }
+    }
+
+    if (tx_mtu > BTM_BLE_DATA_SIZE_MAX)
+        tx_mtu = BTM_BLE_DATA_SIZE_MAX;
+
+    /* update TX data length if changed */
+    if (p_lcb->tx_data_len != tx_mtu)
+        BTM_SetBleDataLength(p_lcb->remote_bd_addr, tx_mtu);
+
+}
+
+/*******************************************************************************
+**
+** Function         l2cble_process_data_length_change_evt
+**
+** Description      This function process the data length change event
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cble_process_data_length_change_event(uint16_t handle, uint16_t tx_data_len, uint16_t rx_data_len)
+{
+    tL2C_LCB *p_lcb = l2cu_find_lcb_by_handle(handle);
+
+    L2CAP_TRACE_DEBUG("%s TX data len = %d", __func__, tx_data_len);
+    if (p_lcb == NULL)
+        return;
+
+    if (tx_data_len > 0)
+        p_lcb->tx_data_len = tx_data_len;
+
+    /* ignore rx_data len for now */
+}
+
+/*******************************************************************************
+**
+** Function         l2cble_set_fixed_channel_tx_data_length
+**
+** Description      This function update max fixed channel tx data length if applicable
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cble_set_fixed_channel_tx_data_length(BD_ADDR remote_bda, uint16_t fix_cid, uint16_t tx_mtu)
+{
+    tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(remote_bda, BT_TRANSPORT_LE);
+    uint16_t cid = fix_cid - L2CAP_FIRST_FIXED_CHNL;
+
+    L2CAP_TRACE_DEBUG("%s TX MTU = %d", __func__, tx_mtu);
+
+    if (!controller_get_interface()->supports_ble_packet_extension())
+    {
+        L2CAP_TRACE_WARNING("%s, request not supported", __func__);
+        return;
+    }
+
+    /* See if we have a link control block for the connection */
+    if (p_lcb == NULL)
+        return;
+
+    if (p_lcb->p_fixed_ccbs[cid] != NULL)
+    {
+        if (tx_mtu > BTM_BLE_DATA_SIZE_MAX)
+            tx_mtu = BTM_BLE_DATA_SIZE_MAX;
+
+        p_lcb->p_fixed_ccbs[cid]->tx_data_len = tx_mtu;
+    }
+
+    l2cble_update_data_length(p_lcb);
+}
+
+/*******************************************************************************
+**
+** Function         l2cble_credit_based_conn_req
+**
+** Description      This function sends LE Credit Based Connection Request for
+**                  LE connection oriented channels.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cble_credit_based_conn_req (tL2C_CCB *p_ccb)
+{
+    if (!p_ccb)
+        return;
+
+    if (p_ccb->p_lcb && p_ccb->p_lcb->transport != BT_TRANSPORT_LE)
+    {
+        L2CAP_TRACE_WARNING ("LE link doesn't exist");
+        return;
+    }
+
+    l2cu_send_peer_ble_credit_based_conn_req (p_ccb);
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         l2cble_credit_based_conn_res
+**
+** Description      This function sends LE Credit Based Connection Response for
+**                  LE connection oriented channels.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cble_credit_based_conn_res (tL2C_CCB *p_ccb, uint16_t result)
+{
+    if (!p_ccb)
+        return;
+
+    if (p_ccb->p_lcb && p_ccb->p_lcb->transport != BT_TRANSPORT_LE)
+    {
+        L2CAP_TRACE_WARNING ("LE link doesn't exist");
+        return;
+    }
+
+    l2cu_send_peer_ble_credit_based_conn_res (p_ccb, result);
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         l2cble_send_flow_control_credit
+**
+** Description      This function sends flow control credits for
+**                  LE connection oriented channels.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cble_send_flow_control_credit(tL2C_CCB *p_ccb, uint16_t credit_value)
+{
+    if (!p_ccb)
+        return;
+
+    if (p_ccb->p_lcb && p_ccb->p_lcb->transport != BT_TRANSPORT_LE)
+    {
+        L2CAP_TRACE_WARNING ("LE link doesn't exist");
+        return;
+    }
+
+    l2cu_send_peer_ble_flow_control_credit(p_ccb, credit_value);
+    return;
+
+}
+
+/*******************************************************************************
+**
+** Function         l2cble_send_peer_disc_req
+**
+** Description      This function sends disconnect request
+**                  to the peer LE device
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cble_send_peer_disc_req(tL2C_CCB *p_ccb)
+{
+    L2CAP_TRACE_DEBUG ("%s",__func__);
+    if (!p_ccb)
+        return;
+
+    if (p_ccb->p_lcb && p_ccb->p_lcb->transport != BT_TRANSPORT_LE)
+    {
+        L2CAP_TRACE_WARNING ("LE link doesn't exist");
+        return;
+    }
+
+    l2cu_send_peer_ble_credit_based_disconn_req(p_ccb);
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         l2cble_sec_comp
+**
+** Description      This function is called when security procedure for an LE COC
+**                  link is done
+**
+** Returns          void
+**
+*******************************************************************************/
+void  l2cble_sec_comp(BD_ADDR p_bda, tBT_TRANSPORT transport, void *p_ref_data, uint8_t status)
+{
+    tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(p_bda, BT_TRANSPORT_LE);
+    tL2CAP_SEC_DATA *p_buf = NULL;
+    uint8_t sec_flag;
+    uint8_t sec_act;
+
+    if (!p_lcb)
+    {
+        L2CAP_TRACE_WARNING ("%s security complete for unknown device", __func__);
+        return;
+    }
+
+    sec_act = p_lcb->sec_act;
+    p_lcb->sec_act = 0;
+
+    if (!fixed_queue_is_empty(p_lcb->le_sec_pending_q))
+    {
+        p_buf = (tL2CAP_SEC_DATA*) fixed_queue_dequeue(p_lcb->le_sec_pending_q);
+        if (!p_buf)
+        {
+            L2CAP_TRACE_WARNING ("%s Security complete for request not initiated from L2CAP",
+                    __func__);
+            return;
+        }
+
+        if (status != BTM_SUCCESS)
+        {
+            (*(p_buf->p_callback))(p_bda, BT_TRANSPORT_LE, p_buf->p_ref_data, status);
+        }
+        else
+        {
+            if (sec_act == BTM_SEC_ENCRYPT_MITM)
+            {
+                BTM_GetSecurityFlagsByTransport(p_bda, &sec_flag, transport);
+                if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED)
+                    (*(p_buf->p_callback))(p_bda, BT_TRANSPORT_LE, p_buf->p_ref_data, status);
+                else
+                {
+                    L2CAP_TRACE_DEBUG ("%s MITM Protection Not present", __func__);
+                    (*(p_buf->p_callback))(p_bda, BT_TRANSPORT_LE, p_buf->p_ref_data,
+                            BTM_FAILED_ON_SECURITY);
+                }
+            }
+            else
+            {
+                L2CAP_TRACE_DEBUG ("%s MITM Protection not required sec_act = %d",
+                        __func__, p_lcb->sec_act);
+
+                (*(p_buf->p_callback))(p_bda, BT_TRANSPORT_LE, p_buf->p_ref_data, status);
+            }
+        }
+    }
+    else
+    {
+        L2CAP_TRACE_WARNING ("%s Security complete for request not initiated from L2CAP", __func__);
+        return;
+    }
+    osi_free(p_buf);
+
+    while (!fixed_queue_is_empty(p_lcb->le_sec_pending_q))
+    {
+        p_buf = (tL2CAP_SEC_DATA*) fixed_queue_dequeue(p_lcb->le_sec_pending_q);
+
+        if (status != BTM_SUCCESS)
+            (*(p_buf->p_callback))(p_bda, BT_TRANSPORT_LE, p_buf->p_ref_data, status);
+        else
+            l2ble_sec_access_req(p_bda, p_buf->psm, p_buf->is_originator,
+                    p_buf->p_callback, p_buf->p_ref_data);
+
+       osi_free(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2ble_sec_access_req
+**
+** Description      This function is called by LE COC link to meet the
+**                  security requirement for the link
+**
+** Returns          true - security procedures are started
+**                  false - failure
+**
+*******************************************************************************/
+bool    l2ble_sec_access_req(BD_ADDR bd_addr, uint16_t psm, bool    is_originator, tL2CAP_SEC_CBACK *p_callback, void *p_ref_data)
+{
+    L2CAP_TRACE_DEBUG ("%s", __func__);
+    bool    status;
+    tL2C_LCB *p_lcb = NULL;
+
+    if (!p_callback)
+    {
+        L2CAP_TRACE_ERROR("%s No callback function", __func__);
+        return false;
+    }
+
+    p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE);
+
+    if (!p_lcb)
+    {
+        L2CAP_TRACE_ERROR ("%s Security check for unknown device", __func__);
+        p_callback(bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_UNKNOWN_ADDR);
+        return false;
+    }
+
+    tL2CAP_SEC_DATA *p_buf = (tL2CAP_SEC_DATA*) osi_malloc((uint16_t)sizeof(tL2CAP_SEC_DATA));
+    if (!p_buf)
+    {
+        p_callback(bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_NO_RESOURCES);
+        return false;
+    }
+
+    p_buf->psm = psm;
+    p_buf->is_originator = is_originator;
+    p_buf->p_callback = p_callback;
+    p_buf->p_ref_data = p_ref_data;
+    fixed_queue_enqueue(p_lcb->le_sec_pending_q, p_buf);
+    status = btm_ble_start_sec_check(bd_addr, psm, is_originator, &l2cble_sec_comp, p_ref_data);
+
+    return status;
+}
+#endif /* (BLE_INCLUDED == TRUE) */
diff --git a/bt/stack/l2cap/l2c_csm.cc b/bt/stack/l2cap/l2c_csm.cc
new file mode 100644
index 0000000..fd504f0
--- /dev/null
+++ b/bt/stack/l2cap/l2c_csm.cc
@@ -0,0 +1,1530 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 L2CAP channel state machine
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "bt_target.h"
+#include "bt_common.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "l2cdefs.h"
+#include "l2c_int.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "hcimsgs.h"
+
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+/********************************************************************************/
+/*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
+/********************************************************************************/
+static void l2c_csm_closed (tL2C_CCB *p_ccb, uint16_t event, void *p_data);
+static void l2c_csm_orig_w4_sec_comp (tL2C_CCB *p_ccb, uint16_t event, void *p_data);
+static void l2c_csm_term_w4_sec_comp (tL2C_CCB *p_ccb, uint16_t event, void *p_data);
+static void l2c_csm_w4_l2cap_connect_rsp (tL2C_CCB *p_ccb, uint16_t event, void *p_data);
+static void l2c_csm_w4_l2ca_connect_rsp (tL2C_CCB *p_ccb, uint16_t event, void *p_data);
+static void l2c_csm_config (tL2C_CCB *p_ccb, uint16_t event, void *p_data);
+static void l2c_csm_open (tL2C_CCB *p_ccb, uint16_t event, void *p_data);
+static void l2c_csm_w4_l2cap_disconnect_rsp (tL2C_CCB *p_ccb, uint16_t event, void *p_data);
+static void l2c_csm_w4_l2ca_disconnect_rsp (tL2C_CCB *p_ccb, uint16_t event, void *p_data);
+
+#if (BT_TRACE_VERBOSE == TRUE)
+static char *l2c_csm_get_event_name (uint16_t event);
+#endif
+
+/*******************************************************************************
+**
+** Function         l2c_csm_execute
+**
+** Description      This function executes the state machine.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2c_csm_execute (tL2C_CCB *p_ccb, uint16_t event, void *p_data)
+{
+    if (!l2cu_is_ccb_active(p_ccb)) {
+        L2CAP_TRACE_WARNING("%s CCB not in use, event (%d) cannot be processed", __func__, event);
+        return;
+    }
+
+    switch (p_ccb->chnl_state)
+    {
+    case CST_CLOSED:
+        l2c_csm_closed (p_ccb, event, p_data);
+        break;
+
+    case CST_ORIG_W4_SEC_COMP:
+        l2c_csm_orig_w4_sec_comp (p_ccb, event, p_data);
+        break;
+
+    case CST_TERM_W4_SEC_COMP:
+        l2c_csm_term_w4_sec_comp (p_ccb, event, p_data);
+        break;
+
+    case CST_W4_L2CAP_CONNECT_RSP:
+        l2c_csm_w4_l2cap_connect_rsp (p_ccb, event, p_data);
+        break;
+
+    case CST_W4_L2CA_CONNECT_RSP:
+        l2c_csm_w4_l2ca_connect_rsp (p_ccb, event, p_data);
+        break;
+
+    case CST_CONFIG:
+        l2c_csm_config (p_ccb, event, p_data);
+        break;
+
+    case CST_OPEN:
+        l2c_csm_open (p_ccb, event, p_data);
+        break;
+
+    case CST_W4_L2CAP_DISCONNECT_RSP:
+        l2c_csm_w4_l2cap_disconnect_rsp (p_ccb, event, p_data);
+        break;
+
+    case CST_W4_L2CA_DISCONNECT_RSP:
+        l2c_csm_w4_l2ca_disconnect_rsp (p_ccb, event, p_data);
+        break;
+
+    default:
+        L2CAP_TRACE_DEBUG("Unhandled event! event = %d",event);
+        break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2c_csm_closed
+**
+** Description      This function handles events when the channel is in
+**                  CLOSED state. This state exists only when the link is
+**                  being initially established.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void l2c_csm_closed (tL2C_CCB *p_ccb, uint16_t event, void *p_data)
+{
+    tL2C_CONN_INFO          *p_ci = (tL2C_CONN_INFO *)p_data;
+    uint16_t                local_cid = p_ccb->local_cid;
+    tL2CA_DISCONNECT_IND_CB *disconnect_ind;
+    tL2CA_CONNECT_CFM_CB    *connect_cfm;
+
+    if (p_ccb->p_rcb == NULL)
+    {
+#if (BT_TRACE_VERBOSE == TRUE)
+        L2CAP_TRACE_ERROR ("L2CAP - LCID: 0x%04x  st: CLOSED  evt: %s p_rcb == NULL", p_ccb->local_cid, l2c_csm_get_event_name (event));
+#else
+        L2CAP_TRACE_ERROR ("L2CAP - LCID: 0x%04x  st: CLOSED  evt: 0x%04x p_rcb == NULL", p_ccb->local_cid, event);
+#endif
+        return;
+    }
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+    if ( local_cid == L2CAP_CONNECTIONLESS_CID )
+    {
+        /* check if this event can be processed by UCD */
+        if ( l2c_ucd_process_event (p_ccb, event, p_data) )
+        {
+            /* The event is processed by UCD state machine */
+            return;
+        }
+    }
+#endif
+
+    disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+    connect_cfm    = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+    L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x  st: CLOSED  evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
+#else
+    L2CAP_TRACE_EVENT ("L2CAP - st: CLOSED evt: %d", event);
+#endif
+
+    switch (event)
+    {
+    case L2CEVT_LP_DISCONNECT_IND:                  /* Link was disconnected */
+        L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x  No Conf Needed", p_ccb->local_cid);
+        l2cu_release_ccb (p_ccb);
+        (*disconnect_ind)(local_cid, false);
+        break;
+
+    case L2CEVT_LP_CONNECT_CFM:                         /* Link came up         */
+        if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
+        {
+            p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
+            l2ble_sec_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, true,
+                    &l2c_link_sec_comp, p_ccb);
+        }
+        else
+        {
+            p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
+            btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
+                                      p_ccb->p_lcb->handle, true, &l2c_link_sec_comp, p_ccb);
+        }
+        break;
+
+    case L2CEVT_LP_CONNECT_CFM_NEG:                     /* Link failed          */
+        /* Disconnect unless ACL collision and upper layer wants to handle it */
+        if (p_ci->status != HCI_ERR_CONNECTION_EXISTS
+            || !btm_acl_notif_conn_collision(p_ccb->p_lcb->remote_bd_addr))
+        {
+            L2CAP_TRACE_API ("L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x  Status: %d", p_ccb->local_cid, p_ci->status);
+            l2cu_release_ccb (p_ccb);
+            (*connect_cfm)(local_cid, p_ci->status);
+        }
+        break;
+
+    case L2CEVT_L2CA_CONNECT_REQ:                       /* API connect request  */
+        if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
+        {
+            p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
+            l2ble_sec_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, true,
+                    &l2c_link_sec_comp, p_ccb);
+        }
+        else
+        {
+            /* Cancel sniff mode if needed */
+            {
+                tBTM_PM_PWR_MD settings;
+                memset((void*)&settings, 0, sizeof(settings));
+                settings.mode = BTM_PM_MD_ACTIVE;
+/* COVERITY
+Event uninit_use_in_call: Using uninitialized value "settings" (field "settings".timeout uninitialized) in call to function "BTM_SetPowerMode" [details]
+Event uninit_use_in_call: Using uninitialized value "settings.max" in call to function "BTM_SetPowerMode" [details]
+Event uninit_use_in_call: Using uninitialized value "settings.min" in call to function "BTM_SetPowerMode"
+// false-POSITIVE error from Coverity test-tool. Please do NOT remove following comment.
+// coverity[uninit_use_in_call] False-positive: setting the mode to BTM_PM_MD_ACTIVE only uses settings.mode the other data members of tBTM_PM_PWR_MD are ignored
+*/
+                BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
+            }
+
+            /* If sec access does not result in started SEC_COM or COMP_NEG are already processed */
+            if (btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
+                                          p_ccb->p_lcb->handle, true, &l2c_link_sec_comp, p_ccb) == BTM_CMD_STARTED)
+                p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
+        }
+        break;
+
+    case L2CEVT_SEC_COMP:
+        p_ccb->chnl_state = CST_W4_L2CAP_CONNECT_RSP;
+
+        /* Wait for the info resp in this state before sending connect req (if needed) */
+        if (!p_ccb->p_lcb->w4_info_rsp)
+        {
+            /* Need to have at least one compatible channel to continue */
+            if (!l2c_fcr_chk_chan_modes(p_ccb))
+            {
+                l2cu_release_ccb (p_ccb);
+                (*p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb)(local_cid, L2CAP_CONN_NO_LINK);
+            }
+            else
+            {
+                l2cu_send_peer_connect_req (p_ccb);
+                alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                                   L2CAP_CHNL_CONNECT_TIMEOUT_MS,
+                                   l2c_ccb_timer_timeout, p_ccb,
+                                   btu_general_alarm_queue);
+            }
+        }
+        break;
+
+    case L2CEVT_SEC_COMP_NEG:                           /* something is really bad with security */
+        L2CAP_TRACE_API ("L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x  Status: %d", p_ccb->local_cid, L2CAP_CONN_TIMEOUT);
+        l2cu_release_ccb (p_ccb);
+        (*connect_cfm)(local_cid, L2CAP_CONN_SECURITY_BLOCK);
+        break;
+
+    case L2CEVT_L2CAP_CONNECT_REQ:                      /* Peer connect request */
+        /* stop link timer to avoid race condition between A2MP, Security, and L2CAP */
+        alarm_cancel(p_ccb->p_lcb->l2c_lcb_timer);
+
+        if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
+        {
+            p_ccb->chnl_state = CST_TERM_W4_SEC_COMP;
+             l2ble_sec_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, false,
+                    &l2c_link_sec_comp, p_ccb);
+        }
+        else
+        {
+            /* Cancel sniff mode if needed */
+            {
+                tBTM_PM_PWR_MD settings;
+                memset((void*)&settings, 0, sizeof(settings));
+                settings.mode = BTM_PM_MD_ACTIVE;
+/* COVERITY
+Event uninit_use_in_call: Using uninitialized value "settings" (field "settings".timeout uninitialized) in call to function "BTM_SetPowerMode" [details]
+Event uninit_use_in_call: Using uninitialized value "settings.max" in call to function "BTM_SetPowerMode" [details]
+Event uninit_use_in_call: Using uninitialized value "settings.min" in call to function "BTM_SetPowerMode"
+// false-POSITIVE error from Coverity test-tool. Please do NOT remove following comment.
+// coverity[uninit_use_in_call] False-positive: setting the mode to BTM_PM_MD_ACTIVE only uses settings.mode the other data members of tBTM_PM_PWR_MD are ignored
+*/
+                BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
+            }
+
+            p_ccb->chnl_state = CST_TERM_W4_SEC_COMP;
+            if (btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
+                                      p_ccb->p_lcb->handle, false, &l2c_link_sec_comp, p_ccb) == BTM_CMD_STARTED)
+            {
+                /* started the security process, tell the peer to set a longer timer */
+                l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_PENDING, 0);
+            }
+        }
+        break;
+
+    case L2CEVT_TIMEOUT:
+        L2CAP_TRACE_API ("L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x  Status: %d", p_ccb->local_cid, L2CAP_CONN_TIMEOUT);
+        l2cu_release_ccb (p_ccb);
+        (*connect_cfm)(local_cid, L2CAP_CONN_TIMEOUT);
+        break;
+
+    case L2CEVT_L2CAP_DATA:                         /* Peer data packet rcvd    */
+    case L2CEVT_L2CA_DATA_WRITE:                    /* Upper layer data to send */
+        osi_free(p_data);
+        break;
+
+    case L2CEVT_L2CA_DISCONNECT_REQ:                 /* Upper wants to disconnect */
+        l2cu_release_ccb (p_ccb);
+        break;
+
+    case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT:
+    case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
+        osi_free(p_data);
+        break;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         l2c_csm_orig_w4_sec_comp
+**
+** Description      This function handles events when the channel is in
+**                  CST_ORIG_W4_SEC_COMP state.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void l2c_csm_orig_w4_sec_comp (tL2C_CCB *p_ccb, uint16_t event, void *p_data)
+{
+    tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+    tL2CA_CONNECT_CFM_CB    *connect_cfm = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb;
+    uint16_t                local_cid = p_ccb->local_cid;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+    L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x  st: ORIG_W4_SEC_COMP  evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
+#else
+    L2CAP_TRACE_EVENT ("L2CAP - st: ORIG_W4_SEC_COMP evt: %d", event);
+#endif
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+    if ( local_cid == L2CAP_CONNECTIONLESS_CID )
+    {
+        /* check if this event can be processed by UCD */
+        if ( l2c_ucd_process_event (p_ccb, event, p_data) )
+        {
+            /* The event is processed by UCD state machine */
+            return;
+        }
+    }
+#endif
+
+    switch (event)
+    {
+    case L2CEVT_LP_DISCONNECT_IND:                   /* Link was disconnected */
+        L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x  No Conf Needed", p_ccb->local_cid);
+        l2cu_release_ccb (p_ccb);
+        (*disconnect_ind)(local_cid, false);
+        break;
+
+    case L2CEVT_SEC_RE_SEND_CMD:                    /* BTM has enough info to proceed */
+    case L2CEVT_LP_CONNECT_CFM:                     /* Link came up         */
+        if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
+        {
+             l2ble_sec_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, false,
+                    &l2c_link_sec_comp, p_ccb);
+        }
+        else
+        {
+            btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
+                                  p_ccb->p_lcb->handle, true, &l2c_link_sec_comp, p_ccb);
+        }
+        break;
+
+    case L2CEVT_SEC_COMP:                            /* Security completed success */
+        /* Wait for the info resp in this state before sending connect req (if needed) */
+        p_ccb->chnl_state = CST_W4_L2CAP_CONNECT_RSP;
+        if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
+        {
+            alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                               L2CAP_CHNL_CONNECT_TIMEOUT_MS,
+                               l2c_ccb_timer_timeout, p_ccb,
+                               btu_general_alarm_queue);
+            l2cble_credit_based_conn_req (p_ccb);          /* Start Connection     */
+        }
+        else
+        {
+            if (!p_ccb->p_lcb->w4_info_rsp)
+            {
+                /* Need to have at least one compatible channel to continue */
+                if (!l2c_fcr_chk_chan_modes(p_ccb))
+                {
+                    l2cu_release_ccb (p_ccb);
+                    (*connect_cfm)(local_cid, L2CAP_CONN_NO_LINK);
+                }
+                else
+                {
+                    alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                                       L2CAP_CHNL_CONNECT_TIMEOUT_MS,
+                                       l2c_ccb_timer_timeout, p_ccb,
+                                       btu_general_alarm_queue);
+                    l2cu_send_peer_connect_req (p_ccb);          /* Start Connection     */
+                }
+            }
+        }
+        break;
+
+    case L2CEVT_SEC_COMP_NEG:
+        L2CAP_TRACE_API ("L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x  Status: %d", p_ccb->local_cid, HCI_ERR_AUTH_FAILURE);
+
+        /* If last channel immediately disconnect the ACL for better security.
+           Also prevents a race condition between BTM and L2CAP */
+        if ( (p_ccb == p_ccb->p_lcb->ccb_queue.p_first_ccb) && (p_ccb == p_ccb->p_lcb->ccb_queue.p_last_ccb) )
+        {
+            p_ccb->p_lcb->idle_timeout = 0;
+        }
+
+        l2cu_release_ccb (p_ccb);
+        (*connect_cfm)(local_cid, HCI_ERR_AUTH_FAILURE);
+        break;
+
+    case L2CEVT_L2CA_DATA_WRITE:                    /* Upper layer data to send */
+    case L2CEVT_L2CAP_DATA:                         /* Peer data packet rcvd    */
+        osi_free(p_data);
+        break;
+
+    case L2CEVT_L2CA_DISCONNECT_REQ:                 /* Upper wants to disconnect */
+        /* Tell security manager to abort */
+        btm_sec_abort_access_req (p_ccb->p_lcb->remote_bd_addr);
+
+        l2cu_release_ccb (p_ccb);
+        break;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         l2c_csm_term_w4_sec_comp
+**
+** Description      This function handles events when the channel is in
+**                  CST_TERM_W4_SEC_COMP state.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void l2c_csm_term_w4_sec_comp (tL2C_CCB *p_ccb, uint16_t event, void *p_data)
+{
+#if (BT_TRACE_VERBOSE == TRUE)
+    L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x  st: TERM_W4_SEC_COMP  evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
+#else
+    L2CAP_TRACE_EVENT ("L2CAP - st: TERM_W4_SEC_COMP evt: %d", event);
+#endif
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+    if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
+    {
+        /* check if this event can be processed by UCD */
+        if ( l2c_ucd_process_event (p_ccb, event, p_data) )
+        {
+            /* The event is processed by UCD state machine */
+            return;
+        }
+    }
+#endif
+
+    switch (event)
+    {
+    case L2CEVT_LP_DISCONNECT_IND:                  /* Link was disconnected */
+        /* Tell security manager to abort */
+        btm_sec_abort_access_req (p_ccb->p_lcb->remote_bd_addr);
+
+        l2cu_release_ccb (p_ccb);
+        break;
+
+    case L2CEVT_SEC_COMP:
+        p_ccb->chnl_state = CST_W4_L2CA_CONNECT_RSP;
+
+        /* Wait for the info resp in next state before sending connect ind (if needed) */
+        if (!p_ccb->p_lcb->w4_info_rsp)
+        {
+            /* Don't need to get info from peer or already retrieved so continue */
+            alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                               L2CAP_CHNL_CONNECT_TIMEOUT_MS,
+                               l2c_ccb_timer_timeout, p_ccb,
+                               btu_general_alarm_queue);
+            L2CAP_TRACE_API ("L2CAP - Calling Connect_Ind_Cb(), CID: 0x%04x", p_ccb->local_cid);
+
+            (*p_ccb->p_rcb->api.pL2CA_ConnectInd_Cb) (p_ccb->p_lcb->remote_bd_addr, p_ccb->local_cid,
+                                                      p_ccb->p_rcb->psm, p_ccb->remote_id);
+        }
+        else
+        {
+            /*
+            ** L2CAP Connect Response will be sent out by 3 sec timer expiration
+            ** because Bluesoleil doesn't respond to L2CAP Information Request.
+            ** Bluesoleil seems to disconnect ACL link as failure case, because
+            ** it takes too long (4~7secs) to get response.
+            ** product version : Bluesoleil 2.1.1.0 EDR Release 060123
+            ** stack version   : 05.04.11.20060119
+            */
+
+            /* Waiting for the info resp, tell the peer to set a longer timer */
+            l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_PENDING, 0);
+        }
+        break;
+
+    case L2CEVT_SEC_COMP_NEG:
+        if (((tL2C_CONN_INFO *)p_data)->status == BTM_DELAY_CHECK)
+        {
+            /* start a timer - encryption change not received before L2CAP connect req */
+            alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                               L2CAP_DELAY_CHECK_SM4_TIMEOUT_MS,
+                               l2c_ccb_timer_timeout, p_ccb,
+                               btu_general_alarm_queue);
+        }
+        else
+        {
+            if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
+                l2cu_reject_ble_connection(p_ccb->p_lcb, p_ccb->remote_id, L2CAP_LE_INSUFFICIENT_AUTHENTICATION);
+            else
+                l2cu_send_peer_connect_rsp (p_ccb, L2CAP_CONN_SECURITY_BLOCK, 0);
+            l2cu_release_ccb (p_ccb);
+        }
+        break;
+
+    case L2CEVT_L2CA_DATA_WRITE:                    /* Upper layer data to send */
+    case L2CEVT_L2CAP_DATA:                         /* Peer data packet rcvd    */
+        osi_free(p_data);
+        break;
+
+    case L2CEVT_L2CA_DISCONNECT_REQ:                 /* Upper wants to disconnect */
+        l2cu_release_ccb (p_ccb);
+        break;
+
+    case L2CEVT_L2CAP_DISCONNECT_REQ:                  /* Peer disconnected request */
+        l2cu_send_peer_disc_rsp (p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid, p_ccb->remote_cid);
+
+        /* Tell security manager to abort */
+        btm_sec_abort_access_req (p_ccb->p_lcb->remote_bd_addr);
+
+        l2cu_release_ccb (p_ccb);
+        break;
+
+    case L2CEVT_TIMEOUT:
+        /* SM4 related. */
+        btsnd_hcic_disconnect(p_ccb->p_lcb->handle, HCI_ERR_AUTH_FAILURE);
+        break;
+
+    case L2CEVT_SEC_RE_SEND_CMD:                    /* BTM has enough info to proceed */
+        btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
+                                  p_ccb->p_lcb->handle, false, &l2c_link_sec_comp, p_ccb);
+        break;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         l2c_csm_w4_l2cap_connect_rsp
+**
+** Description      This function handles events when the channel is in
+**                  CST_W4_L2CAP_CONNECT_RSP state.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void l2c_csm_w4_l2cap_connect_rsp (tL2C_CCB *p_ccb, uint16_t event, void *p_data)
+{
+    tL2C_CONN_INFO          *p_ci = (tL2C_CONN_INFO *)p_data;
+    tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+    tL2CA_CONNECT_CFM_CB    *connect_cfm = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb;
+    uint16_t                local_cid = p_ccb->local_cid;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+    L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x  st: W4_L2CAP_CON_RSP  evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
+#else
+    L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CAP_CON_RSP evt: %d", event);
+#endif
+
+    switch (event)
+    {
+    case L2CEVT_LP_DISCONNECT_IND:                  /* Link was disconnected */
+        /* Send disc indication unless peer to peer race condition AND normal disconnect */
+        /* *((uint8_t *)p_data) != HCI_ERR_PEER_USER happens when peer device try to disconnect for normal reason */
+        p_ccb->chnl_state = CST_CLOSED;
+        if ((p_ccb->flags & CCB_FLAG_NO_RETRY) || !p_data || (*((uint8_t *)p_data) != HCI_ERR_PEER_USER))
+        {
+            L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x  No Conf Needed",
+                              p_ccb->local_cid);
+            l2cu_release_ccb (p_ccb);
+            (*disconnect_ind)(local_cid, false);
+        }
+        p_ccb->flags |= CCB_FLAG_NO_RETRY;
+        break;
+
+    case L2CEVT_L2CAP_CONNECT_RSP:                  /* Got peer connect confirm */
+        p_ccb->remote_cid = p_ci->remote_cid;
+        if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
+        {
+            /* Connection is completed */
+            alarm_cancel(p_ccb->l2c_ccb_timer);
+            p_ccb->chnl_state = CST_OPEN;
+        }
+        else
+        {
+            p_ccb->chnl_state = CST_CONFIG;
+            alarm_set_on_queue(p_ccb->l2c_ccb_timer, L2CAP_CHNL_CFG_TIMEOUT_MS,
+                               l2c_ccb_timer_timeout, p_ccb,
+                               btu_general_alarm_queue);
+        }
+        L2CAP_TRACE_API ("L2CAP - Calling Connect_Cfm_Cb(), CID: 0x%04x, Success", p_ccb->local_cid);
+
+        (*p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb)(local_cid, L2CAP_CONN_OK);
+        break;
+
+    case L2CEVT_L2CAP_CONNECT_RSP_PND:              /* Got peer connect pending */
+        p_ccb->remote_cid = p_ci->remote_cid;
+        alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                           L2CAP_CHNL_CONNECT_EXT_TIMEOUT_MS,
+                           l2c_ccb_timer_timeout, p_ccb,
+                           btu_general_alarm_queue);
+        if (p_ccb->p_rcb->api.pL2CA_ConnectPnd_Cb)
+        {
+            L2CAP_TRACE_API ("L2CAP - Calling Connect_Pnd_Cb(), CID: 0x%04x", p_ccb->local_cid);
+            (*p_ccb->p_rcb->api.pL2CA_ConnectPnd_Cb)(p_ccb->local_cid);
+        }
+        break;
+
+    case L2CEVT_L2CAP_CONNECT_RSP_NEG:              /* Peer rejected connection */
+        L2CAP_TRACE_API ("L2CAP - Calling Connect_Cfm_Cb(), CID: 0x%04x, Failure Code: %d", p_ccb->local_cid, p_ci->l2cap_result);
+        l2cu_release_ccb (p_ccb);
+        (*connect_cfm)(local_cid, p_ci->l2cap_result);
+        break;
+
+    case L2CEVT_TIMEOUT:
+        L2CAP_TRACE_API ("L2CAP - Calling Connect_Cfm_Cb(), CID: 0x%04x, Timeout", p_ccb->local_cid);
+        l2cu_release_ccb (p_ccb);
+        (*connect_cfm)(local_cid, L2CAP_CONN_TIMEOUT);
+        break;
+
+    case L2CEVT_L2CA_DISCONNECT_REQ:                 /* Upper wants to disconnect */
+        /* If we know peer CID from connect pending, we can send disconnect */
+        if (p_ccb->remote_cid != 0)
+        {
+            l2cu_send_peer_disc_req (p_ccb);
+            p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
+            alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                               L2CAP_CHNL_DISCONNECT_TIMEOUT_MS,
+                               l2c_ccb_timer_timeout, p_ccb,
+                               btu_general_alarm_queue);
+        }
+        else
+        {
+            tL2CA_DISCONNECT_CFM_CB *disconnect_cfm = p_ccb->p_rcb->api.pL2CA_DisconnectCfm_Cb;
+            l2cu_release_ccb(p_ccb);
+            if (disconnect_cfm)
+            {
+                L2CAP_TRACE_API("%s: L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x", __func__, local_cid);
+                (*disconnect_cfm)(local_cid, L2CAP_CONN_NO_LINK);
+            }
+        }
+        break;
+
+    case L2CEVT_L2CA_DATA_WRITE:                    /* Upper layer data to send */
+    case L2CEVT_L2CAP_DATA:                         /* Peer data packet rcvd    */
+        osi_free(p_data);
+        break;
+
+    case L2CEVT_L2CAP_INFO_RSP:
+        /* Need to have at least one compatible channel to continue */
+        if (!l2c_fcr_chk_chan_modes(p_ccb))
+        {
+            l2cu_release_ccb (p_ccb);
+            (*connect_cfm)(local_cid, L2CAP_CONN_NO_LINK);
+        }
+        else
+        {
+            /* We have feature info, so now send peer connect request */
+            alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                               L2CAP_CHNL_CONNECT_TIMEOUT_MS,
+                               l2c_ccb_timer_timeout, p_ccb,
+                               btu_general_alarm_queue);
+            l2cu_send_peer_connect_req (p_ccb);          /* Start Connection     */
+        }
+        break;
+
+    case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT:
+    case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
+        osi_free(p_data);
+        break;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         l2c_csm_w4_l2ca_connect_rsp
+**
+** Description      This function handles events when the channel is in
+**                  CST_W4_L2CA_CONNECT_RSP state.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void l2c_csm_w4_l2ca_connect_rsp (tL2C_CCB *p_ccb, uint16_t event, void *p_data)
+{
+    tL2C_CONN_INFO          *p_ci;
+    tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+    uint16_t                local_cid = p_ccb->local_cid;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+    L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x  st: W4_L2CA_CON_RSP  evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
+#else
+    L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CA_CON_RSP evt: %d", event);
+#endif
+
+    switch (event)
+    {
+    case L2CEVT_LP_DISCONNECT_IND:                  /* Link was disconnected */
+        L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x  No Conf Needed", p_ccb->local_cid);
+        l2cu_release_ccb (p_ccb);
+        (*disconnect_ind)(local_cid, false);
+        break;
+
+    case L2CEVT_L2CA_CONNECT_RSP:
+        p_ci = (tL2C_CONN_INFO *)p_data;
+        if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
+        {
+            /* Result should be OK or Reject */
+            if ((!p_ci) || (p_ci->l2cap_result == L2CAP_CONN_OK))
+            {
+                l2cble_credit_based_conn_res (p_ccb, L2CAP_CONN_OK);
+                p_ccb->chnl_state = CST_OPEN;
+                alarm_cancel(p_ccb->l2c_ccb_timer);
+            }
+            else
+            {
+                l2cble_credit_based_conn_res (p_ccb, p_ci->l2cap_result);
+                l2cu_release_ccb (p_ccb);
+            }
+        }
+        else
+        {
+            /* Result should be OK or PENDING */
+            if ((!p_ci) || (p_ci->l2cap_result == L2CAP_CONN_OK))
+            {
+                l2cu_send_peer_connect_rsp (p_ccb, L2CAP_CONN_OK, 0);
+                p_ccb->chnl_state = CST_CONFIG;
+                alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                                   L2CAP_CHNL_CFG_TIMEOUT_MS,
+                                   l2c_ccb_timer_timeout, p_ccb,
+                                   btu_general_alarm_queue);
+            }
+            else
+            {
+                /* If pending, stay in same state and start extended timer */
+                l2cu_send_peer_connect_rsp (p_ccb, p_ci->l2cap_result, p_ci->l2cap_status);
+                alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                                   L2CAP_CHNL_CONNECT_EXT_TIMEOUT_MS,
+                                   l2c_ccb_timer_timeout, p_ccb,
+                                   btu_general_alarm_queue);
+            }
+        }
+        break;
+
+    case L2CEVT_L2CA_CONNECT_RSP_NEG:
+        p_ci = (tL2C_CONN_INFO *)p_data;
+        if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
+            l2cble_credit_based_conn_res (p_ccb, p_ci->l2cap_result);
+        else
+            l2cu_send_peer_connect_rsp (p_ccb, p_ci->l2cap_result, p_ci->l2cap_status);
+        l2cu_release_ccb (p_ccb);
+        break;
+
+    case L2CEVT_TIMEOUT:
+        l2cu_send_peer_connect_rsp (p_ccb, L2CAP_CONN_NO_PSM, 0);
+        L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x  No Conf Needed", p_ccb->local_cid);
+        l2cu_release_ccb (p_ccb);
+        (*disconnect_ind)(local_cid, false);
+        break;
+
+    case L2CEVT_L2CA_DATA_WRITE:                    /* Upper layer data to send */
+    case L2CEVT_L2CAP_DATA:                         /* Peer data packet rcvd    */
+        osi_free(p_data);
+        break;
+
+    case L2CEVT_L2CA_DISCONNECT_REQ:                 /* Upper wants to disconnect */
+        l2cu_send_peer_disc_req (p_ccb);
+        p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
+        alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                           L2CAP_CHNL_DISCONNECT_TIMEOUT_MS,
+                           l2c_ccb_timer_timeout, p_ccb,
+                           btu_general_alarm_queue);
+        break;
+
+    case L2CEVT_L2CAP_INFO_RSP:
+        /* We have feature info, so now give the upper layer connect IND */
+        alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                           L2CAP_CHNL_CONNECT_TIMEOUT_MS,
+                           l2c_ccb_timer_timeout, p_ccb,
+                           btu_general_alarm_queue);
+        L2CAP_TRACE_API ("L2CAP - Calling Connect_Ind_Cb(), CID: 0x%04x", p_ccb->local_cid);
+
+        (*p_ccb->p_rcb->api.pL2CA_ConnectInd_Cb) (p_ccb->p_lcb->remote_bd_addr,
+                                                  p_ccb->local_cid,
+                                                  p_ccb->p_rcb->psm,
+                                                  p_ccb->remote_id);
+        break;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         l2c_csm_config
+**
+** Description      This function handles events when the channel is in
+**                  CONFIG state.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void l2c_csm_config (tL2C_CCB *p_ccb, uint16_t event, void *p_data)
+{
+    tL2CAP_CFG_INFO         *p_cfg = (tL2CAP_CFG_INFO *)p_data;
+    tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+    uint16_t                local_cid = p_ccb->local_cid;
+    uint8_t                 cfg_result;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+    L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x  st: CONFIG  evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
+#else
+    L2CAP_TRACE_EVENT ("L2CAP - st: CONFIG evt: %d", event);
+#endif
+
+    switch (event)
+    {
+    case L2CEVT_LP_DISCONNECT_IND:                  /* Link was disconnected */
+        L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x  No Conf Needed", p_ccb->local_cid);
+        l2cu_release_ccb (p_ccb);
+        (*disconnect_ind)(local_cid, false);
+        break;
+
+    case L2CEVT_L2CAP_CONFIG_REQ:                  /* Peer config request   */
+
+        if ((cfg_result = l2cu_process_peer_cfg_req (p_ccb, p_cfg)) == L2CAP_PEER_CFG_OK)
+        {
+            L2CAP_TRACE_EVENT ("L2CAP - Calling Config_Req_Cb(), CID: 0x%04x, C-bit %d",
+                                p_ccb->local_cid, (p_cfg->flags & L2CAP_CFG_FLAGS_MASK_CONT));
+            (*p_ccb->p_rcb->api.pL2CA_ConfigInd_Cb)(p_ccb->local_cid, p_cfg);
+        }
+        else if (cfg_result == L2CAP_PEER_CFG_DISCONNECT)
+        {
+            /* Disconnect if channels are incompatible */
+            L2CAP_TRACE_EVENT ("L2CAP - incompatible configurations disconnect");
+            l2cu_disconnect_chnl (p_ccb);
+        }
+        else /* Return error to peer so he can renegotiate if possible */
+        {
+            L2CAP_TRACE_EVENT ("L2CAP - incompatible configurations trying reconfig");
+            l2cu_send_peer_config_rsp (p_ccb, p_cfg);
+        }
+        break;
+
+    case L2CEVT_L2CAP_CONFIG_RSP:                  /* Peer config response  */
+         l2cu_process_peer_cfg_rsp (p_ccb, p_cfg);
+
+         if (p_cfg->result != L2CAP_CFG_PENDING)
+         {
+             /* TBD: When config options grow beyong minimum MTU (48 bytes)
+              *      logic needs to be added to handle responses with
+              *      continuation bit set in flags field.
+              *       1. Send additional config request out until C-bit is cleared in response
+              */
+             p_ccb->config_done |= OB_CFG_DONE;
+
+             if (p_ccb->config_done & IB_CFG_DONE)
+             {
+                /* Verify two sides are in compatible modes before continuing */
+                if (p_ccb->our_cfg.fcr.mode != p_ccb->peer_cfg.fcr.mode)
+                {
+                    l2cu_send_peer_disc_req (p_ccb);
+                    L2CAP_TRACE_WARNING ("L2CAP - Calling Disconnect_Ind_Cb(Incompatible CFG), CID: 0x%04x  No Conf Needed", p_ccb->local_cid);
+                    l2cu_release_ccb (p_ccb);
+                    (*disconnect_ind)(local_cid, false);
+                    break;
+                }
+
+                p_ccb->config_done |= RECONFIG_FLAG;
+                p_ccb->chnl_state = CST_OPEN;
+                l2c_link_adjust_chnl_allocation ();
+                alarm_cancel(p_ccb->l2c_ccb_timer);
+
+                /* If using eRTM and waiting for an ACK, restart the ACK timer */
+                if (p_ccb->fcrb.wait_ack)
+                    l2c_fcr_start_timer(p_ccb);
+
+                /*
+                ** check p_ccb->our_cfg.fcr.mon_tout and p_ccb->our_cfg.fcr.rtrans_tout
+                ** we may set them to zero when sending config request during renegotiation
+                */
+                if ((p_ccb->our_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
+                   &&((p_ccb->our_cfg.fcr.mon_tout == 0)||(p_ccb->our_cfg.fcr.rtrans_tout)))
+                {
+                    l2c_fcr_adj_monitor_retran_timeout (p_ccb);
+                }
+
+#if (L2CAP_ERTM_STATS == TRUE)
+                p_ccb->fcrb.connect_tick_count = time_get_os_boottime_ms();
+#endif
+                /* See if we can forward anything on the hold queue */
+                if (!fixed_queue_is_empty(p_ccb->xmit_hold_q))
+                {
+                    l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
+                }
+            }
+        }
+
+        L2CAP_TRACE_API ("L2CAP - Calling Config_Rsp_Cb(), CID: 0x%04x", p_ccb->local_cid);
+        (*p_ccb->p_rcb->api.pL2CA_ConfigCfm_Cb)(p_ccb->local_cid, p_cfg);
+        break;
+
+    case L2CEVT_L2CAP_CONFIG_RSP_NEG:              /* Peer config error rsp */
+        /* Disable the Timer */
+         alarm_cancel(p_ccb->l2c_ccb_timer);
+
+        /* If failure was channel mode try to renegotiate */
+        if (l2c_fcr_renegotiate_chan(p_ccb, p_cfg) == false)
+        {
+            L2CAP_TRACE_API ("L2CAP - Calling Config_Rsp_Cb(), CID: 0x%04x, Failure: %d", p_ccb->local_cid, p_cfg->result);
+            (*p_ccb->p_rcb->api.pL2CA_ConfigCfm_Cb)(p_ccb->local_cid, p_cfg);
+        }
+        break;
+
+    case L2CEVT_L2CAP_DISCONNECT_REQ:                  /* Peer disconnected request */
+        alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                           L2CAP_CHNL_DISCONNECT_TIMEOUT_MS,
+                           l2c_ccb_timer_timeout, p_ccb,
+                           btu_general_alarm_queue);
+        p_ccb->chnl_state = CST_W4_L2CA_DISCONNECT_RSP;
+        L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x  Conf Needed", p_ccb->local_cid);
+        (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(p_ccb->local_cid, true);
+        break;
+
+    case L2CEVT_L2CA_CONFIG_REQ:                   /* Upper layer config req   */
+        l2cu_process_our_cfg_req (p_ccb, p_cfg);
+        l2cu_send_peer_config_req (p_ccb, p_cfg);
+        alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                           L2CAP_CHNL_CFG_TIMEOUT_MS,
+                           l2c_ccb_timer_timeout, p_ccb,
+                           btu_general_alarm_queue);
+        break;
+
+    case L2CEVT_L2CA_CONFIG_RSP:                   /* Upper layer config rsp   */
+        l2cu_process_our_cfg_rsp (p_ccb, p_cfg);
+
+        /* Not finished if continuation flag is set */
+        if ( (p_cfg->flags & L2CAP_CFG_FLAGS_MASK_CONT) || (p_cfg->result == L2CAP_CFG_PENDING) )
+        {
+            /* Send intermediate response; remain in cfg state */
+            l2cu_send_peer_config_rsp (p_ccb, p_cfg);
+            break;
+        }
+
+        /* Local config done; clear cached configuration in case reconfig takes place later */
+        p_ccb->peer_cfg.mtu_present = false;
+        p_ccb->peer_cfg.flush_to_present = false;
+        p_ccb->peer_cfg.qos_present = false;
+
+        p_ccb->config_done |= IB_CFG_DONE;
+
+        if (p_ccb->config_done & OB_CFG_DONE)
+        {
+            /* Verify two sides are in compatible modes before continuing */
+            if (p_ccb->our_cfg.fcr.mode != p_ccb->peer_cfg.fcr.mode)
+            {
+                l2cu_send_peer_disc_req (p_ccb);
+                L2CAP_TRACE_WARNING ("L2CAP - Calling Disconnect_Ind_Cb(Incompatible CFG), CID: 0x%04x  No Conf Needed", p_ccb->local_cid);
+                l2cu_release_ccb (p_ccb);
+                (*disconnect_ind)(local_cid, false);
+                break;
+            }
+
+            p_ccb->config_done |= RECONFIG_FLAG;
+            p_ccb->chnl_state = CST_OPEN;
+            l2c_link_adjust_chnl_allocation ();
+            alarm_cancel(p_ccb->l2c_ccb_timer);
+        }
+
+        l2cu_send_peer_config_rsp (p_ccb, p_cfg);
+
+        /* If using eRTM and waiting for an ACK, restart the ACK timer */
+        if (p_ccb->fcrb.wait_ack)
+            l2c_fcr_start_timer(p_ccb);
+
+#if (L2CAP_ERTM_STATS == TRUE)
+        p_ccb->fcrb.connect_tick_count = time_get_os_boottime_ms();
+#endif
+
+        /* See if we can forward anything on the hold queue */
+        if ( (p_ccb->chnl_state == CST_OPEN) &&
+             (!fixed_queue_is_empty(p_ccb->xmit_hold_q)))
+        {
+            l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
+        }
+        break;
+
+    case L2CEVT_L2CA_CONFIG_RSP_NEG:               /* Upper layer config reject */
+        l2cu_send_peer_config_rsp (p_ccb, p_cfg);
+        alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                           L2CAP_CHNL_CFG_TIMEOUT_MS,
+                           l2c_ccb_timer_timeout, p_ccb,
+                           btu_general_alarm_queue);
+        break;
+
+    case L2CEVT_L2CA_DISCONNECT_REQ:                 /* Upper wants to disconnect */
+        l2cu_send_peer_disc_req (p_ccb);
+        p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
+        alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                           L2CAP_CHNL_DISCONNECT_TIMEOUT_MS,
+                           l2c_ccb_timer_timeout, p_ccb,
+                           btu_general_alarm_queue);
+        break;
+
+    case L2CEVT_L2CAP_DATA:                        /* Peer data packet rcvd    */
+        L2CAP_TRACE_API ("L2CAP - Calling DataInd_Cb(), CID: 0x%04x", p_ccb->local_cid);
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+        if (p_ccb->local_cid >= L2CAP_FIRST_FIXED_CHNL &&
+                p_ccb->local_cid <= L2CAP_LAST_FIXED_CHNL)
+        {
+            if (p_ccb->local_cid < L2CAP_BASE_APPL_CID)
+            {
+                if (l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)
+                    (*l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)
+                        (p_ccb->local_cid, p_ccb->p_lcb->remote_bd_addr,(BT_HDR *)p_data);
+                else
+                    osi_free(p_data);
+            break;
+            }
+        }
+#endif
+        (*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid, (BT_HDR *)p_data);
+        break;
+
+    case L2CEVT_L2CA_DATA_WRITE:                   /* Upper layer data to send */
+        if (p_ccb->config_done & OB_CFG_DONE)
+            l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_data);
+        else
+            osi_free(p_data);
+        break;
+
+    case L2CEVT_TIMEOUT:
+        l2cu_send_peer_disc_req (p_ccb);
+        L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x  No Conf Needed",
+                p_ccb->local_cid);
+        l2cu_release_ccb (p_ccb);
+        (*disconnect_ind)(local_cid, false);
+        break;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         l2c_csm_open
+**
+** Description      This function handles events when the channel is in
+**                  OPEN state.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void l2c_csm_open (tL2C_CCB *p_ccb, uint16_t event, void *p_data)
+{
+    uint16_t                local_cid = p_ccb->local_cid;
+    tL2CAP_CFG_INFO         *p_cfg;
+    tL2C_CHNL_STATE         tempstate;
+    uint8_t                 tempcfgdone;
+    uint8_t                 cfg_result;
+    uint16_t                *credit;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+    L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x  st: OPEN  evt: %s",
+            p_ccb->local_cid, l2c_csm_get_event_name (event));
+#else
+    L2CAP_TRACE_EVENT ("L2CAP - st: OPEN evt: %d", event);
+#endif
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+    if ( local_cid == L2CAP_CONNECTIONLESS_CID )
+    {
+        /* check if this event can be processed by UCD */
+        if ( l2c_ucd_process_event (p_ccb, event, p_data) )
+        {
+            /* The event is processed by UCD state machine */
+            return;
+        }
+    }
+#endif
+
+    switch (event)
+    {
+    case L2CEVT_LP_DISCONNECT_IND:                  /* Link was disconnected */
+        L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x  No Conf Needed",
+                p_ccb->local_cid);
+        l2cu_release_ccb (p_ccb);
+        if (p_ccb->p_rcb)
+            (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(local_cid, false);
+        break;
+
+    case L2CEVT_LP_QOS_VIOLATION_IND:               /* QOS violation         */
+        /* Tell upper layer. If service guaranteed, then clear the channel   */
+        if (p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb)
+            (*p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb)(p_ccb->p_lcb->remote_bd_addr);
+        break;
+
+    case L2CEVT_L2CAP_CONFIG_REQ:                  /* Peer config request   */
+        p_cfg = (tL2CAP_CFG_INFO *)p_data;
+
+        tempstate = p_ccb->chnl_state;
+        tempcfgdone = p_ccb->config_done;
+        p_ccb->chnl_state = CST_CONFIG;
+        p_ccb->config_done &= ~CFG_DONE_MASK;
+
+        alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                           L2CAP_CHNL_CFG_TIMEOUT_MS,
+                           l2c_ccb_timer_timeout, p_ccb,
+                           btu_general_alarm_queue);
+
+        if ((cfg_result = l2cu_process_peer_cfg_req (p_ccb, p_cfg)) == L2CAP_PEER_CFG_OK)
+        {
+            (*p_ccb->p_rcb->api.pL2CA_ConfigInd_Cb)(p_ccb->local_cid, p_cfg);
+        }
+
+        /* Error in config parameters: reset state and config flag */
+        else if (cfg_result == L2CAP_PEER_CFG_UNACCEPTABLE)
+        {
+            alarm_cancel(p_ccb->l2c_ccb_timer);
+            p_ccb->chnl_state = tempstate;
+            p_ccb->config_done = tempcfgdone;
+            l2cu_send_peer_config_rsp (p_ccb, p_cfg);
+        }
+        else    /* L2CAP_PEER_CFG_DISCONNECT */
+        {
+            /* Disconnect if channels are incompatible
+             * Note this should not occur if reconfigure
+             * since this should have never passed original config.
+             */
+            l2cu_disconnect_chnl (p_ccb);
+        }
+        break;
+
+    case L2CEVT_L2CAP_DISCONNECT_REQ:                  /* Peer disconnected request */
+        if (p_ccb->p_lcb->transport != BT_TRANSPORT_LE)
+        {
+        /* Make sure we are not in sniff mode */
+            {
+                tBTM_PM_PWR_MD settings;
+                memset((void*)&settings, 0, sizeof(settings));
+                settings.mode = BTM_PM_MD_ACTIVE;
+                BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
+            }
+        }
+
+        p_ccb->chnl_state = CST_W4_L2CA_DISCONNECT_RSP;
+        alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                           L2CAP_CHNL_DISCONNECT_TIMEOUT_MS,
+                           l2c_ccb_timer_timeout, p_ccb,
+                           btu_general_alarm_queue);
+        L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x  Conf Needed", p_ccb->local_cid);
+        (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(p_ccb->local_cid, true);
+        break;
+
+    case L2CEVT_L2CAP_DATA:                         /* Peer data packet rcvd    */
+        if ((p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_DataInd_Cb))
+            (*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid, (BT_HDR *)p_data);
+        break;
+
+    case L2CEVT_L2CA_DISCONNECT_REQ:                 /* Upper wants to disconnect */
+        if (p_ccb->p_lcb->transport != BT_TRANSPORT_LE)
+        {
+            /* Make sure we are not in sniff mode */
+            {
+                tBTM_PM_PWR_MD settings;
+                memset((void*)&settings, 0, sizeof(settings));
+                settings.mode = BTM_PM_MD_ACTIVE;
+                BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
+            }
+        }
+
+        if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
+            l2cble_send_peer_disc_req (p_ccb);
+        else
+            l2cu_send_peer_disc_req (p_ccb);
+
+        p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
+        alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                           L2CAP_CHNL_DISCONNECT_TIMEOUT_MS,
+                           l2c_ccb_timer_timeout, p_ccb,
+                           btu_general_alarm_queue);
+        break;
+
+    case L2CEVT_L2CA_DATA_WRITE:                    /* Upper layer data to send */
+        l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_data);
+        l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
+        break;
+
+    case L2CEVT_L2CA_CONFIG_REQ:                   /* Upper layer config req   */
+        p_ccb->chnl_state = CST_CONFIG;
+        p_ccb->config_done &= ~CFG_DONE_MASK;
+        l2cu_process_our_cfg_req (p_ccb, (tL2CAP_CFG_INFO *)p_data);
+        l2cu_send_peer_config_req (p_ccb, (tL2CAP_CFG_INFO *)p_data);
+        alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                           L2CAP_CHNL_CFG_TIMEOUT_MS,
+                           l2c_ccb_timer_timeout, p_ccb,
+                           btu_general_alarm_queue);
+        break;
+
+    case L2CEVT_TIMEOUT:
+        /* Process the monitor/retransmission time-outs in flow control/retrans mode */
+        if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
+            l2c_fcr_proc_tout (p_ccb);
+        break;
+
+    case L2CEVT_ACK_TIMEOUT:
+        l2c_fcr_proc_ack_tout (p_ccb);
+        break;
+
+    case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT:
+        L2CAP_TRACE_DEBUG("%s Sending credit",__func__);
+        credit = (uint16_t*)p_data;
+        l2cble_send_flow_control_credit(p_ccb, *credit);
+        break;
+
+    case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
+        credit = (uint16_t*)p_data;
+        L2CAP_TRACE_DEBUG("%s Credits received %d",__func__, *credit);
+        if((p_ccb->peer_conn_cfg.credits + *credit) > L2CAP_LE_MAX_CREDIT)
+        {
+            /* we have received credits more than max coc credits,
+             * so disconnecting the Le Coc Channel
+             */
+            l2cble_send_peer_disc_req (p_ccb);
+        }
+        else
+        {
+            p_ccb->peer_conn_cfg.credits += *credit;
+            l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
+        }
+        break;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         l2c_csm_w4_l2cap_disconnect_rsp
+**
+** Description      This function handles events when the channel is in
+**                  CST_W4_L2CAP_DISCONNECT_RSP state.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void l2c_csm_w4_l2cap_disconnect_rsp (tL2C_CCB *p_ccb, uint16_t event, void *p_data)
+{
+    tL2CA_DISCONNECT_CFM_CB *disconnect_cfm = p_ccb->p_rcb->api.pL2CA_DisconnectCfm_Cb;
+    uint16_t                local_cid = p_ccb->local_cid;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+    L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x  st: W4_L2CAP_DISC_RSP  evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
+#else
+    L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CAP_DISC_RSP evt: %d", event);
+#endif
+
+    switch (event)
+    {
+    case L2CEVT_L2CAP_DISCONNECT_RSP:                /* Peer disconnect response */
+        l2cu_release_ccb (p_ccb);
+        if (disconnect_cfm)
+        {
+            L2CAP_TRACE_API ("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x", local_cid);
+            (*disconnect_cfm)(local_cid, L2CAP_DISC_OK);
+        }
+        break;
+
+    case L2CEVT_L2CAP_DISCONNECT_REQ:                /* Peer disconnect request  */
+        l2cu_send_peer_disc_rsp (p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid, p_ccb->remote_cid);
+        l2cu_release_ccb (p_ccb);
+        if (disconnect_cfm)
+        {
+            L2CAP_TRACE_API ("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x", local_cid);
+            (*disconnect_cfm)(local_cid, L2CAP_DISC_OK);
+        }
+       break;
+
+    case L2CEVT_LP_DISCONNECT_IND:                  /* Link was disconnected */
+    case L2CEVT_TIMEOUT:                            /* Timeout */
+        l2cu_release_ccb (p_ccb);
+        if (disconnect_cfm)
+        {
+            L2CAP_TRACE_API ("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x", local_cid);
+            (*disconnect_cfm)(local_cid, L2CAP_DISC_TIMEOUT);
+        }
+        break;
+
+    case L2CEVT_L2CAP_DATA:                         /* Peer data packet rcvd    */
+    case L2CEVT_L2CA_DATA_WRITE:                    /* Upper layer data to send */
+        osi_free(p_data);
+        break;
+
+    case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT:
+    case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
+        osi_free(p_data);
+        break;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         l2c_csm_w4_l2ca_disconnect_rsp
+**
+** Description      This function handles events when the channel is in
+**                  CST_W4_L2CA_DISCONNECT_RSP state.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void l2c_csm_w4_l2ca_disconnect_rsp (tL2C_CCB *p_ccb, uint16_t event, void *p_data)
+{
+    tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+    uint16_t                local_cid = p_ccb->local_cid;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+    L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x  st: W4_L2CA_DISC_RSP  evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
+#else
+    L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CA_DISC_RSP evt: %d", event);
+#endif
+
+    switch (event)
+    {
+    case L2CEVT_LP_DISCONNECT_IND:                  /* Link was disconnected */
+        L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x  No Conf Needed", p_ccb->local_cid);
+        l2cu_release_ccb (p_ccb);
+        (*disconnect_ind)(local_cid, false);
+        break;
+
+    case L2CEVT_TIMEOUT:
+        l2cu_send_peer_disc_rsp (p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid, p_ccb->remote_cid);
+        L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x  No Conf Needed", p_ccb->local_cid);
+        l2cu_release_ccb (p_ccb);
+        (*disconnect_ind)(local_cid, false);
+        break;
+
+    case L2CEVT_L2CA_DISCONNECT_REQ:                /* Upper disconnect request */
+    case L2CEVT_L2CA_DISCONNECT_RSP:                /* Upper disconnect response */
+        l2cu_send_peer_disc_rsp (p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid, p_ccb->remote_cid);
+        l2cu_release_ccb (p_ccb);
+        break;
+
+    case L2CEVT_L2CAP_DATA:                         /* Peer data packet rcvd    */
+    case L2CEVT_L2CA_DATA_WRITE:                    /* Upper layer data to send */
+        osi_free(p_data);
+        break;
+    }
+}
+
+
+#if (BT_TRACE_VERBOSE == TRUE)
+/*******************************************************************************
+**
+** Function         l2c_csm_get_event_name
+**
+** Description      This function returns the event name.
+**
+** NOTE             conditionally compiled to save memory.
+**
+** Returns          pointer to the name
+**
+*******************************************************************************/
+static char *l2c_csm_get_event_name (uint16_t event)
+{
+    switch (event)
+    {
+    case L2CEVT_LP_CONNECT_CFM:                  /* Lower layer connect confirm          */
+        return ("LOWER_LAYER_CONNECT_CFM");
+    case L2CEVT_LP_CONNECT_CFM_NEG:              /* Lower layer connect confirm (failed) */
+        return ("LOWER_LAYER_CONNECT_CFM_NEG");
+    case L2CEVT_LP_CONNECT_IND:                  /* Lower layer connect indication       */
+        return ("LOWER_LAYER_CONNECT_IND");
+    case L2CEVT_LP_DISCONNECT_IND:               /* Lower layer disconnect indication    */
+        return ("LOWER_LAYER_DISCONNECT_IND");
+    case L2CEVT_LP_QOS_CFM:                      /* Lower layer QOS confirmation         */
+        return ("LOWER_LAYER_QOS_CFM");
+    case L2CEVT_LP_QOS_CFM_NEG:                  /* Lower layer QOS confirmation (failed)*/
+        return ("LOWER_LAYER_QOS_CFM_NEG");
+    case L2CEVT_LP_QOS_VIOLATION_IND:            /* Lower layer QOS violation indication */
+        return ("LOWER_LAYER_QOS_VIOLATION_IND");
+
+    case L2CEVT_SEC_COMP:                        /* Security cleared successfully        */
+        return ("SECURITY_COMPLETE");
+    case L2CEVT_SEC_COMP_NEG:                    /* Security procedure failed            */
+        return ("SECURITY_COMPLETE_NEG");
+
+    case L2CEVT_L2CAP_CONNECT_REQ:               /* Peer connection request              */
+        return ("PEER_CONNECT_REQ");
+    case L2CEVT_L2CAP_CONNECT_RSP:               /* Peer connection response             */
+        return ("PEER_CONNECT_RSP");
+    case L2CEVT_L2CAP_CONNECT_RSP_PND:           /* Peer connection response pending     */
+        return ("PEER_CONNECT_RSP_PND");
+    case L2CEVT_L2CAP_CONNECT_RSP_NEG:           /* Peer connection response (failed)    */
+        return ("PEER_CONNECT_RSP_NEG");
+    case L2CEVT_L2CAP_CONFIG_REQ:                /* Peer configuration request           */
+        return ("PEER_CONFIG_REQ");
+    case L2CEVT_L2CAP_CONFIG_RSP:                /* Peer configuration response          */
+        return ("PEER_CONFIG_RSP");
+    case L2CEVT_L2CAP_CONFIG_RSP_NEG:            /* Peer configuration response (failed) */
+        return ("PEER_CONFIG_RSP_NEG");
+    case L2CEVT_L2CAP_DISCONNECT_REQ:            /* Peer disconnect request              */
+        return ("PEER_DISCONNECT_REQ");
+    case L2CEVT_L2CAP_DISCONNECT_RSP:            /* Peer disconnect response             */
+        return ("PEER_DISCONNECT_RSP");
+    case L2CEVT_L2CAP_DATA:                      /* Peer data                            */
+        return ("PEER_DATA");
+
+    case L2CEVT_L2CA_CONNECT_REQ:                /* Upper layer connect request          */
+        return ("UPPER_LAYER_CONNECT_REQ");
+    case L2CEVT_L2CA_CONNECT_RSP:                /* Upper layer connect response         */
+        return ("UPPER_LAYER_CONNECT_RSP");
+    case L2CEVT_L2CA_CONNECT_RSP_NEG:            /* Upper layer connect response (failed)*/
+        return ("UPPER_LAYER_CONNECT_RSP_NEG");
+    case L2CEVT_L2CA_CONFIG_REQ:                 /* Upper layer config request           */
+        return ("UPPER_LAYER_CONFIG_REQ");
+    case L2CEVT_L2CA_CONFIG_RSP:                 /* Upper layer config response          */
+        return ("UPPER_LAYER_CONFIG_RSP");
+    case L2CEVT_L2CA_CONFIG_RSP_NEG:             /* Upper layer config response (failed) */
+        return ("UPPER_LAYER_CONFIG_RSP_NEG");
+    case L2CEVT_L2CA_DISCONNECT_REQ:             /* Upper layer disconnect request       */
+        return ("UPPER_LAYER_DISCONNECT_REQ");
+    case L2CEVT_L2CA_DISCONNECT_RSP:             /* Upper layer disconnect response      */
+        return ("UPPER_LAYER_DISCONNECT_RSP");
+    case L2CEVT_L2CA_DATA_READ:                  /* Upper layer data read                */
+        return ("UPPER_LAYER_DATA_READ");
+    case L2CEVT_L2CA_DATA_WRITE:                 /* Upper layer data write               */
+        return ("UPPER_LAYER_DATA_WRITE");
+    case L2CEVT_TIMEOUT:                         /* Timeout                              */
+        return ("TIMEOUT");
+    case L2CEVT_SEC_RE_SEND_CMD:
+        return ("SEC_RE_SEND_CMD");
+    case L2CEVT_L2CAP_INFO_RSP:                  /* Peer information response            */
+        return ("L2CEVT_L2CAP_INFO_RSP");
+    case L2CEVT_ACK_TIMEOUT:
+        return ("L2CEVT_ACK_TIMEOUT");
+    case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT:   /* Upper layer send credit packet       */
+        return ("SEND_FLOW_CONTROL_CREDIT");
+    case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:  /* Peer send credit packet              */
+        return ("RECV_FLOW_CONTROL_CREDIT");
+
+    default:
+        return ("???? UNKNOWN EVENT");
+    }
+}
+#endif /* (BT_TRACE_VERBOSE == TRUE) */
+
+
+/*******************************************************************************
+**
+** Function         l2c_enqueue_peer_data
+**
+** Description      Enqueues data destined for the peer in the ccb. Handles
+**                  FCR segmentation and checks for congestion.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2c_enqueue_peer_data (tL2C_CCB *p_ccb, BT_HDR *p_buf)
+{
+    uint8_t     *p;
+
+    if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
+    {
+        p_buf->event = 0;
+    }
+    else
+    {
+        /* Save the channel ID for faster counting */
+        p_buf->event = p_ccb->local_cid;
+
+        /* Step back to add the L2CAP header */
+        p_buf->offset -= L2CAP_PKT_OVERHEAD;
+        p_buf->len    += L2CAP_PKT_OVERHEAD;
+
+        /* Set the pointer to the beginning of the data */
+        p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+        /* Now the L2CAP header */
+        UINT16_TO_STREAM (p, p_buf->len - L2CAP_PKT_OVERHEAD);
+        UINT16_TO_STREAM (p, p_ccb->remote_cid);
+    }
+
+    if (p_ccb->xmit_hold_q == NULL) {
+      L2CAP_TRACE_ERROR("%s: empty queue: p_ccb = %p p_ccb->in_use = %d p_ccb->chnl_state = %d p_ccb->local_cid = %u p_ccb->remote_cid = %u",
+                        __func__, p_ccb, p_ccb->in_use, p_ccb->chnl_state,
+                        p_ccb->local_cid, p_ccb->remote_cid);
+    }
+    fixed_queue_enqueue(p_ccb->xmit_hold_q, p_buf);
+
+    l2cu_check_channel_congestion (p_ccb);
+
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+    /* if new packet is higher priority than serving ccb and it is not overrun */
+    if (( p_ccb->p_lcb->rr_pri > p_ccb->ccb_priority )
+      &&( p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].quota > 0))
+    {
+        /* send out higher priority packet */
+        p_ccb->p_lcb->rr_pri = p_ccb->ccb_priority;
+    }
+#endif
+
+    /* if we are doing a round robin scheduling, set the flag */
+    if (p_ccb->p_lcb->link_xmit_quota == 0)
+        l2cb.check_round_robin = true;
+}
+
+
diff --git a/bt/stack/l2cap/l2c_fcr.cc b/bt/stack/l2cap/l2c_fcr.cc
new file mode 100644
index 0000000..304886d
--- /dev/null
+++ b/bt/stack/l2cap/l2c_fcr.cc
@@ -0,0 +1,2523 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2004-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 L2CAP 1.2 Flow Control and retransmissions
+ *  functions
+ *
+ ******************************************************************************/
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_types.h"
+#include "bt_common.h"
+#include "hcimsgs.h"
+#include "l2c_api.h"
+#include "l2c_int.h"
+#include "l2cdefs.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+/* Flag passed to retransmit_i_frames() when all packets should be retransmitted */
+#define L2C_FCR_RETX_ALL_PKTS   0xFF
+
+/* this is the minimal offset required by OBX to process incoming packets */
+static const uint16_t OBX_BUF_MIN_OFFSET = 4;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+static char *SAR_types[] = { "Unsegmented", "Start", "End", "Continuation" };
+static char *SUP_types[] = { "RR", "REJ", "RNR", "SREJ" };
+#endif
+
+/* Look-up table for the CRC calculation */
+static const unsigned short 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,
+};
+
+
+/*******************************************************************************
+**  Static local functions
+*/
+static bool    process_reqseq (tL2C_CCB *p_ccb, uint16_t ctrl_word);
+static void    process_s_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, uint16_t ctrl_word);
+static void    process_i_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, uint16_t ctrl_word, bool    delay_ack);
+static bool    retransmit_i_frames (tL2C_CCB *p_ccb, uint8_t tx_seq);
+static void    prepare_I_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, bool    is_retransmission);
+static void    process_stream_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf);
+static bool    do_sar_reassembly (tL2C_CCB *p_ccb, BT_HDR *p_buf, uint16_t ctrl_word);
+
+#if (L2CAP_ERTM_STATS == TRUE)
+static void l2c_fcr_collect_ack_delay (tL2C_CCB *p_ccb, uint8_t num_bufs_acked);
+#endif
+
+/*******************************************************************************
+**
+** Function         l2c_fcr_updcrc
+**
+** Description      This function computes the CRC using the look-up table.
+**
+** Returns          CRC
+**
+*******************************************************************************/
+static unsigned short l2c_fcr_updcrc(unsigned short icrc, unsigned char *icp, int icnt)
+{
+    unsigned short crc = icrc;
+    unsigned char *cp = icp;
+    int cnt = icnt;
+
+    while (cnt--)
+    {
+        crc = ((crc >> 8) & 0xff) ^ crctab[(crc & 0xff) ^ *cp++];
+    }
+
+    return(crc);
+}
+
+
+/*******************************************************************************
+**
+** Function         l2c_fcr_tx_get_fcs
+**
+** Description      This function computes the CRC for a frame to be TXed.
+**
+** Returns          CRC
+**
+*******************************************************************************/
+static uint16_t l2c_fcr_tx_get_fcs (BT_HDR *p_buf)
+{
+    uint8_t *p = ((uint8_t *) (p_buf + 1)) + p_buf->offset;
+
+    return (l2c_fcr_updcrc (L2CAP_FCR_INIT_CRC, p, p_buf->len));
+}
+
+/*******************************************************************************
+**
+** Function         l2c_fcr_rx_get_fcs
+**
+** Description      This function computes the CRC for a received frame.
+**
+** Returns          CRC
+**
+*******************************************************************************/
+static uint16_t l2c_fcr_rx_get_fcs (BT_HDR *p_buf)
+{
+    uint8_t *p = ((uint8_t *) (p_buf + 1)) + p_buf->offset;
+
+    /* offset points past the L2CAP header, but the CRC check includes it */
+    p -= L2CAP_PKT_OVERHEAD;
+
+    return (l2c_fcr_updcrc (L2CAP_FCR_INIT_CRC, p, p_buf->len + L2CAP_PKT_OVERHEAD));
+}
+
+/*******************************************************************************
+**
+** Function         l2c_fcr_start_timer
+**
+** Description      This function starts the (monitor or retransmission) timer.
+**
+** Returns          -
+**
+*******************************************************************************/
+void l2c_fcr_start_timer (tL2C_CCB *p_ccb)
+{
+    assert(p_ccb != NULL);
+    uint32_t tout;
+
+    /* The timers which are in milliseconds */
+    if (p_ccb->fcrb.wait_ack)
+    {
+        tout = (uint32_t)p_ccb->our_cfg.fcr.mon_tout;
+    }
+    else
+    {
+        tout = (uint32_t)p_ccb->our_cfg.fcr.rtrans_tout;
+    }
+
+    /* Only start a timer that was not started */
+    if (!alarm_is_scheduled(p_ccb->fcrb.mon_retrans_timer)) {
+        alarm_set_on_queue(p_ccb->fcrb.mon_retrans_timer, tout,
+                           l2c_ccb_timer_timeout, p_ccb,
+                           btu_general_alarm_queue);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2c_fcr_stop_timer
+**
+** Description      This function stops the (monitor or transmission) timer.
+**
+** Returns          -
+**
+*******************************************************************************/
+void l2c_fcr_stop_timer (tL2C_CCB *p_ccb)
+{
+    assert(p_ccb != NULL);
+    alarm_cancel(p_ccb->fcrb.mon_retrans_timer);
+}
+
+/*******************************************************************************
+**
+** Function         l2c_fcr_cleanup
+**
+** Description      This function cleans up the variable used for flow-control/retrans.
+**
+** Returns          -
+**
+*******************************************************************************/
+void l2c_fcr_cleanup (tL2C_CCB *p_ccb)
+{
+    assert(p_ccb != NULL);
+    tL2C_FCRB *p_fcrb = &p_ccb->fcrb;
+
+    alarm_free(p_fcrb->mon_retrans_timer);
+    p_fcrb->mon_retrans_timer = NULL;
+    alarm_free(p_fcrb->ack_timer);
+    p_fcrb->ack_timer = NULL;
+
+    osi_free_and_reset((void **)&p_fcrb->p_rx_sdu);
+
+    fixed_queue_free(p_fcrb->waiting_for_ack_q, osi_free);
+    p_fcrb->waiting_for_ack_q = NULL;
+
+    fixed_queue_free(p_fcrb->srej_rcv_hold_q, osi_free);
+    p_fcrb->srej_rcv_hold_q = NULL;
+
+    fixed_queue_free(p_fcrb->retrans_q, osi_free);
+    p_fcrb->retrans_q = NULL;
+
+#if (L2CAP_ERTM_STATS == TRUE)
+    if ( (p_ccb->local_cid >= L2CAP_BASE_APPL_CID) && (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) )
+    {
+        uint32_t dur = time_get_os_boottime_ms() - p_ccb->fcrb.connect_tick_count;
+        size_t p_str_size = 120;
+        char    *p_str = (char *)osi_malloc(p_str_size);
+        uint16_t i;
+        uint32_t throughput_avg, ack_delay_avg, ack_q_count_avg;
+
+        BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC,
+                   "---  L2CAP ERTM  Stats for CID: 0x%04x   Duration: %08ums", p_ccb->local_cid, dur);
+        BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC,
+                   "Retransmissions:%08u Times Flow Controlled:%08u Retrans Touts:%08u Ack Touts:%08u",
+                    p_ccb->fcrb.pkts_retransmitted, p_ccb->fcrb.xmit_window_closed, p_ccb->fcrb.retrans_touts, p_ccb->fcrb.xmit_ack_touts);
+        BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC,
+                   "Times there is less than 2 packets in controller when flow controlled:%08u", p_ccb->fcrb.controller_idle);
+        BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC,
+                   "max_held_acks:%08u, in_cfg.fcr.tx_win_sz:%08u", p_ccb->fcrb.max_held_acks, p_ccb->peer_cfg.fcr.tx_win_sz );
+
+        snprintf(p_str, p_str_size, "Sent Pkts:%08u Bytes:%10u(%06u/sec) RR:%08u REJ:%08u RNR:%08u SREJ:%08u",
+                p_ccb->fcrb.ertm_pkt_counts[0], p_ccb->fcrb.ertm_byte_counts[0],
+                (dur >= 10 ? (p_ccb->fcrb.ertm_byte_counts[0] * 100) / (dur / 10) : 0),
+                p_ccb->fcrb.s_frames_sent[0], p_ccb->fcrb.s_frames_sent[1], p_ccb->fcrb.s_frames_sent[2], p_ccb->fcrb.s_frames_sent[3]);
+
+        BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, "%s", p_str);
+
+        snprintf(p_str, p_str_size, "Rcvd Pkts:%08u Bytes:%10u(%06u/sec) RR:%08u REJ:%08u RNR:%08u SREJ:%08u",
+                p_ccb->fcrb.ertm_pkt_counts[1], p_ccb->fcrb.ertm_byte_counts[1],
+                (dur >= 10 ? (p_ccb->fcrb.ertm_byte_counts[1] * 100) / (dur / 10) : 0),
+                p_ccb->fcrb.s_frames_rcvd[0], p_ccb->fcrb.s_frames_rcvd[1], p_ccb->fcrb.s_frames_rcvd[2], p_ccb->fcrb.s_frames_rcvd[3]);
+
+        BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, "%s", p_str);
+
+        throughput_avg = 0;
+        ack_delay_avg = 0;
+        ack_q_count_avg = 0;
+
+        for (i = 0; i < L2CAP_ERTM_STATS_NUM_AVG; i++) {
+            if (i == p_ccb->fcrb.ack_delay_avg_index) {
+                BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC,
+                         "[%02u] collecting data ...", i );
+                continue;
+            }
+
+            snprintf(p_str, p_str_size, "[%02u] throughput: %5u, ack_delay avg:%3u, min:%3u, max:%3u, ack_q_count avg:%3u, min:%3u, max:%3u",
+                    i, p_ccb->fcrb.throughput[i],
+                    p_ccb->fcrb.ack_delay_avg[i], p_ccb->fcrb.ack_delay_min[i], p_ccb->fcrb.ack_delay_max[i],
+                    p_ccb->fcrb.ack_q_count_avg[i], p_ccb->fcrb.ack_q_count_min[i], p_ccb->fcrb.ack_q_count_max[i] );
+
+            BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, "%s", p_str);
+
+            throughput_avg  += p_ccb->fcrb.throughput[i];
+            ack_delay_avg   += p_ccb->fcrb.ack_delay_avg[i];
+            ack_q_count_avg += p_ccb->fcrb.ack_q_count_avg[i];
+        }
+
+        throughput_avg  /= (L2CAP_ERTM_STATS_NUM_AVG - 1);
+        ack_delay_avg   /= (L2CAP_ERTM_STATS_NUM_AVG - 1);
+        ack_q_count_avg /= (L2CAP_ERTM_STATS_NUM_AVG - 1);
+
+        BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC,
+                 "throughput_avg: %8u (kbytes/sec), ack_delay_avg: %8u ms, ack_q_count_avg: %8u",
+                 throughput_avg, ack_delay_avg, ack_q_count_avg );
+
+        osi_free(p_str);
+
+        BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC,
+                   "---");
+    }
+#endif
+
+    memset (p_fcrb, 0, sizeof (tL2C_FCRB));
+}
+
+/*******************************************************************************
+**
+** Function         l2c_fcr_clone_buf
+**
+** Description      This function allocates and copies requested part of a buffer
+**                  at a new-offset.
+**
+** Returns          pointer to new buffer
+**
+*******************************************************************************/
+BT_HDR *l2c_fcr_clone_buf(BT_HDR *p_buf, uint16_t new_offset, uint16_t no_of_bytes)
+{
+    assert(p_buf != NULL);
+    /*
+     * NOTE: We allocate extra L2CAP_FCS_LEN octets, in case we need to put
+     * the FCS (Frame Check Sequence) at the end of the buffer.
+     */
+    uint16_t buf_size = no_of_bytes + sizeof(BT_HDR) + new_offset + L2CAP_FCS_LEN;
+#if (L2CAP_ERTM_STATS == TRUE)
+    /*
+     * NOTE: If L2CAP_ERTM_STATS is enabled, we need 4 extra octets at the
+     * end for a timestamp at the end of an I-frame.
+     */
+    buf_size += sizeof(uint32_t);
+#endif
+    BT_HDR *p_buf2 = (BT_HDR *)osi_malloc(buf_size);
+
+    p_buf2->offset = new_offset;
+    p_buf2->len = no_of_bytes;
+    memcpy(((uint8_t *)(p_buf2 + 1)) + p_buf2->offset,
+           ((uint8_t *)(p_buf + 1))  + p_buf->offset,
+           no_of_bytes);
+
+    return (p_buf2);
+}
+
+/*******************************************************************************
+**
+** Function         l2c_fcr_is_flow_controlled
+**
+** Description      This function checks if the CCB is flow controlled by peer.
+**
+** Returns          The control word
+**
+*******************************************************************************/
+bool    l2c_fcr_is_flow_controlled (tL2C_CCB *p_ccb)
+{
+    assert(p_ccb != NULL);
+    if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
+    {
+        /* Check if remote side flowed us off or the transmit window is full */
+        if ( (p_ccb->fcrb.remote_busy == true)
+         ||  (fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q) >= p_ccb->peer_cfg.fcr.tx_win_sz) )
+        {
+#if (L2CAP_ERTM_STATS == TRUE)
+            if (!fixed_queue_is_empty(p_ccb->xmit_hold_q))
+            {
+                p_ccb->fcrb.xmit_window_closed++;
+
+                if ((p_ccb->p_lcb->sent_not_acked < 2)&&(l2cb.controller_xmit_window > 0))
+                    p_ccb->fcrb.controller_idle++;
+            }
+#endif
+            return (true);
+        }
+    }
+    return (false);
+}
+
+/*******************************************************************************
+**
+** Function         prepare_I_frame
+**
+** Description      This function sets the FCR variables in an I-frame that is
+**                  about to be sent to HCI for transmission. This may be the
+**                  first time the I-frame is sent, or a retransmission
+**
+** Returns          -
+**
+*******************************************************************************/
+static void prepare_I_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, bool    is_retransmission)
+{
+    assert(p_ccb != NULL);
+    assert(p_buf != NULL);
+    tL2C_FCRB   *p_fcrb = &p_ccb->fcrb;
+    uint8_t     *p;
+    uint16_t    fcs;
+    uint16_t    ctrl_word;
+    bool        set_f_bit = p_fcrb->send_f_rsp;
+
+    p_fcrb->send_f_rsp = false;
+
+    if (is_retransmission)
+    {
+        /* Get the old control word and clear out the old req_seq and F bits */
+        p = ((uint8_t *) (p_buf+1)) + p_buf->offset + L2CAP_PKT_OVERHEAD;
+
+        STREAM_TO_UINT16 (ctrl_word, p);
+
+        ctrl_word  &= ~(L2CAP_FCR_REQ_SEQ_BITS + L2CAP_FCR_F_BIT);
+    }
+    else
+    {
+        ctrl_word  = p_buf->layer_specific & L2CAP_FCR_SEG_BITS;                /* SAR bits */
+        ctrl_word |= (p_fcrb->next_tx_seq << L2CAP_FCR_TX_SEQ_BITS_SHIFT);      /* Tx Seq */
+
+        p_fcrb->next_tx_seq = (p_fcrb->next_tx_seq + 1) & L2CAP_FCR_SEQ_MODULO;
+    }
+
+    /* Set the F-bit and reqseq only if using re-transmission mode */
+    if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
+    {
+        if (set_f_bit)
+            ctrl_word |= L2CAP_FCR_F_BIT;
+
+        ctrl_word |= (p_fcrb->next_seq_expected) << L2CAP_FCR_REQ_SEQ_BITS_SHIFT;
+
+        p_fcrb->last_ack_sent = p_ccb->fcrb.next_seq_expected;
+
+        alarm_cancel(p_ccb->fcrb.ack_timer);
+    }
+
+    /* Set the control word */
+    p = ((uint8_t *) (p_buf+1)) + p_buf->offset + L2CAP_PKT_OVERHEAD;
+
+    UINT16_TO_STREAM (p, ctrl_word);
+
+    /* Compute the FCS and add to the end of the buffer if not bypassed */
+    if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS)
+    {
+        /* length field in l2cap header has to include FCS length */
+        p = ((uint8_t *) (p_buf+1)) + p_buf->offset;
+        UINT16_TO_STREAM (p, p_buf->len + L2CAP_FCS_LEN - L2CAP_PKT_OVERHEAD);
+
+        /* Calculate the FCS */
+        fcs = l2c_fcr_tx_get_fcs(p_buf);
+
+        /* Point to the end of the buffer and put the FCS there */
+        /*
+         * NOTE: Here we assume the allocated buffer is large enough
+         * to include extra L2CAP_FCS_LEN octets at the end.
+         */
+        p = ((uint8_t *) (p_buf+1)) + p_buf->offset + p_buf->len;
+
+        UINT16_TO_STREAM (p, fcs);
+
+        p_buf->len += L2CAP_FCS_LEN;
+    }
+
+#if (BT_TRACE_VERBOSE == TRUE)
+    if (is_retransmission)
+    {
+        L2CAP_TRACE_EVENT ("L2CAP eRTM ReTx I-frame  CID: 0x%04x  Len: %u  SAR: %s  TxSeq: %u  ReqSeq: %u  F: %u",
+                            p_ccb->local_cid, p_buf->len,
+                            SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT],
+                            (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
+                            (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+                            (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+    }
+    else
+    {
+        L2CAP_TRACE_EVENT ("L2CAP eRTM Tx I-frame CID: 0x%04x  Len: %u  SAR: %-12s  TxSeq: %u  ReqSeq: %u  F: %u",
+                            p_ccb->local_cid, p_buf->len,
+                            SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT],
+                            (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
+                            (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+                            (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+    }
+#endif
+
+    /* Start the retransmission timer if not already running */
+    if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
+        l2c_fcr_start_timer (p_ccb);
+}
+
+/*******************************************************************************
+**
+** Function         l2c_fcr_send_S_frame
+**
+** Description      This function formats and sends an S-frame for transmission.
+**
+** Returns          -
+**
+*******************************************************************************/
+void l2c_fcr_send_S_frame (tL2C_CCB *p_ccb, uint16_t function_code, uint16_t pf_bit)
+{
+    assert(p_ccb != NULL);
+    uint8_t     *p;
+    uint16_t    ctrl_word;
+    uint16_t    fcs;
+
+    if ((!p_ccb->in_use) || (p_ccb->chnl_state != CST_OPEN))
+        return;
+
+#if (L2CAP_ERTM_STATS == TRUE)
+     p_ccb->fcrb.s_frames_sent[function_code]++;
+#endif
+
+    if (pf_bit == L2CAP_FCR_P_BIT)
+    {
+        p_ccb->fcrb.wait_ack = true;
+
+        l2c_fcr_stop_timer (p_ccb);         /* Restart the monitor timer */
+        l2c_fcr_start_timer (p_ccb);
+    }
+
+    /* Create the control word to use */
+    ctrl_word = (function_code << L2CAP_FCR_SUP_SHIFT) | L2CAP_FCR_S_FRAME_BIT;
+    ctrl_word |= (p_ccb->fcrb.next_seq_expected << L2CAP_FCR_REQ_SEQ_BITS_SHIFT);
+    ctrl_word |= pf_bit;
+
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(L2CAP_CMD_BUF_SIZE);
+    p_buf->offset = HCI_DATA_PREAMBLE_SIZE;
+    p_buf->len    = L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD;
+
+    /* Set the pointer to the beginning of the data */
+    p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+    /* Put in the L2CAP header */
+    UINT16_TO_STREAM(p, L2CAP_FCR_OVERHEAD + L2CAP_FCS_LEN);
+    UINT16_TO_STREAM(p, p_ccb->remote_cid);
+    UINT16_TO_STREAM(p, ctrl_word);
+
+    /* Compute the FCS and add to the end of the buffer if not bypassed */
+    if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) {
+        fcs = l2c_fcr_tx_get_fcs (p_buf);
+
+        UINT16_TO_STREAM (p, fcs);
+        p_buf->len += L2CAP_FCS_LEN;
+    } else {
+        /* rewrite the length without FCS length */
+        p -= 6;
+        UINT16_TO_STREAM (p, L2CAP_FCR_OVERHEAD);
+    }
+
+    /* Now, the HCI transport header */
+    p_buf->layer_specific = L2CAP_NON_FLUSHABLE_PKT;
+    l2cu_set_acl_hci_header (p_buf, p_ccb);
+
+#if (BT_TRACE_VERBOSE == TRUE)
+    if ((((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 1)
+        || (((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 3)) {
+        L2CAP_TRACE_WARNING("L2CAP eRTM Tx S-frame  CID: 0x%04x  ctrlword: 0x%04x  Type: %s  ReqSeq: %u  P: %u  F: %u",
+                            p_ccb->local_cid, ctrl_word,
+                            SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT],
+                            (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+                            (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT,
+                            (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+        L2CAP_TRACE_WARNING ("                  Buf Len: %u", p_buf->len);
+    } else {
+        L2CAP_TRACE_EVENT("L2CAP eRTM Tx S-frame  CID: 0x%04x  ctrlword: 0x%04x  Type: %s  ReqSeq: %u  P: %u  F: %u",
+                          p_ccb->local_cid, ctrl_word,
+                          SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT],
+                          (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+                          (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT,
+                          (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+        L2CAP_TRACE_EVENT("                  Buf Len: %u", p_buf->len);
+    }
+#endif  /* BT_TRACE_VERBOSE */
+
+    l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf);
+
+    p_ccb->fcrb.last_ack_sent = p_ccb->fcrb.next_seq_expected;
+
+    alarm_cancel(p_ccb->fcrb.ack_timer);
+}
+
+
+/*******************************************************************************
+**
+** Function         l2c_fcr_proc_pdu
+**
+** Description      This function is the entry point for processing of a
+**                  received PDU when in flow control and/or retransmission modes.
+**
+** Returns          -
+**
+*******************************************************************************/
+void l2c_fcr_proc_pdu (tL2C_CCB *p_ccb, BT_HDR *p_buf)
+{
+    assert(p_ccb != NULL);
+    assert(p_buf != NULL);
+    uint8_t     *p;
+    uint16_t    fcs;
+    uint16_t    min_pdu_len;
+    uint16_t    ctrl_word;
+
+    /* Check the length */
+    min_pdu_len = (p_ccb->bypass_fcs == L2CAP_BYPASS_FCS) ?
+                  (uint16_t)L2CAP_FCR_OVERHEAD : (uint16_t)(L2CAP_FCS_LEN + L2CAP_FCR_OVERHEAD);
+
+    if (p_buf->len < min_pdu_len)
+    {
+        L2CAP_TRACE_WARNING ("Rx L2CAP PDU: CID: 0x%04x  Len too short: %u", p_ccb->local_cid, p_buf->len);
+        osi_free(p_buf);
+        return;
+    }
+
+    if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_STREAM_MODE)
+    {
+        process_stream_frame (p_ccb, p_buf);
+        return;
+    }
+
+#if (BT_TRACE_VERBOSE == TRUE)
+    /* Get the control word */
+    p = ((uint8_t *)(p_buf+1)) + p_buf->offset;
+    STREAM_TO_UINT16 (ctrl_word, p);
+
+    if (ctrl_word & L2CAP_FCR_S_FRAME_BIT)
+    {
+        if ((((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 1)
+         || (((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 3))
+        {
+            /* REJ or SREJ */
+            L2CAP_TRACE_WARNING ("L2CAP eRTM Rx S-frame: cid: 0x%04x  Len: %u  Type: %s  ReqSeq: %u  P: %u  F: %u",
+                            p_ccb->local_cid, p_buf->len,
+                            SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT],
+                            (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+                            (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT,
+                            (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+        }
+        else
+        {
+            L2CAP_TRACE_EVENT ("L2CAP eRTM Rx S-frame: cid: 0x%04x  Len: %u  Type: %s  ReqSeq: %u  P: %u  F: %u",
+                            p_ccb->local_cid, p_buf->len,
+                            SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT],
+                            (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+                            (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT,
+                            (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+        }
+    }
+    else
+    {
+        L2CAP_TRACE_EVENT ("L2CAP eRTM Rx I-frame: cid: 0x%04x  Len: %u  SAR: %-12s  TxSeq: %u  ReqSeq: %u  F: %u",
+                            p_ccb->local_cid, p_buf->len,
+                            SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT],
+                            (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
+                            (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+                            (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+    }
+
+    L2CAP_TRACE_EVENT ("      eRTM Rx Nxt_tx_seq %u, Lst_rx_ack %u, Nxt_seq_exp %u, Lst_ack_snt %u, wt_q.cnt %u, tries %u",
+                       p_ccb->fcrb.next_tx_seq, p_ccb->fcrb.last_rx_ack,
+                       p_ccb->fcrb.next_seq_expected,
+                       p_ccb->fcrb.last_ack_sent,
+                       fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q),
+                       p_ccb->fcrb.num_tries);
+
+#endif /* BT_TRACE_VERBOSE */
+
+    /* Verify FCS if using */
+    if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS)
+    {
+        p = ((uint8_t *)(p_buf+1)) + p_buf->offset + p_buf->len - L2CAP_FCS_LEN;
+
+        /* Extract and drop the FCS from the packet */
+        STREAM_TO_UINT16 (fcs, p);
+        p_buf->len -= L2CAP_FCS_LEN;
+
+        if (l2c_fcr_rx_get_fcs(p_buf) != fcs)
+        {
+            L2CAP_TRACE_WARNING ("Rx L2CAP PDU: CID: 0x%04x  BAD FCS", p_ccb->local_cid);
+            osi_free(p_buf);
+            return;
+        }
+    }
+
+    /* Get the control word */
+    p = ((uint8_t *)(p_buf+1)) + p_buf->offset;
+
+    STREAM_TO_UINT16 (ctrl_word, p);
+
+    p_buf->len    -= L2CAP_FCR_OVERHEAD;
+    p_buf->offset += L2CAP_FCR_OVERHEAD;
+
+    /* If we had a poll bit outstanding, check if we got a final response */
+    if (p_ccb->fcrb.wait_ack)
+    {
+        /* If final bit not set, ignore the frame unless it is a polled S-frame */
+        if ( !(ctrl_word & L2CAP_FCR_F_BIT) )
+        {
+            if ( (ctrl_word & L2CAP_FCR_P_BIT) && (ctrl_word & L2CAP_FCR_S_FRAME_BIT) )
+            {
+                if (p_ccb->fcrb.srej_sent)
+                    l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_SREJ, L2CAP_FCR_F_BIT);
+                else if (p_ccb->fcrb.local_busy)
+                    l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, L2CAP_FCR_F_BIT);
+                else
+                    l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_F_BIT);
+
+                /* Got a poll while in wait_ack state, so re-start our timer with 1-second */
+                /* This is a small optimization... the monitor timer is 12 secs, but we saw */
+                /* that if the other side sends us a poll when we are waiting for a final,  */
+                /* then it speeds up recovery significantly if we poll him back soon after his poll. */
+                alarm_set_on_queue(p_ccb->fcrb.mon_retrans_timer,
+                                   BT_1SEC_TIMEOUT_MS,
+                                   l2c_ccb_timer_timeout, p_ccb,
+                                   btu_general_alarm_queue);
+            }
+            osi_free(p_buf);
+            return;
+        }
+
+        p_ccb->fcrb.wait_ack  = false;
+
+        /* P and F are mutually exclusive */
+        if (ctrl_word & L2CAP_FCR_S_FRAME_BIT)
+            ctrl_word &= ~L2CAP_FCR_P_BIT;
+
+        if (fixed_queue_is_empty(p_ccb->fcrb.waiting_for_ack_q))
+            p_ccb->fcrb.num_tries = 0;
+
+        l2c_fcr_stop_timer (p_ccb);
+    }
+    else
+    {
+        /* Otherwise, ensure the final bit is ignored */
+        ctrl_word &= ~L2CAP_FCR_F_BIT;
+    }
+
+    /* Process receive sequence number */
+    if (!process_reqseq (p_ccb, ctrl_word))
+    {
+        osi_free(p_buf);
+        return;
+    }
+
+     /* Process based on whether it is an S-frame or an I-frame */
+    if (ctrl_word & L2CAP_FCR_S_FRAME_BIT)
+        process_s_frame (p_ccb, p_buf, ctrl_word);
+    else
+        process_i_frame (p_ccb, p_buf, ctrl_word, false);
+
+    /* Return if the channel got disconnected by a bad packet or max retransmissions */
+    if ( (!p_ccb->in_use) || (p_ccb->chnl_state != CST_OPEN) )
+        return;
+
+    /* If we have some buffers held while doing SREJ, and SREJ has cleared, process them now */
+    if ( (!p_ccb->fcrb.local_busy) && (!p_ccb->fcrb.srej_sent) &&
+         (!fixed_queue_is_empty(p_ccb->fcrb.srej_rcv_hold_q)))
+    {
+        fixed_queue_t *temp_q = p_ccb->fcrb.srej_rcv_hold_q;
+        p_ccb->fcrb.srej_rcv_hold_q = fixed_queue_new(SIZE_MAX);
+
+        while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(temp_q)) != NULL)
+        {
+            if (p_ccb->in_use && (p_ccb->chnl_state == CST_OPEN))
+            {
+                /* Get the control word */
+                p = ((uint8_t *)(p_buf+1)) + p_buf->offset - L2CAP_FCR_OVERHEAD;
+
+                STREAM_TO_UINT16 (ctrl_word, p);
+
+                L2CAP_TRACE_DEBUG ("l2c_fcr_proc_pdu() CID: 0x%04x  Process Buffer from SREJ_Hold_Q   TxSeq: %u  Expected_Seq: %u",
+                                    p_ccb->local_cid, (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
+                                    p_ccb->fcrb.next_seq_expected);
+
+                /* Process the SREJ held I-frame, but do not send an RR for each individual frame */
+                process_i_frame (p_ccb, p_buf, ctrl_word, true);
+            }
+            else
+                osi_free(p_buf);
+
+            /* If more frames were lost during SREJ, send a REJ */
+            if (p_ccb->fcrb.rej_after_srej)
+            {
+                p_ccb->fcrb.rej_after_srej = false;
+                p_ccb->fcrb.rej_sent       = true;
+
+                l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_REJ, 0);
+            }
+        }
+        fixed_queue_free(temp_q, NULL);
+
+        /* Now, if needed, send one RR for the whole held queue */
+        if ( (!p_ccb->fcrb.local_busy) && (!p_ccb->fcrb.rej_sent) && (!p_ccb->fcrb.srej_sent)
+         &&  (p_ccb->fcrb.next_seq_expected != p_ccb->fcrb.last_ack_sent) )
+            l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, 0);
+        else
+        {
+            L2CAP_TRACE_DEBUG ("l2c_fcr_proc_pdu() not sending RR CID: 0x%04x  local_busy:%d rej_sent:%d srej_sent:%d Expected_Seq:%u Last_Ack:%u",
+                                p_ccb->local_cid, p_ccb->fcrb.local_busy, p_ccb->fcrb.rej_sent, p_ccb->fcrb.srej_sent, p_ccb->fcrb.next_seq_expected,
+                                p_ccb->fcrb.last_ack_sent);
+        }
+    }
+
+    /* If a window has opened, check if we can send any more packets */
+    if ( (!fixed_queue_is_empty(p_ccb->fcrb.retrans_q) ||
+          !fixed_queue_is_empty(p_ccb->xmit_hold_q))
+      && (p_ccb->fcrb.wait_ack == false)
+      && (l2c_fcr_is_flow_controlled (p_ccb) == false) )
+    {
+        l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2c_lcc_proc_pdu
+**
+** Description      This function is the entry point for processing of a
+**                  received PDU when in LE Coc flow control modes.
+**
+** Returns          -
+**
+*******************************************************************************/
+void l2c_lcc_proc_pdu(tL2C_CCB *p_ccb, BT_HDR *p_buf)
+{
+
+    assert(p_ccb != NULL);
+    assert(p_buf != NULL);
+    uint8_t *p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+    uint16_t sdu_length;
+    BT_HDR *p_data = NULL;
+
+    /* Buffer length should not exceed local mps */
+    if (p_buf->len > p_ccb->local_conn_cfg.mps)
+    {
+        /* Discard the buffer */
+        osi_free(p_buf);
+        return;
+    }
+
+    if (p_ccb->is_first_seg)
+    {
+        STREAM_TO_UINT16(sdu_length, p);
+        /* Check the SDU Length with local MTU size */
+        if (sdu_length > p_ccb->local_conn_cfg.mtu)
+        {
+            /* Discard the buffer */
+            osi_free(p_buf);
+            return;
+        }
+
+
+        if ((p_data = (BT_HDR *) osi_malloc(L2CAP_MAX_BUF_SIZE)) == NULL)
+        {
+            osi_free(p_buf);
+            return;
+        }
+
+        p_ccb->ble_sdu = p_data;
+        p_data->len = 0;
+        p_ccb->ble_sdu_length = sdu_length;
+        L2CAP_TRACE_DEBUG ("%s SDU Length = %d",__func__,sdu_length);
+        p_buf->len -= sizeof(sdu_length);
+        p_buf->offset += sizeof(sdu_length);
+        p_data->offset = 0;
+
+    }
+    else
+        p_data = p_ccb->ble_sdu;
+
+    memcpy((uint8_t*)(p_data + 1) + p_data->offset + p_data->len, (uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
+    p_data->len += p_buf->len;
+    p = (uint8_t*)(p_data+1) + p_data->offset;
+    if (p_data->len == p_ccb->ble_sdu_length)
+    {
+        l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DATA, p_data);
+        p_ccb->is_first_seg = true;
+        p_ccb->ble_sdu = NULL;
+        p_ccb->ble_sdu_length = 0;
+    }
+    else if (p_data->len < p_ccb->ble_sdu_length)
+    {
+        p_ccb->is_first_seg = false;
+    }
+    else
+    {
+        L2CAP_TRACE_ERROR ("%s Length in the SDU messed up",__func__);
+        // TODO: reset every thing may be???
+    }
+
+    osi_free(p_buf);
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         l2c_fcr_proc_tout
+**
+** Description      Handle a timeout. We should be in error recovery state.
+**
+** Returns          -
+**
+*******************************************************************************/
+void l2c_fcr_proc_tout (tL2C_CCB *p_ccb)
+{
+    assert(p_ccb != NULL);
+    L2CAP_TRACE_DEBUG ("l2c_fcr_proc_tout:  CID: 0x%04x  num_tries: %u (max: %u)  wait_ack: %u  ack_q_count: %u",
+                       p_ccb->local_cid, p_ccb->fcrb.num_tries,
+                       p_ccb->peer_cfg.fcr.max_transmit,
+                       p_ccb->fcrb.wait_ack,
+                       fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q));
+
+#if (L2CAP_ERTM_STATS == TRUE)
+    p_ccb->fcrb.retrans_touts++;
+#endif
+
+    if ( (p_ccb->peer_cfg.fcr.max_transmit != 0) && (++p_ccb->fcrb.num_tries > p_ccb->peer_cfg.fcr.max_transmit) )
+    {
+        l2cu_disconnect_chnl (p_ccb);
+    }
+    else
+    {
+        if (!p_ccb->fcrb.srej_sent && !p_ccb->fcrb.rej_sent)
+        {
+            if (p_ccb->fcrb.local_busy)
+                l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, L2CAP_FCR_P_BIT);
+            else
+                l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_P_BIT);
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         l2c_fcr_proc_ack_tout
+**
+** Description      Send RR/RNR if we have not acked I frame
+**
+** Returns          -
+**
+*******************************************************************************/
+void l2c_fcr_proc_ack_tout (tL2C_CCB *p_ccb)
+{
+    assert(p_ccb != NULL);
+    L2CAP_TRACE_DEBUG ("l2c_fcr_proc_ack_tout:  CID: 0x%04x State: %u  Wack:%u  Rq:%d  Acked:%d", p_ccb->local_cid,
+                        p_ccb->chnl_state, p_ccb->fcrb.wait_ack, p_ccb->fcrb.next_seq_expected, p_ccb->fcrb.last_ack_sent);
+
+    if ( (p_ccb->chnl_state == CST_OPEN) && (!p_ccb->fcrb.wait_ack)
+      && (p_ccb->fcrb.last_ack_sent != p_ccb->fcrb.next_seq_expected) )
+    {
+#if (L2CAP_ERTM_STATS == TRUE)
+        p_ccb->fcrb.xmit_ack_touts++;
+#endif
+        if (p_ccb->fcrb.local_busy)
+            l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, 0);
+        else
+            l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, 0);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         process_reqseq
+**
+** Description      Handle receive sequence number
+**
+** Returns          -
+**
+*******************************************************************************/
+static bool    process_reqseq (tL2C_CCB *p_ccb, uint16_t ctrl_word)
+{
+    assert(p_ccb != NULL);
+    tL2C_FCRB   *p_fcrb = &p_ccb->fcrb;
+    uint8_t     req_seq, num_bufs_acked, xx;
+    uint16_t    ls;
+    uint16_t    full_sdus_xmitted;
+
+    /* Receive sequence number does not ack anything for SREJ with P-bit set to zero */
+    if ( (ctrl_word & L2CAP_FCR_S_FRAME_BIT)
+     &&  ((ctrl_word & L2CAP_FCR_SUP_BITS) == (L2CAP_FCR_SUP_SREJ << L2CAP_FCR_SUP_SHIFT))
+     &&  ((ctrl_word & L2CAP_FCR_P_BIT) == 0) )
+    {
+        /* If anything still waiting for ack, restart the timer if it was stopped */
+        if (!fixed_queue_is_empty(p_fcrb->waiting_for_ack_q))
+            l2c_fcr_start_timer(p_ccb);
+
+        return (true);
+    }
+
+    /* Extract the receive sequence number from the control word */
+    req_seq = (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT;
+
+    num_bufs_acked = (req_seq - p_fcrb->last_rx_ack) & L2CAP_FCR_SEQ_MODULO;
+
+    /* Verify the request sequence is in range before proceeding */
+    if (num_bufs_acked > fixed_queue_length(p_fcrb->waiting_for_ack_q))
+    {
+        /* The channel is closed if ReqSeq is not in range */
+        L2CAP_TRACE_WARNING ("L2CAP eRTM Frame BAD Req_Seq - ctrl_word: 0x%04x  req_seq 0x%02x  last_rx_ack: 0x%02x  QCount: %u",
+                             ctrl_word, req_seq, p_fcrb->last_rx_ack,
+                             fixed_queue_length(p_fcrb->waiting_for_ack_q));
+
+        l2cu_disconnect_chnl (p_ccb);
+        return (false);
+    }
+
+    p_fcrb->last_rx_ack = req_seq;
+
+    /* Now we can release all acknowledged frames, and restart the retransmission timer if needed */
+    if (num_bufs_acked != 0)
+    {
+        p_fcrb->num_tries = 0;
+        full_sdus_xmitted = 0;
+
+#if (L2CAP_ERTM_STATS == TRUE)
+        l2c_fcr_collect_ack_delay (p_ccb, num_bufs_acked);
+#endif
+
+        for (xx = 0; xx < num_bufs_acked; xx++)
+        {
+            BT_HDR *p_tmp = (BT_HDR *)fixed_queue_try_dequeue(p_fcrb->waiting_for_ack_q);
+            ls = p_tmp->layer_specific & L2CAP_FCR_SAR_BITS;
+
+            if ( (ls == L2CAP_FCR_UNSEG_SDU) || (ls == L2CAP_FCR_END_SDU) )
+                full_sdus_xmitted++;
+
+            osi_free(p_tmp);
+        }
+
+        /* If we are still in a wait_ack state, do not mess with the timer */
+        if (!p_ccb->fcrb.wait_ack)
+            l2c_fcr_stop_timer (p_ccb);
+
+        /* Check if we need to call the "packet_sent" callback */
+        if ( (p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_TxComplete_Cb) && (full_sdus_xmitted) )
+        {
+            /* Special case for eRTM, if all packets sent, send 0xFFFF */
+            if (fixed_queue_is_empty(p_fcrb->waiting_for_ack_q) &&
+                fixed_queue_is_empty(p_ccb->xmit_hold_q)) {
+                full_sdus_xmitted = 0xFFFF;
+            }
+
+            (*p_ccb->p_rcb->api.pL2CA_TxComplete_Cb)(p_ccb->local_cid, full_sdus_xmitted);
+        }
+    }
+
+    /* If anything still waiting for ack, restart the timer if it was stopped */
+    if (!fixed_queue_is_empty(p_fcrb->waiting_for_ack_q))
+        l2c_fcr_start_timer(p_ccb);
+    return (true);
+}
+
+
+/*******************************************************************************
+**
+** Function         process_s_frame
+**
+** Description      Process an S frame
+**
+** Returns          -
+**
+*******************************************************************************/
+static void process_s_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, uint16_t ctrl_word)
+{
+    assert(p_ccb != NULL);
+    assert(p_buf != NULL);
+
+    tL2C_FCRB   *p_fcrb      = &p_ccb->fcrb;
+    uint16_t    s_frame_type = (ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT;
+    bool        remote_was_busy;
+    bool        all_ok = true;
+
+    if (p_buf->len != 0)
+    {
+        L2CAP_TRACE_WARNING ("Incorrect S-frame Length (%d)", p_buf->len);
+    }
+
+    L2CAP_TRACE_DEBUG ("process_s_frame ctrl_word 0x%04x fcrb_remote_busy:%d", ctrl_word, p_fcrb->remote_busy);
+
+#if (L2CAP_ERTM_STATS == TRUE)
+    p_ccb->fcrb.s_frames_rcvd[s_frame_type]++;
+#endif
+
+    if (ctrl_word & L2CAP_FCR_P_BIT)
+    {
+        p_fcrb->rej_sent   = false;             /* After checkpoint, we can send anoher REJ */
+        p_fcrb->send_f_rsp = true;              /* Set a flag in case an I-frame is pending */
+    }
+
+    switch (s_frame_type)
+    {
+    case L2CAP_FCR_SUP_RR:
+        remote_was_busy     = p_fcrb->remote_busy;
+        p_fcrb->remote_busy = false;
+
+        if ( (ctrl_word & L2CAP_FCR_F_BIT) || (remote_was_busy) )
+            all_ok = retransmit_i_frames (p_ccb, L2C_FCR_RETX_ALL_PKTS);
+        break;
+
+    case L2CAP_FCR_SUP_REJ:
+        p_fcrb->remote_busy = false;
+        all_ok = retransmit_i_frames (p_ccb, L2C_FCR_RETX_ALL_PKTS);
+        break;
+
+    case L2CAP_FCR_SUP_RNR:
+        p_fcrb->remote_busy = true;
+        l2c_fcr_stop_timer (p_ccb);
+        break;
+
+    case L2CAP_FCR_SUP_SREJ:
+        p_fcrb->remote_busy = false;
+        all_ok = retransmit_i_frames (p_ccb, (uint8_t)((ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT));
+        break;
+    }
+
+    if (all_ok)
+    {
+        /* If polled, we need to respond with F-bit. Note, we may have sent a I-frame with the F-bit */
+        if (p_fcrb->send_f_rsp)
+        {
+            if (p_fcrb->srej_sent)
+                l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_SREJ, L2CAP_FCR_F_BIT);
+            else if (p_fcrb->local_busy)
+                l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, L2CAP_FCR_F_BIT);
+            else
+                l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_F_BIT);
+
+            p_fcrb->send_f_rsp = false;
+        }
+    }
+    else
+    {
+        L2CAP_TRACE_DEBUG ("process_s_frame hit_max_retries");
+    }
+
+    osi_free(p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         process_i_frame
+**
+** Description      Process an I frame
+**
+** Returns          -
+**
+*******************************************************************************/
+static void process_i_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, uint16_t ctrl_word, bool    delay_ack)
+{
+    assert(p_ccb != NULL);
+    assert(p_buf != NULL);
+
+    tL2C_FCRB   *p_fcrb = &p_ccb->fcrb;
+    uint8_t     tx_seq, num_lost, num_to_ack, next_srej;
+
+    /* If we were doing checkpoint recovery, first retransmit all unacked I-frames */
+    if (ctrl_word & L2CAP_FCR_F_BIT)
+    {
+        if (!retransmit_i_frames (p_ccb, L2C_FCR_RETX_ALL_PKTS))
+        {
+            osi_free(p_buf);
+            return;
+        }
+    }
+
+#if (L2CAP_ERTM_STATS == TRUE)
+    p_ccb->fcrb.ertm_pkt_counts[1]++;
+    p_ccb->fcrb.ertm_byte_counts[1] += p_buf->len;
+#endif
+
+    /* Extract the sequence number */
+    tx_seq = (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT;
+
+    /* If we have flow controlled the peer, ignore any bad I-frames from him */
+    if ( (tx_seq != p_fcrb->next_seq_expected) && (p_fcrb->local_busy) )
+    {
+        L2CAP_TRACE_WARNING ("Dropping bad I-Frame since we flowed off, tx_seq:%u", tx_seq);
+        l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, 0);
+        osi_free(p_buf);
+        return;
+    }
+
+    /* Check if tx-sequence is the expected one */
+    if (tx_seq != p_fcrb->next_seq_expected)
+    {
+        num_lost = (tx_seq - p_fcrb->next_seq_expected) & L2CAP_FCR_SEQ_MODULO;
+
+        /* Is the frame a duplicate ? If so, just drop it */
+        if (num_lost >= p_ccb->our_cfg.fcr.tx_win_sz)
+        {
+            /* Duplicate - simply drop it */
+            L2CAP_TRACE_WARNING ("process_i_frame() Dropping Duplicate Frame tx_seq:%u  ExpectedTxSeq %u", tx_seq, p_fcrb->next_seq_expected);
+            osi_free(p_buf);
+        }
+        else
+        {
+            L2CAP_TRACE_WARNING ("process_i_frame() CID: 0x%04x  Lost: %u  tx_seq:%u  ExpTxSeq %u  Rej: %u  SRej: %u",
+                                 p_ccb->local_cid, num_lost, tx_seq, p_fcrb->next_seq_expected, p_fcrb->rej_sent, p_fcrb->srej_sent);
+
+            if (p_fcrb->srej_sent)
+            {
+                /* If SREJ sent, save the frame for later processing as long as it is in sequence */
+                next_srej = (((BT_HDR *)fixed_queue_try_peek_last(p_fcrb->srej_rcv_hold_q))->layer_specific + 1) & L2CAP_FCR_SEQ_MODULO;
+
+                if ( (tx_seq == next_srej) && (fixed_queue_length(p_fcrb->srej_rcv_hold_q) < p_ccb->our_cfg.fcr.tx_win_sz) )
+                {
+                    /* If user gave us a pool for held rx buffers, use that */
+                    /* TODO: Could that happen? Get rid of this code. */
+                    if (p_ccb->ertm_info.fcr_rx_buf_size != L2CAP_FCR_RX_BUF_SIZE)
+                    {
+                        BT_HDR *p_buf2;
+
+                        /* Adjust offset and len so that control word is copied */
+                        p_buf->offset -= L2CAP_FCR_OVERHEAD;
+                        p_buf->len    += L2CAP_FCR_OVERHEAD;
+
+                        p_buf2 = l2c_fcr_clone_buf(p_buf, p_buf->offset, p_buf->len);
+
+                        if (p_buf2)
+                        {
+                            osi_free(p_buf);
+                            p_buf = p_buf2;
+                        }
+                        p_buf->offset += L2CAP_FCR_OVERHEAD;
+                        p_buf->len -= L2CAP_FCR_OVERHEAD;
+                    }
+                    L2CAP_TRACE_DEBUG ("process_i_frame() Lost: %u  tx_seq:%u  ExpTxSeq %u  Rej: %u  SRej1",
+                                         num_lost, tx_seq, p_fcrb->next_seq_expected, p_fcrb->rej_sent);
+
+                    p_buf->layer_specific = tx_seq;
+                    fixed_queue_enqueue(p_fcrb->srej_rcv_hold_q, p_buf);
+                }
+                else
+                {
+                    L2CAP_TRACE_WARNING ("process_i_frame() CID: 0x%04x  frame dropped in Srej Sent next_srej:%u  hold_q.count:%u  win_sz:%u",
+                                         p_ccb->local_cid, next_srej, fixed_queue_length(p_fcrb->srej_rcv_hold_q), p_ccb->our_cfg.fcr.tx_win_sz);
+
+                    p_fcrb->rej_after_srej = true;
+                    osi_free(p_buf);
+                }
+            }
+            else if (p_fcrb->rej_sent)
+            {
+                L2CAP_TRACE_WARNING ("process_i_frame() CID: 0x%04x  Lost: %u  tx_seq:%u  ExpTxSeq %u  Rej: 1  SRej: %u",
+                                     p_ccb->local_cid, num_lost, tx_seq, p_fcrb->next_seq_expected, p_fcrb->srej_sent);
+
+                /* If REJ sent, just drop the frame */
+                osi_free(p_buf);
+            }
+            else
+            {
+                L2CAP_TRACE_DEBUG ("process_i_frame() CID: 0x%04x  tx_seq:%u  ExpTxSeq %u  Rej: %u",
+                                     p_ccb->local_cid, tx_seq, p_fcrb->next_seq_expected, p_fcrb->rej_sent);
+
+                /* If only one lost, we will send SREJ, otherwise we will send REJ */
+                if (num_lost > 1)
+                {
+                    osi_free(p_buf);
+                    p_fcrb->rej_sent = true;
+                    l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_REJ, 0);
+                }
+                else
+                {
+                    if (!fixed_queue_is_empty(p_fcrb->srej_rcv_hold_q))
+                    {
+                        L2CAP_TRACE_ERROR ("process_i_frame() CID: 0x%04x  sending SREJ tx_seq:%d hold_q.count:%u",
+                                             p_ccb->local_cid, tx_seq, fixed_queue_length(p_fcrb->srej_rcv_hold_q));
+                    }
+                    p_buf->layer_specific = tx_seq;
+                    fixed_queue_enqueue(p_fcrb->srej_rcv_hold_q, p_buf);
+                    p_fcrb->srej_sent = true;
+                    l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_SREJ, 0);
+                }
+                alarm_cancel(p_ccb->fcrb.ack_timer);
+            }
+        }
+        return;
+    }
+
+    /* Seq number is the next expected. Clear possible reject exception in case it occured */
+    p_fcrb->rej_sent = p_fcrb->srej_sent = false;
+
+    /* Adjust the next_seq, so that if the upper layer sends more data in the callback
+       context, the received frame is acked by an I-frame. */
+    p_fcrb->next_seq_expected = (tx_seq + 1) & L2CAP_FCR_SEQ_MODULO;
+
+    /* If any SAR problem in eRTM mode, spec says disconnect. */
+    if (!do_sar_reassembly (p_ccb, p_buf, ctrl_word))
+    {
+        L2CAP_TRACE_WARNING ("process_i_frame() CID: 0x%04x  reassembly failed", p_ccb->local_cid);
+        l2cu_disconnect_chnl (p_ccb);
+        return;
+    }
+
+    /* RR optimization - if peer can still send us more, then start an ACK timer */
+    num_to_ack = (p_fcrb->next_seq_expected - p_fcrb->last_ack_sent) & L2CAP_FCR_SEQ_MODULO;
+
+    if ( (num_to_ack < p_ccb->fcrb.max_held_acks) && (!p_fcrb->local_busy) )
+        delay_ack = true;
+
+    /* We should neve never ack frame if we are not in OPEN state */
+    if ((num_to_ack != 0) && p_ccb->in_use && (p_ccb->chnl_state == CST_OPEN))
+    {
+        /* If no frames are awaiting transmission or are held, send an RR or RNR S-frame for ack */
+        if (delay_ack)
+        {
+            /* If it is the first I frame we did not ack, start ack timer */
+            if (!alarm_is_scheduled(p_ccb->fcrb.ack_timer)) {
+                alarm_set_on_queue(p_ccb->fcrb.ack_timer,
+                                   L2CAP_FCR_ACK_TIMEOUT_MS,
+                                   l2c_fcrb_ack_timer_timeout, p_ccb,
+                                   btu_general_alarm_queue);
+            }
+        }
+        else if ((fixed_queue_is_empty(p_ccb->xmit_hold_q) ||
+                  l2c_fcr_is_flow_controlled(p_ccb))
+                 && fixed_queue_is_empty(p_ccb->fcrb.srej_rcv_hold_q))
+        {
+            if (p_fcrb->local_busy)
+                l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RNR, 0);
+            else
+                l2c_fcr_send_S_frame (p_ccb, L2CAP_FCR_SUP_RR, 0);
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         process_stream_frame
+**
+** Description      This function processes frames in streaming mode
+**
+** Returns          -
+**
+*******************************************************************************/
+static void process_stream_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf)
+{
+    assert(p_ccb != NULL);
+    assert(p_buf != NULL);
+
+    uint16_t    ctrl_word;
+    uint16_t    fcs;
+    uint8_t     *p;
+    uint8_t     tx_seq;
+
+    /* Verify FCS if using */
+    if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS)
+    {
+        p = ((uint8_t *)(p_buf+1)) + p_buf->offset + p_buf->len - L2CAP_FCS_LEN;
+
+        /* Extract and drop the FCS from the packet */
+        STREAM_TO_UINT16 (fcs, p);
+        p_buf->len -= L2CAP_FCS_LEN;
+
+        if (l2c_fcr_rx_get_fcs(p_buf) != fcs)
+        {
+            L2CAP_TRACE_WARNING ("Rx L2CAP PDU: CID: 0x%04x  BAD FCS", p_ccb->local_cid);
+            osi_free(p_buf);
+            return;
+        }
+    }
+
+    /* Get the control word */
+    p = ((uint8_t *)(p_buf+1)) + p_buf->offset;
+
+    STREAM_TO_UINT16 (ctrl_word, p);
+
+    p_buf->len    -= L2CAP_FCR_OVERHEAD;
+    p_buf->offset += L2CAP_FCR_OVERHEAD;
+
+    /* Make sure it is an I-frame */
+    if (ctrl_word & L2CAP_FCR_S_FRAME_BIT)
+    {
+        L2CAP_TRACE_WARNING ("Rx L2CAP PDU: CID: 0x%04x  BAD S-frame in streaming mode  ctrl_word: 0x%04x", p_ccb->local_cid, ctrl_word);
+        osi_free(p_buf);
+        return;
+    }
+
+#if (BT_TRACE_VERBOSE == TRUE)
+    L2CAP_TRACE_EVENT ("L2CAP eRTM Rx I-frame: cid: 0x%04x  Len: %u  SAR: %-12s  TxSeq: %u  ReqSeq: %u  F: %u",
+                        p_ccb->local_cid, p_buf->len,
+                        SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT],
+                        (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
+                        (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+                        (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+#endif
+
+    /* Extract the sequence number */
+    tx_seq = (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT;
+
+    /* Check if tx-sequence is the expected one */
+    if (tx_seq != p_ccb->fcrb.next_seq_expected)
+    {
+        L2CAP_TRACE_WARNING ("Rx L2CAP PDU: CID: 0x%04x  Lost frames Exp: %u  Got: %u  p_rx_sdu: 0x%08x",
+                                p_ccb->local_cid, p_ccb->fcrb.next_seq_expected, tx_seq, p_ccb->fcrb.p_rx_sdu);
+
+        /* Lost one or more packets, so flush the SAR queue */
+        osi_free_and_reset((void **)&p_ccb->fcrb.p_rx_sdu);
+    }
+
+    p_ccb->fcrb.next_seq_expected = (tx_seq + 1) & L2CAP_FCR_SEQ_MODULO;
+
+    if (!do_sar_reassembly (p_ccb, p_buf, ctrl_word))
+    {
+        /* Some sort of SAR error, so flush the SAR queue */
+        osi_free_and_reset((void **)&p_ccb->fcrb.p_rx_sdu);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         do_sar_reassembly
+**
+** Description      Process SAR bits and re-assemble frame
+**
+** Returns          true if all OK, else false
+**
+*******************************************************************************/
+static bool    do_sar_reassembly (tL2C_CCB *p_ccb, BT_HDR *p_buf, uint16_t ctrl_word)
+{
+    assert(p_ccb != NULL);
+    assert(p_buf != NULL);
+
+    tL2C_FCRB   *p_fcrb = &p_ccb->fcrb;
+    uint16_t    sar_type = ctrl_word & L2CAP_FCR_SEG_BITS;
+    bool        packet_ok = true;
+    uint8_t     *p;
+
+    /* Check if the SAR state is correct */
+    if ((sar_type == L2CAP_FCR_UNSEG_SDU) || (sar_type == L2CAP_FCR_START_SDU))
+    {
+        if (p_fcrb->p_rx_sdu != NULL)
+        {
+            L2CAP_TRACE_WARNING ("SAR - got unexpected unsegmented or start SDU  Expected len: %u  Got so far: %u",
+                                  p_fcrb->rx_sdu_len, p_fcrb->p_rx_sdu->len);
+
+            packet_ok = false;
+        }
+        /* Check the length of the packet */
+        if ( (sar_type == L2CAP_FCR_START_SDU) && (p_buf->len < L2CAP_SDU_LEN_OVERHEAD) )
+        {
+            L2CAP_TRACE_WARNING ("SAR start packet too short: %u", p_buf->len);
+            packet_ok = false;
+        }
+    }
+    else
+    {
+        if (p_fcrb->p_rx_sdu == NULL)
+        {
+            L2CAP_TRACE_WARNING ("SAR - got unexpected cont or end SDU");
+            packet_ok = false;
+        }
+    }
+
+    if ( (packet_ok) && (sar_type != L2CAP_FCR_UNSEG_SDU) )
+    {
+        p = ((uint8_t *)(p_buf + 1)) + p_buf->offset;
+
+        /* For start SDU packet, extract the SDU length */
+        if (sar_type == L2CAP_FCR_START_SDU)
+        {
+            /* Get the SDU length */
+            STREAM_TO_UINT16 (p_fcrb->rx_sdu_len, p);
+            p_buf->offset += 2;
+            p_buf->len    -= 2;
+
+            if (p_fcrb->rx_sdu_len > p_ccb->max_rx_mtu)
+            {
+                L2CAP_TRACE_WARNING ("SAR - SDU len: %u  larger than MTU: %u", p_fcrb->rx_sdu_len, p_fcrb->rx_sdu_len);
+                packet_ok = false;
+            } else {
+                p_fcrb->p_rx_sdu = (BT_HDR *)osi_malloc(L2CAP_MAX_BUF_SIZE);
+                p_fcrb->p_rx_sdu->offset = OBX_BUF_MIN_OFFSET;
+                p_fcrb->p_rx_sdu->len = 0;
+            }
+        }
+
+        if (packet_ok)
+        {
+            if ((p_fcrb->p_rx_sdu->len + p_buf->len) > p_fcrb->rx_sdu_len)
+            {
+                L2CAP_TRACE_ERROR ("SAR - SDU len exceeded  Type: %u   Lengths: %u %u %u",
+                                    sar_type, p_fcrb->p_rx_sdu->len, p_buf->len, p_fcrb->rx_sdu_len);
+                packet_ok = false;
+            }
+            else if ( (sar_type == L2CAP_FCR_END_SDU) && ((p_fcrb->p_rx_sdu->len + p_buf->len) != p_fcrb->rx_sdu_len) )
+            {
+                L2CAP_TRACE_WARNING ("SAR - SDU end rcvd but SDU incomplete: %u %u %u",
+                                      p_fcrb->p_rx_sdu->len, p_buf->len, p_fcrb->rx_sdu_len);
+                packet_ok = false;
+            }
+            else
+            {
+                memcpy (((uint8_t *) (p_fcrb->p_rx_sdu + 1)) + p_fcrb->p_rx_sdu->offset + p_fcrb->p_rx_sdu->len, p, p_buf->len);
+
+                p_fcrb->p_rx_sdu->len += p_buf->len;
+
+                osi_free(p_buf);
+                p_buf = NULL;
+
+                if (sar_type == L2CAP_FCR_END_SDU)
+                {
+                    p_buf            = p_fcrb->p_rx_sdu;
+                    p_fcrb->p_rx_sdu = NULL;
+                }
+            }
+        }
+    }
+
+    if (packet_ok == false)
+    {
+        osi_free(p_buf);
+    }
+    else if (p_buf != NULL)
+    {
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+        if (p_ccb->local_cid < L2CAP_BASE_APPL_CID &&
+            (p_ccb->local_cid >= L2CAP_FIRST_FIXED_CHNL && p_ccb->local_cid <= L2CAP_LAST_FIXED_CHNL))
+        {
+            if (l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)
+                (*l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)
+                    (p_ccb->local_cid, p_ccb->p_lcb->remote_bd_addr, p_buf);
+        }
+        else
+#endif
+            l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DATA, p_buf);
+    }
+
+    return (packet_ok);
+}
+
+
+/*******************************************************************************
+**
+** Function         retransmit_i_frames
+**
+** Description      This function retransmits i-frames awaiting acks.
+**
+** Returns          bool    - true if retransmitted
+**
+*******************************************************************************/
+static bool    retransmit_i_frames (tL2C_CCB *p_ccb, uint8_t tx_seq)
+{
+    assert(p_ccb != NULL);
+
+    BT_HDR      *p_buf = NULL;
+    uint8_t     *p;
+    uint8_t     buf_seq;
+    uint16_t    ctrl_word;
+
+    if ( (!fixed_queue_is_empty(p_ccb->fcrb.waiting_for_ack_q))
+     &&  (p_ccb->peer_cfg.fcr.max_transmit != 0)
+     &&  (p_ccb->fcrb.num_tries >= p_ccb->peer_cfg.fcr.max_transmit) )
+    {
+        L2CAP_TRACE_EVENT ("Max Tries Exceeded:  (last_acq: %d  CID: 0x%04x  num_tries: %u (max: %u) ack_q_count: %u",
+                p_ccb->fcrb.last_rx_ack, p_ccb->local_cid, p_ccb->fcrb.num_tries, p_ccb->peer_cfg.fcr.max_transmit,
+                fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q));
+
+        l2cu_disconnect_chnl (p_ccb);
+        return (false);
+    }
+
+    /* tx_seq indicates whether to retransmit a specific sequence or all (if == L2C_FCR_RETX_ALL_PKTS) */
+    list_t *list_ack = NULL;
+    const list_node_t *node_ack = NULL;
+    if (! fixed_queue_is_empty(p_ccb->fcrb.waiting_for_ack_q)) {
+        list_ack = fixed_queue_get_list(p_ccb->fcrb.waiting_for_ack_q);
+        node_ack = list_begin(list_ack);
+    }
+    if (tx_seq != L2C_FCR_RETX_ALL_PKTS)
+    {
+        /* If sending only one, the sequence number tells us which one. Look for it.
+        */
+        if (list_ack != NULL) {
+            for ( ; node_ack != list_end(list_ack); node_ack = list_next(node_ack)) {
+                p_buf = (BT_HDR *)list_node(node_ack);
+                /* Get the old control word */
+                p = ((uint8_t *) (p_buf+1)) + p_buf->offset + L2CAP_PKT_OVERHEAD;
+
+                STREAM_TO_UINT16 (ctrl_word, p);
+
+                buf_seq = (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT;
+
+                L2CAP_TRACE_DEBUG ("retransmit_i_frames()   cur seq: %u  looking for: %u", buf_seq, tx_seq);
+
+                if (tx_seq == buf_seq)
+                    break;
+            }
+        }
+
+        if (!p_buf)
+        {
+            L2CAP_TRACE_ERROR ("retransmit_i_frames() UNKNOWN seq: %u  q_count: %u",
+                               tx_seq,
+                               fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q));
+            return (true);
+        }
+    }
+    else
+    {
+        // Iterate though list and flush the amount requested from
+        // the transmit data queue that satisfy the layer and event conditions.
+        for (list_node_t *node_tmp = list_begin(p_ccb->p_lcb->link_xmit_data_q);
+            node_tmp != list_end(p_ccb->p_lcb->link_xmit_data_q);) {
+          BT_HDR *p_tmp = (BT_HDR *)list_node(node_tmp);
+          node_tmp = list_next(node_tmp);
+
+            /* Do not flush other CIDs or partial segments */
+          if ((p_tmp->layer_specific == 0) && (p_tmp->event == p_ccb->local_cid)) {
+            list_remove(p_ccb->p_lcb->link_xmit_data_q, p_tmp);
+            osi_free(p_tmp);
+          }
+        }
+
+        /* Also flush our retransmission queue */
+        while (!fixed_queue_is_empty(p_ccb->fcrb.retrans_q))
+            osi_free(fixed_queue_try_dequeue(p_ccb->fcrb.retrans_q));
+
+        if (list_ack != NULL)
+            node_ack = list_begin(list_ack);
+    }
+
+    if (list_ack != NULL) {
+        while (node_ack != list_end(list_ack))
+        {
+            p_buf = (BT_HDR *)list_node(node_ack);
+            node_ack = list_next(node_ack);
+
+            BT_HDR *p_buf2 = l2c_fcr_clone_buf(p_buf, p_buf->offset, p_buf->len);
+            if (p_buf2)
+            {
+                p_buf2->layer_specific = p_buf->layer_specific;
+
+                fixed_queue_enqueue(p_ccb->fcrb.retrans_q, p_buf2);
+            }
+
+            if ( (tx_seq != L2C_FCR_RETX_ALL_PKTS) || (p_buf2 == NULL) )
+                break;
+        }
+    }
+
+    l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
+
+    if (fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q))
+    {
+        p_ccb->fcrb.num_tries++;
+        l2c_fcr_start_timer (p_ccb);
+    }
+
+    return (true);
+}
+
+
+/*******************************************************************************
+**
+** Function         l2c_fcr_get_next_xmit_sdu_seg
+**
+** Description      Get the next SDU segment to transmit.
+**
+** Returns          pointer to buffer with segment or NULL
+**
+*******************************************************************************/
+BT_HDR *l2c_fcr_get_next_xmit_sdu_seg (tL2C_CCB *p_ccb, uint16_t max_packet_length)
+{
+    assert(p_ccb != NULL);
+
+    bool        first_seg    = false,       /* The segment is the first part of data  */
+                mid_seg      = false,       /* The segment is the middle part of data */
+                last_seg     = false;       /* The segment is the last part of data   */
+    uint16_t    sdu_len = 0;
+    BT_HDR      *p_buf, *p_xmit;
+    uint8_t     *p;
+    uint16_t    max_pdu = p_ccb->tx_mps /* Needed? - L2CAP_MAX_HEADER_FCS*/;
+
+    /* If there is anything in the retransmit queue, that goes first
+    */
+    p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->fcrb.retrans_q);
+    if (p_buf != NULL)
+    {
+        /* Update Rx Seq and FCS if we acked some packets while this one was queued */
+        prepare_I_frame (p_ccb, p_buf, true);
+
+        p_buf->event = p_ccb->local_cid;
+
+#if (L2CAP_ERTM_STATS == TRUE)
+        p_ccb->fcrb.pkts_retransmitted++;
+        p_ccb->fcrb.ertm_pkt_counts[0]++;
+        p_ccb->fcrb.ertm_byte_counts[0] += (p_buf->len - 8);
+#endif
+        return (p_buf);
+    }
+
+    /* For BD/EDR controller, max_packet_length is set to 0             */
+    /* For AMP controller, max_packet_length is set by available blocks */
+    if ( (max_packet_length > L2CAP_MAX_HEADER_FCS)
+      && (max_pdu + L2CAP_MAX_HEADER_FCS > max_packet_length) )
+    {
+        max_pdu = max_packet_length - L2CAP_MAX_HEADER_FCS;
+    }
+
+    p_buf = (BT_HDR *)fixed_queue_try_peek_first(p_ccb->xmit_hold_q);
+
+    /* If there is more data than the MPS, it requires segmentation */
+    if (p_buf->len > max_pdu)
+    {
+        /* We are using the "event" field to tell is if we already started segmentation */
+        if (p_buf->event == 0)
+        {
+            first_seg = true;
+            sdu_len   = p_buf->len;
+        }
+        else
+            mid_seg = true;
+
+        /* Get a new buffer and copy the data that can be sent in a PDU */
+        p_xmit = l2c_fcr_clone_buf(p_buf, L2CAP_MIN_OFFSET + L2CAP_SDU_LEN_OFFSET,
+                                   max_pdu);
+
+        if (p_xmit != NULL)
+        {
+            p_buf->event  = p_ccb->local_cid;
+            p_xmit->event = p_ccb->local_cid;
+
+            p_buf->len    -= max_pdu;
+            p_buf->offset += max_pdu;
+
+            /* copy PBF setting */
+            p_xmit->layer_specific = p_buf->layer_specific;
+        }
+        else /* Should never happen if the application has configured buffers correctly */
+        {
+            L2CAP_TRACE_ERROR ("L2CAP - cannot get buffer for segmentation, max_pdu: %u", max_pdu);
+            return (NULL);
+        }
+    }
+    else    /* Use the original buffer if no segmentation, or the last segment */
+    {
+        p_xmit = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->xmit_hold_q);
+
+        if (p_xmit->event != 0)
+            last_seg = true;
+
+        p_xmit->event = p_ccb->local_cid;
+    }
+
+    /* Step back to add the L2CAP headers */
+    p_xmit->offset -= (L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD);
+    p_xmit->len    += L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD;
+
+    if (first_seg)
+    {
+        p_xmit->offset -= L2CAP_SDU_LEN_OVERHEAD;
+        p_xmit->len    += L2CAP_SDU_LEN_OVERHEAD;
+    }
+
+    /* Set the pointer to the beginning of the data */
+    p = (uint8_t *)(p_xmit + 1) + p_xmit->offset;
+
+    /* Now the L2CAP header */
+
+    /* Note: if FCS has to be included then the length is recalculated later */
+    UINT16_TO_STREAM (p, p_xmit->len - L2CAP_PKT_OVERHEAD);
+
+    UINT16_TO_STREAM (p, p_ccb->remote_cid);
+
+    if (first_seg)
+    {
+        /* Skip control word and add SDU length */
+        p += 2;
+        UINT16_TO_STREAM (p, sdu_len);
+
+        /* We will store the SAR type in layer-specific */
+        /* layer_specific is shared with flushable flag(bits 0-1), don't clear it */
+        p_xmit->layer_specific |= L2CAP_FCR_START_SDU;
+
+        first_seg = false;
+    }
+    else if (mid_seg)
+        p_xmit->layer_specific |= L2CAP_FCR_CONT_SDU;
+    else if (last_seg)
+        p_xmit->layer_specific |= L2CAP_FCR_END_SDU;
+    else
+        p_xmit->layer_specific |= L2CAP_FCR_UNSEG_SDU;
+
+    prepare_I_frame (p_ccb, p_xmit, false);
+
+    if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
+    {
+        BT_HDR *p_wack = l2c_fcr_clone_buf(p_xmit, HCI_DATA_PREAMBLE_SIZE, p_xmit->len);
+
+        if (!p_wack)
+        {
+            L2CAP_TRACE_ERROR("L2CAP - no buffer for xmit cloning, CID: 0x%04x  Length: %u",
+                              p_ccb->local_cid, p_xmit->len);
+
+            /* We will not save the FCS in case we reconfigure and change options */
+            if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS)
+                p_xmit->len -= L2CAP_FCS_LEN;
+
+            /* Pretend we sent it and it got lost */
+            fixed_queue_enqueue(p_ccb->fcrb.waiting_for_ack_q, p_xmit);
+            return (NULL);
+        }
+        else
+        {
+#if (L2CAP_ERTM_STATS == TRUE)
+            /* set timestamp at the end of tx I-frame to get acking delay */
+            /*
+             * NOTE: Here we assume the allocate buffer is large enough
+             * to include extra 4 octets at the end.
+             */
+            p = ((uint8_t *) (p_wack+1)) + p_wack->offset + p_wack->len;
+            UINT32_TO_STREAM (p, time_get_os_boottime_ms());
+#endif
+            /* We will not save the FCS in case we reconfigure and change options */
+            if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS)
+                p_wack->len -= L2CAP_FCS_LEN;
+
+            p_wack->layer_specific = p_xmit->layer_specific;
+            fixed_queue_enqueue(p_ccb->fcrb.waiting_for_ack_q, p_wack);
+        }
+
+#if (L2CAP_ERTM_STATS == TRUE)
+        p_ccb->fcrb.ertm_pkt_counts[0]++;
+        p_ccb->fcrb.ertm_byte_counts[0] += (p_xmit->len - 8);
+#endif
+
+    }
+
+    return (p_xmit);
+}
+
+/*******************************************************************************
+**
+** Function         l2c_lcc_get_next_xmit_sdu_seg
+**
+** Description      Get the next SDU segment to transmit for LE connection oriented channel
+**
+** Returns          pointer to buffer with segment or NULL
+**
+*******************************************************************************/
+BT_HDR *l2c_lcc_get_next_xmit_sdu_seg (tL2C_CCB *p_ccb, uint16_t max_packet_length)
+{
+    bool        first_seg    = false;       /* The segment is the first part of data  */
+    bool        last_seg     = false;       /* The segment is the last part of data  */
+    uint16_t    no_of_bytes_to_send = 0;
+    uint16_t    sdu_len = 0;
+    BT_HDR      *p_buf, *p_xmit;
+    uint8_t     *p;
+    uint16_t    max_pdu = p_ccb->peer_conn_cfg.mps;
+
+    p_buf = (BT_HDR *)fixed_queue_try_peek_first(p_ccb->xmit_hold_q);
+
+    /* We are using the "event" field to tell is if we already started segmentation */
+    if (p_buf->event == 0)
+    {
+        first_seg = true;
+        sdu_len   = p_buf->len;
+        if (p_buf->len <= (max_pdu - L2CAP_LCC_SDU_LENGTH))
+        {
+            last_seg = true;
+            no_of_bytes_to_send = p_buf->len;
+        }
+        else
+            no_of_bytes_to_send = max_pdu - L2CAP_LCC_SDU_LENGTH;
+    }
+    else if (p_buf->len <= max_pdu)
+    {
+        last_seg = true;
+        no_of_bytes_to_send = p_buf->len;
+    }
+    else
+    {
+        /* Middle Packet */
+        no_of_bytes_to_send = max_pdu;
+    }
+
+    /* Get a new buffer and copy the data that can be sent in a PDU */
+    if (first_seg == true)
+        p_xmit = l2c_fcr_clone_buf (p_buf, L2CAP_LCC_OFFSET,
+                    no_of_bytes_to_send);
+    else
+        p_xmit = l2c_fcr_clone_buf (p_buf, L2CAP_MIN_OFFSET,
+                   no_of_bytes_to_send);
+
+    if (p_xmit != NULL)
+    {
+        p_buf->event  = p_ccb->local_cid;
+        p_xmit->event = p_ccb->local_cid;
+
+        if (first_seg == true)
+        {
+            p_xmit->offset -= L2CAP_LCC_SDU_LENGTH;  /* for writing the SDU length. */
+            p = (uint8_t *)(p_xmit + 1) + p_xmit->offset;
+            UINT16_TO_STREAM(p, sdu_len);
+            p_xmit->len += L2CAP_LCC_SDU_LENGTH;
+        }
+
+        p_buf->len    -= no_of_bytes_to_send;
+        p_buf->offset += no_of_bytes_to_send;
+
+        /* copy PBF setting */
+        p_xmit->layer_specific = p_buf->layer_specific;
+
+    }
+    else /* Should never happen if the application has configured buffers correctly */
+    {
+        L2CAP_TRACE_ERROR ("L2CAP - cannot get buffer, for segmentation");
+        return (NULL);
+    }
+
+    if (last_seg == true)
+    {
+        p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->xmit_hold_q);
+        osi_free(p_buf);
+    }
+
+    /* Step back to add the L2CAP headers */
+    p_xmit->offset -= L2CAP_PKT_OVERHEAD;
+    p_xmit->len    += L2CAP_PKT_OVERHEAD ;
+
+    /* Set the pointer to the beginning of the data */
+    p = (uint8_t *)(p_xmit + 1) + p_xmit->offset;
+
+    /* Note: if FCS has to be included then the length is recalculated later */
+    UINT16_TO_STREAM (p, p_xmit->len - L2CAP_PKT_OVERHEAD);
+    UINT16_TO_STREAM (p, p_ccb->remote_cid);
+    return (p_xmit);
+
+}
+
+/*******************************************************************************
+** Configuration negotiation functions
+**
+** The following functions are used in negotiating channel modes during
+** configuration
+********************************************************************************/
+
+/*******************************************************************************
+**
+** Function         l2c_fcr_chk_chan_modes
+**
+** Description      Validates and adjusts if necessary, the FCR options
+**                  based on remote EXT features.
+**
+**                  Note: This assumes peer EXT Features have been received.
+**                      Basic mode is used if FCR Options have not been received
+**
+** Returns          uint8_t - nonzero if can continue, '0' if no compatible channels
+**
+*******************************************************************************/
+uint8_t l2c_fcr_chk_chan_modes (tL2C_CCB *p_ccb)
+{
+    assert(p_ccb != NULL);
+
+    /* Remove nonbasic options that the peer does not support */
+    if (!(p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_ENH_RETRANS))
+        p_ccb->ertm_info.allowed_modes &= ~L2CAP_FCR_CHAN_OPT_ERTM;
+
+    if (!(p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_STREAM_MODE))
+        p_ccb->ertm_info.allowed_modes &= ~L2CAP_FCR_CHAN_OPT_STREAM;
+
+    /* At least one type needs to be set (Basic, ERTM, STM) to continue */
+    if (!p_ccb->ertm_info.allowed_modes)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - Peer does not support our desired channel types");
+    }
+
+    return (p_ccb->ertm_info.allowed_modes);
+}
+
+/*******************************************************************************
+**
+** Function         l2c_fcr_adj_our_req_options
+**
+** Description      Validates and sets up the FCR options passed in from
+**                  L2CA_ConfigReq based on remote device's features.
+**
+** Returns          true if no errors, Otherwise false
+**
+*******************************************************************************/
+bool    l2c_fcr_adj_our_req_options (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
+{
+    assert(p_ccb != NULL);
+    assert(p_cfg != NULL);
+
+    tL2CAP_FCR_OPTS *p_fcr = &p_cfg->fcr;
+
+    if (p_fcr->mode != p_ccb->ertm_info.preferred_mode)
+    {
+        L2CAP_TRACE_WARNING ("l2c_fcr_adj_our_req_options - preferred_mode (%d), does not match mode (%d)",
+                            p_ccb->ertm_info.preferred_mode, p_fcr->mode);
+
+        /* The preferred mode is passed in through tL2CAP_ERTM_INFO, so override this one */
+        p_fcr->mode = p_ccb->ertm_info.preferred_mode;
+    }
+
+    /* If upper layer did not request eRTM mode, BASIC must be used */
+    if (p_ccb->ertm_info.allowed_modes == L2CAP_FCR_CHAN_OPT_BASIC)
+    {
+        if (p_cfg->fcr_present && p_fcr->mode != L2CAP_FCR_BASIC_MODE)
+        {
+            L2CAP_TRACE_WARNING ("l2c_fcr_adj_our_req_options (mode %d): ERROR: No FCR options set using BASIC mode", p_fcr->mode);
+        }
+        p_fcr->mode = L2CAP_FCR_BASIC_MODE;
+    }
+
+    /* Process the FCR options if initial channel bring-up (not a reconfig request)
+    ** Determine initial channel mode to try based on our options and remote's features
+    */
+    if (p_cfg->fcr_present && !(p_ccb->config_done & RECONFIG_FLAG))
+    {
+        /* We need to have at least one mode type common with the peer */
+        if (!l2c_fcr_chk_chan_modes(p_ccb))
+        {
+            /* Two channels have incompatible supported types */
+            l2cu_disconnect_chnl (p_ccb);
+            return (false);
+        }
+
+        /* Basic is the only common channel mode between the two devices */
+        else if (p_ccb->ertm_info.allowed_modes == L2CAP_FCR_CHAN_OPT_BASIC)
+        {
+            /* We only want to try Basic, so bypass sending the FCR options entirely */
+            p_cfg->fcr_present = false;
+            p_cfg->fcs_present = false;             /* Illegal to use FCS option in basic mode */
+            p_cfg->ext_flow_spec_present = false;   /* Illegal to use extended flow spec in basic mode */
+        }
+
+        /* We have at least one non-basic mode available
+         * Override mode from available mode options based on preference, if needed
+         */
+        else
+        {
+            /* If peer does not support STREAMING, try ERTM */
+            if (p_fcr->mode == L2CAP_FCR_STREAM_MODE && !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_STREAM))
+            {
+                L2CAP_TRACE_DEBUG ("L2C CFG: mode is STREAM, but peer does not support; Try ERTM");
+                p_fcr->mode = L2CAP_FCR_ERTM_MODE;
+            }
+
+            /* If peer does not support ERTM, try BASIC (will support this if made it here in the code) */
+            if (p_fcr->mode == L2CAP_FCR_ERTM_MODE && !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_ERTM))
+            {
+                L2CAP_TRACE_DEBUG ("L2C CFG: mode is ERTM, but peer does not support; Try BASIC");
+                p_fcr->mode = L2CAP_FCR_BASIC_MODE;
+            }
+        }
+
+        if (p_fcr->mode != L2CAP_FCR_BASIC_MODE)
+        {
+            /* MTU must be smaller than buffer size */
+            if ( (p_cfg->mtu_present) && (p_cfg->mtu > p_ccb->max_rx_mtu) )
+            {
+                L2CAP_TRACE_WARNING ("L2CAP - MTU: %u  larger than buf size: %u", p_cfg->mtu, p_ccb->max_rx_mtu);
+                return (false);
+            }
+
+            /* application want to use the default MPS */
+            if (p_fcr->mps == L2CAP_DEFAULT_ERM_MPS)
+            {
+                p_fcr->mps = L2CAP_MPS_OVER_BR_EDR;
+            }
+            /* MPS must be less than MTU */
+            else if (p_fcr->mps > p_ccb->max_rx_mtu)
+            {
+                L2CAP_TRACE_WARNING ("L2CAP - MPS  %u  invalid  MTU: %u", p_fcr->mps, p_ccb->max_rx_mtu);
+                return (false);
+            }
+
+            /* We always initially read into the HCI buffer pool, so make sure it fits */
+            if (p_fcr->mps > (L2CAP_MTU_SIZE - L2CAP_MAX_HEADER_FCS))
+                p_fcr->mps = L2CAP_MTU_SIZE - L2CAP_MAX_HEADER_FCS;
+        }
+        else
+        {
+            p_cfg->fcs_present = false;             /* Illegal to use FCS option in basic mode */
+            p_cfg->ext_flow_spec_present = false;   /* Illegal to use extended flow spec in basic mode */
+        }
+
+        p_ccb->our_cfg.fcr = *p_fcr;
+    }
+    else    /* Not sure how to send a reconfiguration(??) should fcr be included? */
+    {
+        p_ccb->our_cfg.fcr_present = false;
+    }
+
+    return (true);
+}
+
+
+/*******************************************************************************
+**
+** Function         l2c_fcr_adj_monitor_retran_timeout
+**
+** Description      Overrides monitor/retrans timer value based on controller
+**
+** Returns          None
+**
+*******************************************************************************/
+void l2c_fcr_adj_monitor_retran_timeout (tL2C_CCB *p_ccb)
+{
+    assert(p_ccb != NULL);
+
+    /* adjust our monitor/retran timeout */
+    if (p_ccb->out_cfg_fcr_present)
+    {
+        /*
+        ** if we requestd ERTM or accepted ERTM
+        ** We may accept ERTM even if we didn't request ERTM, in case of requesting STREAM
+        */
+        if ((p_ccb->our_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
+          ||(p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE))
+        {
+            /* upper layer setting is ignored */
+            p_ccb->our_cfg.fcr.mon_tout    = L2CAP_MIN_MONITOR_TOUT;
+            p_ccb->our_cfg.fcr.rtrans_tout = L2CAP_MIN_RETRANS_TOUT;
+        }
+        else
+        {
+            p_ccb->our_cfg.fcr.mon_tout    = 0;
+            p_ccb->our_cfg.fcr.rtrans_tout = 0;
+        }
+
+        L2CAP_TRACE_DEBUG ("l2c_fcr_adj_monitor_retran_timeout: mon_tout:%d, rtrans_tout:%d",
+                             p_ccb->our_cfg.fcr.mon_tout, p_ccb->our_cfg.fcr.rtrans_tout);
+    }
+}
+/*******************************************************************************
+**
+** Function         l2c_fcr_adj_our_rsp_options
+**
+** Description      Overrides any neccesary FCR options passed in from
+**                  L2CA_ConfigRsp based on our FCR options.
+**                  Only makes adjustments if channel is in ERTM mode.
+**
+** Returns          None
+**
+*******************************************************************************/
+void l2c_fcr_adj_our_rsp_options (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
+{
+    assert(p_ccb != NULL);
+    assert(p_cfg != NULL);
+
+    /* adjust our monitor/retran timeout */
+    l2c_fcr_adj_monitor_retran_timeout(p_ccb);
+
+    p_cfg->fcr_present = p_ccb->out_cfg_fcr_present;
+
+    if (p_cfg->fcr_present)
+    {
+        /* Temporary - until a better algorithm is implemented */
+        /* If peer's tx_wnd_sz requires too many buffers for us to support, then adjust it. For now, respond with our own tx_wnd_sz. */
+        /* Note: peer is not guaranteed to obey our adjustment */
+        if (p_ccb->peer_cfg.fcr.tx_win_sz > p_ccb->our_cfg.fcr.tx_win_sz)
+        {
+            L2CAP_TRACE_DEBUG ("%s: adjusting requested tx_win_sz from %i to %i", __func__, p_ccb->peer_cfg.fcr.tx_win_sz, p_ccb->our_cfg.fcr.tx_win_sz);
+            p_ccb->peer_cfg.fcr.tx_win_sz = p_ccb->our_cfg.fcr.tx_win_sz;
+        }
+
+        p_cfg->fcr.mode         = p_ccb->peer_cfg.fcr.mode;
+        p_cfg->fcr.tx_win_sz    = p_ccb->peer_cfg.fcr.tx_win_sz;
+        p_cfg->fcr.max_transmit = p_ccb->peer_cfg.fcr.max_transmit;
+        p_cfg->fcr.mps          = p_ccb->peer_cfg.fcr.mps;
+        p_cfg->fcr.rtrans_tout  = p_ccb->our_cfg.fcr.rtrans_tout;
+        p_cfg->fcr.mon_tout     = p_ccb->our_cfg.fcr.mon_tout;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2c_fcr_renegotiate_chan
+**
+** Description      Called upon unsuccessful peer response to config request.
+**                  If the error is because of the channel mode, it will try
+**                  to resend using another supported optional channel.
+**
+** Returns          true if resent configuration, False if channel matches or
+**                  cannot match.
+**
+*******************************************************************************/
+bool    l2c_fcr_renegotiate_chan(tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
+{
+    assert(p_ccb != NULL);
+    assert(p_cfg != NULL);
+
+    uint8_t peer_mode = p_ccb->our_cfg.fcr.mode;
+    bool    can_renegotiate;
+
+    /* Skip if this is a reconfiguration from OPEN STATE or if FCR is not returned */
+    if (!p_cfg->fcr_present || (p_ccb->config_done & RECONFIG_FLAG))
+        return (false);
+
+    /* Only retry if there are more channel options to try */
+    if (p_cfg->result == L2CAP_CFG_UNACCEPTABLE_PARAMS)
+    {
+        peer_mode = (p_cfg->fcr_present) ? p_cfg->fcr.mode : L2CAP_FCR_BASIC_MODE;
+
+        if (p_ccb->our_cfg.fcr.mode != peer_mode)
+        {
+
+            if ((--p_ccb->fcr_cfg_tries) == 0)
+            {
+                p_cfg->result = L2CAP_CFG_FAILED_NO_REASON;
+                L2CAP_TRACE_WARNING ("l2c_fcr_renegotiate_chan (Max retries exceeded)");
+            }
+
+            can_renegotiate = false;
+
+            /* Try another supported mode if available based on our last attempted channel */
+            switch (p_ccb->our_cfg.fcr.mode)
+            {
+                /* Our Streaming mode request was unnacceptable; try ERTM or Basic */
+            case L2CAP_FCR_STREAM_MODE:
+                /* 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)");
+                    p_ccb->our_cfg.fcr.mode = L2CAP_FCR_ERTM_MODE;
+                    can_renegotiate = true;
+                }
+                else    /* Falls through */
+
+            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 ("l2c_fcr_renegotiate_chan(Trying Basic)");
+                        can_renegotiate = true;
+                        p_ccb->our_cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+                    }
+                }
+                break;
+
+            default:
+                /* All other scenarios cannot be renegotiated */
+                break;
+            }
+
+            if (can_renegotiate)
+            {
+                p_ccb->our_cfg.fcr_present = true;
+
+                if (p_ccb->our_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)
+                {
+                    p_ccb->our_cfg.fcs_present = false;
+                    p_ccb->our_cfg.ext_flow_spec_present = false;
+
+                    /* Basic Mode uses ACL Data Pool, make sure the MTU fits */
+                    if ( (p_cfg->mtu_present) && (p_cfg->mtu > L2CAP_MTU_SIZE) )
+                    {
+                        L2CAP_TRACE_WARNING ("L2CAP - adjust MTU: %u too large", p_cfg->mtu);
+                        p_cfg->mtu = L2CAP_MTU_SIZE;
+                    }
+                }
+
+                l2cu_process_our_cfg_req (p_ccb, &p_ccb->our_cfg);
+                l2cu_send_peer_config_req (p_ccb, &p_ccb->our_cfg);
+                alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                                   L2CAP_CHNL_CFG_TIMEOUT_MS,
+                                   l2c_ccb_timer_timeout, p_ccb,
+                                   btu_general_alarm_queue);
+                return (true);
+            }
+        }
+    }
+
+    /* Disconnect if the channels do not match */
+    if (p_ccb->our_cfg.fcr.mode != peer_mode)
+    {
+        L2CAP_TRACE_WARNING ("L2C CFG:  Channels incompatible (local %d, peer %d)",
+                              p_ccb->our_cfg.fcr.mode, peer_mode);
+        l2cu_disconnect_chnl (p_ccb);
+    }
+
+    return (false);
+}
+
+
+/*******************************************************************************
+**
+** Function         l2c_fcr_process_peer_cfg_req
+**
+** Description      This function is called to process the FCR options passed
+**                  in the peer's configuration request.
+**
+** Returns          uint8_t - L2CAP_PEER_CFG_OK, L2CAP_PEER_CFG_UNACCEPTABLE,
+**                          or L2CAP_PEER_CFG_DISCONNECT.
+**
+*******************************************************************************/
+uint8_t l2c_fcr_process_peer_cfg_req(tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
+{
+    assert(p_ccb != NULL);
+    assert(p_cfg != NULL);
+
+    uint16_t max_retrans_size;
+    uint8_t fcr_ok = L2CAP_PEER_CFG_OK;
+
+    p_ccb->p_lcb->w4_info_rsp = false;      /* Handles T61x SonyEricsson Bug in Info Request */
+
+    L2CAP_TRACE_EVENT ("l2c_fcr_process_peer_cfg_req() CFG fcr_present:%d fcr.mode:%d CCB FCR mode:%d preferred: %u allowed:%u",
+                        p_cfg->fcr_present, p_cfg->fcr.mode, p_ccb->our_cfg.fcr.mode, p_ccb->ertm_info.preferred_mode,
+                        p_ccb->ertm_info.allowed_modes);
+
+    /* If Peer wants basic, we are done (accept it or disconnect) */
+    if (p_cfg->fcr.mode == L2CAP_FCR_BASIC_MODE)
+    {
+        /* If we do not allow basic, disconnect */
+        if ( !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_BASIC) )
+            fcr_ok = L2CAP_PEER_CFG_DISCONNECT;
+    }
+
+    /* Need to negotiate if our modes are not the same */
+    else if (p_cfg->fcr.mode != p_ccb->ertm_info.preferred_mode)
+    {
+        /* If peer wants a mode that we don't support then retry our mode (ex. rtx/flc), OR
+        ** If we want ERTM and they wanted streaming retry our mode.
+        ** Note: If we have already determined they support our mode previously
+        **       from their EXF mask.
+        */
+        if ( (((1 << p_cfg->fcr.mode) & L2CAP_FCR_CHAN_OPT_ALL_MASK) == 0)
+            || (p_ccb->ertm_info.preferred_mode == L2CAP_FCR_ERTM_MODE) )
+        {
+            p_cfg->fcr.mode = p_ccb->our_cfg.fcr.mode;
+            p_cfg->fcr.tx_win_sz = p_ccb->our_cfg.fcr.tx_win_sz;
+            p_cfg->fcr.max_transmit = p_ccb->our_cfg.fcr.max_transmit;
+            fcr_ok = L2CAP_PEER_CFG_UNACCEPTABLE;
+        }
+
+        /* If we wanted basic, then try to renegotiate it */
+        else if (p_ccb->ertm_info.preferred_mode == L2CAP_FCR_BASIC_MODE)
+        {
+            p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE;
+            p_cfg->fcr.max_transmit = p_cfg->fcr.tx_win_sz = 0;
+            p_cfg->fcr.rtrans_tout = p_cfg->fcr.mon_tout = p_cfg->fcr.mps = 0;
+            p_ccb->our_cfg.fcr.rtrans_tout = p_ccb->our_cfg.fcr.mon_tout = p_ccb->our_cfg.fcr.mps = 0;
+            fcr_ok = L2CAP_PEER_CFG_UNACCEPTABLE;
+        }
+
+        /* Only other valid case is if they want ERTM and we wanted STM which should be
+           accepted if we support it; otherwise the channel should be disconnected */
+        else if ( (p_cfg->fcr.mode != L2CAP_FCR_ERTM_MODE)
+              || !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_ERTM) )
+        {
+            fcr_ok = L2CAP_PEER_CFG_DISCONNECT;
+        }
+    }
+
+    /* Configuration for FCR channels so make any adjustments and fwd to upper layer */
+    if (fcr_ok == L2CAP_PEER_CFG_OK)
+    {
+        /* by default don't need to send params in the response */
+        p_ccb->out_cfg_fcr_present = false;
+
+        /* Make any needed adjustments for the response to the peer */
+        if (p_cfg->fcr_present && p_cfg->fcr.mode != L2CAP_FCR_BASIC_MODE)
+        {
+            /* Peer desires to bypass FCS check, and streaming or ERTM mode */
+            if (p_cfg->fcs_present)
+            {
+                p_ccb->peer_cfg.fcs = p_cfg->fcs;
+                p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_FCS;
+                if( p_cfg->fcs == L2CAP_CFG_FCS_BYPASS)
+                    p_ccb->bypass_fcs |= L2CAP_CFG_FCS_PEER;
+            }
+
+            max_retrans_size = p_ccb->ertm_info.fcr_tx_buf_size - sizeof(BT_HDR)
+                                            - L2CAP_MIN_OFFSET - L2CAP_SDU_LEN_OFFSET - L2CAP_FCS_LEN;
+
+            /* Ensure the MPS is not bigger than the MTU */
+            if ( (p_cfg->fcr.mps == 0) || (p_cfg->fcr.mps > p_ccb->peer_cfg.mtu) )
+            {
+                p_cfg->fcr.mps = p_ccb->peer_cfg.mtu;
+                p_ccb->out_cfg_fcr_present = true;
+            }
+
+            /* Ensure the MPS is not bigger than our retransmission buffer */
+            if (p_cfg->fcr.mps > max_retrans_size)
+            {
+                L2CAP_TRACE_DEBUG("CFG: Overriding MPS to %d (orig %d)", max_retrans_size, p_cfg->fcr.mps);
+
+                p_cfg->fcr.mps = max_retrans_size;
+                p_ccb->out_cfg_fcr_present = true;
+            }
+
+            if (p_cfg->fcr.mode == L2CAP_FCR_ERTM_MODE || p_cfg->fcr.mode == L2CAP_FCR_STREAM_MODE)
+            {
+                /* Always respond with FCR ERTM parameters */
+                p_ccb->out_cfg_fcr_present = true;
+            }
+        }
+
+        /* Everything ok, so save the peer's adjusted fcr options */
+        p_ccb->peer_cfg.fcr = p_cfg->fcr;
+
+        if (p_cfg->fcr_present)
+            p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_FCR;
+    }
+    else if (fcr_ok == L2CAP_PEER_CFG_UNACCEPTABLE)
+    {
+        /* Allow peer only one retry for mode */
+        if (p_ccb->peer_cfg_already_rejected)
+            fcr_ok = L2CAP_PEER_CFG_DISCONNECT;
+        else
+            p_ccb->peer_cfg_already_rejected = true;
+    }
+
+    return (fcr_ok);
+}
+
+#if (L2CAP_ERTM_STATS == TRUE)
+/*******************************************************************************
+**
+** Function         l2c_fcr_collect_ack_delay
+**
+** Description      collect throughput, delay, queue size of waiting ack
+**
+** Parameters
+**                  tL2C_CCB
+**
+** Returns          void
+**
+*******************************************************************************/
+static void l2c_fcr_collect_ack_delay (tL2C_CCB *p_ccb, uint8_t num_bufs_acked)
+{
+    uint32_t index;
+    BT_HDR *p_buf;
+    uint8_t *p;
+    uint32_t timestamp, delay;
+    uint8_t xx;
+    uint8_t str[120];
+
+    index = p_ccb->fcrb.ack_delay_avg_index;
+
+    /* update sum, max and min of waiting for ack queue size */
+    p_ccb->fcrb.ack_q_count_avg[index] +=
+        fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q);
+
+    if (fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q) > p_ccb->fcrb.ack_q_count_max[index])
+        p_ccb->fcrb.ack_q_count_max[index] = fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q);
+
+    if (fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q) < p_ccb->fcrb.ack_q_count_min[index])
+        p_ccb->fcrb.ack_q_count_min[index] = fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q);
+
+    /* update sum, max and min of round trip delay of acking */
+    list_t *list = NULL;
+    if (! fixed_queue_is_empty(p_ccb->fcrb.waiting_for_ack_q))
+        list = fixed_queue_get_list(p_ccb->fcrb.waiting_for_ack_q);
+    if (list != NULL) {
+        for (const list_node_t *node = list_begin(list), xx = 0;
+             (node != list_end(list)) && (xx < num_bufs_acked);
+             node = list_next(node), xx++) {
+            p_buf = list_node(node);
+            /* adding up length of acked I-frames to get throughput */
+            p_ccb->fcrb.throughput[index] += p_buf->len - 8;
+
+            if ( xx == num_bufs_acked - 1 )
+            {
+                /* get timestamp from tx I-frame that receiver is acking */
+                p = ((uint8_t *) (p_buf+1)) + p_buf->offset + p_buf->len;
+                if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS)
+                {
+                    p += L2CAP_FCS_LEN;
+                }
+
+                STREAM_TO_UINT32(timestamp, p);
+                delay = time_get_os_boottime_ms() - timestamp;
+
+                p_ccb->fcrb.ack_delay_avg[index] += delay;
+                if ( delay > p_ccb->fcrb.ack_delay_max[index] )
+                    p_ccb->fcrb.ack_delay_max[index] = delay;
+                if ( delay < p_ccb->fcrb.ack_delay_min[index] )
+                    p_ccb->fcrb.ack_delay_min[index] = delay;
+            }
+        }
+    }
+
+    p_ccb->fcrb.ack_delay_avg_count++;
+
+    /* calculate average and initialize next avg, min and max */
+    if (p_ccb->fcrb.ack_delay_avg_count > L2CAP_ERTM_STATS_AVG_NUM_SAMPLES)
+    {
+        p_ccb->fcrb.ack_delay_avg_count = 0;
+
+        p_ccb->fcrb.ack_q_count_avg[index] /= L2CAP_ERTM_STATS_AVG_NUM_SAMPLES;
+        p_ccb->fcrb.ack_delay_avg[index] /= L2CAP_ERTM_STATS_AVG_NUM_SAMPLES;
+
+        /* calculate throughput */
+        timestamp = time_get_os_boottime_ms();
+        if (timestamp - p_ccb->fcrb.throughput_start > 0)
+            p_ccb->fcrb.throughput[index] /= (timestamp - p_ccb->fcrb.throughput_start);
+
+        p_ccb->fcrb.throughput_start = timestamp;
+
+        snprintf(str, sizeof(str), "[%02u] throughput: %5u, ack_delay avg:%3u, min:%3u, max:%3u, ack_q_count avg:%3u, min:%3u, max:%3u",
+                index, p_ccb->fcrb.throughput[index],
+                p_ccb->fcrb.ack_delay_avg[index], p_ccb->fcrb.ack_delay_min[index], p_ccb->fcrb.ack_delay_max[index],
+                p_ccb->fcrb.ack_q_count_avg[index], p_ccb->fcrb.ack_q_count_min[index], p_ccb->fcrb.ack_q_count_max[index] );
+
+        BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI , TRACE_TYPE_GENERIC, "%s", str);
+
+        index = (index + 1) % L2CAP_ERTM_STATS_NUM_AVG;
+        p_ccb->fcrb.ack_delay_avg_index = index;
+
+        p_ccb->fcrb.ack_q_count_max[index] = 0;
+        p_ccb->fcrb.ack_q_count_min[index] = 0xFFFFFFFF;
+        p_ccb->fcrb.ack_q_count_avg[index] = 0;
+
+
+        p_ccb->fcrb.ack_delay_max[index] = 0;
+        p_ccb->fcrb.ack_delay_min[index] = 0xFFFFFFFF;
+        p_ccb->fcrb.ack_delay_avg[index] = 0;
+
+        p_ccb->fcrb.throughput[index] = 0;
+    }
+}
+#endif
diff --git a/bt/stack/l2cap/l2c_int.h b/bt/stack/l2cap/l2c_int.h
new file mode 100644
index 0000000..4312a02
--- /dev/null
+++ b/bt/stack/l2cap/l2c_int.h
@@ -0,0 +1,792 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 L2CAP internal definitions
+ *
+ ******************************************************************************/
+#ifndef L2C_INT_H
+#define L2C_INT_H
+
+#include <stdbool.h>
+
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/list.h"
+#include "btm_api.h"
+#include "bt_common.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define L2CAP_MIN_MTU   48      /* Minimum acceptable MTU is 48 bytes */
+
+/* LE credit based L2CAP connection parameters */
+#define L2CAP_LE_MIN_MTU            23
+#define L2CAP_LE_MIN_MPS            23
+#define L2CAP_LE_MAX_MPS            65533
+#define L2CAP_LE_MIN_CREDIT         0
+#define L2CAP_LE_MAX_CREDIT         65535
+#define L2CAP_LE_DEFAULT_MTU        512
+#define L2CAP_LE_DEFAULT_MPS        23
+#define L2CAP_LE_DEFAULT_CREDIT     1
+
+/*
+ * Timeout values (in milliseconds).
+ */
+#define L2CAP_LINK_ROLE_SWITCH_TIMEOUT_MS  (10 * 1000)  /* 10 seconds */
+#define L2CAP_LINK_CONNECT_TIMEOUT_MS      (60 * 1000)  /* 30 seconds */
+#define L2CAP_LINK_CONNECT_EXT_TIMEOUT_MS (120 * 1000)  /* 120 seconds */
+#define L2CAP_ECHO_RSP_TIMEOUT_MS          (30 * 1000)  /* 30 seconds */
+#define L2CAP_LINK_FLOW_CONTROL_TIMEOUT_MS  (2 * 1000)  /* 2 seconds */
+#define L2CAP_LINK_DISCONNECT_TIMEOUT_MS   (30 * 1000)  /* 30 seconds */
+#define L2CAP_CHNL_CONNECT_TIMEOUT_MS      (60 * 1000)  /* 60 seconds */
+#define L2CAP_CHNL_CONNECT_EXT_TIMEOUT_MS (120 * 1000)  /* 120 seconds */
+#define L2CAP_CHNL_CFG_TIMEOUT_MS          (30 * 1000)  /* 30 seconds */
+#define L2CAP_CHNL_DISCONNECT_TIMEOUT_MS   (10 * 1000)  /* 10 seconds */
+#define L2CAP_DELAY_CHECK_SM4_TIMEOUT_MS    (2 * 1000)  /* 2 seconds */
+#define L2CAP_WAIT_INFO_RSP_TIMEOUT_MS      (3 * 1000)  /* 3 seconds */
+#define L2CAP_BLE_LINK_CONNECT_TIMEOUT_MS  (30 * 1000)  /* 30 seconds */
+#define L2CAP_FCR_ACK_TIMEOUT_MS                  200   /* 200 milliseconds */
+
+/* Define the possible L2CAP channel states. The names of
+** the states may seem a bit strange, but they are taken from
+** the Bluetooth specification.
+*/
+typedef enum
+{
+    CST_CLOSED,                           /* Channel is in closed state           */
+    CST_ORIG_W4_SEC_COMP,                 /* Originator waits security clearence  */
+    CST_TERM_W4_SEC_COMP,                 /* Acceptor waits security clearence    */
+    CST_W4_L2CAP_CONNECT_RSP,             /* Waiting for peer conenct response    */
+    CST_W4_L2CA_CONNECT_RSP,              /* Waiting for upper layer connect rsp  */
+    CST_CONFIG,                           /* Negotiating configuration            */
+    CST_OPEN,                             /* Data transfer state                  */
+    CST_W4_L2CAP_DISCONNECT_RSP,          /* Waiting for peer disconnect rsp      */
+    CST_W4_L2CA_DISCONNECT_RSP            /* Waiting for upper layer disc rsp     */
+} tL2C_CHNL_STATE;
+
+/* Define the possible L2CAP link states
+*/
+typedef enum
+{
+    LST_DISCONNECTED,
+    LST_CONNECT_HOLDING,
+    LST_CONNECTING_WAIT_SWITCH,
+    LST_CONNECTING,
+    LST_CONNECTED,
+    LST_DISCONNECTING
+} tL2C_LINK_STATE;
+
+
+
+/* Define input events to the L2CAP link and channel state machines. The names
+** of the events may seem a bit strange, but they are taken from
+** the Bluetooth specification.
+*/
+#define L2CEVT_LP_CONNECT_CFM          0          /* Lower layer connect confirm          */
+#define L2CEVT_LP_CONNECT_CFM_NEG      1          /* Lower layer connect confirm (failed) */
+#define L2CEVT_LP_CONNECT_IND          2          /* Lower layer connect indication       */
+#define L2CEVT_LP_DISCONNECT_IND       3          /* Lower layer disconnect indication    */
+#define L2CEVT_LP_QOS_CFM              4          /* Lower layer QOS confirmation         */
+#define L2CEVT_LP_QOS_CFM_NEG          5          /* Lower layer QOS confirmation (failed)*/
+#define L2CEVT_LP_QOS_VIOLATION_IND    6          /* Lower layer QOS violation indication */
+
+#define L2CEVT_SEC_COMP                7          /* Security cleared successfully        */
+#define L2CEVT_SEC_COMP_NEG            8          /* Security procedure failed            */
+
+#define L2CEVT_L2CAP_CONNECT_REQ      10          /* Peer connection request              */
+#define L2CEVT_L2CAP_CONNECT_RSP      11          /* Peer connection response             */
+#define L2CEVT_L2CAP_CONNECT_RSP_PND  12          /* Peer connection response pending     */
+#define L2CEVT_L2CAP_CONNECT_RSP_NEG  13          /* Peer connection response (failed)    */
+#define L2CEVT_L2CAP_CONFIG_REQ       14          /* Peer configuration request           */
+#define L2CEVT_L2CAP_CONFIG_RSP       15          /* Peer configuration response          */
+#define L2CEVT_L2CAP_CONFIG_RSP_NEG   16          /* Peer configuration response (failed) */
+#define L2CEVT_L2CAP_DISCONNECT_REQ   17          /* Peer disconnect request              */
+#define L2CEVT_L2CAP_DISCONNECT_RSP   18          /* Peer disconnect response             */
+#define L2CEVT_L2CAP_INFO_RSP         19          /* Peer information response            */
+#define L2CEVT_L2CAP_DATA             20          /* Peer data                            */
+
+#define L2CEVT_L2CA_CONNECT_REQ       21          /* Upper layer connect request          */
+#define L2CEVT_L2CA_CONNECT_RSP       22          /* Upper layer connect response         */
+#define L2CEVT_L2CA_CONNECT_RSP_NEG   23          /* Upper layer connect response (failed)*/
+#define L2CEVT_L2CA_CONFIG_REQ        24          /* Upper layer config request           */
+#define L2CEVT_L2CA_CONFIG_RSP        25          /* Upper layer config response          */
+#define L2CEVT_L2CA_CONFIG_RSP_NEG    26          /* Upper layer config response (failed) */
+#define L2CEVT_L2CA_DISCONNECT_REQ    27          /* Upper layer disconnect request       */
+#define L2CEVT_L2CA_DISCONNECT_RSP    28          /* Upper layer disconnect response      */
+#define L2CEVT_L2CA_DATA_READ         29          /* Upper layer data read                */
+#define L2CEVT_L2CA_DATA_WRITE        30          /* Upper layer data write               */
+#define L2CEVT_L2CA_FLUSH_REQ         31          /* Upper layer flush                    */
+
+#define L2CEVT_TIMEOUT                32          /* Timeout                              */
+#define L2CEVT_SEC_RE_SEND_CMD        33          /* btm_sec has enough info to proceed   */
+
+#define L2CEVT_ACK_TIMEOUT            34          /* RR delay timeout                     */
+
+#define L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT     35    /* Upper layer credit packet */
+#define L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT    36    /* Peer credit packet */
+
+/* Bitmask to skip over Broadcom feature reserved (ID) to avoid sending two
+   successive ID values, '0' id only or both */
+#define L2CAP_ADJ_BRCM_ID           0x1
+#define L2CAP_ADJ_ZERO_ID           0x2
+#define L2CAP_ADJ_ID                0x3
+
+/* Return values for l2cu_process_peer_cfg_req() */
+#define L2CAP_PEER_CFG_UNACCEPTABLE     0
+#define L2CAP_PEER_CFG_OK               1
+#define L2CAP_PEER_CFG_DISCONNECT       2
+
+/* eL2CAP option constants */
+#define L2CAP_MIN_RETRANS_TOUT          2000    /* Min retransmission timeout if no flush timeout or PBF */
+#define L2CAP_MIN_MONITOR_TOUT          12000   /* Min monitor timeout if no flush timeout or PBF */
+
+#define L2CAP_MAX_FCR_CFG_TRIES         2       /* Config attempts before disconnecting */
+
+typedef uint8_t tL2C_BLE_FIXED_CHNLS_MASK;
+
+typedef struct
+{
+    uint8_t     next_tx_seq;                /* Next sequence number to be Tx'ed         */
+    uint8_t     last_rx_ack;                /* Last sequence number ack'ed by the peer  */
+    uint8_t     next_seq_expected;          /* Next peer sequence number expected       */
+    uint8_t     last_ack_sent;              /* Last peer sequence number ack'ed         */
+    uint8_t     num_tries;                  /* Number of retries to send a packet       */
+    uint8_t     max_held_acks;              /* Max acks we can hold before sending      */
+
+    bool        remote_busy;                /* true if peer has flowed us off           */
+    bool        local_busy;                 /* true if we have flowed off the peer      */
+
+    bool        rej_sent;                   /* Reject was sent                          */
+    bool        srej_sent;                  /* Selective Reject was sent                */
+    bool        wait_ack;                   /* Transmitter is waiting ack (poll sent)   */
+    bool        rej_after_srej;             /* Send a REJ when SREJ clears              */
+
+    bool        send_f_rsp;                 /* We need to send an F-bit response        */
+
+    uint16_t    rx_sdu_len;                 /* Length of the SDU being received         */
+    BT_HDR      *p_rx_sdu;                  /* Buffer holding the SDU being received    */
+    fixed_queue_t *waiting_for_ack_q;       /* Buffers sent and waiting for peer to ack */
+    fixed_queue_t *srej_rcv_hold_q;         /* Buffers rcvd but held pending SREJ rsp   */
+    fixed_queue_t *retrans_q;               /* Buffers being retransmitted              */
+
+    alarm_t       *ack_timer;                /* Timer delaying RR                        */
+    alarm_t       *mon_retrans_timer;       /* Timer Monitor or Retransmission          */
+
+#if (L2CAP_ERTM_STATS == TRUE)
+    uint32_t    connect_tick_count;         /* Time channel was established             */
+    uint32_t    ertm_pkt_counts[2];         /* Packets sent and received                */
+    uint32_t    ertm_byte_counts[2];        /* Bytes   sent and received                */
+    uint32_t    s_frames_sent[4];           /* S-frames sent (RR, REJ, RNR, SREJ)       */
+    uint32_t    s_frames_rcvd[4];           /* S-frames rcvd (RR, REJ, RNR, SREJ)       */
+    uint32_t    xmit_window_closed;         /* # of times the xmit window was closed    */
+    uint32_t    controller_idle;            /* # of times less than 2 packets in controller */
+                                            /* when the xmit window was closed          */
+    uint32_t    pkts_retransmitted;         /* # of packets that were retransmitted     */
+    uint32_t    retrans_touts;              /* # of retransmission timouts              */
+    uint32_t    xmit_ack_touts;             /* # of xmit ack timouts                    */
+
+#define L2CAP_ERTM_STATS_NUM_AVG 10
+#define L2CAP_ERTM_STATS_AVG_NUM_SAMPLES 100
+    uint32_t    ack_delay_avg_count;
+    uint32_t    ack_delay_avg_index;
+    uint32_t    throughput_start;
+    uint32_t    throughput[L2CAP_ERTM_STATS_NUM_AVG];
+    uint32_t    ack_delay_avg[L2CAP_ERTM_STATS_NUM_AVG];
+    uint32_t    ack_delay_min[L2CAP_ERTM_STATS_NUM_AVG];
+    uint32_t    ack_delay_max[L2CAP_ERTM_STATS_NUM_AVG];
+    uint32_t    ack_q_count_avg[L2CAP_ERTM_STATS_NUM_AVG];
+    uint32_t    ack_q_count_min[L2CAP_ERTM_STATS_NUM_AVG];
+    uint32_t    ack_q_count_max[L2CAP_ERTM_STATS_NUM_AVG];
+#endif
+} tL2C_FCRB;
+
+
+/* Define a registration control block. Every application (e.g. RFCOMM, SDP,
+** TCS etc) that registers with L2CAP is assigned one of these.
+*/
+#if (L2CAP_UCD_INCLUDED == TRUE)
+#define L2C_UCD_RCB_ID              0x00
+#define L2C_UCD_STATE_UNUSED        0x00
+#define L2C_UCD_STATE_W4_DATA       0x01
+#define L2C_UCD_STATE_W4_RECEPTION  0x02
+#define L2C_UCD_STATE_W4_MTU        0x04
+
+typedef struct
+{
+    uint8_t             state;
+    tL2CAP_UCD_CB_INFO  cb_info;
+} tL2C_UCD_REG;
+#endif
+
+typedef struct
+{
+    bool                    in_use;
+    uint16_t                psm;
+    uint16_t                real_psm;               /* This may be a dummy RCB for an o/b connection but */
+                                                    /* this is the real PSM that we need to connect to   */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+    tL2C_UCD_REG            ucd;
+#endif
+
+    tL2CAP_APPL_INFO        api;
+} tL2C_RCB;
+
+
+#ifndef L2CAP_CBB_DEFAULT_DATA_RATE_BUFF_QUOTA
+#define L2CAP_CBB_DEFAULT_DATA_RATE_BUFF_QUOTA 100
+#endif
+
+typedef void (tL2CAP_SEC_CBACK) (BD_ADDR bd_addr, tBT_TRANSPORT trasnport,
+                                void *p_ref_data, tBTM_STATUS result);
+
+typedef struct
+{
+    uint16_t                psm;
+    tBT_TRANSPORT           transport;
+    bool                    is_originator;
+    tL2CAP_SEC_CBACK        *p_callback;
+    void                    *p_ref_data;
+}tL2CAP_SEC_DATA;
+
+/* Define a channel control block (CCB). There may be many channel control blocks
+** between the same two Bluetooth devices (i.e. on the same link).
+** Each CCB has unique local and remote CIDs. All channel control blocks on
+** the same physical link and are chained together.
+*/
+typedef struct t_l2c_ccb
+{
+    bool                in_use;                 /* true when in use, false when not */
+    tL2C_CHNL_STATE     chnl_state;             /* Channel state                    */
+    tL2CAP_LE_CFG_INFO  local_conn_cfg;         /* Our config for ble conn oriented channel */
+    tL2CAP_LE_CFG_INFO  peer_conn_cfg;          /* Peer device config ble conn oriented channel */
+    bool                is_first_seg;           /* Dtermine whether the received packet is the first segment or not */
+    BT_HDR*             ble_sdu;                /* Buffer for storing unassembled sdu*/
+    uint16_t            ble_sdu_length;         /* Length of unassembled sdu length*/
+    struct t_l2c_ccb    *p_next_ccb;            /* Next CCB in the chain            */
+    struct t_l2c_ccb    *p_prev_ccb;            /* Previous CCB in the chain        */
+    struct t_l2c_linkcb *p_lcb;                 /* Link this CCB is assigned to     */
+
+    uint16_t            local_cid;              /* Local CID                        */
+    uint16_t            remote_cid;             /* Remote CID                       */
+
+    alarm_t             *l2c_ccb_timer;         /* CCB Timer Entry */
+
+    tL2C_RCB            *p_rcb;                 /* Registration CB for this Channel */
+    bool                should_free_rcb;        /* True if RCB was allocated on the heap */
+
+#define IB_CFG_DONE     0x01
+#define OB_CFG_DONE     0x02
+#define RECONFIG_FLAG   0x04                    /* True after initial configuration */
+#define CFG_DONE_MASK   (IB_CFG_DONE | OB_CFG_DONE)
+
+    uint8_t             config_done;            /* Configuration flag word         */
+    uint8_t             local_id;               /* Transaction ID for local trans  */
+    uint8_t             remote_id;              /* Transaction ID for local  */
+
+#define CCB_FLAG_NO_RETRY       0x01            /* no more retry */
+#define CCB_FLAG_SENT_PENDING   0x02            /* already sent pending response */
+    uint8_t             flags;
+
+    tL2CAP_CFG_INFO     our_cfg;                /* Our saved configuration options    */
+    tL2CAP_CH_CFG_BITS  peer_cfg_bits;          /* Store what peer wants to configure */
+    tL2CAP_CFG_INFO     peer_cfg;               /* Peer's saved configuration options */
+
+    fixed_queue_t       *xmit_hold_q;            /* Transmit data hold queue         */
+    bool                cong_sent;              /* Set when congested status sent   */
+    uint16_t            buff_quota;             /* Buffer quota before sending congestion   */
+
+    tL2CAP_CHNL_PRIORITY ccb_priority;          /* Channel priority                 */
+    tL2CAP_CHNL_DATA_RATE tx_data_rate;         /* Channel Tx data rate             */
+    tL2CAP_CHNL_DATA_RATE rx_data_rate;         /* Channel Rx data rate             */
+
+    /* Fields used for eL2CAP */
+    tL2CAP_ERTM_INFO    ertm_info;
+    tL2C_FCRB           fcrb;
+    uint16_t            tx_mps;                 /* TX MPS adjusted based on current controller */
+    uint16_t            max_rx_mtu;
+    uint8_t             fcr_cfg_tries;          /* Max number of negotiation attempts */
+    bool                peer_cfg_already_rejected; /* If mode rejected once, set to true */
+    bool                out_cfg_fcr_present;    /* true if cfg response shoulkd include fcr options */
+
+#define L2CAP_CFG_FCS_OUR   0x01                /* Our desired config FCS option */
+#define L2CAP_CFG_FCS_PEER  0x02                /* Peer's desired config FCS option */
+#define L2CAP_BYPASS_FCS    (L2CAP_CFG_FCS_OUR | L2CAP_CFG_FCS_PEER)
+    uint8_t             bypass_fcs;
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+    bool                is_flushable;                   /* true if channel is flushable     */
+#endif
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0 || L2CAP_UCD_INCLUDED == TRUE)
+    uint16_t            fixed_chnl_idle_tout;   /* Idle timeout to use for the fixed channel       */
+#endif
+    uint16_t            tx_data_len;
+} tL2C_CCB;
+
+/***********************************************************************
+** Define a queue of linked CCBs.
+*/
+typedef struct
+{
+    tL2C_CCB        *p_first_ccb;               /* The first channel in this queue */
+    tL2C_CCB        *p_last_ccb;                /* The last  channel in this queue */
+} tL2C_CCB_Q;
+
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+
+/* Round-Robin service for the same priority channels */
+#define L2CAP_NUM_CHNL_PRIORITY     3           /* Total number of priority group (high, medium, low)*/
+#define L2CAP_CHNL_PRIORITY_WEIGHT  5           /* weight per priority for burst transmission quota */
+#define L2CAP_GET_PRIORITY_QUOTA(pri) ((L2CAP_NUM_CHNL_PRIORITY - (pri)) * L2CAP_CHNL_PRIORITY_WEIGHT)
+
+/* CCBs within the same LCB are served in round robin with priority                       */
+/* It will make sure that low priority channel (for example, HF signaling on RFCOMM)      */
+/* can be sent to headset even if higher priority channel (for example, AV media channel) */
+/* is congested.                                                                          */
+
+typedef struct
+{
+    tL2C_CCB        *p_serve_ccb;               /* current serving ccb within priority group */
+    tL2C_CCB        *p_first_ccb;               /* first ccb of priority group */
+    uint8_t         num_ccb;                    /* number of channels in priority group */
+    uint8_t         quota;                      /* burst transmission quota */
+} tL2C_RR_SERV;
+
+#endif /* (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE) */
+
+/* Define a link control block. There is one link control block between
+** this device and any other device (i.e. BD ADDR).
+*/
+typedef struct t_l2c_linkcb
+{
+    bool                in_use;                     /* true when in use, false when not */
+    tL2C_LINK_STATE     link_state;
+
+    alarm_t             *l2c_lcb_timer;             /* Timer entry for timeout evt */
+    uint16_t            handle;                     /* The handle used with LM          */
+
+    tL2C_CCB_Q          ccb_queue;                  /* Queue of CCBs on this LCB        */
+
+    tL2C_CCB            *p_pending_ccb;             /* ccb of waiting channel during link disconnect */
+    alarm_t             *info_resp_timer;           /* Timer entry for info resp timeout evt */
+    BD_ADDR             remote_bd_addr;             /* The BD address of the remote     */
+
+    uint8_t             link_role;                  /* Master or slave                  */
+    uint8_t             id;
+    uint8_t             cur_echo_id;                /* Current id value for echo request */
+    tL2CA_ECHO_RSP_CB   *p_echo_rsp_cb;             /* Echo response callback           */
+    uint16_t            idle_timeout;               /* Idle timeout                     */
+    bool                is_bonding;                 /* True - link active only for bonding */
+
+    uint16_t            link_flush_tout;            /* Flush timeout used               */
+
+    uint16_t            link_xmit_quota;            /* Num outstanding pkts allowed     */
+    uint16_t            sent_not_acked;             /* Num packets sent but not acked   */
+
+    bool                partial_segment_being_sent; /* Set true when a partial segment  */
+                                                    /* is being sent.                   */
+    bool                w4_info_rsp;                /* true when info request is active */
+    uint8_t             info_rx_bits;               /* set 1 if received info type */
+    uint32_t            peer_ext_fea;               /* Peer's extended features mask    */
+    list_t              *link_xmit_data_q;          /* Link transmit data buffer queue  */
+
+    uint8_t             peer_chnl_mask[L2CAP_FIXED_CHNL_ARRAY_SIZE];
+#if (L2CAP_UCD_INCLUDED == TRUE)
+    uint16_t            ucd_mtu;                    /* peer MTU on UCD */
+    fixed_queue_t       *ucd_out_sec_pending_q;     /* Security pending outgoing UCD packet  */
+    fixed_queue_t       *ucd_in_sec_pending_q;       /* Security pending incoming UCD packet  */
+#endif
+
+    BT_HDR              *p_hcit_rcv_acl;            /* Current HCIT ACL buf being rcvd  */
+    uint16_t            idle_timeout_sv;            /* Save current Idle timeout        */
+    uint8_t             acl_priority;               /* L2C_PRIORITY_NORMAL or L2C_PRIORITY_HIGH */
+    tL2CA_NOCP_CB       *p_nocp_cb;                 /* Num Cmpl pkts callback           */
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+    tL2C_CCB            *p_fixed_ccbs[L2CAP_NUM_FIXED_CHNLS];
+    uint16_t            disc_reason;
+#endif
+
+    tBT_TRANSPORT       transport;
+#if (BLE_INCLUDED == TRUE)
+    tBLE_ADDR_TYPE      ble_addr_type;
+    uint16_t            tx_data_len;            /* tx data length used in data length extension */
+    fixed_queue_t       *le_sec_pending_q;      /* LE coc channels waiting for security check completion */
+    uint8_t             sec_act;
+#define L2C_BLE_CONN_UPDATE_DISABLE 0x1  /* disable update connection parameters */
+#define L2C_BLE_NEW_CONN_PARAM      0x2  /* new connection parameter to be set */
+#define L2C_BLE_UPDATE_PENDING      0x4  /* waiting for connection update finished */
+#define L2C_BLE_NOT_DEFAULT_PARAM   0x8  /* not using default connection parameters */
+    uint8_t             conn_update_mask;
+
+    uint16_t            min_interval; /* parameters as requested by peripheral */
+    uint16_t            max_interval;
+    uint16_t            latency;
+    uint16_t            timeout;
+
+#endif
+
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+    /* each priority group is limited burst transmission  */
+    /* round robin service for the same priority channels */
+    tL2C_RR_SERV        rr_serv[L2CAP_NUM_CHNL_PRIORITY];
+    uint8_t             rr_pri;                             /* current serving priority group */
+#endif
+
+} tL2C_LCB;
+
+/* Define the L2CAP control structure
+*/
+typedef struct
+{
+    uint8_t         l2cap_trace_level;
+    uint16_t        controller_xmit_window;         /* Total ACL window for all links   */
+
+    uint16_t        round_robin_quota;              /* Round-robin link quota           */
+    uint16_t        round_robin_unacked;            /* Round-robin unacked              */
+    bool            check_round_robin;              /* Do a round robin check           */
+
+    bool            is_cong_cback_context;
+
+    tL2C_LCB        lcb_pool[MAX_L2CAP_LINKS];      /* Link Control Block pool          */
+    tL2C_CCB        ccb_pool[MAX_L2CAP_CHANNELS];   /* Channel Control Block pool       */
+    tL2C_RCB        rcb_pool[MAX_L2CAP_CLIENTS];    /* Registration info pool           */
+
+    tL2C_CCB        *p_free_ccb_first;              /* Pointer to first free CCB        */
+    tL2C_CCB        *p_free_ccb_last;               /* Pointer to last  free CCB        */
+
+    uint8_t         desire_role;                    /* desire to be master/slave when accepting a connection */
+    bool            disallow_switch;                /* false, to allow switch at create conn */
+    uint16_t        num_lm_acl_bufs;                /* # of ACL buffers on controller   */
+    uint16_t        idle_timeout;                   /* Idle timeout                     */
+
+    list_t          *rcv_pending_q;                 /* Recv pending queue               */
+    alarm_t         *receive_hold_timer;            /* Timer entry for rcv hold    */
+
+    tL2C_LCB        *p_cur_hcit_lcb;                /* Current HCI Transport buffer     */
+    uint16_t        num_links_active;               /* Number of links active           */
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+    uint16_t        non_flushable_pbf;              /* L2CAP_PKT_START_NON_FLUSHABLE if controller supports */
+                                                    /* Otherwise, L2CAP_PKT_START */
+    bool            is_flush_active;                /* true if an HCI_Enhanced_Flush has been sent */
+#endif
+
+#if (L2CAP_CONFORMANCE_TESTING == TRUE)
+    uint32_t        test_info_resp;                 /* Conformance testing needs a dynamic response */
+#endif
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+    tL2CAP_FIXED_CHNL_REG   fixed_reg[L2CAP_NUM_FIXED_CHNLS];   /* Reg info for fixed channels */
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+    uint16_t                 num_ble_links_active;               /* Number of LE links active           */
+    bool                     is_ble_connecting;
+    BD_ADDR                  ble_connecting_bda;
+    uint16_t                 controller_le_xmit_window;         /* Total ACL window for all links   */
+    tL2C_BLE_FIXED_CHNLS_MASK l2c_ble_fixed_chnls_mask;         // LE fixed channels mask
+    uint16_t                 num_lm_ble_bufs;                   /* # of ACL buffers on controller   */
+    uint16_t                 ble_round_robin_quota;              /* Round-robin link quota           */
+    uint16_t                 ble_round_robin_unacked;            /* Round-robin unacked              */
+    bool                     ble_check_round_robin;              /* Do a round robin check           */
+    tL2C_RCB                 ble_rcb_pool[BLE_MAX_L2CAP_CLIENTS]; /* Registration info pool           */
+#endif
+
+    tL2CA_ECHO_DATA_CB      *p_echo_data_cb;                /* Echo data callback */
+
+#if (L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE == TRUE)
+    uint16_t            high_pri_min_xmit_quota;    /* Minimum number of ACL credit for high priority link */
+#endif /* (L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE == TRUE) */
+
+    uint16_t        dyn_psm;
+} tL2C_CB;
+
+
+
+/* Define a structure that contains the information about a connection.
+** This structure is used to pass between functions, and not all the
+** fields will always be filled in.
+*/
+typedef struct
+{
+    BD_ADDR         bd_addr;                        /* Remote BD address        */
+    uint8_t         status;                         /* Connection status        */
+    uint16_t        psm;                            /* PSM of the connection    */
+    uint16_t        l2cap_result;                   /* L2CAP result             */
+    uint16_t        l2cap_status;                   /* L2CAP status             */
+    uint16_t        remote_cid;                     /* Remote CID               */
+} tL2C_CONN_INFO;
+
+
+typedef void (tL2C_FCR_MGMT_EVT_HDLR) (uint8_t, tL2C_CCB *);
+
+/* The offset in a buffer that L2CAP will use when building commands.
+*/
+#define L2CAP_SEND_CMD_OFFSET       0
+
+
+/* Number of ACL buffers to use for high priority channel
+*/
+#if (L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE == FALSE)
+#define L2CAP_HIGH_PRI_MIN_XMIT_QUOTA_A     (L2CAP_HIGH_PRI_MIN_XMIT_QUOTA)
+#else
+#define L2CAP_HIGH_PRI_MIN_XMIT_QUOTA_A     (l2cb.high_pri_min_xmit_quota)
+#endif
+
+/* L2CAP global data
+************************************
+*/
+extern tL2C_CB  l2cb;
+
+
+/* Functions provided by l2c_main.cc
+************************************
+*/
+void l2c_init(void);
+void l2c_free(void);
+
+extern void     l2c_receive_hold_timer_timeout(void *data);
+extern void     l2c_ccb_timer_timeout(void *data);
+extern void     l2c_lcb_timer_timeout(void *data);
+extern void     l2c_fcrb_ack_timer_timeout(void *data);
+extern uint8_t  l2c_data_write (uint16_t cid, BT_HDR *p_data, uint16_t flag);
+extern void     l2c_rcv_acl_data (BT_HDR *p_msg);
+extern void     l2c_process_held_packets (bool    timed_out);
+
+/* Functions provided by l2c_utils.cc
+************************************
+*/
+extern tL2C_LCB *l2cu_allocate_lcb (BD_ADDR p_bd_addr, bool    is_bonding, tBT_TRANSPORT transport);
+extern bool     l2cu_start_post_bond_timer (uint16_t handle);
+extern void     l2cu_release_lcb (tL2C_LCB *p_lcb);
+extern tL2C_LCB *l2cu_find_lcb_by_bd_addr (BD_ADDR p_bd_addr, tBT_TRANSPORT transport);
+extern tL2C_LCB *l2cu_find_lcb_by_handle (uint16_t handle);
+extern void     l2cu_update_lcb_4_bonding (BD_ADDR p_bd_addr, bool    is_bonding);
+
+extern uint8_t  l2cu_get_conn_role (tL2C_LCB *p_this_lcb);
+extern bool     l2cu_set_acl_priority (BD_ADDR bd_addr, uint8_t priority, bool    reset_after_rs);
+
+extern void     l2cu_enqueue_ccb (tL2C_CCB *p_ccb);
+extern void     l2cu_dequeue_ccb (tL2C_CCB *p_ccb);
+extern void     l2cu_change_pri_ccb (tL2C_CCB *p_ccb, tL2CAP_CHNL_PRIORITY priority);
+
+extern tL2C_CCB *l2cu_allocate_ccb (tL2C_LCB *p_lcb, uint16_t cid);
+extern void     l2cu_release_ccb (tL2C_CCB *p_ccb);
+extern tL2C_CCB *l2cu_find_ccb_by_cid (tL2C_LCB *p_lcb, uint16_t local_cid);
+extern tL2C_CCB *l2cu_find_ccb_by_remote_cid (tL2C_LCB *p_lcb, uint16_t remote_cid);
+extern void     l2cu_adj_id (tL2C_LCB *p_lcb, uint8_t adj_mask);
+extern bool     l2c_is_cmd_rejected (uint8_t cmd_code, uint8_t id, tL2C_LCB *p_lcb);
+
+extern void     l2cu_send_peer_cmd_reject (tL2C_LCB *p_lcb, uint16_t reason,
+                                           uint8_t rem_id,uint16_t p1, uint16_t p2);
+extern void     l2cu_send_peer_connect_req (tL2C_CCB *p_ccb);
+extern void     l2cu_send_peer_connect_rsp (tL2C_CCB *p_ccb, uint16_t result, uint16_t status);
+extern void     l2cu_send_peer_config_req (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg);
+extern void     l2cu_send_peer_config_rsp (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg);
+extern void     l2cu_send_peer_config_rej (tL2C_CCB *p_ccb, uint8_t *p_data, uint16_t data_len, uint16_t rej_len);
+extern void     l2cu_send_peer_disc_req (tL2C_CCB *p_ccb);
+extern void     l2cu_send_peer_disc_rsp (tL2C_LCB *p_lcb, uint8_t remote_id, uint16_t local_cid, uint16_t remote_cid);
+extern void     l2cu_send_peer_echo_req (tL2C_LCB *p_lcb, uint8_t *p_data, uint16_t data_len);
+extern void     l2cu_send_peer_echo_rsp (tL2C_LCB *p_lcb, uint8_t id, uint8_t *p_data, uint16_t data_len);
+extern void     l2cu_send_peer_info_rsp (tL2C_LCB *p_lcb, uint8_t id, uint16_t info_type);
+extern void     l2cu_reject_connection (tL2C_LCB *p_lcb, uint16_t remote_cid, uint8_t rem_id, uint16_t result);
+extern void     l2cu_send_peer_info_req (tL2C_LCB *p_lcb, uint16_t info_type);
+extern void     l2cu_set_acl_hci_header (BT_HDR *p_buf, tL2C_CCB *p_ccb);
+extern void     l2cu_check_channel_congestion (tL2C_CCB *p_ccb);
+extern void     l2cu_disconnect_chnl (tL2C_CCB *p_ccb);
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+extern void     l2cu_set_non_flushable_pbf(bool   );
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+extern void l2cu_send_peer_ble_par_req (tL2C_LCB *p_lcb, uint16_t min_int, uint16_t max_int, uint16_t latency, uint16_t timeout);
+extern void l2cu_send_peer_ble_par_rsp (tL2C_LCB *p_lcb, uint16_t reason, uint8_t rem_id);
+extern void l2cu_reject_ble_connection (tL2C_LCB *p_lcb, uint8_t rem_id, uint16_t result);
+extern void l2cu_send_peer_ble_credit_based_conn_res (tL2C_CCB *p_ccb, uint16_t result);
+extern void l2cu_send_peer_ble_credit_based_conn_req (tL2C_CCB *p_ccb);
+extern void l2cu_send_peer_ble_flow_control_credit(tL2C_CCB *p_ccb, uint16_t credit_value);
+extern void l2cu_send_peer_ble_credit_based_disconn_req(tL2C_CCB *p_ccb);
+#endif
+
+extern bool    l2cu_initialize_fixed_ccb (tL2C_LCB *p_lcb, uint16_t fixed_cid, tL2CAP_FCR_OPTS *p_fcr);
+extern void    l2cu_no_dynamic_ccbs (tL2C_LCB *p_lcb);
+extern void    l2cu_process_fixed_chnl_resp (tL2C_LCB *p_lcb);
+extern bool    l2cu_is_ccb_active (tL2C_CCB *p_ccb);
+
+/* Functions provided by l2c_ucd.cc
+************************************
+*/
+#if (L2CAP_UCD_INCLUDED == TRUE)
+void l2c_ucd_delete_sec_pending_q(tL2C_LCB  *p_lcb);
+void l2c_ucd_enqueue_pending_out_sec_q(tL2C_CCB  *p_ccb, void *p_data);
+bool    l2c_ucd_check_pending_info_req(tL2C_CCB  *p_ccb);
+bool    l2c_ucd_check_pending_out_sec_q(tL2C_CCB  *p_ccb);
+void l2c_ucd_send_pending_out_sec_q(tL2C_CCB  *p_ccb);
+void l2c_ucd_discard_pending_out_sec_q(tL2C_CCB  *p_ccb);
+bool    l2c_ucd_check_pending_in_sec_q(tL2C_CCB  *p_ccb);
+void l2c_ucd_send_pending_in_sec_q(tL2C_CCB  *p_ccb);
+void l2c_ucd_discard_pending_in_sec_q(tL2C_CCB  *p_ccb);
+bool    l2c_ucd_check_rx_pkts(tL2C_LCB  *p_lcb, BT_HDR *p_msg);
+bool    l2c_ucd_process_event(tL2C_CCB *p_ccb, uint16_t event, void *p_data);
+#endif
+
+/* Functions provided for Broadcom Aware
+****************************************
+*/
+extern bool     l2cu_check_feature_req (tL2C_LCB *p_lcb, uint8_t id, uint8_t *p_data, uint16_t data_len);
+extern void     l2cu_check_feature_rsp (tL2C_LCB *p_lcb, uint8_t id, uint8_t *p_data, uint16_t data_len);
+extern void     l2cu_send_feature_req (tL2C_CCB *p_ccb);
+
+extern tL2C_RCB *l2cu_allocate_rcb (uint16_t psm);
+extern tL2C_RCB *l2cu_find_rcb_by_psm (uint16_t psm);
+extern void     l2cu_release_rcb (tL2C_RCB *p_rcb);
+extern tL2C_RCB *l2cu_allocate_ble_rcb (uint16_t psm);
+extern tL2C_RCB *l2cu_find_ble_rcb_by_psm (uint16_t psm);
+
+extern uint8_t  l2cu_process_peer_cfg_req (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg);
+extern void     l2cu_process_peer_cfg_rsp (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg);
+extern void     l2cu_process_our_cfg_req (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg);
+extern void     l2cu_process_our_cfg_rsp (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg);
+
+extern void     l2cu_device_reset (void);
+extern tL2C_LCB *l2cu_find_lcb_by_state (tL2C_LINK_STATE state);
+extern bool     l2cu_lcb_disconnecting (void);
+
+extern bool    l2cu_create_conn (tL2C_LCB *p_lcb, tBT_TRANSPORT transport);
+extern bool    l2cu_create_conn_after_switch (tL2C_LCB *p_lcb);
+extern BT_HDR *l2cu_get_next_buffer_to_send (tL2C_LCB *p_lcb);
+extern void    l2cu_resubmit_pending_sec_req (BD_ADDR p_bda);
+extern void    l2cu_initialize_amp_ccb (tL2C_LCB *p_lcb);
+extern void    l2cu_adjust_out_mps (tL2C_CCB *p_ccb);
+
+/* Functions provided by l2c_link.cc
+************************************
+*/
+extern bool     l2c_link_hci_conn_req (BD_ADDR bd_addr);
+extern bool     l2c_link_hci_conn_comp (uint8_t status, uint16_t handle, BD_ADDR p_bda);
+extern bool     l2c_link_hci_disc_comp (uint16_t handle, uint8_t reason);
+extern bool     l2c_link_hci_qos_violation (uint16_t handle);
+extern void     l2c_link_timeout (tL2C_LCB *p_lcb);
+extern void     l2c_info_resp_timer_timeout(void *data);
+extern void     l2c_link_check_send_pkts (tL2C_LCB *p_lcb, tL2C_CCB *p_ccb, BT_HDR *p_buf);
+extern void     l2c_link_adjust_allocation (void);
+extern void     l2c_link_process_num_completed_pkts (uint8_t *p);
+extern void     l2c_link_process_num_completed_blocks (uint8_t controller_id, uint8_t *p, uint16_t evt_len);
+extern void     l2c_link_processs_num_bufs (uint16_t num_lm_acl_bufs);
+extern uint8_t  l2c_link_pkts_rcvd (uint16_t *num_pkts, uint16_t *handles);
+extern void     l2c_link_role_changed (BD_ADDR bd_addr, uint8_t new_role, uint8_t hci_status);
+extern void     l2c_link_sec_comp (BD_ADDR p_bda, tBT_TRANSPORT trasnport, void *p_ref_data, uint8_t status);
+extern void     l2c_link_segments_xmitted (BT_HDR *p_msg);
+extern void     l2c_pin_code_request (BD_ADDR bd_addr);
+extern void     l2c_link_adjust_chnl_allocation (void);
+
+#if (BLE_INCLUDED == TRUE)
+extern void     l2c_link_processs_ble_num_bufs (uint16_t num_lm_acl_bufs);
+#endif
+
+#if (L2CAP_WAKE_PARKED_LINK == TRUE)
+extern bool     l2c_link_check_power_mode ( tL2C_LCB *p_lcb );
+#define L2C_LINK_CHECK_POWER_MODE(x) l2c_link_check_power_mode ((x))
+#else  // L2CAP_WAKE_PARKED_LINK
+#define L2C_LINK_CHECK_POWER_MODE(x) (false)
+#endif  // L2CAP_WAKE_PARKED_LINK
+
+#if (L2CAP_CONFORMANCE_TESTING == TRUE)
+/* Used only for conformance testing */
+extern void l2cu_set_info_rsp_mask (uint32_t mask);
+#endif
+
+/* Functions provided by l2c_csm.cc
+************************************
+*/
+extern void l2c_csm_execute (tL2C_CCB *p_ccb, uint16_t event, void *p_data);
+
+extern void l2c_enqueue_peer_data (tL2C_CCB *p_ccb, BT_HDR *p_buf);
+
+
+/* Functions provided by l2c_fcr.cc
+************************************
+*/
+extern void     l2c_fcr_cleanup (tL2C_CCB *p_ccb);
+extern void     l2c_fcr_proc_pdu (tL2C_CCB *p_ccb, BT_HDR *p_buf);
+extern void     l2c_fcr_proc_tout (tL2C_CCB *p_ccb);
+extern void     l2c_fcr_proc_ack_tout (tL2C_CCB *p_ccb);
+extern void     l2c_fcr_send_S_frame (tL2C_CCB *p_ccb, uint16_t function_code, uint16_t pf_bit);
+extern BT_HDR   *l2c_fcr_clone_buf(BT_HDR *p_buf, uint16_t new_offset, uint16_t no_of_bytes);
+extern bool     l2c_fcr_is_flow_controlled (tL2C_CCB *p_ccb);
+extern BT_HDR   *l2c_fcr_get_next_xmit_sdu_seg (tL2C_CCB *p_ccb, uint16_t max_packet_length);
+extern void     l2c_fcr_start_timer (tL2C_CCB *p_ccb);
+extern void     l2c_lcc_proc_pdu (tL2C_CCB *p_ccb, BT_HDR *p_buf);
+extern BT_HDR   *l2c_lcc_get_next_xmit_sdu_seg (tL2C_CCB *p_ccb, uint16_t max_packet_length);
+
+/* Configuration negotiation */
+extern uint8_t  l2c_fcr_chk_chan_modes (tL2C_CCB *p_ccb);
+extern bool     l2c_fcr_adj_our_req_options (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg);
+extern void     l2c_fcr_adj_our_rsp_options (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_peer_cfg);
+extern bool     l2c_fcr_renegotiate_chan(tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg);
+extern uint8_t  l2c_fcr_process_peer_cfg_req(tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg);
+extern void     l2c_fcr_adj_monitor_retran_timeout (tL2C_CCB *p_ccb);
+extern void     l2c_fcr_stop_timer (tL2C_CCB *p_ccb);
+
+/* Functions provided by l2c_ble.cc
+************************************
+*/
+#if (BLE_INCLUDED == TRUE)
+extern bool    l2cble_create_conn (tL2C_LCB *p_lcb);
+extern void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, uint8_t *p, uint16_t pkt_len);
+extern void l2cble_conn_comp (uint16_t handle, uint8_t role, BD_ADDR bda, tBLE_ADDR_TYPE type,
+                              uint16_t conn_interval, uint16_t conn_latency, uint16_t conn_timeout);
+extern bool    l2cble_init_direct_conn (tL2C_LCB *p_lcb);
+extern void l2cble_notify_le_connection (BD_ADDR bda);
+extern void l2c_ble_link_adjust_allocation (void);
+extern void l2cble_process_conn_update_evt (uint16_t handle, uint8_t status,
+                        uint16_t interval, uint16_t latency, uint16_t timeout);
+
+extern void l2cble_credit_based_conn_req (tL2C_CCB *p_ccb);
+extern void l2cble_credit_based_conn_res (tL2C_CCB *p_ccb, uint16_t result);
+extern void l2cble_send_peer_disc_req(tL2C_CCB *p_ccb);
+extern void l2cble_send_flow_control_credit(tL2C_CCB *p_ccb, uint16_t credit_value);
+extern bool    l2ble_sec_access_req(BD_ADDR bd_addr, uint16_t psm, bool    is_originator, tL2CAP_SEC_CBACK *p_callback, void *p_ref_data);
+
+#if (BLE_LLT_INCLUDED == TRUE)
+extern void l2cble_process_rc_param_request_evt(uint16_t handle, uint16_t int_min, uint16_t int_max,
+                                                        uint16_t latency, uint16_t timeout);
+#endif
+
+extern void l2cble_update_data_length(tL2C_LCB *p_lcb);
+extern void l2cble_set_fixed_channel_tx_data_length(BD_ADDR remote_bda, uint16_t fix_cid,
+                                                                uint16_t tx_mtu);
+extern void l2cble_process_data_length_change_event(uint16_t handle, uint16_t tx_data_len,
+                                                                uint16_t rx_data_len);
+
+#endif
+extern void l2cu_process_fixed_disc_cback (tL2C_LCB *p_lcb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bt/stack/l2cap/l2c_link.cc b/bt/stack/l2cap/l2c_link.cc
new file mode 100644
index 0000000..b7eb94a
--- /dev/null
+++ b/bt/stack/l2cap/l2c_link.cc
@@ -0,0 +1,1553 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 functions relating to link management. A "link"
+ *  is a connection between this device and another device. Only ACL links
+ *  are managed.
+ *
+ ******************************************************************************/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "device/include/controller.h"
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "hcimsgs.h"
+#include "l2cdefs.h"
+#include "l2c_int.h"
+#include "l2c_api.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btcore/include/bdaddr.h"
+#include "osi/include/osi.h"
+
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+static bool    l2c_link_send_to_lower (tL2C_LCB *p_lcb, BT_HDR *p_buf);
+
+/*******************************************************************************
+**
+** Function         l2c_link_hci_conn_req
+**
+** Description      This function is called when an HCI Connection Request
+**                  event is received.
+**
+** Returns          true, if accept conn
+**
+*******************************************************************************/
+bool    l2c_link_hci_conn_req (BD_ADDR bd_addr)
+{
+    tL2C_LCB        *p_lcb;
+    tL2C_LCB        *p_lcb_cur;
+    int             xx;
+    bool            no_links;
+
+    /* See if we have a link control block for the remote device */
+    p_lcb = l2cu_find_lcb_by_bd_addr (bd_addr, BT_TRANSPORT_BR_EDR);
+
+    /* If we don't have one, create one and accept the connection. */
+    if (!p_lcb)
+    {
+        p_lcb = l2cu_allocate_lcb (bd_addr, false, BT_TRANSPORT_BR_EDR);
+        if (!p_lcb)
+        {
+            btsnd_hcic_reject_conn (bd_addr, HCI_ERR_HOST_REJECT_RESOURCES);
+            L2CAP_TRACE_ERROR ("L2CAP failed to allocate LCB");
+            return false;
+        }
+
+        no_links = true;
+
+        /* If we already have connection, accept as a master */
+        for (xx = 0, p_lcb_cur = &l2cb.lcb_pool[0]; xx < MAX_L2CAP_LINKS; xx++, p_lcb_cur++)
+        {
+            if (p_lcb_cur == p_lcb)
+                continue;
+
+            if (p_lcb_cur->in_use)
+            {
+                no_links = false;
+                p_lcb->link_role = HCI_ROLE_MASTER;
+                break;
+            }
+        }
+
+        if (no_links)
+        {
+            if (!btm_dev_support_switch (bd_addr))
+                p_lcb->link_role = HCI_ROLE_SLAVE;
+            else
+                p_lcb->link_role = l2cu_get_conn_role(p_lcb);
+        }
+
+
+        /* Tell the other side we accept the connection */
+        btsnd_hcic_accept_conn (bd_addr, p_lcb->link_role);
+
+        p_lcb->link_state = LST_CONNECTING;
+
+        /* Start a timer waiting for connect complete */
+        alarm_set_on_queue(p_lcb->l2c_lcb_timer, L2CAP_LINK_CONNECT_TIMEOUT_MS,
+                           l2c_lcb_timer_timeout, p_lcb,
+                           btu_general_alarm_queue);
+        return (true);
+    }
+
+    /* We already had a link control block to the guy. Check what state it is in */
+    if ((p_lcb->link_state == LST_CONNECTING) || (p_lcb->link_state == LST_CONNECT_HOLDING))
+    {
+        /* Connection collision. Accept the connection anyways. */
+
+        if (!btm_dev_support_switch (bd_addr))
+            p_lcb->link_role = HCI_ROLE_SLAVE;
+        else
+            p_lcb->link_role = l2cu_get_conn_role(p_lcb);
+
+        btsnd_hcic_accept_conn (bd_addr, p_lcb->link_role);
+
+        p_lcb->link_state = LST_CONNECTING;
+        return (true);
+    }
+    else if (p_lcb->link_state == LST_DISCONNECTING)
+    {
+        /* In disconnecting state, reject the connection. */
+        btsnd_hcic_reject_conn (bd_addr, HCI_ERR_HOST_REJECT_DEVICE);
+    }
+    else
+    {
+        L2CAP_TRACE_ERROR("L2CAP got conn_req while connected (state:%d). Reject it",
+                p_lcb->link_state);
+        /* Reject the connection with ACL Connection Already exist reason */
+        btsnd_hcic_reject_conn (bd_addr, HCI_ERR_CONNECTION_EXISTS);
+    }
+    return (false);
+}
+
+/*******************************************************************************
+**
+** Function         l2c_link_hci_conn_comp
+**
+** Description      This function is called when an HCI Connection Complete
+**                  event is received.
+**
+** Returns          void
+**
+*******************************************************************************/
+bool    l2c_link_hci_conn_comp (uint8_t status, uint16_t handle, BD_ADDR p_bda)
+{
+    tL2C_CONN_INFO       ci;
+    tL2C_LCB            *p_lcb;
+    tL2C_CCB            *p_ccb;
+    tBTM_SEC_DEV_REC    *p_dev_info = NULL;
+
+    btm_acl_update_busy_level (BTM_BLI_PAGE_DONE_EVT);
+
+    /* Save the parameters */
+    ci.status       = status;
+    memcpy (ci.bd_addr, p_bda, BD_ADDR_LEN);
+
+    /* See if we have a link control block for the remote device */
+    p_lcb = l2cu_find_lcb_by_bd_addr (ci.bd_addr, BT_TRANSPORT_BR_EDR);
+
+    /* If we don't have one, this is an error */
+    if (!p_lcb)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP got conn_comp for unknown BD_ADDR");
+        return (false);
+    }
+
+    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);
+
+        if (status != HCI_SUCCESS)
+            l2c_link_hci_disc_comp (p_lcb->handle, status);
+
+        return (false);
+    }
+
+    /* Save the handle */
+    p_lcb->handle = handle;
+
+    if (ci.status == HCI_SUCCESS)
+    {
+        /* Connected OK. Change state to connected */
+        p_lcb->link_state = LST_CONNECTED;
+
+        /* Get the peer information if the l2cap flow-control/rtrans is supported */
+        l2cu_send_peer_info_req (p_lcb, L2CAP_EXTENDED_FEATURES_INFO_TYPE);
+
+        /* Tell BTM Acl management about the link */
+        if ((p_dev_info = btm_find_dev (p_bda)) != NULL)
+            btm_acl_created (ci.bd_addr, p_dev_info->dev_class,
+                             p_dev_info->sec_bd_name, handle,
+                             p_lcb->link_role, BT_TRANSPORT_BR_EDR);
+        else
+            btm_acl_created (ci.bd_addr, NULL, NULL, handle, p_lcb->link_role, BT_TRANSPORT_BR_EDR);
+
+        BTM_SetLinkSuperTout (ci.bd_addr, btm_cb.btm_def_link_super_tout);
+
+        /* If dedicated bonding do not process any further */
+        if (p_lcb->is_bonding)
+        {
+            if (l2cu_start_post_bond_timer(handle))
+                return (true);
+        }
+
+        /* Update the timeouts in the hold queue */
+        l2c_process_held_packets(false);
+
+        alarm_cancel(p_lcb->l2c_lcb_timer);
+
+        /* For all channels, send the event through their FSMs */
+        for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
+        {
+            l2c_csm_execute (p_ccb, L2CEVT_LP_CONNECT_CFM, &ci);
+        }
+
+        if (p_lcb->p_echo_rsp_cb)
+        {
+            l2cu_send_peer_echo_req (p_lcb, NULL, 0);
+            alarm_set_on_queue(p_lcb->l2c_lcb_timer,
+                               L2CAP_ECHO_RSP_TIMEOUT_MS,
+                               l2c_lcb_timer_timeout, p_lcb,
+                               btu_general_alarm_queue);
+        }
+        else if (!p_lcb->ccb_queue.p_first_ccb)
+        {
+            period_ms_t timeout_ms = L2CAP_LINK_STARTUP_TOUT * 1000;
+            alarm_set_on_queue(p_lcb->l2c_lcb_timer, timeout_ms,
+                               l2c_lcb_timer_timeout, p_lcb,
+                               btu_general_alarm_queue);
+        }
+    }
+    /* Max number of acl connections.                          */
+    /* If there's an lcb disconnecting set this one to holding */
+    else if ((ci.status == HCI_ERR_MAX_NUM_OF_CONNECTIONS) && l2cu_lcb_disconnecting())
+    {
+        p_lcb->link_state = LST_CONNECT_HOLDING;
+        p_lcb->handle = HCI_INVALID_HANDLE;
+    }
+    else
+    {
+        /* Just in case app decides to try again in the callback context */
+        p_lcb->link_state = LST_DISCONNECTING;
+
+        /* Connection failed. For all channels, send the event through */
+        /* their FSMs. The CCBs should remove themselves from the LCB  */
+        for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; )
+        {
+            tL2C_CCB *pn = p_ccb->p_next_ccb;
+
+            l2c_csm_execute (p_ccb, L2CEVT_LP_CONNECT_CFM_NEG, &ci);
+
+            p_ccb = pn;
+        }
+
+        p_lcb->disc_reason = status;
+        /* Release the LCB */
+        if (p_lcb->ccb_queue.p_first_ccb == NULL)
+            l2cu_release_lcb (p_lcb);
+        else                              /* there are any CCBs remaining */
+        {
+            if (ci.status == HCI_ERR_CONNECTION_EXISTS)
+            {
+                /* we are in collision situation, wait for connecttion request from controller */
+                p_lcb->link_state = LST_CONNECTING;
+            }
+            else
+            {
+                l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR);
+            }
+        }
+    }
+    return (true);
+}
+
+
+/*******************************************************************************
+**
+** Function         l2c_link_sec_comp
+**
+** Description      This function is called when required security procedures
+**                  are completed.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2c_link_sec_comp (BD_ADDR p_bda,
+                        UNUSED_ATTR tBT_TRANSPORT transport, void *p_ref_data,
+                        uint8_t status)
+{
+    tL2C_CONN_INFO  ci;
+    tL2C_LCB        *p_lcb;
+    tL2C_CCB        *p_ccb;
+    tL2C_CCB        *p_next_ccb;
+    uint8_t         event;
+
+    L2CAP_TRACE_DEBUG ("l2c_link_sec_comp: %d, 0x%x", status, p_ref_data);
+
+    if (status == BTM_SUCCESS_NO_SECURITY)
+        status = BTM_SUCCESS;
+
+    /* Save the parameters */
+    ci.status       = status;
+    memcpy (ci.bd_addr, p_bda, BD_ADDR_LEN);
+
+    p_lcb = l2cu_find_lcb_by_bd_addr (p_bda, transport);
+
+    /* If we don't have one, this is an error */
+    if (!p_lcb)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP got sec_comp for unknown BD_ADDR");
+        return;
+    }
+
+    /* Match p_ccb with p_ref_data returned by sec manager */
+    for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_next_ccb)
+    {
+        p_next_ccb = p_ccb->p_next_ccb;
+
+        if (p_ccb == p_ref_data)
+        {
+            switch(status)
+            {
+            case BTM_SUCCESS:
+                event = L2CEVT_SEC_COMP;
+                break;
+
+            case BTM_DELAY_CHECK:
+                /* start a timer - encryption change not received before L2CAP connect req */
+                alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+                                   L2CAP_DELAY_CHECK_SM4_TIMEOUT_MS,
+                                   l2c_ccb_timer_timeout, p_ccb,
+                                   btu_general_alarm_queue);
+                return;
+
+            default:
+                event = L2CEVT_SEC_COMP_NEG;
+            }
+            l2c_csm_execute (p_ccb, event, &ci);
+            break;
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         l2c_link_hci_disc_comp
+**
+** Description      This function is called when an HCI Disconnect Complete
+**                  event is received.
+**
+** Returns          true if the link is known about, else false
+**
+*******************************************************************************/
+bool    l2c_link_hci_disc_comp (uint16_t handle, uint8_t reason)
+{
+    tL2C_LCB    *p_lcb;
+    tL2C_CCB    *p_ccb;
+    bool        status = true;
+    bool        lcb_is_free = true;
+    tBT_TRANSPORT   transport = BT_TRANSPORT_BR_EDR;
+
+    /* See if we have a link control block for the connection */
+    p_lcb = l2cu_find_lcb_by_handle (handle);
+
+    /* If we don't have one, maybe an SCO link. Send to MM */
+    if (!p_lcb)
+    {
+        status = false;
+    }
+    else
+    {
+        /* There can be a case when we rejected PIN code authentication */
+        /* otherwise save a new reason */
+        if (btm_cb.acl_disc_reason != HCI_ERR_HOST_REJECT_SECURITY)
+            btm_cb.acl_disc_reason = reason;
+
+        p_lcb->disc_reason = btm_cb.acl_disc_reason;
+
+        /* Just in case app decides to try again in the callback context */
+        p_lcb->link_state = LST_DISCONNECTING;
+
+#if (BLE_INCLUDED == TRUE)
+        /* Check for BLE and handle that differently */
+        if (p_lcb->transport == BT_TRANSPORT_LE)
+            btm_ble_update_link_topology_mask(p_lcb->link_role, false);
+#endif
+        /* Link is disconnected. For all channels, send the event through */
+        /* their FSMs. The CCBs should remove themselves from the LCB     */
+        for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; )
+        {
+            tL2C_CCB *pn = p_ccb->p_next_ccb;
+
+            /* Keep connect pending control block (if exists)
+             * Possible Race condition when a reconnect occurs
+             * on the channel during a disconnect of link. This
+             * ccb will be automatically retried after link disconnect
+             * arrives
+             */
+            if (p_ccb != p_lcb->p_pending_ccb)
+            {
+                l2c_csm_execute (p_ccb, L2CEVT_LP_DISCONNECT_IND, &reason);
+            }
+            p_ccb = pn;
+        }
+
+#if (BTM_SCO_INCLUDED == TRUE)
+#if (BLE_INCLUDED == TRUE)
+        if (p_lcb->transport == BT_TRANSPORT_BR_EDR)
+#endif
+            /* Tell SCO management to drop any SCOs on this ACL */
+            btm_sco_acl_removed (p_lcb->remote_bd_addr);
+#endif
+
+        /* If waiting for disconnect and reconnect is pending start the reconnect now
+           race condition where layer above issued connect request on link that was
+           disconnecting
+         */
+        if (p_lcb->ccb_queue.p_first_ccb != NULL || p_lcb->p_pending_ccb)
+        {
+            L2CAP_TRACE_DEBUG("l2c_link_hci_disc_comp: Restarting pending ACL request");
+            transport = p_lcb->transport;
+#if (BLE_INCLUDED == TRUE)
+            /* for LE link, always drop and re-open to ensure to get LE remote feature */
+            if (p_lcb->transport == BT_TRANSPORT_LE)
+            {
+                l2cb.is_ble_connecting = false;
+                btm_acl_removed (p_lcb->remote_bd_addr, p_lcb->transport);
+                /* Release any held buffers */
+                BT_HDR *p_buf;
+                while (!list_is_empty(p_lcb->link_xmit_data_q))
+                {
+                    p_buf = static_cast<BT_HDR *>(list_front(p_lcb->link_xmit_data_q));
+                    list_remove(p_lcb->link_xmit_data_q, p_buf);
+                    osi_free(p_buf);
+                }
+            }
+            else
+#endif
+       {
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+          /* If we are going to re-use the LCB without dropping it, release all fixed channels
+          here */
+          int xx;
+          for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++)
+          {
+              if (p_lcb->p_fixed_ccbs[xx] && p_lcb->p_fixed_ccbs[xx] != p_lcb->p_pending_ccb)
+              {
+#if (BLE_INCLUDED == TRUE)
+                  (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
+                          p_lcb->remote_bd_addr, false, p_lcb->disc_reason, p_lcb->transport);
+#else
+                  (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
+                          p_lcb->remote_bd_addr, false, p_lcb->disc_reason, BT_TRANSPORT_BR_EDR);
+#endif
+                    if (p_lcb->p_fixed_ccbs[xx] == NULL) {
+                      bdstr_t bd_addr_str = {0};
+                      L2CAP_TRACE_ERROR("%s: unexpected p_fixed_ccbs[%d] is NULL remote_bd_addr = %s p_lcb = %p in_use = %d link_state = %d handle = %d link_role = %d is_bonding = %d disc_reason = %d transport = %d",
+                                        __func__, xx,
+                                        bdaddr_to_string((bt_bdaddr_t *)&p_lcb->remote_bd_addr,
+                                                         bd_addr_str,
+                                                         sizeof(bd_addr_str)),
+                                        p_lcb, p_lcb->in_use,
+                                        p_lcb->link_state, p_lcb->handle,
+                                        p_lcb->link_role, p_lcb->is_bonding,
+                                        p_lcb->disc_reason, p_lcb->transport);
+                    }
+                    assert(p_lcb->p_fixed_ccbs[xx] != NULL);
+                    l2cu_release_ccb (p_lcb->p_fixed_ccbs[xx]);
+
+                    p_lcb->p_fixed_ccbs[xx] = NULL;
+              }
+          }
+#endif
+        }
+            if (l2cu_create_conn(p_lcb, transport))
+                lcb_is_free = false; /* still using this lcb */
+        }
+
+        p_lcb->p_pending_ccb = NULL;
+
+        /* Release the LCB */
+        if (lcb_is_free)
+            l2cu_release_lcb (p_lcb);
+    }
+
+    /* Now that we have a free acl connection, see if any lcbs are pending */
+    if (lcb_is_free && ((p_lcb = l2cu_find_lcb_by_state(LST_CONNECT_HOLDING)) != NULL))
+    {
+        /* we found one-- create a connection */
+        l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR);
+    }
+
+    return status;
+}
+
+
+/*******************************************************************************
+**
+** Function         l2c_link_hci_qos_violation
+**
+** Description      This function is called when an HCI QOS Violation
+**                  event is received.
+**
+** Returns          true if the link is known about, else false
+**
+*******************************************************************************/
+bool    l2c_link_hci_qos_violation (uint16_t handle)
+{
+    tL2C_LCB        *p_lcb;
+    tL2C_CCB        *p_ccb;
+
+    /* See if we have a link control block for the connection */
+    p_lcb = l2cu_find_lcb_by_handle (handle);
+
+    /* If we don't have one, maybe an SCO link. */
+    if (!p_lcb)
+        return (false);
+
+    /* For all channels, tell the upper layer about it */
+    for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
+    {
+        if (p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb)
+            l2c_csm_execute (p_ccb, L2CEVT_LP_QOS_VIOLATION_IND, NULL);
+    }
+
+    return (true);
+}
+
+
+
+/*******************************************************************************
+**
+** Function         l2c_link_timeout
+**
+** Description      This function is called when a link timer expires
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2c_link_timeout (tL2C_LCB *p_lcb)
+{
+    tL2C_CCB   *p_ccb;
+    tBTM_STATUS rc;
+
+     L2CAP_TRACE_EVENT ("L2CAP - l2c_link_timeout() link state %d first CCB %p is_bonding:%d",
+         p_lcb->link_state, p_lcb->ccb_queue.p_first_ccb, p_lcb->is_bonding);
+
+    /* If link was connecting or disconnecting, clear all channels and drop the LCB */
+    if ((p_lcb->link_state == LST_CONNECTING_WAIT_SWITCH) ||
+        (p_lcb->link_state == LST_CONNECTING) ||
+        (p_lcb->link_state == LST_CONNECT_HOLDING) ||
+        (p_lcb->link_state == LST_DISCONNECTING))
+    {
+        p_lcb->p_pending_ccb = NULL;
+
+        /* For all channels, send a disconnect indication event through */
+        /* their FSMs. The CCBs should remove themselves from the LCB   */
+        for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; )
+        {
+            tL2C_CCB *pn = p_ccb->p_next_ccb;
+
+            l2c_csm_execute (p_ccb, L2CEVT_LP_DISCONNECT_IND, NULL);
+
+            p_ccb = pn;
+        }
+#if (BLE_INCLUDED == TRUE)
+        if (p_lcb->link_state == LST_CONNECTING &&
+            l2cb.is_ble_connecting == true)
+        {
+            L2CA_CancelBleConnectReq(l2cb.ble_connecting_bda);
+        }
+#endif
+        /* Release the LCB */
+        l2cu_release_lcb (p_lcb);
+    }
+
+    /* If link is connected, check for inactivity timeout */
+    if (p_lcb->link_state == LST_CONNECTED)
+    {
+        /* Check for ping outstanding */
+        if (p_lcb->p_echo_rsp_cb)
+        {
+            tL2CA_ECHO_RSP_CB *p_cb = p_lcb->p_echo_rsp_cb;
+
+            /* Zero out the callback in case app immediately calls us again */
+            p_lcb->p_echo_rsp_cb = NULL;
+
+            (*p_cb) (L2CAP_PING_RESULT_NO_RESP);
+
+             L2CAP_TRACE_WARNING ("L2CAP - ping timeout");
+
+            /* For all channels, send a disconnect indication event through */
+            /* their FSMs. The CCBs should remove themselves from the LCB   */
+            for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; )
+            {
+                tL2C_CCB *pn = p_ccb->p_next_ccb;
+
+                l2c_csm_execute (p_ccb, L2CEVT_LP_DISCONNECT_IND, NULL);
+
+                p_ccb = pn;
+            }
+        }
+
+        /* If no channels in use, drop the link. */
+        if (!p_lcb->ccb_queue.p_first_ccb)
+        {
+            period_ms_t timeout_ms;
+            bool start_timeout = true;
+
+            rc = btm_sec_disconnect (p_lcb->handle, HCI_ERR_PEER_USER);
+
+            if (rc == BTM_CMD_STORED)
+            {
+                /* Security Manager will take care of disconnecting, state will be updated at that time */
+                start_timeout = false;
+            }
+            else if (rc == BTM_CMD_STARTED)
+            {
+                p_lcb->link_state = LST_DISCONNECTING;
+                timeout_ms = L2CAP_LINK_DISCONNECT_TIMEOUT_MS;
+            }
+            else if (rc == BTM_SUCCESS)
+            {
+                l2cu_process_fixed_disc_cback(p_lcb);
+                /* BTM SEC will make sure that link is release (probably after pairing is done) */
+                p_lcb->link_state = LST_DISCONNECTING;
+                start_timeout = false;
+            }
+            else if (rc == BTM_BUSY)
+            {
+                /* BTM is still executing security process. Let lcb stay as connected */
+                start_timeout = false;
+            }
+            else if (p_lcb->is_bonding)
+            {
+                btsnd_hcic_disconnect(p_lcb->handle, HCI_ERR_PEER_USER);
+                l2cu_process_fixed_disc_cback(p_lcb);
+                p_lcb->link_state = LST_DISCONNECTING;
+                timeout_ms = L2CAP_LINK_DISCONNECT_TIMEOUT_MS;
+            }
+            else
+            {
+                /* probably no buffer to send disconnect */
+                timeout_ms = BT_1SEC_TIMEOUT_MS;
+            }
+
+            if (start_timeout) {
+                alarm_set_on_queue(p_lcb->l2c_lcb_timer, timeout_ms,
+                                   l2c_lcb_timer_timeout, p_lcb,
+                                   btu_general_alarm_queue);
+            }
+        }
+        else
+        {
+            /* Check in case we were flow controlled */
+            l2c_link_check_send_pkts (p_lcb, NULL, NULL);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2c_info_resp_timer_timeout
+**
+** Description      This function is called when an info request times out
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2c_info_resp_timer_timeout(void *data)
+{
+    tL2C_LCB *p_lcb = (tL2C_LCB *)data;
+    tL2C_CCB   *p_ccb;
+    tL2C_CONN_INFO  ci;
+
+    /* If we timed out waiting for info response, just continue using basic if allowed */
+    if (p_lcb->w4_info_rsp)
+    {
+        /* If waiting for security complete, restart the info response timer */
+        for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
+        {
+            if ( (p_ccb->chnl_state == CST_ORIG_W4_SEC_COMP) || (p_ccb->chnl_state == CST_TERM_W4_SEC_COMP) )
+            {
+                alarm_set_on_queue(p_lcb->info_resp_timer,
+                                   L2CAP_WAIT_INFO_RSP_TIMEOUT_MS,
+                                   l2c_info_resp_timer_timeout, p_lcb,
+                                   btu_general_alarm_queue);
+                return;
+            }
+        }
+
+        p_lcb->w4_info_rsp = false;
+
+        /* If link is in process of being brought up */
+        if ((p_lcb->link_state != LST_DISCONNECTED) &&
+            (p_lcb->link_state != LST_DISCONNECTING))
+        {
+            /* Notify active channels that peer info is finished */
+            if (p_lcb->ccb_queue.p_first_ccb)
+            {
+                ci.status = HCI_SUCCESS;
+                memcpy (ci.bd_addr, p_lcb->remote_bd_addr, sizeof(BD_ADDR));
+
+                for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
+                {
+                    l2c_csm_execute (p_ccb, L2CEVT_L2CAP_INFO_RSP, &ci);
+                }
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2c_link_adjust_allocation
+**
+** Description      This function is called when a link is created or removed
+**                  to calculate the amount of packets each link may send to
+**                  the HCI without an ack coming back.
+**
+**                  Currently, this is a simple allocation, dividing the
+**                  number of Controller Packets by the number of links. In
+**                  the future, QOS configuration should be examined.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2c_link_adjust_allocation (void)
+{
+    uint16_t    qq, yy, qq_remainder;
+    tL2C_LCB    *p_lcb;
+    uint16_t    hi_quota, low_quota;
+    uint16_t    num_lowpri_links = 0;
+    uint16_t    num_hipri_links  = 0;
+    uint16_t    controller_xmit_quota = l2cb.num_lm_acl_bufs;
+    uint16_t    high_pri_link_quota = L2CAP_HIGH_PRI_MIN_XMIT_QUOTA_A;
+
+    /* If no links active, reset buffer quotas and controller buffers */
+    if (l2cb.num_links_active == 0)
+    {
+        l2cb.controller_xmit_window = l2cb.num_lm_acl_bufs;
+        l2cb.round_robin_quota = l2cb.round_robin_unacked = 0;
+        return;
+    }
+
+    /* First, count the links */
+    for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++)
+    {
+        if (p_lcb->in_use)
+        {
+            if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)
+                num_hipri_links++;
+            else
+                num_lowpri_links++;
+        }
+    }
+
+    /* now adjust high priority link quota */
+    low_quota = num_lowpri_links ? 1 : 0;
+    while ( (num_hipri_links * high_pri_link_quota + low_quota) > controller_xmit_quota )
+        high_pri_link_quota--;
+
+    /* Work out the xmit quota and buffer quota high and low priorities */
+    hi_quota  = num_hipri_links * high_pri_link_quota;
+    low_quota = (hi_quota < controller_xmit_quota) ? controller_xmit_quota - hi_quota : 1;
+
+    /* Work out and save the HCI xmit quota for each low priority link */
+
+    /* If each low priority link cannot have at least one buffer */
+    if (num_lowpri_links > low_quota)
+    {
+        l2cb.round_robin_quota = low_quota;
+        qq = qq_remainder = 1;
+    }
+    /* If each low priority link can have at least one buffer */
+    else if (num_lowpri_links > 0)
+    {
+        l2cb.round_robin_quota = 0;
+        l2cb.round_robin_unacked = 0;
+        qq = low_quota / num_lowpri_links;
+        qq_remainder = low_quota % num_lowpri_links;
+    }
+    /* If no low priority link */
+    else
+    {
+        l2cb.round_robin_quota = 0;
+        l2cb.round_robin_unacked = 0;
+        qq = qq_remainder = 1;
+    }
+
+    L2CAP_TRACE_EVENT ("l2c_link_adjust_allocation  num_hipri: %u  num_lowpri: %u  low_quota: %u  round_robin_quota: %u  qq: %u",
+                        num_hipri_links, num_lowpri_links, low_quota,
+                        l2cb.round_robin_quota, qq);
+
+    /* Now, assign the quotas to each link */
+    for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++)
+    {
+        if (p_lcb->in_use)
+        {
+            if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)
+            {
+                p_lcb->link_xmit_quota   = high_pri_link_quota;
+            }
+            else
+            {
+                /* Safety check in case we switched to round-robin with something outstanding */
+                /* if sent_not_acked is added into round_robin_unacked then don't add it again */
+                /* l2cap keeps updating sent_not_acked for exiting from round robin */
+                if (( p_lcb->link_xmit_quota > 0 )&&( qq == 0 ))
+                    l2cb.round_robin_unacked += p_lcb->sent_not_acked;
+
+                p_lcb->link_xmit_quota   = qq;
+                if (qq_remainder > 0)
+                {
+                    p_lcb->link_xmit_quota++;
+                    qq_remainder--;
+                }
+            }
+
+            L2CAP_TRACE_EVENT ("l2c_link_adjust_allocation LCB %d   Priority: %d  XmitQuota: %d",
+                                yy, p_lcb->acl_priority, p_lcb->link_xmit_quota);
+
+            L2CAP_TRACE_EVENT ("        SentNotAcked: %d  RRUnacked: %d",
+                                p_lcb->sent_not_acked, l2cb.round_robin_unacked);
+
+            /* There is a special case where we have readjusted the link quotas and  */
+            /* this link may have sent anything but some other link sent packets so  */
+            /* so we may need a timer to kick off this link's transmissions.         */
+            if ( (p_lcb->link_state == LST_CONNECTED)
+              && (!list_is_empty(p_lcb->link_xmit_data_q))
+                 && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota) ) {
+                alarm_set_on_queue(p_lcb->l2c_lcb_timer,
+                                   L2CAP_LINK_FLOW_CONTROL_TIMEOUT_MS,
+                                   l2c_lcb_timer_timeout, p_lcb,
+                                   btu_general_alarm_queue);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2c_link_adjust_chnl_allocation
+**
+** Description      This function is called to calculate the amount of packets each
+**                  non-F&EC channel may have outstanding.
+**
+**                  Currently, this is a simple allocation, dividing the number
+**                  of packets allocated to the link by the number of channels. In
+**                  the future, QOS configuration should be examined.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2c_link_adjust_chnl_allocation (void)
+{
+    uint8_t     xx;
+
+    L2CAP_TRACE_DEBUG("%s", __func__);
+
+    /* assign buffer quota to each channel based on its data rate requirement */
+    for (xx = 0; xx < MAX_L2CAP_CHANNELS; xx++)
+    {
+        tL2C_CCB *p_ccb = l2cb.ccb_pool + xx;
+
+        if (!p_ccb->in_use)
+            continue;
+
+        tL2CAP_CHNL_DATA_RATE data_rate = p_ccb->tx_data_rate + p_ccb->rx_data_rate;
+        p_ccb->buff_quota = L2CAP_CBB_DEFAULT_DATA_RATE_BUFF_QUOTA * data_rate;
+        L2CAP_TRACE_EVENT("CID:0x%04x FCR Mode:%u Priority:%u TxDataRate:%u RxDataRate:%u Quota:%u",
+                          p_ccb->local_cid, p_ccb->peer_cfg.fcr.mode,
+                          p_ccb->ccb_priority, p_ccb->tx_data_rate,
+                          p_ccb->rx_data_rate, p_ccb->buff_quota);
+
+        /* quota may be change so check congestion */
+        l2cu_check_channel_congestion(p_ccb);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2c_link_processs_num_bufs
+**
+** Description      This function is called when a "controller buffer size"
+**                  event is first received from the controller. It updates
+**                  the L2CAP values.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2c_link_processs_num_bufs (uint16_t num_lm_acl_bufs)
+{
+    l2cb.num_lm_acl_bufs = l2cb.controller_xmit_window = num_lm_acl_bufs;
+
+}
+
+/*******************************************************************************
+**
+** Function         l2c_link_pkts_rcvd
+**
+** Description      This function is called from the HCI transport when it is time
+**                  tto send a "Host ready for packets" command. This is only when
+**                  host to controller flow control is used. If fills in the arrays
+**                  of numbers of packets and handles.
+**
+** Returns          count of number of entries filled in
+**
+*******************************************************************************/
+uint8_t l2c_link_pkts_rcvd (UNUSED_ATTR uint16_t *num_pkts,
+                            UNUSED_ATTR uint16_t *handles)
+{
+    uint8_t     num_found = 0;
+
+    return (num_found);
+}
+
+/*******************************************************************************
+**
+** Function         l2c_link_role_changed
+**
+** Description      This function is called whan a link's master/slave role change
+**                  event is received. It simply updates the link control block.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2c_link_role_changed (BD_ADDR bd_addr, uint8_t new_role, uint8_t hci_status)
+{
+    tL2C_LCB *p_lcb;
+    int      xx;
+
+    /* Make sure not called from HCI Command Status (bd_addr and new_role are invalid) */
+    if (bd_addr)
+    {
+        /* If here came form hci role change event */
+        p_lcb = l2cu_find_lcb_by_bd_addr (bd_addr, BT_TRANSPORT_BR_EDR);
+        if (p_lcb)
+        {
+            p_lcb->link_role = new_role;
+
+            /* Reset high priority link if needed */
+            if (hci_status == HCI_SUCCESS)
+                l2cu_set_acl_priority(bd_addr, p_lcb->acl_priority, true);
+        }
+    }
+
+    /* Check if any LCB was waiting for switch to be completed */
+    for (xx = 0, p_lcb = &l2cb.lcb_pool[0]; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
+    {
+        if ((p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTING_WAIT_SWITCH))
+        {
+            l2cu_create_conn_after_switch (p_lcb);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2c_pin_code_request
+**
+** Description      This function is called whan a pin-code request is received
+**                  on a connection. If there are no channels active yet on the
+**                  link, it extends the link first connection timer.  Make sure
+**                  that inactivity timer is not extended if PIN code happens
+**                  to be after last ccb released.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2c_pin_code_request (BD_ADDR bd_addr)
+{
+    tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr (bd_addr, BT_TRANSPORT_BR_EDR);
+
+    if ( (p_lcb) && (!p_lcb->ccb_queue.p_first_ccb) )
+    {
+        alarm_set_on_queue(p_lcb->l2c_lcb_timer,
+                           L2CAP_LINK_CONNECT_EXT_TIMEOUT_MS,
+                           l2c_lcb_timer_timeout, p_lcb,
+                           btu_general_alarm_queue);
+    }
+}
+
+#if (L2CAP_WAKE_PARKED_LINK == TRUE)
+/*******************************************************************************
+**
+** Function         l2c_link_check_power_mode
+**
+** Description      This function is called to check power mode.
+**
+** Returns          true if link is going to be active from park
+**                  false if nothing to send or not in park mode
+**
+*******************************************************************************/
+bool    l2c_link_check_power_mode (tL2C_LCB *p_lcb)
+{
+    tBTM_PM_MODE     mode;
+    tL2C_CCB    *p_ccb;
+    bool    need_to_active = false;
+
+    /*
+     * We only switch park to active only if we have unsent packets
+     */
+    if (list_is_empty(p_lcb->link_xmit_data_q))
+    {
+        for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
+        {
+            if (!fixed_queue_is_empty(p_ccb->xmit_hold_q))
+            {
+                need_to_active = true;
+                break;
+            }
+        }
+    }
+    else
+        need_to_active = true;
+
+    /* if we have packets to send */
+    if ( need_to_active )
+    {
+        /* check power mode */
+        if (BTM_ReadPowerMode(p_lcb->remote_bd_addr, &mode) == BTM_SUCCESS)
+        {
+            if ( mode == BTM_PM_STS_PENDING )
+            {
+                L2CAP_TRACE_DEBUG ("LCB(0x%x) is in PM pending state", p_lcb->handle);
+
+                return true;
+            }
+        }
+    }
+    return false;
+}
+#endif /* L2CAP_WAKE_PARKED_LINK == TRUE) */
+
+/*******************************************************************************
+**
+** Function         l2c_link_check_send_pkts
+**
+** Description      This function is called to check if it can send packets
+**                  to the Host Controller. It may be passed the address of
+**                  a packet to send.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2c_link_check_send_pkts (tL2C_LCB *p_lcb, tL2C_CCB *p_ccb, BT_HDR *p_buf)
+{
+    int         xx;
+    bool        single_write = false;
+
+    /* Save the channel ID for faster counting */
+    if (p_buf)
+    {
+        if (p_ccb != NULL)
+        {
+            p_buf->event = p_ccb->local_cid;
+            single_write = true;
+        }
+        else
+            p_buf->event = 0;
+
+        p_buf->layer_specific = 0;
+        list_append(p_lcb->link_xmit_data_q, p_buf);
+
+        if (p_lcb->link_xmit_quota == 0)
+        {
+#if (BLE_INCLUDED == TRUE)
+            if (p_lcb->transport == BT_TRANSPORT_LE)
+                l2cb.ble_check_round_robin = true;
+            else
+#endif
+                l2cb.check_round_robin = true;
+        }
+    }
+
+    /* If this is called from uncongested callback context break recursive calling.
+    ** This LCB will be served when receiving number of completed packet event.
+    */
+    if (l2cb.is_cong_cback_context)
+        return;
+
+    /* If we are in a scenario where there are not enough buffers for each link to
+    ** have at least 1, then do a round-robin for all the LCBs
+    */
+    if ( (p_lcb == NULL) || (p_lcb->link_xmit_quota == 0) )
+    {
+        if (p_lcb == NULL)
+            p_lcb = l2cb.lcb_pool;
+        else if (!single_write)
+            p_lcb++;
+
+        /* Loop through, starting at the next */
+        for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
+        {
+            /* If controller window is full, nothing to do */
+            if (((l2cb.controller_xmit_window == 0 ||
+                  (l2cb.round_robin_unacked >= l2cb.round_robin_quota))
+#if (BLE_INCLUDED == TRUE)
+                && (p_lcb->transport == BT_TRANSPORT_BR_EDR)
+                )
+              || (p_lcb->transport == BT_TRANSPORT_LE &&
+                 (l2cb.ble_round_robin_unacked >= l2cb.ble_round_robin_quota ||
+                  l2cb.controller_le_xmit_window == 0 )))
+#else
+                ))
+#endif
+            break;
+
+
+            /* Check for wraparound */
+            if (p_lcb == &l2cb.lcb_pool[MAX_L2CAP_LINKS])
+                p_lcb = &l2cb.lcb_pool[0];
+
+            if ( (!p_lcb->in_use)
+               || (p_lcb->partial_segment_being_sent)
+               || (p_lcb->link_state != LST_CONNECTED)
+               || (p_lcb->link_xmit_quota != 0)
+               || (L2C_LINK_CHECK_POWER_MODE (p_lcb)) )
+                continue;
+
+            /* See if we can send anything from the Link Queue */
+            if (!list_is_empty(p_lcb->link_xmit_data_q)) {
+                p_buf = (BT_HDR *)list_front(p_lcb->link_xmit_data_q);
+                list_remove(p_lcb->link_xmit_data_q, p_buf);
+                l2c_link_send_to_lower (p_lcb, p_buf);
+            }
+            else if (single_write)
+            {
+                /* If only doing one write, break out */
+                break;
+            }
+            /* If nothing on the link queue, check the channel queue */
+            else if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb)) != NULL)
+            {
+                l2c_link_send_to_lower (p_lcb, p_buf);
+            }
+        }
+
+        /* If we finished without using up our quota, no need for a safety check */
+        if ( (l2cb.controller_xmit_window > 0)
+          && (l2cb.round_robin_unacked < l2cb.round_robin_quota)
+#if (BLE_INCLUDED == TRUE)
+          && (p_lcb->transport == BT_TRANSPORT_BR_EDR)
+#endif
+          )
+            l2cb.check_round_robin = false;
+
+#if (BLE_INCLUDED == TRUE)
+        if ( (l2cb.controller_le_xmit_window > 0)
+          && (l2cb.ble_round_robin_unacked < l2cb.ble_round_robin_quota)
+          && (p_lcb->transport == BT_TRANSPORT_LE))
+            l2cb.ble_check_round_robin = false;
+#endif
+    }
+    else /* if this is not round-robin service */
+    {
+        /* If a partial segment is being sent, can't send anything else */
+        if ( (p_lcb->partial_segment_being_sent)
+          || (p_lcb->link_state != LST_CONNECTED)
+          || (L2C_LINK_CHECK_POWER_MODE (p_lcb)) )
+            return;
+
+        /* See if we can send anything from the link queue */
+#if (BLE_INCLUDED == TRUE)
+        while ( ((l2cb.controller_xmit_window != 0 && (p_lcb->transport == BT_TRANSPORT_BR_EDR)) ||
+                 (l2cb.controller_le_xmit_window != 0 && (p_lcb->transport == BT_TRANSPORT_LE)))
+             && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
+#else
+        while ( (l2cb.controller_xmit_window != 0)
+             && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
+#endif
+        {
+            if (list_is_empty(p_lcb->link_xmit_data_q))
+                break;
+
+            p_buf = (BT_HDR *)list_front(p_lcb->link_xmit_data_q);
+            list_remove(p_lcb->link_xmit_data_q, p_buf);
+            if (!l2c_link_send_to_lower (p_lcb, p_buf))
+                break;
+        }
+
+        if (!single_write)
+        {
+            /* See if we can send anything for any channel */
+#if (BLE_INCLUDED == TRUE)
+            while ( ((l2cb.controller_xmit_window != 0 && (p_lcb->transport == BT_TRANSPORT_BR_EDR)) ||
+                    (l2cb.controller_le_xmit_window != 0 && (p_lcb->transport == BT_TRANSPORT_LE)))
+                    && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
+#else
+            while ((l2cb.controller_xmit_window != 0) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
+#endif
+            {
+                if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb)) == NULL)
+                    break;
+
+                if (!l2c_link_send_to_lower (p_lcb, p_buf))
+                    break;
+            }
+        }
+
+        /* There is a special case where we have readjusted the link quotas and  */
+        /* this link may have sent anything but some other link sent packets so  */
+        /* so we may need a timer to kick off this link's transmissions.         */
+        if ( (!list_is_empty(p_lcb->link_xmit_data_q)) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota) ) {
+            alarm_set_on_queue(p_lcb->l2c_lcb_timer,
+                               L2CAP_LINK_FLOW_CONTROL_TIMEOUT_MS,
+                               l2c_lcb_timer_timeout, p_lcb,
+                               btu_general_alarm_queue);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2c_link_send_to_lower
+**
+** Description      This function queues the buffer for HCI transmission
+**
+** Returns          true for success, false for fail
+**
+*******************************************************************************/
+static bool    l2c_link_send_to_lower (tL2C_LCB *p_lcb, BT_HDR *p_buf)
+{
+    uint16_t    num_segs;
+    uint16_t    xmit_window, acl_data_size;
+    const controller_t *controller = controller_get_interface();
+
+    if ((p_buf->len <= controller->get_acl_packet_size_classic()
+#if (BLE_INCLUDED == TRUE)
+        && (p_lcb->transport == BT_TRANSPORT_BR_EDR)) ||
+        ((p_lcb->transport == BT_TRANSPORT_LE) && (p_buf->len <= controller->get_acl_packet_size_ble()))
+#else
+        )
+#endif
+        )
+    {
+        if (p_lcb->link_xmit_quota == 0)
+        {
+#if (BLE_INCLUDED == TRUE)
+            if (p_lcb->transport == BT_TRANSPORT_LE)
+                l2cb.ble_round_robin_unacked++;
+            else
+#endif
+                l2cb.round_robin_unacked++;
+        }
+        p_lcb->sent_not_acked++;
+        p_buf->layer_specific = 0;
+
+#if (BLE_INCLUDED == TRUE)
+        if (p_lcb->transport == BT_TRANSPORT_LE)
+        {
+            l2cb.controller_le_xmit_window--;
+            bte_main_hci_send(p_buf, (uint16_t)(BT_EVT_TO_LM_HCI_ACL|LOCAL_BLE_CONTROLLER_ID));
+        }
+        else
+#endif
+        {
+            l2cb.controller_xmit_window--;
+            bte_main_hci_send(p_buf, BT_EVT_TO_LM_HCI_ACL);
+        }
+    }
+    else
+    {
+#if (BLE_INCLUDED == TRUE)
+        if (p_lcb->transport == BT_TRANSPORT_LE)
+        {
+            acl_data_size = controller->get_acl_data_size_ble();
+            xmit_window = l2cb.controller_le_xmit_window;
+
+        }
+        else
+#endif
+        {
+            acl_data_size = controller->get_acl_data_size_classic();
+            xmit_window = l2cb.controller_xmit_window;
+        }
+        num_segs = (p_buf->len - HCI_DATA_PREAMBLE_SIZE + acl_data_size - 1) / acl_data_size;
+
+
+        /* If doing round-robin, then only 1 segment each time */
+        if (p_lcb->link_xmit_quota == 0)
+        {
+            num_segs = 1;
+            p_lcb->partial_segment_being_sent = true;
+        }
+        else
+        {
+            /* Multi-segment packet. Make sure it can fit */
+            if (num_segs > xmit_window)
+            {
+                num_segs = xmit_window;
+                p_lcb->partial_segment_being_sent = true;
+            }
+
+            if (num_segs > (p_lcb->link_xmit_quota - p_lcb->sent_not_acked))
+            {
+                num_segs = (p_lcb->link_xmit_quota - p_lcb->sent_not_acked);
+                p_lcb->partial_segment_being_sent = true;
+            }
+        }
+
+        p_buf->layer_specific        = num_segs;
+#if (BLE_INCLUDED == TRUE)
+        if (p_lcb->transport == BT_TRANSPORT_LE)
+        {
+            l2cb.controller_le_xmit_window -= num_segs;
+            if (p_lcb->link_xmit_quota == 0)
+                l2cb.ble_round_robin_unacked += num_segs;
+        }
+        else
+#endif
+        {
+            l2cb.controller_xmit_window -= num_segs;
+
+            if (p_lcb->link_xmit_quota == 0)
+                l2cb.round_robin_unacked += num_segs;
+        }
+
+        p_lcb->sent_not_acked += num_segs;
+#if (BLE_INCLUDED == TRUE)
+        if (p_lcb->transport == BT_TRANSPORT_LE)
+        {
+            bte_main_hci_send(p_buf, (uint16_t)(BT_EVT_TO_LM_HCI_ACL|LOCAL_BLE_CONTROLLER_ID));
+        }
+        else
+#endif
+        {
+            bte_main_hci_send(p_buf, BT_EVT_TO_LM_HCI_ACL);
+        }
+    }
+
+#if (L2CAP_HCI_FLOW_CONTROL_DEBUG == TRUE)
+#if (BLE_INCLUDED == TRUE)
+    if (p_lcb->transport == BT_TRANSPORT_LE)
+    {
+        L2CAP_TRACE_DEBUG ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d",
+                l2cb.controller_le_xmit_window,
+                p_lcb->handle,
+                p_lcb->link_xmit_quota, p_lcb->sent_not_acked,
+                l2cb.ble_round_robin_quota, l2cb.ble_round_robin_unacked);
+    }
+    else
+#endif
+    {
+        L2CAP_TRACE_DEBUG ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d",
+                l2cb.controller_xmit_window,
+                p_lcb->handle,
+                p_lcb->link_xmit_quota, p_lcb->sent_not_acked,
+                l2cb.round_robin_quota, l2cb.round_robin_unacked);
+    }
+#endif
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         l2c_link_process_num_completed_pkts
+**
+** Description      This function is called when a "number-of-completed-packets"
+**                  event is received from the controller. It updates all the
+**                  LCB transmit counts.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2c_link_process_num_completed_pkts (uint8_t *p)
+{
+    uint8_t     num_handles, xx;
+    uint16_t    handle;
+    uint16_t    num_sent;
+    tL2C_LCB    *p_lcb;
+
+    STREAM_TO_UINT8 (num_handles, p);
+
+    for (xx = 0; xx < num_handles; xx++)
+    {
+        STREAM_TO_UINT16 (handle, p);
+        STREAM_TO_UINT16 (num_sent, p);
+
+        p_lcb = l2cu_find_lcb_by_handle (handle);
+
+        /* Callback for number of completed packet event    */
+        /* Originally designed for [3DSG]                   */
+        if((p_lcb != NULL) && (p_lcb->p_nocp_cb))
+        {
+            L2CAP_TRACE_DEBUG ("L2CAP - calling NoCP callback");
+            (*p_lcb->p_nocp_cb)(p_lcb->remote_bd_addr);
+        }
+
+        if (p_lcb)
+        {
+#if (BLE_INCLUDED == TRUE)
+        if (p_lcb && (p_lcb->transport == BT_TRANSPORT_LE))
+            l2cb.controller_le_xmit_window += num_sent;
+        else
+#endif
+            {
+                /* Maintain the total window to the controller */
+                l2cb.controller_xmit_window += num_sent;
+            }
+            /* If doing round-robin, adjust communal counts */
+            if (p_lcb->link_xmit_quota == 0)
+            {
+#if (BLE_INCLUDED == TRUE)
+                if (p_lcb->transport == BT_TRANSPORT_LE)
+                {
+                   /* Don't go negative */
+                    if (l2cb.ble_round_robin_unacked > num_sent)
+                        l2cb.ble_round_robin_unacked -= num_sent;
+                    else
+                        l2cb.ble_round_robin_unacked = 0;
+                }
+                else
+#endif
+                {
+                    /* Don't go negative */
+                    if (l2cb.round_robin_unacked > num_sent)
+                        l2cb.round_robin_unacked -= num_sent;
+                    else
+                        l2cb.round_robin_unacked = 0;
+                }
+            }
+
+            /* Don't go negative */
+            if (p_lcb->sent_not_acked > num_sent)
+                p_lcb->sent_not_acked -= num_sent;
+            else
+                p_lcb->sent_not_acked = 0;
+
+            l2c_link_check_send_pkts (p_lcb, NULL, NULL);
+
+            /* If we were doing round-robin for low priority links, check 'em */
+            if ( (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)
+              && (l2cb.check_round_robin)
+              && (l2cb.round_robin_unacked < l2cb.round_robin_quota) )
+            {
+              l2c_link_check_send_pkts (NULL, NULL, NULL);
+            }
+#if (BLE_INCLUDED == TRUE)
+            if ((p_lcb->transport == BT_TRANSPORT_LE)
+                && (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)
+                && ((l2cb.ble_check_round_robin)
+                && (l2cb.ble_round_robin_unacked < l2cb.ble_round_robin_quota)))
+            {
+              l2c_link_check_send_pkts (NULL, NULL, NULL);
+            }
+#endif
+        }
+
+#if (L2CAP_HCI_FLOW_CONTROL_DEBUG == TRUE)
+        if (p_lcb)
+        {
+#if (BLE_INCLUDED == TRUE)
+            if (p_lcb->transport == BT_TRANSPORT_LE)
+            {
+                L2CAP_TRACE_DEBUG ("TotalWin=%d,LinkUnack(0x%x)=%d,RRCheck=%d,RRUnack=%d",
+                    l2cb.controller_le_xmit_window,
+                    p_lcb->handle, p_lcb->sent_not_acked,
+                    l2cb.ble_check_round_robin, l2cb.ble_round_robin_unacked);
+            }
+            else
+#endif
+            {
+                L2CAP_TRACE_DEBUG ("TotalWin=%d,LinkUnack(0x%x)=%d,RRCheck=%d,RRUnack=%d",
+                    l2cb.controller_xmit_window,
+                    p_lcb->handle, p_lcb->sent_not_acked,
+                    l2cb.check_round_robin, l2cb.round_robin_unacked);
+
+            }
+        }
+        else
+        {
+#if (BLE_INCLUDED == TRUE)
+            L2CAP_TRACE_DEBUG ("TotalWin=%d  LE_Win: %d, Handle=0x%x, RRCheck=%d, RRUnack=%d",
+                l2cb.controller_xmit_window,
+                l2cb.controller_le_xmit_window,
+                handle,
+                l2cb.ble_check_round_robin, l2cb.ble_round_robin_unacked);
+#else
+            L2CAP_TRACE_DEBUG ("TotalWin=%d  Handle=0x%x  RRCheck=%d  RRUnack=%d",
+                l2cb.controller_xmit_window,
+                handle,
+                l2cb.check_round_robin, l2cb.round_robin_unacked);
+#endif
+        }
+#endif
+    }
+
+#if (HCILP_INCLUDED == TRUE)
+    /* only full stack can enable sleep mode */
+    btu_check_bt_sleep ();
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         l2c_link_segments_xmitted
+**
+** Description      This function is called from the HCI Interface when an ACL
+**                  data packet segment is transmitted.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2c_link_segments_xmitted (BT_HDR *p_msg)
+{
+    uint8_t     *p = (uint8_t *)(p_msg + 1) + p_msg->offset;
+    uint16_t    handle;
+    tL2C_LCB    *p_lcb;
+
+    /* Extract the handle */
+    STREAM_TO_UINT16 (handle, p);
+    handle   = HCID_GET_HANDLE (handle);
+
+    /* Find the LCB based on the handle */
+    if ((p_lcb = l2cu_find_lcb_by_handle (handle)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - rcvd segment complete, unknown handle: %d", handle);
+        osi_free(p_msg);
+        return;
+    }
+
+    if (p_lcb->link_state == LST_CONNECTED)
+    {
+        /* Enqueue the buffer to the head of the transmit queue, and see */
+        /* if we can transmit anything more.                             */
+        list_prepend(p_lcb->link_xmit_data_q, p_msg);
+
+        p_lcb->partial_segment_being_sent = false;
+
+        l2c_link_check_send_pkts (p_lcb, NULL, NULL);
+    }
+    else
+        osi_free(p_msg);
+}
diff --git a/bt/stack/l2cap/l2c_main.cc b/bt/stack/l2cap/l2c_main.cc
new file mode 100644
index 0000000..ffc94a7
--- /dev/null
+++ b/bt/stack/l2cap/l2c_main.cc
@@ -0,0 +1,953 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 main L2CAP entry points
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_l2c_main"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_target.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "bt_common.h"
+#include "hcimsgs.h"
+#include "l2c_api.h"
+#include "l2c_int.h"
+#include "l2cdefs.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+/********************************************************************************/
+/*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
+/********************************************************************************/
+static void process_l2cap_cmd (tL2C_LCB *p_lcb, uint8_t *p, uint16_t pkt_len);
+
+/********************************************************************************/
+/*                 G L O B A L      L 2 C A P       D A T A                     */
+/********************************************************************************/
+tL2C_CB l2cb;
+
+/*******************************************************************************
+**
+** Function         l2c_rcv_acl_data
+**
+** Description      This function is called from the HCI Interface when an ACL
+**                  data packet is received.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2c_rcv_acl_data (BT_HDR *p_msg)
+{
+    uint8_t     *p = (uint8_t *)(p_msg + 1) + p_msg->offset;
+    uint16_t    handle, hci_len;
+    uint8_t     pkt_type;
+    tL2C_LCB    *p_lcb;
+    tL2C_CCB    *p_ccb = NULL;
+    uint16_t    l2cap_len, rcv_cid, psm;
+    uint16_t    credit;
+
+    /* Extract the handle */
+    STREAM_TO_UINT16 (handle, p);
+    pkt_type = HCID_GET_EVENT (handle);
+    handle   = HCID_GET_HANDLE (handle);
+
+    /* Since the HCI Transport is putting segmented packets back together, we */
+    /* should never get a valid packet with the type set to "continuation"    */
+    if (pkt_type != L2CAP_PKT_CONTINUE)
+    {
+        /* Find the LCB based on the handle */
+        if ((p_lcb = l2cu_find_lcb_by_handle (handle)) == NULL)
+        {
+            uint8_t     cmd_code;
+
+            /* There is a slight possibility (specifically with USB) that we get an */
+            /* L2CAP connection request before we get the HCI connection complete.  */
+            /* So for these types of messages, hold them for up to 2 seconds.       */
+            STREAM_TO_UINT16 (hci_len, p);
+            STREAM_TO_UINT16 (l2cap_len, p);
+            STREAM_TO_UINT16 (rcv_cid, p);
+            STREAM_TO_UINT8  (cmd_code, p);
+
+            if ((p_msg->layer_specific == 0) && (rcv_cid == L2CAP_SIGNALLING_CID)
+                    && (cmd_code == L2CAP_CMD_INFO_REQ || cmd_code == L2CAP_CMD_CONN_REQ)) {
+                L2CAP_TRACE_WARNING ("L2CAP - holding ACL for unknown handle:%d ls:%d"
+                        "  cid:%d opcode:%d cur count:%d", handle, p_msg->layer_specific,
+                        rcv_cid, cmd_code, list_length(l2cb.rcv_pending_q));
+                p_msg->layer_specific = 2;
+                list_append(l2cb.rcv_pending_q, p_msg);
+
+                if (list_length(l2cb.rcv_pending_q) == 1) {
+                    alarm_set_on_queue(l2cb.receive_hold_timer,
+                                       BT_1SEC_TIMEOUT_MS,
+                                       l2c_receive_hold_timer_timeout, NULL,
+                                       btu_general_alarm_queue);
+                }
+
+                return;
+            } else {
+                L2CAP_TRACE_ERROR ("L2CAP - rcvd ACL for unknown handle:%d ls:%d cid:%d"
+                        " opcode:%d cur count:%d", handle, p_msg->layer_specific, rcv_cid,
+                        cmd_code, list_length(l2cb.rcv_pending_q));
+            }
+            osi_free(p_msg);
+            return;
+        }
+    }
+    else
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - expected pkt start or complete, got: %d", pkt_type);
+        osi_free(p_msg);
+        return;
+    }
+
+    /* Extract the length and update the buffer header */
+    STREAM_TO_UINT16 (hci_len, p);
+    p_msg->offset += 4;
+
+    /* Extract the length and CID */
+    STREAM_TO_UINT16 (l2cap_len, p);
+    STREAM_TO_UINT16 (rcv_cid, p);
+
+#if (BLE_INCLUDED == TRUE)
+   /* for BLE channel, always notify connection when ACL data received on the link */
+   if (p_lcb && p_lcb->transport == BT_TRANSPORT_LE && p_lcb->link_state != LST_DISCONNECTING)
+      /* only process fixed channel data as channel open indication when link is not in disconnecting mode */
+        l2cble_notify_le_connection(p_lcb->remote_bd_addr);
+#endif
+
+    /* Find the CCB for this CID */
+    if (rcv_cid >= L2CAP_BASE_APPL_CID)
+    {
+        if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, rcv_cid)) == NULL)
+        {
+            L2CAP_TRACE_WARNING ("L2CAP - unknown CID: 0x%04x", rcv_cid);
+            osi_free(p_msg);
+            return;
+        }
+    }
+
+    if (hci_len >= L2CAP_PKT_OVERHEAD)  /* Must receive at least the L2CAP length and CID.*/
+    {
+        p_msg->len    = hci_len - L2CAP_PKT_OVERHEAD;
+        p_msg->offset += L2CAP_PKT_OVERHEAD;
+    }
+    else
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - got incorrect hci header" );
+        osi_free(p_msg);
+        return;
+    }
+
+    if (l2cap_len != p_msg->len)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - bad length in pkt. Exp: %d  Act: %d",
+                              l2cap_len, p_msg->len);
+
+        osi_free(p_msg);
+        return;
+    }
+
+    /* Send the data through the channel state machine */
+    if (rcv_cid == L2CAP_SIGNALLING_CID)
+    {
+        process_l2cap_cmd (p_lcb, p, l2cap_len);
+        osi_free(p_msg);
+    }
+    else if (rcv_cid == L2CAP_CONNECTIONLESS_CID)
+    {
+        /* process_connectionless_data (p_lcb); */
+        STREAM_TO_UINT16 (psm, p);
+        L2CAP_TRACE_DEBUG( "GOT CONNECTIONLESS DATA PSM:%d", psm ) ;
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+        /* if it is not broadcast, check UCD registration */
+        if ( l2c_ucd_check_rx_pkts( p_lcb, p_msg ) )
+        {
+            /* nothing to do */
+        }
+        else
+#endif
+            osi_free(p_msg);
+    }
+#if (BLE_INCLUDED == TRUE)
+    else if (rcv_cid == L2CAP_BLE_SIGNALLING_CID)
+    {
+        l2cble_process_sig_cmd (p_lcb, p, l2cap_len);
+        osi_free(p_msg);
+    }
+#endif
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+    else if ((rcv_cid >= L2CAP_FIRST_FIXED_CHNL) && (rcv_cid <= L2CAP_LAST_FIXED_CHNL) &&
+             (l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb != NULL) )
+    {
+        /* If no CCB for this channel, allocate one */
+        if (p_lcb &&
+            /* only process fixed channel data when link is open or wait for data indication */
+            (p_lcb->link_state != LST_DISCONNECTING) &&
+            l2cu_initialize_fixed_ccb (p_lcb, rcv_cid, &l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
+        {
+            p_ccb = p_lcb->p_fixed_ccbs[rcv_cid - L2CAP_FIRST_FIXED_CHNL];
+
+            if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
+                l2c_fcr_proc_pdu (p_ccb, p_msg);
+            else
+                (*l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)
+                    (rcv_cid, p_lcb->remote_bd_addr, p_msg);
+        }
+        else
+            osi_free(p_msg);
+    }
+#endif
+
+    else
+    {
+        if (p_ccb == NULL)
+            osi_free(p_msg);
+        else
+        {
+            if (p_lcb->transport == BT_TRANSPORT_LE)
+            {
+               l2c_lcc_proc_pdu(p_ccb,p_msg);
+               // Got a pkt, valid send out credits to the peer device
+               credit = L2CAP_LE_DEFAULT_CREDIT;
+               l2c_csm_execute(p_ccb, L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT, &credit);
+            }
+            else
+            {
+                /* Basic mode packets go straight to the state machine */
+                if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)
+                    l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DATA, p_msg);
+                else
+                {
+                    /* eRTM or streaming mode, so we need to validate states first */
+                    if ((p_ccb->chnl_state == CST_OPEN) || (p_ccb->chnl_state == CST_CONFIG))
+                        l2c_fcr_proc_pdu (p_ccb, p_msg);
+                    else
+                        osi_free (p_msg);
+                }
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         process_l2cap_cmd
+**
+** Description      This function is called when a packet is received on the
+**                  L2CAP signalling CID
+**
+** Returns          void
+**
+*******************************************************************************/
+static void process_l2cap_cmd (tL2C_LCB *p_lcb, uint8_t *p, uint16_t pkt_len)
+{
+    uint8_t         *p_pkt_end, *p_next_cmd, *p_cfg_end, *p_cfg_start;
+    uint8_t         cmd_code, cfg_code, cfg_len, id;
+    tL2C_CONN_INFO  con_info;
+    tL2CAP_CFG_INFO cfg_info;
+    uint16_t        rej_reason, rej_mtu, lcid, rcid, info_type;
+    tL2C_CCB        *p_ccb;
+    tL2C_RCB        *p_rcb;
+    bool            cfg_rej, pkt_size_rej = false;
+    uint16_t        cfg_rej_len, cmd_len;
+    uint16_t        result;
+    tL2C_CONN_INFO  ci;
+
+#if (BLE_INCLUDED == TRUE)
+    /* if l2cap command received in CID 1 on top of an LE link, ignore this command */
+    if (p_lcb->transport == BT_TRANSPORT_LE)
+        return;
+#endif
+
+    /* Reject the packet if it exceeds the default Signalling Channel MTU */
+    if (pkt_len > L2CAP_DEFAULT_MTU)
+    {
+        /* Core Spec requires a single response to the first command found in a multi-command
+        ** L2cap packet.  If only responses in the packet, then it will be ignored.
+        ** Here we simply mark the bad packet and decide which cmd ID to reject later
+        */
+        pkt_size_rej = true;
+        L2CAP_TRACE_ERROR ("L2CAP SIG MTU Pkt Len Exceeded (672) -> pkt_len: %d", pkt_len);
+    }
+
+    p_next_cmd = p;
+    p_pkt_end  = p + pkt_len;
+
+    memset (&cfg_info, 0, sizeof(cfg_info));
+
+    /* An L2CAP packet may contain multiple commands */
+    while (true)
+    {
+        /* Smallest command is 4 bytes */
+        if ((p = p_next_cmd) > (p_pkt_end - 4))
+            break;
+
+        STREAM_TO_UINT8  (cmd_code, p);
+        STREAM_TO_UINT8  (id, p);
+        STREAM_TO_UINT16 (cmd_len, p);
+
+        /* Check command length does not exceed packet length */
+        if ((p_next_cmd = p + cmd_len) > p_pkt_end)
+        {
+            L2CAP_TRACE_WARNING ("Command len bad  pkt_len: %d  cmd_len: %d  code: %d",
+                                  pkt_len, cmd_len, cmd_code);
+            break;
+        }
+
+        L2CAP_TRACE_DEBUG ("cmd_code: %d, id:%d, cmd_len:%d", cmd_code, id, cmd_len);
+
+        /* Bad L2CAP packet length, look or cmd to reject */
+        if (pkt_size_rej)
+        {
+            /* If command found rejected it and we're done, otherwise keep looking */
+            if (l2c_is_cmd_rejected(cmd_code, id, p_lcb))
+                return;
+            else
+                continue; /* Look for next cmd/response in current packet */
+        }
+
+        switch (cmd_code)
+        {
+        case L2CAP_CMD_REJECT:
+            STREAM_TO_UINT16 (rej_reason, p);
+            if (rej_reason == L2CAP_CMD_REJ_MTU_EXCEEDED)
+            {
+                STREAM_TO_UINT16 (rej_mtu, p);
+                /* What to do with the MTU reject ? We have negotiated an MTU. For now */
+                /* we will ignore it and let a higher protocol timeout take care of it */
+
+                L2CAP_TRACE_WARNING ("L2CAP - MTU rej Handle: %d MTU: %d", p_lcb->handle, rej_mtu);
+            }
+            if (rej_reason == L2CAP_CMD_REJ_INVALID_CID)
+            {
+                STREAM_TO_UINT16 (rcid, p);
+                STREAM_TO_UINT16 (lcid, p);
+
+                L2CAP_TRACE_WARNING ("L2CAP - rej with CID invalid, LCID: 0x%04x RCID: 0x%04x", lcid, rcid);
+
+                /* Remote CID invalid. Treat as a disconnect */
+                if (((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL)
+                 && (p_ccb->remote_cid == rcid))
+                {
+                    /* Fake link disconnect - no reply is generated */
+                    l2c_csm_execute (p_ccb, L2CEVT_LP_DISCONNECT_IND, NULL);
+                }
+            }
+
+            /* SonyEricsson Info request Bug workaround (Continue connection) */
+            else if (rej_reason == L2CAP_CMD_REJ_NOT_UNDERSTOOD && p_lcb->w4_info_rsp)
+            {
+                alarm_cancel(p_lcb->info_resp_timer);
+
+                p_lcb->w4_info_rsp = false;
+                ci.status = HCI_SUCCESS;
+                memcpy (ci.bd_addr, p_lcb->remote_bd_addr, sizeof(BD_ADDR));
+
+                /* For all channels, send the event through their FSMs */
+                for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
+                {
+                    l2c_csm_execute (p_ccb, L2CEVT_L2CAP_INFO_RSP, &ci);
+                }
+            }
+            break;
+
+        case L2CAP_CMD_CONN_REQ:
+            STREAM_TO_UINT16 (con_info.psm, p);
+            STREAM_TO_UINT16 (rcid, p);
+            if ((p_rcb = l2cu_find_rcb_by_psm (con_info.psm)) == NULL)
+            {
+                L2CAP_TRACE_WARNING ("L2CAP - rcvd conn req for unknown PSM: %d", con_info.psm);
+                l2cu_reject_connection (p_lcb, rcid, id, L2CAP_CONN_NO_PSM);
+                break;
+            }
+            else
+            {
+                if (!p_rcb->api.pL2CA_ConnectInd_Cb)
+                {
+                    L2CAP_TRACE_WARNING ("L2CAP - rcvd conn req for outgoing-only connection PSM: %d", con_info.psm);
+                    l2cu_reject_connection (p_lcb, rcid, id, L2CAP_CONN_NO_PSM);
+                    break;
+                }
+            }
+            if ((p_ccb = l2cu_allocate_ccb (p_lcb, 0)) == NULL)
+            {
+                L2CAP_TRACE_ERROR ("L2CAP - unable to allocate CCB");
+                l2cu_reject_connection (p_lcb, rcid, id, L2CAP_CONN_NO_RESOURCES);
+                break;
+            }
+            p_ccb->remote_id = id;
+            p_ccb->p_rcb = p_rcb;
+            p_ccb->remote_cid = rcid;
+
+            l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_REQ, &con_info);
+            break;
+
+        case L2CAP_CMD_CONN_RSP:
+            STREAM_TO_UINT16 (con_info.remote_cid, p);
+            STREAM_TO_UINT16 (lcid, p);
+            STREAM_TO_UINT16 (con_info.l2cap_result, p);
+            STREAM_TO_UINT16 (con_info.l2cap_status, p);
+
+            if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) == NULL)
+            {
+                L2CAP_TRACE_WARNING ("L2CAP - no CCB for conn rsp, LCID: %d RCID: %d",
+                                      lcid, con_info.remote_cid);
+                break;
+            }
+            if (p_ccb->local_id != id)
+            {
+                L2CAP_TRACE_WARNING ("L2CAP - con rsp - bad ID. Exp: %d Got: %d",
+                                      p_ccb->local_id, id);
+                break;
+            }
+
+            if (con_info.l2cap_result == L2CAP_CONN_OK)
+                l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP, &con_info);
+            else if (con_info.l2cap_result == L2CAP_CONN_PENDING)
+                l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_PND, &con_info);
+            else
+                l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info);
+
+            break;
+
+        case L2CAP_CMD_CONFIG_REQ:
+            p_cfg_end = p + cmd_len;
+            cfg_rej = false;
+            cfg_rej_len = 0;
+
+            STREAM_TO_UINT16 (lcid, p);
+            STREAM_TO_UINT16 (cfg_info.flags, p);
+
+            p_cfg_start = p;
+
+            cfg_info.flush_to_present = cfg_info.mtu_present = cfg_info.qos_present =
+                cfg_info.fcr_present = cfg_info.fcs_present = false;
+
+            while (p < p_cfg_end)
+            {
+                STREAM_TO_UINT8 (cfg_code, p);
+                STREAM_TO_UINT8 (cfg_len, p);
+
+                switch (cfg_code & 0x7F)
+                {
+                case L2CAP_CFG_TYPE_MTU:
+                    cfg_info.mtu_present = true;
+                    STREAM_TO_UINT16 (cfg_info.mtu, p);
+                    break;
+
+                case L2CAP_CFG_TYPE_FLUSH_TOUT:
+                    cfg_info.flush_to_present = true;
+                    STREAM_TO_UINT16 (cfg_info.flush_to, p);
+                    break;
+
+                case L2CAP_CFG_TYPE_QOS:
+                    cfg_info.qos_present = true;
+                    STREAM_TO_UINT8  (cfg_info.qos.qos_flags, p);
+                    STREAM_TO_UINT8  (cfg_info.qos.service_type, p);
+                    STREAM_TO_UINT32 (cfg_info.qos.token_rate, p);
+                    STREAM_TO_UINT32 (cfg_info.qos.token_bucket_size, p);
+                    STREAM_TO_UINT32 (cfg_info.qos.peak_bandwidth, p);
+                    STREAM_TO_UINT32 (cfg_info.qos.latency, p);
+                    STREAM_TO_UINT32 (cfg_info.qos.delay_variation, p);
+                    break;
+
+                case L2CAP_CFG_TYPE_FCR:
+                    cfg_info.fcr_present = true;
+                    STREAM_TO_UINT8 (cfg_info.fcr.mode, p);
+                    STREAM_TO_UINT8 (cfg_info.fcr.tx_win_sz, p);
+                    STREAM_TO_UINT8 (cfg_info.fcr.max_transmit, p);
+                    STREAM_TO_UINT16 (cfg_info.fcr.rtrans_tout, p);
+                    STREAM_TO_UINT16 (cfg_info.fcr.mon_tout, p);
+                    STREAM_TO_UINT16 (cfg_info.fcr.mps, p);
+                    break;
+
+                case L2CAP_CFG_TYPE_FCS:
+                    cfg_info.fcs_present = true;
+                    STREAM_TO_UINT8 (cfg_info.fcs, p);
+                    break;
+
+                case L2CAP_CFG_TYPE_EXT_FLOW:
+                    cfg_info.ext_flow_spec_present = true;
+                    STREAM_TO_UINT8  (cfg_info.ext_flow_spec.id, p);
+                    STREAM_TO_UINT8  (cfg_info.ext_flow_spec.stype, p);
+                    STREAM_TO_UINT16 (cfg_info.ext_flow_spec.max_sdu_size, p);
+                    STREAM_TO_UINT32 (cfg_info.ext_flow_spec.sdu_inter_time, p);
+                    STREAM_TO_UINT32 (cfg_info.ext_flow_spec.access_latency, p);
+                    STREAM_TO_UINT32 (cfg_info.ext_flow_spec.flush_timeout, p);
+                    break;
+
+                default:
+                    /* sanity check option length */
+                    if ((cfg_len + L2CAP_CFG_OPTION_OVERHEAD) <= cmd_len)
+                    {
+                        p += cfg_len;
+                        if ((cfg_code & 0x80) == 0)
+                        {
+                            cfg_rej_len += cfg_len + L2CAP_CFG_OPTION_OVERHEAD;
+                            cfg_rej = true;
+                        }
+                    }
+                    /* bad length; force loop exit */
+                    else
+                    {
+                        p = p_cfg_end;
+                        cfg_rej = true;
+                    }
+                    break;
+                }
+            }
+
+            if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL)
+            {
+                p_ccb->remote_id = id;
+                if (cfg_rej)
+                {
+                    l2cu_send_peer_config_rej (p_ccb, p_cfg_start, (uint16_t) (cmd_len - L2CAP_CONFIG_REQ_LEN), cfg_rej_len);
+                }
+                else
+                {
+                    l2c_csm_execute (p_ccb, L2CEVT_L2CAP_CONFIG_REQ, &cfg_info);
+                }
+            }
+            else
+            {
+                /* updated spec says send command reject on invalid cid */
+                l2cu_send_peer_cmd_reject (p_lcb, L2CAP_CMD_REJ_INVALID_CID, id, 0, 0);
+            }
+            break;
+
+        case L2CAP_CMD_CONFIG_RSP:
+            p_cfg_end = p + cmd_len;
+            STREAM_TO_UINT16 (lcid, p);
+            STREAM_TO_UINT16 (cfg_info.flags, p);
+            STREAM_TO_UINT16 (cfg_info.result, p);
+
+            cfg_info.flush_to_present = cfg_info.mtu_present = cfg_info.qos_present =
+                cfg_info.fcr_present = cfg_info.fcs_present = false;
+
+            while (p < p_cfg_end)
+            {
+                STREAM_TO_UINT8 (cfg_code, p);
+                STREAM_TO_UINT8 (cfg_len, p);
+
+                switch (cfg_code & 0x7F)
+                {
+                case L2CAP_CFG_TYPE_MTU:
+                    cfg_info.mtu_present = true;
+                    STREAM_TO_UINT16 (cfg_info.mtu, p);
+                    break;
+
+                case L2CAP_CFG_TYPE_FLUSH_TOUT:
+                    cfg_info.flush_to_present = true;
+                    STREAM_TO_UINT16 (cfg_info.flush_to, p);
+                    break;
+
+                case L2CAP_CFG_TYPE_QOS:
+                    cfg_info.qos_present = true;
+                    STREAM_TO_UINT8  (cfg_info.qos.qos_flags, p);
+                    STREAM_TO_UINT8  (cfg_info.qos.service_type, p);
+                    STREAM_TO_UINT32 (cfg_info.qos.token_rate, p);
+                    STREAM_TO_UINT32 (cfg_info.qos.token_bucket_size, p);
+                    STREAM_TO_UINT32 (cfg_info.qos.peak_bandwidth, p);
+                    STREAM_TO_UINT32 (cfg_info.qos.latency, p);
+                    STREAM_TO_UINT32 (cfg_info.qos.delay_variation, p);
+                    break;
+
+                case L2CAP_CFG_TYPE_FCR:
+                    cfg_info.fcr_present = true;
+                    STREAM_TO_UINT8 (cfg_info.fcr.mode, p);
+                    STREAM_TO_UINT8 (cfg_info.fcr.tx_win_sz, p);
+                    STREAM_TO_UINT8 (cfg_info.fcr.max_transmit, p);
+                    STREAM_TO_UINT16 (cfg_info.fcr.rtrans_tout, p);
+                    STREAM_TO_UINT16 (cfg_info.fcr.mon_tout, p);
+                    STREAM_TO_UINT16 (cfg_info.fcr.mps, p);
+                    break;
+
+                case L2CAP_CFG_TYPE_FCS:
+                    cfg_info.fcs_present = true;
+                    STREAM_TO_UINT8 (cfg_info.fcs, p);
+                    break;
+
+                case L2CAP_CFG_TYPE_EXT_FLOW:
+                    cfg_info.ext_flow_spec_present = true;
+                    STREAM_TO_UINT8  (cfg_info.ext_flow_spec.id, p);
+                    STREAM_TO_UINT8  (cfg_info.ext_flow_spec.stype, p);
+                    STREAM_TO_UINT16 (cfg_info.ext_flow_spec.max_sdu_size, p);
+                    STREAM_TO_UINT32 (cfg_info.ext_flow_spec.sdu_inter_time, p);
+                    STREAM_TO_UINT32 (cfg_info.ext_flow_spec.access_latency, p);
+                    STREAM_TO_UINT32 (cfg_info.ext_flow_spec.flush_timeout, p);
+                    break;
+                }
+            }
+
+            if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL)
+            {
+                if (p_ccb->local_id != id)
+                {
+                    L2CAP_TRACE_WARNING ("L2CAP - cfg rsp - bad ID. Exp: %d Got: %d",
+                                          p_ccb->local_id, id);
+                    break;
+                }
+                if ( (cfg_info.result == L2CAP_CFG_OK) || (cfg_info.result == L2CAP_CFG_PENDING) )
+                    l2c_csm_execute (p_ccb, L2CEVT_L2CAP_CONFIG_RSP, &cfg_info);
+                else
+                    l2c_csm_execute (p_ccb, L2CEVT_L2CAP_CONFIG_RSP_NEG, &cfg_info);
+            }
+            else
+            {
+                L2CAP_TRACE_WARNING ("L2CAP - rcvd cfg rsp for unknown CID: 0x%04x", lcid);
+            }
+            break;
+
+        case L2CAP_CMD_DISC_REQ:
+            STREAM_TO_UINT16 (lcid, p);
+            STREAM_TO_UINT16 (rcid, p);
+
+            if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL)
+            {
+                if (p_ccb->remote_cid == rcid)
+                {
+                    p_ccb->remote_id = id;
+                    l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DISCONNECT_REQ, &con_info);
+                }
+            }
+            else
+                l2cu_send_peer_disc_rsp (p_lcb, id, lcid, rcid);
+
+            break;
+
+        case L2CAP_CMD_DISC_RSP:
+            STREAM_TO_UINT16 (rcid, p);
+            STREAM_TO_UINT16 (lcid, p);
+
+            if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, lcid)) != NULL)
+            {
+                if ((p_ccb->remote_cid == rcid) && (p_ccb->local_id == id))
+                {
+                    l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DISCONNECT_RSP, &con_info);
+                }
+            }
+            break;
+
+        case L2CAP_CMD_ECHO_REQ:
+            l2cu_send_peer_echo_rsp (p_lcb, id, NULL, 0);
+            break;
+
+        case L2CAP_CMD_ECHO_RSP:
+            if (p_lcb->p_echo_rsp_cb)
+            {
+                tL2CA_ECHO_RSP_CB *p_cb = p_lcb->p_echo_rsp_cb;
+
+                /* Zero out the callback in case app immediately calls us again */
+                p_lcb->p_echo_rsp_cb = NULL;
+
+                (*p_cb) (L2CAP_PING_RESULT_OK);
+            }
+            break;
+
+        case L2CAP_CMD_INFO_REQ:
+            STREAM_TO_UINT16 (info_type, p);
+            l2cu_send_peer_info_rsp (p_lcb, id, info_type);
+            break;
+
+        case L2CAP_CMD_INFO_RSP:
+            /* Stop the link connect timer if sent before L2CAP connection is up */
+            if (p_lcb->w4_info_rsp)
+            {
+                alarm_cancel(p_lcb->info_resp_timer);
+                p_lcb->w4_info_rsp = false;
+            }
+
+            STREAM_TO_UINT16 (info_type, p);
+            STREAM_TO_UINT16 (result, p);
+
+            p_lcb->info_rx_bits |= (1 << info_type);
+
+            if ( (info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE)
+              && (result == L2CAP_INFO_RESP_RESULT_SUCCESS) )
+            {
+                STREAM_TO_UINT32( p_lcb->peer_ext_fea, p );
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+                if (p_lcb->peer_ext_fea & L2CAP_EXTFEA_FIXED_CHNLS)
+                {
+                    l2cu_send_peer_info_req (p_lcb, L2CAP_FIXED_CHANNELS_INFO_TYPE);
+                    break;
+                }
+                else
+                {
+                    l2cu_process_fixed_chnl_resp (p_lcb);
+                }
+#endif
+            }
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+            if (info_type == L2CAP_FIXED_CHANNELS_INFO_TYPE)
+            {
+                if (result == L2CAP_INFO_RESP_RESULT_SUCCESS)
+                {
+                    memcpy (p_lcb->peer_chnl_mask, p, L2CAP_FIXED_CHNL_ARRAY_SIZE);
+                }
+
+                l2cu_process_fixed_chnl_resp (p_lcb);
+            }
+#endif
+#if (L2CAP_UCD_INCLUDED == TRUE)
+            else if (info_type == L2CAP_CONNLESS_MTU_INFO_TYPE)
+            {
+                if (result == L2CAP_INFO_RESP_RESULT_SUCCESS)
+                {
+                    STREAM_TO_UINT16 (p_lcb->ucd_mtu, p);
+                }
+            }
+#endif
+
+            ci.status = HCI_SUCCESS;
+            memcpy (ci.bd_addr, p_lcb->remote_bd_addr, sizeof(BD_ADDR));
+            for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
+            {
+                l2c_csm_execute (p_ccb, L2CEVT_L2CAP_INFO_RSP, &ci);
+            }
+            break;
+
+        default:
+            L2CAP_TRACE_WARNING ("L2CAP - bad cmd code: %d", cmd_code);
+            l2cu_send_peer_cmd_reject (p_lcb, L2CAP_CMD_REJ_NOT_UNDERSTOOD, id, 0, 0);
+            return;
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2c_process_held_packets
+**
+** Description      This function processes any L2CAP packets that arrived before
+**                  the HCI connection complete arrived. It is a work around for
+**                  badly behaved controllers.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2c_process_held_packets(bool    timed_out) {
+    if (list_is_empty(l2cb.rcv_pending_q))
+        return;
+
+    if (!timed_out) {
+        alarm_cancel(l2cb.receive_hold_timer);
+        L2CAP_TRACE_WARNING("L2CAP HOLD CONTINUE");
+    } else {
+        L2CAP_TRACE_WARNING("L2CAP HOLD TIMEOUT");
+    }
+
+    for (const list_node_t *node = list_begin(l2cb.rcv_pending_q);
+        node != list_end(l2cb.rcv_pending_q);)  {
+        BT_HDR *p_buf = static_cast<BT_HDR *>(list_node(node));
+        node = list_next(node);
+        if (!timed_out || (!p_buf->layer_specific) || (--p_buf->layer_specific == 0)) {
+            list_remove(l2cb.rcv_pending_q, p_buf);
+            p_buf->layer_specific = 0xFFFF;
+            l2c_rcv_acl_data(p_buf);
+        }
+    }
+
+    /* If anyone still in the queue, restart the timeout */
+    if (!list_is_empty(l2cb.rcv_pending_q)) {
+        alarm_set_on_queue(l2cb.receive_hold_timer, BT_1SEC_TIMEOUT_MS,
+                           l2c_receive_hold_timer_timeout, NULL,
+                           btu_general_alarm_queue);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2c_init
+**
+** Description      This function is called once at startup to initialize
+**                  all the L2CAP structures
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2c_init (void)
+{
+    int16_t xx;
+
+    memset (&l2cb, 0, sizeof (tL2C_CB));
+    /* the psm is increased by 2 before being used */
+    l2cb.dyn_psm = 0xFFF;
+
+    /* Put all the channel control blocks on the free queue */
+    for (xx = 0; xx < MAX_L2CAP_CHANNELS - 1; xx++)
+    {
+        l2cb.ccb_pool[xx].p_next_ccb = &l2cb.ccb_pool[xx + 1];
+    }
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+    /* it will be set to L2CAP_PKT_START_NON_FLUSHABLE if controller supports */
+    l2cb.non_flushable_pbf = L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT;
+#endif
+
+    l2cb.p_free_ccb_first = &l2cb.ccb_pool[0];
+    l2cb.p_free_ccb_last  = &l2cb.ccb_pool[MAX_L2CAP_CHANNELS - 1];
+
+#ifdef L2CAP_DESIRED_LINK_ROLE
+    l2cb.desire_role      = L2CAP_DESIRED_LINK_ROLE;
+#else
+    l2cb.desire_role      = HCI_ROLE_SLAVE;
+#endif
+
+    /* Set the default idle timeout */
+    l2cb.idle_timeout = L2CAP_LINK_INACTIVITY_TOUT;
+
+#if defined(L2CAP_INITIAL_TRACE_LEVEL)
+    l2cb.l2cap_trace_level = L2CAP_INITIAL_TRACE_LEVEL;
+#else
+    l2cb.l2cap_trace_level = BT_TRACE_LEVEL_NONE;    /* No traces */
+#endif
+
+#if (L2CAP_CONFORMANCE_TESTING == TRUE)
+     /* Conformance testing needs a dynamic response */
+    l2cb.test_info_resp = L2CAP_EXTFEA_SUPPORTED_MASK;
+#endif
+
+    /* Number of ACL buffers to use for high priority channel */
+#if (L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE == TRUE)
+    l2cb.high_pri_min_xmit_quota = L2CAP_HIGH_PRI_MIN_XMIT_QUOTA;
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+    l2cb.l2c_ble_fixed_chnls_mask =
+         L2CAP_FIXED_CHNL_ATT_BIT | L2CAP_FIXED_CHNL_BLE_SIG_BIT | L2CAP_FIXED_CHNL_SMP_BIT;
+#endif
+
+    l2cb.rcv_pending_q = list_new(NULL);
+    if (l2cb.rcv_pending_q == NULL)
+        LOG_ERROR(LOG_TAG, "%s unable to allocate memory for link layer control block", __func__);
+    l2cb.receive_hold_timer = alarm_new("l2c.receive_hold_timer");
+}
+
+void l2c_free(void) {
+    list_free(l2cb.rcv_pending_q);
+    l2cb.rcv_pending_q = NULL;
+}
+
+void l2c_receive_hold_timer_timeout(UNUSED_ATTR void *data)
+{
+    /* Update the timeouts in the hold queue */
+    l2c_process_held_packets(true);
+}
+
+void l2c_ccb_timer_timeout(void *data)
+{
+    tL2C_CCB *p_ccb = (tL2C_CCB *)data;
+
+    l2c_csm_execute(p_ccb, L2CEVT_TIMEOUT, NULL);
+}
+
+void l2c_fcrb_ack_timer_timeout(void *data)
+{
+    tL2C_CCB *p_ccb = (tL2C_CCB *)data;
+
+    l2c_csm_execute(p_ccb, L2CEVT_ACK_TIMEOUT, NULL);
+}
+
+void l2c_lcb_timer_timeout(void *data)
+{
+    tL2C_LCB *p_lcb = (tL2C_LCB *)data;
+
+    l2c_link_timeout(p_lcb);
+}
+
+/*******************************************************************************
+**
+** Function         l2c_data_write
+**
+** Description      API functions 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 l2c_data_write (uint16_t cid, BT_HDR *p_data, uint16_t flags)
+{
+    tL2C_CCB        *p_ccb;
+
+    /* Find the channel control block. We don't know the link it is on. */
+    if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_DataWrite, CID: %d", cid);
+        osi_free(p_data);
+        return (L2CAP_DW_FAILED);
+    }
+
+#ifndef TESTER /* Tester may send any amount of data. otherwise sending message
+                  bigger than mtu size of peer is a violation of protocol */
+    uint16_t mtu;
+
+    if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
+        mtu = p_ccb->peer_conn_cfg.mtu;
+    else
+        mtu = p_ccb->peer_cfg.mtu;
+
+    if (p_data->len > mtu)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - CID: 0x%04x  cannot send message bigger than peer's mtu size", cid);
+        osi_free(p_data);
+        return (L2CAP_DW_FAILED);
+    }
+#endif
+
+    /* channel based, packet based flushable or non-flushable */
+    p_data->layer_specific = flags;
+
+    /* If already congested, do not accept any more packets */
+    if (p_ccb->cong_sent)
+    {
+        L2CAP_TRACE_ERROR ("L2CAP - CID: 0x%04x cannot send, already congested  xmit_hold_q.count: %u  buff_quota: %u",
+                           p_ccb->local_cid,
+                           fixed_queue_length(p_ccb->xmit_hold_q),
+                           p_ccb->buff_quota);
+
+        osi_free(p_data);
+        return (L2CAP_DW_FAILED);
+    }
+
+
+    l2c_csm_execute (p_ccb, L2CEVT_L2CA_DATA_WRITE, p_data);
+
+    if (p_ccb->cong_sent)
+        return (L2CAP_DW_CONGESTED);
+
+    return (L2CAP_DW_SUCCESS);
+}
+
diff --git a/bt/stack/l2cap/l2c_ucd.cc b/bt/stack/l2cap/l2c_ucd.cc
new file mode 100644
index 0000000..9407da5
--- /dev/null
+++ b/bt/stack/l2cap/l2c_ucd.cc
@@ -0,0 +1,1175 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 L2CAP UCD code
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "bt_common.h"
+#include "bt_types.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "l2cdefs.h"
+#include "l2c_int.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+
+extern fixed_queue_t *btu_bta_alarm_queue;
+
+static bool    l2c_ucd_connect ( BD_ADDR rem_bda );
+
+/*******************************************************************************
+**
+** Function         l2c_ucd_discover_cback
+**
+** Description      UCD Discover callback
+**
+** Returns          void
+**
+*******************************************************************************/
+static void l2c_ucd_discover_cback (BD_ADDR rem_bda, uint8_t info_type, uint32_t data)
+{
+    tL2C_RCB    *p_rcb = &l2cb.rcb_pool[0];
+    uint16_t    xx;
+
+    L2CAP_TRACE_DEBUG ("L2CAP - l2c_ucd_discover_cback");
+
+    for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++)
+    {
+        if (p_rcb->in_use)
+        {
+            /* if this application is waiting UCD reception info */
+            if (( info_type == L2CAP_UCD_INFO_TYPE_RECEPTION )
+                && ( p_rcb->ucd.state & L2C_UCD_STATE_W4_RECEPTION ))
+            {
+                p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb (rem_bda, info_type, data);
+                p_rcb->ucd.state &= ~(L2C_UCD_STATE_W4_RECEPTION);
+            }
+
+            /* if this application is waiting UCD MTU info */
+            if (( info_type == L2CAP_UCD_INFO_TYPE_MTU )
+                && ( p_rcb->ucd.state & L2C_UCD_STATE_W4_MTU ))
+            {
+                p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb (rem_bda, info_type, data);
+                p_rcb->ucd.state &= ~(L2C_UCD_STATE_W4_MTU);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2c_ucd_data_ind_cback
+**
+** Description      UCD Data callback
+**
+** Returns          void
+**
+*******************************************************************************/
+static void l2c_ucd_data_ind_cback (BD_ADDR rem_bda, BT_HDR *p_buf)
+{
+    uint8_t *p;
+    uint16_t psm;
+    tL2C_RCB    *p_rcb;
+
+    L2CAP_TRACE_DEBUG ("L2CAP - l2c_ucd_data_ind_cback");
+
+    p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+    STREAM_TO_UINT16(psm, p)
+
+    p_buf->offset += L2CAP_UCD_OVERHEAD;
+    p_buf->len    -= L2CAP_UCD_OVERHEAD;
+
+    if ((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL)
+    {
+        L2CAP_TRACE_ERROR ("L2CAP - no RCB for l2c_ucd_data_ind_cback, PSM: 0x%04x", psm);
+        osi_free(p_buf);
+    }
+    else
+    {
+        p_rcb->ucd.cb_info.pL2CA_UCD_Data_Cb(rem_bda, p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2c_ucd_congestion_status_cback
+**
+** Description      UCD Congestion Status callback
+**
+** Returns          void
+**
+*******************************************************************************/
+static void l2c_ucd_congestion_status_cback (BD_ADDR rem_bda, bool    is_congested)
+{
+    tL2C_RCB    *p_rcb = &l2cb.rcb_pool[0];
+    uint16_t    xx;
+
+    L2CAP_TRACE_DEBUG ("L2CAP - l2c_ucd_congestion_status_cback");
+
+    for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++)
+    {
+        if (( p_rcb->in_use )
+          &&( p_rcb->ucd.state != L2C_UCD_STATE_UNUSED ))
+        {
+            if ( p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb )
+            {
+                L2CAP_TRACE_DEBUG ("L2CAP - Calling UCDCongestionStatus_Cb (%d), PSM=0x%04x, BDA: %08x%04x,",
+                                    is_congested, p_rcb->psm,
+                                    (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3],
+                                    (rem_bda[4]<<8)+rem_bda[5]);
+
+                p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb ( rem_bda, is_congested );
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2c_ucd_disconnect_ind_cback
+**
+** Description      UCD disconnect callback (This prevent to access null pointer)
+**
+** Returns          void
+**
+*******************************************************************************/
+static void l2c_ucd_disconnect_ind_cback (uint16_t cid, bool    result)
+{
+    /* do nothing */
+}
+
+/*******************************************************************************
+**
+** Function         l2c_ucd_config_ind_cback
+**
+** Description      UCD config callback (This prevent to access null pointer)
+**
+** Returns          void
+**
+*******************************************************************************/
+static void l2c_ucd_config_ind_cback (uint16_t cid, tL2CAP_CFG_INFO *p_cfg)
+{
+    /* do nothing */
+}
+
+/*******************************************************************************
+**
+** Function         l2c_ucd_config_cfm_cback
+**
+** Description      UCD config callback (This prevent to access null pointer)
+**
+** Returns          void
+**
+*******************************************************************************/
+static void l2c_ucd_config_cfm_cback (uint16_t cid, tL2CAP_CFG_INFO *p_cfg)
+{
+    /* do nothing */
+}
+
+/*******************************************************************************
+**
+**  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 )
+{
+    tL2C_RCB             *p_rcb;
+
+    L2CAP_TRACE_API  ("L2CA_UcdRegister()  PSM: 0x%04x", psm);
+
+    if ((!p_cb_info->pL2CA_UCD_Discover_Cb)
+     || (!p_cb_info->pL2CA_UCD_Data_Cb))
+    {
+        L2CAP_TRACE_ERROR ("L2CAP - no callback registering PSM(0x%04x) on UCD", psm);
+        return (false);
+    }
+
+    if ((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL)
+    {
+        L2CAP_TRACE_ERROR ("L2CAP - no RCB for L2CA_UcdRegister, PSM: 0x%04x", psm);
+        return (false);
+    }
+
+    p_rcb->ucd.state   = L2C_UCD_STATE_W4_DATA;
+    p_rcb->ucd.cb_info = *p_cb_info;
+
+    /* check if master rcb is created for UCD */
+    if ((p_rcb = l2cu_find_rcb_by_psm (L2C_UCD_RCB_ID)) == NULL)
+    {
+        if ((p_rcb = l2cu_allocate_rcb (L2C_UCD_RCB_ID)) == NULL)
+        {
+            L2CAP_TRACE_ERROR ("L2CAP - no RCB available for L2CA_UcdRegister");
+            return (false);
+        }
+        else
+        {
+            /* these callback functions will forward data to each UCD application */
+            p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb            = l2c_ucd_discover_cback;
+            p_rcb->ucd.cb_info.pL2CA_UCD_Data_Cb                = l2c_ucd_data_ind_cback;
+            p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb   = l2c_ucd_congestion_status_cback;
+
+            memset (&p_rcb->api, 0, sizeof(tL2CAP_APPL_INFO));
+            p_rcb->api.pL2CA_DisconnectInd_Cb        = l2c_ucd_disconnect_ind_cback;
+
+            /* This will make L2CAP check UCD congestion callback */
+            p_rcb->api.pL2CA_CongestionStatus_Cb     = NULL;
+
+            /* do nothing but prevent crash */
+            p_rcb->api.pL2CA_ConfigInd_Cb            = l2c_ucd_config_ind_cback;
+            p_rcb->api.pL2CA_ConfigCfm_Cb            = l2c_ucd_config_cfm_cback;
+        }
+    }
+
+    return (true);
+}
+
+/*******************************************************************************
+**
+**  Function        L2CA_UcdDeregister
+**
+**  Description     Deregister PSM on UCD.
+**
+**  Parameters:     PSM
+**
+**  Return value:   true if successs
+**
+*******************************************************************************/
+bool    L2CA_UcdDeregister ( uint16_t psm )
+{
+    tL2C_CCB    *p_ccb;
+    tL2C_RCB    *p_rcb;
+    uint16_t    xx;
+
+    L2CAP_TRACE_API  ("L2CA_UcdDeregister()  PSM: 0x%04x", psm);
+
+    if ((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL)
+    {
+        L2CAP_TRACE_ERROR ("L2CAP - no RCB for L2CA_UcdDeregister, PSM: 0x%04x", psm);
+        return (false);
+    }
+
+    p_rcb->ucd.state = L2C_UCD_STATE_UNUSED;
+
+    /* check this was the last UCD registration */
+    p_rcb = &l2cb.rcb_pool[0];
+
+    for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++)
+    {
+        if ((p_rcb->in_use) && (p_rcb->ucd.state != L2C_UCD_STATE_UNUSED))
+            return (true);
+    }
+
+    /* delete master rcb for UCD */
+    if ((p_rcb = l2cu_find_rcb_by_psm (L2C_UCD_RCB_ID)) != NULL)
+    {
+        l2cu_release_rcb (p_rcb);
+    }
+
+    /* delete CCB for UCD */
+    p_ccb = l2cb.ccb_pool;
+    for ( xx = 0; xx < MAX_L2CAP_CHANNELS; xx++ )
+    {
+        if (( p_ccb->in_use )
+          &&( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID ))
+        {
+            l2cu_release_ccb (p_ccb);
+        }
+        p_ccb++;
+    }
+
+    return (true);
+}
+
+/*******************************************************************************
+**
+**  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, BD_ADDR rem_bda, uint8_t info_type )
+{
+    tL2C_LCB        *p_lcb;
+    tL2C_CCB        *p_ccb;
+    tL2C_RCB        *p_rcb;
+
+    L2CAP_TRACE_API ("L2CA_UcdDiscover()  PSM: 0x%04x  BDA: %08x%04x, InfoType=0x%02x", psm,
+                      (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3],
+                      (rem_bda[4]<<8)+rem_bda[5], info_type);
+
+    /* Fail if the PSM is not registered */
+    if (((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL)
+        ||( p_rcb->ucd.state == L2C_UCD_STATE_UNUSED ))
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no RCB for L2CA_UcdDiscover, PSM: 0x%04x", psm);
+        return (false);
+    }
+
+    /* First, see if we already have a link to the remote */
+    /* then find the channel control block for UCD. */
+    if (((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_BR_EDR)) == NULL)
+      ||((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL))
+    {
+        if ( l2c_ucd_connect (rem_bda) == false )
+        {
+            return (false);
+        }
+    }
+
+    /* set waiting flags in rcb */
+
+    if ( info_type & L2CAP_UCD_INFO_TYPE_RECEPTION )
+        p_rcb->ucd.state |= L2C_UCD_STATE_W4_RECEPTION;
+
+    if ( info_type & L2CAP_UCD_INFO_TYPE_MTU )
+        p_rcb->ucd.state |= L2C_UCD_STATE_W4_MTU;
+
+    /* if link is already established */
+    if ((p_lcb)&&(p_lcb->link_state == LST_CONNECTED))
+    {
+        if (!p_ccb)
+        {
+            p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID);
+        }
+        l2c_ucd_check_pending_info_req(p_ccb);
+    }
+    return (true);
+}
+
+/*******************************************************************************
+**
+**  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, BD_ADDR rem_bda, BT_HDR *p_buf, uint16_t flags)
+{
+    tL2C_LCB        *p_lcb;
+    tL2C_CCB        *p_ccb;
+    tL2C_RCB        *p_rcb;
+    uint8_t         *p;
+
+    L2CAP_TRACE_API ("L2CA_UcdDataWrite()  PSM: 0x%04x  BDA: %08x%04x", psm,
+                      (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3],
+                      (rem_bda[4]<<8)+rem_bda[5]);
+
+    /* Fail if the PSM is not registered */
+    if (((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL)
+        ||( p_rcb->ucd.state == L2C_UCD_STATE_UNUSED ))
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no RCB for L2CA_UcdDataWrite, PSM: 0x%04x", psm);
+        osi_free(p_buf);
+        return (L2CAP_DW_FAILED);
+    }
+
+    /* First, see if we already have a link to the remote */
+    /*  then find the channel control block for UCD */
+    if (((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_BR_EDR)) == NULL)
+      ||((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL))
+    {
+        if ( l2c_ucd_connect (rem_bda) == false )
+        {
+            osi_free(p_buf);
+            return (L2CAP_DW_FAILED);
+        }
+
+        /* If we still don't have lcb and ccb after connect attempt, then can't proceed */
+        if (((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_BR_EDR)) == NULL)
+            || ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL))
+        {
+            osi_free(p_buf);
+            return (L2CAP_DW_FAILED);
+        }
+    }
+
+    /* write PSM */
+    p_buf->offset -= L2CAP_UCD_OVERHEAD;
+    p_buf->len += L2CAP_UCD_OVERHEAD;
+    p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+    UINT16_TO_STREAM (p, psm);
+
+    /* UCD MTU check */
+    if ((p_lcb->ucd_mtu) && (p_buf->len > p_lcb->ucd_mtu))
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - Handle: 0x%04x  UCD bigger than peer's UCD mtu size cannot be sent", p_lcb->handle);
+        osi_free(p_buf);
+        return (L2CAP_DW_FAILED);
+    }
+
+    /* If already congested, do not accept any more packets */
+    if (p_ccb->cong_sent)
+    {
+        L2CAP_TRACE_ERROR ("L2CAP - Handle: 0x%04x UCD cannot be sent, already congested count: %u  buff_quota: %u",
+                           p_lcb->handle,
+                           (fixed_queue_length(p_ccb->xmit_hold_q) +
+                            fixed_queue_length(p_lcb->ucd_out_sec_pending_q)),
+                           p_ccb->buff_quota);
+
+        osi_free(p_buf);
+        return (L2CAP_DW_FAILED);
+    }
+
+    /* channel based, packet based flushable or non-flushable */
+    p_buf->layer_specific = flags;
+
+    l2c_csm_execute (p_ccb, L2CEVT_L2CA_DATA_WRITE, p_buf);
+
+    if (p_ccb->cong_sent)
+        return (L2CAP_DW_CONGESTED);
+    else
+        return (L2CAP_DW_SUCCESS);
+}
+
+/*******************************************************************************
+**
+**  Function        L2CA_UcdSetIdleTimeout
+**
+**  Description     Set UCD Idle timeout.
+**
+**  Parameters:     BD Addr
+**                  Timeout in second
+**
+**  Return value:   true if successs
+**
+*******************************************************************************/
+bool    L2CA_UcdSetIdleTimeout ( BD_ADDR rem_bda, uint16_t timeout )
+{
+    tL2C_LCB        *p_lcb;
+    tL2C_CCB        *p_ccb;
+
+    L2CAP_TRACE_API ("L2CA_UcdSetIdleTimeout()  Timeout: 0x%04x  BDA: %08x%04x", timeout,
+                      (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3],
+                      (rem_bda[4]<<8)+rem_bda[5]);
+
+    /* First, see if we already have a link to the remote */
+    /* then find the channel control block. */
+    if (((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_BR_EDR)) == NULL)
+      ||((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL))
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no UCD channel");
+        return (false);
+    }
+    else
+    {
+        p_ccb->fixed_chnl_idle_tout = timeout;
+        return (true);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         L2CA_UCDSetTxPriority
+**
+** Description      Sets the transmission priority for a connectionless channel.
+**
+** Returns          true if a valid channel, else false
+**
+*******************************************************************************/
+bool    L2CA_UCDSetTxPriority ( BD_ADDR rem_bda, tL2CAP_CHNL_PRIORITY priority )
+{
+    tL2C_LCB        *p_lcb;
+    tL2C_CCB        *p_ccb;
+
+    L2CAP_TRACE_API ("L2CA_UCDSetTxPriority()  priority: 0x%02x  BDA: %08x%04x", priority,
+                      (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3],
+                      (rem_bda[4]<<8)+rem_bda[5]);
+
+    if ((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_BR_EDR)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no LCB for L2CA_UCDSetTxPriority");
+        return (false);
+    }
+
+    /* Find the channel control block */
+    if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_UCDSetTxPriority");
+        return (false);
+    }
+
+    /* it will update the order of CCB in LCB by priority and update round robin service variables */
+    l2cu_change_pri_ccb (p_ccb, priority);
+
+    return (true);
+}
+
+/*******************************************************************************
+**
+**  Function        l2c_ucd_connect
+**
+**  Description     Connect UCD to remote device.
+**
+**  Parameters:     BD_ADDR of remote device
+**
+**  Return value:   true if successs
+**
+*******************************************************************************/
+static bool    l2c_ucd_connect ( BD_ADDR rem_bda )
+{
+    tL2C_LCB        *p_lcb;
+    tL2C_CCB        *p_ccb;
+    tL2C_RCB        *p_rcb;
+
+    L2CAP_TRACE_DEBUG ("l2c_ucd_connect()  BDA: %08x%04x",
+                      (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3],
+                      (rem_bda[4]<<8)+rem_bda[5]);
+
+    /* Fail if we have not established communications with the controller */
+    if (!BTM_IsDeviceUp())
+    {
+        L2CAP_TRACE_WARNING ("l2c_ucd_connect - BTU not ready");
+        return (false);
+    }
+
+    /* First, see if we already have a link to the remote */
+    if ((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_BR_EDR)) == NULL)
+    {
+        /* No link. Get an LCB and start link establishment */
+        if ( ((p_lcb = l2cu_allocate_lcb (rem_bda, false, BT_TRANSPORT_BR_EDR)) == NULL)
+         ||  (l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR) == false) )
+        {
+            L2CAP_TRACE_WARNING ("L2CAP - conn not started l2c_ucd_connect");
+            return (false);
+        }
+    }
+    else if ( p_lcb->info_rx_bits & (1 << L2CAP_EXTENDED_FEATURES_INFO_TYPE) )
+    {
+        if (!(p_lcb->peer_ext_fea & L2CAP_EXTFEA_UCD_RECEPTION))
+        {
+            L2CAP_TRACE_WARNING ("L2CAP - UCD is not supported by peer, l2c_ucd_connect");
+            return (false);
+        }
+    }
+
+    /* Find the channel control block. */
+    if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL)
+    {
+        /* Allocate a channel control block */
+        if ((p_ccb = l2cu_allocate_ccb (p_lcb, 0)) == NULL)
+        {
+            L2CAP_TRACE_WARNING ("L2CAP - no CCB for l2c_ucd_connect");
+            return (false);
+        }
+        else
+        {
+            /* Set CID for the connection */
+            p_ccb->local_cid  = L2CAP_CONNECTIONLESS_CID;
+            p_ccb->remote_cid = L2CAP_CONNECTIONLESS_CID;
+
+            /* Set the default idle timeout value to use */
+            p_ccb->fixed_chnl_idle_tout = L2CAP_UCD_IDLE_TIMEOUT;
+
+            /* Set the default channel priority value to use */
+            l2cu_change_pri_ccb (p_ccb, L2CAP_UCD_CH_PRIORITY);
+
+            if ((p_rcb = l2cu_find_rcb_by_psm (L2C_UCD_RCB_ID)) == NULL)
+            {
+                L2CAP_TRACE_WARNING ("L2CAP - no UCD registered, l2c_ucd_connect");
+                return (false);
+            }
+            /* Save UCD registration info */
+            p_ccb->p_rcb = p_rcb;
+
+            /* There is no configuration, so if the link is up, the channel is up */
+            if (p_lcb->link_state == LST_CONNECTED)
+            {
+                p_ccb->chnl_state = CST_OPEN;
+            }
+        }
+    }
+
+    return (true);
+}
+
+/*******************************************************************************
+**
+**  Function        l2c_ucd_delete_sec_pending_q
+**
+** Description      discard all of UCD packets in security pending queue
+**
+** Returns          None
+**
+*******************************************************************************/
+void l2c_ucd_delete_sec_pending_q(tL2C_LCB  *p_lcb)
+{
+    /* clean up any security pending UCD */
+    while (! fixed_queue_is_empty(p_lcb->ucd_out_sec_pending_q))
+        osi_free(fixed_queue_try_dequeue(p_lcb->ucd_out_sec_pending_q));
+    fixed_queue_free(p_lcb->ucd_out_sec_pending_q, NULL);
+    p_lcb->ucd_out_sec_pending_q = NULL;
+
+    while (! fixed_queue_is_empty(p_lcb->ucd_in_sec_pending_q))
+        osi_free(fixed_queue_try_dequeue(p_lcb->ucd_in_sec_pending_q));
+    fixed_queue_free(p_lcb->ucd_in_sec_pending_q);
+    p_lcb->ucd_in_sec_pending_q = NULL;
+}
+
+/*******************************************************************************
+**
+**  Function        l2c_ucd_check_pending_info_req
+**
+** Description      check if any application is waiting for UCD information
+**
+**  Return          true if any pending UCD info request
+**
+*******************************************************************************/
+bool    l2c_ucd_check_pending_info_req(tL2C_CCB  *p_ccb)
+{
+    tL2C_RCB    *p_rcb = &l2cb.rcb_pool[0];
+    uint16_t    xx;
+    bool        pending = false;
+
+    if (p_ccb == NULL)
+    {
+        L2CAP_TRACE_ERROR ("L2CAP - NULL p_ccb in l2c_ucd_check_pending_info_req");
+        return (false);
+    }
+
+    for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++)
+    {
+        if (p_rcb->in_use)
+        {
+            /* if application is waiting UCD reception info */
+            if (p_rcb->ucd.state & L2C_UCD_STATE_W4_RECEPTION)
+            {
+                /* if this information is available */
+                if ( p_ccb->p_lcb->info_rx_bits & (1 << L2CAP_EXTENDED_FEATURES_INFO_TYPE) )
+                {
+                    if (!(p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_UCD_RECEPTION))
+                    {
+                        L2CAP_TRACE_WARNING ("L2CAP - UCD is not supported by peer, l2c_ucd_check_pending_info_req");
+
+                        l2c_ucd_delete_sec_pending_q(p_ccb->p_lcb);
+                        l2cu_release_ccb (p_ccb);
+                    }
+
+                    p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb (p_ccb->p_lcb->remote_bd_addr,
+                                                                     L2CAP_UCD_INFO_TYPE_RECEPTION,
+                                                                     p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_UCD_RECEPTION);
+                }
+                else
+                {
+                    pending = true;
+                    if (p_ccb->p_lcb->w4_info_rsp == false)
+                    {
+                        l2cu_send_peer_info_req (p_ccb->p_lcb, L2CAP_EXTENDED_FEATURES_INFO_TYPE);
+                    }
+                }
+            }
+
+            /* if application is waiting for UCD MTU */
+            if (p_rcb->ucd.state & L2C_UCD_STATE_W4_MTU)
+            {
+                /* if this information is available */
+                if ( p_ccb->p_lcb->info_rx_bits & (1 << L2CAP_CONNLESS_MTU_INFO_TYPE))
+                {
+                    p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb (p_ccb->p_lcb->remote_bd_addr,
+                                                                     L2CAP_UCD_INFO_TYPE_MTU,
+                                                                     p_ccb->p_lcb->ucd_mtu);
+                }
+                else
+                {
+                    pending = true;
+                    if (p_ccb->p_lcb->w4_info_rsp == false)
+                    {
+                        l2cu_send_peer_info_req (p_ccb->p_lcb, L2CAP_CONNLESS_MTU_INFO_TYPE);
+                    }
+                }
+            }
+        }
+    }
+    return (pending);
+}
+
+/*******************************************************************************
+**
+**  Function        l2c_ucd_enqueue_pending_out_sec_q
+**
+**  Description     enqueue outgoing UCD packet into security pending queue
+**                  and check congestion
+**
+**  Return          None
+**
+*******************************************************************************/
+void l2c_ucd_enqueue_pending_out_sec_q(tL2C_CCB  *p_ccb, void *p_data)
+{
+    fixed_queue_enqueue(p_ccb->p_lcb->ucd_out_sec_pending_q, p_data);
+    l2cu_check_channel_congestion (p_ccb);
+}
+
+/*******************************************************************************
+**
+**  Function        l2c_ucd_check_pending_out_sec_q
+**
+**  Description     check outgoing security
+**
+**  Return          true if any UCD packet for security
+**
+*******************************************************************************/
+bool    l2c_ucd_check_pending_out_sec_q(tL2C_CCB  *p_ccb)
+{
+    BT_HDR *p_buf = (BT_HDR*)fixed_queue_try_peek_first(p_ccb->p_lcb->ucd_out_sec_pending_q);
+
+    if (p_buf != NULL)
+    {
+        uint16_t psm;
+        uint8_t *p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+        STREAM_TO_UINT16(psm, p)
+
+        p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
+        btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, psm,
+                                  p_ccb->p_lcb->handle, CONNLESS_ORIG, &l2c_link_sec_comp, p_ccb);
+
+        return (true);
+    }
+    return (false);
+}
+
+/*******************************************************************************
+**
+**  Function        l2c_ucd_send_pending_out_sec_q
+**
+**  Description     dequeue UCD packet from security pending queue and
+**                  enqueue it into CCB
+**
+**  Return          None
+**
+*******************************************************************************/
+void l2c_ucd_send_pending_out_sec_q(tL2C_CCB  *p_ccb)
+{
+    BT_HDR *p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_out_sec_pending_q);
+
+    if (p_buf != NULL)
+    {
+        l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_buf);
+        l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
+    }
+}
+
+/*******************************************************************************
+**
+**  Function        l2c_ucd_discard_pending_out_sec_q
+**
+**  Description     dequeue UCD packet from security pending queue and
+**                  discard it.
+**
+**  Return          None
+**
+*******************************************************************************/
+void l2c_ucd_discard_pending_out_sec_q(tL2C_CCB  *p_ccb)
+{
+    BT_HDR *p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_out_sec_pending_q);
+
+    /* we may need to report to application */
+    osi_free(p_buf);
+}
+
+/*******************************************************************************
+**
+**  Function        l2c_ucd_check_pending_in_sec_q
+**
+**  Description     check incoming security
+**
+**  Return          true if any UCD packet for security
+**
+*******************************************************************************/
+bool    l2c_ucd_check_pending_in_sec_q(tL2C_CCB  *p_ccb)
+{
+    BT_HDR *p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_in_sec_pending_q);
+
+    if (p_buf != NULL)
+    {
+        uint16_t psm;
+        uint8_t *p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+        STREAM_TO_UINT16(psm, p)
+
+        p_ccb->chnl_state = CST_TERM_W4_SEC_COMP;
+        btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, psm,
+                                  p_ccb->p_lcb->handle, CONNLESS_TERM, &l2c_link_sec_comp, p_ccb);
+
+        return (true);
+    }
+    return (false);
+}
+
+/*******************************************************************************
+**
+**  Function        l2c_ucd_send_pending_in_sec_q
+**
+**  Description     dequeue UCD packet from security pending queue and
+**                  send it to application
+**
+**  Return          None
+**
+*******************************************************************************/
+void l2c_ucd_send_pending_in_sec_q(tL2C_CCB  *p_ccb)
+{
+    BT_HDR *p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_in_sec_pending_q)
+
+    if (p_buf != NULL)
+    {
+        p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Data_Cb(p_ccb->p_lcb->remote_bd_addr, (BT_HDR *)p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+**  Function        l2c_ucd_discard_pending_in_sec_q
+**
+**  Description     dequeue UCD packet from security pending queue and
+**                  discard it.
+**
+**  Return          None
+**
+*******************************************************************************/
+void l2c_ucd_discard_pending_in_sec_q(tL2C_CCB  *p_ccb)
+{
+    BT_HDR *p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_in_sec_pending_q);
+    osi_free(p_buf);
+}
+
+/*******************************************************************************
+**
+**  Function        l2c_ucd_check_rx_pkts
+**
+**  Description     Check if UCD reception is registered.
+**                  Process received UCD packet if application is expecting.
+**
+**  Return          true if UCD reception is registered
+**
+*******************************************************************************/
+bool    l2c_ucd_check_rx_pkts(tL2C_LCB  *p_lcb, BT_HDR *p_msg)
+{
+    tL2C_CCB   *p_ccb;
+    tL2C_RCB   *p_rcb;
+
+    if (((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) != NULL)
+      ||((p_rcb = l2cu_find_rcb_by_psm (L2C_UCD_RCB_ID)) != NULL))
+    {
+        if (p_ccb == NULL)
+        {
+            /* Allocate a channel control block */
+            if ((p_ccb = l2cu_allocate_ccb (p_lcb, 0)) == NULL)
+            {
+                L2CAP_TRACE_WARNING ("L2CAP - no CCB for UCD reception");
+                osi_free(p_msg);
+                return true;
+            }
+            else
+            {
+                /* Set CID for the connection */
+                p_ccb->local_cid  = L2CAP_CONNECTIONLESS_CID;
+                p_ccb->remote_cid = L2CAP_CONNECTIONLESS_CID;
+
+                /* Set the default idle timeout value to use */
+                p_ccb->fixed_chnl_idle_tout = L2CAP_UCD_IDLE_TIMEOUT;
+
+                /* Set the default channel priority value to use */
+                l2cu_change_pri_ccb (p_ccb, L2CAP_UCD_CH_PRIORITY);
+
+                /* Save registration info */
+                p_ccb->p_rcb = p_rcb;
+
+                p_ccb->chnl_state = CST_OPEN;
+            }
+        }
+        l2c_csm_execute(p_ccb, L2CEVT_L2CAP_DATA, p_msg);
+        return true;
+    }
+    else
+        return false;
+}
+
+/*******************************************************************************
+**
+**  Function        l2c_ucd_process_event
+**
+**  Description     This is called from main state machine when LCID is connectionless
+**                  Process the event if it is for UCD.
+**
+**  Return          true if the event is consumed by UCD
+**                  false if the event needs to be processed by main state machine
+**
+*******************************************************************************/
+bool    l2c_ucd_process_event(tL2C_CCB *p_ccb, uint16_t event, void *p_data)
+{
+    /* if the event is not processed by this function, this variable will be set to false */
+    bool    done = true;
+
+    switch (p_ccb->chnl_state)
+    {
+    case CST_CLOSED:
+        switch (event)
+        {
+        case L2CEVT_LP_CONNECT_CFM:     /* Link came up         */
+            /* check if waiting for UCD info */
+            if (!l2c_ucd_check_pending_info_req (p_ccb))
+            {
+                /* check if any outgoing UCD packet is waiting security check */
+                if (!l2c_ucd_check_pending_out_sec_q(p_ccb))
+                {
+                    p_ccb->chnl_state = CST_OPEN;
+                }
+            }
+            break;
+
+        case L2CEVT_L2CAP_DATA:         /* Peer data packet rcvd    */
+            fixed_queue_enqueue(p_ccb->p_lcb->ucd_in_sec_pending_q, p_data);
+            break;
+
+        case L2CEVT_L2CA_DATA_WRITE:    /* Upper layer data to send */
+            l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data);
+            break;
+
+        case L2CEVT_L2CAP_INFO_RSP:
+            /* check if waiting for UCD info */
+            if (!l2c_ucd_check_pending_info_req (p_ccb))
+            {
+                /* check if any outgoing UCD packet is waiting security check */
+                if (!l2c_ucd_check_pending_out_sec_q(p_ccb))
+                {
+                    p_ccb->chnl_state = CST_OPEN;
+                }
+            }
+            break;
+
+        default:
+            done = false;   /* main state machine continues to process event */
+            break;
+        }
+        break;
+
+    case CST_ORIG_W4_SEC_COMP:
+        switch (event)
+        {
+        case L2CEVT_SEC_RE_SEND_CMD:    /* BTM has enough info to proceed */
+            /* check if any outgoing UCD packet is waiting security check */
+            if (!l2c_ucd_check_pending_out_sec_q(p_ccb))
+            {
+                p_ccb->chnl_state = CST_OPEN;
+            }
+            break;
+
+        case L2CEVT_SEC_COMP:           /* Security completed success */
+            p_ccb->chnl_state = CST_OPEN;
+            l2c_ucd_send_pending_out_sec_q(p_ccb);
+
+            if (! fixed_queue_is_empty(p_ccb->p_lcb->ucd_out_sec_pending_q))
+            {
+                /* start a timer to send next UCD packet in OPEN state */
+                /* it will prevent stack overflow */
+                alarm_set_on_queue(p_ccb->l2c_ccb_timer, 0,
+                                   l2c_ccb_timer_timeout, p_ccb,
+                                   btu_general_alarm_queue);
+            }
+            else
+            {
+                /* start a timer for idle timeout of UCD */
+                period_ms_t timeout_ms = p_ccb->fixed_chnl_idle_tout * 1000;
+                alarm_set_on_queue(p_ccb->l2c_ccb_timer, timeout_ms,
+                                   l2c_ccb_timer_timeout, p_ccb,
+                                   btu_general_alarm_queue);
+            }
+            break;
+
+        case L2CEVT_SEC_COMP_NEG:
+            p_ccb->chnl_state = CST_OPEN;
+            l2c_ucd_discard_pending_out_sec_q(p_ccb);
+
+            /* start a timer for idle timeout of UCD */
+            period_ms_t timeout_ms = p_ccb->fixed_chnl_idle_tout * 1000;
+            alarm_set_on_queue(p_ccb->l2c_ccb_timer, timeout_ms,
+                               l2c_ccb_timer_timeout, p_ccb,
+                               btu_general_alarm_queue);
+            break;
+
+        case L2CEVT_L2CA_DATA_WRITE:    /* Upper layer data to send */
+            l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data);
+            break;
+
+        case L2CEVT_L2CAP_DATA:         /* Peer data packet rcvd    */
+            fixed_queue_enqueue(p_ccb->p_lcb->ucd_in_sec_pending_q, p_data);
+            break;
+
+        case L2CEVT_L2CAP_INFO_RSP:
+            /* check if waiting for UCD info */
+            l2c_ucd_check_pending_info_req (p_ccb);
+            break;
+
+        default:
+            done = false;   /* main state machine continues to process event */
+            break;
+        }
+        break;
+
+
+    case CST_TERM_W4_SEC_COMP:
+        switch (event)
+        {
+        case L2CEVT_SEC_COMP:
+            p_ccb->chnl_state = CST_OPEN;
+            l2c_ucd_send_pending_in_sec_q (p_ccb);
+
+            if (! fixed_queue_is_empty(p_ccb->p_lcb->ucd_in_sec_pending_q))
+            {
+                /* start a timer to check next UCD packet in OPEN state */
+                /* it will prevent stack overflow */
+              alarm_set_on_queue(p_ccb->l2c_ccb_timer, 0,
+                               l2c_ccb_timer_timeout, p_ccb,
+                               btu_general_alarm_queue);
+            }
+            else
+            {
+                /* start a timer for idle timeout of UCD */
+                period_ms_t timeout_ms = p_ccb->fixed_chnl_idle_tout * 1000;
+                alarm_set_on_queue(p_ccb->l2c_ccb_timer, timeout_ms,
+                                   l2c_ccb_timer_timeout, p_ccb,
+                                   btu_general_alarm_queue);
+            }
+            break;
+
+        case L2CEVT_SEC_COMP_NEG:
+            if (((tL2C_CONN_INFO *)p_data)->status == BTM_DELAY_CHECK)
+            {
+                done = false;
+                break;
+            }
+            p_ccb->chnl_state = CST_OPEN;
+            l2c_ucd_discard_pending_in_sec_q (p_ccb);
+
+            /* start a timer for idle timeout of UCD */
+            period_ms_t timeout_ms = p_ccb->fixed_chnl_idle_tout * 1000;
+            alarm_set_on_queue(p_ccb->l2c_ccb_timer, timeout_ms,
+                               l2c_ccb_timer_timeout, p_ccb,
+                               btu_general_alarm_queue);
+            break;
+
+        case L2CEVT_L2CA_DATA_WRITE:        /* Upper layer data to send */
+            l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data);
+            break;
+
+        case L2CEVT_L2CAP_DATA:             /* Peer data packet rcvd    */
+            fixed_queue_enqueue(p_ccb->p_lcb->ucd_in_sec_pending_q, p_data);
+            break;
+
+        case L2CEVT_SEC_RE_SEND_CMD:        /* BTM has enough info to proceed */
+            /* check if any incoming UCD packet is waiting security check */
+            if (!l2c_ucd_check_pending_in_sec_q(p_ccb))
+            {
+                p_ccb->chnl_state = CST_OPEN;
+            }
+            break;
+
+        case L2CEVT_L2CAP_INFO_RSP:
+            /* check if waiting for UCD info */
+            l2c_ucd_check_pending_info_req (p_ccb);
+            break;
+
+        default:
+            done = false;   /* main state machine continues to process event */
+            break;
+        }
+        break;
+
+    case CST_OPEN:
+        switch (event)
+        {
+        case L2CEVT_L2CAP_DATA:             /* Peer data packet rcvd    */
+            /* stop idle timer of UCD */
+            alarm_cancel(p_ccb->l2c_ccb_timer);
+
+            fixed_queue_enqueue(p_ccb->p_lcb->ucd_in_sec_pending_q, p_data);
+            l2c_ucd_check_pending_in_sec_q (p_ccb);
+            break;
+
+        case L2CEVT_L2CA_DATA_WRITE:        /* Upper layer data to send */
+            /* stop idle timer of UCD */
+            alarm_cancel(p_ccb->l2c_ccb_timer);
+
+            l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data);
+
+            /* coverity[check_return] */ /* coverity[unchecked_value] */
+            /* success changes state, failure stays in current state */
+            l2c_ucd_check_pending_out_sec_q (p_ccb);
+            break;
+
+        case L2CEVT_TIMEOUT:
+            /* check if any UCD packet is waiting security check */
+            if ((!l2c_ucd_check_pending_in_sec_q(p_ccb))
+              &&(!l2c_ucd_check_pending_out_sec_q(p_ccb)))
+            {
+                l2cu_release_ccb (p_ccb);
+            }
+            break;
+
+        case L2CEVT_L2CAP_INFO_RSP:
+            /* check if waiting for UCD info */
+            l2c_ucd_check_pending_info_req (p_ccb);
+            break;
+
+        default:
+            done = false;   /* main state machine continues to process event */
+            break;
+        }
+        break;
+
+    default:
+        done = false;   /* main state machine continues to process event */
+        break;
+    }
+
+    return done;
+}
+#endif /* (L2CAP_UCD_INCLUDED == TRUE) */
diff --git a/bt/stack/l2cap/l2c_utils.cc b/bt/stack/l2cap/l2c_utils.cc
new file mode 100644
index 0000000..bf83b44
--- /dev/null
+++ b/bt/stack/l2cap/l2c_utils.cc
@@ -0,0 +1,3833 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 L2CAP utility functions
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "device/include/controller.h"
+#include "bt_common.h"
+#include "bt_types.h"
+#include "hcimsgs.h"
+#include "l2cdefs.h"
+#include "l2c_int.h"
+#include "hcidefs.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "hcidefs.h"
+#include "bt_utils.h"
+#include "osi/include/allocator.h"
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+/*******************************************************************************
+**
+** Function         l2cu_allocate_lcb
+**
+** Description      Look for an unused LCB
+**
+** Returns          LCB address or NULL if none found
+**
+*******************************************************************************/
+tL2C_LCB *l2cu_allocate_lcb (BD_ADDR p_bd_addr, bool    is_bonding, tBT_TRANSPORT transport)
+{
+    int         xx;
+    tL2C_LCB    *p_lcb = &l2cb.lcb_pool[0];
+
+    for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
+    {
+        if (!p_lcb->in_use)
+        {
+            alarm_free(p_lcb->l2c_lcb_timer);
+            alarm_free(p_lcb->info_resp_timer);
+            memset (p_lcb, 0, sizeof (tL2C_LCB));
+
+            memcpy (p_lcb->remote_bd_addr, p_bd_addr, BD_ADDR_LEN);
+
+            p_lcb->in_use          = true;
+            p_lcb->link_state      = LST_DISCONNECTED;
+            p_lcb->handle          = HCI_INVALID_HANDLE;
+            p_lcb->link_flush_tout = 0xFFFF;
+            p_lcb->l2c_lcb_timer   = alarm_new("l2c_lcb.l2c_lcb_timer");
+            p_lcb->info_resp_timer = alarm_new("l2c_lcb.info_resp_timer");
+            p_lcb->idle_timeout    = l2cb.idle_timeout;
+            p_lcb->id              = 1;                     /* spec does not allow '0' */
+            p_lcb->is_bonding      = is_bonding;
+#if (BLE_INCLUDED == TRUE)
+            p_lcb->transport       = transport;
+            p_lcb->tx_data_len     = controller_get_interface()->get_ble_default_data_packet_length();
+            p_lcb->le_sec_pending_q = fixed_queue_new(SIZE_MAX);
+
+            if (transport == BT_TRANSPORT_LE)
+            {
+                l2cb.num_ble_links_active++;
+                l2c_ble_link_adjust_allocation();
+            }
+            else
+#endif
+            {
+                l2cb.num_links_active++;
+                l2c_link_adjust_allocation();
+            }
+#if (L2CAP_UCD_INCLUDED == TRUE)
+            p_lcb->ucd_out_sec_pending_q = fixed_queue_new(SIZE_MAX);
+            p_lcb->ucd_in_sec_pending_q = fixed_queue_new(SIZE_MAX);
+#endif
+            p_lcb->link_xmit_data_q = list_new(NULL);
+            return (p_lcb);
+        }
+    }
+
+    /* If here, no free LCB found */
+    return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_update_lcb_4_bonding
+**
+** Description      Mark the lcb for bonding. Used when bonding takes place on
+**                  an existing ACL connection.  (Pre-Lisbon devices)
+**
+** Returns          Nothing
+**
+*******************************************************************************/
+void l2cu_update_lcb_4_bonding (BD_ADDR p_bd_addr, bool    is_bonding)
+{
+    tL2C_LCB    *p_lcb = l2cu_find_lcb_by_bd_addr (p_bd_addr, BT_TRANSPORT_BR_EDR);
+
+    if (p_lcb)
+    {
+        L2CAP_TRACE_DEBUG ("l2cu_update_lcb_4_bonding  BDA: %08x%04x is_bonding: %d",
+                          (p_bd_addr[0]<<24)+(p_bd_addr[1]<<16)+(p_bd_addr[2]<<8)+p_bd_addr[3],
+                          (p_bd_addr[4]<<8)+p_bd_addr[5], is_bonding);
+        p_lcb->is_bonding = is_bonding;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_release_lcb
+**
+** Description      Release an LCB. All timers will be stopped and freed,
+**                  channels dropped, buffers returned etc.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_release_lcb (tL2C_LCB *p_lcb)
+{
+    tL2C_CCB    *p_ccb;
+
+    p_lcb->in_use     = false;
+    p_lcb->is_bonding = false;
+
+    /* Stop and free timers */
+    alarm_free(p_lcb->l2c_lcb_timer);
+    p_lcb->l2c_lcb_timer = NULL;
+    alarm_free(p_lcb->info_resp_timer);
+    p_lcb->info_resp_timer = NULL;
+
+    /* Release any unfinished L2CAP packet on this link */
+    osi_free_and_reset((void **)&p_lcb->p_hcit_rcv_acl);
+
+#if (BTM_SCO_INCLUDED == TRUE)
+#if (BLE_INCLUDED == TRUE)
+        if (p_lcb->transport == BT_TRANSPORT_BR_EDR)
+#endif
+        /* Release all SCO links */
+        btm_remove_sco_links(p_lcb->remote_bd_addr);
+#endif
+
+    if (p_lcb->sent_not_acked > 0)
+    {
+#if (BLE_INCLUDED == TRUE)
+        if (p_lcb->transport == BT_TRANSPORT_LE)
+        {
+            l2cb.controller_le_xmit_window += p_lcb->sent_not_acked;
+            if (l2cb.controller_le_xmit_window > l2cb.num_lm_ble_bufs)
+            {
+                l2cb.controller_le_xmit_window = l2cb.num_lm_ble_bufs;
+            }
+        }
+        else
+#endif
+        {
+            l2cb.controller_xmit_window += p_lcb->sent_not_acked;
+            if (l2cb.controller_xmit_window > l2cb.num_lm_acl_bufs)
+            {
+                l2cb.controller_xmit_window = l2cb.num_lm_acl_bufs;
+            }
+        }
+    }
+
+#if (BLE_INCLUDED == TRUE)
+    // Reset BLE connecting flag only if the address matches
+    if (!memcmp(l2cb.ble_connecting_bda, p_lcb->remote_bd_addr, BD_ADDR_LEN))
+        l2cb.is_ble_connecting = false;
+#endif
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+    l2cu_process_fixed_disc_cback(p_lcb);
+#endif
+
+    /* Ensure no CCBs left on this LCB */
+    for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_lcb->ccb_queue.p_first_ccb)
+    {
+        l2cu_release_ccb (p_ccb);
+    }
+
+    /* Tell BTM Acl management the link was removed */
+    if ((p_lcb->link_state == LST_CONNECTED) || (p_lcb->link_state == LST_DISCONNECTING))
+#if (BLE_INCLUDED == TRUE)
+        btm_acl_removed (p_lcb->remote_bd_addr, p_lcb->transport);
+#else
+        btm_acl_removed (p_lcb->remote_bd_addr, BT_TRANSPORT_BR_EDR);
+#endif
+
+    /* Release any held buffers */
+    if (p_lcb->link_xmit_data_q)
+    {
+        while (!list_is_empty(p_lcb->link_xmit_data_q)) {
+            BT_HDR *p_buf =
+                static_cast<BT_HDR *>(list_front(p_lcb->link_xmit_data_q));
+            list_remove(p_lcb->link_xmit_data_q, p_buf);
+            osi_free(p_buf);
+        }
+        list_free(p_lcb->link_xmit_data_q);
+        p_lcb->link_xmit_data_q = NULL;
+    }
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+    /* clean up any security pending UCD */
+    l2c_ucd_delete_sec_pending_q(p_lcb);
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+    /* Re-adjust flow control windows make sure it does not go negative */
+    if (p_lcb->transport == BT_TRANSPORT_LE)
+    {
+        if (l2cb.num_ble_links_active >= 1)
+            l2cb.num_ble_links_active--;
+
+        l2c_ble_link_adjust_allocation();
+    }
+    else
+#endif
+    {
+        if (l2cb.num_links_active >= 1)
+            l2cb.num_links_active--;
+
+        l2c_link_adjust_allocation();
+    }
+
+    /* Check for ping outstanding */
+    if (p_lcb->p_echo_rsp_cb)
+    {
+        tL2CA_ECHO_RSP_CB *p_cb = p_lcb->p_echo_rsp_cb;
+
+        /* Zero out the callback in case app immediately calls us again */
+        p_lcb->p_echo_rsp_cb = NULL;
+
+        (*p_cb) (L2CAP_PING_RESULT_NO_LINK);
+    }
+
+    /* Check and release all the LE COC connections waiting for security */
+    if (p_lcb->le_sec_pending_q)
+    {
+        while (!fixed_queue_is_empty(p_lcb->le_sec_pending_q))
+        {
+            tL2CAP_SEC_DATA *p_buf = (tL2CAP_SEC_DATA*) fixed_queue_try_dequeue(p_lcb->le_sec_pending_q);
+            if (p_buf->p_callback)
+                p_buf->p_callback(p_lcb->remote_bd_addr, p_lcb->transport, p_buf->p_ref_data, BTM_DEV_RESET);
+            osi_free(p_buf);
+        }
+        fixed_queue_free(p_lcb->le_sec_pending_q, NULL);
+        p_lcb->le_sec_pending_q = NULL;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         l2cu_find_lcb_by_bd_addr
+**
+** Description      Look through all active LCBs for a match based on the
+**                  remote BD address.
+**
+** Returns          pointer to matched LCB, or NULL if no match
+**
+*******************************************************************************/
+tL2C_LCB  *l2cu_find_lcb_by_bd_addr (BD_ADDR p_bd_addr, tBT_TRANSPORT transport)
+{
+    int         xx;
+    tL2C_LCB    *p_lcb = &l2cb.lcb_pool[0];
+
+    for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
+    {
+        if ((p_lcb->in_use) &&
+#if (BLE_INCLUDED == TRUE)
+            p_lcb->transport == transport &&
+#endif
+            (!memcmp (p_lcb->remote_bd_addr, p_bd_addr, BD_ADDR_LEN)))
+        {
+            return (p_lcb);
+        }
+    }
+
+    /* If here, no match found */
+    return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_get_conn_role
+**
+** Description      Determine the desired role (master or slave) of a link.
+**                  If already got a slave link, this one must be a master. If
+**                  already got at least 1 link where we are the master, make this
+**                  also a master.
+**
+** Returns          HCI_ROLE_MASTER or HCI_ROLE_SLAVE
+**
+*******************************************************************************/
+uint8_t l2cu_get_conn_role (tL2C_LCB *p_this_lcb)
+{
+    return l2cb.desire_role;
+}
+
+/*******************************************************************************
+**
+** Function         l2c_is_cmd_rejected
+**
+** Description      Checks if cmd_code is command or response
+**                  If a command it will be rejected per spec.
+**                  This function is used when a illegal packet length is detected
+**
+** Returns          bool    - true if cmd_code is a command and it is rejected,
+**                            false if response code. (command not rejected)
+**
+*******************************************************************************/
+bool    l2c_is_cmd_rejected (uint8_t cmd_code, uint8_t id, tL2C_LCB *p_lcb)
+{
+    switch(cmd_code)
+    {
+    case L2CAP_CMD_CONN_REQ:
+    case L2CAP_CMD_CONFIG_REQ:
+    case L2CAP_CMD_DISC_REQ:
+    case L2CAP_CMD_ECHO_REQ:
+    case L2CAP_CMD_INFO_REQ:
+    case L2CAP_CMD_AMP_CONN_REQ:
+    case L2CAP_CMD_AMP_MOVE_REQ:
+    case L2CAP_CMD_BLE_UPDATE_REQ:
+        l2cu_send_peer_cmd_reject (p_lcb, L2CAP_CMD_REJ_MTU_EXCEEDED, id, L2CAP_DEFAULT_MTU, 0);
+        L2CAP_TRACE_WARNING ("Dumping first Command (%d)", cmd_code);
+        return true;
+
+    default:    /* Otherwise a response */
+        return false;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_build_header
+**
+** Description      Builds the L2CAP command packet header
+**
+** Returns          Pointer to allocated packet or NULL if no resources
+**
+*******************************************************************************/
+BT_HDR *l2cu_build_header (tL2C_LCB *p_lcb, uint16_t len, uint8_t cmd, uint8_t id)
+{
+    BT_HDR  *p_buf = (BT_HDR *)osi_malloc(L2CAP_CMD_BUF_SIZE);
+    uint8_t *p;
+
+    p_buf->offset = L2CAP_SEND_CMD_OFFSET;
+    p_buf->len = len + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+    p = (uint8_t *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET;
+
+    /* Put in HCI header - handle + pkt boundary */
+#if (BLE_INCLUDED == TRUE)
+    if (p_lcb->transport == BT_TRANSPORT_LE)
+    {
+        UINT16_TO_STREAM (p, (p_lcb->handle | (L2CAP_PKT_START_NON_FLUSHABLE << L2CAP_PKT_TYPE_SHIFT)));
+    }
+    else
+#endif
+    {
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+        UINT16_TO_STREAM (p, p_lcb->handle | l2cb.non_flushable_pbf);
+#else
+        UINT16_TO_STREAM (p, (p_lcb->handle | (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT)));
+#endif
+    }
+
+    UINT16_TO_STREAM (p, len + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD);
+    UINT16_TO_STREAM (p, len + L2CAP_CMD_OVERHEAD);
+
+#if (BLE_INCLUDED == TRUE)
+    if (p_lcb->transport == BT_TRANSPORT_LE)
+    {
+
+        UINT16_TO_STREAM (p, L2CAP_BLE_SIGNALLING_CID);
+    }
+    else
+#endif
+    {
+        UINT16_TO_STREAM (p, L2CAP_SIGNALLING_CID);
+    }
+
+    /* Put in L2CAP command header */
+    UINT8_TO_STREAM  (p, cmd);
+    UINT8_TO_STREAM  (p, id);
+    UINT16_TO_STREAM (p, len);
+
+    return (p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_adj_id
+**
+** Description      Checks for valid ID based on specified mask
+**                  and adjusts the id if invalid.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_adj_id (tL2C_LCB *p_lcb, uint8_t adj_mask)
+{
+    if ((adj_mask & L2CAP_ADJ_ZERO_ID) && !p_lcb->id)
+    {
+        p_lcb->id++;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_cmd_reject
+**
+** Description      Build and send an L2CAP "command reject" message
+**                  to the peer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_cmd_reject (tL2C_LCB *p_lcb, uint16_t reason, uint8_t rem_id,
+                                uint16_t p1, uint16_t p2)
+{
+    uint16_t param_len;
+    BT_HDR  *p_buf;
+    uint8_t *p;
+
+    /* Put in L2CAP packet header */
+    if (reason == L2CAP_CMD_REJ_MTU_EXCEEDED)
+        param_len = 2;
+    else if (reason == L2CAP_CMD_REJ_INVALID_CID)
+        param_len = 4;
+    else
+        param_len = 0;
+
+    if ((p_buf = l2cu_build_header (p_lcb, (uint16_t) (L2CAP_CMD_REJECT_LEN + param_len), L2CAP_CMD_REJECT, rem_id)) == NULL )
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no buffer cmd_rej");
+        return;
+    }
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+                               L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    UINT16_TO_STREAM (p, reason);
+
+    if (param_len >= 2)
+        UINT16_TO_STREAM (p, p1);
+
+    if (param_len >= 4)
+        UINT16_TO_STREAM (p, p2);
+
+    l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_connect_req
+**
+** Description      Build and send an L2CAP "connection request" message
+**                  to the peer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_connect_req (tL2C_CCB *p_ccb)
+{
+    BT_HDR  *p_buf;
+    uint8_t *p;
+
+    /* Create an identifier for this packet */
+    p_ccb->p_lcb->id++;
+    l2cu_adj_id(p_ccb->p_lcb, L2CAP_ADJ_ID);
+
+    p_ccb->local_id = p_ccb->p_lcb->id;
+
+    if ((p_buf = l2cu_build_header (p_ccb->p_lcb, L2CAP_CONN_REQ_LEN, L2CAP_CMD_CONN_REQ,
+                                    p_ccb->local_id)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no buffer for conn_req");
+        return;
+    }
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET+HCI_DATA_PREAMBLE_SIZE +
+        L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    UINT16_TO_STREAM (p, p_ccb->p_rcb->real_psm);
+    UINT16_TO_STREAM (p, p_ccb->local_cid);
+
+    l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_connect_rsp
+**
+** Description      Build and send an L2CAP "connection response" message
+**                  to the peer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_connect_rsp (tL2C_CCB *p_ccb, uint16_t result, uint16_t status)
+{
+    BT_HDR  *p_buf;
+    uint8_t *p;
+
+    if (result == L2CAP_CONN_PENDING)
+    {
+        /* if we already sent pending response */
+        if (p_ccb->flags & CCB_FLAG_SENT_PENDING)
+            return;
+        else
+            p_ccb->flags |= CCB_FLAG_SENT_PENDING;
+    }
+
+    if ((p_buf=l2cu_build_header(p_ccb->p_lcb, L2CAP_CONN_RSP_LEN, L2CAP_CMD_CONN_RSP, p_ccb->remote_id)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no buffer for conn_rsp");
+        return;
+    }
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET+HCI_DATA_PREAMBLE_SIZE +
+        L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    UINT16_TO_STREAM (p, p_ccb->local_cid);
+    UINT16_TO_STREAM (p, p_ccb->remote_cid);
+    UINT16_TO_STREAM (p, result);
+    UINT16_TO_STREAM (p, status);
+
+    l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         l2cu_reject_connection
+**
+** Description      Build and send an L2CAP "connection response neg" message
+**                  to the peer. This function is called when there is no peer
+**                  CCB (non-existant PSM or no resources).
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_reject_connection (tL2C_LCB *p_lcb, uint16_t remote_cid, uint8_t rem_id, uint16_t result)
+{
+    BT_HDR  *p_buf;
+    uint8_t *p;
+
+    if ((p_buf = l2cu_build_header(p_lcb, L2CAP_CONN_RSP_LEN, L2CAP_CMD_CONN_RSP, rem_id)) == NULL )
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no buffer for conn_req");
+        return;
+    }
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET+HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    UINT16_TO_STREAM (p, 0);                    /* Local CID of 0   */
+    UINT16_TO_STREAM (p, remote_cid);
+    UINT16_TO_STREAM (p, result);
+    UINT16_TO_STREAM (p, 0);                    /* Status of 0      */
+
+    l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_config_req
+**
+** Description      Build and send an L2CAP "configuration request" message
+**                  to the peer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_config_req (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
+{
+    BT_HDR  *p_buf;
+    uint16_t cfg_len=0;
+    uint8_t *p;
+
+    /* Create an identifier for this packet */
+    p_ccb->p_lcb->id++;
+    l2cu_adj_id(p_ccb->p_lcb, L2CAP_ADJ_ID);
+
+    p_ccb->local_id = p_ccb->p_lcb->id;
+
+    if (p_cfg->mtu_present)
+        cfg_len += L2CAP_CFG_MTU_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+    if (p_cfg->flush_to_present)
+        cfg_len += L2CAP_CFG_FLUSH_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+    if (p_cfg->qos_present)
+        cfg_len += L2CAP_CFG_QOS_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+    if (p_cfg->fcr_present)
+        cfg_len += L2CAP_CFG_FCR_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+    if (p_cfg->fcs_present)
+        cfg_len += L2CAP_CFG_FCS_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+    if (p_cfg->ext_flow_spec_present)
+        cfg_len += L2CAP_CFG_EXT_FLOW_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+
+    if ((p_buf = l2cu_build_header (p_ccb->p_lcb, (uint16_t) (L2CAP_CONFIG_REQ_LEN + cfg_len),
+        L2CAP_CMD_CONFIG_REQ, p_ccb->local_id)) == NULL )
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no buffer for conn_req");
+        return;
+    }
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+                               L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    UINT16_TO_STREAM (p, p_ccb->remote_cid);
+    UINT16_TO_STREAM (p, p_cfg->flags);                    /* Flags (continuation) */
+
+    /* Now, put the options */
+    if (p_cfg->mtu_present)
+    {
+        UINT8_TO_STREAM  (p, L2CAP_CFG_TYPE_MTU);
+        UINT8_TO_STREAM  (p, L2CAP_CFG_MTU_OPTION_LEN);
+        UINT16_TO_STREAM (p, p_cfg->mtu);
+    }
+    if (p_cfg->flush_to_present)
+    {
+        UINT8_TO_STREAM  (p, L2CAP_CFG_TYPE_FLUSH_TOUT);
+        UINT8_TO_STREAM  (p, L2CAP_CFG_FLUSH_OPTION_LEN);
+        UINT16_TO_STREAM (p, p_cfg->flush_to);
+    }
+    if (p_cfg->qos_present)
+    {
+        UINT8_TO_STREAM  (p, L2CAP_CFG_TYPE_QOS);
+        UINT8_TO_STREAM  (p, L2CAP_CFG_QOS_OPTION_LEN);
+        UINT8_TO_STREAM  (p, p_cfg->qos.qos_flags);
+        UINT8_TO_STREAM  (p, p_cfg->qos.service_type);
+        UINT32_TO_STREAM (p, p_cfg->qos.token_rate);
+        UINT32_TO_STREAM (p, p_cfg->qos.token_bucket_size);
+        UINT32_TO_STREAM (p, p_cfg->qos.peak_bandwidth);
+        UINT32_TO_STREAM (p, p_cfg->qos.latency);
+        UINT32_TO_STREAM (p, p_cfg->qos.delay_variation);
+    }
+    if (p_cfg->fcr_present)
+    {
+        UINT8_TO_STREAM  (p, L2CAP_CFG_TYPE_FCR);
+        UINT8_TO_STREAM  (p, L2CAP_CFG_FCR_OPTION_LEN);
+        UINT8_TO_STREAM  (p, p_cfg->fcr.mode);
+        UINT8_TO_STREAM  (p, p_cfg->fcr.tx_win_sz);
+        UINT8_TO_STREAM  (p, p_cfg->fcr.max_transmit);
+        UINT16_TO_STREAM (p, p_cfg->fcr.rtrans_tout);
+        UINT16_TO_STREAM (p, p_cfg->fcr.mon_tout);
+        UINT16_TO_STREAM (p, p_cfg->fcr.mps);
+    }
+
+    if (p_cfg->fcs_present)
+    {
+        UINT8_TO_STREAM  (p, L2CAP_CFG_TYPE_FCS);
+        UINT8_TO_STREAM  (p, L2CAP_CFG_FCS_OPTION_LEN);
+        UINT8_TO_STREAM  (p, p_cfg->fcs);
+    }
+
+    if (p_cfg->ext_flow_spec_present)
+    {
+        UINT8_TO_STREAM  (p, L2CAP_CFG_TYPE_EXT_FLOW);
+        UINT8_TO_STREAM  (p, L2CAP_CFG_EXT_FLOW_OPTION_LEN);
+        UINT8_TO_STREAM  (p, p_cfg->ext_flow_spec.id);
+        UINT8_TO_STREAM  (p, p_cfg->ext_flow_spec.stype);
+        UINT16_TO_STREAM (p, p_cfg->ext_flow_spec.max_sdu_size);
+        UINT32_TO_STREAM (p, p_cfg->ext_flow_spec.sdu_inter_time);
+        UINT32_TO_STREAM (p, p_cfg->ext_flow_spec.access_latency);
+        UINT32_TO_STREAM (p, p_cfg->ext_flow_spec.flush_timeout);
+    }
+
+    l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_config_rsp
+**
+** Description      Build and send an L2CAP "configuration response" message
+**                  to the peer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_config_rsp (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
+{
+    BT_HDR  *p_buf;
+    uint16_t cfg_len = 0;
+    uint8_t *p;
+
+    /* Create an identifier for this packet */
+    if (p_cfg->mtu_present)
+        cfg_len += L2CAP_CFG_MTU_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+    if (p_cfg->flush_to_present)
+        cfg_len += L2CAP_CFG_FLUSH_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+    if (p_cfg->qos_present)
+        cfg_len += L2CAP_CFG_QOS_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+    if (p_cfg->fcr_present)
+        cfg_len += L2CAP_CFG_FCR_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+    if (p_cfg->ext_flow_spec_present)
+        cfg_len += L2CAP_CFG_EXT_FLOW_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+
+    if ((p_buf = l2cu_build_header (p_ccb->p_lcb, (uint16_t)(L2CAP_CONFIG_RSP_LEN + cfg_len),
+                                    L2CAP_CMD_CONFIG_RSP, p_ccb->remote_id)) == NULL )
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no buffer for conn_req");
+        return;
+    }
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET+HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    UINT16_TO_STREAM (p, p_ccb->remote_cid);
+    UINT16_TO_STREAM (p, p_cfg->flags);           /* Flags (continuation) Must match request */
+    UINT16_TO_STREAM (p, p_cfg->result);
+
+    /* Now, put the options */
+    if (p_cfg->mtu_present)
+    {
+        UINT8_TO_STREAM  (p, L2CAP_CFG_TYPE_MTU);
+        UINT8_TO_STREAM  (p, L2CAP_CFG_MTU_OPTION_LEN);
+        UINT16_TO_STREAM (p, p_cfg->mtu);
+    }
+    if (p_cfg->flush_to_present)
+    {
+        UINT8_TO_STREAM  (p, L2CAP_CFG_TYPE_FLUSH_TOUT);
+        UINT8_TO_STREAM  (p, L2CAP_CFG_FLUSH_OPTION_LEN);
+        UINT16_TO_STREAM (p, p_cfg->flush_to);
+    }
+    if (p_cfg->qos_present)
+    {
+        UINT8_TO_STREAM  (p, L2CAP_CFG_TYPE_QOS);
+        UINT8_TO_STREAM  (p, L2CAP_CFG_QOS_OPTION_LEN);
+        UINT8_TO_STREAM  (p, p_cfg->qos.qos_flags);
+        UINT8_TO_STREAM  (p, p_cfg->qos.service_type);
+        UINT32_TO_STREAM (p, p_cfg->qos.token_rate);
+        UINT32_TO_STREAM (p, p_cfg->qos.token_bucket_size);
+        UINT32_TO_STREAM (p, p_cfg->qos.peak_bandwidth);
+        UINT32_TO_STREAM (p, p_cfg->qos.latency);
+        UINT32_TO_STREAM (p, p_cfg->qos.delay_variation);
+    }
+    if (p_cfg->fcr_present)
+    {
+        UINT8_TO_STREAM  (p, L2CAP_CFG_TYPE_FCR);
+        UINT8_TO_STREAM  (p, L2CAP_CFG_FCR_OPTION_LEN);
+        UINT8_TO_STREAM  (p, p_cfg->fcr.mode);
+        UINT8_TO_STREAM  (p, p_cfg->fcr.tx_win_sz);
+        UINT8_TO_STREAM  (p, p_cfg->fcr.max_transmit);
+        UINT16_TO_STREAM (p, p_ccb->our_cfg.fcr.rtrans_tout);
+        UINT16_TO_STREAM (p, p_ccb->our_cfg.fcr.mon_tout);
+        UINT16_TO_STREAM (p, p_cfg->fcr.mps);
+    }
+
+    if (p_cfg->ext_flow_spec_present)
+    {
+        UINT8_TO_STREAM  (p, L2CAP_CFG_TYPE_EXT_FLOW);
+        UINT8_TO_STREAM  (p, L2CAP_CFG_EXT_FLOW_OPTION_LEN);
+        UINT8_TO_STREAM  (p, p_cfg->ext_flow_spec.id);
+        UINT8_TO_STREAM  (p, p_cfg->ext_flow_spec.stype);
+        UINT16_TO_STREAM (p, p_cfg->ext_flow_spec.max_sdu_size);
+        UINT32_TO_STREAM (p, p_cfg->ext_flow_spec.sdu_inter_time);
+        UINT32_TO_STREAM (p, p_cfg->ext_flow_spec.access_latency);
+        UINT32_TO_STREAM (p, p_cfg->ext_flow_spec.flush_timeout);
+    }
+
+    l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_config_rej
+**
+** Description      Build and send an L2CAP "configuration reject" message
+**                  to the peer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_config_rej (tL2C_CCB *p_ccb, uint8_t *p_data, uint16_t data_len, uint16_t rej_len)
+{
+    uint16_t len, cfg_len, buf_space, len1;
+    uint8_t *p, *p_hci_len, *p_data_end;
+    uint8_t cfg_code;
+
+    L2CAP_TRACE_DEBUG("l2cu_send_peer_config_rej: data_len=%d, rej_len=%d", data_len, rej_len);
+
+
+    len = BT_HDR_SIZE + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD + L2CAP_CONFIG_RSP_LEN;
+    len1 = 0xFFFF - len;
+    if (rej_len > len1)
+    {
+        L2CAP_TRACE_ERROR ("L2CAP - cfg_rej pkt size exceeds buffer design max limit.");
+        return;
+    }
+
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(len + rej_len);
+    p_buf->offset = L2CAP_SEND_CMD_OFFSET;
+    p = (uint8_t *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET;
+
+    /* Put in HCI header - handle + pkt boundary */
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+    if (HCI_NON_FLUSHABLE_PB_SUPPORTED(BTM_ReadLocalFeatures ()))
+    {
+        UINT16_TO_STREAM (p, (p_ccb->p_lcb->handle | (L2CAP_PKT_START_NON_FLUSHABLE << L2CAP_PKT_TYPE_SHIFT)));
+    }
+    else
+#endif
+    {
+        UINT16_TO_STREAM (p, (p_ccb->p_lcb->handle | (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT)));
+    }
+
+    /* Remember the HCI header length position, and save space for it */
+    p_hci_len = p;
+    p += 2;
+
+    /* Put in L2CAP packet header */
+    UINT16_TO_STREAM (p, L2CAP_CMD_OVERHEAD + L2CAP_CONFIG_RSP_LEN + rej_len);
+    UINT16_TO_STREAM (p, L2CAP_SIGNALLING_CID);
+
+    /* Put in L2CAP command header */
+    UINT8_TO_STREAM  (p, L2CAP_CMD_CONFIG_RSP);
+    UINT8_TO_STREAM  (p, p_ccb->remote_id);
+
+    UINT16_TO_STREAM (p, L2CAP_CONFIG_RSP_LEN + rej_len);
+
+    UINT16_TO_STREAM (p, p_ccb->remote_cid);
+    UINT16_TO_STREAM (p, 0);                    /* Flags = 0 (no continuation) */
+    UINT16_TO_STREAM (p, L2CAP_CFG_UNKNOWN_OPTIONS);
+
+    buf_space = rej_len;
+
+    /* Now, put the rejected options */
+    p_data_end = p_data + data_len;
+    while (p_data < p_data_end)
+    {
+        cfg_code = *p_data;
+        cfg_len = *(p_data + 1);
+
+        switch (cfg_code & 0x7F)
+        {
+            /* skip known options */
+            case L2CAP_CFG_TYPE_MTU:
+            case L2CAP_CFG_TYPE_FLUSH_TOUT:
+            case L2CAP_CFG_TYPE_QOS:
+                p_data += cfg_len + L2CAP_CFG_OPTION_OVERHEAD;
+                break;
+
+            /* unknown options; copy into rsp if not hints */
+            default:
+                /* sanity check option length */
+                if ((cfg_len + L2CAP_CFG_OPTION_OVERHEAD) <= data_len)
+                {
+                    if ((cfg_code & 0x80) == 0)
+                    {
+                        if (buf_space >= (cfg_len + L2CAP_CFG_OPTION_OVERHEAD))
+                        {
+                            memcpy(p, p_data, cfg_len + L2CAP_CFG_OPTION_OVERHEAD);
+                            p += cfg_len + L2CAP_CFG_OPTION_OVERHEAD;
+                            buf_space -= (cfg_len + L2CAP_CFG_OPTION_OVERHEAD);
+                        }
+                        else
+                        {
+                            L2CAP_TRACE_WARNING("L2CAP - cfg_rej exceeds allocated buffer");
+                            p_data = p_data_end; /* force loop exit */
+                            break;
+                        }
+                    }
+                    p_data += cfg_len + L2CAP_CFG_OPTION_OVERHEAD;
+                }
+                /* bad length; force loop exit */
+                else
+                {
+                    p_data = p_data_end;
+                }
+                break;
+        }
+    }
+
+    len = (uint16_t) (p - p_hci_len - 2);
+    UINT16_TO_STREAM (p_hci_len, len);
+
+    p_buf->len = len + 4;
+
+    L2CAP_TRACE_DEBUG ("L2CAP - cfg_rej pkt hci_len=%d, l2cap_len=%d",
+                        len, (L2CAP_CMD_OVERHEAD+L2CAP_CONFIG_RSP_LEN+rej_len));
+
+    l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_disc_req
+**
+** Description      Build and send an L2CAP "disconnect request" message
+**                  to the peer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_disc_req (tL2C_CCB *p_ccb)
+{
+    BT_HDR  *p_buf, *p_buf2;
+    uint8_t *p;
+
+    if ((!p_ccb) || (p_ccb->p_lcb == NULL))
+    {
+        L2CAP_TRACE_ERROR ("%s L2CAP - ccb or lcb invalid", __func__);
+        return;
+    }
+
+    /* Create an identifier for this packet */
+    p_ccb->p_lcb->id++;
+    l2cu_adj_id(p_ccb->p_lcb, L2CAP_ADJ_ID);
+
+    p_ccb->local_id = p_ccb->p_lcb->id;
+
+    if ((p_buf = l2cu_build_header(p_ccb->p_lcb, L2CAP_DISC_REQ_LEN, L2CAP_CMD_DISC_REQ, p_ccb->local_id)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no buffer for disc_req");
+        return;
+    }
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    UINT16_TO_STREAM (p, p_ccb->remote_cid);
+    UINT16_TO_STREAM (p, p_ccb->local_cid);
+
+    /* Move all queued data packets to the LCB. In FCR mode, assume the higher
+       layer checks that all buffers are sent before disconnecting.
+    */
+    if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)
+    {
+        while ((p_buf2 = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->xmit_hold_q)) != NULL)
+        {
+            l2cu_set_acl_hci_header (p_buf2, p_ccb);
+            l2c_link_check_send_pkts (p_ccb->p_lcb, p_ccb, p_buf2);
+        }
+    }
+
+    l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_disc_rsp
+**
+** Description      Build and send an L2CAP "disconnect response" message
+**                  to the peer.
+**
+**                  This function is passed the parameters for the disconnect
+**                  response instead of the CCB address, as it may be called
+**                  to send a disconnect response when there is no CCB.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_disc_rsp (tL2C_LCB *p_lcb, uint8_t remote_id, uint16_t local_cid,
+                              uint16_t remote_cid)
+{
+    BT_HDR  *p_buf;
+    uint8_t *p;
+
+    if ((p_buf=l2cu_build_header(p_lcb, L2CAP_DISC_RSP_LEN, L2CAP_CMD_DISC_RSP, remote_id)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no buffer for disc_rsp");
+        return;
+    }
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    UINT16_TO_STREAM (p, local_cid);
+    UINT16_TO_STREAM (p, remote_cid);
+
+    l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_echo_req
+**
+** Description      Build and send an L2CAP "echo request" message
+**                  to the peer. Note that we do not currently allow
+**                  data in the echo request.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_echo_req (tL2C_LCB *p_lcb, uint8_t *p_data, uint16_t data_len)
+{
+    BT_HDR  *p_buf;
+    uint8_t *p;
+
+    p_lcb->id++;
+    l2cu_adj_id(p_lcb, L2CAP_ADJ_ZERO_ID);  /* check for wrap to '0' */
+
+    if ((p_buf = l2cu_build_header(p_lcb, (uint16_t) (L2CAP_ECHO_REQ_LEN + data_len), L2CAP_CMD_ECHO_REQ, p_lcb->id)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no buffer for echo_req");
+        return;
+    }
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    if (data_len)
+    {
+        ARRAY_TO_STREAM  (p, p_data, data_len);
+    }
+
+    l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_echo_rsp
+**
+** Description      Build and send an L2CAP "echo response" message
+**                  to the peer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_echo_rsp (tL2C_LCB *p_lcb, uint8_t id, uint8_t *p_data, uint16_t data_len)
+{
+    BT_HDR  *p_buf;
+    uint8_t *p;
+    uint16_t maxlen;
+    /* Filter out duplicate IDs or if available buffers are low (intruder checking) */
+    if (!id || id == p_lcb->cur_echo_id)
+    {
+        /* Dump this request since it is illegal */
+        L2CAP_TRACE_WARNING ("L2CAP ignoring duplicate echo request (%d)", id);
+        return;
+    }
+    else
+        p_lcb->cur_echo_id = id;
+
+    uint16_t acl_data_size = controller_get_interface()->get_acl_data_size_classic();
+    uint16_t acl_packet_size = controller_get_interface()->get_acl_packet_size_classic();
+    /* Don't return data if it does not fit in ACL and L2CAP MTU */
+    maxlen = (L2CAP_CMD_BUF_SIZE > acl_packet_size) ?
+               acl_data_size : (uint16_t)L2CAP_CMD_BUF_SIZE;
+    maxlen -= (uint16_t)(BT_HDR_SIZE + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD +
+                L2CAP_CMD_OVERHEAD + L2CAP_ECHO_RSP_LEN);
+
+    if (data_len > maxlen)
+        data_len = 0;
+
+    if ((p_buf = l2cu_build_header (p_lcb, (uint16_t)(L2CAP_ECHO_RSP_LEN + data_len), L2CAP_CMD_ECHO_RSP, id)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no buffer for echo_rsp");
+        return;
+    }
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+                               L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    if (data_len)
+    {
+        ARRAY_TO_STREAM  (p, p_data, data_len);
+    }
+
+    l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_info_req
+**
+** Description      Build and send an L2CAP "info request" message
+**                  to the peer.
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_info_req (tL2C_LCB *p_lcb, uint16_t info_type)
+{
+    BT_HDR  *p_buf;
+    uint8_t *p;
+
+    /* check for wrap and/or BRCM ID */
+    p_lcb->id++;
+    l2cu_adj_id(p_lcb, L2CAP_ADJ_ID);
+
+    if ((p_buf = l2cu_build_header(p_lcb, 2, L2CAP_CMD_INFO_REQ, p_lcb->id)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no buffer for info_req");
+        return;
+    }
+
+    L2CAP_TRACE_EVENT ("l2cu_send_peer_info_req: type 0x%04x", info_type);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET+HCI_DATA_PREAMBLE_SIZE +
+        L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    UINT16_TO_STREAM (p, info_type);
+
+    p_lcb->w4_info_rsp = true;
+    alarm_set_on_queue(p_lcb->info_resp_timer, L2CAP_WAIT_INFO_RSP_TIMEOUT_MS,
+                       l2c_info_resp_timer_timeout, p_lcb,
+                       btu_general_alarm_queue);
+
+    l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_info_rsp
+**
+** Description      Build and send an L2CAP "info response" message
+**                  to the peer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_info_rsp (tL2C_LCB *p_lcb, uint8_t remote_id, uint16_t info_type)
+{
+    BT_HDR  *p_buf;
+    uint8_t *p;
+    uint16_t len = L2CAP_INFO_RSP_LEN;
+
+#if (L2CAP_CONFORMANCE_TESTING == TRUE)
+    if ((info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE)
+        && (l2cb.test_info_resp & (L2CAP_EXTFEA_ENH_RETRANS   | L2CAP_EXTFEA_STREAM_MODE |
+                                   L2CAP_EXTFEA_NO_CRC | L2CAP_EXTFEA_EXT_FLOW_SPEC |
+                                   L2CAP_EXTFEA_FIXED_CHNLS | L2CAP_EXTFEA_EXT_WINDOW |
+                                   L2CAP_EXTFEA_UCD_RECEPTION )) )
+#else
+    if ((info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE)
+        && (L2CAP_EXTFEA_SUPPORTED_MASK & (L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE |
+                                           L2CAP_EXTFEA_NO_CRC |L2CAP_EXTFEA_FIXED_CHNLS |
+                                           L2CAP_EXTFEA_UCD_RECEPTION )) != 0 )
+#endif
+    {
+        len += L2CAP_EXTENDED_FEATURES_ARRAY_SIZE;
+    }
+    else if (info_type == L2CAP_FIXED_CHANNELS_INFO_TYPE)
+    {
+        len += L2CAP_FIXED_CHNL_ARRAY_SIZE;
+    }
+    else if (info_type == L2CAP_CONNLESS_MTU_INFO_TYPE)
+    {
+        len += L2CAP_CONNLESS_MTU_INFO_SIZE;
+    }
+
+    if ((p_buf = l2cu_build_header(p_lcb, len, L2CAP_CMD_INFO_RSP, remote_id)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no buffer for info_rsp");
+        return;
+    }
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+                               L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    UINT16_TO_STREAM (p, info_type);
+
+#if (L2CAP_CONFORMANCE_TESTING == TRUE)
+    if ((info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE)
+        && (l2cb.test_info_resp & ( L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE
+                                  | L2CAP_EXTFEA_UCD_RECEPTION )) )
+#else
+    if ((info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE)
+        && (L2CAP_EXTFEA_SUPPORTED_MASK & ( L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE
+                                          | L2CAP_EXTFEA_UCD_RECEPTION )) != 0 )
+#endif
+    {
+        UINT16_TO_STREAM (p, L2CAP_INFO_RESP_RESULT_SUCCESS);
+#if (BLE_INCLUDED == TRUE)
+        if (p_lcb->transport == BT_TRANSPORT_LE)
+        {
+            /* optional data are not added for now */
+            UINT32_TO_STREAM (p, L2CAP_BLE_EXTFEA_MASK);
+        }
+        else
+#endif
+        {
+#if (L2CAP_CONFORMANCE_TESTING == TRUE)
+        UINT32_TO_STREAM (p, l2cb.test_info_resp);
+#else
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+        UINT32_TO_STREAM (p, L2CAP_EXTFEA_SUPPORTED_MASK | L2CAP_EXTFEA_FIXED_CHNLS);
+#else
+        UINT32_TO_STREAM (p, L2CAP_EXTFEA_SUPPORTED_MASK);
+#endif
+#endif
+        }
+    }
+    else if (info_type == L2CAP_FIXED_CHANNELS_INFO_TYPE)
+    {
+        UINT16_TO_STREAM (p, L2CAP_INFO_RESP_RESULT_SUCCESS);
+        memset (p, 0, L2CAP_FIXED_CHNL_ARRAY_SIZE);
+
+        p[0] = L2CAP_FIXED_CHNL_SIG_BIT;
+
+        if ( L2CAP_EXTFEA_SUPPORTED_MASK & L2CAP_EXTFEA_UCD_RECEPTION )
+        	p[0] |= L2CAP_FIXED_CHNL_CNCTLESS_BIT;
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+        {
+            int xx;
+
+            for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++)
+            {
+                /* Skip fixed channels not used on BR/EDR-ACL link */
+                if((xx >= L2CAP_ATT_CID - L2CAP_FIRST_FIXED_CHNL) &&
+                    (xx <= L2CAP_SMP_CID - L2CAP_FIRST_FIXED_CHNL))
+                    continue;
+
+                if (l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb != NULL)
+                   p[(xx + L2CAP_FIRST_FIXED_CHNL) / 8] |= 1 << ((xx + L2CAP_FIRST_FIXED_CHNL) % 8);
+            }
+        }
+#endif
+    }
+    else if (info_type == L2CAP_CONNLESS_MTU_INFO_TYPE)
+    {
+        UINT16_TO_STREAM (p, L2CAP_INFO_RESP_RESULT_SUCCESS);
+        UINT16_TO_STREAM (p, L2CAP_UCD_MTU);
+    }
+    else
+    {
+        UINT16_TO_STREAM (p, L2CAP_INFO_RESP_RESULT_NOT_SUPPORTED);  /* 'not supported' */
+    }
+
+    l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+/******************************************************************************
+**
+** Function         l2cu_enqueue_ccb
+**
+** Description      queue CCB by priority. The first CCB is highest priority and
+**                  is served at first. The CCB is queued to an LLCB or an LCB.
+**
+** Returns          None
+**
+*******************************************************************************/
+void l2cu_enqueue_ccb (tL2C_CCB *p_ccb)
+{
+    tL2C_CCB        *p_ccb1;
+    tL2C_CCB_Q      *p_q = NULL;
+
+    /* Find out which queue the channel is on
+    */
+    if (p_ccb->p_lcb != NULL)
+        p_q = &p_ccb->p_lcb->ccb_queue;
+
+    if ( (!p_ccb->in_use) || (p_q == NULL) )
+    {
+        L2CAP_TRACE_ERROR ("l2cu_enqueue_ccb  CID: 0x%04x ERROR in_use: %u  p_lcb: 0x%08x",
+                            p_ccb->local_cid, p_ccb->in_use, p_ccb->p_lcb);
+        return;
+    }
+
+    L2CAP_TRACE_DEBUG ("l2cu_enqueue_ccb CID: 0x%04x  priority: %d",
+                        p_ccb->local_cid, p_ccb->ccb_priority);
+
+    /* If the queue is empty, we go at the front */
+    if (!p_q->p_first_ccb)
+    {
+        p_q->p_first_ccb  = p_q->p_last_ccb   = p_ccb;
+        p_ccb->p_next_ccb = p_ccb->p_prev_ccb = NULL;
+    }
+    else
+    {
+        p_ccb1 = p_q->p_first_ccb;
+
+        while (p_ccb1 != NULL)
+        {
+            /* Insert new ccb at the end of the same priority. Lower number, higher priority */
+            if (p_ccb->ccb_priority < p_ccb1->ccb_priority)
+            {
+                /* Are we at the head of the queue ? */
+                if (p_ccb1 == p_q->p_first_ccb)
+                    p_q->p_first_ccb = p_ccb;
+                else
+                    p_ccb1->p_prev_ccb->p_next_ccb  = p_ccb;
+
+                p_ccb->p_next_ccb  = p_ccb1;
+                p_ccb->p_prev_ccb  = p_ccb1->p_prev_ccb;
+                p_ccb1->p_prev_ccb = p_ccb;
+                break;
+            }
+
+            p_ccb1 = p_ccb1->p_next_ccb;
+        }
+
+        /* If we are lower then anyone in the list, we go at the end */
+        if (!p_ccb1)
+        {
+            /* add new ccb at the end of the list */
+            p_q->p_last_ccb->p_next_ccb = p_ccb;
+
+            p_ccb->p_next_ccb   = NULL;
+            p_ccb->p_prev_ccb   = p_q->p_last_ccb;
+            p_q->p_last_ccb = p_ccb;
+        }
+    }
+
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+    /* Adding CCB into round robin service table of its LCB */
+    if (p_ccb->p_lcb != NULL)
+    {
+        /* if this is the first channel in this priority group */
+        if (p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb == 0 )
+        {
+        	/* Set the first channel to this CCB */
+            p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb = p_ccb;
+        	/* Set the next serving channel in this group to this CCB */
+            p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb = p_ccb;
+        	/* Initialize quota of this priority group based on its priority */
+            p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].quota = L2CAP_GET_PRIORITY_QUOTA(p_ccb->ccb_priority);
+        }
+        /* increase number of channels in this group */
+        p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb++;
+    }
+#endif
+
+}
+
+/******************************************************************************
+**
+** Function         l2cu_dequeue_ccb
+**
+** Description      dequeue CCB from a queue
+**
+** Returns          -
+**
+*******************************************************************************/
+void l2cu_dequeue_ccb (tL2C_CCB *p_ccb)
+{
+    tL2C_CCB_Q      *p_q = NULL;
+
+    L2CAP_TRACE_DEBUG ("l2cu_dequeue_ccb  CID: 0x%04x", p_ccb->local_cid);
+
+    /* Find out which queue the channel is on
+    */
+    if (p_ccb->p_lcb != NULL)
+        p_q = &p_ccb->p_lcb->ccb_queue;
+
+    if ( (!p_ccb->in_use) || (p_q == NULL) || (p_q->p_first_ccb == NULL) )
+    {
+        L2CAP_TRACE_ERROR ("l2cu_dequeue_ccb  CID: 0x%04x ERROR in_use: %u  p_lcb: 0x%08x  p_q: 0x%08x  p_q->p_first_ccb: 0x%08x",
+                            p_ccb->local_cid, p_ccb->in_use, p_ccb->p_lcb, p_q, p_q ? p_q->p_first_ccb : 0);
+        return;
+    }
+
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+    /* Removing CCB from round robin service table of its LCB */
+    if (p_ccb->p_lcb != NULL)
+    {
+        /* decrease number of channels in this priority group */
+        p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb--;
+
+        /* if it was the last channel in the priority group */
+        if (p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb == 0 )
+        {
+            p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb = NULL;
+            p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb = NULL;
+        }
+        else
+        {
+            /* if it is the first channel of this group */
+            if ( p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb == p_ccb )
+            {
+                p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb = p_ccb->p_next_ccb;
+            }
+            /* if it is the next serving channel of this group */
+            if ( p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb == p_ccb )
+            {
+                /* simply, start serving from the first channel */
+                p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb
+                    = p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb;
+            }
+        }
+    }
+#endif
+
+    if (p_ccb == p_q->p_first_ccb)
+    {
+        /* We are removing the first in a queue */
+        p_q->p_first_ccb = p_ccb->p_next_ccb;
+
+        if (p_q->p_first_ccb)
+            p_q->p_first_ccb->p_prev_ccb = NULL;
+        else
+            p_q->p_last_ccb = NULL;
+    }
+    else if (p_ccb == p_q->p_last_ccb)
+    {
+        /* We are removing the last in a queue */
+        p_q->p_last_ccb = p_ccb->p_prev_ccb;
+        p_q->p_last_ccb->p_next_ccb = NULL;
+    }
+    else
+    {
+        /* In the middle of a chain. */
+        p_ccb->p_prev_ccb->p_next_ccb = p_ccb->p_next_ccb;
+        p_ccb->p_next_ccb->p_prev_ccb = p_ccb->p_prev_ccb;
+    }
+
+    p_ccb->p_next_ccb = p_ccb->p_prev_ccb = NULL;
+}
+
+/******************************************************************************
+**
+** Function         l2cu_change_pri_ccb
+**
+** Description
+**
+** Returns          -
+**
+*******************************************************************************/
+void l2cu_change_pri_ccb (tL2C_CCB *p_ccb, tL2CAP_CHNL_PRIORITY priority)
+{
+    if (p_ccb->ccb_priority != priority)
+    {
+        /* If CCB is not the only guy on the queue */
+        if ( (p_ccb->p_next_ccb != NULL) || (p_ccb->p_prev_ccb != NULL) )
+        {
+            L2CAP_TRACE_DEBUG ("Update CCB list in logical link");
+
+            /* Remove CCB from queue and re-queue it at new priority */
+            l2cu_dequeue_ccb (p_ccb);
+
+            p_ccb->ccb_priority = priority;
+            l2cu_enqueue_ccb (p_ccb);
+        }
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+        else
+        {
+        	/* If CCB is the only guy on the queue, no need to re-enqueue */
+            /* update only round robin service data */
+            p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb = 0;
+            p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb = NULL;
+            p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb = NULL;
+
+            p_ccb->ccb_priority = priority;
+
+            p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb = p_ccb;
+            p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb = p_ccb;
+            p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].quota = L2CAP_GET_PRIORITY_QUOTA(p_ccb->ccb_priority);
+            p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb = 1;
+        }
+#endif
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_allocate_ccb
+**
+** Description      This function allocates a Channel Control Block and
+**                  attaches it to a link control block. The local CID
+**                  is also assigned.
+**
+** Returns          pointer to CCB, or NULL if none
+**
+*******************************************************************************/
+tL2C_CCB *l2cu_allocate_ccb (tL2C_LCB *p_lcb, uint16_t cid)
+{
+    tL2C_CCB    *p_ccb;
+    tL2C_CCB    *p_prev;
+
+    L2CAP_TRACE_DEBUG ("l2cu_allocate_ccb: cid 0x%04x", cid);
+
+    if (!l2cb.p_free_ccb_first)
+        return (NULL);
+
+    /* If a CID was passed in, use that, else take the first free one */
+    if (cid == 0)
+    {
+        p_ccb = l2cb.p_free_ccb_first;
+        l2cb.p_free_ccb_first = p_ccb->p_next_ccb;
+    }
+    else
+    {
+        p_prev = NULL;
+
+        p_ccb = &l2cb.ccb_pool[cid - L2CAP_BASE_APPL_CID];
+
+        if (p_ccb == l2cb.p_free_ccb_first)
+            l2cb.p_free_ccb_first = p_ccb->p_next_ccb;
+        else
+        {
+            for (p_prev = l2cb.p_free_ccb_first; p_prev != NULL; p_prev = p_prev->p_next_ccb)
+            {
+                if (p_prev->p_next_ccb == p_ccb)
+                {
+                    p_prev->p_next_ccb = p_ccb->p_next_ccb;
+
+                    if (p_ccb == l2cb.p_free_ccb_last)
+                        l2cb.p_free_ccb_last = p_prev;
+
+                    break;
+                }
+            }
+            if (p_prev == NULL)
+            {
+                L2CAP_TRACE_ERROR ("l2cu_allocate_ccb: could not find CCB for CID 0x%04x in the free list", cid);
+                return NULL;
+            }
+        }
+    }
+
+    p_ccb->p_next_ccb = p_ccb->p_prev_ccb = NULL;
+
+    p_ccb->in_use = true;
+
+    /* Get a CID for the connection */
+    p_ccb->local_cid = L2CAP_BASE_APPL_CID + (uint16_t)(p_ccb - l2cb.ccb_pool);
+
+    p_ccb->p_lcb = p_lcb;
+    p_ccb->p_rcb = NULL;
+    p_ccb->should_free_rcb = false;
+
+    /* Set priority then insert ccb into LCB queue (if we have an LCB) */
+    p_ccb->ccb_priority = L2CAP_CHNL_PRIORITY_LOW;
+
+    if (p_lcb)
+        l2cu_enqueue_ccb (p_ccb);
+
+    /* clear what peer wants to configure */
+    p_ccb->peer_cfg_bits = 0;
+
+    /* Put in default values for configuration */
+    memset (&p_ccb->our_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+    memset (&p_ccb->peer_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+    /* Put in default values for local/peer configurations */
+    p_ccb->our_cfg.flush_to              = p_ccb->peer_cfg.flush_to              = L2CAP_DEFAULT_FLUSH_TO;
+    p_ccb->our_cfg.mtu                   = p_ccb->peer_cfg.mtu                   = L2CAP_DEFAULT_MTU;
+    p_ccb->our_cfg.qos.service_type      = p_ccb->peer_cfg.qos.service_type      = L2CAP_DEFAULT_SERV_TYPE;
+    p_ccb->our_cfg.qos.token_rate        = p_ccb->peer_cfg.qos.token_rate        = L2CAP_DEFAULT_TOKEN_RATE;
+    p_ccb->our_cfg.qos.token_bucket_size = p_ccb->peer_cfg.qos.token_bucket_size = L2CAP_DEFAULT_BUCKET_SIZE;
+    p_ccb->our_cfg.qos.peak_bandwidth    = p_ccb->peer_cfg.qos.peak_bandwidth    = L2CAP_DEFAULT_PEAK_BANDWIDTH;
+    p_ccb->our_cfg.qos.latency           = p_ccb->peer_cfg.qos.latency           = L2CAP_DEFAULT_LATENCY;
+    p_ccb->our_cfg.qos.delay_variation   = p_ccb->peer_cfg.qos.delay_variation   = L2CAP_DEFAULT_DELAY;
+
+    p_ccb->bypass_fcs = 0;
+    memset (&p_ccb->ertm_info, 0, sizeof(tL2CAP_ERTM_INFO));
+    p_ccb->peer_cfg_already_rejected = false;
+    p_ccb->fcr_cfg_tries         = L2CAP_MAX_FCR_CFG_TRIES;
+
+    alarm_free(p_ccb->fcrb.ack_timer);
+    p_ccb->fcrb.ack_timer = alarm_new("l2c_fcrb.ack_timer");
+
+   /*  CSP408639 Fix: When L2CAP send amp move channel request or receive
+     * L2CEVT_AMP_MOVE_REQ do following sequence. Send channel move
+     * request -> Stop retrans/monitor timer -> Change channel state to CST_AMP_MOVING. */
+    alarm_free(p_ccb->fcrb.mon_retrans_timer);
+    p_ccb->fcrb.mon_retrans_timer = alarm_new("l2c_fcrb.mon_retrans_timer");
+
+    p_ccb->ertm_info.preferred_mode  = L2CAP_FCR_BASIC_MODE;        /* Default mode for channel is basic mode */
+    p_ccb->ertm_info.allowed_modes   = L2CAP_FCR_CHAN_OPT_BASIC;    /* Default mode for channel is basic mode */
+    p_ccb->ertm_info.fcr_rx_buf_size = L2CAP_FCR_RX_BUF_SIZE;
+    p_ccb->ertm_info.fcr_tx_buf_size = L2CAP_FCR_TX_BUF_SIZE;
+    p_ccb->ertm_info.user_rx_buf_size = L2CAP_USER_RX_BUF_SIZE;
+    p_ccb->ertm_info.user_tx_buf_size = L2CAP_USER_TX_BUF_SIZE;
+    p_ccb->max_rx_mtu                = L2CAP_MTU_SIZE;
+    p_ccb->tx_mps                    = L2CAP_FCR_TX_BUF_SIZE - 32;
+
+    p_ccb->xmit_hold_q  = fixed_queue_new(SIZE_MAX);
+    p_ccb->fcrb.srej_rcv_hold_q = fixed_queue_new(SIZE_MAX);
+    p_ccb->fcrb.retrans_q = fixed_queue_new(SIZE_MAX);
+    p_ccb->fcrb.waiting_for_ack_q = fixed_queue_new(SIZE_MAX);
+
+    p_ccb->cong_sent    = false;
+    p_ccb->buff_quota   = 2;                /* This gets set after config */
+
+    /* If CCB was reserved Config_Done can already have some value */
+    if (cid == 0)
+        p_ccb->config_done  = 0;
+    else
+    {
+        L2CAP_TRACE_DEBUG ("l2cu_allocate_ccb: cid 0x%04x config_done:0x%x", cid, p_ccb->config_done);
+    }
+
+    p_ccb->chnl_state   = CST_CLOSED;
+    p_ccb->flags        = 0;
+    p_ccb->tx_data_rate = L2CAP_CHNL_DATA_RATE_LOW;
+    p_ccb->rx_data_rate = L2CAP_CHNL_DATA_RATE_LOW;
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+    p_ccb->is_flushable = false;
+#endif
+
+    alarm_free(p_ccb->l2c_ccb_timer);
+    p_ccb->l2c_ccb_timer = alarm_new("l2c.l2c_ccb_timer");
+
+    l2c_link_adjust_chnl_allocation ();
+
+    return (p_ccb);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_start_post_bond_timer
+**
+** Description      This function starts the ACL Link inactivity timer after
+**                  dedicated bonding
+**                  This timer can be longer than the normal link inactivity
+**                  timer for some platforms.
+**
+** Returns          bool     - true if idle timer started or disconnect initiated
+**                             false if there's one or more pending CCB's exist
+**
+*******************************************************************************/
+bool    l2cu_start_post_bond_timer (uint16_t handle)
+{
+    tL2C_LCB *p_lcb = l2cu_find_lcb_by_handle(handle);
+
+    if (!p_lcb)
+        return (true);
+
+    p_lcb->is_bonding = false;
+
+    /* Only start timer if no control blocks allocated */
+    if (p_lcb->ccb_queue.p_first_ccb != NULL)
+        return (false);
+
+    /* If no channels on the connection, start idle timeout */
+    if ((p_lcb->link_state == LST_CONNECTED) ||
+        (p_lcb->link_state == LST_CONNECTING) ||
+        (p_lcb->link_state == LST_DISCONNECTING)) {
+        period_ms_t timeout_ms = L2CAP_BONDING_TIMEOUT * 1000;
+
+        if (p_lcb->idle_timeout == 0) {
+            btsnd_hcic_disconnect (p_lcb->handle, HCI_ERR_PEER_USER);
+            p_lcb->link_state = LST_DISCONNECTING;
+            timeout_ms = L2CAP_LINK_DISCONNECT_TIMEOUT_MS;
+        }
+        alarm_set_on_queue(p_lcb->l2c_lcb_timer, timeout_ms,
+                           l2c_lcb_timer_timeout, p_lcb,
+                           btu_general_alarm_queue);
+        return (true);
+    }
+
+    return (false);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_release_ccb
+**
+** Description      This function releases a Channel Control Block. The timer
+**                  is stopped, any attached buffers freed, and the CCB is removed
+**                  from the link control block.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_release_ccb (tL2C_CCB *p_ccb)
+{
+    tL2C_LCB    *p_lcb = p_ccb->p_lcb;
+    tL2C_RCB    *p_rcb = p_ccb->p_rcb;
+
+    L2CAP_TRACE_DEBUG ("l2cu_release_ccb: cid 0x%04x  in_use: %u", p_ccb->local_cid, p_ccb->in_use);
+
+    /* If already released, could be race condition */
+    if (!p_ccb->in_use)
+        return;
+
+    if (p_rcb && (p_rcb->psm != p_rcb->real_psm))
+    {
+        btm_sec_clr_service_by_psm(p_rcb->psm);
+    }
+
+    if (p_ccb->should_free_rcb)
+    {
+        osi_free(p_rcb);
+        p_ccb->p_rcb = NULL;
+        p_ccb->should_free_rcb = false;
+    }
+
+    btm_sec_clr_temp_auth_service (p_lcb->remote_bd_addr);
+
+    /* Free the timer */
+    alarm_free(p_ccb->l2c_ccb_timer);
+    p_ccb->l2c_ccb_timer = NULL;
+
+    fixed_queue_free(p_ccb->xmit_hold_q, osi_free);
+    p_ccb->xmit_hold_q = NULL;
+
+    l2c_fcr_cleanup (p_ccb);
+
+    /* Channel may not be assigned to any LCB if it was just pre-reserved */
+    if ( (p_lcb) &&
+         ( (p_ccb->local_cid >= L2CAP_BASE_APPL_CID)
+#if (L2CAP_UCD_INCLUDED == TRUE)
+         ||(p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID)
+#endif
+         )
+       )
+    {
+        l2cu_dequeue_ccb (p_ccb);
+
+        /* Delink the CCB from the LCB */
+        p_ccb->p_lcb = NULL;
+    }
+
+    /* Put the CCB back on the free pool */
+    if (!l2cb.p_free_ccb_first)
+    {
+        l2cb.p_free_ccb_first = p_ccb;
+        l2cb.p_free_ccb_last  = p_ccb;
+        p_ccb->p_next_ccb     = NULL;
+        p_ccb->p_prev_ccb     = NULL;
+    }
+    else
+    {
+        p_ccb->p_next_ccb  = NULL;
+        p_ccb->p_prev_ccb  = l2cb.p_free_ccb_last;
+        l2cb.p_free_ccb_last->p_next_ccb = p_ccb;
+        l2cb.p_free_ccb_last  = p_ccb;
+    }
+
+    /* Flag as not in use */
+    p_ccb->in_use = false;
+
+    /* If no channels on the connection, start idle timeout */
+    if ((p_lcb) && p_lcb->in_use && (p_lcb->link_state == LST_CONNECTED))
+    {
+        if (!p_lcb->ccb_queue.p_first_ccb)
+        {
+            l2cu_no_dynamic_ccbs (p_lcb);
+        }
+        else
+        {
+            /* Link is still active, adjust channel quotas. */
+            l2c_link_adjust_chnl_allocation ();
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_find_ccb_by_remote_cid
+**
+** Description      Look through all active CCBs on a link for a match based
+**                  on the remote CID.
+**
+** Returns          pointer to matched CCB, or NULL if no match
+**
+*******************************************************************************/
+tL2C_CCB *l2cu_find_ccb_by_remote_cid (tL2C_LCB *p_lcb, uint16_t remote_cid)
+{
+    tL2C_CCB    *p_ccb;
+
+    /* If LCB is NULL, look through all active links */
+    if (!p_lcb)
+    {
+        return NULL;
+    }
+    else
+    {
+        for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
+            if ((p_ccb->in_use) && (p_ccb->remote_cid == remote_cid))
+                return (p_ccb);
+    }
+
+    /* If here, no match found */
+    return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_allocate_rcb
+**
+** Description      Look through the Registration Control Blocks for a free
+**                  one.
+**
+** Returns          Pointer to the RCB or NULL if not found
+**
+*******************************************************************************/
+tL2C_RCB *l2cu_allocate_rcb (uint16_t psm)
+{
+    tL2C_RCB    *p_rcb = &l2cb.rcb_pool[0];
+    uint16_t    xx;
+
+    for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++)
+    {
+        if (!p_rcb->in_use)
+        {
+            p_rcb->in_use = true;
+            p_rcb->psm    = psm;
+#if (L2CAP_UCD_INCLUDED == TRUE)
+            p_rcb->ucd.state = L2C_UCD_STATE_UNUSED;
+#endif
+            return (p_rcb);
+        }
+    }
+
+    /* If here, no free RCB found */
+    return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_allocate_ble_rcb
+**
+** Description      Look through the BLE Registration Control Blocks for a free
+**                  one.
+**
+** Returns          Pointer to the BLE RCB or NULL if not found
+**
+*******************************************************************************/
+tL2C_RCB *l2cu_allocate_ble_rcb (uint16_t psm)
+{
+    tL2C_RCB    *p_rcb = &l2cb.ble_rcb_pool[0];
+    uint16_t    xx;
+
+    for (xx = 0; xx < BLE_MAX_L2CAP_CLIENTS; xx++, p_rcb++)
+    {
+        if (!p_rcb->in_use)
+        {
+            p_rcb->in_use = true;
+            p_rcb->psm    = psm;
+#if (L2CAP_UCD_INCLUDED == TRUE)
+            p_rcb->ucd.state = L2C_UCD_STATE_UNUSED;
+#endif
+            return (p_rcb);
+        }
+    }
+
+    /* If here, no free RCB found */
+    return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_release_rcb
+**
+** Description      Mark an RCB as no longet in use
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_release_rcb (tL2C_RCB *p_rcb)
+{
+    p_rcb->in_use = false;
+    p_rcb->psm    = 0;
+}
+
+
+/*******************************************************************************
+**
+** Function         l2cu_disconnect_chnl
+**
+** Description      Disconnect a channel. Typically, this is due to either
+**                  receiving a bad configuration,  bad packet or max_retries expiring.
+**
+*******************************************************************************/
+void l2cu_disconnect_chnl (tL2C_CCB *p_ccb)
+{
+    uint16_t    local_cid = p_ccb->local_cid;
+
+    if (local_cid >= L2CAP_BASE_APPL_CID)
+    {
+        tL2CA_DISCONNECT_IND_CB   *p_disc_cb = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+
+        L2CAP_TRACE_WARNING ("L2CAP - disconnect_chnl CID: 0x%04x", local_cid);
+
+        l2cu_send_peer_disc_req (p_ccb);
+
+        l2cu_release_ccb (p_ccb);
+
+        (*p_disc_cb)(local_cid, false);
+    }
+    else
+    {
+        /* failure on the AMP channel, probably need to disconnect ACL */
+        L2CAP_TRACE_ERROR ("L2CAP - disconnect_chnl CID: 0x%04x Ignored", local_cid);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         l2cu_find_rcb_by_psm
+**
+** Description      Look through the Registration Control Blocks to see if
+**                  anyone registered to handle the PSM in question
+**
+** Returns          Pointer to the RCB or NULL if not found
+**
+*******************************************************************************/
+tL2C_RCB *l2cu_find_rcb_by_psm (uint16_t psm)
+{
+    tL2C_RCB    *p_rcb = &l2cb.rcb_pool[0];
+    uint16_t    xx;
+
+    for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++)
+    {
+        if ((p_rcb->in_use) && (p_rcb->psm == psm))
+            return (p_rcb);
+    }
+
+    /* If here, no match found */
+    return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_find_ble_rcb_by_psm
+**
+** Description      Look through the BLE Registration Control Blocks to see if
+**                  anyone registered to handle the PSM in question
+**
+** Returns          Pointer to the BLE RCB or NULL if not found
+**
+*******************************************************************************/
+tL2C_RCB *l2cu_find_ble_rcb_by_psm (uint16_t psm)
+{
+    tL2C_RCB    *p_rcb = &l2cb.ble_rcb_pool[0];
+    uint16_t    xx;
+
+    for (xx = 0; xx < BLE_MAX_L2CAP_CLIENTS; xx++, p_rcb++)
+    {
+        if ((p_rcb->in_use) && (p_rcb->psm == psm))
+            return (p_rcb);
+    }
+
+    /* If here, no match found */
+    return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_process_peer_cfg_req
+**
+** Description      This function is called when the peer sends us a "config request"
+**                  message. It extracts the configuration of interest and saves
+**                  it in the CCB.
+**
+**                  Note:  Negotiation of the FCR channel type is handled internally,
+**                         all others are passed to the upper layer.
+**
+** Returns          uint8_t - L2CAP_PEER_CFG_OK if passed to upper layer,
+**                          L2CAP_PEER_CFG_UNACCEPTABLE if automatically responded to
+**                              because parameters are unnacceptable from a specification
+**                              point of view.
+**                          L2CAP_PEER_CFG_DISCONNECT if no compatible channel modes
+**                              between the two devices, and shall be closed.
+**
+*******************************************************************************/
+uint8_t l2cu_process_peer_cfg_req (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
+{
+    bool     mtu_ok      = true;
+    bool     qos_type_ok = true;
+    bool     flush_to_ok = true;
+    bool     fcr_ok      = true;
+    uint8_t  fcr_status;
+
+    /* Ignore FCR parameters for basic mode */
+    if (!p_cfg->fcr_present)
+        p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE;
+
+    /* Save the MTU that our peer can receive */
+    if (p_cfg->mtu_present)
+    {
+        /* Make sure MTU is at least the minimum */
+        if (p_cfg->mtu >= L2CAP_MIN_MTU)
+        {
+            /* In basic mode, limit the MTU to our buffer size */
+            if ( (p_cfg->fcr_present == false) && (p_cfg->mtu > L2CAP_MTU_SIZE) )
+                p_cfg->mtu = L2CAP_MTU_SIZE;
+
+            /* Save the accepted value in case of renegotiation */
+            p_ccb->peer_cfg.mtu = p_cfg->mtu;
+            p_ccb->peer_cfg.mtu_present = true;
+            p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_MTU;
+        }
+        else    /* Illegal MTU value */
+        {
+            p_cfg->mtu = L2CAP_MIN_MTU;
+            mtu_ok     = false;
+        }
+    }
+    /* Reload mtu from a previously accepted config request */
+    else if (p_ccb->peer_cfg.mtu_present)
+    {
+        p_cfg->mtu_present = true;
+        p_cfg->mtu = p_ccb->peer_cfg.mtu;
+    }
+
+    /* Verify that the flush timeout is a valid value (0 is illegal) */
+    if (p_cfg->flush_to_present)
+    {
+        if (!p_cfg->flush_to)
+        {
+            p_cfg->flush_to = 0xFFFF;   /* Infinite retransmissions (spec default) */
+            flush_to_ok     = false;
+        }
+        else    /* Save the accepted value in case of renegotiation */
+        {
+            p_ccb->peer_cfg.flush_to_present = true;
+            p_ccb->peer_cfg.flush_to = p_cfg->flush_to;
+            p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_FLUSH_TO;
+        }
+    }
+    /* Reload flush_to from a previously accepted config request */
+    else if (p_ccb->peer_cfg.flush_to_present)
+    {
+        p_cfg->flush_to_present = true;
+        p_cfg->flush_to = p_ccb->peer_cfg.flush_to;
+    }
+
+    /* Save the QOS settings the the peer is using */
+    if (p_cfg->qos_present)
+    {
+        /* Make sure service type is not a reserved value; otherwise let upper
+           layer decide if acceptable
+        */
+        if (p_cfg->qos.service_type <= GUARANTEED)
+        {
+            p_ccb->peer_cfg.qos         = p_cfg->qos;
+            p_ccb->peer_cfg.qos_present = true;
+            p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_QOS;
+        }
+        else    /* Illegal service type value */
+        {
+            p_cfg->qos.service_type = BEST_EFFORT;
+            qos_type_ok             = false;
+        }
+    }
+    /* Reload QOS from a previously accepted config request */
+    else if (p_ccb->peer_cfg.qos_present)
+    {
+        p_cfg->qos_present = true;
+        p_cfg->qos         = p_ccb->peer_cfg.qos;
+    }
+
+    if ((fcr_status = l2c_fcr_process_peer_cfg_req (p_ccb, p_cfg)) == L2CAP_PEER_CFG_DISCONNECT)
+    {
+        /* Notify caller to disconnect the channel (incompatible modes) */
+        p_cfg->result = L2CAP_CFG_FAILED_NO_REASON;
+        p_cfg->mtu_present = p_cfg->qos_present = p_cfg->flush_to_present = 0;
+
+        return (L2CAP_PEER_CFG_DISCONNECT);
+    }
+
+    fcr_ok = (fcr_status == L2CAP_PEER_CFG_OK);
+
+    /* Return any unacceptable parameters */
+    if (mtu_ok && flush_to_ok && qos_type_ok && fcr_ok)
+    {
+        l2cu_adjust_out_mps (p_ccb);
+        return (L2CAP_PEER_CFG_OK);
+    }
+    else
+    {
+        p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+
+        if (mtu_ok)
+            p_cfg->mtu_present = false;
+        if (flush_to_ok)
+            p_cfg->flush_to_present = false;
+        if (qos_type_ok)
+            p_cfg->qos_present = false;
+        if (fcr_ok)
+            p_cfg->fcr_present = false;
+
+        return (L2CAP_PEER_CFG_UNACCEPTABLE);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         l2cu_process_peer_cfg_rsp
+**
+** Description      This function is called when the peer sends us a "config response"
+**                  message. It extracts the configuration of interest and saves
+**                  it in the CCB.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_process_peer_cfg_rsp (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
+{
+    /* If we wanted QoS and the peer sends us a positive response with QoS, use his values */
+    if ( (p_cfg->qos_present) && (p_ccb->our_cfg.qos_present) )
+        p_ccb->our_cfg.qos = p_cfg->qos;
+
+    if (p_cfg->fcr_present)
+    {
+        /* Save the retransmission and monitor timeout values */
+        if (p_cfg->fcr.mode == L2CAP_FCR_ERTM_MODE)
+        {
+            p_ccb->peer_cfg.fcr.rtrans_tout = p_cfg->fcr.rtrans_tout;
+            p_ccb->peer_cfg.fcr.mon_tout = p_cfg->fcr.mon_tout;
+        }
+
+        /* Calculate the max number of packets for which we can delay sending an ack */
+        if (p_cfg->fcr.tx_win_sz < p_ccb->our_cfg.fcr.tx_win_sz)
+            p_ccb->fcrb.max_held_acks = p_cfg->fcr.tx_win_sz / 3;
+        else
+            p_ccb->fcrb.max_held_acks = p_ccb->our_cfg.fcr.tx_win_sz / 3;
+
+        L2CAP_TRACE_DEBUG ("l2cu_process_peer_cfg_rsp(): peer tx_win_sz: %d, our tx_win_sz: %d, max_held_acks: %d",
+                             p_cfg->fcr.tx_win_sz, p_ccb->our_cfg.fcr.tx_win_sz, p_ccb->fcrb.max_held_acks);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_process_our_cfg_req
+**
+** Description      This function is called when we send a "config request"
+**                  message. It extracts the configuration of interest and saves
+**                  it in the CCB.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_process_our_cfg_req (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
+{
+    tL2C_LCB    *p_lcb;
+    uint16_t    hci_flush_to;
+
+    /* Save the QOS settings we are using for transmit */
+    if (p_cfg->qos_present)
+    {
+        p_ccb->our_cfg.qos_present = true;
+        p_ccb->our_cfg.qos         = p_cfg->qos;
+    }
+
+    if (p_cfg->fcr_present)
+    {
+        /* Override FCR options if attempting streaming or basic */
+        if (p_cfg->fcr.mode == L2CAP_FCR_BASIC_MODE)
+            memset(&p_cfg->fcr, 0, sizeof(tL2CAP_FCR_OPTS));
+        else
+        {
+            /* On BR/EDR, timer values are zero in config request */
+            /* On class 2 AMP, timer value in config request shall be non-0 processing time */
+            /*                 timer value in config response shall be greater than received processing time */
+            p_cfg->fcr.mon_tout = p_cfg->fcr.rtrans_tout = 0;
+
+            if (p_cfg->fcr.mode == L2CAP_FCR_STREAM_MODE)
+                p_cfg->fcr.max_transmit = p_cfg->fcr.tx_win_sz = 0;
+        }
+
+        /* Set the threshold to send acks (may be updated in the cfg response) */
+        p_ccb->fcrb.max_held_acks = p_cfg->fcr.tx_win_sz / 3;
+
+        /* Include FCS option only if peer can handle it */
+        if (p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_NO_CRC)
+        {
+            /* FCS check can be bypassed if peer also desires to bypass */
+            if (p_cfg->fcs_present && p_cfg->fcs == L2CAP_CFG_FCS_BYPASS)
+                p_ccb->bypass_fcs |= L2CAP_CFG_FCS_OUR;
+        }
+        else
+            p_cfg->fcs_present = false;
+    }
+    else
+    {
+        p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE;
+    }
+
+    p_ccb->our_cfg.fcr.mode    = p_cfg->fcr.mode;
+    p_ccb->our_cfg.fcr_present = p_cfg->fcr_present;
+
+    /* Check the flush timeout. If it is lower than the current one used */
+    /* then we need to adjust the flush timeout sent to the controller   */
+    if (p_cfg->flush_to_present)
+    {
+        if ((p_cfg->flush_to == 0)||(p_cfg->flush_to == L2CAP_NO_AUTOMATIC_FLUSH))
+        {
+            /* don't send invalid flush timeout */
+            /* SPEC: The sender of the Request shall specify its flush timeout value */
+            /*       if it differs from the default value of 0xFFFF                  */
+            p_cfg->flush_to_present = false;
+        }
+        else
+        {
+            p_ccb->our_cfg.flush_to = p_cfg->flush_to;
+            p_lcb = p_ccb->p_lcb;
+
+            if (p_cfg->flush_to < p_lcb->link_flush_tout)
+            {
+                p_lcb->link_flush_tout = p_cfg->flush_to;
+
+                /* If the timeout is within range of HCI, set the flush timeout */
+                if (p_cfg->flush_to <= ((HCI_MAX_AUTO_FLUSH_TOUT * 5) / 8))
+                {
+                    /* Convert flush timeout to 0.625 ms units, with round */
+                    hci_flush_to = ((p_cfg->flush_to * 8) + 3) / 5;
+                    btsnd_hcic_write_auto_flush_tout (p_lcb->handle, hci_flush_to);
+                }
+            }
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         l2cu_process_our_cfg_rsp
+**
+** Description      This function is called when we send the peer a "config response"
+**                  message. It extracts the configuration of interest and saves
+**                  it in the CCB.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_process_our_cfg_rsp (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg)
+{
+    /* If peer wants QoS, we are allowed to change the values in a positive response */
+    if ( (p_cfg->qos_present) && (p_ccb->peer_cfg.qos_present) )
+        p_ccb->peer_cfg.qos = p_cfg->qos;
+    else
+        p_cfg->qos_present = false;
+
+    l2c_fcr_adj_our_rsp_options (p_ccb, p_cfg);
+}
+
+
+/*******************************************************************************
+**
+** Function         l2cu_device_reset
+**
+** Description      This function is called when reset of the device is
+**                  completed.  For all active connection simulate HCI_DISC
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_device_reset (void)
+{
+    int         xx;
+    tL2C_LCB    *p_lcb = &l2cb.lcb_pool[0];
+
+    for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
+    {
+        if ((p_lcb->in_use) && (p_lcb->handle != HCI_INVALID_HANDLE))
+        {
+            l2c_link_hci_disc_comp (p_lcb->handle, (uint8_t) -1);
+        }
+    }
+#if (BLE_INCLUDED == TRUE)
+    l2cb.is_ble_connecting = false;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_create_conn
+**
+** Description      This function initiates an acl connection via HCI
+**
+** Returns          true if successful, false if get buffer fails.
+**
+*******************************************************************************/
+bool    l2cu_create_conn (tL2C_LCB *p_lcb, tBT_TRANSPORT transport)
+{
+    int             xx;
+    tL2C_LCB        *p_lcb_cur = &l2cb.lcb_pool[0];
+#if (BTM_SCO_INCLUDED == TRUE)
+    bool            is_sco_active;
+#endif
+
+#if (BLE_INCLUDED == TRUE)
+    tBT_DEVICE_TYPE     dev_type;
+    tBLE_ADDR_TYPE      addr_type;
+
+
+    BTM_ReadDevInfo(p_lcb->remote_bd_addr, &dev_type, &addr_type);
+
+    if (transport == BT_TRANSPORT_LE)
+    {
+        if (!controller_get_interface()->supports_ble())
+            return false;
+
+        p_lcb->ble_addr_type = addr_type;
+        p_lcb->transport = BT_TRANSPORT_LE;
+
+        return (l2cble_create_conn(p_lcb));
+    }
+#endif
+
+    /* If there is a connection where we perform as a slave, try to switch roles
+       for this connection */
+    for (xx = 0, p_lcb_cur = &l2cb.lcb_pool[0]; xx < MAX_L2CAP_LINKS; xx++, p_lcb_cur++)
+    {
+        if (p_lcb_cur == p_lcb)
+            continue;
+
+        if ((p_lcb_cur->in_use) && (p_lcb_cur->link_role == HCI_ROLE_SLAVE))
+        {
+
+#if (BTM_SCO_INCLUDED == TRUE)
+            /* The LMP_switch_req shall be sent only if the ACL logical transport
+            is in active mode, when encryption is disabled, and all synchronous
+            logical transports on the same physical link are disabled." */
+
+            /* Check if there is any SCO Active on this BD Address */
+            is_sco_active = btm_is_sco_active_by_bdaddr(p_lcb_cur->remote_bd_addr);
+
+            L2CAP_TRACE_API ("l2cu_create_conn - btm_is_sco_active_by_bdaddr() is_sco_active = %s", \
+                (is_sco_active == true) ? "true":"false");
+
+            if (is_sco_active == true)
+                continue; /* No Master Slave switch not allowed when SCO Active */
+#endif
+            /*4_1_TODO check  if btm_cb.devcb.local_features to be used instead */
+            if (HCI_SWITCH_SUPPORTED(BTM_ReadLocalFeatures()))
+            {
+                /* mark this lcb waiting for switch to be completed and
+                   start switch on the other one */
+                p_lcb->link_state = LST_CONNECTING_WAIT_SWITCH;
+                p_lcb->link_role  = HCI_ROLE_MASTER;
+
+                if (BTM_SwitchRole (p_lcb_cur->remote_bd_addr, HCI_ROLE_MASTER, NULL) == BTM_CMD_STARTED)
+                {
+                    alarm_set_on_queue(p_lcb->l2c_lcb_timer,
+                                       L2CAP_LINK_ROLE_SWITCH_TIMEOUT_MS,
+                                       l2c_lcb_timer_timeout, p_lcb,
+                                       btu_general_alarm_queue);
+                    return (true);
+                }
+            }
+        }
+    }
+
+    p_lcb->link_state = LST_CONNECTING;
+
+    return (l2cu_create_conn_after_switch (p_lcb));
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_get_num_hi_priority
+**
+** Description      Gets the number of high priority channels.
+**
+** Returns
+**
+*******************************************************************************/
+uint8_t l2cu_get_num_hi_priority (void)
+{
+    uint8_t     no_hi = 0;
+    int         xx;
+    tL2C_LCB    *p_lcb = &l2cb.lcb_pool[0];
+
+    for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
+    {
+        if ((p_lcb->in_use) && (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH))
+        {
+            no_hi++;
+        }
+    }
+    return no_hi;
+}
+
+
+/*******************************************************************************
+**
+** Function         l2cu_create_conn_after_switch
+**
+** Description      This function initiates an acl connection via HCI
+**                  If switch required to create connection it is already done.
+**
+** Returns          true if successful, false if get buffer fails.
+**
+*******************************************************************************/
+
+bool    l2cu_create_conn_after_switch (tL2C_LCB *p_lcb)
+{
+    uint8_t          allow_switch = HCI_CR_CONN_ALLOW_SWITCH;
+    tBTM_INQ_INFO    *p_inq_info;
+    uint8_t          page_scan_rep_mode;
+    uint8_t          page_scan_mode;
+    uint16_t         clock_offset;
+    uint8_t          *p_features;
+    uint16_t         num_acl = BTM_GetNumAclLinks();
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_lcb->remote_bd_addr);
+    uint8_t          no_hi_prio_chs = l2cu_get_num_hi_priority();
+
+    p_features = BTM_ReadLocalFeatures();
+
+    L2CAP_TRACE_DEBUG ("l2cu_create_conn_after_switch :%d num_acl:%d no_hi: %d is_bonding:%d",
+        l2cb.disallow_switch, num_acl, no_hi_prio_chs, p_lcb->is_bonding);
+    /* FW team says that we can participant in 4 piconets
+     * typically 3 piconet + 1 for scanning.
+     * We can enhance the code to count the number of piconets later. */
+    if ( ((!l2cb.disallow_switch && (num_acl < 3)) || (p_lcb->is_bonding && (no_hi_prio_chs==0)))
+        && HCI_SWITCH_SUPPORTED(p_features))
+        allow_switch = HCI_CR_CONN_ALLOW_SWITCH;
+    else
+        allow_switch = HCI_CR_CONN_NOT_ALLOW_SWITCH;
+
+    p_lcb->link_state = LST_CONNECTING;
+
+    /* Check with the BT manager if details about remote device are known */
+    if ((p_inq_info = BTM_InqDbRead(p_lcb->remote_bd_addr)) != NULL)
+    {
+        page_scan_rep_mode = p_inq_info->results.page_scan_rep_mode;
+        page_scan_mode = p_inq_info->results.page_scan_mode;
+        clock_offset = (uint16_t)(p_inq_info->results.clock_offset);
+    }
+    else
+    {
+        /* No info known. Use default settings */
+        page_scan_rep_mode = HCI_PAGE_SCAN_REP_MODE_R1;
+        page_scan_mode = HCI_MANDATARY_PAGE_SCAN_MODE;
+
+        clock_offset = (p_dev_rec) ? p_dev_rec->clock_offset : 0;
+    }
+
+    btsnd_hcic_create_conn(p_lcb->remote_bd_addr,
+                           ( HCI_PKT_TYPES_MASK_DM1 | HCI_PKT_TYPES_MASK_DH1
+                           | HCI_PKT_TYPES_MASK_DM3 | HCI_PKT_TYPES_MASK_DH3
+                           | HCI_PKT_TYPES_MASK_DM5 | HCI_PKT_TYPES_MASK_DH5 ),
+                           page_scan_rep_mode,
+                           page_scan_mode,
+                           clock_offset,
+                           allow_switch);
+
+    btm_acl_update_busy_level (BTM_BLI_PAGE_EVT);
+
+    alarm_set_on_queue(p_lcb->l2c_lcb_timer,
+                       L2CAP_LINK_CONNECT_TIMEOUT_MS,
+                       l2c_lcb_timer_timeout, p_lcb,
+                       btu_general_alarm_queue);
+
+    return (true);
+}
+
+
+/*******************************************************************************
+**
+** Function         l2cu_find_lcb_by_state
+**
+** Description      Look through all active LCBs for a match based on the
+**                  LCB state.
+**
+** Returns          pointer to first matched LCB, or NULL if no match
+**
+*******************************************************************************/
+tL2C_LCB *l2cu_find_lcb_by_state (tL2C_LINK_STATE state)
+{
+    uint16_t    i;
+    tL2C_LCB    *p_lcb = &l2cb.lcb_pool[0];
+
+    for (i = 0; i < MAX_L2CAP_LINKS; i++, p_lcb++)
+    {
+        if ((p_lcb->in_use) && (p_lcb->link_state == state))
+        {
+            return (p_lcb);
+        }
+    }
+
+    /* If here, no match found */
+    return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         l2cu_lcb_disconnecting
+**
+** Description      On each active lcb, check if the lcb is in disconnecting
+**                  state, or if there are no ccb's on the lcb (implying
+                    idle timeout is running), or if last ccb on the link
+                    is in disconnecting state.
+**
+** Returns          true if any of above conditions met, false otherwise
+**
+*******************************************************************************/
+bool    l2cu_lcb_disconnecting (void)
+{
+    tL2C_LCB    *p_lcb;
+    tL2C_CCB    *p_ccb;
+    uint16_t    i;
+    bool        status = false;
+
+    p_lcb = &l2cb.lcb_pool[0];
+
+    for (i = 0; i < MAX_L2CAP_LINKS; i++, p_lcb++)
+    {
+        if (p_lcb->in_use)
+        {
+            /* no ccbs on lcb, or lcb is in disconnecting state */
+            if ((!p_lcb->ccb_queue.p_first_ccb) || (p_lcb->link_state == LST_DISCONNECTING))
+            {
+                status = true;
+                break;
+            }
+            /* only one ccb left on lcb */
+            else if (p_lcb->ccb_queue.p_first_ccb == p_lcb->ccb_queue.p_last_ccb)
+            {
+                p_ccb = p_lcb->ccb_queue.p_first_ccb;
+
+                if ((p_ccb->in_use) &&
+                    ((p_ccb->chnl_state == CST_W4_L2CAP_DISCONNECT_RSP) ||
+                     (p_ccb->chnl_state == CST_W4_L2CA_DISCONNECT_RSP)))
+                {
+                    status = true;
+                    break;
+                }
+            }
+        }
+    }
+    return status;
+}
+
+
+/*******************************************************************************
+**
+** Function         l2cu_set_acl_priority
+**
+** Description      Sets the transmission priority for a 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    l2cu_set_acl_priority (BD_ADDR bd_addr, uint8_t priority, bool    reset_after_rs)
+{
+    tL2C_LCB            *p_lcb;
+    uint8_t             *pp;
+    uint8_t              command[HCI_BRCM_ACL_PRIORITY_PARAM_SIZE];
+    uint8_t              vs_param;
+
+    APPL_TRACE_EVENT("SET ACL PRIORITY %d", priority);
+
+    /* Find the link control block for the acl channel */
+    if ((p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_BR_EDR)) == NULL)
+    {
+        L2CAP_TRACE_WARNING ("L2CAP - no LCB for L2CA_SetAclPriority");
+        return (false);
+    }
+
+    if (BTM_IS_BRCM_CONTROLLER())
+    {
+        /* Called from above L2CAP through API; send VSC if changed */
+        if ((!reset_after_rs && (priority != p_lcb->acl_priority)) ||
+              /* Called because of a master/slave role switch; if high resend VSC */
+            ( reset_after_rs && p_lcb->acl_priority == L2CAP_PRIORITY_HIGH))
+        {
+            pp = command;
+
+            vs_param = (priority == L2CAP_PRIORITY_HIGH) ? HCI_BRCM_ACL_PRIORITY_HIGH : HCI_BRCM_ACL_PRIORITY_LOW;
+
+            UINT16_TO_STREAM (pp, p_lcb->handle);
+            UINT8_TO_STREAM  (pp, vs_param);
+
+            BTM_VendorSpecificCommand (HCI_BRCM_SET_ACL_PRIORITY, HCI_BRCM_ACL_PRIORITY_PARAM_SIZE, command, NULL);
+
+            /* Adjust lmp buffer allocation for this channel if priority changed */
+            if (p_lcb->acl_priority != priority)
+            {
+                p_lcb->acl_priority = priority;
+                l2c_link_adjust_allocation();
+            }
+        }
+    }
+    return(true);
+}
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+/******************************************************************************
+**
+** Function         l2cu_set_non_flushable_pbf
+**
+** Description      set L2CAP_PKT_START_NON_FLUSHABLE if controller supoorts
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_set_non_flushable_pbf (bool    is_supported)
+{
+    if (is_supported)
+        l2cb.non_flushable_pbf = (L2CAP_PKT_START_NON_FLUSHABLE << L2CAP_PKT_TYPE_SHIFT);
+    else
+        l2cb.non_flushable_pbf = (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         l2cu_resubmit_pending_sec_req
+**
+** Description      This function is called when required security procedures
+**                  are completed and any pending requests can be re-submitted.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_resubmit_pending_sec_req (BD_ADDR p_bda)
+{
+    tL2C_LCB        *p_lcb;
+    tL2C_CCB        *p_ccb;
+    tL2C_CCB        *p_next_ccb;
+    int             xx;
+
+    L2CAP_TRACE_DEBUG ("l2cu_resubmit_pending_sec_req  p_bda: 0x%08x", p_bda);
+
+    /* If we are called with a BDA, only resubmit for that BDA */
+    if (p_bda)
+    {
+        p_lcb = l2cu_find_lcb_by_bd_addr (p_bda, BT_TRANSPORT_BR_EDR);
+
+        /* If we don't have one, this is an error */
+        if (p_lcb)
+        {
+            /* For all channels, send the event through their FSMs */
+            for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_next_ccb)
+            {
+                p_next_ccb = p_ccb->p_next_ccb;
+                l2c_csm_execute (p_ccb, L2CEVT_SEC_RE_SEND_CMD, NULL);
+            }
+        }
+        else
+        {
+            L2CAP_TRACE_WARNING ("l2cu_resubmit_pending_sec_req - unknown BD_ADDR");
+        }
+    }
+    else
+    {
+        /* No BDA pasesed in, so check all links */
+        for (xx = 0, p_lcb = &l2cb.lcb_pool[0]; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
+        {
+            if (p_lcb->in_use)
+            {
+                /* For all channels, send the event through their FSMs */
+                for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_next_ccb)
+                {
+                    p_next_ccb = p_ccb->p_next_ccb;
+                    l2c_csm_execute (p_ccb, L2CEVT_SEC_RE_SEND_CMD, NULL);
+                }
+            }
+        }
+    }
+}
+
+#if (L2CAP_CONFORMANCE_TESTING == TRUE)
+/*******************************************************************************
+**
+** Function         l2cu_set_info_rsp_mask
+**
+** Description      This function allows the script wrapper to change the
+**                  info resp mask for conformance testing.
+**
+** Returns          pointer to CCB, or NULL if none
+**
+*******************************************************************************/
+void l2cu_set_info_rsp_mask (uint32_t mask)
+{
+    l2cb.test_info_resp = mask;
+}
+#endif  /* L2CAP_CONFORMANCE_TESTING */
+
+/*******************************************************************************
+**
+** Function         l2cu_adjust_out_mps
+**
+** Description      Sets our MPS based on current controller capabilities
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_adjust_out_mps (tL2C_CCB *p_ccb)
+{
+    uint16_t packet_size;
+
+    /* on the tx side MTU is selected based on packet size of the controller */
+    packet_size = btm_get_max_packet_size (p_ccb->p_lcb->remote_bd_addr);
+
+    if (packet_size <= (L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD + L2CAP_SDU_LEN_OVERHEAD + L2CAP_FCS_LEN))
+    {
+        /* something is very wrong */
+        L2CAP_TRACE_ERROR ("l2cu_adjust_out_mps bad packet size: %u  will use MPS: %u", packet_size, p_ccb->peer_cfg.fcr.mps);
+        p_ccb->tx_mps = p_ccb->peer_cfg.fcr.mps;
+    }
+    else
+    {
+        packet_size -= (L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD + L2CAP_SDU_LEN_OVERHEAD + L2CAP_FCS_LEN);
+
+        /* We try to negotiate MTU that each packet can be split into whole
+        number of max packets.  For example if link is 1.2 max packet size is 339 bytes.
+        At first calculate how many whole packets it is.  MAX L2CAP is 1691 + 4 overhead.
+        1695, that will be 5 Dh5 packets.  Now maximum L2CAP packet is
+        5 * 339 = 1695. Minus 4 bytes L2CAP header 1691.
+
+        For EDR 2.0 packet size is 1027.  So we better send RFCOMM packet as 1 3DH5 packet
+        1 * 1027 = 1027.  Minus 4 bytes L2CAP header 1023.  */
+        if (p_ccb->peer_cfg.fcr.mps >= packet_size)
+            p_ccb->tx_mps = p_ccb->peer_cfg.fcr.mps / packet_size * packet_size;
+        else
+            p_ccb->tx_mps = p_ccb->peer_cfg.fcr.mps;
+
+        L2CAP_TRACE_DEBUG ("l2cu_adjust_out_mps use %d   Based on peer_cfg.fcr.mps: %u  packet_size: %u",
+                            p_ccb->tx_mps, p_ccb->peer_cfg.fcr.mps, packet_size);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         l2cu_initialize_fixed_ccb
+**
+** Description      Initialize a fixed channel's CCB
+**
+** Returns          true or false
+**
+*******************************************************************************/
+bool    l2cu_initialize_fixed_ccb (tL2C_LCB *p_lcb, uint16_t fixed_cid, tL2CAP_FCR_OPTS *p_fcr)
+{
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+    tL2C_CCB    *p_ccb;
+
+    /* If we already have a CCB, then simply return */
+    p_ccb = p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL];
+    if ((p_ccb != NULL) && p_ccb->in_use) {
+        /*
+         * NOTE: The "in_use" check is needed to ignore leftover entries
+         * that have been already released by l2cu_release_ccb().
+         */
+        return (true);
+    }
+
+    if ((p_ccb = l2cu_allocate_ccb (NULL, 0)) == NULL)
+        return (false);
+
+    alarm_cancel(p_lcb->l2c_lcb_timer);
+
+    /* Set CID for the connection */
+    p_ccb->local_cid  = fixed_cid;
+    p_ccb->remote_cid = fixed_cid;
+
+    p_ccb->is_flushable = false;
+
+    if (p_fcr)
+    {
+        /* Set the FCR parameters. For now, we will use default pools */
+        p_ccb->our_cfg.fcr = p_ccb->peer_cfg.fcr = *p_fcr;
+
+        p_ccb->ertm_info.fcr_rx_buf_size  = L2CAP_FCR_RX_BUF_SIZE;
+        p_ccb->ertm_info.fcr_tx_buf_size  = L2CAP_FCR_TX_BUF_SIZE;
+        p_ccb->ertm_info.user_rx_buf_size = L2CAP_USER_RX_BUF_SIZE;
+        p_ccb->ertm_info.user_tx_buf_size = L2CAP_USER_TX_BUF_SIZE;
+
+        p_ccb->fcrb.max_held_acks = p_fcr->tx_win_sz / 3;
+    }
+
+    /* Link ccb to lcb and lcb to ccb */
+    p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL] = p_ccb;
+    p_ccb->p_lcb = p_lcb;
+
+    /* There is no configuration, so if the link is up, the channel is up */
+    if (p_lcb->link_state == LST_CONNECTED)
+        p_ccb->chnl_state = CST_OPEN;
+
+    /* Set the default idle timeout value to use */
+    p_ccb->fixed_chnl_idle_tout = l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].default_idle_tout;
+#endif
+    return (true);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_no_dynamic_ccbs
+**
+** Description      Handles the case when there are no more dynamic CCBs. If there
+**                  are any fixed CCBs, start the longest of the fixed CCB timeouts,
+**                  otherwise start the default link idle timeout or disconnect.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_no_dynamic_ccbs (tL2C_LCB *p_lcb)
+{
+    tBTM_STATUS     rc;
+    period_ms_t     timeout_ms = p_lcb->idle_timeout * 1000;
+    bool            start_timeout = true;
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+    int         xx;
+
+    for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++)
+    {
+        if ((p_lcb->p_fixed_ccbs[xx] != NULL) &&
+            (p_lcb->p_fixed_ccbs[xx]->fixed_chnl_idle_tout * 1000 > timeout_ms)) {
+            timeout_ms = p_lcb->p_fixed_ccbs[xx]->fixed_chnl_idle_tout * 1000;
+        }
+    }
+#endif
+
+    /* If the link is pairing, do not mess with the timeouts */
+    if (p_lcb->is_bonding)
+        return;
+
+    if (timeout_ms == 0)
+    {
+        L2CAP_TRACE_DEBUG ("l2cu_no_dynamic_ccbs() IDLE timer 0, disconnecting link");
+
+        rc = btm_sec_disconnect (p_lcb->handle, HCI_ERR_PEER_USER);
+        if (rc == BTM_CMD_STARTED)
+        {
+            l2cu_process_fixed_disc_cback(p_lcb);
+            p_lcb->link_state = LST_DISCONNECTING;
+            timeout_ms = L2CAP_LINK_DISCONNECT_TIMEOUT_MS;
+        }
+        else if (rc == BTM_SUCCESS)
+        {
+            l2cu_process_fixed_disc_cback(p_lcb);
+            /* BTM SEC will make sure that link is release (probably after pairing is done) */
+            p_lcb->link_state = LST_DISCONNECTING;
+            start_timeout = false;
+        }
+        else if (p_lcb->is_bonding)
+        {
+            btsnd_hcic_disconnect(p_lcb->handle, HCI_ERR_PEER_USER);
+            l2cu_process_fixed_disc_cback(p_lcb);
+            p_lcb->link_state = LST_DISCONNECTING;
+            timeout_ms = L2CAP_LINK_DISCONNECT_TIMEOUT_MS;
+        }
+        else
+        {
+            /* probably no buffer to send disconnect */
+            timeout_ms = BT_1SEC_TIMEOUT_MS;
+        }
+    }
+
+    if (start_timeout) {
+        L2CAP_TRACE_DEBUG("%s starting IDLE timeout: %d ms", __func__,
+                          timeout_ms);
+        alarm_set_on_queue(p_lcb->l2c_lcb_timer, timeout_ms,
+                           l2c_lcb_timer_timeout, p_lcb,
+                           btu_general_alarm_queue);
+    } else {
+        alarm_cancel(p_lcb->l2c_lcb_timer);
+    }
+}
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+/*******************************************************************************
+**
+** Function         l2cu_process_fixed_chnl_resp
+**
+** Description      handle a fixed channel response (or lack thereof)
+**                  if the link failed, or a fixed channel response was
+**                  not received, the bitfield is all zeros.
+**
+*******************************************************************************/
+void l2cu_process_fixed_chnl_resp (tL2C_LCB *p_lcb)
+{
+#if (BLE_INCLUDED == TRUE)
+     if (p_lcb->transport == BT_TRANSPORT_BR_EDR)
+     {
+         /* ignore all not assigned BR/EDR channels */
+         p_lcb->peer_chnl_mask[0] &= (L2CAP_FIXED_CHNL_SIG_BIT| \
+                                      L2CAP_FIXED_CHNL_CNCTLESS_BIT| \
+                                      L2CAP_FIXED_CHNL_SMP_BR_BIT);
+     }
+     else
+         p_lcb->peer_chnl_mask[0] = l2cb.l2c_ble_fixed_chnls_mask;
+#endif
+
+    /* Tell all registered fixed channels about the connection */
+    for (int xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++)
+    {
+#if (BLE_INCLUDED == TRUE)
+        /* skip sending LE fix channel callbacks on BR/EDR links */
+        if (p_lcb->transport == BT_TRANSPORT_BR_EDR &&
+            xx + L2CAP_FIRST_FIXED_CHNL >= L2CAP_ATT_CID &&
+            xx + L2CAP_FIRST_FIXED_CHNL <= L2CAP_SMP_CID)
+            continue;
+#endif
+        if (l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb != NULL)
+        {
+            if (p_lcb->peer_chnl_mask[(xx + L2CAP_FIRST_FIXED_CHNL) / 8]
+                    & (1 << ((xx + L2CAP_FIRST_FIXED_CHNL) % 8)))
+            {
+                if (p_lcb->p_fixed_ccbs[xx])
+                    p_lcb->p_fixed_ccbs[xx]->chnl_state = CST_OPEN;
+#if (BLE_INCLUDED == TRUE)
+                (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
+                        p_lcb->remote_bd_addr, true, 0, p_lcb->transport);
+#else
+                (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
+                        p_lcb->remote_bd_addr, true, 0, BT_TRANSPORT_BR_EDR);
+#endif
+            }
+            else
+            {
+#if (BLE_INCLUDED == TRUE)
+                (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
+                        p_lcb->remote_bd_addr, false, p_lcb->disc_reason, p_lcb->transport);
+#else
+                (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
+                        p_lcb->remote_bd_addr, false, p_lcb->disc_reason, BT_TRANSPORT_BR_EDR);
+#endif
+
+                if (p_lcb->p_fixed_ccbs[xx])
+                {
+                    l2cu_release_ccb (p_lcb->p_fixed_ccbs[xx]);
+                    p_lcb->p_fixed_ccbs[xx] = NULL;
+                }
+            }
+        }
+    }
+}
+#endif
+
+
+/*******************************************************************************
+**
+** Function         l2cu_process_fixed_disc_cback
+**
+** Description      send l2cap fixed channel disconnection callback to application
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_process_fixed_disc_cback (tL2C_LCB *p_lcb)
+{
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+
+    /* Select peer channels mask to use depending on transport */
+    uint8_t peer_channel_mask = p_lcb->peer_chnl_mask[0];
+
+    // For LE, reset the stored peer channel mask
+    if (p_lcb->transport == BT_TRANSPORT_LE)
+        p_lcb->peer_chnl_mask[0] = 0;
+
+    for (int xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++)
+    {
+        if (p_lcb->p_fixed_ccbs[xx])
+        {
+            if (p_lcb->p_fixed_ccbs[xx] != p_lcb->p_pending_ccb)
+            {
+                tL2C_CCB *p_l2c_chnl_ctrl_block;
+                p_l2c_chnl_ctrl_block = p_lcb->p_fixed_ccbs[xx];
+                p_lcb->p_fixed_ccbs[xx] = NULL;
+                l2cu_release_ccb(p_l2c_chnl_ctrl_block);
+#if (BLE_INCLUDED == TRUE)
+            (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
+                    p_lcb->remote_bd_addr, false, p_lcb->disc_reason, p_lcb->transport);
+#else
+            (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
+                    p_lcb->remote_bd_addr, false, p_lcb->disc_reason, BT_TRANSPORT_BR_EDR);
+#endif
+           }
+        }
+        else if ( (peer_channel_mask & (1 << (xx + L2CAP_FIRST_FIXED_CHNL)))
+               && (l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb != NULL) )
+#if (BLE_INCLUDED == TRUE)
+            (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
+                    p_lcb->remote_bd_addr, false, p_lcb->disc_reason, p_lcb->transport);
+#else
+            (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
+                    p_lcb->remote_bd_addr, false, p_lcb->disc_reason, BT_TRANSPORT_BR_EDR);
+#endif
+    }
+#endif
+}
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_ble_par_req
+**
+** Description      Build and send a BLE parameter update request message
+**                  to the peer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_ble_par_req (tL2C_LCB *p_lcb, uint16_t min_int, uint16_t max_int,
+        uint16_t latency, uint16_t timeout)
+{
+    BT_HDR  *p_buf;
+    uint8_t *p;
+
+    /* Create an identifier for this packet */
+    p_lcb->id++;
+    l2cu_adj_id (p_lcb, L2CAP_ADJ_ID);
+
+    if ((p_buf = l2cu_build_header (p_lcb, L2CAP_CMD_BLE_UPD_REQ_LEN,
+                    L2CAP_CMD_BLE_UPDATE_REQ, p_lcb->id)) == NULL )
+    {
+        L2CAP_TRACE_WARNING ("l2cu_send_peer_ble_par_req - no buffer");
+        return;
+    }
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+                               L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    UINT16_TO_STREAM (p, min_int);
+    UINT16_TO_STREAM (p, max_int);
+    UINT16_TO_STREAM (p, latency);
+    UINT16_TO_STREAM (p, timeout);
+
+    l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_ble_par_rsp
+**
+** Description      Build and send a BLE parameter update response message
+**                  to the peer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_ble_par_rsp (tL2C_LCB *p_lcb, uint16_t reason, uint8_t rem_id)
+{
+    BT_HDR  *p_buf;
+    uint8_t *p;
+
+    if ((p_buf = l2cu_build_header (p_lcb, L2CAP_CMD_BLE_UPD_RSP_LEN,
+                    L2CAP_CMD_BLE_UPDATE_RSP, rem_id)) == NULL )
+    {
+        L2CAP_TRACE_WARNING ("l2cu_send_peer_ble_par_rsp - no buffer");
+        return;
+    }
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+                               L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    UINT16_TO_STREAM (p, reason);
+
+    l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_ble_credit_based_conn_req
+**
+** Description      Build and send a BLE packet to establish LE connection oriented
+**                  L2CAP channel.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_ble_credit_based_conn_req (tL2C_CCB *p_ccb)
+{
+    BT_HDR  *p_buf;
+    uint8_t *p;
+    tL2C_LCB *p_lcb = NULL;
+    uint16_t mtu;
+    uint16_t mps;
+    uint16_t initial_credit;
+
+    if (!p_ccb)
+        return;
+    p_lcb = p_ccb->p_lcb;
+
+    /* Create an identifier for this packet */
+    p_ccb->p_lcb->id++;
+    l2cu_adj_id(p_ccb->p_lcb, L2CAP_ADJ_ID);
+
+    p_ccb->local_id = p_ccb->p_lcb->id;
+
+    if ((p_buf = l2cu_build_header (p_lcb, L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ_LEN,
+                    L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ, p_lcb->id)) == NULL )
+    {
+        L2CAP_TRACE_WARNING ("l2cu_send_peer_ble_credit_based_conn_req - no buffer");
+        return;
+    }
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+                               L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    mtu = p_ccb->local_conn_cfg.mtu;
+    mps = p_ccb->local_conn_cfg.mps;
+    initial_credit = p_ccb->local_conn_cfg.credits;
+
+    L2CAP_TRACE_DEBUG ("l2cu_send_peer_ble_credit_based_conn_req PSM:0x%04x local_cid:%d\
+                mtu:%d mps:%d initial_credit:%d", p_ccb->p_rcb->real_psm,\
+                p_ccb->local_cid, mtu, mps, initial_credit);
+
+    UINT16_TO_STREAM (p, p_ccb->p_rcb->real_psm);
+    UINT16_TO_STREAM (p, p_ccb->local_cid);
+    UINT16_TO_STREAM (p, mtu);
+    UINT16_TO_STREAM (p, mps);
+    UINT16_TO_STREAM (p, initial_credit);
+
+    l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_reject_ble_connection
+**
+** Description      Build and send an L2CAP "Credit based connection res" message
+**                  to the peer. This function is called for non-success cases.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_reject_ble_connection (tL2C_LCB *p_lcb, uint8_t rem_id, uint16_t result)
+{
+    BT_HDR  *p_buf;
+    uint8_t *p;
+
+    if ((p_buf = l2cu_build_header(p_lcb, L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES_LEN,
+                    L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES, rem_id)) == NULL )
+    {
+        L2CAP_TRACE_WARNING ("l2cu_reject_ble_connection - no buffer");
+        return;
+    }
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+                               L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    UINT16_TO_STREAM (p, 0);                    /* Local CID of 0   */
+    UINT16_TO_STREAM (p, 0);                    /* MTU */
+    UINT16_TO_STREAM (p, 0);                    /* MPS */
+    UINT16_TO_STREAM (p, 0);                    /* initial credit */
+    UINT16_TO_STREAM (p, result);
+
+    l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_ble_credit_based_conn_res
+**
+** Description      Build and send an L2CAP "Credit based connection res" message
+**                  to the peer. This function is called in case of success.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_ble_credit_based_conn_res (tL2C_CCB *p_ccb, uint16_t result)
+{
+    BT_HDR  *p_buf;
+    uint8_t *p;
+
+    L2CAP_TRACE_DEBUG ("l2cu_send_peer_ble_credit_based_conn_res");
+    if ((p_buf = l2cu_build_header(p_ccb->p_lcb, L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES_LEN,
+                    L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES, p_ccb->remote_id)) == NULL )
+    {
+        L2CAP_TRACE_WARNING ("l2cu_send_peer_ble_credit_based_conn_res - no buffer");
+        return;
+    }
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+                               L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    UINT16_TO_STREAM (p, p_ccb->local_cid);                      /* Local CID */
+    UINT16_TO_STREAM (p, p_ccb->local_conn_cfg.mtu);             /* MTU */
+    UINT16_TO_STREAM (p, p_ccb->local_conn_cfg.mps);             /* MPS */
+    UINT16_TO_STREAM (p, p_ccb->local_conn_cfg.credits);         /* initial credit */
+    UINT16_TO_STREAM (p, result);
+
+    l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_ble_flow_control_credit
+**
+** Description      Build and send a BLE packet to give credits to peer device
+**                  for LE connection oriented L2CAP channel.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_ble_flow_control_credit(tL2C_CCB *p_ccb, uint16_t credit_value)
+{
+    BT_HDR  *p_buf;
+    uint8_t *p;
+    tL2C_LCB *p_lcb = NULL;
+
+    if (!p_ccb)
+        return;
+    p_lcb = p_ccb->p_lcb;
+
+    /* Create an identifier for this packet */
+    p_ccb->p_lcb->id++;
+    l2cu_adj_id(p_ccb->p_lcb, L2CAP_ADJ_ID);
+
+    p_ccb->local_id = p_ccb->p_lcb->id;
+
+    if ((p_buf = l2cu_build_header (p_lcb, L2CAP_CMD_BLE_FLOW_CTRL_CREDIT_LEN,
+                    L2CAP_CMD_BLE_FLOW_CTRL_CREDIT, p_lcb->id)) == NULL )
+    {
+        L2CAP_TRACE_WARNING ("l2cu_send_peer_ble_credit_based_conn_req - no buffer");
+        return;
+    }
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+                               L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    UINT16_TO_STREAM (p, p_ccb->local_cid);
+    UINT16_TO_STREAM (p, credit_value);
+
+    l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_send_peer_ble_credit_based_conn_req
+**
+** Description      Build and send a BLE packet to disconnect LE connection oriented
+**                  L2CAP channel.
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cu_send_peer_ble_credit_based_disconn_req(tL2C_CCB *p_ccb)
+{
+    BT_HDR  *p_buf;
+    uint8_t *p;
+    tL2C_LCB *p_lcb = NULL;
+    L2CAP_TRACE_DEBUG ("%s",__func__);
+
+    if (!p_ccb)
+        return;
+    p_lcb = p_ccb->p_lcb;
+
+    /* Create an identifier for this packet */
+    p_ccb->p_lcb->id++;
+    l2cu_adj_id(p_ccb->p_lcb, L2CAP_ADJ_ID);
+
+    p_ccb->local_id = p_ccb->p_lcb->id;
+     if ((p_buf = l2cu_build_header (p_lcb, L2CAP_DISC_REQ_LEN,
+                    L2CAP_CMD_DISC_REQ, p_lcb->id)) == NULL )
+    {
+        L2CAP_TRACE_WARNING ("l2cu_send_peer_ble_credit_based_disconn_req - no buffer");
+        return;
+    }
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+                               L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+    UINT16_TO_STREAM (p, p_ccb->remote_cid);
+    UINT16_TO_STREAM (p,p_ccb->local_cid);
+
+    l2c_link_check_send_pkts (p_lcb, NULL, p_buf);
+}
+#endif /* BLE_INCLUDED == TRUE */
+
+
+/*******************************************************************************
+** Functions used by both Full and Light Stack
+********************************************************************************/
+
+/*******************************************************************************
+**
+** Function         l2cu_find_lcb_by_handle
+**
+** Description      Look through all active LCBs for a match based on the
+**                  HCI handle.
+**
+** Returns          pointer to matched LCB, or NULL if no match
+**
+*******************************************************************************/
+tL2C_LCB  *l2cu_find_lcb_by_handle (uint16_t handle)
+{
+    int         xx;
+    tL2C_LCB    *p_lcb = &l2cb.lcb_pool[0];
+
+    for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
+    {
+        if ((p_lcb->in_use) && (p_lcb->handle == handle))
+        {
+            return (p_lcb);
+        }
+    }
+
+    /* If here, no match found */
+    return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_find_ccb_by_cid
+**
+** Description      Look through all active CCBs on a link for a match based
+**                  on the local CID. If passed the link pointer is NULL, all
+**                  active links are searched.
+**
+** Returns          pointer to matched CCB, or NULL if no match
+**
+*******************************************************************************/
+tL2C_CCB *l2cu_find_ccb_by_cid (tL2C_LCB *p_lcb, uint16_t local_cid)
+{
+    tL2C_CCB    *p_ccb = NULL;
+#if (L2CAP_UCD_INCLUDED == TRUE)
+    uint8_t xx;
+#endif
+
+    if (local_cid >= L2CAP_BASE_APPL_CID)
+    {
+        /* find the associated CCB by "index" */
+        local_cid -= L2CAP_BASE_APPL_CID;
+
+        if (local_cid >= MAX_L2CAP_CHANNELS)
+            return NULL;
+
+        p_ccb = l2cb.ccb_pool + local_cid;
+
+        /* make sure the CCB is in use */
+        if (!p_ccb->in_use)
+        {
+            p_ccb = NULL;
+        }
+        /* make sure it's for the same LCB */
+        else if (p_lcb && p_lcb != p_ccb->p_lcb)
+        {
+            p_ccb = NULL;
+        }
+    }
+#if (L2CAP_UCD_INCLUDED == TRUE)
+    else
+    {
+        /* searching fixed channel */
+        p_ccb = l2cb.ccb_pool;
+        for ( xx = 0; xx < MAX_L2CAP_CHANNELS; xx++ )
+        {
+            if ((p_ccb->local_cid == local_cid)
+              &&(p_ccb->in_use)
+              &&(p_lcb == p_ccb->p_lcb))
+                break;
+            else
+                p_ccb++;
+        }
+        if ( xx >= MAX_L2CAP_CHANNELS )
+            return NULL;
+    }
+#endif
+
+    return (p_ccb);
+}
+
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+
+/******************************************************************************
+**
+** Function         l2cu_get_next_channel_in_rr
+**
+** Description      get the next channel to send on a link. It also adjusts the
+**                  CCB queue to do a basic priority and round-robin scheduling.
+**
+** Returns          pointer to CCB or NULL
+**
+*******************************************************************************/
+static tL2C_CCB *l2cu_get_next_channel_in_rr(tL2C_LCB *p_lcb)
+{
+    tL2C_CCB    *p_serve_ccb = NULL;
+    tL2C_CCB    *p_ccb;
+
+    int i, j;
+
+    /* scan all of priority until finding a channel to serve */
+    for ( i = 0; (i < L2CAP_NUM_CHNL_PRIORITY)&&(!p_serve_ccb); i++ )
+    {
+        /* scan all channel within serving priority group until finding a channel to serve */
+        for ( j = 0; (j < p_lcb->rr_serv[p_lcb->rr_pri].num_ccb)&&(!p_serve_ccb); j++)
+        {
+            /* scaning from next serving channel */
+            p_ccb = p_lcb->rr_serv[p_lcb->rr_pri].p_serve_ccb;
+
+            if (!p_ccb)
+            {
+                L2CAP_TRACE_ERROR("p_serve_ccb is NULL, rr_pri=%d", p_lcb->rr_pri);
+                return NULL;
+            }
+
+            L2CAP_TRACE_DEBUG("RR scan pri=%d, lcid=0x%04x, q_cout=%d",
+                              p_ccb->ccb_priority, p_ccb->local_cid,
+                              fixed_queue_length(p_ccb->xmit_hold_q));
+
+            /* store the next serving channel */
+            /* this channel is the last channel of its priority group */
+            if (( p_ccb->p_next_ccb == NULL )
+              ||( p_ccb->p_next_ccb->ccb_priority != p_ccb->ccb_priority ))
+            {
+                /* next serving channel is set to the first channel in the group */
+                p_lcb->rr_serv[p_lcb->rr_pri].p_serve_ccb = p_lcb->rr_serv[p_lcb->rr_pri].p_first_ccb;
+            }
+            else
+            {
+                /* next serving channel is set to the next channel in the group */
+                p_lcb->rr_serv[p_lcb->rr_pri].p_serve_ccb = p_ccb->p_next_ccb;
+            }
+
+            if (p_ccb->chnl_state != CST_OPEN)
+                continue;
+
+            if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
+            {
+                L2CAP_TRACE_DEBUG("%s : Connection oriented channel",__func__);
+                if (fixed_queue_is_empty(p_ccb->xmit_hold_q))
+                    continue;
+
+            }
+            else
+            {
+                /* eL2CAP option in use */
+                if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
+                {
+                    if (p_ccb->fcrb.wait_ack || p_ccb->fcrb.remote_busy)
+                        continue;
+
+                    if (fixed_queue_is_empty(p_ccb->fcrb.retrans_q))
+                    {
+                        if (fixed_queue_is_empty(p_ccb->xmit_hold_q))
+                            continue;
+
+                        /* If in eRTM mode, check for window closure */
+                        if ( (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) && (l2c_fcr_is_flow_controlled (p_ccb)) )
+                            continue;
+                    }
+                }
+                else
+                {
+                    if (fixed_queue_is_empty(p_ccb->xmit_hold_q))
+                        continue;
+                }
+            }
+
+            /* found a channel to serve */
+            p_serve_ccb = p_ccb;
+            /* decrease quota of its priority group */
+            p_lcb->rr_serv[p_lcb->rr_pri].quota--;
+        }
+
+        /* if there is no more quota of the priority group or no channel to have data to send */
+        if ((p_lcb->rr_serv[p_lcb->rr_pri].quota == 0)||(!p_serve_ccb))
+        {
+            /* serve next priority group */
+            p_lcb->rr_pri = (p_lcb->rr_pri + 1) % L2CAP_NUM_CHNL_PRIORITY;
+            /* initialize its quota */
+            p_lcb->rr_serv[p_lcb->rr_pri].quota = L2CAP_GET_PRIORITY_QUOTA(p_lcb->rr_pri);
+        }
+    }
+
+    if (p_serve_ccb)
+    {
+        L2CAP_TRACE_DEBUG("RR service pri=%d, quota=%d, lcid=0x%04x",
+                            p_serve_ccb->ccb_priority,
+                            p_lcb->rr_serv[p_serve_ccb->ccb_priority].quota,
+                            p_serve_ccb->local_cid );
+    }
+
+    return p_serve_ccb;
+}
+
+#else /* (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE) */
+
+/******************************************************************************
+**
+** Function         l2cu_get_next_channel
+**
+** Description      get the next channel to send on a link bassed on priority
+**                  scheduling.
+**
+** Returns          pointer to CCB or NULL
+**
+*******************************************************************************/
+static tL2C_CCB *l2cu_get_next_channel(tL2C_LCB *p_lcb)
+{
+    tL2C_CCB    *p_ccb;
+
+    /* Get the first CCB with data to send.
+    */
+    for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
+    {
+        if (p_ccb->chnl_state != CST_OPEN)
+            continue;
+
+        if (p_ccb->fcrb.wait_ack || p_ccb->fcrb.remote_busy)
+            continue;
+
+        if (!fixed_queue_is_empty(p_ccb->fcrb.retrans_q))
+            return p_ccb;
+
+        if (fixed_queue_is_empty(p_ccb->xmit_hold_q))
+            continue;
+
+        /* If in eRTM mode, check for window closure */
+        if ( (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) && (l2c_fcr_is_flow_controlled (p_ccb)) )
+            continue;
+
+        /* If here, we found someone */
+        return p_ccb;
+    }
+
+    return NULL;
+}
+#endif /* (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE) */
+
+/******************************************************************************
+**
+** Function         l2cu_get_next_buffer_to_send
+**
+** Description      get the next buffer to send on a link. It also adjusts the
+**                  CCB queue to do a basic priority and round-robin scheduling.
+**
+** Returns          pointer to buffer or NULL
+**
+*******************************************************************************/
+BT_HDR *l2cu_get_next_buffer_to_send (tL2C_LCB *p_lcb)
+{
+    tL2C_CCB    *p_ccb;
+    BT_HDR      *p_buf;
+
+    /* Highest priority are fixed channels */
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+    int         xx;
+
+    for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++)
+    {
+        if ((p_ccb = p_lcb->p_fixed_ccbs[xx]) == NULL)
+            continue;
+
+        /* eL2CAP option in use */
+        if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
+        {
+            if (p_ccb->fcrb.wait_ack || p_ccb->fcrb.remote_busy)
+                continue;
+
+            /* No more checks needed if sending from the reatransmit queue */
+            if (fixed_queue_is_empty(p_ccb->fcrb.retrans_q))
+            {
+                if (fixed_queue_is_empty(p_ccb->xmit_hold_q))
+                    continue;
+
+                /* If in eRTM mode, check for window closure */
+                if ( (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) && (l2c_fcr_is_flow_controlled (p_ccb)) )
+                    continue;
+            }
+
+            if ((p_buf = l2c_fcr_get_next_xmit_sdu_seg(p_ccb, 0)) != NULL)
+            {
+                l2cu_check_channel_congestion (p_ccb);
+                l2cu_set_acl_hci_header (p_buf, p_ccb);
+                return (p_buf);
+            }
+        }
+        else
+        {
+            if (!fixed_queue_is_empty(p_ccb->xmit_hold_q))
+            {
+                p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->xmit_hold_q);
+                if(NULL == p_buf)
+                {
+                    L2CAP_TRACE_ERROR("l2cu_get_buffer_to_send: No data to be sent");
+                    return (NULL);
+                }
+                /* send tx complete */
+                if (l2cb.fixed_reg[xx].pL2CA_FixedTxComplete_Cb)
+                    (*l2cb.fixed_reg[xx].pL2CA_FixedTxComplete_Cb)(p_ccb->local_cid, 1);
+
+                l2cu_check_channel_congestion (p_ccb);
+                l2cu_set_acl_hci_header (p_buf, p_ccb);
+                return (p_buf);
+            }
+        }
+    }
+#endif
+
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+    /* get next serving channel in round-robin */
+    p_ccb  = l2cu_get_next_channel_in_rr( p_lcb );
+#else
+    p_ccb  = l2cu_get_next_channel( p_lcb );
+#endif
+
+    /* Return if no buffer */
+    if (p_ccb == NULL)
+        return (NULL);
+
+    if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
+    {
+        /* Check credits */
+        if(p_ccb->peer_conn_cfg.credits == 0)
+        {
+            L2CAP_TRACE_DEBUG("%s No credits to send packets",__func__);
+            return NULL;
+        }
+        if ((p_buf = l2c_lcc_get_next_xmit_sdu_seg(p_ccb, 0)) == NULL)
+            return (NULL);
+
+        p_ccb->peer_conn_cfg.credits--;
+    }
+    else
+    {
+        if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
+        {
+            if ((p_buf = l2c_fcr_get_next_xmit_sdu_seg(p_ccb, 0)) == NULL)
+                return (NULL);
+        }
+        else
+        {
+            p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->xmit_hold_q);
+            if(NULL == p_buf)
+            {
+                L2CAP_TRACE_ERROR("l2cu_get_buffer_to_send() #2: No data to be sent");
+                return (NULL);
+            }
+        }
+    }
+
+    if ( p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_TxComplete_Cb && (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_ERTM_MODE) )
+        (*p_ccb->p_rcb->api.pL2CA_TxComplete_Cb)(p_ccb->local_cid, 1);
+
+
+    l2cu_check_channel_congestion (p_ccb);
+
+    l2cu_set_acl_hci_header (p_buf, p_ccb);
+
+    return (p_buf);
+}
+
+/******************************************************************************
+**
+** Function         l2cu_set_acl_hci_header
+**
+** Description      Set HCI handle for ACL packet
+**
+** Returns          None
+**
+*******************************************************************************/
+void l2cu_set_acl_hci_header (BT_HDR *p_buf, tL2C_CCB *p_ccb)
+{
+    uint8_t     *p;
+
+    /* Set the pointer to the beginning of the data minus 4 bytes for the packet header */
+    p = (uint8_t *)(p_buf + 1) + p_buf->offset - HCI_DATA_PREAMBLE_SIZE;
+
+#if (BLE_INCLUDED == TRUE)
+    if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
+    {
+        UINT16_TO_STREAM (p, p_ccb->p_lcb->handle | (L2CAP_PKT_START_NON_FLUSHABLE << L2CAP_PKT_TYPE_SHIFT));
+
+        uint16_t acl_data_size = controller_get_interface()->get_acl_data_size_ble();
+        /* The HCI transport will segment the buffers. */
+        if (p_buf->len > acl_data_size)
+        {
+            UINT16_TO_STREAM (p, acl_data_size);
+        }
+        else
+        {
+            UINT16_TO_STREAM (p, p_buf->len);
+        }
+    } /* (BLE_INCLUDED == TRUE) */
+    else
+#endif
+    {
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+        if ( (((p_buf->layer_specific & L2CAP_FLUSHABLE_MASK) == L2CAP_FLUSHABLE_CH_BASED) && (p_ccb->is_flushable))
+                || ((p_buf->layer_specific & L2CAP_FLUSHABLE_MASK) == L2CAP_FLUSHABLE_PKT) )
+        {
+            UINT16_TO_STREAM (p, p_ccb->p_lcb->handle | (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT));
+        }
+        else
+        {
+            UINT16_TO_STREAM (p, p_ccb->p_lcb->handle | l2cb.non_flushable_pbf);
+        }
+#else
+        UINT16_TO_STREAM (p, p_ccb->p_lcb->handle | (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT));
+#endif
+
+        uint16_t acl_data_size = controller_get_interface()->get_acl_data_size_classic();
+        /* The HCI transport will segment the buffers. */
+        if (p_buf->len > acl_data_size)
+        {
+            UINT16_TO_STREAM (p, acl_data_size);
+        }
+        else
+        {
+            UINT16_TO_STREAM (p, p_buf->len);
+        }
+    }
+    p_buf->offset -= HCI_DATA_PREAMBLE_SIZE;
+    p_buf->len    += HCI_DATA_PREAMBLE_SIZE;
+}
+
+/******************************************************************************
+**
+** Function         l2cu_check_channel_congestion
+**
+** Description      check if any change in congestion status
+**
+** Returns          None
+**
+*******************************************************************************/
+void l2cu_check_channel_congestion (tL2C_CCB *p_ccb)
+{
+    size_t q_count = fixed_queue_length(p_ccb->xmit_hold_q);
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+    if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
+    {
+        q_count += fixed_queue_length(p_ccb->p_lcb->ucd_out_sec_pending_q);
+    }
+#endif
+    /* If the CCB queue limit is subject to a quota, check for congestion */
+    /* if this channel has outgoing traffic */
+    if (p_ccb->buff_quota != 0)
+    {
+        /* If this channel was congested */
+        if ( p_ccb->cong_sent )
+        {
+            /* If the channel is not congested now, tell the app */
+            if (q_count <= (p_ccb->buff_quota / 2))
+            {
+                p_ccb->cong_sent = false;
+                if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)
+                {
+                    L2CAP_TRACE_DEBUG ("L2CAP - Calling CongestionStatus_Cb (false), CID: 0x%04x  xmit_hold_q.count: %u  buff_quota: %u",
+                                      p_ccb->local_cid, q_count, p_ccb->buff_quota);
+
+                    /* Prevent recursive calling */
+                    l2cb.is_cong_cback_context = true;
+                    (*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid, false);
+                    l2cb.is_cong_cback_context = false;
+                }
+#if (L2CAP_UCD_INCLUDED == TRUE)
+                else if ( p_ccb->p_rcb && p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
+                {
+                    if ( p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb )
+                    {
+                        L2CAP_TRACE_DEBUG ("L2CAP - Calling UCD CongestionStatus_Cb (false), SecPendingQ:%u,XmitQ:%u,Quota:%u",
+                                           fixed_queue_length(p_ccb->p_lcb->ucd_out_sec_pending_q),
+                                           fixed_queue_length(p_ccb->xmit_hold_q),
+                                           p_ccb->buff_quota);
+                        p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb( p_ccb->p_lcb->remote_bd_addr, false );
+                    }
+                }
+#endif
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+                else
+                {
+                    uint8_t xx;
+                    for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx ++)
+                    {
+                        if (p_ccb->p_lcb->p_fixed_ccbs[xx] == p_ccb)
+                        {
+                            if (l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb != NULL)
+                                (* l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb)(p_ccb->p_lcb->remote_bd_addr, false);
+                            break;
+                        }
+                    }
+                }
+#endif
+            }
+        }
+        else
+        {
+            /* If this channel was not congested but it is congested now, tell the app */
+            if (q_count > p_ccb->buff_quota)
+            {
+                p_ccb->cong_sent = true;
+                if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)
+                {
+                    L2CAP_TRACE_DEBUG ("L2CAP - Calling CongestionStatus_Cb (true),CID:0x%04x,XmitQ:%u,Quota:%u",
+                        p_ccb->local_cid, q_count, p_ccb->buff_quota);
+
+                    (*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid, true);
+                }
+#if (L2CAP_UCD_INCLUDED == TRUE)
+                else if ( p_ccb->p_rcb && p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
+                {
+                    if ( p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb )
+                    {
+                        L2CAP_TRACE_DEBUG("L2CAP - Calling UCD CongestionStatus_Cb (true), SecPendingQ:%u,XmitQ:%u,Quota:%u",
+                                          fixed_queue_length(p_ccb->p_lcb->ucd_out_sec_pending_q),
+                                          fixed_queue_length(p_ccb->xmit_hold_q),
+                                          p_ccb->buff_quota);
+                        p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb( p_ccb->p_lcb->remote_bd_addr, true );
+                    }
+                }
+#endif
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+                else
+                {
+                    uint8_t xx;
+                    for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx ++)
+                    {
+                        if (p_ccb->p_lcb->p_fixed_ccbs[xx] == p_ccb)
+                        {
+                            if (l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb != NULL)
+                                (* l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb)(p_ccb->p_lcb->remote_bd_addr, true);
+                            break;
+                        }
+                    }
+                }
+#endif
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         l2cu_is_ccb_active
+**
+** Description      Check if Channel Control Block is in use or released
+**
+** Returns          bool    - true if Channel Control Block is in use
+**                            false if p_ccb is null or is released.
+**
+*******************************************************************************/
+bool    l2cu_is_ccb_active (tL2C_CCB *p_ccb)
+{
+    return (p_ccb && p_ccb->in_use);
+}
diff --git a/bt/stack/l2cap/l2cap_client.cc b/bt/stack/l2cap/l2cap_client.cc
new file mode 100644
index 0000000..17b95b8
--- /dev/null
+++ b/bt/stack/l2cap/l2cap_client.cc
@@ -0,0 +1,435 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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_l2cap_client"
+
+#include "stack/include/l2cap_client.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include "btcore/include/bdaddr.h"
+#include "osi/include/allocator.h"
+#include "osi/include/buffer.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "stack/include/l2c_api.h"
+
+struct l2cap_client_t {
+  l2cap_client_callbacks_t callbacks;
+  void *context;
+
+  uint16_t local_channel_id;
+  uint16_t remote_mtu;
+  bool configured_self;
+  bool configured_peer;
+  bool is_congested;
+  list_t *outbound_fragments;
+};
+
+static void connect_completed_cb(uint16_t local_channel_id, uint16_t error_code);
+static void config_request_cb(uint16_t local_channel_id, tL2CAP_CFG_INFO *requested_parameters);
+static void config_completed_cb(uint16_t local_channel_id, tL2CAP_CFG_INFO *negotiated_parameters);
+static void disconnect_request_cb(uint16_t local_channel_id, bool ack_required);
+static void disconnect_completed_cb(uint16_t local_channel_id, uint16_t error_code);
+static void congestion_cb(uint16_t local_channel_id, bool is_congested);
+static void read_ready_cb(uint16_t local_channel_id, BT_HDR *packet);
+static void write_completed_cb(uint16_t local_channel_id, uint16_t packets_completed);
+
+static void fragment_packet(l2cap_client_t *client, buffer_t *packet);
+static void dispatch_fragments(l2cap_client_t *client);
+static l2cap_client_t *find(uint16_t local_channel_id);
+
+// From the Bluetooth Core specification.
+static const uint16_t L2CAP_MTU_DEFAULT = 672;
+static const uint16_t L2CAP_MTU_MINIMUM = 48;
+
+static const tL2CAP_APPL_INFO l2cap_callbacks = {
+  .pL2CA_ConnectCfm_Cb       = connect_completed_cb,
+  .pL2CA_ConfigInd_Cb        = config_request_cb,
+  .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_TxComplete_Cb       = write_completed_cb,
+};
+
+static list_t *l2cap_clients;  // A list of l2cap_client_t. Container does not own objects.
+
+buffer_t *l2cap_buffer_new(size_t size) {
+  buffer_t *buf = buffer_new(size + L2CAP_MIN_OFFSET);
+  buffer_t *slice = NULL;
+  if (buf)
+    slice = buffer_new_slice(buf, size);
+  buffer_free(buf);
+  return slice;
+}
+
+l2cap_client_t *l2cap_client_new(const l2cap_client_callbacks_t *callbacks, void *context) {
+  assert(callbacks != NULL);
+  assert(callbacks->connected != NULL);
+  assert(callbacks->disconnected != NULL);
+  assert(callbacks->read_ready != NULL);
+  assert(callbacks->write_ready != NULL);
+
+  if (!l2cap_clients) {
+    l2cap_clients = list_new(NULL);
+    if (!l2cap_clients) {
+      LOG_ERROR(LOG_TAG, "%s unable to allocate space for L2CAP client list.", __func__);
+      return NULL;
+    }
+  }
+
+  l2cap_client_t *ret = (l2cap_client_t *)osi_calloc(sizeof(l2cap_client_t));
+
+  ret->callbacks = *callbacks;
+  ret->context = context;
+
+  ret->remote_mtu = L2CAP_MTU_DEFAULT;
+  ret->outbound_fragments = list_new(NULL);
+  if (!ret) {
+    LOG_ERROR(LOG_TAG, "%s unable to allocate outbound L2CAP fragment list.", __func__);
+    goto error;
+  }
+
+  list_append(l2cap_clients, ret);
+
+  return ret;
+
+error:;
+  osi_free(ret);
+  return NULL;
+}
+
+void l2cap_client_free(l2cap_client_t *client) {
+  if (!client)
+    return;
+
+  list_remove(l2cap_clients, client);
+  l2cap_client_disconnect(client);
+  list_free(client->outbound_fragments);
+  osi_free(client);
+}
+
+bool l2cap_client_connect(l2cap_client_t *client, const bt_bdaddr_t *remote_bdaddr, uint16_t psm) {
+  assert(client != NULL);
+  assert(remote_bdaddr != NULL);
+  assert(psm != 0);
+  assert(!bdaddr_is_empty(remote_bdaddr));
+  assert(client->local_channel_id == 0);
+  assert(!client->configured_self);
+  assert(!client->configured_peer);
+  assert(!L2C_INVALID_PSM(psm));
+
+  client->local_channel_id = L2CA_ConnectReq(psm, (uint8_t *)remote_bdaddr);
+  if (!client->local_channel_id) {
+    LOG_ERROR(LOG_TAG, "%s unable to create L2CAP connection.", __func__);
+    return false;
+  }
+
+  L2CA_SetConnectionCallbacks(client->local_channel_id, &l2cap_callbacks);
+  return true;
+}
+
+void l2cap_client_disconnect(l2cap_client_t *client) {
+  assert(client != NULL);
+
+  if (client->local_channel_id && !L2CA_DisconnectReq(client->local_channel_id))
+    LOG_ERROR(LOG_TAG, "%s unable to send disconnect message for LCID 0x%04x.", __func__, client->local_channel_id);
+
+  client->local_channel_id = 0;
+  client->remote_mtu = L2CAP_MTU_DEFAULT;
+  client->configured_self = false;
+  client->configured_peer = false;
+  client->is_congested = false;
+
+  for (const list_node_t *node = list_begin(client->outbound_fragments); node != list_end(client->outbound_fragments); node = list_next(node))
+    osi_free(list_node(node));
+
+  list_clear(client->outbound_fragments);
+}
+
+bool l2cap_client_is_connected(const l2cap_client_t *client) {
+  assert(client != NULL);
+
+  return client->local_channel_id != 0 && client->configured_self && client->configured_peer;
+}
+
+bool l2cap_client_write(l2cap_client_t *client, buffer_t *packet) {
+  assert(client != NULL);
+  assert(packet != NULL);
+  assert(l2cap_client_is_connected(client));
+
+  if (client->is_congested)
+    return false;
+
+  fragment_packet(client, packet);
+  dispatch_fragments(client);
+  return true;
+}
+
+static void connect_completed_cb(uint16_t local_channel_id, uint16_t error_code) {
+  assert(local_channel_id != 0);
+
+  l2cap_client_t *client = find(local_channel_id);
+  if (!client) {
+    LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client for LCID 0x%04x.", __func__, local_channel_id);
+    return;
+  }
+
+  if (error_code != L2CAP_CONN_OK) {
+    LOG_ERROR(LOG_TAG, "%s error connecting L2CAP channel: %d.", __func__, error_code);
+    client->callbacks.disconnected(client, client->context);
+    return;
+  }
+
+  // Use default L2CAP parameters.
+  tL2CAP_CFG_INFO desired_parameters;
+  memset(&desired_parameters, 0, sizeof(desired_parameters));
+  if (!L2CA_ConfigReq(local_channel_id, &desired_parameters)) {
+    LOG_ERROR(LOG_TAG, "%s error sending L2CAP config parameters.", __func__);
+    client->callbacks.disconnected(client, client->context);
+  }
+}
+
+static void config_request_cb(uint16_t local_channel_id, tL2CAP_CFG_INFO *requested_parameters) {
+  tL2CAP_CFG_INFO response;
+  l2cap_client_t *client = find(local_channel_id);
+
+  if (!client) {
+    LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id);
+    return;
+  }
+
+  memset(&response, 0, sizeof(response));
+  response.result = L2CAP_CFG_OK;
+
+  if (requested_parameters->mtu_present) {
+    // Make sure the peer chose an MTU at least as large as the minimum L2CAP MTU defined
+    // by the Bluetooth Core spec.
+    if (requested_parameters->mtu < L2CAP_MTU_MINIMUM) {
+      response.mtu = L2CAP_MTU_MINIMUM;
+      response.mtu_present = true;
+      response.result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+    } else {
+      client->remote_mtu = requested_parameters->mtu;
+    }
+  }
+
+  if (requested_parameters->fcr_present) {
+    if (requested_parameters->fcr.mode != L2CAP_FCR_BASIC_MODE) {
+      response.fcr_present = true;
+      response.fcr = requested_parameters->fcr;
+      response.fcr.mode = L2CAP_FCR_BASIC_MODE;
+      response.result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+    }
+  }
+
+  if (!L2CA_ConfigRsp(local_channel_id, &response)) {
+    LOG_ERROR(LOG_TAG, "%s unable to send config response for LCID 0x%04x.", __func__, local_channel_id);
+    l2cap_client_disconnect(client);
+    return;
+  }
+
+  // If we've configured both endpoints, let the listener know we've connected.
+  client->configured_peer = true;
+  if (l2cap_client_is_connected(client))
+    client->callbacks.connected(client, client->context);
+}
+
+static void config_completed_cb(uint16_t local_channel_id, tL2CAP_CFG_INFO *negotiated_parameters) {
+  l2cap_client_t *client = find(local_channel_id);
+
+  if (!client) {
+    LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id);
+    return;
+  }
+
+  switch (negotiated_parameters->result) {
+    // We'll get another configuration response later.
+    case L2CAP_CFG_PENDING:
+      break;
+
+    case L2CAP_CFG_UNACCEPTABLE_PARAMS:
+      // TODO: see if we can renegotiate parameters instead of dropping the connection.
+      LOG_WARN(LOG_TAG, "%s dropping L2CAP connection due to unacceptable config parameters.", __func__);
+      l2cap_client_disconnect(client);
+      break;
+
+    case L2CAP_CFG_OK:
+      // If we've configured both endpoints, let the listener know we've connected.
+      client->configured_self = true;
+      if (l2cap_client_is_connected(client))
+        client->callbacks.connected(client, client->context);
+      break;
+
+    // Failure, no further parameter negotiation possible.
+    default:
+      LOG_WARN(LOG_TAG, "%s L2CAP parameter negotiation failed with error code %d.", __func__, negotiated_parameters->result);
+      l2cap_client_disconnect(client);
+      break;
+  }
+}
+
+static void disconnect_request_cb(uint16_t local_channel_id, bool ack_required) {
+  l2cap_client_t *client = find(local_channel_id);
+  if (!client) {
+    LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client with LCID 0x%04x.", __func__, local_channel_id);
+    return;
+  }
+
+  if (ack_required)
+    L2CA_DisconnectRsp(local_channel_id);
+
+  // We already sent a disconnect response so this LCID is now invalid.
+  client->local_channel_id = 0;
+  l2cap_client_disconnect(client);
+
+  client->callbacks.disconnected(client, client->context);
+}
+
+static void disconnect_completed_cb(uint16_t local_channel_id, UNUSED_ATTR uint16_t error_code) {
+  assert(local_channel_id != 0);
+
+  l2cap_client_t *client = find(local_channel_id);
+  if (!client) {
+    LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client with LCID 0x%04x.", __func__, local_channel_id);
+    return;
+  }
+
+  client->local_channel_id = 0;
+  l2cap_client_disconnect(client);
+
+  client->callbacks.disconnected(client, client->context);
+}
+
+static void congestion_cb(uint16_t local_channel_id, bool is_congested) {
+  assert(local_channel_id != 0);
+
+  l2cap_client_t *client = find(local_channel_id);
+  if (!client) {
+    LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id);
+    return;
+  }
+
+  client->is_congested = is_congested;
+
+  if (!is_congested) {
+    // If we just decongested, dispatch whatever we have left over in our queue.
+    // Once that's done, if we're still decongested, notify the listener so it
+    // can start writing again.
+    dispatch_fragments(client);
+    if (!client->is_congested)
+      client->callbacks.write_ready(client, client->context);
+  }
+}
+
+static void read_ready_cb(uint16_t local_channel_id, BT_HDR *packet) {
+  assert(local_channel_id != 0);
+
+  l2cap_client_t *client = find(local_channel_id);
+  if (!client) {
+    LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id);
+    return;
+  }
+
+  // TODO(sharvil): eliminate copy from BT_HDR.
+  buffer_t *buffer = buffer_new(packet->len);
+  memcpy(buffer_ptr(buffer), packet->data + packet->offset, packet->len);
+  osi_free(packet);
+
+  client->callbacks.read_ready(client, buffer, client->context);
+  buffer_free(buffer);
+}
+
+static void write_completed_cb(UNUSED_ATTR uint16_t local_channel_id, UNUSED_ATTR uint16_t packets_completed) {
+  // Do nothing. We update congestion state based on the congestion callback
+  // and we've already removed items from outbound_fragments list so we don't
+  // really care how many packets were successfully dispatched.
+}
+
+static void fragment_packet(l2cap_client_t *client, buffer_t *packet) {
+  assert(client != NULL);
+  assert(packet != NULL);
+
+  // TODO(sharvil): eliminate copy into BT_HDR.
+  BT_HDR* bt_packet = static_cast<BT_HDR*>(
+      osi_malloc(buffer_length(packet) + L2CAP_MIN_OFFSET + sizeof(BT_HDR)));
+  bt_packet->offset = L2CAP_MIN_OFFSET;
+  bt_packet->len = buffer_length(packet);
+  memcpy(bt_packet->data + bt_packet->offset, buffer_ptr(packet), buffer_length(packet));
+
+  for (;;) {
+    if (bt_packet->len <= client->remote_mtu) {
+      if (bt_packet->len > 0)
+        list_append(client->outbound_fragments, bt_packet);
+      else
+        osi_free(bt_packet);
+      break;
+    }
+
+    BT_HDR* fragment = static_cast<BT_HDR*>(
+        osi_malloc(client->remote_mtu + L2CAP_MIN_OFFSET + sizeof(BT_HDR)));
+    fragment->offset = L2CAP_MIN_OFFSET;
+    fragment->len = client->remote_mtu;
+    memcpy(fragment->data + fragment->offset, bt_packet->data + bt_packet->offset, client->remote_mtu);
+
+    list_append(client->outbound_fragments, fragment);
+
+    bt_packet->offset += client->remote_mtu;
+    bt_packet->len -= client->remote_mtu;
+  }
+}
+
+static void dispatch_fragments(l2cap_client_t *client) {
+  assert(client != NULL);
+  assert(!client->is_congested);
+
+  while (!list_is_empty(client->outbound_fragments)) {
+    BT_HDR *packet = (BT_HDR *)list_front(client->outbound_fragments);
+    list_remove(client->outbound_fragments, packet);
+
+    switch (L2CA_DataWrite(client->local_channel_id, packet)) {
+      case L2CAP_DW_CONGESTED:
+        client->is_congested = true;
+        return;
+
+      case L2CAP_DW_FAILED:
+        LOG_ERROR(LOG_TAG, "%s error writing data to L2CAP connection LCID 0x%04x; disconnecting.", __func__, client->local_channel_id);
+        l2cap_client_disconnect(client);
+        return;
+
+      case L2CAP_DW_SUCCESS:
+        break;
+    }
+  }
+}
+
+static l2cap_client_t *find(uint16_t local_channel_id) {
+  assert(local_channel_id != 0);
+
+  for (const list_node_t *node = list_begin(l2cap_clients); node != list_end(l2cap_clients); node = list_next(node)) {
+    l2cap_client_t *client = (l2cap_client_t *)list_node(node);
+    if (client->local_channel_id == local_channel_id)
+      return client;
+  }
+
+  return NULL;
+}
diff --git a/bt/stack/mcap/mca_api.cc b/bt/stack/mcap/mca_api.cc
new file mode 100644
index 0000000..6201e52
--- /dev/null
+++ b/bt/stack/mcap/mca_api.cc
@@ -0,0 +1,906 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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 is the API implementation file for the Multi-Channel Adaptation
+ *  Protocol (MCAP).
+ *
+ ******************************************************************************/
+#include <assert.h>
+#include <string.h>
+
+#include "bt_target.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mca_int.h"
+
+#include "btu.h"
+
+
+/*******************************************************************************
+**
+** Function         mca_process_timeout
+**
+** Description      This function is called by BTU when an MCA timer
+**                  expires.
+**
+**                  This function is for use internal to the stack only.
+**
+** Returns          void
+**
+*******************************************************************************/
+void mca_ccb_timer_timeout(void *data)
+{
+    tMCA_CCB *p_ccb = (tMCA_CCB *)data;
+
+    mca_ccb_event(p_ccb, MCA_CCB_RSP_TOUT_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         MCA_Init
+**
+** Description      Initialize MCAP main control block.
+**                  This function is called at stack start up.
+**
+** Returns          void
+**
+*******************************************************************************/
+void MCA_Init(void)
+{
+    memset(&mca_cb, 0, sizeof(tMCA_CB));
+
+#if defined(MCA_INITIAL_TRACE_LEVEL)
+    mca_cb.trace_level = MCA_INITIAL_TRACE_LEVEL;
+#else
+    mca_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         MCA_SetTraceLevel
+**
+** Description      This function sets the debug trace level for MCA.
+**                  If 0xff is passed, the current trace level is returned.
+**
+**                  Input Parameters:
+**                      level:  The level to set the MCA tracing to:
+**                      0xff-returns the current setting.
+**                      0-turns off tracing.
+**                      >= 1-Errors.
+**                      >= 2-Warnings.
+**                      >= 3-APIs.
+**                      >= 4-Events.
+**                      >= 5-Debug.
+**
+** Returns          The new trace level or current trace level if
+**                  the input parameter is 0xff.
+**
+*******************************************************************************/
+uint8_t MCA_SetTraceLevel (uint8_t level)
+{
+    if (level != 0xFF)
+        mca_cb.trace_level = level;
+
+    return (mca_cb.trace_level);
+}
+
+/*******************************************************************************
+**
+** Function         MCA_Register
+**
+** Description      This function registers an MCAP implementation.
+**                  It is assumed that the control channel PSM and data channel
+**                  PSM are not used by any other instances of the stack.
+**                  If the given p_reg->ctrl_psm is 0, this handle is INT only.
+**
+** Returns          0, if failed. Otherwise, the MCA handle.
+**
+*******************************************************************************/
+tMCA_HANDLE MCA_Register(tMCA_REG *p_reg, tMCA_CTRL_CBACK *p_cback)
+{
+    tMCA_RCB    *p_rcb;
+    tMCA_HANDLE handle = 0;
+    tL2CAP_APPL_INFO l2c_cacp_appl;
+    tL2CAP_APPL_INFO l2c_dacp_appl;
+
+    assert(p_reg != NULL );
+    assert(p_cback != NULL );
+
+    MCA_TRACE_API ("MCA_Register: ctrl_psm:0x%x, data_psm:0x%x", p_reg->ctrl_psm, p_reg->data_psm);
+
+    if ( (p_rcb = mca_rcb_alloc (p_reg)) != NULL)
+    {
+        if (p_reg->ctrl_psm)
+        {
+            if (L2C_INVALID_PSM(p_reg->ctrl_psm) || L2C_INVALID_PSM(p_reg->data_psm))
+            {
+                MCA_TRACE_ERROR ("INVALID_PSM");
+                return 0;
+            }
+
+            l2c_cacp_appl = *(tL2CAP_APPL_INFO *)&mca_l2c_int_appl;
+            l2c_cacp_appl.pL2CA_ConnectCfm_Cb = NULL;
+            l2c_dacp_appl = *(tL2CAP_APPL_INFO *)&l2c_cacp_appl;
+            l2c_cacp_appl.pL2CA_ConnectInd_Cb = mca_l2c_cconn_ind_cback;
+            l2c_dacp_appl.pL2CA_ConnectInd_Cb = mca_l2c_dconn_ind_cback;
+            if (L2CA_Register(p_reg->ctrl_psm, (tL2CAP_APPL_INFO *) &l2c_cacp_appl) &&
+                L2CA_Register(p_reg->data_psm, (tL2CAP_APPL_INFO *) &l2c_dacp_appl))
+            {
+                /* set security level */
+                BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_MCAP_CTRL, p_reg->sec_mask,
+                    p_reg->ctrl_psm, BTM_SEC_PROTO_MCA, MCA_CTRL_TCID);
+
+                /* in theory, we do not need this one for data_psm
+                 * If we don't, L2CAP rejects with security block (3),
+                 * which is different reject code from what MCAP spec suggests.
+                 * we set this one, so mca_l2c_dconn_ind_cback can reject /w no resources (4) */
+                BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_MCAP_DATA, p_reg->sec_mask,
+                    p_reg->data_psm, BTM_SEC_PROTO_MCA, MCA_CTRL_TCID);
+            }
+            else
+            {
+                MCA_TRACE_ERROR ("Failed to register to L2CAP");
+                return 0;
+            }
+        }
+        else
+            p_rcb->reg.data_psm = 0;
+        handle = mca_rcb_to_handle (p_rcb);
+        p_rcb->p_cback = p_cback;
+        p_rcb->reg.rsp_tout = p_reg->rsp_tout;
+    }
+    return handle;
+}
+
+
+/*******************************************************************************
+**
+** Function         MCA_Deregister
+**
+** Description      This function is called to deregister an MCAP implementation.
+**                  Before this function can be called, all control and data
+**                  channels must be removed with MCA_DisconnectReq and MCA_CloseReq.
+**
+** Returns          void
+**
+*******************************************************************************/
+void MCA_Deregister(tMCA_HANDLE handle)
+{
+    tMCA_RCB *p_rcb = mca_rcb_by_handle(handle);
+
+    MCA_TRACE_API ("MCA_Deregister: %d", handle);
+    if (p_rcb && p_rcb->reg.ctrl_psm)
+    {
+        L2CA_Deregister(p_rcb->reg.ctrl_psm);
+        L2CA_Deregister(p_rcb->reg.data_psm);
+        btm_sec_clr_service_by_psm (p_rcb->reg.ctrl_psm);
+        btm_sec_clr_service_by_psm (p_rcb->reg.data_psm);
+    }
+    mca_rcb_dealloc(handle);
+}
+
+
+/*******************************************************************************
+**
+** Function         MCA_CreateDep
+**
+** Description      Create a data endpoint.  If the MDEP is created successfully,
+**                  the MDEP ID is returned in *p_dep. After a data endpoint is
+**                  created, an application can initiate a connection between this
+**                  endpoint and an endpoint on a peer device.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_CreateDep(tMCA_HANDLE handle, tMCA_DEP *p_dep, tMCA_CS *p_cs)
+{
+    tMCA_RESULT result = MCA_BAD_HANDLE;
+    int       i;
+    tMCA_RCB *p_rcb = mca_rcb_by_handle(handle);
+    tMCA_CS  *p_depcs;
+
+    assert(p_dep != NULL );
+    assert(p_cs != NULL );
+    assert(p_cs->p_data_cback != NULL );
+
+    MCA_TRACE_API ("MCA_CreateDep: %d", handle);
+    if (p_rcb)
+    {
+        if (p_cs->max_mdl > MCA_NUM_MDLS)
+        {
+            MCA_TRACE_ERROR ("max_mdl: %d is too big", p_cs->max_mdl );
+            result = MCA_BAD_PARAMS;
+        }
+        else
+        {
+            p_depcs = p_rcb->dep;
+            if (p_cs->type == MCA_TDEP_ECHO)
+            {
+                if (p_depcs->p_data_cback)
+                {
+                    MCA_TRACE_ERROR ("Already has ECHO MDEP");
+                    return MCA_NO_RESOURCES;
+                }
+                memcpy (p_depcs, p_cs, sizeof (tMCA_CS));
+                *p_dep = 0;
+                result = MCA_SUCCESS;
+            }
+            else
+            {
+                result = MCA_NO_RESOURCES;
+                /* non-echo MDEP starts from 1 */
+                p_depcs++;
+                for (i=1; i<MCA_NUM_DEPS; i++, p_depcs++)
+                {
+                    if (p_depcs->p_data_cback == NULL)
+                    {
+                        memcpy (p_depcs, p_cs, sizeof (tMCA_CS));
+                        /* internally use type as the mdep id */
+                        p_depcs->type = i;
+                        *p_dep = i;
+                        result = MCA_SUCCESS;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+    return result;
+}
+
+
+/*******************************************************************************
+**
+** Function         MCA_DeleteDep
+**
+** Description      Delete a data endpoint.  This function is called when
+**                  the implementation is no longer using a data endpoint.
+**                  If this function is called when the endpoint is connected
+**                  the connection is closed and the data endpoint
+**                  is removed.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_DeleteDep(tMCA_HANDLE handle, tMCA_DEP dep)
+{
+    tMCA_RESULT result = MCA_BAD_HANDLE;
+    tMCA_RCB *p_rcb = mca_rcb_by_handle(handle);
+    tMCA_DCB *p_dcb;
+    int      i, max;
+    tMCA_CS  *p_depcs;
+
+    MCA_TRACE_API ("MCA_DeleteDep: %d dep:%d", handle, dep);
+    if (p_rcb)
+    {
+        if (dep < MCA_NUM_DEPS && p_rcb->dep[dep].p_data_cback)
+        {
+            result = MCA_SUCCESS;
+            p_rcb->dep[dep].p_data_cback = NULL;
+            p_depcs = &(p_rcb->dep[dep]);
+            i = handle - 1;
+            max = MCA_NUM_MDLS*MCA_NUM_LINKS;
+            p_dcb = &mca_cb.dcb[i*max];
+            /* make sure no MDL exists for this MDEP */
+            for (i=0; i<max; i++, p_dcb++)
+            {
+                if (p_dcb->state && p_dcb->p_cs == p_depcs)
+                {
+                    mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
+                }
+            }
+        }
+    }
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         MCA_ConnectReq
+**
+** Description      This function initiates an MCAP control channel connection
+**                  to the peer device.  When the connection is completed, an
+**                  MCA_CONNECT_IND_EVT is reported to the application via its
+**                  control callback function.
+**                  This control channel is identified by the tMCA_CL.
+**                  If the connection attempt fails, an MCA_DISCONNECT_IND_EVT is
+**                  reported. The security mask parameter overrides the outgoing
+**                  security mask set in MCA_Register().
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_ConnectReq(tMCA_HANDLE handle, BD_ADDR bd_addr,
+                           uint16_t ctrl_psm, uint16_t sec_mask)
+{
+    tMCA_RESULT result = MCA_BAD_HANDLE;
+    tMCA_CCB    *p_ccb;
+    tMCA_TC_TBL *p_tbl;
+
+    MCA_TRACE_API ("MCA_ConnectReq: %d psm:0x%x", handle, ctrl_psm);
+    if ((p_ccb = mca_ccb_by_bd(handle, bd_addr)) == NULL)
+        p_ccb = mca_ccb_alloc(handle, bd_addr);
+    else
+    {
+        MCA_TRACE_ERROR ("control channel already exists");
+        return MCA_BUSY;
+    }
+
+    if (p_ccb)
+    {
+        p_ccb->ctrl_vpsm = L2CA_Register (ctrl_psm, (tL2CAP_APPL_INFO *)&mca_l2c_int_appl);
+        result = MCA_NO_RESOURCES;
+        if (p_ccb->ctrl_vpsm)
+        {
+            BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_MCAP_CTRL, sec_mask,
+                p_ccb->ctrl_vpsm, BTM_SEC_PROTO_MCA, MCA_CTRL_TCID);
+            p_ccb->lcid = mca_l2c_open_req(bd_addr, p_ccb->ctrl_vpsm, NULL);
+            if (p_ccb->lcid)
+            {
+                p_tbl = mca_tc_tbl_calloc(p_ccb);
+                if (p_tbl)
+                {
+                    p_tbl->state = MCA_TC_ST_CONN;
+                    p_ccb->sec_mask = sec_mask;
+                    result = MCA_SUCCESS;
+                }
+            }
+        }
+        if (result != MCA_SUCCESS)
+            mca_ccb_dealloc (p_ccb, NULL);
+    }
+    return result;
+}
+
+
+/*******************************************************************************
+**
+** Function         MCA_DisconnectReq
+**
+** Description      This function disconnect an MCAP control channel
+**                  to the peer device.
+**                  If associated data channel exists, they are disconnected.
+**                  When the MCL is disconnected an MCA_DISCONNECT_IND_EVT is
+**                  reported to the application via its control callback function.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_DisconnectReq(tMCA_CL mcl)
+{
+    tMCA_RESULT result = MCA_BAD_HANDLE;
+    tMCA_CCB *p_ccb = mca_ccb_by_hdl(mcl);
+
+    MCA_TRACE_API ("MCA_DisconnectReq: %d ", mcl);
+    if (p_ccb)
+    {
+        result = MCA_SUCCESS;
+        mca_ccb_event (p_ccb, MCA_CCB_API_DISCONNECT_EVT, NULL);
+    }
+    return result;
+}
+
+
+/*******************************************************************************
+**
+** Function         MCA_CreateMdl
+**
+** Description      This function sends a CREATE_MDL request to the peer device.
+**                  When the response is received, a MCA_CREATE_CFM_EVT is reported
+**                  with the given MDL ID.
+**                  If the response is successful, a data channel is open
+**                  with the given p_chnl_cfg
+**                  If p_chnl_cfg is NULL, the data channel is not initiated until
+**                  MCA_DataChnlCfg is called to provide the p_chnl_cfg.
+**                  When the data channel is open successfully, a MCA_OPEN_CFM_EVT
+**                  is reported. This data channel is identified as tMCA_DL.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_CreateMdl(tMCA_CL mcl, tMCA_DEP dep, uint16_t data_psm,
+                                         uint16_t mdl_id, uint8_t peer_dep_id,
+                                         uint8_t cfg, const tMCA_CHNL_CFG *p_chnl_cfg)
+{
+    tMCA_RESULT     result = MCA_BAD_HANDLE;
+    tMCA_CCB        *p_ccb = mca_ccb_by_hdl(mcl);
+    tMCA_DCB        *p_dcb;
+
+    MCA_TRACE_API ("MCA_CreateMdl: %d dep=%d mdl_id=%d peer_dep_id=%d", mcl, dep, mdl_id, peer_dep_id);
+    if (p_ccb)
+    {
+        if (p_ccb->p_tx_req || p_ccb->p_rx_msg || p_ccb->cong)
+        {
+            MCA_TRACE_ERROR ("pending req");
+            return MCA_BUSY;
+        }
+
+        if ((peer_dep_id > MCA_MAX_MDEP_ID) || (!MCA_IS_VALID_MDL_ID(mdl_id)))
+        {
+            MCA_TRACE_ERROR ("bad peer dep id:%d or bad mdl id: %d ", peer_dep_id, mdl_id);
+            return MCA_BAD_PARAMS;
+        }
+
+        if (mca_ccb_uses_mdl_id(p_ccb, mdl_id))
+        {
+            MCA_TRACE_ERROR ("mdl id: %d is used in the control link", mdl_id);
+            return MCA_BAD_MDL_ID;
+        }
+
+        p_dcb = mca_dcb_alloc(p_ccb, dep);
+        result = MCA_NO_RESOURCES;
+        if (p_dcb)
+        {
+            /* save the info required by dcb connection */
+            p_dcb->p_chnl_cfg       = p_chnl_cfg;
+            p_dcb->mdl_id           = mdl_id;
+            tMCA_CCB_MSG *p_evt_data =
+                (tMCA_CCB_MSG *)osi_malloc(sizeof(tMCA_CCB_MSG));
+            if (!p_ccb->data_vpsm)
+                p_ccb->data_vpsm = L2CA_Register (data_psm, (tL2CAP_APPL_INFO *)&mca_l2c_int_appl);
+            if (p_ccb->data_vpsm) {
+                p_evt_data->dcb_idx     = mca_dcb_to_hdl (p_dcb);
+                p_evt_data->mdep_id     = peer_dep_id;
+                p_evt_data->mdl_id      = mdl_id;
+                p_evt_data->param       = cfg;
+                p_evt_data->op_code     = MCA_OP_MDL_CREATE_REQ;
+                p_evt_data->hdr.event   = MCA_CCB_API_REQ_EVT;
+                p_evt_data->hdr.layer_specific   = false;
+                mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data);
+                return MCA_SUCCESS;
+            } else {
+                osi_free(p_evt_data);
+            }
+
+            mca_dcb_dealloc(p_dcb, NULL);
+        }
+    }
+    return result;
+}
+
+
+/*******************************************************************************
+**
+** Function         MCA_CreateMdlRsp
+**
+** Description      This function sends a CREATE_MDL response to the peer device
+**                  in response to a received MCA_CREATE_IND_EVT.
+**                  If the rsp_code is successful, a data channel is open
+**                  with the given p_chnl_cfg
+**                  When the data channel is open successfully, a MCA_OPEN_IND_EVT
+**                  is reported. This data channel is identified as tMCA_DL.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_CreateMdlRsp(tMCA_CL mcl, tMCA_DEP dep,
+                                            uint16_t mdl_id, uint8_t cfg, uint8_t rsp_code,
+                                            const tMCA_CHNL_CFG *p_chnl_cfg)
+{
+    tMCA_RESULT     result = MCA_BAD_HANDLE;
+    tMCA_CCB        *p_ccb = mca_ccb_by_hdl(mcl);
+    tMCA_CCB_MSG    evt_data;
+    tMCA_DCB        *p_dcb;
+
+    MCA_TRACE_API ("MCA_CreateMdlRsp: %d dep=%d mdl_id=%d cfg=%d rsp_code=%d", mcl, dep, mdl_id, cfg, rsp_code);
+    assert(p_chnl_cfg != NULL );
+    if (p_ccb)
+    {
+        if (p_ccb->cong)
+        {
+            MCA_TRACE_ERROR ("congested");
+            return MCA_BUSY;
+        }
+        if (p_ccb->p_rx_msg && (p_ccb->p_rx_msg->mdep_id == dep )
+            && (p_ccb->p_rx_msg->mdl_id == mdl_id) && (p_ccb->p_rx_msg->op_code == MCA_OP_MDL_CREATE_REQ))
+        {
+            result = MCA_SUCCESS;
+            evt_data.dcb_idx    = 0;
+            if (rsp_code == MCA_RSP_SUCCESS)
+            {
+                p_dcb = mca_dcb_alloc(p_ccb, dep);
+                if (p_dcb)
+                {
+                    evt_data.dcb_idx    = mca_dcb_to_hdl(p_dcb);
+                    p_dcb->p_chnl_cfg   = p_chnl_cfg;
+                    p_dcb->mdl_id       = mdl_id;
+                }
+                else
+                {
+                    rsp_code = MCA_RSP_MDEP_BUSY;
+                    result = MCA_NO_RESOURCES;
+                }
+            }
+
+            if (result == MCA_SUCCESS)
+            {
+                evt_data.mdl_id     = mdl_id;
+                evt_data.param      = cfg;
+                evt_data.rsp_code   = rsp_code;
+                evt_data.op_code    = MCA_OP_MDL_CREATE_RSP;
+                mca_ccb_event(p_ccb, MCA_CCB_API_RSP_EVT, (tMCA_CCB_EVT *)&evt_data);
+            }
+        }
+        else
+        {
+            MCA_TRACE_ERROR ("The given MCL is not expecting a MCA_CreateMdlRsp with the given parameters" );
+            result = MCA_BAD_PARAMS;
+        }
+    }
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         MCA_CloseReq
+**
+** Description      Close a data channel.  When the channel is closed, an
+**                  MCA_CLOSE_CFM_EVT is sent to the application via the
+**                  control callback function for this handle.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_CloseReq(tMCA_DL mdl)
+{
+    tMCA_RESULT     result = MCA_BAD_HANDLE;
+    tMCA_DCB *p_dcb = mca_dcb_by_hdl(mdl);
+
+    MCA_TRACE_API ("MCA_CloseReq: %d ", mdl);
+    if (p_dcb)
+    {
+        result = MCA_SUCCESS;
+        mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
+    }
+    return result;
+}
+
+
+/*******************************************************************************
+**
+** Function         MCA_ReconnectMdl
+**
+** Description      This function sends a RECONNECT_MDL request to the peer device.
+**                  When the response is received, a MCA_RECONNECT_CFM_EVT is reported.
+**                  If p_chnl_cfg is NULL, the data channel is not initiated until
+**                  MCA_DataChnlCfg is called to provide the p_chnl_cfg.
+**                  If the response is successful, a data channel is open.
+**                  When the data channel is open successfully, a MCA_OPEN_CFM_EVT
+**                  is reported.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_ReconnectMdl(tMCA_CL mcl, tMCA_DEP dep, uint16_t data_psm,
+                                            uint16_t mdl_id, const tMCA_CHNL_CFG *p_chnl_cfg)
+{
+    tMCA_RESULT     result = MCA_BAD_HANDLE;
+    tMCA_CCB        *p_ccb = mca_ccb_by_hdl(mcl);
+    tMCA_DCB        *p_dcb;
+
+    MCA_TRACE_API ("MCA_ReconnectMdl: %d ", mcl);
+    assert(p_chnl_cfg != NULL );
+    if (p_ccb)
+    {
+        if (p_ccb->p_tx_req || p_ccb->p_rx_msg || p_ccb->cong)
+        {
+            MCA_TRACE_ERROR ("pending req");
+            return MCA_BUSY;
+        }
+
+        if (!MCA_IS_VALID_MDL_ID(mdl_id))
+        {
+            MCA_TRACE_ERROR ("bad mdl id: %d ", mdl_id);
+            return MCA_BAD_PARAMS;
+        }
+
+        if (mca_ccb_uses_mdl_id(p_ccb, mdl_id))
+        {
+            MCA_TRACE_ERROR ("mdl id: %d is used in the control link", mdl_id);
+            return MCA_BAD_MDL_ID;
+        }
+
+        p_dcb = mca_dcb_alloc(p_ccb, dep);
+        result = MCA_NO_RESOURCES;
+        if (p_dcb) {
+            tMCA_CCB_MSG *p_evt_data =
+                (tMCA_CCB_MSG *)osi_malloc(sizeof(tMCA_CCB_MSG));
+
+            p_dcb->p_chnl_cfg       = p_chnl_cfg;
+            p_dcb->mdl_id           = mdl_id;
+            if (!p_ccb->data_vpsm)
+                p_ccb->data_vpsm = L2CA_Register (data_psm, (tL2CAP_APPL_INFO *)&mca_l2c_int_appl);
+            p_evt_data->dcb_idx     = mca_dcb_to_hdl(p_dcb);
+            p_evt_data->mdl_id      = mdl_id;
+            p_evt_data->op_code     = MCA_OP_MDL_RECONNECT_REQ;
+            p_evt_data->hdr.event   = MCA_CCB_API_REQ_EVT;
+            mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data);
+            return MCA_SUCCESS;
+        }
+    }
+    return result;
+}
+
+
+/*******************************************************************************
+**
+** Function         MCA_ReconnectMdlRsp
+**
+** Description      This function sends a RECONNECT_MDL response to the peer device
+**                  in response to a MCA_RECONNECT_IND_EVT event.
+**                  If the response is successful, a data channel is open.
+**                  When the data channel is open successfully, a MCA_OPEN_IND_EVT
+**                  is reported.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_ReconnectMdlRsp(tMCA_CL mcl, tMCA_DEP dep,
+                                               uint16_t mdl_id, uint8_t rsp_code,
+                                               const tMCA_CHNL_CFG *p_chnl_cfg)
+{
+    tMCA_RESULT     result = MCA_BAD_HANDLE;
+    tMCA_CCB        *p_ccb = mca_ccb_by_hdl(mcl);
+    tMCA_CCB_MSG    evt_data;
+    tMCA_DCB        *p_dcb;
+
+    MCA_TRACE_API ("MCA_ReconnectMdlRsp: %d ", mcl);
+    assert(p_chnl_cfg != NULL );
+    if (p_ccb)
+    {
+        if (p_ccb->cong)
+        {
+            MCA_TRACE_ERROR ("congested");
+            return MCA_BUSY;
+        }
+        if (p_ccb->p_rx_msg && (p_ccb->p_rx_msg->mdl_id == mdl_id) &&
+            (p_ccb->p_rx_msg->op_code == MCA_OP_MDL_RECONNECT_REQ))
+        {
+            result = MCA_SUCCESS;
+            evt_data.dcb_idx    = 0;
+            if (rsp_code == MCA_RSP_SUCCESS)
+            {
+                p_dcb = mca_dcb_alloc(p_ccb, dep);
+                if (p_dcb)
+                {
+                    evt_data.dcb_idx    = mca_dcb_to_hdl(p_dcb);
+                    p_dcb->p_chnl_cfg   = p_chnl_cfg;
+                    p_dcb->mdl_id       = mdl_id;
+                }
+                else
+                {
+                    MCA_TRACE_ERROR ("Out of MDL for this MDEP");
+                    rsp_code = MCA_RSP_MDEP_BUSY;
+                    result = MCA_NO_RESOURCES;
+                }
+            }
+
+            evt_data.mdl_id     = mdl_id;
+            evt_data.rsp_code   = rsp_code;
+            evt_data.op_code    = MCA_OP_MDL_RECONNECT_RSP;
+            mca_ccb_event(p_ccb, MCA_CCB_API_RSP_EVT, (tMCA_CCB_EVT *)&evt_data);
+        }
+        else
+        {
+            MCA_TRACE_ERROR ("The given MCL is not expecting a MCA_ReconnectMdlRsp with the given parameters" );
+            result = MCA_BAD_PARAMS;
+        }
+    }
+    return result;
+}
+
+
+/*******************************************************************************
+**
+** Function         MCA_DataChnlCfg
+**
+** Description      This function initiates a data channel connection toward the
+**                  connected peer device.
+**                  When the data channel is open successfully, a MCA_OPEN_CFM_EVT
+**                  is reported. This data channel is identified as tMCA_DL.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_DataChnlCfg(tMCA_CL mcl, const tMCA_CHNL_CFG *p_chnl_cfg)
+{
+    tMCA_RESULT     result = MCA_BAD_HANDLE;
+    tMCA_CCB        *p_ccb = mca_ccb_by_hdl(mcl);
+    tMCA_DCB        *p_dcb;
+    tMCA_TC_TBL *p_tbl;
+
+    MCA_TRACE_API ("MCA_DataChnlCfg: %d ", mcl);
+    assert(p_chnl_cfg != NULL );
+    if (p_ccb)
+    {
+        result = MCA_NO_RESOURCES;
+        if ((p_ccb->p_tx_req == NULL) || (p_ccb->status != MCA_CCB_STAT_PENDING) ||
+            ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) == NULL))
+        {
+            MCA_TRACE_ERROR ("The given MCL is not expecting this API:%d", p_ccb->status);
+            return result;
+        }
+
+        p_dcb->p_chnl_cfg       = p_chnl_cfg;
+        BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask,
+            p_ccb->data_vpsm, BTM_SEC_PROTO_MCA, p_ccb->p_tx_req->dcb_idx);
+        p_dcb->lcid = mca_l2c_open_req(p_ccb->peer_addr, p_ccb->data_vpsm, p_dcb->p_chnl_cfg);
+        if (p_dcb->lcid)
+        {
+            p_tbl = mca_tc_tbl_dalloc(p_dcb);
+            if (p_tbl)
+            {
+                p_tbl->state = MCA_TC_ST_CONN;
+                result = MCA_SUCCESS;
+            }
+        }
+    }
+    return result;
+}
+
+
+/*******************************************************************************
+**
+** Function         MCA_Abort
+**
+** Description      This function sends a ABORT_MDL request to the peer device.
+**                  When the response is received, a MCA_ABORT_CFM_EVT is reported.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_Abort(tMCA_CL mcl)
+{
+    tMCA_RESULT     result = MCA_BAD_HANDLE;
+    tMCA_CCB        *p_ccb = mca_ccb_by_hdl(mcl);
+    tMCA_DCB        *p_dcb;
+
+    MCA_TRACE_API ("MCA_Abort: %d", mcl);
+    if (p_ccb)
+    {
+        result = MCA_NO_RESOURCES;
+        /* verify that we are waiting for data channel to come up with the given mdl */
+        if ((p_ccb->p_tx_req == NULL) || (p_ccb->status != MCA_CCB_STAT_PENDING) ||
+            ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) == NULL))
+        {
+            MCA_TRACE_ERROR ("The given MCL is not expecting this API:%d", p_ccb->status);
+            return result;
+        }
+
+        if (p_ccb->cong)
+        {
+            MCA_TRACE_ERROR ("congested");
+            return MCA_BUSY;
+        }
+
+        tMCA_CCB_MSG *p_evt_data =
+            (tMCA_CCB_MSG *)osi_malloc(sizeof(tMCA_CCB_MSG));
+        result = MCA_SUCCESS;
+        p_evt_data->op_code     = MCA_OP_MDL_ABORT_REQ;
+        p_evt_data->hdr.event   = MCA_CCB_API_REQ_EVT;
+        mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data);
+    }
+    return result;
+}
+
+
+/*******************************************************************************
+**
+** Function         MCA_Delete
+**
+** Description      This function sends a DELETE_MDL request to the peer device.
+**                  When the response is received, a MCA_DELETE_CFM_EVT is reported.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_Delete(tMCA_CL mcl, uint16_t mdl_id)
+{
+    tMCA_RESULT     result = MCA_BAD_HANDLE;
+    tMCA_CCB        *p_ccb = mca_ccb_by_hdl(mcl);
+
+    MCA_TRACE_API ("MCA_Delete: %d ", mcl);
+    if (p_ccb)
+    {
+        if (p_ccb->cong)
+        {
+            MCA_TRACE_ERROR ("congested");
+            return MCA_BUSY;
+        }
+        if (!MCA_IS_VALID_MDL_ID(mdl_id) && (mdl_id != MCA_ALL_MDL_ID))
+        {
+            MCA_TRACE_ERROR ("bad mdl id: %d ", mdl_id);
+            return MCA_BAD_PARAMS;
+        }
+
+        tMCA_CCB_MSG *p_evt_data = (tMCA_CCB_MSG *)osi_malloc(sizeof(tMCA_CCB_MSG));
+        result = MCA_SUCCESS;
+        p_evt_data->mdl_id      = mdl_id;
+        p_evt_data->op_code     = MCA_OP_MDL_DELETE_REQ;
+        p_evt_data->hdr.event   = MCA_CCB_API_REQ_EVT;
+        mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT *)p_evt_data);
+    }
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         MCA_WriteReq
+**
+** Description      Send a data packet to the peer device.
+**
+**                  The application passes the packet using the BT_HDR structure.
+**                  The offset field must be equal to or greater than L2CAP_MIN_OFFSET.
+**                  This allows enough space in the buffer for the L2CAP header.
+**
+**                  The memory pointed to by p_pkt must be a GKI buffer
+**                  allocated by the application.  This buffer will be freed
+**                  by the protocol stack; the application must not free
+**                  this buffer.
+**
+** Returns          MCA_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+tMCA_RESULT MCA_WriteReq(tMCA_DL mdl, BT_HDR *p_pkt)
+{
+    tMCA_RESULT     result = MCA_BAD_HANDLE;
+    tMCA_DCB *p_dcb = mca_dcb_by_hdl(mdl);
+    tMCA_DCB_EVT    evt_data;
+
+    MCA_TRACE_API ("MCA_WriteReq: %d ", mdl);
+    if (p_dcb)
+    {
+        if (p_dcb->cong)
+        {
+            result = MCA_BUSY;
+        }
+        else
+        {
+            evt_data.p_pkt  = p_pkt;
+            result = MCA_SUCCESS;
+            mca_dcb_event(p_dcb, MCA_DCB_API_WRITE_EVT, &evt_data);
+        }
+    }
+    return result;
+}
+
+/*******************************************************************************
+**
+** Function         MCA_GetL2CapChannel
+**
+** Description      Get the L2CAP CID used by the given data channel handle.
+**
+** Returns          L2CAP channel ID if successful, otherwise 0.
+**
+*******************************************************************************/
+uint16_t MCA_GetL2CapChannel (tMCA_DL mdl)
+{
+    uint16_t lcid = 0;
+    tMCA_DCB *p_dcb = mca_dcb_by_hdl(mdl);
+
+    MCA_TRACE_API ("MCA_GetL2CapChannel: %d ", mdl);
+    if (p_dcb)
+        lcid = p_dcb->lcid;
+    return lcid;
+}
+
diff --git a/bt/stack/mcap/mca_cact.cc b/bt/stack/mcap/mca_cact.cc
new file mode 100644
index 0000000..1af8d97
--- /dev/null
+++ b/bt/stack/mcap/mca_cact.cc
@@ -0,0 +1,577 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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 is the implementation file for the MCAP Control Channel Action
+ *  Functions.
+ *
+ ******************************************************************************/
+#include <string.h>
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "bt_common.h"
+#include "btm_api.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mca_int.h"
+#include "osi/include/osi.h"
+
+
+#include  "btu.h"
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function         mca_ccb_rsp_tout
+**
+** Description      This function processes the response timeout.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_ccb_rsp_tout(tMCA_CCB *p_ccb,
+                      UNUSED_ATTR tMCA_CCB_EVT *p_data)
+{
+   tMCA_CTRL   evt_data;
+
+   mca_ccb_report_event(p_ccb, MCA_RSP_TOUT_IND_EVT, &evt_data);
+}
+
+/*******************************************************************************
+**
+** Function         mca_ccb_report_event
+**
+** Description      This function reports the given event.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_ccb_report_event(tMCA_CCB *p_ccb, uint8_t event, tMCA_CTRL *p_data)
+{
+    if (p_ccb && p_ccb->p_rcb && p_ccb->p_rcb->p_cback)
+        (*p_ccb->p_rcb->p_cback)(mca_rcb_to_handle(p_ccb->p_rcb), mca_ccb_to_hdl(p_ccb), event, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         mca_ccb_free_msg
+**
+** Description      This function frees the received message.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_ccb_free_msg(UNUSED_ATTR tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
+{
+    osi_free(p_data);
+}
+
+/*******************************************************************************
+**
+** Function         mca_ccb_snd_req
+**
+** Description      This function builds a request and sends it to the peer.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_ccb_snd_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
+{
+    tMCA_CCB_MSG *p_msg = (tMCA_CCB_MSG *)p_data;
+    uint8_t *p, *p_start;
+    bool    is_abort = false;
+    tMCA_DCB *p_dcb;
+
+    MCA_TRACE_DEBUG ("mca_ccb_snd_req cong=%d req=%d", p_ccb->cong, p_msg->op_code);
+    /* check for abort request */
+    if ((p_ccb->status == MCA_CCB_STAT_PENDING) && (p_msg->op_code == MCA_OP_MDL_ABORT_REQ))
+    {
+        p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx);
+        /* the Abort API does not have the associated mdl_id.
+         * Get the mdl_id in dcb to compose the request */
+        p_msg->mdl_id = p_dcb->mdl_id;
+        mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
+        osi_free_and_reset((void **)&p_ccb->p_tx_req);
+        p_ccb->status = MCA_CCB_STAT_NORM;
+        is_abort = true;
+    }
+
+    /* no pending outgoing messages or it's an abort request for a pending data channel */
+    if ((!p_ccb->p_tx_req) || is_abort)
+    {
+        p_ccb->p_tx_req = p_msg;
+        if (!p_ccb->cong)
+        {
+            BT_HDR *p_pkt = (BT_HDR *)osi_malloc(MCA_CTRL_MTU + sizeof(BT_HDR));
+
+            p_pkt->offset = L2CAP_MIN_OFFSET;
+            p = p_start = (uint8_t*)(p_pkt + 1) + L2CAP_MIN_OFFSET;
+            *p++ = p_msg->op_code;
+            UINT16_TO_BE_STREAM (p, p_msg->mdl_id);
+            if (p_msg->op_code == MCA_OP_MDL_CREATE_REQ) {
+                *p++ = p_msg->mdep_id;
+                *p++ = p_msg->param;
+            }
+            p_msg->hdr.layer_specific = true;   /* mark this message as sent */
+            p_pkt->len = p - p_start;
+            L2CA_DataWrite (p_ccb->lcid, p_pkt);
+            period_ms_t interval_ms = p_ccb->p_rcb->reg.rsp_tout * 1000;
+            alarm_set_on_queue(p_ccb->mca_ccb_timer, interval_ms,
+                               mca_ccb_timer_timeout, p_ccb,
+                               btu_general_alarm_queue);
+        }
+        /* else the L2CAP channel is congested. keep the message to be sent later */
+    }
+    else
+    {
+        MCA_TRACE_WARNING ("dropping api req");
+        osi_free(p_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         mca_ccb_snd_rsp
+**
+** Description      This function builds a response and sends it to
+**                  the peer.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_ccb_snd_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
+{
+    tMCA_CCB_MSG *p_msg = (tMCA_CCB_MSG *)p_data;
+    uint8_t *p, *p_start;
+    bool    chk_mdl = false;
+    BT_HDR *p_pkt = (BT_HDR *)osi_malloc(MCA_CTRL_MTU + sizeof(BT_HDR));
+
+    MCA_TRACE_DEBUG("%s cong=%d req=%d", __func__, p_ccb->cong, p_msg->op_code);
+    /* assume that API functions verified the parameters */
+
+    p_pkt->offset = L2CAP_MIN_OFFSET;
+    p = p_start = (uint8_t*)(p_pkt + 1) + L2CAP_MIN_OFFSET;
+    *p++ = p_msg->op_code;
+    *p++ = p_msg->rsp_code;
+    UINT16_TO_BE_STREAM (p, p_msg->mdl_id);
+    if (p_msg->op_code == MCA_OP_MDL_CREATE_RSP) {
+        *p++ = p_msg->param;
+        chk_mdl = true;
+    }
+    else if (p_msg->op_code == MCA_OP_MDL_RECONNECT_RSP) {
+        chk_mdl = true;
+    }
+
+    if (chk_mdl && p_msg->rsp_code == MCA_RSP_SUCCESS) {
+        mca_dcb_by_hdl(p_msg->dcb_idx);
+        BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_MCAP_DATA,
+                             p_ccb->sec_mask,
+                             p_ccb->p_rcb->reg.data_psm, BTM_SEC_PROTO_MCA,
+                             p_msg->dcb_idx);
+        p_ccb->status = MCA_CCB_STAT_PENDING;
+        /* set p_tx_req to block API_REQ/API_RSP before DL is up */
+        osi_free_and_reset((void **)&p_ccb->p_tx_req);
+        p_ccb->p_tx_req = p_ccb->p_rx_msg;
+        p_ccb->p_rx_msg = NULL;
+        p_ccb->p_tx_req->dcb_idx = p_msg->dcb_idx;
+    }
+    osi_free_and_reset((void **)&p_ccb->p_rx_msg);
+    p_pkt->len = p - p_start;
+    L2CA_DataWrite(p_ccb->lcid, p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function         mca_ccb_do_disconn
+**
+** Description      This function closes a control channel.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_ccb_do_disconn (tMCA_CCB *p_ccb,
+                         UNUSED_ATTR tMCA_CCB_EVT *p_data)
+{
+    mca_dcb_close_by_mdl_id (p_ccb, MCA_ALL_MDL_ID);
+    L2CA_DisconnectReq(p_ccb->lcid);
+}
+
+/*******************************************************************************
+**
+** Function         mca_ccb_cong
+**
+** Description      This function sets the congestion state for the CCB.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_ccb_cong(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
+{
+    MCA_TRACE_DEBUG ("mca_ccb_cong cong=%d/%d", p_ccb->cong, p_data->llcong);
+    p_ccb->cong = p_data->llcong;
+    if (!p_ccb->cong)
+    {
+        /* if there's a held packet, send it now */
+        if (p_ccb->p_tx_req && !p_ccb->p_tx_req->hdr.layer_specific)
+        {
+            p_data = (tMCA_CCB_EVT *)p_ccb->p_tx_req;
+            p_ccb->p_tx_req = NULL;
+            mca_ccb_snd_req (p_ccb, p_data);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         mca_ccb_hdl_req
+**
+** Description      This function is called when a MCAP request is received from
+**                  the peer. It calls the application callback function to
+**                  report the event.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_ccb_hdl_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
+{
+    BT_HDR  *p_pkt = &p_data->hdr;
+    uint8_t *p, *p_start;
+    tMCA_DCB    *p_dcb;
+    tMCA_CTRL       evt_data;
+    tMCA_CCB_MSG    *p_rx_msg = NULL;
+    uint8_t         reject_code = MCA_RSP_NO_RESOURCE;
+    bool            send_rsp = false;
+    bool            check_req = false;
+    uint8_t         reject_opcode;
+
+    MCA_TRACE_DEBUG ("mca_ccb_hdl_req status:%d", p_ccb->status);
+    p_rx_msg = (tMCA_CCB_MSG *)p_pkt;
+    p = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+    evt_data.hdr.op_code = *p++;
+    BE_STREAM_TO_UINT16 (evt_data.hdr.mdl_id, p);
+    reject_opcode = evt_data.hdr.op_code+1;
+
+    MCA_TRACE_DEBUG ("received mdl id: %d ", evt_data.hdr.mdl_id);
+    if (p_ccb->status == MCA_CCB_STAT_PENDING)
+    {
+        MCA_TRACE_DEBUG ("received req inpending state");
+        /* allow abort in pending state */
+        if ((p_ccb->status == MCA_CCB_STAT_PENDING) && (evt_data.hdr.op_code == MCA_OP_MDL_ABORT_REQ))
+        {
+            reject_code = MCA_RSP_SUCCESS;
+            send_rsp = true;
+            /* clear the pending status */
+            p_ccb->status = MCA_CCB_STAT_NORM;
+            if (p_ccb->p_tx_req && ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx))!= NULL))
+            {
+                mca_dcb_dealloc(p_dcb, NULL);
+                osi_free_and_reset((void **)&p_ccb->p_tx_req);
+            }
+        }
+        else
+            reject_code = MCA_RSP_BAD_OP;
+    }
+    else if (p_ccb->p_rx_msg)
+    {
+        MCA_TRACE_DEBUG ("still handling prev req");
+        /* still holding previous message, reject this new one ?? */
+
+    }
+    else if (p_ccb->p_tx_req)
+    {
+        MCA_TRACE_DEBUG ("still waiting for a response ctrl_vpsm:0x%x", p_ccb->ctrl_vpsm);
+        /* sent a request; waiting for response */
+        if (p_ccb->ctrl_vpsm == 0)
+        {
+            MCA_TRACE_DEBUG ("local is ACP. accept the cmd from INT");
+            /* local is acceptor, need to handle the request */
+            check_req = true;
+            reject_code = MCA_RSP_SUCCESS;
+            /* drop the previous request */
+            if ((p_ccb->p_tx_req->op_code == MCA_OP_MDL_CREATE_REQ) &&
+                ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL))
+            {
+                mca_dcb_dealloc(p_dcb, NULL);
+            }
+            osi_free_and_reset((void **)&p_ccb->p_tx_req);
+            mca_stop_timer(p_ccb);
+        }
+        else
+        {
+            /*  local is initiator, ignore the req */
+            osi_free(p_pkt);
+            return;
+        }
+    }
+    else if (p_pkt->layer_specific != MCA_RSP_SUCCESS)
+    {
+
+        reject_code = (uint8_t)p_pkt->layer_specific;
+        if (((evt_data.hdr.op_code >= MCA_NUM_STANDARD_OPCODE) &&
+            (evt_data.hdr.op_code < MCA_FIRST_SYNC_OP)) ||
+            (evt_data.hdr.op_code > MCA_LAST_SYNC_OP))
+        {
+            /* invalid op code */
+            reject_opcode = MCA_OP_ERROR_RSP;
+            evt_data.hdr.mdl_id = 0;
+        }
+    }
+    else
+    {
+        check_req = true;
+        reject_code = MCA_RSP_SUCCESS;
+    }
+
+    if (check_req)
+    {
+        if (reject_code == MCA_RSP_SUCCESS)
+        {
+            reject_code = MCA_RSP_BAD_MDL;
+            if (MCA_IS_VALID_MDL_ID(evt_data.hdr.mdl_id) ||
+                ((evt_data.hdr.mdl_id == MCA_ALL_MDL_ID) && (evt_data.hdr.op_code == MCA_OP_MDL_DELETE_REQ)))
+            {
+                reject_code = MCA_RSP_SUCCESS;
+                /* mdl_id is valid according to the spec */
+                switch (evt_data.hdr.op_code)
+                {
+                case MCA_OP_MDL_CREATE_REQ:
+                    evt_data.create_ind.dep_id = *p++;
+                    evt_data.create_ind.cfg = *p++;
+                    p_rx_msg->mdep_id = evt_data.create_ind.dep_id;
+                    if (!mca_is_valid_dep_id(p_ccb->p_rcb, p_rx_msg->mdep_id))
+                    {
+                        MCA_TRACE_ERROR ("not a valid local mdep id");
+                        reject_code = MCA_RSP_BAD_MDEP;
+                    }
+                    else if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id))
+                    {
+                        MCA_TRACE_DEBUG ("the mdl_id is currently used in the CL(create)");
+                        mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id);
+                    }
+                    else
+                    {
+                        /* check if this dep still have MDL available */
+                        if (mca_dep_free_mdl(p_ccb, evt_data.create_ind.dep_id) == 0)
+                        {
+                            MCA_TRACE_ERROR ("the mdep is currently using max_mdl");
+                            reject_code = MCA_RSP_MDEP_BUSY;
+                        }
+                    }
+                    break;
+
+                case MCA_OP_MDL_RECONNECT_REQ:
+                    if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id))
+                    {
+                        MCA_TRACE_ERROR ("the mdl_id is currently used in the CL(reconn)");
+                        reject_code = MCA_RSP_MDL_BUSY;
+                    }
+                    break;
+
+                case MCA_OP_MDL_ABORT_REQ:
+                    reject_code = MCA_RSP_BAD_OP;
+                    break;
+
+                case MCA_OP_MDL_DELETE_REQ:
+                    /* delete the associated mdl */
+                    mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id);
+                    send_rsp = true;
+                    break;
+                }
+            }
+        }
+    }
+
+    if (((reject_code != MCA_RSP_SUCCESS) && (evt_data.hdr.op_code != MCA_OP_SYNC_INFO_IND))
+        || send_rsp) {
+        BT_HDR *p_buf = (BT_HDR *)osi_malloc(MCA_CTRL_MTU + sizeof(BT_HDR));
+        p_buf->offset = L2CAP_MIN_OFFSET;
+        p = p_start = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+        *p++ = reject_opcode;
+        *p++ = reject_code;
+        UINT16_TO_BE_STREAM(p, evt_data.hdr.mdl_id);
+        /*
+          if (((*p_start) == MCA_OP_MDL_CREATE_RSP) && (reject_code == MCA_RSP_SUCCESS))
+          {
+          *p++ = evt_data.create_ind.cfg;
+          }
+        */
+
+        p_buf->len = p - p_start;
+        L2CA_DataWrite (p_ccb->lcid, p_buf);
+    }
+
+    if (reject_code == MCA_RSP_SUCCESS)
+    {
+        /* use the received GKI buffer to store information to double check response API */
+        p_rx_msg->op_code = evt_data.hdr.op_code;
+        p_rx_msg->mdl_id = evt_data.hdr.mdl_id;
+        p_ccb->p_rx_msg = p_rx_msg;
+        if (send_rsp)
+        {
+            osi_free(p_pkt);
+            p_ccb->p_rx_msg = NULL;
+        }
+        mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data);
+    }
+    else
+        osi_free(p_pkt);
+}
+
+/*******************************************************************************
+**
+** Function         mca_ccb_hdl_rsp
+**
+** Description      This function is called when a MCAP response is received from
+**                  the peer.  It calls the application callback function with
+**                  the results.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_ccb_hdl_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
+{
+    BT_HDR  *p_pkt = &p_data->hdr;
+    uint8_t *p;
+    tMCA_CTRL   evt_data;
+    bool        chk_mdl = false;
+    tMCA_DCB    *p_dcb;
+    tMCA_RESULT result = MCA_BAD_HANDLE;
+    tMCA_TC_TBL *p_tbl;
+
+    if (p_ccb->p_tx_req)
+    {
+        /* verify that the received response matches the sent request */
+        p = (uint8_t *)(p_pkt + 1) + p_pkt->offset;
+        evt_data.hdr.op_code = *p++;
+        if ((evt_data.hdr.op_code == 0) ||
+            ((p_ccb->p_tx_req->op_code + 1) == evt_data.hdr.op_code))
+        {
+            evt_data.rsp.rsp_code = *p++;
+            mca_stop_timer(p_ccb);
+            BE_STREAM_TO_UINT16 (evt_data.hdr.mdl_id, p);
+            if (evt_data.hdr.op_code == MCA_OP_MDL_CREATE_RSP)
+            {
+                evt_data.create_cfm.cfg = *p++;
+                chk_mdl = true;
+            }
+            else if (evt_data.hdr.op_code == MCA_OP_MDL_RECONNECT_RSP)
+                    chk_mdl = true;
+
+            if (chk_mdl)
+            {
+                p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx);
+                if (evt_data.rsp.rsp_code == MCA_RSP_SUCCESS)
+                {
+                    if (evt_data.hdr.mdl_id != p_dcb->mdl_id)
+                    {
+                        MCA_TRACE_ERROR ("peer's mdl_id=%d != our mdl_id=%d", evt_data.hdr.mdl_id, p_dcb->mdl_id);
+                        /* change the response code to be an error */
+                        if (evt_data.rsp.rsp_code == MCA_RSP_SUCCESS)
+                        {
+                            evt_data.rsp.rsp_code = MCA_RSP_BAD_MDL;
+                            /* send Abort */
+                            p_ccb->status = MCA_CCB_STAT_PENDING;
+                            MCA_Abort(mca_ccb_to_hdl(p_ccb));
+                        }
+                    }
+                    else if (p_dcb->p_chnl_cfg)
+                    {
+                        /* the data channel configuration is known. Proceed with data channel initiation */
+                        BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask,
+                            p_ccb->data_vpsm, BTM_SEC_PROTO_MCA, p_ccb->p_tx_req->dcb_idx);
+                        p_dcb->lcid = mca_l2c_open_req(p_ccb->peer_addr, p_ccb->data_vpsm, p_dcb->p_chnl_cfg);
+                        if (p_dcb->lcid)
+                        {
+                            p_tbl = mca_tc_tbl_dalloc(p_dcb);
+                            if (p_tbl)
+                            {
+                                p_tbl->state = MCA_TC_ST_CONN;
+                                p_ccb->status = MCA_CCB_STAT_PENDING;
+                                result = MCA_SUCCESS;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        /* mark this MCL as pending and wait for MCA_DataChnlCfg */
+                        p_ccb->status = MCA_CCB_STAT_PENDING;
+                        result = MCA_SUCCESS;
+                    }
+                }
+
+                if (result != MCA_SUCCESS && p_dcb)
+                {
+                    mca_dcb_dealloc(p_dcb, NULL);
+                }
+            } /* end of chk_mdl */
+
+            if (p_ccb->status != MCA_CCB_STAT_PENDING)
+                osi_free_and_reset((void **)&p_ccb->p_tx_req);
+            mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data);
+        }
+        /* else a bad response is received */
+    }
+    else
+    {
+        /* not expecting any response. drop it */
+        MCA_TRACE_WARNING ("dropping received rsp (not expecting a response)");
+    }
+    osi_free(p_data);
+}
+
+/*******************************************************************************
+**
+** Function         mca_ccb_ll_open
+**
+** Description      This function is called to report MCA_CONNECT_IND_EVT event.
+**                  It also clears the congestion flag (ccb.cong).
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_ccb_ll_open (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
+{
+    tMCA_CTRL    evt_data;
+    p_ccb->cong  = false;
+    evt_data.connect_ind.mtu = p_data->open.peer_mtu;
+    memcpy (evt_data.connect_ind.bd_addr, p_ccb->peer_addr, BD_ADDR_LEN);
+    mca_ccb_report_event (p_ccb, MCA_CONNECT_IND_EVT, &evt_data);
+}
+
+/*******************************************************************************
+**
+** Function         mca_ccb_dl_open
+**
+** Description      This function is called when data channel is open.
+**                  It clears p_tx_req to allow other message exchage on this CL.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_ccb_dl_open (tMCA_CCB *p_ccb,
+                      UNUSED_ATTR tMCA_CCB_EVT *p_data)
+{
+    osi_free_and_reset((void **)&p_ccb->p_tx_req);
+    osi_free_and_reset((void **)&p_ccb->p_rx_msg);
+    p_ccb->status = MCA_CCB_STAT_NORM;
+}
diff --git a/bt/stack/mcap/mca_csm.cc b/bt/stack/mcap/mca_csm.cc
new file mode 100644
index 0000000..c95b8e8
--- /dev/null
+++ b/bt/stack/mcap/mca_csm.cc
@@ -0,0 +1,383 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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 is the implementation file for the MCAP Control channel state
+ *  machine.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mca_int.h"
+#include  "btu.h"
+
+/*****************************************************************************
+** data channel state machine constants and types
+*****************************************************************************/
+enum
+{
+    MCA_CCB_FREE_MSG,
+    MCA_CCB_SND_REQ,
+    MCA_CCB_SND_RSP,
+    MCA_CCB_DO_DISCONN,
+    MCA_CCB_CONG,
+    MCA_CCB_HDL_REQ,
+    MCA_CCB_HDL_RSP,
+    MCA_CCB_LL_OPEN,
+    MCA_CCB_DL_OPEN,
+    MCA_CCB_DEALLOC,
+    MCA_CCB_RSP_TOUT,
+    MCA_CCB_NUM_ACTIONS
+};
+#define MCA_CCB_IGNORE     MCA_CCB_NUM_ACTIONS
+
+/* action function list */
+const tMCA_CCB_ACTION mca_ccb_action[] = {
+    mca_ccb_free_msg,
+    mca_ccb_snd_req,
+    mca_ccb_snd_rsp,
+    mca_ccb_do_disconn,
+    mca_ccb_cong,
+    mca_ccb_hdl_req,
+    mca_ccb_hdl_rsp,
+    mca_ccb_ll_open,
+    mca_ccb_dl_open,
+    mca_ccb_dealloc,
+    mca_ccb_rsp_tout,
+};
+
+/* state table information */
+#define MCA_CCB_ACTIONS            1       /* number of actions */
+#define MCA_CCB_ACT_COL            0       /* position of action function */
+#define MCA_CCB_NEXT_STATE         1       /* position of next state */
+#define MCA_CCB_NUM_COLS           2       /* number of columns in state tables */
+
+/* state table for opening state */
+const uint8_t mca_ccb_st_opening[][MCA_CCB_NUM_COLS] = {
+/* Event                            Action              Next State */
+/* MCA_CCB_API_CONNECT_EVT    */   {MCA_CCB_IGNORE,     MCA_CCB_OPENING_ST},
+/* MCA_CCB_API_DISCONNECT_EVT */   {MCA_CCB_DO_DISCONN, MCA_CCB_CLOSING_ST},
+/* MCA_CCB_API_REQ_EVT        */   {MCA_CCB_FREE_MSG,   MCA_CCB_OPENING_ST},
+/* MCA_CCB_API_RSP_EVT        */   {MCA_CCB_IGNORE,     MCA_CCB_OPENING_ST},
+/* MCA_CCB_MSG_REQ_EVT        */   {MCA_CCB_FREE_MSG,   MCA_CCB_OPENING_ST},
+/* MCA_CCB_MSG_RSP_EVT        */   {MCA_CCB_FREE_MSG,   MCA_CCB_OPENING_ST},
+/* MCA_CCB_DL_OPEN_EVT        */   {MCA_CCB_IGNORE,     MCA_CCB_OPENING_ST},
+/* MCA_CCB_LL_OPEN_EVT        */   {MCA_CCB_LL_OPEN,    MCA_CCB_OPEN_ST},
+/* MCA_CCB_LL_CLOSE_EVT       */   {MCA_CCB_DEALLOC,    MCA_CCB_NULL_ST},
+/* MCA_CCB_LL_CONG_EVT        */   {MCA_CCB_CONG,       MCA_CCB_OPENING_ST},
+/* MCA_CCB_RSP_TOUT_EVT       */   {MCA_CCB_IGNORE,     MCA_CCB_OPENING_ST}
+};
+
+/* state table for open state */
+const uint8_t mca_ccb_st_open[][MCA_CCB_NUM_COLS] = {
+/* Event                            Action              Next State */
+/* MCA_CCB_API_CONNECT_EVT    */   {MCA_CCB_IGNORE,     MCA_CCB_OPEN_ST},
+/* MCA_CCB_API_DISCONNECT_EVT */   {MCA_CCB_DO_DISCONN, MCA_CCB_CLOSING_ST},
+/* MCA_CCB_API_REQ_EVT        */   {MCA_CCB_SND_REQ,    MCA_CCB_OPEN_ST},
+/* MCA_CCB_API_RSP_EVT        */   {MCA_CCB_SND_RSP,    MCA_CCB_OPEN_ST},
+/* MCA_CCB_MSG_REQ_EVT        */   {MCA_CCB_HDL_REQ,    MCA_CCB_OPEN_ST},
+/* MCA_CCB_MSG_RSP_EVT        */   {MCA_CCB_HDL_RSP,    MCA_CCB_OPEN_ST},
+/* MCA_CCB_DL_OPEN_EVT        */   {MCA_CCB_DL_OPEN,    MCA_CCB_OPEN_ST},
+/* MCA_CCB_LL_OPEN_EVT        */   {MCA_CCB_IGNORE,     MCA_CCB_OPEN_ST},
+/* MCA_CCB_LL_CLOSE_EVT       */   {MCA_CCB_DEALLOC,    MCA_CCB_NULL_ST},
+/* MCA_CCB_LL_CONG_EVT        */   {MCA_CCB_CONG,       MCA_CCB_OPEN_ST},
+/* MCA_CCB_RSP_TOUT_EVT       */   {MCA_CCB_RSP_TOUT,   MCA_CCB_OPEN_ST}
+};
+
+/* state table for closing state */
+const uint8_t mca_ccb_st_closing[][MCA_CCB_NUM_COLS] = {
+/* Event                            Action              Next State */
+/* MCA_CCB_API_CONNECT_EVT    */   {MCA_CCB_IGNORE,     MCA_CCB_CLOSING_ST},
+/* MCA_CCB_API_DISCONNECT_EVT */   {MCA_CCB_IGNORE,     MCA_CCB_CLOSING_ST},
+/* MCA_CCB_API_REQ_EVT        */   {MCA_CCB_FREE_MSG,   MCA_CCB_CLOSING_ST},
+/* MCA_CCB_API_RSP_EVT        */   {MCA_CCB_IGNORE,     MCA_CCB_CLOSING_ST},
+/* MCA_CCB_MSG_REQ_EVT        */   {MCA_CCB_FREE_MSG,   MCA_CCB_CLOSING_ST},
+/* MCA_CCB_MSG_RSP_EVT        */   {MCA_CCB_FREE_MSG,   MCA_CCB_CLOSING_ST},
+/* MCA_CCB_DL_OPEN_EVT        */   {MCA_CCB_IGNORE,     MCA_CCB_CLOSING_ST},
+/* MCA_CCB_LL_OPEN_EVT        */   {MCA_CCB_IGNORE,     MCA_CCB_CLOSING_ST},
+/* MCA_CCB_LL_CLOSE_EVT       */   {MCA_CCB_DEALLOC,    MCA_CCB_NULL_ST},
+/* MCA_CCB_LL_CONG_EVT        */   {MCA_CCB_IGNORE,     MCA_CCB_CLOSING_ST},
+/* MCA_CCB_RSP_TOUT_EVT       */   {MCA_CCB_IGNORE,     MCA_CCB_CLOSING_ST}
+};
+
+/* type for state table */
+typedef const uint8_t (*tMCA_CCB_ST_TBL)[MCA_CCB_NUM_COLS];
+
+/* state table */
+const tMCA_CCB_ST_TBL mca_ccb_st_tbl[] = {
+    mca_ccb_st_opening,
+    mca_ccb_st_open,
+    mca_ccb_st_closing
+};
+
+#if (BT_TRACE_VERBOSE == TRUE)
+/* verbose event strings for trace */
+static const char * const mca_ccb_evt_str[] = {
+    "API_CONNECT_EVT",
+    "API_DISCONNECT_EVT",
+    "API_REQ_EVT",
+    "API_RSP_EVT",
+    "MSG_REQ_EVT",
+    "MSG_RSP_EVT",
+    "DL_OPEN_EVT",
+    "LL_OPEN_EVT",
+    "LL_CLOSE_EVT",
+    "LL_CONG_EVT",
+    "RSP_TOUT_EVT"
+};
+/* verbose state strings for trace */
+static const char * const mca_ccb_st_str[] = {
+    "NULL_ST",
+    "OPENING_ST",
+    "OPEN_ST",
+    "CLOSING_ST"
+};
+#endif
+
+/*******************************************************************************
+**
+** Function         mca_stop_timer
+**
+** Description      This function is stop a MCAP timer
+**
+**                  This function is for use internal to MCAP only.
+**
+** Returns          void
+**
+*******************************************************************************/
+void mca_stop_timer(tMCA_CCB *p_ccb)
+{
+    alarm_cancel(p_ccb->mca_ccb_timer);
+}
+
+/*******************************************************************************
+**
+** Function         mca_ccb_event
+**
+** Description      This function is the CCB state machine main function.
+**                  It uses the state and action function tables to execute
+**                  action functions.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_ccb_event(tMCA_CCB *p_ccb, uint8_t event, tMCA_CCB_EVT *p_data)
+{
+    tMCA_CCB_ST_TBL    state_table;
+    uint8_t            action;
+
+#if (BT_TRACE_VERBOSE == TRUE)
+    MCA_TRACE_EVENT("CCB ccb=%d event=%s state=%s", mca_ccb_to_hdl(p_ccb), mca_ccb_evt_str[event], mca_ccb_st_str[p_ccb->state]);
+#else
+    MCA_TRACE_EVENT("CCB ccb=%d event=%d state=%d", mca_ccb_to_hdl(p_ccb), event, p_ccb->state);
+#endif
+
+    /* look up the state table for the current state */
+    state_table = mca_ccb_st_tbl[p_ccb->state - 1];
+
+    /* set next state */
+    p_ccb->state = state_table[event][MCA_CCB_NEXT_STATE];
+
+    /* execute action functions */
+    if ((action = state_table[event][MCA_CCB_ACT_COL]) != MCA_CCB_IGNORE)
+    {
+        (*mca_ccb_action[action])(p_ccb, p_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         mca_ccb_by_bd
+**
+** Description      This function looks up the CCB based on the BD address.
+**                  It returns a pointer to the CCB.
+**                  If no CCB is found it returns NULL.
+**
+** Returns          void.
+**
+*******************************************************************************/
+tMCA_CCB *mca_ccb_by_bd(tMCA_HANDLE handle, BD_ADDR bd_addr)
+{
+    tMCA_CCB *p_ccb = NULL;
+    tMCA_RCB *p_rcb = mca_rcb_by_handle(handle);
+    tMCA_CCB *p_ccb_tmp;
+    int       i;
+
+    if (p_rcb)
+    {
+        i = handle-1;
+        p_ccb_tmp = &mca_cb.ccb[i*MCA_NUM_LINKS];
+        for (i=0; i<MCA_NUM_LINKS; i++, p_ccb_tmp++)
+        {
+            if (p_ccb_tmp->state != MCA_CCB_NULL_ST && memcmp(p_ccb_tmp->peer_addr, bd_addr, BD_ADDR_LEN) == 0)
+            {
+                p_ccb = p_ccb_tmp;
+                break;
+            }
+        }
+    }
+    return p_ccb;
+}
+
+/*******************************************************************************
+**
+** Function         mca_ccb_alloc
+**
+** Description      This function allocates a CCB and copies the BD address to
+**                  the CCB.  It returns a pointer to the CCB.  If no CCB can
+**                  be allocated it returns NULL.
+**
+** Returns          void.
+**
+*******************************************************************************/
+tMCA_CCB *mca_ccb_alloc(tMCA_HANDLE handle, BD_ADDR bd_addr)
+{
+    tMCA_CCB *p_ccb = NULL;
+    tMCA_RCB *p_rcb = mca_rcb_by_handle(handle);
+    tMCA_CCB *p_ccb_tmp;
+    int       i;
+
+    MCA_TRACE_DEBUG("mca_ccb_alloc handle:0x%x", handle);
+    if (p_rcb)
+    {
+        i = handle-1;
+        p_ccb_tmp = &mca_cb.ccb[i*MCA_NUM_LINKS];
+        for (i=0; i<MCA_NUM_LINKS; i++, p_ccb_tmp++)
+        {
+            if (p_ccb_tmp->state == MCA_CCB_NULL_ST)
+            {
+                p_ccb_tmp->p_rcb = p_rcb;
+                p_ccb_tmp->mca_ccb_timer = alarm_new("mca.mca_ccb_timer");
+                p_ccb_tmp->state = MCA_CCB_OPENING_ST;
+                p_ccb_tmp->cong  = true;
+                memcpy(p_ccb_tmp->peer_addr, bd_addr, BD_ADDR_LEN);
+                p_ccb = p_ccb_tmp;
+                break;
+            }
+        }
+    }
+    return p_ccb;
+}
+
+
+/*******************************************************************************
+**
+** Function         mca_ccb_dealloc
+**
+** Description      This function deallocates a CCB.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_ccb_dealloc(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
+{
+    tMCA_CTRL   evt_data;
+
+    MCA_TRACE_DEBUG("mca_ccb_dealloc ctrl_vpsm:0x%x", p_ccb->ctrl_vpsm);
+    mca_dcb_close_by_mdl_id (p_ccb, MCA_ALL_MDL_ID);
+    if (p_ccb->ctrl_vpsm)
+    {
+        L2CA_Deregister (p_ccb->ctrl_vpsm);
+    }
+    if (p_ccb->data_vpsm)
+    {
+        L2CA_Deregister (p_ccb->data_vpsm);
+    }
+    osi_free_and_reset((void **)&p_ccb->p_rx_msg);
+    osi_free_and_reset((void **)&p_ccb->p_tx_req);
+    mca_stop_timer(p_ccb);
+
+    if (p_data)
+    {
+        /* non-NULL -> an action function -> report disconnect event */
+        memcpy (evt_data.disconnect_ind.bd_addr, p_ccb->peer_addr, BD_ADDR_LEN);
+        evt_data.disconnect_ind.reason = p_data->close.reason;
+        mca_ccb_report_event(p_ccb, MCA_DISCONNECT_IND_EVT, &evt_data);
+    }
+    mca_free_tc_tbl_by_lcid (p_ccb->lcid);
+    alarm_free(p_ccb->mca_ccb_timer);
+    memset(p_ccb, 0, sizeof(tMCA_CCB));
+}
+
+/*******************************************************************************
+**
+** Function         mca_ccb_to_hdl
+**
+** Description      This function converts a pointer to a CCB to a tMCA_CL
+**                  and returns the value.
+**
+** Returns          void.
+**
+*******************************************************************************/
+tMCA_CL mca_ccb_to_hdl(tMCA_CCB *p_ccb)
+{
+    return (uint8_t) (p_ccb - mca_cb.ccb + 1);
+}
+
+/*******************************************************************************
+**
+** Function         mca_ccb_by_hdl
+**
+** Description      This function converts an index value to a CCB.  It returns
+**                  a pointer to the CCB.  If no valid CCB matches the index it
+**                  returns NULL.
+**
+** Returns          void.
+**
+*******************************************************************************/
+tMCA_CCB *mca_ccb_by_hdl(tMCA_CL mcl)
+{
+    tMCA_CCB * p_ccb = NULL;
+    if (mcl && mcl <= MCA_NUM_CCBS && mca_cb.ccb[mcl-1].state)
+        p_ccb = &mca_cb.ccb[mcl-1];
+    return p_ccb;
+}
+
+
+/*******************************************************************************
+**
+** Function         mca_ccb_uses_mdl_id
+**
+** Description      This function checkes if a given mdl_id is in use.
+**
+** Returns          true, if the given mdl_id is currently used in the MCL.
+**
+*******************************************************************************/
+bool    mca_ccb_uses_mdl_id(tMCA_CCB *p_ccb, uint16_t mdl_id)
+{
+    bool    uses = false;
+    tMCA_DCB *p_dcb;
+    int       i;
+
+    i = mca_ccb_to_hdl(p_ccb)-1;
+    p_dcb = &mca_cb.dcb[i*MCA_NUM_MDLS];
+    for (i=0; i<MCA_NUM_MDLS; i++, p_dcb++)
+    {
+        if (p_dcb->state != MCA_DCB_NULL_ST && p_dcb->mdl_id == mdl_id)
+        {
+            uses = true;
+            break;
+        }
+    }
+
+    return uses;
+}
diff --git a/bt/stack/mcap/mca_dact.cc b/bt/stack/mcap/mca_dact.cc
new file mode 100644
index 0000000..daafb96
--- /dev/null
+++ b/bt/stack/mcap/mca_dact.cc
@@ -0,0 +1,168 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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 is the implementation file for the MCAP Data Channel Action
+ *  Functions.
+ *
+ ******************************************************************************/
+
+#include <stddef.h>
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "bt_common.h"
+#include "mca_api.h"
+#include "mca_int.h"
+#include "osi/include/osi.h"
+
+/*******************************************************************************
+**
+** Function         mca_dcb_report_cong
+**
+** Description      This function is called to report the congestion flag.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_dcb_report_cong (tMCA_DCB *p_dcb)
+{
+    tMCA_CTRL   evt_data;
+
+    evt_data.cong_chg.cong   = p_dcb->cong;
+    evt_data.cong_chg.mdl    = mca_dcb_to_hdl(p_dcb);
+    evt_data.cong_chg.mdl_id = p_dcb->mdl_id;
+    mca_ccb_report_event (p_dcb->p_ccb, MCA_CONG_CHG_EVT, &evt_data);
+}
+
+/*******************************************************************************
+**
+** Function         mca_dcb_tc_open
+**
+** Description      This function is called to report MCA_OPEN_IND_EVT or
+**                  MCA_OPEN_CFM_EVT event.
+**                  It also clears the congestion flag (dcb.cong).
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_dcb_tc_open (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data)
+{
+    tMCA_CTRL   evt_data;
+    tMCA_CCB    *p_ccb = p_dcb->p_ccb;
+    uint8_t     event = MCA_OPEN_IND_EVT;
+
+    if (p_data->open.param == MCA_INT)
+        event = MCA_OPEN_CFM_EVT;
+    p_dcb->cong  = false;
+    evt_data.open_cfm.mtu       = p_data->open.peer_mtu;
+    evt_data.open_cfm.mdl_id    = p_dcb->mdl_id;
+    evt_data.open_cfm.mdl       = mca_dcb_to_hdl(p_dcb);
+    mca_ccb_event (p_ccb, MCA_CCB_DL_OPEN_EVT, NULL);
+    mca_ccb_report_event (p_ccb, event, &evt_data);
+}
+
+/*******************************************************************************
+**
+** Function         mca_dcb_cong
+**
+** Description      This function sets the congestion state for the DCB.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_dcb_cong (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data)
+{
+    p_dcb->cong  = p_data->llcong;
+    mca_dcb_report_cong(p_dcb);
+}
+
+/*******************************************************************************
+**
+** Function         mca_dcb_free_data
+**
+** Description      This function frees the received message.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_dcb_free_data(UNUSED_ATTR tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data)
+{
+    osi_free(p_data);
+}
+
+/*******************************************************************************
+**
+** Function         mca_dcb_do_disconn
+**
+** Description      This function closes a data channel.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_dcb_do_disconn (tMCA_DCB *p_dcb,
+                         UNUSED_ATTR tMCA_DCB_EVT *p_data)
+{
+    tMCA_CLOSE  close;
+
+    if ((p_dcb->lcid == 0) || (L2CA_DisconnectReq(p_dcb->lcid) == false))
+    {
+        close.param  = MCA_INT;
+        close.reason = L2CAP_DISC_OK;
+        close.lcid   = 0;
+        mca_dcb_event(p_dcb, MCA_DCB_TC_CLOSE_EVT, (tMCA_DCB_EVT *) &close);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         mca_dcb_snd_data
+**
+** Description      This function sends the data from application to the peer device.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_dcb_snd_data (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data)
+{
+    uint8_t status;
+
+    /* do not need to check cong, because API already checked the status */
+    status = L2CA_DataWrite (p_dcb->lcid, p_data->p_pkt);
+    if (status == L2CAP_DW_CONGESTED)
+    {
+        p_dcb->cong = true;
+        mca_dcb_report_cong(p_dcb);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         mca_dcb_hdl_data
+**
+** Description      This function reports the received data through the data
+**                  callback function.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_dcb_hdl_data (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data)
+{
+    (*p_dcb->p_cs->p_data_cback) (mca_dcb_to_hdl(p_dcb), (BT_HDR *)p_data);
+}
+
diff --git a/bt/stack/mcap/mca_dsm.cc b/bt/stack/mcap/mca_dsm.cc
new file mode 100644
index 0000000..cc2aaa5
--- /dev/null
+++ b/bt/stack/mcap/mca_dsm.cc
@@ -0,0 +1,346 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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 is the implementation file for the MCAP Data chahnel state machine.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mca_int.h"
+
+/*****************************************************************************
+** data channel state machine constants and types
+*****************************************************************************/
+enum
+{
+    MCA_DCB_TC_OPEN,
+    MCA_DCB_CONG,
+    MCA_DCB_FREE_DATA,
+    MCA_DCB_DEALLOC,
+    MCA_DCB_DO_DISCONN,
+    MCA_DCB_SND_DATA,
+    MCA_DCB_HDL_DATA,
+    MCA_DCB_NUM_ACTIONS
+};
+#define MCA_DCB_IGNORE     MCA_DCB_NUM_ACTIONS
+
+/* action function list */
+const tMCA_DCB_ACTION mca_dcb_action[] = {
+    mca_dcb_tc_open,
+    mca_dcb_cong,
+    mca_dcb_free_data,
+    mca_dcb_dealloc,
+    mca_dcb_do_disconn,
+    mca_dcb_snd_data,
+    mca_dcb_hdl_data
+};
+
+/* state table information */
+#define MCA_DCB_ACTIONS            1       /* number of actions */
+#define MCA_DCB_ACT_COL            0       /* position of action function */
+#define MCA_DCB_NEXT_STATE         1       /* position of next state */
+#define MCA_DCB_NUM_COLS           2       /* number of columns in state tables */
+
+/* state table for opening state */
+const uint8_t mca_dcb_st_opening[][MCA_DCB_NUM_COLS] = {
+/* Event                            Action              Next State */
+/* MCA_DCB_API_CLOSE_EVT    */   {MCA_DCB_DO_DISCONN,   MCA_DCB_CLOSING_ST},
+/* MCA_DCB_API_WRITE_EVT    */   {MCA_DCB_IGNORE,       MCA_DCB_OPENING_ST},
+/* MCA_DCB_TC_OPEN_EVT      */   {MCA_DCB_TC_OPEN,      MCA_DCB_OPEN_ST},
+/* MCA_DCB_TC_CLOSE_EVT     */   {MCA_DCB_DEALLOC,      MCA_DCB_NULL_ST},
+/* MCA_DCB_TC_CONG_EVT      */   {MCA_DCB_CONG,         MCA_DCB_OPENING_ST},
+/* MCA_DCB_TC_DATA_EVT      */   {MCA_DCB_FREE_DATA,    MCA_DCB_OPENING_ST}
+};
+
+/* state table for open state */
+const uint8_t mca_dcb_st_open[][MCA_DCB_NUM_COLS] = {
+/* Event                            Action              Next State */
+/* MCA_DCB_API_CLOSE_EVT    */   {MCA_DCB_DO_DISCONN,   MCA_DCB_CLOSING_ST},
+/* MCA_DCB_API_WRITE_EVT    */   {MCA_DCB_SND_DATA,     MCA_DCB_OPEN_ST},
+/* MCA_DCB_TC_OPEN_EVT      */   {MCA_DCB_IGNORE,       MCA_DCB_OPEN_ST},
+/* MCA_DCB_TC_CLOSE_EVT     */   {MCA_DCB_DEALLOC,      MCA_DCB_NULL_ST},
+/* MCA_DCB_TC_CONG_EVT      */   {MCA_DCB_CONG,         MCA_DCB_OPEN_ST},
+/* MCA_DCB_TC_DATA_EVT      */   {MCA_DCB_HDL_DATA,     MCA_DCB_OPEN_ST}
+};
+
+/* state table for closing state */
+const uint8_t mca_dcb_st_closing[][MCA_DCB_NUM_COLS] = {
+/* Event                            Action              Next State */
+/* MCA_DCB_API_CLOSE_EVT    */   {MCA_DCB_IGNORE,       MCA_DCB_CLOSING_ST},
+/* MCA_DCB_API_WRITE_EVT    */   {MCA_DCB_IGNORE,       MCA_DCB_CLOSING_ST},
+/* MCA_DCB_TC_OPEN_EVT      */   {MCA_DCB_TC_OPEN,      MCA_DCB_OPEN_ST},
+/* MCA_DCB_TC_CLOSE_EVT     */   {MCA_DCB_DEALLOC,      MCA_DCB_NULL_ST},
+/* MCA_DCB_TC_CONG_EVT      */   {MCA_DCB_IGNORE,       MCA_DCB_CLOSING_ST},
+/* MCA_DCB_TC_DATA_EVT      */   {MCA_DCB_FREE_DATA,    MCA_DCB_CLOSING_ST}
+};
+
+/* type for state table */
+typedef const uint8_t (*tMCA_DCB_ST_TBL)[MCA_DCB_NUM_COLS];
+
+/* state table */
+const tMCA_DCB_ST_TBL mca_dcb_st_tbl[] = {
+    mca_dcb_st_opening,
+    mca_dcb_st_open,
+    mca_dcb_st_closing
+};
+
+#if (BT_TRACE_VERBOSE == TRUE)
+/* verbose event strings for trace */
+const char * const mca_dcb_evt_str[] = {
+    "API_CLOSE_EVT",
+    "API_WRITE_EVT",
+    "TC_OPEN_EVT",
+    "TC_CLOSE_EVT",
+    "TC_CONG_EVT",
+    "TC_DATA_EVT"
+};
+/* verbose state strings for trace */
+const char * const mca_dcb_st_str[] = {
+    "NULL_ST",
+    "OPENING_ST",
+    "OPEN_ST",
+    "CLOSING_ST"
+};
+#endif
+
+/*******************************************************************************
+**
+** Function         mca_dcb_event
+**
+** Description      This function is the DCB state machine main function.
+**                  It uses the state and action function tables to execute
+**                  action functions.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_dcb_event(tMCA_DCB *p_dcb, uint8_t event, tMCA_DCB_EVT *p_data)
+{
+    tMCA_DCB_ST_TBL    state_table;
+    uint8_t            action;
+
+    if (p_dcb == NULL)
+        return;
+#if (BT_TRACE_VERBOSE == TRUE)
+    MCA_TRACE_EVENT("DCB dcb=%d event=%s state=%s", mca_dcb_to_hdl(p_dcb), mca_dcb_evt_str[event], mca_dcb_st_str[p_dcb->state]);
+#else
+    MCA_TRACE_EVENT("DCB dcb=%d event=%d state=%d", mca_dcb_to_hdl(p_dcb), event, p_dcb->state);
+#endif
+
+    /* look up the state table for the current state */
+    state_table = mca_dcb_st_tbl[p_dcb->state - 1];
+
+    /* set next state */
+    p_dcb->state = state_table[event][MCA_DCB_NEXT_STATE];
+
+    /* execute action functions */
+    if ((action = state_table[event][MCA_DCB_ACT_COL]) != MCA_DCB_IGNORE)
+    {
+        (*mca_dcb_action[action])(p_dcb, p_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         mca_dcb_alloc
+**
+** Description      This function is called to allocate an DCB.
+**                  It initializes the DCB with the data passed to the function.
+**
+** Returns          tMCA_DCB *
+**
+*******************************************************************************/
+tMCA_DCB *mca_dcb_alloc(tMCA_CCB*p_ccb, tMCA_DEP dep)
+{
+    tMCA_DCB *p_dcb = NULL, *p_dcb_tmp;
+    tMCA_RCB *p_rcb = p_ccb->p_rcb;
+    tMCA_CS  *p_cs;
+    int       i, max;
+
+    if (dep < MCA_NUM_DEPS)
+    {
+        p_cs = &p_rcb->dep[dep];
+        i = mca_ccb_to_hdl(p_ccb)-1;
+        p_dcb_tmp = &mca_cb.dcb[i*MCA_NUM_MDLS];
+        /* make sure p_cs->max_mdl is smaller than MCA_NUM_MDLS at MCA_CreateDep */
+        max = p_cs->max_mdl;
+        for (i=0; i<max; i++, p_dcb_tmp++)
+        {
+            if (p_dcb_tmp->state == MCA_DCB_NULL_ST)
+            {
+                p_dcb_tmp->p_ccb = p_ccb;
+                p_dcb_tmp->state = MCA_DCB_OPENING_ST;
+                p_dcb_tmp->cong  = true;
+                p_dcb_tmp->p_cs  = p_cs;
+                p_dcb = p_dcb_tmp;
+                break;
+            }
+        }
+    }
+    return p_dcb;
+}
+
+/*******************************************************************************
+**
+** Function         mca_dep_free_mdl
+**
+** Description      This function is called to check the number of free mdl for
+**                  the given dep.
+**
+** Returns          the number of free mdl for the given dep
+**
+*******************************************************************************/
+uint8_t mca_dep_free_mdl(tMCA_CCB *p_ccb, tMCA_DEP dep)
+{
+    tMCA_DCB *p_dcb;
+    tMCA_RCB *p_rcb = p_ccb->p_rcb;
+    tMCA_CS  *p_cs;
+    int       i, max;
+    uint8_t count = 0;
+    uint8_t left;
+
+    if (dep < MCA_NUM_DEPS)
+    {
+        p_cs = &p_rcb->dep[dep];
+        i = mca_ccb_to_hdl(p_ccb)-1;
+        p_dcb = &mca_cb.dcb[i * MCA_NUM_MDLS];
+        /* make sure p_cs->max_mdl is smaller than MCA_NUM_MDLS at MCA_CreateDep */
+        max = p_cs->max_mdl;
+        for (i=0; i<max; i++, p_dcb++)
+        {
+            if ((p_dcb->state != MCA_DCB_NULL_ST) && (p_dcb->p_cs == p_cs))
+            {
+                count++;
+                break;
+            }
+        }
+    }
+    else
+    {
+        max = 0;
+        MCA_TRACE_WARNING("Invalid Dep ID");
+    }
+    left = max - count;
+    return left;
+}
+
+/*******************************************************************************
+**
+** Function         mca_dcb_dealloc
+**
+** Description      This function deallocates an DCB.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_dcb_dealloc(tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data)
+{
+    tMCA_CCB *p_ccb = p_dcb->p_ccb;
+    uint8_t  event = MCA_CLOSE_IND_EVT;
+    tMCA_CTRL   evt_data;
+
+    MCA_TRACE_DEBUG("mca_dcb_dealloc");
+    osi_free_and_reset((void **)&p_dcb->p_data);
+    if (p_data)
+    {
+        /* non-NULL -> an action function -> report disconnect event */
+        evt_data.close_cfm.mdl      = mca_dcb_to_hdl(p_dcb);
+        evt_data.close_cfm.reason   = p_data->close.reason;
+        evt_data.close_cfm.mdl_id   = p_dcb->mdl_id;
+        if (p_data->close.param == MCA_INT)
+            event = MCA_CLOSE_CFM_EVT;
+        if (p_data->close.lcid)
+            mca_ccb_report_event(p_ccb, event, &evt_data);
+    }
+    mca_free_tc_tbl_by_lcid (p_dcb->lcid);
+    memset (p_dcb, 0, sizeof (tMCA_DCB));
+}
+
+/*******************************************************************************
+**
+** Function         mca_dcb_to_hdl
+**
+** Description      This function converts a pointer to an DCB to a handle (tMCA_DL).
+**                  It returns the handle.
+**
+** Returns          tMCA_DL.
+**
+*******************************************************************************/
+tMCA_DL mca_dcb_to_hdl(tMCA_DCB *p_dcb)
+{
+    return (uint8_t) (p_dcb - mca_cb.dcb + 1);
+}
+
+/*******************************************************************************
+**
+** Function         mca_dcb_by_hdl
+**
+** Description      This function finds the DCB for a handle (tMCA_DL).
+**                  It returns a pointer to the DCB.
+**                  If no DCB matches the handle it returns NULL.
+**
+** Returns          tMCA_DCB *
+**
+*******************************************************************************/
+tMCA_DCB *mca_dcb_by_hdl(tMCA_DL hdl)
+{
+    tMCA_DCB * p_dcb = NULL;
+    if (hdl && hdl <= MCA_NUM_DCBS && mca_cb.dcb[hdl-1].state)
+        p_dcb = &mca_cb.dcb[hdl-1];
+    return p_dcb;
+}
+
+/*******************************************************************************
+**
+** Function         mca_dcb_close_by_mdl_id
+**
+** Description      This function finds the DCB for a mdl_id and
+**                  disconnect the mdl
+**
+** Returns          void
+**
+*******************************************************************************/
+void mca_dcb_close_by_mdl_id(tMCA_CCB*p_ccb, uint16_t mdl_id)
+{
+    tMCA_DCB *p_dcb;
+    int       i;
+
+    MCA_TRACE_DEBUG("mca_dcb_close_by_mdl_id mdl_id=%d", mdl_id);
+    i = mca_ccb_to_hdl(p_ccb)-1;
+    p_dcb = &mca_cb.dcb[i*MCA_NUM_MDLS];
+    for (i=0; i<MCA_NUM_MDLS; i++, p_dcb++)
+    {
+        if (p_dcb->state)
+        {
+            if (p_dcb->mdl_id == mdl_id)
+            {
+                mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
+                break;
+            }
+            else if (mdl_id == MCA_ALL_MDL_ID)
+            {
+                mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
+            }
+        }
+    }
+}
diff --git a/bt/stack/mcap/mca_int.h b/bt/stack/mcap/mca_int.h
new file mode 100644
index 0000000..accda78
--- /dev/null
+++ b/bt/stack/mcap/mca_int.h
@@ -0,0 +1,360 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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 interfaces which are internal to MCAP.
+ *
+ ******************************************************************************/
+#ifndef MCA_INT_H
+#define MCA_INT_H
+#include "bt_common.h"
+#include "osi/include/alarm.h"
+#include "mca_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* INT initiates the L2CAP channel */
+#define MCA_ACP     0
+#define MCA_INT     1
+
+/*****************************************************************************
+**  Type Definitions
+*****************************************************************************/
+
+/* Header structure for api/received request/response. */
+typedef struct {
+    BT_HDR          hdr;        /* layer specific information */
+    uint8_t         op_code;    /* the request/response opcode */
+    uint8_t         rsp_code;   /* valid only if op_code is a response */
+    uint16_t        mdl_id;     /* the MDL ID associated with this request/response */
+    uint8_t         param;      /* other parameter */
+    uint8_t         mdep_id;    /* the MDEP ID associated with this request/response */
+    /* tMCA_HANDLE     rcb_idx;    For internal use only */
+    /* tMCA_CL         ccb_idx;    For internal use only */
+    tMCA_DL         dcb_idx;    /* For internal use only */
+} tMCA_CCB_MSG;
+
+/* This data structure is associated with the AVDT_OPEN_IND_EVT and AVDT_OPEN_CFM_EVT. */
+typedef struct {
+    BT_HDR          hdr;                /* Event header */
+    uint16_t        peer_mtu;           /* Transport channel L2CAP MTU of the peer */
+    uint16_t        lcid;               /* L2CAP LCID  */
+    uint8_t         param;
+} tMCA_OPEN;
+
+typedef struct {
+    uint16_t        reason;     /* disconnect reason from L2CAP */
+    uint8_t         param;      /* MCA_INT or MCA_ACP */
+    uint16_t        lcid;       /* L2CAP LCID  */
+} tMCA_CLOSE;
+
+/* Header structure for state machine event parameters. */
+typedef union {
+    BT_HDR          hdr;        /* layer specific information */
+    tMCA_CCB_MSG    api;
+    bool            llcong;
+    uint8_t         param;
+    tMCA_OPEN       open;
+    tMCA_CLOSE      close;
+} tMCA_CCB_EVT;
+
+/* control channel states */
+enum
+{
+    MCA_CCB_NULL_ST,        /* not allocated */
+    MCA_CCB_OPENING_ST,
+    MCA_CCB_OPEN_ST,        /* open */
+    MCA_CCB_CLOSING_ST,		/* disconnecting */
+    MCA_CCB_MAX_ST
+};
+typedef uint8_t tMCA_CCB_STATE;
+
+/* control channel events */
+enum
+{
+    MCA_CCB_API_CONNECT_EVT,    /* application initiates a connect request. */
+    MCA_CCB_API_DISCONNECT_EVT, /* application initiates a disconnect request. */
+    MCA_CCB_API_REQ_EVT,        /* application initiates a request. The request may be create_mdl, delete_mdl, reconnect_mdl or abort_mdl. */
+    MCA_CCB_API_RSP_EVT,        /* application initiates a create_mdl or reconnect_mdl response. */
+    MCA_CCB_MSG_REQ_EVT,        /* a create_mdl, delete_mdl, reconnect_mdl or abort_mdl request message is received from the peer. */
+    MCA_CCB_MSG_RSP_EVT,        /* Response received event.  This event is sent whenever a response message is received for an outstanding request message. */
+    MCA_CCB_DL_OPEN_EVT,        /* data channel open. */
+    MCA_CCB_LL_OPEN_EVT,        /* Lower layer open.  This event is sent when the lower layer channel is open.  */
+    MCA_CCB_LL_CLOSE_EVT,       /* Lower layer close.  This event is sent when the lower layer channel is closed. */
+    MCA_CCB_LL_CONG_EVT,        /* Lower layer congestion.  This event is sent when the lower layer is congested. */
+    MCA_CCB_RSP_TOUT_EVT        /* time out for waiting the message response on the control channel */
+};
+
+/* Header structure for callback event parameters. */
+typedef union {
+    tMCA_OPEN       open;
+    tMCA_CLOSE      close;
+    BT_HDR          hdr;        /* layer specific information */
+    BT_HDR          *p_pkt;
+    bool            llcong;
+    uint16_t        mdl_id;     /* the MDL ID associated with this request/response */
+    /* tMCA_HANDLE     rcb_idx;    For internal use only */
+    /* tMCA_CL         ccb_idx;    For internal use only */
+    /* tMCA_DL         dcb_idx;    For internal use only */
+} tMCA_DCB_EVT;
+
+/* data channel states */
+enum
+{
+    MCA_DCB_NULL_ST,        /* not allocated */
+    MCA_DCB_OPENING_ST,     /* create/reconnect sequence is successful, waiting for data channel connection */
+    MCA_DCB_OPEN_ST,        /* open */
+    MCA_DCB_CLOSING_ST,     /* disconnecting */
+    MCA_DCB_MAX_ST
+};
+typedef uint8_t tMCA_DCB_STATE;
+
+/* data channel events */
+enum
+{
+    MCA_DCB_API_CLOSE_EVT,      /* This event is sent when the application wants to disconnect the data channel.*/
+    MCA_DCB_API_WRITE_EVT,      /* This event is sent when the application wants to send a data packet to the peer.*/
+    MCA_DCB_TC_OPEN_EVT,        /* Transport Channel open.  This event is sent when the channel is open.*/
+    MCA_DCB_TC_CLOSE_EVT,       /* Transport Channel close.*/
+    MCA_DCB_TC_CONG_EVT,        /* Transport Channel congestion status.*/
+    MCA_DCB_TC_DATA_EVT         /* This event is sent when a data packet is received from the peer.*/
+};
+
+
+
+
+/* "states" used in transport channel table */
+#define MCA_TC_ST_UNUSED   0       /* Unused - unallocated */
+#define MCA_TC_ST_IDLE     1       /* No connection */
+#define MCA_TC_ST_ACP      2       /* Waiting to accept a connection */
+#define MCA_TC_ST_INT      3       /* Initiating a connection */
+#define MCA_TC_ST_CONN     4       /* Waiting for connection confirm */
+#define MCA_TC_ST_CFG      5       /* Waiting for configuration complete */
+#define MCA_TC_ST_OPEN     6       /* Channel opened */
+#define MCA_TC_ST_SEC_INT  7       /* Security process as INT */
+#define MCA_TC_ST_SEC_ACP  8       /* Security process as ACP */
+
+/* Configuration flags. tMCA_TC_TBL.cfg_flags */
+#define MCA_L2C_CFG_IND_DONE   (1<<0)
+#define MCA_L2C_CFG_CFM_DONE   (1<<1)
+#define MCA_L2C_CFG_CONN_INT   (1<<2)
+#define MCA_L2C_CFG_CONN_ACP   (1<<3)
+#define MCA_L2C_CFG_DISCN_INT  (1<<4)
+#define MCA_L2C_CFG_DISCN_ACP  (1<<5)
+
+
+#define MCA_CTRL_TCID       0   /* to identify control channel by tMCA_TC_TBL.tcid */
+
+/* transport channel table */
+typedef struct {
+    uint16_t peer_mtu;       /* L2CAP mtu of the peer device */
+    uint16_t my_mtu;         /* Our MTU for this channel */
+    uint16_t lcid;           /* L2CAP LCID */
+    uint8_t tcid;           /* transport channel id (0, for control channel. (MDEP ID + 1) for data channel) */
+    tMCA_DL cb_idx;         /* 1-based index to ccb or dcb */
+    uint8_t state;          /* transport channel state */
+    uint8_t cfg_flags;      /* L2CAP configuration flags */
+    uint8_t id;             /* L2CAP id sent by peer device (need this to handle security pending) */
+} tMCA_TC_TBL;
+
+/* transport control block */
+typedef struct {
+    tMCA_TC_TBL     tc_tbl[MCA_NUM_TC_TBL];
+    uint8_t         lcid_tbl[MAX_L2CAP_CHANNELS];   /* map LCID to tc_tbl index */
+} tMCA_TC;
+
+/* registration control block */
+typedef struct {
+    tMCA_REG        reg;                /* the parameter at register */
+    tMCA_CS         dep[MCA_NUM_DEPS];  /* the registration info for each MDEP */
+    tMCA_CTRL_CBACK *p_cback;           /* control callback function */
+} tMCA_RCB;
+
+enum
+{
+    MCA_CCB_STAT_NORM,      /* normal operation (based on ccb state) */
+    MCA_CCB_STAT_PENDING,   /* waiting for data channel  */
+    MCA_CCB_STAT_RECONN,    /* reinitiate connection after transitioning from CLOSING to IDLE state  */
+    MCA_CCB_STAT_DISC       /* MCA_DisconnectReq or MCA_Deregister is called. waiting for all associated CL and DL to detach */
+};
+typedef uint8_t tMCA_CCB_STAT;
+
+/* control channel control block */
+/* the ccbs association with the rcbs
+ * ccb[0]              ...ccb[MCA_NUM_LINKS*1-1] -> rcb[0]
+ * ccb[MCA_NUM_LINKS*1]...ccb[MCA_NUM_LINKS*2-1] -> rcb[1]
+ * ccb[MCA_NUM_LINKS*2]...ccb[MCA_NUM_LINKS*3-1] -> rcb[2]
+ */
+typedef struct {
+    tMCA_RCB        *p_rcb;             /* the associated registration control block */
+    alarm_t         *mca_ccb_timer;     /* MCA CCB timer entry */
+    tMCA_CCB_MSG    *p_tx_req;          /* Current request being sent/awaiting response */
+    tMCA_CCB_MSG    *p_rx_msg;          /* Current message received/being processed */
+    BD_ADDR         peer_addr;          /* BD address of peer */
+    uint16_t        sec_mask;           /* Security mask for connections as initiator */
+    uint16_t        ctrl_vpsm;          /* The virtual PSM that peer is listening for control channel */
+    uint16_t        data_vpsm;          /* The virtual PSM that peer is listening for data channel. */
+    uint16_t        lcid;               /* L2CAP lcid for this control channel */
+    uint8_t         state;              /* The CCB state machine state */
+    bool            cong;               /* Whether control channel is congested */
+    tMCA_CCB_STAT   status;             /* see tMCA_CCB_STAT */
+} tMCA_CCB;
+typedef void (*tMCA_CCB_ACTION)(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+
+enum
+{
+    MCA_DCB_STAT_NORM,      /* normal operation (based on dcb state) */
+    MCA_DCB_STAT_DEL,       /* MCA_Delete is called. waiting for the DL to detach */
+    MCA_DCB_STAT_DISC       /* MCA_CloseReq is called. waiting for the DL to detach */
+};
+typedef uint8_t tMCA_DCB_STAT;
+
+/* data channel control block */
+/* the dcbs association with the ccbs
+ * dcb[0]             ...dcb[MCA_NUM_MDLS*1-1] -> ccb[0]
+ * dcb[MCA_NUM_MDLS*1]...dcb[MCA_NUM_MDLS*2-1] -> ccb[1]
+ * dcb[MCA_NUM_MDLS*2]...dcb[MCA_NUM_MDLS*3-1] -> ccb[2]
+ *
+ * the dcbs association with the rcbs
+ * dcb[0]                             ...dcb[MCA_NUM_MDLS*1*MCA_NUM_LINKS*1-1] -> rcb[0]
+ * dcb[MCA_NUM_MDLS*1*MCA_NUM_LINKS*1]...dcb[MCA_NUM_MDLS*2*MCA_NUM_LINKS*2-1] -> rcb[1]
+ * dcb[MCA_NUM_MDLS*2*MCA_NUM_LINKS*2]...dcb[MCA_NUM_MDLS*3*MCA_NUM_LINKS*3-1] -> rcb[2]
+ */
+typedef struct {
+    tMCA_CCB            *p_ccb;         /* the associated control control block */
+    BT_HDR              *p_data;        /* data packet held due to L2CAP channel congestion */
+    tMCA_CS             *p_cs;          /* the associated MDEP info. p_cs->type is the mdep id(internal use) */
+    const tMCA_CHNL_CFG *p_chnl_cfg;    /* cfg params for L2CAP channel */
+    uint16_t            mdl_id;         /* the MDL ID for this data channel */
+    uint16_t            lcid;           /* L2CAP lcid */
+    uint8_t             state;          /* The DCB state machine state */
+    bool                cong;           /* Whether data channel is congested */
+    tMCA_DCB_STAT       status;         /* see tMCA_DCB_STAT */
+} tMCA_DCB;
+
+typedef void (*tMCA_DCB_ACTION)(tMCA_DCB *p_ccb, tMCA_DCB_EVT *p_data);
+
+/* Control block for MCA */
+typedef struct {
+    tMCA_RCB        rcb[MCA_NUM_REGS];  /* registration control block */
+    tMCA_CCB        ccb[MCA_NUM_CCBS];  /* control channel control blocks */
+    tMCA_DCB        dcb[MCA_NUM_DCBS];  /* data channel control blocks */
+    tMCA_TC         tc;                 /* transport control block */
+    uint8_t         trace_level;        /* trace level */
+} tMCA_CB;
+
+/* csm functions */
+extern void mca_ccb_event(tMCA_CCB *p_ccb, uint8_t event, tMCA_CCB_EVT *p_data);
+extern tMCA_CCB *mca_ccb_by_bd(tMCA_HANDLE handle, BD_ADDR bd_addr);
+extern tMCA_CCB *mca_ccb_alloc(tMCA_HANDLE handle, BD_ADDR bd_addr);
+extern void mca_ccb_rsp_tout(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+extern void mca_ccb_dealloc(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+extern tMCA_CL mca_ccb_to_hdl(tMCA_CCB *p_ccb);
+extern tMCA_CCB *mca_ccb_by_hdl(tMCA_CL mcl);
+extern bool    mca_ccb_uses_mdl_id(tMCA_CCB *p_ccb, uint16_t mdl_id);
+
+/* cact functions */
+extern void mca_ccb_report_event(tMCA_CCB *p_ccb, uint8_t event, tMCA_CTRL *p_data);
+extern void mca_ccb_free_msg(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+extern void mca_ccb_snd_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+extern void mca_ccb_snd_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+extern void mca_ccb_do_disconn (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+extern void mca_ccb_cong(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+extern void mca_ccb_hdl_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+extern void mca_ccb_hdl_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+extern void mca_ccb_ll_open (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+extern void mca_ccb_dl_open (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data);
+
+/* dsm functions */
+extern void mca_dcb_event(tMCA_DCB *p_dcb, uint8_t event, tMCA_DCB_EVT *p_data);
+extern tMCA_DCB *mca_dcb_alloc(tMCA_CCB*p_ccb, tMCA_DEP dep);
+extern uint8_t mca_dep_free_mdl(tMCA_CCB*p_ccb, tMCA_DEP dep);
+extern void mca_dcb_dealloc(tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data);
+extern tMCA_DL mca_dcb_to_hdl(tMCA_DCB *p_dcb);
+extern tMCA_DCB *mca_dcb_by_hdl(tMCA_DL hdl);
+extern void mca_dcb_close_by_mdl_id(tMCA_CCB*p_ccb, uint16_t mdl_id);
+
+/* dact functions */
+extern void mca_dcb_tc_open (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data);
+extern void mca_dcb_cong (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data);
+extern void mca_dcb_free_data (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data);
+extern void mca_dcb_do_disconn (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data);
+extern void mca_dcb_snd_data (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data);
+extern void mca_dcb_hdl_data (tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data);
+
+
+/* main/utils functions */
+extern tMCA_HANDLE mca_handle_by_cpsm(uint16_t psm);
+extern tMCA_HANDLE mca_handle_by_dpsm(uint16_t psm);
+extern tMCA_TC_TBL * mca_tc_tbl_calloc(tMCA_CCB *p_ccb);
+extern tMCA_TC_TBL * mca_tc_tbl_dalloc(tMCA_DCB *p_dcb);
+extern tMCA_TC_TBL * mca_tc_tbl_by_lcid(uint16_t lcid);
+extern void mca_free_tc_tbl_by_lcid(uint16_t lcid);
+extern void mca_set_cfg_by_tbl(tL2CAP_CFG_INFO *p_cfg, tMCA_TC_TBL *p_tbl);
+extern void mca_tc_close_ind(tMCA_TC_TBL *p_tbl, uint16_t reason);
+extern void mca_tc_open_ind(tMCA_TC_TBL *p_tbl);
+extern void mca_tc_cong_ind(tMCA_TC_TBL *p_tbl, bool    is_congested);
+extern void mca_tc_data_ind(tMCA_TC_TBL *p_tbl, BT_HDR *p_buf);
+extern tMCA_RCB * mca_rcb_alloc(tMCA_REG *p_reg);
+extern void mca_rcb_dealloc(tMCA_HANDLE handle);
+extern tMCA_HANDLE mca_rcb_to_handle(tMCA_RCB *p_rcb);
+extern tMCA_RCB *mca_rcb_by_handle(tMCA_HANDLE handle);
+extern bool    mca_is_valid_dep_id(tMCA_RCB *p_rcb, tMCA_DEP dep);
+extern void mca_ccb_timer_timeout(void *data);
+extern void mca_stop_timer(tMCA_CCB *p_ccb);
+
+/* l2c functions */
+extern uint16_t mca_l2c_open_req(BD_ADDR bd_addr, uint16_t PSM, const tMCA_CHNL_CFG *p_chnl_cfg);
+
+/* callback function declarations */
+extern void mca_l2c_cconn_ind_cback(BD_ADDR bd_addr, uint16_t lcid, uint16_t psm, uint8_t id);
+extern void mca_l2c_dconn_ind_cback(BD_ADDR bd_addr, uint16_t lcid, uint16_t psm, uint8_t id);
+extern void mca_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result);
+extern void mca_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg);
+extern void mca_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg);
+extern void mca_l2c_disconnect_ind_cback(uint16_t lcid, bool    ack_needed);
+extern void mca_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result);
+extern void mca_l2c_congestion_ind_cback(uint16_t lcid, bool    is_congested);
+extern void mca_l2c_data_ind_cback(uint16_t lcid, BT_HDR *p_buf);
+
+/*****************************************************************************
+** global data
+*****************************************************************************/
+
+/******************************************************************************
+** Main Control Block
+*******************************************************************************/
+extern tMCA_CB mca_cb;
+
+/* L2CAP callback registration structure */
+extern const tL2CAP_APPL_INFO mca_l2c_int_appl;
+extern const tL2CAP_FCR_OPTS mca_l2c_fcr_opts_def;
+extern const uint8_t mca_std_msg_len[];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MCA_INT_H */
diff --git a/bt/stack/mcap/mca_l2c.cc b/bt/stack/mcap/mca_l2c.cc
new file mode 100644
index 0000000..e595001
--- /dev/null
+++ b/bt/stack/mcap/mca_l2c.cc
@@ -0,0 +1,587 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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 is the implementation file for the MCAP at L2CAP Interface.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mca_int.h"
+#include "osi/include/osi.h"
+
+
+/* L2CAP callback function structure */
+const tL2CAP_APPL_INFO mca_l2c_int_appl =
+{
+    NULL,
+    mca_l2c_connect_cfm_cback,
+    NULL,
+    mca_l2c_config_ind_cback,
+    mca_l2c_config_cfm_cback,
+    mca_l2c_disconnect_ind_cback,
+    mca_l2c_disconnect_cfm_cback,
+    NULL,
+    mca_l2c_data_ind_cback,
+    mca_l2c_congestion_ind_cback,
+	NULL
+};
+
+/* Control channel eL2CAP default options */
+const tL2CAP_FCR_OPTS mca_l2c_fcr_opts_def =
+{
+    L2CAP_FCR_ERTM_MODE,            /* Mandatory for MCAP */
+    MCA_FCR_OPT_TX_WINDOW_SIZE,     /* Tx window size */
+    MCA_FCR_OPT_MAX_TX_B4_DISCNT,   /* Maximum transmissions before disconnecting */
+    MCA_FCR_OPT_RETX_TOUT,          /* Retransmission timeout (2 secs) */
+    MCA_FCR_OPT_MONITOR_TOUT,       /* Monitor timeout (12 secs) */
+    MCA_FCR_OPT_MPS_SIZE            /* MPS segment size */
+};
+
+
+/*******************************************************************************
+**
+** Function         mca_sec_check_complete_term
+**
+** Description      The function called when Security Manager finishes
+**                  verification of the service side connection
+**
+** Returns          void
+**
+*******************************************************************************/
+static void mca_sec_check_complete_term (BD_ADDR bd_addr,
+                                         UNUSED_ATTR tBT_TRANSPORT transport, void *p_ref_data,
+                                         uint8_t res)
+{
+    tMCA_TC_TBL     *p_tbl = (tMCA_TC_TBL *)p_ref_data;
+    tL2CAP_CFG_INFO cfg;
+    tL2CAP_ERTM_INFO ertm_info;
+
+    MCA_TRACE_DEBUG("mca_sec_check_complete_term res: %d", res);
+
+    if ( res == BTM_SUCCESS )
+    {
+        MCA_TRACE_DEBUG ("lcid:x%x id:x%x", p_tbl->lcid, p_tbl->id);
+        /* Set the FCR options: control channel mandates ERTM */
+        ertm_info.preferred_mode    = mca_l2c_fcr_opts_def.mode;
+        ertm_info.allowed_modes     = L2CAP_FCR_CHAN_OPT_ERTM;
+        ertm_info.user_rx_buf_size  = MCA_USER_RX_BUF_SIZE;
+        ertm_info.user_tx_buf_size  = MCA_USER_TX_BUF_SIZE;
+        ertm_info.fcr_rx_buf_size   = MCA_FCR_RX_BUF_SIZE;
+        ertm_info.fcr_tx_buf_size   = MCA_FCR_TX_BUF_SIZE;
+        /* Send response to the L2CAP layer. */
+        L2CA_ErtmConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_OK, L2CAP_CONN_OK, &ertm_info);
+
+        /* transition to configuration state */
+        p_tbl->state = MCA_TC_ST_CFG;
+
+        /* Send L2CAP config req */
+        mca_set_cfg_by_tbl (&cfg, p_tbl);
+        L2CA_ConfigReq(p_tbl->lcid, &cfg);
+    }
+    else
+    {
+        L2CA_ConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
+        mca_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         mca_sec_check_complete_orig
+**
+** Description      The function called when Security Manager finishes
+**                  verification of the service side connection
+**
+** Returns          void
+**
+*******************************************************************************/
+static void mca_sec_check_complete_orig (UNUSED_ATTR BD_ADDR bd_addr, UNUSED_ATTR tBT_TRANSPORT transport, void *p_ref_data,
+                                         uint8_t res)
+{
+    tMCA_TC_TBL     *p_tbl = (tMCA_TC_TBL *)p_ref_data;
+    tL2CAP_CFG_INFO cfg;
+
+    MCA_TRACE_DEBUG("mca_sec_check_complete_orig res: %d", res);
+
+    if ( res == BTM_SUCCESS )
+    {
+        /* set channel state */
+        p_tbl->state = MCA_TC_ST_CFG;
+
+        /* Send L2CAP config req */
+        mca_set_cfg_by_tbl (&cfg, p_tbl);
+        L2CA_ConfigReq(p_tbl->lcid, &cfg);
+    }
+    else
+    {
+        L2CA_DisconnectReq (p_tbl->lcid);
+        mca_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
+    }
+}
+/*******************************************************************************
+**
+** Function         mca_l2c_cconn_ind_cback
+**
+** Description      This is the L2CAP connect indication callback function.
+**
+** Returns          void
+**
+*******************************************************************************/
+void mca_l2c_cconn_ind_cback(BD_ADDR bd_addr, uint16_t lcid, uint16_t psm, uint8_t id)
+{
+    tMCA_HANDLE handle = mca_handle_by_cpsm(psm);
+    tMCA_CCB    *p_ccb;
+    tMCA_TC_TBL *p_tbl = NULL;
+    uint16_t    result = L2CAP_CONN_NO_RESOURCES;
+    tBTM_STATUS rc;
+    tL2CAP_ERTM_INFO ertm_info, *p_ertm_info = NULL;
+    tL2CAP_CFG_INFO  cfg;
+
+    MCA_TRACE_EVENT ("mca_l2c_cconn_ind_cback: lcid:x%x psm:x%x id:x%x", lcid, psm, id);
+
+    /* do we already have a control channel for this peer? */
+    if ((p_ccb = mca_ccb_by_bd(handle, bd_addr)) == NULL)
+    {
+        /* no, allocate ccb */
+        if ((p_ccb = mca_ccb_alloc(handle, bd_addr)) != NULL)
+        {
+            /* allocate and set up entry */
+            p_ccb->lcid     = lcid;
+            p_tbl           = mca_tc_tbl_calloc(p_ccb);
+            p_tbl->id       = id;
+            p_tbl->cfg_flags= MCA_L2C_CFG_CONN_ACP;
+            /* proceed with connection */
+            /* Check the security */
+            rc = btm_sec_mx_access_request (bd_addr, psm, false, BTM_SEC_PROTO_MCA, 0,
+                                            &mca_sec_check_complete_term, p_tbl);
+            if (rc == BTM_CMD_STARTED)
+            {
+                /* Set the FCR options: control channel mandates ERTM */
+                ertm_info.preferred_mode    = mca_l2c_fcr_opts_def.mode;
+                ertm_info.allowed_modes     = L2CAP_FCR_CHAN_OPT_ERTM;
+                ertm_info.user_rx_buf_size  = MCA_USER_RX_BUF_SIZE;
+                ertm_info.user_tx_buf_size  = MCA_USER_TX_BUF_SIZE;
+                ertm_info.fcr_rx_buf_size   = MCA_FCR_RX_BUF_SIZE;
+                ertm_info.fcr_tx_buf_size   = MCA_FCR_TX_BUF_SIZE;
+                p_ertm_info = &ertm_info;
+                result = L2CAP_CONN_PENDING;
+            }
+            else
+                result = L2CAP_CONN_OK;
+        }
+
+        /*  deal with simultaneous control channel connect case */
+    }
+    /* else reject their connection */
+
+    if (!p_tbl || (p_tbl->state != MCA_TC_ST_CFG))
+    {
+        /* Send L2CAP connect rsp */
+        L2CA_ErtmConnectRsp (bd_addr, id, lcid, result, L2CAP_CONN_OK, p_ertm_info);
+
+        /* if result ok, proceed with connection and send L2CAP
+           config req */
+        if (result == L2CAP_CONN_OK)
+        {
+            /* set channel state */
+            p_tbl->state = MCA_TC_ST_CFG;
+
+            /* Send L2CAP config req */
+            mca_set_cfg_by_tbl (&cfg, p_tbl);
+            L2CA_ConfigReq(p_tbl->lcid, &cfg);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         mca_l2c_dconn_ind_cback
+**
+** Description      This is the L2CAP connect indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void mca_l2c_dconn_ind_cback(BD_ADDR bd_addr, uint16_t lcid, uint16_t psm, uint8_t id)
+{
+    tMCA_HANDLE handle = mca_handle_by_dpsm(psm);
+    tMCA_CCB    *p_ccb;
+    tMCA_DCB       *p_dcb;
+    tMCA_TC_TBL    *p_tbl = NULL;
+    uint16_t        result;
+    tL2CAP_CFG_INFO cfg;
+    tL2CAP_ERTM_INFO *p_ertm_info = NULL, ertm_info;
+    const tMCA_CHNL_CFG   *p_chnl_cfg;
+
+    MCA_TRACE_EVENT ("mca_l2c_dconn_ind_cback: lcid:x%x psm:x%x ", lcid, psm);
+
+    if (((p_ccb = mca_ccb_by_bd(handle, bd_addr)) != NULL) && /* find the CCB */
+        (p_ccb->status == MCA_CCB_STAT_PENDING) &&  /* this CCB is expecting a MDL */
+        (p_ccb->p_tx_req && (p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL))
+    {
+        /* found the associated dcb in listening mode */
+        /* proceed with connection */
+        p_dcb->lcid     = lcid;
+        p_tbl           = mca_tc_tbl_dalloc(p_dcb);
+        p_tbl->id       = id;
+        p_tbl->cfg_flags= MCA_L2C_CFG_CONN_ACP;
+        p_chnl_cfg = p_dcb->p_chnl_cfg;
+        /* assume that control channel has verified the security requirement */
+        /* Set the FCR options: control channel mandates ERTM */
+        ertm_info.preferred_mode    = p_chnl_cfg->fcr_opt.mode;
+        ertm_info.allowed_modes     = (1 << p_chnl_cfg->fcr_opt.mode);
+        ertm_info.user_rx_buf_size  = p_chnl_cfg->user_rx_buf_size;
+        ertm_info.user_tx_buf_size  = p_chnl_cfg->user_tx_buf_size;
+        ertm_info.fcr_rx_buf_size   = p_chnl_cfg->fcr_rx_buf_size;
+        ertm_info.fcr_tx_buf_size   = p_chnl_cfg->fcr_tx_buf_size;
+        p_ertm_info = &ertm_info;
+        result = L2CAP_CONN_OK;
+    }
+    else
+    {
+        /* else we're not listening for traffic channel; reject
+         * (this error code is specified by MCAP spec) */
+        result = L2CAP_CONN_NO_RESOURCES;
+    }
+
+    /* Send L2CAP connect rsp */
+    L2CA_ErtmConnectRsp (bd_addr, id, lcid, result, result, p_ertm_info);
+
+    /* if result ok, proceed with connection */
+    if (result == L2CAP_CONN_OK)
+    {
+        /* transition to configuration state */
+        p_tbl->state = MCA_TC_ST_CFG;
+
+        /* Send L2CAP config req */
+        mca_set_cfg_by_tbl (&cfg, p_tbl);
+        L2CA_ConfigReq(lcid, &cfg);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         mca_l2c_connect_cfm_cback
+**
+** Description      This is the L2CAP connect confirm callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void mca_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result)
+{
+    tMCA_TC_TBL    *p_tbl;
+    tL2CAP_CFG_INFO cfg;
+    tMCA_CCB *p_ccb;
+
+    MCA_TRACE_DEBUG("mca_l2c_connect_cfm_cback lcid: x%x, result: %d",
+                     lcid, result);
+    /* look up info for this channel */
+    if ((p_tbl = mca_tc_tbl_by_lcid(lcid)) != NULL)
+    {
+        MCA_TRACE_DEBUG("p_tbl state: %d, tcid: %d", p_tbl->state, p_tbl->tcid);
+        /* if in correct state */
+        if (p_tbl->state == MCA_TC_ST_CONN)
+        {
+            /* if result successful */
+            if (result == L2CAP_CONN_OK)
+            {
+                if (p_tbl->tcid != 0)
+                {
+                    /* set channel state */
+                    p_tbl->state = MCA_TC_ST_CFG;
+
+                    /* Send L2CAP config req */
+                    mca_set_cfg_by_tbl (&cfg, p_tbl);
+                    L2CA_ConfigReq(lcid, &cfg);
+                }
+                else
+                {
+                    p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
+                    if (p_ccb == NULL)
+                    {
+                        result = L2CAP_CONN_NO_RESOURCES;
+                    }
+                    else
+                    {
+                        /* set channel state */
+                        p_tbl->state    = MCA_TC_ST_SEC_INT;
+                        p_tbl->lcid     = lcid;
+                        p_tbl->cfg_flags= MCA_L2C_CFG_CONN_INT;
+
+                        /* Check the security */
+                        btm_sec_mx_access_request (p_ccb->peer_addr, p_ccb->ctrl_vpsm,
+                                                   true, BTM_SEC_PROTO_MCA,
+                                                   p_tbl->tcid,
+                                                   &mca_sec_check_complete_orig, p_tbl);
+                    }
+                }
+            }
+
+            /* failure; notify adaption that channel closed */
+            if (result != L2CAP_CONN_OK)
+            {
+                p_tbl->cfg_flags |= MCA_L2C_CFG_DISCN_INT;
+                mca_tc_close_ind(p_tbl, result);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         mca_l2c_config_cfm_cback
+**
+** Description      This is the L2CAP config confirm callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void mca_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+    tMCA_TC_TBL    *p_tbl;
+
+    /* look up info for this channel */
+    if ((p_tbl = mca_tc_tbl_by_lcid(lcid)) != NULL)
+    {
+        /* if in correct state */
+        if (p_tbl->state == MCA_TC_ST_CFG)
+        {
+            /* if result successful */
+            if (p_cfg->result == L2CAP_CONN_OK)
+            {
+                /* update cfg_flags */
+                p_tbl->cfg_flags |= MCA_L2C_CFG_CFM_DONE;
+
+                /* if configuration complete */
+                if (p_tbl->cfg_flags & MCA_L2C_CFG_IND_DONE)
+                {
+                    mca_tc_open_ind(p_tbl);
+                }
+            }
+            /* else failure */
+            else
+            {
+                /* Send L2CAP disconnect req */
+                L2CA_DisconnectReq(lcid);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         mca_l2c_config_ind_cback
+**
+** Description      This is the L2CAP config indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void mca_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+    tMCA_TC_TBL    *p_tbl;
+    uint16_t        result = L2CAP_CFG_OK;
+
+    /* look up info for this channel */
+    if ((p_tbl = mca_tc_tbl_by_lcid(lcid)) != NULL)
+    {
+        /* store the mtu in tbl */
+        if (p_cfg->mtu_present)
+        {
+            p_tbl->peer_mtu = p_cfg->mtu;
+            if (p_tbl->peer_mtu < MCA_MIN_MTU)
+            {
+                result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+            }
+        }
+        else
+        {
+            p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+        }
+        MCA_TRACE_DEBUG("peer_mtu: %d, lcid: x%x mtu_present:%d",p_tbl->peer_mtu, lcid, p_cfg->mtu_present);
+
+        /* send L2CAP configure response */
+        memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+        p_cfg->result = result;
+        L2CA_ConfigRsp(lcid, p_cfg);
+
+        /* if first config ind */
+        if ((p_tbl->cfg_flags & MCA_L2C_CFG_IND_DONE) == 0)
+        {
+            /* update cfg_flags */
+            p_tbl->cfg_flags |= MCA_L2C_CFG_IND_DONE;
+
+            /* if configuration complete */
+            if (p_tbl->cfg_flags & MCA_L2C_CFG_CFM_DONE)
+            {
+                mca_tc_open_ind(p_tbl);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         mca_l2c_disconnect_ind_cback
+**
+** Description      This is the L2CAP disconnect indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void mca_l2c_disconnect_ind_cback(uint16_t lcid, bool    ack_needed)
+{
+    tMCA_TC_TBL    *p_tbl;
+    uint16_t       reason = L2CAP_DISC_TIMEOUT;
+
+    MCA_TRACE_DEBUG("mca_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d",
+                     lcid, ack_needed);
+    /* look up info for this channel */
+    if ((p_tbl = mca_tc_tbl_by_lcid(lcid)) != NULL)
+    {
+        if (ack_needed)
+        {
+            /* send L2CAP disconnect response */
+            L2CA_DisconnectRsp(lcid);
+        }
+
+        p_tbl->cfg_flags = MCA_L2C_CFG_DISCN_ACP;
+        if (ack_needed)
+            reason = L2CAP_DISC_OK;
+        mca_tc_close_ind(p_tbl, reason);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         mca_l2c_disconnect_cfm_cback
+**
+** Description      This is the L2CAP disconnect confirm callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void mca_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result)
+{
+    tMCA_TC_TBL    *p_tbl;
+
+    MCA_TRACE_DEBUG("mca_l2c_disconnect_cfm_cback lcid: x%x, result: %d",
+                     lcid, result);
+    /* look up info for this channel */
+    if ((p_tbl = mca_tc_tbl_by_lcid(lcid)) != NULL)
+    {
+        p_tbl->cfg_flags = MCA_L2C_CFG_DISCN_INT;
+        mca_tc_close_ind(p_tbl, result);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         mca_l2c_congestion_ind_cback
+**
+** Description      This is the L2CAP congestion indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void mca_l2c_congestion_ind_cback(uint16_t lcid, bool    is_congested)
+{
+    tMCA_TC_TBL    *p_tbl;
+
+    /* look up info for this channel */
+    if ((p_tbl = mca_tc_tbl_by_lcid(lcid)) != NULL)
+    {
+        mca_tc_cong_ind(p_tbl, is_congested);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         mca_l2c_data_ind_cback
+**
+** Description      This is the L2CAP data indication callback function.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void mca_l2c_data_ind_cback(uint16_t lcid, BT_HDR *p_buf)
+{
+    tMCA_TC_TBL    *p_tbl;
+
+    /* look up info for this channel */
+    if ((p_tbl = mca_tc_tbl_by_lcid(lcid)) != NULL)
+    {
+        mca_tc_data_ind(p_tbl, p_buf);
+    }
+    else /* prevent buffer leak */
+        osi_free(p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         mca_l2c_open_req
+**
+** Description      This function calls L2CA_ConnectReq() to initiate a L2CAP channel.
+**
+** Returns          void.
+**
+*******************************************************************************/
+uint16_t mca_l2c_open_req(BD_ADDR bd_addr, uint16_t psm, const tMCA_CHNL_CFG *p_chnl_cfg)
+{
+    tL2CAP_ERTM_INFO ertm_info;
+
+    if (p_chnl_cfg)
+    {
+        ertm_info.preferred_mode    = p_chnl_cfg->fcr_opt.mode;
+        ertm_info.allowed_modes     = (1 << p_chnl_cfg->fcr_opt.mode);
+        ertm_info.user_rx_buf_size  = p_chnl_cfg->user_rx_buf_size;
+        ertm_info.user_tx_buf_size  = p_chnl_cfg->user_tx_buf_size;
+        ertm_info.fcr_rx_buf_size   = p_chnl_cfg->fcr_rx_buf_size;
+        ertm_info.fcr_tx_buf_size   = p_chnl_cfg->fcr_tx_buf_size;
+    }
+    else
+    {
+        ertm_info.preferred_mode    = mca_l2c_fcr_opts_def.mode;
+        ertm_info.allowed_modes     = L2CAP_FCR_CHAN_OPT_ERTM;
+        ertm_info.user_rx_buf_size  = MCA_USER_RX_BUF_SIZE;
+        ertm_info.user_tx_buf_size  = MCA_USER_TX_BUF_SIZE;
+        ertm_info.fcr_rx_buf_size   = MCA_FCR_RX_BUF_SIZE;
+        ertm_info.fcr_tx_buf_size   = MCA_FCR_TX_BUF_SIZE;
+    }
+    return L2CA_ErtmConnectReq (psm, bd_addr, &ertm_info);
+}
+
diff --git a/bt/stack/mcap/mca_main.cc b/bt/stack/mcap/mca_main.cc
new file mode 100644
index 0000000..f2255b0
--- /dev/null
+++ b/bt/stack/mcap/mca_main.cc
@@ -0,0 +1,629 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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 is the implementation file for the MCAP Main Control Block and
+ *  Utility functions.
+ *
+ ******************************************************************************/
+#include <assert.h>
+#include <string.h>
+
+#include "bt_target.h"
+#include "bt_common.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mca_int.h"
+#include "l2c_api.h"
+
+/* Main Control block for MCA */
+tMCA_CB mca_cb;
+
+/*****************************************************************************
+** constants
+*****************************************************************************/
+
+/* table of standard opcode message size */
+const uint8_t mca_std_msg_len[MCA_NUM_STANDARD_OPCODE] = {
+    4,          /* MCA_OP_ERROR_RSP         */
+    5,          /* MCA_OP_MDL_CREATE_REQ    */
+    5,          /* MCA_OP_MDL_CREATE_RSP    */
+    3,          /* MCA_OP_MDL_RECONNECT_REQ */
+    4,          /* MCA_OP_MDL_RECONNECT_RSP */
+    3,          /* MCA_OP_MDL_ABORT_REQ     */
+    4,          /* MCA_OP_MDL_ABORT_RSP     */
+    3,          /* MCA_OP_MDL_DELETE_REQ    */
+    4           /* MCA_OP_MDL_DELETE_RSP    */
+};
+
+
+/*******************************************************************************
+**
+** Function         mca_handle_by_cpsm
+**
+** Description      This function returns the handle for the given control
+**                  channel PSM. 0, if not found.
+**
+** Returns          the MCA handle.
+**
+*******************************************************************************/
+tMCA_HANDLE mca_handle_by_cpsm(uint16_t psm)
+{
+    int     i;
+    tMCA_HANDLE handle = 0;
+    tMCA_RCB *p_rcb = &mca_cb.rcb[0];
+
+    for (i=0; i<MCA_NUM_REGS; i++, p_rcb++)
+    {
+        if (p_rcb->p_cback && p_rcb->reg.ctrl_psm == psm)
+        {
+            handle = i+1;
+            break;
+        }
+    }
+    return handle;
+}
+
+/*******************************************************************************
+**
+** Function         mca_handle_by_dpsm
+**
+** Description      This function returns the handle for the given data
+**                  channel PSM. 0, if not found.
+**
+** Returns          the MCA handle.
+**
+*******************************************************************************/
+tMCA_HANDLE mca_handle_by_dpsm(uint16_t psm)
+{
+    int     i;
+    tMCA_HANDLE handle = 0;
+    tMCA_RCB *p_rcb = &mca_cb.rcb[0];
+
+    for (i=0; i<MCA_NUM_REGS; i++, p_rcb++)
+    {
+        if (p_rcb->p_cback && p_rcb->reg.data_psm == psm)
+        {
+            handle = i+1;
+            break;
+        }
+    }
+    return handle;
+}
+
+/*******************************************************************************
+**
+** Function         mca_tc_tbl_calloc
+**
+** Description      This function allocates a transport table for the given
+**                  control channel.
+**
+** Returns          The tranport table.
+**
+*******************************************************************************/
+tMCA_TC_TBL * mca_tc_tbl_calloc(tMCA_CCB *p_ccb)
+{
+    tMCA_TC_TBL *p_tbl = mca_cb.tc.tc_tbl;
+    int             i;
+
+    /* find next free entry in tc table */
+    for (i = 0; i < MCA_NUM_TC_TBL; i++, p_tbl++)
+    {
+        if (p_tbl->state == MCA_TC_ST_UNUSED)
+        {
+            break;
+        }
+    }
+
+    /* sanity check */
+    assert(i != MCA_NUM_TC_TBL);
+
+    /* initialize entry */
+    p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+    p_tbl->cfg_flags= 0;
+    p_tbl->cb_idx   = mca_ccb_to_hdl(p_ccb);
+    p_tbl->tcid     = MCA_CTRL_TCID;
+    p_tbl->my_mtu   = MCA_CTRL_MTU;
+    p_tbl->state    = MCA_TC_ST_IDLE;
+    p_tbl->lcid     = p_ccb->lcid;
+    mca_cb.tc.lcid_tbl[p_ccb->lcid - L2CAP_BASE_APPL_CID] = i;
+
+    MCA_TRACE_DEBUG("%s() - cb_idx: %d", __func__, p_tbl->cb_idx);
+    return p_tbl;
+}
+
+/*******************************************************************************
+**
+** Function         mca_tc_tbl_dalloc
+**
+** Description      This function allocates a transport table for the given
+**                  data channel.
+**
+** Returns          The tranport table.
+**
+*******************************************************************************/
+tMCA_TC_TBL * mca_tc_tbl_dalloc(tMCA_DCB *p_dcb)
+{
+    tMCA_TC_TBL *p_tbl = mca_cb.tc.tc_tbl;
+    int             i;
+
+    /* find next free entry in tc table */
+    for (i = 0; i < MCA_NUM_TC_TBL; i++, p_tbl++)
+    {
+        if (p_tbl->state == MCA_TC_ST_UNUSED)
+        {
+            break;
+        }
+    }
+
+    /* sanity check */
+    assert(i != MCA_NUM_TC_TBL);
+
+    /* initialize entry */
+    p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+    p_tbl->cfg_flags= 0;
+    p_tbl->cb_idx   = mca_dcb_to_hdl(p_dcb);
+    p_tbl->tcid     = p_dcb->p_cs->type + 1;
+    p_tbl->my_mtu   = p_dcb->p_chnl_cfg->data_mtu;
+    p_tbl->state    = MCA_TC_ST_IDLE;
+    p_tbl->lcid     = p_dcb->lcid;
+    mca_cb.tc.lcid_tbl[p_dcb->lcid - L2CAP_BASE_APPL_CID] = i;
+
+    MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx: %d", __func__, p_tbl->tcid, p_tbl->cb_idx);
+    return p_tbl;
+}
+
+/*******************************************************************************
+**
+** Function         mca_tc_tbl_by_lcid
+**
+** Description      Find the transport channel table entry by LCID.
+**
+**
+** Returns          The tranport table.
+**
+*******************************************************************************/
+tMCA_TC_TBL *mca_tc_tbl_by_lcid(uint16_t lcid)
+{
+    uint8_t idx;
+
+    if (lcid)
+    {
+        idx = mca_cb.tc.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
+
+        if (idx < MCA_NUM_TC_TBL)
+        {
+            return &mca_cb.tc.tc_tbl[idx];
+        }
+    }
+    return NULL;
+}
+
+/*******************************************************************************
+**
+** Function         mca_free_tc_tbl_by_lcid
+**
+** Description      Find the  transport table entry by LCID
+**                  and free the tc_tbl
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_free_tc_tbl_by_lcid(uint16_t lcid)
+{
+    uint8_t idx;
+
+    if (lcid)
+    {
+        idx = mca_cb.tc.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
+
+        if (idx < MCA_NUM_TC_TBL)
+        {
+            mca_cb.tc.tc_tbl[idx].state = MCA_TC_ST_UNUSED;
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         mca_set_cfg_by_tbl
+**
+** Description      Set the L2CAP configuration information
+**
+** Returns          none.
+**
+*******************************************************************************/
+void mca_set_cfg_by_tbl(tL2CAP_CFG_INFO *p_cfg, tMCA_TC_TBL *p_tbl)
+{
+    tMCA_DCB   *p_dcb;
+    const tL2CAP_FCR_OPTS *p_opt;
+    tMCA_FCS_OPT    fcs = MCA_FCS_NONE;
+
+    if (p_tbl->tcid == MCA_CTRL_TCID)
+    {
+        p_opt = &mca_l2c_fcr_opts_def;
+    }
+    else
+    {
+        p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
+        if (p_dcb)
+        {
+            p_opt = &p_dcb->p_chnl_cfg->fcr_opt;
+            fcs   = p_dcb->p_chnl_cfg->fcs;
+        }
+    }
+    memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+    p_cfg->mtu_present = true;
+    p_cfg->mtu = p_tbl->my_mtu;
+    p_cfg->fcr_present = true;
+    memcpy(&p_cfg->fcr, p_opt, sizeof (tL2CAP_FCR_OPTS));
+    if (fcs & MCA_FCS_PRESNT_MASK)
+    {
+        p_cfg->fcs_present = true;
+        p_cfg->fcs = (fcs & MCA_FCS_USE_MASK);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         mca_tc_close_ind
+**
+** Description      This function is called by the L2CAP interface when the
+**                  L2CAP channel is closed.  It looks up the CCB or DCB for
+**                  the channel and sends it a close event.  The reason
+**                  parameter is the same value passed by the L2CAP
+**                  callback function.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void mca_tc_close_ind(tMCA_TC_TBL *p_tbl, uint16_t reason)
+{
+    tMCA_CCB   *p_ccb;
+    tMCA_DCB   *p_dcb;
+    tMCA_CLOSE  close;
+
+    close.param  = MCA_ACP;
+    close.reason = reason;
+    close.lcid   = p_tbl->lcid;
+
+    MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx:%d, old: %d", __func__, 
+                     p_tbl->tcid, p_tbl->cb_idx, p_tbl->state);
+
+    /* Check if the transport channel is in use */
+    if (p_tbl->state == MCA_TC_ST_UNUSED)
+        return;
+
+    /* clear mca_tc_tbl entry */
+    if (p_tbl->cfg_flags&MCA_L2C_CFG_DISCN_INT)
+        close.param = MCA_INT;
+    p_tbl->cfg_flags = 0;
+    p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+
+    /* if control channel, notify ccb that channel close */
+    if (p_tbl->tcid == MCA_CTRL_TCID)
+    {
+        p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
+        mca_ccb_event(p_ccb, MCA_CCB_LL_CLOSE_EVT, (tMCA_CCB_EVT *)&close);
+    }
+    /* notify dcb that channel close */
+    else
+    {
+        /* look up dcb  */
+        p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
+        if (p_dcb != NULL)
+        {
+            mca_dcb_event(p_dcb, MCA_DCB_TC_CLOSE_EVT, (tMCA_DCB_EVT *) &close);
+        }
+    }
+    p_tbl->state = MCA_TC_ST_UNUSED;
+}
+
+/*******************************************************************************
+**
+** Function         mca_tc_open_ind
+**
+** Description      This function is called by the L2CAP interface when
+**                  the L2CAP channel is opened.  It looks up the CCB or DCB
+**                  for the channel and sends it an open event.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void mca_tc_open_ind(tMCA_TC_TBL *p_tbl)
+{
+    tMCA_CCB   *p_ccb;
+    tMCA_DCB   *p_dcb;
+    tMCA_OPEN  open;
+
+    MCA_TRACE_DEBUG("mca_tc_open_ind tcid: %d, cb_idx: %d", p_tbl->tcid, p_tbl->cb_idx);
+    p_tbl->state = MCA_TC_ST_OPEN;
+
+    open.peer_mtu = p_tbl->peer_mtu;
+    open.lcid = p_tbl->lcid;
+    /* use param to indicate the role of connection.
+     * MCA_ACP, if ACP */
+    open.param = MCA_INT;
+    if (p_tbl->cfg_flags & MCA_L2C_CFG_CONN_ACP)
+    {
+        open.param = MCA_ACP;
+    }
+
+    /* if control channel, notify ccb that channel open */
+    if (p_tbl->tcid == MCA_CTRL_TCID)
+    {
+        p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
+
+        mca_ccb_event(p_ccb, MCA_CCB_LL_OPEN_EVT, (tMCA_CCB_EVT *)&open);
+    }
+    /* must be data channel, notify dcb that channel open */
+    else
+    {
+        /* look up dcb */
+        p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
+
+        /* put lcid in event data */
+        if (p_dcb != NULL)
+        {
+            mca_dcb_event(p_dcb, MCA_DCB_TC_OPEN_EVT, (tMCA_DCB_EVT *) &open);
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         mca_tc_cong_ind
+**
+** Description      This function is called by the L2CAP interface layer when
+**                  L2CAP calls the congestion callback.  It looks up the CCB
+**                  or DCB for the channel and sends it a congestion event.
+**                  The is_congested parameter is the same value passed by
+**                  the L2CAP callback function.
+**
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void mca_tc_cong_ind(tMCA_TC_TBL *p_tbl, bool    is_congested)
+{
+    tMCA_CCB   *p_ccb;
+    tMCA_DCB   *p_dcb;
+
+    MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx: %d", __func__, p_tbl->tcid, p_tbl->cb_idx);
+
+    /* if control channel, notify ccb of congestion */
+    if (p_tbl->tcid == MCA_CTRL_TCID)
+    {
+        p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
+        mca_ccb_event(p_ccb, MCA_CCB_LL_CONG_EVT, (tMCA_CCB_EVT *) &is_congested);
+    }
+    /* notify dcb that channel open */
+    else
+    {
+        /* look up dcb by cb_idx */
+        p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
+        if (p_dcb != NULL)
+        {
+            mca_dcb_event(p_dcb, MCA_DCB_TC_CONG_EVT, (tMCA_DCB_EVT *) &is_congested);
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         mca_tc_data_ind
+**
+** Description      This function is called by the L2CAP interface layer when
+**                  incoming data is received from L2CAP.  It looks up the CCB
+**                  or DCB for the channel and routes the data accordingly.
+**
+** Returns          Nothing.
+**
+*******************************************************************************/
+void mca_tc_data_ind(tMCA_TC_TBL *p_tbl, BT_HDR *p_buf)
+{
+    tMCA_CCB   *p_ccb;
+    tMCA_DCB   *p_dcb;
+    uint8_t     event = MCA_CCB_MSG_RSP_EVT;
+    uint8_t     *p;
+    uint8_t     rej_rsp_code = MCA_RSP_SUCCESS;
+
+    MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx: %d", __func__, p_tbl->tcid, p_tbl->cb_idx);
+
+    /* if control channel, handle control message */
+    if (p_tbl->tcid == MCA_CTRL_TCID)
+    {
+        p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
+        if (p_ccb)
+        {
+            p = (uint8_t*)(p_buf+1) + p_buf->offset;
+            /* all the request opcode has bit 0 set. response code has bit 0 clear */
+            if ((*p) & 0x01)
+                event = MCA_CCB_MSG_REQ_EVT;
+
+            if (*p < MCA_NUM_STANDARD_OPCODE)
+            {
+                if (p_buf->len != mca_std_msg_len[*p])
+                {
+                    MCA_TRACE_ERROR ("$s() - opcode: %d required len: %d, got len: %d"
+                      , __func__, *p, mca_std_msg_len[*p], p_buf->len);
+                    rej_rsp_code = MCA_RSP_BAD_PARAM;
+                }
+            }
+            else if ((*p >= MCA_FIRST_SYNC_OP) && (*p <= MCA_LAST_SYNC_OP))
+            {
+                MCA_TRACE_ERROR ("%s() - unsupported SYNC opcode: %d len:%d"
+                    , __func__, *p, p_buf->len);
+                /* reject unsupported request */
+                rej_rsp_code = MCA_RSP_NO_SUPPORT;
+            }
+            else
+            {
+                MCA_TRACE_ERROR ("%s() - bad opcode: %d len:%d", __func__, *p, p_buf->len);
+                /* reject unsupported request */
+                rej_rsp_code = MCA_RSP_BAD_OPCODE;
+            }
+
+            p_buf->layer_specific = rej_rsp_code;
+            /* forward the request/response to state machine */
+            mca_ccb_event(p_ccb, event, (tMCA_CCB_EVT *) p_buf);
+        } /* got a valid ccb */
+        else
+            osi_free(p_buf);
+    }
+    /* else send event to dcb */
+    else
+    {
+        p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
+        if (p_dcb != NULL)
+        {
+            mca_dcb_event(p_dcb, MCA_DCB_TC_DATA_EVT, (tMCA_DCB_EVT *) p_buf);
+        }
+        else
+            osi_free(p_buf);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         mca_rcb_alloc
+**
+** Description      This function allocates a registration control block.
+**                  If no free RCB is available, it returns NULL.
+**
+** Returns          tMCA_RCB *
+**
+*******************************************************************************/
+tMCA_RCB * mca_rcb_alloc(tMCA_REG *p_reg)
+{
+    int     i;
+    tMCA_RCB *p_rcb = NULL;
+
+    for (i=0; i<MCA_NUM_REGS; i++)
+    {
+        if (mca_cb.rcb[i].p_cback == NULL)
+        {
+            p_rcb = &mca_cb.rcb[i];
+            memcpy (&p_rcb->reg, p_reg, sizeof(tMCA_REG));
+            break;
+        }
+    }
+    return p_rcb;
+}
+
+/*******************************************************************************
+**
+** Function         mca_rcb_dealloc
+**
+** Description      This function deallocates the RCB with the given handle.
+**
+** Returns          void.
+**
+*******************************************************************************/
+void mca_rcb_dealloc(tMCA_HANDLE handle)
+{
+    int      i;
+    bool     done = true;
+    tMCA_RCB *p_rcb;
+    tMCA_CCB *p_ccb;
+
+    if (handle && (handle<=MCA_NUM_REGS))
+    {
+        handle--;
+        p_rcb = &mca_cb.rcb[handle];
+        if (p_rcb->p_cback)
+        {
+            p_ccb = &mca_cb.ccb[handle*MCA_NUM_LINKS];
+            /* check if all associated CCB are disconnected */
+            for (i=0; i<MCA_NUM_LINKS; i++, p_ccb++)
+            {
+                if (p_ccb->p_rcb)
+                {
+                    done = false;
+                    mca_ccb_event (p_ccb, MCA_CCB_API_DISCONNECT_EVT, NULL);
+                }
+            }
+
+            if (done)
+            {
+                memset (p_rcb, 0, sizeof(tMCA_RCB));
+                MCA_TRACE_DEBUG("%s() - reset MCA_RCB index=%d", __func__, handle);
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         mca_rcb_to_handle
+**
+** Description      This function converts a pointer to an RCB to
+**                  a handle (tMCA_HANDLE).  It returns the handle.
+**
+** Returns          void.
+**
+*******************************************************************************/
+tMCA_HANDLE mca_rcb_to_handle(tMCA_RCB *p_rcb)
+{
+    return(uint8_t) (p_rcb - mca_cb.rcb + 1);
+}
+
+/*******************************************************************************
+**
+** Function         mca_rcb_by_handle
+**
+** Description      This function finds the RCB for a handle (tMCA_HANDLE).
+**                  It returns a pointer to the RCB.  If no RCB matches the
+**                  handle it returns NULL.
+**
+** Returns          tMCA_RCB *
+**
+*******************************************************************************/
+tMCA_RCB *mca_rcb_by_handle(tMCA_HANDLE handle)
+{
+    tMCA_RCB *p_rcb = NULL;
+
+    if (handle && (handle<=MCA_NUM_REGS) && mca_cb.rcb[handle-1].p_cback)
+    {
+        p_rcb = &mca_cb.rcb[handle-1];
+    }
+    return p_rcb;
+}
+
+/*******************************************************************************
+**
+** Function         mca_is_valid_dep_id
+**
+** Description      This function checks if the given dep_id is valid.
+**
+** Returns          true, if this is a valid local dep_id
+**
+*******************************************************************************/
+bool    mca_is_valid_dep_id(tMCA_RCB *p_rcb, tMCA_DEP dep)
+{
+    bool    valid = false;
+    if (dep < MCA_NUM_DEPS && p_rcb->dep[dep].p_data_cback)
+    {
+        valid = true;
+    }
+    return valid;
+}
diff --git a/bt/stack/pan/pan_api.cc b/bt/stack/pan/pan_api.cc
new file mode 100644
index 0000000..19da970
--- /dev/null
+++ b/bt/stack/pan/pan_api.cc
@@ -0,0 +1,768 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 main functions to support PAN profile
+ *  commands and events.
+ *
+ *****************************************************************************/
+
+#include <string.h>
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bnep_api.h"
+#include "pan_api.h"
+#include "pan_int.h"
+#include "sdp_api.h"
+#include "sdpdefs.h"
+#include "l2c_api.h"
+#include "hcidefs.h"
+#include "btm_api.h"
+#include "bta_sys.h"
+
+
+/*******************************************************************************
+**
+** Function         PAN_Register
+**
+** Description      This function is called by the application to register
+**                  its callbacks with PAN profile. The application then
+**                  should set the PAN role explicitly.
+**
+** Parameters:      p_register - contains all callback function pointers
+**
+**
+** Returns          none
+**
+*******************************************************************************/
+void PAN_Register (tPAN_REGISTER *p_register)
+{
+    BTM_SetDiscoverability (BTM_GENERAL_DISCOVERABLE, 0, 0);
+    BTM_SetConnectability (BTM_CONNECTABLE, 0, 0);
+
+    pan_register_with_bnep ();
+
+    if (!p_register)
+        return;
+
+    pan_cb.pan_conn_state_cb    = p_register->pan_conn_state_cb;
+    pan_cb.pan_bridge_req_cb    = p_register->pan_bridge_req_cb;
+    pan_cb.pan_data_buf_ind_cb  = p_register->pan_data_buf_ind_cb;
+    pan_cb.pan_data_ind_cb      = p_register->pan_data_ind_cb;
+    pan_cb.pan_pfilt_ind_cb     = p_register->pan_pfilt_ind_cb;
+    pan_cb.pan_mfilt_ind_cb     = p_register->pan_mfilt_ind_cb;
+    pan_cb.pan_tx_data_flow_cb  = p_register->pan_tx_data_flow_cb;
+
+    return;
+}
+
+
+
+/*******************************************************************************
+**
+** Function         PAN_Deregister
+**
+** Description      This function is called by the application to de-register
+**                  its callbacks with PAN profile. This will make the PAN to
+**                  become inactive. This will deregister PAN services from SDP
+**                  and close all active connections
+**
+** Parameters:      none
+**
+**
+** Returns          none
+**
+*******************************************************************************/
+void PAN_Deregister (void)
+{
+    pan_cb.pan_bridge_req_cb    = NULL;
+    pan_cb.pan_data_buf_ind_cb  = NULL;
+    pan_cb.pan_data_ind_cb      = NULL;
+    pan_cb.pan_conn_state_cb    = NULL;
+    pan_cb.pan_pfilt_ind_cb     = NULL;
+    pan_cb.pan_mfilt_ind_cb     = NULL;
+
+    PAN_SetRole (PAN_ROLE_INACTIVE, NULL, NULL, NULL, NULL);
+    BNEP_Deregister ();
+
+    return;
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function         PAN_SetRole
+**
+** Description      This function is called by the application to set the PAN
+**                  profile role. This should be called after PAN_Register.
+**                  This can be called any time to change the PAN role
+**
+** Parameters:      role        - is bit map of roles to be active
+**                                      PAN_ROLE_CLIENT is for PANU role
+**                                      PAN_ROLE_GN_SERVER is for GN role
+**                                      PAN_ROLE_NAP_SERVER is for NAP role
+**                  sec_mask    - Security mask for different roles
+**                                      It is array of uint8_t. The byte represent the
+**                                      security for roles PANU, GN and NAP in order
+**                  p_user_name - Service name for PANU role
+**                  p_gn_name   - Service name for GN role
+**                  p_nap_name  - Service name for NAP role
+**                                      Can be NULL if user wants it to be default
+**
+** Returns          PAN_SUCCESS     - if the role is set successfully
+**                  PAN_FAILURE     - if the role is not valid
+**
+*******************************************************************************/
+tPAN_RESULT PAN_SetRole (uint8_t role,
+                         uint8_t *sec_mask,
+                         const char *p_user_name,
+                         const char *p_gn_name,
+                         const char *p_nap_name)
+{
+    const char          *p_desc;
+    uint8_t             security[3] = {PAN_PANU_SECURITY_LEVEL,
+                                       PAN_GN_SECURITY_LEVEL,
+                                       PAN_NAP_SECURITY_LEVEL};
+    uint8_t             *p_sec;
+
+    /* If the role is not a valid combination reject it */
+    if ((!(role & (PAN_ROLE_CLIENT | PAN_ROLE_GN_SERVER | PAN_ROLE_NAP_SERVER))) &&
+        role != PAN_ROLE_INACTIVE)
+    {
+        PAN_TRACE_ERROR ("PAN role %d is invalid", role);
+        return PAN_FAILURE;
+    }
+
+    /* If the current active role is same as the role being set do nothing */
+    if (pan_cb.role == role)
+    {
+        PAN_TRACE_EVENT ("PAN role already was set to: %d", role);
+        return PAN_SUCCESS;
+    }
+
+    if (!sec_mask)
+        p_sec = security;
+    else
+        p_sec = sec_mask;
+
+    /* Register all the roles with SDP */
+    PAN_TRACE_API ("PAN_SetRole() called with role 0x%x", role);
+#if (PAN_SUPPORTS_ROLE_NAP == TRUE)
+    if (role & PAN_ROLE_NAP_SERVER)
+    {
+        /* Check the service name */
+        if ((p_nap_name == NULL) || (*p_nap_name == 0))
+            p_nap_name = PAN_NAP_DEFAULT_SERVICE_NAME;
+
+        /* Registering for NAP service with SDP */
+        p_desc = PAN_NAP_DEFAULT_DESCRIPTION;
+
+        if (pan_cb.pan_nap_sdp_handle != 0)
+            SDP_DeleteRecord (pan_cb.pan_nap_sdp_handle);
+
+        pan_cb.pan_nap_sdp_handle = pan_register_with_sdp (UUID_SERVCLASS_NAP, p_sec[2], p_nap_name, p_desc);
+        bta_sys_add_uuid(UUID_SERVCLASS_NAP);
+    }
+    /* If the NAP role is already active and now being cleared delete the record */
+    else if (pan_cb.role & PAN_ROLE_NAP_SERVER)
+    {
+        if (pan_cb.pan_nap_sdp_handle != 0)
+        {
+            SDP_DeleteRecord (pan_cb.pan_nap_sdp_handle);
+            pan_cb.pan_nap_sdp_handle = 0;
+            bta_sys_remove_uuid(UUID_SERVCLASS_NAP);
+        }
+    }
+#endif
+
+#if (PAN_SUPPORTS_ROLE_GN == TRUE)
+    if (role & PAN_ROLE_GN_SERVER)
+    {
+        /* Check the service name */
+        if ((p_gn_name == NULL) || (*p_gn_name == 0))
+            p_gn_name = PAN_GN_DEFAULT_SERVICE_NAME;
+
+        /* Registering for GN service with SDP */
+        p_desc = PAN_GN_DEFAULT_DESCRIPTION;
+
+        if (pan_cb.pan_gn_sdp_handle != 0)
+            SDP_DeleteRecord (pan_cb.pan_gn_sdp_handle);
+
+        pan_cb.pan_gn_sdp_handle = pan_register_with_sdp (UUID_SERVCLASS_GN, p_sec[1], p_gn_name, p_desc);
+        bta_sys_add_uuid(UUID_SERVCLASS_GN);
+    }
+    /* If the GN role is already active and now being cleared delete the record */
+    else if (pan_cb.role & PAN_ROLE_GN_SERVER)
+    {
+        if (pan_cb.pan_gn_sdp_handle != 0)
+        {
+            SDP_DeleteRecord (pan_cb.pan_gn_sdp_handle);
+            pan_cb.pan_gn_sdp_handle = 0;
+            bta_sys_remove_uuid(UUID_SERVCLASS_GN);
+        }
+    }
+#endif
+
+#if (PAN_SUPPORTS_ROLE_PANU == TRUE)
+    if (role & PAN_ROLE_CLIENT)
+    {
+        /* Check the service name */
+        if ((p_user_name == NULL) || (*p_user_name == 0))
+            p_user_name = PAN_PANU_DEFAULT_SERVICE_NAME;
+
+        /* Registering for PANU service with SDP */
+        p_desc = PAN_PANU_DEFAULT_DESCRIPTION;
+        if (pan_cb.pan_user_sdp_handle != 0)
+            SDP_DeleteRecord (pan_cb.pan_user_sdp_handle);
+
+        pan_cb.pan_user_sdp_handle = pan_register_with_sdp (UUID_SERVCLASS_PANU, p_sec[0], p_user_name, p_desc);
+        bta_sys_add_uuid(UUID_SERVCLASS_PANU);
+    }
+    /* If the PANU role is already active and now being cleared delete the record */
+    else if (pan_cb.role & PAN_ROLE_CLIENT)
+    {
+        if (pan_cb.pan_user_sdp_handle != 0)
+        {
+            SDP_DeleteRecord (pan_cb.pan_user_sdp_handle);
+            pan_cb.pan_user_sdp_handle = 0;
+            bta_sys_remove_uuid(UUID_SERVCLASS_PANU);
+        }
+    }
+#endif
+
+    /* Check if it is a shutdown request */
+    if (role == PAN_ROLE_INACTIVE)
+        pan_close_all_connections ();
+
+    pan_cb.role = role;
+    PAN_TRACE_EVENT ("PAN role set to: %d", role);
+    return PAN_SUCCESS;
+}
+
+
+
+/*******************************************************************************
+**
+** Function         PAN_Connect
+**
+** Description      This function is called by the application to initiate a
+**                  connection to the remote device
+**
+** Parameters:      rem_bda     - BD Addr of the remote device
+**                  src_role    - Role of the local device for the connection
+**                  dst_role    - Role of the remote device for the connection
+**                                      PAN_ROLE_CLIENT is for PANU role
+**                                      PAN_ROLE_GN_SERVER is for GN role
+**                                      PAN_ROLE_NAP_SERVER is for NAP role
+**                  *handle     - Pointer for returning Handle to the connection
+**
+** Returns          PAN_SUCCESS      - if the connection is initiated successfully
+**                  PAN_NO_RESOURCES - resources are not sufficent
+**                  PAN_FAILURE      - if the connection cannot be initiated
+**                                           this can be because of the combination of
+**                                           src and dst roles may not be valid or
+**                                           allowed at that point of time
+**
+*******************************************************************************/
+tPAN_RESULT PAN_Connect (BD_ADDR rem_bda, uint8_t src_role, uint8_t dst_role, uint16_t *handle)
+{
+    tPAN_CONN       *pcb;
+    tBNEP_RESULT    result;
+    tBT_UUID        src_uuid, dst_uuid;
+    uint32_t mx_chan_id;
+
+    /*
+    ** Initialize the handle so that in case of failure return values
+    ** the profile will not get confused
+    */
+    *handle = BNEP_INVALID_HANDLE;
+
+    /* Check if PAN is active or not */
+    if (!(pan_cb.role & src_role))
+    {
+        PAN_TRACE_ERROR ("PAN is not active for the role %d", src_role);
+        return PAN_FAILURE;
+    }
+
+    /* Validate the parameters before proceeding */
+    if ((src_role != PAN_ROLE_CLIENT && src_role != PAN_ROLE_GN_SERVER && src_role != PAN_ROLE_NAP_SERVER) ||
+        (dst_role != PAN_ROLE_CLIENT && dst_role != PAN_ROLE_GN_SERVER && dst_role != PAN_ROLE_NAP_SERVER))
+    {
+        PAN_TRACE_ERROR ("Either source %d or destination role %d is invalid", src_role, dst_role);
+        return PAN_FAILURE;
+    }
+
+    /* Check if connection exists for this remote device */
+    pcb = pan_get_pcb_by_addr (rem_bda);
+
+    /* If we are PANU for this role validate destination role */
+    if (src_role == PAN_ROLE_CLIENT)
+    {
+        if ((pan_cb.num_conns > 1) || (pan_cb.num_conns && (!pcb)))
+        {
+            /*
+            ** If the request is not for existing connection reject it
+            ** because if there is already a connection we cannot accept
+            ** another connection in PANU role
+            */
+            PAN_TRACE_ERROR ("Cannot make PANU connections when there are more than one connection");
+            return PAN_INVALID_SRC_ROLE;
+        }
+
+        src_uuid.uu.uuid16 = UUID_SERVCLASS_PANU;
+        if (dst_role == PAN_ROLE_CLIENT)
+        {
+            dst_uuid.uu.uuid16 = UUID_SERVCLASS_PANU;
+        }
+        else if (dst_role == PAN_ROLE_GN_SERVER)
+        {
+            dst_uuid.uu.uuid16 = UUID_SERVCLASS_GN;
+        }
+        else
+        {
+            dst_uuid.uu.uuid16 = UUID_SERVCLASS_NAP;
+        }
+        mx_chan_id = dst_uuid.uu.uuid16;
+    }
+    /* If destination is PANU role validate source role */
+    else if (dst_role == PAN_ROLE_CLIENT)
+    {
+        if (pan_cb.num_conns && pan_cb.active_role == PAN_ROLE_CLIENT && !pcb)
+        {
+            PAN_TRACE_ERROR ("Device already have a connection in PANU role");
+            return PAN_INVALID_SRC_ROLE;
+        }
+
+        dst_uuid.uu.uuid16 = UUID_SERVCLASS_PANU;
+        if (src_role == PAN_ROLE_GN_SERVER)
+        {
+            src_uuid.uu.uuid16 = UUID_SERVCLASS_GN;
+        }
+        else
+        {
+            src_uuid.uu.uuid16 = UUID_SERVCLASS_NAP;
+        }
+        mx_chan_id = src_uuid.uu.uuid16;
+    }
+    /* The role combination is not valid */
+    else
+    {
+        PAN_TRACE_ERROR ("Source %d and Destination roles %d are not valid combination",
+            src_role, dst_role);
+        return PAN_FAILURE;
+    }
+
+    /* Allocate control block and initiate connection */
+    if (!pcb)
+        pcb = pan_allocate_pcb (rem_bda, BNEP_INVALID_HANDLE);
+    if (!pcb)
+    {
+        PAN_TRACE_ERROR ("PAN Connection failed because of no resources");
+        return PAN_NO_RESOURCES;
+    }
+    BTM_SetOutService(rem_bda, BTM_SEC_SERVICE_BNEP_PANU, mx_chan_id);
+
+    PAN_TRACE_API ("PAN_Connect() for BD Addr %x.%x.%x.%x.%x.%x",
+        rem_bda[0], rem_bda[1], rem_bda[2], rem_bda[3], rem_bda[4], rem_bda[5]);
+    if (pcb->con_state == PAN_STATE_IDLE)
+    {
+        pan_cb.num_conns++;
+    }
+    else if (pcb->con_state == PAN_STATE_CONNECTED)
+    {
+        pcb->con_flags |= PAN_FLAGS_CONN_COMPLETED;
+    }
+    else
+        /* PAN connection is still in progress */
+        return PAN_WRONG_STATE;
+
+    pcb->con_state = PAN_STATE_CONN_START;
+    pcb->prv_src_uuid = pcb->src_uuid;
+    pcb->prv_dst_uuid = pcb->dst_uuid;
+
+    pcb->src_uuid     = src_uuid.uu.uuid16;
+    pcb->dst_uuid     = dst_uuid.uu.uuid16;
+
+    src_uuid.len      = 2;
+    dst_uuid.len      = 2;
+
+    result = BNEP_Connect (rem_bda, &src_uuid, &dst_uuid, &(pcb->handle));
+    if (result != BNEP_SUCCESS)
+    {
+        pan_release_pcb (pcb);
+        return result;
+    }
+
+    PAN_TRACE_DEBUG ("PAN_Connect() current active role set to %d", src_role);
+    pan_cb.prv_active_role = pan_cb.active_role;
+    pan_cb.active_role = src_role;
+    *handle = pcb->handle;
+    return PAN_SUCCESS;
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function         PAN_Disconnect
+**
+** Description      This is used to disconnect the connection
+**
+** Parameters:      handle           - handle for the connection
+**
+** Returns          PAN_SUCCESS      - if the connection is closed successfully
+**                  PAN_FAILURE      - if the connection is not found or
+**                                           there is an error in disconnecting
+**
+*******************************************************************************/
+tPAN_RESULT PAN_Disconnect (uint16_t handle)
+{
+    tPAN_CONN       *pcb;
+    tBNEP_RESULT    result;
+
+    /* Check if the connection exists */
+    pcb = pan_get_pcb_by_handle (handle);
+    if(!pcb)
+    {
+        PAN_TRACE_ERROR ("PAN connection not found for the handle %d", handle);
+        return PAN_FAILURE;
+    }
+
+    result = BNEP_Disconnect (pcb->handle);
+    if (pcb->con_state != PAN_STATE_IDLE)
+        pan_cb.num_conns--;
+
+    if (pan_cb.pan_bridge_req_cb && pcb->src_uuid == UUID_SERVCLASS_NAP)
+        (*pan_cb.pan_bridge_req_cb) (pcb->rem_bda, false);
+
+    pan_release_pcb (pcb);
+
+    if (result != BNEP_SUCCESS)
+    {
+        PAN_TRACE_EVENT ("Error in closing PAN connection");
+        return PAN_FAILURE;
+    }
+
+    PAN_TRACE_EVENT ("PAN connection closed");
+    return PAN_SUCCESS;
+}
+
+
+/*******************************************************************************
+**
+** Function         PAN_Write
+**
+** Description      This sends data over the PAN connections. If this is called
+**                  on GN or NAP side and the packet is multicast or broadcast
+**                  it will be sent on all the links. Otherwise the correct link
+**                  is found based on the destination address and forwarded on it.
+**
+** Parameters:      handle   - handle for the connection
+**                  dst      - MAC or BD Addr of the destination device
+**                  src      - MAC or BD Addr of the source who sent this packet
+**                  protocol - protocol of the ethernet packet like IP or ARP
+**                  p_data   - pointer to the data
+**                  len      - length of the data
+**                  ext      - to indicate that extension headers present
+**
+** Returns          PAN_SUCCESS       - if the data is sent successfully
+**                  PAN_FAILURE       - if the connection is not found or
+**                                           there is an error in sending data
+**
+*******************************************************************************/
+tPAN_RESULT PAN_Write(uint16_t handle, BD_ADDR dst, BD_ADDR src, uint16_t protocol, uint8_t *p_data, uint16_t len, bool    ext)
+{
+    if (pan_cb.role == PAN_ROLE_INACTIVE || !pan_cb.num_conns) {
+        PAN_TRACE_ERROR("%s PAN is not active, data write failed.", __func__);
+        return PAN_FAILURE;
+    }
+
+    // If the packet is broadcast or multicast, we're going to have to create
+    // a copy of the packet for each connection. We can save one extra copy
+    // by fast-pathing here and calling BNEP_Write instead of placing the packet
+    // in a BT_HDR buffer, calling BNEP_Write, and then freeing the buffer.
+    if (dst[0] & 0x01) {
+        int i;
+        for (i = 0; i < MAX_PAN_CONNS; ++i) {
+            if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED)
+                BNEP_Write (pan_cb.pcb[i].handle, dst, p_data, len, protocol, src, ext);
+        }
+        return PAN_SUCCESS;
+    }
+
+    BT_HDR *buffer = (BT_HDR *)osi_malloc(PAN_BUF_SIZE);
+    buffer->len = len;
+    buffer->offset = PAN_MINIMUM_OFFSET;
+    memcpy((uint8_t *)buffer + sizeof(BT_HDR) + buffer->offset, p_data, buffer->len);
+
+    return PAN_WriteBuf(handle, dst, src, protocol, buffer, ext);
+}
+
+
+/*******************************************************************************
+**
+** Function         PAN_WriteBuf
+**
+** Description      This sends data over the PAN connections. If this is called
+**                  on GN or NAP side and the packet is multicast or broadcast
+**                  it will be sent on all the links. Otherwise the correct link
+**                  is found based on the destination address and forwarded on it
+**                  If the return value is not PAN_SUCCESS the application should
+**                  take care of releasing the message buffer
+**
+** Parameters:      handle   - handle for the connection
+**                  dst      - MAC or BD Addr of the destination device
+**                  src      - MAC or BD Addr of the source who sent this packet
+**                  protocol - protocol of the ethernet packet like IP or ARP
+**                  p_buf    - pointer to the data buffer
+**                  ext      - to indicate that extension headers present
+**
+** Returns          PAN_SUCCESS       - if the data is sent successfully
+**                  PAN_FAILURE       - if the connection is not found or
+**                                           there is an error in sending data
+**
+*******************************************************************************/
+tPAN_RESULT PAN_WriteBuf (uint16_t handle, BD_ADDR dst, BD_ADDR src, uint16_t protocol, BT_HDR *p_buf, bool    ext)
+{
+    tPAN_CONN       *pcb;
+    uint16_t        i;
+    tBNEP_RESULT    result;
+
+    if (pan_cb.role == PAN_ROLE_INACTIVE || (!(pan_cb.num_conns)))
+    {
+        PAN_TRACE_ERROR ("PAN is not active Data write failed");
+        osi_free(p_buf);
+        return PAN_FAILURE;
+    }
+
+    /* Check if it is broadcast or multicast packet */
+    if (dst[0] & 0x01)
+    {
+        uint8_t *data = (uint8_t *)p_buf + sizeof(BT_HDR) + p_buf->offset;
+        for (i = 0; i < MAX_PAN_CONNS; ++i) {
+            if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED)
+                BNEP_Write(pan_cb.pcb[i].handle, dst, data, p_buf->len, protocol, src, ext);
+        }
+        osi_free(p_buf);
+        return PAN_SUCCESS;
+    }
+
+    /* Check if the data write is on PANU side */
+    if (pan_cb.active_role == PAN_ROLE_CLIENT)
+    {
+        /* Data write is on PANU connection */
+        for (i=0; i<MAX_PAN_CONNS; i++)
+        {
+            if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED &&
+                pan_cb.pcb[i].src_uuid == UUID_SERVCLASS_PANU)
+                break;
+        }
+
+        if (i == MAX_PAN_CONNS)
+        {
+            PAN_TRACE_ERROR ("PAN Don't have any user connections");
+            osi_free(p_buf);
+            return PAN_FAILURE;
+        }
+
+        result = BNEP_WriteBuf (pan_cb.pcb[i].handle, dst, p_buf, protocol, src, ext);
+        if (result == BNEP_IGNORE_CMD)
+        {
+            PAN_TRACE_DEBUG ("PAN ignored data write for PANU connection");
+            return result;
+        }
+        else if (result != BNEP_SUCCESS)
+        {
+            PAN_TRACE_ERROR ("PAN failed to write data for the PANU connection");
+            return result;
+        }
+
+        PAN_TRACE_DEBUG ("PAN successfully wrote data for the PANU connection");
+        return PAN_SUCCESS;
+    }
+
+    /* findout to which connection the data is meant for */
+    pcb = pan_get_pcb_by_handle (handle);
+    if (!pcb)
+    {
+        PAN_TRACE_ERROR ("PAN Buf write for wrong handle");
+        osi_free(p_buf);
+        return PAN_FAILURE;
+    }
+
+    if (pcb->con_state != PAN_STATE_CONNECTED)
+    {
+        PAN_TRACE_ERROR ("PAN Buf write when conn is not active");
+        osi_free(p_buf);
+        return PAN_FAILURE;
+    }
+
+    result = BNEP_WriteBuf (pcb->handle, dst, p_buf, protocol, src, ext);
+    if (result == BNEP_IGNORE_CMD)
+    {
+        PAN_TRACE_DEBUG ("PAN ignored data buf write to PANU");
+        return result;
+    }
+    else if (result != BNEP_SUCCESS)
+    {
+        PAN_TRACE_ERROR ("PAN failed to send data buf to the PANU");
+        return result;
+    }
+
+    PAN_TRACE_DEBUG ("PAN successfully sent data buf to the PANU");
+    return PAN_SUCCESS;
+}
+
+
+/*******************************************************************************
+**
+** Function         PAN_SetProtocolFilters
+**
+** Description      This function is used to set protocol filters on the peer
+**
+** Parameters:      handle      - handle for the connection
+**                  num_filters - number of protocol filter ranges
+**                  start       - array of starting protocol numbers
+**                  end         - array of ending protocol numbers
+**
+**
+** Returns          PAN_SUCCESS        if protocol filters are set successfully
+**                  PAN_FAILURE        if connection not found or error in setting
+**
+*******************************************************************************/
+tPAN_RESULT PAN_SetProtocolFilters (uint16_t handle,
+                                    uint16_t num_filters,
+                                    uint16_t *p_start_array,
+                                    uint16_t *p_end_array)
+{
+    tPAN_CONN       *pcb;
+    tPAN_RESULT     result;
+
+    /* Check if the connection exists */
+    pcb = pan_get_pcb_by_handle (handle);
+    if(!pcb)
+    {
+        PAN_TRACE_ERROR ("PAN connection not found for the handle %d", handle);
+        return PAN_FAILURE;
+    }
+
+    result = BNEP_SetProtocolFilters (pcb->handle, num_filters, p_start_array, p_end_array);
+    if (result != BNEP_SUCCESS)
+    {
+        PAN_TRACE_ERROR ("PAN failed to set protocol filters for handle %d", handle);
+        return result;
+    }
+
+    PAN_TRACE_API ("PAN successfully sent protocol filters for handle %d", handle);
+    return PAN_SUCCESS;
+}
+
+
+
+/*******************************************************************************
+**
+** Function         PAN_SetMulticastFilters
+**
+** Description      This function is used to set multicast filters on the peer
+**
+** Parameters:      handle      - handle for the connection
+**                  num_filters - number of multicast filter ranges
+**                  start       - array of starting multicast filter addresses
+**                  end         - array of ending multicast filter addresses
+**
+**
+** Returns          PAN_SUCCESS        if multicast filters are set successfully
+**                  PAN_FAILURE        if connection not found or error in setting
+**
+*******************************************************************************/
+tBNEP_RESULT PAN_SetMulticastFilters (uint16_t handle,
+                                      uint16_t num_mcast_filters,
+                                      uint8_t *p_start_array,
+                                      uint8_t *p_end_array)
+{
+    tPAN_CONN       *pcb;
+    tPAN_RESULT     result;
+
+    /* Check if the connection exists */
+    pcb = pan_get_pcb_by_handle (handle);
+    if(!pcb)
+    {
+        PAN_TRACE_ERROR ("PAN connection not found for the handle %d", handle);
+        return PAN_FAILURE;
+    }
+
+    result = BNEP_SetMulticastFilters (pcb->handle,
+                            num_mcast_filters, p_start_array, p_end_array);
+    if (result != BNEP_SUCCESS)
+    {
+        PAN_TRACE_ERROR ("PAN failed to set multicast filters for handle %d", handle);
+        return result;
+    }
+
+    PAN_TRACE_API ("PAN successfully sent multicast filters for handle %d", handle);
+    return PAN_SUCCESS;
+}
+
+
+/*******************************************************************************
+**
+** Function         PAN_SetTraceLevel
+**
+** Description      This function sets the trace level for PAN. If called with
+**                  a value of 0xFF, it simply reads the current trace level.
+**
+** Returns          the new (current) trace level
+**
+*******************************************************************************/
+uint8_t PAN_SetTraceLevel (uint8_t new_level)
+{
+    if (new_level != 0xFF)
+        pan_cb.trace_level = new_level;
+    else
+        pan_dump_status ();
+
+    return (pan_cb.trace_level);
+}
+
+/*******************************************************************************
+**
+** Function         PAN_Init
+**
+** Description      This function initializes the PAN module variables
+**
+** Parameters:      none
+**
+** Returns          none
+**
+*******************************************************************************/
+void PAN_Init (void)
+{
+    memset (&pan_cb, 0, sizeof (tPAN_CB));
+
+#if defined(PAN_INITIAL_TRACE_LEVEL)
+    pan_cb.trace_level = PAN_INITIAL_TRACE_LEVEL;
+#else
+    pan_cb.trace_level = BT_TRACE_LEVEL_NONE;    /* No traces */
+#endif
+}
+
+
diff --git a/bt/stack/pan/pan_int.h b/bt/stack/pan/pan_int.h
new file mode 100644
index 0000000..7779724
--- /dev/null
+++ b/bt/stack/pan/pan_int.h
@@ -0,0 +1,151 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2001-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 internally used PAN definitions
+ *
+ ******************************************************************************/
+
+#ifndef  PAN_INT_H
+#define  PAN_INT_H
+
+#include "pan_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** This role is used to shutdown the profile. Used internally
+** Applications should call PAN_Deregister to shutdown the profile
+*/
+#define PAN_ROLE_INACTIVE      0
+
+/* Protocols supported by the host internal stack, are registered with SDP */
+#define PAN_PROTOCOL_IP        0x0800
+#define PAN_PROTOCOL_ARP       0x0806
+
+#define PAN_PROFILE_VERSION    0x0100   /* Version 1.00 */
+
+/* Define the PAN Connection Control Block
+*/
+typedef struct
+{
+#define PAN_STATE_IDLE              0
+#define PAN_STATE_CONN_START        1
+#define PAN_STATE_CONNECTED         2
+    uint8_t           con_state;
+
+#define PAN_FLAGS_CONN_COMPLETED    0x01
+    uint8_t           con_flags;
+
+    uint16_t          handle;
+    BD_ADDR           rem_bda;
+
+    uint16_t          bad_pkts_rcvd;
+    uint16_t          src_uuid;
+    uint16_t          dst_uuid;
+    uint16_t          prv_src_uuid;
+    uint16_t          prv_dst_uuid;
+    uint16_t          ip_addr_known;
+    uint32_t          ip_addr;
+
+} tPAN_CONN;
+
+
+/*  The main PAN control block
+*/
+typedef struct
+{
+    uint8_t                     role;
+    uint8_t                     active_role;
+    uint8_t                     prv_active_role;
+    tPAN_CONN                   pcb[MAX_PAN_CONNS];
+
+    tPAN_CONN_STATE_CB          *pan_conn_state_cb;     /* Connection state callback */
+    tPAN_BRIDGE_REQ_CB          *pan_bridge_req_cb;
+    tPAN_DATA_IND_CB            *pan_data_ind_cb;
+    tPAN_DATA_BUF_IND_CB        *pan_data_buf_ind_cb;
+    tPAN_FILTER_IND_CB          *pan_pfilt_ind_cb;      /* protocol filter indication callback */
+    tPAN_MFILTER_IND_CB         *pan_mfilt_ind_cb;      /* multicast filter indication callback */
+    tPAN_TX_DATA_FLOW_CB        *pan_tx_data_flow_cb;
+
+    char                        *user_service_name;
+    char                        *gn_service_name;
+    char                        *nap_service_name;
+    uint32_t                    pan_user_sdp_handle;
+    uint32_t                    pan_gn_sdp_handle;
+    uint32_t                    pan_nap_sdp_handle;
+    uint8_t                     num_conns;
+    uint8_t                     trace_level;
+} tPAN_CB;
+
+/* Global PAN data
+*/
+extern tPAN_CB pan_cb;
+
+/*******************************************************************************/
+extern void pan_register_with_bnep (void);
+extern void pan_conn_ind_cb (uint16_t handle,
+                             BD_ADDR p_bda,
+                             tBT_UUID *remote_uuid,
+                             tBT_UUID *local_uuid,
+                             bool    is_role_change);
+extern void pan_connect_state_cb (uint16_t handle, BD_ADDR rem_bda, tBNEP_RESULT result, bool    is_role_change);
+extern void pan_data_ind_cb (uint16_t handle,
+                             uint8_t *src,
+                             uint8_t *dst,
+                             uint16_t protocol,
+                             uint8_t *p_data,
+                             uint16_t len,
+                             bool    fw_ext_present);
+extern void pan_data_buf_ind_cb (uint16_t handle,
+                                 uint8_t *src,
+                                 uint8_t *dst,
+                                 uint16_t protocol,
+                                 BT_HDR *p_buf,
+                                 bool    ext);
+extern void pan_tx_data_flow_cb (uint16_t handle,
+                            tBNEP_RESULT  event);
+void pan_proto_filt_ind_cb (uint16_t handle,
+                            bool    indication,
+                            tBNEP_RESULT result,
+                            uint16_t num_filters,
+                            uint8_t *p_filters);
+void pan_mcast_filt_ind_cb (uint16_t handle,
+                            bool    indication,
+                            tBNEP_RESULT result,
+                            uint16_t num_filters,
+                            uint8_t *p_filters);
+extern uint32_t pan_register_with_sdp (uint16_t uuid, uint8_t sec_mask,
+                                       const char *p_name, const char *p_desc);
+extern tPAN_CONN *pan_allocate_pcb (BD_ADDR p_bda, uint16_t handle);
+extern tPAN_CONN *pan_get_pcb_by_handle (uint16_t handle);
+extern tPAN_CONN *pan_get_pcb_by_addr (BD_ADDR p_bda);
+extern void pan_close_all_connections (void);
+extern void pan_release_pcb (tPAN_CONN *p_pcb);
+extern void pan_dump_status (void);
+
+/********************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bt/stack/pan/pan_main.cc b/bt/stack/pan/pan_main.cc
new file mode 100644
index 0000000..f2887eb
--- /dev/null
+++ b/bt/stack/pan/pan_main.cc
@@ -0,0 +1,757 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 main functions to support PAN profile
+ *  commands and events.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "bnep_api.h"
+#include "pan_api.h"
+#include "pan_int.h"
+#include "sdp_api.h"
+#include "sdpdefs.h"
+#include "l2c_api.h"
+#include "hcidefs.h"
+#include "osi/include/osi.h"
+
+
+tPAN_CB pan_cb;
+
+#define UUID_CONSTANT_PART  12
+uint8_t constant_pan_uuid[UUID_CONSTANT_PART] = {0, 0, 0x10, 0, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+
+
+/*******************************************************************************
+**
+** Function         pan_register_with_bnep
+**
+** Description      This function registers PAN profile with BNEP
+**
+** Parameters:      none
+**
+** Returns          none
+**
+*******************************************************************************/
+void pan_register_with_bnep (void)
+{
+    tBNEP_REGISTER      reg_info;
+
+    memset (&reg_info, 0, sizeof (tBNEP_REGISTER));
+
+    reg_info.p_conn_ind_cb      = pan_conn_ind_cb;
+    reg_info.p_conn_state_cb    = pan_connect_state_cb;
+    reg_info.p_data_buf_cb      = pan_data_buf_ind_cb;
+    reg_info.p_data_ind_cb      = NULL;
+    reg_info.p_tx_data_flow_cb  = pan_tx_data_flow_cb;
+    reg_info.p_filter_ind_cb    = pan_proto_filt_ind_cb;
+    reg_info.p_mfilter_ind_cb   = pan_mcast_filt_ind_cb;
+
+    BNEP_Register (&reg_info);
+}
+
+
+/*******************************************************************************
+**
+** Function         pan_conn_ind_cb
+**
+** Description      This function is registered with BNEP as connection indication
+**                  callback. BNEP will call this when there is connection
+**                  request from the peer. PAN should call BNEP_ConnectResp to
+**                  indicate whether to accept the connection or reject
+**
+** Parameters:      handle          - handle for the connection
+**                  p_bda           - BD Addr of the peer requesting the connection
+**                  remote_uuid     - UUID of the source role (peer device role)
+**                  local_uuid      - UUID of the destination role (local device role)
+**                  is_role_change  - Flag to indicate that it is a role change
+**
+** Returns          none
+**
+*******************************************************************************/
+void pan_conn_ind_cb (uint16_t handle,
+                      BD_ADDR p_bda,
+                      tBT_UUID *remote_uuid,
+                      tBT_UUID *local_uuid,
+                      bool    is_role_change)
+{
+    tPAN_CONN       *pcb;
+    uint8_t         req_role;
+    bool            wrong_uuid;
+
+    /*
+    ** If we are in GN or NAP role and have one or more
+    ** active connections and the received connection is
+    ** for user role reject it.
+    ** If we are in user role with one connection active
+    ** reject the connection.
+    ** Allocate PCB and store the parameters
+    ** Make bridge request to the host system if connection
+    ** is for NAP
+    */
+    wrong_uuid = false;
+    if (remote_uuid->len == 16)
+    {
+        /*
+        ** If the UUID is 16 bytes forst two bytes should be zeros
+        ** and last 12 bytes should match the spec defined constant value
+        */
+        if (memcmp (constant_pan_uuid, remote_uuid->uu.uuid128 + 4, UUID_CONSTANT_PART))
+            wrong_uuid = true;
+
+        if (remote_uuid->uu.uuid128[0] || remote_uuid->uu.uuid128[1])
+            wrong_uuid = true;
+
+        /* Extract the 16 bit equivalent of the UUID */
+        remote_uuid->uu.uuid16 = (uint16_t)((remote_uuid->uu.uuid128[2] << 8) | remote_uuid->uu.uuid128[3]);
+        remote_uuid->len = 2;
+    }
+    if (remote_uuid->len == 4)
+    {
+        /* First two bytes should be zeros */
+        if (remote_uuid->uu.uuid32 & 0xFFFF0000)
+            wrong_uuid = true;
+
+        remote_uuid->uu.uuid16 = (uint16_t)remote_uuid->uu.uuid32;
+        remote_uuid->len = 2;
+    }
+
+    if (wrong_uuid)
+    {
+        PAN_TRACE_ERROR ("PAN Connection failed because of wrong remote UUID ");
+        BNEP_ConnectResp (handle, BNEP_CONN_FAILED_SRC_UUID);
+        return;
+    }
+
+    wrong_uuid = false;
+    if (local_uuid->len == 16)
+    {
+        /*
+        ** If the UUID is 16 bytes forst two bytes should be zeros
+        ** and last 12 bytes should match the spec defined constant value
+        */
+        if (memcmp (constant_pan_uuid, local_uuid->uu.uuid128 + 4, UUID_CONSTANT_PART))
+            wrong_uuid = true;
+
+        if (local_uuid->uu.uuid128[0] || local_uuid->uu.uuid128[1])
+            wrong_uuid = true;
+
+        /* Extract the 16 bit equivalent of the UUID */
+        local_uuid->uu.uuid16 = (uint16_t)((local_uuid->uu.uuid128[2] << 8) | local_uuid->uu.uuid128[3]);
+        local_uuid->len = 2;
+    }
+    if (local_uuid->len == 4)
+    {
+        /* First two bytes should be zeros */
+        if (local_uuid->uu.uuid32 & 0xFFFF0000)
+            wrong_uuid = true;
+
+        local_uuid->uu.uuid16 = (uint16_t)local_uuid->uu.uuid32;
+        local_uuid->len = 2;
+    }
+
+    if (wrong_uuid)
+    {
+        PAN_TRACE_ERROR ("PAN Connection failed because of wrong local UUID ");
+        BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID);
+        return;
+    }
+
+    PAN_TRACE_EVENT ("pan_conn_ind_cb - for handle %d, current role %d, dst uuid 0x%x, src uuid 0x%x, role change %s",
+        handle, pan_cb.role, local_uuid->uu.uuid16, remote_uuid->uu.uuid16, is_role_change?"YES":"NO");
+    /* The acceptable UUID size is only 2 */
+    if (remote_uuid->len != 2)
+    {
+        PAN_TRACE_ERROR ("PAN Connection failed because of wrong UUID size %d", remote_uuid->len);
+        BNEP_ConnectResp (handle, BNEP_CONN_FAILED_UUID_SIZE);
+        return;
+    }
+
+    /* Check if the source UUID is a valid one */
+    if (remote_uuid->uu.uuid16 != UUID_SERVCLASS_PANU &&
+        remote_uuid->uu.uuid16 != UUID_SERVCLASS_NAP &&
+        remote_uuid->uu.uuid16 != UUID_SERVCLASS_GN)
+    {
+        PAN_TRACE_ERROR ("Src UUID 0x%x is not valid", remote_uuid->uu.uuid16);
+        BNEP_ConnectResp (handle, BNEP_CONN_FAILED_SRC_UUID);
+        return;
+    }
+
+    /* Check if the destination UUID is a valid one */
+    if (local_uuid->uu.uuid16 != UUID_SERVCLASS_PANU &&
+        local_uuid->uu.uuid16 != UUID_SERVCLASS_NAP &&
+        local_uuid->uu.uuid16 != UUID_SERVCLASS_GN)
+    {
+        PAN_TRACE_ERROR ("Dst UUID 0x%x is not valid", remote_uuid->uu.uuid16);
+        BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID);
+        return;
+    }
+
+    /* Check if currently we support the destination role requested */
+    if (((!(pan_cb.role & UUID_SERVCLASS_PANU))
+        && local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU) ||
+        ((!(pan_cb.role & UUID_SERVCLASS_GN))
+        && local_uuid->uu.uuid16 == UUID_SERVCLASS_GN) ||
+        ((!(pan_cb.role & UUID_SERVCLASS_NAP))
+        && local_uuid->uu.uuid16 == UUID_SERVCLASS_NAP))
+    {
+        PAN_TRACE_ERROR ("PAN Connection failed because of unsupported destination UUID 0x%x", local_uuid->uu.uuid16);
+        BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID);
+        return;
+    }
+
+    /* Check for valid interactions between the three PAN profile roles */
+    /*
+     * For reference, see Table 1 in PAN Profile v1.0 spec.
+     * Note: the remote is the initiator.
+     */
+    bool is_valid_interaction = false;
+    switch (remote_uuid->uu.uuid16) {
+    case UUID_SERVCLASS_NAP:
+    case UUID_SERVCLASS_GN:
+        if (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU)
+            is_valid_interaction = true;
+        break;
+    case UUID_SERVCLASS_PANU:
+        is_valid_interaction = true;
+        break;
+    }
+    /*
+     * Explicitly disable connections to the local PANU if the remote is
+     * not PANU.
+     */
+    if ((local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU) &&
+        (remote_uuid->uu.uuid16 != UUID_SERVCLASS_PANU)) {
+        is_valid_interaction = false;
+    }
+    if (!is_valid_interaction) {
+        PAN_TRACE_ERROR(
+                "PAN Connection failed because of invalid PAN profile roles "
+                "interaction: Remote UUID 0x%x Local UUID 0x%x",
+                remote_uuid->uu.uuid16, local_uuid->uu.uuid16);
+        BNEP_ConnectResp(handle, BNEP_CONN_FAILED_SRC_UUID);
+        return;
+    }
+
+    /* Requested destination role is */
+    if (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU)
+        req_role = PAN_ROLE_CLIENT;
+    else if (local_uuid->uu.uuid16 == UUID_SERVCLASS_GN)
+        req_role = PAN_ROLE_GN_SERVER;
+    else
+        req_role = PAN_ROLE_NAP_SERVER;
+
+    /* If the connection indication is for the existing connection
+    ** Check if the new destination role is acceptable
+    */
+    pcb = pan_get_pcb_by_handle (handle);
+    if (pcb)
+    {
+        if (pan_cb.num_conns > 1 && local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU)
+        {
+            /* There are connections other than this one
+            ** so we cann't accept PANU role. Reject
+            */
+            PAN_TRACE_ERROR ("Dst UUID should be either GN or NAP only because there are other connections");
+            BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID);
+            return;
+        }
+
+        /* If it is already in connected state check for bridging status */
+        if (pcb->con_state == PAN_STATE_CONNECTED)
+        {
+            PAN_TRACE_EVENT ("PAN Role changing New Src 0x%x Dst 0x%x",
+                remote_uuid->uu.uuid16, local_uuid->uu.uuid16);
+
+            pcb->prv_src_uuid = pcb->src_uuid;
+            pcb->prv_dst_uuid = pcb->dst_uuid;
+
+            if (pcb->src_uuid == UUID_SERVCLASS_NAP &&
+                local_uuid->uu.uuid16 != UUID_SERVCLASS_NAP)
+            {
+                /* Remove bridging */
+                if (pan_cb.pan_bridge_req_cb)
+                    (*pan_cb.pan_bridge_req_cb) (pcb->rem_bda, false);
+            }
+        }
+        /* Set the latest active PAN role */
+        pan_cb.active_role = req_role;
+        pcb->src_uuid = local_uuid->uu.uuid16;
+        pcb->dst_uuid = remote_uuid->uu.uuid16;
+        BNEP_ConnectResp (handle, BNEP_SUCCESS);
+        return;
+    }
+    else
+    {
+        /* If this a new connection and destination is PANU role and
+        ** we already have a connection then reject the request.
+        ** If we have a connection in PANU role then reject it
+        */
+        if (pan_cb.num_conns &&
+            (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU ||
+            pan_cb.active_role == PAN_ROLE_CLIENT))
+        {
+            PAN_TRACE_ERROR ("PAN already have a connection and can't be user");
+            BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID);
+            return;
+        }
+    }
+
+    /* This is a new connection */
+    PAN_TRACE_DEBUG ("New connection indication for handle %d", handle);
+    pcb = pan_allocate_pcb (p_bda, handle);
+    if (!pcb)
+    {
+        PAN_TRACE_ERROR ("PAN no control block for new connection");
+        BNEP_ConnectResp (handle, BNEP_CONN_FAILED);
+        return;
+    }
+
+    PAN_TRACE_EVENT ("PAN connection destination UUID is 0x%x", local_uuid->uu.uuid16);
+    /* Set the latest active PAN role */
+    pan_cb.active_role = req_role;
+    pcb->src_uuid = local_uuid->uu.uuid16;
+    pcb->dst_uuid = remote_uuid->uu.uuid16;
+    pcb->con_state = PAN_STATE_CONN_START;
+    pan_cb.num_conns++;
+
+    BNEP_ConnectResp (handle, BNEP_SUCCESS);
+    return;
+}
+
+
+/*******************************************************************************
+**
+** Function         pan_connect_state_cb
+**
+** Description      This function is registered with BNEP as connection state
+**                  change callback. BNEP will call this when the connection
+**                  is established successfully or terminated
+**
+** Parameters:      handle      - handle for the connection given in the connection
+**                                      indication callback
+**                  rem_bda     - remote device bd addr
+**                  result      - indicates whether the connection is up or down
+**                                      BNEP_SUCCESS if the connection is up
+**                                      all other values indicates appropriate errors
+**                  is_role_change - flag to indicate that it is a role change
+**
+** Returns          none
+**
+*******************************************************************************/
+void pan_connect_state_cb (uint16_t handle,
+                           UNUSED_ATTR BD_ADDR rem_bda, tBNEP_RESULT result,
+                           bool    is_role_change)
+{
+    tPAN_CONN       *pcb;
+    uint8_t          peer_role;
+
+    PAN_TRACE_EVENT ("pan_connect_state_cb - for handle %d, result %d", handle, result);
+    pcb = pan_get_pcb_by_handle (handle);
+    if (!pcb)
+    {
+        PAN_TRACE_ERROR ("PAN State change indication for wrong handle %d", handle);
+        return;
+    }
+
+    /* If the connection is getting terminated remove bridging */
+    if (result != BNEP_SUCCESS)
+    {
+        /* Inform the application that connection is down */
+        if (pan_cb.pan_conn_state_cb)
+            (*pan_cb.pan_conn_state_cb) (pcb->handle, pcb->rem_bda, result, is_role_change, PAN_ROLE_INACTIVE, PAN_ROLE_INACTIVE);
+
+        /* Check if this failure is for role change only */
+        if (pcb->con_state != PAN_STATE_CONNECTED &&
+            (pcb->con_flags & PAN_FLAGS_CONN_COMPLETED))
+        {
+            /* restore the original values */
+            PAN_TRACE_EVENT ("restoring the connection state to active");
+            pcb->con_state = PAN_STATE_CONNECTED;
+            pcb->con_flags &= (~PAN_FLAGS_CONN_COMPLETED);
+
+            pcb->src_uuid = pcb->prv_src_uuid;
+            pcb->dst_uuid = pcb->prv_dst_uuid;
+            pan_cb.active_role = pan_cb.prv_active_role;
+
+            if ((pcb->src_uuid == UUID_SERVCLASS_NAP) && pan_cb.pan_bridge_req_cb)
+                (*pan_cb.pan_bridge_req_cb) (pcb->rem_bda, true);
+
+            return;
+        }
+
+        if (pcb->con_state == PAN_STATE_CONNECTED)
+        {
+            /* If the connections destination role is NAP remove bridging */
+            if ((pcb->src_uuid == UUID_SERVCLASS_NAP) && pan_cb.pan_bridge_req_cb)
+                (*pan_cb.pan_bridge_req_cb) (pcb->rem_bda, false);
+        }
+
+        pan_cb.num_conns--;
+        pan_release_pcb (pcb);
+        return;
+    }
+
+    /* Requested destination role is */
+    if (pcb->src_uuid == UUID_SERVCLASS_PANU)
+        pan_cb.active_role = PAN_ROLE_CLIENT;
+    else if (pcb->src_uuid == UUID_SERVCLASS_GN)
+        pan_cb.active_role = PAN_ROLE_GN_SERVER;
+    else
+        pan_cb.active_role = PAN_ROLE_NAP_SERVER;
+
+    if (pcb->dst_uuid == UUID_SERVCLASS_PANU)
+        peer_role = PAN_ROLE_CLIENT;
+    else if (pcb->dst_uuid == UUID_SERVCLASS_GN)
+        peer_role = PAN_ROLE_GN_SERVER;
+    else
+        peer_role = PAN_ROLE_NAP_SERVER;
+
+    pcb->con_state = PAN_STATE_CONNECTED;
+
+    /* Inform the application that connection is down */
+    if (pan_cb.pan_conn_state_cb)
+        (*pan_cb.pan_conn_state_cb) (pcb->handle, pcb->rem_bda, PAN_SUCCESS, is_role_change, pan_cb.active_role, peer_role);
+
+    /* Create bridge if the destination role is NAP */
+    if (pan_cb.pan_bridge_req_cb && pcb->src_uuid == UUID_SERVCLASS_NAP)
+    {
+        PAN_TRACE_EVENT ("PAN requesting for bridge");
+        (*pan_cb.pan_bridge_req_cb) (pcb->rem_bda, true);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         pan_data_ind_cb
+**
+** Description      This function is registered with BNEP as data indication
+**                  callback. BNEP will call this when the peer sends any data
+**                  on this connection
+**
+** Parameters:      handle      - handle for the connection
+**                  src         - source BD Addr
+**                  dst         - destination BD Addr
+**                  protocol    - Network protocol of the Eth packet
+**                  p_data      - pointer to the data
+**                  len         - length of the data
+**                  fw_ext_present - to indicate whether the data contains any
+**                                         extension headers before the payload
+**
+** Returns          none
+**
+*******************************************************************************/
+void pan_data_ind_cb (uint16_t handle,
+                      uint8_t *src,
+                      uint8_t *dst,
+                      uint16_t protocol,
+                      uint8_t *p_data,
+                      uint16_t len,
+                      bool    ext)
+{
+    tPAN_CONN       *pcb;
+    uint16_t        i;
+    bool            forward;
+
+    /*
+    ** Check the connection status
+    ** If the destination address is MAC broadcast send on all links
+    ** except on the one received
+    ** If the destination uuid is for NAP send to host system also
+    ** If the destination address is one of the devices connected
+    ** send the packet to over that link
+    ** If the destination address is unknown and destination uuid is NAP
+    ** send it to the host system
+    */
+
+    PAN_TRACE_EVENT ("pan_data_ind_cb - for handle %d", handle);
+    pcb = pan_get_pcb_by_handle (handle);
+    if (!pcb)
+    {
+        PAN_TRACE_ERROR ("PAN Data indication for wrong handle %d", handle);
+        return;
+    }
+
+    if (pcb->con_state != PAN_STATE_CONNECTED)
+    {
+        PAN_TRACE_ERROR ("PAN Data indication in wrong state %d for handle %d",
+            pcb->con_state, handle);
+        return;
+    }
+
+    /* Check if it is broadcast packet */
+    if (dst[0] & 0x01)
+    {
+        PAN_TRACE_DEBUG ("PAN received broadcast packet on handle %d, src uuid 0x%x",
+            handle, pcb->src_uuid);
+        for (i=0; i<MAX_PAN_CONNS; i++)
+        {
+            if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED &&
+                pan_cb.pcb[i].handle != handle &&
+                pcb->src_uuid == pan_cb.pcb[i].src_uuid)
+            {
+                BNEP_Write (pan_cb.pcb[i].handle, dst, p_data, len, protocol, src, ext);
+            }
+        }
+
+        if (pan_cb.pan_data_ind_cb)
+            (*pan_cb.pan_data_ind_cb) (pcb->handle, src, dst, protocol, p_data, len, ext, true);
+
+        return;
+    }
+
+    /* Check if it is for any other PAN connection */
+    for (i=0; i<MAX_PAN_CONNS; i++)
+    {
+        if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED &&
+            pcb->src_uuid == pan_cb.pcb[i].src_uuid)
+        {
+            if (memcmp (pan_cb.pcb[i].rem_bda, dst, BD_ADDR_LEN) == 0)
+            {
+                BNEP_Write (pan_cb.pcb[i].handle, dst, p_data, len, protocol, src, ext);
+                return;
+            }
+        }
+    }
+
+   if (pcb->src_uuid == UUID_SERVCLASS_NAP)
+       forward = true;
+   else
+       forward = false;
+
+    /* Send it over the LAN or give it to host software */
+    if (pan_cb.pan_data_ind_cb)
+        (*pan_cb.pan_data_ind_cb) (pcb->handle, src, dst, protocol, p_data, len, ext, forward);
+
+    return;
+}
+
+
+/*******************************************************************************
+**
+** Function         pan_data_buf_ind_cb
+**
+** Description      This function is registered with BNEP as data buffer indication
+**                  callback. BNEP will call this when the peer sends any data
+**                  on this connection. PAN is responsible to release the buffer
+**
+** Parameters:      handle      - handle for the connection
+**                  src         - source BD Addr
+**                  dst         - destination BD Addr
+**                  protocol    - Network protocol of the Eth packet
+**                  p_buf       - pointer to the data buffer
+**                  ext         - to indicate whether the data contains any
+**                                         extension headers before the payload
+**
+** Returns          none
+**
+*******************************************************************************/
+void pan_data_buf_ind_cb (uint16_t handle,
+                          uint8_t *src,
+                          uint8_t *dst,
+                          uint16_t protocol,
+                          BT_HDR *p_buf,
+                          bool    ext)
+{
+    tPAN_CONN       *pcb, *dst_pcb;
+    tBNEP_RESULT    result;
+    uint16_t        i, len;
+    uint8_t         *p_data;
+    bool            forward = false;
+
+    /* Check if the connection is in right state */
+    pcb = pan_get_pcb_by_handle (handle);
+    if (!pcb)
+    {
+        PAN_TRACE_ERROR ("PAN Data buffer indication for wrong handle %d", handle);
+        osi_free(p_buf);
+        return;
+    }
+
+    if (pcb->con_state != PAN_STATE_CONNECTED)
+    {
+        PAN_TRACE_ERROR ("PAN Data indication in wrong state %d for handle %d",
+            pcb->con_state, handle);
+        osi_free(p_buf);
+        return;
+    }
+
+    p_data = (uint8_t *)(p_buf + 1) + p_buf->offset;
+    len    = p_buf->len;
+
+    PAN_TRACE_EVENT ("pan_data_buf_ind_cb - for handle %d, protocol 0x%x, length %d, ext %d",
+        handle, protocol, len, ext);
+
+   if (pcb->src_uuid == UUID_SERVCLASS_NAP)
+       forward = true;
+   else
+       forward = false;
+
+    /* Check if it is broadcast or multicast packet */
+    if (pcb->src_uuid != UUID_SERVCLASS_PANU)
+    {
+        if (dst[0] & 0x01)
+        {
+            PAN_TRACE_DEBUG ("PAN received broadcast packet on handle %d, src uuid 0x%x",
+                handle, pcb->src_uuid);
+            for (i=0; i<MAX_PAN_CONNS; i++)
+            {
+                if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED &&
+                    pan_cb.pcb[i].handle != handle &&
+                    pcb->src_uuid == pan_cb.pcb[i].src_uuid)
+                {
+                    BNEP_Write (pan_cb.pcb[i].handle, dst, p_data, len, protocol, src, ext);
+                }
+            }
+
+            if (pan_cb.pan_data_buf_ind_cb)
+                (*pan_cb.pan_data_buf_ind_cb) (pcb->handle, src, dst, protocol, p_buf, ext, forward);
+            else if (pan_cb.pan_data_ind_cb)
+            {
+                (*pan_cb.pan_data_ind_cb) (pcb->handle, src, dst, protocol, p_data, len, ext, forward);
+                osi_free(p_buf);
+            }
+
+            return;
+        }
+
+        /* Check if it is for any other PAN connection */
+        dst_pcb = pan_get_pcb_by_addr (dst);
+        if (dst_pcb)
+        {
+            PAN_TRACE_EVENT ("%s - destination PANU found on handle %d and sending data, len: %d",
+                __func__, dst_pcb->handle, len);
+
+            result = BNEP_Write (dst_pcb->handle, dst, p_data, len, protocol, src, ext);
+            if (result != BNEP_SUCCESS && result != BNEP_IGNORE_CMD)
+                PAN_TRACE_ERROR ("Failed to write data for PAN connection handle %d", dst_pcb->handle);
+            osi_free(p_buf);
+            return;
+        }
+    }
+
+    /* Send it over the LAN or give it to host software */
+    if (pan_cb.pan_data_buf_ind_cb)
+        (*pan_cb.pan_data_buf_ind_cb) (pcb->handle, src, dst, protocol, p_buf, ext, forward);
+    else if (pan_cb.pan_data_ind_cb)
+    {
+        (*pan_cb.pan_data_ind_cb) (pcb->handle, src, dst, protocol, p_data, len, ext, forward);
+        osi_free(p_buf);
+    }
+    else
+        osi_free(p_buf);
+
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         pan_proto_filt_ind_cb
+**
+** Description      This function is registered with BNEP to receive tx data
+**					flow status
+**
+** Parameters:      handle      - handle for the connection
+**					event       - flow status
+**
+** Returns          none
+**
+*******************************************************************************/
+void pan_tx_data_flow_cb (uint16_t handle,
+                            tBNEP_RESULT  event)
+{
+
+    if (pan_cb.pan_tx_data_flow_cb)
+        (*pan_cb.pan_tx_data_flow_cb) (handle, event);
+
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         pan_proto_filt_ind_cb
+**
+** Description      This function is registered with BNEP as proto filter indication
+**                  callback. BNEP will call this when the peer sends any protocol
+**                  filter set for the connection or to indicate the result of the
+**                  protocol filter set by the local device
+**
+** Parameters:      handle      - handle for the connection
+**                  indication  - true if this is indication
+**                                false if it is called to give the result of local
+**                                      device protocol filter set
+**                  result      - This gives the result of the filter set operation
+**                  num_filters - number of filters set by the peer device
+**                  p_filters   - pointer to the filters set by the peer device
+**
+** Returns          none
+**
+*******************************************************************************/
+void pan_proto_filt_ind_cb (uint16_t handle,
+                            bool    indication,
+                            tBNEP_RESULT result,
+                            uint16_t num_filters,
+                            uint8_t *p_filters)
+{
+    PAN_TRACE_EVENT ("pan_proto_filt_ind_cb - called for handle %d with ind %d, result %d, num %d",
+                            handle, indication, result, num_filters);
+
+    if (pan_cb.pan_pfilt_ind_cb)
+        (*pan_cb.pan_pfilt_ind_cb) (handle, indication, result, num_filters, p_filters);
+}
+
+
+/*******************************************************************************
+**
+** Function         pan_mcast_filt_ind_cb
+**
+** Description      This function is registered with BNEP as mcast filter indication
+**                  callback. BNEP will call this when the peer sends any multicast
+**                  filter set for the connection or to indicate the result of the
+**                  multicast filter set by the local device
+**
+** Parameters:      handle      - handle for the connection
+**                  indication  - true if this is indication
+**                                false if it is called to give the result of local
+**                                      device multicast filter set
+**                  result      - This gives the result of the filter set operation
+**                  num_filters - number of filters set by the peer device
+**                  p_filters   - pointer to the filters set by the peer device
+**
+** Returns          none
+**
+*******************************************************************************/
+void pan_mcast_filt_ind_cb (uint16_t handle,
+                            bool    indication,
+                            tBNEP_RESULT result,
+                            uint16_t num_filters,
+                            uint8_t *p_filters)
+{
+    PAN_TRACE_EVENT ("pan_mcast_filt_ind_cb - called for handle %d with ind %d, result %d, num %d",
+                            handle, indication, result, num_filters);
+
+    if (pan_cb.pan_mfilt_ind_cb)
+        (*pan_cb.pan_mfilt_ind_cb) (handle, indication, result, num_filters, p_filters);
+}
diff --git a/bt/stack/pan/pan_utils.cc b/bt/stack/pan/pan_utils.cc
new file mode 100644
index 0000000..3a5d030
--- /dev/null
+++ b/bt/stack/pan/pan_utils.cc
@@ -0,0 +1,345 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 main functions to support PAN profile
+ *  commands and events.
+ *
+ *****************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include "bt_common.h"
+#include "bnep_api.h"
+#include "pan_api.h"
+#include "pan_int.h"
+#include "sdp_api.h"
+#include "sdpdefs.h"
+#include "l2c_api.h"
+#include "hcidefs.h"
+#include "btm_api.h"
+
+
+static const uint8_t pan_proto_elem_data[]   = {
+                                   0x35, 0x18,          /* data element sequence of length 0x18 bytes */
+                                   0x35, 0x06,          /* data element sequence for L2CAP descriptor */
+                                   0x19, 0x01, 0x00,    /* UUID for L2CAP - 0x0100 */
+                                   0x09, 0x00, 0x0F,    /* PSM for BNEP - 0x000F */
+                                   0x35, 0x0E,          /* data element seqence for BNEP descriptor */
+                                   0x19, 0x00, 0x0F,    /* UUID for BNEP - 0x000F */
+                                   0x09, 0x01, 0x00,    /* BNEP specific parameter 0 -- Version of BNEP = version 1 = 0x0001 */
+                                   0x35, 0x06,          /* BNEP specific parameter 1 -- Supported network packet type list */
+                                   0x09, 0x08, 0x00,    /* network packet type IPv4 = 0x0800 */
+                                   0x09, 0x08, 0x06     /* network packet type ARP  = 0x0806 */
+};
+
+/*******************************************************************************
+**
+** Function         pan_register_with_sdp
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+uint32_t pan_register_with_sdp (uint16_t uuid, uint8_t sec_mask,
+                                const char *p_name, const char *p_desc)
+{
+    uint32_t sdp_handle;
+    uint16_t browse_list = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+    uint16_t security = 0;
+    uint32_t proto_len = (uint32_t )pan_proto_elem_data[1];
+
+    /* Create a record */
+    sdp_handle = SDP_CreateRecord ();
+
+    if (sdp_handle == 0)
+    {
+        PAN_TRACE_ERROR ("PAN_SetRole - could not create SDP record");
+        return 0;
+    }
+
+    /* Service Class ID List */
+    SDP_AddServiceClassIdList (sdp_handle, 1, &uuid);
+
+    /* Add protocol element sequence from the constant string */
+    SDP_AddAttribute (sdp_handle, ATTR_ID_PROTOCOL_DESC_LIST, DATA_ELE_SEQ_DESC_TYPE,
+                      proto_len, (uint8_t *)(pan_proto_elem_data+2));
+
+    /* Language base */
+    SDP_AddLanguageBaseAttrIDList (sdp_handle, LANG_ID_CODE_ENGLISH, LANG_ID_CHAR_ENCODE_UTF8, LANGUAGE_BASE_ID);
+
+    /* Profile descriptor list */
+    SDP_AddProfileDescriptorList (sdp_handle, uuid, PAN_PROFILE_VERSION);
+
+    /* Service Name */
+    SDP_AddAttribute (sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+                        (uint8_t) (strlen(p_name) + 1), (uint8_t *)p_name);
+
+    /* Service description */
+    SDP_AddAttribute (sdp_handle, ATTR_ID_SERVICE_DESCRIPTION, TEXT_STR_DESC_TYPE,
+                        (uint8_t) (strlen(p_desc) + 1), (uint8_t *)p_desc);
+
+    /* Security description */
+    if (sec_mask)
+    {
+        UINT16_TO_BE_FIELD(&security, 0x0001);
+    }
+    SDP_AddAttribute (sdp_handle, ATTR_ID_SECURITY_DESCRIPTION, UINT_DESC_TYPE, 2, (uint8_t *)&security);
+
+#if (PAN_SUPPORTS_ROLE_NAP == TRUE)
+    if (uuid == UUID_SERVCLASS_NAP)
+    {
+        uint16_t NetAccessType = 0x0005;      /* Ethernet */
+        uint32_t NetAccessRate = 0x0001312D0; /* 10Mb/sec */
+        uint8_t array[10], *p;
+
+        /* Net access type. */
+        p = array;
+        UINT16_TO_BE_STREAM (p, NetAccessType);
+        SDP_AddAttribute (sdp_handle, ATTR_ID_NET_ACCESS_TYPE, UINT_DESC_TYPE, 2, array);
+
+        /* Net access rate. */
+        p = array;
+        UINT32_TO_BE_STREAM (p, NetAccessRate);
+        SDP_AddAttribute (sdp_handle, ATTR_ID_MAX_NET_ACCESS_RATE, UINT_DESC_TYPE, 4, array);
+
+        /* Register with Security Manager for the specific security level */
+        if ((!BTM_SetSecurityLevel (true, p_name, BTM_SEC_SERVICE_BNEP_NAP,
+                                    sec_mask, BT_PSM_BNEP, BTM_SEC_PROTO_BNEP, UUID_SERVCLASS_NAP))
+         || (!BTM_SetSecurityLevel (false, p_name, BTM_SEC_SERVICE_BNEP_NAP,
+                                    sec_mask, BT_PSM_BNEP, BTM_SEC_PROTO_BNEP, UUID_SERVCLASS_NAP)))
+        {
+            PAN_TRACE_ERROR ("PAN Security Registration failed for PANU");
+        }
+    }
+#endif
+#if (PAN_SUPPORTS_ROLE_GN == TRUE)
+    if (uuid == UUID_SERVCLASS_GN)
+    {
+        if ((!BTM_SetSecurityLevel (true, p_name, BTM_SEC_SERVICE_BNEP_GN,
+                                    sec_mask, BT_PSM_BNEP, BTM_SEC_PROTO_BNEP, UUID_SERVCLASS_GN))
+         || (!BTM_SetSecurityLevel (false, p_name, BTM_SEC_SERVICE_BNEP_GN,
+                                    sec_mask, BT_PSM_BNEP, BTM_SEC_PROTO_BNEP, UUID_SERVCLASS_GN)))
+        {
+            PAN_TRACE_ERROR ("PAN Security Registration failed for GN");
+        }
+    }
+#endif
+#if (PAN_SUPPORTS_ROLE_PANU == TRUE)
+    if (uuid == UUID_SERVCLASS_PANU)
+    {
+        if ((!BTM_SetSecurityLevel (true, p_name, BTM_SEC_SERVICE_BNEP_PANU,
+                                    sec_mask, BT_PSM_BNEP, BTM_SEC_PROTO_BNEP, UUID_SERVCLASS_PANU))
+         || (!BTM_SetSecurityLevel (false, p_name, BTM_SEC_SERVICE_BNEP_PANU,
+                                    sec_mask, BT_PSM_BNEP, BTM_SEC_PROTO_BNEP, UUID_SERVCLASS_PANU)))
+        {
+            PAN_TRACE_ERROR ("PAN Security Registration failed for PANU");
+        }
+    }
+#endif
+
+    /* Make the service browsable */
+    SDP_AddUuidSequence (sdp_handle,  ATTR_ID_BROWSE_GROUP_LIST, 1, &browse_list);
+
+
+    return sdp_handle;
+}
+
+
+
+/*******************************************************************************
+**
+** Function         pan_allocate_pcb
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+tPAN_CONN *pan_allocate_pcb (BD_ADDR p_bda, uint16_t handle)
+{
+    uint16_t    i;
+
+    for (i=0; i<MAX_PAN_CONNS; i++)
+    {
+        if (pan_cb.pcb[i].con_state != PAN_STATE_IDLE &&
+            pan_cb.pcb[i].handle == handle)
+            return NULL;
+    }
+
+    for (i=0; i<MAX_PAN_CONNS; i++)
+    {
+        if (pan_cb.pcb[i].con_state != PAN_STATE_IDLE &&
+            memcmp (pan_cb.pcb[i].rem_bda, p_bda, BD_ADDR_LEN) == 0)
+            return NULL;
+    }
+
+    for (i=0; i<MAX_PAN_CONNS; i++)
+    {
+        if (pan_cb.pcb[i].con_state == PAN_STATE_IDLE)
+        {
+            memset (&(pan_cb.pcb[i]), 0, sizeof (tPAN_CONN));
+            memcpy (pan_cb.pcb[i].rem_bda, p_bda, BD_ADDR_LEN);
+            pan_cb.pcb[i].handle = handle;
+            return &(pan_cb.pcb[i]);
+        }
+    }
+    return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function         pan_get_pcb_by_handle
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+tPAN_CONN *pan_get_pcb_by_handle (uint16_t handle)
+{
+    uint16_t    i;
+
+    for (i=0; i<MAX_PAN_CONNS; i++)
+    {
+        if (pan_cb.pcb[i].con_state != PAN_STATE_IDLE &&
+            pan_cb.pcb[i].handle == handle)
+            return &(pan_cb.pcb[i]);
+    }
+
+    return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function         pan_get_pcb_by_addr
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+tPAN_CONN *pan_get_pcb_by_addr (BD_ADDR p_bda)
+{
+    uint16_t    i;
+
+    for (i=0; i<MAX_PAN_CONNS; i++)
+    {
+        if (pan_cb.pcb[i].con_state == PAN_STATE_IDLE)
+            continue;
+
+        if (memcmp (pan_cb.pcb[i].rem_bda, p_bda, BD_ADDR_LEN) == 0)
+            return &(pan_cb.pcb[i]);
+
+        /*
+        if (pan_cb.pcb[i].mfilter_present &&
+            (memcmp (p_bda, pan_cb.pcb[i].multi_cast_bridge, BD_ADDR_LEN) == 0))
+            return &(pan_cb.pcb[i]);
+        */
+    }
+
+    return NULL;
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function         pan_close_all_connections
+**
+** Description
+**
+** Returns          void
+**
+*******************************************************************************/
+void pan_close_all_connections (void)
+{
+    uint16_t    i;
+
+    for (i=0; i<MAX_PAN_CONNS; i++)
+    {
+        if (pan_cb.pcb[i].con_state != PAN_STATE_IDLE)
+        {
+            BNEP_Disconnect (pan_cb.pcb[i].handle);
+            pan_cb.pcb[i].con_state = PAN_STATE_IDLE;
+        }
+    }
+
+    pan_cb.active_role = PAN_ROLE_INACTIVE;
+    pan_cb.num_conns   = 0;
+    return;
+}
+
+
+/*******************************************************************************
+**
+** Function         pan_release_pcb
+**
+** Description      This function releases a PCB.
+**
+** Returns          void
+**
+*******************************************************************************/
+void pan_release_pcb (tPAN_CONN *p_pcb)
+{
+    /* Drop any response pointer we may be holding */
+    memset (p_pcb, 0, sizeof (tPAN_CONN));
+    p_pcb->con_state = PAN_STATE_IDLE;
+}
+
+
+/*******************************************************************************
+**
+** Function         pan_dump_status
+**
+** Description      This function dumps the pan control block and connection
+**                  blocks information
+**
+** Returns          none
+**
+*******************************************************************************/
+void pan_dump_status (void)
+{
+#if (PAN_SUPPORTS_DEBUG_DUMP == TRUE)
+    uint16_t        i;
+    char            buff[200];
+    tPAN_CONN      *p_pcb;
+
+    PAN_TRACE_DEBUG ("PAN role %x, active role %d, num_conns %d",
+        pan_cb.role, pan_cb.active_role, pan_cb.num_conns);
+
+    for (i = 0, p_pcb = pan_cb.pcb; i < MAX_PAN_CONNS; i++, p_pcb++)
+    {
+        snprintf (buff, sizeof(buff),
+            "%d state %d, handle %d, src 0x%x, dst 0x%x, BD %x.%x.%x.%x.%x.%x",
+            i, p_pcb->con_state, p_pcb->handle, p_pcb->src_uuid, p_pcb->dst_uuid,
+            p_pcb->rem_bda[0], p_pcb->rem_bda[1], p_pcb->rem_bda[2],
+            p_pcb->rem_bda[3], p_pcb->rem_bda[4], p_pcb->rem_bda[5]);
+
+        PAN_TRACE_DEBUG (buff);
+    }
+#endif
+}
+
+
+
diff --git a/bt/stack/rfcomm/port_api.cc b/bt/stack/rfcomm/port_api.cc
new file mode 100644
index 0000000..83b0ab7
--- /dev/null
+++ b/bt/stack/rfcomm/port_api.cc
@@ -0,0 +1,1869 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 Serial Port API code
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_port_api"
+
+#include <string.h>
+
+#include "osi/include/log.h"
+#include "osi/include/mutex.h"
+
+#include "btm_api.h"
+#include "btm_int.h"
+#include "bt_common.h"
+#include "l2c_api.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+#include "rfcdefs.h"
+#include "sdp_api.h"
+
+/* duration of break in 200ms units */
+#define PORT_BREAK_DURATION     1
+
+#define info(fmt, ...)  LOG_INFO(LOG_TAG, "%s: " fmt,__func__,  ## __VA_ARGS__)
+#define debug(fmt, ...) LOG_DEBUG(LOG_TAG, "%s: " fmt,__func__,  ## __VA_ARGS__)
+#define error(fmt, ...) LOG_ERROR(LOG_TAG, "## ERROR : %s: " fmt "##",__func__,  ## __VA_ARGS__)
+#define asrt(s) if(!(s)) LOG_ERROR(LOG_TAG, "## %s assert %s failed at line:%d ##",__func__, #s, __LINE__)
+
+/* Mapping from PORT_* result codes to human readable strings. */
+static const char *result_code_strings[] = {
+  "Success",
+  "Unknown error",
+  "Already opened",
+  "Command pending",
+  "App not registered",
+  "No memory",
+  "No resources",
+  "Bad BD address",
+  "Unspecified error",
+  "Bad handle",
+  "Not opened",
+  "Line error",
+  "Start failed",
+  "Parameter negotiation failed",
+  "Port negotiation failed",
+  "Sec failed",
+  "Peer connection failed",
+  "Peer failed",
+  "Peer timeout",
+  "Closed",
+  "TX full",
+  "Local closed",
+  "Local timeout",
+  "TX queue disabled",
+  "Page timeout",
+  "Invalid SCN",
+  "Unknown result code"
+};
+
+/*******************************************************************************
+**
+** Function         RFCOMM_CreateConnection
+**
+** Description      RFCOMM_CreateConnection function is used from the application
+**                  to establish serial port connection to the peer device,
+**                  or allow RFCOMM to accept a connection from the peer
+**                  application.
+**
+** Parameters:      scn          - Service Channel Number as registered with
+**                                 the SDP (server) or obtained using SDP from
+**                                 the peer device (client).
+**                  is_server    - true if requesting application is a server
+**                  mtu          - Maximum frame size the application can accept
+**                  bd_addr      - BD_ADDR of the peer (client)
+**                  mask         - specifies events to be enabled.  A value
+**                                 of zero disables all events.
+**                  p_handle     - OUT pointer to the handle.
+**                  p_mgmt_cb    - pointer to callback function to receive
+**                                 connection up/down events.
+** Notes:
+**
+** Server can call this function with the same scn parameter multiple times if
+** it is ready to accept multiple simulteneous connections.
+**
+** DLCI for the connection is (scn * 2 + 1) if client originates connection on
+** existing none initiator multiplexer channel.  Otherwise it is (scn * 2).
+** For the server DLCI can be changed later if client will be calling it using
+** (scn * 2 + 1) dlci.
+**
+*******************************************************************************/
+int RFCOMM_CreateConnection (uint16_t uuid, uint8_t scn, bool    is_server,
+                             uint16_t mtu, BD_ADDR bd_addr, uint16_t *p_handle,
+                             tPORT_CALLBACK *p_mgmt_cb)
+{
+    tPORT      *p_port;
+    int        i;
+    uint8_t    dlci;
+    tRFC_MCB   *p_mcb = port_find_mcb (bd_addr);
+    uint16_t   rfcomm_mtu;
+
+
+    RFCOMM_TRACE_API ("RFCOMM_CreateConnection()  BDA: %02x-%02x-%02x-%02x-%02x-%02x",
+                       bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+
+    *p_handle = 0;
+
+    if (( scn == 0 )||(scn >= PORT_MAX_RFC_PORTS ))
+    {
+        /* Server Channel Number(SCN) should be in range 1...30 */
+        RFCOMM_TRACE_ERROR ("RFCOMM_CreateConnection - invalid SCN");
+        return (PORT_INVALID_SCN);
+    }
+
+    /* For client that originate connection on the existing none initiator */
+    /* multiplexer channel DLCI should be odd */
+    if (p_mcb && !p_mcb->is_initiator && !is_server)
+        dlci = (scn << 1) + 1;
+    else
+        dlci = (scn << 1);
+    RFCOMM_TRACE_API("RFCOMM_CreateConnection(): scn:%d, dlci:%d, is_server:%d mtu:%d, p_mcb:%p",
+                       scn, dlci, is_server, mtu, p_mcb);
+
+    /* For the server side always allocate a new port.  On the client side */
+    /* do not allow the same (dlci, bd_addr) to be opened twice by application */
+    if (!is_server && ((p_port = port_find_port (dlci, bd_addr)) != NULL))
+    {
+        /* if existing port is also a client port */
+        if (p_port->is_server == false)
+        {
+            RFCOMM_TRACE_ERROR ("RFCOMM_CreateConnection - already opened state:%d, RFC state:%d, MCB state:%d",
+                p_port->state, p_port->rfc.state, p_port->rfc.p_mcb ? p_port->rfc.p_mcb->state : 0);
+            *p_handle = p_port->inx;
+            return (PORT_ALREADY_OPENED);
+        }
+    }
+
+    if ((p_port = port_allocate_port (dlci, bd_addr)) == NULL)
+    {
+        RFCOMM_TRACE_WARNING ("RFCOMM_CreateConnection - no resources");
+        return (PORT_NO_RESOURCES);
+    }
+   RFCOMM_TRACE_API("RFCOMM_CreateConnection(): scn:%d, dlci:%d, is_server:%d mtu:%d, p_mcb:%p, p_port:%p",
+                       scn, dlci, is_server, mtu, p_mcb, p_port);
+
+    p_port->default_signal_state = (PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON);
+
+    switch (uuid)
+    {
+    case UUID_PROTOCOL_OBEX:
+        p_port->default_signal_state = PORT_OBEX_DEFAULT_SIGNAL_STATE;
+        break;
+    case UUID_SERVCLASS_SERIAL_PORT:
+        p_port->default_signal_state = PORT_SPP_DEFAULT_SIGNAL_STATE;
+        break;
+    case UUID_SERVCLASS_LAN_ACCESS_USING_PPP:
+        p_port->default_signal_state = PORT_PPP_DEFAULT_SIGNAL_STATE;
+        break;
+    case UUID_SERVCLASS_DIALUP_NETWORKING:
+    case UUID_SERVCLASS_FAX:
+        p_port->default_signal_state = PORT_DUN_DEFAULT_SIGNAL_STATE;
+        break;
+    }
+
+    RFCOMM_TRACE_EVENT ("RFCOMM_CreateConnection dlci:%d signal state:0x%x", dlci, p_port->default_signal_state);
+
+    *p_handle = p_port->inx;
+
+    p_port->state        = PORT_STATE_OPENING;
+    p_port->uuid         = uuid;
+    p_port->is_server    = is_server;
+    p_port->scn          = scn;
+    p_port->ev_mask      = 0;
+
+    /* If the MTU is not specified (0), keep MTU decision until the
+     * PN frame has to be send
+     * at that time connection should be established and we
+     * will know for sure our prefered MTU
+     */
+
+    rfcomm_mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
+
+    if (mtu)
+        p_port->mtu      = (mtu < rfcomm_mtu) ? mtu : rfcomm_mtu;
+    else
+        p_port->mtu      = rfcomm_mtu;
+
+    /* server doesn't need to release port when closing */
+    if( is_server )
+    {
+        p_port->keep_port_handle = true;
+
+        /* keep mtu that user asked, p_port->mtu could be updated during param negotiation */
+        p_port->keep_mtu         = p_port->mtu;
+    }
+
+    p_port->local_ctrl.modem_signal = p_port->default_signal_state;
+    p_port->local_ctrl.fc           = false;
+
+    p_port->p_mgmt_callback = p_mgmt_cb;
+
+    for (i = 0; i < BD_ADDR_LEN; i++)
+        p_port->bd_addr[i] = bd_addr[i];
+
+    /* If this is not initiator of the connection need to just wait */
+    if (p_port->is_server)
+    {
+        return (PORT_SUCCESS);
+    }
+
+    /* Open will be continued after security checks are passed */
+    return port_open_continue (p_port);
+}
+
+/*******************************************************************************
+**
+** Function         RFCOMM_RemoveConnection
+**
+** Description      This function is called to close the specified connection.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**
+*******************************************************************************/
+int RFCOMM_RemoveConnection (uint16_t handle)
+{
+    tPORT      *p_port;
+
+
+    RFCOMM_TRACE_API ("RFCOMM_RemoveConnection() handle:%d", handle);
+
+    /* Check if handle is valid to avoid crashing */
+    if ((handle == 0) || (handle > MAX_RFC_PORTS))
+    {
+        RFCOMM_TRACE_ERROR ("RFCOMM_RemoveConnection() BAD handle:%d", handle);
+        return (PORT_BAD_HANDLE);
+    }
+    p_port = &rfc_cb.port.port[handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        RFCOMM_TRACE_EVENT ("RFCOMM_RemoveConnection() Not opened:%d", handle);
+        return (PORT_SUCCESS);
+    }
+
+    p_port->state = PORT_STATE_CLOSING;
+
+    port_start_close (p_port);
+
+    return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         RFCOMM_RemoveServer
+**
+** Description      This function is called to close the server port.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**
+*******************************************************************************/
+int RFCOMM_RemoveServer (uint16_t handle)
+{
+    tPORT      *p_port;
+
+    RFCOMM_TRACE_API ("RFCOMM_RemoveServer() handle:%d", handle);
+
+    /* Check if handle is valid to avoid crashing */
+    if ((handle == 0) || (handle > MAX_RFC_PORTS))
+    {
+        RFCOMM_TRACE_ERROR ("RFCOMM_RemoveServer() BAD handle:%d", handle);
+        return (PORT_BAD_HANDLE);
+    }
+    p_port = &rfc_cb.port.port[handle - 1];
+
+    /* Do not report any events to the client any more. */
+    p_port->p_mgmt_callback = NULL;
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        RFCOMM_TRACE_EVENT ("RFCOMM_RemoveServer() Not opened:%d", handle);
+        return (PORT_SUCCESS);
+    }
+
+    /* this port will be deallocated after closing */
+    p_port->keep_port_handle = false;
+    p_port->state = PORT_STATE_CLOSING;
+
+    port_start_close (p_port);
+
+    return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         PORT_SetEventCallback
+**
+** Description      This function is called to provide an address of the
+**                  function which will be called when one of the events
+**                  specified in the mask occures.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  p_callback - address of the callback function which should
+**                               be called from the RFCOMM when an event
+**                               specified in the mask occures.
+**
+**
+*******************************************************************************/
+int PORT_SetEventCallback (uint16_t port_handle, tPORT_CALLBACK *p_port_cb)
+{
+    tPORT  *p_port;
+
+    /* Check if handle is valid to avoid crashing */
+    if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+
+    p_port = &rfc_cb.port.port[port_handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    RFCOMM_TRACE_API ("PORT_SetEventCallback() handle:%d", port_handle);
+
+    p_port->p_callback = p_port_cb;
+
+    return (PORT_SUCCESS);
+}
+/*******************************************************************************
+**
+** Function         PORT_ClearKeepHandleFlag
+**
+** Description      This function is called to clear the keep handle flag
+**                  which will cause not to keep the port handle open when closed
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**
+*******************************************************************************/
+
+int PORT_ClearKeepHandleFlag (uint16_t port_handle)
+{
+    tPORT  *p_port;
+
+    /* Check if handle is valid to avoid crashing */
+    if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+
+    p_port = &rfc_cb.port.port[port_handle - 1];
+    p_port->keep_port_handle = 0;
+    return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         PORT_SetDataCallback
+**
+** Description      This function is when a data packet is received
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  p_callback - address of the callback function which should
+**                               be called from the RFCOMM when data packet
+**                               is received.
+**
+**
+*******************************************************************************/
+int PORT_SetDataCallback (uint16_t port_handle, tPORT_DATA_CALLBACK *p_port_cb)
+{
+    tPORT  *p_port;
+
+    RFCOMM_TRACE_API ("PORT_SetDataCallback() handle:%d cb 0x%x", port_handle, p_port_cb);
+
+    /* Check if handle is valid to avoid crashing */
+    if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+
+    p_port = &rfc_cb.port.port[port_handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    p_port->p_data_callback = p_port_cb;
+
+    return (PORT_SUCCESS);
+}
+/*******************************************************************************
+**
+** Function         PORT_SetCODataCallback
+**
+** Description      This function is when a data packet is received
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  p_callback - address of the callback function which should
+**                               be called from the RFCOMM when data packet
+**                               is received.
+**
+**
+*******************************************************************************/
+int PORT_SetDataCOCallback (uint16_t port_handle, tPORT_DATA_CO_CALLBACK *p_port_cb)
+{
+    tPORT  *p_port;
+
+    RFCOMM_TRACE_API ("PORT_SetDataCOCallback() handle:%d cb 0x%x", port_handle, p_port_cb);
+
+    /* Check if handle is valid to avoid crashing */
+    if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+
+    p_port = &rfc_cb.port.port[port_handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    p_port->p_data_co_callback = p_port_cb;
+
+    return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         PORT_SetEventMask
+**
+** Description      This function is called to close the specified connection.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  mask   - Bitmask of the events the host is interested in
+**
+*******************************************************************************/
+int PORT_SetEventMask (uint16_t port_handle, uint32_t mask)
+{
+    tPORT  *p_port;
+
+    RFCOMM_TRACE_API ("PORT_SetEventMask() handle:%d mask:0x%x", port_handle, mask);
+
+    /* Check if handle is valid to avoid crashing */
+    if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+
+    p_port = &rfc_cb.port.port[port_handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    p_port->ev_mask = mask;
+
+    return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         PORT_CheckConnection
+**
+** Description      This function returns PORT_SUCCESS if connection referenced
+**                  by handle is up and running
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  bd_addr    - OUT bd_addr of the peer
+**                  p_lcid     - OUT L2CAP's LCID
+**
+*******************************************************************************/
+int PORT_CheckConnection (uint16_t handle, BD_ADDR bd_addr, uint16_t *p_lcid)
+{
+    tPORT      *p_port;
+
+    RFCOMM_TRACE_API ("PORT_CheckConnection() handle:%d", handle);
+
+    /* Check if handle is valid to avoid crashing */
+    if ((handle == 0) || (handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+
+    p_port = &rfc_cb.port.port[handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    if (!p_port->rfc.p_mcb
+     || !p_port->rfc.p_mcb->peer_ready
+     || (p_port->rfc.state != RFC_STATE_OPENED))
+    {
+        return (PORT_LINE_ERR);
+    }
+
+    memcpy (bd_addr, p_port->rfc.p_mcb->bd_addr, BD_ADDR_LEN);
+    if (p_lcid)
+        *p_lcid = p_port->rfc.p_mcb->lcid;
+
+    return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         PORT_IsOpening
+**
+** Description      This function returns true if there is any RFCOMM connection
+**                  opening in process.
+**
+** Parameters:      true if any connection opening is found
+**                  bd_addr    - bd_addr of the peer
+**
+*******************************************************************************/
+bool    PORT_IsOpening (BD_ADDR bd_addr)
+{
+    uint8_t xx, yy;
+    tRFC_MCB *p_mcb = NULL;
+    tPORT  *p_port;
+    bool    found_port;
+
+    /* Check for any rfc_mcb which is in the middle of opening. */
+    for (xx = 0; xx < MAX_BD_CONNECTIONS; xx++)
+    {
+        if ((rfc_cb.port.rfc_mcb[xx].state > RFC_MX_STATE_IDLE) &&
+            (rfc_cb.port.rfc_mcb[xx].state < RFC_MX_STATE_CONNECTED))
+        {
+            memcpy (bd_addr, rfc_cb.port.rfc_mcb[xx].bd_addr, BD_ADDR_LEN);
+            return true;
+        }
+
+        if (rfc_cb.port.rfc_mcb[xx].state == RFC_MX_STATE_CONNECTED)
+        {
+            found_port = false;
+            p_mcb = &rfc_cb.port.rfc_mcb[xx];
+            p_port = &rfc_cb.port.port[0];
+
+            for (yy = 0; yy < MAX_RFC_PORTS; yy++, p_port++)
+            {
+                if (p_port->rfc.p_mcb == p_mcb)
+                {
+                    found_port = true;
+                    break;
+                }
+            }
+
+            if ((!found_port) ||
+                (found_port && (p_port->rfc.state < RFC_STATE_OPENED)))
+            {
+                /* Port is not established yet. */
+                memcpy (bd_addr, rfc_cb.port.rfc_mcb[xx].bd_addr, BD_ADDR_LEN);
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+/*******************************************************************************
+**
+** Function         PORT_SetState
+**
+** Description      This function configures connection according to the
+**                  specifications in the tPORT_STATE structure.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  p_settings - Pointer to a tPORT_STATE structure containing
+**                               configuration information for the connection.
+**
+**
+*******************************************************************************/
+int PORT_SetState (uint16_t handle, tPORT_STATE *p_settings)
+{
+    tPORT      *p_port;
+    uint8_t     baud_rate;
+
+    RFCOMM_TRACE_API ("PORT_SetState() handle:%d", handle);
+
+    /* Check if handle is valid to avoid crashing */
+    if ((handle == 0) || (handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+
+    p_port = &rfc_cb.port.port[handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    if (p_port->line_status)
+    {
+        return (PORT_LINE_ERR);
+    }
+
+    RFCOMM_TRACE_API ("PORT_SetState() handle:%d FC_TYPE:0x%x", handle,
+                       p_settings->fc_type);
+
+    baud_rate = p_port->user_port_pars.baud_rate;
+    p_port->user_port_pars = *p_settings;
+
+    /* for now we've been asked to pass only baud rate */
+    if (baud_rate != p_settings->baud_rate)
+    {
+        port_start_par_neg (p_port);
+    }
+    return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         PORT_GetRxQueueCnt
+**
+** Description      This function return number of buffers on the rx queue.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  p_rx_queue_count - Pointer to return queue count in.
+**
+*******************************************************************************/
+int PORT_GetRxQueueCnt (uint16_t handle, uint16_t *p_rx_queue_count)
+{
+    tPORT      *p_port;
+
+    RFCOMM_TRACE_API ("PORT_GetRxQueueCnt() handle:%d", handle);
+
+    /* Check if handle is valid to avoid crashing */
+    if ((handle == 0) || (handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+
+    p_port = &rfc_cb.port.port[handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    if (p_port->line_status)
+    {
+        return (PORT_LINE_ERR);
+    }
+
+    *p_rx_queue_count = p_port->rx.queue_size;
+
+	RFCOMM_TRACE_API ("PORT_GetRxQueueCnt() p_rx_queue_count:%d, p_port->rx.queue.count = %d",
+		                                     *p_rx_queue_count, p_port->rx.queue_size);
+
+    return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         PORT_GetState
+**
+** Description      This function is called to fill tPORT_STATE structure
+**                  with the curremt control settings for the port
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  p_settings - Pointer to a tPORT_STATE structure in which
+**                               configuration information is returned.
+**
+*******************************************************************************/
+int PORT_GetState (uint16_t handle, tPORT_STATE *p_settings)
+{
+    tPORT      *p_port;
+
+    RFCOMM_TRACE_API ("PORT_GetState() handle:%d", handle);
+
+    /* Check if handle is valid to avoid crashing */
+    if ((handle == 0) || (handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+
+    p_port = &rfc_cb.port.port[handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    if (p_port->line_status)
+    {
+        return (PORT_LINE_ERR);
+    }
+
+    *p_settings = p_port->user_port_pars;
+    return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         PORT_Control
+**
+** Description      This function directs a specified connection to pass control
+**                  control information to the peer device.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  signal     = specify the function to be passed
+**
+*******************************************************************************/
+int PORT_Control (uint16_t handle, uint8_t signal)
+{
+    tPORT      *p_port;
+    uint8_t    old_modem_signal;
+
+    RFCOMM_TRACE_API ("PORT_Control() handle:%d signal:0x%x", handle, signal);
+
+    /* Check if handle is valid to avoid crashing */
+    if ((handle == 0) || (handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+
+    p_port = &rfc_cb.port.port[handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    old_modem_signal = p_port->local_ctrl.modem_signal;
+    p_port->local_ctrl.break_signal = 0;
+
+    switch (signal)
+    {
+    case PORT_SET_CTSRTS:
+        p_port->local_ctrl.modem_signal |= PORT_CTSRTS_ON;
+        break;
+
+    case PORT_CLR_CTSRTS:
+        p_port->local_ctrl.modem_signal &= ~PORT_CTSRTS_ON;
+        break;
+
+    case PORT_SET_DTRDSR:
+        p_port->local_ctrl.modem_signal |= PORT_DTRDSR_ON;
+        break;
+
+    case PORT_CLR_DTRDSR:
+        p_port->local_ctrl.modem_signal &= ~PORT_DTRDSR_ON;
+        break;
+
+    case PORT_SET_RI:
+        p_port->local_ctrl.modem_signal |= PORT_RING_ON;
+        break;
+
+    case PORT_CLR_RI:
+        p_port->local_ctrl.modem_signal &= ~PORT_RING_ON;
+        break;
+
+    case PORT_SET_DCD:
+        p_port->local_ctrl.modem_signal |= PORT_DCD_ON;
+        break;
+
+    case PORT_CLR_DCD:
+        p_port->local_ctrl.modem_signal &= ~PORT_DCD_ON;
+        break;
+    }
+
+    if (signal == PORT_BREAK)
+        p_port->local_ctrl.break_signal = PORT_BREAK_DURATION;
+    else if (p_port->local_ctrl.modem_signal == old_modem_signal)
+        return (PORT_SUCCESS);
+
+    port_start_control (p_port);
+
+    RFCOMM_TRACE_EVENT ("PORT_Control DTR_DSR : %d, RTS_CTS : %d, RI : %d, DCD : %d",
+        ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_DTRDSR) ? 1 : 0),
+        ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_RTSCTS) ? 1 : 0),
+        ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_RI) ? 1 : 0),
+        ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_DCD) ? 1 : 0));
+
+    return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         PORT_FlowControl
+**
+** Description      This function directs a specified connection to pass
+**                  flow control message to the peer device.  Enable flag passed
+**                  shows if port can accept more data.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  enable     - enables data flow
+**
+*******************************************************************************/
+int PORT_FlowControl (uint16_t handle, bool    enable)
+{
+    tPORT      *p_port;
+    bool       old_fc;
+    uint32_t   events;
+
+    RFCOMM_TRACE_API ("PORT_FlowControl() handle:%d enable: %d", handle, enable);
+
+    /* Check if handle is valid to avoid crashing */
+    if ((handle == 0) || (handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+
+    p_port = &rfc_cb.port.port[handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    if (!p_port->rfc.p_mcb)
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    p_port->rx.user_fc = !enable;
+
+    if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT)
+    {
+        if (!p_port->rx.user_fc)
+        {
+            port_flow_control_peer(p_port, true, 0);
+        }
+    }
+    else
+    {
+        old_fc = p_port->local_ctrl.fc;
+
+        /* FC is set if user is set or peer is set */
+        p_port->local_ctrl.fc = (p_port->rx.user_fc | p_port->rx.peer_fc);
+
+        if (p_port->local_ctrl.fc != old_fc)
+            port_start_control (p_port);
+    }
+
+    /* Need to take care of the case when we could not deliver events */
+    /* to the application because we were flow controlled */
+    if (enable && (p_port->rx.queue_size != 0))
+    {
+        events = PORT_EV_RXCHAR;
+        if (p_port->rx_flag_ev_pending)
+        {
+            p_port->rx_flag_ev_pending = false;
+            events |= PORT_EV_RXFLAG;
+        }
+
+        events &= p_port->ev_mask;
+        if (p_port->p_callback && events)
+        {
+            p_port->p_callback (events, p_port->inx);
+        }
+    }
+    return (PORT_SUCCESS);
+}
+/*******************************************************************************
+**
+** Function         PORT_FlowControl_MaxCredit
+**
+** Description      This function directs a specified connection to pass
+**                  flow control message to the peer device.  Enable flag passed
+**                  shows if port can accept more data. It also sends max credit
+**                  when data flow enabled
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  enable     - enables data flow
+**
+*******************************************************************************/
+
+int PORT_FlowControl_MaxCredit (uint16_t handle, bool    enable)
+{
+    tPORT      *p_port;
+    bool       old_fc;
+    uint32_t   events;
+
+    RFCOMM_TRACE_API ("PORT_FlowControl() handle:%d enable: %d", handle, enable);
+
+    /* Check if handle is valid to avoid crashing */
+    if ((handle == 0) || (handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+
+    p_port = &rfc_cb.port.port[handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    if (!p_port->rfc.p_mcb)
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    p_port->rx.user_fc = !enable;
+
+    if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT)
+    {
+        if (!p_port->rx.user_fc)
+        {
+            port_flow_control_peer(p_port, true, p_port->credit_rx);
+        }
+    }
+    else
+    {
+        old_fc = p_port->local_ctrl.fc;
+
+        /* FC is set if user is set or peer is set */
+        p_port->local_ctrl.fc = (p_port->rx.user_fc | p_port->rx.peer_fc);
+
+        if (p_port->local_ctrl.fc != old_fc)
+            port_start_control (p_port);
+    }
+
+    /* Need to take care of the case when we could not deliver events */
+    /* to the application because we were flow controlled */
+    if (enable && (p_port->rx.queue_size != 0))
+    {
+        events = PORT_EV_RXCHAR;
+        if (p_port->rx_flag_ev_pending)
+        {
+            p_port->rx_flag_ev_pending = false;
+            events |= PORT_EV_RXFLAG;
+        }
+
+        events &= p_port->ev_mask;
+        if (p_port->p_callback && events)
+        {
+            p_port->p_callback (events, p_port->inx);
+        }
+    }
+    return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         PORT_GetModemStatus
+**
+** Description      This function retrieves modem control signals.  Normally
+**                  application will call this function after a callback
+**                  function is called with notification that one of signals
+**                  has been changed.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  p_signal   - specify the pointer to control signals info
+**
+*******************************************************************************/
+int PORT_GetModemStatus (uint16_t handle, uint8_t *p_signal)
+{
+    tPORT      *p_port;
+
+    if ((handle == 0) || (handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+
+    p_port = &rfc_cb.port.port[handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    *p_signal = p_port->peer_ctrl.modem_signal;
+
+    RFCOMM_TRACE_API ("PORT_GetModemStatus() handle:%d signal:%x", handle, *p_signal);
+
+    return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         PORT_ClearError
+**
+** Description      This function retreives information about a communications
+**                  error and reports current status of a connection.  The
+**                  function should be called when an error occures to clear
+**                  the connection error flag and to enable additional read
+**                  and write operations.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  p_errors   - pointer of the variable to receive error codes
+**                  p_status   - pointer to the tPORT_STATUS structur to receive
+**                               connection status
+**
+*******************************************************************************/
+int PORT_ClearError (uint16_t handle, uint16_t *p_errors, tPORT_STATUS *p_status)
+{
+    tPORT  *p_port;
+
+    RFCOMM_TRACE_API ("PORT_ClearError() handle:%d", handle);
+
+    if ((handle == 0) || (handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+
+    p_port = &rfc_cb.port.port[handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    *p_errors = p_port->line_status;
+
+    /* This is the only call to clear error status.  We can not clear */
+    /* connection failed status.  To clean it port should be closed and reopened */
+    p_port->line_status = (p_port->line_status & LINE_STATUS_FAILED);
+
+    PORT_GetQueueStatus (handle, p_status);
+    return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         PORT_SendError
+**
+** Description      This function send a communications error to the peer device
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  errors     - receive error codes
+**
+*******************************************************************************/
+int PORT_SendError (uint16_t handle, uint8_t errors)
+{
+    tPORT      *p_port;
+
+    RFCOMM_TRACE_API ("PORT_SendError() handle:%d errors:0x%x", handle, errors);
+
+    if ((handle == 0) || (handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+
+    p_port = &rfc_cb.port.port[handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    if (!p_port->rfc.p_mcb)
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    RFCOMM_LineStatusReq (p_port->rfc.p_mcb, p_port->dlci, errors);
+    return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         PORT_GetQueueStatus
+**
+** Description      This function reports current status of a connection.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  p_status   - pointer to the tPORT_STATUS structur to receive
+**                               connection status
+**
+*******************************************************************************/
+int PORT_GetQueueStatus (uint16_t handle, tPORT_STATUS *p_status)
+{
+    tPORT      *p_port;
+
+    /* RFCOMM_TRACE_API ("PORT_GetQueueStatus() handle:%d", handle); */
+
+    if ((handle == 0) || (handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+
+    p_port = &rfc_cb.port.port[handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    p_status->in_queue_size  = (uint16_t) p_port->rx.queue_size;
+    p_status->out_queue_size = (uint16_t) p_port->tx.queue_size;
+
+    p_status->mtu_size = (uint16_t) p_port->peer_mtu;
+
+    p_status->flags = 0;
+
+    if (!(p_port->peer_ctrl.modem_signal & PORT_CTSRTS_ON))
+        p_status->flags |= PORT_FLAG_CTS_HOLD;
+
+    if (!(p_port->peer_ctrl.modem_signal & PORT_DTRDSR_ON))
+        p_status->flags |= PORT_FLAG_DSR_HOLD;
+
+    if (!(p_port->peer_ctrl.modem_signal & PORT_DCD_ON))
+        p_status->flags |= PORT_FLAG_RLSD_HOLD;
+
+    return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         PORT_Purge
+**
+** Description      This function discards all the data from the output or
+**                  input queues of the specified connection.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  purge_flags - specify the action to take.
+**
+*******************************************************************************/
+int PORT_Purge (uint16_t handle, uint8_t purge_flags)
+{
+    tPORT      *p_port;
+    BT_HDR     *p_buf;
+    uint16_t    count;
+    uint32_t   events;
+
+    RFCOMM_TRACE_API ("PORT_Purge() handle:%d flags:0x%x", handle, purge_flags);
+
+    /* Check if handle is valid to avoid crashing */
+    if ((handle == 0) || (handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+
+    p_port = &rfc_cb.port.port[handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    if (purge_flags & PORT_PURGE_RXCLEAR)
+    {
+        mutex_global_lock();    /* to prevent missing credit */
+
+        count = fixed_queue_length(p_port->rx.queue);
+
+        while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->rx.queue)) != NULL)
+            osi_free(p_buf);
+
+        p_port->rx.queue_size = 0;
+
+        mutex_global_unlock();
+
+        /* If we flowed controlled peer based on rx_queue size enable data again */
+        if (count)
+            port_flow_control_peer (p_port, true, count);
+    }
+
+    if (purge_flags & PORT_PURGE_TXCLEAR)
+    {
+        mutex_global_lock(); /* to prevent tx.queue_size from being negative */
+
+        while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->tx.queue)) != NULL)
+            osi_free(p_buf);
+
+        p_port->tx.queue_size = 0;
+
+        mutex_global_unlock();
+
+        events = PORT_EV_TXEMPTY;
+
+        events |= port_flow_control_user (p_port);
+
+        events &= p_port->ev_mask;
+
+        if ((p_port->p_callback != NULL) && events)
+            (p_port->p_callback)(events, p_port->inx);
+    }
+
+    return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         PORT_ReadData
+**
+** Description      Normally not GKI aware application will call this function
+**                  after receiving PORT_EV_RXCHAR event.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  p_data      - Data area
+**                  max_len     - Byte count requested
+**                  p_len       - Byte count received
+**
+*******************************************************************************/
+int PORT_ReadData (uint16_t handle, char *p_data, uint16_t max_len, uint16_t *p_len)
+{
+    tPORT      *p_port;
+    BT_HDR     *p_buf;
+    uint16_t    count;
+
+    RFCOMM_TRACE_API ("PORT_ReadData() handle:%d max_len:%d", handle, max_len);
+
+    /* Initialize this in case of an error */
+    *p_len = 0;
+
+    /* Check if handle is valid to avoid crashing */
+    if ((handle == 0) || (handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+
+    p_port = &rfc_cb.port.port[handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    if (p_port->line_status)
+    {
+        return (PORT_LINE_ERR);
+    }
+
+    if (fixed_queue_is_empty(p_port->rx.queue))
+        return (PORT_SUCCESS);
+
+    count = 0;
+
+    while (max_len)
+    {
+        p_buf = (BT_HDR *)fixed_queue_try_peek_first(p_port->rx.queue);
+        if (p_buf == NULL)
+            break;
+
+        if (p_buf->len > max_len)
+        {
+            memcpy (p_data, (uint8_t *)(p_buf + 1) + p_buf->offset, max_len);
+            p_buf->offset += max_len;
+            p_buf->len    -= max_len;
+
+            *p_len += max_len;
+
+            mutex_global_lock();
+
+            p_port->rx.queue_size -= max_len;
+
+            mutex_global_unlock();
+
+            break;
+        }
+        else
+        {
+            memcpy (p_data, (uint8_t *)(p_buf + 1) + p_buf->offset, p_buf->len);
+
+            *p_len  += p_buf->len;
+            max_len -= p_buf->len;
+
+            mutex_global_lock();
+
+            p_port->rx.queue_size -= p_buf->len;
+
+            if (max_len)
+            {
+                p_data  += p_buf->len;
+            }
+
+            osi_free(fixed_queue_try_dequeue(p_port->rx.queue));
+
+            mutex_global_unlock();
+
+            count++;
+        }
+    }
+
+    if (*p_len == 1)
+    {
+        RFCOMM_TRACE_EVENT ("PORT_ReadData queue:%d returned:%d %x", p_port->rx.queue_size, *p_len, (p_data[0]));
+    }
+    else
+    {
+        RFCOMM_TRACE_EVENT ("PORT_ReadData queue:%d returned:%d", p_port->rx.queue_size, *p_len);
+    }
+
+    /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
+    /* check if it can be resumed now */
+    port_flow_control_peer (p_port, true, count);
+
+    return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         PORT_Read
+**
+** Description      Normally application will call this function after receiving
+**                  PORT_EV_RXCHAR event.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  pp_buf      - pointer to address of buffer with data,
+**
+*******************************************************************************/
+int PORT_Read (uint16_t handle, BT_HDR **pp_buf)
+{
+    tPORT      *p_port;
+    BT_HDR     *p_buf;
+
+    RFCOMM_TRACE_API ("PORT_Read() handle:%d", handle);
+
+    /* Check if handle is valid to avoid crashing */
+    if ((handle == 0) || (handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+    p_port = &rfc_cb.port.port[handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    if (p_port->line_status)
+    {
+        return (PORT_LINE_ERR);
+    }
+
+    mutex_global_lock();
+
+    p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->rx.queue);
+    if (p_buf)
+    {
+        p_port->rx.queue_size -= p_buf->len;
+
+        mutex_global_unlock();
+
+        /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
+        /* check if it can be resumed now */
+        port_flow_control_peer (p_port, true, 1);
+    }
+    else
+    {
+        mutex_global_unlock();
+    }
+
+    *pp_buf = p_buf;
+    return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         port_write
+**
+** Description      This function when a data packet is received from the apper
+**                  layer task.
+**
+** Parameters:      p_port     - pointer to address of port control block
+**                  p_buf      - pointer to address of buffer with data,
+**
+*******************************************************************************/
+static int port_write (tPORT *p_port, BT_HDR *p_buf)
+{
+    /* We should not allow to write data in to server port when connection is not opened */
+    if (p_port->is_server && (p_port->rfc.state != RFC_STATE_OPENED))
+    {
+        osi_free(p_buf);
+        return (PORT_CLOSED);
+    }
+
+    /* Keep the data in pending queue if peer does not allow data, or */
+    /* Peer is not ready or Port is not yet opened or initial port control */
+    /* command has not been sent */
+    if (p_port->tx.peer_fc
+     || !p_port->rfc.p_mcb
+     || !p_port->rfc.p_mcb->peer_ready
+     || (p_port->rfc.state != RFC_STATE_OPENED)
+     || ((p_port->port_ctrl & (PORT_CTRL_REQ_SENT | PORT_CTRL_IND_RECEIVED)) !=
+                              (PORT_CTRL_REQ_SENT | PORT_CTRL_IND_RECEIVED)))
+    {
+        if ((p_port->tx.queue_size  > PORT_TX_CRITICAL_WM)
+         || (fixed_queue_length(p_port->tx.queue) > PORT_TX_BUF_CRITICAL_WM))
+        {
+            RFCOMM_TRACE_WARNING ("PORT_Write: Queue size: %d",
+                                   p_port->tx.queue_size);
+
+            osi_free(p_buf);
+
+            if ((p_port->p_callback != NULL) && (p_port->ev_mask & PORT_EV_ERR))
+                  p_port->p_callback (PORT_EV_ERR, p_port->inx);
+
+            return (PORT_TX_FULL);
+        }
+
+        RFCOMM_TRACE_EVENT ("PORT_Write : Data is enqued. flow disabled %d peer_ready %d state %d ctrl_state %x",
+                             p_port->tx.peer_fc,
+                             (p_port->rfc.p_mcb && p_port->rfc.p_mcb->peer_ready),
+                             p_port->rfc.state,
+                             p_port->port_ctrl);
+
+        fixed_queue_enqueue(p_port->tx.queue, p_buf);
+        p_port->tx.queue_size += p_buf->len;
+
+        return (PORT_CMD_PENDING);
+    }
+    else
+    {
+        RFCOMM_TRACE_EVENT ("PORT_Write : Data is being sent");
+
+        RFCOMM_DataReq (p_port->rfc.p_mcb, p_port->dlci, p_buf);
+        return (PORT_SUCCESS);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         PORT_Write
+**
+** Description      This function when a data packet is received from the apper
+**                  layer task.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  pp_buf      - pointer to address of buffer with data,
+**
+*******************************************************************************/
+int PORT_Write (uint16_t handle, BT_HDR *p_buf)
+{
+    tPORT  *p_port;
+    uint32_t event = 0;
+    int    rc;
+
+    RFCOMM_TRACE_API ("PORT_Write() handle:%d", handle);
+
+    /* Check if handle is valid to avoid crashing */
+    if ((handle == 0) || (handle > MAX_RFC_PORTS))
+    {
+        osi_free(p_buf);
+        return (PORT_BAD_HANDLE);
+    }
+
+    p_port = &rfc_cb.port.port[handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        osi_free(p_buf);
+        return (PORT_NOT_OPENED);
+    }
+
+    if (p_port->line_status)
+    {
+        RFCOMM_TRACE_WARNING ("PORT_Write: Data dropped line_status:0x%x",
+                               p_port->line_status);
+        osi_free(p_buf);
+        return (PORT_LINE_ERR);
+    }
+
+    rc = port_write (p_port, p_buf);
+    event |= port_flow_control_user (p_port);
+
+    switch (rc)
+    {
+    case PORT_TX_FULL:
+        event |= PORT_EV_ERR;
+        break;
+
+    case PORT_SUCCESS:
+        event |= (PORT_EV_TXCHAR | PORT_EV_TXEMPTY);
+        break;
+    }
+    /* Mask out all events that are not of interest to user */
+    event &= p_port->ev_mask;
+
+    /* Send event to the application */
+    if (p_port->p_callback && event)
+        (p_port->p_callback)(event, p_port->inx);
+
+    return (PORT_SUCCESS);
+}
+/*******************************************************************************
+**
+** Function         PORT_WriteDataCO
+**
+** Description      Normally not GKI aware application will call this function
+**                  to send data to the port by callout functions
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  fd         - socket fd
+**                  p_len      - Byte count returned
+**
+*******************************************************************************/
+int PORT_WriteDataCO (uint16_t handle, int* p_len)
+{
+
+    tPORT      *p_port;
+    BT_HDR     *p_buf;
+    uint32_t   event = 0;
+    int        rc = 0;
+    uint16_t   length;
+
+    RFCOMM_TRACE_API ("PORT_WriteDataCO() handle:%d", handle);
+    *p_len = 0;
+
+    /* Check if handle is valid to avoid crashing */
+    if ((handle == 0) || (handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+    p_port = &rfc_cb.port.port[handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        RFCOMM_TRACE_WARNING ("PORT_WriteDataByFd() no port state:%d", p_port->state);
+        return (PORT_NOT_OPENED);
+    }
+
+    if (!p_port->peer_mtu)
+    {
+        RFCOMM_TRACE_ERROR ("PORT_WriteDataByFd() peer_mtu:%d", p_port->peer_mtu);
+        return (PORT_UNKNOWN_ERROR);
+    }
+    int available = 0;
+    //if(ioctl(fd, FIONREAD, &available) < 0)
+    if(p_port->p_data_co_callback(handle, (uint8_t*)&available, sizeof(available),
+                                DATA_CO_CALLBACK_TYPE_OUTGOING_SIZE) == false)
+    {
+        RFCOMM_TRACE_ERROR("p_data_co_callback DATA_CO_CALLBACK_TYPE_INCOMING_SIZE failed, available:%d", available);
+        return (PORT_UNKNOWN_ERROR);
+    }
+    if(available == 0)
+        return PORT_SUCCESS;
+    /* Length for each buffer is the smaller of GKI buffer, peer MTU, or max_len */
+    length = RFCOMM_DATA_BUF_SIZE -
+            (uint16_t)(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + RFCOMM_DATA_OVERHEAD);
+
+    /* If there are buffers scheduled for transmission check if requested */
+    /* data fits into the end of the queue */
+    mutex_global_lock();
+
+    if (((p_buf = (BT_HDR *)fixed_queue_try_peek_last(p_port->tx.queue)) != NULL)
+     && (((int)p_buf->len + available) <= (int)p_port->peer_mtu)
+     && (((int)p_buf->len + available) <= (int)length))
+    {
+        //if(recv(fd, (uint8_t *)(p_buf + 1) + p_buf->offset + p_buf->len, available, 0) != available)
+        if(p_port->p_data_co_callback(handle, (uint8_t *)(p_buf + 1) + p_buf->offset + p_buf->len,
+                                    available, DATA_CO_CALLBACK_TYPE_OUTGOING) == false)
+
+        {
+            error("p_data_co_callback DATA_CO_CALLBACK_TYPE_OUTGOING failed, available:%d", available);
+            mutex_global_unlock();
+            return (PORT_UNKNOWN_ERROR);
+        }
+        //memcpy ((uint8_t *)(p_buf + 1) + p_buf->offset + p_buf->len, p_data, max_len);
+        p_port->tx.queue_size += (uint16_t)available;
+
+        *p_len = available;
+        p_buf->len += (uint16_t)available;
+
+        mutex_global_unlock();
+
+        return (PORT_SUCCESS);
+    }
+
+    mutex_global_unlock();
+
+    //int max_read = length < p_port->peer_mtu ? length : p_port->peer_mtu;
+
+    //max_read = available < max_read ? available : max_read;
+
+    while (available)
+    {
+        /* if we're over buffer high water mark, we're done */
+        if ((p_port->tx.queue_size  > PORT_TX_HIGH_WM)
+         || (fixed_queue_length(p_port->tx.queue) > PORT_TX_BUF_HIGH_WM))
+        {
+            port_flow_control_user(p_port);
+            event |= PORT_EV_FC;
+            RFCOMM_TRACE_EVENT ("tx queue is full,tx.queue_size:%d,tx.queue.count:%d,available:%d",
+                    p_port->tx.queue_size, fixed_queue_length(p_port->tx.queue), available);
+            break;
+         }
+
+        /* continue with rfcomm data write */
+        p_buf = (BT_HDR *)osi_malloc(RFCOMM_DATA_BUF_SIZE);
+        p_buf->offset         = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET;
+        p_buf->layer_specific = handle;
+
+        if (p_port->peer_mtu < length)
+            length = p_port->peer_mtu;
+        if (available < (int)length)
+            length = (uint16_t)available;
+        p_buf->len = length;
+        p_buf->event          = BT_EVT_TO_BTU_SP_DATA;
+
+        //memcpy ((uint8_t *)(p_buf + 1) + p_buf->offset, p_data, length);
+        //if(recv(fd, (uint8_t *)(p_buf + 1) + p_buf->offset, (int)length, 0) != (int)length)
+        if(p_port->p_data_co_callback(handle, (uint8_t *)(p_buf + 1) + p_buf->offset, length,
+                                      DATA_CO_CALLBACK_TYPE_OUTGOING) == false)
+        {
+            error("p_data_co_callback DATA_CO_CALLBACK_TYPE_OUTGOING failed, length:%d", length);
+            return (PORT_UNKNOWN_ERROR);
+        }
+
+        RFCOMM_TRACE_EVENT ("PORT_WriteData %d bytes", length);
+
+        rc = port_write (p_port, p_buf);
+
+        /* If queue went below the threashold need to send flow control */
+        event |= port_flow_control_user (p_port);
+
+        if (rc == PORT_SUCCESS)
+            event |= PORT_EV_TXCHAR;
+
+        if ((rc != PORT_SUCCESS) && (rc != PORT_CMD_PENDING))
+            break;
+
+        *p_len  += length;
+        available -= (int)length;
+    }
+    if (!available && (rc != PORT_CMD_PENDING) && (rc != PORT_TX_QUEUE_DISABLED))
+        event |= PORT_EV_TXEMPTY;
+
+    /* Mask out all events that are not of interest to user */
+    event &= p_port->ev_mask;
+
+    /* Send event to the application */
+    if (p_port->p_callback && event)
+        (p_port->p_callback)(event, p_port->inx);
+
+    return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         PORT_WriteData
+**
+** Description      Normally not GKI aware application will call this function
+**                  to send data to the port.
+**
+** Parameters:      handle     - Handle returned in the RFCOMM_CreateConnection
+**                  p_data      - Data area
+**                  max_len     - Byte count requested
+**                  p_len       - Byte count received
+**
+*******************************************************************************/
+int PORT_WriteData (uint16_t handle, const char *p_data, uint16_t max_len,
+                    uint16_t *p_len)
+{
+    tPORT      *p_port;
+    BT_HDR     *p_buf;
+    uint32_t   event = 0;
+    int        rc = 0;
+    uint16_t   length;
+
+    RFCOMM_TRACE_API ("PORT_WriteData() max_len:%d", max_len);
+
+    *p_len = 0;
+
+    /* Check if handle is valid to avoid crashing */
+    if ((handle == 0) || (handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+    p_port = &rfc_cb.port.port[handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        RFCOMM_TRACE_WARNING ("PORT_WriteData() no port state:%d", p_port->state);
+        return (PORT_NOT_OPENED);
+    }
+
+    if (!max_len || !p_port->peer_mtu)
+    {
+        RFCOMM_TRACE_ERROR ("PORT_WriteData() peer_mtu:%d", p_port->peer_mtu);
+        return (PORT_UNKNOWN_ERROR);
+    }
+
+    /* Length for each buffer is the smaller of GKI buffer, peer MTU, or max_len */
+    length = RFCOMM_DATA_BUF_SIZE -
+            (uint16_t)(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + RFCOMM_DATA_OVERHEAD);
+
+    /* If there are buffers scheduled for transmission check if requested */
+    /* data fits into the end of the queue */
+    mutex_global_lock();
+
+    if (((p_buf = (BT_HDR *)fixed_queue_try_peek_last(p_port->tx.queue)) != NULL)
+     && ((p_buf->len + max_len) <= p_port->peer_mtu)
+     && ((p_buf->len + max_len) <= length))
+    {
+        memcpy ((uint8_t *)(p_buf + 1) + p_buf->offset + p_buf->len, p_data, max_len);
+        p_port->tx.queue_size += max_len;
+
+        *p_len = max_len;
+        p_buf->len += max_len;
+
+        mutex_global_unlock();
+
+        return (PORT_SUCCESS);
+    }
+
+    mutex_global_unlock();
+
+    while (max_len)
+    {
+        /* if we're over buffer high water mark, we're done */
+        if ((p_port->tx.queue_size  > PORT_TX_HIGH_WM)
+         || (fixed_queue_length(p_port->tx.queue) > PORT_TX_BUF_HIGH_WM))
+            break;
+
+        /* continue with rfcomm data write */
+        p_buf = (BT_HDR *)osi_malloc(RFCOMM_DATA_BUF_SIZE);
+        p_buf->offset         = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET;
+        p_buf->layer_specific = handle;
+
+        if (p_port->peer_mtu < length)
+            length = p_port->peer_mtu;
+        if (max_len < length)
+            length = max_len;
+        p_buf->len = length;
+        p_buf->event          = BT_EVT_TO_BTU_SP_DATA;
+
+        memcpy ((uint8_t *)(p_buf + 1) + p_buf->offset, p_data, length);
+
+        RFCOMM_TRACE_EVENT ("PORT_WriteData %d bytes", length);
+
+        rc = port_write (p_port, p_buf);
+
+        /* If queue went below the threashold need to send flow control */
+        event |= port_flow_control_user (p_port);
+
+        if (rc == PORT_SUCCESS)
+            event |= PORT_EV_TXCHAR;
+
+        if ((rc != PORT_SUCCESS) && (rc != PORT_CMD_PENDING))
+            break;
+
+        *p_len  += length;
+        max_len -= length;
+        p_data  += length;
+
+    }
+    if (!max_len && (rc != PORT_CMD_PENDING) && (rc != PORT_TX_QUEUE_DISABLED))
+        event |= PORT_EV_TXEMPTY;
+
+    /* Mask out all events that are not of interest to user */
+    event &= p_port->ev_mask;
+
+    /* Send event to the application */
+    if (p_port->p_callback && event)
+        (p_port->p_callback)(event, p_port->inx);
+
+    return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         PORT_Test
+**
+** Description      Application can call this function to send RFCOMM Test frame
+**
+** Parameters:      handle      - Handle returned in the RFCOMM_CreateConnection
+**                  p_data      - Data area
+**                  max_len     - Byte count requested
+**
+*******************************************************************************/
+int PORT_Test (uint16_t handle, uint8_t *p_data, uint16_t len)
+{
+    tPORT    *p_port;
+
+    RFCOMM_TRACE_API ("PORT_Test() len:%d", len);
+
+    if ((handle == 0) || (handle > MAX_RFC_PORTS))
+    {
+        return (PORT_BAD_HANDLE);
+    }
+    p_port = &rfc_cb.port.port[handle - 1];
+
+    if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+    {
+        return (PORT_NOT_OPENED);
+    }
+
+    if (len > ((p_port->mtu == 0) ? RFCOMM_DEFAULT_MTU : p_port->mtu))
+    {
+        return (PORT_UNKNOWN_ERROR);
+    }
+
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+    p_buf->offset  = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2;
+    p_buf->len = len;
+
+    memcpy((uint8_t *)(p_buf + 1) + p_buf->offset, p_data, p_buf->len);
+
+    rfc_send_test(p_port->rfc.p_mcb, true, p_buf);
+
+    return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         RFCOMM_Init
+**
+** Description      This function is called to initialize RFCOMM layer
+**
+*******************************************************************************/
+void RFCOMM_Init (void)
+{
+    memset (&rfc_cb, 0, sizeof (tRFC_CB));  /* Init RFCOMM control block */
+
+    rfc_cb.rfc.last_mux = MAX_BD_CONNECTIONS;
+
+#if defined(RFCOMM_INITIAL_TRACE_LEVEL)
+    rfc_cb.trace_level = RFCOMM_INITIAL_TRACE_LEVEL;
+#else
+    rfc_cb.trace_level = BT_TRACE_LEVEL_NONE;    /* No traces */
+#endif
+
+    rfcomm_l2cap_if_init ();
+}
+
+/*******************************************************************************
+**
+** Function         PORT_SetTraceLevel
+**
+** Description      This function sets the trace level for RFCOMM. If called with
+**                  a value of 0xFF, it simply reads the current trace level.
+**
+** Returns          the new (current) trace level
+**
+*******************************************************************************/
+uint8_t PORT_SetTraceLevel (uint8_t new_level)
+{
+    if (new_level != 0xFF)
+        rfc_cb.trace_level = new_level;
+
+    return (rfc_cb.trace_level);
+}
+
+/*******************************************************************************
+**
+** Function         PORT_GetResultString
+**
+** Description      This function returns the human-readable string for a given
+**                  result code.
+**
+** Returns          a pointer to the human-readable string for the given result.
+**
+*******************************************************************************/
+const char *PORT_GetResultString (const uint8_t result_code) {
+  if (result_code > PORT_ERR_MAX) {
+    return result_code_strings[PORT_ERR_MAX];
+  }
+
+  return result_code_strings[result_code];
+}
diff --git a/bt/stack/rfcomm/port_int.h b/bt/stack/rfcomm/port_int.h
new file mode 100644
index 0000000..e30685b
--- /dev/null
+++ b/bt/stack/rfcomm/port_int.h
@@ -0,0 +1,251 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 definitions internal to the PORT unit
+ *
+ *****************************************************************************/
+
+#ifndef PORT_INT_H
+#define PORT_INT_H
+
+#include "bt_target.h"
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+#include "bt_common.h"
+#include "rfcdefs.h"
+#include "port_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Local events passed when application event is sent from the api to PORT */
+/* ???*/
+#define PORT_EVENT_OPEN         (1  | BT_EVT_TO_BTU_SP_EVT)
+#define PORT_EVENT_CONTROL      (2  | BT_EVT_TO_BTU_SP_EVT)
+#define PORT_EVENT_SET_STATE    (3  | BT_EVT_TO_BTU_SP_EVT)
+#define PORT_EVENT_SET_CALLBACK (5  | BT_EVT_TO_BTU_SP_EVT)
+#define PORT_EVENT_WRITE        (6  | BT_EVT_TO_BTU_SP_EVT)
+#define PORT_EVENT_PURGE        (7  | BT_EVT_TO_BTU_SP_EVT)
+#define PORT_EVENT_SEND_ERROR   (8  | BT_EVT_TO_BTU_SP_EVT)
+#define PORT_EVENT_FLOW_CONTROL (9  | BT_EVT_TO_BTU_SP_EVT)
+
+/*
+** Flow control configuration values for the mux
+*/
+#define PORT_FC_UNDEFINED       0   /* mux flow control mechanism not defined yet */
+#define PORT_FC_TS710           1   /* use TS 07.10 flow control  */
+#define PORT_FC_CREDIT          2   /* use RFCOMM credit based flow control */
+
+/*
+** Define Port Data Transfere control block
+*/
+typedef struct
+{
+    fixed_queue_t *queue;   /* Queue of buffers waiting to be sent */
+    bool     peer_fc;       /* true if flow control is set based on peer's request */
+    bool     user_fc;       /* true if flow control is set based on user's request  */
+    uint32_t queue_size;    /* Number of data bytes in the queue */
+    tPORT_CALLBACK *p_callback;  /* Address of the callback function */
+} tPORT_DATA;
+
+/*
+** Port control structure used to pass modem info
+*/
+typedef struct
+{
+#define MODEM_SIGNAL_DTRDSR        0x01
+#define MODEM_SIGNAL_RTSCTS        0x02
+#define MODEM_SIGNAL_RI            0x04
+#define MODEM_SIGNAL_DCD           0x08
+
+    uint8_t modem_signal;       /* [DTR/DSR | RTS/CTS | RI | DCD ] */
+
+    uint8_t break_signal;       /* 0-3 s in steps of 200 ms */
+
+    uint8_t discard_buffers;    /* 0 - do not discard, 1 - discard */
+
+#define RFCOMM_CTRL_BREAK_ASAP      0
+#define RFCOMM_CTRL_BREAK_IN_SEQ    1
+
+    uint8_t break_signal_seq;   /* as soon as possible | in sequence (default) */
+
+    bool    fc;                 /* true when the device is unable to accept frames */
+} tPORT_CTRL;
+
+
+/*
+** RFCOMM multiplexer Control Block
+*/
+typedef struct
+{
+    alarm_t *mcb_timer;       /* MCB timer */
+    fixed_queue_t *cmd_q;     /* Queue for command messages on this mux */
+    uint8_t   port_inx[RFCOMM_MAX_DLCI + 1];  /* Array for quick access to  */
+                                              /* tPORT based on dlci        */
+    BD_ADDR   bd_addr;        /* BD ADDR of the peer if initiator */
+    uint16_t  lcid;           /* Local cid used for this channel */
+    uint16_t  peer_l2cap_mtu; /* Max frame that can be sent to peer L2CAP */
+    uint8_t   state;          /* Current multiplexer channel state */
+    uint8_t   is_initiator;   /* true if this side sends SABME (dlci=0) */
+    bool      local_cfg_sent;
+    bool      peer_cfg_rcvd;
+    bool      restart_required; /* true if has to restart channel after disc */
+    bool      peer_ready;      /* True if other side can accept frames */
+    uint8_t   flow;            /* flow control mechanism for this mux */
+    bool      l2cap_congested; /* true if L2CAP is congested */
+    bool      is_disc_initiator; /* true if initiated disc of port */
+    uint16_t  pending_lcid;    /* store LCID for incoming connection while connecting */
+    uint8_t   pending_id;      /* store l2cap ID for incoming connection while connecting */
+} tRFC_MCB;
+
+
+/*
+** RFCOMM Port Connection Control Block
+*/
+typedef struct {
+#define RFC_PORT_STATE_IDLE          0
+#define RFC_PORT_STATE_WAIT_START    1
+#define RFC_PORT_STATE_OPENING       2
+#define RFC_PORT_STATE_OPENED        3
+#define RFC_PORT_STATE_CLOSING       4
+
+    uint8_t   state;          /* Current state of the connection */
+
+#define RFC_RSP_PN                  0x01
+#define RFC_RSP_RPN_REPLY           0x02
+#define RFC_RSP_RPN                 0x04
+#define RFC_RSP_MSC                 0x08
+#define RFC_RSP_RLS                 0x10
+
+    uint8_t  expected_rsp;
+
+    tRFC_MCB *p_mcb;
+
+    alarm_t  *port_timer;
+} tRFC_PORT;
+
+
+/*
+** Define control block containing information about PORT connection
+*/
+typedef struct
+{
+    uint8_t inx;            /* Index of this control block in the port_info array */
+    bool    in_use;         /* True when structure is allocated */
+
+#define PORT_STATE_CLOSED   0
+#define PORT_STATE_OPENING  1
+#define PORT_STATE_OPENED   2
+#define PORT_STATE_CLOSING  3
+
+    uint8_t state;          /* State of the application */
+
+    uint8_t scn;            /* Service channel number */
+    uint16_t uuid;           /* Service UUID */
+
+    BD_ADDR bd_addr;        /* BD ADDR of the device for the multiplexer channel */
+    bool    is_server;      /* true if the server application */
+    uint8_t dlci;           /* DLCI of the connection */
+
+    uint8_t error;          /* Last error detected */
+
+    uint8_t line_status;    /* Line status as reported by peer */
+
+    uint8_t default_signal_state; /* Initial signal state depending on uuid */
+
+    uint16_t mtu;            /* Max MTU that port can receive */
+    uint16_t peer_mtu;       /* Max MTU that port can send */
+
+    tPORT_DATA tx;          /* Control block for data from app to peer */
+    tPORT_DATA rx;          /* Control block for data from peer to app */
+
+    tPORT_STATE user_port_pars;  /* Port parameters for user connection */
+    tPORT_STATE peer_port_pars;  /* Port parameters for user connection */
+
+    tPORT_CTRL  local_ctrl;
+    tPORT_CTRL  peer_ctrl;
+
+#define PORT_CTRL_REQ_SENT          0x01
+#define PORT_CTRL_REQ_CONFIRMED     0x02
+#define PORT_CTRL_IND_RECEIVED      0x04
+#define PORT_CTRL_IND_RESPONDED     0x08
+
+    uint8_t     port_ctrl;                  /* Modem Status Command  */
+
+    bool        rx_flag_ev_pending;         /* RXFLAG Character is received */
+
+    tRFC_PORT   rfc;                        /* RFCOMM port control block */
+
+    uint32_t    ev_mask;                    /* Event mask for the callback */
+    tPORT_CALLBACK      *p_callback;        /* Pointer to users callback function */
+    tPORT_CALLBACK      *p_mgmt_callback;   /* Callback function to receive connection up/down */
+    tPORT_DATA_CALLBACK *p_data_callback;   /* Callback function to receive data indications */
+    tPORT_DATA_CO_CALLBACK *p_data_co_callback;   /* Callback function with callouts and flowctrl */
+    uint16_t    credit_tx;                  /* Flow control credits for tx path */
+    uint16_t    credit_rx;                  /* Flow control credits for rx path, this is */
+                                            /* number of buffers peer is allowed to sent */
+    uint16_t    credit_rx_max;              /* Max number of credits we will allow this guy to sent */
+    uint16_t    credit_rx_low;              /* Number of credits when we send credit update */
+    uint16_t    rx_buf_critical;            /* port receive queue critical watermark level */
+    bool        keep_port_handle;           /* true if port is not deallocated when closing */
+                                            /* it is set to true for server when allocating port */
+    uint16_t    keep_mtu;                   /* Max MTU that port can receive by server */
+} tPORT;
+
+
+/* Define the PORT/RFCOMM control structure
+*/
+typedef struct
+{
+    tPORT        port[MAX_RFC_PORTS];            /* Port info pool */
+    tRFC_MCB     rfc_mcb[MAX_BD_CONNECTIONS];    /* RFCOMM bd_connections pool */
+} tPORT_CB;
+
+/*
+** Functions provided by the port_utils.cc
+*/
+extern tPORT    *port_allocate_port (uint8_t dlci, BD_ADDR bd_addr);
+extern void     port_set_defaults (tPORT *p_port);
+extern void     port_select_mtu (tPORT *p_port);
+extern void     port_release_port (tPORT *p_port);
+extern tPORT    *port_find_mcb_dlci_port (tRFC_MCB *p_mcb, uint8_t dlci);
+extern tRFC_MCB *port_find_mcb (BD_ADDR bd_addr);
+extern tPORT    *port_find_dlci_port (uint8_t dlci);
+extern tPORT    *port_find_port (uint8_t dlci, BD_ADDR bd_addr);
+extern uint32_t port_get_signal_changes (tPORT *p_port, uint8_t old_signals, uint8_t signal);
+extern uint32_t port_flow_control_user (tPORT *p_port);
+extern void     port_flow_control_peer(tPORT *p_port, bool    enable, uint16_t count);
+
+/*
+** Functions provided by the port_rfc.cc
+*/
+extern int  port_open_continue (tPORT *p_port);
+extern void port_start_port_open (tPORT *p_port);
+extern void port_start_par_neg (tPORT *p_port);
+extern void port_start_control (tPORT *p_port);
+extern void port_start_close (tPORT *p_port);
+extern void port_rfc_closed (tPORT *p_port, uint8_t res);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bt/stack/rfcomm/port_rfc.cc b/bt/stack/rfcomm/port_rfc.cc
new file mode 100644
index 0000000..32b4806
--- /dev/null
+++ b/bt/stack/rfcomm/port_rfc.cc
@@ -0,0 +1,1122 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 module contains functions for port emulation entity and RFCOMM
+ *  communications
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "osi/include/mutex.h"
+#include "osi/include/osi.h"
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+#include "rfcdefs.h"
+
+/*
+** Local function definitions
+*/
+uint32_t port_rfc_send_tx_data (tPORT *p_port);
+void   port_rfc_closed (tPORT *p_port, uint8_t res);
+void   port_get_credits (tPORT *p_port, uint8_t k);
+
+
+/*******************************************************************************
+**
+** Function         port_open_continue
+**
+** Description      This function is called after security manager completes
+**                  required security checks.
+**
+** Returns          void
+**
+*******************************************************************************/
+int port_open_continue (tPORT *p_port)
+{
+    tRFC_MCB *p_mcb;
+
+    RFCOMM_TRACE_EVENT ("port_open_continue, p_port:%p", p_port);
+
+    /* Check if multiplexer channel has already been established */
+    if ((p_mcb = rfc_alloc_multiplexer_channel (p_port->bd_addr, true)) == NULL)
+    {
+        RFCOMM_TRACE_WARNING ("port_open_continue no mx channel");
+        port_release_port (p_port);
+        return (PORT_NO_RESOURCES);
+    }
+
+    p_port->rfc.p_mcb = p_mcb;
+
+    p_mcb->port_inx[p_port->dlci] = p_port->inx;
+
+    /* Connection is up and we know local and remote features, select MTU */
+    port_select_mtu (p_port);
+
+    if (p_mcb->state == RFC_MX_STATE_CONNECTED)
+    {
+        RFCOMM_ParNegReq (p_mcb, p_port->dlci, p_port->mtu);
+    }
+    else if ((p_mcb->state == RFC_MX_STATE_IDLE)
+           ||(p_mcb->state == RFC_MX_STATE_DISC_WAIT_UA))
+    {
+        /* In RFC_MX_STATE_IDLE state, MX state machine will create connection           */
+        /* In RFC_MX_STATE_DISC_WAIT_UA state, MX state machine will recreate connection */
+        /*    after disconnecting is completed                                           */
+        RFCOMM_StartReq (p_mcb);
+    }
+    else
+    {
+        /* MX state machine ignores RFC_MX_EVENT_START_REQ in these states */
+        /* When it enters RFC_MX_STATE_CONNECTED, it will check any openning ports */
+        RFCOMM_TRACE_DEBUG ("port_open_continue: mx state(%d) mx channel is openning", p_mcb->state);
+    }
+    return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function         port_start_control
+**
+** Description      This function is called in the BTU_TASK context to
+**                  send control information
+**
+** Returns          void
+**
+*******************************************************************************/
+void port_start_control (tPORT *p_port)
+{
+    tRFC_MCB *p_mcb = p_port->rfc.p_mcb;
+
+    if (p_mcb == NULL)
+        return;
+
+    RFCOMM_ControlReq (p_mcb, p_port->dlci, &p_port->local_ctrl);
+}
+
+
+/*******************************************************************************
+**
+** Function         port_start_par_neg
+**
+** Description      This function is called in the BTU_TASK context to
+**                  send configuration information
+**
+** Returns          void
+**
+*******************************************************************************/
+void port_start_par_neg (tPORT *p_port)
+{
+    tRFC_MCB *p_mcb = p_port->rfc.p_mcb;
+
+    if (p_mcb == NULL)
+        return;
+
+    RFCOMM_PortNegReq (p_mcb, p_port->dlci, &p_port->user_port_pars);
+}
+
+
+/*******************************************************************************
+**
+** Function         port_start_close
+**
+** Description      This function is called in the BTU_TASK context to
+**                  release DLC
+**
+** Returns          void
+**
+*******************************************************************************/
+void port_start_close (tPORT *p_port)
+{
+    tRFC_MCB *p_mcb = p_port->rfc.p_mcb;
+    uint8_t old_signals;
+    uint32_t events = 0;
+
+    /* At first indicate to the user that signals on the connection were dropped */
+    p_port->line_status |= LINE_STATUS_FAILED;
+    old_signals = p_port->peer_ctrl.modem_signal;
+
+    p_port->peer_ctrl.modem_signal &= ~(PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON);
+
+    events |= port_get_signal_changes (p_port, old_signals, p_port->peer_ctrl.modem_signal);
+
+    if(p_port->ev_mask & PORT_EV_CONNECT_ERR)
+        events |= PORT_EV_CONNECT_ERR;
+
+    if(p_port->ev_mask & PORT_EV_ERR)
+        events |= PORT_EV_ERR;
+
+    if ((p_port->p_callback != NULL) && events)
+        p_port->p_callback (events, p_port->inx);
+
+
+    /* Check if RFCOMM side has been closed while the message was queued */
+    if ((p_mcb == NULL) || (p_port->rfc.state == RFC_STATE_CLOSED))
+    {
+        /* Call management callback function before calling port_release_port() to clear tPort */
+        if (p_port->p_mgmt_callback)
+            p_port->p_mgmt_callback (PORT_CLOSED, p_port->inx);
+
+        port_release_port (p_port);
+    }
+    else
+    {
+        RFCOMM_DlcReleaseReq (p_mcb, p_port->dlci);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         PORT_StartCnf
+**
+** Description      This function is called from the RFCOMM layer when
+**                  establishing of the multiplexer channel is completed.
+**                  Continue establishing of the connection for all ports that
+**                  are in the OPENING state
+**
+*******************************************************************************/
+void PORT_StartCnf (tRFC_MCB *p_mcb, uint16_t result)
+{
+    tPORT   *p_port;
+    int     i;
+    bool    no_ports_up = true;
+
+    RFCOMM_TRACE_EVENT ("PORT_StartCnf result:%d", result);
+
+    p_port = &rfc_cb.port.port[0];
+    for (i = 0; i < MAX_RFC_PORTS; i++, p_port++)
+    {
+        if (p_port->rfc.p_mcb == p_mcb)
+        {
+            no_ports_up = false;
+
+            if (result == RFCOMM_SUCCESS)
+                RFCOMM_ParNegReq (p_mcb, p_port->dlci, p_port->mtu);
+            else
+            {
+                RFCOMM_TRACE_WARNING ("PORT_StartCnf failed result:%d", result);
+
+                /* Warning: result is also set to 4 when l2cap connection
+                   fails due to l2cap connect cnf (no_resources) */
+                if( result == HCI_ERR_PAGE_TIMEOUT )
+                    p_port->error = PORT_PAGE_TIMEOUT;
+                else
+                    p_port->error = PORT_START_FAILED;
+
+                rfc_release_multiplexer_channel (p_mcb);
+
+                /* Send event to the application */
+                if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECT_ERR))
+                    (p_port->p_callback)(PORT_EV_CONNECT_ERR, p_port->inx);
+
+                if (p_port->p_mgmt_callback)
+                    p_port->p_mgmt_callback (PORT_START_FAILED, p_port->inx);
+
+                port_release_port (p_port);
+            }
+        }
+    }
+
+    /* There can be a situation when after starting connection, user closes the */
+    /* port, we can catch it here to close multiplexor channel */
+    if (no_ports_up)
+    {
+        rfc_check_mcb_active (p_mcb);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         PORT_StartInd
+**
+** Description      This function is called from the RFCOMM layer when
+**                  some peer device wants to establish a multiplexer
+**                  connection.  Check if there are any ports open with this
+**                  or not assigned multiplexer.
+**
+*******************************************************************************/
+void PORT_StartInd (tRFC_MCB *p_mcb)
+{
+    tPORT *p_port;
+    int   i;
+
+    RFCOMM_TRACE_EVENT ("PORT_StartInd");
+
+    p_port = &rfc_cb.port.port[0];
+    for (i = 0; i < MAX_RFC_PORTS; i++, p_port++)
+    {
+        if ((p_port->rfc.p_mcb == NULL)
+         || (p_port->rfc.p_mcb == p_mcb))
+        {
+            RFCOMM_TRACE_DEBUG("PORT_StartInd, RFCOMM_StartRsp RFCOMM_SUCCESS: p_mcb:%p", p_mcb);
+            RFCOMM_StartRsp (p_mcb, RFCOMM_SUCCESS);
+            return;
+        }
+    }
+    RFCOMM_StartRsp (p_mcb, RFCOMM_ERROR);
+}
+
+
+/*******************************************************************************
+**
+** Function         PORT_ParNegInd
+**
+** Description      This function is called from the RFCOMM layer to change
+**                  DLCI parameters (currently only MTU is negotiated).
+**                  If can not find the port do not accept the request.
+**                  Otherwise save the MTU size supported by the peer.
+**
+*******************************************************************************/
+void PORT_ParNegInd (tRFC_MCB *p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl, uint8_t k)
+{
+    tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+    uint8_t our_cl;
+    uint8_t our_k;
+
+    RFCOMM_TRACE_EVENT ("PORT_ParNegInd dlci:%d mtu:%d", dlci, mtu);
+
+    if (!p_port)
+    {
+        /* This can be a first request for this port */
+        p_port = port_find_dlci_port (dlci);
+        if (!p_port)
+        {
+            /* If the port cannot be opened, send a DM.  Per Errata 1205 */
+            rfc_send_dm(p_mcb, dlci, false);
+            /* check if this is the last port open, some headsets have
+            problem, they don't disconnect if we send DM */
+            rfc_check_mcb_active( p_mcb );
+            RFCOMM_TRACE_EVENT( "PORT_ParNegInd: port not found" );
+            return;
+        }
+        p_mcb->port_inx[dlci] = p_port->inx;
+    }
+
+    memcpy (p_port->bd_addr, p_mcb->bd_addr, BD_ADDR_LEN);
+
+    /* Connection is up and we know local and remote features, select MTU */
+    port_select_mtu (p_port);
+
+    p_port->rfc.p_mcb   = p_mcb;
+    p_port->mtu         = (p_port->mtu < mtu) ? p_port->mtu : mtu;
+    p_port->peer_mtu    = p_port->mtu;
+
+    /* Negotiate the flow control mechanism.  If flow control mechanism for */
+    /* mux has not been set yet, set it now.  If either we or peer wants TS 07.10, */
+    /* use that.  Otherwise both must want credit based, so use that. If flow is */
+    /* already defined for this mux, we respond with that value. */
+    if (p_mcb->flow == PORT_FC_UNDEFINED)
+    {
+        if ((PORT_FC_DEFAULT == PORT_FC_TS710) || (cl == RFCOMM_PN_CONV_LAYER_TYPE_1))
+        {
+            p_mcb->flow = PORT_FC_TS710;
+        }
+        else
+        {
+            p_mcb->flow = PORT_FC_CREDIT;
+        }
+    }
+
+    /* Regardless of our flow control mechanism, if the PN cl is zero, we must */
+    /* respond with zero.  "A responding implementation must set this field to 14 */
+    /* if (and only if) the PN request was 15."  This could happen if a PN is sent */
+    /* after the DLCI is already established-- the PN in that case must have cl = 0. */
+    /* See RFCOMM spec 5.5.3 */
+    if (cl == RFCOMM_PN_CONV_LAYER_TYPE_1)
+    {
+        our_cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
+        our_k = 0;
+    }
+    else if (p_mcb->flow == PORT_FC_CREDIT)
+    {
+        /* get credits */
+        port_get_credits (p_port, k);
+
+        /* Set convergence layer and number of credits (k) */
+        our_cl = RFCOMM_PN_CONV_LAYER_CBFC_R;
+        our_k = (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max : RFCOMM_K_MAX;
+        p_port->credit_rx = our_k;
+    }
+    else
+    {
+        /* must not be using credit based flow control; use TS 7.10 */
+        our_cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
+        our_k = 0;
+    }
+    RFCOMM_ParNegRsp (p_mcb, dlci, p_port->mtu, our_cl, our_k);
+}
+
+
+/*******************************************************************************
+**
+** Function         PORT_ParNegCnf
+**
+** Description      This function is called from the RFCOMM layer to change
+**                  DLCI parameters (currently only MTU is negotiated).
+**                  Save the MTU size supported by the peer.
+**                  If the confirmation is received during the port opening
+**                  procedure send EstablishRequest to continue.
+**
+*******************************************************************************/
+void PORT_ParNegCnf (tRFC_MCB *p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl, uint8_t k)
+{
+    tPORT   *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+    RFCOMM_TRACE_EVENT ("PORT_ParNegCnf dlci:%d mtu:%d cl: %d k: %d", dlci, mtu, cl, k);
+
+    if (!p_port)
+        return;
+
+    /* Flow control mechanism not set yet.  Negotiate flow control mechanism. */
+    if (p_mcb->flow == PORT_FC_UNDEFINED)
+    {
+        /* Our stack is configured for TS07.10 and they responded with credit-based. */
+        /* This is illegal-- negotiation fails. */
+        if ((PORT_FC_DEFAULT == PORT_FC_TS710) && (cl == RFCOMM_PN_CONV_LAYER_CBFC_R))
+        {
+            rfc_send_disc (p_mcb, p_port->dlci);
+            rfc_port_closed (p_port);
+            return;
+        }
+        /* Our stack is configured for credit-based and they responded with credit-based. */
+        else if (cl == RFCOMM_PN_CONV_LAYER_CBFC_R)
+        {
+            p_mcb->flow = PORT_FC_CREDIT;
+        }
+        /* They responded with any other value.  Treat this as negotiation to TS07.10. */
+        else
+        {
+            p_mcb->flow = PORT_FC_TS710;
+        }
+    }
+    /* If mux flow control mechanism set, we honor that setting regardless of */
+    /* the CL value in their response.  This allows us to gracefully accept any */
+    /* illegal PN negotiation scenarios. */
+
+    p_port->mtu         = (p_port->mtu < mtu) ? p_port->mtu : mtu;
+    p_port->peer_mtu    = p_port->mtu;
+
+    if (p_mcb->flow == PORT_FC_CREDIT)
+    {
+        port_get_credits (p_port, k);
+    }
+
+    if (p_port->state == PORT_STATE_OPENING)
+        RFCOMM_DlcEstablishReq (p_mcb, p_port->dlci, p_port->mtu);
+}
+
+
+/*******************************************************************************
+**
+** Function         PORT_DlcEstablishInd
+**
+** Description      This function is called from the RFCOMM layer when peer
+**                  device wants to establish a new DLC.  If this is not the
+**                  first message in the establishment procedure port_handle
+**                  has a handle to the port control block otherwise the control
+**                  block should be found based on the muliplexer channel and
+**                  dlci.  The block should be allocated allocated before
+**                  meaning that application already made open.
+**
+*******************************************************************************/
+void PORT_DlcEstablishInd (tRFC_MCB *p_mcb, uint8_t dlci, uint16_t mtu)
+{
+    tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+    RFCOMM_TRACE_DEBUG ("PORT_DlcEstablishInd p_mcb:%p, dlci:%d mtu:%di, p_port:%p", p_mcb, dlci, mtu, p_port);
+    RFCOMM_TRACE_DEBUG ("PORT_DlcEstablishInd p_mcb addr:%02x:%02x:%02x:%02x:%02x:%02x",
+                         p_mcb->bd_addr[0], p_mcb->bd_addr[1], p_mcb->bd_addr[2],
+                         p_mcb->bd_addr[3], p_mcb->bd_addr[4], p_mcb->bd_addr[5]);
+
+    if (!p_port)
+    {
+        /* This can be a first request for this port */
+        p_port = port_find_dlci_port (dlci);
+        if (!p_port)
+        {
+            RFCOMM_DlcEstablishRsp (p_mcb, dlci, 0, RFCOMM_ERROR);
+            return;
+        }
+        p_mcb->port_inx[dlci] = p_port->inx;
+    }
+
+    /* If L2CAP's mtu less then RFCOMM's take it */
+    if (mtu && (mtu < p_port->peer_mtu))
+        p_port->peer_mtu = mtu;
+
+    /* If there was an inactivity timer running for MCB stop it */
+    rfc_timer_stop (p_mcb);
+
+    RFCOMM_DlcEstablishRsp (p_mcb, dlci, p_port->mtu, RFCOMM_SUCCESS);
+
+    /* This is the server side.  If application wants to know when connection */
+    /* is established, thats the place */
+    if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECTED))
+        (p_port->p_callback)(PORT_EV_CONNECTED, p_port->inx);
+
+    if (p_port->p_mgmt_callback)
+        p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx);
+
+    p_port->state = PORT_STATE_OPENED;
+}
+
+
+/*******************************************************************************
+**
+** Function         PORT_DlcEstablishCnf
+**
+** Description      This function is called from the RFCOMM layer when peer
+**                  acknowledges establish procedure (SABME/UA).  Send reply
+**                  to the user and set state to OPENED if result was
+**                  successfull.
+**
+*******************************************************************************/
+void PORT_DlcEstablishCnf (tRFC_MCB *p_mcb, uint8_t dlci, uint16_t mtu, uint16_t result)
+{
+    tPORT  *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+    RFCOMM_TRACE_EVENT ("PORT_DlcEstablishCnf dlci:%d mtu:%d result:%d", dlci, mtu, result);
+
+    if (!p_port)
+        return;
+
+    if (result != RFCOMM_SUCCESS)
+    {
+        p_port->error = PORT_START_FAILED;
+        port_rfc_closed (p_port, PORT_START_FAILED);
+        return;
+    }
+
+    /* If L2CAP's mtu less then RFCOMM's take it */
+    if (mtu && (mtu < p_port->peer_mtu))
+        p_port->peer_mtu = mtu;
+
+    /* If there was an inactivity timer running for MCB stop it */
+    rfc_timer_stop (p_mcb);
+
+    if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECTED))
+        (p_port->p_callback)(PORT_EV_CONNECTED, p_port->inx);
+
+    if (p_port->p_mgmt_callback)
+        p_port->p_mgmt_callback (PORT_SUCCESS, p_port->inx);
+
+    p_port->state = PORT_STATE_OPENED;
+
+    /* RPN is required only if we want to tell DTE how the port should be opened */
+    if ((p_port->uuid == UUID_SERVCLASS_DIALUP_NETWORKING)
+     || (p_port->uuid == UUID_SERVCLASS_FAX))
+        RFCOMM_PortNegReq (p_port->rfc.p_mcb, p_port->dlci, NULL);
+    else
+        RFCOMM_ControlReq (p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl);
+}
+
+
+/*******************************************************************************
+**
+** Function         PORT_PortNegInd
+**
+** Description      This function is called from the RFCOMM layer when peer
+**                  device wants to set parameters of the port.  As per the spec
+**                  this message has to be sent before the first data packet
+**                  and can be sent before establish.  The block should be
+**                  allocated before meaning that application already made open.
+**
+*******************************************************************************/
+void PORT_PortNegInd (tRFC_MCB *p_mcb, uint8_t dlci, tPORT_STATE *p_pars,
+                      uint16_t param_mask)
+{
+    tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+    RFCOMM_TRACE_EVENT ("PORT_PortNegInd");
+
+    if (!p_port)
+    {
+        /* This can be a first request for this port */
+        p_port = port_find_dlci_port (dlci);
+        if (!p_port)
+        {
+            RFCOMM_PortNegRsp (p_mcb, dlci, p_pars, 0);
+            return;
+        }
+        p_mcb->port_inx[dlci] = p_port->inx;
+    }
+
+    /* Check if the flow control is acceptable on local side */
+    p_port->peer_port_pars = *p_pars;
+    RFCOMM_PortNegRsp (p_mcb, dlci, p_pars, param_mask);
+}
+
+
+/*******************************************************************************
+**
+** Function         PORT_PortNegCnf
+**
+** Description      This function is called from the RFCOMM layer to change
+**                  state for the port.  Propagate change to the user.
+**
+*******************************************************************************/
+void PORT_PortNegCnf (tRFC_MCB *p_mcb, uint8_t dlci,
+                      UNUSED_ATTR tPORT_STATE *p_pars, uint16_t result)
+{
+    tPORT  *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+    RFCOMM_TRACE_EVENT ("PORT_PortNegCnf");
+
+    if (!p_port)
+    {
+        RFCOMM_TRACE_WARNING ("PORT_PortNegCnf no port");
+        return;
+    }
+    /* Port negotiation failed. Drop the connection */
+    if (result != RFCOMM_SUCCESS)
+    {
+        p_port->error = PORT_PORT_NEG_FAILED;
+
+        RFCOMM_DlcReleaseReq (p_mcb, p_port->dlci);
+
+        port_rfc_closed (p_port, PORT_PORT_NEG_FAILED);
+        return;
+    }
+
+    if (!(p_port->port_ctrl & PORT_CTRL_REQ_SENT))
+    {
+        RFCOMM_ControlReq (p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl);
+    }
+    else
+    {
+        RFCOMM_TRACE_WARNING ("PORT_PortNegCnf Control Already sent");
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         PORT_ControlInd
+**
+** Description      This function is called from the RFCOMM layer on the modem
+**                  signal change.  Propagate change to the user.
+**
+*******************************************************************************/
+void PORT_ControlInd (tRFC_MCB *p_mcb, uint8_t dlci, tPORT_CTRL *p_pars)
+{
+    tPORT  *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+    uint32_t event;
+    uint8_t old_signals;
+
+    RFCOMM_TRACE_EVENT ("PORT_ControlInd");
+
+    if (!p_port)
+        return;
+
+    old_signals = p_port->peer_ctrl.modem_signal;
+
+    event = port_get_signal_changes (p_port, old_signals, p_pars->modem_signal);
+
+    p_port->peer_ctrl = *p_pars;
+
+    if (!(p_port->port_ctrl & PORT_CTRL_REQ_SENT))
+        RFCOMM_ControlReq (p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl);
+    else
+    {
+        /* If this is the first time we received control RFCOMM is connected */
+        if (!(p_port->port_ctrl & PORT_CTRL_IND_RECEIVED))
+        {
+            event |= (PORT_EV_CONNECTED & p_port->ev_mask);
+        }
+
+        if (p_port->port_ctrl & PORT_CTRL_REQ_CONFIRMED)
+        {
+            event |= port_rfc_send_tx_data(p_port);
+        }
+    }
+
+    p_port->port_ctrl |= (PORT_CTRL_IND_RECEIVED | PORT_CTRL_IND_RESPONDED);
+
+    if (p_pars->break_signal)
+        event |= (PORT_EV_BREAK & p_port->ev_mask);
+
+    /* execute call back function only if the application is registered for events */
+    if (event && p_port->p_callback)
+        (p_port->p_callback)(event, p_port->inx);
+
+    RFCOMM_TRACE_EVENT ("PORT_ControlInd DTR_DSR : %d, RTS_CTS : %d, RI : %d, DCD : %d",
+        ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_DTRDSR) ? 1 : 0),
+        ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_RTSCTS) ? 1 : 0),
+        ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_RI) ? 1 : 0),
+        ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_DCD) ? 1 : 0));
+
+}
+
+
+/*******************************************************************************
+**
+** Function         PORT_ControlCnf
+**
+** Description      This function is called from the RFCOMM layer when
+**                  peer acknowleges change of the modem signals.
+**
+*******************************************************************************/
+void PORT_ControlCnf (tRFC_MCB *p_mcb, uint8_t dlci,
+                      UNUSED_ATTR tPORT_CTRL *p_pars)
+{
+    tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+    uint32_t event = 0;
+
+    RFCOMM_TRACE_EVENT ("PORT_ControlCnf");
+
+    if (!p_port)
+        return;
+
+    if (!(p_port->port_ctrl & PORT_CTRL_REQ_CONFIRMED))
+    {
+        p_port->port_ctrl |= PORT_CTRL_REQ_CONFIRMED;
+
+        if (p_port->port_ctrl & PORT_CTRL_IND_RECEIVED)
+            event = (p_port->ev_mask & PORT_EV_CONNECTED);
+    }
+
+    if (p_port->port_ctrl & PORT_CTRL_IND_RECEIVED)
+    {
+        event |= port_rfc_send_tx_data(p_port);
+    }
+
+    /* execute call back function only if the application is registered for events */
+    if (event && p_port->p_callback)
+        (p_port->p_callback)(event, p_port->inx);
+}
+
+
+/*******************************************************************************
+**
+** Function         PORT_LineStatusInd
+**
+** Description      This function is called from the RFCOMM layer when
+**                  peer indicates change in the line status
+**
+*******************************************************************************/
+void PORT_LineStatusInd (tRFC_MCB *p_mcb, uint8_t dlci, uint8_t line_status)
+{
+    tPORT  *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+    uint32_t event = 0;
+
+    RFCOMM_TRACE_EVENT ("PORT_LineStatusInd");
+
+    if (!p_port)
+        return;
+
+    p_port->line_status |= line_status;
+
+    if (line_status & PORT_ERR_OVERRUN)
+        event |= PORT_EV_OVERRUN;
+
+    if (line_status & PORT_ERR_BREAK)
+        event |= PORT_EV_BREAK;
+
+    if (line_status & ~(PORT_ERR_OVERRUN | PORT_ERR_BREAK))
+        event |= PORT_EV_ERR;
+
+    if ((p_port->p_callback != NULL) && (p_port->ev_mask & event))
+          p_port->p_callback ((p_port->ev_mask & event), p_port->inx);
+}
+
+
+/*******************************************************************************
+**
+** Function         PORT_DlcReleaseInd
+**
+** Description      This function is called from the RFCOMM layer when
+**                  DLC connection is released.
+**
+*******************************************************************************/
+void PORT_DlcReleaseInd (tRFC_MCB *p_mcb, uint8_t dlci)
+{
+    tPORT  *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+
+    RFCOMM_TRACE_EVENT ("PORT_DlcReleaseInd");
+
+    if (!p_port)
+        return;
+
+    port_rfc_closed (p_port, PORT_CLOSED);
+}
+
+
+/*******************************************************************************
+**
+** Function         PORT_CloseInd
+**
+** Description      This function is called from the RFCOMM layer when
+**                  multiplexer connection is released.
+**
+*******************************************************************************/
+void PORT_CloseInd (tRFC_MCB *p_mcb)
+{
+    tPORT  *p_port;
+    int    i;
+
+    RFCOMM_TRACE_EVENT ("PORT_CloseInd");
+
+    p_port = &rfc_cb.port.port[0];
+    for (i = 0; i < MAX_RFC_PORTS; i++, p_port++)
+    {
+        if (p_port->rfc.p_mcb == p_mcb)
+        {
+            port_rfc_closed (p_port, PORT_PEER_CONNECTION_FAILED);
+        }
+    }
+    rfc_release_multiplexer_channel (p_mcb);
+}
+
+/*******************************************************************************
+**
+** Function         Port_TimeOutCloseMux
+**
+** Description      This function is called when RFCOMM timesout on a command
+**                  as a result multiplexer connection is closed.
+**
+*******************************************************************************/
+void Port_TimeOutCloseMux (tRFC_MCB *p_mcb)
+{
+    tPORT  *p_port;
+    int    i;
+
+    RFCOMM_TRACE_EVENT ("Port_TimeOutCloseMux");
+
+    p_port = &rfc_cb.port.port[0];
+    for (i = 0; i < MAX_RFC_PORTS; i++, p_port++)
+    {
+        if (p_port->rfc.p_mcb == p_mcb)
+        {
+            port_rfc_closed (p_port, PORT_PEER_TIMEOUT);
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         PORT_DataInd
+**
+** Description      This function is called from the RFCOMM layer when data
+**                  buffer is received from the peer.
+**
+*******************************************************************************/
+void PORT_DataInd (tRFC_MCB *p_mcb, uint8_t dlci, BT_HDR *p_buf)
+{
+    tPORT  *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+    uint8_t rx_char1;
+    uint32_t events = 0;
+    uint8_t *p;
+    int    i;
+
+    RFCOMM_TRACE_EVENT("PORT_DataInd with data length %d, p_mcb:%p,p_port:%p,dlci:%d",
+                        p_buf->len, p_mcb, p_port, dlci);
+    if (!p_port)
+    {
+        osi_free(p_buf);
+        return;
+    }
+    /* If client registered callout callback with flow control we can just deliver receive data */
+    if (p_port->p_data_co_callback)
+    {
+        /* Another packet is delivered to user.  Send credits to peer if required */
+
+        if(p_port->p_data_co_callback(p_port->inx, (uint8_t*)p_buf, -1, DATA_CO_CALLBACK_TYPE_INCOMING))
+            port_flow_control_peer(p_port, true, 1);
+        else port_flow_control_peer(p_port, false, 0);
+        //osi_free(p_buf);
+        return;
+    }
+    else RFCOMM_TRACE_ERROR("PORT_DataInd, p_port:%p, p_data_co_callback is null", p_port);
+    /* If client registered callback we can just deliver receive data */
+    if (p_port->p_data_callback)
+    {
+        /* Another packet is delivered to user.  Send credits to peer if required */
+        port_flow_control_peer(p_port, true, 1);
+
+        p_port->p_data_callback (p_port->inx, (uint8_t *)(p_buf + 1) + p_buf->offset, p_buf->len);
+        osi_free(p_buf);
+        return;
+    }
+
+    /* Check if rx queue exceeds the limit */
+    if ((p_port->rx.queue_size + p_buf->len > PORT_RX_CRITICAL_WM)
+     || (fixed_queue_length(p_port->rx.queue) + 1 > p_port->rx_buf_critical))
+    {
+        RFCOMM_TRACE_EVENT ("PORT_DataInd. Buffer over run. Dropping the buffer");
+        osi_free(p_buf);
+
+        RFCOMM_LineStatusReq (p_mcb, dlci, LINE_STATUS_OVERRUN);
+        return;
+    }
+
+    /* If user registered to receive notification when a particular byte is */
+    /* received we mast check all received bytes */
+    if (((rx_char1 = p_port->user_port_pars.rx_char1) != 0)
+     && (p_port->ev_mask & PORT_EV_RXFLAG))
+    {
+        for (i = 0, p = (uint8_t *)(p_buf + 1) + p_buf->offset; i < p_buf->len; i++)
+        {
+            if (*p++ == rx_char1)
+            {
+                events |= PORT_EV_RXFLAG;
+                break;
+            }
+        }
+    }
+
+    mutex_global_lock();
+
+    fixed_queue_enqueue(p_port->rx.queue, p_buf);
+    p_port->rx.queue_size += p_buf->len;
+
+    mutex_global_unlock();
+
+    /* perform flow control procedures if necessary */
+    port_flow_control_peer(p_port, false, 0);
+
+    /* If user indicated flow control can not deliver any notifications to him */
+    if (p_port->rx.user_fc)
+    {
+        if (events & PORT_EV_RXFLAG)
+            p_port->rx_flag_ev_pending = true;
+
+        return;
+    }
+
+    events |= PORT_EV_RXCHAR;
+
+    /* Mask out all events that are not of interest to user */
+    events &= p_port->ev_mask;
+
+    if (p_port->p_callback && events)
+        p_port->p_callback (events, p_port->inx);
+}
+
+
+/*******************************************************************************
+**
+** Function         PORT_FlowInd
+**
+** Description      This function is called from the RFCOMM layer on the flow
+**                  control signal change.  Propagate change to the user.
+**
+*******************************************************************************/
+void PORT_FlowInd (tRFC_MCB *p_mcb, uint8_t dlci, bool    enable_data)
+{
+    tPORT  *p_port = (tPORT *)NULL;
+    uint32_t events = 0;
+    int    i;
+
+    RFCOMM_TRACE_EVENT ("PORT_FlowInd fc:%d", enable_data);
+
+    if (dlci == 0)
+    {
+        p_mcb->peer_ready = enable_data;
+    }
+    else
+    {
+        if ((p_port = port_find_mcb_dlci_port (p_mcb, dlci)) == NULL)
+            return;
+
+        p_port->tx.peer_fc = !enable_data;
+    }
+
+    for (i = 0; i < MAX_RFC_PORTS; i++)
+    {
+        /* If DLCI is 0 event applies to all ports */
+        if (dlci == 0)
+        {
+            p_port = &rfc_cb.port.port[i];
+            if (!p_port->in_use
+             || (p_port->rfc.p_mcb != p_mcb)
+             || (p_port->rfc.state != RFC_STATE_OPENED))
+                continue;
+        }
+        events = 0;
+
+        /* Check if flow of data is still enabled */
+        events |= port_flow_control_user (p_port);
+
+        /* Check if data can be sent and send it */
+        events |= port_rfc_send_tx_data (p_port);
+
+        /* Mask out all events that are not of interest to user */
+        events &= p_port->ev_mask;
+
+        /* Send event to the application */
+        if (p_port->p_callback && events)
+            (p_port->p_callback)(events, p_port->inx);
+
+        /* If DLCI is not 0 event applies to one port only */
+        if (dlci != 0)
+            break;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         port_rfc_send_tx_data
+**
+** Description      This function is when forward data can be sent to the peer
+**
+*******************************************************************************/
+uint32_t port_rfc_send_tx_data (tPORT *p_port)
+{
+    uint32_t events = 0;
+    BT_HDR *p_buf;
+
+    /* if there is data to be sent */
+    if (p_port->tx.queue_size > 0)
+    {
+        /* while the rfcomm peer is not flow controlling us, and peer is ready */
+        while (!p_port->tx.peer_fc && p_port->rfc.p_mcb && p_port->rfc.p_mcb->peer_ready)
+        {
+            /* get data from tx queue and send it */
+            mutex_global_lock();
+
+            if ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->tx.queue)) != NULL)
+            {
+                p_port->tx.queue_size -= p_buf->len;
+
+                mutex_global_unlock();
+
+                RFCOMM_TRACE_DEBUG ("Sending RFCOMM_DataReq tx.queue_size=%d", p_port->tx.queue_size);
+
+                RFCOMM_DataReq (p_port->rfc.p_mcb, p_port->dlci, p_buf);
+
+                events |= PORT_EV_TXCHAR;
+
+                if (p_port->tx.queue_size == 0)
+                {
+                    events |= PORT_EV_TXEMPTY;
+                    break;
+                }
+            }
+            /* queue is empty-- all data sent */
+            else
+            {
+                mutex_global_unlock();
+
+                events |= PORT_EV_TXEMPTY;
+                break;
+            }
+        }
+        /* If we flow controlled user based on the queue size enable data again */
+        events |= port_flow_control_user (p_port);
+    }
+    return (events & p_port->ev_mask);
+}
+
+
+/*******************************************************************************
+**
+** Function         port_rfc_closed
+**
+** Description      This function when RFCOMM side of port is closed
+**
+*******************************************************************************/
+void port_rfc_closed (tPORT *p_port, uint8_t res)
+{
+    uint8_t   old_signals;
+    uint32_t  events = 0;
+    tRFC_MCB *p_mcb = p_port->rfc.p_mcb;
+
+    if ((p_port->state == PORT_STATE_OPENING) && (p_port->is_server))
+    {
+        /* The servr side has not been informed that connection is up, ignore */
+        RFCOMM_TRACE_EVENT ("port_rfc_closed in OPENING state ignored");
+
+        rfc_port_timer_stop (p_port);
+        p_port->rfc.state = RFC_STATE_CLOSED;
+
+        if (p_mcb)
+        {
+            p_mcb->port_inx[p_port->dlci] = 0;
+
+            /* If there are no more ports opened on this MCB release it */
+            rfc_check_mcb_active (p_mcb);
+            p_port->rfc.p_mcb = NULL;
+        }
+
+        /* Need to restore DLCI to listening state
+         * if the server was on the initiating RFC
+         */
+        p_port->dlci &= 0xfe;
+
+        return;
+    }
+
+    if ((p_port->state != PORT_STATE_CLOSING) && (p_port->state != PORT_STATE_CLOSED))
+    {
+        p_port->line_status |= LINE_STATUS_FAILED;
+
+        old_signals = p_port->peer_ctrl.modem_signal;
+
+        p_port->peer_ctrl.modem_signal &= ~(PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON);
+
+        events |= port_get_signal_changes (p_port, old_signals, p_port->peer_ctrl.modem_signal);
+
+        if(p_port->ev_mask & PORT_EV_CONNECT_ERR)
+            events |= PORT_EV_CONNECT_ERR;
+    }
+    RFCOMM_TRACE_EVENT ("port_rfc_closed state:%d sending events:%x", p_port->state, events);
+
+    if ((p_port->p_callback != NULL) && events)
+        p_port->p_callback (events, p_port->inx);
+
+    if (p_port->p_mgmt_callback)
+        p_port->p_mgmt_callback (res, p_port->inx);
+
+    p_port->rfc.state = RFC_STATE_CLOSED;
+
+    RFCOMM_TRACE_WARNING ("%s RFCOMM connection in state %d closed: %s (res: %d)",
+                          __func__, p_port->state, PORT_GetResultString(res), res);
+
+    port_release_port (p_port);
+}
+
+
+/*******************************************************************************
+**
+** Function         port_get_credits
+**
+** Description      Set initial values for credits.
+**                  Adjust max number of rx credits based on negotiated MTU.
+**                  Check max allowed num of bytes, max allowed num buffers,
+**                  should be less then 255
+**
+*******************************************************************************/
+void port_get_credits (tPORT *p_port, uint8_t k)
+{
+    p_port->credit_tx = k;
+    if (p_port->credit_tx == 0)
+        p_port->tx.peer_fc = true;
+}
diff --git a/bt/stack/rfcomm/port_utils.cc b/bt/stack/rfcomm/port_utils.cc
new file mode 100644
index 0000000..706062c
--- /dev/null
+++ b/bt/stack/rfcomm/port_utils.cc
@@ -0,0 +1,592 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *  Port Emulation entity utilities
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "osi/include/mutex.h"
+
+#include "bt_target.h"
+#include "bt_common.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "l2cdefs.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+#include "rfcdefs.h"
+
+static const tPORT_STATE default_port_pars =
+{
+    PORT_BAUD_RATE_9600,
+    PORT_8_BITS,
+    PORT_ONESTOPBIT,
+    PORT_PARITY_NO,
+    PORT_ODD_PARITY,
+    PORT_FC_OFF,
+    0,                      /* No rx_char */
+    PORT_XON_DC1,
+    PORT_XOFF_DC3,
+};
+
+
+
+/*******************************************************************************
+**
+** Function         port_allocate_port
+**
+** Description      Look through the Port Control Blocks for a free one.  Note
+**                  that one server can open several ports with the same SCN
+**                  if it can support simulteneous requests from different
+**                  clients.
+**
+** Returns          Pointer to the PORT or NULL if not found
+**
+*******************************************************************************/
+tPORT *port_allocate_port (uint8_t dlci, BD_ADDR bd_addr)
+{
+    tPORT  *p_port = &rfc_cb.port.port[0];
+    uint8_t xx, yy;
+
+    for (xx = 0, yy = rfc_cb.rfc.last_port + 1; xx < MAX_RFC_PORTS; xx++, yy++)
+    {
+        if (yy >= MAX_RFC_PORTS)
+            yy = 0;
+
+        p_port = &rfc_cb.port.port[yy];
+        if (!p_port->in_use)
+        {
+            memset(p_port, 0, sizeof (tPORT));
+
+            p_port->in_use = true;
+            p_port->inx    = yy + 1;
+
+            /* During the open set default state for the port connection */
+            port_set_defaults (p_port);
+
+            p_port->rfc.port_timer = alarm_new("rfcomm_port.port_timer");
+            rfc_cb.rfc.last_port = yy;
+
+            p_port->dlci   = dlci;
+            memcpy (p_port->bd_addr, bd_addr, BD_ADDR_LEN);
+
+            RFCOMM_TRACE_DEBUG("rfc_cb.port.port[%d]:%p allocated, last_port:%d", yy, p_port, rfc_cb.rfc.last_port);
+            RFCOMM_TRACE_DEBUG("port_allocate_port:bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
+                                bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+            return (p_port);
+        }
+    }
+
+    /* If here, no free PORT found */
+    return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         port_set_defaults
+**
+** Description      Set defualt port parameters
+**
+**
+*******************************************************************************/
+void port_set_defaults (tPORT *p_port)
+{
+    p_port->ev_mask        = 0;
+    p_port->p_callback     = NULL;
+    p_port->port_ctrl      = 0;
+    p_port->error          = 0;
+    p_port->line_status    = 0;
+    p_port->rx_flag_ev_pending = false;
+    p_port->peer_mtu       = RFCOMM_DEFAULT_MTU;
+
+    p_port->user_port_pars = default_port_pars;
+    p_port->peer_port_pars = default_port_pars;
+
+    p_port->credit_tx      = 0;
+    p_port->credit_rx      = 0;
+
+    memset (&p_port->local_ctrl, 0, sizeof (p_port->local_ctrl));
+    memset (&p_port->peer_ctrl, 0, sizeof (p_port->peer_ctrl));
+    memset (&p_port->rx, 0, sizeof (p_port->rx));
+    memset (&p_port->tx, 0, sizeof (p_port->tx));
+
+    p_port->tx.queue = fixed_queue_new(SIZE_MAX);
+    p_port->rx.queue = fixed_queue_new(SIZE_MAX);
+}
+
+/*******************************************************************************
+**
+** Function         port_select_mtu
+**
+** Description      Select MTU which will best serve connection from our
+**                  point of view.
+**                  If our device is 1.2 or lower we calculate how many DH5s
+**                  fit into 1 RFCOMM buffer.
+**
+**
+*******************************************************************************/
+void port_select_mtu (tPORT *p_port)
+{
+    uint16_t packet_size;
+
+    /* Will select MTU only if application did not setup something */
+    if (p_port->mtu == 0)
+    {
+        /* find packet size which connection supports */
+        packet_size = btm_get_max_packet_size (p_port->bd_addr);
+        if (packet_size == 0)
+        {
+            /* something is very wrong */
+            RFCOMM_TRACE_WARNING ("port_select_mtu bad packet size");
+            p_port->mtu = RFCOMM_DEFAULT_MTU;
+        }
+        else
+        {
+            /* We try to negotiate MTU that each packet can be split into whole
+            number of max packets.  For example if link is 1.2 max packet size is 339 bytes.
+            At first calculate how many whole packets it is.  MAX L2CAP is 1691 + 4 overhead.
+            1695, that will be 5 Dh5 packets.  Now maximum RFCOMM packet is
+            5 * 339 = 1695. Minus 4 bytes L2CAP header 1691.  Minus RFCOMM 6 bytes header overhead 1685
+
+            For EDR 2.0 packet size is 1027.  So we better send RFCOMM packet as 1 3DH5 packet
+            1 * 1027 = 1027.  Minus 4 bytes L2CAP header 1023.  Minus RFCOMM 6 bytes header overhead 1017 */
+            if ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) >= packet_size)
+            {
+                p_port->mtu = ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) / packet_size * packet_size) - RFCOMM_DATA_OVERHEAD - L2CAP_PKT_OVERHEAD;
+                RFCOMM_TRACE_DEBUG ("port_select_mtu selected %d based on connection speed", p_port->mtu);
+            }
+            else
+            {
+                p_port->mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
+                RFCOMM_TRACE_DEBUG ("port_select_mtu selected %d based on l2cap PDU size", p_port->mtu);
+            }
+        }
+    }
+    else
+    {
+        RFCOMM_TRACE_DEBUG ("port_select_mtu application selected %d", p_port->mtu);
+    }
+    p_port->credit_rx_max  = (PORT_RX_HIGH_WM / p_port->mtu);
+    if( p_port->credit_rx_max > PORT_RX_BUF_HIGH_WM )
+        p_port->credit_rx_max = PORT_RX_BUF_HIGH_WM;
+    p_port->credit_rx_low  = (PORT_RX_LOW_WM / p_port->mtu);
+    if( p_port->credit_rx_low > PORT_RX_BUF_LOW_WM )
+        p_port->credit_rx_low = PORT_RX_BUF_LOW_WM;
+    p_port->rx_buf_critical = (PORT_RX_CRITICAL_WM / p_port->mtu);
+    if( p_port->rx_buf_critical > PORT_RX_BUF_CRITICAL_WM )
+        p_port->rx_buf_critical = PORT_RX_BUF_CRITICAL_WM;
+    RFCOMM_TRACE_DEBUG ("port_select_mtu credit_rx_max %d, credit_rx_low %d, rx_buf_critical %d",
+                          p_port->credit_rx_max, p_port->credit_rx_low, p_port->rx_buf_critical);
+}
+
+/*******************************************************************************
+**
+** Function         port_release_port
+**
+** Description      Release port control block.
+**
+** Returns          Pointer to the PORT or NULL if not found
+**
+*******************************************************************************/
+void port_release_port(tPORT *p_port)
+{
+    RFCOMM_TRACE_DEBUG("%s p_port: %p state: %d keep_handle: %d", __func__,
+        p_port, p_port->rfc.state, p_port->keep_port_handle);
+
+    mutex_global_lock();
+    BT_HDR *p_buf;
+    while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->rx.queue)) != NULL)
+        osi_free(p_buf);
+    p_port->rx.queue_size = 0;
+
+    while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->tx.queue)) != NULL)
+        osi_free(p_buf);
+    p_port->tx.queue_size = 0;
+    mutex_global_unlock();
+
+    alarm_cancel(p_port->rfc.port_timer);
+
+    p_port->state = PORT_STATE_CLOSED;
+
+    if (p_port->rfc.state == RFC_STATE_CLOSED)
+    {
+        if (p_port->rfc.p_mcb)
+        {
+            p_port->rfc.p_mcb->port_inx[p_port->dlci] = 0;
+
+            /* If there are no more ports opened on this MCB release it */
+            rfc_check_mcb_active(p_port->rfc.p_mcb);
+        }
+
+        rfc_port_timer_stop (p_port);
+        fixed_queue_free(p_port->tx.queue, NULL);
+        p_port->tx.queue = NULL;
+        fixed_queue_free(p_port->rx.queue, NULL);
+        p_port->rx.queue = NULL;
+
+        if (p_port->keep_port_handle)
+        {
+            RFCOMM_TRACE_DEBUG("%s Re-initialize handle: %d", __func__, p_port->inx);
+
+            /* save event mask and callback */
+            uint32_t mask = p_port->ev_mask;
+            tPORT_CALLBACK *p_port_cb = p_port->p_callback;
+            tPORT_STATE user_port_pars = p_port->user_port_pars;
+
+            port_set_defaults(p_port);
+
+            /* restore */
+            p_port->ev_mask         = mask;
+            p_port->p_callback      = p_port_cb;
+            p_port->user_port_pars  = user_port_pars;
+            p_port->mtu             = p_port->keep_mtu;
+
+            p_port->state           = PORT_STATE_OPENING;
+            p_port->rfc.p_mcb       = NULL;
+            if (p_port->is_server)
+                p_port->dlci       &= 0xfe;
+
+            p_port->local_ctrl.modem_signal = p_port->default_signal_state;
+            memcpy (p_port->bd_addr, BT_BD_ANY, BD_ADDR_LEN);
+        } else {
+            RFCOMM_TRACE_DEBUG("%s Clean-up handle: %d", __func__, p_port->inx);
+            alarm_free(p_port->rfc.port_timer);
+            memset (p_port, 0, sizeof (tPORT));
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         port_find_mcb
+**
+** Description      This function checks if connection exists to device with
+**                  the BD_ADDR.
+**
+*******************************************************************************/
+tRFC_MCB *port_find_mcb (BD_ADDR bd_addr)
+{
+    int      i;
+
+    for (i = 0; i < MAX_BD_CONNECTIONS; i++)
+    {
+        if ((rfc_cb.port.rfc_mcb[i].state != RFC_MX_STATE_IDLE)
+         && !memcmp (rfc_cb.port.rfc_mcb[i].bd_addr, bd_addr, BD_ADDR_LEN))
+        {
+            /* Multiplexer channel found do not change anything */
+            RFCOMM_TRACE_DEBUG("port_find_mcb: found  bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
+                                bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+            RFCOMM_TRACE_DEBUG("port_find_mcb: rfc_cb.port.rfc_mcb:index:%d, %p, lcid:%d",
+                                i, &rfc_cb.port.rfc_mcb[i], rfc_cb.port.rfc_mcb[i].lcid);
+            return (&rfc_cb.port.rfc_mcb[i]);
+        }
+    }
+    RFCOMM_TRACE_DEBUG("port_find_mcb: not found, bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
+                         bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+    return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         port_find_mcb_dlci_port
+**
+** Description      Find port on the multiplexer channel based on DLCI.  If
+**                  this port with DLCI not found try to use even DLCI.  This
+**                  is for the case when client is establishing connection on
+**                  none-initiator MCB.
+**
+** Returns          Pointer to the PORT or NULL if not found
+**
+*******************************************************************************/
+tPORT *port_find_mcb_dlci_port (tRFC_MCB *p_mcb, uint8_t dlci)
+{
+    uint8_t inx;
+
+    if (!p_mcb)
+        return (NULL);
+
+    if (dlci > RFCOMM_MAX_DLCI)
+        return (NULL);
+
+    inx = p_mcb->port_inx[dlci];
+    if (inx == 0)
+    {
+        RFCOMM_TRACE_DEBUG("port_find_mcb_dlci_port: p_mcb:%p, port_inx[dlci:%d] is 0", p_mcb, dlci);
+        return (NULL);
+    }
+    else
+        return (&rfc_cb.port.port[inx - 1]);
+}
+
+
+/*******************************************************************************
+**
+** Function         port_find_dlci_port
+**
+** Description      Find port with DLCI not assigned to multiplexer channel
+**
+** Returns          Pointer to the PORT or NULL if not found
+**
+*******************************************************************************/
+tPORT *port_find_dlci_port (uint8_t dlci)
+{
+    uint16_t i;
+    tPORT  *p_port;
+
+    for (i = 0; i < MAX_RFC_PORTS; i++)
+    {
+        p_port = &rfc_cb.port.port[i];
+
+        if (p_port->in_use && (p_port->rfc.p_mcb == NULL))
+        {
+            if (p_port->dlci == dlci)
+            {
+                return (p_port);
+            }
+            else if ((dlci & 0x01) && (p_port->dlci == (dlci - 1)))
+            {
+                p_port->dlci++;
+                return (p_port);
+            }
+        }
+    }
+    return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         port_find_port
+**
+** Description      Find port with DLCI, BD_ADDR
+**
+** Returns          Pointer to the PORT or NULL if not found
+**
+*******************************************************************************/
+tPORT *port_find_port (uint8_t dlci, BD_ADDR bd_addr)
+{
+    uint16_t i;
+    tPORT  *p_port;
+
+    for (i = 0; i < MAX_RFC_PORTS; i++)
+    {
+        p_port = &rfc_cb.port.port[i];
+        if (p_port->in_use
+         && (p_port->dlci == dlci)
+         && !memcmp (p_port->bd_addr, bd_addr, BD_ADDR_LEN))
+        {
+            return (p_port);
+        }
+    }
+    return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         port_flow_control_user
+**
+** Description      Check the current user flow control and if necessary return
+**                  events to be send to the user based on the user's specified
+**                  flow control type.
+**
+** Returns          event mask to be returned to the application
+**
+*******************************************************************************/
+uint32_t port_flow_control_user (tPORT *p_port)
+{
+    uint32_t event = 0;
+
+    /* Flow control to the user can be caused by flow controlling by the peer */
+    /* (FlowInd, or flow control by the peer RFCOMM (Fcon) or internally if */
+    /* tx_queue is full */
+    bool    fc = p_port->tx.peer_fc
+              || !p_port->rfc.p_mcb
+              || !p_port->rfc.p_mcb->peer_ready
+              || (p_port->tx.queue_size > PORT_TX_HIGH_WM)
+              || (fixed_queue_length(p_port->tx.queue) > PORT_TX_BUF_HIGH_WM);
+
+    if (p_port->tx.user_fc == fc)
+        return (0);
+
+    p_port->tx.user_fc = fc;
+
+    if (fc)
+        event = PORT_EV_FC;
+    else
+        event = PORT_EV_FC | PORT_EV_FCS;
+
+    return (event);
+}
+
+
+/*******************************************************************************
+**
+** Function         port_get_signal_changes
+**
+** Description      Check modem signals that has been changed
+**
+** Returns          event mask to be returned to the application
+**
+*******************************************************************************/
+uint32_t port_get_signal_changes (tPORT *p_port, uint8_t old_signals, uint8_t signal)
+{
+    uint8_t changed_signals = (signal ^ old_signals);
+    uint32_t events = 0;
+
+    if (changed_signals & PORT_DTRDSR_ON)
+    {
+        events |= PORT_EV_DSR;
+
+        if (signal & PORT_DTRDSR_ON)
+            events |= PORT_EV_DSRS;
+    }
+
+    if (changed_signals & PORT_CTSRTS_ON)
+    {
+        events |= PORT_EV_CTS;
+
+        if (signal & PORT_CTSRTS_ON)
+            events |= PORT_EV_CTSS;
+    }
+
+    if (changed_signals & PORT_RING_ON)
+        events |= PORT_EV_RING;
+
+    if (changed_signals & PORT_DCD_ON)
+    {
+        events |= PORT_EV_RLSD;
+
+        if (signal & PORT_DCD_ON)
+            events |= PORT_EV_RLSDS;
+    }
+
+    return (p_port->ev_mask & events);
+}
+
+/*******************************************************************************
+**
+** Function         port_flow_control_peer
+**
+** Description      Send flow control messages to the peer for both enabling
+**                  and disabling flow control, for both credit-based and
+**                  TS 07.10 flow control mechanisms.
+**
+** Returns          nothing
+**
+*******************************************************************************/
+void port_flow_control_peer(tPORT *p_port, bool    enable, uint16_t count)
+{
+    if (!p_port->rfc.p_mcb)
+        return;
+
+    /* If using credit based flow control */
+    if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT)
+    {
+        /* if want to enable flow from peer */
+        if (enable)
+        {
+            /* update rx credits */
+            if (count > p_port->credit_rx)
+            {
+                p_port->credit_rx = 0;
+            }
+            else
+            {
+                p_port->credit_rx -= count;
+            }
+
+            /* If credit count is less than low credit watermark, and user */
+            /* did not force flow control, send a credit update */
+            /* There might be a special case when we just adjusted rx_max */
+            if ((p_port->credit_rx <= p_port->credit_rx_low)
+             && !p_port->rx.user_fc
+             && (p_port->credit_rx_max > p_port->credit_rx))
+            {
+                rfc_send_credit(p_port->rfc.p_mcb, p_port->dlci,
+                                (uint8_t) (p_port->credit_rx_max - p_port->credit_rx));
+
+                p_port->credit_rx = p_port->credit_rx_max;
+
+                p_port->rx.peer_fc = false;
+            }
+        }
+        /* else want to disable flow from peer */
+        else
+        {
+            /* if client registered data callback, just do what they want */
+            if (p_port->p_data_callback || p_port->p_data_co_callback)
+            {
+                p_port->rx.peer_fc = true;
+            }
+            /* if queue count reached credit rx max, set peer fc */
+            else if (fixed_queue_length(p_port->rx.queue) >= p_port->credit_rx_max)
+            {
+                p_port->rx.peer_fc = true;
+            }
+        }
+    }
+    /* else using TS 07.10 flow control */
+    else
+    {
+        /* if want to enable flow from peer */
+        if (enable)
+        {
+            /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
+            /* check if it can be resumed now */
+            if (p_port->rx.peer_fc
+             && (p_port->rx.queue_size < PORT_RX_LOW_WM)
+             && (fixed_queue_length(p_port->rx.queue) < PORT_RX_BUF_LOW_WM))
+            {
+                p_port->rx.peer_fc = false;
+
+                /* If user did not force flow control allow traffic now */
+                if (!p_port->rx.user_fc)
+                    RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, true);
+            }
+        }
+        /* else want to disable flow from peer */
+        else
+        {
+            /* if client registered data callback, just do what they want */
+            if (p_port->p_data_callback || p_port->p_data_co_callback)
+            {
+                p_port->rx.peer_fc = true;
+                RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, false);
+            }
+            /* Check the size of the rx queue.  If it exceeds certain */
+            /* level and flow control has not been sent to the peer do it now */
+            else if ( ((p_port->rx.queue_size > PORT_RX_HIGH_WM)
+                     || (fixed_queue_length(p_port->rx.queue) > PORT_RX_BUF_HIGH_WM))
+                     && !p_port->rx.peer_fc)
+            {
+                RFCOMM_TRACE_EVENT ("PORT_DataInd Data reached HW. Sending FC set.");
+
+                p_port->rx.peer_fc = true;
+                RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, false);
+            }
+        }
+    }
+}
+
diff --git a/bt/stack/rfcomm/rfc_int.h b/bt/stack/rfcomm/rfc_int.h
new file mode 100644
index 0000000..dd3259e
--- /dev/null
+++ b/bt/stack/rfcomm/rfc_int.h
@@ -0,0 +1,372 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 definitions internal to the RFC unit
+ *
+ *****************************************************************************/
+
+#ifndef RFC_INT_H
+#define RFC_INT_H
+
+#include "l2c_api.h"
+#include "port_int.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Define RFCOMM result codes
+*/
+#define RFCOMM_SUCCESS          0
+#define RFCOMM_ERROR            1
+#define RFCOMM_LOW_RESOURCES    2
+#define RFCOMM_TRY_LATER        3
+
+#define RFCOMM_USER_ERR         111
+#define RFCOMM_SECURITY_ERR     112
+
+/*
+** Define max and min RFCOMM MTU (N1)
+*/
+#define RFCOMM_MIN_MTU          23
+#define RFCOMM_MAX_MTU          32767
+
+extern void RFCOMM_StartReq (tRFC_MCB *p_mcb);
+extern void RFCOMM_StartRsp (tRFC_MCB *p_mcb, uint16_t result);
+
+extern void RFCOMM_DlcEstablishReq (tRFC_MCB *p_mcb, uint8_t dlci, uint16_t mtu);
+extern void RFCOMM_DlcEstablishRsp (tRFC_MCB *p_mcb, uint8_t dlci, uint16_t mtu, uint16_t result);
+
+extern void RFCOMM_DataReq (tRFC_MCB *p_mcb, uint8_t dlci, BT_HDR *p_buf);
+
+extern void RFCOMM_DlcReleaseReq (tRFC_MCB *p_mcb, uint8_t dlci);
+
+extern void RFCOMM_ParNegReq (tRFC_MCB *p_mcb, uint8_t dlci, uint16_t mtu);
+extern void RFCOMM_ParNegRsp (tRFC_MCB *p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl, uint8_t k);
+
+extern void RFCOMM_TestReq (uint8_t *p_data, uint16_t len);
+
+#define RFCOMM_FLOW_STATE_DISABLE       0
+#define RFCOMM_FLOW_STATE_ENABLE        1
+
+extern void RFCOMM_FlowReq (tRFC_MCB *p_mcb, uint8_t dlci, uint8_t state);
+
+extern void RFCOMM_PortNegReq (tRFC_MCB *p_mcb, uint8_t dlci, tPORT_STATE *p_pars);
+extern void RFCOMM_PortNegRsp (tRFC_MCB *p_mcb, uint8_t dlci, tPORT_STATE *p_pars, uint16_t param_mask);
+
+extern void RFCOMM_ControlReq (tRFC_MCB *p_mcb, uint8_t dlci, tPORT_CTRL *p_pars);
+extern void RFCOMM_ControlRsp (tRFC_MCB *p_mcb, uint8_t dlci, tPORT_CTRL *p_pars);
+
+extern void RFCOMM_LineStatusReq (tRFC_MCB *p_mcb, uint8_t dlci, uint8_t line_status);
+/*
+** Define logical struct used for sending and decoding MX frames
+*/
+typedef struct
+{
+    uint8_t dlci;
+    uint8_t type;
+    uint8_t cr;
+    uint8_t ea;
+    uint8_t pf;
+    uint8_t credit;
+
+    union
+    {
+        struct
+        {
+            uint8_t dlci;
+            uint8_t frame_type;
+            uint8_t conv_layer;
+            uint8_t priority;
+            uint8_t t1;
+            uint16_t mtu;
+            uint8_t n2;
+            uint8_t k;
+        } pn;
+        struct
+        {
+            uint8_t *p_data;
+            uint16_t data_len;
+        } test;
+        struct
+        {
+            uint8_t dlci;
+            uint8_t signals;
+            uint8_t break_present;
+            uint8_t break_duration;
+        } msc;
+        struct
+        {
+            uint8_t ea;
+            uint8_t cr;
+            uint8_t type;
+        } nsc;
+        struct
+        {
+            uint8_t dlci;
+            uint8_t is_request;
+            uint8_t baud_rate;
+            uint8_t byte_size;
+            uint8_t stop_bits;
+            uint8_t parity;
+            uint8_t parity_type;
+            uint8_t fc_type;
+            uint8_t xon_char;
+            uint8_t xoff_char;
+            uint16_t param_mask;
+        } rpn;
+        struct
+        {
+            uint8_t dlci;
+            uint8_t line_status;
+        } rls;
+    } u;
+} MX_FRAME;
+
+#define LINE_STATUS_NO_ERROR       0x00
+#define LINE_STATUS_OVERRUN        0x02  /* Receive Overrun Error   */
+#define LINE_STATUS_RXPARITY       0x04  /* Receive Parity Error    */
+#define LINE_STATUS_FRAME          0x08  /* Receive Framing error   */
+#define LINE_STATUS_FAILED         0x10  /* Connection Failed       */
+
+/*
+** Define states and events for the RFC multiplexer state machine
+*/
+#define RFC_MX_STATE_IDLE           0
+#define RFC_MX_STATE_WAIT_CONN_CNF  1
+#define RFC_MX_STATE_CONFIGURE      2
+#define RFC_MX_STATE_SABME_WAIT_UA  3
+#define RFC_MX_STATE_WAIT_SABME     4
+#define RFC_MX_STATE_CONNECTED      5
+#define RFC_MX_STATE_DISC_WAIT_UA   6
+
+/*
+** Define port states
+*/
+#define RFC_STATE_CLOSED                0
+#define RFC_STATE_SABME_WAIT_UA         1
+#define RFC_STATE_ORIG_WAIT_SEC_CHECK   2
+#define RFC_STATE_TERM_WAIT_SEC_CHECK   3
+#define RFC_STATE_OPENED                4
+#define RFC_STATE_DISC_WAIT_UA          5
+
+/*
+** Events that can be received by multiplexer as well as port state machines
+*/
+#define RFC_EVENT_SABME                 0
+#define RFC_EVENT_UA                    1
+#define RFC_EVENT_DM                    2
+#define RFC_EVENT_DISC                  3
+#define RFC_EVENT_UIH                   4
+#define RFC_EVENT_TIMEOUT               5
+#define RFC_EVENT_BAD_FRAME             50
+/*
+** Multiplexer events
+*/
+#define RFC_MX_EVENT_START_REQ          6
+#define RFC_MX_EVENT_START_RSP          7
+#define RFC_MX_EVENT_CLOSE_REQ          8
+#define RFC_MX_EVENT_CONN_CNF           9
+#define RFC_MX_EVENT_CONN_IND           10
+#define RFC_MX_EVENT_CONF_CNF           11
+#define RFC_MX_EVENT_CONF_IND           12
+#define RFC_MX_EVENT_QOS_VIOLATION_IND  13
+#define RFC_MX_EVENT_DISC_IND           14
+#define RFC_MX_EVENT_TEST_CMD           15
+#define RFC_MX_EVENT_TEST_RSP           16
+#define RFC_MX_EVENT_FCON_CMD           17
+#define RFC_MX_EVENT_FCOFF_CMD          18
+#define RFC_MX_EVENT_NSC                19
+#define RFC_MX_EVENT_NSC_RSP            20
+
+/*
+** Port events
+*/
+#define RFC_EVENT_OPEN                  9
+#define RFC_EVENT_ESTABLISH_RSP         11
+#define RFC_EVENT_CLOSE                 12
+#define RFC_EVENT_CLEAR                 13
+#define RFC_EVENT_DATA                  14
+#define RFC_EVENT_SEC_COMPLETE          15
+
+#define RFC_T1_TIMEOUT                  20   /* seconds to wait for reply with Poll bit */
+#define RFC_PORT_T1_TIMEOUT             60   /* seconds to wait for reply with Poll bit other than MX */
+#define RFC_T2_TIMEOUT                  20   /* timeout to wait for Mx UIH */
+#define RFC_DISC_TIMEOUT                3    /* If something goes wrong and we send DISC we should not wait for min */
+#define RFC_CLOSE_TIMEOUT               10
+#define RFCOMM_CONN_TIMEOUT            120   /* first connection to be established on Mx */
+
+
+/* Define RFComm control block
+*/
+typedef struct
+{
+    MX_FRAME  rx_frame;
+    tL2CAP_APPL_INFO  reg_info;              /* L2CAP Registration info */
+    tRFC_MCB *p_rfc_lcid_mcb[MAX_L2CAP_CHANNELS];     /* MCB based on the L2CAP's lcid */
+    bool      peer_rx_disabled;              /* If true peer sent FCOFF */
+    uint8_t   last_mux;                      /* Last mux allocated */
+    uint8_t   last_port;                     /* Last port allocated */
+} tRFCOMM_CB;
+
+/* Main Control Block for the RFCOMM Layer (PORT and RFC) */
+typedef struct
+{
+    tRFCOMM_CB  rfc;
+    tPORT_CB    port;
+    uint8_t     trace_level;
+} tRFC_CB;
+
+
+extern tRFC_CB rfc_cb;
+
+/* Timer running on the multiplexor channel while no DLCI connection is opened */
+#define RFC_MCB_INIT_INACT_TIMER    60  /* in seconds */
+
+/* Timer running on the multiplexor channel after last DLCI is released */
+#define RFC_MCB_RELEASE_INACT_TIMER 2   /* in seconds */
+
+/*
+** Define RFCOMM frame processing errors
+*/
+#define RFCOMM_ERR_BAD_SABME        1
+#define RFCOMM_ERR_BAD_UA           2
+#define RFCOMM_ERR_BAD_DM           3
+#define RFCOMM_ERR_BAD_DISC         4
+#define RFCOMM_ERR_BAD_UIH          5
+
+#ifdef RFCOMM_PRECALC_FCS
+
+#define RFCOMM_SABME_FCS(p_data, cr, dlci) rfc_sabme_fcs[cr][dlci]
+#define RFCOMM_UA_FCS(p_data, cr, dlci)    rfc_ua_fcs[cr][dlci]
+#define RFCOMM_DM_FCS(p_data, cr, dlci)    rfc_dm_fcs[cr][dlci]
+#define RFCOMM_DISC_FCS(p_data, cr, dlci)  rfc_disc_fcs[cr][dlci]
+#define RFCOMM_UIH_FCS(p_data, dlci)       rfc_uih_fcs[dlci]
+
+#else
+
+extern  uint8_t rfc_calc_fcs (uint16_t len, uint8_t *p);
+
+#define RFCOMM_SABME_FCS(p_data, cr, dlci) rfc_calc_fcs(3, p_data)
+#define RFCOMM_UA_FCS(p_data, cr, dlci)    rfc_calc_fcs(3, p_data)
+#define RFCOMM_DM_FCS(p_data, cr, dlci)    rfc_calc_fcs(3, p_data)
+#define RFCOMM_DISC_FCS(p_data, cr, dlci)  rfc_calc_fcs(3, p_data)
+#define RFCOMM_UIH_FCS(p_data, dlci)       rfc_calc_fcs(2, p_data)
+
+#endif
+
+extern void rfc_mx_sm_execute (tRFC_MCB *p_mcb, uint16_t event, void *p_data);
+
+/*
+** Functions provided by the rfc_port_fsm.cc
+*/
+extern void rfc_port_sm_execute (tPORT *p_port, uint16_t event, void *p_data);
+
+
+extern void rfc_process_pn (tRFC_MCB *p_rfc_mcb, bool    is_command, MX_FRAME *p_frame);
+extern void rfc_process_msc (tRFC_MCB *p_rfc_mcb, bool    is_command, MX_FRAME *p_frame);
+extern void rfc_process_rpn (tRFC_MCB *p_rfc_mcb, bool    is_command, bool    is_request, MX_FRAME *p_frame);
+extern void rfc_process_rls (tRFC_MCB *p_rfc_mcb, bool    is_command, MX_FRAME *p_frame);
+extern void rfc_process_nsc (tRFC_MCB *p_rfc_mcb, MX_FRAME *p_frame);
+extern void rfc_process_test_rsp (tRFC_MCB *p_rfc_mcb, BT_HDR *p_buf);
+extern void rfc_process_fcon (tRFC_MCB *p_rfc_mcb, bool    is_command);
+extern void rfc_process_fcoff (tRFC_MCB *p_rfc_mcb, bool    is_command);
+extern void rfc_process_l2cap_congestion (tRFC_MCB *p_mcb, bool    is_congested);
+
+/*
+** Functions provided by the rfc_utils.cc
+*/
+tRFC_MCB  *rfc_alloc_multiplexer_channel (BD_ADDR bd_addr, bool    is_initiator);
+extern void      rfc_release_multiplexer_channel (tRFC_MCB *p_rfc_mcb);
+extern void      rfc_timer_start (tRFC_MCB *p_rfc_mcb, uint16_t timeout);
+extern void      rfc_timer_stop (tRFC_MCB *p_rfc_mcb);
+extern void      rfc_port_timer_start (tPORT *p_port, uint16_t tout);
+extern void      rfc_port_timer_stop (tPORT *p_port);
+
+bool      rfc_check_uih_fcs (uint8_t dlci, uint8_t received_fcs);
+bool      rfc_check_fcs (uint16_t len, uint8_t *p, uint8_t received_fcs);
+tRFC_MCB  *rfc_find_lcid_mcb (uint16_t lcid);
+extern void      rfc_save_lcid_mcb (tRFC_MCB *p_rfc_mcb, uint16_t lcid);
+extern void      rfc_check_mcb_active (tRFC_MCB *p_mcb);
+extern void      rfc_port_closed (tPORT *p_port);
+extern void      rfc_sec_check_complete (BD_ADDR bd_addr, tBT_TRANSPORT transport,void *p_ref_data, uint8_t res);
+extern void      rfc_inc_credit (tPORT *p_port, uint8_t credit);
+extern void      rfc_dec_credit (tPORT *p_port);
+extern void      rfc_check_send_cmd(tRFC_MCB *p_mcb, BT_HDR *p_buf);
+
+/*
+** Functions provided by the rfc_ts_frames.cc
+*/
+extern void     rfc_send_sabme (tRFC_MCB *p_rfc_mcb, uint8_t dlci);
+extern void     rfc_send_ua (tRFC_MCB *p_rfc_mcb, uint8_t dlci);
+extern void     rfc_send_dm (tRFC_MCB *p_rfc_mcb, uint8_t dlci, bool    pf);
+extern void     rfc_send_disc (tRFC_MCB *p_rfc_mcb, uint8_t dlci);
+extern void     rfc_send_pn (tRFC_MCB *p_mcb, uint8_t dlci, bool    is_command, uint16_t mtu,
+                             uint8_t cl, uint8_t k);
+extern void     rfc_send_test (tRFC_MCB *p_rfc_mcb, bool    is_command, BT_HDR *p_buf);
+extern void     rfc_send_msc (tRFC_MCB *p_mcb, uint8_t dlci, bool    is_command,
+                              tPORT_CTRL *p_pars);
+extern void     rfc_send_rls (tRFC_MCB *p_mcb, uint8_t dlci, bool    is_command, uint8_t status);
+extern void     rfc_send_rpn (tRFC_MCB *p_mcb, uint8_t dlci, bool    is_command,
+                              tPORT_STATE *p_pars, uint16_t mask);
+extern void     rfc_send_fcon (tRFC_MCB *p_mcb, bool    is_command);
+extern void     rfc_send_fcoff (tRFC_MCB *p_mcb, bool    is_command);
+extern void     rfc_send_buf_uih (tRFC_MCB *p_rfc_mcb, uint8_t dlci, BT_HDR *p_buf);
+extern void     rfc_send_credit(tRFC_MCB *p_mcb, uint8_t dlci, uint8_t credit);
+extern void     rfc_process_mx_message (tRFC_MCB *p_rfc_mcb, BT_HDR *p_buf);
+extern uint8_t  rfc_parse_data (tRFC_MCB *p_rfc_mcb, MX_FRAME *p_frame, BT_HDR *p_buf);
+
+/* Call back functions from RFCOMM */
+extern void rfcomm_l2cap_if_init (void);
+
+extern void PORT_StartInd (tRFC_MCB *p_mcb);
+extern void PORT_StartCnf (tRFC_MCB *p_mcb, uint16_t result);
+
+extern void PORT_CloseInd (tRFC_MCB *p_mcb);
+extern void Port_TimeOutCloseMux (tRFC_MCB *p_mcb);
+
+extern void PORT_DlcEstablishInd (tRFC_MCB *p_mcb, uint8_t dlci, uint16_t mtu);
+extern void PORT_DlcEstablishCnf (tRFC_MCB *p_mcb, uint8_t dlci, uint16_t mtu, uint16_t result);
+
+extern void PORT_DataInd (tRFC_MCB *p_mcb, uint8_t dlci, BT_HDR *p_buf);
+
+extern void PORT_DlcReleaseInd (tRFC_MCB *p_mcb, uint8_t dlci);
+
+extern void PORT_ParNegInd (tRFC_MCB *p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl, uint8_t k);
+extern void PORT_ParNegCnf (tRFC_MCB *p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl, uint8_t k);
+
+extern void PORT_TestCnf (tRFC_MCB *p_mcb, uint8_t *p_data, uint16_t len);
+
+extern void PORT_FlowInd (tRFC_MCB *p_mcb, uint8_t dlci, bool    fc);
+
+extern void PORT_PortNegInd (tRFC_MCB *p_mcb, uint8_t dlci, tPORT_STATE *p_pars, uint16_t param_mask);
+extern void PORT_PortNegCnf (tRFC_MCB *p_mcb, uint8_t dlci, tPORT_STATE *p_pars, uint16_t result);
+
+extern void PORT_ControlInd (tRFC_MCB *p_mcb, uint8_t dlci, tPORT_CTRL *p_pars);
+extern void PORT_ControlCnf (tRFC_MCB *p_mcb, uint8_t dlci, tPORT_CTRL *p_pars);
+
+extern void PORT_LineStatusInd (tRFC_MCB *p_mcb, uint8_t dlci, uint8_t line_status);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bt/stack/rfcomm/rfc_l2cap_if.cc b/bt/stack/rfcomm/rfc_l2cap_if.cc
new file mode 100644
index 0000000..a8c3043
--- /dev/null
+++ b/bt/stack/rfcomm/rfc_l2cap_if.cc
@@ -0,0 +1,452 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 L2CAP interface functions
+ *
+ ******************************************************************************/
+
+#include <stddef.h>
+#include "bt_target.h"
+
+#include "osi/include/osi.h"
+#include "osi/include/time.h"
+#include "bt_common.h"
+
+#include "rfcdefs.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "rfc_int.h"
+#include "bt_utils.h"
+
+
+/*
+** Define Callback functions to be called by L2CAP
+*/
+static void RFCOMM_ConnectInd (BD_ADDR bd_addr, uint16_t lcid, uint16_t psm, uint8_t id);
+static void RFCOMM_ConnectCnf (uint16_t lcid, uint16_t err);
+static void RFCOMM_ConfigInd (uint16_t lcid, tL2CAP_CFG_INFO *p_cfg);
+static void RFCOMM_ConfigCnf (uint16_t lcid, tL2CAP_CFG_INFO *p_cfg);
+static void RFCOMM_DisconnectInd (uint16_t lcid, bool    is_clear);
+static void RFCOMM_QoSViolationInd (UNUSED_ATTR BD_ADDR bd_addr);
+static void RFCOMM_BufDataInd (uint16_t lcid, BT_HDR *p_buf);
+static void RFCOMM_CongestionStatusInd (uint16_t lcid, bool    is_congested);
+
+
+/*******************************************************************************
+**
+** Function         rfcomm_l2cap_if_init
+**
+** Description      This function is called during the RFCOMM task startup
+**                  to register interface functions with L2CAP.
+**
+*******************************************************************************/
+void rfcomm_l2cap_if_init (void)
+{
+    tL2CAP_APPL_INFO *p_l2c = &rfc_cb.rfc.reg_info;
+
+    p_l2c->pL2CA_ConnectInd_Cb       = RFCOMM_ConnectInd;
+    p_l2c->pL2CA_ConnectCfm_Cb       = RFCOMM_ConnectCnf;
+    p_l2c->pL2CA_ConnectPnd_Cb       = NULL;
+    p_l2c->pL2CA_ConfigInd_Cb        = RFCOMM_ConfigInd;
+    p_l2c->pL2CA_ConfigCfm_Cb        = RFCOMM_ConfigCnf;
+    p_l2c->pL2CA_DisconnectInd_Cb    = RFCOMM_DisconnectInd;
+    p_l2c->pL2CA_DisconnectCfm_Cb    = NULL;
+    p_l2c->pL2CA_QoSViolationInd_Cb  = RFCOMM_QoSViolationInd;
+    p_l2c->pL2CA_DataInd_Cb          = RFCOMM_BufDataInd;
+    p_l2c->pL2CA_CongestionStatus_Cb = RFCOMM_CongestionStatusInd;
+    p_l2c->pL2CA_TxComplete_Cb       = NULL;
+
+
+    L2CA_Register (BT_PSM_RFCOMM, p_l2c);
+}
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_ConnectInd
+**
+** Description      This is a callback function called by L2CAP when
+**                  L2CA_ConnectInd received.  Allocate multiplexer control block
+**                  and dispatch the event to it.
+**
+*******************************************************************************/
+void RFCOMM_ConnectInd (BD_ADDR bd_addr, uint16_t lcid,
+                        UNUSED_ATTR uint16_t psm, uint8_t id)
+{
+    tRFC_MCB *p_mcb = rfc_alloc_multiplexer_channel(bd_addr, false);
+
+    if ((p_mcb)&&(p_mcb->state != RFC_MX_STATE_IDLE))
+    {
+        /* if this is collision case */
+        if ((p_mcb->is_initiator)&&(p_mcb->state == RFC_MX_STATE_WAIT_CONN_CNF))
+        {
+            p_mcb->pending_lcid = lcid;
+            p_mcb->pending_id   = id;
+
+            /* wait random timeout (2 - 12) to resolve collision */
+            /* if peer gives up then local device rejects incoming connection and continues as initiator */
+            /* if timeout, local device disconnects outgoing connection and continues as acceptor */
+            RFCOMM_TRACE_DEBUG ("RFCOMM_ConnectInd start timer for collision, initiator's LCID(0x%x), acceptor's LCID(0x%x)",
+                                  p_mcb->lcid, p_mcb->pending_lcid);
+
+            rfc_timer_start(p_mcb, (uint16_t)(time_get_os_boottime_ms() % 10 + 2));
+            return;
+        }
+        else
+        {
+            /* we cannot accept connection request from peer at this state */
+            /* don't update lcid */
+            p_mcb = NULL;
+        }
+    }
+    else
+    {
+        /* store mcb even if null */
+        rfc_save_lcid_mcb (p_mcb, lcid);
+    }
+
+    if (p_mcb == NULL)
+    {
+        L2CA_ConnectRsp (bd_addr, id, lcid, L2CAP_CONN_NO_RESOURCES, 0);
+        return;
+    }
+    p_mcb->lcid     = lcid;
+
+    rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONN_IND, &id);
+}
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_ConnectCnf
+**
+** Description      This is a callback function called by L2CAP when
+**                  L2CA_ConnectCnf received.  Save L2CAP handle and dispatch
+**                  event to the FSM.
+**
+*******************************************************************************/
+void RFCOMM_ConnectCnf (uint16_t lcid, uint16_t result)
+{
+    tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid);
+
+    if (!p_mcb)
+    {
+        RFCOMM_TRACE_ERROR ("RFCOMM_ConnectCnf LCID:0x%x", lcid);
+        return;
+    }
+
+    if (p_mcb->pending_lcid)
+    {
+        /* if peer rejects our connect request but peer's connect request is pending */
+        if (result != L2CAP_CONN_OK )
+        {
+            uint16_t i;
+            uint8_t idx;
+
+            RFCOMM_TRACE_DEBUG ("RFCOMM_ConnectCnf retry as acceptor on pending LCID(0x%x)", p_mcb->pending_lcid);
+
+            /* remove mcb from mapping table */
+            rfc_save_lcid_mcb (NULL, p_mcb->lcid);
+
+            p_mcb->lcid         = p_mcb->pending_lcid;
+            p_mcb->is_initiator = false;
+            p_mcb->state        = RFC_MX_STATE_IDLE;
+
+            /* store mcb into mapping table */
+            rfc_save_lcid_mcb (p_mcb, p_mcb->lcid);
+
+            /* update direction bit */
+            for (i = 0; i < RFCOMM_MAX_DLCI; i += 2)
+            {
+                if ((idx = p_mcb->port_inx[i]) != 0)
+                {
+                    p_mcb->port_inx[i] = 0;
+                    p_mcb->port_inx[i+1] = idx;
+                    rfc_cb.port.port[idx - 1].dlci += 1;
+                    RFCOMM_TRACE_DEBUG ("RFCOMM MX - DLCI:%d -> %d", i, rfc_cb.port.port[idx - 1].dlci);
+                }
+            }
+
+            rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONN_IND, &(p_mcb->pending_id));
+            return;
+        }
+        else
+        {
+            RFCOMM_TRACE_DEBUG ("RFCOMM_ConnectCnf peer gave up pending LCID(0x%x)", p_mcb->pending_lcid);
+
+            /* Peer gave up his connection request, make sure cleaning up L2CAP channel */
+            L2CA_ConnectRsp (p_mcb->bd_addr, p_mcb->pending_id, p_mcb->pending_lcid, L2CAP_CONN_NO_RESOURCES, 0);
+
+            p_mcb->pending_lcid = 0;
+        }
+    }
+
+    /* Save LCID to be used in all consecutive calls to L2CAP */
+    p_mcb->lcid         = lcid;
+
+    rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONN_CNF, &result);
+}
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_ConfigInd
+**
+** Description      This is a callback function called by L2CAP when
+**                  L2CA_ConfigInd received.  Save parameters in the control
+**                  block and dispatch event to the FSM.
+**
+*******************************************************************************/
+void RFCOMM_ConfigInd (uint16_t lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+    tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid);
+
+    if (!p_mcb)
+    {
+        RFCOMM_TRACE_ERROR ("RFCOMM_ConfigInd LCID:0x%x", lcid);
+        return;
+    }
+
+    rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONF_IND, (void *)p_cfg);
+}
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_ConfigCnf
+**
+** Description      This is a callback function called by L2CAP when
+**                  L2CA_ConfigCnf received.  Save L2CAP handle and dispatch
+**                  event to the FSM.
+**
+*******************************************************************************/
+void RFCOMM_ConfigCnf (uint16_t lcid, tL2CAP_CFG_INFO *p_cfg)
+{
+    tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid);
+
+    if (!p_mcb)
+    {
+        RFCOMM_TRACE_ERROR ("RFCOMM_ConfigCnf no MCB LCID:0x%x", lcid);
+        return;
+    }
+
+    rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONF_CNF, (void *)p_cfg);
+}
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_QoSViolationInd
+**
+** Description      This is a callback function called by L2CAP when
+**                  L2CA_QoSViolationIndInd received.  Dispatch event to the FSM.
+**
+*******************************************************************************/
+void RFCOMM_QoSViolationInd (UNUSED_ATTR BD_ADDR bd_addr)
+{
+}
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_DisconnectInd
+**
+** Description      This is a callback function called by L2CAP when
+**                  L2CA_DisconnectInd received.  Dispatch event to the FSM.
+**
+*******************************************************************************/
+void RFCOMM_DisconnectInd (uint16_t lcid, bool    is_conf_needed)
+{
+    tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid);
+
+    if (is_conf_needed)
+    {
+        L2CA_DisconnectRsp (lcid);
+    }
+
+    if (!p_mcb)
+    {
+        RFCOMM_TRACE_WARNING ("RFCOMM_DisconnectInd LCID:0x%x", lcid);
+        return;
+    }
+
+    rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_DISC_IND, NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_BufDataInd
+**
+** Description      This is a callback function called by L2CAP when
+**                  data RFCOMM frame is received.  Parse the frames, check
+**                  the checksum and dispatch event to multiplexer or port
+**                  state machine depending on the frame destination.
+**
+*******************************************************************************/
+void RFCOMM_BufDataInd (uint16_t lcid, BT_HDR *p_buf)
+{
+    tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid);
+    tPORT    *p_port;
+    uint8_t  event;
+
+
+    if (!p_mcb)
+    {
+        RFCOMM_TRACE_WARNING ("RFCOMM_BufDataInd LCID:0x%x", lcid);
+        osi_free(p_buf);
+        return;
+    }
+
+    event = rfc_parse_data (p_mcb, &rfc_cb.rfc.rx_frame, p_buf);
+
+    /* If the frame did not pass validation just ignore it */
+    if (event == RFC_EVENT_BAD_FRAME)
+    {
+        osi_free(p_buf);
+        return;
+    }
+
+    if (rfc_cb.rfc.rx_frame.dlci == RFCOMM_MX_DLCI)
+    {
+        /* Take special care of the Multiplexer Control Messages */
+        if (event == RFC_EVENT_UIH)
+        {
+            rfc_process_mx_message (p_mcb, p_buf);
+            return;
+        }
+
+        /* Other multiplexer events go to state machine */
+        rfc_mx_sm_execute (p_mcb, event, NULL);
+        osi_free(p_buf);
+        return;
+    }
+
+    /* The frame was received on the data channel DLCI, verify that DLC exists */
+    if (((p_port = port_find_mcb_dlci_port (p_mcb, rfc_cb.rfc.rx_frame.dlci)) == NULL)
+     || (!p_port->rfc.p_mcb))
+    {
+        /* If this is a SABME on the new port, check if any appl is waiting for it */
+        if (event != RFC_EVENT_SABME)
+        {
+            if (( p_mcb->is_initiator && !rfc_cb.rfc.rx_frame.cr)
+             || (!p_mcb->is_initiator &&  rfc_cb.rfc.rx_frame.cr))
+                rfc_send_dm (p_mcb, rfc_cb.rfc.rx_frame.dlci, rfc_cb.rfc.rx_frame.pf);
+            osi_free(p_buf);
+            return;
+        }
+
+        if ((p_port = port_find_dlci_port (rfc_cb.rfc.rx_frame.dlci)) == NULL)
+        {
+            rfc_send_dm (p_mcb, rfc_cb.rfc.rx_frame.dlci, true);
+            osi_free(p_buf);
+            return;
+        }
+        p_mcb->port_inx[rfc_cb.rfc.rx_frame.dlci] = p_port->inx;
+        p_port->rfc.p_mcb = p_mcb;
+    }
+
+    if (event == RFC_EVENT_UIH)
+    {
+
+        if (p_buf->len > 0)
+            rfc_port_sm_execute (p_port, event, p_buf);
+        else
+            osi_free(p_buf);
+
+        if (rfc_cb.rfc.rx_frame.credit != 0)
+            rfc_inc_credit (p_port, rfc_cb.rfc.rx_frame.credit);
+
+        return;
+    }
+    rfc_port_sm_execute (p_port, event,  NULL);
+    osi_free(p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         RFCOMM_CongestionStatusInd
+**
+** Description      This is a callback function called by L2CAP when
+**                  data RFCOMM L2CAP congestion status changes
+**
+*******************************************************************************/
+void RFCOMM_CongestionStatusInd (uint16_t lcid, bool    is_congested)
+{
+    tRFC_MCB *p_mcb = rfc_find_lcid_mcb (lcid);
+
+    if (!p_mcb)
+    {
+        RFCOMM_TRACE_ERROR ("RFCOMM_CongestionStatusInd dropped LCID:0x%x", lcid);
+        return;
+    }
+    else
+    {
+        RFCOMM_TRACE_EVENT ("RFCOMM_CongestionStatusInd LCID:0x%x", lcid);
+    }
+    rfc_process_l2cap_congestion (p_mcb, is_congested);
+}
+
+/*******************************************************************************
+**
+** Function         rfc_find_lcid_mcb
+**
+** Description      This function returns MCB block supporting local cid
+**
+*******************************************************************************/
+tRFC_MCB *rfc_find_lcid_mcb (uint16_t lcid)
+{
+    tRFC_MCB *p_mcb;
+
+    if (lcid - L2CAP_BASE_APPL_CID >= MAX_L2CAP_CHANNELS)
+    {
+        RFCOMM_TRACE_ERROR ("rfc_find_lcid_mcb LCID:0x%x", lcid);
+        return (NULL);
+    }
+    else
+    {
+        if ((p_mcb = rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID]) != NULL)
+        {
+            if (p_mcb->lcid != lcid)
+            {
+                RFCOMM_TRACE_WARNING ("rfc_find_lcid_mcb LCID reused LCID:0x%x current:0x%x", lcid, p_mcb->lcid);
+                return (NULL);
+            }
+        }
+    }
+    return (p_mcb);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_save_lcid_mcb
+**
+** Description      This function returns MCB block supporting local cid
+**
+*******************************************************************************/
+void rfc_save_lcid_mcb(tRFC_MCB *p_mcb, uint16_t lcid)
+{
+    if (lcid < L2CAP_BASE_APPL_CID)
+        return;
+    rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID] = p_mcb;
+}
diff --git a/bt/stack/rfcomm/rfc_mx_fsm.cc b/bt/stack/rfcomm/rfc_mx_fsm.cc
new file mode 100644
index 0000000..62a4869
--- /dev/null
+++ b/bt/stack/rfcomm/rfc_mx_fsm.cc
@@ -0,0 +1,680 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 state machine and action routines for multiplexer
+ *  channel of the RFCOMM unit
+ *
+ ******************************************************************************/
+#include <string.h>
+#include "bt_common.h"
+#include "bt_types.h"
+#include "rfcdefs.h"
+#include "l2cdefs.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "l2c_api.h"
+#include "rfc_int.h"
+#include "bt_utils.h"
+#include "osi/include/osi.h"
+
+#define L2CAP_SUCCESS   0
+#define L2CAP_ERROR     1
+
+
+/********************************************************************************/
+/*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
+/********************************************************************************/
+static void rfc_mx_sm_state_idle (tRFC_MCB *p_mcb, uint16_t event, void *p_data);
+static void rfc_mx_sm_state_wait_conn_cnf (tRFC_MCB *p_mcb, uint16_t event, void *p_data);
+static void rfc_mx_sm_state_configure (tRFC_MCB *p_mcb, uint16_t event, void *p_data);
+static void rfc_mx_sm_sabme_wait_ua (tRFC_MCB *p_mcb, uint16_t event, void *p_data);
+static void rfc_mx_sm_state_wait_sabme (tRFC_MCB *p_mcb, uint16_t event, void *p_data);
+static void rfc_mx_sm_state_connected (tRFC_MCB *p_mcb, uint16_t event,
+				       UNUSED_ATTR void *p_data);
+static void rfc_mx_sm_state_disc_wait_ua (tRFC_MCB *p_mcb, uint16_t event, void *p_data);
+
+static void rfc_mx_send_config_req (tRFC_MCB *p_mcb);
+static void rfc_mx_conf_ind (tRFC_MCB *p_mcb, tL2CAP_CFG_INFO *p_cfg);
+static void rfc_mx_conf_cnf (tRFC_MCB *p_mcb, tL2CAP_CFG_INFO *p_cfg);
+
+
+
+/*******************************************************************************
+**
+** Function         rfc_mx_sm_execute
+**
+** Description      This function sends multiplexor events through the state
+**                  machine.
+**
+** Returns          void
+**
+*******************************************************************************/
+void rfc_mx_sm_execute (tRFC_MCB *p_mcb, uint16_t event, void *p_data)
+{
+    switch (p_mcb->state)
+    {
+    case RFC_MX_STATE_IDLE:
+        rfc_mx_sm_state_idle (p_mcb, event, p_data);
+        break;
+
+    case RFC_MX_STATE_WAIT_CONN_CNF:
+        rfc_mx_sm_state_wait_conn_cnf (p_mcb, event, p_data);
+        break;
+
+    case RFC_MX_STATE_CONFIGURE:
+        rfc_mx_sm_state_configure (p_mcb, event, p_data);
+        break;
+
+    case RFC_MX_STATE_SABME_WAIT_UA:
+        rfc_mx_sm_sabme_wait_ua (p_mcb, event, p_data);
+        break;
+
+    case RFC_MX_STATE_WAIT_SABME:
+        rfc_mx_sm_state_wait_sabme (p_mcb, event, p_data);
+        break;
+
+    case RFC_MX_STATE_CONNECTED:
+        rfc_mx_sm_state_connected (p_mcb, event, p_data);
+        break;
+
+    case RFC_MX_STATE_DISC_WAIT_UA:
+        rfc_mx_sm_state_disc_wait_ua (p_mcb, event, p_data);
+        break;
+
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_mx_sm_state_idle
+**
+** Description      This function handles events when the multiplexer is in
+**                  IDLE state. This state exists when connection is being
+**                  initially established.
+**
+** Returns          void
+**
+*******************************************************************************/
+void rfc_mx_sm_state_idle (tRFC_MCB *p_mcb, uint16_t event, void *p_data)
+{
+    RFCOMM_TRACE_EVENT ("rfc_mx_sm_state_idle - evt:%d", event);
+    switch (event)
+    {
+    case RFC_MX_EVENT_START_REQ:
+    {
+        /* Initialize L2CAP MTU */
+        p_mcb->peer_l2cap_mtu = L2CAP_DEFAULT_MTU - RFCOMM_MIN_OFFSET - 1;
+
+        uint16_t lcid = L2CA_ConnectReq(BT_PSM_RFCOMM, p_mcb->bd_addr);
+        if (lcid == 0) {
+            rfc_save_lcid_mcb(NULL, p_mcb->lcid);
+            p_mcb->lcid = 0;
+            PORT_StartCnf(p_mcb, RFCOMM_ERROR);
+            return;
+        }
+        p_mcb->lcid = lcid;
+        /* Save entry for quicker access to mcb based on the LCID */
+        rfc_save_lcid_mcb (p_mcb, p_mcb->lcid);
+
+        p_mcb->state = RFC_MX_STATE_WAIT_CONN_CNF;
+        return;
+    }
+
+    case RFC_MX_EVENT_START_RSP:
+    case RFC_MX_EVENT_CONN_CNF:
+    case RFC_MX_EVENT_CONF_IND:
+    case RFC_MX_EVENT_CONF_CNF:
+        RFCOMM_TRACE_ERROR ("Mx error state %d event %d", p_mcb->state, event);
+        return;
+
+    case RFC_MX_EVENT_CONN_IND:
+
+        rfc_timer_start (p_mcb, RFCOMM_CONN_TIMEOUT);
+        L2CA_ConnectRsp (p_mcb->bd_addr, *((uint8_t *)p_data), p_mcb->lcid, L2CAP_CONN_OK, 0);
+
+        rfc_mx_send_config_req (p_mcb);
+
+        p_mcb->state = RFC_MX_STATE_CONFIGURE;
+        return;
+
+    case RFC_EVENT_SABME:
+        break;
+
+    case RFC_EVENT_UA:
+    case RFC_EVENT_DM:
+        return;
+
+    case RFC_EVENT_DISC:
+        rfc_send_dm (p_mcb, RFCOMM_MX_DLCI, true);
+        return;
+
+    case RFC_EVENT_UIH:
+        rfc_send_dm (p_mcb, RFCOMM_MX_DLCI, false);
+        return;
+    }
+    RFCOMM_TRACE_EVENT ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_mx_sm_state_wait_conn_cnf
+**
+** Description      This function handles events when the multiplexer is
+**                  waiting for Connection Confirm from L2CAP.
+**
+** Returns          void
+**
+*******************************************************************************/
+void rfc_mx_sm_state_wait_conn_cnf (tRFC_MCB *p_mcb, uint16_t event, void *p_data)
+{
+    RFCOMM_TRACE_EVENT ("rfc_mx_sm_state_wait_conn_cnf - evt:%d", event);
+    switch (event)
+    {
+    case RFC_MX_EVENT_START_REQ:
+        RFCOMM_TRACE_ERROR ("Mx error state %d event %d", p_mcb->state, event);
+        return;
+
+    /* There is some new timing so that Config Ind comes before security is completed
+       so we are still waiting fo the confirmation. */
+    case RFC_MX_EVENT_CONF_IND:
+        rfc_mx_conf_ind (p_mcb, (tL2CAP_CFG_INFO *)p_data);
+        return;
+
+    case RFC_MX_EVENT_CONN_CNF:
+        if (*((uint16_t *)p_data) != L2CAP_SUCCESS)
+        {
+            p_mcb->state = RFC_MX_STATE_IDLE;
+
+            PORT_StartCnf (p_mcb, *((uint16_t *)p_data));
+            return;
+        }
+        p_mcb->state = RFC_MX_STATE_CONFIGURE;
+        rfc_mx_send_config_req (p_mcb);
+        return;
+
+    case RFC_MX_EVENT_DISC_IND:
+        p_mcb->state = RFC_MX_STATE_IDLE;
+        PORT_CloseInd (p_mcb);
+        return;
+
+    case RFC_EVENT_TIMEOUT:
+        p_mcb->state = RFC_MX_STATE_IDLE;
+        L2CA_DisconnectReq (p_mcb->lcid);
+
+        /* we gave up outgoing connection request then try peer's request */
+        if (p_mcb->pending_lcid)
+        {
+            uint16_t i;
+            uint8_t idx;
+
+            RFCOMM_TRACE_DEBUG ("RFCOMM MX retry as acceptor in collision case - evt:%d in state:%d", event, p_mcb->state);
+
+            rfc_save_lcid_mcb (NULL, p_mcb->lcid);
+            p_mcb->lcid = p_mcb->pending_lcid;
+            rfc_save_lcid_mcb (p_mcb, p_mcb->lcid);
+
+            p_mcb->is_initiator = false;
+
+            /* update direction bit */
+            for (i = 0; i < RFCOMM_MAX_DLCI; i += 2)
+            {
+                if ((idx = p_mcb->port_inx[i]) != 0)
+                {
+                    p_mcb->port_inx[i] = 0;
+                    p_mcb->port_inx[i+1] = idx;
+                    rfc_cb.port.port[idx - 1].dlci += 1;
+                    RFCOMM_TRACE_DEBUG ("RFCOMM MX - DLCI:%d -> %d", i, rfc_cb.port.port[idx - 1].dlci);
+                }
+            }
+
+            rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CONN_IND, &(p_mcb->pending_id));
+        }
+        else
+        {
+            PORT_CloseInd (p_mcb);
+        }
+        return;
+    }
+    RFCOMM_TRACE_EVENT ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_mx_sm_state_configure
+**
+** Description      This function handles events when the multiplexer in the
+**                  configuration state.
+**
+** Returns          void
+**
+*******************************************************************************/
+void rfc_mx_sm_state_configure (tRFC_MCB *p_mcb, uint16_t event, void *p_data)
+{
+    RFCOMM_TRACE_EVENT ("rfc_mx_sm_state_configure - evt:%d", event);
+    switch (event)
+    {
+    case RFC_MX_EVENT_START_REQ:
+    case RFC_MX_EVENT_CONN_CNF:
+
+        RFCOMM_TRACE_ERROR ("Mx error state %d event %d", p_mcb->state, event);
+        return;
+
+    case RFC_MX_EVENT_CONF_IND:
+        rfc_mx_conf_ind (p_mcb, (tL2CAP_CFG_INFO *)p_data);
+        return;
+
+    case RFC_MX_EVENT_CONF_CNF:
+        rfc_mx_conf_cnf (p_mcb, (tL2CAP_CFG_INFO *)p_data);
+        return;
+
+    case RFC_MX_EVENT_DISC_IND:
+        p_mcb->state = RFC_MX_STATE_IDLE;
+        PORT_CloseInd (p_mcb);
+        return;
+
+    case RFC_EVENT_TIMEOUT:
+        p_mcb->state = RFC_MX_STATE_IDLE;
+        L2CA_DisconnectReq (p_mcb->lcid);
+
+        PORT_StartCnf (p_mcb, RFCOMM_ERROR);
+        return;
+    }
+    RFCOMM_TRACE_EVENT ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_mx_sm_sabme_wait_ua
+**
+** Description      This function handles events when the multiplexer sent
+**                  SABME and is waiting for UA reply.
+**
+** Returns          void
+**
+*******************************************************************************/
+void rfc_mx_sm_sabme_wait_ua (tRFC_MCB *p_mcb, uint16_t event,
+			      UNUSED_ATTR void *p_data)
+{
+    RFCOMM_TRACE_EVENT ("rfc_mx_sm_sabme_wait_ua - evt:%d", event);
+    switch (event)
+    {
+    case RFC_MX_EVENT_START_REQ:
+    case RFC_MX_EVENT_CONN_CNF:
+        RFCOMM_TRACE_ERROR ("Mx error state %d event %d", p_mcb->state, event);
+        return;
+
+    /* workaround: we don't support reconfig */
+    /* commented out until we support reconfig
+    case RFC_MX_EVENT_CONF_IND:
+        rfc_mx_conf_ind (p_mcb, (tL2CAP_CFG_INFO *)p_data);
+        return;
+
+    case RFC_MX_EVENT_CONF_CNF:
+        rfc_mx_conf_cnf (p_mcb, (tL2CAP_CFG_INFO *)p_data);
+        return;
+    */
+
+    case RFC_MX_EVENT_DISC_IND:
+        p_mcb->state = RFC_MX_STATE_IDLE;
+        PORT_CloseInd (p_mcb);
+        return;
+
+    case RFC_EVENT_UA:
+        rfc_timer_stop (p_mcb);
+
+        p_mcb->state      = RFC_MX_STATE_CONNECTED;
+        p_mcb->peer_ready = true;
+
+        PORT_StartCnf (p_mcb, RFCOMM_SUCCESS);
+        return;
+
+    case RFC_EVENT_DM:
+        rfc_timer_stop (p_mcb);
+        /* Case falls through */
+
+    case RFC_MX_EVENT_CONF_IND: /* workaround: we don't support reconfig */
+    case RFC_MX_EVENT_CONF_CNF: /* workaround: we don't support reconfig */
+    case RFC_EVENT_TIMEOUT:
+        p_mcb->state = RFC_MX_STATE_IDLE;
+        L2CA_DisconnectReq (p_mcb->lcid);
+
+        PORT_StartCnf (p_mcb, RFCOMM_ERROR);
+        return;
+    }
+    RFCOMM_TRACE_EVENT ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
+}
+
+/*******************************************************************************
+**
+** Function         rfc_mx_sm_state_wait_sabme
+**
+** Description      This function handles events when the multiplexer is
+**                  waiting for SABME on the acceptor side after configuration
+**
+** Returns          void
+**
+*******************************************************************************/
+void rfc_mx_sm_state_wait_sabme (tRFC_MCB *p_mcb, uint16_t event, void *p_data)
+{
+    RFCOMM_TRACE_EVENT ("rfc_mx_sm_state_wait_sabme - evt:%d", event);
+    switch (event)
+    {
+    case RFC_MX_EVENT_DISC_IND:
+        p_mcb->state = RFC_MX_STATE_IDLE;
+        PORT_CloseInd (p_mcb);
+        return;
+
+    case RFC_EVENT_SABME:
+        /* if we gave up outgoing connection request */
+        if (p_mcb->pending_lcid)
+        {
+            p_mcb->pending_lcid = 0;
+
+            rfc_send_ua (p_mcb, RFCOMM_MX_DLCI);
+
+            rfc_timer_stop (p_mcb);
+            p_mcb->state      = RFC_MX_STATE_CONNECTED;
+            p_mcb->peer_ready = true;
+
+            /* MX channel collision has been resolved, continue to open ports */
+            PORT_StartCnf (p_mcb, RFCOMM_SUCCESS);
+        }
+        else
+        {
+            rfc_timer_stop (p_mcb);
+            PORT_StartInd (p_mcb);
+        }
+        return;
+
+    case RFC_MX_EVENT_START_RSP:
+        if (*((uint16_t *)p_data) != RFCOMM_SUCCESS)
+            rfc_send_dm (p_mcb, RFCOMM_MX_DLCI, true);
+        else
+        {
+            rfc_send_ua (p_mcb, RFCOMM_MX_DLCI);
+
+            p_mcb->state      = RFC_MX_STATE_CONNECTED;
+            p_mcb->peer_ready = true;
+            PORT_StartCnf (p_mcb, RFCOMM_SUCCESS);
+        }
+        return;
+
+    case RFC_MX_EVENT_CONF_IND: /* workaround: we don't support reconfig */
+    case RFC_MX_EVENT_CONF_CNF: /* workaround: we don't support reconfig */
+    case RFC_EVENT_TIMEOUT:
+        p_mcb->state = RFC_MX_STATE_IDLE;
+        L2CA_DisconnectReq (p_mcb->lcid);
+
+        PORT_CloseInd (p_mcb);
+        return;
+    }
+    RFCOMM_TRACE_EVENT ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_mx_sm_state_connected
+**
+** Description      This function handles events when the multiplexer is
+**                  in the CONNECTED state
+**
+** Returns          void
+**
+*******************************************************************************/
+void rfc_mx_sm_state_connected (tRFC_MCB *p_mcb, uint16_t event,
+                                UNUSED_ATTR void *p_data)
+{
+    RFCOMM_TRACE_EVENT ("rfc_mx_sm_state_connected - evt:%d", event);
+
+    switch (event)
+    {
+    case RFC_EVENT_TIMEOUT:
+    case RFC_MX_EVENT_CLOSE_REQ:
+        rfc_timer_start (p_mcb, RFC_DISC_TIMEOUT);
+        p_mcb->state = RFC_MX_STATE_DISC_WAIT_UA;
+        rfc_send_disc (p_mcb, RFCOMM_MX_DLCI);
+        return;
+
+    case RFC_MX_EVENT_DISC_IND:
+        p_mcb->state = RFC_MX_STATE_IDLE;
+        PORT_CloseInd (p_mcb);
+        return;
+
+    case RFC_EVENT_DISC:
+        /* Reply with UA.  If initiator bring down L2CAP connection */
+        /* If server wait for some time if client decide to reinitiate channel */
+        rfc_send_ua (p_mcb, RFCOMM_MX_DLCI);
+        if (p_mcb->is_initiator)
+        {
+            L2CA_DisconnectReq (p_mcb->lcid);
+        }
+        /* notify all ports that connection is gone */
+        PORT_CloseInd (p_mcb);
+        return;
+    }
+    RFCOMM_TRACE_EVENT ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_mx_sm_state_disc_wait_ua
+**
+** Description      This function handles events when the multiplexer sent
+**                  DISC and is waiting for UA reply.
+**
+** Returns          void
+**
+*******************************************************************************/
+void rfc_mx_sm_state_disc_wait_ua (tRFC_MCB *p_mcb, uint16_t event, void *p_data)
+{
+    BT_HDR *p_buf;
+
+    RFCOMM_TRACE_EVENT ("rfc_mx_sm_state_disc_wait_ua - evt:%d", event);
+    switch (event)
+    {
+    case RFC_EVENT_UA:
+    case RFC_EVENT_DM:
+    case RFC_EVENT_TIMEOUT:
+        L2CA_DisconnectReq (p_mcb->lcid);
+
+        if (p_mcb->restart_required)
+        {
+            /* Start Request was received while disconnecting.  Execute it again */
+            uint16_t lcid = L2CA_ConnectReq(BT_PSM_RFCOMM, p_mcb->bd_addr);
+            if (lcid == 0) {
+                rfc_save_lcid_mcb(NULL, p_mcb->lcid);
+                p_mcb->lcid = 0;
+                PORT_StartCnf(p_mcb, RFCOMM_ERROR);
+                return;
+            }
+            p_mcb->lcid = lcid;
+            /* Save entry for quicker access to mcb based on the LCID */
+            rfc_save_lcid_mcb (p_mcb, p_mcb->lcid);
+
+            /* clean up before reuse it */
+            while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_mcb->cmd_q)) != NULL)
+                osi_free(p_buf);
+
+            rfc_timer_start (p_mcb, RFC_MCB_INIT_INACT_TIMER);
+
+            p_mcb->is_initiator     = true;
+            p_mcb->restart_required = false;
+            p_mcb->local_cfg_sent   = false;
+            p_mcb->peer_cfg_rcvd    = false;
+
+            p_mcb->state = RFC_MX_STATE_WAIT_CONN_CNF;
+            return;
+        }
+        rfc_release_multiplexer_channel (p_mcb);
+        return;
+
+    case RFC_EVENT_DISC:
+        rfc_send_ua (p_mcb, RFCOMM_MX_DLCI);
+        return;
+
+    case RFC_EVENT_UIH:
+        osi_free(p_data);
+        rfc_send_dm (p_mcb, RFCOMM_MX_DLCI, false);
+        return;
+
+    case RFC_MX_EVENT_START_REQ:
+        p_mcb->restart_required = true;
+        return;
+
+    case RFC_MX_EVENT_DISC_IND:
+        p_mcb->state = RFC_MX_STATE_IDLE;
+        PORT_CloseInd (p_mcb);
+        return;
+
+    case RFC_MX_EVENT_CLOSE_REQ:
+        return;
+
+    case RFC_MX_EVENT_QOS_VIOLATION_IND:
+        break;
+    }
+    RFCOMM_TRACE_EVENT ("RFCOMM MX ignored - evt:%d in state:%d", event, p_mcb->state);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_mx_send_config_req
+**
+** Description      This function handles L2CA_ConnectInd message from the
+**                  L2CAP.  Accept connection.
+**
+*******************************************************************************/
+static void rfc_mx_send_config_req (tRFC_MCB *p_mcb)
+{
+    tL2CAP_CFG_INFO cfg;
+
+    RFCOMM_TRACE_EVENT ("rfc_mx_send_config_req");
+
+    memset (&cfg, 0, sizeof (tL2CAP_CFG_INFO));
+
+    cfg.mtu_present      = true;
+    cfg.mtu              = L2CAP_MTU_SIZE;
+
+/* Defaults set by memset
+    cfg.flush_to_present = false;
+    cfg.qos_present      = false;
+    cfg.fcr_present      = false;
+    cfg.fcr.mode         = L2CAP_FCR_BASIC_MODE;
+    cfg.fcs_present      = false;
+    cfg.fcs              = N/A when fcs_present is false;
+*/
+    L2CA_ConfigReq (p_mcb->lcid, &cfg);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_mx_conf_cnf
+**
+** Description      This function handles L2CA_ConfigCnf message from the
+**                  L2CAP.  If result is not success tell upper layer that
+**                  start has not been accepted.  If initiator send SABME
+**                  on DLCI 0.  T1 is still running.
+**
+*******************************************************************************/
+static void rfc_mx_conf_cnf (tRFC_MCB *p_mcb, tL2CAP_CFG_INFO *p_cfg)
+{
+    RFCOMM_TRACE_EVENT ("rfc_mx_conf_cnf p_cfg:%08x res:%d ", p_cfg, (p_cfg) ? p_cfg->result : 0);
+
+    if (p_cfg->result != L2CAP_CFG_OK)
+    {
+        if (p_mcb->is_initiator)
+        {
+            PORT_StartCnf (p_mcb, p_cfg->result);
+            L2CA_DisconnectReq (p_mcb->lcid);
+        }
+        rfc_release_multiplexer_channel (p_mcb);
+        return;
+    }
+
+    p_mcb->local_cfg_sent = true;
+    if ((p_mcb->state == RFC_MX_STATE_CONFIGURE) && p_mcb->peer_cfg_rcvd)
+    {
+        if (p_mcb->is_initiator)
+        {
+            p_mcb->state = RFC_MX_STATE_SABME_WAIT_UA;
+            rfc_send_sabme (p_mcb, RFCOMM_MX_DLCI);
+            rfc_timer_start (p_mcb, RFC_T1_TIMEOUT);
+        }
+        else
+        {
+            p_mcb->state = RFC_MX_STATE_WAIT_SABME;
+            rfc_timer_start (p_mcb, RFCOMM_CONN_TIMEOUT); /* - increased from T2=20 to CONN=120
+                                                to allow the user more than 10 sec to type in the
+                                                pin which can be e.g. 16 digits */
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_mx_conf_ind
+**
+** Description      This function handles L2CA_ConfigInd message from the
+**                  L2CAP.  Send the L2CA_ConfigRsp message.
+**
+*******************************************************************************/
+static void rfc_mx_conf_ind (tRFC_MCB *p_mcb, tL2CAP_CFG_INFO *p_cfg)
+{
+    /* Save peer L2CAP MTU if present */
+    /* RFCOMM adds 3-4 bytes in the beginning and 1 bytes FCS */
+    if (p_cfg->mtu_present)
+        p_mcb->peer_l2cap_mtu = p_cfg->mtu - RFCOMM_MIN_OFFSET - 1;
+    else
+        p_mcb->peer_l2cap_mtu = L2CAP_DEFAULT_MTU - RFCOMM_MIN_OFFSET - 1;
+
+    p_cfg->mtu_present      = false;
+    p_cfg->flush_to_present = false;
+    p_cfg->qos_present      = false;
+
+    p_cfg->result = L2CAP_CFG_OK;
+
+    L2CA_ConfigRsp (p_mcb->lcid, p_cfg);
+
+    p_mcb->peer_cfg_rcvd = true;
+    if ((p_mcb->state == RFC_MX_STATE_CONFIGURE) && p_mcb->local_cfg_sent)
+    {
+        if (p_mcb->is_initiator)
+        {
+            p_mcb->state = RFC_MX_STATE_SABME_WAIT_UA;
+            rfc_send_sabme (p_mcb, RFCOMM_MX_DLCI);
+            rfc_timer_start (p_mcb, RFC_T1_TIMEOUT);
+        }
+        else
+        {
+            p_mcb->state = RFC_MX_STATE_WAIT_SABME;
+            rfc_timer_start (p_mcb, RFCOMM_CONN_TIMEOUT); /* - increased from T2=20 to CONN=120
+                                                to allow the user more than 10 sec to type in the
+                                                pin which can be e.g. 16 digits */
+        }
+    }
+}
diff --git a/bt/stack/rfcomm/rfc_port_fsm.cc b/bt/stack/rfcomm/rfc_port_fsm.cc
new file mode 100644
index 0000000..9f63307
--- /dev/null
+++ b/bt/stack/rfcomm/rfc_port_fsm.cc
@@ -0,0 +1,917 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 state machine and action routines for a port of the
+ *  RFCOMM unit
+ *
+ ******************************************************************************/
+#include <string.h>
+#include "bt_target.h"
+#include "bt_common.h"
+#include "rfcdefs.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+#include "bt_utils.h"
+#include "osi/include/osi.h"
+
+/********************************************************************************/
+/*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
+/********************************************************************************/
+static void rfc_port_sm_state_closed (tPORT *p_port, uint16_t event, void *p_data);
+static void rfc_port_sm_sabme_wait_ua (tPORT *p_port, uint16_t event, void *p_data);
+static void rfc_port_sm_opened (tPORT *p_port, uint16_t event, void *p_data);
+static void rfc_port_sm_orig_wait_sec_check (tPORT *p_port, uint16_t event, void *p_data);
+static void rfc_port_sm_term_wait_sec_check (tPORT *p_port, uint16_t event, void *p_data);
+static void rfc_port_sm_disc_wait_ua (tPORT *p_port, uint16_t event, void *p_data);
+
+static void rfc_port_uplink_data (tPORT *p_port, BT_HDR *p_buf);
+
+static void rfc_set_port_state(tPORT_STATE *port_pars, MX_FRAME *p_frame);
+
+
+/*******************************************************************************
+**
+** Function         rfc_port_sm_execute
+**
+** Description      This function sends port events through the state
+**                  machine.
+**
+** Returns          void
+**
+*******************************************************************************/
+void rfc_port_sm_execute (tPORT *p_port, uint16_t event, void *p_data)
+{
+    if (!p_port)
+    {
+        RFCOMM_TRACE_WARNING ("NULL port event %d", event);
+        return;
+    }
+
+    switch (p_port->rfc.state)
+    {
+    case RFC_STATE_CLOSED:
+        rfc_port_sm_state_closed (p_port, event, p_data);
+        break;
+
+    case RFC_STATE_SABME_WAIT_UA:
+        rfc_port_sm_sabme_wait_ua (p_port, event, p_data);
+        break;
+
+    case RFC_STATE_ORIG_WAIT_SEC_CHECK:
+        rfc_port_sm_orig_wait_sec_check (p_port, event, p_data);
+        break;
+
+    case RFC_STATE_TERM_WAIT_SEC_CHECK:
+        rfc_port_sm_term_wait_sec_check (p_port, event, p_data);
+        break;
+
+    case RFC_STATE_OPENED:
+        rfc_port_sm_opened (p_port, event, p_data);
+        break;
+
+    case RFC_STATE_DISC_WAIT_UA:
+        rfc_port_sm_disc_wait_ua (p_port, event, p_data);
+        break;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_port_sm_state_closed
+**
+** Description      This function handles events when the port is in
+**                  CLOSED state. This state exists when port is
+**                  being initially established.
+**
+** Returns          void
+**
+*******************************************************************************/
+void rfc_port_sm_state_closed (tPORT *p_port, uint16_t event, void *p_data)
+{
+    switch (event)
+    {
+    case RFC_EVENT_OPEN:
+        p_port->rfc.state = RFC_STATE_ORIG_WAIT_SEC_CHECK;
+        btm_sec_mx_access_request (p_port->rfc.p_mcb->bd_addr, BT_PSM_RFCOMM, true,
+                                   BTM_SEC_PROTO_RFCOMM, (uint32_t)(p_port->dlci / 2),
+                                   &rfc_sec_check_complete, p_port);
+        return;
+
+    case RFC_EVENT_CLOSE:
+        break;
+
+    case RFC_EVENT_CLEAR:
+        return;
+
+    case RFC_EVENT_DATA:
+        osi_free(p_data);
+        break;
+
+    case RFC_EVENT_SABME:
+        /* make sure the multiplexer disconnect timer is not running (reconnect case) */
+        rfc_timer_stop(p_port->rfc.p_mcb );
+
+        /* Open will be continued after security checks are passed */
+        p_port->rfc.state = RFC_STATE_TERM_WAIT_SEC_CHECK;
+        btm_sec_mx_access_request (p_port->rfc.p_mcb->bd_addr, BT_PSM_RFCOMM, false,
+                                   BTM_SEC_PROTO_RFCOMM, (uint32_t)(p_port->dlci / 2),
+                                   &rfc_sec_check_complete, p_port);
+        return;
+
+    case RFC_EVENT_UA:
+        return;
+
+    case RFC_EVENT_DM:
+        rfc_port_closed (p_port);
+        return;
+
+    case RFC_EVENT_UIH:
+        osi_free(p_data);
+        rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, false);
+        return;
+
+    case RFC_EVENT_DISC:
+        rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, false);
+        return;
+
+    case RFC_EVENT_TIMEOUT:
+        Port_TimeOutCloseMux( p_port->rfc.p_mcb ) ;
+        RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event);
+        return;
+    }
+
+    RFCOMM_TRACE_WARNING ("Port state closed Event ignored %d", event);
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         rfc_port_sm_sabme_wait_ua
+**
+** Description      This function handles events when SABME on the DLC was
+**                  sent and SM is waiting for UA or DM.
+**
+** Returns          void
+**
+*******************************************************************************/
+void rfc_port_sm_sabme_wait_ua (tPORT *p_port, uint16_t event, void *p_data)
+{
+    switch (event)
+    {
+    case RFC_EVENT_OPEN:
+    case RFC_EVENT_ESTABLISH_RSP:
+        RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event);
+        return;
+
+    case RFC_EVENT_CLOSE:
+        rfc_port_timer_start (p_port, RFC_DISC_TIMEOUT);
+        rfc_send_disc (p_port->rfc.p_mcb, p_port->dlci);
+        p_port->rfc.expected_rsp = 0;
+        p_port->rfc.state = RFC_STATE_DISC_WAIT_UA;
+        return;
+
+    case RFC_EVENT_CLEAR:
+        rfc_port_closed (p_port);
+        return;
+
+    case RFC_EVENT_DATA:
+        osi_free(p_data);
+        break;
+
+    case RFC_EVENT_UA:
+        rfc_port_timer_stop (p_port);
+        p_port->rfc.state = RFC_STATE_OPENED;
+        PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_SUCCESS);
+        return;
+
+    case RFC_EVENT_DM:
+        p_port->rfc.p_mcb->is_disc_initiator = true;
+        PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR);
+        rfc_port_closed (p_port);
+        return;
+
+    case RFC_EVENT_DISC:
+        rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
+        PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR);
+        rfc_port_closed (p_port);
+        return;
+
+    case RFC_EVENT_SABME:
+        /* Continue to wait for the UA the SABME this side sent */
+        rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
+        return;
+
+    case RFC_EVENT_UIH:
+        osi_free(p_data);
+        return;
+
+    case RFC_EVENT_TIMEOUT:
+        p_port->rfc.state = RFC_STATE_CLOSED;
+        PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR);
+        return;
+    }
+    RFCOMM_TRACE_WARNING ("Port state sabme_wait_ua Event ignored %d", event);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_port_sm_term_wait_sec_check
+**
+** Description      This function handles events for the port in the
+**                  WAIT_SEC_CHECK state.  SABME has been received from the
+**                  peer and Security Manager verifes BD_ADDR, before we can
+**                  send ESTABLISH_IND to the Port entity
+**
+** Returns          void
+**
+*******************************************************************************/
+void rfc_port_sm_term_wait_sec_check (tPORT *p_port, uint16_t event, void *p_data)
+{
+    switch (event)
+    {
+    case RFC_EVENT_SEC_COMPLETE:
+        if (*((uint8_t *)p_data) != BTM_SUCCESS)
+        {
+            /* Authentication/authorization failed.  If link is still  */
+            /* up send DM and check if we need to start inactive timer */
+            if (p_port->rfc.p_mcb)
+            {
+                rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, true);
+                p_port->rfc.p_mcb->is_disc_initiator = true;
+                port_rfc_closed (p_port, PORT_SEC_FAILED);
+            }
+        }
+        else
+        {
+            PORT_DlcEstablishInd (p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu);
+        }
+        return;
+
+    case RFC_EVENT_OPEN:
+    case RFC_EVENT_CLOSE:
+        RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event);
+        return;
+
+    case RFC_EVENT_CLEAR:
+        btm_sec_abort_access_req (p_port->rfc.p_mcb->bd_addr);
+        rfc_port_closed (p_port);
+        return;
+
+    case RFC_EVENT_DATA:
+        RFCOMM_TRACE_ERROR ("Port error state Term Wait Sec event Data");
+        osi_free(p_data);
+        return;
+
+    case RFC_EVENT_SABME:
+        /* Ignore SABME retransmission if client dares to do so */
+        return;
+
+    case RFC_EVENT_DISC:
+        btm_sec_abort_access_req (p_port->rfc.p_mcb->bd_addr);
+        p_port->rfc.state = RFC_STATE_CLOSED;
+        rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
+
+        PORT_DlcReleaseInd (p_port->rfc.p_mcb, p_port->dlci);
+        return;
+
+    case RFC_EVENT_UIH:
+        osi_free(p_data);
+        return;
+
+    case RFC_EVENT_ESTABLISH_RSP:
+        if (*((uint8_t *)p_data) != RFCOMM_SUCCESS)
+        {
+            if (p_port->rfc.p_mcb)
+                rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, true);
+        }
+        else
+        {
+            rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
+            p_port->rfc.state = RFC_STATE_OPENED;
+        }
+        return;
+    }
+    RFCOMM_TRACE_WARNING ("Port state term_wait_sec_check Event ignored %d", event);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_port_sm_orig_wait_sec_check
+**
+** Description      This function handles events for the port in the
+**                  ORIG_WAIT_SEC_CHECK state.  RFCOMM is waiting for Security
+**                  manager to finish before sending SABME to the peer
+**
+** Returns          void
+**
+*******************************************************************************/
+void rfc_port_sm_orig_wait_sec_check (tPORT *p_port, uint16_t event, void *p_data)
+{
+    switch (event)
+    {
+    case RFC_EVENT_SEC_COMPLETE:
+        if (*((uint8_t *)p_data) != BTM_SUCCESS)
+        {
+            p_port->rfc.p_mcb->is_disc_initiator = true;
+            PORT_DlcEstablishCnf (p_port->rfc.p_mcb, p_port->dlci, 0, RFCOMM_SECURITY_ERR);
+            rfc_port_closed (p_port);
+            return;
+        }
+        rfc_send_sabme (p_port->rfc.p_mcb, p_port->dlci);
+        rfc_port_timer_start (p_port, RFC_PORT_T1_TIMEOUT);
+        p_port->rfc.state = RFC_STATE_SABME_WAIT_UA;
+        return;
+
+    case RFC_EVENT_OPEN:
+    case RFC_EVENT_SABME:       /* Peer should not use the same dlci */
+        RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event);
+        return;
+
+    case RFC_EVENT_CLOSE:
+        btm_sec_abort_access_req (p_port->rfc.p_mcb->bd_addr);
+        rfc_port_closed (p_port);
+        return;
+
+    case RFC_EVENT_DATA:
+        RFCOMM_TRACE_ERROR ("Port error state Orig Wait Sec event Data");
+        osi_free(p_data);
+        return;
+
+    case RFC_EVENT_UIH:
+        osi_free(p_data);
+        return;
+    }
+    RFCOMM_TRACE_WARNING ("Port state orig_wait_sec_check Event ignored %d", event);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_port_sm_opened
+**
+** Description      This function handles events for the port in the OPENED
+**                  state
+**
+** Returns          void
+**
+*******************************************************************************/
+void rfc_port_sm_opened (tPORT *p_port, uint16_t event, void *p_data)
+{
+    switch (event)
+    {
+    case RFC_EVENT_OPEN:
+        RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event);
+        return;
+
+    case RFC_EVENT_CLOSE:
+        rfc_port_timer_start (p_port, RFC_DISC_TIMEOUT);
+        rfc_send_disc (p_port->rfc.p_mcb, p_port->dlci);
+        p_port->rfc.expected_rsp = 0;
+        p_port->rfc.state = RFC_STATE_DISC_WAIT_UA;
+        return;
+
+    case RFC_EVENT_CLEAR:
+        rfc_port_closed (p_port);
+        return;
+
+    case RFC_EVENT_DATA:
+        /* Send credits in the frame.  Pass them in the layer specific member of the hdr. */
+        /* There might be an initial case when we reduced rx_max and credit_rx is still */
+        /* bigger.  Make sure that we do not send 255 */
+        if ((p_port->rfc.p_mcb->flow == PORT_FC_CREDIT)
+         && (((BT_HDR *)p_data)->len < p_port->peer_mtu)
+         && (!p_port->rx.user_fc)
+         && (p_port->credit_rx_max > p_port->credit_rx))
+        {
+            ((BT_HDR *)p_data)->layer_specific = (uint8_t) (p_port->credit_rx_max - p_port->credit_rx);
+            p_port->credit_rx = p_port->credit_rx_max;
+        }
+        else
+        {
+            ((BT_HDR *)p_data)->layer_specific = 0;
+        }
+        rfc_send_buf_uih (p_port->rfc.p_mcb, p_port->dlci, (BT_HDR *)p_data);
+        rfc_dec_credit (p_port);
+        return;
+
+    case RFC_EVENT_UA:
+        return;
+
+    case RFC_EVENT_SABME:
+        rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
+        return;
+
+    case RFC_EVENT_DM:
+        PORT_DlcReleaseInd (p_port->rfc.p_mcb, p_port->dlci);
+        rfc_port_closed (p_port);
+        return;
+
+    case RFC_EVENT_DISC:
+        p_port->rfc.state = RFC_STATE_CLOSED;
+        rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci);
+        if(! fixed_queue_is_empty(p_port->rx.queue))
+        {
+            /* give a chance to upper stack to close port properly */
+            RFCOMM_TRACE_DEBUG("port queue is not empty");
+            rfc_port_timer_start (p_port, RFC_DISC_TIMEOUT);
+        }
+        else
+            PORT_DlcReleaseInd (p_port->rfc.p_mcb, p_port->dlci);
+        return;
+
+    case RFC_EVENT_UIH:
+        rfc_port_uplink_data (p_port, (BT_HDR *)p_data);
+        return;
+
+    case RFC_EVENT_TIMEOUT:
+        Port_TimeOutCloseMux( p_port->rfc.p_mcb ) ;
+        RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event);
+        return;
+    }
+    RFCOMM_TRACE_WARNING ("Port state opened Event ignored %d", event);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_port_sm_disc_wait_ua
+**
+** Description      This function handles events when DISC on the DLC was
+**                  sent and SM is waiting for UA or DM.
+**
+** Returns          void
+**
+*******************************************************************************/
+void rfc_port_sm_disc_wait_ua (tPORT *p_port, uint16_t event, void *p_data)
+{
+    switch (event)
+    {
+    case RFC_EVENT_OPEN:
+    case RFC_EVENT_ESTABLISH_RSP:
+        RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event);
+        return;
+
+    case RFC_EVENT_CLEAR:
+        rfc_port_closed (p_port);
+        return;
+
+    case RFC_EVENT_DATA:
+        osi_free(p_data);
+        return;
+
+    case RFC_EVENT_UA:
+        p_port->rfc.p_mcb->is_disc_initiator = true;
+        /* Case falls through */
+
+   case RFC_EVENT_DM:
+        rfc_port_closed (p_port);
+        return;
+
+    case RFC_EVENT_SABME:
+        rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, true);
+        return;
+
+    case RFC_EVENT_DISC:
+        rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, true);
+        return;
+
+    case RFC_EVENT_UIH:
+        osi_free(p_data);
+        rfc_send_dm (p_port->rfc.p_mcb, p_port->dlci, false);
+        return;
+
+    case RFC_EVENT_TIMEOUT:
+        rfc_port_closed (p_port);
+        return;
+    }
+
+    RFCOMM_TRACE_WARNING ("Port state disc_wait_ua Event ignored %d", event);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_port_uplink_data
+**
+** Description      This function handles uplink information data frame.
+**
+*******************************************************************************/
+void rfc_port_uplink_data (tPORT *p_port, BT_HDR *p_buf)
+{
+    PORT_DataInd (p_port->rfc.p_mcb, p_port->dlci, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_process_pn
+**
+** Description      This function handles DLC parameter negotiation frame.
+**                  Record MTU and pass indication to the upper layer.
+**
+*******************************************************************************/
+void rfc_process_pn (tRFC_MCB *p_mcb, bool    is_command, MX_FRAME *p_frame)
+{
+    tPORT *p_port;
+    uint8_t dlci = p_frame->dlci;
+
+    if (is_command)
+    {
+        /* Ignore if Multiplexer is being shut down */
+        if (p_mcb->state != RFC_MX_STATE_DISC_WAIT_UA)
+        {
+            PORT_ParNegInd (p_mcb, dlci, p_frame->u.pn.mtu,
+                        p_frame->u.pn.conv_layer, p_frame->u.pn.k);
+        }
+        else
+        {
+            rfc_send_dm(p_mcb, dlci, false);
+            RFCOMM_TRACE_WARNING("***** MX PN while disconnecting *****");
+        }
+
+        return;
+    }
+    /* If we are not awaiting response just ignore it */
+    p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+    if ((p_port == NULL) || !(p_port->rfc.expected_rsp & RFC_RSP_PN))
+        return;
+
+    p_port->rfc.expected_rsp &= ~RFC_RSP_PN;
+
+    rfc_port_timer_stop (p_port);
+
+    PORT_ParNegCnf (p_mcb, dlci, p_frame->u.pn.mtu,
+                    p_frame->u.pn.conv_layer, p_frame->u.pn.k);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_process_rpn
+**
+** Description      This function handles Remote DLC parameter negotiation
+**                  command/response.  Pass command to the user.
+**
+*******************************************************************************/
+void rfc_process_rpn (tRFC_MCB *p_mcb, bool    is_command,
+                      bool    is_request, MX_FRAME *p_frame)
+{
+    tPORT_STATE port_pars;
+    tPORT       *p_port;
+
+    if ((p_port = port_find_mcb_dlci_port (p_mcb, p_frame->dlci)) == NULL)
+    {
+        /* This is the first command on the port */
+        if (is_command)
+        {
+
+            memset(&port_pars, 0, sizeof(tPORT_STATE));
+            rfc_set_port_state(&port_pars, p_frame);
+
+            PORT_PortNegInd(p_mcb, p_frame->dlci, &port_pars, p_frame->u.rpn.param_mask);
+        }
+        return;
+    }
+
+    if (is_command && is_request)
+    {
+        /* This is the special situation when peer just request local pars */
+        port_pars = p_port->peer_port_pars;
+        rfc_send_rpn (p_mcb, p_frame->dlci, false, &p_port->peer_port_pars, 0);
+        return;
+    }
+
+    port_pars = p_port->peer_port_pars;
+
+    rfc_set_port_state(&port_pars, p_frame);
+
+    if (is_command)
+    {
+        PORT_PortNegInd (p_mcb, p_frame->dlci, &port_pars, p_frame->u.rpn.param_mask);
+        return;
+    }
+
+    /* If we are not awaiting response just ignore it */
+    p_port = port_find_mcb_dlci_port (p_mcb, p_frame->dlci);
+    if ((p_port == NULL) || !(p_port->rfc.expected_rsp & (RFC_RSP_RPN | RFC_RSP_RPN_REPLY)))
+        return;
+
+    /* If we sent a request for port parameters to the peer he is replying with */
+    /* mask 0. */
+    rfc_port_timer_stop (p_port);
+
+    if (p_port->rfc.expected_rsp & RFC_RSP_RPN_REPLY)
+    {
+        p_port->rfc.expected_rsp &= ~RFC_RSP_RPN_REPLY;
+
+        p_port->peer_port_pars = port_pars;
+
+        if ((port_pars.fc_type == (RFCOMM_FC_RTR_ON_INPUT | RFCOMM_FC_RTR_ON_OUTPUT))
+         || (port_pars.fc_type == (RFCOMM_FC_RTC_ON_INPUT | RFCOMM_FC_RTC_ON_OUTPUT)))
+        {
+            /* This is satisfactory port parameters.  Set mask as it was Ok */
+            p_frame->u.rpn.param_mask = RFCOMM_RPN_PM_MASK;
+        }
+        else
+        {
+            /* Current peer parameters are not good, try to fix them */
+            p_port->peer_port_pars.fc_type = (RFCOMM_FC_RTR_ON_INPUT | RFCOMM_FC_RTR_ON_OUTPUT);
+
+            p_port->rfc.expected_rsp |= RFC_RSP_RPN;
+            rfc_send_rpn (p_mcb, p_frame->dlci, true, &p_port->peer_port_pars,
+                          RFCOMM_RPN_PM_RTR_ON_INPUT | RFCOMM_RPN_PM_RTR_ON_OUTPUT);
+            rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;
+            return;
+        }
+    }
+    else
+        p_port->rfc.expected_rsp &= ~RFC_RSP_RPN;
+
+    /* Check if all suggested parameters were accepted */
+    if (((p_frame->u.rpn.param_mask & (RFCOMM_RPN_PM_RTR_ON_INPUT | RFCOMM_RPN_PM_RTR_ON_OUTPUT)) ==
+        (RFCOMM_RPN_PM_RTR_ON_INPUT | RFCOMM_RPN_PM_RTR_ON_OUTPUT))
+     || ((p_frame->u.rpn.param_mask & (RFCOMM_RPN_PM_RTC_ON_INPUT | RFCOMM_RPN_PM_RTC_ON_OUTPUT)) ==
+        (RFCOMM_RPN_PM_RTC_ON_INPUT | RFCOMM_RPN_PM_RTC_ON_OUTPUT)))
+    {
+        PORT_PortNegCnf (p_mcb, p_port->dlci, &port_pars, RFCOMM_SUCCESS);
+        return;
+    }
+
+    /* If we were proposing RTR flow control try RTC flow control */
+    /* If we were proposing RTC flow control try no flow control */
+    /* otherwise drop the connection */
+    if (p_port->peer_port_pars.fc_type == (RFCOMM_FC_RTR_ON_INPUT | RFCOMM_FC_RTR_ON_OUTPUT))
+    {
+        /* Current peer parameters are not good, try to fix them */
+        p_port->peer_port_pars.fc_type = (RFCOMM_FC_RTC_ON_INPUT | RFCOMM_FC_RTC_ON_OUTPUT);
+
+        p_port->rfc.expected_rsp |= RFC_RSP_RPN;
+
+        rfc_send_rpn (p_mcb, p_frame->dlci, true, &p_port->peer_port_pars,
+                      RFCOMM_RPN_PM_RTC_ON_INPUT | RFCOMM_RPN_PM_RTC_ON_OUTPUT);
+        rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;
+        return;
+    }
+
+    /* Other side does not support flow control */
+    if (p_port->peer_port_pars.fc_type == (RFCOMM_FC_RTC_ON_INPUT | RFCOMM_FC_RTC_ON_OUTPUT))
+    {
+        p_port->peer_port_pars.fc_type = RFCOMM_FC_OFF;
+        PORT_PortNegCnf (p_mcb, p_port->dlci, &port_pars, RFCOMM_SUCCESS);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_process_msc
+**
+** Description      This function handles Modem Status Command.
+**                  Pass command to the user.
+**
+*******************************************************************************/
+void rfc_process_msc (tRFC_MCB *p_mcb, bool    is_command, MX_FRAME *p_frame)
+{
+    tPORT_CTRL pars;
+    tPORT      *p_port;
+    uint8_t    modem_signals = p_frame->u.msc.signals;
+    bool       new_peer_fc = false;
+
+    p_port = port_find_mcb_dlci_port (p_mcb, p_frame->dlci);
+    if (p_port == NULL)
+        return;
+
+    pars.modem_signal = 0;
+
+    if (modem_signals & RFCOMM_MSC_RTC)
+        pars.modem_signal |= MODEM_SIGNAL_DTRDSR;
+
+    if (modem_signals & RFCOMM_MSC_RTR)
+        pars.modem_signal |= MODEM_SIGNAL_RTSCTS;
+
+    if (modem_signals & RFCOMM_MSC_IC)
+        pars.modem_signal |= MODEM_SIGNAL_RI;
+
+    if (modem_signals & RFCOMM_MSC_DV)
+        pars.modem_signal |= MODEM_SIGNAL_DCD;
+
+    pars.fc = ((modem_signals & RFCOMM_MSC_FC) == RFCOMM_MSC_FC);
+
+    pars.break_signal     = (p_frame->u.msc.break_present) ?
+                             p_frame->u.msc.break_duration : 0;
+    pars.discard_buffers  = 0;
+    pars.break_signal_seq = RFCOMM_CTRL_BREAK_IN_SEQ;   /* this is default */
+
+    /* Check if this command is passed only to indicate flow control */
+    if (is_command)
+    {
+        rfc_send_msc (p_mcb, p_frame->dlci, false, &pars);
+
+        if (p_port->rfc.p_mcb->flow != PORT_FC_CREDIT)
+        {
+            /* Spec 1.1 indicates that only FC bit is used for flow control */
+            p_port->peer_ctrl.fc = new_peer_fc = pars.fc;
+
+            if (new_peer_fc != p_port->tx.peer_fc)
+                PORT_FlowInd (p_mcb, p_frame->dlci, (bool   )!new_peer_fc);
+        }
+
+        PORT_ControlInd (p_mcb, p_frame->dlci, &pars);
+
+        return;
+    }
+
+    /* If we are not awaiting response just ignore it */
+    if (!(p_port->rfc.expected_rsp & RFC_RSP_MSC))
+        return;
+
+    p_port->rfc.expected_rsp &= ~RFC_RSP_MSC;
+
+    rfc_port_timer_stop (p_port);
+
+    PORT_ControlCnf (p_port->rfc.p_mcb, p_port->dlci, &pars);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_process_rls
+**
+** Description      This function handles Remote Line Status command.
+**                  Pass command to the user.
+**
+*******************************************************************************/
+void rfc_process_rls (tRFC_MCB *p_mcb, bool    is_command, MX_FRAME *p_frame)
+{
+    tPORT *p_port;
+
+    if (is_command)
+    {
+        PORT_LineStatusInd (p_mcb, p_frame->dlci, p_frame->u.rls.line_status);
+        rfc_send_rls (p_mcb, p_frame->dlci, false, p_frame->u.rls.line_status);
+    }
+    else
+    {
+        p_port = port_find_mcb_dlci_port (p_mcb, p_frame->dlci);
+
+        /* If we are not awaiting response just ignore it */
+        if (!p_port || !(p_port->rfc.expected_rsp & RFC_RSP_RLS))
+            return;
+
+        p_port->rfc.expected_rsp &= ~RFC_RSP_RLS;
+
+        rfc_port_timer_stop (p_port);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_process_nsc
+**
+** Description      This function handles None Supported Command frame.
+**
+*******************************************************************************/
+void rfc_process_nsc (UNUSED_ATTR tRFC_MCB *p_mcb,
+                      UNUSED_ATTR MX_FRAME *p_frame)
+{
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_process_test
+**
+** Description      This function handles Test frame.  If this is a command
+**                  reply to it.  Otherwise pass response to the user.
+**
+*******************************************************************************/
+void rfc_process_test_rsp(UNUSED_ATTR tRFC_MCB *p_mcb, BT_HDR *p_buf)
+{
+    osi_free(p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         rfc_process_fcon
+**
+** Description      This function handles FCON frame.  The peer entity is able
+**                  to receive new information
+**
+*******************************************************************************/
+void rfc_process_fcon (tRFC_MCB *p_mcb, bool    is_command)
+{
+    if (is_command)
+    {
+        rfc_cb.rfc.peer_rx_disabled = false;
+
+        rfc_send_fcon (p_mcb, false);
+
+        if (!p_mcb->l2cap_congested)
+            PORT_FlowInd (p_mcb, 0, true);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         rfc_process_fcoff
+**
+** Description      This function handles FCOFF frame.  The peer entity is unable
+**                  to receive new information
+**
+*******************************************************************************/
+void rfc_process_fcoff (tRFC_MCB *p_mcb, bool    is_command)
+{
+    if (is_command)
+    {
+        rfc_cb.rfc.peer_rx_disabled = true;
+
+        if (!p_mcb->l2cap_congested)
+            PORT_FlowInd (p_mcb, 0, false);
+
+        rfc_send_fcoff (p_mcb, false);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_process_l2cap_congestion
+**
+** Description      This function handles L2CAP congestion messages
+**
+*******************************************************************************/
+void rfc_process_l2cap_congestion (tRFC_MCB *p_mcb, bool    is_congested)
+{
+    p_mcb->l2cap_congested = is_congested;
+
+    if (!is_congested)
+    {
+        rfc_check_send_cmd(p_mcb, NULL);
+    }
+
+    if (!rfc_cb.rfc.peer_rx_disabled)
+    {
+        if (!is_congested)
+            PORT_FlowInd (p_mcb, 0, true);
+        else
+            PORT_FlowInd (p_mcb, 0, false);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         rfc_set_port_pars
+**
+** Description      This function sets the tPORT_STATE structure given a p_frame.
+**
+*******************************************************************************/
+
+void rfc_set_port_state(tPORT_STATE *port_pars, MX_FRAME *p_frame)
+{
+    if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_BIT_RATE)
+        port_pars->baud_rate   = p_frame->u.rpn.baud_rate;
+    if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_DATA_BITS)
+        port_pars->byte_size   = p_frame->u.rpn.byte_size;
+    if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_STOP_BITS)
+        port_pars->stop_bits   = p_frame->u.rpn.stop_bits;
+    if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_PARITY)
+        port_pars->parity      = p_frame->u.rpn.parity;
+    if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_PARITY_TYPE)
+        port_pars->parity_type = p_frame->u.rpn.parity_type;
+    if (p_frame->u.rpn.param_mask & (RFCOMM_RPN_PM_XONXOFF_ON_INPUT |
+                                     RFCOMM_RPN_PM_XONXOFF_ON_OUTPUT |
+                                     RFCOMM_RPN_PM_RTR_ON_INPUT |
+                                     RFCOMM_RPN_PM_RTR_ON_OUTPUT |
+                                     RFCOMM_RPN_PM_RTC_ON_INPUT |
+                                     RFCOMM_RPN_PM_RTC_ON_OUTPUT))
+        port_pars->fc_type     = p_frame->u.rpn.fc_type;
+    if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_XON_CHAR)
+        port_pars->xon_char    = p_frame->u.rpn.xon_char;
+    if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_XOFF_CHAR)
+        port_pars->xoff_char   = p_frame->u.rpn.xoff_char;
+}
+
diff --git a/bt/stack/rfcomm/rfc_port_if.cc b/bt/stack/rfcomm/rfc_port_if.cc
new file mode 100644
index 0000000..79f3486
--- /dev/null
+++ b/bt/stack/rfcomm/rfc_port_if.cc
@@ -0,0 +1,375 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 functions callable by an application
+ * running on top of RFCOMM
+ *
+ *****************************************************************************/
+
+#include <string.h>
+#include "bt_target.h"
+#include "bt_common.h"
+#include "rfcdefs.h"
+#include "port_api.h"
+#include "l2c_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+#include "bt_utils.h"
+#include "osi/include/osi.h"
+
+tRFC_CB rfc_cb;
+
+/*******************************************************************************
+**
+** Function         RFCOMM_StartReq
+**
+** Description      This function handles Start Request from the upper layer.
+**                  If RFCOMM multiplexer channel can not be allocated
+**                  send start not accepted confirmation.  Otherwise dispatch
+**                  start event to the state machine.
+**
+*******************************************************************************/
+void RFCOMM_StartReq (tRFC_MCB *p_mcb)
+{
+    rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_START_REQ, NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_StartRsp
+**
+** Description      This function handles Start Response from the upper layer.
+**                  Save upper layer handle and result of the Start Indication
+**                  in the control block and dispatch event to the FSM.
+**
+*******************************************************************************/
+void RFCOMM_StartRsp (tRFC_MCB *p_mcb, uint16_t result)
+{
+    rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_START_RSP, &result);
+}
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_DlcEstablishReq
+**
+** Description      This function is called by the user app to establish
+**                  connection with the specific dlci on a specific bd device.
+**                  It will allocate RFCOMM connection control block if not
+**                  allocated before and dispatch open event to the state
+**                  machine.
+**
+*******************************************************************************/
+void RFCOMM_DlcEstablishReq (tRFC_MCB *p_mcb, uint8_t dlci,
+                             UNUSED_ATTR uint16_t mtu)
+{
+    if (p_mcb->state != RFC_MX_STATE_CONNECTED)
+    {
+        PORT_DlcEstablishCnf (p_mcb, dlci, 0, RFCOMM_ERROR);
+        return;
+    }
+
+    tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+    if (p_port == NULL) {
+        RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__,
+                dlci);
+        return;
+    }
+
+    rfc_port_sm_execute(p_port, RFC_EVENT_OPEN, NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_DlcEstablishRsp
+**
+** Description      This function is called by the port emulation entity
+**                  acks Establish Indication.
+**
+*******************************************************************************/
+void RFCOMM_DlcEstablishRsp (tRFC_MCB *p_mcb, uint8_t dlci,
+                             UNUSED_ATTR uint16_t mtu, uint16_t result)
+{
+    if ((p_mcb->state != RFC_MX_STATE_CONNECTED) && (result == RFCOMM_SUCCESS))
+    {
+        PORT_DlcReleaseInd (p_mcb, dlci);
+        return;
+    }
+
+    tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
+    if (p_port == NULL) {
+        RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__,
+                dlci);
+        return;
+    }
+    rfc_port_sm_execute(p_port, RFC_EVENT_ESTABLISH_RSP, &result);
+}
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_ParNegReq
+**
+** Description      This function is called by the user app to start
+**                  DLC parameter negotiation.  Port emulation can send this
+**                  request before actually establishing the DLC.  In this
+**                  case the function will allocate RFCOMM connection control
+**                  block.
+**
+*******************************************************************************/
+void RFCOMM_ParNegReq (tRFC_MCB *p_mcb, uint8_t dlci, uint16_t mtu)
+{
+    uint8_t flow;
+    uint8_t cl;
+    uint8_t k;
+
+    tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+    if (p_port == NULL) {
+        RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__,
+                dlci);
+        return;
+    }
+
+    if (p_mcb->state != RFC_MX_STATE_CONNECTED)
+    {
+        p_port->error = PORT_PAR_NEG_FAILED;
+        return;
+    }
+
+    /* Negotiate the flow control mechanism.  If flow control mechanism for */
+    /* mux has not been set yet, use our default value.  If it has been set, */
+    /* use that value. */
+    flow = (p_mcb->flow == PORT_FC_UNDEFINED) ? PORT_FC_DEFAULT : p_mcb->flow;
+
+    /* Set convergence layer and number of credits (k) */
+    if (flow == PORT_FC_CREDIT)
+    {
+        cl = RFCOMM_PN_CONV_LAYER_CBFC_I;
+        k = (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max : RFCOMM_K_MAX;
+        p_port->credit_rx = k;
+    }
+    else
+    {
+        cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
+        k = 0;
+    }
+
+    /* Send Parameter Negotiation Command UIH frame */
+    p_port->rfc.expected_rsp |= RFC_RSP_PN;
+
+    rfc_send_pn (p_mcb, dlci, true, mtu, cl, k);
+
+    rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;
+}
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_ParNegRsp
+**
+** Description      This function is called by the user app to acknowledge
+**                  DLC parameter negotiation.
+**
+*******************************************************************************/
+void RFCOMM_ParNegRsp (tRFC_MCB *p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl, uint8_t k)
+{
+    if (p_mcb->state != RFC_MX_STATE_CONNECTED)
+        return;
+
+    /* Send Parameter Negotiation Response UIH frame */
+    rfc_send_pn (p_mcb, dlci, false, mtu, cl, k);
+}
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_PortNegReq
+**
+** Description      This function is called by the user app to start
+**                  Remote Port parameter negotiation.  Port emulation can
+**                  send this request before actually establishing the DLC.
+**                  In this case the function will allocate RFCOMM connection
+**                  control block.
+**
+*******************************************************************************/
+void RFCOMM_PortNegReq (tRFC_MCB *p_mcb, uint8_t dlci, tPORT_STATE *p_pars)
+{
+    if (p_mcb->state != RFC_MX_STATE_CONNECTED)
+    {
+        PORT_PortNegCnf (p_mcb, dlci, NULL, RFCOMM_ERROR);
+        return;
+    }
+
+    tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+    if (p_port == NULL) {
+        RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__,
+                dlci);
+        return;
+    }
+
+    /* Send Parameter Negotiation Command UIH frame */
+    if (!p_pars)
+        p_port->rfc.expected_rsp |= RFC_RSP_RPN_REPLY;
+    else
+        p_port->rfc.expected_rsp |= RFC_RSP_RPN;
+
+    rfc_send_rpn (p_mcb, dlci, true, p_pars, RFCOMM_RPN_PM_MASK);
+    rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;
+
+}
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_PortNegRsp
+**
+** Description      This function is called by the user app to acknowledge
+**                  Port parameters negotiation.
+**
+*******************************************************************************/
+void RFCOMM_PortNegRsp (tRFC_MCB *p_mcb, uint8_t dlci, tPORT_STATE *p_pars,
+                        uint16_t param_mask)
+{
+    if (p_mcb->state != RFC_MX_STATE_CONNECTED)
+        return;
+
+   rfc_send_rpn (p_mcb, dlci, false, p_pars, param_mask);
+}
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_ControlReq
+**
+** Description      This function is called by the port entity to send control
+**                  parameters to remote port emulation entity.
+**
+*******************************************************************************/
+void RFCOMM_ControlReq (tRFC_MCB *p_mcb, uint8_t dlci, tPORT_CTRL *p_pars)
+{
+    tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+    if (p_port == NULL) {
+        RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__,
+                dlci);
+        return;
+    }
+
+    if ((p_port->state != PORT_STATE_OPENED)
+     || (p_port->rfc.state  != RFC_STATE_OPENED))
+        return;
+
+    p_port->port_ctrl |= PORT_CTRL_REQ_SENT;
+
+    p_port->rfc.expected_rsp |= RFC_RSP_MSC;
+
+    rfc_send_msc (p_mcb, dlci, true, p_pars);
+    rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;
+
+}
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_FlowReq
+**
+** Description      This function is called by the port entity when flow
+**                  control state has changed.  Enable flag passed shows if
+**                  port can accept more data.
+**
+*******************************************************************************/
+void RFCOMM_FlowReq (tRFC_MCB *p_mcb, uint8_t dlci, uint8_t enable)
+{
+    tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+    if (p_port == NULL) {
+        RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__,
+                dlci);
+        return;
+    }
+
+    if ((p_port->state != PORT_STATE_OPENED)
+     || (p_port->rfc.state  != RFC_STATE_OPENED))
+        return;
+
+    p_port->local_ctrl.fc = !enable;
+
+    p_port->rfc.expected_rsp |= RFC_RSP_MSC;
+
+    rfc_send_msc (p_mcb, dlci, true, &p_port->local_ctrl);
+    rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;
+
+}
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_LineStatusReq
+**
+** Description      This function is called by the port entity when line
+**                  status should be delivered to the peer.
+**
+*******************************************************************************/
+void RFCOMM_LineStatusReq (tRFC_MCB *p_mcb, uint8_t dlci, uint8_t status)
+{
+    tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+    if (p_port == NULL) {
+        RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__,
+                dlci);
+        return;
+    }
+
+    if ((p_port->state != PORT_STATE_OPENED)
+     || (p_port->rfc.state  != RFC_STATE_OPENED))
+        return;
+
+    p_port->rfc.expected_rsp |= RFC_RSP_RLS;
+
+    rfc_send_rls (p_mcb, dlci, true, status);
+    rfc_port_timer_start (p_port, RFC_T2_TIMEOUT);
+}
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_DlcReleaseReq
+**
+** Description      This function is called by the PORT unit to close DLC
+**
+*******************************************************************************/
+void RFCOMM_DlcReleaseReq (tRFC_MCB *p_mcb, uint8_t dlci)
+{
+    rfc_port_sm_execute(port_find_mcb_dlci_port (p_mcb, dlci), RFC_EVENT_CLOSE, 0);
+}
+
+
+/*******************************************************************************
+**
+** Function         RFCOMM_DataReq
+**
+** Description      This function is called by the user app to send data buffer
+**
+*******************************************************************************/
+void RFCOMM_DataReq (tRFC_MCB *p_mcb, uint8_t dlci, BT_HDR *p_buf)
+{
+    rfc_port_sm_execute(port_find_mcb_dlci_port (p_mcb, dlci), RFC_EVENT_DATA, p_buf);
+}
+
+
diff --git a/bt/stack/rfcomm/rfc_ts_frames.cc b/bt/stack/rfcomm/rfc_ts_frames.cc
new file mode 100644
index 0000000..9e07936
--- /dev/null
+++ b/bt/stack/rfcomm/rfc_ts_frames.cc
@@ -0,0 +1,876 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 functions to send TS 07.10 frames
+ *
+ ******************************************************************************/
+
+#include <stddef.h>
+#include "bt_target.h"
+#include "bt_common.h"
+#include "rfcdefs.h"
+#include "port_api.h"
+#include "l2c_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+
+/*******************************************************************************
+**
+** Function         rfc_send_sabme
+**
+** Description      This function sends SABME frame.
+**
+*******************************************************************************/
+void rfc_send_sabme (tRFC_MCB *p_mcb, uint8_t dlci)
+{
+    uint8_t *p_data;
+    uint8_t cr = RFCOMM_CR(p_mcb->is_initiator, true);
+    BT_HDR  *p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_data = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+    /* SABME frame, command, PF = 1, dlci */
+    *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
+    *p_data++ = RFCOMM_SABME | RFCOMM_PF;
+    *p_data++ = RFCOMM_EA | 0;
+
+    *p_data   = RFCOMM_SABME_FCS ((uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci);
+
+    p_buf->len = 4;
+
+    rfc_check_send_cmd(p_mcb, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_send_ua
+**
+** Description      This function sends UA frame.
+**
+*******************************************************************************/
+void rfc_send_ua (tRFC_MCB *p_mcb, uint8_t dlci)
+{
+    uint8_t *p_data;
+    uint8_t cr = RFCOMM_CR(p_mcb->is_initiator, false);
+    BT_HDR  *p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_data = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+    /* ua frame, response, PF = 1, dlci */
+    *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
+    *p_data++ = RFCOMM_UA | RFCOMM_PF;
+    *p_data++ = RFCOMM_EA | 0;
+
+    *p_data   = RFCOMM_UA_FCS ((uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci);
+
+    p_buf->len = 4;
+
+    rfc_check_send_cmd(p_mcb, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_send_dm
+**
+** Description      This function sends DM frame.
+**
+*******************************************************************************/
+void rfc_send_dm (tRFC_MCB *p_mcb, uint8_t dlci, bool    pf)
+{
+    uint8_t *p_data;
+    uint8_t cr = RFCOMM_CR(p_mcb->is_initiator, false);
+    BT_HDR  *p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_data = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+    /* DM frame, response, PF = 1, dlci */
+    *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
+    *p_data++ = RFCOMM_DM | ((pf) ? RFCOMM_PF : 0);
+    *p_data++ = RFCOMM_EA | 0;
+
+    *p_data   = RFCOMM_DM_FCS ((uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci);
+
+    p_buf->len = 4;
+
+    rfc_check_send_cmd(p_mcb, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_send_disc
+**
+** Description      This function sends DISC frame.
+**
+*******************************************************************************/
+void rfc_send_disc (tRFC_MCB *p_mcb, uint8_t dlci)
+{
+    uint8_t *p_data;
+    uint8_t cr = RFCOMM_CR(p_mcb->is_initiator, true);
+    BT_HDR  *p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_data = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+    /* DISC frame, command, PF = 1, dlci */
+    *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
+    *p_data++ = RFCOMM_DISC | RFCOMM_PF;
+    *p_data++ = RFCOMM_EA | 0;
+
+    *p_data   = RFCOMM_DISC_FCS ((uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci);
+
+    p_buf->len = 4;
+
+    rfc_check_send_cmd(p_mcb, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_send_buf_uih
+**
+** Description      This function sends UIH frame.
+**
+*******************************************************************************/
+void rfc_send_buf_uih (tRFC_MCB *p_mcb, uint8_t dlci, BT_HDR *p_buf)
+{
+    uint8_t *p_data;
+    uint8_t cr = RFCOMM_CR(p_mcb->is_initiator, true);
+    uint8_t credits;
+
+    p_buf->offset -= RFCOMM_CTRL_FRAME_LEN;
+    if (p_buf->len > 127)
+        p_buf->offset--;
+
+    if (dlci)
+        credits = (uint8_t)p_buf->layer_specific;
+    else
+        credits = 0;
+
+    if (credits)
+        p_buf->offset--;
+
+    p_data = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+    /* UIH frame, command, PF = 0, dlci */
+    *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
+    *p_data++ = RFCOMM_UIH | ((credits) ? RFCOMM_PF : 0);
+    if (p_buf->len <= 127)
+    {
+        *p_data++   = RFCOMM_EA | (p_buf->len << 1);
+        p_buf->len += 3;
+    }
+    else
+    {
+        *p_data++   = (p_buf->len & 0x7f) << 1;
+        *p_data++   = p_buf->len >> RFCOMM_SHIFT_LENGTH2;
+        p_buf->len += 4;
+    }
+
+    if (credits)
+    {
+        *p_data++ = credits;
+        p_buf->len++;
+    }
+
+    p_data  = (uint8_t *)(p_buf + 1) + p_buf->offset + p_buf->len++;
+
+    *p_data = RFCOMM_UIH_FCS ((uint8_t *)(p_buf + 1) + p_buf->offset, dlci);
+
+    if (dlci == RFCOMM_MX_DLCI)
+    {
+        rfc_check_send_cmd(p_mcb, p_buf);
+    }
+    else
+    {
+        L2CA_DataWrite (p_mcb->lcid, p_buf);
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_send_pn
+**
+** Description      This function sends DLC Parameters Negotiation Frame.
+**
+*******************************************************************************/
+void rfc_send_pn (tRFC_MCB *p_mcb, uint8_t dlci, bool    is_command, uint16_t mtu, uint8_t cl, uint8_t k)
+{
+    uint8_t  *p_data;
+    BT_HDR   *p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+    p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
+    p_data = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+    *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_PN;
+    *p_data++ = RFCOMM_EA | (RFCOMM_MX_PN_LEN << 1);
+
+    *p_data++ = dlci;
+    *p_data++ = RFCOMM_PN_FRAM_TYPE_UIH | cl;
+
+    /* It appeared that we need to reply with the same priority bits as we received.
+    ** We will use the fact that we reply in the same context so rx_frame can still be used.
+    */
+    if (is_command)
+        *p_data++ = RFCOMM_PN_PRIORITY_0;
+    else
+        *p_data++ = rfc_cb.rfc.rx_frame.u.pn.priority;
+
+    *p_data++ = RFCOMM_T1_DSEC;
+    *p_data++ = mtu & 0xFF;
+    *p_data++ = mtu >> 8;
+    *p_data++ = RFCOMM_N2;
+    *p_data   = k;
+
+    /* Total length is sizeof PN data + mx header 2 */
+    p_buf->len = RFCOMM_MX_PN_LEN + 2;
+
+    rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_send_fcon
+**
+** Description      This function sends Flow Control On Command.
+**
+*******************************************************************************/
+void rfc_send_fcon (tRFC_MCB *p_mcb, bool    is_command)
+{
+    uint8_t *p_data;
+    BT_HDR  *p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+    p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
+    p_data = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+    *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_FCON;
+    *p_data++ = RFCOMM_EA | (RFCOMM_MX_FCON_LEN << 1);
+
+    /* Total length is sizeof FCON data + mx header 2 */
+    p_buf->len = RFCOMM_MX_FCON_LEN + 2;
+
+    rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_send_fcoff
+**
+** Description      This function sends Flow Control Off Command.
+**
+*******************************************************************************/
+void rfc_send_fcoff (tRFC_MCB *p_mcb, bool    is_command)
+{
+    uint8_t *p_data;
+    BT_HDR  *p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+    p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
+    p_data = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+    *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_FCOFF;
+    *p_data++ = RFCOMM_EA | (RFCOMM_MX_FCOFF_LEN << 1);
+
+    /* Total length is sizeof FCOFF data + mx header 2 */
+    p_buf->len = RFCOMM_MX_FCOFF_LEN + 2;
+
+    rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_send_msc
+**
+** Description      This function sends Modem Status Command Frame.
+**
+*******************************************************************************/
+void rfc_send_msc (tRFC_MCB *p_mcb, uint8_t dlci, bool    is_command,
+                   tPORT_CTRL *p_pars)
+{
+    uint8_t *p_data;
+    uint8_t signals;
+    uint8_t break_duration;
+    uint8_t len;
+    BT_HDR  *p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+    signals        = p_pars->modem_signal;
+    break_duration = p_pars->break_signal;
+
+    p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
+    p_data = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+    if (break_duration)
+        len = RFCOMM_MX_MSC_LEN_WITH_BREAK;
+    else
+        len = RFCOMM_MX_MSC_LEN_NO_BREAK;
+
+    *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_MSC;
+    *p_data++ = RFCOMM_EA | (len << 1);
+
+    *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI);
+    *p_data++ = RFCOMM_EA |
+                ((p_pars->fc)                    ? RFCOMM_MSC_FC : 0)  |
+                ((signals & MODEM_SIGNAL_DTRDSR) ? RFCOMM_MSC_RTC : 0) |
+                ((signals & MODEM_SIGNAL_RTSCTS) ? RFCOMM_MSC_RTR : 0) |
+                ((signals & MODEM_SIGNAL_RI)     ? RFCOMM_MSC_IC : 0)  |
+                ((signals & MODEM_SIGNAL_DCD)    ? RFCOMM_MSC_DV : 0);
+
+    if (break_duration)
+    {
+        *p_data++ = RFCOMM_EA | RFCOMM_MSC_BREAK_PRESENT_MASK |
+                    (break_duration << RFCOMM_MSC_SHIFT_BREAK);
+    }
+
+    /* Total length is sizeof MSC data + mx header 2 */
+    p_buf->len = len + 2;
+
+    rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_send_rls
+**
+** Description      This function sends Remote Line Status Command Frame.
+**
+*******************************************************************************/
+void rfc_send_rls (tRFC_MCB *p_mcb, uint8_t dlci, bool    is_command, uint8_t status)
+{
+    uint8_t *p_data;
+    BT_HDR  *p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+    p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
+    p_data = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+    *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_RLS;
+    *p_data++ = RFCOMM_EA | (RFCOMM_MX_RLS_LEN << 1);
+
+    *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI);
+    *p_data++ = RFCOMM_RLS_ERROR | status;
+
+    /* Total length is sizeof RLS data + mx header 2 */
+    p_buf->len = RFCOMM_MX_RLS_LEN + 2;
+
+    rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_send_nsc
+**
+** Description      This function sends Non Supported Command Response.
+**
+*******************************************************************************/
+void rfc_send_nsc (tRFC_MCB *p_mcb)
+{
+    uint8_t *p_data;
+    BT_HDR  *p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+    p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
+    p_data = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+    *p_data++ = RFCOMM_EA | RFCOMM_I_CR(false) | RFCOMM_MX_NSC;
+    *p_data++ = RFCOMM_EA | (RFCOMM_MX_NSC_LEN << 1);
+
+    *p_data++ =  rfc_cb.rfc.rx_frame.ea |
+                (rfc_cb.rfc.rx_frame.cr << RFCOMM_SHIFT_CR) |
+                 rfc_cb.rfc.rx_frame.type;
+
+    /* Total length is sizeof NSC data + mx header 2 */
+    p_buf->len = RFCOMM_MX_NSC_LEN + 2;
+
+    rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_send_rpn
+**
+** Description      This function sends Remote Port Negotiation Command
+**
+*******************************************************************************/
+void rfc_send_rpn (tRFC_MCB *p_mcb, uint8_t dlci, bool    is_command,
+                   tPORT_STATE *p_pars, uint16_t mask)
+{
+    uint8_t  *p_data;
+    BT_HDR   *p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+    p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
+    p_data = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+    *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_RPN;
+
+    if (!p_pars)
+    {
+        *p_data++ = RFCOMM_EA | (RFCOMM_MX_RPN_REQ_LEN << 1);
+
+        *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI);
+
+        p_buf->len = RFCOMM_MX_RPN_REQ_LEN + 2;
+    }
+    else
+    {
+        *p_data++ = RFCOMM_EA | (RFCOMM_MX_RPN_LEN << 1);
+
+        *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI);
+        *p_data++ = p_pars->baud_rate;
+        *p_data++ =  (p_pars->byte_size << RFCOMM_RPN_BITS_SHIFT)
+                   | (p_pars->stop_bits << RFCOMM_RPN_STOP_BITS_SHIFT)
+                   | (p_pars->parity << RFCOMM_RPN_PARITY_SHIFT)
+                   | (p_pars->parity_type << RFCOMM_RPN_PARITY_TYPE_SHIFT);
+        *p_data++ = p_pars->fc_type;
+        *p_data++ = p_pars->xon_char;
+        *p_data++ = p_pars->xoff_char;
+        *p_data++ = (mask & 0xFF);
+        *p_data++ = (mask >> 8);
+
+        /* Total length is sizeof RPN data + mx header 2 */
+        p_buf->len = RFCOMM_MX_RPN_LEN + 2;
+    }
+
+    rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_send_test
+**
+** Description      This function sends Test frame.
+**
+*******************************************************************************/
+void rfc_send_test (tRFC_MCB *p_mcb, bool    is_command, BT_HDR *p_buf)
+{
+    /* Shift buffer to give space for header */
+    if (p_buf->offset < (L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2))
+    {
+        uint8_t *p_src  = (uint8_t *) (p_buf + 1) + p_buf->offset + p_buf->len - 1;
+        BT_HDR *p_new_buf = (BT_HDR *) osi_malloc(p_buf->len + (L2CAP_MIN_OFFSET +
+                            RFCOMM_MIN_OFFSET + 2 + sizeof(BT_HDR) + 1));
+
+        p_new_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2;
+        p_new_buf->len = p_buf->len;
+
+        uint8_t *p_dest = (uint8_t *) (p_new_buf + 1) + p_new_buf->offset + p_new_buf->len - 1;
+
+        for (uint16_t xx = 0; xx < p_buf->len; xx++)
+            *p_dest-- = *p_src--;
+
+        osi_free(p_buf);
+        p_buf = p_new_buf;
+    }
+
+    /* Adjust offset by number of bytes we are going to fill */
+    p_buf->offset -= 2;
+    uint8_t *p_data = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+    *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_TEST;
+    *p_data++ = RFCOMM_EA | (p_buf->len << 1);
+
+    p_buf->len += 2;
+
+    rfc_send_buf_uih (p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         rfc_send_credit
+**
+** Description      This function sends a flow control credit in UIH frame.
+**
+*******************************************************************************/
+void rfc_send_credit(tRFC_MCB *p_mcb, uint8_t dlci, uint8_t credit)
+{
+    uint8_t  *p_data;
+    uint8_t  cr = RFCOMM_CR(p_mcb->is_initiator, true);
+    BT_HDR   *p_buf = (BT_HDR *)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_data = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+    *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
+    *p_data++ = RFCOMM_UIH | RFCOMM_PF;
+    *p_data++ = RFCOMM_EA | 0;
+    *p_data++ = credit;
+    *p_data   = RFCOMM_UIH_FCS ((uint8_t *)(p_buf + 1) + p_buf->offset, dlci);
+
+    p_buf->len = 5;
+
+    rfc_check_send_cmd(p_mcb, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_parse_data
+**
+** Description      This function processes data packet received from L2CAP
+**
+*******************************************************************************/
+uint8_t rfc_parse_data (tRFC_MCB *p_mcb, MX_FRAME *p_frame, BT_HDR *p_buf)
+{
+    uint8_t   ead, eal, fcs;
+    uint8_t   *p_data = (uint8_t *)(p_buf + 1) + p_buf->offset;
+    uint8_t   *p_start = p_data;
+    uint16_t  len;
+
+    if (p_buf->len < RFCOMM_CTRL_FRAME_LEN)
+    {
+        RFCOMM_TRACE_ERROR ("Bad Length1: %d", p_buf->len);
+        return (RFC_EVENT_BAD_FRAME);
+    }
+
+    RFCOMM_PARSE_CTRL_FIELD (ead, p_frame->cr, p_frame->dlci, p_data);
+    if( !ead )
+    {
+        RFCOMM_TRACE_ERROR ("Bad Address(EA must be 1)");
+        return (RFC_EVENT_BAD_FRAME);
+    }
+    RFCOMM_PARSE_TYPE_FIELD (p_frame->type, p_frame->pf, p_data);
+    RFCOMM_PARSE_LEN_FIELD (eal, len, p_data);
+
+    p_buf->len      -= (3 + !ead + !eal + 1);  /* Additional 1 for FCS */
+    p_buf->offset   += (3 + !ead + !eal);
+
+    /* handle credit if credit based flow control */
+    if ((p_mcb->flow == PORT_FC_CREDIT) && (p_frame->type == RFCOMM_UIH) &&
+        (p_frame->dlci != RFCOMM_MX_DLCI) && (p_frame->pf == 1))
+    {
+        p_frame->credit = *p_data++;
+        p_buf->len--;
+        p_buf->offset++;
+    }
+    else
+        p_frame->credit = 0;
+
+    if (p_buf->len != len)
+    {
+        RFCOMM_TRACE_ERROR ("Bad Length2 %d %d", p_buf->len, len);
+        return (RFC_EVENT_BAD_FRAME);
+    }
+
+    fcs = *(p_data + len);
+
+    /* All control frames that we are sending are sent with P=1, expect */
+    /* reply with F=1 */
+    /* According to TS 07.10 spec ivalid frames are discarded without */
+    /* notification to the sender */
+    switch (p_frame->type)
+    {
+    case RFCOMM_SABME:
+        if (RFCOMM_FRAME_IS_RSP(p_mcb->is_initiator, p_frame->cr)
+         || !p_frame->pf || len || !RFCOMM_VALID_DLCI (p_frame->dlci)
+         || !rfc_check_fcs (RFCOMM_CTRL_FRAME_LEN, p_start, fcs))
+        {
+            RFCOMM_TRACE_ERROR ("Bad SABME");
+            return (RFC_EVENT_BAD_FRAME);
+        }
+        else
+            return (RFC_EVENT_SABME);
+
+    case RFCOMM_UA:
+        if (RFCOMM_FRAME_IS_CMD(p_mcb->is_initiator, p_frame->cr)
+          || !p_frame->pf || len || !RFCOMM_VALID_DLCI (p_frame->dlci)
+          || !rfc_check_fcs (RFCOMM_CTRL_FRAME_LEN, p_start, fcs))
+        {
+            RFCOMM_TRACE_ERROR ("Bad UA");
+            return (RFC_EVENT_BAD_FRAME);
+        }
+        else
+            return (RFC_EVENT_UA);
+
+    case RFCOMM_DM:
+        if (RFCOMM_FRAME_IS_CMD(p_mcb->is_initiator, p_frame->cr)
+         || len || !RFCOMM_VALID_DLCI(p_frame->dlci)
+         || !rfc_check_fcs (RFCOMM_CTRL_FRAME_LEN, p_start, fcs))
+        {
+            RFCOMM_TRACE_ERROR ("Bad DM");
+            return (RFC_EVENT_BAD_FRAME);
+        }
+        else
+            return (RFC_EVENT_DM);
+
+    case RFCOMM_DISC:
+        if (RFCOMM_FRAME_IS_RSP(p_mcb->is_initiator, p_frame->cr)
+          || !p_frame->pf || len || !RFCOMM_VALID_DLCI(p_frame->dlci)
+          || !rfc_check_fcs (RFCOMM_CTRL_FRAME_LEN, p_start, fcs))
+        {
+            RFCOMM_TRACE_ERROR ("Bad DISC");
+            return (RFC_EVENT_BAD_FRAME);
+        }
+        else
+            return (RFC_EVENT_DISC);
+
+    case RFCOMM_UIH:
+        if (!RFCOMM_VALID_DLCI(p_frame->dlci))
+        {
+            RFCOMM_TRACE_ERROR ("Bad UIH - invalid DLCI");
+            return (RFC_EVENT_BAD_FRAME);
+        }
+        else if (!rfc_check_fcs (2, p_start, fcs))
+        {
+            RFCOMM_TRACE_ERROR ("Bad UIH - FCS");
+            return (RFC_EVENT_BAD_FRAME);
+        }
+        else if (RFCOMM_FRAME_IS_RSP(p_mcb->is_initiator, p_frame->cr))
+        {
+            /* we assume that this is ok to allow bad implementations to work */
+            RFCOMM_TRACE_ERROR ("Bad UIH - response");
+            return (RFC_EVENT_UIH);
+        }
+        else
+            return (RFC_EVENT_UIH);
+    }
+
+    return (RFC_EVENT_BAD_FRAME);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_process_mx_message
+**
+** Description      This function processes UIH frames received on the
+**                  multiplexer control channel.
+**
+*******************************************************************************/
+void rfc_process_mx_message (tRFC_MCB *p_mcb, BT_HDR *p_buf)
+{
+    uint8_t     *p_data = (uint8_t *)(p_buf + 1) + p_buf->offset;
+    MX_FRAME    *p_rx_frame = &rfc_cb.rfc.rx_frame;
+    uint16_t     length  = p_buf->len;
+    uint8_t      ea, cr, mx_len;
+    bool         is_command;
+
+    p_rx_frame->ea   = *p_data & RFCOMM_EA;
+    p_rx_frame->cr   = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
+    p_rx_frame->type = *p_data++ & ~(RFCOMM_CR_MASK | RFCOMM_EA_MASK);
+
+    if (!p_rx_frame->ea || !length)
+    {
+        RFCOMM_TRACE_ERROR ("Illegal MX Frame ea:%d len:%d", p_rx_frame->ea, length);
+        osi_free(p_buf);
+        return;
+    }
+
+    length--;
+
+    is_command = p_rx_frame->cr;
+
+    ea = *p_data & RFCOMM_EA;
+
+    mx_len = *p_data++ >> RFCOMM_SHIFT_LENGTH1;
+    length--;
+
+    if (!ea)
+    {
+        mx_len += *p_data++ << RFCOMM_SHIFT_LENGTH2;
+        length --;
+    }
+
+    if (mx_len != length)
+    {
+        RFCOMM_TRACE_ERROR ("Bad MX frame");
+        osi_free(p_buf);
+        return;
+    }
+
+    switch (p_rx_frame->type)
+    {
+    case RFCOMM_MX_PN:
+        if (length != RFCOMM_MX_PN_LEN)
+            break;
+
+        p_rx_frame->dlci            = *p_data++ & RFCOMM_PN_DLCI_MASK;
+        p_rx_frame->u.pn.frame_type = *p_data & RFCOMM_PN_FRAME_TYPE_MASK;
+        p_rx_frame->u.pn.conv_layer = *p_data++ & RFCOMM_PN_CONV_LAYER_MASK;
+        p_rx_frame->u.pn.priority   = *p_data++ & RFCOMM_PN_PRIORITY_MASK;
+        p_rx_frame->u.pn.t1         = *p_data++;
+        p_rx_frame->u.pn.mtu        = *p_data + (*(p_data + 1) << 8);
+        p_data += 2;
+        p_rx_frame->u.pn.n2         = *p_data++;
+        p_rx_frame->u.pn.k          = *p_data++ & RFCOMM_PN_K_MASK;
+
+        if (!p_rx_frame->dlci
+         || !RFCOMM_VALID_DLCI (p_rx_frame->dlci)
+         || (p_rx_frame->u.pn.mtu < RFCOMM_MIN_MTU)
+         || (p_rx_frame->u.pn.mtu > RFCOMM_MAX_MTU))
+        {
+            RFCOMM_TRACE_ERROR ("Bad PN frame");
+            break;
+        }
+
+        osi_free(p_buf);
+
+        rfc_process_pn (p_mcb, is_command, p_rx_frame);
+        return;
+
+    case RFCOMM_MX_TEST:
+        if (!length)
+            break;
+
+        p_rx_frame->u.test.p_data   = p_data;
+        p_rx_frame->u.test.data_len = length;
+
+        p_buf->offset += 2;
+        p_buf->len    -= 2;
+
+        if (is_command)
+            rfc_send_test (p_mcb, false, p_buf);
+        else
+            rfc_process_test_rsp (p_mcb, p_buf);
+        return;
+
+    case RFCOMM_MX_FCON:
+        if (length != RFCOMM_MX_FCON_LEN)
+            break;
+
+        osi_free(p_buf);
+
+        rfc_process_fcon (p_mcb, is_command);
+        return;
+
+    case RFCOMM_MX_FCOFF:
+        if (length != RFCOMM_MX_FCOFF_LEN)
+            break;
+
+        osi_free(p_buf);
+
+        rfc_process_fcoff (p_mcb, is_command);
+        return;
+
+    case RFCOMM_MX_MSC:
+
+        ea                   = *p_data & RFCOMM_EA;
+        cr                   = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
+        p_rx_frame->dlci = *p_data++ >> RFCOMM_SHIFT_DLCI;
+
+        if (!ea || !cr || !p_rx_frame->dlci
+         || !RFCOMM_VALID_DLCI (p_rx_frame->dlci))
+        {
+            RFCOMM_TRACE_ERROR ("Bad MSC frame");
+            break;
+        }
+
+        p_rx_frame->u.msc.signals        = *p_data++;
+
+        if (mx_len == RFCOMM_MX_MSC_LEN_WITH_BREAK)
+        {
+            p_rx_frame->u.msc.break_present  = *p_data & RFCOMM_MSC_BREAK_PRESENT_MASK;
+            p_rx_frame->u.msc.break_duration = (*p_data & RFCOMM_MSC_BREAK_MASK) >> RFCOMM_MSC_SHIFT_BREAK;
+        }
+        else
+        {
+            p_rx_frame->u.msc.break_present  = false;
+            p_rx_frame->u.msc.break_duration = 0;
+        }
+        osi_free(p_buf);
+
+        rfc_process_msc (p_mcb, is_command, p_rx_frame);
+        return;
+
+    case RFCOMM_MX_NSC:
+        if ((length != RFCOMM_MX_NSC_LEN) || !is_command)
+            break;
+
+        p_rx_frame->u.nsc.ea   = *p_data & RFCOMM_EA;
+        p_rx_frame->u.nsc.cr   = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
+        p_rx_frame->u.nsc.type = *p_data++ >> RFCOMM_SHIFT_DLCI;
+
+        osi_free(p_buf);
+
+        rfc_process_nsc (p_mcb, p_rx_frame);
+        return;
+
+    case RFCOMM_MX_RPN:
+        if ((length != RFCOMM_MX_RPN_REQ_LEN) && (length != RFCOMM_MX_RPN_LEN))
+            break;
+
+        ea                   = *p_data & RFCOMM_EA;
+        cr                   = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
+        p_rx_frame->dlci = *p_data++ >> RFCOMM_SHIFT_DLCI;
+
+        if (!ea || !cr || !p_rx_frame->dlci
+         || !RFCOMM_VALID_DLCI (p_rx_frame->dlci))
+        {
+            RFCOMM_TRACE_ERROR ("Bad RPN frame");
+            break;
+        }
+
+        p_rx_frame->u.rpn.is_request  = (length == RFCOMM_MX_RPN_REQ_LEN);
+
+        if (!p_rx_frame->u.rpn.is_request)
+        {
+            p_rx_frame->u.rpn.baud_rate   = *p_data++;
+            p_rx_frame->u.rpn.byte_size   = (*p_data >> RFCOMM_RPN_BITS_SHIFT) & RFCOMM_RPN_BITS_MASK;
+            p_rx_frame->u.rpn.stop_bits   = (*p_data >> RFCOMM_RPN_STOP_BITS_SHIFT) & RFCOMM_RPN_STOP_BITS_MASK;
+            p_rx_frame->u.rpn.parity      = (*p_data >> RFCOMM_RPN_PARITY_SHIFT) & RFCOMM_RPN_PARITY_MASK;
+            p_rx_frame->u.rpn.parity_type = (*p_data++ >> RFCOMM_RPN_PARITY_TYPE_SHIFT) & RFCOMM_RPN_PARITY_TYPE_MASK;
+
+            p_rx_frame->u.rpn.fc_type     = *p_data++ & RFCOMM_FC_MASK;
+            p_rx_frame->u.rpn.xon_char    = *p_data++;
+            p_rx_frame->u.rpn.xoff_char   = *p_data++;
+            p_rx_frame->u.rpn.param_mask  = (*p_data + (*(p_data + 1) << 8)) & RFCOMM_RPN_PM_MASK;
+        }
+        osi_free(p_buf);
+
+        rfc_process_rpn (p_mcb, is_command, p_rx_frame->u.rpn.is_request, p_rx_frame);
+        return;
+
+    case RFCOMM_MX_RLS:
+        if (length != RFCOMM_MX_RLS_LEN)
+            break;
+
+        ea = *p_data & RFCOMM_EA;
+        cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
+
+        p_rx_frame->dlci              = *p_data++ >> RFCOMM_SHIFT_DLCI;
+        p_rx_frame->u.rls.line_status = (*p_data & ~0x01);
+
+        if (!ea || !cr || !p_rx_frame->dlci
+         || !RFCOMM_VALID_DLCI (p_rx_frame->dlci))
+        {
+            RFCOMM_TRACE_ERROR ("Bad RPN frame");
+            break;
+        }
+
+        osi_free(p_buf);
+
+        rfc_process_rls (p_mcb, is_command, p_rx_frame);
+        return;
+    }
+
+    osi_free(p_buf);
+
+    if (is_command)
+        rfc_send_nsc (p_mcb);
+}
+
diff --git a/bt/stack/rfcomm/rfc_utils.cc b/bt/stack/rfcomm/rfc_utils.cc
new file mode 100644
index 0000000..7d63241
--- /dev/null
+++ b/bt/stack/rfcomm/rfc_utils.cc
@@ -0,0 +1,474 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 collection of utility functions used the RFCOMM unit
+ *
+ *****************************************************************************/
+
+#include "bt_target.h"
+#include "bt_common.h"
+
+#include "btm_api.h"
+#include "btm_int.h"
+#include "rfcdefs.h"
+#include "port_api.h"
+#include "port_ext.h"
+#include "port_int.h"
+#include "rfc_int.h"
+#include "btu.h"
+#include "bt_utils.h"
+#include "osi/include/osi.h"
+
+#include <string.h>
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+/*******************************************************************************
+**
+** Function         rfc_calc_fcs
+**
+** Description      Reversed CRC Table , 8-bit, poly=0x07
+**                  (GSM 07.10 TS 101 369 V6.3.0)
+*******************************************************************************/
+static const uint8_t rfc_crctable[] =
+{
+    0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75,  0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
+    0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69,  0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
+    0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D,  0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
+    0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51,  0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
+
+    0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05,  0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
+    0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19,  0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
+    0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D,  0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
+    0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21,  0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
+
+    0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95,  0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
+    0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89,  0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
+    0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD,  0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
+    0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1,  0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
+
+    0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5,  0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
+    0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9,  0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
+    0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD,  0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
+    0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1,  0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
+};
+
+
+/*******************************************************************************
+**
+** Function         rfc_calc_fcs
+**
+** Description      This function calculate FCS for the RFCOMM frame
+**                  (GSM 07.10 TS 101 369 V6.3.0)
+**
+** Input            len - number of bytes in the message
+**                  p   - points to message
+**
+*******************************************************************************/
+uint8_t rfc_calc_fcs (uint16_t len, uint8_t *p)
+{
+    uint8_t fcs = 0xFF;
+
+    while (len--)
+    {
+        fcs = rfc_crctable[fcs ^ *p++];
+    }
+
+    /* Ones compliment */
+    return (0xFF - fcs);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_check_fcs
+**
+** Description      This function checks FCS for the RFCOMM frame
+**                  (GSM 07.10 TS 101 369 V6.3.0)
+**
+** Input            len          - number of bytes in the message
+**                  p            - points to message
+**                  received_fcs - received FCS
+**
+*******************************************************************************/
+bool    rfc_check_fcs (uint16_t len, uint8_t *p, uint8_t received_fcs)
+{
+    uint8_t fcs = 0xFF;
+
+    while (len--)
+    {
+        fcs = rfc_crctable[fcs ^ *p++];
+    }
+
+    /* Ones compliment */
+    fcs = rfc_crctable[fcs ^ received_fcs];
+
+    /*0xCF is the reversed order of 11110011.*/
+    return (fcs == 0xCF);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_alloc_multiplexer_channel
+**
+** Description      This function returns existing or new control block for
+**                  the BD_ADDR.
+**
+*******************************************************************************/
+tRFC_MCB *rfc_alloc_multiplexer_channel (BD_ADDR bd_addr, bool    is_initiator)
+{
+    int i, j;
+    tRFC_MCB *p_mcb = NULL;
+    RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel: bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
+                                bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+    RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel:is_initiator:%d", is_initiator);
+
+    for (i = 0; i < MAX_BD_CONNECTIONS; i++)
+    {
+        RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel rfc_cb.port.rfc_mcb[%d].state:%d",
+                            i, rfc_cb.port.rfc_mcb[i].state);
+        RFCOMM_TRACE_DEBUG("(rfc_cb.port.rfc_mcb[i].bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
+                                rfc_cb.port.rfc_mcb[i].bd_addr[0], rfc_cb.port.rfc_mcb[i].bd_addr[1],
+                                rfc_cb.port.rfc_mcb[i].bd_addr[2], rfc_cb.port.rfc_mcb[i].bd_addr[3],
+                                rfc_cb.port.rfc_mcb[i].bd_addr[4], rfc_cb.port.rfc_mcb[i].bd_addr[5]);
+
+        if ((rfc_cb.port.rfc_mcb[i].state != RFC_MX_STATE_IDLE)
+         && (!memcmp (rfc_cb.port.rfc_mcb[i].bd_addr, bd_addr, BD_ADDR_LEN)))
+        {
+            /* Multiplexer channel found do not change anything */
+            /* If there was an inactivity timer running stop it now */
+            if (rfc_cb.port.rfc_mcb[i].state == RFC_MX_STATE_CONNECTED)
+                rfc_timer_stop (&rfc_cb.port.rfc_mcb[i]);
+            RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel:is_initiator:%d, found, state:%d, p_mcb:%p",
+                                is_initiator, rfc_cb.port.rfc_mcb[i].state, &rfc_cb.port.rfc_mcb[i]);
+            return (&rfc_cb.port.rfc_mcb[i]);
+        }
+    }
+
+    /* connection with bd_addr does not exist */
+    for (i = 0, j = rfc_cb.rfc.last_mux + 1; i < MAX_BD_CONNECTIONS; i++, j++)
+    {
+        if (j >= MAX_BD_CONNECTIONS)
+            j = 0;
+
+        p_mcb = &rfc_cb.port.rfc_mcb[j];
+        if (rfc_cb.port.rfc_mcb[j].state == RFC_MX_STATE_IDLE)
+        {
+            /* New multiplexer control block */
+            alarm_free(p_mcb->mcb_timer);
+            fixed_queue_free(p_mcb->cmd_q, NULL);
+            memset (p_mcb, 0, sizeof (tRFC_MCB));
+            memcpy (p_mcb->bd_addr, bd_addr, BD_ADDR_LEN);
+            RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel:is_initiator:%d, create new p_mcb:%p, index:%d",
+                                is_initiator, &rfc_cb.port.rfc_mcb[j], j);
+
+            p_mcb->mcb_timer = alarm_new("rfcomm_mcb.mcb_timer");
+            p_mcb->cmd_q = fixed_queue_new(SIZE_MAX);
+
+            p_mcb->is_initiator = is_initiator;
+
+            rfc_timer_start (p_mcb, RFC_MCB_INIT_INACT_TIMER);
+
+            rfc_cb.rfc.last_mux = (uint8_t) j;
+            return (p_mcb);
+        }
+    }
+    return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_release_multiplexer_channel
+**
+** Description      Release a multiplexer control block
+**
+*******************************************************************************/
+void rfc_release_multiplexer_channel (tRFC_MCB *p_mcb)
+{
+    /* Remove the MCB from the mapping table */
+    rfc_save_lcid_mcb(NULL, p_mcb->lcid);
+
+    /* Remove the MCB from the ports */
+    for (int i = 0; i < MAX_RFC_PORTS; i++) {
+        if (rfc_cb.port.port[i].rfc.p_mcb == p_mcb)
+            rfc_cb.port.port[i].rfc.p_mcb = NULL;
+    }
+
+    rfc_timer_stop (p_mcb);
+    alarm_free(p_mcb->mcb_timer);
+
+    fixed_queue_free(p_mcb->cmd_q, osi_free);
+
+    memset (p_mcb, 0, sizeof (tRFC_MCB));
+    p_mcb->state = RFC_MX_STATE_IDLE;
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_timer_start
+**
+** Description      Start RFC Timer
+**
+*******************************************************************************/
+void rfc_timer_start(tRFC_MCB *p_mcb, uint16_t timeout)
+{
+    RFCOMM_TRACE_EVENT ("%s - timeout:%d seconds", __func__, timeout);
+
+    period_ms_t interval_ms = timeout * 1000;
+    alarm_set_on_queue(p_mcb->mcb_timer, interval_ms,
+                       rfcomm_mcb_timer_timeout, p_mcb,
+                       btu_general_alarm_queue);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_timer_stop
+**
+** Description      Stop RFC Timer
+**
+*******************************************************************************/
+void rfc_timer_stop(tRFC_MCB *p_mcb)
+{
+    RFCOMM_TRACE_EVENT("%s", __func__);
+
+    alarm_cancel(p_mcb->mcb_timer);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_port_timer_start
+**
+** Description      Start RFC Timer
+**
+*******************************************************************************/
+void rfc_port_timer_start(tPORT *p_port, uint16_t timeout)
+{
+    RFCOMM_TRACE_EVENT("%s - timeout:%d seconds", __func__, timeout);
+
+    period_ms_t interval_ms = timeout * 1000;
+    alarm_set_on_queue(p_port->rfc.port_timer, interval_ms,
+                       rfcomm_port_timer_timeout, p_port,
+                       btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+**
+** Function         rfc_port_timer_stop
+**
+** Description      Stop RFC Timer
+**
+*******************************************************************************/
+void rfc_port_timer_stop(tPORT *p_port)
+{
+    RFCOMM_TRACE_EVENT ("%s", __func__);
+
+    alarm_cancel(p_port->rfc.port_timer);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_check_mcb_active
+**
+** Description      Check if there are any opened ports on the MCB if not
+**                  start MCB Inact timer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void rfc_check_mcb_active (tRFC_MCB *p_mcb)
+{
+    uint16_t i;
+
+    for (i = 0; i < RFCOMM_MAX_DLCI; i++)
+    {
+        if (p_mcb->port_inx[i] != 0)
+        {
+            p_mcb->is_disc_initiator = false;
+            return;
+        }
+    }
+    /* The last port was DISCed.  On the client side start disconnecting Mx */
+    /* On the server side start inactivity timer */
+    if (p_mcb->is_disc_initiator)
+    {
+        p_mcb->is_disc_initiator = false;
+        rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_CLOSE_REQ, NULL);
+    }
+    else
+        rfc_timer_start (p_mcb, RFC_MCB_RELEASE_INACT_TIMER);
+}
+
+void rfcomm_port_timer_timeout(void *data)
+{
+    tPORT *p_port = (tPORT *)data;
+
+    rfc_port_sm_execute(p_port, RFC_EVENT_TIMEOUT, NULL);
+}
+
+void rfcomm_mcb_timer_timeout(void *data)
+{
+    tRFC_MCB *p_mcb = (tRFC_MCB *)data;
+
+    rfc_mx_sm_execute(p_mcb, RFC_EVENT_TIMEOUT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         rfc_sec_check_complete
+**
+** Description      The function called when Security Manager finishes
+**                  verification of the service side connection
+**
+** Returns          void
+**
+*******************************************************************************/
+void rfc_sec_check_complete (UNUSED_ATTR BD_ADDR bd_addr, UNUSED_ATTR tBT_TRANSPORT transport, void *p_ref_data,
+                             uint8_t res)
+{
+    tPORT *p_port = (tPORT *)p_ref_data;
+
+    /* Verify that PORT is still waiting for Security to complete */
+    if (!p_port->in_use
+     || ((p_port->rfc.state != RFC_STATE_ORIG_WAIT_SEC_CHECK)
+      && (p_port->rfc.state != RFC_STATE_TERM_WAIT_SEC_CHECK)))
+        return;
+
+    rfc_port_sm_execute ((tPORT *)p_ref_data, RFC_EVENT_SEC_COMPLETE, &res);
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_port_closed
+**
+** Description      The function is called when port is released based on the
+**                  event received from the lower layer, typically L2CAP
+**                  connection down, DISC, or DM frame.
+**
+** Returns          void
+**
+*******************************************************************************/
+void rfc_port_closed (tPORT *p_port)
+{
+    tRFC_MCB *p_mcb = p_port->rfc.p_mcb;
+
+    RFCOMM_TRACE_DEBUG ("rfc_port_closed");
+
+    rfc_port_timer_stop (p_port);
+
+    p_port->rfc.state = RFC_STATE_CLOSED;
+
+    /* If multiplexer channel was up mark it as down */
+    if (p_mcb)
+    {
+        p_mcb->port_inx[p_port->dlci] = 0;
+
+        /* If there are no more ports opened on this MCB release it */
+        rfc_check_mcb_active (p_mcb);
+    }
+
+    /* Notify port that RFC connection is gone */
+    port_rfc_closed (p_port, PORT_CLOSED);
+}
+
+/*******************************************************************************
+**
+** Function         rfc_inc_credit
+**
+** Description      The function is called when a credit is received in a UIH
+**                  frame.  It increments the TX credit count, and if data
+**                  flow had halted, it restarts it.
+**
+** Returns          void
+**
+*******************************************************************************/
+void rfc_inc_credit (tPORT *p_port, uint8_t credit)
+{
+    if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT)
+    {
+        p_port->credit_tx += credit;
+
+        RFCOMM_TRACE_EVENT ("rfc_inc_credit:%d", p_port->credit_tx);
+
+        if (p_port->tx.peer_fc == true)
+            PORT_FlowInd(p_port->rfc.p_mcb, p_port->dlci, true);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         rfc_dec_credit
+**
+** Description      The function is called when a UIH frame of user data is
+**                  sent.  It decrements the credit count.  If credit count
+**                  Reaches zero, peer_fc is set.
+**
+** Returns          void
+**
+*******************************************************************************/
+void rfc_dec_credit (tPORT *p_port)
+{
+    if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT)
+    {
+        if (p_port->credit_tx > 0)
+            p_port->credit_tx--;
+
+        if (p_port->credit_tx == 0)
+            p_port->tx.peer_fc = true;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         rfc_check_send_cmd
+**
+** Description      This function is called to send an RFCOMM command message
+**                  or to handle the RFCOMM command message queue.
+**
+** Returns          void
+**
+*******************************************************************************/
+void rfc_check_send_cmd(tRFC_MCB *p_mcb, BT_HDR *p_buf)
+{
+    /* if passed a buffer queue it */
+    if (p_buf != NULL) {
+        if (p_mcb->cmd_q == NULL) {
+            RFCOMM_TRACE_ERROR("%s: empty queue: p_mcb = %p p_mcb->lcid = %u cached p_mcb = %p",
+                               __func__, p_mcb, p_mcb->lcid,
+                               rfc_find_lcid_mcb(p_mcb->lcid));
+        }
+        fixed_queue_enqueue(p_mcb->cmd_q, p_buf);
+    }
+
+    /* handle queue if L2CAP not congested */
+    while (p_mcb->l2cap_congested == false) {
+        BT_HDR *p = (BT_HDR *)fixed_queue_try_dequeue(p_mcb->cmd_q);
+        if (p == NULL)
+            break;
+        L2CA_DataWrite(p_mcb->lcid, p);
+    }
+}
diff --git a/bt/stack/sdp/sdp_api.cc b/bt/stack/sdp/sdp_api.cc
new file mode 100644
index 0000000..6ac29cf
--- /dev/null
+++ b/bt/stack/sdp/sdp_api.cc
@@ -0,0 +1,1276 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 SDP interface functions
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "bt_common.h"
+#include "l2cdefs.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+
+#include "sdp_api.h"
+#include "sdpint.h"
+#include "btu.h"
+
+#include "osi/include/osi.h"
+
+/**********************************************************************
+**   C L I E N T    F U N C T I O N    P R O T O T Y P E S            *
+***********************************************************************/
+
+/*******************************************************************************
+**
+** Function         SDP_InitDiscoveryDb
+**
+** Description      This function is called to initialize a discovery database.
+**
+** Parameters:      p_db        - (input) address of an area of memory where the
+**                                        discovery database is managed.
+**                  len         - (input) size (in bytes) of the memory
+**                                  NOTE: This must be larger than sizeof(tSDP_DISCOVERY_DB)
+**                  num_uuid    - (input) number of UUID filters applied
+**                  p_uuid_list - (input) list of UUID filters
+**                  num_attr    - (input) number of attribute filters applied
+**                  p_attr_list - (input) list of attribute filters
+**
+**
+** Returns          bool
+**                          true if successful
+**                          false if one or more parameters are bad
+**
+*******************************************************************************/
+bool    SDP_InitDiscoveryDb (tSDP_DISCOVERY_DB *p_db, uint32_t len, uint16_t num_uuid,
+                             tSDP_UUID *p_uuid_list, uint16_t num_attr, uint16_t *p_attr_list)
+{
+#if (SDP_CLIENT_ENABLED == TRUE)
+    uint16_t xx;
+
+    /* verify the parameters */
+    if (p_db == NULL || (sizeof (tSDP_DISCOVERY_DB) > len) ||
+        num_attr > SDP_MAX_ATTR_FILTERS || num_uuid > SDP_MAX_UUID_FILTERS)
+    {
+        SDP_TRACE_ERROR("SDP_InitDiscoveryDb Illegal param: p_db 0x%x, len %d, num_uuid %d, num_attr %d",
+                        PTR_TO_UINT(p_db), len, num_uuid, num_attr);
+
+        return(false);
+    }
+
+    memset (p_db, 0, (size_t)len);
+
+    p_db->mem_size = len - sizeof (tSDP_DISCOVERY_DB);
+    p_db->mem_free = p_db->mem_size;
+    p_db->p_first_rec = NULL;
+    p_db->p_free_mem = (uint8_t *)(p_db + 1);
+
+    for (xx = 0; xx < num_uuid; xx++)
+        p_db->uuid_filters[xx] = *p_uuid_list++;
+
+    p_db->num_uuid_filters = num_uuid;
+
+    for (xx = 0; xx < num_attr; xx++)
+        p_db->attr_filters[xx] = *p_attr_list++;
+
+    /* sort attributes */
+    sdpu_sort_attr_list( num_attr, p_db );
+
+    p_db->num_attr_filters = num_attr;
+#endif
+    return(true);
+}
+
+
+
+/*******************************************************************************
+**
+** Function         SDP_CancelServiceSearch
+**
+** Description      This function cancels an active query to an SDP server.
+**
+** Returns          true if discovery cancelled, false if a matching activity is not found.
+**
+*******************************************************************************/
+bool    SDP_CancelServiceSearch (tSDP_DISCOVERY_DB *p_db)
+{
+#if (SDP_CLIENT_ENABLED == TRUE)
+    tCONN_CB     *p_ccb = sdpu_find_ccb_by_db (p_db);
+    if (!p_ccb)
+        return(false);
+
+    sdp_disconnect (p_ccb, SDP_CANCEL);
+    p_ccb->disc_state = SDP_DISC_WAIT_CANCEL;
+#endif
+    return(true);
+}
+
+
+
+/*******************************************************************************
+**
+** Function         SDP_ServiceSearchRequest
+**
+** Description      This function queries an SDP server for information.
+**
+** Returns          true if discovery started, false if failed.
+**
+*******************************************************************************/
+bool    SDP_ServiceSearchRequest (uint8_t *p_bd_addr, tSDP_DISCOVERY_DB *p_db,
+                                  tSDP_DISC_CMPL_CB *p_cb)
+{
+#if (SDP_CLIENT_ENABLED == TRUE)
+    tCONN_CB     *p_ccb;
+
+    /* Specific BD address */
+    p_ccb = sdp_conn_originate (p_bd_addr);
+
+    if (!p_ccb)
+        return(false);
+
+    p_ccb->disc_state = SDP_DISC_WAIT_CONN;
+    p_ccb->p_db       = p_db;
+    p_ccb->p_cb       = p_cb;
+
+    return(true);
+#else
+    return(false);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function         SDP_ServiceSearchAttributeRequest
+**
+** Description      This function queries an SDP server for information.
+**
+**                  The difference between this API function and the function
+**                  SDP_ServiceSearchRequest is that this one does a
+**                  combined ServiceSearchAttributeRequest SDP function.
+**                  (This is for Unplug Testing)
+**
+** Returns          true if discovery started, false if failed.
+**
+*******************************************************************************/
+bool    SDP_ServiceSearchAttributeRequest (uint8_t *p_bd_addr, tSDP_DISCOVERY_DB *p_db,
+                                           tSDP_DISC_CMPL_CB *p_cb)
+{
+#if (SDP_CLIENT_ENABLED == TRUE)
+    tCONN_CB     *p_ccb;
+
+    /* Specific BD address */
+    p_ccb = sdp_conn_originate (p_bd_addr);
+
+    if (!p_ccb)
+        return(false);
+
+    p_ccb->disc_state = SDP_DISC_WAIT_CONN;
+    p_ccb->p_db       = p_db;
+    p_ccb->p_cb       = p_cb;
+
+    p_ccb->is_attr_search = true;
+
+    return(true);
+#else
+    return(false);
+#endif
+}
+/*******************************************************************************
+**
+** Function         SDP_ServiceSearchAttributeRequest2
+**
+** Description      This function queries an SDP server for information.
+**
+**                  The difference between this API function and the function
+**                  SDP_ServiceSearchRequest is that this one does a
+**                  combined ServiceSearchAttributeRequest SDP function.
+**                  (This is for Unplug Testing)
+**
+** Returns          true if discovery started, false if failed.
+**
+*******************************************************************************/
+bool    SDP_ServiceSearchAttributeRequest2 (uint8_t *p_bd_addr, tSDP_DISCOVERY_DB *p_db,
+                                            tSDP_DISC_CMPL_CB2 *p_cb2, void * user_data)
+{
+#if (SDP_CLIENT_ENABLED == TRUE)
+    tCONN_CB     *p_ccb;
+
+    /* Specific BD address */
+    p_ccb = sdp_conn_originate (p_bd_addr);
+
+    if (!p_ccb)
+        return(false);
+
+    p_ccb->disc_state = SDP_DISC_WAIT_CONN;
+    p_ccb->p_db       = p_db;
+    p_ccb->p_cb2       = p_cb2;
+
+    p_ccb->is_attr_search = true;
+    p_ccb->user_data = user_data;
+
+    return(true);
+#else
+    return(false);
+#endif
+}
+
+#if (SDP_CLIENT_ENABLED == TRUE)
+void SDP_SetIdleTimeout (UNUSED_ATTR BD_ADDR addr,
+                         UNUSED_ATTR uint16_t timeout)
+{
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         SDP_FindAttributeInDb
+**
+** Description      This function queries an SDP database for a specific attribute.
+**                  If the p_start_rec pointer is NULL, it looks from the beginning
+**                  of the database, else it continues from the next record after
+**                  p_start_rec.
+**
+** Returns          Pointer to matching record, or NULL
+**
+*******************************************************************************/
+tSDP_DISC_REC *SDP_FindAttributeInDb (tSDP_DISCOVERY_DB *p_db, uint16_t attr_id,
+                                      tSDP_DISC_REC *p_start_rec)
+{
+#if (SDP_CLIENT_ENABLED == TRUE)
+    tSDP_DISC_REC   *p_rec;
+    tSDP_DISC_ATTR  *p_attr;
+
+    /* Must have a valid database */
+    if (p_db == NULL)
+        return(NULL);
+
+    if (!p_start_rec)
+        p_rec = p_db->p_first_rec;
+    else
+        p_rec = p_start_rec->p_next_rec;
+
+    while (p_rec)
+    {
+        p_attr = p_rec->p_first_attr;
+        while (p_attr)
+        {
+            if (p_attr->attr_id == attr_id)
+                return(p_rec);
+
+            p_attr = p_attr->p_next_attr;
+        }
+
+        p_rec = p_rec->p_next_rec;
+    }
+#endif
+    /* If here, no matching attribute found */
+    return(NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         SDP_FindAttributeInRec
+**
+** Description      This function searches an SDP discovery record for a specific
+**                  attribute.
+**
+** Returns          Pointer to matching attribute entry, or NULL
+**
+*******************************************************************************/
+tSDP_DISC_ATTR *SDP_FindAttributeInRec (tSDP_DISC_REC *p_rec, uint16_t attr_id)
+{
+#if (SDP_CLIENT_ENABLED == TRUE)
+    tSDP_DISC_ATTR  *p_attr;
+
+    p_attr = p_rec->p_first_attr;
+    while (p_attr)
+    {
+        if (p_attr->attr_id == attr_id)
+            return(p_attr);
+
+        p_attr = p_attr->p_next_attr;
+    }
+#endif
+    /* If here, no matching attribute found */
+    return(NULL);
+}
+
+/*******************************************************************************
+**
+** Function         SDP_FindServiceUUIDInRec
+**
+** Description      This function is called to read the service UUID within a record
+**                  if there is any.
+**
+** Parameters:      p_rec      - pointer to a SDP record.
+**                  p_uuid     - output parameter to save the UUID found.
+**
+** Returns          true if found, otherwise false.
+**
+*******************************************************************************/
+bool    SDP_FindServiceUUIDInRec(tSDP_DISC_REC *p_rec, tBT_UUID * p_uuid)
+{
+#if (SDP_CLIENT_ENABLED == TRUE)
+    tSDP_DISC_ATTR  *p_attr, *p_sattr, *p_extra_sattr;
+
+    p_attr = p_rec->p_first_attr;
+
+    while (p_attr)
+    {
+        if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
+            && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
+        {
+            for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
+            {
+                if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
+                {
+                    if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_16)
+                    {
+                        p_uuid->len = LEN_UUID_16;
+                        p_uuid->uu.uuid16 = p_sattr->attr_value.v.u16;
+                    }
+                    else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_128)
+                    {
+                        p_uuid->len = LEN_UUID_128;
+                        for (uint8_t i = 0; i != LEN_UUID_128; ++i)
+                            p_uuid->uu.uuid128[i] = p_sattr->attr_value.v.array[LEN_UUID_128-i-1];
+                    }
+                    else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_32)
+                    {
+                        p_uuid->len = LEN_UUID_32;
+                        p_uuid->uu.uuid32 = p_sattr->attr_value.v.u32;
+                    }
+
+                    return(true);
+                }
+
+                /* Checking for Toyota G Block Car Kit:
+                **  This car kit puts an extra data element sequence
+                **  where the UUID is suppose to be!!!
+                */
+                else
+                {
+                    if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)
+                    {
+                        /* Look through data element sequence until no more UUIDs */
+                        for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr; p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr)
+                        {
+                            /* Increment past this to see if the next attribut is UUID */
+                            if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) == UUID_DESC_TYPE)
+                                /* only support 16 bits UUID for now */
+                                && (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2))
+                            {
+                                p_uuid->len = 2;
+                                p_uuid->uu.uuid16 = p_extra_sattr->attr_value.v.u16;
+                                return(true);
+                            }
+                        }
+                    }
+                }
+            }
+            break;
+        }
+        else if (p_attr->attr_id == ATTR_ID_SERVICE_ID)
+        {
+            if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
+                /* only support 16 bits UUID for now */
+                && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2))
+            {
+                p_uuid->len = 2;
+                p_uuid->uu.uuid16 = p_attr->attr_value.v.u16;
+                return(true);
+            }
+        }
+        p_attr = p_attr->p_next_attr;
+    }
+    return false;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         SDP_FindServiceUUIDInRec_128bit
+**
+** Description      This function is called to read the 128-bit service UUID within a record
+**                  if there is any.
+**
+** Parameters:      p_rec      - pointer to a SDP record.
+**                  p_uuid     - output parameter to save the UUID found.
+**
+** Returns          true if found, otherwise false.
+**
+*******************************************************************************/
+bool    SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC *p_rec, tBT_UUID * p_uuid)
+{
+#if (SDP_CLIENT_ENABLED == TRUE)
+    tSDP_DISC_ATTR  *p_attr = p_rec->p_first_attr;
+    while (p_attr)
+    {
+        if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
+            && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
+        {
+            tSDP_DISC_ATTR *p_sattr = p_attr->attr_value.v.p_sub_attr;
+            while (p_sattr)
+            {
+                if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
+                {
+                    /* only support 128 bits UUID for now */
+                    if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16)
+                    {
+                        p_uuid->len = LEN_UUID_128;
+                        for (uint8_t i = 0; i != LEN_UUID_128; ++i)
+                            p_uuid->uu.uuid128[i] = p_sattr->attr_value.v.array[LEN_UUID_128-i-1];
+                    }
+                    return(true);
+                }
+
+                p_sattr = p_sattr->p_next_attr;
+            }
+            break;
+        }
+        else if (p_attr->attr_id == ATTR_ID_SERVICE_ID)
+        {
+            if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
+                /* only support 128 bits UUID for now */
+                && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16))
+            {
+                p_uuid->len = LEN_UUID_128;
+                for (uint8_t i = 0; i != LEN_UUID_128; ++i)
+                    p_uuid->uu.uuid128[i] = p_attr->attr_value.v.array[LEN_UUID_128-i-1];
+                return(true);
+            }
+        }
+        p_attr = p_attr->p_next_attr;
+    }
+    return false;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         SDP_FindServiceInDb
+**
+** Description      This function queries an SDP database for a specific service.
+**                  If the p_start_rec pointer is NULL, it looks from the beginning
+**                  of the database, else it continues from the next record after
+**                  p_start_rec.
+**
+** Returns          Pointer to record containing service class, or NULL
+**
+*******************************************************************************/
+tSDP_DISC_REC *SDP_FindServiceInDb (tSDP_DISCOVERY_DB *p_db, uint16_t service_uuid, tSDP_DISC_REC *p_start_rec)
+{
+#if (SDP_CLIENT_ENABLED == TRUE)
+    tSDP_DISC_REC   *p_rec;
+    tSDP_DISC_ATTR  *p_attr, *p_sattr, *p_extra_sattr;
+
+    /* Must have a valid database */
+    if (p_db == NULL)
+        return(NULL);
+
+    if (!p_start_rec)
+        p_rec = p_db->p_first_rec;
+    else
+        p_rec = p_start_rec->p_next_rec;
+
+    while (p_rec)
+    {
+        p_attr = p_rec->p_first_attr;
+        while (p_attr)
+        {
+            if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
+                && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
+            {
+                for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
+                {
+
+                    if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
+                     && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) ) {
+                        SDP_TRACE_DEBUG("SDP_FindServiceInDb - p_sattr value = 0x%x serviceuuid = 0x%x",
+                                        p_sattr->attr_value.v.u16, service_uuid);
+                        if(service_uuid == UUID_SERVCLASS_HDP_PROFILE)
+                        {
+                            if( (p_sattr->attr_value.v.u16==UUID_SERVCLASS_HDP_SOURCE) || ( p_sattr->attr_value.v.u16==UUID_SERVCLASS_HDP_SINK))
+                            {
+                                SDP_TRACE_DEBUG("SDP_FindServiceInDb found HDP source or sink\n" );
+                                return (p_rec);
+                            }
+                        }
+
+                    }
+
+                    if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE && (service_uuid == 0
+                        || (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2
+                            && p_sattr->attr_value.v.u16 == service_uuid)))
+                        /* for a specific uuid, or any one */
+                    {
+                        return(p_rec);
+                    }
+
+                    /* Checking for Toyota G Block Car Kit:
+                    **  This car kit puts an extra data element sequence
+                    **  where the UUID is suppose to be!!!
+                    */
+                    else
+                    {
+                        if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)
+                        {
+                            /* Look through data element sequence until no more UUIDs */
+                            for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr; p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr)
+                            {
+                                /* Increment past this to see if the next attribut is UUID */
+                                if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) == UUID_DESC_TYPE)
+                                    && (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2)
+                                    /* for a specific uuid, or any one */
+                                    && ((p_extra_sattr->attr_value.v.u16 == service_uuid) || (service_uuid == 0)))
+                                {
+                                    return(p_rec);
+                                }
+                            }
+                        }
+                    }
+                }
+                break;
+            }
+            else if (p_attr->attr_id == ATTR_ID_SERVICE_ID)
+            {
+                if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
+                    && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2)
+                    /* find a specific UUID or anyone */
+                    && ((p_attr->attr_value.v.u16 == service_uuid) || service_uuid == 0))
+                    return(p_rec);
+            }
+
+            p_attr = p_attr->p_next_attr;
+        }
+
+        p_rec = p_rec->p_next_rec;
+    }
+#endif
+    /* If here, no matching UUID found */
+    return(NULL);
+}
+
+/*******************************************************************************
+**
+** Function         SDP_FindServiceInDb_128bit
+**
+** Description      This function queries an SDP database for a specific service.
+**                  If the p_start_rec pointer is NULL, it looks from the beginning
+**                  of the database, else it continues from the next record after
+**                  p_start_rec.
+**
+**                  This function is kept separate from SDP_FindServiceInDb since
+**                  that API is expected to return only 16-bit UUIDs
+**
+** Returns          Pointer to record containing service class, or NULL
+**
+*******************************************************************************/
+tSDP_DISC_REC *SDP_FindServiceInDb_128bit(tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_start_rec)
+{
+#if (SDP_CLIENT_ENABLED == TRUE)
+    tSDP_DISC_REC   *p_rec;
+    tSDP_DISC_ATTR  *p_attr, *p_sattr;
+
+    /* Must have a valid database */
+    if (p_db == NULL)
+        return(NULL);
+
+    if (!p_start_rec)
+        p_rec = p_db->p_first_rec;
+    else
+        p_rec = p_start_rec->p_next_rec;
+
+    while (p_rec)
+    {
+        p_attr = p_rec->p_first_attr;
+        while (p_attr)
+        {
+            if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
+                && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
+            {
+                for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
+                {
+                    if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
+                        && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16))
+                    {
+                        return(p_rec);
+                    }
+                }
+                break;
+            }
+            else if (p_attr->attr_id == ATTR_ID_SERVICE_ID)
+            {
+                if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
+                    && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16))
+                    return(p_rec);
+            }
+
+            p_attr = p_attr->p_next_attr;
+        }
+
+        p_rec = p_rec->p_next_rec;
+    }
+#endif
+    /* If here, no matching UUID found */
+    return(NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         SDP_FindServiceUUIDInDb
+**
+** Description      This function queries an SDP database for a specific service.
+**                  If the p_start_rec pointer is NULL, it looks from the beginning
+**                  of the database, else it continues from the next record after
+**                  p_start_rec.
+**
+** NOTE             the only difference between this function and the previous function
+**                  "SDP_FindServiceInDb()" is that this function takes a tBT_UUID input
+**
+** Returns          Pointer to record containing service class, or NULL
+**
+*******************************************************************************/
+tSDP_DISC_REC *SDP_FindServiceUUIDInDb (tSDP_DISCOVERY_DB *p_db, tBT_UUID *p_uuid, tSDP_DISC_REC *p_start_rec)
+{
+#if (SDP_CLIENT_ENABLED == TRUE)
+    tSDP_DISC_REC   *p_rec;
+    tSDP_DISC_ATTR  *p_attr, *p_sattr;
+
+    /* Must have a valid database */
+    if (p_db == NULL)
+        return(NULL);
+
+    if (!p_start_rec)
+        p_rec = p_db->p_first_rec;
+    else
+        p_rec = p_start_rec->p_next_rec;
+
+    while (p_rec)
+    {
+        p_attr = p_rec->p_first_attr;
+        while (p_attr)
+        {
+            if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
+                && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
+            {
+                for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
+                {
+                    if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
+                    {
+                        if (sdpu_compare_uuid_with_attr (p_uuid, p_sattr))
+                            return(p_rec);
+                    }
+                }
+                break;
+            }
+            else if (p_attr->attr_id == ATTR_ID_SERVICE_ID)
+            {
+                if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE )
+                {
+                    if (sdpu_compare_uuid_with_attr (p_uuid, p_attr))
+                        return(p_rec);
+                }
+            }
+
+            p_attr = p_attr->p_next_attr;
+        }
+
+        p_rec = p_rec->p_next_rec;
+    }
+#endif  /* CLIENT_ENABLED == TRUE */
+    /* If here, no matching UUID found */
+    return(NULL);
+}
+
+#if (SDP_CLIENT_ENABLED == TRUE)
+/*******************************************************************************
+**
+** Function         sdp_fill_proto_elem
+**
+** Description      This function retrieves the protocol element.
+**
+** Returns          true if found, false if not
+**                  If found, the passed protocol list element is filled in.
+**
+*******************************************************************************/
+static bool    sdp_fill_proto_elem( tSDP_DISC_ATTR  *p_attr, uint16_t layer_uuid,
+                                    tSDP_PROTOCOL_ELEM *p_elem)
+{
+    tSDP_DISC_ATTR  *p_sattr;
+
+    /* Walk through the protocol descriptor list */
+    for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr; p_attr = p_attr->p_next_attr)
+    {
+        /* Safety check - each entry should itself be a sequence */
+        if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE)
+            return(false);
+
+        /* Now, see if the entry contains the layer we are interested in */
+        for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
+        {
+            /* SDP_TRACE_DEBUG ("SDP - p_sattr 0x%x, layer_uuid:0x%x, u16:0x%x####",
+                p_sattr, layer_uuid, p_sattr->attr_value.v.u16); */
+
+            if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
+                && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)
+                && (p_sattr->attr_value.v.u16 == layer_uuid))
+            {
+                /* Bingo. Now fill in the passed element */
+                p_elem->protocol_uuid = layer_uuid;
+                p_elem->num_params = 0;
+
+                /* Store the parameters, if any */
+                for (p_sattr = p_sattr->p_next_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
+                {
+                    if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) != UINT_DESC_TYPE)
+                        break;
+
+                    if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)
+                        p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u16;
+                    else
+                        p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u8;
+
+                    if (p_elem->num_params >= SDP_MAX_PROTOCOL_PARAMS)
+                        break;
+                }
+                return(true);
+            }
+        }
+    }
+
+    return(false);
+}
+#endif  /* CLIENT_ENABLED == TRUE */
+
+/*******************************************************************************
+**
+** Function         SDP_FindProtocolListElemInRec
+**
+** Description      This function looks at a specific discovery record for a protocol
+**                  list element.
+**
+** Returns          true if found, false if not
+**                  If found, the passed protocol list element is filled in.
+**
+*******************************************************************************/
+bool    SDP_FindProtocolListElemInRec (tSDP_DISC_REC *p_rec, uint16_t layer_uuid, tSDP_PROTOCOL_ELEM *p_elem)
+{
+#if (SDP_CLIENT_ENABLED == TRUE)
+    tSDP_DISC_ATTR  *p_attr;
+
+    p_attr = p_rec->p_first_attr;
+    while (p_attr)
+    {
+        /* Find the protocol descriptor list */
+        if ((p_attr->attr_id == ATTR_ID_PROTOCOL_DESC_LIST)
+            && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
+        {
+            return sdp_fill_proto_elem(p_attr, layer_uuid, p_elem);
+        }
+        p_attr = p_attr->p_next_attr;
+    }
+#endif
+    /* If here, no match found */
+    return(false);
+}
+
+
+/*******************************************************************************
+**
+** Function         SDP_FindAddProtoListsElemInRec
+**
+** Description      This function looks at a specific discovery record for a protocol
+**                  list element.
+**
+** Returns          true if found, false if not
+**                  If found, the passed protocol list element is filled in.
+**
+*******************************************************************************/
+bool    SDP_FindAddProtoListsElemInRec (tSDP_DISC_REC *p_rec, uint16_t layer_uuid, tSDP_PROTOCOL_ELEM *p_elem)
+{
+#if (SDP_CLIENT_ENABLED == TRUE)
+    tSDP_DISC_ATTR  *p_attr, *p_sattr;
+    bool            ret = false;
+
+    p_attr = p_rec->p_first_attr;
+    while (p_attr)
+    {
+        /* Find the additional protocol descriptor list attribute */
+        if ((p_attr->attr_id == ATTR_ID_ADDITION_PROTO_DESC_LISTS)
+            && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
+        {
+            for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
+            {
+                /* Safety check - each entry should itself be a sequence */
+                if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)
+                {
+                    if ( (ret = sdp_fill_proto_elem(p_sattr, layer_uuid, p_elem)) == true)
+                        break;
+                }
+            }
+            return ret;
+        }
+        p_attr = p_attr->p_next_attr;
+    }
+#endif
+    /* If here, no match found */
+    return(false);
+}
+
+
+/*******************************************************************************
+**
+** Function         SDP_FindProfileVersionInRec
+**
+** Description      This function looks at a specific discovery record for the
+**                  Profile list descriptor, and pulls out the version number.
+**                  The version number consists of an 8-bit major version and
+**                  an 8-bit minor version.
+**
+** Returns          true if found, false if not
+**                  If found, the major and minor version numbers that were passed
+**                  in are filled in.
+**
+*******************************************************************************/
+bool    SDP_FindProfileVersionInRec (tSDP_DISC_REC *p_rec, uint16_t profile_uuid, uint16_t *p_version)
+{
+#if (SDP_CLIENT_ENABLED == TRUE)
+    tSDP_DISC_ATTR  *p_attr, *p_sattr;
+
+    p_attr = p_rec->p_first_attr;
+    while (p_attr)
+    {
+        /* Find the profile descriptor list */
+        if ((p_attr->attr_id == ATTR_ID_BT_PROFILE_DESC_LIST)
+            && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE))
+        {
+            /* Walk through the protocol descriptor list */
+            for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr; p_attr = p_attr->p_next_attr)
+            {
+                /* Safety check - each entry should itself be a sequence */
+                if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE)
+                    return(false);
+
+                /* Now, see if the entry contains the profile UUID we are interested in */
+                for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr)
+                {
+                    if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
+                        && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)  /* <- This is bytes, not size code! */
+                        && (p_sattr->attr_value.v.u16 == profile_uuid))
+                    {
+                        /* Now fill in the major and minor numbers */
+                        /* if the attribute matches the description for version (type UINT, size 2 bytes) */
+                        p_sattr = p_sattr->p_next_attr;
+
+                        if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UINT_DESC_TYPE) &&
+                            (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2))
+                        {
+                            /* The high order 8 bits is the major number, low order is the minor number (big endian) */
+                            *p_version = p_sattr->attr_value.v.u16;
+
+                            return(true);
+                        }
+                        else
+                            return(false);  /* The type and/or size was not valid for the profile list version */
+                    }
+                }
+            }
+
+            return(false);
+        }
+        p_attr = p_attr->p_next_attr;
+    }
+#endif  /* CLIENT_ENABLED == TRUE */
+
+    /* If here, no match found */
+    return(false);
+}
+
+/*******************************************************************************
+**                   Device Identification (DI) Client Functions
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Function         SDP_DiDiscover
+**
+** Description      This function queries a remote device for DI information.
+**
+** Returns          SDP_SUCCESS if query started successfully, else error
+**
+*******************************************************************************/
+uint16_t SDP_DiDiscover( BD_ADDR remote_device, tSDP_DISCOVERY_DB *p_db,
+                       uint32_t len, tSDP_DISC_CMPL_CB *p_cb )
+{
+#if (SDP_CLIENT_ENABLED == TRUE)
+    uint16_t result   = SDP_DI_DISC_FAILED;
+    uint16_t num_uuids = 1;
+    uint16_t di_uuid   = UUID_SERVCLASS_PNP_INFORMATION;
+
+    /* build uuid for db init */
+    tSDP_UUID init_uuid;
+    init_uuid.len = 2;
+    init_uuid.uu.uuid16 = di_uuid;
+
+    if ( SDP_InitDiscoveryDb(p_db, len, num_uuids, &init_uuid, 0, NULL) )
+        if ( SDP_ServiceSearchRequest(remote_device, p_db, p_cb) )
+            result = SDP_SUCCESS;
+
+    return result;
+#else
+    return SDP_DI_DISC_FAILED;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         SDP_GetNumDiRecords
+**
+** Description      Searches specified database for DI records
+**
+** Returns          number of DI records found
+**
+*******************************************************************************/
+uint8_t SDP_GetNumDiRecords( tSDP_DISCOVERY_DB *p_db )
+{
+#if (SDP_CLIENT_ENABLED == TRUE)
+    uint8_t num_records = 0;
+    tSDP_DISC_REC *p_curr_record = NULL;
+
+    do
+    {
+        p_curr_record = SDP_FindServiceInDb( p_db, UUID_SERVCLASS_PNP_INFORMATION,
+                                             p_curr_record );
+        if ( p_curr_record )
+            num_records++;
+    }while ( p_curr_record );
+
+    return num_records;
+#else
+    return 0;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         SDP_AttrStringCopy
+**
+** Description      This function copy given attribute to specified buffer as a string
+**
+** Returns          none
+**
+*******************************************************************************/
+static void SDP_AttrStringCopy(char *dst, tSDP_DISC_ATTR *p_attr, uint16_t dst_size)
+{
+    if ( dst == NULL ) return;
+    if ( p_attr )
+    {
+        uint16_t len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+        if ( len > dst_size - 1 )
+        {
+            len = dst_size - 1;
+        }
+        memcpy(dst, (char *)p_attr->attr_value.v.array, len);
+        dst[len] = '\0';
+    }
+    else
+    {
+        dst[0] = '\0';
+    }
+}
+
+/*******************************************************************************
+**
+** Function         SDP_GetDiRecord
+**
+** Description      This function retrieves a remote device's DI record from
+**                  the specified database.
+**
+** Returns          SDP_SUCCESS if record retrieved, else error
+**
+*******************************************************************************/
+uint16_t SDP_GetDiRecord( uint8_t get_record_index, tSDP_DI_GET_RECORD *p_device_info,
+                        tSDP_DISCOVERY_DB *p_db )
+{
+#if (SDP_CLIENT_ENABLED == TRUE)
+    uint16_t result = SDP_NO_DI_RECORD_FOUND;
+    uint8_t curr_record_index = 1;
+
+    tSDP_DISC_REC *p_curr_record = NULL;
+
+    /* find the requested SDP record in the discovery database */
+    do
+    {
+        p_curr_record = SDP_FindServiceInDb( p_db, UUID_SERVCLASS_PNP_INFORMATION,
+                                             p_curr_record );
+        if ( p_curr_record )
+        {
+            if ( curr_record_index++ == get_record_index )
+            {
+                result = SDP_SUCCESS;
+                break;
+            }
+        }
+    }while ( p_curr_record );
+
+    if ( result == SDP_SUCCESS )
+    {
+        /* copy the information from the SDP record to the DI record */
+        tSDP_DISC_ATTR *p_curr_attr = NULL;
+
+        /* ClientExecutableURL is optional */
+        p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_CLIENT_EXE_URL );
+        SDP_AttrStringCopy( p_device_info->rec.client_executable_url, p_curr_attr,
+                            SDP_MAX_ATTR_LEN );
+
+        /* Service Description is optional */
+        p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_SERVICE_DESCRIPTION );
+        SDP_AttrStringCopy( p_device_info->rec.service_description, p_curr_attr, SDP_MAX_ATTR_LEN );
+
+        /* DocumentationURL is optional */
+        p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_DOCUMENTATION_URL );
+        SDP_AttrStringCopy( p_device_info->rec.documentation_url, p_curr_attr, SDP_MAX_ATTR_LEN );
+
+        p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_SPECIFICATION_ID );
+        if ( p_curr_attr )
+            p_device_info->spec_id = p_curr_attr->attr_value.v.u16;
+        else
+            result = SDP_ERR_ATTR_NOT_PRESENT;
+
+        p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_VENDOR_ID );
+        if ( p_curr_attr )
+            p_device_info->rec.vendor = p_curr_attr->attr_value.v.u16;
+        else
+            result = SDP_ERR_ATTR_NOT_PRESENT;
+
+        p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_VENDOR_ID_SOURCE );
+        if ( p_curr_attr )
+            p_device_info->rec.vendor_id_source = p_curr_attr->attr_value.v.u16;
+        else
+            result = SDP_ERR_ATTR_NOT_PRESENT;
+
+        p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_PRODUCT_ID );
+        if ( p_curr_attr )
+            p_device_info->rec.product = p_curr_attr->attr_value.v.u16;
+        else
+            result = SDP_ERR_ATTR_NOT_PRESENT;
+
+        p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_PRODUCT_VERSION );
+        if ( p_curr_attr )
+            p_device_info->rec.version = p_curr_attr->attr_value.v.u16;
+        else
+            result = SDP_ERR_ATTR_NOT_PRESENT;
+
+        p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_PRIMARY_RECORD );
+        if ( p_curr_attr )
+            p_device_info->rec.primary_record = (bool   )p_curr_attr->attr_value.v.u8;
+        else
+            result = SDP_ERR_ATTR_NOT_PRESENT;
+    }
+
+    return result;
+#else   /* SDP_CLIENT_ENABLED is FALSE */
+    return SDP_NO_DI_RECORD_FOUND;
+#endif
+}
+
+/*******************************************************************************
+**                   Device Identification (DI) Server Functions
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Function         SDP_SetLocalDiRecord
+**
+** Description      This function adds a DI record to the local SDP database.
+**
+**
+**
+** Returns          Returns SDP_SUCCESS if record added successfully, else error
+**
+*******************************************************************************/
+uint16_t SDP_SetLocalDiRecord( tSDP_DI_RECORD *p_device_info, uint32_t *p_handle )
+{
+#if (SDP_SERVER_ENABLED == TRUE)
+    uint16_t result = SDP_SUCCESS;
+    uint32_t handle;
+    uint16_t di_uuid = UUID_SERVCLASS_PNP_INFORMATION;
+    uint16_t di_specid = BLUETOOTH_DI_SPECIFICATION;
+    uint8_t temp_u16[2];
+    uint8_t *p_temp;
+    uint8_t u8;
+
+    *p_handle = 0;
+    if ( p_device_info == NULL )
+        return SDP_ILLEGAL_PARAMETER;
+
+    /* if record is to be primary record, get handle to replace old primary */
+    if ( p_device_info->primary_record == true && sdp_cb.server_db.di_primary_handle )
+        handle = sdp_cb.server_db.di_primary_handle;
+    else
+    {
+        if ( (handle = SDP_CreateRecord()) == 0 )
+            return SDP_NO_RESOURCES;
+    }
+
+    *p_handle = handle;
+
+    /* build the SDP entry */
+    /* Add the UUID to the Service Class ID List */
+    if ((SDP_AddServiceClassIdList(handle, 1, &di_uuid)) == false)
+        result = SDP_DI_REG_FAILED;
+
+    /* mandatory */
+    if ( result == SDP_SUCCESS)
+    {
+        p_temp = temp_u16;
+        UINT16_TO_BE_STREAM(p_temp, di_specid);
+        if ( !(SDP_AddAttribute(handle, ATTR_ID_SPECIFICATION_ID,
+                                UINT_DESC_TYPE, sizeof(di_specid),
+                                temp_u16)) )
+            result = SDP_DI_REG_FAILED;
+    }
+
+    /* optional - if string is null, do not add attribute */
+    if ( result == SDP_SUCCESS )
+    {
+        if ( p_device_info->client_executable_url[0] != '\0' )
+        {
+            if ( !((strlen(p_device_info->client_executable_url)+1 <= SDP_MAX_ATTR_LEN) &&
+                   SDP_AddAttribute(handle, ATTR_ID_CLIENT_EXE_URL, URL_DESC_TYPE,
+                                    (uint32_t)(strlen(p_device_info->client_executable_url)+1),
+                                    (uint8_t *)p_device_info->client_executable_url)) )
+                result = SDP_DI_REG_FAILED;
+        }
+    }
+
+    /* optional - if string is null, do not add attribute */
+    if ( result == SDP_SUCCESS )
+    {
+        if ( p_device_info->service_description[0] != '\0' )
+        {
+            if ( !((strlen(p_device_info->service_description)+1 <= SDP_MAX_ATTR_LEN) &&
+                   SDP_AddAttribute(handle, ATTR_ID_SERVICE_DESCRIPTION,
+                                    TEXT_STR_DESC_TYPE,
+                                    (uint32_t)(strlen(p_device_info->service_description)+1),
+                                    (uint8_t *)p_device_info->service_description)) )
+                result = SDP_DI_REG_FAILED;
+        }
+    }
+
+    /* optional - if string is null, do not add attribute */
+    if ( result == SDP_SUCCESS )
+    {
+        if ( p_device_info->documentation_url[0] != '\0' )
+        {
+            if ( !((strlen(p_device_info->documentation_url)+1 <= SDP_MAX_ATTR_LEN) &&
+                   SDP_AddAttribute(handle, ATTR_ID_DOCUMENTATION_URL, URL_DESC_TYPE,
+                                    (uint32_t)(strlen(p_device_info->documentation_url)+1),
+                                    (uint8_t *)p_device_info->documentation_url)) )
+                result = SDP_DI_REG_FAILED;
+        }
+    }
+
+    /* mandatory */
+    if ( result == SDP_SUCCESS)
+    {
+        p_temp = temp_u16;
+        UINT16_TO_BE_STREAM(p_temp, p_device_info->vendor);
+        if ( !(SDP_AddAttribute(handle, ATTR_ID_VENDOR_ID, UINT_DESC_TYPE,
+                                sizeof(p_device_info->vendor), temp_u16)) )
+            result = SDP_DI_REG_FAILED;
+    }
+
+    /* mandatory */
+    if ( result == SDP_SUCCESS)
+    {
+        p_temp = temp_u16;
+        UINT16_TO_BE_STREAM (p_temp, p_device_info->product);
+        if ( !(SDP_AddAttribute(handle, ATTR_ID_PRODUCT_ID,
+                                UINT_DESC_TYPE, sizeof(p_device_info->product), temp_u16)) )
+            result = SDP_DI_REG_FAILED;
+    }
+
+    /* mandatory */
+    if ( result == SDP_SUCCESS)
+    {
+        p_temp = temp_u16;
+        UINT16_TO_BE_STREAM (p_temp, p_device_info->version);
+        if ( !(SDP_AddAttribute(handle, ATTR_ID_PRODUCT_VERSION, UINT_DESC_TYPE,
+                                sizeof(p_device_info->version), temp_u16)) )
+            result = SDP_DI_REG_FAILED;
+    }
+
+    /* mandatory */
+    if ( result == SDP_SUCCESS)
+    {
+        u8 = (uint8_t)p_device_info->primary_record;
+        if ( !(SDP_AddAttribute(handle, ATTR_ID_PRIMARY_RECORD,
+                                BOOLEAN_DESC_TYPE, 1, &u8)) )
+            result = SDP_DI_REG_FAILED;
+    }
+
+    /* mandatory */
+    if ( result == SDP_SUCCESS)
+    {
+        p_temp = temp_u16;
+        UINT16_TO_BE_STREAM(p_temp, p_device_info->vendor_id_source);
+        if ( !(SDP_AddAttribute(handle, ATTR_ID_VENDOR_ID_SOURCE, UINT_DESC_TYPE,
+                                sizeof(p_device_info->vendor_id_source), temp_u16)) )
+            result = SDP_DI_REG_FAILED;
+    }
+
+    if ( result != SDP_SUCCESS )
+        SDP_DeleteRecord( handle );
+    else if (p_device_info->primary_record == true)
+        sdp_cb.server_db.di_primary_handle = handle;
+
+    return result;
+#else   /* SDP_SERVER_ENABLED is FALSE */
+    return SDP_DI_REG_FAILED;
+#endif  /* if SDP_SERVER_ENABLED */
+}
+
+/*******************************************************************************
+**
+** Function         SDP_SetTraceLevel
+**
+** Description      This function sets the trace level for SDP. If called with
+**                  a value of 0xFF, it simply reads the current trace level.
+**
+** Returns          the new (current) trace level
+**
+*******************************************************************************/
+uint8_t SDP_SetTraceLevel (uint8_t new_level)
+{
+    if (new_level != 0xFF)
+        sdp_cb.trace_level = new_level;
+
+    return(sdp_cb.trace_level);
+}
diff --git a/bt/stack/sdp/sdp_db.cc b/bt/stack/sdp/sdp_db.cc
new file mode 100644
index 0000000..77e4fe4
--- /dev/null
+++ b/bt/stack/sdp/sdp_db.cc
@@ -0,0 +1,980 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 functions that handle the database
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "bt_target.h"
+
+#include "bt_common.h"
+
+#include "l2cdefs.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+
+#include "sdp_api.h"
+#include "sdpint.h"
+
+#if (SDP_SERVER_ENABLED == TRUE)
+/********************************************************************************/
+/*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
+/********************************************************************************/
+static bool    find_uuid_in_seq (uint8_t *p , uint32_t seq_len, uint8_t *p_his_uuid,
+                                 uint16_t his_len, int nest_level);
+
+
+/*******************************************************************************
+**
+** Function         sdp_db_service_search
+**
+** Description      This function searches for a record that contains the
+**                  specified UIDs. It is passed either NULL to start at the
+**                  beginning, or the previous record found.
+**
+** Returns          Pointer to the record, or NULL if not found.
+**
+*******************************************************************************/
+tSDP_RECORD *sdp_db_service_search (tSDP_RECORD *p_rec, tSDP_UUID_SEQ *p_seq)
+{
+    uint16_t        xx, yy;
+    tSDP_ATTRIBUTE *p_attr;
+    tSDP_RECORD     *p_end = &sdp_cb.server_db.record[sdp_cb.server_db.num_records];
+
+    /* If NULL, start at the beginning, else start at the first specified record */
+    if (!p_rec)
+        p_rec = &sdp_cb.server_db.record[0];
+    else
+        p_rec++;
+
+    /* Look through the records. The spec says that a match occurs if */
+    /* the record contains all the passed UUIDs in it.                */
+    for ( ; p_rec < p_end; p_rec++)
+    {
+        for (yy = 0; yy < p_seq->num_uids; yy++)
+        {
+            p_attr = &p_rec->attribute[0];
+            for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++)
+            {
+                if (p_attr->type == UUID_DESC_TYPE)
+                {
+                    if (sdpu_compare_uuid_arrays (p_attr->value_ptr, p_attr->len,
+                                                  &p_seq->uuid_entry[yy].value[0],
+                                                  p_seq->uuid_entry[yy].len))
+                        break;
+                }
+                else if (p_attr->type == DATA_ELE_SEQ_DESC_TYPE)
+                {
+                    if (find_uuid_in_seq (p_attr->value_ptr, p_attr->len,
+                                          &p_seq->uuid_entry[yy].value[0],
+                                          p_seq->uuid_entry[yy].len, 0))
+                        break;
+                }
+            }
+            /* If any UUID was not found,  on to the next record */
+            if (xx == p_rec->num_attributes)
+                break;
+        }
+
+        /* If every UUID was found in the record, return the record */
+        if (yy == p_seq->num_uids)
+            return (p_rec);
+    }
+
+    /* If here, no more records found */
+    return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function         find_uuid_in_seq
+**
+** Description      This function searches a data element sequenct for a UUID.
+**
+** Returns          true if found, else false
+**
+*******************************************************************************/
+static bool    find_uuid_in_seq (uint8_t *p , uint32_t seq_len, uint8_t *p_uuid,
+                                 uint16_t uuid_len, int nest_level)
+{
+    uint8_t *p_end = p + seq_len;
+    uint8_t type;
+    uint32_t len;
+
+    /* A little safety check to avoid excessive recursion */
+    if (nest_level > 3)
+        return (false);
+
+    while (p < p_end)
+    {
+        type = *p++;
+        p = sdpu_get_len_from_type (p, type, &len);
+        type = type >> 3;
+        if (type == UUID_DESC_TYPE)
+        {
+            if (sdpu_compare_uuid_arrays (p, len, p_uuid, uuid_len))
+                return (true);
+        }
+        else if (type == DATA_ELE_SEQ_DESC_TYPE)
+        {
+            if (find_uuid_in_seq (p, len, p_uuid, uuid_len, nest_level + 1))
+                return (true);
+        }
+        p = p + len;
+    }
+
+    /* If here, failed to match */
+    return (false);
+}
+
+/*******************************************************************************
+**
+** Function         sdp_db_find_record
+**
+** Description      This function searches for a record with a specific handle
+**                  It is passed the handle of the record.
+**
+** Returns          Pointer to the record, or NULL if not found.
+**
+*******************************************************************************/
+tSDP_RECORD *sdp_db_find_record (uint32_t handle)
+{
+    tSDP_RECORD     *p_rec;
+    tSDP_RECORD     *p_end = &sdp_cb.server_db.record[sdp_cb.server_db.num_records];
+
+    /* Look through the records for the caller's handle */
+    for (p_rec = &sdp_cb.server_db.record[0]; p_rec < p_end; p_rec++)
+    {
+        if (p_rec->record_handle == handle)
+            return (p_rec);
+    }
+
+    /* Record with that handle not found. */
+    return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function         sdp_db_find_attr_in_rec
+**
+** Description      This function searches a record for specific attributes.
+**                  It is passed a pointer to the record. If the record contains
+**                  the specified attribute, (the caller may specify be a range
+**                  of attributes), the attribute is returned.
+**
+** Returns          Pointer to the attribute, or NULL if not found.
+**
+*******************************************************************************/
+tSDP_ATTRIBUTE *sdp_db_find_attr_in_rec (tSDP_RECORD *p_rec, uint16_t start_attr,
+                                         uint16_t end_attr)
+{
+    tSDP_ATTRIBUTE  *p_at;
+    uint16_t        xx;
+
+    /* Note that the attributes in a record are assumed to be in sorted order */
+    for (xx = 0, p_at = &p_rec->attribute[0]; xx < p_rec->num_attributes;
+         xx++, p_at++)
+    {
+        if ((p_at->id >= start_attr) && (p_at->id <= end_attr))
+            return (p_at);
+    }
+
+    /* No matching attribute found */
+    return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         sdp_compose_proto_list
+**
+** Description      This function is called to compose a data sequence from
+**                  protocol element list struct pointer
+**
+** Returns          the length of the data sequence
+**
+*******************************************************************************/
+static int sdp_compose_proto_list( uint8_t *p, uint16_t num_elem,
+                                  tSDP_PROTOCOL_ELEM *p_elem_list)
+{
+    uint16_t        xx, yy, len;
+    bool               is_rfcomm_scn;
+    uint8_t         *p_head = p;
+    uint8_t          *p_len;
+
+    /* First, build the protocol list. This consists of a set of data element
+    ** sequences, one for each layer. Each layer sequence consists of layer's
+    ** UUID and optional parameters
+    */
+    for (xx = 0; xx < num_elem; xx++, p_elem_list++)
+    {
+        len = 3 + (p_elem_list->num_params * 3);
+        UINT8_TO_BE_STREAM  (p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+
+        p_len = p;
+        *p++ = (uint8_t) len;
+
+        UINT8_TO_BE_STREAM  (p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+        UINT16_TO_BE_STREAM (p, p_elem_list->protocol_uuid);
+
+        if (p_elem_list->protocol_uuid == UUID_PROTOCOL_RFCOMM)
+            is_rfcomm_scn = true;
+        else
+            is_rfcomm_scn = false;
+
+        for (yy = 0; yy < p_elem_list->num_params; yy++)
+        {
+            if (is_rfcomm_scn)
+            {
+                UINT8_TO_BE_STREAM  (p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
+                UINT8_TO_BE_STREAM (p, p_elem_list->params[yy]);
+
+                *p_len -= 1;
+            }
+            else
+            {
+                UINT8_TO_BE_STREAM  (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+                UINT16_TO_BE_STREAM (p, p_elem_list->params[yy]);
+            }
+        }
+    }
+    return (p - p_head);
+}
+
+#endif  /* SDP_SERVER_ENABLED == TRUE */
+
+/*******************************************************************************
+**
+** Function         SDP_CreateRecord
+**
+** Description      This function is called to create a record in the database.
+**                  This would be through the SDP database maintenance API. The
+**                  record is created empty, teh application should then call
+**                  "add_attribute" to add the record's attributes.
+**
+** Returns          Record handle if OK, else 0.
+**
+*******************************************************************************/
+uint32_t SDP_CreateRecord (void)
+{
+#if (SDP_SERVER_ENABLED == TRUE)
+    uint32_t  handle;
+    uint8_t   buf[4];
+    tSDP_DB  *p_db = &sdp_cb.server_db;
+
+    /* First, check if there is a free record */
+    if (p_db->num_records < SDP_MAX_RECORDS)
+    {
+        memset (&p_db->record[p_db->num_records], 0,
+                sizeof (tSDP_RECORD));
+
+        /* We will use a handle of the first unreserved handle plus last record
+        ** number + 1 */
+        if (p_db->num_records)
+            handle = p_db->record[p_db->num_records - 1].record_handle + 1;
+        else
+            handle = 0x10000;
+
+        p_db->record[p_db->num_records].record_handle = handle;
+
+        p_db->num_records++;
+        SDP_TRACE_DEBUG("SDP_CreateRecord ok, num_records:%d", p_db->num_records);
+        /* Add the first attribute (the handle) automatically */
+        UINT32_TO_BE_FIELD (buf, handle);
+        SDP_AddAttribute (handle, ATTR_ID_SERVICE_RECORD_HDL, UINT_DESC_TYPE,
+                          4, buf);
+
+        return (p_db->record[p_db->num_records - 1].record_handle);
+    }
+    else SDP_TRACE_ERROR("SDP_CreateRecord fail, exceed maximum records:%d", SDP_MAX_RECORDS);
+#endif
+        return (0);
+}
+
+
+/*******************************************************************************
+**
+** Function         SDP_DeleteRecord
+**
+** Description      This function is called to add a record (or all records)
+**                  from the database. This would be through the SDP database
+**                  maintenance API.
+**
+**                  If a record handle of 0 is passed, all records are deleted.
+**
+** Returns          true if succeeded, else false
+**
+*******************************************************************************/
+bool    SDP_DeleteRecord (uint32_t handle)
+{
+#if (SDP_SERVER_ENABLED == TRUE)
+    uint16_t        xx, yy, zz;
+    tSDP_RECORD     *p_rec = &sdp_cb.server_db.record[0];
+
+    if (handle == 0 || sdp_cb.server_db.num_records == 0)
+    {
+        /* Delete all records in the database */
+        sdp_cb.server_db.num_records = 0;
+
+        /* require new DI record to be created in SDP_SetLocalDiRecord */
+        sdp_cb.server_db.di_primary_handle = 0;
+
+        return (true);
+    }
+    else
+    {
+        /* Find the record in the database */
+        for (xx = 0; xx < sdp_cb.server_db.num_records; xx++, p_rec++)
+        {
+            if (p_rec->record_handle == handle)
+            {
+                /* Found it. Shift everything up one */
+                for (yy = xx; yy < sdp_cb.server_db.num_records; yy++, p_rec++)
+                {
+                    *p_rec = *(p_rec + 1);
+
+                    /* Adjust the attribute value pointer for each attribute */
+                    for (zz = 0; zz < p_rec->num_attributes; zz++)
+                        p_rec->attribute[zz].value_ptr -= sizeof(tSDP_RECORD);
+                }
+
+                sdp_cb.server_db.num_records--;
+
+                SDP_TRACE_DEBUG("SDP_DeleteRecord ok, num_records:%d", sdp_cb.server_db.num_records);
+                /* if we're deleting the primary DI record, clear the */
+                /* value in the control block */
+                if( sdp_cb.server_db.di_primary_handle == handle )
+                {
+                    sdp_cb.server_db.di_primary_handle = 0;
+                }
+
+                return (true);
+            }
+        }
+    }
+#endif
+    return (false);
+}
+
+
+/*******************************************************************************
+**
+** Function         SDP_AddAttribute
+**
+** Description      This function is called to add an attribute to a record.
+**                  This would be through the SDP database maintenance API.
+**                  If the attribute already exists in the record, it is replaced
+**                  with the new value.
+**
+** NOTE             Attribute values must be passed as a Big Endian stream.
+**
+** Returns          true if added OK, else false
+**
+*******************************************************************************/
+bool    SDP_AddAttribute (uint32_t handle, uint16_t attr_id, uint8_t attr_type,
+                          uint32_t attr_len, uint8_t *p_val)
+{
+#if (SDP_SERVER_ENABLED == TRUE)
+    uint16_t        xx, yy, zz;
+    tSDP_RECORD     *p_rec = &sdp_cb.server_db.record[0];
+
+#if (BT_TRACE_VERBOSE == TRUE)
+    if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG)
+    {
+        if ((attr_type == UINT_DESC_TYPE) ||
+            (attr_type == TWO_COMP_INT_DESC_TYPE) ||
+            (attr_type == UUID_DESC_TYPE) ||
+            (attr_type == DATA_ELE_SEQ_DESC_TYPE) ||
+            (attr_type == DATA_ELE_ALT_DESC_TYPE))
+        {
+            uint8_t num_array[400];
+            uint32_t len = (attr_len > 200) ? 200 : attr_len;
+
+            num_array[0] ='\0';
+            for (uint32_t i = 0; i < len; i++)
+            {
+                snprintf((char *)&num_array[i*2], sizeof(num_array) - i*2,
+                    "%02X",(uint8_t)(p_val[i]));
+            }
+            SDP_TRACE_DEBUG("SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, *p_val:%s",
+                            handle,attr_id,attr_type,attr_len,p_val,num_array);
+        }
+        else if (attr_type == bool   _DESC_TYPE)
+        {
+            SDP_TRACE_DEBUG("SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, *p_val:%d",
+                             handle,attr_id,attr_type,attr_len,p_val,*p_val);
+        }
+        else
+        {
+            SDP_TRACE_DEBUG("SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, *p_val:%s",
+                handle,attr_id,attr_type,attr_len,p_val,p_val);
+        }
+    }
+#endif
+
+    /* Find the record in the database */
+    for (zz = 0; zz < sdp_cb.server_db.num_records; zz++, p_rec++)
+    {
+        if (p_rec->record_handle == handle)
+        {
+            tSDP_ATTRIBUTE  *p_attr = &p_rec->attribute[0];
+
+            /* Found the record. Now, see if the attribute already exists */
+            for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++)
+            {
+                /* The attribute exists. replace it */
+                if (p_attr->id == attr_id)
+                {
+                    SDP_DeleteAttribute (handle, attr_id);
+                    break;
+                }
+                if (p_attr->id > attr_id)
+                    break;
+            }
+
+            if (p_rec->num_attributes == SDP_MAX_REC_ATTR)
+                return (false);
+
+            /* If not found, see if we can allocate a new entry */
+            if (xx == p_rec->num_attributes)
+                p_attr = &p_rec->attribute[p_rec->num_attributes];
+            else
+            {
+                /* Since the attributes are kept in sorted order, insert ours here */
+                for (yy = p_rec->num_attributes; yy > xx; yy--)
+                    p_rec->attribute[yy] = p_rec->attribute[yy - 1];
+            }
+
+            p_attr->id   = attr_id;
+            p_attr->type = attr_type;
+            p_attr->len  = attr_len;
+
+            if (p_rec->free_pad_ptr + attr_len >= SDP_MAX_PAD_LEN)
+            {
+                /* do truncate only for text string type descriptor */
+                if (attr_type == TEXT_STR_DESC_TYPE)
+                {
+                    SDP_TRACE_WARNING("SDP_AddAttribute: attr_len:%d too long. truncate to (%d)",
+                        attr_len, SDP_MAX_PAD_LEN - p_rec->free_pad_ptr );
+
+                    attr_len = SDP_MAX_PAD_LEN - p_rec->free_pad_ptr;
+                    p_val[SDP_MAX_PAD_LEN - p_rec->free_pad_ptr] = '\0';
+                    p_val[SDP_MAX_PAD_LEN - p_rec->free_pad_ptr+1] = '\0';
+                }
+                else
+                    attr_len = 0;
+            }
+
+            if ((attr_len > 0) && (p_val != 0))
+            {
+                p_attr->len  = attr_len;
+                memcpy (&p_rec->attr_pad[p_rec->free_pad_ptr], p_val, (size_t)attr_len);
+                p_attr->value_ptr = &p_rec->attr_pad[p_rec->free_pad_ptr];
+                p_rec->free_pad_ptr += attr_len;
+            }
+            else if ((attr_len == 0 && p_attr->len != 0) || /* if truncate to 0 length, simply don't add */
+                      p_val == 0)
+            {
+                SDP_TRACE_ERROR("SDP_AddAttribute fail, length exceed maximum: ID %d: attr_len:%d ",
+                    attr_id, attr_len );
+                p_attr->id   = p_attr->type = p_attr->len  = 0;
+                return (false);
+            }
+            p_rec->num_attributes++;
+            return (true);
+        }
+    }
+#endif
+    return (false);
+}
+
+
+/*******************************************************************************
+**
+** Function         SDP_AddSequence
+**
+** Description      This function is called to add a sequence to a record.
+**                  This would be through the SDP database maintenance API.
+**                  If the sequence already exists in the record, it is replaced
+**                  with the new sequence.
+**
+** NOTE             Element values must be passed as a Big Endian stream.
+**
+** Returns          true if added OK, else false
+**
+*******************************************************************************/
+bool    SDP_AddSequence (uint32_t handle,  uint16_t attr_id, uint16_t num_elem,
+                         uint8_t type[], uint8_t len[], uint8_t *p_val[])
+{
+#if (SDP_SERVER_ENABLED == TRUE)
+    uint16_t xx;
+    uint8_t *p;
+    uint8_t *p_head;
+    bool    result;
+    uint8_t *p_buff = (uint8_t *)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2);
+
+    p = p_buff;
+
+    /* First, build the sequence */
+    for (xx = 0; xx < num_elem; xx++)
+    {
+        p_head = p;
+        switch (len[xx])
+        {
+        case 1:
+            UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_ONE_BYTE);
+            break;
+        case 2:
+            UINT8_TO_BE_STREAM  (p, (type[xx] << 3) | SIZE_TWO_BYTES);
+            break;
+        case 4:
+            UINT8_TO_BE_STREAM  (p, (type[xx] << 3) | SIZE_FOUR_BYTES);
+            break;
+        case 8:
+            UINT8_TO_BE_STREAM  (p, (type[xx] << 3) | SIZE_EIGHT_BYTES);
+            break;
+        case 16:
+            UINT8_TO_BE_STREAM  (p, (type[xx] << 3) | SIZE_SIXTEEN_BYTES);
+            break;
+        default:
+            UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_IN_NEXT_BYTE);
+            UINT8_TO_BE_STREAM (p, len[xx]);
+            break;
+        }
+
+        ARRAY_TO_BE_STREAM (p, p_val[xx], len[xx]);
+
+        if (p - p_buff > SDP_MAX_ATTR_LEN)
+        {
+            /* go back to before we add this element */
+            p = p_head;
+            if(p_head == p_buff)
+            {
+                /* the first element exceed the max length */
+                SDP_TRACE_ERROR ("SDP_AddSequence - too long(attribute is not added)!!");
+                osi_free(p_buff);
+                return false;
+            }
+            else
+                SDP_TRACE_ERROR ("SDP_AddSequence - too long, add %d elements of %d", xx, num_elem);
+            break;
+        }
+    }
+    result = SDP_AddAttribute (handle, attr_id, DATA_ELE_SEQ_DESC_TYPE,(uint32_t) (p - p_buff), p_buff);
+    osi_free(p_buff);
+    return result;
+#else   /* SDP_SERVER_ENABLED == FALSE */
+    return (false);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function         SDP_AddUuidSequence
+**
+** Description      This function is called to add a UUID sequence to a record.
+**                  This would be through the SDP database maintenance API.
+**                  If the sequence already exists in the record, it is replaced
+**                  with the new sequence.
+**
+** Returns          true if added OK, else false
+**
+*******************************************************************************/
+bool    SDP_AddUuidSequence (uint32_t handle,  uint16_t attr_id, uint16_t num_uuids,
+                             uint16_t *p_uuids)
+{
+#if (SDP_SERVER_ENABLED == TRUE)
+    uint16_t xx;
+    uint8_t *p;
+    int32_t max_len = SDP_MAX_ATTR_LEN -3;
+    bool    result;
+    uint8_t *p_buff = (uint8_t *)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2);
+
+    p = p_buff;
+
+    /* First, build the sequence */
+    for (xx = 0; xx < num_uuids ; xx++, p_uuids++)
+    {
+        UINT8_TO_BE_STREAM  (p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+        UINT16_TO_BE_STREAM (p, *p_uuids);
+
+        if((p - p_buff) > max_len)
+        {
+            SDP_TRACE_WARNING ("SDP_AddUuidSequence - too long, add %d uuids of %d", xx, num_uuids);
+            break;
+        }
+    }
+
+    result = SDP_AddAttribute (handle, attr_id, DATA_ELE_SEQ_DESC_TYPE,(uint32_t) (p - p_buff), p_buff);
+    osi_free(p_buff);
+    return result;
+#else   /* SDP_SERVER_ENABLED == FALSE */
+    return (false);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         SDP_AddProtocolList
+**
+** Description      This function is called to add a protocol descriptor list to
+**                  a record. This would be through the SDP database maintenance API.
+**                  If the protocol list already exists in the record, it is replaced
+**                  with the new list.
+**
+** Returns          true if added OK, else false
+**
+*******************************************************************************/
+bool    SDP_AddProtocolList (uint32_t handle, uint16_t num_elem,
+                             tSDP_PROTOCOL_ELEM *p_elem_list)
+{
+#if (SDP_SERVER_ENABLED == TRUE)
+    int offset;
+    bool    result;
+    uint8_t *p_buff = (uint8_t *)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2);
+
+    offset = sdp_compose_proto_list(p_buff, num_elem, p_elem_list);
+    result = SDP_AddAttribute (handle, ATTR_ID_PROTOCOL_DESC_LIST,DATA_ELE_SEQ_DESC_TYPE, (uint32_t) offset, p_buff);
+    osi_free(p_buff);
+    return result;
+#else   /* SDP_SERVER_ENABLED == FALSE */
+    return (false);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function         SDP_AddAdditionProtoLists
+**
+** Description      This function is called to add a protocol descriptor list to
+**                  a record. This would be through the SDP database maintenance API.
+**                  If the protocol list already exists in the record, it is replaced
+**                  with the new list.
+**
+** Returns          true if added OK, else false
+**
+*******************************************************************************/
+bool    SDP_AddAdditionProtoLists (uint32_t handle, uint16_t num_elem,
+                                   tSDP_PROTO_LIST_ELEM *p_proto_list)
+{
+#if (SDP_SERVER_ENABLED == TRUE)
+    uint16_t xx;
+    uint8_t *p;
+    uint8_t *p_len;
+    int offset;
+    bool    result;
+    uint8_t *p_buff = (uint8_t *)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2);
+
+    p = p_buff;
+
+    /* for each ProtocolDescriptorList */
+    for (xx = 0; xx < num_elem; xx++, p_proto_list++)
+    {
+        UINT8_TO_BE_STREAM  (p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+        p_len = p++;
+
+        offset = sdp_compose_proto_list(p, p_proto_list->num_elems,
+                                        p_proto_list->list_elem);
+        p += offset;
+
+        *p_len  = (uint8_t)(p - p_len - 1);
+    }
+    result = SDP_AddAttribute (handle, ATTR_ID_ADDITION_PROTO_DESC_LISTS,DATA_ELE_SEQ_DESC_TYPE,
+	                           (uint32_t) (p - p_buff), p_buff);
+    osi_free(p_buff);
+    return result;
+
+#else   /* SDP_SERVER_ENABLED == FALSE */
+    return (false);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         SDP_AddProfileDescriptorList
+**
+** Description      This function is called to add a profile descriptor list to
+**                  a record. This would be through the SDP database maintenance API.
+**                  If the version already exists in the record, it is replaced
+**                  with the new one.
+**
+** Returns          true if added OK, else false
+**
+*******************************************************************************/
+bool    SDP_AddProfileDescriptorList (uint32_t handle, uint16_t profile_uuid,
+                                      uint16_t version)
+{
+#if (SDP_SERVER_ENABLED == TRUE)
+    uint8_t *p;
+    bool    result;
+    uint8_t *p_buff = (uint8_t *)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN);
+
+    p = p_buff + 2;
+
+    /* First, build the profile descriptor list. This consists of a data element sequence. */
+    /* The sequence consists of profile's UUID and version number  */
+    UINT8_TO_BE_STREAM  (p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+    UINT16_TO_BE_STREAM (p, profile_uuid);
+
+    UINT8_TO_BE_STREAM  (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+    UINT16_TO_BE_STREAM (p, version);
+
+    /* Add in type and length fields */
+    *p_buff = (uint8_t) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+    *(p_buff+1) = (uint8_t) (p - (p_buff+2));
+
+    result = SDP_AddAttribute (handle, ATTR_ID_BT_PROFILE_DESC_LIST,DATA_ELE_SEQ_DESC_TYPE, (uint32_t) (p - p_buff), p_buff);
+    osi_free(p_buff);
+    return result;
+
+#else   /* SDP_SERVER_ENABLED == FALSE */
+    return (false);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function         SDP_AddLanguageBaseAttrIDList
+**
+** Description      This function is called to add a language base attr list to
+**                  a record. This would be through the SDP database maintenance API.
+**                  If the version already exists in the record, it is replaced
+**                  with the new one.
+**
+** Returns          true if added OK, else false
+**
+*******************************************************************************/
+bool    SDP_AddLanguageBaseAttrIDList (uint32_t handle, uint16_t lang,
+                                       uint16_t char_enc, uint16_t base_id)
+{
+#if (SDP_SERVER_ENABLED == TRUE)
+    uint8_t *p;
+    bool    result;
+    uint8_t *p_buff = (uint8_t *) osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN);
+
+    p = p_buff;
+
+    /* First, build the language base descriptor list. This consists of a data */
+    /* element sequence. The sequence consists of 9 bytes (3 UINt16 fields)    */
+    UINT8_TO_BE_STREAM  (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+    UINT16_TO_BE_STREAM (p, lang);
+
+    UINT8_TO_BE_STREAM  (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+    UINT16_TO_BE_STREAM (p, char_enc);
+
+    UINT8_TO_BE_STREAM  (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+    UINT16_TO_BE_STREAM (p, base_id);
+
+    result = SDP_AddAttribute (handle, ATTR_ID_LANGUAGE_BASE_ATTR_ID_LIST,DATA_ELE_SEQ_DESC_TYPE,
+	                           (uint32_t) (p - p_buff), p_buff);
+    osi_free(p_buff);
+    return result;
+#else   /* SDP_SERVER_ENABLED == FALSE */
+    return (false);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function         SDP_AddServiceClassIdList
+**
+** Description      This function is called to add a service list to a record.
+**                  This would be through the SDP database maintenance API.
+**                  If the service list already exists in the record, it is replaced
+**                  with the new list.
+**
+** Returns          true if added OK, else false
+**
+*******************************************************************************/
+bool    SDP_AddServiceClassIdList (uint32_t handle, uint16_t num_services,
+                                   uint16_t *p_service_uuids)
+{
+#if (SDP_SERVER_ENABLED == TRUE)
+    uint16_t xx;
+    uint8_t *p;
+    bool    result;
+    uint8_t *p_buff = (uint8_t *) osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2);
+
+    p = p_buff;
+
+    for (xx = 0; xx < num_services; xx++, p_service_uuids++)
+    {
+        UINT8_TO_BE_STREAM  (p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+        UINT16_TO_BE_STREAM (p, *p_service_uuids);
+    }
+
+    result = SDP_AddAttribute (handle, ATTR_ID_SERVICE_CLASS_ID_LIST,DATA_ELE_SEQ_DESC_TYPE,
+	                           (uint32_t) (p - p_buff), p_buff);
+    osi_free(p_buff);
+    return result;
+#else   /* SDP_SERVER_ENABLED == FALSE */
+    return (false);
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function         SDP_DeleteAttribute
+**
+** Description      This function is called to delete an attribute from a record.
+**                  This would be through the SDP database maintenance API.
+**
+** Returns          true if deleted OK, else false if not found
+**
+*******************************************************************************/
+bool    SDP_DeleteAttribute (uint32_t handle, uint16_t attr_id)
+{
+#if (SDP_SERVER_ENABLED == TRUE)
+    uint16_t        xx, yy;
+    tSDP_RECORD     *p_rec = &sdp_cb.server_db.record[0];
+    uint8_t         *pad_ptr;
+    uint32_t len;                        /* Number of bytes in the entry */
+
+    /* Find the record in the database */
+    for (xx = 0; xx < sdp_cb.server_db.num_records; xx++, p_rec++)
+    {
+        if (p_rec->record_handle == handle)
+        {
+            tSDP_ATTRIBUTE  *p_attr = &p_rec->attribute[0];
+
+            SDP_TRACE_API("Deleting attr_id 0x%04x for handle 0x%x", attr_id, handle);
+            /* Found it. Now, find the attribute */
+            for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++)
+            {
+                if (p_attr->id == attr_id)
+                {
+                    pad_ptr = p_attr->value_ptr;
+                    len = p_attr->len;
+
+                    if (len)
+                    {
+                        for (yy = 0; yy < p_rec->num_attributes; yy++)
+                        {
+                            if( p_rec->attribute[yy].value_ptr > pad_ptr )
+                                p_rec->attribute[yy].value_ptr -= len;
+                        }
+                    }
+
+                    /* Found it. Shift everything up one */
+                    p_rec->num_attributes--;
+
+                    for (yy = xx; yy < p_rec->num_attributes; yy++, p_attr++)
+                    {
+                        *p_attr = *(p_attr + 1);
+                    }
+
+                    /* adjust attribute values if needed */
+                    if (len)
+                    {
+                        xx = (p_rec->free_pad_ptr - ((pad_ptr+len) -
+                                                  &p_rec->attr_pad[0]));
+                        for( yy=0; yy<xx; yy++, pad_ptr++)
+                            *pad_ptr = *(pad_ptr+len);
+                        p_rec->free_pad_ptr -= len;
+                    }
+                    return (true);
+                }
+            }
+        }
+    }
+#endif
+    /* If here, not found */
+    return (false);
+}
+
+/*******************************************************************************
+**
+** Function         SDP_ReadRecord
+**
+** Description      This function is called to get the raw data of the record
+**                  with the given handle from the database.
+**
+** Returns          -1, if the record is not found.
+**                  Otherwise, the offset (0 or 1) to start of data in p_data.
+**
+**                  The size of data copied into p_data is in *p_data_len.
+**
+*******************************************************************************/
+#if (SDP_RAW_DATA_INCLUDED == TRUE)
+int32_t SDP_ReadRecord(uint32_t handle, uint8_t *p_data, int32_t *p_data_len)
+{
+    int32_t         len = 0;                        /* Number of bytes in the entry */
+    int32_t         offset = -1; /* default to not found */
+#if (SDP_SERVER_ENABLED == TRUE)
+    tSDP_RECORD     *p_rec;
+    uint16_t        start = 0;
+    uint16_t        end = 0xffff;
+    tSDP_ATTRIBUTE  *p_attr;
+    uint16_t        rem_len;
+    uint8_t         *p_rsp;
+
+    /* Find the record in the database */
+    p_rec = sdp_db_find_record(handle);
+    if(p_rec && p_data && p_data_len)
+    {
+        p_rsp = &p_data[3];
+        while ( (p_attr = sdp_db_find_attr_in_rec (p_rec, start, end)) != NULL)
+        {
+            /* Check if attribute fits. Assume 3-byte value type/length */
+            rem_len = *p_data_len - (uint16_t) (p_rsp - p_data);
+
+            if (p_attr->len > (uint32_t)(rem_len - 6))
+                break;
+
+            p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
+
+            /* next attr id */
+            start = p_attr->id + 1;
+        }
+        len = (int32_t) (p_rsp - p_data);
+
+        /* Put in the sequence header (2 or 3 bytes) */
+        if (len > 255)
+        {
+            offset = 0;
+            p_data[0] = (uint8_t) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
+            p_data[1] = (uint8_t) ((len - 3) >> 8);
+            p_data[2] = (uint8_t) (len - 3);
+        }
+        else
+        {
+            offset = 1;
+
+            p_data[1] = (uint8_t) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+            p_data[2] = (uint8_t) (len - 3);
+
+            len--;
+        }
+        *p_data_len = len;
+    }
+#endif
+    /* If here, not found */
+    return (offset);
+}
+#endif
diff --git a/bt/stack/sdp/sdp_discovery.cc b/bt/stack/sdp/sdp_discovery.cc
new file mode 100644
index 0000000..d1fdc55
--- /dev/null
+++ b/bt/stack/sdp/sdp_discovery.cc
@@ -0,0 +1,1065 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 SDP discovery functions
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "bt_target.h"
+#include "bt_common.h"
+#include "l2cdefs.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "sdp_api.h"
+#include "sdpint.h"
+#include "btu.h"
+#include "btm_api.h"
+
+
+#ifndef SDP_DEBUG_RAW
+#define SDP_DEBUG_RAW       false
+#endif
+
+/********************************************************************************/
+/*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
+/********************************************************************************/
+#if (SDP_CLIENT_ENABLED == TRUE)
+static void          process_service_search_rsp (tCONN_CB *p_ccb, uint8_t *p_reply);
+static void          process_service_attr_rsp (tCONN_CB *p_ccb, uint8_t *p_reply);
+static void          process_service_search_attr_rsp (tCONN_CB *p_ccb, uint8_t *p_reply);
+static uint8_t       *save_attr_seq (tCONN_CB *p_ccb, uint8_t *p, uint8_t *p_msg_end);
+static tSDP_DISC_REC *add_record (tSDP_DISCOVERY_DB *p_db, BD_ADDR p_bda);
+static uint8_t       *add_attr (uint8_t *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
+                                uint16_t attr_id, tSDP_DISC_ATTR *p_parent_attr, uint8_t nest_level);
+
+/* Safety check in case we go crazy */
+#define MAX_NEST_LEVELS     5
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+/*******************************************************************************
+**
+** Function         sdpu_build_uuid_seq
+**
+** Description      This function builds a UUID sequence from the list of
+**                  passed UUIDs. It is also passed the address of the output
+**                  buffer.
+**
+** Returns          Pointer to next byte in the output buffer.
+**
+*******************************************************************************/
+static uint8_t *sdpu_build_uuid_seq (uint8_t *p_out, uint16_t num_uuids, tSDP_UUID *p_uuid_list)
+{
+    uint16_t xx;
+    uint8_t *p_len;
+
+    /* First thing is the data element header */
+    UINT8_TO_BE_STREAM  (p_out, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+
+    /* Remember where the length goes. Leave space for it. */
+    p_len = p_out;
+    p_out += 1;
+
+    /* Now, loop through and put in all the UUID(s) */
+    for (xx = 0; xx < num_uuids; xx++, p_uuid_list++)
+    {
+        if (p_uuid_list->len == 2)
+        {
+            UINT8_TO_BE_STREAM  (p_out, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+            UINT16_TO_BE_STREAM (p_out, p_uuid_list->uu.uuid16);
+        }
+        else if (p_uuid_list->len == 4)
+        {
+            UINT8_TO_BE_STREAM  (p_out, (UUID_DESC_TYPE << 3) | SIZE_FOUR_BYTES);
+            UINT32_TO_BE_STREAM (p_out, p_uuid_list->uu.uuid32);
+        }
+        else
+        {
+            UINT8_TO_BE_STREAM (p_out, (UUID_DESC_TYPE << 3) | SIZE_SIXTEEN_BYTES);
+            ARRAY_TO_BE_STREAM (p_out, p_uuid_list->uu.uuid128, p_uuid_list->len);
+        }
+    }
+
+    /* Now, put in the length */
+    xx = (uint16_t)(p_out - p_len - 1);
+    UINT8_TO_BE_STREAM (p_len, xx);
+
+    return (p_out);
+}
+
+/*******************************************************************************
+**
+** Function         sdp_snd_service_search_req
+**
+** Description      Send a service search request to the SDP server.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void sdp_snd_service_search_req(tCONN_CB *p_ccb, uint8_t cont_len, uint8_t * p_cont)
+{
+    uint8_t         *p, *p_start, *p_param_len;
+    BT_HDR          *p_cmd = (BT_HDR *) osi_malloc(SDP_DATA_BUF_SIZE);
+    uint16_t        param_len;
+
+    /* Prepare the buffer for sending the packet to L2CAP */
+    p_cmd->offset = L2CAP_MIN_OFFSET;
+    p = p_start = (uint8_t *)(p_cmd + 1) + L2CAP_MIN_OFFSET;
+
+    /* Build a service search request packet */
+    UINT8_TO_BE_STREAM  (p, SDP_PDU_SERVICE_SEARCH_REQ);
+    UINT16_TO_BE_STREAM (p, p_ccb->transaction_id);
+    p_ccb->transaction_id++;
+
+    /* Skip the length, we need to add it at the end */
+    p_param_len = p;
+    p += 2;
+
+    /* Build the UID sequence. */
+#if (SDP_BROWSE_PLUS == TRUE)
+    p = sdpu_build_uuid_seq (p, 1, &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx]);
+#else
+    p = sdpu_build_uuid_seq (p, p_ccb->p_db->num_uuid_filters, p_ccb->p_db->uuid_filters);
+#endif
+
+    /* Set max service record count */
+    UINT16_TO_BE_STREAM (p, sdp_cb.max_recs_per_search);
+
+    /* Set continuation state */
+    UINT8_TO_BE_STREAM (p, cont_len);
+
+    /* if this is not the first request */
+    if(cont_len && p_cont)
+    {
+        memcpy(p, p_cont, cont_len);
+        p += cont_len;
+    }
+
+    /* Go back and put the parameter length into the buffer */
+    param_len = (uint16_t)(p - p_param_len - 2);
+    UINT16_TO_BE_STREAM (p_param_len, param_len);
+
+    p_ccb->disc_state = SDP_DISC_WAIT_HANDLES;
+
+    /* Set the length of the SDP data in the buffer */
+    p_cmd->len = (uint16_t)(p - p_start);
+
+#if (SDP_DEBUG_RAW == TRUE)
+    SDP_TRACE_WARNING("sdp_snd_service_search_req cont_len :%d disc_state:%d",cont_len, p_ccb->disc_state);
+#endif
+
+
+    L2CA_DataWrite (p_ccb->connection_id, p_cmd);
+
+    /* Start inactivity timer */
+    alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
+                       sdp_conn_timer_timeout, p_ccb, btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+**
+** Function         sdp_disc_connected
+**
+** Description      This function is called when an SDP discovery attempt is
+**                  connected.
+**
+** Returns          void
+**
+*******************************************************************************/
+void sdp_disc_connected (tCONN_CB *p_ccb)
+{
+    if (p_ccb->is_attr_search)
+    {
+        p_ccb->disc_state = SDP_DISC_WAIT_SEARCH_ATTR;
+
+        process_service_search_attr_rsp (p_ccb, NULL);
+    }
+    else
+    {
+        /* First step is to get a list of the handles from the server. */
+        /* We are not searching for a specific attribute, so we will   */
+        /* first search for the service, then get all attributes of it */
+
+        p_ccb->num_handles = 0;
+        sdp_snd_service_search_req(p_ccb, 0, NULL);
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         sdp_disc_server_rsp
+**
+** Description      This function is called when there is a response from
+**                  the server.
+**
+** Returns          void
+**
+*******************************************************************************/
+void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg)
+{
+    uint8_t         *p, rsp_pdu;
+    bool            invalid_pdu = true;
+
+#if (SDP_DEBUG_RAW == TRUE)
+    SDP_TRACE_WARNING("sdp_disc_server_rsp disc_state:%d", p_ccb->disc_state);
+#endif
+
+    /* stop inactivity timer when we receive a response */
+    alarm_cancel(p_ccb->sdp_conn_timer);
+
+    /* Got a reply!! Check what we got back */
+    p = (uint8_t *)(p_msg + 1) + p_msg->offset;
+
+    BE_STREAM_TO_UINT8 (rsp_pdu, p);
+
+    p_msg->len--;
+
+    switch (rsp_pdu)
+    {
+    case SDP_PDU_SERVICE_SEARCH_RSP:
+        if (p_ccb->disc_state == SDP_DISC_WAIT_HANDLES)
+        {
+            process_service_search_rsp (p_ccb, p);
+            invalid_pdu = false;
+        }
+        break;
+
+    case SDP_PDU_SERVICE_ATTR_RSP:
+        if (p_ccb->disc_state == SDP_DISC_WAIT_ATTR)
+        {
+            process_service_attr_rsp (p_ccb, p);
+            invalid_pdu = false;
+        }
+        break;
+
+    case SDP_PDU_SERVICE_SEARCH_ATTR_RSP:
+        if (p_ccb->disc_state == SDP_DISC_WAIT_SEARCH_ATTR)
+        {
+            process_service_search_attr_rsp (p_ccb, p);
+            invalid_pdu = false;
+        }
+        break;
+    }
+
+    if (invalid_pdu)
+    {
+        SDP_TRACE_WARNING ("SDP - Unexp. PDU: %d in state: %d", rsp_pdu, p_ccb->disc_state);
+        sdp_disconnect (p_ccb, SDP_GENERIC_ERROR);
+    }
+}
+
+/******************************************************************************
+**
+** Function         process_service_search_rsp
+**
+** Description      This function is called when there is a search response from
+**                  the server.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void process_service_search_rsp (tCONN_CB *p_ccb, uint8_t *p_reply)
+{
+    uint16_t    xx;
+    uint16_t    total, cur_handles, orig;
+    uint8_t     cont_len;
+
+    /* Skip transaction, and param len */
+    p_reply += 4;
+    BE_STREAM_TO_UINT16 (total, p_reply);
+    BE_STREAM_TO_UINT16 (cur_handles, p_reply);
+
+    orig = p_ccb->num_handles;
+    p_ccb->num_handles += cur_handles;
+    if (p_ccb->num_handles == 0)
+    {
+        SDP_TRACE_WARNING ("SDP - Rcvd ServiceSearchRsp, no matches");
+        sdp_disconnect (p_ccb, SDP_NO_RECS_MATCH);
+        return;
+    }
+
+    /* Save the handles that match. We will can only process a certain number. */
+    if (total > sdp_cb.max_recs_per_search)
+        total = sdp_cb.max_recs_per_search;
+    if (p_ccb->num_handles > sdp_cb.max_recs_per_search)
+        p_ccb->num_handles = sdp_cb.max_recs_per_search;
+
+    for (xx = orig; xx < p_ccb->num_handles; xx++)
+        BE_STREAM_TO_UINT32 (p_ccb->handles[xx], p_reply);
+
+    BE_STREAM_TO_UINT8 (cont_len, p_reply);
+    if(cont_len != 0)
+    {
+        if(cont_len > SDP_MAX_CONTINUATION_LEN)
+        {
+            sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE);
+            return;
+        }
+        /* stay in the same state */
+        sdp_snd_service_search_req(p_ccb, cont_len, p_reply);
+    }
+    else
+    {
+        /* change state */
+        p_ccb->disc_state = SDP_DISC_WAIT_ATTR;
+
+        /* Kick off the first attribute request */
+        process_service_attr_rsp (p_ccb, NULL);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         sdp_copy_raw_data
+**
+** Description      copy the raw data
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+#if (SDP_RAW_DATA_INCLUDED == TRUE)
+static void sdp_copy_raw_data (tCONN_CB *p_ccb, bool    offset)
+{
+    unsigned int    cpy_len;
+    uint32_t        list_len;
+    uint8_t         *p;
+    uint8_t         type;
+
+#if (SDP_DEBUG_RAW == TRUE)
+    uint8_t num_array[SDP_MAX_LIST_BYTE_COUNT];
+    uint32_t i;
+
+    for (i = 0; i < p_ccb->list_len; i++)
+    {
+        snprintf((char *)&num_array[i*2], sizeof(num_array) - i*2,
+            "%02X",(uint8_t)(p_ccb->rsp_list[i]));
+    }
+    SDP_TRACE_WARNING("result :%s",num_array);
+#endif
+
+    if(p_ccb->p_db->raw_data)
+    {
+        cpy_len = p_ccb->p_db->raw_size - p_ccb->p_db->raw_used;
+        list_len = p_ccb->list_len;
+        p = &p_ccb->rsp_list[0];
+
+        if(offset)
+        {
+            type = *p++;
+            p = sdpu_get_len_from_type (p, type, &list_len);
+        }
+        if(list_len && list_len < cpy_len )
+        {
+            cpy_len = list_len;
+        }
+#if (SDP_DEBUG_RAW == TRUE)
+        SDP_TRACE_WARNING("list_len :%d cpy_len:%d raw_size:%d raw_used:%d",
+            list_len, cpy_len, p_ccb->p_db->raw_size, p_ccb->p_db->raw_used);
+#endif
+        memcpy (&p_ccb->p_db->raw_data[p_ccb->p_db->raw_used], p, cpy_len);
+        p_ccb->p_db->raw_used += cpy_len;
+    }
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         process_service_attr_rsp
+**
+** Description      This function is called when there is a attribute response from
+**                  the server.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void process_service_attr_rsp (tCONN_CB *p_ccb, uint8_t *p_reply)
+{
+    uint8_t         *p_start, *p_param_len;
+    uint16_t        param_len, list_byte_count;
+    bool            cont_request_needed = false;
+
+#if (SDP_DEBUG_RAW == TRUE)
+    SDP_TRACE_WARNING("process_service_attr_rsp raw inc:%d",
+        SDP_RAW_DATA_INCLUDED);
+#endif
+    /* If p_reply is NULL, we were called after the records handles were read */
+    if (p_reply)
+    {
+#if (SDP_DEBUG_RAW == TRUE)
+        SDP_TRACE_WARNING("ID & len: 0x%02x-%02x-%02x-%02x",
+            p_reply[0], p_reply[1], p_reply[2], p_reply[3]);
+#endif
+        /* Skip transaction ID and length */
+        p_reply += 4;
+
+        BE_STREAM_TO_UINT16 (list_byte_count, p_reply);
+#if (SDP_DEBUG_RAW == TRUE)
+        SDP_TRACE_WARNING("list_byte_count:%d", list_byte_count);
+#endif
+
+        /* Copy the response to the scratchpad. First, a safety check on the length */
+        if ((p_ccb->list_len + list_byte_count) > SDP_MAX_LIST_BYTE_COUNT)
+        {
+            sdp_disconnect (p_ccb, SDP_INVALID_PDU_SIZE);
+            return;
+        }
+
+#if (SDP_DEBUG_RAW == TRUE)
+        SDP_TRACE_WARNING("list_len: %d, list_byte_count: %d",
+            p_ccb->list_len, list_byte_count);
+#endif
+        if (p_ccb->rsp_list == NULL)
+            p_ccb->rsp_list = (uint8_t *)osi_malloc(SDP_MAX_LIST_BYTE_COUNT);
+        memcpy(&p_ccb->rsp_list[p_ccb->list_len], p_reply, list_byte_count);
+        p_ccb->list_len += list_byte_count;
+        p_reply         += list_byte_count;
+#if (SDP_DEBUG_RAW == TRUE)
+        SDP_TRACE_WARNING("list_len: %d(attr_rsp)", p_ccb->list_len);
+
+        /* Check if we need to request a continuation */
+        SDP_TRACE_WARNING("*p_reply:%d(%d)", *p_reply, SDP_MAX_CONTINUATION_LEN);
+#endif
+        if (*p_reply)
+        {
+            if (*p_reply > SDP_MAX_CONTINUATION_LEN)
+            {
+                sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE);
+                return;
+            }
+            cont_request_needed = true;
+        }
+        else
+        {
+
+#if (SDP_RAW_DATA_INCLUDED == TRUE)
+            SDP_TRACE_WARNING("process_service_attr_rsp");
+            sdp_copy_raw_data (p_ccb, false);
+#endif
+
+            /* Save the response in the database. Stop on any error */
+            if (!save_attr_seq (p_ccb, &p_ccb->rsp_list[0], &p_ccb->rsp_list[p_ccb->list_len]))
+            {
+                sdp_disconnect (p_ccb, SDP_DB_FULL);
+                return;
+            }
+            p_ccb->list_len = 0;
+            p_ccb->cur_handle++;
+        }
+    }
+
+    /* Now, ask for the next handle. Re-use the buffer we just got. */
+    if (p_ccb->cur_handle < p_ccb->num_handles)
+    {
+        BT_HDR  *p_msg = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
+        uint8_t *p;
+
+        p_msg->offset = L2CAP_MIN_OFFSET;
+        p = p_start = (uint8_t *)(p_msg + 1) + L2CAP_MIN_OFFSET;
+
+        /* Get all the attributes from the server */
+        UINT8_TO_BE_STREAM  (p, SDP_PDU_SERVICE_ATTR_REQ);
+        UINT16_TO_BE_STREAM (p, p_ccb->transaction_id);
+        p_ccb->transaction_id++;
+
+        /* Skip the length, we need to add it at the end */
+        p_param_len = p;
+        p += 2;
+
+        UINT32_TO_BE_STREAM (p, p_ccb->handles[p_ccb->cur_handle]);
+
+        /* Max attribute byte count */
+        UINT16_TO_BE_STREAM (p, sdp_cb.max_attr_list_size);
+
+        /* If no attribute filters, build a wildcard attribute sequence */
+        if (p_ccb->p_db->num_attr_filters)
+            p = sdpu_build_attrib_seq (p, p_ccb->p_db->attr_filters, p_ccb->p_db->num_attr_filters);
+        else
+            p = sdpu_build_attrib_seq (p, NULL, 0);
+
+        /* Was this a continuation request ? */
+        if (cont_request_needed)
+        {
+            memcpy (p, p_reply, *p_reply + 1);
+            p += *p_reply + 1;
+        }
+        else
+            UINT8_TO_BE_STREAM (p, 0);
+
+        /* Go back and put the parameter length into the buffer */
+        param_len = (uint16_t)(p - p_param_len - 2);
+        UINT16_TO_BE_STREAM (p_param_len, param_len);
+
+        /* Set the length of the SDP data in the buffer */
+        p_msg->len = (uint16_t)(p - p_start);
+
+
+        L2CA_DataWrite (p_ccb->connection_id, p_msg);
+
+        /* Start inactivity timer */
+        alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
+                           sdp_conn_timer_timeout, p_ccb,
+                           btu_general_alarm_queue);
+    }
+    else
+    {
+        sdp_disconnect (p_ccb, SDP_SUCCESS);
+        return;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         process_service_search_attr_rsp
+**
+** Description      This function is called when there is a search attribute
+**                  response from the server.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void process_service_search_attr_rsp (tCONN_CB *p_ccb, uint8_t *p_reply)
+{
+    uint8_t         *p, *p_start, *p_end, *p_param_len;
+    uint8_t         type;
+    uint32_t        seq_len;
+    uint16_t        param_len, lists_byte_count = 0;
+    bool            cont_request_needed = false;
+
+#if (SDP_DEBUG_RAW == TRUE)
+    SDP_TRACE_WARNING("process_service_search_attr_rsp");
+#endif
+    /* If p_reply is NULL, we were called for the initial read */
+    if (p_reply)
+    {
+#if (SDP_DEBUG_RAW == TRUE)
+        SDP_TRACE_WARNING("ID & len: 0x%02x-%02x-%02x-%02x",
+            p_reply[0], p_reply[1], p_reply[2], p_reply[3]);
+#endif
+        /* Skip transaction ID and length */
+        p_reply += 4;
+
+        BE_STREAM_TO_UINT16 (lists_byte_count, p_reply);
+#if (SDP_DEBUG_RAW == TRUE)
+        SDP_TRACE_WARNING("lists_byte_count:%d", lists_byte_count);
+#endif
+
+        /* Copy the response to the scratchpad. First, a safety check on the length */
+        if ((p_ccb->list_len + lists_byte_count) > SDP_MAX_LIST_BYTE_COUNT)
+        {
+            sdp_disconnect (p_ccb, SDP_INVALID_PDU_SIZE);
+            return;
+        }
+
+#if (SDP_DEBUG_RAW == TRUE)
+        SDP_TRACE_WARNING("list_len: %d, list_byte_count: %d",
+            p_ccb->list_len, lists_byte_count);
+#endif
+        if (p_ccb->rsp_list == NULL)
+            p_ccb->rsp_list = (uint8_t *)osi_malloc(SDP_MAX_LIST_BYTE_COUNT);
+        memcpy (&p_ccb->rsp_list[p_ccb->list_len], p_reply, lists_byte_count);
+        p_ccb->list_len += lists_byte_count;
+        p_reply         += lists_byte_count;
+#if (SDP_DEBUG_RAW == TRUE)
+        SDP_TRACE_WARNING("list_len: %d(search_attr_rsp)", p_ccb->list_len);
+
+        /* Check if we need to request a continuation */
+        SDP_TRACE_WARNING("*p_reply:%d(%d)", *p_reply, SDP_MAX_CONTINUATION_LEN);
+#endif
+        if (*p_reply)
+        {
+            if (*p_reply > SDP_MAX_CONTINUATION_LEN)
+            {
+                sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE);
+                return;
+            }
+
+            cont_request_needed = true;
+        }
+    }
+
+#if (SDP_DEBUG_RAW == TRUE)
+    SDP_TRACE_WARNING("cont_request_needed:%d", cont_request_needed);
+#endif
+    /* If continuation request (or first time request) */
+    if ((cont_request_needed) || (!p_reply))
+    {
+        BT_HDR  *p_msg = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
+        uint8_t *p;
+
+        p_msg->offset = L2CAP_MIN_OFFSET;
+        p = p_start = (uint8_t *)(p_msg + 1) + L2CAP_MIN_OFFSET;
+
+        /* Build a service search request packet */
+        UINT8_TO_BE_STREAM  (p, SDP_PDU_SERVICE_SEARCH_ATTR_REQ);
+        UINT16_TO_BE_STREAM (p, p_ccb->transaction_id);
+        p_ccb->transaction_id++;
+
+        /* Skip the length, we need to add it at the end */
+        p_param_len = p;
+        p += 2;
+
+        /* Build the UID sequence. */
+#if (SDP_BROWSE_PLUS == TRUE)
+        p = sdpu_build_uuid_seq (p, 1, &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx]);
+#else
+        p = sdpu_build_uuid_seq (p, p_ccb->p_db->num_uuid_filters, p_ccb->p_db->uuid_filters);
+#endif
+
+        /* Max attribute byte count */
+        UINT16_TO_BE_STREAM (p, sdp_cb.max_attr_list_size);
+
+        /* If no attribute filters, build a wildcard attribute sequence */
+        if (p_ccb->p_db->num_attr_filters)
+            p = sdpu_build_attrib_seq (p, p_ccb->p_db->attr_filters, p_ccb->p_db->num_attr_filters);
+        else
+            p = sdpu_build_attrib_seq (p, NULL, 0);
+
+        /* No continuation for first request */
+        if (p_reply)
+        {
+            memcpy (p, p_reply, *p_reply + 1);
+            p += *p_reply + 1;
+        }
+        else
+            UINT8_TO_BE_STREAM (p, 0);
+
+        /* Go back and put the parameter length into the buffer */
+        param_len = p - p_param_len - 2;
+        UINT16_TO_BE_STREAM (p_param_len, param_len);
+
+        /* Set the length of the SDP data in the buffer */
+        p_msg->len = p - p_start;
+
+
+        L2CA_DataWrite (p_ccb->connection_id, p_msg);
+
+        /* Start inactivity timer */
+        alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
+                           sdp_conn_timer_timeout, p_ccb,
+                           btu_general_alarm_queue);
+
+        return;
+    }
+
+
+    /*******************************************************************/
+    /* We now have the full response, which is a sequence of sequences */
+    /*******************************************************************/
+
+#if (SDP_RAW_DATA_INCLUDED == TRUE)
+    SDP_TRACE_WARNING("process_service_search_attr_rsp");
+    sdp_copy_raw_data (p_ccb, true);
+#endif
+
+    p = &p_ccb->rsp_list[0];
+
+    /* The contents is a sequence of attribute sequences */
+    type = *p++;
+
+    if ((type >> 3) != DATA_ELE_SEQ_DESC_TYPE)
+    {
+        SDP_TRACE_WARNING ("SDP - Wrong type: 0x%02x in attr_rsp", type);
+        return;
+    }
+    p = sdpu_get_len_from_type (p, type, &seq_len);
+
+    p_end = &p_ccb->rsp_list[p_ccb->list_len];
+
+    if ((p + seq_len) != p_end)
+    {
+        sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE);
+        return;
+    }
+
+    while (p < p_end)
+    {
+        p = save_attr_seq (p_ccb, p, &p_ccb->rsp_list[p_ccb->list_len]);
+        if (!p)
+        {
+            sdp_disconnect (p_ccb, SDP_DB_FULL);
+            return;
+        }
+    }
+
+    /* Since we got everything we need, disconnect the call */
+    sdp_disconnect (p_ccb, SDP_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function         save_attr_seq
+**
+** Description      This function is called when there is a response from
+**                  the server.
+**
+** Returns          pointer to next byte or NULL if error
+**
+*******************************************************************************/
+static uint8_t *save_attr_seq (tCONN_CB *p_ccb, uint8_t *p, uint8_t *p_msg_end)
+{
+    uint32_t    seq_len, attr_len;
+    uint16_t    attr_id;
+    uint8_t     type, *p_seq_end;
+    tSDP_DISC_REC *p_rec;
+
+    type = *p++;
+
+    if ((type >> 3) != DATA_ELE_SEQ_DESC_TYPE)
+    {
+        SDP_TRACE_WARNING ("SDP - Wrong type: 0x%02x in attr_rsp", type);
+        return (NULL);
+    }
+
+    p = sdpu_get_len_from_type (p, type, &seq_len);
+    if ((p + seq_len) > p_msg_end)
+    {
+        SDP_TRACE_WARNING ("SDP - Bad len in attr_rsp %d", seq_len);
+        return (NULL);
+    }
+
+    /* Create a record */
+    p_rec = add_record (p_ccb->p_db, p_ccb->device_address);
+    if (!p_rec)
+    {
+        SDP_TRACE_WARNING ("SDP - DB full add_record");
+        return (NULL);
+    }
+
+    p_seq_end = p + seq_len;
+
+    while (p < p_seq_end)
+    {
+        /* First get the attribute ID */
+        type = *p++;
+        p = sdpu_get_len_from_type (p, type, &attr_len);
+        if (((type >> 3) != UINT_DESC_TYPE) || (attr_len != 2))
+        {
+            SDP_TRACE_WARNING ("SDP - Bad type: 0x%02x or len: %d in attr_rsp", type, attr_len);
+            return (NULL);
+        }
+        BE_STREAM_TO_UINT16 (attr_id, p);
+
+        /* Now, add the attribute value */
+        p = add_attr (p, p_ccb->p_db, p_rec, attr_id, NULL, 0);
+
+        if (!p)
+        {
+            SDP_TRACE_WARNING ("SDP - DB full add_attr");
+            return (NULL);
+        }
+    }
+
+    return (p);
+}
+
+
+/*******************************************************************************
+**
+** Function         add_record
+**
+** Description      This function allocates space for a record from the DB.
+**
+** Returns          pointer to next byte in data stream
+**
+*******************************************************************************/
+tSDP_DISC_REC *add_record (tSDP_DISCOVERY_DB *p_db, BD_ADDR p_bda)
+{
+    tSDP_DISC_REC   *p_rec;
+
+    /* See if there is enough space in the database */
+    if (p_db->mem_free < sizeof (tSDP_DISC_REC))
+        return (NULL);
+
+    p_rec = (tSDP_DISC_REC *) p_db->p_free_mem;
+    p_db->p_free_mem += sizeof (tSDP_DISC_REC);
+    p_db->mem_free   -= sizeof (tSDP_DISC_REC);
+
+    p_rec->p_first_attr = NULL;
+    p_rec->p_next_rec   = NULL;
+
+    memcpy (p_rec->remote_bd_addr, p_bda, BD_ADDR_LEN);
+
+    /* Add the record to the end of chain */
+    if (!p_db->p_first_rec)
+        p_db->p_first_rec = p_rec;
+    else
+    {
+        tSDP_DISC_REC   *p_rec1 = p_db->p_first_rec;
+
+        while (p_rec1->p_next_rec)
+            p_rec1 = p_rec1->p_next_rec;
+
+        p_rec1->p_next_rec = p_rec;
+    }
+
+    return (p_rec);
+}
+
+#define SDP_ADDITIONAL_LIST_MASK        0x80
+/*******************************************************************************
+**
+** Function         add_attr
+**
+** Description      This function allocates space for an attribute from the DB
+**                  and copies the data into it.
+**
+** Returns          pointer to next byte in data stream
+**
+*******************************************************************************/
+static uint8_t *add_attr (uint8_t *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
+                        uint16_t attr_id, tSDP_DISC_ATTR *p_parent_attr, uint8_t nest_level)
+{
+    tSDP_DISC_ATTR  *p_attr;
+    uint32_t        attr_len;
+    uint32_t        total_len;
+    uint16_t        attr_type;
+    uint16_t        id;
+    uint8_t         type;
+    uint8_t         *p_end;
+    uint8_t         is_additional_list = nest_level & SDP_ADDITIONAL_LIST_MASK;
+
+    nest_level &= ~(SDP_ADDITIONAL_LIST_MASK);
+
+    type = *p++;
+    p = sdpu_get_len_from_type (p, type, &attr_len);
+
+    attr_len &= SDP_DISC_ATTR_LEN_MASK;
+    attr_type = (type >> 3) & 0x0f;
+
+    /* See if there is enough space in the database */
+    if (attr_len > 4)
+        total_len = attr_len - 4 + (uint16_t)sizeof (tSDP_DISC_ATTR);
+    else
+        total_len = sizeof (tSDP_DISC_ATTR);
+
+    /* Ensure it is a multiple of 4 */
+    total_len = (total_len + 3) & ~3;
+
+    /* See if there is enough space in the database */
+    if (p_db->mem_free < total_len)
+        return (NULL);
+
+    p_attr                = (tSDP_DISC_ATTR *) p_db->p_free_mem;
+    p_attr->attr_id       = attr_id;
+    p_attr->attr_len_type = (uint16_t)attr_len | (attr_type << 12);
+    p_attr->p_next_attr = NULL;
+
+    /* Store the attribute value */
+    switch (attr_type)
+    {
+    case UINT_DESC_TYPE:
+        if( (is_additional_list != 0) && (attr_len == 2) )
+        {
+            BE_STREAM_TO_UINT16 (id, p);
+            if(id != ATTR_ID_PROTOCOL_DESC_LIST)
+                p -= 2;
+            else
+            {
+                /* Reserve the memory for the attribute now, as we need to add sub-attributes */
+                p_db->p_free_mem += sizeof (tSDP_DISC_ATTR);
+                p_db->mem_free   -= sizeof (tSDP_DISC_ATTR);
+                p_end             = p + attr_len;
+                total_len         = 0;
+
+                /* SDP_TRACE_DEBUG ("SDP - attr nest level:%d(list)", nest_level); */
+                if (nest_level >= MAX_NEST_LEVELS)
+                {
+                    SDP_TRACE_ERROR ("SDP - attr nesting too deep");
+                    return (p_end);
+                }
+
+                /* Now, add the list entry */
+                p = add_attr (p, p_db, p_rec, ATTR_ID_PROTOCOL_DESC_LIST, p_attr, (uint8_t)(nest_level + 1));
+
+                break;
+            }
+        }
+        /* Case falls through */
+
+    case TWO_COMP_INT_DESC_TYPE:
+        switch (attr_len)
+        {
+        case 1:
+            p_attr->attr_value.v.u8 = *p++;
+            break;
+        case 2:
+            BE_STREAM_TO_UINT16 (p_attr->attr_value.v.u16, p);
+            break;
+        case 4:
+            BE_STREAM_TO_UINT32 (p_attr->attr_value.v.u32, p);
+            break;
+        default:
+            BE_STREAM_TO_ARRAY (p, p_attr->attr_value.v.array, (int32_t)attr_len);
+            break;
+        }
+        break;
+
+    case UUID_DESC_TYPE:
+        switch (attr_len)
+        {
+        case 2:
+            BE_STREAM_TO_UINT16 (p_attr->attr_value.v.u16, p);
+            break;
+        case 4:
+            BE_STREAM_TO_UINT32 (p_attr->attr_value.v.u32, p);
+            if (p_attr->attr_value.v.u32 < 0x10000)
+            {
+                attr_len = 2;
+                p_attr->attr_len_type = (uint16_t)attr_len | (attr_type << 12);
+                p_attr->attr_value.v.u16 = (uint16_t) p_attr->attr_value.v.u32;
+
+            }
+            break;
+        case 16:
+            /* See if we can compress his UUID down to 16 or 32bit UUIDs */
+            if (sdpu_is_base_uuid (p))
+            {
+                if ((p[0] == 0) && (p[1] == 0))
+                {
+                    p_attr->attr_len_type = (p_attr->attr_len_type & ~SDP_DISC_ATTR_LEN_MASK) | 2;
+                    p += 2;
+                    BE_STREAM_TO_UINT16 (p_attr->attr_value.v.u16, p);
+                    p += MAX_UUID_SIZE - 4;
+                }
+                else
+                {
+                    p_attr->attr_len_type = (p_attr->attr_len_type & ~SDP_DISC_ATTR_LEN_MASK) | 4;
+                    BE_STREAM_TO_UINT32 (p_attr->attr_value.v.u32, p);
+                    p += MAX_UUID_SIZE - 4;
+                }
+            }
+            else
+            {
+                 /* coverity[overrun-local] */
+                 /*
+                    Event overrun-local: Overrun of static array "p_attr->attr_value.v.array" of size 4 at position 15 with index variable "ijk"
+                    False-positive: SDP uses scratch buffer to hold the attribute value.
+                    The actual size of tSDP_DISC_ATVAL does not matter.
+                    If the array size in tSDP_DISC_ATVAL is increase, we would increase the system RAM usage unnecessarily
+                */
+                BE_STREAM_TO_ARRAY (p, p_attr->attr_value.v.array, (int32_t)attr_len);
+            }
+            break;
+        default:
+            SDP_TRACE_WARNING ("SDP - bad len in UUID attr: %d", attr_len);
+            return (p + attr_len);
+        }
+        break;
+
+    case DATA_ELE_SEQ_DESC_TYPE:
+    case DATA_ELE_ALT_DESC_TYPE:
+        /* Reserve the memory for the attribute now, as we need to add sub-attributes */
+        p_db->p_free_mem += sizeof (tSDP_DISC_ATTR);
+        p_db->mem_free   -= sizeof (tSDP_DISC_ATTR);
+        p_end             = p + attr_len;
+        total_len         = 0;
+
+        /* SDP_TRACE_DEBUG ("SDP - attr nest level:%d", nest_level); */
+        if (nest_level >= MAX_NEST_LEVELS)
+        {
+            SDP_TRACE_ERROR ("SDP - attr nesting too deep");
+            return (p_end);
+        }
+        if(is_additional_list != 0 || attr_id == ATTR_ID_ADDITION_PROTO_DESC_LISTS)
+            nest_level |= SDP_ADDITIONAL_LIST_MASK;
+        /* SDP_TRACE_DEBUG ("SDP - attr nest level:0x%x(finish)", nest_level); */
+
+        while (p < p_end)
+        {
+            /* Now, add the list entry */
+            p = add_attr (p, p_db, p_rec, 0, p_attr, (uint8_t)(nest_level + 1));
+
+            if (!p)
+                return (NULL);
+        }
+        break;
+
+    case TEXT_STR_DESC_TYPE:
+    case URL_DESC_TYPE:
+        BE_STREAM_TO_ARRAY (p, p_attr->attr_value.v.array, (int32_t)attr_len);
+        break;
+
+    case BOOLEAN_DESC_TYPE:
+        switch (attr_len)
+        {
+        case 1:
+            p_attr->attr_value.v.u8 = *p++;
+            break;
+        default:
+            SDP_TRACE_WARNING ("SDP - bad len in boolean attr: %d", attr_len);
+            return (p + attr_len);
+        }
+        break;
+
+    default:    /* switch (attr_type) */
+        break;
+    }
+
+    p_db->p_free_mem += total_len;
+    p_db->mem_free   -= total_len;
+
+    /* Add the attribute to the end of the chain */
+    if (!p_parent_attr)
+    {
+        if (!p_rec->p_first_attr)
+            p_rec->p_first_attr = p_attr;
+        else
+        {
+            tSDP_DISC_ATTR  *p_attr1 = p_rec->p_first_attr;
+
+            while (p_attr1->p_next_attr)
+                p_attr1 = p_attr1->p_next_attr;
+
+            p_attr1->p_next_attr = p_attr;
+        }
+    }
+    else
+    {
+        if (!p_parent_attr->attr_value.v.p_sub_attr)
+        {
+            p_parent_attr->attr_value.v.p_sub_attr = p_attr;
+            /* SDP_TRACE_DEBUG ("parent:0x%x(id:%d), ch:0x%x(id:%d)",
+                p_parent_attr, p_parent_attr->attr_id, p_attr, p_attr->attr_id); */
+        }
+        else
+        {
+            tSDP_DISC_ATTR  *p_attr1 = p_parent_attr->attr_value.v.p_sub_attr;
+            /* SDP_TRACE_DEBUG ("parent:0x%x(id:%d), ch1:0x%x(id:%d)",
+                p_parent_attr, p_parent_attr->attr_id, p_attr1, p_attr1->attr_id); */
+
+            while (p_attr1->p_next_attr)
+                p_attr1 = p_attr1->p_next_attr;
+
+            p_attr1->p_next_attr = p_attr;
+            /* SDP_TRACE_DEBUG ("new ch:0x%x(id:%d)", p_attr, p_attr->attr_id); */
+        }
+    }
+
+    return (p);
+}
+
+#endif  /* CLIENT_ENABLED == TRUE */
diff --git a/bt/stack/sdp/sdp_main.cc b/bt/stack/sdp/sdp_main.cc
new file mode 100644
index 0000000..341c260
--- /dev/null
+++ b/bt/stack/sdp/sdp_main.cc
@@ -0,0 +1,728 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 main SDP functions
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "bt_common.h"
+#include "l2cdefs.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "osi/include/osi.h"
+
+#include "btu.h"
+#include "btm_api.h"
+
+#include "sdp_api.h"
+#include "sdpint.h"
+
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+/********************************************************************************/
+/*                       G L O B A L      S D P       D A T A                   */
+/********************************************************************************/
+tSDP_CB  sdp_cb;
+
+/********************************************************************************/
+/*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
+/********************************************************************************/
+static void sdp_connect_ind (BD_ADDR  bd_addr, uint16_t l2cap_cid, UNUSED_ATTR uint16_t psm,
+                             uint8_t l2cap_id);
+static void sdp_config_ind (uint16_t l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void sdp_config_cfm (uint16_t l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
+static void sdp_disconnect_ind (uint16_t l2cap_cid, bool    ack_needed);
+static void sdp_data_ind (uint16_t l2cap_cid, BT_HDR *p_msg);
+
+#if (SDP_CLIENT_ENABLED == TRUE)
+static void sdp_connect_cfm (uint16_t l2cap_cid, uint16_t result);
+static void sdp_disconnect_cfm (uint16_t l2cap_cid, uint16_t result);
+#else
+#define sdp_connect_cfm     NULL
+#define sdp_disconnect_cfm  NULL
+#endif
+
+
+/*******************************************************************************
+**
+** Function         sdp_init
+**
+** Description      This function initializes the SDP unit.
+**
+** Returns          void
+**
+*******************************************************************************/
+void sdp_init (void)
+{
+    /* Clears all structures and local SDP database (if Server is enabled) */
+    memset (&sdp_cb, 0, sizeof (tSDP_CB));
+
+    /* Initialize the L2CAP configuration. We only care about MTU and flush */
+    sdp_cb.l2cap_my_cfg.mtu_present       = true;
+    sdp_cb.l2cap_my_cfg.mtu               = SDP_MTU_SIZE;
+    sdp_cb.l2cap_my_cfg.flush_to_present  = true;
+    sdp_cb.l2cap_my_cfg.flush_to          = SDP_FLUSH_TO;
+
+    sdp_cb.max_attr_list_size             = SDP_MTU_SIZE - 16;
+    sdp_cb.max_recs_per_search            = SDP_MAX_DISC_SERVER_RECS;
+
+#if (SDP_SERVER_ENABLED == TRUE)
+    /* Register with Security Manager for the specific security level */
+    if (!BTM_SetSecurityLevel (false, SDP_SERVICE_NAME, BTM_SEC_SERVICE_SDP_SERVER,
+                               SDP_SECURITY_LEVEL, SDP_PSM, 0, 0))
+    {
+        SDP_TRACE_ERROR ("Security Registration Server failed");
+        return;
+    }
+#endif
+
+#if (SDP_CLIENT_ENABLED == TRUE)
+    /* Register with Security Manager for the specific security level */
+    if (!BTM_SetSecurityLevel (true, SDP_SERVICE_NAME, BTM_SEC_SERVICE_SDP_SERVER,
+                               SDP_SECURITY_LEVEL, SDP_PSM, 0, 0))
+    {
+        SDP_TRACE_ERROR ("Security Registration for Client failed");
+        return;
+    }
+#endif
+
+#if defined(SDP_INITIAL_TRACE_LEVEL)
+    sdp_cb.trace_level = SDP_INITIAL_TRACE_LEVEL;
+#else
+    sdp_cb.trace_level = BT_TRACE_LEVEL_NONE;    /* No traces */
+#endif
+
+    sdp_cb.reg_info.pL2CA_ConnectInd_Cb = sdp_connect_ind;
+    sdp_cb.reg_info.pL2CA_ConnectCfm_Cb = sdp_connect_cfm;
+    sdp_cb.reg_info.pL2CA_ConnectPnd_Cb = NULL;
+    sdp_cb.reg_info.pL2CA_ConfigInd_Cb  = sdp_config_ind;
+    sdp_cb.reg_info.pL2CA_ConfigCfm_Cb  = sdp_config_cfm;
+    sdp_cb.reg_info.pL2CA_DisconnectInd_Cb = sdp_disconnect_ind;
+    sdp_cb.reg_info.pL2CA_DisconnectCfm_Cb = sdp_disconnect_cfm;
+    sdp_cb.reg_info.pL2CA_QoSViolationInd_Cb = NULL;
+    sdp_cb.reg_info.pL2CA_DataInd_Cb = sdp_data_ind;
+    sdp_cb.reg_info.pL2CA_CongestionStatus_Cb = NULL;
+    sdp_cb.reg_info.pL2CA_TxComplete_Cb       = NULL;
+
+    /* Now, register with L2CAP */
+    if (!L2CA_Register (SDP_PSM, &sdp_cb.reg_info))
+    {
+        SDP_TRACE_ERROR ("SDP Registration failed");
+    }
+}
+
+#if (SDP_DEBUG == TRUE)
+/*******************************************************************************
+**
+** Function         sdp_set_max_attr_list_size
+**
+** Description      This function sets the max attribute list size to use
+**
+** Returns          void
+**
+*******************************************************************************/
+uint16_t sdp_set_max_attr_list_size (uint16_t max_size)
+{
+    if (max_size > (sdp_cb.l2cap_my_cfg.mtu - 16) )
+        max_size = sdp_cb.l2cap_my_cfg.mtu - 16;
+
+    sdp_cb.max_attr_list_size  = max_size;
+
+    return sdp_cb.max_attr_list_size;
+}
+#endif
+
+/*******************************************************************************
+**
+** Function         sdp_connect_ind
+**
+** Description      This function handles an inbound connection indication
+**                  from L2CAP. This is the case where we are acting as a
+**                  server.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void sdp_connect_ind (BD_ADDR  bd_addr, uint16_t l2cap_cid,
+                             UNUSED_ATTR uint16_t psm, uint8_t l2cap_id)
+{
+#if (SDP_SERVER_ENABLED == TRUE)
+    tCONN_CB    *p_ccb;
+
+    /* Allocate a new CCB. Return if none available. */
+    if ((p_ccb = sdpu_allocate_ccb()) == NULL)
+        return;
+
+    /* Transition to the next appropriate state, waiting for config setup. */
+    p_ccb->con_state = SDP_STATE_CFG_SETUP;
+
+    /* Save the BD Address and Channel ID. */
+    memcpy (&p_ccb->device_address[0], bd_addr, sizeof (BD_ADDR));
+    p_ccb->connection_id = l2cap_cid;
+
+    /* Send response to the L2CAP layer. */
+    L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+    {
+        tL2CAP_CFG_INFO cfg = sdp_cb.l2cap_my_cfg;
+
+        if (cfg.fcr_present)
+        {
+            SDP_TRACE_DEBUG("sdp_connect_ind:  mode %u, txwinsz %u, max_trans %u, rtrans_tout %u, mon_tout %u, mps %u",
+                        cfg.fcr.mode, cfg.fcr.tx_win_sz, cfg.fcr.max_transmit,
+                        cfg.fcr.rtrans_tout,cfg.fcr.mon_tout, cfg.fcr.mps);
+        }
+
+        if ((!L2CA_ConfigReq (l2cap_cid, &cfg)) && cfg.fcr_present
+             && cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
+        {
+            /* FCR not desired; try again in basic mode */
+            cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+            cfg.fcr_present = false;
+            L2CA_ConfigReq (l2cap_cid, &cfg);
+        }
+    }
+
+    SDP_TRACE_EVENT ("SDP - Rcvd L2CAP conn ind, sent config req, CID 0x%x", p_ccb->connection_id);
+#else   /* No server */
+    /* Reject the connection */
+    L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_PSM, 0);
+#endif
+}
+
+#if (SDP_CLIENT_ENABLED == TRUE)
+/*******************************************************************************
+**
+** Function         sdp_connect_cfm
+**
+** Description      This function handles the connect confirm events
+**                  from L2CAP. This is the case when we are acting as a
+**                  client and have sent a connect request.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void sdp_connect_cfm (uint16_t l2cap_cid, uint16_t result)
+{
+    tCONN_CB    *p_ccb;
+    tL2CAP_CFG_INFO cfg;
+
+    /* Find CCB based on CID */
+    if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
+    {
+        SDP_TRACE_WARNING ("SDP - Rcvd conn cnf for unknown CID 0x%x", l2cap_cid);
+        return;
+    }
+
+    /* If the connection response contains success status, then */
+    /* Transition to the next state and startup the timer.      */
+    if ((result == L2CAP_CONN_OK) && (p_ccb->con_state == SDP_STATE_CONN_SETUP))
+    {
+        p_ccb->con_state = SDP_STATE_CFG_SETUP;
+
+        cfg = sdp_cb.l2cap_my_cfg;
+
+        if (cfg.fcr_present)
+        {
+            SDP_TRACE_DEBUG("sdp_connect_cfm:  mode %u, txwinsz %u, max_trans %u, rtrans_tout %u, mon_tout %u, mps %u",
+                        cfg.fcr.mode, cfg.fcr.tx_win_sz, cfg.fcr.max_transmit,
+                        cfg.fcr.rtrans_tout,cfg.fcr.mon_tout, cfg.fcr.mps);
+        }
+
+        if ((!L2CA_ConfigReq (l2cap_cid, &cfg)) && cfg.fcr_present
+             && cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
+        {
+            /* FCR not desired; try again in basic mode */
+            cfg.fcr_present = false;
+            cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+            L2CA_ConfigReq (l2cap_cid, &cfg);
+        }
+
+        SDP_TRACE_EVENT ("SDP - got conn cnf, sent cfg req, CID: 0x%x", p_ccb->connection_id);
+    }
+    else
+    {
+        SDP_TRACE_WARNING ("SDP - Rcvd conn cnf with error: 0x%x  CID 0x%x", result, p_ccb->connection_id);
+
+        /* Tell the user if he has a callback */
+        if (p_ccb->p_cb || p_ccb->p_cb2)
+        {
+            uint16_t err = -1;
+            if ((result == HCI_ERR_HOST_REJECT_SECURITY)
+             || (result == HCI_ERR_AUTH_FAILURE)
+             || (result == HCI_ERR_PAIRING_NOT_ALLOWED)
+             || (result == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED)
+             || (result == HCI_ERR_KEY_MISSING))
+                err = SDP_SECURITY_ERR;
+            else if (result == HCI_ERR_HOST_REJECT_DEVICE)
+                err = SDP_CONN_REJECTED;
+            else
+                err = SDP_CONN_FAILED;
+            if(p_ccb->p_cb)
+                (*p_ccb->p_cb)(err);
+            else if(p_ccb->p_cb2)
+                (*p_ccb->p_cb2)(err, p_ccb->user_data);
+
+        }
+        sdpu_release_ccb (p_ccb);
+    }
+}
+#endif  /* SDP_CLIENT_ENABLED == TRUE */
+
+
+/*******************************************************************************
+**
+** Function         sdp_config_ind
+**
+** Description      This function processes the L2CAP configuration indication
+**                  event.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void sdp_config_ind (uint16_t l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+    tCONN_CB    *p_ccb;
+
+    /* Find CCB based on CID */
+    if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
+    {
+        SDP_TRACE_WARNING ("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+        return;
+    }
+
+    /* Remember the remote MTU size */
+    if (!p_cfg->mtu_present)
+    {
+        /* use min(L2CAP_DEFAULT_MTU,SDP_MTU_SIZE) for GKI buffer size reasons */
+        p_ccb->rem_mtu_size = (L2CAP_DEFAULT_MTU > SDP_MTU_SIZE)?SDP_MTU_SIZE:L2CAP_DEFAULT_MTU;
+    }
+    else
+    {
+        if (p_cfg->mtu > SDP_MTU_SIZE)
+            p_ccb->rem_mtu_size = SDP_MTU_SIZE;
+        else
+            p_ccb->rem_mtu_size = p_cfg->mtu;
+    }
+
+    /* For now, always accept configuration from the other side */
+    p_cfg->flush_to_present = false;
+    p_cfg->mtu_present      = false;
+    p_cfg->result           = L2CAP_CFG_OK;
+
+    /* Check peer config request against our rfcomm configuration */
+    if (p_cfg->fcr_present)
+    {
+        /* Reject the window size if it is bigger than we want it to be */
+        if (p_cfg->fcr.mode != L2CAP_FCR_BASIC_MODE)
+        {
+            if (sdp_cb.l2cap_my_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE
+                && p_cfg->fcr.tx_win_sz > sdp_cb.l2cap_my_cfg.fcr.tx_win_sz)
+            {
+                p_cfg->fcr.tx_win_sz = sdp_cb.l2cap_my_cfg.fcr.tx_win_sz;
+                p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+                SDP_TRACE_DEBUG("sdp_config_ind(CONFIG) -> Please try again with SMALLER TX WINDOW");
+            }
+
+            /* Reject if locally we want basic and they don't */
+            if (sdp_cb.l2cap_my_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)
+            {
+                /* Ask for a new setup */
+                p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE;
+                p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+                SDP_TRACE_DEBUG("sdp_config_ind(CONFIG) -> Please try again with BASIC mode");
+            }
+            /* Remain in configure state and give the peer our desired configuration */
+            if (p_cfg->result != L2CAP_CFG_OK)
+            {
+                SDP_TRACE_WARNING ("SDP - Rcvd cfg ind, Unacceptable Parameters sent cfg cfm, CID: 0x%x", l2cap_cid);
+                L2CA_ConfigRsp (l2cap_cid, p_cfg);
+                return;
+            }
+        }
+        else    /* We agree with peer's request */
+            p_cfg->fcr_present = false;
+    }
+
+    L2CA_ConfigRsp (l2cap_cid, p_cfg);
+
+    SDP_TRACE_EVENT ("SDP - Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
+
+    p_ccb->con_flags |= SDP_FLAGS_HIS_CFG_DONE;
+
+    if (p_ccb->con_flags & SDP_FLAGS_MY_CFG_DONE)
+    {
+        p_ccb->con_state = SDP_STATE_CONNECTED;
+
+        if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) {
+            sdp_disc_connected (p_ccb);
+        } else {
+            /* Start inactivity timer */
+            alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
+                               sdp_conn_timer_timeout, p_ccb,
+                               btu_general_alarm_queue);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         sdp_config_cfm
+**
+** Description      This function processes the L2CAP configuration confirmation
+**                  event.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void sdp_config_cfm (uint16_t l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
+{
+    tCONN_CB    *p_ccb;
+
+    SDP_TRACE_EVENT ("SDP - Rcvd cfg cfm, CID: 0x%x  Result: %d", l2cap_cid, p_cfg->result);
+
+    /* Find CCB based on CID */
+    if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
+    {
+        SDP_TRACE_WARNING ("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+        return;
+    }
+
+    /* For now, always accept configuration from the other side */
+    if (p_cfg->result == L2CAP_CFG_OK)
+    {
+        p_ccb->con_flags |= SDP_FLAGS_MY_CFG_DONE;
+
+        if (p_ccb->con_flags & SDP_FLAGS_HIS_CFG_DONE)
+        {
+            p_ccb->con_state = SDP_STATE_CONNECTED;
+
+            if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) {
+                sdp_disc_connected (p_ccb);
+            } else {
+                /* Start inactivity timer */
+                alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
+                                   sdp_conn_timer_timeout, p_ccb,
+                                   btu_general_alarm_queue);
+            }
+        }
+    }
+    else
+    {
+        /* If peer has rejected FCR and suggested basic then try basic */
+        if (p_cfg->fcr_present)
+        {
+            tL2CAP_CFG_INFO cfg = sdp_cb.l2cap_my_cfg;
+            cfg.fcr_present = false;
+            L2CA_ConfigReq (l2cap_cid, &cfg);
+
+            /* Remain in configure state */
+            return;
+        }
+
+#if (SDP_CLIENT_ENABLED == TRUE)
+        sdp_disconnect(p_ccb, SDP_CFG_FAILED);
+#endif
+    }
+}
+
+/*******************************************************************************
+**
+** Function         sdp_disconnect_ind
+**
+** Description      This function handles a disconnect event from L2CAP. If
+**                  requested to, we ack the disconnect before dropping the CCB
+**
+** Returns          void
+**
+*******************************************************************************/
+static void sdp_disconnect_ind (uint16_t l2cap_cid, bool    ack_needed)
+{
+    tCONN_CB    *p_ccb;
+
+    /* Find CCB based on CID */
+    if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
+    {
+        SDP_TRACE_WARNING ("SDP - Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
+        return;
+    }
+
+    if (ack_needed)
+        L2CA_DisconnectRsp (l2cap_cid);
+
+    SDP_TRACE_EVENT ("SDP - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
+#if (SDP_CLIENT_ENABLED == TRUE)
+    /* Tell the user if he has a callback */
+    if (p_ccb->p_cb)
+        (*p_ccb->p_cb) ((uint16_t) ((p_ccb->con_state == SDP_STATE_CONNECTED) ?
+                        SDP_SUCCESS : SDP_CONN_FAILED));
+    else if (p_ccb->p_cb2)
+        (*p_ccb->p_cb2) ((uint16_t) ((p_ccb->con_state == SDP_STATE_CONNECTED) ?
+                        SDP_SUCCESS : SDP_CONN_FAILED), p_ccb->user_data);
+
+#endif
+    sdpu_release_ccb (p_ccb);
+}
+
+/*******************************************************************************
+**
+** Function         sdp_data_ind
+**
+** Description      This function is called when data is received from L2CAP.
+**                  if we are the originator of the connection, we are the SDP
+**                  client, and the received message is queued up for the client.
+**
+**                  If we are the destination of the connection, we are the SDP
+**                  server, so the message is passed to the server processing
+**                  function.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void sdp_data_ind (uint16_t l2cap_cid, BT_HDR *p_msg)
+{
+    tCONN_CB    *p_ccb;
+
+    /* Find CCB based on CID */
+    if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) != NULL)
+    {
+        if (p_ccb->con_state == SDP_STATE_CONNECTED)
+        {
+            if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG)
+                sdp_disc_server_rsp (p_ccb, p_msg);
+            else
+                sdp_server_handle_client_req (p_ccb, p_msg);
+        }
+        else
+        {
+            SDP_TRACE_WARNING ("SDP - Ignored L2CAP data while in state: %d, CID: 0x%x",
+                                p_ccb->con_state, l2cap_cid);
+        }
+    }
+    else
+    {
+        SDP_TRACE_WARNING ("SDP - Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
+    }
+
+    osi_free(p_msg);
+}
+
+
+#if (SDP_CLIENT_ENABLED == TRUE)
+/*******************************************************************************
+**
+** Function         sdp_conn_originate
+**
+** Description      This function is called from the API to originate a
+**                  connection.
+**
+** Returns          void
+**
+*******************************************************************************/
+tCONN_CB* sdp_conn_originate (uint8_t *p_bd_addr)
+{
+    tCONN_CB              *p_ccb;
+    uint16_t              cid;
+
+    /* Allocate a new CCB. Return if none available. */
+    if ((p_ccb = sdpu_allocate_ccb()) == NULL)
+    {
+        SDP_TRACE_WARNING ("SDP - no spare CCB for orig");
+        return (NULL);
+    }
+
+    SDP_TRACE_EVENT ("SDP - Originate started");
+
+    /* We are the originator of this connection */
+    p_ccb->con_flags |= SDP_FLAGS_IS_ORIG;
+
+    /* Save the BD Address and Channel ID. */
+    memcpy (&p_ccb->device_address[0], p_bd_addr, sizeof (BD_ADDR));
+
+    /* Transition to the next appropriate state, waiting for connection confirm. */
+    p_ccb->con_state = SDP_STATE_CONN_SETUP;
+
+    cid = L2CA_ConnectReq (SDP_PSM, p_bd_addr);
+
+    /* Check if L2CAP started the connection process */
+    if (cid != 0)
+    {
+        p_ccb->connection_id = cid;
+
+        return (p_ccb);
+    }
+    else
+    {
+        SDP_TRACE_WARNING ("SDP - Originate failed");
+        sdpu_release_ccb (p_ccb);
+        return (NULL);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         sdp_disconnect
+**
+** Description      This function disconnects a connection.
+**
+** Returns          void
+**
+*******************************************************************************/
+void sdp_disconnect (tCONN_CB*p_ccb, uint16_t reason)
+{
+#if (SDP_BROWSE_PLUS == TRUE)
+
+    /* If we are browsing for multiple UUIDs ... */
+    if ((p_ccb->con_state == SDP_STATE_CONNECTED)
+     && (p_ccb->con_flags & SDP_FLAGS_IS_ORIG)
+     && ((reason == SDP_SUCCESS) || (reason == SDP_NO_RECS_MATCH)))
+    {
+        /* If the browse found something, do no more searching */
+        if ((p_ccb->cur_uuid_idx == 0) && (p_ccb->p_db->p_first_rec))
+            p_ccb->cur_uuid_idx = p_ccb->p_db->num_uuid_filters;
+
+        while (++p_ccb->cur_uuid_idx < p_ccb->p_db->num_uuid_filters)
+        {
+            /* Check we have not already found the UUID (maybe through browse) */
+            if ((p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].len == 2)
+                && (SDP_FindServiceInDb (p_ccb->p_db,
+                        p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].uu.uuid16,
+                        NULL)))
+                continue;
+
+            if ((p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].len > 2)
+                && (SDP_FindServiceUUIDInDb (p_ccb->p_db,
+                        &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx], NULL)))
+                continue;
+
+            p_ccb->cur_handle = 0;
+
+            SDP_TRACE_EVENT ("SDP - looking for for more,  CID: 0x%x",
+                              p_ccb->connection_id);
+
+            sdp_disc_connected (p_ccb);
+            return;
+        }
+    }
+
+    if ((reason == SDP_NO_RECS_MATCH) && (p_ccb->p_db->p_first_rec))
+        reason = SDP_SUCCESS;
+
+#endif
+
+    SDP_TRACE_EVENT ("SDP - disconnect  CID: 0x%x", p_ccb->connection_id);
+
+    /* Check if we have a connection ID */
+    if (p_ccb->connection_id != 0)
+    {
+        L2CA_DisconnectReq (p_ccb->connection_id);
+        p_ccb->disconnect_reason = reason;
+    }
+
+    /* If at setup state, we may not get callback ind from L2CAP */
+    /* Call user callback immediately */
+    if (p_ccb->con_state == SDP_STATE_CONN_SETUP)
+    {
+        /* Tell the user if he has a callback */
+        if (p_ccb->p_cb)
+            (*p_ccb->p_cb) (reason);
+        else if (p_ccb->p_cb2)
+            (*p_ccb->p_cb2) (reason, p_ccb->user_data);
+
+        sdpu_release_ccb (p_ccb);
+    }
+
+}
+
+/*******************************************************************************
+**
+** Function         sdp_disconnect_cfm
+**
+** Description      This function handles a disconnect confirm event from L2CAP.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void sdp_disconnect_cfm (uint16_t l2cap_cid,
+                                UNUSED_ATTR uint16_t result)
+{
+    tCONN_CB    *p_ccb;
+
+    /* Find CCB based on CID */
+    if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) == NULL)
+    {
+        SDP_TRACE_WARNING ("SDP - Rcvd L2CAP disc cfm, unknown CID: 0x%x", l2cap_cid);
+        return;
+    }
+
+    SDP_TRACE_EVENT ("SDP - Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid);
+
+    /* Tell the user if he has a callback */
+    if (p_ccb->p_cb)
+        (*p_ccb->p_cb) (p_ccb->disconnect_reason);
+    else if (p_ccb->p_cb2)
+        (*p_ccb->p_cb2) (p_ccb->disconnect_reason, p_ccb->user_data);
+
+
+    sdpu_release_ccb (p_ccb);
+}
+
+#endif  /* SDP_CLIENT_ENABLED == TRUE */
+
+/*******************************************************************************
+**
+** Function         sdp_conn_timer_timeout
+**
+** Description      This function processes a timeout. Currently, we simply send
+**                  a disconnect request to L2CAP.
+**
+** Returns          void
+**
+*******************************************************************************/
+void sdp_conn_timer_timeout(void *data)
+{
+    tCONN_CB *p_ccb = (tCONN_CB *)data;
+
+    SDP_TRACE_EVENT ("SDP - CCB timeout in state: %d  CID: 0x%x",
+                      p_ccb->con_state, p_ccb->connection_id);
+
+    L2CA_DisconnectReq (p_ccb->connection_id);
+#if (SDP_CLIENT_ENABLED == TRUE)
+    /* Tell the user if he has a callback */
+    if (p_ccb->p_cb)
+        (*p_ccb->p_cb) (SDP_CONN_FAILED);
+    else if (p_ccb->p_cb2)
+        (*p_ccb->p_cb2) (SDP_CONN_FAILED, p_ccb->user_data);
+#endif
+    sdpu_release_ccb (p_ccb);
+}
+
+
+
+
diff --git a/bt/stack/sdp/sdp_server.cc b/bt/stack/sdp/sdp_server.cc
new file mode 100644
index 0000000..086626a
--- /dev/null
+++ b/bt/stack/sdp/sdp_server.cc
@@ -0,0 +1,829 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 functions that handle the SDP server functions.
+ *  This is mainly dealing with client requests
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btu.h"
+
+#include "l2cdefs.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+
+#include "osi/include/osi.h"
+#include "sdp_api.h"
+#include "sdpint.h"
+
+
+#if (SDP_SERVER_ENABLED == TRUE)
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+/* Maximum number of bytes to reserve out of SDP MTU for response data */
+#define SDP_MAX_SERVICE_RSPHDR_LEN      12
+#define SDP_MAX_SERVATTR_RSPHDR_LEN     10
+#define SDP_MAX_ATTR_RSPHDR_LEN         10
+
+/********************************************************************************/
+/*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
+/********************************************************************************/
+static void process_service_search (tCONN_CB *p_ccb, uint16_t trans_num,
+                                    uint16_t param_len, uint8_t *p_req,
+                                    UNUSED_ATTR uint8_t *p_req_end);
+
+static void process_service_attr_req (tCONN_CB *p_ccb, uint16_t trans_num,
+                                      uint16_t param_len, uint8_t *p_req,
+                                      uint8_t *p_req_end);
+
+static void process_service_search_attr_req (tCONN_CB *p_ccb, uint16_t trans_num,
+                                             uint16_t param_len, uint8_t *p_req,
+                                             UNUSED_ATTR uint8_t *p_req_end);
+
+
+/********************************************************************************/
+/*                  E R R O R   T E X T   S T R I N G S                         */
+/*                                                                              */
+/* The default is to have no text string, but we allow the strings to be        */
+/* configured in target.h if people want them.                                  */
+/********************************************************************************/
+#ifndef SDP_TEXT_BAD_HEADER
+#define SDP_TEXT_BAD_HEADER     NULL
+#endif
+
+#ifndef SDP_TEXT_BAD_PDU
+#define SDP_TEXT_BAD_PDU        NULL
+#endif
+
+#ifndef SDP_TEXT_BAD_UUID_LIST
+#define SDP_TEXT_BAD_UUID_LIST  NULL
+#endif
+
+#ifndef SDP_TEXT_BAD_HANDLE
+#define SDP_TEXT_BAD_HANDLE     NULL
+#endif
+
+#ifndef SDP_TEXT_BAD_ATTR_LIST
+#define SDP_TEXT_BAD_ATTR_LIST  NULL
+#endif
+
+#ifndef SDP_TEXT_BAD_CONT_LEN
+#define SDP_TEXT_BAD_CONT_LEN   NULL
+#endif
+
+#ifndef SDP_TEXT_BAD_CONT_INX
+#define SDP_TEXT_BAD_CONT_INX   NULL
+#endif
+
+#ifndef SDP_TEXT_BAD_MAX_RECORDS_LIST
+#define SDP_TEXT_BAD_MAX_RECORDS_LIST   NULL
+#endif
+
+/*******************************************************************************
+**
+** Function         sdp_server_handle_client_req
+**
+** Description      This is the main dispatcher of the SDP server. It is called
+**                  when any data is received from L2CAP, and dispatches the
+**                  request to the appropriate handler.
+**
+** Returns          void
+**
+*******************************************************************************/
+void sdp_server_handle_client_req (tCONN_CB *p_ccb, BT_HDR *p_msg)
+{
+    uint8_t *p_req     = (uint8_t *) (p_msg + 1) + p_msg->offset;
+    uint8_t *p_req_end = p_req + p_msg->len;
+    uint8_t pdu_id;
+    uint16_t trans_num, param_len;
+
+
+    /* Start inactivity timer */
+    alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
+                       sdp_conn_timer_timeout, p_ccb, btu_general_alarm_queue);
+
+    /* The first byte in the message is the pdu type */
+    pdu_id = *p_req++;
+
+    /* Extract the transaction number and parameter length */
+    BE_STREAM_TO_UINT16 (trans_num, p_req);
+    BE_STREAM_TO_UINT16 (param_len, p_req);
+
+    if ((p_req + param_len) != p_req_end)
+    {
+        sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_PDU_SIZE, SDP_TEXT_BAD_HEADER);
+        return;
+    }
+
+    switch (pdu_id)
+    {
+    case SDP_PDU_SERVICE_SEARCH_REQ:
+        process_service_search (p_ccb, trans_num, param_len, p_req, p_req_end);
+        break;
+
+    case SDP_PDU_SERVICE_ATTR_REQ:
+        process_service_attr_req (p_ccb, trans_num, param_len, p_req, p_req_end);
+        break;
+
+    case SDP_PDU_SERVICE_SEARCH_ATTR_REQ:
+        process_service_search_attr_req (p_ccb, trans_num, param_len, p_req, p_req_end);
+        break;
+
+    default:
+        sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_PDU);
+        SDP_TRACE_WARNING ("SDP - server got unknown PDU: 0x%x", pdu_id);
+        break;
+    }
+}
+
+
+
+/*******************************************************************************
+**
+** Function         process_service_search
+**
+** Description      This function handles a service search request from the
+**                  client. It builds a reply message with info from the database,
+**                  and sends the reply back to the client.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void process_service_search (tCONN_CB *p_ccb, uint16_t trans_num,
+                                    uint16_t param_len, uint8_t *p_req,
+                                    UNUSED_ATTR uint8_t *p_req_end)
+{
+    uint16_t        max_replies, cur_handles, rem_handles, cont_offset;
+    tSDP_UUID_SEQ   uid_seq;
+    uint8_t         *p_rsp, *p_rsp_start, *p_rsp_param_len;
+    uint16_t        rsp_param_len, num_rsp_handles, xx;
+    uint32_t        rsp_handles[SDP_MAX_RECORDS] = {0};
+    tSDP_RECORD    *p_rec = NULL;
+    bool            is_cont = false;
+
+    p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
+
+    if ((!p_req) || (!uid_seq.num_uids))
+    {
+        sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
+        return;
+    }
+
+    /* Get the max replies we can send. Cap it at our max anyways. */
+    BE_STREAM_TO_UINT16 (max_replies, p_req);
+
+    if (max_replies > SDP_MAX_RECORDS)
+        max_replies = SDP_MAX_RECORDS;
+
+
+    if ((!p_req) || (p_req > p_req_end))
+    {
+        sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_MAX_RECORDS_LIST);
+        return;
+    }
+
+
+    /* Get a list of handles that match the UUIDs given to us */
+    for (num_rsp_handles = 0; num_rsp_handles < max_replies; )
+    {
+        p_rec = sdp_db_service_search (p_rec, &uid_seq);
+
+        if (p_rec)
+            rsp_handles[num_rsp_handles++] = p_rec->record_handle;
+        else
+            break;
+    }
+
+    /* Check if this is a continuation request */
+    if (*p_req)
+    {
+        if (*p_req++ != SDP_CONTINUATION_LEN || (p_req >= p_req_end))
+        {
+            sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
+                                     SDP_TEXT_BAD_CONT_LEN);
+            return;
+        }
+        BE_STREAM_TO_UINT16 (cont_offset, p_req);
+
+        if (cont_offset != p_ccb->cont_offset || num_rsp_handles < cont_offset)
+        {
+            sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
+                                     SDP_TEXT_BAD_CONT_INX);
+            return;
+        }
+
+        rem_handles = num_rsp_handles - cont_offset;    /* extract the remaining handles */
+    }
+    else
+    {
+        rem_handles = num_rsp_handles;
+        cont_offset = 0;
+        p_ccb->cont_offset = 0;
+    }
+
+    /* Calculate how many handles will fit in one PDU */
+    cur_handles = (uint16_t)((p_ccb->rem_mtu_size - SDP_MAX_SERVICE_RSPHDR_LEN) / 4);
+
+    if (rem_handles <= cur_handles)
+        cur_handles = rem_handles;
+    else /* Continuation is set */
+    {
+        p_ccb->cont_offset += cur_handles;
+        is_cont = true;
+    }
+
+    /* Get a buffer to use to build the response */
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_rsp = p_rsp_start = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+    /* Start building a rsponse */
+    UINT8_TO_BE_STREAM  (p_rsp, SDP_PDU_SERVICE_SEARCH_RSP);
+    UINT16_TO_BE_STREAM (p_rsp, trans_num);
+
+    /* Skip the length, we need to add it at the end */
+    p_rsp_param_len = p_rsp;
+    p_rsp += 2;
+
+    /* Put in total and current number of handles, and handles themselves */
+    UINT16_TO_BE_STREAM (p_rsp, num_rsp_handles);
+    UINT16_TO_BE_STREAM (p_rsp, cur_handles);
+
+/*    SDP_TRACE_DEBUG("SDP Service Rsp: tothdl %d, curhdlr %d, start %d, end %d, cont %d",
+                     num_rsp_handles, cur_handles, cont_offset,
+                     cont_offset + cur_handles-1, is_cont); */
+    for (xx = cont_offset; xx < cont_offset + cur_handles; xx++)
+        UINT32_TO_BE_STREAM (p_rsp, rsp_handles[xx]);
+
+    if (is_cont)
+    {
+        UINT8_TO_BE_STREAM  (p_rsp, SDP_CONTINUATION_LEN);
+        UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
+    }
+    else
+        UINT8_TO_BE_STREAM (p_rsp, 0);
+
+    /* Go back and put the parameter length into the buffer */
+    rsp_param_len = p_rsp - p_rsp_param_len - 2;
+    UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
+
+    /* Set the length of the SDP data in the buffer */
+    p_buf->len = p_rsp - p_rsp_start;
+
+
+    /* Send the buffer through L2CAP */
+    L2CA_DataWrite (p_ccb->connection_id, p_buf);
+}
+
+
+/*******************************************************************************
+**
+** Function         process_service_attr_req
+**
+** Description      This function handles an attribute request from the client.
+**                  It builds a reply message with info from the database,
+**                  and sends the reply back to the client.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void process_service_attr_req (tCONN_CB *p_ccb, uint16_t trans_num,
+                                      uint16_t param_len, uint8_t *p_req,
+                                      uint8_t *p_req_end)
+{
+    uint16_t        max_list_len, len_to_send, cont_offset;
+    int16_t         rem_len;
+    tSDP_ATTR_SEQ   attr_seq, attr_seq_sav;
+    uint8_t         *p_rsp, *p_rsp_start, *p_rsp_param_len;
+    uint16_t        rsp_param_len, xx;
+    uint32_t        rec_handle;
+    tSDP_RECORD     *p_rec;
+    tSDP_ATTRIBUTE  *p_attr;
+    bool            is_cont = false;
+    uint16_t        attr_len;
+
+    /* Extract the record handle */
+    BE_STREAM_TO_UINT32 (rec_handle, p_req);
+
+    if (p_req > p_req_end)
+    {
+        sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE);
+        return;
+    }
+
+    /* Get the max list length we can send. Cap it at MTU size minus overhead */
+    BE_STREAM_TO_UINT16 (max_list_len, p_req);
+
+    if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN))
+        max_list_len = p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN;
+
+    p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
+
+    if ((!p_req) || (!attr_seq.num_attr) || (p_req > p_req_end))
+    {
+        sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
+        return;
+    }
+
+    memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ;
+
+    /* Find a record with the record handle */
+    p_rec = sdp_db_find_record (rec_handle);
+    if (!p_rec)
+    {
+        sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE);
+        return;
+    }
+
+    /* Free and reallocate buffer */
+    osi_free(p_ccb->rsp_list);
+    p_ccb->rsp_list = (uint8_t *)osi_malloc(max_list_len);
+
+    /* Check if this is a continuation request */
+    if (*p_req) {
+        if (*p_req++ != SDP_CONTINUATION_LEN) {
+            sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
+                                    SDP_TEXT_BAD_CONT_LEN);
+            return;
+        }
+        BE_STREAM_TO_UINT16(cont_offset, p_req);
+
+        if (cont_offset != p_ccb->cont_offset) {
+            sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
+                                    SDP_TEXT_BAD_CONT_INX);
+            return;
+        }
+        is_cont = true;
+
+        /* Initialise for continuation response */
+        p_rsp = &p_ccb->rsp_list[0];
+        attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start =
+            p_ccb->cont_info.next_attr_start_id;
+    } else {
+        p_ccb->cont_offset = 0;
+        p_rsp = &p_ccb->rsp_list[3];    /* Leave space for data elem descr */
+
+        /* Reset continuation parameters in p_ccb */
+        p_ccb->cont_info.prev_sdp_rec = NULL;
+        p_ccb->cont_info.next_attr_index = 0;
+        p_ccb->cont_info.attr_offset = 0;
+    }
+
+    /* Search for attributes that match the list given to us */
+    for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++)
+    {
+        p_attr = sdp_db_find_attr_in_rec (p_rec, attr_seq.attr_entry[xx].start, attr_seq.attr_entry[xx].end);
+
+        if (p_attr)
+        {
+            /* Check if attribute fits. Assume 3-byte value type/length */
+            rem_len = max_list_len - (int16_t) (p_rsp - &p_ccb->rsp_list[0]);
+
+            /* just in case */
+            if (rem_len <= 0)
+            {
+                p_ccb->cont_info.next_attr_index = xx;
+                p_ccb->cont_info.next_attr_start_id = p_attr->id;
+                break;
+            }
+
+            attr_len = sdpu_get_attrib_entry_len(p_attr);
+            /* if there is a partial attribute pending to be sent */
+            if (p_ccb->cont_info.attr_offset)
+            {
+                p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len,
+                                                         &p_ccb->cont_info.attr_offset);
+
+                /* If the partial attrib could not been fully added yet */
+                if (p_ccb->cont_info.attr_offset != attr_len)
+                    break;
+                else /* If the partial attrib has been added in full by now */
+                    p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
+            }
+            else if (rem_len < attr_len) /* Not enough space for attr... so add partially */
+            {
+                if (attr_len >= SDP_MAX_ATTR_LEN)
+                {
+                    SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d", max_list_len, attr_len);
+                    sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
+                    return;
+                }
+
+                /* add the partial attribute if possible */
+                p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, (uint16_t)rem_len,
+                                                         &p_ccb->cont_info.attr_offset);
+
+                p_ccb->cont_info.next_attr_index = xx;
+                p_ccb->cont_info.next_attr_start_id = p_attr->id;
+                break;
+            }
+            else /* build the whole attribute */
+                p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
+
+            /* If doing a range, stick with this one till no more attributes found */
+            if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end)
+            {
+                /* Update for next time through */
+                attr_seq.attr_entry[xx].start = p_attr->id + 1;
+
+                xx--;
+            }
+        }
+    }
+    /* If all the attributes have been accomodated in p_rsp,
+       reset next_attr_index */
+    if (xx == attr_seq.num_attr)
+        p_ccb->cont_info.next_attr_index = 0;
+
+    len_to_send = (uint16_t) (p_rsp - &p_ccb->rsp_list[0]);
+    cont_offset = 0;
+
+    if (!is_cont)
+    {
+        p_ccb->list_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav) + 3;
+        /* Put in the sequence header (2 or 3 bytes) */
+        if (p_ccb->list_len > 255)
+        {
+            p_ccb->rsp_list[0] = (uint8_t) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
+            p_ccb->rsp_list[1] = (uint8_t) ((p_ccb->list_len - 3) >> 8);
+            p_ccb->rsp_list[2] = (uint8_t) (p_ccb->list_len - 3);
+        }
+        else
+        {
+            cont_offset = 1;
+
+            p_ccb->rsp_list[1] = (uint8_t) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+            p_ccb->rsp_list[2] = (uint8_t) (p_ccb->list_len - 3);
+
+            p_ccb->list_len--;
+            len_to_send--;
+        }
+    }
+
+    /* Get a buffer to use to build the response */
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_rsp = p_rsp_start = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+    /* Start building a rsponse */
+    UINT8_TO_BE_STREAM  (p_rsp, SDP_PDU_SERVICE_ATTR_RSP);
+    UINT16_TO_BE_STREAM (p_rsp, trans_num);
+
+    /* Skip the parameter length, add it when we know the length */
+    p_rsp_param_len = p_rsp;
+    p_rsp += 2;
+
+    UINT16_TO_BE_STREAM (p_rsp, len_to_send);
+
+    memcpy (p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
+    p_rsp += len_to_send;
+
+    p_ccb->cont_offset += len_to_send;
+
+    /* If anything left to send, continuation needed */
+    if (p_ccb->cont_offset < p_ccb->list_len)
+    {
+        is_cont = true;
+
+        UINT8_TO_BE_STREAM  (p_rsp, SDP_CONTINUATION_LEN);
+        UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
+    }
+    else
+        UINT8_TO_BE_STREAM (p_rsp, 0);
+
+    /* Go back and put the parameter length into the buffer */
+    rsp_param_len = p_rsp - p_rsp_param_len - 2;
+    UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
+
+    /* Set the length of the SDP data in the buffer */
+    p_buf->len = p_rsp - p_rsp_start;
+
+
+    /* Send the buffer through L2CAP */
+    L2CA_DataWrite (p_ccb->connection_id, p_buf);
+}
+
+
+
+/*******************************************************************************
+**
+** Function         process_service_search_attr_req
+**
+** Description      This function handles a combined service search and attribute
+**                  read request from the client. It builds a reply message with
+**                  info from the database, and sends the reply back to the client.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void process_service_search_attr_req (tCONN_CB *p_ccb, uint16_t trans_num,
+                                             uint16_t param_len, uint8_t *p_req,
+                                             UNUSED_ATTR uint8_t *p_req_end)
+{
+    uint16_t       max_list_len;
+    int16_t        rem_len;
+    uint16_t       len_to_send, cont_offset;
+    tSDP_UUID_SEQ   uid_seq;
+    uint8_t         *p_rsp, *p_rsp_start, *p_rsp_param_len;
+    uint16_t        rsp_param_len, xx;
+    tSDP_RECORD    *p_rec;
+    tSDP_ATTR_SEQ   attr_seq, attr_seq_sav;
+    tSDP_ATTRIBUTE *p_attr;
+    bool            maxxed_out = false, is_cont = false;
+    uint8_t         *p_seq_start;
+    uint16_t        seq_len, attr_len;
+
+    /* Extract the UUID sequence to search for */
+    p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
+
+    if ((!p_req) || (!uid_seq.num_uids))
+    {
+        sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
+        return;
+    }
+
+    /* Get the max list length we can send. Cap it at our max list length. */
+    BE_STREAM_TO_UINT16 (max_list_len, p_req);
+
+    if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN))
+        max_list_len = p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN;
+
+    p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
+
+    if ((!p_req) || (!attr_seq.num_attr))
+    {
+        sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
+        return;
+    }
+
+    memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ;
+
+    /* Free and reallocate buffer */
+    osi_free(p_ccb->rsp_list);
+    p_ccb->rsp_list = (uint8_t *)osi_malloc(max_list_len);
+
+    /* Check if this is a continuation request */
+    if (*p_req) {
+        if (*p_req++ != SDP_CONTINUATION_LEN) {
+            sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
+                                    SDP_TEXT_BAD_CONT_LEN);
+            return;
+        }
+        BE_STREAM_TO_UINT16(cont_offset, p_req);
+
+        if (cont_offset != p_ccb->cont_offset) {
+            sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
+                                     SDP_TEXT_BAD_CONT_INX);
+            return;
+        }
+        is_cont = true;
+
+        /* Initialise for continuation response */
+        p_rsp = &p_ccb->rsp_list[0];
+        attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start =
+            p_ccb->cont_info.next_attr_start_id;
+    } else {
+        p_ccb->cont_offset = 0;
+        p_rsp = &p_ccb->rsp_list[3];    /* Leave space for data elem descr */
+
+        /* Reset continuation parameters in p_ccb */
+        p_ccb->cont_info.prev_sdp_rec = NULL;
+        p_ccb->cont_info.next_attr_index = 0;
+        p_ccb->cont_info.last_attr_seq_desc_sent = false;
+        p_ccb->cont_info.attr_offset = 0;
+    }
+
+    /* Get a list of handles that match the UUIDs given to us */
+    for (p_rec = sdp_db_service_search (p_ccb->cont_info.prev_sdp_rec, &uid_seq); p_rec; p_rec = sdp_db_service_search (p_rec, &uid_seq))
+    {
+        /* Allow space for attribute sequence type and length */
+        p_seq_start = p_rsp;
+        if (p_ccb->cont_info.last_attr_seq_desc_sent == false)
+        {
+            /* See if there is enough room to include a new service in the current response */
+            rem_len = max_list_len - (int16_t) (p_rsp - &p_ccb->rsp_list[0]);
+            if (rem_len < 3)
+            {
+                /* Not enough room. Update continuation info for next response */
+                p_ccb->cont_info.next_attr_index = 0;
+                p_ccb->cont_info.next_attr_start_id = attr_seq.attr_entry[0].start;
+                break;
+            }
+            p_rsp += 3;
+        }
+
+        /* Get a list of handles that match the UUIDs given to us */
+        for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++)
+        {
+            p_attr = sdp_db_find_attr_in_rec (p_rec, attr_seq.attr_entry[xx].start, attr_seq.attr_entry[xx].end);
+
+            if (p_attr)
+            {
+                /* Check if attribute fits. Assume 3-byte value type/length */
+                rem_len = max_list_len - (int16_t) (p_rsp - &p_ccb->rsp_list[0]);
+
+                /* just in case */
+                if (rem_len <= 0)
+                {
+                    p_ccb->cont_info.next_attr_index = xx;
+                    p_ccb->cont_info.next_attr_start_id = p_attr->id;
+                    maxxed_out = true;
+                    break;
+                }
+
+                attr_len = sdpu_get_attrib_entry_len(p_attr);
+                /* if there is a partial attribute pending to be sent */
+                if (p_ccb->cont_info.attr_offset)
+                {
+                    p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len,
+                                                             &p_ccb->cont_info.attr_offset);
+
+                    /* If the partial attrib could not been fully added yet */
+                    if (p_ccb->cont_info.attr_offset != attr_len)
+                    {
+                        maxxed_out = true;
+                        break;
+                    }
+                    else /* If the partial attrib has been added in full by now */
+                        p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
+                }
+                else if (rem_len < attr_len) /* Not enough space for attr... so add partially */
+                {
+                    if (attr_len >= SDP_MAX_ATTR_LEN)
+                    {
+                        SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d", max_list_len, attr_len);
+                        sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
+                        return;
+                    }
+
+                    /* add the partial attribute if possible */
+                    p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, (uint16_t)rem_len,
+                                                             &p_ccb->cont_info.attr_offset);
+
+                    p_ccb->cont_info.next_attr_index = xx;
+                    p_ccb->cont_info.next_attr_start_id = p_attr->id;
+                    maxxed_out = true;
+                    break;
+                }
+                else /* build the whole attribute */
+                    p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
+
+                /* If doing a range, stick with this one till no more attributes found */
+                if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end)
+                {
+                    /* Update for next time through */
+                    attr_seq.attr_entry[xx].start = p_attr->id + 1;
+
+                    xx--;
+                }
+            }
+        }
+
+        /* Go back and put the type and length into the buffer */
+        if (p_ccb->cont_info.last_attr_seq_desc_sent == false)
+        {
+            seq_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav);
+            if (seq_len != 0)
+            {
+                UINT8_TO_BE_STREAM  (p_seq_start, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
+                UINT16_TO_BE_STREAM (p_seq_start, seq_len);
+
+                if (maxxed_out)
+                    p_ccb->cont_info.last_attr_seq_desc_sent = true;
+            }
+            else
+                p_rsp = p_seq_start;
+        }
+
+        if (maxxed_out)
+            break;
+
+        /* Restore the attr_seq to look for in the next sdp record */
+        memcpy(&attr_seq, &attr_seq_sav, sizeof(tSDP_ATTR_SEQ)) ;
+
+        /* Reset the next attr index */
+        p_ccb->cont_info.next_attr_index = 0;
+        p_ccb->cont_info.prev_sdp_rec = p_rec;
+        p_ccb->cont_info.last_attr_seq_desc_sent = false;
+    }
+
+    /* response length */
+    len_to_send = (uint16_t) (p_rsp - &p_ccb->rsp_list[0]);
+    cont_offset = 0;
+
+    // The current SDP server design has a critical flaw where it can run into an infinite
+    // request/response loop with the client. Here's the scenario:
+    // - client makes SDP request
+    // - server returns the first fragment of the response with a continuation token
+    // - an SDP record is deleted from the server
+    // - client issues another request with previous continuation token
+    // - server has nothing to send back because the record is unavailable but in the
+    //   first fragment, it had specified more response bytes than are now available
+    // - server sends back no additional response bytes and returns the same continuation token
+    // - client issues another request with the continuation token, and the process repeats
+    //
+    // We work around this design flaw here by checking if we will make forward progress
+    // (i.e. we will send > 0 response bytes) on a continued request. If not, we must have
+    // run into the above situation and we tell the peer an error occurred.
+    //
+    // TODO(sharvil): rewrite SDP server.
+    if (is_cont && len_to_send == 0) {
+      sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE, NULL);
+      return;
+    }
+
+    /* If first response, insert sequence header */
+    if (!is_cont)
+    {
+        /* Get the total list length for requested uid and attribute sequence */
+        p_ccb->list_len = sdpu_get_list_len(&uid_seq, &attr_seq_sav) + 3;
+        /* Put in the sequence header (2 or 3 bytes) */
+        if (p_ccb->list_len > 255)
+        {
+            p_ccb->rsp_list[0] = (uint8_t) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
+            p_ccb->rsp_list[1] = (uint8_t) ((p_ccb->list_len - 3) >> 8);
+            p_ccb->rsp_list[2] = (uint8_t) (p_ccb->list_len - 3);
+        }
+        else
+        {
+            cont_offset = 1;
+
+            p_ccb->rsp_list[1] = (uint8_t) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+            p_ccb->rsp_list[2] = (uint8_t) (p_ccb->list_len - 3);
+
+            p_ccb->list_len--;
+            len_to_send--;
+        }
+    }
+
+    /* Get a buffer to use to build the response */
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_rsp = p_rsp_start = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+    /* Start building a rsponse */
+    UINT8_TO_BE_STREAM  (p_rsp, SDP_PDU_SERVICE_SEARCH_ATTR_RSP);
+    UINT16_TO_BE_STREAM (p_rsp, trans_num);
+
+    /* Skip the parameter length, add it when we know the length */
+    p_rsp_param_len = p_rsp;
+    p_rsp += 2;
+
+    /* Stream the list length to send */
+    UINT16_TO_BE_STREAM (p_rsp, len_to_send);
+
+    /* copy from rsp_list to the actual buffer to be sent */
+    memcpy (p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
+    p_rsp += len_to_send;
+
+    p_ccb->cont_offset += len_to_send;
+
+    /* If anything left to send, continuation needed */
+    if (p_ccb->cont_offset < p_ccb->list_len)
+    {
+        is_cont = true;
+
+        UINT8_TO_BE_STREAM  (p_rsp, SDP_CONTINUATION_LEN);
+        UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
+    }
+    else
+        UINT8_TO_BE_STREAM (p_rsp, 0);
+
+    /* Go back and put the parameter length into the buffer */
+    rsp_param_len = p_rsp - p_rsp_param_len - 2;
+    UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
+
+    /* Set the length of the SDP data in the buffer */
+    p_buf->len = p_rsp - p_rsp_start;
+
+
+    /* Send the buffer through L2CAP */
+    L2CA_DataWrite (p_ccb->connection_id, p_buf);
+}
+
+#endif  /* SDP_SERVER_ENABLED == TRUE */
diff --git a/bt/stack/sdp/sdp_utils.cc b/bt/stack/sdp/sdp_utils.cc
new file mode 100644
index 0000000..407f828
--- /dev/null
+++ b/bt/stack/sdp/sdp_utils.cc
@@ -0,0 +1,1043 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 SDP utility functions
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <stdio.h>
+
+#include "bt_common.h"
+#include "bt_types.h"
+
+#include "l2cdefs.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+
+#include "sdp_api.h"
+#include "sdpint.h"
+
+#include "btu.h"
+
+
+static const uint8_t sdp_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+                                        0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+
+/*******************************************************************************
+**
+** Function         sdpu_find_ccb_by_cid
+**
+** Description      This function searches the CCB table for an entry with the
+**                  passed CID.
+**
+** Returns          the CCB address, or NULL if not found.
+**
+*******************************************************************************/
+tCONN_CB *sdpu_find_ccb_by_cid (uint16_t cid)
+{
+    uint16_t     xx;
+    tCONN_CB     *p_ccb;
+
+    /* Look through each connection control block */
+    for (xx = 0, p_ccb = sdp_cb.ccb; xx < SDP_MAX_CONNECTIONS; xx++, p_ccb++)
+    {
+        if ((p_ccb->con_state != SDP_STATE_IDLE) && (p_ccb->connection_id == cid))
+            return (p_ccb);
+    }
+
+    /* If here, not found */
+    return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         sdpu_find_ccb_by_db
+**
+** Description      This function searches the CCB table for an entry with the
+**                  passed discovery db.
+**
+** Returns          the CCB address, or NULL if not found.
+**
+*******************************************************************************/
+tCONN_CB *sdpu_find_ccb_by_db (tSDP_DISCOVERY_DB *p_db)
+{
+#if (SDP_CLIENT_ENABLED == TRUE)
+    uint16_t     xx;
+    tCONN_CB     *p_ccb;
+
+    if (p_db)
+    {
+        /* Look through each connection control block */
+        for (xx = 0, p_ccb = sdp_cb.ccb; xx < SDP_MAX_CONNECTIONS; xx++, p_ccb++)
+        {
+            if ((p_ccb->con_state != SDP_STATE_IDLE) && (p_ccb->p_db == p_db))
+                return (p_ccb);
+        }
+    }
+#endif
+    /* If here, not found */
+    return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         sdpu_allocate_ccb
+**
+** Description      This function allocates a new CCB.
+**
+** Returns          CCB address, or NULL if none available.
+**
+*******************************************************************************/
+tCONN_CB *sdpu_allocate_ccb (void)
+{
+    uint16_t     xx;
+    tCONN_CB     *p_ccb;
+
+    /* Look through each connection control block for a free one */
+    for (xx = 0, p_ccb = sdp_cb.ccb; xx < SDP_MAX_CONNECTIONS; xx++, p_ccb++)
+    {
+        if (p_ccb->con_state == SDP_STATE_IDLE)
+        {
+            memset(p_ccb, 0, sizeof(tCONN_CB));
+            p_ccb->sdp_conn_timer = alarm_new("sdp.sdp_conn_timer");
+            return (p_ccb);
+        }
+    }
+
+    /* If here, no free CCB found */
+    return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function         sdpu_release_ccb
+**
+** Description      This function releases a CCB.
+**
+** Returns          void
+**
+*******************************************************************************/
+void sdpu_release_ccb (tCONN_CB *p_ccb)
+{
+    /* Ensure timer is stopped */
+    alarm_free(p_ccb->sdp_conn_timer);
+    p_ccb->sdp_conn_timer = NULL;
+
+    /* Drop any response pointer we may be holding */
+    p_ccb->con_state = SDP_STATE_IDLE;
+#if (SDP_CLIENT_ENABLED == TRUE)
+    p_ccb->is_attr_search = false;
+#endif
+
+    /* Free the response buffer */
+    if (p_ccb->rsp_list)
+        SDP_TRACE_DEBUG("releasing SDP rsp_list");
+    osi_free_and_reset((void **)&p_ccb->rsp_list);
+}
+
+
+/*******************************************************************************
+**
+** Function         sdpu_build_attrib_seq
+**
+** Description      This function builds an attribute sequence from the list of
+**                  passed attributes. It is also passed the address of the output
+**                  buffer.
+**
+** Returns          Pointer to next byte in the output buffer.
+**
+*******************************************************************************/
+uint8_t *sdpu_build_attrib_seq (uint8_t *p_out, uint16_t *p_attr, uint16_t num_attrs)
+{
+    uint16_t xx;
+
+    /* First thing is the data element header. See if the length fits 1 byte */
+    /* If no attributes, assume a 4-byte wildcard */
+    if (!p_attr)
+        xx = 5;
+    else
+        xx = num_attrs * 3;
+
+    if (xx > 255)
+    {
+        UINT8_TO_BE_STREAM  (p_out, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
+        UINT16_TO_BE_STREAM (p_out, xx);
+    }
+    else
+    {
+        UINT8_TO_BE_STREAM (p_out, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+        UINT8_TO_BE_STREAM (p_out, xx);
+    }
+
+    /* If there are no attributes specified, assume caller wants wildcard */
+    if (!p_attr)
+    {
+        UINT8_TO_BE_STREAM  (p_out, (UINT_DESC_TYPE << 3) | SIZE_FOUR_BYTES);
+        UINT16_TO_BE_STREAM (p_out, 0);
+        UINT16_TO_BE_STREAM (p_out, 0xFFFF);
+    }
+    else
+    {
+        /* Loop through and put in all the attributes(s) */
+        for (xx = 0; xx < num_attrs; xx++, p_attr++)
+        {
+            UINT8_TO_BE_STREAM  (p_out, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+            UINT16_TO_BE_STREAM (p_out, *p_attr);
+        }
+    }
+
+    return (p_out);
+}
+
+
+/*******************************************************************************
+**
+** Function         sdpu_build_attrib_entry
+**
+** Description      This function builds an attribute entry from the passed
+**                  attribute record. It is also passed the address of the output
+**                  buffer.
+**
+** Returns          Pointer to next byte in the output buffer.
+**
+*******************************************************************************/
+uint8_t *sdpu_build_attrib_entry (uint8_t *p_out, tSDP_ATTRIBUTE *p_attr)
+{
+    /* First, store the attribute ID. Goes as a UINT */
+    UINT8_TO_BE_STREAM  (p_out, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+    UINT16_TO_BE_STREAM (p_out, p_attr->id);
+
+    /* the attribute is in the db record.
+     * assuming the attribute len is less than SDP_MAX_ATTR_LEN */
+    switch(p_attr->type)
+    {
+    case TEXT_STR_DESC_TYPE:    /* 4 */
+    case DATA_ELE_SEQ_DESC_TYPE:/* 6 */
+    case DATA_ELE_ALT_DESC_TYPE:/* 7 */
+    case URL_DESC_TYPE:         /* 8 */
+#if (SDP_MAX_ATTR_LEN > 0xFFFF)
+        if(p_attr->len > 0xFFFF)
+        {
+            UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_IN_NEXT_LONG);
+            UINT32_TO_BE_STREAM (p_out, p_attr->len);
+        }
+        else
+
+#endif /* 0xFFFF - 0xFF */
+#if (SDP_MAX_ATTR_LEN > 0xFF)
+        if(p_attr->len > 0xFF)
+        {
+            UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_IN_NEXT_WORD);
+            UINT16_TO_BE_STREAM (p_out, p_attr->len);
+        }
+        else
+
+#endif /* 0xFF and less*/
+        {
+            UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_IN_NEXT_BYTE);
+            UINT8_TO_BE_STREAM (p_out, p_attr->len);
+        }
+
+        if (p_attr->value_ptr != NULL) {
+            ARRAY_TO_BE_STREAM (p_out, p_attr->value_ptr, (int)p_attr->len);
+        }
+
+        return (p_out);
+    }
+
+    /* Now, store the attribute value */
+    switch (p_attr->len)
+    {
+    case 1:
+        UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_ONE_BYTE);
+        break;
+    case 2:
+        UINT8_TO_BE_STREAM  (p_out, (p_attr->type << 3) | SIZE_TWO_BYTES);
+        break;
+    case 4:
+        UINT8_TO_BE_STREAM  (p_out, (p_attr->type << 3) | SIZE_FOUR_BYTES);
+        break;
+    case 8:
+        UINT8_TO_BE_STREAM  (p_out, (p_attr->type << 3) | SIZE_EIGHT_BYTES);
+        break;
+    case 16:
+        UINT8_TO_BE_STREAM  (p_out, (p_attr->type << 3) | SIZE_SIXTEEN_BYTES);
+        break;
+    default:
+        UINT8_TO_BE_STREAM (p_out, (p_attr->type << 3) | SIZE_IN_NEXT_BYTE);
+        UINT8_TO_BE_STREAM (p_out, p_attr->len);
+        break;
+    }
+
+    if (p_attr->value_ptr != NULL) {
+        ARRAY_TO_BE_STREAM (p_out, p_attr->value_ptr, (int)p_attr->len);
+    }
+
+    return (p_out);
+}
+
+
+/*******************************************************************************
+**
+** Function         sdpu_build_n_send_error
+**
+** Description      This function builds and sends an error packet.
+**
+** Returns          void
+**
+*******************************************************************************/
+void sdpu_build_n_send_error (tCONN_CB *p_ccb, uint16_t trans_num, uint16_t error_code, char *p_error_text)
+{
+    uint8_t         *p_rsp, *p_rsp_start, *p_rsp_param_len;
+    uint16_t        rsp_param_len;
+    BT_HDR          *p_buf = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
+
+
+    SDP_TRACE_WARNING ("SDP - sdpu_build_n_send_error  code: 0x%x  CID: 0x%x",
+                        error_code, p_ccb->connection_id);
+
+    /* Send the packet to L2CAP */
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_rsp = p_rsp_start = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+    UINT8_TO_BE_STREAM(p_rsp, SDP_PDU_ERROR_RESPONSE);
+    UINT16_TO_BE_STREAM(p_rsp, trans_num);
+
+    /* Skip the parameter length, we need to add it at the end */
+    p_rsp_param_len = p_rsp;
+    p_rsp += 2;
+
+    UINT16_TO_BE_STREAM  (p_rsp, error_code);
+
+    /* Unplugfest example traces do not have any error text */
+    if (p_error_text)
+        ARRAY_TO_BE_STREAM(p_rsp, p_error_text, (int)strlen(p_error_text));
+
+    /* Go back and put the parameter length into the buffer */
+    rsp_param_len = p_rsp - p_rsp_param_len - 2;
+    UINT16_TO_BE_STREAM(p_rsp_param_len, rsp_param_len);
+
+    /* Set the length of the SDP data in the buffer */
+    p_buf->len = p_rsp - p_rsp_start;
+
+    /* Send the buffer through L2CAP */
+    L2CA_DataWrite(p_ccb->connection_id, p_buf);
+}
+
+
+
+/*******************************************************************************
+**
+** Function         sdpu_extract_uid_seq
+**
+** Description      This function extracts a UUID sequence from the passed input
+**                  buffer, and puts it into the passed output list.
+**
+** Returns          Pointer to next byte in the input buffer after the sequence.
+**
+*******************************************************************************/
+uint8_t *sdpu_extract_uid_seq (uint8_t *p, uint16_t param_len, tSDP_UUID_SEQ *p_seq)
+{
+    uint8_t *p_seq_end;
+    uint8_t descr, type, size;
+    uint32_t seq_len, uuid_len;
+
+    /* Assume none found */
+    p_seq->num_uids = 0;
+
+    /* A UID sequence is composed of a bunch of UIDs. */
+
+    BE_STREAM_TO_UINT8 (descr, p);
+    type = descr >> 3;
+    size = descr & 7;
+
+    if (type != DATA_ELE_SEQ_DESC_TYPE)
+        return (NULL);
+
+    switch (size)
+    {
+    case SIZE_TWO_BYTES:
+        seq_len = 2;
+        break;
+    case SIZE_FOUR_BYTES:
+        seq_len = 4;
+        break;
+    case SIZE_SIXTEEN_BYTES:
+        seq_len = 16;
+        break;
+    case SIZE_IN_NEXT_BYTE:
+        BE_STREAM_TO_UINT8 (seq_len, p);
+        break;
+    case SIZE_IN_NEXT_WORD:
+        BE_STREAM_TO_UINT16 (seq_len, p);
+        break;
+    case SIZE_IN_NEXT_LONG:
+        BE_STREAM_TO_UINT32 (seq_len, p);
+        break;
+    default:
+        return (NULL);
+    }
+
+    if (seq_len >= param_len)
+        return (NULL);
+
+    p_seq_end = p + seq_len;
+
+    /* Loop through, extracting the UIDs */
+    for ( ; p < p_seq_end ; )
+    {
+        BE_STREAM_TO_UINT8 (descr, p);
+        type = descr >> 3;
+        size = descr & 7;
+
+        if (type != UUID_DESC_TYPE)
+            return (NULL);
+
+        switch (size)
+        {
+        case SIZE_TWO_BYTES:
+            uuid_len = 2;
+            break;
+        case SIZE_FOUR_BYTES:
+            uuid_len = 4;
+            break;
+        case SIZE_SIXTEEN_BYTES:
+            uuid_len = 16;
+            break;
+        case SIZE_IN_NEXT_BYTE:
+            BE_STREAM_TO_UINT8 (uuid_len, p);
+            break;
+        case SIZE_IN_NEXT_WORD:
+            BE_STREAM_TO_UINT16 (uuid_len, p);
+            break;
+        case SIZE_IN_NEXT_LONG:
+            BE_STREAM_TO_UINT32 (uuid_len, p);
+            break;
+        default:
+            return (NULL);
+        }
+
+        /* If UUID length is valid, copy it across */
+        if ((uuid_len == 2) || (uuid_len == 4) || (uuid_len == 16))
+        {
+            p_seq->uuid_entry[p_seq->num_uids].len = (uint16_t) uuid_len;
+            BE_STREAM_TO_ARRAY (p, p_seq->uuid_entry[p_seq->num_uids].value, (int)uuid_len);
+            p_seq->num_uids++;
+        }
+        else
+            return (NULL);
+
+        /* We can only do so many */
+        if (p_seq->num_uids >= MAX_UUIDS_PER_SEQ)
+            return (NULL);
+    }
+
+    if (p != p_seq_end)
+        return (NULL);
+
+    return (p);
+}
+
+
+
+/*******************************************************************************
+**
+** Function         sdpu_extract_attr_seq
+**
+** Description      This function extracts an attribute sequence from the passed
+**                  input buffer, and puts it into the passed output list.
+**
+** Returns          Pointer to next byte in the input buffer after the sequence.
+**
+*******************************************************************************/
+uint8_t *sdpu_extract_attr_seq (uint8_t *p, uint16_t param_len, tSDP_ATTR_SEQ *p_seq)
+{
+    uint8_t *p_end_list;
+    uint8_t descr, type, size;
+    uint32_t list_len, attr_len;
+
+    /* Assume none found */
+    p_seq->num_attr = 0;
+
+    /* Get attribute sequence info */
+    BE_STREAM_TO_UINT8 (descr, p);
+    type = descr >> 3;
+    size = descr & 7;
+
+    if (type != DATA_ELE_SEQ_DESC_TYPE)
+        return (p);
+
+    switch (size)
+    {
+    case SIZE_IN_NEXT_BYTE:
+        BE_STREAM_TO_UINT8 (list_len, p);
+        break;
+
+    case SIZE_IN_NEXT_WORD:
+        BE_STREAM_TO_UINT16 (list_len, p);
+        break;
+
+    case SIZE_IN_NEXT_LONG:
+        BE_STREAM_TO_UINT32 (list_len, p);
+        break;
+
+    default:
+        return (p);
+    }
+
+    if (list_len > param_len)
+        return (p);
+
+    p_end_list = p + list_len;
+
+    /* Loop through, extracting the attribute IDs */
+    for ( ; p < p_end_list ; )
+    {
+        BE_STREAM_TO_UINT8 (descr, p);
+        type = descr >> 3;
+        size = descr & 7;
+
+        if (type != UINT_DESC_TYPE)
+            return (p);
+
+        switch (size)
+        {
+        case SIZE_TWO_BYTES:
+            attr_len = 2;
+            break;
+        case SIZE_FOUR_BYTES:
+            attr_len = 4;
+            break;
+        case SIZE_IN_NEXT_BYTE:
+            BE_STREAM_TO_UINT8 (attr_len, p);
+            break;
+        case SIZE_IN_NEXT_WORD:
+            BE_STREAM_TO_UINT16 (attr_len, p);
+            break;
+        case SIZE_IN_NEXT_LONG:
+            BE_STREAM_TO_UINT32 (attr_len, p);
+            break;
+        default:
+            return (NULL);
+            break;
+        }
+
+        /* Attribute length must be 2-bytes or 4-bytes for a paired entry. */
+        if (attr_len == 2)
+        {
+            BE_STREAM_TO_UINT16 (p_seq->attr_entry[p_seq->num_attr].start, p);
+            p_seq->attr_entry[p_seq->num_attr].end = p_seq->attr_entry[p_seq->num_attr].start;
+        }
+        else if (attr_len == 4)
+        {
+            BE_STREAM_TO_UINT16 (p_seq->attr_entry[p_seq->num_attr].start, p);
+            BE_STREAM_TO_UINT16 (p_seq->attr_entry[p_seq->num_attr].end, p);
+        }
+        else
+            return (NULL);
+
+        /* We can only do so many */
+        if (++p_seq->num_attr >= MAX_ATTR_PER_SEQ)
+            return (NULL);
+    }
+
+    return (p);
+}
+
+
+/*******************************************************************************
+**
+** Function         sdpu_get_len_from_type
+**
+** Description      This function gets the length
+**
+** Returns          void
+**
+*******************************************************************************/
+uint8_t *sdpu_get_len_from_type (uint8_t *p, uint8_t type, uint32_t *p_len)
+{
+    uint8_t u8;
+    uint16_t u16;
+    uint32_t u32;
+
+    switch (type & 7)
+    {
+    case SIZE_ONE_BYTE:
+        *p_len = 1;
+        break;
+    case SIZE_TWO_BYTES:
+        *p_len = 2;
+        break;
+    case SIZE_FOUR_BYTES:
+        *p_len = 4;
+        break;
+    case SIZE_EIGHT_BYTES:
+        *p_len = 8;
+        break;
+    case SIZE_SIXTEEN_BYTES:
+        *p_len = 16;
+        break;
+    case SIZE_IN_NEXT_BYTE:
+        BE_STREAM_TO_UINT8 (u8, p);
+        *p_len = u8;
+        break;
+    case SIZE_IN_NEXT_WORD:
+        BE_STREAM_TO_UINT16 (u16, p);
+        *p_len = u16;
+        break;
+    case SIZE_IN_NEXT_LONG:
+        BE_STREAM_TO_UINT32 (u32, p);
+        *p_len = (uint16_t) u32;
+        break;
+    }
+
+    return (p);
+}
+
+
+/*******************************************************************************
+**
+** Function         sdpu_is_base_uuid
+**
+** Description      This function checks a 128-bit UUID with the base to see if
+**                  it matches. Only the last 12 bytes are compared.
+**
+** Returns          true if matched, else false
+**
+*******************************************************************************/
+bool    sdpu_is_base_uuid (uint8_t *p_uuid)
+{
+    uint16_t  xx;
+
+    for (xx = 4; xx < MAX_UUID_SIZE; xx++)
+        if (p_uuid[xx] != sdp_base_uuid[xx])
+            return (false);
+
+    /* If here, matched */
+    return (true);
+}
+
+
+/*******************************************************************************
+**
+** Function         sdpu_compare_uuid_arrays
+**
+** Description      This function compares 2 BE UUIDs. If needed, they are expanded
+**                  to 128-bit UUIDs, then compared.
+**
+** NOTE             it is assumed that the arrays are in Big Endian format
+**
+** Returns          true if matched, else false
+**
+*******************************************************************************/
+bool    sdpu_compare_uuid_arrays (uint8_t *p_uuid1, uint32_t len1, uint8_t *p_uuid2, uint16_t len2)
+{
+    uint8_t     nu1[MAX_UUID_SIZE];
+    uint8_t     nu2[MAX_UUID_SIZE];
+
+    if( ((len1 != 2) && (len1 != 4) && (len1 != 16)) ||
+        ((len2 != 2) && (len2 != 4) && (len2 != 16)) )
+    {
+        SDP_TRACE_ERROR("%s: invalid length", __func__);
+        return false;
+    }
+
+    /* If lengths match, do a straight compare */
+    if (len1 == len2)
+    {
+        if (len1 == 2)
+            return ((p_uuid1[0] == p_uuid2[0]) && (p_uuid1[1] == p_uuid2[1]));
+        if (len1 == 4)
+            return (  (p_uuid1[0] == p_uuid2[0]) && (p_uuid1[1] == p_uuid2[1])
+                   && (p_uuid1[2] == p_uuid2[2]) && (p_uuid1[3] == p_uuid2[3]) );
+        else
+            return (memcmp (p_uuid1, p_uuid2, (size_t)len1) == 0);
+    }
+    else if (len1 > len2)
+    {
+        /* If the len1 was 4-byte, (so len2 is 2-byte), compare on the fly */
+        if (len1 == 4)
+        {
+            return ( (p_uuid1[0] == 0) && (p_uuid1[1] == 0)
+                  && (p_uuid1[2] == p_uuid2[0]) && (p_uuid1[3] == p_uuid2[1]) );
+        }
+        else
+        {
+            /* Normalize UUIDs to 16-byte form, then compare. Len1 must be 16 */
+            memcpy (nu1, p_uuid1,       MAX_UUID_SIZE);
+            memcpy (nu2, sdp_base_uuid, MAX_UUID_SIZE);
+
+            if (len2 == 4)
+                memcpy (nu2, p_uuid2, len2);
+            else if (len2 == 2)
+                memcpy (nu2 + 2, p_uuid2, len2);
+
+            return (memcmp (nu1, nu2, MAX_UUID_SIZE) == 0);
+        }
+    }
+    else
+    {
+        /* len2 is greater than len1 */
+        /* If the len2 was 4-byte, (so len1 is 2-byte), compare on the fly */
+        if (len2 == 4)
+        {
+            return ( (p_uuid2[0] == 0) && (p_uuid2[1] == 0)
+                  && (p_uuid2[2] == p_uuid1[0]) && (p_uuid2[3] == p_uuid1[1]) );
+        }
+        else
+        {
+            /* Normalize UUIDs to 16-byte form, then compare. Len1 must be 16 */
+            memcpy (nu2, p_uuid2,       MAX_UUID_SIZE);
+            memcpy (nu1, sdp_base_uuid, MAX_UUID_SIZE);
+
+            if (len1 == 4)
+                memcpy (nu1, p_uuid1, (size_t)len1);
+            else if (len1 == 2)
+                memcpy (nu1 + 2, p_uuid1, (size_t)len1);
+
+            return (memcmp (nu1, nu2, MAX_UUID_SIZE) == 0);
+        }
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         sdpu_compare_bt_uuids
+**
+** Description      This function compares 2 BT UUID structures.
+**
+** NOTE             it is assumed that BT UUID structures are compressed to the
+**                  smallest possible UUIDs (by removing the base SDP UUID)
+**
+** Returns          true if matched, else false
+**
+*******************************************************************************/
+bool    sdpu_compare_bt_uuids (tBT_UUID *p_uuid1, tBT_UUID *p_uuid2)
+{
+    /* Lengths must match for BT UUIDs to match */
+    if (p_uuid1->len == p_uuid2->len)
+    {
+        if (p_uuid1->len == 2)
+            return (p_uuid1->uu.uuid16 == p_uuid2->uu.uuid16);
+        else if (p_uuid1->len == 4)
+            return (p_uuid1->uu.uuid32 == p_uuid2->uu.uuid32);
+        else if (!memcmp (p_uuid1->uu.uuid128, p_uuid2->uu.uuid128, 16))
+            return (true);
+    }
+
+    return (false);
+}
+
+
+/*******************************************************************************
+**
+** Function         sdpu_compare_uuid_with_attr
+**
+** Description      This function compares a BT UUID structure with the UUID in an
+**                  SDP attribute record. If needed, they are expanded to 128-bit
+**                  UUIDs, then compared.
+**
+** NOTE           - it is assumed that BT UUID structures are compressed to the
+**                  smallest possible UUIDs (by removing the base SDP UUID).
+**                - it is also assumed that the discovery atribute is compressed
+**                  to the smallest possible
+**
+** Returns          true if matched, else false
+**
+*******************************************************************************/
+bool    sdpu_compare_uuid_with_attr (tBT_UUID *p_btuuid, tSDP_DISC_ATTR *p_attr)
+{
+    uint16_t    attr_len = SDP_DISC_ATTR_LEN (p_attr->attr_len_type);
+
+    /* Since both UUIDs are compressed, lengths must match  */
+    if (p_btuuid->len != attr_len)
+        return (false);
+
+    if (p_btuuid->len == 2)
+        return (bool   )(p_btuuid->uu.uuid16 == p_attr->attr_value.v.u16);
+    else if (p_btuuid->len == 4)
+        return (bool   )(p_btuuid->uu.uuid32 == p_attr->attr_value.v.u32);
+    /* coverity[overrun-buffer-arg] */
+    /*
+       Event overrun-buffer-arg: Overrun of static array "&p_attr->attr_value.v.array" of size 4 bytes by passing it to a function which indexes it with argument "16U" at byte position 15
+       false-POSITIVE error from Coverity test tool. Please do NOT remove following comment.
+       False-positive: SDP uses scratch buffer to hold the attribute value.
+       The actual size of tSDP_DISC_ATVAL does not matter.
+       If the array size in tSDP_DISC_ATVAL is increase, we would increase the system RAM usage unnecessarily
+    */
+    else if (!memcmp (p_btuuid->uu.uuid128,(void*) p_attr->attr_value.v.array, MAX_UUID_SIZE))
+        return (true);
+
+    return (false);
+}
+
+/*******************************************************************************
+**
+** Function         sdpu_sort_attr_list
+**
+** Description      sorts a list of attributes in numeric order from lowest to
+**                  highest to conform to SDP specification
+**
+** Returns          void
+**
+*******************************************************************************/
+void sdpu_sort_attr_list( uint16_t num_attr, tSDP_DISCOVERY_DB *p_db )
+{
+    uint16_t i;
+    uint16_t x;
+
+    /* Done if no attributes to sort */
+    if (num_attr <= 1)
+    {
+        return;
+    }
+    else if (num_attr > SDP_MAX_ATTR_FILTERS)
+    {
+        num_attr = SDP_MAX_ATTR_FILTERS;
+    }
+
+    num_attr--; /* for the for-loop */
+    for( i = 0; i < num_attr; )
+    {
+        if( p_db->attr_filters[i] > p_db->attr_filters[i+1] )
+        {
+            /* swap the attribute IDs and start from the beginning */
+            x = p_db->attr_filters[i];
+            p_db->attr_filters[i] = p_db->attr_filters[i+1];
+            p_db->attr_filters[i+1] = x;
+
+            i = 0;
+        }
+        else
+            i++;
+    }
+}
+
+
+/*******************************************************************************
+**
+** Function         sdpu_get_list_len
+**
+** Description      gets the total list length in the sdp database for a given
+**                  uid sequence and attr sequence
+**
+** Returns          void
+**
+*******************************************************************************/
+uint16_t sdpu_get_list_len(tSDP_UUID_SEQ *uid_seq, tSDP_ATTR_SEQ *attr_seq)
+{
+    tSDP_RECORD    *p_rec;
+    uint16_t len = 0;
+    uint16_t len1;
+
+    for (p_rec = sdp_db_service_search (NULL, uid_seq); p_rec; p_rec = sdp_db_service_search (p_rec, uid_seq))
+    {
+        len += 3;
+
+        len1 = sdpu_get_attrib_seq_len(p_rec, attr_seq );
+
+        if (len1 != 0)
+            len += len1;
+        else
+            len -= 3;
+    }
+    return len;
+}
+
+/*******************************************************************************
+**
+** Function         sdpu_get_attrib_seq_len
+**
+** Description      gets the length of the specific attributes in a given
+**                  sdp record
+**
+** Returns          void
+**
+*******************************************************************************/
+uint16_t sdpu_get_attrib_seq_len(tSDP_RECORD *p_rec, tSDP_ATTR_SEQ *attr_seq)
+{
+    tSDP_ATTRIBUTE *p_attr;
+    uint16_t len1 = 0;
+    uint16_t xx;
+    bool    is_range = false;
+    uint16_t start_id=0, end_id=0;
+
+    for (xx = 0; xx < attr_seq->num_attr; xx++)
+    {
+        if (is_range == false)
+        {
+            start_id = attr_seq->attr_entry[xx].start;
+            end_id = attr_seq->attr_entry[xx].end;
+        }
+        p_attr = sdp_db_find_attr_in_rec (p_rec,
+                                          start_id,
+                                          end_id);
+        if (p_attr)
+        {
+            len1 += sdpu_get_attrib_entry_len (p_attr);
+
+            /* If doing a range, stick with this one till no more attributes found */
+            if (start_id != end_id)
+            {
+                /* Update for next time through */
+                start_id = p_attr->id + 1;
+                xx--;
+                is_range = true;
+            }
+            else
+                is_range = false;
+        }
+        else
+            is_range = false;
+    }
+    return len1;
+}
+
+/*******************************************************************************
+**
+** Function         sdpu_get_attrib_entry_len
+**
+** Description      gets the length of a specific attribute
+**
+** Returns          void
+**
+*******************************************************************************/
+uint16_t sdpu_get_attrib_entry_len(tSDP_ATTRIBUTE *p_attr)
+{
+    uint16_t len = 3;
+
+    /* the attribute is in the db record.
+     * assuming the attribute len is less than SDP_MAX_ATTR_LEN */
+    switch(p_attr->type)
+    {
+    case TEXT_STR_DESC_TYPE:    /* 4 */
+    case DATA_ELE_SEQ_DESC_TYPE:/* 6 */
+    case DATA_ELE_ALT_DESC_TYPE:/* 7 */
+    case URL_DESC_TYPE:         /* 8 */
+#if (SDP_MAX_ATTR_LEN > 0xFFFF)
+        if(p_attr->len > 0xFFFF)
+        {
+            len += 5;
+        }
+        else
+
+#endif/* 0xFFFF - 0xFF */
+#if (SDP_MAX_ATTR_LEN > 0xFF)
+        if(p_attr->len > 0xFF)
+        {
+            len += 3;
+        }
+        else
+
+#endif /* 0xFF and less*/
+        {
+            len += 2;
+        }
+        len += p_attr->len;
+        return len;
+	}
+
+    /* Now, the attribute value */
+    switch (p_attr->len)
+    {
+    case 1:
+    case 2:
+    case 4:
+    case 8:
+    case 16:
+        len += 1;
+        break;
+    default:
+        len += 2;
+        break;
+    }
+
+    len += p_attr->len;
+    return len;
+}
+
+
+/*******************************************************************************
+**
+** Function         sdpu_build_partial_attrib_entry
+**
+** Description      This function fills a buffer with partial attribute. It is
+**                  assumed that the maximum size of any attribute is 256 bytes.
+**
+**                  p_out: output buffer
+**                  p_attr: attribute to be copied partially into p_out
+**                  rem_len: num bytes to copy into p_out
+**                  offset: current start offset within the attr that needs to be copied
+**
+** Returns          Pointer to next byte in the output buffer.
+**                  offset is also updated
+**
+*******************************************************************************/
+uint8_t *sdpu_build_partial_attrib_entry (uint8_t *p_out, tSDP_ATTRIBUTE *p_attr, uint16_t len, uint16_t *offset)
+{
+    uint8_t *p_attr_buff = (uint8_t *)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN);
+    sdpu_build_attrib_entry(p_attr_buff, p_attr);
+
+    uint16_t attr_len = sdpu_get_attrib_entry_len(p_attr);
+
+    if (len > SDP_MAX_ATTR_LEN)
+    {
+        SDP_TRACE_ERROR("%s len %d exceeds SDP_MAX_ATTR_LEN", __func__, len);
+        len = SDP_MAX_ATTR_LEN;
+    }
+
+    size_t len_to_copy = ((attr_len - *offset) < len) ? (attr_len - *offset) : len;
+    memcpy(p_out, &p_attr_buff[*offset], len_to_copy);
+
+    p_out = &p_out[len_to_copy];
+    *offset += len_to_copy;
+
+    osi_free(p_attr_buff);
+    return p_out;
+}
+
+/*******************************************************************************
+**
+** Function         sdpu_uuid16_to_uuid128
+**
+** Description      This function converts UUID-16 to UUID-128 by including the base UUID
+**
+**                  uuid16: 2-byte UUID
+**                  p_uuid128: Expanded 128-bit UUID
+**
+** Returns          None
+**
+*******************************************************************************/
+void sdpu_uuid16_to_uuid128(uint16_t uuid16, uint8_t* p_uuid128)
+{
+    uint16_t uuid16_bo;
+    memset(p_uuid128, 0, 16);
+
+    memcpy(p_uuid128, sdp_base_uuid, MAX_UUID_SIZE);
+    uuid16_bo = ntohs(uuid16);
+    memcpy(p_uuid128+ 2, &uuid16_bo, sizeof(uint16_t));
+}
diff --git a/bt/stack/sdp/sdpint.h b/bt/stack/sdp/sdpint.h
new file mode 100644
index 0000000..4a9f726
--- /dev/null
+++ b/bt/stack/sdp/sdpint.h
@@ -0,0 +1,316 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 internally used SDP definitions
+ *
+ ******************************************************************************/
+
+#ifndef  SDP_INT_H
+#define  SDP_INT_H
+
+#include "bt_target.h"
+#include "osi/include/alarm.h"
+#include "sdp_api.h"
+#include "l2c_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Continuation length - we use a 2-byte offset */
+#define SDP_CONTINUATION_LEN        2
+#define SDP_MAX_CONTINUATION_LEN    16          /* As per the spec */
+
+/* Timeout definitions. */
+#define SDP_INACT_TIMEOUT_MS  (30 * 1000)    /* Inactivity timeout (in ms) */
+
+
+/* Define the Out-Flow default values. */
+#define  SDP_OFLOW_QOS_FLAG                 0
+#define  SDP_OFLOW_SERV_TYPE                0
+#define  SDP_OFLOW_TOKEN_RATE               0
+#define  SDP_OFLOW_TOKEN_BUCKET_SIZE        0
+#define  SDP_OFLOW_PEAK_BANDWIDTH           0
+#define  SDP_OFLOW_LATENCY                  0
+#define  SDP_OFLOW_DELAY_VARIATION          0
+
+/* Define the In-Flow default values. */
+#define  SDP_IFLOW_QOS_FLAG                 0
+#define  SDP_IFLOW_SERV_TYPE                0
+#define  SDP_IFLOW_TOKEN_RATE               0
+#define  SDP_IFLOW_TOKEN_BUCKET_SIZE        0
+#define  SDP_IFLOW_PEAK_BANDWIDTH           0
+#define  SDP_IFLOW_LATENCY                  0
+#define  SDP_IFLOW_DELAY_VARIATION          0
+
+#define  SDP_LINK_TO                        0
+
+/* Define the type of device notification. */
+/* (Inquiry Scan and Page Scan)            */
+#define  SDP_DEVICE_NOTI_LEN               (sizeof (BT_HDR) +           \
+                                            HCIC_PREAMBLE_SIZE +        \
+                                            HCIC_PARAM_SIZE_WRITE_PARAM1)
+
+#define  SDP_DEVICE_NOTI_FLAG               0x03
+
+/* Define the Protocol Data Unit (PDU) types.
+*/
+#define  SDP_PDU_ERROR_RESPONSE                 0x01
+#define  SDP_PDU_SERVICE_SEARCH_REQ             0x02
+#define  SDP_PDU_SERVICE_SEARCH_RSP             0x03
+#define  SDP_PDU_SERVICE_ATTR_REQ               0x04
+#define  SDP_PDU_SERVICE_ATTR_RSP               0x05
+#define  SDP_PDU_SERVICE_SEARCH_ATTR_REQ        0x06
+#define  SDP_PDU_SERVICE_SEARCH_ATTR_RSP        0x07
+
+/* Max UUIDs and attributes we support per sequence */
+#define     MAX_UUIDS_PER_SEQ       16
+#define     MAX_ATTR_PER_SEQ        16
+
+/* Max length we support for any attribute */
+#ifdef SDP_MAX_ATTR_LEN
+#define MAX_ATTR_LEN SDP_MAX_ATTR_LEN
+#else
+#define     MAX_ATTR_LEN            256
+#endif
+
+/* Internal UUID sequence representation */
+typedef struct
+{
+    uint16_t   len;
+    uint8_t    value[MAX_UUID_SIZE];
+} tUID_ENT;
+
+typedef struct
+{
+    uint16_t    num_uids;
+    tUID_ENT    uuid_entry[MAX_UUIDS_PER_SEQ];
+} tSDP_UUID_SEQ;
+
+
+/* Internal attribute sequence definitions */
+typedef struct
+{
+    uint16_t    start;
+    uint16_t    end;
+} tATT_ENT;
+
+typedef struct
+{
+    uint16_t    num_attr;
+    tATT_ENT    attr_entry[MAX_ATTR_PER_SEQ];
+} tSDP_ATTR_SEQ;
+
+
+/* Define the attribute element of the SDP database record */
+typedef struct
+{
+    uint32_t len;           /* Number of bytes in the entry */
+    uint8_t *value_ptr;    /* Points to attr_pad */
+    uint16_t id;
+    uint8_t type;
+} tSDP_ATTRIBUTE;
+
+/* An SDP record consists of a handle, and 1 or more attributes */
+typedef struct
+{
+    uint32_t            record_handle;
+    uint32_t            free_pad_ptr;
+    uint16_t            num_attributes;
+    tSDP_ATTRIBUTE      attribute[SDP_MAX_REC_ATTR];
+    uint8_t             attr_pad[SDP_MAX_PAD_LEN];
+} tSDP_RECORD;
+
+
+/* Define the SDP database */
+typedef struct
+{
+    uint32_t       di_primary_handle;       /* Device ID Primary record or NULL if nonexistent */
+    uint16_t       num_records;
+    tSDP_RECORD    record[SDP_MAX_RECORDS];
+} tSDP_DB;
+
+enum
+{
+    SDP_IS_SEARCH,
+    SDP_IS_ATTR_SEARCH,
+};
+
+#if (SDP_SERVER_ENABLED == TRUE)
+/* Continuation information for the SDP server response */
+typedef struct
+{
+    uint16_t          next_attr_index; /* attr index for next continuation response */
+    uint16_t          next_attr_start_id;  /* attr id to start with for the attr index in next cont. response */
+    tSDP_RECORD       *prev_sdp_rec; /* last sdp record that was completely sent in the response */
+    bool              last_attr_seq_desc_sent; /* whether attr seq length has been sent previously */
+    uint16_t          attr_offset; /* offset within the attr to keep trak of partial attributes in the responses */
+} tSDP_CONT_INFO;
+#endif  /* SDP_SERVER_ENABLED == TRUE */
+
+/* Define the SDP Connection Control Block */
+typedef struct
+{
+#define SDP_STATE_IDLE              0
+#define SDP_STATE_CONN_SETUP        1
+#define SDP_STATE_CFG_SETUP         2
+#define SDP_STATE_CONNECTED         3
+    uint8_t           con_state;
+
+#define SDP_FLAGS_IS_ORIG           0x01
+#define SDP_FLAGS_HIS_CFG_DONE      0x02
+#define SDP_FLAGS_MY_CFG_DONE       0x04
+    uint8_t           con_flags;
+
+    BD_ADDR           device_address;
+    alarm_t           *sdp_conn_timer;
+    uint16_t          rem_mtu_size;
+    uint16_t          connection_id;
+    uint16_t          list_len;                 /* length of the response in the GKI buffer */
+    uint8_t           *rsp_list;                /* pointer to GKI buffer holding response */
+
+#if (SDP_CLIENT_ENABLED == TRUE)
+    tSDP_DISCOVERY_DB *p_db;                    /* Database to save info into   */
+    tSDP_DISC_CMPL_CB *p_cb;                    /* Callback for discovery done  */
+    tSDP_DISC_CMPL_CB2 *p_cb2;                   /* Callback for discovery done piggy back with the user data */
+    void               *user_data;              /* piggy back user data */
+    uint32_t          handles[SDP_MAX_DISC_SERVER_RECS]; /* Discovered server record handles */
+    uint16_t          num_handles;              /* Number of server handles     */
+    uint16_t          cur_handle;               /* Current handle being processed */
+    uint16_t          transaction_id;
+    uint16_t          disconnect_reason;        /* Disconnect reason            */
+#if (SDP_BROWSE_PLUS == TRUE)
+    uint16_t          cur_uuid_idx;
+#endif
+
+#define SDP_DISC_WAIT_CONN          0
+#define SDP_DISC_WAIT_HANDLES       1
+#define SDP_DISC_WAIT_ATTR          2
+#define SDP_DISC_WAIT_SEARCH_ATTR   3
+#define SDP_DISC_WAIT_CANCEL        5
+
+    uint8_t           disc_state;
+    uint8_t           is_attr_search;
+#endif  /* SDP_CLIENT_ENABLED == TRUE */
+
+#if (SDP_SERVER_ENABLED == TRUE)
+    uint16_t          cont_offset;              /* Continuation state data in the server response */
+    tSDP_CONT_INFO    cont_info;                /* structure to hold continuation information for the server response */
+#endif  /* SDP_SERVER_ENABLED == TRUE */
+
+} tCONN_CB;
+
+
+/*  The main SDP control block */
+typedef struct
+{
+    tL2CAP_CFG_INFO   l2cap_my_cfg;             /* My L2CAP config     */
+    tCONN_CB          ccb[SDP_MAX_CONNECTIONS];
+#if (SDP_SERVER_ENABLED == TRUE)
+    tSDP_DB           server_db;
+#endif
+    tL2CAP_APPL_INFO  reg_info;                 /* L2CAP Registration info */
+    uint16_t          max_attr_list_size;       /* Max attribute list size to use   */
+    uint16_t          max_recs_per_search;      /* Max records we want per seaarch  */
+    uint8_t           trace_level;
+} tSDP_CB;
+
+/* Global SDP data */
+extern tSDP_CB  sdp_cb;
+
+/* Functions provided by sdp_main.cc */
+extern void     sdp_init (void);
+extern void     sdp_disconnect (tCONN_CB*p_ccb, uint16_t reason);
+
+#if (SDP_DEBUG == TRUE)
+extern uint16_t sdp_set_max_attr_list_size (uint16_t max_size);
+#endif
+
+/* Functions provided by sdp_conn.cc
+*/
+extern void sdp_conn_rcv_l2e_conn_ind (BT_HDR *p_msg);
+extern void sdp_conn_rcv_l2e_conn_cfm (BT_HDR *p_msg);
+extern void sdp_conn_rcv_l2e_disc (BT_HDR *p_msg);
+extern void sdp_conn_rcv_l2e_config_ind (BT_HDR *p_msg);
+extern void sdp_conn_rcv_l2e_config_cfm (BT_HDR *p_msg);
+extern void sdp_conn_rcv_l2e_conn_failed (BT_HDR *p_msg);
+extern void sdp_conn_rcv_l2e_connected (BT_HDR *p_msg);
+extern void sdp_conn_rcv_l2e_conn_failed (BT_HDR *p_msg);
+extern void sdp_conn_rcv_l2e_data (BT_HDR *p_msg);
+extern void sdp_conn_timer_timeout(void *data);
+
+extern tCONN_CB *sdp_conn_originate (uint8_t *p_bd_addr);
+
+/* Functions provided by sdp_utils.cc
+*/
+extern tCONN_CB *sdpu_find_ccb_by_cid (uint16_t cid);
+extern tCONN_CB *sdpu_find_ccb_by_db (tSDP_DISCOVERY_DB *p_db);
+extern tCONN_CB *sdpu_allocate_ccb (void);
+extern void      sdpu_release_ccb (tCONN_CB *p_ccb);
+
+extern uint8_t  *sdpu_build_attrib_seq (uint8_t *p_out, uint16_t *p_attr, uint16_t num_attrs);
+extern uint8_t  *sdpu_build_attrib_entry (uint8_t *p_out, tSDP_ATTRIBUTE *p_attr);
+extern void      sdpu_build_n_send_error (tCONN_CB *p_ccb, uint16_t trans_num, uint16_t error_code, char *p_error_text);
+
+extern uint8_t  *sdpu_extract_attr_seq (uint8_t *p, uint16_t param_len, tSDP_ATTR_SEQ *p_seq);
+extern uint8_t  *sdpu_extract_uid_seq (uint8_t *p, uint16_t param_len, tSDP_UUID_SEQ *p_seq);
+
+extern uint8_t  *sdpu_get_len_from_type (uint8_t *p, uint8_t type, uint32_t *p_len);
+extern bool     sdpu_is_base_uuid (uint8_t *p_uuid);
+extern bool     sdpu_compare_uuid_arrays (uint8_t *p_uuid1, uint32_t len1, uint8_t *p_uuid2, uint16_t len2);
+extern bool     sdpu_compare_bt_uuids (tBT_UUID *p_uuid1, tBT_UUID *p_uuid2);
+extern bool     sdpu_compare_uuid_with_attr (tBT_UUID *p_btuuid, tSDP_DISC_ATTR *p_attr);
+
+extern void     sdpu_sort_attr_list( uint16_t num_attr, tSDP_DISCOVERY_DB *p_db );
+extern uint16_t sdpu_get_list_len( tSDP_UUID_SEQ   *uid_seq, tSDP_ATTR_SEQ   *attr_seq );
+extern uint16_t sdpu_get_attrib_seq_len(tSDP_RECORD *p_rec, tSDP_ATTR_SEQ *attr_seq);
+extern uint16_t sdpu_get_attrib_entry_len(tSDP_ATTRIBUTE *p_attr);
+extern uint8_t *sdpu_build_partial_attrib_entry (uint8_t *p_out, tSDP_ATTRIBUTE *p_attr, uint16_t len, uint16_t *offset);
+
+/* Functions provided by sdp_db.cc
+*/
+extern tSDP_RECORD    *sdp_db_service_search (tSDP_RECORD *p_rec, tSDP_UUID_SEQ *p_seq);
+extern tSDP_RECORD    *sdp_db_find_record (uint32_t handle);
+extern tSDP_ATTRIBUTE *sdp_db_find_attr_in_rec (tSDP_RECORD *p_rec, uint16_t start_attr, uint16_t end_attr);
+
+
+/* Functions provided by sdp_server.cc
+*/
+#if (SDP_SERVER_ENABLED == TRUE)
+extern void     sdp_server_handle_client_req (tCONN_CB *p_ccb, BT_HDR *p_msg);
+#else
+#define sdp_server_handle_client_req(p_ccb, p_msg)
+#endif
+
+/* Functions provided by sdp_discovery.cc
+*/
+#if (SDP_CLIENT_ENABLED == TRUE)
+extern void sdp_disc_connected (tCONN_CB *p_ccb);
+extern void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg);
+#else
+#define sdp_disc_connected(p_ccb)
+#define sdp_disc_server_rsp(p_ccb, p_msg)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bt/stack/smp/aes.cc b/bt/stack/smp/aes.cc
new file mode 100644
index 0000000..1665fcc
--- /dev/null
+++ b/bt/stack/smp/aes.cc
@@ -0,0 +1,934 @@
+/*
+ ---------------------------------------------------------------------------
+ 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 <stdlib.h>
+
+/* add the target configuration to allow using internal data types and compilation options */
+#include "bt_target.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/bt/stack/smp/aes.h b/bt/stack/smp/aes.h
new file mode 100644
index 0000000..dcfde93
--- /dev/null
+++ b/bt/stack/smp/aes.h
@@ -0,0 +1,162 @@
+/*
+ ---------------------------------------------------------------------------
+ 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/bt/stack/smp/p_256_curvepara.cc b/bt/stack/smp/p_256_curvepara.cc
new file mode 100644
index 0000000..9d2c942
--- /dev/null
+++ b/bt/stack/smp/p_256_curvepara.cc
@@ -0,0 +1,80 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 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 <string.h>
+#include "p_256_ecc_pp.h"
+
+void p_256_init_curve(uint32_t keyLength)
+{
+    elliptic_curve_t *ec;
+
+    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;
+
+        memset(ec->omega, 0, KEY_LENGTH_DWORDS_P256);
+        memset(ec->a, 0, KEY_LENGTH_DWORDS_P256);
+
+        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;
+
+        //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;
+    }
+}
+
diff --git a/bt/stack/smp/p_256_ecc_pp.cc b/bt/stack/smp/p_256_ecc_pp.cc
new file mode 100644
index 0000000..0b12b6c
--- /dev/null
+++ b/bt/stack/smp/p_256_ecc_pp.cc
@@ -0,0 +1,262 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "p_256_ecc_pp.h"
+#include "p_256_multprecision.h"
+
+elliptic_curve_t curve;
+elliptic_curve_t curve_p256;
+
+static void p_256_init_point(Point *q)
+{
+    memset(q, 0, sizeof(Point));
+}
+
+static void p_256_copy_point(Point *q, Point *p)
+{
+    memcpy(q, p, sizeof(Point));
+}
+
+// q=2q
+static void ECC_Double(Point *q, Point *p, uint32_t keyLength)
+{
+    uint32_t t1[KEY_LENGTH_DWORDS_P256];
+    uint32_t t2[KEY_LENGTH_DWORDS_P256];
+    uint32_t t3[KEY_LENGTH_DWORDS_P256];
+    uint32_t *x1;
+    uint32_t *x3;
+    uint32_t *y1;
+    uint32_t *y3;
+    uint32_t *z1;
+    uint32_t *z3;
+
+    if (multiprecision_iszero(p->z, keyLength))
+    {
+        multiprecision_init(q->z, keyLength);
+        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, 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_mult_mod(z3, y1, z1, keyLength);  // z3=y1*z1
+    multiprecision_lshift_mod(z3, z3, keyLength);
+
+    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(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
+}
+
+// q=q+p,     zp must be 1
+static void ECC_Add(Point *r, Point *p, Point *q, uint32_t keyLength)
+{
+    uint32_t t1[KEY_LENGTH_DWORDS_P256];
+    uint32_t t2[KEY_LENGTH_DWORDS_P256];
+    uint32_t *x1;
+    uint32_t *x2;
+    uint32_t *x3;
+    uint32_t *y1;
+    uint32_t *y2;
+    uint32_t *y3;
+    uint32_t *z1;
+    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, keyLength))
+    {
+        p_256_copy_point(r, p);
+        return;
+    }
+
+    // if P=infinity, return q
+    if (multiprecision_iszero(z1, keyLength))
+    {
+        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_sub_mod(t1, t1, x1, keyLength);  // t1=t1-x1
+    multiprecision_sub_mod(t2, t2, y1, keyLength);  // t2=t2-y1
+
+    if (multiprecision_iszero(t1, keyLength))
+    {
+        if (multiprecision_iszero(t2, keyLength))
+        {
+            ECC_Double(r, q, keyLength) ;
+            return;
+        }
+        else
+        {
+            multiprecision_init(z3, keyLength);
+            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);
+}
+
+// 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)
+{
+    uint32_t sign;
+    int i=0;
+    int j;
+    uint32_t var;
+
+    while ((var = multiprecision_most_signbits(k, keyLength))>=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, keyLength);
+        naf[i / 4] |= (sign) << ((i % 4) * 2);
+        i++;
+    }
+
+    *NumNAF=i;
+}
+
+// Binary Non-Adjacent Form for point multiplication
+void ECC_PointMult_Bin_NAF(Point *q, Point *p, uint32_t *n, uint32_t keyLength)
+{
+    uint32_t sign;
+    uint8_t naf[256 / 4 +1];
+    uint32_t NumNaf;
+    Point minus_p;
+    Point r;
+    uint32_t *modp;
+
+    if (keyLength == KEY_LENGTH_DWORDS_P256)
+    {
+        modp = curve_p256.p;
+    }
+    else
+    {
+        modp = curve.p;
+    }
+
+    p_256_init_point(&r);
+    multiprecision_init(p->z, keyLength);
+    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_init(minus_p.z, keyLength);
+    minus_p.z[0]=1;
+
+    // NAF
+    memset(naf, 0, sizeof(naf));
+    ECC_NAF(naf, &NumNaf, n, keyLength);
+
+    for (int i = NumNaf - 1; i >= 0; i--)
+    {
+        p_256_copy_point(&r, q);
+        ECC_Double(q, &r, keyLength);
+        sign = (naf[i / 4] >> ((i % 4) * 2)) & 0x03;
+
+        if (sign == 1)
+        {
+            p_256_copy_point(&r, q);
+            ECC_Add(q, &r, p, keyLength);
+        }
+        else if (sign == 3)
+        {
+            p_256_copy_point(&r, q);
+            ECC_Add(q, &r, &minus_p, keyLength);
+        }
+    }
+
+    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);
+}
+
+
diff --git a/bt/stack/smp/p_256_ecc_pp.h b/bt/stack/smp/p_256_ecc_pp.h
new file mode 100644
index 0000000..ebbb479
--- /dev/null
+++ b/bt/stack/smp/p_256_ecc_pp.h
@@ -0,0 +1,63 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 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 "p_256_multprecision.h"
+
+typedef struct {
+    uint32_t x[KEY_LENGTH_DWORDS_P256];
+    uint32_t y[KEY_LENGTH_DWORDS_P256];
+    uint32_t z[KEY_LENGTH_DWORDS_P256];
+} Point;
+
+typedef struct {
+    // curve's coefficients
+    uint32_t a[KEY_LENGTH_DWORDS_P256];
+    uint32_t b[KEY_LENGTH_DWORDS_P256];
+
+    //whether a is -3
+    int a_minus3;
+
+    // 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;
+
+} elliptic_curve_t;
+
+extern elliptic_curve_t curve;
+extern elliptic_curve_t curve_p256;
+
+void ECC_PointMult_Bin_NAF(Point *q, Point *p, uint32_t *n, uint32_t keyLength);
+
+#define ECC_PointMult(q, p, n, keyLength)  ECC_PointMult_Bin_NAF(q, p, n, keyLength)
+
+void p_256_init_curve(uint32_t keyLength);
+
+
diff --git a/bt/stack/smp/p_256_multprecision.cc b/bt/stack/smp/p_256_multprecision.cc
new file mode 100644
index 0000000..9610ae3
--- /dev/null
+++ b/bt/stack/smp/p_256_multprecision.cc
@@ -0,0 +1,704 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 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 <string.h>
+#include "bt_target.h"
+#include "p_256_ecc_pp.h"
+#include "p_256_multprecision.h"
+
+void multiprecision_init(uint32_t *c, uint32_t keyLength)
+{
+    for (uint32_t i = 0; i < keyLength; 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];
+}
+
+int multiprecision_compare(uint32_t *a, uint32_t *b, uint32_t keyLength)
+{
+    for (int i = keyLength - 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++)
+        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(uint32_t *a, uint32_t keyLength)
+{
+    int  i;
+    for (i = keyLength - 1; i >= 0; i--)
+        if (a[i])
+           break;
+    return (i + 1);
+}
+
+uint32_t multiprecision_most_signbits(uint32_t *a, uint32_t keyLength)
+{
+    int aMostSignDWORDs;
+
+    aMostSignDWORDs = multiprecision_most_signdwords(a, keyLength);
+    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 carrier;
+    uint32_t temp;
+
+    carrier=0;
+    for (uint32_t i = 0; i < keyLength; 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, uint32_t *a, uint32_t *b, uint32_t keyLength)
+{
+    uint32_t borrow;
+    uint32_t temp;
+
+    borrow=0;
+    for (uint32_t i=0; i < keyLength; 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, uint32_t * a, uint32_t keyLength)
+{
+    uint32_t carrier;
+    uint32_t *modp;
+
+    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);
+    if (carrier)
+    {
+        multiprecision_sub(c, c, modp, keyLength);
+    }
+    else if (multiprecision_compare(c, modp, keyLength)>=0)
+    {
+        multiprecision_sub(c, c, modp, keyLength);
+    }
+}
+
+// c=a>>1
+void multiprecision_rshift(uint32_t * c, uint32_t * a, uint32_t keyLength)
+{
+    int j;
+    uint32_t b = 1;
+
+    j = DWORD_BITS - b;
+
+    uint32_t carrier = 0;
+    uint32_t temp;
+    for (int i = keyLength-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, uint32_t *a, uint32_t *b, uint32_t keyLength)
+{
+    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);
+    }
+}
+
+// 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);
+}
+
+// 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)
+{
+    uint32_t carrier;
+    uint32_t *modp;
+
+    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);
+    if (carrier)
+    {
+        multiprecision_sub(c, c, modp, keyLength);
+    }
+    else if (multiprecision_compare(c, modp, keyLength) >= 0)
+    {
+        multiprecision_sub(c, c, modp, keyLength);
+    }
+}
+
+// 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)
+{
+    uint32_t borrow;
+    uint32_t *modp;
+
+    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);
+}
+
+// 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)
+{
+    int j;
+    uint32_t b = 1;
+    j = DWORD_BITS - b;
+
+    uint32_t carrier = 0;
+    uint32_t temp;
+
+    for (uint32_t i = 0; i < keyLength; 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, uint32_t *a, uint32_t *b, uint32_t keyLength)
+{
+    uint32_t W;
+    uint32_t U;
+    uint32_t V;
+
+    U = V = W = 0;
+    multiprecision_init(c, keyLength);
+
+    //assume little endian right now
+    for (uint32_t i = 0; i < keyLength; i++)
+    {
+        U = 0;
+        for (uint32_t j = 0; j < keyLength; 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+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);
+    }
+}
+
+void multiprecision_fast_mod_P256(uint32_t *c, uint32_t *a)
+{
+    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;
+    uint32_t *modp = curve_p256.p;
+
+    // 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, KEY_LENGTH_DWORDS_P256);
+            U++;
+        }
+    }
+    else if (U)
+    {
+        while (U)
+        {
+            multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P256);
+            U--;
+        }
+    }
+
+    if (multiprecision_compare(c, modp, KEY_LENGTH_DWORDS_P256)>=0)
+        multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P256);
+
+}
+
+void multiprecision_inv_mod(uint32_t *aminus, uint32_t *u, uint32_t keyLength)
+{
+    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;
+
+    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);
+    A[0] = 1;
+
+    while (!multiprecision_iszero(u, keyLength))
+    {
+        while (!(u[0] & 0x01))  // u is even
+        {
+            multiprecision_rshift(u, u, keyLength);
+            if(!(A[0] & 0x01))  // A is even
+                multiprecision_rshift(A, A, keyLength);
+            else
+            {
+                A[keyLength]=multiprecision_add(A, A, modp, keyLength); // A =A+p
+                multiprecision_rshift(A, A, keyLength);
+                A[keyLength-1] |= (A[keyLength]<<31);
+            }
+        }
+
+        while (!(v[0] & 0x01))  // v is even
+        {
+            multiprecision_rshift(v, v, keyLength);
+            if (!(C[0] & 0x01))  // C is even
+            {
+                multiprecision_rshift(C, C, keyLength);
+            }
+            else
+            {
+                C[keyLength] = multiprecision_add(C, C, modp, keyLength); // C =C+p
+                multiprecision_rshift(C, C, keyLength);
+                C[keyLength-1] |= (C[keyLength] << 31);
+            }
+        }
+
+        if (multiprecision_compare(u, v, keyLength) >= 0)
+        {
+            multiprecision_sub(u, u, v, keyLength);
+            multiprecision_sub_mod(A, A, C, keyLength);
+        }
+        else
+        {
+            multiprecision_sub(v, v, u, keyLength);
+            multiprecision_sub_mod(C, C, A, keyLength);
+        }
+    }
+
+    if (multiprecision_compare(C, modp, keyLength) >= 0)
+        multiprecision_sub(aminus, C, modp, keyLength);
+    else
+        multiprecision_copy(aminus, C, keyLength);
+}
+
diff --git a/bt/stack/smp/p_256_multprecision.h b/bt/stack/smp/p_256_multprecision.h
new file mode 100644
index 0000000..ce87ef3
--- /dev/null
+++ b/bt/stack/smp/p_256_multprecision.h
@@ -0,0 +1,59 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 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 "bt_types.h"
+
+#define DWORD_BITS      32
+#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);
+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);
+void multiprecision_fast_mod(uint32_t *c, uint32_t *a);
+void multiprecision_fast_mod_P256(uint32_t *c, uint32_t *a);
+
+
diff --git a/bt/stack/smp/smp_act.cc b/bt/stack/smp/smp_act.cc
new file mode 100644
index 0000000..4a14555
--- /dev/null
+++ b/bt/stack/smp/smp_act.cc
@@ -0,0 +1,2191 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "device/include/interop.h"
+#include "include/bt_target.h"
+#include "stack/btm/btm_int.h"
+#include "stack/include/l2c_api.h"
+#include "stack/smp/smp_int.h"
+#include "utils/include/bt_utils.h"
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+#if (SMP_INCLUDED == TRUE)
+
+#define SMP_KEY_DIST_TYPE_MAX       4
+const tSMP_ACT smp_distribute_act [] =
+{
+    smp_generate_ltk,
+    smp_send_id_info,
+    smp_generate_csrk,
+    smp_set_derive_link_key
+};
+
+static bool lmp_version_below(BD_ADDR bda, uint8_t version)
+{
+    tACL_CONN *acl = btm_bda_to_acl(bda, BT_TRANSPORT_LE);
+    if (acl == NULL || acl->lmp_version == 0)
+    {
+        SMP_TRACE_WARNING("%s cannot retrieve LMP version...", __func__);
+        return false;
+    }
+    SMP_TRACE_WARNING("%s LMP version %d < %d", __func__, acl->lmp_version, version);
+    return acl->lmp_version < version;
+}
+
+static bool pts_test_send_authentication_complete_failure(tSMP_CB *p_cb)
+{
+    uint8_t reason = 0;
+
+    if (p_cb->cert_failure < 2 || p_cb->cert_failure > 6)
+        return false;
+
+    SMP_TRACE_ERROR("%s failure case = %d", __func__, p_cb->cert_failure);
+
+    switch (p_cb->cert_failure)
+    {
+        case 2:
+            reason = SMP_PAIR_AUTH_FAIL;
+            smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+            break;
+        case 3:
+            reason = SMP_PAIR_FAIL_UNKNOWN;
+            smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+            break;
+        case 4:
+            reason = SMP_PAIR_NOT_SUPPORT;
+            smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+            break;
+        case 5:
+            reason = SMP_PASSKEY_ENTRY_FAIL;
+            smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+            break;
+        case 6:
+            reason = SMP_REPEATED_ATTEMPTS;
+            smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+            break;
+    }
+
+    return true;;
+}
+
+/*******************************************************************************
+** Function         smp_update_key_mask
+** Description      This function updates the key mask for sending or receiving.
+*******************************************************************************/
+static void smp_update_key_mask (tSMP_CB *p_cb, uint8_t key_type, bool    recv)
+{
+    SMP_TRACE_DEBUG("%s before update role=%d recv=%d local_i_key = %02x, local_r_key = %02x",
+        __func__, p_cb->role, recv, p_cb->local_i_key, p_cb->local_r_key);
+
+    if (((p_cb->le_secure_connections_mode_is_used) ||
+        (p_cb->smp_over_br)) &&
+        ((key_type == SMP_SEC_KEY_TYPE_ENC) || (key_type == SMP_SEC_KEY_TYPE_LK)))
+    {
+        /* in LE SC mode LTK, CSRK and BR/EDR LK are derived locally instead of
+        ** being exchanged with the peer */
+        p_cb->local_i_key &= ~key_type;
+        p_cb->local_r_key &= ~key_type;
+    }
+    else
+    if (p_cb->role == HCI_ROLE_SLAVE)
+    {
+        if (recv)
+            p_cb->local_i_key &= ~key_type;
+        else
+            p_cb->local_r_key &= ~key_type;
+    }
+    else
+    {
+        if (recv)
+            p_cb->local_r_key &= ~key_type;
+        else
+            p_cb->local_i_key &= ~key_type;
+    }
+
+    SMP_TRACE_DEBUG("updated local_i_key = %02x, local_r_key = %02x", p_cb->local_i_key,
+                      p_cb->local_r_key);
+}
+
+/*******************************************************************************
+** Function     smp_send_app_cback
+** Description  notifies application about the events the application is interested in
+*******************************************************************************/
+void smp_send_app_cback(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    tSMP_EVT_DATA   cb_data;
+    tSMP_STATUS callback_rc;
+    SMP_TRACE_DEBUG("%s p_cb->cb_evt=%d", __func__, p_cb->cb_evt);
+    if (p_cb->p_callback && p_cb->cb_evt != 0)
+    {
+        switch (p_cb->cb_evt)
+        {
+            case SMP_IO_CAP_REQ_EVT:
+                cb_data.io_req.auth_req = p_cb->peer_auth_req;
+                cb_data.io_req.oob_data = SMP_OOB_NONE;
+                cb_data.io_req.io_cap = SMP_DEFAULT_IO_CAPS;
+                cb_data.io_req.max_key_size = SMP_MAX_ENC_KEY_SIZE;
+                cb_data.io_req.init_keys = p_cb->local_i_key ;
+                cb_data.io_req.resp_keys = p_cb->local_r_key ;
+                SMP_TRACE_WARNING ( "io_cap = %d",cb_data.io_req.io_cap);
+                break;
+
+            case SMP_NC_REQ_EVT:
+                cb_data.passkey = p_data->passkey;
+                break;
+            case SMP_SC_OOB_REQ_EVT:
+                cb_data.req_oob_type = p_data->req_oob_type;
+                break;
+            case SMP_SC_LOC_OOB_DATA_UP_EVT:
+                cb_data.loc_oob_data = p_cb->sc_oob_data.loc_oob_data;
+                break;
+
+            case SMP_BR_KEYS_REQ_EVT:
+                cb_data.io_req.auth_req = 0;
+                cb_data.io_req.oob_data = SMP_OOB_NONE;
+                cb_data.io_req.io_cap = 0;
+                cb_data.io_req.max_key_size = SMP_MAX_ENC_KEY_SIZE;
+                cb_data.io_req.init_keys = SMP_BR_SEC_DEFAULT_KEY;
+                cb_data.io_req.resp_keys = SMP_BR_SEC_DEFAULT_KEY;
+                break;
+
+            default:
+                break;
+        }
+
+        callback_rc = (*p_cb->p_callback)(p_cb->cb_evt, p_cb->pairing_bda, &cb_data);
+
+        SMP_TRACE_DEBUG("%s: callback_rc=%d  p_cb->cb_evt=%d", __func__, callback_rc, p_cb->cb_evt );
+
+        if (callback_rc == SMP_SUCCESS)
+        {
+            switch (p_cb->cb_evt)
+            {
+                case SMP_IO_CAP_REQ_EVT:
+                    p_cb->loc_auth_req   = cb_data.io_req.auth_req;
+                    p_cb->local_io_capability  = cb_data.io_req.io_cap;
+                    p_cb->loc_oob_flag = cb_data.io_req.oob_data;
+                    p_cb->loc_enc_size = cb_data.io_req.max_key_size;
+                    p_cb->local_i_key = cb_data.io_req.init_keys;
+                    p_cb->local_r_key = cb_data.io_req.resp_keys;
+
+                    if (!(p_cb->loc_auth_req & SMP_AUTH_BOND))
+                    {
+                        SMP_TRACE_WARNING ("Non bonding: No keys will be exchanged");
+                        p_cb->local_i_key = 0;
+                        p_cb->local_r_key = 0;
+                    }
+
+                    SMP_TRACE_WARNING ( "rcvd auth_req: 0x%02x, io_cap: %d \
+                        loc_oob_flag: %d loc_enc_size: %d,"
+                        "local_i_key: 0x%02x, local_r_key: 0x%02x",
+                        p_cb->loc_auth_req, p_cb->local_io_capability, p_cb->loc_oob_flag,
+                        p_cb->loc_enc_size, p_cb->local_i_key, p_cb->local_r_key);
+
+                    p_cb->secure_connections_only_mode_required =
+                        (btm_cb.security_mode == BTM_SEC_MODE_SC) ? true : false;
+
+                    if (p_cb->secure_connections_only_mode_required)
+                    {
+                        p_cb->loc_auth_req |= SMP_SC_SUPPORT_BIT;
+                    }
+
+                    if (!(p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT)
+                        || lmp_version_below(p_cb->pairing_bda, HCI_PROTO_VERSION_4_2)
+                        || interop_match_addr(INTEROP_DISABLE_LE_SECURE_CONNECTIONS,
+                            (const bt_bdaddr_t *)&p_cb->pairing_bda))
+                    {
+                        p_cb->loc_auth_req &= ~SMP_KP_SUPPORT_BIT;
+                        p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK;
+                        p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK;
+                    }
+
+                    SMP_TRACE_WARNING("set auth_req: 0x%02x, local_i_key: 0x%02x, local_r_key: 0x%02x",
+                        p_cb->loc_auth_req, p_cb->local_i_key, p_cb->local_r_key);
+
+                    smp_sm_event(p_cb, SMP_IO_RSP_EVT, NULL);
+                    break;
+
+                case SMP_BR_KEYS_REQ_EVT:
+                    p_cb->loc_enc_size = cb_data.io_req.max_key_size;
+                    p_cb->local_i_key = cb_data.io_req.init_keys;
+                    p_cb->local_r_key = cb_data.io_req.resp_keys;
+
+                    p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK;
+                    p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK;
+
+                    SMP_TRACE_WARNING ( "for SMP over BR max_key_size: 0x%02x,\
+                        local_i_key: 0x%02x, local_r_key: 0x%02x",
+                        p_cb->loc_enc_size, p_cb->local_i_key, p_cb->local_r_key);
+
+                    smp_br_state_machine_event(p_cb, SMP_BR_KEYS_RSP_EVT, NULL);
+                    break;
+            }
+        }
+    }
+
+    if (!p_cb->cb_evt && p_cb->discard_sec_req)
+    {
+        p_cb->discard_sec_req = false;
+        smp_sm_event(p_cb, SMP_DISCARD_SEC_REQ_EVT, NULL);
+    }
+
+    SMP_TRACE_DEBUG("%s return", __func__);
+}
+
+/*******************************************************************************
+** Function     smp_send_pair_fail
+** Description  pairing failure to peer device if needed.
+*******************************************************************************/
+void smp_send_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    p_cb->status = *(uint8_t *)p_data;
+    p_cb->failure = *(uint8_t *)p_data;
+
+    SMP_TRACE_DEBUG("%s status=%d failure=%d ", __func__, p_cb->status, p_cb->failure);
+
+    if (p_cb->status <= SMP_MAX_FAIL_RSN_PER_SPEC && p_cb->status != SMP_SUCCESS)
+    {
+        smp_send_cmd(SMP_OPCODE_PAIRING_FAILED, p_cb);
+        p_cb->wait_for_authorization_complete = true;
+    }
+}
+
+/*******************************************************************************
+** Function     smp_send_pair_req
+** Description  actions related to sending pairing request
+*******************************************************************************/
+void smp_send_pair_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_cb->pairing_bda);
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    /* erase all keys when master sends pairing req*/
+    if (p_dev_rec)
+        btm_sec_clear_ble_keys(p_dev_rec);
+    /* do not manipulate the key, let app decide,
+       leave out to BTM to mandate key distribution for bonding case */
+    smp_send_cmd(SMP_OPCODE_PAIRING_REQ, p_cb);
+}
+
+/*******************************************************************************
+** Function     smp_send_pair_rsp
+** Description  actions related to sending pairing response
+*******************************************************************************/
+void smp_send_pair_rsp(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    p_cb->local_i_key &= p_cb->peer_i_key;
+    p_cb->local_r_key &= p_cb->peer_r_key;
+
+    if (smp_send_cmd (SMP_OPCODE_PAIRING_RSP, p_cb))
+    {
+        if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB)
+            smp_use_oob_private_key(p_cb, NULL);
+        else
+            smp_decide_association_model(p_cb, NULL);
+    }
+}
+
+/*******************************************************************************
+** Function     smp_send_confirm
+** Description  send confirmation to the peer
+*******************************************************************************/
+void smp_send_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+    smp_send_cmd(SMP_OPCODE_CONFIRM, p_cb);
+}
+
+/*******************************************************************************
+** Function     smp_send_init
+** Description  process pairing initializer to slave device
+*******************************************************************************/
+void smp_send_init(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+    smp_send_cmd(SMP_OPCODE_INIT, p_cb);
+}
+
+/*******************************************************************************
+** Function     smp_send_rand
+** Description  send pairing random to the peer
+*******************************************************************************/
+void smp_send_rand(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+    smp_send_cmd(SMP_OPCODE_RAND, p_cb);
+}
+
+/*******************************************************************************
+** Function     smp_send_pair_public_key
+** Description  send pairing public key command to the peer
+*******************************************************************************/
+void smp_send_pair_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+    smp_send_cmd(SMP_OPCODE_PAIR_PUBLIC_KEY, p_cb);
+}
+
+/*******************************************************************************
+** Function     SMP_SEND_COMMITMENT
+** Description send commitment command to the peer
+*******************************************************************************/
+void smp_send_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+    smp_send_cmd(SMP_OPCODE_PAIR_COMMITM, p_cb);
+}
+
+/*******************************************************************************
+** Function     smp_send_dhkey_check
+** Description send DHKey Check command to the peer
+*******************************************************************************/
+void smp_send_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+    smp_send_cmd(SMP_OPCODE_PAIR_DHKEY_CHECK, p_cb);
+}
+
+/*******************************************************************************
+** Function     smp_send_keypress_notification
+** Description send Keypress Notification command to the peer
+*******************************************************************************/
+void smp_send_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    p_cb->local_keypress_notification = *(uint8_t *) p_data;
+    smp_send_cmd(SMP_OPCODE_PAIR_KEYPR_NOTIF, p_cb);
+}
+
+/*******************************************************************************
+** Function     smp_send_enc_info
+** Description  send encryption information command.
+*******************************************************************************/
+void smp_send_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    tBTM_LE_LENC_KEYS   le_key;
+
+    SMP_TRACE_DEBUG("%s p_cb->loc_enc_size = %d", __func__, p_cb->loc_enc_size);
+    smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, false);
+
+    smp_send_cmd(SMP_OPCODE_ENCRYPT_INFO, p_cb);
+    smp_send_cmd(SMP_OPCODE_MASTER_ID, p_cb);
+
+    /* save the DIV and key size information when acting as slave device */
+    memcpy(le_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
+    le_key.div =  p_cb->div;
+    le_key.key_size = p_cb->loc_enc_size;
+    le_key.sec_level = p_cb->sec_level;
+
+    if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND))
+        btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LENC,
+                            (tBTM_LE_KEY_VALUE *)&le_key, true);
+
+    SMP_TRACE_WARNING ("%s", __func__);
+
+    smp_key_distribution(p_cb, NULL);
+}
+
+/*******************************************************************************
+** Function     smp_send_id_info
+** Description  send ID information command.
+*******************************************************************************/
+void smp_send_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    tBTM_LE_KEY_VALUE   le_key;
+    SMP_TRACE_DEBUG("%s", __func__);
+    smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ID, false);
+
+    smp_send_cmd(SMP_OPCODE_IDENTITY_INFO, p_cb);
+    smp_send_cmd(SMP_OPCODE_ID_ADDR, p_cb);
+
+    if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND))
+        btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LID,
+                            &le_key, true);
+
+    SMP_TRACE_WARNING ("%s", __func__);
+    smp_key_distribution_by_transport(p_cb, NULL);
+}
+
+/*******************************************************************************
+** Function     smp_send_csrk_info
+** Description  send CSRK command.
+*******************************************************************************/
+void smp_send_csrk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    tBTM_LE_LCSRK_KEYS  key;
+    SMP_TRACE_DEBUG("%s", __func__);
+    smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_CSRK, false);
+
+    if (smp_send_cmd(SMP_OPCODE_SIGN_INFO, p_cb))
+    {
+        key.div = p_cb->div;
+        key.sec_level = p_cb->sec_level;
+        key.counter = 0; /* initialize the local counter */
+        memcpy (key.csrk, p_cb->csrk, BT_OCTET16_LEN);
+        btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LCSRK, (tBTM_LE_KEY_VALUE *)&key, true);
+    }
+
+    smp_key_distribution_by_transport(p_cb, NULL);
+}
+
+/*******************************************************************************
+** Function     smp_send_ltk_reply
+** Description  send LTK reply
+*******************************************************************************/
+void smp_send_ltk_reply(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+    /* send stk as LTK response */
+    btm_ble_ltk_request_reply(p_cb->pairing_bda, true, p_data->key.p_data);
+}
+
+/*******************************************************************************
+** Function     smp_proc_sec_req
+** Description  process security request.
+*******************************************************************************/
+void smp_proc_sec_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    tBTM_LE_AUTH_REQ auth_req = *(tBTM_LE_AUTH_REQ *)p_data;
+    tBTM_BLE_SEC_REQ_ACT sec_req_act;
+    uint8_t reason;
+
+    SMP_TRACE_DEBUG("%s auth_req=0x%x", __func__, auth_req);
+
+    p_cb->cb_evt = 0;
+
+    btm_ble_link_sec_check(p_cb->pairing_bda, auth_req,  &sec_req_act);
+
+    SMP_TRACE_DEBUG("%s sec_req_act=0x%x", __func__, sec_req_act);
+
+    switch (sec_req_act)
+    {
+        case  BTM_BLE_SEC_REQ_ACT_ENCRYPT:
+            SMP_TRACE_DEBUG("%s BTM_BLE_SEC_REQ_ACT_ENCRYPT", __func__);
+            smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL);
+            break;
+
+        case BTM_BLE_SEC_REQ_ACT_PAIR:
+            p_cb->secure_connections_only_mode_required =
+                    (btm_cb.security_mode == BTM_SEC_MODE_SC) ? true : false;
+
+            /* respond to non SC pairing request as failure in SC only mode */
+            if (p_cb->secure_connections_only_mode_required &&
+                (auth_req & SMP_SC_SUPPORT_BIT) == 0)
+            {
+                reason = SMP_PAIR_AUTH_FAIL;
+                smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+            }
+            else
+            {
+                /* initialize local i/r key to be default keys */
+                p_cb->peer_auth_req = auth_req;
+                p_cb->local_r_key = p_cb->local_i_key = SMP_SEC_DEFAULT_KEY ;
+                p_cb->cb_evt = SMP_SEC_REQUEST_EVT;
+            }
+            break;
+
+        case BTM_BLE_SEC_REQ_ACT_DISCARD:
+            p_cb->discard_sec_req = true;
+            break;
+
+        default:
+            /* do nothing */
+            break;
+    }
+}
+
+/*******************************************************************************
+** Function     smp_proc_sec_grant
+** Description  process security grant.
+*******************************************************************************/
+void smp_proc_sec_grant(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t res= *(uint8_t *)p_data;
+    SMP_TRACE_DEBUG("%s", __func__);
+    if (res != SMP_SUCCESS)
+    {
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, p_data);
+    }
+    else /*otherwise, start pairing */
+    {
+        /* send IO request callback */
+        p_cb->cb_evt = SMP_IO_CAP_REQ_EVT;
+    }
+}
+
+/*******************************************************************************
+** Function     smp_proc_pair_fail
+** Description  process pairing failure from peer device
+*******************************************************************************/
+void smp_proc_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+    p_cb->status = *(uint8_t *)p_data;
+
+    /* Cancel pending auth complete timer if set */
+    alarm_cancel(p_cb->delayed_auth_timer_ent);
+}
+
+/*******************************************************************************
+** Function     smp_proc_pair_cmd
+** Description  Process the SMP pairing request/response from peer device
+*******************************************************************************/
+void smp_proc_pair_cmd(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t *p = (uint8_t *)p_data;
+    uint8_t reason = SMP_ENC_KEY_SIZE;
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_cb->pairing_bda);
+
+    SMP_TRACE_DEBUG("%s", __func__);
+    /* erase all keys if it is slave proc pairing req*/
+    if (p_dev_rec && (p_cb->role == HCI_ROLE_SLAVE))
+        btm_sec_clear_ble_keys(p_dev_rec);
+
+    p_cb->flags |= SMP_PAIR_FLAG_ENC_AFTER_PAIR;
+
+    STREAM_TO_UINT8(p_cb->peer_io_caps, p);
+    STREAM_TO_UINT8(p_cb->peer_oob_flag, p);
+    STREAM_TO_UINT8(p_cb->peer_auth_req, p);
+    STREAM_TO_UINT8(p_cb->peer_enc_size, p);
+    STREAM_TO_UINT8(p_cb->peer_i_key, p);
+    STREAM_TO_UINT8(p_cb->peer_r_key, p);
+
+    if (smp_command_has_invalid_parameters(p_cb))
+    {
+        reason = SMP_INVALID_PARAMETERS;
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+        return;
+    }
+
+    // PTS Testing failure modes
+    if (pts_test_send_authentication_complete_failure(p_cb))
+        return;
+
+    if (p_cb->role == HCI_ROLE_SLAVE)
+    {
+        if (!(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD))
+        {
+            /* peer (master) started pairing sending Pairing Request */
+            p_cb->local_i_key = p_cb->peer_i_key;
+            p_cb->local_r_key = p_cb->peer_r_key;
+
+            p_cb->cb_evt = SMP_SEC_REQUEST_EVT;
+        }
+        else /* update local i/r key according to pairing request */
+        {
+            /* pairing started with this side (slave) sending Security Request */
+            p_cb->local_i_key &= p_cb->peer_i_key;
+            p_cb->local_r_key &= p_cb->peer_r_key;
+            p_cb->selected_association_model = smp_select_association_model(p_cb);
+
+            if (p_cb->secure_connections_only_mode_required &&
+                (!(p_cb->le_secure_connections_mode_is_used) ||
+               (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS)))
+            {
+                SMP_TRACE_ERROR("%s pairing failed - slave requires secure connection only mode",
+                    __func__);
+                reason = SMP_PAIR_AUTH_FAIL;
+                smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+                return;
+            }
+
+            if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB)
+            {
+                if (smp_request_oob_data(p_cb)) return;
+            }
+            else
+            {
+                smp_send_pair_rsp(p_cb, NULL);
+            }
+        }
+    }
+    else /* Master receives pairing response */
+    {
+        p_cb->selected_association_model = smp_select_association_model(p_cb);
+
+        if (p_cb->secure_connections_only_mode_required &&
+            (!(p_cb->le_secure_connections_mode_is_used) ||
+           (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS)))
+        {
+            SMP_TRACE_ERROR ("Master requires secure connection only mode \
+                but it can't be provided -> Master fails pairing");
+            reason = SMP_PAIR_AUTH_FAIL;
+            smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+            return;
+        }
+
+        if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB)
+        {
+            if (smp_request_oob_data(p_cb)) return;
+        }
+        else
+        {
+            smp_decide_association_model(p_cb, NULL);
+        }
+    }
+}
+
+/*******************************************************************************
+** Function     smp_proc_confirm
+** Description  process pairing confirm from peer device
+*******************************************************************************/
+void smp_proc_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t *p = (uint8_t *)p_data;
+    uint8_t reason = SMP_INVALID_PARAMETERS;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    if (smp_command_has_invalid_parameters(p_cb))
+    {
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+        return;
+    }
+
+    if (p != NULL)
+    {
+        /* save the SConfirm for comparison later */
+        STREAM_TO_ARRAY(p_cb->rconfirm, p, BT_OCTET16_LEN);
+    }
+
+    p_cb->flags |= SMP_PAIR_FLAGS_CMD_CONFIRM;
+}
+
+/*******************************************************************************
+** Function     smp_proc_init
+** Description  process pairing initializer from peer device
+*******************************************************************************/
+void smp_proc_init(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t *p = (uint8_t *)p_data;
+    uint8_t reason = SMP_INVALID_PARAMETERS;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    if (smp_command_has_invalid_parameters(p_cb))
+    {
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+        return;
+    }
+
+    /* save the SRand for comparison */
+    STREAM_TO_ARRAY(p_cb->rrand, p, BT_OCTET16_LEN);
+}
+
+/*******************************************************************************
+** Function     smp_proc_rand
+** Description  process pairing random (nonce) from peer device
+*******************************************************************************/
+void smp_proc_rand(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t *p = (uint8_t *)p_data;
+    uint8_t reason = SMP_INVALID_PARAMETERS;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    if (smp_command_has_invalid_parameters(p_cb))
+    {
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+        return;
+    }
+
+    /* save the SRand for comparison */
+    STREAM_TO_ARRAY(p_cb->rrand, p, BT_OCTET16_LEN);
+}
+
+/*******************************************************************************
+** Function     smp_process_pairing_public_key
+** Description  process pairing public key command from the peer device
+**              - saves the peer public key;
+**              - sets the flag indicating that the peer public key is received;
+**              - calls smp_wait_for_both_public_keys(...).
+**
+*******************************************************************************/
+void smp_process_pairing_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t *p = (uint8_t *)p_data;
+    uint8_t reason = SMP_INVALID_PARAMETERS;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    if (smp_command_has_invalid_parameters(p_cb))
+    {
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+        return;
+    }
+
+    STREAM_TO_ARRAY(p_cb->peer_publ_key.x, p, BT_OCTET32_LEN);
+    STREAM_TO_ARRAY(p_cb->peer_publ_key.y, p, BT_OCTET32_LEN);
+    p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY;
+
+    smp_wait_for_both_public_keys(p_cb, NULL);
+}
+
+/*******************************************************************************
+** Function     smp_process_pairing_commitment
+** Description  process pairing commitment from peer device
+*******************************************************************************/
+void smp_process_pairing_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t *p = (uint8_t *)p_data;
+    uint8_t reason = SMP_INVALID_PARAMETERS;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    if (smp_command_has_invalid_parameters(p_cb))
+    {
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+        return;
+    }
+
+    p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_COMM;
+
+    if (p != NULL)
+    {
+        STREAM_TO_ARRAY(p_cb->remote_commitment, p, BT_OCTET16_LEN);
+    }
+}
+
+/*******************************************************************************
+** Function     smp_process_dhkey_check
+** Description  process DHKey Check from peer device
+*******************************************************************************/
+void smp_process_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t *p = (uint8_t *)p_data;
+    uint8_t reason = SMP_INVALID_PARAMETERS;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    if (smp_command_has_invalid_parameters(p_cb))
+    {
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+        return;
+    }
+
+    if (p != NULL)
+    {
+        STREAM_TO_ARRAY(p_cb->remote_dhkey_check, p, BT_OCTET16_LEN);
+    }
+
+    p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_DHK_CHK;
+}
+
+/*******************************************************************************
+** Function     smp_process_keypress_notification
+** Description  process pairing keypress notification from peer device
+*******************************************************************************/
+void smp_process_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t *p = (uint8_t *)p_data;
+    uint8_t reason = SMP_INVALID_PARAMETERS;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+    p_cb->status = *(uint8_t *)p_data;
+
+    if (smp_command_has_invalid_parameters(p_cb))
+    {
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+        return;
+    }
+
+    if (p != NULL)
+    {
+        STREAM_TO_UINT8(p_cb->peer_keypress_notification, p);
+    }
+    else
+    {
+        p_cb->peer_keypress_notification = BTM_SP_KEY_OUT_OF_RANGE;
+    }
+    p_cb->cb_evt = SMP_PEER_KEYPR_NOT_EVT;
+}
+
+/*******************************************************************************
+** Function     smp_br_process_pairing_command
+** Description  Process the SMP pairing request/response from peer device via
+**              BR/EDR transport.
+*******************************************************************************/
+void smp_br_process_pairing_command(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t *p = (uint8_t *)p_data;
+    uint8_t reason = SMP_ENC_KEY_SIZE;
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_cb->pairing_bda);
+
+    SMP_TRACE_DEBUG("%s", __func__);
+    /* rejecting BR pairing request over non-SC BR link */
+    if (!p_dev_rec->new_encryption_key_is_p256 && p_cb->role == HCI_ROLE_SLAVE)
+    {
+        reason = SMP_XTRANS_DERIVE_NOT_ALLOW;
+        smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
+        return;
+    }
+
+    /* erase all keys if it is slave proc pairing req*/
+    if (p_dev_rec && (p_cb->role == HCI_ROLE_SLAVE))
+        btm_sec_clear_ble_keys(p_dev_rec);
+
+    p_cb->flags |= SMP_PAIR_FLAG_ENC_AFTER_PAIR;
+
+    STREAM_TO_UINT8(p_cb->peer_io_caps, p);
+    STREAM_TO_UINT8(p_cb->peer_oob_flag, p);
+    STREAM_TO_UINT8(p_cb->peer_auth_req, p);
+    STREAM_TO_UINT8(p_cb->peer_enc_size, p);
+    STREAM_TO_UINT8(p_cb->peer_i_key, p);
+    STREAM_TO_UINT8(p_cb->peer_r_key, p);
+
+    if (smp_command_has_invalid_parameters(p_cb))
+    {
+        reason = SMP_INVALID_PARAMETERS;
+        smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
+        return;
+    }
+
+    /* peer (master) started pairing sending Pairing Request */
+    /* or being master device always use received i/r key as keys to distribute */
+    p_cb->local_i_key = p_cb->peer_i_key;
+    p_cb->local_r_key = p_cb->peer_r_key;
+
+    if (p_cb->role == HCI_ROLE_SLAVE)
+    {
+        p_dev_rec->new_encryption_key_is_p256 = false;
+        /* shortcut to skip Security Grant step */
+        p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT;
+    }
+    else /* Master receives pairing response */
+    {
+        SMP_TRACE_DEBUG("%s master rcvs valid PAIRING RESPONSE."
+                          " Supposed to move to key distribution phase. ", __func__);
+    }
+
+    /* auth_req received via BR/EDR SM channel is set to 0,
+       but everything derived/exchanged has to be saved */
+    p_cb->peer_auth_req |= SMP_AUTH_BOND;
+    p_cb->loc_auth_req |= SMP_AUTH_BOND;
+}
+
+/*******************************************************************************
+** Function     smp_br_process_security_grant
+** Description  process security grant in case of pairing over BR/EDR transport.
+*******************************************************************************/
+void smp_br_process_security_grant(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t res= *(uint8_t *)p_data;
+    SMP_TRACE_DEBUG("%s", __func__);
+    if (res != SMP_SUCCESS)
+    {
+        smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, p_data);
+    }
+    else /*otherwise, start pairing */
+    {
+        /* send IO request callback */
+        p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT;
+    }
+}
+
+/*******************************************************************************
+** Function     smp_br_check_authorization_request
+** Description  sets the SMP kes to be derived/distribute over BR/EDR transport
+**              before starting the distribution/derivation
+*******************************************************************************/
+void smp_br_check_authorization_request(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t reason = SMP_SUCCESS;
+
+    SMP_TRACE_DEBUG("%s rcvs i_keys=0x%x r_keys=0x%x "
+                      "(i-initiator r-responder)", __func__, p_cb->local_i_key,
+                      p_cb->local_r_key);
+
+    /* In LE SC mode LK field is ignored when BR/EDR transport is used */
+    p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK;
+    p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK;
+
+    /* In LE SC mode only IRK, IAI, CSRK are exchanged with the peer.
+    ** Set local_r_key on master to expect only these keys. */
+    if (p_cb->role == HCI_ROLE_MASTER)
+    {
+        p_cb->local_r_key &= (SMP_SEC_KEY_TYPE_ID | SMP_SEC_KEY_TYPE_CSRK);
+    }
+
+    SMP_TRACE_DEBUG("%s rcvs upgrades: i_keys=0x%x r_keys=0x%x "
+                      "(i-initiator r-responder)", __func__, p_cb->local_i_key,
+                      p_cb->local_r_key);
+
+    if (/*((p_cb->peer_auth_req & SMP_AUTH_BOND) ||
+            (p_cb->loc_auth_req & SMP_AUTH_BOND)) &&*/
+        (p_cb->local_i_key || p_cb->local_r_key))
+    {
+        smp_br_state_machine_event(p_cb, SMP_BR_BOND_REQ_EVT, NULL);
+
+        /* if no peer key is expected, start master key distribution */
+        if (p_cb->role == HCI_ROLE_MASTER && p_cb->local_r_key == 0)
+            smp_key_distribution_by_transport(p_cb, NULL);
+    }
+    else
+    {
+        smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
+    }
+}
+
+/*******************************************************************************
+** Function     smp_br_select_next_key
+** Description  selects the next key to derive/send when BR/EDR transport is
+**              used.
+*******************************************************************************/
+void smp_br_select_next_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t reason = SMP_SUCCESS;
+    SMP_TRACE_DEBUG("%s role=%d (0-master) r_keys=0x%x i_keys=0x%x",
+                       __func__, p_cb->role, p_cb->local_r_key, p_cb->local_i_key);
+
+    if (p_cb->role == HCI_ROLE_SLAVE||
+        (!p_cb->local_r_key && p_cb->role == HCI_ROLE_MASTER))
+    {
+        smp_key_pick_key(p_cb, p_data);
+    }
+
+    if (!p_cb->local_i_key && !p_cb->local_r_key)
+    {
+        /* state check to prevent re-entrance */
+        if (smp_get_br_state() == SMP_BR_STATE_BOND_PENDING)
+        {
+            if (p_cb->total_tx_unacked == 0)
+                smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
+            else
+                p_cb->wait_for_authorization_complete = true;
+        }
+    }
+}
+
+/*******************************************************************************
+** Function     smp_proc_enc_info
+** Description  process encryption information from peer device
+*******************************************************************************/
+void smp_proc_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t *p = (uint8_t *)p_data;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+    STREAM_TO_ARRAY(p_cb->ltk, p, BT_OCTET16_LEN);
+
+    smp_key_distribution(p_cb, NULL);
+}
+/*******************************************************************************
+** Function     smp_proc_master_id
+** Description  process master ID from slave device
+*******************************************************************************/
+void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t *p = (uint8_t *)p_data;
+    tBTM_LE_PENC_KEYS   le_key;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+    smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, true);
+
+    STREAM_TO_UINT16(le_key.ediv, p);
+    STREAM_TO_ARRAY(le_key.rand, p, BT_OCTET8_LEN );
+
+    /* store the encryption keys from peer device */
+    memcpy(le_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
+    le_key.sec_level = p_cb->sec_level;
+    le_key.key_size  = p_cb->loc_enc_size;
+
+    if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND))
+        btm_sec_save_le_key(p_cb->pairing_bda,
+                            BTM_LE_KEY_PENC,
+                            (tBTM_LE_KEY_VALUE *)&le_key, true);
+
+    smp_key_distribution(p_cb, NULL);
+}
+
+/*******************************************************************************
+** Function     smp_proc_enc_info
+** Description  process identity information from peer device
+*******************************************************************************/
+void smp_proc_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t *p = (uint8_t *)p_data;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+    STREAM_TO_ARRAY (p_cb->tk, p, BT_OCTET16_LEN);   /* reuse TK for IRK */
+    smp_key_distribution_by_transport(p_cb, NULL);
+}
+
+/*******************************************************************************
+** Function     smp_proc_id_addr
+** Description  process identity address from peer device
+*******************************************************************************/
+void smp_proc_id_addr(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t *p = (uint8_t *)p_data;
+    tBTM_LE_PID_KEYS    pid_key;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+    smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ID, true);
+
+    STREAM_TO_UINT8(pid_key.addr_type, p);
+    STREAM_TO_BDADDR(pid_key.static_addr, p);
+    memcpy(pid_key.irk, p_cb->tk, BT_OCTET16_LEN);
+
+    /* to use as BD_ADDR for lk derived from ltk */
+    p_cb->id_addr_rcvd = true;
+    p_cb->id_addr_type = pid_key.addr_type;
+    memcpy(p_cb->id_addr, pid_key.static_addr, BD_ADDR_LEN);
+
+    /* store the ID key from peer device */
+    if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND))
+        btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PID,
+                            (tBTM_LE_KEY_VALUE *)&pid_key, true);
+    smp_key_distribution_by_transport(p_cb, NULL);
+}
+
+/*******************************************************************************
+** Function     smp_proc_srk_info
+** Description  process security information from peer device
+*******************************************************************************/
+void smp_proc_srk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    tBTM_LE_PCSRK_KEYS   le_key;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+    smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_CSRK, true);
+
+    /* save CSRK to security record */
+    le_key.sec_level = p_cb->sec_level;
+    memcpy (le_key.csrk, p_data, BT_OCTET16_LEN);   /* get peer CSRK */
+    le_key.counter = 0; /* initialize the peer counter */
+
+    if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND))
+        btm_sec_save_le_key(p_cb->pairing_bda,
+                            BTM_LE_KEY_PCSRK,
+                            (tBTM_LE_KEY_VALUE *)&le_key, true);
+    smp_key_distribution_by_transport(p_cb, NULL);
+}
+
+/*******************************************************************************
+** Function     smp_proc_compare
+** Description  process compare value
+*******************************************************************************/
+void smp_proc_compare(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t reason;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+    if (!memcmp(p_cb->rconfirm, p_data->key.p_data, BT_OCTET16_LEN))
+    {
+        /* compare the max encryption key size, and save the smaller one for the link */
+        if ( p_cb->peer_enc_size < p_cb->loc_enc_size)
+            p_cb->loc_enc_size = p_cb->peer_enc_size;
+
+        if (p_cb->role == HCI_ROLE_SLAVE)
+            smp_sm_event(p_cb, SMP_RAND_EVT, NULL);
+        else
+        {
+            /* master device always use received i/r key as keys to distribute */
+            p_cb->local_i_key = p_cb->peer_i_key;
+            p_cb->local_r_key = p_cb->peer_r_key;
+
+            smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL);
+        }
+
+    }
+    else
+    {
+        reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR;
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+    }
+}
+
+/*******************************************************************************
+** Function     smp_proc_sl_key
+** Description  process key ready events.
+*******************************************************************************/
+void smp_proc_sl_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t key_type = p_data->key.key_type;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+    if (key_type == SMP_KEY_TYPE_TK)
+    {
+        smp_generate_srand_mrand_confirm(p_cb, NULL);
+    }
+    else if (key_type == SMP_KEY_TYPE_CFM)
+    {
+        smp_set_state(SMP_STATE_WAIT_CONFIRM);
+
+        if (p_cb->flags & SMP_PAIR_FLAGS_CMD_CONFIRM)
+            smp_sm_event(p_cb, SMP_CONFIRM_EVT, NULL);
+    }
+}
+
+/*******************************************************************************
+** Function     smp_start_enc
+** Description  start encryption
+*******************************************************************************/
+void smp_start_enc(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    tBTM_STATUS cmd;
+    uint8_t reason = SMP_ENC_FAIL;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+    if (p_data != NULL)
+        cmd = btm_ble_start_encrypt(p_cb->pairing_bda, true, p_data->key.p_data);
+    else
+        cmd = btm_ble_start_encrypt(p_cb->pairing_bda, false, NULL);
+
+    if (cmd != BTM_CMD_STARTED && cmd != BTM_BUSY)
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+}
+
+/*******************************************************************************
+** Function     smp_proc_discard
+** Description   processing for discard security request
+*******************************************************************************/
+void smp_proc_discard(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+    if (!(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD))
+        smp_reset_control_value(p_cb);
+}
+
+/*******************************************************************************
+** Function     smp_enc_cmpl
+** Description   encryption success
+*******************************************************************************/
+void smp_enc_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t enc_enable = *(uint8_t *)p_data;
+    uint8_t reason = enc_enable ? SMP_SUCCESS : SMP_ENC_FAIL;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+}
+
+/*******************************************************************************
+** Function     smp_check_auth_req
+** Description  check authentication request
+*******************************************************************************/
+void smp_check_auth_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t enc_enable = *(uint8_t *)p_data;
+    uint8_t reason = enc_enable ? SMP_SUCCESS : SMP_ENC_FAIL;
+
+    SMP_TRACE_DEBUG("%s rcvs enc_enable=%d i_keys=0x%x r_keys=0x%x "
+                      "(i-initiator r-responder)",
+                      __func__, enc_enable, p_cb->local_i_key, p_cb->local_r_key);
+    if (enc_enable == 1)
+    {
+        if (p_cb->le_secure_connections_mode_is_used)
+        {
+            /* In LE SC mode LTK is used instead of STK and has to be always saved */
+            p_cb->local_i_key |= SMP_SEC_KEY_TYPE_ENC;
+            p_cb->local_r_key |= SMP_SEC_KEY_TYPE_ENC;
+
+           /* In LE SC mode LK is derived from LTK only if both sides request it */
+           if (!(p_cb->local_i_key & SMP_SEC_KEY_TYPE_LK) ||
+               !(p_cb->local_r_key & SMP_SEC_KEY_TYPE_LK))
+            {
+                p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK;
+                p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK;
+            }
+
+            /* In LE SC mode only IRK, IAI, CSRK are exchanged with the peer.
+            ** Set local_r_key on master to expect only these keys.
+            */
+            if (p_cb->role == HCI_ROLE_MASTER)
+            {
+                p_cb->local_r_key &= (SMP_SEC_KEY_TYPE_ID | SMP_SEC_KEY_TYPE_CSRK);
+            }
+        }
+        else
+        {
+            /* in legacy mode derivation of BR/EDR LK is not supported */
+            p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK;
+            p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK;
+        }
+        SMP_TRACE_DEBUG("%s rcvs upgrades: i_keys=0x%x r_keys=0x%x "
+                          "(i-initiator r-responder)",
+                          __func__, p_cb->local_i_key, p_cb->local_r_key);
+
+        if (/*((p_cb->peer_auth_req & SMP_AUTH_BOND) ||
+             (p_cb->loc_auth_req & SMP_AUTH_BOND)) &&*/
+            (p_cb->local_i_key || p_cb->local_r_key))
+        {
+            smp_sm_event(p_cb, SMP_BOND_REQ_EVT, NULL);
+        }
+        else
+            smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+    }
+    else if (enc_enable == 0)
+    {
+        /* if failed for encryption after pairing, send callback */
+        if (p_cb->flags & SMP_PAIR_FLAG_ENC_AFTER_PAIR)
+            smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+        /* if enc failed for old security information */
+        /* if master device, clean up and abck to idle; slave device do nothing */
+        else if (p_cb->role == HCI_ROLE_MASTER)
+        {
+            smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+        }
+    }
+}
+
+/*******************************************************************************
+** Function     smp_key_pick_key
+** Description  Pick a key distribution function based on the key mask.
+*******************************************************************************/
+void smp_key_pick_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t key_to_dist = (p_cb->role == HCI_ROLE_SLAVE) ? p_cb->local_r_key : p_cb->local_i_key;
+    uint8_t i = 0;
+
+    SMP_TRACE_DEBUG("%s key_to_dist=0x%x", __func__, key_to_dist);
+    while (i < SMP_KEY_DIST_TYPE_MAX)
+    {
+        SMP_TRACE_DEBUG("key to send = %02x, i = %d",  key_to_dist, i);
+
+        if (key_to_dist & (1 << i))
+        {
+            SMP_TRACE_DEBUG("smp_distribute_act[%d]", i);
+            (* smp_distribute_act[i])(p_cb, p_data);
+            break;
+        }
+        i ++;
+    }
+}
+/*******************************************************************************
+** Function     smp_key_distribution
+** Description  start key distribution if required.
+*******************************************************************************/
+void smp_key_distribution(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s role=%d (0-master) r_keys=0x%x i_keys=0x%x",
+                      __func__, p_cb->role, p_cb->local_r_key, p_cb->local_i_key);
+
+    if (p_cb->role == HCI_ROLE_SLAVE ||
+       (!p_cb->local_r_key && p_cb->role == HCI_ROLE_MASTER))
+    {
+        smp_key_pick_key(p_cb, p_data);
+    }
+
+    if (!p_cb->local_i_key && !p_cb->local_r_key)
+    {
+        /* state check to prevent re-entrant */
+        if (smp_get_state() == SMP_STATE_BOND_PENDING)
+        {
+            if (p_cb->derive_lk)
+            {
+                smp_derive_link_key_from_long_term_key(p_cb, NULL);
+                p_cb->derive_lk = false;
+            }
+
+            if (p_cb->total_tx_unacked == 0)
+            {
+                /*
+                 * Instead of declaring authorization complete immediately,
+                 * delay the event from being sent by SMP_DELAYED_AUTH_TIMEOUT_MS.
+                 * This allows the slave to send over Pairing Failed if the
+                 * last key is rejected.  During this waiting window, the
+                 * state should remain in SMP_STATE_BOND_PENDING.
+                 */
+                if (!alarm_is_scheduled(p_cb->delayed_auth_timer_ent)) {
+                    SMP_TRACE_DEBUG("%s delaying auth complete.", __func__);
+                    alarm_set_on_queue(p_cb->delayed_auth_timer_ent, SMP_DELAYED_AUTH_TIMEOUT_MS,
+                                       smp_delayed_auth_complete_timeout, NULL, btu_general_alarm_queue);
+                }
+            } else {
+                p_cb->wait_for_authorization_complete = true;
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+** Function         smp_decide_association_model
+** Description      This function is called to select assoc model to be used for
+**                  STK generation and to start STK generation process.
+**
+*******************************************************************************/
+void smp_decide_association_model(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t failure = SMP_UNKNOWN_IO_CAP;
+    uint8_t int_evt = 0;
+    tSMP_KEY key;
+    tSMP_INT_DATA   *p = NULL;
+
+    SMP_TRACE_DEBUG("%s Association Model = %d", __func__, p_cb->selected_association_model);
+
+    switch (p_cb->selected_association_model)
+    {
+        case SMP_MODEL_ENCRYPTION_ONLY:  /* TK = 0, go calculate Confirm */
+            if (p_cb->role == HCI_ROLE_MASTER &&
+                ((p_cb->peer_auth_req & SMP_AUTH_YN_BIT) != 0) &&
+                ((p_cb->loc_auth_req & SMP_AUTH_YN_BIT) == 0))
+            {
+                SMP_TRACE_ERROR ("IO capability does not meet authentication requirement");
+                failure = SMP_PAIR_AUTH_FAIL;
+                p = (tSMP_INT_DATA *)&failure;
+                int_evt = SMP_AUTH_CMPL_EVT;
+            }
+            else
+            {
+                p_cb->sec_level = SMP_SEC_UNAUTHENTICATE;
+                SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_UNAUTHENTICATE) ", p_cb->sec_level );
+
+                key.key_type = SMP_KEY_TYPE_TK;
+                key.p_data = p_cb->tk;
+                p = (tSMP_INT_DATA *)&key;
+
+                memset(p_cb->tk, 0, BT_OCTET16_LEN);
+                /* TK, ready  */
+                int_evt = SMP_KEY_READY_EVT;
+            }
+            break;
+
+        case SMP_MODEL_PASSKEY:
+            p_cb->sec_level = SMP_SEC_AUTHENTICATED;
+            SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) ", p_cb->sec_level );
+
+            p_cb->cb_evt = SMP_PASSKEY_REQ_EVT;
+            int_evt = SMP_TK_REQ_EVT;
+            break;
+
+        case SMP_MODEL_OOB:
+            SMP_TRACE_ERROR ("Association Model = SMP_MODEL_OOB");
+            p_cb->sec_level = SMP_SEC_AUTHENTICATED;
+            SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) ", p_cb->sec_level );
+
+            p_cb->cb_evt = SMP_OOB_REQ_EVT;
+            int_evt = SMP_TK_REQ_EVT;
+            break;
+
+        case SMP_MODEL_KEY_NOTIF:
+            p_cb->sec_level = SMP_SEC_AUTHENTICATED;
+            SMP_TRACE_DEBUG("Need to generate Passkey");
+
+            /* generate passkey and notify application */
+            smp_generate_passkey(p_cb, NULL);
+            break;
+
+        case SMP_MODEL_SEC_CONN_JUSTWORKS:
+        case SMP_MODEL_SEC_CONN_NUM_COMP:
+        case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
+        case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
+        case SMP_MODEL_SEC_CONN_OOB:
+            int_evt = SMP_PUBL_KEY_EXCH_REQ_EVT;
+            break;
+
+        case SMP_MODEL_OUT_OF_RANGE:
+            SMP_TRACE_ERROR("Association Model = SMP_MODEL_OUT_OF_RANGE (failed)");
+            p = (tSMP_INT_DATA *)&failure;
+            int_evt = SMP_AUTH_CMPL_EVT;
+            break;
+
+        default:
+            SMP_TRACE_ERROR("Association Model = %d (SOMETHING IS WRONG WITH THE CODE)",
+                             p_cb->selected_association_model);
+            p = (tSMP_INT_DATA *)&failure;
+            int_evt = SMP_AUTH_CMPL_EVT;
+    }
+
+    SMP_TRACE_EVENT ("sec_level=%d ", p_cb->sec_level );
+    if (int_evt)
+        smp_sm_event(p_cb, int_evt, p);
+}
+
+/*******************************************************************************
+** Function     smp_process_io_response
+** Description  process IO response for a slave device.
+*******************************************************************************/
+void smp_process_io_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t reason = SMP_PAIR_AUTH_FAIL;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+    if (p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)
+    {
+        /* pairing started by local (slave) Security Request */
+        smp_set_state(SMP_STATE_SEC_REQ_PENDING);
+        smp_send_cmd(SMP_OPCODE_SEC_REQ, p_cb);
+    }
+    else /* plan to send pairing respond */
+    {
+        /* pairing started by peer (master) Pairing Request */
+        p_cb->selected_association_model = smp_select_association_model(p_cb);
+
+        if (p_cb->secure_connections_only_mode_required &&
+            (!(p_cb->le_secure_connections_mode_is_used) ||
+            (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS)))
+        {
+            SMP_TRACE_ERROR ("Slave requires secure connection only mode \
+                              but it can't be provided -> Slave fails pairing");
+            smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+            return;
+        }
+
+        if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB)
+        {
+            if (smp_request_oob_data(p_cb)) return;
+        }
+
+        // PTS Testing failure modes
+        if (pts_test_send_authentication_complete_failure(p_cb))
+            return;
+
+        smp_send_pair_rsp(p_cb, NULL);
+    }
+}
+
+/*******************************************************************************
+** Function     smp_br_process_slave_keys_response
+** Description  process application keys response for a slave device
+**              (BR/EDR transport).
+*******************************************************************************/
+void smp_br_process_slave_keys_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    smp_br_send_pair_response(p_cb, NULL);
+}
+
+/*******************************************************************************
+** Function     smp_br_send_pair_response
+** Description  actions related to sending pairing response over BR/EDR transport.
+*******************************************************************************/
+void smp_br_send_pair_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    p_cb->local_i_key &= p_cb->peer_i_key;
+    p_cb->local_r_key &= p_cb->peer_r_key;
+
+    smp_send_cmd (SMP_OPCODE_PAIRING_RSP, p_cb);
+}
+
+/*******************************************************************************
+** Function         smp_pairing_cmpl
+** Description      This function is called to send the pairing complete callback
+**                  and remove the connection if needed.
+*******************************************************************************/
+void smp_pairing_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    if (p_cb->total_tx_unacked == 0)
+    {
+        /* process the pairing complete */
+        smp_proc_pairing_cmpl(p_cb);
+    }
+}
+
+/*******************************************************************************
+** Function         smp_pair_terminate
+** Description      This function is called to send the pairing complete callback
+**                  and remove the connection if needed.
+*******************************************************************************/
+void smp_pair_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+    p_cb->status = SMP_CONN_TOUT;
+    smp_proc_pairing_cmpl(p_cb);
+}
+
+/*******************************************************************************
+** Function         smp_idle_terminate
+** Description      This function calledin idle state to determine to send authentication
+**                  complete or not.
+*******************************************************************************/
+void smp_idle_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    if (p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)
+    {
+        SMP_TRACE_DEBUG("Pairing terminated at IDLE state.");
+        p_cb->status = SMP_FAIL;
+        smp_proc_pairing_cmpl(p_cb);
+    }
+}
+
+/*******************************************************************************
+** Function     smp_fast_conn_param
+** Description  apply default connection parameter for pairing process
+*******************************************************************************/
+void smp_fast_conn_param(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    /* Disable L2CAP connection parameter updates while bonding since
+       some peripherals are not able to revert to fast connection parameters
+       during the start of service discovery. Connection paramter updates
+       get enabled again once service discovery completes. */
+    L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, false);
+}
+
+/*******************************************************************************
+** Function     smp_both_have_public_keys
+** Description  The function is called when both local and peer public keys are
+**              saved.
+**              Actions:
+**              - invokes DHKey computation;
+**              - on slave side invokes sending local public key to the peer.
+**              - invokes SC phase 1 process.
+*******************************************************************************/
+void smp_both_have_public_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s",__func__);
+
+    /* invokes DHKey computation */
+    smp_compute_dhkey(p_cb);
+
+    /* on slave side invokes sending local public key to the peer */
+    if (p_cb->role == HCI_ROLE_SLAVE)
+        smp_send_pair_public_key(p_cb, NULL);
+
+    smp_sm_event(p_cb, SMP_SC_DHKEY_CMPLT_EVT, NULL);
+}
+
+/*******************************************************************************
+** Function     smp_start_secure_connection_phase1
+** Description  The function starts Secure Connection phase1 i.e. invokes initialization of Secure Connection
+**              phase 1 parameters and starts building/sending to the peer
+**              messages appropriate for the role and association model.
+*******************************************************************************/
+void smp_start_secure_connection_phase1(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS)
+    {
+        p_cb->sec_level = SMP_SEC_UNAUTHENTICATE;
+        SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_UNAUTHENTICATE) ", p_cb->sec_level );
+    }
+    else
+    {
+        p_cb->sec_level = SMP_SEC_AUTHENTICATED;
+        SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) ", p_cb->sec_level );
+    }
+
+    switch(p_cb->selected_association_model)
+    {
+        case SMP_MODEL_SEC_CONN_JUSTWORKS:
+        case SMP_MODEL_SEC_CONN_NUM_COMP:
+            memset(p_cb->local_random, 0, BT_OCTET16_LEN);
+            smp_start_nonce_generation(p_cb);
+            break;
+        case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
+            /* user has to provide passkey */
+            p_cb->cb_evt = SMP_PASSKEY_REQ_EVT;
+            smp_sm_event(p_cb, SMP_TK_REQ_EVT, NULL);
+            break;
+        case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
+            /* passkey has to be provided to user */
+            SMP_TRACE_DEBUG("Need to generate SC Passkey");
+            smp_generate_passkey(p_cb, NULL);
+            break;
+        case SMP_MODEL_SEC_CONN_OOB:
+            /* use the available OOB information */
+            smp_process_secure_connection_oob_data(p_cb, NULL);
+            break;
+        default:
+            SMP_TRACE_ERROR ("Association Model = %d is not used in LE SC",
+                              p_cb->selected_association_model);
+            break;
+    }
+}
+
+/*******************************************************************************
+** Function     smp_process_local_nonce
+** Description  The function processes new local nonce.
+**
+** Note         It is supposed to be called in SC phase1.
+*******************************************************************************/
+void smp_process_local_nonce(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    switch(p_cb->selected_association_model)
+    {
+        case SMP_MODEL_SEC_CONN_JUSTWORKS:
+        case SMP_MODEL_SEC_CONN_NUM_COMP:
+            if (p_cb->role == HCI_ROLE_SLAVE)
+            {
+                /* slave calculates and sends local commitment */
+                smp_calculate_local_commitment(p_cb);
+                smp_send_commitment(p_cb, NULL);
+                /* slave has to wait for peer nonce */
+                smp_set_state(SMP_STATE_WAIT_NONCE);
+            }
+            else    /* i.e. master */
+            {
+                if (p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_COMM)
+                {
+                    /* slave commitment is already received, send local nonce, wait for remote nonce*/
+                    SMP_TRACE_DEBUG("master in assoc mode = %d \
+                    already rcvd slave commitment - race condition",
+                                      p_cb->selected_association_model);
+                    p_cb->flags &= ~SMP_PAIR_FLAG_HAVE_PEER_COMM;
+                    smp_send_rand(p_cb, NULL);
+                    smp_set_state(SMP_STATE_WAIT_NONCE);
+                }
+            }
+            break;
+        case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
+        case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
+            smp_calculate_local_commitment(p_cb);
+
+            if (p_cb->role == HCI_ROLE_MASTER)
+            {
+                smp_send_commitment(p_cb, NULL);
+            }
+            else    /* slave */
+            {
+                if (p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_COMM)
+                {
+                    /* master commitment is already received */
+                    smp_send_commitment(p_cb, NULL);
+                    smp_set_state(SMP_STATE_WAIT_NONCE);
+                }
+            }
+            break;
+        case SMP_MODEL_SEC_CONN_OOB:
+            if (p_cb->role == HCI_ROLE_MASTER)
+            {
+                smp_send_rand(p_cb, NULL);
+            }
+
+            smp_set_state(SMP_STATE_WAIT_NONCE);
+            break;
+        default:
+            SMP_TRACE_ERROR ("Association Model = %d is not used in LE SC",
+                              p_cb->selected_association_model);
+            break;
+    }
+}
+
+/*******************************************************************************
+** Function     smp_process_peer_nonce
+** Description  The function processes newly received and saved in CB peer nonce.
+**              The actions depend on the selected association model and the role.
+**
+** Note         It is supposed to be called in SC phase1.
+*******************************************************************************/
+void smp_process_peer_nonce(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t reason;
+
+    SMP_TRACE_DEBUG("%s start ", __func__);
+
+    // PTS Testing failure modes
+    if (p_cb->cert_failure == 1) {
+        SMP_TRACE_ERROR("%s failure case = %d", __func__, p_cb->cert_failure);
+        reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR;
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+        return;
+    }
+
+    switch(p_cb->selected_association_model)
+    {
+        case SMP_MODEL_SEC_CONN_JUSTWORKS:
+        case SMP_MODEL_SEC_CONN_NUM_COMP:
+            /* in these models only master receives commitment */
+            if (p_cb->role == HCI_ROLE_MASTER)
+            {
+                if (!smp_check_commitment(p_cb))
+                {
+                    reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR;
+                    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+                    break;
+                }
+            }
+            else
+            {
+                /* slave sends local nonce */
+                smp_send_rand(p_cb, NULL);
+            }
+
+            if(p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS)
+            {
+                /* go directly to phase 2 */
+                smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL);
+            }
+            else    /* numeric comparison */
+            {
+                smp_set_state(SMP_STATE_WAIT_NONCE);
+                smp_sm_event(p_cb, SMP_SC_CALC_NC_EVT, NULL);
+            }
+            break;
+        case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
+        case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
+            if (!smp_check_commitment(p_cb) && p_cb->cert_failure != 9)
+            {
+                reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR;
+                smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+                break;
+            }
+
+            if (p_cb->role == HCI_ROLE_SLAVE)
+            {
+                smp_send_rand(p_cb, NULL);
+            }
+
+            if (++p_cb->round < 20)
+            {
+                smp_set_state(SMP_STATE_SEC_CONN_PHS1_START);
+                p_cb->flags &= ~SMP_PAIR_FLAG_HAVE_PEER_COMM;
+                smp_start_nonce_generation(p_cb);
+                break;
+            }
+
+            smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL);
+            break;
+        case SMP_MODEL_SEC_CONN_OOB:
+            if (p_cb->role == HCI_ROLE_SLAVE)
+            {
+                smp_send_rand(p_cb, NULL);
+            }
+
+            smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL);
+            break;
+        default:
+            SMP_TRACE_ERROR ("Association Model = %d is not used in LE SC",
+                              p_cb->selected_association_model);
+            break;
+    }
+
+    SMP_TRACE_DEBUG("%s end ",__func__);
+}
+
+/*******************************************************************************
+** Function     smp_match_dhkey_checks
+** Description  checks if the calculated peer DHKey Check value is the same as
+**              received from the peer DHKey check value.
+*******************************************************************************/
+void smp_match_dhkey_checks(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t reason = SMP_DHKEY_CHK_FAIL;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    if (memcmp(p_data->key.p_data, p_cb->remote_dhkey_check, BT_OCTET16_LEN))
+    {
+        SMP_TRACE_WARNING ("dhkey chcks do no match");
+        p_cb->failure = reason;
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+        return;
+    }
+
+    SMP_TRACE_EVENT ("dhkey chcks match");
+
+    /* compare the max encryption key size, and save the smaller one for the link */
+    if (p_cb->peer_enc_size < p_cb->loc_enc_size)
+        p_cb->loc_enc_size = p_cb->peer_enc_size;
+
+    if (p_cb->role == HCI_ROLE_SLAVE)
+    {
+        smp_sm_event(p_cb, SMP_PAIR_DHKEY_CHCK_EVT, NULL);
+    }
+    else
+    {
+        /* master device always use received i/r key as keys to distribute */
+        p_cb->local_i_key = p_cb->peer_i_key;
+        p_cb->local_r_key = p_cb->peer_r_key;
+        smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL);
+    }
+}
+
+/*******************************************************************************
+** Function     smp_move_to_secure_connections_phase2
+** Description  Signal State Machine to start SC phase 2 initialization (to
+**              compute local DHKey Check value).
+**
+** Note         SM is supposed to be in the state SMP_STATE_SEC_CONN_PHS2_START.
+*******************************************************************************/
+void smp_move_to_secure_connections_phase2(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s",__func__);
+    smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL);
+}
+
+/*******************************************************************************
+** Function     smp_phase_2_dhkey_checks_are_present
+** Description  generates event if dhkey check from the peer is already received.
+**
+** Note         It is supposed to be used on slave to prevent race condition.
+**              It is supposed to be called after slave dhkey check is calculated.
+*******************************************************************************/
+void smp_phase_2_dhkey_checks_are_present(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s",__func__);
+
+    if (p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_DHK_CHK)
+        smp_sm_event(p_cb, SMP_SC_2_DHCK_CHKS_PRES_EVT, NULL);
+}
+
+/*******************************************************************************
+** Function     smp_wait_for_both_public_keys
+** Description  generates SMP_BOTH_PUBL_KEYS_RCVD_EVT event when both local and master
+**              public keys are available.
+**
+** Note         on the slave it is used to prevent race condition.
+**
+*******************************************************************************/
+void smp_wait_for_both_public_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s",__func__);
+
+    if ((p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY) &&
+        (p_cb->flags & SMP_PAIR_FLAG_HAVE_LOCAL_PUBL_KEY))
+    {
+        if ((p_cb->role == HCI_ROLE_SLAVE) &&
+            ((p_cb->req_oob_type == SMP_OOB_LOCAL) || (p_cb->req_oob_type == SMP_OOB_BOTH)))
+        {
+            smp_set_state(SMP_STATE_PUBLIC_KEY_EXCH);
+        }
+        smp_sm_event(p_cb, SMP_BOTH_PUBL_KEYS_RCVD_EVT, NULL);
+    }
+}
+
+/*******************************************************************************
+** Function     smp_start_passkey_verification
+** Description  Starts SC passkey entry verification.
+*******************************************************************************/
+void smp_start_passkey_verification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t *p = NULL;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+    p = p_cb->local_random;
+    UINT32_TO_STREAM(p, p_data->passkey);
+
+    p = p_cb->peer_random;
+    UINT32_TO_STREAM(p, p_data->passkey);
+
+    p_cb->round = 0;
+    smp_start_nonce_generation(p_cb);
+}
+
+/*******************************************************************************
+** Function     smp_process_secure_connection_oob_data
+** Description  Processes local/peer SC OOB data received from somewhere.
+*******************************************************************************/
+void smp_process_secure_connection_oob_data(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    tSMP_SC_OOB_DATA *p_sc_oob_data = &p_cb->sc_oob_data;
+    if (p_sc_oob_data->loc_oob_data.present)
+    {
+        memcpy(p_cb->local_random, p_sc_oob_data->loc_oob_data.randomizer,
+               sizeof(p_cb->local_random));
+    }
+    else
+    {
+        SMP_TRACE_EVENT ("%s: local OOB randomizer is absent", __func__);
+        memset(p_cb->local_random, 0, sizeof (p_cb->local_random));
+    }
+
+    if (!p_sc_oob_data->peer_oob_data.present)
+    {
+        SMP_TRACE_EVENT ("%s: peer OOB data is absent", __func__);
+        memset(p_cb->peer_random, 0, sizeof (p_cb->peer_random));
+    }
+    else
+    {
+        memcpy(p_cb->peer_random, p_sc_oob_data->peer_oob_data.randomizer,
+               sizeof(p_cb->peer_random));
+        memcpy(p_cb->remote_commitment, p_sc_oob_data->peer_oob_data.commitment,
+               sizeof(p_cb->remote_commitment));
+
+        uint8_t reason = SMP_CONFIRM_VALUE_ERR;
+        /* check commitment */
+        if (!smp_check_commitment(p_cb))
+        {
+            p_cb->failure = reason;
+            smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+            return;
+        }
+
+        if (p_cb->peer_oob_flag != SMP_OOB_PRESENT)
+        {
+            /* the peer doesn't have local randomiser */
+            SMP_TRACE_EVENT ("%s: peer didn't receive local OOB data, set local randomizer to 0",
+                             __func__);
+            memset(p_cb->local_random, 0, sizeof (p_cb->local_random));
+        }
+    }
+
+    print128(p_cb->local_random, (const uint8_t *)"local OOB randomizer");
+    print128(p_cb->peer_random, (const uint8_t *)"peer OOB randomizer");
+    smp_start_nonce_generation(p_cb);
+}
+
+/*******************************************************************************
+** Function     smp_set_local_oob_keys
+** Description  Saves calculated private/public keys in sc_oob_data.loc_oob_data,
+**              starts nonce generation
+**              (to be saved in sc_oob_data.loc_oob_data.randomizer).
+*******************************************************************************/
+void smp_set_local_oob_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    memcpy(p_cb->sc_oob_data.loc_oob_data.private_key_used, p_cb->private_key,
+           BT_OCTET32_LEN);
+    p_cb->sc_oob_data.loc_oob_data.publ_key_used = p_cb->loc_publ_key;
+    smp_start_nonce_generation(p_cb);
+}
+
+/*******************************************************************************
+** Function     smp_set_local_oob_random_commitment
+** Description  Saves calculated randomizer and commitment in sc_oob_data.loc_oob_data,
+**              passes sc_oob_data.loc_oob_data up for safekeeping.
+*******************************************************************************/
+void smp_set_local_oob_random_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+    memcpy(p_cb->sc_oob_data.loc_oob_data.randomizer, p_cb->rand,
+           BT_OCTET16_LEN);
+
+    smp_calculate_f4(p_cb->sc_oob_data.loc_oob_data.publ_key_used.x,
+                     p_cb->sc_oob_data.loc_oob_data.publ_key_used.x,
+                     p_cb->sc_oob_data.loc_oob_data.randomizer, 0,
+                     p_cb->sc_oob_data.loc_oob_data.commitment);
+
+#if (SMP_DEBUG == TRUE)
+    uint8_t *p_print = NULL;
+    SMP_TRACE_DEBUG("local SC OOB data set:");
+    p_print = (uint8_t*) &p_cb->sc_oob_data.loc_oob_data.addr_sent_to;
+    smp_debug_print_nbyte_little_endian (p_print, (const uint8_t *)"addr_sent_to",
+                                         sizeof(tBLE_BD_ADDR));
+    p_print = (uint8_t*) &p_cb->sc_oob_data.loc_oob_data.private_key_used;
+    smp_debug_print_nbyte_little_endian (p_print, (const uint8_t *)"private_key_used",
+                                         BT_OCTET32_LEN);
+    p_print = (uint8_t*) &p_cb->sc_oob_data.loc_oob_data.publ_key_used.x;
+    smp_debug_print_nbyte_little_endian (p_print, (const uint8_t *)"publ_key_used.x",
+                                         BT_OCTET32_LEN);
+    p_print = (uint8_t*) &p_cb->sc_oob_data.loc_oob_data.publ_key_used.y;
+    smp_debug_print_nbyte_little_endian (p_print, (const uint8_t *)"publ_key_used.y",
+                                         BT_OCTET32_LEN);
+    p_print = (uint8_t*) &p_cb->sc_oob_data.loc_oob_data.randomizer;
+    smp_debug_print_nbyte_little_endian (p_print, (const uint8_t *)"randomizer",
+                                         BT_OCTET16_LEN);
+    p_print = (uint8_t*) &p_cb->sc_oob_data.loc_oob_data.commitment;
+    smp_debug_print_nbyte_little_endian (p_print,(const uint8_t *) "commitment",
+                                         BT_OCTET16_LEN);
+    SMP_TRACE_DEBUG("");
+#endif
+
+    /* pass created OOB data up */
+    p_cb->cb_evt = SMP_SC_LOC_OOB_DATA_UP_EVT;
+    smp_send_app_cback(p_cb, NULL);
+
+    smp_cb_cleanup(p_cb);
+}
+
+/*******************************************************************************
+**
+** Function         smp_link_encrypted
+**
+** Description      This function is called when link is encrypted and notified to
+**                  slave device. Proceed to to send LTK, DIV and ER to master if
+**                  bonding the devices.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_link_encrypted(BD_ADDR bda, uint8_t encr_enable)
+{
+    tSMP_CB *p_cb = &smp_cb;
+
+    SMP_TRACE_DEBUG("%s encr_enable=%d", __func__, encr_enable);
+
+    if (memcmp(&smp_cb.pairing_bda[0], bda, BD_ADDR_LEN) == 0)
+    {
+        /* encryption completed with STK, remmeber the key size now, could be overwite
+        *  when key exchange happens                                        */
+        if (p_cb->loc_enc_size != 0 && encr_enable)
+        {
+            /* update the link encryption key size if a SMP pairing just performed */
+            btm_ble_update_sec_key_size(bda, p_cb->loc_enc_size);
+        }
+
+        smp_sm_event(&smp_cb, SMP_ENCRYPTED_EVT, &encr_enable);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         smp_proc_ltk_request
+**
+** Description      This function is called when LTK request is received from
+**                  controller.
+**
+** Returns          void
+**
+*******************************************************************************/
+bool    smp_proc_ltk_request(BD_ADDR bda)
+{
+    SMP_TRACE_DEBUG("%s state = %d",  __func__, smp_cb.state);
+    bool    match = false;
+
+    if (!memcmp(bda, smp_cb.pairing_bda, BD_ADDR_LEN))
+    {
+        match = true;
+    } else {
+        BD_ADDR dummy_bda = {0};
+        tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bda);
+        if (p_dev_rec != NULL &&
+            0 == memcmp(p_dev_rec->ble.pseudo_addr, smp_cb.pairing_bda, BD_ADDR_LEN) &&
+            0 != memcmp(p_dev_rec->ble.pseudo_addr, dummy_bda, BD_ADDR_LEN))
+        {
+            match = true;
+        }
+    }
+
+    if (match && smp_cb.state == SMP_STATE_ENCRYPTION_PENDING)
+    {
+        smp_sm_event(&smp_cb, SMP_ENC_REQ_EVT, NULL);
+        return true;
+    }
+
+    return false;
+}
+
+/*******************************************************************************
+**
+** Function         smp_process_secure_connection_long_term_key
+**
+** Description      This function is called to process SC LTK.
+**                  SC LTK is calculated and used instead of STK.
+**                  Here SC LTK is saved in BLE DB.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_process_secure_connection_long_term_key(void)
+{
+    tSMP_CB     *p_cb = &smp_cb;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+    smp_save_secure_connections_long_term_key(p_cb);
+
+    smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, false);
+    smp_key_distribution(p_cb, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         smp_set_derive_link_key
+**
+** Description      This function is called to set flag that indicates that
+**                  BR/EDR LK has to be derived from LTK after all keys are
+**                  distributed.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_set_derive_link_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG ("%s", __func__);
+    p_cb->derive_lk = true;
+    smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_LK, false);
+    smp_key_distribution(p_cb, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         smp_derive_link_key_from_long_term_key
+**
+** Description      This function is called to derive BR/EDR LK from LTK.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_derive_link_key_from_long_term_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+    if (!smp_calculate_link_key_from_long_term_key(p_cb))
+    {
+        SMP_TRACE_ERROR("%s failed", __func__);
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+        return;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         smp_br_process_link_key
+**
+** Description      This function is called to process BR/EDR LK:
+**                  - to derive SMP LTK from BR/EDR LK;
+*8                  - to save SMP LTK.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_br_process_link_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+    if (!smp_calculate_long_term_key_from_link_key(p_cb))
+    {
+        SMP_TRACE_ERROR ("%s failed",__func__);
+        smp_sm_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &status);
+        return;
+    }
+
+    SMP_TRACE_DEBUG("%s: LTK derivation from LK successfully completed", __func__);
+    smp_save_secure_connections_long_term_key(p_cb);
+    smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, false);
+    smp_br_select_next_key(p_cb, NULL);
+}
+
+/*******************************************************************************
+** Function     smp_key_distribution_by_transport
+** Description  depending on the transport used at the moment calls either
+**              smp_key_distribution(...) or smp_br_key_distribution(...).
+*******************************************************************************/
+void smp_key_distribution_by_transport(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+    if (p_cb->smp_over_br)
+    {
+        smp_br_select_next_key(p_cb, NULL);
+    }
+    else
+    {
+        smp_key_distribution(p_cb, NULL);
+    }
+}
+
+/*******************************************************************************
+** Function         smp_br_pairing_complete
+** Description      This function is called to send the pairing complete callback
+**                  and remove the connection if needed.
+*******************************************************************************/
+void smp_br_pairing_complete(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    if (p_cb->total_tx_unacked == 0)
+    {
+        /* process the pairing complete */
+        smp_proc_pairing_cmpl(p_cb);
+    }
+}
+
+#endif
diff --git a/bt/stack/smp/smp_api.cc b/bt/stack/smp/smp_api.cc
new file mode 100644
index 0000000..7fcda63
--- /dev/null
+++ b/bt/stack/smp/smp_api.cc
@@ -0,0 +1,622 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 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 SMP interface used by
+ *  applications that can run over an SMP.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "stack_config.h"
+
+#if (SMP_INCLUDED == TRUE)
+    #include "smp_int.h"
+    #include "smp_api.h"
+    #include "l2cdefs.h"
+    #include "l2c_int.h"
+    #include "btm_int.h"
+    #include "hcimsgs.h"
+
+    #include "btu.h"
+    #include "p_256_ecc_pp.h"
+
+/*******************************************************************************
+**
+** Function         SMP_Init
+**
+** Description      This function initializes the SMP unit.
+**
+** Returns          void
+**
+*******************************************************************************/
+void SMP_Init(void)
+{
+    memset(&smp_cb, 0, sizeof(tSMP_CB));
+    smp_cb.smp_rsp_timer_ent = alarm_new("smp.smp_rsp_timer_ent");
+    smp_cb.delayed_auth_timer_ent = alarm_new("smp.delayed_auth_timer_ent");
+
+#if defined(SMP_INITIAL_TRACE_LEVEL)
+    smp_cb.trace_level = SMP_INITIAL_TRACE_LEVEL;
+#else
+    smp_cb.trace_level = BT_TRACE_LEVEL_NONE;    /* No traces */
+#endif
+    SMP_TRACE_EVENT ("%s", __func__);
+
+    smp_l2cap_if_init();
+    /* initialization of P-256 parameters */
+    p_256_init_curve(KEY_LENGTH_DWORDS_P256);
+
+    /* Initialize failure case for certification */
+    smp_cb.cert_failure = stack_config_get_interface()->get_pts_smp_failure_case();
+    if (smp_cb.cert_failure)
+        SMP_TRACE_ERROR ("%s PTS FAILURE MODE IN EFFECT (CASE %d)", __func__, smp_cb.cert_failure);
+}
+
+
+/*******************************************************************************
+**
+** Function         SMP_SetTraceLevel
+**
+** Description      This function sets the trace level for SMP.  If called with
+**                  a value of 0xFF, it simply returns the current trace level.
+**
+**                  Input Parameters:
+**                      level:  The level to set the GATT tracing to:
+**                      0xff-returns the current setting.
+**                      0-turns off tracing.
+**                      >= 1-Errors.
+**                      >= 2-Warnings.
+**                      >= 3-APIs.
+**                      >= 4-Events.
+**                      >= 5-Debug.
+**
+** Returns          The new or current trace level
+**
+*******************************************************************************/
+extern uint8_t SMP_SetTraceLevel (uint8_t new_level)
+{
+    if (new_level != 0xFF)
+        smp_cb.trace_level = new_level;
+
+    return(smp_cb.trace_level);
+}
+
+
+/*******************************************************************************
+**
+** Function         SMP_Register
+**
+** Description      This function register for the SMP services callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+bool    SMP_Register (tSMP_CALLBACK *p_cback)
+{
+    SMP_TRACE_EVENT ("SMP_Register state=%d", smp_cb.state);
+
+    if (smp_cb.p_callback != NULL)
+    {
+        SMP_TRACE_ERROR ("SMP_Register: duplicate registration, overwrite it");
+    }
+    smp_cb.p_callback = p_cback;
+
+    return(true);
+
+}
+
+/*******************************************************************************
+**
+** Function         SMP_Pair
+**
+** Description      This function call to perform a SMP pairing with peer device.
+**                  Device support one SMP pairing at one time.
+**
+** Parameters       bd_addr - peer device bd address.
+**
+** Returns          None
+**
+*******************************************************************************/
+tSMP_STATUS SMP_Pair (BD_ADDR bd_addr)
+{
+    tSMP_CB   *p_cb = &smp_cb;
+    uint8_t   status = SMP_PAIR_INTERNAL_ERR;
+
+    SMP_TRACE_EVENT ("%s state=%d br_state=%d flag=0x%x ",
+                      __func__, p_cb->state, p_cb->br_state, p_cb->flags);
+    if (p_cb->state != SMP_STATE_IDLE || p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD ||
+        p_cb->smp_over_br)
+    {
+        /* pending security on going, reject this one */
+        return SMP_BUSY;
+    }
+    else
+    {
+        p_cb->flags = SMP_PAIR_FLAGS_WE_STARTED_DD;
+
+        memcpy (p_cb->pairing_bda, bd_addr, BD_ADDR_LEN);
+
+        if (!L2CA_ConnectFixedChnl (L2CAP_SMP_CID, bd_addr))
+        {
+            SMP_TRACE_ERROR("%s: L2C connect fixed channel failed.", __func__);
+            smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+            return status;
+        }
+
+        return SMP_STARTED;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         SMP_BR_PairWith
+**
+** Description      This function is called to start a SMP pairing over BR/EDR.
+**                  Device support one SMP pairing at one time.
+**
+** Parameters       bd_addr - peer device bd address.
+**
+** Returns          SMP_STARTED if pairing started, otherwise reason for failure.
+**
+*******************************************************************************/
+tSMP_STATUS SMP_BR_PairWith (BD_ADDR bd_addr)
+{
+    tSMP_CB   *p_cb = &smp_cb;
+    uint8_t   status = SMP_PAIR_INTERNAL_ERR;
+
+    SMP_TRACE_EVENT ("%s state=%d br_state=%d flag=0x%x ",
+                      __func__, p_cb->state, p_cb->br_state, p_cb->flags);
+
+    if (p_cb->state != SMP_STATE_IDLE ||
+        p_cb->smp_over_br ||
+        p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)
+    {
+        /* pending security on going, reject this one */
+        return SMP_BUSY;
+    }
+
+    p_cb->role = HCI_ROLE_MASTER;
+    p_cb->flags = SMP_PAIR_FLAGS_WE_STARTED_DD;
+    p_cb->smp_over_br = true;
+
+    memcpy (p_cb->pairing_bda, bd_addr, BD_ADDR_LEN);
+
+    if (!L2CA_ConnectFixedChnl (L2CAP_SMP_BR_CID, bd_addr))
+    {
+        SMP_TRACE_ERROR("%s: L2C connect fixed channel failed.",__func__);
+        smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &status);
+        return status;
+    }
+
+    return SMP_STARTED;
+}
+
+/*******************************************************************************
+**
+** Function         SMP_PairCancel
+**
+** Description      This function call to cancel a SMP pairing with peer device.
+**
+** Parameters       bd_addr - peer device bd address.
+**
+** Returns          true - Pairining is cancelled
+**
+*******************************************************************************/
+bool    SMP_PairCancel (BD_ADDR bd_addr)
+{
+    tSMP_CB   *p_cb = &smp_cb;
+    uint8_t   err_code = SMP_PAIR_FAIL_UNKNOWN;
+    bool      status = false;
+
+    // PTS SMP failure test cases
+    if (p_cb->cert_failure == 7)
+        err_code = SMP_PASSKEY_ENTRY_FAIL;
+    else if (p_cb->cert_failure == 8)
+        err_code = SMP_NUMERIC_COMPAR_FAIL;
+
+    BTM_TRACE_EVENT ("SMP_CancelPair state=%d flag=0x%x ", p_cb->state, p_cb->flags);
+    if ( (p_cb->state != SMP_STATE_IDLE)  &&
+         (!memcmp (p_cb->pairing_bda, bd_addr, BD_ADDR_LEN)) )
+    {
+        p_cb->is_pair_cancel = true;
+        SMP_TRACE_DEBUG("Cancel Pairing: set fail reason Unknown");
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &err_code);
+        status = true;
+    }
+
+    return status;
+}
+/*******************************************************************************
+**
+** Function         SMP_SecurityGrant
+**
+** Description      This function is called to grant security process.
+**
+** Parameters       bd_addr - peer device bd address.
+**                  res     - result of the operation SMP_SUCCESS if success.
+**                            Otherwise, SMP_REPEATED_ATTEMPTS is too many attempts.
+**
+** Returns          None
+**
+*******************************************************************************/
+void SMP_SecurityGrant(BD_ADDR bd_addr, uint8_t res)
+{
+    SMP_TRACE_EVENT ("SMP_SecurityGrant ");
+
+    if (smp_cb.smp_over_br)
+    {
+        if (smp_cb.br_state != SMP_BR_STATE_WAIT_APP_RSP ||
+            smp_cb.cb_evt != SMP_SEC_REQUEST_EVT ||
+            memcmp (smp_cb.pairing_bda, bd_addr, BD_ADDR_LEN))
+        {
+            return;
+        }
+
+        /* clear the SMP_SEC_REQUEST_EVT event after get grant */
+        /* avoid generating duplicate pair request */
+        smp_cb.cb_evt = 0;
+        smp_br_state_machine_event(&smp_cb, SMP_BR_API_SEC_GRANT_EVT, &res);
+        return;
+    }
+
+    if (smp_cb.state != SMP_STATE_WAIT_APP_RSP ||
+        smp_cb.cb_evt != SMP_SEC_REQUEST_EVT ||
+        memcmp (smp_cb.pairing_bda, bd_addr, BD_ADDR_LEN))
+        return;
+    /* clear the SMP_SEC_REQUEST_EVT event after get grant */
+    /* avoid generate duplicate pair request */
+    smp_cb.cb_evt = 0;
+    smp_sm_event(&smp_cb, SMP_API_SEC_GRANT_EVT, &res);
+}
+
+/*******************************************************************************
+**
+** Function         SMP_PasskeyReply
+**
+** 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 SMP_PasskeyReply (BD_ADDR bd_addr, uint8_t res, uint32_t passkey)
+{
+    tSMP_CB *p_cb = & smp_cb;
+    uint8_t failure = SMP_PASSKEY_ENTRY_FAIL;
+
+    SMP_TRACE_EVENT ("SMP_PasskeyReply: Key: %d  Result:%d",
+                      passkey, res);
+
+    /* If timeout already expired or has been canceled, ignore the reply */
+    if (p_cb->cb_evt != SMP_PASSKEY_REQ_EVT)
+    {
+        SMP_TRACE_WARNING ("SMP_PasskeyReply() - Wrong State: %d", p_cb->state);
+        return;
+    }
+
+    if (memcmp (bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0)
+    {
+        SMP_TRACE_ERROR ("SMP_PasskeyReply() - Wrong BD Addr");
+        return;
+    }
+
+    if (btm_find_dev (bd_addr) == NULL)
+    {
+        SMP_TRACE_ERROR ("SMP_PasskeyReply() - no dev CB");
+        return;
+    }
+
+    if (passkey > BTM_MAX_PASSKEY_VAL || res != SMP_SUCCESS)
+    {
+        SMP_TRACE_WARNING ("SMP_PasskeyReply() - Wrong key len: %d or passkey entry fail", passkey);
+        /* send pairing failure */
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+
+    }
+    else if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_PASSKEY_ENT)
+    {
+        smp_sm_event(&smp_cb, SMP_SC_KEY_READY_EVT, &passkey);
+    }
+    else
+    {
+        smp_convert_string_to_tk(p_cb->tk, passkey);
+    }
+
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         SMP_ConfirmReply
+**
+** 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 SMP_SUCCESS if success
+**
+*******************************************************************************/
+void SMP_ConfirmReply (BD_ADDR bd_addr, uint8_t res)
+{
+    tSMP_CB *p_cb = & smp_cb;
+    uint8_t failure = SMP_NUMERIC_COMPAR_FAIL;
+
+    SMP_TRACE_EVENT ("%s: Result:%d", __func__, res);
+
+    /* If timeout already expired or has been canceled, ignore the reply */
+    if (p_cb->cb_evt != SMP_NC_REQ_EVT)
+    {
+        SMP_TRACE_WARNING ("%s() - Wrong State: %d", __func__,p_cb->state);
+        return;
+    }
+
+    if (memcmp (bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0)
+    {
+        SMP_TRACE_ERROR ("%s() - Wrong BD Addr",__func__);
+        return;
+    }
+
+    if (btm_find_dev (bd_addr) == NULL)
+    {
+        SMP_TRACE_ERROR ("%s() - no dev CB",__func__);
+        return;
+    }
+
+    if (res != SMP_SUCCESS)
+    {
+        SMP_TRACE_WARNING ("%s() - Numeric Comparison fails",__func__);
+        /* send pairing failure */
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+    }
+    else
+    {
+        smp_sm_event(p_cb, SMP_SC_NC_OK_EVT, NULL);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         SMP_OobDataReply
+**
+** Description      This function is called to provide the OOB data for
+**                  SMP in response to SMP_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 SMP_OobDataReply(BD_ADDR bd_addr, tSMP_STATUS res, uint8_t len, uint8_t *p_data)
+{
+    tSMP_CB *p_cb = & smp_cb;
+    uint8_t failure = SMP_OOB_FAIL;
+    tSMP_KEY        key;
+
+    SMP_TRACE_EVENT ("%s State: %d  res:%d", __func__, smp_cb.state, res);
+
+    /* If timeout already expired or has been canceled, ignore the reply */
+    if (p_cb->state != SMP_STATE_WAIT_APP_RSP || p_cb->cb_evt != SMP_OOB_REQ_EVT)
+        return;
+
+    if (res != SMP_SUCCESS || len == 0 || !p_data)
+    {
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+    }
+    else
+    {
+        if (len > BT_OCTET16_LEN)
+            len = BT_OCTET16_LEN;
+
+        memcpy(p_cb->tk, p_data, len);
+
+        key.key_type    = SMP_KEY_TYPE_TK;
+        key.p_data      = p_cb->tk;
+
+        smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &key);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         SMP_SecureConnectionOobDataReply
+**
+** Description      This function is called to provide the SC OOB data for
+**                  SMP in response to SMP_SC_OOB_REQ_EVT
+**
+** Parameters:      p_data      - pointer to the data
+**
+*******************************************************************************/
+void SMP_SecureConnectionOobDataReply(uint8_t *p_data)
+{
+    tSMP_CB  *p_cb = &smp_cb;
+
+    uint8_t failure = SMP_OOB_FAIL;
+    tSMP_SC_OOB_DATA  *p_oob = (tSMP_SC_OOB_DATA *) p_data;
+    if (!p_oob)
+    {
+        SMP_TRACE_ERROR("%s received no data",__func__);
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+        return;
+    }
+
+    SMP_TRACE_EVENT ("%s req_oob_type: %d, loc_oob_data.present: %d, "
+                       "peer_oob_data.present: %d",
+                       __func__, p_cb->req_oob_type, p_oob->loc_oob_data.present,
+                       p_oob->peer_oob_data.present);
+
+    if (p_cb->state != SMP_STATE_WAIT_APP_RSP || p_cb->cb_evt != SMP_SC_OOB_REQ_EVT)
+        return;
+
+    bool     data_missing = false;
+    switch (p_cb->req_oob_type)
+    {
+        case SMP_OOB_PEER:
+            if (!p_oob->peer_oob_data.present)
+                data_missing = true;
+            break;
+        case SMP_OOB_LOCAL:
+            if (!p_oob->loc_oob_data.present)
+                data_missing = true;
+            break;
+        case SMP_OOB_BOTH:
+            if (!p_oob->loc_oob_data.present || !p_oob->peer_oob_data.present)
+                data_missing = true;
+            break;
+        default:
+            SMP_TRACE_EVENT ("Unexpected OOB data type requested. Fail OOB");
+            data_missing = true;
+            break;
+    }
+
+    if (data_missing)
+    {
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+        return;
+    }
+
+    p_cb->sc_oob_data = *p_oob;
+
+    smp_sm_event(&smp_cb, SMP_SC_OOB_DATA_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function         SMP_Encrypt
+**
+** Description      This function is called to encrypt the data with the specified
+**                  key
+**
+** Parameters:      key                 - Pointer to key key[0] conatins the MSB
+**                  key_len             - key length
+**                  plain_text          - Pointer to data to be encrypted
+**                                        plain_text[0] conatins the MSB
+**                  pt_len              - plain text length
+**                  p_out                - output of the encrypted texts
+**
+**  Returns         Boolean - request is successful
+*******************************************************************************/
+bool    SMP_Encrypt (uint8_t *key, uint8_t key_len,
+                     uint8_t *plain_text, uint8_t pt_len,
+                     tSMP_ENC *p_out)
+
+{
+    bool    status=false;
+    status = smp_encrypt_data(key, key_len, plain_text, pt_len, p_out);
+    return status;
+}
+
+/*******************************************************************************
+**
+** Function         SMP_KeypressNotification
+**
+** Description      This function is called to notify Security Manager about Keypress Notification.
+**
+** Parameters:     bd_addr      Address of the device to send keypress notification to
+**                 value        Keypress notification parameter value
+**
+*******************************************************************************/
+void SMP_KeypressNotification (BD_ADDR bd_addr, uint8_t value)
+{
+    tSMP_CB   *p_cb = &smp_cb;
+
+    SMP_TRACE_EVENT ("%s: Value: %d", __func__,value);
+
+    if (memcmp (bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0)
+    {
+        SMP_TRACE_ERROR ("%s() - Wrong BD Addr",__func__);
+        return;
+    }
+
+    if (btm_find_dev (bd_addr) == NULL)
+    {
+        SMP_TRACE_ERROR ("%s() - no dev CB",__func__);
+        return;
+    }
+
+    /* Keypress Notification is used by a device with KeyboardOnly IO capabilities */
+    /* during the passkey entry protocol */
+    if (p_cb->local_io_capability != SMP_IO_CAP_IN)
+    {
+        SMP_TRACE_ERROR ("%s() - wrong local IO capabilities %d",
+                          __func__, p_cb->local_io_capability);
+        return;
+    }
+
+    if (p_cb->selected_association_model != SMP_MODEL_SEC_CONN_PASSKEY_ENT)
+    {
+        SMP_TRACE_ERROR ("%s() - wrong protocol %d", __func__,
+                         p_cb->selected_association_model);
+        return;
+    }
+
+    smp_sm_event(p_cb, SMP_KEYPRESS_NOTIFICATION_EVENT, &value);
+}
+
+/*******************************************************************************
+**
+** Function         SMP_CreateLocalSecureConnectionsOobData
+**
+** Description      This function is called to start creation of local SC OOB
+**                  data set (tSMP_LOC_OOB_DATA).
+**
+** Parameters:      bd_addr      - Address of the device to send OOB data block to
+**
+**  Returns         Boolean - true: creation of local SC OOB data set started.
+*******************************************************************************/
+bool    SMP_CreateLocalSecureConnectionsOobData (tBLE_BD_ADDR *addr_to_send_to)
+{
+    tSMP_CB *p_cb = &smp_cb;
+    uint8_t *bd_addr;
+
+    if (addr_to_send_to == NULL)
+    {
+        SMP_TRACE_ERROR ("%s addr_to_send_to is not provided",__func__);
+        return false;
+    }
+
+    bd_addr = addr_to_send_to->bda;
+
+    SMP_TRACE_EVENT ("%s addr type: %u,  BDA: %08x%04x,  state: %u, br_state: %u",
+                      __func__, addr_to_send_to->type,
+                      (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8) + bd_addr[3],
+                      (bd_addr[4]<<8)+bd_addr[5],
+                      p_cb->state,
+                      p_cb->br_state);
+
+    if ((p_cb->state != SMP_STATE_IDLE) || (p_cb->smp_over_br))
+    {
+        SMP_TRACE_WARNING ("%s creation of local OOB data set "\
+            "starts only in IDLE state",__func__);
+        return false;
+    }
+
+    p_cb->sc_oob_data.loc_oob_data.addr_sent_to = *addr_to_send_to;
+    smp_sm_event(p_cb, SMP_CR_LOC_SC_OOB_DATA_EVT, NULL);
+
+    return true;
+}
+
+#endif /* SMP_INCLUDED */
diff --git a/bt/stack/smp/smp_br_main.cc b/bt/stack/smp/smp_br_main.cc
new file mode 100644
index 0000000..dbeea27
--- /dev/null
+++ b/bt/stack/smp/smp_br_main.cc
@@ -0,0 +1,399 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014-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.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#include <string.h>
+#include "smp_int.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+const char *const smp_br_state_name [SMP_BR_STATE_MAX+1] =
+{
+    "SMP_BR_STATE_IDLE",
+    "SMP_BR_STATE_WAIT_APP_RSP",
+    "SMP_BR_STATE_PAIR_REQ_RSP",
+    "SMP_BR_STATE_BOND_PENDING",
+    "SMP_BR_STATE_OUT_OF_RANGE"
+};
+
+const char *const smp_br_event_name [SMP_BR_MAX_EVT] =
+{
+    "BR_PAIRING_REQ_EVT",
+    "BR_PAIRING_RSP_EVT",
+    "BR_CONFIRM_EVT",
+    "BR_RAND_EVT",
+    "BR_PAIRING_FAILED_EVT",
+    "BR_ENCRPTION_INFO_EVT",
+    "BR_MASTER_ID_EVT",
+    "BR_ID_INFO_EVT",
+    "BR_ID_ADDR_EVT",
+    "BR_SIGN_INFO_EVT",
+    "BR_SECURITY_REQ_EVT",
+    "BR_PAIR_PUBLIC_KEY_EVT",
+    "BR_PAIR_DHKEY_CHCK_EVT",
+    "BR_PAIR_KEYPR_NOTIF_EVT",
+    "BR_KEY_READY_EVT",
+    "BR_ENCRYPTED_EVT",
+    "BR_L2CAP_CONN_EVT",
+    "BR_L2CAP_DISCONN_EVT",
+    "BR_KEYS_RSP_EVT",
+    "BR_API_SEC_GRANT_EVT",
+    "BR_TK_REQ_EVT",
+    "BR_AUTH_CMPL_EVT",
+    "BR_ENC_REQ_EVT",
+    "BR_BOND_REQ_EVT",
+    "BR_DISCARD_SEC_REQ_EVT",
+    "BR_OUT_OF_RANGE_EVT"
+};
+
+const char *smp_get_br_event_name(tSMP_BR_EVENT event);
+const char *smp_get_br_state_name(tSMP_BR_STATE state);
+
+#define SMP_BR_SM_IGNORE       0
+#define SMP_BR_NUM_ACTIONS     2
+#define SMP_BR_SME_NEXT_STATE  2
+#define SMP_BR_SM_NUM_COLS     3
+typedef const uint8_t (*tSMP_BR_SM_TBL)[SMP_BR_SM_NUM_COLS];
+
+enum
+{
+    SMP_SEND_PAIR_REQ,
+    SMP_BR_SEND_PAIR_RSP,
+    SMP_SEND_PAIR_FAIL,
+    SMP_SEND_ID_INFO,
+    SMP_BR_PROC_PAIR_CMD,
+    SMP_PROC_PAIR_FAIL,
+    SMP_PROC_ID_INFO,
+    SMP_PROC_ID_ADDR,
+    SMP_PROC_SRK_INFO,
+    SMP_BR_PROC_SEC_GRANT,
+    SMP_BR_PROC_SL_KEYS_RSP,
+    SMP_BR_KEY_DISTRIBUTION,
+    SMP_BR_PAIRING_COMPLETE,
+    SMP_SEND_APP_CBACK,
+    SMP_BR_CHECK_AUTH_REQ,
+    SMP_PAIR_TERMINATE,
+    SMP_IDLE_TERMINATE,
+    SMP_BR_SM_NO_ACTION
+};
+
+static const tSMP_ACT smp_br_sm_action[] =
+{
+    smp_send_pair_req,
+    smp_br_send_pair_response,
+    smp_send_pair_fail,
+    smp_send_id_info,
+    smp_br_process_pairing_command,
+    smp_proc_pair_fail,
+    smp_proc_id_info,
+    smp_proc_id_addr,
+    smp_proc_srk_info,
+    smp_br_process_security_grant,
+    smp_br_process_slave_keys_response,
+    smp_br_select_next_key,
+    smp_br_pairing_complete,
+    smp_send_app_cback,
+    smp_br_check_authorization_request,
+    smp_pair_terminate,
+    smp_idle_terminate
+};
+
+static const uint8_t smp_br_all_table[][SMP_BR_SM_NUM_COLS] =
+{
+/*                               Event                    Action           Next State */
+/* BR_PAIRING_FAILED        */  {SMP_PROC_PAIR_FAIL,  SMP_BR_PAIRING_COMPLETE, SMP_BR_STATE_IDLE},
+/* BR_AUTH_CMPL             */  {SMP_SEND_PAIR_FAIL,  SMP_BR_PAIRING_COMPLETE, SMP_BR_STATE_IDLE},
+/* BR_L2CAP_DISCONN         */  {SMP_PAIR_TERMINATE,  SMP_BR_SM_NO_ACTION, SMP_BR_STATE_IDLE}
+};
+
+/************ SMP Master FSM State/Event Indirection Table **************/
+static const uint8_t smp_br_master_entry_map[][SMP_BR_STATE_MAX] =
+{
+/* br_state name:               Idle      WaitApp  Pair    Bond
+                                          Rsp      ReqRsp  Pend       */
+/* BR_PAIRING_REQ           */  { 0,       0,       0,      0     },
+/* BR_PAIRING_RSP           */  { 0,       0,       1,      0     },
+/* BR_CONFIRM               */  { 0,       0,       0,      0     },
+/* BR_RAND                  */  { 0,       0,       0,      0     },
+/* BR_PAIRING_FAILED        */  { 0,       0x81,    0x81,   0     },
+/* BR_ENCRPTION_INFO        */  { 0,       0,       0,      0     },
+/* BR_MASTER_ID             */  { 0,       0,       0,      0     },
+/* BR_ID_INFO               */  { 0,       0,       0,      1     },
+/* BR_ID_ADDR               */  { 0,       0,       0,      2     },
+/* BR_SIGN_INFO             */  { 0,       0,       0,      3     },
+/* BR_SECURITY_REQ          */  { 0,       0,       0,      0     },
+/* BR_PAIR_PUBLIC_KEY_EVT   */  { 0,       0,       0,      0     },
+/* BR_PAIR_DHKEY_CHCK_EVT   */  { 0,       0,       0,      0     },
+/* BR_PAIR_KEYPR_NOTIF_EVT  */  { 0,       0,       0,      0     },
+/* BR_KEY_READY             */  { 0,       0,       0,      0     },
+/* BR_ENCRYPTED             */  { 0,       0,       0,      0     },
+/* BR_L2CAP_CONN            */  { 1,       0,       0,      0     },
+/* BR_L2CAP_DISCONN         */  { 2,       0x83,    0x83,   0x83  },
+/* BR_KEYS_RSP              */  { 0,       1,       0,      0     },
+/* BR_API_SEC_GRANT         */  { 0,       0,       0,      0     },
+/* BR_TK_REQ                */  { 0,       0,       0,      0     },
+/* BR_AUTH_CMPL             */  { 0,       0x82,    0x82,   0x82  },
+/* BR_ENC_REQ               */  { 0,       0,       0,      0     },
+/* BR_BOND_REQ              */  { 0,       0,       2,      0     },
+/* BR_DISCARD_SEC_REQ       */  { 0,       0,       0,      0     }
+};
+
+static const uint8_t smp_br_master_idle_table[][SMP_BR_SM_NUM_COLS] =
+{
+/*                                Event               Action               Next State */
+/* BR_L2CAP_CONN        */  {SMP_SEND_APP_CBACK, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_WAIT_APP_RSP},
+/* BR_L2CAP_DISCONN   */  {SMP_IDLE_TERMINATE,  SMP_BR_SM_NO_ACTION, SMP_BR_STATE_IDLE}
+};
+
+static const uint8_t smp_br_master_wait_appln_response_table[][SMP_BR_SM_NUM_COLS] =
+{
+/*                                Event               Action              Next State */
+/* BR_KEYS_RSP           */{SMP_SEND_PAIR_REQ, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_PAIR_REQ_RSP}
+};
+
+static const uint8_t smp_br_master_pair_request_response_table [][SMP_BR_SM_NUM_COLS] =
+{
+/*                        Event               Action                  Next State */
+/* BR_PAIRING_RSP   */  {SMP_BR_PROC_PAIR_CMD, SMP_BR_CHECK_AUTH_REQ, SMP_BR_STATE_PAIR_REQ_RSP},
+/* BR_BOND_REQ      */  {SMP_BR_SM_NO_ACTION, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING}
+};
+
+static const uint8_t smp_br_master_bond_pending_table[][SMP_BR_SM_NUM_COLS] =
+{
+/*                                Event               Action              Next State */
+/* BR_ID_INFO               */{SMP_PROC_ID_INFO, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING},
+/* BR_ID_ADDR               */{SMP_PROC_ID_ADDR, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING},
+/* BR_SIGN_INFO             */{SMP_PROC_SRK_INFO, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING}
+};
+
+static const uint8_t smp_br_slave_entry_map[][SMP_BR_STATE_MAX] =
+{
+/* br_state name:               Idle      WaitApp  Pair    Bond
+                                          Rsp      ReqRsp  Pend      */
+/* BR_PAIRING_REQ           */  { 1,       0,       0,      0    },
+/* BR_PAIRING_RSP           */  { 0,       0,       0,      0    },
+/* BR_CONFIRM               */  { 0,       0,       0,      0    },
+/* BR_RAND                  */  { 0,       0,       0,      0    },
+/* BR_PAIRING_FAILED        */  { 0,       0x81,    0x81,   0x81 },
+/* BR_ENCRPTION_INFO        */  { 0,       0,       0,      0    },
+/* BR_MASTER_ID             */  { 0,       0,       0,      0    },
+/* BR_ID_INFO               */  { 0,       0,       0,      1    },
+/* BR_ID_ADDR               */  { 0,       0,       0,      2    },
+/* BR_SIGN_INFO             */  { 0,       0,       0,      3    },
+/* BR_SECURITY_REQ          */  { 0,       0,       0,      0    },
+/* BR_PAIR_PUBLIC_KEY_EVT   */  { 0,       0,       0,      0    },
+/* BR_PAIR_DHKEY_CHCK_EVT   */  { 0,       0,       0,      0    },
+/* BR_PAIR_KEYPR_NOTIF_EVT  */  { 0,       0,       0,      0    },
+/* BR_KEY_READY             */  { 0,       0,       0,      0    },
+/* BR_ENCRYPTED             */  { 0,       0,       0,      0    },
+/* BR_L2CAP_CONN            */  { 0,       0,       0,      0    },
+/* BR_L2CAP_DISCONN         */  { 0,       0x83,    0x83,   0x83 },
+/* BR_KEYS_RSP              */  { 0,       2,       0,      0    },
+/* BR_API_SEC_GRANT         */  { 0,       1,       0,      0    },
+/* BR_TK_REQ                */  { 0,       0,       0,      0    },
+/* BR_AUTH_CMPL             */  { 0,       0x82,    0x82,   0x82 },
+/* BR_ENC_REQ               */  { 0,       0,       0,      0    },
+/* BR_BOND_REQ              */  { 0,       3,       0,      0    },
+/* BR_DISCARD_SEC_REQ       */  { 0,       0,       0,      0    }
+};
+
+static const uint8_t smp_br_slave_idle_table[][SMP_BR_SM_NUM_COLS] =
+{
+/*                               Event                Action              Next State */
+/* BR_PAIRING_REQ    */ {SMP_BR_PROC_PAIR_CMD, SMP_SEND_APP_CBACK, SMP_BR_STATE_WAIT_APP_RSP}
+};
+
+static const uint8_t smp_br_slave_wait_appln_response_table [][SMP_BR_SM_NUM_COLS] =
+{
+/*                               Event                 Action             Next State */
+/* BR_API_SEC_GRANT */ {SMP_BR_PROC_SEC_GRANT, SMP_SEND_APP_CBACK, SMP_BR_STATE_WAIT_APP_RSP},
+/* BR_KEYS_RSP     */{SMP_BR_PROC_SL_KEYS_RSP, SMP_BR_CHECK_AUTH_REQ,SMP_BR_STATE_WAIT_APP_RSP},
+/* BR_BOND_REQ        */ {SMP_BR_KEY_DISTRIBUTION, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING}
+};
+
+static const uint8_t smp_br_slave_bond_pending_table[][SMP_BR_SM_NUM_COLS] =
+{
+/*                                Event               Action               Next State */
+/* BR_ID_INFO               */  {SMP_PROC_ID_INFO, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING},
+/* BR_ID_ADDR               */  {SMP_PROC_ID_ADDR, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING},
+/* BR_SIGN_INFO             */  {SMP_PROC_SRK_INFO, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING}
+};
+
+static const tSMP_BR_SM_TBL smp_br_state_table[][2] =
+{
+    /* SMP_BR_STATE_IDLE */
+    {smp_br_master_idle_table, smp_br_slave_idle_table},
+
+    /* SMP_BR_STATE_WAIT_APP_RSP */
+    {smp_br_master_wait_appln_response_table, smp_br_slave_wait_appln_response_table},
+
+    /* SMP_BR_STATE_PAIR_REQ_RSP */
+    {smp_br_master_pair_request_response_table, NULL},
+
+    /* SMP_BR_STATE_BOND_PENDING */
+    {smp_br_master_bond_pending_table, smp_br_slave_bond_pending_table},
+};
+
+typedef const uint8_t (*tSMP_BR_ENTRY_TBL)[SMP_BR_STATE_MAX];
+
+static const tSMP_BR_ENTRY_TBL smp_br_entry_table[] =
+{
+    smp_br_master_entry_map,
+    smp_br_slave_entry_map
+};
+
+#define SMP_BR_ALL_TABLE_MASK  0x80
+
+/*******************************************************************************
+** Function     smp_set_br_state
+** Returns      None
+*******************************************************************************/
+void smp_set_br_state(tSMP_BR_STATE br_state)
+{
+    if (br_state < SMP_BR_STATE_MAX)
+    {
+        SMP_TRACE_DEBUG( "BR_State change: %s(%d) ==> %s(%d)",
+                          smp_get_br_state_name(smp_cb.br_state), smp_cb.br_state,
+                          smp_get_br_state_name(br_state), br_state );
+        smp_cb.br_state = br_state;
+    }
+    else
+    {
+        SMP_TRACE_DEBUG("%s invalid br_state =%d", __func__,br_state );
+    }
+}
+
+/*******************************************************************************
+** Function     smp_get_br_state
+** Returns      The smp_br state
+*******************************************************************************/
+tSMP_BR_STATE smp_get_br_state(void)
+{
+    return smp_cb.br_state;
+}
+
+/*******************************************************************************
+** Function     smp_get_br_state_name
+** Returns      The smp_br state name.
+*******************************************************************************/
+const char *smp_get_br_state_name(tSMP_BR_STATE br_state)
+{
+    const char *p_str = smp_br_state_name[SMP_BR_STATE_MAX];
+
+    if (br_state < SMP_BR_STATE_MAX)
+        p_str = smp_br_state_name[br_state];
+
+    return p_str;
+}
+/*******************************************************************************
+** Function     smp_get_br_event_name
+** Returns      The smp_br event name.
+*******************************************************************************/
+const char * smp_get_br_event_name(tSMP_BR_EVENT event)
+{
+    const char * p_str = smp_br_event_name[SMP_BR_MAX_EVT - 1];
+
+    if (event < SMP_BR_MAX_EVT)
+    {
+        p_str = smp_br_event_name[event- 1];
+    }
+    return p_str;
+}
+
+/*******************************************************************************
+**
+** Function     smp_br_state_machine_event
+**
+** Description  Handle events to the state machine. It looks up the entry
+**              in the smp_br_entry_table array.
+**              If it is a valid entry, it gets the state table.Set the next state,
+**              if not NULL state. Execute the action function according to the
+**              state table. If the state returned by action function is not NULL
+**              state, adjust the new state to the returned state.
+**
+** Returns      void.
+**
+*******************************************************************************/
+void smp_br_state_machine_event(tSMP_CB *p_cb, tSMP_BR_EVENT event, void *p_data)
+{
+    tSMP_BR_STATE       curr_state = p_cb->br_state;
+    tSMP_BR_SM_TBL      state_table;
+    uint8_t             action, entry;
+    tSMP_BR_ENTRY_TBL   entry_table =  smp_br_entry_table[p_cb->role];
+
+    SMP_TRACE_EVENT("main %s", __func__);
+    if (curr_state >= SMP_BR_STATE_MAX)
+    {
+        SMP_TRACE_DEBUG( "Invalid br_state: %d", curr_state) ;
+        return;
+    }
+
+    SMP_TRACE_DEBUG( "SMP Role: %s State: [%s (%d)], Event: [%s (%d)]",
+                      (p_cb->role == HCI_ROLE_SLAVE) ? "Slave" : "Master",
+                      smp_get_br_state_name( p_cb->br_state),
+                      p_cb->br_state, smp_get_br_event_name(event), event) ;
+
+    /* look up the state table for the current state */
+    /* lookup entry / w event & curr_state */
+    /* If entry is ignore, return.
+     * Otherwise, get state table (according to curr_state or all_state) */
+    if ((event <= SMP_BR_MAX_EVT) && ( (entry = entry_table[event - 1][curr_state])
+        != SMP_BR_SM_IGNORE ))
+    {
+        if (entry & SMP_BR_ALL_TABLE_MASK)
+        {
+            entry &= ~SMP_BR_ALL_TABLE_MASK;
+            state_table = smp_br_all_table;
+        }
+        else
+        {
+            state_table = smp_br_state_table[curr_state][p_cb->role];
+        }
+    }
+    else
+    {
+        SMP_TRACE_DEBUG( "Ignore event [%s (%d)] in state [%s (%d)]",
+                          smp_get_br_event_name(event), event,
+                          smp_get_br_state_name(curr_state), curr_state);
+        return;
+    }
+
+    /* Get possible next state from state table. */
+
+    smp_set_br_state(state_table[entry - 1][SMP_BR_SME_NEXT_STATE]);
+
+    /* If action is not ignore, clear param, exec action and get next state.
+     * The action function may set the Param for cback.
+     * Depending on param, call cback or free buffer. */
+    /* execute action functions */
+    for (uint8_t i = 0; i < SMP_BR_NUM_ACTIONS; i++)
+    {
+        if ((action = state_table[entry - 1][i]) != SMP_BR_SM_NO_ACTION)
+        {
+            (*smp_br_sm_action[action])(p_cb, (tSMP_INT_DATA *)p_data);
+        }
+        else
+        {
+            break;
+        }
+    }
+    SMP_TRACE_DEBUG( "result state = %s", smp_get_br_state_name( p_cb->br_state ) ) ;
+}
+
+#endif
diff --git a/bt/stack/smp/smp_cmac.cc b/bt/stack/smp/smp_cmac.cc
new file mode 100644
index 0000000..30beb7b
--- /dev/null
+++ b/bt/stack/smp/smp_cmac.cc
@@ -0,0 +1,328 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 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 CMAC algorithm.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if (SMP_INCLUDED == TRUE)
+    #include <stdio.h>
+    #include <string.h>
+
+    #include "btm_ble_api.h"
+    #include "smp_int.h"
+    #include "hcimsgs.h"
+
+typedef struct
+{
+    uint8_t             *text;
+    uint16_t            len;
+    uint16_t            round;
+}tCMAC_CB;
+
+tCMAC_CB    cmac_cb;
+
+/* Rb for AES-128 as block cipher, LSB as [0] */
+BT_OCTET16 const_Rb = {
+    0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+void print128(BT_OCTET16 x, const uint8_t *key_name)
+{
+#if (SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE)
+    uint8_t *p = (uint8_t *)x;
+    uint8_t i;
+
+    SMP_TRACE_WARNING("%s(MSB ~ LSB) = ", key_name);
+
+    for (i = 0; i < 4; i ++)
+    {
+        SMP_TRACE_WARNING("%02x %02x %02x %02x",
+                           p[BT_OCTET16_LEN - i*4 -1], p[BT_OCTET16_LEN - i*4 -2],
+                           p[BT_OCTET16_LEN - i*4 -3], p[BT_OCTET16_LEN - i*4 -4]);
+    }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         padding
+**
+** Description      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 BT_OCTET16_LEN memory space; where include
+**                  length bytes valid data.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void padding ( BT_OCTET16 dest, uint8_t length )
+{
+    uint8_t i, *p = dest;
+    /* original last block */
+    for ( i = length ; i < BT_OCTET16_LEN; i++ )
+        p[BT_OCTET16_LEN - i - 1] = ( i == length ) ? 0x80 : 0;
+}
+/*******************************************************************************
+**
+** Function         leftshift_onebit
+**
+** Description      utility function to left shift one bit for a 128 bits value.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void leftshift_onebit(uint8_t *input, uint8_t *output)
+{
+    uint8_t i, overflow = 0 , next_overflow = 0;
+    SMP_TRACE_EVENT ("leftshift_onebit ");
+    /* input[0] is LSB */
+    for ( i = 0; i < BT_OCTET16_LEN ; i ++ )
+    {
+        next_overflow = (input[i] & 0x80) ? 1:0;
+        output[i] = (input[i] << 1) | overflow;
+        overflow = next_overflow;
+    }
+    return;
+}
+/*******************************************************************************
+**
+** Function         cmac_aes_cleanup
+**
+** Description      clean up function for AES_CMAC algorithm.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void cmac_aes_cleanup(void)
+{
+    osi_free(cmac_cb.text);
+    memset(&cmac_cb, 0, sizeof(tCMAC_CB));
+}
+
+/*******************************************************************************
+**
+** Function         cmac_aes_k_calculate
+**
+** Description      This function is the calculation of block cipher using AES-128.
+**
+** Returns          void
+**
+*******************************************************************************/
+static bool    cmac_aes_k_calculate(BT_OCTET16 key, uint8_t *p_signature, uint16_t tlen)
+{
+    tSMP_ENC output;
+    uint8_t  i = 1, err = 0;
+    uint8_t  x[16] = {0};
+    uint8_t *p_mac;
+
+    SMP_TRACE_EVENT ("cmac_aes_k_calculate ");
+
+    while (i <= cmac_cb.round)
+    {
+        smp_xor_128(&cmac_cb.text[(cmac_cb.round - i)*BT_OCTET16_LEN], x); /* Mi' := Mi (+) X  */
+
+        if (!SMP_Encrypt(key, BT_OCTET16_LEN, &cmac_cb.text[(cmac_cb.round - i)*BT_OCTET16_LEN], BT_OCTET16_LEN, &output))
+        {
+            err = 1;
+            break;
+        }
+
+        memcpy(x, output.param_buf, BT_OCTET16_LEN);
+        i ++;
+    }
+
+    if (!err)
+    {
+        p_mac = output.param_buf + (BT_OCTET16_LEN - tlen);
+        memcpy(p_signature, p_mac, tlen);
+
+        SMP_TRACE_DEBUG("tlen = %d p_mac = %d", tlen, p_mac);
+        SMP_TRACE_DEBUG("p_mac[0] = 0x%02x p_mac[1] = 0x%02x p_mac[2] = 0x%02x p_mac[3] = 0x%02x",
+                         *p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3));
+        SMP_TRACE_DEBUG("p_mac[4] = 0x%02x p_mac[5] = 0x%02x p_mac[6] = 0x%02x p_mac[7] = 0x%02x",
+                         *(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7));
+
+        return true;
+
+    }
+    else
+        return false;
+}
+/*******************************************************************************
+**
+** Function         cmac_prepare_last_block
+**
+** Description      This function proceeed to prepare the last block of message
+**                  Mn depending on the size of the message.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void cmac_prepare_last_block (BT_OCTET16 k1, BT_OCTET16 k2)
+{
+//    uint8_t     x[16] = {0};
+    bool         flag;
+
+    SMP_TRACE_EVENT ("cmac_prepare_last_block ");
+    /* last block is a complete block set flag to 1 */
+    flag = ((cmac_cb.len % BT_OCTET16_LEN) == 0 && cmac_cb.len != 0)  ? true : false;
+
+    SMP_TRACE_WARNING("flag = %d round = %d", flag, cmac_cb.round);
+
+    if ( flag )
+    { /* last block is complete block */
+        smp_xor_128(&cmac_cb.text[0], k1);
+    }
+    else /* padding then xor with k2 */
+    {
+        padding(&cmac_cb.text[0], (uint8_t)(cmac_cb.len % 16));
+
+        smp_xor_128(&cmac_cb.text[0], k2);
+    }
+}
+/*******************************************************************************
+**
+** Function         cmac_subkey_cont
+**
+** Description      This is the callback function when CIPHk(0[128]) is completed.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void cmac_subkey_cont(tSMP_ENC *p)
+{
+    uint8_t k1[BT_OCTET16_LEN], k2[BT_OCTET16_LEN];
+    uint8_t *pp = p->param_buf;
+    SMP_TRACE_EVENT ("cmac_subkey_cont ");
+    print128(pp, (const uint8_t *)"K1 before shift");
+
+    /* If MSB(L) = 0, then K1 = L << 1 */
+    if ( (pp[BT_OCTET16_LEN - 1] & 0x80) != 0 )
+    {
+        /* Else K1 = ( L << 1 ) (+) Rb */
+        leftshift_onebit(pp, k1);
+        smp_xor_128(k1, const_Rb);
+    }
+    else
+    {
+        leftshift_onebit(pp, k1);
+    }
+
+    if ( (k1[BT_OCTET16_LEN - 1] & 0x80) != 0 )
+    {
+        /* K2 =  (K1 << 1) (+) Rb */
+        leftshift_onebit(k1, k2);
+        smp_xor_128(k2, const_Rb);
+    }
+    else
+    {
+        /* If MSB(K1) = 0, then K2 = K1 << 1 */
+        leftshift_onebit(k1, k2);
+    }
+
+    print128(k1, (const uint8_t *)"K1");
+    print128(k2, (const uint8_t *)"K2");
+
+    cmac_prepare_last_block (k1, k2);
+}
+/*******************************************************************************
+**
+** Function         cmac_generate_subkey
+**
+** Description      This is the function to generate the two subkeys.
+**
+** Parameters       key - CMAC key, expect SRK when used by SMP.
+**
+** Returns          void
+**
+*******************************************************************************/
+static bool    cmac_generate_subkey(BT_OCTET16 key)
+{
+    BT_OCTET16 z = {0};
+    bool        ret = true;
+    tSMP_ENC output;
+    SMP_TRACE_EVENT (" cmac_generate_subkey");
+
+    if (SMP_Encrypt(key, BT_OCTET16_LEN, z, BT_OCTET16_LEN, &output))
+    {
+        cmac_subkey_cont(&output);;
+    }
+    else
+        ret = false;
+
+    return ret;
+}
+/*******************************************************************************
+**
+** Function         aes_cipher_msg_auth_code
+**
+** Description      This is the AES-CMAC Generation Function with tlen implemented.
+**
+** Parameters       key - CMAC key in little endian order, expect SRK when used by SMP.
+**                  input - text to be signed in little endian byte order.
+**                  length - length of the input in byte.
+**                  tlen - lenth of mac desired
+**                  p_signature - data pointer to where signed data to be stored, tlen long.
+**
+** Returns          false if out of resources, true in other cases.
+**
+*******************************************************************************/
+bool    aes_cipher_msg_auth_code(BT_OCTET16 key, uint8_t *input, uint16_t length,
+                                 uint16_t tlen, uint8_t *p_signature)
+{
+    uint16_t len, diff;
+    uint16_t n = (length + BT_OCTET16_LEN - 1) / BT_OCTET16_LEN;       /* n is number of rounds */
+    bool    ret = false;
+
+    SMP_TRACE_EVENT ("%s", __func__);
+
+    if (n == 0)  n = 1;
+    len = n * BT_OCTET16_LEN;
+
+    SMP_TRACE_WARNING("AES128_CMAC started, allocate buffer size = %d", len);
+    /* allocate a memory space of multiple of 16 bytes to hold text  */
+    cmac_cb.text = (uint8_t *)osi_calloc(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 */
+    if (cmac_generate_subkey(key)) {
+        /* start calculation */
+        ret = cmac_aes_k_calculate(key, p_signature, tlen);
+    }
+    /* clean up */
+    cmac_aes_cleanup();
+
+    return ret;
+}
+
+#endif
+
diff --git a/bt/stack/smp/smp_int.h b/bt/stack/smp/smp_int.h
new file mode 100644
index 0000000..93256ad
--- /dev/null
+++ b/bt/stack/smp/smp_int.h
@@ -0,0 +1,540 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 internally used SMP definitions
+ *
+ ******************************************************************************/
+#ifndef  SMP_INT_H
+#define  SMP_INT_H
+
+#if (BLE_INCLUDED == TRUE)
+
+#include "btu.h"
+#include "btm_ble_api.h"
+#include "btm_api.h"
+#include "smp_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SMP_MODEL_ENCRYPTION_ONLY  0   /* Legacy mode, Just Works model */
+#define SMP_MODEL_PASSKEY       1   /* Legacy mode, Passkey Entry model, this side inputs the key */
+#define SMP_MODEL_OOB           2   /* Legacy mode, OOB model */
+#define SMP_MODEL_KEY_NOTIF     3   /* Legacy mode, Passkey Entry model, this side displays the key */
+#define SMP_MODEL_SEC_CONN_JUSTWORKS  4  /* Secure Connections mode, Just Works model */
+#define SMP_MODEL_SEC_CONN_NUM_COMP   5  /* Secure Connections mode, Numeric Comparison model */
+#define SMP_MODEL_SEC_CONN_PASSKEY_ENT 6 /* Secure Connections mode, Passkey Entry model, */
+                                    /* this side inputs the key */
+#define SMP_MODEL_SEC_CONN_PASSKEY_DISP 7   /* Secure Connections mode, Passkey Entry model, */
+                                    /* this side displays the key */
+#define SMP_MODEL_SEC_CONN_OOB  8   /* Secure Connections mode, OOB model */
+#define SMP_MODEL_OUT_OF_RANGE  9
+typedef uint8_t tSMP_ASSO_MODEL;
+
+
+#ifndef SMP_MAX_CONN
+    #define SMP_MAX_CONN    2
+#endif
+
+#define SMP_WAIT_FOR_RSP_TIMEOUT_MS      (30 * 1000)
+#define SMP_DELAYED_AUTH_TIMEOUT_MS      500
+
+#define SMP_OPCODE_INIT                   0x04
+
+/* SMP events */
+#define SMP_PAIRING_REQ_EVT             SMP_OPCODE_PAIRING_REQ
+#define SMP_PAIRING_RSP_EVT             SMP_OPCODE_PAIRING_RSP
+#define SMP_CONFIRM_EVT                 SMP_OPCODE_CONFIRM
+#define SMP_RAND_EVT                    SMP_OPCODE_RAND
+#define SMP_PAIRING_FAILED_EVT          SMP_OPCODE_PAIRING_FAILED
+#define SMP_ENCRPTION_INFO_EVT          SMP_OPCODE_ENCRYPT_INFO
+#define SMP_MASTER_ID_EVT               SMP_OPCODE_MASTER_ID
+#define SMP_ID_INFO_EVT                 SMP_OPCODE_IDENTITY_INFO
+#define SMP_ID_ADDR_EVT                 SMP_OPCODE_ID_ADDR
+#define SMP_SIGN_INFO_EVT               SMP_OPCODE_SIGN_INFO
+#define SMP_SECURITY_REQ_EVT            SMP_OPCODE_SEC_REQ
+
+#define SMP_PAIR_PUBLIC_KEY_EVT         SMP_OPCODE_PAIR_PUBLIC_KEY
+#define SMP_PAIR_KEYPRESS_NOTIFICATION_EVT SMP_OPCODE_PAIR_KEYPR_NOTIF
+
+#define SMP_PAIR_COMMITM_EVT            SMP_OPCODE_PAIR_COMMITM
+
+#define SMP_SELF_DEF_EVT                (SMP_PAIR_COMMITM_EVT + 1)
+#define SMP_KEY_READY_EVT               (SMP_SELF_DEF_EVT)
+#define SMP_ENCRYPTED_EVT               (SMP_SELF_DEF_EVT + 1)
+#define SMP_L2CAP_CONN_EVT              (SMP_SELF_DEF_EVT + 2)
+#define SMP_L2CAP_DISCONN_EVT           (SMP_SELF_DEF_EVT + 3)
+#define SMP_IO_RSP_EVT                  (SMP_SELF_DEF_EVT + 4)
+#define SMP_API_SEC_GRANT_EVT           (SMP_SELF_DEF_EVT + 5)
+#define SMP_TK_REQ_EVT                  (SMP_SELF_DEF_EVT + 6)
+#define SMP_AUTH_CMPL_EVT               (SMP_SELF_DEF_EVT + 7)
+#define SMP_ENC_REQ_EVT                 (SMP_SELF_DEF_EVT + 8)
+#define SMP_BOND_REQ_EVT                (SMP_SELF_DEF_EVT + 9)
+#define SMP_DISCARD_SEC_REQ_EVT         (SMP_SELF_DEF_EVT + 10)
+
+#define SMP_PAIR_DHKEY_CHCK_EVT         SMP_OPCODE_PAIR_DHKEY_CHECK
+
+#define SMP_PUBL_KEY_EXCH_REQ_EVT       (SMP_SELF_DEF_EVT + 11) /* request to start public */
+                                                                /* key exchange */
+
+#define SMP_LOC_PUBL_KEY_CRTD_EVT       (SMP_SELF_DEF_EVT + 12) /* local public key created */
+
+#define SMP_BOTH_PUBL_KEYS_RCVD_EVT     (SMP_SELF_DEF_EVT + 13) /* both local and peer public */
+                                                                /* keys are saved in cb */
+
+#define SMP_SC_DHKEY_CMPLT_EVT          (SMP_SELF_DEF_EVT + 14) /* DHKey computation is completed,*/
+                                                                /* time to start SC phase1 */
+
+#define SMP_HAVE_LOC_NONCE_EVT          (SMP_SELF_DEF_EVT + 15) /* new local nonce is generated */
+                                                                /*and saved in p_cb->rand */
+
+#define SMP_SC_PHASE1_CMPLT_EVT         (SMP_SELF_DEF_EVT + 16) /* time to start SC phase2 */
+
+#define SMP_SC_CALC_NC_EVT              (SMP_SELF_DEF_EVT + 17) /* request to calculate number */
+                                                             /* for user check. Used only in the */
+                                                             /* numeric compare protocol */
+
+/* Request to display the number for user check to the user.*/
+/* Used only in the numeric compare protocol */
+#define SMP_SC_DSPL_NC_EVT              (SMP_SELF_DEF_EVT + 18)
+
+#define SMP_SC_NC_OK_EVT                (SMP_SELF_DEF_EVT + 19) /* user confirms 'OK' numeric */
+                                                                /*comparison request */
+
+/* both local and peer DHKey Checks are already present - it is used on slave to prevent race condition */
+#define SMP_SC_2_DHCK_CHKS_PRES_EVT     (SMP_SELF_DEF_EVT + 20)
+
+/* same meaning as SMP_KEY_READY_EVT to separate between SC and legacy actions */
+#define SMP_SC_KEY_READY_EVT            (SMP_SELF_DEF_EVT + 21)
+#define SMP_KEYPRESS_NOTIFICATION_EVENT (SMP_SELF_DEF_EVT + 22)
+
+#define SMP_SC_OOB_DATA_EVT             (SMP_SELF_DEF_EVT + 23) /* SC OOB data from some */
+                                                                /* repository is provided */
+
+#define SMP_CR_LOC_SC_OOB_DATA_EVT      (SMP_SELF_DEF_EVT + 24)
+#define SMP_MAX_EVT                      SMP_CR_LOC_SC_OOB_DATA_EVT
+
+typedef uint8_t tSMP_EVENT;
+
+/* Assumption it's only using the low 8 bits, if bigger than that, need to expand it to 16 bits */
+#define SMP_SEC_KEY_MASK                    0x00ff
+
+/* SMP pairing state */
+enum
+{
+    SMP_STATE_IDLE,
+    SMP_STATE_WAIT_APP_RSP,
+    SMP_STATE_SEC_REQ_PENDING,
+    SMP_STATE_PAIR_REQ_RSP,
+    SMP_STATE_WAIT_CONFIRM,
+    SMP_STATE_CONFIRM,
+    SMP_STATE_RAND,
+    SMP_STATE_PUBLIC_KEY_EXCH,
+    SMP_STATE_SEC_CONN_PHS1_START,
+    SMP_STATE_WAIT_COMMITMENT,
+    SMP_STATE_WAIT_NONCE,
+    SMP_STATE_SEC_CONN_PHS2_START,
+    SMP_STATE_WAIT_DHK_CHECK,
+    SMP_STATE_DHK_CHECK,
+    SMP_STATE_ENCRYPTION_PENDING,
+    SMP_STATE_BOND_PENDING,
+    SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA,
+    SMP_STATE_MAX
+};
+typedef uint8_t tSMP_STATE;
+
+/* SMP over BR/EDR events */
+#define SMP_BR_PAIRING_REQ_EVT              SMP_OPCODE_PAIRING_REQ
+#define SMP_BR_PAIRING_RSP_EVT              SMP_OPCODE_PAIRING_RSP
+#define SMP_BR_CONFIRM_EVT                  SMP_OPCODE_CONFIRM    /* not expected over BR/EDR */
+#define SMP_BR_RAND_EVT                     SMP_OPCODE_RAND       /* not expected over BR/EDR */
+#define SMP_BR_PAIRING_FAILED_EVT           SMP_OPCODE_PAIRING_FAILED
+#define SMP_BR_ENCRPTION_INFO_EVT           SMP_OPCODE_ENCRYPT_INFO /* not expected over BR/EDR */
+#define SMP_BR_MASTER_ID_EVT                SMP_OPCODE_MASTER_ID    /* not expected over BR/EDR */
+#define SMP_BR_ID_INFO_EVT                  SMP_OPCODE_IDENTITY_INFO
+#define SMP_BR_ID_ADDR_EVT                  SMP_OPCODE_ID_ADDR
+#define SMP_BR_SIGN_INFO_EVT                SMP_OPCODE_SIGN_INFO
+#define SMP_BR_SECURITY_REQ_EVT          SMP_OPCODE_SEC_REQ          /* not expected over BR/EDR */
+#define SMP_BR_PAIR_PUBLIC_KEY_EVT       SMP_OPCODE_PAIR_PUBLIC_KEY  /* not expected over BR/EDR */
+#define SMP_BR_PAIR_DHKEY_CHCK_EVT       SMP_OPCODE_PAIR_DHKEY_CHECK /* not expected over BR/EDR */
+#define SMP_BR_PAIR_KEYPR_NOTIF_EVT      SMP_OPCODE_PAIR_KEYPR_NOTIF /* not expected over BR/EDR */
+#define SMP_BR_SELF_DEF_EVT              SMP_BR_PAIR_KEYPR_NOTIF_EVT
+#define SMP_BR_KEY_READY_EVT                (SMP_BR_SELF_DEF_EVT + 1)
+#define SMP_BR_ENCRYPTED_EVT                (SMP_BR_SELF_DEF_EVT + 2)
+#define SMP_BR_L2CAP_CONN_EVT               (SMP_BR_SELF_DEF_EVT + 3)
+#define SMP_BR_L2CAP_DISCONN_EVT            (SMP_BR_SELF_DEF_EVT + 4)
+#define SMP_BR_KEYS_RSP_EVT                 (SMP_BR_SELF_DEF_EVT + 5)
+#define SMP_BR_API_SEC_GRANT_EVT            (SMP_BR_SELF_DEF_EVT + 6)
+#define SMP_BR_TK_REQ_EVT                   (SMP_BR_SELF_DEF_EVT + 7)
+#define SMP_BR_AUTH_CMPL_EVT                (SMP_BR_SELF_DEF_EVT + 8)
+#define SMP_BR_ENC_REQ_EVT                  (SMP_BR_SELF_DEF_EVT + 9)
+#define SMP_BR_BOND_REQ_EVT                 (SMP_BR_SELF_DEF_EVT + 10)
+#define SMP_BR_DISCARD_SEC_REQ_EVT          (SMP_BR_SELF_DEF_EVT + 11)
+#define SMP_BR_MAX_EVT                      (SMP_BR_SELF_DEF_EVT + 12)
+typedef uint8_t tSMP_BR_EVENT;
+
+/* SMP over BR/EDR pairing states */
+enum
+{
+    SMP_BR_STATE_IDLE = SMP_STATE_IDLE,
+    SMP_BR_STATE_WAIT_APP_RSP,
+    SMP_BR_STATE_PAIR_REQ_RSP,
+    SMP_BR_STATE_BOND_PENDING,
+    SMP_BR_STATE_MAX
+};
+typedef uint8_t tSMP_BR_STATE;
+
+/* random and encrption activity state */
+enum
+{
+    SMP_GEN_COMPARE = 1,
+    SMP_GEN_CONFIRM,
+
+    SMP_GEN_DIV_LTK,
+    SMP_GEN_DIV_CSRK,
+    SMP_GEN_RAND_V,
+    SMP_GEN_TK,
+    SMP_GEN_SRAND_MRAND,
+    SMP_GEN_SRAND_MRAND_CONT,
+    SMP_GENERATE_PRIVATE_KEY_0_7,
+    SMP_GENERATE_PRIVATE_KEY_8_15,
+    SMP_GENERATE_PRIVATE_KEY_16_23,
+    SMP_GENERATE_PRIVATE_KEY_24_31,
+    SMP_GEN_NONCE_0_7,
+    SMP_GEN_NONCE_8_15
+};
+
+enum
+{
+    SMP_KEY_TYPE_TK,
+    SMP_KEY_TYPE_CFM,
+    SMP_KEY_TYPE_CMP,
+    SMP_KEY_TYPE_PEER_DHK_CHCK,
+    SMP_KEY_TYPE_STK,
+    SMP_KEY_TYPE_LTK
+};
+typedef struct
+{
+    uint8_t key_type;
+    uint8_t*  p_data;
+}tSMP_KEY;
+
+typedef union
+{
+    uint8_t     *p_data;    /* uint8_t type data pointer */
+    tSMP_KEY    key;
+    uint16_t    reason;
+    uint32_t    passkey;
+    tSMP_OOB_DATA_TYPE  req_oob_type;
+}tSMP_INT_DATA;
+
+/* internal status mask */
+#define SMP_PAIR_FLAGS_WE_STARTED_DD           (1)
+#define SMP_PAIR_FLAGS_PEER_STARTED_DD         (1 << 1)
+#define SMP_PAIR_FLAGS_CMD_CONFIRM             (1 << SMP_OPCODE_CONFIRM) /* 1 << 3 */
+#define SMP_PAIR_FLAG_ENC_AFTER_PAIR           (1 << 4)
+#define SMP_PAIR_FLAG_HAVE_PEER_DHK_CHK   (1 << 5) /* used on slave to resolve race condition */
+#define SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY  (1 << 6) /* used on slave to resolve race condition */
+#define SMP_PAIR_FLAG_HAVE_PEER_COMM      (1 << 7) /* used to resolve race condition */
+#define SMP_PAIR_FLAG_HAVE_LOCAL_PUBL_KEY (1 << 8) /* used on slave to resolve race condition */
+
+/* check if authentication requirement need MITM protection */
+#define SMP_NO_MITM_REQUIRED(x)  (((x) & SMP_AUTH_YN_BIT) == 0)
+
+#define SMP_ENCRYT_KEY_SIZE                16
+#define SMP_ENCRYT_DATA_SIZE               16
+#define SMP_ECNCRPYT_STATUS                HCI_SUCCESS
+
+typedef struct
+{
+    BD_ADDR bd_addr;
+    BT_HDR* p_copy;
+} tSMP_REQ_Q_ENTRY;
+
+/* SMP control block */
+typedef struct
+{
+    tSMP_CALLBACK   *p_callback;
+    alarm_t         *smp_rsp_timer_ent;
+    uint8_t         trace_level;
+    BD_ADDR         pairing_bda;
+    tSMP_STATE      state;
+    bool            derive_lk;
+    bool            id_addr_rcvd;
+    tBLE_ADDR_TYPE  id_addr_type;
+    BD_ADDR         id_addr;
+    bool            smp_over_br;
+    tSMP_BR_STATE   br_state;           /* if SMP over BR/ERD has priority over SMP */
+    uint8_t         failure;
+    uint8_t         status;
+    uint8_t         role;
+    uint16_t        flags;
+    uint8_t         cb_evt;
+    tSMP_SEC_LEVEL  sec_level;
+    bool            connect_initialized;
+    BT_OCTET16      confirm;
+    BT_OCTET16      rconfirm;
+    BT_OCTET16      rrand;                      /* for SC this is peer nonce */
+    BT_OCTET16      rand;                       /* for SC this is local nonce */
+    BT_OCTET32      private_key;
+    BT_OCTET32      dhkey;
+    BT_OCTET16      commitment;
+    BT_OCTET16      remote_commitment;
+    BT_OCTET16      local_random;               /* local randomizer - passkey or OOB randomizer */
+    BT_OCTET16      peer_random;                /* peer randomizer - passkey or OOB randomizer */
+    BT_OCTET16      dhkey_check;
+    BT_OCTET16      remote_dhkey_check;
+    tSMP_PUBLIC_KEY loc_publ_key;
+    tSMP_PUBLIC_KEY peer_publ_key;
+    tSMP_OOB_DATA_TYPE  req_oob_type;
+    tSMP_SC_OOB_DATA    sc_oob_data;
+    tSMP_IO_CAP     peer_io_caps;
+    tSMP_IO_CAP     local_io_capability;
+    tSMP_OOB_FLAG   peer_oob_flag;
+    tSMP_OOB_FLAG   loc_oob_flag;
+    tSMP_AUTH_REQ   peer_auth_req;
+    tSMP_AUTH_REQ   loc_auth_req;
+    bool            secure_connections_only_mode_required;/* true if locally SM is required to operate */
+                                            /* either in Secure Connections mode or not at all */
+    tSMP_ASSO_MODEL selected_association_model;
+    bool            le_secure_connections_mode_is_used;
+    bool    le_sc_kp_notif_is_used;
+    tSMP_SC_KEY_TYPE local_keypress_notification;
+    tSMP_SC_KEY_TYPE peer_keypress_notification;
+    uint8_t         round;       /* authentication stage 1 round for passkey association model */
+    uint32_t        number_to_display;
+    BT_OCTET16      mac_key;
+    uint8_t         peer_enc_size;
+    uint8_t         loc_enc_size;
+    uint8_t         peer_i_key;
+    uint8_t         peer_r_key;
+    uint8_t         local_i_key;
+    uint8_t         local_r_key;
+
+    BT_OCTET16      tk;
+    BT_OCTET16      ltk;
+    uint16_t        div;
+    BT_OCTET16      csrk;  /* storage for local CSRK */
+    uint16_t        ediv;
+    BT_OCTET8       enc_rand;
+    uint8_t         rand_enc_proc_state;
+    uint8_t         addr_type;
+    BD_ADDR         local_bda;
+    bool            is_pair_cancel;
+    bool            discard_sec_req;
+    uint8_t         rcvd_cmd_code;
+    uint8_t         rcvd_cmd_len;
+    uint16_t        total_tx_unacked;
+    bool            wait_for_authorization_complete;
+    uint8_t         cert_failure; /*failure case for certification */
+    alarm_t         *delayed_auth_timer_ent;
+}tSMP_CB;
+
+/* Server Action functions are of this type */
+typedef void (*tSMP_ACT)(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+
+extern tSMP_CB smp_cb;
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Functions provided by att_main.cc */
+extern void smp_init (void);
+
+/* smp main */
+extern void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data);
+
+extern void smp_proc_sec_request(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void  smp_set_fail_nc (bool    enable);
+extern void  smp_set_fail_conf (bool    enable);
+extern void  smp_set_passk_entry_fail(bool    enable);
+extern void  smp_set_oob_fail(bool    enable);
+extern void  smp_set_peer_sc_notif(bool    enable);
+extern void smp_aes_cmac_rfc4493_chk (uint8_t *key, uint8_t *msg, uint8_t msg_len,
+                                              uint8_t mac_len, uint8_t *mac);
+extern void smp_f4_calc_chk (uint8_t *U, uint8_t *V, uint8_t *X, uint8_t *Z, uint8_t *mac);
+extern void smp_g2_calc_chk (uint8_t *U, uint8_t *V, uint8_t *X, uint8_t *Y);
+extern void smp_h6_calc_chk (uint8_t *key, uint8_t *key_id, uint8_t *mac);
+extern void smp_f5_key_calc_chk (uint8_t *w, uint8_t *mac);
+extern void smp_f5_mackey_or_ltk_calc_chk(uint8_t *t, uint8_t *counter,
+                                                  uint8_t *key_id, uint8_t *n1,
+                                                  uint8_t *n2, uint8_t *a1, uint8_t *a2,
+                                                  uint8_t *length, uint8_t *mac);
+extern void smp_f5_calc_chk (uint8_t *w, uint8_t *n1, uint8_t *n2, uint8_t *a1, uint8_t *a2,
+                                    uint8_t *mac_key, uint8_t *ltk);
+extern void smp_f6_calc_chk (uint8_t *w, uint8_t *n1, uint8_t *n2, uint8_t *r,
+                                     uint8_t *iocap, uint8_t *a1, uint8_t *a2, uint8_t *mac);
+/* smp_main */
+extern void         smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data);
+extern tSMP_STATE   smp_get_state(void);
+extern void         smp_set_state(tSMP_STATE state);
+
+/* smp_br_main */
+extern void smp_br_state_machine_event(tSMP_CB *p_cb, tSMP_BR_EVENT event, void *p_data);
+extern tSMP_BR_STATE    smp_get_br_state(void);
+extern void             smp_set_br_state(tSMP_BR_STATE state);
+
+
+/* smp_act.cc */
+extern void smp_send_pair_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_rand(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_pair_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_rand(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_process_pairing_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_id_addr(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_sec_grant(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_sec_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_sl_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_start_enc(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_enc_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_discard(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_pairing_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_decide_association_model(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_app_cback(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_compare(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_check_auth_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_process_io_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_csrk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_ltk_reply(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_pair_cmd(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_pair_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_idle_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_pair_rsp(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_key_distribution(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_srk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_generate_csrk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_fast_conn_param(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_key_pick_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_both_have_public_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_start_secure_connection_phase1(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_process_local_nonce(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_process_pairing_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_process_peer_nonce(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_process_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_match_dhkey_checks(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_process_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_move_to_secure_connections_phase2(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_phase_2_dhkey_checks_are_present(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_wait_for_both_public_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_start_passkey_verification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_process_secure_connection_oob_data(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_process_secure_connection_long_term_key(void);
+extern void smp_set_local_oob_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_set_local_oob_random_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_set_derive_link_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_derive_link_key_from_long_term_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_br_process_pairing_command(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_br_process_security_grant(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_br_process_slave_keys_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_br_send_pair_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_br_check_authorization_request(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_br_select_next_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_br_process_link_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_key_distribution_by_transport(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_br_pairing_complete(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+
+/* smp_l2c */
+extern void smp_l2cap_if_init (void);
+extern void smp_data_ind (BD_ADDR bd_addr, BT_HDR *p_buf);
+
+/* smp_util.cc */
+extern bool    smp_send_cmd(uint8_t cmd_code, tSMP_CB *p_cb);
+extern void smp_cb_cleanup(tSMP_CB *p_cb);
+extern void smp_reset_control_value(tSMP_CB *p_cb);
+extern void smp_proc_pairing_cmpl(tSMP_CB *p_cb);
+extern void smp_convert_string_to_tk(BT_OCTET16 tk, uint32_t passkey);
+extern void smp_mask_enc_key(uint8_t loc_enc_size, uint8_t * p_data);
+extern void smp_rsp_timeout(void *data);
+extern void smp_delayed_auth_complete_timeout(void *data);
+extern void smp_xor_128(BT_OCTET16 a, BT_OCTET16 b);
+extern bool    smp_encrypt_data (uint8_t *key, uint8_t key_len,
+                                 uint8_t *plain_text, uint8_t pt_len,
+                                 tSMP_ENC *p_out);
+extern bool    smp_command_has_invalid_parameters(tSMP_CB *p_cb);
+extern void smp_reject_unexpected_pairing_command(BD_ADDR bd_addr);
+extern tSMP_ASSO_MODEL smp_select_association_model(tSMP_CB *p_cb);
+extern void smp_reverse_array(uint8_t *arr, uint8_t len);
+extern uint8_t smp_calculate_random_input(uint8_t *random, uint8_t round);
+extern void smp_collect_local_io_capabilities(uint8_t *iocap, tSMP_CB *p_cb);
+extern void smp_collect_peer_io_capabilities(uint8_t *iocap, tSMP_CB *p_cb);
+extern void smp_collect_local_ble_address(uint8_t *le_addr, tSMP_CB *p_cb);
+extern void smp_collect_peer_ble_address(uint8_t *le_addr, tSMP_CB *p_cb);
+extern bool    smp_check_commitment(tSMP_CB *p_cb);
+extern void smp_save_secure_connections_long_term_key(tSMP_CB *p_cb);
+extern bool    smp_calculate_f5_mackey_and_long_term_key(tSMP_CB *p_cb);
+extern void smp_remove_fixed_channel(tSMP_CB *p_cb);
+extern bool    smp_request_oob_data(tSMP_CB *p_cb);
+
+/* smp_keys.cc */
+extern void smp_generate_srand_mrand_confirm (tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_generate_compare (tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_generate_stk (tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_generate_ltk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_generate_passkey (tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_generate_rand_cont(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_create_private_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_use_oob_private_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_compute_dhkey(tSMP_CB *p_cb);
+extern void smp_calculate_local_commitment(tSMP_CB *p_cb);
+extern void smp_calculate_peer_commitment(tSMP_CB *p_cb, BT_OCTET16 output_buf);
+extern void smp_calculate_numeric_comparison_display_number(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_calculate_local_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_calculate_peer_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_start_nonce_generation(tSMP_CB *p_cb);
+extern bool    smp_calculate_link_key_from_long_term_key(tSMP_CB *p_cb);
+extern bool    smp_calculate_long_term_key_from_link_key(tSMP_CB *p_cb);
+extern void smp_calculate_f4(uint8_t *u, uint8_t *v, uint8_t *x, uint8_t z, uint8_t *c);
+extern uint32_t smp_calculate_g2(uint8_t *u, uint8_t *v, uint8_t *x, uint8_t *y);
+extern bool    smp_calculate_f5(uint8_t *w, uint8_t *n1, uint8_t *n2, uint8_t *a1, uint8_t *a2,
+                           uint8_t *mac_key, uint8_t *ltk);
+extern bool    smp_calculate_f5_mackey_or_long_term_key(uint8_t *t, uint8_t *counter,
+                                         uint8_t *key_id, uint8_t *n1, uint8_t *n2, uint8_t *a1,
+                                         uint8_t *a2, uint8_t *length, uint8_t *mac);
+extern bool    smp_calculate_f5_key(uint8_t *w, uint8_t *t);
+extern bool    smp_calculate_f6(uint8_t *w, uint8_t *n1, uint8_t *n2, uint8_t *r, uint8_t *iocap,
+                               uint8_t *a1, uint8_t *a2, uint8_t *f3);
+extern bool    smp_calculate_h6(uint8_t *w, uint8_t *keyid, uint8_t *h2);
+#if (SMP_DEBUG == TRUE)
+extern void smp_debug_print_nbyte_little_endian (uint8_t *p, const uint8_t *key_name,
+                                                 uint8_t len);
+#endif
+
+/* smp_cmac.cc */
+extern bool    aes_cipher_msg_auth_code(BT_OCTET16 key, uint8_t *input, uint16_t length,
+                                                 uint16_t tlen, uint8_t *p_signature);
+extern void print128(BT_OCTET16 x, const uint8_t *key_name);
+
+#endif
+
+#endif /* SMP_INT_H */
diff --git a/bt/stack/smp/smp_keys.cc b/bt/stack/smp/smp_keys.cc
new file mode 100644
index 0000000..1d65f74
--- /dev/null
+++ b/bt/stack/smp/smp_keys.cc
@@ -0,0 +1,2254 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 security manager protocol utility functions
+ *
+ ******************************************************************************/
+#include "bt_target.h"
+
+#if (SMP_INCLUDED == TRUE)
+#if (SMP_DEBUG == TRUE)
+    #include <stdio.h>
+#endif
+#include <string.h>
+#include "bt_utils.h"
+#include "btm_ble_api.h"
+#include "smp_int.h"
+#include "btm_int.h"
+#include "btm_ble_int.h"
+#include "hcimsgs.h"
+#include "aes.h"
+#include "p_256_ecc_pp.h"
+#include "device/include/controller.h"
+#include "osi/include/osi.h"
+
+#ifndef SMP_MAX_ENC_REPEAT
+  #define SMP_MAX_ENC_REPEAT  3
+#endif
+
+static void smp_rand_back(tBTM_RAND_ENC *p);
+static void smp_generate_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+static void smp_generate_ltk_cont(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+static void smp_generate_y(tSMP_CB *p_cb, tSMP_INT_DATA *p);
+static void smp_generate_rand_vector (tSMP_CB *p_cb, tSMP_INT_DATA *p);
+static void smp_process_stk(tSMP_CB *p_cb, tSMP_ENC *p);
+static void smp_calculate_comfirm_cont(tSMP_CB *p_cb, tSMP_ENC *p);
+static void smp_process_confirm(tSMP_CB *p_cb, tSMP_ENC *p);
+static void smp_process_compare(tSMP_CB *p_cb, tSMP_ENC *p);
+static void smp_process_ediv(tSMP_CB *p_cb, tSMP_ENC *p);
+static bool    smp_calculate_legacy_short_term_key(tSMP_CB *p_cb, tSMP_ENC *output);
+static void smp_continue_private_key_creation(tSMP_CB *p_cb, tBTM_RAND_ENC *p);
+static void smp_process_private_key(tSMP_CB *p_cb);
+static void smp_finish_nonce_generation(tSMP_CB *p_cb);
+static void smp_process_new_nonce(tSMP_CB *p_cb);
+
+#define SMP_PASSKEY_MASK    0xfff00000
+
+void smp_debug_print_nbyte_little_endian(uint8_t *p, const uint8_t *key_name, uint8_t len)
+{
+#if (SMP_DEBUG == TRUE)
+    int     ind;
+    int     col_count = 32;
+    int     row_count;
+    uint8_t p_buf[512];
+
+    SMP_TRACE_WARNING("%s(LSB ~ MSB):", key_name);
+    memset(p_buf, 0, sizeof(p_buf));
+    row_count = len % col_count ? len / col_count + 1: len / col_count;
+
+    ind = 0;
+    for (int row = 0; row <  row_count; row++)
+    {
+        for (int column = 0, x = 0; (ind < len) && (column < col_count); column++, ind++)
+        {
+            x += snprintf((char *)&p_buf[x], sizeof(p_buf) - x, "%02x ", p[ind]);
+        }
+        SMP_TRACE_WARNING("  [%03d]: %s", row * col_count, p_buf);
+    }
+#endif
+}
+
+void smp_debug_print_nbyte_big_endian (uint8_t *p, const uint8_t *key_name, uint8_t len)
+{
+#if (SMP_DEBUG == TRUE)
+    uint8_t p_buf[512];
+
+    SMP_TRACE_WARNING("%s(MSB ~ LSB):", key_name);
+    memset(p_buf, 0, sizeof(p_buf));
+
+    int ind = 0;
+    int  ncols = 32; /* num entries in one line */
+    int  nrows;      /* num lines */
+
+    nrows = len % ncols ? len / ncols + 1: len / ncols;
+    for (int row = 0; row <  nrows; row++)
+    {
+        for (int col = 0, x = 0; (ind < len) && (col < ncols); col++, ind++)
+        {
+            x += snprintf ((char *)&p_buf[len-x-1], sizeof(p_buf) - (len-x-1), "%02x ", p[ind]);
+        }
+        SMP_TRACE_WARNING("[%03d]: %s", row * ncols, p_buf);
+    }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         smp_encrypt_data
+**
+** Description      This function is called to encrypt data.
+**                  It uses AES-128 encryption algorithm.
+**                  Plain_text is encrypted using key, the result is at p_out.
+**
+** Returns          void
+**
+*******************************************************************************/
+bool    smp_encrypt_data (uint8_t *key, uint8_t key_len,
+                          uint8_t *plain_text, uint8_t pt_len,
+                          tSMP_ENC *p_out)
+{
+    aes_context ctx;
+    uint8_t *p_start = NULL;
+    uint8_t *p = NULL;
+    uint8_t *p_rev_data = NULL;    /* input data in big endilan format */
+    uint8_t *p_rev_key = NULL;     /* input key in big endilan format */
+    uint8_t *p_rev_output = NULL;  /* encrypted output in big endilan format */
+
+    SMP_TRACE_DEBUG ("%s", __func__);
+    if ( (p_out == NULL ) || (key_len != SMP_ENCRYT_KEY_SIZE) )
+    {
+        SMP_TRACE_ERROR ("%s failed", __func__);
+        return false;
+    }
+
+    p_start = (uint8_t *)osi_calloc(SMP_ENCRYT_DATA_SIZE * 4);
+
+    if (pt_len > SMP_ENCRYT_DATA_SIZE)
+        pt_len = SMP_ENCRYT_DATA_SIZE;
+
+    p = p_start;
+    ARRAY_TO_STREAM (p, plain_text, pt_len); /* byte 0 to byte 15 */
+    p_rev_data = p = p_start + SMP_ENCRYT_DATA_SIZE; /* start at byte 16 */
+    REVERSE_ARRAY_TO_STREAM (p, p_start, SMP_ENCRYT_DATA_SIZE);  /* byte 16 to byte 31 */
+    p_rev_key = p; /* start at byte 32 */
+    REVERSE_ARRAY_TO_STREAM (p, key, SMP_ENCRYT_KEY_SIZE); /* byte 32 to byte 47 */
+
+#if (SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE)
+    smp_debug_print_nbyte_little_endian(key, (const uint8_t *)"Key", SMP_ENCRYT_KEY_SIZE);
+    smp_debug_print_nbyte_little_endian(p_start, (const uint8_t *)"Plain text", SMP_ENCRYT_DATA_SIZE);
+#endif
+    p_rev_output = p;
+    aes_set_key(p_rev_key, SMP_ENCRYT_KEY_SIZE, &ctx);
+    aes_encrypt(p_rev_data, p, &ctx);  /* outputs in byte 48 to byte 63 */
+
+    p = p_out->param_buf;
+    REVERSE_ARRAY_TO_STREAM (p, p_rev_output, SMP_ENCRYT_DATA_SIZE);
+#if (SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE)
+    smp_debug_print_nbyte_little_endian(p_out->param_buf, (const uint8_t *)"Encrypted text", SMP_ENCRYT_KEY_SIZE);
+#endif
+
+    p_out->param_len = SMP_ENCRYT_KEY_SIZE;
+    p_out->status = HCI_SUCCESS;
+    p_out->opcode =  HCI_BLE_ENCRYPT;
+
+    osi_free(p_start);
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         smp_generate_passkey
+**
+** Description      This function is called to generate passkey.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_generate_passkey(tSMP_CB *p_cb,
+                          UNUSED_ATTR tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG ("%s", __func__);
+    p_cb->rand_enc_proc_state = SMP_GEN_TK;
+
+    /* generate MRand or SRand */
+    btsnd_hcic_ble_rand((void *)smp_rand_back);
+}
+
+/*******************************************************************************
+**
+** Function         smp_proc_passkey
+**
+** Description      This function is called to process a passkey.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_proc_passkey(tSMP_CB *p_cb , tBTM_RAND_ENC *p)
+{
+    uint8_t *tt = p_cb->tk;
+    tSMP_KEY    key;
+    uint32_t passkey; /* 19655 test number; */
+    uint8_t *pp = p->param_buf;
+
+    SMP_TRACE_DEBUG ("%s", __func__);
+    STREAM_TO_UINT32(passkey, pp);
+    passkey &= ~SMP_PASSKEY_MASK;
+
+    /* truncate by maximum value */
+    while (passkey > BTM_MAX_PASSKEY_VAL)
+        passkey >>= 1;
+
+    /* save the TK */
+    memset(p_cb->tk, 0, BT_OCTET16_LEN);
+    UINT32_TO_STREAM(tt, passkey);
+
+    key.key_type = SMP_KEY_TYPE_TK;
+    key.p_data  = p_cb->tk;
+
+    if (p_cb->p_callback)
+    {
+        (*p_cb->p_callback)(SMP_PASSKEY_NOTIF_EVT, p_cb->pairing_bda, (tSMP_EVT_DATA *)&passkey);
+    }
+
+    if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_PASSKEY_DISP)
+    {
+        smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &passkey);
+    }
+    else
+    {
+        smp_sm_event(p_cb, SMP_KEY_READY_EVT, (tSMP_INT_DATA *)&key);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         smp_generate_stk
+**
+** Description      This function is called to generate STK calculated by running
+**                  AES with the TK value as key and a concatenation of the random
+**                  values.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_generate_stk(tSMP_CB *p_cb,
+                      UNUSED_ATTR tSMP_INT_DATA *p_data)
+{
+
+    tSMP_ENC output;
+    tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+    SMP_TRACE_DEBUG ("%s", __func__);
+
+    if (p_cb->le_secure_connections_mode_is_used)
+    {
+        SMP_TRACE_WARNING ("FOR LE SC LTK IS USED INSTEAD OF STK");
+        output.param_len = SMP_ENCRYT_KEY_SIZE;
+        output.status = HCI_SUCCESS;
+        output.opcode =  HCI_BLE_ENCRYPT;
+        memcpy(output.param_buf, p_cb->ltk, SMP_ENCRYT_DATA_SIZE);
+    }
+    else if (!smp_calculate_legacy_short_term_key(p_cb, &output))
+    {
+        SMP_TRACE_ERROR("%s failed", __func__);
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+        return;
+    }
+
+    smp_process_stk(p_cb, &output);
+}
+
+/*******************************************************************************
+**
+** Function         smp_generate_srand_mrand_confirm
+**
+** Description      This function is called to start the second pairing phase by
+**                  start generating random number.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_generate_srand_mrand_confirm(tSMP_CB *p_cb,
+                                      UNUSED_ATTR tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG ("%s", __func__);
+    p_cb->rand_enc_proc_state = SMP_GEN_SRAND_MRAND;
+    /* generate MRand or SRand */
+    btsnd_hcic_ble_rand((void *)smp_rand_back);
+}
+
+/*******************************************************************************
+**
+** Function         smp_generate_rand_cont
+**
+** Description      This function is called to generate another 64 bits random for
+**                  MRand or Srand.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_generate_rand_cont(tSMP_CB *p_cb,
+                            UNUSED_ATTR tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG ("%s", __func__);
+    p_cb->rand_enc_proc_state = SMP_GEN_SRAND_MRAND_CONT;
+    /* generate 64 MSB of MRand or SRand */
+    btsnd_hcic_ble_rand((void *)smp_rand_back);
+}
+
+/*******************************************************************************
+**
+** Function         smp_generate_ltk
+**
+** Description      This function is called:
+**                  - in legacy pairing - to calculate LTK, starting with DIV
+**                    generation;
+**                  - in LE Secure Connections pairing over LE transport - to process LTK
+**                    already generated to encrypt LE link;
+**                  - in LE Secure Connections pairing over BR/EDR transport - to start
+**                    BR/EDR Link Key processing.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_generate_ltk(tSMP_CB *p_cb,
+                      UNUSED_ATTR tSMP_INT_DATA *p_data)
+{
+
+    bool    div_status;
+    SMP_TRACE_DEBUG ("%s", __func__);
+    if (smp_get_br_state() == SMP_BR_STATE_BOND_PENDING)
+    {
+        smp_br_process_link_key(p_cb, NULL);
+        return;
+    }
+    else if (p_cb->le_secure_connections_mode_is_used)
+    {
+        smp_process_secure_connection_long_term_key();
+        return;
+    }
+
+    div_status = btm_get_local_div(p_cb->pairing_bda, &p_cb->div);
+
+    if (div_status)
+    {
+        smp_generate_ltk_cont(p_cb, NULL);
+    }
+    else
+    {
+        SMP_TRACE_DEBUG ("Generate DIV for LTK");
+        p_cb->rand_enc_proc_state = SMP_GEN_DIV_LTK;
+        /* generate MRand or SRand */
+        btsnd_hcic_ble_rand((void *)smp_rand_back);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         smp_compute_csrk
+**
+** Description      This function is called to calculate CSRK
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_compute_csrk(tSMP_CB *p_cb,
+                      UNUSED_ATTR tSMP_INT_DATA *p_data)
+{
+
+    BT_OCTET16  er;
+    uint8_t     buffer[4]; /* for (r || DIV)  r=1*/
+    uint16_t    r=1;
+    uint8_t     *p=buffer;
+    tSMP_ENC    output;
+    tSMP_STATUS   status = SMP_PAIR_FAIL_UNKNOWN;
+
+    SMP_TRACE_DEBUG ("smp_compute_csrk div=%x", p_cb->div);
+    BTM_GetDeviceEncRoot(er);
+    /* CSRK = d1(ER, DIV, 1) */
+    UINT16_TO_STREAM(p, p_cb->div);
+    UINT16_TO_STREAM(p, r);
+
+    if (!SMP_Encrypt(er, BT_OCTET16_LEN, buffer, 4, &output))
+    {
+        SMP_TRACE_ERROR("smp_generate_csrk failed");
+        if (p_cb->smp_over_br)
+        {
+            smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &status);
+        }
+        else
+        {
+            smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+        }
+    }
+    else
+    {
+        memcpy((void *)p_cb->csrk, output.param_buf, BT_OCTET16_LEN);
+        smp_send_csrk_info(p_cb, NULL);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         smp_generate_csrk
+**
+** Description      This function is called to calculate CSRK, starting with DIV
+**                  generation.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_generate_csrk(tSMP_CB *p_cb,
+                       UNUSED_ATTR tSMP_INT_DATA *p_data)
+{
+
+    bool        div_status;
+
+    SMP_TRACE_DEBUG ("smp_generate_csrk");
+
+    div_status = btm_get_local_div(p_cb->pairing_bda, &p_cb->div);
+    if (div_status)
+    {
+        smp_compute_csrk(p_cb, NULL);
+    }
+    else
+    {
+        SMP_TRACE_DEBUG ("Generate DIV for CSRK");
+        p_cb->rand_enc_proc_state = SMP_GEN_DIV_CSRK;
+        btsnd_hcic_ble_rand((void *)smp_rand_back);
+    }
+}
+
+/*******************************************************************************
+** Function         smp_concatenate_peer
+**                  add pairing command sent from local device into p1.
+*******************************************************************************/
+void smp_concatenate_local( tSMP_CB *p_cb, uint8_t **p_data, uint8_t op_code)
+{
+    uint8_t *p = *p_data;
+
+    SMP_TRACE_DEBUG ("%s", __func__);
+    UINT8_TO_STREAM(p, op_code);
+    UINT8_TO_STREAM(p, p_cb->local_io_capability);
+    UINT8_TO_STREAM(p, p_cb->loc_oob_flag);
+    UINT8_TO_STREAM(p, p_cb->loc_auth_req);
+    UINT8_TO_STREAM(p, p_cb->loc_enc_size);
+    UINT8_TO_STREAM(p, p_cb->local_i_key);
+    UINT8_TO_STREAM(p, p_cb->local_r_key);
+
+    *p_data = p;
+}
+
+/*******************************************************************************
+** Function         smp_concatenate_peer
+**                  add pairing command received from peer device into p1.
+*******************************************************************************/
+void smp_concatenate_peer( tSMP_CB *p_cb, uint8_t **p_data, uint8_t op_code)
+{
+    uint8_t *p = *p_data;
+
+    SMP_TRACE_DEBUG ("smp_concatenate_peer ");
+    UINT8_TO_STREAM(p, op_code);
+    UINT8_TO_STREAM(p, p_cb->peer_io_caps);
+    UINT8_TO_STREAM(p, p_cb->peer_oob_flag);
+    UINT8_TO_STREAM(p, p_cb->peer_auth_req);
+    UINT8_TO_STREAM(p, p_cb->peer_enc_size);
+    UINT8_TO_STREAM(p, p_cb->peer_i_key);
+    UINT8_TO_STREAM(p, p_cb->peer_r_key);
+
+    *p_data = p;
+}
+
+/*******************************************************************************
+**
+** Function         smp_gen_p1_4_confirm
+**
+** Description      Generate Confirm/Compare Step1:
+**                  p1 = pres || preq || rat' || iat'
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_gen_p1_4_confirm( tSMP_CB *p_cb, BT_OCTET16 p1)
+{
+    uint8_t *p = (uint8_t *)p1;
+    tBLE_ADDR_TYPE    addr_type = 0;
+    BD_ADDR           remote_bda;
+
+    SMP_TRACE_DEBUG ("smp_gen_p1_4_confirm");
+
+    if (!BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, remote_bda, &addr_type))
+    {
+        SMP_TRACE_ERROR("can not generate confirm for unknown device");
+        return;
+    }
+
+    BTM_ReadConnectionAddr( p_cb->pairing_bda, p_cb->local_bda, &p_cb->addr_type);
+
+    if (p_cb->role == HCI_ROLE_MASTER)
+    {
+        /* LSB : rat': initiator's(local) address type */
+        UINT8_TO_STREAM(p, p_cb->addr_type);
+        /* LSB : iat': responder's address type */
+        UINT8_TO_STREAM(p, addr_type);
+        /* concatinate preq */
+        smp_concatenate_local(p_cb, &p, SMP_OPCODE_PAIRING_REQ);
+        /* concatinate pres */
+        smp_concatenate_peer(p_cb, &p, SMP_OPCODE_PAIRING_RSP);
+    }
+    else
+    {
+        /* LSB : iat': initiator's address type */
+        UINT8_TO_STREAM(p, addr_type);
+        /* LSB : rat': responder's(local) address type */
+        UINT8_TO_STREAM(p, p_cb->addr_type);
+        /* concatinate preq */
+        smp_concatenate_peer(p_cb, &p, SMP_OPCODE_PAIRING_REQ);
+        /* concatinate pres */
+        smp_concatenate_local(p_cb, &p, SMP_OPCODE_PAIRING_RSP);
+    }
+#if (SMP_DEBUG == TRUE)
+    SMP_TRACE_DEBUG("p1 = pres || preq || rat' || iat'");
+    smp_debug_print_nbyte_little_endian ((uint8_t *)p1, (const uint8_t *)"P1", 16);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         smp_gen_p2_4_confirm
+**
+** Description      Generate Confirm/Compare Step2:
+**                  p2 = padding || ia || ra
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_gen_p2_4_confirm( tSMP_CB *p_cb, BT_OCTET16 p2)
+{
+    uint8_t     *p = (uint8_t *)p2;
+    BD_ADDR     remote_bda;
+    tBLE_ADDR_TYPE  addr_type = 0;
+
+    if (!BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, remote_bda, &addr_type))
+    {
+        SMP_TRACE_ERROR("can not generate confirm p2 for unknown device");
+        return;
+    }
+
+    SMP_TRACE_DEBUG ("smp_gen_p2_4_confirm");
+
+    memset(p, 0, sizeof(BT_OCTET16));
+
+    if (p_cb->role == HCI_ROLE_MASTER)
+    {
+        /* LSB ra */
+        BDADDR_TO_STREAM(p, remote_bda);
+        /* ia */
+        BDADDR_TO_STREAM(p, p_cb->local_bda);
+    }
+    else
+    {
+        /* LSB ra */
+        BDADDR_TO_STREAM(p, p_cb->local_bda);
+        /* ia */
+        BDADDR_TO_STREAM(p, remote_bda);
+    }
+#if (SMP_DEBUG == TRUE)
+    SMP_TRACE_DEBUG("p2 = padding || ia || ra");
+    smp_debug_print_nbyte_little_endian(p2, (const uint8_t *)"p2", 16);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function         smp_calculate_comfirm
+**
+** Description      This function is called to calculate Confirm value.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_calculate_comfirm (tSMP_CB *p_cb, BT_OCTET16 rand,
+                            UNUSED_ATTR BD_ADDR bda)
+{
+
+    BT_OCTET16      p1;
+    tSMP_ENC       output;
+    tSMP_STATUS     status = SMP_PAIR_FAIL_UNKNOWN;
+
+    SMP_TRACE_DEBUG ("smp_calculate_comfirm ");
+    /* generate p1 = pres || preq || rat' || iat' */
+    smp_gen_p1_4_confirm(p_cb, p1);
+
+    /* p1 = rand XOR p1 */
+    smp_xor_128(p1, rand);
+
+    smp_debug_print_nbyte_little_endian ((uint8_t *)p1, (const uint8_t *)"P1' = r XOR p1", 16);
+
+    /* calculate e(k, r XOR p1), where k = TK */
+    if (!SMP_Encrypt(p_cb->tk, BT_OCTET16_LEN, p1, BT_OCTET16_LEN, &output))
+    {
+        SMP_TRACE_ERROR("smp_generate_csrk failed");
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+    }
+    else
+    {
+        smp_calculate_comfirm_cont(p_cb, &output);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         smp_calculate_comfirm_cont
+**
+** Description      This function is called when SConfirm/MConfirm is generated
+**                  proceed to send the Confirm request/response to peer device.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void smp_calculate_comfirm_cont(tSMP_CB *p_cb, tSMP_ENC *p)
+{
+    BT_OCTET16    p2;
+    tSMP_ENC      output;
+    tSMP_STATUS     status = SMP_PAIR_FAIL_UNKNOWN;
+
+    SMP_TRACE_DEBUG ("smp_calculate_comfirm_cont ");
+#if (SMP_DEBUG == TRUE)
+    SMP_TRACE_DEBUG("Confirm step 1 p1' = e(k, r XOR p1)  Generated");
+    smp_debug_print_nbyte_little_endian (p->param_buf, (const uint8_t *)"C1", 16);
+#endif
+
+    smp_gen_p2_4_confirm(p_cb, p2);
+
+    /* calculate p2 = (p1' XOR p2) */
+    smp_xor_128(p2, p->param_buf);
+    smp_debug_print_nbyte_little_endian ((uint8_t *)p2, (const uint8_t *)"p2' = C1 xor p2", 16);
+
+    /* calculate: Confirm = E(k, p1' XOR p2) */
+    if (!SMP_Encrypt(p_cb->tk, BT_OCTET16_LEN, p2, BT_OCTET16_LEN, &output))
+    {
+        SMP_TRACE_ERROR("smp_calculate_comfirm_cont failed");
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+    }
+    else
+    {
+        switch (p_cb->rand_enc_proc_state)
+        {
+            case SMP_GEN_CONFIRM:
+                smp_process_confirm(p_cb, &output);
+                break;
+
+            case SMP_GEN_COMPARE:
+                smp_process_compare(p_cb, &output);
+                break;
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         smp_generate_confirm
+**
+** Description      This function is called when a 48 bits random number is generated
+**                  as SRand or MRand, continue to calculate Sconfirm or MConfirm.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void smp_generate_confirm(tSMP_CB *p_cb,
+                                 UNUSED_ATTR tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG ("%s", __func__);
+    p_cb->rand_enc_proc_state = SMP_GEN_CONFIRM;
+    smp_debug_print_nbyte_little_endian ((uint8_t *)p_cb->rand,  (const uint8_t *)"local rand", 16);
+    smp_calculate_comfirm(p_cb, p_cb->rand, p_cb->pairing_bda);
+}
+
+/*******************************************************************************
+**
+** Function         smp_generate_compare
+**
+** Description      This function is called to generate SConfirm for Slave device,
+**                  or MSlave for Master device. This function can be also used for
+**                  generating Compare number for confirm value check.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_generate_compare (tSMP_CB *p_cb,
+                           UNUSED_ATTR tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG ("smp_generate_compare ");
+    p_cb->rand_enc_proc_state = SMP_GEN_COMPARE;
+    smp_debug_print_nbyte_little_endian ((uint8_t *)p_cb->rrand,  (const uint8_t *)"peer rand", 16);
+    smp_calculate_comfirm(p_cb, p_cb->rrand, p_cb->local_bda);
+}
+
+/*******************************************************************************
+**
+** Function         smp_process_confirm
+**
+** Description      This function is called when SConfirm/MConfirm is generated
+**                  proceed to send the Confirm request/response to peer device.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void smp_process_confirm(tSMP_CB *p_cb, tSMP_ENC *p)
+{
+    tSMP_KEY    key;
+
+    SMP_TRACE_DEBUG ("%s", __func__);
+    memcpy(p_cb->confirm, p->param_buf, BT_OCTET16_LEN);
+
+#if (SMP_DEBUG == TRUE)
+    SMP_TRACE_DEBUG("Confirm  Generated");
+    smp_debug_print_nbyte_little_endian ((uint8_t *)p_cb->confirm,  (const uint8_t *)"Confirm", 16);
+#endif
+
+    key.key_type = SMP_KEY_TYPE_CFM;
+    key.p_data = p->param_buf;
+    smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key);
+}
+
+/*******************************************************************************
+**
+** Function         smp_process_compare
+**
+** Description      This function is called when Compare is generated using the
+**                  RRand and local BDA, TK information.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void smp_process_compare(tSMP_CB *p_cb, tSMP_ENC *p)
+{
+    tSMP_KEY    key;
+
+    SMP_TRACE_DEBUG ("smp_process_compare ");
+#if (SMP_DEBUG == TRUE)
+    SMP_TRACE_DEBUG("Compare Generated");
+    smp_debug_print_nbyte_little_endian (p->param_buf,  (const uint8_t *)"Compare", 16);
+#endif
+    key.key_type = SMP_KEY_TYPE_CMP;
+    key.p_data   = p->param_buf;
+
+    smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key);
+}
+
+/*******************************************************************************
+**
+** Function         smp_process_stk
+**
+** Description      This function is called when STK is generated
+**                  proceed to send the encrypt the link using STK.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void smp_process_stk(tSMP_CB *p_cb, tSMP_ENC *p)
+{
+    tSMP_KEY    key;
+
+    SMP_TRACE_DEBUG ("smp_process_stk ");
+#if (SMP_DEBUG == TRUE)
+    SMP_TRACE_ERROR("STK Generated");
+#endif
+    smp_mask_enc_key(p_cb->loc_enc_size, p->param_buf);
+
+    key.key_type = SMP_KEY_TYPE_STK;
+    key.p_data   = p->param_buf;
+
+    smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key);
+}
+
+/*******************************************************************************
+**
+** Function         smp_generate_ltk_cont
+**
+** Description      This function is to calculate LTK = d1(ER, DIV, 0)= e(ER, DIV)
+**
+** Returns          void
+**
+*******************************************************************************/
+static void smp_generate_ltk_cont(tSMP_CB *p_cb,
+                                  UNUSED_ATTR tSMP_INT_DATA *p_data)
+{
+
+    BT_OCTET16  er;
+    tSMP_ENC    output;
+    tSMP_STATUS     status = SMP_PAIR_FAIL_UNKNOWN;
+
+    SMP_TRACE_DEBUG ("%s", __func__);
+    BTM_GetDeviceEncRoot(er);
+
+    /* LTK = d1(ER, DIV, 0)= e(ER, DIV)*/
+    if (!SMP_Encrypt(er, BT_OCTET16_LEN, (uint8_t *)&p_cb->div,
+                     sizeof(uint16_t), &output))
+    {
+        SMP_TRACE_ERROR("%s failed", __func__);
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+    }
+    else
+    {
+        /* mask the LTK */
+        smp_mask_enc_key(p_cb->loc_enc_size, output.param_buf);
+        memcpy((void *)p_cb->ltk, output.param_buf, BT_OCTET16_LEN);
+        smp_generate_rand_vector(p_cb, NULL);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         smp_generate_y
+**
+** Description      This function is to proceed generate Y = E(DHK, Rand)
+**
+** Returns          void
+**
+*******************************************************************************/
+static void smp_generate_y(tSMP_CB *p_cb,
+                           UNUSED_ATTR tSMP_INT_DATA *p)
+{
+
+    BT_OCTET16  dhk;
+    tSMP_ENC   output;
+    tSMP_STATUS     status = SMP_PAIR_FAIL_UNKNOWN;
+
+
+    SMP_TRACE_DEBUG ("smp_generate_y ");
+    BTM_GetDeviceDHK(dhk);
+
+    if (!SMP_Encrypt(dhk, BT_OCTET16_LEN, p_cb->enc_rand,
+                     BT_OCTET8_LEN, &output))
+    {
+        SMP_TRACE_ERROR("smp_generate_y failed");
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+    }
+    else
+    {
+        smp_process_ediv(p_cb, &output);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         smp_generate_rand_vector
+**
+** Description      This function is called when LTK is generated, send state machine
+**                  event to SMP.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void smp_generate_rand_vector (tSMP_CB *p_cb,
+                                      UNUSED_ATTR tSMP_INT_DATA *p)
+{
+    /* generate EDIV and rand now */
+    /* generate random vector */
+    SMP_TRACE_DEBUG ("smp_generate_rand_vector ");
+    p_cb->rand_enc_proc_state = SMP_GEN_RAND_V;
+    btsnd_hcic_ble_rand((void *)smp_rand_back);
+}
+
+/*******************************************************************************
+**
+** Function         smp_process_ediv
+**
+** Description      This function is to calculate EDIV = Y xor DIV
+**
+** Returns          void
+**
+*******************************************************************************/
+static void smp_process_ediv(tSMP_CB *p_cb, tSMP_ENC *p)
+{
+    tSMP_KEY    key;
+    uint8_t *pp= p->param_buf;
+    uint16_t y;
+
+    SMP_TRACE_DEBUG ("smp_process_ediv ");
+    STREAM_TO_UINT16(y, pp);
+
+    /* EDIV = Y xor DIV */
+    p_cb->ediv = p_cb->div ^ y;
+    /* send LTK ready */
+    SMP_TRACE_ERROR("LTK ready");
+    key.key_type = SMP_KEY_TYPE_LTK;
+    key.p_data   = p->param_buf;
+
+    smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key);
+}
+
+/*******************************************************************************
+**
+** Function         smp_calculate_legacy_short_term_key
+**
+** Description      The function calculates legacy STK.
+**
+** Returns          false if out of resources, true in other cases.
+**
+*******************************************************************************/
+bool    smp_calculate_legacy_short_term_key(tSMP_CB *p_cb, tSMP_ENC *output)
+{
+    BT_OCTET16 ptext;
+    uint8_t *p = ptext;
+
+    SMP_TRACE_DEBUG ("%s", __func__);
+    memset(p, 0, BT_OCTET16_LEN);
+    if (p_cb->role == HCI_ROLE_MASTER)
+    {
+        memcpy(p, p_cb->rand, BT_OCTET8_LEN);
+        memcpy(&p[BT_OCTET8_LEN], p_cb->rrand, BT_OCTET8_LEN);
+    }
+    else
+    {
+        memcpy(p, p_cb->rrand, BT_OCTET8_LEN);
+        memcpy(&p[BT_OCTET8_LEN], p_cb->rand, BT_OCTET8_LEN);
+    }
+
+    bool    encrypted;
+    /* generate STK = Etk(rand|rrand)*/
+    encrypted = SMP_Encrypt( p_cb->tk, BT_OCTET16_LEN, ptext, BT_OCTET16_LEN, output);
+    if (!encrypted)
+    {
+        SMP_TRACE_ERROR("%s failed", __func__);
+    }
+    return encrypted;
+}
+
+/*******************************************************************************
+**
+** Function         smp_create_private_key
+**
+** Description      This function is called to create private key used to
+**                  calculate public key and DHKey.
+**                  The function starts private key creation requesting controller
+**                  to generate [0-7] octets of private key.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_create_private_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG ("%s",__func__);
+    p_cb->rand_enc_proc_state = SMP_GENERATE_PRIVATE_KEY_0_7;
+    btsnd_hcic_ble_rand((void *)smp_rand_back);
+}
+
+/*******************************************************************************
+**
+** Function         smp_use_oob_private_key
+**
+** Description      This function is called
+**                  - to save the secret key used to calculate the public key used
+**                    in calculations of commitment sent OOB to a peer
+**                  - to use this secret key to recalculate the public key and
+**                    start the process of sending this public key to the peer
+**                  if secret/public keys have to be reused.
+**                  If the keys aren't supposed to be reused, continue from the
+**                  point from which request for OOB data was issued.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_use_oob_private_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG ("%s req_oob_type: %d, role: %d",
+                      __func__, p_cb->req_oob_type, p_cb->role);
+
+    switch (p_cb->req_oob_type)
+    {
+        case SMP_OOB_BOTH:
+        case SMP_OOB_LOCAL:
+            SMP_TRACE_DEBUG("%s restore secret key", __func__)
+            memcpy(p_cb->private_key, p_cb->sc_oob_data.loc_oob_data.private_key_used, BT_OCTET32_LEN);
+            smp_process_private_key(p_cb);
+            break;
+        default:
+            SMP_TRACE_DEBUG("%s create secret key anew", __func__);
+            smp_set_state(SMP_STATE_PAIR_REQ_RSP);
+            smp_decide_association_model(p_cb, NULL);
+            break;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         smp_continue_private_key_creation
+**
+** Description      This function is used to continue private key creation.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_continue_private_key_creation (tSMP_CB *p_cb, tBTM_RAND_ENC *p)
+{
+    uint8_t state = p_cb->rand_enc_proc_state & ~0x80;
+    SMP_TRACE_DEBUG ("%s state=0x%x", __func__, state);
+
+    switch (state)
+    {
+        case SMP_GENERATE_PRIVATE_KEY_0_7:
+            memcpy((void *)p_cb->private_key, p->param_buf, p->param_len);
+            p_cb->rand_enc_proc_state = SMP_GENERATE_PRIVATE_KEY_8_15;
+            btsnd_hcic_ble_rand((void *)smp_rand_back);
+            break;
+
+        case SMP_GENERATE_PRIVATE_KEY_8_15:
+            memcpy((void *)&p_cb->private_key[8], p->param_buf, p->param_len);
+            p_cb->rand_enc_proc_state = SMP_GENERATE_PRIVATE_KEY_16_23;
+            btsnd_hcic_ble_rand((void *)smp_rand_back);
+            break;
+
+        case SMP_GENERATE_PRIVATE_KEY_16_23:
+            memcpy((void *)&p_cb->private_key[16], p->param_buf, p->param_len);
+            p_cb->rand_enc_proc_state = SMP_GENERATE_PRIVATE_KEY_24_31;
+            btsnd_hcic_ble_rand((void *)smp_rand_back);
+            break;
+
+        case SMP_GENERATE_PRIVATE_KEY_24_31:
+            memcpy((void *)&p_cb->private_key[24], p->param_buf, p->param_len);
+            smp_process_private_key (p_cb);
+            break;
+
+        default:
+            break;
+    }
+
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         smp_process_private_key
+**
+** Description      This function processes private key.
+**                  It calculates public key and notifies SM that private key /
+**                  public key pair is created.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_process_private_key(tSMP_CB *p_cb)
+{
+    Point       public_key;
+    BT_OCTET32  private_key;
+
+    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);
+    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);
+
+    smp_debug_print_nbyte_little_endian (p_cb->private_key, (const uint8_t *)"private",
+                                         BT_OCTET32_LEN);
+    smp_debug_print_nbyte_little_endian (p_cb->loc_publ_key.x, (const uint8_t *)"local public(x)",
+                                         BT_OCTET32_LEN);
+    smp_debug_print_nbyte_little_endian (p_cb->loc_publ_key.y, (const uint8_t *)"local public(y)",
+                                         BT_OCTET32_LEN);
+    p_cb->flags |= SMP_PAIR_FLAG_HAVE_LOCAL_PUBL_KEY;
+    smp_sm_event(p_cb, SMP_LOC_PUBL_KEY_CRTD_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         smp_compute_dhkey
+**
+** Description      The function:
+**                  - calculates a new public key using as input local private
+**                    key and peer public key;
+**                  - saves the new public key x-coordinate as DHKey.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_compute_dhkey (tSMP_CB *p_cb)
+{
+    Point       peer_publ_key, new_publ_key;
+    BT_OCTET32  private_key;
+
+    SMP_TRACE_DEBUG ("%s", __func__);
+
+    memcpy(private_key, p_cb->private_key, BT_OCTET32_LEN);
+    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);
+
+    memcpy(p_cb->dhkey, new_publ_key.x, BT_OCTET32_LEN);
+
+    smp_debug_print_nbyte_little_endian (p_cb->dhkey, (const uint8_t *)"Old DHKey",
+                                         BT_OCTET32_LEN);
+
+    smp_debug_print_nbyte_little_endian (p_cb->private_key, (const uint8_t *)"private",
+                                         BT_OCTET32_LEN);
+    smp_debug_print_nbyte_little_endian (p_cb->peer_publ_key.x, (const uint8_t *)"rem public(x)",
+                                         BT_OCTET32_LEN);
+    smp_debug_print_nbyte_little_endian (p_cb->peer_publ_key.y, (const uint8_t *)"rem public(y)",
+                                         BT_OCTET32_LEN);
+    smp_debug_print_nbyte_little_endian (p_cb->dhkey, (const uint8_t *)"Reverted DHKey",
+                                         BT_OCTET32_LEN);
+}
+
+/*******************************************************************************
+**
+** Function         smp_calculate_local_commitment
+**
+** Description      The function calculates and saves local commmitment in CB.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_calculate_local_commitment(tSMP_CB *p_cb)
+{
+    uint8_t random_input;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    switch (p_cb->selected_association_model)
+    {
+        case SMP_MODEL_SEC_CONN_JUSTWORKS:
+        case SMP_MODEL_SEC_CONN_NUM_COMP:
+            if (p_cb->role  == HCI_ROLE_MASTER)
+                SMP_TRACE_WARNING ("local commitment calc on master is not expected \
+                                    for Just Works/Numeric Comparison models");
+            smp_calculate_f4(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand, 0,
+                             p_cb->commitment);
+            break;
+        case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
+        case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
+            random_input = smp_calculate_random_input(p_cb->local_random, p_cb->round);
+            smp_calculate_f4(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand,
+                             random_input, p_cb->commitment);
+            break;
+        case SMP_MODEL_SEC_CONN_OOB:
+            SMP_TRACE_WARNING ("local commitment calc is expected for OOB model BEFORE pairing");
+            smp_calculate_f4(p_cb->loc_publ_key.x, p_cb->loc_publ_key.x, p_cb->local_random, 0,
+                             p_cb->commitment);
+            break;
+        default:
+            SMP_TRACE_ERROR("Association Model = %d is not used in LE SC",
+                             p_cb->selected_association_model);
+            return;
+    }
+
+    SMP_TRACE_EVENT ("local commitment calculation is completed");
+}
+
+/*******************************************************************************
+**
+** Function         smp_calculate_peer_commitment
+**
+** Description      The function calculates and saves peer commmitment at the
+**                  provided output buffer.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_calculate_peer_commitment(tSMP_CB *p_cb, BT_OCTET16 output_buf)
+{
+    uint8_t ri;
+
+    SMP_TRACE_DEBUG ("%s", __func__);
+
+    switch (p_cb->selected_association_model)
+    {
+        case SMP_MODEL_SEC_CONN_JUSTWORKS:
+        case SMP_MODEL_SEC_CONN_NUM_COMP:
+            if (p_cb->role  == HCI_ROLE_SLAVE)
+                SMP_TRACE_WARNING ("peer commitment calc on slave is not expected \
+                for Just Works/Numeric Comparison models");
+            smp_calculate_f4(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, p_cb->rrand, 0,
+                             output_buf);
+            break;
+        case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
+        case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
+            ri = smp_calculate_random_input(p_cb->peer_random, p_cb->round);
+            smp_calculate_f4(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, p_cb->rrand, ri,
+                             output_buf);
+            break;
+        case SMP_MODEL_SEC_CONN_OOB:
+            smp_calculate_f4(p_cb->peer_publ_key.x, p_cb->peer_publ_key.x, p_cb->peer_random, 0,
+                             output_buf);
+            break;
+        default:
+            SMP_TRACE_ERROR("Association Model = %d is not used in LE SC",
+                             p_cb->selected_association_model);
+            return;
+    }
+
+    SMP_TRACE_EVENT ("peer commitment calculation is completed");
+}
+
+/*******************************************************************************
+**
+** Function         smp_calculate_f4
+**
+** Description      The function calculates
+**                  C = f4(U, V, X, Z) = AES-CMAC (U||V||Z)
+**                                               X
+**                  where
+**                  input:  U is 256 bit,
+**                          V is 256 bit,
+**                          X is 128 bit,
+**                          Z is 8 bit,
+**                  output: C is 128 bit.
+**
+** Returns          void
+**
+** Note             The LSB is the first octet, the MSB is the last octet of
+**                  the AES-CMAC input/output stream.
+**
+*******************************************************************************/
+void smp_calculate_f4(uint8_t *u, uint8_t *v, uint8_t *x, uint8_t z, uint8_t *c)
+{
+    uint8_t msg_len = BT_OCTET32_LEN /* U size */ + BT_OCTET32_LEN /* V size */ + 1 /* Z size */;
+    uint8_t msg[BT_OCTET32_LEN + BT_OCTET32_LEN + 1];
+    uint8_t key[BT_OCTET16_LEN];
+    uint8_t cmac[BT_OCTET16_LEN];
+    uint8_t *p = NULL;
+#if (SMP_DEBUG == TRUE)
+    uint8_t *p_prnt = NULL;
+#endif
+
+    SMP_TRACE_DEBUG ("%s", __func__);
+
+#if (SMP_DEBUG == TRUE)
+    p_prnt = u;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"U", BT_OCTET32_LEN);
+    p_prnt = v;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"V", BT_OCTET32_LEN);
+    p_prnt = x;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"X", BT_OCTET16_LEN);
+    p_prnt = &z;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"Z", 1);
+#endif
+
+    p = msg;
+    UINT8_TO_STREAM(p, z);
+    ARRAY_TO_STREAM(p, v, BT_OCTET32_LEN);
+    ARRAY_TO_STREAM(p, u, BT_OCTET32_LEN);
+#if (SMP_DEBUG == TRUE)
+    p_prnt = msg;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"M", msg_len);
+#endif
+
+    p = key;
+    ARRAY_TO_STREAM(p, x, BT_OCTET16_LEN);
+#if (SMP_DEBUG == TRUE)
+    p_prnt = key;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"K", BT_OCTET16_LEN);
+#endif
+
+    aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac);
+#if (SMP_DEBUG == TRUE)
+    p_prnt = cmac;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"AES_CMAC", BT_OCTET16_LEN);
+#endif
+
+    p = c;
+    ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
+}
+
+/*******************************************************************************
+**
+** Function         smp_calculate_numeric_comparison_display_number
+**
+** Description      The function calculates and saves number to display in numeric
+**                  comparison association mode.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_calculate_numeric_comparison_display_number(tSMP_CB *p_cb,
+                                                     tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG ("%s", __func__);
+
+    if (p_cb->role == HCI_ROLE_MASTER)
+    {
+        p_cb->number_to_display =
+            smp_calculate_g2(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand,
+                             p_cb->rrand);
+    }
+    else
+    {
+        p_cb->number_to_display =
+            smp_calculate_g2(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, p_cb->rrand,
+                             p_cb->rand);
+    }
+
+    if (p_cb->number_to_display >= (BTM_MAX_PASSKEY_VAL + 1))
+    {
+        uint8_t reason;
+        reason = p_cb->failure = SMP_PAIR_FAIL_UNKNOWN;
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+        return;
+    }
+
+    SMP_TRACE_EVENT("Number to display in numeric comparison = %d", p_cb->number_to_display);
+    p_cb->cb_evt = SMP_NC_REQ_EVT;
+    smp_sm_event(p_cb, SMP_SC_DSPL_NC_EVT, &p_cb->number_to_display);
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         smp_calculate_g2
+**
+** Description      The function calculates
+**                  g2(U, V, X, Y) = AES-CMAC (U||V||Y) mod 2**32 mod 10**6
+**                                           X
+**                  and
+**                  Vres = g2(U, V, X, Y) mod 10**6
+**                  where
+**                  input:  U     is 256 bit,
+**                          V     is 256 bit,
+**                          X     is 128 bit,
+**                          Y     is 128 bit,
+**
+** Returns          Vres.
+**                  Expected value has to be in the range [0 - 999999] i.e. [0 - 0xF423F].
+**                  Vres = 1000000 means that the calculation fails.
+**
+** Note             The LSB is the first octet, the MSB is the last octet of
+**                  the AES-CMAC input/output stream.
+**
+*******************************************************************************/
+uint32_t smp_calculate_g2(uint8_t *u, uint8_t *v, uint8_t *x, uint8_t *y)
+{
+    uint8_t msg_len = BT_OCTET32_LEN /* U size */ + BT_OCTET32_LEN /* V size */
+                      + BT_OCTET16_LEN /* Y size */;
+    uint8_t msg[BT_OCTET32_LEN + BT_OCTET32_LEN + BT_OCTET16_LEN];
+    uint8_t key[BT_OCTET16_LEN];
+    uint8_t cmac[BT_OCTET16_LEN];
+    uint8_t *p = NULL;
+    uint32_t vres;
+#if (SMP_DEBUG == TRUE)
+    uint8_t *p_prnt = NULL;
+#endif
+
+    SMP_TRACE_DEBUG ("%s", __func__);
+
+    p = msg;
+    ARRAY_TO_STREAM(p, y, BT_OCTET16_LEN);
+    ARRAY_TO_STREAM(p, v, BT_OCTET32_LEN);
+    ARRAY_TO_STREAM(p, u, BT_OCTET32_LEN);
+#if (SMP_DEBUG == TRUE)
+    p_prnt = u;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"U", BT_OCTET32_LEN);
+    p_prnt = v;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"V", BT_OCTET32_LEN);
+    p_prnt = x;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"X", BT_OCTET16_LEN);
+    p_prnt = y;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"Y", BT_OCTET16_LEN);
+#endif
+
+    p = key;
+    ARRAY_TO_STREAM(p, x, BT_OCTET16_LEN);
+#if (SMP_DEBUG == TRUE)
+    p_prnt = key;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"K", BT_OCTET16_LEN);
+#endif
+
+    if(!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac))
+    {
+        SMP_TRACE_ERROR("%s failed",__func__);
+        return (BTM_MAX_PASSKEY_VAL + 1);
+    }
+
+#if (SMP_DEBUG == TRUE)
+    p_prnt = cmac;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"AES-CMAC", BT_OCTET16_LEN);
+#endif
+
+    /* vres = cmac mod 2**32 mod 10**6 */
+    p = &cmac[0];
+    STREAM_TO_UINT32(vres, p);
+#if (SMP_DEBUG == TRUE)
+    p_prnt = (uint8_t *) &vres;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"cmac mod 2**32", 4);
+#endif
+
+    while (vres > BTM_MAX_PASSKEY_VAL)
+        vres -= (BTM_MAX_PASSKEY_VAL + 1);
+#if (SMP_DEBUG == TRUE)
+    p_prnt = (uint8_t *) &vres;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"cmac mod 2**32 mod 10**6", 4);
+#endif
+
+    SMP_TRACE_ERROR("Value for numeric comparison = %d", vres);
+    return vres;
+}
+
+/*******************************************************************************
+**
+** Function         smp_calculate_f5
+**
+** Description      The function provides two AES-CMAC that are supposed to be used as
+**                  - MacKey (MacKey is used in pairing DHKey check calculation);
+**                  - LTK (LTK is used to ecrypt the link after completion of Phase 2
+**                    and on reconnection, to derive BR/EDR LK).
+**                  The function inputs are W, N1, N2, A1, A2.
+**                  F5 rules:
+**                  - the value used as key in MacKey/LTK (T) is calculated
+**                    (function smp_calculate_f5_key(...));
+**                    The formula is:
+**                          T = AES-CMAC    (W)
+**                                      salt
+**                    where salt is internal parameter of smp_calculate_f5_key(...).
+**                  - MacKey and LTK are calculated as AES-MAC values received with the
+**                    key T calculated in the previous step and the plaintext message
+**                    built from the external parameters N1, N2, A1, A2 and the internal
+**                    parameters counter, keyID, length.
+**                    The function smp_calculate_f5_mackey_or_long_term_key(...) is used in the
+**                    calculations.
+**                    The same formula is used in calculation of MacKey and LTK and the
+**                    same parameter values except the value of the internal parameter
+**                    counter:
+**                    - in MacKey calculations the value is 0;
+**                    - in LTK calculations the value is 1.
+**                      MacKey  = AES-CMAC (Counter=0||keyID||N1||N2||A1||A2||Length=256)
+**                                        T
+**                      LTK     = AES-CMAC (Counter=1||keyID||N1||N2||A1||A2||Length=256)
+**                                        T
+**                  The parameters are
+**                  input:
+**                          W       is 256 bits,
+**                          N1      is 128 bits,
+**                          N2      is 128 bits,
+**                          A1 is 56 bit,
+**                          A2 is 56 bit.
+**                  internal:
+**                          Counter is 8 bits,  its value is 0 for MacKey,
+**                                                          1 for LTK;
+**                          KeyId   is 32 bits, its value is
+**                                              0x62746c65 (MSB~LSB);
+**                          Length  is 16 bits, its value is 0x0100
+**                                              (MSB~LSB).
+**                  output:
+**                          MacKey  is 128 bits;
+**                          LTK     is 128 bits
+**
+** Returns          false if out of resources, true in other cases.
+**
+** Note             The LSB is the first octet, the MSB is the last octet of
+**                  the AES-CMAC input/output stream.
+**
+*******************************************************************************/
+bool    smp_calculate_f5(uint8_t *w, uint8_t *n1, uint8_t *n2, uint8_t *a1, uint8_t *a2,
+                         uint8_t *mac_key, uint8_t *ltk)
+{
+    BT_OCTET16  t;    /* AES-CMAC output in smp_calculate_f5_key(...), key in */
+                      /* smp_calculate_f5_mackey_or_long_term_key(...) */
+#if (SMP_DEBUG == TRUE)
+    uint8_t *p_prnt = NULL;
+#endif
+    /* internal parameters: */
+
+    /*
+        counter is 0 for MacKey,
+                is 1 for LTK
+    */
+    uint8_t counter_mac_key[1]  = {0};
+    uint8_t counter_ltk[1]      = {1};
+    /*
+        keyID   62746c65
+    */
+    uint8_t key_id[4] = {0x65, 0x6c, 0x74, 0x62};
+    /*
+        length  0100
+    */
+    uint8_t length[2] = {0x00, 0x01};
+
+    SMP_TRACE_DEBUG ("%s", __func__);
+#if (SMP_DEBUG == TRUE)
+    p_prnt = w;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"W", BT_OCTET32_LEN);
+    p_prnt = n1;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"N1", BT_OCTET16_LEN);
+    p_prnt = n2;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"N2", BT_OCTET16_LEN);
+    p_prnt = a1;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"A1", 7);
+    p_prnt = a2;
+    smp_debug_print_nbyte_little_endian (p_prnt,(const uint8_t *) "A2", 7);
+#endif
+
+    if (!smp_calculate_f5_key(w, t))
+    {
+        SMP_TRACE_ERROR("%s failed to calc T",__func__);
+        return false;
+    }
+#if (SMP_DEBUG == TRUE)
+    p_prnt = t;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"T", BT_OCTET16_LEN);
+#endif
+
+    if (!smp_calculate_f5_mackey_or_long_term_key(t, counter_mac_key, key_id, n1, n2, a1, a2,
+                                                  length, mac_key))
+    {
+        SMP_TRACE_ERROR("%s failed to calc MacKey", __func__);
+        return false;
+    }
+#if (SMP_DEBUG == TRUE)
+    p_prnt = mac_key;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"MacKey", BT_OCTET16_LEN);
+#endif
+
+    if (!smp_calculate_f5_mackey_or_long_term_key(t, counter_ltk, key_id, n1, n2, a1, a2,
+                                                  length, ltk))
+    {
+        SMP_TRACE_ERROR("%s failed to calc LTK",__func__);
+        return false;
+    }
+#if (SMP_DEBUG == TRUE)
+    p_prnt = ltk;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"LTK", BT_OCTET16_LEN);
+#endif
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         smp_calculate_f5_mackey_or_long_term_key
+**
+** Description      The function calculates the value of MacKey or LTK by the rules
+**                  defined for f5 function.
+**                  At the moment exactly the same formula is used to calculate
+**                  LTK and MacKey.
+**                  The difference is the value of input parameter Counter:
+**                  - in MacKey calculations the value is 0;
+**                  - in LTK calculations the value is 1.
+**                  The formula:
+**                  mac = AES-CMAC (Counter||keyID||N1||N2||A1||A2||Length)
+**                                T
+**                  where
+**                  input:      T       is 256 bits;
+**                              Counter is 8 bits, its value is 0 for MacKey,
+**                                                              1 for LTK;
+**                              keyID   is 32 bits, its value is 0x62746c65;
+**                              N1      is 128 bits;
+**                              N2      is 128 bits;
+**                              A1      is 56 bits;
+**                              A2      is 56 bits;
+**                              Length  is 16 bits, its value is 0x0100
+**                  output:     LTK     is 128 bit.
+**
+** Returns          false if out of resources, true in other cases.
+**
+** Note             The LSB is the first octet, the MSB is the last octet of
+**                  the AES-CMAC input/output stream.
+**
+*******************************************************************************/
+bool    smp_calculate_f5_mackey_or_long_term_key(uint8_t *t, uint8_t *counter,
+                                  uint8_t *key_id, uint8_t *n1, uint8_t *n2, uint8_t *a1, uint8_t *a2,
+                                  uint8_t *length, uint8_t *mac)
+{
+    uint8_t *p = NULL;
+    uint8_t cmac[BT_OCTET16_LEN];
+    uint8_t key[BT_OCTET16_LEN];
+    uint8_t msg_len = 1 /* Counter size */ + 4 /* keyID size */ +
+            BT_OCTET16_LEN /* N1 size */ + BT_OCTET16_LEN /* N2 size */ +
+            7 /* A1 size*/ + 7 /* A2 size*/ + 2 /* Length size */;
+    uint8_t msg[1 + 4 + BT_OCTET16_LEN + BT_OCTET16_LEN + 7 + 7 + 2];
+    bool    ret = true;
+#if (SMP_DEBUG == TRUE)
+    uint8_t *p_prnt = NULL;
+#endif
+
+    SMP_TRACE_DEBUG ("%s", __func__);
+#if (SMP_DEBUG == TRUE)
+    p_prnt = t;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"T", BT_OCTET16_LEN);
+    p_prnt = counter;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"Counter", 1);
+    p_prnt = key_id;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"KeyID", 4);
+    p_prnt = n1;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"N1", BT_OCTET16_LEN);
+    p_prnt = n2;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"N2", BT_OCTET16_LEN);
+    p_prnt = a1;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"A1", 7);
+    p_prnt = a2;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"A2", 7);
+    p_prnt = length;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"Length", 2);
+#endif
+
+    p = key;
+    ARRAY_TO_STREAM(p, t, BT_OCTET16_LEN);
+#if (SMP_DEBUG == TRUE)
+    p_prnt = key;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"K", BT_OCTET16_LEN);
+#endif
+    p = msg;
+    ARRAY_TO_STREAM(p, length, 2);
+    ARRAY_TO_STREAM(p, a2, 7);
+    ARRAY_TO_STREAM(p, a1, 7);
+    ARRAY_TO_STREAM(p, n2, BT_OCTET16_LEN);
+    ARRAY_TO_STREAM(p, n1, BT_OCTET16_LEN);
+    ARRAY_TO_STREAM(p, key_id, 4);
+    ARRAY_TO_STREAM(p, counter, 1);
+#if (SMP_DEBUG == TRUE)
+    p_prnt = msg;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"M", msg_len);
+#endif
+
+    if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac))
+    {
+        SMP_TRACE_ERROR("%s failed", __func__);
+        ret = false;
+    }
+
+#if (SMP_DEBUG == TRUE)
+    p_prnt = cmac;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"AES-CMAC", BT_OCTET16_LEN);
+#endif
+
+    p = mac;
+    ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
+    return ret;
+}
+
+/*******************************************************************************
+**
+** Function         smp_calculate_f5_key
+**
+** Description      The function calculates key T used in calculation of
+**                  MacKey and LTK (f5 output is defined as MacKey || LTK).
+**                  T = AES-CMAC    (W)
+**                              salt
+**                  where
+**                  Internal:   salt    is 128 bit.
+**                  input:      W       is 256 bit.
+**                  Output:     T       is 128 bit.
+**
+** Returns          false if out of resources, true in other cases.
+**
+** Note             The LSB is the first octet, the MSB is the last octet of
+**                  the AES-CMAC input/output stream.
+**
+*******************************************************************************/
+bool    smp_calculate_f5_key(uint8_t *w, uint8_t *t)
+{
+    uint8_t *p = NULL;
+    /* Please see 2.2.7 LE Secure Connections Key Generation Function f5 */
+    /*
+        salt:   6C88 8391 AAF5 A538 6037 0BDB 5A60 83BE
+    */
+    BT_OCTET16  salt = {
+        0xBE, 0x83, 0x60, 0x5A, 0xDB, 0x0B, 0x37, 0x60,
+        0x38, 0xA5, 0xF5, 0xAA, 0x91, 0x83, 0x88, 0x6C
+    };
+#if (SMP_DEBUG == TRUE)
+    uint8_t *p_prnt = NULL;
+#endif
+
+    SMP_TRACE_DEBUG ("%s", __func__);
+#if (SMP_DEBUG == TRUE)
+    p_prnt = salt;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"salt", BT_OCTET16_LEN);
+    p_prnt = w;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"W", BT_OCTET32_LEN);
+#endif
+
+    BT_OCTET16 key;
+    BT_OCTET32 msg;
+
+    p = key;
+    ARRAY_TO_STREAM(p, salt, BT_OCTET16_LEN);
+    p = msg;
+    ARRAY_TO_STREAM(p, w, BT_OCTET32_LEN);
+#if (SMP_DEBUG == TRUE)
+    p_prnt = key;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"K", BT_OCTET16_LEN);
+    p_prnt = msg;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"M", BT_OCTET32_LEN);
+#endif
+
+    BT_OCTET16 cmac;
+    bool    ret = true;
+    if (!aes_cipher_msg_auth_code(key, msg, BT_OCTET32_LEN, BT_OCTET16_LEN, cmac))
+    {
+        SMP_TRACE_ERROR("%s failed", __func__);
+        ret = false;
+    }
+
+#if (SMP_DEBUG == TRUE)
+    p_prnt = cmac;
+    smp_debug_print_nbyte_little_endian (p_prnt, (const uint8_t *)"AES-CMAC", BT_OCTET16_LEN);
+#endif
+
+    p = t;
+    ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
+    return ret;
+}
+
+/*******************************************************************************
+**
+** Function         smp_calculate_local_dhkey_check
+**
+** Description      The function calculates and saves local device DHKey check
+**                  value in CB.
+**                  Before doing this it calls smp_calculate_f5_mackey_and_long_term_key(...).
+**                  to calculate MacKey and LTK.
+**                  MacKey is used in dhkey calculation.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_calculate_local_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t iocap[3], a[7], b[7];
+
+    SMP_TRACE_DEBUG ("%s", __func__);
+
+    smp_calculate_f5_mackey_and_long_term_key(p_cb);
+
+    smp_collect_local_io_capabilities(iocap, p_cb);
+
+    smp_collect_local_ble_address(a, p_cb);
+    smp_collect_peer_ble_address(b, p_cb);
+    smp_calculate_f6(p_cb->mac_key, p_cb->rand, p_cb->rrand, p_cb->peer_random, iocap, a, b,
+                     p_cb->dhkey_check);
+
+    SMP_TRACE_EVENT ("local DHKey check calculation is completed");
+}
+
+/*******************************************************************************
+**
+** Function         smp_calculate_peer_dhkey_check
+**
+** Description      The function calculates peer device DHKey check value.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_calculate_peer_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    uint8_t     iocap[3], a[7], b[7];
+    BT_OCTET16  param_buf;
+    bool        ret;
+    tSMP_KEY    key;
+    tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+    SMP_TRACE_DEBUG ("%s", __func__);
+
+    smp_collect_peer_io_capabilities(iocap, p_cb);
+
+    smp_collect_local_ble_address(a, p_cb);
+    smp_collect_peer_ble_address(b, p_cb);
+    ret = smp_calculate_f6(p_cb->mac_key, p_cb->rrand, p_cb->rand, p_cb->local_random, iocap,
+                           b, a, param_buf);
+
+    if (ret)
+    {
+        SMP_TRACE_EVENT ("peer DHKey check calculation is completed");
+#if (SMP_DEBUG == TRUE)
+        smp_debug_print_nbyte_little_endian (param_buf, (const uint8_t *)"peer DHKey check",
+                                             BT_OCTET16_LEN);
+#endif
+        key.key_type = SMP_KEY_TYPE_PEER_DHK_CHCK;
+        key.p_data   = param_buf;
+        smp_sm_event(p_cb, SMP_SC_KEY_READY_EVT, &key);
+    }
+    else
+    {
+        SMP_TRACE_EVENT ("peer DHKey check calculation failed");
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         smp_calculate_f6
+**
+** Description      The function calculates
+**                  C = f6(W, N1, N2, R, IOcap, A1, A2) = AES-CMAC (N1||N2||R||IOcap||A1||A2)
+**                                                                W
+**                  where
+**                  input:  W is 128 bit,
+**                          N1 is 128 bit,
+**                          N2 is 128 bit,
+**                          R is 128 bit,
+**                          IOcap is 24 bit,
+**                          A1 is 56 bit,
+**                          A2 is 56 bit,
+**                  output: C is 128 bit.
+**
+** Returns          false if out of resources, true in other cases.
+**
+** Note             The LSB is the first octet, the MSB is the last octet of
+**                  the AES-CMAC input/output stream.
+**
+*******************************************************************************/
+bool    smp_calculate_f6(uint8_t *w, uint8_t *n1, uint8_t *n2, uint8_t *r, uint8_t *iocap, uint8_t *a1,
+                         uint8_t *a2, uint8_t *c)
+{
+    uint8_t *p = NULL;
+    uint8_t msg_len = BT_OCTET16_LEN /* N1 size */ + BT_OCTET16_LEN /* N2 size */ +
+                      BT_OCTET16_LEN /* R size */ + 3 /* IOcap size */ + 7 /* A1 size*/
+                      + 7 /* A2 size*/;
+    uint8_t msg[BT_OCTET16_LEN + BT_OCTET16_LEN + BT_OCTET16_LEN + 3 + 7 + 7];
+#if (SMP_DEBUG == TRUE)
+    uint8_t *p_print = NULL;
+#endif
+
+    SMP_TRACE_DEBUG ("%s", __func__);
+#if (SMP_DEBUG == TRUE)
+    p_print = w;
+    smp_debug_print_nbyte_little_endian (p_print, (const uint8_t *)"W", BT_OCTET16_LEN);
+    p_print = n1;
+    smp_debug_print_nbyte_little_endian (p_print, (const uint8_t *)"N1", BT_OCTET16_LEN);
+    p_print = n2;
+    smp_debug_print_nbyte_little_endian (p_print, (const uint8_t *)"N2", BT_OCTET16_LEN);
+    p_print = r;
+    smp_debug_print_nbyte_little_endian (p_print, (const uint8_t *)"R", BT_OCTET16_LEN);
+    p_print = iocap;
+    smp_debug_print_nbyte_little_endian (p_print, (const uint8_t *)"IOcap", 3);
+    p_print = a1;
+    smp_debug_print_nbyte_little_endian (p_print, (const uint8_t *)"A1", 7);
+    p_print = a2;
+    smp_debug_print_nbyte_little_endian (p_print, (const uint8_t *)"A2", 7);
+#endif
+
+    uint8_t cmac[BT_OCTET16_LEN];
+    uint8_t key[BT_OCTET16_LEN];
+
+    p = key;
+    ARRAY_TO_STREAM(p, w, BT_OCTET16_LEN);
+#if (SMP_DEBUG == TRUE)
+    p_print = key;
+    smp_debug_print_nbyte_little_endian (p_print, (const uint8_t *)"K", BT_OCTET16_LEN);
+#endif
+
+    p = msg;
+    ARRAY_TO_STREAM(p, a2, 7);
+    ARRAY_TO_STREAM(p, a1, 7);
+    ARRAY_TO_STREAM(p, iocap, 3);
+    ARRAY_TO_STREAM(p, r, BT_OCTET16_LEN);
+    ARRAY_TO_STREAM(p, n2, BT_OCTET16_LEN);
+    ARRAY_TO_STREAM(p, n1, BT_OCTET16_LEN);
+#if (SMP_DEBUG == TRUE)
+    p_print = msg;
+    smp_debug_print_nbyte_little_endian (p_print, (const uint8_t *)"M", msg_len);
+#endif
+
+    bool    ret = true;
+    if(!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac))
+    {
+        SMP_TRACE_ERROR("%s failed", __func__);
+        ret = false;
+    }
+
+#if (SMP_DEBUG == TRUE)
+    p_print = cmac;
+    smp_debug_print_nbyte_little_endian (p_print, (const uint8_t *)"AES-CMAC", BT_OCTET16_LEN);
+#endif
+
+    p = c;
+    ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
+    return ret;
+}
+
+/*******************************************************************************
+**
+** Function         smp_calculate_link_key_from_long_term_key
+**
+** Description      The function calculates and saves BR/EDR link key derived from
+**                  LE SC LTK.
+**
+** Returns          false if out of resources, true in other cases.
+**
+*******************************************************************************/
+bool    smp_calculate_link_key_from_long_term_key(tSMP_CB *p_cb)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec;
+    BD_ADDR bda_for_lk;
+    tBLE_ADDR_TYPE conn_addr_type;
+
+    SMP_TRACE_DEBUG ("%s", __func__);
+
+    if (p_cb->id_addr_rcvd && p_cb->id_addr_type == BLE_ADDR_PUBLIC)
+    {
+        SMP_TRACE_DEBUG ("Use rcvd identity address as BD_ADDR of LK rcvd identity address");
+        memcpy(bda_for_lk, p_cb->id_addr, BD_ADDR_LEN);
+    }
+    else if ((BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, bda_for_lk, &conn_addr_type)) &&
+              conn_addr_type == BLE_ADDR_PUBLIC)
+    {
+        SMP_TRACE_DEBUG ("Use rcvd connection address as BD_ADDR of LK");
+    }
+    else
+    {
+        SMP_TRACE_WARNING ("Don't have peer public address to associate with LK");
+        return false;
+    }
+
+    if ((p_dev_rec = btm_find_dev (p_cb->pairing_bda)) == NULL)
+    {
+        SMP_TRACE_ERROR("%s failed to find Security Record", __func__);
+        return false;
+    }
+
+    BT_OCTET16 intermediate_link_key;
+    bool    ret = true;
+
+    ret = smp_calculate_h6(p_cb->ltk, (uint8_t *)"1pmt" /* reversed "tmp1" */,intermediate_link_key);
+    if (!ret)
+    {
+        SMP_TRACE_ERROR("%s failed to derive intermediate_link_key", __func__);
+        return ret;
+    }
+
+    BT_OCTET16 link_key;
+    ret = smp_calculate_h6(intermediate_link_key, (uint8_t *) "rbel" /* reversed "lebr" */, link_key);
+    if (!ret)
+    {
+        SMP_TRACE_ERROR("%s failed", __func__);
+    }
+    else
+    {
+        uint8_t link_key_type;
+        if (btm_cb.security_mode == BTM_SEC_MODE_SC)
+        {
+            /* Secure Connections Only Mode */
+            link_key_type = BTM_LKEY_TYPE_AUTH_COMB_P_256;
+        }
+        else if (controller_get_interface()->supports_secure_connections())
+        {
+            /* both transports are SC capable */
+            if (p_cb->sec_level == SMP_SEC_AUTHENTICATED)
+                link_key_type = BTM_LKEY_TYPE_AUTH_COMB_P_256;
+            else
+                link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB_P_256;
+        }
+        else if (btm_cb.security_mode == BTM_SEC_MODE_SP)
+        {
+            /* BR/EDR transport is SSP capable */
+            if (p_cb->sec_level == SMP_SEC_AUTHENTICATED)
+                link_key_type = BTM_LKEY_TYPE_AUTH_COMB;
+            else
+                link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB;
+        }
+        else
+        {
+            SMP_TRACE_ERROR ("%s failed to update link_key. Sec Mode = %d, sm4 = 0x%02x",
+                 __func__, btm_cb.security_mode, p_dev_rec->sm4);
+            return false;
+        }
+
+        link_key_type += BTM_LTK_DERIVED_LKEY_OFFSET;
+
+        uint8_t *p;
+        BT_OCTET16 notif_link_key;
+        p = notif_link_key;
+        ARRAY16_TO_STREAM(p, link_key);
+
+        btm_sec_link_key_notification (bda_for_lk, notif_link_key, link_key_type);
+
+        SMP_TRACE_EVENT ("%s is completed", __func__);
+    }
+
+    return ret;
+}
+
+/*******************************************************************************
+**
+** Function         smp_calculate_long_term_key_from_link_key
+**
+** Description      The function calculates and saves SC LTK derived from BR/EDR
+**                  link key.
+**
+** Returns          false if out of resources, true in other cases.
+**
+*******************************************************************************/
+bool    smp_calculate_long_term_key_from_link_key(tSMP_CB *p_cb)
+{
+    bool    ret = true;
+    tBTM_SEC_DEV_REC *p_dev_rec;
+    uint8_t rev_link_key[16];
+
+    SMP_TRACE_DEBUG ("%s", __func__);
+
+    if ((p_dev_rec = btm_find_dev (p_cb->pairing_bda)) == NULL)
+    {
+        SMP_TRACE_ERROR("%s failed to find Security Record",__func__);
+        return false;
+    }
+
+    uint8_t br_link_key_type;
+    if ((br_link_key_type = BTM_SecGetDeviceLinkKeyType (p_cb->pairing_bda))
+        == BTM_LKEY_TYPE_IGNORE)
+    {
+        SMP_TRACE_ERROR("%s failed to retrieve BR link type",__func__);
+        return false;
+    }
+
+    if ((br_link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256) &&
+        (br_link_key_type != BTM_LKEY_TYPE_UNAUTH_COMB_P_256))
+    {
+        SMP_TRACE_ERROR("%s LE SC LTK can't be derived from LK %d",
+                         __func__, br_link_key_type);
+        return false;
+    }
+
+    uint8_t *p1;
+    uint8_t *p2;
+    p1 = rev_link_key;
+    p2 = p_dev_rec->link_key;
+    REVERSE_ARRAY_TO_STREAM(p1, p2, 16);
+
+    BT_OCTET16 intermediate_long_term_key;
+    /* "tmp2" obtained from the spec */
+    ret = smp_calculate_h6(rev_link_key, (uint8_t *) "2pmt" /* reversed "tmp2" */,
+                           intermediate_long_term_key);
+
+    if (!ret)
+    {
+        SMP_TRACE_ERROR("%s failed to derive intermediate_long_term_key",__func__);
+        return ret;
+    }
+
+    /* "brle" obtained from the spec */
+    ret = smp_calculate_h6(intermediate_long_term_key, (uint8_t *) "elrb" /* reversed "brle" */,
+                           p_cb->ltk);
+
+    if (!ret)
+    {
+        SMP_TRACE_ERROR("%s failed",__func__);
+    }
+    else
+    {
+        p_cb->sec_level = (br_link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256)
+                           ? SMP_SEC_AUTHENTICATED : SMP_SEC_UNAUTHENTICATE;
+        SMP_TRACE_EVENT ("%s is completed",__func__);
+    }
+
+    return ret;
+}
+
+/*******************************************************************************
+**
+** Function         smp_calculate_h6
+**
+** Description      The function calculates
+**                  C = h6(W, KeyID) = AES-CMAC (KeyID)
+**                                             W
+**                  where
+**                  input:  W is 128 bit,
+**                          KeyId is 32 bit,
+**                  output: C is 128 bit.
+**
+** Returns          false if out of resources, true in other cases.
+**
+** Note             The LSB is the first octet, the MSB is the last octet of
+**                  the AES-CMAC input/output stream.
+**
+*******************************************************************************/
+bool    smp_calculate_h6(uint8_t *w, uint8_t *keyid, uint8_t *c)
+{
+#if (SMP_DEBUG == TRUE)
+    uint8_t *p_print = NULL;
+#endif
+
+    SMP_TRACE_DEBUG ("%s",__func__);
+#if (SMP_DEBUG == TRUE)
+    p_print = w;
+    smp_debug_print_nbyte_little_endian (p_print, (const uint8_t *)"W", BT_OCTET16_LEN);
+    p_print = keyid;
+    smp_debug_print_nbyte_little_endian (p_print, (const uint8_t *)"keyID", 4);
+#endif
+
+    uint8_t *p = NULL;
+    uint8_t key[BT_OCTET16_LEN];
+
+    p = key;
+    ARRAY_TO_STREAM(p, w, BT_OCTET16_LEN);
+
+#if (SMP_DEBUG == TRUE)
+    p_print = key;
+    smp_debug_print_nbyte_little_endian (p_print, (const uint8_t *)"K", BT_OCTET16_LEN);
+#endif
+
+    uint8_t msg_len = 4 /* KeyID size */;
+    uint8_t msg[4];
+
+    p = msg;
+    ARRAY_TO_STREAM(p, keyid, 4);
+
+#if (SMP_DEBUG == TRUE)
+    p_print = msg;
+    smp_debug_print_nbyte_little_endian (p_print,(const uint8_t *) "M", msg_len);
+#endif
+
+    bool    ret = true;
+    uint8_t cmac[BT_OCTET16_LEN];
+    if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac))
+    {
+        SMP_TRACE_ERROR("%s failed",__func__);
+        ret = false;
+    }
+
+#if (SMP_DEBUG == TRUE)
+    p_print = cmac;
+    smp_debug_print_nbyte_little_endian (p_print, (const uint8_t *)"AES-CMAC", BT_OCTET16_LEN);
+#endif
+
+    p = c;
+    ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
+    return ret;
+}
+
+/*******************************************************************************
+**
+** Function         smp_start_nonce_generation
+**
+** Description      This function starts nonce generation.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_start_nonce_generation(tSMP_CB *p_cb)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+    p_cb->rand_enc_proc_state = SMP_GEN_NONCE_0_7;
+    btsnd_hcic_ble_rand((void *)smp_rand_back);
+}
+
+/*******************************************************************************
+**
+** Function         smp_finish_nonce_generation
+**
+** Description      This function finishes nonce generation.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_finish_nonce_generation(tSMP_CB *p_cb)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+    p_cb->rand_enc_proc_state = SMP_GEN_NONCE_8_15;
+    btsnd_hcic_ble_rand((void *)smp_rand_back);
+}
+
+/*******************************************************************************
+**
+** Function         smp_process_new_nonce
+**
+** Description      This function notifies SM that it has new nonce.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_process_new_nonce(tSMP_CB *p_cb)
+{
+    SMP_TRACE_DEBUG ("%s round %d", __func__, p_cb->round);
+    smp_sm_event(p_cb, SMP_HAVE_LOC_NONCE_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function         smp_rand_back
+**
+** Description      This function is to process the rand command finished,
+**                  process the random/encrypted number for further action.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void smp_rand_back(tBTM_RAND_ENC *p)
+{
+    tSMP_CB *p_cb = &smp_cb;
+    uint8_t *pp = p->param_buf;
+    uint8_t failure = SMP_PAIR_FAIL_UNKNOWN;
+    uint8_t state = p_cb->rand_enc_proc_state & ~0x80;
+
+    SMP_TRACE_DEBUG ("%s state=0x%x", __func__, state);
+    if (p && p->status == HCI_SUCCESS)
+    {
+        switch (state)
+        {
+            case SMP_GEN_SRAND_MRAND:
+                memcpy((void *)p_cb->rand, p->param_buf, p->param_len);
+                smp_generate_rand_cont(p_cb, NULL);
+                break;
+
+            case SMP_GEN_SRAND_MRAND_CONT:
+                memcpy((void *)&p_cb->rand[8], p->param_buf, p->param_len);
+                smp_generate_confirm(p_cb, NULL);
+                break;
+
+            case SMP_GEN_DIV_LTK:
+                STREAM_TO_UINT16(p_cb->div, pp);
+                smp_generate_ltk_cont(p_cb, NULL);
+                break;
+
+            case SMP_GEN_DIV_CSRK:
+                STREAM_TO_UINT16(p_cb->div, pp);
+                smp_compute_csrk(p_cb, NULL);
+                break;
+
+            case SMP_GEN_TK:
+                smp_proc_passkey(p_cb, p);
+                break;
+
+            case SMP_GEN_RAND_V:
+                memcpy(p_cb->enc_rand, p->param_buf, BT_OCTET8_LEN);
+                smp_generate_y(p_cb, NULL);
+                break;
+
+            case SMP_GENERATE_PRIVATE_KEY_0_7:
+            case SMP_GENERATE_PRIVATE_KEY_8_15:
+            case SMP_GENERATE_PRIVATE_KEY_16_23:
+            case SMP_GENERATE_PRIVATE_KEY_24_31:
+                smp_continue_private_key_creation(p_cb, p);
+                break;
+
+            case SMP_GEN_NONCE_0_7:
+                memcpy((void *)p_cb->rand, p->param_buf, p->param_len);
+                smp_finish_nonce_generation(p_cb);
+                break;
+
+            case SMP_GEN_NONCE_8_15:
+                memcpy((void *)&p_cb->rand[8], p->param_buf, p->param_len);
+                smp_process_new_nonce(p_cb);
+                break;
+        }
+
+        return;
+    }
+
+    SMP_TRACE_ERROR("%s key generation failed: (%d)", __func__, p_cb->rand_enc_proc_state);
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+}
+
+#endif
+
diff --git a/bt/stack/smp/smp_l2c.cc b/bt/stack/smp/smp_l2c.cc
new file mode 100644
index 0000000..a7a8e6d
--- /dev/null
+++ b/bt/stack/smp/smp_l2c.cc
@@ -0,0 +1,345 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 functions for the SMP L2Cap interface
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if (SMP_INCLUDED == TRUE)
+
+#include <string.h>
+#include "btm_ble_api.h"
+#include "l2c_api.h"
+
+#include "smp_int.h"
+
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+static void smp_tx_complete_callback(uint16_t cid, uint16_t num_pkt);
+
+static void smp_connect_callback(uint16_t channel, BD_ADDR bd_addr, bool    connected, uint16_t reason,
+                               tBT_TRANSPORT transport);
+static void smp_data_received(uint16_t channel, BD_ADDR bd_addr, BT_HDR *p_buf);
+
+static void smp_br_connect_callback(uint16_t channel, BD_ADDR bd_addr, bool    connected, uint16_t reason,
+                                    tBT_TRANSPORT transport);
+static void smp_br_data_received(uint16_t channel, BD_ADDR bd_addr, BT_HDR *p_buf);
+
+/*******************************************************************************
+**
+** Function         smp_l2cap_if_init
+**
+** Description      This function is called during the SMP task startup
+**                  to register interface functions with L2CAP.
+**
+*******************************************************************************/
+void smp_l2cap_if_init (void)
+{
+    tL2CAP_FIXED_CHNL_REG  fixed_reg;
+    SMP_TRACE_EVENT ("SMDBG l2c %s", __func__);
+    fixed_reg.fixed_chnl_opts.mode         = L2CAP_FCR_BASIC_MODE;
+    fixed_reg.fixed_chnl_opts.max_transmit = 0;
+    fixed_reg.fixed_chnl_opts.rtrans_tout  = 0;
+    fixed_reg.fixed_chnl_opts.mon_tout     = 0;
+    fixed_reg.fixed_chnl_opts.mps          = 0;
+    fixed_reg.fixed_chnl_opts.tx_win_sz    = 0;
+
+    fixed_reg.pL2CA_FixedConn_Cb = smp_connect_callback;
+    fixed_reg.pL2CA_FixedData_Cb = smp_data_received;
+    fixed_reg.pL2CA_FixedTxComplete_Cb = smp_tx_complete_callback;
+
+    fixed_reg.pL2CA_FixedCong_Cb = NULL;    /* do not handle congestion on this channel */
+    fixed_reg.default_idle_tout  = 60;      /* set 60 seconds timeout, 0xffff default idle timeout */
+
+    L2CA_RegisterFixedChannel (L2CAP_SMP_CID, &fixed_reg);
+
+    fixed_reg.pL2CA_FixedConn_Cb = smp_br_connect_callback;
+    fixed_reg.pL2CA_FixedData_Cb = smp_br_data_received;
+
+    L2CA_RegisterFixedChannel (L2CAP_SMP_BR_CID, &fixed_reg);
+}
+
+/*******************************************************************************
+**
+** Function         smp_connect_callback
+**
+** Description      This callback function is called by L2CAP to indicate that
+**                  SMP channel is
+**                      connected (conn = true)/disconnected (conn = false).
+**
+*******************************************************************************/
+static void smp_connect_callback (uint16_t channel, BD_ADDR bd_addr, bool    connected, uint16_t reason,
+                                  tBT_TRANSPORT transport)
+{
+    tSMP_CB   *p_cb = &smp_cb;
+    tSMP_INT_DATA   int_data;
+    BD_ADDR dummy_bda = {0};
+
+    SMP_TRACE_EVENT ("SMDBG l2c %s", __func__);
+
+    if (transport == BT_TRANSPORT_BR_EDR || memcmp(bd_addr, dummy_bda, BD_ADDR_LEN) == 0)
+        return;
+
+    if (memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0)
+    {
+        SMP_TRACE_EVENT ("%s()  for pairing BDA: %08x%04x  Event: %s",
+                        __func__,
+                        (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8) + bd_addr[3],
+                        (bd_addr[4]<<8)+bd_addr[5],
+                        (connected) ? "connected" : "disconnected");
+
+        if (connected)
+        {
+            if(!p_cb->connect_initialized)
+            {
+                p_cb->connect_initialized = true;
+                /* initiating connection established */
+                p_cb->role = L2CA_GetBleConnRole(bd_addr);
+
+                /* initialize local i/r key to be default keys */
+                p_cb->local_r_key = p_cb->local_i_key =  SMP_SEC_DEFAULT_KEY;
+                p_cb->loc_auth_req = p_cb->peer_auth_req = SMP_DEFAULT_AUTH_REQ;
+                p_cb->cb_evt = SMP_IO_CAP_REQ_EVT;
+                smp_sm_event(p_cb, SMP_L2CAP_CONN_EVT, NULL);
+            }
+        }
+        else
+        {
+            int_data.reason = reason;
+            /* Disconnected while doing security */
+            smp_sm_event(p_cb, SMP_L2CAP_DISCONN_EVT, &int_data);
+        }
+    }
+}
+
+/*******************************************************************************
+**
+** Function         smp_data_received
+**
+** Description      This function is called when data is received from L2CAP on
+**                  SMP channel.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+static void smp_data_received(uint16_t channel, BD_ADDR bd_addr, BT_HDR *p_buf)
+{
+    tSMP_CB *p_cb = &smp_cb;
+    uint8_t *p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+    uint8_t cmd ;
+    SMP_TRACE_EVENT ("SMDBG l2c %s", __func__);
+
+    STREAM_TO_UINT8(cmd, p);
+
+    /* sanity check */
+    if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd))
+    {
+        SMP_TRACE_WARNING( "Ignore received command with RESERVED code 0x%02x", cmd);
+        osi_free(p_buf);
+        return;
+    }
+
+    /* reject the pairing request if there is an on-going SMP pairing */
+    if (SMP_OPCODE_PAIRING_REQ == cmd || SMP_OPCODE_SEC_REQ == cmd)
+    {
+        if ((p_cb->state == SMP_STATE_IDLE) && (p_cb->br_state == SMP_BR_STATE_IDLE) &&
+            !(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD))
+        {
+            p_cb->role = L2CA_GetBleConnRole(bd_addr);
+            memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN);
+        }
+        else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN))
+        {
+            osi_free(p_buf);
+            smp_reject_unexpected_pairing_command(bd_addr);
+            return;
+        }
+        /* else, out of state pairing request/security request received, passed into SM */
+    }
+
+    if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0)
+    {
+        alarm_set_on_queue(p_cb->smp_rsp_timer_ent,
+                           SMP_WAIT_FOR_RSP_TIMEOUT_MS, smp_rsp_timeout, NULL,
+                           btu_general_alarm_queue);
+
+        if (cmd == SMP_OPCODE_CONFIRM)
+        {
+            SMP_TRACE_DEBUG ("in %s cmd = 0x%02x, peer_auth_req = 0x%02x,"
+                              "loc_auth_req = 0x%02x",
+                              __func__, cmd, p_cb->peer_auth_req, p_cb->loc_auth_req);
+
+            if ((p_cb->peer_auth_req  & SMP_SC_SUPPORT_BIT) &&
+                (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT))
+            {
+                cmd = SMP_OPCODE_PAIR_COMMITM;
+            }
+        }
+
+        p_cb->rcvd_cmd_code = cmd;
+        p_cb->rcvd_cmd_len = (uint8_t) p_buf->len;
+        smp_sm_event(p_cb, cmd, p);
+    }
+
+    osi_free(p_buf);
+}
+
+/*******************************************************************************
+**
+** Function         smp_tx_complete_callback
+**
+** Description      SMP channel tx complete callback
+**
+*******************************************************************************/
+static void smp_tx_complete_callback (uint16_t cid, uint16_t num_pkt)
+{
+    tSMP_CB *p_cb = &smp_cb;
+
+    if (p_cb->total_tx_unacked >= num_pkt)
+        p_cb->total_tx_unacked -= num_pkt;
+    else
+        SMP_TRACE_ERROR("Unexpected %s: num_pkt = %d", __func__,num_pkt);
+
+    uint8_t reason = SMP_SUCCESS;
+    if (p_cb->total_tx_unacked == 0 && p_cb->wait_for_authorization_complete)
+    {
+        if (cid == L2CAP_SMP_CID)
+            smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+        else
+            smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         smp_br_connect_callback
+**
+** Description      This callback function is called by L2CAP to indicate that
+**                  SMP BR channel is
+**                      connected (conn = true)/disconnected (conn = false).
+**
+*******************************************************************************/
+static void smp_br_connect_callback(uint16_t channel, BD_ADDR bd_addr, bool    connected,
+                                    uint16_t reason, tBT_TRANSPORT transport)
+{
+    tSMP_CB *p_cb = &smp_cb;
+    tSMP_INT_DATA int_data;
+
+    SMP_TRACE_EVENT ("%s", __func__);
+
+    if (transport != BT_TRANSPORT_BR_EDR)
+    {
+        SMP_TRACE_WARNING("%s is called on unexpected transport %d",
+                           __func__, transport);
+        return;
+    }
+
+    if (!(memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0))
+        return;
+
+    SMP_TRACE_EVENT ("%s for pairing BDA: %08x%04x  Event: %s",
+                     __func__,
+                     (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8) + bd_addr[3],
+                     (bd_addr[4]<<8)+bd_addr[5],
+                     (connected) ? "connected" : "disconnected");
+
+    if (connected)
+    {
+        if(!p_cb->connect_initialized)
+        {
+            p_cb->connect_initialized = true;
+            /* initialize local i/r key to be default keys */
+            p_cb->local_r_key = p_cb->local_i_key =  SMP_BR_SEC_DEFAULT_KEY;
+            p_cb->loc_auth_req = p_cb->peer_auth_req = 0;
+            p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT;
+            smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_CONN_EVT, NULL);
+        }
+    }
+    else
+    {
+        int_data.reason = reason;
+        /* Disconnected while doing security */
+        smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_DISCONN_EVT, &int_data);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         smp_br_data_received
+**
+** Description      This function is called when data is received from L2CAP on
+**                  SMP BR channel.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void smp_br_data_received(uint16_t channel, BD_ADDR bd_addr, BT_HDR *p_buf)
+{
+    tSMP_CB *p_cb = &smp_cb;
+    uint8_t *p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+    uint8_t cmd ;
+    SMP_TRACE_EVENT ("SMDBG l2c %s", __func__);
+
+    STREAM_TO_UINT8(cmd, p);
+
+    /* sanity check */
+    if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd))
+    {
+        SMP_TRACE_WARNING( "Ignore received command with RESERVED code 0x%02x", cmd);
+        osi_free(p_buf);
+        return;
+    }
+
+    /* reject the pairing request if there is an on-going SMP pairing */
+    if (SMP_OPCODE_PAIRING_REQ == cmd)
+    {
+        if ((p_cb->state == SMP_STATE_IDLE) && (p_cb->br_state == SMP_BR_STATE_IDLE))
+        {
+            p_cb->role = HCI_ROLE_SLAVE;
+            p_cb->smp_over_br = true;
+            memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN);
+        }
+        else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN))
+        {
+            osi_free(p_buf);
+            smp_reject_unexpected_pairing_command(bd_addr);
+            return;
+        }
+        /* else, out of state pairing request received, passed into State Machine */
+    }
+
+    if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0)
+    {
+        alarm_set_on_queue(p_cb->smp_rsp_timer_ent,
+                           SMP_WAIT_FOR_RSP_TIMEOUT_MS, smp_rsp_timeout, NULL,
+                           btu_general_alarm_queue);
+
+        p_cb->rcvd_cmd_code = cmd;
+        p_cb->rcvd_cmd_len = (uint8_t) p_buf->len;
+        smp_br_state_machine_event(p_cb, cmd, p);
+    }
+
+    osi_free(p_buf);
+}
+#endif /* SMP_INCLUDED == TRUE */
diff --git a/bt/stack/smp/smp_main.cc b/bt/stack/smp/smp_main.cc
new file mode 100644
index 0000000..87c1f74
--- /dev/null
+++ b/bt/stack/smp/smp_main.cc
@@ -0,0 +1,861 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-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.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if (SMP_INCLUDED == TRUE)
+
+#include <string.h>
+#include "smp_int.h"
+
+const char *const smp_state_name [] =
+{
+    "SMP_STATE_IDLE",
+    "SMP_STATE_WAIT_APP_RSP",
+    "SMP_STATE_SEC_REQ_PENDING",
+    "SMP_STATE_PAIR_REQ_RSP",
+    "SMP_STATE_WAIT_CONFIRM",
+    "SMP_STATE_CONFIRM",
+    "SMP_STATE_RAND",
+    "SMP_STATE_PUBLIC_KEY_EXCH",
+    "SMP_STATE_SEC_CONN_PHS1_START",
+    "SMP_STATE_WAIT_COMMITMENT",
+    "SMP_STATE_WAIT_NONCE",
+    "SMP_STATE_SEC_CONN_PHS2_START",
+    "SMP_STATE_WAIT_DHK_CHECK",
+    "SMP_STATE_DHK_CHECK",
+    "SMP_STATE_ENCRYPTION_PENDING",
+    "SMP_STATE_BOND_PENDING",
+    "SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA",
+    "SMP_STATE_MAX"
+};
+
+const char *const smp_event_name [] =
+{
+    "PAIRING_REQ_EVT",
+    "PAIRING_RSP_EVT",
+    "CONFIRM_EVT",
+    "RAND_EVT",
+    "PAIRING_FAILED_EVT",
+    "ENC_INFO_EVT",
+    "MASTER_ID_EVT",
+    "ID_INFO_EVT",
+    "ID_ADDR_EVT",
+    "SIGN_INFO_EVT",
+    "SECURITY_REQ_EVT",
+    "PAIR_PUBLIC_KEY_EVT",
+    "PAIR_DHKEY_CHECK_EVT",
+    "PAIR_KEYPRESS_NOTIFICATION_EVT",
+    "PAIR_COMMITMENT_EVT",
+    "KEY_READY_EVT",
+    "ENCRYPTED_EVT",
+    "L2CAP_CONN_EVT",
+    "L2CAP_DISCONN_EVT",
+    "API_IO_RSP_EVT",
+    "API_SEC_GRANT_EVT",
+    "TK_REQ_EVT",
+    "AUTH_CMPL_EVT",
+    "ENC_REQ_EVT",
+    "BOND_REQ_EVT",
+    "DISCARD_SEC_REQ_EVT",
+    "PUBLIC_KEY_EXCHANGE_REQ_EVT",
+    "LOCAL_PUBLIC_KEY_CRTD_EVT",
+    "BOTH_PUBLIC_KEYS_RCVD_EVT",
+    "SEC_CONN_DHKEY_COMPLETE_EVT",
+    "HAVE_LOCAL_NONCE_EVT",
+    "SEC_CONN_PHASE1_CMPLT_EVT",
+    "SEC_CONN_CALC_NC_EVT",
+    "SEC_CONN_DISPLAY_NC_EVT",
+    "SEC_CONN_OK_EVT",
+    "SEC_CONN_2_DHCK_CHECKS_PRESENT_EVT",
+    "SEC_CONN_KEY_READY_EVT",
+    "KEYPRESS_NOTIFICATION_EVT",
+    "SEC_CONN_OOB_DATA_EVT",
+    "CREATE_LOCAL_SEC_CONN_OOB_DATA_EVT",
+    "OUT_OF_RANGE_EVT"
+};
+
+const char *smp_get_event_name(tSMP_EVENT event);
+const char *smp_get_state_name(tSMP_STATE state);
+
+#define SMP_SM_IGNORE       0
+#define SMP_NUM_ACTIONS     2
+#define SMP_SME_NEXT_STATE  2
+#define SMP_SM_NUM_COLS     3
+
+typedef const uint8_t (*tSMP_SM_TBL)[SMP_SM_NUM_COLS];
+
+enum
+{
+    SMP_PROC_SEC_REQ,
+    SMP_SEND_PAIR_REQ,
+    SMP_SEND_PAIR_RSP,
+    SMP_SEND_CONFIRM,
+    SMP_SEND_PAIR_FAIL,
+    SMP_SEND_RAND,
+    SMP_SEND_ENC_INFO,
+    SMP_SEND_ID_INFO,
+    SMP_SEND_LTK_REPLY,
+    SMP_PROC_PAIR_CMD,
+    SMP_PROC_PAIR_FAIL,
+    SMP_PROC_CONFIRM,
+    SMP_PROC_RAND,
+    SMP_PROC_ENC_INFO,
+    SMP_PROC_MASTER_ID,
+    SMP_PROC_ID_INFO,
+    SMP_PROC_ID_ADDR,
+    SMP_PROC_SRK_INFO,
+    SMP_PROC_SEC_GRANT,
+    SMP_PROC_SL_KEY,
+    SMP_PROC_COMPARE,
+    SMP_PROC_IO_RSP,
+    SMP_GENERATE_COMPARE,
+    SMP_GENERATE_CONFIRM,
+    SMP_GENERATE_STK,
+    SMP_KEY_DISTRIBUTE,
+    SMP_START_ENC,
+    SMP_PAIRING_CMPL,
+    SMP_DECIDE_ASSO_MODEL,
+    SMP_SEND_APP_CBACK,
+    SMP_CHECK_AUTH_REQ,
+    SMP_PAIR_TERMINATE,
+    SMP_ENC_CMPL,
+    SMP_PROC_DISCARD,
+    SMP_CREATE_PRIVATE_KEY,
+    SMP_USE_OOB_PRIVATE_KEY,
+    SMP_SEND_PAIR_PUBLIC_KEY,
+    SMP_PROCESS_PAIR_PUBLIC_KEY,
+    SMP_HAVE_BOTH_PUBLIC_KEYS,
+    SMP_START_SEC_CONN_PHASE1,
+    SMP_PROCESS_LOCAL_NONCE,
+    SMP_SEND_COMMITMENT,
+    SMP_PROCESS_PAIRING_COMMITMENT,
+    SMP_PROCESS_PEER_NONCE,
+    SMP_CALCULATE_LOCAL_DHKEY_CHECK,
+    SMP_SEND_DHKEY_CHECK,
+    SMP_PROCESS_DHKEY_CHECK,
+    SMP_CALCULATE_PEER_DHKEY_CHECK,
+    SMP_MATCH_DHKEY_CHECKS,
+    SMP_CALCULATE_NUMERIC_COMPARISON_DISPLAY_NUMBER,
+    SMP_MOVE_TO_SEC_CONN_PHASE2,
+    SMP_PH2_DHKEY_CHECKS_ARE_PRESENT,
+    SMP_WAIT_FOR_BOTH_PUBLIC_KEYS,
+    SMP_START_PASSKEY_VERIFICATION,
+    SMP_SEND_KEYPRESS_NOTIFICATION,
+    SMP_PROCESS_KEYPRESS_NOTIFICATION,
+    SMP_PROCESS_SECURE_CONNECTION_OOB_DATA,
+    SMP_SET_LOCAL_OOB_KEYS,
+    SMP_SET_LOCAL_OOB_RAND_COMMITMENT,
+    SMP_IDLE_TERMINATE,
+    SMP_FAST_CONN_PARAM,
+    SMP_SM_NO_ACTION
+};
+
+static const tSMP_ACT smp_sm_action[] =
+{
+    smp_proc_sec_req,
+    smp_send_pair_req,
+    smp_send_pair_rsp,
+    smp_send_confirm,
+    smp_send_pair_fail,
+    smp_send_rand,
+    smp_send_enc_info,
+    smp_send_id_info,
+    smp_send_ltk_reply,
+    smp_proc_pair_cmd,
+    smp_proc_pair_fail,
+    smp_proc_confirm,
+    smp_proc_rand,
+    smp_proc_enc_info,
+    smp_proc_master_id,
+    smp_proc_id_info,
+    smp_proc_id_addr,
+    smp_proc_srk_info,
+    smp_proc_sec_grant,
+    smp_proc_sl_key,
+    smp_proc_compare,
+    smp_process_io_response,
+    smp_generate_compare,
+    smp_generate_srand_mrand_confirm,
+    smp_generate_stk,
+    smp_key_distribution,
+    smp_start_enc,
+    smp_pairing_cmpl,
+    smp_decide_association_model,
+    smp_send_app_cback,
+    smp_check_auth_req,
+    smp_pair_terminate,
+    smp_enc_cmpl,
+    smp_proc_discard,
+    smp_create_private_key,
+    smp_use_oob_private_key,
+    smp_send_pair_public_key,
+    smp_process_pairing_public_key,
+    smp_both_have_public_keys,
+    smp_start_secure_connection_phase1,
+    smp_process_local_nonce,
+    smp_send_commitment,
+    smp_process_pairing_commitment,
+    smp_process_peer_nonce,
+    smp_calculate_local_dhkey_check,
+    smp_send_dhkey_check,
+    smp_process_dhkey_check,
+    smp_calculate_peer_dhkey_check,
+    smp_match_dhkey_checks,
+    smp_calculate_numeric_comparison_display_number,
+    smp_move_to_secure_connections_phase2,
+    smp_phase_2_dhkey_checks_are_present,
+    smp_wait_for_both_public_keys,
+    smp_start_passkey_verification,
+    smp_send_keypress_notification,
+    smp_process_keypress_notification,
+    smp_process_secure_connection_oob_data,
+    smp_set_local_oob_keys,
+    smp_set_local_oob_random_commitment,
+    smp_idle_terminate,
+    smp_fast_conn_param
+};
+
+/************ SMP Master FSM State/Event Indirection Table **************/
+static const uint8_t smp_master_entry_map[][SMP_STATE_MAX] =
+{
+/* state name:             Idle WaitApp SecReq Pair   Wait Confirm Rand PublKey SCPhs1  Wait  Wait  SCPhs2  Wait   DHKChk Enc   Bond  CrLocSc
+                                 Rsp    Pend   ReqRsp Cfm               Exch    Strt    Cmtm  Nonce Strt    DHKChk        Pend  Pend  OobData   */
+/* PAIR_REQ             */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* PAIR_RSP             */{ 0,    0,     0,      1,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* CONFIRM              */{ 0,    0,     0,      0,     0,   1,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* RAND                 */{ 0,    0,     0,      0,     0,   0,    1,   0,      0,      0,    1,    0,      0,     0,     0,    0,     0   },
+/* PAIR_FAIL            */{ 0,    0x81,  0,      0x81,  0x81,0x81, 0x81,0x81,   0x81,   0x81, 0x81, 0x81,   0x81,  0x81,  0,    0x81,  0   },
+/* ENC_INFO             */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    1,     0   },
+/* MASTER_ID            */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    4,     0   },
+/* ID_INFO              */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    2,     0   },
+/* ID_ADDR              */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    5,     0   },
+/* SIGN_INFO            */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    3,     0   },
+/* SEC_REQ              */{ 2,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* PAIR_PUBLIC_KEY      */{ 0,    0,     0,      0,     0,   0,    0,   2,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* PAIR_DHKEY_CHCK      */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      1,     0,     0,    0,     0   },
+/* PAIR_KEYPR_NOTIF     */{ 0,    8,     0,      0,     0,   0,    0,   0,      5,      2,    0,    0,      0,     0,     0,    0,     0   },
+/* PAIR_COMMITM         */{ 0,    0,     0,      0,     0,   0,    0,   0,      6,      1,    0,    0,      0,     0,     0,    0,     0   },
+/* KEY_READY            */{ 0,    3,     0,      3,     1,   0,    2,   0,      4,      0,    0,    0,      0,     0,     1,    6,     0   },
+/* ENC_CMPL             */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     2,    0,     0   },
+/* L2C_CONN             */{ 1,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* L2C_DISC             */{ 3,    0x83,  0,      0x83,  0x83,0x83, 0x83,0x83,   0x83,   0x83, 0x83, 0x83,   0x83,  0x83,  0x83, 0x83,  0   },
+/* IO_RSP               */{ 0,    2,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* SEC_GRANT            */{ 0,    1,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* TK_REQ               */{ 0,    0,     0,      2,     0,   0,    0,   0,      3,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* AUTH_CMPL            */{ 4,    0x82,  0,      0x82,  0x82,0x82, 0x82,0x82,   0x82,   0x82, 0x82, 0x82,   0x82,  0x82,  0x82, 0x82,  0   },
+/* ENC_REQ              */{ 0,    4,     0,      0,     0,   0,    3,   0,      0,      0,    0,    0,      0,     2,     0,    0,     0   },
+/* BOND_REQ             */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     3,    0,     0   },
+/* DISCARD_SEC_REQ      */{ 0,    5,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     3,    0,     0   },
+/* PUBL_KEY_EXCH_REQ    */{ 0,    0,     0,      4,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* LOC_PUBL_KEY_CRTD    */{ 0,    0,     0,      0,     0,   0,    0,   1,      0,      0,    0,    0,      0,     0,     0,    0,     1   },
+/* BOTH_PUBL_KEYS_RCVD  */{ 0,    0,     0,      0,     0,   0,    0,   3,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* SC_DHKEY_CMPLT       */{ 0,    0,     0,      0,     0,   0,    0,   0,      1,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* HAVE_LOC_NONCE       */{ 0,    0,     0,      0,     0,   0,    0,   0,      2,      0,    0,    0,      0,     0,     0,    0,     2   },
+/* SC_PHASE1_CMPLT      */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    1,      0,     0,     0,    0,     0   },
+/* SC_CALC_NC           */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    2,    0,      0,     0,     0,    0,     0   },
+/* SC_DSPL_NC           */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    3,    0,      0,     0,     0,    0,     0   },
+/* SC_NC_OK             */{ 0,    6,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* SC_2_DHCK_CHKS_PRES  */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* SC_KEY_READY         */{ 0,    7,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     1,     0,    0,     0   },
+/* KEYPR_NOTIF          */{ 0,    9,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* SC_OOB_DATA          */{ 0,    10,    0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* CR_LOC_SC_OOB_DATA   */{ 5,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+};
+
+static const uint8_t smp_all_table[][SMP_SM_NUM_COLS] =
+{
+/*                       Event                     Action                 Next State */
+/* PAIR_FAIL */          {SMP_PROC_PAIR_FAIL,      SMP_PAIRING_CMPL, SMP_STATE_IDLE},
+/* AUTH_CMPL */          {SMP_SEND_PAIR_FAIL,      SMP_PAIRING_CMPL, SMP_STATE_IDLE},
+/* L2C_DISC  */          {SMP_PAIR_TERMINATE,      SMP_SM_NO_ACTION, SMP_STATE_IDLE}
+};
+
+static const uint8_t smp_master_idle_table[][SMP_SM_NUM_COLS] =
+{
+/*                   Event                  Action               Next State */
+/* L2C_CONN */      {SMP_SEND_APP_CBACK,     SMP_SM_NO_ACTION,   SMP_STATE_WAIT_APP_RSP},
+/* SEC_REQ  */      {SMP_PROC_SEC_REQ,       SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP},
+/* L2C_DISC  */     {SMP_IDLE_TERMINATE,     SMP_SM_NO_ACTION, SMP_STATE_IDLE},
+/* AUTH_CMPL */     {SMP_PAIRING_CMPL,       SMP_SM_NO_ACTION, SMP_STATE_IDLE}
+/* CR_LOC_SC_OOB_DATA   */ ,{SMP_CREATE_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA}
+
+};
+
+static const uint8_t smp_master_wait_for_app_response_table[][SMP_SM_NUM_COLS] =
+{
+/*                            Event                Action               Next State */
+/* SEC_GRANT            */ {SMP_PROC_SEC_GRANT, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP},
+/* IO_RSP               */ {SMP_SEND_PAIR_REQ, SMP_FAST_CONN_PARAM, SMP_STATE_PAIR_REQ_RSP},
+
+                    /* TK ready */
+/* KEY_READY            */ {SMP_GENERATE_CONFIRM, SMP_SM_NO_ACTION,   SMP_STATE_WAIT_CONFIRM},
+
+                    /* start enc mode setup */
+/* ENC_REQ              */ { SMP_START_ENC, SMP_FAST_CONN_PARAM, SMP_STATE_ENCRYPTION_PENDING},
+/* DISCARD_SEC_REQ      */ { SMP_PROC_DISCARD, SMP_SM_NO_ACTION, SMP_STATE_IDLE}
+/* user confirms NC 'OK', i.e. phase 1 is completed */
+/* SC_NC_OK             */,{ SMP_MOVE_TO_SEC_CONN_PHASE2, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS2_START},
+/* user-provided passkey is rcvd */
+/* SC_KEY_READY  */ { SMP_START_PASSKEY_VERIFICATION, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START},
+/* PAIR_KEYPR_NOTIF */ { SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP},
+/* KEYPR_NOTIF          */ { SMP_SEND_KEYPRESS_NOTIFICATION, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+/* SC_OOB_DATA      */ { SMP_USE_OOB_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH}
+};
+
+static const uint8_t smp_master_pair_request_response_table[][SMP_SM_NUM_COLS] =
+{
+/*               Event                  Action                  Next State */
+/* PAIR_RSP */ { SMP_PROC_PAIR_CMD,     SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP},
+/* TK_REQ   */ { SMP_SEND_APP_CBACK,    SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+
+                    /* TK ready */
+/* KEY_READY */{ SMP_GENERATE_CONFIRM,  SMP_SM_NO_ACTION, SMP_STATE_WAIT_CONFIRM}
+/* PUBL_KEY_EXCH_REQ    */,{ SMP_CREATE_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH}
+};
+
+static const uint8_t smp_master_wait_for_confirm_table[][SMP_SM_NUM_COLS] =
+{
+/*              Event                   Action          Next State */
+/* KEY_READY*/ {SMP_SEND_CONFIRM,     SMP_SM_NO_ACTION, SMP_STATE_CONFIRM}/* CONFIRM ready */
+};
+
+static const uint8_t smp_master_confirm_table[][SMP_SM_NUM_COLS] =
+{
+/*               Event                  Action                 Next State */
+/* CONFIRM  */ { SMP_PROC_CONFIRM, SMP_SEND_RAND, SMP_STATE_RAND}
+};
+
+static const uint8_t smp_master_rand_table[][SMP_SM_NUM_COLS] =
+{
+/*               Event                  Action                   Next State */
+/* RAND     */ { SMP_PROC_RAND,         SMP_GENERATE_COMPARE, SMP_STATE_RAND},
+/* KEY_READY*/ { SMP_PROC_COMPARE,      SMP_SM_NO_ACTION,   SMP_STATE_RAND},  /* Compare ready */
+/* ENC_REQ  */ { SMP_GENERATE_STK,      SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}
+};
+
+static const uint8_t smp_master_public_key_exchange_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                        Action              Next State */
+/* LOC_PUBL_KEY_CRTD    */{ SMP_SEND_PAIR_PUBLIC_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH},
+/* PAIR_PUBLIC_KEY      */{ SMP_PROCESS_PAIR_PUBLIC_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH},
+/* BOTH_PUBL_KEYS_RCVD  */{ SMP_HAVE_BOTH_PUBLIC_KEYS, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START},
+};
+
+static const uint8_t smp_master_sec_conn_phs1_start_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                Next State */
+/* SC_DHKEY_CMPLT       */{ SMP_START_SEC_CONN_PHASE1, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START},
+/* HAVE_LOC_NONCE       */{ SMP_PROCESS_LOCAL_NONCE, SMP_SM_NO_ACTION, SMP_STATE_WAIT_COMMITMENT},
+/* TK_REQ               */{ SMP_SEND_APP_CBACK,    SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+/* SMP_MODEL_SEC_CONN_PASSKEY_DISP model, passkey is sent up to display,*/
+/* It's time to start commitment calculation */
+/* KEY_READY            */{ SMP_START_PASSKEY_VERIFICATION, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START},
+/* PAIR_KEYPR_NOTIF  */{ SMP_PROCESS_KEYPRESS_NOTIFICATION,  SMP_SEND_APP_CBACK, SMP_STATE_SEC_CONN_PHS1_START},
+/* PAIR_COMMITM  */{ SMP_PROCESS_PAIRING_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START},
+};
+
+static const uint8_t smp_master_wait_commitment_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+/* PAIR_COMMITM         */{ SMP_PROCESS_PAIRING_COMMITMENT, SMP_SEND_RAND, SMP_STATE_WAIT_NONCE},
+/* PAIR_KEYPR_NOTIF */{ SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_COMMITMENT},
+};
+
+static const uint8_t smp_master_wait_nonce_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+/* peer nonce is received */
+/* RAND                 */{SMP_PROC_RAND,  SMP_PROCESS_PEER_NONCE, SMP_STATE_SEC_CONN_PHS2_START},
+/* NC model, time to calculate number for NC */
+/* SC_CALC_NC           */{SMP_CALCULATE_NUMERIC_COMPARISON_DISPLAY_NUMBER, SMP_SM_NO_ACTION, SMP_STATE_WAIT_NONCE},
+/* NC model, time to display calculated number for NC to the user */
+/* SC_DSPL_NC           */{SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+};
+
+static const uint8_t smp_master_sec_conn_phs2_start_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+/* SC_PHASE1_CMPLT */{SMP_CALCULATE_LOCAL_DHKEY_CHECK, SMP_SEND_DHKEY_CHECK, SMP_STATE_WAIT_DHK_CHECK},
+};
+
+static const uint8_t smp_master_wait_dhk_check_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+/* PAIR_DHKEY_CHCK  */{SMP_PROCESS_DHKEY_CHECK, SMP_CALCULATE_PEER_DHKEY_CHECK, SMP_STATE_DHK_CHECK},
+};
+
+static const uint8_t smp_master_dhk_check_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+/* locally calculated peer dhkey check is ready -> compare it withs DHKey Check actually received from peer */
+/* SC_KEY_READY         */{SMP_MATCH_DHKEY_CHECKS, SMP_SM_NO_ACTION, SMP_STATE_DHK_CHECK},
+/* locally calculated peer dhkey check is ready -> calculate STK, go to sending */
+/* HCI LE Start Encryption command */
+/* ENC_REQ              */{SMP_GENERATE_STK, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
+};
+
+static const uint8_t smp_master_enc_pending_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+/* STK ready */
+/* KEY_READY */ { SMP_START_ENC,        SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
+/* ENCRYPTED */ { SMP_CHECK_AUTH_REQ,   SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
+/* BOND_REQ  */ { SMP_KEY_DISTRIBUTE,   SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}
+};
+static const uint8_t smp_master_bond_pending_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+/* ENC_INFO */ { SMP_PROC_ENC_INFO,     SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+/* ID_INFO  */ { SMP_PROC_ID_INFO,      SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+/* SIGN_INFO*/ { SMP_PROC_SRK_INFO,     SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+/* MASTER_ID*/ { SMP_PROC_MASTER_ID,    SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+/* ID_ADDR  */ { SMP_PROC_ID_ADDR,      SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+/* KEY_READY */{SMP_SEND_ENC_INFO,      SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING} /* LTK ready */
+};
+
+static const uint8_t smp_master_create_local_sec_conn_oob_data[][SMP_SM_NUM_COLS] =
+{
+/*                       Event                   Action            Next State */
+/* LOC_PUBL_KEY_CRTD */ {SMP_SET_LOCAL_OOB_KEYS,   SMP_SM_NO_ACTION, SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA},
+/* HAVE_LOC_NONCE    */ {SMP_SET_LOCAL_OOB_RAND_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_IDLE}
+};
+
+
+/************ SMP Slave FSM State/Event Indirection Table **************/
+static const uint8_t smp_slave_entry_map[][SMP_STATE_MAX] =
+{
+/* state name:             Idle WaitApp SecReq Pair   Wait Confirm Rand PublKey SCPhs1  Wait  Wait  SCPhs2  Wait   DHKChk Enc   Bond  CrLocSc
+                                 Rsp    Pend   ReqRsp Cfm               Exch    Strt    Cmtm  Nonce Strt    DHKChk        Pend  Pend  OobData   */
+/* PAIR_REQ             */{ 2,    0,     1,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* PAIR_RSP             */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* CONFIRM              */{ 0,    4,     0,      1,     1,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* RAND                 */{ 0,    0,     0,      0,     0,   1,    2,   0,      0,      0,    1,    0,      0,     0,     0,    0,     0   },
+/* PAIR_FAIL            */{ 0,    0x81,  0x81,   0x81,  0x81,0x81, 0x81,0x81,   0x81,   0x81, 0x81, 0x81,   0x81,  0x81,  0x81, 0,     0   },
+/* ENC_INFO             */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    3,     0   },
+/* MASTER_ID            */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    5,     0   },
+/* ID_INFO              */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    4,     0   },
+/* ID_ADDR              */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    6,     0   },
+/* SIGN_INFO            */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    2,     0   },
+/* SEC_REQ              */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* PAIR_PUBLIC_KEY      */{ 0,    0,     0,      5,     0,   0,    0,   2,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* PAIR_DHKEY_CHCK      */{ 0,    5,     0,      0,     0,   0,    0,   0,      0,      0,    0,    2,      1,     2,     0,    0,     0   },
+/* PAIR_KEYPR_NOTIF     */{ 0,    9,     0,      0,     0,   0,    0,   0,      5,      2,    0,    0,      0,     0,     0,    0,     0   },
+/* PAIR_COMMITM         */{ 0,    8,     0,      0,     0,   0,    0,   0,      6,      1,    0,    0,      0,     0,     0,    0,     0   },
+/* KEY_READY            */{ 0,    3,     0,      3,     2,   2,    1,   0,      4,      0,    0,    0,      0,     0,     2,    1,     0   },
+/* ENC_CMPL             */{ 0,    0,     2,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     3,    0,     0   },
+/* L2C_CONN             */{ 1,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* L2C_DISC             */{ 0,    0x83,  0x83,   0x83,  0x83,0x83, 0x83,0x83,   0x83,   0x83, 0x83, 0x83,   0x83,  0x83,  0x83, 0x83,  0   },
+/* IO_RSP               */{ 0,    1,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* SEC_GRANT            */{ 0,    2,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* TK_REQ               */{ 0,    0,     0,      2,     0,   0,    0,   0,      3,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* AUTH_CMPL            */{ 0,    0x82,  0x82,   0x82,  0x82,0x82, 0x82,0x82,   0x82,   0x82, 0x82, 0x82,   0x82,  0x82,  0x82, 0x82,  0   },
+/* ENC_REQ              */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     1,    0,     0   },
+/* BOND_REQ             */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     4,    0,     0   },
+/* DISCARD_SEC_REQ      */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* PUBL_KEY_EXCH_REQ    */{ 0,    0,     0,      4,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* LOC_PUBL_KEY_CRTD    */{ 0,    0,     0,      0,     0,   0,    0,   1,      0,      0,    0,    0,      0,     0,     0,    0,     1   },
+/* BOTH_PUBL_KEYS_RCVD  */{ 0,    0,     0,      0,     0,   0,    0,   3,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* SC_DHKEY_CMPLT       */{ 0,    0,     0,      0,     0,   0,    0,   0,      1,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* HAVE_LOC_NONCE       */{ 0,    0,     0,      0,     0,   0,    0,   0,      2,      0,    0,    0,      0,     0,     0,    0,     2   },
+/* SC_PHASE1_CMPLT      */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    1,      0,     0,     0,    0,     0   },
+/* SC_CALC_NC           */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    2,    0,      0,     0,     0,    0,     0   },
+/* SC_DSPL_NC           */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    3,    0,      0,     0,     0,    0,     0   },
+/* SC_NC_OK             */{ 0,    6,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* SC_2_DHCK_CHKS_PRES  */{ 0,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      2,     0,     0,    0,     0   },
+/* SC_KEY_READY         */{ 0,    7,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     1,     0,    0,     0   },
+/* KEYPR_NOTIF          */{ 0,    10,    0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* SC_OOB_DATA          */{ 0,    11,    0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+/* CR_LOC_SC_OOB_DATA   */{ 3,    0,     0,      0,     0,   0,    0,   0,      0,      0,    0,    0,      0,     0,     0,    0,     0   },
+};
+
+static const uint8_t smp_slave_idle_table[][SMP_SM_NUM_COLS] =
+{
+/*                   Event                 Action                Next State */
+/* L2C_CONN */      {SMP_SEND_APP_CBACK,  SMP_SM_NO_ACTION,      SMP_STATE_WAIT_APP_RSP},
+/* PAIR_REQ */      {SMP_PROC_PAIR_CMD,   SMP_SEND_APP_CBACK,     SMP_STATE_WAIT_APP_RSP}
+/* CR_LOC_SC_OOB_DATA   */ ,{SMP_CREATE_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA}
+};
+
+static const uint8_t smp_slave_wait_for_app_response_table [][SMP_SM_NUM_COLS] =
+{
+/*               Event                   Action                 Next State */
+/* IO_RSP    */ {SMP_PROC_IO_RSP,       SMP_FAST_CONN_PARAM, SMP_STATE_PAIR_REQ_RSP},
+/* SEC_GRANT */ {SMP_PROC_SEC_GRANT,    SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP},
+
+                        /* TK ready */
+/* KEY_READY */ {SMP_PROC_SL_KEY,   SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+/* CONFIRM   */ {SMP_PROC_CONFIRM,   SMP_SM_NO_ACTION, SMP_STATE_CONFIRM}
+/* DHKey Check from master is received before phase 1 is completed - race */
+/* PAIR_DHKEY_CHCK      */,{SMP_PROCESS_DHKEY_CHECK, SMP_SM_NO_ACTION,  SMP_STATE_WAIT_APP_RSP},
+/* user confirms NC 'OK', i.e. phase 1 is completed */
+/* SC_NC_OK             */ {SMP_MOVE_TO_SEC_CONN_PHASE2, SMP_SM_NO_ACTION,  SMP_STATE_SEC_CONN_PHS2_START},
+/* user-provided passkey is rcvd */
+/* SC_KEY_READY   */ {SMP_START_PASSKEY_VERIFICATION, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START},
+/* PAIR_COMMITM   */ {SMP_PROCESS_PAIRING_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+/* PAIR_KEYPR_NOTIF */ {SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP},
+/* KEYPR_NOTIF */ {SMP_SEND_KEYPRESS_NOTIFICATION, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+/* SC_OOB_DATA          */ {SMP_SEND_PAIR_RSP,    SMP_SM_NO_ACTION,    SMP_STATE_PAIR_REQ_RSP},
+};
+
+static const uint8_t smp_slave_sec_request_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+/* PAIR_REQ */{SMP_PROC_PAIR_CMD,       SMP_SM_NO_ACTION,       SMP_STATE_PAIR_REQ_RSP},
+/* ENCRYPTED*/{SMP_ENC_CMPL,            SMP_SM_NO_ACTION,       SMP_STATE_PAIR_REQ_RSP},
+};
+
+static const uint8_t smp_slave_pair_request_response_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+/* CONFIRM  */ {SMP_PROC_CONFIRM,       SMP_SM_NO_ACTION,   SMP_STATE_CONFIRM},
+/* TK_REQ   */ {SMP_SEND_APP_CBACK,     SMP_SM_NO_ACTION,   SMP_STATE_WAIT_APP_RSP},
+
+                    /* TK/Confirm ready */
+/* KEY_READY */{SMP_PROC_SL_KEY,        SMP_SM_NO_ACTION,   SMP_STATE_PAIR_REQ_RSP}
+/* PUBL_KEY_EXCH_REQ    */,{ SMP_CREATE_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH},
+/* PAIR_PUBLIC_KEY      */ { SMP_PROCESS_PAIR_PUBLIC_KEY, SMP_SM_NO_ACTION,   SMP_STATE_PAIR_REQ_RSP},
+};
+
+static const uint8_t smp_slave_wait_confirm_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+/* CONFIRM  */ {SMP_PROC_CONFIRM,       SMP_SEND_CONFIRM,   SMP_STATE_CONFIRM},
+/* KEY_READY*/ {SMP_PROC_SL_KEY,        SMP_SM_NO_ACTION,   SMP_STATE_WAIT_CONFIRM}
+};
+
+static const uint8_t smp_slave_confirm_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+/* RAND     */ {SMP_PROC_RAND,          SMP_GENERATE_COMPARE,   SMP_STATE_RAND},
+
+                    /* TK/Confirm ready */
+/* KEY_READY*/ {SMP_PROC_SL_KEY,        SMP_SM_NO_ACTION,       SMP_STATE_CONFIRM}
+};
+
+static const uint8_t smp_slave_rand_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+/* KEY_READY */ {SMP_PROC_COMPARE,      SMP_SM_NO_ACTION,   SMP_STATE_RAND}, /* compare match */
+/* RAND      */ {SMP_SEND_RAND,         SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}
+};
+
+static const uint8_t smp_slave_public_key_exch_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+/* LOC_PUBL_KEY_CRTD  */{ SMP_WAIT_FOR_BOTH_PUBLIC_KEYS, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH},
+/* PAIR_PUBLIC_KEY      */{ SMP_PROCESS_PAIR_PUBLIC_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH},
+/* BOTH_PUBL_KEYS_RCVD */{ SMP_HAVE_BOTH_PUBLIC_KEYS, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START},
+};
+
+static const uint8_t smp_slave_sec_conn_phs1_start_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+/* SC_DHKEY_CMPLT       */{ SMP_START_SEC_CONN_PHASE1, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START},
+/* HAVE_LOC_NONCE       */{ SMP_PROCESS_LOCAL_NONCE,SMP_SM_NO_ACTION, SMP_STATE_WAIT_COMMITMENT},
+/* TK_REQ               */{ SMP_SEND_APP_CBACK,      SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+/* SMP_MODEL_SEC_CONN_PASSKEY_DISP model, passkey is sent up to display, it's time to start */
+/* commitment calculation */
+/* KEY_READY */{ SMP_START_PASSKEY_VERIFICATION, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START},
+/* PAIR_KEYPR_NOTIF  */{ SMP_PROCESS_KEYPRESS_NOTIFICATION,SMP_SEND_APP_CBACK, SMP_STATE_SEC_CONN_PHS1_START},
+/*COMMIT*/{SMP_PROCESS_PAIRING_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START},
+};
+
+static const uint8_t smp_slave_wait_commitment_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+/* PAIR_COMMITM  */{SMP_PROCESS_PAIRING_COMMITMENT, SMP_SEND_COMMITMENT,  SMP_STATE_WAIT_NONCE},
+/* PAIR_KEYPR_NOTIF */{SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_COMMITMENT},
+};
+
+static const uint8_t smp_slave_wait_nonce_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+/* peer nonce is received */
+/* RAND           */{SMP_PROC_RAND, SMP_PROCESS_PEER_NONCE, SMP_STATE_SEC_CONN_PHS2_START},
+/* NC model, time to calculate number for NC */
+/* SC_CALC_NC  */{SMP_CALCULATE_NUMERIC_COMPARISON_DISPLAY_NUMBER, SMP_SM_NO_ACTION, SMP_STATE_WAIT_NONCE},
+/* NC model, time to display calculated number for NC to the user */
+/* SC_DSPL_NC   */{SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+};
+
+static const uint8_t smp_slave_sec_conn_phs2_start_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+/* SC_PHASE1_CMPLT */{SMP_CALCULATE_LOCAL_DHKEY_CHECK, SMP_PH2_DHKEY_CHECKS_ARE_PRESENT, SMP_STATE_WAIT_DHK_CHECK},
+/* DHKey Check from master is received before slave DHKey calculation is completed - race */
+/* PAIR_DHKEY_CHCK  */{SMP_PROCESS_DHKEY_CHECK, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS2_START},
+};
+
+static const uint8_t smp_slave_wait_dhk_check_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+/* PAIR_DHKEY_CHCK      */{SMP_PROCESS_DHKEY_CHECK, SMP_CALCULATE_PEER_DHKEY_CHECK, SMP_STATE_DHK_CHECK},
+/* DHKey Check from master was received before slave came to this state */
+/* SC_2_DHCK_CHKS_PRES  */{SMP_CALCULATE_PEER_DHKEY_CHECK, SMP_SM_NO_ACTION, SMP_STATE_DHK_CHECK},
+};
+
+static const uint8_t smp_slave_dhk_check_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+
+/* locally calculated peer dhkey check is ready -> compare it withs DHKey Check */
+/* actually received from peer */
+/* SC_KEY_READY         */{SMP_MATCH_DHKEY_CHECKS, SMP_SM_NO_ACTION, SMP_STATE_DHK_CHECK},
+
+/* dhkey checks match -> send local dhkey check to master, go to wait for HCI LE */
+/* Long Term Key Request Event */
+/* PAIR_DHKEY_CHCK      */{SMP_SEND_DHKEY_CHECK, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
+};
+
+static const uint8_t smp_slave_enc_pending_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+/* ENC_REQ   */ {SMP_GENERATE_STK,      SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
+
+                    /* STK ready */
+/* KEY_READY */ {SMP_SEND_LTK_REPLY,    SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
+/* ENCRYPTED */ {SMP_CHECK_AUTH_REQ,    SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
+/* BOND_REQ  */ {SMP_KEY_DISTRIBUTE,    SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}
+};
+static const uint8_t smp_slave_bond_pending_table[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+
+                /* LTK ready */
+/* KEY_READY */{ SMP_SEND_ENC_INFO,     SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+
+                /* rev SRK */
+/* SIGN_INFO */{ SMP_PROC_SRK_INFO,     SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+/* ENC_INFO */ { SMP_PROC_ENC_INFO,     SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+/* ID_INFO  */ { SMP_PROC_ID_INFO,      SMP_SM_NO_ACTION,  SMP_STATE_BOND_PENDING},
+/* MASTER_ID*/ { SMP_PROC_MASTER_ID,    SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+/* ID_ADDR  */ { SMP_PROC_ID_ADDR,      SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}
+
+};
+
+static const uint8_t smp_slave_create_local_sec_conn_oob_data[][SMP_SM_NUM_COLS] =
+{
+/*                          Event                  Action                 Next State */
+/* LOC_PUBL_KEY_CRTD */ {SMP_SET_LOCAL_OOB_KEYS, SMP_SM_NO_ACTION, SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA},
+/* HAVE_LOC_NONCE    */ {SMP_SET_LOCAL_OOB_RAND_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_IDLE}
+};
+
+static const tSMP_SM_TBL smp_state_table[][2] =
+{
+    /* SMP_STATE_IDLE */
+    {smp_master_idle_table, smp_slave_idle_table},
+
+    /* SMP_STATE_WAIT_APP_RSP */
+    {smp_master_wait_for_app_response_table, smp_slave_wait_for_app_response_table},
+
+    /* SMP_STATE_SEC_REQ_PENDING */
+    {NULL, smp_slave_sec_request_table},
+
+    /* SMP_STATE_PAIR_REQ_RSP */
+    {smp_master_pair_request_response_table, smp_slave_pair_request_response_table},
+
+    /* SMP_STATE_WAIT_CONFIRM */
+    {smp_master_wait_for_confirm_table, smp_slave_wait_confirm_table},
+
+    /* SMP_STATE_CONFIRM */
+    {smp_master_confirm_table, smp_slave_confirm_table},
+
+    /* SMP_STATE_RAND */
+    {smp_master_rand_table, smp_slave_rand_table},
+
+    /* SMP_STATE_PUBLIC_KEY_EXCH */
+    {smp_master_public_key_exchange_table,smp_slave_public_key_exch_table},
+
+    /* SMP_STATE_SEC_CONN_PHS1_START */
+    {smp_master_sec_conn_phs1_start_table, smp_slave_sec_conn_phs1_start_table},
+
+    /* SMP_STATE_WAIT_COMMITMENT */
+    {smp_master_wait_commitment_table, smp_slave_wait_commitment_table},
+
+    /* SMP_STATE_WAIT_NONCE */
+    {smp_master_wait_nonce_table, smp_slave_wait_nonce_table},
+
+     /* SMP_STATE_SEC_CONN_PHS2_START */
+    {smp_master_sec_conn_phs2_start_table, smp_slave_sec_conn_phs2_start_table},
+
+    /* SMP_STATE_WAIT_DHK_CHECK */
+    {smp_master_wait_dhk_check_table, smp_slave_wait_dhk_check_table},
+
+    /* SMP_STATE_DHK_CHECK */
+    {smp_master_dhk_check_table, smp_slave_dhk_check_table},
+
+    /* SMP_STATE_ENCRYPTION_PENDING */
+    {smp_master_enc_pending_table, smp_slave_enc_pending_table},
+
+     /* SMP_STATE_BOND_PENDING */
+    {smp_master_bond_pending_table, smp_slave_bond_pending_table},
+
+    /* SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA */
+    {smp_master_create_local_sec_conn_oob_data, smp_slave_create_local_sec_conn_oob_data}
+};
+
+typedef const uint8_t (*tSMP_ENTRY_TBL)[SMP_STATE_MAX];
+static const tSMP_ENTRY_TBL smp_entry_table[] =
+{
+    smp_master_entry_map,
+    smp_slave_entry_map
+};
+
+tSMP_CB smp_cb;
+
+#define SMP_ALL_TBL_MASK        0x80
+
+/*******************************************************************************
+** Function     smp_set_state
+** Returns      None
+*******************************************************************************/
+void smp_set_state(tSMP_STATE state)
+{
+    if (state < SMP_STATE_MAX)
+    {
+        SMP_TRACE_DEBUG( "State change: %s(%d) ==> %s(%d)",
+                          smp_get_state_name(smp_cb.state), smp_cb.state,
+                          smp_get_state_name(state), state );
+        smp_cb.state = state;
+    }
+    else
+    {
+        SMP_TRACE_DEBUG("smp_set_state invalid state =%d", state );
+    }
+}
+
+/*******************************************************************************
+** Function     smp_get_state
+** Returns      The smp state
+*******************************************************************************/
+tSMP_STATE smp_get_state(void)
+{
+    return smp_cb.state;
+}
+
+/*******************************************************************************
+**
+** Function     smp_sm_event
+**
+** Description  Handle events to the state machine. It looks up the entry
+**              in the smp_entry_table array.
+**              If it is a valid entry, it gets the state table.Set the next state,
+**              if not NULL state.Execute the action function according to the
+**              state table. If the state returned by action function is not NULL
+**              state, adjust the new state to the returned state.If (api_evt != MAX),
+**              call callback function.
+**
+** Returns      void.
+**
+*******************************************************************************/
+void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data)
+{
+    uint8_t         curr_state = p_cb->state;
+    tSMP_SM_TBL     state_table;
+    uint8_t         action, entry, i;
+    tSMP_ENTRY_TBL  entry_table =  smp_entry_table[p_cb->role];
+
+    SMP_TRACE_EVENT("main smp_sm_event");
+    if (curr_state >= SMP_STATE_MAX)
+    {
+        SMP_TRACE_DEBUG( "Invalid state: %d", curr_state) ;
+        return;
+    }
+
+    SMP_TRACE_DEBUG( "SMP Role: %s State: [%s (%d)], Event: [%s (%d)]",\
+                      (p_cb->role == 0x01) ?"Slave" : "Master", smp_get_state_name( p_cb->state),
+                      p_cb->state, smp_get_event_name(event), event) ;
+
+    /* look up the state table for the current state */
+    /* lookup entry /w event & curr_state */
+    /* If entry is ignore, return.
+     * Otherwise, get state table (according to curr_state or all_state) */
+    if ((event <= SMP_MAX_EVT) && ( (entry = entry_table[event - 1][curr_state]) != SMP_SM_IGNORE ))
+    {
+        if (entry & SMP_ALL_TBL_MASK)
+        {
+            entry &= ~SMP_ALL_TBL_MASK;
+            state_table = smp_all_table;
+        }
+        else
+            state_table = smp_state_table[curr_state][p_cb->role];
+    }
+    else
+    {
+        SMP_TRACE_DEBUG( "Ignore event [%s (%d)] in state [%s (%d)]",
+                          smp_get_event_name(event), event, smp_get_state_name(curr_state),
+                          curr_state);
+        return;
+    }
+
+    /* Get possible next state from state table. */
+
+    smp_set_state(state_table[entry-1][SMP_SME_NEXT_STATE]);
+
+    /* If action is not ignore, clear param, exec action and get next state.
+     * The action function may set the Param for cback.
+     * Depending on param, call cback or free buffer. */
+    /* execute action */
+    /* execute action functions */
+    for (i = 0; i < SMP_NUM_ACTIONS; i++)
+    {
+        if ((action = state_table[entry-1][i]) != SMP_SM_NO_ACTION)
+        {
+            (*smp_sm_action[action])(p_cb, (tSMP_INT_DATA *)p_data);
+        }
+        else
+        {
+            break;
+        }
+    }
+    SMP_TRACE_DEBUG( "result state = %s", smp_get_state_name( p_cb->state ) ) ;
+}
+
+/*******************************************************************************
+** Function     smp_get_state_name
+** Returns      The smp state name.
+*******************************************************************************/
+const char * smp_get_state_name(tSMP_STATE state)
+{
+    const char *p_str = smp_state_name[SMP_STATE_MAX];
+
+    if (state < SMP_STATE_MAX)
+    {
+        p_str = smp_state_name[state];
+    }
+    return p_str;
+}
+
+/*******************************************************************************
+** Function     smp_get_event_name
+** Returns      The smp event name.
+*******************************************************************************/
+const char * smp_get_event_name(tSMP_EVENT event)
+{
+    const char *p_str = smp_event_name[SMP_MAX_EVT];
+
+    if (event <= SMP_MAX_EVT)
+    {
+        p_str = smp_event_name[event- 1];
+    }
+    return p_str;
+}
+
+#endif
+
diff --git a/bt/stack/smp/smp_utils.cc b/bt/stack/smp/smp_utils.cc
new file mode 100644
index 0000000..3b2cc7e
--- /dev/null
+++ b/bt/stack/smp/smp_utils.cc
@@ -0,0 +1,1561 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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 functions for the SMP L2CAP utility functions
+ *
+ ******************************************************************************/
+#include "bt_target.h"
+
+#if (SMP_INCLUDED == TRUE)
+
+#include "bt_types.h"
+#include "bt_utils.h"
+#include <string.h>
+#include <ctype.h>
+#include "hcidefs.h"
+#include "btm_ble_api.h"
+#include "l2c_api.h"
+#include "l2c_int.h"
+#include "smp_int.h"
+#include "device/include/controller.h"
+#include "btm_int.h"
+#include "osi/include/osi.h"
+
+
+extern fixed_queue_t *btu_general_alarm_queue;
+
+#define SMP_PAIRING_REQ_SIZE    7
+#define SMP_CONFIRM_CMD_SIZE    (BT_OCTET16_LEN + 1)
+#define SMP_RAND_CMD_SIZE       (BT_OCTET16_LEN + 1)
+#define SMP_INIT_CMD_SIZE       (BT_OCTET16_LEN + 1)
+#define SMP_ENC_INFO_SIZE       (BT_OCTET16_LEN + 1)
+#define SMP_MASTER_ID_SIZE      (BT_OCTET8_LEN + 2 + 1)
+#define SMP_ID_INFO_SIZE        (BT_OCTET16_LEN + 1)
+#define SMP_ID_ADDR_SIZE        (BD_ADDR_LEN + 1 + 1)
+#define SMP_SIGN_INFO_SIZE      (BT_OCTET16_LEN + 1)
+#define SMP_PAIR_FAIL_SIZE      2
+#define SMP_SECURITY_REQUEST_SIZE  2
+#define SMP_PAIR_PUBL_KEY_SIZE  (1 /* opcode */ + (2*BT_OCTET32_LEN))
+#define SMP_PAIR_COMMITM_SIZE           (1 /* opcode */ + BT_OCTET16_LEN /*Commitment*/)
+#define SMP_PAIR_DHKEY_CHECK_SIZE       (1 /* opcode */ + BT_OCTET16_LEN /*DHKey Check*/)
+#define SMP_PAIR_KEYPR_NOTIF_SIZE       (1 /* opcode */ + 1 /*Notif Type*/)
+
+/* SMP command sizes per spec */
+static const uint8_t smp_cmd_size_per_spec[] =
+{
+    0,
+    SMP_PAIRING_REQ_SIZE,       /* 0x01: pairing request */
+    SMP_PAIRING_REQ_SIZE,       /* 0x02: pairing response */
+    SMP_CONFIRM_CMD_SIZE,       /* 0x03: pairing confirm */
+    SMP_RAND_CMD_SIZE,          /* 0x04: pairing random */
+    SMP_PAIR_FAIL_SIZE,         /* 0x05: pairing failed */
+    SMP_ENC_INFO_SIZE,          /* 0x06: encryption information */
+    SMP_MASTER_ID_SIZE,         /* 0x07: master identification */
+    SMP_ID_INFO_SIZE,           /* 0x08: identity information */
+    SMP_ID_ADDR_SIZE,           /* 0x09: identity address information */
+    SMP_SIGN_INFO_SIZE,         /* 0x0A: signing information */
+    SMP_SECURITY_REQUEST_SIZE,  /* 0x0B: security request */
+    SMP_PAIR_PUBL_KEY_SIZE,     /* 0x0C: pairing public key */
+    SMP_PAIR_DHKEY_CHECK_SIZE,  /* 0x0D: pairing dhkey check */
+    SMP_PAIR_KEYPR_NOTIF_SIZE,  /* 0x0E: pairing keypress notification */
+    SMP_PAIR_COMMITM_SIZE       /* 0x0F: pairing commitment */
+};
+
+static bool    smp_parameter_unconditionally_valid(tSMP_CB *p_cb);
+static bool    smp_parameter_unconditionally_invalid(tSMP_CB *p_cb);
+
+/* type for SMP command length validation functions */
+typedef bool    (*tSMP_CMD_LEN_VALID)(tSMP_CB *p_cb);
+
+static bool    smp_command_has_valid_fixed_length(tSMP_CB *p_cb);
+
+static const tSMP_CMD_LEN_VALID smp_cmd_len_is_valid[] =
+{
+    smp_parameter_unconditionally_invalid,
+    smp_command_has_valid_fixed_length, /* 0x01: pairing request */
+    smp_command_has_valid_fixed_length, /* 0x02: pairing response */
+    smp_command_has_valid_fixed_length, /* 0x03: pairing confirm */
+    smp_command_has_valid_fixed_length, /* 0x04: pairing random */
+    smp_command_has_valid_fixed_length, /* 0x05: pairing failed */
+    smp_command_has_valid_fixed_length, /* 0x06: encryption information */
+    smp_command_has_valid_fixed_length, /* 0x07: master identification */
+    smp_command_has_valid_fixed_length, /* 0x08: identity information */
+    smp_command_has_valid_fixed_length, /* 0x09: identity address information */
+    smp_command_has_valid_fixed_length, /* 0x0A: signing information */
+    smp_command_has_valid_fixed_length, /* 0x0B: security request */
+    smp_command_has_valid_fixed_length, /* 0x0C: pairing public key */
+    smp_command_has_valid_fixed_length, /* 0x0D: pairing dhkey check */
+    smp_command_has_valid_fixed_length, /* 0x0E: pairing keypress notification */
+    smp_command_has_valid_fixed_length  /* 0x0F: pairing commitment */
+};
+
+/* type for SMP command parameter ranges validation functions */
+typedef bool    (*tSMP_CMD_PARAM_RANGES_VALID)(tSMP_CB *p_cb);
+
+static bool    smp_pairing_request_response_parameters_are_valid(tSMP_CB *p_cb);
+static bool    smp_pairing_keypress_notification_is_valid(tSMP_CB *p_cb);
+
+static const tSMP_CMD_PARAM_RANGES_VALID smp_cmd_param_ranges_are_valid[] =
+{
+    smp_parameter_unconditionally_invalid,
+    smp_pairing_request_response_parameters_are_valid, /* 0x01: pairing request */
+    smp_pairing_request_response_parameters_are_valid, /* 0x02: pairing response */
+    smp_parameter_unconditionally_valid, /* 0x03: pairing confirm */
+    smp_parameter_unconditionally_valid, /* 0x04: pairing random */
+    smp_parameter_unconditionally_valid, /* 0x05: pairing failed */
+    smp_parameter_unconditionally_valid, /* 0x06: encryption information */
+    smp_parameter_unconditionally_valid, /* 0x07: master identification */
+    smp_parameter_unconditionally_valid, /* 0x08: identity information */
+    smp_parameter_unconditionally_valid, /* 0x09: identity address information */
+    smp_parameter_unconditionally_valid, /* 0x0A: signing information */
+    smp_parameter_unconditionally_valid, /* 0x0B: security request */
+    smp_parameter_unconditionally_valid, /* 0x0C: pairing public key */
+    smp_parameter_unconditionally_valid, /* 0x0D: pairing dhkey check */
+    smp_pairing_keypress_notification_is_valid, /* 0x0E: pairing keypress notification */
+    smp_parameter_unconditionally_valid /* 0x0F: pairing commitment */
+};
+
+/* type for action functions */
+typedef BT_HDR * (*tSMP_CMD_ACT)(uint8_t cmd_code, tSMP_CB *p_cb);
+
+static BT_HDR *smp_build_pairing_cmd(uint8_t cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_confirm_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_rand_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_pairing_fail(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_identity_info_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_encrypt_info_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_security_request(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_signing_info_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_master_id_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_id_addr_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_pair_public_key_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_pairing_commitment_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_pair_dhkey_check_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_pairing_keypress_notification_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb);
+
+static const tSMP_CMD_ACT smp_cmd_build_act[] =
+{
+    NULL,
+    smp_build_pairing_cmd,          /* 0x01: pairing request */
+    smp_build_pairing_cmd,          /* 0x02: pairing response */
+    smp_build_confirm_cmd,          /* 0x03: pairing confirm */
+    smp_build_rand_cmd,             /* 0x04: pairing random */
+    smp_build_pairing_fail,         /* 0x05: pairing failure */
+    smp_build_encrypt_info_cmd,     /* 0x06: encryption information */
+    smp_build_master_id_cmd,        /* 0x07: master identification */
+    smp_build_identity_info_cmd,    /* 0x08: identity information */
+    smp_build_id_addr_cmd,          /* 0x09: identity address information */
+    smp_build_signing_info_cmd,     /* 0x0A: signing information */
+    smp_build_security_request,     /* 0x0B: security request */
+    smp_build_pair_public_key_cmd,  /* 0x0C: pairing public key */
+    smp_build_pair_dhkey_check_cmd, /* 0x0D: pairing DHKey check */
+    smp_build_pairing_keypress_notification_cmd, /* 0x0E: pairing keypress notification */
+    smp_build_pairing_commitment_cmd /* 0x0F: pairing commitment */
+};
+
+static const uint8_t smp_association_table[2][SMP_IO_CAP_MAX][SMP_IO_CAP_MAX] =
+{
+    /* display only */    /* Display Yes/No */   /* keyboard only */
+                       /* No Input/Output */ /* keyboard display */
+
+     /* initiator */
+     /* model = tbl[peer_io_caps][loc_io_caps] */
+     /* Display Only */
+    {{SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY,
+                                 SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY},
+
+     /* Display Yes/No */
+     {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY,
+                                 SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY},
+
+     /* Keyboard only */
+     {SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY,
+                           SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF},
+
+     /* No Input No Output */
+     {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY,
+                                 SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY},
+
+     /* keyboard display */
+     {SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY,
+                           SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF}},
+
+     /* responder */
+     /* model = tbl[loc_io_caps][peer_io_caps] */
+     /* Display Only */
+    {{SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF,
+                                 SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF},
+
+      /* Display Yes/No */
+     {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF,
+                                 SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF},
+
+      /* keyboard only */
+     {SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY,
+                         SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY},
+
+      /* No Input No Output */
+     {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY,
+                                 SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY},
+
+      /* keyboard display */
+     {SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_KEY_NOTIF,
+                         SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY}}
+};
+
+static const uint8_t smp_association_table_sc[2][SMP_IO_CAP_MAX][SMP_IO_CAP_MAX] =
+{
+     /* display only */    /* Display Yes/No */   /* keyboard only */
+                                             /* No InputOutput */  /* keyboard display */
+
+     /* initiator */
+     /* model = tbl[peer_io_caps][loc_io_caps] */
+
+     /* Display Only */
+    {{SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_ENT,
+                                    SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_ENT},
+
+     /* Display Yes/No */
+     {SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP, SMP_MODEL_SEC_CONN_PASSKEY_ENT,
+                                    SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP},
+
+     /* keyboard only */
+     {SMP_MODEL_SEC_CONN_PASSKEY_DISP, SMP_MODEL_SEC_CONN_PASSKEY_DISP, SMP_MODEL_SEC_CONN_PASSKEY_ENT,
+                                       SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_DISP},
+
+     /* No Input No Output */
+     {SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS,
+                                    SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS},
+
+     /* keyboard display */
+     {SMP_MODEL_SEC_CONN_PASSKEY_DISP, SMP_MODEL_SEC_CONN_NUM_COMP, SMP_MODEL_SEC_CONN_PASSKEY_ENT,
+                                       SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP}},
+
+     /* responder */
+     /* model = tbl[loc_io_caps][peer_io_caps] */
+
+     /* Display Only */
+    {{SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_DISP,
+                                    SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_DISP},
+
+     /* Display Yes/No */
+     {SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP, SMP_MODEL_SEC_CONN_PASSKEY_DISP,
+                                    SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP},
+
+     /* keyboard only */
+     {SMP_MODEL_SEC_CONN_PASSKEY_ENT, SMP_MODEL_SEC_CONN_PASSKEY_ENT, SMP_MODEL_SEC_CONN_PASSKEY_ENT,
+                                      SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_ENT},
+
+     /* No Input No Output */
+     {SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS,
+                                    SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS},
+
+     /* keyboard display */
+     {SMP_MODEL_SEC_CONN_PASSKEY_ENT, SMP_MODEL_SEC_CONN_NUM_COMP, SMP_MODEL_SEC_CONN_PASSKEY_DISP,
+                       SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP}}
+};
+
+static tSMP_ASSO_MODEL smp_select_legacy_association_model(tSMP_CB *p_cb);
+static tSMP_ASSO_MODEL smp_select_association_model_secure_connections(tSMP_CB *p_cb);
+
+/*******************************************************************************
+**
+** Function         smp_send_msg_to_L2CAP
+**
+** Description      Send message to L2CAP.
+**
+*******************************************************************************/
+bool     smp_send_msg_to_L2CAP(BD_ADDR rem_bda, BT_HDR *p_toL2CAP)
+{
+    uint16_t l2cap_ret;
+    uint16_t fixed_cid = L2CAP_SMP_CID;
+
+    if (smp_cb.smp_over_br)
+    {
+        fixed_cid = L2CAP_SMP_BR_CID;
+    }
+
+    SMP_TRACE_EVENT("%s", __func__);
+    smp_cb.total_tx_unacked += 1;
+
+    if ((l2cap_ret = L2CA_SendFixedChnlData (fixed_cid, rem_bda, p_toL2CAP)) == L2CAP_DW_FAILED)
+    {
+        smp_cb.total_tx_unacked -= 1;
+        SMP_TRACE_ERROR("SMP   failed to pass msg:0x%0x to L2CAP",
+                         *((uint8_t *)(p_toL2CAP + 1) + p_toL2CAP->offset));
+        return false;
+    }
+    else
+        return true;
+}
+
+/*******************************************************************************
+**
+** Function         smp_send_cmd
+**
+** Description      send a SMP command on L2CAP channel.
+**
+*******************************************************************************/
+bool    smp_send_cmd(uint8_t cmd_code, tSMP_CB *p_cb)
+{
+    BT_HDR *p_buf;
+    bool    sent = false;
+    uint8_t failure = SMP_PAIR_INTERNAL_ERR;
+    SMP_TRACE_EVENT("smp_send_cmd on l2cap cmd_code=0x%x", cmd_code);
+    if ( cmd_code <= (SMP_OPCODE_MAX + 1 /* for SMP_OPCODE_PAIR_COMMITM */) &&
+         smp_cmd_build_act[cmd_code] != NULL)
+    {
+        p_buf = (*smp_cmd_build_act[cmd_code])(cmd_code, p_cb);
+
+        if (p_buf != NULL &&
+            smp_send_msg_to_L2CAP(p_cb->pairing_bda, p_buf))
+        {
+            sent = true;
+            alarm_set_on_queue(p_cb->smp_rsp_timer_ent,
+                               SMP_WAIT_FOR_RSP_TIMEOUT_MS, smp_rsp_timeout,
+                               NULL, btu_general_alarm_queue);
+        }
+    }
+
+    if (!sent)
+    {
+        if (p_cb->smp_over_br)
+        {
+            smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &failure);
+        }
+        else
+        {
+            smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+        }
+    }
+    return sent;
+}
+
+/*******************************************************************************
+**
+** Function         smp_rsp_timeout
+**
+** Description      Called when SMP wait for SMP command response timer expires
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_rsp_timeout(UNUSED_ATTR void *data)
+{
+    tSMP_CB   *p_cb = &smp_cb;
+    uint8_t failure = SMP_RSP_TIMEOUT;
+
+    SMP_TRACE_EVENT("%s state:%d br_state:%d", __func__, p_cb->state, p_cb->br_state);
+
+    if (p_cb->smp_over_br)
+    {
+        smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &failure);
+    }
+    else
+    {
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         smp_delayed_auth_complete_timeout
+**
+** Description      Called when no pairing failed command received within timeout
+**                  period.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_delayed_auth_complete_timeout(UNUSED_ATTR void *data)
+{
+    /*
+     * Waited for potential pair failure. Send SMP_AUTH_CMPL_EVT if
+     * the state is still in bond pending.
+     */
+    if (smp_get_state() == SMP_STATE_BOND_PENDING)
+    {
+        uint8_t reason = SMP_SUCCESS;
+        SMP_TRACE_EVENT("%s sending delayed auth complete.", __func__);
+        smp_sm_event(&smp_cb, SMP_AUTH_CMPL_EVT, &reason);
+    }
+}
+
+/*******************************************************************************
+**
+** Function         smp_build_pairing_req_cmd
+**
+** Description      Build pairing request command.
+**
+*******************************************************************************/
+BT_HDR * smp_build_pairing_cmd(uint8_t cmd_code, tSMP_CB *p_cb)
+{
+    uint8_t *p;
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) +
+                        SMP_PAIRING_REQ_SIZE + L2CAP_MIN_OFFSET);
+
+    SMP_TRACE_EVENT("%s", __func__);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+    UINT8_TO_STREAM(p, cmd_code);
+    UINT8_TO_STREAM(p, p_cb->local_io_capability);
+    UINT8_TO_STREAM(p, p_cb->loc_oob_flag);
+    UINT8_TO_STREAM(p, p_cb->loc_auth_req);
+    UINT8_TO_STREAM(p, p_cb->loc_enc_size);
+    UINT8_TO_STREAM(p, p_cb->local_i_key);
+    UINT8_TO_STREAM(p, p_cb->local_r_key);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    /* 1B ERR_RSP op code + 1B cmd_op_code + 2B handle + 1B status */
+    p_buf->len = SMP_PAIRING_REQ_SIZE;
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function         smp_build_confirm_cmd
+**
+** Description      Build confirm request command.
+**
+*******************************************************************************/
+static BT_HDR * smp_build_confirm_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb)
+{
+    uint8_t *p;
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) +
+                        SMP_CONFIRM_CMD_SIZE + L2CAP_MIN_OFFSET);
+
+    SMP_TRACE_EVENT("%s", __func__);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+    UINT8_TO_STREAM(p, SMP_OPCODE_CONFIRM);
+    ARRAY_TO_STREAM(p, p_cb->confirm, BT_OCTET16_LEN);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_buf->len = SMP_CONFIRM_CMD_SIZE;
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function         smp_build_rand_cmd
+**
+** Description      Build Random command.
+**
+*******************************************************************************/
+static BT_HDR * smp_build_rand_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb)
+{
+    uint8_t *p;
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) +
+                        SMP_RAND_CMD_SIZE + L2CAP_MIN_OFFSET);
+
+    SMP_TRACE_EVENT("%s", __func__);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+    UINT8_TO_STREAM(p, SMP_OPCODE_RAND);
+    ARRAY_TO_STREAM(p, p_cb->rand, BT_OCTET16_LEN);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_buf->len = SMP_RAND_CMD_SIZE;
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function         smp_build_encrypt_info_cmd
+**
+** Description      Build security information command.
+**
+*******************************************************************************/
+static BT_HDR * smp_build_encrypt_info_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb)
+{
+    uint8_t *p;
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) +
+                        SMP_ENC_INFO_SIZE + L2CAP_MIN_OFFSET);
+
+    SMP_TRACE_EVENT("%s", __func__);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+    UINT8_TO_STREAM(p, SMP_OPCODE_ENCRYPT_INFO);
+    ARRAY_TO_STREAM(p, p_cb->ltk, BT_OCTET16_LEN);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_buf->len = SMP_ENC_INFO_SIZE;
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function         smp_build_master_id_cmd
+**
+** Description      Build security information command.
+**
+*******************************************************************************/
+static BT_HDR * smp_build_master_id_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb)
+{
+    uint8_t *p;
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) +
+                        SMP_MASTER_ID_SIZE + L2CAP_MIN_OFFSET);
+
+    SMP_TRACE_EVENT("%s", __func__);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+    UINT8_TO_STREAM(p, SMP_OPCODE_MASTER_ID);
+    UINT16_TO_STREAM(p, p_cb->ediv);
+    ARRAY_TO_STREAM(p, p_cb->enc_rand, BT_OCTET8_LEN);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_buf->len = SMP_MASTER_ID_SIZE;
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function         smp_build_identity_info_cmd
+**
+** Description      Build identity information command.
+**
+*******************************************************************************/
+static BT_HDR * smp_build_identity_info_cmd(UNUSED_ATTR uint8_t cmd_code,
+                                            UNUSED_ATTR tSMP_CB *p_cb)
+{
+    uint8_t *p;
+    BT_OCTET16 irk;
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) +
+                        SMP_ID_INFO_SIZE + L2CAP_MIN_OFFSET);
+
+    SMP_TRACE_EVENT("%s", __func__);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+    BTM_GetDeviceIDRoot(irk);
+
+    UINT8_TO_STREAM(p, SMP_OPCODE_IDENTITY_INFO);
+    ARRAY_TO_STREAM(p,  irk, BT_OCTET16_LEN);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_buf->len = SMP_ID_INFO_SIZE;
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function         smp_build_id_addr_cmd
+**
+** Description      Build identity address information command.
+**
+*******************************************************************************/
+static BT_HDR * smp_build_id_addr_cmd(UNUSED_ATTR uint8_t cmd_code,
+                                      UNUSED_ATTR tSMP_CB *p_cb)
+{
+    uint8_t *p;
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) +
+                        SMP_ID_ADDR_SIZE + L2CAP_MIN_OFFSET);
+
+    SMP_TRACE_EVENT("%s", __func__);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+    UINT8_TO_STREAM(p, SMP_OPCODE_ID_ADDR);
+    UINT8_TO_STREAM(p, 0);
+    BDADDR_TO_STREAM(p, controller_get_interface()->get_address()->address);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_buf->len = SMP_ID_ADDR_SIZE;
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function         smp_build_signing_info_cmd
+**
+** Description      Build signing information command.
+**
+*******************************************************************************/
+static BT_HDR * smp_build_signing_info_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb)
+{
+    uint8_t *p;
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) +
+                        SMP_SIGN_INFO_SIZE + L2CAP_MIN_OFFSET);
+
+    SMP_TRACE_EVENT("%s", __func__);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+    UINT8_TO_STREAM(p, SMP_OPCODE_SIGN_INFO);
+    ARRAY_TO_STREAM(p, p_cb->csrk, BT_OCTET16_LEN);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_buf->len = SMP_SIGN_INFO_SIZE;
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function         smp_build_pairing_fail
+**
+** Description      Build Pairing Fail command.
+**
+*******************************************************************************/
+static BT_HDR * smp_build_pairing_fail(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb)
+{
+    uint8_t *p;
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) +
+                        SMP_PAIR_FAIL_SIZE + L2CAP_MIN_OFFSET);
+
+    SMP_TRACE_EVENT("%s", __func__);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+    UINT8_TO_STREAM(p, SMP_OPCODE_PAIRING_FAILED);
+    UINT8_TO_STREAM(p, p_cb->failure);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_buf->len = SMP_PAIR_FAIL_SIZE;
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function         smp_build_security_request
+**
+** Description      Build security request command.
+**
+*******************************************************************************/
+static BT_HDR *smp_build_security_request(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb)
+{
+    uint8_t *p;
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) +
+                        2 + L2CAP_MIN_OFFSET);
+
+    SMP_TRACE_EVENT("%s", __func__);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+    UINT8_TO_STREAM(p, SMP_OPCODE_SEC_REQ);
+    UINT8_TO_STREAM(p, p_cb->loc_auth_req);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_buf->len = SMP_SECURITY_REQUEST_SIZE;
+
+    SMP_TRACE_EVENT("opcode=%d auth_req=0x%x",SMP_OPCODE_SEC_REQ,  p_cb->loc_auth_req );
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function         smp_build_pair_public_key_cmd
+**
+** Description      Build pairing public key command.
+**
+*******************************************************************************/
+static BT_HDR *smp_build_pair_public_key_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb)
+{
+    uint8_t *p;
+    uint8_t publ_key[2*BT_OCTET32_LEN];
+    uint8_t *p_publ_key = publ_key;
+    BT_HDR  *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) +
+                        SMP_PAIR_PUBL_KEY_SIZE + L2CAP_MIN_OFFSET);
+
+    SMP_TRACE_EVENT("%s", __func__);
+
+    memcpy(p_publ_key, p_cb->loc_publ_key.x, BT_OCTET32_LEN);
+    memcpy(p_publ_key + BT_OCTET32_LEN, p_cb->loc_publ_key.y, BT_OCTET32_LEN);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+    UINT8_TO_STREAM(p, SMP_OPCODE_PAIR_PUBLIC_KEY);
+    ARRAY_TO_STREAM(p, p_publ_key, 2*BT_OCTET32_LEN);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_buf->len = SMP_PAIR_PUBL_KEY_SIZE;
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function         smp_build_pairing_commitment_cmd
+**
+** Description      Build pairing commitment command.
+**
+*******************************************************************************/
+static BT_HDR *smp_build_pairing_commitment_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb)
+{
+    uint8_t *p;
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) +
+                        SMP_PAIR_COMMITM_SIZE + L2CAP_MIN_OFFSET);
+
+    SMP_TRACE_EVENT("%s", __func__);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+    UINT8_TO_STREAM(p, SMP_OPCODE_CONFIRM);
+    ARRAY_TO_STREAM(p, p_cb->commitment, BT_OCTET16_LEN);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_buf->len = SMP_PAIR_COMMITM_SIZE;
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function         smp_build_pair_dhkey_check_cmd
+**
+** Description      Build pairing DHKey check command.
+**
+*******************************************************************************/
+static BT_HDR *smp_build_pair_dhkey_check_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb)
+{
+    uint8_t *p;
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) +
+                        SMP_PAIR_DHKEY_CHECK_SIZE + L2CAP_MIN_OFFSET);
+
+    SMP_TRACE_EVENT("%s", __func__);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+    UINT8_TO_STREAM(p, SMP_OPCODE_PAIR_DHKEY_CHECK);
+    ARRAY_TO_STREAM(p, p_cb->dhkey_check, BT_OCTET16_LEN);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_buf->len = SMP_PAIR_DHKEY_CHECK_SIZE;
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function         smp_build_pairing_keypress_notification_cmd
+**
+** Description      Build keypress notification command.
+**
+*******************************************************************************/
+static BT_HDR * smp_build_pairing_keypress_notification_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB *p_cb)
+{
+    uint8_t     *p;
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) +
+                        SMP_PAIR_KEYPR_NOTIF_SIZE + L2CAP_MIN_OFFSET);
+
+    SMP_TRACE_EVENT("%s", __func__);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+    UINT8_TO_STREAM(p, SMP_OPCODE_PAIR_KEYPR_NOTIF);
+    UINT8_TO_STREAM(p, p_cb->local_keypress_notification);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_buf->len = SMP_PAIR_KEYPR_NOTIF_SIZE;
+
+    return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function         smp_convert_string_to_tk
+**
+** Description      This function is called to convert a 6 to 16 digits numeric
+**                  character string into SMP TK.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_convert_string_to_tk(BT_OCTET16 tk, uint32_t passkey)
+{
+    uint8_t *p = tk;
+    tSMP_KEY    key;
+    SMP_TRACE_EVENT("smp_convert_string_to_tk");
+    UINT32_TO_STREAM(p, passkey);
+
+    key.key_type    = SMP_KEY_TYPE_TK;
+    key.p_data      = tk;
+
+    smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &key);
+}
+
+/*******************************************************************************
+**
+** Function         smp_mask_enc_key
+**
+** Description      This function is called to mask off the encryption key based
+**                  on the maximum encryption key size.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_mask_enc_key(uint8_t loc_enc_size, uint8_t * p_data)
+{
+    SMP_TRACE_EVENT("smp_mask_enc_key");
+    if (loc_enc_size < BT_OCTET16_LEN)
+    {
+        for (; loc_enc_size < BT_OCTET16_LEN; loc_enc_size ++)
+            * (p_data + loc_enc_size) = 0;
+    }
+    return;
+}
+
+/*******************************************************************************
+**
+** Function         smp_xor_128
+**
+** Description      utility function to do an biteise exclusive-OR of two bit
+**                  strings of the length of BT_OCTET16_LEN.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_xor_128(BT_OCTET16 a, BT_OCTET16 b)
+{
+    uint8_t i, *aa = a, *bb = b;
+
+    SMP_TRACE_EVENT("smp_xor_128");
+    for (i = 0; i < BT_OCTET16_LEN; i++)
+    {
+        aa[i] = aa[i] ^ bb[i];
+    }
+}
+
+/*******************************************************************************
+**
+** Function         smp_cb_cleanup
+**
+** Description      Clean up SMP control block
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_cb_cleanup(tSMP_CB   *p_cb)
+{
+    tSMP_CALLBACK   *p_callback = p_cb->p_callback;
+    uint8_t         trace_level = p_cb->trace_level;
+
+    SMP_TRACE_EVENT("smp_cb_cleanup");
+
+    alarm_free(p_cb->smp_rsp_timer_ent);
+    alarm_free(p_cb->delayed_auth_timer_ent);
+    memset(p_cb, 0, sizeof(tSMP_CB));
+    p_cb->p_callback = p_callback;
+    p_cb->trace_level = trace_level;
+    p_cb->smp_rsp_timer_ent = alarm_new("smp.smp_rsp_timer_ent");
+    p_cb->delayed_auth_timer_ent = alarm_new("smp.delayed_auth_timer_ent");
+}
+
+/*******************************************************************************
+**
+** Function         smp_remove_fixed_channel
+**
+** Description      This function is called to remove the fixed channel
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_remove_fixed_channel(tSMP_CB *p_cb)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    if (p_cb->smp_over_br)
+        L2CA_RemoveFixedChnl (L2CAP_SMP_BR_CID, p_cb->pairing_bda);
+    else
+        L2CA_RemoveFixedChnl (L2CAP_SMP_CID, p_cb->pairing_bda);
+}
+
+/*******************************************************************************
+**
+** Function         smp_reset_control_value
+**
+** Description      This function is called to reset the control block value when
+**                  pairing procedure finished.
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_reset_control_value(tSMP_CB *p_cb)
+{
+    SMP_TRACE_EVENT("%s", __func__);
+
+    alarm_cancel(p_cb->smp_rsp_timer_ent);
+    p_cb->flags = 0;
+    /* set the link idle timer to drop the link when pairing is done
+       usually service discovery will follow authentication complete, to avoid
+       racing condition for a link down/up, set link idle timer to be
+       SMP_LINK_TOUT_MIN to guarantee SMP key exchange */
+    L2CA_SetIdleTimeoutByBdAddr(p_cb->pairing_bda, SMP_LINK_TOUT_MIN, BT_TRANSPORT_LE);
+
+    /* We can tell L2CAP to remove the fixed channel (if it has one) */
+    smp_remove_fixed_channel(p_cb);
+    smp_cb_cleanup(p_cb);
+}
+
+/*******************************************************************************
+**
+** Function         smp_proc_pairing_cmpl
+**
+** Description      This function is called to process pairing complete
+**
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_proc_pairing_cmpl(tSMP_CB *p_cb)
+{
+    tSMP_EVT_DATA   evt_data = {0};
+    tSMP_CALLBACK   *p_callback = p_cb->p_callback;
+    BD_ADDR         pairing_bda;
+
+    SMP_TRACE_DEBUG ("smp_proc_pairing_cmpl ");
+
+    evt_data.cmplt.reason = p_cb->status;
+    evt_data.cmplt.smp_over_br = p_cb->smp_over_br;
+
+    if (p_cb->status == SMP_SUCCESS)
+        evt_data.cmplt.sec_level = p_cb->sec_level;
+
+    evt_data.cmplt.is_pair_cancel  = false;
+
+    if (p_cb->is_pair_cancel)
+        evt_data.cmplt.is_pair_cancel = true;
+
+
+    SMP_TRACE_DEBUG ("send SMP_COMPLT_EVT reason=0x%0x sec_level=0x%0x",
+                      evt_data.cmplt.reason,
+                      evt_data.cmplt.sec_level );
+
+    memcpy (pairing_bda, p_cb->pairing_bda, BD_ADDR_LEN);
+
+    smp_reset_control_value(p_cb);
+
+    if (p_callback)
+        (*p_callback) (SMP_COMPLT_EVT, pairing_bda, &evt_data);
+}
+
+/*******************************************************************************
+**
+** Function         smp_command_has_invalid_parameters
+**
+** Description      Checks if the received SMP command has invalid parameters i.e.
+**                  if the command length is valid and the command parameters are
+**                  inside specified range.
+**                  It returns true if the command has invalid parameters.
+**
+** Returns          true if the command has invalid parameters, false otherwise.
+**
+*******************************************************************************/
+bool    smp_command_has_invalid_parameters(tSMP_CB *p_cb)
+{
+    uint8_t cmd_code = p_cb->rcvd_cmd_code;
+
+    SMP_TRACE_DEBUG("%s for cmd code 0x%02x", __func__, cmd_code);
+
+    if ((cmd_code > (SMP_OPCODE_MAX + 1 /* for SMP_OPCODE_PAIR_COMMITM */)) ||
+        (cmd_code < SMP_OPCODE_MIN))
+    {
+        SMP_TRACE_WARNING("Somehow received command with the RESERVED code 0x%02x", cmd_code);
+        return true;
+    }
+
+    if (!(*smp_cmd_len_is_valid[cmd_code])(p_cb))
+        return true;
+
+    if (!(*smp_cmd_param_ranges_are_valid[cmd_code])(p_cb))
+        return true;
+
+    return false;
+}
+
+/*******************************************************************************
+**
+** Function         smp_command_has_valid_fixed_length
+**
+** Description      Checks if the received command size is equal to the size
+**                  according to specs.
+**
+** Returns          true if the command size is as expected, false otherwise.
+**
+** Note             The command is expected to have fixed length.
+*******************************************************************************/
+bool    smp_command_has_valid_fixed_length(tSMP_CB *p_cb)
+{
+    uint8_t cmd_code = p_cb->rcvd_cmd_code;
+
+    SMP_TRACE_DEBUG("%s for cmd code 0x%02x", __func__, cmd_code);
+
+    if (p_cb->rcvd_cmd_len != smp_cmd_size_per_spec[cmd_code])
+    {
+        SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with invalid length\
+            0x%02x (per spec the length is 0x%02x).",
+            cmd_code, p_cb->rcvd_cmd_len, smp_cmd_size_per_spec[cmd_code]);
+        return false;
+    }
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         smp_pairing_request_response_parameters_are_valid
+**
+** Description      Validates parameter ranges in the received SMP command
+**                  pairing request or pairing response.
+**                  The parameters to validate:
+**                  IO capability,
+**                  OOB data flag,
+**                  Bonding_flags in AuthReq
+**                  Maximum encryption key size.
+**                  Returns false if at least one of these parameters is out of range.
+**
+*******************************************************************************/
+bool    smp_pairing_request_response_parameters_are_valid(tSMP_CB *p_cb)
+{
+    uint8_t io_caps = p_cb->peer_io_caps;
+    uint8_t oob_flag = p_cb->peer_oob_flag;
+    uint8_t bond_flag = p_cb->peer_auth_req & 0x03; //0x03 is gen bond with appropriate mask
+    uint8_t enc_size = p_cb->peer_enc_size;
+
+    SMP_TRACE_DEBUG("%s for cmd code 0x%02x", __func__, p_cb->rcvd_cmd_code);
+
+    if (io_caps >= BTM_IO_CAP_MAX)
+    {
+        SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with IO Capabilty \
+            value (0x%02x) out of range).",
+            p_cb->rcvd_cmd_code, io_caps);
+        return false;
+    }
+
+    if (!((oob_flag == SMP_OOB_NONE) || (oob_flag == SMP_OOB_PRESENT)))
+    {
+        SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with OOB data flag value \
+            (0x%02x) out of range).",
+             p_cb->rcvd_cmd_code, oob_flag);
+        return false;
+    }
+
+    if (!((bond_flag == SMP_AUTH_NO_BOND) || (bond_flag == SMP_AUTH_BOND)))
+    {
+        SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with Bonding_Flags value (0x%02x)\
+                           out of range).",
+                           p_cb->rcvd_cmd_code, bond_flag);
+        return false;
+    }
+
+    if ((enc_size < SMP_ENCR_KEY_SIZE_MIN) || (enc_size > SMP_ENCR_KEY_SIZE_MAX))
+    {
+        SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with Maximum Encryption \
+            Key value (0x%02x) out of range).",
+            p_cb->rcvd_cmd_code, enc_size);
+        return false;
+    }
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         smp_pairing_keypress_notification_is_valid
+**
+** Description      Validates Notification Type parameter range in the received SMP command
+**                  pairing keypress notification.
+**                  Returns false if this parameter is out of range.
+**
+*******************************************************************************/
+bool    smp_pairing_keypress_notification_is_valid(tSMP_CB *p_cb)
+{
+    tBTM_SP_KEY_TYPE keypress_notification = p_cb->peer_keypress_notification;
+
+    SMP_TRACE_DEBUG("%s for cmd code 0x%02x", __func__, p_cb->rcvd_cmd_code);
+
+    if (keypress_notification >= BTM_SP_KEY_OUT_OF_RANGE)
+    {
+        SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with Pairing Keypress \
+            Notification value (0x%02x) out of range).",
+            p_cb->rcvd_cmd_code, keypress_notification);
+        return false;
+    }
+
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         smp_parameter_unconditionally_valid
+**
+** Description      Always returns true.
+**
+*******************************************************************************/
+bool    smp_parameter_unconditionally_valid(UNUSED_ATTR tSMP_CB *p_cb)
+{
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         smp_parameter_unconditionally_invalid
+**
+** Description      Always returns false.
+**
+*******************************************************************************/
+bool    smp_parameter_unconditionally_invalid(UNUSED_ATTR tSMP_CB *p_cb)
+{
+    return false;
+}
+
+/*******************************************************************************
+**
+** Function         smp_reject_unexpected_pairing_command
+**
+** Description      send pairing failure to an unexpected pairing command during
+**                  an active pairing process.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_reject_unexpected_pairing_command(BD_ADDR bd_addr)
+{
+    uint8_t *p;
+    BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) +
+                        SMP_PAIR_FAIL_SIZE + L2CAP_MIN_OFFSET);
+
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    p = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+    UINT8_TO_STREAM(p, SMP_OPCODE_PAIRING_FAILED);
+    UINT8_TO_STREAM(p, SMP_PAIR_NOT_SUPPORT);
+
+    p_buf->offset = L2CAP_MIN_OFFSET;
+    p_buf->len = SMP_PAIR_FAIL_SIZE;
+
+    smp_send_msg_to_L2CAP(bd_addr, p_buf);
+}
+
+/*******************************************************************************
+** Function         smp_select_association_model
+**
+** Description      This function selects association model to use for STK
+**                  generation. Selection is based on both sides' io capability,
+**                  oob data flag and authentication request.
+**
+** Note             If Secure Connections Only mode is required locally then we
+**                  come to this point only if both sides support Secure Connections
+**                  mode, i.e. if p_cb->secure_connections_only_mode_required = true then we come
+**                  to this point only if
+**                      (p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) ==
+**                      (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT) ==
+**                      SMP_SC_SUPPORT_BIT
+**
+*******************************************************************************/
+tSMP_ASSO_MODEL smp_select_association_model(tSMP_CB *p_cb)
+{
+    tSMP_ASSO_MODEL model = SMP_MODEL_OUT_OF_RANGE;
+    p_cb->le_secure_connections_mode_is_used = false;
+
+    SMP_TRACE_EVENT("%s", __func__);
+    SMP_TRACE_DEBUG("%s p_cb->peer_io_caps = %d p_cb->local_io_capability = %d",
+                       __func__, p_cb->peer_io_caps, p_cb->local_io_capability);
+    SMP_TRACE_DEBUG("%s p_cb->peer_oob_flag = %d p_cb->loc_oob_flag = %d",
+                       __func__, p_cb->peer_oob_flag, p_cb->loc_oob_flag);
+    SMP_TRACE_DEBUG("%s p_cb->peer_auth_req = 0x%02x p_cb->loc_auth_req = 0x%02x",
+                       __func__, p_cb->peer_auth_req, p_cb->loc_auth_req);
+    SMP_TRACE_DEBUG("%s p_cb->secure_connections_only_mode_required = %s",
+                       __func__, p_cb->secure_connections_only_mode_required ?
+                                    "true" : "false");
+
+    if ((p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) && (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT))
+    {
+        p_cb->le_secure_connections_mode_is_used = true;
+    }
+
+    SMP_TRACE_DEBUG("use_sc_process = %d", p_cb->le_secure_connections_mode_is_used);
+
+    if (p_cb->le_secure_connections_mode_is_used)
+    {
+        model = smp_select_association_model_secure_connections(p_cb);
+    }
+    else
+    {
+        model = smp_select_legacy_association_model(p_cb);
+    }
+    return model;
+}
+
+/*******************************************************************************
+** Function         smp_select_legacy_association_model
+**
+** Description      This function is called to select association mode if at least
+**                  one side doesn't support secure connections.
+**
+*******************************************************************************/
+tSMP_ASSO_MODEL smp_select_legacy_association_model(tSMP_CB *p_cb)
+{
+    tSMP_ASSO_MODEL model = SMP_MODEL_OUT_OF_RANGE;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+    /* if OOB data is present on both devices, then use OOB association model */
+    if (p_cb->peer_oob_flag == SMP_OOB_PRESENT && p_cb->loc_oob_flag == SMP_OOB_PRESENT)
+        return SMP_MODEL_OOB;
+
+    /* else if neither device requires MITM, then use Just Works association model */
+    if (SMP_NO_MITM_REQUIRED (p_cb->peer_auth_req) && SMP_NO_MITM_REQUIRED(p_cb->loc_auth_req))
+        return SMP_MODEL_ENCRYPTION_ONLY;
+
+    /* otherwise use IO capability to select association model */
+    if (p_cb->peer_io_caps < SMP_IO_CAP_MAX && p_cb->local_io_capability < SMP_IO_CAP_MAX)
+    {
+        if (p_cb->role == HCI_ROLE_MASTER)
+        {
+            model = smp_association_table[p_cb->role][p_cb->peer_io_caps]
+                                         [p_cb->local_io_capability];
+        }
+        else
+        {
+            model = smp_association_table[p_cb->role][p_cb->local_io_capability]
+                                         [p_cb->peer_io_caps];
+        }
+    }
+
+    return model;
+}
+
+/*******************************************************************************
+** Function         smp_select_association_model_secure_connections
+**
+** Description      This function is called to select association mode if both
+**                  sides support secure connections.
+**
+*******************************************************************************/
+tSMP_ASSO_MODEL smp_select_association_model_secure_connections(tSMP_CB *p_cb)
+{
+    tSMP_ASSO_MODEL model = SMP_MODEL_OUT_OF_RANGE;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+    /* if OOB data is present on at least one device, then use OOB association model */
+    if (p_cb->peer_oob_flag == SMP_OOB_PRESENT || p_cb->loc_oob_flag == SMP_OOB_PRESENT)
+        return SMP_MODEL_SEC_CONN_OOB;
+
+    /* else if neither device requires MITM, then use Just Works association model */
+    if (SMP_NO_MITM_REQUIRED (p_cb->peer_auth_req) && SMP_NO_MITM_REQUIRED(p_cb->loc_auth_req))
+        return SMP_MODEL_SEC_CONN_JUSTWORKS;
+
+    /* otherwise use IO capability to select association model */
+    if (p_cb->peer_io_caps < SMP_IO_CAP_MAX && p_cb->local_io_capability < SMP_IO_CAP_MAX)
+    {
+        if (p_cb->role == HCI_ROLE_MASTER)
+        {
+            model = smp_association_table_sc[p_cb->role][p_cb->peer_io_caps]
+                                            [p_cb->local_io_capability];
+        }
+        else
+        {
+            model = smp_association_table_sc[p_cb->role][p_cb->local_io_capability]
+                                            [p_cb->peer_io_caps];
+        }
+    }
+
+    return model;
+}
+
+/*******************************************************************************
+** Function         smp_reverse_array
+**
+** Description      This function reverses array bytes
+**
+*******************************************************************************/
+void smp_reverse_array(uint8_t *arr, uint8_t len)
+{
+    uint8_t i =0, tmp;
+
+    SMP_TRACE_DEBUG("smp_reverse_array");
+
+    for (i = 0; i < len/2; i ++)
+    {
+        tmp = arr[i];
+        arr[i] = arr[len -1 - i];
+        arr[len -1 - i] = tmp;
+    }
+}
+
+/*******************************************************************************
+** Function         smp_calculate_random_input
+**
+** Description      This function returns random input value to be used in commitment
+**                  calculation for SC passkey entry association mode
+**                  (if bit["round"] in "random" array == 1 then returns 0x81
+**                   else returns 0x80).
+**
+** Returns          ri value
+**
+*******************************************************************************/
+uint8_t smp_calculate_random_input(uint8_t *random, uint8_t round)
+{
+    uint8_t i = round/8;
+    uint8_t j = round%8;
+    uint8_t ri;
+
+    SMP_TRACE_DEBUG("random: 0x%02x, round: %d, i: %d, j: %d", random[i], round, i, j);
+    ri = ((random[i] >> j) & 1) | 0x80;
+    SMP_TRACE_DEBUG("%s ri=0x%02x", __func__, ri);
+    return ri;
+}
+
+/*******************************************************************************
+** Function         smp_collect_local_io_capabilities
+**
+** Description      This function puts into IOcap array local device
+**                  IOCapability, OOB data, AuthReq.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_collect_local_io_capabilities(uint8_t *iocap, tSMP_CB *p_cb)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    iocap[0] = p_cb->local_io_capability;
+    iocap[1] = p_cb->loc_oob_flag;
+    iocap[2] = p_cb->loc_auth_req;
+}
+
+/*******************************************************************************
+** Function         smp_collect_peer_io_capabilities
+**
+** Description      This function puts into IOcap array peer device
+**                  IOCapability, OOB data, AuthReq.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_collect_peer_io_capabilities(uint8_t *iocap, tSMP_CB *p_cb)
+{
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    iocap[0] = p_cb->peer_io_caps;
+    iocap[1] = p_cb->peer_oob_flag;
+    iocap[2] = p_cb->peer_auth_req;
+}
+
+/*******************************************************************************
+** Function         smp_collect_local_ble_address
+**
+** Description      This function puts into le_addr array local device le address:
+**                  le_addr[0-5] = local BD ADDR,
+**                  le_addr[6] = local le address type (PUBLIC/RANDOM).
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_collect_local_ble_address(uint8_t *le_addr, tSMP_CB *p_cb)
+{
+    tBLE_ADDR_TYPE  addr_type = 0;
+    BD_ADDR         bda;
+    uint8_t         *p = le_addr;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    BTM_ReadConnectionAddr( p_cb->pairing_bda, bda, &addr_type);
+    BDADDR_TO_STREAM(p, bda);
+    UINT8_TO_STREAM(p, addr_type);
+}
+
+/*******************************************************************************
+** Function         smp_collect_peer_ble_address
+**
+** Description      This function puts into le_addr array peer device le address:
+**                  le_addr[0-5] = peer BD ADDR,
+**                  le_addr[6] = peer le address type (PUBLIC/RANDOM).
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_collect_peer_ble_address(uint8_t *le_addr, tSMP_CB *p_cb)
+{
+    tBLE_ADDR_TYPE  addr_type = 0;
+    BD_ADDR         bda;
+    uint8_t         *p = le_addr;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    if (!BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, bda, &addr_type))
+    {
+        SMP_TRACE_ERROR("can not collect peer le addr information for unknown device");
+        return;
+    }
+
+    BDADDR_TO_STREAM(p, bda);
+    UINT8_TO_STREAM(p, addr_type);
+}
+
+/*******************************************************************************
+** Function         smp_check_commitment
+**
+** Description      This function compares peer commitment values:
+**                  - expected (i.e. calculated locally),
+**                  - received from the peer.
+**
+** Returns          true  if the values are the same
+**                  false otherwise
+**
+*******************************************************************************/
+bool    smp_check_commitment(tSMP_CB *p_cb)
+{
+    BT_OCTET16 expected;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    smp_calculate_peer_commitment(p_cb, expected);
+    print128(expected, (const uint8_t *)"calculated peer commitment");
+    print128(p_cb->remote_commitment, (const uint8_t *)"received peer commitment");
+
+    if (memcmp(p_cb->remote_commitment, expected, BT_OCTET16_LEN))
+    {
+        SMP_TRACE_WARNING("%s: Commitment check fails", __func__);
+        return false;
+    }
+
+    SMP_TRACE_DEBUG("%s: Commitment check succeeds", __func__);
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         smp_save_secure_connections_long_term_key
+**
+** Description      The function saves SC LTK as BLE key for future use as local
+**                  and/or peer key.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_save_secure_connections_long_term_key(tSMP_CB *p_cb)
+{
+    tBTM_LE_LENC_KEYS   lle_key;
+    tBTM_LE_PENC_KEYS   ple_key;
+
+    SMP_TRACE_DEBUG("%s-Save LTK as local LTK key", __func__);
+    memcpy(lle_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
+    lle_key.div = 0;
+    lle_key.key_size = p_cb->loc_enc_size;
+    lle_key.sec_level = p_cb->sec_level;
+    btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LENC, (tBTM_LE_KEY_VALUE *)&lle_key, true);
+
+    SMP_TRACE_DEBUG("%s-Save LTK as peer LTK key", __func__);
+    ple_key.ediv = 0;
+    memset(ple_key.rand, 0, BT_OCTET8_LEN);
+    memcpy(ple_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
+    ple_key.sec_level = p_cb->sec_level;
+    ple_key.key_size  = p_cb->loc_enc_size;
+    btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PENC, (tBTM_LE_KEY_VALUE *)&ple_key, true);
+}
+
+/*******************************************************************************
+**
+** Function         smp_calculate_f5_mackey_and_long_term_key
+**
+** Description      The function calculates MacKey and LTK and saves them in CB.
+**                  To calculate MacKey and LTK it calls smp_calc_f5(...).
+**                  MacKey is used in dhkey calculation, LTK is used to encrypt
+**                  the link.
+**
+** Returns          false if out of resources, true otherwise.
+**
+*******************************************************************************/
+bool    smp_calculate_f5_mackey_and_long_term_key(tSMP_CB *p_cb)
+{
+    uint8_t a[7];
+    uint8_t b[7];
+    uint8_t *p_na;
+    uint8_t *p_nb;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    if (p_cb->role == HCI_ROLE_MASTER)
+    {
+        smp_collect_local_ble_address(a, p_cb);
+        smp_collect_peer_ble_address(b, p_cb);
+        p_na = p_cb->rand;
+        p_nb = p_cb->rrand;
+    }
+    else
+    {
+        smp_collect_local_ble_address(b, p_cb);
+        smp_collect_peer_ble_address(a, p_cb);
+        p_na = p_cb->rrand;
+        p_nb = p_cb->rand;
+    }
+
+    if(!smp_calculate_f5(p_cb->dhkey, p_na, p_nb, a, b, p_cb->mac_key, p_cb->ltk))
+    {
+        SMP_TRACE_ERROR("%s failed", __func__);
+        return false;
+    }
+
+    SMP_TRACE_EVENT ("%s is completed", __func__);
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         smp_request_oob_data
+**
+** Description      Requests application to provide OOB data.
+**
+** Returns          true - OOB data has to be provided by application
+**                  false - otherwise (unexpected)
+**
+*******************************************************************************/
+bool    smp_request_oob_data(tSMP_CB *p_cb)
+{
+    tSMP_OOB_DATA_TYPE req_oob_type = SMP_OOB_INVALID_TYPE;
+
+    SMP_TRACE_DEBUG("%s", __func__);
+
+    if (p_cb->peer_oob_flag == SMP_OOB_PRESENT && p_cb->loc_oob_flag == SMP_OOB_PRESENT)
+    {
+        /* both local and peer rcvd data OOB */
+        req_oob_type = SMP_OOB_BOTH;
+    }
+    else if (p_cb->peer_oob_flag == SMP_OOB_PRESENT)
+    {
+        /* peer rcvd OOB local data, local didn't receive OOB peer data */
+        req_oob_type = SMP_OOB_LOCAL;
+    }
+    else if (p_cb->loc_oob_flag == SMP_OOB_PRESENT)
+    {
+        req_oob_type = SMP_OOB_PEER;
+    }
+
+    SMP_TRACE_DEBUG("req_oob_type = %d", req_oob_type);
+
+    if (req_oob_type == SMP_OOB_INVALID_TYPE)
+        return false;
+
+    p_cb->req_oob_type = req_oob_type;
+    p_cb->cb_evt = SMP_SC_OOB_REQ_EVT;
+    smp_sm_event(p_cb, SMP_TK_REQ_EVT, &req_oob_type);
+
+    return true;
+}
+
+
+#endif
+
diff --git a/bt/stack/srvc/srvc_battery.cc b/bt/stack/srvc/srvc_battery.cc
new file mode 100644
index 0000000..21b10aa
--- /dev/null
+++ b/bt/stack/srvc/srvc_battery.cc
@@ -0,0 +1,399 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-2013 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.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "gatt_api.h"
+#include "gatt_int.h"
+#include "srvc_eng_int.h"
+#include "srvc_battery_int.h"
+#include "btcore/include/uuid.h"
+#include "osi/include/osi.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+#define BA_MAX_CHAR_NUM          1
+#define BA_MAX_ATTR_NUM          (BA_MAX_CHAR_NUM * 5 + 1) /* max 3 descriptors, 1 desclration and 1 value */
+
+#ifndef BATTER_LEVEL_PROP
+#define BATTER_LEVEL_PROP           (GATT_CHAR_PROP_BIT_READ|GATT_CHAR_PROP_BIT_NOTIFY)
+#endif
+
+
+#ifndef BATTER_LEVEL_PERM
+#define BATTER_LEVEL_PERM           (GATT_PERM_READ)
+#endif
+
+tBATTERY_CB battery_cb;
+
+
+/*******************************************************************************
+**   battery_valid_handle_range
+**
+**   validate a handle to be a DIS attribute handle or not.
+*******************************************************************************/
+bool    battery_valid_handle_range(uint16_t handle)
+{
+    uint8_t     i = 0;
+    tBA_INST    *p_inst = &battery_cb.battery_inst[0];
+
+    for (;i < BA_MAX_INT_NUM; i ++, p_inst++)
+    {
+        if (handle == p_inst->ba_level_hdl ||
+            handle == p_inst->clt_cfg_hdl ||
+            handle == p_inst->rpt_ref_hdl ||
+            handle == p_inst->pres_fmt_hdl )
+        {
+            return true;
+        }
+    }
+    return false;
+}
+/*******************************************************************************
+**   battery_s_write_attr_value
+**
+**   Process write DIS attribute request.
+*******************************************************************************/
+uint8_t battery_s_write_attr_value(uint8_t clcb_idx, tGATT_WRITE_REQ * p_value,
+                                 tGATT_STATUS *p_status)
+{
+    uint8_t     *p = p_value->value, i;
+    uint16_t    handle = p_value->handle;
+    tBA_INST    *p_inst = &battery_cb.battery_inst[0];
+    tGATT_STATUS    st = GATT_NOT_FOUND;
+    tBA_WRITE_DATA   cfg;
+    uint8_t     act = SRVC_ACT_RSP;
+
+    for (i = 0; i < BA_MAX_INT_NUM; i ++, p_inst ++)
+    {
+        /* read battery level */
+        if (handle == p_inst->clt_cfg_hdl)
+        {
+            memcpy(cfg.remote_bda, srvc_eng_cb.clcb[clcb_idx].bda, BD_ADDR_LEN);
+            STREAM_TO_UINT16(cfg.clt_cfg, p);
+
+            if (p_inst->p_cback)
+            {
+                p_inst->pending_clcb_idx = clcb_idx;
+                p_inst->pending_evt = BA_WRITE_CLT_CFG_REQ;
+                p_inst->pending_handle = handle;
+                cfg.need_rsp = p_value->need_rsp;
+                act = SRVC_ACT_PENDING;
+
+                (* p_inst->p_cback)(p_inst->app_id, BA_WRITE_CLT_CFG_REQ, &cfg);
+            }
+        }
+        else /* all other handle is not writable */
+        {
+            st = GATT_WRITE_NOT_PERMIT;
+            break;
+        }
+    }
+    *p_status = st;
+
+    return act;
+}
+/*******************************************************************************
+**   BA Attributes Database Server Request callback
+*******************************************************************************/
+uint8_t battery_s_read_attr_value (uint8_t clcb_idx, uint16_t handle,
+                                   UNUSED_ATTR tGATT_VALUE *p_value, bool    is_long,
+                                   tGATT_STATUS* p_status)
+{
+    uint8_t     i;
+    tBA_INST    *p_inst = &battery_cb.battery_inst[0];
+    tGATT_STATUS    st = GATT_NOT_FOUND;
+    uint8_t     act = SRVC_ACT_RSP;
+
+    for (i = 0; i < BA_MAX_INT_NUM; i ++, p_inst ++)
+    {
+        /* read battery level */
+        if (handle == p_inst->ba_level_hdl ||
+            handle == p_inst->clt_cfg_hdl ||
+            handle == p_inst->rpt_ref_hdl ||
+            handle == p_inst->pres_fmt_hdl)
+            {
+            if (is_long)
+                st = GATT_NOT_LONG;
+
+                if (p_inst->p_cback)
+                {
+                if (handle == p_inst->ba_level_hdl) p_inst->pending_evt = BA_READ_LEVEL_REQ;
+                if (handle == p_inst->clt_cfg_hdl) p_inst->pending_evt = BA_READ_CLT_CFG_REQ;
+                if (handle == p_inst->pres_fmt_hdl) p_inst->pending_evt = BA_READ_PRE_FMT_REQ;
+                if (handle == p_inst->rpt_ref_hdl) p_inst->pending_evt = BA_READ_RPT_REF_REQ ;
+
+                    p_inst->pending_clcb_idx = clcb_idx;
+                    p_inst->pending_handle = handle;
+                    act = SRVC_ACT_PENDING;
+
+                (* p_inst->p_cback)(p_inst->app_id, p_inst->pending_evt, NULL);
+                }
+            else /* application is not registered */
+                st = GATT_ERR_UNLIKELY;
+                break;
+            }
+        /* else attribute not found */
+    }
+
+
+    *p_status = st;
+    return act;
+}
+
+
+/*******************************************************************************
+**
+** Function         battery_gatt_c_read_ba_req
+**
+** Description      Read remote device BA level attribute request.
+**
+** Returns          void
+**
+*******************************************************************************/
+bool    battery_gatt_c_read_ba_req(UNUSED_ATTR uint16_t conn_id)
+{
+    return true;
+}
+
+/*******************************************************************************
+**
+** Function         battery_c_cmpl_cback
+**
+** Description      Client operation complete callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+void battery_c_cmpl_cback (UNUSED_ATTR tSRVC_CLCB *p_clcb, UNUSED_ATTR tGATTC_OPTYPE op,
+                              UNUSED_ATTR tGATT_STATUS status,
+                           UNUSED_ATTR tGATT_CL_COMPLETE *p_data)
+{
+}
+
+
+/*******************************************************************************
+**
+** Function         Battery_Instantiate
+**
+** Description      Instantiate a Battery service
+**
+*******************************************************************************/
+uint16_t Battery_Instantiate (uint8_t app_id, tBA_REG_INFO *p_reg_info)
+{
+    uint16_t            srvc_hdl = 0;
+    tGATT_STATUS        status = GATT_ERROR;
+    tBA_INST            *p_inst;
+
+    if (battery_cb.inst_id == BA_MAX_INT_NUM)
+    {
+        GATT_TRACE_ERROR("MAX battery service has been reached");
+        return 0;
+    }
+
+    p_inst = &battery_cb.battery_inst[battery_cb.inst_id];
+
+    btgatt_db_element_t service[BA_MAX_ATTR_NUM] = {};
+
+    bt_uuid_t service_uuid;
+    uuid_128_from_16(&service_uuid, UUID_SERVCLASS_BATTERY);
+    service[0].type = /* p_reg_info->is_pri */ BTGATT_DB_PRIMARY_SERVICE;
+    service[0].uuid = service_uuid;
+
+    bt_uuid_t char_uuid;
+    uuid_128_from_16(&char_uuid, GATT_UUID_BATTERY_LEVEL);
+    service[1].type = BTGATT_DB_CHARACTERISTIC;
+    service[1].uuid = char_uuid;
+    service[1].properties = GATT_CHAR_PROP_BIT_READ;
+    if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY)
+        service[1].properties |= GATT_CHAR_PROP_BIT_NOTIFY;
+
+    int i=2;
+    if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY) {
+        bt_uuid_t desc_uuid;
+        uuid_128_from_16(&desc_uuid, GATT_UUID_CHAR_CLIENT_CONFIG);
+
+        service[i].type = BTGATT_DB_DESCRIPTOR;
+        service[i].uuid = desc_uuid;
+        service[i].permissions = (GATT_PERM_READ|GATT_PERM_WRITE);
+        i++;
+    }
+
+    /* need presentation format descriptor? */
+    if (p_reg_info->ba_level_descr & BA_LEVEL_PRE_FMT) {
+        bt_uuid_t desc_uuid;
+        uuid_128_from_16(&desc_uuid, GATT_UUID_CHAR_PRESENT_FORMAT);
+
+        service[i].type = BTGATT_DB_DESCRIPTOR;
+        service[i].uuid = desc_uuid;
+        service[i].permissions = GATT_PERM_READ;
+        i++;
+    }
+
+    /* need presentation format descriptor? */
+    if (p_reg_info->ba_level_descr & BA_LEVEL_RPT_REF) {
+        bt_uuid_t desc_uuid;
+        uuid_128_from_16(&desc_uuid, GATT_UUID_RPT_REF_DESCR);
+
+        service[i].type = BTGATT_DB_DESCRIPTOR;
+        service[i].uuid = desc_uuid;
+        service[i].permissions = GATT_PERM_READ;
+        i++;
+    }
+
+    GATTS_AddService(srvc_eng_cb.gatt_if, service, i);
+
+    if (status != GATT_SUCCESS) {
+        battery_cb.inst_id --;
+        GATT_TRACE_ERROR("%s: Failed to add battery servuce!", __func__);
+    }
+
+    battery_cb.inst_id ++;
+
+    p_inst->app_id  =   app_id;
+    p_inst->p_cback =   p_reg_info->p_cback;
+
+    srvc_hdl = service[0].attribute_handle;
+    p_inst->ba_level_hdl = service[1].attribute_handle;
+
+    i=2;
+    if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY) {
+        p_inst->clt_cfg_hdl = service[i].attribute_handle;
+        i++;
+    }
+
+    if (p_reg_info->ba_level_descr & BA_LEVEL_PRE_FMT) {
+        p_inst->pres_fmt_hdl = service[i].attribute_handle;
+        i++;
+    }
+
+    if (p_reg_info->ba_level_descr & BA_LEVEL_RPT_REF) {
+        p_inst->rpt_ref_hdl = service[i].attribute_handle;
+        i++;
+    }
+
+    return srvc_hdl;
+}
+/*******************************************************************************
+**
+** Function         Battery_Rsp
+**
+** Description      Respond to a battery service request
+**
+*******************************************************************************/
+void Battery_Rsp (uint8_t app_id, tGATT_STATUS st, uint8_t event, tBA_RSP_DATA *p_rsp)
+{
+    tBA_INST *p_inst = &battery_cb.battery_inst[0];
+    tGATTS_RSP  rsp;
+    uint8_t *pp;
+
+    uint8_t i = 0;
+    while (i < BA_MAX_INT_NUM)
+    {
+        if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0)
+            break;
+        i ++;
+    }
+
+    if (i == BA_MAX_INT_NUM)
+        return;
+
+    memset(&rsp, 0, sizeof(tGATTS_RSP));
+
+    if (p_inst->pending_evt == event)
+    {
+        switch (event)
+        {
+        case BA_READ_CLT_CFG_REQ:
+            rsp.attr_value.handle = p_inst->pending_handle;
+            rsp.attr_value.len = 2;
+            pp = rsp.attr_value.value;
+            UINT16_TO_STREAM(pp, p_rsp->clt_cfg);
+            srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
+            break;
+
+        case BA_READ_LEVEL_REQ:
+            rsp.attr_value.handle = p_inst->pending_handle;
+            rsp.attr_value.len = 1;
+            pp = rsp.attr_value.value;
+            UINT8_TO_STREAM(pp, p_rsp->ba_level);
+            srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
+            break;
+
+        case BA_WRITE_CLT_CFG_REQ:
+            srvc_sr_rsp(p_inst->pending_clcb_idx, st, NULL);
+            break;
+
+        case BA_READ_RPT_REF_REQ:
+            rsp.attr_value.handle = p_inst->pending_handle;
+            rsp.attr_value.len = 2;
+            pp = rsp.attr_value.value;
+            UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_id);
+            UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_type);
+            srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
+            break;
+
+        default:
+            break;
+        }
+        p_inst->pending_clcb_idx = 0;
+        p_inst->pending_evt = 0;
+        p_inst->pending_handle = 0;
+    }
+    return;
+}
+/*******************************************************************************
+**
+** Function         Battery_Notify
+**
+** Description      Send battery level notification
+**
+*******************************************************************************/
+void Battery_Notify (uint8_t app_id, BD_ADDR remote_bda, uint8_t battery_level)
+{
+    tBA_INST *p_inst = &battery_cb.battery_inst[0];
+    uint8_t  i = 0;
+
+    while (i < BA_MAX_INT_NUM)
+    {
+        if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0)
+            break;
+        i ++;
+    }
+
+    if (i == BA_MAX_INT_NUM || p_inst->clt_cfg_hdl == 0)
+        return;
+
+    srvc_sr_notify(remote_bda, p_inst->ba_level_hdl, 1, &battery_level);
+
+}
+/*******************************************************************************
+**
+** Function         Battery_ReadBatteryLevel
+**
+** Description      Read remote device Battery Level information.
+**
+** Returns          void
+**
+*******************************************************************************/
+bool    Battery_ReadBatteryLevel(UNUSED_ATTR BD_ADDR peer_bda)
+{
+    /* to be implemented */
+    return true;
+}
+#endif  /* BLE_INCLUDED */
diff --git a/bt/stack/srvc/srvc_battery_int.h b/bt/stack/srvc/srvc_battery_int.h
new file mode 100644
index 0000000..4b03e87
--- /dev/null
+++ b/bt/stack/srvc/srvc_battery_int.h
@@ -0,0 +1,76 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+
+#ifndef SRVC_BATTERY_INT_H
+#define SRVC_BATTERY_INT_H
+
+#include "bt_target.h"
+#include "srvc_api.h"
+#include "gatt_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef BA_MAX_INT_NUM
+#define BA_MAX_INT_NUM     4
+#endif
+
+#define BATTERY_LEVEL_SIZE      1
+
+
+typedef struct
+{
+    uint8_t         app_id;
+    uint16_t        ba_level_hdl;
+    uint16_t        clt_cfg_hdl;
+    uint16_t        rpt_ref_hdl;
+    uint16_t        pres_fmt_hdl;
+
+    tBA_CBACK       *p_cback;
+
+    uint16_t        pending_handle;
+    uint8_t         pending_clcb_idx;
+    uint8_t         pending_evt;
+
+}tBA_INST;
+
+typedef struct
+{
+    tBA_INST                battery_inst[BA_MAX_INT_NUM];
+    uint8_t                 inst_id;
+    bool                    enabled;
+
+}tBATTERY_CB;
+
+/* Global GATT data */
+extern tBATTERY_CB battery_cb;
+
+
+extern bool    battery_valid_handle_range(uint16_t handle);
+
+extern uint8_t battery_s_write_attr_value(uint8_t clcb_idx, tGATT_WRITE_REQ * p_value,
+                                 tGATT_STATUS *p_status);
+extern uint8_t battery_s_read_attr_value (uint8_t clcb_idx, uint16_t handle, tGATT_VALUE *p_value, bool    is_long, tGATT_STATUS* p_status);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/bt/stack/srvc/srvc_dis.cc b/bt/stack/srvc/srvc_dis.cc
new file mode 100644
index 0000000..308228e
--- /dev/null
+++ b/bt/stack/srvc/srvc_dis.cc
@@ -0,0 +1,490 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-2013 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.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_srvc"
+
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "gatt_api.h"
+#include "gatt_int.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "srvc_dis_int.h"
+#include "srvc_eng_int.h"
+#include "btcore/include/uuid.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+#define DIS_MAX_NUM_INC_SVR       0
+#define DIS_MAX_CHAR_NUM          9
+#define DIS_MAX_ATTR_NUM          (DIS_MAX_CHAR_NUM * 2 + DIS_MAX_NUM_INC_SVR + 1)
+
+#ifndef DIS_ATTR_DB_SIZE
+#define DIS_ATTR_DB_SIZE      GATT_DB_MEM_SIZE(DIS_MAX_NUM_INC_SVR, DIS_MAX_CHAR_NUM, 0)
+#endif
+
+#define uint64_t_TO_STREAM(p, u64) {*(p)++ = (uint8_t)(u64);       *(p)++ = (uint8_t)((u64) >> 8);*(p)++ = (uint8_t)((u64) >> 16); *(p)++ = (uint8_t)((u64) >> 24); \
+                                    *(p)++ = (uint8_t)((u64) >> 32); *(p)++ = (uint8_t)((u64) >> 40);*(p)++ = (uint8_t)((u64) >> 48); *(p)++ = (uint8_t)((u64) >> 56);}
+
+#define STREAM_TO_UINT64(u64, p) {(u64) = (((uint64_t)(*(p))) + ((((uint64_t)(*((p) + 1)))) << 8) + ((((uint64_t)(*((p) + 2)))) << 16) + ((((uint64_t)(*((p) + 3)))) << 24) \
+                                  + ((((uint64_t)(*((p) + 4)))) << 32) + ((((uint64_t)(*((p) + 5)))) << 40) + ((((uint64_t)(*((p) + 6)))) << 48) + ((((uint64_t)(*((p) + 7)))) << 56)); (p) += 8;}
+
+static const uint16_t dis_attr_uuid[DIS_MAX_CHAR_NUM] =
+{
+    GATT_UUID_SYSTEM_ID,
+    GATT_UUID_MODEL_NUMBER_STR,
+    GATT_UUID_SERIAL_NUMBER_STR,
+    GATT_UUID_FW_VERSION_STR,
+    GATT_UUID_HW_VERSION_STR,
+    GATT_UUID_SW_VERSION_STR,
+    GATT_UUID_MANU_NAME,
+    GATT_UUID_IEEE_DATA,
+    GATT_UUID_PNP_ID
+};
+
+tDIS_CB dis_cb;
+
+static tDIS_ATTR_MASK dis_uuid_to_attr(uint16_t uuid)
+{
+    switch (uuid)
+    {
+        case GATT_UUID_SYSTEM_ID:
+            return DIS_ATTR_SYS_ID_BIT;
+        case GATT_UUID_MODEL_NUMBER_STR:
+            return DIS_ATTR_MODEL_NUM_BIT;
+        case GATT_UUID_SERIAL_NUMBER_STR:
+            return DIS_ATTR_SERIAL_NUM_BIT;
+        case GATT_UUID_FW_VERSION_STR:
+            return DIS_ATTR_FW_NUM_BIT;
+        case GATT_UUID_HW_VERSION_STR:
+            return DIS_ATTR_HW_NUM_BIT;
+        case GATT_UUID_SW_VERSION_STR:
+            return DIS_ATTR_SW_NUM_BIT;
+        case GATT_UUID_MANU_NAME:
+            return DIS_ATTR_MANU_NAME_BIT;
+        case GATT_UUID_IEEE_DATA:
+            return DIS_ATTR_IEEE_DATA_BIT;
+        case GATT_UUID_PNP_ID:
+            return DIS_ATTR_PNP_ID_BIT;
+        default:
+            return 0;
+    };
+}
+
+/*******************************************************************************
+**   dis_valid_handle_range
+**
+**   validate a handle to be a DIS attribute handle or not.
+*******************************************************************************/
+bool    dis_valid_handle_range(uint16_t handle)
+{
+    if (handle >= dis_cb.service_handle && handle <= dis_cb.max_handle)
+        return true;
+    else
+        return false;
+}
+/*******************************************************************************
+**   dis_write_attr_value
+**
+**   Process write DIS attribute request.
+*******************************************************************************/
+uint8_t dis_write_attr_value(UNUSED_ATTR tGATT_WRITE_REQ *p_data, tGATT_STATUS *p_status)
+{
+    *p_status = GATT_WRITE_NOT_PERMIT;
+    return SRVC_ACT_RSP;
+}
+/*******************************************************************************
+**   DIS Attributes Database Server Request callback
+*******************************************************************************/
+uint8_t dis_read_attr_value (UNUSED_ATTR uint8_t clcb_idx, uint16_t handle,
+                             tGATT_VALUE *p_value,
+                           bool    is_long, tGATT_STATUS *p_status)
+{
+    tDIS_DB_ENTRY   *p_db_attr = dis_cb.dis_attr;
+    uint8_t         *p = p_value->value, i, *pp;
+    uint16_t        offset = p_value->offset;
+    uint8_t         act = SRVC_ACT_RSP;
+    tGATT_STATUS    st = GATT_NOT_FOUND;
+
+    for (i = 0; i < DIS_MAX_CHAR_NUM; i ++, p_db_attr ++)
+    {
+        if (handle == p_db_attr->handle)
+        {
+            if ((p_db_attr->uuid == GATT_UUID_PNP_ID || p_db_attr->uuid == GATT_UUID_SYSTEM_ID)&&
+                is_long == true)
+            {
+                st = GATT_NOT_LONG;
+                break;
+            }
+            st = GATT_SUCCESS;
+
+            switch (p_db_attr->uuid)
+            {
+                case GATT_UUID_MANU_NAME:
+                case GATT_UUID_MODEL_NUMBER_STR:
+                case GATT_UUID_SERIAL_NUMBER_STR:
+                case GATT_UUID_FW_VERSION_STR:
+                case GATT_UUID_HW_VERSION_STR:
+                case GATT_UUID_SW_VERSION_STR:
+                case GATT_UUID_IEEE_DATA:
+                    pp = dis_cb.dis_value.data_string[p_db_attr->uuid - GATT_UUID_MODEL_NUMBER_STR];
+                    if (pp != NULL)
+                    {
+                        if (strlen ((char *)pp) > GATT_MAX_ATTR_LEN)
+                            p_value->len = GATT_MAX_ATTR_LEN;
+                        else
+                            p_value->len = (uint16_t)strlen ((char *)pp);
+                    }
+                    else
+                        p_value->len = 0;
+
+                    if (offset > p_value->len)
+                    {
+                        st = GATT_INVALID_OFFSET;
+                        break;
+                    }
+                    else
+                    {
+                        p_value->len -= offset;
+                        pp += offset;
+                        ARRAY_TO_STREAM(p, pp, p_value->len);
+                        GATT_TRACE_EVENT("GATT_UUID_MANU_NAME len=0x%04x", p_value->len);
+                    }
+                    break;
+
+                case GATT_UUID_SYSTEM_ID:
+                    uint64_t_TO_STREAM(p, dis_cb.dis_value.system_id); /* int_min */
+                    p_value->len = DIS_SYSTEM_ID_SIZE;
+                    break;
+
+                case  GATT_UUID_PNP_ID:
+                    UINT8_TO_STREAM(p, dis_cb.dis_value.pnp_id.vendor_id_src);
+                    UINT16_TO_STREAM(p, dis_cb.dis_value.pnp_id.vendor_id);
+                    UINT16_TO_STREAM(p, dis_cb.dis_value.pnp_id.product_id);
+                    UINT16_TO_STREAM(p, dis_cb.dis_value.pnp_id.product_version);
+                    p_value->len = DIS_PNP_ID_SIZE;
+                    break;
+
+            }
+            break;
+        }
+    }
+    *p_status = st;
+    return act;
+}
+
+/*******************************************************************************
+**
+** Function         dis_gatt_c_read_dis_value_cmpl
+**
+** Description      Client read DIS database complete callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void dis_gatt_c_read_dis_value_cmpl(uint16_t conn_id)
+{
+    tSRVC_CLCB *p_clcb = srvc_eng_find_clcb_by_conn_id(conn_id);
+
+    dis_cb.dis_read_uuid_idx = 0xff;
+
+    srvc_eng_release_channel(conn_id);
+
+    if (dis_cb.p_read_dis_cback && p_clcb)
+    {
+        LOG_INFO(LOG_TAG, "%s conn_id:%d attr_mask = 0x%04x", __func__, conn_id,
+                p_clcb->dis_value.attr_mask);
+
+        (*dis_cb.p_read_dis_cback)(p_clcb->bda, &p_clcb->dis_value);
+        dis_cb.p_read_dis_cback = NULL;
+    }
+}
+
+/*******************************************************************************
+**
+** Function         dis_gatt_c_read_dis_req
+**
+** Description      Read remote device DIS attribute request.
+**
+** Returns          void
+**
+*******************************************************************************/
+bool    dis_gatt_c_read_dis_req(uint16_t conn_id)
+{
+    tGATT_READ_PARAM   param;
+
+    memset(&param, 0, sizeof(tGATT_READ_PARAM));
+
+    param.service.uuid.len       = LEN_UUID_16;
+    param.service.s_handle       = 1;
+    param.service.e_handle       = 0xFFFF;
+    param.service.auth_req       = 0;
+
+    while (dis_cb.dis_read_uuid_idx < DIS_MAX_CHAR_NUM)
+    {
+        if (dis_uuid_to_attr(dis_attr_uuid[dis_cb.dis_read_uuid_idx]) &
+                dis_cb.request_mask)
+        {
+             param.service.uuid.uu.uuid16 = dis_attr_uuid[dis_cb.dis_read_uuid_idx];
+
+             if (GATTC_Read(conn_id, GATT_READ_BY_TYPE, &param) == GATT_SUCCESS)
+                 return true;
+
+            GATT_TRACE_ERROR ("Read DISInfo: 0x%04x GATT_Read Failed", param.service.uuid.uu.uuid16);
+        }
+
+        dis_cb.dis_read_uuid_idx++;
+    }
+
+    dis_gatt_c_read_dis_value_cmpl(conn_id);
+
+    return(false);
+}
+
+/*******************************************************************************
+**
+** Function         dis_c_cmpl_cback
+**
+** Description      Client operation complete callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+void dis_c_cmpl_cback (tSRVC_CLCB *p_clcb, tGATTC_OPTYPE op,
+                              tGATT_STATUS status, tGATT_CL_COMPLETE *p_data)
+{
+    uint16_t    read_type = dis_attr_uuid[dis_cb.dis_read_uuid_idx];
+    uint8_t     *pp = NULL, *p_str;
+    uint16_t    conn_id = p_clcb->conn_id;
+
+    GATT_TRACE_EVENT ("dis_c_cmpl_cback() - op_code: 0x%02x  status: 0x%02x  \
+                        read_type: 0x%04x", op, status, read_type);
+
+    if (op != GATTC_OPTYPE_READ)
+        return;
+
+    if (p_data != NULL && status == GATT_SUCCESS)
+    {
+        pp = p_data->att_value.value;
+
+        switch (read_type)
+        {
+            case GATT_UUID_SYSTEM_ID:
+                GATT_TRACE_EVENT ("DIS_ATTR_SYS_ID_BIT");
+                if (p_data->att_value.len == DIS_SYSTEM_ID_SIZE)
+                {
+                    p_clcb->dis_value.attr_mask |= DIS_ATTR_SYS_ID_BIT;
+                    /* save system ID*/
+                    STREAM_TO_UINT64 (p_clcb->dis_value.system_id, pp);
+                }
+                break;
+
+            case GATT_UUID_PNP_ID:
+                if (p_data->att_value.len == DIS_PNP_ID_SIZE)
+                {
+                    p_clcb->dis_value.attr_mask |= DIS_ATTR_PNP_ID_BIT;
+                    STREAM_TO_UINT8 (p_clcb->dis_value.pnp_id.vendor_id_src, pp);
+                    STREAM_TO_UINT16 (p_clcb->dis_value.pnp_id.vendor_id, pp);
+                    STREAM_TO_UINT16 (p_clcb->dis_value.pnp_id.product_id, pp);
+                    STREAM_TO_UINT16 (p_clcb->dis_value.pnp_id.product_version, pp);
+                }
+                break;
+
+            case GATT_UUID_MODEL_NUMBER_STR:
+            case GATT_UUID_SERIAL_NUMBER_STR:
+            case GATT_UUID_FW_VERSION_STR:
+            case GATT_UUID_HW_VERSION_STR:
+            case GATT_UUID_SW_VERSION_STR:
+            case GATT_UUID_MANU_NAME:
+            case GATT_UUID_IEEE_DATA:
+                p_str = p_clcb->dis_value.data_string[read_type - GATT_UUID_MODEL_NUMBER_STR];
+                osi_free(p_str);
+                p_str = (uint8_t *)osi_malloc(p_data->att_value.len + 1);
+                p_clcb->dis_value.attr_mask |= dis_uuid_to_attr(read_type);
+                memcpy(p_str, p_data->att_value.value, p_data->att_value.len);
+                p_str[p_data->att_value.len] = 0;
+                p_clcb->dis_value.data_string[read_type - GATT_UUID_MODEL_NUMBER_STR] = p_str;
+                break;
+
+            default:
+                    break;
+
+                break;
+        }/* end switch */
+    }/* end if */
+
+    dis_cb.dis_read_uuid_idx ++;
+
+    dis_gatt_c_read_dis_req(conn_id);
+}
+
+/*******************************************************************************
+**
+** Function         DIS_SrInit
+**
+** Description      Initialize the Device Information Service Server.
+**
+*******************************************************************************/
+tDIS_STATUS DIS_SrInit (tDIS_ATTR_MASK dis_attr_mask)
+{
+    tGATT_STATUS      status;
+
+    if (dis_cb.enabled) {
+        GATT_TRACE_ERROR("DIS already initalized");
+        return DIS_SUCCESS;
+    }
+
+    memset(&dis_cb, 0, sizeof(tDIS_CB));
+
+    btgatt_db_element_t service[DIS_MAX_ATTR_NUM] = { };
+
+    bt_uuid_t svc_uuid;
+    uuid_128_from_16(&svc_uuid, UUID_SERVCLASS_DEVICE_INFO);
+    service[0].type = BTGATT_DB_PRIMARY_SERVICE;
+    service[0].uuid = svc_uuid;
+
+    for(int i=0; dis_attr_mask != 0 && i < DIS_MAX_CHAR_NUM; i++) {
+        dis_cb.dis_attr[i].uuid = dis_attr_uuid[i];
+
+        bt_uuid_t char_uuid;
+        uuid_128_from_16(&char_uuid, dis_cb.dis_attr[i].uuid);
+        /* index 0 is service, so characteristics start from 1 */
+        service[i+1].type = BTGATT_DB_CHARACTERISTIC;
+        service[i+1].uuid = char_uuid;
+        service[i+1].properties = GATT_CHAR_PROP_BIT_READ;
+        service[i+1].permissions = GATT_PERM_READ;
+
+        dis_attr_mask >>= 1;
+    }
+
+    /* Add a GAP service */
+    status = GATTS_AddService(srvc_eng_cb.gatt_if, service, sizeof(service)/sizeof(btgatt_db_element_t));
+    if (status != GATT_SERVICE_STARTED) {
+        GATT_TRACE_ERROR("Can not create service, DIS_Init failed!");
+        return GATT_ERROR;
+    }
+
+    dis_cb.service_handle = service[0].attribute_handle;
+    dis_cb.max_handle = dis_cb.service_handle + DIS_MAX_ATTR_NUM;
+
+    for (int i = 0; i < DIS_MAX_CHAR_NUM; i++) {
+        dis_cb.dis_attr[i].handle = service[i+1].attribute_handle;
+
+        GATT_TRACE_DEBUG ("%s:  handle of new attribute 0x%04 = x%d", __func__,
+            dis_cb.dis_attr[i].uuid, dis_cb.dis_attr[i].handle);
+    }
+
+    dis_cb.enabled = true;
+    return (tDIS_STATUS) status;
+}
+/*******************************************************************************
+**
+** Function         DIS_SrUpdate
+**
+** Description      Update the DIS server attribute values
+**
+*******************************************************************************/
+tDIS_STATUS DIS_SrUpdate(tDIS_ATTR_BIT dis_attr_bit, tDIS_ATTR *p_info)
+{
+    uint8_t         i = 1;
+    tDIS_STATUS     st = DIS_SUCCESS;
+
+    if (dis_attr_bit & DIS_ATTR_SYS_ID_BIT)
+    {
+        dis_cb.dis_value.system_id = p_info->system_id;
+    }
+    else if (dis_attr_bit & DIS_ATTR_PNP_ID_BIT)
+    {
+        dis_cb.dis_value.pnp_id.vendor_id         = p_info->pnp_id.vendor_id;
+        dis_cb.dis_value.pnp_id.vendor_id_src     = p_info->pnp_id.vendor_id_src;
+        dis_cb.dis_value.pnp_id.product_id        = p_info->pnp_id.product_id;
+        dis_cb.dis_value.pnp_id.product_version   = p_info->pnp_id.product_version;
+    }
+    else
+    {
+        st = DIS_ILLEGAL_PARAM;
+
+        while (dis_attr_bit && i < (DIS_MAX_CHAR_NUM -1 ))
+        {
+            if (dis_attr_bit & (uint16_t)(1 << i))
+            {
+                osi_free(dis_cb.dis_value.data_string[i - 1]);
+/* coverity[OVERRUN-STATIC] False-positive : when i = 8, (1 << i) == DIS_ATTR_PNP_ID_BIT, and it will never come down here
+CID 49902: Out-of-bounds read (OVERRUN_STATIC)
+Overrunning static array "dis_cb.dis_value.data_string", with 7 elements, at position 7 with index variable "i".
+*/
+                dis_cb.dis_value.data_string[i - 1] = (uint8_t *)osi_malloc(p_info->data_str.len + 1);
+                memcpy(dis_cb.dis_value.data_string[i - 1], p_info->data_str.p_data, p_info->data_str.len);
+                dis_cb.dis_value.data_string[i - 1][p_info->data_str.len] = 0; /* make sure null terminate */
+                st = DIS_SUCCESS;
+
+                break;
+            }
+            i ++;
+        }
+    }
+    return st;
+}
+/*******************************************************************************
+**
+** Function         DIS_ReadDISInfo
+**
+** Description      Read remote device DIS information.
+**
+** Returns          void
+**
+*******************************************************************************/
+bool    DIS_ReadDISInfo(BD_ADDR peer_bda, tDIS_READ_CBACK *p_cback, tDIS_ATTR_MASK mask)
+{
+    uint16_t           conn_id;
+
+    /* Initialize the DIS client if it hasn't been initialized already. */
+    srvc_eng_init();
+
+    /* For now we only handle one at a time */
+    if (dis_cb.dis_read_uuid_idx != 0xff)
+        return(false);
+
+    if (p_cback == NULL)
+        return(false);
+
+    dis_cb.p_read_dis_cback = p_cback;
+    /* Mark currently active operation */
+    dis_cb.dis_read_uuid_idx = 0;
+
+    dis_cb.request_mask = mask;
+
+    GATT_TRACE_EVENT ("DIS_ReadDISInfo() - BDA: %08x%04x  cl_read_uuid: 0x%04x",
+                      (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3],
+                      (peer_bda[4]<<8)+peer_bda[5], dis_attr_uuid[dis_cb.dis_read_uuid_idx]);
+
+    GATT_GetConnIdIfConnected(srvc_eng_cb.gatt_if, peer_bda, &conn_id, BT_TRANSPORT_LE);
+
+    /* need to enhance it as multiple service is needed */
+    srvc_eng_request_channel(peer_bda, SRVC_ID_DIS);
+
+    if (conn_id == GATT_INVALID_CONN_ID)
+    {
+        return GATT_Connect(srvc_eng_cb.gatt_if, peer_bda, true, BT_TRANSPORT_LE, false);
+    }
+
+    return dis_gatt_c_read_dis_req(conn_id);
+
+}
+#endif  /* BLE_INCLUDED */
+
diff --git a/bt/stack/srvc/srvc_dis_int.h b/bt/stack/srvc/srvc_dis_int.h
new file mode 100644
index 0000000..d3be95e
--- /dev/null
+++ b/bt/stack/srvc/srvc_dis_int.h
@@ -0,0 +1,73 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-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.
+ *
+ ******************************************************************************/
+
+#ifndef SRVC_DIS_INT_H
+#define SRVC_DIS_INT_H
+
+#include "bt_target.h"
+#include "gatt_api.h"
+#include "srvc_api.h"
+#include "srvc_eng_int.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DIS_MAX_CHAR_NUM            9
+
+typedef struct
+{
+    uint16_t    uuid;
+    uint16_t    handle;
+}tDIS_DB_ENTRY;
+
+#define DIS_SYSTEM_ID_SIZE      8
+#define DIS_PNP_ID_SIZE         7
+
+typedef struct
+{
+    tDIS_DB_ENTRY           dis_attr[DIS_MAX_CHAR_NUM];
+    tDIS_VALUE              dis_value;
+
+    tDIS_READ_CBACK         *p_read_dis_cback;
+
+    uint16_t                service_handle;
+    uint16_t                max_handle;
+
+    bool                    enabled;
+
+    uint8_t                 dis_read_uuid_idx;
+
+    tDIS_ATTR_MASK          request_mask;
+}tDIS_CB;
+
+/* Global GATT data */
+extern tDIS_CB dis_cb;
+
+extern bool    dis_valid_handle_range(uint16_t handle);
+extern uint8_t dis_read_attr_value (uint8_t clcb_idx, uint16_t handle, tGATT_VALUE *p_value,
+                           bool    is_long, tGATT_STATUS *p_status);
+extern uint8_t dis_write_attr_value(tGATT_WRITE_REQ * p_data, tGATT_STATUS *p_status);
+
+extern void dis_c_cmpl_cback (tSRVC_CLCB *p_clcb, tGATTC_OPTYPE op,
+                                    tGATT_STATUS status, tGATT_CL_COMPLETE *p_data);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/bt/stack/srvc/srvc_eng.cc b/bt/stack/srvc/srvc_eng.cc
new file mode 100644
index 0000000..a2be5f7
--- /dev/null
+++ b/bt/stack/srvc/srvc_eng.cc
@@ -0,0 +1,478 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-2013 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.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "gatt_api.h"
+#include "gatt_int.h"
+#include "osi/include/osi.h"
+#include "srvc_eng_int.h"
+
+#if (BLE_INCLUDED == TRUE)
+
+#include "srvc_dis_int.h"
+#include "srvc_battery_int.h"
+
+static void srvc_eng_s_request_cback (uint16_t conn_id, uint32_t trans_id, uint8_t op_code, tGATTS_DATA *p_data);
+static void srvc_eng_connect_cback (UNUSED_ATTR tGATT_IF gatt_if, BD_ADDR bda,
+				    uint16_t conn_id, bool    connected,
+                                          tGATT_DISCONN_REASON reason, tBT_TRANSPORT transport);
+static void srvc_eng_c_cmpl_cback (uint16_t conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data);
+
+static tGATT_CBACK srvc_gatt_cback =
+{
+    srvc_eng_connect_cback,
+    srvc_eng_c_cmpl_cback,
+    NULL,
+    NULL,
+    srvc_eng_s_request_cback,
+    NULL,
+    NULL
+} ;
+/* type for action functions */
+typedef void (*tSRVC_ENG_C_CMPL_ACTION)(tSRVC_CLCB *p_clcb, tGATTC_OPTYPE op,
+                                    tGATT_STATUS status, tGATT_CL_COMPLETE *p_data);
+
+const tSRVC_ENG_C_CMPL_ACTION srvc_eng_c_cmpl_act[SRVC_ID_MAX] =
+{
+    dis_c_cmpl_cback,
+};
+
+tSRVC_ENG_CB srvc_eng_cb;
+
+/*******************************************************************************
+**
+** Function         srvc_eng_find_conn_id_by_bd_addr
+**
+** Description      The function searches all LCB with macthing bd address
+**
+** Returns          total number of clcb found.
+**
+*******************************************************************************/
+uint16_t srvc_eng_find_conn_id_by_bd_addr(BD_ADDR bda)
+{
+    uint8_t i_clcb;
+    tSRVC_CLCB    *p_clcb = NULL;
+
+    for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++)
+    {
+        if (p_clcb->in_use && p_clcb->connected && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN))
+        {
+            return p_clcb->conn_id;
+        }
+    }
+
+    return GATT_INVALID_CONN_ID;
+}
+
+/*******************************************************************************
+**
+** Function         srvc_eng_find_clcb_by_bd_addr
+**
+** Description      The function searches all LCBs with macthing bd address.
+**
+** Returns          Pointer to the found link conenction control block.
+**
+*******************************************************************************/
+tSRVC_CLCB *srvc_eng_find_clcb_by_bd_addr(BD_ADDR bda)
+{
+    uint8_t i_clcb;
+    tSRVC_CLCB    *p_clcb = NULL;
+
+    for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++)
+    {
+        if (p_clcb->in_use && p_clcb->connected && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN))
+        {
+            return p_clcb;
+        }
+    }
+
+    return NULL;
+}
+/*******************************************************************************
+**
+** Function         srvc_eng_find_clcb_by_conn_id
+**
+** Description      The function searches all LCBs with macthing connection ID.
+**
+** Returns          Pointer to the found link conenction control block.
+**
+*******************************************************************************/
+tSRVC_CLCB *srvc_eng_find_clcb_by_conn_id(uint16_t conn_id)
+{
+    uint8_t i_clcb;
+    tSRVC_CLCB    *p_clcb = NULL;
+
+    for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++)
+    {
+        if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id)
+        {
+            return p_clcb;
+        }
+    }
+
+    return NULL;
+}
+/*******************************************************************************
+**
+** Function         srvc_eng_find_clcb_by_conn_id
+**
+** Description      The function searches all LCBs with macthing connection ID.
+**
+** Returns          Pointer to the found link conenction control block.
+**
+*******************************************************************************/
+uint8_t srvc_eng_find_clcb_idx_by_conn_id(uint16_t conn_id)
+{
+    uint8_t i_clcb;
+    tSRVC_CLCB    *p_clcb = NULL;
+
+    for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++)
+    {
+        if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id)
+        {
+            return i_clcb;
+        }
+    }
+
+    return SRVC_MAX_APPS;
+}
+/*******************************************************************************
+**
+** Function         srvc_eng_clcb_alloc
+**
+** Description      The function allocates a GATT profile  connection link control block
+**
+** Returns           NULL if not found. Otherwise pointer to the connection link block.
+**
+*******************************************************************************/
+tSRVC_CLCB *srvc_eng_clcb_alloc (uint16_t conn_id, BD_ADDR bda)
+{
+    uint8_t                 i_clcb = 0;
+    tSRVC_CLCB      *p_clcb = NULL;
+
+    for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++)
+    {
+        if (!p_clcb->in_use)
+        {
+            p_clcb->in_use      = true;
+            p_clcb->conn_id     = conn_id;
+            p_clcb->connected   = true;
+            memcpy (p_clcb->bda, bda, BD_ADDR_LEN);
+            break;
+        }
+    }
+    return p_clcb;
+}
+/*******************************************************************************
+**
+** Function         srvc_eng_clcb_dealloc
+**
+** Description      The function deallocates a GATT profile  connection link control block
+**
+** Returns           True the deallocation is successful
+**
+*******************************************************************************/
+bool    srvc_eng_clcb_dealloc (uint16_t conn_id)
+{
+    uint8_t                 i_clcb = 0;
+    tSRVC_CLCB      *p_clcb = NULL;
+
+    for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++)
+    {
+        if (p_clcb->in_use && p_clcb->connected && (p_clcb->conn_id == conn_id))
+        {
+            unsigned j;
+            for (j = 0; j < ARRAY_SIZE(p_clcb->dis_value.data_string); j++)
+                osi_free(p_clcb->dis_value.data_string[j]);
+
+            memset(p_clcb, 0, sizeof(tSRVC_CLCB));
+            return true;
+        }
+    }
+    return false;
+}
+/*******************************************************************************
+**   Service Engine Server Attributes Database Read/Read Blob Request process
+*******************************************************************************/
+uint8_t srvc_eng_process_read_req (uint8_t clcb_idx, tGATT_READ_REQ *p_data, tGATTS_RSP *p_rsp, tGATT_STATUS *p_status)
+{
+    tGATT_STATUS    status = GATT_NOT_FOUND;
+    uint8_t     act = SRVC_ACT_RSP;
+
+    if (p_data->is_long)
+        p_rsp->attr_value.offset = p_data->offset;
+
+    p_rsp->attr_value.handle = p_data->handle;
+
+    if (dis_valid_handle_range(p_data->handle))
+        act = dis_read_attr_value(clcb_idx, p_data->handle, &p_rsp->attr_value, p_data->is_long, p_status);
+
+    else if (battery_valid_handle_range(p_data->handle))
+        act = battery_s_read_attr_value(clcb_idx, p_data->handle, &p_rsp->attr_value, p_data->is_long, p_status);
+
+    else
+        *p_status = status;
+    return act;
+}
+/*******************************************************************************
+**   Service Engine Server Attributes Database write Request process
+*******************************************************************************/
+uint8_t srvc_eng_process_write_req (uint8_t clcb_idx, tGATT_WRITE_REQ *p_data,
+                                    UNUSED_ATTR tGATTS_RSP *p_rsp, tGATT_STATUS *p_status)
+{
+    uint8_t     act = SRVC_ACT_RSP;
+
+    if (dis_valid_handle_range(p_data->handle))
+    {
+        act = dis_write_attr_value(p_data, p_status);
+    }
+    else if (battery_valid_handle_range(p_data->handle))
+    {
+        act = battery_s_write_attr_value(clcb_idx, p_data, p_status);
+    }
+    else
+        *p_status = GATT_NOT_FOUND;
+
+    return act;
+}
+
+/*******************************************************************************
+**
+** Function         srvc_eng_s_request_cback
+**
+** Description      GATT DIS attribute access request callback.
+**
+** Returns          void.
+**
+*******************************************************************************/
+static void srvc_eng_s_request_cback (uint16_t conn_id, uint32_t trans_id, tGATTS_REQ_TYPE type,
+                                        tGATTS_DATA *p_data)
+{
+    uint8_t     status = GATT_INVALID_PDU;
+    tGATTS_RSP  rsp_msg ;
+    uint8_t     act = SRVC_ACT_IGNORE;
+    uint8_t clcb_idx = srvc_eng_find_clcb_idx_by_conn_id(conn_id);
+
+    GATT_TRACE_EVENT("srvc_eng_s_request_cback : recv type (0x%02x)", type);
+
+    memset(&rsp_msg, 0, sizeof(tGATTS_RSP));
+
+    srvc_eng_cb.clcb[clcb_idx].trans_id = trans_id;
+
+    switch (type)
+    {
+        case GATTS_REQ_TYPE_READ_CHARACTERISTIC:
+        case GATTS_REQ_TYPE_READ_DESCRIPTOR:
+            act = srvc_eng_process_read_req(clcb_idx, &p_data->read_req, &rsp_msg, &status);
+            break;
+
+        case GATTS_REQ_TYPE_WRITE_CHARACTERISTIC:
+        case GATTS_REQ_TYPE_WRITE_DESCRIPTOR:
+            act = srvc_eng_process_write_req(clcb_idx, &p_data->write_req, &rsp_msg, &status);
+            if (!p_data->write_req.need_rsp)
+                act = SRVC_ACT_IGNORE;
+            break;
+
+        case GATTS_REQ_TYPE_WRITE_EXEC:
+            GATT_TRACE_EVENT("Ignore GATT_REQ_EXEC_WRITE/WRITE_CMD" );
+            break;
+
+        case GATTS_REQ_TYPE_MTU:
+            GATT_TRACE_EVENT("Get MTU exchange new mtu size: %d", p_data->mtu);
+            break;
+
+        default:
+            GATT_TRACE_EVENT("Unknown/unexpected LE GAP ATT request: 0x%02x", type);
+            break;
+    }
+
+    srvc_eng_cb.clcb[clcb_idx].trans_id = 0;
+
+    if (act == SRVC_ACT_RSP)
+        GATTS_SendRsp (conn_id, trans_id, status, &rsp_msg);
+
+
+}
+
+
+/*******************************************************************************
+**
+** Function         srvc_eng_c_cmpl_cback
+**
+** Description      Client operation complete callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void srvc_eng_c_cmpl_cback (uint16_t conn_id, tGATTC_OPTYPE op, tGATT_STATUS status,
+                                   tGATT_CL_COMPLETE *p_data)
+{
+    tSRVC_CLCB   *p_clcb = srvc_eng_find_clcb_by_conn_id(conn_id);
+
+    GATT_TRACE_EVENT ("srvc_eng_c_cmpl_cback() - op_code: 0x%02x  status: 0x%02x ", op, status);
+
+    if (p_clcb == NULL)
+    {
+        GATT_TRACE_ERROR("srvc_eng_c_cmpl_cback received for unknown connection");
+        return;
+    }
+
+    if (p_clcb->cur_srvc_id != SRVC_ID_NONE &&
+        p_clcb->cur_srvc_id <= SRVC_ID_MAX)
+        srvc_eng_c_cmpl_act[p_clcb->cur_srvc_id - 1](p_clcb, op, status, p_data);
+}
+
+
+/*******************************************************************************
+**
+** Function         srvc_eng_connect_cback
+**
+** Description      Gatt profile connection callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+static void srvc_eng_connect_cback (UNUSED_ATTR tGATT_IF gatt_if, BD_ADDR bda,
+                                    uint16_t conn_id,
+                                    bool connected, tGATT_DISCONN_REASON reason,
+                                    UNUSED_ATTR tBT_TRANSPORT transport)
+{
+    GATT_TRACE_EVENT ("srvc_eng_connect_cback: from %08x%04x connected:%d conn_id=%d reason = 0x%04x",
+                       (bda[0]<<24)+(bda[1]<<16)+(bda[2]<<8)+bda[3],
+                       (bda[4]<<8)+bda[5], connected, conn_id, reason);
+
+    if (connected)
+    {
+        if (srvc_eng_clcb_alloc(conn_id, bda) == NULL)
+        {
+            GATT_TRACE_ERROR ("srvc_eng_connect_cback: no_resource");
+            return;
+        }
+    }
+    else
+    {
+        srvc_eng_clcb_dealloc(conn_id);
+    }
+
+}
+/*******************************************************************************
+**
+** Function         srvc_eng_c_cmpl_cback
+**
+** Description      Client operation complete callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+bool    srvc_eng_request_channel (BD_ADDR remote_bda, uint8_t srvc_id )
+{
+    bool    set = true;
+    tSRVC_CLCB  *p_clcb = srvc_eng_find_clcb_by_bd_addr(remote_bda);
+
+    if (p_clcb == NULL)
+        p_clcb = srvc_eng_clcb_alloc(0, remote_bda);
+
+    if (p_clcb && p_clcb->cur_srvc_id == SRVC_ID_NONE)
+        p_clcb->cur_srvc_id = srvc_id;
+    else
+        set = false;
+
+    return set;
+}
+/*******************************************************************************
+**
+** Function         srvc_eng_release_channel
+**
+** Description      Client operation complete callback.
+**
+** Returns          void
+**
+*******************************************************************************/
+void srvc_eng_release_channel (uint16_t conn_id)
+{
+    tSRVC_CLCB *p_clcb =  srvc_eng_find_clcb_by_conn_id(conn_id);
+
+    if (p_clcb == NULL)
+    {
+        GATT_TRACE_ERROR("%s: invalid connection id %d", __func__, conn_id);
+        return;
+    }
+
+    p_clcb->cur_srvc_id = SRVC_ID_NONE;
+
+    /* check pending request */
+    GATT_Disconnect(p_clcb->conn_id);
+}
+/*******************************************************************************
+**
+** Function         srvc_eng_init
+**
+** Description      Initializa the GATT Service engine.
+**
+*******************************************************************************/
+tGATT_STATUS srvc_eng_init (void)
+{
+    tBT_UUID          app_uuid = {LEN_UUID_16, {UUID_SERVCLASS_DEVICE_INFO}};
+
+    if (srvc_eng_cb.enabled)
+    {
+        GATT_TRACE_ERROR("DIS already initalized");
+    }
+    else
+    {
+        memset(&srvc_eng_cb, 0, sizeof(tSRVC_ENG_CB));
+
+        /* Create a GATT profile service */
+        srvc_eng_cb.gatt_if = GATT_Register(&app_uuid, &srvc_gatt_cback);
+        GATT_StartIf(srvc_eng_cb.gatt_if);
+
+        GATT_TRACE_DEBUG ("Srvc_Init:  gatt_if=%d  ", srvc_eng_cb.gatt_if);
+
+        srvc_eng_cb.enabled = true;
+        dis_cb.dis_read_uuid_idx = 0xff;
+    }
+    return GATT_SUCCESS;
+}
+
+void srvc_sr_rsp(uint8_t clcb_idx, tGATT_STATUS st, tGATTS_RSP *p_rsp)
+{
+    if (srvc_eng_cb.clcb[clcb_idx].trans_id != 0)
+    {
+        GATTS_SendRsp(srvc_eng_cb.clcb[clcb_idx].conn_id,
+                  srvc_eng_cb.clcb[clcb_idx].trans_id,
+                  st,
+                  p_rsp);
+
+        srvc_eng_cb.clcb[clcb_idx].trans_id = 0;
+    }
+}
+void srvc_sr_notify(BD_ADDR remote_bda, uint16_t handle, uint16_t len, uint8_t *p_value)
+{
+    uint16_t conn_id = srvc_eng_find_conn_id_by_bd_addr(remote_bda);
+
+    if (conn_id != GATT_INVALID_CONN_ID)
+    {
+        GATTS_HandleValueNotification( conn_id, handle, len, p_value);
+    }
+}
+
+#endif
+
+
+
diff --git a/bt/stack/srvc/srvc_eng_int.h b/bt/stack/srvc/srvc_eng_int.h
new file mode 100644
index 0000000..c5076da
--- /dev/null
+++ b/bt/stack/srvc/srvc_eng_int.h
@@ -0,0 +1,80 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 1999-2013 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.
+ *
+ ******************************************************************************/
+
+#ifndef SRVC_ENG_INT_H
+#define SRVC_ENG_INT_H
+
+#include "bt_target.h"
+#include "gatt_api.h"
+#include "srvc_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SRVC_MAX_APPS                  GATT_CL_MAX_LCB
+
+#define SRVC_ID_NONE            0
+#define SRVC_ID_DIS             1
+#define SRVC_ID_MAX             SRVC_ID_DIS
+
+#define SRVC_ACT_IGNORE     0
+#define SRVC_ACT_RSP        1
+#define SRVC_ACT_PENDING    2
+
+typedef struct
+{
+    bool            in_use;
+    uint16_t        conn_id;
+    bool            connected;
+    BD_ADDR         bda;
+    uint32_t        trans_id;
+    uint8_t         cur_srvc_id;
+
+    tDIS_VALUE      dis_value;
+
+}tSRVC_CLCB;
+
+
+/* service engine control block */
+typedef struct
+{
+    tSRVC_CLCB              clcb[SRVC_MAX_APPS]; /* connection link*/
+    tGATT_IF                gatt_if;
+    bool                    enabled;
+
+}tSRVC_ENG_CB;
+
+/* Global GATT data */
+extern tSRVC_ENG_CB srvc_eng_cb;
+
+extern tSRVC_CLCB *srvc_eng_find_clcb_by_conn_id(uint16_t conn_id);
+extern tSRVC_CLCB *srvc_eng_find_clcb_by_bd_addr(BD_ADDR bda);
+extern uint16_t srvc_eng_find_conn_id_by_bd_addr(BD_ADDR bda);
+
+
+extern void srvc_eng_release_channel (uint16_t conn_id) ;
+extern bool    srvc_eng_request_channel (BD_ADDR remote_bda, uint8_t srvc_id );
+extern void srvc_sr_rsp(uint8_t clcb_idx, tGATT_STATUS st, tGATTS_RSP *p_rsp);
+extern void srvc_sr_notify(BD_ADDR remote_bda, uint16_t handle, uint16_t len, uint8_t *p_value);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/bt/stack/test/ble_advertiser_test.cc b/bt/stack/test/ble_advertiser_test.cc
new file mode 100644
index 0000000..d67fda9
--- /dev/null
+++ b/bt/stack/test/ble_advertiser_test.cc
@@ -0,0 +1,322 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "device/include/controller.h"
+#include "stack/btm/ble_advertiser_hci_interface.h"
+#include "stack/include/ble_advertiser.h"
+
+using ::testing::_;
+using ::testing::Args;
+using ::testing::ElementsAreArray;
+using ::testing::Exactly;
+using ::testing::IsEmpty;
+using ::testing::SaveArg;
+using status_cb = BleAdvertiserHciInterface::status_cb;
+
+const int num_adv_instances = 16;
+
+/* Below are methods that must be implemented if we don't want to compile the
+ * whole stack. They will be removed, or changed into mocks one by one in the
+ * future, as the refactoring progresses */
+bool BTM_BleLocalPrivacyEnabled() { return true; }
+uint16_t BTM_ReadConnectability(uint16_t *p_window, uint16_t *p_interval) {
+  return true;
+}
+uint16_t BTM_ReadDiscoverability(uint16_t *p_window, uint16_t *p_interval) {
+  return true;
+}
+bool SMP_Encrypt(uint8_t *key, uint8_t key_len, uint8_t *plain_text,
+                 uint8_t pt_len, tSMP_ENC *p_out) {
+  return true;
+}
+void BTM_GetDeviceIDRoot(BT_OCTET16 irk) {}
+tBTM_STATUS btm_ble_set_connectability(uint16_t combined_mode) { return 0; }
+void btm_ble_update_dmt_flag_bits(uint8_t *flag_value,
+                                  const uint16_t connect_mode,
+                                  const uint16_t disc_mode) {}
+void btm_acl_update_conn_addr(uint8_t conn_handle, BD_ADDR address) {}
+
+void btm_gen_resolvable_private_addr(void *p_cmd_cplt_cback) {
+  // TODO(jpawlowski): should call p_cmd_cplt_cback();
+}
+void alarm_set_on_queue(alarm_t *alarm, period_ms_t interval_ms,
+                        alarm_callback_t cb, void *data, fixed_queue_t *queue) {
+}
+void alarm_cancel(alarm_t *alarm) {}
+alarm_t *alarm_new_periodic(const char *name) { return nullptr; }
+alarm_t *alarm_new(const char *name) { return nullptr; }
+void alarm_free(alarm_t *alarm) {}
+const controller_t *controller_get_interface() { return nullptr; }
+fixed_queue_t *btu_general_alarm_queue = nullptr;
+
+namespace {
+
+class AdvertiserHciMock : public BleAdvertiserHciInterface {
+ public:
+  AdvertiserHciMock() = default;
+  ~AdvertiserHciMock() override = default;
+
+  MOCK_METHOD1(ReadInstanceCount, void(base::Callback<void(uint8_t /* inst_cnt*/)>));
+  MOCK_METHOD4(SetAdvertisingData,
+               void(uint8_t, uint8_t *, uint8_t, status_cb));
+  MOCK_METHOD4(SetScanResponseData,
+               void(uint8_t, uint8_t *, uint8_t, status_cb));
+  MOCK_METHOD3(SetRandomAddress, void(BD_ADDR, uint8_t, status_cb));
+  MOCK_METHOD3(Enable, void(uint8_t, uint8_t, status_cb));
+
+  MOCK_METHOD6(SetParameters1,
+               void(uint8_t, uint8_t, uint8_t, uint8_t, BD_ADDR, uint8_t));
+  MOCK_METHOD6(SetParameters2,
+               void(BD_ADDR, uint8_t, uint8_t, uint8_t, uint8_t, status_cb));
+
+  void SetParameters(uint8_t adv_int_min, uint8_t adv_int_max,
+                     uint8_t advertising_type, uint8_t own_address_type,
+                     BD_ADDR own_address, uint8_t direct_address_type,
+                     BD_ADDR direct_address, uint8_t channel_map,
+                     uint8_t filter_policy, uint8_t instance, uint8_t tx_power,
+                     status_cb cmd_complete) override {
+    SetParameters1(adv_int_min, adv_int_max, advertising_type, own_address_type,
+                   own_address, direct_address_type);
+    SetParameters2(direct_address, channel_map, filter_policy, instance,
+                   tx_power, cmd_complete);
+  };
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AdvertiserHciMock);
+};
+
+}  // namespace
+
+class BleAdvertisingManagerTest : public testing::Test {
+ protected:
+  int reg_inst_id = -1;
+  int reg_status = -1;
+  int set_params_status = -1;
+  int set_data_status = -1;
+  int enable_status = -1;
+  std::unique_ptr<AdvertiserHciMock> hci_mock;
+
+  virtual void SetUp() {
+    hci_mock.reset(new AdvertiserHciMock());
+
+    base::Callback<void(uint8_t)> inst_cnt_Cb;
+    EXPECT_CALL(*hci_mock, ReadInstanceCount(_))
+      .Times(Exactly(1))
+      .WillOnce(SaveArg<0>(&inst_cnt_Cb));
+
+    BleAdvertisingManager::Initialize(hci_mock.get());
+
+    // we are a truly gracious fake controller, let the command succeed!
+    inst_cnt_Cb.Run(num_adv_instances);
+    ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+  }
+
+  virtual void TearDown() {
+    BleAdvertisingManager::CleanUp();
+    hci_mock.reset();
+  }
+
+ public:
+  void RegistrationCb(uint8_t inst_id, uint8_t status) {
+    reg_inst_id = inst_id;
+    reg_status = status;
+  }
+
+  void SetParametersCb(uint8_t status) { set_params_status = status; }
+  void SetDataCb(uint8_t status) { set_data_status = status; }
+  void EnableCb(uint8_t status) { enable_status = status; }
+};
+
+TEST_F(BleAdvertisingManagerTest, test_registration) {
+  for (int i = 1; i < num_adv_instances; i++) {
+    BleAdvertisingManager::Get()->RegisterAdvertiser(base::Bind(
+        &BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this)));
+    EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status);
+    EXPECT_EQ(i, reg_inst_id);
+  }
+
+  // This call should return an error - no more advertisers left.
+  BleAdvertisingManager::Get()->RegisterAdvertiser(base::Bind(
+      &BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this)));
+  EXPECT_EQ(BTM_BLE_MULTI_ADV_FAILURE, reg_status);
+  // Don't bother checking inst_id, it doesn't matter
+
+  // This will currently trigger a mock message about a call to Enable(). This
+  // should be fixed in the future- we shouldn't disable non-enabled scan.
+  BleAdvertisingManager::Get()->Unregister(5);
+
+  // One advertiser was freed, so should be able to register one now
+  BleAdvertisingManager::Get()->RegisterAdvertiser(base::Bind(
+      &BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this)));
+  EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status);
+  EXPECT_EQ(5, reg_inst_id);
+}
+
+/* This test verifies that the only flow that is currently used on Android, is
+ * working correctly. This flow is : register, set parameters, set data, enable,
+ * ... (advertise) ..., unregister*/
+TEST_F(BleAdvertisingManagerTest, test_android_flow) {
+  BleAdvertisingManager::Get()->RegisterAdvertiser(base::Bind(
+      &BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this)));
+  EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status);
+  int advertiser_id = reg_inst_id;
+
+  status_cb set_params_cb;
+  tBTM_BLE_ADV_PARAMS params;
+  EXPECT_CALL(*hci_mock, SetParameters1(_, _, _, _, _, _)).Times(1);
+  EXPECT_CALL(*hci_mock, SetParameters2(_, _, _, advertiser_id, _, _))
+      .Times(1)
+      .WillOnce(SaveArg<5>(&set_params_cb));
+  BleAdvertisingManager::Get()->SetParameters(
+      advertiser_id, &params,
+      base::Bind(&BleAdvertisingManagerTest::SetParametersCb,
+                 base::Unretained(this)));
+
+  // we are a truly gracious fake controller, let the command succeed!
+  set_params_cb.Run(0);
+  EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_params_status);
+  ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+  status_cb set_data_cb;
+  EXPECT_CALL(*hci_mock, SetAdvertisingData(_, _, advertiser_id, _))
+      .Times(1)
+      .WillOnce(SaveArg<3>(&set_data_cb));
+  BleAdvertisingManager::Get()->SetData(
+      advertiser_id, false, std::vector<uint8_t>(),
+      base::Bind(&BleAdvertisingManagerTest::SetDataCb,
+                 base::Unretained(this)));
+  set_data_cb.Run(0);
+  EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status);
+  ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+  status_cb enable_cb;
+  EXPECT_CALL(*hci_mock, Enable(0x01 /* enable */, advertiser_id, _))
+      .Times(1)
+      .WillOnce(SaveArg<2>(&enable_cb));
+  BleAdvertisingManager::Get()->Enable(
+      advertiser_id, true,
+      base::Bind(&BleAdvertisingManagerTest::EnableCb, base::Unretained(this)),
+      0, base::Callback<void(uint8_t)>());
+  enable_cb.Run(0);
+  EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, enable_status);
+  ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+  /* fake controller should be advertising */
+
+  EXPECT_CALL(*hci_mock, Enable(0x00 /* disable */, advertiser_id, _))
+      .Times(1)
+      .WillOnce(SaveArg<2>(&enable_cb));
+  BleAdvertisingManager::Get()->Unregister(advertiser_id);
+  enable_cb.Run(0);
+  EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, enable_status);
+  ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+}
+
+/* This test verifies that when advertising data is set, tx power and flags will
+ * be properly filled. */
+TEST_F(BleAdvertisingManagerTest, test_adv_data_filling) {
+  BleAdvertisingManager::Get()->RegisterAdvertiser(base::Bind(
+      &BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this)));
+  EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status);
+  int advertiser_id = reg_inst_id;
+
+  status_cb set_params_cb;
+  tBTM_BLE_ADV_PARAMS params;
+  params.adv_type = BTM_BLE_CONNECT_EVT;
+  params.tx_power = -15;
+  EXPECT_CALL(*hci_mock, SetParameters1(_, _, _, _, _, _)).Times(1);
+  EXPECT_CALL(*hci_mock, SetParameters2(_, _, _, advertiser_id,
+                                        (uint8_t)params.tx_power, _))
+      .Times(1)
+      .WillOnce(SaveArg<5>(&set_params_cb));
+  BleAdvertisingManager::Get()->SetParameters(
+      advertiser_id, &params,
+      base::Bind(&BleAdvertisingManagerTest::SetParametersCb,
+                 base::Unretained(this)));
+
+  // let the set parameters command succeed!
+  set_params_cb.Run(0);
+  EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_params_status);
+  ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+  status_cb set_data_cb;
+  /* verify that flags will be added, and tx power filled, if call to SetData
+   * contained only tx power, and the advertisement is connectable */
+  uint8_t expected_adv_data[] = {0x02 /* len */,         0x01 /* flags */,
+                                 0x02 /* flags value */, 0x02 /* len */,
+                                 0x0A /* tx_power */,    params.tx_power};
+  EXPECT_CALL(*hci_mock, SetAdvertisingData(_, _, advertiser_id, _))
+      .With(Args<1, 0>(ElementsAreArray(expected_adv_data)))
+      .Times(1)
+      .WillOnce(SaveArg<3>(&set_data_cb));
+  BleAdvertisingManager::Get()->SetData(
+      advertiser_id, false,
+      std::vector<uint8_t>({0x02 /* len */, 0x0A /* tx_power */, 0x00}),
+      base::Bind(&BleAdvertisingManagerTest::SetDataCb,
+                 base::Unretained(this)));
+  set_data_cb.Run(0);
+  EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status);
+  ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+}
+
+/* This test verifies that when advertising is non-connectable, flags will not
+ * be added. */
+TEST_F(BleAdvertisingManagerTest, test_adv_data_not_filling) {
+  BleAdvertisingManager::Get()->RegisterAdvertiser(base::Bind(
+      &BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this)));
+  EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status);
+  int advertiser_id = reg_inst_id;
+
+  status_cb set_params_cb;
+  tBTM_BLE_ADV_PARAMS params;
+  params.adv_type = BTM_BLE_NON_CONNECT_EVT;
+  params.tx_power = -15;
+  EXPECT_CALL(*hci_mock, SetParameters1(_, _, _, _, _, _)).Times(1);
+  EXPECT_CALL(*hci_mock, SetParameters2(_, _, _, advertiser_id,
+                                        (uint8_t)params.tx_power, _))
+      .Times(1)
+      .WillOnce(SaveArg<5>(&set_params_cb));
+  BleAdvertisingManager::Get()->SetParameters(
+      advertiser_id, &params,
+      base::Bind(&BleAdvertisingManagerTest::SetParametersCb,
+                 base::Unretained(this)));
+
+  // let the set parameters command succeed!
+  set_params_cb.Run(0);
+  EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_params_status);
+  ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+  status_cb set_data_cb;
+  /* verify that flags will not be added */
+  uint8_t expected_adv_data[] = {
+      0x02 /* len */, 0xFF /* manufacturer specific */, 0x01 /* data */};
+  EXPECT_CALL(*hci_mock, SetAdvertisingData(_, _, advertiser_id, _))
+      .With(Args<1, 0>(ElementsAreArray(expected_adv_data)))
+      .Times(1)
+      .WillOnce(SaveArg<3>(&set_data_cb));
+  BleAdvertisingManager::Get()->SetData(
+      advertiser_id, false, std::vector<uint8_t>({0x02 /* len */, 0xFF, 0x01}),
+      base::Bind(&BleAdvertisingManagerTest::SetDataCb,
+                 base::Unretained(this)));
+  set_data_cb.Run(0);
+  EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status);
+  ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+}
diff --git a/bt/stack/test/stack_a2dp_test.cc b/bt/stack/test/stack_a2dp_test.cc
new file mode 100644
index 0000000..1c9122e
--- /dev/null
+++ b/bt/stack/test/stack_a2dp_test.cc
@@ -0,0 +1,595 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+
+#include "stack/include/a2dp_api.h"
+#include "stack/include/a2dp_sbc.h"
+#include "stack/include/a2dp_vendor.h"
+
+//TODO(jpawlowski): remove once weird dependency in hci_layer.cc is removed
+#include <hardware/bluetooth.h>
+bt_bdaddr_t btif_local_bd_addr;
+
+namespace {
+const uint8_t codec_info_sbc[AVDT_CODEC_SIZE] = {
+  6,                    // Length (A2DP_SBC_INFO_LEN)
+  0,                    // Media Type: AVDT_MEDIA_TYPE_AUDIO
+  0,                    // Media Codec Type: A2DP_MEDIA_CT_SBC
+  0x20 | 0x01,          // Sample Frequency: A2DP_SBC_IE_SAMP_FREQ_44 |
+                        // Channel Mode: A2DP_SBC_IE_CH_MD_JOINT
+  0x10 | 0x04 | 0x01,   // Block Length: A2DP_SBC_IE_BLOCKS_16 |
+                        // Subbands: A2DP_SBC_IE_SUBBAND_8 |
+                        // Allocation Method: A2DP_SBC_IE_ALLOC_MD_L
+  2,                    // MinimumBitpool Value: A2DP_SBC_IE_MIN_BITPOOL
+  53,                   // Maximum Bitpool Value: A2DP_SBC_MAX_BITPOOL
+  7,                    // Dummy
+  8,                    // Dummy
+  9                     // Dummy
+};
+
+const uint8_t codec_info_sbc_sink[AVDT_CODEC_SIZE] = {
+  6,                    // Length (A2DP_SBC_INFO_LEN)
+  0,                    // Media Type: AVDT_MEDIA_TYPE_AUDIO
+  0,                    // Media Codec Type: A2DP_MEDIA_CT_SBC
+  0x20 | 0x10 |         // Sample Frequency: A2DP_SBC_IE_SAMP_FREQ_44 |
+                        // A2DP_SBC_IE_SAMP_FREQ_48 |
+  0x08 | 0x04 | 0x02 | 0x01, // Channel Mode: A2DP_SBC_IE_CH_MD_MONO |
+                        // A2DP_SBC_IE_CH_MD_DUAL |
+                        // A2DP_SBC_IE_CH_MD_STEREO |
+                        // A2DP_SBC_IE_CH_MD_JOINT
+  0x80 | 0x40 | 0x20 | 0x10 | // Block Length: A2DP_SBC_IE_BLOCKS_4 |
+                        // A2DP_SBC_IE_BLOCKS_8 |
+                        // A2DP_SBC_IE_BLOCKS_12 |
+                        // A2DP_SBC_IE_BLOCKS_16 |
+  0x08 | 0x04 |         // Subbands: A2DP_SBC_IE_SUBBAND_4 |
+                        // A2DP_SBC_IE_SUBBAND_8 |
+  0x02 | 0x01,          // Allocation Method: A2DP_SBC_IE_ALLOC_MD_S |
+                        // A2DP_SBC_IE_ALLOC_MD_L
+  2,                    // MinimumBitpool Value: A2DP_SBC_IE_MIN_BITPOOL
+  250,                  // Maximum Bitpool Value: A2DP_SBC_IE_MAX_BITPOOL
+  7,                    // Dummy
+  8,                    // Dummy
+  9                     // Dummy
+};
+
+const uint8_t codec_info_non_a2dp[AVDT_CODEC_SIZE] = {
+  8,                    // Length
+  0,                    // Media Type: AVDT_MEDIA_TYPE_AUDIO
+  0xFF,                 // Media Codec Type: A2DP_MEDIA_CT_NON_A2DP
+  3, 4, 0, 0,           // Vendor ID: LSB first, upper two octets should be 0
+  7, 8,                 // Codec ID: LSB first
+  9                     // Dummy
+};
+
+const uint8_t codec_info_non_a2dp_dummy[AVDT_CODEC_SIZE] = {
+  8,                    // Length
+  0,                    // Media Type: AVDT_MEDIA_TYPE_AUDIO
+  0xFF,                 // Media Codec Type: A2DP_MEDIA_CT_NON_A2DP
+  3, 4, 0, 0,           // Vendor ID: LSB first, upper two octets should be 0
+  7, 8,                 // Codec ID: LSB first
+  10                    // Dummy
+};
+
+} // namespace
+
+TEST(StackA2dpTest, test_a2dp_is_codec_valid) {
+  EXPECT_TRUE(A2DP_IsSourceCodecValid(codec_info_sbc));
+  EXPECT_TRUE(A2DP_IsPeerSourceCodecValid(codec_info_sbc));
+
+  EXPECT_TRUE(A2DP_IsSinkCodecValid(codec_info_sbc_sink));
+  EXPECT_TRUE(A2DP_IsPeerSinkCodecValid(codec_info_sbc_sink));
+
+  EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_non_a2dp));
+  EXPECT_FALSE(A2DP_IsSinkCodecValid(codec_info_non_a2dp));
+  EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_non_a2dp));
+  EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_non_a2dp));
+
+  // Test with invalid SBC codecs
+  uint8_t codec_info_sbc_invalid[AVDT_CODEC_SIZE];
+  memset(codec_info_sbc_invalid, 0, sizeof(codec_info_sbc_invalid));
+  EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_sbc_invalid));
+  EXPECT_FALSE(A2DP_IsSinkCodecValid(codec_info_sbc_invalid));
+  EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_sbc_invalid));
+  EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_sbc_invalid));
+
+  memcpy(codec_info_sbc_invalid, codec_info_sbc, sizeof(codec_info_sbc));
+  codec_info_sbc_invalid[0] = 0;        // Corrupt the Length field
+  EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_sbc_invalid));
+  EXPECT_FALSE(A2DP_IsSinkCodecValid(codec_info_sbc_invalid));
+  EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_sbc_invalid));
+  EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_sbc_invalid));
+
+  memcpy(codec_info_sbc_invalid, codec_info_sbc, sizeof(codec_info_sbc));
+  codec_info_sbc_invalid[1] = 0xff;        // Corrupt the Media Type field
+  EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_sbc_invalid));
+  EXPECT_FALSE(A2DP_IsSinkCodecValid(codec_info_sbc_invalid));
+  EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_sbc_invalid));
+  EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_sbc_invalid));
+}
+
+TEST(StackA2dpTest, test_a2dp_get_codec_type) {
+  tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(codec_info_sbc);
+  EXPECT_EQ(codec_type, A2DP_MEDIA_CT_SBC);
+
+  codec_type = A2DP_GetCodecType(codec_info_non_a2dp);
+  EXPECT_EQ(codec_type, A2DP_MEDIA_CT_NON_A2DP);
+}
+
+TEST(StackA2dpTest, test_a2dp_is_source_codec_supported) {
+  EXPECT_TRUE(A2DP_IsSourceCodecSupported(codec_info_sbc));
+  EXPECT_FALSE(A2DP_IsSourceCodecSupported(codec_info_non_a2dp));
+}
+
+TEST(StackA2dpTest, test_a2dp_is_sink_codec_supported) {
+  EXPECT_TRUE(A2DP_IsSinkCodecSupported(codec_info_sbc));
+  EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_non_a2dp));
+}
+
+TEST(StackA2dpTest, test_a2dp_is_peer_source_codec_supported) {
+  EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_sbc));
+  EXPECT_FALSE(A2DP_IsPeerSourceCodecSupported(codec_info_non_a2dp));
+}
+
+TEST(StackA2dpTest, test_init_default_codec) {
+  uint8_t codec_info_result[AVDT_CODEC_SIZE];
+
+  memset(codec_info_result, 0, sizeof(codec_info_result));
+  A2DP_InitDefaultCodec(codec_info_result);
+
+  // Compare the result codec with the local test codec info
+  for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
+    EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
+  }
+}
+
+TEST(StackA2dpTest, test_set_codec) {
+  uint8_t codec_info_result[AVDT_CODEC_SIZE];
+
+  const tA2DP_FEEDING_PARAMS feeding_params = {
+      .sampling_freq = 44100,
+      .num_channel = 2,
+      .bit_per_sample = 16
+  };
+  tA2DP_FEEDING_PARAMS bad_feeding_params;
+
+  EXPECT_TRUE(A2DP_SetSourceCodec(A2DP_CODEC_SEP_INDEX_SOURCE_SBC,
+                                  &feeding_params, codec_info_result));
+
+  // Compare the result codec with the local test codec info
+  for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
+    EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
+  }
+
+  // Test for invalid values of source codec SEP index
+  EXPECT_FALSE(A2DP_SetSourceCodec(A2DP_CODEC_SEP_INDEX_SINK_SBC,
+                                   &feeding_params, codec_info_result));
+  EXPECT_FALSE(A2DP_SetSourceCodec(A2DP_CODEC_SEP_INDEX_SINK_MAX,
+                                   &feeding_params, codec_info_result));
+
+  // Test invalid feeding - invalid num_channel
+  bad_feeding_params = feeding_params;
+  bad_feeding_params.num_channel = 3;
+  EXPECT_FALSE(A2DP_SetSourceCodec(A2DP_CODEC_SEP_INDEX_SOURCE_SBC,
+                                   &bad_feeding_params, codec_info_result));
+
+  // Test invalid feeding - invalid bit_per_sample
+  bad_feeding_params = feeding_params;
+  bad_feeding_params.bit_per_sample = 7;
+  EXPECT_FALSE(A2DP_SetSourceCodec(A2DP_CODEC_SEP_INDEX_SOURCE_SBC,
+                                   &bad_feeding_params, codec_info_result));
+
+  // Test invalid feeding - invalid sampling_freq
+  bad_feeding_params = feeding_params;
+  bad_feeding_params.sampling_freq = 7999;
+  EXPECT_FALSE(A2DP_SetSourceCodec(A2DP_CODEC_SEP_INDEX_SOURCE_SBC,
+                                   &bad_feeding_params, codec_info_result));
+}
+
+TEST(StackA2dpTest, test_build_src2sink_config) {
+  uint8_t codec_info_result[AVDT_CODEC_SIZE];
+
+  memset(codec_info_result, 0, sizeof(codec_info_result));
+  EXPECT_EQ(A2DP_BuildSrc2SinkConfig(codec_info_sbc, codec_info_result),
+            A2DP_SUCCESS);
+  // Compare the result codec with the local test codec info
+  for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
+    EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
+  }
+
+  // Include extra (less preferred) capabilities and test again
+  uint8_t codec_info_sbc_test1[AVDT_CODEC_SIZE];
+  memcpy(codec_info_sbc_test1, codec_info_sbc, sizeof(codec_info_sbc));
+  codec_info_sbc_test1[3] |= (A2DP_SBC_IE_CH_MD_STEREO | A2DP_SBC_IE_CH_MD_DUAL |
+                              A2DP_SBC_IE_CH_MD_MONO);
+  codec_info_sbc_test1[4] |= (A2DP_SBC_IE_BLOCKS_12 | A2DP_SBC_IE_BLOCKS_8 |
+                              A2DP_SBC_IE_BLOCKS_4);
+  codec_info_sbc_test1[4] |= A2DP_SBC_IE_SUBBAND_4;
+  codec_info_sbc_test1[4] |= A2DP_SBC_IE_ALLOC_MD_S;
+  memset(codec_info_result, 0, sizeof(codec_info_result));
+  EXPECT_EQ(A2DP_BuildSrc2SinkConfig(codec_info_sbc_test1, codec_info_result),
+            A2DP_SUCCESS);
+  // Compare the result codec with the local test codec info
+  for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
+    EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
+  }
+
+  // Test invalid codec info
+  memset(codec_info_result, 0, sizeof(codec_info_result));
+  memset(codec_info_sbc_test1, 0, sizeof(codec_info_sbc_test1));
+  EXPECT_NE(A2DP_BuildSrc2SinkConfig(codec_info_sbc_test1, codec_info_result),
+            A2DP_SUCCESS);
+}
+
+TEST(StackA2dpTest, test_build_sink_config) {
+  uint8_t codec_info_result[AVDT_CODEC_SIZE];
+  uint8_t codec_info_expected[AVDT_CODEC_SIZE];
+
+  memcpy(codec_info_expected, codec_info_sbc, sizeof(codec_info_sbc));
+  codec_info_expected[5] = codec_info_sbc_sink[5];
+  codec_info_expected[6] = codec_info_sbc_sink[6];
+
+  memset(codec_info_result, 0, sizeof(codec_info_result));
+  EXPECT_EQ(A2DP_BuildSinkConfig(codec_info_sbc, codec_info_sbc_sink,
+                                codec_info_result),
+            A2DP_SUCCESS);
+  // Compare the result codec with the local test codec info
+  for (size_t i = 0; i < codec_info_expected[0] + 1; i++) {
+    EXPECT_EQ(codec_info_result[i], codec_info_expected[i]);
+  }
+
+  // Change the min/max bitpool and test again
+  uint8_t codec_info_sbc_sink_test1[AVDT_CODEC_SIZE];
+  memcpy(codec_info_sbc_sink_test1, codec_info_sbc_sink,
+         sizeof(codec_info_sbc_sink));
+  codec_info_sbc_sink_test1[5] = 3;
+  codec_info_sbc_sink_test1[6] = 200;
+  codec_info_expected[5] = codec_info_sbc_sink_test1[5];
+  codec_info_expected[6] = codec_info_sbc_sink_test1[6];
+  memset(codec_info_result, 0, sizeof(codec_info_result));
+  EXPECT_EQ(A2DP_BuildSinkConfig(codec_info_sbc, codec_info_sbc_sink_test1,
+                                codec_info_result),
+            A2DP_SUCCESS);
+  // Compare the result codec with the local test codec info
+  for (size_t i = 0; i < codec_info_expected[0] + 1; i++) {
+    EXPECT_EQ(codec_info_result[i], codec_info_expected[i]);
+  }
+
+  // Test invalid codec info
+  uint8_t codec_info_sbc_test1[AVDT_CODEC_SIZE];
+  memset(codec_info_sbc_test1, 0, sizeof(codec_info_sbc_test1));
+  EXPECT_NE(A2DP_BuildSinkConfig(codec_info_sbc_test1, codec_info_sbc_sink,
+                                codec_info_result),
+            A2DP_SUCCESS);
+}
+
+TEST(StackA2dpTest, test_a2dp_uses_rtp_header) {
+  EXPECT_TRUE(A2DP_UsesRtpHeader(true, codec_info_sbc));
+  EXPECT_TRUE(A2DP_UsesRtpHeader(false, codec_info_sbc));
+  EXPECT_TRUE(A2DP_UsesRtpHeader(true, codec_info_non_a2dp));
+  EXPECT_TRUE(A2DP_UsesRtpHeader(false, codec_info_non_a2dp));
+}
+
+TEST(StackA2dpTest, test_a2dp_codec_sep_index_str) {
+  // Explicit tests for known codecs
+  EXPECT_STREQ(A2DP_CodecSepIndexStr(A2DP_CODEC_SEP_INDEX_SOURCE_SBC), "SBC");
+  EXPECT_STREQ(A2DP_CodecSepIndexStr(A2DP_CODEC_SEP_INDEX_SINK_SBC), "SBC SINK");
+
+  // Test that the unknown codec string has not changed
+  EXPECT_STREQ(A2DP_CodecSepIndexStr(A2DP_CODEC_SEP_INDEX_MAX),
+               "UNKNOWN CODEC SEP INDEX");
+
+  // Test that each codec has a known string
+  for (int i = 0; i < A2DP_CODEC_SEP_INDEX_MAX; i++) {
+    tA2DP_CODEC_SEP_INDEX codec_sep_index =
+      static_cast<tA2DP_CODEC_SEP_INDEX>(i);
+    EXPECT_STRNE(A2DP_CodecSepIndexStr(codec_sep_index),
+                 "UNKNOWN CODEC SEP INDEX");
+  }
+}
+
+TEST(StackA2dpTest, test_a2dp_init_codec_config) {
+  tAVDT_CFG avdt_cfg;
+
+  //
+  // Test for SBC Source
+  //
+  memset(&avdt_cfg, 0, sizeof(avdt_cfg));
+  EXPECT_TRUE(A2DP_InitCodecConfig(A2DP_CODEC_SEP_INDEX_SOURCE_SBC, &avdt_cfg));
+  // Compare the result codec with the local test codec info
+  for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
+    EXPECT_EQ(avdt_cfg.codec_info[i], codec_info_sbc[i]);
+  }
+  // Test for content protection
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+  EXPECT_EQ(avdt_cfg.protect_info[0], AVDT_CP_LOSC);
+  EXPECT_EQ(avdt_cfg.protect_info[1], (AVDT_CP_SCMS_T_ID & 0xFF));
+  EXPECT_EQ(avdt_cfg.protect_info[2], ((AVDT_CP_SCMS_T_ID >> 8) & 0xFF));
+  EXPECT_EQ(avdt_cfg.num_protect, 1);
+#endif
+
+  //
+  // Test for SBC Sink
+  //
+  memset(&avdt_cfg, 0, sizeof(avdt_cfg));
+  EXPECT_TRUE(A2DP_InitCodecConfig(A2DP_CODEC_SEP_INDEX_SINK_SBC, &avdt_cfg));
+  // Compare the result codec with the local test codec info
+  for (size_t i = 0; i < codec_info_sbc_sink[0] + 1; i++) {
+    EXPECT_EQ(avdt_cfg.codec_info[i], codec_info_sbc_sink[i]);
+  }
+}
+
+TEST(StackA2dpTest, test_a2dp_get_media_type) {
+  uint8_t codec_info_test[AVDT_CODEC_SIZE];
+
+  EXPECT_EQ(A2DP_GetMediaType(codec_info_sbc), AVDT_MEDIA_TYPE_AUDIO);
+  EXPECT_EQ(A2DP_GetMediaType(codec_info_non_a2dp), AVDT_MEDIA_TYPE_AUDIO);
+
+  // Prepare dummy codec info for video and for multimedia
+  memset(codec_info_test, 0, sizeof(codec_info_test));
+  codec_info_test[0] = sizeof(codec_info_test);
+  codec_info_test[1] = 0x01 << 4;
+  EXPECT_EQ(A2DP_GetMediaType(codec_info_test), AVDT_MEDIA_TYPE_VIDEO);
+  codec_info_test[1] = 0x02 << 4;
+  EXPECT_EQ(A2DP_GetMediaType(codec_info_test), AVDT_MEDIA_TYPE_MULTI);
+}
+
+TEST(StackA2dpTest, test_a2dp_codec_name) {
+  uint8_t codec_info_test[AVDT_CODEC_SIZE];
+
+  // Explicit tests for known codecs
+  EXPECT_STREQ(A2DP_CodecName(codec_info_sbc), "SBC");
+  EXPECT_STREQ(A2DP_CodecName(codec_info_sbc_sink), "SBC");
+  EXPECT_STREQ(A2DP_CodecName(codec_info_non_a2dp), "UNKNOWN VENDOR CODEC");
+
+  // Test all unknown codecs
+  memcpy(codec_info_test, codec_info_sbc, sizeof(codec_info_sbc));
+  for (uint8_t codec_type = A2DP_MEDIA_CT_SBC + 1;
+       codec_type < A2DP_MEDIA_CT_NON_A2DP;
+       codec_type++) {
+    codec_info_test[2] = codec_type;        // Unknown codec type
+    EXPECT_STREQ(A2DP_CodecName(codec_info_test), "UNKNOWN CODEC");
+  }
+}
+
+TEST(StackA2dpTest, test_a2dp_vendor) {
+  EXPECT_FALSE(A2DP_IsVendorSourceCodecSupported(codec_info_non_a2dp));
+  EXPECT_EQ(A2DP_VendorCodecGetVendorId(codec_info_non_a2dp),
+              (uint32_t)0x00000403);
+  EXPECT_EQ(A2DP_VendorCodecGetCodecId(codec_info_non_a2dp), (uint16_t)0x0807);
+  EXPECT_TRUE(A2DP_VendorUsesRtpHeader(true, codec_info_non_a2dp));
+  EXPECT_TRUE(A2DP_VendorUsesRtpHeader(false, codec_info_non_a2dp));
+}
+
+TEST(StackA2dpTest, test_a2dp_codec_type_equals) {
+  EXPECT_TRUE(A2DP_CodecTypeEquals(codec_info_sbc, codec_info_sbc_sink));
+  EXPECT_TRUE(A2DP_CodecTypeEquals(codec_info_non_a2dp,
+                                  codec_info_non_a2dp_dummy));
+  EXPECT_FALSE(A2DP_CodecTypeEquals(codec_info_sbc, codec_info_non_a2dp));
+}
+
+TEST(StackA2dpTest, test_a2dp_codec_equals) {
+  uint8_t codec_info_sbc_test[AVDT_CODEC_SIZE];
+  uint8_t codec_info_non_a2dp_test[AVDT_CODEC_SIZE];
+
+  // Test two identical SBC codecs
+  memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
+  memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
+  EXPECT_TRUE(A2DP_CodecEquals(codec_info_sbc, codec_info_sbc_test));
+
+  // Test two identical non-A2DP codecs that are not recognized
+  memset(codec_info_non_a2dp_test, 0xAB, sizeof(codec_info_non_a2dp_test));
+  memcpy(codec_info_non_a2dp_test, codec_info_non_a2dp,
+         sizeof(codec_info_non_a2dp));
+  EXPECT_FALSE(A2DP_CodecEquals(codec_info_non_a2dp, codec_info_non_a2dp_test));
+
+  // Test two codecs that have different types
+  EXPECT_FALSE(A2DP_CodecEquals(codec_info_sbc, codec_info_non_a2dp));
+
+  // Test two SBC codecs that are slightly different
+  memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
+  memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
+  codec_info_sbc_test[5] = codec_info_sbc[5] + 1;
+  EXPECT_FALSE(A2DP_CodecEquals(codec_info_sbc, codec_info_sbc_test));
+  codec_info_sbc_test[5] = codec_info_sbc[5];
+  codec_info_sbc_test[6] = codec_info_sbc[6] + 1;
+  EXPECT_FALSE(A2DP_CodecEquals(codec_info_sbc, codec_info_sbc_test));
+
+  // Test two SBC codecs that are identical, but with different dummy
+  // trailer data.
+  memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
+  memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
+  codec_info_sbc_test[7] = codec_info_sbc[7] + 1;
+  EXPECT_TRUE(A2DP_CodecEquals(codec_info_sbc, codec_info_sbc_test));
+}
+
+TEST(StackA2dpTest, test_a2dp_codec_requires_reconfig) {
+  uint8_t codec_info_sbc_test[AVDT_CODEC_SIZE];
+
+  // Test two identical SBC codecs
+  memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
+  memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
+  EXPECT_FALSE(A2DP_CodecRequiresReconfig(codec_info_sbc, codec_info_sbc_test));
+
+  // Test two codecs that have different types
+  EXPECT_TRUE(A2DP_CodecRequiresReconfig(codec_info_sbc, codec_info_non_a2dp));
+
+  // Test two SBC codecs that are slightly different, and don't require
+  // reconfig.
+  memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
+  memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
+  codec_info_sbc_test[5] = codec_info_sbc[5] + 1;
+  EXPECT_FALSE(A2DP_CodecRequiresReconfig(codec_info_sbc, codec_info_sbc_test));
+  codec_info_sbc_test[5] = codec_info_sbc[5];
+  codec_info_sbc_test[6] = codec_info_sbc[6] + 1;
+  EXPECT_FALSE(A2DP_CodecRequiresReconfig(codec_info_sbc, codec_info_sbc_test));
+
+  // Test two SBC codecs that are slightly different, and require reconfig.
+  memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
+  memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
+  codec_info_sbc_test[3] = 0x10 | 0x01; // A2DP_SBC_IE_SAMP_FREQ_48 |
+                                        // A2DP_SBC_IE_CH_MD_JOINT
+  EXPECT_TRUE(A2DP_CodecRequiresReconfig(codec_info_sbc, codec_info_sbc_test));
+
+  // Test two SBC codecs that are identical, but with different dummy
+  // trailer data.
+  memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
+  memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
+  codec_info_sbc_test[7] = codec_info_sbc[7] + 1;
+  EXPECT_FALSE(A2DP_CodecRequiresReconfig(codec_info_sbc, codec_info_sbc_test));
+}
+
+TEST(StackA2dpTest, test_a2dp_codec_config_matches_capabilities) {
+  EXPECT_TRUE(A2DP_CodecConfigMatchesCapabilities(codec_info_sbc,
+                                                 codec_info_sbc_sink));
+  EXPECT_FALSE(A2DP_CodecConfigMatchesCapabilities(codec_info_non_a2dp,
+                                                  codec_info_non_a2dp_dummy));
+  EXPECT_FALSE(A2DP_CodecConfigMatchesCapabilities(codec_info_sbc,
+                                                  codec_info_non_a2dp));
+}
+
+TEST(StackA2dpTest, test_a2dp_get_track_frequency) {
+  EXPECT_EQ(A2DP_GetTrackFrequency(codec_info_sbc), 44100);
+  EXPECT_EQ(A2DP_GetTrackFrequency(codec_info_non_a2dp), -1);
+}
+
+TEST(StackA2dpTest, test_a2dp_get_track_channel_count) {
+  EXPECT_EQ(A2DP_GetTrackChannelCount(codec_info_sbc), 2);
+  EXPECT_EQ(A2DP_GetTrackChannelCount(codec_info_non_a2dp), -1);
+}
+
+TEST(StackA2dpTest, test_a2dp_get_number_of_subbands) {
+  EXPECT_EQ(A2DP_GetNumberOfSubbands(codec_info_sbc), 8);
+  EXPECT_EQ(A2DP_GetNumberOfSubbands(codec_info_non_a2dp), -1);
+}
+
+TEST(StackA2dpTest, test_a2dp_get_number_of_blocks) {
+  EXPECT_EQ(A2DP_GetNumberOfBlocks(codec_info_sbc), 16);
+  EXPECT_EQ(A2DP_GetNumberOfBlocks(codec_info_non_a2dp), -1);
+}
+
+TEST(StackA2dpTest, test_a2dp_get_allocation_method_code) {
+  EXPECT_EQ(A2DP_GetAllocationMethodCode(codec_info_sbc), 0);
+  EXPECT_EQ(A2DP_GetAllocationMethodCode(codec_info_non_a2dp), -1);
+}
+
+TEST(StackA2dpTest, test_a2dp_get_channel_mode_code) {
+  EXPECT_EQ(A2DP_GetChannelModeCode(codec_info_sbc), 3);
+  EXPECT_EQ(A2DP_GetChannelModeCode(codec_info_non_a2dp), -1);
+}
+
+TEST(StackA2dpTest, test_a2dp_get_sampling_frequency_code) {
+  EXPECT_EQ(A2DP_GetSamplingFrequencyCode(codec_info_sbc), 2);
+  EXPECT_EQ(A2DP_GetSamplingFrequencyCode(codec_info_non_a2dp), -1);
+}
+
+TEST(StackA2dpTest, test_a2dp_get_min_bitpool) {
+  EXPECT_EQ(A2DP_GetMinBitpool(codec_info_sbc), 2);
+  EXPECT_EQ(A2DP_GetMinBitpool(codec_info_sbc_sink), 2);
+  EXPECT_EQ(A2DP_GetMinBitpool(codec_info_non_a2dp), -1);
+}
+
+TEST(StackA2dpTest, test_a2dp_get_max_bitpool) {
+  EXPECT_EQ(A2DP_GetMaxBitpool(codec_info_sbc), 53);
+  EXPECT_EQ(A2DP_GetMaxBitpool(codec_info_sbc_sink), 250);
+  EXPECT_EQ(A2DP_GetMaxBitpool(codec_info_non_a2dp), -1);
+}
+
+TEST(StackA2dpTest, test_a2dp_get_sink_track_channel_type) {
+  EXPECT_EQ(A2DP_GetSinkTrackChannelType(codec_info_sbc), 3);
+  EXPECT_EQ(A2DP_GetSinkTrackChannelType(codec_info_non_a2dp), -1);
+}
+
+TEST(StackA2dpTest, test_a2dp_get_sink_frames_count_to_process) {
+  EXPECT_EQ(A2DP_GetSinkFramesCountToProcess(20, codec_info_sbc), 7);
+  EXPECT_EQ(A2DP_GetSinkFramesCountToProcess(20, codec_info_non_a2dp), -1);
+}
+
+TEST(StackA2dpTest, test_a2dp_get_packet_timestamp) {
+  uint8_t a2dp_data[1000];
+  uint32_t timestamp;
+  uint32_t *p_ts = reinterpret_cast<uint32_t *>(a2dp_data);
+
+  memset(a2dp_data, 0xAB, sizeof(a2dp_data));
+  *p_ts = 0x12345678;
+  timestamp = 0xFFFFFFFF;
+  EXPECT_TRUE(A2DP_GetPacketTimestamp(codec_info_sbc, a2dp_data, &timestamp));
+  EXPECT_EQ(timestamp, static_cast<uint32_t>(0x12345678));
+
+  memset(a2dp_data, 0xAB, sizeof(a2dp_data));
+  *p_ts = 0x12345678;
+  timestamp = 0xFFFFFFFF;
+  EXPECT_FALSE(A2DP_GetPacketTimestamp(codec_info_non_a2dp, a2dp_data,
+                                      &timestamp));
+}
+
+TEST(StackA2dpTest, test_a2dp_build_codec_header) {
+  uint8_t a2dp_data[1000];
+  BT_HDR *p_buf = reinterpret_cast<BT_HDR *>(a2dp_data);
+  const uint16_t BT_HDR_LEN = 500;
+  const uint16_t BT_HDR_OFFSET = 50;
+  const uint8_t FRAMES_PER_PACKET = 0xCD;
+
+  memset(a2dp_data, 0xAB, sizeof(a2dp_data));
+  p_buf->len = BT_HDR_LEN;
+  p_buf->offset = BT_HDR_OFFSET;
+  EXPECT_TRUE(A2DP_BuildCodecHeader(codec_info_sbc, p_buf, FRAMES_PER_PACKET));
+  EXPECT_EQ(p_buf->offset + 1, BT_HDR_OFFSET);  // Modified by A2DP_SBC_MPL_HDR_LEN
+  EXPECT_EQ(p_buf->len - 1, BT_HDR_LEN);        // Modified by A2DP_SBC_MPL_HDR_LEN
+  const uint8_t *p =
+      reinterpret_cast<const uint8_t *>(p_buf + 1) + p_buf->offset;
+  EXPECT_EQ(*p, static_cast<uint8_t>(0x0D));    // 0xCD masked with A2DP_SBC_HDR_NUM_MSK
+
+  memset(a2dp_data, 0xAB, sizeof(a2dp_data));
+  p_buf->len = BT_HDR_LEN;
+  p_buf->offset = BT_HDR_OFFSET;
+  EXPECT_FALSE(A2DP_BuildCodecHeader(codec_info_non_a2dp, p_buf,
+                                    FRAMES_PER_PACKET));
+}
+
+TEST(StackA2dpTest, test_a2dp_adjust_codec) {
+  uint8_t codec_info_sbc_test[AVDT_CODEC_SIZE];
+  uint8_t codec_info_non_a2dp_test[AVDT_CODEC_SIZE];
+
+  // Test updating a valid SBC codec that doesn't need adjustment
+  memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
+  memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
+  EXPECT_TRUE(A2DP_AdjustCodec(codec_info_sbc_test));
+  EXPECT_TRUE(memcmp(codec_info_sbc_test, codec_info_sbc,
+                     sizeof(codec_info_sbc)) == 0);
+
+  // Test updating a valid SBC codec that needs adjustment
+  memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
+  memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
+  codec_info_sbc_test[6] = 54;  // A2DP_SBC_MAX_BITPOOL + 1
+  EXPECT_TRUE(A2DP_AdjustCodec(codec_info_sbc_test));
+  EXPECT_TRUE(memcmp(codec_info_sbc_test, codec_info_sbc,
+                     sizeof(codec_info_sbc)) == 0);
+
+  // Test updating an invalid SBC codec
+  memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
+  memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
+  codec_info_sbc_test[6] = 255; // Invalid MAX_BITPOOL
+  EXPECT_FALSE(A2DP_AdjustCodec(codec_info_sbc_test));
+
+  // Test updating a non-A2DP codec that is not recognized
+  memset(codec_info_non_a2dp_test, 0xAB, sizeof(codec_info_non_a2dp_test));
+  memcpy(codec_info_non_a2dp_test, codec_info_non_a2dp,
+         sizeof(codec_info_non_a2dp));
+  EXPECT_FALSE(A2DP_AdjustCodec(codec_info_non_a2dp_test));
+}
diff --git a/bt/test/Android.mk b/bt/test/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/bt/test/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/bt/test/README.md b/bt/test/README.md
new file mode 100644
index 0000000..7b72f30
--- /dev/null
+++ b/bt/test/README.md
@@ -0,0 +1,81 @@
+# Fluoride Bluetooth Tests
+
+This document refers to the tests in the system/bt/test directory.
+
+The tests are designed to be run when the Android runtime is not running.  From a terminal, run:
+
+## Before you run tests
+```sh
+adb shell stop
+```
+
+## After you're done
+```sh
+adb shell start
+```
+
+## Running tests
+Then see what options the test script provides:
+
+```sh
+./run_unit_tests.sh --help
+```
+
+But for the impatient, run specific groups of tests like this:
+
+```sh
+./run_unit_tests.sh net_test_bluetooth
+```
+
+a single test:
+
+```sh
+./run_unit_tests.sh net_test_bluetooth.BluetoothTest.AdapterRepeatedEnableDisable
+```
+
+## Sample Output
+
+system/bt/test$ ./run_unit_tests.sh net_test_bluetooth  
+--- net_test_bluetooth ---  
+pushing...  
+/tbd/aosp-master/out/target/product/bullhead/data/nativetest/n...st_bluetooth: 1 file pushed. 9.2 MB/s (211832 bytes in 0.022s)  
+running...  
+  
+Running main() from gtest_main.cc  
+[==========] Running 11 tests from 2 test cases.  
+[----------] Global test environment set-up.  
+[----------] 6 tests from BluetoothTest  
+[ RUN      ] BluetoothTest.AdapterEnableDisable  
+[       OK ] BluetoothTest.AdapterEnableDisable (2538 ms)  
+[ RUN      ] BluetoothTest.AdapterRepeatedEnableDisable  
+[       OK ] BluetoothTest.AdapterRepeatedEnableDisable (11384 ms)  
+[ RUN      ] BluetoothTest.AdapterSetGetName  
+[       OK ] BluetoothTest.AdapterSetGetName (2378 ms)  
+[ RUN      ] BluetoothTest.AdapterStartDiscovery  
+[       OK ] BluetoothTest.AdapterStartDiscovery (2397 ms)  
+[ RUN      ] BluetoothTest.AdapterCancelDiscovery  
+[       OK ] BluetoothTest.AdapterCancelDiscovery (2401 ms)  
+[ RUN      ] BluetoothTest.AdapterDisableDuringBonding  
+[       OK ] BluetoothTest.AdapterDisableDuringBonding (11689 ms)  
+[----------] 6 tests from BluetoothTest (32789 ms total)  
+
+[----------] 5 tests from GattTest  
+[ RUN      ] GattTest.GattClientRegister  
+[       OK ] GattTest.GattClientRegister (2370 ms)  
+[ RUN      ] GattTest.GattClientScanRemoteDevice  
+[       OK ] GattTest.GattClientScanRemoteDevice (2273 ms)  
+[ RUN      ] GattTest.GattClientAdvertise  
+[       OK ] GattTest.GattClientAdvertise (2236 ms)  
+[ RUN      ] GattTest.GattServerRegister  
+[       OK ] GattTest.GattServerRegister (2391 ms)  
+[ RUN      ] GattTest.GattServerBuild  
+[       OK ] GattTest.GattServerBuild (2435 ms)  
+[----------] 5 tests from GattTest (11706 ms total)  
+  
+[----------] Global test environment tear-down  
+[==========] 11 tests from 2 test cases ran. (44495 ms total)  
+[  PASSED  ] 11 tests.  
+
+## Troubleshooting: Your phone is bricked!
+Probably not.  See [After you're done](#After-you're-done)
+
diff --git a/bt/test/run_unit_tests.sh b/bt/test/run_unit_tests.sh
new file mode 100755
index 0000000..bc3a8be
--- /dev/null
+++ b/bt/test/run_unit_tests.sh
@@ -0,0 +1,135 @@
+#!/bin/sh
+
+known_tests=(
+  bluetoothtbd_test
+  net_test_bluetooth
+  net_test_btcore
+  net_test_bta
+  net_test_btif
+  net_test_device
+  net_test_hci
+  net_test_stack
+  net_test_stack_multi_adv
+  net_test_osi
+)
+
+known_remote_tests=(
+  net_test_rfcomm
+)
+
+
+usage() {
+  binary="$(basename "$0")"
+  echo "Usage: ${binary} --help"
+  echo "       ${binary} [-i <iterations>] [-s <specific device>] [--all] [<test name>[.<filter>] ...] [--<arg> ...]"
+  echo
+  echo "Unknown long arguments are passed to the test."
+  echo
+  echo "Known test names:"
+
+  for name in "${known_tests[@]}"
+  do
+    echo "    ${name}"
+  done
+
+  echo
+  echo "Known tests that need a remote device:"
+  for name in "${known_remote_tests[@]}"
+  do
+    echo "    ${name}"
+  done
+}
+
+iterations=1
+device=
+tests=()
+test_args=()
+while [ $# -gt 0 ]
+do
+  case "$1" in
+    -h|--help)
+      usage
+      exit 0
+      ;;
+    -i)
+      shift
+      if [ $# -eq 0 ]; then
+        echo "error: number of iterations expected" 1>&2
+        usage
+        exit 2
+      fi
+      iterations=$(( $1 ))
+      shift
+      ;;
+    -s)
+      shift
+      if [ $# -eq 0 ]; then
+        echo "error: no device specified" 1>&2
+        usage
+        exit 2
+      fi
+      device="$1"
+      shift
+      ;;
+    --all)
+      tests+=( "${known_tests[@]}" )
+      shift
+      ;;
+    --*)
+      test_args+=( "$1" )
+      shift
+      ;;
+    *)
+      tests+=( "$1" )
+      shift
+      ;;
+  esac
+done
+
+if [ "${#tests[@]}" -eq 0 ]; then
+  tests+=( "${known_tests[@]}" )
+fi
+
+adb=( "adb" )
+if [ -n "${device}" ]; then
+  adb+=( "-s" "${device}" )
+fi
+
+failed_tests=()
+for spec in "${tests[@]}"
+do
+  name="${spec%%.*}"
+  binary="/data/nativetest/${name}/${name}"
+
+  push_command=( "${adb[@]}" push {"${ANDROID_PRODUCT_OUT}",}"${binary}" )
+  test_command=( "${adb[@]}" shell "${binary}" )
+  if [ "${name}" != "${spec}" ]; then
+    filter="${spec#*.}"
+    test_command+=( "--gtest_filter=${filter}" )
+  fi
+  test_command+=( "${test_args[@]}" )
+
+  echo "--- ${name} ---"
+  echo "pushing..."
+  "${push_command[@]}"
+  echo "running..."
+  failed_count=0
+  for i in $(seq 1 ${iterations})
+  do
+    "${test_command[@]}" || failed_count=$(( $failed_count + 1 ))
+  done
+
+  if [ $failed_count != 0 ]; then
+    failed_tests+=( "${name} ${failed_count}/${iterations}" )
+  fi
+done
+
+if [ "${#failed_tests[@]}" -ne 0 ]; then
+  for failed_test in "${failed_tests[@]}"
+  do
+    echo "!!! FAILED TEST: ${failed_test} !!!"
+  done
+  exit 1
+fi
+
+exit 0
diff --git a/bt/test/suite/Android.mk b/bt/test/suite/Android.mk
new file mode 100644
index 0000000..bfd30c6
--- /dev/null
+++ b/bt/test/suite/Android.mk
@@ -0,0 +1,93 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# These tests use the bluetoothtbd HAL wrappers in order to easily interact
+# with the interface using C++
+# TODO: Make the bluetoothtbd HAL a static library
+bluetoothHalSrc := \
+    ../../service/hal/bluetooth_gatt_interface.cc \
+    ../../service/hal/bluetooth_interface.cc \
+    ../../service/logging_helpers.cc
+
+# Bluetooth test suite for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := net_test_bluetooth
+
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH)/../../
+
+LOCAL_SRC_FILES := \
+    adapter/adapter_unittest.cc \
+    adapter/bluetooth_test.cc \
+    gatt/gatt_test.cc \
+    gatt/gatt_unittest.cc \
+    $(bluetoothHalSrc)
+
+LOCAL_SHARED_LIBRARIES := \
+    liblog \
+    libhardware \
+    libhardware_legacy \
+    libcutils \
+    libchrome
+
+LOCAL_STATIC_LIBRARIES := \
+    libbtcore \
+    libosi
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_NATIVE_TEST)
+
+# Bluetooth test suite for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := net_test_rfcomm
+
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH)/../../ \
+    $(bluetooth_C_INCLUDES) \
+
+LOCAL_SRC_FILES := \
+    adapter/bluetooth_test.cc \
+    rfcomm/rfcomm_test.cc \
+    rfcomm/rfcomm_unittest.cc \
+    $(bluetoothHalSrc)
+
+LOCAL_SHARED_LIBRARIES := \
+    liblog \
+    libhardware \
+    libhardware_legacy \
+    libcutils \
+    libchrome \
+
+LOCAL_STATIC_LIBRARIES := \
+    libbtcore \
+    libosi \
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_NATIVE_TEST)
diff --git a/bt/test/suite/BUILD.gn b/bt/test/suite/BUILD.gn
new file mode 100644
index 0000000..e413eb0
--- /dev/null
+++ b/bt/test/suite/BUILD.gn
@@ -0,0 +1,45 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+executable("net_test_bluetooth") {
+  testonly = true
+  sources = [
+    "adapter/adapter_unittest.cc",
+    "adapter/bluetooth_test.cc",
+  ]
+
+  include_dirs = [
+    "//",
+    "//test/suite",
+  ]
+
+  deps = [
+    "//btcore",
+    "//main:bluetooth.default",
+    "//service:service",
+    "//service:service_unittests",
+    "//third_party/libchrome:base",
+    "//osi",
+    "//third_party/googletest:gtest_main",
+  ]
+
+  libs = [
+    "-lpthread",
+    "-lrt",
+    "-ldl",
+    "-latomic",
+  ]
+}
diff --git a/bt/test/suite/adapter/adapter_unittest.cc b/bt/test/suite/adapter/adapter_unittest.cc
new file mode 100644
index 0000000..b16dfc5
--- /dev/null
+++ b/bt/test/suite/adapter/adapter_unittest.cc
@@ -0,0 +1,171 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "adapter/bluetooth_test.h"
+#include "btcore/include/property.h"
+#include "stack/include/bt_types.h"
+
+namespace {
+
+// Each iteration of the test takes about 2 seconds to run, so choose a value
+// that matches your time constraints. For example, 5 iterations would take
+// about 10 seconds to run
+const int kTestRepeatCount = 5;
+
+}  // namespace
+
+namespace bttest {
+
+TEST_F(BluetoothTest, AdapterEnableDisable) {
+  EXPECT_EQ(GetState(), BT_STATE_OFF) <<
+    "Test should be run with Adapter disabled";
+
+  EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+  semaphore_wait(adapter_state_changed_callback_sem_);
+  EXPECT_EQ(GetState(), BT_STATE_ON) <<  "Adapter did not turn on.";
+
+  EXPECT_EQ(bt_interface()->disable(), BT_STATUS_SUCCESS);
+  semaphore_wait(adapter_state_changed_callback_sem_);
+  EXPECT_EQ(GetState(), BT_STATE_OFF) << "Adapter did not turn off.";
+}
+
+TEST_F(BluetoothTest, AdapterRepeatedEnableDisable) {
+  EXPECT_EQ(GetState(), BT_STATE_OFF)
+    << "Test should be run with Adapter disabled";
+
+  for (int i = 0; i < kTestRepeatCount; ++i) {
+    EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+    semaphore_wait(adapter_state_changed_callback_sem_);
+    EXPECT_EQ(GetState(), BT_STATE_ON) <<  "Adapter did not turn on.";
+
+    EXPECT_EQ(bt_interface()->disable(), BT_STATUS_SUCCESS);
+    semaphore_wait(adapter_state_changed_callback_sem_);
+    EXPECT_EQ(GetState(), BT_STATE_OFF) << "Adapter did not turn off.";
+  }
+}
+
+TEST_F(BluetoothTest, AdapterSetGetName) {
+  bt_property_t *new_name = property_new_name("BluetoothTestName1");
+
+  EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+  semaphore_wait(adapter_state_changed_callback_sem_);
+  EXPECT_EQ(GetState(), BT_STATE_ON)
+    << "Test should be run with Adapter enabled";
+
+  // Enabling the interface will call the properties callback twice before
+  // ever reaching this point.
+  ClearSemaphore(adapter_properties_callback_sem_);
+
+  EXPECT_EQ(bt_interface()->get_adapter_property(BT_PROPERTY_BDNAME),
+      BT_STATUS_SUCCESS);
+  semaphore_wait(adapter_properties_callback_sem_);
+  EXPECT_GT(GetPropertiesChangedCount(), 0)
+    << "Expected at least one adapter property to change";
+  bt_property_t *name_property = GetProperty(BT_PROPERTY_BDNAME);
+  EXPECT_NE(name_property, nullptr);
+  if (property_equals(name_property, new_name)) {
+    property_free(new_name);
+    new_name = property_new_name("BluetoothTestName2");
+  }
+  std::string old_name((const char *)property_as_name(name_property)->name);
+
+  EXPECT_EQ(bt_interface()->set_adapter_property(new_name), BT_STATUS_SUCCESS);
+  semaphore_wait(adapter_properties_callback_sem_);
+  EXPECT_GT(GetPropertiesChangedCount(), 0)
+    << "Expected at least one adapter property to change";
+  EXPECT_TRUE(GetProperty(BT_PROPERTY_BDNAME))
+    << "The Bluetooth name property did not change.";
+  EXPECT_TRUE(property_equals(GetProperty(BT_PROPERTY_BDNAME), new_name))
+    << "Bluetooth name "
+    << property_as_name(GetProperty(BT_PROPERTY_BDNAME))->name
+    << " does not match test value " << property_as_name(new_name)->name;
+
+
+  bt_property_t *old_name_property = property_new_name(old_name.c_str());
+  EXPECT_EQ(bt_interface()->set_adapter_property(old_name_property), BT_STATUS_SUCCESS);
+  semaphore_wait(adapter_properties_callback_sem_);
+  EXPECT_TRUE(property_equals(GetProperty(BT_PROPERTY_BDNAME), old_name_property))
+    << "Bluetooth name "
+    << property_as_name(GetProperty(BT_PROPERTY_BDNAME))->name
+    << " does not match original name" << old_name;
+
+  EXPECT_EQ(bt_interface()->disable(), BT_STATUS_SUCCESS);
+  semaphore_wait(adapter_state_changed_callback_sem_);
+  EXPECT_EQ(GetState(), BT_STATE_OFF) << "Adapter did not turn off.";
+  property_free(new_name);
+  property_free(old_name_property);
+}
+
+TEST_F(BluetoothTest, AdapterStartDiscovery) {
+  EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+  semaphore_wait(adapter_state_changed_callback_sem_);
+  EXPECT_EQ(GetState(), BT_STATE_ON)
+    << "Test should be run with Adapter enabled";
+
+  EXPECT_EQ(bt_interface()->start_discovery(), BT_STATUS_SUCCESS);
+  semaphore_wait(discovery_state_changed_callback_sem_);
+  EXPECT_EQ(GetDiscoveryState(), BT_DISCOVERY_STARTED)
+    << "Unable to start discovery.";
+
+  EXPECT_EQ(bt_interface()->disable(), BT_STATUS_SUCCESS);
+  semaphore_wait(adapter_state_changed_callback_sem_);
+  EXPECT_EQ(GetState(), BT_STATE_OFF) << "Adapter did not turn off.";
+}
+
+TEST_F(BluetoothTest, AdapterCancelDiscovery) {
+  EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+  semaphore_wait(adapter_state_changed_callback_sem_);
+  EXPECT_EQ(GetState(), BT_STATE_ON)
+    << "Test should be run with Adapter enabled";
+
+  EXPECT_EQ(bt_interface()->start_discovery(), BT_STATUS_SUCCESS);
+  semaphore_wait(discovery_state_changed_callback_sem_);
+  EXPECT_EQ(bt_interface()->cancel_discovery(), BT_STATUS_SUCCESS);
+  semaphore_wait(discovery_state_changed_callback_sem_);
+
+  EXPECT_EQ(GetDiscoveryState(), BT_DISCOVERY_STOPPED)
+    << "Unable to stop discovery.";
+
+  EXPECT_EQ(bt_interface()->disable(), BT_STATUS_SUCCESS);
+  semaphore_wait(adapter_state_changed_callback_sem_);
+  EXPECT_EQ(GetState(), BT_STATE_OFF) << "Adapter did not turn off.";
+}
+
+TEST_F(BluetoothTest, AdapterDisableDuringBonding) {
+  EXPECT_EQ(GetState(), BT_STATE_OFF)
+    << "Test should be run with Adapter disabled";
+
+  bt_bdaddr_t bdaddr = { { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 } };
+
+  for (int i = 0; i < kTestRepeatCount; ++i) {
+    EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+    semaphore_wait(adapter_state_changed_callback_sem_);
+    EXPECT_EQ(GetState(), BT_STATE_ON) <<  "Adapter did not turn on.";
+
+    EXPECT_EQ(bt_interface()->create_bond(&bdaddr, BT_TRANSPORT_BR_EDR),
+              BT_STATUS_SUCCESS);
+
+    EXPECT_EQ(bt_interface()->cancel_bond(&bdaddr), BT_STATUS_SUCCESS);
+
+    EXPECT_EQ(bt_interface()->disable(), BT_STATUS_SUCCESS);
+    semaphore_wait(adapter_state_changed_callback_sem_);
+    EXPECT_EQ(GetState(), BT_STATE_OFF) << "Adapter did not turn off.";
+  }
+}
+
+}  // bttest
diff --git a/bt/test/suite/adapter/bluetooth_test.cc b/bt/test/suite/adapter/bluetooth_test.cc
new file mode 100644
index 0000000..0ee88da
--- /dev/null
+++ b/bt/test/suite/adapter/bluetooth_test.cc
@@ -0,0 +1,159 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "adapter/bluetooth_test.h"
+#include <mutex>
+#include "btcore/include/bdaddr.h"
+#include "btcore/include/property.h"
+
+namespace {
+
+// Mutex lock used by callbacks to protect |callback_semaphores_| from
+// racey behaviour caused when Wait and Notify are called at the same time
+std::mutex callback_lock;
+
+}  // namespace
+
+namespace bttest {
+
+void BluetoothTest::SetUp() {
+  bt_interface_ = nullptr;
+  state_ = BT_STATE_OFF;
+  properties_changed_count_ = 0;
+  last_changed_properties_ = nullptr;
+  remote_device_properties_changed_count_ = 0;
+  remote_device_last_changed_properties_ = nullptr;
+  discovery_state_ = BT_DISCOVERY_STOPPED;
+  acl_state_ = BT_ACL_STATE_DISCONNECTED;
+  bond_state_ = BT_BOND_STATE_NONE;
+
+  adapter_properties_callback_sem_ = semaphore_new(0);
+  remote_device_properties_callback_sem_ = semaphore_new(0);
+  adapter_state_changed_callback_sem_ = semaphore_new(0);
+  discovery_state_changed_callback_sem_ = semaphore_new(0);
+
+  bluetooth::hal::BluetoothInterface::Initialize();
+  ASSERT_TRUE(bluetooth::hal::BluetoothInterface::IsInitialized());
+  auto bt_hal_interface = bluetooth::hal::BluetoothInterface::Get();
+  bt_hal_interface->AddObserver(this);
+  bt_interface_ = bt_hal_interface->GetHALInterface();
+  ASSERT_NE(nullptr, bt_interface_) << "bt_interface is null.";
+}
+
+void BluetoothTest::TearDown() {
+  semaphore_free(adapter_properties_callback_sem_);
+  semaphore_free(remote_device_properties_callback_sem_);
+  semaphore_free(adapter_state_changed_callback_sem_);
+  semaphore_free(discovery_state_changed_callback_sem_);
+
+  auto bt_hal_interface = bluetooth::hal::BluetoothInterface::Get();
+  bt_hal_interface->RemoveObserver(this);
+  bt_hal_interface->CleanUp();
+  ASSERT_FALSE(bt_hal_interface->IsInitialized());
+}
+
+void BluetoothTest::ClearSemaphore(semaphore_t* sem) {
+  while (semaphore_try_wait(sem));
+}
+
+const bt_interface_t* BluetoothTest::bt_interface() {
+  return bt_interface_;
+}
+
+bt_state_t BluetoothTest::GetState() {
+  return state_;
+}
+
+int BluetoothTest::GetPropertiesChangedCount() {
+  return properties_changed_count_;
+}
+
+bt_property_t* BluetoothTest::GetProperty(bt_property_type_t type) {
+  for (int i = 0; i < properties_changed_count_; ++i) {
+    if (last_changed_properties_[i].type == type) {
+      return &last_changed_properties_[i];
+    }
+  }
+  return nullptr;
+}
+
+bt_property_t* BluetoothTest::GetRemoteDeviceProperty(const bt_bdaddr_t* addr,
+                                                      bt_property_type_t type) {
+  if (!bdaddr_equals(&curr_remote_device_, addr))
+    return nullptr;
+
+  for (int i = 0; i < remote_device_properties_changed_count_; i++) {
+    if (remote_device_last_changed_properties_[i].type == type) {
+      return &remote_device_last_changed_properties_[i];
+    }
+  }
+  return nullptr;
+}
+
+bt_discovery_state_t BluetoothTest::GetDiscoveryState() {
+  return discovery_state_;
+}
+
+bt_acl_state_t BluetoothTest::GetAclState() {
+  return acl_state_;
+}
+
+// Returns the device bond state.
+bt_bond_state_t BluetoothTest::GetBondState() {
+  return bond_state_;
+}
+
+// callback
+void BluetoothTest::AdapterStateChangedCallback(bt_state_t new_state) {
+  state_ = new_state;
+  semaphore_post(adapter_state_changed_callback_sem_);
+}
+
+// callback
+void BluetoothTest::AdapterPropertiesCallback(
+    bt_status_t status,
+    int num_properties,
+    bt_property_t* new_properties) {
+  property_free_array(last_changed_properties_, properties_changed_count_);
+  last_changed_properties_ = property_copy_array(new_properties, num_properties);
+  properties_changed_count_ = num_properties;
+  semaphore_post(adapter_properties_callback_sem_);
+}
+
+//callback
+void BluetoothTest::RemoteDevicePropertiesCallback(
+    bt_status_t status,
+    bt_bdaddr_t *remote_bd_addr,
+    int num_properties,
+    bt_property_t *properties) {
+  bdaddr_copy(&curr_remote_device_, remote_bd_addr);
+  property_free_array(remote_device_last_changed_properties_,
+                      remote_device_properties_changed_count_);
+  remote_device_last_changed_properties_ = property_copy_array(properties,
+                                                               num_properties);
+  remote_device_properties_changed_count_ = num_properties;
+  semaphore_post(remote_device_properties_callback_sem_);
+}
+
+// callback
+void BluetoothTest::DiscoveryStateChangedCallback(bt_discovery_state_t state) {
+  discovery_state_ = state;
+  semaphore_post(discovery_state_changed_callback_sem_);
+}
+
+} // bttest
diff --git a/bt/test/suite/adapter/bluetooth_test.h b/bt/test/suite/adapter/bluetooth_test.h
new file mode 100644
index 0000000..e655ab4
--- /dev/null
+++ b/bt/test/suite/adapter/bluetooth_test.h
@@ -0,0 +1,123 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR 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 <gtest/gtest.h>
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
+#include <hardware/bt_pan.h>
+#include <hardware/bt_sock.h>
+#include <hardware/hardware.h>
+#include <signal.h>
+#include <time.h>
+#include <map>
+#include <string>
+#include "osi/include/semaphore.h"
+#include "service/hal/bluetooth_interface.h"
+
+namespace bttest {
+
+// This class represents the Bluetooth testing framework and provides
+// helpers and callbacks for GUnit to use for testing.
+class BluetoothTest : public ::testing::Test,
+                      public bluetooth::hal::BluetoothInterface::Observer {
+ protected:
+  BluetoothTest() = default;
+  virtual ~BluetoothTest() = default;
+
+  // Getter for the bt_interface
+  const bt_interface_t* bt_interface();
+
+  // Gets the current state of the Bluetooth Interface
+  bt_state_t GetState();
+
+  // Get the number of properties that have changed on the
+  // Adapter Properties callback
+  int GetPropertiesChangedCount();
+
+  // Get the value of a specific property
+  bt_property_t* GetProperty(bt_property_type_t type);
+
+  // Get the value of a specific remote device property
+  bt_property_t* GetRemoteDeviceProperty(const bt_bdaddr_t* addr,
+                                         bt_property_type_t type);
+
+  // Get the current discovery state
+  bt_discovery_state_t GetDiscoveryState();
+
+  // Get the current Acl State
+  bt_acl_state_t GetAclState();
+
+  // Get the current Bond State
+  bt_bond_state_t GetBondState();
+
+  // Reset a semaphores count to 0
+  void ClearSemaphore(semaphore_t* sem);
+
+  // SetUp initializes the Bluetooth interface and registers the callbacks
+  // before running every test
+  void SetUp() override;
+
+  // TearDown cleans up the stack and interface at the end of every test
+  void TearDown() override;
+
+  // A callback that is called when a property changes
+  void AdapterPropertiesCallback(
+      bt_status_t status,
+      int num_properties,
+      bt_property_t *properties) override;
+
+  // A callback that is called when the remote device's property changes
+  void RemoteDevicePropertiesCallback(
+      bt_status_t status,
+      bt_bdaddr_t *remote_bd_addr,
+      int num_properties,
+      bt_property_t *properties) override;
+
+  // A callback that is called when the adapter state changes
+  void AdapterStateChangedCallback(bt_state_t state) override;
+
+  // A callback that is called when the Discovery state changes
+  void DiscoveryStateChangedCallback(bt_discovery_state_t state) override;
+
+  // Semaphores used to wait for specific callback execution. Each callback
+  // has its own semaphore associated with it.
+  semaphore_t* adapter_properties_callback_sem_;
+  semaphore_t* remote_device_properties_callback_sem_;
+  semaphore_t* adapter_state_changed_callback_sem_;
+  semaphore_t* discovery_state_changed_callback_sem_;
+
+ private:
+  // The bluetooth interface that all the tests use to interact with the HAL
+  const bt_interface_t* bt_interface_;
+
+  bt_state_t state_;
+  int properties_changed_count_;
+  bt_property_t *last_changed_properties_;
+  bt_bdaddr_t curr_remote_device_;
+  int remote_device_properties_changed_count_;
+  bt_property_t *remote_device_last_changed_properties_;
+  bt_discovery_state_t discovery_state_;
+  bt_acl_state_t acl_state_;
+  bt_bond_state_t bond_state_;
+
+  DISALLOW_COPY_AND_ASSIGN(BluetoothTest);
+};
+
+}  // bttest
diff --git a/bt/test/suite/gatt/gatt_test.cc b/bt/test/suite/gatt/gatt_test.cc
new file mode 100644
index 0000000..50791f1
--- /dev/null
+++ b/bt/test/suite/gatt/gatt_test.cc
@@ -0,0 +1,143 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "gatt/gatt_test.h"
+#include "adapter/bluetooth_test.h"
+#include "btcore/include/bdaddr.h"
+
+namespace bttest {
+
+void GattTest::SetUp() {
+  gatt_client_interface_ = nullptr;
+  gatt_server_interface_ = nullptr;
+
+  client_interface_id_ = 0;
+  server_interface_id_ = 0;
+  service_handle_ = 0;
+  characteristic_handle_ = 0;
+  descriptor_handle_ = 0;
+  status_ = 0;
+
+  BluetoothTest::SetUp();
+  ASSERT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+  semaphore_wait(adapter_state_changed_callback_sem_);
+  EXPECT_TRUE(GetState() == BT_STATE_ON);
+
+  register_client_callback_sem_ = semaphore_new(0);
+  scan_result_callback_sem_ = semaphore_new(0);
+
+  register_server_callback_sem_ = semaphore_new(0);
+  service_added_callback_sem_ = semaphore_new(0);
+  service_stopped_callback_sem_ = semaphore_new(0);
+  service_deleted_callback_sem_ = semaphore_new(0);
+
+  bluetooth::hal::BluetoothGattInterface::Initialize();
+  ASSERT_TRUE(bluetooth::hal::BluetoothGattInterface::IsInitialized());
+  auto gatt_interface = bluetooth::hal::BluetoothGattInterface::Get();
+  gatt_interface->AddClientObserver(this);
+  gatt_interface->AddServerObserver(this);
+
+  gatt_client_interface_ = gatt_interface->GetClientHALInterface();
+  gatt_server_interface_ = gatt_interface->GetServerHALInterface();
+
+  ASSERT_NE(nullptr, gatt_client_interface_);
+  ASSERT_NE(nullptr, gatt_server_interface_);
+}
+
+void GattTest::TearDown() {
+  gatt_client_interface_ = nullptr;
+  gatt_server_interface_ = nullptr;
+
+  semaphore_free(register_client_callback_sem_);
+  semaphore_free(scan_result_callback_sem_);
+
+  semaphore_free(register_server_callback_sem_);
+  semaphore_free(service_added_callback_sem_);
+  semaphore_free(service_stopped_callback_sem_);
+  semaphore_free(service_deleted_callback_sem_);
+
+  bluetooth::hal::BluetoothGattInterface::CleanUp();
+
+  ASSERT_EQ(bt_interface()->disable(), BT_STATUS_SUCCESS);
+  semaphore_wait(adapter_state_changed_callback_sem_);
+  BluetoothTest::TearDown();
+}
+
+const btgatt_scanner_interface_t* GattTest::gatt_scanner_interface() {
+  return gatt_scanner_interface_;
+}
+
+const btgatt_client_interface_t* GattTest::gatt_client_interface() {
+  return gatt_client_interface_;
+}
+
+const btgatt_server_interface_t* GattTest::gatt_server_interface() {
+  return gatt_server_interface_;
+}
+
+void GattTest::RegisterClientCallback(
+    bluetooth::hal::BluetoothGattInterface* /* unused */,
+    int status, int clientIf, const bt_uuid_t& app_uuid) {
+  status_ = status;
+  client_interface_id_ = clientIf;
+  semaphore_post(register_client_callback_sem_);
+}
+
+void GattTest::ScanResultCallback(
+    bluetooth::hal::BluetoothGattInterface* /* unused */,
+    const bt_bdaddr_t& bda, int rssi, vector<uint8_t> adv_data) {
+  semaphore_post(scan_result_callback_sem_);
+}
+
+// GATT server callbacks
+void GattTest::RegisterServerCallback(
+    bluetooth::hal::BluetoothGattInterface* /* unused */,
+    int status, int server_if, const bt_uuid_t& uuid) {
+  status_ = status;
+  server_interface_id_ = server_if;
+  semaphore_post(register_server_callback_sem_);
+}
+
+void GattTest::ServiceAddedCallback(
+    bluetooth::hal::BluetoothGattInterface* /* unused */,
+    int status, int server_if, vector<btgatt_db_element_t> service) {
+  status_ = status;
+  server_interface_id_ = server_if;
+  service_handle_ = service[0].attribute_handle;
+  semaphore_post(service_added_callback_sem_);
+}
+
+void GattTest::ServiceStoppedCallback(
+    bluetooth::hal::BluetoothGattInterface* /* unused */,
+    int status, int server_if, int srvc_handle) {
+  status_ = status;
+  server_interface_id_ = server_if;
+  service_handle_ = srvc_handle;
+  semaphore_post(service_stopped_callback_sem_);
+}
+
+void GattTest::ServiceDeletedCallback(
+    bluetooth::hal::BluetoothGattInterface* /* unused */,
+    int status, int server_if, int srvc_handle) {
+  status_ = status;
+  server_interface_id_ = server_if;
+  service_handle_ = srvc_handle;
+  semaphore_post(service_deleted_callback_sem_);
+}
+
+}  // bttest
diff --git a/bt/test/suite/gatt/gatt_test.h b/bt/test/suite/gatt/gatt_test.h
new file mode 100644
index 0000000..b9bdd08
--- /dev/null
+++ b/bt/test/suite/gatt/gatt_test.h
@@ -0,0 +1,129 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "adapter/bluetooth_test.h"
+#include "service/hal/bluetooth_gatt_interface.h"
+
+namespace bttest {
+
+// This class represents the Bluetooth GATT testing framework and provides
+// helpers and callbacks for GUnit to use for testing gatt.
+class GattTest : public BluetoothTest,
+                 public bluetooth::hal::BluetoothGattInterface::ClientObserver,
+                 public bluetooth::hal::BluetoothGattInterface::ScannerObserver,
+                 public bluetooth::hal::BluetoothGattInterface::ServerObserver {
+ protected:
+  GattTest() = default;
+  virtual ~GattTest() = default;
+
+  // Gets the gatt_scanner_interface
+  const btgatt_scanner_interface_t* gatt_scanner_interface();
+
+  // Gets the gatt_client_interface
+  const btgatt_client_interface_t* gatt_client_interface();
+
+  // Gets the gatt_server_interface
+  const btgatt_server_interface_t* gatt_server_interface();
+
+  // Getters for variables that track GATT-related state
+  int client_interface_id() const { return client_interface_id_; }
+  int server_interface_id() const { return server_interface_id_; }
+  int service_handle() const { return service_handle_; }
+  int characteristic_handle() const { return characteristic_handle_; }
+  int descriptor_handle() const { return descriptor_handle_; }
+  int status() const { return status_; }
+
+  // SetUp initializes the Bluetooth interfaces and the GATT Interface as well
+  // as registers the callbacks and initializes the semaphores before every test
+  virtual void SetUp();
+
+  // TearDown cleans up the Bluetooth and GATT interfaces and destroys the
+  // callback semaphores at the end of every test
+  virtual void TearDown();
+
+  // bluetooth::hal::BluetoothGattInterface::ClientObserver overrides
+  void RegisterClientCallback(
+      bluetooth::hal::BluetoothGattInterface* /* unused */,
+      int status, int clientIf, const bt_uuid_t& app_uuid) override;
+  void ScanResultCallback(
+      bluetooth::hal::BluetoothGattInterface* /* unused */,
+      const bt_bdaddr_t& bda, int rssi, vector<uint8_t> adv_data) override;
+
+  // bluetooth::hal::BluetoothGattInterface::ServerObserver overrides
+  void RegisterServerCallback(
+      bluetooth::hal::BluetoothGattInterface* /* unused */,
+      int status, int server_if, const bt_uuid_t& uuid) override;
+  void ServiceAddedCallback(
+      bluetooth::hal::BluetoothGattInterface* /* unused */,
+      int status, int server_if, vector<btgatt_db_element_t> service) override;
+  void ServiceStoppedCallback(
+      bluetooth::hal::BluetoothGattInterface* /* unused */,
+      int status, int server_if, int srvc_handle) override;
+  void ServiceDeletedCallback(
+      bluetooth::hal::BluetoothGattInterface* /* unused */,
+      int status, int server_if, int srvc_handle) override;
+
+  // Semaphores used to wait for specific callback execution. Each callback
+  // has its own semaphore associated with it
+  semaphore_t* register_client_callback_sem_;
+  semaphore_t* scan_result_callback_sem_;
+  semaphore_t* listen_callback_sem_;
+
+  semaphore_t* register_server_callback_sem_;
+  semaphore_t* service_added_callback_sem_;
+  semaphore_t* characteristic_added_callback_sem_;
+  semaphore_t* descriptor_added_callback_sem_;
+  semaphore_t* service_started_callback_sem_;
+  semaphore_t* service_stopped_callback_sem_;
+  semaphore_t* service_deleted_callback_sem_;
+
+ private:
+  // The btgatt_scanner_interface_t that all the tests use to interact with the HAL
+  const btgatt_scanner_interface_t* gatt_scanner_interface_;
+
+  // The gatt_client_interface that all the tests use to interact with the HAL
+  const btgatt_client_interface_t* gatt_client_interface_;
+
+  // The gatt_server_interface that all the tests use to interact with the HAL
+  const btgatt_server_interface_t* gatt_server_interface_;
+
+  // No mutex needed for these as the semaphores should ensure
+  // synchronous access
+
+  // An ID that is used as a handle for each gatt client.
+  int client_interface_id_;
+
+  // An ID that is used as a handle for each gatt server.
+  int server_interface_id_;
+
+  // A handle to the last used service.
+  int service_handle_;
+
+  // A handle to the last characteristic added.
+  int characteristic_handle_;
+
+  // A handle to the last descriptor added.
+  int descriptor_handle_;
+
+  // The status of the last callback. Is BT_STATUS_SUCCESS if no issues.
+  int status_;
+
+  DISALLOW_COPY_AND_ASSIGN(GattTest);
+};
+
+}  // bttest
diff --git a/bt/test/suite/gatt/gatt_unittest.cc b/bt/test/suite/gatt/gatt_unittest.cc
new file mode 100644
index 0000000..64435a3
--- /dev/null
+++ b/bt/test/suite/gatt/gatt_unittest.cc
@@ -0,0 +1,115 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2015 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "gatt/gatt_test.h"
+
+#define DEFAULT_RANDOM_SEED 42
+
+namespace {
+
+static void create_random_uuid(bt_uuid_t *uuid, int seed) {
+  srand(seed < 0 ? time(NULL) : seed);
+  for (int i = 0; i < 16; ++i) {
+    uuid->uu[i] = (uint8_t) (rand() % 256);
+  }
+}
+
+}  // namespace
+
+namespace bttest {
+
+TEST_F(GattTest, GattClientRegister) {
+  // Registers gatt client.
+  bt_uuid_t gatt_client_uuid;
+  create_random_uuid(&gatt_client_uuid, DEFAULT_RANDOM_SEED);
+  gatt_client_interface()->register_client(&gatt_client_uuid);
+  semaphore_wait(register_client_callback_sem_);
+  EXPECT_TRUE(status() == BT_STATUS_SUCCESS)
+    << "Error registering GATT client app callback.";
+
+  // Unregisters gatt client. No callback is expected.
+  gatt_client_interface()->unregister_client(client_interface_id());
+}
+
+TEST_F(GattTest, GattServerRegister) {
+  // Registers gatt server.
+  bt_uuid_t gatt_server_uuid;
+  create_random_uuid(&gatt_server_uuid, DEFAULT_RANDOM_SEED);
+  gatt_server_interface()->register_server(&gatt_server_uuid);
+  semaphore_wait(register_server_callback_sem_);
+  EXPECT_TRUE(status() == BT_STATUS_SUCCESS)
+    << "Error registering GATT server app callback.";
+
+  // Unregisters gatt server. No callback is expected.
+  gatt_server_interface()->unregister_server(server_interface_id());
+}
+
+TEST_F(GattTest, GattServerBuild) {
+  // Registers gatt server.
+  bt_uuid_t gatt_server_uuid;
+  create_random_uuid(&gatt_server_uuid, DEFAULT_RANDOM_SEED);
+  gatt_server_interface()->register_server(&gatt_server_uuid);
+  semaphore_wait(register_server_callback_sem_);
+  EXPECT_TRUE(status() == BT_STATUS_SUCCESS)
+    << "Error registering GATT server app callback.";
+
+  // Service UUID.
+  bt_uuid_t srvc_uuid;
+  create_random_uuid(&srvc_uuid, -1);
+
+  // Characteristics UUID.
+  bt_uuid_t char_uuid;
+  create_random_uuid(&char_uuid, -1);
+
+  // Descriptor UUID.
+  bt_uuid_t desc_uuid;
+  create_random_uuid(&desc_uuid, -1);
+
+  // Adds service.
+  int server_if = server_interface_id();
+
+  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}
+  };
+
+  gatt_server_interface()->add_service(server_if, service);
+  semaphore_wait(service_added_callback_sem_);
+  EXPECT_TRUE(status() == BT_STATUS_SUCCESS) << "Error adding service.";
+
+  // Stops server.
+  gatt_server_interface()->stop_service(server_if, service_handle());
+  semaphore_wait(service_stopped_callback_sem_);
+  EXPECT_TRUE(status() == BT_STATUS_SUCCESS) << "Error stopping server.";
+
+  // Deletes service.
+  gatt_server_interface()->delete_service(server_if, service_handle());
+  semaphore_wait(service_deleted_callback_sem_);
+  EXPECT_TRUE(status() == BT_STATUS_SUCCESS) << "Error deleting service.";
+
+  // Unregisters gatt server. No callback is expected.
+  gatt_server_interface()->unregister_server(server_if);
+}
+
+}  // bttest
diff --git a/bt/test/suite/rfcomm/rfcomm_test.cc b/bt/test/suite/rfcomm/rfcomm_test.cc
new file mode 100644
index 0000000..93a23f1
--- /dev/null
+++ b/bt/test/suite/rfcomm/rfcomm_test.cc
@@ -0,0 +1,83 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "adapter/bluetooth_test.h"
+#include "rfcomm/rfcomm_test.h"
+
+#include "btcore/include/bdaddr.h"
+#include "btcore/include/uuid.h"
+
+namespace bttest {
+
+const bt_uuid_t RFCommTest::HFP_UUID = {{ 0x00, 0x00, 0x11, 0x1E,
+                                          0x00, 0x00, 0x10, 0x00,
+                                          0x80, 0x00, 0x00, 0x80,
+                                          0x5F, 0x9B, 0x34, 0xFB }};
+
+void RFCommTest::SetUp(){
+  BluetoothTest::SetUp();
+
+  ASSERT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+  semaphore_wait(adapter_state_changed_callback_sem_);
+  ASSERT_TRUE(GetState() == BT_STATE_ON);
+  socket_interface_ = (const btsock_interface_t *)bt_interface()->
+                         get_profile_interface(BT_PROFILE_SOCKETS_ID);
+  ASSERT_NE(socket_interface_, nullptr);
+
+  // Find a bonded device that supports HFP
+  string_to_bdaddr("00:00:00:00:00:00", &bt_remote_bdaddr_);
+  char value[1280];
+
+  bt_property_t* bonded_devices_prop = GetProperty(BT_PROPERTY_ADAPTER_BONDED_DEVICES);
+  bt_bdaddr_t* devices = (bt_bdaddr_t*)bonded_devices_prop->val;
+  int num_bonded_devices = bonded_devices_prop->len / sizeof(bt_bdaddr_t);
+
+  for (int i = 0; i < num_bonded_devices && bdaddr_is_empty(&bt_remote_bdaddr_); i++) {
+    ClearSemaphore(remote_device_properties_callback_sem_);
+    bt_interface()->get_remote_device_property(&devices[i], BT_PROPERTY_UUIDS);
+    semaphore_wait(remote_device_properties_callback_sem_);
+
+    bt_property_t* uuid_prop = GetRemoteDeviceProperty(&devices[i], BT_PROPERTY_UUIDS);
+    if (uuid_prop == nullptr)
+      continue;
+    bt_uuid_t* uuids = (bt_uuid_t*) uuid_prop->val;
+    int num_uuids = uuid_prop->len / sizeof(bt_uuid_t);
+
+    for (int j = 0; j < num_uuids; j++) {
+      uuid_to_string(&uuids[j], (uuid_string_t*)value);
+      if (!memcmp(uuids + j, &HFP_UUID, sizeof(bt_uuid_t))) {
+        bdaddr_copy(&bt_remote_bdaddr_, devices+i);
+        break;
+      }
+    }
+  }
+
+  ASSERT_FALSE(bdaddr_is_empty(&bt_remote_bdaddr_))
+      << "Could not find paired device that supports HFP";
+}
+
+void RFCommTest::TearDown() {
+  socket_interface_ = NULL;
+
+  ASSERT_EQ(bt_interface()->disable(), BT_STATUS_SUCCESS);
+  semaphore_wait(adapter_state_changed_callback_sem_);
+
+  BluetoothTest::TearDown();
+}
+
+}  // bttest
diff --git a/bt/test/suite/rfcomm/rfcomm_test.h b/bt/test/suite/rfcomm/rfcomm_test.h
new file mode 100644
index 0000000..c7e5a7b
--- /dev/null
+++ b/bt/test/suite/rfcomm/rfcomm_test.h
@@ -0,0 +1,46 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "adapter/bluetooth_test.h"
+
+namespace bttest {
+
+class RFCommTest : public BluetoothTest {
+ protected:
+  RFCommTest() = default;
+  virtual ~RFCommTest() = default;
+
+  // Getter for the RFCOMM socket
+  const btsock_interface_t* socket_interface() const
+    { return socket_interface_; }
+
+  // SetUp initializes the Bluetooth interfaces and the RFCOMM interface
+  virtual void SetUp();
+
+  // TearDown cleans up the Bluetooth and RFCOMM interfaces
+  virtual void TearDown();
+
+  bt_bdaddr_t bt_remote_bdaddr_;
+
+  static const bt_uuid_t HFP_UUID;
+
+ private:
+  const btsock_interface_t *socket_interface_;
+};
+
+}  // bttest
diff --git a/bt/test/suite/rfcomm/rfcomm_unittest.cc b/bt/test/suite/rfcomm/rfcomm_unittest.cc
new file mode 100644
index 0000000..c9fd9d6
--- /dev/null
+++ b/bt/test/suite/rfcomm/rfcomm_unittest.cc
@@ -0,0 +1,130 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "adapter/bluetooth_test.h"
+#include "rfcomm/rfcomm_test.h"
+
+#include "btcore/include/bdaddr.h"
+
+#include <sys/socket.h>
+#include <unistd.h>
+
+namespace {
+static const char HANDSHAKE_COMMAND[] = "AT+BRSF=29\r";
+}  // namespace
+
+namespace bttest {
+
+TEST_F(RFCommTest, RfcommConnectPairedDevice) {
+  int fd = -1;
+  int error = 0;
+  size_t len = 0;
+
+  error = socket_interface()->connect(&bt_remote_bdaddr_, BTSOCK_RFCOMM,
+                                      (const uint8_t *)&HFP_UUID, 0, &fd, 0, getuid());
+  EXPECT_TRUE(error == BT_STATUS_SUCCESS)
+    << "Error creating RFCOMM socket: " << error;
+  EXPECT_TRUE(fd != -1) << "Error creating RFCOMM socket: invalid fd";
+
+  int channel;
+  sock_connect_signal_t signal;
+  len = read(fd, &channel, sizeof(channel));
+  EXPECT_TRUE(len == sizeof(channel))
+    << "Channel not read from RFCOMM socket. Bytes read: " << len;
+  len = read(fd, &signal, sizeof(signal));
+  EXPECT_TRUE(len == sizeof(signal))
+    << "Connection signal not read from RFCOMM socket. Bytes read: " << len;
+
+  EXPECT_TRUE(!memcmp(&signal.bd_addr, &bt_remote_bdaddr_, sizeof(bt_bdaddr_t)))
+    << "Connected to a different bdaddr than expected.";
+  EXPECT_TRUE(channel == signal.channel) << "Inconsistent channels returned: "
+    << channel << " and " << signal.channel;
+
+  len = write(fd, HANDSHAKE_COMMAND, sizeof(HANDSHAKE_COMMAND));
+  EXPECT_TRUE( len == sizeof(HANDSHAKE_COMMAND))
+    << "Unable to send HFP handshake. Bytes written: " << len;
+
+  char response[1024];
+  len = read(fd, response, sizeof(response));
+  EXPECT_TRUE(len > 0) << "Read " << len << " bytes";
+
+  close(fd);
+}
+
+TEST_F(RFCommTest, RfcommRepeatedConnectPairedDevice) {
+  static const int max_iterations = 128;
+  int channel_fail = 0, signal_fail = 0, handshake_fail = 0, read_fail = 0;
+
+  for (int i = 0; i < max_iterations; ++i) {
+      int fd = -1;
+      int error = 0;
+      size_t len = 0;
+
+      error = socket_interface()->connect(&bt_remote_bdaddr_, BTSOCK_RFCOMM,
+                                        (const uint8_t *)&HFP_UUID, 0,
+                                        &fd, 0, getuid());
+      ASSERT_TRUE(error == BT_STATUS_SUCCESS)
+        << "Error creating RFCOMM socket: " << error;
+      ASSERT_TRUE(fd != -1) << "Error creating RFCOMM socket: invalid fd";
+
+      int channel;
+      sock_connect_signal_t signal;
+      if ((len = read(fd, &channel, sizeof(channel))) != sizeof(channel)) {
+        ADD_FAILURE() << "Channel not read from RFCOMM socket. Bytes read: " << len
+                      << ", Sizeof channel: " << sizeof(channel);
+        channel_fail++;
+      }
+
+      if ((len = read(fd, &signal, sizeof(signal))) != sizeof(signal)) {
+        ADD_FAILURE() << "Connection signal not read from RFCOMM socket. Bytes read: "
+                      << len;
+        signal_fail++;
+      }
+
+      EXPECT_TRUE(!memcmp(&signal.bd_addr, &bt_remote_bdaddr_,
+                  sizeof(bt_bdaddr_t)))
+        << "Connected to a different bdaddr than expected.";
+      EXPECT_TRUE(channel == signal.channel)
+        << "Inconsistent channels returned: " << channel << " and "
+        << signal.channel;
+
+      if ((len = write(fd, HANDSHAKE_COMMAND, sizeof(HANDSHAKE_COMMAND))) !=
+          sizeof(HANDSHAKE_COMMAND)) {
+        ADD_FAILURE() << "Unable to send HFP handshake. Bytes written: " << len;
+        handshake_fail++;
+      }
+
+      char response[1024];
+      if ((len = read(fd, response, sizeof(response))) <= 0) {
+          ADD_FAILURE() << "Read " << len << " bytes";
+          read_fail++;
+      }
+
+      close(fd);
+  }
+
+  if (channel_fail > 0 || signal_fail > 0 ||
+      handshake_fail > 0 || read_fail > 0) {
+      ADD_FAILURE() << "Number of channel read fails: " << channel_fail << "\n"
+                    << "Number of signal read fails: " << signal_fail << "\n"
+                    << "Number of handshake send fails: " << handshake_fail << "\n"
+                    << "Number of read response fails: " << read_fail;
+  }
+}
+
+}  // bttest
diff --git a/bt/tools/Android.mk.disabled b/bt/tools/Android.mk.disabled
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/bt/tools/Android.mk.disabled
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/bt/tools/bdtool/Android.mk.disabled b/bt/tools/bdtool/Android.mk.disabled
new file mode 100644
index 0000000..fa616e5
--- /dev/null
+++ b/bt/tools/bdtool/Android.mk.disabled
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# Bluetooth tools for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := net_bdtool
+
+LOCAL_SRC_FILES := \
+  adapter.c \
+  bdtool.c \
+  ../../test/suite/support/callbacks.c \
+  ../../test/suite/support/gatt.c \
+  ../../test/suite/support/hal.c \
+  ../../test/suite/support/pan.c
+
+LOCAL_STATIC_LIBRARIES := \
+  libbtcore \
+  libosi
+
+LOCAL_C_INCLUDES := \
+  $(LOCAL_PATH)/../../test/suite \
+  $(LOCAL_PATH)/../..
+
+LOCAL_SHARED_LIBRARIES := \
+  libhardware liblog
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_EXECUTABLE)
diff --git a/bt/tools/bdtool/adapter.c b/bt/tools/bdtool/adapter.c
new file mode 100644
index 0000000..dde8d41
--- /dev/null
+++ b/bt/tools/bdtool/adapter.c
@@ -0,0 +1,306 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 "base.h"
+#include "btcore/include/bdaddr.h"
+#include "btcore/include/property.h"
+#include "support/adapter.h"
+#include "support/callbacks.h"
+
+static bt_state_t state;
+static int property_count = 0;
+static bt_property_t *properties = NULL;
+static bt_discovery_state_t discovery_state;
+static bt_acl_state_t acl_state;
+static bt_bond_state_t bond_state;
+
+static void parse_properties(int num_properties, bt_property_t *property);
+
+// Returns the current adapter state.
+bt_state_t adapter_get_state() {
+  return state;
+}
+
+// Returns the number of adapter properties.
+int adapter_get_property_count() {
+  return property_count;
+}
+
+// Returns the specified property.
+bt_property_t *adapter_get_property(bt_property_type_t type) {
+  for (int i = 0; i < property_count; ++i) {
+    if (properties[i].type == type) {
+      return &properties[i];
+    }
+  }
+
+  return NULL;
+}
+
+// Returns the device discovery state.
+bt_discovery_state_t adapter_get_discovery_state() {
+  return discovery_state;
+}
+
+// Returns the device acl state.
+bt_acl_state_t adapter_get_acl_state() {
+  return acl_state;
+}
+
+// Returns the device bond state.
+bt_bond_state_t adapter_get_bond_state() {
+  return bond_state;
+}
+
+// callback
+void acl_state_changed(bt_status_t status, bt_bdaddr_t *remote_bd_addr, bt_acl_state_t state) {
+  acl_state = state;
+  CALLBACK_RET();
+}
+
+// callback
+void adapter_properties(bt_status_t status,
+    int num_properties,
+    bt_property_t *new_properties) {
+  property_free_array(properties, property_count);
+  properties = property_copy_array(new_properties, num_properties);
+  property_count = num_properties;
+
+  CALLBACK_RET();
+}
+
+// callback
+void adapter_state_changed(bt_state_t new_state) {
+  state = new_state;
+  CALLBACK_RET();
+}
+
+// callback
+void bond_state_changed(bt_status_t status,
+    bt_bdaddr_t *bdaddr,
+    bt_bond_state_t state) {
+  char buf[18];
+  bond_state = state;
+
+  const char *state_name = "Bond state unknown";
+  switch (bond_state) {
+    case BT_BOND_STATE_NONE:
+      state_name = "Bond state none";
+      break;
+
+    case BT_BOND_STATE_BONDING:
+      state_name = "Bond state bonding";
+      break;
+
+    case BT_BOND_STATE_BONDED:
+      state_name = "Bond state bonded";
+      break;
+
+      // default none
+  }
+  fprintf(stdout, "Bond state changed callback addr:%s state:%s\n", bdaddr_to_string(bdaddr, buf, sizeof(buf)), state_name);
+
+  CALLBACK_RET();
+}
+
+// callback
+void device_found(int num_properties, bt_property_t *property) {
+  fprintf(stdout, "Device found num_properties:%d\n", num_properties);
+  parse_properties(num_properties, property);
+
+  CALLBACK_RET();
+}
+
+// callback
+void discovery_state_changed(bt_discovery_state_t state) {
+  const char *state_name = "Unknown";
+  discovery_state = state;
+
+  switch (discovery_state) {
+    case BT_DISCOVERY_STOPPED:
+      state_name = "Discovery stopped";
+      break;
+
+    case BT_DISCOVERY_STARTED:
+      state_name = "Discovery started";
+      break;
+
+      // default omitted
+  }
+  fprintf(stdout, "Discover state %s\n", state_name);
+
+  CALLBACK_RET();
+}
+
+// callback
+void remote_device_properties(bt_status_t status,
+    bt_bdaddr_t *bdaddr,
+    int num_properties,
+    bt_property_t *properties) {
+  char buf[18];
+  fprintf(stdout, "Device found bdaddr:%s num_properties:%d\n",
+      bdaddr_to_string(bdaddr, buf, sizeof(buf)), num_properties);
+
+  parse_properties(num_properties, properties);
+
+  CALLBACK_RET();
+}
+
+// callback
+void ssp_request(
+    bt_bdaddr_t *remote_bd_addr,
+    bt_bdname_t *bd_name,
+    uint32_t cod,
+    bt_ssp_variant_t pairing_variant,
+    uint32_t pass_key) {
+  char *pairing_variant_name = "Unknown";
+
+  switch (pairing_variant) {
+    case BT_SSP_VARIANT_PASSKEY_CONFIRMATION:
+      pairing_variant_name = "Passkey confirmation";
+      break;
+    case BT_SSP_VARIANT_PASSKEY_ENTRY:
+      pairing_variant_name = "Passkey entry";
+      break;
+
+    case BT_SSP_VARIANT_CONSENT:
+      pairing_variant_name = "Passkey consent";
+      break;
+
+    case BT_SSP_VARIANT_PASSKEY_NOTIFICATION:
+      pairing_variant_name = "Passkey notification";
+      break;
+  }
+
+  fprintf(stdout, "Got ssp request device_class:%u passkey:%x pairing_variant:%s\n", cod, pass_key, pairing_variant_name);
+  char buf[18];
+  fprintf(stdout, "Device found:%s %s\n", bdaddr_to_string(remote_bd_addr, buf, sizeof(buf)), bd_name->name);
+
+
+  fprintf(stdout, "auto-accepting bond\n");
+  bool accept = true;
+  int rc = bt_interface->ssp_reply(remote_bd_addr, pairing_variant,
+      (uint8_t)accept, pass_key);
+  CALLBACK_RET();
+}
+
+// callback
+void thread_evt(bt_cb_thread_evt evt) {
+  CALLBACK_RET();
+}
+
+static void parse_properties(int num_properties, bt_property_t *property) {
+  while (num_properties-- > 0) {
+    switch(property->type) {
+      case BT_PROPERTY_BDNAME:
+        {
+          const bt_bdname_t *name = property_as_name(property);
+          if (name)
+            fprintf(stdout, " name:%s\n", name->name);
+        }
+        break;
+
+      case BT_PROPERTY_BDADDR:
+        {
+          char buf[18];
+          const bt_bdaddr_t *addr = property_as_addr(property);
+          if (addr)
+            fprintf(stdout, " addr:%s\n", bdaddr_to_string(addr, buf, sizeof(buf)));
+        }
+        break;
+
+      case BT_PROPERTY_UUIDS:
+        {
+          size_t num_uuid;
+          const bt_uuid_t *uuid = property_as_uuids(property, &num_uuid);
+          if (uuid) {
+            for (size_t i = 0; i < num_uuid; i++) {
+              fprintf(stdout, " uuid:%zd: ", i);
+              for (size_t j = 0; j < sizeof(uuid); j++) {
+                fprintf(stdout, "%02x", uuid->uu[j]);
+              }
+              fprintf(stdout, "\n");
+            }
+          }
+        }
+        break;
+
+      case BT_PROPERTY_TYPE_OF_DEVICE:
+        {
+          bt_device_type_t device_type = property_as_device_type(property);
+          if (device_type) {
+            const struct {
+              const char * device_type;
+            } device_type_lookup[] = {
+              { "Unknown" },
+              { "Classic Only" },
+              { "BLE Only" },
+              { "Both Classic and BLE" },
+            };
+            int idx = (int)device_type;
+            if (idx > BT_DEVICE_DEVTYPE_DUAL)
+              idx = 0;
+            fprintf(stdout, " device_type:%s\n", device_type_lookup[idx].device_type);
+          }
+        }
+        break;
+
+      case BT_PROPERTY_CLASS_OF_DEVICE:
+        {
+          const bt_device_class_t *dc = property_as_device_class(property);
+          int dc_int = device_class_to_int(dc);
+          fprintf(stdout, " device_class:0x%x\n", dc_int);
+        }
+        break;
+
+      case BT_PROPERTY_REMOTE_RSSI:
+        {
+          int8_t rssi = property_as_rssi(property);
+          fprintf(stdout, " rssi:%d\n", rssi);
+        }
+        break;
+
+      case BT_PROPERTY_REMOTE_FRIENDLY_NAME:
+        {
+          const bt_bdname_t *name = property_as_name(property);
+          if (name)
+            fprintf(stdout, " remote_name:%s\n", name->name);
+        }
+        break;
+
+      case BT_PROPERTY_SERVICE_RECORD:
+      case BT_PROPERTY_ADAPTER_SCAN_MODE:
+      case BT_PROPERTY_ADAPTER_BONDED_DEVICES:
+      case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+      case BT_PROPERTY_REMOTE_VERSION_INFO:
+      case BT_PROPERTY_LOCAL_LE_FEATURES:
+      case BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP:
+      default:
+        {
+          fprintf(stderr, "Unhandled property type:%d len:%d\n", property->type, property->len);
+          uint8_t *p = (uint8_t *)property->val;
+          for (int i = 0; i < property->len; ++i, p++) {
+            fprintf(stderr, " %02x", *p);
+          }
+          if (property->len != 0)
+            fprintf(stderr, "\n");
+        }
+    }
+    property++;
+  }
+}
diff --git a/bt/tools/bdtool/bdtool.c b/bt/tools/bdtool/bdtool.c
new file mode 100644
index 0000000..0f81685
--- /dev/null
+++ b/bt/tools/bdtool/bdtool.c
@@ -0,0 +1,336 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <getopt.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "btcore/include/bdaddr.h"
+#include "btcore/include/property.h"
+#include "osi/include/osi.h"
+#include "test/suite/support/callbacks.h"
+#include "test/suite/support/hal.h"
+
+static const bt_uuid_t HFP_UUID = {{ 0x00, 0x00, 0x11, 0x1E, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB }};
+static const bt_uuid_t HFP_AG_UUID = {{ 0x00, 0x00, 0x11, 0x1F, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB }};
+
+const bt_interface_t *bt_interface;
+
+bt_bdaddr_t bt_remote_bdaddr;
+
+static int f_verbose;
+static bool discover = false;
+static bool discoverable = false;
+static bool bond = false;
+static bool up = false;
+static bool get_name = false;
+static bool set_name = false;
+static bool sco_listen = false;
+static bool sco_connect = false;
+
+static int timeout_in_sec = 30;
+static char *bd_name;
+
+static struct option long_options[] = {
+  {"bdaddr", required_argument, 0, 0 },
+  {"discover", no_argument, 0, 0 },
+  {"discoverable", no_argument, 0, 0 },
+  {"time", required_argument, 0, 0 },
+  {"bond", no_argument, 0, 0 },
+  {"up", no_argument, 0, 0 },
+  {"verbose", no_argument, 0, 0 },
+  {"get_name", no_argument, 0, 0 },
+  {"set_name", required_argument, 0, 0 },
+  {"sco_listen", no_argument, 0, 0 },
+  {"sco_connect", no_argument, 0, 0 },
+  {0, 0, 0, 0 }
+};
+
+static void usage(const char *name);
+static bool parse_args(int argc, char **argv);
+static void sig_handler(int signo);
+
+bt_property_t *adapter_get_property(bt_property_type_t type);
+
+int main(int argc, char **argv) {
+  if (!parse_args(argc, argv)) {
+    usage(argv[0]);
+  }
+
+  if (bond && discoverable) {
+    fprintf(stderr, "Can only select either bond or discoverable, not both\n");
+    usage(argv[0]);
+  }
+
+  if (sco_listen && sco_connect) {
+    fprintf(stderr, "Can only select either sco_listen or sco_connect, not both\n");
+    usage(argv[0]);
+  }
+
+  if (!bond && !discover && !discoverable && !up && !get_name && !set_name && !sco_listen && !sco_connect) {
+    fprintf(stderr, "Must specify one command\n");
+    usage(argv[0]);
+  }
+
+  if (signal(SIGINT, sig_handler) == SIG_ERR) {
+    fprintf(stderr, "Will be unable to catch signals\n");
+  }
+
+  fprintf(stdout, "Bringing up bluetooth adapter\n");
+  if (!hal_open(callbacks_get_adapter_struct())) {
+    fprintf(stderr, "Unable to open Bluetooth HAL.\n");
+    return 1;
+  }
+
+  if (discover) {
+    CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed);
+    fprintf(stdout, "BT adapter is up\n");
+
+    fprintf(stdout, "Starting to start discovery\n");
+    CALL_AND_WAIT(bt_interface->start_discovery(), discovery_state_changed);
+    fprintf(stdout, "Started discovery for %d seconds\n", timeout_in_sec);
+
+    sleep(timeout_in_sec);
+
+    fprintf(stdout, "Starting to cancel discovery\n");
+    CALL_AND_WAIT(bt_interface->cancel_discovery(), discovery_state_changed);
+    fprintf(stdout, "Cancelled discovery after %d seconds\n", timeout_in_sec);
+  }
+
+  if (discoverable) {
+    CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed);
+    fprintf(stdout, "BT adapter is up\n");
+
+    bt_property_t *property = property_new_scan_mode(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+
+    int rc = bt_interface->set_adapter_property(property);
+    fprintf(stdout, "Set rc:%d device as discoverable for %d seconds\n", rc, timeout_in_sec);
+
+    sleep(timeout_in_sec);
+
+    property_free(property);
+  }
+
+   if (bond) {
+    if (bdaddr_is_empty(&bt_remote_bdaddr)) {
+      fprintf(stderr, "Must specify a remote device address [ --bdaddr=xx:yy:zz:aa:bb:cc ]\n");
+      exit(1);
+    }
+
+    CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed);
+    fprintf(stdout, "BT adapter is up\n");
+
+    int rc = bt_interface->create_bond(&bt_remote_bdaddr, 0 /* UNKNOWN; Currently not documented :( */);
+    fprintf(stdout, "Started bonding:%d for %d seconds\n", rc, timeout_in_sec);
+
+    sleep(timeout_in_sec);
+  }
+
+  if (up) {
+    CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed);
+    fprintf(stdout, "BT adapter is up\n");
+
+    fprintf(stdout, "Waiting for %d seconds\n", timeout_in_sec);
+    sleep(timeout_in_sec);
+  }
+
+  if (get_name) {
+    CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed);
+    fprintf(stdout, "BT adapter is up\n");
+    int error;
+    CALL_AND_WAIT(error = bt_interface->get_adapter_property(BT_PROPERTY_BDNAME), adapter_properties);
+    if (error != BT_STATUS_SUCCESS) {
+      fprintf(stderr, "Unable to get adapter property\n");
+      exit(1);
+    }
+    bt_property_t *property = adapter_get_property(BT_PROPERTY_BDNAME);
+    const bt_bdname_t *name = property_as_name(property);
+    if (name)
+      printf("Queried bluetooth device name:%s\n", name->name);
+    else
+      printf("No name\n");
+  }
+
+  if (set_name) {
+    CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed);
+    fprintf(stdout, "BT adapter is up\n");
+
+    bt_property_t *property = property_new_name(bd_name);
+    printf("Setting bluetooth device name to:%s\n", bd_name);
+    int error;
+    CALL_AND_WAIT(error = bt_interface->set_adapter_property(property), adapter_properties);
+    if (error != BT_STATUS_SUCCESS) {
+      fprintf(stderr, "Unable to set adapter property\n");
+      exit(1);
+    }
+    CALL_AND_WAIT(error = bt_interface->get_adapter_property(BT_PROPERTY_BDNAME), adapter_properties);
+    if (error != BT_STATUS_SUCCESS) {
+      fprintf(stderr, "Unable to get adapter property\n");
+      exit(1);
+    }
+    property_free(property);
+    sleep(timeout_in_sec);
+  }
+
+  const int app_uid = 0;
+
+  if (sco_listen) {
+    CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed);
+    fprintf(stdout, "BT adapter is up\n");
+
+    bt_property_t *property = property_new_scan_mode(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+    CALL_AND_WAIT(bt_interface->set_adapter_property(property), adapter_properties);
+    property_free(property);
+
+    const btsock_interface_t *sock = bt_interface->get_profile_interface(BT_PROFILE_SOCKETS_ID);
+
+    int rfcomm_fd = INVALID_FD;
+    int error = sock->listen(BTSOCK_RFCOMM, "meow", (const uint8_t *)&HFP_AG_UUID, 0, &rfcomm_fd, 0, app_uid);
+    if (error != BT_STATUS_SUCCESS) {
+      fprintf(stderr, "Unable to listen for incoming RFCOMM socket: %d\n", error);
+      exit(1);
+    }
+
+    int sock_fd = INVALID_FD;
+    error = sock->listen(BTSOCK_SCO, NULL, NULL, 5, &sock_fd, 0, app_uid);
+    if (error != BT_STATUS_SUCCESS) {
+      fprintf(stderr, "Unable to listen for incoming SCO sockets: %d\n", error);
+      exit(1);
+    }
+    fprintf(stdout, "Waiting for incoming SCO connections...\n");
+    sleep(timeout_in_sec);
+  }
+
+  if (sco_connect) {
+    if (bdaddr_is_empty(&bt_remote_bdaddr)) {
+      fprintf(stderr, "Must specify a remote device address [ --bdaddr=xx:yy:zz:aa:bb:cc ]\n");
+      exit(1);
+    }
+
+    CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed);
+    fprintf(stdout, "BT adapter is up\n");
+
+    const btsock_interface_t *sock = bt_interface->get_profile_interface(BT_PROFILE_SOCKETS_ID);
+
+    int rfcomm_fd = INVALID_FD;
+    int error = sock->connect(&bt_remote_bdaddr, BTSOCK_RFCOMM, (const uint8_t *)&HFP_AG_UUID, 0, &rfcomm_fd, 0, app_uid);
+    if (error != BT_STATUS_SUCCESS) {
+      fprintf(stderr, "Unable to connect to RFCOMM socket: %d.\n", error);
+      exit(1);
+    }
+
+    WAIT(acl_state_changed);
+
+    fprintf(stdout, "Establishing SCO connection...\n");
+
+    int sock_fd = INVALID_FD;
+    error = sock->connect(&bt_remote_bdaddr, BTSOCK_SCO, NULL, 5, &sock_fd, 0, app_uid);
+    if (error != BT_STATUS_SUCCESS) {
+      fprintf(stderr, "Unable to connect to SCO socket: %d.\n", error);
+      exit(1);
+    }
+    sleep(timeout_in_sec);
+  }
+
+  CALL_AND_WAIT(bt_interface->disable(), adapter_state_changed);
+  fprintf(stdout, "BT adapter is down\n");
+}
+
+static void sig_handler(int signo) {
+  if (signo == SIGINT) {
+    fprintf(stderr, "Received SIGINT\n");
+    CALL_AND_WAIT(bt_interface->disable(), adapter_state_changed);
+    fprintf(stderr, "BT adapter is down\n");
+    exit(1);
+  }
+}
+
+static void usage(const char *name) {
+  fprintf(stderr, "Usage: %s [--bond|--discover|--discoverable|--up|--sco_listen|--sco_connect] [--bdaddr=<bdaddr>] [--time=<time_in_sec>] --verbose\n", name);
+  fprintf(stderr, "     bond: Discover actively advertising devices\n");
+  fprintf(stderr, "     discover: Discover actively advertising devices\n");
+  fprintf(stderr, "     discoverable: Set into a connectable and discoverable mode\n");
+  fprintf(stderr, "     up: Only bring up stack\n");
+  fprintf(stderr, "     sco_listen: Listen for incoming SCO connections\n");
+  fprintf(stderr, "     sco_connect: Establish a SCO connection with another device\n");
+  fprintf(stderr, "     time: Time to hold in the specified mode\n");
+  exit(1);
+}
+
+static bool parse_args(int argc, char **argv) {
+  while (1) {
+    int option_index = 0;
+    int c = getopt_long_only(argc, argv, "", long_options, &option_index);
+    if (c != 0)
+      break;
+
+    switch (c) {
+      case 0:
+        if (option_index == 0) {
+          if (!string_to_bdaddr(optarg, &bt_remote_bdaddr)) {
+            return false;
+          }
+        }
+        if (option_index == 1) {
+          discover = true;
+        }
+        if (option_index == 2) {
+          discoverable = true;
+        }
+        if (option_index == 3) {
+          timeout_in_sec = atoi(optarg);
+        }
+        if (option_index == 4) {
+          bond  = true;
+        }
+        if (option_index == 5) {
+          up = true;
+        }
+        if (option_index == 6) {
+          f_verbose++;
+        }
+        if (option_index == 7) {
+          get_name = true;
+        }
+        if (option_index == 8) {
+          bd_name = (char *)optarg;
+          set_name = true;
+        }
+        if (option_index == 9) {
+          sco_listen = true;
+        }
+        if (option_index == 10) {
+          sco_connect = true;
+        }
+        break;
+
+      default:
+        fprintf(stderr, "?? getopt returned character code 0%o ??\n", c);
+    }
+  }
+
+  if (optind < argc) {
+    fprintf(stderr, "non-option ARGV-elements: ");
+    while (optind < argc)
+      fprintf(stderr, "%s ", argv[optind++]);
+    fprintf(stderr, "\n");
+    return false;
+  }
+  return true;
+}
diff --git a/bt/tools/hci/Android.mk.disabled b/bt/tools/hci/Android.mk.disabled
new file mode 100644
index 0000000..3e2286a
--- /dev/null
+++ b/bt/tools/hci/Android.mk.disabled
@@ -0,0 +1,34 @@
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# Bluetooth HCI tools for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := net_hci
+
+LOCAL_SRC_FILES := main.c
+LOCAL_STATIC_LIBRARIES := libosi
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_EXECUTABLE)
diff --git a/bt/tools/hci/main.c b/bt/tools/hci/main.c
new file mode 100644
index 0000000..4fbb457
--- /dev/null
+++ b/bt/tools/hci/main.c
@@ -0,0 +1,215 @@
+#include <hardware/bluetooth.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "osi/include/osi.h"
+
+typedef int (*handler_t)(int argc, char **argv);
+
+typedef enum {
+  HCI_PACKET_COMMAND  = 1,
+  HCI_PACKET_ACL_DATA = 2,
+  HCI_PACKET_SCO_DATA = 3,
+  HCI_PACKET_EVENT    = 4,
+} hci_packet_t;
+
+typedef struct {
+  const char *name;
+  const char *help;
+  handler_t handler;
+} command_t;
+
+static int help(int argc, char **argv);
+static int set_discoverable(int argc, char **argv);
+static int set_name(int argc, char **argv);
+static int set_pcm_loopback(int argc, char **argv);
+static int set_sco_route(int argc, char **argv);
+
+static bool write_hci_command(hci_packet_t type, const void *packet, size_t length);
+static const command_t *find_command(const char *name);
+static void usage(const char *name);
+
+static const command_t commands[] = {
+  { "help", "<command> - shows help text for <command>.", help },
+  { "setDiscoverable", "(true|false) - whether the controller should be discoverable.", set_discoverable },
+  { "setName", "<name> - sets the device's Bluetooth name to <name>.", set_name },
+  { "setPcmLoopback", "(true|false) - enables or disables PCM loopback on the controller.", set_pcm_loopback },
+  { "setScoRoute", "(pcm|i2s|uart) - sets the SCO packet route to one of the specified buses.", set_sco_route },
+};
+
+static int help(int argc, char **argv) {
+  if (!argc) {
+    printf("No help command specified.\n");
+    return 1;
+  }
+
+  const command_t *command = find_command(argv[0]);
+  if (!command) {
+    printf("No command named '%s'.\n", argv[0]);
+    return 2;
+  }
+
+  printf("%s %s\n", argv[0], command->help);
+  return 0;
+}
+
+static int set_discoverable(int argc, char **argv) {
+  if (argc != 1) {
+    printf("Discoverable mode not specified.\n");
+    return 1;
+  }
+
+  if (strcmp(argv[0], "true") && strcmp(argv[0], "false")) {
+    printf("Invalid discoverable mode '%s'.\n", argv[0]);
+    return 2;
+  }
+
+  uint8_t packet[] = { 0x1A, 0x0C, 0x01, 0x00 };
+  if (argv[0][0] == 't')
+    packet[ARRAY_SIZE(packet) - 1] = 0x03;
+
+  return !write_hci_command(HCI_PACKET_COMMAND, packet, ARRAY_SIZE(packet));
+}
+
+static int set_name(int argc, char **argv) {
+  if (argc != 1) {
+    printf("Device name not specified.\n");
+    return 1;
+  }
+
+  size_t len = strlen(argv[0]);
+  if (len > 247) {
+    printf("Device name cannot exceed 247 bytes.\n");
+    return 2;
+  }
+
+  uint8_t packet[251] = { 0x13, 0x0C, 248 };
+  memcpy(&packet[3], argv[0], len + 1);
+
+  if (!write_hci_command(HCI_PACKET_COMMAND, packet, sizeof(packet)))
+    return 1;
+
+  memset(&packet[0], 0, sizeof(packet));
+  packet[0] = 0x52;
+  packet[1] = 0x0C;
+  packet[2] = 0xF1;  // HCI command packet length.
+  packet[3] = 0x01;  // FEC required.
+  packet[4] = len + 1;
+  packet[5] = 0x09;  // Device name field tag.
+  memcpy(&packet[6], argv[0], len);
+  return !write_hci_command(HCI_PACKET_COMMAND, packet, 0xF4);
+}
+
+static int set_pcm_loopback(int argc, char **argv) {
+  if (argc != 1) {
+    printf("PCM loopback mode not specified.\n");
+    return 1;
+  }
+
+  if (strcmp(argv[0], "true") && strcmp(argv[0], "false")) {
+    printf("Invalid PCM mode '%s'.\n", argv[0]);
+    return 2;
+  }
+
+  uint8_t packet[] = { 0x24, 0xFC, 0x01, 0x00 };
+  if (argv[0][0] == 't')
+    packet[ARRAY_SIZE(packet) - 1] = 0x01;
+
+  return !write_hci_command(HCI_PACKET_COMMAND, packet, ARRAY_SIZE(packet));
+}
+
+static int set_sco_route(int argc, char **argv) {
+  if (argc != 1) {
+    printf("SCO route parameter must be specified.\n");
+    return 1;
+  }
+
+  uint8_t route = 0xFF;
+  if (!strcmp(argv[0], "pcm"))
+    route = 0;
+  else if (!strcmp(argv[0], "i2s"))
+    route = 3;
+  else if (!strcmp(argv[0], "uart"))
+    route = 1;
+
+  if (route == 0xFF) {
+    printf("Invalid SCO route specified: %s\n", argv[0]);
+    return 2;
+  }
+
+  uint8_t packet[] = { 0x1C, 0xFC, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00 };
+  packet[3] = route;
+
+  return !write_hci_command(HCI_PACKET_COMMAND, packet, ARRAY_SIZE(packet));
+}
+
+int main(int argc, char **argv) {
+  if (argc < 2) {
+    usage(argv[0]);
+    return -1;
+  }
+
+  const command_t *command = find_command(argv[1]);
+  if (!command) {
+    printf("Unrecognized command '%s'.\n", argv[1]);
+    return -2;
+  }
+
+  if (!command->handler) {
+    printf("Unhandled command '%s'.\n", argv[1]);
+    return -3;
+  }
+
+  return command->handler(argc - 2, &argv[2]);
+}
+
+static bool write_hci_command(hci_packet_t type, const void *packet, size_t length) {
+  int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (sock == INVALID_FD)
+    goto error;
+
+  struct sockaddr_in addr;
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = htonl(0x7F000001);
+  addr.sin_port = htons(8873);
+  int ret;
+  OSI_NO_INTR(ret = connect(sock, (const struct sockaddr *)&addr,
+                            sizeof(addr)));
+  if (ret == -1)
+    goto error;
+
+  if (send(sock, &type, 1, 0) != 1)
+    goto error;
+
+  if (send(sock, &length, 2, 0) != 2)
+    goto error;
+
+  if (send(sock, packet, length, 0) != (ssize_t)length)
+    goto error;
+
+  close(sock);
+  return true;
+
+error:;
+  close(sock);
+  return false;
+}
+
+static const command_t *find_command(const char *name) {
+  for (size_t i = 0; i < ARRAY_SIZE(commands); ++i)
+    if (!strcmp(commands[i].name, name))
+      return &commands[i];
+  return NULL;
+}
+
+static void usage(const char *name) {
+  printf("Usage: %s <command> [options]\n", name);
+  printf("Commands:\n");
+  for (size_t i = 0; i < ARRAY_SIZE(commands); ++i)
+    printf("  %s\n", commands[i].name);
+  printf("For detailed help on a command, run '%s help <command>'.\n", name);
+}
diff --git a/bt/tools/scripts/btsnooz.py b/bt/tools/scripts/btsnooz.py
new file mode 100755
index 0000000..6e0e112
--- /dev/null
+++ b/bt/tools/scripts/btsnooz.py
@@ -0,0 +1,167 @@
+#!/usr/bin/env python
+"""
+This script extracts btsnooz content from bugreports and generates
+a valid btsnoop log file which can be viewed using standard tools
+like Wireshark.
+
+btsnooz is a custom format designed to be included in bugreports.
+It can be described as:
+
+base64 {
+  file_header
+  deflate {
+    repeated {
+      record_header
+      record_data
+    }
+  }
+}
+
+where the file_header and record_header are modified versions of
+the btsnoop headers.
+"""
+
+
+import base64
+import fileinput
+import struct
+import sys
+import zlib
+
+
+# Enumeration of the values the 'type' field can take in a btsnooz
+# header. These values come from the Bluetooth stack's internal
+# representation of packet types.
+TYPE_IN_EVT = 0x10
+TYPE_IN_ACL = 0x11
+TYPE_IN_SCO = 0x12
+TYPE_OUT_CMD = 0x20
+TYPE_OUT_ACL = 0x21
+TYPE_OUT_SCO = 0x22
+
+
+def type_to_direction(type):
+  """
+  Returns the inbound/outbound direction of a packet given its type.
+  0 = sent packet
+  1 = received packet
+  """
+  if type in [TYPE_IN_EVT, TYPE_IN_ACL, TYPE_IN_SCO]:
+    return 1
+  return 0
+
+
+def type_to_hci(type):
+  """
+  Returns the HCI type of a packet given its btsnooz type.
+  """
+  if type == TYPE_OUT_CMD:
+    return '\x01'
+  if type == TYPE_IN_ACL or type == TYPE_OUT_ACL:
+    return '\x02'
+  if type == TYPE_IN_SCO or type == TYPE_OUT_SCO:
+    return '\x03'
+  if type == TYPE_IN_EVT:
+    return '\x04'
+
+
+def decode_snooz(snooz):
+  """
+  Decodes all known versions of a btsnooz file into a btsnoop file.
+  """
+  version, last_timestamp_ms = struct.unpack_from('=bQ', snooz)
+
+  if version != 1 and version != 2:
+    sys.stderr.write('Unsupported btsnooz version: %s\n' % version)
+    exit(1)
+
+  # Oddly, the file header (9 bytes) is not compressed, but the rest is.
+  decompressed = zlib.decompress(snooz[9:])
+
+  sys.stdout.write('btsnoop\x00\x00\x00\x00\x01\x00\x00\x03\xea')
+
+  if version == 1:
+    decode_snooz_v1(decompressed, last_timestamp_ms)
+  elif version == 2:
+    decode_snooz_v2(decompressed, last_timestamp_ms)
+
+
+def decode_snooz_v1(decompressed, last_timestamp_ms):
+  """
+  Decodes btsnooz v1 files into a btsnoop file.
+  """
+  # An unfortunate consequence of the file format design: we have to do a
+  # pass of the entire file to determine the timestamp of the first packet.
+  first_timestamp_ms = last_timestamp_ms + 0x00dcddb30f2f8000
+  offset = 0
+  while offset < len(decompressed):
+    length, delta_time_ms, type = struct.unpack_from('=HIb', decompressed, offset)
+    offset += 7 + length - 1
+    first_timestamp_ms -= delta_time_ms
+
+  # Second pass does the actual writing out to stdout.
+  offset = 0
+  while offset < len(decompressed):
+    length, delta_time_ms, type = struct.unpack_from('=HIb', decompressed, offset)
+    first_timestamp_ms += delta_time_ms
+    offset += 7
+    sys.stdout.write(struct.pack('>II', length, length))
+    sys.stdout.write(struct.pack('>II', type_to_direction(type), 0))
+    sys.stdout.write(struct.pack('>II', (first_timestamp_ms >> 32), (first_timestamp_ms & 0xFFFFFFFF)))
+    sys.stdout.write(type_to_hci(type))
+    sys.stdout.write(decompressed[offset : offset + length - 1])
+    offset += length - 1
+
+
+def decode_snooz_v2(decompressed, last_timestamp_ms):
+  """
+  Decodes btsnooz v2 files into a btsnoop file.
+  """
+  # An unfortunate consequence of the file format design: we have to do a
+  # pass of the entire file to determine the timestamp of the first packet.
+  first_timestamp_ms = last_timestamp_ms + 0x00dcddb30f2f8000
+  offset = 0
+  while offset < len(decompressed):
+    length, packet_length, delta_time_ms, snooz_type = struct.unpack_from('=HHIb', decompressed, offset)
+    offset += 9 + length - 1
+    first_timestamp_ms -= delta_time_ms
+
+  # Second pass does the actual writing out to stdout.
+  offset = 0
+  while offset < len(decompressed):
+    length, packet_length, delta_time_ms, snooz_type = struct.unpack_from('=HHIb', decompressed, offset)
+    first_timestamp_ms += delta_time_ms
+    offset += 9
+    sys.stdout.write(struct.pack('>II', packet_length, length))
+    sys.stdout.write(struct.pack('>II', type_to_direction(snooz_type), 0))
+    sys.stdout.write(struct.pack('>II', (first_timestamp_ms >> 32), (first_timestamp_ms & 0xFFFFFFFF)))
+    sys.stdout.write(type_to_hci(snooz_type))
+    sys.stdout.write(decompressed[offset : offset + length - 1])
+    offset += length - 1
+
+
+def main():
+  if len(sys.argv) > 2:
+    sys.stderr.write('Usage: %s [bugreport]\n' % sys.argv[0])
+    exit(1)
+
+  iterator = fileinput.input()
+  found = False
+  base64_string = ""
+  for line in iterator:
+    if found:
+      if line.find('--- END:BTSNOOP_LOG_SUMMARY') != -1:
+        decode_snooz(base64.standard_b64decode(base64_string))
+        sys.exit(0)
+      base64_string += line.strip()
+
+    if line.find('--- BEGIN:BTSNOOP_LOG_SUMMARY') != -1:
+      found = True
+
+  if not found:
+    sys.stderr.write('No btsnooz section found in bugreport.\n')
+    sys.exit(1)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/bt/tools/scripts/change_types.sh b/bt/tools/scripts/change_types.sh
new file mode 100755
index 0000000..24f2c9f
--- /dev/null
+++ b/bt/tools/scripts/change_types.sh
@@ -0,0 +1,85 @@
+#!/bin/bash
+
+# This script will recursively search all |FILES| from the current
+# directory and replace all |TYPES| according to the list below.
+
+# NOTE 1:
+# If this script is run from .../system/bt (as it's intended to be),
+# please edit stack/include/bt_types.h next and remove the typedef's
+# near the top and restore the definitions of TRUE and FALSE. These
+# are still used in the vnd_* files and device specific repositories.
+
+# NOTE 2:
+# The list of files to be modified also includes "*.patch", which means
+# this script can be used to help cherry-picking changes from older
+# branches. Follow this workflow outline:
+#  1. git format-patch [-1] <your sha1>
+#  2. Run change_type script on patch[es]
+#  3. git apply / git am
+
+
+# Regular expression matching the file name
+FILES="\.h$|\.c$|\.cpp$|\.cc$|\.patch$"
+
+# Search/replace terms, separated by ":"
+TYPES=(
+  "UINT8   :uint8_t "
+  "UINT16   :uint16_t "
+  "UINT32   :uint32_t "
+  "UINT64   :uint64_t "
+  "INT8   :int8_t "
+  "INT16   :int16_t "
+  "INT32   :int32_t "
+  "INT64   :int64_t "
+  "UINT8:uint8_t"
+  "UINT16:uint16_t"
+  "UINT32:uint32_t"
+  "UINT64:uint64_t"
+  "INT8:int8_t"
+  "INT16:int16_t"
+  "INT32:int32_t"
+  "INT64:int64_t"
+  "BOOLEAN:bool   "
+  "TRUE:true"
+  "FALSE:false"
+  "__FUNCTION__:__func__"
+)
+
+function process_file
+{
+  echo -n "Processing file $1 "
+
+  for tt in "${TYPES[@]}" ;
+  do
+    before=${tt%%:*}
+    after=${tt#*:}
+
+    echo -n "."
+    sed -i -e "s/\b${before}/${after}/g" "$1"
+  done
+  echo
+}
+
+function process_files
+{
+  until [ -z "$1" ]
+  do
+    process_file "$1"
+    shift
+  done
+}
+
+
+# Let's do this ...
+process_files `find ./ | grep -E "${FILES}"`
+
+# All done ...
+echo
+echo "All done."
+
+# Try to be helpful ...
+PWD=`pwd`
+if [[ "${PWD}" == */system/bt ]]
+then
+  echo "Please edit ${PWD}/stack/include/bt_types.h next."
+fi
diff --git a/bt/tools/scripts/viewbtsnoop.sh b/bt/tools/scripts/viewbtsnoop.sh
new file mode 100755
index 0000000..61f2485
--- /dev/null
+++ b/bt/tools/scripts/viewbtsnoop.sh
@@ -0,0 +1,74 @@
+#!/bin/bash
+
+# This is a script that will allow you to open a btsnooz log
+# in wireshark directly from a zip file. This script will handle
+# the unzipping if it is a zip file, or will convert the btsnooz
+# directly in the case of a plain text file for use with wireshark.
+# After wireshark closes, it will clean up all the temporary files
+# used.
+
+WIRESHARK="${WIRESHARK:-wireshark}"
+BTSNOOZ="${BTSNOOZ:-btsnooz.py}"
+
+if ! hash "${WIRESHARK}" 2>/dev/null;
+then
+    echo "Please make sure wireshark is in your path before running."
+    exit 1;
+fi
+
+if ! hash btsnooz.py 2>/dev/null;
+then
+    echo "Please make sure btsnooz.py is in your path before running."
+    exit 2;
+fi
+
+if [ $# -eq 0 ];
+then
+    echo "Usage: $0 bugreport(.txt|.zip)"
+    exit 3;
+fi
+
+BUGREPORT="$1"
+FILENAME="$(basename ${BUGREPORT})"
+TMPDIR=$(mktemp --tmpdir -d "viewbtsnooz_XXXXX")
+LOGFILE="${TMPDIR}/${FILENAME%.*}.btsnooz"
+
+trap ctrl_c INT
+function ctrl_c() {
+    rm -rf "${TMPDIR}"
+}
+
+if [ ! -f "${BUGREPORT}" ];
+then
+    echo "File ${BUGREPORT} does not exist."
+    exit 4;
+fi
+
+if [ ! -d "${TMPDIR}" ];
+then
+    echo "Unable to create temp. dir (${TMPDIR}) :("
+    exit 5;
+fi
+
+if [ "${BUGREPORT: -4}" == ".zip" ];
+then
+    unzip "${BUGREPORT}" -d "${TMPDIR}"
+    BUGREPORT="${TMPDIR}/${FILENAME%.*}.txt"
+fi
+
+if [ -f "${BUGREPORT}" ];
+then
+    ${BTSNOOZ} "${BUGREPORT}" > "${LOGFILE}"
+    if [ ! $? -eq 0 ];
+    then
+        echo "Could not extract btsnooz data from ${BUGREPORT}."
+        rm -rf "${TMPDIR}"
+        exit 6;
+    fi
+
+    ${WIRESHARK} "${LOGFILE}"
+else
+    echo "Looks like there is no plain text bugreport (${BUGREPORT})?"
+fi
+
+rm -rf "${TMPDIR}"
diff --git a/bt/udrv/BUILD.gn b/bt/udrv/BUILD.gn
new file mode 100644
index 0000000..1993cc3
--- /dev/null
+++ b/bt/udrv/BUILD.gn
@@ -0,0 +1,31 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+source_set("udrv") {
+  sources = [
+    "ulinux/uipc.cc",
+  ]
+
+  include_dirs = [
+    "include",
+    "uipc",
+    "//",
+    "//audio_a2dp_hw",
+    "//include",
+    "//stack/include",
+    "//utils/include",
+  ]
+}
diff --git a/bt/udrv/include/uipc.h b/bt/udrv/include/uipc.h
new file mode 100644
index 0000000..766477b
--- /dev/null
+++ b/bt/udrv/include/uipc.h
@@ -0,0 +1,127 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2007-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.
+ *
+ ******************************************************************************/
+#ifndef UIPC_H
+#define UIPC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define UIPC_CH_ID_AV_CTRL  0
+#define UIPC_CH_ID_AV_AUDIO 1
+#define UIPC_CH_NUM         2
+
+#define UIPC_CH_ID_ALL      3   /* used to address all the ch id at once */
+
+#define DEFAULT_READ_POLL_TMO_MS 100
+
+typedef uint8_t tUIPC_CH_ID;
+
+/* Events generated */
+typedef enum {
+    UIPC_OPEN_EVT           = 0x0001,
+    UIPC_CLOSE_EVT          = 0x0002,
+    UIPC_RX_DATA_EVT        = 0x0004,
+    UIPC_RX_DATA_READY_EVT  = 0x0008,
+    UIPC_TX_DATA_READY_EVT  = 0x0010
+} tUIPC_EVENT;
+
+/*
+ * UIPC IOCTL Requests
+ */
+
+#define UIPC_REQ_RX_FLUSH               1
+#define UIPC_REG_CBACK                  2
+#define UIPC_REG_REMOVE_ACTIVE_READSET  3
+#define UIPC_SET_READ_POLL_TMO          4
+
+typedef void (tUIPC_RCV_CBACK)(tUIPC_CH_ID ch_id, tUIPC_EVENT event); /* points to BT_HDR which describes event type and length of data; len contains the number of bytes of entire message (sizeof(BT_HDR) + offset + size of data) */
+
+const char* dump_uipc_event(tUIPC_EVENT event);
+
+/*******************************************************************************
+**
+** Function         UIPC_Init
+**
+** Description      Initialize UIPC module
+**
+** Returns          void
+**
+*******************************************************************************/
+void UIPC_Init(void *);
+
+/*******************************************************************************
+**
+** Function         UIPC_Open
+**
+** Description      Open UIPC interface
+**
+** Returns          void
+**
+*******************************************************************************/
+bool    UIPC_Open(tUIPC_CH_ID ch_id, tUIPC_RCV_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function         UIPC_Close
+**
+** Description      Close UIPC interface
+**
+** Returns          void
+**
+*******************************************************************************/
+void UIPC_Close(tUIPC_CH_ID ch_id);
+
+/*******************************************************************************
+**
+** Function         UIPC_Send
+**
+** Description      Called to transmit a message over UIPC.
+**
+** Returns          void
+**
+*******************************************************************************/
+bool    UIPC_Send(tUIPC_CH_ID ch_id, uint16_t msg_evt, uint8_t *p_buf, uint16_t msglen);
+
+/*******************************************************************************
+**
+** Function         UIPC_Read
+**
+** Description      Called to read a message from UIPC.
+**
+** Returns          void
+**
+*******************************************************************************/
+uint32_t UIPC_Read(tUIPC_CH_ID ch_id, uint16_t *p_msg_evt, uint8_t *p_buf, uint32_t len);
+
+/*******************************************************************************
+**
+** Function         UIPC_Ioctl
+**
+** Description      Called to control UIPC.
+**
+** Returns          void
+**
+*******************************************************************************/
+bool    UIPC_Ioctl(tUIPC_CH_ID ch_id, uint32_t request, void *param);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* UIPC_H */
diff --git a/bt/udrv/ulinux/uipc.cc b/bt/udrv/ulinux/uipc.cc
new file mode 100644
index 0000000..898d839
--- /dev/null
+++ b/bt/udrv/ulinux/uipc.cc
@@ -0,0 +1,865 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ *  Filename:      uipc.cc
+ *
+ *  Description:   UIPC implementation for bluedroid
+ *
+ *****************************************************************************/
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/poll.h>
+#include <sys/prctl.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "audio_a2dp_hw.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "bt_common.h"
+#include "osi/include/osi.h"
+#include "osi/include/socket_utils/sockets.h"
+#include "uipc.h"
+
+/*****************************************************************************
+**  Constants & Macros
+******************************************************************************/
+
+#define PCM_FILENAME "/data/test.pcm"
+
+#define MAX(a,b) ((a)>(b)?(a):(b))
+
+#define CASE_RETURN_STR(const) case const: return #const;
+
+#define UIPC_DISCONNECTED (-1)
+
+#define UIPC_LOCK() /*BTIF_TRACE_EVENT(" %s lock", __func__);*/ pthread_mutex_lock(&uipc_main.mutex);
+#define UIPC_UNLOCK() /*BTIF_TRACE_EVENT("%s unlock", __func__);*/ pthread_mutex_unlock(&uipc_main.mutex);
+
+#define SAFE_FD_ISSET(fd, set) (((fd) == -1) ? false : FD_ISSET((fd), (set)))
+
+#define UIPC_FLUSH_BUFFER_SIZE 1024
+
+/*****************************************************************************
+**  Local type definitions
+******************************************************************************/
+
+typedef enum {
+    UIPC_TASK_FLAG_DISCONNECT_CHAN = 0x1,
+} tUIPC_TASK_FLAGS;
+
+typedef struct {
+    int srvfd;
+    int fd;
+    int read_poll_tmo_ms;
+    int task_evt_flags;   /* event flags pending to be processed in read task */
+    tUIPC_EVENT cond_flags;
+    pthread_mutex_t cond_mutex;
+    pthread_cond_t  cond;
+    tUIPC_RCV_CBACK *cback;
+} tUIPC_CHAN;
+
+typedef struct {
+    pthread_t tid; /* main thread id */
+    int running;
+    pthread_mutex_t mutex;
+
+    fd_set active_set;
+    fd_set read_set;
+    int max_fd;
+    int signal_fds[2];
+
+    tUIPC_CHAN ch[UIPC_CH_NUM];
+} tUIPC_MAIN;
+
+
+/*****************************************************************************
+**  Static variables
+******************************************************************************/
+
+static tUIPC_MAIN uipc_main;
+
+
+/*****************************************************************************
+**  Static functions
+******************************************************************************/
+
+static int uipc_close_ch_locked(tUIPC_CH_ID ch_id);
+
+/*****************************************************************************
+**  Externs
+******************************************************************************/
+
+
+/*****************************************************************************
+**   Helper functions
+******************************************************************************/
+
+
+const char* dump_uipc_event(tUIPC_EVENT event)
+{
+    switch(event)
+    {
+        CASE_RETURN_STR(UIPC_OPEN_EVT)
+        CASE_RETURN_STR(UIPC_CLOSE_EVT)
+        CASE_RETURN_STR(UIPC_RX_DATA_EVT)
+        CASE_RETURN_STR(UIPC_RX_DATA_READY_EVT)
+        CASE_RETURN_STR(UIPC_TX_DATA_READY_EVT)
+        default:
+            return "UNKNOWN MSG ID";
+    }
+}
+
+/*****************************************************************************
+**   socket helper functions
+*****************************************************************************/
+
+static inline int create_server_socket(const char* name)
+{
+    int s = socket(AF_LOCAL, SOCK_STREAM, 0);
+    if (s < 0)
+        return -1;
+
+    BTIF_TRACE_EVENT("create_server_socket %s", name);
+
+    if(osi_socket_local_server_bind(s, name,
+#if defined(OS_GENERIC)
+        ANDROID_SOCKET_NAMESPACE_FILESYSTEM
+#else  // !defined(OS_GENERIC)
+        ANDROID_SOCKET_NAMESPACE_ABSTRACT
+#endif  // defined(OS_GENERIC)
+        ) < 0)
+    {
+        BTIF_TRACE_EVENT("socket failed to create (%s)", strerror(errno));
+        close(s);
+        return -1;
+    }
+
+    if(listen(s, 5) < 0)
+    {
+        BTIF_TRACE_EVENT("listen failed", strerror(errno));
+        close(s);
+        return -1;
+    }
+
+    BTIF_TRACE_EVENT("created socket fd %d", s);
+    return s;
+}
+
+static int accept_server_socket(int sfd)
+{
+    struct sockaddr_un remote;
+    struct pollfd pfd;
+    int fd;
+    socklen_t len = sizeof(struct sockaddr_un);
+
+    BTIF_TRACE_EVENT("accept fd %d", sfd);
+
+    /* make sure there is data to process */
+    pfd.fd = sfd;
+    pfd.events = POLLIN;
+
+    int poll_ret;
+    OSI_NO_INTR(poll_ret = poll(&pfd, 1, 0));
+    if (poll_ret == 0)
+    {
+        BTIF_TRACE_WARNING("accept poll timeout");
+        return -1;
+    }
+
+    //BTIF_TRACE_EVENT("poll revents 0x%x", pfd.revents);
+
+    OSI_NO_INTR(fd = accept(sfd, (struct sockaddr *)&remote, &len));
+    if (fd == -1) {
+         BTIF_TRACE_ERROR("sock accept failed (%s)", strerror(errno));
+         return -1;
+    }
+
+    // match socket buffer size option with client
+    const int size = AUDIO_STREAM_OUTPUT_BUFFER_SZ;
+    int ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char*)&size, (int)sizeof(size));
+    if (ret < 0) {
+        BTIF_TRACE_ERROR("setsockopt failed (%s)", strerror(errno));
+    }
+
+    //BTIF_TRACE_EVENT("new fd %d", fd);
+
+    return fd;
+}
+
+/*****************************************************************************
+**
+**   uipc helper functions
+**
+*****************************************************************************/
+
+static int uipc_main_init(void)
+{
+    int i;
+    pthread_mutexattr_t attr;
+    pthread_mutexattr_init(&attr);
+    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+    pthread_mutex_init(&uipc_main.mutex, &attr);
+
+    BTIF_TRACE_EVENT("### uipc_main_init ###");
+
+    /* setup interrupt socket pair */
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, uipc_main.signal_fds) < 0)
+    {
+        return -1;
+    }
+
+    FD_SET(uipc_main.signal_fds[0], &uipc_main.active_set);
+    uipc_main.max_fd = MAX(uipc_main.max_fd, uipc_main.signal_fds[0]);
+
+    for (i=0; i< UIPC_CH_NUM; i++)
+    {
+        tUIPC_CHAN *p = &uipc_main.ch[i];
+        p->srvfd = UIPC_DISCONNECTED;
+        p->fd = UIPC_DISCONNECTED;
+        p->task_evt_flags = 0;
+        pthread_cond_init(&p->cond, NULL);
+        pthread_mutex_init(&p->cond_mutex, NULL);
+        p->cback = NULL;
+    }
+
+    return 0;
+}
+
+void uipc_main_cleanup(void)
+{
+    int i;
+
+    BTIF_TRACE_EVENT("uipc_main_cleanup");
+
+    close(uipc_main.signal_fds[0]);
+    close(uipc_main.signal_fds[1]);
+
+    /* close any open channels */
+    for (i=0; i<UIPC_CH_NUM; i++)
+        uipc_close_ch_locked(i);
+}
+
+
+
+/* check pending events in read task */
+static void uipc_check_task_flags_locked(void)
+{
+    int i;
+
+    for (i=0; i<UIPC_CH_NUM; i++)
+    {
+        //BTIF_TRACE_EVENT("CHECK TASK FLAGS %x %x",  uipc_main.ch[i].task_evt_flags, UIPC_TASK_FLAG_DISCONNECT_CHAN);
+        if (uipc_main.ch[i].task_evt_flags & UIPC_TASK_FLAG_DISCONNECT_CHAN)
+        {
+            uipc_main.ch[i].task_evt_flags &= ~UIPC_TASK_FLAG_DISCONNECT_CHAN;
+            uipc_close_ch_locked(i);
+        }
+
+        /* add here */
+
+    }
+}
+
+
+static int uipc_check_fd_locked(tUIPC_CH_ID ch_id)
+{
+    if (ch_id >= UIPC_CH_NUM)
+        return -1;
+
+    //BTIF_TRACE_EVENT("CHECK SRVFD %d (ch %d)", uipc_main.ch[ch_id].srvfd, ch_id);
+
+    if (SAFE_FD_ISSET(uipc_main.ch[ch_id].srvfd, &uipc_main.read_set))
+    {
+        BTIF_TRACE_EVENT("INCOMING CONNECTION ON CH %d", ch_id);
+
+        uipc_main.ch[ch_id].fd = accept_server_socket(uipc_main.ch[ch_id].srvfd);
+
+        BTIF_TRACE_EVENT("NEW FD %d", uipc_main.ch[ch_id].fd);
+
+        if ((uipc_main.ch[ch_id].fd > 0) && uipc_main.ch[ch_id].cback)
+        {
+            /*  if we have a callback we should add this fd to the active set
+                and notify user with callback event */
+            BTIF_TRACE_EVENT("ADD FD %d TO ACTIVE SET", uipc_main.ch[ch_id].fd);
+            FD_SET(uipc_main.ch[ch_id].fd, &uipc_main.active_set);
+            uipc_main.max_fd = MAX(uipc_main.max_fd, uipc_main.ch[ch_id].fd);
+        }
+
+        if (uipc_main.ch[ch_id].fd < 0)
+        {
+            BTIF_TRACE_ERROR("FAILED TO ACCEPT CH %d (%s)", ch_id, strerror(errno));
+            return -1;
+        }
+
+        if (uipc_main.ch[ch_id].cback)
+            uipc_main.ch[ch_id].cback(ch_id, UIPC_OPEN_EVT);
+    }
+
+    //BTIF_TRACE_EVENT("CHECK FD %d (ch %d)", uipc_main.ch[ch_id].fd, ch_id);
+
+    if (SAFE_FD_ISSET(uipc_main.ch[ch_id].fd, &uipc_main.read_set))
+    {
+        //BTIF_TRACE_EVENT("INCOMING DATA ON CH %d", ch_id);
+
+        if (uipc_main.ch[ch_id].cback)
+            uipc_main.ch[ch_id].cback(ch_id, UIPC_RX_DATA_READY_EVT);
+    }
+    return 0;
+}
+
+static void uipc_check_interrupt_locked(void)
+{
+    if (SAFE_FD_ISSET(uipc_main.signal_fds[0], &uipc_main.read_set))
+    {
+        char sig_recv = 0;
+        OSI_NO_INTR(recv(uipc_main.signal_fds[0], &sig_recv, sizeof(sig_recv),
+                         MSG_WAITALL));
+    }
+}
+
+static inline void uipc_wakeup_locked(void)
+{
+    char sig_on = 1;
+    BTIF_TRACE_EVENT("UIPC SEND WAKE UP");
+
+    OSI_NO_INTR(send(uipc_main.signal_fds[1], &sig_on, sizeof(sig_on), 0));
+}
+
+static int uipc_setup_server_locked(tUIPC_CH_ID ch_id, const char *name,
+                                    tUIPC_RCV_CBACK *cback)
+{
+    int fd;
+
+    BTIF_TRACE_EVENT("SETUP CHANNEL SERVER %d", ch_id);
+
+    if (ch_id >= UIPC_CH_NUM)
+        return -1;
+
+    UIPC_LOCK();
+
+    fd = create_server_socket(name);
+
+    if (fd < 0)
+    {
+        BTIF_TRACE_ERROR("failed to setup %s", name, strerror(errno));
+        UIPC_UNLOCK();
+         return -1;
+    }
+
+    BTIF_TRACE_EVENT("ADD SERVER FD TO ACTIVE SET %d", fd);
+    FD_SET(fd, &uipc_main.active_set);
+    uipc_main.max_fd = MAX(uipc_main.max_fd, fd);
+
+    uipc_main.ch[ch_id].srvfd = fd;
+    uipc_main.ch[ch_id].cback = cback;
+    uipc_main.ch[ch_id].read_poll_tmo_ms = DEFAULT_READ_POLL_TMO_MS;
+
+    /* trigger main thread to update read set */
+    uipc_wakeup_locked();
+
+    UIPC_UNLOCK();
+
+    return 0;
+}
+
+static void uipc_flush_ch_locked(tUIPC_CH_ID ch_id)
+{
+    char buf[UIPC_FLUSH_BUFFER_SIZE];
+    struct pollfd pfd;
+
+    pfd.events = POLLIN;
+    pfd.fd = uipc_main.ch[ch_id].fd;
+
+    if (uipc_main.ch[ch_id].fd == UIPC_DISCONNECTED)
+    {
+        BTIF_TRACE_EVENT("%s() - fd disconnected. Exiting", __func__);
+        return;
+    }
+
+    while (1)
+    {
+        int ret;
+        OSI_NO_INTR(ret = poll(&pfd, 1, 1));
+        if (ret == 0) {
+            BTIF_TRACE_VERBOSE("%s(): poll() timeout - nothing to do. Exiting",
+                               __func__);
+            return;
+        }
+        if (ret < 0) {
+            BTIF_TRACE_WARNING("%s() - poll() failed: return %d errno %d (%s). Exiting",
+                               __func__, ret, errno, strerror(errno));
+            return;
+        }
+        BTIF_TRACE_VERBOSE("%s() - polling fd %d, revents: 0x%x, ret %d",
+                __func__, pfd.fd, pfd.revents, ret);
+        if (pfd.revents & (POLLERR|POLLHUP))
+        {
+            BTIF_TRACE_WARNING("%s() - POLLERR or POLLHUP. Exiting", __func__);
+            return;
+        }
+
+        /* read sufficiently large buffer to ensure flush empties socket faster than
+           it is getting refilled */
+        read(pfd.fd, &buf, UIPC_FLUSH_BUFFER_SIZE);
+    }
+}
+
+
+static void uipc_flush_locked(tUIPC_CH_ID ch_id)
+{
+    if (ch_id >= UIPC_CH_NUM)
+        return;
+
+    switch(ch_id)
+    {
+        case UIPC_CH_ID_AV_CTRL:
+            uipc_flush_ch_locked(UIPC_CH_ID_AV_CTRL);
+            break;
+
+        case UIPC_CH_ID_AV_AUDIO:
+            uipc_flush_ch_locked(UIPC_CH_ID_AV_AUDIO);
+            break;
+    }
+}
+
+
+static int uipc_close_ch_locked(tUIPC_CH_ID ch_id)
+{
+    int wakeup = 0;
+
+    BTIF_TRACE_EVENT("CLOSE CHANNEL %d", ch_id);
+
+    if (ch_id >= UIPC_CH_NUM)
+        return -1;
+
+    if (uipc_main.ch[ch_id].srvfd != UIPC_DISCONNECTED)
+    {
+        BTIF_TRACE_EVENT("CLOSE SERVER (FD %d)", uipc_main.ch[ch_id].srvfd);
+        close(uipc_main.ch[ch_id].srvfd);
+        FD_CLR(uipc_main.ch[ch_id].srvfd, &uipc_main.active_set);
+        uipc_main.ch[ch_id].srvfd = UIPC_DISCONNECTED;
+        wakeup = 1;
+    }
+
+    if (uipc_main.ch[ch_id].fd != UIPC_DISCONNECTED)
+    {
+        BTIF_TRACE_EVENT("CLOSE CONNECTION (FD %d)", uipc_main.ch[ch_id].fd);
+        close(uipc_main.ch[ch_id].fd);
+        FD_CLR(uipc_main.ch[ch_id].fd, &uipc_main.active_set);
+        uipc_main.ch[ch_id].fd = UIPC_DISCONNECTED;
+        wakeup = 1;
+    }
+
+    /* notify this connection is closed */
+    if (uipc_main.ch[ch_id].cback)
+        uipc_main.ch[ch_id].cback(ch_id, UIPC_CLOSE_EVT);
+
+    /* trigger main thread update if something was updated */
+    if (wakeup)
+        uipc_wakeup_locked();
+
+    return 0;
+}
+
+
+void uipc_close_locked(tUIPC_CH_ID ch_id)
+{
+    if (uipc_main.ch[ch_id].srvfd == UIPC_DISCONNECTED)
+    {
+        BTIF_TRACE_EVENT("CHANNEL %d ALREADY CLOSED", ch_id);
+        return;
+    }
+
+    /* schedule close on this channel */
+    uipc_main.ch[ch_id].task_evt_flags |= UIPC_TASK_FLAG_DISCONNECT_CHAN;
+    uipc_wakeup_locked();
+}
+
+
+static void *uipc_read_task(UNUSED_ATTR void *arg)
+{
+    int ch_id;
+    int result;
+
+    prctl(PR_SET_NAME, (unsigned long)"uipc-main", 0, 0, 0);
+
+    raise_priority_a2dp(TASK_UIPC_READ);
+
+    while (uipc_main.running)
+    {
+        uipc_main.read_set = uipc_main.active_set;
+
+        result = select(uipc_main.max_fd+1, &uipc_main.read_set, NULL, NULL, NULL);
+
+        if (result == 0) {
+            BTIF_TRACE_EVENT("select timeout");
+            continue;
+        }
+        if (result < 0) {
+            if (errno != EINTR)
+                BTIF_TRACE_EVENT("select failed %s", strerror(errno));
+            continue;
+        }
+
+        UIPC_LOCK();
+
+        /* clear any wakeup interrupt */
+        uipc_check_interrupt_locked();
+
+        /* check pending task events */
+        uipc_check_task_flags_locked();
+
+        /* make sure we service audio channel first */
+        uipc_check_fd_locked(UIPC_CH_ID_AV_AUDIO);
+
+        /* check for other connections */
+        for (ch_id = 0; ch_id < UIPC_CH_NUM; ch_id++)
+        {
+            if (ch_id != UIPC_CH_ID_AV_AUDIO)
+                uipc_check_fd_locked(ch_id);
+        }
+
+        UIPC_UNLOCK();
+    }
+
+    BTIF_TRACE_EVENT("UIPC READ THREAD EXITING");
+
+    uipc_main_cleanup();
+
+    uipc_main.tid = 0;
+
+    BTIF_TRACE_EVENT("UIPC READ THREAD DONE");
+
+    return nullptr;
+}
+
+
+int uipc_start_main_server_thread(void)
+{
+    uipc_main.running = 1;
+
+    if (pthread_create(&uipc_main.tid, (const pthread_attr_t *) NULL,
+                       uipc_read_task, nullptr) < 0)
+    {
+        BTIF_TRACE_ERROR("uipc_thread_create pthread_create failed:%d", errno);
+        return -1;
+    }
+
+    return 0;
+}
+
+/* blocking call */
+void uipc_stop_main_server_thread(void)
+{
+    /* request shutdown of read thread */
+    UIPC_LOCK();
+    uipc_main.running = 0;
+    uipc_wakeup_locked();
+    UIPC_UNLOCK();
+
+    /* wait until read thread is fully terminated */
+    /* tid might hold pointer value where it's value
+       is negative vaule with singed bit is set, so
+       corrected the logic to check zero or non zero */
+    if (uipc_main.tid)
+        pthread_join(uipc_main.tid, NULL);
+}
+
+/*******************************************************************************
+ **
+ ** Function         UIPC_Init
+ **
+ ** Description      Initialize UIPC module
+ **
+ ** Returns          void
+ **
+ *******************************************************************************/
+
+void UIPC_Init(UNUSED_ATTR void *p_data)
+{
+    BTIF_TRACE_DEBUG("UIPC_Init");
+
+    memset(&uipc_main, 0, sizeof(tUIPC_MAIN));
+
+    uipc_main_init();
+
+    uipc_start_main_server_thread();
+}
+
+/*******************************************************************************
+ **
+ ** Function         UIPC_Open
+ **
+ ** Description      Open UIPC interface
+ **
+ ** Returns          true in case of success, false in case of failure.
+ **
+ *******************************************************************************/
+bool    UIPC_Open(tUIPC_CH_ID ch_id, tUIPC_RCV_CBACK *p_cback)
+{
+    BTIF_TRACE_DEBUG("UIPC_Open : ch_id %d, p_cback %x", ch_id, p_cback);
+
+    UIPC_LOCK();
+
+    if (ch_id >= UIPC_CH_NUM)
+    {
+        UIPC_UNLOCK();
+        return false;
+    }
+
+    if (uipc_main.ch[ch_id].srvfd != UIPC_DISCONNECTED)
+    {
+        BTIF_TRACE_EVENT("CHANNEL %d ALREADY OPEN", ch_id);
+        UIPC_UNLOCK();
+        return 0;
+    }
+
+    switch(ch_id)
+    {
+        case UIPC_CH_ID_AV_CTRL:
+            uipc_setup_server_locked(ch_id, A2DP_CTRL_PATH, p_cback);
+            break;
+
+        case UIPC_CH_ID_AV_AUDIO:
+            uipc_setup_server_locked(ch_id, A2DP_DATA_PATH, p_cback);
+            break;
+    }
+
+    UIPC_UNLOCK();
+
+    return true;
+}
+
+/*******************************************************************************
+ **
+ ** Function         UIPC_Close
+ **
+ ** Description      Close UIPC interface
+ **
+ ** Returns          void
+ **
+ *******************************************************************************/
+
+void UIPC_Close(tUIPC_CH_ID ch_id)
+{
+    BTIF_TRACE_DEBUG("UIPC_Close : ch_id %d", ch_id);
+
+    /* special case handling uipc shutdown */
+    if (ch_id != UIPC_CH_ID_ALL)
+    {
+        UIPC_LOCK();
+        uipc_close_locked(ch_id);
+        UIPC_UNLOCK();
+    }
+    else
+    {
+        BTIF_TRACE_DEBUG("UIPC_Close : waiting for shutdown to complete");
+        uipc_stop_main_server_thread();
+        BTIF_TRACE_DEBUG("UIPC_Close : shutdown complete");
+    }
+}
+
+/*******************************************************************************
+ **
+ ** Function         UIPC_Send
+ **
+ ** Description      Called to transmit a message over UIPC.
+ **
+ ** Returns          true in case of success, false in case of failure.
+ **
+ *******************************************************************************/
+bool    UIPC_Send(tUIPC_CH_ID ch_id,
+                  UNUSED_ATTR uint16_t msg_evt, uint8_t *p_buf,
+        uint16_t msglen)
+{
+    BTIF_TRACE_DEBUG("UIPC_Send : ch_id:%d %d bytes", ch_id, msglen);
+
+    UIPC_LOCK();
+
+    ssize_t ret;
+    OSI_NO_INTR(ret = write(uipc_main.ch[ch_id].fd, p_buf, msglen));
+    if (ret < 0) {
+        BTIF_TRACE_ERROR("failed to write (%s)", strerror(errno));
+    }
+
+    UIPC_UNLOCK();
+
+    return false;
+}
+
+/*******************************************************************************
+ **
+ ** Function         UIPC_Read
+ **
+ ** Description      Called to read a message from UIPC.
+ **
+ ** Returns          return the number of bytes read.
+ **
+ *******************************************************************************/
+
+uint32_t UIPC_Read(tUIPC_CH_ID ch_id,
+                   UNUSED_ATTR uint16_t *p_msg_evt, uint8_t *p_buf,
+                   uint32_t len)
+{
+    int n_read = 0;
+    int fd = uipc_main.ch[ch_id].fd;
+    struct pollfd pfd;
+
+    if (ch_id >= UIPC_CH_NUM)
+    {
+        BTIF_TRACE_ERROR("UIPC_Read : invalid ch id %d", ch_id);
+        return 0;
+    }
+
+    if (fd == UIPC_DISCONNECTED)
+    {
+        BTIF_TRACE_ERROR("UIPC_Read : channel %d closed", ch_id);
+        return 0;
+    }
+
+    //BTIF_TRACE_DEBUG("UIPC_Read : ch_id %d, len %d, fd %d, polltmo %d", ch_id, len,
+    //        fd, uipc_main.ch[ch_id].read_poll_tmo_ms);
+
+    while (n_read < (int)len)
+    {
+        pfd.fd = fd;
+        pfd.events = POLLIN|POLLHUP;
+
+        /* make sure there is data prior to attempting read to avoid blocking
+           a read for more than poll timeout */
+
+        int poll_ret;
+        OSI_NO_INTR(poll_ret = poll(&pfd, 1,
+                                    uipc_main.ch[ch_id].read_poll_tmo_ms));
+        if (poll_ret == 0)
+        {
+            BTIF_TRACE_WARNING("poll timeout (%d ms)", uipc_main.ch[ch_id].read_poll_tmo_ms);
+            break;
+        }
+        if (poll_ret < 0) {
+            BTIF_TRACE_ERROR("%s(): poll() failed: return %d errno %d (%s)",
+                           __func__, poll_ret, errno, strerror(errno));
+            break;
+        }
+
+        //BTIF_TRACE_EVENT("poll revents %x", pfd.revents);
+
+        if (pfd.revents & (POLLHUP|POLLNVAL) )
+        {
+            BTIF_TRACE_WARNING("poll : channel detached remotely");
+            UIPC_LOCK();
+            uipc_close_locked(ch_id);
+            UIPC_UNLOCK();
+            return 0;
+        }
+
+        ssize_t n;
+        OSI_NO_INTR(n = recv(fd, p_buf+n_read, len-n_read, 0));
+
+        //BTIF_TRACE_EVENT("read %d bytes", n);
+
+        if (n == 0)
+        {
+            BTIF_TRACE_WARNING("UIPC_Read : channel detached remotely");
+            UIPC_LOCK();
+            uipc_close_locked(ch_id);
+            UIPC_UNLOCK();
+            return 0;
+        }
+
+        if (n < 0)
+        {
+            BTIF_TRACE_WARNING("UIPC_Read : read failed (%s)", strerror(errno));
+            return 0;
+        }
+
+        n_read+=n;
+
+    }
+
+    return n_read;
+}
+
+/*******************************************************************************
+**
+** Function         UIPC_Ioctl
+**
+** Description      Called to control UIPC.
+**
+** Returns          void
+**
+*******************************************************************************/
+
+extern bool    UIPC_Ioctl(tUIPC_CH_ID ch_id, uint32_t request, void *param)
+{
+    BTIF_TRACE_DEBUG("#### UIPC_Ioctl : ch_id %d, request %d ####", ch_id, request);
+
+    UIPC_LOCK();
+
+    switch(request)
+    {
+        case UIPC_REQ_RX_FLUSH:
+            uipc_flush_locked(ch_id);
+            break;
+
+        case UIPC_REG_CBACK:
+            //BTIF_TRACE_EVENT("register callback ch %d srvfd %d, fd %d", ch_id, uipc_main.ch[ch_id].srvfd, uipc_main.ch[ch_id].fd);
+            uipc_main.ch[ch_id].cback = (tUIPC_RCV_CBACK*)param;
+            break;
+
+        case UIPC_REG_REMOVE_ACTIVE_READSET:
+
+            /* user will read data directly and not use select loop */
+            if (uipc_main.ch[ch_id].fd != UIPC_DISCONNECTED)
+            {
+                /* remove this channel from active set */
+                FD_CLR(uipc_main.ch[ch_id].fd, &uipc_main.active_set);
+
+                /* refresh active set */
+                uipc_wakeup_locked();
+            }
+            break;
+
+        case UIPC_SET_READ_POLL_TMO:
+            uipc_main.ch[ch_id].read_poll_tmo_ms = (intptr_t)param;
+            BTIF_TRACE_EVENT("UIPC_SET_READ_POLL_TMO : CH %d, TMO %d ms", ch_id, uipc_main.ch[ch_id].read_poll_tmo_ms );
+            break;
+
+        default:
+            BTIF_TRACE_EVENT("UIPC_Ioctl : request not handled (%d)", request);
+            break;
+    }
+
+    UIPC_UNLOCK();
+
+    return false;
+}
+
diff --git a/bt/udrv/ulinux/uipc_linux.h b/bt/udrv/ulinux/uipc_linux.h
new file mode 100644
index 0000000..45cfc31
--- /dev/null
+++ b/bt/udrv/ulinux/uipc_linux.h
@@ -0,0 +1,41 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2007-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.
+ *
+ ******************************************************************************/
+#ifndef _UIPC_LINUX_H_
+#define _UIPC_LINUX_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int SOCKET;
+#define INVALID_SOCKET  (SOCKET)(-1)
+#define SOCKET_ERROR            (-1)
+
+/* tcp/ip socket configuration */
+typedef struct {
+    char            *p_address;
+    unsigned int    port;
+} tUIPC_LINUX_CFG_TCP ;
+
+/* Socket configuration for GLGPS interface */
+extern tUIPC_LINUX_CFG_TCP uipc_linux_cfg_glgps;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _UIPC_LINUX_H_ */
diff --git a/bt/utils/Android.mk b/bt/utils/Android.mk
new file mode 100644
index 0000000..5ba3e88
--- /dev/null
+++ b/bt/utils/Android.mk
@@ -0,0 +1,27 @@
+LOCAL_PATH := $(call my-dir)
+
+# Utils static library for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_CPP_EXTENSION := .cc
+
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH)/include \
+    $(LOCAL_PATH)/../btcore/include \
+    $(LOCAL_PATH)/../stack/include \
+    $(LOCAL_PATH)/../ \
+    $(bluetooth_C_INCLUDES)
+
+LOCAL_SRC_FILES := \
+    ./src/bt_utils.cc
+
+LOCAL_MODULE := libbt-utils
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/bt/utils/BUILD.gn b/bt/utils/BUILD.gn
new file mode 100644
index 0000000..13d57a1
--- /dev/null
+++ b/bt/utils/BUILD.gn
@@ -0,0 +1,27 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+static_library("utils") {
+  sources = [
+    "src/bt_utils.cc",
+  ]
+
+  include_dirs = [
+    "include",
+    "//",
+    "//stack/include",
+  ]
+}
diff --git a/bt/utils/include/bt_utils.h b/bt/utils/include/bt_utils.h
new file mode 100644
index 0000000..fb0ff7c
--- /dev/null
+++ b/bt/utils/include/bt_utils.h
@@ -0,0 +1,49 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BT_UTILS_H
+#define BT_UTILS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static const char BT_UTILS_MODULE[] = "bt_utils_module";
+
+/*******************************************************************************
+**  Type definitions
+********************************************************************************/
+
+typedef enum {
+    TASK_HIGH_MEDIA = 0,
+    TASK_UIPC_READ,
+    TASK_HIGH_MAX
+} tHIGH_PRIORITY_TASK;
+
+/*******************************************************************************
+**  Functions
+********************************************************************************/
+
+void raise_priority_a2dp(tHIGH_PRIORITY_TASK high_task);
+void adjust_priority_a2dp(int start);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BT_UTILS_H */
diff --git a/bt/utils/src/bt_utils.cc b/bt/utils/src/bt_utils.cc
new file mode 100644
index 0000000..a524edf
--- /dev/null
+++ b/bt/utils/src/bt_utils.cc
@@ -0,0 +1,188 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ *  Filename:      bt_utils.cc
+ *
+ *  Description:   Miscellaneous helper functions
+ *
+ *
+ ***********************************************************************************/
+
+#define LOG_TAG "bt_utils"
+
+#include "bt_utils.h"
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+#ifdef OS_GENERIC
+#define ANDROID_PRIORITY_AUDIO -16
+#define ANDROID_PRIORITY_URGENT_AUDIO -19
+#else
+#include <utils/ThreadDefs.h>
+#include <cutils/sched_policy.h>
+#endif
+
+#include "bt_types.h"
+#include "btcore/include/module.h"
+#include "osi/include/compat.h"
+#include "osi/include/log.h"
+#include "osi/include/properties.h"
+
+/*******************************************************************************
+**  Type definitions for callback functions
+********************************************************************************/
+static pthread_once_t g_DoSchedulingGroupOnce[TASK_HIGH_MAX];
+static bool    g_DoSchedulingGroup[TASK_HIGH_MAX];
+static pthread_mutex_t         gIdxLock;
+static int g_TaskIdx;
+static int g_TaskIDs[TASK_HIGH_MAX];
+#define INVALID_TASK_ID  (-1)
+
+static future_t *init(void) {
+  int i;
+  pthread_mutexattr_t lock_attr;
+
+  for(i = 0; i < TASK_HIGH_MAX; i++) {
+    g_DoSchedulingGroupOnce[i] = PTHREAD_ONCE_INIT;
+    g_DoSchedulingGroup[i] = true;
+    g_TaskIDs[i] = INVALID_TASK_ID;
+  }
+
+  pthread_mutexattr_init(&lock_attr);
+  pthread_mutex_init(&gIdxLock, &lock_attr);
+  return NULL;
+}
+
+static future_t *clean_up(void) {
+  pthread_mutex_destroy(&gIdxLock);
+  return NULL;
+}
+
+EXPORT_SYMBOL extern const module_t bt_utils_module = {
+  .name = BT_UTILS_MODULE,
+  .init = init,
+  .start_up = NULL,
+  .shut_down = NULL,
+  .clean_up = clean_up,
+  .dependencies = {
+    NULL
+  }
+};
+
+/*****************************************************************************
+**
+** Function        check_do_scheduling_group
+**
+** Description     check if it is ok to change schedule group
+**
+** Returns         void
+**
+*******************************************************************************/
+static void check_do_scheduling_group(void) {
+    char buf[PROPERTY_VALUE_MAX];
+    int len = osi_property_get("debug.sys.noschedgroups", buf, "");
+    if (len > 0) {
+        int temp;
+        if (sscanf(buf, "%d", &temp) == 1) {
+            g_DoSchedulingGroup[g_TaskIdx] = temp == 0;
+        }
+    }
+}
+
+/*****************************************************************************
+**
+** Function        raise_priority_a2dp
+**
+** Description     Raise task priority for A2DP streaming
+**
+** Returns         void
+**
+*******************************************************************************/
+void raise_priority_a2dp(tHIGH_PRIORITY_TASK high_task) {
+    int rc = 0;
+    int tid = gettid();
+    int priority = ANDROID_PRIORITY_AUDIO;
+
+    pthread_mutex_lock(&gIdxLock);
+    g_TaskIdx = high_task;
+
+    // TODO(armansito): Remove this conditional check once we find a solution
+    // for system/core on non-Android platforms.
+#if defined(OS_GENERIC)
+    rc = -1;
+#else  // !defined(OS_GENERIC)
+    pthread_once(&g_DoSchedulingGroupOnce[g_TaskIdx], check_do_scheduling_group);
+    if (g_DoSchedulingGroup[g_TaskIdx]) {
+        // set_sched_policy does not support tid == 0
+        rc = set_sched_policy(tid, SP_AUDIO_SYS);
+    }
+#endif  // defined(OS_GENERIC)
+
+    g_TaskIDs[high_task] = tid;
+    pthread_mutex_unlock(&gIdxLock);
+
+    if (rc) {
+        LOG_WARN(LOG_TAG, "failed to change sched policy, tid %d, err: %d", tid, errno);
+    }
+
+    // always use urgent priority for HCI worker thread until we can adjust
+    // its prio individually. All other threads can be dynamically adjusted voa
+    // adjust_priority_a2dp()
+
+    priority = ANDROID_PRIORITY_URGENT_AUDIO;
+
+    if (setpriority(PRIO_PROCESS, tid, priority) < 0) {
+        LOG_WARN(LOG_TAG, "failed to change priority tid: %d to %d", tid, priority);
+    }
+}
+
+/*****************************************************************************
+**
+** Function        adjust_priority_a2dp
+**
+** Description     increase the a2dp consumer task priority temporarily when start
+**                 audio playing, to avoid overflow the audio packet queue, restore
+**                 the a2dp consumer task priority when stop audio playing.
+**
+** Returns         void
+**
+*******************************************************************************/
+void adjust_priority_a2dp(int start) {
+    int priority = start ? ANDROID_PRIORITY_URGENT_AUDIO : ANDROID_PRIORITY_AUDIO;
+    int tid;
+    int i;
+
+    for (i = 0; i < TASK_HIGH_MAX; i++)
+    {
+        tid = g_TaskIDs[i];
+        if (tid != INVALID_TASK_ID)
+        {
+            if (setpriority(PRIO_PROCESS, tid, priority) < 0)
+            {
+                LOG_WARN(LOG_TAG, "failed to change priority tid: %d to %d", tid, priority);
+            }
+        }
+    }
+}
diff --git a/bt/vendor_libs/Android.mk b/bt/vendor_libs/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/bt/vendor_libs/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/bt/vendor_libs/BUILD.gn b/bt/vendor_libs/BUILD.gn
new file mode 100644
index 0000000..a088315
--- /dev/null
+++ b/bt/vendor_libs/BUILD.gn
@@ -0,0 +1,22 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+group("vendor-libs") {
+  deps = [
+    "linux:bt-vendor-linux",
+    "test_vendor_lib:test_vendor_lib",
+  ]
+}
diff --git a/bt/vendor_libs/linux/Android.mk b/bt/vendor_libs/linux/Android.mk
new file mode 100644
index 0000000..3cdaabc
--- /dev/null
+++ b/bt/vendor_libs/linux/Android.mk
@@ -0,0 +1,47 @@
+#
+#  Copyright (C) 2015 Intel 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+ifeq ($(BOARD_HAVE_BLUETOOTH_LINUX), true)
+
+# libbt-vendor shared library for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_CPP_EXTENSION := .cc
+
+LOCAL_SRC_FILES := \
+        bt_vendor_linux.cc
+
+LOCAL_C_INCLUDES := \
+        $(LOCAL_PATH)/../../
+
+LOCAL_SHARED_LIBRARIES := \
+        libcutils
+
+LOCAL_STATIC_LIBRARIES := libosi
+
+LOCAL_MODULE := libbt-vendor
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif  # BOARD_HAVE_BLUETOOTH_LINUX
diff --git a/bt/vendor_libs/linux/BUILD.gn b/bt/vendor_libs/linux/BUILD.gn
new file mode 100644
index 0000000..1b7d5d9
--- /dev/null
+++ b/bt/vendor_libs/linux/BUILD.gn
@@ -0,0 +1,33 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+shared_library("bt-vendor-linux") {
+  output_name = "libbt-vendor"
+  sources = [
+    "bt_vendor_linux.cc",
+  ]
+
+  deps = [
+   "//osi",
+  ]
+
+  cflags_c = [
+    "-Lobj/osi",
+    "-losi",
+  ]
+
+  include_dirs = [ "//" ]
+}
diff --git a/bt/vendor_libs/linux/bt_vendor_linux.cc b/bt/vendor_libs/linux/bt_vendor_linux.cc
new file mode 100644
index 0000000..5270eab
--- /dev/null
+++ b/bt/vendor_libs/linux/bt_vendor_linux.cc
@@ -0,0 +1,411 @@
+/**********************************************************************
+ *
+ *  Copyright (C) 2015 Intel 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.
+ *
+ **********************************************************************/
+
+#define LOG_TAG "bt_vendor"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include "hci/include/bt_vendor_lib.h"
+#include "osi/include/compat.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+
+#define BTPROTO_HCI 1
+#define HCI_CHANNEL_USER 1
+#define HCI_CHANNEL_CONTROL 3
+#define HCI_DEV_NONE 0xffff
+
+#define RFKILL_TYPE_BLUETOOTH 2
+#define RFKILL_OP_CHANGE_ALL 3
+
+#define MGMT_OP_INDEX_LIST 0x0003
+#define MGMT_EV_INDEX_ADDED 0x0004
+#define MGMT_EV_COMMAND_COMP 0x0001
+#define MGMT_EV_SIZE_MAX 1024
+#define MGMT_EV_POLL_TIMEOUT 3000 /* 3000ms */
+
+#define IOCTL_HCIDEVDOWN _IOW('H', 202, int)
+
+struct sockaddr_hci {
+  sa_family_t hci_family;
+  unsigned short hci_dev;
+  unsigned short hci_channel;
+};
+
+struct rfkill_event {
+  uint32_t idx;
+  uint8_t type;
+  uint8_t op;
+  uint8_t soft, hard;
+} __attribute__((packed));
+
+struct mgmt_pkt {
+  uint16_t opcode;
+  uint16_t index;
+  uint16_t len;
+  uint8_t data[MGMT_EV_SIZE_MAX];
+} __attribute__((packed));
+
+struct mgmt_event_read_index {
+  uint16_t cc_opcode;
+  uint8_t status;
+  uint16_t num_intf;
+  uint16_t index[0];
+} __attribute__((packed));
+
+static const bt_vendor_callbacks_t* bt_vendor_callbacks;
+static unsigned char bt_vendor_local_bdaddr[6];
+static int bt_vendor_fd = -1;
+static int hci_interface;
+static int rfkill_en;
+static int bt_hwcfg_en;
+
+static int bt_vendor_init(const bt_vendor_callbacks_t* p_cb,
+                          unsigned char* local_bdaddr) {
+  char prop_value[PROPERTY_VALUE_MAX];
+
+  LOG_INFO(LOG_TAG, "%s", __func__);
+
+  if (p_cb == NULL) {
+    LOG_ERROR(LOG_TAG, "init failed with no user callbacks!");
+    return -1;
+  }
+
+  bt_vendor_callbacks = p_cb;
+
+  memcpy(bt_vendor_local_bdaddr, local_bdaddr, sizeof(bt_vendor_local_bdaddr));
+
+  osi_property_get("bluetooth.interface", prop_value, "0");
+
+  errno = 0;
+  if (memcmp(prop_value, "hci", 3))
+    hci_interface = strtol(prop_value, NULL, 10);
+  else
+    hci_interface = strtol(prop_value + 3, NULL, 10);
+  if (errno) hci_interface = 0;
+
+  LOG_INFO(LOG_TAG, "Using interface hci%d", hci_interface);
+
+  osi_property_get("bluetooth.rfkill", prop_value, "0");
+
+  rfkill_en = atoi(prop_value);
+  if (rfkill_en) LOG_INFO(LOG_TAG, "RFKILL enabled");
+
+  bt_hwcfg_en =
+      osi_property_get("bluetooth.hwcfg", prop_value, NULL) > 0 ? 1 : 0;
+  if (bt_hwcfg_en) LOG_INFO(LOG_TAG, "HWCFG enabled");
+
+  return 0;
+}
+
+static int bt_vendor_hw_cfg(int stop) {
+  if (!bt_hwcfg_en) return 0;
+
+  if (stop) {
+    if (osi_property_set("bluetooth.hwcfg", "stop") < 0) {
+      LOG_ERROR(LOG_TAG, "%s cannot stop btcfg service via prop", __func__);
+      return 1;
+    }
+  } else {
+    if (osi_property_set("bluetooth.hwcfg", "start") < 0) {
+      LOG_ERROR(LOG_TAG, "%s cannot start btcfg service via prop", __func__);
+      return 1;
+    }
+  }
+  return 0;
+}
+
+static int bt_vendor_wait_hcidev(void) {
+  struct sockaddr_hci addr;
+  struct pollfd fds[1];
+  struct mgmt_pkt ev;
+  int fd;
+  int ret = 0;
+
+  LOG_INFO(LOG_TAG, "%s", __func__);
+
+  fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+  if (fd < 0) {
+    LOG_ERROR(LOG_TAG, "Bluetooth socket error: %s", strerror(errno));
+    return -1;
+  }
+
+  memset(&addr, 0, sizeof(addr));
+  addr.hci_family = AF_BLUETOOTH;
+  addr.hci_dev = HCI_DEV_NONE;
+  addr.hci_channel = HCI_CHANNEL_CONTROL;
+
+  if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+    LOG_ERROR(LOG_TAG, "HCI Channel Control: %s", strerror(errno));
+    close(fd);
+    return -1;
+  }
+
+  fds[0].fd = fd;
+  fds[0].events = POLLIN;
+
+  /* Read Controller Index List Command */
+  ev.opcode = MGMT_OP_INDEX_LIST;
+  ev.index = HCI_DEV_NONE;
+  ev.len = 0;
+
+  ssize_t wrote;
+  OSI_NO_INTR(wrote = write(fd, &ev, 6));
+  if (wrote != 6) {
+    LOG_ERROR(LOG_TAG, "Unable to write mgmt command: %s", strerror(errno));
+    ret = -1;
+    goto end;
+  }
+
+  while (1) {
+    int n;
+    OSI_NO_INTR(n = poll(fds, 1, MGMT_EV_POLL_TIMEOUT));
+    if (n == -1) {
+      LOG_ERROR(LOG_TAG, "Poll error: %s", strerror(errno));
+      ret = -1;
+      break;
+    } else if (n == 0) {
+      LOG_ERROR(LOG_TAG, "Timeout, no HCI device detected");
+      ret = -1;
+      break;
+    }
+
+    if (fds[0].revents & POLLIN) {
+      OSI_NO_INTR(n = read(fd, &ev, sizeof(struct mgmt_pkt)));
+      if (n < 0) {
+        LOG_ERROR(LOG_TAG, "Error reading control channel: %s",
+                  strerror(errno));
+        ret = -1;
+        break;
+      }
+
+      if (ev.opcode == MGMT_EV_INDEX_ADDED && ev.index == hci_interface) {
+        goto end;
+      } else if (ev.opcode == MGMT_EV_COMMAND_COMP) {
+        struct mgmt_event_read_index* cc;
+        int i;
+
+        cc = (struct mgmt_event_read_index*)ev.data;
+
+        if (cc->cc_opcode != MGMT_OP_INDEX_LIST || cc->status != 0) continue;
+
+        for (i = 0; i < cc->num_intf; i++) {
+          if (cc->index[i] == hci_interface) goto end;
+        }
+      }
+    }
+  }
+
+end:
+  close(fd);
+  return ret;
+}
+
+static int bt_vendor_open(void* param) {
+  int(*fd_array)[] = (int(*)[])param;
+  int fd;
+
+  LOG_INFO(LOG_TAG, "%s", __func__);
+
+  fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+  if (fd < 0) {
+    LOG_ERROR(LOG_TAG, "socket create error %s", strerror(errno));
+    return -1;
+  }
+
+  (*fd_array)[CH_CMD] = fd;
+  (*fd_array)[CH_EVT] = fd;
+  (*fd_array)[CH_ACL_OUT] = fd;
+  (*fd_array)[CH_ACL_IN] = fd;
+
+  bt_vendor_fd = fd;
+
+  LOG_INFO(LOG_TAG, "%s returning %d", __func__, bt_vendor_fd);
+
+  return 1;
+}
+
+static int bt_vendor_close(void* param) {
+  (void)(param);
+
+  LOG_INFO(LOG_TAG, "%s", __func__);
+
+  if (bt_vendor_fd != -1) {
+    close(bt_vendor_fd);
+    bt_vendor_fd = -1;
+  }
+
+  return 0;
+}
+
+static int bt_vendor_rfkill(int block) {
+  struct rfkill_event event;
+  int fd;
+
+  LOG_INFO(LOG_TAG, "%s", __func__);
+
+  fd = open("/dev/rfkill", O_WRONLY);
+  if (fd < 0) {
+    LOG_ERROR(LOG_TAG, "Unable to open /dev/rfkill");
+    return -1;
+  }
+
+  memset(&event, 0, sizeof(struct rfkill_event));
+  event.op = RFKILL_OP_CHANGE_ALL;
+  event.type = RFKILL_TYPE_BLUETOOTH;
+  event.hard = block;
+  event.soft = block;
+
+  ssize_t len;
+  OSI_NO_INTR(len = write(fd, &event, sizeof(event)));
+  if (len < 0) {
+    LOG_ERROR(LOG_TAG, "Failed to change rfkill state");
+    close(fd);
+    return 1;
+  }
+
+  close(fd);
+  return 0;
+}
+
+/* TODO: fw config should thread the device waiting and return immedialty */
+static void bt_vendor_fw_cfg(void) {
+  struct sockaddr_hci addr;
+  int fd = bt_vendor_fd;
+
+  LOG_INFO(LOG_TAG, "%s", __func__);
+
+  if (fd == -1) {
+    LOG_ERROR(LOG_TAG, "bt_vendor_fd: %s", strerror(EBADF));
+    goto failure;
+  }
+
+  memset(&addr, 0, sizeof(addr));
+  addr.hci_family = AF_BLUETOOTH;
+  addr.hci_dev = hci_interface;
+  addr.hci_channel = HCI_CHANNEL_USER;
+
+  if (bt_vendor_wait_hcidev()) {
+    LOG_ERROR(LOG_TAG, "HCI interface (%d) not found", hci_interface);
+    goto failure;
+  }
+
+  if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+    LOG_ERROR(LOG_TAG, "socket bind error %s", strerror(errno));
+    goto failure;
+  }
+
+  LOG_INFO(LOG_TAG, "HCI device ready");
+
+  bt_vendor_callbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);
+
+  return;
+
+failure:
+  LOG_ERROR(LOG_TAG, "Hardware Config Error");
+  bt_vendor_callbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
+}
+
+static int bt_vendor_op(bt_vendor_opcode_t opcode, void* param) {
+  int retval = 0;
+
+  LOG_INFO(LOG_TAG, "%s op %d", __func__, opcode);
+
+  switch (opcode) {
+    case BT_VND_OP_POWER_CTRL:
+      if (!rfkill_en || !param) break;
+
+      if (*((int*)param) == BT_VND_PWR_ON) {
+        retval = bt_vendor_rfkill(0);
+        if (!retval) retval = bt_vendor_hw_cfg(0);
+      } else {
+        retval = bt_vendor_hw_cfg(1);
+        if (!retval) retval = bt_vendor_rfkill(1);
+      }
+
+      break;
+
+    case BT_VND_OP_FW_CFG:
+      bt_vendor_fw_cfg();
+      break;
+
+    case BT_VND_OP_SCO_CFG:
+      bt_vendor_callbacks->scocfg_cb(BT_VND_OP_RESULT_SUCCESS);
+      break;
+
+    case BT_VND_OP_USERIAL_OPEN:
+      retval = bt_vendor_open(param);
+      break;
+
+    case BT_VND_OP_USERIAL_CLOSE:
+      retval = bt_vendor_close(param);
+      break;
+
+    case BT_VND_OP_GET_LPM_IDLE_TIMEOUT:
+      *((uint32_t*)param) = 3000;
+      retval = 0;
+      break;
+
+    case BT_VND_OP_LPM_SET_MODE:
+      bt_vendor_callbacks->lpm_cb(BT_VND_OP_RESULT_SUCCESS);
+      break;
+
+    case BT_VND_OP_LPM_WAKE_SET_STATE:
+      break;
+
+    case BT_VND_OP_SET_AUDIO_STATE:
+      bt_vendor_callbacks->audio_state_cb(BT_VND_OP_RESULT_SUCCESS);
+      break;
+
+    case BT_VND_OP_EPILOG:
+      bt_vendor_callbacks->epilog_cb(BT_VND_OP_RESULT_SUCCESS);
+      break;
+
+    case BT_VND_OP_A2DP_OFFLOAD_START:
+      break;
+
+    case BT_VND_OP_A2DP_OFFLOAD_STOP:
+      break;
+  }
+
+  LOG_INFO(LOG_TAG, "%s op %d retval %d", __func__, opcode, retval);
+
+  return retval;
+}
+
+static void bt_vendor_cleanup(void) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+
+  bt_vendor_callbacks = NULL;
+}
+
+EXPORT_SYMBOL const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = {
+    sizeof(bt_vendor_interface_t), bt_vendor_init, bt_vendor_op,
+    bt_vendor_cleanup,
+};
diff --git a/bt/vendor_libs/test_vendor_lib/Android.mk b/bt/vendor_libs/test_vendor_lib/Android.mk
new file mode 100644
index 0000000..8ea93e9
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/Android.mk
@@ -0,0 +1,112 @@
+LOCAL_PATH := $(call my-dir)
+
+# test-vendor shared library for target
+# ========================================================
+include $(CLEAR_VARS)
+
+BT_DIR := $(TOP_DIR)system/bt
+
+LOCAL_SRC_FILES := \
+    src/async_manager.cc \
+    src/bt_address.cc \
+    src/bt_vendor.cc \
+    src/command_packet.cc \
+    src/dual_mode_controller.cc \
+    src/event_packet.cc \
+    src/hci_transport.cc \
+    src/packet.cc \
+    src/packet_stream.cc \
+    src/test_channel_transport.cc \
+    src/vendor_manager.cc
+
+# We pull in gtest because base/files/file_util.h, which is used to read the
+# controller properties file, needs gtest/gtest_prod.h.
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH)/include \
+    $(BT_DIR) \
+    $(BT_DIR)/include \
+    $(BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR) \
+    $(BT_DIR)/utils/include \
+    $(BT_DIR)/hci/include \
+    $(BT_DIR)/stack/include \
+    $(BT_DIR)/third_party/gtest/include
+
+LOCAL_SHARED_LIBRARIES := \
+    liblog \
+    libchrome
+
+LOCAL_CPP_EXTENSION := .cc
+# On some devices this is the actual vendor library. On other devices build
+# as a test library.
+ifneq (,$(BOARD_BLUETOOTH_USE_TEST_AS_VENDOR))
+LOCAL_MODULE := libbt-vendor
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_SHARED_LIBRARIES)
+LOCAL_CFLAGS += -DBLUETOOTH_USE_TEST_AS_VENDOR
+ifeq ($(TARGET_TRANSLATE_2ND_ARCH),true)
+# If its vendor library and secondary arch is translated then only one library
+# is provided
+ifneq (1,$(words $(LOCAL_MODULE_TARGET_ARCH)))
+LOCAL_MULTILIB := first
+endif
+endif
+else
+LOCAL_MODULE := test-vendor
+endif
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+
+LOCAL_CFLAGS += \
+  -fvisibility=hidden \
+  -Wall \
+  -Wextra \
+  -Werror \
+  -UNDEBUG \
+  -DLOG_NDEBUG=1
+
+LOCAL_CFLAGS += -DEXPORT_SYMBOL="__attribute__((visibility(\"default\")))"
+
+include $(BUILD_SHARED_LIBRARY)
+
+# test-vendor unit tests for host
+# ========================================================
+ifeq ($(HOST_OS), linux)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    src/async_manager.cc \
+    src/bt_address.cc \
+    src/command_packet.cc \
+    src/event_packet.cc \
+    src/hci_transport.cc \
+    src/packet.cc \
+    src/packet_stream.cc \
+    test/async_manager_unittest.cc \
+    test/bt_address_unittest.cc \
+    test/hci_transport_unittest.cc \
+    test/packet_stream_unittest.cc
+
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH)/include \
+    $(BT_DIR) \
+    $(BT_DIR)/utils/include \
+    $(BT_DIR)/hci/include \
+    $(BT_DIR)/stack/include
+
+LOCAL_SHARED_LIBRARIES := \
+    liblog \
+    libchrome
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_MODULE := test-vendor_test_host
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_CFLAGS += \
+  -fvisibility=hidden \
+  -Wall \
+  -Wextra \
+  -Werror \
+  -UNDEBUG \
+  -DLOG_NDEBUG=1
+
+include $(BUILD_HOST_NATIVE_TEST)
+endif
diff --git a/bt/vendor_libs/test_vendor_lib/BUILD.gn b/bt/vendor_libs/test_vendor_lib/BUILD.gn
new file mode 100644
index 0000000..ad42c28
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/BUILD.gn
@@ -0,0 +1,63 @@
+shared_library("test_vendor_lib") {
+  sources = [
+    "src/async_manager.cc",
+    "src/bt_address.cc",
+    "src/bt_vendor.cc",
+    "src/command_packet.cc",
+    "src/dual_mode_controller.cc",
+    "src/event_packet.cc",
+    "src/hci_transport.cc",
+    "src/packet.cc",
+    "src/packet_stream.cc",
+    "src/test_channel_transport.cc",
+    "src/vendor_manager.cc",
+  ]
+
+  include_dirs = [
+    "include",
+    "//",
+
+    # TODO(dennischeng): Ideally we should need to have the lines below for
+    # indirect includes.
+    "//stack/include",
+  ]
+
+  deps = [
+    "//third_party/libchrome:base"
+  ]
+}
+
+executable("test_vendor_lib_test") {
+  testonly = true
+  sources = [
+    "src/async_manager.cc",
+    "src/command_packet.cc",
+    "src/event_packet.cc",
+    "src/hci_transport.cc",
+    "src/packet.cc",
+    "src/packet_stream.cc",
+    "test/hci_transport_unittest.cc",
+    "test/packet_stream_unittest.cc",
+  ]
+
+  include_dirs = [
+    "include",
+    "//",
+    "//btcore/include",
+    "//hci/include",
+    "//stack/include",
+  ]
+
+  deps = [
+    "//third_party/googletest:gtest_main",
+    "//third_party/libchrome:base",
+    "//vendor_libs/test_vendor_lib",
+  ]
+
+  libs = [
+    "-lpthread",
+    "-lrt",
+    "-ldl",
+    "-latomic",
+  ]
+}
diff --git a/bt/vendor_libs/test_vendor_lib/data/controller_properties.json b/bt/vendor_libs/test_vendor_lib/data/controller_properties.json
new file mode 100644
index 0000000..32adc52
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/data/controller_properties.json
@@ -0,0 +1,13 @@
+{
+  "AclDataPacketSize": "1024",
+  "ScoDataPacketSize": "255",
+  "NumAclDataPackets": "10",
+  "NumScoDataPackets": "10",
+  "Version": "4",
+  "Revision": "0",
+  "LmpPalVersion": "0",
+  "ManufacturerName": "0",
+  "LmpPalSubversion": "0",
+  "MaximumPageNumber": "0",
+  "BdAddress": "123456"
+}
diff --git a/bt/vendor_libs/test_vendor_lib/include/async_manager.h b/bt/vendor_libs/test_vendor_lib/include/async_manager.h
new file mode 100644
index 0000000..71b2e07
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/include/async_manager.h
@@ -0,0 +1,107 @@
+#ifndef TEST_VENDOR_LIB_ASYNC_MANAGER_H_
+#define TEST_VENDOR_LIB_ASYNC_MANAGER_H_
+
+#include <time.h>
+#include <cstdint>
+#include <map>
+#include <set>
+#include "errno.h"
+#include "stdio.h"
+
+#include "osi/include/log.h"
+
+#include <chrono>
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <utility>
+
+namespace test_vendor_lib {
+
+using TaskCallback = std::function<void(void)>;
+using ReadCallback = std::function<void(int)>;
+using CriticalCallback = std::function<void(void)>;
+using AsyncTaskId = uint16_t;
+constexpr uint16_t kInvalidTaskId = 0;
+
+// Manages tasks that should be done in the future. It can watch file
+// descriptors to call a given callback when it is certain that a block will not
+// occur or can call a callback at a specific time (aproximately) and
+// (optionally) repeat the call periodically. The class itself is thread safe in
+// the sense that all its member functions can be called simultaneously from
+// different concurrent thread. However, no asumption should be made about
+// callback execution. The safest approach is to assume that any two callbacks
+// could be executed concurrently in different threads, so code provided in
+// callbacks need to actively deal with race conditions, deadlocks, etc. While
+// not required, it is strongly recommended to use the Synchronize(const
+// CriticalCallback&) member function to execute code inside critical sections.
+// Callbacks passed to this method on the same AsyncManager object from
+// different threads are granted to *NOT* run concurrently.
+class AsyncManager {
+ public:
+  // Starts watching a file descriptor in a separate thread. The
+  // on_read_fd_ready_callback() will be asynchronously called when it is
+  // guaranteed that a call to read() on the FD will not block. No promise is
+  // made about when in the future the callback will be called, in particular,
+  // it is perfectly possible to have it called before this function returns. A
+  // return of 0 means success, an error code is returned otherwise.
+  int WatchFdForNonBlockingReads(int file_descriptor,
+                                 const ReadCallback& on_read_fd_ready_callback);
+
+  // If the fd was not being watched before the call will be ignored.
+  void StopWatchingFileDescriptor(int file_descriptor);
+
+  // Schedules an action to occur in the future. Even if the delay given is not
+  // positive the callback will be called asynchronously.
+  AsyncTaskId ExecAsync(std::chrono::milliseconds delay,
+                        const TaskCallback& callback);
+
+  // Schedules an action to occur periodically in the future. If the delay given
+  // is not positive the callback will be asynchronously called once for each
+  // time in the past that it should have been called and then scheduled for
+  // future times.
+  AsyncTaskId ExecAsyncPeriodically(std::chrono::milliseconds delay,
+                                    std::chrono::milliseconds period,
+                                    const TaskCallback& callback);
+
+  // Cancels the/every future ocurrence of the action specified by this id. It
+  // is guaranteed that the asociated callback will not be called after this
+  // method returns (it could be called during the execution of the method).
+  // The calling thread may block until the scheduling thread acknowledges the
+  // cancelation.
+  bool CancelAsyncTask(AsyncTaskId async_task_id);
+
+  // Execs the given code in a synchronized manner. It is guaranteed that code
+  // given on (possibly)concurrent calls to this member function on the same
+  // AsyncManager object will never be executed simultaneously. It is the
+  // class's user's resposability to ensure that no calls to Synchronize are
+  // made from inside a CriticalCallback, since that would cause a lock to be
+  // acquired twice with unpredictable results. It is strongly recommended to
+  // have very simple CriticalCallbacks, preferably using lambda expressions.
+  void Synchronize(const CriticalCallback&);
+
+  AsyncManager();
+
+  ~AsyncManager();
+
+ private:
+  // Implementation of the FD watching part of AsyncManager, extracted to its
+  // own class for clarity purposes.
+  class AsyncFdWatcher;
+
+  // Implementation of the asynchronous tasks part of AsyncManager, extracted to
+  // its own class for clarity purposes.
+  class AsyncTaskManager;
+
+  AsyncManager(const AsyncManager&) = delete;
+  AsyncManager& operator=(const AsyncManager&) = delete;
+
+  // Kept as pointers because we may want to support reseting either without
+  // destroying the other one
+  std::unique_ptr<AsyncFdWatcher> fdWatcher_p_;
+  std::unique_ptr<AsyncTaskManager> taskManager_p_;
+
+  std::mutex synchronization_mutex_;
+};
+}
+#endif  // TEST_VENDOR_LIB_ASYNC_MANAGER_H_
diff --git a/bt/vendor_libs/test_vendor_lib/include/bt_address.h b/bt/vendor_libs/test_vendor_lib/include/bt_address.h
new file mode 100644
index 0000000..e6eef59
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/include/bt_address.h
@@ -0,0 +1,87 @@
+//
+// Copyright 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <cstdint>
+#include <vector>
+#include <string>
+
+namespace test_vendor_lib {
+
+// Encapsulate handling for Bluetooth Addresses:
+// - store the address
+// - convert to/from strings and vectors of bytes
+// - check strings to see if they represent a valid address
+class BtAddress {
+ public:
+  // Conversion constants
+  static const size_t kStringLength = 17;  // "XX:XX:XX:XX:XX:XX"
+  static const size_t kOctets = 6;         // "X0:X1:X2:X3:X4:X5"
+
+  BtAddress() : address_(0){};
+  virtual ~BtAddress() = default;
+
+  // Returns true if |addr| has the form "XX:XX:XX:XX:XX:XX":
+  // - the length of |addr| is >= kStringLength
+  // - every third character is ':'
+  // - each remaining character is a hexadecimal digit
+  static bool IsValid(const std::string& addr);
+
+  inline bool operator==(const BtAddress& right) {
+    return address_ == right.address_;
+  }
+  inline bool operator!=(const BtAddress& right) {
+    return address_ != right.address_;
+  }
+  inline bool operator<(const BtAddress& right) {
+    return address_ < right.address_;
+  }
+  inline bool operator>(const BtAddress& right) {
+    return address_ > right.address_;
+  }
+  inline bool operator<=(const BtAddress& right) {
+    return address_ <= right.address_;
+  }
+  inline bool operator>=(const BtAddress& right) {
+    return address_ >= right.address_;
+  }
+
+  inline void operator=(const BtAddress& right) { address_ = right.address_; }
+  inline void operator|=(const BtAddress& right) { address_ |= right.address_; }
+  inline void operator&=(const BtAddress& right) { address_ &= right.address_; }
+
+  // Set the address to the address represented by |str|.
+  // returns true if |str| represents a valid address, otherwise false.
+  bool FromString(const std::string& str);
+
+  // Set the address to the address represented by |str|.
+  // returns true if octets.size() >= kOctets, otherwise false.
+  bool FromVector(const std::vector<uint8_t>& octets);
+
+  // Appends the Bluetooth address to the vector |octets|.
+  void ToVector(std::vector<uint8_t>& octets) const;
+
+  // Return a string representation of the Bluetooth address, in this format:
+  // "xx:xx:xx:xx:xx:xx", where x represents a lowercase hexadecimal digit.
+  std::string ToString() const;
+
+ private:
+  // The Bluetooth Address is stored in the lower 48 bits of a 64-bit value
+  uint64_t address_;
+};
+
+}  // namespace test_vendor_lib
diff --git a/bt/vendor_libs/test_vendor_lib/include/command_packet.h b/bt/vendor_libs/test_vendor_lib/include/command_packet.h
new file mode 100644
index 0000000..3f7debb
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/include/command_packet.h
@@ -0,0 +1,81 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR 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 "base/macros.h"
+#include "packet.h"
+
+namespace test_vendor_lib {
+
+// The following is specified in the Bluetooth Core Specification Version 4.2,
+// Volume 2, Part E, Section 5.4.1 (page 470). Command Packets begin with a 3
+// octet header formatted as follows:
+// - Opcode: 2 octets
+//   - Opcode Group Field (OGF): Upper bits 10-15
+//   - Opcode Command Field (OCF): Lower bits 0-9
+// - Payload size (in octets): 1 octet
+// The header is followed by the payload, which contains command specific
+// parameters and has a maximum size of 255 octets. Valid command opcodes are
+// defined in stack/include/hcidefs.h. The OGF ranges from 0x00 to 0x3F, with
+// 0x3F reserved for vendor-specific debug functions. The OCF ranges from
+// 0x0000 to 0x03FF. Note that the payload size is the size in octets of the
+// command parameters and not the number of parameters. Finally, although the
+// parameters contained in the payload are command specific (including the size
+// and number of parameters), each parameter will be an integer number of octets
+// in size.
+class CommandPacket : public Packet {
+ public:
+  explicit CommandPacket(std::vector<uint8_t> header);
+  explicit CommandPacket(uint16_t opcode);
+  CommandPacket(std::vector<uint8_t> header, std::vector<uint8_t> payload);
+
+  CommandPacket(const CommandPacket&) = default;
+  CommandPacket& operator=(const CommandPacket&) = default;
+  CommandPacket(CommandPacket&&) = default;
+  CommandPacket& operator=(CommandPacket&&) = default;
+  virtual ~CommandPacket() override = default;
+
+  // Returns the command opcode as defined in stack/include/hcidefs.h.
+  // See the Bluetooth Core Specification Version 4.2, Volume 2, Part E,
+  // Section 7 for more information about each HCI commands and for a listing
+  // of their specific opcodes/OGF and OCF values.
+  uint16_t GetOpcode() const;
+
+  // Returns the 6 bit opcode group field that specifies the general category of
+  // the command. The OGF can be one of seven values:
+  // - 0x01: Link control commands
+  // - 0x02: Link policy commands
+  // - 0x03: Controller and baseband commands
+  // - 0x04: Informational parameters commands
+  // - 0x05: Status parameters commands
+  // - 0x06: Testing commands
+  // - 0x08: Low energy controller commands
+  // The upper 2 bits will be zero filled.
+  uint8_t GetOGF() const;
+
+  // Returns the 10 bit opcode command field that specifies an exact command
+  // within an opcode group field. The upper 6 bits will be zero filled.
+  uint16_t GetOCF() const;
+
+  // Size of a command packet header, which consists of a 2 octet opcode
+  static const size_t kCommandHeaderSize = 2;
+};
+
+}  // namespace test_vendor_lib
diff --git a/bt/vendor_libs/test_vendor_lib/include/dual_mode_controller.h b/bt/vendor_libs/test_vendor_lib/include/dual_mode_controller.h
new file mode 100644
index 0000000..d52d275
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/include/dual_mode_controller.h
@@ -0,0 +1,547 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR 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 <unordered_map>
+#include <vector>
+
+#include "async_manager.h"
+#include "base/json/json_value_converter.h"
+#include "base/time/time.h"
+#include "bt_address.h"
+#include "command_packet.h"
+#include "hci_transport.h"
+#include "test_channel_transport.h"
+
+namespace test_vendor_lib {
+
+// 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
+// commands sent by the HCI. These methods will be registered as callbacks from
+// a controller instance with the HciHandler. To implement a new Bluetooth
+// command, simply add the method declaration below, with return type void and a
+// single const std::vector<uint8_t>& argument. After implementing the
+// method, simply register it with the HciHandler using the SET_HANDLER macro in
+// the controller's default constructor. Be sure to name your method after the
+// corresponding Bluetooth command in the Core Specification with the prefix
+// "Hci" to distinguish it as a controller command.
+class DualModeController {
+ public:
+  class Properties {
+   public:
+    explicit Properties(const std::string& file_name);
+
+    // Access private configuration data
+
+    // Specification Version 4.2, Volume 2, Part E, Section 7.4.1
+    const std::vector<uint8_t>& GetLocalVersionInformation() const;
+
+    // Specification Version 4.2, Volume 2, Part E, Section 7.4.2
+    const std::vector<uint8_t>& GetLocalSupportedCommands() const {
+      return local_supported_commands_;
+    }
+
+    // Specification Version 4.2, Volume 2, Part E, Section 7.4.3
+    uint64_t GetLocalSupportedFeatures() const {
+      return local_extended_features_[0];
+    };
+
+    // Specification Version 4.2, Volume 2, Part E, Section 7.4.4
+    uint8_t GetLocalExtendedFeaturesMaximumPageNumber() const {
+      return local_extended_features_.size() - 1;
+    };
+
+    uint64_t GetLocalExtendedFeatures(uint8_t page_number) const {
+      CHECK(page_number < local_extended_features_.size());
+      return local_extended_features_[page_number];
+    };
+
+    // Specification Version 4.2, Volume 2, Part E, Section 7.4.5
+    uint16_t GetAclDataPacketSize() const { return acl_data_packet_size_; }
+
+    uint8_t GetSynchronousDataPacketSize() const {
+      return sco_data_packet_size_;
+    }
+
+    uint16_t GetTotalNumAclDataPackets() const { return num_acl_data_packets_; }
+
+    uint16_t GetTotalNumSynchronousDataPackets() const {
+      return num_sco_data_packets_;
+    }
+
+    const BtAddress& GetAddress() const { return address_; }
+
+    // Specification Version 4.2, Volume 2, Part E, Section 7.4.8
+    const std::vector<uint8_t>& GetSupportedCodecs() const {
+      return supported_codecs_;
+    }
+
+    const std::vector<uint32_t>& GetVendorSpecificCodecs() const {
+      return vendor_specific_codecs_;
+    }
+
+    const std::string& GetLocalName() const { return local_name_; }
+
+    uint8_t GetVersion() const { return version_; }
+
+    uint16_t GetRevision() const { return revision_; }
+
+    uint8_t GetLmpPalVersion() const { return lmp_pal_version_; }
+
+    uint16_t GetLmpPalSubversion() const { return lmp_pal_subversion_; }
+
+    uint16_t GetManufacturerName() const { return manufacturer_name_; }
+
+    // Specification Version 4.2, Volume 2, Part E, Section 7.8.2
+    uint16_t GetLeDataPacketLength() const { return le_data_packet_length_; }
+
+    uint8_t GetTotalNumLeDataPackets() const { return num_le_data_packets_; }
+
+    // Specification Version 4.2, Volume 2, Part E, Section 7.8.3
+    uint64_t GetLeLocalSupportedFeatures() const {
+      return le_supported_features_;
+    }
+
+    // Specification Version 4.2, Volume 2, Part E, Section 7.8.14
+    uint8_t GetLeWhiteListSize() const { return le_white_list_size_; }
+
+    // Specification Version 4.2, Volume 2, Part E, Section 7.8.27
+    uint64_t GetLeSupportedStates() const { return le_supported_states_; }
+
+    // Vendor-specific commands (see hcidefs.h)
+    const std::vector<uint8_t>& GetLeVendorCap() const {
+      return le_vendor_cap_;
+    }
+
+    static void RegisterJSONConverter(
+        base::JSONValueConverter<Properties>* converter);
+
+   private:
+    uint16_t acl_data_packet_size_;
+    uint8_t sco_data_packet_size_;
+    uint16_t num_acl_data_packets_;
+    uint16_t num_sco_data_packets_;
+    uint8_t version_;
+    uint16_t revision_;
+    uint8_t lmp_pal_version_;
+    uint16_t manufacturer_name_;
+    uint16_t lmp_pal_subversion_;
+    std::vector<uint8_t> supported_codecs_;
+    std::vector<uint32_t> vendor_specific_codecs_;
+    std::vector<uint8_t> local_supported_commands_;
+    std::string local_name_;
+    std::vector<uint64_t> local_extended_features_;
+    BtAddress address_;
+
+    uint16_t le_data_packet_length_;
+    uint8_t num_le_data_packets_;
+    uint8_t le_white_list_size_;
+    uint64_t le_supported_features_;
+    uint64_t le_supported_states_;
+    std::vector<uint8_t> le_vendor_cap_;
+  };
+
+  // Sets all of the methods to be used as callbacks in the HciHandler.
+  DualModeController();
+
+  ~DualModeController() = default;
+
+  // Preprocesses the command, primarily checking testh channel hooks. If
+  // possible, dispatches the corresponding controller method corresponding to
+  // carry out the command.
+  void HandleCommand(std::unique_ptr<CommandPacket> command_packet);
+
+  // Dispatches the test channel action corresponding to the command specified
+  // by |name|.
+  void HandleTestChannelCommand(const std::string& name,
+                                const std::vector<std::string>& args);
+
+  // Set the callbacks for scheduling tasks.
+  void RegisterTaskScheduler(
+      std::function<AsyncTaskId(std::chrono::milliseconds, const TaskCallback&)>
+          evtScheduler);
+
+  void RegisterPeriodicTaskScheduler(
+      std::function<AsyncTaskId(std::chrono::milliseconds,
+                                std::chrono::milliseconds, const TaskCallback&)>
+          periodicEvtScheduler);
+
+  void RegisterTaskCancel(std::function<void(AsyncTaskId)> cancel);
+
+  // Sets the callback to be used for sending events back to the HCI.
+  void RegisterEventChannel(
+      const std::function<void(std::unique_ptr<EventPacket>)>& send_event);
+
+  // Controller commands. For error codes, see the Bluetooth Core Specification,
+  // Version 4.2, Volume 2, Part D (page 370).
+
+  // OGF: 0x0003
+  // OCF: 0x0003
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.2
+  void HciReset(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0004
+  // OGF: 0x0005
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.4.5
+  void HciReadBufferSize(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0003
+  // OCF: 0x0033
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.39
+  void HciHostBufferSize(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0004
+  // OCF: 0x0001
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.4.1
+  void HciReadLocalVersionInformation(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0004
+  // OCF: 0x0009
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.4.6
+  void HciReadBdAddr(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0004
+  // OCF: 0x0002
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.4.2
+  void HciReadLocalSupportedCommands(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0004
+  // OCF: 0x0004
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.4.4
+  void HciReadLocalExtendedFeatures(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0004
+  // OCF: 0x000B
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.4.8
+  void HciReadLocalSupportedCodecs(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0003
+  // OCF: 0x0056
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.59
+  void HciWriteSimplePairingMode(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0003
+  // OCF: 0x006D
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.79
+  void HciWriteLeHostSupport(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0003
+  // OCF: 0x0001
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.1
+  void HciSetEventMask(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0003
+  // OCF: 0x0045
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.50
+  void HciWriteInquiryMode(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0003
+  // OCF: 0x0047
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.52
+  void HciWritePageScanType(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0003
+  // OCF: 0x0043
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.48
+  void HciWriteInquiryScanType(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0003
+  // OCF: 0x0024
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.26
+  void HciWriteClassOfDevice(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0003
+  // OCF: 0x0018
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.16
+  void HciWritePageTimeout(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0002
+  // OCF: 0x000F
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.2.12
+  void HciWriteDefaultLinkPolicySettings(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0003
+  // OCF: 0x0014
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.12
+  void HciReadLocalName(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0003
+  // OCF: 0x0013
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.11
+  void HciWriteLocalName(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0003
+  // OCF: 0x0052
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.56
+  void HciWriteExtendedInquiryResponse(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0003
+  // OCF: 0x0026
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.28
+  void HciWriteVoiceSetting(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0003
+  // OCF: 0x003A
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.45
+  void HciWriteCurrentIacLap(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0003
+  // OCF: 0x001E
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.22
+  void HciWriteInquiryScanActivity(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0003
+  // OCF: 0x001A
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.18
+  void HciWriteScanEnable(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0003
+  // OCF: 0x0005
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.3
+  void HciSetEventFilter(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0001
+  // OCF: 0x0001
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.1.1
+  void HciInquiry(const std::vector<uint8_t>& args);
+
+  void InquiryTimeout();
+
+  // OGF: 0x0001
+  // OCF: 0x0002
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.1.2
+  void HciInquiryCancel(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0003
+  // OCF: 0x0012
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.10
+  void HciDeleteStoredLinkKey(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0001
+  // OCF: 0x0019
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.1.19
+  void HciRemoteNameRequest(const std::vector<uint8_t>& args);
+
+  // LE Controller Commands
+
+  // OGF: 0x0008
+  // OCF: 0x0001
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.1
+  void HciLeSetEventMask(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0008
+  // OCF: 0x0002
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.2
+  void HciLeReadBufferSize(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0008
+  // OCF: 0x0003
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.3
+  void HciLeReadLocalSupportedFeatures(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0008
+  // OCF: 0x0005
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.4
+  void HciLeSetRandomAddress(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0008
+  // OCF: 0x0006
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.5
+  void HciLeSetAdvertisingParameters(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0008
+  // OCF: 0x0008
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.7
+  void HciLeSetAdvertisingData(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0008
+  // OCF: 0x000B
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.10
+  void HciLeSetScanParameters(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0008
+  // OCF: 0x000C
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.11
+  void HciLeSetScanEnable(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0008
+  // OCF: 0x000F
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.14
+  void HciLeReadWhiteListSize(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0008
+  // OCF: 0x0018
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.23
+  void HciLeRand(const std::vector<uint8_t>& args);
+
+  // OGF: 0x0008
+  // OCF: 0x001C
+  // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.27
+  void HciLeReadSupportedStates(const std::vector<uint8_t>& args);
+
+  // Vendor-specific commands (see hcidefs.h)
+
+  // OGF: 0x00FC
+  // OCF: 0x0027
+  void HciBleVendorSleepMode(const std::vector<uint8_t>& args);
+
+  // OGF: 0x00FC
+  // OCF: 0x0153
+  void HciBleVendorCap(const std::vector<uint8_t>& args);
+
+  // OGF: 0x00FC
+  // OCF: 0x0154
+  void HciBleVendorMultiAdv(const std::vector<uint8_t>& args);
+
+  // OGF: 0x00FC
+  // OCF: 0x0155
+  void HciBleVendor155(const std::vector<uint8_t>& args);
+
+  // OGF: 0x00FC
+  // OCF: 0x0157
+  void HciBleVendor157(const std::vector<uint8_t>& args);
+
+  // OGF: 0x00FC
+  // OCF: 0x0159
+  void HciBleEnergyInfo(const std::vector<uint8_t>& args);
+
+  // OGF: 0x00FC
+  // OCF: 0x015A
+  void HciBleExtendedScanParams(const std::vector<uint8_t>& args);
+
+  // Test Channel commands:
+
+  // Clears all test channel modifications.
+  void TestChannelClear(const std::vector<std::string>& args);
+
+  // Sets the response delay for events to 0.
+  void TestChannelClearEventDelay(const std::vector<std::string>& args);
+
+  // Discovers a fake device.
+  void TestChannelDiscover(const std::vector<std::string>& args);
+
+  // Causes events to be sent after a delay.
+  void TestChannelSetEventDelay(const std::vector<std::string>& args);
+
+  // Causes all future HCI commands to timeout.
+  void TestChannelTimeoutAll(const std::vector<std::string>& args);
+
+  void HandleTimerTick();
+  void SetTimerPeriod(std::chrono::milliseconds new_period);
+  void StartTimer();
+  void StopTimer();
+
+ private:
+  // Current link layer state of the controller.
+  enum State {
+    kStandby,  // Not receiving/transmitting any packets from/to other devices.
+    kInquiry,  // The controller is discovering other nearby devices.
+  };
+
+  enum TestChannelState {
+    kNone,             // The controller is running normally.
+    kTimeoutAll,       // All commands should time out, i.e. send no response.
+    kDelayedResponse,  // Event responses are sent after a delay.
+  };
+
+  // Set a timer for a future action
+  void AddControllerEvent(std::chrono::milliseconds,
+                          const TaskCallback& callback);
+
+  // Creates a command complete event and sends it back to the HCI.
+  void SendCommandComplete(uint16_t command_opcode,
+                           const std::vector<uint8_t>& return_parameters) const;
+
+  // Sends a command complete event with no return parameters. This event is
+  // typically sent for commands that can be completed immediately.
+  void SendCommandCompleteSuccess(uint16_t command_opcode) const;
+
+  // Sends a command complete event with no return parameters. This event is
+  // typically sent for commands that can be completed immediately.
+  void SendCommandCompleteOnlyStatus(uint16_t command_opcode,
+                                     uint8_t status) const;
+
+  // Creates a command status event and sends it back to the HCI.
+  void SendCommandStatus(uint8_t status, uint16_t command_opcode) const;
+
+  // Sends a command status event with default event parameters.
+  void SendCommandStatusSuccess(uint16_t command_opcode) const;
+
+  void SetEventDelay(int64_t delay);
+
+  // Callbacks to schedule tasks.
+  std::function<AsyncTaskId(std::chrono::milliseconds, const TaskCallback&)>
+      schedule_task_;
+  std::function<AsyncTaskId(std::chrono::milliseconds,
+                            std::chrono::milliseconds, const TaskCallback&)>
+      schedule_periodic_task_;
+
+  std::function<void(AsyncTaskId)> cancel_task_;
+
+  // Callback provided to send events from the controller back to the HCI.
+  std::function<void(std::unique_ptr<EventPacket>)> send_event_;
+
+  // 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(const std::vector<uint8_t>&)>>
+      active_hci_commands_;
+
+  std::unordered_map<std::string,
+                     std::function<void(const std::vector<std::string>&)>>
+      active_test_channel_commands_;
+
+  // Specifies the format of Inquiry Result events to be returned during the
+  // Inquiry command.
+  // 0x00: Standard Inquiry Result event format (default).
+  // 0x01: Inquiry Result format with RSSI.
+  // 0x02 Inquiry Result with RSSI format or Extended Inquiry Result format.
+  // 0x03-0xFF: Reserved.
+  uint8_t inquiry_mode_;
+
+  std::vector<uint8_t> le_event_mask_;
+
+  BtAddress le_random_address_;
+
+  uint8_t le_scan_type_;
+  uint16_t le_scan_interval_;
+  uint16_t le_scan_window_;
+  uint8_t own_address_type_;
+  uint8_t scanning_filter_policy_;
+
+  uint8_t le_scan_enable_;
+  uint8_t filter_duplicates_;
+
+  State state_;
+
+  Properties properties_;
+
+  TestChannelState test_channel_state_;
+
+  std::vector<AsyncTaskId> controller_events_;
+  AsyncTaskId timer_tick_task_;
+  std::chrono::milliseconds timer_period_ = std::chrono::milliseconds(1000);
+
+  DualModeController(const DualModeController& cmdPckt) = delete;
+  DualModeController& operator=(const DualModeController& cmdPckt) = delete;
+};
+
+}  // namespace test_vendor_lib
diff --git a/bt/vendor_libs/test_vendor_lib/include/event_packet.h b/bt/vendor_libs/test_vendor_lib/include/event_packet.h
new file mode 100644
index 0000000..d7c8268
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/include/event_packet.h
@@ -0,0 +1,158 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR 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 <vector>
+
+#include "base/logging.h"
+#include "bt_address.h"
+#include "packet.h"
+
+namespace test_vendor_lib {
+
+// Event Packets are specified in the Bluetooth Core Specification Version 4.2,
+// Volume 2, Part E, Section 5.4.4
+class EventPacket : public Packet {
+ public:
+  virtual ~EventPacket() override = default;
+
+  uint8_t GetEventCode() const;
+
+  // Static functions for creating event packets:
+
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.1
+  static std::unique_ptr<EventPacket> CreateInquiryCompleteEvent(
+      uint8_t 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<EventPacket> CreateCommandCompleteEvent(
+      uint16_t command_opcode,
+      const std::vector<uint8_t>& event_return_parameters);
+
+  static std::unique_ptr<EventPacket> CreateCommandCompleteOnlyStatusEvent(
+      uint16_t command_opcode, uint8_t status);
+
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.15
+  static std::unique_ptr<EventPacket> CreateCommandStatusEvent(
+      uint8_t status, uint16_t command_opcode);
+
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.12
+  static std::unique_ptr<EventPacket> CreateCommandCompleteReadLocalName(
+      uint8_t status, const std::string& local_name);
+
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.1
+  static std::unique_ptr<EventPacket>
+  CreateCommandCompleteReadLocalVersionInformation(uint8_t 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<EventPacket>
+  CreateCommandCompleteReadLocalSupportedCommands(
+      uint8_t 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<EventPacket>
+  CreateCommandCompleteReadLocalExtendedFeatures(
+      uint8_t 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<EventPacket> CreateCommandCompleteReadBufferSize(
+      uint8_t 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<EventPacket> CreateCommandCompleteReadBdAddr(
+      uint8_t status, const BtAddress& bt_address);
+
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.8
+  static std::unique_ptr<EventPacket>
+  CreateCommandCompleteReadLocalSupportedCodecs(
+      uint8_t 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.7.2
+  enum PageScanRepetitionMode {
+    kR0 = 0,
+    kR1 = 1,
+    kR2 = 2,
+  };
+
+  static std::unique_ptr<EventPacket> CreateInquiryResultEvent(
+      const BtAddress& bt_address,
+      const PageScanRepetitionMode page_scan_repetition_mode,
+      uint32_t class_of_device, uint16_t clock_offset);
+
+  void AddInquiryResult(const BtAddress& bt_address,
+                        const PageScanRepetitionMode page_scan_repetition_mode,
+                        uint32_t class_of_device, uint16_t clock_offset);
+
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.38
+  static std::unique_ptr<EventPacket> CreateExtendedInquiryResultEvent(
+      const BtAddress& bt_address,
+      const PageScanRepetitionMode page_scan_repetition_mode,
+      uint32_t 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.8.2
+  static std::unique_ptr<EventPacket> CreateCommandCompleteLeReadBufferSize(
+      uint8_t 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<EventPacket>
+  CreateCommandCompleteLeReadLocalSupportedFeatures(uint8_t status,
+                                                    uint64_t le_features);
+
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.14
+  static std::unique_ptr<EventPacket> CreateCommandCompleteLeReadWhiteListSize(
+      uint8_t status, uint8_t white_list_size);
+
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.23
+  static std::unique_ptr<EventPacket> CreateCommandCompleteLeRand(
+      uint8_t status, uint64_t random_val);
+
+  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.27
+  static std::unique_ptr<EventPacket>
+  CreateCommandCompleteLeReadSupportedStates(uint8_t status,
+                                             uint64_t le_states);
+
+  // Vendor-specific commands (see hcidefs.h)
+
+  static std::unique_ptr<EventPacket> CreateCommandCompleteLeVendorCap(
+      uint8_t status, const std::vector<uint8_t>& vendor_cap);
+
+  // Size of a data packet header, which consists of a 1 octet event code
+  static const size_t kEventHeaderSize = 1;
+
+ private:
+  explicit EventPacket(uint8_t event_code);
+  EventPacket(uint8_t event_code, const std::vector<uint8_t>& payload);
+};
+
+}  // namespace test_vendor_lib
diff --git a/bt/vendor_libs/test_vendor_lib/include/hci_transport.h b/bt/vendor_libs/test_vendor_lib/include/hci_transport.h
new file mode 100644
index 0000000..21f786d
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/include/hci_transport.h
@@ -0,0 +1,82 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR 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 <list>
+#include <memory>
+
+#include "base/files/scoped_file.h"
+#include "command_packet.h"
+#include "event_packet.h"
+#include "packet.h"
+#include "packet_stream.h"
+
+namespace test_vendor_lib {
+
+// Manages communication channel between HCI and the controller by providing the
+// socket mechanisms for sending HCI [commands|events] [to|from] the controller.
+class HciTransport {
+ public:
+  HciTransport();
+
+  virtual ~HciTransport() = default;
+
+  void CloseHciFd();
+
+  void CloseVendorFd();
+
+  int GetHciFd() const;
+
+  int GetVendorFd() const;
+
+  // Creates the underlying socketpair to be used as a communication channel
+  // between the HCI and the vendor library/controller. Returns false if an
+  // error occurs.
+  bool SetUp();
+
+  // Sets the callback that is run when command packets are received.
+  void RegisterCommandHandler(
+      const std::function<void(std::unique_ptr<CommandPacket>)>& callback);
+
+  // Blocks while it tries to writes the event to the vendor file descriptor.
+  void SendEvent(std::unique_ptr<EventPacket> event);
+
+  // Called when there is a command to read on |fd|.
+  void OnCommandReady(int fd);
+
+ private:
+  // Callback executed in ReceiveReadyCommand() to pass the incoming command
+  // over to the handler for further processing.
+  std::function<void(std::unique_ptr<CommandPacket>)> command_handler_;
+
+  // For performing packet-based IO.
+  PacketStream packet_stream_;
+
+  // The two ends of the socketpair. |hci_fd_| is handed back to the HCI in
+  // bt_vendor.cc and |vendor_fd_| is used by |packet_stream_| to receive/send
+  // data from/to the HCI. Both file descriptors are owned and managed by the
+  // transport object, although |hci_fd_| can be closed by the HCI in
+  // TestVendorOp().
+  std::unique_ptr<base::ScopedFD> hci_fd_;
+  std::unique_ptr<base::ScopedFD> vendor_fd_;
+
+  HciTransport(const HciTransport& cmdPckt) = delete;
+  HciTransport& operator=(const HciTransport& cmdPckt) = delete;
+};
+
+}  // namespace test_vendor_lib
diff --git a/bt/vendor_libs/test_vendor_lib/include/packet.h b/bt/vendor_libs/test_vendor_lib/include/packet.h
new file mode 100644
index 0000000..0feeb58
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/include/packet.h
@@ -0,0 +1,95 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR 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 "bt_address.h"
+#include "hci/include/hci_hal.h"
+
+namespace test_vendor_lib {
+
+const size_t kReservedZero = 0;
+
+// Abstract base class that is subclassed to provide type-specifc accessors on
+// data. Manages said data's memory and guarantees the data's persistence for IO
+// operations.
+class Packet {
+ public:
+  virtual ~Packet() = default;
+
+  // Returns the size in octets of the entire packet, which consists of the type
+  // octet, the header, and the payload.
+  size_t GetPacketSize() const;
+
+  const std::vector<uint8_t>& GetPayload() const;
+
+  size_t GetPayloadSize() const;
+
+  const std::vector<uint8_t>& GetHeader() const;
+
+  uint8_t GetHeaderSize() const;
+
+  serial_data_type_t GetType() 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 < |kMaxPacketOctets|
+  bool AddPayloadOctets(size_t octets, const std::vector<uint8_t>& bytes);
+
+ 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 < |kMaxPacketOctets|
+  bool AddPayloadOctets(size_t octets, uint64_t value);
+
+ public:
+  // Add type-checking versions
+  bool AddPayloadOctets1(uint8_t value) { return AddPayloadOctets(1, value); }
+  bool AddPayloadOctets2(uint16_t value) { return AddPayloadOctets(2, value); }
+  bool AddPayloadOctets3(uint32_t value) { return AddPayloadOctets(3, value); }
+  bool AddPayloadOctets4(uint32_t value) { return AddPayloadOctets(4, value); }
+  bool AddPayloadOctets6(uint64_t value) { return AddPayloadOctets(6, value); }
+  bool AddPayloadOctets8(uint64_t value) { return AddPayloadOctets(8, value); }
+
+  // Add |address| to the payload.  Return true if:
+  // - the new size of the payload is still < |kMaxPacketOctets|
+  bool AddPayloadBtAddress(const BtAddress& address);
+
+ protected:
+  // Constructs an empty packet of type |type| and header |header|
+  Packet(serial_data_type_t type, std::vector<uint8_t> header);
+
+  bool IncrementPayloadCounter(size_t index);
+  bool IncrementPayloadCounter(size_t index, uint8_t max_val);
+
+ private:
+  const size_t kMaxPacketOctets = 256;  // Includes the Octet count
+
+  // Underlying containers for storing the actual packet
+
+  // The packet type is one of DATA_TYPE_ACL, DATA_TYPE_COMMAND,
+  // DATA_TYPE_EVENT, or DATA_TYPE_SCO.
+  serial_data_type_t type_;
+
+  std::vector<uint8_t> header_;
+
+  std::vector<uint8_t> payload_;
+};
+
+}  // namespace test_vendor_lib
diff --git a/bt/vendor_libs/test_vendor_lib/include/packet_stream.h b/bt/vendor_libs/test_vendor_lib/include/packet_stream.h
new file mode 100644
index 0000000..e2cec7d
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/include/packet_stream.h
@@ -0,0 +1,66 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR 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 "command_packet.h"
+#include "event_packet.h"
+#include "packet.h"
+
+namespace test_vendor_lib {
+
+// Provides abstractions for IO with Packet objects. Used to receive commands
+// and data from the HCI and to send controller events back to the host.
+class PacketStream {
+ public:
+  PacketStream() = default;
+
+  virtual ~PacketStream() = default;
+
+  // Reads a command packet from the file descriptor at |fd| and returns the
+  // packet back to the caller, along with the responsibility of managing the
+  // packet.
+  std::unique_ptr<CommandPacket> ReceiveCommand(int fd) const;
+
+  // Reads a single octet from |fd| and interprets it as a packet type octet.
+  // Validates the type octet for correctness.
+  serial_data_type_t ReceivePacketType(int fd) const;
+
+  // Sends an event to file descriptor |fd|. The ownership of the event is left
+  // with the caller.
+  bool SendEvent(std::unique_ptr<EventPacket> event, int fd) const;
+
+ private:
+  // Checks if |type| is in the valid range from DATA_TYPE_COMMAND to
+  // DATA_TYPE_SCO.
+  bool ValidateTypeOctet(serial_data_type_t type) const;
+
+  // Attempts to receive |num_octets_to_receive| into |destination| from |fd|,
+  // returning false if an error occurs.
+  bool ReceiveAll(std::vector<uint8_t>& destination,
+                  size_t num_octets_to_receive, int fd) const;
+
+  // Attempts to send |num_octets_to_send| from |source| to |fd|, returning
+  // false if an error occurs.
+  bool SendAll(const std::vector<uint8_t>& source, size_t num_octets_to_send,
+               int fd) const;
+};
+
+}  // namespace test_vendor_lib
diff --git a/bt/vendor_libs/test_vendor_lib/include/test_channel_transport.h b/bt/vendor_libs/test_vendor_lib/include/test_channel_transport.h
new file mode 100644
index 0000000..b38a8ce
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/include/test_channel_transport.h
@@ -0,0 +1,65 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR 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 <memory>
+#include <string>
+#include <vector>
+
+#include "base/files/scoped_file.h"
+
+namespace test_vendor_lib {
+
+// Manages communications between test channel and the controller. Mirrors the
+// HciTransport for the test channel.
+class TestChannelTransport {
+ public:
+  TestChannelTransport() {}
+
+  ~TestChannelTransport() {}
+
+  // Opens a port and returns the file descriptor for the socket.
+  // Returns -1 on an error.
+  int SetUp(int port);
+
+  // Closes the port (if succesfully opened in SetUp).
+  void CleanUp();
+
+  // Waits for a connection request from the test channel program and
+  // returns the file descriptor to watch for run-time parameters.
+  // Returns -1 on an error.
+  int Accept(int listen_fd);
+
+  // Sets the callback that fires when data is read in WatchFd().
+  void RegisterCommandHandler(
+      const std::function<void(const std::string&,
+                               const std::vector<std::string>&)>& callback);
+
+  void OnCommandReady(int fd, std::function<void(void)> unwatch);
+
+ private:
+  std::function<void(const std::string&, const std::vector<std::string>&)>
+      command_handler_;
+
+  int listen_fd_ = -1;
+
+  TestChannelTransport(const TestChannelTransport& cmdPckt) = delete;
+  TestChannelTransport& operator=(const TestChannelTransport& cmdPckt) = delete;
+};
+
+}  // namespace test_vendor_lib
diff --git a/bt/vendor_libs/test_vendor_lib/include/vendor_manager.h b/bt/vendor_libs/test_vendor_lib/include/vendor_manager.h
new file mode 100644
index 0000000..84bb779
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/include/vendor_manager.h
@@ -0,0 +1,86 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR 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 "async_manager.h"
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "dual_mode_controller.h"
+#include "event_packet.h"
+#include "hci/include/bt_vendor_lib.h"
+#include "hci_transport.h"
+#include "test_channel_transport.h"
+
+#include <memory>
+
+namespace test_vendor_lib {
+
+// Contains the three core objects that make up the test vendor library: the
+// HciTransport for communication, the HciHandler for processing commands, and
+// the Controller for actual command implementations. The VendorManager shall
+// be used in bt_vendor.cc to provide access to the test controller by setting
+// up a message loop (on another thread) that the HCI will talk to and
+// controller methods will execute on.
+class VendorManager {
+ public:
+  VendorManager();
+
+  ~VendorManager() = default;
+
+  void CleanUp();
+
+  // Initializes the controller and sets up the test channel to wait for
+  // connections.
+  bool Initialize();
+
+  void CloseHciFd();
+
+  int GetHciFd() const;
+
+  const bt_vendor_callbacks_t& GetVendorCallbacks() const;
+
+  // Stores a copy of the vendor specific configuration callbacks passed into
+  // the vendor library from the HCI in TestVendorInit().
+  void SetVendorCallbacks(const bt_vendor_callbacks_t& callbacks);
+
+ private:
+  // Set up a test channel on _port_
+  void SetUpTestChannel(int port);
+
+  // Creates the HCI's communication channel and overrides IO callbacks to
+  // receive and send packets.
+  HciTransport transport_;
+
+  // The controller object that provides implementations of Bluetooth commands.
+  DualModeController controller_;
+
+  // The two test channel objects that perform functions corresponding to the
+  // HciTransport and HciHandler.
+  TestChannelTransport test_channel_transport_;
+
+  // Configuration callbacks provided by the HCI for use in TestVendorOp().
+  bt_vendor_callbacks_t vendor_callbacks_;
+
+  // The object that manages asynchronous tasks such as watching a file
+  // descriptor or doing something in the future
+  AsyncManager async_manager_;
+
+  VendorManager(const VendorManager& cmdPckt) = delete;
+  VendorManager& operator=(const VendorManager& cmdPckt) = delete;
+};
+
+}  // namespace test_vendor_lib
diff --git a/bt/vendor_libs/test_vendor_lib/scripts/build_and_run.sh b/bt/vendor_libs/test_vendor_lib/scripts/build_and_run.sh
new file mode 100755
index 0000000..34e0cfe
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/scripts/build_and_run.sh
@@ -0,0 +1,127 @@
+#!/bin/bash
+
+#
+# Copyright 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Builds and pushes the test vendor library to a connected device and starts
+# logcat with project-specific tag filters. If the --test-channel flag is set,
+# logcat is started in a separate process and the test channel is run in the
+# current shell. The kTestChannelEnabled flag must be set in the vendor manager
+# if the test channel is to be used. Also ensure that 'lunch' has been run for
+# the appropriate device.
+
+if [[ "$#" -ne 2 && "$#" -ne 4 ]]; then
+  echo "Usage:"
+  echo "./build_and_run.sh [/path/to/aosp] [device_name] or"
+  echo "./build_and_run.sh [/path/to/aosp] [device_name] --test-channel [port]"
+  exit 1
+fi
+
+# Exit the script if any command fails.
+set -e
+
+# The home directory for AOSP.
+AOSP_ABS=$1
+# The name of the device to build for.
+DEVICE=$2
+
+# The location of Bluetooth within AOSP.
+BT_REL=/system/bt
+BT_ABS=${AOSP_ABS}${BT_REL}
+
+# The location of the test vendor library.
+TEST_VENDOR_LIB_REL=/vendor_libs/test_vendor_lib
+TEST_VENDOR_LIB_ABS=${BT_ABS}${TEST_VENDOR_LIB_REL}
+
+DEVICE_TARGET_REL=/out/target/product
+DEVICE_TARGET_ABS=${AOSP_ABS}${DEVICE_TARGET_REL}
+
+VENDOR_SYMBOLS_REL=/symbols/system/vendor/lib
+VENDOR_SYMBOLS_ABS=${DEVICE_TARGET_ABS}/${DEVICE}/${VENDOR_SYMBOLS_REL}
+
+# The name of the object built by the test vendor library.
+TEST_VENDOR_LIB=test-vendor.so
+# The name of the regular vendor object to be replaced by $TEST_VENDOR_LIB.
+VENDOR_LIB=libbt-vendor.so
+# The config file specifying controller properties.
+CONTROLLER_PROPERTIES=controller_properties.json
+
+if [[ "$#" -eq 4 && $3 == "--test-channel" ]]; then
+  TEST_CHANNEL_PORT=$4
+  TEST_CHANNEL_REL=/scripts
+  TEST_CHANNEL_ABS=${TEST_VENDOR_LIB_ABS}${TEST_CHANNEL_REL}
+
+  # Start logcat in a subshell.
+  x-terminal-emulator -e "scripts/build_and_run.sh ${AOSP_ABS} ${DEVICE}"
+
+  echo "Setting up build environment."
+  cd ${AOSP_ABS}
+  source build/envsetup.sh
+
+  # Forward local port to the same port on the device.
+  echo "Forwarding port ${TEST_CHANNEL_PORT} to device."
+  adb forward tcp:${TEST_CHANNEL_PORT} tcp:${TEST_CHANNEL_PORT}
+
+  # Turn Bluetooth on. Requires user approval via a dialog on the device.
+  echo "Enabling Bluetooth. Please see dialog on device."
+  adb shell am start -a android.bluetooth.adapter.action.REQUEST_ENABLE
+
+  # Start the test channel once Bluetooth is on and logcat has started.
+  read -p "Press [ENTER] once Bluetooth is enabling AND logcat has started."
+
+  # Start the test channel.
+  python ${TEST_CHANNEL_ABS}/test_channel.py localhost ${TEST_CHANNEL_PORT}
+else
+  echo "Setting up build environment."
+  cd ${AOSP_ABS}
+  source build/envsetup.sh
+
+  echo "Navigating to test vendor library: ${TEST_VENDOR_LIB_ABS}"
+  cd ${TEST_VENDOR_LIB_ABS}
+
+  echo "Building test vendor library."
+  mm
+
+  echo "Remounting device rootfs."
+  adb shell mount -o remount,rw /
+  adb remount
+
+  # Replace the actual vendor library with the test vendor library.
+  mv ${DEVICE_TARGET_ABS}/${DEVICE}/system/lib/${TEST_VENDOR_LIB} \
+    ${VENDOR_SYMBOLS_ABS}/${VENDOR_LIB}
+
+  # Push the test vendor library to the device.
+  echo "Pushing the test vendor library to device: $DEVICE"
+  adb push ${VENDOR_SYMBOLS_ABS}/${VENDOR_LIB} /vendor/lib
+
+  echo "Pushing controller properties."
+  adb push ${TEST_VENDOR_LIB_ABS}/data/${CONTROLLER_PROPERTIES} /etc/bluetooth/
+
+  echo "Pushing libevent."
+  adb push ${DEVICE_TARGET_ABS}/${DEVICE}/system/lib/libevent.so /system/lib/
+
+  echo "Pushing libchrome."
+  adb push ${DEVICE_TARGET_ABS}/${DEVICE}/system/lib/libchrome.so /system/lib/
+
+  # Clear logcat.
+  adb logcat -c
+
+  # Run logcat with filters.
+  adb logcat bt_btif:D bt_btif_core:D bt_hci:D bt_main:D bt_vendor:D \
+   bte_logmsg:D command_packet:D dual_mode_controller:D event_packet:D \
+   hci_transport:D hci_handler:D packet:D packet_stream:D \
+   test_channel_transport:D vendor_manager:D *:S
+fi
diff --git a/bt/vendor_libs/test_vendor_lib/scripts/test_channel.py b/bt/vendor_libs/test_vendor_lib/scripts/test_channel.py
new file mode 100644
index 0000000..cf470f9
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/scripts/test_channel.py
@@ -0,0 +1,247 @@
+#
+# Copyright 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""Script for sending testing parameters and commands to a Bluetooth device.
+
+This script provides a simple shell interface for sending data at run-time to a
+Bluetooth device. It is intended to be used in tandem with the test vendor
+library project.
+
+Usage:
+  Option A: Script
+    1. Run build_and_run.sh in scripts/ with the --test-channel flag set and the
+    port to use for the test channel.
+  Option B: Manual
+    1. Choose a port to use for the test channel. Use 'adb forward tcp:<port>
+    tcp:<port>' to forward the port to the device.
+    2. In a separate shell, build and push the test vendor library to the device
+    using the script mentioned in option A (i.e. without the --test-channel flag
+    set).
+    3. Once logcat has started, turn Bluetooth on from the device.
+    4. Run this program, in the shell from step 1,  the port, also from step 1,
+    as arguments.
+"""
+
+#!/usr/bin/env python
+
+import cmd
+import random
+import socket
+import string
+import struct
+import sys
+
+DEVICE_NAME_LENGTH = 6
+DEVICE_ADDRESS_LENGTH = 6
+
+# Used to generate fake device names and addresses during discovery.
+def generate_random_name():
+  return ''.join(random.SystemRandom().choice(string.ascii_uppercase + \
+    string.digits) for _ in range(DEVICE_NAME_LENGTH))
+
+def generate_random_address():
+  return ''.join(random.SystemRandom().choice(string.digits) for _ in \
+    range(DEVICE_ADDRESS_LENGTH))
+
+class Connection(object):
+  """Simple wrapper class for a socket object.
+
+  Attributes:
+    socket: The underlying socket created for the specified address and port.
+  """
+
+  def __init__(self, port):
+    self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    self._socket.connect(('localhost', port))
+
+  def close(self):
+    self._socket.close()
+
+  def send(self, data):
+    self._socket.sendall(data)
+
+class TestChannel(object):
+  """Checks outgoing commands and sends them once verified.
+
+  Attributes:
+    connection: The connection to the test vendor library that commands are sent
+    on.
+  """
+
+  def __init__(self, port):
+    self._connection = Connection(port)
+    self._discovered_devices = DeviceManager()
+
+  def discover_new_device(self, name=None, address=None):
+    device = Device(name, address)
+    self._discovered_devices.add_device(device)
+    return device
+
+  def close(self):
+    self._connection.close()
+
+  def send_command(self, name, args):
+    name_size = len(name)
+    args_size = len(args)
+    self.lint_command(name, args, name_size, args_size)
+    encoded_name = chr(name_size) + name
+    encoded_args = chr(args_size) + ''.join(chr(len(arg)) + arg for arg in args)
+    command = encoded_name + encoded_args
+    self._connection.send(command)
+
+  def lint_command(self, name, args, name_size, args_size):
+    assert name_size == len(name) and args_size == len(args)
+    try:
+      name.encode('utf-8')
+      for arg in args:
+        arg.encode('utf-8')
+    except UnicodeError:
+      print 'Unrecognized characters.'
+      raise
+    if name_size > 255 or args_size > 255:
+      raise ValueError  # Size must be encodable in one octet.
+    for arg in args:
+      if len(arg) > 255:
+        raise ValueError  # Size must be encodable in one octet.
+
+class DeviceManager(object):
+  """Maintains the active fake devices that have been "discovered".
+
+  Attributes:
+    device_list: Maps device addresses (keys) to devices (values).
+  """
+
+  def __init__(self):
+    self.device_list = {}
+
+  def add_device(self, device):
+    self.device_list[device.get_address()] = device
+
+class Device(object):
+  """A fake device to be returned in inquiry and scan results. Note that if an
+  explicit name or address is not provided, a random string of characters
+  is used.
+
+  Attributes:
+    name: The device name for use in extended results.
+    address: The BD address of the device.
+  """
+
+  def __init__(self, name=None, address=None):
+    # TODO(dennischeng): Generate device properties more robustly.
+    self._name = generate_random_name() if name is None else name
+    self._address = generate_random_address() if address is None else address
+
+  def get_name(self):
+    return self._name
+
+  def get_address(self):
+    return self._address
+
+class TestChannelShell(cmd.Cmd):
+  """Shell for sending test channel data to controller.
+
+  Manages the test channel to the controller and defines a set of commands the
+  user can send to the controller as well. These commands are processed parallel
+  to commands sent from the device stack and used to provide additional
+  debugging/testing capabilities.
+
+  Attributes:
+    test_channel: The communication channel to send data to the controller.
+  """
+
+  def __init__(self, test_channel):
+    print 'Type \'help\' for more information.'
+    cmd.Cmd.__init__(self)
+    self._test_channel = test_channel
+
+  def do_clear(self, args):
+    """
+    Arguments: None.
+    Resets the controller to its original, unmodified state.
+    """
+    self._test_channel.send_command('CLEAR', [])
+
+  def do_clear_event_delay(self, args):
+    """
+    Arguments: None.
+    Clears the response delay set by set_event_delay.
+    """
+    self._test_channel.send_command('CLEAR_EVENT_DELAY', args.split())
+
+  def do_discover(self, args):
+    """
+    Arguments: name_1 name_2 ...
+    Sends an inquiry result for named device(s). If no names are provided, a
+    random name is used instead.
+    """
+    if len(args) == 0:
+      args = generate_random_name()
+    device_list = [self._test_channel.discover_new_device(arg) for arg in \
+                   args.split()]
+    device_names_and_addresses = []
+    for device in device_list:
+      device_names_and_addresses.append(device.get_name())
+      device_names_and_addresses.append(device.get_address())
+    self._test_channel.send_command('DISCOVER', device_names_and_addresses)
+
+  def do_set_event_delay(self, args):
+    """
+    Arguments: interval_in_ms
+    Sets the response delay for all event packets sent from the controller back
+    to the HCI.
+    """
+    self._test_channel.send_command('SET_EVENT_DELAY', args.split())
+
+  def do_timeout_all(self, args):
+    """
+    Arguments: None.
+    Causes all HCI commands to timeout.
+    """
+    self._test_channel.send_command('TIMEOUT_ALL', [])
+
+  def do_quit(self, args):
+    """
+    Arguments: None.
+    Exits the test channel.
+    """
+    self._test_channel.send_command('CLOSE_TEST_CHANNEL', [])
+    self._test_channel.close()
+    print 'Goodbye.'
+    return True
+
+def main(argv):
+  if len(argv) != 2:
+    print 'Usage: python test_channel.py [port]'
+    return
+  try:
+    port = int(argv[1])
+  except ValueError:
+    print 'Error parsing port.'
+  else:
+    try:
+      test_channel = TestChannel(port)
+    except socket.error, e:
+      print 'Error connecting to socket: %s' % e
+    except:
+      print 'Error creating test channel (check argument).'
+    else:
+      test_channel_shell = TestChannelShell(test_channel)
+      test_channel_shell.prompt = '$ '
+      test_channel_shell.cmdloop()
+
+if __name__ == '__main__':
+  main(sys.argv)
diff --git a/bt/vendor_libs/test_vendor_lib/src/async_manager.cc b/bt/vendor_libs/test_vendor_lib/src/async_manager.cc
new file mode 100644
index 0000000..076eab3
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/src/async_manager.cc
@@ -0,0 +1,513 @@
+//
+// Copyright 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#define LOG_TAG "async_manager"
+
+#include "async_manager.h"
+
+#include <algorithm>
+#include <atomic>
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+#include <vector>
+#include "fcntl.h"
+#include "sys/select.h"
+#include "unistd.h"
+
+namespace test_vendor_lib {
+// Implementation of AsyncManager is divided between two classes, three if
+// AsyncManager itself is taken into account, but its only responsability
+// besides being a proxy for the other two classes is to provide a global
+// synchronization mechanism for callbacks and client code to use.
+
+// The watching of file descriptors is done through AsyncFdWatcher. Several
+// objects of this class may coexist simultaneosly as they share no state.
+// After construction of this objects nothing happens beyond some very simple
+// member initialization. When the first FD is set up for watching the object
+// starts a new thread which watches the given (and later provided) FDs using
+// select() inside a loop. A special FD (a pipe) is also watched which is
+// used to notify the thread of internal changes on the object state (like
+// the addition of new FDs to watch on). Every access to internal state is
+// synchronized using a single internal mutex. The thread is only stopped on
+// destruction of the object, by modifying a flag, which is the only member
+// variable accessed without acquiring the lock (because the notification to
+// the thread is done later by writing to a pipe which means the thread will
+// be notified regardless of what phase of the loop it is in that moment)
+
+// The scheduling of asynchronous tasks, periodic or not, is handled by the
+// AsyncTaskManager class. Like the one for FDs, this class shares no internal
+// state between different instances so it is safe to use several objects of
+// this class, also nothing interesting happens upon construction, but only
+// after a Task has been scheduled and access to internal state is synchronized
+// using a single internal mutex. When the first task is scheduled a thread
+// is started which monitors a queue of tasks. The queue is peeked to see
+// when the next task should be carried out and then the thread performs a
+// (absolute) timed wait on a condition variable. The wait ends because of a
+// time out or a notify on the cond var, the former means a task is due
+// for execution while the later means there has been a change in internal
+// state, like a task has been scheduled/canceled or the flag to stop has
+// been set. Setting and querying the stop flag or modifying the task queue
+// and subsequent notification on the cond var is done atomically (e.g while
+// holding the lock on the internal mutex) to ensure that the thread never
+// misses the notification, since notifying a cond var is not persistent as
+// writing on a pipe (if not done this way, the thread could query the
+// stopping flag and be put aside by the OS scheduler right after, then the
+// 'stop thread' procedure could run, setting the flag, notifying a cond
+// var that no one is waiting on and joining the thread, the thread then
+// resumes execution believing that it needs to continue and waits on the
+// cond var possibly forever if there are no tasks scheduled, efectively
+// causing a deadlock).
+
+// This number also states the maximum number of scheduled tasks we can handle
+// at a given time
+static const uint16_t kMaxTaskId =
+    -1; /* 2^16 - 1, permisible ids are {1..2^16-1}*/
+static inline AsyncTaskId NextAsyncTaskId(const AsyncTaskId id) {
+  return (id == kMaxTaskId) ? 1 : id + 1;
+}
+// The buffer is only 10 bytes because the expected number of bytes
+// written on this socket is 1. It is possible that the thread is notified
+// more than once but highly unlikely, so a buffer of size 10 seems enough
+// and the reads are performed inside a while just in case it isn't. From
+// the thread routine's point of view it is the same to have been notified
+// just once or 100 times so it just tries to consume the entire buffer.
+// In the cases where an interrupt would cause read to return without
+// having read everything that was available a new iteration of the thread
+// loop will bring execution to this point almost immediately, so there is
+// no need to treat that case.
+static const int kNotificationBufferSize = 10;
+
+// Async File Descriptor Watcher Implementation:
+class AsyncManager::AsyncFdWatcher {
+ public:
+  int WatchFdForNonBlockingReads(
+      int file_descriptor, const ReadCallback& on_read_fd_ready_callback) {
+    // add file descriptor and callback
+    {
+      std::unique_lock<std::mutex> guard(internal_mutex_);
+      watched_shared_fds_[file_descriptor] = on_read_fd_ready_callback;
+    }
+
+    // start the thread if not started yet
+    int started = tryStartThread();
+    if (started != 0) {
+      LOG_ERROR(LOG_TAG, "%s: Unable to start thread", __FUNCTION__);
+      return started;
+    }
+
+    // notify the thread so that it knows of the new FD
+    notifyThread();
+
+    return 0;
+  }
+
+  void StopWatchingFileDescriptor(int file_descriptor) {
+    std::unique_lock<std::mutex> guard(internal_mutex_);
+    watched_shared_fds_.erase(file_descriptor);
+  }
+
+  AsyncFdWatcher() = default;
+
+  ~AsyncFdWatcher() { stopThread(); }
+
+ private:
+  AsyncFdWatcher(const AsyncFdWatcher&) = delete;
+  AsyncFdWatcher& operator=(const AsyncFdWatcher&) = delete;
+
+  // Make sure to call this with at least one file descriptor ready to be
+  // watched upon or the thread routine will return immediately
+  int tryStartThread() {
+    if (std::atomic_exchange(&running_, true)) {
+      return 0;  // if already running
+    }
+    // set up the communication channel
+    int pipe_fds[2];
+    if (pipe(pipe_fds)) {
+      LOG_ERROR(LOG_TAG,
+                "%s:Unable to establish a communication channel to the reading "
+                "thread",
+                __FUNCTION__);
+      return -1;
+    }
+    notification_listen_fd_ = pipe_fds[0];
+    notification_write_fd_ = pipe_fds[1];
+    TEMP_FAILURE_RETRY(fcntl(notification_listen_fd_, F_SETFD, O_NONBLOCK));
+    TEMP_FAILURE_RETRY(fcntl(notification_write_fd_, F_SETFD, O_NONBLOCK));
+
+    thread_ = std::thread([this]() { ThreadRoutine(); });
+    if (!thread_.joinable()) {
+      LOG_ERROR(LOG_TAG, "%s: Unable to start reading thread", __FUNCTION__);
+      return -1;
+    }
+    return 0;
+  }
+
+  int stopThread() {
+    if (!std::atomic_exchange(&running_, false)) {
+      return 0;  // if not running already
+    }
+
+    notifyThread();
+
+    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",
+               __FUNCTION__);
+    }
+
+    {
+      std::unique_lock<std::mutex> guard(internal_mutex_);
+      watched_shared_fds_.clear();
+    }
+
+    return 0;
+  }
+
+  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",
+                __FUNCTION__);
+      return -1;
+    }
+    return 0;
+  }
+
+  int setUpFileDescriptorSet(fd_set& read_fds) {
+    // add comm channel to the set
+    FD_SET(notification_listen_fd_, &read_fds);
+    int nfds = notification_listen_fd_;
+
+    // add watched FDs to the set
+    {
+      std::unique_lock<std::mutex> guard(internal_mutex_);
+      for (auto& fdp : watched_shared_fds_) {
+        FD_SET(fdp.first, &read_fds);
+        nfds = std::max(fdp.first, nfds);
+      }
+    }
+    return nfds;
+  }
+
+  // check the comm channel and read everything there
+  bool consumeThreadNotifications(fd_set& read_fds) {
+    if (FD_ISSET(notification_listen_fd_, &read_fds)) {
+      char buffer[kNotificationBufferSize];
+      while (TEMP_FAILURE_RETRY(read(notification_listen_fd_, buffer,
+                                     kNotificationBufferSize)) ==
+             kNotificationBufferSize) {
+      }
+      return true;
+    }
+    return false;
+  }
+
+  // check all file descriptors and call callbacks if necesary
+  void runAppropriateCallbacks(fd_set& read_fds) {
+    // not a good idea to call a callback while holding the FD lock,
+    // nor to release the lock while traversing the map
+    std::vector<decltype(watched_shared_fds_)::value_type> fds;
+    {
+      std::unique_lock<std::mutex> guard(internal_mutex_);
+      for (auto& fdc : watched_shared_fds_) {
+        if (FD_ISSET(fdc.first, &read_fds)) {
+          fds.push_back(fdc);
+        }
+      }
+    }
+    for (auto& p : fds) {
+      p.second(p.first);
+    }
+  }
+
+  void ThreadRoutine() {
+    while (running_) {
+      fd_set read_fds;
+      FD_ZERO(&read_fds);
+      int nfds = setUpFileDescriptorSet(read_fds);
+
+      // 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",
+                  __FUNCTION__);
+        continue;
+      }
+
+      consumeThreadNotifications(read_fds);
+
+      // Do not read if there was a call to stop running
+      if (!running_) {
+        break;
+      }
+
+      runAppropriateCallbacks(read_fds);
+    }
+  }
+
+  std::atomic_bool running_{false};
+  std::thread thread_;
+  std::mutex internal_mutex_;
+
+  std::map<int, ReadCallback> watched_shared_fds_;
+
+  // A pair of FD to send information to the reading thread
+  int notification_listen_fd_;
+  int notification_write_fd_;
+};
+
+// Async task manager implementation
+class AsyncManager::AsyncTaskManager {
+ public:
+  AsyncTaskId ExecAsync(std::chrono::milliseconds delay,
+                        const TaskCallback& callback) {
+    return scheduleTask(std::make_shared<Task>(
+        std::chrono::steady_clock::now() + delay, callback));
+  }
+
+  AsyncTaskId ExecAsyncPeriodically(std::chrono::milliseconds delay,
+                                    std::chrono::milliseconds period,
+                                    const TaskCallback& callback) {
+    return scheduleTask(std::make_shared<Task>(
+        std::chrono::steady_clock::now() + delay, period, callback));
+  }
+
+  bool CancelAsyncTask(AsyncTaskId async_task_id) {
+    // remove task from queue (and task id asociation) while holding lock
+    std::unique_lock<std::mutex> guard(internal_mutex_);
+    if (tasks_by_id.count(async_task_id) == 0) {
+      return false;
+    }
+    task_queue_.erase(tasks_by_id[async_task_id]);
+    tasks_by_id.erase(async_task_id);
+    return true;
+  }
+
+  AsyncTaskManager() = default;
+
+  ~AsyncTaskManager() { stopThread(); }
+
+ private:
+  // Holds the data for each task
+  class Task {
+   public:
+    Task(std::chrono::steady_clock::time_point time,
+         std::chrono::milliseconds period, const TaskCallback& callback)
+        : time(time),
+          periodic(true),
+          period(period),
+          callback(callback),
+          task_id(kInvalidTaskId) {}
+    Task(std::chrono::steady_clock::time_point time,
+         const TaskCallback& callback)
+        : time(time),
+          periodic(false),
+          callback(callback),
+          task_id(kInvalidTaskId) {}
+
+    // Operators needed to be in a collection
+    bool operator<(const Task& another) const {
+      return std::make_pair(time, task_id) <
+             std::make_pair(another.time, another.task_id);
+    }
+
+    bool isPeriodic() const { return periodic; }
+
+    // These fields should no longer be public if the class ever becomes
+    // public or gets more complex
+    std::chrono::steady_clock::time_point time;
+    bool periodic;
+    std::chrono::milliseconds period;
+    TaskCallback callback;
+    AsyncTaskId task_id;
+  };
+
+  // A comparator class to put shared pointers to tasks in an ordered set
+  struct task_p_comparator {
+    bool operator()(const std::shared_ptr<Task>& t1,
+                    const std::shared_ptr<Task>& t2) const {
+      return *t1 < *t2;
+    }
+  };
+
+  AsyncTaskManager(const AsyncTaskManager&) = delete;
+  AsyncTaskManager& operator=(const AsyncTaskManager&) = delete;
+
+  AsyncTaskId scheduleTask(const std::shared_ptr<Task>& task) {
+    AsyncTaskId task_id = kInvalidTaskId;
+    {
+      std::unique_lock<std::mutex> guard(internal_mutex_);
+      // no more room for new tasks, we need a larger type for IDs
+      if (tasks_by_id.size() == kMaxTaskId)  // TODO potentially type unsafe
+        return kInvalidTaskId;
+      do {
+        lastTaskId_ = NextAsyncTaskId(lastTaskId_);
+      } while (isTaskIdInUse(lastTaskId_));
+      task->task_id = lastTaskId_;
+      // add task to the queue and map
+      tasks_by_id[lastTaskId_] = task;
+      task_queue_.insert(task);
+      task_id = lastTaskId_;
+    }
+    // start thread if necessary
+    int started = tryStartThread();
+    if (started != 0) {
+      LOG_ERROR(LOG_TAG, "%s: Unable to start thread", __FUNCTION__);
+      return kInvalidTaskId;
+    }
+    // notify the thread so that it knows of the new task
+    internal_cond_var_.notify_one();
+    // return task id
+    return task_id;
+  }
+
+  bool isTaskIdInUse(const AsyncTaskId& task_id) const {
+    return tasks_by_id.count(task_id) != 0;
+  }
+
+  int tryStartThread() {
+    // need the lock because of the running flag and the cond var
+    std::unique_lock<std::mutex> guard(internal_mutex_);
+    // check that the thread is not yet running
+    if (running_) {
+      return 0;
+    }
+    // start the thread
+    running_ = true;
+    thread_ = std::thread([this]() { ThreadRoutine(); });
+    if (!thread_.joinable()) {
+      LOG_ERROR(LOG_TAG, "%s: Unable to start task thread", __FUNCTION__);
+    }
+    return -1;
+  }
+
+  int stopThread() {
+    {
+      std::unique_lock<std::mutex> guard(internal_mutex_);
+      tasks_by_id.clear();
+      task_queue_.clear();
+      if (!running_) {
+        return 0;
+      }
+      running_ = false;
+      // notify the thread
+      internal_cond_var_.notify_one();
+    }  // release the lock before joining a thread that is likely waiting for it
+    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",
+               __FUNCTION__);
+    }
+    return 0;
+  }
+
+  void ThreadRoutine() {
+    while (1) {
+      TaskCallback callback;
+      bool run_it = false;
+      {
+        std::unique_lock<std::mutex> guard(internal_mutex_);
+        if (!task_queue_.empty()) {
+          std::shared_ptr<Task> task_p = *(task_queue_.begin());
+          if (task_p->time < std::chrono::steady_clock::now()) {
+            run_it = true;
+            callback = task_p->callback;
+            task_queue_.erase(task_p);  // need to remove and add again if
+                                        // periodic to update order
+            if (task_p->isPeriodic()) {
+              task_p->time += task_p->period;
+              task_queue_.insert(task_p);
+            } else {
+              tasks_by_id.erase(task_p->task_id);
+            }
+          }
+        }
+      }
+      if (run_it) {
+        callback();
+      }
+      {
+        std::unique_lock<std::mutex> guard(internal_mutex_);
+        // wait on condition variable with timeout just in time for next task if
+        // any
+        if (task_queue_.size() > 0) {
+          internal_cond_var_.wait_until(guard, (*task_queue_.begin())->time);
+        } else {
+          internal_cond_var_.wait(guard);
+        }
+        // check for termination right after being notified (and maybe before?)
+        if (!running_) break;
+      }
+    }
+  }
+
+  bool running_ = false;
+  std::thread thread_;
+  std::mutex internal_mutex_;
+  std::condition_variable internal_cond_var_;
+
+  AsyncTaskId lastTaskId_ = kInvalidTaskId;
+  std::map<AsyncTaskId, std::shared_ptr<Task> > tasks_by_id;
+  std::set<std::shared_ptr<Task>, task_p_comparator> task_queue_;
+};
+
+// Async Manager Implementation:
+AsyncManager::AsyncManager()
+    : fdWatcher_p_(new AsyncFdWatcher()),
+      taskManager_p_(new AsyncTaskManager()) {}
+
+AsyncManager::~AsyncManager() {
+  fdWatcher_p_.reset();    // make sure the threads are stopped
+  taskManager_p_.reset();  // before destroying the mutex
+}
+
+int AsyncManager::WatchFdForNonBlockingReads(
+    int file_descriptor, const ReadCallback& on_read_fd_ready_callback) {
+  return fdWatcher_p_->WatchFdForNonBlockingReads(file_descriptor,
+                                                  on_read_fd_ready_callback);
+}
+
+void AsyncManager::StopWatchingFileDescriptor(int file_descriptor) {
+  fdWatcher_p_->StopWatchingFileDescriptor(file_descriptor);
+}
+
+AsyncTaskId AsyncManager::ExecAsync(std::chrono::milliseconds delay,
+                                    const TaskCallback& callback) {
+  return taskManager_p_->ExecAsync(delay, callback);
+}
+
+AsyncTaskId AsyncManager::ExecAsyncPeriodically(
+    std::chrono::milliseconds delay, std::chrono::milliseconds period,
+    const TaskCallback& callback) {
+  return taskManager_p_->ExecAsyncPeriodically(delay, period, callback);
+}
+
+bool AsyncManager::CancelAsyncTask(AsyncTaskId async_task_id) {
+  return taskManager_p_->CancelAsyncTask(async_task_id);
+}
+
+void AsyncManager::Synchronize(const CriticalCallback& critical) {
+  std::unique_lock<std::mutex> guard(synchronization_mutex_);
+  critical();
+}
+}
diff --git a/bt/vendor_libs/test_vendor_lib/src/bt_address.cc b/bt/vendor_libs/test_vendor_lib/src/bt_address.cc
new file mode 100644
index 0000000..4a0c4c4
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/src/bt_address.cc
@@ -0,0 +1,85 @@
+//
+// Copyright 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "bt_address.h"
+#include <assert.h>
+#include <iomanip>
+#include <vector>
+using std::vector;
+
+#include "base/logging.h"
+
+namespace test_vendor_lib {
+
+bool BtAddress::IsValid(const std::string& addr) {
+  if (addr.length() < kStringLength) return false;
+
+  for (size_t i = 0; i < kStringLength; i++) {
+    if (i % 3 == 2) {  // Every third character must be ':'
+      if (addr[i] != ':') return false;
+    } else {  // The rest must be hexadecimal digits
+      if (!isxdigit(addr[i])) return false;
+    }
+  }
+  return true;
+}
+
+bool BtAddress::FromString(const std::string& str) {
+  std::string tok;
+  std::istringstream iss(str);
+
+  if (IsValid(str) == false) return false;
+
+  address_ = 0;
+  for (size_t i = 0; i < kOctets; i++) {
+    getline(iss, tok, ':');
+    uint64_t octet = std::stoi(tok, nullptr, 16);
+    address_ |= (octet << (8 * ((kOctets - 1) - i)));
+  }
+  return true;
+}
+
+bool BtAddress::FromVector(const vector<uint8_t>& octets) {
+  if (octets.size() < kOctets) return false;
+
+  address_ = 0;
+  for (size_t i = 0; i < kOctets; i++) {
+    uint64_t to_shift = octets[i];
+    address_ |= to_shift << (8 * i);
+  }
+  return true;
+}
+
+void BtAddress::ToVector(vector<uint8_t>& octets) const {
+  for (size_t i = 0; i < kOctets; i++) {
+    octets.push_back(address_ >> (8 * i));
+  }
+}
+
+std::string BtAddress::ToString() const {
+  std::stringstream ss;
+
+  ss << std::hex << std::setfill('0') << std::setw(2);
+  for (size_t i = 0; i < kOctets; i++) {
+    uint64_t octet = (address_ >> (8 * ((kOctets - 1) - i))) & 0xff;
+    ss << std::hex << std::setfill('0') << std::setw(2) << octet;
+    if (i != kOctets - 1) ss << std::string(":");
+  }
+
+  return ss.str();
+}
+
+}  // namespace test_vendor_lib
diff --git a/bt/vendor_libs/test_vendor_lib/src/bt_vendor.cc b/bt/vendor_libs/test_vendor_lib/src/bt_vendor.cc
new file mode 100644
index 0000000..b078505
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/src/bt_vendor.cc
@@ -0,0 +1,143 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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_vendor"
+
+#include <unistd.h>
+#include <memory>
+
+#include "base/logging.h"
+#include "osi/include/log.h"
+#include "vendor_manager.h"
+
+namespace test_vendor_lib {
+
+class BtVendor {
+ public:
+  // Initializes vendor manager for test controller. |p_cb| are the callbacks to
+  // be in TestVendorOp(). |local_bdaddr| points to the address of the Bluetooth
+  // device. Returns 0 on success, -1 on error.
+  static int Initialize(const bt_vendor_callbacks_t* p_cb,
+                        unsigned char* /* local_bdaddr */) {
+    LOG_INFO(LOG_TAG, "Initializing test controller.");
+    CHECK(p_cb);
+
+    vendor_callbacks_ = *p_cb;
+
+    vendor_manager_.reset(new VendorManager());
+    return vendor_manager_->Initialize() ? 0 : 1;
+  }
+
+  // Vendor specific operations. |opcode| is the opcode for Bluedroid's vendor
+  // op definitions. |param| points to operation specific arguments. Return
+  // value is dependent on the operation invoked, or -1 on error.
+  static int Op(bt_vendor_opcode_t opcode, void* param) {
+    LOG_INFO(LOG_TAG, "Opcode received in vendor library: %d", opcode);
+
+    switch (opcode) {
+      case BT_VND_OP_POWER_CTRL: {
+        LOG_INFO(LOG_TAG, "Doing op: BT_VND_OP_POWER_CTRL");
+        int* state = static_cast<int*>(param);
+        if (*state == BT_VND_PWR_OFF)
+          LOG_INFO(LOG_TAG, "Turning Bluetooth off.");
+        else if (*state == BT_VND_PWR_ON)
+          LOG_INFO(LOG_TAG, "Turning Bluetooth on.");
+        return 0;
+      }
+
+      // Give the HCI its fd to communicate with the HciTransport.
+      case BT_VND_OP_USERIAL_OPEN: {
+        LOG_INFO(LOG_TAG, "Doing op: BT_VND_OP_USERIAL_OPEN");
+        CHECK(vendor_manager_);
+        int* fd_list = static_cast<int*>(param);
+        fd_list[0] = vendor_manager_->GetHciFd();
+        LOG_INFO(LOG_TAG, "Setting HCI's fd to: %d", fd_list[0]);
+        return 1;
+      }
+
+      // Close the HCI's file descriptor.
+      case BT_VND_OP_USERIAL_CLOSE:
+        LOG_INFO(LOG_TAG, "Doing op: BT_VND_OP_USERIAL_CLOSE");
+        CHECK(vendor_manager_);
+        LOG_INFO(LOG_TAG, "Closing HCI's fd (fd: %d)",
+                 vendor_manager_->GetHciFd());
+        vendor_manager_->CloseHciFd();
+        return 1;
+
+      case BT_VND_OP_FW_CFG:
+        LOG_INFO(LOG_TAG, "Unsupported op: BT_VND_OP_FW_CFG");
+        vendor_callbacks_.fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);
+        return -1;
+
+      case BT_VND_OP_SCO_CFG:
+        LOG_INFO(LOG_TAG, "Unsupported op: BT_VND_OP_SCO_CFG");
+        vendor_callbacks_.scocfg_cb(BT_VND_OP_RESULT_SUCCESS);
+        return -1;
+
+      case BT_VND_OP_GET_LPM_IDLE_TIMEOUT:
+        LOG_INFO(LOG_TAG, "Doing op: BT_VND_OP_SCO_CFG");
+        *((uint32_t*)param) = 1000;
+        return 0;
+
+      case BT_VND_OP_LPM_SET_MODE:
+        LOG_INFO(LOG_TAG, "Unsupported op: BT_VND_OP_LPM_SET_MODE");
+        vendor_callbacks_.lpm_cb(BT_VND_OP_RESULT_SUCCESS);
+        return -1;
+
+      case BT_VND_OP_LPM_WAKE_SET_STATE:
+        LOG_INFO(LOG_TAG, "Unsupported op: BT_VND_OP_LPM_WAKE_SET_STATE");
+        return -1;
+
+      case BT_VND_OP_SET_AUDIO_STATE:
+        LOG_INFO(LOG_TAG, "Unsupported op: BT_VND_OP_SET_AUDIO_STATE");
+        return -1;
+
+      case BT_VND_OP_EPILOG:
+        LOG_INFO(LOG_TAG, "Unsupported op: BT_VND_OP_EPILOG");
+        vendor_callbacks_.epilog_cb(BT_VND_OP_RESULT_SUCCESS);
+        return -1;
+
+      default:
+        LOG_INFO(LOG_TAG, "Op not recognized.");
+        return -1;
+    }
+    return 0;
+  }
+
+  // Closes the vendor interface and cleans up the global vendor manager object.
+  static void CleanUp(void) {
+    LOG_INFO(LOG_TAG, "Cleaning up vendor library.");
+    CHECK(vendor_manager_);
+    vendor_manager_->CleanUp();
+    vendor_manager_.reset();
+  }
+
+ private:
+  static std::unique_ptr<VendorManager> vendor_manager_;
+  static bt_vendor_callbacks_t vendor_callbacks_;
+};
+
+// Definition of static class members
+std::unique_ptr<VendorManager> BtVendor::vendor_manager_;
+bt_vendor_callbacks_t BtVendor::vendor_callbacks_;
+
+}  // namespace test_vendor_lib
+
+// Entry point of DLib.
+EXPORT_SYMBOL
+const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = {
+    sizeof(bt_vendor_interface_t), test_vendor_lib::BtVendor::Initialize,
+    test_vendor_lib::BtVendor::Op, test_vendor_lib::BtVendor::CleanUp};
diff --git a/bt/vendor_libs/test_vendor_lib/src/command_packet.cc b/bt/vendor_libs/test_vendor_lib/src/command_packet.cc
new file mode 100644
index 0000000..79935dc
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/src/command_packet.cc
@@ -0,0 +1,49 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 "command_packet"
+
+#include "command_packet.h"
+
+#include "hci/include/hci_hal.h"
+#include "osi/include/log.h"
+#include "stack/include/hcidefs.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+CommandPacket::CommandPacket(vector<uint8_t> header)
+    : Packet(DATA_TYPE_COMMAND, std::move(header)) {}
+
+CommandPacket::CommandPacket(uint16_t opcode)
+    : Packet(DATA_TYPE_COMMAND, {static_cast<uint8_t>(opcode),
+                                 static_cast<uint8_t>(opcode >> 8)}) {}
+
+CommandPacket::CommandPacket(vector<uint8_t> header, vector<uint8_t> payload)
+    : Packet(DATA_TYPE_COMMAND, std::move(header)) {
+  AddPayloadOctets(payload.size(), std::move(payload));
+}
+
+uint16_t CommandPacket::GetOpcode() const {
+  return 0 | (GetHeader()[0] | (GetHeader()[1] << 8));
+}
+
+uint8_t CommandPacket::GetOGF() const { return HCI_OGF(GetOpcode()); }
+
+uint16_t CommandPacket::GetOCF() const { return HCI_OCF(GetOpcode()); }
+
+}  // namespace test_vendor_lib
diff --git a/bt/vendor_libs/test_vendor_lib/src/dual_mode_controller.cc b/bt/vendor_libs/test_vendor_lib/src/dual_mode_controller.cc
new file mode 100644
index 0000000..1db4b2e
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/src/dual_mode_controller.cc
@@ -0,0 +1,748 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 "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 "event_packet.h"
+#include "hci_transport.h"
+
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "stack/include/hcidefs.h"
+
+using std::vector;
+
+namespace {
+
+// Included in certain events to indicate success (specific to the event
+// context).
+const uint8_t kSuccessStatus = 0;
+
+const uint8_t kUnknownHciCommand = 1;
+
+// The location of the config file loaded to populate controller attributes.
+const std::string kControllerPropertiesFile =
+    "/etc/bluetooth/controller_properties.json";
+
+// Inquiry modes for specifiying inquiry result formats.
+const uint8_t kStandardInquiry = 0x00;
+const uint8_t kRssiInquiry = 0x01;
+const uint8_t kExtendedOrRssiInquiry = 0x02;
+
+// The bd address of another (fake) device.
+const vector<uint8_t> kOtherDeviceBdAddress = {6, 5, 4, 3, 2, 1};
+
+void LogCommand(const char* command) {
+  LOG_INFO(LOG_TAG, "Controller performing command: %s", command);
+}
+
+// Functions used by JSONValueConverter to read stringified JSON into Properties
+// object.
+bool ParseUint8t(const base::StringPiece& value, uint8_t* field) {
+  *field = std::stoi(value.as_string());
+  return true;
+}
+
+bool ParseUint16t(const base::StringPiece& value, uint16_t* field) {
+  *field = std::stoi(value.as_string());
+  return true;
+}
+
+}  // namespace
+
+namespace test_vendor_lib {
+
+void DualModeController::AddControllerEvent(std::chrono::milliseconds delay,
+                                            const TaskCallback& task) {
+  controller_events_.push_back(schedule_task_(delay, task));
+}
+
+void DualModeController::SendCommandCompleteSuccess(
+    uint16_t command_opcode) const {
+  send_event_(EventPacket::CreateCommandCompleteOnlyStatusEvent(
+      command_opcode, kSuccessStatus));
+}
+
+void DualModeController::SendCommandCompleteOnlyStatus(uint16_t command_opcode,
+                                                       uint8_t status) const {
+  send_event_(EventPacket::CreateCommandCompleteOnlyStatusEvent(command_opcode,
+                                                                status));
+}
+
+void DualModeController::SendCommandStatus(uint8_t status,
+                                           uint16_t command_opcode) const {
+  send_event_(EventPacket::CreateCommandStatusEvent(status, command_opcode));
+}
+
+void DualModeController::SendCommandStatusSuccess(
+    uint16_t command_opcode) const {
+  SendCommandStatus(kSuccessStatus, command_opcode);
+}
+
+DualModeController::DualModeController()
+    : state_(kStandby),
+      properties_(kControllerPropertiesFile),
+      test_channel_state_(kNone) {
+#define SET_HANDLER(opcode, method)                                     \
+  active_hci_commands_[opcode] = [this](const vector<uint8_t>& param) { \
+    method(param);                                                      \
+  };
+  SET_HANDLER(HCI_RESET, HciReset);
+  SET_HANDLER(HCI_READ_BUFFER_SIZE, HciReadBufferSize);
+  SET_HANDLER(HCI_HOST_BUFFER_SIZE, HciHostBufferSize);
+  SET_HANDLER(HCI_READ_LOCAL_VERSION_INFO, HciReadLocalVersionInformation);
+  SET_HANDLER(HCI_READ_BD_ADDR, HciReadBdAddr);
+  SET_HANDLER(HCI_READ_LOCAL_SUPPORTED_CMDS, HciReadLocalSupportedCommands);
+  SET_HANDLER(HCI_READ_LOCAL_SUPPORTED_CODECS, HciReadLocalSupportedCodecs);
+  SET_HANDLER(HCI_READ_LOCAL_EXT_FEATURES, HciReadLocalExtendedFeatures);
+  SET_HANDLER(HCI_WRITE_SIMPLE_PAIRING_MODE, HciWriteSimplePairingMode);
+  SET_HANDLER(HCI_WRITE_LE_HOST_SUPPORT, HciWriteLeHostSupport);
+  SET_HANDLER(HCI_SET_EVENT_MASK, HciSetEventMask);
+  SET_HANDLER(HCI_WRITE_INQUIRY_MODE, HciWriteInquiryMode);
+  SET_HANDLER(HCI_WRITE_PAGESCAN_TYPE, HciWritePageScanType);
+  SET_HANDLER(HCI_WRITE_INQSCAN_TYPE, HciWriteInquiryScanType);
+  SET_HANDLER(HCI_WRITE_CLASS_OF_DEVICE, HciWriteClassOfDevice);
+  SET_HANDLER(HCI_WRITE_PAGE_TOUT, HciWritePageTimeout);
+  SET_HANDLER(HCI_WRITE_DEF_POLICY_SETTINGS, HciWriteDefaultLinkPolicySettings);
+  SET_HANDLER(HCI_READ_LOCAL_NAME, HciReadLocalName);
+  SET_HANDLER(HCI_CHANGE_LOCAL_NAME, HciWriteLocalName);
+  SET_HANDLER(HCI_WRITE_EXT_INQ_RESPONSE, HciWriteExtendedInquiryResponse);
+  SET_HANDLER(HCI_WRITE_VOICE_SETTINGS, HciWriteVoiceSetting);
+  SET_HANDLER(HCI_WRITE_CURRENT_IAC_LAP, HciWriteCurrentIacLap);
+  SET_HANDLER(HCI_WRITE_INQUIRYSCAN_CFG, HciWriteInquiryScanActivity);
+  SET_HANDLER(HCI_WRITE_SCAN_ENABLE, HciWriteScanEnable);
+  SET_HANDLER(HCI_SET_EVENT_FILTER, HciSetEventFilter);
+  SET_HANDLER(HCI_INQUIRY, HciInquiry);
+  SET_HANDLER(HCI_INQUIRY_CANCEL, HciInquiryCancel);
+  SET_HANDLER(HCI_DELETE_STORED_LINK_KEY, HciDeleteStoredLinkKey);
+  SET_HANDLER(HCI_RMT_NAME_REQUEST, HciRemoteNameRequest);
+  SET_HANDLER(HCI_BLE_SET_EVENT_MASK, HciLeSetEventMask);
+  SET_HANDLER(HCI_BLE_READ_BUFFER_SIZE, HciLeReadBufferSize);
+  SET_HANDLER(HCI_BLE_READ_LOCAL_SPT_FEAT, HciLeReadLocalSupportedFeatures);
+  SET_HANDLER(HCI_BLE_WRITE_RANDOM_ADDR, HciLeSetRandomAddress);
+  SET_HANDLER(HCI_BLE_WRITE_ADV_DATA, HciLeSetAdvertisingData);
+  SET_HANDLER(HCI_BLE_WRITE_ADV_PARAMS, HciLeSetAdvertisingParameters);
+  SET_HANDLER(HCI_BLE_WRITE_SCAN_PARAMS, HciLeSetScanParameters);
+  SET_HANDLER(HCI_BLE_WRITE_SCAN_ENABLE, HciLeSetScanEnable);
+  SET_HANDLER(HCI_BLE_READ_WHITE_LIST_SIZE, HciLeReadWhiteListSize);
+  SET_HANDLER(HCI_BLE_RAND, HciLeRand);
+  SET_HANDLER(HCI_BLE_READ_SUPPORTED_STATES, HciLeReadSupportedStates);
+  SET_HANDLER((HCI_GRP_VENDOR_SPECIFIC | 0x27), HciBleVendorSleepMode);
+  SET_HANDLER(HCI_BLE_VENDOR_CAP_OCF, HciBleVendorCap);
+  SET_HANDLER(HCI_BLE_MULTI_ADV_OCF, HciBleVendorMultiAdv);
+  SET_HANDLER((HCI_GRP_VENDOR_SPECIFIC | 0x155), HciBleVendor155);
+  SET_HANDLER((HCI_GRP_VENDOR_SPECIFIC | 0x157), HciBleVendor157);
+  SET_HANDLER(HCI_BLE_ENERGY_INFO_OCF, HciBleEnergyInfo);
+  SET_HANDLER(HCI_BLE_EXTENDED_SCAN_PARAMS_OCF, HciBleExtendedScanParams);
+#undef SET_HANDLER
+
+#define SET_TEST_HANDLER(command_name, method)  \
+  active_test_channel_commands_[command_name] = \
+      [this](const vector<std::string>& param) { method(param); };
+  SET_TEST_HANDLER("CLEAR", TestChannelClear);
+  SET_TEST_HANDLER("CLEAR_EVENT_DELAY", TestChannelClearEventDelay);
+  SET_TEST_HANDLER("DISCOVER", TestChannelDiscover);
+  SET_TEST_HANDLER("SET_EVENT_DELAY", TestChannelSetEventDelay);
+  SET_TEST_HANDLER("TIMEOUT_ALL", TestChannelTimeoutAll);
+#undef SET_TEST_HANDLER
+}
+
+void DualModeController::RegisterTaskScheduler(
+    std::function<AsyncTaskId(std::chrono::milliseconds, const TaskCallback&)>
+        oneshotScheduler) {
+  schedule_task_ = oneshotScheduler;
+}
+
+void DualModeController::RegisterPeriodicTaskScheduler(
+    std::function<AsyncTaskId(std::chrono::milliseconds,
+                              std::chrono::milliseconds, const TaskCallback&)>
+        periodicScheduler) {
+  schedule_periodic_task_ = periodicScheduler;
+}
+
+void DualModeController::RegisterTaskCancel(
+    std::function<void(AsyncTaskId)> task_cancel) {
+  cancel_task_ = task_cancel;
+}
+
+void DualModeController::HandleTestChannelCommand(
+    const std::string& name, const vector<std::string>& args) {
+  if (active_test_channel_commands_.count(name) == 0) return;
+  active_test_channel_commands_[name](args);
+}
+
+void DualModeController::HandleCommand(
+    std::unique_ptr<CommandPacket> command_packet) {
+  uint16_t opcode = command_packet->GetOpcode();
+  LOG_INFO(LOG_TAG, "Command opcode: 0x%04X, OGF: 0x%04X, OCF: 0x%04X", opcode,
+           command_packet->GetOGF(), command_packet->GetOCF());
+
+  // The command hasn't been registered with the handler yet. There is nothing
+  // to do.
+  if (active_hci_commands_.count(opcode) == 0)
+    return;
+  else if (test_channel_state_ == kTimeoutAll)
+    return;
+  active_hci_commands_[opcode](command_packet->GetPayload());
+}
+
+void DualModeController::RegisterEventChannel(
+    const std::function<void(std::unique_ptr<EventPacket>)>& callback) {
+  send_event_ = callback;
+}
+
+void DualModeController::HandleTimerTick() {
+  // PageScan();
+  if (le_scan_enable_) LOG_ERROR(LOG_TAG, "LE scan");
+  // LeScan();
+}
+
+void DualModeController::SetTimerPeriod(std::chrono::milliseconds new_period) {
+  timer_period_ = new_period;
+
+  if (timer_tick_task_ == kInvalidTaskId) return;
+
+  // Restart the timer with the new period
+  StopTimer();
+  StartTimer();
+}
+
+void DualModeController::StartTimer() {
+  LOG_ERROR(LOG_TAG, "StartTimer");
+  timer_tick_task_ = schedule_periodic_task_(
+      std::chrono::milliseconds(0), timer_period_,
+      [this]() { DualModeController::HandleTimerTick(); });
+}
+
+void DualModeController::StopTimer() {
+  LOG_ERROR(LOG_TAG, "StopTimer");
+  cancel_task_(timer_tick_task_);
+  timer_tick_task_ = kInvalidTaskId;
+}
+
+void DualModeController::TestChannelClear(
+    UNUSED_ATTR const vector<std::string>& args) {
+  LogCommand("TestChannel Clear");
+  test_channel_state_ = kNone;
+}
+
+void DualModeController::TestChannelDiscover(
+    UNUSED_ATTR const vector<std::string>& args) {
+  LogCommand("TestChannel Discover");
+  /* TODO: Replace with adding devices */
+  /*
+
+    for (size_t i = 0; i < args.size() - 1; i += 2)
+      SendExtendedInquiryResult(args[i], args[i + 1]);
+  */
+}
+
+void DualModeController::TestChannelTimeoutAll(
+    UNUSED_ATTR const vector<std::string>& args) {
+  LogCommand("TestChannel Timeout All");
+  test_channel_state_ = kTimeoutAll;
+}
+
+void DualModeController::TestChannelSetEventDelay(
+    const vector<std::string>& args UNUSED_ATTR) {
+  LogCommand("TestChannel Set Event Delay");
+  test_channel_state_ = kDelayedResponse;
+}
+
+void DualModeController::TestChannelClearEventDelay(
+    UNUSED_ATTR const vector<std::string>& args) {
+  LogCommand("TestChannel Clear Event Delay");
+  test_channel_state_ = kNone;
+}
+
+void DualModeController::HciReset(UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Reset");
+  state_ = kStandby;
+  if (timer_tick_task_ != kInvalidTaskId) {
+    LOG_INFO(LOG_TAG, "The timer was already running!");
+    StopTimer();
+  }
+  LOG_INFO(LOG_TAG, "Starting timer.");
+  StartTimer();
+
+  SendCommandCompleteSuccess(HCI_RESET);
+}
+
+void DualModeController::HciReadBufferSize(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Read Buffer Size");
+  std::unique_ptr<EventPacket> command_complete =
+      EventPacket::CreateCommandCompleteReadBufferSize(
+          kSuccessStatus, properties_.GetAclDataPacketSize(),
+          properties_.GetSynchronousDataPacketSize(),
+          properties_.GetTotalNumAclDataPackets(),
+          properties_.GetTotalNumSynchronousDataPackets());
+
+  send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciHostBufferSize(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Host Buffer Size");
+  SendCommandCompleteSuccess(HCI_HOST_BUFFER_SIZE);
+}
+
+void DualModeController::HciReadLocalVersionInformation(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Read Local Version Information");
+  std::unique_ptr<EventPacket> command_complete =
+      EventPacket::CreateCommandCompleteReadLocalVersionInformation(
+          kSuccessStatus, properties_.GetVersion(), properties_.GetRevision(),
+          properties_.GetLmpPalVersion(), properties_.GetManufacturerName(),
+          properties_.GetLmpPalSubversion());
+  send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciReadBdAddr(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  std::unique_ptr<EventPacket> command_complete =
+      EventPacket::CreateCommandCompleteReadBdAddr(kSuccessStatus,
+                                                   properties_.GetAddress());
+  send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciReadLocalSupportedCommands(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Read Local Supported Commands");
+  std::unique_ptr<EventPacket> command_complete =
+      EventPacket::CreateCommandCompleteReadLocalSupportedCommands(
+          kSuccessStatus, properties_.GetLocalSupportedCommands());
+  send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciReadLocalSupportedCodecs(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Read Local Supported Codecs");
+  std::unique_ptr<EventPacket> command_complete =
+      EventPacket::CreateCommandCompleteReadLocalSupportedCodecs(
+          kSuccessStatus, properties_.GetSupportedCodecs(),
+          properties_.GetVendorSpecificCodecs());
+  send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciReadLocalExtendedFeatures(
+    const vector<uint8_t>& args) {
+  LogCommand("Read Local Extended Features");
+  CHECK(args.size() == 2);
+  std::unique_ptr<EventPacket> command_complete =
+      EventPacket::CreateCommandCompleteReadLocalExtendedFeatures(
+          kSuccessStatus, args[1],
+          properties_.GetLocalExtendedFeaturesMaximumPageNumber(),
+          properties_.GetLocalExtendedFeatures(args[1]));
+  send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciWriteSimplePairingMode(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Write Simple Pairing Mode");
+  SendCommandCompleteSuccess(HCI_WRITE_SIMPLE_PAIRING_MODE);
+}
+
+void DualModeController::HciWriteLeHostSupport(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Write Le Host Support");
+  SendCommandCompleteSuccess(HCI_WRITE_LE_HOST_SUPPORT);
+}
+
+void DualModeController::HciSetEventMask(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Set Event Mask");
+  SendCommandCompleteSuccess(HCI_SET_EVENT_MASK);
+}
+
+void DualModeController::HciWriteInquiryMode(const vector<uint8_t>& args) {
+  LogCommand("Write Inquiry Mode");
+  CHECK(args.size() == 2);
+  inquiry_mode_ = args[1];
+  SendCommandCompleteSuccess(HCI_WRITE_INQUIRY_MODE);
+}
+
+void DualModeController::HciWritePageScanType(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Write Page Scan Type");
+  SendCommandCompleteSuccess(HCI_WRITE_PAGESCAN_TYPE);
+}
+
+void DualModeController::HciWriteInquiryScanType(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Write Inquiry Scan Type");
+  SendCommandCompleteSuccess(HCI_WRITE_INQSCAN_TYPE);
+}
+
+void DualModeController::HciWriteClassOfDevice(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Write Class Of Device");
+  SendCommandCompleteSuccess(HCI_WRITE_CLASS_OF_DEVICE);
+}
+
+void DualModeController::HciWritePageTimeout(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Write Page Timeout");
+  SendCommandCompleteSuccess(HCI_WRITE_PAGE_TOUT);
+}
+
+void DualModeController::HciWriteDefaultLinkPolicySettings(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Write Default Link Policy Settings");
+  SendCommandCompleteSuccess(HCI_WRITE_DEF_POLICY_SETTINGS);
+}
+
+void DualModeController::HciReadLocalName(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Get Local Name");
+  std::unique_ptr<EventPacket> command_complete =
+      EventPacket::CreateCommandCompleteReadLocalName(
+          kSuccessStatus, properties_.GetLocalName());
+  send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciWriteLocalName(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Write Local Name");
+  SendCommandCompleteSuccess(HCI_CHANGE_LOCAL_NAME);
+}
+
+void DualModeController::HciWriteExtendedInquiryResponse(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Write Extended Inquiry Response");
+  SendCommandCompleteSuccess(HCI_WRITE_EXT_INQ_RESPONSE);
+}
+
+void DualModeController::HciWriteVoiceSetting(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Write Voice Setting");
+  SendCommandCompleteSuccess(HCI_WRITE_VOICE_SETTINGS);
+}
+
+void DualModeController::HciWriteCurrentIacLap(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Write Current IAC LAP");
+  SendCommandCompleteSuccess(HCI_WRITE_CURRENT_IAC_LAP);
+}
+
+void DualModeController::HciWriteInquiryScanActivity(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Write Inquiry Scan Activity");
+  SendCommandCompleteSuccess(HCI_WRITE_INQUIRYSCAN_CFG);
+}
+
+void DualModeController::HciWriteScanEnable(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Write Scan Enable");
+  SendCommandCompleteSuccess(HCI_WRITE_SCAN_ENABLE);
+}
+
+void DualModeController::HciSetEventFilter(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Set Event Filter");
+  SendCommandCompleteSuccess(HCI_SET_EVENT_FILTER);
+}
+
+void DualModeController::HciInquiry(const vector<uint8_t>& args) {
+  // Fake inquiry response for a fake device.
+  const EventPacket::PageScanRepetitionMode kPageScanRepetitionMode =
+      EventPacket::kR0;
+  const uint32_t kClassOfDevice = 0x030201;
+  const uint16_t kClockOffset = 513;
+  BtAddress other_addr;
+  other_addr.FromVector(kOtherDeviceBdAddress);
+
+  LogCommand("Inquiry");
+  state_ = kInquiry;
+  SendCommandStatusSuccess(HCI_INQUIRY);
+  switch (inquiry_mode_) {
+    case (kStandardInquiry): {
+      std::unique_ptr<EventPacket> inquiry_result_evt =
+          EventPacket::CreateInquiryResultEvent(other_addr,
+                                                kPageScanRepetitionMode,
+                                                kClassOfDevice, kClockOffset);
+      send_event_(std::move(inquiry_result_evt));
+      /* TODO: Return responses from modeled devices */
+    } break;
+
+    case (kRssiInquiry):
+      LOG_INFO(LOG_TAG, "RSSI Inquiry Mode currently not supported.");
+      break;
+
+    case (kExtendedOrRssiInquiry): {
+      const std::string name = "Foobar";
+      vector<uint8_t> extended_inquiry_data = {
+          static_cast<uint8_t>(name.length() + 1), 0x09};
+
+      for (size_t i = 0; i < name.length(); i++)
+        extended_inquiry_data.push_back(name[i]);
+      extended_inquiry_data.push_back('\0');
+
+      uint8_t rssi = static_cast<uint8_t>(-20);
+      send_event_(EventPacket::CreateExtendedInquiryResultEvent(
+          other_addr, kPageScanRepetitionMode, kClassOfDevice, kClockOffset,
+          rssi, extended_inquiry_data));
+      /* TODO: Return responses from modeled devices */
+    } break;
+  }
+  AddControllerEvent(std::chrono::milliseconds(args[4] * 1280),
+                     [this]() { DualModeController::InquiryTimeout(); });
+}
+
+void DualModeController::HciInquiryCancel(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Inquiry Cancel");
+  CHECK(state_ == kInquiry);
+  state_ = kStandby;
+  SendCommandCompleteSuccess(HCI_INQUIRY_CANCEL);
+}
+
+void DualModeController::InquiryTimeout() {
+  LOG_INFO(LOG_TAG, "InquiryTimer fired");
+  if (state_ == kInquiry) {
+    state_ = kStandby;
+    send_event_(EventPacket::CreateInquiryCompleteEvent(kSuccessStatus));
+  }
+}
+
+void DualModeController::HciDeleteStoredLinkKey(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Delete Stored Link Key");
+  /* Check the last octect in |args|. If it is 0, delete only the link key for
+   * the given BD_ADDR. If is is 1, delete all stored link keys. */
+  SendCommandCompleteOnlyStatus(HCI_INQUIRY_CANCEL, kUnknownHciCommand);
+}
+
+void DualModeController::HciRemoteNameRequest(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("Remote Name Request");
+  SendCommandStatusSuccess(HCI_RMT_NAME_REQUEST);
+}
+
+void DualModeController::HciLeSetEventMask(const vector<uint8_t>& args) {
+  LogCommand("LE SetEventMask");
+  le_event_mask_ = args;
+  SendCommandCompleteSuccess(HCI_BLE_SET_EVENT_MASK);
+}
+
+void DualModeController::HciLeReadBufferSize(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  std::unique_ptr<EventPacket> command_complete =
+      EventPacket::CreateCommandCompleteLeReadBufferSize(
+          kSuccessStatus, properties_.GetLeDataPacketLength(),
+          properties_.GetTotalNumLeDataPackets());
+  send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciLeReadLocalSupportedFeatures(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  std::unique_ptr<EventPacket> command_complete =
+      EventPacket::CreateCommandCompleteLeReadLocalSupportedFeatures(
+          kSuccessStatus, properties_.GetLeLocalSupportedFeatures());
+  send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciLeSetRandomAddress(const vector<uint8_t>& args) {
+  LogCommand("LE SetRandomAddress");
+  CHECK(args.size() == 7);
+  vector<uint8_t> new_addr = {args[1], args[2], args[3],
+                              args[4], args[5], args[6]};
+  CHECK(le_random_address_.FromVector(new_addr));
+  SendCommandCompleteSuccess(HCI_BLE_WRITE_RANDOM_ADDR);
+}
+
+void DualModeController::HciLeSetAdvertisingParameters(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("LE SetAdvertisingParameters");
+  SendCommandCompleteSuccess(HCI_BLE_WRITE_ADV_PARAMS);
+}
+
+void DualModeController::HciLeSetAdvertisingData(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  LogCommand("LE SetAdvertisingData");
+  SendCommandCompleteSuccess(HCI_BLE_WRITE_ADV_DATA);
+}
+
+void DualModeController::HciLeSetScanParameters(const vector<uint8_t>& args) {
+  LogCommand("LE SetScanParameters");
+  CHECK(args.size() == 8);
+  le_scan_type_ = args[1];
+  le_scan_interval_ = args[2] | (args[3] << 8);
+  le_scan_window_ = args[4] | (args[5] << 8);
+  own_address_type_ = args[6];
+  scanning_filter_policy_ = args[7];
+  SendCommandCompleteSuccess(HCI_BLE_WRITE_SCAN_PARAMS);
+}
+
+void DualModeController::HciLeSetScanEnable(const vector<uint8_t>& args) {
+  LogCommand("LE SetScanEnable");
+  CHECK(args.size() == 3);
+  CHECK(args[0] == 2);
+  le_scan_enable_ = args[1];
+  filter_duplicates_ = args[2];
+  SendCommandCompleteSuccess(HCI_BLE_WRITE_SCAN_ENABLE);
+}
+
+void DualModeController::HciLeReadWhiteListSize(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  std::unique_ptr<EventPacket> command_complete =
+      EventPacket::CreateCommandCompleteLeReadWhiteListSize(
+          kSuccessStatus, properties_.GetLeWhiteListSize());
+  send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciLeRand(UNUSED_ATTR const vector<uint8_t>& args) {
+  uint64_t random_val = rand();
+  std::unique_ptr<EventPacket> command_complete =
+      EventPacket::CreateCommandCompleteLeRand(kSuccessStatus, random_val);
+  send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciLeReadSupportedStates(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  std::unique_ptr<EventPacket> command_complete =
+      EventPacket::CreateCommandCompleteLeReadSupportedStates(
+          kSuccessStatus, properties_.GetLeSupportedStates());
+  send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciBleVendorSleepMode(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  SendCommandCompleteOnlyStatus(HCI_GRP_VENDOR_SPECIFIC | 0x27,
+                                kUnknownHciCommand);
+}
+
+void DualModeController::HciBleVendorCap(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  std::unique_ptr<EventPacket> command_complete =
+      EventPacket::CreateCommandCompleteLeVendorCap(
+          kSuccessStatus, properties_.GetLeVendorCap());
+  send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciBleVendorMultiAdv(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  SendCommandCompleteOnlyStatus(HCI_BLE_MULTI_ADV_OCF, kUnknownHciCommand);
+}
+
+void DualModeController::HciBleVendor155(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  SendCommandCompleteOnlyStatus(HCI_GRP_VENDOR_SPECIFIC | 0x155,
+                                kUnknownHciCommand);
+}
+
+void DualModeController::HciBleVendor157(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  SendCommandCompleteOnlyStatus(HCI_GRP_VENDOR_SPECIFIC | 0x157,
+                                kUnknownHciCommand);
+}
+
+void DualModeController::HciBleEnergyInfo(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  SendCommandCompleteOnlyStatus(HCI_BLE_ENERGY_INFO_OCF, kUnknownHciCommand);
+}
+
+void DualModeController::HciBleExtendedScanParams(
+    UNUSED_ATTR const vector<uint8_t>& args) {
+  SendCommandCompleteOnlyStatus(HCI_BLE_EXTENDED_SCAN_PARAMS_OCF,
+                                kUnknownHciCommand);
+}
+
+DualModeController::Properties::Properties(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_(4),
+      revision_(1),
+      lmp_pal_version_(0),
+      manufacturer_name_(0),
+      lmp_pal_subversion_(0),
+      le_data_packet_length_(27),
+      num_le_data_packets_(15),
+      le_white_list_size_(15) {
+  std::string properties_raw;
+
+  local_extended_features_ = {0xffffffffffffffff, 0x7};
+
+  CHECK(address_.FromString("01:02:03:04:05:06"));
+  local_name_ = "DefaultName";
+
+  supported_codecs_ = {1};
+  vendor_specific_codecs_ = {};
+
+  for (int i = 0; i < 64; i++) local_supported_commands_.push_back(0xff);
+
+  le_supported_features_ = 0x1f;
+  le_supported_states_ = 0x3ffffffffff;
+  le_vendor_cap_ = {0x05, 0x01, 0x00, 0x04, 0x80, 0x01, 0x10,
+                    0x01, 0x60, 0x00, 0x0a, 0x00, 0x01, 0x01};
+
+  LOG_INFO(LOG_TAG, "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.");
+    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.");
+
+  // Get the underlying base::Value object, which is of type
+  // base::Value::TYPE_DICTIONARY, and read it into member variables.
+  base::Value& properties_dictionary = *(properties_value_ptr.get());
+  base::JSONValueConverter<DualModeController::Properties> converter;
+
+  if (!converter.Convert(properties_dictionary, this))
+    LOG_INFO(LOG_TAG,
+             "Error converting JSON properties into Properties object.");
+}
+
+// static
+void DualModeController::Properties::RegisterJSONConverter(
+    base::JSONValueConverter<DualModeController::Properties>* converter) {
+// TODO(dennischeng): Use RegisterIntField() here?
+#define REGISTER_UINT8_T(field_name, field) \
+  converter->RegisterCustomField<uint8_t>(  \
+      field_name, &DualModeController::Properties::field, &ParseUint8t);
+#define REGISTER_UINT16_T(field_name, field) \
+  converter->RegisterCustomField<uint16_t>(  \
+      field_name, &DualModeController::Properties::field, &ParseUint16t);
+  REGISTER_UINT16_T("AclDataPacketSize", acl_data_packet_size_);
+  REGISTER_UINT8_T("ScoDataPacketSize", sco_data_packet_size_);
+  REGISTER_UINT16_T("NumAclDataPackets", num_acl_data_packets_);
+  REGISTER_UINT16_T("NumScoDataPackets", num_sco_data_packets_);
+  REGISTER_UINT8_T("Version", version_);
+  REGISTER_UINT16_T("Revision", revision_);
+  REGISTER_UINT8_T("LmpPalVersion", lmp_pal_version_);
+  REGISTER_UINT16_T("ManufacturerName", manufacturer_name_);
+  REGISTER_UINT16_T("LmpPalSubversion", lmp_pal_subversion_);
+#undef REGISTER_UINT8_T
+#undef REGISTER_UINT16_T
+}
+
+}  // namespace test_vendor_lib
diff --git a/bt/vendor_libs/test_vendor_lib/src/event_packet.cc b/bt/vendor_libs/test_vendor_lib/src/event_packet.cc
new file mode 100644
index 0000000..98802b0
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/src/event_packet.cc
@@ -0,0 +1,329 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 "event_packet"
+
+#include "event_packet.h"
+
+#include "osi/include/log.h"
+#include "stack/include/hcidefs.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+EventPacket::EventPacket(uint8_t event_code)
+    : Packet(DATA_TYPE_EVENT, {event_code}) {}
+
+uint8_t EventPacket::GetEventCode() const { return GetHeader()[0]; }
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.1
+std::unique_ptr<EventPacket> EventPacket::CreateInquiryCompleteEvent(
+    uint8_t status) {
+  std::unique_ptr<EventPacket> evt_ptr =
+      std::unique_ptr<EventPacket>(new EventPacket(HCI_INQUIRY_COMP_EVT));
+  CHECK(evt_ptr->AddPayloadOctets1(status));
+
+  return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.14
+std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteEvent(
+    uint16_t command_opcode, const vector<uint8_t>& event_return_parameters) {
+  std::unique_ptr<EventPacket> evt_ptr =
+      std::unique_ptr<EventPacket>(new EventPacket(HCI_COMMAND_COMPLETE_EVT));
+
+  CHECK(evt_ptr->AddPayloadOctets1(1));  // num_hci_command_packets
+  CHECK(evt_ptr->AddPayloadOctets2(command_opcode));
+  CHECK(evt_ptr->AddPayloadOctets(event_return_parameters.size(),
+                                  event_return_parameters));
+
+  return evt_ptr;
+}
+
+std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteOnlyStatusEvent(
+    uint16_t command_opcode, uint8_t status) {
+  std::unique_ptr<EventPacket> evt_ptr =
+      std::unique_ptr<EventPacket>(new EventPacket(HCI_COMMAND_COMPLETE_EVT));
+
+  CHECK(evt_ptr->AddPayloadOctets1(1));  // num_hci_command_packets
+  CHECK(evt_ptr->AddPayloadOctets2(command_opcode));
+  CHECK(evt_ptr->AddPayloadOctets1(status));
+
+  return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.15
+std::unique_ptr<EventPacket> EventPacket::CreateCommandStatusEvent(
+    uint8_t status, uint16_t command_opcode) {
+  std::unique_ptr<EventPacket> evt_ptr =
+      std::unique_ptr<EventPacket>(new EventPacket(HCI_COMMAND_STATUS_EVT));
+
+  CHECK(evt_ptr->AddPayloadOctets1(status));
+  CHECK(evt_ptr->AddPayloadOctets1(1));  // num_hci_command_packets
+  CHECK(evt_ptr->AddPayloadOctets2(command_opcode));
+
+  return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.12
+std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteReadLocalName(
+    uint8_t status, const std::string& local_name) {
+  std::unique_ptr<EventPacket> evt_ptr =
+      EventPacket::CreateCommandCompleteOnlyStatusEvent(HCI_READ_LOCAL_NAME,
+                                                        status);
+
+  for (size_t i = 0; i < local_name.length(); i++)
+    CHECK(evt_ptr->AddPayloadOctets1(local_name[i]));
+  CHECK(evt_ptr->AddPayloadOctets1(0));  // Null terminated
+  for (size_t i = 0; i < 248 - local_name.length() - 1; i++)
+    CHECK(evt_ptr->AddPayloadOctets1(0xFF));
+
+  return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.1
+std::unique_ptr<EventPacket>
+EventPacket::CreateCommandCompleteReadLocalVersionInformation(
+    uint8_t 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<EventPacket> evt_ptr =
+      EventPacket::CreateCommandCompleteOnlyStatusEvent(
+          HCI_READ_LOCAL_VERSION_INFO, 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;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.2
+std::unique_ptr<EventPacket>
+EventPacket::CreateCommandCompleteReadLocalSupportedCommands(
+    uint8_t status, const vector<uint8_t>& supported_commands) {
+  std::unique_ptr<EventPacket> evt_ptr =
+      EventPacket::CreateCommandCompleteOnlyStatusEvent(
+          HCI_READ_LOCAL_SUPPORTED_CMDS, 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<EventPacket>
+EventPacket::CreateCommandCompleteReadLocalExtendedFeatures(
+    uint8_t status, uint8_t page_number, uint8_t maximum_page_number,
+    uint64_t extended_lmp_features) {
+  std::unique_ptr<EventPacket> evt_ptr =
+      EventPacket::CreateCommandCompleteOnlyStatusEvent(
+          HCI_READ_LOCAL_EXT_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;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.5
+std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteReadBufferSize(
+    uint8_t 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<EventPacket> evt_ptr =
+      EventPacket::CreateCommandCompleteOnlyStatusEvent(HCI_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<EventPacket> EventPacket::CreateCommandCompleteReadBdAddr(
+    uint8_t status, const BtAddress& address) {
+  std::unique_ptr<EventPacket> evt_ptr =
+      EventPacket::CreateCommandCompleteOnlyStatusEvent(HCI_READ_BD_ADDR,
+                                                        status);
+
+  CHECK(evt_ptr->AddPayloadBtAddress(address));
+
+  return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.8
+std::unique_ptr<EventPacket>
+EventPacket::CreateCommandCompleteReadLocalSupportedCodecs(
+    uint8_t status, const vector<uint8_t>& supported_codecs,
+    const vector<uint32_t>& vendor_specific_codecs) {
+  std::unique_ptr<EventPacket> evt_ptr =
+      EventPacket::CreateCommandCompleteOnlyStatusEvent(
+          HCI_READ_LOCAL_SUPPORTED_CODECS, status);
+
+  CHECK(evt_ptr->AddPayloadOctets(supported_codecs.size(), supported_codecs));
+  for (size_t i = 0; i < vendor_specific_codecs.size(); i++)
+    CHECK(evt_ptr->AddPayloadOctets4(vendor_specific_codecs[i]));
+
+  return evt_ptr;
+}
+
+std::unique_ptr<EventPacket> EventPacket::CreateInquiryResultEvent(
+    const BtAddress& address,
+    const PageScanRepetitionMode page_scan_repetition_mode,
+    uint32_t class_of_device, uint16_t clock_offset) {
+  std::unique_ptr<EventPacket> evt_ptr =
+      std::unique_ptr<EventPacket>(new EventPacket(HCI_INQUIRY_RESULT_EVT));
+
+  CHECK(evt_ptr->AddPayloadOctets1(1));  // Start with a single response
+
+  CHECK(evt_ptr->AddPayloadBtAddress(address));
+  CHECK(evt_ptr->AddPayloadOctets1(page_scan_repetition_mode));
+  CHECK(evt_ptr->AddPayloadOctets2(kReservedZero));
+  CHECK(evt_ptr->AddPayloadOctets3(class_of_device));
+  CHECK(!(clock_offset & 0x8000));
+  CHECK(evt_ptr->AddPayloadOctets2(clock_offset));
+
+  return evt_ptr;
+}
+
+void EventPacket::AddInquiryResult(
+    const BtAddress& address,
+    const PageScanRepetitionMode page_scan_repetition_mode,
+    uint32_t class_of_device, uint16_t clock_offset) {
+  CHECK(GetEventCode() == HCI_INQUIRY_RESULT_EVT);
+
+  CHECK(IncrementPayloadCounter(1));  // Increment the number of responses
+
+  CHECK(AddPayloadBtAddress(address));
+  CHECK(AddPayloadOctets1(page_scan_repetition_mode));
+  CHECK(AddPayloadOctets2(kReservedZero));
+  CHECK(AddPayloadOctets3(class_of_device));
+  CHECK(!(clock_offset & 0x8000));
+  CHECK(AddPayloadOctets2(clock_offset));
+}
+
+std::unique_ptr<EventPacket> EventPacket::CreateExtendedInquiryResultEvent(
+    const BtAddress& address,
+    const PageScanRepetitionMode page_scan_repetition_mode,
+    uint32_t class_of_device, uint16_t clock_offset, uint8_t rssi,
+    const vector<uint8_t>& extended_inquiry_response) {
+  std::unique_ptr<EventPacket> evt_ptr = std::unique_ptr<EventPacket>(
+      new EventPacket(HCI_EXTENDED_INQUIRY_RESULT_EVT));
+
+  CHECK(evt_ptr->AddPayloadOctets1(1));  // Always contains a single response
+
+  CHECK(evt_ptr->AddPayloadBtAddress(address));
+  CHECK(evt_ptr->AddPayloadOctets1(page_scan_repetition_mode));
+  CHECK(evt_ptr->AddPayloadOctets1(kReservedZero));
+  CHECK(evt_ptr->AddPayloadOctets3(class_of_device));
+  CHECK(!(clock_offset & 0x8000));
+  CHECK(evt_ptr->AddPayloadOctets2(clock_offset));
+  CHECK(evt_ptr->AddPayloadOctets1(rssi));
+  CHECK(evt_ptr->AddPayloadOctets(extended_inquiry_response.size(),
+                                  extended_inquiry_response));
+  while (evt_ptr->AddPayloadOctets1(0xff))
+    ;  // Fill packet
+  return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.2
+std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteLeReadBufferSize(
+    uint8_t status, uint16_t hc_le_data_packet_length,
+    uint8_t hc_total_num_le_data_packets) {
+  std::unique_ptr<EventPacket> evt_ptr =
+      EventPacket::CreateCommandCompleteOnlyStatusEvent(
+          HCI_BLE_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<EventPacket>
+EventPacket::CreateCommandCompleteLeReadLocalSupportedFeatures(
+    uint8_t status, uint64_t le_features) {
+  std::unique_ptr<EventPacket> evt_ptr =
+      EventPacket::CreateCommandCompleteOnlyStatusEvent(
+          HCI_BLE_READ_LOCAL_SPT_FEAT, status);
+
+  CHECK(evt_ptr->AddPayloadOctets1(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<EventPacket>
+EventPacket::CreateCommandCompleteLeReadWhiteListSize(uint8_t status,
+                                                      uint8_t white_list_size) {
+  std::unique_ptr<EventPacket> evt_ptr =
+      EventPacket::CreateCommandCompleteOnlyStatusEvent(
+          HCI_BLE_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<EventPacket> EventPacket::CreateCommandCompleteLeRand(
+    uint8_t status, uint64_t random_val) {
+  std::unique_ptr<EventPacket> evt_ptr =
+      EventPacket::CreateCommandCompleteOnlyStatusEvent(HCI_BLE_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<EventPacket>
+EventPacket::CreateCommandCompleteLeReadSupportedStates(uint8_t status,
+                                                        uint64_t le_states) {
+  std::unique_ptr<EventPacket> evt_ptr =
+      EventPacket::CreateCommandCompleteOnlyStatusEvent(
+          HCI_BLE_READ_SUPPORTED_STATES, status);
+
+  CHECK(evt_ptr->AddPayloadOctets8(le_states));
+
+  return evt_ptr;
+}
+
+// Vendor-specific commands (see hcidefs.h)
+
+std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteLeVendorCap(
+    uint8_t status, const vector<uint8_t>& vendor_cap) {
+  std::unique_ptr<EventPacket> evt_ptr =
+      EventPacket::CreateCommandCompleteOnlyStatusEvent(HCI_BLE_VENDOR_CAP_OCF,
+                                                        status);
+
+  CHECK(evt_ptr->AddPayloadOctets(vendor_cap.size(), vendor_cap));
+
+  return evt_ptr;
+}
+
+}  // namespace test_vendor_lib
diff --git a/bt/vendor_libs/test_vendor_lib/src/hci_transport.cc b/bt/vendor_libs/test_vendor_lib/src/hci_transport.cc
new file mode 100644
index 0000000..92bf7a5
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/src/hci_transport.cc
@@ -0,0 +1,87 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 "hci_transport"
+
+#include "hci_transport.h"
+
+#include <assert.h>
+#include <sys/socket.h>
+
+#include "osi/include/log.h"
+#include "stack/include/hcidefs.h"
+
+namespace test_vendor_lib {
+
+HciTransport::HciTransport() = default;
+
+void HciTransport::CloseHciFd() { hci_fd_.reset(nullptr); }
+
+void HciTransport::CloseVendorFd() { vendor_fd_.reset(nullptr); }
+
+int HciTransport::GetHciFd() const { return hci_fd_->get(); }
+
+int HciTransport::GetVendorFd() const { return vendor_fd_->get(); }
+
+bool HciTransport::SetUp() {
+  int socketpair_fds[2];
+
+  const int success = socketpair(AF_LOCAL, SOCK_STREAM, 0, socketpair_fds);
+  if (success < 0) return false;
+  hci_fd_.reset(new base::ScopedFD(socketpair_fds[0]));
+  vendor_fd_.reset(new base::ScopedFD(socketpair_fds[1]));
+  return true;
+}
+
+void HciTransport::OnCommandReady(int fd) {
+  CHECK(fd == GetVendorFd());
+  LOG_VERBOSE(LOG_TAG, "Command ready in HciTransport on fd: %d.", fd);
+
+  const serial_data_type_t packet_type = packet_stream_.ReceivePacketType(fd);
+  switch (packet_type) {
+    case (DATA_TYPE_COMMAND): {
+      command_handler_(packet_stream_.ReceiveCommand(fd));
+      break;
+    }
+
+    case (DATA_TYPE_ACL): {
+      LOG_ERROR(LOG_TAG, "ACL data packets not currently supported.");
+      break;
+    }
+
+    case (DATA_TYPE_SCO): {
+      LOG_ERROR(LOG_TAG, "SCO data packets not currently supported.");
+      break;
+    }
+
+    default: {
+      LOG_ERROR(LOG_TAG, "Error received an invalid packet type from the HCI.");
+      assert(packet_type == DATA_TYPE_COMMAND);
+      break;
+    }
+  }
+}
+
+void HciTransport::RegisterCommandHandler(
+    const std::function<void(std::unique_ptr<CommandPacket>)>& callback) {
+  command_handler_ = callback;
+}
+
+void HciTransport::SendEvent(std::unique_ptr<EventPacket> event) {
+  packet_stream_.SendEvent(std::move(event), GetVendorFd());
+}
+
+}  // namespace test_vendor_lib
diff --git a/bt/vendor_libs/test_vendor_lib/src/packet.cc b/bt/vendor_libs/test_vendor_lib/src/packet.cc
new file mode 100644
index 0000000..2972ada
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/src/packet.cc
@@ -0,0 +1,108 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 "packet"
+
+#include "packet.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "osi/include/log.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+Packet::Packet(serial_data_type_t type, vector<uint8_t> header)
+    : type_(type), header_(std::move(header)) {
+  payload_ = {0};
+}
+
+bool Packet::AddPayloadOctets(size_t octets, const vector<uint8_t>& bytes) {
+  if (octets + payload_.size() > kMaxPacketOctets) return false;
+
+  if (octets != bytes.size()) return false;
+
+  payload_.insert(payload_.end(), bytes.begin(), bytes.end());
+  payload_[0] = payload_.size() - 1;
+
+  return true;
+}
+
+bool Packet::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 Packet::AddPayloadBtAddress(const BtAddress& address) {
+  if (BtAddress::kOctets + payload_.size() > kMaxPacketOctets) return false;
+
+  address.ToVector(payload_);
+
+  payload_[0] = payload_.size() - 1;
+
+  return true;
+}
+
+bool Packet::IncrementPayloadCounter(size_t index) {
+  if (payload_.size() < index - 1) return false;
+
+  payload_[index]++;
+  return true;
+}
+
+bool Packet::IncrementPayloadCounter(size_t index, uint8_t max_val) {
+  if (payload_.size() < index - 1) return false;
+
+  if (payload_[index] + 1 > max_val) return false;
+
+  payload_[index]++;
+  return true;
+}
+
+const vector<uint8_t>& Packet::GetHeader() const {
+  // Every packet must have a header.
+  CHECK(GetHeaderSize() > 0);
+  return header_;
+}
+
+uint8_t Packet::GetHeaderSize() const { return header_.size(); }
+
+size_t Packet::GetPacketSize() const {
+  // Add one for the type octet.
+  return 1 + header_.size() + payload_.size();
+}
+
+const vector<uint8_t>& Packet::GetPayload() const { return payload_; }
+
+size_t Packet::GetPayloadSize() const { return payload_.size(); }
+
+serial_data_type_t Packet::GetType() const { return type_; }
+
+}  // namespace test_vendor_lib
diff --git a/bt/vendor_libs/test_vendor_lib/src/packet_stream.cc b/bt/vendor_libs/test_vendor_lib/src/packet_stream.cc
new file mode 100644
index 0000000..428afaf
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/src/packet_stream.cc
@@ -0,0 +1,129 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 "packet_stream"
+
+#include "packet_stream.h"
+
+#include "base/logging.h"
+
+#include <errno.h>
+#include <unistd.h>
+
+#include "osi/include/log.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+std::unique_ptr<CommandPacket> PacketStream::ReceiveCommand(int fd) const {
+  vector<uint8_t> header;
+  vector<uint8_t> params_size;
+  vector<uint8_t> payload;
+
+  if (!ReceiveAll(header, CommandPacket::kCommandHeaderSize, fd)) {
+    LOG_ERROR(LOG_TAG, "Error: receiving command header.");
+    return std::unique_ptr<CommandPacket>(nullptr);
+  }
+
+  if (!ReceiveAll(params_size, 1, fd)) {
+    LOG_ERROR(LOG_TAG, "Error: receiving params size.");
+    return std::unique_ptr<CommandPacket>(nullptr);
+  }
+
+  if (!ReceiveAll(payload, params_size[0], fd)) {
+    LOG_ERROR(LOG_TAG, "Error: receiving command payload.");
+    return std::unique_ptr<CommandPacket>(nullptr);
+  }
+  return std::unique_ptr<CommandPacket>(new CommandPacket(header, payload));
+}
+
+serial_data_type_t PacketStream::ReceivePacketType(int fd) const {
+  vector<uint8_t> raw_type_octet;
+
+  if (!ReceiveAll(raw_type_octet, 1, fd)) {
+    // TODO(dennischeng): Proper error handling.
+    LOG_ERROR(LOG_TAG, "Error: Could not receive packet type.");
+  }
+
+  // Check that the type octet received is in the valid range, i.e. the packet
+  // must be a command or data packet.
+  const serial_data_type_t type =
+      static_cast<serial_data_type_t>(raw_type_octet[0]);
+  if (!ValidateTypeOctet(type)) {
+    // TODO(dennischeng): Proper error handling.
+    LOG_ERROR(LOG_TAG, "Error: Received invalid packet type.");
+  }
+  return type;
+}
+
+bool PacketStream::SendEvent(std::unique_ptr<EventPacket> event, int fd) const {
+  if (event->GetPayload()[0] != event->GetPayloadSize() - 1)
+    LOG_WARN(LOG_TAG, "Malformed event: 0x%04X, payload size %zu, reported %u",
+             event->GetEventCode(), event->GetPacketSize(),
+             event->GetPayload()[0]);
+
+  if (!SendAll({static_cast<uint8_t>(event->GetType())}, 1, fd)) {
+    LOG_ERROR(LOG_TAG, "Error: Could not send event type.");
+    return false;
+  }
+
+  if (!SendAll(event->GetHeader(), event->GetHeaderSize(), fd)) {
+    LOG_ERROR(LOG_TAG, "Error: Could not send event header.");
+    return false;
+  }
+
+  if (!SendAll(event->GetPayload(), event->GetPayloadSize(), fd)) {
+    LOG_ERROR(LOG_TAG, "Error: Could not send event payload.");
+    return false;
+  }
+  return true;
+}
+
+bool PacketStream::ValidateTypeOctet(serial_data_type_t type) const {
+  // The only types of packets that should be received from the HCI are command
+  // packets and data packets.
+  return (type >= DATA_TYPE_COMMAND) && (type <= DATA_TYPE_SCO);
+}
+
+bool PacketStream::ReceiveAll(vector<uint8_t>& destination,
+                              size_t num_octets_to_receive, int fd) const {
+  destination.resize(num_octets_to_receive);
+  size_t octets_remaining = num_octets_to_receive;
+  while (octets_remaining > 0) {
+    const int num_octets_received =
+        read(fd, &destination[num_octets_to_receive - octets_remaining],
+             octets_remaining);
+    if (num_octets_received < 0) return false;
+    octets_remaining -= num_octets_received;
+  }
+  return true;
+}
+
+bool PacketStream::SendAll(const vector<uint8_t>& source,
+                           size_t num_octets_to_send, int fd) const {
+  CHECK(source.size() >= num_octets_to_send);
+  size_t octets_remaining = num_octets_to_send;
+  while (octets_remaining > 0) {
+    const int num_octets_sent = write(
+        fd, &source[num_octets_to_send - octets_remaining], octets_remaining);
+    if (num_octets_sent < 0) return false;
+    octets_remaining -= num_octets_sent;
+  }
+  return true;
+}
+
+}  // namespace test_vendor_lib
diff --git a/bt/vendor_libs/test_vendor_lib/src/test_channel_transport.cc b/bt/vendor_libs/test_vendor_lib/src/test_channel_transport.cc
new file mode 100644
index 0000000..7c1963a
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/src/test_channel_transport.cc
@@ -0,0 +1,142 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 "test_channel_transport"
+
+#include "test_channel_transport.h"
+
+#include "base/logging.h"
+
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+int TestChannelTransport::SetUp(int port) {
+  struct sockaddr_in listen_address;
+  socklen_t sockaddr_in_size = sizeof(struct sockaddr_in);
+  memset(&listen_address, 0, sockaddr_in_size);
+
+  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.");
+    return -1;
+  }
+
+  LOG_INFO(LOG_TAG, "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.");
+    close(listen_fd_);
+    return -1;
+  }
+
+  if (listen(listen_fd_, 1) < 0) {
+    LOG_INFO(LOG_TAG, "Error listening for test channel.");
+    close(listen_fd_);
+    return -1;
+  }
+  return listen_fd_;
+}
+
+void TestChannelTransport::CleanUp() {
+  if (listen_fd_ == -1) {
+    return;
+  }
+  if (close(listen_fd_)) {
+    LOG_ERROR(LOG_TAG, "Error closing listen_fd_.");
+  }
+  listen_fd_ = -1;
+}
+
+int TestChannelTransport::Accept(int listen_fd_) {
+  int accept_fd = -1;
+  struct sockaddr_in test_channel_address;
+  socklen_t sockaddr_in_size = sizeof(struct sockaddr_in);
+  memset(&test_channel_address, 0, sockaddr_in_size);
+
+  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));
+
+    if (errno != EAGAIN && errno != EWOULDBLOCK) {
+      LOG_ERROR(LOG_TAG, "Closing listen_fd_ (won't try again).");
+      close(listen_fd_);
+      return -1;
+    }
+  }
+
+  LOG_INFO(LOG_TAG, "accept_fd = %d.", accept_fd);
+
+  return accept_fd;
+}
+
+void TestChannelTransport::OnCommandReady(int fd,
+                                          std::function<void(void)> unwatch) {
+  uint8_t command_name_size = 0;
+  read(fd, &command_name_size, 1);
+  vector<uint8_t> command_name_raw;
+  command_name_raw.resize(command_name_size);
+  read(fd, &command_name_raw[0], command_name_size);
+  std::string command_name(command_name_raw.begin(), command_name_raw.end());
+  LOG_INFO(LOG_TAG, "Received command from test channel: %s",
+           command_name.data());
+
+  if (command_name == "CLOSE_TEST_CHANNEL" || command_name == "") {
+    LOG_INFO(LOG_TAG, "Test channel closed");
+    unwatch();
+    close(fd);
+    return;
+  }
+
+  uint8_t num_args = 0;
+  read(fd, &num_args, 1);
+  LOG_INFO(LOG_TAG, "num_args: %d", num_args);
+  vector<std::string> args;
+  for (uint8_t i = 0; i < num_args; ++i) {
+    uint8_t arg_size = 0;
+    read(fd, &arg_size, 1);
+    vector<uint8_t> arg;
+    arg.resize(arg_size);
+    read(fd, &arg[0], arg_size);
+    args.push_back(std::string(arg.begin(), arg.end()));
+  }
+
+  for (size_t i = 0; i < args.size(); ++i)
+    LOG_INFO(LOG_TAG, "Command argument %zu: %s", i, args[i].data());
+
+  command_handler_(command_name, args);
+}
+
+void TestChannelTransport::RegisterCommandHandler(
+    const std::function<void(const std::string&, const vector<std::string>&)>&
+        callback) {
+  command_handler_ = callback;
+}
+
+}  // namespace test_vendor_lib {
diff --git a/bt/vendor_libs/test_vendor_lib/src/vendor_manager.cc b/bt/vendor_libs/test_vendor_lib/src/vendor_manager.cc
new file mode 100644
index 0000000..1651ab3
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/src/vendor_manager.cc
@@ -0,0 +1,117 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 "vendor_manager"
+
+#include "vendor_manager.h"
+
+#include "base/logging.h"
+
+#include "osi/include/log.h"
+
+#include <vector>
+
+namespace test_vendor_lib {
+
+VendorManager* g_manager = nullptr;
+
+void VendorManager::CleanUp() { test_channel_transport_.CleanUp(); }
+
+bool VendorManager::Initialize() {
+  if (!transport_.SetUp()) {
+    LOG_ERROR(LOG_TAG, "Error setting up transport object.");
+    return false;
+  }
+
+  transport_.RegisterCommandHandler(
+      [this](std::unique_ptr<CommandPacket> command) {
+        CommandPacket& cmd =
+            *command;  // only to be copied into the lambda, not a memory leak
+        async_manager_.ExecAsync(std::chrono::milliseconds(0), [this, cmd]() {
+          controller_.HandleCommand(std::unique_ptr<CommandPacket>(
+              new CommandPacket(std::move(cmd))));
+        });
+      });
+
+  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]() {
+              controller_.HandleTestChannelCommand(name, args);
+            });
+      });
+
+  controller_.RegisterEventChannel([this](std::unique_ptr<EventPacket> event) {
+    transport_.SendEvent(std::move(event));
+  });
+
+  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) {
+        return async_manager_.ExecAsyncPeriodically(delay, period, task);
+      });
+
+  controller_.RegisterTaskCancel(
+      [this](AsyncTaskId task) { async_manager_.CancelAsyncTask(task); });
+
+  if (async_manager_.WatchFdForNonBlockingReads(
+          transport_.GetVendorFd(),
+          [this](int fd) { transport_.OnCommandReady(fd); }) != 0) {
+    LOG_ERROR(LOG_TAG, "Error watching vendor fd.");
+    return true;
+  }
+
+  SetUpTestChannel(6111);
+
+  return true;
+}
+
+VendorManager::VendorManager() : test_channel_transport_() {}
+
+void VendorManager::SetUpTestChannel(int port) {
+  int socket_fd = test_channel_transport_.SetUp(port);
+
+  if (socket_fd == -1) {
+    LOG_ERROR(LOG_TAG, "Test channel SetUp(%d) failed.", port);
+    return;
+  }
+
+  LOG_INFO(LOG_TAG, "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) {
+      LOG_ERROR(LOG_TAG, "Error watching test channel fd.");
+      return;
+    }
+    LOG_INFO(LOG_TAG, "Test channel connection accepted.");
+    async_manager_.WatchFdForNonBlockingReads(conn_fd, [this](int conn_fd) {
+      test_channel_transport_.OnCommandReady(conn_fd, [this, conn_fd]() {
+        async_manager_.StopWatchingFileDescriptor(conn_fd);
+      });
+    });
+  });
+}
+
+void VendorManager::CloseHciFd() { transport_.CloseHciFd(); }
+
+int VendorManager::GetHciFd() const { return transport_.GetHciFd(); }
+
+}  // namespace test_vendor_lib
diff --git a/bt/vendor_libs/test_vendor_lib/test/async_manager_unittest.cc b/bt/vendor_libs/test_vendor_lib/test/async_manager_unittest.cc
new file mode 100644
index 0000000..90972d0
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/test/async_manager_unittest.cc
@@ -0,0 +1,148 @@
+//
+// Copyright 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "async_manager.h"
+#include <gtest/gtest.h>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace test_vendor_lib {
+
+class AsyncManagerSocketTest : public ::testing::Test {
+ public:
+  static const uint16_t kPort = 6111;
+  static const size_t kBufferSize = 16;
+
+  bool CheckBufferEquals() {
+    return strcmp(server_buffer_, client_buffer_) == 0;
+  }
+
+ protected:
+  void StartServer() {
+    struct sockaddr_in serv_addr;
+    socket_fd_ = socket(AF_INET, SOCK_STREAM, 0);
+    EXPECT_FALSE(socket_fd_ < 0);
+
+    memset(&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(kPort);
+    EXPECT_FALSE(bind(socket_fd_, (sockaddr*)&serv_addr, sizeof(serv_addr)) <
+                 0);
+
+    listen(socket_fd_, 1);
+  }
+
+  int AcceptConnection(int socket_fd_) {
+    struct sockaddr_in cli_addr;
+    memset(&cli_addr, 0, sizeof(cli_addr));
+    socklen_t clilen = sizeof(cli_addr);
+
+    int connection_fd =
+        accept(socket_fd_, (struct sockaddr*)&cli_addr, &clilen);
+    EXPECT_FALSE(connection_fd < 0);
+
+    return connection_fd;
+  }
+
+  void ReadIncomingMessage(int fd) {
+    int n = TEMP_FAILURE_RETRY(read(fd, server_buffer_, kBufferSize - 1));
+    EXPECT_FALSE(n < 0);
+
+    if (n == 0) {  // got EOF
+      async_manager_.StopWatchingFileDescriptor(fd);
+      close(fd);
+    } else {
+      n = write(fd, "1", 1);
+    }
+  }
+
+  void SetUp() override {
+    memset(server_buffer_, 0, kBufferSize);
+
+    StartServer();
+
+    async_manager_.WatchFdForNonBlockingReads(socket_fd_, [this](int fd) {
+      int connection_fd = AcceptConnection(fd);
+
+      async_manager_.WatchFdForNonBlockingReads(
+          connection_fd, [this](int fd) { ReadIncomingMessage(fd); });
+    });
+  }
+
+  void TearDown() override {
+    async_manager_.StopWatchingFileDescriptor(socket_fd_);
+    close(socket_fd_);
+    EXPECT_TRUE(CheckBufferEquals());
+  }
+
+  int ConnectClient() {
+    int socket_cli_fd = socket(AF_INET, SOCK_STREAM, 0);
+    EXPECT_FALSE(socket_cli_fd < 0);
+
+    struct hostent* server;
+    server = gethostbyname("localhost");
+    EXPECT_FALSE(server == NULL);
+
+    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 = *(reinterpret_cast<in_addr_t*>(server->h_addr));
+    serv_addr.sin_port = htons(kPort);
+
+    int result =
+        connect(socket_cli_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
+    EXPECT_FALSE(result < 0);
+
+    return socket_cli_fd;
+  }
+
+  void WriteFromClient(int socket_cli_fd) {
+    strcpy(client_buffer_, "1");
+    int n = write(socket_cli_fd, client_buffer_, strlen(client_buffer_));
+    EXPECT_TRUE(n > 0);
+  }
+
+  void AwaitServerResponse(int socket_cli_fd) {
+    int n = read(socket_cli_fd, client_buffer_, 1);
+    EXPECT_TRUE(n > 0);
+  }
+
+ private:
+  AsyncManager async_manager_;
+  int socket_fd_;
+  char server_buffer_[kBufferSize];
+  char client_buffer_[kBufferSize];
+};
+
+TEST_F(AsyncManagerSocketTest, TestOneConnection) {
+  int socket_cli_fd = ConnectClient();
+
+  WriteFromClient(socket_cli_fd);
+
+  AwaitServerResponse(socket_cli_fd);
+
+  close(socket_cli_fd);
+}
+
+}  // namespace test_vendor_lib
diff --git a/bt/vendor_libs/test_vendor_lib/test/bt_address_unittest.cc b/bt/vendor_libs/test_vendor_lib/test/bt_address_unittest.cc
new file mode 100644
index 0000000..d998179
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/test/bt_address_unittest.cc
@@ -0,0 +1,194 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2016 Google, Inc.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at:
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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 <string>
+#include <vector>
+using std::vector;
+
+#include "bt_address.h"
+
+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 kUpperMask = "ff:ff:00:00:00:00";
+const std::string kLowerMask = "00:00:ff:ff:ff:ff";
+const std::string kZeros = "00:00:00:00:00:00";
+const vector<uint8_t> kZeros_octets = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+const vector<uint8_t> kTestAddr1_octets = {0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12};
+}
+
+namespace test_vendor_lib {
+
+class BtAddressTest : public ::testing::Test {
+ public:
+  BtAddressTest() {}
+  ~BtAddressTest() {}
+};
+
+TEST_F(BtAddressTest, IsValid) {
+  EXPECT_FALSE(BtAddress::IsValid(""));
+  EXPECT_FALSE(BtAddress::IsValid("000000000000"));
+  EXPECT_FALSE(BtAddress::IsValid("00:00:00:00:0000"));
+  EXPECT_FALSE(BtAddress::IsValid("00:00:00:00:00:0"));
+  EXPECT_FALSE(BtAddress::IsValid("00:00:00:00:00:0;"));
+  EXPECT_FALSE(BtAddress::IsValid("00:00:000:00:00:0;"));
+  EXPECT_TRUE(BtAddress::IsValid("00:00:00:00:00:00"));
+  EXPECT_FALSE(BtAddress::IsValid("aB:cD:eF:Gh:iJ:Kl"));
+  EXPECT_TRUE(BtAddress::IsValid(kTestAddr1));
+  EXPECT_TRUE(BtAddress::IsValid(kTestAddr2));
+  EXPECT_TRUE(BtAddress::IsValid(kTestAddr3));
+}
+
+TEST_F(BtAddressTest, test_comparisons) {
+  BtAddress btaddr1;
+  BtAddress btaddr1_copy;
+  BtAddress btaddr2;
+
+  EXPECT_TRUE(btaddr1.FromString(kTestAddr1));
+  EXPECT_TRUE(btaddr1_copy.FromString(kTestAddr1));
+  EXPECT_TRUE(btaddr2.FromString(kTestAddr2));
+
+  EXPECT_TRUE(btaddr1 == btaddr1_copy);
+  EXPECT_FALSE(btaddr1 == btaddr2);
+
+  EXPECT_FALSE(btaddr1 != btaddr1_copy);
+  EXPECT_TRUE(btaddr1 != btaddr2);
+
+  EXPECT_FALSE(btaddr1 < btaddr1_copy);
+  EXPECT_TRUE(btaddr1 < btaddr2);
+  EXPECT_FALSE(btaddr2 < btaddr1);
+
+  EXPECT_FALSE(btaddr1 > btaddr1_copy);
+  EXPECT_FALSE(btaddr1 > btaddr2);
+  EXPECT_TRUE(btaddr2 > btaddr1);
+
+  EXPECT_TRUE(btaddr1 <= btaddr1_copy);
+  EXPECT_TRUE(btaddr1 <= btaddr2);
+  EXPECT_FALSE(btaddr2 <= btaddr1);
+
+  EXPECT_TRUE(btaddr1 >= btaddr1_copy);
+  EXPECT_FALSE(btaddr1 >= btaddr2);
+  EXPECT_TRUE(btaddr2 >= btaddr1);
+}
+
+TEST_F(BtAddressTest, test_assignment) {
+  BtAddress btaddr1;
+  BtAddress btaddr2;
+  BtAddress btaddr3;
+
+  EXPECT_TRUE(btaddr1.FromString(kTestAddr1));
+  EXPECT_TRUE(btaddr2.FromString(kTestAddr2));
+  EXPECT_TRUE(btaddr3.FromString(kTestAddr3));
+
+  EXPECT_TRUE(btaddr1 != btaddr2);
+  EXPECT_TRUE(btaddr2 != btaddr3);
+  EXPECT_TRUE(btaddr1 != btaddr3);
+
+  btaddr1 = btaddr2;
+  EXPECT_TRUE(btaddr1 == btaddr2);
+  EXPECT_TRUE(btaddr2 != btaddr3);
+  EXPECT_TRUE(btaddr1 != btaddr3);
+
+  btaddr3 = btaddr2;
+  EXPECT_TRUE(btaddr1 == btaddr2);
+  EXPECT_TRUE(btaddr2 == btaddr3);
+  EXPECT_TRUE(btaddr1 == btaddr3);
+}
+
+TEST_F(BtAddressTest, test_bitoperations) {
+  BtAddress btaddr1;
+  BtAddress btaddr2;
+  BtAddress btaddr3;
+  BtAddress btaddr_lowmask;
+  BtAddress btaddr_upmask;
+
+  EXPECT_TRUE(btaddr1.FromString(kTestAddr1));
+  EXPECT_TRUE(btaddr2.FromString(kTestAddr2));
+  EXPECT_TRUE(btaddr3.FromString(kTestAddr3));
+  EXPECT_TRUE(btaddr_lowmask.FromString(kLowerMask));
+  EXPECT_TRUE(btaddr_upmask.FromString(kUpperMask));
+
+  EXPECT_TRUE(btaddr1 != btaddr2);
+  EXPECT_TRUE(btaddr2 != btaddr3);
+  btaddr1 &= btaddr_lowmask;
+  btaddr2 &= btaddr_upmask;
+  btaddr1 |= btaddr2;
+  EXPECT_TRUE(btaddr1 == btaddr3);
+}
+
+TEST_F(BtAddressTest, FromString) {
+  BtAddress btaddrA;
+  BtAddress btaddrB;
+  BtAddress btaddrC;
+  EXPECT_TRUE(btaddrA.FromString(kTestAddr1));
+  EXPECT_TRUE(btaddrA != btaddrB);
+  EXPECT_TRUE(btaddrC == btaddrB);
+  EXPECT_TRUE(btaddrB.FromString(kTestAddr1));
+  EXPECT_TRUE(btaddrC.FromString(kTestAddr1));
+  EXPECT_TRUE(btaddrA == btaddrB);
+  EXPECT_TRUE(btaddrC == btaddrB);
+}
+
+TEST_F(BtAddressTest, FromVector) {
+  BtAddress btaddr1;
+  EXPECT_TRUE(btaddr1.FromString(kTestAddr1));
+  BtAddress btaddrA;
+  BtAddress btaddrB;
+  EXPECT_TRUE(btaddrA.FromVector(kTestAddr1_octets));
+  EXPECT_TRUE(btaddrA != btaddrB);
+  EXPECT_TRUE(btaddrB.FromVector(kTestAddr1_octets));
+  EXPECT_TRUE(btaddrA == btaddrB);
+  EXPECT_TRUE(btaddr1 == btaddrB);
+}
+
+TEST_F(BtAddressTest, ToVector) {
+  BtAddress btaddr1;
+  BtAddress btaddr1_copy;
+  BtAddress btaddr2;
+  vector<uint8_t> octets1;
+  vector<uint8_t> octets1_copy;
+  vector<uint8_t> octets2;
+  EXPECT_TRUE(btaddr1.FromString(kTestAddr1));
+  EXPECT_TRUE(btaddr1_copy.FromString(kTestAddr1));
+  EXPECT_TRUE(btaddr2.FromString(kTestAddr2));
+  EXPECT_TRUE(btaddr1 == btaddr1_copy);
+  EXPECT_TRUE(btaddr1 != btaddr2);
+  btaddr1.ToVector(octets1);
+  btaddr2.ToVector(octets2);
+  btaddr1_copy.ToVector(octets1_copy);
+  EXPECT_TRUE(octets1 != octets2);
+  EXPECT_TRUE(octets1 == octets1_copy);
+  EXPECT_TRUE(octets1.size() == BtAddress::kOctets);
+  btaddr1.ToVector(octets1);
+  EXPECT_TRUE(octets1.size() == (2 * BtAddress::kOctets));
+}
+
+TEST_F(BtAddressTest, ToString) {
+  BtAddress btaddr_zeros;
+  BtAddress btaddr1;
+  EXPECT_TRUE(btaddr_zeros.FromString(kZeros));
+  EXPECT_TRUE(btaddr1.FromString(kTestAddr1));
+  EXPECT_TRUE(btaddr_zeros.ToString() == kZeros);
+  EXPECT_TRUE(btaddr1.ToString() == kTestAddr1);
+  EXPECT_TRUE(btaddr_zeros.ToString() != kTestAddr1);
+  EXPECT_TRUE(btaddr1.ToString() != kZeros);
+}
+
+}  // namespace test_vendor_lib
diff --git a/bt/vendor_libs/test_vendor_lib/test/hci_transport_unittest.cc b/bt/vendor_libs/test_vendor_lib/test/hci_transport_unittest.cc
new file mode 100644
index 0000000..6389034
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/test/hci_transport_unittest.cc
@@ -0,0 +1,138 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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_transport.h"
+#include "command_packet.h"
+
+#include "async_manager.h"
+
+#include <condition_variable>
+#include <gtest/gtest.h>
+#include <functional>
+#include <mutex>
+#include <thread>
+
+#include "stack/include/hcidefs.h"
+
+using std::vector;
+
+namespace {
+const vector<uint8_t> stub_command({DATA_TYPE_COMMAND,
+                                    static_cast<uint8_t>(HCI_RESET),
+                                    static_cast<uint8_t>(HCI_RESET >> 8), 0});
+
+const int kMultiIterations = 10000;
+
+void WriteStubCommand(int fd) {
+  write(fd, &stub_command[0], stub_command.size());
+}
+
+}  // namespace
+
+namespace test_vendor_lib {
+
+class HciTransportTest : public ::testing::Test {
+ public:
+  HciTransportTest() : command_callback_count_(0) {
+    SetUpTransport();
+    StartThread();
+  }
+
+  ~HciTransportTest() {
+    async_manager_.StopWatchingFileDescriptor(transport_.GetVendorFd());
+    transport_.CloseVendorFd();
+    async_manager_.StopWatchingFileDescriptor(transport_.GetHciFd());
+    transport_.CloseHciFd();
+  }
+
+  void CommandCallback(std::unique_ptr<CommandPacket> command) {
+    ++command_callback_count_;
+    // Ensure that the received packet matches the stub command.
+    EXPECT_EQ(DATA_TYPE_COMMAND, command->GetType());
+    EXPECT_EQ(HCI_RESET, command->GetOpcode());
+    EXPECT_EQ(static_cast<size_t>(1), command->GetPayloadSize());
+    SignalCommandhandlerFinished();
+  }
+
+  void MultiCommandCallback(std::unique_ptr<CommandPacket> command) {
+    ++command_callback_count_;
+    // Ensure that the received packet matches the stub command.
+    EXPECT_EQ(DATA_TYPE_COMMAND, command->GetType());
+    EXPECT_EQ(HCI_RESET, command->GetOpcode());
+    EXPECT_EQ(static_cast<size_t>(1), command->GetPayloadSize());
+    if (command_callback_count_ == kMultiIterations) {
+      SignalCommandhandlerFinished();
+    }
+  }
+
+ protected:
+  // Tracks the number of commands received.
+  int command_callback_count_;
+  AsyncManager async_manager_;
+  HciTransport transport_;
+  bool command_handler_finished_ = false;
+  std::mutex mutex_;
+  std::condition_variable cond_var_;
+
+  void WaitCommandhandlerFinish() {
+    std::unique_lock<std::mutex> lock(mutex_);
+    while (!command_handler_finished_) {
+      cond_var_.wait(lock);
+    }
+  }
+
+ private:
+  // Workarounds because ASSERT cannot be used directly in a constructor
+  void SetUpTransport() { ASSERT_TRUE(transport_.SetUp()); }
+
+  void StartThread() {
+    ASSERT_TRUE(async_manager_.WatchFdForNonBlockingReads(
+                    transport_.GetVendorFd(),
+                    [this](int fd) { transport_.OnCommandReady(fd); }) == 0);
+  }
+
+  void SignalCommandhandlerFinished() {
+    std::unique_lock<std::mutex> lock(mutex_);
+    command_handler_finished_ = true;
+    cond_var_.notify_one();
+  }
+};
+
+TEST_F(HciTransportTest, SingleCommandCallback) {
+  transport_.RegisterCommandHandler(
+      [this](std::unique_ptr<CommandPacket> command) {
+        CommandCallback(std::move(command));
+      });
+  EXPECT_EQ(0, command_callback_count_);
+  WriteStubCommand(transport_.GetHciFd());
+  WaitCommandhandlerFinish();
+  EXPECT_EQ(1, command_callback_count_);
+}
+
+TEST_F(HciTransportTest, MultiCommandCallback) {
+  transport_.RegisterCommandHandler(
+      [this](std::unique_ptr<CommandPacket> command) {
+        MultiCommandCallback(std::move(command));
+      });
+  EXPECT_EQ(0, command_callback_count_);
+  WriteStubCommand(transport_.GetHciFd());
+  for (int i = 1; i < kMultiIterations; ++i)
+    WriteStubCommand(transport_.GetHciFd());
+  WaitCommandhandlerFinish();
+  EXPECT_EQ(kMultiIterations, command_callback_count_);
+}
+
+}  // namespace test_vendor_lib
diff --git a/bt/vendor_libs/test_vendor_lib/test/packet_stream_unittest.cc b/bt/vendor_libs/test_vendor_lib/test/packet_stream_unittest.cc
new file mode 100644
index 0000000..3908b9e
--- /dev/null
+++ b/bt/vendor_libs/test_vendor_lib/test/packet_stream_unittest.cc
@@ -0,0 +1,154 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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_stream.h"
+#include "command_packet.h"
+#include "event_packet.h"
+#include "packet.h"
+
+#include <gtest/gtest.h>
+#include <cstdint>
+#include <memory>
+#include <vector>
+using std::vector;
+
+#include "hci/include/hci_hal.h"
+#include "stack/include/hcidefs.h"
+
+#include <sys/socket.h>
+
+namespace {
+const char small_payload[] = "foo bar baz";
+const char large_payload[] =
+    "Aristotle's principles will then be no more principles to him, than those "
+    "of Epicurus and the Stoics: let this diversity of opinions be propounded "
+    "to, and laid before him; he will himself choose, if he be able; if not, "
+    "he will remain in doubt.";
+}  // namespace
+
+namespace test_vendor_lib {
+
+class PacketStreamTest : public ::testing::Test {
+ public:
+  PacketStreamTest() {
+    socketpair(AF_LOCAL, SOCK_STREAM, 0, socketpair_fds_);
+    CheckSocketpairInit();
+  }
+
+  ~PacketStreamTest() {
+    close(socketpair_fds_[0]);
+    close(socketpair_fds_[1]);
+  }
+
+  void CheckedReceiveCommand(const char* payload, uint16_t opcode) {
+    uint8_t payload_size = strlen(payload);
+    vector<uint8_t> packet;
+
+    packet.push_back(DATA_TYPE_COMMAND);
+    packet.push_back(opcode);
+    packet.push_back(opcode >> 8);
+    packet.push_back(payload_size);
+
+    // Set the packet's payload.
+    for (int i = 0; i < payload_size; ++i) packet.push_back(payload[i]);
+
+    // Send the packet to |packet_stream_|.
+    write(socketpair_fds_[1], &packet[1], packet.size());
+
+    // Read the command packet.
+    std::unique_ptr<CommandPacket> command =
+        packet_stream_.ReceiveCommand(socketpair_fds_[0]);
+
+    const vector<uint8_t> received_payload = command->GetPayload();
+
+    // Validate the packet by checking that it's the appropriate size and then
+    // checking each byte.
+    EXPECT_EQ(packet.size(), command->GetPacketSize());
+    EXPECT_EQ(DATA_TYPE_COMMAND, command->GetType());
+    EXPECT_EQ(opcode, command->GetOpcode());
+    EXPECT_EQ(static_cast<size_t>(payload_size + 1), command->GetPayloadSize());
+    EXPECT_EQ(payload_size, received_payload[0]);
+    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_;
+
+  int socketpair_fds_[2];
+
+ private:
+  // Workaround because ASSERT cannot be used directly in a constructor
+  void CheckSocketpairInit() {
+    ASSERT_TRUE(socketpair_fds_[0] > 0);
+    ASSERT_TRUE(socketpair_fds_[1] > 0);
+  }
+};
+
+TEST_F(PacketStreamTest, ReceivePacketType) {
+  serial_data_type_t command_type = DATA_TYPE_COMMAND;
+  write(socketpair_fds_[1], &command_type, 1);
+  EXPECT_EQ(command_type, packet_stream_.ReceivePacketType(socketpair_fds_[0]));
+}
+
+TEST_F(PacketStreamTest, ReceiveEmptyCommand) {
+  CheckedReceiveCommand("", HCI_RESET);
+}
+
+TEST_F(PacketStreamTest, ReceiveSmallCommand) {
+  CheckedReceiveCommand(small_payload, HCI_RESET);
+}
+
+TEST_F(PacketStreamTest, ReceiveLargeCommand) {
+  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/bt/vnd/ble/vendor_hcidefs.h b/bt/vnd/ble/vendor_hcidefs.h
new file mode 100644
index 0000000..b5e770b
--- /dev/null
+++ b/bt/vnd/ble/vendor_hcidefs.h
@@ -0,0 +1,54 @@
+/******************************************************************************
+ *
+ *  Copyright (C) 2003-2014 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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+**
+**  Name        vendor_hcidefs.h
+**
+**  Function    This file contains Broadcom Specific Host Controller Interface
+**              definitions.
+**
+******************************************************************************/
+
+#ifndef VENDOR_HCIDEFS_H
+#define VENDOR_HCIDEFS_H
+
+/*****************************************************************************
+** Private address resolution VSC
+******************************************************************************/
+
+/* VSC */
+#define HCI_VENDOR_BLE_RPA_VSC                (0x0155 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Sub codes */
+#define HCI_VENDOR_BLE_RPA_ENABLE       0x01
+#define HCI_VENDOR_BLE_RPA_ADD_IRK      0x02
+#define HCI_VENDOR_BLE_RPA_REMOVE_IRK   0x03
+#define HCI_VENDOR_BLE_RPA_CLEAR_IRK    0x04
+#define HCI_VENDOR_BLE_RPA_READ_IRK     0x05
+
+
+/*****************************************************************************
+** Advertising data payload filter VSC
+******************************************************************************/
+
+/* VSC */
+#define HCI_VENDOR_BLE_PCF_VSC                (0x0157 | HCI_GRP_VENDOR_SPECIFIC)
+
+#endif
+
diff --git a/bt/vnd/include/vendor_api.h b/bt/vnd/include/vendor_api.h
new file mode 100644
index 0000000..102eafe
--- /dev/null
+++ b/bt/vnd/include/vendor_api.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Name:         vendor_api.h
+**
+** Description:  Vendor specific BTE API function external definitions.
+**
+** Copyright (c) 2009-2011, BROADCOM Inc., All Rights Reserved.
+** Broadcom Bluetooth Core. Proprietary and confidential.
+**
+******************************************************************************/
+#ifndef VENDOR_API_H
+#define VENDOR_API_H
+
+#include "bt_types.h"
+#include "btm_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/****************************************************************************
+**  Resolvable private address offload VSC specific definitions
+******************************************************************************/
+
+enum
+{
+    BTM_BLE_PRIVACY_ENABLE,
+    BTM_BLE_PRIVACY_DISABLE
+};
+
+
+/****************************************************************************
+**  Advertising packet filter VSC specific definitions
+******************************************************************************/
+
+
+/*****************************************************************************
+**              VENDOR SPECIFIC BLE FEATURE FUNCTIONS
+******************************************************************************/
+#if (BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE)
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif